From 64e1e8cff85ddcfe97b9d5525b879ffb5f51f0f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Thu, 5 Jul 2012 18:22:44 +0800 Subject: [PATCH 001/261] rk2928: add initial support --- arch/arm/Kconfig | 12 ++++++++++++ arch/arm/Makefile | 1 + arch/arm/mach-rk2928/Kconfig | 15 +++++++++++++++ arch/arm/mach-rk2928/Makefile.boot | 3 +++ arch/arm/mach-rk2928/include/mach/clkdev.h | 1 + arch/arm/mach-rk2928/include/mach/debug-macro.S | 1 + arch/arm/mach-rk2928/include/mach/dma-pl330.h | 1 + arch/arm/mach-rk2928/include/mach/entry-macro.S | 1 + arch/arm/mach-rk2928/include/mach/fiq.h | 1 + arch/arm/mach-rk2928/include/mach/hardware.h | 4 ++++ arch/arm/mach-rk2928/include/mach/memory.h | 14 ++++++++++++++ arch/arm/mach-rk2928/include/mach/sram.h | 13 +++++++++++++ arch/arm/mach-rk2928/include/mach/system.h | 1 + arch/arm/mach-rk2928/include/mach/timex.h | 1 + arch/arm/mach-rk2928/include/mach/uncompress.h | 1 + 15 files changed, 70 insertions(+) create mode 100644 arch/arm/mach-rk2928/Kconfig create mode 100644 arch/arm/mach-rk2928/Makefile.boot create mode 100644 arch/arm/mach-rk2928/include/mach/clkdev.h create mode 100644 arch/arm/mach-rk2928/include/mach/debug-macro.S create mode 100644 arch/arm/mach-rk2928/include/mach/dma-pl330.h create mode 100644 arch/arm/mach-rk2928/include/mach/entry-macro.S create mode 100644 arch/arm/mach-rk2928/include/mach/fiq.h create mode 100644 arch/arm/mach-rk2928/include/mach/hardware.h create mode 100644 arch/arm/mach-rk2928/include/mach/memory.h create mode 100644 arch/arm/mach-rk2928/include/mach/sram.h create mode 100644 arch/arm/mach-rk2928/include/mach/system.h create mode 100644 arch/arm/mach-rk2928/include/mach/timex.h create mode 100644 arch/arm/mach-rk2928/include/mach/uncompress.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index b7635e71087d..359ef7a6dbb2 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -871,6 +871,17 @@ config ARCH_RK29 help Support for Rockchip's RK29xx SoCs. +config ARCH_RK2928 + bool "Rockchip RK2928" + select PLAT_RK + select CPU_V7 + select ARM_GIC + select PL330 + select MIGHT_HAVE_CACHE_L2X0 + select ARM_ERRATA_754322 + help + Support for Rockchip's RK2928 SoCs. + config ARCH_RK30 bool "Rockchip RK30xx" select PLAT_RK @@ -986,6 +997,7 @@ source "arch/arm/mach-realview/Kconfig" source "arch/arm/plat-rk/Kconfig" source "arch/arm/mach-rk29/Kconfig" +source "arch/arm/mach-rk2928/Kconfig" source "arch/arm/mach-rk30/Kconfig" source "arch/arm/mach-sa1100/Kconfig" diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 83aa4bd2c5a7..43c17789695f 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -172,6 +172,7 @@ machine-$(CONFIG_ARCH_PNX4008) := pnx4008 machine-$(CONFIG_ARCH_PXA) := pxa machine-$(CONFIG_ARCH_REALVIEW) := realview machine-$(CONFIG_ARCH_RK29) := rk29 +machine-$(CONFIG_ARCH_RK2928) := rk2928 machine-$(CONFIG_ARCH_RK30) := rk30 machine-$(CONFIG_ARCH_RPC) := rpc machine-$(CONFIG_ARCH_S3C2410) := s3c2410 s3c2400 s3c2412 s3c2416 s3c2440 s3c2443 diff --git a/arch/arm/mach-rk2928/Kconfig b/arch/arm/mach-rk2928/Kconfig new file mode 100644 index 000000000000..9427d232d354 --- /dev/null +++ b/arch/arm/mach-rk2928/Kconfig @@ -0,0 +1,15 @@ +if ARCH_RK2928 + +choice + prompt "RK2928 Board Type" + default MACH_RK2928_SDK + +config MACH_RK2928_FPGA + bool "RK2928 FPGA board" + +config MACH_RK2928_SDK + bool "RK2928 SDK board" + +endchoice + +endif diff --git a/arch/arm/mach-rk2928/Makefile.boot b/arch/arm/mach-rk2928/Makefile.boot new file mode 100644 index 000000000000..820e50c1b2b6 --- /dev/null +++ b/arch/arm/mach-rk2928/Makefile.boot @@ -0,0 +1,3 @@ + zreladdr-y := 0x60408000 +params_phys-y := 0x60088000 +initrd_phys-y := 0x60800000 diff --git a/arch/arm/mach-rk2928/include/mach/clkdev.h b/arch/arm/mach-rk2928/include/mach/clkdev.h new file mode 100644 index 000000000000..c0cf3286a662 --- /dev/null +++ b/arch/arm/mach-rk2928/include/mach/clkdev.h @@ -0,0 +1 @@ +#include diff --git a/arch/arm/mach-rk2928/include/mach/debug-macro.S b/arch/arm/mach-rk2928/include/mach/debug-macro.S new file mode 100644 index 000000000000..00d5467951fe --- /dev/null +++ b/arch/arm/mach-rk2928/include/mach/debug-macro.S @@ -0,0 +1 @@ +#include diff --git a/arch/arm/mach-rk2928/include/mach/dma-pl330.h b/arch/arm/mach-rk2928/include/mach/dma-pl330.h new file mode 100644 index 000000000000..9afde6529658 --- /dev/null +++ b/arch/arm/mach-rk2928/include/mach/dma-pl330.h @@ -0,0 +1 @@ +#include diff --git a/arch/arm/mach-rk2928/include/mach/entry-macro.S b/arch/arm/mach-rk2928/include/mach/entry-macro.S new file mode 100644 index 000000000000..d5136aa47385 --- /dev/null +++ b/arch/arm/mach-rk2928/include/mach/entry-macro.S @@ -0,0 +1 @@ +#include diff --git a/arch/arm/mach-rk2928/include/mach/fiq.h b/arch/arm/mach-rk2928/include/mach/fiq.h new file mode 100644 index 000000000000..31e146e6f1f4 --- /dev/null +++ b/arch/arm/mach-rk2928/include/mach/fiq.h @@ -0,0 +1 @@ +#include diff --git a/arch/arm/mach-rk2928/include/mach/hardware.h b/arch/arm/mach-rk2928/include/mach/hardware.h new file mode 100644 index 000000000000..9e84f2395d97 --- /dev/null +++ b/arch/arm/mach-rk2928/include/mach/hardware.h @@ -0,0 +1,4 @@ +#ifndef __MACH_HARDWARE_H +#define __MACH_HARDWARE_H + +#endif diff --git a/arch/arm/mach-rk2928/include/mach/memory.h b/arch/arm/mach-rk2928/include/mach/memory.h new file mode 100644 index 000000000000..5aa902f91630 --- /dev/null +++ b/arch/arm/mach-rk2928/include/mach/memory.h @@ -0,0 +1,14 @@ +#ifndef __MACH_MEMORY_H +#define __MACH_MEMORY_H + +#include + +/* + * SRAM memory whereabouts + */ +#define SRAM_CODE_OFFSET (RK2928_IMEM_BASE + 0x0000) +#define SRAM_CODE_END (RK2928_IMEM_BASE + 0x0FFF) +#define SRAM_DATA_OFFSET (RK2928_IMEM_BASE + 0x1000) +#define SRAM_DATA_END (RK2928_IMEM_BASE + 0x1FFF) + +#endif diff --git a/arch/arm/mach-rk2928/include/mach/sram.h b/arch/arm/mach-rk2928/include/mach/sram.h new file mode 100644 index 000000000000..eba76bccf64d --- /dev/null +++ b/arch/arm/mach-rk2928/include/mach/sram.h @@ -0,0 +1,13 @@ +#ifndef __MACH_SRAM_H +#define __MACH_SRAM_H + +#include + +#define SRAM_LOOPS_PER_USEC 24 +#define SRAM_LOOP(loops) do { unsigned int i = (loops); if (i < 7) i = 7; barrier(); while (--i) barrier(); } while (0) +/* delay on slow mode */ +#define sram_udelay(usecs) SRAM_LOOP((usecs)*SRAM_LOOPS_PER_USEC) +/* delay on deep slow mode */ +#define sram_32k_udelay(usecs) SRAM_LOOP(((usecs)*SRAM_LOOPS_PER_USEC)/(24000000/32768)) + +#endif diff --git a/arch/arm/mach-rk2928/include/mach/system.h b/arch/arm/mach-rk2928/include/mach/system.h new file mode 100644 index 000000000000..e68cfe7e31ed --- /dev/null +++ b/arch/arm/mach-rk2928/include/mach/system.h @@ -0,0 +1 @@ +#include diff --git a/arch/arm/mach-rk2928/include/mach/timex.h b/arch/arm/mach-rk2928/include/mach/timex.h new file mode 100644 index 000000000000..d2a02f98c397 --- /dev/null +++ b/arch/arm/mach-rk2928/include/mach/timex.h @@ -0,0 +1 @@ +#include diff --git a/arch/arm/mach-rk2928/include/mach/uncompress.h b/arch/arm/mach-rk2928/include/mach/uncompress.h new file mode 100644 index 000000000000..a4acb7198e1c --- /dev/null +++ b/arch/arm/mach-rk2928/include/mach/uncompress.h @@ -0,0 +1 @@ +#include From f9fc02f2166433abed8da64b62314ba1b594163a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Thu, 5 Jul 2012 18:47:03 +0800 Subject: [PATCH 002/261] rk2928: mach-types add rk2928 --- arch/arm/tools/mach-types | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types index 1fad7ed44a6d..5bb762af6c1d 100644 --- a/arch/arm/tools/mach-types +++ b/arch/arm/tools/mach-types @@ -568,8 +568,9 @@ oratisaes MACH_ORATISAES ORATISAES 2924 smdkv310 MACH_SMDKV310 SMDKV310 2925 siemens_l0 MACH_SIEMENS_L0 SIEMENS_L0 2926 ventana MACH_VENTANA VENTANA 2927 -wm8505_7in_netbook MACH_WM8505_7IN_NETBOOK WM8505_7IN_NETBOOK 2928 +#wm8505_7in_netbook MACH_WM8505_7IN_NETBOOK WM8505_7IN_NETBOOK 2928 rk29 MACH_RK29 RK29 2929 +rk2928 ARCH_RK2928 RK2928 2928 rk30 ARCH_RK30 RK30 3066 #ec4350sdb MACH_EC4350SDB EC4350SDB 2929 mimas MACH_MIMAS MIMAS 2930 From be7fa86fae07c091cd0b343fe9f85800752051f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Mon, 9 Jul 2012 17:00:55 +0800 Subject: [PATCH 003/261] rk2928: add common.c io.c gpio.h io.h irqs.h memory.h vmalloc.h pm.c reset.c board.h --- arch/arm/mach-rk2928/Makefile | 4 + arch/arm/mach-rk2928/common.c | 156 +++++++++ arch/arm/mach-rk2928/include/mach/board.h | 34 ++ arch/arm/mach-rk2928/include/mach/gpio.h | 367 ++++++++++++++++++++ arch/arm/mach-rk2928/include/mach/io.h | 188 ++++++++++ arch/arm/mach-rk2928/include/mach/irqs.h | 64 ++++ arch/arm/mach-rk2928/include/mach/memory.h | 1 + arch/arm/mach-rk2928/include/mach/vmalloc.h | 6 + arch/arm/mach-rk2928/io.c | 62 ++++ arch/arm/mach-rk2928/pm.c | 35 ++ arch/arm/mach-rk2928/reset.c | 11 + 11 files changed, 928 insertions(+) create mode 100644 arch/arm/mach-rk2928/Makefile create mode 100644 arch/arm/mach-rk2928/common.c create mode 100644 arch/arm/mach-rk2928/include/mach/board.h create mode 100644 arch/arm/mach-rk2928/include/mach/gpio.h create mode 100644 arch/arm/mach-rk2928/include/mach/io.h create mode 100644 arch/arm/mach-rk2928/include/mach/irqs.h create mode 100644 arch/arm/mach-rk2928/include/mach/vmalloc.h create mode 100644 arch/arm/mach-rk2928/io.c create mode 100755 arch/arm/mach-rk2928/pm.c create mode 100644 arch/arm/mach-rk2928/reset.c diff --git a/arch/arm/mach-rk2928/Makefile b/arch/arm/mach-rk2928/Makefile new file mode 100644 index 000000000000..1f1fe597f457 --- /dev/null +++ b/arch/arm/mach-rk2928/Makefile @@ -0,0 +1,4 @@ +obj-y += common.o +obj-y += io.o +obj-y += reset.o +obj-$(CONFIG_PM) += pm.o diff --git a/arch/arm/mach-rk2928/common.c b/arch/arm/mach-rk2928/common.c new file mode 100644 index 000000000000..277ee537f753 --- /dev/null +++ b/arch/arm/mach-rk2928/common.c @@ -0,0 +1,156 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +//#include +#include +//#include +//#include + +static void __init rk2928_cpu_axi_init(void) +{ +#if 0 + writel_relaxed(0x0, RK2928_CPU_AXI_BUS_BASE + 0x0088); // cpu0 + writel_relaxed(0x0, RK2928_CPU_AXI_BUS_BASE + 0x0108); // dmac1 + writel_relaxed(0x0, RK2928_CPU_AXI_BUS_BASE + 0x0188); // cpu1r + writel_relaxed(0x0, RK2928_CPU_AXI_BUS_BASE + 0x0388); // cpu1w + writel_relaxed(0x0, RK2928_CPU_AXI_BUS_BASE + 0x4008); // peri + writel_relaxed(0x0, RK2928_CPU_AXI_BUS_BASE + 0x5008); // gpu + writel_relaxed(0x0, RK2928_CPU_AXI_BUS_BASE + 0x6008); // vpu + writel_relaxed(0xa, RK2928_CPU_AXI_BUS_BASE + 0x7008); // lcdc0 + writel_relaxed(0x0, RK2928_CPU_AXI_BUS_BASE + 0x7088); // cif0 + writel_relaxed(0x0, RK2928_CPU_AXI_BUS_BASE + 0x7108); // ipp + writel_relaxed(0xa, RK2928_CPU_AXI_BUS_BASE + 0x7188); // lcdc1 + writel_relaxed(0x0, RK2928_CPU_AXI_BUS_BASE + 0x7208); // cif1 + writel_relaxed(0x0, RK2928_CPU_AXI_BUS_BASE + 0x7288); // rga +#endif + writel_relaxed(0x3f, RK2928_CPU_AXI_BUS_BASE + 0x0014); // memory scheduler read latency + dsb(); +} + +#define L2_LY_SP_OFF (0) +#define L2_LY_SP_MSK (0x7) + +#define L2_LY_RD_OFF (4) +#define L2_LY_RD_MSK (0x7) + +#define L2_LY_WR_OFF (8) +#define L2_LY_WR_MSK (0x7) +#define L2_LY_SET(ly,off) (((ly)-1)<<(off)) + +static void __init rk2928_l2_cache_init(void) +{ +#ifdef CONFIG_CACHE_L2X0 + u32 aux_ctrl, aux_ctrl_mask; + + writel_relaxed(L2_LY_SET(1,L2_LY_SP_OFF) + |L2_LY_SET(1,L2_LY_RD_OFF) + |L2_LY_SET(1,L2_LY_WR_OFF), RK2928_L2C_BASE + L2X0_TAG_LATENCY_CTRL); + writel_relaxed(L2_LY_SET(4,L2_LY_SP_OFF) + |L2_LY_SET(6,L2_LY_RD_OFF) + |L2_LY_SET(1,L2_LY_WR_OFF), RK2928_L2C_BASE + L2X0_DATA_LATENCY_CTRL); + + /* L2X0 Prefetch Control */ + writel_relaxed(0x70000003, RK2928_L2C_BASE + L2X0_PREFETCH_CTRL); + + /* L2X0 Power Control */ + writel_relaxed(L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN, RK2928_L2C_BASE + L2X0_POWER_CTRL); + + aux_ctrl = ( +// (1 << L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT) | // 16-way + (0x1 << 25) | // Round-robin cache replacement policy + (0x1 << 0) | // Full Line of Zero Enable + (0x1 << L2X0_AUX_CTRL_NS_LOCKDOWN_SHIFT) | +// (0x2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) | // 32KB way-size + (0x1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT) | + (0x1 << L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT) | + (0x1 << L2X0_AUX_CTRL_EARLY_BRESP_SHIFT) ); + + aux_ctrl_mask = ~( +// (1 << L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT) | // 16-way + (0x1 << 25) | // Cache replacement policy + (0x1 << 0) | // Full Line of Zero Enable + (0x1 << L2X0_AUX_CTRL_NS_LOCKDOWN_SHIFT) | +// (0x7 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) | // 32KB way-size + (0x1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT) | + (0x1 << L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT) | + (0x1 << L2X0_AUX_CTRL_EARLY_BRESP_SHIFT) ); + + l2x0_init(RK2928_L2C_BASE, aux_ctrl, aux_ctrl_mask); +#endif +} + +static int boot_mode; +static void __init rk2928_boot_mode_init(void) +{ +#if 0 + u32 boot_flag = readl_relaxed(RK2928_PMU_BASE + PMU_SYS_REG0); + boot_mode = readl_relaxed(RK2928_PMU_BASE + PMU_SYS_REG1); + + if (boot_flag == (SYS_KERNRL_REBOOT_FLAG | BOOT_RECOVER)) { + boot_mode = BOOT_MODE_RECOVERY; + } else if (strstr(boot_command_line, "(parameter)")) { + boot_mode = BOOT_MODE_RECOVERY; + } + if (boot_mode || boot_flag) + printk("Boot mode: %d flag: 0x%08x\n", boot_mode, boot_flag); +#endif +} + +int board_boot_mode(void) +{ + return boot_mode; +} +EXPORT_SYMBOL(board_boot_mode); + +void __init rk2928_init_irq(void) +{ + gic_init(0, IRQ_LOCALTIMER, GIC_DIST_BASE, GIC_CPU_BASE); +#ifdef CONFIG_FIQ + rk_fiq_init(); +#endif +// rk30_gpio_init(); +} + +extern void __init rk2928_map_common_io(void); +extern int __init clk_disable_unused(void); + +void __init rk2928_map_io(void) +{ + rk2928_map_common_io(); + rk29_setup_early_printk(); + rk2928_cpu_axi_init(); + rk29_sram_init(); +// board_clock_init(); + rk2928_l2_cache_init(); +// ddr_init(DDR_TYPE, DDR_FREQ); +// clk_disable_unused(); +// rk2928_iomux_init(); + rk2928_boot_mode_init(); +} + +extern u32 ddr_get_cap(void); +static __init u32 rk2928_get_ddr_size(void) +{ +#ifdef CONFIG_MACH_RK2928_FPGA + return SZ_64M; +#endif +} + +void __init rk2928_fixup(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ + mi->nr_banks = 1; + mi->bank[0].start = PLAT_PHYS_OFFSET; + mi->bank[0].size = rk2928_get_ddr_size(); +} + diff --git a/arch/arm/mach-rk2928/include/mach/board.h b/arch/arm/mach-rk2928/include/mach/board.h new file mode 100644 index 000000000000..d4ec846e7d76 --- /dev/null +++ b/arch/arm/mach-rk2928/include/mach/board.h @@ -0,0 +1,34 @@ +#ifndef __MACH_BOARD_H +#define __MACH_BOARD_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern struct rk29_sdmmc_platform_data default_sdmmc0_data; +extern struct rk29_sdmmc_platform_data default_sdmmc1_data; + +extern struct i2c_gpio_platform_data default_i2c_gpio_data; + +void __init rk2928_map_common_io(void); +void __init rk2928_init_irq(void); +void __init rk2928_map_io(void); +struct machine_desc; +void __init rk2928_fixup(struct machine_desc *desc, struct tag *tags, char **cmdline, struct meminfo *mi); +void __init rk2928_clock_data_init(unsigned long gpll,unsigned long cpll,u32 flags); +void __init board_clock_init(void); +void board_gpio_suspend(void); +void board_gpio_resume(void); +void __sramfunc board_pmu_suspend(void); +void __sramfunc board_pmu_resume(void); + +extern struct sys_timer rk2928_timer; + +#endif diff --git a/arch/arm/mach-rk2928/include/mach/gpio.h b/arch/arm/mach-rk2928/include/mach/gpio.h new file mode 100644 index 000000000000..913896953b09 --- /dev/null +++ b/arch/arm/mach-rk2928/include/mach/gpio.h @@ -0,0 +1,367 @@ +#ifndef __MACH_GPIO_H +#define __MACH_GPIO_H + +#include +#include + +//定义GPIO相关寄存器偏移地址 +#define GPIO_SWPORT_DR 0x00 +#define GPIO_SWPORT_DDR 0x04 +#define GPIO_INTEN 0x30 +#define GPIO_INTMASK 0x34 +#define GPIO_INTTYPE_LEVEL 0x38 +#define GPIO_INT_POLARITY 0x3c +#define GPIO_INT_STATUS 0x40 +#define GPIO_INT_RAWSTATUS 0x44 +#define GPIO_DEBOUNCE 0x48 +#define GPIO_PORTS_EOI 0x4c +#define GPIO_EXT_PORT 0x50 +#define GPIO_LS_SYNC 0x60 + +#define NUM_GROUP 32 +#define MAX_BANK 4 + +#define PIN_BASE NR_GIC_IRQS + +#define RK2928_TOTOL_GPIO_NUM (NUM_GROUP*MAX_BANK) + +#define SPI_FPGA_EXPANDER_BASE (PIN_BASE+RK2928_TOTOL_GPIO_NUM) + +#if defined (CONFIG_SPI_FPGA_GPIO) +#define GPIO_EXPANDER_BASE (PIN_BASE+RK2928_TOTOL_GPIO_NUM+CONFIG_SPI_FPGA_GPIO_NUM) +#else +#define GPIO_EXPANDER_BASE (PIN_BASE+RK2928_TOTOL_GPIO_NUM) +#endif + +#if defined(CONFIG_IOEXTEND_TCA6424) +#define TCA6424_TOTOL_GPIO_NUM 24 +#define TCA6424_TOTOL_GPIO_IRQ_NUM 24 +#define TCA6424_GPIO_EXPANDER_BASE GPIO_EXPANDER_BASE +#else +#define TCA6424_TOTOL_GPIO_NUM 0 +#define TCA6424_TOTOL_GPIO_IRQ_NUM 0 +#endif + +#if defined(CONFIG_GPIO_WM831X) +#define WM831X_TOTOL_GPIO_NUM 12 +#define WM831X_GPIO_EXPANDER_BASE (GPIO_EXPANDER_BASE+TCA6424_TOTOL_GPIO_NUM) +#else +#define WM831X_TOTOL_GPIO_NUM 0 +#define WM831X_GPIO_EXPANDER_BASE (GPIO_EXPANDER_BASE+TCA6424_TOTOL_GPIO_NUM) +#endif + +#if defined (CONFIG_GPIO_WM8994) +#define CONFIG_GPIO_WM8994_NUM 11 +#define WM8994_GPIO_EXPANDER_BASE (GPIO_EXPANDER_BASE+WM831X_TOTOL_GPIO_NUM) +#else +#define CONFIG_GPIO_WM8994_NUM 0 +#endif + +//定义GPIO的PIN口最大数目。CONFIG_SPI_FPGA_GPIO_NUM表示FPGA的PIN脚数。 +#define ARCH_NR_GPIOS (PIN_BASE + RK2928_TOTOL_GPIO_NUM + TCA6424_TOTOL_GPIO_NUM + WM831X_TOTOL_GPIO_NUM + CONFIG_SPI_FPGA_GPIO_NUM + CONFIG_GPIO_WM8994_NUM) + +#define INVALID_GPIO -1 + +#define RK2928_PIN0_PA0 (0*NUM_GROUP + PIN_BASE + 0) +#define RK2928_PIN0_PA1 (0*NUM_GROUP + PIN_BASE + 1) +#define RK2928_PIN0_PA2 (0*NUM_GROUP + PIN_BASE + 2) +#define RK2928_PIN0_PA3 (0*NUM_GROUP + PIN_BASE + 3) +#define RK2928_PIN0_PA4 (0*NUM_GROUP + PIN_BASE + 4) +#define RK2928_PIN0_PA5 (0*NUM_GROUP + PIN_BASE + 5) +#define RK2928_PIN0_PA6 (0*NUM_GROUP + PIN_BASE + 6) +#define RK2928_PIN0_PA7 (0*NUM_GROUP + PIN_BASE + 7) +#define RK2928_PIN0_PB0 (0*NUM_GROUP + PIN_BASE + 8) +#define RK2928_PIN0_PB1 (0*NUM_GROUP + PIN_BASE + 9) +#define RK2928_PIN0_PB2 (0*NUM_GROUP + PIN_BASE + 10) +#define RK2928_PIN0_PB3 (0*NUM_GROUP + PIN_BASE + 11) +#define RK2928_PIN0_PB4 (0*NUM_GROUP + PIN_BASE + 12) +#define RK2928_PIN0_PB5 (0*NUM_GROUP + PIN_BASE + 13) +#define RK2928_PIN0_PB6 (0*NUM_GROUP + PIN_BASE + 14) +#define RK2928_PIN0_PB7 (0*NUM_GROUP + PIN_BASE + 15) +#define RK2928_PIN0_PC0 (0*NUM_GROUP + PIN_BASE + 16) +#define RK2928_PIN0_PC1 (0*NUM_GROUP + PIN_BASE + 17) +#define RK2928_PIN0_PC2 (0*NUM_GROUP + PIN_BASE + 18) +#define RK2928_PIN0_PC3 (0*NUM_GROUP + PIN_BASE + 19) +#define RK2928_PIN0_PC4 (0*NUM_GROUP + PIN_BASE + 20) +#define RK2928_PIN0_PC5 (0*NUM_GROUP + PIN_BASE + 21) +#define RK2928_PIN0_PC6 (0*NUM_GROUP + PIN_BASE + 22) +#define RK2928_PIN0_PC7 (0*NUM_GROUP + PIN_BASE + 23) +#define RK2928_PIN0_PD0 (0*NUM_GROUP + PIN_BASE + 24) +#define RK2928_PIN0_PD1 (0*NUM_GROUP + PIN_BASE + 25) +#define RK2928_PIN0_PD2 (0*NUM_GROUP + PIN_BASE + 26) +#define RK2928_PIN0_PD3 (0*NUM_GROUP + PIN_BASE + 27) +#define RK2928_PIN0_PD4 (0*NUM_GROUP + PIN_BASE + 28) +#define RK2928_PIN0_PD5 (0*NUM_GROUP + PIN_BASE + 29) +#define RK2928_PIN0_PD6 (0*NUM_GROUP + PIN_BASE + 30) +#define RK2928_PIN0_PD7 (0*NUM_GROUP + PIN_BASE + 31) + +#define RK2928_PIN1_PA0 (1*NUM_GROUP + PIN_BASE + 0) +#define RK2928_PIN1_PA1 (1*NUM_GROUP + PIN_BASE + 1) +#define RK2928_PIN1_PA2 (1*NUM_GROUP + PIN_BASE + 2) +#define RK2928_PIN1_PA3 (1*NUM_GROUP + PIN_BASE + 3) +#define RK2928_PIN1_PA4 (1*NUM_GROUP + PIN_BASE + 4) +#define RK2928_PIN1_PA5 (1*NUM_GROUP + PIN_BASE + 5) +#define RK2928_PIN1_PA6 (1*NUM_GROUP + PIN_BASE + 6) +#define RK2928_PIN1_PA7 (1*NUM_GROUP + PIN_BASE + 7) +#define RK2928_PIN1_PB0 (1*NUM_GROUP + PIN_BASE + 8) +#define RK2928_PIN1_PB1 (1*NUM_GROUP + PIN_BASE + 9) +#define RK2928_PIN1_PB2 (1*NUM_GROUP + PIN_BASE + 10) +#define RK2928_PIN1_PB3 (1*NUM_GROUP + PIN_BASE + 11) +#define RK2928_PIN1_PB4 (1*NUM_GROUP + PIN_BASE + 12) +#define RK2928_PIN1_PB5 (1*NUM_GROUP + PIN_BASE + 13) +#define RK2928_PIN1_PB6 (1*NUM_GROUP + PIN_BASE + 14) +#define RK2928_PIN1_PB7 (1*NUM_GROUP + PIN_BASE + 15) +#define RK2928_PIN1_PC0 (1*NUM_GROUP + PIN_BASE + 16) +#define RK2928_PIN1_PC1 (1*NUM_GROUP + PIN_BASE + 17) +#define RK2928_PIN1_PC2 (1*NUM_GROUP + PIN_BASE + 18) +#define RK2928_PIN1_PC3 (1*NUM_GROUP + PIN_BASE + 19) +#define RK2928_PIN1_PC4 (1*NUM_GROUP + PIN_BASE + 20) +#define RK2928_PIN1_PC5 (1*NUM_GROUP + PIN_BASE + 21) +#define RK2928_PIN1_PC6 (1*NUM_GROUP + PIN_BASE + 22) +#define RK2928_PIN1_PC7 (1*NUM_GROUP + PIN_BASE + 23) +#define RK2928_PIN1_PD0 (1*NUM_GROUP + PIN_BASE + 24) +#define RK2928_PIN1_PD1 (1*NUM_GROUP + PIN_BASE + 25) +#define RK2928_PIN1_PD2 (1*NUM_GROUP + PIN_BASE + 26) +#define RK2928_PIN1_PD3 (1*NUM_GROUP + PIN_BASE + 27) +#define RK2928_PIN1_PD4 (1*NUM_GROUP + PIN_BASE + 28) +#define RK2928_PIN1_PD5 (1*NUM_GROUP + PIN_BASE + 29) +#define RK2928_PIN1_PD6 (1*NUM_GROUP + PIN_BASE + 30) +#define RK2928_PIN1_PD7 (1*NUM_GROUP + PIN_BASE + 31) + +#define RK2928_PIN2_PA0 (2*NUM_GROUP + PIN_BASE + 0) +#define RK2928_PIN2_PA1 (2*NUM_GROUP + PIN_BASE + 1) +#define RK2928_PIN2_PA2 (2*NUM_GROUP + PIN_BASE + 2) +#define RK2928_PIN2_PA3 (2*NUM_GROUP + PIN_BASE + 3) +#define RK2928_PIN2_PA4 (2*NUM_GROUP + PIN_BASE + 4) +#define RK2928_PIN2_PA5 (2*NUM_GROUP + PIN_BASE + 5) +#define RK2928_PIN2_PA6 (2*NUM_GROUP + PIN_BASE + 6) +#define RK2928_PIN2_PA7 (2*NUM_GROUP + PIN_BASE + 7) +#define RK2928_PIN2_PB0 (2*NUM_GROUP + PIN_BASE + 8) +#define RK2928_PIN2_PB1 (2*NUM_GROUP + PIN_BASE + 9) +#define RK2928_PIN2_PB2 (2*NUM_GROUP + PIN_BASE + 10) +#define RK2928_PIN2_PB3 (2*NUM_GROUP + PIN_BASE + 11) +#define RK2928_PIN2_PB4 (2*NUM_GROUP + PIN_BASE + 12) +#define RK2928_PIN2_PB5 (2*NUM_GROUP + PIN_BASE + 13) +#define RK2928_PIN2_PB6 (2*NUM_GROUP + PIN_BASE + 14) +#define RK2928_PIN2_PB7 (2*NUM_GROUP + PIN_BASE + 15) +#define RK2928_PIN2_PC0 (2*NUM_GROUP + PIN_BASE + 16) +#define RK2928_PIN2_PC1 (2*NUM_GROUP + PIN_BASE + 17) +#define RK2928_PIN2_PC2 (2*NUM_GROUP + PIN_BASE + 18) +#define RK2928_PIN2_PC3 (2*NUM_GROUP + PIN_BASE + 19) +#define RK2928_PIN2_PC4 (2*NUM_GROUP + PIN_BASE + 20) +#define RK2928_PIN2_PC5 (2*NUM_GROUP + PIN_BASE + 21) +#define RK2928_PIN2_PC6 (2*NUM_GROUP + PIN_BASE + 22) +#define RK2928_PIN2_PC7 (2*NUM_GROUP + PIN_BASE + 23) +#define RK2928_PIN2_PD0 (2*NUM_GROUP + PIN_BASE + 24) +#define RK2928_PIN2_PD1 (2*NUM_GROUP + PIN_BASE + 25) +#define RK2928_PIN2_PD2 (2*NUM_GROUP + PIN_BASE + 26) +#define RK2928_PIN2_PD3 (2*NUM_GROUP + PIN_BASE + 27) +#define RK2928_PIN2_PD4 (2*NUM_GROUP + PIN_BASE + 28) +#define RK2928_PIN2_PD5 (2*NUM_GROUP + PIN_BASE + 29) +#define RK2928_PIN2_PD6 (2*NUM_GROUP + PIN_BASE + 30) +#define RK2928_PIN2_PD7 (2*NUM_GROUP + PIN_BASE + 31) + +#define RK2928_PIN3_PA0 (3*NUM_GROUP + PIN_BASE + 0) +#define RK2928_PIN3_PA1 (3*NUM_GROUP + PIN_BASE + 1) +#define RK2928_PIN3_PA2 (3*NUM_GROUP + PIN_BASE + 2) +#define RK2928_PIN3_PA3 (3*NUM_GROUP + PIN_BASE + 3) +#define RK2928_PIN3_PA4 (3*NUM_GROUP + PIN_BASE + 4) +#define RK2928_PIN3_PA5 (3*NUM_GROUP + PIN_BASE + 5) +#define RK2928_PIN3_PA6 (3*NUM_GROUP + PIN_BASE + 6) +#define RK2928_PIN3_PA7 (3*NUM_GROUP + PIN_BASE + 7) +#define RK2928_PIN3_PB0 (3*NUM_GROUP + PIN_BASE + 8) +#define RK2928_PIN3_PB1 (3*NUM_GROUP + PIN_BASE + 9) +#define RK2928_PIN3_PB2 (3*NUM_GROUP + PIN_BASE + 10) +#define RK2928_PIN3_PB3 (3*NUM_GROUP + PIN_BASE + 11) +#define RK2928_PIN3_PB4 (3*NUM_GROUP + PIN_BASE + 12) +#define RK2928_PIN3_PB5 (3*NUM_GROUP + PIN_BASE + 13) +#define RK2928_PIN3_PB6 (3*NUM_GROUP + PIN_BASE + 14) +#define RK2928_PIN3_PB7 (3*NUM_GROUP + PIN_BASE + 15) +#define RK2928_PIN3_PC0 (3*NUM_GROUP + PIN_BASE + 16) +#define RK2928_PIN3_PC1 (3*NUM_GROUP + PIN_BASE + 17) +#define RK2928_PIN3_PC2 (3*NUM_GROUP + PIN_BASE + 18) +#define RK2928_PIN3_PC3 (3*NUM_GROUP + PIN_BASE + 19) +#define RK2928_PIN3_PC4 (3*NUM_GROUP + PIN_BASE + 20) +#define RK2928_PIN3_PC5 (3*NUM_GROUP + PIN_BASE + 21) +#define RK2928_PIN3_PC6 (3*NUM_GROUP + PIN_BASE + 22) +#define RK2928_PIN3_PC7 (3*NUM_GROUP + PIN_BASE + 23) +#define RK2928_PIN3_PD0 (3*NUM_GROUP + PIN_BASE + 24) +#define RK2928_PIN3_PD1 (3*NUM_GROUP + PIN_BASE + 25) +#define RK2928_PIN3_PD2 (3*NUM_GROUP + PIN_BASE + 26) +#define RK2928_PIN3_PD3 (3*NUM_GROUP + PIN_BASE + 27) +#define RK2928_PIN3_PD4 (3*NUM_GROUP + PIN_BASE + 28) +#define RK2928_PIN3_PD5 (3*NUM_GROUP + PIN_BASE + 29) +#define RK2928_PIN3_PD6 (3*NUM_GROUP + PIN_BASE + 30) +#define RK2928_PIN3_PD7 (3*NUM_GROUP + PIN_BASE + 31) + +#if defined(CONFIG_SPI_FPGA_GPIO) +#define FPGA_PIO0_00 (SPI_FPGA_EXPANDER_BASE + 0*NUM_GROUP + 0) +#define FPGA_PIO0_01 (SPI_FPGA_EXPANDER_BASE + 0*NUM_GROUP + 1) +#define FPGA_PIO0_02 (SPI_FPGA_EXPANDER_BASE + 0*NUM_GROUP + 2) +#define FPGA_PIO0_03 (SPI_FPGA_EXPANDER_BASE + 0*NUM_GROUP + 3) +#define FPGA_PIO0_04 (SPI_FPGA_EXPANDER_BASE + 0*NUM_GROUP + 4) +#define FPGA_PIO0_05 (SPI_FPGA_EXPANDER_BASE + 0*NUM_GROUP + 5) +#define FPGA_PIO0_06 (SPI_FPGA_EXPANDER_BASE + 0*NUM_GROUP + 6) +#define FPGA_PIO0_07 (SPI_FPGA_EXPANDER_BASE + 0*NUM_GROUP + 7) + +#define FPGA_PIO0_08 (SPI_FPGA_EXPANDER_BASE + 1*NUM_GROUP + 0) +#define FPGA_PIO0_09 (SPI_FPGA_EXPANDER_BASE + 1*NUM_GROUP + 1) +#define FPGA_PIO0_10 (SPI_FPGA_EXPANDER_BASE + 1*NUM_GROUP + 2) +#define FPGA_PIO0_11 (SPI_FPGA_EXPANDER_BASE + 1*NUM_GROUP + 3) +#define FPGA_PIO0_12 (SPI_FPGA_EXPANDER_BASE + 1*NUM_GROUP + 4) +#define FPGA_PIO0_13 (SPI_FPGA_EXPANDER_BASE + 1*NUM_GROUP + 5) +#define FPGA_PIO0_14 (SPI_FPGA_EXPANDER_BASE + 1*NUM_GROUP + 6) +#define FPGA_PIO0_15 (SPI_FPGA_EXPANDER_BASE + 1*NUM_GROUP + 7) + +#define FPGA_PIO1_00 (SPI_FPGA_EXPANDER_BASE + 2*NUM_GROUP + 0) +#define FPGA_PIO1_01 (SPI_FPGA_EXPANDER_BASE + 2*NUM_GROUP + 1) +#define FPGA_PIO1_02 (SPI_FPGA_EXPANDER_BASE + 2*NUM_GROUP + 2) +#define FPGA_PIO1_03 (SPI_FPGA_EXPANDER_BASE + 2*NUM_GROUP + 3) +#define FPGA_PIO1_04 (SPI_FPGA_EXPANDER_BASE + 2*NUM_GROUP + 4) +#define FPGA_PIO1_05 (SPI_FPGA_EXPANDER_BASE + 2*NUM_GROUP + 5) +#define FPGA_PIO1_06 (SPI_FPGA_EXPANDER_BASE + 2*NUM_GROUP + 6) +#define FPGA_PIO1_07 (SPI_FPGA_EXPANDER_BASE + 2*NUM_GROUP + 7) + +#define FPGA_PIO1_08 (SPI_FPGA_EXPANDER_BASE + 3*NUM_GROUP + 0) +#define FPGA_PIO1_09 (SPI_FPGA_EXPANDER_BASE + 3*NUM_GROUP + 1) +#define FPGA_PIO1_10 (SPI_FPGA_EXPANDER_BASE + 3*NUM_GROUP + 2) +#define FPGA_PIO1_11 (SPI_FPGA_EXPANDER_BASE + 3*NUM_GROUP + 3) +#define FPGA_PIO1_12 (SPI_FPGA_EXPANDER_BASE + 3*NUM_GROUP + 4) +#define FPGA_PIO1_13 (SPI_FPGA_EXPANDER_BASE + 3*NUM_GROUP + 5) +#define FPGA_PIO1_14 (SPI_FPGA_EXPANDER_BASE + 3*NUM_GROUP + 6) +#define FPGA_PIO1_15 (SPI_FPGA_EXPANDER_BASE + 3*NUM_GROUP + 7) + +#define FPGA_PIO2_00 (SPI_FPGA_EXPANDER_BASE + 4*NUM_GROUP + 0) +#define FPGA_PIO2_01 (SPI_FPGA_EXPANDER_BASE + 4*NUM_GROUP + 1) +#define FPGA_PIO2_02 (SPI_FPGA_EXPANDER_BASE + 4*NUM_GROUP + 2) +#define FPGA_PIO2_03 (SPI_FPGA_EXPANDER_BASE + 4*NUM_GROUP + 3) +#define FPGA_PIO2_04 (SPI_FPGA_EXPANDER_BASE + 4*NUM_GROUP + 4) +#define FPGA_PIO2_05 (SPI_FPGA_EXPANDER_BASE + 4*NUM_GROUP + 5) +#define FPGA_PIO2_06 (SPI_FPGA_EXPANDER_BASE + 4*NUM_GROUP + 6) +#define FPGA_PIO2_07 (SPI_FPGA_EXPANDER_BASE + 4*NUM_GROUP + 7) + +#define FPGA_PIO2_08 (SPI_FPGA_EXPANDER_BASE + 5*NUM_GROUP + 0) +#define FPGA_PIO2_09 (SPI_FPGA_EXPANDER_BASE + 5*NUM_GROUP + 1) +#define FPGA_PIO2_10 (SPI_FPGA_EXPANDER_BASE + 5*NUM_GROUP + 2) +#define FPGA_PIO2_11 (SPI_FPGA_EXPANDER_BASE + 5*NUM_GROUP + 3) +#define FPGA_PIO2_12 (SPI_FPGA_EXPANDER_BASE + 5*NUM_GROUP + 4) +#define FPGA_PIO2_13 (SPI_FPGA_EXPANDER_BASE + 5*NUM_GROUP + 5) +#define FPGA_PIO2_14 (SPI_FPGA_EXPANDER_BASE + 5*NUM_GROUP + 6) +#define FPGA_PIO2_15 (SPI_FPGA_EXPANDER_BASE + 5*NUM_GROUP + 7) + +#define FPGA_PIO3_00 (SPI_FPGA_EXPANDER_BASE + 6*NUM_GROUP + 0) +#define FPGA_PIO3_01 (SPI_FPGA_EXPANDER_BASE + 6*NUM_GROUP + 1) +#define FPGA_PIO3_02 (SPI_FPGA_EXPANDER_BASE + 6*NUM_GROUP + 2) +#define FPGA_PIO3_03 (SPI_FPGA_EXPANDER_BASE + 6*NUM_GROUP + 3) +#define FPGA_PIO3_04 (SPI_FPGA_EXPANDER_BASE + 6*NUM_GROUP + 4) +#define FPGA_PIO3_05 (SPI_FPGA_EXPANDER_BASE + 6*NUM_GROUP + 5) +#define FPGA_PIO3_06 (SPI_FPGA_EXPANDER_BASE + 6*NUM_GROUP + 6) +#define FPGA_PIO3_07 (SPI_FPGA_EXPANDER_BASE + 6*NUM_GROUP + 7) + +#define FPGA_PIO3_08 (SPI_FPGA_EXPANDER_BASE + 7*NUM_GROUP + 0) +#define FPGA_PIO3_09 (SPI_FPGA_EXPANDER_BASE + 7*NUM_GROUP + 1) +#define FPGA_PIO3_10 (SPI_FPGA_EXPANDER_BASE + 7*NUM_GROUP + 2) +#define FPGA_PIO3_11 (SPI_FPGA_EXPANDER_BASE + 7*NUM_GROUP + 3) +#define FPGA_PIO3_12 (SPI_FPGA_EXPANDER_BASE + 7*NUM_GROUP + 4) +#define FPGA_PIO3_13 (SPI_FPGA_EXPANDER_BASE + 7*NUM_GROUP + 5) +#define FPGA_PIO3_14 (SPI_FPGA_EXPANDER_BASE + 7*NUM_GROUP + 6) +#define FPGA_PIO3_15 (SPI_FPGA_EXPANDER_BASE + 7*NUM_GROUP + 7) + +#define FPGA_PIO4_00 (SPI_FPGA_EXPANDER_BASE + 8*NUM_GROUP + 0) +#define FPGA_PIO4_01 (SPI_FPGA_EXPANDER_BASE + 8*NUM_GROUP + 1) +#define FPGA_PIO4_02 (SPI_FPGA_EXPANDER_BASE + 8*NUM_GROUP + 2) +#define FPGA_PIO4_03 (SPI_FPGA_EXPANDER_BASE + 8*NUM_GROUP + 3) +#define FPGA_PIO4_04 (SPI_FPGA_EXPANDER_BASE + 8*NUM_GROUP + 4) +#define FPGA_PIO4_05 (SPI_FPGA_EXPANDER_BASE + 8*NUM_GROUP + 5) +#define FPGA_PIO4_06 (SPI_FPGA_EXPANDER_BASE + 8*NUM_GROUP + 6) +#define FPGA_PIO4_07 (SPI_FPGA_EXPANDER_BASE + 8*NUM_GROUP + 7) + +#define FPGA_PIO4_08 (SPI_FPGA_EXPANDER_BASE + 9*NUM_GROUP + 0) +#define FPGA_PIO4_09 (SPI_FPGA_EXPANDER_BASE + 9*NUM_GROUP + 1) +#define FPGA_PIO4_10 (SPI_FPGA_EXPANDER_BASE + 9*NUM_GROUP + 2) +#define FPGA_PIO4_11 (SPI_FPGA_EXPANDER_BASE + 9*NUM_GROUP + 3) +#define FPGA_PIO4_12 (SPI_FPGA_EXPANDER_BASE + 9*NUM_GROUP + 4) +#define FPGA_PIO4_13 (SPI_FPGA_EXPANDER_BASE + 9*NUM_GROUP + 5) +#define FPGA_PIO4_14 (SPI_FPGA_EXPANDER_BASE + 9*NUM_GROUP + 6) +#define FPGA_PIO4_15 (SPI_FPGA_EXPANDER_BASE + 9*NUM_GROUP + 7) + +#define FPGA_PIO5_00 (SPI_FPGA_EXPANDER_BASE + 10*NUM_GROUP + 0) +#define FPGA_PIO5_01 (SPI_FPGA_EXPANDER_BASE + 10*NUM_GROUP + 1) +#define FPGA_PIO5_02 (SPI_FPGA_EXPANDER_BASE + 10*NUM_GROUP + 2) +#define FPGA_PIO5_03 (SPI_FPGA_EXPANDER_BASE + 10*NUM_GROUP + 3) +#define FPGA_PIO5_04 (SPI_FPGA_EXPANDER_BASE + 10*NUM_GROUP + 4) +#define FPGA_PIO5_05 (SPI_FPGA_EXPANDER_BASE + 10*NUM_GROUP + 5) +#define FPGA_PIO5_06 (SPI_FPGA_EXPANDER_BASE + 10*NUM_GROUP + 6) +#define FPGA_PIO5_07 (SPI_FPGA_EXPANDER_BASE + 10*NUM_GROUP + 7) + +#define FPGA_PIO5_08 (SPI_FPGA_EXPANDER_BASE + 11*NUM_GROUP + 0) +#define FPGA_PIO5_09 (SPI_FPGA_EXPANDER_BASE + 11*NUM_GROUP + 1) +#define FPGA_PIO5_10 (SPI_FPGA_EXPANDER_BASE + 11*NUM_GROUP + 2) +#define FPGA_PIO5_11 (SPI_FPGA_EXPANDER_BASE + 11*NUM_GROUP + 3) +#define FPGA_PIO5_12 (SPI_FPGA_EXPANDER_BASE + 11*NUM_GROUP + 4) +#define FPGA_PIO5_13 (SPI_FPGA_EXPANDER_BASE + 11*NUM_GROUP + 5) +#define FPGA_PIO5_14 (SPI_FPGA_EXPANDER_BASE + 11*NUM_GROUP + 6) +#define FPGA_PIO5_15 (SPI_FPGA_EXPANDER_BASE + 11*NUM_GROUP + 7) + +#endif + +#if defined(CONFIG_IOEXTEND_TCA6424) +#define TCA6424_P00 (TCA6424_GPIO_EXPANDER_BASE + 0*NUM_GROUP + 0) +#define TCA6424_P01 (TCA6424_GPIO_EXPANDER_BASE + 0*NUM_GROUP + 1) +#define TCA6424_P02 (TCA6424_GPIO_EXPANDER_BASE + 0*NUM_GROUP + 2) +#define TCA6424_P03 (TCA6424_GPIO_EXPANDER_BASE + 0*NUM_GROUP + 3) +#define TCA6424_P04 (TCA6424_GPIO_EXPANDER_BASE + 0*NUM_GROUP + 4) +#define TCA6424_P05 (TCA6424_GPIO_EXPANDER_BASE + 0*NUM_GROUP + 5) +#define TCA6424_P06 (TCA6424_GPIO_EXPANDER_BASE + 0*NUM_GROUP + 6) +#define TCA6424_P07 (TCA6424_GPIO_EXPANDER_BASE + 0*NUM_GROUP + 7) + +#define TCA6424_P10 (TCA6424_GPIO_EXPANDER_BASE + 1*NUM_GROUP + 0) +#define TCA6424_P11 (TCA6424_GPIO_EXPANDER_BASE + 1*NUM_GROUP + 1) +#define TCA6424_P12 (TCA6424_GPIO_EXPANDER_BASE + 1*NUM_GROUP + 2) +#define TCA6424_P13 (TCA6424_GPIO_EXPANDER_BASE + 1*NUM_GROUP + 3) +#define TCA6424_P14 (TCA6424_GPIO_EXPANDER_BASE + 1*NUM_GROUP + 4) +#define TCA6424_P15 (TCA6424_GPIO_EXPANDER_BASE + 1*NUM_GROUP + 5) +#define TCA6424_P16 (TCA6424_GPIO_EXPANDER_BASE + 1*NUM_GROUP + 6) +#define TCA6424_P17 (TCA6424_GPIO_EXPANDER_BASE + 1*NUM_GROUP + 7) + +#define TCA6424_P20 (TCA6424_GPIO_EXPANDER_BASE + 2*NUM_GROUP + 0) +#define TCA6424_P21 (TCA6424_GPIO_EXPANDER_BASE + 2*NUM_GROUP + 1) +#define TCA6424_P22 (TCA6424_GPIO_EXPANDER_BASE + 2*NUM_GROUP + 2) +#define TCA6424_P23 (TCA6424_GPIO_EXPANDER_BASE + 2*NUM_GROUP + 3) +#define TCA6424_P24 (TCA6424_GPIO_EXPANDER_BASE + 2*NUM_GROUP + 4) +#define TCA6424_P25 (TCA6424_GPIO_EXPANDER_BASE + 2*NUM_GROUP + 5) +#define TCA6424_P26 (TCA6424_GPIO_EXPANDER_BASE + 2*NUM_GROUP + 6) +#define TCA6424_P27 (TCA6424_GPIO_EXPANDER_BASE + 2*NUM_GROUP + 7) +#endif + +#if defined(CONFIG_GPIO_WM831X) +#define WM831X_P01 (WM831X_GPIO_EXPANDER_BASE + 0*NUM_GROUP + 0) +#define WM831X_P02 (WM831X_GPIO_EXPANDER_BASE + 0*NUM_GROUP + 1) +#define WM831X_P03 (WM831X_GPIO_EXPANDER_BASE + 0*NUM_GROUP + 2) +#define WM831X_P04 (WM831X_GPIO_EXPANDER_BASE + 0*NUM_GROUP + 3) +#define WM831X_P05 (WM831X_GPIO_EXPANDER_BASE + 0*NUM_GROUP + 4) +#define WM831X_P06 (WM831X_GPIO_EXPANDER_BASE + 0*NUM_GROUP + 5) +#define WM831X_P07 (WM831X_GPIO_EXPANDER_BASE + 0*NUM_GROUP + 6) +#define WM831X_P08 (WM831X_GPIO_EXPANDER_BASE + 0*NUM_GROUP + 7) + +#define WM831X_P09 (WM831X_GPIO_EXPANDER_BASE + 1*NUM_GROUP + 0) +#define WM831X_P10 (WM831X_GPIO_EXPANDER_BASE + 1*NUM_GROUP + 1) +#define WM831X_P11 (WM831X_GPIO_EXPANDER_BASE + 1*NUM_GROUP + 2) +#define WM831X_P12 (WM831X_GPIO_EXPANDER_BASE + 1*NUM_GROUP + 3) +#endif + +#include + +#ifndef __ASSEMBLY__ +static inline int gpio_to_irq(unsigned gpio) +{ + return gpio - PIN_BASE + NR_GIC_IRQS; +} + +static inline int irq_to_gpio(unsigned irq) +{ + return irq - NR_GIC_IRQS + PIN_BASE; +} +#endif /* __ASSEMBLY__ */ + +#endif diff --git a/arch/arm/mach-rk2928/include/mach/io.h b/arch/arm/mach-rk2928/include/mach/io.h new file mode 100644 index 000000000000..6f20120a8d97 --- /dev/null +++ b/arch/arm/mach-rk2928/include/mach/io.h @@ -0,0 +1,188 @@ +#ifndef __MACH_IO_H +#define __MACH_IO_H + +#include + +/* + * RK2928 IO memory map: + * + * Virt Phys Size What + * --------------------------------------------------------------------------- + * FEA00000 10000000 3M + * FED00000 20000000 1M + * FEF00000 0 8K SRAM + */ + +#define RK2928_IO_TO_VIRT0(pa) IOMEM(pa + (0xFEA00000 - 0x10000000)) +#define RK2928_IO_TO_VIRT1(pa) IOMEM(pa + (0xFED00000 - 0x20000000)) + +#define RK2928_IMEM_PHYS 0x10080000 +#define RK2928_IMEM_BASE IOMEM(0xFEF00000) +#define RK2928_IMEM_NONCACHED RK2928_IO_TO_VIRT0(RK2928_IMEM_PHYS) +#define RK2928_IMEM_SIZE SZ_8K + +#define RK2928_GPU_PHYS 0x10090000 +#define RK2928_GPU_SIZE SZ_64K + +#define RK2928_ROM_PHYS 0x10100000 +#define RK2928_ROM_SIZE SZ_16K +#define RK2928_VCODEC_PHYS 0x10104000 +#define RK2928_VCODEC_SIZE SZ_16K + +#define RK2928_CIF_PHYS 0x1010a000 +#define RK2928_CIF_SIZE SZ_8K +#define RK2928_RGA_PHYS 0x1010c000 +#define RK2928_RGA_SIZE SZ_8K +#define RK2928_LCDC_PHYS 0x1010e000 +#define RK2928_LCDC_SIZE SZ_8K + +#define RK2928_CPU_AXI_BUS_PHYS 0x10128000 +#define RK2928_CPU_AXI_BUS_BASE RK2928_IO_TO_VIRT0(RK2928_CPU_AXI_BUS_PHYS) +#define RK2928_CPU_AXI_BUS_SIZE SZ_32K + +#define RK2928_L2C_PHYS 0x10138000 +#define RK2928_L2C_BASE RK2928_IO_TO_VIRT0(RK2928_L2C_PHYS) +#define RK2928_L2C_SIZE SZ_16K +#define RK2928_SCU_PHYS 0x1013c000 +#define RK2928_SCU_BASE RK2928_IO_TO_VIRT0(RK2928_SCU_PHYS) +#define RK2928_SCU_SIZE SZ_256 +#define RK2928_GICC_PHYS 0x1013c100 +#define RK2928_GICC_BASE RK2928_IO_TO_VIRT0(RK2928_GICC_PHYS) +#define RK2928_GICC_SIZE SZ_256 +#define RK2928_GTIMER_PHYS 0x1013c200 +#define RK2928_GTIMER_BASE RK2928_IO_TO_VIRT0(RK2928_GTIMER_PHYS) +#define RK2928_GTIMER_SIZE SZ_1K +#define RK2928_PTIMER_PHYS 0x1013c600 +#define RK2928_PTIMER_BASE RK2928_IO_TO_VIRT0(RK2928_PTIMER_PHYS) +#define RK2928_PTIMER_SIZE (SZ_2K + SZ_512) +#define RK2928_GICD_PHYS 0x1013d000 +#define RK2928_GICD_BASE RK2928_IO_TO_VIRT0(RK2928_GICD_PHYS) +#define RK2928_GICD_SIZE SZ_4K + +#define RK2928_CORE_PHYS RK2928_L2C_PHYS +#define RK2928_CORE_BASE RK2928_IO_TO_VIRT0(RK2928_CORE_PHYS) +#define RK2928_CORE_SIZE (RK2928_L2C_SIZE + SZ_8K) + +#define RK2928_USBOTG20_PHYS 0x10180000 +#define RK2928_USBOTG20_SIZE SZ_256K +#define RK2928_USBHOST20_PHYS 0x101c0000 +#define RK2928_USBHOST20_SIZE SZ_256K + +#define RK2928_SDMMC_PHYS 0x10214000 +#define RK2928_SDMMC_SIZE SZ_16K +#define RK2928_SDIO_PHYS 0x10218000 +#define RK2928_SDIO_SIZE SZ_16K +#define RK2928_EMMC_PHYS 0x1021c000 +#define RK2928_EMMC_SIZE SZ_16K +#define RK2928_I2S_PHYS 0x10220000 +#define RK2928_I2S_SIZE SZ_8K + +#define RK2928_AHB_ARB0_PHYS 0x10234000 +#define RK2928_AHB_ARB0_SIZE SZ_32K +#define RK2928_AHB_ARB1_PHYS 0x1023C000 +#define RK2928_AHB_ARB1_SIZE (784 * SZ_1K) +#define RK2928_PERI_AXI_BUS_PHYS 0x10300000 +#define RK2928_PERI_AXI_BUS_SIZE SZ_1M +#define RK2928_GPS_PHYS 0x10400000 +#define RK2928_GPS_SIZE SZ_1M +#define RK2928_NANDC_PHYS 0x10500000 +#define RK2928_NANDC_SIZE SZ_16K + +#define RK2928_CRU_PHYS 0x20000000 +#define RK2928_CRU_BASE RK2928_IO_TO_VIRT1(RK2928_CRU_PHYS) +#define RK2928_CRU_SIZE SZ_4K +#define RK2928_DDR_PCTL_PHYS 0x20004000 +#define RK2928_DDR_PCTL_BASE RK2928_IO_TO_VIRT1(RK2928_DDR_PCTL_PHYS) +#define RK2928_DDR_PCTL_SIZE SZ_16K +#define RK2928_GRF_PHYS 0x20008000 +#define RK2928_GRF_BASE RK2928_IO_TO_VIRT1(RK2928_GRF_PHYS) +#define RK2928_GRF_SIZE SZ_4K +#define RK2928_DDR_PHY_PHYS 0x2000a000 +#define RK2928_DDR_PHY_BASE RK2928_IO_TO_VIRT1(RK2928_DDR_PHY_PHYS) +#define RK2928_DDR_PHY_SIZE (SZ_16K + SZ_8K) + +#define RK2928_DBG_PHYS 0x20020000 +#define RK2928_DBG_SIZE SZ_64K +#define RK2928_ACODEC_PHYS 0x20030000 +#define RK2928_ACODEC_SIZE SZ_16K +#define RK2928_HDMI_PHYS 0x20034000 +#define RK2928_HDMI_SIZE SZ_16K + +#define RK2928_TIMER0_PHYS 0x20044000 +#define RK2928_TIMER0_BASE RK2928_IO_TO_VIRT1(RK2928_TIMER0_PHYS) +#define RK2928_TIMER0_SIZE SZ_4K +#define RK2928_TIMER1_PHYS 0x20046000 +#define RK2928_TIMER1_BASE RK2928_IO_TO_VIRT1(RK2928_TIMER1_PHYS) +#define RK2928_TIMER1_SIZE SZ_4K + +#define RK2928_WDT_PHYS 0x2004c000 +#define RK2928_WDT_SIZE SZ_4K +#define RK2928_PWM_PHYS 0x20050000 +#define RK2928_PWM_BASE RK2928_IO_TO_VIRT1(RK2928_PWM_PHYS) +#define RK2928_PWM_SIZE SZ_4K + +#define RK2928_I2C1_PHYS 0x20054000 +#define RK2928_I2C1_SIZE SZ_4K +#define RK2928_RKI2C1_PHYS 0x20056000 +#define RK2928_RKI2C1_SIZE SZ_4K +#define RK2928_I2C2_PHYS 0x20058000 +#define RK2928_I2C2_SIZE SZ_4K +#define RK2928_RKI2C2_PHYS 0x2005a000 +#define RK2928_RKI2C2_SIZE SZ_4K +#define RK2928_I2C3_PHYS 0x2005c000 +#define RK2928_I2C3_SIZE SZ_4K +#define RK2928_RKI2C3_PHYS 0x2005e000 +#define RK2928_RKI2C3_SIZE SZ_4K + +#define RK2928_UART0_PHYS 0x20060000 +#define RK2928_UART0_BASE RK2928_IO_TO_VIRT1(RK2928_UART0_PHYS) +#define RK2928_UART0_SIZE SZ_4K +#define RK2928_UART1_PHYS 0x20064000 +#define RK2928_UART1_BASE RK2928_IO_TO_VIRT1(RK2928_UART1_PHYS) +#define RK2928_UART1_SIZE SZ_4K +#define RK2928_UART2_PHYS 0x20068000 +#define RK2928_UART2_BASE RK2928_IO_TO_VIRT1(RK2928_UART2_PHYS) +#define RK2928_UART2_SIZE SZ_4K + +#define RK2928_SARADC_PHYS 0x2006c000 +#define RK2928_SARADC_SIZE SZ_4K +#define RK2928_I2C0_PHYS 0x20070000 +#define RK2928_I2C0_SIZE SZ_4K +#define RK2928_RKI2C0_PHYS 0x20072000 +#define RK2928_RKI2C0_SIZE SZ_4K +#define RK2928_SPI_PHYS 0x20074000 +#define RK2928_SPI_SIZE SZ_16K +#define RK2928_DMAC_PHYS 0x20078000 +#define RK2928_DMAC_SIZE SZ_16K + +#define RK2928_GPIO0_PHYS 0x2007c000 +#define RK2928_GPIO0_BASE RK2928_IO_TO_VIRT1(RK2928_GPIO0_PHYS) +#define RK2928_GPIO0_SIZE SZ_4K +#define RK2928_GPIO1_PHYS 0x20080000 +#define RK2928_GPIO1_BASE RK2928_IO_TO_VIRT1(RK2928_GPIO1_PHYS) +#define RK2928_GPIO1_SIZE SZ_4K +#define RK2928_GPIO2_PHYS 0x20084000 +#define RK2928_GPIO2_BASE RK2928_IO_TO_VIRT1(RK2928_GPIO2_PHYS) +#define RK2928_GPIO2_SIZE SZ_4K +#define RK2928_GPIO3_PHYS 0x20088000 +#define RK2928_GPIO3_BASE RK2928_IO_TO_VIRT1(RK2928_GPIO3_PHYS) +#define RK2928_GPIO3_SIZE SZ_4K + +#define RK2928_EFUSE_PHYS 0x20090000 +#define RK2928_EFUSE_SIZE SZ_4K + +#if CONFIG_RK_DEBUG_UART == 0 +#define DEBUG_UART_PHYS RK2928_UART0_PHYS +#define DEBUG_UART_BASE RK2928_UART0_BASE +#elif CONFIG_RK_DEBUG_UART == 1 +#define DEBUG_UART_PHYS RK2928_UART1_PHYS +#define DEBUG_UART_BASE RK2928_UART1_BASE +#elif CONFIG_RK_DEBUG_UART == 2 +#define DEBUG_UART_PHYS RK2928_UART2_PHYS +#define DEBUG_UART_BASE RK2928_UART2_BASE +#endif + +#define GIC_DIST_BASE RK2928_GICD_BASE +#define GIC_CPU_BASE RK2928_GICC_BASE + +#endif diff --git a/arch/arm/mach-rk2928/include/mach/irqs.h b/arch/arm/mach-rk2928/include/mach/irqs.h new file mode 100644 index 000000000000..34869d5257a0 --- /dev/null +++ b/arch/arm/mach-rk2928/include/mach/irqs.h @@ -0,0 +1,64 @@ +#ifndef __MACH_IRQS_H +#define __MACH_IRQS_H + +#define FIQ_START 0 + +#define IRQ_LOCALTIMER 29 + +#define IRQ_DMAC_0 32 +#define IRQ_DMAC_1 33 +#define IRQ_DDR_PCTL 34 +#define IRQ_GPU_GP 35 +#define IRQ_GPU_MMU 36 +#define IRQ_GPU_PP 37 +#define IRQ_VEPU 38 +#define IRQ_VDPU 39 +#define IRQ_CIF 40 +#define IRQ_LCDC 41 +#define IRQ_USB_OTG 42 +#define IRQ_USB_HOST 43 +#define IRQ_GPS 44 +#define IRQ_GPS_TIMER 45 +#define IRQ_SDMMC 46 +#define IRQ_SDIO 47 +#define IRQ_EMMC 48 +#define IRQ_SARADC 49 +#define IRQ_NANDC 50 +#define IRQ_I2S 51 +#define IRQ_UART0 52 +#define IRQ_UART1 53 +#define IRQ_UART2 54 +#define IRQ_SPI 55 +#define IRQ_I2C0 56 +#define IRQ_I2C1 57 +#define IRQ_I2C2 58 +#define IRQ_I2C3 59 +#define IRQ_TIMER0 60 +#define IRQ_TIMER1 61 +#define IRQ_PWM0 62 +#define IRQ_PWM1 63 +#define IRQ_PWM2 64 + +#define IRQ_WDT 66 +#define IRQ_OTG_BVALID 67 +#define IRQ_GPIO0 68 +#define IRQ_GPIO1 69 +#define IRQ_GPIO2 70 +#define IRQ_GPIO3 71 + +#define IRQ_PERI_AHB_USB_ARBITER 74 +#define IRQ_PERI_AHB_EMEM_ARBITER 75 +#define IRQ_RGA 76 +#define IRQ_HDMI 77 +#define IRQ_SDMMC_DETECT 78 +#define IRQ_SDIO_DETECT 79 + +//hhb@rock-chips.com this spi is used for fiq_debugger signal irq +#define IRQ_UART_SIGNAL 127 + +#define NR_GIC_IRQS (4 * 32) +#define NR_GPIO_IRQS (4 * 32) +#define NR_BOARD_IRQS 64 +#define NR_IRQS (NR_GIC_IRQS + NR_GPIO_IRQS + NR_BOARD_IRQS) + +#endif diff --git a/arch/arm/mach-rk2928/include/mach/memory.h b/arch/arm/mach-rk2928/include/mach/memory.h index 5aa902f91630..268a43bce07f 100644 --- a/arch/arm/mach-rk2928/include/mach/memory.h +++ b/arch/arm/mach-rk2928/include/mach/memory.h @@ -1,6 +1,7 @@ #ifndef __MACH_MEMORY_H #define __MACH_MEMORY_H +#include #include /* diff --git a/arch/arm/mach-rk2928/include/mach/vmalloc.h b/arch/arm/mach-rk2928/include/mach/vmalloc.h new file mode 100644 index 000000000000..f77718234cf3 --- /dev/null +++ b/arch/arm/mach-rk2928/include/mach/vmalloc.h @@ -0,0 +1,6 @@ +#ifndef __MACH_VMALLOC_H +#define __MACH_VMALLOC_H + +#define VMALLOC_END 0xFE800000 + +#endif diff --git a/arch/arm/mach-rk2928/io.c b/arch/arm/mach-rk2928/io.c new file mode 100644 index 000000000000..53e607840337 --- /dev/null +++ b/arch/arm/mach-rk2928/io.c @@ -0,0 +1,62 @@ +/* arch/arm/mach-rk2928/io.c + * + * Copyright (C) 2012 ROCKCHIP, Inc. + * + * 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 +#include +#include + +#include +#include + +#define RK2928_DEVICE(name) { \ + .virtual = (unsigned long) RK2928_##name##_BASE, \ + .pfn = __phys_to_pfn(RK2928_##name##_PHYS), \ + .length = RK2928_##name##_SIZE, \ + .type = MT_DEVICE, \ + } + +static struct map_desc rk2928_io_desc[] __initdata = { + RK2928_DEVICE(CORE), + RK2928_DEVICE(CPU_AXI_BUS), +#if CONFIG_RK_DEBUG_UART == 0 + RK2928_DEVICE(UART0), +#elif CONFIG_RK_DEBUG_UART == 1 + RK2928_DEVICE(UART1), +#elif CONFIG_RK_DEBUG_UART == 2 + RK2928_DEVICE(UART2), +#endif + RK2928_DEVICE(GRF), + RK2928_DEVICE(CRU), + RK2928_DEVICE(GPIO0), + RK2928_DEVICE(GPIO1), + RK2928_DEVICE(GPIO2), + RK2928_DEVICE(GPIO3), + RK2928_DEVICE(TIMER0), + RK2928_DEVICE(TIMER1), + RK2928_DEVICE(PWM), + RK2928_DEVICE(DDR_PCTL), + RK2928_DEVICE(DDR_PHY), + { + .virtual = (unsigned long) RK2928_IMEM_NONCACHED, + .pfn = __phys_to_pfn(RK2928_IMEM_PHYS), + .length = RK2928_IMEM_SIZE, + .type = MT_MEMORY_NONCACHED, + }, +}; + +void __init rk2928_map_common_io(void) +{ + iotable_init(rk2928_io_desc, ARRAY_SIZE(rk2928_io_desc)); +} diff --git a/arch/arm/mach-rk2928/pm.c b/arch/arm/mach-rk2928/pm.c new file mode 100755 index 000000000000..b8bcc0292339 --- /dev/null +++ b/arch/arm/mach-rk2928/pm.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +void __sramfunc sram_printch(char byte) +{ +#ifdef DEBUG_UART_BASE + writel_relaxed(byte, DEBUG_UART_BASE); + dsb(); + + /* loop check LSR[6], Transmitter Empty bit */ + while (!(readl_relaxed(DEBUG_UART_BASE + 0x14) & 0x40)) + barrier(); + + if (byte == '\n') + sram_printch('\r'); +#endif +} + diff --git a/arch/arm/mach-rk2928/reset.c b/arch/arm/mach-rk2928/reset.c new file mode 100644 index 000000000000..24b088e9a1c2 --- /dev/null +++ b/arch/arm/mach-rk2928/reset.c @@ -0,0 +1,11 @@ +#include +#include +#include +#include + +static void rk2928_arch_reset(char mode, const char *cmd) +{ + while (1); +} + +void (*arch_reset)(char, const char *) = rk2928_arch_reset; From cfd51ed06f11277fb63cf97e1bc2a9ba943e4424 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Mon, 9 Jul 2012 17:01:12 +0800 Subject: [PATCH 004/261] rk2928: fpga: add defconfig --- arch/arm/configs/rk2928_fpga_defconfig | 90 ++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 arch/arm/configs/rk2928_fpga_defconfig diff --git a/arch/arm/configs/rk2928_fpga_defconfig b/arch/arm/configs/rk2928_fpga_defconfig new file mode 100644 index 000000000000..cd42707df05d --- /dev/null +++ b/arch/arm/configs/rk2928_fpga_defconfig @@ -0,0 +1,90 @@ +CONFIG_EXPERIMENTAL=y +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_KERNEL_LZO=y +CONFIG_LOG_BUF_SHIFT=19 +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_CGROUP_SCHED=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_PANIC_TIMEOUT=1 +# CONFIG_SYSCTL_SYSCALL is not set +# CONFIG_ELF_CORE is not set +CONFIG_ASHMEM=y +# CONFIG_AIO is not set +CONFIG_EMBEDDED=y +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_ARCH_RK2928=y +# CONFIG_DDR_TEST is not set +CONFIG_RK_DEBUG_UART=0 +CONFIG_MACH_RK2928_FPGA=y +# CONFIG_CACHE_L2X0 is not set +CONFIG_FIQ_DEBUGGER=y +CONFIG_FIQ_DEBUGGER_NO_SLEEP=y +CONFIG_FIQ_DEBUGGER_CONSOLE=y +CONFIG_FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +CONFIG_HIGHMEM=y +CONFIG_COMPACTION=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=32768 +CONFIG_CMDLINE="console=ttyFIQ0 androidboot.console=ttyFIQ0 init=/init debug" +CONFIG_CPU_IDLE=y +CONFIG_WAKELOCK=y +CONFIG_PM_RUNTIME=y +CONFIG_SUSPEND_TIME=y +CONFIG_NET=y +CONFIG_UNIX=y +# CONFIG_NET_ACTIVITY_STATS is not set +# CONFIG_WIRELESS is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_FIRMWARE_IN_KERNEL is not set +CONFIG_MTD=y +CONFIG_MISC_DEVICES=y +# CONFIG_ANDROID_PMEM is not set +CONFIG_INPUT_POLLDEV=y +# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_SERIO is not set +# CONFIG_CONSOLE_TRANSLATIONS is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_ADC is not set +CONFIG_EXPANDED_GPIO_NUM=0 +CONFIG_EXPANDED_GPIO_IRQ_NUM=0 +CONFIG_SPI_FPGA_GPIO_NUM=0 +CONFIG_SPI_FPGA_GPIO_IRQ_NUM=0 +# CONFIG_HWMON is not set +# CONFIG_MFD_SUPPORT is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +CONFIG_RTC_CLASS=y +# CONFIG_CMMB is not set +# CONFIG_DNOTIFY is not set +CONFIG_TMPFS=y +# CONFIG_MISC_FILESYSTEMS is not set +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_PRINTK_TIME=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DETECT_HUNG_TASK=y +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +CONFIG_SLUB_DEBUG_ON=y +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_FTRACE is not set From 009df1d1a53b6fcd76c2b6a998e644218774c19f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Mon, 9 Jul 2012 20:03:06 +0800 Subject: [PATCH 005/261] rk2928: add board-rk2928-fpga.c timer.c, irqs.h add IRQ_DEBUG_UART define --- arch/arm/mach-rk2928/Makefile | 3 + arch/arm/mach-rk2928/board-rk2928-fpga.c | 129 ++++++++++++++ arch/arm/mach-rk2928/include/mach/irqs.h | 3 + arch/arm/mach-rk2928/timer.c | 215 +++++++++++++++++++++++ 4 files changed, 350 insertions(+) create mode 100644 arch/arm/mach-rk2928/board-rk2928-fpga.c create mode 100644 arch/arm/mach-rk2928/timer.c diff --git a/arch/arm/mach-rk2928/Makefile b/arch/arm/mach-rk2928/Makefile index 1f1fe597f457..06e6cae19294 100644 --- a/arch/arm/mach-rk2928/Makefile +++ b/arch/arm/mach-rk2928/Makefile @@ -1,4 +1,7 @@ obj-y += common.o obj-y += io.o obj-y += reset.o +obj-y += timer.o obj-$(CONFIG_PM) += pm.o + +obj-$(CONFIG_MACH_RK2928_FPGA) += board-rk2928-fpga.o diff --git a/arch/arm/mach-rk2928/board-rk2928-fpga.c b/arch/arm/mach-rk2928/board-rk2928-fpga.c new file mode 100644 index 000000000000..029d3accc9d2 --- /dev/null +++ b/arch/arm/mach-rk2928/board-rk2928-fpga.c @@ -0,0 +1,129 @@ +/* arch/arm/mach-rk2928/board-rk2928-fpga.c + * + * Copyright (C) 2012 ROCKCHIP, Inc. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static void __init rk2928_board_init(void) +{ +} + +static void __init rk2928_reserve(void) +{ + board_mem_reserved(); +} + +#include + +struct clk { + const char *name; + unsigned long rate; +}; + +static struct clk xin24m = { + .name = "xin24m", + .rate = 24000000, +}; + +#define CLK(dev, con, ck) \ + { \ + .dev_id = dev, \ + .con_id = con, \ + .clk = ck, \ + } + +static struct clk_lookup clks[] = { + CLK("rk30_i2c.0", "i2c", &xin24m), + CLK("rk30_i2c.1", "i2c", &xin24m), + CLK("rk30_i2c.2", "i2c", &xin24m), + CLK("rk30_i2c.3", "i2c", &xin24m), + CLK("rk29xx_spim.0", "spi", &xin24m), + CLK("rk29xx_spim.1", "spi", &xin24m), +}; + +void __init rk30_clock_init(void) +{ + struct clk_lookup *lk; + + for (lk = clks; lk < clks + ARRAY_SIZE(clks); lk++) { + clkdev_add(lk); + } +} + +int clk_enable(struct clk *clk) +{ + return 0; +} +EXPORT_SYMBOL(clk_enable); + +void clk_disable(struct clk *clk) +{ +} +EXPORT_SYMBOL(clk_disable); + +unsigned long clk_get_rate(struct clk *clk) +{ + return 24000000; +} +EXPORT_SYMBOL(clk_get_rate); + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + return 0; +} +EXPORT_SYMBOL(clk_set_rate); + +int clk_set_parent(struct clk *clk, struct clk *parent) +{ + return 0; +} +EXPORT_SYMBOL(clk_set_parent); + +MACHINE_START(RK2928, "RK2928board") + .boot_params = PLAT_PHYS_OFFSET + 0x800, + .fixup = rk2928_fixup, + .reserve = &rk2928_reserve, + .map_io = rk2928_map_io, + .init_irq = rk2928_init_irq, + .timer = &rk2928_timer, + .init_machine = rk2928_board_init, +MACHINE_END diff --git a/arch/arm/mach-rk2928/include/mach/irqs.h b/arch/arm/mach-rk2928/include/mach/irqs.h index 34869d5257a0..f1bdd00d2cc8 100644 --- a/arch/arm/mach-rk2928/include/mach/irqs.h +++ b/arch/arm/mach-rk2928/include/mach/irqs.h @@ -55,6 +55,9 @@ //hhb@rock-chips.com this spi is used for fiq_debugger signal irq #define IRQ_UART_SIGNAL 127 +#if CONFIG_RK_DEBUG_UART >= 0 && CONFIG_RK_DEBUG_UART < 3 +#define IRQ_DEBUG_UART (IRQ_UART0 + CONFIG_RK_DEBUG_UART) +#endif #define NR_GIC_IRQS (4 * 32) #define NR_GPIO_IRQS (4 * 32) diff --git a/arch/arm/mach-rk2928/timer.c b/arch/arm/mach-rk2928/timer.c new file mode 100644 index 000000000000..1969681c8285 --- /dev/null +++ b/arch/arm/mach-rk2928/timer.c @@ -0,0 +1,215 @@ +/* linux/arch/arm/mach-rk2928/timer.c + * + * Copyright (C) 2012 ROCKCHIP, Inc. + * + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include + +#define TIMER_LOAD_COUNT 0x0000 +#define TIMER_CUR_VALUE 0x0004 +#define TIMER_CONTROL_REG 0x0008 +#define TIMER_EOI 0x000C +#define TIMER_INT_STATUS 0x0010 + +#define TIMER_DISABLE 6 +#define TIMER_ENABLE 3 +#define TIMER_ENABLE_FREE_RUNNING 5 + +static inline void timer_write(u32 n, u32 v, u32 offset) +{ + __raw_writel(v, RK2928_TIMER0_BASE + 0x2000 * n + offset); + dsb(); +} + +static inline u32 timer_read(u32 n, u32 offset) +{ + return __raw_readl(RK2928_TIMER0_BASE + 0x2000 * n + offset); +} + +#define RK_TIMER_ENABLE(n) timer_write(n, TIMER_ENABLE, TIMER_CONTROL_REG) +#define RK_TIMER_ENABLE_FREE_RUNNING(n) timer_write(n, TIMER_ENABLE_FREE_RUNNING, TIMER_CONTROL_REG) +#define RK_TIMER_DISABLE(n) timer_write(n, TIMER_DISABLE, TIMER_CONTROL_REG) + +#define RK_TIMER_SETCOUNT(n, count) timer_write(n, count, TIMER_LOAD_COUNT) +#define RK_TIMER_GETCOUNT(n) timer_read(n, TIMER_LOAD_COUNT) + +#define RK_TIMER_READVALUE(n) timer_read(n, TIMER_CUR_VALUE) +#define RK_TIMER_INT_CLEAR(n) timer_read(n, TIMER_EOI) + +#define RK_TIMER_INT_STATUS(n) timer_read(n, TIMER_INT_STATUS) + +#define TIMER_CLKEVT 0 /* timer0 */ +#define IRQ_NR_TIMER_CLKEVT IRQ_TIMER0 +#define TIMER_CLKEVT_NAME "timer0" + +#define TIMER_CLKSRC 1 /* timer1 */ +#define IRQ_NR_TIMER_CLKSRC IRQ_TIMER1 +#define TIMER_CLKSRC_NAME "timer1" + +static int rk2928_timer_set_next_event(unsigned long cycles, struct clock_event_device *evt) +{ + do { + RK_TIMER_DISABLE(TIMER_CLKEVT); + RK_TIMER_SETCOUNT(TIMER_CLKEVT, cycles); + RK_TIMER_ENABLE(TIMER_CLKEVT); + } while (RK_TIMER_READVALUE(TIMER_CLKEVT) > cycles); + return 0; +} + +static void rk2928_timer_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) +{ + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + rk2928_timer_set_next_event(24000000 / HZ - 1, evt); + break; + case CLOCK_EVT_MODE_RESUME: + case CLOCK_EVT_MODE_ONESHOT: + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + RK_TIMER_DISABLE(TIMER_CLKEVT); + break; + } +} + +static struct clock_event_device rk2928_timer_clockevent = { + .name = TIMER_CLKEVT_NAME, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .rating = 200, + .set_next_event = rk2928_timer_set_next_event, + .set_mode = rk2928_timer_set_mode, +}; + +static irqreturn_t rk2928_timer_clockevent_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + + RK_TIMER_INT_CLEAR(TIMER_CLKEVT); + if (evt->mode == CLOCK_EVT_MODE_ONESHOT) + RK_TIMER_DISABLE(TIMER_CLKEVT); + + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static struct irqaction rk2928_timer_clockevent_irq = { + .name = TIMER_CLKEVT_NAME, + .flags = IRQF_DISABLED | IRQF_TIMER, + .handler = rk2928_timer_clockevent_interrupt, + .irq = IRQ_NR_TIMER_CLKEVT, + .dev_id = &rk2928_timer_clockevent, +}; + +static __init int rk2928_timer_init_clockevent(void) +{ + struct clock_event_device *ce = &rk2928_timer_clockevent; + struct clk *clk = clk_get(NULL, TIMER_CLKEVT_NAME); + struct clk *pclk = clk_get(NULL, "pclk_" TIMER_CLKEVT_NAME); + struct clk *pclk_periph = clk_get(NULL, "pclk_periph"); + + clk_set_parent(clk, pclk_periph); + clk_enable(pclk); + clk_enable(clk); + + RK_TIMER_DISABLE(TIMER_CLKEVT); + + setup_irq(rk2928_timer_clockevent_irq.irq, &rk2928_timer_clockevent_irq); + + ce->irq = rk2928_timer_clockevent_irq.irq; + ce->cpumask = cpu_all_mask; + clockevents_config_and_register(ce, clk_get_rate(clk), 0xF, 0xFFFFFFFF); + + return 0; +} + +static cycle_t rk2928_timer_read(struct clocksource *cs) +{ + return ~RK_TIMER_READVALUE(TIMER_CLKSRC); +} + +#define MASK (u32)~0 + +static struct clocksource rk2928_timer_clocksource = { + .name = TIMER_CLKSRC_NAME, + .rating = 200, + .read = rk2928_timer_read, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static void __init rk2928_timer_init_clocksource(void) +{ + static char err[] __initdata = KERN_ERR "%s: can't register clocksource!\n"; + struct clocksource *cs = &rk2928_timer_clocksource; + struct clk *clk = clk_get(NULL, TIMER_CLKSRC_NAME); + struct clk *pclk = clk_get(NULL, "pclk_" TIMER_CLKSRC_NAME); + struct clk *pclk_periph = clk_get(NULL, "pclk_periph"); + + clk_set_parent(clk, pclk_periph); + clk_enable(pclk); + clk_enable(clk); + + RK_TIMER_DISABLE(TIMER_CLKSRC); + clk_disable(clk); + RK_TIMER_SETCOUNT(TIMER_CLKSRC, 0xFFFFFFFF); + RK_TIMER_ENABLE_FREE_RUNNING(TIMER_CLKSRC); + clk_enable(clk); + + if (clocksource_register_hz(cs, clk_get_rate(clk))) + printk(err, cs->name); +} + +#ifdef CONFIG_HAVE_SCHED_CLOCK +static DEFINE_CLOCK_DATA(cd); + +unsigned long long notrace sched_clock(void) +{ + u32 cyc = ~RK_TIMER_READVALUE(TIMER_CLKSRC); + return cyc_to_sched_clock(&cd, cyc, MASK); +} + +static void notrace rk2928_update_sched_clock(void) +{ + u32 cyc = ~RK_TIMER_READVALUE(TIMER_CLKSRC); + update_sched_clock(&cd, cyc, MASK); +} + +static void __init rk2928_sched_clock_init(void) +{ + init_sched_clock(&cd, rk2928_update_sched_clock, 32, clk_get_rate(clk_get(NULL, TIMER_CLKSRC_NAME))); +} +#endif + +static void __init rk2928_timer_init(void) +{ + rk2928_timer_init_clocksource(); + rk2928_timer_init_clockevent(); +#ifdef CONFIG_HAVE_SCHED_CLOCK + rk2928_sched_clock_init(); +#endif +} + +struct sys_timer rk2928_timer = { + .init = rk2928_timer_init +}; + From 14774179cb6b68d381958fc5467de4252a3e0cb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Tue, 10 Jul 2012 09:32:00 +0800 Subject: [PATCH 006/261] rk2928: fpga: defconfig: enable vfp --- arch/arm/configs/rk2928_fpga_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/rk2928_fpga_defconfig b/arch/arm/configs/rk2928_fpga_defconfig index cd42707df05d..a32edb8795e4 100644 --- a/arch/arm/configs/rk2928_fpga_defconfig +++ b/arch/arm/configs/rk2928_fpga_defconfig @@ -23,6 +23,7 @@ CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_ARCH_RK2928=y # CONFIG_DDR_TEST is not set +# CONFIG_RK29_LAST_LOG is not set CONFIG_RK_DEBUG_UART=0 CONFIG_MACH_RK2928_FPGA=y # CONFIG_CACHE_L2X0 is not set @@ -40,6 +41,7 @@ CONFIG_COMPACTION=y CONFIG_DEFAULT_MMAP_MIN_ADDR=32768 CONFIG_CMDLINE="console=ttyFIQ0 androidboot.console=ttyFIQ0 init=/init debug" CONFIG_CPU_IDLE=y +CONFIG_VFP=y CONFIG_WAKELOCK=y CONFIG_PM_RUNTIME=y CONFIG_SUSPEND_TIME=y From 9e853b76d41df6887c0cf683527dddc0b87c8384 Mon Sep 17 00:00:00 2001 From: kfx Date: Tue, 10 Jul 2012 10:49:34 +0800 Subject: [PATCH 007/261] rk2928: add devices.c --- arch/arm/mach-rk2928/Makefile | 1 + arch/arm/mach-rk2928/devices.c | 39 ++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100755 arch/arm/mach-rk2928/devices.c diff --git a/arch/arm/mach-rk2928/Makefile b/arch/arm/mach-rk2928/Makefile index 06e6cae19294..1ed968ac88d6 100644 --- a/arch/arm/mach-rk2928/Makefile +++ b/arch/arm/mach-rk2928/Makefile @@ -2,6 +2,7 @@ obj-y += common.o obj-y += io.o obj-y += reset.o obj-y += timer.o +obj-y += devices.o obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_MACH_RK2928_FPGA) += board-rk2928-fpga.o diff --git a/arch/arm/mach-rk2928/devices.c b/arch/arm/mach-rk2928/devices.c new file mode 100755 index 000000000000..3da7cfc3f95e --- /dev/null +++ b/arch/arm/mach-rk2928/devices.c @@ -0,0 +1,39 @@ +/* arch/arm/mach-rk30/devices.c + * + * Copyright (C) 2012 ROCKCHIP, Inc. + * + * 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 +#include +#include +#ifdef CONFIG_USB_ANDROID +#include +#endif +#include +#include +#include +#include +#include +#include +#include +//#include +#include + +static int __init rk2928_init_devices(void) +{ +#if defined(CONFIG_FIQ_DEBUGGER) && defined(DEBUG_UART_PHYS) + rk_serial_debug_init(DEBUG_UART_BASE, IRQ_DEBUG_UART, IRQ_UART_SIGNAL, -1); +#endif + return 0; +} +arch_initcall(rk2928_init_devices); From 897f46a57c24bded11d148fb5e694a6cee566371 Mon Sep 17 00:00:00 2001 From: kfx Date: Tue, 10 Jul 2012 11:53:00 +0800 Subject: [PATCH 008/261] rk2928: dma init --- arch/arm/mach-rk2928/devices.c | 78 +++++++++++++++++++++++++++++++++- arch/arm/plat-rk/Makefile | 1 + 2 files changed, 77 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-rk2928/devices.c b/arch/arm/mach-rk2928/devices.c index 3da7cfc3f95e..8a1cac7d6b99 100755 --- a/arch/arm/mach-rk2928/devices.c +++ b/arch/arm/mach-rk2928/devices.c @@ -1,4 +1,4 @@ -/* arch/arm/mach-rk30/devices.c +/* arch/arm/mach-rk2928/devices.c * * Copyright (C) 2012 ROCKCHIP, Inc. * @@ -24,13 +24,87 @@ #include #include #include -#include +#include #include //#include #include + +static u64 dma_dmamask = DMA_BIT_MASK(32); + +static struct resource resource_dmac[] = { + [0] = { + .start = RK2928_DMAC_PHYS, + .end = RK2928_DMAC_PHYS + RK2928_DMAC_SIZE -1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_DMAC_0, + .end = IRQ_DMAC_1, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct rk29_pl330_platdata dmac_pdata = { + .peri = { + [0] = DMACH_I2S0_8CH_TX, + [1] = DMACH_I2S0_8CH_RX, + [2] = DMACH_UART0_TX, + [3] = DMACH_UART0_RX, + [4] = DMACH_UART1_TX, + [5] = DMACH_UART1_RX, + [6] = DMACH_UART2_TX, + [7] = DMACH_UART2_RX, + [8] = DMACH_SPI0_TX, + [9] = DMACH_SPI0_RX, + [10] = DMACH_SDMMC, + [11] = DMACH_SDIO, + [12] = DMACH_EMMC, + [13] = DMACH_DMAC1_MEMTOMEM, + [14] = DMACH_MAX, + [15] = DMACH_MAX, + [16] = DMACH_MAX, + [17] = DMACH_MAX, + [18] = DMACH_MAX, + [19] = DMACH_MAX, + [20] = DMACH_MAX, + [21] = DMACH_MAX, + [22] = DMACH_MAX, + [23] = DMACH_MAX, + [24] = DMACH_MAX, + [25] = DMACH_MAX, + [26] = DMACH_MAX, + [27] = DMACH_MAX, + [28] = DMACH_MAX, + [29] = DMACH_MAX, + [30] = DMACH_MAX, + [31] = DMACH_MAX, + }, +}; + +static struct platform_device device_dmac = { + .name = "rk29-pl330", + .id = -1, + .num_resources = ARRAY_SIZE(resource_dmac), + .resource = resource_dmac, + .dev = { + .dma_mask = &dma_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &dmac_pdata, + }, +}; + +static struct platform_device *rk2928_dmacs[] __initdata = { + &device_dmac, +}; + +static void __init rk2928_init_dma(void) +{ + platform_add_devices(rk2928_dmacs, ARRAY_SIZE(rk2928_dmacs)); +} static int __init rk2928_init_devices(void) { + rk2928_init_dma(); #if defined(CONFIG_FIQ_DEBUGGER) && defined(DEBUG_UART_PHYS) rk_serial_debug_init(DEBUG_UART_BASE, IRQ_DEBUG_UART, IRQ_UART_SIGNAL, -1); #endif diff --git a/arch/arm/plat-rk/Makefile b/arch/arm/plat-rk/Makefile index 1fd707849d73..d6b65428a9ef 100644 --- a/arch/arm/plat-rk/Makefile +++ b/arch/arm/plat-rk/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_RK29_LAST_LOG) += last_log.o obj-$(CONFIG_USB_GADGET) += usb_detect.o obj-$(CONFIG_RK29_VPU) += vpu_service.o obj-$(CONFIG_ARCH_RK30) += dma-pl330.o +obj-$(CONFIG_ARCH_RK2928) += dma-pl330.o obj-$(CONFIG_FIQ) += fiq.o obj-$(CONFIG_FIQ_DEBUGGER) += rk_fiq_debugger.o obj-$(CONFIG_RK_EARLY_PRINTK) += early_printk.o ../kernel/debug.o From b9eb3fa8bb0980e3a736bfebcd5715e83de6487c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Tue, 10 Jul 2012 13:13:32 +0800 Subject: [PATCH 009/261] rk2928: enable RK_PL330_DMA config --- arch/arm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 873f0174c837..fe16128b67b5 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -876,7 +876,7 @@ config ARCH_RK2928 select PLAT_RK select CPU_V7 select ARM_GIC - select PL330 + select RK_PL330_DMA select MIGHT_HAVE_CACHE_L2X0 select ARM_ERRATA_754322 help From 7c348751935c90378db391e273f255c1dbd303e6 Mon Sep 17 00:00:00 2001 From: kfx Date: Wed, 11 Jul 2012 15:13:02 +0800 Subject: [PATCH 010/261] rk2928: iomux init --- arch/arm/mach-rk2928/Makefile | 1 + arch/arm/mach-rk2928/include/mach/iomux.h | 474 ++++++++++++++++++++++ arch/arm/mach-rk2928/iomux.c | 278 +++++++++++++ 3 files changed, 753 insertions(+) create mode 100755 arch/arm/mach-rk2928/include/mach/iomux.h create mode 100755 arch/arm/mach-rk2928/iomux.c diff --git a/arch/arm/mach-rk2928/Makefile b/arch/arm/mach-rk2928/Makefile index 1ed968ac88d6..81ab4330f097 100644 --- a/arch/arm/mach-rk2928/Makefile +++ b/arch/arm/mach-rk2928/Makefile @@ -3,6 +3,7 @@ obj-y += io.o obj-y += reset.o obj-y += timer.o obj-y += devices.o +obj-y += iomux.o obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_MACH_RK2928_FPGA) += board-rk2928-fpga.o diff --git a/arch/arm/mach-rk2928/include/mach/iomux.h b/arch/arm/mach-rk2928/include/mach/iomux.h new file mode 100755 index 000000000000..9bd014bb58fe --- /dev/null +++ b/arch/arm/mach-rk2928/include/mach/iomux.h @@ -0,0 +1,474 @@ +/* + * arch/arm/mach-rk2928/include/mach/iomux.h + * + *Copyright (C) 2010 ROCKCHIP, Inc. + * + * 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. + */ + +#ifndef __RK2928_IOMUX_H__ +#define __RK2928_IOMUX_H__ + +#include + +//gpio0a +#define GPIO0A_GPIO0A0 0 +#define GPIO0A_I2C0_SCL 1 +#define GPIO0A_GPIO0A1 0 +#define GPIO0A_I2C0_SDA 1 +#define GPIO0A_GPIO0A2 0 +#define GPIO0A_I2C1_SCL 1 +#define GPIO0A_GPIO0A3 0 +#define GPIO0A_I2C1_SDA 1 +#define GPIO0A_GPIO0A4 0 +#define GPIO0A_I2C2_SCL 1 +#define GPIO0A_GPIO0A5 0 +#define GPIO0A_I2C2_SDA 1 +#define GPIO0A_GPIO0A6 0 +#define GPIO0A_I2C3_SCL 1 +#define GPIO0A_HDMI_DDCSCL 2 +#define GPIO0A_GPIO0A7 0 +#define GPIO0A_I2C3_SDA 1 +#define GPIO0A_HDMI_DDCSDA 2 + +//gpio0b +#define GPIO0B_GPIO0B0 0 +#define GPIO0B_MMC1_CMD 1 +#define GPIO0B_GPIO0B1 0 +#define GPIO0B_MMC1_CLKOUT 1 +#define GPIO0B_GPIO0B2 0 +#define GPIO0B_MMC1_DETN 1 +#define GPIO0B_GPIO0B3 0 +#define GPIO0B_MMC1_D0 1 +#define GPIO0B_GPIO0B4 0 +#define GPIO0B_MMC1_D1 1 +#define GPIO0B_GPIO0B5 0 +#define GPIO0B_MMC1_D2 1 +#define GPIO0B_GPIO0B6 0 +#define GPIO0B_MMC1_D3 1 +#define GPIO0B_GPIO0B7 0 +#define GPIO0B_HDMI_HOTPLUGIN 1 + +//gpio0c +#define GPIO0C_GPIO0C0 0 +#define GPIO0C_UART0_SOUT 1 +#define GPIO0C_GPIO0C1 0 +#define GPIO0C_UART0_SIN 1 +#define GPIO0C_GPIO0C2 0 +#define GPIO0C_UART0_RTSN 1 +#define GPIO0C_GPIO0C3 0 +#define GPIO0C_UART0_CTSN 1 +#define GPIO0C_GPIO0C4 0 +#define GPIO0C_HDMI_CECSDA 1 +#define GPIO0C_GPIO0C7 0 +#define GPIO0C_NAND_CS1 1 + +//gpio0d +#define GPIO0D_GPIO0D0 0 +#define GPIO0D_UART2_RTSN 1 +#define GPIO0D_GPIO0D1 0 +#define GPIO0D_UART2_CTSN 1 +#define GPIO0D_GPIO0D2 0 +#define GPIO0D_PWM_0 1 +#define GPIO0D_GPIO0D3 0 +#define GPIO0D_PWM_1 1 +#define GPIO0D_GPIO0D4 0 +#define GPIO0D_PWM_2 1 +#define GPIO0D_GPIO0D5 0 +#define GPIO0D_MMC1_WRPRT 1 +#define GPIO0D_GPIO0D6 0 +#define GPIO0D_MC1_PWREN 1 +#define GPIO0D_GPIO0D7 0 +#define GPIO0D_MMC1_BKEPWR 1 + +//gpio1a +#define GPIO1A_GPIO1A0 0 +#define GPIO1A_I2S_MCLK 1 +#define GPIO1A_GPIO1A1 0 +#define GPIO1A_I2S_SCLK 1 +#define GPIO1A_GPIO1A2 0 +#define GPIO1A_I2S_LRCKRX 1 +#define GPIO1A_GPIO1A3 0 +#define GPIO1A_I2S_LRCKTX 1 +#define GPIO1A_GPIO1A4 0 +#define GPIO1A_I2S_SDO 1 +#define GPIO1A_GPIO1A5 0 +#define GPIO1A_I2S_SDI 1 +#define GPIO1A_GPIO1A6 0 +#define GPIO1A_MMC1_INTN 1 +#define GPIO1A_GPIO1A7 0 +#define GPIO1A_MMC0_WRPRT 1 + +//gpio1b +#define GPIO1B_GPIO1B0 0 +#define GPIO1B_SPI_CLK 1 +#define GPIO1B_GPS_CLK 2 +#define GPIO1B_GPIO1B1 0 +#define GPIO1B_SPI_TXD 1 +#define GPIO1B_UART1_SOUT 2 +#define GPIO1B_GPS_MAG 3 +#define GPIO1B_GPIO1B2 0 +#define GPIO1B_SPI_RXD 1 +#define GPIO1B_UART1_SIN 2 +#define GPIO1B_GPS_SIGN 3 +#define GPIO1B_GPIO1B3 0 +#define GPIO1B_SPI_CSN0 1 +#define GPIO1B_UART1_RTSN 2 +#define GPIO1B_GPIO1B4 0 +#define GPIO1B_SPI_CSN1 1 +#define GPIO1B_UART1_CTSN 2 +#define GPIO1B_GPIO1B5 0 +#define GPIO1B_MMC0_RSTNOUT 1 +#define GPIO1B_GPIO1B6 0 +#define GPIO1B_MMC0_PWREN 1 +#define GPIO1B_GPIO1B7 0 +#define GPIO1B_MMC0_CMD 1 + +//gpio1c +#define GPIO1C_GPIO1C0 0 +#define GPIO1C_MMC0_CLKOUT 1 +#define GPIO1C_GPIO1C1 0 +#define GPIO1C_MMC0_DETN 1 +#define GPIO1C_GPIO1C2 0 +#define GPIO1C_MMC0_D0 1 +#define GPIO1C_GPIO1C3 0 +#define GPIO1C_MMC0_D1 1 +#define GPIO1C_GPIO1C4 0 +#define GPIO1C_MMC0_D2 1 +#define GPIO1C_GPIO1C5 0 +#define GPIO1C_MMC0_D3 1 +#define GPIO1C_GPIO1C6 0 +#define GPIO1C_NAND_CS2 1 +#define GPIO1C_GPIO1C7 0 +#define GPIO1C_NAND_CS3 1 + +//gpio1d +#define GPIO1D_GPIO1D0 0 +#define GPIO1D_NAND_D0 1 +#define GPIO1D_EMMC_D0 2 +#define GPIO1D_GPIO1D1 0 +#define GPIO1D_NAND_D1 1 +#define GPIO1D_EMMC_D1 2 +#define GPIO1D_GPIO1D2 0 +#define GPIO1D_NAND_D2 1 +#define GPIO1D_EMMC_D2 2 +#define GPIO1D_GPIO1D3 0 +#define GPIO1D_NAND_D3 1 +#define GPIO1D_EMMC_D3 2 +#define GPIO1D_GPIO1D4 0 +#define GPIO1D_NAND_D4 1 +#define GPIO1D_EMMC_D4 2 +#define GPIO1D_GPIO1D5 0 +#define GPIO1D_NAND_D5 1 +#define GPIO1D_EMMC_D5 2 +#define GPIO1D_GPIO1D6 0 +#define GPIO1D_NAND_D6 1 +#define GPIO1D_EMMC_D6 2 +#define GPIO1D_GPIO1D7 0 +#define GPIO1D_NAND_D7 1 +#define GPIO1D_EMMC_D7 2 + +//gpio2a +#define GPIO2A_GPIO2A0 0 +#define GPIO2A_NAND_ALE 1 +#define GPIO2A_GPIO2A1 0 +#define GPIO2A_NAND_CLE 1 +#define GPIO2A_GPIO2A2 0 +#define GPIO2A_NAND_WRN 1 +#define GPIO2A_GPIO2A3 0 +#define GPIO2A_NAND_RDN 1 +#define GPIO2A_GPIO2A4 0 +#define GPIO2A_NAND_RDY 1 +#define GPIO2A_EMMC_RSTNOUT 2 +#define GPIO2A_GPIO2A5 0 +#define GPIO2A_NAND_WP 1 +#define GPIO2A_EMMC_PWREN 2 +#define GPIO2A_GPIO2A6 0 +#define GPIO2A_NAND_CS0 1 +#define GPIO2A_EMMC_CMD 2 +#define GPIO2A_GPIO2A7 0 +#define GPIO2A_NAND_DPS 1 +#define GPIO2A_EMMC_CLKOUT 2 + +//gpio2b +#define GPIO2B_GPIO2B0 0 +#define GPIO2B_LCDC0_DCLK 1 +#define GPIO2B_LCDC1_DCLK 2 +#define GPIO2B_GPIO2B1 0 +#define GPIO2B_LCDC0_HSYNC 1 +#define GPIO2B_LCDC1_HSYNC 2 +#define GPIO2B_GPIO2B2 0 +#define GPIO2B_LCDC0_VSYNC 1 +#define GPIO2B_LCDC1_VSYNC 2 +#define GPIO2B_GPIO2B3 0 +#define GPIO2B_LCDC0_DEN 1 +#define GPIO2B_LCDC1_DEN 2 +#define GPIO2B_GPIO2B4 0 +#define GPIO2B_LCDC0_D10 1 +#define GPIO2B_LCDC1_D10 2 +#define GPIO2B_GPIO2B5 0 +#define GPIO2B_LCDC0_D11 1 +#define GPIO2B_LCDC1_D11 2 +#define GPIO2B_GPIO2B6 0 +#define GPIO2B_LCDC0_D12 1 +#define GPIO2B_LCDC1_D12 2 +#define GPIO2B_GPIO2B7 0 +#define GPIO2B_LCDC0_D13 1 +#define GPIO2B_LCDC1_D13 2 + +//gpio2c +#define GPIO2C_GPIO2C0 0 +#define GPIO2C_LCDC0_D14 1 +#define GPIO2C_LCDC1_D14 2 +#define GPIO2C_GPIO2C1 0 +#define GPIO2C_LCDC0_D15 1 +#define GPIO2C_LCDC1_D15 2 +#define GPIO2C_GPIO2C2 0 +#define GPIO2C_LCDC0_D16 1 +#define GPIO2C_LCDC1_D16 2 +#define GPIO2C_GPIO2C3 0 +#define GPIO2C_LCDC0_D17 1 +#define GPIO2C_LCDC1_D17 2 +#define GPIO2C_GPIO2C4 0 +#define GPIO2C_LCDC0_D18 1 +#define GPIO2C_LCDC1_D18 2 +#define GPIO2C_GPIO2C5 0 +#define GPIO2C_LCDC0_D19 1 +#define GPIO2C_LCDC1_D19 2 +#define GPIO2C_GPIO2C6 0 +#define GPIO2C_LCDC0_D20 1 +#define GPIO2C_LCDC1_D20 2 +#define GPIO2C_GPIO2C7 0 +#define GPIO2C_LCDC0_D21 1 +#define GPIO2C_LCDC1_D21 2 + +//gpio2d +#define GPIO2D_GPIO2D0 0 +#define GPIO2D_LCDC0_D23 1 +#define GPIO2D_LCDC1_D23 2 +#define GPIO2D_UART2_SOUT 3 +#define GPIO2D_GPIO2D1 0 +#define GPIO2D_LCDC0_D23 1 +#define GPIO2D_LCDC1_D23 2 +#define GPIO2D_UART2_SIN 3 + +//gpio3d +#define GPIO3D_GPIO3D7 0 +#define GPIO3D_TESTCLK_OUT 1 + + + +//gpio0a +#define GPIO0A0_I2C0_SCL_NAME "gpio0a0_i2c0_scl_name" +#define GPIO0A1_I2C0_SDA_NAME "gpio0a1_i2c0_sda_name" +#define GPIO0A2_I2C1_SCL_NAME "gpio0a2_i2c1_scl_name" +#define GPIO0A3_I2C1_SDA_NAME "gpio0a3_i2c1_sda_name" +#define GPIO0A4_I2C2_SCL_NAME "gpio0a4_i2c2_scl_name" +#define GPIO0A5_I2C2_SDA_NAME "gpio0a5_i2c2_sda_name" +#define GPIO0A6_I2C3_SCL_HDMI_DDCSCL_NAME "gpio0a6_i2c3_scl_hdmi_ddcscl_name" +#define GPIO0A7_I2C3_SDA_HDMI_DDCSDA_NAME "gpio0a7_i2c3_sda_hdmi_ddcsda_name" + +//gpio0b +#define GPIO0B0_MMC1_CMD_NAME "gpio0b0_mmc1_cmd_name" +#define GPIO0B1_MMC1_CLKOUT_NAME "gpio0b1_mmc1_clkout_name" +#define GPIO0B2_MMC1_DETN_NAME "gpio0b2_mmc1_detn_name" +#define GPIO0B3_MMC1_D0_NAME "gpio0b3_mmc1_d0_name" +#define GPIO0B4_MMC1_D1_NAME "gpio0b4_mmc1_d1_name" +#define GPIO0B5_MMC1_D2_NAME "gpio0b5_mmc1_d2_name" +#define GPIO0B6_MMC1_D3_NAME "gpio0b6_mmc1_d3_name" +#define GPIO0B7_HDMI_HOTPLUGIN_NAME "gpio0b7_hdmi_hotplugin_name" + +//gpio0c +#define GPIO0C0_UART0_SOUT_NAME "gpio0c0_uart0_sout_name" +#define GPIO0C1_UART0_SIN_NAME "gpio0c1_uart0_sin_name" +#define GPIO0C2_UART0_RTSN_NAME "gpio0c2_uart0_rtsn_name" +#define GPIO0C3_UART0_CTSN_NAME "gpio0c3_uart0_ctsn_name" +#define GPIO0C4_HDMI_CECSDA_NAME "gpio0c4_hdmi_cecsda_name" +#define GPIO0C7_NAND_CS1_NAME "gpio0c7_nand_cs1_name" + +//gpio0d +#define GPIO0D0_UART2_RTSN_NAME "gpio0d0_uart2_rtsn_name" +#define GPIO0D1_UART2_CTSN_NAME "gpio0d1_uart2_ctsn_name" +#define GPIO0D2_PWM_0_NAME "gpio0d2_pwm_0_name" +#define GPIO0D3_PWM_1_NAME "gpio0d3_pwm_1_name" +#define GPIO0D4_PWM_2_NAME "gpio0d4_pwm_2_name" +#define GPIO0D5_MMC1_WRPRT_NAME "gpio0d5_mmc1_wrprt_name" +#define GPIO0D6_MC1_PWREN_NAME "gpio0d6_mc1_pwren_name" +#define GPIO0D7_MMC1_BKEPWR_NAME "gpio0d7_mmc1_bkepwr_name" + +//gpio1a +#define GPIO1A0_I2S_MCLK_NAME "gpio1a0_i2s_mclk_name" +#define GPIO1A1_I2S_SCLK_NAME "gpio1a1_i2s_sclk_name" +#define GPIO1A2_I2S_LRCKRX_NAME "gpio1a2_i2s_lrckrx_name" +#define GPIO1A3_I2S_LRCKTX_NAME "gpio1a3_i2s_lrcktx_name" +#define GPIO1A4_I2S_SDO_NAME "gpio1a4_i2s_sdo_name" +#define GPIO1A5_I2S_SDI_NAME "gpio1a5_i2s_sdi_name" +#define GPIO1A6_MMC1_INTN_NAME "gpio1a6_mmc1_intn_name" +#define GPIO1A7_MMC0_WRPRT_NAME "gpio1a7_mmc0_wrprt_name" + +//gpio1b +#define GPIO1B0_SPI_CLK_GPS_CLK_NAME "gpio1b0_spi_clk_gps_clk_name" +#define GPIO1B1_SPI_TXD_UART1_SOUT_GPS_MAG_NAME "gpio1b1_spi_txd_uart1_sout_gps_mag_name" +#define GPIO1B2_SPI_RXD_UART1_SIN_GPS_SIGN_NAME "gpio1b2_spi_rxd_uart1_sin_gps_sign_name" +#define GPIO1B3_SPI_CSN0_UART1_RTSN_NAME "gpio1b3_spi_csn0_uart1_rtsn_name" +#define GPIO1B4_SPI_CSN1_UART1_CTSN_NAME "gpio1b4_spi_csn1_uart1_ctsn_name" +#define GPIO1B5_MMC0_RSTNOUT_NAME "gpio1b5_mmc0_rstnout_name" +#define GPIO1B6_MMC0_PWREN_NAME "gpio1b6_mmc0_pwren_name" +#define GPIO1B7_MMC0_CMD_NAME "gpio1b7_mmc0_cmd_name" + +//gpio1c +#define GPIO1C0_MMC0_CLKOUT_NAME "gpio1c0_mmc0_clkout_name" +#define GPIO1C1_MMC0_DETN_NAME "gpio1c1_mmc0_detn_name" +#define GPIO1C2_MMC0_D0_NAME "gpio1c2_mmc0_d0_name" +#define GPIO1C3_MMC0_D1_NAME "gpio1c3_mmc0_d1_name" +#define GPIO1C4_MMC0_D2_NAME "gpio1c4_mmc0_d2_name" +#define GPIO1C5_MMC0_D3_NAME "gpio1c5_mmc0_d3_name" +#define GPIO1C6_NAND_CS2_NAME "gpio1c6_nand_cs2_name" +#define GPIO1C7_NAND_CS3_NAME "gpio1c7_nand_cs3_name" + +//gpio1d +#define GPIO1D0_NAND_D0_EMMC_D0_NAME "gpio1d0_nand_d0_emmc_d0_name" +#define GPIO1D1_NAND_D1_EMMC_D1_NAME "gpio1d1_nand_d1_emmc_d1_name" +#define GPIO1D2_NAND_D2_EMMC_D2_NAME "gpio1d2_nand_d2_emmc_d2_name" +#define GPIO1D3_NAND_D3_EMMC_D3_NAME "gpio1d3_nand_d3_emmc_d3_name" +#define GPIO1D4_NAND_D4_EMMC_D4_NAME "gpio1d4_nand_d4_emmc_d4_name" +#define GPIO1D5_NAND_D5_EMMC_D5_NAME "gpio1d5_nand_d5_emmc_d5_name" +#define GPIO1D6_NAND_D6_EMMC_D6_NAME "gpio1d6_nand_d6_emmc_d6_name" +#define GPIO1D7_NAND_D7_EMMC_D7_NAME "gpio1d7_nand_d7_emmc_d7_name" + +//gpio2a +#define GPIO2A0_NAND_ALE_NAME "gpio2a0_nand_ale_name" +#define GPIO2A1_NAND_CLE_NAME "gpio2a1_nand_cle_name" +#define GPIO2A2_NAND_WRN_NAME "gpio2a2_nand_wrn_name" +#define GPIO2A3_NAND_RDN_NAME "gpio2a3_nand_rdn_name" +#define GPIO2A4_NAND_RDY_EMMC_RSTNOUT_NAME "gpio2a4_nand_rdy_emmc_rstnout_name" +#define GPIO2A5_NAND_WP_EMMC_PWREN_NAME "gpio2a5_nand_wp_emmc_pwren_name" +#define GPIO2A6_NAND_CS0_EMMC_CMD_NAME "gpio2a6_nand_cs0_emmc_cmd_name" +#define GPIO2A7_NAND_DPS_EMMC_CLKOUT_NAME "gpio2a7_nand_dps_emmc_clkout_name" + +//gpio2b +#define GPIO2B0_LCDC0_DCLK_LCDC1_DCLK_NAME "gpio2b0_lcdc0_dclk_lcdc1_dclk_name" +#define GPIO2B1_LCDC0_HSYNC_LCDC1_HSYNC_NAME "gpio2b1_lcdc0_hsync_lcdc1_hsync_name" +#define GPIO2B2_LCDC0_VSYNC_LCDC1_VSYNC_NAME "gpio2b2_lcdc0_vsync_lcdc1_vsync_name" +#define GPIO2B3_LCDC0_DEN_LCDC1_DEN_NAME "gpio2b3_lcdc0_den_lcdc1_den_name" +#define GPIO2B4_LCDC0_D10_LCDC1_D10_NAME "gpio2b4_lcdc0_d10_lcdc1_d10_name" +#define GPIO2B5_LCDC0_D11_LCDC1_D11_NAME "gpio2b5_lcdc0_d11_lcdc1_d11_name" +#define GPIO2B6_LCDC0_D12_LCDC1_D12_NAME "gpio2b6_lcdc0_d12_lcdc1_d12_name" +#define GPIO2B7_LCDC0_D13_LCDC1_D13_NAME "gpio2b7_lcdc0_d13_lcdc1_d13_name" + +//gpio2c +#define GPIO2C0_LCDC0_D14_LCDC1_D14_NAME "gpio2c0_lcdc0_d14_lcdc1_d14_name" +#define GPIO2C1_LCDC0_D15_LCDC1_D15_NAME "gpio2c1_lcdc0_d15_lcdc1_d15_name" +#define GPIO2C2_LCDC0_D16_LCDC1_D16_NAME "gpio2c2_lcdc0_d16_lcdc1_d16_name" +#define GPIO2C3_LCDC0_D17_LCDC1_D17_NAME "gpio2c3_lcdc0_d17_lcdc1_d17_name" +#define GPIO2C4_LCDC0_D18_LCDC1_D18_NAME "gpio2c4_lcdc0_d18_lcdc1_d18_name" +#define GPIO2C5_LCDC0_D19_LCDC1_D19_NAME "gpio2c5_lcdc0_d19_lcdc1_d19_name" +#define GPIO2C6_LCDC0_D20_LCDC1_D20_NAME "gpio2c6_lcdc0_d20_lcdc1_d20_name" +#define GPIO2C7_LCDC0_D21_LCDC1_D21_NAME "gpio2c7_lcdc0_d21_lcdc1_d21_name" + +//gpio2d +#define GPIO2D0_LCDC0_D23_LCDC1_D23_UART2_SOUT_NAME "gpio2d0_lcdc0_d23_lcdc1_d23_uart2_sout_name" +#define GPIO2D1_LCDC0_D23_LCDC1_D23_UART2_SIN_NAME "gpio2d1_lcdc0_d23_lcdc1_d23_uart2_sin_name" + +//gpio3d +#define GPIO3D7_TESTCLK_OUT_NAME "gpio3d7_testclk_out_name" + + +#define DEFAULT 0 +#define INITIAL 1 + +#define GRF_GPIO0A_IOMUX RK2928_GRF_BASE+0x00a8 +#define GRF_GPIO0B_IOMUX RK2928_GRF_BASE+0x00ac +#define GRF_GPIO0C_IOMUX RK2928_GRF_BASE+0x00b0 +#define GRF_GPIO0D_IOMUX RK2928_GRF_BASE+0x00b4 + +#define GRF_GPIO1A_IOMUX RK2928_GRF_BASE+0x00b8 +#define GRF_GPIO1B_IOMUX RK2928_GRF_BASE+0x00bc +#define GRF_GPIO1C_IOMUX RK2928_GRF_BASE+0x00c0 +#define GRF_GPIO1D_IOMUX RK2928_GRF_BASE+0x00c4 + +#define GRF_GPIO2A_IOMUX RK2928_GRF_BASE+0x00c8 +#define GRF_GPIO2B_IOMUX RK2928_GRF_BASE+0x00cc +#define GRF_GPIO2C_IOMUX RK2928_GRF_BASE+0x00d0 +#define GRF_GPIO2D_IOMUX RK2928_GRF_BASE+0x00d4 + +#define GRF_GPIO3D_IOMUX RK2928_GRF_BASE+0x00e4 + +#define GRF_GPIO0L_PULL 0x0118 +#define GRF_GPIO0H_PULL 0x011c + +#define GRF_GPIO1L_PULL 0x0120 +#define GRF_GPIO1H_PULL 0x0124 + +#define GRF_GPIO2L_PULL 0x0128 +#define GRF_GPIO2H_PULL 0x012c + +#define GRF_GPIO3L_PULL 0x0130 +#define GRF_GPIO3H_PULL 0x0134 + +#define GRF_SOC_CON0 0x0140 +#define GRF_SOC_CON1 0x0144 +#define GRF_SOC_CON2 0x0148 + +#define GRF_SOC_STATUS0 0x014c + +#define GRF_LVDS_CON0 0x0150 + +#define GRF_DMAC1_CON0 0x015c +#define GRF_DMAC1_CON1 0x0160 +#define GRF_DMAC1_CON2 0x0164 + +#define GRF_UOC0_CON0 0x016c +#define GRF_UOC0_CON1 0x0170 +#define GRF_UOC0_CON2 0x0174 +#define GRF_UOC0_CON3 0x0178 +#define GRF_UOC0_CON5 0x017c + +#define GRF_UOC1_CON0 0x0180 +#define GRF_UOC1_CON1 0x0184 +#define GRF_UOC1_CON2 0x0188 +#define GRF_UOC1_CON3 0x018c +#define GRF_UOC1_CON4 0x0190 +#define GRF_UOC1_CON5 0x0194 + +#define GRF_DDRC_STAT 0x019c + +#define GRF_OS_REG0 0x01c8 +#define GRF_OS_REG1 0x01cc +#define GRF_OS_REG2 0x01d0 +#define GRF_OS_REG3 0x01d4 + +#define MUX_CFG(desc,reg,off,interl,mux_mode,bflags) \ +{ \ + .name = desc, \ + .offset = off, \ + .interleave = interl, \ + .mux_reg = GRF_##reg##_IOMUX, \ + .mode = mux_mode, \ + .premode = mux_mode, \ + .flags = bflags, \ +}, + +struct mux_config { + char *name; + const unsigned int offset; + unsigned int mode; + unsigned int premode; + const void* __iomem mux_reg; + const unsigned int interleave; + unsigned int flags; +}; +#define rk29_mux_api_set rk30_mux_api_set + +extern int __init rk30_iomux_init(void); +extern void rk30_mux_api_set(char *name, unsigned int mode); +extern int rk30_mux_api_get(char *name); + +#endif diff --git a/arch/arm/mach-rk2928/iomux.c b/arch/arm/mach-rk2928/iomux.c new file mode 100755 index 000000000000..44968e1b25b9 --- /dev/null +++ b/arch/arm/mach-rk2928/iomux.c @@ -0,0 +1,278 @@ +/* + * arch/arm/mach-rk2928/iomux.c + * + *Copyright (C) 2010 ROCKCHIP, Inc. + * + * 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 +#include +#include +#include +#include + +#include +#include + +//#define IOMUX_DBG + +static struct mux_config rk30_muxs[] = { +/* + * description mux mode mux mux + * reg offset inter mode + */ +//gpio0a +MUX_CFG(GPIO0A0_I2C0_SCL_NAME, GPIO0A, 0, 1, 0, DEFAULT) +MUX_CFG(GPIO0A1_I2C0_SDA_NAME, GPIO0A, 2, 1, 0, DEFAULT) +MUX_CFG(GPIO0A2_I2C1_SCL_NAME, GPIO0A, 4, 1, 0, DEFAULT) +MUX_CFG(GPIO0A3_I2C1_SDA_NAME, GPIO0A, 6, 1, 0, DEFAULT) +MUX_CFG(GPIO0A4_I2C2_SCL_NAME, GPIO0A, 8, 1, 0, DEFAULT) +MUX_CFG(GPIO0A5_I2C2_SDA_NAME, GPIO0A, 10, 1, 0, DEFAULT) +MUX_CFG(GPIO0A6_I2C3_SCL_HDMI_DDCSCL_NAME, GPIO0A, 12, 2, 0, DEFAULT) +MUX_CFG(GPIO0A7_I2C3_SDA_HDMI_DDCSDA_NAME, GPIO0A, 14, 2, 0, DEFAULT) + +//gpio0b +MUX_CFG(GPIO0B0_MMC1_CMD_NAME, GPIO0B, 0, 1, 0, DEFAULT) +MUX_CFG(GPIO0B1_MMC1_CLKOUT_NAME, GPIO0B, 2, 1, 0, DEFAULT) +MUX_CFG(GPIO0B2_MMC1_DETN_NAME, GPIO0B, 4, 1, 0, DEFAULT) +MUX_CFG(GPIO0B3_MMC1_D0_NAME, GPIO0B, 6, 1, 0, DEFAULT) +MUX_CFG(GPIO0B4_MMC1_D1_NAME, GPIO0B, 8, 1, 0, DEFAULT) +MUX_CFG(GPIO0B5_MMC1_D2_NAME, GPIO0B, 10, 1, 0, DEFAULT) +MUX_CFG(GPIO0B6_MMC1_D3_NAME, GPIO0B, 12, 1, 0, DEFAULT) +MUX_CFG(GPIO0B7_HDMI_HOTPLUGIN_NAME, GPIO0B, 14, 1, 0, DEFAULT) + +//gpio0c +MUX_CFG(GPIO0C0_UART0_SOUT_NAME, GPIO0C, 0, 1, 0, DEFAULT) +MUX_CFG(GPIO0C1_UART0_SIN_NAME, GPIO0C, 2, 1, 0, DEFAULT) +MUX_CFG(GPIO0C2_UART0_RTSN_NAME, GPIO0C, 4, 1, 0, DEFAULT) +MUX_CFG(GPIO0C3_UART0_CTSN_NAME, GPIO0C, 6, 1, 0, DEFAULT) +MUX_CFG(GPIO0C4_HDMI_CECSDA_NAME, GPIO0C, 8, 1, 0, DEFAULT) +MUX_CFG(GPIO0C7_NAND_CS1_NAME, GPIO0C, 14, 1, 0, DEFAULT) + +//gpio0d +MUX_CFG(GPIO0D0_UART2_RTSN_NAME, GPIO0D, 0, 1, 0, DEFAULT) +MUX_CFG(GPIO0D1_UART2_CTSN_NAME, GPIO0D, 2, 1, 0, DEFAULT) +MUX_CFG(GPIO0D2_PWM_0_NAME, GPIO0D, 4, 1, 0, DEFAULT) +MUX_CFG(GPIO0D3_PWM_1_NAME, GPIO0D, 6, 1, 0, DEFAULT) +MUX_CFG(GPIO0D4_PWM_2_NAME, GPIO0D, 8, 1, 0, DEFAULT) +MUX_CFG(GPIO0D5_MMC1_WRPRT_NAME, GPIO0D, 10, 1, 0, DEFAULT) +MUX_CFG(GPIO0D6_MC1_PWREN_NAME, GPIO0D, 12, 1, 0, DEFAULT) +MUX_CFG(GPIO0D7_MMC1_BKEPWR_NAME, GPIO0D, 14, 1, 0, DEFAULT) + +//gpio1a +MUX_CFG(GPIO1A0_I2S_MCLK_NAME, GPIO1A, 0, 1, 0, DEFAULT) +MUX_CFG(GPIO1A1_I2S_SCLK_NAME, GPIO1A, 2, 1, 0, DEFAULT) +MUX_CFG(GPIO1A2_I2S_LRCKRX_NAME, GPIO1A, 4, 1, 0, DEFAULT) +MUX_CFG(GPIO1A3_I2S_LRCKTX_NAME, GPIO1A, 6, 1, 0, DEFAULT) +MUX_CFG(GPIO1A4_I2S_SDO_NAME, GPIO1A, 8, 1, 0, DEFAULT) +MUX_CFG(GPIO1A5_I2S_SDI_NAME, GPIO1A, 10, 1, 0, DEFAULT) +MUX_CFG(GPIO1A6_MMC1_INTN_NAME, GPIO1A, 12, 1, 0, DEFAULT) +MUX_CFG(GPIO1A7_MMC0_WRPRT_NAME, GPIO1A, 14, 1, 0, DEFAULT) + +//gpio1b +MUX_CFG(GPIO1B0_SPI_CLK_GPS_CLK_NAME, GPIO1B, 0, 2, 0, DEFAULT) +MUX_CFG(GPIO1B1_SPI_TXD_UART1_SOUT_GPS_MAG_NAME,GPIO1B, 2, 3, 0, DEFAULT) +MUX_CFG(GPIO1B2_SPI_RXD_UART1_SIN_GPS_SIGN_NAME,GPIO1B, 4, 3, 0, DEFAULT) +MUX_CFG(GPIO1B3_SPI_CSN0_UART1_RTSN_NAME, GPIO1B, 6, 2, 0, DEFAULT) +MUX_CFG(GPIO1B4_SPI_CSN1_UART1_CTSN_NAME, GPIO1B, 8, 2, 0, DEFAULT) +MUX_CFG(GPIO1B5_MMC0_RSTNOUT_NAME, GPIO1B, 10, 1, 0, DEFAULT) +MUX_CFG(GPIO1B6_MMC0_PWREN_NAME, GPIO1B, 12, 1, 0, DEFAULT) +MUX_CFG(GPIO1B7_MMC0_CMD_NAME, GPIO1B, 14, 1, 0, DEFAULT) + +//gpio1c +MUX_CFG(GPIO1C0_MMC0_CLKOUT_NAME, GPIO1C, 0, 1, 0, DEFAULT) +MUX_CFG(GPIO1C1_MMC0_DETN_NAME, GPIO1C, 2, 1, 0, DEFAULT) +MUX_CFG(GPIO1C2_MMC0_D0_NAME, GPIO1C, 4, 1, 0, DEFAULT) +MUX_CFG(GPIO1C3_MMC0_D1_NAME, GPIO1C, 6, 1, 0, DEFAULT) +MUX_CFG(GPIO1C4_MMC0_D2_NAME, GPIO1C, 8, 1, 0, DEFAULT) +MUX_CFG(GPIO1C5_MMC0_D3_NAME, GPIO1C, 10, 1, 0, DEFAULT) +MUX_CFG(GPIO1C6_NAND_CS2_NAME, GPIO1C, 12, 1, 0, DEFAULT) +MUX_CFG(GPIO1C7_NAND_CS3_NAME, GPIO1C, 14, 1, 0, DEFAULT) + +//gpio1d +MUX_CFG(GPIO1D0_NAND_D0_EMMC_D0_NAME, GPIO1D, 0, 2, 0, DEFAULT) +MUX_CFG(GPIO1D1_NAND_D1_EMMC_D1_NAME, GPIO1D, 2, 2, 0, DEFAULT) +MUX_CFG(GPIO1D2_NAND_D2_EMMC_D2_NAME, GPIO1D, 4, 2, 0, DEFAULT) +MUX_CFG(GPIO1D3_NAND_D3_EMMC_D3_NAME, GPIO1D, 6, 2, 0, DEFAULT) +MUX_CFG(GPIO1D4_NAND_D4_EMMC_D4_NAME, GPIO1D, 8, 2, 0, DEFAULT) +MUX_CFG(GPIO1D5_NAND_D5_EMMC_D5_NAME, GPIO1D, 10, 2, 0, DEFAULT) +MUX_CFG(GPIO1D6_NAND_D6_EMMC_D6_NAME, GPIO1D, 12, 2, 0, DEFAULT) +MUX_CFG(GPIO1D7_NAND_D7_EMMC_D7_NAME, GPIO1D, 14, 2, 0, DEFAULT) + +//gpio2a +MUX_CFG(GPIO2A0_NAND_ALE_NAME, GPIO2A, 0, 1, 0, DEFAULT) +MUX_CFG(GPIO2A1_NAND_CLE_NAME, GPIO2A, 2, 1, 0, DEFAULT) +MUX_CFG(GPIO2A2_NAND_WRN_NAME, GPIO2A, 4, 1, 0, DEFAULT) +MUX_CFG(GPIO2A3_NAND_RDN_NAME, GPIO2A, 6, 1, 0, DEFAULT) +MUX_CFG(GPIO2A4_NAND_RDY_EMMC_RSTNOUT_NAME, GPIO2A, 8, 2, 0, DEFAULT) +MUX_CFG(GPIO2A5_NAND_WP_EMMC_PWREN_NAME, GPIO2A, 10, 2, 0, DEFAULT) +MUX_CFG(GPIO2A6_NAND_CS0_EMMC_CMD_NAME, GPIO2A, 12, 2, 0, DEFAULT) +MUX_CFG(GPIO2A7_NAND_DPS_EMMC_CLKOUT_NAME, GPIO2A, 14, 2, 0, DEFAULT) + +//gpio2b +MUX_CFG(GPIO2B0_LCDC0_DCLK_LCDC1_DCLK_NAME, GPIO2B, 0, 2, 0, DEFAULT) +MUX_CFG(GPIO2B1_LCDC0_HSYNC_LCDC1_HSYNC_NAME, GPIO2B, 2, 2, 0, DEFAULT) +MUX_CFG(GPIO2B2_LCDC0_VSYNC_LCDC1_VSYNC_NAME, GPIO2B, 4, 2, 0, DEFAULT) +MUX_CFG(GPIO2B3_LCDC0_DEN_LCDC1_DEN_NAME, GPIO2B, 6, 2, 0, DEFAULT) +MUX_CFG(GPIO2B4_LCDC0_D10_LCDC1_D10_NAME, GPIO2B, 8, 2, 0, DEFAULT) +MUX_CFG(GPIO2B5_LCDC0_D11_LCDC1_D11_NAME, GPIO2B, 10, 2, 0, DEFAULT) +MUX_CFG(GPIO2B6_LCDC0_D12_LCDC1_D12_NAME, GPIO2B, 12, 2, 0, DEFAULT) +MUX_CFG(GPIO2B7_LCDC0_D13_LCDC1_D13_NAME, GPIO2B, 14, 2, 0, DEFAULT) + +//gpio2c +MUX_CFG(GPIO2C0_LCDC0_D14_LCDC1_D14_NAME, GPIO2C, 0, 2, 0, DEFAULT) +MUX_CFG(GPIO2C1_LCDC0_D15_LCDC1_D15_NAME, GPIO2C, 2, 2, 0, DEFAULT) +MUX_CFG(GPIO2C2_LCDC0_D16_LCDC1_D16_NAME, GPIO2C, 4, 2, 0, DEFAULT) +MUX_CFG(GPIO2C3_LCDC0_D17_LCDC1_D17_NAME, GPIO2C, 6, 2, 0, DEFAULT) +MUX_CFG(GPIO2C4_LCDC0_D18_LCDC1_D18_NAME, GPIO2C, 8, 2, 0, DEFAULT) +MUX_CFG(GPIO2C5_LCDC0_D19_LCDC1_D19_NAME, GPIO2C, 10, 2, 0, DEFAULT) +MUX_CFG(GPIO2C6_LCDC0_D20_LCDC1_D20_NAME, GPIO2C, 12, 2, 0, DEFAULT) +MUX_CFG(GPIO2C7_LCDC0_D21_LCDC1_D21_NAME, GPIO2C, 14, 2, 0, DEFAULT) + +//gpio2d +MUX_CFG(GPIO2D0_LCDC0_D23_LCDC1_D23_UART2_SOUT_NAME,GPIO2D, 0, 3, 0, DEFAULT) +MUX_CFG(GPIO2D1_LCDC0_D23_LCDC1_D23_UART2_SIN_NAME,GPIO2D, 2, 3, 0, DEFAULT) + +//gpio3d +MUX_CFG(GPIO3D7_TESTCLK_OUT_NAME, GPIO3D, 14, 1, 0, DEFAULT) +}; + + +void rk30_mux_set(struct mux_config *cfg) +{ + int regValue = 0; + int mask; + + mask = (((1<<(cfg->interleave))-1)<offset) << 16; + regValue |= mask; + regValue |=(cfg->mode<offset); +#ifdef IOMUX_DBG + printk("%s::reg=0x%p,Value=0x%x,mask=0x%x\n",__FUNCTION__,cfg->mux_reg,regValue,mask); +#endif + writel_relaxed(regValue,cfg->mux_reg); + dsb(); + + return; +} + + +int __init rk30_iomux_init(void) +{ + int i; + printk("%s\n",__func__); + for(i=0;i> rk30_muxs[i].offset) &((1<<(rk30_muxs[i].interleave))-1); + return ret; + } + } + + return -1; +} +EXPORT_SYMBOL(rk30_mux_api_get); + From c0c865ee36c0a4f9aece62cec364f9b66851a5fd Mon Sep 17 00:00:00 2001 From: kfx Date: Wed, 11 Jul 2012 15:52:07 +0800 Subject: [PATCH 011/261] rk2928: add board_clock_init --- arch/arm/mach-rk2928/board-rk2928-fpga.c | 4 ++++ arch/arm/mach-rk2928/common.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-rk2928/board-rk2928-fpga.c b/arch/arm/mach-rk2928/board-rk2928-fpga.c index 029d3accc9d2..74e21a4631ad 100644 --- a/arch/arm/mach-rk2928/board-rk2928-fpga.c +++ b/arch/arm/mach-rk2928/board-rk2928-fpga.c @@ -88,6 +88,10 @@ void __init rk30_clock_init(void) clkdev_add(lk); } } +void __init board_clock_init(void) +{ + rk30_clock_init(); +} int clk_enable(struct clk *clk) { diff --git a/arch/arm/mach-rk2928/common.c b/arch/arm/mach-rk2928/common.c index 277ee537f753..170cc3cf715c 100644 --- a/arch/arm/mach-rk2928/common.c +++ b/arch/arm/mach-rk2928/common.c @@ -130,7 +130,7 @@ void __init rk2928_map_io(void) rk29_setup_early_printk(); rk2928_cpu_axi_init(); rk29_sram_init(); -// board_clock_init(); + board_clock_init(); rk2928_l2_cache_init(); // ddr_init(DDR_TYPE, DDR_FREQ); // clk_disable_unused(); From 02b33dc94fcc786d045b3b3ed48337740711ec7c Mon Sep 17 00:00:00 2001 From: kfx Date: Wed, 11 Jul 2012 16:38:16 +0800 Subject: [PATCH 012/261] rk2928: i2c init --- arch/arm/configs/rk2928_fpga_defconfig | 5 + arch/arm/mach-rk2928/devices.c | 201 ++++++++++++++++++++++++- drivers/i2c/busses/i2c-rk30.c | 2 +- drivers/i2c/busses/i2c-rk30.h | 6 +- 4 files changed, 211 insertions(+), 3 deletions(-) diff --git a/arch/arm/configs/rk2928_fpga_defconfig b/arch/arm/configs/rk2928_fpga_defconfig index a32edb8795e4..66550f0c503c 100644 --- a/arch/arm/configs/rk2928_fpga_defconfig +++ b/arch/arm/configs/rk2928_fpga_defconfig @@ -10,6 +10,7 @@ CONFIG_RESOURCE_COUNTERS=y CONFIG_CGROUP_SCHED=y CONFIG_RT_GROUP_SCHED=y CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="root" CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_PANIC_TIMEOUT=1 # CONFIG_SYSCTL_SYSCALL is not set @@ -64,6 +65,10 @@ CONFIG_INPUT_EVDEV=y # CONFIG_CONSOLE_TRANSLATIONS is not set # CONFIG_LEGACY_PTYS is not set # CONFIG_HW_RANDOM is not set +CONFIG_I2C=y +CONFIG_I2C0_CONTROLLER_RK30=y +CONFIG_I2C2_CONTROLLER_RK30=y +# CONFIG_I2C3_RK30 is not set # CONFIG_ADC is not set CONFIG_EXPANDED_GPIO_NUM=0 CONFIG_EXPANDED_GPIO_IRQ_NUM=0 diff --git a/arch/arm/mach-rk2928/devices.c b/arch/arm/mach-rk2928/devices.c index 8a1cac7d6b99..3226bf9a4afb 100755 --- a/arch/arm/mach-rk2928/devices.c +++ b/arch/arm/mach-rk2928/devices.c @@ -26,7 +26,7 @@ #include #include #include -//#include +#include #include @@ -102,9 +102,208 @@ static void __init rk2928_init_dma(void) { platform_add_devices(rk2928_dmacs, ARRAY_SIZE(rk2928_dmacs)); } +// i2c +#ifdef CONFIG_I2C0_CONTROLLER_RK29 +#define I2C0_ADAP_TYPE I2C_RK29_ADAP +#define I2C0_START RK2928_I2C0_PHYS +#define I2C0_END RK2928_I2C0_PHYS + SZ_4K - 1 +#endif +#ifdef CONFIG_I2C0_CONTROLLER_RK30 +#define I2C0_ADAP_TYPE I2C_RK30_ADAP +#define I2C0_START RK2928_RKI2C0_PHYS +#define I2C0_END RK2928_RKI2C0_PHYS + SZ_4K - 1 +#endif + +#ifdef CONFIG_I2C1_CONTROLLER_RK29 +#define I2C1_ADAP_TYPE I2C_RK29_ADAP +#define I2C1_START RK2928_I2C1_PHYS +#define I2C1_END RK2928_I2C1_PHYS + SZ_4K - 1 +#endif +#ifdef CONFIG_I2C1_CONTROLLER_RK30 +#define I2C1_ADAP_TYPE I2C_RK30_ADAP +#define I2C1_START RK2928_RKI2C1_PHYS +#define I2C1_END RK2928_RKI2C1_PHYS + SZ_4K - 1 +#endif + +#ifdef CONFIG_I2C2_CONTROLLER_RK29 +#define I2C2_ADAP_TYPE I2C_RK29_ADAP +#define I2C2_START RK2928_I2C2_PHYS +#define I2C2_END RK2928_I2C2_PHYS + SZ_4K - 1 +#endif +#ifdef CONFIG_I2C2_CONTROLLER_RK30 +#define I2C2_ADAP_TYPE I2C_RK30_ADAP +#define I2C2_START RK2928_RKI2C2_PHYS +#define I2C2_END RK2928_RKI2C2_PHYS + SZ_4K - 1 +#endif + +#ifdef CONFIG_I2C3_CONTROLLER_RK29 +#define I2C3_ADAP_TYPE I2C_RK29_ADAP +#define I2C3_START RK2928_I2C3_PHYS +#define I2C3_END RK2928_I2C3_PHYS + SZ_4K - 1 +#endif +#ifdef CONFIG_I2C3_CONTROLLER_RK30 +#define I2C3_ADAP_TYPE I2C_RK30_ADAP +#define I2C3_START RK2928_RKI2C3_PHYS +#define I2C3_END RK2928_RKI2C3_PHYS + SZ_4K - 1 +#endif + +#ifdef CONFIG_I2C0_RK30 +static struct rk30_i2c_platform_data default_i2c0_data = { + .bus_num = 0, + .is_div_from_arm = 1, + .adap_type = I2C0_ADAP_TYPE, +}; + +static struct resource resources_i2c0[] = { + { + .start = IRQ_I2C0, + .end = IRQ_I2C0, + .flags = IORESOURCE_IRQ, + }, + { + .start = I2C0_START, + .end = I2C0_END, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device device_i2c0 = { + .name = "rk30_i2c", + .id = 0, + .num_resources = ARRAY_SIZE(resources_i2c0), + .resource = resources_i2c0, + .dev = { + .platform_data = &default_i2c0_data, + }, +}; +#endif + +#ifdef CONFIG_I2C1_RK30 +static struct rk30_i2c_platform_data default_i2c1_data = { + .bus_num = 1, + .is_div_from_arm = 1, + .adap_type = I2C1_ADAP_TYPE, +}; + +static struct resource resources_i2c1[] = { + { + .start = IRQ_I2C1, + .end = IRQ_I2C1, + .flags = IORESOURCE_IRQ, + }, + { + .start = I2C1_START, + .end = I2C1_END, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device device_i2c1 = { + .name = "rk30_i2c", + .id = 1, + .num_resources = ARRAY_SIZE(resources_i2c1), + .resource = resources_i2c1, + .dev = { + .platform_data = &default_i2c1_data, + }, +}; +#endif + +#ifdef CONFIG_I2C2_RK30 +static struct rk30_i2c_platform_data default_i2c2_data = { + .bus_num = 2, + .is_div_from_arm = 0, + .adap_type = I2C2_ADAP_TYPE, +}; + +static struct resource resources_i2c2[] = { + { + .start = IRQ_I2C2, + .end = IRQ_I2C2, + .flags = IORESOURCE_IRQ, + }, + { + .start = I2C2_START, + .end = I2C2_END, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device device_i2c2 = { + .name = "rk30_i2c", + .id = 2, + .num_resources = ARRAY_SIZE(resources_i2c2), + .resource = resources_i2c2, + .dev = { + .platform_data = &default_i2c2_data, + }, +}; +#endif + +#ifdef CONFIG_I2C3_RK30 +static struct rk30_i2c_platform_data default_i2c3_data = { + .bus_num = 3, + .is_div_from_arm = 0, + .adap_type = I2C3_ADAP_TYPE, +}; + +static struct resource resources_i2c3[] = { + { + .start = IRQ_I2C3, + .end = IRQ_I2C3, + .flags = IORESOURCE_IRQ, + }, + { + .start = I2C3_START, + .end = I2C3_END, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device device_i2c3 = { + .name = "rk30_i2c", + .id = 3, + .num_resources = ARRAY_SIZE(resources_i2c3), + .resource = resources_i2c3, + .dev = { + .platform_data = &default_i2c3_data, + }, +}; +#endif + +#ifdef CONFIG_I2C_GPIO_RK30 +static struct platform_device device_i2c_gpio = { + .name = "i2c-gpio", + .id = 4, + .dev = { + .platform_data = &default_i2c_gpio_data, + }, +}; +#endif + +static void __init rk30_init_i2c(void) +{ +#ifdef CONFIG_I2C0_RK30 + platform_device_register(&device_i2c0); +#endif +#ifdef CONFIG_I2C1_RK30 + platform_device_register(&device_i2c1); +#endif +#ifdef CONFIG_I2C2_RK30 + platform_device_register(&device_i2c2); +#endif +#ifdef CONFIG_I2C3_RK30 + platform_device_register(&device_i2c3); +#endif +#ifdef CONFIG_I2C_GPIO_RK30 + platform_device_register(&device_i2c_gpio); +#endif +} +//end of i2c static int __init rk2928_init_devices(void) { rk2928_init_dma(); + rk30_init_i2c(); #if defined(CONFIG_FIQ_DEBUGGER) && defined(DEBUG_UART_PHYS) rk_serial_debug_init(DEBUG_UART_BASE, IRQ_DEBUG_UART, IRQ_UART_SIGNAL, -1); #endif diff --git a/drivers/i2c/busses/i2c-rk30.c b/drivers/i2c/busses/i2c-rk30.c index ccd3777bb91f..bc0cc1054e9e 100755 --- a/drivers/i2c/busses/i2c-rk30.c +++ b/drivers/i2c/busses/i2c-rk30.c @@ -17,7 +17,7 @@ void i2c_adap_sel(struct rk30_i2c *i2c, int nr, int adap_type) { - writel((1 << I2C_ADAP_SEL_BIT(nr)) | (1 << I2C_ADAP_SEL_MASK(nr)) , + i2c_writel((1 << I2C_ADAP_SEL_BIT(nr)) | (1 << I2C_ADAP_SEL_MASK(nr)) , i2c->con_base); } diff --git a/drivers/i2c/busses/i2c-rk30.h b/drivers/i2c/busses/i2c-rk30.h index afb2d33721bc..2fe9a206a006 100755 --- a/drivers/i2c/busses/i2c-rk30.h +++ b/drivers/i2c/busses/i2c-rk30.h @@ -44,8 +44,12 @@ #define rk30_ceil(x, y) \ ({ unsigned long __x = (x), __y = (y); (__x + __y - 1) / __y; }) - +#ifdef CONFIG_ARCH_RK30 #define GRF_I2C_CON_BASE (RK30_GRF_BASE + GRF_SOC_CON1) +#endif +#ifdef CONFIG_ARCH_RK2928 +#define GRF_I2C_CON_BASE (RK2928_GRF_BASE + GRF_SOC_CON1) +#endif #define I2C_ADAP_SEL_BIT(nr) ((nr) + 11) #define I2C_ADAP_SEL_MASK(nr) ((nr) + 27) enum rk30_i2c_state { From dfeede9fe7b8f2344bb98074717a6fbcdcebebab Mon Sep 17 00:00:00 2001 From: kfx Date: Wed, 11 Jul 2012 17:24:11 +0800 Subject: [PATCH 013/261] rk2928: spi init --- arch/arm/mach-rk2928/devices.c | 116 ++++++++++++++++++++++++++++++++- drivers/spi/Kconfig | 5 +- 2 files changed, 116 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-rk2928/devices.c b/arch/arm/mach-rk2928/devices.c index 3226bf9a4afb..88c89c446b7e 100755 --- a/arch/arm/mach-rk2928/devices.c +++ b/arch/arm/mach-rk2928/devices.c @@ -281,7 +281,7 @@ static struct platform_device device_i2c_gpio = { }; #endif -static void __init rk30_init_i2c(void) +static void __init rk2928_init_i2c(void) { #ifdef CONFIG_I2C0_RK30 platform_device_register(&device_i2c0); @@ -300,10 +300,122 @@ static void __init rk30_init_i2c(void) #endif } //end of i2c + +#if defined(CONFIG_SPIM0_RK29) || defined(CONFIG_SPIM1_RK29) +/***************************************************************************************** + * spi devices + * author: cmc@rock-chips.com + *****************************************************************************************/ +#define SPI_CHIPSELECT_NUM 2 + +static int spi_io_init(struct spi_cs_gpio *cs_gpios, int cs_num) +{ + int i; + if (cs_gpios) { + for (i = 0; i < cs_num; i++) { + rk30_mux_api_set(cs_gpios[i].cs_iomux_name, cs_gpios[i].cs_iomux_mode); + } + } + return 0; +} + +static int spi_io_deinit(struct spi_cs_gpio *cs_gpios, int cs_num) +{ + return 0; +} + +static int spi_io_fix_leakage_bug(void) +{ +#if 0 + gpio_direction_output(RK29_PIN2_PC1, GPIO_LOW); +#endif + return 0; +} + +static int spi_io_resume_leakage_bug(void) +{ +#if 0 + gpio_direction_output(RK29_PIN2_PC1, GPIO_HIGH); +#endif + return 0; +} +#endif + +/* + * rk29xx spi master device + */ +#ifdef CONFIG_SPIM0_RK29 +static struct spi_cs_gpio rk29xx_spi0_cs_gpios[SPI_CHIPSELECT_NUM] = { + { + .name = "spi0 cs0", + .cs_gpio = RK2928_PIN1_PB3, + .cs_iomux_name = GPIO1B3_SPI_CSN0_UART1_RTSN_NAME, + .cs_iomux_mode = GPIO1B_SPI_CSN0, + }, + { + .name = "spi0 cs1", + .cs_gpio = RK2928_PIN1_PB4, + .cs_iomux_name = GPIO1B4_SPI_CSN1_UART1_CTSN_NAME,//if no iomux,set it NULL + .cs_iomux_mode = GPIO1B_SPI_CSN1, + }, +}; + +static struct rk29xx_spi_platform_data rk29xx_spi0_platdata = { + .num_chipselect = SPI_CHIPSELECT_NUM, + .chipselect_gpios = rk29xx_spi0_cs_gpios, + .io_init = spi_io_init, + .io_deinit = spi_io_deinit, + .io_fix_leakage_bug = spi_io_fix_leakage_bug, + .io_resume_leakage_bug = spi_io_resume_leakage_bug, +}; + +static struct resource rk29_spi0_resources[] = { + { + .start = IRQ_SPI, + .end = IRQ_SPI, + .flags = IORESOURCE_IRQ, + }, + { + .start = RK2928_SPI_PHYS, + .end = RK2928_SPI_PHYS + RK2928_SPI_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = DMACH_SPI0_TX, + .end = DMACH_SPI0_TX, + .flags = IORESOURCE_DMA, + }, + { + .start = DMACH_SPI0_RX, + .end = DMACH_SPI0_RX, + .flags = IORESOURCE_DMA, + }, +}; + +struct platform_device rk29xx_device_spi0m = { + .name = "rk29xx_spim", + .id = 0, + .num_resources = ARRAY_SIZE(rk29_spi0_resources), + .resource = rk29_spi0_resources, + .dev = { + .dma_mask = &dma_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &rk29xx_spi0_platdata, + }, +}; +#endif + +static void __init rk2928_init_spim(void) +{ +#ifdef CONFIG_SPIM0_RK29 + platform_device_register(&rk29xx_device_spi0m); +#endif +} static int __init rk2928_init_devices(void) { rk2928_init_dma(); - rk30_init_i2c(); + rk2928_init_i2c(); + rk2928_init_spim(); #if defined(CONFIG_FIQ_DEBUGGER) && defined(DEBUG_UART_PHYS) rk_serial_debug_init(DEBUG_UART_BASE, IRQ_DEBUG_UART, IRQ_UART_SIGNAL, -1); #endif diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 51fc9c9f56ab..769044ca1887 100755 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -426,7 +426,7 @@ config SPI_NUC900 config SPIM_RK29 tristate "RK SPI master controller core support" - depends on (ARCH_RK29 || ARCH_RK30) && SPI_MASTER + depends on (ARCH_RK29 || ARCH_RK30 || ARCH_RK2928) && SPI_MASTER help general driver for SPI controller core from RockChips @@ -438,13 +438,12 @@ config SPIM0_RK29 config SPIM1_RK29 bool "RK SPI1 master controller" - depends on SPIM_RK29 + depends on SPIM_RK29 && !ARCH_RK2928 help enable SPI1 master controller for RK29 config RK_SPIM_TEST bool "RK SPIM test" - depends on (SPIM0_RK29 && SPIM1_RK29) config LCD_USE_SPIM_CONTROL bool "Switch gpio to spim with spin lock" From 615c02451751af06e86ebfeb3edc5b3a3d5dec55 Mon Sep 17 00:00:00 2001 From: kfx Date: Wed, 11 Jul 2012 18:43:53 +0800 Subject: [PATCH 014/261] rk2928: uart init --- arch/arm/mach-rk2928/board-rk2928-fpga.c | 13 ++++ arch/arm/mach-rk2928/devices.c | 80 ++++++++++++++++++++++++ drivers/tty/serial/Kconfig | 2 +- 3 files changed, 94 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-rk2928/board-rk2928-fpga.c b/arch/arm/mach-rk2928/board-rk2928-fpga.c index 74e21a4631ad..ed5b66e9303f 100644 --- a/arch/arm/mach-rk2928/board-rk2928-fpga.c +++ b/arch/arm/mach-rk2928/board-rk2928-fpga.c @@ -78,6 +78,19 @@ static struct clk_lookup clks[] = { CLK("rk30_i2c.3", "i2c", &xin24m), CLK("rk29xx_spim.0", "spi", &xin24m), CLK("rk29xx_spim.1", "spi", &xin24m), + + CLK("rk_serial.0", "uart_div", &xin24m), + CLK("rk_serial.0", "uart_frac_div", &xin24m), + CLK("rk_serial.0", "uart", &xin24m), + CLK("rk_serial.0", "pclk_uart", &xin24m), + CLK("rk_serial.1", "uart_div", &xin24m), + CLK("rk_serial.1", "uart_frac_div", &xin24m), + CLK("rk_serial.1", "uart", &xin24m), + CLK("rk_serial.1", "pclk_uart", &xin24m), + CLK("rk_serial.2", "uart_div", &xin24m), + CLK("rk_serial.2", "uart_frac_div", &xin24m), + CLK("rk_serial.2", "uart", &xin24m), + CLK("rk_serial.2", "pclk_uart", &xin24m), }; void __init rk30_clock_init(void) diff --git a/arch/arm/mach-rk2928/devices.c b/arch/arm/mach-rk2928/devices.c index 88c89c446b7e..112f302cd6a0 100755 --- a/arch/arm/mach-rk2928/devices.c +++ b/arch/arm/mach-rk2928/devices.c @@ -102,6 +102,85 @@ static void __init rk2928_init_dma(void) { platform_add_devices(rk2928_dmacs, ARRAY_SIZE(rk2928_dmacs)); } + +#ifdef CONFIG_UART0_RK29 +static struct resource resources_uart0[] = { + { + .start = IRQ_UART0, + .end = IRQ_UART0, + .flags = IORESOURCE_IRQ, + }, + { + .start = RK2928_UART0_PHYS, + .end = RK2928_UART0_PHYS + RK2928_UART0_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device device_uart0 = { + .name = "rk_serial", + .id = 0, + .num_resources = ARRAY_SIZE(resources_uart0), + .resource = resources_uart0, +}; +#endif + +#ifdef CONFIG_UART1_RK29 +static struct resource resources_uart1[] = { + { + .start = IRQ_UART1, + .end = IRQ_UART1, + .flags = IORESOURCE_IRQ, + }, + { + .start = RK2928_UART1_PHYS, + .end = RK2928_UART1_PHYS + RK2928_UART1_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device device_uart1 = { + .name = "rk_serial", + .id = 1, + .num_resources = ARRAY_SIZE(resources_uart1), + .resource = resources_uart1, +}; +#endif + +#ifdef CONFIG_UART2_RK29 +static struct resource resources_uart2[] = { + { + .start = IRQ_UART2, + .end = IRQ_UART2, + .flags = IORESOURCE_IRQ, + }, + { + .start = RK2928_UART2_PHYS, + .end = RK2928_UART2_PHYS + RK2928_UART2_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device device_uart2 = { + .name = "rk_serial", + .id = 2, + .num_resources = ARRAY_SIZE(resources_uart2), + .resource = resources_uart2, +}; +#endif + +static void __init rk2928_init_uart(void) +{ +#ifdef CONFIG_UART0_RK29 + platform_device_register(&device_uart0); +#endif +#ifdef CONFIG_UART1_RK29 + platform_device_register(&device_uart1); +#endif +#ifdef CONFIG_UART2_RK29 + platform_device_register(&device_uart2); +#endif +} // i2c #ifdef CONFIG_I2C0_CONTROLLER_RK29 #define I2C0_ADAP_TYPE I2C_RK29_ADAP @@ -414,6 +493,7 @@ static void __init rk2928_init_spim(void) static int __init rk2928_init_devices(void) { rk2928_init_dma(); + rk2928_init_uart(); rk2928_init_i2c(); rk2928_init_spim(); #if defined(CONFIG_FIQ_DEBUGGER) && defined(DEBUG_UART_PHYS) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 4763420c6a4a..3405977f4d43 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1555,7 +1555,7 @@ config UART2_DMA_RK29 config UART3_RK29 bool "Serial port 3 support" - depends on SERIAL_RK29 + depends on SERIAL_RK29 && !ARCH_RK2928 config UART3_CTS_RTS_RK29 bool "Serial port 3 CTS/RTS support" From 9344f9d5994122f2d7fe17a01758d064cac23315 Mon Sep 17 00:00:00 2001 From: kfx Date: Wed, 11 Jul 2012 18:53:07 +0800 Subject: [PATCH 015/261] rk2928: i2c: SZ_4K -> RK2928_XXI2CX_SIZE --- arch/arm/mach-rk2928/devices.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-rk2928/devices.c b/arch/arm/mach-rk2928/devices.c index 112f302cd6a0..6b72f1019092 100755 --- a/arch/arm/mach-rk2928/devices.c +++ b/arch/arm/mach-rk2928/devices.c @@ -185,45 +185,45 @@ static void __init rk2928_init_uart(void) #ifdef CONFIG_I2C0_CONTROLLER_RK29 #define I2C0_ADAP_TYPE I2C_RK29_ADAP #define I2C0_START RK2928_I2C0_PHYS -#define I2C0_END RK2928_I2C0_PHYS + SZ_4K - 1 +#define I2C0_END RK2928_I2C0_PHYS + RK2928_I2C0_SIZE - 1 #endif #ifdef CONFIG_I2C0_CONTROLLER_RK30 #define I2C0_ADAP_TYPE I2C_RK30_ADAP #define I2C0_START RK2928_RKI2C0_PHYS -#define I2C0_END RK2928_RKI2C0_PHYS + SZ_4K - 1 +#define I2C0_END RK2928_RKI2C0_PHYS + RK2928_RKI2C0_SIZE - 1 #endif #ifdef CONFIG_I2C1_CONTROLLER_RK29 #define I2C1_ADAP_TYPE I2C_RK29_ADAP #define I2C1_START RK2928_I2C1_PHYS -#define I2C1_END RK2928_I2C1_PHYS + SZ_4K - 1 +#define I2C1_END RK2928_I2C1_PHYS + RK2928_I2C1_SIZE - 1 #endif #ifdef CONFIG_I2C1_CONTROLLER_RK30 #define I2C1_ADAP_TYPE I2C_RK30_ADAP #define I2C1_START RK2928_RKI2C1_PHYS -#define I2C1_END RK2928_RKI2C1_PHYS + SZ_4K - 1 +#define I2C1_END RK2928_RKI2C1_PHYS + RK2928_RKI2C1_SIZE - 1 #endif #ifdef CONFIG_I2C2_CONTROLLER_RK29 #define I2C2_ADAP_TYPE I2C_RK29_ADAP #define I2C2_START RK2928_I2C2_PHYS -#define I2C2_END RK2928_I2C2_PHYS + SZ_4K - 1 +#define I2C2_END RK2928_I2C2_PHYS + RK2928_I2C2_SIZE - 1 #endif #ifdef CONFIG_I2C2_CONTROLLER_RK30 #define I2C2_ADAP_TYPE I2C_RK30_ADAP #define I2C2_START RK2928_RKI2C2_PHYS -#define I2C2_END RK2928_RKI2C2_PHYS + SZ_4K - 1 +#define I2C2_END RK2928_RKI2C2_PHYS + RK2928_RKI2C2_SIZE - 1 #endif #ifdef CONFIG_I2C3_CONTROLLER_RK29 #define I2C3_ADAP_TYPE I2C_RK29_ADAP #define I2C3_START RK2928_I2C3_PHYS -#define I2C3_END RK2928_I2C3_PHYS + SZ_4K - 1 +#define I2C3_END RK2928_I2C3_PHYS + RK2928_I2C3_SIZE - 1 #endif #ifdef CONFIG_I2C3_CONTROLLER_RK30 #define I2C3_ADAP_TYPE I2C_RK30_ADAP #define I2C3_START RK2928_RKI2C3_PHYS -#define I2C3_END RK2928_RKI2C3_PHYS + SZ_4K - 1 +#define I2C3_END RK2928_RKI2C3_PHYS + RK2928_RKI2C3_SIZE - 1 #endif #ifdef CONFIG_I2C0_RK30 From d37628c897fb42a9e365ea44df9503b3607e0945 Mon Sep 17 00:00:00 2001 From: kfx Date: Thu, 12 Jul 2012 10:50:10 +0800 Subject: [PATCH 016/261] rk2928: gpio enable & iomux enable & fpga keypad init --- arch/arm/mach-rk2928/Makefile | 2 +- arch/arm/mach-rk2928/board-rk2928-fpga-key.c | 53 ++ arch/arm/mach-rk2928/common.c | 4 +- arch/arm/mach-rk2928/devices.c | 13 + arch/arm/mach-rk2928/include/mach/board.h | 1 + arch/arm/mach-rk2928/include/mach/gpio.h | 1 + arch/arm/mach-rk2928/iomux.c | 2 +- drivers/gpio/Makefile | 1 + drivers/gpio/gpio-rk2928.c | 487 +++++++++++++++++++ 9 files changed, 560 insertions(+), 4 deletions(-) create mode 100755 arch/arm/mach-rk2928/board-rk2928-fpga-key.c create mode 100755 drivers/gpio/gpio-rk2928.c diff --git a/arch/arm/mach-rk2928/Makefile b/arch/arm/mach-rk2928/Makefile index 81ab4330f097..6a734d2980e3 100644 --- a/arch/arm/mach-rk2928/Makefile +++ b/arch/arm/mach-rk2928/Makefile @@ -6,4 +6,4 @@ obj-y += devices.o obj-y += iomux.o obj-$(CONFIG_PM) += pm.o -obj-$(CONFIG_MACH_RK2928_FPGA) += board-rk2928-fpga.o +obj-$(CONFIG_MACH_RK2928_FPGA) += board-rk2928-fpga.o board-rk2928-fpga-key.o diff --git a/arch/arm/mach-rk2928/board-rk2928-fpga-key.c b/arch/arm/mach-rk2928/board-rk2928-fpga-key.c new file mode 100755 index 000000000000..8a86e544c1dd --- /dev/null +++ b/arch/arm/mach-rk2928/board-rk2928-fpga-key.c @@ -0,0 +1,53 @@ +#include +#include + +#define EV_ENCALL KEY_F4 +#define EV_MENU KEY_F1 + +#define PRESS_LEV_LOW 1 +#define PRESS_LEV_HIGH 0 + +static struct rk29_keys_button key_button[] = { + { + .desc = "menu", + .code = EV_MENU, + .gpio = RK2928_PIN3_PB2, + .active_low = PRESS_LEV_LOW, + }, + { + .desc = "vol+", + .code = KEY_VOLUMEUP, + .gpio = RK2928_PIN3_PB1, + .active_low = PRESS_LEV_LOW, + }, + { + .desc = "vol-", + .code = KEY_VOLUMEDOWN, + .gpio = RK2928_PIN3_PB0, + .active_low = PRESS_LEV_LOW, + }, + { + .desc = "home", + .code = KEY_HOME, + .gpio = RK2928_PIN3_PB3, + .active_low = PRESS_LEV_LOW, + }, + { + .desc = "esc", + .code = KEY_BACK, + .gpio = RK2928_PIN3_PB4, + .active_low = PRESS_LEV_LOW, + }, + { + .desc = "key6", + .code = KEY_CAMERA, + .gpio = RK2928_PIN3_PB5, + .active_low = PRESS_LEV_LOW, + }, +}; +struct rk29_keys_platform_data rk29_keys_pdata = { + .buttons = key_button, + .nbuttons = ARRAY_SIZE(key_button), + .chn = -1, //chn: 0-7, if do not use ADC,set 'chn' -1 +}; + diff --git a/arch/arm/mach-rk2928/common.c b/arch/arm/mach-rk2928/common.c index 170cc3cf715c..6f8d458fad64 100644 --- a/arch/arm/mach-rk2928/common.c +++ b/arch/arm/mach-rk2928/common.c @@ -118,7 +118,7 @@ void __init rk2928_init_irq(void) #ifdef CONFIG_FIQ rk_fiq_init(); #endif -// rk30_gpio_init(); + rk2928_gpio_init(); } extern void __init rk2928_map_common_io(void); @@ -134,7 +134,7 @@ void __init rk2928_map_io(void) rk2928_l2_cache_init(); // ddr_init(DDR_TYPE, DDR_FREQ); // clk_disable_unused(); -// rk2928_iomux_init(); + rk2928_iomux_init(); rk2928_boot_mode_init(); } diff --git a/arch/arm/mach-rk2928/devices.c b/arch/arm/mach-rk2928/devices.c index 6b72f1019092..bbc9868cf2a6 100755 --- a/arch/arm/mach-rk2928/devices.c +++ b/arch/arm/mach-rk2928/devices.c @@ -490,12 +490,25 @@ static void __init rk2928_init_spim(void) platform_device_register(&rk29xx_device_spi0m); #endif } +#ifdef CONFIG_KEYS_RK29 +extern struct rk29_keys_platform_data rk29_keys_pdata; +static struct platform_device device_keys = { + .name = "rk29-keypad", + .id = -1, + .dev = { + .platform_data = &rk29_keys_pdata, + }, +}; +#endif static int __init rk2928_init_devices(void) { rk2928_init_dma(); rk2928_init_uart(); rk2928_init_i2c(); rk2928_init_spim(); +#ifdef CONFIG_KEYS_RK29 + platform_device_register(&device_keys); +#endif #if defined(CONFIG_FIQ_DEBUGGER) && defined(DEBUG_UART_PHYS) rk_serial_debug_init(DEBUG_UART_BASE, IRQ_DEBUG_UART, IRQ_UART_SIGNAL, -1); #endif diff --git a/arch/arm/mach-rk2928/include/mach/board.h b/arch/arm/mach-rk2928/include/mach/board.h index d4ec846e7d76..fad769ca8b30 100644 --- a/arch/arm/mach-rk2928/include/mach/board.h +++ b/arch/arm/mach-rk2928/include/mach/board.h @@ -24,6 +24,7 @@ struct machine_desc; void __init rk2928_fixup(struct machine_desc *desc, struct tag *tags, char **cmdline, struct meminfo *mi); void __init rk2928_clock_data_init(unsigned long gpll,unsigned long cpll,u32 flags); void __init board_clock_init(void); +void __init rk2928_iomux_init(void); void board_gpio_suspend(void); void board_gpio_resume(void); void __sramfunc board_pmu_suspend(void); diff --git a/arch/arm/mach-rk2928/include/mach/gpio.h b/arch/arm/mach-rk2928/include/mach/gpio.h index 913896953b09..d7e713e035ce 100644 --- a/arch/arm/mach-rk2928/include/mach/gpio.h +++ b/arch/arm/mach-rk2928/include/mach/gpio.h @@ -353,6 +353,7 @@ #include #ifndef __ASSEMBLY__ +extern void __init rk2928_gpio_init(void); static inline int gpio_to_irq(unsigned gpio) { return gpio - PIN_BASE + NR_GIC_IRQS; diff --git a/arch/arm/mach-rk2928/iomux.c b/arch/arm/mach-rk2928/iomux.c index 44968e1b25b9..11b2dcaf7b8a 100755 --- a/arch/arm/mach-rk2928/iomux.c +++ b/arch/arm/mach-rk2928/iomux.c @@ -164,7 +164,7 @@ void rk30_mux_set(struct mux_config *cfg) } -int __init rk30_iomux_init(void) +int __init rk2928_iomux_init(void) { int i; printk("%s\n",__func__); diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 441f198aac86..402c46f345c9 100755 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_PLAT_NOMADIK) += gpio-nomadik.o obj-$(CONFIG_GPIO_RDC321X) += rdc321x-gpio.o obj-$(CONFIG_ARCH_RK29) += gpio-rk29.o obj-$(CONFIG_ARCH_RK30) += gpio-rk30.o +obj-$(CONFIG_ARCH_RK2928) += gpio-rk2928.o obj-$(CONFIG_GPIO_JANZ_TTL) += janz-ttl.o obj-$(CONFIG_GPIO_SX150X) += sx150x.o obj-$(CONFIG_GPIO_VX855) += vx855_gpio.o diff --git a/drivers/gpio/gpio-rk2928.c b/drivers/gpio/gpio-rk2928.c new file mode 100755 index 000000000000..8726c7e7035c --- /dev/null +++ b/drivers/gpio/gpio-rk2928.c @@ -0,0 +1,487 @@ +/* arch/arm/mach-rk29/gpio.c + * + * Copyright (C) 2010 ROCKCHIP, Inc. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define MAX_PIN RK2928_PIN3_PD7 + +#define to_rk30_gpio_bank(c) container_of(c, struct rk30_gpio_bank, chip) + +struct rk30_gpio_bank { + struct gpio_chip chip; + unsigned short id; + short irq; + void __iomem *regbase; /* Base of register bank */ + struct clk *clk; + u32 suspend_wakeup; + u32 saved_wakeup; + spinlock_t lock; +}; + +static struct lock_class_key gpio_lock_class; + +static void rk30_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip); +static void rk30_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val); +static int rk30_gpiolib_get(struct gpio_chip *chip, unsigned offset); +static int rk30_gpiolib_direction_output(struct gpio_chip *chip,unsigned offset, int val); +static int rk30_gpiolib_direction_input(struct gpio_chip *chip,unsigned offset); +static int rk30_gpiolib_pull_updown(struct gpio_chip *chip, unsigned offset, unsigned enable); +static int rk30_gpiolib_to_irq(struct gpio_chip *chip,unsigned offset); + +#define RK30_GPIO_BANK(ID) \ + { \ + .chip = { \ + .label = "gpio" #ID, \ + .direction_input = rk30_gpiolib_direction_input, \ + .direction_output = rk30_gpiolib_direction_output, \ + .get = rk30_gpiolib_get, \ + .set = rk30_gpiolib_set, \ + .pull_updown = rk30_gpiolib_pull_updown, \ + .dbg_show = rk30_gpiolib_dbg_show, \ + .to_irq = rk30_gpiolib_to_irq, \ + .base = ID < 6 ? PIN_BASE + ID*NUM_GROUP : PIN_BASE + 5*NUM_GROUP, \ + .ngpio = ID < 6 ? NUM_GROUP : 16, \ + }, \ + .id = ID, \ + .irq = IRQ_GPIO##ID, \ + .regbase = (unsigned char __iomem *) RK2928_GPIO##ID##_BASE, \ + } + +static struct rk30_gpio_bank rk30_gpio_banks[] = { + RK30_GPIO_BANK(0), + RK30_GPIO_BANK(1), + RK30_GPIO_BANK(2), + RK30_GPIO_BANK(3), +}; + +static inline void rk30_gpio_bit_op(void __iomem *regbase, unsigned int offset, u32 bit, unsigned char flag) +{ + u32 val = __raw_readl(regbase + offset); + if (flag) + val |= bit; + else + val &= ~bit; + __raw_writel(val, regbase + offset); +} + +static inline struct gpio_chip *pin_to_gpio_chip(unsigned pin) +{ + if (pin < PIN_BASE || pin > MAX_PIN) + return NULL; + + pin -= PIN_BASE; + pin /= NUM_GROUP; + if (likely(pin < ARRAY_SIZE(rk30_gpio_banks))) + return &(rk30_gpio_banks[pin].chip); + return NULL; +} + +static inline unsigned gpio_to_bit(unsigned gpio) +{ + gpio -= PIN_BASE; + return 1u << (gpio % NUM_GROUP); +} + +static inline unsigned offset_to_bit(unsigned offset) +{ + return 1u << offset; +} + +static void GPIOSetPinLevel(void __iomem *regbase, unsigned int bit, eGPIOPinLevel_t level) +{ + rk30_gpio_bit_op(regbase, GPIO_SWPORT_DDR, bit, 1); + rk30_gpio_bit_op(regbase, GPIO_SWPORT_DR, bit, level); +} + +static int GPIOGetPinLevel(void __iomem *regbase, unsigned int bit) +{ + return ((__raw_readl(regbase + GPIO_EXT_PORT) & bit) != 0); +} + +static void GPIOSetPinDirection(void __iomem *regbase, unsigned int bit, eGPIOPinDirection_t direction) +{ + rk30_gpio_bit_op(regbase, GPIO_SWPORT_DDR, bit, direction); + /* Enable debounce may halt cpu on wfi, disable it by default */ + //rk30_gpio_bit_op(regbase, GPIO_DEBOUNCE, bit, 1); +} + +static void GPIOEnableIntr(void __iomem *regbase, unsigned int bit) +{ + rk30_gpio_bit_op(regbase, GPIO_INTEN, bit, 1); +} + +static void GPIODisableIntr(void __iomem *regbase, unsigned int bit) +{ + rk30_gpio_bit_op(regbase, GPIO_INTEN, bit, 0); +} + +static void GPIOAckIntr(void __iomem *regbase, unsigned int bit) +{ + rk30_gpio_bit_op(regbase, GPIO_PORTS_EOI, bit, 1); +} + +static void GPIOSetIntrType(void __iomem *regbase, unsigned int bit, eGPIOIntType_t type) +{ + switch (type) { + case GPIOLevelLow: + rk30_gpio_bit_op(regbase, GPIO_INT_POLARITY, bit, 0); + rk30_gpio_bit_op(regbase, GPIO_INTTYPE_LEVEL, bit, 0); + break; + case GPIOLevelHigh: + rk30_gpio_bit_op(regbase, GPIO_INTTYPE_LEVEL, bit, 0); + rk30_gpio_bit_op(regbase, GPIO_INT_POLARITY, bit, 1); + break; + case GPIOEdgelFalling: + rk30_gpio_bit_op(regbase, GPIO_INTTYPE_LEVEL, bit, 1); + rk30_gpio_bit_op(regbase, GPIO_INT_POLARITY, bit, 0); + break; + case GPIOEdgelRising: + rk30_gpio_bit_op(regbase, GPIO_INTTYPE_LEVEL, bit, 1); + rk30_gpio_bit_op(regbase, GPIO_INT_POLARITY, bit, 1); + break; + } +} + +static int rk30_gpio_irq_set_type(struct irq_data *d, unsigned int type) +{ + struct rk30_gpio_bank *bank = irq_data_get_irq_chip_data(d); + u32 bit = gpio_to_bit(irq_to_gpio(d->irq)); + eGPIOIntType_t int_type; + unsigned long flags; + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + int_type = GPIOEdgelRising; + break; + case IRQ_TYPE_EDGE_FALLING: + int_type = GPIOEdgelFalling; + break; + case IRQ_TYPE_LEVEL_HIGH: + int_type = GPIOLevelHigh; + break; + case IRQ_TYPE_LEVEL_LOW: + int_type = GPIOLevelLow; + break; + default: + return -EINVAL; + } + + spin_lock_irqsave(&bank->lock, flags); + //设置为中断之前,必须先设置为输入状态 + GPIOSetPinDirection(bank->regbase, bit, GPIO_IN); + GPIOSetIntrType(bank->regbase, bit, int_type); + spin_unlock_irqrestore(&bank->lock, flags); + + if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) + __irq_set_handler_locked(d->irq, handle_level_irq); + else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) + __irq_set_handler_locked(d->irq, handle_edge_irq); + + return 0; +} + +static int rk30_gpio_irq_set_wake(struct irq_data *d, unsigned int on) +{ + struct rk30_gpio_bank *bank = irq_data_get_irq_chip_data(d); + u32 bit = gpio_to_bit(irq_to_gpio(d->irq)); + unsigned long flags; + + spin_lock_irqsave(&bank->lock, flags); + if (on) + bank->suspend_wakeup |= bit; + else + bank->suspend_wakeup &= ~bit; + spin_unlock_irqrestore(&bank->lock, flags); + + return 0; +} + +static void rk30_gpio_irq_unmask(struct irq_data *d) +{ + struct rk30_gpio_bank *bank = irq_data_get_irq_chip_data(d); + u32 bit = gpio_to_bit(irq_to_gpio(d->irq)); + unsigned long flags; + + spin_lock_irqsave(&bank->lock, flags); + GPIOEnableIntr(bank->regbase, bit); + spin_unlock_irqrestore(&bank->lock, flags); +} + +static void rk30_gpio_irq_mask(struct irq_data *d) +{ + struct rk30_gpio_bank *bank = irq_data_get_irq_chip_data(d); + u32 bit = gpio_to_bit(irq_to_gpio(d->irq)); + unsigned long flags; + + spin_lock_irqsave(&bank->lock, flags); + GPIODisableIntr(bank->regbase, bit); + spin_unlock_irqrestore(&bank->lock, flags); +} + +static void rk30_gpio_irq_ack(struct irq_data *d) +{ + struct rk30_gpio_bank *bank = irq_data_get_irq_chip_data(d); + u32 bit = gpio_to_bit(irq_to_gpio(d->irq)); + + GPIOAckIntr(bank->regbase, bit); +} + +static int rk30_gpiolib_direction_output(struct gpio_chip *chip, unsigned offset, int val) +{ + struct rk30_gpio_bank *bank = to_rk30_gpio_bank(chip); + u32 bit = offset_to_bit(offset); + unsigned long flags; + + spin_lock_irqsave(&bank->lock, flags); + GPIOSetPinDirection(bank->regbase, bit, GPIO_OUT); + GPIOSetPinLevel(bank->regbase, bit, val); + spin_unlock_irqrestore(&bank->lock, flags); + return 0; +} + +static int rk30_gpiolib_direction_input(struct gpio_chip *chip,unsigned offset) +{ + struct rk30_gpio_bank *bank = to_rk30_gpio_bank(chip); + unsigned long flags; + + spin_lock_irqsave(&bank->lock, flags); + GPIOSetPinDirection(bank->regbase, offset_to_bit(offset), GPIO_IN); + spin_unlock_irqrestore(&bank->lock, flags); + return 0; +} + + +static int rk30_gpiolib_get(struct gpio_chip *chip, unsigned offset) +{ + return GPIOGetPinLevel(to_rk30_gpio_bank(chip)->regbase, offset_to_bit(offset)); +} + +static void rk30_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val) +{ + struct rk30_gpio_bank *bank = to_rk30_gpio_bank(chip); + unsigned long flags; + + spin_lock_irqsave(&bank->lock, flags); + GPIOSetPinLevel(bank->regbase, offset_to_bit(offset), val); + spin_unlock_irqrestore(&bank->lock, flags); +} + +static int rk30_gpiolib_pull_updown(struct gpio_chip *chip, unsigned offset, unsigned enable) +{ + struct rk30_gpio_bank *bank = to_rk30_gpio_bank(chip); + unsigned long flags; + + spin_lock_irqsave(&bank->lock, flags); + if(offset>=16) + rk30_gpio_bit_op((void *__iomem) RK2928_GRF_BASE, GRF_GPIO0H_PULL + bank->id * 8, (1<id * 8, (1<<(offset+16)) | offset_to_bit(offset), !enable); + spin_unlock_irqrestore(&bank->lock, flags); + + return 0; +} + +static int rk30_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset) +{ + return chip->base + offset; +} + +static void rk30_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ +#if 0 + int i; + + for (i = 0; i < chip->ngpio; i++) { + unsigned pin = chip->base + i; + struct gpio_chip *chip = pin_to_gpioChip(pin); + u32 bit = pin_to_bit(pin); + const char *gpio_label; + + if(!chip ||!bit) + return; + + gpio_label = gpiochip_is_requested(chip, i); + if (gpio_label) { + seq_printf(s, "[%s] GPIO%s%d: ", + gpio_label, chip->label, i); + + if (!chip || !bit) + { + seq_printf(s, "!chip || !bit\t"); + return; + } + + GPIOSetPinDirection(chip,bit,GPIO_IN); + seq_printf(s, "pin=%d,level=%d\t", pin,GPIOGetPinLevel(chip,bit)); + seq_printf(s, "\t"); + } + } +#endif +} + +static void rk30_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + struct rk30_gpio_bank *bank = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned gpio_irq; + u32 isr, ilr; + unsigned pin; + unsigned unmasked = 0; + + chained_irq_enter(chip, desc); + + isr = __raw_readl(bank->regbase + GPIO_INT_STATUS); + ilr = __raw_readl(bank->regbase + GPIO_INTTYPE_LEVEL); + + gpio_irq = gpio_to_irq(bank->chip.base); + + while (isr) { + pin = fls(isr) - 1; + /* if gpio is edge triggered, clear condition + * before executing the hander so that we don't + * miss edges + */ + if (ilr & (1 << pin)) { + unmasked = 1; + chained_irq_exit(chip, desc); + } + + generic_handle_irq(gpio_irq + pin); + isr &= ~(1 << pin); + } + + if (!unmasked) + chained_irq_exit(chip, desc); +} + +static struct irq_chip rk30_gpio_irq_chip = { + .name = "GPIO", + .irq_ack = rk30_gpio_irq_ack, + .irq_disable = rk30_gpio_irq_mask, + .irq_mask = rk30_gpio_irq_mask, + .irq_unmask = rk30_gpio_irq_unmask, + .irq_set_type = rk30_gpio_irq_set_type, + .irq_set_wake = rk30_gpio_irq_set_wake, +}; + +void __init rk2928_gpio_init(void) +{ + unsigned int i, j, pin; + struct rk30_gpio_bank *bank; + + bank = rk30_gpio_banks; + pin = PIN_BASE; + + for (i = 0; i < ARRAY_SIZE(rk30_gpio_banks); i++, bank++) { + spin_lock_init(&bank->lock); + bank->clk = clk_get(NULL, bank->chip.label); + clk_enable(bank->clk); + gpiochip_add(&bank->chip); + + __raw_writel(0, bank->regbase + GPIO_INTEN); + for (j = 0; j < 32; j++) { + unsigned int irq = gpio_to_irq(pin); + if (pin > MAX_PIN) + break; + irq_set_lockdep_class(irq, &gpio_lock_class); + irq_set_chip_data(irq, bank); + irq_set_chip_and_handler(irq, &rk30_gpio_irq_chip, handle_level_irq); + set_irq_flags(irq, IRQF_VALID); + pin++; + } + + irq_set_handler_data(bank->irq, bank); + irq_set_chained_handler(bank->irq, rk30_gpio_irq_handler); + } + printk("%s: %d gpio irqs in %d banks\n", __func__, pin - PIN_BASE, ARRAY_SIZE(rk30_gpio_banks)); +} + +#ifdef CONFIG_PM +__weak void rk30_setgpio_suspend_board(void) +{ +} + +__weak void rk30_setgpio_resume_board(void) +{ +} + +static int rk30_gpio_suspend(void) +{ + unsigned i; + + rk30_setgpio_suspend_board(); + + for (i = 0; i < ARRAY_SIZE(rk30_gpio_banks); i++) { + struct rk30_gpio_bank *bank = &rk30_gpio_banks[i]; + + bank->saved_wakeup = __raw_readl(bank->regbase + GPIO_INTEN); + __raw_writel(bank->suspend_wakeup, bank->regbase + GPIO_INTEN); + + if (!bank->suspend_wakeup) + clk_disable(bank->clk); + } + + return 0; +} + +static void rk30_gpio_resume(void) +{ + unsigned i; + + for (i = 0; i < ARRAY_SIZE(rk30_gpio_banks); i++) { + struct rk30_gpio_bank *bank = &rk30_gpio_banks[i]; + u32 isr; + + if (!bank->suspend_wakeup) + clk_enable(bank->clk); + + /* keep enable for resume irq */ + isr = __raw_readl(bank->regbase + GPIO_INT_STATUS); + __raw_writel(bank->saved_wakeup | (bank->suspend_wakeup & isr), bank->regbase + GPIO_INTEN); + } + + rk30_setgpio_resume_board(); +} + +static struct syscore_ops rk30_gpio_syscore_ops = { + .suspend = rk30_gpio_suspend, + .resume = rk30_gpio_resume, +}; + +static int __init rk30_gpio_sysinit(void) +{ + register_syscore_ops(&rk30_gpio_syscore_ops); + return 0; +} + +arch_initcall(rk30_gpio_sysinit); +#endif From ec0d6b3a8a781b62cb3d40d0a1730acab7642f5b Mon Sep 17 00:00:00 2001 From: kfx Date: Thu, 12 Jul 2012 13:05:31 +0800 Subject: [PATCH 017/261] rk2928: update gpio driver(gpio-rk30.c) --- arch/arm/mach-rk2928/common.c | 2 +- arch/arm/mach-rk2928/include/mach/gpio.h | 2 +- drivers/gpio/Makefile | 2 +- drivers/gpio/gpio-rk2928.c | 487 ----------------------- drivers/gpio/gpio-rk30.c | 37 ++ 5 files changed, 40 insertions(+), 490 deletions(-) delete mode 100755 drivers/gpio/gpio-rk2928.c diff --git a/arch/arm/mach-rk2928/common.c b/arch/arm/mach-rk2928/common.c index 6f8d458fad64..f7f96d0eec29 100644 --- a/arch/arm/mach-rk2928/common.c +++ b/arch/arm/mach-rk2928/common.c @@ -118,7 +118,7 @@ void __init rk2928_init_irq(void) #ifdef CONFIG_FIQ rk_fiq_init(); #endif - rk2928_gpio_init(); + rk30_gpio_init(); } extern void __init rk2928_map_common_io(void); diff --git a/arch/arm/mach-rk2928/include/mach/gpio.h b/arch/arm/mach-rk2928/include/mach/gpio.h index d7e713e035ce..0b0a76f31335 100644 --- a/arch/arm/mach-rk2928/include/mach/gpio.h +++ b/arch/arm/mach-rk2928/include/mach/gpio.h @@ -353,7 +353,7 @@ #include #ifndef __ASSEMBLY__ -extern void __init rk2928_gpio_init(void); +extern void __init rk30_gpio_init(void); static inline int gpio_to_irq(unsigned gpio) { return gpio - PIN_BASE + NR_GIC_IRQS; diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 402c46f345c9..51743a21ba9b 100755 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -47,7 +47,7 @@ obj-$(CONFIG_PLAT_NOMADIK) += gpio-nomadik.o obj-$(CONFIG_GPIO_RDC321X) += rdc321x-gpio.o obj-$(CONFIG_ARCH_RK29) += gpio-rk29.o obj-$(CONFIG_ARCH_RK30) += gpio-rk30.o -obj-$(CONFIG_ARCH_RK2928) += gpio-rk2928.o +obj-$(CONFIG_ARCH_RK2928) += gpio-rk30.o obj-$(CONFIG_GPIO_JANZ_TTL) += janz-ttl.o obj-$(CONFIG_GPIO_SX150X) += sx150x.o obj-$(CONFIG_GPIO_VX855) += vx855_gpio.o diff --git a/drivers/gpio/gpio-rk2928.c b/drivers/gpio/gpio-rk2928.c deleted file mode 100755 index 8726c7e7035c..000000000000 --- a/drivers/gpio/gpio-rk2928.c +++ /dev/null @@ -1,487 +0,0 @@ -/* arch/arm/mach-rk29/gpio.c - * - * Copyright (C) 2010 ROCKCHIP, Inc. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#define MAX_PIN RK2928_PIN3_PD7 - -#define to_rk30_gpio_bank(c) container_of(c, struct rk30_gpio_bank, chip) - -struct rk30_gpio_bank { - struct gpio_chip chip; - unsigned short id; - short irq; - void __iomem *regbase; /* Base of register bank */ - struct clk *clk; - u32 suspend_wakeup; - u32 saved_wakeup; - spinlock_t lock; -}; - -static struct lock_class_key gpio_lock_class; - -static void rk30_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip); -static void rk30_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val); -static int rk30_gpiolib_get(struct gpio_chip *chip, unsigned offset); -static int rk30_gpiolib_direction_output(struct gpio_chip *chip,unsigned offset, int val); -static int rk30_gpiolib_direction_input(struct gpio_chip *chip,unsigned offset); -static int rk30_gpiolib_pull_updown(struct gpio_chip *chip, unsigned offset, unsigned enable); -static int rk30_gpiolib_to_irq(struct gpio_chip *chip,unsigned offset); - -#define RK30_GPIO_BANK(ID) \ - { \ - .chip = { \ - .label = "gpio" #ID, \ - .direction_input = rk30_gpiolib_direction_input, \ - .direction_output = rk30_gpiolib_direction_output, \ - .get = rk30_gpiolib_get, \ - .set = rk30_gpiolib_set, \ - .pull_updown = rk30_gpiolib_pull_updown, \ - .dbg_show = rk30_gpiolib_dbg_show, \ - .to_irq = rk30_gpiolib_to_irq, \ - .base = ID < 6 ? PIN_BASE + ID*NUM_GROUP : PIN_BASE + 5*NUM_GROUP, \ - .ngpio = ID < 6 ? NUM_GROUP : 16, \ - }, \ - .id = ID, \ - .irq = IRQ_GPIO##ID, \ - .regbase = (unsigned char __iomem *) RK2928_GPIO##ID##_BASE, \ - } - -static struct rk30_gpio_bank rk30_gpio_banks[] = { - RK30_GPIO_BANK(0), - RK30_GPIO_BANK(1), - RK30_GPIO_BANK(2), - RK30_GPIO_BANK(3), -}; - -static inline void rk30_gpio_bit_op(void __iomem *regbase, unsigned int offset, u32 bit, unsigned char flag) -{ - u32 val = __raw_readl(regbase + offset); - if (flag) - val |= bit; - else - val &= ~bit; - __raw_writel(val, regbase + offset); -} - -static inline struct gpio_chip *pin_to_gpio_chip(unsigned pin) -{ - if (pin < PIN_BASE || pin > MAX_PIN) - return NULL; - - pin -= PIN_BASE; - pin /= NUM_GROUP; - if (likely(pin < ARRAY_SIZE(rk30_gpio_banks))) - return &(rk30_gpio_banks[pin].chip); - return NULL; -} - -static inline unsigned gpio_to_bit(unsigned gpio) -{ - gpio -= PIN_BASE; - return 1u << (gpio % NUM_GROUP); -} - -static inline unsigned offset_to_bit(unsigned offset) -{ - return 1u << offset; -} - -static void GPIOSetPinLevel(void __iomem *regbase, unsigned int bit, eGPIOPinLevel_t level) -{ - rk30_gpio_bit_op(regbase, GPIO_SWPORT_DDR, bit, 1); - rk30_gpio_bit_op(regbase, GPIO_SWPORT_DR, bit, level); -} - -static int GPIOGetPinLevel(void __iomem *regbase, unsigned int bit) -{ - return ((__raw_readl(regbase + GPIO_EXT_PORT) & bit) != 0); -} - -static void GPIOSetPinDirection(void __iomem *regbase, unsigned int bit, eGPIOPinDirection_t direction) -{ - rk30_gpio_bit_op(regbase, GPIO_SWPORT_DDR, bit, direction); - /* Enable debounce may halt cpu on wfi, disable it by default */ - //rk30_gpio_bit_op(regbase, GPIO_DEBOUNCE, bit, 1); -} - -static void GPIOEnableIntr(void __iomem *regbase, unsigned int bit) -{ - rk30_gpio_bit_op(regbase, GPIO_INTEN, bit, 1); -} - -static void GPIODisableIntr(void __iomem *regbase, unsigned int bit) -{ - rk30_gpio_bit_op(regbase, GPIO_INTEN, bit, 0); -} - -static void GPIOAckIntr(void __iomem *regbase, unsigned int bit) -{ - rk30_gpio_bit_op(regbase, GPIO_PORTS_EOI, bit, 1); -} - -static void GPIOSetIntrType(void __iomem *regbase, unsigned int bit, eGPIOIntType_t type) -{ - switch (type) { - case GPIOLevelLow: - rk30_gpio_bit_op(regbase, GPIO_INT_POLARITY, bit, 0); - rk30_gpio_bit_op(regbase, GPIO_INTTYPE_LEVEL, bit, 0); - break; - case GPIOLevelHigh: - rk30_gpio_bit_op(regbase, GPIO_INTTYPE_LEVEL, bit, 0); - rk30_gpio_bit_op(regbase, GPIO_INT_POLARITY, bit, 1); - break; - case GPIOEdgelFalling: - rk30_gpio_bit_op(regbase, GPIO_INTTYPE_LEVEL, bit, 1); - rk30_gpio_bit_op(regbase, GPIO_INT_POLARITY, bit, 0); - break; - case GPIOEdgelRising: - rk30_gpio_bit_op(regbase, GPIO_INTTYPE_LEVEL, bit, 1); - rk30_gpio_bit_op(regbase, GPIO_INT_POLARITY, bit, 1); - break; - } -} - -static int rk30_gpio_irq_set_type(struct irq_data *d, unsigned int type) -{ - struct rk30_gpio_bank *bank = irq_data_get_irq_chip_data(d); - u32 bit = gpio_to_bit(irq_to_gpio(d->irq)); - eGPIOIntType_t int_type; - unsigned long flags; - - switch (type) { - case IRQ_TYPE_EDGE_RISING: - int_type = GPIOEdgelRising; - break; - case IRQ_TYPE_EDGE_FALLING: - int_type = GPIOEdgelFalling; - break; - case IRQ_TYPE_LEVEL_HIGH: - int_type = GPIOLevelHigh; - break; - case IRQ_TYPE_LEVEL_LOW: - int_type = GPIOLevelLow; - break; - default: - return -EINVAL; - } - - spin_lock_irqsave(&bank->lock, flags); - //设置为中断之前,必须先设置为输入状态 - GPIOSetPinDirection(bank->regbase, bit, GPIO_IN); - GPIOSetIntrType(bank->regbase, bit, int_type); - spin_unlock_irqrestore(&bank->lock, flags); - - if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) - __irq_set_handler_locked(d->irq, handle_level_irq); - else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) - __irq_set_handler_locked(d->irq, handle_edge_irq); - - return 0; -} - -static int rk30_gpio_irq_set_wake(struct irq_data *d, unsigned int on) -{ - struct rk30_gpio_bank *bank = irq_data_get_irq_chip_data(d); - u32 bit = gpio_to_bit(irq_to_gpio(d->irq)); - unsigned long flags; - - spin_lock_irqsave(&bank->lock, flags); - if (on) - bank->suspend_wakeup |= bit; - else - bank->suspend_wakeup &= ~bit; - spin_unlock_irqrestore(&bank->lock, flags); - - return 0; -} - -static void rk30_gpio_irq_unmask(struct irq_data *d) -{ - struct rk30_gpio_bank *bank = irq_data_get_irq_chip_data(d); - u32 bit = gpio_to_bit(irq_to_gpio(d->irq)); - unsigned long flags; - - spin_lock_irqsave(&bank->lock, flags); - GPIOEnableIntr(bank->regbase, bit); - spin_unlock_irqrestore(&bank->lock, flags); -} - -static void rk30_gpio_irq_mask(struct irq_data *d) -{ - struct rk30_gpio_bank *bank = irq_data_get_irq_chip_data(d); - u32 bit = gpio_to_bit(irq_to_gpio(d->irq)); - unsigned long flags; - - spin_lock_irqsave(&bank->lock, flags); - GPIODisableIntr(bank->regbase, bit); - spin_unlock_irqrestore(&bank->lock, flags); -} - -static void rk30_gpio_irq_ack(struct irq_data *d) -{ - struct rk30_gpio_bank *bank = irq_data_get_irq_chip_data(d); - u32 bit = gpio_to_bit(irq_to_gpio(d->irq)); - - GPIOAckIntr(bank->regbase, bit); -} - -static int rk30_gpiolib_direction_output(struct gpio_chip *chip, unsigned offset, int val) -{ - struct rk30_gpio_bank *bank = to_rk30_gpio_bank(chip); - u32 bit = offset_to_bit(offset); - unsigned long flags; - - spin_lock_irqsave(&bank->lock, flags); - GPIOSetPinDirection(bank->regbase, bit, GPIO_OUT); - GPIOSetPinLevel(bank->regbase, bit, val); - spin_unlock_irqrestore(&bank->lock, flags); - return 0; -} - -static int rk30_gpiolib_direction_input(struct gpio_chip *chip,unsigned offset) -{ - struct rk30_gpio_bank *bank = to_rk30_gpio_bank(chip); - unsigned long flags; - - spin_lock_irqsave(&bank->lock, flags); - GPIOSetPinDirection(bank->regbase, offset_to_bit(offset), GPIO_IN); - spin_unlock_irqrestore(&bank->lock, flags); - return 0; -} - - -static int rk30_gpiolib_get(struct gpio_chip *chip, unsigned offset) -{ - return GPIOGetPinLevel(to_rk30_gpio_bank(chip)->regbase, offset_to_bit(offset)); -} - -static void rk30_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val) -{ - struct rk30_gpio_bank *bank = to_rk30_gpio_bank(chip); - unsigned long flags; - - spin_lock_irqsave(&bank->lock, flags); - GPIOSetPinLevel(bank->regbase, offset_to_bit(offset), val); - spin_unlock_irqrestore(&bank->lock, flags); -} - -static int rk30_gpiolib_pull_updown(struct gpio_chip *chip, unsigned offset, unsigned enable) -{ - struct rk30_gpio_bank *bank = to_rk30_gpio_bank(chip); - unsigned long flags; - - spin_lock_irqsave(&bank->lock, flags); - if(offset>=16) - rk30_gpio_bit_op((void *__iomem) RK2928_GRF_BASE, GRF_GPIO0H_PULL + bank->id * 8, (1<id * 8, (1<<(offset+16)) | offset_to_bit(offset), !enable); - spin_unlock_irqrestore(&bank->lock, flags); - - return 0; -} - -static int rk30_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset) -{ - return chip->base + offset; -} - -static void rk30_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) -{ -#if 0 - int i; - - for (i = 0; i < chip->ngpio; i++) { - unsigned pin = chip->base + i; - struct gpio_chip *chip = pin_to_gpioChip(pin); - u32 bit = pin_to_bit(pin); - const char *gpio_label; - - if(!chip ||!bit) - return; - - gpio_label = gpiochip_is_requested(chip, i); - if (gpio_label) { - seq_printf(s, "[%s] GPIO%s%d: ", - gpio_label, chip->label, i); - - if (!chip || !bit) - { - seq_printf(s, "!chip || !bit\t"); - return; - } - - GPIOSetPinDirection(chip,bit,GPIO_IN); - seq_printf(s, "pin=%d,level=%d\t", pin,GPIOGetPinLevel(chip,bit)); - seq_printf(s, "\t"); - } - } -#endif -} - -static void rk30_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) -{ - struct rk30_gpio_bank *bank = irq_get_handler_data(irq); - struct irq_chip *chip = irq_desc_get_chip(desc); - unsigned gpio_irq; - u32 isr, ilr; - unsigned pin; - unsigned unmasked = 0; - - chained_irq_enter(chip, desc); - - isr = __raw_readl(bank->regbase + GPIO_INT_STATUS); - ilr = __raw_readl(bank->regbase + GPIO_INTTYPE_LEVEL); - - gpio_irq = gpio_to_irq(bank->chip.base); - - while (isr) { - pin = fls(isr) - 1; - /* if gpio is edge triggered, clear condition - * before executing the hander so that we don't - * miss edges - */ - if (ilr & (1 << pin)) { - unmasked = 1; - chained_irq_exit(chip, desc); - } - - generic_handle_irq(gpio_irq + pin); - isr &= ~(1 << pin); - } - - if (!unmasked) - chained_irq_exit(chip, desc); -} - -static struct irq_chip rk30_gpio_irq_chip = { - .name = "GPIO", - .irq_ack = rk30_gpio_irq_ack, - .irq_disable = rk30_gpio_irq_mask, - .irq_mask = rk30_gpio_irq_mask, - .irq_unmask = rk30_gpio_irq_unmask, - .irq_set_type = rk30_gpio_irq_set_type, - .irq_set_wake = rk30_gpio_irq_set_wake, -}; - -void __init rk2928_gpio_init(void) -{ - unsigned int i, j, pin; - struct rk30_gpio_bank *bank; - - bank = rk30_gpio_banks; - pin = PIN_BASE; - - for (i = 0; i < ARRAY_SIZE(rk30_gpio_banks); i++, bank++) { - spin_lock_init(&bank->lock); - bank->clk = clk_get(NULL, bank->chip.label); - clk_enable(bank->clk); - gpiochip_add(&bank->chip); - - __raw_writel(0, bank->regbase + GPIO_INTEN); - for (j = 0; j < 32; j++) { - unsigned int irq = gpio_to_irq(pin); - if (pin > MAX_PIN) - break; - irq_set_lockdep_class(irq, &gpio_lock_class); - irq_set_chip_data(irq, bank); - irq_set_chip_and_handler(irq, &rk30_gpio_irq_chip, handle_level_irq); - set_irq_flags(irq, IRQF_VALID); - pin++; - } - - irq_set_handler_data(bank->irq, bank); - irq_set_chained_handler(bank->irq, rk30_gpio_irq_handler); - } - printk("%s: %d gpio irqs in %d banks\n", __func__, pin - PIN_BASE, ARRAY_SIZE(rk30_gpio_banks)); -} - -#ifdef CONFIG_PM -__weak void rk30_setgpio_suspend_board(void) -{ -} - -__weak void rk30_setgpio_resume_board(void) -{ -} - -static int rk30_gpio_suspend(void) -{ - unsigned i; - - rk30_setgpio_suspend_board(); - - for (i = 0; i < ARRAY_SIZE(rk30_gpio_banks); i++) { - struct rk30_gpio_bank *bank = &rk30_gpio_banks[i]; - - bank->saved_wakeup = __raw_readl(bank->regbase + GPIO_INTEN); - __raw_writel(bank->suspend_wakeup, bank->regbase + GPIO_INTEN); - - if (!bank->suspend_wakeup) - clk_disable(bank->clk); - } - - return 0; -} - -static void rk30_gpio_resume(void) -{ - unsigned i; - - for (i = 0; i < ARRAY_SIZE(rk30_gpio_banks); i++) { - struct rk30_gpio_bank *bank = &rk30_gpio_banks[i]; - u32 isr; - - if (!bank->suspend_wakeup) - clk_enable(bank->clk); - - /* keep enable for resume irq */ - isr = __raw_readl(bank->regbase + GPIO_INT_STATUS); - __raw_writel(bank->saved_wakeup | (bank->suspend_wakeup & isr), bank->regbase + GPIO_INTEN); - } - - rk30_setgpio_resume_board(); -} - -static struct syscore_ops rk30_gpio_syscore_ops = { - .suspend = rk30_gpio_suspend, - .resume = rk30_gpio_resume, -}; - -static int __init rk30_gpio_sysinit(void) -{ - register_syscore_ops(&rk30_gpio_syscore_ops); - return 0; -} - -arch_initcall(rk30_gpio_sysinit); -#endif diff --git a/drivers/gpio/gpio-rk30.c b/drivers/gpio/gpio-rk30.c index 3d30d7341fb7..54b64f968dca 100755 --- a/drivers/gpio/gpio-rk30.c +++ b/drivers/gpio/gpio-rk30.c @@ -32,7 +32,12 @@ #include #include +#ifdef CONFIG_ARCH_RK30 #define MAX_PIN RK30_PIN6_PB7 +#endif +#ifdef CONFIG_ARCH_RK2928 +#define MAX_PIN RK2928_PIN3_PD7 +#endif #define to_rk30_gpio_bank(c) container_of(c, struct rk30_gpio_bank, chip) @@ -57,6 +62,7 @@ static int rk30_gpiolib_direction_input(struct gpio_chip *chip,unsigned offset); static int rk30_gpiolib_pull_updown(struct gpio_chip *chip, unsigned offset, unsigned enable); static int rk30_gpiolib_to_irq(struct gpio_chip *chip,unsigned offset); +#ifdef CONFIG_ARCH_RK30 #define RK30_GPIO_BANK(ID) \ { \ .chip = { \ @@ -75,14 +81,37 @@ static int rk30_gpiolib_to_irq(struct gpio_chip *chip,unsigned offset); .irq = IRQ_GPIO##ID, \ .regbase = (unsigned char __iomem *) RK30_GPIO##ID##_BASE, \ } +#endif +#ifdef CONFIG_ARCH_RK2928 +#define RK30_GPIO_BANK(ID) \ + { \ + .chip = { \ + .label = "gpio" #ID, \ + .direction_input = rk30_gpiolib_direction_input, \ + .direction_output = rk30_gpiolib_direction_output, \ + .get = rk30_gpiolib_get, \ + .set = rk30_gpiolib_set, \ + .pull_updown = rk30_gpiolib_pull_updown, \ + .dbg_show = rk30_gpiolib_dbg_show, \ + .to_irq = rk30_gpiolib_to_irq, \ + .base = ID < 6 ? PIN_BASE + ID*NUM_GROUP : PIN_BASE + 5*NUM_GROUP, \ + .ngpio = ID < 6 ? NUM_GROUP : 16, \ + }, \ + .id = ID, \ + .irq = IRQ_GPIO##ID, \ + .regbase = (unsigned char __iomem *) RK2928_GPIO##ID##_BASE, \ + } +#endif static struct rk30_gpio_bank rk30_gpio_banks[] = { RK30_GPIO_BANK(0), RK30_GPIO_BANK(1), RK30_GPIO_BANK(2), RK30_GPIO_BANK(3), +#ifdef CONFIG_ARCH_RK30 RK30_GPIO_BANK(4), RK30_GPIO_BANK(6), +#endif }; static inline void rk30_gpio_bit_op(void __iomem *regbase, unsigned int offset, u32 bit, unsigned char flag) @@ -303,10 +332,18 @@ static int rk30_gpiolib_pull_updown(struct gpio_chip *chip, unsigned offset, uns unsigned long flags; spin_lock_irqsave(&bank->lock, flags); +#ifdef CONFIG_ARCH_RK30 if(offset>=16) rk30_gpio_bit_op((void *__iomem) RK30_GRF_BASE, GRF_GPIO0H_PULL + bank->id * 8, (1<id * 8, (1<<(offset+16)) | offset_to_bit(offset), !enable); +#endif +#ifdef CONFIG_ARCH_RK2928 + if(offset>=16) + rk30_gpio_bit_op((void *__iomem) RK2928_GRF_BASE, GRF_GPIO0H_PULL + bank->id * 8, (1<id * 8, (1<<(offset+16)) | offset_to_bit(offset), !enable); +#endif spin_unlock_irqrestore(&bank->lock, flags); return 0; From 0f7b34679500b8370283067ea5571d2b88cb5bfe Mon Sep 17 00:00:00 2001 From: kfx Date: Thu, 12 Jul 2012 14:31:18 +0800 Subject: [PATCH 018/261] rk2928: i2s init --- arch/arm/mach-rk2928/board-rk2928-fpga.c | 5 +++ arch/arm/mach-rk2928/devices.c | 46 ++++++++++++++++++++++++ sound/soc/rk29/Kconfig | 4 +-- sound/soc/rk29/Makefile | 5 ++- sound/soc/rk29/rk30_i2s.c | 23 +++++++++++- 5 files changed, 79 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-rk2928/board-rk2928-fpga.c b/arch/arm/mach-rk2928/board-rk2928-fpga.c index ed5b66e9303f..cc9c9923a6fe 100644 --- a/arch/arm/mach-rk2928/board-rk2928-fpga.c +++ b/arch/arm/mach-rk2928/board-rk2928-fpga.c @@ -91,6 +91,11 @@ static struct clk_lookup clks[] = { CLK("rk_serial.2", "uart_frac_div", &xin24m), CLK("rk_serial.2", "uart", &xin24m), CLK("rk_serial.2", "pclk_uart", &xin24m), + + CLK("rk29_i2s.0", "i2s_div", &xin24m), + CLK("rk29_i2s.0", "i2s_frac_div", &xin24m), + CLK("rk29_i2s.0", "i2s", &xin24m), + CLK("rk29_i2s.0", "hclk_i2s", &xin24m), }; void __init rk30_clock_init(void) diff --git a/arch/arm/mach-rk2928/devices.c b/arch/arm/mach-rk2928/devices.c index bbc9868cf2a6..4f8ea31fbdbe 100755 --- a/arch/arm/mach-rk2928/devices.c +++ b/arch/arm/mach-rk2928/devices.c @@ -490,6 +490,51 @@ static void __init rk2928_init_spim(void) platform_device_register(&rk29xx_device_spi0m); #endif } +#ifdef CONFIG_SND_RK29_SOC_I2S +#ifdef CONFIG_SND_RK29_SOC_I2S_8CH +static struct resource resource_iis0_8ch[] = { + [0] = { + .start = RK2928_I2S_PHYS, + .end = RK2928_I2S_PHYS + RK2928_I2S_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = DMACH_I2S0_8CH_TX, + .end = DMACH_I2S0_8CH_TX, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = DMACH_I2S0_8CH_RX, + .end = DMACH_I2S0_8CH_RX, + .flags = IORESOURCE_DMA, + }, + [3] = { + .start = IRQ_I2S, + .end = IRQ_I2S, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device device_iis0_8ch = { + .name = "rk29_i2s", + .id = 0, + .num_resources = ARRAY_SIZE(resource_iis0_8ch), + .resource = resource_iis0_8ch, +}; +#endif +#endif +static struct platform_device device_pcm = { + .name = "rockchip-audio", + .id = -1, +}; + +static void __init rk2928_init_i2s(void) +{ +#ifdef CONFIG_SND_RK29_SOC_I2S_8CH + platform_device_register(&device_iis0_8ch); +#endif + platform_device_register(&device_pcm); +} #ifdef CONFIG_KEYS_RK29 extern struct rk29_keys_platform_data rk29_keys_pdata; static struct platform_device device_keys = { @@ -512,6 +557,7 @@ static int __init rk2928_init_devices(void) #if defined(CONFIG_FIQ_DEBUGGER) && defined(DEBUG_UART_PHYS) rk_serial_debug_init(DEBUG_UART_BASE, IRQ_DEBUG_UART, IRQ_UART_SIGNAL, -1); #endif + rk2928_init_i2s(); return 0; } arch_initcall(rk2928_init_devices); diff --git a/sound/soc/rk29/Kconfig b/sound/soc/rk29/Kconfig index 1bc84a597cdf..63e28d3c21e1 100755 --- a/sound/soc/rk29/Kconfig +++ b/sound/soc/rk29/Kconfig @@ -19,14 +19,14 @@ config SND_RK29_SOC_I2S_8CH config SND_RK29_SOC_I2S_2CH bool "Soc RK29 I2S 2 Channel support(I2S1)" default n - depends on SND_RK29_SOC_I2S + depends on SND_RK29_SOC_I2S && !ARCH_RK2928 help This supports the use of the 2 Channel I2S interface on rk29 processors. config SND_RK_SOC_I2S2_2CH bool "Soc RK29 I2S 2 Channel support(I2S2)" default n - depends on SND_RK29_SOC_I2S && ARCH_RK30 + depends on SND_RK29_SOC_I2S && ARCH_RK30 && !ARCH_RK2928 help This supports the use of the 2 Channel I2S2 interface on rk30 processors. diff --git a/sound/soc/rk29/Makefile b/sound/soc/rk29/Makefile index a1f0de123846..0d06e37a1620 100644 --- a/sound/soc/rk29/Makefile +++ b/sound/soc/rk29/Makefile @@ -6,6 +6,9 @@ endif ifdef CONFIG_ARCH_RK30 snd-soc-rockchip-i2s-objs := rk30_i2s.o endif +ifdef CONFIG_ARCH_RK2928 +snd-soc-rockchip-i2s-objs := rk30_i2s.o +endif snd-soc-rockchip-spdif-objs := rk29_spdif.o obj-$(CONFIG_SND_RK29_SOC) += snd-soc-rockchip.o @@ -37,4 +40,4 @@ obj-$(CONFIG_SND_RK29_SOC_CS42L52) += snd-soc-cs42l52.o obj-$(CONFIG_SND_RK29_SOC_AIC3111) += snd-soc-aic3111.o obj-$(CONFIG_SND_RK29_SOC_AIC3262) += snd-soc-aic3262.o obj-$(CONFIG_SND_RK29_SOC_HDMI) += snd-soc-hdmi.o -obj-$(CONFIG_SND_RK29_SOC_RK610) += snd-soc-rk610.o \ No newline at end of file +obj-$(CONFIG_SND_RK29_SOC_RK610) += snd-soc-rk610.o diff --git a/sound/soc/rk29/rk30_i2s.c b/sound/soc/rk29/rk30_i2s.c index 19ce18820571..f03cbbee1f3b 100755 --- a/sound/soc/rk29/rk30_i2s.c +++ b/sound/soc/rk29/rk30_i2s.c @@ -484,6 +484,7 @@ static int rockchip_i2s_dai_probe(struct snd_soc_dai *dai) { I2S_DBG("Enter %s, %d >>>>>>>>>>>\n", __func__, __LINE__); switch(dai->id) { +#ifdef CONFIG_ARCH_RK30 case 0: rk30_mux_api_set(GPIO0A7_I2S8CHSDI_NAME, GPIO0A_I2S_8CH_SDI); rk30_mux_api_set(GPIO0B0_I2S8CHCLK_NAME, GPIO0B_I2S_8CH_CLK); @@ -511,6 +512,16 @@ static int rockchip_i2s_dai_probe(struct snd_soc_dai *dai) rk30_mux_api_set(GPIO0D4_I2S22CHSDI_SMCADDR0_NAME, GPIO0D_I2S2_2CH_SDI); rk30_mux_api_set(GPIO0D5_I2S22CHSDO_SMCADDR1_NAME, GPIO0D_I2S2_2CH_SDO); break; +#endif +#ifdef CONFIG_ARCH_RK2928 + case 0: + rk30_mux_api_set(GPIO1A0_I2S_MCLK_NAME, GPIO1A_I2S_MCLK); + rk30_mux_api_set(GPIO1A1_I2S_SCLK_NAME, GPIO1A_I2S_SCLK); + rk30_mux_api_set(GPIO1A2_I2S_LRCKRX_NAME, GPIO1A_I2S_LRCKRX); + rk30_mux_api_set(GPIO1A3_I2S_LRCKTX_NAME, GPIO1A_I2S_LRCKTX); + rk30_mux_api_set(GPIO1A4_I2S_SDO_NAME, GPIO1A_I2S_SDO); + rk30_mux_api_set(GPIO1A5_I2S_SDI_NAME, GPIO1A_I2S_SDI); +#endif default: I2S_DBG("Enter:%s, %d, Error For DevId!!!", __FUNCTION__, __LINE__); return -EINVAL; @@ -627,6 +638,7 @@ static int __devinit rockchip_i2s_probe(struct platform_device *pdev) switch(pdev->id) { +#ifdef CONFIG_ARCH_RK30 case 0: i2s->dma_capture->channel = DMACH_I2S0_8CH_RX; i2s->dma_capture->dma_addr = RK30_I2S0_8CH_PHYS + I2S_RXR_BUFF; @@ -644,7 +656,16 @@ static int __devinit rockchip_i2s_probe(struct platform_device *pdev) i2s->dma_capture->dma_addr = RK30_I2S2_2CH_PHYS + I2S_RXR_BUFF; i2s->dma_playback->channel = DMACH_I2S2_2CH_TX; i2s->dma_playback->dma_addr = RK30_I2S2_2CH_PHYS + I2S_TXR_BUFF; - break; + break; +#endif +#ifdef CONFIG_ARCH_RK2928 + case 0: + i2s->dma_capture->channel = DMACH_I2S0_8CH_RX; + i2s->dma_capture->dma_addr = RK2928_I2S_PHYS + I2S_RXR_BUFF; + i2s->dma_playback->channel = DMACH_I2S0_8CH_TX; + i2s->dma_playback->dma_addr = RK2928_I2S_PHYS + I2S_TXR_BUFF; + break; +#endif } i2s->dma_capture->client = &rk29_dma_client_in; From e2dbca8dae4abaf3e907cc536191ee69c7cb768c Mon Sep 17 00:00:00 2001 From: kfx Date: Thu, 12 Jul 2012 14:57:37 +0800 Subject: [PATCH 019/261] rk2928: update i2s driver --- sound/soc/rk29/rk30_i2s.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/rk29/rk30_i2s.c b/sound/soc/rk29/rk30_i2s.c index f03cbbee1f3b..150c44770c75 100755 --- a/sound/soc/rk29/rk30_i2s.c +++ b/sound/soc/rk29/rk30_i2s.c @@ -521,6 +521,7 @@ static int rockchip_i2s_dai_probe(struct snd_soc_dai *dai) rk30_mux_api_set(GPIO1A3_I2S_LRCKTX_NAME, GPIO1A_I2S_LRCKTX); rk30_mux_api_set(GPIO1A4_I2S_SDO_NAME, GPIO1A_I2S_SDO); rk30_mux_api_set(GPIO1A5_I2S_SDI_NAME, GPIO1A_I2S_SDI); + break; #endif default: I2S_DBG("Enter:%s, %d, Error For DevId!!!", __FUNCTION__, __LINE__); From a6c33cb21c3792d27f40baa31cf045f229a1ead3 Mon Sep 17 00:00:00 2001 From: kfx Date: Thu, 12 Jul 2012 17:32:13 +0800 Subject: [PATCH 020/261] rk2928: add spi&i2c board config --- arch/arm/mach-rk2928/board-rk2928-fpga.c | 49 ++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/arch/arm/mach-rk2928/board-rk2928-fpga.c b/arch/arm/mach-rk2928/board-rk2928-fpga.c index cc9c9923a6fe..c04f2b352926 100644 --- a/arch/arm/mach-rk2928/board-rk2928-fpga.c +++ b/arch/arm/mach-rk2928/board-rk2928-fpga.c @@ -43,8 +43,57 @@ #include #include +//i2c +#ifdef CONFIG_I2C0_RK30 +static struct i2c_board_info __initdata i2c0_info[] = { +}; +#endif +#ifdef CONFIG_I2C1_RK30 +static struct i2c_board_info __initdata i2c1_info[] = { +}; +#endif +#ifdef CONFIG_I2C2_RK30 +static struct i2c_board_info __initdata i2c2_info[] = { +}; +#endif +#ifdef CONFIG_I2C3_RK30 +static struct i2c_board_info __initdata i2c3_info[] = { +}; +#endif +#ifdef CONFIG_I2C_GPIO_RK30 +static struct i2c_board_info __initdata i2c_gpio_info[] = { +}; +#endif +static void __init rk30_i2c_register_board_info(void) +{ +#ifdef CONFIG_I2C0_RK30 + i2c_register_board_info(0, i2c0_info, ARRAY_SIZE(i2c0_info)); +#endif +#ifdef CONFIG_I2C1_RK30 + i2c_register_board_info(1, i2c1_info, ARRAY_SIZE(i2c1_info)); +#endif +#ifdef CONFIG_I2C2_RK30 + i2c_register_board_info(2, i2c2_info, ARRAY_SIZE(i2c2_info)); +#endif +#ifdef CONFIG_I2C3_RK30 + i2c_register_board_info(3, i2c3_info, ARRAY_SIZE(i2c3_info)); +#endif +#ifdef CONFIG_I2C_GPIO_RK30 + i2c_register_board_info(4, i2c_gpio_info, ARRAY_SIZE(i2c_gpio_info)); +#endif +} +//end of i2c +static struct spi_board_info board_spi_devices[] = { +}; + +static struct platform_device *devices[] __initdata = { +}; + static void __init rk2928_board_init(void) { + rk30_i2c_register_board_info(); + spi_register_board_info(board_spi_devices, ARRAY_SIZE(board_spi_devices)); + platform_add_devices(devices, ARRAY_SIZE(devices)); } static void __init rk2928_reserve(void) From 693e55f09b99ca2028a55494da9f9af50258f6ba Mon Sep 17 00:00:00 2001 From: kfx Date: Mon, 16 Jul 2012 18:07:00 +0800 Subject: [PATCH 021/261] rk2928: devices.c: add rga support --- arch/arm/mach-rk2928/devices.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/arm/mach-rk2928/devices.c b/arch/arm/mach-rk2928/devices.c index 4f8ea31fbdbe..65088c834bcc 100755 --- a/arch/arm/mach-rk2928/devices.c +++ b/arch/arm/mach-rk2928/devices.c @@ -490,6 +490,27 @@ static void __init rk2928_init_spim(void) platform_device_register(&rk29xx_device_spi0m); #endif } +#ifdef CONFIG_RGA_RK30 +static struct resource resource_rga[] = { + [0] = { + .start = RK30_RGA_PHYS, + .end = RK30_RGA_PHYS + RK30_RGA_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_RGA, + .end = IRQ_RGA, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device device_rga = { + .name = "rga", + .id = -1, + .num_resources = ARRAY_SIZE(resource_rga), + .resource = resource_rga, +}; +#endif #ifdef CONFIG_SND_RK29_SOC_I2S #ifdef CONFIG_SND_RK29_SOC_I2S_8CH static struct resource resource_iis0_8ch[] = { @@ -554,6 +575,9 @@ static int __init rk2928_init_devices(void) #ifdef CONFIG_KEYS_RK29 platform_device_register(&device_keys); #endif +#ifdef CONFIG_RGA_RK30 + platform_device_register(&device_rga); +#endif #if defined(CONFIG_FIQ_DEBUGGER) && defined(DEBUG_UART_PHYS) rk_serial_debug_init(DEBUG_UART_BASE, IRQ_DEBUG_UART, IRQ_UART_SIGNAL, -1); #endif From fd02ff2c9de40abb89b0da263afbbac4271fb6d1 Mon Sep 17 00:00:00 2001 From: zsq Date: Tue, 17 Jul 2012 09:13:40 +0800 Subject: [PATCH 022/261] add rga driver that are debugged --- arch/arm/mach-rk2928/devices.c | 4 +- arch/arm/mach-rk30/include/mach/io.h | 2 +- drivers/video/rockchip/rga/Kconfig | 4 +- drivers/video/rockchip/rga/rga.h | 2 +- drivers/video/rockchip/rga/rga_drv.c | 90 ++++++++++++++++++++++------ 5 files changed, 77 insertions(+), 25 deletions(-) mode change 100644 => 100755 arch/arm/mach-rk30/include/mach/io.h diff --git a/arch/arm/mach-rk2928/devices.c b/arch/arm/mach-rk2928/devices.c index 65088c834bcc..51b3d6b42f03 100755 --- a/arch/arm/mach-rk2928/devices.c +++ b/arch/arm/mach-rk2928/devices.c @@ -493,8 +493,8 @@ static void __init rk2928_init_spim(void) #ifdef CONFIG_RGA_RK30 static struct resource resource_rga[] = { [0] = { - .start = RK30_RGA_PHYS, - .end = RK30_RGA_PHYS + RK30_RGA_SIZE - 1, + .start = RK2928_RGA_PHYS, + .end = RK2928_RGA_PHYS + RK2928_RGA_SIZE - 1, .flags = IORESOURCE_MEM, }, [1] = { diff --git a/arch/arm/mach-rk30/include/mach/io.h b/arch/arm/mach-rk30/include/mach/io.h old mode 100644 new mode 100755 index 062123b5fcf4..4e63be277cc7 --- a/arch/arm/mach-rk30/include/mach/io.h +++ b/arch/arm/mach-rk30/include/mach/io.h @@ -44,7 +44,7 @@ #define RK30_LCDC1_SIZE SZ_8K #define RK30_IPP_PHYS 0x10110000 #define RK30_IPP_SIZE SZ_16K -#define RK30_RGA_PHYS 0x10114000 +#define RK30_RGA_PHYS 0x1010c000 #define RK30_RGA_SIZE SZ_8K #define RK30_HDMI_PHYS 0x10116000 #define RK30_HDMI_SIZE SZ_8K diff --git a/drivers/video/rockchip/rga/Kconfig b/drivers/video/rockchip/rga/Kconfig index 4653cd8a1c70..152e2bd55ef0 100755 --- a/drivers/video/rockchip/rga/Kconfig +++ b/drivers/video/rockchip/rga/Kconfig @@ -1,8 +1,8 @@ menu "RGA" - depends on ARCH_RK30 + depends on ARCH_RK30 || ARCH_RK2928 config RGA_RK30 - tristate "ROCKCHIP RK30 RGA" + tristate "ROCKCHIP RK30 || RK2928 RGA" help rk30 rga module. diff --git a/drivers/video/rockchip/rga/rga.h b/drivers/video/rockchip/rga/rga.h index 9b30f05045fb..ff741623f176 100755 --- a/drivers/video/rockchip/rga/rga.h +++ b/drivers/video/rockchip/rga/rga.h @@ -386,7 +386,7 @@ typedef struct rga_service_info { -#define RGA_BASE 0x10114000 +#define RGA_BASE 0x1010c000 //General Registers #define RGA_SYS_CTRL 0x000 diff --git a/drivers/video/rockchip/rga/rga_drv.c b/drivers/video/rockchip/rga/rga_drv.c index ae966f488a29..00fa3796019a 100755 --- a/drivers/video/rockchip/rga/rga_drv.c +++ b/drivers/video/rockchip/rga/rga_drv.c @@ -60,7 +60,7 @@ #define RGA_MAJOR 255 -#define RK30_RGA_PHYS 0x10114000 +#define RK30_RGA_PHYS 0x1010C000 #define RK30_RGA_SIZE SZ_8K #define RGA_RESET_TIMEOUT 1000 @@ -100,7 +100,7 @@ static void rga_try_set_reg(void); /* Logging */ -#define RGA_DEBUG 0 +#define RGA_DEBUG 1 #if RGA_DEBUG #define DBG(format, args...) printk(KERN_DEBUG "%s: " format, DRIVER_NAME, ## args) #define ERR(format, args...) printk(KERN_ERR "%s: " format, DRIVER_NAME, ## args) @@ -124,6 +124,7 @@ static inline u32 rga_read(u32 r) return __raw_readl(drvdata->rga_base + r); } +#if 0 static void rga_soft_reset(void) { u32 i; @@ -144,6 +145,7 @@ static void rga_soft_reset(void) if(i == RGA_RESET_TIMEOUT) ERR("soft reset timeout.\n"); } +#endif static void rga_dump(void) { @@ -571,7 +573,7 @@ static void rga_try_set_reg(void) dmac_flush_range(&rga_service.cmd_buff[0], &rga_service.cmd_buff[28]); outer_flush_range(virt_to_phys(&rga_service.cmd_buff[0]),virt_to_phys(&rga_service.cmd_buff[28])); - rga_soft_reset(); + //rga_soft_reset(); rga_write(0, RGA_MMU_CTRL); /* CMD buff */ @@ -588,7 +590,6 @@ static void rga_try_set_reg(void) printk("%.8x %.8x %.8x %.8x\n", p[0 + i*4], p[1+i*4], p[2 + i*4], p[3 + i*4]); } #endif - /* master mode */ rga_write((0x1<<2)|(0x1<<3), RGA_SYS_CTRL); @@ -609,10 +610,10 @@ static void rga_try_set_reg(void) } #endif } - else - { +// else +// { // rga_power_off(); - } +// } } } @@ -1037,6 +1038,7 @@ static irqreturn_t rga_irq_thread(int irq, void *dev_id) rga_del_running_list(); rga_try_set_reg(); } + printk("****** rga irq prc avil ******\n"); mutex_unlock(&rga_service.lock); return IRQ_HANDLED; @@ -1079,6 +1081,8 @@ static int __devinit rga_drv_probe(struct platform_device *pdev) rga_service.last_prc_src_format = 1; /* default is yuv first*/ rga_service.enable = false; + printk("rga_drv_probe\n"); + data = kzalloc(sizeof(struct rga_drvdata), GFP_KERNEL); if(NULL == data) { @@ -1247,12 +1251,15 @@ static void __exit rga_exit(void) #if 0 +#if 1 extern struct fb_info * rk_get_fb(int fb_id); EXPORT_SYMBOL(rk_get_fb); extern void rk_direct_fb_show(struct fb_info * fbi); EXPORT_SYMBOL(rk_direct_fb_show); +#endif + unsigned int src_buf[1920*1080]; unsigned int dst_buf[1920*1080]; @@ -1276,9 +1283,9 @@ void rga_test_0(void) //file->private_data = (void *)session; fb = rk_get_fb(0); - + memset(&req, 0, sizeof(struct rga_req)); - src = Y4200_320_240_swap0; + src = src_buf; dst = dst_buf; //memset(src_buf, 0x80, 1920*1080*4); @@ -1294,15 +1301,15 @@ void rga_test_0(void) outer_flush_range(virt_to_phys(&dst_buf[0]),virt_to_phys(&dst_buf[800*480])); #endif - req.src.act_w = 320; - req.src.act_h = 240; + req.src.act_w = 1280; + req.src.act_h = 800; - req.src.vir_w = 320; - req.src.vir_h = 240; - req.src.yrgb_addr = (uint32_t)src; - req.src.uv_addr = (uint32_t)UV4200_320_240_swap0; - req.src.v_addr = (uint32_t)V4200_320_240_swap0; - req.src.format = RK_FORMAT_YCbCr_420_SP; + req.src.vir_w = 1280; + req.src.vir_h = 800; + req.src.yrgb_addr = (uint32_t)virt_to_phys(src); + req.src.uv_addr = (uint32_t)virt_to_phys(src); + req.src.v_addr = (uint32_t)virt_to_phys(src); + req.src.format = 0; req.dst.act_w = 1280; req.dst.act_h = 800; @@ -1311,7 +1318,7 @@ void rga_test_0(void) req.dst.vir_h = 800; req.dst.x_offset = 0; req.dst.y_offset = 0; - req.dst.yrgb_addr = (uint32_t)dst; + req.dst.yrgb_addr = (uint32_t)virt_to_phys(dst); //req.dst.format = RK_FORMAT_RGB_565; @@ -1337,8 +1344,52 @@ void rga_test_0(void) rga_blit_sync(&session, &req); - fb->var.bits_per_pixel = 32; + req.src.act_w = 1280; + req.src.act_h = 800; + req.src.vir_w = 1280; + req.src.vir_h = 800; + req.src.yrgb_addr = (uint32_t)virt_to_phys(src); + req.src.uv_addr = (uint32_t)virt_to_phys(src); + req.src.v_addr = (uint32_t)virt_to_phys(src); + req.src.format = RK_FORMAT_YCbCr_420_SP; + + req.dst.act_w = 1280; + req.dst.act_h = 800; + + req.dst.vir_w = 1280; + req.dst.vir_h = 800; + req.dst.x_offset = 0; + req.dst.y_offset = 0; + req.dst.yrgb_addr = (uint32_t)virt_to_phys(dst); + + //req.dst.format = RK_FORMAT_RGB_565; + + req.clip.xmin = 0; + req.clip.xmax = 1279; + req.clip.ymin = 0; + req.clip.ymax = 799; + + //req.render_mode = color_fill_mode; + //req.fg_color = 0x80ffffff; + + req.rotate_mode = 1; + req.scale_mode = 2; + + //req.alpha_rop_flag = 0; + //req.alpha_rop_mode = 0x1; + + req.sina = 0; + req.cosa = 65536; + + //req.mmu_info.mmu_flag = 0x21; + //req.mmu_info.mmu_en = 1; + + rga_blit_sync(&session, &req); + + #if 0 + fb->var.bits_per_pixel = 32; + fb->var.xres = 1280; fb->var.yres = 800; @@ -1365,6 +1416,7 @@ void rga_test_0(void) fb->fix.smem_start = virt_to_phys(dst); rk_direct_fb_show(fb); + #endif } From 64a147f2460aedc9f857a6800516f49d155a9019 Mon Sep 17 00:00:00 2001 From: zsq Date: Tue, 17 Jul 2012 10:04:11 +0800 Subject: [PATCH 023/261] add some define for rga common platform used --- arch/arm/mach-rk30/include/mach/io.h | 2 +- drivers/video/rockchip/rga/rga.h | 4 ++++ drivers/video/rockchip/rga/rga_drv.c | 31 +++++++++++++++++++++++----- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-rk30/include/mach/io.h b/arch/arm/mach-rk30/include/mach/io.h index 4e63be277cc7..062123b5fcf4 100755 --- a/arch/arm/mach-rk30/include/mach/io.h +++ b/arch/arm/mach-rk30/include/mach/io.h @@ -44,7 +44,7 @@ #define RK30_LCDC1_SIZE SZ_8K #define RK30_IPP_PHYS 0x10110000 #define RK30_IPP_SIZE SZ_16K -#define RK30_RGA_PHYS 0x1010c000 +#define RK30_RGA_PHYS 0x10114000 #define RK30_RGA_SIZE SZ_8K #define RK30_HDMI_PHYS 0x10116000 #define RK30_HDMI_SIZE SZ_8K diff --git a/drivers/video/rockchip/rga/rga.h b/drivers/video/rockchip/rga/rga.h index ff741623f176..bbf5fa94833d 100755 --- a/drivers/video/rockchip/rga/rga.h +++ b/drivers/video/rockchip/rga/rga.h @@ -386,7 +386,11 @@ typedef struct rga_service_info { +#if defined(CONFIG_ARCH_RK2928) #define RGA_BASE 0x1010c000 +#elif defined(CONFIG_ARCH_RK30) +#define RGA_BASE 0x10114000 +#endif //General Registers #define RGA_SYS_CTRL 0x000 diff --git a/drivers/video/rockchip/rga/rga_drv.c b/drivers/video/rockchip/rga/rga_drv.c index 00fa3796019a..149769b85c1b 100755 --- a/drivers/video/rockchip/rga/rga_drv.c +++ b/drivers/video/rockchip/rga/rga_drv.c @@ -60,9 +60,17 @@ #define RGA_MAJOR 255 +#if 0 +#if CONFIG_ARCH_RK2928 #define RK30_RGA_PHYS 0x1010C000 #define RK30_RGA_SIZE SZ_8K #define RGA_RESET_TIMEOUT 1000 +#elif CONFIG_ARCH_RK30 +#define RK30_RGA_PHYS 0x10114000 +#define RK30_RGA_SIZE SZ_8K +#define RGA_RESET_TIMEOUT 1000 +#endif +#endif /* Driver information */ #define DRIVER_DESC "RGA Device Driver" @@ -100,7 +108,7 @@ static void rga_try_set_reg(void); /* Logging */ -#define RGA_DEBUG 1 +#define RGA_DEBUG 0 #if RGA_DEBUG #define DBG(format, args...) printk(KERN_DEBUG "%s: " format, DRIVER_NAME, ## args) #define ERR(format, args...) printk(KERN_ERR "%s: " format, DRIVER_NAME, ## args) @@ -124,7 +132,7 @@ static inline u32 rga_read(u32 r) return __raw_readl(drvdata->rga_base + r); } -#if 0 +#if defined(CONFIG_ARCH_RK30) static void rga_soft_reset(void) { u32 i; @@ -573,7 +581,10 @@ static void rga_try_set_reg(void) dmac_flush_range(&rga_service.cmd_buff[0], &rga_service.cmd_buff[28]); outer_flush_range(virt_to_phys(&rga_service.cmd_buff[0]),virt_to_phys(&rga_service.cmd_buff[28])); - //rga_soft_reset(); + #if defined(CONFIG_ARCH_RK30) + rga_soft_reset(); + #endif + rga_write(0, RGA_MMU_CTRL); /* CMD buff */ @@ -1097,13 +1108,23 @@ static int __devinit rga_drv_probe(struct platform_device *pdev) data->aclk_rga = clk_get(NULL, "aclk_rga"); data->hclk_rga = clk_get(NULL, "hclk_rga"); + /* map the memory */ - if (!request_mem_region(RK30_RGA_PHYS, RK30_RGA_SIZE, "rga_io")) + #if defined(CONFIG_ARCH_RK2928) + if (!request_mem_region(RK2928_RGA_PHYS, RK2928_RGA_SIZE, "rga_io")) + #elif defined(CONFIG_ARCH_RK30) + if (!request_mem_region(RK30_RGA_PHYS, RK30_RGA_SIZE, "rga_io")) + #endif { pr_info("failed to reserve rga HW regs\n"); return -EBUSY; } - data->rga_base = (void*)ioremap_nocache(RK30_RGA_PHYS, RK30_RGA_SIZE); + + #if defined(CONFIG_ARCH_RK2928) + data->rga_base = (void*)ioremap_nocache(RK2928_RGA_PHYS, RK2928_RGA_SIZE); + #elif defined(CONFIG_ARCH_RK30) + data->rga_base = (void*)ioremap_nocache(RK30_RGA_PHYS, RK30_RGA_SIZE); + #endif if (data->rga_base == NULL) { ERR("rga ioremap failed\n"); From 1fd0835ee318a034498db8aee7f647f0e178fabe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Tue, 17 Jul 2012 14:27:21 +0800 Subject: [PATCH 024/261] rk2928: irqs.h: add IRQ_ARM_PMU define --- arch/arm/mach-rk2928/include/mach/irqs.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-rk2928/include/mach/irqs.h b/arch/arm/mach-rk2928/include/mach/irqs.h index f1bdd00d2cc8..d0d398074bac 100644 --- a/arch/arm/mach-rk2928/include/mach/irqs.h +++ b/arch/arm/mach-rk2928/include/mach/irqs.h @@ -53,6 +53,8 @@ #define IRQ_SDMMC_DETECT 78 #define IRQ_SDIO_DETECT 79 +#define IRQ_ARM_PMU 86 + //hhb@rock-chips.com this spi is used for fiq_debugger signal irq #define IRQ_UART_SIGNAL 127 #if CONFIG_RK_DEBUG_UART >= 0 && CONFIG_RK_DEBUG_UART < 3 From 323e1a575efcc223329695767c30fa2a25c677d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Tue, 17 Jul 2012 14:30:05 +0800 Subject: [PATCH 025/261] pl330: fix support RK2928/RK31 --- arch/arm/common/pl330.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/common/pl330.c b/arch/arm/common/pl330.c index ecfc14c11215..7dc18b42d510 100644 --- a/arch/arm/common/pl330.c +++ b/arch/arm/common/pl330.c @@ -379,11 +379,11 @@ static inline u32 get_id(struct pl330_info *pi, u32 off) void __iomem *regs = pi->base; u32 id = 0; -#ifdef CONFIG_ARCH_RK30 +#ifdef CONFIG_PLAT_RK id |= ((readl(regs + off + 0x0) & 0xff) << 0); - id |= ((readl(regs + off + 0x4) & 0xff)<< 8); + id |= ((readl(regs + off + 0x4) & 0xff) << 8); id |= ((readl(regs + off + 0x8) & 0xff) << 16); - id |= ((readl(regs + off + 0xc) & 0xff)<< 24); + id |= ((readl(regs + off + 0xc) & 0xff) << 24); #else id |= (readb(regs + off + 0x0) << 0); id |= (readb(regs + off + 0x4) << 8); From 3145fc703ec00e77ae322233eaef8009f6269fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Tue, 17 Jul 2012 14:47:33 +0800 Subject: [PATCH 026/261] rk31: add initial support --- arch/arm/Kconfig | 13 +++++++ arch/arm/Makefile | 1 + arch/arm/mach-rk30/Kconfig | 12 ++++++ arch/arm/mach-rk30/Makefile | 3 ++ arch/arm/mach-rk30/devices.c | 6 ++- arch/arm/mach-rk30/include/mach/io.h | 27 +++++++++++++ arch/arm/mach-rk30/include/mach/irqs.h | 5 ++- arch/arm/mach-rk30/io.c | 2 + arch/arm/mach-rk30/pm.c | 4 ++ arch/arm/tools/mach-types | 1 + drivers/gpio/Makefile | 3 +- drivers/gpio/gpio-rk30.c | 52 +++++++++----------------- drivers/i2c/busses/i2c-rk30.h | 2 +- 13 files changed, 93 insertions(+), 38 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index fe16128b67b5..9b167ea55b5b 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -895,6 +895,19 @@ config ARCH_RK30 help Support for Rockchip's RK30xx SoCs. +config ARCH_RK31 + bool "Rockchip RK31xx" + select PLAT_RK + select CPU_V7 + select ARM_GIC + select RK_PL330_DMA + select HAVE_SMP + select MIGHT_HAVE_CACHE_L2X0 + select ARM_ERRATA_764369 + select ARM_ERRATA_754322 + help + Support for Rockchip's RK31xx SoCs. + config PLAT_SPEAR bool "ST SPEAr" select ARM_AMBA diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 43c17789695f..2e9474688af6 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -174,6 +174,7 @@ machine-$(CONFIG_ARCH_REALVIEW) := realview machine-$(CONFIG_ARCH_RK29) := rk29 machine-$(CONFIG_ARCH_RK2928) := rk2928 machine-$(CONFIG_ARCH_RK30) := rk30 +machine-$(CONFIG_ARCH_RK31) := rk30 machine-$(CONFIG_ARCH_RPC) := rpc machine-$(CONFIG_ARCH_S3C2410) := s3c2410 s3c2400 s3c2412 s3c2416 s3c2440 s3c2443 machine-$(CONFIG_ARCH_S3C24A0) := s3c24a0 diff --git a/arch/arm/mach-rk30/Kconfig b/arch/arm/mach-rk30/Kconfig index 99fd61624530..8570164a8175 100755 --- a/arch/arm/mach-rk30/Kconfig +++ b/arch/arm/mach-rk30/Kconfig @@ -24,3 +24,15 @@ config MACH_RK30_PHONE_A22 endchoice endif + +if ARCH_RK31 + +choice + prompt "RK31xx Board Type" + +config MACH_RK31_FPGA + bool "RK31 FPGA board" + +endchoice + +endif diff --git a/arch/arm/mach-rk30/Makefile b/arch/arm/mach-rk30/Makefile index 09578e7ed830..dd80c7fbb443 100755 --- a/arch/arm/mach-rk30/Makefile +++ b/arch/arm/mach-rk30/Makefile @@ -1,5 +1,7 @@ +ifneq ($(CONFIG_MACH_RK31_FPGA),y) obj-y += clock.o obj-y += clock_data.o +endif obj-y += common.o CFLAGS_common.o += -DTEXT_OFFSET=$(TEXT_OFFSET) obj-y += ddr.o @@ -27,3 +29,4 @@ obj-$(CONFIG_MACH_RK30_PHONE_LOQUAT) += board-rk30-phone-loquat.o board-rk30-pho obj-$(CONFIG_MACH_RK30_DS1001B) += board-rk30-ds1001b.o board-rk30-ds1001b-key.o board-rk30-ds1001b-rfkill.o obj-$(CONFIG_MACH_RK30_PHONE_A22) += board-rk30-phone-a22.o board-rk30-phone-a22-key.o +obj-$(CONFIG_MACH_RK31_FPGA) += board-rk31-fpga.o diff --git a/arch/arm/mach-rk30/devices.c b/arch/arm/mach-rk30/devices.c index 2a9838aa123b..6330b292ce1f 100755 --- a/arch/arm/mach-rk30/devices.c +++ b/arch/arm/mach-rk30/devices.c @@ -51,6 +51,7 @@ struct platform_device device_adc = { }; #endif +#ifdef CONFIG_ARCH_RK30 static struct resource rk30_tsadc_resource[] = { { .start = IRQ_TSADC, @@ -64,12 +65,13 @@ static struct resource rk30_tsadc_resource[] = { }, }; -struct platform_device device_tsadc = { +static struct platform_device device_tsadc = { .name = "rk30-tsadc", .id = -1, .num_resources = ARRAY_SIZE(rk30_tsadc_resource), .resource = rk30_tsadc_resource, }; +#endif static u64 dma_dmamask = DMA_BIT_MASK(32); @@ -1161,7 +1163,9 @@ static int __init rk30_init_devices(void) #ifdef CONFIG_ADC_RK30 platform_device_register(&device_adc); #endif +#ifdef CONFIG_ARCH_RK30 platform_device_register(&device_tsadc); +#endif rk30_init_sdmmc(); #if defined(CONFIG_FIQ_DEBUGGER) && defined(DEBUG_UART_PHYS) rk_serial_debug_init(DEBUG_UART_BASE, IRQ_DEBUG_UART, IRQ_UART_SIGNAL, -1); diff --git a/arch/arm/mach-rk30/include/mach/io.h b/arch/arm/mach-rk30/include/mach/io.h index 062123b5fcf4..e4a9c7210e21 100755 --- a/arch/arm/mach-rk30/include/mach/io.h +++ b/arch/arm/mach-rk30/include/mach/io.h @@ -26,7 +26,11 @@ #define RK30_IMEM_PHYS 0x10080000 #define RK30_IMEM_BASE IOMEM(0xFEF00000) #define RK30_IMEM_NONCACHED RK30_IO_TO_VIRT0(RK30_IMEM_PHYS) +#ifdef CONFIG_ARCH_RK31 +#define RK30_IMEM_SIZE SZ_16K +#else #define RK30_IMEM_SIZE SZ_64K +#endif #define RK30_GPU_PHYS 0x10090000 #define RK30_GPU_SIZE SZ_64K @@ -36,8 +40,10 @@ #define RK30_VCODEC_SIZE SZ_16K #define RK30_CIF0_PHYS 0x10108000 #define RK30_CIF0_SIZE SZ_8K +#ifdef CONFIG_ARCH_RK30 #define RK30_CIF1_PHYS 0x1010a000 #define RK30_CIF1_SIZE SZ_8K +#endif #define RK30_LCDC0_PHYS 0x1010c000 #define RK30_LCDC0_SIZE SZ_8K #define RK30_LCDC1_PHYS 0x1010e000 @@ -46,14 +52,18 @@ #define RK30_IPP_SIZE SZ_16K #define RK30_RGA_PHYS 0x10114000 #define RK30_RGA_SIZE SZ_8K +#ifdef CONFIG_ARCH_RK30 #define RK30_HDMI_PHYS 0x10116000 #define RK30_HDMI_SIZE SZ_8K #define RK30_I2S0_8CH_PHYS 0x10118000 #define RK30_I2S0_8CH_SIZE SZ_8K +#endif #define RK30_I2S1_2CH_PHYS 0x1011a000 #define RK30_I2S1_2CH_SIZE SZ_8K +#ifdef CONFIG_ARCH_RK30 #define RK30_I2S2_2CH_PHYS 0x1011c000 #define RK30_I2S2_2CH_SIZE SZ_8K +#endif #define RK30_SPDIF_PHYS 0x1011e000 #define RK30_SPDIF_SIZE SZ_8K @@ -133,9 +143,11 @@ #define RK30_GRF_PHYS 0x20008000 #define RK30_GRF_BASE RK30_IO_TO_VIRT1(RK30_GRF_PHYS) #define RK30_GRF_SIZE SZ_8K +#ifdef CONFIG_ARCH_RK30 #define RK30_GPIO6_PHYS 0x2000a000 #define RK30_GPIO6_BASE RK30_IO_TO_VIRT1(RK30_GPIO6_PHYS) #define RK30_GPIO6_SIZE SZ_8K +#endif #define RK30_TIMER2_PHYS 0x2000e000 #define RK30_TIMER2_BASE RK30_IO_TO_VIRT1(RK30_TIMER2_PHYS) @@ -159,7 +171,11 @@ #define RK30_PWM01_PHYS 0x20030000 #define RK30_PWM01_BASE RK30_IO_TO_VIRT1(RK30_PWM01_PHYS) #define RK30_PWM01_SIZE SZ_16K +#ifdef CONFIG_ARCH_RK31 +#define RK30_GPIO0_PHYS 0x2000a000 +#else #define RK30_GPIO0_PHYS 0x20034000 +#endif #define RK30_GPIO0_BASE RK30_IO_TO_VIRT1(RK30_GPIO0_PHYS) #define RK30_GPIO0_SIZE SZ_16K #define RK30_TIMER0_PHYS 0x20038000 @@ -189,8 +205,10 @@ #define RK30_I2C3_SIZE SZ_16K #define RK30_I2C4_PHYS 0x2005c000 #define RK30_I2C4_SIZE SZ_16K +#ifdef CONFIG_ARCH_RK30 #define RK30_TSADC_PHYS 0x20060000 #define RK30_TSADC_SIZE SZ_16K +#endif #define RK30_UART2_PHYS 0x20064000 #define RK30_UART2_BASE RK30_IO_TO_VIRT1(RK30_UART2_PHYS) #define RK30_UART2_SIZE SZ_16K @@ -210,9 +228,18 @@ #define RK30_GPIO3_PHYS 0x20080000 #define RK30_GPIO3_BASE RK30_IO_TO_VIRT1(RK30_GPIO3_PHYS) #define RK30_GPIO3_SIZE SZ_16K +#ifdef CONFIG_ARCH_RK30 #define RK30_GPIO4_PHYS 0x20084000 #define RK30_GPIO4_BASE RK30_IO_TO_VIRT1(RK30_GPIO4_PHYS) #define RK30_GPIO4_SIZE SZ_16K +#endif + +#ifdef CONFIG_ARCH_RK31 +#define RK31_GPS_PHYS 0x10230000 +#define RK31_GPS_SIZE SZ_64K +#define RK31_HSIC_PHYS 0x10240000 +#define RK31_HSIC_SIZE SZ_256K +#endif #if CONFIG_RK_DEBUG_UART == 0 #define DEBUG_UART_PHYS RK30_UART0_PHYS diff --git a/arch/arm/mach-rk30/include/mach/irqs.h b/arch/arm/mach-rk30/include/mach/irqs.h index 636752bc1ed0..9dc6a6157094 100644 --- a/arch/arm/mach-rk30/include/mach/irqs.h +++ b/arch/arm/mach-rk30/include/mach/irqs.h @@ -12,6 +12,8 @@ #define IRQ_DMAC2_0 RK30XX_IRQ(2) #define IRQ_DMAC2_1 RK30XX_IRQ(3) #define IRQ_DDR_PCTL RK30XX_IRQ(4) +#define IRQ_HSIC 37 +#define IRQ_GPU 39 #define IRQ_GPU_GP RK30XX_IRQ(5) #define IRQ_GPU_MMU RK30XX_IRQ(6) #define IRQ_GPU_PP RK30XX_IRQ(7) @@ -25,7 +27,7 @@ #define IRQ_IPP RK30XX_IRQ(15) #define IRQ_USB_OTG RK30XX_IRQ(16) #define IRQ_USB_HOST RK30XX_IRQ(17) - +#define IRQ_GPS 50 #define IRQ_MAC RK30XX_IRQ(19) #define IRQ_I2S2_2CH RK30XX_IRQ(20) #define IRQ_TSADC RK30XX_IRQ(21) @@ -79,6 +81,7 @@ #define IRQ_PMU_STOP_EXIT_INT RK30XX_IRQ(69) #define IRQ_OBSERVER_MAINFAULT RK30XX_IRQ(70) #define IRQ_VPU_OBSRV_MAINFAULT RK30XX_IRQ(71) +#define IRQ_ARM_PMU 103 #define IRQ_PERI_OBSRV_MAINFAULT RK30XX_IRQ(72) #define IRQ_VIO1_OBSRV_MAINFAULT RK30XX_IRQ(73) #define IRQ_VIO0_OBSRV_MAINFAULT RK30XX_IRQ(74) diff --git a/arch/arm/mach-rk30/io.c b/arch/arm/mach-rk30/io.c index a548607c5a50..80b421e4c91b 100644 --- a/arch/arm/mach-rk30/io.c +++ b/arch/arm/mach-rk30/io.c @@ -46,8 +46,10 @@ static struct map_desc rk30_io_desc[] __initdata = { RK30_DEVICE(GPIO1), RK30_DEVICE(GPIO2), RK30_DEVICE(GPIO3), +#ifdef CONFIG_ARCH_RK30 RK30_DEVICE(GPIO4), RK30_DEVICE(GPIO6), +#endif RK30_DEVICE(TIMER0), RK30_DEVICE(TIMER1), RK30_DEVICE(TIMER2), diff --git a/arch/arm/mach-rk30/pm.c b/arch/arm/mach-rk30/pm.c index 1b4bf52d3d12..ac99222b9a39 100644 --- a/arch/arm/mach-rk30/pm.c +++ b/arch/arm/mach-rk30/pm.c @@ -190,10 +190,12 @@ static noinline void rk30_pm_dump_irq(void) printk("wakeup gpio2: %08x\n", readl_relaxed(RK30_GPIO2_BASE + GPIO_INT_STATUS)); if (irq_gpio & 8) printk("wakeup gpio3: %08x\n", readl_relaxed(RK30_GPIO3_BASE + GPIO_INT_STATUS)); +#ifdef CONFIG_ARCH_RK30 if (irq_gpio & 0x10) printk("wakeup gpio4: %08x\n", readl_relaxed(RK30_GPIO4_BASE + GPIO_INT_STATUS)); if (irq_gpio & 0x40) printk("wakeup gpio6: %08x\n", readl_relaxed(RK30_GPIO6_BASE + GPIO_INT_STATUS)); +#endif } #define DUMP_GPIO_INTEN(ID) \ @@ -212,8 +214,10 @@ static noinline void rk30_pm_dump_inten(void) DUMP_GPIO_INTEN(1); DUMP_GPIO_INTEN(2); DUMP_GPIO_INTEN(3); +#ifdef CONFIG_ARCH_RK30 DUMP_GPIO_INTEN(4); DUMP_GPIO_INTEN(6); +#endif } static void pm_pll_wait_lock(int pll_idx) diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types index 5bb762af6c1d..04d13dd8b8bc 100644 --- a/arch/arm/tools/mach-types +++ b/arch/arm/tools/mach-types @@ -572,6 +572,7 @@ ventana MACH_VENTANA VENTANA 2927 rk29 MACH_RK29 RK29 2929 rk2928 ARCH_RK2928 RK2928 2928 rk30 ARCH_RK30 RK30 3066 +rk31 ARCH_RK31 RK31 3066 #ec4350sdb MACH_EC4350SDB EC4350SDB 2929 mimas MACH_MIMAS MIMAS 2930 titan MACH_TITAN TITAN 2931 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 51743a21ba9b..46508ae87340 100755 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -46,8 +46,9 @@ obj-$(CONFIG_MACH_U300) += gpio-u300.o obj-$(CONFIG_PLAT_NOMADIK) += gpio-nomadik.o obj-$(CONFIG_GPIO_RDC321X) += rdc321x-gpio.o obj-$(CONFIG_ARCH_RK29) += gpio-rk29.o -obj-$(CONFIG_ARCH_RK30) += gpio-rk30.o obj-$(CONFIG_ARCH_RK2928) += gpio-rk30.o +obj-$(CONFIG_ARCH_RK30) += gpio-rk30.o +obj-$(CONFIG_ARCH_RK31) += gpio-rk30.o obj-$(CONFIG_GPIO_JANZ_TTL) += janz-ttl.o obj-$(CONFIG_GPIO_SX150X) += sx150x.o obj-$(CONFIG_GPIO_VX855) += vx855_gpio.o diff --git a/drivers/gpio/gpio-rk30.c b/drivers/gpio/gpio-rk30.c index 54b64f968dca..520d5a74d8e3 100755 --- a/drivers/gpio/gpio-rk30.c +++ b/drivers/gpio/gpio-rk30.c @@ -34,9 +34,23 @@ #ifdef CONFIG_ARCH_RK30 #define MAX_PIN RK30_PIN6_PB7 -#endif -#ifdef CONFIG_ARCH_RK2928 +#elif defined(CONFIG_ARCH_RK31) +#define MAX_PIN RK30_PIN3_PD7 +#elif defined(CONFIG_ARCH_RK2928) #define MAX_PIN RK2928_PIN3_PD7 +#define RK30_GPIO0_PHYS RK2928_GPIO0_PHYS +#define RK30_GPIO0_BASE RK2928_GPIO0_BASE +#define RK30_GPIO0_SIZE RK2928_GPIO0_SIZE +#define RK30_GPIO1_PHYS RK2928_GPIO1_PHYS +#define RK30_GPIO1_BASE RK2928_GPIO1_BASE +#define RK30_GPIO1_SIZE RK2928_GPIO1_SIZE +#define RK30_GPIO2_PHYS RK2928_GPIO2_PHYS +#define RK30_GPIO2_BASE RK2928_GPIO2_BASE +#define RK30_GPIO2_SIZE RK2928_GPIO2_SIZE +#define RK30_GPIO3_PHYS RK2928_GPIO3_PHYS +#define RK30_GPIO3_BASE RK2928_GPIO3_BASE +#define RK30_GPIO3_SIZE RK2928_GPIO3_SIZE +#define RK30_GRF_BASE RK2928_GRF_BASE #endif #define to_rk30_gpio_bank(c) container_of(c, struct rk30_gpio_bank, chip) @@ -62,7 +76,6 @@ static int rk30_gpiolib_direction_input(struct gpio_chip *chip,unsigned offset); static int rk30_gpiolib_pull_updown(struct gpio_chip *chip, unsigned offset, unsigned enable); static int rk30_gpiolib_to_irq(struct gpio_chip *chip,unsigned offset); -#ifdef CONFIG_ARCH_RK30 #define RK30_GPIO_BANK(ID) \ { \ .chip = { \ @@ -81,27 +94,6 @@ static int rk30_gpiolib_to_irq(struct gpio_chip *chip,unsigned offset); .irq = IRQ_GPIO##ID, \ .regbase = (unsigned char __iomem *) RK30_GPIO##ID##_BASE, \ } -#endif -#ifdef CONFIG_ARCH_RK2928 -#define RK30_GPIO_BANK(ID) \ - { \ - .chip = { \ - .label = "gpio" #ID, \ - .direction_input = rk30_gpiolib_direction_input, \ - .direction_output = rk30_gpiolib_direction_output, \ - .get = rk30_gpiolib_get, \ - .set = rk30_gpiolib_set, \ - .pull_updown = rk30_gpiolib_pull_updown, \ - .dbg_show = rk30_gpiolib_dbg_show, \ - .to_irq = rk30_gpiolib_to_irq, \ - .base = ID < 6 ? PIN_BASE + ID*NUM_GROUP : PIN_BASE + 5*NUM_GROUP, \ - .ngpio = ID < 6 ? NUM_GROUP : 16, \ - }, \ - .id = ID, \ - .irq = IRQ_GPIO##ID, \ - .regbase = (unsigned char __iomem *) RK2928_GPIO##ID##_BASE, \ - } -#endif static struct rk30_gpio_bank rk30_gpio_banks[] = { RK30_GPIO_BANK(0), @@ -332,18 +324,10 @@ static int rk30_gpiolib_pull_updown(struct gpio_chip *chip, unsigned offset, uns unsigned long flags; spin_lock_irqsave(&bank->lock, flags); -#ifdef CONFIG_ARCH_RK30 if(offset>=16) - rk30_gpio_bit_op((void *__iomem) RK30_GRF_BASE, GRF_GPIO0H_PULL + bank->id * 8, (1<id * 8, (1<id * 8, (1<<(offset+16)) | offset_to_bit(offset), !enable); -#endif -#ifdef CONFIG_ARCH_RK2928 - if(offset>=16) - rk30_gpio_bit_op((void *__iomem) RK2928_GRF_BASE, GRF_GPIO0H_PULL + bank->id * 8, (1<id * 8, (1<<(offset+16)) | offset_to_bit(offset), !enable); -#endif + rk30_gpio_bit_op((void *__iomem) RK30_GRF_BASE, GRF_GPIO0L_PULL + bank->id * 8, (1<<(offset+16)) | offset_to_bit(offset), !enable); spin_unlock_irqrestore(&bank->lock, flags); return 0; diff --git a/drivers/i2c/busses/i2c-rk30.h b/drivers/i2c/busses/i2c-rk30.h index 2fe9a206a006..3e6ea7adfd13 100755 --- a/drivers/i2c/busses/i2c-rk30.h +++ b/drivers/i2c/busses/i2c-rk30.h @@ -44,7 +44,7 @@ #define rk30_ceil(x, y) \ ({ unsigned long __x = (x), __y = (y); (__x + __y - 1) / __y; }) -#ifdef CONFIG_ARCH_RK30 +#if defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) #define GRF_I2C_CON_BASE (RK30_GRF_BASE + GRF_SOC_CON1) #endif #ifdef CONFIG_ARCH_RK2928 From e6a9f68960a1e30eceb5117cfe7ee0b22246fbc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Tue, 17 Jul 2012 14:48:20 +0800 Subject: [PATCH 027/261] rk31: add fpga board support --- arch/arm/configs/rk31_fpga_defconfig | 96 +++++++++ arch/arm/mach-rk30/board-rk31-fpga.c | 288 +++++++++++++++++++++++++++ 2 files changed, 384 insertions(+) create mode 100644 arch/arm/configs/rk31_fpga_defconfig create mode 100644 arch/arm/mach-rk30/board-rk31-fpga.c diff --git a/arch/arm/configs/rk31_fpga_defconfig b/arch/arm/configs/rk31_fpga_defconfig new file mode 100644 index 000000000000..c58c4ba18355 --- /dev/null +++ b/arch/arm/configs/rk31_fpga_defconfig @@ -0,0 +1,96 @@ +CONFIG_EXPERIMENTAL=y +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_KERNEL_LZO=y +CONFIG_LOG_BUF_SHIFT=19 +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_CGROUP_SCHED=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="root" +CONFIG_INITRAMFS_COMPRESSION_GZIP=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_PANIC_TIMEOUT=1 +# CONFIG_SYSCTL_SYSCALL is not set +# CONFIG_ELF_CORE is not set +CONFIG_ASHMEM=y +# CONFIG_AIO is not set +CONFIG_EMBEDDED=y +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_ARCH_RK31=y +# CONFIG_DDR_TEST is not set +# CONFIG_RK29_LAST_LOG is not set +CONFIG_RK_DEBUG_UART=1 +# CONFIG_CACHE_L2X0 is not set +CONFIG_FIQ_DEBUGGER=y +CONFIG_FIQ_DEBUGGER_NO_SLEEP=y +CONFIG_FIQ_DEBUGGER_CONSOLE=y +CONFIG_FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +CONFIG_HIGHMEM=y +CONFIG_COMPACTION=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=32768 +CONFIG_CMDLINE="console=ttyFIQ0 androidboot.console=ttyFIQ0 init=/init debug" +CONFIG_VFP=y +CONFIG_WAKELOCK=y +CONFIG_PM_RUNTIME=y +CONFIG_SUSPEND_TIME=y +CONFIG_NET=y +CONFIG_UNIX=y +# CONFIG_NET_ACTIVITY_STATS is not set +# CONFIG_WIRELESS is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_FIRMWARE_IN_KERNEL is not set +CONFIG_MTD=y +CONFIG_MISC_DEVICES=y +# CONFIG_ANDROID_PMEM is not set +CONFIG_INPUT_POLLDEV=y +# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_SERIO is not set +# CONFIG_CONSOLE_TRANSLATIONS is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_HW_RANDOM is not set +CONFIG_I2C=y +CONFIG_I2C0_CONTROLLER_RK30=y +CONFIG_I2C2_CONTROLLER_RK30=y +# CONFIG_I2C3_RK30 is not set +# CONFIG_ADC is not set +CONFIG_EXPANDED_GPIO_NUM=0 +CONFIG_EXPANDED_GPIO_IRQ_NUM=0 +CONFIG_SPI_FPGA_GPIO_NUM=0 +CONFIG_SPI_FPGA_GPIO_IRQ_NUM=0 +# CONFIG_HWMON is not set +# CONFIG_MFD_SUPPORT is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +CONFIG_RTC_CLASS=y +# CONFIG_CMMB is not set +# CONFIG_DNOTIFY is not set +CONFIG_TMPFS=y +# CONFIG_MISC_FILESYSTEMS is not set +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_PRINTK_TIME=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DETECT_HUNG_TASK=y +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +CONFIG_SLUB_DEBUG_ON=y +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_FTRACE is not set diff --git a/arch/arm/mach-rk30/board-rk31-fpga.c b/arch/arm/mach-rk30/board-rk31-fpga.c new file mode 100644 index 000000000000..4495e7ca3cd9 --- /dev/null +++ b/arch/arm/mach-rk30/board-rk31-fpga.c @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2012 ROCKCHIP, Inc. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//i2c +#ifdef CONFIG_I2C0_RK30 +static struct i2c_board_info __initdata i2c0_info[] = { +}; +#endif +#ifdef CONFIG_I2C1_RK30 +static struct i2c_board_info __initdata i2c1_info[] = { +}; +#endif +#ifdef CONFIG_I2C2_RK30 +static struct i2c_board_info __initdata i2c2_info[] = { +}; +#endif +#ifdef CONFIG_I2C3_RK30 +static struct i2c_board_info __initdata i2c3_info[] = { +}; +#endif + +#ifdef CONFIG_I2C_GPIO_RK30 +static struct i2c_board_info __initdata i2c_gpio_info[] = { +}; +#endif + +static void __init rk30_i2c_register_board_info(void) +{ +#ifdef CONFIG_I2C0_RK30 + i2c_register_board_info(0, i2c0_info, ARRAY_SIZE(i2c0_info)); +#endif +#ifdef CONFIG_I2C1_RK30 + i2c_register_board_info(1, i2c1_info, ARRAY_SIZE(i2c1_info)); +#endif +#ifdef CONFIG_I2C2_RK30 + i2c_register_board_info(2, i2c2_info, ARRAY_SIZE(i2c2_info)); +#endif +#ifdef CONFIG_I2C3_RK30 + i2c_register_board_info(3, i2c3_info, ARRAY_SIZE(i2c3_info)); +#endif +#ifdef CONFIG_I2C_GPIO_RK30 + i2c_register_board_info(4, i2c_gpio_info, ARRAY_SIZE(i2c_gpio_info)); +#endif +} +//end of i2c + +static struct spi_board_info board_spi_devices[] = { +}; + +static struct platform_device *devices[] __initdata = { +}; + +static void __init rk31_board_init(void) +{ + rk30_i2c_register_board_info(); + spi_register_board_info(board_spi_devices, ARRAY_SIZE(board_spi_devices)); + platform_add_devices(devices, ARRAY_SIZE(devices)); +} + +static void __init rk31_reserve(void) +{ + board_mem_reserved(); +} + +#include + +struct clk { + const char *name; + unsigned long rate; +}; + +static struct clk xin24m = { + .name = "xin24m", + .rate = 24000000, +}; + +#define CLK(dev, con, ck) \ + { \ + .dev_id = dev, \ + .con_id = con, \ + .clk = ck, \ + } + +static struct clk_lookup clks[] = { + CLK("rk30_i2c.0", "i2c", &xin24m), + CLK("rk30_i2c.1", "i2c", &xin24m), + CLK("rk30_i2c.2", "i2c", &xin24m), + CLK("rk30_i2c.3", "i2c", &xin24m), + CLK("rk30_i2c.4", "i2c", &xin24m), + CLK("rk29xx_spim.0", "spi", &xin24m), + CLK("rk29xx_spim.1", "spi", &xin24m), + + CLK("rk_serial.0", "uart_div", &xin24m), + CLK("rk_serial.0", "uart_frac_div", &xin24m), + CLK("rk_serial.0", "uart", &xin24m), + CLK("rk_serial.0", "pclk_uart", &xin24m), + CLK("rk_serial.1", "uart_div", &xin24m), + CLK("rk_serial.1", "uart_frac_div", &xin24m), + CLK("rk_serial.1", "uart", &xin24m), + CLK("rk_serial.1", "pclk_uart", &xin24m), + CLK("rk_serial.2", "uart_div", &xin24m), + CLK("rk_serial.2", "uart_frac_div", &xin24m), + CLK("rk_serial.2", "uart", &xin24m), + CLK("rk_serial.2", "pclk_uart", &xin24m), + + CLK("rk29_i2s.0", "i2s_div", &xin24m), + CLK("rk29_i2s.0", "i2s_frac_div", &xin24m), + CLK("rk29_i2s.0", "i2s", &xin24m), + CLK("rk29_i2s.0", "hclk_i2s", &xin24m), +}; + +static void __init rk30_clock_init(void) +{ + struct clk_lookup *lk; + + for (lk = clks; lk < clks + ARRAY_SIZE(clks); lk++) { + clkdev_add(lk); + } +} + +void __init board_clock_init(void) +{ + rk30_clock_init(); +} + +int __init clk_disable_unused(void) +{ + return 0; +} + +int clk_enable(struct clk *clk) +{ + return 0; +} +EXPORT_SYMBOL(clk_enable); + +void clk_disable(struct clk *clk) +{ +} +EXPORT_SYMBOL(clk_disable); + +unsigned long clk_get_rate(struct clk *clk) +{ + return 24000000; +} +EXPORT_SYMBOL(clk_get_rate); + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + return 0; +} +EXPORT_SYMBOL(clk_set_rate); + +int clk_set_parent(struct clk *clk, struct clk *parent) +{ + return 0; +} +EXPORT_SYMBOL(clk_set_parent); + +#include +#include + +#define EV_ENCALL KEY_F4 +#define EV_MENU KEY_F1 + +#define PRESS_LEV_LOW 1 +#define PRESS_LEV_HIGH 0 + +static struct rk29_keys_button key_button[] = { + { + .desc = "menu", + .code = EV_MENU, + .gpio = RK30_PIN3_PB2, + .active_low = PRESS_LEV_LOW, + }, + { + .desc = "vol+", + .code = KEY_VOLUMEUP, + .gpio = RK30_PIN3_PB1, + .active_low = PRESS_LEV_LOW, + }, + { + .desc = "vol-", + .code = KEY_VOLUMEDOWN, + .gpio = RK30_PIN3_PB0, + .active_low = PRESS_LEV_LOW, + }, + { + .desc = "home", + .code = KEY_HOME, + .gpio = RK30_PIN3_PB3, + .active_low = PRESS_LEV_LOW, + }, + { + .desc = "esc", + .code = KEY_BACK, + .gpio = RK30_PIN3_PB4, + .active_low = PRESS_LEV_LOW, + }, + { + .desc = "key6", + .code = KEY_CAMERA, + .gpio = RK30_PIN3_PB5, + .active_low = PRESS_LEV_LOW, + }, +}; + +struct rk29_keys_platform_data rk29_keys_pdata = { + .buttons = key_button, + .nbuttons = ARRAY_SIZE(key_button), + .chn = -1, //chn: 0-7, if do not use ADC,set 'chn' -1 +}; + +static void __init fpga_fixup(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ + mi->nr_banks = 1; + mi->bank[0].start = PLAT_PHYS_OFFSET; + mi->bank[0].size = SZ_128M; +} + +#include +static void fpga_reset(char mode, const char *cmd) +{ + while (1); +} + +static void __init fpga_map_io(void) +{ + arch_reset = fpga_reset; + rk30_map_common_io(); + rk29_setup_early_printk(); + rk29_sram_init(); + board_clock_init(); + rk30_iomux_init(); +} + +MACHINE_START(RK31, "RK31board") + .boot_params = PLAT_PHYS_OFFSET + 0x800, + .fixup = fpga_fixup, + .reserve = &rk31_reserve, + .map_io = fpga_map_io, + .init_irq = rk30_init_irq, + .timer = &rk30_timer, + .init_machine = rk31_board_init, +MACHINE_END From 4b68042201e3007c9e81862be21a8f7fd01567b5 Mon Sep 17 00:00:00 2001 From: kfx Date: Tue, 17 Jul 2012 21:02:16 +0800 Subject: [PATCH 028/261] rk2928: add lcdc support and add rga config --- arch/arm/configs/rk2928_fpga_defconfig | 15 + arch/arm/mach-rk2928/board-rk2928-fpga.c | 62 ++ arch/arm/mach-rk2928/devices.c | 35 + drivers/video/rockchip/Kconfig | 6 +- drivers/video/rockchip/Makefile | 3 +- drivers/video/rockchip/chips/rk2928_lcdc.c | 952 +++++++++++++++++++++ drivers/video/rockchip/chips/rk2928_lcdc.h | 452 ++++++++++ 7 files changed, 1523 insertions(+), 2 deletions(-) mode change 100644 => 100755 arch/arm/mach-rk2928/board-rk2928-fpga.c mode change 100644 => 100755 drivers/video/rockchip/Kconfig mode change 100644 => 100755 drivers/video/rockchip/Makefile create mode 100755 drivers/video/rockchip/chips/rk2928_lcdc.c create mode 100755 drivers/video/rockchip/chips/rk2928_lcdc.h diff --git a/arch/arm/configs/rk2928_fpga_defconfig b/arch/arm/configs/rk2928_fpga_defconfig index 66550f0c503c..f0c6d3624979 100644 --- a/arch/arm/configs/rk2928_fpga_defconfig +++ b/arch/arm/configs/rk2928_fpga_defconfig @@ -76,6 +76,21 @@ CONFIG_SPI_FPGA_GPIO_NUM=0 CONFIG_SPI_FPGA_GPIO_IRQ_NUM=0 # CONFIG_HWMON is not set # CONFIG_MFD_SUPPORT is not set +CONFIG_ION=y +CONFIG_ION_ROCKCHIP=y +CONFIG_FB=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +# CONFIG_BACKLIGHT_CLASS_DEVICE is not set +CONFIG_DISPLAY_SUPPORT=y +CONFIG_LCD_TD043MGEA1=y +CONFIG_FB_ROCKCHIP=y +CONFIG_LCDC_RK2928=y +# CONFIG_THREE_FB_BUFFER is not set +CONFIG_RGA_RK30=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set # CONFIG_HID_SUPPORT is not set # CONFIG_USB_SUPPORT is not set CONFIG_RTC_CLASS=y diff --git a/arch/arm/mach-rk2928/board-rk2928-fpga.c b/arch/arm/mach-rk2928/board-rk2928-fpga.c old mode 100644 new mode 100755 index c04f2b352926..8a38cd02a5ef --- a/arch/arm/mach-rk2928/board-rk2928-fpga.c +++ b/arch/arm/mach-rk2928/board-rk2928-fpga.c @@ -43,6 +43,57 @@ #include #include + +#define RK2928_FB_MEM_SIZE 3*SZ_1M + +#ifdef CONFIG_FB_ROCKCHIP + +static int rk_fb_io_init(struct rk29_fb_setting_info *fb_setting) +{ + return 0; +} +static int rk_fb_io_disable(void) +{ + return 0; +} +static int rk_fb_io_enable(void) +{ + return 0; +} + +#if defined(CONFIG_LCDC_RK2928) +struct rk29fb_info lcdc_screen_info = { + .prop = PRMRY, //primary display device + .io_init = rk_fb_io_init, + .io_disable = rk_fb_io_disable, + .io_enable = rk_fb_io_enable, + .set_screen_info = set_lcd_info, +}; +#endif + +static struct resource resource_fb[] = { + [0] = { + .name = "fb0 buf", + .start = 0, + .end = 0,//RK30_FB0_MEM_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "ipp buf", //for rotate + .start = 0, + .end = 0,//RK30_FB0_MEM_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device device_fb = { + .name = "rk-fb", + .id = -1, + .num_resources = ARRAY_SIZE(resource_fb), + .resource = resource_fb, +}; +#endif + //i2c #ifdef CONFIG_I2C0_RK30 static struct i2c_board_info __initdata i2c0_info[] = { @@ -87,6 +138,9 @@ static struct spi_board_info board_spi_devices[] = { }; static struct platform_device *devices[] __initdata = { +#ifdef CONFIG_FB_ROCKCHIP + &device_fb, +#endif }; static void __init rk2928_board_init(void) @@ -98,6 +152,10 @@ static void __init rk2928_board_init(void) static void __init rk2928_reserve(void) { +#ifdef CONFIG_FB_ROCKCHIP + resource_fb[0].start = board_mem_reserve_add("fb0", RK2928_FB_MEM_SIZE); + resource_fb[0].end = resource_fb[0].start + RK2928_FB_MEM_SIZE - 1; +#endif board_mem_reserved(); } @@ -145,6 +203,10 @@ static struct clk_lookup clks[] = { CLK("rk29_i2s.0", "i2s_frac_div", &xin24m), CLK("rk29_i2s.0", "i2s", &xin24m), CLK("rk29_i2s.0", "hclk_i2s", &xin24m), + CLK(NULL, "pd_lcdc0", &xin24m), + CLK(NULL, "hclk_lcdc0", &xin24m), + CLK(NULL, "aclk_lcdc0", &xin24m), + CLK(NULL, "dclk_lcdc0", &xin24m), }; void __init rk30_clock_init(void) diff --git a/arch/arm/mach-rk2928/devices.c b/arch/arm/mach-rk2928/devices.c index 51b3d6b42f03..d90a8055eec8 100755 --- a/arch/arm/mach-rk2928/devices.c +++ b/arch/arm/mach-rk2928/devices.c @@ -181,6 +181,38 @@ static void __init rk2928_init_uart(void) platform_device_register(&device_uart2); #endif } + + +//LCDC +#ifdef CONFIG_LCDC_RK2928 +extern struct rk29fb_info lcdc_screen_info; +static struct resource resource_lcdc[] = { + [0] = { + .name = "lcdc reg", + .start = RK2928_LCDC_PHYS, + .end = RK2928_LCDC_PHYS + RK2928_LCDC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + + [1] = { + .name = "lcdc irq", + .start = IRQ_LCDC, + .end = IRQ_LCDC, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device device_lcdc = { + .name = "rk2928-lcdc", + .id = 0, + .num_resources = ARRAY_SIZE(resource_lcdc), + .resource = resource_lcdc, + .dev = { + .platform_data = &lcdc_screen_info, + }, +}; +#endif + // i2c #ifdef CONFIG_I2C0_CONTROLLER_RK29 #define I2C0_ADAP_TYPE I2C_RK29_ADAP @@ -578,6 +610,9 @@ static int __init rk2928_init_devices(void) #ifdef CONFIG_RGA_RK30 platform_device_register(&device_rga); #endif +#ifdef CONFIG_LCDC_RK2928 + platform_device_register(&device_lcdc); +#endif #if defined(CONFIG_FIQ_DEBUGGER) && defined(DEBUG_UART_PHYS) rk_serial_debug_init(DEBUG_UART_BASE, IRQ_DEBUG_UART, IRQ_UART_SIGNAL, -1); #endif diff --git a/drivers/video/rockchip/Kconfig b/drivers/video/rockchip/Kconfig old mode 100644 new mode 100755 index 06cd988688dc..c6b81ec773f4 --- a/drivers/video/rockchip/Kconfig +++ b/drivers/video/rockchip/Kconfig @@ -33,7 +33,11 @@ config LCDC1_RK30 default y if HDMI_RK30 help Support rk30 lcdc1 if you say y here - +config LCDC_RK2928 + tristate "rk2928 lcdc support " + depends on FB_ROCKCHIP + help + Driver for rk2928 lcdc . config DUAL_DISP_IN_KERNEL bool "implement dual display in kernel" depends on FB_ROCKCHIP diff --git a/drivers/video/rockchip/Makefile b/drivers/video/rockchip/Makefile old mode 100644 new mode 100755 index 169786122ed1..d5a4aed8c623 --- a/drivers/video/rockchip/Makefile +++ b/drivers/video/rockchip/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_FB_ROCKCHIP) += rk_fb.o rkfb_sysfs.o obj-$(CONFIG_FB_WIMO) +=wimo.o -obj-$(CONFIG_LCDC_RK30) += chips/rk30_lcdc.o +obj-$(CONFIG_LCDC_RK30) += chips/rk30_lcdc.o +obj-$(CONFIG_LCDC_RK2928) += chips/rk2928_lcdc.o obj-$(CONFIG_RGA_RK30) += rga/ obj-$(CONFIG_HDMI_RK30) += hdmi/ diff --git a/drivers/video/rockchip/chips/rk2928_lcdc.c b/drivers/video/rockchip/chips/rk2928_lcdc.c new file mode 100755 index 000000000000..5298a8e98291 --- /dev/null +++ b/drivers/video/rockchip/chips/rk2928_lcdc.c @@ -0,0 +1,952 @@ +/* + * drivers/video/rockchip/chips/rk2928_lcdc.c + * + * Copyright (C) 2012 ROCKCHIP, Inc. + *Author:yzq + * yxj + *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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rk2928_lcdc.h" + + + + + + +static int dbg_thresd = 0; +module_param(dbg_thresd, int, S_IRUGO|S_IWUSR); +#define DBG(level,x...) do { if(unlikely(dbg_thresd > level)) printk(KERN_INFO x); } while (0) + + +static int init_rk2928_lcdc(struct rk_lcdc_device_driver *dev_drv) +{ + struct rk2928_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk2928_lcdc_device,driver); + if(lcdc_dev->id == 0) //lcdc0 + { + lcdc_dev->pd = clk_get(NULL,"pd_lcdc0"); + lcdc_dev->hclk = clk_get(NULL,"hclk_lcdc0"); + lcdc_dev->aclk = clk_get(NULL,"aclk_lcdc0"); + lcdc_dev->dclk = clk_get(NULL,"dclk_lcdc0"); + } + else if(lcdc_dev->id == 1) + { + lcdc_dev->pd = clk_get(NULL,"pd_lcdc1"); + lcdc_dev->hclk = clk_get(NULL,"hclk_lcdc1"); + lcdc_dev->aclk = clk_get(NULL,"aclk_lcdc1"); + lcdc_dev->dclk = clk_get(NULL,"dclk_lcdc1"); + } + else + { + printk(KERN_ERR "invalid lcdc device!\n"); + return -EINVAL; + } + if (IS_ERR(lcdc_dev->pd) || (IS_ERR(lcdc_dev->aclk)) ||(IS_ERR(lcdc_dev->dclk)) || (IS_ERR(lcdc_dev->hclk))) + { + printk(KERN_ERR "failed to get lcdc%d clk source\n",lcdc_dev->id); + } + clk_enable(lcdc_dev->pd); + clk_enable(lcdc_dev->hclk); //enable aclk and hclk for register config + clk_enable(lcdc_dev->aclk); + lcdc_dev->clk_on = 1; + LcdSetBit(lcdc_dev,SYS_CFG, m_LCDC_AXICLK_AUTO_ENABLE);//eanble axi-clk auto gating for low power + LcdMskReg(lcdc_dev,INT_STATUS,m_FRM_START_INT_CLEAR | m_BUS_ERR_INT_CLEAR | m_LINE_FLAG_INT_EN | + m_FRM_START_INT_EN | m_HOR_START_INT_EN,v_FRM_START_INT_CLEAR(1) | v_BUS_ERR_INT_CLEAR(0) | + v_LINE_FLAG_INT_EN(0) | v_FRM_START_INT_EN(0) | v_HOR_START_INT_EN(0)); //enable frame start interrupt for sync + LCDC_REG_CFG_DONE(); // write any value to REG_CFG_DONE let config become effective + return 0; +} + +static int rk2928_lcdc_deinit(struct rk2928_lcdc_device *lcdc_dev) +{ + spin_lock(&lcdc_dev->reg_lock); + if(likely(lcdc_dev->clk_on)) + { + lcdc_dev->clk_on = 0; + LcdMskReg(lcdc_dev, INT_STATUS, m_FRM_START_INT_CLEAR, v_FRM_START_INT_CLEAR(1)); + LcdMskReg(lcdc_dev, INT_STATUS, m_HOR_START_INT_EN | m_FRM_START_INT_EN | + m_LINE_FLAG_INT_EN | m_BUS_ERR_INT_EN,v_HOR_START_INT_EN(0) | v_FRM_START_INT_EN(0) | + v_LINE_FLAG_INT_EN(0) | v_BUS_ERR_INT_EN(0)); //disable all lcdc interrupt + LcdSetBit(lcdc_dev,SYS_CFG,m_LCDC_STANDBY); + LCDC_REG_CFG_DONE(); + spin_unlock(&lcdc_dev->reg_lock); + } + else //clk already disabled + { + spin_unlock(&lcdc_dev->reg_lock); + return 0; + } + mdelay(1); + + return 0; +} + +static int rk2928_load_screen(struct rk_lcdc_device_driver *dev_drv, bool initscreen) +{ + int ret = -EINVAL; + struct rk2928_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk2928_lcdc_device,driver); + rk_screen *screen = lcdc_dev->screen; + u64 ft; + int fps; + u16 face; + u16 right_margin = screen->right_margin; + u16 lower_margin = screen->lower_margin; + u16 x_res = screen->x_res, y_res = screen->y_res; + + // set the rgb or mcu + spin_lock(&lcdc_dev->reg_lock); + if(likely(lcdc_dev->clk_on)) + { + if(screen->type==SCREEN_MCU) + { + printk(KERN_ERR "MCU Screen is not supported by RK2928\n"); + + } + + switch (screen->face) + { + case OUT_P565: + face = OUT_P565; + LcdMskReg(lcdc_dev, DSP_CTRL, m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE, v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(0)); + break; + case OUT_P666: + face = OUT_P666; + LcdMskReg(lcdc_dev, DSP_CTRL, m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE, v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(1)); + break; + case OUT_D888_P565: + face = OUT_P888; + LcdMskReg(lcdc_dev, DSP_CTRL, m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE, v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(0)); + break; + case OUT_D888_P666: + face = OUT_P888; + LcdMskReg(lcdc_dev, DSP_CTRL, m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE, v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(1)); + break; + case OUT_P888: + face = OUT_P888; + LcdMskReg(lcdc_dev, DSP_CTRL, m_DITHER_UP_EN, v_DITHER_UP_EN(1)); + LcdMskReg(lcdc_dev, DSP_CTRL, m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE, v_DITHER_DOWN_EN(0) | v_DITHER_DOWN_MODE(0)); + break; + default: + LcdMskReg(lcdc_dev, DSP_CTRL, m_DITHER_UP_EN, v_DITHER_UP_EN(0)); + LcdMskReg(lcdc_dev, DSP_CTRL, m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE, v_DITHER_DOWN_EN(0) | v_DITHER_DOWN_MODE(0)); + face = screen->face; + break; + } + + //use default overlay,set vsyn hsync den dclk polarity + LcdMskReg(lcdc_dev, DSP_CTRL,m_DISPLAY_FORMAT | m_HSYNC_POLARITY | m_VSYNC_POLARITY | + m_DEN_POLARITY |m_DCLK_POLARITY | m_OUTPUT_RB_SWAP | m_OUTPUT_RG_SWAP | m_BLACK_MODE, + v_DISPLAY_FORMAT(face) | v_HSYNC_POLARITY(screen->pin_hsync) | + v_VSYNC_POLARITY(screen->pin_vsync) | v_DEN_POLARITY(screen->pin_den) | + v_DCLK_POLARITY(screen->pin_dclk) | v_OUTPUT_RB_SWAP(screen->swap_rb) | + v_OUTPUT_RG_SWAP(screen->swap_rg) |v_BLACK_MODE(0)); + + //set background color to black,set swap according to the screen panel,disable blank mode + LcdMskReg(lcdc_dev, BG_COLOR, m_BG_COLOR ,v_BG_COLOR(0x000000)); + + + LcdWrReg(lcdc_dev, DSP_HTOTAL_HS_END,v_HSYNC(screen->hsync_len) | + v_HORPRD(screen->hsync_len + screen->left_margin + x_res + right_margin)); + LcdWrReg(lcdc_dev, DSP_HACT_ST_END, v_HAEP(screen->hsync_len + screen->left_margin + x_res) | + v_HASP(screen->hsync_len + screen->left_margin)); + + LcdWrReg(lcdc_dev, DSP_VTOTAL_VS_END, v_VSYNC(screen->vsync_len) | + v_VERPRD(screen->vsync_len + screen->upper_margin + y_res + lower_margin)); + LcdWrReg(lcdc_dev, DSP_VACT_ST_END, v_VAEP(screen->vsync_len + screen->upper_margin+y_res)| + v_VASP(screen->vsync_len + screen->upper_margin)); + // let above to take effect + LCDC_REG_CFG_DONE(); + } + spin_unlock(&lcdc_dev->reg_lock); + + ret = clk_set_rate(lcdc_dev->dclk, screen->pixclock); + if(ret) + { + printk(KERN_ERR ">>>>>> set lcdc%d dclk failed\n",lcdc_dev->id); + } + lcdc_dev->driver.pixclock = lcdc_dev->pixclock = div_u64(1000000000000llu, clk_get_rate(lcdc_dev->dclk)); + clk_enable(lcdc_dev->dclk); + + ft = (u64)(screen->upper_margin + screen->lower_margin + screen->y_res +screen->vsync_len)* + (screen->left_margin + screen->right_margin + screen->x_res + screen->hsync_len)* + (dev_drv->pixclock); // one frame time ,(pico seconds) + fps = div64_u64(1000000000000llu,ft); + screen->ft = 1000/fps; + printk("%s: dclk:%lu>>fps:%d ",lcdc_dev->driver.name,clk_get_rate(lcdc_dev->dclk),fps); + + if(screen->init) + { + screen->init(); + } + + printk("%s for lcdc%d ok!\n",__func__,lcdc_dev->id); + return 0; +} + + +//enable layer,open:1,enable;0 disable +static int win0_open(struct rk2928_lcdc_device *lcdc_dev,bool open) +{ + + spin_lock(&lcdc_dev->reg_lock); + if(likely(lcdc_dev->clk_on)) + { + if(open) + { + if(!lcdc_dev->atv_layer_cnt) + { + LcdClrBit(lcdc_dev, SYS_CFG,m_LCDC_STANDBY); + } + lcdc_dev->atv_layer_cnt++; + } + else + { + lcdc_dev->atv_layer_cnt--; + } + lcdc_dev->driver.layer_par[0]->state = open; + + LcdMskReg(lcdc_dev, SYS_CFG, m_W0_EN, v_W0_EN(open)); + if(!lcdc_dev->atv_layer_cnt) //if no layer used,disable lcdc + { + LcdSetBit(lcdc_dev, SYS_CFG,m_LCDC_STANDBY); + } + LCDC_REG_CFG_DONE(); + } + spin_unlock(&lcdc_dev->reg_lock); + printk(KERN_INFO "lcdc%d win0 %s\n",lcdc_dev->id,open?"open":"closed"); + return 0; +} +static int win1_open(struct rk2928_lcdc_device *lcdc_dev,bool open) +{ + spin_lock(&lcdc_dev->reg_lock); + if(likely(lcdc_dev->clk_on)) + { + if(open) + { + if(!lcdc_dev->atv_layer_cnt) + { + printk("lcdc%d wakeup from stanby\n",lcdc_dev->id); + LcdClrBit(lcdc_dev, SYS_CFG,m_LCDC_STANDBY); + } + lcdc_dev->atv_layer_cnt++; + } + else + { + lcdc_dev->atv_layer_cnt--; + } + lcdc_dev->driver.layer_par[1]->state = open; + + LcdMskReg(lcdc_dev, SYS_CFG, m_W1_EN, v_W1_EN(open)); + if(!lcdc_dev->atv_layer_cnt) //if no layer used,disable lcdc + { + printk(KERN_INFO "no layer of lcdc%d is used,go to standby!",lcdc_dev->id); + LcdSetBit(lcdc_dev, SYS_CFG,m_LCDC_STANDBY); + } + LCDC_REG_CFG_DONE(); + } + spin_unlock(&lcdc_dev->reg_lock); + printk(KERN_INFO "lcdc%d win1 %s\n",lcdc_dev->id,open?"open":"closed"); + return 0; +} + + +static int rk2928_lcdc_blank(struct rk_lcdc_device_driver*lcdc_drv,int layer_id,int blank_mode) +{ + struct rk2928_lcdc_device * lcdc_dev = container_of(lcdc_drv,struct rk2928_lcdc_device ,driver); + + printk(KERN_INFO "%s>>>>>%d\n",__func__, blank_mode); + + spin_lock(&lcdc_dev->reg_lock); + if(likely(lcdc_dev->clk_on)) + { + switch(blank_mode) + { + case FB_BLANK_UNBLANK: + LcdMskReg(lcdc_dev,DSP_CTRL,m_BLANK_MODE ,v_BLANK_MODE(0)); + break; + case FB_BLANK_NORMAL: + LcdMskReg(lcdc_dev,DSP_CTRL,m_BLANK_MODE ,v_BLANK_MODE(1)); + break; + default: + LcdMskReg(lcdc_dev,DSP_CTRL,m_BLANK_MODE ,v_BLANK_MODE(1)); + break; + } + LCDC_REG_CFG_DONE(); + } + spin_unlock(&lcdc_dev->reg_lock); + + return 0; +} + +static int win0_display(struct rk2928_lcdc_device *lcdc_dev,struct layer_par *par ) +{ + u32 y_addr; + u32 uv_addr; + y_addr = par->smem_start + par->y_offset; + uv_addr = par->cbr_start + par->c_offset; + DBG(2,KERN_INFO "lcdc%d>>%s:y_addr:0x%x>>uv_addr:0x%x\n",lcdc_dev->id,__func__,y_addr,uv_addr); + + spin_lock(&lcdc_dev->reg_lock); + if(likely(lcdc_dev->clk_on)) + { + LcdWrReg(lcdc_dev, WIN0_YRGB_MST,y_addr); + LcdWrReg(lcdc_dev, WIN0_CBR_MST,uv_addr); + LCDC_REG_CFG_DONE(); + } + spin_unlock(&lcdc_dev->reg_lock); + + return 0; + +} + +static int win1_display(struct rk2928_lcdc_device *lcdc_dev,struct layer_par *par ) +{ + u32 y_addr; + u32 uv_addr; + y_addr = par->smem_start + par->y_offset; + uv_addr = par->cbr_start + par->c_offset; + DBG(2,KERN_INFO "lcdc%d>>%s>>y_addr:0x%x>>uv_addr:0x%x\n",lcdc_dev->id,__func__,y_addr,uv_addr); + + spin_lock(&lcdc_dev->reg_lock); + if(likely(lcdc_dev->clk_on)) + { + LcdWrReg(lcdc_dev, WIN1_RGB_MST, y_addr); + LCDC_REG_CFG_DONE(); + } + spin_unlock(&lcdc_dev->reg_lock); + + return 0; +} + +static int win0_set_par(struct rk2928_lcdc_device *lcdc_dev,rk_screen *screen, + struct layer_par *par ) +{ + u32 xact, yact, xvir, yvir, xpos, ypos; + u32 ScaleYrgbX = 0x1000; + u32 ScaleYrgbY = 0x1000; + u32 ScaleCbrX = 0x1000; + u32 ScaleCbrY = 0x1000; + + xact = par->xact; //active (origin) picture window width/height + yact = par->yact; + xvir = par->xvir; // virtual resolution + yvir = par->yvir; + xpos = par->xpos+screen->left_margin + screen->hsync_len; + ypos = par->ypos+screen->upper_margin + screen->vsync_len; + + + ScaleYrgbX = CalScale(xact, par->xsize); //both RGB and yuv need this two factor + ScaleYrgbY = CalScale(yact, par->ysize); + switch (par->format) + { + case YUV422:// yuv422 + ScaleCbrX = CalScale((xact/2), par->xsize); + ScaleCbrY = CalScale(yact, par->ysize); + break; + case YUV420: // yuv420 + ScaleCbrX = CalScale(xact/2, par->xsize); + ScaleCbrY = CalScale(yact/2, par->ysize); + break; + case YUV444:// yuv444 + ScaleCbrX = CalScale(xact, par->xsize); + ScaleCbrY = CalScale(yact, par->ysize); + break; + default: + break; + } + + DBG(1,"%s for lcdc%d>>format:%d>>>xact:%d>>yact:%d>>xsize:%d>>ysize:%d>>xvir:%d>>yvir:%d>>xpos:%d>>ypos:%d>>\n", + __func__,lcdc_dev->id,par->format,xact,yact,par->xsize,par->ysize,xvir,yvir,xpos,ypos); + + spin_lock(&lcdc_dev->reg_lock); + if(likely(lcdc_dev->clk_on)) + { + LcdWrReg(lcdc_dev, WIN0_SCL_FACTOR_YRGB, v_X_SCL_FACTOR(ScaleYrgbX) | v_Y_SCL_FACTOR(ScaleYrgbY)); + LcdWrReg(lcdc_dev, WIN0_SCL_FACTOR_CBR,v_X_SCL_FACTOR(ScaleCbrX)| v_Y_SCL_FACTOR(ScaleCbrY)); + LcdMskReg(lcdc_dev, SYS_CFG, m_W0_FORMAT, v_W0_FORMAT(par->format)); //(inf->video_mode==0) + LcdWrReg(lcdc_dev, WIN0_ACT_INFO,v_ACT_WIDTH(xact) | v_ACT_HEIGHT(yact)); + LcdWrReg(lcdc_dev, WIN0_DSP_ST, v_DSP_STX(xpos) | v_DSP_STY(ypos)); + LcdWrReg(lcdc_dev, WIN0_DSP_INFO, v_DSP_WIDTH(par->xsize)| v_DSP_HEIGHT(par->ysize)); + LcdMskReg(lcdc_dev,WIN0_COLOR_KEY_CTRL, m_COLORKEY_EN | m_KEYCOLOR, + v_COLORKEY_EN(1) | v_KEYCOLOR(0)); + switch(par->format) + { + case ARGB888: + LcdMskReg(lcdc_dev, WIN_VIR,m_WIN0_VIR,v_WIN0_ARGB888_VIRWIDTH(xvir)); + //LcdMskReg(lcdc_dev,SYS_CTRL1,m_W0_RGB_RB_SWAP,v_W1_RGB_RB_SWAP(1)); + break; + case RGB888: //rgb888 + LcdMskReg(lcdc_dev, WIN_VIR,m_WIN0_VIR,v_WIN0_RGB888_VIRWIDTH(xvir)); + //LcdMskReg(lcdc_dev,SYS_CTRL1,m_W0_RGB_RB_SWAP,v_W0_RGB_RB_SWAP(1)); + break; + case RGB565: //rgb565 + LcdMskReg(lcdc_dev, WIN_VIR,m_WIN0_VIR,v_WIN0_RGB565_VIRWIDTH(xvir)); + break; + case YUV422: + case YUV420: + LcdMskReg(lcdc_dev, WIN_VIR,m_WIN0_VIR,v_WIN0_YUV_VIRWIDTH(xvir)); + break; + default: + LcdMskReg(lcdc_dev, WIN_VIR,m_WIN0_VIR,v_WIN0_RGB888_VIRWIDTH(xvir)); + break; + } + + LCDC_REG_CFG_DONE(); + } + spin_unlock(&lcdc_dev->reg_lock); + + return 0; + +} + +static int win1_set_par(struct rk2928_lcdc_device *lcdc_dev,rk_screen *screen, + struct layer_par *par ) +{ + u32 xact, yact, xvir, yvir, xpos, ypos; + u32 ScaleYrgbX = 0x1000; + u32 ScaleYrgbY = 0x1000; + u32 ScaleCbrX = 0x1000; + u32 ScaleCbrY = 0x1000; + + xact = par->xact; + yact = par->yact; + xvir = par->xvir; + yvir = par->yvir; + xpos = par->xpos+screen->left_margin + screen->hsync_len; + ypos = par->ypos+screen->upper_margin + screen->vsync_len; + + DBG(1,"%s for lcdc%d>>format:%d>>>xact:%d>>yact:%d>>xsize:%d>>ysize:%d>>xvir:%d>>yvir:%d>>xpos:%d>>ypos:%d>>\n", + __func__,lcdc_dev->id,par->format,xact,yact,par->xsize,par->ysize,xvir,yvir,xpos,ypos); + + + spin_lock(&lcdc_dev->reg_lock); + if(likely(lcdc_dev->clk_on)) + { + LcdMskReg(lcdc_dev,SYS_CFG, m_W1_FORMAT, v_W1_FORMAT(par->format)); + LcdWrReg(lcdc_dev, WIN1_DSP_ST,v_DSP_STX(xpos) | v_DSP_STY(ypos)); + LcdWrReg(lcdc_dev, WIN1_DSP_INFO,v_DSP_WIDTH(par->xsize) | v_DSP_HEIGHT(par->ysize)); + // enable win1 color key and set the color to black(rgb=0) + LcdMskReg(lcdc_dev, WIN1_COLOR_KEY_CTRL, m_COLORKEY_EN | m_KEYCOLOR,v_COLORKEY_EN(1) | v_KEYCOLOR(0)); + + + switch(par->format) + { + case ARGB888: + LcdMskReg(lcdc_dev, WIN_VIR,m_WIN1_VIR,v_WIN1_ARGB888_VIRWIDTH(xvir)); + //LcdMskReg(lcdc_dev,SYS_CTRL1,m_W1_RGB_RB_SWAP,v_W1_RGB_RB_SWAP(1)); + break; + case RGB888: //rgb888 + LcdMskReg(lcdc_dev, WIN_VIR,m_WIN1_VIR,v_WIN1_RGB888_VIRWIDTH(xvir)); + // LcdMskReg(lcdc_dev,SYS_CTRL1,m_W1_RGB_RB_SWAP,v_W1_RGB_RB_SWAP(1)); + break; + case RGB565: //rgb565 + LcdMskReg(lcdc_dev, WIN_VIR,m_WIN1_VIR,v_WIN1_RGB565_VIRWIDTH(xvir)); + break; + default: + LcdMskReg(lcdc_dev, WIN_VIR,m_WIN1_VIR,v_WIN1_RGB888_VIRWIDTH(xvir)); + break; + } + + + LCDC_REG_CFG_DONE(); + } + spin_unlock(&lcdc_dev->reg_lock); + return 0; +} + +static int rk2928_lcdc_open(struct rk_lcdc_device_driver *dev_drv,int layer_id,bool open) +{ + struct rk2928_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk2928_lcdc_device,driver); + if(layer_id == 0) + { + win0_open(lcdc_dev,open); + } + else if(layer_id == 1) + { + win1_open(lcdc_dev,open); + } + + return 0; +} + +static int rk2928_lcdc_set_par(struct rk_lcdc_device_driver *dev_drv,int layer_id) +{ + struct rk2928_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk2928_lcdc_device,driver); + struct layer_par *par = NULL; + rk_screen *screen = lcdc_dev->screen; + if(!screen) + { + printk(KERN_ERR "screen is null!\n"); + return -ENOENT; + } + if(layer_id==0) + { + par = dev_drv->layer_par[0]; + win0_set_par(lcdc_dev,screen,par); + } + else if(layer_id==1) + { + par = dev_drv->layer_par[1]; + win1_set_par(lcdc_dev,screen,par); + } + + return 0; +} + +int rk2928_lcdc_pan_display(struct rk_lcdc_device_driver * dev_drv,int layer_id) +{ + struct rk2928_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk2928_lcdc_device,driver); + struct layer_par *par = NULL; + rk_screen *screen = lcdc_dev->screen; + unsigned long flags; + int timeout; + if(!screen) + { + printk(KERN_ERR "screen is null!\n"); + return -ENOENT; + } + if(layer_id==0) + { + par = dev_drv->layer_par[0]; + win0_display(lcdc_dev,par); + } + else if(layer_id==1) + { + par = dev_drv->layer_par[1]; + win1_display(lcdc_dev,par); + } + if((dev_drv->first_frame)) //this is the first frame of the system ,enable frame start interrupt + { + dev_drv->first_frame = 0; + LcdMskReg(lcdc_dev,INT_STATUS,m_FRM_START_INT_CLEAR |m_FRM_START_INT_EN , + v_FRM_START_INT_CLEAR(1) | v_FRM_START_INT_EN(1)); + LCDC_REG_CFG_DONE(); // write any value to REG_CFG_DONE let config become effective + + } + + if(dev_drv->num_buf < 3) //3buffer ,no need to wait for sysn + { + spin_lock_irqsave(&dev_drv->cpl_lock,flags); + init_completion(&dev_drv->frame_done); + spin_unlock_irqrestore(&dev_drv->cpl_lock,flags); + timeout = wait_for_completion_timeout(&dev_drv->frame_done,msecs_to_jiffies(dev_drv->screen->ft+5)); + if(!timeout&&(!dev_drv->frame_done.done)) + { + printk(KERN_ERR "wait for new frame start time out!\n"); + return -ETIMEDOUT; + } + } + + return 0; +} + +int rk2928_lcdc_ioctl(struct rk_lcdc_device_driver * dev_drv,unsigned int cmd, unsigned long arg,int layer_id) +{ + struct rk2928_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk2928_lcdc_device,driver); + u32 panel_size[2]; + void __user *argp = (void __user *)arg; + int ret = 0; + switch(cmd) + { + case FBIOGET_PANEL_SIZE: //get panel size + panel_size[0] = lcdc_dev->screen->x_res; + panel_size[1] = lcdc_dev->screen->y_res; + if(copy_to_user(argp, panel_size, 8)) + return -EFAULT; + break; + default: + break; + } + + return ret; +} +static int rk2928_lcdc_get_layer_state(struct rk_lcdc_device_driver *dev_drv,int layer_id) +{ + struct rk2928_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk2928_lcdc_device,driver); + struct layer_par *par = dev_drv->layer_par[layer_id]; + + spin_lock(&lcdc_dev->reg_lock); + if(lcdc_dev->clk_on) + { + if(layer_id == 0) + { + par->state = LcdReadBit(lcdc_dev,SYS_CFG,m_W0_EN); + } + else if( layer_id == 1) + { + par->state = LcdReadBit(lcdc_dev,SYS_CFG,m_W1_EN); + } + } + spin_unlock(&lcdc_dev->reg_lock); + + return par->state; + +} + +/*********************************** +overlay manager +swap:1 win0 on the top of win1 + 0 win1 on the top of win0 +set : 1 set overlay + 0 get overlay state +************************************/ +static int rk2928_lcdc_ovl_mgr(struct rk_lcdc_device_driver *dev_drv,int swap,bool set) +{ + struct rk2928_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk2928_lcdc_device,driver); + int ovl; + spin_lock(&lcdc_dev->reg_lock); + if(lcdc_dev->clk_on) + { + if(set) //set overlay + { + LcdMskReg(lcdc_dev,DSP_CTRL,m_W0W1_POSITION_SWAP,v_W0W1_POSITION_SWAP(swap)); + LCDC_REG_CFG_DONE(); + ovl = swap; + } + else //get overlay + { + ovl = LcdReadBit(lcdc_dev,DSP_CTRL,m_W0W1_POSITION_SWAP); + } + } + else + { + ovl = -EPERM; + } + spin_unlock(&lcdc_dev->reg_lock); + + return ovl; +} +static int rk2928_lcdc_get_disp_info(struct rk_lcdc_device_driver *dev_drv,int layer_id) +{ + struct rk2928_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk2928_lcdc_device,driver); + return 0; +} + + +/******************************************* +lcdc fps manager,set or get lcdc fps +set:0 get + 1 set +********************************************/ +static int rk2928_lcdc_fps_mgr(struct rk_lcdc_device_driver *dev_drv,int fps,bool set) +{ + struct rk2928_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk2928_lcdc_device,driver); + rk_screen * screen = dev_drv->screen; + u64 ft = 0; + u32 dotclk; + int ret; + + if(set) + { + ft = div_u64(1000000000000llu,fps); + dev_drv->pixclock = div_u64(ft,(screen->upper_margin + screen->lower_margin + screen->y_res +screen->vsync_len)* + (screen->left_margin + screen->right_margin + screen->x_res + screen->hsync_len)); + dotclk = div_u64(1000000000000llu,dev_drv->pixclock); + ret = clk_set_rate(lcdc_dev->dclk, dotclk); + if(ret) + { + printk(KERN_ERR ">>>>>> set lcdc%d dclk failed\n",lcdc_dev->id); + } + dev_drv->pixclock = lcdc_dev->pixclock = div_u64(1000000000000llu, clk_get_rate(lcdc_dev->dclk)); + + } + + ft = (u64)(screen->upper_margin + screen->lower_margin + screen->y_res +screen->vsync_len)* + (screen->left_margin + screen->right_margin + screen->x_res + screen->hsync_len)* + (dev_drv->pixclock); // one frame time ,(pico seconds) + fps = div64_u64(1000000000000llu,ft); + screen->ft = 1000/fps ; //one frame time in ms + return fps; +} +int rk2928_lcdc_early_suspend(struct rk_lcdc_device_driver *dev_drv) +{ + struct rk2928_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk2928_lcdc_device,driver); + + spin_lock(&lcdc_dev->reg_lock); + if(likely(lcdc_dev->clk_on)) + { + lcdc_dev->clk_on = 0; + LcdMskReg(lcdc_dev, INT_STATUS, m_FRM_START_INT_CLEAR, v_FRM_START_INT_CLEAR(1)); + LcdSetBit(lcdc_dev, SYS_CFG,m_LCDC_STANDBY); + LCDC_REG_CFG_DONE(); + spin_unlock(&lcdc_dev->reg_lock); + } + else //clk already disabled + { + spin_unlock(&lcdc_dev->reg_lock); + return 0; + } + + + mdelay(1); + clk_disable(lcdc_dev->dclk); + clk_disable(lcdc_dev->hclk); + clk_disable(lcdc_dev->aclk); + clk_disable(lcdc_dev->pd); + + return 0; +} + + +int rk2928_lcdc_early_resume(struct rk_lcdc_device_driver *dev_drv) +{ + struct rk2928_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk2928_lcdc_device,driver); + + if(!lcdc_dev->clk_on) + { + clk_enable(lcdc_dev->pd); + clk_enable(lcdc_dev->hclk); + clk_enable(lcdc_dev->dclk); + clk_enable(lcdc_dev->aclk); + } + memcpy((u8*)lcdc_dev->preg, (u8*)&lcdc_dev->regbak, 0xc4); //resume reg + + spin_lock(&lcdc_dev->reg_lock); + if(lcdc_dev->atv_layer_cnt) + { + LcdClrBit(lcdc_dev, SYS_CFG,m_LCDC_STANDBY); + LCDC_REG_CFG_DONE(); + } + lcdc_dev->clk_on = 1; + spin_unlock(&lcdc_dev->reg_lock); + + return 0; +} +static irqreturn_t rk2928_lcdc_isr(int irq, void *dev_id) +{ + struct rk2928_lcdc_device *lcdc_dev = (struct rk2928_lcdc_device *)dev_id; + + LcdMskReg(lcdc_dev, INT_STATUS, m_FRM_START_INT_CLEAR, v_FRM_START_INT_CLEAR(1)); + LCDC_REG_CFG_DONE(); + //LcdMskReg(lcdc_dev, INT_STATUS, m_LINE_FLAG_INT_CLEAR, v_LINE_FLAG_INT_CLEAR(1)); + + if(lcdc_dev->driver.num_buf < 3) //three buffer ,no need to wait for sync + { + spin_lock(&(lcdc_dev->driver.cpl_lock)); + complete(&(lcdc_dev->driver.frame_done)); + spin_unlock(&(lcdc_dev->driver.cpl_lock)); + } + return IRQ_HANDLED; +} + +static struct layer_par lcdc_layer[] = { + [0] = { + .name = "win0", + .id = 0, + .support_3d = true, + }, + [1] = { + .name = "win1", + .id = 1, + .support_3d = false, + }, +}; + +static struct rk_lcdc_device_driver lcdc_driver = { + .name = "lcdc", + .def_layer_par = lcdc_layer, + .num_layer = ARRAY_SIZE(lcdc_layer), + .open = rk2928_lcdc_open, + .init_lcdc = init_rk2928_lcdc, + .ioctl = rk2928_lcdc_ioctl, + .suspend = rk2928_lcdc_early_suspend, + .resume = rk2928_lcdc_early_resume, + .set_par = rk2928_lcdc_set_par, + .blank = rk2928_lcdc_blank, + .pan_display = rk2928_lcdc_pan_display, + .load_screen = rk2928_load_screen, + .get_layer_state = rk2928_lcdc_get_layer_state, + .ovl_mgr = rk2928_lcdc_ovl_mgr, + .get_disp_info = rk2928_lcdc_get_disp_info, + .fps_mgr = rk2928_lcdc_fps_mgr, +}; +#ifdef CONFIG_PM +static int rk2928_lcdc_suspend(struct platform_device *pdev, pm_message_t state) +{ + return 0; +} + +static int rk2928_lcdc_resume(struct platform_device *pdev) +{ + return 0; +} + +#else +#define rk2928_lcdc_suspend NULL +#define rk2928_lcdc_resume NULL +#endif + +static int __devinit rk2928_lcdc_probe (struct platform_device *pdev) +{ + struct rk2928_lcdc_device *lcdc_dev=NULL; + rk_screen *screen; + struct rk29fb_info *screen_ctr_info; + struct resource *res = NULL; + struct resource *mem; + int ret = 0; + + /*************Malloc rk2928lcdc_inf and set it to pdev for drvdata**********/ + lcdc_dev = kzalloc(sizeof(struct rk2928_lcdc_device), GFP_KERNEL); + if(!lcdc_dev) + { + dev_err(&pdev->dev, ">>rk2928 lcdc device kmalloc fail!"); + return -ENOMEM; + } + platform_set_drvdata(pdev, lcdc_dev); + lcdc_dev->id = pdev->id; + screen_ctr_info = (struct rk29fb_info * )pdev->dev.platform_data; + screen = kzalloc(sizeof(rk_screen), GFP_KERNEL); + if(!screen) + { + dev_err(&pdev->dev, ">>rk2928 lcdc screen kmalloc fail!"); + ret = -ENOMEM; + goto err0; + } + else + { + lcdc_dev->screen = screen; + } + /****************get lcdc0 reg *************************/ + res = platform_get_resource(pdev, IORESOURCE_MEM,0); + if (res == NULL) + { + dev_err(&pdev->dev, "failed to get io resource for lcdc%d \n",lcdc_dev->id); + ret = -ENOENT; + goto err1; + } + lcdc_dev->reg_phy_base = res->start; + lcdc_dev->len = resource_size(res); + mem = request_mem_region(lcdc_dev->reg_phy_base, resource_size(res), pdev->name); + if (mem == NULL) + { + dev_err(&pdev->dev, "failed to request mem region for lcdc%d\n",lcdc_dev->id); + ret = -ENOENT; + goto err1; + } + lcdc_dev->reg_vir_base = ioremap(lcdc_dev->reg_phy_base, resource_size(res)); + if (lcdc_dev->reg_vir_base == NULL) + { + dev_err(&pdev->dev, "cannot map IO\n"); + ret = -ENXIO; + goto err2; + } + + lcdc_dev->preg = (LCDC_REG*)lcdc_dev->reg_vir_base; + printk("lcdc%d:reg_phy_base = 0x%08x,reg_vir_base:0x%p\n",pdev->id,lcdc_dev->reg_phy_base, lcdc_dev->preg); + lcdc_dev->driver.dev=&pdev->dev; + lcdc_dev->driver.screen = screen; + lcdc_dev->driver.screen_ctr_info = screen_ctr_info; + spin_lock_init(&lcdc_dev->reg_lock); + lcdc_dev->irq = platform_get_irq(pdev, 0); + if(lcdc_dev->irq < 0) + { + dev_err(&pdev->dev, "cannot find IRQ\n"); + goto err3; + } + ret = request_irq(lcdc_dev->irq, rk2928_lcdc_isr, IRQF_DISABLED,dev_name(&pdev->dev),lcdc_dev); + if (ret) + { + dev_err(&pdev->dev, "cannot requeset irq %d - err %d\n", lcdc_dev->irq, ret); + ret = -EBUSY; + goto err3; + } + ret = rk_fb_register(&(lcdc_dev->driver),&lcdc_driver,lcdc_dev->id); + if(ret < 0) + { + printk(KERN_ERR "register fb for lcdc%d failed!\n",lcdc_dev->id); + goto err4; + } + printk("rk2928 lcdc%d probe ok!\n",lcdc_dev->id); + + return 0; + +err4: + free_irq(lcdc_dev->irq,lcdc_dev); +err3: + iounmap(lcdc_dev->reg_vir_base); +err2: + release_mem_region(lcdc_dev->reg_phy_base,resource_size(res)); +err1: + kfree(screen); +err0: + platform_set_drvdata(pdev, NULL); + kfree(lcdc_dev); + return ret; + +} +static int __devexit rk2928_lcdc_remove(struct platform_device *pdev) +{ + struct rk2928_lcdc_device *lcdc_dev = platform_get_drvdata(pdev); + rk_fb_unregister(&(lcdc_dev->driver)); + rk2928_lcdc_deinit(lcdc_dev); + iounmap(lcdc_dev->reg_vir_base); + release_mem_region(lcdc_dev->reg_phy_base,lcdc_dev->len); + kfree(lcdc_dev->screen); + kfree(lcdc_dev); + return 0; +} + +static void rk2928_lcdc_shutdown(struct platform_device *pdev) +{ + struct rk2928_lcdc_device *lcdc_dev = platform_get_drvdata(pdev); + rk_fb_unregister(&(lcdc_dev->driver)); + rk2928_lcdc_deinit(lcdc_dev); + /*iounmap(lcdc_dev->reg_vir_base); + release_mem_region(lcdc_dev->reg_phy_base,lcdc_dev->len); + kfree(lcdc_dev->screen); + kfree(lcdc_dev);*/ +} + + +static struct platform_driver rk2928lcdc_driver = { + .probe = rk2928_lcdc_probe, + .remove = __devexit_p(rk2928_lcdc_remove), + .driver = { + .name = "rk2928-lcdc", + .owner = THIS_MODULE, + }, + .suspend = rk2928_lcdc_suspend, + .resume = rk2928_lcdc_resume, + .shutdown = rk2928_lcdc_shutdown, +}; + +static int __init rk2928_lcdc_init(void) +{ + return platform_driver_register(&rk2928lcdc_driver); +} + +static void __exit rk2928_lcdc_exit(void) +{ + platform_driver_unregister(&rk2928lcdc_driver); +} + + + +fs_initcall(rk2928_lcdc_init); +module_exit(rk2928_lcdc_exit); + + + diff --git a/drivers/video/rockchip/chips/rk2928_lcdc.h b/drivers/video/rockchip/chips/rk2928_lcdc.h new file mode 100755 index 000000000000..826828f25091 --- /dev/null +++ b/drivers/video/rockchip/chips/rk2928_lcdc.h @@ -0,0 +1,452 @@ +#ifndef RK2928_LCDC_H_ +#define RK2928_LCDC_H_ + +#include + +#define LcdReadBit(inf, addr, msk) ((inf->regbak.addr=inf->preg->addr)&(msk)) +#define LcdWrReg(inf, addr, val) inf->preg->addr=inf->regbak.addr=(val) +#define LcdRdReg(inf, addr) (inf->preg->addr) +#define LcdSetBit(inf, addr, msk) inf->preg->addr=((inf->regbak.addr) |= (msk)) +#define LcdClrBit(inf, addr, msk) inf->preg->addr=((inf->regbak.addr) &= ~(msk)) +#define LcdSetRegBit(inf, addr, msk) inf->preg->addr=((inf->preg->addr) |= (msk)) +#define LcdMskReg(inf, addr, msk, val) (inf->regbak.addr)&=~(msk); inf->preg->addr=(inf->regbak.addr|=(val)) +#define LCDC_REG_CFG_DONE() LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); dsb() + +/******************************************************************** +** 结构定义 * +********************************************************************/ +/* LCDC的寄存器结构 */ + +typedef volatile struct tagLCDC_REG +{ + /* offset 0x00~0xc0 */ + unsigned int SYS_CFG; //0x00 system config register + unsigned int DSP_CTRL; //0x0c display control register + unsigned int BG_COLOR; //back ground color register + unsigned int ALPHA_CTRL; //alpha control register + unsigned int INT_STATUS; //0x10 Interrupt status register + unsigned int WIN0_COLOR_KEY_CTRL; //0x1c Win0 blending control register + unsigned int WIN1_COLOR_KEY_CTRL; //0x20 Win1 blending control register + unsigned int WIN0_YRGB_MST; //0x28 Win0 active YRGB memory start address0 + unsigned int WIN0_CBR_MST; //0x2c Win0 active Cbr memory start address0 + unsigned int WIN_VIR; //0x38 WIN0 virtual display width/height + unsigned int WIN0_ACT_INFO; //0x3C Win0 active window width/height + unsigned int WIN0_DSP_INFO; //0x40 Win0 display width/height on panel + unsigned int WIN0_DSP_ST; //0x44 Win0 display start point on panel + unsigned int WIN0_SCL_FACTOR_YRGB; //0x48Win0 YRGB scaling factor setting + unsigned int WIN0_SCL_FACTOR_CBR; //0x4c Win0 YRGB scaling factor setting + unsigned int WIN0_SCL_OFFSET; //0x50 Win0 Cbr scaling start point offset + unsigned int WIN1_RGB_MST; //0x54 Win1 active YRGB memory start address + unsigned int WIN1_DSP_INFO; //0x64 Win1 display width/height on panel + unsigned int WIN1_DSP_ST; //0x68 Win1 display start point on panel + unsigned int HWC_MST; //0x88 HWC memory start address + unsigned int HWC_DSP_ST; //0x8C HWC display start point on panel + unsigned int HWC_COLOR_LUT0; //0x90 Hardware cursor color 2’b01 look up table 0 + unsigned int HWC_COLOR_LUT1; //0x94 Hardware cursor color 2’b10 look up table 1 + unsigned int HWC_COLOR_LUT2; //0x98 Hardware cursor color 2’b11 look up table 2 + unsigned int DSP_HTOTAL_HS_END; //0x9c Panel scanning horizontal width and hsync pulse end point + unsigned int DSP_HACT_ST_END; //0xa0 Panel active horizontal scanning start/end point + unsigned int DSP_VTOTAL_VS_END; //0xa4 Panel scanning vertical height and vsync pulse end point + unsigned int DSP_VACT_ST_END; //0xa8 Panel active vertical scanning start/end point + unsigned int SCL_REG0; //scaler register + unsigned int SCL_REG1; + unsigned int SCL_REG2; + unsigned int SCL_REG3; + unsigned int SCL_REG4; + unsigned int SCL_REG5; + unsigned int SCL_REG6; + unsigned int SCL_REG7; + unsigned int SCL_REG8; + unsigned int reserve[3]; + unsigned int REG_CFG_DONE; //0xc0 REGISTER CONFIG FINISH + +} LCDC_REG, *pLCDC_REG; + + +/* SYS_CONFIG */ + +#define m_W0_EN (1<<0) +#define m_W1_EN (1<<1) +#define m_HWC_EN (1<<2) +#define m_W0_FORMAT (7<<3) +#define m_W1_FORMAT (7<<6) + +#define m_W0_AXI_OUTSTANDING_DISABLE (1<<16) +#define m_W1_AXI_OUTSTANDING_DISABLE (1<<17) +#define m_DMA_BURST_LENGTH (3<<18) +#define m_LCDC_STANDBY (1<<22) + +#define m_LCDC_AXICLK_AUTO_ENABLE (1<<24) //eanble for low power + +#define v_W0_EN(x) (((x)&1)<<0) +#define v_W1_EN(x) (((x)&1)<<1) +#define v_HWC_EN(x) (((x)&1)<<2) +#define v_W0_FORMAT(x) (((x)&7)<<3) +#define v_W1_FORMAT(x) (((x)&7)<<6) +#define v_LCDC_STANDBY(x) (((x)&1)<<22) + +#define v_LCDC_AXICLK_AUTO_ENABLE(x) (((x)&1)<<24) + +#define v_LCDC_DMA_STOP(x) (((x)&1)<<0) +#define v_HWC_RELOAD_EN(x) (((x)&1)<<2) +#define v_W0_AXI_OUTSTANDING_DISABLE(x) (((x)&1)<<3) +#define v_W1_AXI_OUTSTANDING_DISABLE(x) (((x)&1)<<4) +#define v_W2_AXI_OUTSTANDING_DISABLE(x) (((x)&1)<<5) +#define v_DMA_BURST_LENGTH(x) (((x)&3)<<6) +#define v_WIN0_YRGB_CHANNEL0_ID(x) (((x)&7)<<8) +#define v_WIN0_CBR_CHANNEL0_ID(x) (((x)&7)<<11) +#define v_WIN0_YRGB_CHANNEL1_ID(x) (((x)&7)<<14) +#define v_WIN0_CBR_CHANNEL1_ID(x) (((x)&7)<<17) +#define v_WIN1_YRGB_CHANNEL_ID(x) (((x)&7)<<20) +#define v_WIN1_CBR_CHANNEL_ID(x) (((x)&7)<<23) +#define v_WIN2_CHANNEL_ID(x) (((x)&7)<<26) +#define v_HWC_CHANNEL_ID(x) (((x)&7)<<29) + + + +//LCDC_DSP_CTRL_REG +#define m_DISPLAY_FORMAT (3<<0) +#define m_BLANK_MODE (1<<2) +#define m_BLACK_MODE (1<<3) +#define m_HSYNC_POLARITY (1<<4) +#define m_VSYNC_POLARITY (1<<5) +#define m_DEN_POLARITY (1<<6) +#define m_DCLK_POLARITY (1<<7) +#define m_W0W1_POSITION_SWAP (1<<8) +#define m_OUTPUT_BG_SWAP (1<<9) +#define m_OUTPUT_RB_SWAP (1<<10) +#define m_OUTPUT_RG_SWAP (1<<11) +#define m_DITHER_UP_EN (1<<12) +#define m_DITHER_DOWN_MODE (1<<13) +#define m_DITHER_DOWN_EN (1<<14) + + +#define m_W1_INTERLACE_READ_MODE (1<<15) +#define m_W2_INTERLACE_READ_MODE (1<<16) +#define m_W0_YRGB_DEFLICK_MODE (1<<17) +#define m_W0_CBR_DEFLICK_MODE (1<<18) +#define m_W1_YRGB_DEFLICK_MODE (1<<19) +#define m_W1_CBR_DEFLICK_MODE (1<<20) +#define m_W0_ALPHA_MODE (1<<21) +#define m_W1_ALPHA_MODE (1<<22) +#define m_W2_ALPHA_MODE (1<<23) +#define m_W0_COLOR_SPACE_CONVERSION (3<<24) +#define m_W1_COLOR_SPACE_CONVERSION (3<<26) +#define m_W2_COLOR_SPACE_CONVERSION (1<<28) +#define m_YCRCB_CLIP_EN (1<<29) +#define m_CBR_FILTER_656 (1<<30) + +#define v_DISPLAY_FORMAT(x) (((x)&0x3)<<0) +#define v_BLANK_MODE(x) (((x)&1)<<2) +#define v_BLACK_MODE(x) (((x)&1)<<2) +#define v_HSYNC_POLARITY(x) (((x)&1)<<4) +#define v_VSYNC_POLARITY(x) (((x)&1)<<5) +#define v_DEN_POLARITY(x) (((x)&1)<<6) +#define v_DCLK_POLARITY(x) (((x)&1)<<7) +#define v_W0W1_POSITION_SWAP(x) (((x)&1)<<8) +#define v_OUTPUT_BG_SWAP(x) (((x)&1)<<9) +#define v_OUTPUT_RB_SWAP(x) (((x)&1)<<10) +#define v_OUTPUT_RG_SWAP(x) (((x)&1)<<11) +#define v_DITHER_UP_EN(x) (((x)&1)<<12) +#define v_DITHER_DOWN_MODE(x) (((x)&1)<<13) +#define v_DITHER_DOWN_EN(x) (((x)&1)<<14) + +#define v_INTERLACE_DSP_EN(x) (((x)&1)<<12) +#define v_INTERLACE_FIELD_POLARITY(x) (((x)&1)<<13) +#define v_W0_INTERLACE_READ_MODE(x) (((x)&1)<<14) +#define v_W1_INTERLACE_READ_MODE(x) (((x)&1)<<15) +#define v_W2_INTERLACE_READ_MODE(x) (((x)&1)<<16) +#define v_W0_YRGB_DEFLICK_MODE(x) (((x)&1)<<17) +#define v_W0_CBR_DEFLICK_MODE(x) (((x)&1)<<18) +#define v_W1_YRGB_DEFLICK_MODE(x) (((x)&1)<<19) +#define v_W1_CBR_DEFLICK_MODE(x) (((x)&1)<<20) +#define v_W0_ALPHA_MODE(x) (((x)&1)<<21) +#define v_W1_ALPHA_MODE(x) (((x)&1)<<22) +#define v_W2_ALPHA_MODE(x) (((x)&1)<<23) +#define v_W0_COLOR_SPACE_CONVERSION(x) (((x)&3)<<24) +#define v_W1_COLOR_SPACE_CONVERSION(x) (((x)&3)<<26) +#define v_W2_COLOR_SPACE_CONVERSION(x) (((x)&1)<<28) +#define v_YCRCB_CLIP_EN(x) (((x)&1)<<29) +#define v_CBR_FILTER_656(x) (((x)&1)<<30) + +//LCDC_BG_COLOR +#define m_BG_COLOR (0xffffff<<0) +#define m_BG_B (0xff<<0) +#define m_BG_G (0xff<<8) +#define m_BG_R (0xff<<16) +#define v_BG_COLOR(x) (((x)&0xffffff)<<0) +#define v_BG_B(x) (((x)&0xff)<<0) +#define v_BG_G(x) (((x)&0xff)<<8) +#define v_BG_R(x) (((x)&0xff)<<16) + + + + +//LCDC_ BLEND_CTRL +#define m_HWC_BLEND_EN (1<<0) +#define m_W2_BLEND_EN (1<<1) +#define m_W1_BLEND_EN (1<<2) +#define m_W0_BLEND_EN (1<<3) +#define m_HWC_BLEND_FACTOR (15<<4) +#define m_W2_BLEND_FACTOR (0xff<<8) +#define m_W1_BLEND_FACTOR (0xff<<16) +#define m_W0_BLEND_FACTOR (0xff<<24) + +#define v_HWC_BLEND_EN(x) (((x)&1)<<0) +#define v_W2_BLEND_EN(x) (((x)&1)<<1) +#define v_W1_BLEND_EN(x) (((x)&1)<<2) +#define v_W0_BLEND_EN(x) (((x)&1)<<3) +#define v_HWC_BLEND_FACTOR(x) (((x)&15)<<4) +#define v_W2_BLEND_FACTOR(x) (((x)&0xff)<<8) +#define v_W1_BLEND_FACTOR(x) (((x)&0xff)<<16) +#define v_W0_BLEND_FACTOR(x) (((x)&0xff)<<24) + +//LCDC_INT_STATUS +#define v_HOR_START_INT_STA (1<<0) //status +#define v_FRM_START_INT_STA (1<<1) +#define v_LINE_FLAG_INT_STA (1<<2) +#define v_BUS_ERR_INT_STA (1<<3) +#define m_HOR_START_INT_EN (1<<4) //enable +#define m_FRM_START_INT_EN (1<<5) +#define m_LINE_FLAG_INT_EN (1<<6) +#define m_BUS_ERR_INT_EN (1<<7) +#define m_HOR_START_INT_CLEAR (1<<8) //auto clear +#define m_FRM_START_INT_CLEAR (1<<9) +#define m_LINE_FLAG_INT_CLEAR (1<<10) +#define m_BUS_ERR_INT_CLEAR (1<<11) +#define m_LINE_FLAG_NUM (0xfff<<12) +#define v_HOR_START_INT_EN(x) (((x)&1)<<4) +#define v_FRM_START_INT_EN(x) (((x)&1)<<5) +#define v_LINE_FLAG_INT_EN(x) (((x)&1)<<6) +#define v_BUS_ERR_INT_EN(x) (((x)&1)<<7) +#define v_HOR_START_INT_CLEAR(x) (((x)&1)<<8) +#define v_FRM_START_INT_CLEAR(x) (((x)&1)<<9) +#define v_LINE_FLAG_INT_CLEAR(x) (((x)&1)<<10) +#define v_BUS_ERR_INT_CLEAR(x) (((x)&1)<<11) +#define v_LINE_FLAG_NUM(x) (((x)&0xfff)<<12) + + +//LCDC_WIN_VIR +#define m_WIN0_VIR (0xfff << 0) +#define m_WIN1_VIR (0xfff << 16) +//LCDC_WINx_VIR ,x is number of words of win0 virtual width +#define v_WIN0_ARGB888_VIRWIDTH(x) (x) +#define v_WIN0_RGB888_VIRWIDTH(x) (((x*3)>>2)+((x)%3)) +#define v_WIN0_RGB565_VIRWIDTH(x) (((x)>>1) + ((x%2)?1:0)) +#define v_WIN0_YUV_VIRWIDTH(x) (((x)>>2) +((x%4)?1:0)) + +#define v_WIN1_ARGB888_VIRWIDTH(x) (x << 16) +#define v_WIN1_RGB888_VIRWIDTH(x) ((((x*3)>>2)+((x)%3)) << 16) +#define v_WIN1_RGB565_VIRWIDTH(x) ((((x)>>1) + ((x%2)?1:0)) << 16) +#define v_WIN1_YUV_VIRWIDTH(x) ((((x)>>2) +((x%4)?1:0)) << 16 ) + + +//LCDC_WIN0_COLOR_KEY_CTRL / LCDC_WIN1_COLOR_KEY_CTRL +#define m_KEYCOLOR (0xffffff<<0) +#define m_KEYCOLOR_B (0xff<<0) +#define m_KEYCOLOR_G (0xff<<8) +#define m_KEYCOLOR_R (0xff<<16) +#define m_COLORKEY_EN (1<<24) +#define v_KEYCOLOR(x) (((x)&0xffffff)<<0) +#define v_KEYCOLOR_B(x) (((x)&0xff)<<0) +#define v_KEYCOLOR_G(x) (((x)&0xff)<<8) +#define v_KEYCOLOR_R(x) (((x)&0xff)<<16) +#define v_COLORKEY_EN(x) (((x)&1)<<24) + +//LCDC_DEFLICKER_SCL_OFFSET +#define m_W0_YRGB_VSD_OFFSET (0xff<<0) +#define m_W0_YRGB_VSP_OFFSET (0xff<<8) +#define m_W1_VSD_OFFSET (0xff<<16) +#define m_W1_VSP_OFFSET (0xff<<24) +#define v_W0_YRGB_VSD_OFFSET(x) (((x)&0xff)<<0) +#define v_W0_YRGB_VSP_OFFSET(x) (((x)&0xff)<<8) +#define v_W1_VSD_OFFSET(x) (((x)&0xff)<<16) +#define v_W1_VSP_OFFSET(x) (((x)&0xff)<<24) + + + + + +//AXI MS ID +#define m_W0_YRGB_CH_ID (0xF<<0) +#define m_W0_CBR_CH_ID (0xF<<4) +#define m_W1_YRGB_CH_ID (0xF<<8) +#define m_W2_CH_ID (0xF<<12) +#define m_HWC_CH_ID (0xF<<16) +#define v_W0_YRGB_CH_ID(x) (((x)&0xF)<<0) +#define v_W0_CBR_CH_ID(x) (((x)&0xF)<<4) +#define v_W1_YRGB_CH_ID(x) (((x)&0xF)<<8) +#define v_W2_CH_ID(x) (((x)&0xF)<<12) +#define v_HWC_CH_ID(x) (((x)&0xF)<<16) + + +/* Low Bits Mask */ +#define m_WORDLO (0xffff<<0) +#define m_WORDHI (0xffff<<16) +#define v_WORDLO(x) (((x)&0xffff)<<0) +#define v_WORDHI(x) (((x)&0xffff)<<16) + + +//LCDC_WINx_SCL_FACTOR_Y/CBCR +#define v_X_SCL_FACTOR(x) ((x)<<0) +#define v_Y_SCL_FACTOR(x) ((x)<<16) + +//LCDC_DSP_HTOTAL_HS_END +#define v_HSYNC(x) ((x)<<0) //hsync pulse width +#define v_HORPRD(x) ((x)<<16) //horizontal period + + +//LCDC_DSP_HACT_ST_END +#define v_HAEP(x) ((x)<<0) //horizontal active end point +#define v_HASP(x) ((x)<<16) //horizontal active start point + +//LCDC_DSP_VTOTAL_VS_END +#define v_VSYNC(x) ((x)<<0) +#define v_VERPRD(x) ((x)<<16) + +//LCDC_DSP_VACT_ST_END +#define v_VAEP(x) ((x)<<0) +#define v_VASP(x) ((x)<<16) + + + +#define m_ACTWIDTH (0xffff<<0) +#define m_ACTHEIGHT (0xffff<<16) +#define v_ACTWIDTH(x) (((x)&0xffff)<<0) +#define v_ACTHEIGHT(x) (((x)&0xffff)<<16) + +#define m_VIRST_X (0xffff<<0) +#define m_VIRST_Y (0xffff<<16) +#define v_VIRST_X(x) (((x)&0xffff)<<0) +#define v_VIRST_Y(x) (((x)&0xffff)<<16) + +#define m_PANELST_X (0x3ff<<0) +#define m_PANELST_Y (0x3ff<<16) +#define v_PANELST_X(x) (((x)&0x3ff)<<0) +#define v_PANELST_Y(x) (((x)&0x3ff)<<16) + +#define m_PANELWIDTH (0x3ff<<0) +#define m_PANELHEIGHT (0x3ff<<16) +#define v_PANELWIDTH(x) (((x)&0x3ff)<<0) +#define v_PANELHEIGHT(x) (((x)&0x3ff)<<16) + +#define m_HWC_B (0xff<<0) +#define m_HWC_G (0xff<<8) +#define m_HWC_R (0xff<<16) +#define m_W0_YRGB_HSP_OFFSET (0xff<<24) +#define m_W0_YRGB_HSD_OFFSET (0xff<<24) +#define v_HWC_B(x) (((x)&0xff)<<0) +#define v_HWC_G(x) (((x)&0xff)<<8) +#define v_HWC_R(x) (((x)&0xff)<<16) +#define v_W0_YRGB_HSP_OFFSET(x) (((x)&0xff)<<24) +#define v_W0_YRGB_HSD_OFFSET(x) (((x)&0xff)<<24) + +//LCDC_WIN0_ACT_INFO +#define v_ACT_WIDTH(x) ((x-1)<<0) +#define v_ACT_HEIGHT(x) ((x-1)<<16) + +//LCDC_WIN0_DSP_INFO +#define v_DSP_WIDTH(x) ((x-1)<<0) +#define v_DSP_HEIGHT(x) ((x-1)<<16) + +//LCDC_WIN0_DSP_ST //x,y start point of the panel scanning +#define v_DSP_STX(x) (x<<0) +#define v_DSP_STY(x) (x<<16) + +//Panel display scanning +#define m_PANEL_HSYNC_WIDTH (0x3ff<<0) +#define m_PANEL_HORIZONTAL_PERIOD (0x3ff<<16) +#define v_PANEL_HSYNC_WIDTH(x) (((x)&0x3ff)<<0) +#define v_PANEL_HORIZONTAL_PERIOD(x) (((x)&0x3ff)<<16) + +#define m_PANEL_END (0x3ff<<0) +#define m_PANEL_START (0x3ff<<16) +#define v_PANEL_END(x) (((x)&0x3ff)<<0) +#define v_PANEL_START(x) (((x)&0x3ff)<<16) + +#define m_PANEL_VSYNC_WIDTH (0x3ff<<0) +#define m_PANEL_VERTICAL_PERIOD (0x3ff<<16) +#define v_PANEL_VSYNC_WIDTH(x) (((x)&0x3ff)<<0) +#define v_PANEL_VERTICAL_PERIOD(x) (((x)&0x3ff)<<16) +//----------- + +#define m_HSCALE_FACTOR (0xffff<<0) +#define m_VSCALE_FACTOR (0xffff<<16) +#define v_HSCALE_FACTOR(x) (((x)&0xffff)<<0) +#define v_VSCALE_FACTOR(x) (((x)&0xffff)<<16) + +#define m_W0_CBR_HSD_OFFSET (0xff<<0) +#define m_W0_CBR_HSP_OFFSET (0xff<<8) +#define m_W0_CBR_VSD_OFFSET (0xff<<16) +#define m_W0_CBR_VSP_OFFSET (0xff<<24) +#define v_W0_CBR_HSD_OFFSET(x) (((x)&0xff)<<0) +#define v_W0_CBR_HSP_OFFSET(x) (((x)&0xff)<<8) +#define v_W0_CBR_VSD_OFFSET(x) (((x)&0xff)<<16) +#define v_W0_CBR_VSP_OFFSET(x) (((x)&0xff)<<24) + + + +#define CalScale(x, y) (((u32)x*0x1000)/y) +struct rk2928_lcdc_device{ + int id; + struct rk_lcdc_device_driver driver; + rk_screen *screen; + + LCDC_REG *preg; // LCDC reg base address and backup reg + LCDC_REG regbak; + + void __iomem *reg_vir_base; // virtual basic address of lcdc register + u32 reg_phy_base; // physical basic address of lcdc register + u32 len; // physical map length of lcdc register + spinlock_t reg_lock; //one time only one process allowed to config the register + bool clk_on; //if aclk or hclk is closed ,acess to register is not allowed + u8 atv_layer_cnt; //active layer counter,when atv_layer_cnt = 0,disable lcdc + unsigned int irq; + + struct clk *pd; //lcdc power domain + struct clk *hclk; //lcdc AHP clk + struct clk *dclk; //lcdc dclk + struct clk *aclk; //lcdc share memory frequency + struct clk *aclk_parent; //lcdc aclk divider frequency source + struct clk *aclk_ddr_lcdc; //DDR LCDC AXI clock disable. + struct clk *aclk_disp_matrix; //DISPLAY matrix AXI clock disable. + struct clk *hclk_cpu_display; //CPU DISPLAY AHB bus clock disable. + struct clk *pd_display; // display power domain + u32 pixclock; +}; + +struct lcdc_info{ +/*LCD CLK*/ + struct rk2928_lcdc_device lcdc0; + +}; + + +struct win_set { + volatile u32 y_offset; + volatile u32 c_offset; +}; + +struct win0_par { + u32 refcount; + u32 pseudo_pal[16]; + u32 y_offset; + u32 c_offset; + u32 xpos; //size in panel + u32 ypos; + u32 xsize; //start point in panel + u32 ysize; + enum data_format format; + + wait_queue_head_t wait; + struct win_set mirror; + struct win_set displ; + struct win_set done; + + u8 par_seted; + u8 addr_seted; +}; + +#endif + + From 9eb18c287ee528ad4d20a69b0012996561df4afc Mon Sep 17 00:00:00 2001 From: zyc Date: Wed, 18 Jul 2012 15:36:30 +0800 Subject: [PATCH 029/261] init cif driver for rk2928,compatable with rk30. --- arch/arm/mach-rk2928/board-rk2928-fpga.c | 146 ++++++++++++++++ .../mach-rk2928/include/mach/rk2928_camera.h | 28 ++++ drivers/media/video/Makefile | 4 + drivers/media/video/rk2928_camera.c | 156 ++++++++++++++++++ drivers/media/video/rk30_camera_oneframe.c | 21 ++- 5 files changed, 350 insertions(+), 5 deletions(-) create mode 100644 arch/arm/mach-rk2928/include/mach/rk2928_camera.h create mode 100644 drivers/media/video/rk2928_camera.c diff --git a/arch/arm/mach-rk2928/board-rk2928-fpga.c b/arch/arm/mach-rk2928/board-rk2928-fpga.c index 8a38cd02a5ef..8b9a4c90df17 100755 --- a/arch/arm/mach-rk2928/board-rk2928-fpga.c +++ b/arch/arm/mach-rk2928/board-rk2928-fpga.c @@ -43,6 +43,152 @@ #include #include +#ifdef CONFIG_VIDEO_RK29 +/*---------------- Camera Sensor Macro Define Begin ------------------------*/ +/*---------------- Camera Sensor Configuration Macro Begin ------------------------*/ +#define CONFIG_SENSOR_0 RK29_CAM_SENSOR_OV5642 /* back camera sensor */ +#define CONFIG_SENSOR_IIC_ADDR_0 0x78 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_0 4 +#define CONFIG_SENSOR_CIF_INDEX_0 0 +#define CONFIG_SENSOR_ORIENTATION_0 90 +#define CONFIG_SENSOR_POWER_PIN_0 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_0 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_0 RK30_PIN1_PD6 +#define CONFIG_SENSOR_FALSH_PIN_0 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_0 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_0 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_0 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_0 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_0 30000 + +#define CONFIG_SENSOR_01 RK29_CAM_SENSOR_OV5642 /* back camera sensor 1 */ +#define CONFIG_SENSOR_IIC_ADDR_01 0x00 +#define CONFIG_SENSOR_CIF_INDEX_01 0 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_01 4 +#define CONFIG_SENSOR_ORIENTATION_01 90 +#define CONFIG_SENSOR_POWER_PIN_01 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_01 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_01 RK30_PIN1_PD6 +#define CONFIG_SENSOR_FALSH_PIN_01 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_01 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_01 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_01 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_01 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_01 30000 + +#define CONFIG_SENSOR_02 RK29_CAM_SENSOR_OV5640 /* back camera sensor 2 */ +#define CONFIG_SENSOR_IIC_ADDR_02 0x00 +#define CONFIG_SENSOR_CIF_INDEX_02 0 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_02 4 +#define CONFIG_SENSOR_ORIENTATION_02 90 +#define CONFIG_SENSOR_POWER_PIN_02 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_02 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_02 RK30_PIN1_PD6 +#define CONFIG_SENSOR_FALSH_PIN_02 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_02 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_02 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_02 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_02 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_02 30000 + +#define CONFIG_SENSOR_1 RK29_CAM_SENSOR_OV2659 /* front camera sensor 0 */ +#define CONFIG_SENSOR_IIC_ADDR_1 0x60 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_1 3 +#define CONFIG_SENSOR_CIF_INDEX_1 0 +#define CONFIG_SENSOR_ORIENTATION_1 270 +#define CONFIG_SENSOR_POWER_PIN_1 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_1 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_1 RK30_PIN1_PB7 +#define CONFIG_SENSOR_FALSH_PIN_1 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_1 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_1 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_1 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_1 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_1 30000 + +#define CONFIG_SENSOR_11 RK29_CAM_SENSOR_OV2659 /* front camera sensor 1 */ +#define CONFIG_SENSOR_IIC_ADDR_11 0x00 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_11 3 +#define CONFIG_SENSOR_CIF_INDEX_11 0 +#define CONFIG_SENSOR_ORIENTATION_11 270 +#define CONFIG_SENSOR_POWER_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_11 INVALID_GPIO//RK30_PIN1_PB7 +#define CONFIG_SENSOR_FALSH_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_11 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_11 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_11 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_11 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_11 30000 + +#define CONFIG_SENSOR_12 RK29_CAM_SENSOR_OV2659//RK29_CAM_SENSOR_OV2655 /* front camera sensor 2 */ +#define CONFIG_SENSOR_IIC_ADDR_12 0x00 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_12 3 +#define CONFIG_SENSOR_CIF_INDEX_12 0 +#define CONFIG_SENSOR_ORIENTATION_12 270 +#define CONFIG_SENSOR_POWER_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_12 INVALID_GPIO//RK30_PIN1_PB7 +#define CONFIG_SENSOR_FALSH_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_12 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_12 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_12 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_12 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_12 30000 + + +#endif //#ifdef CONFIG_VIDEO_RK29 +/*---------------- Camera Sensor Configuration Macro End------------------------*/ +#include "../../../drivers/media/video/rk2928_camera.c" +/*---------------- Camera Sensor Macro Define End ---------*/ #define RK2928_FB_MEM_SIZE 3*SZ_1M diff --git a/arch/arm/mach-rk2928/include/mach/rk2928_camera.h b/arch/arm/mach-rk2928/include/mach/rk2928_camera.h new file mode 100644 index 000000000000..95ab7aabd949 --- /dev/null +++ b/arch/arm/mach-rk2928/include/mach/rk2928_camera.h @@ -0,0 +1,28 @@ +/* camera driver header file + + Copyright (C) 2003, Intel Corporation + Copyright (C) 2008, Guennadi Liakhovetski + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#ifndef __ASM_ARCH_CAMERA_RK2928_H_ + +#define __ASM_ARCH_CAMERA_RK2928_H_ +#define RK29_CAM_DRV_NAME "rk-camera-rk2928" + +#include + +#endif + diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 46540d4a6542..c1dd9fb56bb0 100755 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -194,6 +194,10 @@ ifeq ($(CONFIG_ARCH_RK30),y) obj-$(CONFIG_VIDEO_RK29_WORK_ONEFRAME) += rk30_camera_oneframe.o obj-$(CONFIG_VIDEO_RK29_WORK_PINGPONG) += rk30_camera_pingpong.o endif +ifeq ($(CONFIG_ARCH_RK2928),y) +obj-$(CONFIG_VIDEO_RK29_WORK_ONEFRAME) += rk30_camera_oneframe.o +obj-$(CONFIG_VIDEO_RK29_WORK_PINGPONG) += rk30_camera_pingpong.o +endif ifeq ($(CONFIG_ARCH_RK29),y) obj-$(CONFIG_VIDEO_RK29_WORK_ONEFRAME) += rk29_camera_oneframe.o obj-$(CONFIG_VIDEO_RK29_WORK_PINGPONG) += rk29_camera_pingpong.o diff --git a/drivers/media/video/rk2928_camera.c b/drivers/media/video/rk2928_camera.c new file mode 100644 index 000000000000..4c6e923a2037 --- /dev/null +++ b/drivers/media/video/rk2928_camera.c @@ -0,0 +1,156 @@ + +#include +#include +#include +#include +#ifndef PMEM_CAM_SIZE +#include "../../../arch/arm/plat-rk/rk_camera.c" +#else +/***************************************************************************************** + * camera devices + * author: ddl@rock-chips.com + *****************************************************************************************/ +#ifdef CONFIG_VIDEO_RK29 + +static int rk_sensor_iomux(int pin) +{ + return 0; +} +#define PMEM_CAM_BASE 0 //just for compile ,no meaning +#include "../../../arch/arm/plat-rk/rk_camera.c" + + +static u64 rockchip_device_camera_dmamask = 0xffffffffUL; +static struct resource rk_camera_resource_host_0[] = { + [0] = { + .start = RK2928_CIF_PHYS, + .end = RK2928_CIF_PHYS + RK2928_CIF_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_CIF, + .end = IRQ_CIF, + .flags = IORESOURCE_IRQ, + } +}; +static struct resource rk_camera_resource_host_1[] = { + [0] = { + .start = RK2928_CIF_PHYS, + .end = RK2928_CIF_PHYS+ RK2928_CIF_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_CIF, + .end = IRQ_CIF, + .flags = IORESOURCE_IRQ, + } +}; +/*platform_device : */ + struct platform_device rk_device_camera_host_0 = { + .name = RK29_CAM_DRV_NAME, + .id = RK_CAM_PLATFORM_DEV_ID_0, /* This is used to put cameras on this interface */ + .num_resources = ARRAY_SIZE(rk_camera_resource_host_0), + .resource = rk_camera_resource_host_0, + .dev = { + .dma_mask = &rockchip_device_camera_dmamask, + .coherent_dma_mask = 0xffffffffUL, + .platform_data = &rk_camera_platform_data, + } +}; +/*platform_device : */ + struct platform_device rk_device_camera_host_1 = { + .name = RK29_CAM_DRV_NAME, + .id = RK_CAM_PLATFORM_DEV_ID_1, /* This is used to put cameras on this interface */ + .num_resources = ARRAY_SIZE(rk_camera_resource_host_1), + .resource = rk_camera_resource_host_1, + .dev = { + .dma_mask = &rockchip_device_camera_dmamask, + .coherent_dma_mask = 0xffffffffUL, + .platform_data = &rk_camera_platform_data, + } +}; + +static void rk_init_camera_plateform_data(void) +{ + int i,dev_idx; + + dev_idx = 0; + for (i=0; i #include #include @@ -38,9 +38,15 @@ #include #include #include +#ifdef CONFIG_ARCH_RK30 #include -#include -#include +#else +#include +#define RK30_CRU_BASE 0 +#endif +//#include +//#include + static int debug ; module_param(debug, int, S_IRUGO|S_IWUSR); @@ -1263,6 +1269,7 @@ static void rk_camera_setup_format(struct soc_camera_device *icd, __u32 host_pix } #if 1 { +#ifdef CONFIG_ARCH_RK30 mdelay(100); if(IS_CIF0()){ // pmu_set_idle_request(IDLE_REQ_VIO, true); @@ -1278,6 +1285,7 @@ static void rk_camera_setup_format(struct soc_camera_device *icd, __u32 host_pix cru_set_soft_reset(SOFT_RST_CIF1, false); // pmu_set_idle_request(IDLE_REQ_VIO, false); } +#endif } write_cif_reg(pcdev->base,CIF_CIF_CTRL,AXI_BURST_16|MODE_ONEFRAME|DISABLE_CAPTURE); /* ddl@rock-chips.com : vip ahb burst 16 */ write_cif_reg(pcdev->base,CIF_CIF_INTEN, 0x01|0x200); //capture complete interrupt enable @@ -2385,6 +2393,7 @@ static struct soc_camera_host_ops rk_soc_camera_host_ops = }; static void rk_camera_cif_iomux(int cif_index) { +#ifdef CONFIG_ARCH_RK30 switch(cif_index){ case 0: rk30_mux_api_set(GPIO1B3_CIF0CLKOUT_NAME, GPIO1B_CIF0_CLKOUT); @@ -2411,6 +2420,8 @@ static void rk_camera_cif_iomux(int cif_index) default: printk("cif index is erro!!!\n"); } +#else +#endif } @@ -2522,7 +2533,7 @@ static int rk_camera_probe(struct platform_device *pdev) } } -#ifdef CONFIG_VIDEO_RK29_WORK_IPP +//#ifdef CONFIG_VIDEO_RK29_WORK_IPP if(IS_CIF0()){ pcdev->camera_wq = create_workqueue("rk_cam_wkque_cif0"); } @@ -2531,7 +2542,7 @@ static int rk_camera_probe(struct platform_device *pdev) } if (pcdev->camera_wq == NULL) goto exit_free_irq; -#endif +//#endif pcdev->camera_reinit_work.pcdev = pcdev; INIT_WORK(&(pcdev->camera_reinit_work.work), rk_camera_reinit_work); From f5796180ff26e167ea8f395b2f4fbf3253e1b9aa Mon Sep 17 00:00:00 2001 From: yxj Date: Thu, 19 Jul 2012 12:26:52 +0800 Subject: [PATCH 030/261] rk31:add lcdc support --- arch/arm/configs/rk31_fpga_defconfig | 10 + arch/arm/mach-rk30/board-rk31-fpga.c | 109 +++ arch/arm/mach-rk30/devices.c | 8 +- drivers/video/rockchip/Kconfig | 28 +- drivers/video/rockchip/Makefile | 3 +- drivers/video/rockchip/chips/rk31_lcdc.c | 969 +++++++++++++++++++++++ drivers/video/rockchip/chips/rk31_lcdc.h | 543 +++++++++++++ 7 files changed, 1662 insertions(+), 8 deletions(-) create mode 100644 drivers/video/rockchip/chips/rk31_lcdc.c create mode 100644 drivers/video/rockchip/chips/rk31_lcdc.h diff --git a/arch/arm/configs/rk31_fpga_defconfig b/arch/arm/configs/rk31_fpga_defconfig index c58c4ba18355..7b739e2bbff1 100644 --- a/arch/arm/configs/rk31_fpga_defconfig +++ b/arch/arm/configs/rk31_fpga_defconfig @@ -75,6 +75,16 @@ CONFIG_SPI_FPGA_GPIO_NUM=0 CONFIG_SPI_FPGA_GPIO_IRQ_NUM=0 # CONFIG_HWMON is not set # CONFIG_MFD_SUPPORT is not set +CONFIG_FB=y +CONFIG_DISPLAY_SUPPORT=y +CONFIG_LCD_TD043MGEA1=y +CONFIG_FB_ROCKCHIP=y +CONFIG_LCDC_RK31=y +CONFIG_LCDC1_RK31=y +# CONFIG_THREE_FB_BUFFER is not set +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set # CONFIG_HID_SUPPORT is not set # CONFIG_USB_SUPPORT is not set CONFIG_RTC_CLASS=y diff --git a/arch/arm/mach-rk30/board-rk31-fpga.c b/arch/arm/mach-rk30/board-rk31-fpga.c index 4495e7ca3cd9..309d3eb274ee 100644 --- a/arch/arm/mach-rk30/board-rk31-fpga.c +++ b/arch/arm/mach-rk30/board-rk31-fpga.c @@ -43,6 +43,108 @@ #include #include + +#define RK_FB_MEM_SIZE 3*SZ_1M + +#if defined(CONFIG_FB_ROCKCHIP) +#define LCD_CS_MUX_NAME GPIO4C7_SMCDATA7_TRACEDATA7_NAME +#define LCD_CS_PIN RK30_PIN4_PC7 +#define LCD_CS_VALUE GPIO_HIGH + +#define LCD_EN_MUX_NAME GPIO4C7_SMCDATA7_TRACEDATA7_NAME +#define LCD_EN_PIN RK30_PIN6_PB4 +#define LCD_EN_VALUE GPIO_LOW + +static int rk_fb_io_init(struct rk29_fb_setting_info *fb_setting) +{ + int ret = 0; + rk30_mux_api_set(LCD_CS_MUX_NAME, GPIO4C_GPIO4C7); + ret = gpio_request(LCD_CS_PIN, NULL); + if (ret != 0) + { + gpio_free(LCD_CS_PIN); + printk(KERN_ERR "request lcd cs pin fail!\n"); + return -1; + } + else + { + gpio_direction_output(LCD_CS_PIN, LCD_CS_VALUE); + } + ret = gpio_request(LCD_EN_PIN, NULL); + if (ret != 0) + { + gpio_free(LCD_EN_PIN); + printk(KERN_ERR "request lcd en pin fail!\n"); + return -1; + } + else + { + gpio_direction_output(LCD_EN_PIN, LCD_EN_VALUE); + } + return 0; +} +static int rk_fb_io_disable(void) +{ + gpio_set_value(LCD_CS_PIN, LCD_CS_VALUE? 0:1); + gpio_set_value(LCD_EN_PIN, LCD_EN_VALUE? 0:1); + return 0; +} +static int rk_fb_io_enable(void) +{ + gpio_set_value(LCD_CS_PIN, LCD_CS_VALUE); + gpio_set_value(LCD_EN_PIN, LCD_EN_VALUE); + return 0; +} + +#if defined(CONFIG_LCDC0_RK31) +struct rk29fb_info lcdc0_screen_info = { + .prop = PRMRY, //primary display device + .io_init = rk_fb_io_init, + .io_disable = rk_fb_io_disable, + .io_enable = rk_fb_io_enable, + .set_screen_info = set_lcd_info, +}; +#endif + +#if defined(CONFIG_LCDC1_RK31) +struct rk29fb_info lcdc1_screen_info = { + #if defined(CONFIG_HDMI_RK30) + .prop = EXTEND, //extend display device + .lcd_info = NULL, + .set_screen_info = hdmi_init_lcdc, + #endif +}; +#endif + +static struct resource resource_fb[] = { + [0] = { + .name = "fb0 buf", + .start = 0, + .end = 0,//RK30_FB0_MEM_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "ipp buf", //for rotate + .start = 0, + .end = 0,//RK30_FB0_MEM_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [2] = { + .name = "fb2 buf", + .start = 0, + .end = 0,//RK30_FB0_MEM_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device device_fb = { + .name = "rk-fb", + .id = -1, + .num_resources = ARRAY_SIZE(resource_fb), + .resource = resource_fb, +}; +#endif + //i2c #ifdef CONFIG_I2C0_RK30 static struct i2c_board_info __initdata i2c0_info[] = { @@ -90,6 +192,9 @@ static struct spi_board_info board_spi_devices[] = { }; static struct platform_device *devices[] __initdata = { +#if defined(CONFIG_FB_ROCKCHIP) + &device_fb, +#endif }; static void __init rk31_board_init(void) @@ -101,6 +206,10 @@ static void __init rk31_board_init(void) static void __init rk31_reserve(void) { +#if defined(CONFIG_FB_ROCKCHIP) + resource_fb[0].start = board_mem_reserve_add("fb0", RK_FB_MEM_SIZE); + resource_fb[0].end = resource_fb[0].start + RK_FB_MEM_SIZE - 1; +#endif board_mem_reserved(); } diff --git a/arch/arm/mach-rk30/devices.c b/arch/arm/mach-rk30/devices.c index 6330b292ce1f..07c6e675ea54 100755 --- a/arch/arm/mach-rk30/devices.c +++ b/arch/arm/mach-rk30/devices.c @@ -749,7 +749,7 @@ static struct platform_device device_nand = { }; #endif -#ifdef CONFIG_LCDC0_RK30 +#if defined(CONFIG_LCDC0_RK30) || defined(CONFIG_LCDC0_RK31) extern struct rk29fb_info lcdc0_screen_info; static struct resource resource_lcdc0[] = { [0] = { @@ -777,7 +777,7 @@ static struct platform_device device_lcdc0 = { }, }; #endif -#ifdef CONFIG_LCDC1_RK30 +#if defined(CONFIG_LCDC1_RK30) || defined(CONFIG_LCDC1_RK31) extern struct rk29fb_info lcdc1_screen_info; static struct resource resource_lcdc1[] = { [0] = { @@ -1151,10 +1151,10 @@ static int __init rk30_init_devices(void) platform_device_register(&device_rga); #endif platform_device_register(&device_ipp); -#ifdef CONFIG_LCDC0_RK30 +#if defined(CONFIG_LCDC0_RK30) || defined(CONFIG_LCDC0_RK31) platform_device_register(&device_lcdc0); #endif -#ifdef CONFIG_LCDC1_RK30 +#if defined(CONFIG_LCDC1_RK30) || defined(CONFIG_LCDC1_RK31) platform_device_register(&device_lcdc1); #endif #ifdef CONFIG_HDMI_RK30 diff --git a/drivers/video/rockchip/Kconfig b/drivers/video/rockchip/Kconfig index c6b81ec773f4..04ba7263c5ac 100755 --- a/drivers/video/rockchip/Kconfig +++ b/drivers/video/rockchip/Kconfig @@ -14,6 +14,12 @@ config FB_WIMO help Support wimo +config LCDC_RK2928 + tristate "rk2928 lcdc support " + depends on FB_ROCKCHIP + help + Driver for rk2928 lcdc . + config LCDC_RK30 tristate "rk30 lcdc support " depends on FB_ROCKCHIP @@ -33,11 +39,27 @@ config LCDC1_RK30 default y if HDMI_RK30 help Support rk30 lcdc1 if you say y here -config LCDC_RK2928 - tristate "rk2928 lcdc support " + +config LCDC_RK31 + tristate "rk31 lcdc support " depends on FB_ROCKCHIP help - Driver for rk2928 lcdc . + Driver for rk31 lcdc .There are two lcdc controllers on RK31 + +config LCDC0_RK31 + bool "lcdc0 support" + depends on LCDC_RK31 + default y + help + Support rk31 lcdc0 if you say y here + +config LCDC1_RK31 + bool "lcdc1 support" + depends on LCDC_RK31 + default y if HDMI_RK31 + help + Support rk31 lcdc1 if you say y here + config DUAL_DISP_IN_KERNEL bool "implement dual display in kernel" depends on FB_ROCKCHIP diff --git a/drivers/video/rockchip/Makefile b/drivers/video/rockchip/Makefile index d5a4aed8c623..ed778bb77b99 100755 --- a/drivers/video/rockchip/Makefile +++ b/drivers/video/rockchip/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_FB_ROCKCHIP) += rk_fb.o rkfb_sysfs.o obj-$(CONFIG_FB_WIMO) +=wimo.o obj-$(CONFIG_LCDC_RK30) += chips/rk30_lcdc.o -obj-$(CONFIG_LCDC_RK2928) += chips/rk2928_lcdc.o +obj-$(CONFIG_LCDC_RK2928) += chips/rk2928_lcdc.o +obj-$(CONFIG_LCDC_RK31) += chips/rk31_lcdc.o obj-$(CONFIG_RGA_RK30) += rga/ obj-$(CONFIG_HDMI_RK30) += hdmi/ diff --git a/drivers/video/rockchip/chips/rk31_lcdc.c b/drivers/video/rockchip/chips/rk31_lcdc.c new file mode 100644 index 000000000000..be14760bb886 --- /dev/null +++ b/drivers/video/rockchip/chips/rk31_lcdc.c @@ -0,0 +1,969 @@ +/* + * drivers/video/rockchip/chips/rk31_lcdc.c + * + * Copyright (C) 2012 ROCKCHIP, Inc. + *Author:yzq + * yxj + *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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rk31_lcdc.h" + + + + + + +static int dbg_thresd = 0; +module_param(dbg_thresd, int, S_IRUGO|S_IWUSR); +#define DBG(level,x...) do { if(unlikely(dbg_thresd > level)) printk(KERN_INFO x); } while (0) + + +static int init_rk31_lcdc(struct rk_lcdc_device_driver *dev_drv) +{ + struct rk31_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk31_lcdc_device,driver); + if(lcdc_dev->id == 0) //lcdc0 + { + lcdc_dev->pd = clk_get(NULL,"pd_lcdc0"); + lcdc_dev->hclk = clk_get(NULL,"hclk_lcdc0"); + lcdc_dev->aclk = clk_get(NULL,"aclk_lcdc0"); + lcdc_dev->dclk = clk_get(NULL,"dclk_lcdc0"); + } + else if(lcdc_dev->id == 1) + { + lcdc_dev->pd = clk_get(NULL,"pd_lcdc1"); + lcdc_dev->hclk = clk_get(NULL,"hclk_lcdc1"); + lcdc_dev->aclk = clk_get(NULL,"aclk_lcdc1"); + lcdc_dev->dclk = clk_get(NULL,"dclk_lcdc1"); + } + else + { + printk(KERN_ERR "invalid lcdc device!\n"); + return -EINVAL; + } + if (IS_ERR(lcdc_dev->pd) || (IS_ERR(lcdc_dev->aclk)) ||(IS_ERR(lcdc_dev->dclk)) || (IS_ERR(lcdc_dev->hclk))) + { + printk(KERN_ERR "failed to get lcdc%d clk source\n",lcdc_dev->id); + } + clk_enable(lcdc_dev->pd); + clk_enable(lcdc_dev->hclk); //enable aclk and hclk for register config + clk_enable(lcdc_dev->aclk); + lcdc_dev->clk_on = 1; + + LcdMskReg(lcdc_dev,SYS_CFG, m_LCDC_AXICLK_AUTO_ENABLE | m_W0_AXI_OUTSTANDING2 | + m_W1_AXI_OUTSTANDING2,v_LCDC_AXICLK_AUTO_ENABLE(1) | v_W0_AXI_OUTSTANDING2(1) | + v_W1_AXI_OUTSTANDING2(1));//eanble axi-clk auto gating for low power + LcdMskReg(lcdc_dev, INT_STATUS,m_HOR_STARTMASK| m_FRM_STARTMASK | + m_SCANNING_MASK, v_HOR_STARTMASK(1) | v_FRM_STARTMASK(1) | + v_SCANNING_MASK(1)); //mask all interrupt in init + LcdMskReg(lcdc_dev,FIFO_WATER_MARK,m_WIN1_FIFO_FULL_LEVEL,v_WIN1_FIFO_FULL_LEVEL(0x1e0)); + LCDC_REG_CFG_DONE(); // write any value to REG_CFG_DONE let config become effective + return 0; +} + +static int rk31_lcdc_deinit(struct rk31_lcdc_device *lcdc_dev) +{ + spin_lock(&lcdc_dev->reg_lock); + if(likely(lcdc_dev->clk_on)) + { + lcdc_dev->clk_on = 0; + LcdMskReg(lcdc_dev, INT_STATUS, m_FRM_STARTCLEAR, v_FRM_STARTCLEAR(1)); + LcdMskReg(lcdc_dev, INT_STATUS,m_HOR_STARTMASK| m_FRM_STARTMASK | + m_SCANNING_MASK, v_HOR_STARTMASK(1) | v_FRM_STARTMASK(1) | + v_SCANNING_MASK(1)); //mask all interrupt in init + LcdSetBit(lcdc_dev,SYS_CFG,m_LCDC_STANDBY); + LCDC_REG_CFG_DONE(); + spin_unlock(&lcdc_dev->reg_lock); + } + else //clk already disabled + { + spin_unlock(&lcdc_dev->reg_lock); + return 0; + } + mdelay(1); + + return 0; +} + +static int rk31_load_screen(struct rk_lcdc_device_driver *dev_drv, bool initscreen) +{ + int ret = -EINVAL; + struct rk31_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk31_lcdc_device,driver); + rk_screen *screen = lcdc_dev->screen; + u64 ft; + int fps; + u16 face; + u16 mcu_total, mcu_rwstart, mcu_csstart, mcu_rwend, mcu_csend; + u16 right_margin = screen->right_margin; + u16 lower_margin = screen->lower_margin; + u16 x_res = screen->x_res, y_res = screen->y_res; + + // set the rgb or mcu + spin_lock(&lcdc_dev->reg_lock); + if(likely(lcdc_dev->clk_on)) + { + if(screen->type==SCREEN_MCU) + { + LcdMskReg(lcdc_dev, MCU_CTRL, m_MCU_OUTPUT_SELECT,v_MCU_OUTPUT_SELECT(1)); + // set out format and mcu timing + mcu_total = (screen->mcu_wrperiod*150*1000)/1000000; + if(mcu_total>31) + mcu_total = 31; + if(mcu_total<3) + mcu_total = 3; + mcu_rwstart = (mcu_total+1)/4 - 1; + mcu_rwend = ((mcu_total+1)*3)/4 - 1; + mcu_csstart = (mcu_rwstart>2) ? (mcu_rwstart-3) : (0); + mcu_csend = (mcu_rwend>15) ? (mcu_rwend-1) : (mcu_rwend); + + //DBG(1,">> mcu_total=%d, mcu_rwstart=%d, mcu_csstart=%d, mcu_rwend=%d, mcu_csend=%d \n", + // mcu_total, mcu_rwstart, mcu_csstart, mcu_rwend, mcu_csend); + + // set horizontal & vertical out timing + + right_margin = x_res/6; + screen->pixclock = 150000000; //mcu fix to 150 MHz + LcdMskReg(lcdc_dev, MCU_CTRL,m_MCU_CS_ST | m_MCU_CS_END| m_MCU_RW_ST | m_MCU_RW_END | + m_MCU_WRITE_PERIOD | m_MCU_HOLDMODE_SELECT | m_MCU_HOLDMODE_FRAME_ST, + v_MCU_CS_ST(mcu_csstart) | v_MCU_CS_END(mcu_csend) | v_MCU_RW_ST(mcu_rwstart) | + v_MCU_RW_END(mcu_rwend) | v_MCU_WRITE_PERIOD(mcu_total) | + v_MCU_HOLDMODE_SELECT((SCREEN_MCU==screen->type)?(1):(0)) | v_MCU_HOLDMODE_FRAME_ST(0)); + + } + + switch (screen->face) + { + case OUT_P565: + face = OUT_P565; + LcdMskReg(lcdc_dev, DSP_CTRL0, m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE, v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(0)); + break; + case OUT_P666: + face = OUT_P666; + LcdMskReg(lcdc_dev, DSP_CTRL0, m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE, v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(1)); + break; + case OUT_D888_P565: + face = OUT_P888; + LcdMskReg(lcdc_dev, DSP_CTRL0, m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE, v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(0)); + break; + case OUT_D888_P666: + face = OUT_P888; + LcdMskReg(lcdc_dev, DSP_CTRL0, m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE, v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(1)); + break; + case OUT_P888: + face = OUT_P888; + LcdMskReg(lcdc_dev, DSP_CTRL0, m_DITHER_UP_EN, v_DITHER_UP_EN(1)); + LcdMskReg(lcdc_dev, DSP_CTRL0, m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE, v_DITHER_DOWN_EN(0) | v_DITHER_DOWN_MODE(0)); + break; + default: + LcdMskReg(lcdc_dev, DSP_CTRL0, m_DITHER_UP_EN, v_DITHER_UP_EN(0)); + LcdMskReg(lcdc_dev, DSP_CTRL0, m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE, v_DITHER_DOWN_EN(0) | v_DITHER_DOWN_MODE(0)); + face = screen->face; + break; + } + + //use default overlay,set vsyn hsync den dclk polarity + LcdMskReg(lcdc_dev, DSP_CTRL0,m_DISPLAY_FORMAT | m_HSYNC_POLARITY | m_VSYNC_POLARITY | + m_DEN_POLARITY |m_DCLK_POLARITY,v_DISPLAY_FORMAT(face) | + v_HSYNC_POLARITY(screen->pin_hsync) | v_VSYNC_POLARITY(screen->pin_vsync) | + v_DEN_POLARITY(screen->pin_den) | v_DCLK_POLARITY(screen->pin_dclk)); + + //set background color to black,set swap according to the screen panel,disable blank mode + LcdMskReg(lcdc_dev, DSP_CTRL1, m_BG_COLOR | m_OUTPUT_RB_SWAP | m_OUTPUT_RG_SWAP | m_DELTA_SWAP | + m_DUMMY_SWAP | m_BLANK_MODE,v_BG_COLOR(0x000000) | v_OUTPUT_RB_SWAP(screen->swap_rb) | + v_OUTPUT_RG_SWAP(screen->swap_rg) | v_DELTA_SWAP(screen->swap_delta) | v_DUMMY_SWAP(screen->swap_dumy) | + v_BLACK_MODE(0)); + + + LcdWrReg(lcdc_dev, DSP_HTOTAL_HS_END,v_HSYNC(screen->hsync_len) | + v_HORPRD(screen->hsync_len + screen->left_margin + x_res + right_margin)); + LcdWrReg(lcdc_dev, DSP_HACT_ST_END, v_HAEP(screen->hsync_len + screen->left_margin + x_res) | + v_HASP(screen->hsync_len + screen->left_margin)); + + LcdWrReg(lcdc_dev, DSP_VTOTAL_VS_END, v_VSYNC(screen->vsync_len) | + v_VERPRD(screen->vsync_len + screen->upper_margin + y_res + lower_margin)); + LcdWrReg(lcdc_dev, DSP_VACT_ST_END, v_VAEP(screen->vsync_len + screen->upper_margin+y_res)| + v_VASP(screen->vsync_len + screen->upper_margin)); + // let above to take effect + LCDC_REG_CFG_DONE(); + } + spin_unlock(&lcdc_dev->reg_lock); + + ret = clk_set_rate(lcdc_dev->dclk, screen->pixclock); + if(ret) + { + printk(KERN_ERR ">>>>>> set lcdc%d dclk failed\n",lcdc_dev->id); + } + lcdc_dev->driver.pixclock = lcdc_dev->pixclock = div_u64(1000000000000llu, clk_get_rate(lcdc_dev->dclk)); + clk_enable(lcdc_dev->dclk); + + ft = (u64)(screen->upper_margin + screen->lower_margin + screen->y_res +screen->vsync_len)* + (screen->left_margin + screen->right_margin + screen->x_res + screen->hsync_len)* + (dev_drv->pixclock); // one frame time ,(pico seconds) + fps = div64_u64(1000000000000llu,ft); + screen->ft = 1000/fps; + printk("%s: dclk:%lu>>fps:%d ",lcdc_dev->driver.name,clk_get_rate(lcdc_dev->dclk),fps); + + if(screen->init) + { + screen->init(); + } + + printk("%s for lcdc%d ok!\n",__func__,lcdc_dev->id); + return 0; +} + +static int mcu_refresh(struct rk31_lcdc_device *lcdc_dev) +{ + + return 0; +} + + + +//enable layer,open:1,enable;0 disable +static int win0_open(struct rk31_lcdc_device *lcdc_dev,bool open) +{ + + spin_lock(&lcdc_dev->reg_lock); + if(likely(lcdc_dev->clk_on)) + { + if(open) + { + if(!lcdc_dev->atv_layer_cnt) + { + LcdMskReg(lcdc_dev, SYS_CFG,m_LCDC_STANDBY,v_LCDC_STANDBY(0)); + } + lcdc_dev->atv_layer_cnt++; + } + else + { + lcdc_dev->atv_layer_cnt--; + } + lcdc_dev->driver.layer_par[0]->state = open; + + LcdMskReg(lcdc_dev, SYS_CFG, m_W0_EN, v_W0_EN(open)); + if(!lcdc_dev->atv_layer_cnt) //if no layer used,disable lcdc + { + LcdMskReg(lcdc_dev, SYS_CFG,m_LCDC_STANDBY,v_LCDC_STANDBY(1)); + } + LCDC_REG_CFG_DONE(); + } + spin_unlock(&lcdc_dev->reg_lock); + printk(KERN_INFO "lcdc%d win0 %s\n",lcdc_dev->id,open?"open":"closed"); + return 0; +} +static int win1_open(struct rk31_lcdc_device *lcdc_dev,bool open) +{ + spin_lock(&lcdc_dev->reg_lock); + if(likely(lcdc_dev->clk_on)) + { + if(open) + { + if(!lcdc_dev->atv_layer_cnt) + { + printk("lcdc%d wakeup from stanby\n",lcdc_dev->id); + LcdMskReg(lcdc_dev, SYS_CFG,m_LCDC_STANDBY,v_LCDC_STANDBY(0)); + } + lcdc_dev->atv_layer_cnt++; + } + else + { + lcdc_dev->atv_layer_cnt--; + } + lcdc_dev->driver.layer_par[1]->state = open; + + LcdMskReg(lcdc_dev, SYS_CFG, m_W1_EN, v_W1_EN(open)); + if(!lcdc_dev->atv_layer_cnt) //if no layer used,disable lcdc + { + printk(KERN_INFO "no layer of lcdc%d is used,go to standby!",lcdc_dev->id); + LcdMskReg(lcdc_dev, SYS_CFG,m_LCDC_STANDBY,v_LCDC_STANDBY(1)); + } + LCDC_REG_CFG_DONE(); + } + spin_unlock(&lcdc_dev->reg_lock); + printk(KERN_INFO "lcdc%d win1 %s\n",lcdc_dev->id,open?"open":"closed"); + return 0; +} + + +static int rk31_lcdc_blank(struct rk_lcdc_device_driver*lcdc_drv,int layer_id,int blank_mode) +{ + struct rk31_lcdc_device * lcdc_dev = container_of(lcdc_drv,struct rk31_lcdc_device ,driver); + + printk(KERN_INFO "%s>>>>>%d\n",__func__, blank_mode); + + spin_lock(&lcdc_dev->reg_lock); + if(likely(lcdc_dev->clk_on)) + { + switch(blank_mode) + { + case FB_BLANK_UNBLANK: + LcdMskReg(lcdc_dev,DSP_CTRL1,m_BLANK_MODE ,v_BLANK_MODE(0)); + break; + case FB_BLANK_NORMAL: + LcdMskReg(lcdc_dev,DSP_CTRL1,m_BLANK_MODE ,v_BLANK_MODE(1)); + break; + default: + LcdMskReg(lcdc_dev,DSP_CTRL1,m_BLANK_MODE ,v_BLANK_MODE(1)); + break; + } + LCDC_REG_CFG_DONE(); + } + spin_unlock(&lcdc_dev->reg_lock); + + return 0; +} + +static int win0_display(struct rk31_lcdc_device *lcdc_dev,struct layer_par *par ) +{ + u32 y_addr; + u32 uv_addr; + y_addr = par->smem_start + par->y_offset; + uv_addr = par->cbr_start + par->c_offset; + DBG(2,KERN_INFO "lcdc%d>>%s:y_addr:0x%x>>uv_addr:0x%x\n",lcdc_dev->id,__func__,y_addr,uv_addr); + + spin_lock(&lcdc_dev->reg_lock); + if(likely(lcdc_dev->clk_on)) + { + LcdWrReg(lcdc_dev, WIN0_YRGB_MST,y_addr); + LcdWrReg(lcdc_dev, WIN0_CBR_MST,uv_addr); + LCDC_REG_CFG_DONE(); + } + spin_unlock(&lcdc_dev->reg_lock); + + return 0; + +} + +static int win1_display(struct rk31_lcdc_device *lcdc_dev,struct layer_par *par ) +{ + u32 y_addr; + u32 uv_addr; + y_addr = par->smem_start + par->y_offset; + uv_addr = par->cbr_start + par->c_offset; + DBG(2,KERN_INFO "lcdc%d>>%s>>y_addr:0x%x>>uv_addr:0x%x\n",lcdc_dev->id,__func__,y_addr,uv_addr); + + spin_lock(&lcdc_dev->reg_lock); + if(likely(lcdc_dev->clk_on)) + { + LcdWrReg(lcdc_dev, WIN1_YRGB_MST, y_addr); + LCDC_REG_CFG_DONE(); + } + spin_unlock(&lcdc_dev->reg_lock); + + return 0; +} + +static int win0_set_par(struct rk31_lcdc_device *lcdc_dev,rk_screen *screen, + struct layer_par *par ) +{ + u32 xact, yact, xvir, yvir, xpos, ypos; + u32 ScaleYrgbX = 0x1000; + u32 ScaleYrgbY = 0x1000; + u32 ScaleCbrX = 0x1000; + u32 ScaleCbrY = 0x1000; + + xact = par->xact; //active (origin) picture window width/height + yact = par->yact; + xvir = par->xvir; // virtual resolution + yvir = par->yvir; + xpos = par->xpos+screen->left_margin + screen->hsync_len; + ypos = par->ypos+screen->upper_margin + screen->vsync_len; + + + ScaleYrgbX = CalScale(xact, par->xsize); //both RGB and yuv need this two factor + ScaleYrgbY = CalScale(yact, par->ysize); + switch (par->format) + { + case YUV422:// yuv422 + ScaleCbrX = CalScale((xact/2), par->xsize); + ScaleCbrY = CalScale(yact, par->ysize); + break; + case YUV420: // yuv420 + ScaleCbrX = CalScale(xact/2, par->xsize); + ScaleCbrY = CalScale(yact/2, par->ysize); + break; + case YUV444:// yuv444 + ScaleCbrX = CalScale(xact, par->xsize); + ScaleCbrY = CalScale(yact, par->ysize); + break; + default: + break; + } + + DBG(1,"%s for lcdc%d>>format:%d>>>xact:%d>>yact:%d>>xsize:%d>>ysize:%d>>xvir:%d>>yvir:%d>>xpos:%d>>ypos:%d>>\n", + __func__,lcdc_dev->id,par->format,xact,yact,par->xsize,par->ysize,xvir,yvir,xpos,ypos); + + spin_lock(&lcdc_dev->reg_lock); + if(likely(lcdc_dev->clk_on)) + { + LcdWrReg(lcdc_dev, WIN0_SCL_FACTOR_YRGB, v_X_SCL_FACTOR(ScaleYrgbX) | v_Y_SCL_FACTOR(ScaleYrgbY)); + LcdWrReg(lcdc_dev, WIN0_SCL_FACTOR_CBR,v_X_SCL_FACTOR(ScaleCbrX)| v_Y_SCL_FACTOR(ScaleCbrY)); + LcdMskReg(lcdc_dev,SYS_CFG, m_W0_FORMAT, v_W0_FORMAT(par->format - 1)); //(inf->video_mode==0) + LcdWrReg(lcdc_dev, WIN0_ACT_INFO,v_ACT_WIDTH(xact) | v_ACT_HEIGHT(yact)); + LcdWrReg(lcdc_dev, WIN0_DSP_ST, v_DSP_STX(xpos) | v_DSP_STY(ypos)); + LcdWrReg(lcdc_dev, WIN0_DSP_INFO, v_DSP_WIDTH(par->xsize)| v_DSP_HEIGHT(par->ysize)); + LcdMskReg(lcdc_dev, WIN0_COLOR_KEY_CTRL, m_COLORKEY_EN | m_KEYCOLOR, + v_COLORKEY_EN(0) | v_KEYCOLOR(0)); + LcdWrReg(lcdc_dev,WIN0_VIR,v_VIRWIDTH(xvir)); + LCDC_REG_CFG_DONE(); + } + spin_unlock(&lcdc_dev->reg_lock); + + return 0; + +} + +static int win1_set_par(struct rk31_lcdc_device *lcdc_dev,rk_screen *screen, + struct layer_par *par ) +{ + u32 xact, yact, xvir, yvir, xpos, ypos; + u32 ScaleYrgbX = 0x1000; + u32 ScaleYrgbY = 0x1000; + u32 ScaleCbrX = 0x1000; + u32 ScaleCbrY = 0x1000; + + xact = par->xact; + yact = par->yact; + xvir = par->xvir; + yvir = par->yvir; + xpos = par->xpos+screen->left_margin + screen->hsync_len; + ypos = par->ypos+screen->upper_margin + screen->vsync_len; + + ScaleYrgbX = CalScale(xact, par->xsize); + ScaleYrgbY = CalScale(yact, par->ysize); + DBG(1,"%s for lcdc%d>>format:%d>>>xact:%d>>yact:%d>>xsize:%d>>ysize:%d>>xvir:%d>>yvir:%d>>xpos:%d>>ypos:%d>>\n", + __func__,lcdc_dev->id,par->format,xact,yact,par->xsize,par->ysize,xvir,yvir,xpos,ypos); + + + spin_lock(&lcdc_dev->reg_lock); + if(likely(lcdc_dev->clk_on)) + { + switch (par->format) + { + case YUV422:// yuv422 + ScaleCbrX = CalScale((xact/2), par->xsize); + ScaleCbrY = CalScale(yact, par->ysize); + break; + case YUV420: // yuv420 + ScaleCbrX = CalScale(xact/2, par->xsize); + ScaleCbrY = CalScale(yact/2, par->ysize); + break; + case YUV444:// yuv444 + ScaleCbrX = CalScale(xact, par->xsize); + ScaleCbrY = CalScale(yact, par->ysize); + break; + default: + break; + } + + LcdMskReg(lcdc_dev,SYS_CFG, m_W1_FORMAT, v_W1_FORMAT(par->format - 1)); + LcdWrReg(lcdc_dev, WIN1_DSP_ST,v_DSP_STX(xpos) | v_DSP_STY(ypos)); + LcdWrReg(lcdc_dev, WIN1_DSP_INFO,v_DSP_WIDTH(par->xsize) | v_DSP_HEIGHT(par->ysize)); + // enable win1 color key and set the color to black(rgb=0) + LcdMskReg(lcdc_dev,WIN1_COLOR_KEY_CTRL, m_COLORKEY_EN | m_KEYCOLOR,v_COLORKEY_EN(0) | v_KEYCOLOR(0)); + LcdWrReg(lcdc_dev,WIN1_VIR,v_VIRWIDTH(xvir)); + + LCDC_REG_CFG_DONE(); + } + spin_unlock(&lcdc_dev->reg_lock); + return 0; +} + +static int rk31_lcdc_open(struct rk_lcdc_device_driver *dev_drv,int layer_id,bool open) +{ + struct rk31_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk31_lcdc_device,driver); + if(layer_id == 0) + { + win0_open(lcdc_dev,open); + } + else if(layer_id == 1) + { + win1_open(lcdc_dev,open); + } + + return 0; +} + +static int rk31_lcdc_set_par(struct rk_lcdc_device_driver *dev_drv,int layer_id) +{ + struct rk31_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk31_lcdc_device,driver); + struct layer_par *par = NULL; + rk_screen *screen = lcdc_dev->screen; + if(!screen) + { + printk(KERN_ERR "screen is null!\n"); + return -ENOENT; + } + if(layer_id==0) + { + par = dev_drv->layer_par[0]; + win0_set_par(lcdc_dev,screen,par); + } + else if(layer_id==1) + { + par = dev_drv->layer_par[1]; + win1_set_par(lcdc_dev,screen,par); + } + + return 0; +} + +int rk31_lcdc_pan_display(struct rk_lcdc_device_driver * dev_drv,int layer_id) +{ + struct rk31_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk31_lcdc_device,driver); + struct layer_par *par = NULL; + rk_screen *screen = lcdc_dev->screen; + unsigned long flags; + int timeout; + if(!screen) + { + printk(KERN_ERR "screen is null!\n"); + return -ENOENT; + } + if(layer_id==0) + { + par = dev_drv->layer_par[0]; + win0_display(lcdc_dev,par); + } + else if(layer_id==1) + { + par = dev_drv->layer_par[1]; + win1_display(lcdc_dev,par); + } + if((dev_drv->first_frame)) //this is the first frame of the system ,enable frame start interrupt + { + dev_drv->first_frame = 0; + LcdMskReg(lcdc_dev,INT_STATUS,m_FRM_STARTCLEAR | m_FRM_STARTMASK , + v_FRM_STARTCLEAR(1) | v_FRM_STARTMASK(0)); + LCDC_REG_CFG_DONE(); // write any value to REG_CFG_DONE let config become effective + + } + + if(dev_drv->num_buf < 3) //3buffer ,no need to wait for sysn + { + spin_lock_irqsave(&dev_drv->cpl_lock,flags); + init_completion(&dev_drv->frame_done); + spin_unlock_irqrestore(&dev_drv->cpl_lock,flags); + timeout = wait_for_completion_timeout(&dev_drv->frame_done,msecs_to_jiffies(dev_drv->screen->ft+5)); + if(!timeout&&(!dev_drv->frame_done.done)) + { + printk(KERN_ERR "wait for new frame start time out!\n"); + return -ETIMEDOUT; + } + } + + return 0; +} + +int rk31_lcdc_ioctl(struct rk_lcdc_device_driver * dev_drv,unsigned int cmd, unsigned long arg,int layer_id) +{ + struct rk31_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk31_lcdc_device,driver); + u32 panel_size[2]; + void __user *argp = (void __user *)arg; + int ret = 0; + switch(cmd) + { + case FBIOGET_PANEL_SIZE: //get panel size + panel_size[0] = lcdc_dev->screen->x_res; + panel_size[1] = lcdc_dev->screen->y_res; + if(copy_to_user(argp, panel_size, 8)) + return -EFAULT; + break; + default: + break; + } + + return ret; +} +static int rk31_lcdc_get_layer_state(struct rk_lcdc_device_driver *dev_drv,int layer_id) +{ + struct rk31_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk31_lcdc_device,driver); + struct layer_par *par = dev_drv->layer_par[layer_id]; + + spin_lock(&lcdc_dev->reg_lock); + if(lcdc_dev->clk_on) + { + if(layer_id == 0) + { + par->state = LcdReadBit(lcdc_dev,SYS_CFG,m_W0_EN); + } + else if( layer_id == 1) + { + par->state = LcdReadBit(lcdc_dev,SYS_CFG,m_W1_EN); + } + } + spin_unlock(&lcdc_dev->reg_lock); + + return par->state; + +} + +/*********************************** +overlay manager +swap:1 win0 on the top of win1 + 0 win1 on the top of win0 +set : 1 set overlay + 0 get overlay state +************************************/ +static int rk31_lcdc_ovl_mgr(struct rk_lcdc_device_driver *dev_drv,int swap,bool set) +{ + struct rk31_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk31_lcdc_device,driver); + int ovl; + spin_lock(&lcdc_dev->reg_lock); + if(lcdc_dev->clk_on) + { + if(set) //set overlay + { + LcdMskReg(lcdc_dev,DSP_CTRL0,m_W0W1_POSITION_SWAP,v_W0W1_POSITION_SWAP(swap)); + LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); + LCDC_REG_CFG_DONE(); + ovl = swap; + } + else //get overlay + { + ovl = LcdReadBit(lcdc_dev,DSP_CTRL0,m_W0W1_POSITION_SWAP); + } + } + else + { + ovl = -EPERM; + } + spin_unlock(&lcdc_dev->reg_lock); + + return ovl; +} +static int rk31_lcdc_get_disp_info(struct rk_lcdc_device_driver *dev_drv,int layer_id) +{ + struct rk31_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk31_lcdc_device,driver); + return 0; +} + + +/******************************************* +lcdc fps manager,set or get lcdc fps +set:0 get + 1 set +********************************************/ +static int rk31_lcdc_fps_mgr(struct rk_lcdc_device_driver *dev_drv,int fps,bool set) +{ + struct rk31_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk31_lcdc_device,driver); + rk_screen * screen = dev_drv->screen; + u64 ft = 0; + u32 dotclk; + int ret; + + if(set) + { + ft = div_u64(1000000000000llu,fps); + dev_drv->pixclock = div_u64(ft,(screen->upper_margin + screen->lower_margin + screen->y_res +screen->vsync_len)* + (screen->left_margin + screen->right_margin + screen->x_res + screen->hsync_len)); + dotclk = div_u64(1000000000000llu,dev_drv->pixclock); + ret = clk_set_rate(lcdc_dev->dclk, dotclk); + if(ret) + { + printk(KERN_ERR ">>>>>> set lcdc%d dclk failed\n",lcdc_dev->id); + } + dev_drv->pixclock = lcdc_dev->pixclock = div_u64(1000000000000llu, clk_get_rate(lcdc_dev->dclk)); + + } + + ft = (u64)(screen->upper_margin + screen->lower_margin + screen->y_res +screen->vsync_len)* + (screen->left_margin + screen->right_margin + screen->x_res + screen->hsync_len)* + (dev_drv->pixclock); // one frame time ,(pico seconds) + fps = div64_u64(1000000000000llu,ft); + screen->ft = 1000/fps ; //one frame time in ms + return fps; +} +int rk31_lcdc_early_suspend(struct rk_lcdc_device_driver *dev_drv) +{ + struct rk31_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk31_lcdc_device,driver); + + spin_lock(&lcdc_dev->reg_lock); + if(likely(lcdc_dev->clk_on)) + { + lcdc_dev->clk_on = 0; + LcdMskReg(lcdc_dev, INT_STATUS, m_FRM_STARTCLEAR, v_FRM_STARTCLEAR(1)); + LcdMskReg(lcdc_dev, SYS_CFG,m_LCDC_STANDBY,v_LCDC_STANDBY(1)); + LCDC_REG_CFG_DONE(); + spin_unlock(&lcdc_dev->reg_lock); + } + else //clk already disabled + { + spin_unlock(&lcdc_dev->reg_lock); + return 0; + } + + + mdelay(1); + clk_disable(lcdc_dev->dclk); + clk_disable(lcdc_dev->hclk); + clk_disable(lcdc_dev->aclk); + clk_disable(lcdc_dev->pd); + + return 0; +} + + +int rk31_lcdc_early_resume(struct rk_lcdc_device_driver *dev_drv) +{ + struct rk31_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk31_lcdc_device,driver); + + if(!lcdc_dev->clk_on) + { + clk_enable(lcdc_dev->pd); + clk_enable(lcdc_dev->hclk); + clk_enable(lcdc_dev->dclk); + clk_enable(lcdc_dev->aclk); + } + memcpy((u8*)lcdc_dev->preg, (u8*)&lcdc_dev->regbak, 0xc4); //resume reg + + spin_lock(&lcdc_dev->reg_lock); + if(lcdc_dev->atv_layer_cnt) + { + LcdMskReg(lcdc_dev, SYS_CFG,m_LCDC_STANDBY,v_LCDC_STANDBY(0)); + LCDC_REG_CFG_DONE(); + } + lcdc_dev->clk_on = 1; + spin_unlock(&lcdc_dev->reg_lock); + + return 0; +} +static irqreturn_t rk31_lcdc_isr(int irq, void *dev_id) +{ + struct rk31_lcdc_device *lcdc_dev = (struct rk31_lcdc_device *)dev_id; + + LcdMskReg(lcdc_dev, INT_STATUS, m_FRM_STARTCLEAR, v_FRM_STARTCLEAR(1)); + LCDC_REG_CFG_DONE(); + //LcdMskReg(lcdc_dev, INT_STATUS, m_LINE_FLAG_INT_CLEAR, v_LINE_FLAG_INT_CLEAR(1)); + + if(lcdc_dev->driver.num_buf < 3) //three buffer ,no need to wait for sync + { + spin_lock(&(lcdc_dev->driver.cpl_lock)); + complete(&(lcdc_dev->driver.frame_done)); + spin_unlock(&(lcdc_dev->driver.cpl_lock)); + } + return IRQ_HANDLED; +} + +static struct layer_par lcdc_layer[] = { + [0] = { + .name = "win0", + .id = 0, + .support_3d = true, + }, + [1] = { + .name = "win1", + .id = 1, + .support_3d = false, + }, +}; + +static struct rk_lcdc_device_driver lcdc_driver = { + .name = "lcdc", + .def_layer_par = lcdc_layer, + .num_layer = ARRAY_SIZE(lcdc_layer), + .open = rk31_lcdc_open, + .init_lcdc = init_rk31_lcdc, + .ioctl = rk31_lcdc_ioctl, + .suspend = rk31_lcdc_early_suspend, + .resume = rk31_lcdc_early_resume, + .set_par = rk31_lcdc_set_par, + .blank = rk31_lcdc_blank, + .pan_display = rk31_lcdc_pan_display, + .load_screen = rk31_load_screen, + .get_layer_state = rk31_lcdc_get_layer_state, + .ovl_mgr = rk31_lcdc_ovl_mgr, + .get_disp_info = rk31_lcdc_get_disp_info, + .fps_mgr = rk31_lcdc_fps_mgr, +}; +#ifdef CONFIG_PM +static int rk31_lcdc_suspend(struct platform_device *pdev, pm_message_t state) +{ + return 0; +} + +static int rk31_lcdc_resume(struct platform_device *pdev) +{ + return 0; +} + +#else +#define rk31_lcdc_suspend NULL +#define rk31_lcdc_resume NULL +#endif + +static int __devinit rk31_lcdc_probe (struct platform_device *pdev) +{ + struct rk31_lcdc_device *lcdc_dev=NULL; + rk_screen *screen; + struct rk29fb_info *screen_ctr_info; + struct resource *res = NULL; + struct resource *mem; + int ret = 0; + + /*************Malloc rk31lcdc_inf and set it to pdev for drvdata**********/ + lcdc_dev = kzalloc(sizeof(struct rk31_lcdc_device), GFP_KERNEL); + if(!lcdc_dev) + { + dev_err(&pdev->dev, ">>rk31 lcdc device kmalloc fail!"); + return -ENOMEM; + } + platform_set_drvdata(pdev, lcdc_dev); + lcdc_dev->id = pdev->id; + screen_ctr_info = (struct rk29fb_info * )pdev->dev.platform_data; + screen = kzalloc(sizeof(rk_screen), GFP_KERNEL); + if(!screen) + { + dev_err(&pdev->dev, ">>rk31 lcdc screen kmalloc fail!"); + ret = -ENOMEM; + goto err0; + } + else + { + lcdc_dev->screen = screen; + } + /****************get lcdc0 reg *************************/ + res = platform_get_resource(pdev, IORESOURCE_MEM,0); + if (res == NULL) + { + dev_err(&pdev->dev, "failed to get io resource for lcdc%d \n",lcdc_dev->id); + ret = -ENOENT; + goto err1; + } + lcdc_dev->reg_phy_base = res->start; + lcdc_dev->len = resource_size(res); + mem = request_mem_region(lcdc_dev->reg_phy_base, resource_size(res), pdev->name); + if (mem == NULL) + { + dev_err(&pdev->dev, "failed to request mem region for lcdc%d\n",lcdc_dev->id); + ret = -ENOENT; + goto err1; + } + lcdc_dev->reg_vir_base = ioremap(lcdc_dev->reg_phy_base, resource_size(res)); + if (lcdc_dev->reg_vir_base == NULL) + { + dev_err(&pdev->dev, "cannot map IO\n"); + ret = -ENXIO; + goto err2; + } + + lcdc_dev->preg = (LCDC_REG*)lcdc_dev->reg_vir_base; + printk("lcdc%d:reg_phy_base = 0x%08x,reg_vir_base:0x%p\n",pdev->id,lcdc_dev->reg_phy_base, lcdc_dev->preg); + lcdc_dev->driver.dev=&pdev->dev; + lcdc_dev->driver.screen = screen; + lcdc_dev->driver.screen_ctr_info = screen_ctr_info; + spin_lock_init(&lcdc_dev->reg_lock); + lcdc_dev->irq = platform_get_irq(pdev, 0); + if(lcdc_dev->irq < 0) + { + dev_err(&pdev->dev, "cannot find IRQ\n"); + goto err3; + } + ret = request_irq(lcdc_dev->irq, rk31_lcdc_isr, IRQF_DISABLED,dev_name(&pdev->dev),lcdc_dev); + if (ret) + { + dev_err(&pdev->dev, "cannot requeset irq %d - err %d\n", lcdc_dev->irq, ret); + ret = -EBUSY; + goto err3; + } + ret = rk_fb_register(&(lcdc_dev->driver),&lcdc_driver,lcdc_dev->id); + if(ret < 0) + { + printk(KERN_ERR "register fb for lcdc%d failed!\n",lcdc_dev->id); + goto err4; + } + printk("rk31 lcdc%d probe ok!\n",lcdc_dev->id); + + return 0; + +err4: + free_irq(lcdc_dev->irq,lcdc_dev); +err3: + iounmap(lcdc_dev->reg_vir_base); +err2: + release_mem_region(lcdc_dev->reg_phy_base,resource_size(res)); +err1: + kfree(screen); +err0: + platform_set_drvdata(pdev, NULL); + kfree(lcdc_dev); + return ret; + +} +static int __devexit rk31_lcdc_remove(struct platform_device *pdev) +{ + struct rk31_lcdc_device *lcdc_dev = platform_get_drvdata(pdev); + rk_fb_unregister(&(lcdc_dev->driver)); + rk31_lcdc_deinit(lcdc_dev); + iounmap(lcdc_dev->reg_vir_base); + release_mem_region(lcdc_dev->reg_phy_base,lcdc_dev->len); + kfree(lcdc_dev->screen); + kfree(lcdc_dev); + return 0; +} + +static void rk31_lcdc_shutdown(struct platform_device *pdev) +{ + struct rk31_lcdc_device *lcdc_dev = platform_get_drvdata(pdev); + rk_fb_unregister(&(lcdc_dev->driver)); + rk31_lcdc_deinit(lcdc_dev); + /*iounmap(lcdc_dev->reg_vir_base); + release_mem_region(lcdc_dev->reg_phy_base,lcdc_dev->len); + kfree(lcdc_dev->screen); + kfree(lcdc_dev);*/ +} + + +static struct platform_driver rk31_lcdc_driver = { + .probe = rk31_lcdc_probe, + .remove = __devexit_p(rk31_lcdc_remove), + .driver = { + .name = "rk30-lcdc", + .owner = THIS_MODULE, + }, + .suspend = rk31_lcdc_suspend, + .resume = rk31_lcdc_resume, + .shutdown = rk31_lcdc_shutdown, +}; + +static int __init rk31_lcdc_init(void) +{ + return platform_driver_register(&rk31_lcdc_driver); +} + +static void __exit rk31_lcdc_exit(void) +{ + platform_driver_unregister(&rk31_lcdc_driver); +} + + + +fs_initcall(rk31_lcdc_init); +module_exit(rk31_lcdc_exit); + + + diff --git a/drivers/video/rockchip/chips/rk31_lcdc.h b/drivers/video/rockchip/chips/rk31_lcdc.h new file mode 100644 index 000000000000..25c6044d8688 --- /dev/null +++ b/drivers/video/rockchip/chips/rk31_lcdc.h @@ -0,0 +1,543 @@ +/* drivers/video/rockchip/chips/rk29_fb.h + * + * Copyright (C) 2010 ROCKCHIP, Inc. + * + * 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. + * + */ + +#ifndef __RK31_LCDC_H +#define __RK31_LCDC_H + +#include + +#define LcdReadBit(inf, addr, msk) ((inf->regbak.addr=inf->preg->addr)&(msk)) +#define LcdWrReg(inf, addr, val) inf->preg->addr=inf->regbak.addr=(val) +#define LcdRdReg(inf, addr) (inf->preg->addr) +#define LcdSetBit(inf, addr, msk) inf->preg->addr=((inf->regbak.addr) |= (msk)) +#define LcdClrBit(inf, addr, msk) inf->preg->addr=((inf->regbak.addr) &= ~(msk)) +#define LcdSetRegBit(inf, addr, msk) inf->preg->addr=((inf->preg->addr) |= (msk)) +#define LcdMskReg(inf, addr, msk, val) (inf->regbak.addr)&=~(msk); inf->preg->addr=(inf->regbak.addr|=(val)) +#define LCDC_REG_CFG_DONE() LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); dsb() + + +/******************************************************************** +** 宏定义 * +********************************************************************/ +/* SYS_CONFIG */ +#define m_W2_FORMAT (3<<0) +#define m_W1_FORMAT (1<<2) +#define m_W0_FORMAT (7<<3) +#define m_W0_CBR_DEFLICK_EN (1<<6) +#define m_W0_YRGB_DEFLICK_EN (1<<7) +#define m_INTERIACE_EN (1<<8) +#define m_W2_EN (1<<9) +#define m_W1_EN (1<<10) +#define m_W0_EN (1<<11) +#define m_HWC_EN (1<<12) +#define m_HWC_RELOAD_EN (1<<13) +#define m_W2_INTERLACE_READ (1<<14) +#define m_W1_INTERLACE_READ (1<<15) +#define m_W0_INTERLACE_READ (1<<16) +#define m_LCDC_STANDBY (1<<17) +#define m_HWC_BURST (3<<18) +#define m_W2_BURST (3<<20) +#define m_W1_BURST (3<<22) +#define m_W0_BURST (3<<24) +#define m_W2_LUT_CTL (1<<26) +#define m_DSIP_LUT_CTL (1<<27) +#define m_HWC_REVERSED_COLOR (1<<28) +#define m_W1_AXI_OUTSTANDING2 (1<<29) +#define m_W0_AXI_OUTSTANDING2 (1<<30) +#define m_LCDC_AXICLK_AUTO_ENABLE (1<<31) + +#define v_W2_FORMAT(x) (((x)&3)<<0) +#define v_W1_FORMAT(x) (((x)&1)<<2) +#define v_W0_FORMAT(x) (((x)&7)<<3) +#define v_W0_CBR_DEFLICK_EN(x) (((x)&1)<<6) +#define v_W0_YRGB_DEFLICK_EN(x) (((x)&1)<<7) +#define v_INTERIACE_EN(x) (((x)&1)<<8) +#define v_W2_EN(x) (((x)&)1<<9) +#define v_W1_EN(x) (((x)&1)<<10) +#define v_W0_EN(x) (((x)&1)<<11) +#define v_HWC_EN(x) (((x)&1)<<12) +#define v_HWC_RELOAD_EN(x) (((x)&1)<<13) +#define v_W2_INTERLACE_READ(x) (((x)&1)<<14) +#define v_W1_INTERLACE_READ(x) (((x)&1)<<15) +#define v_W0_INTERLACE_READ(x) (((x)&1)<<16) +#define v_LCDC_STANDBY(x) (((x)&1)<<17) +#define v_HWC_BURST(x) (((x)&3)<<18) +#define v_W2_BURST(x) (((x)&3)<<20) +#define v_W1_BURST(x) (((x)&3)<<22) +#define v_W0_BURST(x) (((x)&3)<<24) +#define v_W2_LUT_CTL(x) (((x)&1)<<26) +#define v_DSIP_LUT_CTL(x) (((x)&1)<<27) +#define v_HWC_REVERSED_COLOR(x) (((x)&1)<<28) +#define v_W1_AXI_OUTSTANDING2(x) (((x)&1)<<29) +#define v_W0_AXI_OUTSTANDING2(x) (((x)&1)<<30) +#define v_LCDC_AXICLK_AUTO_ENABLE(x) (((x)&1)<<31) + +//LCDC_SWAP_CTRL +#define m_W1_565_RB_SWAP (1<<0) +#define m_W0_565_RB_SWAP (1<<1) +#define m_W0_YRGB_M8_SWAP (1<<2) +#define m_W0_YRGB_R_SHIFT_SWAP (1<<3) +#define m_W0_CBR_R_SHIFT_SWAP (1<<4) +#define m_W0_YRGB_16_SWAP (1<<5) +#define m_W0_YRGB_8_SWAP (1<<6) +#define m_W0_CBR_16_SWAP (1<<7) +#define m_W0_CBR_8_SWAP (1<<8) +#define m_W1_16_SWAP (1<<9) +#define m_W1_8_SWAP (1<<10) +#define m_W1_R_SHIFT_SWAP (1<<11) +#define m_OUTPUT_BG_SWAP (1<<12) +#define m_OUTPUT_RB_SWAP (1<<13) +#define m_OUTPUT_RG_SWAP (1<<14) +#define m_DELTA_SWAP (1<<15) +#define m_DUMMY_SWAP (1<<16) +#define m_W2_BYTE_SWAP (1<<17) +#define v_W1_565_RB_SWAP(x) (((x)&1)<<0) +#define v_W0_565_RB_SWAP(x) (((x)&1)<<1) +#define v_W0_YRGB_M8_SWAP(x) (((x)&1)<<2) +#define v_W0_YRGB_R_SHIFT_SWAP(x) (((x)&1)<<3) +#define v_W0_CBR_R_SHIFT_SWAP(x) (((x)&1)<<4) +#define v_W0_YRGB_16_SWAP(x) (((x)&1)<<5) +#define v_W0_YRGB_8_SWAP(x) (((x)&1)<<6) +#define v_W0_CBR_16_SWAP(x) (((x)&1)<<7) +#define v_W0_CBR_8_SWAP(x) (((x)&1)<<8) +#define v_W1_16_SWAP(x) (((x)&1)<<9) +#define v_W1_8_SWAP(x) (((x)&1)<<10) +#define v_W1_R_SHIFT_SWAP(x) (((x)&1)<<11) +#define v_OUTPUT_BG_SWAP(x) (((x)&1)<<12) +#define v_OUTPUT_RB_SWAP(x) (((x)&1)<<13) +#define v_OUTPUT_RG_SWAP(x) (((x)&1)<<14) +#define v_DELTA_SWAP(x) (((x)&1)<<15) +#define v_DUMMY_SWAP(x) (((x)&1)<<16) +#define v_W2_BYTE_SWAP(x) (((x)&1)<<17) + +//LCDC_MCU_TIMING_CTRL +#define m_MCU_WRITE_PERIOD (31<<0) +#define m_MCU_CS_ST (31<<5) +#define m_MCU_CS_END (31<<10) +#define m_MCU_RW_ST (31<<15) +#define m_MCU_RW_END (31<<20) +#define m_MCU_HOLDMODE_SELECT (1<<27) +#define m_MCU_HOLDMODE_FRAME_ST (1<<28) +#define m_MCU_RS_SELECT (1<<29) +#define m_MCU_BYPASSMODE_SELECT (1<<30) +#define m_MCU_OUTPUT_SELECT (1<<31) +#define v_MCU_WRITE_PERIOD(x) (((x)&31)<<0) +#define v_MCU_CS_ST(x) (((x)&31)<<5) +#define v_MCU_CS_END(x) (((x)&31)<<10) +#define v_MCU_RW_ST(x) (((x)&31)<<15) +#define v_MCU_RW_END(x) (((x)&31)<<20) +#define v_MCU_HOLD_STATUS(x) (((x)&1)<<26) +#define v_MCU_HOLDMODE_SELECT(x) (((x)&1)<<27) +#define v_MCU_HOLDMODE_FRAME_ST(x) (((x)&1)<<28) +#define v_MCU_RS_SELECT(x) (((x)&1)<<29) +#define v_MCU_BYPASSMODE_SELECT(x) (((x)&1)<<30) +#define v_MCU_OUTPUT_SELECT(x) (((x)&1)<<31) + +//LCDC_ BLEND_CTRL +#define m_HWC_BLEND_EN (1<<0) +#define m_W2_BLEND_EN (1<<1) +#define m_W1_BLEND_EN (1<<2) +#define m_W0_BLEND_EN (1<<3) +#define m_HWC_BLEND_FACTOR (15<<4) +#define m_W2_BLEND_FACTOR (0xff<<8) +#define m_W1_BLEND_FACTOR (0xff<<16) +#define m_W0_BLEND_FACTOR (0xff<<24) + +#define v_HWC_BLEND_EN(x) (((x)&1)<<0) +#define v_W2_BLEND_EN(x) (((x)&1)<<1) +#define v_W1_BLEND_EN(x) (((x)&1)<<2) +#define v_W0_BLEND_EN(x) (((x)&1)<<3) +#define v_HWC_BLEND_FACTOR(x) (((x)&15)<<4) +#define v_W2_BLEND_FACTOR(x) (((x)&0xff)<<8) +#define v_W1_BLEND_FACTOR(x) (((x)&0xff)<<16) +#define v_W0_BLEND_FACTOR(x) (((x)&0xff)<<24) + + +//LCDC_WIN0_COLOR_KEY_CTRL / LCDC_WIN1_COLOR_KEY_CTRL +#define m_KEYCOLOR (0xffffff<<0) +#define m_KEYCOLOR_B (0xff<<0) +#define m_KEYCOLOR_G (0xff<<8) +#define m_KEYCOLOR_R (0xff<<16) +#define m_COLORKEY_EN (1<<24) +#define v_KEYCOLOR(x) (((x)&0xffffff)<<0) +#define v_KEYCOLOR_B(x) (((x)&0xff)<<0) +#define v_KEYCOLOR_G(x) (((x)&0xff)<<8) +#define v_KEYCOLOR_R(x) (((x)&0xff)<<16) +#define v_COLORKEY_EN(x) (((x)&1)<<24) + +//LCDC_DEFLICKER_SCL_OFFSET +#define m_W0_YRGB_VSD_OFFSET (0xff<<0) +#define m_W0_YRGB_VSP_OFFSET (0xff<<8) +#define m_W1_VSD_OFFSET (0xff<<16) +#define m_W1_VSP_OFFSET (0xff<<24) +#define v_W0_YRGB_VSD_OFFSET(x) (((x)&0xff)<<0) +#define v_W0_YRGB_VSP_OFFSET(x) (((x)&0xff)<<8) +#define v_W1_VSD_OFFSET(x) (((x)&0xff)<<16) +#define v_W1_VSP_OFFSET(x) (((x)&0xff)<<24) + +//LCDC_DSP_CTRL_REG0 +#define m_DISPLAY_FORMAT (0xf<<0) +#define m_HSYNC_POLARITY (1<<4) +#define m_VSYNC_POLARITY (1<<5) +#define m_DEN_POLARITY (1<<6) +#define m_DCLK_POLARITY (1<<7) +#define m_COLOR_SPACE_CONVERSION (3<<8) +#define m_DITHER_UP_EN (1<<10) +#define m_DITHER_DOWN_MODE (1<<11) +#define m_DITHER_DOWN_EN (1<<12) +#define m_INTERLACE_FIELD_POLARITY (1<<13) +#define m_YUV_CLIP (1<<14) +#define m_W1_TRANSP_FROM (1<<15) +#define m_W0_TRANSP_FROM (1<<16) +#define m_W0W1_POSITION_SWAP (1<<17) +#define m_W1_CLIP_EN (1<<18) +#define m_W0_CLIP_EN (1<<19) +#define m_W0_YCBR_PRIORITY_MODE (1<<20) +#define m_CBR_FILTER_656 (1<<21) +#define m_W2_CHIP_EN (1<<22) + +#define v_DISPLAY_FORMAT(x) (((x)&0xf)<<0) +#define v_HSYNC_POLARITY(x) (((x)&1)<<4) +#define v_VSYNC_POLARITY(x) (((x)&1)<<5) +#define v_DEN_POLARITY(x) (((x)&1)<<6) +#define v_DCLK_POLARITY(x) (((x)&1)<<7) +#define v_COLOR_SPACE_CONVERSION(x) (((x)&3)<<8) +#define v_DITHER_UP_EN(x) (((x)&1)<<10) +#define v_DITHER_DOWN_MODE(x) (((x)&1)<<11) +#define v_DITHER_DOWN_EN(x) (((x)&1)<<12) +#define v_INTERLACE_FIELD_POLARITY(x) (((x)&1)<<13) +#define v_YUV_CLIP(x) (((x)&1)<<14) +#define v_W1_TRANSP_FROM(x) (((x)&1)<<15) +#define v_W0_TRANSP_FROM(x) (((x)&1)<<16) +#define v_W0W1_POSITION_SWAP(x) (((x)&1)<<17) +#define v_W1_CLIP_EN(x) (((x)&1)<<18) +#define v_W0_CLIP_EN(x) (((x)&1)<<19) +#define v_W0_YCBR_PRIORITY_MODE(x) (((x)&1)<<20) +#define v_CBR_FILTER_656(x) (((x)&1)<<21) +#define v_W2_CHIP_EN(x) (((x)&1)<<22) + + +//LCDC_DSP_CTRL_REG1 +#define m_BG_COLOR (0xffffff<<0) +#define m_BG_B (0xff<<0) +#define m_BG_G (0xff<<8) +#define m_BG_R (0xff<<16) +#define m_BLANK_MODE (1<<24) +#define m_BLACK_MODE (1<<25) +#define m_DISP_FILTER_FACTOR (3<<26) +#define m_DISP_FILTER_MODE (1<<28) +#define m_DISP_FILTER_EN (1<<29) +#define v_BG_COLOR(x) (((x)&0xffffff)<<0) +#define v_BG_B(x) (((x)&0xff)<<0) +#define v_BG_G(x) (((x)&0xff)<<8) +#define v_BG_R(x) (((x)&0xff)<<16) +#define v_BLANK_MODE(x) (((x)&1)<<24) +#define v_BLACK_MODE(x) (((x)&1)<<25) +#define v_DISP_FILTER_FACTOR(x) (((x)&3)<<26) +#define v_DISP_FILTER_MODE(x) (((x)&1)<<28) +#define v_DISP_FILTER_EN(x) (((x)&1)<<29) + +//LCDC_INT_STATUS +#define m_HOR_START (1<<0) +#define m_FRM_START (1<<1) +#define m_SCANNING_FLAG (1<<2) +#define m_HOR_STARTMASK (1<<3) +#define m_FRM_STARTMASK (1<<4) +#define m_SCANNING_MASK (1<<5) +#define m_HOR_STARTCLEAR (1<<6) +#define m_FRM_STARTCLEAR (1<<7) +#define m_SCANNING_CLEAR (1<<8) +#define m_SCAN_LINE_NUM (0x7ff<<9) +#define v_HOR_START(x) (((x)&1)<<0) +#define v_FRM_START(x) (((x)&1)<<1) +#define v_SCANNING_FLAG(x) (((x)&1)<<2) +#define v_HOR_STARTMASK(x) (((x)&1)<<3) +#define v_FRM_STARTMASK(x) (((x)&1)<<4) +#define v_SCANNING_MASK(x) (((x)&1)<<5) +#define v_HOR_STARTCLEAR(x) (((x)&1)<<6) +#define v_FRM_STARTCLEAR(x) (((x)&1)<<7) +#define v_SCANNING_CLEAR(x) (((x)&1)<<8) +#define v_SCAN_LINE_NUM(x) (((x)&0x7ff)<<9) + +//AXI MS ID +#define m_W0_YRGB_CH_ID (0xF<<0) +#define m_W0_CBR_CH_ID (0xF<<4) +#define m_W1_YRGB_CH_ID (0xF<<8) +#define m_W2_CH_ID (0xF<<12) +#define m_HWC_CH_ID (0xF<<16) +#define v_W0_YRGB_CH_ID(x) (((x)&0xF)<<0) +#define v_W0_CBR_CH_ID(x) (((x)&0xF)<<4) +#define v_W1_YRGB_CH_ID(x) (((x)&0xF)<<8) +#define v_W2_CH_ID(x) (((x)&0xF)<<12) +#define v_HWC_CH_ID(x) (((x)&0xF)<<16) + + +/* Low Bits Mask */ +#define m_WORDLO (0xffff<<0) +#define m_WORDHI (0xffff<<16) +#define v_WORDLO(x) (((x)&0xffff)<<0) +#define v_WORDHI(x) (((x)&0xffff)<<16) + +#define m_BIT11LO (0x7ff<<0) +#define m_BIT11HI (0x7ff<<16) +#define v_BIT11LO(x) (((x)&0x7ff)<<0) +#define v_BIT11HI(x) (((x)&0x7ff)<<16) + +#define m_BIT12LO (0xfff<<0) +#define m_BIT12HI (0xfff<<16) +#define v_BIT12LO(x) (((x)&0xfff)<<0) +#define v_BIT12HI(x) (((x)&0xfff)<<16) + + +#define m_VIRWIDTH (0xffff<<0) +#define m_VIRHEIGHT (0xffff<<16) +#define v_VIRWIDTH(x) (((x)&0xffff)<<0) +#define v_VIRHEIGHT(x) (((x)&0xffff)<<16) + +#define m_ACTWIDTH (0xffff<<0) +#define m_ACTHEIGHT (0xffff<<16) +#define v_ACTWIDTH(x) (((x)&0xffff)<<0) +#define v_ACTHEIGHT(x) (((x)&0xffff)<<16) + +#define m_VIRST_X (0xffff<<0) +#define m_VIRST_Y (0xffff<<16) +#define v_VIRST_X(x) (((x)&0xffff)<<0) +#define v_VIRST_Y(x) (((x)&0xffff)<<16) + +#define m_PANELST_X (0x3ff<<0) +#define m_PANELST_Y (0x3ff<<16) +#define v_PANELST_X(x) (((x)&0x3ff)<<0) +#define v_PANELST_Y(x) (((x)&0x3ff)<<16) + +#define m_PANELWIDTH (0x3ff<<0) +#define m_PANELHEIGHT (0x3ff<<16) +#define v_PANELWIDTH(x) (((x)&0x3ff)<<0) +#define v_PANELHEIGHT(x) (((x)&0x3ff)<<16) + +#define m_HWC_B (0xff<<0) +#define m_HWC_G (0xff<<8) +#define m_HWC_R (0xff<<16) +#define m_W0_YRGB_HSP_OFFSET (0xff<<24) +#define m_W0_YRGB_HSD_OFFSET (0xff<<24) +#define v_HWC_B(x) (((x)&0xff)<<0) +#define v_HWC_G(x) (((x)&0xff)<<8) +#define v_HWC_R(x) (((x)&0xff)<<16) +#define v_W0_YRGB_HSP_OFFSET(x) (((x)&0xff)<<24) +#define v_W0_YRGB_HSD_OFFSET(x) (((x)&0xff)<<24) + + +//Panel display scanning +#define m_PANEL_HSYNC_WIDTH (0x3ff<<0) +#define m_PANEL_HORIZONTAL_PERIOD (0x3ff<<16) +#define v_PANEL_HSYNC_WIDTH(x) (((x)&0x3ff)<<0) +#define v_PANEL_HORIZONTAL_PERIOD(x) (((x)&0x3ff)<<16) + +#define m_PANEL_END (0x3ff<<0) +#define m_PANEL_START (0x3ff<<16) +#define v_PANEL_END(x) (((x)&0x3ff)<<0) +#define v_PANEL_START(x) (((x)&0x3ff)<<16) + +#define m_PANEL_VSYNC_WIDTH (0x3ff<<0) +#define m_PANEL_VERTICAL_PERIOD (0x3ff<<16) +#define v_PANEL_VSYNC_WIDTH(x) (((x)&0x3ff)<<0) +#define v_PANEL_VERTICAL_PERIOD(x) (((x)&0x3ff)<<16) +//----------- + +#define m_HSCALE_FACTOR (0xffff<<0) +#define m_VSCALE_FACTOR (0xffff<<16) +#define v_HSCALE_FACTOR(x) (((x)&0xffff)<<0) +#define v_VSCALE_FACTOR(x) (((x)&0xffff)<<16) + +#define m_W0_CBR_HSD_OFFSET (0xff<<0) +#define m_W0_CBR_HSP_OFFSET (0xff<<8) +#define m_W0_CBR_VSD_OFFSET (0xff<<16) +#define m_W0_CBR_VSP_OFFSET (0xff<<24) +#define v_W0_CBR_HSD_OFFSET(x) (((x)&0xff)<<0) +#define v_W0_CBR_HSP_OFFSET(x) (((x)&0xff)<<8) +#define v_W0_CBR_VSD_OFFSET(x) (((x)&0xff)<<16) +#define v_W0_CBR_VSP_OFFSET(x) (((x)&0xff)<<24) + + +#define m_WIN1_FIFO_FULL_LEVEL (0x7f << 0) +#define m_WIN2_FIFO_FULL_LEVEL (0x1f << 7) +#define v_WIN1_FIFO_FULL_LEVEL(x) (((x)&0x7f) << 0) +#define v_WIN2_FIFO_FULL_LEVEL(x) (((x)&0x1f) << 7) + + + +//LCDC_WINx_SCL_FACTOR_Y/CBCR +#define v_X_SCL_FACTOR(x) ((x)<<0) +#define v_Y_SCL_FACTOR(x) ((x)<<16) + +//LCDC_DSP_HTOTAL_HS_END +#define v_HSYNC(x) ((x)<<0) //hsync pulse width +#define v_HORPRD(x) ((x)<<16) //horizontal period + + +//LCDC_DSP_HACT_ST_END +#define v_HAEP(x) ((x)<<0) //horizontal active end point +#define v_HASP(x) ((x)<<16) //horizontal active start point + +//LCDC_DSP_VTOTAL_VS_END +#define v_VSYNC(x) ((x)<<0) +#define v_VERPRD(x) ((x)<<16) + +//LCDC_DSP_VACT_ST_END +#define v_VAEP(x) ((x)<<0) +#define v_VASP(x) ((x)<<16) + +//LCDC_WIN0_ACT_INFO +#define v_ACT_WIDTH(x) ((x)<<0) +#define v_ACT_HEIGHT(x) ((x)<<16) + +//LCDC_WIN0_DSP_INFO +#define v_DSP_WIDTH(x) ((x)<<0) +#define v_DSP_HEIGHT(x) ((x)<<16) + +//LCDC_WIN0_DSP_ST //x,y start point of the panel scanning +#define v_DSP_STX(x) (x<<0) +#define v_DSP_STY(x) (x<<16) + + +/******************************************************************** +** 结构定义 * +********************************************************************/ +/* LCDC的寄存器结构 */ + +typedef volatile struct tagLCDC_REG +{ + /* offset 0x00~0xc0 */ + unsigned int SYS_CFG; //0x00 SYSTEM configure register + unsigned int SWAP_CTRL; //0x04 Data SWAP control + unsigned int MCU_CTRL; //0x08 MCU TIMING control register + unsigned int BLEND_CTRL; //0x0c Blending control register + unsigned int WIN0_COLOR_KEY_CTRL; //0x10 Win0 blending control register + unsigned int WIN1_COLOR_KEY_CTRL; //0x14 Win1 blending control register + unsigned int WIN2_VIR; //0x18 WIN2 virtual display width + unsigned int DSP_CTRL0; //0x1c Display control register0 + unsigned int DSP_CTRL1; //0x20 Display control register1 + unsigned int INT_STATUS; //0x24 Interrupt status register + unsigned int WIN0_VIR; //0x28 WIN0 virtual display width/height + unsigned int WIN0_YRGB_MST; //0x2c Win0 active YRGB memory start address + unsigned int WIN0_CBR_MST; //0x30 Win0 active Cbr memory start address + unsigned int WIN0_ACT_INFO; //0x34 Win0 active window width/height + unsigned int WIN0_DSP_ST; //0x38 Win0 display start point on panel + unsigned int WIN0_DSP_INFO; //0x3c Win0 display width/height on panel + unsigned int WIN1_VIR; //0x40 Win1 virtual display width/height + unsigned int WIN1_YRGB_MST; //0x44 Win1 active memory start address + unsigned int WIN1_DSP_INFO; //0x48 Win1 display width/height on panel + unsigned int WIN1_DSP_ST; //0x4c Win1 display start point on panel + unsigned int WIN2_MST; //0X50 Win2 memory start address + unsigned int WIN2_DSP_INFO; //0x54 Win1 display width/height on panel + unsigned int WIN2_DSP_ST; //0x58 Win1 display start point on panel + unsigned int HWC_MST; //0x5C HWC memory start address + unsigned int HWC_DSP_ST; //0x60 HWC display start point on panel + unsigned int HWC_COLOR_LUT0; //0x64 Hardware cursor color 2’b01 look up table 0 + unsigned int HWC_COLOR_LUT1; //0x68 Hardware cursor color 2’b10 look up table 1 + unsigned int HWC_COLOR_LUT2; //0x6c Hardware cursor color 2’b11 look up table 2 + unsigned int DSP_HTOTAL_HS_END; //0x70 Panel scanning horizontal width and hsync pulse end point + unsigned int DSP_HACT_ST_END; //0x74 Panel active horizontal scanning start/end point + unsigned int DSP_VTOTAL_VS_END; //0x78 Panel scanning vertical height and vsync pulse end point + unsigned int DSP_VACT_ST_END; //0x7c Panel active vertical scanning start/end point + unsigned int DSP_VS_ST_END_F1; //0x80 Vertical scanning start point and vsync pulse end point of even filed in interlace mode + unsigned int DSP_VACT_ST_END_F1; //0x84 Vertical scanning active start/end point of even filed in interlace mode + unsigned int WIN0_SCL_FACTOR_YRGB; //0x88 Win0 YRGB scaling down factor setting + unsigned int WIN0_SCL_FACTOR_CBR; //0x8c Win0 YRGB scaling up factor setting + unsigned int WIN0_SCL_OFFSET; //0x90 Win0 Cbr scaling start point offset + unsigned int FIFO_WATER_MARK; //0x94 Fifo water mark + unsigned int AXI_MS_ID; //0x98 Axi master ID + unsigned int reserved0; //0x9c + unsigned int REG_CFG_DONE; //0xa0 REGISTER CONFIG FINISH + unsigned int reserved1[(0x100-0xa4)/4]; + unsigned int MCU_BYPASS_WPORT; //0x100 MCU BYPASS MODE, DATA Write Only Port + unsigned int reserved2[(0x200-0x104)/4]; + unsigned int MCU_BYPASS_RPORT; //0x200 MCU BYPASS MODE, DATA Read Only Port +} LCDC_REG, *pLCDC_REG; + +//roate +#define ROTATE_0 0 +#define ROTATE_90 90 +#define ROTATE_180 180 +#define ROTATE_270 270 +#define X_MIRROR (1<<10) +#define Y_MIRROR (1<<11) + + + + +#define CalScale(x, y) (((u32)x*0x1000)/y) +struct rk31_lcdc_device{ + int id; + struct rk_lcdc_device_driver driver; + rk_screen *screen; + + LCDC_REG *preg; // LCDC reg base address and backup reg + LCDC_REG regbak; + + void __iomem *reg_vir_base; // virtual basic address of lcdc register + u32 reg_phy_base; // physical basic address of lcdc register + u32 len; // physical map length of lcdc register + spinlock_t reg_lock; //one time only one process allowed to config the register + bool clk_on; //if aclk or hclk is closed ,acess to register is not allowed + u8 atv_layer_cnt; //active layer counter,when atv_layer_cnt = 0,disable lcdc + + unsigned int irq; + + struct clk *pd; //lcdc power domain + struct clk *hclk; //lcdc AHP clk + struct clk *dclk; //lcdc dclk + struct clk *aclk; //lcdc share memory frequency + struct clk *aclk_parent; //lcdc aclk divider frequency source + struct clk *aclk_ddr_lcdc; //DDR LCDC AXI clock disable. + struct clk *aclk_disp_matrix; //DISPLAY matrix AXI clock disable. + struct clk *hclk_cpu_display; //CPU DISPLAY AHB bus clock disable. + struct clk *pd_display; // display power domain + u32 pixclock; +}; + +struct lcdc_info{ +/*LCD CLK*/ + struct rk31_lcdc_device lcdc0; + struct rk31_lcdc_device lcdc1; + +}; + + +struct win_set { + volatile u32 y_offset; + volatile u32 c_offset; +}; + +struct win0_par { + u32 refcount; + u32 pseudo_pal[16]; + u32 y_offset; + u32 c_offset; + u32 xpos; //size in panel + u32 ypos; + u32 xsize; //start point in panel + u32 ysize; + enum data_format format; + + wait_queue_head_t wait; + struct win_set mirror; + struct win_set displ; + struct win_set done; + + u8 par_seted; + u8 addr_seted; +}; + +#endif From b526f4b4ac141fa7bb54e31ce8e6b0e390486a83 Mon Sep 17 00:00:00 2001 From: kfx Date: Fri, 20 Jul 2012 14:47:18 +0800 Subject: [PATCH 031/261] rk2928: update iomux --- arch/arm/mach-rk2928/include/mach/iomux.h | 74 ++++++++++++----------- arch/arm/mach-rk2928/iomux.c | 73 +++++++++++----------- 2 files changed, 76 insertions(+), 71 deletions(-) diff --git a/arch/arm/mach-rk2928/include/mach/iomux.h b/arch/arm/mach-rk2928/include/mach/iomux.h index 9bd014bb58fe..6e7ab6a2fee9 100755 --- a/arch/arm/mach-rk2928/include/mach/iomux.h +++ b/arch/arm/mach-rk2928/include/mach/iomux.h @@ -27,10 +27,6 @@ #define GPIO0A_I2C1_SCL 1 #define GPIO0A_GPIO0A3 0 #define GPIO0A_I2C1_SDA 1 -#define GPIO0A_GPIO0A4 0 -#define GPIO0A_I2C2_SCL 1 -#define GPIO0A_GPIO0A5 0 -#define GPIO0A_I2C2_SDA 1 #define GPIO0A_GPIO0A6 0 #define GPIO0A_I2C3_SCL 1 #define GPIO0A_HDMI_DDCSCL 2 @@ -84,7 +80,7 @@ #define GPIO0D_GPIO0D5 0 #define GPIO0D_MMC1_WRPRT 1 #define GPIO0D_GPIO0D6 0 -#define GPIO0D_MC1_PWREN 1 +#define GPIO0D_MMC1_PWREN 1 #define GPIO0D_GPIO0D7 0 #define GPIO0D_MMC1_BKEPWR 1 @@ -95,12 +91,15 @@ #define GPIO1A_I2S_SCLK 1 #define GPIO1A_GPIO1A2 0 #define GPIO1A_I2S_LRCKRX 1 +#define GPIO1A_GPS_CLK 2 #define GPIO1A_GPIO1A3 0 #define GPIO1A_I2S_LRCKTX 1 #define GPIO1A_GPIO1A4 0 #define GPIO1A_I2S_SDO 1 +#define GPIO1A_GPS_MAG 2 #define GPIO1A_GPIO1A5 0 #define GPIO1A_I2S_SDI 1 +#define GPIO1A_GPS_SIGN 2 #define GPIO1A_GPIO1A6 0 #define GPIO1A_MMC1_INTN 1 #define GPIO1A_GPIO1A7 0 @@ -109,21 +108,18 @@ //gpio1b #define GPIO1B_GPIO1B0 0 #define GPIO1B_SPI_CLK 1 -#define GPIO1B_GPS_CLK 2 +#define GPIO1B_UART1_CTSN 2 #define GPIO1B_GPIO1B1 0 #define GPIO1B_SPI_TXD 1 #define GPIO1B_UART1_SOUT 2 -#define GPIO1B_GPS_MAG 3 #define GPIO1B_GPIO1B2 0 #define GPIO1B_SPI_RXD 1 #define GPIO1B_UART1_SIN 2 -#define GPIO1B_GPS_SIGN 3 #define GPIO1B_GPIO1B3 0 #define GPIO1B_SPI_CSN0 1 #define GPIO1B_UART1_RTSN 2 #define GPIO1B_GPIO1B4 0 #define GPIO1B_SPI_CSN1 1 -#define GPIO1B_UART1_CTSN 2 #define GPIO1B_GPIO1B5 0 #define GPIO1B_MMC0_RSTNOUT 1 #define GPIO1B_GPIO1B6 0 @@ -146,8 +142,10 @@ #define GPIO1C_MMC0_D3 1 #define GPIO1C_GPIO1C6 0 #define GPIO1C_NAND_CS2 1 +#define GPIO1C_EMMC_CMD 2 #define GPIO1C_GPIO1C7 0 #define GPIO1C_NAND_CS3 1 +#define GPIO1C_EMMC_RSTNOUT 2 //gpio1d #define GPIO1D_GPIO1D0 0 @@ -186,13 +184,11 @@ #define GPIO2A_NAND_RDN 1 #define GPIO2A_GPIO2A4 0 #define GPIO2A_NAND_RDY 1 -#define GPIO2A_EMMC_RSTNOUT 2 #define GPIO2A_GPIO2A5 0 #define GPIO2A_NAND_WP 1 #define GPIO2A_EMMC_PWREN 2 #define GPIO2A_GPIO2A6 0 #define GPIO2A_NAND_CS0 1 -#define GPIO2A_EMMC_CMD 2 #define GPIO2A_GPIO2A7 0 #define GPIO2A_NAND_DPS 1 #define GPIO2A_EMMC_CLKOUT 2 @@ -239,25 +235,31 @@ #define GPIO2C_GPIO2C4 0 #define GPIO2C_LCDC0_D18 1 #define GPIO2C_LCDC1_D18 2 +#define GPIO2C_I2C2_SDA 3 #define GPIO2C_GPIO2C5 0 #define GPIO2C_LCDC0_D19 1 #define GPIO2C_LCDC1_D19 2 +#define GPIO2C_I2C2_SCL 3 #define GPIO2C_GPIO2C6 0 #define GPIO2C_LCDC0_D20 1 #define GPIO2C_LCDC1_D20 2 +#define GPIO2C_UART2_SIN 3 #define GPIO2C_GPIO2C7 0 #define GPIO2C_LCDC0_D21 1 #define GPIO2C_LCDC1_D21 2 +#define GPIO2C_UART2_SOUT 3 //gpio2d #define GPIO2D_GPIO2D0 0 -#define GPIO2D_LCDC0_D23 1 -#define GPIO2D_LCDC1_D23 2 -#define GPIO2D_UART2_SOUT 3 +#define GPIO2D_LCDC0_D22 1 +#define GPIO2D_LCDC1_D22 2 #define GPIO2D_GPIO2D1 0 #define GPIO2D_LCDC0_D23 1 #define GPIO2D_LCDC1_D23 2 -#define GPIO2D_UART2_SIN 3 + +//gpio3c +#define GPIO3C_GPIO3C1 0 +#define GPIO3C_OTG_DRVVBUS 1 //gpio3d #define GPIO3D_GPIO3D7 0 @@ -270,8 +272,6 @@ #define GPIO0A1_I2C0_SDA_NAME "gpio0a1_i2c0_sda_name" #define GPIO0A2_I2C1_SCL_NAME "gpio0a2_i2c1_scl_name" #define GPIO0A3_I2C1_SDA_NAME "gpio0a3_i2c1_sda_name" -#define GPIO0A4_I2C2_SCL_NAME "gpio0a4_i2c2_scl_name" -#define GPIO0A5_I2C2_SDA_NAME "gpio0a5_i2c2_sda_name" #define GPIO0A6_I2C3_SCL_HDMI_DDCSCL_NAME "gpio0a6_i2c3_scl_hdmi_ddcscl_name" #define GPIO0A7_I2C3_SDA_HDMI_DDCSDA_NAME "gpio0a7_i2c3_sda_hdmi_ddcsda_name" @@ -300,25 +300,25 @@ #define GPIO0D3_PWM_1_NAME "gpio0d3_pwm_1_name" #define GPIO0D4_PWM_2_NAME "gpio0d4_pwm_2_name" #define GPIO0D5_MMC1_WRPRT_NAME "gpio0d5_mmc1_wrprt_name" -#define GPIO0D6_MC1_PWREN_NAME "gpio0d6_mc1_pwren_name" +#define GPIO0D6_MMC1_PWREN_NAME "gpio0d6_mmc1_pwren_name" #define GPIO0D7_MMC1_BKEPWR_NAME "gpio0d7_mmc1_bkepwr_name" //gpio1a #define GPIO1A0_I2S_MCLK_NAME "gpio1a0_i2s_mclk_name" #define GPIO1A1_I2S_SCLK_NAME "gpio1a1_i2s_sclk_name" -#define GPIO1A2_I2S_LRCKRX_NAME "gpio1a2_i2s_lrckrx_name" +#define GPIO1A2_I2S_LRCKRX_GPS_CLK_NAME "gpio1a2_i2s_lrckrx_gps_clk_name" #define GPIO1A3_I2S_LRCKTX_NAME "gpio1a3_i2s_lrcktx_name" -#define GPIO1A4_I2S_SDO_NAME "gpio1a4_i2s_sdo_name" -#define GPIO1A5_I2S_SDI_NAME "gpio1a5_i2s_sdi_name" +#define GPIO1A4_I2S_SDO_GPS_MAG_NAME "gpio1a4_i2s_sdo_gps_mag_name" +#define GPIO1A5_I2S_SDI_GPS_SIGN_NAME "gpio1a5_i2s_sdi_gps_sign_name" #define GPIO1A6_MMC1_INTN_NAME "gpio1a6_mmc1_intn_name" #define GPIO1A7_MMC0_WRPRT_NAME "gpio1a7_mmc0_wrprt_name" //gpio1b -#define GPIO1B0_SPI_CLK_GPS_CLK_NAME "gpio1b0_spi_clk_gps_clk_name" -#define GPIO1B1_SPI_TXD_UART1_SOUT_GPS_MAG_NAME "gpio1b1_spi_txd_uart1_sout_gps_mag_name" -#define GPIO1B2_SPI_RXD_UART1_SIN_GPS_SIGN_NAME "gpio1b2_spi_rxd_uart1_sin_gps_sign_name" +#define GPIO1B0_SPI_CLK_UART1_CTSN_NAME "gpio1b0_spi_clk_uart1_ctsn_name" +#define GPIO1B1_SPI_TXD_UART1_SOUT_NAME "gpio1b1_spi_txd_uart1_sout_name" +#define GPIO1B2_SPI_RXD_UART1_SIN_NAME "gpio1b2_spi_rxd_uart1_sin_name" #define GPIO1B3_SPI_CSN0_UART1_RTSN_NAME "gpio1b3_spi_csn0_uart1_rtsn_name" -#define GPIO1B4_SPI_CSN1_UART1_CTSN_NAME "gpio1b4_spi_csn1_uart1_ctsn_name" +#define GPIO1B4_SPI_CSN1_NAME "gpio1b4_spi_csn1_name" #define GPIO1B5_MMC0_RSTNOUT_NAME "gpio1b5_mmc0_rstnout_name" #define GPIO1B6_MMC0_PWREN_NAME "gpio1b6_mmc0_pwren_name" #define GPIO1B7_MMC0_CMD_NAME "gpio1b7_mmc0_cmd_name" @@ -330,8 +330,8 @@ #define GPIO1C3_MMC0_D1_NAME "gpio1c3_mmc0_d1_name" #define GPIO1C4_MMC0_D2_NAME "gpio1c4_mmc0_d2_name" #define GPIO1C5_MMC0_D3_NAME "gpio1c5_mmc0_d3_name" -#define GPIO1C6_NAND_CS2_NAME "gpio1c6_nand_cs2_name" -#define GPIO1C7_NAND_CS3_NAME "gpio1c7_nand_cs3_name" +#define GPIO1C6_NAND_CS2_EMMC_CMD_NAME "gpio1c6_nand_cs2_emmc_cmd_name" +#define GPIO1C7_NAND_CS3_EMMC_RSTNOUT_NAME "gpio1c7_nand_cs3_emmc_rstnout_name" //gpio1d #define GPIO1D0_NAND_D0_EMMC_D0_NAME "gpio1d0_nand_d0_emmc_d0_name" @@ -348,9 +348,9 @@ #define GPIO2A1_NAND_CLE_NAME "gpio2a1_nand_cle_name" #define GPIO2A2_NAND_WRN_NAME "gpio2a2_nand_wrn_name" #define GPIO2A3_NAND_RDN_NAME "gpio2a3_nand_rdn_name" -#define GPIO2A4_NAND_RDY_EMMC_RSTNOUT_NAME "gpio2a4_nand_rdy_emmc_rstnout_name" +#define GPIO2A4_NAND_RDY_NAME "gpio2a4_nand_rdy_name" #define GPIO2A5_NAND_WP_EMMC_PWREN_NAME "gpio2a5_nand_wp_emmc_pwren_name" -#define GPIO2A6_NAND_CS0_EMMC_CMD_NAME "gpio2a6_nand_cs0_emmc_cmd_name" +#define GPIO2A6_NAND_CS0_NAME "gpio2a6_nand_cs0_name" #define GPIO2A7_NAND_DPS_EMMC_CLKOUT_NAME "gpio2a7_nand_dps_emmc_clkout_name" //gpio2b @@ -368,14 +368,17 @@ #define GPIO2C1_LCDC0_D15_LCDC1_D15_NAME "gpio2c1_lcdc0_d15_lcdc1_d15_name" #define GPIO2C2_LCDC0_D16_LCDC1_D16_NAME "gpio2c2_lcdc0_d16_lcdc1_d16_name" #define GPIO2C3_LCDC0_D17_LCDC1_D17_NAME "gpio2c3_lcdc0_d17_lcdc1_d17_name" -#define GPIO2C4_LCDC0_D18_LCDC1_D18_NAME "gpio2c4_lcdc0_d18_lcdc1_d18_name" -#define GPIO2C5_LCDC0_D19_LCDC1_D19_NAME "gpio2c5_lcdc0_d19_lcdc1_d19_name" -#define GPIO2C6_LCDC0_D20_LCDC1_D20_NAME "gpio2c6_lcdc0_d20_lcdc1_d20_name" -#define GPIO2C7_LCDC0_D21_LCDC1_D21_NAME "gpio2c7_lcdc0_d21_lcdc1_d21_name" +#define GPIO2C4_LCDC0_D18_LCDC1_D18_I2C2_SDA_NAME "gpio2c4_lcdc0_d18_lcdc1_d18_i2c2_sda_name" +#define GPIO2C5_LCDC0_D19_LCDC1_D19_I2C2_SCL_NAME "gpio2c5_lcdc0_d19_lcdc1_d19_i2c2_scl_name" +#define GPIO2C6_LCDC0_D20_LCDC1_D20_UART2_SIN_NAME "gpio2c6_lcdc0_d20_lcdc1_d20_uart2_sin_name" +#define GPIO2C7_LCDC0_D21_LCDC1_D21_UART2_SOUT_NAME "gpio2c7_lcdc0_d21_lcdc1_d21_uart2_sout_name" //gpio2d -#define GPIO2D0_LCDC0_D23_LCDC1_D23_UART2_SOUT_NAME "gpio2d0_lcdc0_d23_lcdc1_d23_uart2_sout_name" -#define GPIO2D1_LCDC0_D23_LCDC1_D23_UART2_SIN_NAME "gpio2d1_lcdc0_d23_lcdc1_d23_uart2_sin_name" +#define GPIO2D0_LCDC0_D22_LCDC1_D22_NAME "gpio2d0_lcdc0_d22_lcdc1_d22_name" +#define GPIO2D1_LCDC0_D23_LCDC1_D23_NAME "gpio2d1_lcdc0_d23_lcdc1_d23_name" + +//gpio3c +#define GPIO3C1_OTG_DRVVBUS_NAME "gpio3c1_otg_drvvbus_name" //gpio3d #define GPIO3D7_TESTCLK_OUT_NAME "gpio3d7_testclk_out_name" @@ -399,6 +402,7 @@ #define GRF_GPIO2C_IOMUX RK2928_GRF_BASE+0x00d0 #define GRF_GPIO2D_IOMUX RK2928_GRF_BASE+0x00d4 +#define GRF_GPIO3C_IOMUX RK2928_GRF_BASE+0x00e0 #define GRF_GPIO3D_IOMUX RK2928_GRF_BASE+0x00e4 #define GRF_GPIO0L_PULL 0x0118 diff --git a/arch/arm/mach-rk2928/iomux.c b/arch/arm/mach-rk2928/iomux.c index 11b2dcaf7b8a..c931237c4661 100755 --- a/arch/arm/mach-rk2928/iomux.c +++ b/arch/arm/mach-rk2928/iomux.c @@ -34,8 +34,6 @@ MUX_CFG(GPIO0A0_I2C0_SCL_NAME, GPIO0A, 0, 1, 0, DEF MUX_CFG(GPIO0A1_I2C0_SDA_NAME, GPIO0A, 2, 1, 0, DEFAULT) MUX_CFG(GPIO0A2_I2C1_SCL_NAME, GPIO0A, 4, 1, 0, DEFAULT) MUX_CFG(GPIO0A3_I2C1_SDA_NAME, GPIO0A, 6, 1, 0, DEFAULT) -MUX_CFG(GPIO0A4_I2C2_SCL_NAME, GPIO0A, 8, 1, 0, DEFAULT) -MUX_CFG(GPIO0A5_I2C2_SDA_NAME, GPIO0A, 10, 1, 0, DEFAULT) MUX_CFG(GPIO0A6_I2C3_SCL_HDMI_DDCSCL_NAME, GPIO0A, 12, 2, 0, DEFAULT) MUX_CFG(GPIO0A7_I2C3_SDA_HDMI_DDCSDA_NAME, GPIO0A, 14, 2, 0, DEFAULT) @@ -64,25 +62,25 @@ MUX_CFG(GPIO0D2_PWM_0_NAME, GPIO0D, 4, 1, 0, DEF MUX_CFG(GPIO0D3_PWM_1_NAME, GPIO0D, 6, 1, 0, DEFAULT) MUX_CFG(GPIO0D4_PWM_2_NAME, GPIO0D, 8, 1, 0, DEFAULT) MUX_CFG(GPIO0D5_MMC1_WRPRT_NAME, GPIO0D, 10, 1, 0, DEFAULT) -MUX_CFG(GPIO0D6_MC1_PWREN_NAME, GPIO0D, 12, 1, 0, DEFAULT) +MUX_CFG(GPIO0D6_MMC1_PWREN_NAME, GPIO0D, 12, 1, 0, DEFAULT) MUX_CFG(GPIO0D7_MMC1_BKEPWR_NAME, GPIO0D, 14, 1, 0, DEFAULT) //gpio1a MUX_CFG(GPIO1A0_I2S_MCLK_NAME, GPIO1A, 0, 1, 0, DEFAULT) MUX_CFG(GPIO1A1_I2S_SCLK_NAME, GPIO1A, 2, 1, 0, DEFAULT) -MUX_CFG(GPIO1A2_I2S_LRCKRX_NAME, GPIO1A, 4, 1, 0, DEFAULT) +MUX_CFG(GPIO1A2_I2S_LRCKRX_GPS_CLK_NAME, GPIO1A, 4, 2, 0, DEFAULT) MUX_CFG(GPIO1A3_I2S_LRCKTX_NAME, GPIO1A, 6, 1, 0, DEFAULT) -MUX_CFG(GPIO1A4_I2S_SDO_NAME, GPIO1A, 8, 1, 0, DEFAULT) -MUX_CFG(GPIO1A5_I2S_SDI_NAME, GPIO1A, 10, 1, 0, DEFAULT) +MUX_CFG(GPIO1A4_I2S_SDO_GPS_MAG_NAME, GPIO1A, 8, 2, 0, DEFAULT) +MUX_CFG(GPIO1A5_I2S_SDI_GPS_SIGN_NAME, GPIO1A, 10, 2, 0, DEFAULT) MUX_CFG(GPIO1A6_MMC1_INTN_NAME, GPIO1A, 12, 1, 0, DEFAULT) MUX_CFG(GPIO1A7_MMC0_WRPRT_NAME, GPIO1A, 14, 1, 0, DEFAULT) //gpio1b -MUX_CFG(GPIO1B0_SPI_CLK_GPS_CLK_NAME, GPIO1B, 0, 2, 0, DEFAULT) -MUX_CFG(GPIO1B1_SPI_TXD_UART1_SOUT_GPS_MAG_NAME,GPIO1B, 2, 3, 0, DEFAULT) -MUX_CFG(GPIO1B2_SPI_RXD_UART1_SIN_GPS_SIGN_NAME,GPIO1B, 4, 3, 0, DEFAULT) +MUX_CFG(GPIO1B0_SPI_CLK_UART1_CTSN_NAME, GPIO1B, 0, 2, 0, DEFAULT) +MUX_CFG(GPIO1B1_SPI_TXD_UART1_SOUT_NAME, GPIO1B, 2, 2, 0, DEFAULT) +MUX_CFG(GPIO1B2_SPI_RXD_UART1_SIN_NAME, GPIO1B, 4, 2, 0, DEFAULT) MUX_CFG(GPIO1B3_SPI_CSN0_UART1_RTSN_NAME, GPIO1B, 6, 2, 0, DEFAULT) -MUX_CFG(GPIO1B4_SPI_CSN1_UART1_CTSN_NAME, GPIO1B, 8, 2, 0, DEFAULT) +MUX_CFG(GPIO1B4_SPI_CSN1_NAME, GPIO1B, 8, 1, 0, DEFAULT) MUX_CFG(GPIO1B5_MMC0_RSTNOUT_NAME, GPIO1B, 10, 1, 0, DEFAULT) MUX_CFG(GPIO1B6_MMC0_PWREN_NAME, GPIO1B, 12, 1, 0, DEFAULT) MUX_CFG(GPIO1B7_MMC0_CMD_NAME, GPIO1B, 14, 1, 0, DEFAULT) @@ -94,8 +92,8 @@ MUX_CFG(GPIO1C2_MMC0_D0_NAME, GPIO1C, 4, 1, 0, DEF MUX_CFG(GPIO1C3_MMC0_D1_NAME, GPIO1C, 6, 1, 0, DEFAULT) MUX_CFG(GPIO1C4_MMC0_D2_NAME, GPIO1C, 8, 1, 0, DEFAULT) MUX_CFG(GPIO1C5_MMC0_D3_NAME, GPIO1C, 10, 1, 0, DEFAULT) -MUX_CFG(GPIO1C6_NAND_CS2_NAME, GPIO1C, 12, 1, 0, DEFAULT) -MUX_CFG(GPIO1C7_NAND_CS3_NAME, GPIO1C, 14, 1, 0, DEFAULT) +MUX_CFG(GPIO1C6_NAND_CS2_EMMC_CMD_NAME, GPIO1C, 12, 2, 0, DEFAULT) +MUX_CFG(GPIO1C7_NAND_CS3_EMMC_RSTNOUT_NAME, GPIO1C, 14, 2, 0, DEFAULT) //gpio1d MUX_CFG(GPIO1D0_NAND_D0_EMMC_D0_NAME, GPIO1D, 0, 2, 0, DEFAULT) @@ -112,9 +110,9 @@ MUX_CFG(GPIO2A0_NAND_ALE_NAME, GPIO2A, 0, 1, 0, DEF MUX_CFG(GPIO2A1_NAND_CLE_NAME, GPIO2A, 2, 1, 0, DEFAULT) MUX_CFG(GPIO2A2_NAND_WRN_NAME, GPIO2A, 4, 1, 0, DEFAULT) MUX_CFG(GPIO2A3_NAND_RDN_NAME, GPIO2A, 6, 1, 0, DEFAULT) -MUX_CFG(GPIO2A4_NAND_RDY_EMMC_RSTNOUT_NAME, GPIO2A, 8, 2, 0, DEFAULT) +MUX_CFG(GPIO2A4_NAND_RDY_NAME, GPIO2A, 8, 1, 0, DEFAULT) MUX_CFG(GPIO2A5_NAND_WP_EMMC_PWREN_NAME, GPIO2A, 10, 2, 0, DEFAULT) -MUX_CFG(GPIO2A6_NAND_CS0_EMMC_CMD_NAME, GPIO2A, 12, 2, 0, DEFAULT) +MUX_CFG(GPIO2A6_NAND_CS0_NAME, GPIO2A, 12, 1, 0, DEFAULT) MUX_CFG(GPIO2A7_NAND_DPS_EMMC_CLKOUT_NAME, GPIO2A, 14, 2, 0, DEFAULT) //gpio2b @@ -132,14 +130,17 @@ MUX_CFG(GPIO2C0_LCDC0_D14_LCDC1_D14_NAME, GPIO2C, 0, 2, 0, DEF MUX_CFG(GPIO2C1_LCDC0_D15_LCDC1_D15_NAME, GPIO2C, 2, 2, 0, DEFAULT) MUX_CFG(GPIO2C2_LCDC0_D16_LCDC1_D16_NAME, GPIO2C, 4, 2, 0, DEFAULT) MUX_CFG(GPIO2C3_LCDC0_D17_LCDC1_D17_NAME, GPIO2C, 6, 2, 0, DEFAULT) -MUX_CFG(GPIO2C4_LCDC0_D18_LCDC1_D18_NAME, GPIO2C, 8, 2, 0, DEFAULT) -MUX_CFG(GPIO2C5_LCDC0_D19_LCDC1_D19_NAME, GPIO2C, 10, 2, 0, DEFAULT) -MUX_CFG(GPIO2C6_LCDC0_D20_LCDC1_D20_NAME, GPIO2C, 12, 2, 0, DEFAULT) -MUX_CFG(GPIO2C7_LCDC0_D21_LCDC1_D21_NAME, GPIO2C, 14, 2, 0, DEFAULT) +MUX_CFG(GPIO2C4_LCDC0_D18_LCDC1_D18_I2C2_SDA_NAME,GPIO2C, 8, 3, 0, DEFAULT) +MUX_CFG(GPIO2C5_LCDC0_D19_LCDC1_D19_I2C2_SCL_NAME,GPIO2C, 10, 3, 0, DEFAULT) +MUX_CFG(GPIO2C6_LCDC0_D20_LCDC1_D20_UART2_SIN_NAME,GPIO2C, 12, 3, 0, DEFAULT) +MUX_CFG(GPIO2C7_LCDC0_D21_LCDC1_D21_UART2_SOUT_NAME,GPIO2C, 14, 3, 0, DEFAULT) //gpio2d -MUX_CFG(GPIO2D0_LCDC0_D23_LCDC1_D23_UART2_SOUT_NAME,GPIO2D, 0, 3, 0, DEFAULT) -MUX_CFG(GPIO2D1_LCDC0_D23_LCDC1_D23_UART2_SIN_NAME,GPIO2D, 2, 3, 0, DEFAULT) +MUX_CFG(GPIO2D0_LCDC0_D22_LCDC1_D22_NAME, GPIO2D, 0, 2, 0, DEFAULT) +MUX_CFG(GPIO2D1_LCDC0_D23_LCDC1_D23_NAME, GPIO2D, 2, 2, 0, DEFAULT) + +//gpio3c +MUX_CFG(GPIO3C1_OTG_DRVVBUS_NAME, GPIO3C, 2, 1, 0, DEFAULT) //gpio3d MUX_CFG(GPIO3D7_TESTCLK_OUT_NAME, GPIO3D, 14, 1, 0, DEFAULT) @@ -185,28 +186,28 @@ int __init rk2928_iomux_init(void) #if defined(CONFIG_UART1_RK29) || (CONFIG_RK_DEBUG_UART == 1) //UART1 OR SPIM0 - rk30_mux_api_set(GPIO1B1_SPI_TXD_UART1_SOUT_GPS_MAG_NAME, GPIO1B_UART1_SOUT); - rk30_mux_api_set(GPIO1B2_SPI_RXD_UART1_SIN_GPS_SIGN_NAME, GPIO1B_UART1_SIN); + rk30_mux_api_set(GPIO1B2_SPI_RXD_UART1_SIN_NAME, GPIO1B_UART1_SIN); + rk30_mux_api_set(GPIO1B1_SPI_TXD_UART1_SOUT_NAME, GPIO1B_UART1_SOUT); #ifdef CONFIG_UART1_CTS_RTS_RK29 + rk30_mux_api_set(GPIO1B0_SPI_CLK_UART1_CTSN_NAME, GPIO1B_UART1_CTSN); rk30_mux_api_set(GPIO1B3_SPI_CSN0_UART1_RTSN_NAME, GPIO1B_UART1_RTSN); - rk30_mux_api_set(GPIO1B4_SPI_CSN1_UART1_CTSN_NAME, GPIO1B_UART1_CTSN); #endif #endif #if defined(CONFIG_UART2_RK29) || (CONFIG_RK_DEBUG_UART == 2) - rk30_mux_api_set(GPIO2D0_LCDC0_D23_LCDC1_D23_UART2_SOUT_NAME, GPIO2D_UART2_SOUT); - rk30_mux_api_set(GPIO2D1_LCDC0_D23_LCDC1_D23_UART2_SIN_NAME, GPIO2D_UART2_SIN); + rk30_mux_api_set(GPIO0D0_UART2_RTSN_NAME, GPIO0D_UART2_RTSN); + rk30_mux_api_set(GPIO0D1_UART2_CTSN_NAME, GPIO0D_UART2_CTSN); #ifdef CONFIG_UART2_CTS_RTS_RK29 - rk30_mux_api_set(GPIO0D0_UART2_RTSN_NAME, GPIO0D_UART2_RTSN); - rk30_mux_api_set(GPIO0D1_UART2_CTSN_NAME, GPIO0D_UART2_CTSN); + rk30_mux_api_set(GPIO2C6_LCDC0_D20_LCDC1_D20_UART2_SIN_NAME, GPIO2C_UART2_SIN); + rk30_mux_api_set(GPIO2C7_LCDC0_D21_LCDC1_D21_UART2_SOUT_NAME, GPIO2C_UART2_SOUT); #endif #endif #ifdef CONFIG_SPIM0_RK29 //UART1 OR SPIM0 - rk30_mux_api_set(GPIO1B0_SPI_CLK_GPS_CLK_NAME, GPIO1B_SPI_CLK); - rk30_mux_api_set(GPIO1B1_SPI_TXD_UART1_SOUT_GPS_MAG_NAME, GPIO1B_SPI_TXD); - rk30_mux_api_set(GPIO1B2_SPI_RXD_UART1_SIN_GPS_SIGN_NAME, GPIO1B_SPI_RXD); + rk30_mux_api_set(GPIO1B0_SPI_CLK_UART1_CTSN_NAME, GPIO1B_SPI_CLK); + rk30_mux_api_set(GPIO1B1_SPI_TXD_UART1_SOUT_NAME, GPIO1B_SPI_TXD); + rk30_mux_api_set(GPIO1B2_SPI_RXD_UART1_SIN_NAME, GPIO1B_SPI_RXD); rk30_mux_api_set(GPIO1B3_SPI_CSN0_UART1_RTSN_NAME, GPIO1B_SPI_CSN0); #endif @@ -216,18 +217,18 @@ int __init rk2928_iomux_init(void) #endif #ifdef CONFIG_I2C1_RK30 - rk30_mux_api_set(GPIO0A2_I2C1_SCL_NAME, GPIO0A_I2C1_SCL); - rk30_mux_api_set(GPIO0A3_I2C1_SDA_NAME, GPIO0A_I2C1_SDA); + rk30_mux_api_set(GPIO0A2_I2C1_SCL_NAME, GPIO0A_I2C1_SCL); + rk30_mux_api_set(GPIO0A3_I2C1_SDA_NAME, GPIO0A_I2C1_SDA); #endif #ifdef CONFIG_I2C2_RK30 - rk30_mux_api_set(GPIO0A4_I2C2_SCL_NAME, GPIO0A_I2C2_SCL); - rk30_mux_api_set(GPIO0A5_I2C2_SDA_NAME, GPIO0A_I2C2_SDA); + rk30_mux_api_set(GPIO2C4_LCDC0_D18_LCDC1_D18_I2C2_SDA_NAME, GPIO2C_I2C2_SDA); + rk30_mux_api_set(GPIO2C5_LCDC0_D19_LCDC1_D19_I2C2_SCL_NAME, GPIO2C_I2C2_SCL); #endif #ifdef CONFIG_I2C3_RK30 - rk30_mux_api_set(GPIO0A6_I2C3_SCL_HDMI_DDCSCL_NAME, GPIO0A_I2C3_SCL); - rk30_mux_api_set(GPIO0A7_I2C3_SDA_HDMI_DDCSDA_NAME, GPIO0A_I2C3_SDA); + rk30_mux_api_set(GPIO0A6_I2C3_SCL_HDMI_DDCSCL_NAME, GPIO0A_I2C3_SCL); + rk30_mux_api_set(GPIO0A7_I2C3_SDA_HDMI_DDCSDA_NAME, GPIO0A_I2C3_SDA); #endif return 0; From 3a35b5af72dcd168af3a63a992846ad2461dbae7 Mon Sep 17 00:00:00 2001 From: yzq Date: Fri, 20 Jul 2012 17:04:55 +0800 Subject: [PATCH 032/261] rk2928 hdmi support --- arch/arm/mach-rk2928/devices.c | 22 + drivers/video/Kconfig | 4 + drivers/video/rockchip/Makefile | 2 +- drivers/video/rockchip/hdmi/Kconfig | 30 +- drivers/video/rockchip/hdmi/Makefile | 6 +- drivers/video/rockchip/hdmi/chips/Kconfig | 23 + drivers/video/rockchip/hdmi/chips/Makefile | 8 + .../video/rockchip/hdmi/chips/rk2928/Kconfig | 1 + .../video/rockchip/hdmi/chips/rk2928/Makefile | 8 + .../rockchip/hdmi/chips/rk2928/hdcp/Kconfig | 14 + .../rockchip/hdmi/chips/rk2928/hdcp/Makefile | 8 + .../hdmi/chips/rk2928/hdcp/rk30_hdcp.c | 570 ++++++++++++++++++ .../hdmi/chips/rk2928/hdcp/rk30_hdmi_hdcp.c | 157 +++++ .../hdmi/chips/rk2928/hdcp/rk30_hdmi_hdcp.h | 99 +++ .../rockchip/hdmi/chips/rk2928/rk2928_hdmi.c | 299 +++++++++ .../rockchip/hdmi/chips/rk2928/rk2928_hdmi.h | 11 + .../hdmi/chips/rk2928/rk2928_hdmi_hw.c | 456 ++++++++++++++ .../hdmi/chips/rk2928/rk2928_hdmi_hw.h | 248 ++++++++ .../hdmi/chips/rk2928/rk2928_hdmi_hw.hbak | 497 +++++++++++++++ .../video/rockchip/hdmi/chips/rk30/Kconfig | 15 + .../video/rockchip/hdmi/chips/rk30/Makefile | 8 + .../rockchip/hdmi/chips/rk30/hdcp/Kconfig | 14 + .../rockchip/hdmi/chips/rk30/hdcp/Makefile | 8 + .../rockchip/hdmi/chips/rk30/hdcp/rk30_hdcp.c | 570 ++++++++++++++++++ .../hdmi/chips/rk30/hdcp/rk30_hdmi_hdcp.c | 157 +++++ .../hdmi/chips/rk30/hdcp/rk30_hdmi_hdcp.h | 99 +++ .../hdmi/{ => chips/rk30}/rk30_hdmi.c | 0 .../rockchip/hdmi/chips/rk30/rk30_hdmi.h | 11 + .../hdmi/{ => chips/rk30}/rk30_hdmi_hw.c | 15 +- .../hdmi/{ => chips/rk30}/rk30_hdmi_hw.h | 32 +- drivers/video/rockchip/hdmi/rk30_hdmi.h | 108 ---- drivers/video/rockchip/hdmi/rk_hdmi.h | 136 +++++ drivers/video/rockchip/hdmi/rk_hdmi_core.c | 254 ++++++++ .../hdmi/{rk30_hdmi_edid.c => rk_hdmi_edid.c} | 9 +- .../hdmi/{rk30_hdmi_lcdc.c => rk_hdmi_lcdc.c} | 5 +- .../{rk30_hdmi_sysfs.c => rk_hdmi_sysfs.c} | 4 +- .../hdmi/{rk30_hdmi_task.c => rk_hdmi_task.c} | 26 +- 37 files changed, 3746 insertions(+), 188 deletions(-) create mode 100755 drivers/video/rockchip/hdmi/chips/Kconfig create mode 100755 drivers/video/rockchip/hdmi/chips/Makefile create mode 100755 drivers/video/rockchip/hdmi/chips/rk2928/Kconfig create mode 100755 drivers/video/rockchip/hdmi/chips/rk2928/Makefile create mode 100755 drivers/video/rockchip/hdmi/chips/rk2928/hdcp/Kconfig create mode 100755 drivers/video/rockchip/hdmi/chips/rk2928/hdcp/Makefile create mode 100755 drivers/video/rockchip/hdmi/chips/rk2928/hdcp/rk30_hdcp.c create mode 100755 drivers/video/rockchip/hdmi/chips/rk2928/hdcp/rk30_hdmi_hdcp.c create mode 100755 drivers/video/rockchip/hdmi/chips/rk2928/hdcp/rk30_hdmi_hdcp.h create mode 100755 drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi.c create mode 100755 drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi.h create mode 100755 drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.c create mode 100644 drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.h create mode 100755 drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.hbak create mode 100755 drivers/video/rockchip/hdmi/chips/rk30/Kconfig create mode 100755 drivers/video/rockchip/hdmi/chips/rk30/Makefile create mode 100755 drivers/video/rockchip/hdmi/chips/rk30/hdcp/Kconfig create mode 100755 drivers/video/rockchip/hdmi/chips/rk30/hdcp/Makefile create mode 100755 drivers/video/rockchip/hdmi/chips/rk30/hdcp/rk30_hdcp.c create mode 100755 drivers/video/rockchip/hdmi/chips/rk30/hdcp/rk30_hdmi_hdcp.c create mode 100755 drivers/video/rockchip/hdmi/chips/rk30/hdcp/rk30_hdmi_hdcp.h rename drivers/video/rockchip/hdmi/{ => chips/rk30}/rk30_hdmi.c (100%) create mode 100755 drivers/video/rockchip/hdmi/chips/rk30/rk30_hdmi.h rename drivers/video/rockchip/hdmi/{ => chips/rk30}/rk30_hdmi_hw.c (97%) rename drivers/video/rockchip/hdmi/{ => chips/rk30}/rk30_hdmi_hw.h (94%) delete mode 100755 drivers/video/rockchip/hdmi/rk30_hdmi.h create mode 100755 drivers/video/rockchip/hdmi/rk_hdmi_core.c rename drivers/video/rockchip/hdmi/{rk30_hdmi_edid.c => rk_hdmi_edid.c} (95%) rename drivers/video/rockchip/hdmi/{rk30_hdmi_lcdc.c => rk_hdmi_lcdc.c} (99%) rename drivers/video/rockchip/hdmi/{rk30_hdmi_sysfs.c => rk_hdmi_sysfs.c} (99%) rename drivers/video/rockchip/hdmi/{rk30_hdmi_task.c => rk_hdmi_task.c} (94%) diff --git a/arch/arm/mach-rk2928/devices.c b/arch/arm/mach-rk2928/devices.c index d90a8055eec8..21e24335a532 100755 --- a/arch/arm/mach-rk2928/devices.c +++ b/arch/arm/mach-rk2928/devices.c @@ -522,6 +522,28 @@ static void __init rk2928_init_spim(void) platform_device_register(&rk29xx_device_spi0m); #endif } + +#ifdef CONFIG_HDMI_RK2928 +static struct resource resource_hdmi[] = { + [0] = { + .start = RK2928_HDMI_PHYS, + .end = RK2928_HDMI_PHYS + RK2928_HDMI_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_HDMI, + .end = IRQ_HDMI, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device device_hdmi = { + .name = "rk2928-hdmi", + .id = -1, + .num_resources = ARRAY_SIZE(resource_hdmi), + .resource = resource_hdmi, +}; +#endif #ifdef CONFIG_RGA_RK30 static struct resource resource_rga[] = { [0] = { diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index b4117f636264..47d5735793ba 100755 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -2438,7 +2438,11 @@ source "drivers/video/omap2/Kconfig" source "drivers/video/backlight/Kconfig" source "drivers/video/display/Kconfig" + +if !LCDC_RK30 && !LCDC_RK2928 source "drivers/video/hdmi/Kconfig" +endif + source "drivers/video/rockchip/Kconfig" if VT diff --git a/drivers/video/rockchip/Makefile b/drivers/video/rockchip/Makefile index ed778bb77b99..68967a49fc80 100755 --- a/drivers/video/rockchip/Makefile +++ b/drivers/video/rockchip/Makefile @@ -4,4 +4,4 @@ obj-$(CONFIG_LCDC_RK30) += chips/rk30_lcdc.o obj-$(CONFIG_LCDC_RK2928) += chips/rk2928_lcdc.o obj-$(CONFIG_LCDC_RK31) += chips/rk31_lcdc.o obj-$(CONFIG_RGA_RK30) += rga/ -obj-$(CONFIG_HDMI_RK30) += hdmi/ +obj-$(CONFIG_RK_HDMI) += hdmi/ diff --git a/drivers/video/rockchip/hdmi/Kconfig b/drivers/video/rockchip/hdmi/Kconfig index 654bfa0e67db..e3700bbd817d 100755 --- a/drivers/video/rockchip/hdmi/Kconfig +++ b/drivers/video/rockchip/hdmi/Kconfig @@ -1,23 +1,9 @@ -menuconfig HDMI_RK30 - bool "RK30 HDMI support" - depends on LCDC_RK30 - select FB_MODE_HELPERS - help - Support rk30 hdmi if you say y here +menu "RK_HDMI" +config RK_HDMI + bool "RK_HDMI support" + +if RK_HDMI +source "drivers/video/rockchip/hdmi/chips/Kconfig" +endif -config HDMI_RK30_CTL_CODEC - bool "Mute Codec When HDMI Actived" - depends on HDMI_RK30 - default n - help - If you say y heres, Codec will be mute when hdmi inserted, - and unmute when removed. - -config HDMI_RK30_DEBUG - bool "RK30 HDMI Debugging" - depends on HDMI_RK30 && LCDC_RK30 - default n - help - Enableds verbose debugging the the HDMI drivers - -source "drivers/video/rockchip/hdmi/hdcp/Kconfig" \ No newline at end of file +endmenu diff --git a/drivers/video/rockchip/hdmi/Makefile b/drivers/video/rockchip/hdmi/Makefile index 4692311dbd9a..ed00a162460d 100755 --- a/drivers/video/rockchip/hdmi/Makefile +++ b/drivers/video/rockchip/hdmi/Makefile @@ -2,7 +2,7 @@ # Makefile for HDMI linux kernel module. # -ccflags-$(CONFIG_HDMI_RK30_DEBUG) = -DDEBUG -DHDMI_DEBUG +ccflags-$(CONFIG_RK_HDMI_DEBUG) = -DDEBUG -DHDMI_DEBUG -obj-$(CONFIG_HDMI_RK30) += rk30_hdmi_hw.o rk30_hdmi_edid.o rk30_hdmi_lcdc.o rk30_hdmi_task.o rk30_hdmi_sysfs.o rk30_hdmi.o -obj-$(CONFIG_HDCP_RK30) += hdcp/ +obj-$(CONFIG_RK_HDMI) += rk_hdmi_edid.o rk_hdmi_lcdc.o rk_hdmi_task.o rk_hdmi_sysfs.o +obj-$(CONFIG_RK_HDMI) += chips/ diff --git a/drivers/video/rockchip/hdmi/chips/Kconfig b/drivers/video/rockchip/hdmi/chips/Kconfig new file mode 100755 index 000000000000..e0c1c271bdc1 --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/Kconfig @@ -0,0 +1,23 @@ +choice + prompt "HDMI chips select" +config HDMI_RK30 + bool "RK30 HDMI support" + depends on LCDC_RK30 + select FB_MODE_HELPERS + help + Support rk30 hdmi if you say y here +config HDMI_RK2928 + bool "RK2928 HDMI support" + depends on LCDC_RK2928 + select FB_MODE_HELPERS + help + Support rk2928 hdmi if you say y here +endchoice + +if HDMI_RK30 +source "drivers/video/rockchip/hdmi/chips/rk30/Kconfig" +endif + +if HDMI_RK2928 +source "drivers/video/rockchip/hdmi/chips/rk2928/Kconfig" +endif diff --git a/drivers/video/rockchip/hdmi/chips/Makefile b/drivers/video/rockchip/hdmi/chips/Makefile new file mode 100755 index 000000000000..a43ac0633d6a --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for HDMI linux kernel module. +# + +ccflags-$(CONFIG_HDMI_RK30_DEBUG) = -DDEBUG -DHDMI_DEBUG + +obj-$(CONFIG_HDMI_RK30) += rk30/ +obj-$(CONFIG_HDMI_RK2928) += rk2928/ diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/Kconfig b/drivers/video/rockchip/hdmi/chips/rk2928/Kconfig new file mode 100755 index 000000000000..8b137891791f --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/rk2928/Kconfig @@ -0,0 +1 @@ + diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/Makefile b/drivers/video/rockchip/hdmi/chips/rk2928/Makefile new file mode 100755 index 000000000000..d3227c7f27d9 --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/rk2928/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for HDMI linux kernel module. +# + +ccflags-$(CONFIG_HDMI_RK30_DEBUG) = -DDEBUG -DHDMI_DEBUG + +obj-y += rk2928_hdmi_hw.o rk2928_hdmi.o +obj-$(CONFIG_HDCP_RK2928) += hdcp/ diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/Kconfig b/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/Kconfig new file mode 100755 index 000000000000..1bb3c3a24f56 --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/Kconfig @@ -0,0 +1,14 @@ +config HDCP_RK30 + bool "RK30 HDCP support" + depends on LCDC_RK30 && HDMI_RK30 + default n + help + HDCP Interface. This adds the High Definition Content Protection Interface. + See http://www.digital-cp.com/ for HDCP specification. + +config HDCP_RK30_DEBUG + bool "RK30 HDCP Debugging" + depends on HDCP_RK30 + default n + help + Enableds verbose debugging the the HDCP drivers diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/Makefile b/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/Makefile new file mode 100755 index 000000000000..108b67ca134e --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for HDCP linux kernel module. +# + +ccflags-$(CONFIG_HDCP_RK30_DEBUG) = -DDEBUG -DHDCP_DEBUG + +obj-$(CONFIG_HDCP_RK30) += hdcp.o +hdcp-y := rk30_hdcp.o rk30_hdmi_hdcp.o diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/rk30_hdcp.c b/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/rk30_hdcp.c new file mode 100755 index 000000000000..68d0ac841a67 --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/rk30_hdcp.c @@ -0,0 +1,570 @@ +#include +#include +#include +#include +#include +#include +#include +#include "../rk30_hdmi.h" +#include "../rk30_hdmi_hw.h" +#include "rk30_hdmi_hdcp.h" + +struct hdcp *hdcp = NULL; + +static void hdcp_work_queue(struct work_struct *work); + +/*----------------------------------------------------------------------------- + * Function: hdcp_submit_work + *----------------------------------------------------------------------------- + */ +static struct delayed_work *hdcp_submit_work(int event, int delay) +{ + struct hdcp_delayed_work *work; + + DBG("%s event %04x delay %d", __FUNCTION__, event, delay); + + work = kmalloc(sizeof(struct hdcp_delayed_work), GFP_ATOMIC); + + if (work) { + INIT_DELAYED_WORK(&work->work, hdcp_work_queue); + work->event = event; + queue_delayed_work(hdcp->workqueue, + &work->work, + msecs_to_jiffies(delay)); + } else { + printk(KERN_WARNING "HDCP: Cannot allocate memory to " + "create work\n"); + return 0; + } + + return &work->work; +} + +/*----------------------------------------------------------------------------- + * Function: hdcp_cancel_work + *----------------------------------------------------------------------------- + */ +static void hdcp_cancel_work(struct delayed_work **work) +{ + int ret = 0; + + if (*work) { + ret = cancel_delayed_work(*work); + if (ret != 1) { + ret = cancel_work_sync(&((*work)->work)); + printk(KERN_INFO "Canceling work failed - " + "cancel_work_sync done %d\n", ret); + } + kfree(*work); + *work = 0; + } +} + +/*----------------------------------------------------------------------------- + * Function: hdcp_wq_authentication_failure + *----------------------------------------------------------------------------- + */ +static void hdcp_wq_authentication_failure(void) +{ + if (hdcp->hdmi_state == HDMI_STOPPED) { + return; + } + + rk30_hdcp_disable(); + rk30_hdmi_control_output(false); + + hdcp_cancel_work(&hdcp->pending_wq_event); + + if (hdcp->retry_cnt && (hdcp->hdmi_state != HDMI_STOPPED)) { + if (hdcp->retry_cnt < HDCP_INFINITE_REAUTH) { + hdcp->retry_cnt--; + printk(KERN_INFO "HDCP: authentication failed - " + "retrying, attempts=%d\n", + hdcp->retry_cnt); + } else + printk(KERN_INFO "HDCP: authentication failed - " + "retrying\n"); + + hdcp->hdcp_state = HDCP_AUTHENTICATION_START; + + hdcp->pending_wq_event = hdcp_submit_work(HDCP_AUTH_REATT_EVENT, + HDCP_REAUTH_DELAY); + } else { + printk(KERN_INFO "HDCP: authentication failed - " + "HDCP disabled\n"); + hdcp->hdcp_state = HDCP_ENABLE_PENDING; + } + +} + +/*----------------------------------------------------------------------------- + * Function: hdcp_wq_start_authentication + *----------------------------------------------------------------------------- + */ +static void hdcp_wq_start_authentication(void) +{ + int status = HDCP_OK; + + hdcp->hdcp_state = HDCP_AUTHENTICATION_START; + + DBG("HDCP: authentication start"); + + status = rk30_hdcp_start_authentication(); + + if (status != HDCP_OK) { + DBG("HDCP: authentication failed"); + hdcp_wq_authentication_failure(); + } else { + hdcp->hdcp_state = HDCP_WAIT_KSV_LIST; + } +} + +/*----------------------------------------------------------------------------- + * Function: hdcp_wq_check_bksv + *----------------------------------------------------------------------------- + */ +static void hdcp_wq_check_bksv(void) +{ + int status = HDCP_OK; + + DBG("Check BKSV start"); + + status = rk30_hdcp_check_bksv(); + + if (status != HDCP_OK) { + printk(KERN_INFO "HDCP: Check BKSV failed"); + hdcp->retry_cnt = 0; + hdcp_wq_authentication_failure(); + } + else { + DBG("HDCP: Check BKSV successful"); + + hdcp->hdcp_state = HDCP_LINK_INTEGRITY_CHECK; + + /* Restore retry counter */ + if(hdcp->retry_times == 0) + hdcp->retry_cnt = HDCP_INFINITE_REAUTH; + else + hdcp->retry_cnt = hdcp->retry_times; + } +} + +/*----------------------------------------------------------------------------- + * Function: hdcp_wq_authentication_sucess + *----------------------------------------------------------------------------- + */ +static void hdcp_wq_authentication_sucess(void) +{ + printk(KERN_INFO "HDCP: authentication pass"); + rk30_hdmi_control_output(true); +} + +/*----------------------------------------------------------------------------- + * Function: hdcp_wq_disable + *----------------------------------------------------------------------------- + */ +static void hdcp_wq_disable(int event) +{ + printk(KERN_INFO "HDCP: disabled"); + + hdcp_cancel_work(&hdcp->pending_wq_event); + rk30_hdcp_disable(); + if(event == HDCP_DISABLE_CTL) { + hdcp->hdcp_state = HDCP_DISABLED; + if(hdcp->hdmi_state == HDMI_STARTED) + rk30_hdmi_control_output(true); + } + else if(event == HDCP_STOP_FRAME_EVENT) + hdcp->hdcp_state = HDCP_ENABLE_PENDING; +} + +/*----------------------------------------------------------------------------- + * Function: hdcp_work_queue + *----------------------------------------------------------------------------- + */ +static void hdcp_work_queue(struct work_struct *work) +{ + struct hdcp_delayed_work *hdcp_w = + container_of(work, struct hdcp_delayed_work, work.work); + int event = hdcp_w->event; + + mutex_lock(&hdcp->lock); + + DBG("hdcp_work_queue() - START - %u hdmi=%d hdcp=%d evt= %x %d", + jiffies_to_msecs(jiffies), + hdcp->hdmi_state, + hdcp->hdcp_state, + (event & 0xFF00) >> 8, + event & 0xFF); + + if(event == HDCP_STOP_FRAME_EVENT) { + hdcp->hdmi_state = HDMI_STOPPED; + } + + if (event == HDCP_DISABLE_CTL || event == HDCP_STOP_FRAME_EVENT) { + hdcp_wq_disable(event); + } + + if (event & HDCP_WORKQUEUE_SRC) + hdcp->pending_wq_event = 0; + + /* First handle HDMI state */ + if (event == HDCP_START_FRAME_EVENT) { + hdcp->pending_start = 0; + hdcp->hdmi_state = HDMI_STARTED; + } + + /**********************/ + /* HDCP state machine */ + /**********************/ + switch (hdcp->hdcp_state) { + case HDCP_DISABLED: + /* HDCP enable control or re-authentication event */ + if (event == HDCP_ENABLE_CTL) { + if(hdcp->retry_times == 0) + hdcp->retry_cnt = HDCP_INFINITE_REAUTH; + else + hdcp->retry_cnt = hdcp->retry_times; + if (hdcp->hdmi_state == HDMI_STARTED) + hdcp_wq_start_authentication(); + else + hdcp->hdcp_state = HDCP_ENABLE_PENDING; + } + break; + + case HDCP_ENABLE_PENDING: + /* HDMI start frame event */ + if (event == HDCP_START_FRAME_EVENT) + hdcp_wq_start_authentication(); + + break; + + case HDCP_AUTHENTICATION_START: + /* Re-authentication */ + if (event == HDCP_AUTH_REATT_EVENT) + hdcp_wq_start_authentication(); + + break; + + case HDCP_WAIT_KSV_LIST: + /* KSV failure */ + if (event == HDCP_FAIL_EVENT) { + printk(KERN_INFO "HDCP: KSV switch failure\n"); + + hdcp_wq_authentication_failure(); + } + /* KSV list ready event */ + else if (event == HDCP_KSV_LIST_RDY_EVENT) + hdcp_wq_check_bksv(); + break; + + case HDCP_LINK_INTEGRITY_CHECK: + /* Ri failure */ + if (event == HDCP_FAIL_EVENT) { + printk(KERN_INFO "HDCP: Ri check failure\n"); + hdcp_wq_authentication_failure(); + } + else if(event == HDCP_AUTH_PASS_EVENT) + hdcp_wq_authentication_sucess(); + break; + + default: + printk(KERN_WARNING "HDCP: error - unknow HDCP state\n"); + break; + } + + kfree(hdcp_w); + if(event == HDCP_STOP_FRAME_EVENT) + complete(&hdcp->complete); + + mutex_unlock(&hdcp->lock); +} + +/*----------------------------------------------------------------------------- + * Function: hdcp_start_frame_cb + *----------------------------------------------------------------------------- + */ +static void hdcp_start_frame_cb(void) +{ + DBG("hdcp_start_frame_cb()"); + + /* Cancel any pending work */ + if (hdcp->pending_start) + hdcp_cancel_work(&hdcp->pending_start); + if (hdcp->pending_wq_event) + hdcp_cancel_work(&hdcp->pending_wq_event); + + hdcp->pending_start = hdcp_submit_work(HDCP_START_FRAME_EVENT, + HDCP_ENABLE_DELAY); +} + +/*----------------------------------------------------------------------------- + * Function: hdcp_irq_cb + *----------------------------------------------------------------------------- + */ +static void hdcp_irq_cb(int interrupt) +{ + int value; + DBG("%s 0x%x", __FUNCTION__, interrupt); + if(interrupt & m_INT_HDCP_ERR) + { + value = HDMIRdReg(HDCP_ERROR); + HDMIWrReg(HDCP_ERROR, value); + printk(KERN_INFO "HDCP: Error 0x%02x\n", value); + + if( (hdcp->hdcp_state != HDCP_DISABLED) && + (hdcp->hdcp_state != HDCP_ENABLE_PENDING) ) + { + hdcp_submit_work(HDCP_FAIL_EVENT, 0); + } + } + else if(interrupt & (m_INT_BKSV_RPRDY | m_INT_BKSV_RCRDY)) + hdcp_submit_work(HDCP_KSV_LIST_RDY_EVENT, 0); + else if(interrupt & m_INT_AUTH_DONE) + hdcp_submit_work(HDCP_AUTH_PASS_EVENT, 0); +} + +/*----------------------------------------------------------------------------- + * Function: hdcp_power_on_cb + *----------------------------------------------------------------------------- + */ +static int hdcp_power_on_cb(void) +{ + DBG("%s", __FUNCTION__); + return rk30_hdcp_load_key2mem(hdcp->keys); +} + +/*----------------------------------------------------------------------------- + * Function: hdcp_power_off_cb + *----------------------------------------------------------------------------- + */ +static void hdcp_power_off_cb(void) +{ + DBG("%s", __FUNCTION__); + if(!hdcp->enable) + return; + + hdcp_cancel_work(&hdcp->pending_start); + hdcp_cancel_work(&hdcp->pending_wq_event); + init_completion(&hdcp->complete); + /* Post event to workqueue */ + if (hdcp_submit_work(HDCP_STOP_FRAME_EVENT, 0)) + wait_for_completion_interruptible_timeout(&hdcp->complete, + msecs_to_jiffies(2000)); +} + +// Load HDCP key to external HDCP memory +static void hdcp_load_keys_cb(const struct firmware *fw, void *context) +{ + if (!fw) { + pr_err("HDCP: failed to load keys\n"); + return; + } + + if(fw->size < HDCP_KEY_SIZE) { + pr_err("HDCP: firmware wrong size %d\n", fw->size); + return; + } + + hdcp->keys = kmalloc(HDCP_KEY_SIZE, GFP_KERNEL); + if(hdcp->keys == NULL) { + pr_err("HDCP: can't allocated space for keys\n"); + return; + } + + memcpy(hdcp->keys, fw->data, HDCP_KEY_SIZE); + + rk30_hdcp_load_key2mem(hdcp->keys); + printk(KERN_INFO "HDCP: loaded hdcp key success\n"); + + if(fw->size > HDCP_KEY_SIZE) { + DBG("%s invalid key size %d", __FUNCTION__, fw->size - HDCP_KEY_SIZE); + if((fw->size - HDCP_KEY_SIZE) % 5) { + pr_err("HDCP: failed to load invalid keys\n"); + return; + } + hdcp->invalidkeys = kmalloc(fw->size - HDCP_KEY_SIZE, GFP_KERNEL); + if(hdcp->invalidkeys == NULL) { + pr_err("HDCP: can't allocated space for invalid keys\n"); + return; + } + memcpy(hdcp->invalidkeys, fw->data + HDCP_KEY_SIZE, fw->size - HDCP_KEY_SIZE); + hdcp->invalidkey = (fw->size - HDCP_KEY_SIZE)/5; + printk(KERN_INFO "HDCP: loaded hdcp invalid key success\n"); + } +} + +static ssize_t hdcp_enable_read(struct device *device, + struct device_attribute *attr, char *buf) +{ + int enable = 0; + + if(hdcp) + enable = hdcp->enable; + + return snprintf(buf, PAGE_SIZE, "%d\n", enable); +} + +static ssize_t hdcp_enable_write(struct device *device, + struct device_attribute *attr, const char *buf, size_t count) +{ + int enable; + + if(hdcp == NULL) + return -EINVAL; + + sscanf(buf, "%d", &enable); + if(hdcp->enable != enable) + { + /* Post event to workqueue */ + if(enable) { + if (hdcp_submit_work(HDCP_ENABLE_CTL, 0) == 0) + return -EFAULT; + } + else { + hdcp_cancel_work(&hdcp->pending_start); + hdcp_cancel_work(&hdcp->pending_wq_event); + + /* Post event to workqueue */ + if (hdcp_submit_work(HDCP_DISABLE_CTL, 0) == 0) + return -EFAULT; + } + hdcp->enable = enable; + } + return count; +} + +static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR, hdcp_enable_read, hdcp_enable_write); + +static ssize_t hdcp_trytimes_read(struct device *device, + struct device_attribute *attr, char *buf) +{ + int trytimes = 0; + + if(hdcp) + trytimes = hdcp->retry_times; + + return snprintf(buf, PAGE_SIZE, "%d\n", trytimes); +} + +static ssize_t hdcp_trytimes_wrtie(struct device *device, + struct device_attribute *attr, const char *buf, size_t count) +{ + int trytimes; + + if(hdcp == NULL) + return -EINVAL; + + sscanf(buf, "%d", &trytimes); + if(hdcp->retry_times != trytimes) + hdcp->retry_times = trytimes; + + return count; +} + + +static DEVICE_ATTR(trytimes, S_IRUGO|S_IWUSR, hdcp_trytimes_read, hdcp_trytimes_wrtie); + + +static struct miscdevice mdev; + +static int __init rk30_hdcp_init(void) +{ + int ret; + + DBG("[%s] %u", __FUNCTION__, jiffies_to_msecs(jiffies)); + + hdcp = kmalloc(sizeof(struct hdcp), GFP_KERNEL); + if(!hdcp) + { + printk(KERN_ERR ">>HDCP: kmalloc fail!"); + ret = -ENOMEM; + goto error0; + } + memset(hdcp, 0, sizeof(struct hdcp)); + mutex_init(&hdcp->lock); + + mdev.minor = MISC_DYNAMIC_MINOR; + mdev.name = "hdcp"; + mdev.mode = 0666; + if (misc_register(&mdev)) { + printk(KERN_ERR "HDCP: Could not add character driver\n"); + ret = HDMI_ERROR_FALSE; + goto error1; + } + ret = device_create_file(mdev.this_device, &dev_attr_enable); + if(ret) + { + printk(KERN_ERR "HDCP: Could not add sys file enable\n"); + ret = -EINVAL; + goto error2; + } + + ret = device_create_file(mdev.this_device, &dev_attr_trytimes); + if(ret) + { + printk(KERN_ERR "HDCP: Could not add sys file trytimes\n"); + ret = -EINVAL; + goto error3; + } + + hdcp->workqueue = create_singlethread_workqueue("hdcp"); + if (hdcp->workqueue == NULL) { + printk(KERN_ERR "HDCP,: create workqueue failed.\n"); + goto error4; + } + + + ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG, + "hdcp.keys", mdev.this_device, GFP_KERNEL, + hdcp, hdcp_load_keys_cb); + if (ret < 0) { + printk(KERN_ERR "HDCP: request_firmware_nowait failed: %d\n", ret); + goto error5; + } + + rk30_hdmi_register_hdcp_callbacks( hdcp_start_frame_cb, + hdcp_irq_cb, + hdcp_power_on_cb, + hdcp_power_off_cb); + + DBG("%s success %u", __FUNCTION__, jiffies_to_msecs(jiffies)); + return 0; + +error5: + destroy_workqueue(hdcp->workqueue); +error4: + device_remove_file(mdev.this_device, &dev_attr_trytimes); +error3: + device_remove_file(mdev.this_device, &dev_attr_enable); +error2: + misc_deregister(&mdev); +error1: + if(hdcp->keys) + kfree(hdcp->keys); + if(hdcp->invalidkeys) + kfree(hdcp->invalidkeys); + kfree(hdcp); +error0: + return ret; +} + +static void __exit rk30_hdcp_exit(void) +{ + if(hdcp) { + mutex_lock(&hdcp->lock); + rk30_hdmi_register_hdcp_callbacks(0, 0, 0, 0); + device_remove_file(mdev.this_device, &dev_attr_enable); + misc_deregister(&mdev); + destroy_workqueue(hdcp->workqueue); + if(hdcp->keys) + kfree(hdcp->keys); + if(hdcp->invalidkeys) + kfree(hdcp->invalidkeys); + mutex_unlock(&hdcp->lock); + kfree(hdcp); + } +} + +module_init(rk30_hdcp_init); +module_exit(rk30_hdcp_exit); \ No newline at end of file diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/rk30_hdmi_hdcp.c b/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/rk30_hdmi_hdcp.c new file mode 100755 index 000000000000..1184989a57b2 --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/rk30_hdmi_hdcp.c @@ -0,0 +1,157 @@ +#include +#include +#include +#include "../rk30_hdmi.h" +#include "../rk30_hdmi_hw.h" +#include "rk30_hdmi_hdcp.h" + +static void rk30_hdcp_write_mem(int addr_8, char value) +{ + int temp; + int addr_32 = addr_8 - addr_8%4; + int shift = (addr_8%4) * 8; + + temp = HDMIRdReg(addr_32); + temp &= ~(0xff << shift); + temp |= value << shift; +// printk("temp is %08x\n", temp); + HDMIWrReg(addr_32, temp); +} + +int rk30_hdcp_load_key2mem(struct hdcp_keys *key) +{ + int i; + + if(key == NULL) return HDMI_ERROR_FALSE; + + HDMIWrReg(0x800, HDMI_INTERANL_CLK_DIV); + + for(i = 0; i < 7; i++) + rk30_hdcp_write_mem(HDCP_RAM_KEY_KSV1 + i, key->KSV[i]); + for(i = 0; i < 7; i++) + rk30_hdcp_write_mem(HDCP_RAM_KEY_KSV2 + i, key->KSV[i]); + for(i = 0; i < HDCP_PRIVATE_KEY_SIZE; i++) + rk30_hdcp_write_mem(HDCP_RAM_KEY_PRIVATE + i, key->DeviceKey[i]); + for(i = 0; i < HDCP_KEY_SHA_SIZE; i++) + rk30_hdcp_write_mem(HDCP_RAM_KEY_PRIVATE + HDCP_PRIVATE_KEY_SIZE + i, key->sha1[i]); + + HDMIWrReg(0x800, HDMI_INTERANL_CLK_DIV | 0x20); + return HDCP_OK; +} + +void rk30_hdcp_disable(void) +{ + int temp; + // Diable HDCP Interrupt + HDMIWrReg(INTR_MASK2, 0x00); + // Stop and Reset HDCP + HDMIMskReg(temp, HDCP_CTRL, m_HDCP_FRAMED_ENCRYPED | m_HDCP_AUTH_STOP | m_HDCP_RESET, + v_HDCP_FRAMED_ENCRYPED(0) | v_HDCP_AUTH_STOP(1) | v_HDCP_RESET(1) ); +} + +static int rk30_hdcp_load_key(void) +{ + int value, temp = 0; + + if(hdcp->keys == NULL) { + pr_err("[%s] HDCP key not loaded.\n", __FUNCTION__); + return HDCP_KEY_ERR; + } + + value = HDMIRdReg(HDCP_KEY_MEM_CTRL); + //Check HDCP key loaded from external HDCP memory + while((value & (m_KSV_VALID | m_KEY_VALID | m_KEY_READY)) != (m_KSV_VALID | m_KEY_VALID | m_KEY_READY)) { + if(temp > 10) { + pr_err("[%s] loaded hdcp key is incorrectable %02x\n", __FUNCTION__, value & 0xFF); + return HDCP_KEY_ERR; + } + //Load HDCP Key from external HDCP memory + HDMIWrReg(HDCP_KEY_ACCESS_CTRL2, m_LOAD_HDCP_KEY); + msleep(1); + value = HDMIRdReg(HDCP_KEY_MEM_CTRL); + temp++; + } + + return HDCP_OK; +} + + +int rk30_hdcp_start_authentication(void) +{ + int rc, temp; + + rc = rk30_hdcp_load_key(); + if(rc != HDCP_OK) + return rc; + + // Set 100ms & 5 sec timer + switch(hdmi->vic) + { + case HDMI_720x576p_50Hz_4_3: + case HDMI_720x576p_50Hz_16_9: + case HDMI_1280x720p_50Hz: + case HDMI_1920x1080i_50Hz: + case HDMI_720x576i_50Hz_4_3: + case HDMI_720x576i_50Hz_16_9: + case HDMI_1920x1080p_50Hz: + HDMIWrReg(HDCP_TIMER_100MS, 5); + HDMIWrReg(HDCP_TIMER_5S, 250); + break; + + default: + HDMIWrReg(HDCP_TIMER_100MS, 0x26); + HDMIWrReg(HDCP_TIMER_5S, 0x2c); + break; + } + // Config DDC Clock + temp = (hdmi->tmdsclk/HDCP_DDC_CLK)/4; + HDMIWrReg(DDC_BUS_FREQ_L, temp & 0xFF); + HDMIWrReg(DDC_BUS_FREQ_H, (temp >> 8) & 0xFF); + // Enable HDCP Interrupt + HDMIWrReg(INTR_MASK2, m_INT_HDCP_ERR | m_INT_BKSV_RPRDY | m_INT_BKSV_RCRDY | m_INT_AUTH_DONE | m_INT_AUTH_READY); + // Start HDCP + HDMIMskReg(temp, HDCP_CTRL, m_HDCP_AUTH_START | m_HDCP_FRAMED_ENCRYPED, v_HDCP_AUTH_START(1) | v_HDCP_FRAMED_ENCRYPED(0)); + + return HDCP_OK; +} + +int rk30_hdcp_check_bksv(void) +{ + int i, temp; + char bksv[5]; + char *invalidkey; + + temp = HDMIRdReg(HDCP_BCAPS); + DBG("Receiver capacity is 0x%02x", temp); + +#ifdef DEBUG + if(temp & m_HDMI_RECEIVED) + DBG("Receiver support HDMI"); + if(temp & m_REPEATER) + DBG("Receiver is a repeater"); + if(temp & m_DDC_FAST) + DBG("Receiver support 400K DDC"); + if(temp & m_1_1_FEATURE) + DBG("Receiver support 1.1 features, such as advanced cipher, EESS."); + if(temp & m_FAST_REAUTHENTICATION) + DBG("Receiver support fast reauthentication."); +#endif + + for(i = 0; i < 5; i++) { + bksv[i] = HDMIRdReg(HDCP_KSV_BYTE0 + (4 - i)*4) & 0xFF; + } + + DBG("bksv is 0x%02x%02x%02x%02x%02x", bksv[0], bksv[1], bksv[2], bksv[3], bksv[4]); + + for(i = 0; i < hdcp->invalidkey; i++) + { + invalidkey = hdcp->invalidkeys + i *5; + if(memcmp(bksv, invalidkey, 5) == 0) { + printk(KERN_ERR "HDCP: BKSV was revocated!!!\n"); + HDMIMskReg(temp, HDCP_CTRL, m_HDCP_BKSV_FAILED | m_HDCP_FRAMED_ENCRYPED, v_HDCP_BKSV_FAILED(1) | v_HDCP_FRAMED_ENCRYPED(0)); + return HDCP_KSV_ERR; + } + } + HDMIMskReg(temp, HDCP_CTRL, m_HDCP_BKSV_PASS | m_HDCP_FRAMED_ENCRYPED, v_HDCP_BKSV_PASS(1) | v_HDCP_FRAMED_ENCRYPED(1)); + return HDCP_OK; +} diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/rk30_hdmi_hdcp.h b/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/rk30_hdmi_hdcp.h new file mode 100755 index 000000000000..0224d88ab134 --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/rk30_hdmi_hdcp.h @@ -0,0 +1,99 @@ +#ifndef __RK30_HDMI_HDCP_H__ +#define __RK30_HDMI_HDCP_H__ + +/***************************/ +/* Definitions */ +/***************************/ + +/* Status / error codes */ +#define HDCP_OK 0 +#define HDCP_KEY_ERR 1 +#define HDCP_KSV_ERR 2 + +/* Delays */ +#define HDCP_ENABLE_DELAY 300 +#define HDCP_REAUTH_DELAY 100 + +/* Event source */ +#define HDCP_SRC_SHIFT 8 +#define HDCP_IOCTL_SRC (0x1 << HDCP_SRC_SHIFT) +#define HDCP_HDMI_SRC (0x2 << HDCP_SRC_SHIFT) +#define HDCP_IRQ_SRC (0x4 << HDCP_SRC_SHIFT) +#define HDCP_WORKQUEUE_SRC (0x8 << HDCP_SRC_SHIFT) + +/* Event */ +#define HDCP_ENABLE_CTL (HDCP_IOCTL_SRC | 0) +#define HDCP_DISABLE_CTL (HDCP_IOCTL_SRC | 1) +#define HDCP_START_FRAME_EVENT (HDCP_HDMI_SRC | 2) +#define HDCP_STOP_FRAME_EVENT (HDCP_HDMI_SRC | 3) +#define HDCP_KSV_LIST_RDY_EVENT (HDCP_IRQ_SRC | 4) +#define HDCP_FAIL_EVENT (HDCP_IRQ_SRC | 5) +#define HDCP_AUTH_PASS_EVENT (HDCP_IRQ_SRC | 6) +#define HDCP_AUTH_REATT_EVENT (HDCP_WORKQUEUE_SRC | 7) + +/* Key size */ +#define HDCP_KEY_SIZE 308 + +/* Authentication retry times */ +#define HDCP_INFINITE_REAUTH 0x100 + +enum hdcp_states { + HDCP_DISABLED, + HDCP_ENABLE_PENDING, + HDCP_AUTHENTICATION_START, + HDCP_WAIT_KSV_LIST, + HDCP_LINK_INTEGRITY_CHECK, +}; + +enum hdmi_states { + HDMI_STOPPED, + HDMI_STARTED +}; + +#define HDCP_PRIVATE_KEY_SIZE 280 +#define HDCP_KEY_SHA_SIZE 20 +#define HDCP_DDC_CLK 100000 + +struct hdcp_keys{ + u8 KSV[8]; + u8 DeviceKey[HDCP_PRIVATE_KEY_SIZE]; + u8 sha1[HDCP_KEY_SHA_SIZE]; +}; + +struct hdcp_delayed_work { + struct delayed_work work; + int event; +}; + +struct hdcp { + int enable; + int retry_times; + struct hdcp_keys *keys; + int invalidkey; + char *invalidkeys; + struct mutex lock; + struct completion complete; + struct workqueue_struct *workqueue; + + enum hdmi_states hdmi_state; + enum hdcp_states hdcp_state; + + struct delayed_work *pending_start; + struct delayed_work *pending_wq_event; + int retry_cnt; +}; + +extern struct hdcp *hdcp; + +#ifdef HDCP_DEBUG +#define DBG(format, ...) \ + printk(KERN_INFO "HDCP: " format "\n", ## __VA_ARGS__) +#else +#define DBG(format, ...) +#endif + +extern void rk30_hdcp_disable(void); +extern int rk30_hdcp_start_authentication(void); +extern int rk30_hdcp_check_bksv(void); +extern int rk30_hdcp_load_key2mem(struct hdcp_keys *key); +#endif /* __RK30_HDMI_HDCP_H__ */ \ No newline at end of file diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi.c b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi.c new file mode 100755 index 000000000000..1ef14180bd6f --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi.c @@ -0,0 +1,299 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "rk2928_hdmi.h" +#include "rk2928_hdmi_hw.h" + +struct hdmi *hdmi = NULL; + +extern irqreturn_t hdmi_irq(int irq, void *priv); +extern void hdmi_work(struct work_struct *work); +extern struct rk_lcdc_device_driver * rk_get_lcdc_drv(char *name); +extern void hdmi_register_display_sysfs(struct hdmi *hdmi, struct device *parent); +extern void hdmi_unregister_display_sysfs(struct hdmi *hdmi); + +int rk2928_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void), + void (*hdcp_irq_cb)(int status), + int (*hdcp_power_on_cb)(void), + void (*hdcp_power_off_cb)(void)) +{ + if(hdmi == NULL) + return HDMI_ERROR_FALSE; + + hdmi->hdcp_cb = hdcp_cb; + hdmi->hdcp_irq_cb = hdcp_irq_cb; + hdmi->hdcp_power_on_cb = hdcp_power_on_cb; + hdmi->hdcp_power_off_cb = hdcp_power_off_cb; + + return HDMI_ERROR_SUCESS; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void hdmi_early_suspend(struct early_suspend *h) +{ + hdmi_dbg(hdmi->dev, "hdmi enter early suspend pwr %d state %d\n", hdmi->pwr_mode, hdmi->state); + flush_delayed_work(&hdmi->delay_work); + mutex_lock(&hdmi->enable_mutex); + hdmi->suspend = 1; + if(!hdmi->enable) { + mutex_unlock(&hdmi->enable_mutex); + return; + } + disable_irq(hdmi->irq); + mutex_unlock(&hdmi->enable_mutex); + hdmi->command = HDMI_CONFIG_ENABLE; + init_completion(&hdmi->complete); + hdmi->wait = 1; + queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, 0); + wait_for_completion_interruptible_timeout(&hdmi->complete, + msecs_to_jiffies(5000)); + flush_delayed_work(&hdmi->delay_work); + // When HDMI 1.1V and 2.5V power off, DDC channel will be pull down, current is produced + // from VCC_IO which is pull up outside soc. We need to switch DDC IO to GPIO. +// rk2928_mux_api_set(GPIO0A7_I2C3_SDA_HDMI_DDCSDA_NAME, GPIO0A_GPIO0A7); +// rk2928_mux_api_set(GPIO0A6_I2C3_SCL_HDMI_DDCSCL_NAME, GPIO0A_GPIO0A6); + return; +} + +static void hdmi_early_resume(struct early_suspend *h) +{ + hdmi_dbg(hdmi->dev, "hdmi exit early resume\n"); + mutex_lock(&hdmi->enable_mutex); + +// rk2928_mux_api_set(GPIO0A7_I2C3_SDA_HDMI_DDCSDA_NAME, GPIO0A_HDMI_DDCSDA); +// rk2928_mux_api_set(GPIO0A6_I2C3_SCL_HDMI_DDCSCL_NAME, GPIO0A_HDMI_DDCSCL); + + hdmi->suspend = 0; + rk2928_hdmi_initial(); + if(hdmi->enable) { + enable_irq(hdmi->irq); + } + mutex_unlock(&hdmi->enable_mutex); + return; +} +#endif + +static inline void hdmi_io_remap(void) +{ + unsigned int value; + + // Remap HDMI IO Pin +// rk2928_mux_api_set(GPIO0A7_I2C3_SDA_HDMI_DDCSDA_NAME, GPIO0A_HDMI_DDCSDA); +// rk2928_mux_api_set(GPIO0A6_I2C3_SCL_HDMI_DDCSCL_NAME, GPIO0A_HDMI_DDCSCL); +// rk2928_mux_api_set(GPIO0B7_HDMI_HOTPLUGIN_NAME, GPIO0B_HDMI_HOTPLUGIN); + + // Select LCDC0 as video source and enabled. +// value = (HDMI_SOURCE_DEFAULT << 14) | (1 << 30); +// writel(value, GRF_SOC_CON0 + rk2928_GRF_BASE); +} + +static int __devinit rk2928_hdmi_probe (struct platform_device *pdev) +{ + int ret; + struct resource *res; + struct resource *mem; + + hdmi = kmalloc(sizeof(struct hdmi), GFP_KERNEL); + if(!hdmi) + { + dev_err(&pdev->dev, ">>rk30 hdmi kmalloc fail!"); + return -ENOMEM; + } + memset(hdmi, 0, sizeof(struct hdmi)); + hdmi->dev = &pdev->dev; + platform_set_drvdata(pdev, hdmi); + + if(HDMI_SOURCE_DEFAULT == HDMI_SOURCE_LCDC0) + hdmi->lcdc = rk_get_lcdc_drv("lcdc0"); + else + hdmi->lcdc = rk_get_lcdc_drv("lcdc1"); + if(hdmi->lcdc == NULL) + { + dev_err(hdmi->dev, "can not connect to video source lcdc\n"); + ret = -ENXIO; + goto err0; + } + hdmi->xscale = 95; + hdmi->yscale = 95; + + hdmi->hclk = clk_get(NULL,"hclk_hdmi"); + if(IS_ERR(hdmi->hclk)) + { + dev_err(hdmi->dev, "Unable to get hdmi hclk\n"); + ret = -ENXIO; + goto err0; + } + clk_enable(hdmi->hclk); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(hdmi->dev, "Unable to get register resource\n"); + ret = -ENXIO; + goto err0; + } + hdmi->regbase_phy = res->start; + hdmi->regsize_phy = (res->end - res->start) + 1; + mem = request_mem_region(res->start, (res->end - res->start) + 1, pdev->name); + if (!mem) + { + dev_err(hdmi->dev, "failed to request mem region for hdmi\n"); + ret = -ENOENT; + goto err0; + } + + + hdmi->regbase = (int)ioremap(res->start, (res->end - res->start) + 1); + if (!hdmi->regbase) { + dev_err(hdmi->dev, "cannot ioremap registers\n"); + ret = -ENXIO; + goto err1; + } + + ret = rk2928_hdmi_initial(); + if(ret != HDMI_ERROR_SUCESS) + goto err1; + + hdmi_io_remap(); + hdmi_sys_init(); + + hdmi->workqueue = create_singlethread_workqueue("hdmi"); + INIT_DELAYED_WORK(&(hdmi->delay_work), hdmi_work); + + #ifdef CONFIG_HAS_EARLYSUSPEND + hdmi->early_suspend.suspend = hdmi_early_suspend; + hdmi->early_suspend.resume = hdmi_early_resume; + hdmi->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 10; + register_early_suspend(&hdmi->early_suspend); + #endif + + hdmi_register_display_sysfs(hdmi, NULL); + #ifdef CONFIG_SWITCH + hdmi->switch_hdmi.name="hdmi"; + switch_dev_register(&(hdmi->switch_hdmi)); + #endif + + spin_lock_init(&hdmi->irq_lock); + mutex_init(&hdmi->enable_mutex); + + /* get the IRQ */ + hdmi->irq = platform_get_irq(pdev, 0); + if(hdmi->irq <= 0) { + dev_err(hdmi->dev, "failed to get hdmi irq resource (%d).\n", hdmi->irq); + ret = -ENXIO; + goto err2; + } + + /* request the IRQ */ + ret = request_irq(hdmi->irq, hdmi_irq, 0, dev_name(&pdev->dev), hdmi); + if (ret) + { + dev_err(hdmi->dev, "hdmi request_irq failed (%d).\n", ret); + goto err2; + } + + hdmi_dbg(hdmi->dev, "rk30 hdmi probe sucess.\n"); + return 0; +err2: + #ifdef CONFIG_SWITCH + switch_dev_unregister(&(hdmi->switch_hdmi)); + #endif + hdmi_unregister_display_sysfs(hdmi); + #ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&hdmi->early_suspend); + #endif + iounmap((void*)hdmi->regbase); +err1: + release_mem_region(res->start,(res->end - res->start) + 1); + clk_disable(hdmi->hclk); +err0: + hdmi_dbg(hdmi->dev, "rk30 hdmi probe error.\n"); + kfree(hdmi); + hdmi = NULL; + return ret; +} + +static int __devexit rk2928_hdmi_remove(struct platform_device *pdev) +{ + if(hdmi) { + mutex_lock(&hdmi->enable_mutex); + if(!hdmi->suspend && hdmi->enable) + disable_irq(hdmi->irq); + mutex_unlock(&hdmi->enable_mutex); + free_irq(hdmi->irq, NULL); + flush_workqueue(hdmi->workqueue); + destroy_workqueue(hdmi->workqueue); + #ifdef CONFIG_SWITCH + switch_dev_unregister(&(hdmi->switch_hdmi)); + #endif + hdmi_unregister_display_sysfs(hdmi); + #ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&hdmi->early_suspend); + #endif + iounmap((void*)hdmi->regbase); + release_mem_region(hdmi->regbase_phy, hdmi->regsize_phy); + clk_disable(hdmi->hclk); + fb_destroy_modelist(&hdmi->edid.modelist); + if(hdmi->edid.audio) + kfree(hdmi->edid.audio); + if(hdmi->edid.specs) + { + if(hdmi->edid.specs->modedb) + kfree(hdmi->edid.specs->modedb); + kfree(hdmi->edid.specs); + } + kfree(hdmi); + hdmi = NULL; + } + printk(KERN_INFO "rk30 hdmi removed.\n"); + return 0; +} + +static void rk2928_hdmi_shutdown(struct platform_device *pdev) +{ + if(hdmi) { + #ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&hdmi->early_suspend); + #endif + } + printk(KERN_INFO "rk30 hdmi shut down.\n"); +} + +static struct platform_driver rk2928_hdmi_driver = { + .probe = rk2928_hdmi_probe, + .remove = __devexit_p(rk2928_hdmi_remove), + .driver = { + .name = "rk30-hdmi", + .owner = THIS_MODULE, + }, + .shutdown = rk2928_hdmi_shutdown, +}; + +static int __init rk2928_hdmi_init(void) +{ + return platform_driver_register(&rk2928_hdmi_driver); +} + +static void __exit rk2928_hdmi_exit(void) +{ + platform_driver_unregister(&rk2928_hdmi_driver); +} + + +//fs_initcall(rk2928_hdmi_init); +module_init(rk2928_hdmi_init); +module_exit(rk2928_hdmi_exit); diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi.h b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi.h new file mode 100755 index 000000000000..4695086bf329 --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi.h @@ -0,0 +1,11 @@ +#ifndef __RK30_HDMI_H__ +#define __RK30_HDMI_H__ + +#include "../../rk_hdmi.h" + + +extern int rk30_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void), + void (*hdcp_irq_cb)(int status), + int (*hdcp_power_on_cb)(void), + void (*hdcp_power_off_cb)(void)); +#endif /* __RK30_HDMI_H__ */ diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.c b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.c new file mode 100755 index 000000000000..4f6e636cc956 --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.c @@ -0,0 +1,456 @@ +#include +#include +#include +#include "rk2928_hdmi.h" +#include "rk2928_hdmi_hw.h" + +static char edid_result = 0; +static bool analog_sync = 0; + +static inline void delay100us(void) +{ + msleep(1); +} + + +static void rk2928_hdmi_av_mute(bool enable) +{ + HDMIWrReg(AV_MUTE, v_AUDIO_MUTE(enable) | v_VIDEO_MUTE(enable)); +} + +static void rk2928_hdmi_sys_power_up(void) +{ + hdmi_dbg(hdmi->dev,"%s \n",__FUNCTION__); + HDMIWrReg(SYS_CTRL, v_REG_CLK_SOURCE_IIS | v_PWR_ON | v_INT_POL_HIGH); +} +static void rk2928_hdmi_sys_power_down(void) +{ + hdmi_dbg(hdmi->dev,"%s \n",__FUNCTION__); + HDMIWrReg(SYS_CTRL, v_REG_CLK_SOURCE_IIS | v_PWR_OFF | v_INT_POL_HIGH); +} + + + +static void rk2928_hdmi_set_pwr_mode(int mode) +{ + hdmi_dbg(hdmi->dev,"%s \n",__FUNCTION__); + if(hdmi->pwr_mode == mode) + return; + switch(mode){ + case NORMAL: + rk2928_hdmi_sys_power_down(); + HDMIWrReg(0xe3, 0x82); + HDMIWrReg(0xe5, 0x00); + HDMIWrReg(0xe4, 0x00); + HDMIWrReg(0xe7, 0x00); + HDMIWrReg(0xe1, 0x8e); + HDMIWrReg(0xce, 0x00); + HDMIWrReg(0xce, 0x01); + rk2928_hdmi_av_mute(1); + rk2928_hdmi_sys_power_up(); + analog_sync = 1; + break; + case LOWER_PWR: + rk2928_hdmi_av_mute(0); + rk2928_hdmi_sys_power_down(); + HDMIWrReg(0xe3, 0x02); + HDMIWrReg(0xe5, 0x1c); + HDMIWrReg(0xe1, 0x8c); + HDMIWrReg(0xe7, 0x04); + HDMIWrReg(0xe4, 0x03); + break; + default: + hdmi_dbg(hdmi->dev,"unkown rk2928 hdmi pwr mode %d\n",mode); + } + hdmi->pwr_mode = mode; +} + + +int rk2928_hdmi_detect_hotplug(void) +{ + int value = HDMIRdReg(HDMI_STATUS); + + hdmi_dbg(hdmi->dev, "[%s] value %02x\n", __FUNCTION__, value); + value &= m_HOTPLUG; + if(value == m_HOTPLUG) + return HDMI_HPD_ACTIVED; + else if(value) + return HDMI_HPD_INSERT; + else + return HDMI_HPD_REMOVED; +} + +#define HDMI_SYS_FREG_CLK 11289600 +#define HDMI_SCL_RATE (100*1000) +#define HDMI_DDC_CONFIG (HDMI_SYS_FREG_CLK>>2)/HDMI_SCL_RATE +#define DDC_BUS_FREQ_L 0x4b +#define DDC_BUS_FREQ_H 0x4c + +int rk2928_hdmi_read_edid(int block, unsigned char *buff) +{ + int value, ret = -1, ddc_bus_freq = 0; + char interrupt = 0, trytime = 2; + unsigned long flags; + + hdmi_dbg(hdmi->dev, "[%s] block %d\n", __FUNCTION__, block); + spin_lock_irqsave(&hdmi->irq_lock, flags); + edid_result = 0; + spin_unlock_irqrestore(&hdmi->irq_lock, flags); + //Before Phy parameter was set, DDC_CLK is equal to PLLA freq which is 30MHz. + //Set DDC I2C CLK which devided from DDC_CLK to 100KHz. + + ddc_bus_freq = HDMI_DDC_CONFIG; + HDMIWrReg(DDC_BUS_FREQ_L, ddc_bus_freq & 0xFF); + HDMIWrReg(DDC_BUS_FREQ_H, (ddc_bus_freq >> 8) & 0xFF); + + // Enable edid interrupt + HDMIWrReg(INTERRUPT_MASK1, m_INT_HOTPLUG | m_INT_EDID_READY); + + while(trytime--) { + // Config EDID block and segment addr + HDMIWrReg(EDID_WORD_ADDR, (block%2) * 0x80); + HDMIWrReg(EDID_SEGMENT_POINTER, block/2); + + value = 10; + while(value--) + { + spin_lock_irqsave(&hdmi->irq_lock, flags); + interrupt = edid_result; + edid_result = 0; + spin_unlock_irqrestore(&hdmi->irq_lock, flags); + if(interrupt & (m_INT_EDID_READY)) + break; + msleep(10); + } + hdmi_dbg(hdmi->dev, "[%s] edid read value %d\n", __FUNCTION__, value); + if(interrupt & m_INT_EDID_READY) + { + for(value = 0; value < HDMI_EDID_BLOCK_SIZE; value++) + buff[value] = HDMIRdReg(EDID_FIFO_ADDR); + ret = 0; + + hdmi_dbg(hdmi->dev, "[%s] edid read sucess\n", __FUNCTION__); +#ifdef HDMI_DEBUG + for(value = 0; value < 128; value++) { + printk("%02x ,", buff[value]); + if( (value + 1) % 16 == 0) + printk("\n"); + } +#endif + break; + }else + hdmi_err(hdmi->dev, "[%s] edid read error\n", __FUNCTION__); + + } + // Disable edid interrupt + HDMIWrReg(INTERRUPT_MASK1, m_INT_HOTPLUG); +// msleep(100); + return ret; +} + +static void rk2928_hdmi_config_avi(unsigned char vic, unsigned char output_color) +{ + int i; + char info[SIZE_AVI_INFOFRAME]; + + memset(info, 0, SIZE_AVI_INFOFRAME); + HDMIWrReg(CONTROL_PACKET_BUF_INDEX, INFOFRAME_AVI); + info[0] = 0x82; + info[1] = 0x02; + info[2] = 0x0D; + info[3] = info[0] + info[1] + info[2]; + info[4] = (AVI_COLOR_MODE_RGB << 5); + info[5] = (AVI_COLORIMETRY_NO_DATA << 6) | (AVI_CODED_FRAME_ASPECT_NO_DATA << 4) | ACTIVE_ASPECT_RATE_SAME_AS_CODED_FRAME; + info[6] = 0; + info[7] = vic; + info[8] = 0; + + // Calculate AVI InfoFrame ChecKsum + for (i = 4; i < SIZE_AVI_INFOFRAME; i++) + { + info[3] += info[i]; + } + info[3] = 0x100 - info[3]; + + for(i = 0; i < SIZE_AVI_INFOFRAME; i++) + HDMIWrReg(CONTROL_PACKET_ADDR + i, info[i]); +} + +static int rk2928_hdmi_config_video(struct hdmi_video_para *vpara) +{ + int value; + struct fb_videomode *mode; + + hdmi_dbg(hdmi->dev, "[%s]\n", __FUNCTION__); + if(vpara == NULL) { + hdmi_err(hdmi->dev, "[%s] input parameter error\n", __FUNCTION__); + return -1; + } + + if(hdmi->hdcp_power_off_cb) + hdmi->hdcp_power_off_cb(); + // Diable video and audio output + HDMIWrReg(AV_MUTE, v_AUDIO_MUTE(1) | v_VIDEO_MUTE(1)); + + // Input video mode is SDR RGB24bit, Data enable signal from external + HDMIWrReg(VIDEO_CONTRL1, v_VIDEO_INPUT_FORMAT(VIDEO_INPUT_SDR_RGB444) | v_DE_EXTERNAL); + HDMIWrReg(VIDEO_CONTRL2, v_VIDEO_INPUT_BITS(VIDEO_INPUT_8BITS) | (vpara->output_color & 0xFF)); + + // Set HDMI Mode + HDMIWrReg(HDCP_CTRL, v_HDMI_DVI(vpara->output_mode)); + + // Enable or disalbe color space convert + if(vpara->input_color != vpara->output_color) { + value = v_SOF_DISABLE | v_CSC_ENABLE; + } + else + value = v_SOF_DISABLE; + HDMIWrReg(VIDEO_CONTRL3, value); + + // Set ext video +#if 1 + HDMIWrReg(VIDEO_TIMING_CTL, 0); + mode = (struct fb_videomode *)hdmi_vic_to_videomode(vpara->vic); + if(mode == NULL) + { + hdmi_err(hdmi->dev, "[%s] not found vic %d\n", __FUNCTION__, vpara->vic); + return -ENOENT; + } + hdmi->tmdsclk = mode->pixclock; +#else + value = v_EXTERANL_VIDEO(1) | v_INETLACE(mode->vmode); + if(mode->sync & FB_SYNC_HOR_HIGH_ACT) + value |= v_HSYNC_POLARITY(1); + if(mode->sync & FB_SYNC_VERT_HIGH_ACT) + value |= v_VSYNC_POLARITY(1); + HDMIWrReg(VIDEO_TIMING_CTL, value); + + value = mode->left_margin + mode->xres + mode->right_margin + mode->hsync_len; + HDMIWrReg(VIDEO_EXT_HTOTAL_L, value & 0xFF); + HDMIWrReg(VIDEO_EXT_HTOTAL_H, (value >> 8) & 0xFF); + + value = mode->left_margin + mode->right_margin + mode->hsync_len; + HDMIWrReg(VIDEO_EXT_HBLANK_L, value & 0xFF); + HDMIWrReg(VIDEO_EXT_HBLANK_H, (value >> 8) & 0xFF); + + value = mode->left_margin + mode->hsync_len; + HDMIWrReg(VIDEO_EXT_HDELAY_L, value & 0xFF); + HDMIWrReg(VIDEO_EXT_HDELAY_H, (value >> 8) & 0xFF); + + value = mode->hsync_len; + HDMIWrReg(VIDEO_EXT_HDURATION_L, value & 0xFF); + HDMIWrReg(VIDEO_EXT_HDURATION_H, (value >> 8) & 0xFF); + + value = mode->upper_margin + mode->yres + mode->lower_margin + mode->vsync_len; + HDMIWrReg(VIDEO_EXT_VTOTAL_L, value & 0xFF); + HDMIWrReg(VIDEO_EXT_VTOTAL_H, (value >> 8) & 0xFF); + + value = mode->upper_margin + mode->vsync_len + mode->lower_margin; + HDMIWrReg(VIDEO_EXT_VBLANK, value & 0xFF); + + if(vpara->vic == HDMI_720x480p_60Hz_4_3 || vpara->vic == HDMI_720x480p_60Hz_16_9) + value = 42; + else + value = mode->upper_margin + mode->vsync_len; + + HDMIWrReg(VIDEO_EXT_VDELAY, value & 0xFF); + + value = mode->vsync_len; + HDMIWrReg(VIDEO_EXT_VDURATION, value & 0xFF); +#endif + + if(vpara->output_mode == OUTPUT_HDMI) { + rk2928_hdmi_config_avi(vpara->vic, vpara->output_color); + hdmi_dbg(hdmi->dev, "[%s] sucess output HDMI.\n", __FUNCTION__); + } + else { + hdmi_dbg(hdmi->dev, "[%s] sucess output DVI.\n", __FUNCTION__); + } + // Power on TMDS + HDMIWrReg(PHY_PRE_EMPHASIS, v_PRE_EMPHASIS(0) | v_TMDS_PWRDOWN(0)); // TMDS power on + + // Enable TMDS + value = HDMIRdReg(PHY_DRIVER); + value |= v_TX_ENABLE(1); + HDMIWrReg(PHY_DRIVER, value); + + return 0; +} + +static void rk2928_hdmi_config_aai(void) +{ + int i; + char info[SIZE_AUDIO_INFOFRAME]; + + memset(info, 0, SIZE_AUDIO_INFOFRAME); + + info[0] = 0x84; + info[1] = 0x01; + info[2] = 0x0A; + + info[3] = info[0] + info[1] + info[2]; + for (i = 4; i < SIZE_AUDIO_INFOFRAME; i++) + info[3] += info[i]; + + info[3] = 0x100 - info[3]; + + HDMIWrReg(CONTROL_PACKET_BUF_INDEX, INFOFRAME_AAI); + for(i = 0; i < SIZE_AUDIO_INFOFRAME; i++) + HDMIWrReg(CONTROL_PACKET_ADDR + i, info[i]); +} + +static int rk2928_hdmi_config_audio(struct hdmi_audio *audio) +{ + int rate, N, channel, mclk_fs; + + if(audio->channel < 3) + channel = I2S_CHANNEL_1_2; + else if(audio->channel < 5) + channel = I2S_CHANNEL_3_4; + else if(audio->channel < 7) + channel = I2S_CHANNEL_5_6; + else + channel = I2S_CHANNEL_7_8; + + switch(audio->rate) + { + case HDMI_AUDIO_FS_32000: + rate = AUDIO_32K; + N = N_32K; + mclk_fs = MCLK_384FS; + break; + case HDMI_AUDIO_FS_44100: + rate = AUDIO_441K; + N = N_441K; + mclk_fs = MCLK_256FS; + break; + case HDMI_AUDIO_FS_48000: + rate = AUDIO_48K; + N = N_48K; + mclk_fs = MCLK_256FS; + break; + case HDMI_AUDIO_FS_88200: + rate = AUDIO_882K; + N = N_882K; + mclk_fs = MCLK_128FS; + break; + case HDMI_AUDIO_FS_96000: + rate = AUDIO_96K; + N = N_96K; + mclk_fs = MCLK_128FS; + break; + case HDMI_AUDIO_FS_176400: + rate = AUDIO_1764K; + N = N_1764K; + mclk_fs = MCLK_128FS; + break; + case HDMI_AUDIO_FS_192000: + rate = AUDIO_192K; + N = N_192K; + mclk_fs = MCLK_128FS; + break; + default: + dev_err(hdmi->dev, "[%s] not support such sample rate %d\n", __FUNCTION__, audio->rate); + return -ENOENT; + } + + //set_audio source I2S + HDMIWrReg(AUDIO_CTRL1, 0x00); //internal CTS, disable down sample, i2s input, disable MCLK + HDMIWrReg(AUDIO_SAMPLE_RATE, rate); + HDMIWrReg(AUDIO_I2S_MODE, v_I2S_MODE(I2S_STANDARD) | v_I2S_CHANNEL(channel) ); + HDMIWrReg(AUDIO_I2S_MAP, 0x00); + HDMIWrReg(AUDIO_I2S_SWAPS_SPDIF, 0); // no swap + + //Set N value + HDMIWrReg(AUDIO_N_H, (N >> 16) & 0x0F); + HDMIWrReg(AUDIO_N_M, (N >> 8) & 0xFF); + HDMIWrReg(AUDIO_N_L, N & 0xFF); + rk2928_hdmi_config_aai(); + + return 0; +} + +static void rk2928_hdmi_control_output(int enable) +{ + char mutestatus = 0; + + if(enable) { + mutestatus = HDMIRdReg(AV_MUTE); + if(mutestatus && (m_AUDIO_MUTE | m_VIDEO_BLACK)) { + HDMIWrReg(AV_MUTE, v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0)); + rk2928_hdmi_sys_power_up(); + rk2928_hdmi_sys_power_down(); + rk2928_hdmi_sys_power_up(); + if(analog_sync){ + HDMIWrReg(0xce, 0x00); + delay100us(); + HDMIWrReg(0xce, 0x01); + analog_sync = 0; + } + } + } + else { + HDMIWrReg(AV_MUTE, v_AUDIO_MUTE(1) | v_VIDEO_MUTE(1)); + } +} + +int rk2928_hdmi_removed(void) +{ + + dev_printk(KERN_INFO , hdmi->dev , "Removed.\n"); + rk2928_hdmi_set_pwr_mode(LOWER_PWR); + + return HDMI_ERROR_SUCESS; +} + + +irqreturn_t hdmi_irq(int irq, void *priv) +{ + char interrupt1 = 0; + unsigned long flags; + spin_lock_irqsave(&hdmi->irq_lock,flags); + interrupt1 = HDMIRdReg(INTERRUPT_STATUS1); + HDMIWrReg(INTERRUPT_STATUS1, interrupt1); +#if 1 + hdmi_dbg(hdmi->dev, "[%s] interrupt1 %02x interrupt2 %02x \n",\ + __FUNCTION__, interrupt1, interrupt2); +#endif + if(interrupt1 & m_INT_HOTPLUG ){ + if(hdmi->state == HDMI_SLEEP) + hdmi->state = WAIT_HOTPLUG; + if(hdmi->pwr_mode == LOWER_PWR) + rk2928_hdmi_set_pwr_mode(NORMAL); + queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, msecs_to_jiffies(10)); + }else if(interrupt1 & m_INT_EDID_READY) { + edid_result = interrupt1; + }else if(hdmi->state == HDMI_SLEEP) { + hdmi_dbg(hdmi->dev, "hdmi return to sleep mode\n"); + rk2928_hdmi_set_pwr_mode(LOWER_PWR); + } +#if 0 + if(hdmi->hdcp_irq_cb) + hdmi->hdcp_irq_cb(interrupt2); +#endif + spin_unlock_irqrestore(&hdmi->irq_lock,flags); + return IRQ_HANDLED; +} + +int rk2928_hdmi_initial(void) +{ + int rc = HDMI_ERROR_SUCESS; + + hdmi->pwr_mode = NORMAL; + hdmi->hdmi_removed = rk2928_hdmi_removed ; + hdmi->control_output = rk2928_hdmi_control_output; + hdmi->config_video = rk2928_hdmi_config_video; + hdmi->config_audio = rk2928_hdmi_config_audio; + hdmi->detect_hotplug = rk2928_hdmi_detect_hotplug; + hdmi->read_edid = rk2928_hdmi_read_edid; + // internal hclk = hdmi_hclk/20 + //HDMIWrReg(0x800, HDMI_INTERANL_CLK_DIV); + + if(hdmi->hdcp_power_on_cb) + rc = hdmi->hdcp_power_on_cb(); + + return rc; +} diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.h b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.h new file mode 100644 index 000000000000..6fd0f957a1ad --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.h @@ -0,0 +1,248 @@ +#ifndef _RK2928_HDMI_HW_H +#define _RK2928_HDMI_HW_H + +enum PWR_MODE{ + NORMAL, + LOWER_PWR, +}; +enum { + OUTPUT_DVI = 0, + OUTPUT_HDMI + }; +#define SYS_CTRL 0x00 + #define m_INT_POL (1 << 0) + #define m_POWER (1 << 1) + #define m_REG_CLK_SOURCE (1 << 2) + #define v_INT_POL_HIGH 1 + #define v_INT_POL_LOW 0 + #define v_PWR_ON (0 << 1) + #define v_PWR_OFF (1 << 1) + #define v_REG_CLK_SOURCE_TMDS (0 << 2) + #define v_REG_CLK_SOURCE_IIS (1 << 2) +#define VIDEO_CONTRL1 0x01 + #define m_VIDEO_INPUT_FORMAT (7 << 1) + #define m_DE_SOURCE (1 << 0) + enum { + VIDEO_INPUT_SDR_RGB444 = 0, + VIDEO_INPUT_DDR_RGB444 = 5, + VIDEO_INPUT_DDR_YCBCR422 = 6 + }; + #define v_VIDEO_INPUT_FORMAT(n) (n << 1) + #define v_DE_EXTERNAL 1 + #define v_DE_INTERANL 0 + +#define VIDEO_CONTRL2 0x02 + #define m_VIDEO_OUTPUT_FORMAT (3 << 6) + #define m_VIDEO_INPUT_BITS (3 << 4) + #define v_VIDEO_OUTPUT_FORMAT(n)(n << 6) + #define v_VIDEO_INPUT_BITS(n) (n << 4) + enum{ + VIDEO_INPUT_12BITS = 0, + VIDEO_INPUT_10BITS, + VIDEO_INPUT_8BITS + }; +#define VIDEO_CONTRL3 0x04 + #define m_SOF (1 << 3) + #define m_CSC (1 << 0) + #define v_SOF_ENABLE (0 << 3) + #define v_SOF_DISABLE (1 << 3) + #define v_CSC_ENABLE 1 + #define v_CSC_DISABLE 0 + +#define AV_MUTE 0x05 + #define m_AVMUTE_CLEAR (1 << 7) + #define m_AVMUTE_ENABLE (1 << 6) + #define m_AUDIO_MUTE (1 << 1) + #define m_VIDEO_BLACK (1 << 0) + #define v_AUDIO_MUTE(n) (n << 1) + #define v_VIDEO_MUTE(n) (n << 0) + +#define VIDEO_TIMING_CTL 0x08 + #define v_HSYNC_POLARITY(n) (n << 3) + #define v_VSYNC_POLARITY(n) (n << 2) + #define v_INETLACE(n) (n << 1) + #define v_EXTERANL_VIDEO(n) (n << 0) + +#define VIDEO_EXT_HTOTAL_L 0x09 +#define VIDEO_EXT_HTOTAL_H 0x0a +#define VIDEO_EXT_HBLANK_L 0x0b +#define VIDEO_EXT_HBLANK_H 0x0c +#define VIDEO_EXT_HDELAY_L 0x0d +#define VIDEO_EXT_HDELAY_H 0x0e +#define VIDEO_EXT_HDURATION_L 0x0f +#define VIDEO_EXT_HDURATION_H 0x10 +#define VIDEO_EXT_VTOTAL_L 0x11 +#define VIDEO_EXT_VTOTAL_H 0x12 +#define VIDEO_EXT_VBLANK 0x13 +#define VIDEO_EXT_VDELAY 0x14 +#define VIDEO_EXT_VDURATION 0x15 + +#define AUDIO_CTRL1 0x35 + enum { + CTS_SOURCE_INTERNAL = 0, + CTS_SOURCE_EXTERNAL + }; + #define v_CTS_SOURCE(n) (n << 7) + enum { + DOWNSAMPLE_DISABLE = 0, + DOWNSAMPLE_1_2, + DOWNSAMPLE_1_4 + }; + #define v_DOWN_SAMPLE(n) (n << 5) + enum { + AUDIO_SOURCE_IIS = 0, + AUDIO_SOURCE_SPDIF + }; + #define v_AUDIO_SOURCE(n) (n << 3) + #define v_MCLK_ENABLE(n) (n << 2) + enum { + MCLK_128FS = 0, + MCLK_256FS, + MCLK_384FS, + MCLK_512FS + }; + #define v_MCLK_RATIO(n) (n) + +#define AUDIO_SAMPLE_RATE 0x37 + enum { + AUDIO_32K = 0x3, + AUDIO_441K = 0x0, + AUDIO_48K = 0x2, + AUDIO_882K = 0x8, + AUDIO_96K = 0xa, + AUDIO_1764K = 0xc, + AUDIO_192K = 0xe, + }; + +#define AUDIO_I2S_MODE 0x38 + enum { + I2S_CHANNEL_1_2 = 1, + I2S_CHANNEL_3_4 = 3, + I2S_CHANNEL_5_6 = 7, + I2S_CHANNEL_7_8 = 0xf + }; + #define v_I2S_CHANNEL(n) ((n) << 2) + enum { + I2S_STANDARD = 0, + I2S_LEFT_JUSTIFIED, + I2S_RIGHT_JUSTIFIED + }; + #define v_I2S_MODE(n) (n) + +#define AUDIO_I2S_MAP 0x39 +#define AUDIO_I2S_SWAPS_SPDIF 0x3a + #define v_SPIDF_FREQ(n) (n) + +#define N_32K 0x1000 +#define N_441K 0x1880 +#define N_882K 0x3100 +#define N_1764K 0x6200 +#define N_48K 0x1800 +#define N_96K 0x3000 +#define N_192K 0x6000 + +#define AUDIO_N_H 0x3f +#define AUDIO_N_M 0x40 +#define AUDIO_N_L 0x41 + +#define AUDIO_CTS_H 0x45 +#define AUDIO_CTS_M 0x46 +#define AUDIO_CTS_L 0x47 + + +#define DDC_CLK_L 0x4b +#define DDC_CLK_H 0x4c + +#define EDID_SEGMENT_POINTER 0x4d +#define EDID_WORD_ADDR 0x4e +#define EDID_FIFO_OFFSET 0x4f +#define EDID_FIFO_ADDR 0x50 + +/* CONTROL_PACKET_BUF_INDEX */ +#define CONTROL_PACKET_BUF_INDEX 0x9f +enum { + INFOFRAME_AVI = 0x06, + INFOFRAME_AAI = 0x08 +}; +#define CONTROL_PACKET_ADDR 0xa0 + + +#define SIZE_AVI_INFOFRAME 0x11 // 14 bytes +#define SIZE_AUDIO_INFOFRAME 0x0F // 15 bytes +enum { + AVI_COLOR_MODE_RGB = 0, + AVI_COLOR_MODE_YCBCR422, + AVI_COLOR_MODE_YCBCR444 +}; +enum { + AVI_COLORIMETRY_NO_DATA = 0, + AVI_COLORIMETRY_SMPTE_170M, + AVI_COLORIMETRY_ITU709, + AVI_COLORIMETRY_EXTENDED +}; +enum { + AVI_CODED_FRAME_ASPECT_NO_DATA, + AVI_CODED_FRAME_ASPECT_4_3, + AVI_CODED_FRAME_ASPECT_16_9 +}; +enum { + ACTIVE_ASPECT_RATE_SAME_AS_CODED_FRAME = 0x08, + ACTIVE_ASPECT_RATE_4_3, + ACTIVE_ASPECT_RATE_16_9, + ACTIVE_ASPECT_RATE_14_9 +}; + +#define HDCP_CTRL 0x52 + #define m_HDMI_DVI (1 << 1) + #define v_HDMI_DVI(n) (n << 1) + +#define INTERRUPT_MASK1 0xc0 +#define INTERRUPT_STATUS1 0xc1 + #define m_INT_HOTPLUG (1 << 7) + #define m_INT_ACTIVE_VSYNC (1 << 6) + #define m_INT_EDID_READY (1 << 2) + +#define INTERRUPT_MASK2 0xc2 +#define INTERRUPT_STATUS2 0xc3 + #define m_INT_HDCP_ERR (1 << 7) + #define m_INT_BKSV_FLAG (1 << 6) + #define m_INT_HDCP_OK (1 << 4) + +#define HDMI_STATUS 0xc8 + #define m_HOTPLUG (1 << 7) + #define m_DDC_SDA (1 << 5) + #define m_DDC_SDC (1 << 4) + +#define PHY_SYNC 0xce //sync phy parameter + +#define PHY_DRIVER 0xe1 + #define v_MAIN_DRIVER(n) (n << 4) + #define v_PRE_DRIVER(n) (n << 2) + #define v_TX_ENABLE(n) (n << 1) + +#define PHY_PRE_EMPHASIS 0xe2 + #define v_PRE_EMPHASIS(n) (n << 4) + #define v_TMDS_PWRDOWN(n) (n) + +#define PHY_PLL_TEST 0xe3 +#define PHY_BANDGAP_PWR 0xe4 + #define v_BANDGAP_PWR_DOWN 0x03 + #define v_BANDGAP_PWR_UP 0 + +#define PHY_PLL_CTRL 0xe5 + #define v_PLL_DISABLE(n) (n << 4) + #define v_PLL_RESET(n) (n << 3) + #define v_TMDS_RESET(n) (n << 2) + +#define PHY_PLL_LDO_PWR 0xe7 + #define v_LDO_PWR_DOWN(n) (n << 2) + +#define HDMIRdReg(addr) __raw_readl(hdmi->regbase + addr) +#define HDMIWrReg(addr, val) __raw_writel((val), hdmi->regbase + addr); +#define HDMIMskReg(temp, addr, msk, val) \ + temp = __raw_readl(hdmi->regbase + addr) & (0xFF - (msk)) ; \ + __raw_writel(temp | ( (val) & (msk) ), hdmi->regbase + addr); + +extern int rk2928_hdmi_initial(void); + +#endif diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.hbak b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.hbak new file mode 100755 index 000000000000..fe06fe040278 --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.hbak @@ -0,0 +1,497 @@ +#ifndef __RK2928_HDMI_HW_H__ +#define __RK2928_HDMI_HW_H__ + + +//0x00 +#define INT_POL 1 +#define SYS_PWR_ON 0 +#define SYS_PWR_OFF 1 +#define PHY_CLK 0 +#define SYS_CLK 1 + +#define MCLK_FS 0x01 //256fs +//0x01 +// INPUT_VIDEO_FORMAT +#define RGB_YUV444 0x00 +#define DDR_RGB444_YUV444 0x05 +#define DDR_YUV422 0x06 + +//0x02 +//video output format +#define RGB444 0x00 +#define YUV444 0x01 +#define YUV422 0x02 + +//DATA WIDTH +#define DATA_12BIT 0X00 +#define DATA_10BIT 0X01 +#define DATA_8BIT 0X03 + +//0X04 +//1:after 0:not After 1st sof for external DE sample +#define DE_AFTER_SOF 0 +#define DE_NOAFTER_SOF 1 + +#define CSC_ENABLE 0 +#define CSC_DISABLE 1 + +//0X05 +#define CLEAR_AVMUTE(x) (x)<<7 +#define SET_AVMUTE(x) (x)<<6 +#define AUDIO_MUTE(x) (x)<<1 +#define VIDEO_BLACK(x) (x)<<0 //1:black 0:normal + +//0x08 +#define VSYNC_POL(x) (x)<<3 //0:Negative 1:Positive +#define HSYNC_POL(x) (x)<<2 //0:Negative 1:Positive +#define INTER_PROGRESSIVE(x) (x)<<1 //0: progressive 1:interlace +#define VIDEO_SET_ENABLE(x) (x)<<0 //0:disable 1: enable + +/* 0xe1 */ +//Main-driver strength :0000~1111: the strength from low to high +#define M_DRIVER_STR(x) (((x)&0xf)<<4) +//Pre-driver strength :00~11: the strength from low to high +#define P_DRIVER_STR(x) (((x)&3)<<2) +//TX driver enable 1: enable 0: disable +#define TX_DRIVER_EN(x) (((x)&1)<<1) +/* 0xe2 */ +//Pre-emphasis strength 00~11: the strength from 0 to high +#define P_EMPHASIS_STR(x) (((x)&3)<<4) +//Power down TMDS driver 1: power down. 0: not +#define PWR_DOWN_TMDS(x) (((x)&1)<<0) +/* 0xe3 */ +//PLL out enable. Just for test. need set to 1鈥檅0 +#define PLL_OUT_EN(x) (((x)&1)<<7) +/* 0xe4 */ +// Band-Gap power down 11: power down 00: not +#define BAND_PWR(x) (((x)&3)<<0) +/* 0xe5 */ +//PLL disable 1: disable 0: enable +#define PLL_PWR(x) (((x)&1)<<4) +// PLL reset 1: reset 0: not +#define PLL_RST(x) (((x)&1)<<3) +//PHY TMDS channels reset 1: reset 0: not +#define TMDS_RST(x) (((x)&1)<<2) +/* 0xe7 */ +// PLL LDO power down 1: power down 0: not +#define PLL_LDO_PWR(x) (((x)&1)<<2) + +enum PWR_MODE{ + NORMAL, + LOWER_PWR, +}; + +#if 0 +/* HDMI_SYS_CONTROL */ +#define SYS_CTRL 0x0 + +enum { + PWR_SAVE_MODE_A = 1, + PWR_SAVE_MODE_B = 2, + PWR_SAVE_MODE_D = 4, + PWR_SAVE_MODE_E = 8 +}; +#define m_PWR_SAVE_MODE 0xF0 +#define v_PWR_SAVE_MODE(n) (n << 4) +#define PLL_B_RESET (1 << 3) + +#define N_32K 0x1000 +#define N_441K 0x1880 +#define N_882K 0x3100 +#define N_1764K 0x6200 +#define N_48K 0x1800 +#define N_96K 0x3000 +#define N_192K 0x6000 + +#define LR_SWAP_N3 0x04 +#define N_2 0x08 +#define N_1 0x0c + +#define AUDIO_CTRL1 0x28 +#define AUDIO_CTRL2 0x2c +#define I2S_AUDIO_CTRL 0x30 +enum { + I2S_MODE_STANDARD = 0, + I2S_MODE_RIGHT_JUSTIFIED, + I2S_MODE_LEFT_JUSTIFIED +}; +#define v_I2S_MODE(n) n +enum { + I2S_CHANNEL_1_2 = 1, + I2S_CHANNEL_3_4 = 3, + I2S_CHANNEL_5_6 = 7, + I2S_CHANNEL_7_8 = 0xf +}; +#define v_I2S_CHANNEL(n) ( (n) << 2 ) + +#define I2S_INPUT_SWAP 0x40 + +#define SRC_NUM_AUDIO_LEN 0x50 + +/* HDMI_AV_CTRL1*/ +#define AV_CTRL1 0x54 +enum { + AUDIO_32K = 0x3, + AUDIO_441K = 0x0, + AUDIO_48K = 0x2, + AUDIO_882K = 0x8, + AUDIO_96K = 0xa, + AUDIO_1764K = 0xc, + AUDIO_192K = 0xe, +}; +#define m_AUDIO_SAMPLE_RATE 0xF0 +#define v_AUDIO_SAMPLE_RATE(n) (n << 4) +#define m_INPUT_VIDEO_MODE (7 << 1) +#define v_INPUT_VIDEO_MODE(n) (n << 1) +enum { + INTERNAL_DE = 0, + EXTERNAL_DE +}; +#define m_DE_SIGNAL_SELECT (1 << 0) + +/* HDMI_AV_CTRL2 */ +#define AV_CTRL2 0xec +#define m_CSC_ENABLE (1 << 0) +#define v_CSC_ENABLE(n) (n) + +/* HDMI_VIDEO_CTRL1 */ +#define VIDEO_CTRL1 0x58 + +#define m_VIDEO_OUTPUT_MODE (0x3 << 6) +#define v_VIDEO_OUTPUT_MODE(n) (n << 6) +enum { + VIDEO_INPUT_DEPTH_12BIT = 0, + VIDEO_INPUT_DEPTH_10BIT = 0x1, + VIDEO_INPUT_DEPTH_8BIT = 0x3 +}; +#define m_VIDEO_INPUT_DEPTH (3 << 4) +#define v_VIDEO_INPUT_DEPTH(n) (n << 4) +enum { + VIDEO_EMBEDDED_SYNC_LOCATION_0 = 0, + VIDEO_EMBEDDED_SYNC_LOCATION_1, + VIDEO_EMBEDDED_SYNC_LOCATION_2 +}; +#define m_VIDEO_EMBEDDED_SYNC_LOCATION (3 << 2) +#define VIDEO_EMBEDDED_SYNC_LOCATION(n) (n << 2) +#define m_VIDEO_INPUT_COLOR_MODE (1 << 0) + +/* DEEP_COLOR_MODE */ +#define DEEP_COLOR_MODE 0x5c +enum{ + TMDS_CLOCK_MODE_8BIT = 0, + TMDS_CLOKK_MODE_10BIT, + TMDS_CLOKK_MODE_12BIT +}; +#define TMDS_CLOCK_MODE_MASK 0x3 << 6 +#define TMDS_CLOCK_MODE(n) (n) << 6 + +/* VIDEO_CTRL2 */ +#define VIDEO_SETTING2 0x114 +#define m_UNMUTE (1 << 7) +#define m_MUTE (1 << 6) +#define m_AUDIO_RESET (1 << 2) +#define m_NOT_SEND_AUDIO (1 << 1) +#define m_NOT_SEND_VIDEO (1 << 0) +#define AV_UNMUTE (1 << 7) // Unmute video and audio, send normal video and audio data +#define AV_MUTE (1 << 6) // Mute video and audio, send black video data and silent audio data +#define AUDIO_CAPTURE_RESET (1 << 2) // Reset audio process logic, only available in pwr_e mode. +#define NOT_SEND_AUDIO (1 << 1) // Send silent audio data +#define NOT_SEND_VIDEO (1 << 0) // Send black video data + +/* Color Space Convertion Parameter*/ +#define CSC_PARA_C0_H 0x60 +#define CSC_PARA_C0_L 0x64 +#define CSC_PARA_C1_H 0x68 +#define CSC_PARA_C1_L 0x6c +#define CSC_PARA_C2_H 0x70 +#define CSC_PARA_C2_L 0x74 +#define CSC_PARA_C3_H 0x78 +#define CSC_PARA_C3_L 0x7c +#define CSC_PARA_C4_H 0x80 +#define CSC_PARA_C4_L 0x84 +#define CSC_PARA_C5_H 0x88 +#define CSC_PARA_C5_L 0x8c +#define CSC_PARA_C6_H 0x90 +#define CSC_PARA_C6_L 0x94 +#define CSC_PARA_C7_H 0x98 +#define CSC_PARA_C7_L 0x9c +#define CSC_PARA_C8_H 0xa0 +#define CSC_PARA_C8_L 0xa4 +#define CSC_PARA_C9_H 0xa8 +#define CSC_PARA_C9_L 0xac +#define CSC_PARA_C10_H 0xac +#define CSC_PARA_C10_L 0xb4 +#define CSC_PARA_C11_H 0xb8 +#define CSC_PARA_C11_L 0xbc + +#define CSC_CONFIG1 0x34c +#define m_CSC_MODE (1 << 7) +#define m_CSC_COEF_MODE (0xF << 3) //Only used in auto csc mode +#define m_CSC_STATUS (1 << 2) +#define m_CSC_VID_SELECT (1 << 1) +#define m_CSC_BRSWAP_DIABLE (1) + +enum { + CSC_MODE_MANUAL = 0, + CSC_MODE_AUTO +}; +#define v_CSC_MODE(n) (n << 7) +enum { + COE_SDTV_LIMITED_RANGE = 0x08, + COE_SDTV_FULL_RANGE = 0x04, + COE_HDTV_60Hz = 0x2, + COE_HDTV_50Hz = 0x1 +}; +#define v_CSC_COE_MODE(n) (n << 3) +enum { + CSC_INPUT_VID_5_19 = 0, + CSC_INPUT_VID_28_29 +}; +#define v_CSC_VID_SELECT(n) (n << 1) +#define v_CSC_BRSWAP_DIABLE(n) (n) +#endif +/* CONTROL_PACKET_BUF_INDEX */ +#define CONTROL_PACKET_BUF_INDEX 0x17c +enum { + INFOFRAME_AVI = 0x06, + INFOFRAME_AAI = 0x08 +}; +#define CONTROL_PACKET_HB0 0x180 +#define CONTROL_PACKET_HB1 0x184 +#define CONTROL_PACKET_HB2 0x188 +#define CONTROL_PACKET_PB_ADDR 0x18c +#define SIZE_AVI_INFOFRAME 0x11 // 17 bytes +#define SIZE_AUDIO_INFOFRAME 0x0F // 15 bytes +enum { + AVI_COLOR_MODE_RGB = 0, + AVI_COLOR_MODE_YCBCR422, + AVI_COLOR_MODE_YCBCR444 +}; +enum { + AVI_COLORIMETRY_NO_DATA = 0, + AVI_COLORIMETRY_SMPTE_170M, + AVI_COLORIMETRY_ITU709, + AVI_COLORIMETRY_EXTENDED +}; +enum { + AVI_CODED_FRAME_ASPECT_NO_DATA, + AVI_CODED_FRAME_ASPECT_4_3, + AVI_CODED_FRAME_ASPECT_16_9 +}; +enum { + ACTIVE_ASPECT_RATE_SAME_AS_CODED_FRAME = 0x08, + ACTIVE_ASPECT_RATE_4_3, + ACTIVE_ASPECT_RATE_16_9, + ACTIVE_ASPECT_RATE_14_9 +}; +#if 0 +/* External Video Parameter Setting*/ +#define EXT_VIDEO_PARA 0xC0 +#define m_VSYNC_OFFSET (0xF << 4) +#define m_VSYNC_POLARITY (1 << 3) +#define m_HSYNC_POLARITY (1 << 2) +#define m_INTERLACE (1 << 1) +#define m_EXT_VIDEO_ENABLE (1 << 0) + +#define v_VSYNC_OFFSET(n) (n << 4) +#define v_VSYNC_POLARITY(n) (n << 3) +#define v_HSYNC_POLARITY(n) (n << 2) +#define v_INTERLACE(n) (n << 1) +#define v_EXT_VIDEO_ENABLE(n) (n << 0) + +#define EXT_VIDEO_PARA_HTOTAL_L 0xC4 +#define EXT_VIDEO_PARA_HTOTAL_H 0xC8 +#define EXT_VIDEO_PARA_HBLANK_L 0xCC +#define EXT_VIDEO_PARA_HBLANK_H 0xD0 +#define EXT_VIDEO_PARA_HDELAY_L 0xD4 +#define EXT_VIDEO_PARA_HDELAY_H 0xD8 +#define EXT_VIDEO_PARA_HSYNCWIDTH_L 0xDC +#define EXT_VIDEO_PARA_HSYNCWIDTH_H 0xE0 + +#define EXT_VIDEO_PARA_VTOTAL_L 0xE4 +#define EXT_VIDEO_PARA_VTOTAL_H 0xE8 +#define EXT_VIDEO_PARA_VBLANK_L 0xF4 +#define EXT_VIDEO_PARA_VDELAY 0xF8 +#define EXT_VIDEO_PARA_VSYNCWIDTH 0xFC + +#define PHY_PLL_SPEED 0x158 + #define v_TEST_EN(n) (n << 6) + #define v_PLLA_BYPASS(n) (n << 4) + #define v_PLLB_SPEED(n) (n << 2) + #define v_PLLA_SPEED(n) (n) + enum { + PLL_SPEED_LOWEST = 0, + PLL_SPEED_MIDLOW, + PLL_SPEED_MIDHIGH, + PLL_SPEED_HIGHEST + }; + +#define PHY_PLL_17 0x15c // PLL A & B config bit 17 + #define v_PLLA_BIT17(n) (n << 2) + #define v_PLLB_BIT17(n) (n << 1) + +#define PHY_BGR 0x160 + #define v_BGR_DISCONNECT(n) (n << 7) + #define v_BGR_V_OFFSET(n) (n << 4) + #define v_BGR_I_OFFSET(n) (n) + +#define PHY_PLLA_1 0x164 +#define PHY_PLLA_2 0x168 +#define PHY_PLLB_1 0x16c +#define PHY_PLLB_2 0x170 + +#define PHY_DRIVER_PREEMPHASIS 0x174 + #define v_TMDS_SWING(n) (n << 4) + #define v_PRE_EMPHASIS(n) (n) + +#define PHY_PLL_16_AML 0x178 // PLL A & B config bit 16 and AML control + #define v_PLLA_BIT16(n) (n << 5) + #define v_PLLB_BIT16(n) (n << 4) + #define v_AML(n) (n) +#endif +/* Interrupt Setting */ +#define INTR_MASK1 0xc0 +#define INTR_STATUS1 0xc1 + #define m_INT_HOTPLUG (1 << 7) + #define m_INT_VSYNC (1 << 5) + #define m_INT_EDID_READY (1 << 2) + +#define INTR_MASK2 0xc2 +#define INTR_STATUS2 0xc3 + #define m_INT_HDCP_ERR (1 << 7) // HDCP error detected + #define m_INT_BKSV_RPRDY (1 << 6) // BKSV list ready from repeater + #define m_INT_AUTH_DONE (1 << 4) // HDCP authentication done + +#if 0 +#define DDC_READ_FIFO_ADDR 0x200 +#define DDC_BUS_FREQ_L 0x204 +#define DDC_BUS_FREQ_H 0x208 +#define DDC_BUS_CTRL 0x2dc +#define DDC_I2C_LEN 0x278 +#define DDC_I2C_OFFSET 0x280 +#define DDC_I2C_CTRL 0x284 +#define DDC_I2C_READ_BUF0 0x288 +#define DDC_I2C_READ_BUF1 0x28c +#define DDC_I2C_READ_BUF2 0x290 +#define DDC_I2C_READ_BUF3 0x294 +#define DDC_I2C_WRITE_BUF0 0x298 +#define DDC_I2C_WRITE_BUF1 0x29c +#define DDC_I2C_WRITE_BUF2 0x2a0 +#define DDC_I2C_WRITE_BUF3 0x2a4 +#define DDC_I2C_WRITE_BUF4 0x2ac +#define DDC_I2C_WRITE_BUF5 0x2b0 +#define DDC_I2C_WRITE_BUF6 0x2b4 + +#endif +#define EDID_SEGMENT_POINTER 0x4d +#define EDID_WORD_ADDR 0x4e +#define EDID_FIFO_ADDR 0x4f + +#define PIN_STATUS 0xc8 +#define m_HOTPLUG_STATUS (1 << 7) +#define m_DDCSDA_STATUS (1 << 5) +#define m_DDCSCL_STATUS (1 << 4) +#if 0 +/* HDCP_CTRL */ +#define HDCP_CTRL 0x2bc + enum { + OUTPUT_DVI = 0, + OUTPUT_HDMI + }; + #define m_HDCP_AUTH_START (1 << 7) // start hdcp + #define m_HDCP_BKSV_PASS (1 << 6) // bksv valid + #define m_HDCP_BKSV_FAILED (1 << 5) // bksv invalid + #define m_HDCP_FRAMED_ENCRYPED (1 << 4) + #define m_HDCP_AUTH_STOP (1 << 3) // stop hdcp + #define m_HDCP_ADV_CIPHER (1 << 2) // advanced cipher mode + #define m_HDMI_DVI (1 << 1) + #define m_HDCP_RESET (1 << 0) // reset hdcp + #define v_HDCP_AUTH_START(n) (n << 7) + #define v_HDCP_BKSV_PASS(n) (n << 6) + #define v_HDCP_BKSV_FAILED(n) (n << 5) + #define v_HDCP_FRAMED_ENCRYPED(n) (n << 4) + #define v_HDCP_AUTH_STOP(n) (n << 3) + #define v_HDCP_ADV_CIPHER(n) (n << 2) + #define v_HDMI_DVI(n) (n << 1) + #define v_HDCP_RESET(n) (n << 0) +#define HDCP_CTRL2 0x340 + +/* HDCP Key Memory Access Control */ +#define HDCP_KEY_ACCESS_CTRL1 0x338 +#define HDCP_KEY_ACCESS_CTRL2 0x33c + #define m_LOAD_FACSIMILE_HDCP_KEY (1 << 1) + #define m_LOAD_HDCP_KEY (1 << 0) +/* HDCP Key Memory Control */ +#define HDCP_KEY_MEM_CTRL 0x348 + #define m_USE_KEY1 (1 << 6) + #define m_USE_KEY2 (1 << 5) + #define m_LOAD_AKSV (1 << 4) + #define m_KSV_SELECTED (1 << 3) + #define m_KSV_VALID (1 << 2) + #define m_KEY_VALID (1 << 1) + #define m_KEY_READY (1 << 0) + #define v_USE_KEY1(n) (n << 6) + #define v_USE_KEY2(n) (n << 5) + #define v_LOAD_AKSV(n) (n << 4) + +/* HDCP B device capacity */ +#define HDCP_BCAPS 0x2f8 + #define m_HDMI_RECEIVED (1 << 7) //If HDCP receiver support HDMI, this bit must be 1. + #define m_REPEATER (1 << 6) + #define m_KSV_FIFO_READY (1 << 5) + #define m_DDC_FAST (1 << 4) + #define m_1_1_FEATURE (1 << 1) + #define m_FAST_REAUTHENTICATION (1 << 0) //For HDMI, this function is supported whether this bit is enabled or not. + +/* HDCP KSV Value */ +#define HDCP_KSV_BYTE0 0x2fc +#define HDCP_KSV_BYTE1 0x300 +#define HDCP_KSV_BYTE2 0x304 +#define HDCP_KSV_BYTE3 0x308 +#define HDCP_KSV_BYTE4 0x30c + +/* HDCP error status */ +#define HDCP_ERROR 0x320 + +/* HDCP 100 ms timer */ +#define HDCP_TIMER_100MS 0x324 +/* HDCP 5s timer */ +#define HDCP_TIMER_5S 0x328 + +/* HDCP Key ram address */ +#define HDCP_RAM_KEY_KSV1 0x400 +#define HDCP_RAM_KEY_KSV2 0x407 +#define HDCP_RAM_KEY_PRIVATE 0x40e +#define HDCP_KEY_LENGTH 0x13C + + +#define HDCP_ENABLE_HW_AUTH // Enable hardware authentication mode +#define HDMI_INTERANL_CLK_DIV 0x19 + +#define HDMIRdReg(addr) __raw_readl(hdmi->regbase + addr) +#define HDMIWrReg(addr, val) __raw_writel((val), hdmi->regbase + addr); +#define HDMIMskReg(temp, addr, msk, val) \ + temp = __raw_readl(hdmi->regbase + addr) & (0xFF - (msk)) ; \ + __raw_writel(temp | ( (val) & (msk) ), hdmi->regbase + addr); + + + +/* Color Space Convertion Mode */ +enum { + CSC_RGB_0_255_TO_ITU601_16_235 = 0, //RGB 0-255 input to YCbCr 16-235 output according BT601 + CSC_RGB_0_255_TO_ITU709_16_235, //RGB 0-255 input to YCbCr 16-235 output accroding BT709 + CSC_ITU601_16_235_TO_RGB_16_235, //YCbCr 16-235 input to RGB 16-235 output according BT601 + CSC_ITU709_16_235_TO_RGB_16_235, //YCbCr 16-235 input to RGB 16-235 output according BT709 + CSC_ITU601_16_235_TO_RGB_0_255, //YCbCr 16-235 input to RGB 0-255 output according BT601 + CSC_ITU709_16_235_TO_RGB_0_255 //YCbCr 16-235 input to RGB 0-255 output according BT709 +}; +#endif +extern int rk2928_hdmi_initial(void); +extern int rk2928_hdmi_detect_hotplug(void); +extern int rk2928_hdmi_read_edid(int block, unsigned char *buff); +extern int rk2928_hdmi_removed(void); +extern int rk2928_hdmi_config_video(struct hdmi_video_para *vpara); +extern int rk2928_hdmi_config_audio(struct hdmi_audio *audio); +extern void rk2928_hdmi_control_output(int enable); + +#endif diff --git a/drivers/video/rockchip/hdmi/chips/rk30/Kconfig b/drivers/video/rockchip/hdmi/chips/rk30/Kconfig new file mode 100755 index 000000000000..c33318d43622 --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/rk30/Kconfig @@ -0,0 +1,15 @@ +config HDMI_RK30_CTL_CODEC + bool "Mute Codec When HDMI Actived" + depends on HDMI_RK30 + default n + help + If you say y heres, Codec will be mute when hdmi inserted, + and unmute when removed. + +config HDMI_RK30_DEBUG + bool "RK30 HDMI Debugging" + depends on HDMI_RK30 && LCDC_RK30 + default n + help + Enableds verbose debugging the the HDMI drivers + diff --git a/drivers/video/rockchip/hdmi/chips/rk30/Makefile b/drivers/video/rockchip/hdmi/chips/rk30/Makefile new file mode 100755 index 000000000000..98dfae276674 --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/rk30/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for HDMI linux kernel module. +# + +ccflags-$(CONFIG_HDMI_RK30_DEBUG) = -DDEBUG -DHDMI_DEBUG + +obj-$(CONFIG_HDMI_RK30) += rk30_hdmi_hw.o rk30_hdmi.o +obj-$(CONFIG_HDCP_RK30) += hdcp/ diff --git a/drivers/video/rockchip/hdmi/chips/rk30/hdcp/Kconfig b/drivers/video/rockchip/hdmi/chips/rk30/hdcp/Kconfig new file mode 100755 index 000000000000..1bb3c3a24f56 --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/rk30/hdcp/Kconfig @@ -0,0 +1,14 @@ +config HDCP_RK30 + bool "RK30 HDCP support" + depends on LCDC_RK30 && HDMI_RK30 + default n + help + HDCP Interface. This adds the High Definition Content Protection Interface. + See http://www.digital-cp.com/ for HDCP specification. + +config HDCP_RK30_DEBUG + bool "RK30 HDCP Debugging" + depends on HDCP_RK30 + default n + help + Enableds verbose debugging the the HDCP drivers diff --git a/drivers/video/rockchip/hdmi/chips/rk30/hdcp/Makefile b/drivers/video/rockchip/hdmi/chips/rk30/hdcp/Makefile new file mode 100755 index 000000000000..108b67ca134e --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/rk30/hdcp/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for HDCP linux kernel module. +# + +ccflags-$(CONFIG_HDCP_RK30_DEBUG) = -DDEBUG -DHDCP_DEBUG + +obj-$(CONFIG_HDCP_RK30) += hdcp.o +hdcp-y := rk30_hdcp.o rk30_hdmi_hdcp.o diff --git a/drivers/video/rockchip/hdmi/chips/rk30/hdcp/rk30_hdcp.c b/drivers/video/rockchip/hdmi/chips/rk30/hdcp/rk30_hdcp.c new file mode 100755 index 000000000000..68d0ac841a67 --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/rk30/hdcp/rk30_hdcp.c @@ -0,0 +1,570 @@ +#include +#include +#include +#include +#include +#include +#include +#include "../rk30_hdmi.h" +#include "../rk30_hdmi_hw.h" +#include "rk30_hdmi_hdcp.h" + +struct hdcp *hdcp = NULL; + +static void hdcp_work_queue(struct work_struct *work); + +/*----------------------------------------------------------------------------- + * Function: hdcp_submit_work + *----------------------------------------------------------------------------- + */ +static struct delayed_work *hdcp_submit_work(int event, int delay) +{ + struct hdcp_delayed_work *work; + + DBG("%s event %04x delay %d", __FUNCTION__, event, delay); + + work = kmalloc(sizeof(struct hdcp_delayed_work), GFP_ATOMIC); + + if (work) { + INIT_DELAYED_WORK(&work->work, hdcp_work_queue); + work->event = event; + queue_delayed_work(hdcp->workqueue, + &work->work, + msecs_to_jiffies(delay)); + } else { + printk(KERN_WARNING "HDCP: Cannot allocate memory to " + "create work\n"); + return 0; + } + + return &work->work; +} + +/*----------------------------------------------------------------------------- + * Function: hdcp_cancel_work + *----------------------------------------------------------------------------- + */ +static void hdcp_cancel_work(struct delayed_work **work) +{ + int ret = 0; + + if (*work) { + ret = cancel_delayed_work(*work); + if (ret != 1) { + ret = cancel_work_sync(&((*work)->work)); + printk(KERN_INFO "Canceling work failed - " + "cancel_work_sync done %d\n", ret); + } + kfree(*work); + *work = 0; + } +} + +/*----------------------------------------------------------------------------- + * Function: hdcp_wq_authentication_failure + *----------------------------------------------------------------------------- + */ +static void hdcp_wq_authentication_failure(void) +{ + if (hdcp->hdmi_state == HDMI_STOPPED) { + return; + } + + rk30_hdcp_disable(); + rk30_hdmi_control_output(false); + + hdcp_cancel_work(&hdcp->pending_wq_event); + + if (hdcp->retry_cnt && (hdcp->hdmi_state != HDMI_STOPPED)) { + if (hdcp->retry_cnt < HDCP_INFINITE_REAUTH) { + hdcp->retry_cnt--; + printk(KERN_INFO "HDCP: authentication failed - " + "retrying, attempts=%d\n", + hdcp->retry_cnt); + } else + printk(KERN_INFO "HDCP: authentication failed - " + "retrying\n"); + + hdcp->hdcp_state = HDCP_AUTHENTICATION_START; + + hdcp->pending_wq_event = hdcp_submit_work(HDCP_AUTH_REATT_EVENT, + HDCP_REAUTH_DELAY); + } else { + printk(KERN_INFO "HDCP: authentication failed - " + "HDCP disabled\n"); + hdcp->hdcp_state = HDCP_ENABLE_PENDING; + } + +} + +/*----------------------------------------------------------------------------- + * Function: hdcp_wq_start_authentication + *----------------------------------------------------------------------------- + */ +static void hdcp_wq_start_authentication(void) +{ + int status = HDCP_OK; + + hdcp->hdcp_state = HDCP_AUTHENTICATION_START; + + DBG("HDCP: authentication start"); + + status = rk30_hdcp_start_authentication(); + + if (status != HDCP_OK) { + DBG("HDCP: authentication failed"); + hdcp_wq_authentication_failure(); + } else { + hdcp->hdcp_state = HDCP_WAIT_KSV_LIST; + } +} + +/*----------------------------------------------------------------------------- + * Function: hdcp_wq_check_bksv + *----------------------------------------------------------------------------- + */ +static void hdcp_wq_check_bksv(void) +{ + int status = HDCP_OK; + + DBG("Check BKSV start"); + + status = rk30_hdcp_check_bksv(); + + if (status != HDCP_OK) { + printk(KERN_INFO "HDCP: Check BKSV failed"); + hdcp->retry_cnt = 0; + hdcp_wq_authentication_failure(); + } + else { + DBG("HDCP: Check BKSV successful"); + + hdcp->hdcp_state = HDCP_LINK_INTEGRITY_CHECK; + + /* Restore retry counter */ + if(hdcp->retry_times == 0) + hdcp->retry_cnt = HDCP_INFINITE_REAUTH; + else + hdcp->retry_cnt = hdcp->retry_times; + } +} + +/*----------------------------------------------------------------------------- + * Function: hdcp_wq_authentication_sucess + *----------------------------------------------------------------------------- + */ +static void hdcp_wq_authentication_sucess(void) +{ + printk(KERN_INFO "HDCP: authentication pass"); + rk30_hdmi_control_output(true); +} + +/*----------------------------------------------------------------------------- + * Function: hdcp_wq_disable + *----------------------------------------------------------------------------- + */ +static void hdcp_wq_disable(int event) +{ + printk(KERN_INFO "HDCP: disabled"); + + hdcp_cancel_work(&hdcp->pending_wq_event); + rk30_hdcp_disable(); + if(event == HDCP_DISABLE_CTL) { + hdcp->hdcp_state = HDCP_DISABLED; + if(hdcp->hdmi_state == HDMI_STARTED) + rk30_hdmi_control_output(true); + } + else if(event == HDCP_STOP_FRAME_EVENT) + hdcp->hdcp_state = HDCP_ENABLE_PENDING; +} + +/*----------------------------------------------------------------------------- + * Function: hdcp_work_queue + *----------------------------------------------------------------------------- + */ +static void hdcp_work_queue(struct work_struct *work) +{ + struct hdcp_delayed_work *hdcp_w = + container_of(work, struct hdcp_delayed_work, work.work); + int event = hdcp_w->event; + + mutex_lock(&hdcp->lock); + + DBG("hdcp_work_queue() - START - %u hdmi=%d hdcp=%d evt= %x %d", + jiffies_to_msecs(jiffies), + hdcp->hdmi_state, + hdcp->hdcp_state, + (event & 0xFF00) >> 8, + event & 0xFF); + + if(event == HDCP_STOP_FRAME_EVENT) { + hdcp->hdmi_state = HDMI_STOPPED; + } + + if (event == HDCP_DISABLE_CTL || event == HDCP_STOP_FRAME_EVENT) { + hdcp_wq_disable(event); + } + + if (event & HDCP_WORKQUEUE_SRC) + hdcp->pending_wq_event = 0; + + /* First handle HDMI state */ + if (event == HDCP_START_FRAME_EVENT) { + hdcp->pending_start = 0; + hdcp->hdmi_state = HDMI_STARTED; + } + + /**********************/ + /* HDCP state machine */ + /**********************/ + switch (hdcp->hdcp_state) { + case HDCP_DISABLED: + /* HDCP enable control or re-authentication event */ + if (event == HDCP_ENABLE_CTL) { + if(hdcp->retry_times == 0) + hdcp->retry_cnt = HDCP_INFINITE_REAUTH; + else + hdcp->retry_cnt = hdcp->retry_times; + if (hdcp->hdmi_state == HDMI_STARTED) + hdcp_wq_start_authentication(); + else + hdcp->hdcp_state = HDCP_ENABLE_PENDING; + } + break; + + case HDCP_ENABLE_PENDING: + /* HDMI start frame event */ + if (event == HDCP_START_FRAME_EVENT) + hdcp_wq_start_authentication(); + + break; + + case HDCP_AUTHENTICATION_START: + /* Re-authentication */ + if (event == HDCP_AUTH_REATT_EVENT) + hdcp_wq_start_authentication(); + + break; + + case HDCP_WAIT_KSV_LIST: + /* KSV failure */ + if (event == HDCP_FAIL_EVENT) { + printk(KERN_INFO "HDCP: KSV switch failure\n"); + + hdcp_wq_authentication_failure(); + } + /* KSV list ready event */ + else if (event == HDCP_KSV_LIST_RDY_EVENT) + hdcp_wq_check_bksv(); + break; + + case HDCP_LINK_INTEGRITY_CHECK: + /* Ri failure */ + if (event == HDCP_FAIL_EVENT) { + printk(KERN_INFO "HDCP: Ri check failure\n"); + hdcp_wq_authentication_failure(); + } + else if(event == HDCP_AUTH_PASS_EVENT) + hdcp_wq_authentication_sucess(); + break; + + default: + printk(KERN_WARNING "HDCP: error - unknow HDCP state\n"); + break; + } + + kfree(hdcp_w); + if(event == HDCP_STOP_FRAME_EVENT) + complete(&hdcp->complete); + + mutex_unlock(&hdcp->lock); +} + +/*----------------------------------------------------------------------------- + * Function: hdcp_start_frame_cb + *----------------------------------------------------------------------------- + */ +static void hdcp_start_frame_cb(void) +{ + DBG("hdcp_start_frame_cb()"); + + /* Cancel any pending work */ + if (hdcp->pending_start) + hdcp_cancel_work(&hdcp->pending_start); + if (hdcp->pending_wq_event) + hdcp_cancel_work(&hdcp->pending_wq_event); + + hdcp->pending_start = hdcp_submit_work(HDCP_START_FRAME_EVENT, + HDCP_ENABLE_DELAY); +} + +/*----------------------------------------------------------------------------- + * Function: hdcp_irq_cb + *----------------------------------------------------------------------------- + */ +static void hdcp_irq_cb(int interrupt) +{ + int value; + DBG("%s 0x%x", __FUNCTION__, interrupt); + if(interrupt & m_INT_HDCP_ERR) + { + value = HDMIRdReg(HDCP_ERROR); + HDMIWrReg(HDCP_ERROR, value); + printk(KERN_INFO "HDCP: Error 0x%02x\n", value); + + if( (hdcp->hdcp_state != HDCP_DISABLED) && + (hdcp->hdcp_state != HDCP_ENABLE_PENDING) ) + { + hdcp_submit_work(HDCP_FAIL_EVENT, 0); + } + } + else if(interrupt & (m_INT_BKSV_RPRDY | m_INT_BKSV_RCRDY)) + hdcp_submit_work(HDCP_KSV_LIST_RDY_EVENT, 0); + else if(interrupt & m_INT_AUTH_DONE) + hdcp_submit_work(HDCP_AUTH_PASS_EVENT, 0); +} + +/*----------------------------------------------------------------------------- + * Function: hdcp_power_on_cb + *----------------------------------------------------------------------------- + */ +static int hdcp_power_on_cb(void) +{ + DBG("%s", __FUNCTION__); + return rk30_hdcp_load_key2mem(hdcp->keys); +} + +/*----------------------------------------------------------------------------- + * Function: hdcp_power_off_cb + *----------------------------------------------------------------------------- + */ +static void hdcp_power_off_cb(void) +{ + DBG("%s", __FUNCTION__); + if(!hdcp->enable) + return; + + hdcp_cancel_work(&hdcp->pending_start); + hdcp_cancel_work(&hdcp->pending_wq_event); + init_completion(&hdcp->complete); + /* Post event to workqueue */ + if (hdcp_submit_work(HDCP_STOP_FRAME_EVENT, 0)) + wait_for_completion_interruptible_timeout(&hdcp->complete, + msecs_to_jiffies(2000)); +} + +// Load HDCP key to external HDCP memory +static void hdcp_load_keys_cb(const struct firmware *fw, void *context) +{ + if (!fw) { + pr_err("HDCP: failed to load keys\n"); + return; + } + + if(fw->size < HDCP_KEY_SIZE) { + pr_err("HDCP: firmware wrong size %d\n", fw->size); + return; + } + + hdcp->keys = kmalloc(HDCP_KEY_SIZE, GFP_KERNEL); + if(hdcp->keys == NULL) { + pr_err("HDCP: can't allocated space for keys\n"); + return; + } + + memcpy(hdcp->keys, fw->data, HDCP_KEY_SIZE); + + rk30_hdcp_load_key2mem(hdcp->keys); + printk(KERN_INFO "HDCP: loaded hdcp key success\n"); + + if(fw->size > HDCP_KEY_SIZE) { + DBG("%s invalid key size %d", __FUNCTION__, fw->size - HDCP_KEY_SIZE); + if((fw->size - HDCP_KEY_SIZE) % 5) { + pr_err("HDCP: failed to load invalid keys\n"); + return; + } + hdcp->invalidkeys = kmalloc(fw->size - HDCP_KEY_SIZE, GFP_KERNEL); + if(hdcp->invalidkeys == NULL) { + pr_err("HDCP: can't allocated space for invalid keys\n"); + return; + } + memcpy(hdcp->invalidkeys, fw->data + HDCP_KEY_SIZE, fw->size - HDCP_KEY_SIZE); + hdcp->invalidkey = (fw->size - HDCP_KEY_SIZE)/5; + printk(KERN_INFO "HDCP: loaded hdcp invalid key success\n"); + } +} + +static ssize_t hdcp_enable_read(struct device *device, + struct device_attribute *attr, char *buf) +{ + int enable = 0; + + if(hdcp) + enable = hdcp->enable; + + return snprintf(buf, PAGE_SIZE, "%d\n", enable); +} + +static ssize_t hdcp_enable_write(struct device *device, + struct device_attribute *attr, const char *buf, size_t count) +{ + int enable; + + if(hdcp == NULL) + return -EINVAL; + + sscanf(buf, "%d", &enable); + if(hdcp->enable != enable) + { + /* Post event to workqueue */ + if(enable) { + if (hdcp_submit_work(HDCP_ENABLE_CTL, 0) == 0) + return -EFAULT; + } + else { + hdcp_cancel_work(&hdcp->pending_start); + hdcp_cancel_work(&hdcp->pending_wq_event); + + /* Post event to workqueue */ + if (hdcp_submit_work(HDCP_DISABLE_CTL, 0) == 0) + return -EFAULT; + } + hdcp->enable = enable; + } + return count; +} + +static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR, hdcp_enable_read, hdcp_enable_write); + +static ssize_t hdcp_trytimes_read(struct device *device, + struct device_attribute *attr, char *buf) +{ + int trytimes = 0; + + if(hdcp) + trytimes = hdcp->retry_times; + + return snprintf(buf, PAGE_SIZE, "%d\n", trytimes); +} + +static ssize_t hdcp_trytimes_wrtie(struct device *device, + struct device_attribute *attr, const char *buf, size_t count) +{ + int trytimes; + + if(hdcp == NULL) + return -EINVAL; + + sscanf(buf, "%d", &trytimes); + if(hdcp->retry_times != trytimes) + hdcp->retry_times = trytimes; + + return count; +} + + +static DEVICE_ATTR(trytimes, S_IRUGO|S_IWUSR, hdcp_trytimes_read, hdcp_trytimes_wrtie); + + +static struct miscdevice mdev; + +static int __init rk30_hdcp_init(void) +{ + int ret; + + DBG("[%s] %u", __FUNCTION__, jiffies_to_msecs(jiffies)); + + hdcp = kmalloc(sizeof(struct hdcp), GFP_KERNEL); + if(!hdcp) + { + printk(KERN_ERR ">>HDCP: kmalloc fail!"); + ret = -ENOMEM; + goto error0; + } + memset(hdcp, 0, sizeof(struct hdcp)); + mutex_init(&hdcp->lock); + + mdev.minor = MISC_DYNAMIC_MINOR; + mdev.name = "hdcp"; + mdev.mode = 0666; + if (misc_register(&mdev)) { + printk(KERN_ERR "HDCP: Could not add character driver\n"); + ret = HDMI_ERROR_FALSE; + goto error1; + } + ret = device_create_file(mdev.this_device, &dev_attr_enable); + if(ret) + { + printk(KERN_ERR "HDCP: Could not add sys file enable\n"); + ret = -EINVAL; + goto error2; + } + + ret = device_create_file(mdev.this_device, &dev_attr_trytimes); + if(ret) + { + printk(KERN_ERR "HDCP: Could not add sys file trytimes\n"); + ret = -EINVAL; + goto error3; + } + + hdcp->workqueue = create_singlethread_workqueue("hdcp"); + if (hdcp->workqueue == NULL) { + printk(KERN_ERR "HDCP,: create workqueue failed.\n"); + goto error4; + } + + + ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG, + "hdcp.keys", mdev.this_device, GFP_KERNEL, + hdcp, hdcp_load_keys_cb); + if (ret < 0) { + printk(KERN_ERR "HDCP: request_firmware_nowait failed: %d\n", ret); + goto error5; + } + + rk30_hdmi_register_hdcp_callbacks( hdcp_start_frame_cb, + hdcp_irq_cb, + hdcp_power_on_cb, + hdcp_power_off_cb); + + DBG("%s success %u", __FUNCTION__, jiffies_to_msecs(jiffies)); + return 0; + +error5: + destroy_workqueue(hdcp->workqueue); +error4: + device_remove_file(mdev.this_device, &dev_attr_trytimes); +error3: + device_remove_file(mdev.this_device, &dev_attr_enable); +error2: + misc_deregister(&mdev); +error1: + if(hdcp->keys) + kfree(hdcp->keys); + if(hdcp->invalidkeys) + kfree(hdcp->invalidkeys); + kfree(hdcp); +error0: + return ret; +} + +static void __exit rk30_hdcp_exit(void) +{ + if(hdcp) { + mutex_lock(&hdcp->lock); + rk30_hdmi_register_hdcp_callbacks(0, 0, 0, 0); + device_remove_file(mdev.this_device, &dev_attr_enable); + misc_deregister(&mdev); + destroy_workqueue(hdcp->workqueue); + if(hdcp->keys) + kfree(hdcp->keys); + if(hdcp->invalidkeys) + kfree(hdcp->invalidkeys); + mutex_unlock(&hdcp->lock); + kfree(hdcp); + } +} + +module_init(rk30_hdcp_init); +module_exit(rk30_hdcp_exit); \ No newline at end of file diff --git a/drivers/video/rockchip/hdmi/chips/rk30/hdcp/rk30_hdmi_hdcp.c b/drivers/video/rockchip/hdmi/chips/rk30/hdcp/rk30_hdmi_hdcp.c new file mode 100755 index 000000000000..1184989a57b2 --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/rk30/hdcp/rk30_hdmi_hdcp.c @@ -0,0 +1,157 @@ +#include +#include +#include +#include "../rk30_hdmi.h" +#include "../rk30_hdmi_hw.h" +#include "rk30_hdmi_hdcp.h" + +static void rk30_hdcp_write_mem(int addr_8, char value) +{ + int temp; + int addr_32 = addr_8 - addr_8%4; + int shift = (addr_8%4) * 8; + + temp = HDMIRdReg(addr_32); + temp &= ~(0xff << shift); + temp |= value << shift; +// printk("temp is %08x\n", temp); + HDMIWrReg(addr_32, temp); +} + +int rk30_hdcp_load_key2mem(struct hdcp_keys *key) +{ + int i; + + if(key == NULL) return HDMI_ERROR_FALSE; + + HDMIWrReg(0x800, HDMI_INTERANL_CLK_DIV); + + for(i = 0; i < 7; i++) + rk30_hdcp_write_mem(HDCP_RAM_KEY_KSV1 + i, key->KSV[i]); + for(i = 0; i < 7; i++) + rk30_hdcp_write_mem(HDCP_RAM_KEY_KSV2 + i, key->KSV[i]); + for(i = 0; i < HDCP_PRIVATE_KEY_SIZE; i++) + rk30_hdcp_write_mem(HDCP_RAM_KEY_PRIVATE + i, key->DeviceKey[i]); + for(i = 0; i < HDCP_KEY_SHA_SIZE; i++) + rk30_hdcp_write_mem(HDCP_RAM_KEY_PRIVATE + HDCP_PRIVATE_KEY_SIZE + i, key->sha1[i]); + + HDMIWrReg(0x800, HDMI_INTERANL_CLK_DIV | 0x20); + return HDCP_OK; +} + +void rk30_hdcp_disable(void) +{ + int temp; + // Diable HDCP Interrupt + HDMIWrReg(INTR_MASK2, 0x00); + // Stop and Reset HDCP + HDMIMskReg(temp, HDCP_CTRL, m_HDCP_FRAMED_ENCRYPED | m_HDCP_AUTH_STOP | m_HDCP_RESET, + v_HDCP_FRAMED_ENCRYPED(0) | v_HDCP_AUTH_STOP(1) | v_HDCP_RESET(1) ); +} + +static int rk30_hdcp_load_key(void) +{ + int value, temp = 0; + + if(hdcp->keys == NULL) { + pr_err("[%s] HDCP key not loaded.\n", __FUNCTION__); + return HDCP_KEY_ERR; + } + + value = HDMIRdReg(HDCP_KEY_MEM_CTRL); + //Check HDCP key loaded from external HDCP memory + while((value & (m_KSV_VALID | m_KEY_VALID | m_KEY_READY)) != (m_KSV_VALID | m_KEY_VALID | m_KEY_READY)) { + if(temp > 10) { + pr_err("[%s] loaded hdcp key is incorrectable %02x\n", __FUNCTION__, value & 0xFF); + return HDCP_KEY_ERR; + } + //Load HDCP Key from external HDCP memory + HDMIWrReg(HDCP_KEY_ACCESS_CTRL2, m_LOAD_HDCP_KEY); + msleep(1); + value = HDMIRdReg(HDCP_KEY_MEM_CTRL); + temp++; + } + + return HDCP_OK; +} + + +int rk30_hdcp_start_authentication(void) +{ + int rc, temp; + + rc = rk30_hdcp_load_key(); + if(rc != HDCP_OK) + return rc; + + // Set 100ms & 5 sec timer + switch(hdmi->vic) + { + case HDMI_720x576p_50Hz_4_3: + case HDMI_720x576p_50Hz_16_9: + case HDMI_1280x720p_50Hz: + case HDMI_1920x1080i_50Hz: + case HDMI_720x576i_50Hz_4_3: + case HDMI_720x576i_50Hz_16_9: + case HDMI_1920x1080p_50Hz: + HDMIWrReg(HDCP_TIMER_100MS, 5); + HDMIWrReg(HDCP_TIMER_5S, 250); + break; + + default: + HDMIWrReg(HDCP_TIMER_100MS, 0x26); + HDMIWrReg(HDCP_TIMER_5S, 0x2c); + break; + } + // Config DDC Clock + temp = (hdmi->tmdsclk/HDCP_DDC_CLK)/4; + HDMIWrReg(DDC_BUS_FREQ_L, temp & 0xFF); + HDMIWrReg(DDC_BUS_FREQ_H, (temp >> 8) & 0xFF); + // Enable HDCP Interrupt + HDMIWrReg(INTR_MASK2, m_INT_HDCP_ERR | m_INT_BKSV_RPRDY | m_INT_BKSV_RCRDY | m_INT_AUTH_DONE | m_INT_AUTH_READY); + // Start HDCP + HDMIMskReg(temp, HDCP_CTRL, m_HDCP_AUTH_START | m_HDCP_FRAMED_ENCRYPED, v_HDCP_AUTH_START(1) | v_HDCP_FRAMED_ENCRYPED(0)); + + return HDCP_OK; +} + +int rk30_hdcp_check_bksv(void) +{ + int i, temp; + char bksv[5]; + char *invalidkey; + + temp = HDMIRdReg(HDCP_BCAPS); + DBG("Receiver capacity is 0x%02x", temp); + +#ifdef DEBUG + if(temp & m_HDMI_RECEIVED) + DBG("Receiver support HDMI"); + if(temp & m_REPEATER) + DBG("Receiver is a repeater"); + if(temp & m_DDC_FAST) + DBG("Receiver support 400K DDC"); + if(temp & m_1_1_FEATURE) + DBG("Receiver support 1.1 features, such as advanced cipher, EESS."); + if(temp & m_FAST_REAUTHENTICATION) + DBG("Receiver support fast reauthentication."); +#endif + + for(i = 0; i < 5; i++) { + bksv[i] = HDMIRdReg(HDCP_KSV_BYTE0 + (4 - i)*4) & 0xFF; + } + + DBG("bksv is 0x%02x%02x%02x%02x%02x", bksv[0], bksv[1], bksv[2], bksv[3], bksv[4]); + + for(i = 0; i < hdcp->invalidkey; i++) + { + invalidkey = hdcp->invalidkeys + i *5; + if(memcmp(bksv, invalidkey, 5) == 0) { + printk(KERN_ERR "HDCP: BKSV was revocated!!!\n"); + HDMIMskReg(temp, HDCP_CTRL, m_HDCP_BKSV_FAILED | m_HDCP_FRAMED_ENCRYPED, v_HDCP_BKSV_FAILED(1) | v_HDCP_FRAMED_ENCRYPED(0)); + return HDCP_KSV_ERR; + } + } + HDMIMskReg(temp, HDCP_CTRL, m_HDCP_BKSV_PASS | m_HDCP_FRAMED_ENCRYPED, v_HDCP_BKSV_PASS(1) | v_HDCP_FRAMED_ENCRYPED(1)); + return HDCP_OK; +} diff --git a/drivers/video/rockchip/hdmi/chips/rk30/hdcp/rk30_hdmi_hdcp.h b/drivers/video/rockchip/hdmi/chips/rk30/hdcp/rk30_hdmi_hdcp.h new file mode 100755 index 000000000000..0224d88ab134 --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/rk30/hdcp/rk30_hdmi_hdcp.h @@ -0,0 +1,99 @@ +#ifndef __RK30_HDMI_HDCP_H__ +#define __RK30_HDMI_HDCP_H__ + +/***************************/ +/* Definitions */ +/***************************/ + +/* Status / error codes */ +#define HDCP_OK 0 +#define HDCP_KEY_ERR 1 +#define HDCP_KSV_ERR 2 + +/* Delays */ +#define HDCP_ENABLE_DELAY 300 +#define HDCP_REAUTH_DELAY 100 + +/* Event source */ +#define HDCP_SRC_SHIFT 8 +#define HDCP_IOCTL_SRC (0x1 << HDCP_SRC_SHIFT) +#define HDCP_HDMI_SRC (0x2 << HDCP_SRC_SHIFT) +#define HDCP_IRQ_SRC (0x4 << HDCP_SRC_SHIFT) +#define HDCP_WORKQUEUE_SRC (0x8 << HDCP_SRC_SHIFT) + +/* Event */ +#define HDCP_ENABLE_CTL (HDCP_IOCTL_SRC | 0) +#define HDCP_DISABLE_CTL (HDCP_IOCTL_SRC | 1) +#define HDCP_START_FRAME_EVENT (HDCP_HDMI_SRC | 2) +#define HDCP_STOP_FRAME_EVENT (HDCP_HDMI_SRC | 3) +#define HDCP_KSV_LIST_RDY_EVENT (HDCP_IRQ_SRC | 4) +#define HDCP_FAIL_EVENT (HDCP_IRQ_SRC | 5) +#define HDCP_AUTH_PASS_EVENT (HDCP_IRQ_SRC | 6) +#define HDCP_AUTH_REATT_EVENT (HDCP_WORKQUEUE_SRC | 7) + +/* Key size */ +#define HDCP_KEY_SIZE 308 + +/* Authentication retry times */ +#define HDCP_INFINITE_REAUTH 0x100 + +enum hdcp_states { + HDCP_DISABLED, + HDCP_ENABLE_PENDING, + HDCP_AUTHENTICATION_START, + HDCP_WAIT_KSV_LIST, + HDCP_LINK_INTEGRITY_CHECK, +}; + +enum hdmi_states { + HDMI_STOPPED, + HDMI_STARTED +}; + +#define HDCP_PRIVATE_KEY_SIZE 280 +#define HDCP_KEY_SHA_SIZE 20 +#define HDCP_DDC_CLK 100000 + +struct hdcp_keys{ + u8 KSV[8]; + u8 DeviceKey[HDCP_PRIVATE_KEY_SIZE]; + u8 sha1[HDCP_KEY_SHA_SIZE]; +}; + +struct hdcp_delayed_work { + struct delayed_work work; + int event; +}; + +struct hdcp { + int enable; + int retry_times; + struct hdcp_keys *keys; + int invalidkey; + char *invalidkeys; + struct mutex lock; + struct completion complete; + struct workqueue_struct *workqueue; + + enum hdmi_states hdmi_state; + enum hdcp_states hdcp_state; + + struct delayed_work *pending_start; + struct delayed_work *pending_wq_event; + int retry_cnt; +}; + +extern struct hdcp *hdcp; + +#ifdef HDCP_DEBUG +#define DBG(format, ...) \ + printk(KERN_INFO "HDCP: " format "\n", ## __VA_ARGS__) +#else +#define DBG(format, ...) +#endif + +extern void rk30_hdcp_disable(void); +extern int rk30_hdcp_start_authentication(void); +extern int rk30_hdcp_check_bksv(void); +extern int rk30_hdcp_load_key2mem(struct hdcp_keys *key); +#endif /* __RK30_HDMI_HDCP_H__ */ \ No newline at end of file diff --git a/drivers/video/rockchip/hdmi/rk30_hdmi.c b/drivers/video/rockchip/hdmi/chips/rk30/rk30_hdmi.c similarity index 100% rename from drivers/video/rockchip/hdmi/rk30_hdmi.c rename to drivers/video/rockchip/hdmi/chips/rk30/rk30_hdmi.c diff --git a/drivers/video/rockchip/hdmi/chips/rk30/rk30_hdmi.h b/drivers/video/rockchip/hdmi/chips/rk30/rk30_hdmi.h new file mode 100755 index 000000000000..4695086bf329 --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/rk30/rk30_hdmi.h @@ -0,0 +1,11 @@ +#ifndef __RK30_HDMI_H__ +#define __RK30_HDMI_H__ + +#include "../../rk_hdmi.h" + + +extern int rk30_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void), + void (*hdcp_irq_cb)(int status), + int (*hdcp_power_on_cb)(void), + void (*hdcp_power_off_cb)(void)); +#endif /* __RK30_HDMI_H__ */ diff --git a/drivers/video/rockchip/hdmi/rk30_hdmi_hw.c b/drivers/video/rockchip/hdmi/chips/rk30/rk30_hdmi_hw.c similarity index 97% rename from drivers/video/rockchip/hdmi/rk30_hdmi_hw.c rename to drivers/video/rockchip/hdmi/chips/rk30/rk30_hdmi_hw.c index 8cb76ebfb14d..e8b5f1e74b74 100755 --- a/drivers/video/rockchip/hdmi/rk30_hdmi_hw.c +++ b/drivers/video/rockchip/hdmi/chips/rk30/rk30_hdmi_hw.c @@ -14,6 +14,14 @@ static inline void delay100us(void) int rk30_hdmi_initial(void) { int rc = HDMI_ERROR_SUCESS; + + hdmi->pwr_mode = PWR_SAVE_MODE_A; + hdmi->hdmi_removed = rk30_hdmi_removed ; + hdmi->control_output = rk30_hdmi_control_output; + hdmi->config_video = rk30_hdmi_config_video; + hdmi->config_audio = rk30_hdmi_config_audio; + hdmi->detect_hotplug = rk30_hdmi_detect_hotplug; + hdmi->read_edid = rk30_hdmi_read_edid; // internal hclk = hdmi_hclk/20 HDMIWrReg(0x800, HDMI_INTERANL_CLK_DIV); @@ -292,7 +300,7 @@ static char coeff_csc[][24] = { }; -static void rk30_hdmi_config_csc(struct rk30_hdmi_video_para *vpara) +static void rk30_hdmi_config_csc(struct hdmi_video_para *vpara) { int i, mode; char *coeff = NULL; @@ -339,7 +347,7 @@ static void rk30_hdmi_config_csc(struct rk30_hdmi_video_para *vpara) HDMIWrReg(AV_CTRL2, v_CSC_ENABLE(1)); } -int rk30_hdmi_config_video(struct rk30_hdmi_video_para *vpara) +int rk30_hdmi_config_video(struct hdmi_video_para *vpara) { int value; struct fb_videomode *mode; @@ -548,9 +556,10 @@ void rk30_hdmi_control_output(int enable) { hdmi_dbg(hdmi->dev, "[%s] %d\n", __FUNCTION__, enable); if(enable == 0) { - HDMIWrReg(VIDEO_SETTING2, 0x03); + HDMIWrReg(AV_MUTE, v_AUDIO_MUTE(1) | v_VIDEO_MUTE(1)); } else { + HDMIWrReg(VIDEO_SETTING2, 0x03); if(hdmi->pwr_mode == PWR_SAVE_MODE_B) { // Switch to power save mode_d rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_D); diff --git a/drivers/video/rockchip/hdmi/rk30_hdmi_hw.h b/drivers/video/rockchip/hdmi/chips/rk30/rk30_hdmi_hw.h similarity index 94% rename from drivers/video/rockchip/hdmi/rk30_hdmi_hw.h rename to drivers/video/rockchip/hdmi/chips/rk30/rk30_hdmi_hw.h index 6a5fc3368a62..c42f0614b942 100755 --- a/drivers/video/rockchip/hdmi/rk30_hdmi_hw.h +++ b/drivers/video/rockchip/hdmi/chips/rk30/rk30_hdmi_hw.h @@ -60,15 +60,6 @@ enum { }; #define m_AUDIO_SAMPLE_RATE 0xF0 #define v_AUDIO_SAMPLE_RATE(n) (n << 4) -enum { - VIDEO_INPUT_RGB_YCBCR_444 = 0, - VIDEO_INPUT_YCBCR422, - VIDEO_INPUT_YCBCR422_EMBEDDED_SYNC, - VIDEO_INPUT_2X_CLOCK, - VIDEO_INPUT_2X_CLOCK_EMBEDDED_SYNC, - VIDEO_INPUT_RGB444_DDR, - VIDEO_INPUT_YCBCR422_DDR -}; #define m_INPUT_VIDEO_MODE (7 << 1) #define v_INPUT_VIDEO_MODE(n) (n << 1) enum { @@ -84,11 +75,7 @@ enum { /* HDMI_VIDEO_CTRL1 */ #define VIDEO_CTRL1 0x58 -enum { - VIDEO_OUTPUT_RGB444 = 0, - VIDEO_OUTPUT_YCBCR444, - VIDEO_OUTPUT_YCBCR422 -}; + #define m_VIDEO_OUTPUT_MODE (0x3 << 6) #define v_VIDEO_OUTPUT_MODE(n) (n << 6) enum { @@ -105,10 +92,6 @@ enum { }; #define m_VIDEO_EMBEDDED_SYNC_LOCATION (3 << 2) #define VIDEO_EMBEDDED_SYNC_LOCATION(n) (n << 2) -enum { - VIDEO_INPUT_COLOR_RGB = 0, - VIDEO_INPUT_COLOR_YCBCR -}; #define m_VIDEO_INPUT_COLOR_MODE (1 << 0) /* DEEP_COLOR_MODE */ @@ -416,14 +399,7 @@ enum { temp = __raw_readl(hdmi->regbase + addr) & (0xFF - (msk)) ; \ __raw_writel(temp | ( (val) & (msk) ), hdmi->regbase + addr); -/* RK30 HDMI Video Configure Parameters */ -struct rk30_hdmi_video_para { - int vic; - int input_mode; //input video data interface - int input_color; //input video color mode - int output_mode; //output hdmi or dvi - int output_color; //output video color mode -}; + /* Color Space Convertion Mode */ enum { @@ -439,8 +415,8 @@ extern int rk30_hdmi_initial(void); extern int rk30_hdmi_detect_hotplug(void); extern int rk30_hdmi_read_edid(int block, unsigned char *buff); extern int rk30_hdmi_removed(void); -extern int rk30_hdmi_config_video(struct rk30_hdmi_video_para *vpara); +extern int rk30_hdmi_config_video(struct hdmi_video_para *vpara); extern int rk30_hdmi_config_audio(struct hdmi_audio *audio); extern void rk30_hdmi_control_output(int enable); -#endif \ No newline at end of file +#endif diff --git a/drivers/video/rockchip/hdmi/rk30_hdmi.h b/drivers/video/rockchip/hdmi/rk30_hdmi.h deleted file mode 100755 index 54f5a5c0a676..000000000000 --- a/drivers/video/rockchip/hdmi/rk30_hdmi.h +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef __RK30_HDMI_H__ -#define __RK30_HDMI_H__ - -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_SWITCH -#include -#endif -#ifdef CONFIG_HAS_EARLYSUSPEND -#include -#endif -#include -#include -#include -#include "rk_hdmi.h" - -// HDMI video source -enum { - HDMI_SOURCE_LCDC0 = 0, - HDMI_SOURCE_LCDC1 = 1 -}; - -/* default HDMI video source */ -#define HDMI_SOURCE_DEFAULT HDMI_SOURCE_LCDC1 - -/* If HDMI_ENABLE, system will auto configure output mode according to EDID - * If HDMI_DISABLE, system will output mode according to macro HDMI_VIDEO_DEFAULT_MODE - */ -#define HDMI_AUTO_CONFIGURE HDMI_ENABLE - -/* default HDMI output video mode */ -#define HDMI_VIDEO_DEFAULT_MODE HDMI_1280x720p_60Hz//HDMI_1920x1080p_60Hz -/* default HDMI output audio mode */ -#define HDMI_AUDIO_DEFAULT_CHANNEL 2 -#define HDMI_AUDIO_DEFAULT_RATE HDMI_AUDIO_FS_44100 -#define HDMI_AUDIO_DEFAULT_WORD_LENGTH HDMI_AUDIO_WORD_LENGTH_16bit - -struct hdmi { - struct device *dev; - struct clk *hclk; //HDMI AHP clk - int regbase; - int irq; - int regbase_phy; - int regsize_phy; - struct rk_lcdc_device_driver *lcdc; - - #ifdef CONFIG_SWITCH - struct switch_dev switch_hdmi; - #endif - - struct workqueue_struct *workqueue; - struct delayed_work delay_work; - - spinlock_t irq_lock; - struct mutex enable_mutex; - - int wait; - struct completion complete; - - int suspend; -#ifdef CONFIG_HAS_EARLYSUSPEND - struct early_suspend early_suspend; -#endif - - struct hdmi_edid edid; - int enable; // Enable HDMI output or not - int vic; // HDMI output video mode code - struct hdmi_audio audio; // HDMI output audio type. - - int pwr_mode; // power mode - int hotplug; // hot plug status - int state; // hdmi state machine status - int autoconfig; // if true, auto config hdmi output mode according to EDID. - int command; // HDMI configuration command - int display; // HDMI display status - int xscale; // x direction scale value - int yscale; // y directoon scale value - int tmdsclk; // TDMS Clock frequency - // call back for hdcp operatoion - void (*hdcp_cb)(void); - void (*hdcp_irq_cb)(int); - int (*hdcp_power_on_cb)(void); - void (*hdcp_power_off_cb)(void); -}; - -extern struct hdmi *hdmi; - -extern int hdmi_sys_init(void); -extern int hdmi_sys_parse_edid(struct hdmi* hdmi); -extern const char *hdmi_get_video_mode_name(unsigned char vic); -extern int hdmi_videomode_to_vic(struct fb_videomode *vmode); -extern const struct fb_videomode* hdmi_vic_to_videomode(int vic); -extern int hdmi_add_videomode(const struct fb_videomode *mode, struct list_head *head); -extern struct hdmi_video_timing * hdmi_find_mode(int vic); -extern int hdmi_find_best_mode(struct hdmi* hdmi, int vic); -extern int hdmi_ouputmode_select(struct hdmi *hdmi, int edid_ok); -extern int hdmi_switch_fb(struct hdmi *hdmi, int vic); -extern void hdmi_sys_remove(void); -extern int rk30_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void), - void (*hdcp_irq_cb)(int status), - int (*hdcp_power_on_cb)(void), - void (*hdcp_power_off_cb)(void)); -#endif /* __RK30_HDMI_H__ */ diff --git a/drivers/video/rockchip/hdmi/rk_hdmi.h b/drivers/video/rockchip/hdmi/rk_hdmi.h index 534ba51ab5bd..cf6d34c6ce80 100755 --- a/drivers/video/rockchip/hdmi/rk_hdmi.h +++ b/drivers/video/rockchip/hdmi/rk_hdmi.h @@ -1,6 +1,61 @@ #ifndef __RK_HDMI_H__ #define __RK_HDMI_H__ +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_SWITCH +#include +#endif +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include +#include + +/* default HDMI output video mode */ +#define HDMI_VIDEO_DEFAULT_MODE HDMI_1280x720p_60Hz//HDMI_1920x1080p_60Hz + +// HDMI video source +enum { + HDMI_SOURCE_LCDC0 = 0, + HDMI_SOURCE_LCDC1 = 1 +}; + +/* default HDMI video source */ +#define HDMI_SOURCE_DEFAULT HDMI_SOURCE_LCDC1 +/* If HDMI_ENABLE, system will auto configure output mode according to EDID + * If HDMI_DISABLE, system will output mode according to macro HDMI_VIDEO_DEFAULT_MODE + */ +#define HDMI_AUTO_CONFIGURE HDMI_ENABLE + +/* default HDMI output audio mode */ +#define HDMI_AUDIO_DEFAULT_CHANNEL 2 +#define HDMI_AUDIO_DEFAULT_RATE HDMI_AUDIO_FS_44100 +#define HDMI_AUDIO_DEFAULT_WORD_LENGTH HDMI_AUDIO_WORD_LENGTH_16bit +enum { + VIDEO_INPUT_RGB_YCBCR_444 = 0, + VIDEO_INPUT_YCBCR422, + VIDEO_INPUT_YCBCR422_EMBEDDED_SYNC, + VIDEO_INPUT_2X_CLOCK, + VIDEO_INPUT_2X_CLOCK_EMBEDDED_SYNC, + VIDEO_INPUT_RGB444_DDR, + VIDEO_INPUT_YCBCR422_DDR +}; +enum { + VIDEO_OUTPUT_RGB444 = 0, + VIDEO_OUTPUT_YCBCR444, + VIDEO_OUTPUT_YCBCR422 +}; +enum { + VIDEO_INPUT_COLOR_RGB = 0, + VIDEO_INPUT_COLOR_YCBCR +}; /******************************************************************** ** 结构定义 * ********************************************************************/ @@ -186,6 +241,72 @@ struct hdmi_edid { }; extern const struct fb_videomode hdmi_mode[]; +/* RK HDMI Video Configure Parameters */ +struct hdmi_video_para { + int vic; + int input_mode; //input video data interface + int input_color; //input video color mode + int output_mode; //output hdmi or dvi + int output_color; //output video color mode +}; +struct hdmi { + struct device *dev; + struct clk *hclk; //HDMI AHP clk + int id; + int regbase; + int irq; + int regbase_phy; + int regsize_phy; + struct rk_lcdc_device_driver *lcdc; + + #ifdef CONFIG_SWITCH + struct switch_dev switch_hdmi; + #endif + + struct workqueue_struct *workqueue; + struct delayed_work delay_work; + + spinlock_t irq_lock; + struct mutex enable_mutex; + + int wait; + struct completion complete; + + int suspend; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + + struct hdmi_edid edid; + int enable; // Enable HDMI output or not + int vic; // HDMI output video mode code + struct hdmi_audio audio; // HDMI output audio type. + + int pwr_mode; // power mode + int hotplug; // hot plug status + int state; // hdmi state machine status + int autoconfig; // if true, auto config hdmi output mode according to EDID. + int command; // HDMI configuration command + int display; // HDMI display status + int xscale; // x direction scale value + int yscale; // y directoon scale value + int tmdsclk; // TDMS Clock frequency + + + int (*hdmi_removed)(void); + void (*control_output)(int enable); + int (*config_video)(struct hdmi_video_para *vpara); + int (*config_audio)(struct hdmi_audio *audio); + int (*detect_hotplug)(void); + // call back for edid + int (*read_edid)(int block, unsigned char *buff); + + // call back for hdcp operatoion + void (*hdcp_cb)(void); + void (*hdcp_irq_cb)(int); + int (*hdcp_power_on_cb)(void); + void (*hdcp_power_off_cb)(void); +}; #define hdmi_err(dev, format, arg...) \ dev_printk(KERN_ERR , dev , format , ## arg) @@ -197,7 +318,22 @@ extern const struct fb_videomode hdmi_mode[]; #define hdmi_dbg(dev, format, arg...) #endif +extern struct hdmi *hdmi; +extern struct hdmi *hdmi_register(int extra); +extern void hdmi_unregister(struct hdmi *hdmi); extern int hdmi_get_hotplug(void); extern int hdmi_set_info(struct rk29fb_screen *screen, unsigned int vic); extern void hdmi_init_lcdc(struct rk29fb_screen *screen, struct rk29lcd_info *lcd_info); +extern int hdmi_sys_init(void); +extern int hdmi_sys_parse_edid(struct hdmi* hdmi); +extern const char *hdmi_get_video_mode_name(unsigned char vic); +extern int hdmi_videomode_to_vic(struct fb_videomode *vmode); +extern const struct fb_videomode* hdmi_vic_to_videomode(int vic); +extern int hdmi_add_videomode(const struct fb_videomode *mode, struct list_head *head); +extern struct hdmi_video_timing * hdmi_find_mode(int vic); +extern int hdmi_find_best_mode(struct hdmi* hdmi, int vic); +extern int hdmi_ouputmode_select(struct hdmi *hdmi, int edid_ok); +extern int hdmi_switch_fb(struct hdmi *hdmi, int vic); +extern void hdmi_sys_remove(void); + #endif diff --git a/drivers/video/rockchip/hdmi/rk_hdmi_core.c b/drivers/video/rockchip/hdmi/rk_hdmi_core.c new file mode 100755 index 000000000000..1b17185b6da9 --- /dev/null +++ b/drivers/video/rockchip/hdmi/rk_hdmi_core.c @@ -0,0 +1,254 @@ +#include +#include +#include +#include +#include +#include +#include + + +struct class *hdmi_class; +struct hdmi_id_ref_info { + struct hdmi *hdmi; + int id; + int ref; +}ref_info[HDMI_MAX_ID]; +#ifdef CONFIG_SYSFS + +extern int hdmi_create_attrs(struct hdmi *hdmi); +extern void hdmi_remove_attrs(struct hdmi *hdmi); + +#else + +static inline int hdmi_create_attrs(struct hdmi *hdmi) +{ return 0; } +static inline void hdmi_remove_attrs(struct hdmi *hdmi) {} + +#endif /* CONFIG_SYSFS */ +static void __hdmi_changed(struct hdmi *hdmi) +{ + int precent; + + mutex_lock(&hdmi->lock); + precent = hdmi->ops->hdmi_precent(hdmi); + if(precent && (hdmi->mode == DISP_ON_LCD) && hdmi->display_on){ + if(hdmi->ops->insert(hdmi) == 0){ + hdmi->mode = hdmi->display_on; + kobject_uevent(&hdmi->dev->kobj, KOBJ_CHANGE); + } + else + hdmi_dbg(hdmi->dev, "insert error\n"); + hdmi_set_backlight(hdmi->display_on==DISP_ON_HDMI?HDMI_DISABLE: HDMI_ENABLE); + + } + else if(precent &&(hdmi->mode != hdmi->display_on)&& hdmi->display_on){ + hdmi->mode = hdmi->display_on; + hdmi_set_backlight(hdmi->display_on==DISP_ON_HDMI?HDMI_DISABLE: HDMI_ENABLE); + } + else if((!precent || !hdmi->display_on) && hdmi->mode != DISP_ON_LCD){ + if(hdmi->ops->remove(hdmi) == 0){ + hdmi->mode = DISP_ON_LCD; + hdmi_set_backlight(HDMI_ENABLE); + kobject_uevent(&hdmi->dev->kobj, KOBJ_CHANGE); + } + else + hdmi_dbg(hdmi->dev, "remove error\n"); + } + mutex_unlock(&hdmi->lock); + return; +} + +void hdmi_changed(struct hdmi *hdmi, int msec) +{ + schedule_delayed_work(&hdmi->work, msecs_to_jiffies(msec)); + return; +} +void hdmi_suspend(struct hdmi *hdmi) +{ + del_timer(&hdmi->timer); + flush_delayed_work(&hdmi->work); + if(hdmi->mode != DISP_ON_LCD){ + hdmi->ops->remove(hdmi); + hdmi->mode = DISP_ON_LCD; + } + return; +} +void hdmi_resume(struct hdmi *hdmi) +{ + mod_timer(&hdmi->timer, jiffies + msecs_to_jiffies(10)); + return; +} + +static void hdmi_changed_work(struct work_struct *work) +{ + struct hdmi *hdmi = container_of(work, struct hdmi, + work.work); + + __hdmi_changed(hdmi); + return; +} + +void *hdmi_priv(struct hdmi *hdmi) +{ + return (void *)hdmi->priv; +} +static void hdmi_detect_timer(unsigned long data) +{ + struct hdmi *hdmi = (struct hdmi*)data; + + int precent = hdmi->ops->hdmi_precent(hdmi); + + if((precent && hdmi->mode == DISP_ON_LCD) || + (!precent && hdmi->mode != DISP_ON_LCD)) + hdmi_changed(hdmi, 100); + mod_timer(&hdmi->timer, jiffies + msecs_to_jiffies(200)); +} +struct hdmi *hdmi_register(int extra, struct device *parent) +{ + int rc = 0, i; + char name[8]; + struct hdmi *hdmi = kzalloc(sizeof(struct hdmi)+ extra, GFP_KERNEL); + + if(!hdmi) + return NULL; + for(i = 0; i < HDMI_MAX_ID; i++) + { + if(ref_info[i].ref == 0) + { + ref_info[i].ref = 1; + hdmi->id = i; + break; + } + } + if(i == HDMI_MAX_ID) + { + kfree(hdmi); + return NULL; + } + sprintf(name, "hdmi-%d", hdmi->id); + + hdmi->dev = device_create(hdmi_class, parent, 0, + "%s", name); + if (IS_ERR(hdmi->dev)) { + rc = PTR_ERR(hdmi->dev); + goto dev_create_failed; + } + + dev_set_drvdata(hdmi->dev, hdmi); + ref_info[i].hdmi = hdmi; + + INIT_DELAYED_WORK(&hdmi->work, hdmi_changed_work); + + rc = hdmi_create_attrs(hdmi); + if (rc) + goto create_attrs_failed; + + goto success; + +create_attrs_failed: + device_unregister(hdmi->dev); +dev_create_failed: + hdmi_remove_attrs(hdmi); + kfree(hdmi); + return NULL; +success: + mutex_init(&hdmi->lock); + setup_timer(&hdmi->timer, hdmi_detect_timer,(unsigned long)hdmi); + mod_timer(&hdmi->timer, jiffies + msecs_to_jiffies(200)); + return hdmi; +} +void hdmi_unregister(struct hdmi *hdmi) +{ + int id; + + if(!hdmi) + return; + id = hdmi->id; + del_timer(&hdmi->timer); + flush_scheduled_work(); + hdmi_remove_attrs(hdmi); + device_unregister(hdmi->dev); + + kfree(hdmi); + hdmi = NULL; + ref_info[id].ref = 0; + ref_info[id].hdmi = NULL; +} +struct hdmi *get_hdmi_struct(int nr) +{ + if(ref_info[nr].ref == 0) + return NULL; + else + return ref_info[nr].hdmi; +} +int hdmi_is_insert(void) +{ + struct hdmi *hdmi = get_hdmi_struct(0); + + if(hdmi && hdmi->ops && hdmi->ops->hdmi_precent) + return hdmi->ops->hdmi_precent(hdmi); + else + return 0; +} +int hdmi_get_scale(void) +{ + struct hdmi* hdmi = get_hdmi_struct(0); + if(!hdmi) + return 100; + else if(hdmi->mode != DISP_ON_LCD) + return hdmi->scale; + else + return 100; +} + +int hdmi_set_scale(int event, char *data, int len) +{ + int result; + struct hdmi* hdmi = get_hdmi_struct(0); + + if(!hdmi) + return -1; + if(len != 4) + return -1; + if(fb_get_video_mode() || hdmi->mode == DISP_ON_LCD) + return -1; + + result = data[0] | data[1]<<1 | data[2]<<2; + if(event != MOUSE_NONE && (result & event) != event) + return -1; + + hdmi->scale += data[3]; + + hdmi->scale = (hdmi->scale>100)?100:hdmi->scale; + hdmi->scale = (hdmi->scalescale; + return 0; +} + +static int __init hdmi_class_init(void) +{ + int i; + + hdmi_class = class_create(THIS_MODULE, "hdmi"); + + if (IS_ERR(hdmi_class)) + return PTR_ERR(hdmi_class); + for(i = 0; i < HDMI_MAX_ID; i++) { + ref_info[i].id = i; + ref_info[i].ref = 0; + ref_info[i].hdmi = NULL; + } + return 0; +} + +static void __exit hdmi_class_exit(void) +{ + class_destroy(hdmi_class); +} +EXPORT_SYMBOL(hdmi_changed); +EXPORT_SYMBOL(hdmi_register); +EXPORT_SYMBOL(hdmi_unregister); +EXPORT_SYMBOL(get_hdmi_struct); + +subsys_initcall(hdmi_class_init); +module_exit(hdmi_class_exit); + diff --git a/drivers/video/rockchip/hdmi/rk30_hdmi_edid.c b/drivers/video/rockchip/hdmi/rk_hdmi_edid.c similarity index 95% rename from drivers/video/rockchip/hdmi/rk30_hdmi_edid.c rename to drivers/video/rockchip/hdmi/rk_hdmi_edid.c index 9fec195fea3c..ff44f4898f34 100755 --- a/drivers/video/rockchip/hdmi/rk30_hdmi_edid.c +++ b/drivers/video/rockchip/hdmi/rk_hdmi_edid.c @@ -1,5 +1,4 @@ -#include "rk30_hdmi.h" -#include "rk30_hdmi_hw.h" +#include "rk_hdmi.h" #include "../../edid.h" #define hdmi_edid_error(fmt, ...) \ @@ -374,7 +373,7 @@ int hdmi_sys_parse_edid(struct hdmi* hdmi) } // Read base block edid. memset(buff, 0 , HDMI_EDID_BLOCK_SIZE); - rc = rk30_hdmi_read_edid(0, buff); + rc = hdmi->read_edid(0, buff); if(rc) { dev_err(hdmi->dev, "[HDMI] read edid base block error\n"); @@ -389,7 +388,7 @@ int hdmi_sys_parse_edid(struct hdmi* hdmi) for(i = 1; i < extendblock + 1; i++) { memset(buff, 0 , HDMI_EDID_BLOCK_SIZE); - rc = rk30_hdmi_read_edid(i, buff); + rc = hdmi->read_edid(i, buff); if(rc) { printk("[HDMI] read edid block %d error\n", i); @@ -407,4 +406,4 @@ int hdmi_sys_parse_edid(struct hdmi* hdmi) kfree(buff); rc = hdmi_ouputmode_select(hdmi, rc); return rc; -} \ No newline at end of file +} diff --git a/drivers/video/rockchip/hdmi/rk30_hdmi_lcdc.c b/drivers/video/rockchip/hdmi/rk_hdmi_lcdc.c similarity index 99% rename from drivers/video/rockchip/hdmi/rk30_hdmi_lcdc.c rename to drivers/video/rockchip/hdmi/rk_hdmi_lcdc.c index 406837e2e200..da445b953211 100755 --- a/drivers/video/rockchip/hdmi/rk30_hdmi_lcdc.c +++ b/drivers/video/rockchip/hdmi/rk_hdmi_lcdc.c @@ -1,7 +1,6 @@ #include -#include "rk30_hdmi.h" -#include "rk30_hdmi_hw.h" #include +#include "rk_hdmi.h" #define OUT_TYPE SCREEN_HDMI #define OUT_FACE OUT_P888 @@ -524,4 +523,4 @@ int hdmi_get_hotplug(void) return hdmi->hotplug; else return HDMI_HPD_REMOVED; -} \ No newline at end of file +} diff --git a/drivers/video/rockchip/hdmi/rk30_hdmi_sysfs.c b/drivers/video/rockchip/hdmi/rk_hdmi_sysfs.c similarity index 99% rename from drivers/video/rockchip/hdmi/rk30_hdmi_sysfs.c rename to drivers/video/rockchip/hdmi/rk_hdmi_sysfs.c index 828b77120f2f..45d28eea57b5 100755 --- a/drivers/video/rockchip/hdmi/rk30_hdmi_sysfs.c +++ b/drivers/video/rockchip/hdmi/rk_hdmi_sysfs.c @@ -2,7 +2,7 @@ #include #include #include -#include "rk30_hdmi.h" +#include "rk_hdmi.h" static int hdmi_get_enable(struct rk_display_device *device) { @@ -174,4 +174,4 @@ void hdmi_unregister_display_sysfs(struct hdmi *hdmi) if(display_device_hdmi) rk_display_device_unregister(display_device_hdmi); } -#endif \ No newline at end of file +#endif diff --git a/drivers/video/rockchip/hdmi/rk30_hdmi_task.c b/drivers/video/rockchip/hdmi/rk_hdmi_task.c similarity index 94% rename from drivers/video/rockchip/hdmi/rk30_hdmi_task.c rename to drivers/video/rockchip/hdmi/rk_hdmi_task.c index cbee83a5d509..233d1757ff04 100755 --- a/drivers/video/rockchip/hdmi/rk30_hdmi_task.c +++ b/drivers/video/rockchip/hdmi/rk_hdmi_task.c @@ -1,13 +1,13 @@ #include #include -#include "rk30_hdmi.h" -#include "rk30_hdmi_hw.h" +#include "rk_hdmi.h" #ifdef CONFIG_HDMI_RK30_CTL_CODEC extern void codec_set_spk(bool on); #endif #define HDMI_MAX_TRY_TIMES 1 +#define HDMI_MAX_ID 1 static char *envp[] = {"INTERFACE=HDMI", NULL}; @@ -50,7 +50,6 @@ static void hdmi_sys_show_state(int state) int hdmi_sys_init(void) { - hdmi->pwr_mode = PWR_SAVE_MODE_A; hdmi->hotplug = HDMI_HPD_REMOVED; hdmi->state = HDMI_SLEEP; hdmi->enable = HDMI_ENABLE; @@ -97,7 +96,7 @@ static void hdmi_sys_sleep(void) if(hdmi->enable) disable_irq(hdmi->irq); hdmi->state = HDMI_SLEEP; - rk30_hdmi_removed(); + hdmi->hdmi_removed(); if(hdmi->enable) enable_irq(hdmi->irq); mutex_unlock(&hdmi->enable_mutex); @@ -122,7 +121,7 @@ static int hdmi_process_command(void) hdmi_sys_remove(); hdmi->state = HDMI_SLEEP; hdmi->hotplug = HDMI_HPD_REMOVED; - rk30_hdmi_removed(); + hdmi->hdmi_removed(); state = HDMI_SLEEP; } mutex_unlock(&hdmi->enable_mutex); @@ -168,7 +167,7 @@ void hdmi_work(struct work_struct *work) { int hotplug, state_last; int rc = HDMI_ERROR_SUCESS, trytimes = 0; - struct rk30_hdmi_video_para video; + struct hdmi_video_para video; mutex_lock(&work_mutex); /* Process hdmi command */ @@ -178,7 +177,7 @@ void hdmi_work(struct work_struct *work) mutex_unlock(&work_mutex); return; } - hotplug = rk30_hdmi_detect_hotplug(); + hotplug = hdmi->detect_hotplug(); hdmi_dbg(hdmi->dev, "[%s] hotplug %02x curvalue %d\n", __FUNCTION__, hotplug, hdmi->hotplug); if(hotplug != hdmi->hotplug) @@ -193,7 +192,7 @@ void hdmi_work(struct work_struct *work) hdmi_sys_sleep(); else { hdmi->state = WAIT_HOTPLUG; - rk30_hdmi_removed(); + hdmi->hdmi_removed(); } if(hdmi->wait == 1) { complete(&hdmi->complete); @@ -204,7 +203,7 @@ void hdmi_work(struct work_struct *work) } else if(hotplug == HDMI_HPD_REMOVED) { hdmi->state = HDMI_SLEEP; - rk30_hdmi_removed(); + hdmi->hdmi_removed(); } hdmi->hotplug = hotplug; } @@ -256,7 +255,7 @@ void hdmi_work(struct work_struct *work) if(hdmi->edid.sink_hdmi == 0) video.output_color = VIDEO_OUTPUT_RGB444; - rc = rk30_hdmi_config_video(&video); + rc = hdmi->config_video(&video); if(rc == HDMI_ERROR_SUCESS) { if(hdmi->edid.sink_hdmi) @@ -266,14 +265,14 @@ void hdmi_work(struct work_struct *work) } break; case CONFIG_AUDIO: - rc = rk30_hdmi_config_audio(&(hdmi->audio)); + rc = hdmi->config_audio(&(hdmi->audio)); if(rc == HDMI_ERROR_SUCESS) hdmi->state = PLAY_BACK; break; case PLAY_BACK: if(hdmi->display != HDMI_ENABLE) { - rk30_hdmi_control_output(HDMI_ENABLE); + hdmi->control_output(HDMI_ENABLE); hdmi->display = HDMI_ENABLE; if(hdmi->hdcp_cb) { hdmi->hdcp_cb(); @@ -309,4 +308,5 @@ void hdmi_work(struct work_struct *work) // } hdmi_dbg(hdmi->dev, "[%s] done\n", __FUNCTION__); mutex_unlock(&work_mutex); -} \ No newline at end of file +} + From 531e2ac111d283a351731f7916afc5c952cb14d2 Mon Sep 17 00:00:00 2001 From: hxy Date: Fri, 20 Jul 2012 17:36:48 +0800 Subject: [PATCH 033/261] rk31: add sdmmc support --- arch/arm/configs/rk31_fpga_defconfig | 5 + arch/arm/mach-rk30/board-rk31-fpga.c | 159 +++++++++++++++++++++++++++ drivers/mmc/host/rk29_sdmmc.c | 4 +- drivers/mmc/host/rk29_sdmmc.h | 6 +- 4 files changed, 169 insertions(+), 5 deletions(-) diff --git a/arch/arm/configs/rk31_fpga_defconfig b/arch/arm/configs/rk31_fpga_defconfig index 7b739e2bbff1..c9d5822ed73a 100644 --- a/arch/arm/configs/rk31_fpga_defconfig +++ b/arch/arm/configs/rk31_fpga_defconfig @@ -87,6 +87,11 @@ CONFIG_LOGO=y # CONFIG_LOGO_LINUX_VGA16 is not set # CONFIG_HID_SUPPORT is not set # CONFIG_USB_SUPPORT is not set +CONFIG_MMC=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_SDMMC_RK29=y +# CONFIG_SDMMC1_RK29 is not set CONFIG_RTC_CLASS=y # CONFIG_CMMB is not set # CONFIG_DNOTIFY is not set diff --git a/arch/arm/mach-rk30/board-rk31-fpga.c b/arch/arm/mach-rk30/board-rk31-fpga.c index 309d3eb274ee..3b4a517678fc 100644 --- a/arch/arm/mach-rk30/board-rk31-fpga.c +++ b/arch/arm/mach-rk30/board-rk31-fpga.c @@ -196,6 +196,165 @@ static struct platform_device *devices[] __initdata = { &device_fb, #endif }; +/************************************************************************************************** + * SDMMC devices, include the module of SD,MMC,and sdio.noted by xbw at 2012-03-05 +**************************************************************************************************/ +#ifdef CONFIG_SDMMC_RK29 +#include "board-rk30-sdk-sdmmc.c" + +#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) +#define SDMMC0_WRITE_PROTECT_PIN RK30_PIN3_PB7 //According to your own project to set the value of write-protect-pin. +#endif + +#if defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT) +#define SDMMC1_WRITE_PROTECT_PIN RK30_PIN3_PC7 //According to your own project to set the value of write-protect-pin. +#endif + +#define RK29SDK_WIFI_SDIO_CARD_DETECT_N RK30_PIN6_PB2 + +#endif //endif ---#ifdef CONFIG_SDMMC_RK29 + +#ifdef CONFIG_SDMMC0_RK29 +static int rk29_sdmmc0_cfg_gpio(void) +{ +#ifdef CONFIG_SDMMC_RK29_OLD + rk30_mux_api_set(GPIO3B1_SDMMC0CMD_NAME, GPIO3B_SDMMC0_CMD); + rk30_mux_api_set(GPIO3B0_SDMMC0CLKOUT_NAME, GPIO3B_SDMMC0_CLKOUT); + rk30_mux_api_set(GPIO3B2_SDMMC0DATA0_NAME, GPIO3B_SDMMC0_DATA0); + rk30_mux_api_set(GPIO3B3_SDMMC0DATA1_NAME, GPIO3B_SDMMC0_DATA1); + rk30_mux_api_set(GPIO3B4_SDMMC0DATA2_NAME, GPIO3B_SDMMC0_DATA2); + rk30_mux_api_set(GPIO3B5_SDMMC0DATA3_NAME, GPIO3B_SDMMC0_DATA3); + + rk30_mux_api_set(GPIO3B6_SDMMC0DETECTN_NAME, GPIO3B_GPIO3B6); + + rk30_mux_api_set(GPIO3A7_SDMMC0PWREN_NAME, GPIO3A_GPIO3A7); + gpio_request(RK30_PIN3_PA7, "sdmmc-power"); + gpio_direction_output(RK30_PIN3_PA7, GPIO_LOW); + +#else + rk29_sdmmc_set_iomux(0, 0xFFFF); + + rk30_mux_api_set(GPIO3B6_SDMMC0DETECTN_NAME, GPIO3B_SDMMC0_DETECT_N); + +#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) + gpio_request(SDMMC0_WRITE_PROTECT_PIN, "sdmmc-wp"); + gpio_direction_input(SDMMC0_WRITE_PROTECT_PIN); +#endif + +#endif + + return 0; +} + +#define CONFIG_SDMMC0_USE_DMA +struct rk29_sdmmc_platform_data default_sdmmc0_data = { + .host_ocr_avail = + (MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 | MMC_VDD_28_29 | + MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | + MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36), + .host_caps = + (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), + .io_init = rk29_sdmmc0_cfg_gpio, + +#if !defined(CONFIG_SDMMC_RK29_OLD) + .set_iomux = rk29_sdmmc_set_iomux, +#endif + + .dma_name = "sd_mmc", +#ifdef CONFIG_SDMMC0_USE_DMA + .use_dma = 1, +#else + .use_dma = 0, +#endif + .detect_irq = RK30_PIN3_PB6, // INVALID_GPIO + .enable_sd_wakeup = 0, + +#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) + .write_prt = SDMMC0_WRITE_PROTECT_PIN, +#else + .write_prt = INVALID_GPIO, +#endif +}; +#endif // CONFIG_SDMMC0_RK29 + +#ifdef CONFIG_SDMMC1_RK29 +#define CONFIG_SDMMC1_USE_DMA +static int rk29_sdmmc1_cfg_gpio(void) +{ +#if defined(CONFIG_SDMMC_RK29_OLD) + rk30_mux_api_set(GPIO3C0_SMMC1CMD_NAME, GPIO3C_SMMC1_CMD); + rk30_mux_api_set(GPIO3C5_SDMMC1CLKOUT_NAME, GPIO3C_SDMMC1_CLKOUT); + rk30_mux_api_set(GPIO3C1_SDMMC1DATA0_NAME, GPIO3C_SDMMC1_DATA0); + rk30_mux_api_set(GPIO3C2_SDMMC1DATA1_NAME, GPIO3C_SDMMC1_DATA1); + rk30_mux_api_set(GPIO3C3_SDMMC1DATA2_NAME, GPIO3C_SDMMC1_DATA2); + rk30_mux_api_set(GPIO3C4_SDMMC1DATA3_NAME, GPIO3C_SDMMC1_DATA3); + //rk30_mux_api_set(GPIO3C6_SDMMC1DETECTN_NAME, GPIO3C_SDMMC1_DETECT_N); + +#else + +#if defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT) + gpio_request(SDMMC1_WRITE_PROTECT_PIN, "sdio-wp"); + gpio_direction_input(SDMMC1_WRITE_PROTECT_PIN); +#endif + +#endif + + return 0; +} + +struct rk29_sdmmc_platform_data default_sdmmc1_data = { + .host_ocr_avail = + (MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 | MMC_VDD_28_29 | + MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | + MMC_VDD_33_34), + +#if !defined(CONFIG_USE_SDMMC1_FOR_WIFI_DEVELOP_BOARD) + .host_caps = (MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ | + MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), +#else + .host_caps = + (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), +#endif + + .io_init = rk29_sdmmc1_cfg_gpio, + +#if !defined(CONFIG_SDMMC_RK29_OLD) + .set_iomux = rk29_sdmmc_set_iomux, +#endif + + .dma_name = "sdio", +#ifdef CONFIG_SDMMC1_USE_DMA + .use_dma = 1, +#else + .use_dma = 0, +#endif + +#if !defined(CONFIG_USE_SDMMC1_FOR_WIFI_DEVELOP_BOARD) +#ifdef CONFIG_WIFI_CONTROL_FUNC + .status = rk29sdk_wifi_status, + .register_status_notify = rk29sdk_wifi_status_register, +#endif +#if 0 + .detect_irq = RK29SDK_WIFI_SDIO_CARD_DETECT_N, +#endif + +#if defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT) + .write_prt = SDMMC1_WRITE_PROTECT_PIN, +#else + .write_prt = INVALID_GPIO, +#endif + +#else + .detect_irq = INVALID_GPIO, + .enable_sd_wakeup = 0, +#endif + +}; +#endif //endif--#ifdef CONFIG_SDMMC1_RK29 + +/************************************************************************************************** + * the end of setting for SDMMC devices +**************************************************************************************************/ static void __init rk31_board_init(void) { diff --git a/drivers/mmc/host/rk29_sdmmc.c b/drivers/mmc/host/rk29_sdmmc.c index b7028a0408e6..57ada8690736 100755 --- a/drivers/mmc/host/rk29_sdmmc.c +++ b/drivers/mmc/host/rk29_sdmmc.c @@ -1470,7 +1470,7 @@ int rk29_sdmmc_reset_controller(struct rk29_sdmmc *host) /* reset */ #if defined(CONFIG_ARCH_RK29) rk29_sdmmc_write(host->regs, SDMMC_CTRL,(SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET )); -#elif defined(CONFIG_ARCH_RK30) +#elif defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) rk29_sdmmc_write(host->regs, SDMMC_CTRL,(SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET)); #endif timeOut = 1000; @@ -3605,7 +3605,7 @@ static void rk29_sdmmc_sdcard_resume(struct rk29_sdmmc *host) rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_SDMMC0_DETECT_N); } -#elif defined(CONFIG_ARCH_RK30) +#elif defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) static irqreturn_t det_keys_isr(int irq, void *dev_id) { struct rk29_sdmmc *host = dev_id; diff --git a/drivers/mmc/host/rk29_sdmmc.h b/drivers/mmc/host/rk29_sdmmc.h index 60bb6c7ef23f..9360cd3ea85e 100755 --- a/drivers/mmc/host/rk29_sdmmc.h +++ b/drivers/mmc/host/rk29_sdmmc.h @@ -48,7 +48,7 @@ #if defined(CONFIG_ARCH_RK29) #define SDMMC_DATA (0x100) -#elif defined(CONFIG_ARCH_RK30) +#elif defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) #define SDMMC_VERID (0x06c) //Version ID register #define SDMMC_UHS_REG (0x074) //UHS-I register #define SDMMC_RST_n (0x078) //Hardware reset register @@ -102,7 +102,7 @@ /* Interrupt status & mask register defines(base+0x24) */ #if defined(CONFIG_ARCH_RK29) #define SDMMC_INT_SDIO RK2818_BIT(16) //SDIO interrupt -#elif defined(CONFIG_ARCH_RK30) +#elif defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) #define SDMMC_INT_SDIO RK2818_BIT(24) //SDIO interrupt #define SDMMC_INT_UNBUSY RK2818_BIT(16) //data no busy interrupt #endif @@ -181,7 +181,7 @@ #define RX_WMARK (0xF) //RX watermark level set to 15 #define TX_WMARK (0x10) //TX watermark level set to 16 -#elif defined(CONFIG_ARCH_RK30) +#elif defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) #define FIFO_DEPTH (0x100) //FIFO depth = 256 word #define RX_WMARK_SHIFT (16) #define TX_WMARK_SHIFT (0) From c833379e3be17b07168c67ac0994a42c1328f07b Mon Sep 17 00:00:00 2001 From: hxy Date: Mon, 23 Jul 2012 11:08:54 +0800 Subject: [PATCH 034/261] add sdcard fs support --- arch/arm/configs/rk31_fpga_defconfig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/configs/rk31_fpga_defconfig b/arch/arm/configs/rk31_fpga_defconfig index c9d5822ed73a..d4f9f0e6cffe 100644 --- a/arch/arm/configs/rk31_fpga_defconfig +++ b/arch/arm/configs/rk31_fpga_defconfig @@ -95,9 +95,14 @@ CONFIG_SDMMC_RK29=y CONFIG_RTC_CLASS=y # CONFIG_CMMB is not set # CONFIG_DNOTIFY is not set +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y CONFIG_TMPFS=y # CONFIG_MISC_FILESYSTEMS is not set # CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=y CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y From 6d914b8a0cb1de8cf9464fbcd95874f1c1e4cfa8 Mon Sep 17 00:00:00 2001 From: kfx Date: Mon, 23 Jul 2012 14:20:22 +0800 Subject: [PATCH 035/261] rk2928: add sdmmc support --- arch/arm/mach-rk2928/board-rk2928-fpga.c | 511 +++++++++++++++++- arch/arm/mach-rk2928/board-rk2928-sdk-sdmmc.c | 441 +++++++++++++++ arch/arm/mach-rk2928/devices.c | 60 ++ drivers/mmc/host/rk29_sdmmc.c | 54 +- drivers/mmc/host/rk29_sdmmc.h | 6 +- 5 files changed, 1044 insertions(+), 28 deletions(-) create mode 100644 arch/arm/mach-rk2928/board-rk2928-sdk-sdmmc.c diff --git a/arch/arm/mach-rk2928/board-rk2928-fpga.c b/arch/arm/mach-rk2928/board-rk2928-fpga.c index 8b9a4c90df17..7fd99583b24c 100755 --- a/arch/arm/mach-rk2928/board-rk2928-fpga.c +++ b/arch/arm/mach-rk2928/board-rk2928-fpga.c @@ -47,13 +47,13 @@ /*---------------- Camera Sensor Macro Define Begin ------------------------*/ /*---------------- Camera Sensor Configuration Macro Begin ------------------------*/ #define CONFIG_SENSOR_0 RK29_CAM_SENSOR_OV5642 /* back camera sensor */ -#define CONFIG_SENSOR_IIC_ADDR_0 0x78 +#define CONFIG_SENSOR_IIC_ADDR_0 0 #define CONFIG_SENSOR_IIC_ADAPTER_ID_0 4 #define CONFIG_SENSOR_CIF_INDEX_0 0 #define CONFIG_SENSOR_ORIENTATION_0 90 #define CONFIG_SENSOR_POWER_PIN_0 INVALID_GPIO #define CONFIG_SENSOR_RESET_PIN_0 INVALID_GPIO -#define CONFIG_SENSOR_POWERDN_PIN_0 RK30_PIN1_PD6 +#define CONFIG_SENSOR_POWERDN_PIN_0 RK2928_PIN1_PD6 #define CONFIG_SENSOR_FALSH_PIN_0 INVALID_GPIO #define CONFIG_SENSOR_POWERACTIVE_LEVEL_0 RK29_CAM_POWERACTIVE_L #define CONFIG_SENSOR_RESETACTIVE_LEVEL_0 RK29_CAM_RESETACTIVE_L @@ -76,7 +76,7 @@ #define CONFIG_SENSOR_ORIENTATION_01 90 #define CONFIG_SENSOR_POWER_PIN_01 INVALID_GPIO #define CONFIG_SENSOR_RESET_PIN_01 INVALID_GPIO -#define CONFIG_SENSOR_POWERDN_PIN_01 RK30_PIN1_PD6 +#define CONFIG_SENSOR_POWERDN_PIN_01 RK2928_PIN1_PD6 #define CONFIG_SENSOR_FALSH_PIN_01 INVALID_GPIO #define CONFIG_SENSOR_POWERACTIVE_LEVEL_01 RK29_CAM_POWERACTIVE_L #define CONFIG_SENSOR_RESETACTIVE_LEVEL_01 RK29_CAM_RESETACTIVE_L @@ -99,7 +99,7 @@ #define CONFIG_SENSOR_ORIENTATION_02 90 #define CONFIG_SENSOR_POWER_PIN_02 INVALID_GPIO #define CONFIG_SENSOR_RESET_PIN_02 INVALID_GPIO -#define CONFIG_SENSOR_POWERDN_PIN_02 RK30_PIN1_PD6 +#define CONFIG_SENSOR_POWERDN_PIN_02 RK2928_PIN1_PD6 #define CONFIG_SENSOR_FALSH_PIN_02 INVALID_GPIO #define CONFIG_SENSOR_POWERACTIVE_LEVEL_02 RK29_CAM_POWERACTIVE_L #define CONFIG_SENSOR_RESETACTIVE_LEVEL_02 RK29_CAM_RESETACTIVE_L @@ -117,12 +117,12 @@ #define CONFIG_SENSOR_1 RK29_CAM_SENSOR_OV2659 /* front camera sensor 0 */ #define CONFIG_SENSOR_IIC_ADDR_1 0x60 -#define CONFIG_SENSOR_IIC_ADAPTER_ID_1 3 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_1 1 #define CONFIG_SENSOR_CIF_INDEX_1 0 #define CONFIG_SENSOR_ORIENTATION_1 270 #define CONFIG_SENSOR_POWER_PIN_1 INVALID_GPIO #define CONFIG_SENSOR_RESET_PIN_1 INVALID_GPIO -#define CONFIG_SENSOR_POWERDN_PIN_1 RK30_PIN1_PB7 +#define CONFIG_SENSOR_POWERDN_PIN_1 RK2928_PIN1_PB7 #define CONFIG_SENSOR_FALSH_PIN_1 INVALID_GPIO #define CONFIG_SENSOR_POWERACTIVE_LEVEL_1 RK29_CAM_POWERACTIVE_L #define CONFIG_SENSOR_RESETACTIVE_LEVEL_1 RK29_CAM_RESETACTIVE_L @@ -190,6 +190,470 @@ #include "../../../drivers/media/video/rk2928_camera.c" /*---------------- Camera Sensor Macro Define End ---------*/ +#define PMEM_CAM_SIZE PMEM_CAM_NECESSARY +/***************************************************************************************** + * camera devices + * author: ddl@rock-chips.com + *****************************************************************************************/ +#ifdef CONFIG_VIDEO_RK29 +#define CONFIG_SENSOR_POWER_IOCTL_USR 0 //define this refer to your board layout +#define CONFIG_SENSOR_RESET_IOCTL_USR 0 +#define CONFIG_SENSOR_POWERDOWN_IOCTL_USR 0 +#define CONFIG_SENSOR_FLASH_IOCTL_USR 0 + +static void rk_cif_power(int on) +{ + struct regulator *ldo_18,*ldo_28; + ldo_28 = regulator_get(NULL, "ldo7"); // vcc28_cif + ldo_18 = regulator_get(NULL, "ldo1"); // vcc18_cif + if (ldo_28 == NULL || IS_ERR(ldo_28) || ldo_18 == NULL || IS_ERR(ldo_18)){ + printk("get cif ldo failed!\n"); + return; + } + if(on == 0){ + regulator_disable(ldo_28); + regulator_put(ldo_28); + regulator_disable(ldo_18); + regulator_put(ldo_18); + mdelay(500); + } + else{ + regulator_set_voltage(ldo_28, 2800000, 2800000); + regulator_enable(ldo_28); + // printk("%s set ldo7 vcc28_cif=%dmV end\n", __func__, regulator_get_voltage(ldo_28)); + regulator_put(ldo_28); + + regulator_set_voltage(ldo_18, 1800000, 1800000); + // regulator_set_suspend_voltage(ldo, 1800000); + regulator_enable(ldo_18); + // printk("%s set ldo1 vcc18_cif=%dmV end\n", __func__, regulator_get_voltage(ldo_18)); + regulator_put(ldo_18); + } +} + +#if CONFIG_SENSOR_POWER_IOCTL_USR +static int sensor_power_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + //#error "CONFIG_SENSOR_POWER_IOCTL_USR is 1, sensor_power_usr_cb function must be writed!!"; + rk_cif_power(on); +} +#endif + +#if CONFIG_SENSOR_RESET_IOCTL_USR +static int sensor_reset_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + #error "CONFIG_SENSOR_RESET_IOCTL_USR is 1, sensor_reset_usr_cb function must be writed!!"; +} +#endif + +#if CONFIG_SENSOR_POWERDOWN_IOCTL_USR +static int sensor_powerdown_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + #error "CONFIG_SENSOR_POWERDOWN_IOCTL_USR is 1, sensor_powerdown_usr_cb function must be writed!!"; +} +#endif + +#if CONFIG_SENSOR_FLASH_IOCTL_USR +static int sensor_flash_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + #error "CONFIG_SENSOR_FLASH_IOCTL_USR is 1, sensor_flash_usr_cb function must be writed!!"; +} +#endif + +static struct rk29camera_platform_ioctl_cb sensor_ioctl_cb = { + #if CONFIG_SENSOR_POWER_IOCTL_USR + .sensor_power_cb = sensor_power_usr_cb, + #else + .sensor_power_cb = NULL, + #endif + + #if CONFIG_SENSOR_RESET_IOCTL_USR + .sensor_reset_cb = sensor_reset_usr_cb, + #else + .sensor_reset_cb = NULL, + #endif + + #if CONFIG_SENSOR_POWERDOWN_IOCTL_USR + .sensor_powerdown_cb = sensor_powerdown_usr_cb, + #else + .sensor_powerdown_cb = NULL, + #endif + + #if CONFIG_SENSOR_FLASH_IOCTL_USR + .sensor_flash_cb = sensor_flash_usr_cb, + #else + .sensor_flash_cb = NULL, + #endif +}; + +#if CONFIG_SENSOR_IIC_ADDR_0 +static struct reginfo_t rk_init_data_sensor_reg_0[] = +{ + {0x0000, 0x00,0,0} + }; +static struct reginfo_t rk_init_data_sensor_winseqreg_0[] ={ + {0x0000, 0x00,0,0} + }; +#endif + +#if CONFIG_SENSOR_IIC_ADDR_1 +static struct reginfo_t rk_init_data_sensor_reg_1[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_1[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_01 +static struct reginfo_t rk_init_data_sensor_reg_01[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_01[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_02 +static struct reginfo_t rk_init_data_sensor_reg_02[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_02[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_11 +static struct reginfo_t rk_init_data_sensor_reg_11[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_11[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_12 +static struct reginfo_t rk_init_data_sensor_reg_12[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_12[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +static rk_sensor_user_init_data_s rk_init_data_sensor[RK_CAM_NUM] = +{ + #if CONFIG_SENSOR_IIC_ADDR_0 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_0, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_0, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_0) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_0) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_1 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_1, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_1, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_1) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_1) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_01 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_01, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_01, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_01) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_01) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_02 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_02, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_02, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_02) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_02) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_11 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_11, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_11, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_11) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_11) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_12 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_12, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_12, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_12) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_12) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + + }; +#include "../../../drivers/media/video/rk2928_camera.c" + +#endif /* CONFIG_VIDEO_RK29 */ + +/************************************************************************************************** + * SDMMC devices, include the module of SD,MMC,and sdio.noted by xbw at 2012-03-05 +**************************************************************************************************/ +#ifdef CONFIG_SDMMC_RK29 +#include "board-rk2928-sdk-sdmmc.c" + +#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) +#define SDMMC0_WRITE_PROTECT_PIN RK2928_PIN1_PA7 //According to your own project to set the value of write-protect-pin. +#endif + +#if defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT) +#define SDMMC1_WRITE_PROTECT_PIN RK2928_PIN0_PD5 //According to your own project to set the value of write-protect-pin. +#endif + +#define RK29SDK_WIFI_SDIO_CARD_DETECT_N RK2928_PIN0_PB2 + +#endif //endif ---#ifdef CONFIG_SDMMC_RK29 + +#ifdef CONFIG_SDMMC0_RK29 +static int rk29_sdmmc0_cfg_gpio(void) +{ +#ifdef CONFIG_SDMMC_RK29_OLD + rk30_mux_api_set(GPIO1B7_MMC0_CMD_NAME, GPIO1B_MMC0_CMD); + rk30_mux_api_set(GPIO1C0_MMC0_CLKOUT_NAME, GPIO1C_MMC0_CLKOUT); + rk30_mux_api_set(GPIO1C2_MMC0_D0_NAME, GPIO1C_MMC0_D0); + rk30_mux_api_set(GPIO1C3_MMC0_D1_NAME, GPIO1C_MMC0_D1); + rk30_mux_api_set(GPIO1C4_MMC0_D2_NAME, GPIO1C_MMC0_D2); + rk30_mux_api_set(GPIO1C5_MMC0_D3_NAME, GPIO1C_MMC0_D3); + + rk30_mux_api_set(GPIO1C1_MMC0_DETN_NAME, GPIO1C_MMC0_DETN); + + rk30_mux_api_set(GPIO1B6_MMC0_PWREN_NAME, GPIO1B_MMC0_PWREN); + gpio_request(RK30_PIN3_PA7, "sdmmc-power"); + gpio_direction_output(RK2928_PIN1_PB6, GPIO_LOW); + +#else + rk29_sdmmc_set_iomux(0, 0xFFFF); + + rk30_mux_api_set(GPIO1C1_MMC0_DETN_NAME, GPIO1C_MMC0_DETN); + +#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) + gpio_request(SDMMC0_WRITE_PROTECT_PIN, "sdmmc-wp"); + gpio_direction_input(SDMMC0_WRITE_PROTECT_PIN); +#endif + +#endif + + return 0; +} + +#define CONFIG_SDMMC0_USE_DMA +struct rk29_sdmmc_platform_data default_sdmmc0_data = { + .host_ocr_avail = + (MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 | MMC_VDD_28_29 | + MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | + MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36), + .host_caps = + (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), + .io_init = rk29_sdmmc0_cfg_gpio, + +#if !defined(CONFIG_SDMMC_RK29_OLD) + .set_iomux = rk29_sdmmc_set_iomux, +#endif + + .dma_name = "sd_mmc", +#ifdef CONFIG_SDMMC0_USE_DMA + .use_dma = 1, +#else + .use_dma = 0, +#endif + .detect_irq = RK2928_PIN1_PC1, // INVALID_GPIO + .enable_sd_wakeup = 0, + +#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) + .write_prt = SDMMC0_WRITE_PROTECT_PIN, +#else + .write_prt = INVALID_GPIO, +#endif +}; +#endif // CONFIG_SDMMC0_RK29 + +#ifdef CONFIG_SDMMC1_RK29 +#define CONFIG_SDMMC1_USE_DMA +static int rk29_sdmmc1_cfg_gpio(void) +{ +#if defined(CONFIG_SDMMC_RK29_OLD) + rk30_mux_api_set(GPIO0B0_MMC1_CMD_NAME, GPIO0B_MMC1_CMD); + rk30_mux_api_set(GPIO0B1_MMC1_CLKOUT_NAME, GPIO0B_MMC1_CLKOUT); + rk30_mux_api_set(GPIO0B3_MMC1_D0_NAME, GPIO0B_MMC1_D0); + rk30_mux_api_set(GPIO0B4_MMC1_D1_NAME, GPIO0B_MMC1_D1); + rk30_mux_api_set(GPIO0B5_MMC1_D2_NAME, GPIO0B_MMC1_D2); + rk30_mux_api_set(GPIO0B6_MMC1_D3_NAME, GPIO0B_MMC1_D3); + //rk30_mux_api_set(GPIO0B2_MMC1_DETN_NAME, GPIO0B_MMC1_DETN); + +#else + +#if defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT) + gpio_request(SDMMC1_WRITE_PROTECT_PIN, "sdio-wp"); + gpio_direction_input(SDMMC1_WRITE_PROTECT_PIN); +#endif + +#endif + + return 0; +} + +struct rk29_sdmmc_platform_data default_sdmmc1_data = { + .host_ocr_avail = + (MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 | MMC_VDD_28_29 | + MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | + MMC_VDD_33_34), + +#if !defined(CONFIG_USE_SDMMC1_FOR_WIFI_DEVELOP_BOARD) + .host_caps = (MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ | + MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), +#else + .host_caps = + (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), +#endif + + .io_init = rk29_sdmmc1_cfg_gpio, + +#if !defined(CONFIG_SDMMC_RK29_OLD) + .set_iomux = rk29_sdmmc_set_iomux, +#endif + + .dma_name = "sdio", +#ifdef CONFIG_SDMMC1_USE_DMA + .use_dma = 1, +#else + .use_dma = 0, +#endif + +#if !defined(CONFIG_USE_SDMMC1_FOR_WIFI_DEVELOP_BOARD) +#ifdef CONFIG_WIFI_CONTROL_FUNC + .status = rk29sdk_wifi_status, + .register_status_notify = rk29sdk_wifi_status_register, +#endif +#if 0 + .detect_irq = RK29SDK_WIFI_SDIO_CARD_DETECT_N, +#endif + +#if defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT) + .write_prt = SDMMC1_WRITE_PROTECT_PIN, +#else + .write_prt = INVALID_GPIO, +#endif + +#else + .detect_irq = INVALID_GPIO, + .enable_sd_wakeup = 0, +#endif + +}; +#endif //endif--#ifdef CONFIG_SDMMC1_RK29 + +/************************************************************************************************** + * the end of setting for SDMMC devices +**************************************************************************************************/ + + + #define RK2928_FB_MEM_SIZE 3*SZ_1M #ifdef CONFIG_FB_ROCKCHIP @@ -283,7 +747,33 @@ static void __init rk30_i2c_register_board_info(void) static struct spi_board_info board_spi_devices[] = { }; +#ifdef CONFIG_ION +#define ION_RESERVE_SIZE (8 * SZ_1M) +static struct ion_platform_data rk30_ion_pdata = { + .nr = 1, + .heaps = { + { + .type = ION_HEAP_TYPE_CARVEOUT, + .id = ION_NOR_HEAP_ID, + .name = "norheap", + .size = ION_RESERVE_SIZE, + } + }, +}; + +static struct platform_device device_ion = { + .name = "ion-rockchip", + .id = 0, + .dev = { + .platform_data = &rk30_ion_pdata, + }, +}; +#endif + static struct platform_device *devices[] __initdata = { +#ifdef CONFIG_ION + &device_ion, +#endif #ifdef CONFIG_FB_ROCKCHIP &device_fb, #endif @@ -298,6 +788,9 @@ static void __init rk2928_board_init(void) static void __init rk2928_reserve(void) { +#ifdef CONFIG_ION + rk30_ion_pdata.heaps[0].base = board_mem_reserve_add("ion", ION_RESERVE_SIZE); +#endif #ifdef CONFIG_FB_ROCKCHIP resource_fb[0].start = board_mem_reserve_add("fb0", RK2928_FB_MEM_SIZE); resource_fb[0].end = resource_fb[0].start + RK2928_FB_MEM_SIZE - 1; @@ -353,6 +846,12 @@ static struct clk_lookup clks[] = { CLK(NULL, "hclk_lcdc0", &xin24m), CLK(NULL, "aclk_lcdc0", &xin24m), CLK(NULL, "dclk_lcdc0", &xin24m), + + CLK(NULL, "pd_cif0", &xin24m), + CLK(NULL, "aclk_cif0", &xin24m), + CLK(NULL, "hclk_cif0", &xin24m), + CLK(NULL, "cif0_in", &xin24m), + CLK(NULL, "cif0_out", &xin24m), }; void __init rk30_clock_init(void) diff --git a/arch/arm/mach-rk2928/board-rk2928-sdk-sdmmc.c b/arch/arm/mach-rk2928/board-rk2928-sdk-sdmmc.c new file mode 100644 index 000000000000..09395ed49c40 --- /dev/null +++ b/arch/arm/mach-rk2928/board-rk2928-sdk-sdmmc.c @@ -0,0 +1,441 @@ +/* arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c + * + * Copyright (C) 2012 ROCKCHIP, Inc. + * + * 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. + * + */ + +#ifdef CONFIG_SDMMC_RK29 + +#if !defined(CONFIG_SDMMC_RK29_OLD) +static void rk29_sdmmc_gpio_open(int device_id, int on) +{ + switch(device_id) + { + case 0://mmc0 + { + #ifdef CONFIG_SDMMC0_RK29 + if(on) + { + gpio_direction_output(RK2928_PIN1_PC0,GPIO_HIGH);//set mmc0-clk to high + gpio_direction_output(RK2928_PIN1_PB7,GPIO_HIGH);// set mmc0-cmd to high. + gpio_direction_output(RK2928_PIN1_PC2,GPIO_HIGH);//set mmc0-data0 to high. + gpio_direction_output(RK2928_PIN1_PC3,GPIO_HIGH);//set mmc0-data1 to high. + gpio_direction_output(RK2928_PIN1_PC4,GPIO_HIGH);//set mmc0-data2 to high. + gpio_direction_output(RK2928_PIN1_PC5,GPIO_HIGH);//set mmc0-data3 to high. + + mdelay(30); + } + else + { + rk30_mux_api_set(GPIO1C0_MMC0_CLKOUT_NAME, GPIO1C_GPIO1C0); + gpio_request(RK2928_PIN1_PC0, "mmc0-clk"); + gpio_direction_output(RK2928_PIN1_PC0,GPIO_LOW);//set mmc0-clk to low. + + rk30_mux_api_set(GPIO1B7_MMC0_CMD_NAME, GPIO1B_GPIO1B7); + gpio_request(RK2928_PIN1_PB7, "mmc0-cmd"); + gpio_direction_output(RK2928_PIN1_PB7,GPIO_LOW);//set mmc0-cmd to low. + + rk30_mux_api_set(GPIO1C2_MMC0_D0_NAME, GPIO1C_GPIO1C2); + gpio_request(RK2928_PIN1_PC2, "mmc0-data0"); + gpio_direction_output(RK2928_PIN1_PC2,GPIO_LOW);//set mmc0-data0 to low. + + rk30_mux_api_set(GPIO1C3_MMC0_D1_NAME, GPIO1C_GPIO1C3); + gpio_request(RK2928_PIN1_PC3, "mmc0-data1"); + gpio_direction_output(RK2928_PIN1_PC3,GPIO_LOW);//set mmc0-data1 to low. + + rk30_mux_api_set(GPIO1C4_MMC0_D2_NAME, GPIO1C_GPIO1C4); + gpio_request(RK2928_PIN1_PC4, "mmc0-data2"); + gpio_direction_output(RK2928_PIN1_PC4,GPIO_LOW);//set mmc0-data2 to low. + + rk30_mux_api_set(GPIO1C5_MMC0_D3_NAME, GPIO1C_GPIO1C5); + gpio_request(RK2928_PIN1_PC5, "mmc0-data3"); + gpio_direction_output(RK2928_PIN1_PC5,GPIO_LOW);//set mmc0-data3 to low. + + mdelay(30); + } + #endif + } + break; + + case 1://mmc1 + { + #ifdef CONFIG_SDMMC1_RK29 + if(on) + { + gpio_direction_output(RK2928_PIN0_PB1,GPIO_HIGH);//set mmc1-clk to high + gpio_direction_output(RK2928_PIN0_PB0,GPIO_HIGH);//set mmc1-cmd to high. + gpio_direction_output(RK2928_PIN0_PB3,GPIO_HIGH);//set mmc1-data0 to high. + gpio_direction_output(RK2928_PIN0_PB4,GPIO_HIGH);//set mmc1-data1 to high. + gpio_direction_output(RK2928_PIN0_PB5,GPIO_HIGH);//set mmc1-data2 to high. + gpio_direction_output(RK2928_PIN0_PB6,GPIO_HIGH);//set mmc1-data3 to high. + mdelay(100); + } + else + { + rk30_mux_api_set(GPIO0B1_MMC1_CLKOUT_NAME, GPIO0B_GPIO0B1); + gpio_request(RK2928_PIN0_PB1, "mmc1-clk"); + gpio_direction_output(RK2928_PIN0_PB1,GPIO_LOW);//set mmc1-clk to low. + + rk30_mux_api_set(GPIO0B0_MMC1_CMD_NAME, GPIO0B_GPIO0B0); + gpio_request(RK2928_PIN0_PB0, "mmc1-cmd"); + gpio_direction_output(RK2928_PIN0_PB0,GPIO_LOW);//set mmc1-cmd to low. + + rk30_mux_api_set(GPIO0B3_MMC1_D0_NAME, GPIO0B_GPIO0B3); + gpio_request(RK2928_PIN0_PB3, "mmc1-data0"); + gpio_direction_output(RK2928_PIN0_PB3,GPIO_LOW);//set mmc1-data0 to low. + + mdelay(100); + } + #endif + } + break; + + case 2: //mmc2 + break; + + default: + break; + } +} + +static void rk29_sdmmc_set_iomux_mmc0(unsigned int bus_width) +{ + switch (bus_width) + { + + case 1://SDMMC_CTYPE_4BIT: + { + rk30_mux_api_set(GPIO1C3_MMC0_D1_NAME, GPIO1C_MMC0_D1); + rk30_mux_api_set(GPIO1C4_MMC0_D2_NAME, GPIO1C_MMC0_D2); + rk30_mux_api_set(GPIO1C5_MMC0_D3_NAME, GPIO1C_MMC0_D3); + } + break; + + case 0x10000://SDMMC_CTYPE_8BIT: + break; + case 0xFFFF: //gpio_reset + { + rk30_mux_api_set(GPIO1B6_MMC0_PWREN_NAME, GPIO1B_GPIO1B6); + gpio_request(RK2928_PIN1_PB6,"sdmmc-power"); + gpio_direction_output(RK2928_PIN1_PB6,GPIO_HIGH); //power-off + + rk29_sdmmc_gpio_open(0, 0); + + gpio_direction_output(RK2928_PIN1_PB6,GPIO_LOW); //power-on + + rk29_sdmmc_gpio_open(0, 1); + } + break; + + default: //case 0://SDMMC_CTYPE_1BIT: + { + rk30_mux_api_set(GPIO1B7_MMC0_CMD_NAME, GPIO1B_MMC0_CMD); + rk30_mux_api_set(GPIO1C0_MMC0_CLKOUT_NAME, GPIO1C_MMC0_CLKOUT); + rk30_mux_api_set(GPIO1C2_MMC0_D0_NAME, GPIO1C_MMC0_D0); + + rk30_mux_api_set(GPIO1C3_MMC0_D1_NAME, GPIO1C_GPIO1C3); + gpio_request(RK2928_PIN1_PC3, "mmc0-data1"); + gpio_direction_output(RK2928_PIN1_PC3,GPIO_HIGH);//set mmc0-data1 to high. + + rk30_mux_api_set(GPIO1C4_MMC0_D2_NAME, GPIO1C_GPIO1C4); + gpio_request(RK2928_PIN1_PC4, "mmc0-data2"); + gpio_direction_output(RK2928_PIN1_PC4,GPIO_HIGH);//set mmc0-data2 to high. + + rk30_mux_api_set(GPIO1C5_MMC0_D3_NAME, GPIO1C_GPIO1C5); + gpio_request(RK2928_PIN1_PC5, "mmc0-data3"); + gpio_direction_output(RK2928_PIN1_PC5,GPIO_HIGH);//set mmc0-data3 to high. + } + break; + } +} + +static void rk29_sdmmc_set_iomux_mmc1(unsigned int bus_width) +{ + rk30_mux_api_set(GPIO0B0_MMC1_CMD_NAME, GPIO0B_MMC1_CMD); + rk30_mux_api_set(GPIO0B1_MMC1_CLKOUT_NAME, GPIO0B_MMC1_CLKOUT); + rk30_mux_api_set(GPIO0B3_MMC1_D0_NAME, GPIO0B_MMC1_D0); + rk30_mux_api_set(GPIO0B4_MMC1_D1_NAME, GPIO0B_MMC1_D1); + rk30_mux_api_set(GPIO0B5_MMC1_D2_NAME, GPIO0B_MMC1_D2); + rk30_mux_api_set(GPIO0B6_MMC1_D3_NAME, GPIO0B_MMC1_D3); +} + +static void rk29_sdmmc_set_iomux_mmc2(unsigned int bus_width) +{ + ;// +} + +static void rk29_sdmmc_set_iomux(int device_id, unsigned int bus_width) +{ + switch(device_id) + { + case 0: + #ifdef CONFIG_SDMMC0_RK29 + rk29_sdmmc_set_iomux_mmc0(bus_width); + #endif + break; + case 1: + #ifdef CONFIG_SDMMC1_RK29 + rk29_sdmmc_set_iomux_mmc1(bus_width); + #endif + break; + case 2: + rk29_sdmmc_set_iomux_mmc2(bus_width); + break; + default: + break; + } +} + +#endif + + +//int rk29sdk_wifi_power_state = 0; +//int rk29sdk_bt_power_state = 0; + +#ifdef CONFIG_WIFI_CONTROL_FUNC +//#define RK29SDK_WIFI_BT_GPIO_POWER_N RK30_PIN3_PD0 +//#define RK29SDK_WIFI_GPIO_RESET_N RK30_PIN3_PD0 +//#define RK29SDK_BT_GPIO_RESET_N RK30_PIN3_PD1 +#define RK30SDK_WIFI_GPIO_POWER_N RK30_PIN3_PD0 +//#define RK30SDK_BT_GPIO_POWER_N RK30_PIN3_PD1 + +#define PREALLOC_WLAN_SEC_NUM 4 +#define PREALLOC_WLAN_BUF_NUM 160 +#define PREALLOC_WLAN_SECTION_HEADER 24 + +#define WLAN_SECTION_SIZE_0 (PREALLOC_WLAN_BUF_NUM * 128) +#define WLAN_SECTION_SIZE_1 (PREALLOC_WLAN_BUF_NUM * 128) +#define WLAN_SECTION_SIZE_2 (PREALLOC_WLAN_BUF_NUM * 512) +#define WLAN_SECTION_SIZE_3 (PREALLOC_WLAN_BUF_NUM * 1024) + +#define WLAN_SKB_BUF_NUM 16 + +static struct sk_buff *wlan_static_skb[WLAN_SKB_BUF_NUM]; + +struct wifi_mem_prealloc { + void *mem_ptr; + unsigned long size; +}; + +static struct wifi_mem_prealloc wifi_mem_array[PREALLOC_WLAN_SEC_NUM] = { + {NULL, (WLAN_SECTION_SIZE_0 + PREALLOC_WLAN_SECTION_HEADER)}, + {NULL, (WLAN_SECTION_SIZE_1 + PREALLOC_WLAN_SECTION_HEADER)}, + {NULL, (WLAN_SECTION_SIZE_2 + PREALLOC_WLAN_SECTION_HEADER)}, + {NULL, (WLAN_SECTION_SIZE_3 + PREALLOC_WLAN_SECTION_HEADER)} +}; + +static void *rk29sdk_mem_prealloc(int section, unsigned long size) +{ + if (section == PREALLOC_WLAN_SEC_NUM) + return wlan_static_skb; + + if ((section < 0) || (section > PREALLOC_WLAN_SEC_NUM)) + return NULL; + + if (wifi_mem_array[section].size < size) + return NULL; + + return wifi_mem_array[section].mem_ptr; +} + +static int __init rk29sdk_init_wifi_mem(void) +{ + int i; + int j; + + for (i = 0 ; i < WLAN_SKB_BUF_NUM ; i++) { + wlan_static_skb[i] = dev_alloc_skb( + ((i < (WLAN_SKB_BUF_NUM / 2)) ? 4096 : 8192)); + + if (!wlan_static_skb[i]) + goto err_skb_alloc; + } + + for (i = 0 ; i < PREALLOC_WLAN_SEC_NUM ; i++) { + wifi_mem_array[i].mem_ptr = + kmalloc(wifi_mem_array[i].size, GFP_KERNEL); + + if (!wifi_mem_array[i].mem_ptr) + goto err_mem_alloc; + } + return 0; + +err_mem_alloc: + pr_err("Failed to mem_alloc for WLAN\n"); + for (j = 0 ; j < i ; j++) + kfree(wifi_mem_array[j].mem_ptr); + + i = WLAN_SKB_BUF_NUM; + +err_skb_alloc: + pr_err("Failed to skb_alloc for WLAN\n"); + for (j = 0 ; j < i ; j++) + dev_kfree_skb(wlan_static_skb[j]); + + return -ENOMEM; +} + +static int rk29sdk_wifi_cd = 0; /* wifi virtual 'card detect' status */ +static void (*wifi_status_cb)(int card_present, void *dev_id); +static void *wifi_status_cb_devid; + +static int rk29sdk_wifi_status(struct device *dev) +{ + return rk29sdk_wifi_cd; +} + +static int rk29sdk_wifi_status_register(void (*callback)(int card_present, void *dev_id), void *dev_id) +{ + if(wifi_status_cb) + return -EAGAIN; + wifi_status_cb = callback; + wifi_status_cb_devid = dev_id; + return 0; +} + +static int __init rk29sdk_wifi_bt_gpio_control_init(void) +{ + rk29sdk_init_wifi_mem(); + + rk29_mux_api_set(GPIO0D6_MMC1_PWREN_NAME, GPIO0D_GPIO0D6); + + if (gpio_request(RK30SDK_WIFI_GPIO_POWER_N, "wifi_power")) { + pr_info("%s: request wifi power gpio failed\n", __func__); + return -1; + } + + /*if (gpio_request(RK29SDK_WIFI_GPIO_RESET_N, "wifi reset")) { + pr_info("%s: request wifi reset gpio failed\n", __func__); + gpio_free(RK30SDK_WIFI_GPIO_POWER_N); + return -1; + } + + if (gpio_request(RK29SDK_BT_GPIO_RESET_N, "bt reset")) { + pr_info("%s: request bt reset gpio failed\n", __func__); + gpio_free(RK29SDK_WIFI_GPIO_RESET_N); + return -1; + }*/ + + gpio_direction_output(RK30SDK_WIFI_GPIO_POWER_N, GPIO_LOW); + //gpio_direction_output(RK29SDK_WIFI_GPIO_RESET_N, GPIO_LOW); + //gpio_direction_output(RK29SDK_BT_GPIO_RESET_N, GPIO_LOW); + + #if defined(CONFIG_SDMMC1_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + + rk29_mux_api_set(GPIO0B4_MMC1_D1_NAME, GPIO0B_GPIO0B4); + gpio_request(RK2928_PIN0_PB4, "mmc1-data1"); + gpio_direction_output(RK2928_PIN0_PB4,GPIO_LOW);//set mmc1-data1 to low. + + rk29_mux_api_set(GPIO0B5_MMC1_D2_NAME, GPIO0B_GPIO0B5); + gpio_request(RK2928_PIN0_PB5, "mmc1-data2"); + gpio_direction_output(RK2928_PIN0_PB5,GPIO_LOW);//set mmc1-data2 to low. + + rk29_mux_api_set(GPIO0B6_MMC1_D3_NAME, GPIO0B_GPIO0B6); + gpio_request(RK2928_PIN0_PB6, "mmc1-data3"); + gpio_direction_output(RK2928_PIN0_PB6,GPIO_LOW);//set mmc1-data3 to low. + + rk29_sdmmc_gpio_open(1, 0); //added by xbw at 2011-10-13 + #endif + pr_info("%s: init finished\n",__func__); + + return 0; +} + +static int rk29sdk_wifi_power(int on) +{ + pr_info("%s: %d\n", __func__, on); + if (on){ + gpio_set_value(RK30SDK_WIFI_GPIO_POWER_N, GPIO_HIGH); + + #if defined(CONFIG_SDMMC1_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + rk29_sdmmc_gpio_open(1, 1); //added by xbw at 2011-10-13 + #endif + + //gpio_set_value(RK29SDK_WIFI_GPIO_RESET_N, GPIO_HIGH); + mdelay(100); + pr_info("wifi turn on power\n"); + }else{ +// if (!rk29sdk_bt_power_state){ + gpio_set_value(RK30SDK_WIFI_GPIO_POWER_N, GPIO_LOW); + + #if defined(CONFIG_SDMMC1_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + rk29_sdmmc_gpio_open(1, 0); //added by xbw at 2011-10-13 + #endif + + mdelay(100); + pr_info("wifi shut off power\n"); +// }else +// { +// pr_info("wifi shouldn't shut off power, bt is using it!\n"); +// } + //gpio_set_value(RK29SDK_WIFI_GPIO_RESET_N, GPIO_LOW); + + } + +// rk29sdk_wifi_power_state = on; + return 0; +} + +static int rk29sdk_wifi_reset_state; +static int rk29sdk_wifi_reset(int on) +{ + pr_info("%s: %d\n", __func__, on); + //gpio_set_value(RK29SDK_WIFI_GPIO_RESET_N, on); + //mdelay(100); + rk29sdk_wifi_reset_state = on; + return 0; +} + +int rk29sdk_wifi_set_carddetect(int val) +{ + pr_info("%s:%d\n", __func__, val); + rk29sdk_wifi_cd = val; + if (wifi_status_cb){ + wifi_status_cb(val, wifi_status_cb_devid); + }else { + pr_warning("%s, nobody to notify\n", __func__); + } + return 0; +} +EXPORT_SYMBOL(rk29sdk_wifi_set_carddetect); + +#define WIFI_HOST_WAKE RK30_PIN3_PD2 + +static struct resource resources[] = { + { + .start = WIFI_HOST_WAKE, + .flags = IORESOURCE_IRQ, + .name = "bcmdhd_wlan_irq", + }, +}; + +static struct wifi_platform_data rk29sdk_wifi_control = { + .set_power = rk29sdk_wifi_power, + .set_reset = rk29sdk_wifi_reset, + .set_carddetect = rk29sdk_wifi_set_carddetect, + .mem_prealloc = rk29sdk_mem_prealloc, +}; + +static struct platform_device rk29sdk_wifi_device = { + .name = "bcmdhd_wlan", + .id = 1, + .num_resources = ARRAY_SIZE(resources), + .resource = resources, + .dev = { + .platform_data = &rk29sdk_wifi_control, + }, +}; +#endif + + +#endif // endif --#ifdef CONFIG_SDMMC_RK29 + diff --git a/arch/arm/mach-rk2928/devices.c b/arch/arm/mach-rk2928/devices.c index 21e24335a532..4d9f39826138 100755 --- a/arch/arm/mach-rk2928/devices.c +++ b/arch/arm/mach-rk2928/devices.c @@ -620,6 +620,65 @@ static struct platform_device device_keys = { }, }; #endif + +#ifdef CONFIG_SDMMC0_RK29 +static struct resource resources_sdmmc0[] = { + { + .start = IRQ_SDMMC, + .end = IRQ_SDMMC, + .flags = IORESOURCE_IRQ, + }, + { + .start = RK2928_SDMMC_PHYS, + .end = RK2928_SDMMC_PHYS + RK2928_SDMMC_SIZE -1, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device device_sdmmc0 = { + .name = "rk29_sdmmc", + .id = 0, + .num_resources = ARRAY_SIZE(resources_sdmmc0), + .resource = resources_sdmmc0, + .dev = { + .platform_data = &default_sdmmc0_data, + }, +}; +#endif + +#ifdef CONFIG_SDMMC1_RK29 +static struct resource resources_sdmmc1[] = { + { + .start = IRQ_SDIO, + .end = IRQ_SDIO, + .flags = IORESOURCE_IRQ, + }, + { + .start = RK2928_SDIO_PHYS, + .end = RK2928_SDIO_PHYS + RK2928_SDIO_SIZE - 1, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device device_sdmmc1 = { + .name = "rk29_sdmmc", + .id = 1, + .num_resources = ARRAY_SIZE(resources_sdmmc1), + .resource = resources_sdmmc1, + .dev = { + .platform_data = &default_sdmmc1_data, + }, +}; +#endif +static void __init rk2928_init_sdmmc(void) +{ +#ifdef CONFIG_SDMMC0_RK29 + platform_device_register(&device_sdmmc0); +#endif +#ifdef CONFIG_SDMMC1_RK29 + platform_device_register(&device_sdmmc1); +#endif +} static int __init rk2928_init_devices(void) { rk2928_init_dma(); @@ -635,6 +694,7 @@ static int __init rk2928_init_devices(void) #ifdef CONFIG_LCDC_RK2928 platform_device_register(&device_lcdc); #endif + rk2928_init_sdmmc(); #if defined(CONFIG_FIQ_DEBUGGER) && defined(DEBUG_UART_PHYS) rk_serial_debug_init(DEBUG_UART_BASE, IRQ_DEBUG_UART, IRQ_UART_SIGNAL, -1); #endif diff --git a/drivers/mmc/host/rk29_sdmmc.c b/drivers/mmc/host/rk29_sdmmc.c index 57ada8690736..acab9705e8de 100755 --- a/drivers/mmc/host/rk29_sdmmc.c +++ b/drivers/mmc/host/rk29_sdmmc.c @@ -50,6 +50,22 @@ #include "rk29_sdmmc.h" +#if defined(CONFIG_ARCH_RK29) +#define SD_DETECT_PIN RK29_PIN2_PA2 +#define SD_DETECT_NAME GPIO2A2_SDMMC0DETECTN_NAME +#define SD_DETECT_GPIO_MODE GPIO2L_GPIO2A2 +#define SD_DETECT_DET_MODE GPIO2L_SDMMC0_DETECT_N +#elif defined(CONFIG_ARCH_RK30) +#define SD_DETECT_PIN RK30_PIN3_PB6 +#define SD_DETECT_NAME GPIO3B6_SDMMC0DETECTN_NAME +#define SD_DETECT_GPIO_MODE GPIO3B_GPIO3B6 +#define SD_DETECT_DET_MODE GPIO3B_SDMMC_DETECT_N +#elif defined(CONFIG_ARCH_RK2928) +#define SD_DETECT_PIN RK2928_PIN1_PC7 +#define SD_DETECT_NAME GPIO1C1_MMC0_DETN_NAME +#define SD_DETECT_GPIO_MODE GPIO1C_GPIO1C1 +#define SD_DETECT_DET_MODE GPIO1C_MMC0_DETN +#endif #define RK29_SDMMC_xbw_Debug 0 @@ -1103,6 +1119,7 @@ static int rk29_sdmmc_submit_data_dma(struct rk29_sdmmc *host, struct mmc_data * rk29_sdmmc_control_host_dma(host, TRUE);// enable dma ret = rk29_dma_ctrl(host->dma_info.chn, RK29_DMAOP_START); + if(ret < 0) { printk(KERN_WARNING "%s..%d...rk29_dma_ctrl start error![%s]\n", __FUNCTION__, __LINE__, host->dma_name); @@ -1470,7 +1487,7 @@ int rk29_sdmmc_reset_controller(struct rk29_sdmmc *host) /* reset */ #if defined(CONFIG_ARCH_RK29) rk29_sdmmc_write(host->regs, SDMMC_CTRL,(SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET )); -#elif defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) +#elif defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) || defined(CONFIG_ARCH_RK2928) rk29_sdmmc_write(host->regs, SDMMC_CTRL,(SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET)); #endif timeOut = 1000; @@ -3566,7 +3583,6 @@ static int __exit rk29_sdmmc_remove(struct platform_device *pdev) return 0; } - #ifdef CONFIG_PM #if defined(CONFIG_ARCH_RK29) @@ -3574,7 +3590,7 @@ static irqreturn_t det_keys_isr(int irq, void *dev_id) { struct rk29_sdmmc *host = dev_id; dev_info(&host->pdev->dev, "sd det_gpio changed(%s), send wakeup key!\n", - gpio_get_value(RK29_PIN2_PA2)?"removed":"insert"); + gpio_get_value(SD_DETECT_PIN)?"removed":"insert"); rk29_sdmmc_detect_change((unsigned long)dev_id); return IRQ_HANDLED; @@ -3583,13 +3599,13 @@ static irqreturn_t det_keys_isr(int irq, void *dev_id) static int rk29_sdmmc_sdcard_suspend(struct rk29_sdmmc *host) { int ret = 0; - rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_GPIO2A2); - gpio_request(RK29_PIN2_PA2, "sd_detect"); - gpio_direction_input(RK29_PIN2_PA2); + rk29_mux_api_set(SD_DETECT_NAME, SD_DETECT_GPIO_MODE); + gpio_request(SD_DETECT_PIN, "sd_detect"); + gpio_direction_input(SD_DETECT_PIN); - host->gpio_irq = gpio_to_irq(RK29_PIN2_PA2); + host->gpio_irq = gpio_to_irq(SD_DETECT_PIN); ret = request_irq(host->gpio_irq, det_keys_isr, - (gpio_get_value(RK29_PIN2_PA2))?IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING, + (gpio_get_value(SD_DETECT_PIN))?IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING, "sd_detect", host); @@ -3601,16 +3617,16 @@ static void rk29_sdmmc_sdcard_resume(struct rk29_sdmmc *host) { disable_irq_wake(host->gpio_irq); free_irq(host->gpio_irq,host); - gpio_free(RK29_PIN2_PA2); - rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_SDMMC0_DETECT_N); + gpio_free(SD_DETECT_PIN); + rk29_mux_api_set(SD_DETECT_NAME, SD_DETECT_DET_MODE); } -#elif defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) +#elif defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) || defined(CONFIG_ARCH_RK2928) static irqreturn_t det_keys_isr(int irq, void *dev_id) { struct rk29_sdmmc *host = dev_id; dev_info(&host->pdev->dev, "sd det_gpio changed(%s), send wakeup key!\n", - gpio_get_value(RK30_PIN3_PB6)?"removed":"insert"); + gpio_get_value(SD_DETECT_PIN)?"removed":"insert"); rk29_sdmmc_detect_change((unsigned long)dev_id); return IRQ_HANDLED; @@ -3619,13 +3635,13 @@ static irqreturn_t det_keys_isr(int irq, void *dev_id) static int rk29_sdmmc_sdcard_suspend(struct rk29_sdmmc *host) { int ret = 0; - rk29_mux_api_set(GPIO3B6_SDMMC0DETECTN_NAME, GPIO3B_GPIO3B6); - gpio_request(RK30_PIN3_PB6, "sd_detect"); - gpio_direction_input(RK30_PIN3_PB6); + rk29_mux_api_set(SD_DETECT_NAME, SD_DETECT_GPIO_MODE); + gpio_request(SD_DETECT_PIN, "sd_detect"); + gpio_direction_input(SD_DETECT_PIN); - host->gpio_irq = gpio_to_irq(RK30_PIN3_PB6); + host->gpio_irq = gpio_to_irq(SD_DETECT_PIN); ret = request_irq(host->gpio_irq, det_keys_isr, - (gpio_get_value(RK30_PIN3_PB6))?IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING, + (gpio_get_value(SD_DETECT_PIN))?IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING, "sd_detect", host); @@ -3637,8 +3653,8 @@ static void rk29_sdmmc_sdcard_resume(struct rk29_sdmmc *host) { disable_irq_wake(host->gpio_irq); free_irq(host->gpio_irq,host); - gpio_free(RK30_PIN3_PB6); - rk29_mux_api_set(GPIO3B6_SDMMC0DETECTN_NAME, GPIO3B_SDMMC0_DETECT_N); + gpio_free(SD_DETECT_PIN); + rk29_mux_api_set(SD_DETECT_NAME, SD_DETECT_DET_MODE); } #endif diff --git a/drivers/mmc/host/rk29_sdmmc.h b/drivers/mmc/host/rk29_sdmmc.h index 9360cd3ea85e..17b6d2b209b8 100755 --- a/drivers/mmc/host/rk29_sdmmc.h +++ b/drivers/mmc/host/rk29_sdmmc.h @@ -48,7 +48,7 @@ #if defined(CONFIG_ARCH_RK29) #define SDMMC_DATA (0x100) -#elif defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) +#elif defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) || defined(CONFIG_ARCH_RK2928) #define SDMMC_VERID (0x06c) //Version ID register #define SDMMC_UHS_REG (0x074) //UHS-I register #define SDMMC_RST_n (0x078) //Hardware reset register @@ -102,7 +102,7 @@ /* Interrupt status & mask register defines(base+0x24) */ #if defined(CONFIG_ARCH_RK29) #define SDMMC_INT_SDIO RK2818_BIT(16) //SDIO interrupt -#elif defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) +#elif defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) || defined(CONFIG_ARCH_RK2928) #define SDMMC_INT_SDIO RK2818_BIT(24) //SDIO interrupt #define SDMMC_INT_UNBUSY RK2818_BIT(16) //data no busy interrupt #endif @@ -181,7 +181,7 @@ #define RX_WMARK (0xF) //RX watermark level set to 15 #define TX_WMARK (0x10) //TX watermark level set to 16 -#elif defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) +#elif defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) || defined(CONFIG_ARCH_RK2928) #define FIFO_DEPTH (0x100) //FIFO depth = 256 word #define RX_WMARK_SHIFT (16) #define TX_WMARK_SHIFT (0) From 42c4038c46249ce61ba68f99cb0a0e0c68f5a691 Mon Sep 17 00:00:00 2001 From: hxy Date: Mon, 23 Jul 2012 16:14:29 +0800 Subject: [PATCH 036/261] rk31: fix sdmmc bug after rk2928 commit sdmmc support --- drivers/mmc/host/rk29_sdmmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/rk29_sdmmc.c b/drivers/mmc/host/rk29_sdmmc.c index acab9705e8de..952b51c1dde1 100755 --- a/drivers/mmc/host/rk29_sdmmc.c +++ b/drivers/mmc/host/rk29_sdmmc.c @@ -55,11 +55,11 @@ #define SD_DETECT_NAME GPIO2A2_SDMMC0DETECTN_NAME #define SD_DETECT_GPIO_MODE GPIO2L_GPIO2A2 #define SD_DETECT_DET_MODE GPIO2L_SDMMC0_DETECT_N -#elif defined(CONFIG_ARCH_RK30) +#elif defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) #define SD_DETECT_PIN RK30_PIN3_PB6 #define SD_DETECT_NAME GPIO3B6_SDMMC0DETECTN_NAME #define SD_DETECT_GPIO_MODE GPIO3B_GPIO3B6 -#define SD_DETECT_DET_MODE GPIO3B_SDMMC_DETECT_N +#define SD_DETECT_DET_MODE GPIO3B_SDMMC0_DETECT_N #elif defined(CONFIG_ARCH_RK2928) #define SD_DETECT_PIN RK2928_PIN1_PC7 #define SD_DETECT_NAME GPIO1C1_MMC0_DETN_NAME From 046ee1ba24b1f38a4d4ae73a7f8a92dabd3534f8 Mon Sep 17 00:00:00 2001 From: Zheng Yang Date: Mon, 23 Jul 2012 18:14:13 +0800 Subject: [PATCH 037/261] rk2928: add audio codec. --- arch/arm/mach-rk2928/devices.c | 21 ++ sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 3 +- sound/soc/codecs/rk2928_codec.c | 337 ++++++++++++++++++++++++++++++++ sound/soc/codecs/rk2928_codec.h | 82 ++++++++ sound/soc/rk29/Kconfig | 12 +- sound/soc/rk29/Makefile | 2 + sound/soc/rk29/rk2928-card.c | 163 +++++++++++++++ 8 files changed, 622 insertions(+), 2 deletions(-) mode change 100644 => 100755 sound/soc/codecs/Kconfig mode change 100644 => 100755 sound/soc/codecs/Makefile create mode 100755 sound/soc/codecs/rk2928_codec.c create mode 100755 sound/soc/codecs/rk2928_codec.h mode change 100644 => 100755 sound/soc/rk29/Makefile create mode 100755 sound/soc/rk29/rk2928-card.c diff --git a/arch/arm/mach-rk2928/devices.c b/arch/arm/mach-rk2928/devices.c index 4d9f39826138..5c670f4330df 100755 --- a/arch/arm/mach-rk2928/devices.c +++ b/arch/arm/mach-rk2928/devices.c @@ -679,6 +679,24 @@ static void __init rk2928_init_sdmmc(void) platform_device_register(&device_sdmmc1); #endif } + +#ifdef CONFIG_SND_SOC_RK2928 +static struct resource resources_acodec[] = { + { + .start = RK2928_ACODEC_PHYS, + .end = RK2928_ACODEC_PHYS + RK2928_ACODEC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device device_acodec = { + .name = "rk2928-codec", + .id = -1, + .num_resources = ARRAY_SIZE(resources_acodec), + .resource = resources_acodec, +}; +#endif + static int __init rk2928_init_devices(void) { rk2928_init_dma(); @@ -699,6 +717,9 @@ static int __init rk2928_init_devices(void) rk_serial_debug_init(DEBUG_UART_BASE, IRQ_DEBUG_UART, IRQ_UART_SIGNAL, -1); #endif rk2928_init_i2s(); +#ifdef CONFIG_SND_SOC_RK2928 + platform_device_register(&device_acodec); +#endif return 0; } arch_initcall(rk2928_init_devices); diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig old mode 100644 new mode 100755 index ab6dbb51b7c2..7a3904d93387 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -418,3 +418,7 @@ config SND_SOC_WM2000 config SND_SOC_WM9090 tristate + +config SND_SOC_RK2928 + tristate + depends on ARCH_RK2928 \ No newline at end of file diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile old mode 100644 new mode 100755 index ea82f0d8e08e..2e6d428b45d0 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -89,7 +89,7 @@ snd-soc-wm-hubs-objs := wm_hubs.o snd-soc-rk1000-objs := rk1000_codec.o snd-soc-jz4740-codec-objs := jz4740.o snd-soc-rk610-objs := rk610_codec.o - +snd-soc-rk2928-objs := rk2928_codec.o # Amp snd-soc-lm4857-objs := lm4857.o snd-soc-max9877-objs := max9877.o @@ -188,6 +188,7 @@ obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o obj-$(CONFIG_SND_SOC_RK1000) += snd-soc-rk1000.o obj-$(CONFIG_SND_SOC_RK610) += snd-soc-rk610.o +obj-$(CONFIG_SND_SOC_RK2928) += snd-soc-rk2928.o # Amp obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o diff --git a/sound/soc/codecs/rk2928_codec.c b/sound/soc/codecs/rk2928_codec.c new file mode 100755 index 000000000000..57086b8ec237 --- /dev/null +++ b/sound/soc/codecs/rk2928_codec.c @@ -0,0 +1,337 @@ +/* + * rk2928_codec.c ALSA SoC RK2928 codec driver + * + * Copyright 2012 Rockchip + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "rk2928_codec.h" + +static struct rk2928_codec_data { + struct device *dev; + struct clk *hclk; + int regbase; + int regbase_phy; + int regsize_phy; + int mute; +} rk2928_data; + +static const struct snd_soc_dapm_widget rk2928_dapm_widgets[] = { + SND_SOC_DAPM_DAC("DACL", "HIFI Playback", CODEC_REG_POWER, 5, 1), + SND_SOC_DAPM_DAC("DACR", "HIFI Playback", CODEC_REG_POWER, 4, 1), + SND_SOC_DAPM_PGA("DACL Amp", CODEC_REG_DAC_GAIN, 2, 0, NULL, 0), + SND_SOC_DAPM_PGA("DACR Amp", CODEC_REG_DAC_GAIN, 0, 0, NULL, 0), + SND_SOC_DAPM_OUT_DRV("DACL Drv", CODEC_REG_DAC_MUTE, 1, 1, NULL, 0), + SND_SOC_DAPM_OUT_DRV("DACR Drv", CODEC_REG_DAC_MUTE, 0, 1, NULL, 0), + SND_SOC_DAPM_OUTPUT("SPKL"), + SND_SOC_DAPM_OUTPUT("SPKR"), + SND_SOC_DAPM_ADC("ADCL", "HIFI Capture", CODEC_REG_POWER, 3, 1), + SND_SOC_DAPM_ADC("ADCR", "HIFI Capture", CODEC_REG_POWER, 2, 1), + SND_SOC_DAPM_INPUT("MICL"), + SND_SOC_DAPM_INPUT("MICR"), +}; + +static const struct snd_soc_dapm_route rk2928_audio_map[] = { + {"DACL Drv", "DACL Amp", "DACL"}, + {"DACR Drv", "DACR Amp", "DACR"}, + {"SPKL", NULL, "DACL Drv"}, + {"SPKR", NULL, "DACR Drv"}, + {"ADCL", NULL, "MICL"}, + {"ADCR", NULL, "MICR"}, +}; + +void codec_set_spk(bool on) +{ + +} + +static unsigned int rk2928_read(struct snd_soc_codec *codec, unsigned int reg) +{ + return readl(rk2928_data.regbase + reg); +} + +static int rk2928_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) +{ + DBG("%s reg 0x%02x value 0x%02x", __FUNCTION__, reg, value); + writel(value, rk2928_data.regbase + reg); + return 0; +} + +static int rk2928_write_mask(struct snd_soc_codec *codec, unsigned int reg, + unsigned int mask, unsigned int value) +{ + unsigned int regvalue = rk2928_read(codec, reg); + + DBG("%s reg 0x%02x mask 0x%02x value 0x%02x", __FUNCTION__, reg, mask, value); + + regvalue &= ~mask; + regvalue |= mask & value; + return rk2928_write(codec, reg, regvalue); +} + +static int rk2928_audio_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ +// struct snd_soc_pcm_runtime *rtd = substream->private_data; +// struct snd_soc_codec *codec = rtd->codec; +// struct rk2928_codec_data *priv = snd_soc_codec_get_drvdata(codec); + + DBG("%s", __FUNCTION__); + + return 0; +} + +static int rk2928_audio_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ +// struct snd_soc_pcm_runtime *rtd = substream->private_data; +// struct snd_soc_codec *codec = rtd->codec; +// struct rk2928_codec_data *priv = snd_soc_codec_get_drvdata(codec); + int err = 0; + + DBG("%s cmd 0x%x", __FUNCTION__, cmd); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + break; + default: + err = -EINVAL; + } + return err; +} + +static int rk2928_audio_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ +// struct snd_soc_pcm_runtime *rtd = substream->private_data; +// struct snd_soc_codec *codec = rtd->codec; + DBG("%s", __FUNCTION__); + return 0; +} + +static int rk2928_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + DBG("%s level %d", __FUNCTION__, level); + + if(codec == NULL) + return -1; + + switch(level) + { + case SND_SOC_BIAS_ON: + break; + case SND_SOC_BIAS_PREPARE: + rk2928_write_mask(codec, CODEC_REG_POWER, m_PD_MIC_BIAS | m_PD_CODEC, v_PD_MIC_BIAS(0) | v_PD_CODEC(0)); + break; + case SND_SOC_BIAS_STANDBY: + case SND_SOC_BIAS_OFF: + rk2928_write(codec, CODEC_REG_POWER, v_PWR_OFF); + break; + default: + return -1; + } + codec->dapm.bias_level = level; + return 0; +} + +static int rk2928_probe(struct snd_soc_codec *codec) +{ + struct platform_device *pdev = to_platform_device(codec->dev); + struct snd_soc_dapm_context *dapm = &codec->dapm; + struct resource *res, *mem; + int ret; + + DBG("%s", __FUNCTION__); + + snd_soc_codec_set_drvdata(codec, &rk2928_data); + + rk2928_data.dev = &pdev->dev; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Unable to get register resource\n"); + ret = -ENXIO; + goto err0; + } + rk2928_data.regbase_phy = res->start; + rk2928_data.regsize_phy = (res->end - res->start) + 1; + mem = request_mem_region(res->start, (res->end - res->start) + 1, pdev->name); + if (!mem) + { + dev_err(&pdev->dev, "failed to request mem region for rk2928 codec\n"); + ret = -ENOENT; + goto err0; + } + + + rk2928_data.regbase = (int)ioremap(res->start, (res->end - res->start) + 1); + if (!rk2928_data.regbase) { + dev_err(&pdev->dev, "cannot ioremap acodec registers\n"); + ret = -ENXIO; + goto err1; + } + + rk2928_write(codec, CODEC_REG_DAC_MUTE, v_MUTE_DAC(1)); + rk2928_write(codec, CODEC_REG_DAC_GAIN, v_GAIN_DAC(DAC_GAIN_3DB_P)); + rk2928_set_bias_level(codec, SND_SOC_BIAS_OFF); + + snd_soc_dapm_new_controls(dapm, rk2928_dapm_widgets, + ARRAY_SIZE(rk2928_dapm_widgets)); + snd_soc_dapm_add_routes(dapm, rk2928_audio_map, ARRAY_SIZE(rk2928_audio_map)); + + return 0; + +err1: + release_mem_region(res->start,(res->end - res->start) + 1); +// clk_disable(rk2928_data.hclk); +err0: + DBG("%s failed", __FUNCTION__); + return ret; +} + +static int rk2928_remove(struct snd_soc_codec *codec) +{ + return 0; +} + +static int rk2928_suspend(struct snd_soc_codec *codec, pm_message_t state) +{ + DBG("%s", __FUNCTION__); + rk2928_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} + +static int rk2928_resume(struct snd_soc_codec *codec) +{ + DBG("%s", __FUNCTION__); + rk2928_write(codec, CODEC_REG_POWER, v_PD_ADC(1) | v_PD_DAC(1) | v_PD_MIC_BIAS(1)); + return 0; +} + +static struct snd_soc_codec_driver rk2928_audio_codec_drv = { + .probe = rk2928_probe, + .remove = rk2928_remove, + .suspend = rk2928_suspend, + .resume = rk2928_resume, + .read = rk2928_read, + .write = rk2928_write, + .set_bias_level = rk2928_set_bias_level, +}; + +static struct snd_soc_dai_ops rk2928_audio_codec_ops = { + .hw_params = rk2928_audio_hw_params, + .trigger = rk2928_audio_trigger, + .startup = rk2928_audio_startup, +}; + +static struct snd_soc_dai_driver rk2928_codec_dai = { + .name = "rk2928-codec", + .playback = { + .stream_name = "HIFI Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | + SNDRV_PCM_FMTBIT_S24_LE, + }, + .capture = { + .stream_name = "HIFI Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE, + }, + .ops = &rk2928_audio_codec_ops, +}; + +static __devinit int rk2928_codec_probe(struct platform_device *pdev) +{ + int r; + + DBG("%s", __FUNCTION__); + + /* Register ASoC codec DAI */ + r = snd_soc_register_codec(&pdev->dev, &rk2928_audio_codec_drv, + &rk2928_codec_dai, 1); + if (r) { + dev_err(&pdev->dev, "can't register ASoC rk2928 audio codec\n"); + return r; + } + + DBG("%s success", __FUNCTION__); + return 0; + +} + +static int __devexit rk2928_codec_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + return 0; +} + +static struct platform_driver rk2928_codec_driver = { + .probe = rk2928_codec_probe, + .remove = __devexit_p(rk2928_codec_remove), + .driver = { + .name = "rk2928-codec", + .owner = THIS_MODULE, + }, +}; + +static int __init rk2928_codec_init(void) +{ + return platform_driver_register(&rk2928_codec_driver); +} +module_init(rk2928_codec_init); + +static void __exit rk2928_codec_exit(void) +{ + #ifdef CODEC_I2C_MODE + i2c_del_driver(&rk2928_codec_driver); + #else + platform_driver_unregister(&rk2928_codec_driver); + #endif +} +module_exit(rk2928_codec_exit); + +MODULE_DESCRIPTION("ASoC RK2928 codec driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rk2928_codec.h b/sound/soc/codecs/rk2928_codec.h new file mode 100755 index 000000000000..42401a94afde --- /dev/null +++ b/sound/soc/codecs/rk2928_codec.h @@ -0,0 +1,82 @@ +/* + * rk2928.h ALSA SoC RK2928 codec driver + * + * Copyright 2012 Rockchip + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __RK2928_CODEC_H__ +#define __RK2928_CODEC_H__ + + +#define CODEC_REG_ADC_PGA_GAIN 0x0b + #define m_MIC_GAIN_CHANNEL_L (0x0F << 4) + #define m_MIC_GAIN_CHANNEL_R (0x0F) + #define v_MIC_GAIN_CHANNEL_L(n) ((n) << 4) + #define v_MIC_GAIN_CHANNEL_R(n) (n) + +#define CODEC_REG_POWER 0x0c + #define m_PD_CODEC (0x01) + #define m_PD_MIC_BIAS (0x01 << 1) + #define m_PD_ADC (0x03 << 2) + #define m_PD_DAC (0x03 << 4) + #define v_PD_CODEC(n) (n) + #define v_PD_MIC_BIAS(n) (n << 1) + #define v_PD_ADC_R(n) (n << 2) + #define v_PD_ADC_L(n) (n << 3) + #define v_PD_DAC_R(n) (n << 4) + #define v_PD_DAC_L(n) (n << 5) + #define v_PD_ADC(n) (v_PD_ADC_L(n) | v_PD_ADC_R(n)) + #define v_PD_DAC(n) (v_PD_DAC_L(n) | v_PD_DAC_R(n)) + #define v_PWR_OFF v_PD_DAC_L(1) | v_PD_DAC_R(1) | v_PD_ADC_L(1) | v_PD_ADC_R(1) | v_PD_MIC_BIAS(1) | v_PD_CODEC(1) + +#define CODEC_REG_VCM_BIAS 0x0d + #define v_MIC_BIAS(n) (n) + enum { + VCM_RESISTOR_100K = 0, + VCM_RESISTOR_25K + }; + #define v_VCM_25K_100K(n) (n << 2) + +#define CODEC_REG_DAC_MUTE 0x0e + #define v_MUTE_DAC_L(n) (n << 1) + #define v_MUTE_DAC_R(n) (n) + #define v_MUTE_DAC(n) v_MUTE_DAC_L(n) | v_MUTE_DAC_R(n) + +#define CODEC_REG_ADC_SOURCE 0x0f + enum { + ADC_SRC_MIC = 0, + ADC_SRC_LINE_IN + }; + #define v_SRC_ADC_L(n) (n << 1) + #define v_SRC_ADC_R(n) (n) + +#define CODEC_REG_DAC_GAIN 0x10 + #define m_GAIN_DAC_L (0x03 << 2) + #define m_GAIN_DAC_R (0x03) + enum { + DAC_GAIN_0DB = 0, + DAC_GAIN_3DB_P = 0x2, //3db + DAC_GAIN_3DB_N //-3db + }; + #define v_GAIN_DAC_L(n) (n << 2) + #define v_GAIN_DAC_R(n) (n) + #define v_GAIN_DAC(n) (v_GAIN_DAC_L(n) | v_GAIN_DAC_R(n)) + +//#ifndef DEBUG +//#define DEBUG +//#endif + +#ifdef DEBUG +#define DBG(format, ...) \ + printk(KERN_INFO "RK2928 CODEC: " format "\n", ## __VA_ARGS__) +#else +#define DBG(format, ...) +#endif + + + +#endif /* __RK2928_CODEC_H__ */ diff --git a/sound/soc/rk29/Kconfig b/sound/soc/rk29/Kconfig index 63e28d3c21e1..c95b1d03768f 100755 --- a/sound/soc/rk29/Kconfig +++ b/sound/soc/rk29/Kconfig @@ -169,7 +169,17 @@ config SND_RK29_SOC_RK610 Say Y if you want to add support for SoC audio on rockchip with the RK610(JETTA). -if SND_RK29_SOC_WM8988 || SND_RK29_SOC_RK1000 || SND_RK29_SOC_WM8994 || SND_RK29_SOC_WM8900 || SND_RK29_SOC_RT5621 || SND_RK29_SOC_RT5631 || SND_RK29_SOC_RT5625 || SND_RK29_SOC_CS42L52 || SND_RK29_SOC_AIC3111 || SND_RK29_SOC_HDMI || SND_RK29_SOC_RK610 || SND_RK29_SOC_AIC3262 +config SND_RK_SOC_RK2928 + tristate "SoC I2S Audio support for rockchip - RK2928" + depends on SND_RK29_SOC && ARCH_RK2928 + select SND_RK29_SOC_I2S + select SND_SOC_RK2928 + select SND_RK29_CODEC_SOC_SLAVE + help + Say Y if you want to add support for SoC audio on rockchip + with the RK2928 internal codec. + +if SND_RK29_SOC_WM8988 || SND_RK29_SOC_RK1000 || SND_RK29_SOC_WM8994 || SND_RK29_SOC_WM8900 || SND_RK29_SOC_RT5621 || SND_RK29_SOC_RT5631 || SND_RK29_SOC_RT5625 || SND_RK29_SOC_CS42L52 || SND_RK29_SOC_AIC3111 || SND_RK29_SOC_HDMI || SND_RK29_SOC_RK610 || SND_RK29_SOC_AIC3262 || SND_RK_SOC_RK2928 choice bool "Set i2s type" default SND_RK29_CODEC_SOC_SLAVE diff --git a/sound/soc/rk29/Makefile b/sound/soc/rk29/Makefile old mode 100644 new mode 100755 index 0d06e37a1620..1f9622291282 --- a/sound/soc/rk29/Makefile +++ b/sound/soc/rk29/Makefile @@ -28,6 +28,7 @@ snd-soc-wm8994-objs := rk29_wm8994.o snd-soc-hdmi-objs := rk29_hdmi.o snd-soc-rk610-objs := rk29_jetta_codec.o snd-soc-aic3262-objs := rk29_aic3262.o +snd-soc-rk2928-objs := rk2928-card.o obj-$(CONFIG_SND_RK29_SOC_WM8994) += snd-soc-wm8994.o obj-$(CONFIG_SND_RK29_SOC_WM8988) += snd-soc-wm8988.o @@ -41,3 +42,4 @@ obj-$(CONFIG_SND_RK29_SOC_AIC3111) += snd-soc-aic3111.o obj-$(CONFIG_SND_RK29_SOC_AIC3262) += snd-soc-aic3262.o obj-$(CONFIG_SND_RK29_SOC_HDMI) += snd-soc-hdmi.o obj-$(CONFIG_SND_RK29_SOC_RK610) += snd-soc-rk610.o +obj-$(CONFIG_SND_RK_SOC_RK2928) += snd-soc-rk2928.o \ No newline at end of file diff --git a/sound/soc/rk29/rk2928-card.c b/sound/soc/rk29/rk2928-card.c new file mode 100755 index 000000000000..185d8ea1567d --- /dev/null +++ b/sound/soc/rk29/rk2928-card.c @@ -0,0 +1,163 @@ +/* + * rk2928-card.c -- SoC audio for RockChip RK2928 + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ +#include +#include +#include + +#include "rk29_pcm.h" +#include "rk29_i2s.h" + +#ifdef DEBUG +#define DBG(format, ...) \ + printk(KERN_INFO "RK2928 Card: " format "\n", ## __VA_ARGS__) +#else +#define DBG(format, ...) +#endif + +static int rk2928_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + unsigned int pll_out = 0; + int div_bclk,div_mclk; + int ret; + + DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); + + /* set cpu DAI configuration */ + #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) + DBG("Set cpu_dai master\n"); + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); + #endif + #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + DBG("Set cpu_dai slave\n"); + #endif + if (ret < 0) + return ret; + + switch(params_rate(params)) { + case 8000: + case 16000: + case 24000: + case 32000: + case 48000: + case 96000: + pll_out = 12288000; + break; + case 11025: + case 22050: + case 44100: + case 88200: + pll_out = 11289600; + break; + case 176400: + pll_out = 11289600*2; + break; + case 192000: + pll_out = 12288000*2; + break; + default: + DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params)); + return -EINVAL; + break; + } + DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params)); + + #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) + snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0); + #endif + + #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) + div_bclk = 63; + div_mclk = pll_out/(params_rate(params)*64) - 1; + + snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0); + snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK,div_bclk); + snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk); + #endif + + return 0; +} + +static struct snd_soc_ops rk2928_dai_ops = { + .hw_params = rk2928_dai_hw_params, +}; + +static struct snd_soc_dai_link rk2928_dai[] = { + { + .name = "RK2928", + .stream_name = "RK2928", + .cpu_dai_name = "rk29_i2s.0", + .platform_name = "rockchip-audio", + .codec_name = "rk2928-codec.0-0001", + .codec_dai_name = "rk2928-codec", + .ops = &rk2928_dai_ops, + }, +}; + +/* Audio machine driver */ +static struct snd_soc_card snd_soc_rk2928 = { + .name = "RK2928", + .dai_link = rk2928_dai, + .num_links = ARRAY_SIZE(rk2928_dai), +}; + +static struct platform_device *rk2928_snd_device; + +static int __init rk2928_soc_init(void) +{ + int ret; + + printk(KERN_INFO "RK2928 SoC init\n"); + + rk2928_snd_device = platform_device_alloc("soc-audio", -1); + if (!rk2928_snd_device) { + printk(KERN_ERR "Platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(rk2928_snd_device, &snd_soc_rk2928); + + ret = platform_device_add(rk2928_snd_device); + if (ret) + goto err1; + + return 0; + +err1: + printk(KERN_ERR "Unable to add platform device\n"); + platform_device_put(rk2928_snd_device); + + return ret; +} +module_init(rk2928_soc_init); + +static void __exit rk2928_soc_exit(void) +{ + platform_device_unregister(rk2928_snd_device); +} +module_exit(rk2928_soc_exit); + +MODULE_DESCRIPTION("ALSA SoC RK2928"); +MODULE_LICENSE("GPL"); \ No newline at end of file From 4c9e1d535cc0074da7f39ea5e0f9d27d3d449c9d Mon Sep 17 00:00:00 2001 From: yzq Date: Mon, 23 Jul 2012 17:47:06 +0800 Subject: [PATCH 038/261] rk2928 lvds support --- drivers/video/rockchip/Kconfig | 1 + drivers/video/rockchip/Makefile | 1 + drivers/video/rockchip/chips/rk2928_lcdc.c | 12 ++- drivers/video/rockchip/lvds/Kconfig | 2 + drivers/video/rockchip/lvds/Makefile | 6 ++ drivers/video/rockchip/lvds/rk_lvds.c | 58 ++++++++++++++ drivers/video/rockchip/lvds/rk_lvds.h | 93 ++++++++++++++++++++++ 7 files changed, 172 insertions(+), 1 deletion(-) create mode 100755 drivers/video/rockchip/lvds/Kconfig create mode 100755 drivers/video/rockchip/lvds/Makefile create mode 100644 drivers/video/rockchip/lvds/rk_lvds.c create mode 100644 drivers/video/rockchip/lvds/rk_lvds.h diff --git a/drivers/video/rockchip/Kconfig b/drivers/video/rockchip/Kconfig index 04ba7263c5ac..267b5b5a222e 100755 --- a/drivers/video/rockchip/Kconfig +++ b/drivers/video/rockchip/Kconfig @@ -75,3 +75,4 @@ config THREE_FB_BUFFER select y if android support three buffer,like Jelly Bean source "drivers/video/rockchip/hdmi/Kconfig" source "drivers/video/rockchip/rga/Kconfig" +source "drivers/video/rockchip/lvds/Kconfig" diff --git a/drivers/video/rockchip/Makefile b/drivers/video/rockchip/Makefile index 68967a49fc80..0f1a3880879e 100755 --- a/drivers/video/rockchip/Makefile +++ b/drivers/video/rockchip/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_LCDC_RK2928) += chips/rk2928_lcdc.o obj-$(CONFIG_LCDC_RK31) += chips/rk31_lcdc.o obj-$(CONFIG_RGA_RK30) += rga/ obj-$(CONFIG_RK_HDMI) += hdmi/ +obj-$(CONFIG_RK_LVDS) += lvds/ diff --git a/drivers/video/rockchip/chips/rk2928_lcdc.c b/drivers/video/rockchip/chips/rk2928_lcdc.c index 5298a8e98291..71146072f545 100755 --- a/drivers/video/rockchip/chips/rk2928_lcdc.c +++ b/drivers/video/rockchip/chips/rk2928_lcdc.c @@ -31,7 +31,7 @@ #include #include #include "rk2928_lcdc.h" - +#include "../lvds/rk_lvds.h" @@ -68,6 +68,10 @@ static int init_rk2928_lcdc(struct rk_lcdc_device_driver *dev_drv) { printk(KERN_ERR "failed to get lcdc%d clk source\n",lcdc_dev->id); } +#ifdef CONFIG_RK_LVDS + rk_lvds_register(lcdc_dev->screen); +#endif + clk_enable(lcdc_dev->pd); clk_enable(lcdc_dev->hclk); //enable aclk and hclk for register config clk_enable(lcdc_dev->aclk); @@ -685,6 +689,9 @@ int rk2928_lcdc_early_suspend(struct rk_lcdc_device_driver *dev_drv) { struct rk2928_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk2928_lcdc_device,driver); + if(lcdc_dev->screen->sscreen_set != NULL) + lcdc_dev->screen->sscreen_set(lcdc_dev->screen , 0); + spin_lock(&lcdc_dev->reg_lock); if(likely(lcdc_dev->clk_on)) { @@ -733,6 +740,9 @@ int rk2928_lcdc_early_resume(struct rk_lcdc_device_driver *dev_drv) lcdc_dev->clk_on = 1; spin_unlock(&lcdc_dev->reg_lock); + if(lcdc_dev->screen->sscreen_set != NULL) + lcdc_dev->screen->sscreen_set(lcdc_dev->screen , 1); + return 0; } static irqreturn_t rk2928_lcdc_isr(int irq, void *dev_id) diff --git a/drivers/video/rockchip/lvds/Kconfig b/drivers/video/rockchip/lvds/Kconfig new file mode 100755 index 000000000000..1577242cb924 --- /dev/null +++ b/drivers/video/rockchip/lvds/Kconfig @@ -0,0 +1,2 @@ +config RK_LVDS + bool "RK_LVDS support" diff --git a/drivers/video/rockchip/lvds/Makefile b/drivers/video/rockchip/lvds/Makefile new file mode 100755 index 000000000000..f410fda78ee1 --- /dev/null +++ b/drivers/video/rockchip/lvds/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for LVDS linux kernel module. +# + + +obj-$(CONFIG_RK_LVDS) += rk_lvds.o diff --git a/drivers/video/rockchip/lvds/rk_lvds.c b/drivers/video/rockchip/lvds/rk_lvds.c new file mode 100644 index 000000000000..0fd1656120cb --- /dev/null +++ b/drivers/video/rockchip/lvds/rk_lvds.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include "rk_lvds.h" + +static void rk_output_lvds(rk_screen *screen) +{ + LVDSWrReg(m_PD_PLL(1)|m_PD_PLL(0)|m_PDN(1)|m_OEN(0) \ + |m_DS(DS_10PF)|m_MSBSEL(DATA_D0_MSB) \ + |m_OUT_FORMAT(screen->hw_format) \ + |m_LCDC_SEL(FROM_LCDC0)); +} + +static void rk_output_lvttl(rk_screen *screen) +{ + LVDSWrReg(m_PD_PLL(0)|m_PD_PLL(1)|m_PDN(0)|m_OEN(1) \ + |m_DS(DS_10PF)|m_MSBSEL(DATA_D0_MSB) \ + |m_OUT_FORMAT(screen->hw_format) \ + |m_LCDC_SEL(FROM_LCDC0)); +} + +static void rk_output_disable(void) +{ + LVDSWrReg(m_PD_PLL(0)|m_PD_PLL(0)|m_PDN(0)|m_OEN(0)); +} + +static int rk_lvds_set_param(rk_screen *screen,bool enable ) +{ + if(OUT_ENABLE == enable){ + switch(screen->type){ + case SCREEN_LVDS: + rk_output_lvds(screen); + break; + case SCREEN_RGB: + rk_output_lvttl(screen); + break; + default: + printk("%s>>>>LVDS not support this screen type %d,power down LVDS\n",__func__,screen->type); + rk_output_disable(); + break; + } + }else{ + rk_output_disable(); + } + return 0; +} + +int rk_lvds_register(rk_screen *screen) +{ + if(screen->sscreen_set == NULL) + screen->sscreen_set = rk_lvds_set_param; + + rk_lvds_set_param(screen , OUT_ENABLE); + + return 0; +} diff --git a/drivers/video/rockchip/lvds/rk_lvds.h b/drivers/video/rockchip/lvds/rk_lvds.h new file mode 100644 index 000000000000..3916fad54a90 --- /dev/null +++ b/drivers/video/rockchip/lvds/rk_lvds.h @@ -0,0 +1,93 @@ +#ifndef RK_LVDS_H_ +#define RK_LVDS_H + +#define LVDS_CON0_OFFSET 0x150 +#define LVDS_CON0_REG (RK2928_GRF_PHYS + LVDS_CON0_OFFSET) + +#define LVDSRdReg() __raw_readl(LVDS_CON0_REG) +#define LVDSWrReg(val) __raw_writel( val ,LVDS_CON0_REG) + +#define m_value(x,offset,mask) \ + ((mask<<(offset+8)) | (x&mask)< Date: Thu, 26 Jul 2012 16:56:35 +0800 Subject: [PATCH 039/261] rk31: add i2s/codec/pwm/backlight support --- arch/arm/mach-rk30/board-rk31-fpga.c | 109 +++++++++++++++++++++-- arch/arm/mach-rk30/include/mach/io.h | 2 +- drivers/video/backlight/Kconfig | 2 +- drivers/video/backlight/rk29_backlight.c | 7 +- sound/soc/rk29/Kconfig | 4 +- sound/soc/rk29/Makefile | 3 + sound/soc/rk29/rk29_rk1000codec.c | 6 +- 7 files changed, 121 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-rk30/board-rk31-fpga.c b/arch/arm/mach-rk30/board-rk31-fpga.c index 3b4a517678fc..abd4303591aa 100644 --- a/arch/arm/mach-rk30/board-rk31-fpga.c +++ b/arch/arm/mach-rk30/board-rk31-fpga.c @@ -148,6 +148,18 @@ static struct platform_device device_fb = { //i2c #ifdef CONFIG_I2C0_RK30 static struct i2c_board_info __initdata i2c0_info[] = { +#if defined (CONFIG_SND_SOC_RK1000) + { + .type = "rk1000_i2c_codec", + .addr = 0x60, + .flags = 0, + }, + { + .type = "rk1000_control", + .addr = 0x40, + .flags = 0, + }, +#endif }; #endif #ifdef CONFIG_I2C1_RK30 @@ -191,10 +203,73 @@ static void __init rk30_i2c_register_board_info(void) static struct spi_board_info board_spi_devices[] = { }; +/*********************************************************** +* rk30 backlight +************************************************************/ +#ifdef CONFIG_BACKLIGHT_RK29_BL +#define PWM_ID 1 +#define PWM_MUX_NAME GPIO0A3_PWM0_NAME +#define PWM_MUX_MODE GPIO0A_PWM0 +#define PWM_MUX_MODE_GPIO GPIO0A_GPIO0A3 +#define PWM_GPIO RK30_PIN0_PA3 +#define PWM_EFFECT_VALUE 1 + +#define LCD_DISP_ON_PIN + +#ifdef LCD_DISP_ON_PIN + +#define BL_EN_PIN RK30_PIN6_PB3 +#define BL_EN_VALUE GPIO_HIGH +#endif +static int rk29_backlight_io_init(void) +{ + int ret = 0; + return ret; +} + +static int rk29_backlight_io_deinit(void) +{ + int ret = 0; + return ret; +} + +static int rk29_backlight_pwm_suspend(void) +{ + int ret = 0; + return ret; +} + +static int rk29_backlight_pwm_resume(void) +{ + return 0; +} + +static struct rk29_bl_info rk29_bl_info = { + .pwm_id = PWM_ID, + .bl_ref = PWM_EFFECT_VALUE, + .io_init = rk29_backlight_io_init, + .io_deinit = rk29_backlight_io_deinit, + .pwm_suspend = rk29_backlight_pwm_suspend, + .pwm_resume = rk29_backlight_pwm_resume, +}; + +static struct platform_device rk29_device_backlight = { + .name = "rk29_backlight", + .id = -1, + .dev = { + .platform_data = &rk29_bl_info, + } +}; + +#endif + static struct platform_device *devices[] __initdata = { #if defined(CONFIG_FB_ROCKCHIP) &device_fb, #endif +#ifdef CONFIG_BACKLIGHT_RK29_BL + &rk29_device_backlight, +#endif }; /************************************************************************************************** * SDMMC devices, include the module of SD,MMC,and sdio.noted by xbw at 2012-03-05 @@ -384,6 +459,11 @@ static struct clk xin24m = { .rate = 24000000, }; +static struct clk xin12m = { + .name = "xin12m", + .rate = 12000000, +}; + #define CLK(dev, con, ck) \ { \ .dev_id = dev, \ @@ -413,10 +493,26 @@ static struct clk_lookup clks[] = { CLK("rk_serial.2", "uart", &xin24m), CLK("rk_serial.2", "pclk_uart", &xin24m), - CLK("rk29_i2s.0", "i2s_div", &xin24m), - CLK("rk29_i2s.0", "i2s_frac_div", &xin24m), - CLK("rk29_i2s.0", "i2s", &xin24m), - CLK("rk29_i2s.0", "hclk_i2s", &xin24m), + CLK("rk29_i2s.1", "i2s_div", &xin24m), + CLK("rk29_i2s.1", "i2s_frac_div", &xin24m), + CLK("rk29_i2s.1", "i2s", &xin12m), + CLK("rk29_i2s.1", "hclk_i2s", &xin24m), + + CLK("rk29_sdmmc.0","mmc",&xin24m), + CLK("rk29_sdmmc.0","hclk_mmc",&xin24m), + CLK("rk29_sdmmc.1","mmc",&xin24m), + CLK("rk29_sdmmc.1","hclk_mmc",&xin24m), + + CLK(NULL,"pd_lcdc0",&xin24m), + CLK(NULL,"hclk_lcdc0",&xin24m), + CLK(NULL,"aclk_lcdc0",&xin24m), + CLK(NULL,"dclk_lcdc0",&xin24m), + CLK(NULL,"pd_lcdc1",&xin24m), + CLK(NULL,"hclk_lcdc1",&xin24m), + CLK(NULL,"aclk_lcdc1",&xin24m), + CLK(NULL,"dclk_lcdc1",&xin24m), + + CLK(NULL,"pwm01",&xin24m), }; static void __init rk30_clock_init(void) @@ -451,7 +547,10 @@ EXPORT_SYMBOL(clk_disable); unsigned long clk_get_rate(struct clk *clk) { - return 24000000; + if(clk) + return clk->rate; + else + return 24000000; } EXPORT_SYMBOL(clk_get_rate); diff --git a/arch/arm/mach-rk30/include/mach/io.h b/arch/arm/mach-rk30/include/mach/io.h index e4a9c7210e21..99cbdf4b13ad 100755 --- a/arch/arm/mach-rk30/include/mach/io.h +++ b/arch/arm/mach-rk30/include/mach/io.h @@ -52,7 +52,7 @@ #define RK30_IPP_SIZE SZ_16K #define RK30_RGA_PHYS 0x10114000 #define RK30_RGA_SIZE SZ_8K -#ifdef CONFIG_ARCH_RK30 +#if defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) #define RK30_HDMI_PHYS 0x10116000 #define RK30_HDMI_SIZE SZ_8K #define RK30_I2S0_8CH_PHYS 0x10118000 diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 81056931d8c6..4e7324b87588 100755 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -299,7 +299,7 @@ config BACKLIGHT_RK2818_BL config BACKLIGHT_RK29_BL bool "rk backlight driver" - depends on BACKLIGHT_CLASS_DEVICE && (ARCH_RK29 || ARCH_RK30) + depends on BACKLIGHT_CLASS_DEVICE && (ARCH_RK29 || ARCH_RK30 || ARCH_RK31) default y help rk29 backlight support. diff --git a/drivers/video/backlight/rk29_backlight.c b/drivers/video/backlight/rk29_backlight.c index a60a0245797c..f8c251de5e8b 100755 --- a/drivers/video/backlight/rk29_backlight.c +++ b/drivers/video/backlight/rk29_backlight.c @@ -38,7 +38,7 @@ #define DBG(x...) #endif -#if defined(CONFIG_ARCH_RK30) +#if defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) #define write_pwm_reg(id, addr, val) __raw_writel(val, addr+(RK30_PWM01_BASE+(id>>1)*0x20000)+id*0x10) #define read_pwm_reg(id, addr) __raw_readl(addr+(RK30_PWM01_BASE+(id>>1)*0x20000+id*0x10)) #elif defined(CONFIG_ARCH_RK29) @@ -170,6 +170,7 @@ static int rk29_backlight_probe(struct platform_device *pdev) unsigned long pwm_clk_rate; struct backlight_properties props; + if (rk29_bl) { printk(KERN_CRIT "%s: backlight device register has existed \n", __func__); @@ -186,6 +187,7 @@ static int rk29_backlight_probe(struct platform_device *pdev) rk29_bl_info->io_init(); } + memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = BL_STEP; @@ -196,9 +198,10 @@ static int rk29_backlight_probe(struct platform_device *pdev) return -ENODEV; } + #if defined(CONFIG_ARCH_RK29) pwm_clk = clk_get(NULL, "pwm"); -#elif defined(CONFIG_ARCH_RK30) +#elif defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) if (id == 0 || id == 1) pwm_clk = clk_get(NULL, "pwm01"); else if (id == 2 || id == 3) diff --git a/sound/soc/rk29/Kconfig b/sound/soc/rk29/Kconfig index c95b1d03768f..1596ca660a73 100755 --- a/sound/soc/rk29/Kconfig +++ b/sound/soc/rk29/Kconfig @@ -1,5 +1,5 @@ config SND_RK29_SOC - tristate "SoC Audio for the rockchip RK29/RK30 System-on-Chip" + tristate "SoC Audio for the rockchip RK29/RK30/RK31 System-on-Chip" depends on PLAT_RK && SND_SOC help Say Y or M if you want to add support for codecs attached to @@ -12,7 +12,7 @@ config SND_RK29_SOC_I2S config SND_RK29_SOC_I2S_8CH bool "Soc RK29 I2S 8 Channel support(I2S0)" default y - depends on SND_RK29_SOC_I2S + depends on SND_RK29_SOC_I2S && !ARCH_RK31 help This supports the use of the 8 Channel I2S interface on rk29 processors. diff --git a/sound/soc/rk29/Makefile b/sound/soc/rk29/Makefile index 1f9622291282..cce9283a31d7 100755 --- a/sound/soc/rk29/Makefile +++ b/sound/soc/rk29/Makefile @@ -9,6 +9,9 @@ endif ifdef CONFIG_ARCH_RK2928 snd-soc-rockchip-i2s-objs := rk30_i2s.o endif +ifdef CONFIG_ARCH_RK31 +snd-soc-rockchip-i2s-objs := rk30_i2s.o +endif snd-soc-rockchip-spdif-objs := rk29_spdif.o obj-$(CONFIG_SND_RK29_SOC) += snd-soc-rockchip.o diff --git a/sound/soc/rk29/rk29_rk1000codec.c b/sound/soc/rk29/rk29_rk1000codec.c index b5457b986803..a65bfba54617 100755 --- a/sound/soc/rk29/rk29_rk1000codec.c +++ b/sound/soc/rk29/rk29_rk1000codec.c @@ -85,7 +85,11 @@ static struct snd_soc_dai_link rk29_dai[] = { .platform_name = "rockchip-audio", .codec_name = "RK1000_CODEC.0-0060", .codec_dai_name = "rk1000_codec", - .cpu_dai_name = "rk29_i2s.1", +#if defined(CONFIG_SND_RK29_SOC_I2S_8CH) + .cpu_dai_name = "rk29_i2s.0", +#elif defined(CONFIG_SND_RK29_SOC_I2S_2CH) + .cpu_dai_name = "rk29_i2s.1", +#endif .init = rk29_rk1000_codec_init, .ops = &rk29_ops, } From 265fda7e27051b484b5fc2ed4ebc72260b5c88cd Mon Sep 17 00:00:00 2001 From: hxy Date: Thu, 26 Jul 2012 17:47:51 +0800 Subject: [PATCH 040/261] rk31: update iomux.h --- arch/arm/mach-rk30/include/mach/iomux.h | 80 +++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/arch/arm/mach-rk30/include/mach/iomux.h b/arch/arm/mach-rk30/include/mach/iomux.h index 779b977c16a2..6e2f2c7e5e28 100755 --- a/arch/arm/mach-rk30/include/mach/iomux.h +++ b/arch/arm/mach-rk30/include/mach/iomux.h @@ -486,6 +486,84 @@ #define DEFAULT 0 #define INITIAL 1 +#if defined(CONFIG_ARCH_RK31) + +#define GRF_GPIO0L_DIR 0x0000 +#define GRF_GPIO0H_DIR 0x0004 +#define GRF_GPIO1L_DIR 0x0008 +#define GRF_GPIO1H_DIR 0x000c +#define GRF_GPIO2L_DIR 0x0010 +#define GRF_GPIO2H_DIR 0x0014 +#define GRF_GPIO3L_DIR 0x0018 +#define GRF_GPIO3H_DIR 0x001c +#define GRF_GPIO0L_DO 0x0020 +#define GRF_GPIO0H_DO 0x0024 +#define GRF_GPIO1L_DO 0x0028 +#define GRF_GPIO1H_DO 0x002c +#define GRF_GPIO2L_DO 0x0030 +#define GRF_GPIO2H_DO 0x0034 +#define GRF_GPIO3L_DO 0x0038 +#define GRF_GPIO3H_DO 0x003c +#define GRF_GPIO0L_EN 0x0040 +#define GRF_GPIO0H_EN 0x0044 +#define GRF_GPIO1L_EN 0x0048 +#define GRF_GPIO1H_EN 0x004c +#define GRF_GPIO2L_EN 0x0050 +#define GRF_GPIO2H_EN 0x0054 +#define GRF_GPIO3L_EN 0x0058 +#define GRF_GPIO3H_EN 0x005c +#define GRF_GPIO0A_IOMUX RK30_GRF_BASE+0x0060 +#define GRF_GPIO0B_IOMUX RK30_GRF_BASE+0x0064 +#define GRF_GPIO0C_IOMUX RK30_GRF_BASE+0x0068 +#define GRF_GPIO0D_IOMUX RK30_GRF_BASE+0x006c +#define GRF_GPIO1A_IOMUX RK30_GRF_BASE+0x0070 +#define GRF_GPIO1B_IOMUX RK30_GRF_BASE+0x0074 +#define GRF_GPIO1C_IOMUX RK30_GRF_BASE+0x0078 +#define GRF_GPIO1D_IOMUX RK30_GRF_BASE+0x007c +#define GRF_GPIO2A_IOMUX RK30_GRF_BASE+0x0080 +#define GRF_GPIO2B_IOMUX RK30_GRF_BASE+0x0084 +#define GRF_GPIO2C_IOMUX RK30_GRF_BASE+0x0088 +#define GRF_GPIO2D_IOMUX RK30_GRF_BASE+0x008c +#define GRF_GPIO3A_IOMUX RK30_GRF_BASE+0x0090 +#define GRF_GPIO3B_IOMUX RK30_GRF_BASE+0x0094 +#define GRF_GPIO3C_IOMUX RK30_GRF_BASE+0x0098 +#define GRF_GPIO3D_IOMUX RK30_GRF_BASE+0x009c +#define GRF_SOC_CON0 0x00a0 +#define GRF_SOC_CON1 0x00a4 +#define GRF_SOC_CON2 0x00a8 +#define GRF_SOC_STATUS0 0x00ac +#define GRF_DMAC1_CON0 0x00b0 +#define GRF_DMAC1_CON1 0x00b4 +#define GRF_DMAC1_CON2 0x00b8 +#define GRF_DMAC2_CON0 0x00bc +#define GRF_DMAC2_CON1 0x00c0 +#define GRF_DMAC2_CON2 0x00c4 +#define GRF_DMAC2_CON3 0x00c8 +#define GRF_UOC0_CON0 0x010c +#define GRF_UOC0_CON1 0x0110 +#define GRF_UOC0_CON2 0x0114 +#define GRF_UOC0_CON3 0x0118 +#define GRF_UOC1_CON0 0x011c +#define GRF_UOC1_CON1 0x0120 +#define GRF_UOC1_CON2 0x0124 +#define GRF_UOC1_CON3 0x0128 +#define GRF_UOC2_CON0 0x012c +#define GRF_UOC2_CON1 0x0130 +#define GRF_UOC3_CON0 0x0138 +#define GRF_UOC3_CON1 0x013c +#define GRF_HSIC_STAT 0x0140 +#define GRF_DDRC_CON0 0x00ec +#define GRF_DDRC_STAT 0x00f0 +#define GRF_OS_REG0 0x0144 +#define GRF_OS_REG1 0x0148 +#define GRF_OS_REG2 0x014c +#define GRF_OS_REG3 0x0150 +#define GRF_OS_REG4 0x0154 +#define GRF_OS_REG5 0x0158 +#define GRF_OS_REG6 0x015c +#define GRF_OS_REG7 0x0160 + +#else #define GRF_GPIO0L_DIR 0x0000 #define GRF_GPIO0H_DIR 0x0004 @@ -577,6 +655,8 @@ #define GRF_OS_REG2 0x01d0 #define GRF_OS_REG3 0x01d4 +#endif + //GPIO0A #define GPIO0A7_I2S8CHSDI_NAME "gpio0a7_i2s8chsdi_name" From 225e3950a37b33e000ed1dd0b0e25f083e83988a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=93=9D=E6=96=8C=E5=85=83?= Date: Thu, 26 Jul 2012 18:14:24 +0800 Subject: [PATCH 041/261] rk2928 add gps support --- arch/arm/mach-rk2928/board-rk2928-fpga.c | 84 ++++ drivers/misc/Makefile | 2 +- drivers/misc/gps/Kconfig | 3 +- drivers/misc/gps/Makefile | 2 +- drivers/misc/gps/hv5820b/Kconfig | 13 + drivers/misc/gps/hv5820b/Makefile | 3 + drivers/misc/gps/hv5820b/PALAPI.c | 421 ++++++++++++++++++ drivers/misc/gps/hv5820b/PALAPI.h | 72 +++ drivers/misc/gps/hv5820b/gpsdriver.c | 529 +++++++++++++++++++++++ drivers/misc/gps/hv5820b/gpsdriver.h | 50 +++ drivers/misc/gps/hv5820b/gpsdrv.h | 53 +++ drivers/misc/gps/hv5820b/hv5820b_gps.h | 25 ++ drivers/misc/gps/hv5820b/lnxdrv.h | 52 +++ 13 files changed, 1306 insertions(+), 3 deletions(-) create mode 100755 drivers/misc/gps/hv5820b/Kconfig create mode 100755 drivers/misc/gps/hv5820b/Makefile create mode 100755 drivers/misc/gps/hv5820b/PALAPI.c create mode 100755 drivers/misc/gps/hv5820b/PALAPI.h create mode 100755 drivers/misc/gps/hv5820b/gpsdriver.c create mode 100755 drivers/misc/gps/hv5820b/gpsdriver.h create mode 100755 drivers/misc/gps/hv5820b/gpsdrv.h create mode 100755 drivers/misc/gps/hv5820b/hv5820b_gps.h create mode 100755 drivers/misc/gps/hv5820b/lnxdrv.h diff --git a/arch/arm/mach-rk2928/board-rk2928-fpga.c b/arch/arm/mach-rk2928/board-rk2928-fpga.c index 7fd99583b24c..07e366c32fb2 100755 --- a/arch/arm/mach-rk2928/board-rk2928-fpga.c +++ b/arch/arm/mach-rk2928/board-rk2928-fpga.c @@ -42,6 +42,9 @@ #include #include #include +#if defined(CONFIG_GPS_HV5820B) +#include "../../../drivers/misc/gps/hv5820b/hv5820b_gps.h" +#endif #ifdef CONFIG_VIDEO_RK29 /*---------------- Camera Sensor Macro Define Begin ------------------------*/ @@ -769,7 +772,85 @@ static struct platform_device device_ion = { }, }; #endif +#if defined(CONFIG_GPS_HV5820B) +int hv5820b_gps_io_init(void) +{ + printk("%s \n", __FUNCTION__); + rk30_mux_api_set(GPIO1B1_SPI_TXD_UART1_SOUT_NAME, GPIO1B_GPIO1B1);//VCC_EN + gpio_request(RK2928_PIN1_PB1, NULL); + gpio_direction_output(RK2928_PIN1_PB1, GPIO_LOW); + rk30_mux_api_set(GPIO1A2_I2S_LRCKRX_GPS_CLK_NAME, GPIO1A_GPS_CLK);//GPS_CLK + rk30_mux_api_set(GPIO1A4_I2S_SDO_GPS_MAG_NAME, GPIO1A_GPS_MAG);//GPS_MAG + rk30_mux_api_set(GPIO1A5_I2S_SDI_GPS_SIGN_NAME, GPIO1A_GPS_SIGN);//GPS_SIGN + + rk30_mux_api_set(GPIO1B0_SPI_CLK_UART1_CTSN_NAME, GPIO1B_GPIO1B0);//SPI_CLK + gpio_request(RK2928_PIN1_PB0, NULL); + gpio_direction_output(RK2928_PIN1_PB0, GPIO_LOW); + + rk30_mux_api_set(GPIO1B2_SPI_RXD_UART1_SIN_NAME, GPIO1B_GPIO1B2);//SPI_MOSI + gpio_request(RK2928_PIN1_PB2, NULL); + gpio_direction_output(RK2928_PIN1_PB2, GPIO_LOW); + + rk30_mux_api_set(GPIO1B3_SPI_CSN0_UART1_RTSN_NAME, GPIO1B_GPIO1B3);//SPI_CS + gpio_request(RK2928_PIN1_PB3, NULL); + gpio_direction_output(RK2928_PIN1_PB3, GPIO_LOW); + return 0; +} +int hv5820b_gps_power_up(void) +{ + printk("%s \n", __FUNCTION__); + + return 0; +} + +int hv5820b_gps_power_down(void) +{ + printk("%s \n", __FUNCTION__); + + return 0; +} + +int hv5820b_gps_reset_set(int level) +{ + return 0; +} +int hv5820b_enable_hclk_gps(void) +{ + printk("%s \n", __FUNCTION__); + clk_enable(clk_get(NULL, "hclk_gps")); + return 0; +} +int hv5820b_disable_hclk_gps(void) +{ + printk("%s \n", __FUNCTION__); + clk_disable(clk_get(NULL, "hclk_gps")); + return 0; +} +struct hv5820b_gps_data hv5820b_gps_info = { + .io_init = hv5820b_gps_io_init, + .power_up = hv5820b_gps_power_up, + .power_down = hv5820b_gps_power_down, + .reset = hv5820b_gps_reset_set, + .enable_hclk_gps = hv5820b_enable_hclk_gps, + .disable_hclk_gps = hv5820b_disable_hclk_gps, + .GpsSign = RK2928_PIN1_PA4, + .GpsMag = RK2928_PIN1_PB1, //GPIO index + .GpsClk = RK2928_PIN1_PA2, //GPIO index + .GpsVCCEn = RK2928_PIN1_PB1, //GPIO index + .GpsSpi_CSO = RK2928_PIN1_PB3, //GPIO index + .GpsSpiClk = RK2928_PIN1_PB0, //GPIO index + .GpsSpiMOSI = RK2928_PIN1_PB2, //GPIO index +}; + +struct platform_device hv5820b_device_gps = { + .name = "gps_hv5820b", + .id = -1, + .dev = { + .platform_data = &hv5820b_gps_info, + } + }; +#endif static struct platform_device *devices[] __initdata = { #ifdef CONFIG_ION &device_ion, @@ -777,6 +858,9 @@ static struct platform_device *devices[] __initdata = { #ifdef CONFIG_FB_ROCKCHIP &device_fb, #endif +#ifdef CONFIG_GPS_HV5820B + &hv5820b_device_gps, +#endif }; static void __init rk2928_board_init(void) diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index e5b97a33c724..5a99f5aaab7c 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -58,7 +58,7 @@ obj-$(CONFIG_MW100) += mw100.o obj-$(CONFIG_MT6229) += mt6229.o obj-$(CONFIG_STE) += ste.o obj-$(CONFIG_RK29_SUPPORT_MODEM) += rk29_modem/ -obj-$(CONFIG_GPS_GNS7560) += gps/ +obj-$(CONFIG_RK29_GPS) += gps/ obj-y += inv_mpu/ obj-$(CONFIG_RK29_NEWTON) += newton.o obj-$(CONFIG_TDSC8800) += tdsc8800.o diff --git a/drivers/misc/gps/Kconfig b/drivers/misc/gps/Kconfig index ae012dbcaefd..7c912b3f74f6 100644 --- a/drivers/misc/gps/Kconfig +++ b/drivers/misc/gps/Kconfig @@ -13,7 +13,8 @@ if RK29_GPS config GPS_GNS7560 bool "gns7560 support" default n - + +source "drivers/misc/gps/hv5820b/Kconfig" endif # RK29_GPS diff --git a/drivers/misc/gps/Makefile b/drivers/misc/gps/Makefile index 6b4bdb6480c2..5488d964d9fd 100644 --- a/drivers/misc/gps/Makefile +++ b/drivers/misc/gps/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_GPS_GNS7560) += rk29_gps.o - +obj-$(CONFIG_RK29_GPS) += hv5820b/ diff --git a/drivers/misc/gps/hv5820b/Kconfig b/drivers/misc/gps/hv5820b/Kconfig new file mode 100755 index 000000000000..47365c07ec1e --- /dev/null +++ b/drivers/misc/gps/hv5820b/Kconfig @@ -0,0 +1,13 @@ +# +# gps device configuration +# + + + +config GPS_HV5820B + bool "HV5820B support" + default n + + + + diff --git a/drivers/misc/gps/hv5820b/Makefile b/drivers/misc/gps/hv5820b/Makefile new file mode 100755 index 000000000000..150c55411149 --- /dev/null +++ b/drivers/misc/gps/hv5820b/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_GPS_HV5820B) += gpsdriver.o PALAPI.o gpsdrv.a + + diff --git a/drivers/misc/gps/hv5820b/PALAPI.c b/drivers/misc/gps/hv5820b/PALAPI.c new file mode 100755 index 000000000000..610bfca31752 --- /dev/null +++ b/drivers/misc/gps/hv5820b/PALAPI.c @@ -0,0 +1,421 @@ +/////////////////////////////////////////////////////////////////////////////////// +// +// Filename: PALAPI.c +// Author: sjchen +// Copyright: +// Date: 2010/12/01 +// Description: +// linux system interface +// +// Revision: +// 0.0.1 +// +/////////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:PAL_AllocMem +// Parameters: +// Description: allocate system memory +// Notes: sjchen 2010/12/01 +// +/////////////////////////////////////////////////////////////////////////////////// +void* PAL_AllocMem(int nBytes) +{ + return kmalloc ( nBytes, GFP_KERNEL); +} + + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:PAL_FreeMem +// Parameters: +// Description: free system memory +// Notes: sjchen 2010/12/01 +// +/////////////////////////////////////////////////////////////////////////////////// +void PAL_FreeMem(void* pMem) +{ + if(pMem) + { + kfree(pMem); + } +} + + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:PAL_CreateMutex +// Parameters: +// Description: Create a semaphore +// Notes: sjchen 2010/12/01 +// +/////////////////////////////////////////////////////////////////////////////////// +int PAL_CreateMutex ( void) +{ + struct semaphore *psem; + + psem = (struct semaphore *)PAL_AllocMem(sizeof(struct semaphore)); + //init_MUTEX_LOCKED(psem); + sema_init(psem, 0); + return (int)psem; + +} + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:PAL_ReleaseMutex +// Parameters: +// Description: Release a semaphore +// Notes: sjchen 2010/12/01 +// +/////////////////////////////////////////////////////////////////////////////////// +void PAL_ReleaseMutex ( int hMutex ) +{ + if(hMutex) + { + up((struct semaphore *)hMutex); + } + + return ; +} + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:PAL_WaitMutex +// Parameters: +// Description: Wait semaphore to signal +// Notes: sjchen 2010/12/01 +// +/////////////////////////////////////////////////////////////////////////////////// +void PAL_WaitMutex(int hMutex) +{ + if(hMutex) + { + down((struct semaphore *)hMutex); + } +} + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:PAL_CloseMutes +// Parameters: +// Description: Close a semaphore +// Notes: sjchen 2010/12/01 +// +/////////////////////////////////////////////////////////////////////////////////// +void PAL_CloseMutes(int hMutex) +{ + if(hMutex) + { + PAL_FreeMem((void *)hMutex); + } +} + + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:PAL_memset +// Parameters: +// Description: +// Notes: sjchen 2010/12/01 +// +/////////////////////////////////////////////////////////////////////////////////// +void PAL_memset ( + void* pbuf, + unsigned char nval, + int nsize + ) +{ + memset ( pbuf, nval, nsize ); +} + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:PAL_memcpy +// Parameters: +// Description: +// Notes: sjchen 2010/12/01 +// +/////////////////////////////////////////////////////////////////////////////////// +void PAL_memcpy ( + void* pDst, + void* pSrc, + int nSize + ) +{ + memcpy ( pDst, pSrc, nSize ); +} + + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:PAL_GetCurTimer_US +// Parameters: +// Description: Get system time +// Notes: sjchen 2010/11/30 +// +/////////////////////////////////////////////////////////////////////////////////// +void PAL_GetCurTimer_US( + int *n32Second, + int *n32us + ) +{ + struct timeval tv; + + do_gettimeofday(&tv); + + *n32Second = tv.tv_sec; + *n32us = tv.tv_usec; +} + + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:PAL_GetCurTimer_US +// Parameters: +// Description: Get system time +// Notes: sjchen 2010/11/30 +// +/////////////////////////////////////////////////////////////////////////////////// +void PAL_GetSysTimer_US( + int *n32Second, + int *n32us + ) +{ + PAL_GetCurTimer_US(n32Second, n32us); +} + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:PAL_GetKernelFreePage +// Parameters: +// Description: Allocate kernel free page +// Notes: sjchen 2010/11/30 +// +/////////////////////////////////////////////////////////////////////////////////// +int PAL_GetKernelFreePage(int nPageSize) +{ + return __get_free_pages(GFP_KERNEL,get_order(nPageSize)); +} + + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:PAL_FreeKernelPage +// Parameters: +// Description: Free kernel page +// Notes: sjchen 2010/11/30 +// +/////////////////////////////////////////////////////////////////////////////////// +void PAL_FreeKernelPage(int nAddr,int nPageSize) +{ + if(nAddr != 0 && nPageSize != 0) + { + free_pages(nAddr,get_order(nPageSize)); + + } +} + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:PAL_GetUser +// Parameters: +// Description: +// Notes: sjchen 2010/11/30 +// +/////////////////////////////////////////////////////////////////////////////////// +int PAL_GetUser(int *p) +{ + int nData = 0; + + __get_user(nData,(int __user *)p); + + return nData; +} + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:PAL_CopyFromUser +// Parameters: +// Description: Copy datas from user space to kernel space +// Notes: sjchen 2010/11/30 +// +/////////////////////////////////////////////////////////////////////////////////// +void PAL_CopyFromUser(void *pDest,void *pSrc,int nSize) +{ + __copy_from_user(pDest,(void __user *)pSrc,nSize); +} + + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:PAL_CopyToUser +// Parameters: +// Description: Copy datas from kernel space to user space +// Notes: sjchen 2010/11/30 +// +/////////////////////////////////////////////////////////////////////////////////// +int PAL_CopyToUser(void *pDest,void *pSrc,int nSize) +{ + return copy_to_user((void __user *)pDest, pSrc, nSize); +} + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:PAL_Sprintf +// Parameters: +// Description: +// Notes: sjchen 2010/11/04 +// +/////////////////////////////////////////////////////////////////////////////////// +int PAL_Sprintf ( + char * pDst, + const char * pFormat, + ... + ) +{ + int nNum = 0; + + va_list ptr; + + va_start ( ptr, pFormat ); + + nNum = vsprintf ( pDst, pFormat, ptr ); + + va_end ( ptr ); + + return nNum; +} +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:PAL_Sprintf +// Parameters: +// Description: +// Notes: sjchen 2010/11/04 +// +/////////////////////////////////////////////////////////////////////////////////// +void PAL_KDEBUG ( + const char * pFormat, + ... + ) +{ +#if 1 + va_list ptr; + + va_start ( ptr, pFormat ); + + vprintk ( pFormat, ptr ); + + va_end ( ptr ); +#endif + return ; +} + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:PAL_mdelay +// Parameters: +// Description: +// Notes: sjchen 2010/11/04 +// +/////////////////////////////////////////////////////////////////////////////////// +void PAL_mdelay(int ms) +{ + mdelay(ms); +} + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:PAL_dma_cache_wback_inv +// Parameters: +// Description: +// Notes: sjchen 2010/11/04 +// +/////////////////////////////////////////////////////////////////////////////////// +void PAL_dma_cache_wback_inv(void * pMem, int size ) +{ + //TODO: + //fluch cache + + __cpuc_flush_dcache_area(pMem, size ); +} + + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:PAL_dma_cache_wback_inv +// Parameters: +// Description: +// Notes: sjchen 2010/11/04 +// +/////////////////////////////////////////////////////////////////////////////////// +void PAL_dma_cache_inv(void * pMem, int size ) +{ + //TODO: + //fluch cache + + __cpuc_flush_dcache_area(pMem, size ); +} + + + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:PAL_Set_GPIO_Pin +// Parameters: +// Description: +// Notes: sjchen 2010/11/04 +// +/////////////////////////////////////////////////////////////////////////////////// +void PAL_Set_GPIO_Pin(int gpio) +{ + //TODO: + //Set gpio to high level + + //gpio_write_one_pin_value(gpio, 1); + gpio_set_value(gpio, GPIO_HIGH); +} + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:PAL_Clr_GPIO_Pin +// Parameters: +// Description: +// Notes: sjchen 2010/11/04 +// +/////////////////////////////////////////////////////////////////////////////////// +void PAL_Clr_GPIO_Pin(int gpio) +{ + //TODO: + //Set gpio to low level + + //gpio_write_one_pin_value(gpio, 0); + gpio_set_value(gpio, GPIO_LOW); +} + + diff --git a/drivers/misc/gps/hv5820b/PALAPI.h b/drivers/misc/gps/hv5820b/PALAPI.h new file mode 100755 index 000000000000..b45a7a86dd59 --- /dev/null +++ b/drivers/misc/gps/hv5820b/PALAPI.h @@ -0,0 +1,72 @@ +/////////////////////////////////////////////////////////////////////////////////// +// +// Filename: PALAPI.h +// Author: sjchen +// Copyright: +// Date: 2010/12/01 +// Description: +// declare linux driver function +// +// Revision: +// 0.0.1 +// +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef __PALAPI_H___ +#define __PALAPI_H___ + +extern void* PAL_AllocMem(int nBytes); +extern void PAL_FreeMem(void* pMem); +extern int PAL_CreateMutex ( void); +extern void PAL_ReleaseMutex ( int hMutex ); +extern void PAL_WaitMutex(int hMutex); +extern void PAL_CloseMutes(int hMutex); + +extern void PAL_memset ( + void* pbuf, + unsigned char nval, + int nsize + ); + +extern void PAL_memcpy ( + void* pDst, + void* pSrc, + int nSize + ); + +void PAL_GetCurTimer_US( + int *n32Second, + int *n32us + ); + +void PAL_GetSysTimer_US( + int *n32Second, + int *n32us + ); + +int PAL_GetKernelFreePage(int nPageSize); + +void PAL_FreeKernelPage(int nAddr,int nPageSize); + +int PAL_GetUser(int *p); + +void PAL_CopyFromUser(void *pDest,void *pSrc,int nSize); + +int PAL_CopyToUser(void *pDest,void *pSrc,int nSize); + +int PAL_Sprintf ( + char * pDst, + const char * pFormat, + ... + ); + +void PAL_mdelay(int ms); + +void PAL_KDEBUG ( + const char * pFormat, + ... + ); +void PAL_Set_GPIO_Pin(int gpio); +void PAL_Clr_GPIO_Pin(int gpio); + +#endif //__PALAPI_H___ diff --git a/drivers/misc/gps/hv5820b/gpsdriver.c b/drivers/misc/gps/hv5820b/gpsdriver.c new file mode 100755 index 000000000000..97877d3654cc --- /dev/null +++ b/drivers/misc/gps/hv5820b/gpsdriver.c @@ -0,0 +1,529 @@ +/////////////////////////////////////////////////////////////////////////////////// +// +// Filename: gpsdriver.c +// Author: sjchen +// Copyright: +// Date: 2012/07/09 +// Description: +// GPS driver +// +// Revision: +// 0.0.1 +// +/////////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#include + + +#include "gpsdrv.h" +#include "gpsdriver.h" +#include "lnxdrv.h" +#include "PALAPI.h" + +#include +#include +#include "hv5820b_gps.h" + +/////////////////////////////////////////////////////////////////////////////////// +// +// macro declaration +// +/////////////////////////////////////////////////////////////////////////////////// +#define GPS_MAJOR ( 61 ) +#define SW_VA_GPS_IO_BASE 0x10400000 +#define GPS_USE_SPI + + +/////////////////////////////////////////////////////////////////////////////////// +// +// static variables declaration +// +/////////////////////////////////////////////////////////////////////////////////// +static char gpsstr[]="gps"; +static struct miscdevice gps_miscdev; +struct hv5820b_gps_data *hv5820b_pdata ; +void *gps_mem =NULL; +unsigned long gps_mem_address; //BSP define for u32MemoryPhyAddr +unsigned long gps_mem_size = 8*0x00100000; //it must be more than 8MB + +/////////////////////////////////////////////////////////////////////////////////// +// +// extern variables declaration +// +/////////////////////////////////////////////////////////////////////////////////// +extern unsigned long gps_mem_address; //BSP define for u32MemoryPhyAddr +extern unsigned long gps_mem_size; //it must be more than 8MB + + +#ifdef GPS_USE_SPI +#include +void VtuneAndSpiCheck_rk(int enable_check); +int AdcValueGet(void); +int GetVtuneAdcValue_rk(void); +void ConfigRfSpi_rk(int Val ); +struct adc_client *adc_gps_cleint; +#define LOW_SCALE_0_65V 600 +#define HIGH_SCALE_0_95V 1000 +void gps_callback(struct adc_client *client, void *callback_param, int result) +{ + return; +} +void VtuneAndSpiCheck_rk(int enable_check) +{ + int VtuneAvg; + int SpiValue = 2; + int cnt = 0; + + if( enable_check == 0) + return; + + VtuneAvg = 0; + while( (VtuneAvg < LOW_SCALE_0_65V) || (VtuneAvg > HIGH_SCALE_0_95V) && cnt < 10) + { + if( (SpiValue >= 8) || (SpiValue <= 0) ) + break; + + VtuneAvg = AdcValueGet(); + + if( VtuneAvg < LOW_SCALE_0_65V) + { + SpiValue++; + ConfigRfSpi_rk( SpiValue); + } + + if( VtuneAvg > HIGH_SCALE_0_95V) + { + SpiValue--; + ConfigRfSpi_rk( SpiValue); + } + cnt ++; + } +} + + +int AdcValueGet() +{ + // Read adc value + int adc_value; + int sampletime = 100; + int AveValue; + int SumValue; + int i; + + + SumValue = 0; + for(i = 0; i < sampletime; i++) + { + adc_value = GetVtuneAdcValue_rk(); + + SumValue += adc_value; + } + AveValue = SumValue / sampletime; + return AveValue; +} + +int GetVtuneAdcValue_rk() +{ + int adc_val = 0; + + adc_val = adc_sync_read(adc_gps_cleint); + if(adc_val < 0) + printk("GetVtuneAdcValue error"); + + return adc_val; +} + +void ConfigRfSpi_rk(int Val ) +{ + int i; + +#define GPS_SCLK hv5820b_pdata->GpsSpiMOSI +#define GPS_MOSI hv5820b_pdata->GpsSpiClk +#define GPS_SCS hv5820b_pdata->GpsSpi_CSO + + + PAL_Clr_GPIO_Pin(GPS_SCLK); + PAL_Clr_GPIO_Pin(GPS_SCS); + + for(i = 0; i < 100000000; i++); + + PAL_Set_GPIO_Pin(GPS_SCLK); + PAL_Set_GPIO_Pin(GPS_MOSI); //b15 + + + for(i = 0; i < 100000000; i++); + PAL_Clr_GPIO_Pin(GPS_SCLK); + for(i = 0; i < 100000000; i++); + PAL_Set_GPIO_Pin(GPS_SCLK); //b14 + for(i = 0; i < 100000000; i++); + PAL_Clr_GPIO_Pin(GPS_SCLK); + for(i = 0; i < 100000000; i++); + PAL_Set_GPIO_Pin(GPS_SCLK); //b13 + for(i = 0; i < 100000000; i++); + PAL_Clr_GPIO_Pin(GPS_SCLK); + for(i = 0; i < 100000000; i++); + PAL_Set_GPIO_Pin(GPS_SCLK); //b12 + PAL_Clr_GPIO_Pin(GPS_MOSI); + for(i = 0; i < 100000000; i++); + PAL_Clr_GPIO_Pin(GPS_SCLK); + for(i = 0; i < 100000000; i++); + PAL_Set_GPIO_Pin(GPS_SCLK); //b11 + PAL_Set_GPIO_Pin(GPS_MOSI); + for(i = 0; i < 100000000; i++); + PAL_Clr_GPIO_Pin(GPS_SCLK); + for(i = 0; i < 100000000; i++); + PAL_Set_GPIO_Pin(GPS_SCLK); //b10 + for(i = 0; i < 100000000; i++); + PAL_Clr_GPIO_Pin(GPS_SCLK); + for(i = 0; i < 100000000; i++); + PAL_Set_GPIO_Pin(GPS_SCLK); //b9 + PAL_Clr_GPIO_Pin(GPS_MOSI); + for(i = 0; i < 100000000; i++); + PAL_Clr_GPIO_Pin(GPS_SCLK); + for(i = 0; i < 100000000; i++); + PAL_Set_GPIO_Pin(GPS_SCLK); //b8 + for(i = 0; i < 100000000; i++); + PAL_Clr_GPIO_Pin(GPS_SCLK); + for(i = 0; i < 100000000; i++); + PAL_Set_GPIO_Pin(GPS_SCLK); //b7 + for(i = 0; i < 100000000; i++); + PAL_Clr_GPIO_Pin(GPS_SCLK); + for(i = 0; i < 100000000; i++); + PAL_Set_GPIO_Pin(GPS_SCLK); //b6 + if ((Val >> 4) & 1) + PAL_Set_GPIO_Pin(GPS_MOSI); + else + PAL_Clr_GPIO_Pin(GPS_MOSI); + for(i = 0; i < 100000000; i++); + PAL_Clr_GPIO_Pin(GPS_SCLK); + for(i = 0; i < 100000000; i++); + PAL_Set_GPIO_Pin(GPS_SCLK); //b5 + if ((Val >> 3) & 1) + PAL_Set_GPIO_Pin(GPS_MOSI); + else + PAL_Clr_GPIO_Pin(GPS_MOSI); + for(i = 0; i < 100000000; i++); + PAL_Clr_GPIO_Pin(GPS_SCLK); + for(i = 0; i < 100000000; i++); + PAL_Set_GPIO_Pin(GPS_SCLK); //b4 + if ((Val >> 2) & 1) + PAL_Set_GPIO_Pin(GPS_MOSI); + else + PAL_Clr_GPIO_Pin(GPS_MOSI); + for(i = 0; i < 100000000; i++); + PAL_Clr_GPIO_Pin(GPS_SCLK); + for(i = 0; i < 100000000; i++); + PAL_Set_GPIO_Pin(GPS_SCLK); //b3 + if ((Val >> 1) & 1) + PAL_Set_GPIO_Pin(GPS_MOSI); + else + PAL_Clr_GPIO_Pin(GPS_MOSI); + for(i = 0; i < 100000000; i++); + PAL_Clr_GPIO_Pin(GPS_SCLK); + for(i = 0; i < 100000000; i++); + PAL_Set_GPIO_Pin(GPS_SCLK); //b2 + if ((Val >> 0) & 1) + PAL_Set_GPIO_Pin(GPS_MOSI); + else + PAL_Clr_GPIO_Pin(GPS_MOSI); + for(i = 0; i < 100000000; i++); + PAL_Clr_GPIO_Pin(GPS_SCLK); + for(i = 0; i < 100000000; i++); + PAL_Set_GPIO_Pin(GPS_SCLK); //b1 + for(i = 0; i < 100000000; i++); + PAL_Clr_GPIO_Pin(GPS_SCLK); + for(i = 0; i < 100000000; i++); + PAL_Set_GPIO_Pin(GPS_SCLK); //b0 + for(i = 0; i < 100000000; i++); + PAL_Clr_GPIO_Pin(GPS_SCLK); + for(i = 0; i < 100000000; i++); + for(i = 0; i < 100000000; i++); + PAL_Set_GPIO_Pin(GPS_SCS); +} +#endif +static int hv5820b_gps_probe(struct platform_device *pdev) +{ + int err; + struct hv5820b_gps_data *pdata = pdev->dev.platform_data; + if(!pdata) + return -1; + hv5820b_pdata = pdata; + + printk("Enter GPSDrv_Init\n"); + + err = request_irq ( GPS_BB_INT_MASK, gps_int_handler, IRQF_DISABLED, gpsstr, NULL ); + + if ( err ) + { + printk ( "gps_mod_init: gps request irq failed!\n" ); + + return err; + } + + err = misc_register( &gps_miscdev); + if (err < 0) + { + return err; + } + + gps_mem=kzalloc(gps_mem_size, GFP_KERNEL); + gps_mem_address = (unsigned long)(&gps_mem); + //TODO: + //Set the GPIO (GPS_VCC_EN) to low level in here + // + if(pdata->io_init) + pdata->io_init(); + gpio_direction_output(pdata->GpsVCCEn, GPIO_LOW); + #ifdef GPS_USE_SPI + adc_gps_cleint = adc_register(2, gps_callback, NULL); + #endif + return 0; +} +static int hv5820b_gps_remove(struct platform_device *pdev) +{ +#ifdef GPS_USE_SPI + adc_unregister(adc_gps_cleint); +#endif + return 0; +} +static int hv5820b_gps_suspend(struct platform_device *pdev, pm_message_t state) +{ + return 0; +} +static int hv5820b_gps_resume(struct platform_device *pdev) +{ + return 0; +} +static struct platform_driver hv5820b_gps_driver = { + .probe = hv5820b_gps_probe, + .remove = hv5820b_gps_remove, + .suspend = hv5820b_gps_suspend, + .resume = hv5820b_gps_resume, + .driver = { + .name = "gps_hv5820b", + .owner = THIS_MODULE, + }, +}; + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name: gps_mod_init +// Parameters: +// Description: +// Notes: sjchen 2010/11/04 +// +/////////////////////////////////////////////////////////////////////////////////// +static int __init gps_mod_init(void) +{ + return platform_driver_register(&hv5820b_gps_driver); +} + + + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name: gps_mod_exit +// Parameters: +// Description: +// Notes: sjchen 2010/11/04 +// +/////////////////////////////////////////////////////////////////////////////////// +static void __exit gps_mod_exit ( void ) +{ + //Disable baseband interrupt + WriteGpsRegisterUlong ( BB_INT_ENA_OFFSET, 0 ); + + free_irq( GPS_BB_INT_MASK, NULL ); + + //unregister_chrdev ( GPS_MAJOR, gpsstr ); + misc_deregister(&gps_miscdev); + platform_driver_unregister(&hv5820b_gps_driver); + printk ( "GPS exit ok!\n"); +} + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:gps_ioctl +// Parameters: +// Description: +// Notes: sjchen 2010/11/04 +// +/////////////////////////////////////////////////////////////////////////////////// +long gps_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int ret = 0; + BB_DRV_VERSION __user * pVersion; + GPS_DRV_INIT GpsInitStruct; + + switch(cmd) + { + + case IOCTL_BB_GPS_START: + //TODO: + // Gps baseband module initialize in here. + // Module power up + if(hv5820b_pdata->enable_hclk_gps) + hv5820b_pdata->enable_hclk_gps(); + + memset(&GpsInitStruct,0,sizeof(GpsInitStruct)); + GpsInitStruct.u32GpsRegBase = SW_VA_GPS_IO_BASE; // GPS Reg Base address + GpsInitStruct.u32MemoryPhyAddr = gps_mem_address; // sample code + GpsInitStruct.u32MemoryVirAddr = __phys_to_virt(gps_mem_address); + GpsInitStruct.u32GpsSign = hv5820b_pdata->GpsSign; //GPIO index + GpsInitStruct.u32GpsMag = hv5820b_pdata->GpsMag; //GPIO index + GpsInitStruct.u32GpsClk = hv5820b_pdata->GpsClk; //GPIO index + GpsInitStruct.u32GpsVCCEn = hv5820b_pdata->GpsVCCEn; //GPIO index + GpsInitStruct.u32GpsSpi_CSO = hv5820b_pdata->GpsSpi_CSO; //GPIO index + GpsInitStruct.u32GpsSpiClk = hv5820b_pdata->GpsSpiClk; //GPIO index + GpsInitStruct.u32GpsSpiMOSI = hv5820b_pdata->GpsSpiMOSI; //GPIO index + //TODO: + //Add other member of struct GpsInitStruct + Gps_Init( arg,&GpsInitStruct); + #ifdef GPS_USE_SPI + VtuneAndSpiCheck_rk(1); + #endif + break; + + case IOCTL_BB_UPDATEDATA: + Gps_UpdateData(arg); + break; + + + case IOCTL_BB_GPS_STOP: + Gps_Stop(); + + //TODO: + // Set the GPIO(GPS_VCC_EN) to low level + // Close the module clk. + gpio_direction_output(hv5820b_pdata->GpsVCCEn, GPIO_LOW); + if(hv5820b_pdata->disable_hclk_gps) + hv5820b_pdata->disable_hclk_gps(); + break; + + case IOCTL_BB_GET_VERSION: + pVersion = ( void __user * ) arg; + + pVersion->u32Major = DRV_MAJOR_VERSION; + pVersion->u32Minor = DRV_MINOR_VERSION; + PAL_Sprintf(pVersion->strCompileTime,"%s,%s",__DATE__,__TIME__); + + break; + + default: + + printk ( "gpsdrv: ioctl number is worng %d\n",cmd); + + break; + }; + + return ret; +} + + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:gps_read +// Parameters: +// Description: Read gps data +// Notes: sjchen 2010/11/04 +// +/////////////////////////////////////////////////////////////////////////////////// +ssize_t gps_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) +{ + ssize_t nsize; + if((nsize = GpsDrv_Read(buf,size))) + { + return nsize; + } + + return -EFAULT; +} + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:gps_open +// Parameters: +// Description: +// Notes: sjchen 2010/11/04 +// +/////////////////////////////////////////////////////////////////////////////////// +static int gps_open (struct inode *inode, struct file *filp) +{ + return 0; /* success */ +} + + + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name:gps_close +// Parameters: +// Description: +// Notes: sjchen 2010/11/04 +// +/////////////////////////////////////////////////////////////////////////////////// +static int gps_close (struct inode *inode, struct file *filp) +{ + return 0; +} + +/////////////////////////////////////////////////////////////////////////////////// +// +// Function Name: driver struct +// Parameters: +// Description: +// Notes: sjchen 2010/11/04 +// +/////////////////////////////////////////////////////////////////////////////////// +static const struct file_operations gps_fops = +{ + . owner = THIS_MODULE, + . open = gps_open, + . release = gps_close, + . unlocked_ioctl = gps_ioctl, + . read = gps_read, +}; + +static struct miscdevice gps_miscdev = +{ + .minor = MISC_DYNAMIC_MINOR, + .name = gpsstr, + .fops = &gps_fops, +}; + + +/////////////////////////////////////////////////////////////////////////////////// +// +// Module Name: +// Parameters: +// Description: +// Notes: sjchen 2010/11/04 +// +/////////////////////////////////////////////////////////////////////////////////// +module_init ( gps_mod_init ); +module_exit ( gps_mod_exit ); + + +MODULE_LICENSE("GPL"); + + diff --git a/drivers/misc/gps/hv5820b/gpsdriver.h b/drivers/misc/gps/hv5820b/gpsdriver.h new file mode 100755 index 000000000000..026ab5a6faea --- /dev/null +++ b/drivers/misc/gps/hv5820b/gpsdriver.h @@ -0,0 +1,50 @@ +/////////////////////////////////////////////////////////////////////////////////// +// +// Filename: gpsdriver.h +// Author: sjchen +// Copyright: +// Date: 2012/07/09 +// Description: +// gps driver function +// +// Revision: +// 0.0.1 +// +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef __GPSDRIVER_H___ +#define __GPSDRIVER_H___ + +#define GPS_BB_INT_MASK 57 + + +typedef struct __tag_GPS_DRV_INIT +{ + unsigned long u32MemoryPhyAddr; //must reserved 8MB memory for GPS + unsigned long u32MemoryVirAddr; + unsigned long u32GpsRegBase; //GPS register base virtual address + unsigned int u32GpsSign; //GPIO index + unsigned int u32GpsMag; //GPIO index + unsigned int u32GpsClk; //GPIO index + unsigned int u32GpsVCCEn; //GPIO index + unsigned int u32GpsSpi_CSO; //GPIO index + unsigned int u32GpsSpiClk; //GPIO index + unsigned int u32GpsSpiMOSI; //GPIO index +}GPS_DRV_INIT,*PGPS_DRV_INIT; + +extern void WriteGpsRegisterUlong ( int reg_offset, int value ); + +extern int ReadGpsRegisterUlong ( int reg_offset ); + +extern irqreturn_t gps_int_handler ( int irq, void * dev_id ); + +extern void Gps_Init(unsigned long arg,PGPS_DRV_INIT pGpsDrvInit); + +extern void Gps_UpdateData(unsigned long arg); + +extern void Gps_Stop(void); + +extern int GpsDrv_Read(char *buf ,int nSize); + +#endif //__GPSDRIVER_H___ + diff --git a/drivers/misc/gps/hv5820b/gpsdrv.h b/drivers/misc/gps/hv5820b/gpsdrv.h new file mode 100755 index 000000000000..cc24b891c4d4 --- /dev/null +++ b/drivers/misc/gps/hv5820b/gpsdrv.h @@ -0,0 +1,53 @@ +/////////////////////////////////////////////////////////////////////////////////// +// +// Filename: gpsdrv.h +// Author: sjchen +// Copyright: +// Date: 2012/07/09 +// Description: +// the struct driver to app +// +// Revision: +// 0.0.1 +// +/////////////////////////////////////////////////////////////////////////////////// +#ifndef __GPSDRV_H__ +#define __GPSDRV_H__ + + +#define DRV_MAJOR_VERSION 1 +#define DRV_MINOR_VERSION 9 + +typedef struct __tag_BB_COMMAND_BUFFER { + int n32BufferA; + int n32BufferB; + int n32NavBuf; +} BB_COMMAND_BUFFER, *PBB_COMMAND_BUFFER; + + +typedef struct __tag_DRV_VERSION { + unsigned int u32Major; + unsigned int u32Minor; + char strCompileTime[32]; + +}BB_DRV_VERSION,*PBB_DRV_VERSION; + +// IOCTL code +enum +{ + // GPS Start + IOCTL_BB_GPS_START = 128, + IOCTL_BB_GPS_STOP, + + //Update gps data + IOCTL_BB_UPDATEDATA, + + //Driver version + IOCTL_BB_GET_VERSION + +}; + +#endif /* __GPSDRV_H__ */ + + + diff --git a/drivers/misc/gps/hv5820b/hv5820b_gps.h b/drivers/misc/gps/hv5820b/hv5820b_gps.h new file mode 100755 index 000000000000..bec227d55104 --- /dev/null +++ b/drivers/misc/gps/hv5820b/hv5820b_gps.h @@ -0,0 +1,25 @@ +/* + 2012.07.25 lby@rock-chips.com +*/ + +#ifndef __HV5820B_GPS_H__ +#define __HV5820B_GPS_H__ + +struct hv5820b_gps_data { + int (*io_init)(void); + int (*power_up)(void); + int (*power_down)(void); + int (*reset)(int); + int (*enable_hclk_gps)(void); + int (*disable_hclk_gps)(void); + int GpsSign; + int GpsMag; //GPIO index + int GpsClk; //GPIO index + int GpsVCCEn; //GPIO index + int GpsSpi_CSO; //GPIO index + int GpsSpiClk; //GPIO index + int GpsSpiMOSI; //GPIO index + +}; + +#endif diff --git a/drivers/misc/gps/hv5820b/lnxdrv.h b/drivers/misc/gps/hv5820b/lnxdrv.h new file mode 100755 index 000000000000..56c6f026fefd --- /dev/null +++ b/drivers/misc/gps/hv5820b/lnxdrv.h @@ -0,0 +1,52 @@ +/////////////////////////////////////////////////////////////////////////////////// +// +// Filename: lnxdrv.h +// Author: sjchen +// Copyright: +// Date: 2012/07/09 +// Description: +// the macor of GPS baseband +// +// Revision: +// 0.0.1 +// +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef __LNXDRV_H__ +#define __LNXDRV_H__ + +/////////////////////////////////////////////////////////////////////////////////// +// +// macro declaration +// +/////////////////////////////////////////////////////////////////////////////////// + +#define MEM_CHECK_BOUNDARY (16) + +//base band control registers offset +#define BB_CTRL_OFFSET 0x0400 +#define BB_START_ADR_OFFSET 0x0404 +#define BB_DS_PAR_OFFSET 0x0408 +#define BB_INT_ENA_OFFSET 0x040c +#define BB_INT_STATUS_OFFSET 0x0410 +#define BB_CHN_STATUS_OFFSET 0x0414 +#define BB_CHN_VALID_OFFSET 0x0418 +#define BB_TIMER_VAL_OFFSET 0x041c +#define BB_RF_WT_ADDR_OFFSET 0x0420 + + + +//the following is bb register bit define +#define BB_RESET 0x4 +#define BB_NXT_BLK 0x2 +#define BB_TRICKLE 0x1 +#define BB_CTRL_CLR 0x0 + +#define TIMEOUT_INT 0x1 +#define ACC_BLK_DONE_INT 0x2 +#define OBUF_RDY_INT 0x4 + +#endif /* __LNXDRV_H__ */ + + + From d6da2cba04a76e80709666261dd460e516cf3bc7 Mon Sep 17 00:00:00 2001 From: hxy Date: Fri, 27 Jul 2012 10:01:32 +0800 Subject: [PATCH 042/261] rk31: add cif clock source --- arch/arm/mach-rk30/board-rk31-fpga.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/mach-rk30/board-rk31-fpga.c b/arch/arm/mach-rk30/board-rk31-fpga.c index abd4303591aa..6f54f5fa0c36 100644 --- a/arch/arm/mach-rk30/board-rk31-fpga.c +++ b/arch/arm/mach-rk30/board-rk31-fpga.c @@ -512,6 +512,12 @@ static struct clk_lookup clks[] = { CLK(NULL,"aclk_lcdc1",&xin24m), CLK(NULL,"dclk_lcdc1",&xin24m), + CLK(NULL,"pd_cif0",&xin24m), + CLK(NULL,"aclk_cif0",&xin24m), + CLK(NULL,"hclk_cif0",&xin24m), + CLK(NULL,"cif0_in",&xin24m), + CLK(NULL,"cif0_out",&xin24m), + CLK(NULL,"pwm01",&xin24m), }; From d27062163c3b36421f4cb6dd2a8cafc1ce8dab18 Mon Sep 17 00:00:00 2001 From: kfx Date: Fri, 27 Jul 2012 10:12:54 +0800 Subject: [PATCH 043/261] rk2928: adc support --- drivers/adc/plat/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/adc/plat/Kconfig b/drivers/adc/plat/Kconfig index 390639868fd7..c70b12a5a349 100644 --- a/drivers/adc/plat/Kconfig +++ b/drivers/adc/plat/Kconfig @@ -24,7 +24,7 @@ config ADC_RK29 config ADC_RK30 bool "RK30 adc interface" - depends on ARCH_RK30 + depends on ARCH_RK30 || ARCH_RK2928 help This supports the use of the ADC interface on rk30 processors. endchoice From 6752c3e143766f93201fee1b01af36c879685c0d Mon Sep 17 00:00:00 2001 From: hxy Date: Fri, 27 Jul 2012 10:30:29 +0800 Subject: [PATCH 044/261] rk31: update i2s/codec/backlight config & iomux --- arch/arm/configs/rk31_fpga_defconfig | 16 ++++++++++++++++ arch/arm/mach-rk30/iomux.c | 2 ++ drivers/gpio/gpio-rk30.c | 5 ++++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/arch/arm/configs/rk31_fpga_defconfig b/arch/arm/configs/rk31_fpga_defconfig index d4f9f0e6cffe..1647438bf279 100644 --- a/arch/arm/configs/rk31_fpga_defconfig +++ b/arch/arm/configs/rk31_fpga_defconfig @@ -76,6 +76,10 @@ CONFIG_SPI_FPGA_GPIO_IRQ_NUM=0 # CONFIG_HWMON is not set # CONFIG_MFD_SUPPORT is not set CONFIG_FB=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set CONFIG_DISPLAY_SUPPORT=y CONFIG_LCD_TD043MGEA1=y CONFIG_FB_ROCKCHIP=y @@ -85,6 +89,18 @@ CONFIG_LCDC1_RK31=y CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +# CONFIG_SND_SUPPORT_OLD_API is not set +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_ARM is not set +CONFIG_SND_SOC=y +CONFIG_SND_RK29_SOC=y +CONFIG_SND_RK29_SOC_I2S_2CH=y +CONFIG_SND_I2S_DMA_EVENT_STATIC=y +CONFIG_SND_RK29_SOC_RK1000=y +CONFIG_SND_RK29_CODEC_SOC_SLAVE=y # CONFIG_HID_SUPPORT is not set # CONFIG_USB_SUPPORT is not set CONFIG_MMC=y diff --git a/arch/arm/mach-rk30/iomux.c b/arch/arm/mach-rk30/iomux.c index bbd37a149f42..9c2f237fe11d 100755 --- a/arch/arm/mach-rk30/iomux.c +++ b/arch/arm/mach-rk30/iomux.c @@ -189,6 +189,7 @@ MUX_CFG(GPIO3D2_SDMMC1INTN_NAME, GPIO3D, 4, 1, 0, DEFAULT) MUX_CFG(GPIO3D1_SDMMC1BACKENDPWR_NAME, GPIO3D, 2, 1, 0, DEFAULT) MUX_CFG(GPIO3D0_SDMMC1PWREN_NAME, GPIO3D, 0, 1, 0, DEFAULT) +#if defined(CONFIG_ARCH_RK30) //GPIO4A MUX_CFG(GPIO4A7_FLASHDATA15_NAME, GPIO4A, 14, 1, 0, DEFAULT) MUX_CFG(GPIO4A6_FLASHDATA14_NAME, GPIO4A, 12, 1, 0, DEFAULT) @@ -232,6 +233,7 @@ MUX_CFG(GPIO4D0_SMCDATA8_TRACEDATA8_NAME, GPIO4D, 0, 2, 0, DEFAULT) //GPIO6B MUX_CFG(GPIO6B7_TESTCLOCKOUT_NAME, GPIO6B, 14, 1, 0, DEFAULT) +#endif }; diff --git a/drivers/gpio/gpio-rk30.c b/drivers/gpio/gpio-rk30.c index 520d5a74d8e3..14417a33a4a9 100755 --- a/drivers/gpio/gpio-rk30.c +++ b/drivers/gpio/gpio-rk30.c @@ -318,8 +318,10 @@ static void rk30_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val) spin_unlock_irqrestore(&bank->lock, flags); } + static int rk30_gpiolib_pull_updown(struct gpio_chip *chip, unsigned offset, unsigned enable) { +#if defined(CONFIG_ARCH_RK30) struct rk30_gpio_bank *bank = to_rk30_gpio_bank(chip); unsigned long flags; @@ -329,10 +331,11 @@ static int rk30_gpiolib_pull_updown(struct gpio_chip *chip, unsigned offset, uns else rk30_gpio_bit_op((void *__iomem) RK30_GRF_BASE, GRF_GPIO0L_PULL + bank->id * 8, (1<<(offset+16)) | offset_to_bit(offset), !enable); spin_unlock_irqrestore(&bank->lock, flags); - +#endif return 0; } + static int rk30_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset) { return chip->base + offset; From 4ddde9aa6779800974c0e7380e0f29c2ed89b7ff Mon Sep 17 00:00:00 2001 From: hxy Date: Fri, 27 Jul 2012 14:45:54 +0800 Subject: [PATCH 045/261] rk31: add ion support --- arch/arm/configs/rk31_fpga_defconfig | 2 ++ arch/arm/mach-rk30/board-rk31-fpga.c | 32 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/arch/arm/configs/rk31_fpga_defconfig b/arch/arm/configs/rk31_fpga_defconfig index 1647438bf279..5d2202df2120 100644 --- a/arch/arm/configs/rk31_fpga_defconfig +++ b/arch/arm/configs/rk31_fpga_defconfig @@ -75,6 +75,8 @@ CONFIG_SPI_FPGA_GPIO_NUM=0 CONFIG_SPI_FPGA_GPIO_IRQ_NUM=0 # CONFIG_HWMON is not set # CONFIG_MFD_SUPPORT is not set +CONFIG_ION=y +CONFIG_ION_ROCKCHIP=y CONFIG_FB=y CONFIG_BACKLIGHT_LCD_SUPPORT=y # CONFIG_LCD_CLASS_DEVICE is not set diff --git a/arch/arm/mach-rk30/board-rk31-fpga.c b/arch/arm/mach-rk30/board-rk31-fpga.c index 6f54f5fa0c36..cf9b9ee7d894 100644 --- a/arch/arm/mach-rk30/board-rk31-fpga.c +++ b/arch/arm/mach-rk30/board-rk31-fpga.c @@ -263,6 +263,32 @@ static struct platform_device rk29_device_backlight = { #endif +/*********************************************************** +* rk30 ion device +************************************************************/ +#ifdef CONFIG_ION +#define ION_RESERVE_SIZE (8 * SZ_1M) +static struct ion_platform_data rk30_ion_pdata = { + .nr = 1, + .heaps = { + { + .type = ION_HEAP_TYPE_CARVEOUT, + .id = ION_NOR_HEAP_ID, + .name = "norheap", + .size = ION_RESERVE_SIZE, + } + }, +}; + +static struct platform_device device_ion = { + .name = "ion-rockchip", + .id = 0, + .dev = { + .platform_data = &rk30_ion_pdata, + }, +}; +#endif + static struct platform_device *devices[] __initdata = { #if defined(CONFIG_FB_ROCKCHIP) &device_fb, @@ -270,6 +296,9 @@ static struct platform_device *devices[] __initdata = { #ifdef CONFIG_BACKLIGHT_RK29_BL &rk29_device_backlight, #endif +#ifdef CONFIG_ION + &device_ion, +#endif }; /************************************************************************************************** * SDMMC devices, include the module of SD,MMC,and sdio.noted by xbw at 2012-03-05 @@ -443,6 +472,9 @@ static void __init rk31_reserve(void) #if defined(CONFIG_FB_ROCKCHIP) resource_fb[0].start = board_mem_reserve_add("fb0", RK_FB_MEM_SIZE); resource_fb[0].end = resource_fb[0].start + RK_FB_MEM_SIZE - 1; +#endif +#ifdef CONFIG_ION + rk30_ion_pdata.heaps[0].base = board_mem_reserve_add("ion", ION_RESERVE_SIZE); #endif board_mem_reserved(); } From b69a17f7b61e32929ac982bdfa1e0a7063fe6b77 Mon Sep 17 00:00:00 2001 From: ddl Date: Fri, 27 Jul 2012 16:33:06 +0800 Subject: [PATCH 046/261] rk31 camera: add support camera, only ov2659 --- arch/arm/configs/rk31_fpga_defconfig | 7 + .../mach-rk2928/include/mach/rk2928_camera.h | 3 +- arch/arm/mach-rk30/board-rk31-fpga.c | 455 ++++++++++++++++++ arch/arm/mach-rk30/include/mach/rk30_camera.h | 21 +- arch/arm/plat-rk/include/plat/rk_camera.h | 2 +- arch/arm/plat-rk/rk_camera.c | 15 +- drivers/media/video/Kconfig | 2 +- drivers/media/video/Makefile | 4 + drivers/media/video/rk30_camera.c | 30 +- drivers/media/video/rk30_camera_oneframe.c | 386 ++++++++------- 10 files changed, 710 insertions(+), 215 deletions(-) diff --git a/arch/arm/configs/rk31_fpga_defconfig b/arch/arm/configs/rk31_fpga_defconfig index 5d2202df2120..49213e435eae 100644 --- a/arch/arm/configs/rk31_fpga_defconfig +++ b/arch/arm/configs/rk31_fpga_defconfig @@ -66,6 +66,7 @@ CONFIG_INPUT_EVDEV=y # CONFIG_HW_RANDOM is not set CONFIG_I2C=y CONFIG_I2C0_CONTROLLER_RK30=y +CONFIG_I2C1_CONTROLLER_RK30=y CONFIG_I2C2_CONTROLLER_RK30=y # CONFIG_I2C3_RK30 is not set # CONFIG_ADC is not set @@ -75,6 +76,12 @@ CONFIG_SPI_FPGA_GPIO_NUM=0 CONFIG_SPI_FPGA_GPIO_IRQ_NUM=0 # CONFIG_HWMON is not set # CONFIG_MFD_SUPPORT is not set +CONFIG_MEDIA_SUPPORT=y +CONFIG_VIDEO_DEV=y +CONFIG_SOC_CAMERA=y +CONFIG_SOC_CAMERA_OV2659=y +CONFIG_VIDEO_RK29=y +CONFIG_VIDEO_RK29_CAMMEM_ION=y CONFIG_ION=y CONFIG_ION_ROCKCHIP=y CONFIG_FB=y diff --git a/arch/arm/mach-rk2928/include/mach/rk2928_camera.h b/arch/arm/mach-rk2928/include/mach/rk2928_camera.h index 95ab7aabd949..733a95f5e726 100644 --- a/arch/arm/mach-rk2928/include/mach/rk2928_camera.h +++ b/arch/arm/mach-rk2928/include/mach/rk2928_camera.h @@ -21,7 +21,8 @@ #define __ASM_ARCH_CAMERA_RK2928_H_ #define RK29_CAM_DRV_NAME "rk-camera-rk2928" - +#define RK_SUPPORT_CIF0 1 +#define RK_SUPPORT_CIF1 0 #include #endif diff --git a/arch/arm/mach-rk30/board-rk31-fpga.c b/arch/arm/mach-rk30/board-rk31-fpga.c index cf9b9ee7d894..fcde79e30f81 100644 --- a/arch/arm/mach-rk30/board-rk31-fpga.c +++ b/arch/arm/mach-rk30/board-rk31-fpga.c @@ -44,6 +44,453 @@ #include +#ifdef CONFIG_VIDEO_RK29 +/*---------------- Camera Sensor Macro Define Begin ------------------------*/ +/*---------------- Camera Sensor Configuration Macro Begin ------------------------*/ +#define CONFIG_SENSOR_0 RK29_CAM_SENSOR_OV5642 /* back camera sensor */ +#define CONFIG_SENSOR_IIC_ADDR_0 0 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_0 4 +#define CONFIG_SENSOR_ORIENTATION_0 90 +#define CONFIG_SENSOR_POWER_PIN_0 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_0 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_0 INVALID_GPIO +#define CONFIG_SENSOR_FALSH_PIN_0 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_0 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_0 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_0 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_0 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_0 30000 + +#define CONFIG_SENSOR_01 RK29_CAM_SENSOR_OV5642 /* back camera sensor 1 */ +#define CONFIG_SENSOR_IIC_ADDR_01 0x00 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_01 4 +#define CONFIG_SENSOR_ORIENTATION_01 90 +#define CONFIG_SENSOR_POWER_PIN_01 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_01 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_01 INVALID_GPIO +#define CONFIG_SENSOR_FALSH_PIN_01 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_01 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_01 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_01 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_01 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_01 30000 + +#define CONFIG_SENSOR_02 RK29_CAM_SENSOR_OV5640 /* back camera sensor 2 */ +#define CONFIG_SENSOR_IIC_ADDR_02 0x00 +#define CONFIG_SENSOR_CIF_INDEX_02 0 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_02 4 +#define CONFIG_SENSOR_ORIENTATION_02 90 +#define CONFIG_SENSOR_POWER_PIN_02 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_02 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_02 INVALID_GPIO +#define CONFIG_SENSOR_FALSH_PIN_02 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_02 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_02 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_02 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_02 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_02 30000 + +#define CONFIG_SENSOR_1 RK29_CAM_SENSOR_OV2659 /* front camera sensor 0 */ +#define CONFIG_SENSOR_IIC_ADDR_1 0x60 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_1 1 +#define CONFIG_SENSOR_ORIENTATION_1 270 +#define CONFIG_SENSOR_POWER_PIN_1 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_1 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_1 INVALID_GPIO +#define CONFIG_SENSOR_FALSH_PIN_1 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_1 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_1 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_1 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_1 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_1 30000 + +#define CONFIG_SENSOR_11 RK29_CAM_SENSOR_OV2659 /* front camera sensor 1 */ +#define CONFIG_SENSOR_IIC_ADDR_11 0x00 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_11 3 +#define CONFIG_SENSOR_ORIENTATION_11 270 +#define CONFIG_SENSOR_POWER_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_FALSH_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_11 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_11 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_11 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_11 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_11 30000 + +#define CONFIG_SENSOR_12 RK29_CAM_SENSOR_OV2659//RK29_CAM_SENSOR_OV2655 /* front camera sensor 2 */ +#define CONFIG_SENSOR_IIC_ADDR_12 0x00 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_12 3 +#define CONFIG_SENSOR_ORIENTATION_12 270 +#define CONFIG_SENSOR_POWER_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_FALSH_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_12 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_12 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_12 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_12 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_12 30000 + + +#endif //#ifdef CONFIG_VIDEO_RK29 +/*---------------- Camera Sensor Configuration Macro End------------------------*/ +#include "../../../drivers/media/video/rk30_camera.c" +/*---------------- Camera Sensor Macro Define End ---------*/ + +#define PMEM_CAM_SIZE PMEM_CAM_NECESSARY +/***************************************************************************************** + * camera devices + * author: ddl@rock-chips.com + *****************************************************************************************/ +#ifdef CONFIG_VIDEO_RK29 +#define CONFIG_SENSOR_POWER_IOCTL_USR 0 //define this refer to your board layout +#define CONFIG_SENSOR_RESET_IOCTL_USR 0 +#define CONFIG_SENSOR_POWERDOWN_IOCTL_USR 0 +#define CONFIG_SENSOR_FLASH_IOCTL_USR 0 + +static void rk_cif_power(int on) +{ + struct regulator *ldo_18,*ldo_28; + + ldo_28 = regulator_get(NULL, "ldo7"); // vcc28_cif + ldo_18 = regulator_get(NULL, "ldo1"); // vcc18_cif + if (ldo_28 == NULL || IS_ERR(ldo_28) || ldo_18 == NULL || IS_ERR(ldo_18)) { + printk("get cif ldo failed!\n"); + return; + } + if(on == 0) { + regulator_disable(ldo_28); + regulator_put(ldo_28); + regulator_disable(ldo_18); + regulator_put(ldo_18); + mdelay(500); + } else { + regulator_set_voltage(ldo_28, 2800000, 2800000); + regulator_enable(ldo_28); + // printk("%s set ldo7 vcc28_cif=%dmV end\n", __func__, regulator_get_voltage(ldo_28)); + regulator_put(ldo_28); + + regulator_set_voltage(ldo_18, 1800000, 1800000); + // regulator_set_suspend_voltage(ldo, 1800000); + regulator_enable(ldo_18); + // printk("%s set ldo1 vcc18_cif=%dmV end\n", __func__, regulator_get_voltage(ldo_18)); + regulator_put(ldo_18); + } +} + +#if CONFIG_SENSOR_POWER_IOCTL_USR +static int sensor_power_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + //#error "CONFIG_SENSOR_POWER_IOCTL_USR is 1, sensor_power_usr_cb function must be writed!!"; + rk_cif_power(on); +} +#endif + +#if CONFIG_SENSOR_RESET_IOCTL_USR +static int sensor_reset_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + #error "CONFIG_SENSOR_RESET_IOCTL_USR is 1, sensor_reset_usr_cb function must be writed!!"; +} +#endif + +#if CONFIG_SENSOR_POWERDOWN_IOCTL_USR +static int sensor_powerdown_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + #error "CONFIG_SENSOR_POWERDOWN_IOCTL_USR is 1, sensor_powerdown_usr_cb function must be writed!!"; +} +#endif + +#if CONFIG_SENSOR_FLASH_IOCTL_USR +static int sensor_flash_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + #error "CONFIG_SENSOR_FLASH_IOCTL_USR is 1, sensor_flash_usr_cb function must be writed!!"; +} +#endif + +static struct rk29camera_platform_ioctl_cb sensor_ioctl_cb = { + #if CONFIG_SENSOR_POWER_IOCTL_USR + .sensor_power_cb = sensor_power_usr_cb, + #else + .sensor_power_cb = NULL, + #endif + + #if CONFIG_SENSOR_RESET_IOCTL_USR + .sensor_reset_cb = sensor_reset_usr_cb, + #else + .sensor_reset_cb = NULL, + #endif + + #if CONFIG_SENSOR_POWERDOWN_IOCTL_USR + .sensor_powerdown_cb = sensor_powerdown_usr_cb, + #else + .sensor_powerdown_cb = NULL, + #endif + + #if CONFIG_SENSOR_FLASH_IOCTL_USR + .sensor_flash_cb = sensor_flash_usr_cb, + #else + .sensor_flash_cb = NULL, + #endif +}; + +#if CONFIG_SENSOR_IIC_ADDR_0 +static struct reginfo_t rk_init_data_sensor_reg_0[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_0[] = +{ + {0x0000, 0x00,0,0} +}; +#endif + +#if CONFIG_SENSOR_IIC_ADDR_1 +static struct reginfo_t rk_init_data_sensor_reg_1[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_1[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_01 +static struct reginfo_t rk_init_data_sensor_reg_01[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_01[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_02 +static struct reginfo_t rk_init_data_sensor_reg_02[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_02[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_11 +static struct reginfo_t rk_init_data_sensor_reg_11[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_11[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_12 +static struct reginfo_t rk_init_data_sensor_reg_12[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_12[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +static rk_sensor_user_init_data_s rk_init_data_sensor[RK_CAM_NUM] = +{ + #if CONFIG_SENSOR_IIC_ADDR_0 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_0, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_0, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_0) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_0) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_1 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_1, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_1, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_1) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_1) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_01 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_01, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_01, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_01) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_01) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_02 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_02, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_02, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_02) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_02) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_11 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_11, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_11, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_11) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_11) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_12 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_12, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_12, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_12) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_12) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + + }; +#include "../../../drivers/media/video/rk30_camera.c" + +#endif /* CONFIG_VIDEO_RK29 */ + + + #define RK_FB_MEM_SIZE 3*SZ_1M #if defined(CONFIG_FB_ROCKCHIP) @@ -293,12 +740,15 @@ static struct platform_device *devices[] __initdata = { #if defined(CONFIG_FB_ROCKCHIP) &device_fb, #endif + #ifdef CONFIG_BACKLIGHT_RK29_BL &rk29_device_backlight, #endif + #ifdef CONFIG_ION &device_ion, #endif + }; /************************************************************************************************** * SDMMC devices, include the module of SD,MMC,and sdio.noted by xbw at 2012-03-05 @@ -473,9 +923,14 @@ static void __init rk31_reserve(void) resource_fb[0].start = board_mem_reserve_add("fb0", RK_FB_MEM_SIZE); resource_fb[0].end = resource_fb[0].start + RK_FB_MEM_SIZE - 1; #endif + #ifdef CONFIG_ION rk30_ion_pdata.heaps[0].base = board_mem_reserve_add("ion", ION_RESERVE_SIZE); #endif + +#ifdef CONFIG_VIDEO_RK29 + rk30_camera_request_reserve_mem(); +#endif board_mem_reserved(); } diff --git a/arch/arm/mach-rk30/include/mach/rk30_camera.h b/arch/arm/mach-rk30/include/mach/rk30_camera.h index 5365fabe9aac..acb1ce975416 100755 --- a/arch/arm/mach-rk30/include/mach/rk30_camera.h +++ b/arch/arm/mach-rk30/include/mach/rk30_camera.h @@ -18,12 +18,23 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef __ASM_ARCH_CAMERA_RK30_H_ +#ifndef __ASM_ARCH_CAMERA_RK30_H_ -#define __ASM_ARCH_CAMERA_RK29_H_ -#define RK29_CAM_DRV_NAME "rk-camera-rk30" +#define __ASM_ARCH_CAMERA_RK30_H_ + +#ifdef CONFIG_ARCH_RK30 +#define RK29_CAM_DRV_NAME "rk-camera-rk30" +#define RK_SUPPORT_CIF0 1 +#define RK_SUPPORT_CIF1 1 +#endif + +#ifdef CONFIG_ARCH_RK31 +#define RK29_CAM_DRV_NAME "rk-camera-rk31" +#define RK_SUPPORT_CIF0 1 +#define RK_SUPPORT_CIF1 0 +#endif #include -#endif - +#endif + diff --git a/arch/arm/plat-rk/include/plat/rk_camera.h b/arch/arm/plat-rk/include/plat/rk_camera.h index 58f17a2767c0..8c3780322eb4 100755 --- a/arch/arm/plat-rk/include/plat/rk_camera.h +++ b/arch/arm/plat-rk/include/plat/rk_camera.h @@ -32,7 +32,7 @@ #define INVALID_GPIO -1 #define INVALID_VALUE -1 #define RK29_CAM_IO_SUCCESS 0 -#define RK29_CAM_EIO_INVALID -1 +#define RK29_CAM_EIO_INVALID 1 #define RK29_CAM_EIO_REQUESTFAIL -2 #define RK_CAM_NUM 6 diff --git a/arch/arm/plat-rk/rk_camera.c b/arch/arm/plat-rk/rk_camera.c index 8fd46a810e09..2347ca0fb5d6 100755 --- a/arch/arm/plat-rk/rk_camera.c +++ b/arch/arm/plat-rk/rk_camera.c @@ -241,14 +241,17 @@ #define PMEM_CAM_NECESSARY PMEM_CAM_NECESSARY_CIF_1 #define PMEM_CAMIPP_NECESSARY PMEM_CAMIPP_NECESSARY_CIF_1 #endif -#else - #ifdef CONFIG_ARCH_RK29 - #warning "Camera driver config two CIF work simultaneity,but rk29 has only one CIF" - #endif - #define PMEM_CAM_NECESSARY PMEM_CAM_NECESSARY_CIF_0 - #define PMEM_CAMIPP_NECESSARY PMEM_CAMIPP_NECESSARY_CIF_0 #endif +#if (!defined(CONFIG_VIDEO_RKCIF_WORK_SIMUL_OFF) && !defined(CONFIG_VIDEO_RKCIF_WORK_SIMUL_ON)) + #if PMEM_CAM_NECESSARY_CIF_0 + #define PMEM_CAM_NECESSARY PMEM_CAM_NECESSARY_CIF_0 + #define PMEM_CAMIPP_NECESSARY PMEM_CAMIPP_NECESSARY_CIF_0 + #else + #define PMEM_CAM_NECESSARY PMEM_CAM_NECESSARY_CIF_1 + #define PMEM_CAMIPP_NECESSARY PMEM_CAMIPP_NECESSARY_CIF_1 + #endif +#endif #ifdef CONFIG_VIDEO_RK29_CAMMEM_ION #undef PMEM_CAM_NECESSARY diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 67c42bca47f6..536f3ac34fa4 100755 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -1361,7 +1361,7 @@ endchoice choice prompt "RKXX CIF work simultaneity" - depends on VIDEO_RK29 + depends on VIDEO_RK29 && ARCH_RK30 default VIDEO_RKCIF_WORK_SIMUL_OFF ---help--- CIFs work simultaneity diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index c1dd9fb56bb0..064d0ef16d2f 100755 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -194,6 +194,10 @@ ifeq ($(CONFIG_ARCH_RK30),y) obj-$(CONFIG_VIDEO_RK29_WORK_ONEFRAME) += rk30_camera_oneframe.o obj-$(CONFIG_VIDEO_RK29_WORK_PINGPONG) += rk30_camera_pingpong.o endif +ifeq ($(CONFIG_ARCH_RK31),y) +obj-$(CONFIG_VIDEO_RK29_WORK_ONEFRAME) += rk30_camera_oneframe.o +obj-$(CONFIG_VIDEO_RK29_WORK_PINGPONG) += rk30_camera_pingpong.o +endif ifeq ($(CONFIG_ARCH_RK2928),y) obj-$(CONFIG_VIDEO_RK29_WORK_ONEFRAME) += rk30_camera_oneframe.o obj-$(CONFIG_VIDEO_RK29_WORK_PINGPONG) += rk30_camera_pingpong.o diff --git a/drivers/media/video/rk30_camera.c b/drivers/media/video/rk30_camera.c index c594c7b64f17..3b4d3217518c 100644 --- a/drivers/media/video/rk30_camera.c +++ b/drivers/media/video/rk30_camera.c @@ -854,6 +854,7 @@ static int rk_sensor_iomux(int pin) static u64 rockchip_device_camera_dmamask = 0xffffffffUL; +#if RK_SUPPORT_CIF0 static struct resource rk_camera_resource_host_0[] = { [0] = { .start = RK30_CIF0_PHYS, @@ -866,6 +867,8 @@ static struct resource rk_camera_resource_host_0[] = { .flags = IORESOURCE_IRQ, } }; +#endif +#if RK_SUPPORT_CIF1 static struct resource rk_camera_resource_host_1[] = { [0] = { .start = RK30_CIF1_PHYS, @@ -878,7 +881,10 @@ static struct resource rk_camera_resource_host_1[] = { .flags = IORESOURCE_IRQ, } }; +#endif + /*platform_device : */ +#if RK_SUPPORT_CIF0 struct platform_device rk_device_camera_host_0 = { .name = RK29_CAM_DRV_NAME, .id = RK_CAM_PLATFORM_DEV_ID_0, /* This is used to put cameras on this interface */ @@ -890,6 +896,9 @@ static struct resource rk_camera_resource_host_1[] = { .platform_data = &rk_camera_platform_data, } }; +#endif + +#if RK_SUPPORT_CIF1 /*platform_device : */ struct platform_device rk_device_camera_host_1 = { .name = RK29_CAM_DRV_NAME, @@ -902,6 +911,7 @@ static struct resource rk_camera_resource_host_1[] = { .platform_data = &rk_camera_platform_data, } }; +#endif static void rk_init_camera_plateform_data(void) { @@ -923,8 +933,8 @@ static void rk_init_camera_plateform_data(void) static void rk30_camera_request_reserve_mem(void) { -#ifdef CONFIG_VIDEO_RK29_WORK_IPP - #ifdef VIDEO_RKCIF_WORK_SIMUL_OFF +#ifdef CONFIG_VIDEO_RK29_WORK_IPP + #if defined(CONFIG_VIDEO_RKCIF_WORK_SIMUL_OFF) || ((RK_SUPPORT_CIF0 && RK_SUPPORT_CIF1) == false) rk_camera_platform_data.meminfo.name = "camera_ipp_mem"; rk_camera_platform_data.meminfo.start = board_mem_reserve_add("camera_ipp_mem",PMEM_CAMIPP_NECESSARY); rk_camera_platform_data.meminfo.size= PMEM_CAMIPP_NECESSARY; @@ -957,16 +967,27 @@ static int rk_register_camera_devices(void) host_registered_1 = 0; for (i=0; i #include #include @@ -38,15 +38,16 @@ #include #include #include -#ifdef CONFIG_ARCH_RK30 -#include -#else -#include -#define RK30_CRU_BASE 0 -#endif -//#include -//#include +#if defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) +#include +#include +#include +#endif + +#if defined(CONFIG_ARCH_RK2928) +#include +#endif static int debug ; module_param(debug, int, S_IRUGO|S_IWUSR); @@ -56,108 +57,110 @@ module_param(debug, int, S_IRUGO|S_IWUSR); printk(KERN_WARNING"rk_camera: " fmt , ## arg); } while (0) #define RKCAMERA_TR(format, ...) printk(KERN_ERR format, ## __VA_ARGS__) -#define RKCAMERA_DG(format, ...) dprintk(1, format, ## __VA_ARGS__) +#define RKCAMERA_DG(format, ...) dprintk(0, format, ## __VA_ARGS__) // CIF Reg Offset -#define CIF_CIF_CTRL 0x00 -#define CIF_CIF_INTEN 0x04 -#define CIF_CIF_INTSTAT 0x08 -#define CIF_CIF_FOR 0x0c -#define CIF_CIF_LINE_NUM_ADDR 0x10 -#define CIF_CIF_FRM0_ADDR_Y 0x14 -#define CIF_CIF_FRM0_ADDR_UV 0x18 -#define CIF_CIF_FRM1_ADDR_Y 0x1c -#define CIF_CIF_FRM1_ADDR_UV 0x20 -#define CIF_CIF_VIR_LINE_WIDTH 0x24 -#define CIF_CIF_SET_SIZE 0x28 -#define CIF_CIF_SCM_ADDR_Y 0x2c -#define CIF_CIF_SCM_ADDR_U 0x30 -#define CIF_CIF_SCM_ADDR_V 0x34 -#define CIF_CIF_WB_UP_FILTER 0x38 -#define CIF_CIF_WB_LOW_FILTER 0x3c +#define CIF_CIF_CTRL 0x00 +#define CIF_CIF_INTEN 0x04 +#define CIF_CIF_INTSTAT 0x08 +#define CIF_CIF_FOR 0x0c +#define CIF_CIF_LINE_NUM_ADDR 0x10 +#define CIF_CIF_FRM0_ADDR_Y 0x14 +#define CIF_CIF_FRM0_ADDR_UV 0x18 +#define CIF_CIF_FRM1_ADDR_Y 0x1c +#define CIF_CIF_FRM1_ADDR_UV 0x20 +#define CIF_CIF_VIR_LINE_WIDTH 0x24 +#define CIF_CIF_SET_SIZE 0x28 +#define CIF_CIF_SCM_ADDR_Y 0x2c +#define CIF_CIF_SCM_ADDR_U 0x30 +#define CIF_CIF_SCM_ADDR_V 0x34 +#define CIF_CIF_WB_UP_FILTER 0x38 +#define CIF_CIF_WB_LOW_FILTER 0x3c #define CIF_CIF_WBC_CNT 0x40 -#define CIF_CIF_CROP 0x44 -#define CIF_CIF_SCL_CTRL 0x48 -#define CIF_CIF_SCL_DST 0x4c -#define CIF_CIF_SCL_FCT 0x50 -#define CIF_CIF_SCL_VALID_NUM 0x54 -#define CIF_CIF_LINE_LOOP_CTR 0x58 -#define CIF_CIF_FRAME_STATUS 0x60 -#define CIF_CIF_CUR_DST 0x64 -#define CIF_CIF_LAST_LINE 0x68 -#define CIF_CIF_LAST_PIX 0x6c +#define CIF_CIF_CROP 0x44 +#define CIF_CIF_SCL_CTRL 0x48 +#define CIF_CIF_SCL_DST 0x4c +#define CIF_CIF_SCL_FCT 0x50 +#define CIF_CIF_SCL_VALID_NUM 0x54 +#define CIF_CIF_LINE_LOOP_CTR 0x58 +#define CIF_CIF_FRAME_STATUS 0x60 +#define CIF_CIF_CUR_DST 0x64 +#define CIF_CIF_LAST_LINE 0x68 +#define CIF_CIF_LAST_PIX 0x6c //The key register bit descrition // CIF_CTRL Reg , ignore SCM,WBC,ISP, #define DISABLE_CAPTURE (0x00<<0) #define ENABLE_CAPTURE (0x01<<0) -#define MODE_ONEFRAME (0x00<<1) -#define MODE_PINGPONG (0x01<<1) -#define MODE_LINELOOP (0x02<<1) -#define AXI_BURST_16 (0x0F << 12) +#define MODE_ONEFRAME (0x00<<1) +#define MODE_PINGPONG (0x01<<1) +#define MODE_LINELOOP (0x02<<1) +#define AXI_BURST_16 (0x0F << 12) //CIF_CIF_INTEN -#define FRAME_END_EN (0x01<<1) -#define BUS_ERR_EN (0x01<<6) -#define SCL_ERR_EN (0x01<<7) +#define FRAME_END_EN (0x01<<1) +#define BUS_ERR_EN (0x01<<6) +#define SCL_ERR_EN (0x01<<7) //CIF_CIF_FOR -#define VSY_HIGH_ACTIVE (0x01<<0) -#define VSY_LOW_ACTIVE (0x00<<0) -#define HSY_LOW_ACTIVE (0x01<<1) -#define HSY_HIGH_ACTIVE (0x00<<1) -#define INPUT_MODE_YUV (0x00<<2) -#define INPUT_MODE_PAL (0x02<<2) -#define INPUT_MODE_NTSC (0x03<<2) -#define INPUT_MODE_RAW (0x04<<2) -#define INPUT_MODE_JPEG (0x05<<2) -#define INPUT_MODE_MIPI (0x06<<2) -#define YUV_INPUT_ORDER_UYVY(ori) (ori & (~(0x03<<5))) -#define YUV_INPUT_ORDER_YVYU(ori) ((ori & (~(0x01<<6)))|(0x01<<5)) -#define YUV_INPUT_ORDER_VYUY(ori) ((ori & (~(0x01<<5))) | (0x1<<6)) -#define YUV_INPUT_ORDER_YUYV(ori) (ori|(0x03<<5)) -#define YUV_INPUT_422 (0x00<<7) -#define YUV_INPUT_420 (0x01<<7) -#define INPUT_420_ORDER_EVEN (0x00<<8) -#define INPUT_420_ORDER_ODD (0x01<<8) -#define CCIR_INPUT_ORDER_ODD (0x00<<9) -#define CCIR_INPUT_ORDER_EVEN (0x01<<9) -#define RAW_DATA_WIDTH_8 (0x00<<11) -#define RAW_DATA_WIDTH_10 (0x01<<11) -#define RAW_DATA_WIDTH_12 (0x02<<11) -#define YUV_OUTPUT_422 (0x00<<16) -#define YUV_OUTPUT_420 (0x01<<16) -#define OUTPUT_420_ORDER_EVEN (0x00<<17) -#define OUTPUT_420_ORDER_ODD (0x01<<17) -#define RAWD_DATA_LITTLE_ENDIAN (0x00<<18) -#define RAWD_DATA_BIG_ENDIAN (0x01<<18) -#define UV_STORAGE_ORDER_UVUV (0x00<<19) -#define UV_STORAGE_ORDER_VUVU (0x01<<19) +#define VSY_HIGH_ACTIVE (0x01<<0) +#define VSY_LOW_ACTIVE (0x00<<0) +#define HSY_LOW_ACTIVE (0x01<<1) +#define HSY_HIGH_ACTIVE (0x00<<1) +#define INPUT_MODE_YUV (0x00<<2) +#define INPUT_MODE_PAL (0x02<<2) +#define INPUT_MODE_NTSC (0x03<<2) +#define INPUT_MODE_RAW (0x04<<2) +#define INPUT_MODE_JPEG (0x05<<2) +#define INPUT_MODE_MIPI (0x06<<2) +#define YUV_INPUT_ORDER_UYVY(ori) (ori & (~(0x03<<5))) +#define YUV_INPUT_ORDER_YVYU(ori) ((ori & (~(0x01<<6)))|(0x01<<5)) +#define YUV_INPUT_ORDER_VYUY(ori) ((ori & (~(0x01<<5))) | (0x1<<6)) +#define YUV_INPUT_ORDER_YUYV(ori) (ori|(0x03<<5)) +#define YUV_INPUT_422 (0x00<<7) +#define YUV_INPUT_420 (0x01<<7) +#define INPUT_420_ORDER_EVEN (0x00<<8) +#define INPUT_420_ORDER_ODD (0x01<<8) +#define CCIR_INPUT_ORDER_ODD (0x00<<9) +#define CCIR_INPUT_ORDER_EVEN (0x01<<9) +#define RAW_DATA_WIDTH_8 (0x00<<11) +#define RAW_DATA_WIDTH_10 (0x01<<11) +#define RAW_DATA_WIDTH_12 (0x02<<11) +#define YUV_OUTPUT_422 (0x00<<16) +#define YUV_OUTPUT_420 (0x01<<16) +#define OUTPUT_420_ORDER_EVEN (0x00<<17) +#define OUTPUT_420_ORDER_ODD (0x01<<17) +#define RAWD_DATA_LITTLE_ENDIAN (0x00<<18) +#define RAWD_DATA_BIG_ENDIAN (0x01<<18) +#define UV_STORAGE_ORDER_UVUV (0x00<<19) +#define UV_STORAGE_ORDER_VUVU (0x01<<19) //CIF_CIF_SCL_CTRL -#define ENABLE_SCL_DOWN (0x01<<0) -#define DISABLE_SCL_DOWN (0x00<<0) -#define ENABLE_SCL_UP (0x01<<1) -#define DISABLE_SCL_UP (0x00<<1) -#define ENABLE_YUV_16BIT_BYPASS (0x01<<4) -#define DISABLE_YUV_16BIT_BYPASS (0x00<<4) -#define ENABLE_RAW_16BIT_BYPASS (0x01<<5) -#define DISABLE_RAW_16BIT_BYPASS (0x00<<5) -#define ENABLE_32BIT_BYPASS (0x01<<6) -#define DISABLE_32BIT_BYPASS (0x00<<6) +#define ENABLE_SCL_DOWN (0x01<<0) +#define DISABLE_SCL_DOWN (0x00<<0) +#define ENABLE_SCL_UP (0x01<<1) +#define DISABLE_SCL_UP (0x00<<1) +#define ENABLE_YUV_16BIT_BYPASS (0x01<<4) +#define DISABLE_YUV_16BIT_BYPASS (0x00<<4) +#define ENABLE_RAW_16BIT_BYPASS (0x01<<5) +#define DISABLE_RAW_16BIT_BYPASS (0x00<<5) +#define ENABLE_32BIT_BYPASS (0x01<<6) +#define DISABLE_32BIT_BYPASS (0x00<<6) +#if (defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31)) //CRU,PIXCLOCK -#define CRU_PCLK_REG30 0xbc -#define ENANABLE_INVERT_PCLK_CIF0 ((0x1<<24)|(0x1<<8)) -#define DISABLE_INVERT_PCLK_CIF0 ((0x1<<24)|(0x0<<8)) -#define ENANABLE_INVERT_PCLK_CIF1 ((0x1<<28)|(0x1<<12)) -#define DISABLE_INVERT_PCLK_CIF1 ((0x1<<28)|(0x0<<12)) +#define CRU_PCLK_REG30 0xbc +#define ENANABLE_INVERT_PCLK_CIF0 ((0x1<<24)|(0x1<<8)) +#define DISABLE_INVERT_PCLK_CIF0 ((0x1<<24)|(0x0<<8)) +#define ENANABLE_INVERT_PCLK_CIF1 ((0x1<<28)|(0x1<<12)) +#define DISABLE_INVERT_PCLK_CIF1 ((0x1<<28)|(0x0<<12)) -#define CRU_CIF_RST_REG30 0x128 -#define MASK_RST_CIF0 (0x01 << 30) -#define MASK_RST_CIF1 (0x01 << 31) -#define RQUEST_RST_CIF0 (0x01 << 14) -#define RQUEST_RST_CIF1 (0x01 << 15) +#define CRU_CIF_RST_REG30 0x128 +#define MASK_RST_CIF0 (0x01 << 30) +#define MASK_RST_CIF1 (0x01 << 31) +#define RQUEST_RST_CIF0 (0x01 << 14) +#define RQUEST_RST_CIF1 (0x01 << 15) +#endif #define MIN(x,y) ((xy) ? x: y) @@ -168,9 +171,18 @@ module_param(debug, int, S_IRUGO|S_IWUSR); #define read_cif_reg(base,addr) __raw_readl(addr+(base)) #define mask_cif_reg(addr, msk, val) write_cif_reg(addr, (val)|((~(msk))&read_cif_reg(addr))) +#if (defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31)) #define write_cru_reg(addr, val) __raw_writel(val, addr+RK30_CRU_BASE) #define read_cru_reg(addr) __raw_readl(addr+RK30_CRU_BASE) #define mask_cru_reg(addr, msk, val) write_cru_reg(addr,(val)|((~(msk))&read_cru_reg(addr))) +#endif + +#if defined(CONFIG_ARCH_RK2928) +#define write_cru_reg(addr, val) +#define read_cru_reg(addr) 0 +#define mask_cru_reg(addr, msk, val) +#endif + //when work_with_ipp is not enabled,CONFIG_VIDEO_RK29_DIGITALZOOM_IPP_OFF is not defined.something wrong with it #ifdef CONFIG_VIDEO_RK29_WORK_IPP//CONFIG_VIDEO_RK29_DIGITALZOOM_IPP_OFF @@ -183,8 +195,8 @@ module_param(debug, int, S_IRUGO|S_IWUSR); #define CAM_IPPWORK_IS_EN() ((pcdev->zoominfo.a.c.width != pcdev->icd->user_width) || (pcdev->zoominfo.a.c.height != pcdev->icd->user_height)) #endif #else //CONFIG_VIDEO_RK29_WORK_IPP -#define CAM_WORKQUEUE_IS_EN() (false) -#define CAM_IPPWORK_IS_EN() (false) +#define CAM_WORKQUEUE_IS_EN() (false) +#define CAM_IPPWORK_IS_EN() (false) #endif #define IS_CIF0() (pcdev->hostid == RK_CAM_PLATFORM_DEV_ID_0) @@ -217,7 +229,7 @@ module_param(debug, int, S_IRUGO|S_IWUSR); 2. irq process is splitted to two step. *v0.x.e: fix bugs of early suspend when display_pd is closed. */ -#define RK_CAM_VERSION_CODE KERNEL_VERSION(0, 2, 0xc) +#define RK_CAM_VERSION_CODE KERNEL_VERSION(0, 2, 0xe) /* limit to rk29 hardware capabilities */ #define RK_CAM_BUS_PARAM (SOCAM_MASTER |\ @@ -239,6 +251,7 @@ module_param(debug, int, S_IRUGO|S_IWUSR); #define RK_CAM_FRAME_INVAL_INIT 3 #define RK_CAM_FRAME_INVAL_DC 3 /* ddl@rock-chips.com : */ #define RK30_CAM_FRAME_MEASURE 5 + extern void videobuf_dma_contig_free(struct videobuf_queue *q, struct videobuf_buffer *buf); extern dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf); @@ -399,7 +412,6 @@ static int rk_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, return bytes_per_line_host; /* planar capture requires Y, U and V buffers to be page aligned */ - //*size = PAGE_ALIGN(bytes_per_line*icd->user_height); /* Y pages UV pages, yuv422*/ *size = PAGE_ALIGN(bytes_per_line*icd->user_height); /* Y pages UV pages, yuv422*/ pcdev->vipmem_bsize = PAGE_ALIGN(bytes_per_line_host * pcdev->host_height); @@ -476,15 +488,9 @@ static int rk_videobuf_prepare(struct videobuf_queue *vq, struct videobuf_buffer dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, vb, vb->baddr, vb->bsize); - - //RK29CAMERA_TR("\n%s..%d.. \n",__FUNCTION__,__LINE__); - + /* Added list head initialization on alloc */ - WARN_ON(!list_empty(&vb->queue)); - - /* This can be useful if you want to see if we actually fill - * the buffer with something */ - //memset((void *)vb->baddr, 0xaa, vb->bsize); + WARN_ON(!list_empty(&vb->queue)); BUG_ON(NULL == icd->current_fmt); @@ -512,7 +518,7 @@ static int rk_videobuf_prepare(struct videobuf_queue *vq, struct videobuf_buffer } vb->state = VIDEOBUF_PREPARED; } - //RK29CAMERA_TR("\n%s..%d.. \n",__FUNCTION__,__LINE__); + return 0; fail: rk_videobuf_free(vq, buf); @@ -540,7 +546,6 @@ static inline void rk_videobuf_capture(struct videobuf_buffer *vb,struct rk_came } write_cif_reg(pcdev->base,CIF_CIF_FRM0_ADDR_Y, y_addr); write_cif_reg(pcdev->base,CIF_CIF_FRM0_ADDR_UV, uv_addr); - //printk("y_addr = 0x%x, uv_addr = 0x%x \n",read_cif_reg(pcdev->base, CIF_CIF_FRM0_ADDR_Y),read_cif_reg(pcdev->base, CIF_CIF_FRM0_ADDR_UV)); write_cif_reg(pcdev->base,CIF_CIF_FRM1_ADDR_Y, y_addr); write_cif_reg(pcdev->base,CIF_CIF_FRM1_ADDR_UV, uv_addr); write_cif_reg(pcdev->base,CIF_CIF_FRAME_STATUS, 0x00000002);//frame1 has been ready to receive data,frame 2 is not used @@ -621,11 +626,9 @@ static void rk_camera_capture_process(struct work_struct *work) down(&pcdev->zoominfo.sem); ipp_req.timeout = 3000; ipp_req.flag = IPP_ROT_0; - // if(pcdev->icd->user_width != pcdev->zoominfo.vir_width) ipp_req.store_clip_mode =1; ipp_req.src0.w = pcdev->zoominfo.a.c.width/scale_times; ipp_req.src0.h = pcdev->zoominfo.a.c.height/scale_times; - //ipp_req.src_vir_w = pcdev->zoominfo.a.c.width; ipp_req.src_vir_w = pcdev->zoominfo.vir_width; rk_pixfmt2ippfmt(pcdev->pixfmt, &ipp_req.src0.fmt); ipp_req.dst0.w = pcdev->icd->user_width/scale_times; @@ -633,7 +636,6 @@ static void rk_camera_capture_process(struct work_struct *work) ipp_req.dst_vir_w = pcdev->icd->user_width; rk_pixfmt2ippfmt(pcdev->pixfmt, &ipp_req.dst0.fmt); vipdata_base = pcdev->vipmem_phybase + vb->i*pcdev->vipmem_bsize; - //src_y_size = pcdev->zoominfo.a.c.width*pcdev->zoominfo.a.c.height; src_y_size = pcdev->host_width*pcdev->host_height; //vipmem dst_y_size = pcdev->icd->user_width*pcdev->icd->user_height; for (h=0; hboff + dst_y_offset; ipp_req.dst0.CbrMst = vb->boff + dst_y_size + dst_uv_offset; - // printk("ipp_req.src0.YrgbMst = 0x%x , ipp_req.src0.CbrMst = 0x%x\n",ipp_req.src0.YrgbMst,ipp_req.src0.CbrMst); - // printk("ipp_req.dst0.YrgbMst = 0x%x , ipp_req.dst0.CbrMst = 0x%x\n",ipp_req.dst0.YrgbMst,ipp_req.dst0.CbrMst); - // printk("%dx%d@(%d,%d)->%dx%d\n",pcdev->zoominfo.a.c.width,pcdev->zoominfo.a.c.height,pcdev->zoominfo.a.c.left,pcdev->zoominfo.a.c.top,pcdev->icd->user_width,pcdev->icd->user_height); - // printk("ipp_req.src_vir_w:0x%x ipp_req.dst_vir_w :0x%x\n",ipp_req.src_vir_w ,ipp_req.dst_vir_w); - while(ipp_times-- > 0) - { + while(ipp_times-- > 0) { if (ipp_blit_sync(&ipp_req)){ RKCAMERA_TR("ipp do erro,do again,ipp_times = %d!\n",ipp_times); - } - else{ + } else { break; - } - } - if (ipp_times <= 0) - { + } + } + + if (ipp_times <= 0) { spin_lock_irqsave(&pcdev->lock, flags); vb->state = VIDEOBUF_NEEDS_INIT; spin_unlock_irqrestore(&pcdev->lock, flags); @@ -700,10 +696,8 @@ static irqreturn_t rk_camera_irq(int irq, void *data) struct rk_camera_work *wk; struct timeval tv; unsigned long tmp_intstat; - unsigned long tmp_cifctrl; - - - #if 1 + unsigned long tmp_cifctrl; + tmp_intstat = read_cif_reg(pcdev->base,CIF_CIF_INTSTAT); tmp_cifctrl = read_cif_reg(pcdev->base,CIF_CIF_CTRL); if(pcdev->stop_cif == true) @@ -718,7 +712,7 @@ static irqreturn_t rk_camera_irq(int irq, void *data) write_cif_reg(pcdev->base,CIF_CIF_CTRL, (tmp_cifctrl & ~ENABLE_CAPTURE)); return IRQ_HANDLED; } -#endif + /* ddl@rock-chps.com : Current VIP is run in One Frame Mode, Frame 1 is validate */ if (read_cif_reg(pcdev->base,CIF_CIF_FRAME_STATUS) & 0x01) { write_cif_reg(pcdev->base,CIF_CIF_INTSTAT,0x01); /* clear vip interrupte single */ @@ -745,7 +739,7 @@ static irqreturn_t rk_camera_irq(int irq, void *data) if(!vb){ printk("no acticve buffer!!!\n"); goto RK_CAMERA_IRQ_END; - } + } /* ddl@rock-chips.com : this vb may be deleted from queue */ if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) { list_del_init(&vb->queue); @@ -757,7 +751,7 @@ static irqreturn_t rk_camera_irq(int irq, void *data) rk_videobuf_capture(pcdev->active,pcdev); } else if(pcdev->active){ - printk("vb state is wrong ,del it \n"); + RKCAMERA_TR("%s : vb state is wrong ,del it \n",__FUNCTION__); list_del_init(&(pcdev->active->queue)); pcdev->active->state = VIDEOBUF_NEEDS_INIT; wake_up(&pcdev->active->done); @@ -776,7 +770,6 @@ static irqreturn_t rk_camera_irq(int irq, void *data) } if (CAM_WORKQUEUE_IS_EN()) { wk = pcdev->camera_work + vb->i; - //INIT_WORK(&(wk->work), rk_camera_capture_process); wk->vb = vb; wk->pcdev = pcdev; queue_work(pcdev->camera_wq, &(wk->work)); @@ -820,10 +813,10 @@ static void rk_videobuf_release(struct videobuf_queue *vq, break; } #endif - if(vb->i == 0){ - // printk("flush work queue.......\n"); + if (vb->i == 0) { flush_workqueue(pcdev->camera_wq); - } + } + if (vb == pcdev->active) { RKCAMERA_DG("%s Wait for this video buf(0x%x) write finished!\n ",__FUNCTION__,(unsigned int)vb); interruptible_sleep_on_timeout(&vb->done, 100); @@ -924,8 +917,6 @@ static int rk_camera_activate(struct rk_camera_dev *pcdev, struct soc_camera_dev static void rk_camera_deactivate(struct rk_camera_dev *pcdev) { - //pcdev->active = NULL; - // printk("rk_camera_deactivate enter\n"); clk_disable(pcdev->aclk_cif); clk_disable(pcdev->hclk_cif); @@ -1044,7 +1035,7 @@ static void rk_camera_remove_device(struct soc_camera_device *icd) if(pcdev->fps_timer.istarted){ hrtimer_cancel(&pcdev->fps_timer.timer); pcdev->fps_timer.istarted = false; - } + } flush_work(&(pcdev->camera_reinit_work.work)); flush_workqueue((pcdev->camera_wq)); @@ -1119,27 +1110,21 @@ static int rk_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) cif_ctrl_val = read_cif_reg(pcdev->base,CIF_CIF_FOR); RKCAMERA_DG("%s..%d..cif_ctrl_val = 0x%x\n",__FUNCTION__,__LINE__,cif_ctrl_val); if (common_flags & SOCAM_PCLK_SAMPLE_FALLING) { - if(IS_CIF0()) - { + if(IS_CIF0()) { write_cru_reg(CRU_PCLK_REG30, read_cru_reg(CRU_PCLK_REG30) | ENANABLE_INVERT_PCLK_CIF0); RKCAMERA_DG("enable cif0 pclk invert\n"); - } - else - { + } else { write_cru_reg(CRU_PCLK_REG30, read_cru_reg(CRU_PCLK_REG30) | ENANABLE_INVERT_PCLK_CIF1); RKCAMERA_DG("enable cif1 pclk invert\n"); - } + } } else { - if(IS_CIF0()) - { + if(IS_CIF0()){ write_cru_reg(CRU_PCLK_REG30, (read_cru_reg(CRU_PCLK_REG30) & 0xFFFFEFF ) | DISABLE_INVERT_PCLK_CIF0); RKCAMERA_DG("diable cif0 pclk invert\n"); - } - else - { + } else { write_cru_reg(CRU_PCLK_REG30, (read_cru_reg(CRU_PCLK_REG30) & 0xFFFEFFF) | DISABLE_INVERT_PCLK_CIF1); RKCAMERA_DG("diable cif1 pclk invert\n"); - } + } } if (common_flags & SOCAM_HSYNC_ACTIVE_LOW) { cif_ctrl_val |= HSY_LOW_ACTIVE; @@ -1894,7 +1879,6 @@ static int rk_camera_resume(struct soc_camera_device *icd) static void rk_camera_reinit_work(struct work_struct *work) { - struct device *control; struct v4l2_subdev *sd; struct v4l2_mbus_framefmt mf; const struct soc_camera_format_xlate *xlate; @@ -2332,7 +2316,9 @@ static int rk_camera_set_ctrl(struct soc_camera_device *icd, struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); const struct v4l2_queryctrl *qctrl; +#ifdef CONFIG_VIDEO_RK29_DIGITALZOOM_IPP_ON struct rk_camera_dev *pcdev = ici->priv; +#endif int ret = 0; qctrl = rk_camera_soc_camera_find_qctrl(ici->ops, sctrl->id); @@ -2433,7 +2419,18 @@ static int rk_camera_probe(struct platform_device *pdev) int irq,i; int err = 0; - RKCAMERA_DG("%s..%s..%d \n",__FUNCTION__,__FILE__,__LINE__); + RKCAMERA_DG("%s(%d) Enter..\n",__FUNCTION__,__LINE__); + + if ((pdev->id == RK_CAM_PLATFORM_DEV_ID_1) && (RK_SUPPORT_CIF1 == 0)) { + RKCAMERA_TR("%s(%d): This chip is not support CIF1!!\n",__FUNCTION__,__LINE__); + BUG(); + } + + if ((pdev->id == RK_CAM_PLATFORM_DEV_ID_0) && (RK_SUPPORT_CIF0 == 0)) { + RKCAMERA_TR("%s(%d): This chip is not support CIF0!!\n",__FUNCTION__,__LINE__); + BUG(); + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); if (!res || irq < 0) { @@ -2449,18 +2446,16 @@ static int rk_camera_probe(struct platform_device *pdev) pcdev->zoominfo.zoom_rate = 100; pcdev->hostid = pdev->id; + /*config output clk*/ // must modify start if(IS_CIF0()){ - // printk("it is cif 0!!!!!!!1\n"); pcdev->pd_cif = clk_get(NULL, "pd_cif0"); pcdev->aclk_cif = clk_get(NULL, "aclk_cif0"); pcdev->hclk_cif = clk_get(NULL, "hclk_cif0"); pcdev->cif_clk_in = clk_get(NULL, "cif0_in"); pcdev->cif_clk_out = clk_get(NULL, "cif0_out"); rk_camera_cif_iomux(0); - } - else{ - // printk("it is cif 1!!!!!!!1\n"); + } else { pcdev->pd_cif = clk_get(NULL, "pd_cif1"); pcdev->aclk_cif = clk_get(NULL, "aclk_cif1"); pcdev->hclk_cif = clk_get(NULL, "hclk_cif1"); @@ -2468,12 +2463,14 @@ static int rk_camera_probe(struct platform_device *pdev) pcdev->cif_clk_out = clk_get(NULL, "cif1_out"); rk_camera_cif_iomux(1); - } + } + if(IS_ERR(pcdev->pd_cif) || IS_ERR(pcdev->aclk_cif) || IS_ERR(pcdev->hclk_cif) || IS_ERR(pcdev->cif_clk_in) || IS_ERR(pcdev->cif_clk_out)){ - RKCAMERA_TR(KERN_ERR "failed to get cif clock source\n"); + RKCAMERA_TR(KERN_ERR "%s(%d): failed to get cif clock source\n",__FUNCTION__,__LINE__); err = -ENOENT; goto exit_reqmem_vip; - } + } + dev_set_drvdata(&pdev->dev, pcdev); pcdev->res = res; pcdev->pdata = pdev->dev.platform_data; /* ddl@rock-chips.com : Request IO in init function */ @@ -2485,14 +2482,12 @@ static int rk_camera_probe(struct platform_device *pdev) if (pcdev->pdata && IS_CIF0()) { pcdev->vipmem_phybase = pcdev->pdata->meminfo.start; pcdev->vipmem_size = pcdev->pdata->meminfo.size; - RKCAMERA_TR("\n%s Memory(start:0x%x size:0x%x) for IPP obtain \n",__FUNCTION__, pcdev->pdata->meminfo.start,pcdev->pdata->meminfo.size); - } - else if (pcdev->pdata){ + RKCAMERA_TR("%s(%d): Memory(start:0x%x size:0x%x) for IPP obtain \n",__FUNCTION__,__LINE__, pcdev->pdata->meminfo.start,pcdev->pdata->meminfo.size); + } else if (pcdev->pdata) { pcdev->vipmem_phybase = pcdev->pdata->meminfo_cif1.start; pcdev->vipmem_size = pcdev->pdata->meminfo_cif1.size; - RKCAMERA_TR("\n%s Memory(start:0x%x size:0x%x) for IPP obtain \n",__FUNCTION__, pcdev->pdata->meminfo.start,pcdev->pdata->meminfo.size); - } - else{ + RKCAMERA_TR("%s(%d): Memory(start:0x%x size:0x%x) for IPP obtain \n",__FUNCTION__,__LINE__, pcdev->pdata->meminfo.start,pcdev->pdata->meminfo.size); + } else { RKCAMERA_TR("\n%s Memory for IPP have not obtain! IPP Function is fail\n",__FUNCTION__); pcdev->vipmem_phybase = 0; pcdev->vipmem_size = 0; @@ -2505,43 +2500,42 @@ static int rk_camera_probe(struct platform_device *pdev) /* * Request the regions. */ - if(res){ - if (!request_mem_region(res->start, res->end - res->start + 1, - RK29_CAM_DRV_NAME)) { - err = -EBUSY; - goto exit_reqmem_vip; - } - pcdev->base = ioremap(res->start, res->end - res->start + 1); - if (pcdev->base == NULL) { - dev_err(pcdev->dev, "ioremap() of registers failed\n"); - err = -ENXIO; - goto exit_ioremap_vip; - } - } + if(res) { + if (!request_mem_region(res->start, res->end - res->start + 1, + RK29_CAM_DRV_NAME)) { + err = -EBUSY; + goto exit_reqmem_vip; + } + pcdev->base = ioremap(res->start, res->end - res->start + 1); + if (pcdev->base == NULL) { + dev_err(pcdev->dev, "ioremap() of registers failed\n"); + err = -ENXIO; + goto exit_ioremap_vip; + } + } pcdev->irq = irq; pcdev->dev = &pdev->dev; /* config buffer address */ /* request irq */ - if(irq > 0){ - err = request_irq(pcdev->irq, rk_camera_irq, 0, RK29_CAM_DRV_NAME, - pcdev); - if (err) { - dev_err(pcdev->dev, "Camera interrupt register failed \n"); - goto exit_reqirq; - } + if(irq > 0){ + err = request_irq(pcdev->irq, rk_camera_irq, 0, RK29_CAM_DRV_NAME, + pcdev); + if (err) { + dev_err(pcdev->dev, "Camera interrupt register failed \n"); + goto exit_reqirq; + } } //#ifdef CONFIG_VIDEO_RK29_WORK_IPP - if(IS_CIF0()){ - pcdev->camera_wq = create_workqueue("rk_cam_wkque_cif0"); - } - else{ - pcdev->camera_wq = create_workqueue("rk_cam_wkque_cif1"); - } - if (pcdev->camera_wq == NULL) - goto exit_free_irq; + if(IS_CIF0()) { + pcdev->camera_wq = create_workqueue("rk_cam_wkque_cif0"); + } else { + pcdev->camera_wq = create_workqueue("rk_cam_wkque_cif1"); + } + if (pcdev->camera_wq == NULL) + goto exit_free_irq; //#endif pcdev->camera_reinit_work.pcdev = pcdev; @@ -2565,8 +2559,8 @@ static int rk_camera_probe(struct platform_device *pdev) hrtimer_init(&(pcdev->fps_timer.timer), CLOCK_MONOTONIC, HRTIMER_MODE_REL); pcdev->fps_timer.timer.function = rk_camera_fps_func; pcdev->icd_cb.sensor_cb = NULL; -// rk29_camdev_info_ptr = pcdev; - RKCAMERA_DG("%s..%s..%d \n",__FUNCTION__,__FILE__,__LINE__); + + RKCAMERA_DG("%s(%d) Exit \n",__FUNCTION__,__LINE__); return 0; exit_free_irq: @@ -2603,7 +2597,7 @@ static int rk_camera_probe(struct platform_device *pdev) kfree(pcdev); exit_alloc: -// rk_camdev_info_ptr = NULL; + exit: return err; } @@ -2642,7 +2636,7 @@ static int __devexit rk_camera_remove(struct platform_device *pdev) } kfree(pcdev); - // rk_camdev_info_ptr = NULL; + dev_info(&pdev->dev, "RK28 Camera driver unloaded\n"); return 0; From ec6308916cdffddb5f2d6aa69bbfc9f16afb6889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=93=9D=E6=96=8C=E5=85=83?= Date: Fri, 27 Jul 2012 17:49:00 +0800 Subject: [PATCH 047/261] Revert "rk2928 add gps support" This reverts commit 225e3950a37b33e000ed1dd0b0e25f083e83988a. --- arch/arm/mach-rk2928/board-rk2928-fpga.c | 84 ---- drivers/misc/Makefile | 2 +- drivers/misc/gps/Kconfig | 3 +- drivers/misc/gps/Makefile | 2 +- drivers/misc/gps/hv5820b/Kconfig | 13 - drivers/misc/gps/hv5820b/Makefile | 3 - drivers/misc/gps/hv5820b/PALAPI.c | 421 ------------------ drivers/misc/gps/hv5820b/PALAPI.h | 72 --- drivers/misc/gps/hv5820b/gpsdriver.c | 529 ----------------------- drivers/misc/gps/hv5820b/gpsdriver.h | 50 --- drivers/misc/gps/hv5820b/gpsdrv.h | 53 --- drivers/misc/gps/hv5820b/hv5820b_gps.h | 25 -- drivers/misc/gps/hv5820b/lnxdrv.h | 52 --- 13 files changed, 3 insertions(+), 1306 deletions(-) delete mode 100755 drivers/misc/gps/hv5820b/Kconfig delete mode 100755 drivers/misc/gps/hv5820b/Makefile delete mode 100755 drivers/misc/gps/hv5820b/PALAPI.c delete mode 100755 drivers/misc/gps/hv5820b/PALAPI.h delete mode 100755 drivers/misc/gps/hv5820b/gpsdriver.c delete mode 100755 drivers/misc/gps/hv5820b/gpsdriver.h delete mode 100755 drivers/misc/gps/hv5820b/gpsdrv.h delete mode 100755 drivers/misc/gps/hv5820b/hv5820b_gps.h delete mode 100755 drivers/misc/gps/hv5820b/lnxdrv.h diff --git a/arch/arm/mach-rk2928/board-rk2928-fpga.c b/arch/arm/mach-rk2928/board-rk2928-fpga.c index 07e366c32fb2..7fd99583b24c 100755 --- a/arch/arm/mach-rk2928/board-rk2928-fpga.c +++ b/arch/arm/mach-rk2928/board-rk2928-fpga.c @@ -42,9 +42,6 @@ #include #include #include -#if defined(CONFIG_GPS_HV5820B) -#include "../../../drivers/misc/gps/hv5820b/hv5820b_gps.h" -#endif #ifdef CONFIG_VIDEO_RK29 /*---------------- Camera Sensor Macro Define Begin ------------------------*/ @@ -772,85 +769,7 @@ static struct platform_device device_ion = { }, }; #endif -#if defined(CONFIG_GPS_HV5820B) -int hv5820b_gps_io_init(void) -{ - printk("%s \n", __FUNCTION__); - rk30_mux_api_set(GPIO1B1_SPI_TXD_UART1_SOUT_NAME, GPIO1B_GPIO1B1);//VCC_EN - gpio_request(RK2928_PIN1_PB1, NULL); - gpio_direction_output(RK2928_PIN1_PB1, GPIO_LOW); - rk30_mux_api_set(GPIO1A2_I2S_LRCKRX_GPS_CLK_NAME, GPIO1A_GPS_CLK);//GPS_CLK - rk30_mux_api_set(GPIO1A4_I2S_SDO_GPS_MAG_NAME, GPIO1A_GPS_MAG);//GPS_MAG - rk30_mux_api_set(GPIO1A5_I2S_SDI_GPS_SIGN_NAME, GPIO1A_GPS_SIGN);//GPS_SIGN - - rk30_mux_api_set(GPIO1B0_SPI_CLK_UART1_CTSN_NAME, GPIO1B_GPIO1B0);//SPI_CLK - gpio_request(RK2928_PIN1_PB0, NULL); - gpio_direction_output(RK2928_PIN1_PB0, GPIO_LOW); - - rk30_mux_api_set(GPIO1B2_SPI_RXD_UART1_SIN_NAME, GPIO1B_GPIO1B2);//SPI_MOSI - gpio_request(RK2928_PIN1_PB2, NULL); - gpio_direction_output(RK2928_PIN1_PB2, GPIO_LOW); - - rk30_mux_api_set(GPIO1B3_SPI_CSN0_UART1_RTSN_NAME, GPIO1B_GPIO1B3);//SPI_CS - gpio_request(RK2928_PIN1_PB3, NULL); - gpio_direction_output(RK2928_PIN1_PB3, GPIO_LOW); - return 0; -} -int hv5820b_gps_power_up(void) -{ - printk("%s \n", __FUNCTION__); - - return 0; -} - -int hv5820b_gps_power_down(void) -{ - printk("%s \n", __FUNCTION__); - - return 0; -} - -int hv5820b_gps_reset_set(int level) -{ - return 0; -} -int hv5820b_enable_hclk_gps(void) -{ - printk("%s \n", __FUNCTION__); - clk_enable(clk_get(NULL, "hclk_gps")); - return 0; -} -int hv5820b_disable_hclk_gps(void) -{ - printk("%s \n", __FUNCTION__); - clk_disable(clk_get(NULL, "hclk_gps")); - return 0; -} -struct hv5820b_gps_data hv5820b_gps_info = { - .io_init = hv5820b_gps_io_init, - .power_up = hv5820b_gps_power_up, - .power_down = hv5820b_gps_power_down, - .reset = hv5820b_gps_reset_set, - .enable_hclk_gps = hv5820b_enable_hclk_gps, - .disable_hclk_gps = hv5820b_disable_hclk_gps, - .GpsSign = RK2928_PIN1_PA4, - .GpsMag = RK2928_PIN1_PB1, //GPIO index - .GpsClk = RK2928_PIN1_PA2, //GPIO index - .GpsVCCEn = RK2928_PIN1_PB1, //GPIO index - .GpsSpi_CSO = RK2928_PIN1_PB3, //GPIO index - .GpsSpiClk = RK2928_PIN1_PB0, //GPIO index - .GpsSpiMOSI = RK2928_PIN1_PB2, //GPIO index -}; - -struct platform_device hv5820b_device_gps = { - .name = "gps_hv5820b", - .id = -1, - .dev = { - .platform_data = &hv5820b_gps_info, - } - }; -#endif static struct platform_device *devices[] __initdata = { #ifdef CONFIG_ION &device_ion, @@ -858,9 +777,6 @@ static struct platform_device *devices[] __initdata = { #ifdef CONFIG_FB_ROCKCHIP &device_fb, #endif -#ifdef CONFIG_GPS_HV5820B - &hv5820b_device_gps, -#endif }; static void __init rk2928_board_init(void) diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 5a99f5aaab7c..e5b97a33c724 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -58,7 +58,7 @@ obj-$(CONFIG_MW100) += mw100.o obj-$(CONFIG_MT6229) += mt6229.o obj-$(CONFIG_STE) += ste.o obj-$(CONFIG_RK29_SUPPORT_MODEM) += rk29_modem/ -obj-$(CONFIG_RK29_GPS) += gps/ +obj-$(CONFIG_GPS_GNS7560) += gps/ obj-y += inv_mpu/ obj-$(CONFIG_RK29_NEWTON) += newton.o obj-$(CONFIG_TDSC8800) += tdsc8800.o diff --git a/drivers/misc/gps/Kconfig b/drivers/misc/gps/Kconfig index 7c912b3f74f6..ae012dbcaefd 100644 --- a/drivers/misc/gps/Kconfig +++ b/drivers/misc/gps/Kconfig @@ -13,8 +13,7 @@ if RK29_GPS config GPS_GNS7560 bool "gns7560 support" default n - -source "drivers/misc/gps/hv5820b/Kconfig" + endif # RK29_GPS diff --git a/drivers/misc/gps/Makefile b/drivers/misc/gps/Makefile index 5488d964d9fd..6b4bdb6480c2 100644 --- a/drivers/misc/gps/Makefile +++ b/drivers/misc/gps/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_GPS_GNS7560) += rk29_gps.o -obj-$(CONFIG_RK29_GPS) += hv5820b/ + diff --git a/drivers/misc/gps/hv5820b/Kconfig b/drivers/misc/gps/hv5820b/Kconfig deleted file mode 100755 index 47365c07ec1e..000000000000 --- a/drivers/misc/gps/hv5820b/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# -# gps device configuration -# - - - -config GPS_HV5820B - bool "HV5820B support" - default n - - - - diff --git a/drivers/misc/gps/hv5820b/Makefile b/drivers/misc/gps/hv5820b/Makefile deleted file mode 100755 index 150c55411149..000000000000 --- a/drivers/misc/gps/hv5820b/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_GPS_HV5820B) += gpsdriver.o PALAPI.o gpsdrv.a - - diff --git a/drivers/misc/gps/hv5820b/PALAPI.c b/drivers/misc/gps/hv5820b/PALAPI.c deleted file mode 100755 index 610bfca31752..000000000000 --- a/drivers/misc/gps/hv5820b/PALAPI.c +++ /dev/null @@ -1,421 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////// -// -// Filename: PALAPI.c -// Author: sjchen -// Copyright: -// Date: 2010/12/01 -// Description: -// linux system interface -// -// Revision: -// 0.0.1 -// -/////////////////////////////////////////////////////////////////////////////////// -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:PAL_AllocMem -// Parameters: -// Description: allocate system memory -// Notes: sjchen 2010/12/01 -// -/////////////////////////////////////////////////////////////////////////////////// -void* PAL_AllocMem(int nBytes) -{ - return kmalloc ( nBytes, GFP_KERNEL); -} - - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:PAL_FreeMem -// Parameters: -// Description: free system memory -// Notes: sjchen 2010/12/01 -// -/////////////////////////////////////////////////////////////////////////////////// -void PAL_FreeMem(void* pMem) -{ - if(pMem) - { - kfree(pMem); - } -} - - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:PAL_CreateMutex -// Parameters: -// Description: Create a semaphore -// Notes: sjchen 2010/12/01 -// -/////////////////////////////////////////////////////////////////////////////////// -int PAL_CreateMutex ( void) -{ - struct semaphore *psem; - - psem = (struct semaphore *)PAL_AllocMem(sizeof(struct semaphore)); - //init_MUTEX_LOCKED(psem); - sema_init(psem, 0); - return (int)psem; - -} - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:PAL_ReleaseMutex -// Parameters: -// Description: Release a semaphore -// Notes: sjchen 2010/12/01 -// -/////////////////////////////////////////////////////////////////////////////////// -void PAL_ReleaseMutex ( int hMutex ) -{ - if(hMutex) - { - up((struct semaphore *)hMutex); - } - - return ; -} - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:PAL_WaitMutex -// Parameters: -// Description: Wait semaphore to signal -// Notes: sjchen 2010/12/01 -// -/////////////////////////////////////////////////////////////////////////////////// -void PAL_WaitMutex(int hMutex) -{ - if(hMutex) - { - down((struct semaphore *)hMutex); - } -} - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:PAL_CloseMutes -// Parameters: -// Description: Close a semaphore -// Notes: sjchen 2010/12/01 -// -/////////////////////////////////////////////////////////////////////////////////// -void PAL_CloseMutes(int hMutex) -{ - if(hMutex) - { - PAL_FreeMem((void *)hMutex); - } -} - - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:PAL_memset -// Parameters: -// Description: -// Notes: sjchen 2010/12/01 -// -/////////////////////////////////////////////////////////////////////////////////// -void PAL_memset ( - void* pbuf, - unsigned char nval, - int nsize - ) -{ - memset ( pbuf, nval, nsize ); -} - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:PAL_memcpy -// Parameters: -// Description: -// Notes: sjchen 2010/12/01 -// -/////////////////////////////////////////////////////////////////////////////////// -void PAL_memcpy ( - void* pDst, - void* pSrc, - int nSize - ) -{ - memcpy ( pDst, pSrc, nSize ); -} - - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:PAL_GetCurTimer_US -// Parameters: -// Description: Get system time -// Notes: sjchen 2010/11/30 -// -/////////////////////////////////////////////////////////////////////////////////// -void PAL_GetCurTimer_US( - int *n32Second, - int *n32us - ) -{ - struct timeval tv; - - do_gettimeofday(&tv); - - *n32Second = tv.tv_sec; - *n32us = tv.tv_usec; -} - - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:PAL_GetCurTimer_US -// Parameters: -// Description: Get system time -// Notes: sjchen 2010/11/30 -// -/////////////////////////////////////////////////////////////////////////////////// -void PAL_GetSysTimer_US( - int *n32Second, - int *n32us - ) -{ - PAL_GetCurTimer_US(n32Second, n32us); -} - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:PAL_GetKernelFreePage -// Parameters: -// Description: Allocate kernel free page -// Notes: sjchen 2010/11/30 -// -/////////////////////////////////////////////////////////////////////////////////// -int PAL_GetKernelFreePage(int nPageSize) -{ - return __get_free_pages(GFP_KERNEL,get_order(nPageSize)); -} - - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:PAL_FreeKernelPage -// Parameters: -// Description: Free kernel page -// Notes: sjchen 2010/11/30 -// -/////////////////////////////////////////////////////////////////////////////////// -void PAL_FreeKernelPage(int nAddr,int nPageSize) -{ - if(nAddr != 0 && nPageSize != 0) - { - free_pages(nAddr,get_order(nPageSize)); - - } -} - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:PAL_GetUser -// Parameters: -// Description: -// Notes: sjchen 2010/11/30 -// -/////////////////////////////////////////////////////////////////////////////////// -int PAL_GetUser(int *p) -{ - int nData = 0; - - __get_user(nData,(int __user *)p); - - return nData; -} - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:PAL_CopyFromUser -// Parameters: -// Description: Copy datas from user space to kernel space -// Notes: sjchen 2010/11/30 -// -/////////////////////////////////////////////////////////////////////////////////// -void PAL_CopyFromUser(void *pDest,void *pSrc,int nSize) -{ - __copy_from_user(pDest,(void __user *)pSrc,nSize); -} - - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:PAL_CopyToUser -// Parameters: -// Description: Copy datas from kernel space to user space -// Notes: sjchen 2010/11/30 -// -/////////////////////////////////////////////////////////////////////////////////// -int PAL_CopyToUser(void *pDest,void *pSrc,int nSize) -{ - return copy_to_user((void __user *)pDest, pSrc, nSize); -} - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:PAL_Sprintf -// Parameters: -// Description: -// Notes: sjchen 2010/11/04 -// -/////////////////////////////////////////////////////////////////////////////////// -int PAL_Sprintf ( - char * pDst, - const char * pFormat, - ... - ) -{ - int nNum = 0; - - va_list ptr; - - va_start ( ptr, pFormat ); - - nNum = vsprintf ( pDst, pFormat, ptr ); - - va_end ( ptr ); - - return nNum; -} -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:PAL_Sprintf -// Parameters: -// Description: -// Notes: sjchen 2010/11/04 -// -/////////////////////////////////////////////////////////////////////////////////// -void PAL_KDEBUG ( - const char * pFormat, - ... - ) -{ -#if 1 - va_list ptr; - - va_start ( ptr, pFormat ); - - vprintk ( pFormat, ptr ); - - va_end ( ptr ); -#endif - return ; -} - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:PAL_mdelay -// Parameters: -// Description: -// Notes: sjchen 2010/11/04 -// -/////////////////////////////////////////////////////////////////////////////////// -void PAL_mdelay(int ms) -{ - mdelay(ms); -} - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:PAL_dma_cache_wback_inv -// Parameters: -// Description: -// Notes: sjchen 2010/11/04 -// -/////////////////////////////////////////////////////////////////////////////////// -void PAL_dma_cache_wback_inv(void * pMem, int size ) -{ - //TODO: - //fluch cache - - __cpuc_flush_dcache_area(pMem, size ); -} - - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:PAL_dma_cache_wback_inv -// Parameters: -// Description: -// Notes: sjchen 2010/11/04 -// -/////////////////////////////////////////////////////////////////////////////////// -void PAL_dma_cache_inv(void * pMem, int size ) -{ - //TODO: - //fluch cache - - __cpuc_flush_dcache_area(pMem, size ); -} - - - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:PAL_Set_GPIO_Pin -// Parameters: -// Description: -// Notes: sjchen 2010/11/04 -// -/////////////////////////////////////////////////////////////////////////////////// -void PAL_Set_GPIO_Pin(int gpio) -{ - //TODO: - //Set gpio to high level - - //gpio_write_one_pin_value(gpio, 1); - gpio_set_value(gpio, GPIO_HIGH); -} - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:PAL_Clr_GPIO_Pin -// Parameters: -// Description: -// Notes: sjchen 2010/11/04 -// -/////////////////////////////////////////////////////////////////////////////////// -void PAL_Clr_GPIO_Pin(int gpio) -{ - //TODO: - //Set gpio to low level - - //gpio_write_one_pin_value(gpio, 0); - gpio_set_value(gpio, GPIO_LOW); -} - - diff --git a/drivers/misc/gps/hv5820b/PALAPI.h b/drivers/misc/gps/hv5820b/PALAPI.h deleted file mode 100755 index b45a7a86dd59..000000000000 --- a/drivers/misc/gps/hv5820b/PALAPI.h +++ /dev/null @@ -1,72 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////// -// -// Filename: PALAPI.h -// Author: sjchen -// Copyright: -// Date: 2010/12/01 -// Description: -// declare linux driver function -// -// Revision: -// 0.0.1 -// -/////////////////////////////////////////////////////////////////////////////////// - -#ifndef __PALAPI_H___ -#define __PALAPI_H___ - -extern void* PAL_AllocMem(int nBytes); -extern void PAL_FreeMem(void* pMem); -extern int PAL_CreateMutex ( void); -extern void PAL_ReleaseMutex ( int hMutex ); -extern void PAL_WaitMutex(int hMutex); -extern void PAL_CloseMutes(int hMutex); - -extern void PAL_memset ( - void* pbuf, - unsigned char nval, - int nsize - ); - -extern void PAL_memcpy ( - void* pDst, - void* pSrc, - int nSize - ); - -void PAL_GetCurTimer_US( - int *n32Second, - int *n32us - ); - -void PAL_GetSysTimer_US( - int *n32Second, - int *n32us - ); - -int PAL_GetKernelFreePage(int nPageSize); - -void PAL_FreeKernelPage(int nAddr,int nPageSize); - -int PAL_GetUser(int *p); - -void PAL_CopyFromUser(void *pDest,void *pSrc,int nSize); - -int PAL_CopyToUser(void *pDest,void *pSrc,int nSize); - -int PAL_Sprintf ( - char * pDst, - const char * pFormat, - ... - ); - -void PAL_mdelay(int ms); - -void PAL_KDEBUG ( - const char * pFormat, - ... - ); -void PAL_Set_GPIO_Pin(int gpio); -void PAL_Clr_GPIO_Pin(int gpio); - -#endif //__PALAPI_H___ diff --git a/drivers/misc/gps/hv5820b/gpsdriver.c b/drivers/misc/gps/hv5820b/gpsdriver.c deleted file mode 100755 index 97877d3654cc..000000000000 --- a/drivers/misc/gps/hv5820b/gpsdriver.c +++ /dev/null @@ -1,529 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////// -// -// Filename: gpsdriver.c -// Author: sjchen -// Copyright: -// Date: 2012/07/09 -// Description: -// GPS driver -// -// Revision: -// 0.0.1 -// -/////////////////////////////////////////////////////////////////////////////////// -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -//#include - - -#include "gpsdrv.h" -#include "gpsdriver.h" -#include "lnxdrv.h" -#include "PALAPI.h" - -#include -#include -#include "hv5820b_gps.h" - -/////////////////////////////////////////////////////////////////////////////////// -// -// macro declaration -// -/////////////////////////////////////////////////////////////////////////////////// -#define GPS_MAJOR ( 61 ) -#define SW_VA_GPS_IO_BASE 0x10400000 -#define GPS_USE_SPI - - -/////////////////////////////////////////////////////////////////////////////////// -// -// static variables declaration -// -/////////////////////////////////////////////////////////////////////////////////// -static char gpsstr[]="gps"; -static struct miscdevice gps_miscdev; -struct hv5820b_gps_data *hv5820b_pdata ; -void *gps_mem =NULL; -unsigned long gps_mem_address; //BSP define for u32MemoryPhyAddr -unsigned long gps_mem_size = 8*0x00100000; //it must be more than 8MB - -/////////////////////////////////////////////////////////////////////////////////// -// -// extern variables declaration -// -/////////////////////////////////////////////////////////////////////////////////// -extern unsigned long gps_mem_address; //BSP define for u32MemoryPhyAddr -extern unsigned long gps_mem_size; //it must be more than 8MB - - -#ifdef GPS_USE_SPI -#include -void VtuneAndSpiCheck_rk(int enable_check); -int AdcValueGet(void); -int GetVtuneAdcValue_rk(void); -void ConfigRfSpi_rk(int Val ); -struct adc_client *adc_gps_cleint; -#define LOW_SCALE_0_65V 600 -#define HIGH_SCALE_0_95V 1000 -void gps_callback(struct adc_client *client, void *callback_param, int result) -{ - return; -} -void VtuneAndSpiCheck_rk(int enable_check) -{ - int VtuneAvg; - int SpiValue = 2; - int cnt = 0; - - if( enable_check == 0) - return; - - VtuneAvg = 0; - while( (VtuneAvg < LOW_SCALE_0_65V) || (VtuneAvg > HIGH_SCALE_0_95V) && cnt < 10) - { - if( (SpiValue >= 8) || (SpiValue <= 0) ) - break; - - VtuneAvg = AdcValueGet(); - - if( VtuneAvg < LOW_SCALE_0_65V) - { - SpiValue++; - ConfigRfSpi_rk( SpiValue); - } - - if( VtuneAvg > HIGH_SCALE_0_95V) - { - SpiValue--; - ConfigRfSpi_rk( SpiValue); - } - cnt ++; - } -} - - -int AdcValueGet() -{ - // Read adc value - int adc_value; - int sampletime = 100; - int AveValue; - int SumValue; - int i; - - - SumValue = 0; - for(i = 0; i < sampletime; i++) - { - adc_value = GetVtuneAdcValue_rk(); - - SumValue += adc_value; - } - AveValue = SumValue / sampletime; - return AveValue; -} - -int GetVtuneAdcValue_rk() -{ - int adc_val = 0; - - adc_val = adc_sync_read(adc_gps_cleint); - if(adc_val < 0) - printk("GetVtuneAdcValue error"); - - return adc_val; -} - -void ConfigRfSpi_rk(int Val ) -{ - int i; - -#define GPS_SCLK hv5820b_pdata->GpsSpiMOSI -#define GPS_MOSI hv5820b_pdata->GpsSpiClk -#define GPS_SCS hv5820b_pdata->GpsSpi_CSO - - - PAL_Clr_GPIO_Pin(GPS_SCLK); - PAL_Clr_GPIO_Pin(GPS_SCS); - - for(i = 0; i < 100000000; i++); - - PAL_Set_GPIO_Pin(GPS_SCLK); - PAL_Set_GPIO_Pin(GPS_MOSI); //b15 - - - for(i = 0; i < 100000000; i++); - PAL_Clr_GPIO_Pin(GPS_SCLK); - for(i = 0; i < 100000000; i++); - PAL_Set_GPIO_Pin(GPS_SCLK); //b14 - for(i = 0; i < 100000000; i++); - PAL_Clr_GPIO_Pin(GPS_SCLK); - for(i = 0; i < 100000000; i++); - PAL_Set_GPIO_Pin(GPS_SCLK); //b13 - for(i = 0; i < 100000000; i++); - PAL_Clr_GPIO_Pin(GPS_SCLK); - for(i = 0; i < 100000000; i++); - PAL_Set_GPIO_Pin(GPS_SCLK); //b12 - PAL_Clr_GPIO_Pin(GPS_MOSI); - for(i = 0; i < 100000000; i++); - PAL_Clr_GPIO_Pin(GPS_SCLK); - for(i = 0; i < 100000000; i++); - PAL_Set_GPIO_Pin(GPS_SCLK); //b11 - PAL_Set_GPIO_Pin(GPS_MOSI); - for(i = 0; i < 100000000; i++); - PAL_Clr_GPIO_Pin(GPS_SCLK); - for(i = 0; i < 100000000; i++); - PAL_Set_GPIO_Pin(GPS_SCLK); //b10 - for(i = 0; i < 100000000; i++); - PAL_Clr_GPIO_Pin(GPS_SCLK); - for(i = 0; i < 100000000; i++); - PAL_Set_GPIO_Pin(GPS_SCLK); //b9 - PAL_Clr_GPIO_Pin(GPS_MOSI); - for(i = 0; i < 100000000; i++); - PAL_Clr_GPIO_Pin(GPS_SCLK); - for(i = 0; i < 100000000; i++); - PAL_Set_GPIO_Pin(GPS_SCLK); //b8 - for(i = 0; i < 100000000; i++); - PAL_Clr_GPIO_Pin(GPS_SCLK); - for(i = 0; i < 100000000; i++); - PAL_Set_GPIO_Pin(GPS_SCLK); //b7 - for(i = 0; i < 100000000; i++); - PAL_Clr_GPIO_Pin(GPS_SCLK); - for(i = 0; i < 100000000; i++); - PAL_Set_GPIO_Pin(GPS_SCLK); //b6 - if ((Val >> 4) & 1) - PAL_Set_GPIO_Pin(GPS_MOSI); - else - PAL_Clr_GPIO_Pin(GPS_MOSI); - for(i = 0; i < 100000000; i++); - PAL_Clr_GPIO_Pin(GPS_SCLK); - for(i = 0; i < 100000000; i++); - PAL_Set_GPIO_Pin(GPS_SCLK); //b5 - if ((Val >> 3) & 1) - PAL_Set_GPIO_Pin(GPS_MOSI); - else - PAL_Clr_GPIO_Pin(GPS_MOSI); - for(i = 0; i < 100000000; i++); - PAL_Clr_GPIO_Pin(GPS_SCLK); - for(i = 0; i < 100000000; i++); - PAL_Set_GPIO_Pin(GPS_SCLK); //b4 - if ((Val >> 2) & 1) - PAL_Set_GPIO_Pin(GPS_MOSI); - else - PAL_Clr_GPIO_Pin(GPS_MOSI); - for(i = 0; i < 100000000; i++); - PAL_Clr_GPIO_Pin(GPS_SCLK); - for(i = 0; i < 100000000; i++); - PAL_Set_GPIO_Pin(GPS_SCLK); //b3 - if ((Val >> 1) & 1) - PAL_Set_GPIO_Pin(GPS_MOSI); - else - PAL_Clr_GPIO_Pin(GPS_MOSI); - for(i = 0; i < 100000000; i++); - PAL_Clr_GPIO_Pin(GPS_SCLK); - for(i = 0; i < 100000000; i++); - PAL_Set_GPIO_Pin(GPS_SCLK); //b2 - if ((Val >> 0) & 1) - PAL_Set_GPIO_Pin(GPS_MOSI); - else - PAL_Clr_GPIO_Pin(GPS_MOSI); - for(i = 0; i < 100000000; i++); - PAL_Clr_GPIO_Pin(GPS_SCLK); - for(i = 0; i < 100000000; i++); - PAL_Set_GPIO_Pin(GPS_SCLK); //b1 - for(i = 0; i < 100000000; i++); - PAL_Clr_GPIO_Pin(GPS_SCLK); - for(i = 0; i < 100000000; i++); - PAL_Set_GPIO_Pin(GPS_SCLK); //b0 - for(i = 0; i < 100000000; i++); - PAL_Clr_GPIO_Pin(GPS_SCLK); - for(i = 0; i < 100000000; i++); - for(i = 0; i < 100000000; i++); - PAL_Set_GPIO_Pin(GPS_SCS); -} -#endif -static int hv5820b_gps_probe(struct platform_device *pdev) -{ - int err; - struct hv5820b_gps_data *pdata = pdev->dev.platform_data; - if(!pdata) - return -1; - hv5820b_pdata = pdata; - - printk("Enter GPSDrv_Init\n"); - - err = request_irq ( GPS_BB_INT_MASK, gps_int_handler, IRQF_DISABLED, gpsstr, NULL ); - - if ( err ) - { - printk ( "gps_mod_init: gps request irq failed!\n" ); - - return err; - } - - err = misc_register( &gps_miscdev); - if (err < 0) - { - return err; - } - - gps_mem=kzalloc(gps_mem_size, GFP_KERNEL); - gps_mem_address = (unsigned long)(&gps_mem); - //TODO: - //Set the GPIO (GPS_VCC_EN) to low level in here - // - if(pdata->io_init) - pdata->io_init(); - gpio_direction_output(pdata->GpsVCCEn, GPIO_LOW); - #ifdef GPS_USE_SPI - adc_gps_cleint = adc_register(2, gps_callback, NULL); - #endif - return 0; -} -static int hv5820b_gps_remove(struct platform_device *pdev) -{ -#ifdef GPS_USE_SPI - adc_unregister(adc_gps_cleint); -#endif - return 0; -} -static int hv5820b_gps_suspend(struct platform_device *pdev, pm_message_t state) -{ - return 0; -} -static int hv5820b_gps_resume(struct platform_device *pdev) -{ - return 0; -} -static struct platform_driver hv5820b_gps_driver = { - .probe = hv5820b_gps_probe, - .remove = hv5820b_gps_remove, - .suspend = hv5820b_gps_suspend, - .resume = hv5820b_gps_resume, - .driver = { - .name = "gps_hv5820b", - .owner = THIS_MODULE, - }, -}; - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name: gps_mod_init -// Parameters: -// Description: -// Notes: sjchen 2010/11/04 -// -/////////////////////////////////////////////////////////////////////////////////// -static int __init gps_mod_init(void) -{ - return platform_driver_register(&hv5820b_gps_driver); -} - - - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name: gps_mod_exit -// Parameters: -// Description: -// Notes: sjchen 2010/11/04 -// -/////////////////////////////////////////////////////////////////////////////////// -static void __exit gps_mod_exit ( void ) -{ - //Disable baseband interrupt - WriteGpsRegisterUlong ( BB_INT_ENA_OFFSET, 0 ); - - free_irq( GPS_BB_INT_MASK, NULL ); - - //unregister_chrdev ( GPS_MAJOR, gpsstr ); - misc_deregister(&gps_miscdev); - platform_driver_unregister(&hv5820b_gps_driver); - printk ( "GPS exit ok!\n"); -} - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:gps_ioctl -// Parameters: -// Description: -// Notes: sjchen 2010/11/04 -// -/////////////////////////////////////////////////////////////////////////////////// -long gps_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - int ret = 0; - BB_DRV_VERSION __user * pVersion; - GPS_DRV_INIT GpsInitStruct; - - switch(cmd) - { - - case IOCTL_BB_GPS_START: - //TODO: - // Gps baseband module initialize in here. - // Module power up - if(hv5820b_pdata->enable_hclk_gps) - hv5820b_pdata->enable_hclk_gps(); - - memset(&GpsInitStruct,0,sizeof(GpsInitStruct)); - GpsInitStruct.u32GpsRegBase = SW_VA_GPS_IO_BASE; // GPS Reg Base address - GpsInitStruct.u32MemoryPhyAddr = gps_mem_address; // sample code - GpsInitStruct.u32MemoryVirAddr = __phys_to_virt(gps_mem_address); - GpsInitStruct.u32GpsSign = hv5820b_pdata->GpsSign; //GPIO index - GpsInitStruct.u32GpsMag = hv5820b_pdata->GpsMag; //GPIO index - GpsInitStruct.u32GpsClk = hv5820b_pdata->GpsClk; //GPIO index - GpsInitStruct.u32GpsVCCEn = hv5820b_pdata->GpsVCCEn; //GPIO index - GpsInitStruct.u32GpsSpi_CSO = hv5820b_pdata->GpsSpi_CSO; //GPIO index - GpsInitStruct.u32GpsSpiClk = hv5820b_pdata->GpsSpiClk; //GPIO index - GpsInitStruct.u32GpsSpiMOSI = hv5820b_pdata->GpsSpiMOSI; //GPIO index - //TODO: - //Add other member of struct GpsInitStruct - Gps_Init( arg,&GpsInitStruct); - #ifdef GPS_USE_SPI - VtuneAndSpiCheck_rk(1); - #endif - break; - - case IOCTL_BB_UPDATEDATA: - Gps_UpdateData(arg); - break; - - - case IOCTL_BB_GPS_STOP: - Gps_Stop(); - - //TODO: - // Set the GPIO(GPS_VCC_EN) to low level - // Close the module clk. - gpio_direction_output(hv5820b_pdata->GpsVCCEn, GPIO_LOW); - if(hv5820b_pdata->disable_hclk_gps) - hv5820b_pdata->disable_hclk_gps(); - break; - - case IOCTL_BB_GET_VERSION: - pVersion = ( void __user * ) arg; - - pVersion->u32Major = DRV_MAJOR_VERSION; - pVersion->u32Minor = DRV_MINOR_VERSION; - PAL_Sprintf(pVersion->strCompileTime,"%s,%s",__DATE__,__TIME__); - - break; - - default: - - printk ( "gpsdrv: ioctl number is worng %d\n",cmd); - - break; - }; - - return ret; -} - - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:gps_read -// Parameters: -// Description: Read gps data -// Notes: sjchen 2010/11/04 -// -/////////////////////////////////////////////////////////////////////////////////// -ssize_t gps_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) -{ - ssize_t nsize; - if((nsize = GpsDrv_Read(buf,size))) - { - return nsize; - } - - return -EFAULT; -} - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:gps_open -// Parameters: -// Description: -// Notes: sjchen 2010/11/04 -// -/////////////////////////////////////////////////////////////////////////////////// -static int gps_open (struct inode *inode, struct file *filp) -{ - return 0; /* success */ -} - - - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name:gps_close -// Parameters: -// Description: -// Notes: sjchen 2010/11/04 -// -/////////////////////////////////////////////////////////////////////////////////// -static int gps_close (struct inode *inode, struct file *filp) -{ - return 0; -} - -/////////////////////////////////////////////////////////////////////////////////// -// -// Function Name: driver struct -// Parameters: -// Description: -// Notes: sjchen 2010/11/04 -// -/////////////////////////////////////////////////////////////////////////////////// -static const struct file_operations gps_fops = -{ - . owner = THIS_MODULE, - . open = gps_open, - . release = gps_close, - . unlocked_ioctl = gps_ioctl, - . read = gps_read, -}; - -static struct miscdevice gps_miscdev = -{ - .minor = MISC_DYNAMIC_MINOR, - .name = gpsstr, - .fops = &gps_fops, -}; - - -/////////////////////////////////////////////////////////////////////////////////// -// -// Module Name: -// Parameters: -// Description: -// Notes: sjchen 2010/11/04 -// -/////////////////////////////////////////////////////////////////////////////////// -module_init ( gps_mod_init ); -module_exit ( gps_mod_exit ); - - -MODULE_LICENSE("GPL"); - - diff --git a/drivers/misc/gps/hv5820b/gpsdriver.h b/drivers/misc/gps/hv5820b/gpsdriver.h deleted file mode 100755 index 026ab5a6faea..000000000000 --- a/drivers/misc/gps/hv5820b/gpsdriver.h +++ /dev/null @@ -1,50 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////// -// -// Filename: gpsdriver.h -// Author: sjchen -// Copyright: -// Date: 2012/07/09 -// Description: -// gps driver function -// -// Revision: -// 0.0.1 -// -/////////////////////////////////////////////////////////////////////////////////// - -#ifndef __GPSDRIVER_H___ -#define __GPSDRIVER_H___ - -#define GPS_BB_INT_MASK 57 - - -typedef struct __tag_GPS_DRV_INIT -{ - unsigned long u32MemoryPhyAddr; //must reserved 8MB memory for GPS - unsigned long u32MemoryVirAddr; - unsigned long u32GpsRegBase; //GPS register base virtual address - unsigned int u32GpsSign; //GPIO index - unsigned int u32GpsMag; //GPIO index - unsigned int u32GpsClk; //GPIO index - unsigned int u32GpsVCCEn; //GPIO index - unsigned int u32GpsSpi_CSO; //GPIO index - unsigned int u32GpsSpiClk; //GPIO index - unsigned int u32GpsSpiMOSI; //GPIO index -}GPS_DRV_INIT,*PGPS_DRV_INIT; - -extern void WriteGpsRegisterUlong ( int reg_offset, int value ); - -extern int ReadGpsRegisterUlong ( int reg_offset ); - -extern irqreturn_t gps_int_handler ( int irq, void * dev_id ); - -extern void Gps_Init(unsigned long arg,PGPS_DRV_INIT pGpsDrvInit); - -extern void Gps_UpdateData(unsigned long arg); - -extern void Gps_Stop(void); - -extern int GpsDrv_Read(char *buf ,int nSize); - -#endif //__GPSDRIVER_H___ - diff --git a/drivers/misc/gps/hv5820b/gpsdrv.h b/drivers/misc/gps/hv5820b/gpsdrv.h deleted file mode 100755 index cc24b891c4d4..000000000000 --- a/drivers/misc/gps/hv5820b/gpsdrv.h +++ /dev/null @@ -1,53 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////// -// -// Filename: gpsdrv.h -// Author: sjchen -// Copyright: -// Date: 2012/07/09 -// Description: -// the struct driver to app -// -// Revision: -// 0.0.1 -// -/////////////////////////////////////////////////////////////////////////////////// -#ifndef __GPSDRV_H__ -#define __GPSDRV_H__ - - -#define DRV_MAJOR_VERSION 1 -#define DRV_MINOR_VERSION 9 - -typedef struct __tag_BB_COMMAND_BUFFER { - int n32BufferA; - int n32BufferB; - int n32NavBuf; -} BB_COMMAND_BUFFER, *PBB_COMMAND_BUFFER; - - -typedef struct __tag_DRV_VERSION { - unsigned int u32Major; - unsigned int u32Minor; - char strCompileTime[32]; - -}BB_DRV_VERSION,*PBB_DRV_VERSION; - -// IOCTL code -enum -{ - // GPS Start - IOCTL_BB_GPS_START = 128, - IOCTL_BB_GPS_STOP, - - //Update gps data - IOCTL_BB_UPDATEDATA, - - //Driver version - IOCTL_BB_GET_VERSION - -}; - -#endif /* __GPSDRV_H__ */ - - - diff --git a/drivers/misc/gps/hv5820b/hv5820b_gps.h b/drivers/misc/gps/hv5820b/hv5820b_gps.h deleted file mode 100755 index bec227d55104..000000000000 --- a/drivers/misc/gps/hv5820b/hv5820b_gps.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - 2012.07.25 lby@rock-chips.com -*/ - -#ifndef __HV5820B_GPS_H__ -#define __HV5820B_GPS_H__ - -struct hv5820b_gps_data { - int (*io_init)(void); - int (*power_up)(void); - int (*power_down)(void); - int (*reset)(int); - int (*enable_hclk_gps)(void); - int (*disable_hclk_gps)(void); - int GpsSign; - int GpsMag; //GPIO index - int GpsClk; //GPIO index - int GpsVCCEn; //GPIO index - int GpsSpi_CSO; //GPIO index - int GpsSpiClk; //GPIO index - int GpsSpiMOSI; //GPIO index - -}; - -#endif diff --git a/drivers/misc/gps/hv5820b/lnxdrv.h b/drivers/misc/gps/hv5820b/lnxdrv.h deleted file mode 100755 index 56c6f026fefd..000000000000 --- a/drivers/misc/gps/hv5820b/lnxdrv.h +++ /dev/null @@ -1,52 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////// -// -// Filename: lnxdrv.h -// Author: sjchen -// Copyright: -// Date: 2012/07/09 -// Description: -// the macor of GPS baseband -// -// Revision: -// 0.0.1 -// -/////////////////////////////////////////////////////////////////////////////////// - -#ifndef __LNXDRV_H__ -#define __LNXDRV_H__ - -/////////////////////////////////////////////////////////////////////////////////// -// -// macro declaration -// -/////////////////////////////////////////////////////////////////////////////////// - -#define MEM_CHECK_BOUNDARY (16) - -//base band control registers offset -#define BB_CTRL_OFFSET 0x0400 -#define BB_START_ADR_OFFSET 0x0404 -#define BB_DS_PAR_OFFSET 0x0408 -#define BB_INT_ENA_OFFSET 0x040c -#define BB_INT_STATUS_OFFSET 0x0410 -#define BB_CHN_STATUS_OFFSET 0x0414 -#define BB_CHN_VALID_OFFSET 0x0418 -#define BB_TIMER_VAL_OFFSET 0x041c -#define BB_RF_WT_ADDR_OFFSET 0x0420 - - - -//the following is bb register bit define -#define BB_RESET 0x4 -#define BB_NXT_BLK 0x2 -#define BB_TRICKLE 0x1 -#define BB_CTRL_CLR 0x0 - -#define TIMEOUT_INT 0x1 -#define ACC_BLK_DONE_INT 0x2 -#define OBUF_RDY_INT 0x4 - -#endif /* __LNXDRV_H__ */ - - - From 6c4535aae9a53558525b2f71e3fbcad2080b4551 Mon Sep 17 00:00:00 2001 From: zyc Date: Sat, 28 Jul 2012 14:57:24 +0800 Subject: [PATCH 048/261] rk2928 camera :add configs in rk2928_fpga_defconfig --- arch/arm/configs/rk2928_fpga_defconfig | 7 + arch/arm/mach-rk2928/board-rk2928-fpga.c | 203 +---------------------- 2 files changed, 9 insertions(+), 201 deletions(-) diff --git a/arch/arm/configs/rk2928_fpga_defconfig b/arch/arm/configs/rk2928_fpga_defconfig index f0c6d3624979..6ce1f5065e53 100644 --- a/arch/arm/configs/rk2928_fpga_defconfig +++ b/arch/arm/configs/rk2928_fpga_defconfig @@ -76,6 +76,13 @@ CONFIG_SPI_FPGA_GPIO_NUM=0 CONFIG_SPI_FPGA_GPIO_IRQ_NUM=0 # CONFIG_HWMON is not set # CONFIG_MFD_SUPPORT is not set +CONFIG_MEDIA_SUPPORT=y +CONFIG_VIDEO_DEV=y +CONFIG_SOC_CAMERA=y +CONFIG_SOC_CAMERA_OV2659=y +CONFIG_SOC_CAMERA_OV5642=y +CONFIG_VIDEO_RK29=y +CONFIG_VIDEO_RK29_CAMMEM_ION=y CONFIG_ION=y CONFIG_ION_ROCKCHIP=y CONFIG_FB=y diff --git a/arch/arm/mach-rk2928/board-rk2928-fpga.c b/arch/arm/mach-rk2928/board-rk2928-fpga.c index 7fd99583b24c..06b0b9f4182c 100755 --- a/arch/arm/mach-rk2928/board-rk2928-fpga.c +++ b/arch/arm/mach-rk2928/board-rk2928-fpga.c @@ -47,8 +47,8 @@ /*---------------- Camera Sensor Macro Define Begin ------------------------*/ /*---------------- Camera Sensor Configuration Macro Begin ------------------------*/ #define CONFIG_SENSOR_0 RK29_CAM_SENSOR_OV5642 /* back camera sensor */ -#define CONFIG_SENSOR_IIC_ADDR_0 0 -#define CONFIG_SENSOR_IIC_ADAPTER_ID_0 4 +#define CONFIG_SENSOR_IIC_ADDR_0 0x78 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_0 1 #define CONFIG_SENSOR_CIF_INDEX_0 0 #define CONFIG_SENSOR_ORIENTATION_0 90 #define CONFIG_SENSOR_POWER_PIN_0 INVALID_GPIO @@ -189,7 +189,6 @@ /*---------------- Camera Sensor Configuration Macro End------------------------*/ #include "../../../drivers/media/video/rk2928_camera.c" /*---------------- Camera Sensor Macro Define End ---------*/ - #define PMEM_CAM_SIZE PMEM_CAM_NECESSARY /***************************************************************************************** * camera devices @@ -491,169 +490,6 @@ static rk_sensor_user_init_data_s rk_init_data_sensor[RK_CAM_NUM] = #include "../../../drivers/media/video/rk2928_camera.c" #endif /* CONFIG_VIDEO_RK29 */ - -/************************************************************************************************** - * SDMMC devices, include the module of SD,MMC,and sdio.noted by xbw at 2012-03-05 -**************************************************************************************************/ -#ifdef CONFIG_SDMMC_RK29 -#include "board-rk2928-sdk-sdmmc.c" - -#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) -#define SDMMC0_WRITE_PROTECT_PIN RK2928_PIN1_PA7 //According to your own project to set the value of write-protect-pin. -#endif - -#if defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT) -#define SDMMC1_WRITE_PROTECT_PIN RK2928_PIN0_PD5 //According to your own project to set the value of write-protect-pin. -#endif - -#define RK29SDK_WIFI_SDIO_CARD_DETECT_N RK2928_PIN0_PB2 - -#endif //endif ---#ifdef CONFIG_SDMMC_RK29 - -#ifdef CONFIG_SDMMC0_RK29 -static int rk29_sdmmc0_cfg_gpio(void) -{ -#ifdef CONFIG_SDMMC_RK29_OLD - rk30_mux_api_set(GPIO1B7_MMC0_CMD_NAME, GPIO1B_MMC0_CMD); - rk30_mux_api_set(GPIO1C0_MMC0_CLKOUT_NAME, GPIO1C_MMC0_CLKOUT); - rk30_mux_api_set(GPIO1C2_MMC0_D0_NAME, GPIO1C_MMC0_D0); - rk30_mux_api_set(GPIO1C3_MMC0_D1_NAME, GPIO1C_MMC0_D1); - rk30_mux_api_set(GPIO1C4_MMC0_D2_NAME, GPIO1C_MMC0_D2); - rk30_mux_api_set(GPIO1C5_MMC0_D3_NAME, GPIO1C_MMC0_D3); - - rk30_mux_api_set(GPIO1C1_MMC0_DETN_NAME, GPIO1C_MMC0_DETN); - - rk30_mux_api_set(GPIO1B6_MMC0_PWREN_NAME, GPIO1B_MMC0_PWREN); - gpio_request(RK30_PIN3_PA7, "sdmmc-power"); - gpio_direction_output(RK2928_PIN1_PB6, GPIO_LOW); - -#else - rk29_sdmmc_set_iomux(0, 0xFFFF); - - rk30_mux_api_set(GPIO1C1_MMC0_DETN_NAME, GPIO1C_MMC0_DETN); - -#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) - gpio_request(SDMMC0_WRITE_PROTECT_PIN, "sdmmc-wp"); - gpio_direction_input(SDMMC0_WRITE_PROTECT_PIN); -#endif - -#endif - - return 0; -} - -#define CONFIG_SDMMC0_USE_DMA -struct rk29_sdmmc_platform_data default_sdmmc0_data = { - .host_ocr_avail = - (MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 | MMC_VDD_28_29 | - MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | - MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36), - .host_caps = - (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), - .io_init = rk29_sdmmc0_cfg_gpio, - -#if !defined(CONFIG_SDMMC_RK29_OLD) - .set_iomux = rk29_sdmmc_set_iomux, -#endif - - .dma_name = "sd_mmc", -#ifdef CONFIG_SDMMC0_USE_DMA - .use_dma = 1, -#else - .use_dma = 0, -#endif - .detect_irq = RK2928_PIN1_PC1, // INVALID_GPIO - .enable_sd_wakeup = 0, - -#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) - .write_prt = SDMMC0_WRITE_PROTECT_PIN, -#else - .write_prt = INVALID_GPIO, -#endif -}; -#endif // CONFIG_SDMMC0_RK29 - -#ifdef CONFIG_SDMMC1_RK29 -#define CONFIG_SDMMC1_USE_DMA -static int rk29_sdmmc1_cfg_gpio(void) -{ -#if defined(CONFIG_SDMMC_RK29_OLD) - rk30_mux_api_set(GPIO0B0_MMC1_CMD_NAME, GPIO0B_MMC1_CMD); - rk30_mux_api_set(GPIO0B1_MMC1_CLKOUT_NAME, GPIO0B_MMC1_CLKOUT); - rk30_mux_api_set(GPIO0B3_MMC1_D0_NAME, GPIO0B_MMC1_D0); - rk30_mux_api_set(GPIO0B4_MMC1_D1_NAME, GPIO0B_MMC1_D1); - rk30_mux_api_set(GPIO0B5_MMC1_D2_NAME, GPIO0B_MMC1_D2); - rk30_mux_api_set(GPIO0B6_MMC1_D3_NAME, GPIO0B_MMC1_D3); - //rk30_mux_api_set(GPIO0B2_MMC1_DETN_NAME, GPIO0B_MMC1_DETN); - -#else - -#if defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT) - gpio_request(SDMMC1_WRITE_PROTECT_PIN, "sdio-wp"); - gpio_direction_input(SDMMC1_WRITE_PROTECT_PIN); -#endif - -#endif - - return 0; -} - -struct rk29_sdmmc_platform_data default_sdmmc1_data = { - .host_ocr_avail = - (MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 | MMC_VDD_28_29 | - MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | - MMC_VDD_33_34), - -#if !defined(CONFIG_USE_SDMMC1_FOR_WIFI_DEVELOP_BOARD) - .host_caps = (MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ | - MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), -#else - .host_caps = - (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), -#endif - - .io_init = rk29_sdmmc1_cfg_gpio, - -#if !defined(CONFIG_SDMMC_RK29_OLD) - .set_iomux = rk29_sdmmc_set_iomux, -#endif - - .dma_name = "sdio", -#ifdef CONFIG_SDMMC1_USE_DMA - .use_dma = 1, -#else - .use_dma = 0, -#endif - -#if !defined(CONFIG_USE_SDMMC1_FOR_WIFI_DEVELOP_BOARD) -#ifdef CONFIG_WIFI_CONTROL_FUNC - .status = rk29sdk_wifi_status, - .register_status_notify = rk29sdk_wifi_status_register, -#endif -#if 0 - .detect_irq = RK29SDK_WIFI_SDIO_CARD_DETECT_N, -#endif - -#if defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT) - .write_prt = SDMMC1_WRITE_PROTECT_PIN, -#else - .write_prt = INVALID_GPIO, -#endif - -#else - .detect_irq = INVALID_GPIO, - .enable_sd_wakeup = 0, -#endif - -}; -#endif //endif--#ifdef CONFIG_SDMMC1_RK29 - -/************************************************************************************************** - * the end of setting for SDMMC devices -**************************************************************************************************/ - - - #define RK2928_FB_MEM_SIZE 3*SZ_1M #ifdef CONFIG_FB_ROCKCHIP @@ -747,33 +583,7 @@ static void __init rk30_i2c_register_board_info(void) static struct spi_board_info board_spi_devices[] = { }; -#ifdef CONFIG_ION -#define ION_RESERVE_SIZE (8 * SZ_1M) -static struct ion_platform_data rk30_ion_pdata = { - .nr = 1, - .heaps = { - { - .type = ION_HEAP_TYPE_CARVEOUT, - .id = ION_NOR_HEAP_ID, - .name = "norheap", - .size = ION_RESERVE_SIZE, - } - }, -}; - -static struct platform_device device_ion = { - .name = "ion-rockchip", - .id = 0, - .dev = { - .platform_data = &rk30_ion_pdata, - }, -}; -#endif - static struct platform_device *devices[] __initdata = { -#ifdef CONFIG_ION - &device_ion, -#endif #ifdef CONFIG_FB_ROCKCHIP &device_fb, #endif @@ -788,9 +598,6 @@ static void __init rk2928_board_init(void) static void __init rk2928_reserve(void) { -#ifdef CONFIG_ION - rk30_ion_pdata.heaps[0].base = board_mem_reserve_add("ion", ION_RESERVE_SIZE); -#endif #ifdef CONFIG_FB_ROCKCHIP resource_fb[0].start = board_mem_reserve_add("fb0", RK2928_FB_MEM_SIZE); resource_fb[0].end = resource_fb[0].start + RK2928_FB_MEM_SIZE - 1; @@ -846,12 +653,6 @@ static struct clk_lookup clks[] = { CLK(NULL, "hclk_lcdc0", &xin24m), CLK(NULL, "aclk_lcdc0", &xin24m), CLK(NULL, "dclk_lcdc0", &xin24m), - - CLK(NULL, "pd_cif0", &xin24m), - CLK(NULL, "aclk_cif0", &xin24m), - CLK(NULL, "hclk_cif0", &xin24m), - CLK(NULL, "cif0_in", &xin24m), - CLK(NULL, "cif0_out", &xin24m), }; void __init rk30_clock_init(void) From 0da78e5a321c5371768a2a133098e1f1dbc982c1 Mon Sep 17 00:00:00 2001 From: zyc Date: Sat, 28 Jul 2012 15:28:33 +0800 Subject: [PATCH 049/261] Revert "rk2928 camera :add configs in rk2928_fpga_defconfig" This reverts commit 6c4535aae9a53558525b2f71e3fbcad2080b4551. --- arch/arm/configs/rk2928_fpga_defconfig | 7 - arch/arm/mach-rk2928/board-rk2928-fpga.c | 203 ++++++++++++++++++++++- 2 files changed, 201 insertions(+), 9 deletions(-) diff --git a/arch/arm/configs/rk2928_fpga_defconfig b/arch/arm/configs/rk2928_fpga_defconfig index 6ce1f5065e53..f0c6d3624979 100644 --- a/arch/arm/configs/rk2928_fpga_defconfig +++ b/arch/arm/configs/rk2928_fpga_defconfig @@ -76,13 +76,6 @@ CONFIG_SPI_FPGA_GPIO_NUM=0 CONFIG_SPI_FPGA_GPIO_IRQ_NUM=0 # CONFIG_HWMON is not set # CONFIG_MFD_SUPPORT is not set -CONFIG_MEDIA_SUPPORT=y -CONFIG_VIDEO_DEV=y -CONFIG_SOC_CAMERA=y -CONFIG_SOC_CAMERA_OV2659=y -CONFIG_SOC_CAMERA_OV5642=y -CONFIG_VIDEO_RK29=y -CONFIG_VIDEO_RK29_CAMMEM_ION=y CONFIG_ION=y CONFIG_ION_ROCKCHIP=y CONFIG_FB=y diff --git a/arch/arm/mach-rk2928/board-rk2928-fpga.c b/arch/arm/mach-rk2928/board-rk2928-fpga.c index 06b0b9f4182c..7fd99583b24c 100755 --- a/arch/arm/mach-rk2928/board-rk2928-fpga.c +++ b/arch/arm/mach-rk2928/board-rk2928-fpga.c @@ -47,8 +47,8 @@ /*---------------- Camera Sensor Macro Define Begin ------------------------*/ /*---------------- Camera Sensor Configuration Macro Begin ------------------------*/ #define CONFIG_SENSOR_0 RK29_CAM_SENSOR_OV5642 /* back camera sensor */ -#define CONFIG_SENSOR_IIC_ADDR_0 0x78 -#define CONFIG_SENSOR_IIC_ADAPTER_ID_0 1 +#define CONFIG_SENSOR_IIC_ADDR_0 0 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_0 4 #define CONFIG_SENSOR_CIF_INDEX_0 0 #define CONFIG_SENSOR_ORIENTATION_0 90 #define CONFIG_SENSOR_POWER_PIN_0 INVALID_GPIO @@ -189,6 +189,7 @@ /*---------------- Camera Sensor Configuration Macro End------------------------*/ #include "../../../drivers/media/video/rk2928_camera.c" /*---------------- Camera Sensor Macro Define End ---------*/ + #define PMEM_CAM_SIZE PMEM_CAM_NECESSARY /***************************************************************************************** * camera devices @@ -490,6 +491,169 @@ static rk_sensor_user_init_data_s rk_init_data_sensor[RK_CAM_NUM] = #include "../../../drivers/media/video/rk2928_camera.c" #endif /* CONFIG_VIDEO_RK29 */ + +/************************************************************************************************** + * SDMMC devices, include the module of SD,MMC,and sdio.noted by xbw at 2012-03-05 +**************************************************************************************************/ +#ifdef CONFIG_SDMMC_RK29 +#include "board-rk2928-sdk-sdmmc.c" + +#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) +#define SDMMC0_WRITE_PROTECT_PIN RK2928_PIN1_PA7 //According to your own project to set the value of write-protect-pin. +#endif + +#if defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT) +#define SDMMC1_WRITE_PROTECT_PIN RK2928_PIN0_PD5 //According to your own project to set the value of write-protect-pin. +#endif + +#define RK29SDK_WIFI_SDIO_CARD_DETECT_N RK2928_PIN0_PB2 + +#endif //endif ---#ifdef CONFIG_SDMMC_RK29 + +#ifdef CONFIG_SDMMC0_RK29 +static int rk29_sdmmc0_cfg_gpio(void) +{ +#ifdef CONFIG_SDMMC_RK29_OLD + rk30_mux_api_set(GPIO1B7_MMC0_CMD_NAME, GPIO1B_MMC0_CMD); + rk30_mux_api_set(GPIO1C0_MMC0_CLKOUT_NAME, GPIO1C_MMC0_CLKOUT); + rk30_mux_api_set(GPIO1C2_MMC0_D0_NAME, GPIO1C_MMC0_D0); + rk30_mux_api_set(GPIO1C3_MMC0_D1_NAME, GPIO1C_MMC0_D1); + rk30_mux_api_set(GPIO1C4_MMC0_D2_NAME, GPIO1C_MMC0_D2); + rk30_mux_api_set(GPIO1C5_MMC0_D3_NAME, GPIO1C_MMC0_D3); + + rk30_mux_api_set(GPIO1C1_MMC0_DETN_NAME, GPIO1C_MMC0_DETN); + + rk30_mux_api_set(GPIO1B6_MMC0_PWREN_NAME, GPIO1B_MMC0_PWREN); + gpio_request(RK30_PIN3_PA7, "sdmmc-power"); + gpio_direction_output(RK2928_PIN1_PB6, GPIO_LOW); + +#else + rk29_sdmmc_set_iomux(0, 0xFFFF); + + rk30_mux_api_set(GPIO1C1_MMC0_DETN_NAME, GPIO1C_MMC0_DETN); + +#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) + gpio_request(SDMMC0_WRITE_PROTECT_PIN, "sdmmc-wp"); + gpio_direction_input(SDMMC0_WRITE_PROTECT_PIN); +#endif + +#endif + + return 0; +} + +#define CONFIG_SDMMC0_USE_DMA +struct rk29_sdmmc_platform_data default_sdmmc0_data = { + .host_ocr_avail = + (MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 | MMC_VDD_28_29 | + MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | + MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36), + .host_caps = + (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), + .io_init = rk29_sdmmc0_cfg_gpio, + +#if !defined(CONFIG_SDMMC_RK29_OLD) + .set_iomux = rk29_sdmmc_set_iomux, +#endif + + .dma_name = "sd_mmc", +#ifdef CONFIG_SDMMC0_USE_DMA + .use_dma = 1, +#else + .use_dma = 0, +#endif + .detect_irq = RK2928_PIN1_PC1, // INVALID_GPIO + .enable_sd_wakeup = 0, + +#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) + .write_prt = SDMMC0_WRITE_PROTECT_PIN, +#else + .write_prt = INVALID_GPIO, +#endif +}; +#endif // CONFIG_SDMMC0_RK29 + +#ifdef CONFIG_SDMMC1_RK29 +#define CONFIG_SDMMC1_USE_DMA +static int rk29_sdmmc1_cfg_gpio(void) +{ +#if defined(CONFIG_SDMMC_RK29_OLD) + rk30_mux_api_set(GPIO0B0_MMC1_CMD_NAME, GPIO0B_MMC1_CMD); + rk30_mux_api_set(GPIO0B1_MMC1_CLKOUT_NAME, GPIO0B_MMC1_CLKOUT); + rk30_mux_api_set(GPIO0B3_MMC1_D0_NAME, GPIO0B_MMC1_D0); + rk30_mux_api_set(GPIO0B4_MMC1_D1_NAME, GPIO0B_MMC1_D1); + rk30_mux_api_set(GPIO0B5_MMC1_D2_NAME, GPIO0B_MMC1_D2); + rk30_mux_api_set(GPIO0B6_MMC1_D3_NAME, GPIO0B_MMC1_D3); + //rk30_mux_api_set(GPIO0B2_MMC1_DETN_NAME, GPIO0B_MMC1_DETN); + +#else + +#if defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT) + gpio_request(SDMMC1_WRITE_PROTECT_PIN, "sdio-wp"); + gpio_direction_input(SDMMC1_WRITE_PROTECT_PIN); +#endif + +#endif + + return 0; +} + +struct rk29_sdmmc_platform_data default_sdmmc1_data = { + .host_ocr_avail = + (MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 | MMC_VDD_28_29 | + MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | + MMC_VDD_33_34), + +#if !defined(CONFIG_USE_SDMMC1_FOR_WIFI_DEVELOP_BOARD) + .host_caps = (MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ | + MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), +#else + .host_caps = + (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), +#endif + + .io_init = rk29_sdmmc1_cfg_gpio, + +#if !defined(CONFIG_SDMMC_RK29_OLD) + .set_iomux = rk29_sdmmc_set_iomux, +#endif + + .dma_name = "sdio", +#ifdef CONFIG_SDMMC1_USE_DMA + .use_dma = 1, +#else + .use_dma = 0, +#endif + +#if !defined(CONFIG_USE_SDMMC1_FOR_WIFI_DEVELOP_BOARD) +#ifdef CONFIG_WIFI_CONTROL_FUNC + .status = rk29sdk_wifi_status, + .register_status_notify = rk29sdk_wifi_status_register, +#endif +#if 0 + .detect_irq = RK29SDK_WIFI_SDIO_CARD_DETECT_N, +#endif + +#if defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT) + .write_prt = SDMMC1_WRITE_PROTECT_PIN, +#else + .write_prt = INVALID_GPIO, +#endif + +#else + .detect_irq = INVALID_GPIO, + .enable_sd_wakeup = 0, +#endif + +}; +#endif //endif--#ifdef CONFIG_SDMMC1_RK29 + +/************************************************************************************************** + * the end of setting for SDMMC devices +**************************************************************************************************/ + + + #define RK2928_FB_MEM_SIZE 3*SZ_1M #ifdef CONFIG_FB_ROCKCHIP @@ -583,7 +747,33 @@ static void __init rk30_i2c_register_board_info(void) static struct spi_board_info board_spi_devices[] = { }; +#ifdef CONFIG_ION +#define ION_RESERVE_SIZE (8 * SZ_1M) +static struct ion_platform_data rk30_ion_pdata = { + .nr = 1, + .heaps = { + { + .type = ION_HEAP_TYPE_CARVEOUT, + .id = ION_NOR_HEAP_ID, + .name = "norheap", + .size = ION_RESERVE_SIZE, + } + }, +}; + +static struct platform_device device_ion = { + .name = "ion-rockchip", + .id = 0, + .dev = { + .platform_data = &rk30_ion_pdata, + }, +}; +#endif + static struct platform_device *devices[] __initdata = { +#ifdef CONFIG_ION + &device_ion, +#endif #ifdef CONFIG_FB_ROCKCHIP &device_fb, #endif @@ -598,6 +788,9 @@ static void __init rk2928_board_init(void) static void __init rk2928_reserve(void) { +#ifdef CONFIG_ION + rk30_ion_pdata.heaps[0].base = board_mem_reserve_add("ion", ION_RESERVE_SIZE); +#endif #ifdef CONFIG_FB_ROCKCHIP resource_fb[0].start = board_mem_reserve_add("fb0", RK2928_FB_MEM_SIZE); resource_fb[0].end = resource_fb[0].start + RK2928_FB_MEM_SIZE - 1; @@ -653,6 +846,12 @@ static struct clk_lookup clks[] = { CLK(NULL, "hclk_lcdc0", &xin24m), CLK(NULL, "aclk_lcdc0", &xin24m), CLK(NULL, "dclk_lcdc0", &xin24m), + + CLK(NULL, "pd_cif0", &xin24m), + CLK(NULL, "aclk_cif0", &xin24m), + CLK(NULL, "hclk_cif0", &xin24m), + CLK(NULL, "cif0_in", &xin24m), + CLK(NULL, "cif0_out", &xin24m), }; void __init rk30_clock_init(void) From 5404401969f10a210c7e012e211a8b319d879ed3 Mon Sep 17 00:00:00 2001 From: zyc Date: Sat, 28 Jul 2012 15:34:34 +0800 Subject: [PATCH 050/261] rk2928 camera : revert and recommit rk2928_fpga_defconfig. --- arch/arm/configs/rk2928_fpga_defconfig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/configs/rk2928_fpga_defconfig b/arch/arm/configs/rk2928_fpga_defconfig index f0c6d3624979..6ce1f5065e53 100644 --- a/arch/arm/configs/rk2928_fpga_defconfig +++ b/arch/arm/configs/rk2928_fpga_defconfig @@ -76,6 +76,13 @@ CONFIG_SPI_FPGA_GPIO_NUM=0 CONFIG_SPI_FPGA_GPIO_IRQ_NUM=0 # CONFIG_HWMON is not set # CONFIG_MFD_SUPPORT is not set +CONFIG_MEDIA_SUPPORT=y +CONFIG_VIDEO_DEV=y +CONFIG_SOC_CAMERA=y +CONFIG_SOC_CAMERA_OV2659=y +CONFIG_SOC_CAMERA_OV5642=y +CONFIG_VIDEO_RK29=y +CONFIG_VIDEO_RK29_CAMMEM_ION=y CONFIG_ION=y CONFIG_ION_ROCKCHIP=y CONFIG_FB=y From 07dd9223d97c9f9f384429cfef404085b8c4f5d5 Mon Sep 17 00:00:00 2001 From: wlf Date: Mon, 30 Jul 2012 11:28:35 +0800 Subject: [PATCH 051/261] RK2928 usb hcd modified --- arch/arm/mach-rk2928/devices.c | 51 +++++++++ drivers/usb/dwc_otg/dwc_otg_cil.c | 4 +- drivers/usb/dwc_otg/dwc_otg_driver.c | 126 +++++++++++++++++++++-- drivers/usb/dwc_otg/dwc_otg_hcd.c | 48 ++++++++- drivers/usb/dwc_otg/dwc_otg_pcd.c | 19 +++- drivers/usb/dwc_otg/linux/dwc_otg_plat.h | 9 ++ 6 files changed, 243 insertions(+), 14 deletions(-) diff --git a/arch/arm/mach-rk2928/devices.c b/arch/arm/mach-rk2928/devices.c index 5c670f4330df..eca32631660f 100755 --- a/arch/arm/mach-rk2928/devices.c +++ b/arch/arm/mach-rk2928/devices.c @@ -621,6 +621,51 @@ static struct platform_device device_keys = { }; #endif +#ifdef CONFIG_USB20_OTG +/*DWC_OTG*/ +static struct resource usb20_otg_resource[] = { + { + .start = IRQ_USB_OTG, + .end = IRQ_USB_OTG, + .flags = IORESOURCE_IRQ, + }, + { + .start = RK2928_USBOTG20_PHYS, + .end = RK2928_USBOTG20_PHYS + RK2928_USBOTG20_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + +}; + +struct platform_device device_usb20_otg = { + .name = "usb20_otg", + .id = -1, + .num_resources = ARRAY_SIZE(usb20_otg_resource), + .resource = usb20_otg_resource, +}; +#endif +#ifdef CONFIG_USB20_HOST +static struct resource usb20_host_resource[] = { + { + .start = IRQ_USB_HOST, + .end = IRQ_USB_HOST, + .flags = IORESOURCE_IRQ, + }, + { + .start = RK2928_USBHOST20_PHYS, + .end = RK2928_USBHOST20_PHYS + RK2928_USBHOST20_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + +}; + +struct platform_device device_usb20_host = { + .name = "usb20_host", + .id = -1, + .num_resources = ARRAY_SIZE(usb20_host_resource), + .resource = usb20_host_resource, +}; +#endif #ifdef CONFIG_SDMMC0_RK29 static struct resource resources_sdmmc0[] = { { @@ -711,6 +756,12 @@ static int __init rk2928_init_devices(void) #endif #ifdef CONFIG_LCDC_RK2928 platform_device_register(&device_lcdc); +#endif +#ifdef CONFIG_USB20_OTG + platform_device_register(&device_usb20_otg); +#endif +#ifdef CONFIG_USB20_HOST + platform_device_register(&device_usb20_host); #endif rk2928_init_sdmmc(); #if defined(CONFIG_FIQ_DEBUGGER) && defined(DEBUG_UART_PHYS) diff --git a/drivers/usb/dwc_otg/dwc_otg_cil.c b/drivers/usb/dwc_otg/dwc_otg_cil.c index ec4f27fb9981..9f44adc2796f 100755 --- a/drivers/usb/dwc_otg/dwc_otg_cil.c +++ b/drivers/usb/dwc_otg/dwc_otg_cil.c @@ -729,8 +729,8 @@ void dwc_otg_core_dev_init(dwc_otg_core_if_t *_core_if) dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[0], 0x01000130 ); //ep1 tx fifo dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[1], 0x00800230 ); //ep3 tx fifo dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[2], 0x008002b0 ); //ep5 tx fifo - dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[2], 0x00800330 ); //ep7 tx fifo - dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[2], 0x001003b0 ); //ep9 tx fifo + dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[3], 0x00800330 ); //ep7 tx fifo + dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[4], 0x001003b0 ); //ep9 tx fifo #endif if(_core_if->en_multiple_tx_fifo && _core_if->dma_enable) { diff --git a/drivers/usb/dwc_otg/dwc_otg_driver.c b/drivers/usb/dwc_otg/dwc_otg_driver.c index 34af78a3a4dd..84c360d55af3 100755 --- a/drivers/usb/dwc_otg/dwc_otg_driver.c +++ b/drivers/usb/dwc_otg/dwc_otg_driver.c @@ -1203,6 +1203,9 @@ static __devinit int dwc_otg_driver_probe(struct platform_device *pdev) #ifdef CONFIG_ARCH_RK30 unsigned int * otg_phy_con = (unsigned int*)(USBGRF_UOC0_CON2); #endif +#ifdef CONFIG_ARCH_RK2928 + unsigned int * otg_phy_con = (unsigned int*)(USBGRF_UOC0_CON5); +#endif #ifdef CONFIG_ARCH_RK29 regval = * otg_phy_con1; @@ -1254,8 +1257,8 @@ static __devinit int dwc_otg_driver_probe(struct platform_device *pdev) } clk_enable(ahbclk); - regval &= ~(0x01<<14); // exit suspend. - regval |= (0x01<<13); // software control + regval &= ~(0x01<<14); // enter suspend. + regval |= (0x01<<13); // software control enable. *otg_phy_con1 = regval; udelay(3); @@ -1291,6 +1294,34 @@ static __devinit int dwc_otg_driver_probe(struct platform_device *pdev) clk_disable(phyclk); clk_disable(ahbclk); #endif +#endif +#ifdef CONFIG_ARCH_RK2928 +#ifndef CONFIG_USB20_HOST + otg_phy_con = (unsigned int*)(USBGRF_UOC1_CON5); + /* + * disable usb host 2.0 phy if not support + */ + phyclk = clk_get(NULL, "otgphy1"); + if (IS_ERR(phyclk)) { + retval = PTR_ERR(phyclk); + DWC_ERROR("can't get USBPHY1 clock\n"); + goto fail; + } + clk_enable(phyclk); + + ahbclk = clk_get(NULL, "hclk_otg1"); + if (IS_ERR(ahbclk)) { + retval = PTR_ERR(ahbclk); + DWC_ERROR("can't get USBOTG1 ahb bus clock\n"); + goto fail; + } + clk_enable(ahbclk); + + *otg_phy_con = ((0x01<<0)|(0x00<<1)|(0x05<<4))|(((0x01<<0)|(0x01<<1)|(0x07<<4))<<16); // enter suspend. + udelay(3); + clk_disable(phyclk); + clk_disable(ahbclk); +#endif #endif dwc_otg_device = kmalloc(sizeof(dwc_otg_device_t), GFP_KERNEL); @@ -1385,6 +1416,41 @@ static __devinit int dwc_otg_driver_probe(struct platform_device *pdev) dwc_otg_device->phyclk = phyclk; dwc_otg_device->ahbclk = ahbclk; #endif +#ifdef CONFIG_ARCH_RK2928 + otg_phy_con = (unsigned int*)(USBGRF_UOC0_CON5); + cru_set_soft_reset(SOFT_RST_USBPHY0, true); + cru_set_soft_reset(SOFT_RST_OTGC0, true); + cru_set_soft_reset(SOFT_RST_USBOTG0, true); + udelay(1); + + cru_set_soft_reset(SOFT_RST_USBOTG0, false); + cru_set_soft_reset(SOFT_RST_OTGC0, false); + cru_set_soft_reset(SOFT_RST_USBPHY0, false); + + phyclk = clk_get(NULL, "otgphy0"); + if (IS_ERR(phyclk)) { + retval = PTR_ERR(phyclk); + DWC_ERROR("can't get USBPHY0 clock\n"); + goto fail; + } + clk_enable(phyclk); + + ahbclk = clk_get(NULL, "hclk_otg0"); + if (IS_ERR(ahbclk)) { + retval = PTR_ERR(ahbclk); + DWC_ERROR("can't get USB otg0 ahb bus clock\n"); + goto fail; + } + clk_enable(ahbclk); + + /* + * Enable usb phy 0 + */ + *otg_phy_con = (0x01<<16); + + dwc_otg_device->phyclk = phyclk; + dwc_otg_device->ahbclk = ahbclk; +#endif /* * Map the DWC_otg Core memory into virtual address space. */ @@ -1498,6 +1564,9 @@ static __devinit int dwc_otg_driver_probe(struct platform_device *pdev) dwc_otg_device->core_if->usb_mode = USB_MODE_FORCE_HOST; #else dwc_otg_device->core_if->usb_mode = USB_MODE_NORMAL; +#ifdef CONFIG_DWC_OTG_DEFAULT_DEVICE + dwc_otg_device->core_if->usb_mode = USB_MODE_FORCE_DEVICE; +#endif #endif #endif @@ -1516,6 +1585,9 @@ static __devinit int dwc_otg_driver_probe(struct platform_device *pdev) #endif #ifdef CONFIG_ARCH_RK30 USB_IOMUX_INIT(GPIO0A5_OTGDRVVBUS_NAME, GPIO0A_OTG_DRV_VBUS); +#endif +#ifdef CONFIG_ARCH_RK2928 + USB_IOMUX_INIT(GPIO3C1_OTG_DRVVBUS_NAME, GPIO3C_OTG_DRVVBUS); #endif /* * Initialize the HCD @@ -1557,6 +1629,26 @@ static __devinit int dwc_otg_driver_probe(struct platform_device *pdev) *otg_phy_con1 &= ~(0x01<<3); // enter suspend. } #endif +#endif +#ifdef CONFIG_ARCH_RK30 +#ifndef CONFIG_DWC_OTG_DEVICE_ONLY + if(dwc_otg_device->hcd->host_enabled == 0) + { + clk_disable(dwc_otg_device->phyclk); + clk_disable(dwc_otg_device->ahbclk); + *otg_phy_con = ((0x01<<2)|(0x00<<3)|(0x05<<6))|(((0x01<<2)|(0x01<<3)|(0x07<<6))<<16); // enter suspend. + } +#endif +#endif +#ifdef CONFIG_ARCH_RK2928 +#ifndef CONFIG_DWC_OTG_DEVICE_ONLY + if(dwc_otg_device->hcd->host_enabled == 0) + { + clk_disable(dwc_otg_device->phyclk); + clk_disable(dwc_otg_device->ahbclk); + *otg_phy_con = ((0x01<<0)|(0x00<<1)|(0x05<<4))|(((0x01<<0)|(0x01<<1)|(0x07<<4))<<16); // enter suspend. + } +#endif #endif return 0; fail: @@ -2044,16 +2136,20 @@ static __devinit int host20_driver_probe(struct platform_device *pdev) */ #ifdef CONFIG_ARCH_RK29 unsigned int * otg_phy_con1 = (unsigned int*)(USB_GRF_CON); + otgreg = * otg_phy_con1; + otgreg |= (0x01<<13); // software control enable + otgreg |= (0x01<<14); // exit suspend. + otgreg &= ~(0x01<<13); // software control disable + *otg_phy_con1 = otgreg; #endif #ifdef CONFIG_ARCH_RK30 unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC1_CON2); + *otg_phy_con1 = ((0x01<<2)<<16); // exit suspend. +#endif +#ifdef CONFIG_ARCH_RK2928 + unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC1_CON5); + *otg_phy_con1 = (0x01<<16); // exit suspend. #endif - - otgreg = * otg_phy_con1; - otgreg |= (0x01<<13); // software control - otgreg |= (0x01<<14); // exit suspend. - otgreg &= ~(0x01<<13); // software control - *otg_phy_con1 = otgreg; #if 0 *otg_phy_con1 |= (0x01<<2); *otg_phy_con1 |= (0x01<<3); // exit suspend. @@ -2080,6 +2176,9 @@ static __devinit int host20_driver_probe(struct platform_device *pdev) #ifdef CONFIG_ARCH_RK30 *(unsigned int*)(USBGRF_UOC1_CON2+4) = ((1<<5)|((1<<5)<<16)); #endif +#ifdef CONFIG_ARCH_RK2928 + *(unsigned int*)(USBGRF_UOC1_CON5-4) = ((1<<5)|((1<<5)<<16)); +#endif if (dwc_otg_device == 0) { dev_err(dev, "kmalloc of dwc_otg_device failed\n"); @@ -2104,6 +2203,9 @@ static __devinit int host20_driver_probe(struct platform_device *pdev) #ifdef CONFIG_ARCH_RK30 ahbclk = clk_get(NULL, "hclk_otg1"); #endif +#ifdef CONFIG_ARCH_RK2928 + ahbclk = clk_get(NULL, "hclk_otg1"); //check +#endif if (IS_ERR(ahbclk)) { retval = PTR_ERR(ahbclk); DWC_ERROR("can't get USBOTG1 ahb bus clock\n"); @@ -2242,9 +2344,15 @@ static __devinit int host20_driver_probe(struct platform_device *pdev) #ifndef CONFIG_USB20_HOST_EN clk_disable(phyclk); clk_disable(ahbclk); +#if defined(CONFIG_ARCH_RK29) otgreg &= ~(0x01<<14); // suspend. - otgreg |= (0x01<<13); // software control + otgreg |= (0x01<<13); // software control enable *otg_phy_con1 = otgreg; +#elif defined(CONFIG_ARCH_RK30) + *otg_phy_con1 = ((0x01<<2)|(0x00<<3)|(0x05<<6))|(((0x01<<2)|(0x01<<3)|(0x07<<6))<<16); // enter suspend. +#elif defined(CONFIG_ARCH_RK2928) + *otg_phy_con1 = ((0x01<<0)|(0x00<<1)|(0x05<<4))|(((0x01<<0)|(0x01<<1)|(0x07<<4))<<16); // enter suspend. +#endif #endif return 0; diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd.c b/drivers/usb/dwc_otg/dwc_otg_hcd.c index e85ada78ead6..4c84033c2a59 100755 --- a/drivers/usb/dwc_otg/dwc_otg_hcd.c +++ b/drivers/usb/dwc_otg/dwc_otg_hcd.c @@ -617,6 +617,24 @@ static int32_t dwc_otg_phy_suspend_cb( void *_p, int suspend) udelay(3); DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n"); } +#endif +#ifdef CONFIG_ARCH_RK2928 + unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC0_CON5); + if(exitsuspend && (pcd->phy_suspend == 1)) { + clk_enable(pcd->otg_dev->ahbclk); + clk_enable(pcd->otg_dev->phyclk); + pcd->phy_suspend = 0; + *otg_phy_con1 = (0x01<<16); // exit suspend. + DWC_DEBUGPL(DBG_PCDV, "enable usb phy\n"); + } + if( !exitsuspend && (pcd->phy_suspend == 0)) { + pcd->phy_suspend = 1; + *otg_phy_con1 = 0x55 |(0x7f<<16); // enter suspend. + udelay(3); + clk_disable(pcd->otg_dev->phyclk); + clk_disable(pcd->otg_dev->ahbclk); + DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n"); + } #endif return suspend; } @@ -663,7 +681,7 @@ static struct tasklet_struct reset_tasklet = { .func = reset_tasklet_func, .data = 0, }; -#ifdef CONFIG_ARCH_RK30 +#if defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK2928) static void dwc_otg_hcd_enable(struct work_struct *work) { dwc_otg_hcd_t *dwc_otg_hcd; @@ -721,7 +739,11 @@ static void dwc_otg_hcd_connect_detect(unsigned long pdata) local_irq_save(flags); // DWC_PRINT("%s hprt %x, grfstatus 0x%x\n", __func__, dwc_read_reg32(core_if->host_if->hprt0), usbgrf_status& (7<<22)); +#ifdef CONFIG_ARCH_RK30 if(usbgrf_status & (7<<22)){ +#else //CONFIG_ARCH_RK2928 + if(usbgrf_status & (7<<12)){ +#endif // usb device connected dwc_otg_hcd->host_setenable = 1; } @@ -732,7 +754,11 @@ static void dwc_otg_hcd_connect_detect(unsigned long pdata) } if(dwc_otg_hcd->host_setenable != dwc_otg_hcd->host_enabled){ +#ifdef CONFIG_ARCH_RK30 DWC_PRINT("%s schedule delaywork \n", __func__, dwc_read_reg32(core_if->host_if->hprt0), usbgrf_status& (7<<22)); +#else //CONFIG_ARCH_RK2928 + DWC_PRINT("%s schedule delaywork \n", __func__, dwc_read_reg32(core_if->host_if->hprt0), usbgrf_status& (7<<12)); +#endif schedule_delayed_work(&dwc_otg_hcd->host_enable_work, 8); } // dwc_otg_hcd->connect_detect_timer.expires = jiffies + (HZ<<1); /* 1 s */ @@ -1116,6 +1142,24 @@ static int32_t host20_phy_suspend_cb( void *_p, int suspend) udelay(3); DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n"); } +#endif +#ifdef CONFIG_ARCH_RK2928 + unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC0_CON5); + if(exitsuspend && (pcd->phy_suspend == 1)) { + clk_enable(pcd->otg_dev->ahbclk); + clk_enable(pcd->otg_dev->phyclk); + pcd->phy_suspend = 0; + *otg_phy_con1 = (0x01<<16); // exit suspend. + DWC_DEBUGPL(DBG_PCDV, "enable usb phy\n"); + } + if( !exitsuspend && (pcd->phy_suspend == 0)) { + pcd->phy_suspend = 1; + *otg_phy_con1 = 0x55 |(0x7f<<16); // enter suspend. + udelay(3); + clk_disable(pcd->otg_dev->phyclk); + clk_disable(pcd->otg_dev->ahbclk); + DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n"); + } #endif return suspend; } @@ -1266,7 +1310,7 @@ int __devinit host20_hcd_init(struct device *dev) goto error3; } -#ifdef CONFIG_ARCH_RK30 +#if defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK2928) dwc_otg_hcd->connect_detect_timer.function = dwc_otg_hcd_connect_detect; dwc_otg_hcd->connect_detect_timer.data = (unsigned long)(dwc_otg_hcd); init_timer( &dwc_otg_hcd->connect_detect_timer); diff --git a/drivers/usb/dwc_otg/dwc_otg_pcd.c b/drivers/usb/dwc_otg/dwc_otg_pcd.c index c89715f0e4dc..35729af45d88 100755 --- a/drivers/usb/dwc_otg/dwc_otg_pcd.c +++ b/drivers/usb/dwc_otg/dwc_otg_pcd.c @@ -1657,7 +1657,24 @@ int dwc_otg20phy_suspend( int exitsuspend ) DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n"); } #endif - +#ifdef CONFIG_ARCH_RK2928 + unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC0_CON5); + if(exitsuspend && (pcd->phy_suspend == 1)) { + clk_enable(pcd->otg_dev->ahbclk); + clk_enable(pcd->otg_dev->phyclk); + pcd->phy_suspend = 0; + *otg_phy_con1 = (0x01<<16); // exit suspend. + DWC_DEBUGPL(DBG_PCDV, "enable usb phy\n"); + } + if( !exitsuspend && (pcd->phy_suspend == 0)) { + pcd->phy_suspend = 1; + *otg_phy_con1 = 0x55 |(0x7f<<16); // enter suspend. + udelay(3); + clk_disable(pcd->otg_dev->phyclk); + clk_disable(pcd->otg_dev->ahbclk); + DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n"); + } +#endif return pcd->phy_suspend; } diff --git a/drivers/usb/dwc_otg/linux/dwc_otg_plat.h b/drivers/usb/dwc_otg/linux/dwc_otg_plat.h index e3f7d6e99640..1fa1f5c886a6 100755 --- a/drivers/usb/dwc_otg/linux/dwc_otg_plat.h +++ b/drivers/usb/dwc_otg/linux/dwc_otg_plat.h @@ -67,6 +67,15 @@ #define USB_IOMUX_INIT(a,b) rk30_mux_api_set(a,b) #endif +#ifdef CONFIG_ARCH_RK2928 +#include +#define GRF_REG_BASE RK2928_GRF_BASE +#define USBOTG_SIZE RK2928_USBOTG20_SIZE +#define USBGRF_SOC_STATUS0 (GRF_REG_BASE+0x14c) +#define USBGRF_UOC0_CON5 (GRF_REG_BASE+0x17c) +#define USBGRF_UOC1_CON5 (GRF_REG_BASE+0x194) +#define USB_IOMUX_INIT(a,b) rk30_mux_api_set(a,b) +#endif /** * @file * From 78c5e1c2bec66fd20a1f3cef8db2ffdd2982cc2a Mon Sep 17 00:00:00 2001 From: Zheng Yang Date: Mon, 30 Jul 2012 15:43:22 +0800 Subject: [PATCH 052/261] rk2928: fix audio codec register operation error. --- sound/soc/codecs/rk2928_codec.c | 4 ++-- sound/soc/rk29/rk2928-card.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rk2928_codec.c b/sound/soc/codecs/rk2928_codec.c index 57086b8ec237..e877ae2e6e73 100755 --- a/sound/soc/codecs/rk2928_codec.c +++ b/sound/soc/codecs/rk2928_codec.c @@ -79,13 +79,13 @@ void codec_set_spk(bool on) static unsigned int rk2928_read(struct snd_soc_codec *codec, unsigned int reg) { - return readl(rk2928_data.regbase + reg); + return readl(rk2928_data.regbase + reg*4); } static int rk2928_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { DBG("%s reg 0x%02x value 0x%02x", __FUNCTION__, reg, value); - writel(value, rk2928_data.regbase + reg); + writel(value, rk2928_data.regbase + reg*4); return 0; } diff --git a/sound/soc/rk29/rk2928-card.c b/sound/soc/rk29/rk2928-card.c index 185d8ea1567d..8d08942bd86d 100755 --- a/sound/soc/rk29/rk2928-card.c +++ b/sound/soc/rk29/rk2928-card.c @@ -110,7 +110,7 @@ static struct snd_soc_dai_link rk2928_dai[] = { .stream_name = "RK2928", .cpu_dai_name = "rk29_i2s.0", .platform_name = "rockchip-audio", - .codec_name = "rk2928-codec.0-0001", + .codec_name = "rk2928-codec", .codec_dai_name = "rk2928-codec", .ops = &rk2928_dai_ops, }, From de3f7c318ec7a893671504b564130db329b8ded3 Mon Sep 17 00:00:00 2001 From: wlf Date: Tue, 31 Jul 2012 10:40:48 +0800 Subject: [PATCH 053/261] RK2928 usb pcd modified --- drivers/usb/dwc_otg/dwc_otg_cil.c | 10 +++ drivers/usb/dwc_otg/dwc_otg_pcd.c | 127 +++++++++++++++++++++++++++++- 2 files changed, 134 insertions(+), 3 deletions(-) diff --git a/drivers/usb/dwc_otg/dwc_otg_cil.c b/drivers/usb/dwc_otg/dwc_otg_cil.c index 9f44adc2796f..406aad103928 100755 --- a/drivers/usb/dwc_otg/dwc_otg_cil.c +++ b/drivers/usb/dwc_otg/dwc_otg_cil.c @@ -731,6 +731,16 @@ void dwc_otg_core_dev_init(dwc_otg_core_if_t *_core_if) dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[2], 0x008002b0 ); //ep5 tx fifo dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[3], 0x00800330 ); //ep7 tx fifo dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[4], 0x001003b0 ); //ep9 tx fifo +#endif +#ifdef CONFIG_ARCH_RK2928 //@lyz the same with RK30 + /* Configure data FIFO sizes, RK30 otg has 0x3cc dwords total */ + dwc_write_reg32( &global_regs->grxfsiz, 0x00000120 ); + dwc_write_reg32( &global_regs->gnptxfsiz, 0x00100120 ); //ep0 tx fifo + dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[0], 0x01000130 ); //ep1 tx fifo 256*4Byte + dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[1], 0x00800230 ); //ep3 tx fifo 128*4Byte + dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[2], 0x008002b0 ); //ep5 tx fifo 128*4Byte + dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[3], 0x00800330 ); //ep7 tx fifo 128*4Byte + dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[4], 0x001003b0 ); //ep9 tx fifo 16*4Byte #endif if(_core_if->en_multiple_tx_fifo && _core_if->dma_enable) { diff --git a/drivers/usb/dwc_otg/dwc_otg_pcd.c b/drivers/usb/dwc_otg/dwc_otg_pcd.c index 35729af45d88..8dd5bce818c5 100755 --- a/drivers/usb/dwc_otg/dwc_otg_pcd.c +++ b/drivers/usb/dwc_otg/dwc_otg_pcd.c @@ -189,7 +189,7 @@ void request_nuke( dwc_otg_pcd_ep_t *_ep ) * This function assigns periodic Tx FIFO to an periodic EP * in shared Tx FIFO mode */ - #ifdef CONFIG_ARCH_RK30 + #if defined(CONFIG_ARCH_RK30)||defined(CONFIG_ARCH_RK2928) //@lyz static uint32_t assign_perio_tx_fifo(dwc_otg_core_if_t *core_if) { uint32_t PerTxMsk = 1; @@ -218,7 +218,7 @@ static void release_perio_tx_fifo(dwc_otg_core_if_t *core_if, uint32_t fifo_num) * This function assigns periodic Tx FIFO to an periodic EP * in Dedicated FIFOs mode */ -#ifdef CONFIG_ARCH_RK30 +#if defined(CONFIG_ARCH_RK30)||defined(CONFIG_ARCH_RK2928) //@lyz static uint32_t assign_tx_fifo(dwc_otg_core_if_t *core_if) { uint32_t TxMsk = 1; @@ -304,7 +304,7 @@ static int dwc_otg_pcd_ep_enable(struct usb_ep *_ep, if(ep->dwc_ep.is_in) { -#ifdef CONFIG_ARCH_RK30 +#if defined(CONFIG_ARCH_RK30)||defined(CONFIG_ARCH_RK2928) //@lyz if(!pcd->otg_dev->core_if->en_multiple_tx_fifo) { ep->dwc_ep.tx_fifo_num = 0; @@ -1492,6 +1492,10 @@ void dwc_otg_pcd_reinit(dwc_otg_pcd_t *_pcd) * EP8&EP9 of rk30 are IN&OUT ep, we use ep8 as OUT EP default */ #ifdef CONFIG_ARCH_RK30 + if(i == 8) + continue; + #endif + #ifdef CONFIG_ARCH_RK2928 //@lyz the same with rk30 if(i == 8) continue; #endif @@ -1553,6 +1557,10 @@ void dwc_otg_pcd_reinit(dwc_otg_pcd_t *_pcd) * EP8&EP9 of rk30 are IN&OUT ep, we use ep9 as IN EP default */ #ifdef CONFIG_ARCH_RK30 + if(i == 9) + continue; + #endif + #ifdef CONFIG_ARCH_RK2928 //@lyz the same with rk30 if(i == 9) continue; #endif @@ -1880,6 +1888,69 @@ static void dwc_otg_pcd_check_vbus_timer( unsigned long pdata ) return; } +#endif +#ifdef CONFIG_ARCH_RK2928 +static void dwc_otg_pcd_check_vbus_timer( unsigned long pdata ) +{ + dwc_otg_pcd_t * _pcd = (dwc_otg_pcd_t *)pdata; + unsigned long flags; + unsigned int usbgrf_status = *(unsigned int*)(USBGRF_SOC_STATUS0);//@lyz USBGRF_SOC_STATUS0结构有变 + + local_irq_save(flags); + _pcd->check_vbus_timer.expires = jiffies + (HZ); /* 1 s */ + if((usbgrf_status &(1<<10)) == 0){ // id low //@lyz SOC_STATUS0[10] represents id_dig + + if( _pcd->phy_suspend) + dwc_otg20phy_suspend( 1 ); + } + else if(usbgrf_status & (1<<7)){ //@lyz SOC_STATUS0[7] represents bvalid + /* if usb not connect before ,then start connect */ + if( _pcd->vbus_status == 0 ) { + DWC_PRINT("********vbus detect*********************************************\n"); + dwc_otg_msc_lock(_pcd); + _pcd->vbus_status = 1; + if(_pcd->conn_en) + goto connect; + else + dwc_otg20phy_suspend( 0 ); + } + else if((_pcd->conn_en)&&(_pcd->conn_status>=0)&&(_pcd->conn_status <3)){ + DWC_PRINT("********soft reconnect******************************************\n"); + goto connect; + } + else if(_pcd->conn_status ==3){ + //*连接不上时释放锁,允许系统进入二级睡眠,yk@rk,20100331*// + dwc_otg_msc_unlock(_pcd); + _pcd->conn_status++; + if((dwc_read_reg32((uint32_t*)((uint8_t *)_pcd->otg_dev->base + DWC_OTG_HOST_PORT_REGS_OFFSET))&0xc00) == 0xc00) + _pcd->vbus_status = 2; + } + }else { + _pcd->vbus_status = 0; + if(_pcd->conn_status) + { + _pcd->conn_status = 0; + dwc_otg_msc_unlock(_pcd); + } + /* every 500 ms open usb phy power and start 1 jiffies timer to get vbus */ + if( _pcd->phy_suspend == 0 ) + /* no vbus detect here , close usb phy */ + dwc_otg20phy_suspend( 0 ); + } + add_timer(&_pcd->check_vbus_timer); + local_irq_restore(flags); + return; + +connect: + if( _pcd->phy_suspend == 1 ) + dwc_otg20phy_suspend( 1 ); + schedule_delayed_work( &_pcd->reconnect , 8 ); /* delay 1 jiffies */ + _pcd->check_vbus_timer.expires = jiffies + (HZ<<1); /* 1 s */ + add_timer(&_pcd->check_vbus_timer); + local_irq_restore(flags); + return; +} + #endif #ifdef CONFIG_ARCH_RK29 /* @@ -1987,6 +2058,56 @@ int dwc_otg_check_dpdm(void) return bus_status; } +EXPORT_SYMBOL(dwc_otg_check_dpdm); +#endif +#ifdef CONFIG_ARCH_RK2928 +int dwc_otg_check_dpdm(void) +{ + static uint8_t * reg_base = 0; + volatile unsigned int * otg_dctl; + volatile unsigned int * otg_gotgctl; + volatile unsigned int * otg_hprt0; + int bus_status = 0; + unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC0_CON5);//@lyz modify UOC0_CON2 to CON5 + + // softreset & clockgate //@lyz modify RK2928_CRU_BASE + *(unsigned int*)(RK2928_CRU_BASE+0x120) = ((7<<5)<<16)|(7<<5); // otg0 phy clkgate + udelay(3); + *(unsigned int*)(RK2928_CRU_BASE+0x120) = ((7<<5)<<16)|(0<<5); // otg0 phy clkgate + dsb(); + *(unsigned int*)(RK2928_CRU_BASE+0xd4) = ((1<<5)<<16); // otg0 phy clkgate + *(unsigned int*)(RK2928_CRU_BASE+0xe4) = ((1<<13)<<16); // otg0 hclk clkgate + *(unsigned int*)(RK2928_CRU_BASE+0xf4) = ((3<<10)<<16); // hclk usb clkgate//@lyz to be check + + // exit phy suspend + *otg_phy_con1 = ((0x01<<0)<<16); // exit suspend.@lyz + + // soft connect + if(reg_base == 0){ + reg_base = ioremap(RK2928_USBOTG20_PHYS,USBOTG_SIZE);//@lyz + if(!reg_base){ + bus_status = -1; + goto out; + } + } + mdelay(105); + printk("regbase %p 0x%x, otg_phy_con%p, 0x%x\n", + reg_base, *(reg_base), otg_phy_con1, *otg_phy_con1); + otg_dctl = (unsigned int * )(reg_base+0x804); + otg_gotgctl = (unsigned int * )(reg_base); + otg_hprt0 = (unsigned int * )(reg_base + DWC_OTG_HOST_PORT_REGS_OFFSET); + if(*otg_gotgctl &(1<<19)){ + bus_status = 1; + *otg_dctl &= ~(0x01<<1);//@lyz exit soft-disconnect mode + mdelay(50); // delay about 10ms + // check dp,dm + if((*otg_hprt0 & 0xc00)==0xc00)//@lyz check hprt[11:10] + bus_status = 2; + } +out: + return bus_status; +} + EXPORT_SYMBOL(dwc_otg_check_dpdm); #endif void dwc_otg_pcd_start_vbus_timer( dwc_otg_pcd_t * _pcd ) From 740949e306133d64f3ea054be27d0e1721eb5ad6 Mon Sep 17 00:00:00 2001 From: yangkai Date: Tue, 31 Jul 2012 16:58:23 +0800 Subject: [PATCH 054/261] pcd disconnect with phy suspend --- drivers/usb/dwc_otg/dwc_otg_pcd.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/usb/dwc_otg/dwc_otg_pcd.c b/drivers/usb/dwc_otg/dwc_otg_pcd.c index 35b8a9e08d67..b6e4d28c4d66 100755 --- a/drivers/usb/dwc_otg/dwc_otg_pcd.c +++ b/drivers/usb/dwc_otg/dwc_otg_pcd.c @@ -1047,6 +1047,7 @@ static int dwc_otg_pcd_pullup(struct usb_gadget *_gadget, int is_on) dctl.d32 = dwc_read_reg32( &core_if->dev_if->dev_global_regs->dctl ); dctl.b.sftdiscon = 1; dwc_write_reg32( &core_if->dev_if->dev_global_regs->dctl, dctl.d32 ); + pcd->conn_status = 3; } return 0; } @@ -1596,6 +1597,7 @@ int dwc_pcd_reset(dwc_otg_pcd_t *pcd) cru_set_soft_reset(SOFT_RST_USB_OTG_2_0_AHB_BUS, false); cru_set_soft_reset(SOFT_RST_USB_OTG_2_0_PHY, false); cru_set_soft_reset(SOFT_RST_USB_OTG_2_0_CONTROLLER, false); + mdelay(1); #endif //rockchip_scu_reset_unit(12); dwc_otg_pcd_reinit( pcd ); @@ -1819,12 +1821,12 @@ static void dwc_otg_pcd_check_vbus_timer( unsigned long pdata ) /* if usb not connect before ,then start connect */ if( _pcd->vbus_status == 0 ) { DWC_PRINT("********vbus detect*********************************************\n"); - dwc_otg_msc_lock(_pcd); _pcd->vbus_status = 1; if(_pcd->conn_en) goto connect; else - dwc_otg20phy_suspend( 0 ); + // not connect, suspend phy + dwc_otg20phy_suspend(0); } else if((_pcd->conn_en)&&(_pcd->conn_status>=0)&&(_pcd->conn_status <3)){ DWC_PRINT("********soft reconnect******************************************\n"); @@ -1836,11 +1838,13 @@ static void dwc_otg_pcd_check_vbus_timer( unsigned long pdata ) _pcd->conn_status++; if((dwc_read_reg32((uint32_t*)((uint8_t *)_pcd->otg_dev->base + DWC_OTG_HOST_PORT_REGS_OFFSET))&0xc00) == 0xc00) _pcd->vbus_status = 2; + + // not connect, suspend phy + dwc_otg20phy_suspend(0); } }else { _pcd->vbus_status = 0; - if(_pcd->conn_status) - { + if(_pcd->conn_status){ _pcd->conn_status = 0; dwc_otg_msc_unlock(_pcd); } @@ -1854,6 +1858,8 @@ static void dwc_otg_pcd_check_vbus_timer( unsigned long pdata ) return; connect: + if(_pcd->conn_status==0) + dwc_otg_msc_lock(_pcd); if( _pcd->phy_suspend == 1 ) dwc_otg20phy_suspend( 1 ); schedule_delayed_work( &_pcd->reconnect , 8 ); /* delay 1 jiffies */ From ea8a2fb3d4dbd2ade67834f25f5110635bb3adc5 Mon Sep 17 00:00:00 2001 From: hxy Date: Tue, 31 Jul 2012 17:34:50 +0800 Subject: [PATCH 055/261] rk31: add rga support --- arch/arm/configs/rk31_fpga_defconfig | 1 + drivers/video/rockchip/rga/Kconfig | 4 +- drivers/video/rockchip/rga/rga.h | 2 + drivers/video/rockchip/rga/rga_drv.c | 95 +++++++++------------------- 4 files changed, 36 insertions(+), 66 deletions(-) diff --git a/arch/arm/configs/rk31_fpga_defconfig b/arch/arm/configs/rk31_fpga_defconfig index 49213e435eae..d6e2dafed4f6 100644 --- a/arch/arm/configs/rk31_fpga_defconfig +++ b/arch/arm/configs/rk31_fpga_defconfig @@ -95,6 +95,7 @@ CONFIG_FB_ROCKCHIP=y CONFIG_LCDC_RK31=y CONFIG_LCDC1_RK31=y # CONFIG_THREE_FB_BUFFER is not set +CONFIG_RGA_RK30=y CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set diff --git a/drivers/video/rockchip/rga/Kconfig b/drivers/video/rockchip/rga/Kconfig index 152e2bd55ef0..305130cac236 100755 --- a/drivers/video/rockchip/rga/Kconfig +++ b/drivers/video/rockchip/rga/Kconfig @@ -1,8 +1,8 @@ menu "RGA" - depends on ARCH_RK30 || ARCH_RK2928 + depends on ARCH_RK30 || ARCH_RK2928 || ARCH_RK31 config RGA_RK30 - tristate "ROCKCHIP RK30 || RK2928 RGA" + tristate "ROCKCHIP RK30 || RK2928 RGA || RK31 RGA " help rk30 rga module. diff --git a/drivers/video/rockchip/rga/rga.h b/drivers/video/rockchip/rga/rga.h index bbf5fa94833d..2623d6dd1e9b 100755 --- a/drivers/video/rockchip/rga/rga.h +++ b/drivers/video/rockchip/rga/rga.h @@ -390,6 +390,8 @@ typedef struct rga_service_info { #define RGA_BASE 0x1010c000 #elif defined(CONFIG_ARCH_RK30) #define RGA_BASE 0x10114000 +#elif defined(CONFIG_ARCH_RK31) +#define RGA_BASE 0x10114000 #endif //General Registers diff --git a/drivers/video/rockchip/rga/rga_drv.c b/drivers/video/rockchip/rga/rga_drv.c index 149769b85c1b..65f17f4e412e 100755 --- a/drivers/video/rockchip/rga/rga_drv.c +++ b/drivers/video/rockchip/rga/rga_drv.c @@ -60,7 +60,7 @@ #define RGA_MAJOR 255 -#if 0 +#if 1 #if CONFIG_ARCH_RK2928 #define RK30_RGA_PHYS 0x1010C000 #define RK30_RGA_SIZE SZ_8K @@ -69,6 +69,10 @@ #define RK30_RGA_PHYS 0x10114000 #define RK30_RGA_SIZE SZ_8K #define RGA_RESET_TIMEOUT 1000 +#elif CONFIG_ARCH_RK31 +#define RK30_RGA_PHYS 0x10114000 +#define RK30_RGA_SIZE SZ_8K +#define RGA_RESET_TIMEOUT 1000 #endif #endif @@ -132,7 +136,7 @@ static inline u32 rga_read(u32 r) return __raw_readl(drvdata->rga_base + r); } -#if defined(CONFIG_ARCH_RK30) +#if defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) static void rga_soft_reset(void) { u32 i; @@ -583,6 +587,8 @@ static void rga_try_set_reg(void) #if defined(CONFIG_ARCH_RK30) rga_soft_reset(); + #elif defined(CONFIG_ARCH_RK31) + rga_soft_reset(); #endif rga_write(0, RGA_MMU_CTRL); @@ -1114,6 +1120,8 @@ static int __devinit rga_drv_probe(struct platform_device *pdev) if (!request_mem_region(RK2928_RGA_PHYS, RK2928_RGA_SIZE, "rga_io")) #elif defined(CONFIG_ARCH_RK30) if (!request_mem_region(RK30_RGA_PHYS, RK30_RGA_SIZE, "rga_io")) + #elif defined(CONFIG_ARCH_RK31) + if (!request_mem_region(RK30_RGA_PHYS, RK30_RGA_SIZE, "rga_io")) #endif { pr_info("failed to reserve rga HW regs\n"); @@ -1124,6 +1132,8 @@ static int __devinit rga_drv_probe(struct platform_device *pdev) data->rga_base = (void*)ioremap_nocache(RK2928_RGA_PHYS, RK2928_RGA_SIZE); #elif defined(CONFIG_ARCH_RK30) data->rga_base = (void*)ioremap_nocache(RK30_RGA_PHYS, RK30_RGA_SIZE); + #elif defined(CONFIG_ARCH_RK31) + data->rga_base = (void*)ioremap_nocache(RK30_RGA_PHYS, RK30_RGA_SIZE); #endif if (data->rga_base == NULL) { @@ -1242,7 +1252,7 @@ static int __init rga_init(void) return ret; } - //rga_test_0(); + // rga_test_0(); INFO("Module initialized.\n"); @@ -1309,10 +1319,10 @@ void rga_test_0(void) src = src_buf; dst = dst_buf; - //memset(src_buf, 0x80, 1920*1080*4); + memset(src_buf, 0xff, 1920*1080*4); - //dmac_flush_range(&src_buf[0], &src_buf[1920*1080]); - //outer_flush_range(virt_to_phys(&src_buf[0]),virt_to_phys(&src_buf[1024*1024])); + dmac_flush_range(&src_buf[0], &src_buf[1920*1080]); + outer_flush_range(virt_to_phys(&src_buf[0]),virt_to_phys(&src_buf[1024*1024])); #if 0 memset(src_buf, 0x80, 800*480*4); @@ -1322,21 +1332,21 @@ void rga_test_0(void) outer_flush_range(virt_to_phys(&dst_buf[0]),virt_to_phys(&dst_buf[800*480])); #endif - req.src.act_w = 1280; - req.src.act_h = 800; + req.src.act_w = 320; + req.src.act_h = 240; - req.src.vir_w = 1280; - req.src.vir_h = 800; + req.src.vir_w = 320; + req.src.vir_h = 240; req.src.yrgb_addr = (uint32_t)virt_to_phys(src); req.src.uv_addr = (uint32_t)virt_to_phys(src); req.src.v_addr = (uint32_t)virt_to_phys(src); req.src.format = 0; - req.dst.act_w = 1280; - req.dst.act_h = 800; + req.dst.act_w = 320; + req.dst.act_h = 240; - req.dst.vir_w = 1280; - req.dst.vir_h = 800; + req.dst.vir_w = 800; + req.dst.vir_h = 480; req.dst.x_offset = 0; req.dst.y_offset = 0; req.dst.yrgb_addr = (uint32_t)virt_to_phys(dst); @@ -1344,58 +1354,15 @@ void rga_test_0(void) //req.dst.format = RK_FORMAT_RGB_565; req.clip.xmin = 0; - req.clip.xmax = 1279; + req.clip.xmax = 799; req.clip.ymin = 0; - req.clip.ymax = 799; + req.clip.ymax = 479; //req.render_mode = color_fill_mode; //req.fg_color = 0x80ffffff; - req.rotate_mode = 1; - req.scale_mode = 2; - - //req.alpha_rop_flag = 0; - //req.alpha_rop_mode = 0x1; - - req.sina = 0; - req.cosa = 65536; - - req.mmu_info.mmu_flag = 0x21; - req.mmu_info.mmu_en = 1; - - rga_blit_sync(&session, &req); - - req.src.act_w = 1280; - req.src.act_h = 800; - - req.src.vir_w = 1280; - req.src.vir_h = 800; - req.src.yrgb_addr = (uint32_t)virt_to_phys(src); - req.src.uv_addr = (uint32_t)virt_to_phys(src); - req.src.v_addr = (uint32_t)virt_to_phys(src); - req.src.format = RK_FORMAT_YCbCr_420_SP; - - req.dst.act_w = 1280; - req.dst.act_h = 800; - - req.dst.vir_w = 1280; - req.dst.vir_h = 800; - req.dst.x_offset = 0; - req.dst.y_offset = 0; - req.dst.yrgb_addr = (uint32_t)virt_to_phys(dst); - - //req.dst.format = RK_FORMAT_RGB_565; - - req.clip.xmin = 0; - req.clip.xmax = 1279; - req.clip.ymin = 0; - req.clip.ymax = 799; - - //req.render_mode = color_fill_mode; - //req.fg_color = 0x80ffffff; - - req.rotate_mode = 1; - req.scale_mode = 2; + //req.rotate_mode = 1; + //req.scale_mode = 2; //req.alpha_rop_flag = 0; //req.alpha_rop_mode = 0x1; @@ -1408,11 +1375,11 @@ void rga_test_0(void) rga_blit_sync(&session, &req); - #if 0 + #if 1 fb->var.bits_per_pixel = 32; - fb->var.xres = 1280; - fb->var.yres = 800; + fb->var.xres = 800; + fb->var.yres = 480; fb->var.red.length = 8; fb->var.red.offset = 0; From a5b59cb5c55eb9763c11b85d1d06e609a7766959 Mon Sep 17 00:00:00 2001 From: hxy Date: Tue, 31 Jul 2012 17:37:13 +0800 Subject: [PATCH 056/261] rk31: fix lcdc rgb888 bug --- drivers/video/rockchip/chips/rk31_lcdc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/video/rockchip/chips/rk31_lcdc.c b/drivers/video/rockchip/chips/rk31_lcdc.c index be14760bb886..37ece0d6e28c 100644 --- a/drivers/video/rockchip/chips/rk31_lcdc.c +++ b/drivers/video/rockchip/chips/rk31_lcdc.c @@ -37,7 +37,7 @@ -static int dbg_thresd = 0; +static int dbg_thresd = 3; module_param(dbg_thresd, int, S_IRUGO|S_IWUSR); #define DBG(level,x...) do { if(unlikely(dbg_thresd > level)) printk(KERN_INFO x); } while (0) @@ -464,6 +464,9 @@ static int win1_set_par(struct rk31_lcdc_device *lcdc_dev,rk_screen *screen, { switch (par->format) { + case ARGB888: + par->format = RGB888; + break; case YUV422:// yuv422 ScaleCbrX = CalScale((xact/2), par->xsize); ScaleCbrY = CalScale(yact, par->ysize); From 34bcc3db74e06b9fd867318afe6d07e443a3355d Mon Sep 17 00:00:00 2001 From: wlq Date: Tue, 31 Jul 2012 15:19:35 +0800 Subject: [PATCH 057/261] add mi700 --- arch/arm/mach-rk30/board-rk30-phonepad.c | 52 ++++ drivers/misc/3g_module/Kconfig | 3 + drivers/misc/3g_module/Makefile | 2 +- drivers/misc/3g_module/mi700.c | 352 +++++++++++++++++++++++ include/linux/mi700.h | 27 ++ 5 files changed, 435 insertions(+), 1 deletion(-) create mode 100755 drivers/misc/3g_module/mi700.c create mode 100644 include/linux/mi700.h diff --git a/arch/arm/mach-rk30/board-rk30-phonepad.c b/arch/arm/mach-rk30/board-rk30-phonepad.c index 711fdb8ba7a5..da846b986009 100755 --- a/arch/arm/mach-rk30/board-rk30-phonepad.c +++ b/arch/arm/mach-rk30/board-rk30-phonepad.c @@ -71,6 +71,11 @@ #if defined(CONFIG_SEW868) #include #endif + +#if defined(CONFIG_MI700) +#include +#endif + #if defined(CONFIG_ANDROID_TIMED_GPIO) #include "../../../drivers/staging/android/timed_gpio.h" #endif @@ -960,7 +965,51 @@ struct platform_device rk30_device_sew868 = { } }; #endif +#if defined(CONFIG_MI700) +#define BP_POWER RK29_PIN6_PB1 +#define BP_RESET RK29_PIN6_PC7 +static int mi700_io_init(void) +{ + int result; + result = gpio_request(BP_RESET, NULL); + if (result) + { + gpio_free(BP_RESET); + printk("failed to request BP_RESET gpio\n"); + } + result = gpio_request(BP_POWER, NULL); + if (result) + { + gpio_free(BP_POWER); + printk("failed to request BP_POWER gpio\n"); + } + return 0; +} +static int mi700_io_deinit(void) +{ + gpio_free(BP_RESET); + gpio_free(BP_POWER); + + return 0; +} + +struct rk29_mi700_data rk29_mi700_info = { + .io_init = mi700_io_init, + .io_deinit = mi700_io_deinit, + .bp_power = RK29_PIN6_PB1,//RK29_PIN0_PB4, + .bp_reset = RK29_PIN6_PC7,//RK29_PIN0_PB3, + .bp_wakeup_ap = RK29_PIN6_PC6,//RK29_PIN0_PC2, + .ap_wakeup_bp = NULL,//RK29_PIN0_PB0, +}; +struct platform_device rk29_device_mi700 = { + .name = "MI700", + .id = -1, + .dev = { + .platform_data = &rk29_mi700_info, + } + }; +#endif /*MMA8452 gsensor*/ #if defined (CONFIG_GS_MMA8452) #define MMA8452_INT_PIN RK30_PIN4_PC0 @@ -1629,6 +1678,9 @@ static struct platform_device *devices[] __initdata = { #if defined (CONFIG_RK_HEADSET_DET) || defined (CONFIG_RK_HEADSET_IRQ_HOOK_ADC_DET) &rk_device_headset, #endif +#if defined(CONFIG_MI700) + &rk29_device_mi700, +#endif #ifdef CONFIG_BATTERY_RK30_ADC &rk30_device_adc_battery, #endif diff --git a/drivers/misc/3g_module/Kconfig b/drivers/misc/3g_module/Kconfig index 2074779c92f4..d702973a2d09 100644 --- a/drivers/misc/3g_module/Kconfig +++ b/drivers/misc/3g_module/Kconfig @@ -23,6 +23,9 @@ choice config SEW868 bool "SEW868" + config MI700 + bool "MI700" + endchoice diff --git a/drivers/misc/3g_module/Makefile b/drivers/misc/3g_module/Makefile index 33af3f5a603f..768a2d535124 100644 --- a/drivers/misc/3g_module/Makefile +++ b/drivers/misc/3g_module/Makefile @@ -2,4 +2,4 @@ obj-$(CONFIG_MU509) += mu509.o obj-$(CONFIG_MW100) += mw100.o obj-$(CONFIG_MT6229) += mt6229.o obj-$(CONFIG_SEW868) += sew868.o - +obj-$(CONFIG_MI700) += mi700.o diff --git a/drivers/misc/3g_module/mi700.c b/drivers/misc/3g_module/mi700.c new file mode 100755 index 000000000000..3b6ecb1c6ca4 --- /dev/null +++ b/drivers/misc/3g_module/mi700.c @@ -0,0 +1,352 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); + +#define DEBUG +#ifdef DEBUG +#define MODEMDBG(x...) printk(x) +#else +#define MODEMDBG(fmt,argss...) +#endif + +#define MW100IO 0XA1 +#define MW_IOCTL_RESET _IO(MW100IO,0X01) + +#define SLEEP 1 +#define READY 0 +#define MI700_RESET 0x01 +static struct wake_lock modem_wakelock; +#define IRQ_BB_WAKEUP_AP_TRIGGER IRQF_TRIGGER_RISING +struct rk29_mi700_data *gpdata = NULL; +static int bp_wakeup_ap_irq = 0; +struct class *modem_class = NULL; +static int do_wakeup_irq = 1; +static int modem_status; +static int online = 0; + +static void ap_wakeup_bp(struct platform_device *pdev, int wake) +{ + struct rk29_mi700_data *pdata = pdev->dev.platform_data; + MODEMDBG("ap_wakeup_bp\n"); + + gpio_set_value(pdata->ap_wakeup_bp, wake); + +} +extern void rk28_send_wakeup_key(void); + +static void do_wakeup(struct work_struct *work) +{ + MODEMDBG("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); + //rk28_send_wakeup_key(); +} + +static DECLARE_DELAYED_WORK(wakeup_work, do_wakeup); +static irqreturn_t detect_irq_handler(int irq, void *dev_id) +{ + if(do_wakeup_irq) + { + do_wakeup_irq = 0; + printk("%s[%d]: %s\n", __FILE__, __LINE__, __FUNCTION__); + wake_lock_timeout(&modem_wakelock, 10 * HZ); + schedule_delayed_work(&wakeup_work, HZ / 10); + } else + printk("%s: already wakeup\n", __FUNCTION__); + + return IRQ_HANDLED; +} +int modem_poweron_off(int on_off) +{ + struct rk29_mi700_data *pdata = gpdata; + + mutex_lock(&pdata->bp_mutex); + if(on_off) + { + MODEMDBG("------------modem_poweron\n"); + gpio_set_value(pdata->bp_reset, GPIO_LOW); + msleep(100); + gpio_set_value(pdata->bp_reset, GPIO_HIGH); + gpio_set_value(pdata->bp_power, GPIO_HIGH); + msleep(1000); + gpio_set_value(pdata->bp_power, GPIO_LOW); + msleep(700); + gpio_set_value(pdata->bp_power, GPIO_HIGH); + } + else + { + MODEMDBG("------------modem_poweroff\n"); + gpio_set_value(pdata->bp_power, GPIO_LOW); + gpio_set_value(pdata->bp_power, GPIO_HIGH); + msleep(2500); + gpio_set_value(pdata->bp_power, GPIO_LOW); + } + mutex_unlock(&pdata->bp_mutex); + return 0; +} +static int mi700_open(struct inode *inode, struct file *file) +{ + //MODEMDBG("-------------%s\n",__FUNCTION__); + struct rk29_mi700_data *pdata = gpdata; +// struct platform_data *pdev = container_of(pdata, struct device, platform_data); + device_init_wakeup(pdata->dev, 1); + return 0; +} + +static int mi700_release(struct inode *inode, struct file *file) +{ + MODEMDBG("%s::%d--bruins--\n",__func__,__LINE__); + //modem_poweron_off(0); + return 0; +} + +static long mi700_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct rk29_mi700_data *pdata = gpdata; + switch(cmd) + { + case MI700_RESET: + gpio_set_value(pdata->bp_reset, GPIO_LOW); + msleep(100); + gpio_set_value(pdata->bp_reset, GPIO_HIGH); + msleep(100); + gpio_set_value(pdata->bp_power, GPIO_HIGH); + msleep(1000); + gpio_set_value(pdata->bp_power, GPIO_LOW); + msleep(700); + gpio_set_value(pdata->bp_power, GPIO_HIGH); + break; + default: + break; + } + return 0; +} + +static struct file_operations mi700_fops = { + .owner = THIS_MODULE, + .open = mi700_open, + .release = mi700_release, + .unlocked_ioctl = mi700_ioctl +}; + +static struct miscdevice mi700_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "mi700", + .fops = &mi700_fops +}; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) +static ssize_t modem_status_read(struct class *cls, struct class_attribute *attr, char *_buf) +#else +static ssize_t modem_status_read(struct class *cls, char *_buf) +#endif +{ + + return sprintf(_buf, "%d\n", modem_status); + +} +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) +static ssize_t modem_status_write(struct class *cls, struct class_attribute *attr, const char *_buf, size_t _count) +#else +static ssize_t modem_status_write(struct class *cls, const char *_buf, size_t _count) +#endif +{ + int new_state = simple_strtoul(_buf, NULL, 16); + if(new_state == modem_status) + return _count; + + if (new_state == 1){ + printk("%s, c(%d), open modem \n", __FUNCTION__, new_state); + modem_poweron_off(1); + }else if(new_state == 0){ + printk("%s, c(%d), close modem \n", __FUNCTION__, new_state); + modem_poweron_off(0); + }else{ + printk("%s, invalid parameter \n", __FUNCTION__); + } + + modem_status = new_state; + return _count; +} +static CLASS_ATTR(modem_status, 0777, modem_status_read, modem_status_write); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) +static ssize_t online_read(struct class *cls, struct class_attribute *attr, char *_buf) +#else +static ssize_t online_read(struct class *cls, char *_buf) +#endif +{ + return sprintf(_buf, "%d\n", online); + +} +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) +static ssize_t online_write(struct class *cls, struct class_attribute *attr, const char *_buf, size_t _count) +#else +static ssize_t online_write(struct class *cls, const char *_buf, size_t _count) +#endif +{ + int new_value = simple_strtoul(_buf, NULL, 16); + if(new_value == online) return _count; + online = new_value; + return _count; +} +static CLASS_ATTR(online, 0777, online_read, online_write); +static int mi700_probe(struct platform_device *pdev) +{ + struct rk29_mi700_data *pdata = gpdata = pdev->dev.platform_data; + struct modem_dev *mi700_data = NULL; + int result, irq = 0; + MODEMDBG("-------------%s\n",__FUNCTION__); + + pdata->dev = &pdev->dev; + if(pdata->io_init) + pdata->io_init(); + + mi700_data = kzalloc(sizeof(struct modem_dev), GFP_KERNEL); + if(mi700_data == NULL) + { + printk("failed to request mi700_data\n"); + goto err2; + } + platform_set_drvdata(pdev, mi700_data); + #if 0 + result = gpio_request(pdata->ap_wakeup_bp, "mi700"); + if (result) { + printk("failed to request AP_BP_WAKEUP gpio\n"); + goto err1; + } + #endif + irq = gpio_to_irq(pdata->bp_wakeup_ap); + enable_irq_wake(irq); + if(irq < 0) + { + gpio_free(pdata->bp_wakeup_ap); + printk("failed to request bp_wakeup_ap\n"); + } + result = gpio_request(pdata->bp_wakeup_ap, "bp_wakeup_ap"); + if (result < 0) { + printk("%s: gpio_request(%d) failed\n", __func__, pdata->bp_wakeup_ap); + } + wake_lock_init(&modem_wakelock, WAKE_LOCK_SUSPEND, "bp_wakeup_ap"); + gpio_direction_input(pdata->bp_wakeup_ap); + gpio_pull_updown(pdata->bp_wakeup_ap, 1); + result = request_irq(irq, detect_irq_handler, IRQ_BB_WAKEUP_AP_TRIGGER, "bp_wakeup_ap", NULL); + if (result < 0) { + printk("%s: request_irq(%d) failed\n", __func__, irq); + gpio_free(pdata->bp_wakeup_ap); + goto err0; + } + enable_irq_wake(gpio_to_irq(pdata->bp_wakeup_ap)); + + mutex_init(&pdata->bp_mutex); + + modem_poweron_off(1); + modem_status = 1; + + result = misc_register(&mi700_misc); + if(result) + { + printk("misc_register err\n"); + } + return result; +err0: + cancel_work_sync(&mi700_data->work); + gpio_free(pdata->bp_wakeup_ap); +err1: + //gpio_free(pdata->ap_wakeup_bp); +err2: + kfree(mi700_data); + return 0; +} + +int mi700_suspend(struct platform_device *pdev) +{ + + struct rk29_mi700_data *pdata = pdev->dev.platform_data; + do_wakeup_irq = 1; + MODEMDBG("%s::%d--\n",__func__,__LINE__); + //gpio_set_value(pdata->ap_wakeup_bp, GPIO_LOW); + return 0; +} + +int mi700_resume(struct platform_device *pdev) +{ + MODEMDBG("-------------%s\n",__FUNCTION__); + //ap_wakeup_bp(pdev, 0); + //rk29_mux_api_set(GPIO1C1_UART0RTSN_SDMMC1WRITEPRT_NAME, GPIO1H_UART0_RTS_N); + return 0; +} + +void mi700_shutdown(struct platform_device *pdev, pm_message_t state) +{ + struct rk29_mi700_data *pdata = pdev->dev.platform_data; + struct modem_dev *mi700_data = platform_get_drvdata(pdev); + + MODEMDBG("-------------%s\n",__FUNCTION__); + modem_poweron_off(0); + + if(pdata->io_deinit) + pdata->io_deinit(); + cancel_work_sync(&mi700_data->work); + //gpio_free(pdata->bp_power); + //gpio_free(pdata->bp_reset); + //gpio_free(pdata->ap_wakeup_bp); + gpio_free(pdata->bp_wakeup_ap); + kfree(mi700_data); +} + +static struct platform_driver mi700_driver = { + .probe = mi700_probe, + .shutdown = mi700_shutdown, + .suspend = mi700_suspend, + .resume = mi700_resume, + .driver = { + .name = "MW100", + .owner = THIS_MODULE, + }, +}; + +static int __init mi700_init(void) +{ + MODEMDBG("-------------%s\n",__FUNCTION__); + int ret ; + + modem_class = class_create(THIS_MODULE, "rk291x_modem"); + ret = class_create_file(modem_class, &class_attr_modem_status); + ret = class_create_file(modem_class, &class_attr_online); + if (ret) + { + printk("Fail to class rk291x_modem.\n"); + } + return platform_driver_register(&mi700_driver); +} + +static void __exit mi700_exit(void) +{ + MODEMDBG("%s::%d--bruins--\n",__func__,__LINE__); + platform_driver_unregister(&mi700_driver); + class_remove_file(modem_class, &class_attr_modem_status); + class_remove_file(modem_class, &class_attr_online); +} + +module_init(mi700_init); +module_exit(mi700_exit); diff --git a/include/linux/mi700.h b/include/linux/mi700.h new file mode 100644 index 000000000000..df20b2c9d93a --- /dev/null +++ b/include/linux/mi700.h @@ -0,0 +1,27 @@ +#include +#include +#include + +struct modem_dev +{ + const char *name; + struct miscdevice miscdev; + struct work_struct work; +}; + +/* 鑰虫満鏁版嵁缁撴瀯浣 */ +struct rk29_mi700_data { + struct device *dev; + int (*io_init)(void); + int (*io_deinit)(void); + unsigned int bp_power; + unsigned int bp_power_active_low; + unsigned int bp_reset; + unsigned int bp_reset_active_low; + unsigned int bp_wakeup_ap; + unsigned int ap_wakeup_bp; + unsigned int modem_power_en; + struct mutex bp_mutex; +}; + +#define MODEM_NAME "mi700" From cdfde8c3752bdabea6dd4e8dde113d5eeb5d8b92 Mon Sep 17 00:00:00 2001 From: yangkai Date: Tue, 31 Jul 2012 17:51:05 +0800 Subject: [PATCH 058/261] usb code modify --- drivers/usb/dwc_otg/dwc_otg_driver.c | 16 ++-------------- drivers/usb/dwc_otg/dwc_otg_hcd.c | 4 ++-- drivers/usb/dwc_otg/dwc_otg_pcd.c | 1 + 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/drivers/usb/dwc_otg/dwc_otg_driver.c b/drivers/usb/dwc_otg/dwc_otg_driver.c index 84c360d55af3..d802e279674f 100755 --- a/drivers/usb/dwc_otg/dwc_otg_driver.c +++ b/drivers/usb/dwc_otg/dwc_otg_driver.c @@ -74,7 +74,7 @@ #include "dwc_otg_cil.h" #include "dwc_otg_pcd.h" #include "dwc_otg_hcd.h" -#include +//#include //#define DWC_DRIVER_VERSION "2.60a 22-NOV-2006" //#define DWC_DRIVER_VERSION "2.70 2009-12-31" #define DWC_DRIVER_VERSION "3.00 2010-12-12 rockchip" @@ -1416,7 +1416,7 @@ static __devinit int dwc_otg_driver_probe(struct platform_device *pdev) dwc_otg_device->phyclk = phyclk; dwc_otg_device->ahbclk = ahbclk; #endif -#ifdef CONFIG_ARCH_RK2928 +#if 0//def CONFIG_ARCH_RK2928 otg_phy_con = (unsigned int*)(USBGRF_UOC0_CON5); cru_set_soft_reset(SOFT_RST_USBPHY0, true); cru_set_soft_reset(SOFT_RST_OTGC0, true); @@ -2176,9 +2176,6 @@ static __devinit int host20_driver_probe(struct platform_device *pdev) #ifdef CONFIG_ARCH_RK30 *(unsigned int*)(USBGRF_UOC1_CON2+4) = ((1<<5)|((1<<5)<<16)); #endif -#ifdef CONFIG_ARCH_RK2928 - *(unsigned int*)(USBGRF_UOC1_CON5-4) = ((1<<5)|((1<<5)<<16)); -#endif if (dwc_otg_device == 0) { dev_err(dev, "kmalloc of dwc_otg_device failed\n"); @@ -2311,15 +2308,6 @@ static __devinit int host20_driver_probe(struct platform_device *pdev) #endif #ifdef CONFIG_ARCH_RK30 USB_IOMUX_INIT(GPIO0A6_HOSTDRVVBUS_NAME, GPIO0A_HOST_DRV_VBUS); -#ifdef CONFIG_MACH_RK30_DS1001B - USB_IOMUX_INIT(GPIO0A5_OTGDRVVBUS_NAME, GPIO0A_GPIO0A5); - if(gpio_request(RK30_PIN0_PA5,"host_drv")<0){ - DWC_ERROR("request of host power control failed\n"); - gpio_free(RK30_PIN0_PA5); - } - gpio_direction_output(RK30_PIN0_PA5, GPIO_HIGH); - gpio_set_value(RK30_PIN0_PA5, GPIO_HIGH); -#endif #endif /* * Initialize the DWC_otg core. diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd.c b/drivers/usb/dwc_otg/dwc_otg_hcd.c index 4c84033c2a59..55a1e8931f54 100755 --- a/drivers/usb/dwc_otg/dwc_otg_hcd.c +++ b/drivers/usb/dwc_otg/dwc_otg_hcd.c @@ -618,7 +618,7 @@ static int32_t dwc_otg_phy_suspend_cb( void *_p, int suspend) DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n"); } #endif -#ifdef CONFIG_ARCH_RK2928 +#if 0//def CONFIG_ARCH_RK2928 unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC0_CON5); if(exitsuspend && (pcd->phy_suspend == 1)) { clk_enable(pcd->otg_dev->ahbclk); @@ -1143,7 +1143,7 @@ static int32_t host20_phy_suspend_cb( void *_p, int suspend) DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n"); } #endif -#ifdef CONFIG_ARCH_RK2928 +#if 0//def CONFIG_ARCH_RK2928 unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC0_CON5); if(exitsuspend && (pcd->phy_suspend == 1)) { clk_enable(pcd->otg_dev->ahbclk); diff --git a/drivers/usb/dwc_otg/dwc_otg_pcd.c b/drivers/usb/dwc_otg/dwc_otg_pcd.c index 8dd5bce818c5..5b962bf8657e 100755 --- a/drivers/usb/dwc_otg/dwc_otg_pcd.c +++ b/drivers/usb/dwc_otg/dwc_otg_pcd.c @@ -1604,6 +1604,7 @@ int dwc_pcd_reset(dwc_otg_pcd_t *pcd) cru_set_soft_reset(SOFT_RST_USB_OTG_2_0_AHB_BUS, false); cru_set_soft_reset(SOFT_RST_USB_OTG_2_0_PHY, false); cru_set_soft_reset(SOFT_RST_USB_OTG_2_0_CONTROLLER, false); + mdelay(1); #endif //rockchip_scu_reset_unit(12); dwc_otg_pcd_reinit( pcd ); From d19e195105d5cc437fe0890e3cdb4428da59560d Mon Sep 17 00:00:00 2001 From: ddl Date: Tue, 31 Jul 2012 17:54:22 +0800 Subject: [PATCH 059/261] camera: add support gc0329/s5k5ca/sp0838 sensor driver --- arch/arm/plat-rk/include/plat/rk_camera.h | 10 + drivers/media/video/Kconfig | 34 + drivers/media/video/Makefile | 3 + drivers/media/video/gc0329.c | 3046 ++++++++++ drivers/media/video/s5k5ca.c | 6093 +++++++++++++++++++++ drivers/media/video/s5k5ca.h | 242 + drivers/media/video/sp0838.c | 2884 ++++++++++ include/media/v4l2-chip-ident.h | 3 + 8 files changed, 12315 insertions(+) create mode 100755 drivers/media/video/gc0329.c create mode 100755 drivers/media/video/s5k5ca.c create mode 100755 drivers/media/video/s5k5ca.h create mode 100755 drivers/media/video/sp0838.c diff --git a/arch/arm/plat-rk/include/plat/rk_camera.h b/arch/arm/plat-rk/include/plat/rk_camera.h index 58f17a2767c0..19ca16b0692d 100755 --- a/arch/arm/plat-rk/include/plat/rk_camera.h +++ b/arch/arm/plat-rk/include/plat/rk_camera.h @@ -64,6 +64,10 @@ #define RK29_CAM_SENSOR_HI253 hi253 #define RK29_CAM_SENSOR_HI704 hi704 #define RK29_CAM_SENSOR_NT99250 nt99250 +#define RK29_CAM_SENSOR_SP0838 sp0838 +#define RK29_CAM_SENSOR_GC0329 gc0329 +#define RK29_CAM_SENSOR_S5K5CA s5k5ca + #define RK29_CAM_SENSOR_NAME_OV7675 "ov7675" #define RK29_CAM_SENSOR_NAME_OV9650 "ov9650" @@ -90,6 +94,9 @@ #define RK29_CAM_SENSOR_NAME_HI253 "hi253" #define RK29_CAM_SENSOR_NAME_HI704 "hi704" #define RK29_CAM_SENSOR_NAME_NT99250 "nt99250" +#define RK29_CAM_SENSOR_NAME_SP0838 "sp0838" +#define RK29_CAM_SENSOR_NAME_GC0329 "gc0329" +#define RK29_CAM_SENSOR_NAME_S5K5CA "s5k5ca" #define ov7675_FULL_RESOLUTION 0x30000 // 0.3 megapixel #define ov9650_FULL_RESOLUTION 0x130000 // 1.3 megapixel @@ -115,6 +122,9 @@ #define hi253_FULL_RESOLUTION 0x200000 // 2 megapixel #define hi704_FULL_RESOLUTION 0x30000 // 0.3 megapixel #define nt99250_FULL_RESOLUTION 0x200000 // 2 megapixel +#define sp0838_FULL_RESOLUTION 0x30000 // 0.3 megapixel +#define gc0329_FULL_RESOLUTION 0x30000 // 0.3 megapixel +#define s5k5ca_FULL_RESOLUTION 0x300000 // 3 megapixel /*---------------- Camera Sensor Must Define Macro End ------------------------*/ diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 67c42bca47f6..08120f7a91da 100755 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -1217,6 +1217,40 @@ config NT99250_USER_DEFINED_SERIES bool "NT99250 user defined init series" default n +config SOC_CAMERA_GC0329 + tristate "gc0329 camera support for rockchip" + depends on SOC_CAMERA && I2C + help + This is a gc0329 camera driver for rockchip + +config GC0329_USER_DEFINED_SERIES + depends on SOC_CAMERA_GC0329 + bool "GC0329 user defined init series" + default n + +config SOC_CAMERA_S5K5CA + tristate "s5k5ca camera support for rockchip" + depends on SOC_CAMERA && I2C + help + This is a s5k5ca camera driver for rockchip + +config S5K5CA_USER_DEFINED_SERIES + depends on SOC_CAMERA_S5K5CA + bool "s5k5ca user defined init series" + default n + +config SOC_CAMERA_SP0838 + tristate "sp0838 camera support for rockchip" + depends on SOC_CAMERA && I2C + help + This is a sp0838 camera driver for rockchip + +config S5K5CA_USER_DEFINED_SERIES + depends on SOC_CAMERA_SP0838 + bool "sp0838 user defined init series" + default n + + config SOC_CAMERA_OV9640 tristate "ov9640 camera support" depends on SOC_CAMERA && I2C diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 46540d4a6542..b96c68fdef76 100755 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -112,6 +112,9 @@ obj-$(CONFIG_SOC_CAMERA_SID130B) += sid130B.o obj-$(CONFIG_SOC_CAMERA_HI253) += hi253.o obj-$(CONFIG_SOC_CAMERA_HI704) += hi704.o obj-$(CONFIG_SOC_CAMERA_NT99250) += nt99250.o +obj-$(CONFIG_SOC_CAMERA_GC0329) += gc0329.o +obj-$(CONFIG_SOC_CAMERA_SP0838) += sp0838.o +obj-$(CONFIG_SOC_CAMERA_S5K5CA) += s5k5ca.o # And now the v4l2 drivers: obj-$(CONFIG_VIDEO_BT848) += bt8xx/ diff --git a/drivers/media/video/gc0329.c b/drivers/media/video/gc0329.c new file mode 100755 index 000000000000..9db5a4190ca7 --- /dev/null +++ b/drivers/media/video/gc0329.c @@ -0,0 +1,3046 @@ + +/* +o* Driver for MT9M001 CMOS Image Sensor from Micron + * + * Copyright (C) 2008, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int debug; +module_param(debug, int, S_IRUGO|S_IWUSR); + +#define dprintk(level, fmt, arg...) do { \ + if (debug >= level) \ + printk(KERN_WARNING fmt , ## arg); } while (0) + +#define SENSOR_TR(format, ...) printk(KERN_ERR format, ## __VA_ARGS__) +#define SENSOR_DG(format, ...) dprintk(1, format, ## __VA_ARGS__) + + +#define _CONS(a,b) a##b +#define CONS(a,b) _CONS(a,b) + +#define __STR(x) #x +#define _STR(x) __STR(x) +#define STR(x) _STR(x) + +#define MIN(x,y) ((xy) ? x: y) + +/* Sensor Driver Configuration */ +#define SENSOR_NAME RK29_CAM_SENSOR_GC0329 +#define SENSOR_V4L2_IDENT V4L2_IDENT_GC0329 +#define SENSOR_ID 0xc0 //GC0329 ID +#define SENSOR_MIN_WIDTH 640//176 +#define SENSOR_MIN_HEIGHT 480//144 +#define SENSOR_MAX_WIDTH 640 +#define SENSOR_MAX_HEIGHT 480 +#define SENSOR_INIT_WIDTH 640 /* Sensor pixel size for sensor_init_data array */ +#define SENSOR_INIT_HEIGHT 480 +#define SENSOR_INIT_WINSEQADR sensor_vga +#define SENSOR_INIT_PIXFMT V4L2_MBUS_FMT_YUYV8_2X8 + +#define CONFIG_SENSOR_WhiteBalance 1 +#define CONFIG_SENSOR_Brightness 0 +#define CONFIG_SENSOR_Contrast 0 +#define CONFIG_SENSOR_Saturation 0 +#define CONFIG_SENSOR_Effect 1 +#define CONFIG_SENSOR_Scene 1 +#define CONFIG_SENSOR_AntiBanding 0 +#define CONFIG_SENSOR_DigitalZoom 0 +#define CONFIG_SENSOR_Focus 0 +#define CONFIG_SENSOR_Exposure 0 +#define CONFIG_SENSOR_Flash 0 +#define CONFIG_SENSOR_Mirror 0 +#define CONFIG_SENSOR_Flip 0 + +#define CONFIG_SENSOR_I2C_SPEED 100000 /* Hz */ +/* Sensor write register continues by preempt_disable/preempt_enable for current process not be scheduled */ +#define CONFIG_SENSOR_I2C_NOSCHED 0 +#define CONFIG_SENSOR_I2C_RDWRCHK 0 + +#define SENSOR_BUS_PARAM (SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |\ + SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH|\ + SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8 |SOCAM_MCLK_24MHZ) + +#define COLOR_TEMPERATURE_CLOUDY_DN 6500 +#define COLOR_TEMPERATURE_CLOUDY_UP 8000 +#define COLOR_TEMPERATURE_CLEARDAY_DN 5000 +#define COLOR_TEMPERATURE_CLEARDAY_UP 6500 +#define COLOR_TEMPERATURE_OFFICE_DN 3500 +#define COLOR_TEMPERATURE_OFFICE_UP 5000 +#define COLOR_TEMPERATURE_HOME_DN 2500 +#define COLOR_TEMPERATURE_HOME_UP 3500 + +#define SENSOR_NAME_STRING(a) STR(CONS(SENSOR_NAME, a)) +#define SENSOR_NAME_VARFUN(a) CONS(SENSOR_NAME, a) + +#define SENSOR_AF_IS_ERR (0x00<<0) +#define SENSOR_AF_IS_OK (0x01<<0) +#define SENSOR_INIT_IS_ERR (0x00<<28) +#define SENSOR_INIT_IS_OK (0x01<<28) +struct reginfo +{ + u8 reg; + u8 val; +}; + +/* init 640X480 VGA */ +static struct reginfo sensor_init_data[] = +{ + // TODO: add initial code here + {0xfe, 0x80}, + {0xfe, 0x80}, + {0xfc, 0x16}, + {0xfc, 0x16}, + {0xfc, 0x16}, + {0xfc, 0x16}, + {0xfe, 0x00}, + {0xf0, 0x07}, + {0xf1, 0x01}, + + + + + {0x73, 0x90}, + {0x74, 0x80}, + {0x75, 0x80}, + {0x76, 0x94}, + + {0x42, 0x00}, + {0x77, 0x57}, + {0x78, 0x4d}, + {0x79, 0x45}, + //{0x42, 0xfc}, + + ////////////////////analog//////////////////// + {0x0a, 0x02}, + {0x0c, 0x02}, + {0x17, 0x17}, + {0x19, 0x05}, + {0x1b, 0x24}, + {0x1c, 0x04}, + {0x1e, 0x08}, + {0x1f, 0xc0}, //Analog_mode2//[7:6] comv_r + {0x20, 0x00}, + {0x21, 0x48}, + {0x22, 0xba}, + {0x23, 0x22}, + {0x24, 0x17}, + + ////////////////////blk//////////////////// + {0x26, 0xf7}, + {0x29, 0x80}, + {0x32, 0x04}, + {0x33, 0x20}, + {0x34, 0x20}, + {0x35, 0x20}, + {0x36, 0x20}, + + ////////////////////ISP BLOCK ENABL//////////////////// + {0x40, 0xff}, + {0x41, 0x44}, + {0x42, 0x7e}, + {0x44, 0xa2}, + {0x46, 0x03}, + {0x4b, 0xca}, + {0x4d, 0x01}, + {0x4f, 0x01}, + {0x70, 0x48}, + + //{0xb0, 0x00}, + //{0xbc, 0x00}, + //{0xbd, 0x00}, + //{0xbe, 0x00}, + ////////////////////DNDD//////////////////// + {0x80, 0xe7}, + {0x82, 0x55}, + {0x83, 0x03}, + {0x87, 0x4a}, + + ////////////////////INTPEE//////////////////// + {0x95, 0x45}, + + ////////////////////ASDE//////////////////// + //{0xfe, 0x01}, + //{0x18, 0x22}, + //{0xfe, 0x00); + //{0x9c, 0x0a}, + //{0xa0, 0xaf}, + //{0xa2, 0xff}, + //{0xa4, 0x50}, + //{0xa5, 0x21}, + //{0xa7, 0x35}, + + ////////////////////RGB gamma//////////////////// + //RGB gamma m4' + {0xbf, 0x06}, + {0xc0, 0x14}, + {0xc1, 0x27}, + {0xc2, 0x3b}, + {0xc3, 0x4f}, + {0xc4, 0x62}, + {0xc5, 0x72}, + {0xc6, 0x8d}, + {0xc7, 0xa4}, + {0xc8, 0xb8}, + {0xc9, 0xc9}, + {0xcA, 0xd6}, + {0xcB, 0xe0}, + {0xcC, 0xe8}, + {0xcD, 0xf4}, + {0xcE, 0xFc}, + {0xcF, 0xFF}, + + //////////////////CC/////////////////// + {0xfe, 0x00}, + + {0xb3, 0x44}, + {0xb4, 0xfd}, + {0xb5, 0x02}, + {0xb6, 0xfa}, + {0xb7, 0x48}, + {0xb8, 0xf0}, + + // crop + {0x50, 0x01}, + + ////////////////////YCP//////////////////// + {0xfe, 0x00}, + {0xd1, 0x38}, + {0xd2, 0x38}, + {0xdd, 0x54}, + + ////////////////////AEC//////////////////// + {0xfe, 0x01}, + {0x10, 0x40}, + {0x11, 0x21},//a1 + {0x12, 0x07}, + {0x13, 0x50}, //Y target + {0x17, 0x88}, + {0x21, 0xb0}, + {0x22, 0x48}, + {0x3c, 0x95}, + {0x3d, 0x50}, + {0x3e, 0x48}, + + ////////////////////AWB//////////////////// + {0xfe, 0x01}, + {0x06, 0x16}, + {0x07, 0x06}, + {0x08, 0x98}, + {0x09, 0xee}, + {0x50, 0xfc}, + {0x51, 0x20}, + {0x52, 0x0b}, + {0x53, 0x20}, + {0x54, 0x40}, + {0x55, 0x10}, + {0x56, 0x20}, + //{0x57, 0x40}, + {0x58, 0xa0}, + {0x59, 0x28}, + {0x5a, 0x02}, + {0x5b, 0x63}, + {0x5c, 0x34}, + {0x5d, 0x73}, + {0x5e, 0x11}, + {0x5f, 0x40}, + {0x60, 0x40}, + {0x61, 0xc8}, + {0x62, 0xa0}, + {0x63, 0x40}, + {0x64, 0x50}, + {0x65, 0x98}, + {0x66, 0xfa}, + {0x67, 0x70}, + {0x68, 0x58}, + {0x69, 0x85}, + {0x6a, 0x40}, + {0x6b, 0x39}, + {0x6c, 0x18}, + {0x6d, 0x28}, + {0x6e, 0x41}, + {0x70, 0x02}, + {0x71, 0x00}, + {0x72, 0x10}, + {0x73, 0x40}, + + //{0x74, 0x32}, + //{0x75, 0x40}, + //{0x76, 0x30}, + //{0x77, 0x48}, + //{0x7a, 0x50}, + //{0x7b, 0x20}, + + {0x80, 0x60}, + {0x81, 0x50}, + {0x82, 0x42}, + {0x83, 0x40}, + {0x84, 0x40}, + {0x85, 0x40}, + + {0x74, 0x40}, + {0x75, 0x58}, + {0x76, 0x24}, + {0x77, 0x40}, + {0x78, 0x20}, + {0x79, 0x60}, + {0x7a, 0x58}, + {0x7b, 0x20}, + {0x7c, 0x30}, + {0x7d, 0x35}, + {0x7e, 0x10}, + {0x7f, 0x08}, + + ////////////////////ABS//////////////////// + {0x9c, 0x02}, + {0x9d, 0x20}, + //{0x9f, 0x40}, + + ////////////////////CC-AWB//////////////////// + {0xd0, 0x00}, + {0xd2, 0x2c}, + {0xd3, 0x80}, + + ////////////////////LSC/////////////////// + //// for xuye062d lens setting + {0xfe, 0x01}, + {0xa0, 0x00}, + {0xa1, 0x3c}, + {0xa2, 0x50}, + {0xa3, 0x00}, + {0xa8, 0x0f}, + {0xa9, 0x08}, + {0xaa, 0x00}, + {0xab, 0x04}, + {0xac, 0x00}, + {0xad, 0x07}, + {0xae, 0x0e}, + {0xaf, 0x00}, + {0xb0, 0x00}, + {0xb1, 0x09}, + {0xb2, 0x00}, + {0xb3, 0x00}, + {0xb4, 0x31}, + {0xb5, 0x19}, + {0xb6, 0x24}, + {0xba, 0x3a}, + {0xbb, 0x24}, + {0xbc, 0x2a}, + {0xc0, 0x17}, + {0xc1, 0x13}, + {0xc2, 0x17}, + {0xc6, 0x21}, + {0xc7, 0x1c}, + {0xc8, 0x1c}, + {0xb7, 0x00}, + {0xb8, 0x00}, + {0xb9, 0x00}, + {0xbd, 0x00}, + {0xbe, 0x00}, + {0xbf, 0x00}, + {0xc3, 0x00}, + {0xc4, 0x00}, + {0xc5, 0x00}, + {0xc9, 0x00}, + {0xca, 0x00}, + {0xcb, 0x00}, + {0xa4, 0x00}, + {0xa5, 0x00}, + {0xa6, 0x00}, + {0xa7, 0x00}, + + + {0xfe, 0x00}, + {0x05, 0x00}, + {0x06, 0x6a}, + {0x07, 0x00}, + {0x08, 0x70}, + + {0xfe, 0x01}, + {0x29, 0x00}, + {0x2a, 0x96}, + + {0x2b, 0x02}, + {0x2c, 0x58},//12 fps + {0x2d, 0x02}, + {0x2e, 0x58}, + {0x2f, 0x02},//10 fps + {0x30, 0x58}, + {0x31, 0x07}, + {0x32, 0x08}, + + + + ////////////20120427//////////////// + {0xfe,0x01}, + {0x18,0x22}, + {0x21,0xc0}, + {0x06,0x12}, + {0x08,0x9c}, + {0x51,0x28}, + {0x52,0x10}, + {0x53,0x20}, + {0x54,0x40}, + {0x55,0x16}, + {0x56,0x30}, + {0x58,0x60}, + {0x59,0x08}, + {0x5c,0x35}, + {0x5d,0x72}, + {0x67,0x80}, + {0x68,0x60}, + {0x69,0x90}, + {0x6c,0x30}, + {0x6d,0x60}, + {0x70,0x10}, + + {0xfe,0x00}, + {0x9c,0x0a}, + {0xa0,0xaf}, + {0xa2,0xff}, + {0xa4,0x60}, + {0xa5,0x31}, + {0xa7,0x35}, + {0x42,0xfe}, + {0xd1,0x34}, + {0xd2,0x34}, + {0xfe,0x00}, + + + + + + + + {0xfe, 0x00}, + ////////////////////asde /////////////////// + {0xa0, 0xaf}, + {0xa2, 0xff}, + + {0x44, 0xa2}, // YUV order + {0x00, 0x00}, + +}; +/* 1280X1024 SXGA */ +static struct reginfo sensor_sxga[] = +{ + {0x00,0x00} +}; + +/* 800X600 SVGA*/ +static struct reginfo sensor_svga[] = +{ + {0x0, 0x0}, +}; + +/* 640X480 VGA */ +static struct reginfo sensor_vga[] = +{ + + + {0xfe, 0x00}, + {0x05, 0x00}, + {0x06, 0x6a}, + {0x07, 0x00}, + {0x08, 0x70}, + + {0xfe, 0x01}, + {0x29, 0x00}, + {0x2a, 0x96}, + + {0x2b, 0x02}, + {0x2c, 0x58},//12 fps + {0x2d, 0x02}, + {0x2e, 0x58}, + {0x2f, 0x02},//10 fps + {0x30, 0x58}, + {0x31, 0x07}, + {0x32, 0x08}, + {0xfe, 0x00}, + + {0x00,0x00} +}; + +/* 352X288 CIF */ +static struct reginfo sensor_cif[] = +{ + {0x00,0x00} +}; + +/* 320*240 QVGA */ +static struct reginfo sensor_qvga[] = +{ + {0x00,0x00} +}; + +/* 176X144 QCIF*/ +static struct reginfo sensor_qcif[] = +{ + {0x00,0x00} +}; + +static struct reginfo sensor_ClrFmt_YUYV[]= +{ + {0x00, 0x00} +}; + +static struct reginfo sensor_ClrFmt_UYVY[]= +{ + {0x00, 0x00} +}; + + +#if CONFIG_SENSOR_WhiteBalance +static struct reginfo sensor_WhiteB_Auto[]= +{ + + {0x77, 0x57}, + {0x78, 0x4d}, + {0x79, 0x45}, + {0x42, 0xfe}, + {0x00, 0x00} +}; +/* Office Colour Temperature : 3500K - 5000K [incandesceny]*/ +static struct reginfo sensor_WhiteB_TungstenLamp1[]= +{ + //Office + {0x42, 0xfd}, + {0x77, 0x40}, + {0x78, 0x58}, + {0x79, 0x5a}, + {0x00, 0x00} + +}; +/* Home Colour Temperature : 2500K - 3500K [daylight]*/ +static struct reginfo sensor_WhiteB_TungstenLamp2[]= +{ + //Home + {0x42, 0xfd}, + {0x77, 0x40}, + {0x78, 0x56}, + {0x79, 0x50}, + {0x00, 0x00} +}; + +/* ClearDay Colour Temperature : 5000K - 6500K [fluorescent]*/ +static struct reginfo sensor_WhiteB_ClearDay[]= +{ + //Sunny + {0x42, 0xfd}, + {0x77, 0x40}, + {0x78, 0x58}, + {0x79, 0x5a}, + {0x00, 0x00} +}; + +/* Cloudy Colour Temperature : 6500K - 8000K */ +static struct reginfo sensor_WhiteB_Cloudy[]= +{ + {0x42, 0xfd}, + {0x77, 0x7a}, //WB_manual_gain + {0x78, 0x60}, + {0x79, 0x40}, + {0x00, 0x00} +}; +static struct reginfo *sensor_WhiteBalanceSeqe[] = {sensor_WhiteB_Auto, sensor_WhiteB_TungstenLamp1,sensor_WhiteB_TungstenLamp2, + sensor_WhiteB_ClearDay, sensor_WhiteB_Cloudy,NULL, +}; +#endif + +#if CONFIG_SENSOR_Brightness +static struct reginfo sensor_Brightness0[]= +{ + // Brightness -2 + + {0xfe, 0x01}, + {0x13, 0x40}, + {0xfe, 0x00}, + {0xd5, 0xe0}, + {0x00, 0x00} +}; + +static struct reginfo sensor_Brightness1[]= +{ + // Brightness -1 + + {0xfe, 0x01}, + {0x13, 0x48}, + {0xfe, 0x00}, + {0xd5, 0xf0}, + {0x00, 0x00} +}; + +static struct reginfo sensor_Brightness2[]= +{ + // Brightness 0 + + + {0xfe, 0x01}, + {0x13, 0x50}, + {0xfe, 0x00}, + {0xd5, 0x00}, + {0x00, 0x00} +}; + +static struct reginfo sensor_Brightness3[]= +{ + // Brightness +1 + + {0xfe, 0x01}, + {0x13, 0x58}, + {0xfe, 0x00}, + {0xd5, 0x10}, + {0x00, 0x00} +}; + +static struct reginfo sensor_Brightness4[]= +{ + // Brightness +2 + + {0xfe, 0x01}, + {0x13, 0x60}, + {0xfe, 0x00}, + {0xd5, 0x20}, + {0x00, 0x00} +}; + +static struct reginfo sensor_Brightness5[]= +{ + // Brightness +3 + + {0xfe, 0x01}, + {0x13, 0x68}, + {0xfe, 0x00}, + {0xd5, 0x30}, + {0x00, 0x00} +}; +static struct reginfo *sensor_BrightnessSeqe[] = {sensor_Brightness0, sensor_Brightness1, sensor_Brightness2, sensor_Brightness3, + sensor_Brightness4, sensor_Brightness5,NULL, +}; + +#endif + +#if CONFIG_SENSOR_Effect +static struct reginfo sensor_Effect_Normal[] = +{ + {0xfe, 0x00}, + {0x43, 0x00}, //special_effect + {0x40, 0xff}, //[7:6]gamma + {0x41, 0x22}, //[1]Y_gamma_en + {0x42, 0xff}, //[2]ABS [1]AWB + + {0x95, 0x64}, //Edge effect + {0x96, 0x82}, //[7:4] edge_max [3:0] edge_th + {0x90, 0xbc}, //EEINTP mode 1 + + {0x4f, 0x01}, //AEC_en + {0xd3, 0x40}, //luma_contrast + {0xd4, 0x80}, //contrast_center + {0xd5, 0x00}, //luma_offset + {0xda, 0x00}, //fixed_Cb + {0xdb, 0x00}, //fixed_Cr + + {0xbf, 0x0e}, //RGB gamma + {0xc0, 0x1c}, + {0xc1, 0x34}, + {0xc2, 0x48}, + {0xc3, 0x5a}, + {0xc4, 0x6b}, + {0xc5, 0x7b}, + {0xc6, 0x95}, + {0xc7, 0xab}, + {0xc8, 0xbf}, + {0xc9, 0xce}, + {0xca, 0xd9}, + {0xcb, 0xe4}, + {0xcc, 0xec}, + {0xcd, 0xf7}, + {0xce, 0xfd}, + {0xcf, 0xff}, + + {0x00,0x00} +}; + +static struct reginfo sensor_Effect_WandB[] = +{ + {0xfe, 0x00}, + {0x43, 0x02}, //special_effect + {0x40, 0xff}, //[7:6]gamma + {0x41, 0x22}, //[1]Y_gamma_en + {0x42, 0xff}, //[2]ABS [1]AWB + + {0x95, 0x64}, //Edge effect + {0x96, 0x82}, //[7:4] edge_max [3:0] edge_th + {0x90, 0xbc}, //EEINTP mode 1 + + {0x4f, 0x01}, //AEC_en + {0xd3, 0x40}, //luma_contrast + {0xd4, 0x80}, //contrast_center + {0xd5, 0x00}, //luma_offset + {0xda, 0x00}, //fixed_Cb + {0xdb, 0x00}, //fixed_Cr + + {0xbf, 0x0e}, //RGB gamma + {0xc0, 0x1c}, + {0xc1, 0x34}, + {0xc2, 0x48}, + {0xc3, 0x5a}, + {0xc4, 0x6b}, + {0xc5, 0x7b}, + {0xc6, 0x95}, + {0xc7, 0xab}, + {0xc8, 0xbf}, + {0xc9, 0xce}, + {0xca, 0xd9}, + {0xcb, 0xe4}, + {0xcc, 0xec}, + {0xcd, 0xf7}, + {0xce, 0xfd}, + {0xcf, 0xff}, + + {0x00,0x00} +}; + +static struct reginfo sensor_Effect_Sepia[] = +{ + + {0xfe, 0x00}, + {0x43, 0x02}, //special_effect + {0x40, 0xff}, //[7:6]gamma + {0x41, 0x22}, //[1]Y_gamma_en + {0x42, 0xff}, //[2]ABS [1]AWB + + {0x95, 0x64}, //Edge effect + {0x96, 0x82}, //[7:4] edge_max [3:0] edge_th + {0x90, 0xbc}, //EEINTP mode 1 + + {0x4f, 0x01}, //AEC_en + {0xd3, 0x40}, //luma_contrast + {0xd4, 0x80}, //contrast_center + {0xd5, 0x00}, //luma_offset + {0xda, 0xd0}, //fixed_Cb + {0xdb, 0x28}, //fixed_Cr + + {0xbf, 0x0e}, //RGB gamma + {0xc0, 0x1c}, + {0xc1, 0x34}, + {0xc2, 0x48}, + {0xc3, 0x5a}, + {0xc4, 0x6b}, + {0xc5, 0x7b}, + {0xc6, 0x95}, + {0xc7, 0xab}, + {0xc8, 0xbf}, + {0xc9, 0xce}, + {0xca, 0xd9}, + {0xcb, 0xe4}, + {0xcc, 0xec}, + {0xcd, 0xf7}, + {0xce, 0xfd}, + {0xcf, 0xff}, + {0x00,0x00} +}; + +static struct reginfo sensor_Effect_Negative[] = +{ + {0xfe, 0x00}, + {0x43, 0x01}, //special_effect + {0x40, 0xff}, //[7:6]gamma + {0x41, 0x22}, //[1]Y_gamma_en + {0x42, 0xff}, //[2]ABS [1]AWB + + {0x95, 0x64}, //Edge effect + {0x96, 0x82}, //[7:4] edge_max [3:0] edge_th + {0x90, 0xbc}, //EEINTP mode 1 + + {0x4f, 0x01}, //AEC_en + {0xd3, 0x40}, //luma_contrast + {0xd4, 0x80}, //contrast_center + {0xd5, 0x00}, //luma_offset + {0xda, 0x00}, //fixed_Cb + {0xdb, 0x00}, //fixed_Cr + + {0xbf, 0x0e}, //RGB gamma + {0xc0, 0x1c}, + {0xc1, 0x34}, + {0xc2, 0x48}, + {0xc3, 0x5a}, + {0xc4, 0x6b}, + {0xc5, 0x7b}, + {0xc6, 0x95}, + {0xc7, 0xab}, + {0xc8, 0xbf}, + {0xc9, 0xce}, + {0xca, 0xd9}, + {0xcb, 0xe4}, + {0xcc, 0xec}, + {0xcd, 0xf7}, + {0xce, 0xfd}, + {0xcf, 0xff}, + + {0x00,0x00} +}; + +//SOLARIZE +static struct reginfo sensor_Effect_Bluish[] = +{ + {0xfe, 0x00}, + {0x43, 0x00}, //special_effect + {0x40, 0xff}, //[7:6]gamma + {0x41, 0x22}, //[1]Y_gamma_en + {0x42, 0xff}, //[2]ABS [1]AWB + + {0x95, 0x64}, //Edge effect + {0x96, 0x82}, //[7:4] edge_max [3:0] edge_th + {0x90, 0xbc}, //EEINTP mode 1 + + {0x4f, 0x01}, //AEC_en + {0xd3, 0x40}, //luma_contrast + {0xd4, 0x80}, //contrast_center + {0xd5, 0x00}, //luma_offset + {0xda, 0x00}, //fixed_Cb + {0xdb, 0x00}, //fixed_Cr + + {0xbf, 0x10}, //RGB gamma + {0xc0, 0x20}, + {0xc1, 0x38}, + {0xc2, 0x4e}, + {0xc3, 0x63}, + {0xc4, 0x76}, + {0xc5, 0x87}, + {0xc6, 0xa2}, + {0xc7, 0xb4}, + {0xc8, 0xa8}, + {0xc9, 0x91}, + {0xca, 0x7b}, + {0xcb, 0x66}, + {0xcc, 0x4f}, + {0xcd, 0x39}, + {0xce, 0x24}, + {0xcf, 0x12}, + + {0x00, 0x00} +}; + +static struct reginfo sensor_Effect_Green[] = +{ + //Greenish + {0x43,0x02}, + {0xda,0xc0}, + {0xdb,0xc0}, + {0x00,0x00} +}; +static struct reginfo *sensor_EffectSeqe[] = {sensor_Effect_Normal, sensor_Effect_WandB, sensor_Effect_Negative,sensor_Effect_Sepia, + sensor_Effect_Bluish, sensor_Effect_Green,NULL, +}; +#endif +#if CONFIG_SENSOR_Exposure +static struct reginfo sensor_Exposure0[]= +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_Exposure1[]= +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_Exposure2[]= +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_Exposure3[]= +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_Exposure4[]= +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_Exposure5[]= +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_Exposure6[]= +{ + + {0x00, 0x00} +}; + +static struct reginfo *sensor_ExposureSeqe[] = {sensor_Exposure0, sensor_Exposure1, sensor_Exposure2, sensor_Exposure3, + sensor_Exposure4, sensor_Exposure5,sensor_Exposure6,NULL, +}; +#endif +#if CONFIG_SENSOR_Saturation +static struct reginfo sensor_Saturation0[]= +{ + {0x00, 0x00} +}; + +static struct reginfo sensor_Saturation1[]= +{ + {0x00, 0x00} +}; + +static struct reginfo sensor_Saturation2[]= +{ + {0x00, 0x00} +}; +static struct reginfo *sensor_SaturationSeqe[] = {sensor_Saturation0, sensor_Saturation1, sensor_Saturation2, NULL,}; + +#endif +#if CONFIG_SENSOR_Contrast +static struct reginfo sensor_Contrast0[]= +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_Contrast1[]= +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_Contrast2[]= +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_Contrast3[]= +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_Contrast4[]= +{ + + {0x00, 0x00} +}; + + +static struct reginfo sensor_Contrast5[]= +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_Contrast6[]= +{ + {0xb3,0x50}, + {0x00, 0x00} +}; +static struct reginfo *sensor_ContrastSeqe[] = {sensor_Contrast0, sensor_Contrast1, sensor_Contrast2, sensor_Contrast3, + sensor_Contrast4, sensor_Contrast5, sensor_Contrast6, NULL, +}; + +#endif +#if CONFIG_SENSOR_Mirror +static struct reginfo sensor_MirrorOn[]= +{ + + {0x00, 0x00} +}; + +static struct reginfo sensor_MirrorOff[]= +{ + + {0x00, 0x00} +}; +static struct reginfo *sensor_MirrorSeqe[] = {sensor_MirrorOff, sensor_MirrorOn,NULL,}; +#endif +#if CONFIG_SENSOR_Flip +static struct reginfo sensor_FlipOn[]= +{ + {0x00, 0x00} +}; + +static struct reginfo sensor_FlipOff[]= +{ + {0x00, 0x00} +}; +static struct reginfo *sensor_FlipSeqe[] = {sensor_FlipOff, sensor_FlipOn,NULL,}; + +#endif +#if CONFIG_SENSOR_Scene +static struct reginfo sensor_SceneAuto[] = +{ + {0xfe, 0x01}, + {0x33, 0x20}, + {0xfe, 0x00}, + {0x00, 0x00} +}; + +static struct reginfo sensor_SceneNight[] = +{ + {0xfe, 0x01}, + {0x33, 0x30}, + {0xfe, 0x00}, + {0x00, 0x00} +}; +static struct reginfo *sensor_SceneSeqe[] = {sensor_SceneAuto, sensor_SceneNight,NULL,}; + +#endif + +#if CONFIG_SENSOR_AntiBanding +static struct reginfo sensor_AntiBanding_50HZ[] = +{ + +{0xfe, 0x00}, + {0x05, 0x00}, + {0x06, 0x6a}, + {0x07, 0x00}, + {0x08, 0x70}, + + {0xfe, 0x01}, + {0x29, 0x00}, + {0x2a, 0x96}, + + {0x2b, 0x02}, + {0x2c, 0x58},//12 fps + {0x2d, 0x02}, + {0x2e, 0x58}, + {0x2f, 0x02},//10 fps + {0x30, 0x58}, + {0x31, 0x07}, + {0x32, 0x08}, + + +{0xfe, 0x00}, + + {0x00, 0x00} +}; + +static struct reginfo sensor_AntiBanding_60HZ[] = +{ + {0xfe, 0x00}, + {0x05, 0x00}, + {0x06, 0x6a}, + {0x07, 0x00}, + {0x08, 0x89}, + + {0xfe, 0x01}, + {0x29, 0x00}, + {0x2a, 0x7d}, + + {0x2b, 0x02}, + {0x2c, 0x71},//12 fps + {0x2d, 0x02}, + {0x2e, 0x71}, + {0x2f, 0x02},//10 fps + {0x30, 0x71}, + {0x31, 0x04}, + {0x32, 0xe2}, + + +{0xfe, 0x00}, + + + {0x00, 0x00} +}; +static struct reginfo *sensor_AntibandingSeqe[] = {sensor_AntiBanding_50HZ, sensor_AntiBanding_60HZ,NULL,}; +#endif + +#if CONFIG_SENSOR_DigitalZoom +static struct reginfo sensor_Zoom0[] = +{ + {0x0, 0x0}, +}; + +static struct reginfo sensor_Zoom1[] = +{ + {0x0, 0x0}, +}; + +static struct reginfo sensor_Zoom2[] = +{ + {0x0, 0x0}, +}; + + +static struct reginfo sensor_Zoom3[] = +{ + {0x0, 0x0}, +}; +static struct reginfo *sensor_ZoomSeqe[] = {sensor_Zoom0, sensor_Zoom1, sensor_Zoom2, sensor_Zoom3, NULL,}; +#endif +static const struct v4l2_querymenu sensor_menus[] = +{ + #if CONFIG_SENSOR_WhiteBalance + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 0, .name = "auto", .reserved = 0, }, { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 1, .name = "incandescent", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 2, .name = "fluorescent", .reserved = 0,}, { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 3, .name = "daylight", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 4, .name = "cloudy-daylight", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Effect + { .id = V4L2_CID_EFFECT, .index = 0, .name = "none", .reserved = 0,}, { .id = V4L2_CID_EFFECT, .index = 1, .name = "mono", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 2, .name = "negative", .reserved = 0,}, { .id = V4L2_CID_EFFECT, .index = 3, .name = "sepia", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 4, .name = "posterize", .reserved = 0,}, //{ .id = V4L2_CID_EFFECT, .index = 5, .name = "aqua", .reserved = 0,} , + #endif + + #if CONFIG_SENSOR_Scene + { .id = V4L2_CID_SCENE, .index = 0, .name = "auto", .reserved = 0,} ,{ .id = V4L2_CID_SCENE, .index = 1, .name = "night", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_AntiBanding + { .id = V4L2_CID_ANTIBANDING, .index = 0, .name = "50hz", .reserved = 0,} ,{ .id = V4L2_CID_ANTIBANDING, .index = 1, .name = "60hz", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Flash + { .id = V4L2_CID_FLASH, .index = 0, .name = "off", .reserved = 0, }, { .id = V4L2_CID_FLASH, .index = 1, .name = "auto", .reserved = 0,}, + { .id = V4L2_CID_FLASH, .index = 2, .name = "on", .reserved = 0,}, { .id = V4L2_CID_FLASH, .index = 3, .name = "torch", .reserved = 0,}, + #endif +}; + +static const struct v4l2_queryctrl sensor_controls[] = +{ + #if CONFIG_SENSOR_WhiteBalance + { + .id = V4L2_CID_DO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "White Balance Control", + .minimum = 0, + .maximum = 4, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Brightness + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness Control", + .minimum = -3, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Effect + { + .id = V4L2_CID_EFFECT, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Effect Control", + .minimum = 0, + .maximum = 4, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Exposure + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure Control", + .minimum = 0, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Saturation + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation Control", + .minimum = 0, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Contrast + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast Control", + .minimum = -3, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Mirror + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + #endif + + #if CONFIG_SENSOR_Flip + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + #endif + + #if CONFIG_SENSOR_Scene + { + .id = V4L2_CID_SCENE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Scene Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_AntiBanding + { + .id = V4L2_CID_ANTIBANDING, + .type = V4L2_CTRL_TYPE_MENU, + .name = "antibanding Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_DigitalZoom + { + .id = V4L2_CID_ZOOM_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DigitalZoom Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_ZOOM_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DigitalZoom Control", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Focus + { + .id = V4L2_CID_FOCUS_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Focus Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_FOCUS_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Focus Control", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 125, + }, + #endif + + #if CONFIG_SENSOR_Flash + { + .id = V4L2_CID_FLASH, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Flash Control", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif +}; + +static int sensor_probe(struct i2c_client *client, const struct i2c_device_id *did); +static int sensor_video_probe(struct soc_camera_device *icd, struct i2c_client *client); +static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl); +static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl); +static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg); +static int sensor_resume(struct soc_camera_device *icd); +static int sensor_set_bus_param(struct soc_camera_device *icd,unsigned long flags); +static unsigned long sensor_query_bus_param(struct soc_camera_device *icd); +#if CONFIG_SENSOR_Effect +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +#endif +#if CONFIG_SENSOR_WhiteBalance +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +#endif +static int sensor_deactivate(struct i2c_client *client); + +static struct soc_camera_ops sensor_ops = +{ + .suspend = sensor_suspend, + .resume = sensor_resume, + .set_bus_param = sensor_set_bus_param, + .query_bus_param = sensor_query_bus_param, + .controls = sensor_controls, + .menus = sensor_menus, + .num_controls = ARRAY_SIZE(sensor_controls), + .num_menus = ARRAY_SIZE(sensor_menus), +}; + +/* only one fixed colorspace per pixelcode */ +struct sensor_datafmt { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; +}; + +/* Find a data format by a pixel code in an array */ +static const struct sensor_datafmt *sensor_find_datafmt( + enum v4l2_mbus_pixelcode code, const struct sensor_datafmt *fmt, + int n) +{ + int i; + for (i = 0; i < n; i++) + if (fmt[i].code == code) + return fmt + i; + + return NULL; +} + +static const struct sensor_datafmt sensor_colour_fmts[] = { + //{V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG}, + {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG} +}; + +typedef struct sensor_info_priv_s +{ + int whiteBalance; + int brightness; + int contrast; + int saturation; + int effect; + int scene; + int antibanding; + int digitalzoom; + int focus; + int flash; + int exposure; + bool snap2preview; + bool video2preview; + unsigned char mirror; /* HFLIP */ + unsigned char flip; /* VFLIP */ + unsigned int winseqe_cur_addr; + struct sensor_datafmt fmt; + unsigned int funmodule_state; +} sensor_info_priv_t; + +struct sensor +{ + struct v4l2_subdev subdev; + struct i2c_client *client; + sensor_info_priv_t info_priv; + int model; /* V4L2_IDENT_OV* codes from v4l2-chip-ident.h */ +#if CONFIG_SENSOR_I2C_NOSCHED + atomic_t tasklock_cnt; +#endif + struct rk29camera_platform_data *sensor_io_request; + struct rk29camera_gpio_res *sensor_gpio_res; +}; + +static struct sensor* to_sensor(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct sensor, subdev); +} + +static int sensor_task_lock(struct i2c_client *client, int lock) +{ +#if CONFIG_SENSOR_I2C_NOSCHED + int cnt = 3; + struct sensor *sensor = to_sensor(client); + + if (lock) { + if (atomic_read(&sensor->tasklock_cnt) == 0) { + while ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt>0)) { + SENSOR_TR("\n %s will obtain i2c in atomic, but i2c bus is locked! Wait...\n",SENSOR_NAME_STRING()); + msleep(35); + cnt--; + } + if ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt<=0)) { + SENSOR_TR("\n %s obtain i2c fail in atomic!!\n",SENSOR_NAME_STRING()); + goto sensor_task_lock_err; + } + preempt_disable(); + } + + atomic_add(1, &sensor->tasklock_cnt); + } else { + if (atomic_read(&sensor->tasklock_cnt) > 0) { + atomic_sub(1, &sensor->tasklock_cnt); + + if (atomic_read(&sensor->tasklock_cnt) == 0) + preempt_enable(); + } + } + return 0; +sensor_task_lock_err: + return -1; +#else + return 0; +#endif + +} + +/* sensor register write */ +static int sensor_write(struct i2c_client *client, u8 reg, u8 val) +{ + int err,cnt; + u8 buf[2]; + struct i2c_msg msg[1]; + + buf[0] = reg & 0xFF; + buf[1] = val; + + msg->addr = client->addr; + msg->flags = client->flags; + msg->buf = buf; + msg->len = sizeof(buf); + msg->scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg->read_type = 0; /* fpga i2c:0==I2C_NORMAL : direct use number not enum for don't want include spi_fpga.h */ + + cnt = 3; + err = -EAGAIN; + + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + err = i2c_transfer(client->adapter, msg, 1); + + if (err >= 0) { + return 0; + } else { + SENSOR_TR("\n %s write reg(0x%x, val:0x%x) failed, try to write again!\n",SENSOR_NAME_STRING(),reg, val); + udelay(10); + } + } + + return err; +} + +/* sensor register read */ +static int sensor_read(struct i2c_client *client, u8 reg, u8 *val) +{ + int err,cnt; + //u8 buf[2]; + u8 buf[1]; + struct i2c_msg msg[2]; + + //buf[0] = reg >> 8; + buf[0] = reg; + buf[1] = reg & 0xFF; + + msg[0].addr = client->addr; + msg[0].flags = client->flags; + msg[0].buf = buf; + msg[0].len = sizeof(buf); + msg[0].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg[0].read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */ + + msg[1].addr = client->addr; + msg[1].flags = client->flags|I2C_M_RD; + msg[1].buf = buf; + msg[1].len = 1; + msg[1].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg[1].read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */ + + cnt = 1; + err = -EAGAIN; + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + err = i2c_transfer(client->adapter, msg, 2); + + if (err >= 0) { + *val = buf[0]; + return 0; + } else { + SENSOR_TR("\n %s read reg(0x%x val:0x%x) failed, try to read again! \n",SENSOR_NAME_STRING(),reg, *val); + udelay(10); + } + } + + return err; +} + +/* write a array of registers */ +static int sensor_write_array(struct i2c_client *client, struct reginfo *regarray) +{ + int err = 0, cnt; + int i = 0; +#if CONFIG_SENSOR_I2C_RDWRCHK + char valchk; +#endif + + cnt = 0; + if (sensor_task_lock(client, 1) < 0) + goto sensor_write_array_end; + + while (regarray[i].reg != 0) + { + err = sensor_write(client, regarray[i].reg, regarray[i].val); + if (err < 0) + { + if (cnt-- > 0) { + SENSOR_TR("%s..write failed current reg:0x%x, Write array again !\n", SENSOR_NAME_STRING(),regarray[i].reg); + i = 0; + continue; + } else { + SENSOR_TR("%s..write array failed!!!\n", SENSOR_NAME_STRING()); + err = -EPERM; + goto sensor_write_array_end; + } + } else { + #if CONFIG_SENSOR_I2C_RDWRCHK + sensor_read(client, regarray[i].reg, &valchk); + if (valchk != regarray[i].val) + SENSOR_TR("%s Reg:0x%x write(0x%x, 0x%x) fail\n",SENSOR_NAME_STRING(), regarray[i].reg, regarray[i].val, valchk); + #endif + } + i++; + } + +sensor_write_array_end: + sensor_task_lock(client,0); + return err; +} +#if CONFIG_SENSOR_I2C_RDWRCHK + + +static int sensor_check_array(struct i2c_client *client, struct reginfo *regarray) +{ + int ret; + int i = 0; + + u8 value; + + for(i=0;ipowerdown) { + ret = icl->powerdown(icd->pdev, on); + if (ret == RK29_CAM_IO_SUCCESS) { + if (on == 0) { + mdelay(2); + if (icl->reset) + icl->reset(icd->pdev); + } + } else if (ret == RK29_CAM_EIO_REQUESTFAIL) { + ret = -ENODEV; + goto sensor_power_end; + } + } + break; + } + case Sensor_Flash: + { + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + if (sensor->sensor_io_request && sensor->sensor_io_request->sensor_ioctrl) { + sensor->sensor_io_request->sensor_ioctrl(icd->pdev,Cam_Flash, on); + } + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown!",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } +sensor_power_end: + return ret; +} + +static int sensor_init(struct v4l2_subdev *sd, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + const struct sensor_datafmt *fmt; + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + int ret; + + SENSOR_DG("\n%s..%s.. \n",SENSOR_NAME_STRING(),__FUNCTION__); + + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + /* soft reset */ + if (sensor_task_lock(client,1)<0) + goto sensor_INIT_ERR; + /* ret = sensor_write(client, 0x12, 0x80); + if (ret != 0) + { + SENSOR_TR("%s soft reset sensor failed\n",SENSOR_NAME_STRING()); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + mdelay(5); */ //delay 5 microseconds + + ret = sensor_write_array(client, sensor_init_data); + if (ret != 0) + { + SENSOR_TR("error: %s initial failed\n",SENSOR_NAME_STRING()); + goto sensor_INIT_ERR; + } + + sensor_task_lock(client,0); + + sensor->info_priv.winseqe_cur_addr = (int)SENSOR_INIT_WINSEQADR; + fmt = sensor_find_datafmt(SENSOR_INIT_PIXFMT,sensor_colour_fmts, ARRAY_SIZE(sensor_colour_fmts)); + if (!fmt) { + SENSOR_TR("error: %s initial array colour fmts is not support!!",SENSOR_NAME_STRING()); + ret = -EINVAL; + goto sensor_INIT_ERR; + } + sensor->info_priv.fmt = *fmt; + + /* sensor sensor information for initialization */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + if (qctrl) + sensor->info_priv.whiteBalance = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_BRIGHTNESS); + if (qctrl) + sensor->info_priv.brightness = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + if (qctrl) + sensor->info_priv.effect = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EXPOSURE); + if (qctrl) + sensor->info_priv.exposure = qctrl->default_value; + + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SATURATION); + if (qctrl) + sensor->info_priv.saturation = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_CONTRAST); + if (qctrl) + sensor->info_priv.contrast = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_HFLIP); + if (qctrl) + sensor->info_priv.mirror = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_VFLIP); + if (qctrl) + sensor->info_priv.flip = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SCENE); + if (qctrl) + sensor->info_priv.scene = qctrl->default_value; + #if CONFIG_SENSOR_AntiBanding + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ANTIBANDING); + if (qctrl) + sensor->info_priv.antibanding = qctrl->default_value; + #endif + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE); + if (qctrl) + sensor->info_priv.digitalzoom = qctrl->default_value; + + /* ddl@rock-chips.com : if sensor support auto focus and flash, programer must run focus and flash code */ + #if CONFIG_SENSOR_Focus + sensor_set_focus(); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FOCUS_ABSOLUTE); + if (qctrl) + sensor->info_priv.focus = qctrl->default_value; + #endif + + #if CONFIG_SENSOR_Flash + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FLASH); + if (qctrl) + sensor->info_priv.flash = qctrl->default_value; + #endif + + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),((val == 0)?__FUNCTION__:"sensor_reinit"),icd->user_width,icd->user_height); + sensor->info_priv.funmodule_state |= SENSOR_INIT_IS_OK; + return 0; +sensor_INIT_ERR: + sensor->info_priv.funmodule_state &= ~SENSOR_INIT_IS_OK; + sensor_task_lock(client,0); + sensor_deactivate(client); + return ret; +} + +static int sensor_deactivate(struct i2c_client *client) +{ + struct soc_camera_device *icd = client->dev.platform_data; + //u8 reg_val; + struct sensor *sensor = to_sensor(client); + SENSOR_DG("\n%s..%s.. Enter\n",SENSOR_NAME_STRING(),__FUNCTION__); + + /* ddl@rock-chips.com : all sensor output pin must change to input for other sensor */ + sensor_ioctrl(icd, Sensor_PowerDown, 1); + msleep(10); + + /* ddl@rock-chips.com : sensor config init width , because next open sensor quickly(soc_camera_open -> Try to configure with default parameters) */ + icd->user_width = SENSOR_INIT_WIDTH; + icd->user_height = SENSOR_INIT_HEIGHT; + sensor->info_priv.funmodule_state &= ~SENSOR_INIT_IS_OK; + + return 0; +} +static struct reginfo sensor_power_down_sequence[]= +{ + {0x00,0x00} +}; +static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg) +{ + int ret; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if (pm_msg.event == PM_EVENT_SUSPEND) { + SENSOR_DG("\n %s Enter Suspend.. \n", SENSOR_NAME_STRING()); + ret = sensor_write_array(client, sensor_power_down_sequence) ; + if (ret != 0) { + SENSOR_TR("\n %s..%s WriteReg Fail.. \n", SENSOR_NAME_STRING(),__FUNCTION__); + return ret; + } else { + ret = sensor_ioctrl(icd, Sensor_PowerDown, 1); + if (ret < 0) { + SENSOR_TR("\n %s suspend fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + } + } else { + SENSOR_TR("\n %s cann't suppout Suspend..\n",SENSOR_NAME_STRING()); + return -EINVAL; + } + return 0; +} + +static int sensor_resume(struct soc_camera_device *icd) +{ + int ret; + + ret = sensor_ioctrl(icd, Sensor_PowerDown, 0); + if (ret < 0) { + SENSOR_TR("\n %s resume fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + + SENSOR_DG("\n %s Enter Resume.. \n", SENSOR_NAME_STRING()); + + return 0; + +} + +static int sensor_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + + return 0; +} + +static unsigned long sensor_query_bus_param(struct soc_camera_device *icd) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + unsigned long flags = SENSOR_BUS_PARAM; + + return soc_camera_apply_sensor_flags(icl, flags); +} + +static int sensor_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + + mf->width = icd->user_width; + mf->height = icd->user_height; + mf->code = sensor->info_priv.fmt.code; + mf->colorspace = sensor->info_priv.fmt.colorspace; + mf->field = V4L2_FIELD_NONE; + + return 0; +} +/* +static bool sensor_fmt_capturechk(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + bool ret = false; + + if ((mf->width == 1024) && (mf->height == 768)) { + ret = true; + } else if ((mf->width == 1280) && (mf->height == 1024)) { + ret = true; + } else if ((mf->width == 1600) && (mf->height == 1200)) { + ret = true; + } else if ((mf->width == 2048) && (mf->height == 1536)) { + ret = true; + } else if ((mf->width == 2592) && (mf->height == 1944)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is capture format\n", __FUNCTION__, mf->width, mf->height); + return ret; +} + +static bool sensor_fmt_videochk(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + bool ret = false; + + if ((mf->width == 1280) && (mf->height == 720)) { + ret = true; + } else if ((mf->width == 1920) && (mf->height == 1080)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is video format\n", __FUNCTION__, mf->width, mf->height); + return ret; +} +*/ +static int sensor_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + const struct sensor_datafmt *fmt; + struct sensor *sensor = to_sensor(client); +// const struct v4l2_queryctrl *qctrl; +// struct soc_camera_device *icd = client->dev.platform_data; + struct reginfo *winseqe_set_addr=NULL; + int ret=0, set_w,set_h; + + fmt = sensor_find_datafmt(mf->code, sensor_colour_fmts, + ARRAY_SIZE(sensor_colour_fmts)); + if (!fmt) { + ret = -EINVAL; + goto sensor_s_fmt_end; + } + + if (sensor->info_priv.fmt.code != mf->code) { + switch (mf->code) + { + case V4L2_MBUS_FMT_YUYV8_2X8: + { + winseqe_set_addr = sensor_ClrFmt_YUYV; + break; + } + case V4L2_MBUS_FMT_UYVY8_2X8: + { + winseqe_set_addr = sensor_ClrFmt_UYVY; + break; + } + default: + break; + } + if (winseqe_set_addr != NULL) { + sensor_write_array(client, winseqe_set_addr); + sensor->info_priv.fmt.code = mf->code; + sensor->info_priv.fmt.colorspace= mf->colorspace; + SENSOR_DG("%s v4l2_mbus_code:%d set success!\n", SENSOR_NAME_STRING(),mf->code); + } else { + SENSOR_TR("%s v4l2_mbus_code:%d is invalidate!\n", SENSOR_NAME_STRING(),mf->code); + } + } + + set_w = mf->width; + set_h = mf->height; + + if (((set_w <= 176) && (set_h <= 144)) && sensor_qcif[0].reg) + { + winseqe_set_addr = sensor_qcif; + set_w = 176; + set_h = 144; + } + else if (((set_w <= 320) && (set_h <= 240)) && sensor_qvga[0].reg) + { + winseqe_set_addr = sensor_qvga; + set_w = 320; + set_h = 240; + } + else if (((set_w <= 352) && (set_h<= 288)) && sensor_cif[0].reg) + { + winseqe_set_addr = sensor_cif; + set_w = 352; + set_h = 288; + } + else if (((set_w <= 640) && (set_h <= 480)) && sensor_vga[0].reg) + { + winseqe_set_addr = sensor_vga; + set_w = 640; + set_h = 480; + } + else if (((set_w <= 800) && (set_h <= 600)) && sensor_svga[0].reg) + { + winseqe_set_addr = sensor_svga; + set_w = 800; + set_h = 600; + } + else if (((set_w <= 1280) && (set_h <= 1024)) && sensor_sxga[0].reg) + { + winseqe_set_addr = sensor_sxga; + set_w = 1280; + set_h = 1024; + } + else + { + winseqe_set_addr = SENSOR_INIT_WINSEQADR; /* ddl@rock-chips.com : Sensor output smallest size if isn't support app */ + set_w = SENSOR_INIT_WIDTH; + set_h = SENSOR_INIT_HEIGHT; + SENSOR_TR("\n %s..%s Format is Invalidate. pix->width = %d.. pix->height = %d\n",SENSOR_NAME_STRING(),__FUNCTION__,mf->width,mf->height); + } + + if ((int)winseqe_set_addr != sensor->info_priv.winseqe_cur_addr) { + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,mf) == true) { /* ddl@rock-chips.com : Capture */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_On); + SENSOR_DG("%s flash on in capture!\n", SENSOR_NAME_STRING()); + } + } else { /* ddl@rock-chips.com : Video */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_DG("%s flash off in preivew!\n", SENSOR_NAME_STRING()); + } + } + #endif + ret |= sensor_write_array(client, winseqe_set_addr); + if (ret != 0) { + SENSOR_TR("%s set format capability failed\n", SENSOR_NAME_STRING()); + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,mf) == true) { + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_TR("%s Capture format set fail, flash off !\n", SENSOR_NAME_STRING()); + } + } + #endif + goto sensor_s_fmt_end; + } + + sensor->info_priv.winseqe_cur_addr = (int)winseqe_set_addr; + + + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),__FUNCTION__,set_w,set_h); + } + else + { + SENSOR_DG("\n %s .. Current Format is validate. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),set_w,set_h); + } + + mf->width = set_w; + mf->height = set_h; + +sensor_s_fmt_end: + return ret; +} + +static int sensor_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct sensor *sensor = to_sensor(client); + const struct sensor_datafmt *fmt; + int ret = 0,set_w,set_h; + + fmt = sensor_find_datafmt(mf->code, sensor_colour_fmts, + ARRAY_SIZE(sensor_colour_fmts)); + if (fmt == NULL) { + fmt = &sensor->info_priv.fmt; + mf->code = fmt->code; + } + + if (mf->height > SENSOR_MAX_HEIGHT) + mf->height = SENSOR_MAX_HEIGHT; + else if (mf->height < SENSOR_MIN_HEIGHT) + mf->height = SENSOR_MIN_HEIGHT; + + if (mf->width > SENSOR_MAX_WIDTH) + mf->width = SENSOR_MAX_WIDTH; + else if (mf->width < SENSOR_MIN_WIDTH) + mf->width = SENSOR_MIN_WIDTH; + + set_w = mf->width; + set_h = mf->height; + + if (((set_w <= 176) && (set_h <= 144)) && sensor_qcif[0].reg) + { + set_w = 176; + set_h = 144; + } + else if (((set_w <= 320) && (set_h <= 240)) && sensor_qvga[0].reg) + { + set_w = 320; + set_h = 240; + } + else if (((set_w <= 352) && (set_h<= 288)) && sensor_cif[0].reg) + { + set_w = 352; + set_h = 288; + } + else if (((set_w <= 640) && (set_h <= 480)) && sensor_vga[0].reg) + { + set_w = 640; + set_h = 480; + } + else if (((set_w <= 800) && (set_h <= 600)) && sensor_svga[0].reg) + { + set_w = 800; + set_h = 600; + } + else if (((set_w <= 1280) && (set_h <= 1024)) && sensor_sxga[0].reg) + { + set_w = 1280; + set_h = 1024; + } + else + { /* ddl@rock-chips.com : Sensor output smallest size if isn't support app */ + set_w = SENSOR_INIT_WIDTH; + set_h = SENSOR_INIT_HEIGHT; + } + + mf->width = set_w; + mf->height = set_h; + mf->colorspace = fmt->colorspace; + + return ret; +} + + static int sensor_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *id) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) + return -EINVAL; + + if (id->match.addr != client->addr) + return -ENODEV; + + id->ident = SENSOR_V4L2_IDENT; /* ddl@rock-chips.com : Return OV9650 identifier */ + id->revision = 0; + + return 0; +} +#if CONFIG_SENSOR_Brightness +static int sensor_set_brightness(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_BrightnessSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_BrightnessSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Effect +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_EffectSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_EffectSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Exposure +static int sensor_set_exposure(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_ExposureSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_ExposureSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Saturation +static int sensor_set_saturation(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_SaturationSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_SaturationSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Contrast +static int sensor_set_contrast(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_ContrastSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_ContrastSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Mirror +static int sensor_set_mirror(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_MirrorSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_MirrorSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Flip +static int sensor_set_flip(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_FlipSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_FlipSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Scene +static int sensor_set_scene(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_SceneSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_SceneSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif + +#if CONFIG_SENSOR_AntiBanding +static int sensor_set_antibanding(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_AntibandingSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_AntibandingSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif + +#if CONFIG_SENSOR_WhiteBalance +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_WhiteBalanceSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_WhiteBalanceSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_DigitalZoom +static int sensor_set_digitalzoom(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int *value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl_info; + int digitalzoom_cur, digitalzoom_total; + + qctrl_info = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE); + if (qctrl_info) + return -EINVAL; + + digitalzoom_cur = sensor->info_priv.digitalzoom; + digitalzoom_total = qctrl_info->maximum; + + if ((value > 0) && (digitalzoom_cur >= digitalzoom_total)) + { + SENSOR_TR("%s digitalzoom is maximum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur); + return -EINVAL; + } + + if ((value < 0) && (digitalzoom_cur <= qctrl_info->minimum)) + { + SENSOR_TR("%s digitalzoom is minimum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur); + return -EINVAL; + } + + if ((value > 0) && ((digitalzoom_cur + value) > digitalzoom_total)) + { + value = digitalzoom_total - digitalzoom_cur; + } + + if ((value < 0) && ((digitalzoom_cur + value) < 0)) + { + value = 0 - digitalzoom_cur; + } + + digitalzoom_cur += value; + + if (sensor_ZoomSeqe[digitalzoom_cur] != NULL) + { + if (sensor_write_array(client, sensor_ZoomSeqe[digitalzoom_cur]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Flash +static int sensor_set_flash(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) { + if (value == 3) { /* ddl@rock-chips.com: torch */ + sensor_ioctrl(icd, Sensor_Flash, Flash_Torch); /* Flash On */ + } else { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif + +static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + + qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + return -EINVAL; + } + + switch (ctrl->id) + { + case V4L2_CID_BRIGHTNESS: + { + ctrl->value = sensor->info_priv.brightness; + break; + } + case V4L2_CID_SATURATION: + { + ctrl->value = sensor->info_priv.saturation; + break; + } + case V4L2_CID_CONTRAST: + { + ctrl->value = sensor->info_priv.contrast; + break; + } + case V4L2_CID_DO_WHITE_BALANCE: + { + ctrl->value = sensor->info_priv.whiteBalance; + break; + } + case V4L2_CID_EXPOSURE: + { + ctrl->value = sensor->info_priv.exposure; + break; + } + case V4L2_CID_HFLIP: + { + ctrl->value = sensor->info_priv.mirror; + break; + } + case V4L2_CID_VFLIP: + { + ctrl->value = sensor->info_priv.flip; + break; + } + default : + break; + } + return 0; +} + + + +static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct sensor *sensor = to_sensor(client); + struct soc_camera_device *icd = client->dev.platform_data; + const struct v4l2_queryctrl *qctrl; + + + qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + return -EINVAL; + } + + switch (ctrl->id) + { +#if CONFIG_SENSOR_Brightness + case V4L2_CID_BRIGHTNESS: + { + if (ctrl->value != sensor->info_priv.brightness) + { + if (sensor_set_brightness(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.brightness = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Exposure + case V4L2_CID_EXPOSURE: + { + if (ctrl->value != sensor->info_priv.exposure) + { + if (sensor_set_exposure(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.exposure = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Saturation + case V4L2_CID_SATURATION: + { + if (ctrl->value != sensor->info_priv.saturation) + { + if (sensor_set_saturation(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.saturation = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Contrast + case V4L2_CID_CONTRAST: + { + if (ctrl->value != sensor->info_priv.contrast) + { + if (sensor_set_contrast(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.contrast = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_WhiteBalance + case V4L2_CID_DO_WHITE_BALANCE: + { + if (ctrl->value != sensor->info_priv.whiteBalance) + { + if (sensor_set_whiteBalance(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.whiteBalance = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Mirror + case V4L2_CID_HFLIP: + { + if (ctrl->value != sensor->info_priv.mirror) + { + if (sensor_set_mirror(icd, qctrl,ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.mirror = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Flip + case V4L2_CID_VFLIP: + { + if (ctrl->value != sensor->info_priv.flip) + { + if (sensor_set_flip(icd, qctrl,ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.flip = ctrl->value; + } + break; + } +#endif + default: + break; + } + + return 0; +} +static int sensor_g_ext_control(struct soc_camera_device *icd , struct v4l2_ext_control *ext_ctrl) +{ + const struct v4l2_queryctrl *qctrl; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + return -EINVAL; + } + + switch (ext_ctrl->id) + { + case V4L2_CID_SCENE: + { + ext_ctrl->value = sensor->info_priv.scene; + break; + } + #if CONFIG_SENSOR_AntiBanding + case V4L2_CID_ANTIBANDING: + { + ext_ctrl->value = sensor->info_priv.antibanding; + break; + } + #endif + case V4L2_CID_EFFECT: + { + ext_ctrl->value = sensor->info_priv.effect; + break; + } + case V4L2_CID_ZOOM_ABSOLUTE: + { + ext_ctrl->value = sensor->info_priv.digitalzoom; + break; + } + case V4L2_CID_ZOOM_RELATIVE: + { + return -EINVAL; + } + case V4L2_CID_FOCUS_ABSOLUTE: + { + ext_ctrl->value = sensor->info_priv.focus; + break; + } + case V4L2_CID_FOCUS_RELATIVE: + { + return -EINVAL; + } + case V4L2_CID_FLASH: + { + ext_ctrl->value = sensor->info_priv.flash; + break; + } + default : + break; + } + return 0; +} +static int sensor_s_ext_control(struct soc_camera_device *icd, struct v4l2_ext_control *ext_ctrl) +{ + const struct v4l2_queryctrl *qctrl; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + int val_offset; + + qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + return -EINVAL; + } + + val_offset = 0; + switch (ext_ctrl->id) + { +#if CONFIG_SENSOR_Scene + case V4L2_CID_SCENE: + { + if (ext_ctrl->value != sensor->info_priv.scene) + { + if (sensor_set_scene(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.scene = ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_AntiBanding + case V4L2_CID_ANTIBANDING: + { + if (ext_ctrl->value != sensor->info_priv.antibanding) + { + if (sensor_set_antibanding(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.antibanding = ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Effect + case V4L2_CID_EFFECT: + { + if (ext_ctrl->value != sensor->info_priv.effect) + { + if (sensor_set_effect(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.effect= ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_DigitalZoom + case V4L2_CID_ZOOM_ABSOLUTE: + { + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; + + if (ext_ctrl->value != sensor->info_priv.digitalzoom) + { + val_offset = ext_ctrl->value -sensor->info_priv.digitalzoom; + + if (sensor_set_digitalzoom(icd, qctrl,&val_offset) != 0) + return -EINVAL; + sensor->info_priv.digitalzoom += val_offset; + + SENSOR_DG("%s digitalzoom is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.digitalzoom); + } + + break; + } + case V4L2_CID_ZOOM_RELATIVE: + { + if (ext_ctrl->value) + { + if (sensor_set_digitalzoom(icd, qctrl,&ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.digitalzoom += ext_ctrl->value; + + SENSOR_DG("%s digitalzoom is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.digitalzoom); + } + break; + } +#endif +#if CONFIG_SENSOR_Focus + case V4L2_CID_FOCUS_ABSOLUTE: + { + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; + + if (ext_ctrl->value != sensor->info_priv.focus) + { + val_offset = ext_ctrl->value -sensor->info_priv.focus; + + sensor->info_priv.focus += val_offset; + } + + break; + } + case V4L2_CID_FOCUS_RELATIVE: + { + if (ext_ctrl->value) + { + sensor->info_priv.focus += ext_ctrl->value; + + SENSOR_DG("%s focus is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.focus); + } + break; + } +#endif +#if CONFIG_SENSOR_Flash + case V4L2_CID_FLASH: + { + if (sensor_set_flash(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.flash = ext_ctrl->value; + + SENSOR_DG("%s flash is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.flash); + break; + } +#endif + default: + break; + } + + return 0; +} + +static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + int i, error_cnt=0, error_idx=-1; + + + for (i=0; icount; i++) { + if (sensor_g_ext_control(icd, &ext_ctrl->controls[i]) != 0) { + error_cnt++; + error_idx = i; + } + } + + if (error_cnt > 1) + error_idx = ext_ctrl->count; + + if (error_idx != -1) { + ext_ctrl->error_idx = error_idx; + return -EINVAL; + } else { + return 0; + } +} + +static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + int i, error_cnt=0, error_idx=-1; + + + for (i=0; icount; i++) { + if (sensor_s_ext_control(icd, &ext_ctrl->controls[i]) != 0) { + error_cnt++; + error_idx = i; + } + } + + if (error_cnt > 1) + error_idx = ext_ctrl->count; + + if (error_idx != -1) { + ext_ctrl->error_idx = error_idx; + return -EINVAL; + } else { + return 0; + } +} + +/* Interface active, can use i2c. If it fails, it can indeed mean, that + * this wasn't our capture interface, so, we wait for the right one */ +static int sensor_video_probe(struct soc_camera_device *icd, + struct i2c_client *client) +{ + char pid = 0; + int ret; + struct sensor *sensor = to_sensor(client); + + /* We must have a parent by now. And it cannot be a wrong one. + * So this entire test is completely redundant. */ + if (!icd->dev.parent || + to_soc_camera_host(icd->dev.parent)->nr != icd->iface) + return -ENODEV; + + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + SENSOR_TR("power down %s failed\n",SENSOR_NAME_STRING()); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + /* soft reset */ + /* ret = sensor_write(client, 0x12, 0x80); + if (ret != 0) + { + SENSOR_TR("soft reset %s failed\n",SENSOR_NAME_STRING()); + return -ENODEV; + } + mdelay(50); *///delay 5 microseconds + + /* check if it is an sensor sensor */ + ret = sensor_write(client, 0xfc, 0x16); //before read id should write 0xfc + msleep(20); + ret = sensor_read(client, 0x00, &pid); + if (ret != 0) { + SENSOR_TR("%s read chip id high byte failed\n",SENSOR_NAME_STRING()); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + SENSOR_DG("\n %s pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + if (pid == SENSOR_ID) { + sensor->model = SENSOR_V4L2_IDENT; + } else { + SENSOR_TR("error: %s mismatched pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + return 0; + +sensor_video_probe_err: + + return ret; +} + +static long sensor_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + int ret = 0; +#if CONFIG_SENSOR_Flash + int i; +#endif + + SENSOR_DG("\n%s..%s..cmd:%x \n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + switch (cmd) + { + case RK29_CAM_SUBDEV_DEACTIVATE: + { + sensor_deactivate(client); + break; + } + + case RK29_CAM_SUBDEV_IOREQUEST: + { + sensor->sensor_io_request = (struct rk29camera_platform_data*)arg; + if (sensor->sensor_io_request != NULL) { + int j = 0; + for(j = 0;j < RK29_CAM_SUPPORT_NUMS;j++){ + if (sensor->sensor_io_request->gpio_res[j].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[j].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[j]; + break; + } + } + if(j == RK29_CAM_SUPPORT_NUMS){ + SENSOR_TR("%s %s RK_CAM_SUBDEV_IOREQUEST fail\n",SENSOR_NAME_STRING(),__FUNCTION__); + ret = -EINVAL; + goto sensor_ioctl_end; + } + } + + /* ddl@rock-chips.com : if gpio_flash havn't been set in board-xxx.c, sensor driver must notify is not support flash control + for this project */ + #if CONFIG_SENSOR_Flash + if (sensor->sensor_gpio_res) { + if (sensor->sensor_gpio_res->gpio_flash == INVALID_GPIO) { + for (i = 0; i < icd->ops->num_controls; i++) { + if (V4L2_CID_FLASH == icd->ops->controls[i].id) { + memset((char*)&icd->ops->controls[i],0x00,sizeof(struct v4l2_queryctrl)); + } + } + sensor->info_priv.flash = 0xff; + SENSOR_DG("%s flash gpio is invalidate!\n",SENSOR_NAME_STRING()); + } + } + #endif + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown !\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } +sensor_ioctl_end: + return ret; + +} +static int sensor_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + if (index >= ARRAY_SIZE(sensor_colour_fmts)) + return -EINVAL; + + *code = sensor_colour_fmts[index].code; + return 0; +} + +static struct v4l2_subdev_core_ops sensor_subdev_core_ops = { + .init = sensor_init, + .g_ctrl = sensor_g_control, + .s_ctrl = sensor_s_control, + .g_ext_ctrls = sensor_g_ext_controls, + .s_ext_ctrls = sensor_s_ext_controls, + .g_chip_ident = sensor_g_chip_ident, + .ioctl = sensor_ioctl, +}; + +static struct v4l2_subdev_video_ops sensor_subdev_video_ops = { + .s_mbus_fmt = sensor_s_fmt, + .g_mbus_fmt = sensor_g_fmt, + .try_mbus_fmt = sensor_try_fmt, + .enum_mbus_fmt = sensor_enum_fmt, +}; + +static struct v4l2_subdev_ops sensor_subdev_ops = { + .core = &sensor_subdev_core_ops, + .video = &sensor_subdev_video_ops, +}; + +static int sensor_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct sensor *sensor; + struct soc_camera_device *icd = client->dev.platform_data; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct soc_camera_link *icl; + int ret; + + SENSOR_DG("\n%s..%s..%d..\n",__FUNCTION__,__FILE__,__LINE__); + if (!icd) { + dev_err(&client->dev, "%s: missing soc-camera data!\n",SENSOR_NAME_STRING()); + return -EINVAL; + } + + icl = to_soc_camera_link(icd); + if (!icl) { + dev_err(&client->dev, "%s driver needs platform data\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { + dev_warn(&adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_I2C\n"); + return -EIO; + } + + sensor = kzalloc(sizeof(struct sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + v4l2_i2c_subdev_init(&sensor->subdev, client, &sensor_subdev_ops); + + /* Second stage probe - when a capture adapter is there */ + icd->ops = &sensor_ops; + + sensor->info_priv.fmt = sensor_colour_fmts[0]; + + #if CONFIG_SENSOR_I2C_NOSCHED + atomic_set(&sensor->tasklock_cnt,0); + #endif + + ret = sensor_video_probe(icd, client); + if (ret < 0) { + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + kfree(sensor); + sensor = NULL; + } + + SENSOR_DG("\n%s..%s..%d ret = %x \n",__FUNCTION__,__FILE__,__LINE__,ret); + return ret; +} + +static int sensor_remove(struct i2c_client *client) +{ + struct sensor *sensor = to_sensor(client); + struct soc_camera_device *icd = client->dev.platform_data; + + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + client->driver = NULL; + kfree(sensor); + sensor = NULL; + return 0; +} + +static const struct i2c_device_id sensor_id[] = { + {SENSOR_NAME_STRING(), 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sensor_id); + +static struct i2c_driver sensor_i2c_driver = { + .driver = { + .name = SENSOR_NAME_STRING(), + }, + .probe = sensor_probe, + .remove = sensor_remove, + .id_table = sensor_id, +}; + +static int __init sensor_mod_init(void) +{ + SENSOR_DG("\n%s..%s.. \n",__FUNCTION__,SENSOR_NAME_STRING()); + return i2c_add_driver(&sensor_i2c_driver); +} + +static void __exit sensor_mod_exit(void) +{ + i2c_del_driver(&sensor_i2c_driver); +} + +device_initcall_sync(sensor_mod_init); +module_exit(sensor_mod_exit); + +MODULE_DESCRIPTION(SENSOR_NAME_STRING(Camera sensor driver)); +MODULE_AUTHOR("ddl "); +MODULE_LICENSE("GPL"); + + diff --git a/drivers/media/video/s5k5ca.c b/drivers/media/video/s5k5ca.c new file mode 100755 index 000000000000..0b3e431ca4d0 --- /dev/null +++ b/drivers/media/video/s5k5ca.c @@ -0,0 +1,6093 @@ +/* + * Driver for OV5642 CMOS Image Sensor from OmniVision + * + * Copyright (C) 2008, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "s5k5ca.h" + +#define CURRENT_8MA + +static int debug; +module_param(debug, int, S_IRUGO|S_IWUSR); + +#define dprintk(level, fmt, arg...) do { \ + if (debug >= level) \ + printk(KERN_WARNING fmt , ## arg); } while (0) + +#define SENSOR_TR(format, ...) printk(KERN_ERR format, ## __VA_ARGS__) +#define SENSOR_DG(format, ...) dprintk(1, format, ## __VA_ARGS__) + + +#define _CONS(a,b) a##b +#define CONS(a,b) _CONS(a,b) + +#define __STR(x) #x +#define _STR(x) __STR(x) +#define STR(x) _STR(x) + +#define MIN(x,y) ((xy) ? x: y) + +/* Sensor Driver Configuration */ +#define SENSOR_NAME RK29_CAM_SENSOR_S5K5CA +#define SENSOR_V4L2_IDENT V4L2_IDENT_S5K5CA +#define SENSOR_ID 0x05ca +#define SENSOR_ID_REG SEQUENCE_END +#define SENSOR_RESET_REG SEQUENCE_END +#define SENSOR_RESET_VAL 0x00 +#define SENSOR_MIN_WIDTH 640 +#define SENSOR_MIN_HEIGHT 480 +#define SENSOR_MAX_WIDTH 2048 +#define SENSOR_MAX_HEIGHT 1536 +#define SENSOR_INIT_WIDTH 640 /* Sensor pixel size for sensor_init_data array */ +#define SENSOR_INIT_HEIGHT 480 +#define SENSOR_INIT_WINSEQADR sensor_vga +#define SENSOR_INIT_PIXFMT V4L2_MBUS_FMT_UYVY8_2X8 + +#define CONFIG_SENSOR_WhiteBalance 1 +#define CONFIG_SENSOR_Brightness 0 +#define CONFIG_SENSOR_Contrast 0 +#define CONFIG_SENSOR_Saturation 0 +#define CONFIG_SENSOR_Effect 1 +#define CONFIG_SENSOR_Scene 1 +#define CONFIG_SENSOR_AntiBanding 0 +#define CONFIG_SENSOR_DigitalZoom 0 +#define CONFIG_SENSOR_Focus 0 +#define CONFIG_SENSOR_Exposure 0 +#define CONFIG_SENSOR_Flash 0 +#define CONFIG_SENSOR_Mirror 0 +#define CONFIG_SENSOR_Flip 0 +#define CONFIG_SENSOR_Focus 0 + + +#define CONFIG_SENSOR_I2C_SPEED 400000 /* Hz */ +/* Sensor write register continues by preempt_disable/preempt_enable for current process not be scheduled */ +#define CONFIG_SENSOR_I2C_NOSCHED 0 +#define CONFIG_SENSOR_I2C_RDWRCHK 0 + + +#define SENSOR_BUS_PARAM (SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |\ + SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |\ + SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8 |SOCAM_MCLK_24MHZ) + +#define COLOR_TEMPERATURE_CLOUDY_DN 6500 +#define COLOR_TEMPERATURE_CLOUDY_UP 8000 +#define COLOR_TEMPERATURE_CLEARDAY_DN 5000 +#define COLOR_TEMPERATURE_CLEARDAY_UP 6500 +#define COLOR_TEMPERATURE_OFFICE_DN 3500 +#define COLOR_TEMPERATURE_OFFICE_UP 5000 +#define COLOR_TEMPERATURE_HOME_DN 2500 +#define COLOR_TEMPERATURE_HOME_UP 3500 + +#define SENSOR_NAME_STRING(a) STR(CONS(SENSOR_NAME, a)) +#define SENSOR_NAME_VARFUN(a) CONS(SENSOR_NAME, a) + +#define SENSOR_AF_IS_ERR (0x00<<0) +#define SENSOR_AF_IS_OK (0x01<<0) +#define SENSOR_INIT_IS_ERR (0x00<<28) +#define SENSOR_INIT_IS_OK (0x01<<28) + +#if CONFIG_SENSOR_Focus +#define SENSOR_AF_MODE_INFINITY 0 +#define SENSOR_AF_MODE_MACRO 1 +#define SENSOR_AF_MODE_FIXED 2 +#define SENSOR_AF_MODE_AUTO 3 +#define SENSOR_AF_MODE_CONTINUOUS 4 +#define SENSOR_AF_MODE_CLOSE 5 +#endif + +/* init 640X480 SVGA */ +static struct reginfo sensor_init_data[] = +{ + {0xFCFC, 0xD000}, //Reset // + {0x0010, 0x0001}, //Clear host interrupt so main will wait // + {0x1030, 0x0000}, //ARM go // + {0x0014, 0x0001}, //Wait100mSec // + {SEQUENCE_WAIT_MS,100}, //DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + + //tp + {0x0028, 0x7000}, + {0x002A, 0x2CF8}, + {0x0F12, 0xB510}, + {0x0F12, 0x4827}, + {0x0F12, 0x21C0}, + {0x0F12, 0x8041}, + {0x0F12, 0x4825}, + {0x0F12, 0x4A26}, + {0x0F12, 0x3020}, + {0x0F12, 0x8382}, + {0x0F12, 0x1D12}, + {0x0F12, 0x83C2}, + {0x0F12, 0x4822}, + {0x0F12, 0x3040}, + {0x0F12, 0x8041}, + {0x0F12, 0x4821}, + {0x0F12, 0x4922}, + {0x0F12, 0x3060}, + {0x0F12, 0x8381}, + {0x0F12, 0x1D09}, + {0x0F12, 0x83C1}, + {0x0F12, 0x4821}, + {0x0F12, 0x491D}, + {0x0F12, 0x8802}, + {0x0F12, 0x3980}, + {0x0F12, 0x804A}, + {0x0F12, 0x8842}, + {0x0F12, 0x808A}, + {0x0F12, 0x8882}, + {0x0F12, 0x80CA}, + {0x0F12, 0x88C2}, + {0x0F12, 0x810A}, + {0x0F12, 0x8902}, + {0x0F12, 0x491C}, + {0x0F12, 0x80CA}, + {0x0F12, 0x8942}, + {0x0F12, 0x814A}, + {0x0F12, 0x8982}, + {0x0F12, 0x830A}, + {0x0F12, 0x89C2}, + {0x0F12, 0x834A}, + {0x0F12, 0x8A00}, + {0x0F12, 0x4918}, + {0x0F12, 0x8188}, + {0x0F12, 0x4918}, + {0x0F12, 0x4819}, + {0x0F12, 0xF000}, + {0x0F12, 0xFA0C},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x4918}, + {0x0F12, 0x4819}, + {0x0F12, 0x6341}, + {0x0F12, 0x4919}, + {0x0F12, 0x4819}, + {0x0F12, 0xF000}, + {0x0F12, 0xFA05},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x4816}, + {0x0F12, 0x4918}, + {0x0F12, 0x3840}, + {0x0F12, 0x62C1}, + {0x0F12, 0x4918}, + {0x0F12, 0x3880}, + {0x0F12, 0x63C1}, + {0x0F12, 0x4917}, + {0x0F12, 0x6301}, + {0x0F12, 0x4917}, + {0x0F12, 0x3040}, + {0x0F12, 0x6181}, + {0x0F12, 0x4917}, + {0x0F12, 0x4817}, + {0x0F12, 0xF000}, + {0x0F12, 0xF9F5},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x4917}, + {0x0F12, 0x4817}, + {0x0F12, 0xF000}, + {0x0F12, 0xF9F1},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x4917}, + {0x0F12, 0x4817}, + {0x0F12, 0xF000}, + {0x0F12, 0xF9ED},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0xBC10}, + {0x0F12, 0xBC08}, + {0x0F12, 0x4718}, + {0x0F12, 0x1100}, + {0x0F12, 0xD000}, + {0x0F12, 0x267C}, + {0x0F12, 0x0000}, + {0x0F12, 0x2CE8}, + {0x0F12, 0x0000}, + {0x0F12, 0x3274}, + {0x0F12, 0x7000}, + {0x0F12, 0xF400}, + {0x0F12, 0xD000}, + {0x0F12, 0xF520}, + {0x0F12, 0xD000}, + {0x0F12, 0x2DF1}, + {0x0F12, 0x7000}, + {0x0F12, 0x89A9}, + {0x0F12, 0x0000}, + {0x0F12, 0x2E43}, + {0x0F12, 0x7000}, + {0x0F12, 0x0140}, + {0x0F12, 0x7000}, + {0x0F12, 0x2E75},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x7000}, + {0x0F12, 0xB4F7}, + {0x0F12, 0x0000}, + {0x0F12, 0x2EFF},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x7000}, + {0x0F12, 0x2F23},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x7000}, + {0x0F12, 0x2FCD},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x7000}, + {0x0F12, 0x2FE1},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x7000}, + {0x0F12, 0x2FB5},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x7000}, + {0x0F12, 0x013D}, + {0x0F12, 0x0001}, + {0x0F12, 0x3067},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x7000}, + {0x0F12, 0x5823}, + {0x0F12, 0x0000}, + {0x0F12, 0x30B5},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x7000}, + {0x0F12, 0xD789}, + {0x0F12, 0x0000}, + {0x0F12, 0xB570}, + {0x0F12, 0x6804}, + {0x0F12, 0x6845}, + {0x0F12, 0x6881}, + {0x0F12, 0x6840}, + {0x0F12, 0x2900}, + {0x0F12, 0x6880}, + {0x0F12, 0xD007}, + {0x0F12, 0x49C2},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x8949}, + {0x0F12, 0x084A}, + {0x0F12, 0x1880}, + {0x0F12, 0xF000}, + {0x0F12, 0xF9B8},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x80A0}, + {0x0F12, 0xE000}, + {0x0F12, 0x80A0}, + {0x0F12, 0x88A0}, + {0x0F12, 0x2800}, + {0x0F12, 0xD010}, + {0x0F12, 0x68A9}, + {0x0F12, 0x6828}, + {0x0F12, 0x084A}, + {0x0F12, 0x1880}, + {0x0F12, 0xF000}, + {0x0F12, 0xF9AC},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x8020}, + {0x0F12, 0x1D2D}, + {0x0F12, 0xCD03}, + {0x0F12, 0x084A}, + {0x0F12, 0x1880}, + {0x0F12, 0xF000}, + {0x0F12, 0xF9A5},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x8060}, + {0x0F12, 0xBC70}, + {0x0F12, 0xBC08}, + {0x0F12, 0x4718}, + {0x0F12, 0x2000}, + {0x0F12, 0x8060}, + {0x0F12, 0x8020}, + {0x0F12, 0xE7F8}, + {0x0F12, 0xB510}, + {0x0F12, 0xF000}, + //BEGIN: DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0xF9A0}, + //{0x0F12, 0x48B2}, + //{0x0F12, 0x8A40}, + //{0x0F12, 0x2800}, + //{0x0F12, 0xD00C}, + //END: DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x48B1}, + {0x0F12, 0x49B2}, + {0x0F12, 0x8800}, + {0x0F12, 0x4AB2}, + {0x0F12, 0x2805}, + {0x0F12, 0xD003}, + {0x0F12, 0x4BB1}, + {0x0F12, 0x795B}, + {0x0F12, 0x2B00}, + {0x0F12, 0xD005}, + {0x0F12, 0x2001}, + {0x0F12, 0x8008}, + {0x0F12, 0x8010}, + {0x0F12, 0xBC10}, + {0x0F12, 0xBC08}, + {0x0F12, 0x4718}, + {0x0F12, 0x2800}, + {0x0F12, 0xD1FA}, + {0x0F12, 0x2000}, + {0x0F12, 0x8008}, + {0x0F12, 0x8010}, + {0x0F12, 0xE7F6}, + {0x0F12, 0xB5F8}, + {0x0F12, 0x2407}, + {0x0F12, 0x2C06}, + {0x0F12, 0xD035}, + {0x0F12, 0x2C07}, + {0x0F12, 0xD033}, + {0x0F12, 0x48A3}, + {0x0F12, 0x8BC1}, + {0x0F12, 0x2900}, + {0x0F12, 0xD02A}, + {0x0F12, 0x00A2}, + {0x0F12, 0x1815}, + {0x0F12, 0x4AA4}, + {0x0F12, 0x6DEE}, + {0x0F12, 0x8A92}, + {0x0F12, 0x4296}, + {0x0F12, 0xD923}, + {0x0F12, 0x0028}, + {0x0F12, 0x3080}, + {0x0F12, 0x0007}, + {0x0F12, 0x69C0}, + {0x0F12, 0xF000}, + {0x0F12, 0xF96D},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x1C71}, + {0x0F12, 0x0280}, + {0x0F12, 0xF000}, + {0x0F12, 0xF969},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x0006}, + {0x0F12, 0x4898}, + {0x0F12, 0x0061}, + {0x0F12, 0x1808}, + {0x0F12, 0x8D80}, + {0x0F12, 0x0A01}, + {0x0F12, 0x0600}, + {0x0F12, 0x0E00}, + {0x0F12, 0x1A08}, + {0x0F12, 0xF000}, + {0x0F12, 0xF96C},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x0002}, + {0x0F12, 0x6DE9}, + {0x0F12, 0x6FE8}, + {0x0F12, 0x1A08}, + {0x0F12, 0x4351}, + {0x0F12, 0x0300}, + {0x0F12, 0x1C49}, + {0x0F12, 0xF000}, + {0x0F12, 0xF955},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x0401}, + {0x0F12, 0x0430}, + {0x0F12, 0x0C00}, + {0x0F12, 0x4301}, + {0x0F12, 0x61F9}, + {0x0F12, 0xE004}, + {0x0F12, 0x00A2}, + {0x0F12, 0x4990}, + {0x0F12, 0x1810}, + {0x0F12, 0x3080}, + {0x0F12, 0x61C1}, + {0x0F12, 0x1E64}, + {0x0F12, 0xD2C5}, + {0x0F12, 0x2006}, + {0x0F12, 0xF000}, + {0x0F12, 0xF95B},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x2007}, + {0x0F12, 0xF000}, + {0x0F12, 0xF958},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0xBCF8}, + {0x0F12, 0xBC08}, + {0x0F12, 0x4718}, + {0x0F12, 0xB510}, + {0x0F12, 0xF000}, + {0x0F12, 0xF95A},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x2800}, + {0x0F12, 0xD00A}, + {0x0F12, 0x4881}, + {0x0F12, 0x8B81}, + {0x0F12, 0x0089}, + {0x0F12, 0x1808}, + {0x0F12, 0x6DC1}, + {0x0F12, 0x4883}, + {0x0F12, 0x8A80}, + {0x0F12, 0x4281}, + {0x0F12, 0xD901}, + {0x0F12, 0x2001}, + {0x0F12, 0xE7A1}, + {0x0F12, 0x2000}, + {0x0F12, 0xE79F}, + {0x0F12, 0xB5F8}, + {0x0F12, 0x0004}, + {0x0F12, 0x4F80}, + {0x0F12, 0x227D}, + {0x0F12, 0x8938}, + {0x0F12, 0x0152}, + {0x0F12, 0x4342}, + {0x0F12, 0x487E}, + {0x0F12, 0x9000}, + {0x0F12, 0x8A01}, + {0x0F12, 0x0848}, + {0x0F12, 0x1810}, + {0x0F12, 0xF000}, + {0x0F12, 0xF91F},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x210F}, + {0x0F12, 0xF000}, + {0x0F12, 0xF942},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x497A}, + {0x0F12, 0x8C49}, + {0x0F12, 0x090E}, + {0x0F12, 0x0136}, + {0x0F12, 0x4306}, + {0x0F12, 0x4979}, + {0x0F12, 0x2C00}, + {0x0F12, 0xD003}, + {0x0F12, 0x2001}, + {0x0F12, 0x0240}, + {0x0F12, 0x4330}, + {0x0F12, 0x8108}, + {0x0F12, 0x4876}, + {0x0F12, 0x2C00}, + {0x0F12, 0x8D00}, + {0x0F12, 0xD001}, + {0x0F12, 0x2501}, + {0x0F12, 0xE000}, + {0x0F12, 0x2500}, + {0x0F12, 0x4972}, + {0x0F12, 0x4328}, + {0x0F12, 0x8008}, + {0x0F12, 0x207D}, + {0x0F12, 0x00C0}, + {0x0F12, 0xF000}, + {0x0F12, 0xF930},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x2C00}, + {0x0F12, 0x496E}, + {0x0F12, 0x0328}, + {0x0F12, 0x4330}, + {0x0F12, 0x8108}, + {0x0F12, 0x88F8}, + {0x0F12, 0x2C00}, + {0x0F12, 0x01AA}, + {0x0F12, 0x4310}, + {0x0F12, 0x8088}, + {0x0F12, 0x2C00},//DTS2012071201781: add by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0xD00B},//DTS2012071201781: add by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x9800}, + {0x0F12, 0x8A01}, + {0x0F12, 0x4869},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0xF000}, + {0x0F12, 0xF8F1}, + {0x0F12, 0x4969},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x8809}, + {0x0F12, 0x4348}, + {0x0F12, 0x0400}, + {0x0F12, 0x0C00}, + {0x0F12, 0xF000}, + {0x0F12, 0xF918}, + {0x0F12, 0x0020}, + {0x0F12, 0xF000}, + {0x0F12, 0xF91D}, + {0x0F12, 0x4865},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x7004}, + {0x0F12, 0xE7A1},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0xB510}, + {0x0F12, 0x0004}, + {0x0F12, 0xF000}, + {0x0F12, 0xF91E}, + {0x0F12, 0x6020}, + {0x0F12, 0x4962},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x8B49}, + {0x0F12, 0x0789}, + {0x0F12, 0xD001}, + {0x0F12, 0x0040}, + {0x0F12, 0x6020}, + {0x0F12, 0xE74A},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0xB510}, + {0x0F12, 0xF000}, + {0x0F12, 0xF91B}, + {0x0F12, 0x485E},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x8880}, + {0x0F12, 0x0601}, + {0x0F12, 0x4853},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x1609}, + {0x0F12, 0x8141}, + {0x0F12, 0xE740},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0xB5F8}, + {0x0F12, 0x000F}, + {0x0F12, 0x4C54},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x3420}, + {0x0F12, 0x2500}, + {0x0F12, 0x5765}, + {0x0F12, 0x0039}, + {0x0F12, 0xF000}, + {0x0F12, 0xF913}, + {0x0F12, 0x9000}, + {0x0F12, 0x2600}, + {0x0F12, 0x57A6}, + {0x0F12, 0x4C4B},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x42AE}, + {0x0F12, 0xD01B}, + {0x0F12, 0x4D53},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x8AE8}, + {0x0F12, 0x2800}, + {0x0F12, 0xD013}, + {0x0F12, 0x484C},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x8A01}, + {0x0F12, 0x8B80}, + {0x0F12, 0x4378}, + {0x0F12, 0xF000}, + {0x0F12, 0xF8B5}, + {0x0F12, 0x89A9}, + {0x0F12, 0x1A41}, + {0x0F12, 0x484D},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x3820}, + {0x0F12, 0x8AC0}, + {0x0F12, 0x4348}, + {0x0F12, 0x17C1}, + {0x0F12, 0x0D89}, + {0x0F12, 0x1808}, + {0x0F12, 0x1280}, + {0x0F12, 0x8961}, + {0x0F12, 0x1A08}, + {0x0F12, 0x8160}, + {0x0F12, 0xE003}, + {0x0F12, 0x88A8}, + {0x0F12, 0x0600}, + {0x0F12, 0x1600}, + {0x0F12, 0x8160}, + {0x0F12, 0x200A}, + {0x0F12, 0x5E20}, + {0x0F12, 0x42B0}, + {0x0F12, 0xD011}, + {0x0F12, 0xF000}, + {0x0F12, 0xF8AB}, + {0x0F12, 0x1D40}, + {0x0F12, 0x00C3}, + {0x0F12, 0x1A18}, + {0x0F12, 0x214B}, + {0x0F12, 0xF000}, + {0x0F12, 0xF897}, + {0x0F12, 0x211F}, + {0x0F12, 0xF000}, + {0x0F12, 0xF8BA}, + {0x0F12, 0x210A}, + {0x0F12, 0x5E61}, + {0x0F12, 0x0FC9}, + {0x0F12, 0x0149}, + {0x0F12, 0x4301}, + {0x0F12, 0x483C},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x81C1}, + {0x0F12, 0x9800}, + {0x0F12, 0xE748},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0xB5F1}, + {0x0F12, 0xB082}, + {0x0F12, 0x2500}, + {0x0F12, 0x4839},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x9001}, + {0x0F12, 0x2400}, + {0x0F12, 0x2028}, + {0x0F12, 0x4368}, + {0x0F12, 0x4A39}, + {0x0F12, 0x4937},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x1887}, + {0x0F12, 0x1840}, + {0x0F12, 0x9000}, + {0x0F12, 0x9800}, + {0x0F12, 0x0066}, + {0x0F12, 0x9A01}, + {0x0F12, 0x1980}, + {0x0F12, 0x218C}, + {0x0F12, 0x5A09}, + {0x0F12, 0x8A80}, + {0x0F12, 0x8812}, + {0x0F12, 0xF000}, + {0x0F12, 0xF8CA}, + {0x0F12, 0x53B8}, + {0x0F12, 0x1C64}, + {0x0F12, 0x2C14}, + {0x0F12, 0xDBF1}, + {0x0F12, 0x1C6D}, + {0x0F12, 0x2D03}, + {0x0F12, 0xDBE6}, + {0x0F12, 0x9802}, + {0x0F12, 0x6800}, + {0x0F12, 0x0600}, + {0x0F12, 0x0E00}, + {0x0F12, 0xF000}, + {0x0F12, 0xF8C5}, + {0x0F12, 0xBCFE}, + {0x0F12, 0xBC08}, + {0x0F12, 0x4718}, + {0x0F12, 0xB570}, + {0x0F12, 0x6805}, + {0x0F12, 0x2404}, + {0x0F12, 0xF000}, + {0x0F12, 0xF8C5}, + {0x0F12, 0x2800}, + {0x0F12, 0xD103}, + {0x0F12, 0xF000}, + {0x0F12, 0xF8C9}, + {0x0F12, 0x2800}, + {0x0F12, 0xD000}, + {0x0F12, 0x2400}, + {0x0F12, 0x3540}, + {0x0F12, 0x88E8}, + {0x0F12, 0x0500}, + {0x0F12, 0xD403}, + {0x0F12, 0x4822}, + {0x0F12, 0x89C0}, + {0x0F12, 0x2800}, + {0x0F12, 0xD002}, + {0x0F12, 0x2008}, + {0x0F12, 0x4304}, + {0x0F12, 0xE001}, + {0x0F12, 0x2010}, + {0x0F12, 0x4304}, + {0x0F12, 0x481F}, + {0x0F12, 0x8B80}, + {0x0F12, 0x0700}, + {0x0F12, 0x0F81}, + {0x0F12, 0x2001}, + {0x0F12, 0x2900}, + {0x0F12, 0xD000}, + {0x0F12, 0x4304}, + {0x0F12, 0x491C}, + {0x0F12, 0x8B0A}, + {0x0F12, 0x42A2}, + {0x0F12, 0xD004}, + {0x0F12, 0x0762}, + {0x0F12, 0xD502}, + {0x0F12, 0x4A19}, + {0x0F12, 0x3220}, + {0x0F12, 0x8110}, + {0x0F12, 0x830C}, + {0x0F12, 0xE693},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x0C3C}, + //BEGIN: DTS2012071201781: del by huyouhua 00136760 at 2012-7-20 + //{0x0F12, 0x7000}, + //{0x0F12, 0x3274}, + //END: DTS2012071201781: del by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x7000}, + {0x0F12, 0x26E8}, + {0x0F12, 0x7000}, + {0x0F12, 0x6100}, + {0x0F12, 0xD000}, + {0x0F12, 0x6500}, + {0x0F12, 0xD000}, + {0x0F12, 0x1A7C}, + {0x0F12, 0x7000}, + {0x0F12, 0x1120}, + {0x0F12, 0x7000}, + {0x0F12, 0xFFFF}, + {0x0F12, 0x0000}, + {0x0F12, 0x3374}, + {0x0F12, 0x7000}, + {0x0F12, 0x1D6C}, + {0x0F12, 0x7000}, + {0x0F12, 0x167C}, + {0x0F12, 0x7000}, + {0x0F12, 0xF400}, + {0x0F12, 0xD000}, + {0x0F12, 0x2C2C}, + {0x0F12, 0x7000}, + {0x0F12, 0x40A0}, + {0x0F12, 0x00DD}, + {0x0F12, 0xF520}, + {0x0F12, 0xD000}, + {0x0F12, 0x2C29}, + {0x0F12, 0x7000}, + {0x0F12, 0x1A54}, + {0x0F12, 0x7000}, + {0x0F12, 0x1564}, + {0x0F12, 0x7000}, + {0x0F12, 0xF2A0}, + {0x0F12, 0xD000}, + {0x0F12, 0x2440}, + {0x0F12, 0x7000},//DTS2012071201781: add by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x3274},//DTS2012071201781: add by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x7000}, + {0x0F12, 0x05A0}, + {0x0F12, 0x7000}, + {0x0F12, 0x2894}, + {0x0F12, 0x7000}, + {0x0F12, 0x1224}, + {0x0F12, 0x7000}, + {0x0F12, 0xB000}, + {0x0F12, 0xD000}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0x1A3F}, + {0x0F12, 0x0001}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xF004}, + {0x0F12, 0xE51F}, + {0x0F12, 0x1F48}, + {0x0F12, 0x0001}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0x24BD}, + {0x0F12, 0x0000}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0x36DD}, + {0x0F12, 0x0000}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0xB4CF}, + {0x0F12, 0x0000}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0xB5D7}, + {0x0F12, 0x0000}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0x36ED}, + {0x0F12, 0x0000}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0xF53F}, + {0x0F12, 0x0000}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0xF5D9}, + {0x0F12, 0x0000}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0x013D}, + {0x0F12, 0x0001}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0xF5C9}, + {0x0F12, 0x0000}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0xFAA9}, + {0x0F12, 0x0000}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0x3723}, + {0x0F12, 0x0000}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0x5823}, + {0x0F12, 0x0000}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0xD771}, + {0x0F12, 0x0000}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0xD75B}, + {0x0F12, 0x0000}, + {0x0F12, 0x7E77},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x0000}, + //end tp + + //======================================================== + // CIs/APs/An setting - 400LsB sYsCLK 32MHz + //======================================================== + // This regis are for FACTORY ONLY. If you change it without prior notification, + // YOU are REsIBLE for the FAILURE that will happen in the future. + //======================================================== + {0x0028, 0x7000},//DTS2012071201781: add by huyouhua 00136760 at 2012-7-20 + + {0x002A, 0x157A}, + {0x0F12, 0x0001}, + {0x002A, 0x1578}, + {0x0F12, 0x0001}, + {0x002A, 0x1576}, + {0x0F12, 0x0020}, + {0x002A, 0x1574}, + {0x0F12, 0x0006}, + {0x002A, 0x156E}, + {0x0F12, 0x0001}, // slope calibration tolerance in units of 1/256 + {0x002A, 0x1568}, + {0x0F12, 0x00FC}, + + //ADC control + {0x002A, 0x155A}, + {0x0F12, 0x01CC}, //ADC sAT of 450mV for 10bit default in EVT1 + {0x002A, 0x157E}, + {0x0F12, 0x0C80}, // 3200 Max. Reset ramp DCLK counts {default 2048 0x800} + {0x0F12, 0x0578}, // 1400 Max. Reset ramp DCLK counts for x3.5 + {0x002A, 0x157C}, + {0x0F12, 0x0190}, // 400 Reset ramp for x1 in DCLK counts + {0x002A, 0x1570}, + {0x0F12, 0x00A0}, // 160 LsB + {0x0F12, 0x0010}, // reset threshold + {0x002A, 0x12C4}, + {0x0F12, 0x006A}, // 106 additional timing columns. + {0x002A, 0x12C8}, + {0x0F12, 0x08AC}, // 2220 ADC columns in normal mode including Hold & Latch + {0x0F12, 0x0050}, // 80 addition of ADC columns in Y-ave mode {default 244 0x74} + + {0x002A, 0x1696}, // based on APs guidelines + {0x0F12, 0x0000}, // based on APs guidelines + {0x0F12, 0x0000}, // default. 1492 used for ADC dark characteristics + {0x0F12, 0x00C6}, // default. 1492 used for ADC dark characteristics + {0x0F12, 0x00C6}, + //BEGIN: DTS2012071201781: add by huyouhua 00136760 at 2012-7-20 + {0x002A, 0x12B8}, + {0x0F12, 0x0B00}, //#senHal_ExpMinPixels //disable CINTR 0 + //END: DTS2012071201781: add by huyouhua 00136760 at 2012-7-20 + {0x002A, 0x1690}, // when set double sampling is activated - requires different set of pointers + {0x0F12, 0x0001}, + + {0x002A, 0x12B0}, // comp and pixel bias control 0xF40E - default for EVT1 + {0x0F12, 0x0055}, // comp and pixel bias control 0xF40E for binning mode + {0x0F12, 0x005A}, + + {0x002A, 0x337A}, // [7] - is used for rest-only mode {EVT0 value is 0xD and HW 0x6} + {0x0F12, 0x0006}, + {0x0F12, 0x0068}, + //BEGIN:DTS2012071201781: del by huyouhua 00136760 at 2012-7-20 + //{0x002A, 0x169E}, + //{0x0F12, 0x0007}, + //{0x002A, 0x0BF6}, + //{0x0F12, 0x0000}, + //END:DTS2012071201781: del by huyouhua 00136760 at 2012-7-20 + + {0x002A, 0x327C}, + {0x0F12, 0x1000}, + {0x0F12, 0x6998}, + {0x0F12, 0x0078}, + {0x0F12, 0x04FE}, + {0x0F12, 0x8800}, +#if defined(CURRENT_4MA) + {0x002A, 0x3274}, + {0x0F12, 0x0155}, //set IO driving current 4mA for Data + {0x0F12, 0x0155}, //set IO driving current 4ma for Data + {0x0F12, 0x1555}, //set IO driving current + {0x0F12, 0x0555}, //set IO driving current 4ma for PCLK/HSYNC/Vsync +#elif defined(CURRENT_8MA) + {0x002A, 0x3274}, + {0x0F12, 0x02aa}, //set IO driving current 8mA for Data + {0x0F12, 0x02aa}, //set IO driving current + {0x0F12, 0x1555}, //set IO driving current + {0x0F12, 0x059a}, //set IO driving current +#elif defined(CURRENT_12MA) + {0x002A, 0x3274}, + {0x0F12, 0x03ff}, //set IO driving current 12mA for Data + {0x0F12, 0x03ff}, //set IO driving current + {0x0F12, 0x1555}, //set IO driving current + {0x0F12, 0x05df}, //set IO driving current + //BEGIN: DTS2012071201781 add by huyouhua 00136760 at 2012-7-23 +#elif defined(CURRENT_SLIM) + {0x002A, 0x3274}, + {0x0F12, 0x0155},//------- //#Tune_TP_IO_DrivingCurrent_D0_D4_cs10Set IO driving current--------------- + {0x0F12, 0x0155},//------- //#Tune_TP_IO_DrivingCurrent_D9_D5_cs10Set IO driving current--------------- + {0x0F12, 0x1555},//------- //#Tune_TP_IO_DrivingCurrent_GPIO_cd10 Set IO driving current--------------- + //{0x0F12, 0x05DF}//0x0555},//------- - //059A//05DF//#Tune_TP_IO_DrivingCurrent_CLKs_cd10 Set IO driving current- + {0x0F12, 0x059A},//0x0555},//------- - //059A//05DF//#Tune_TP_IO_DrivingCurrent_CLKs_cd10 Set IO driving current- + //595,59A,5DA,5DF + //END: DTS2012071201781 add by huyouhua 00136760 at 2012-7-23 +#endif + + //BEGIN: DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x002A, 0x169E}, + {0x0F12, 0x0007}, //evt1_senHal_Dblr2Value // [3:0]- specifies the target (default 7)- DCLK = 64MHz instead of 116MHz. + {0x002A, 0x0BF6}, + {0x0F12, 0x0000}, //from ALEX //Enable Bayer Downscaler + //END: DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0028, 0x7000}, + {0x002A, 0x12D2}, + {0x0F12, 0x0003}, //senHal_pContSenModesRegsArray[0][0]2 700012D2 + {0x0F12, 0x0003}, //senHal_pContSenModesRegsArray[0][1]2 700012D4 + {0x0F12, 0x0003}, //senHal_pContSenModesRegsArray[0][2]2 700012D6 + {0x0F12, 0x0003}, //senHal_pContSenModesRegsArray[0][3]2 700012D8 + {0x0F12, 0x0884}, //senHal_pContSenModesRegsArray[1][0]2 700012DA + {0x0F12, 0x08CF}, //senHal_pContSenModesRegsArray[1][1]2 700012DC + {0x0F12, 0x0500}, //senHal_pContSenModesRegsArray[1][2]2 700012DE + {0x0F12, 0x054B}, //senHal_pContSenModesRegsArray[1][3]2 700012E0 + {0x0F12, 0x0001}, //senHal_pContSenModesRegsArray[2][0]2 700012E2 + {0x0F12, 0x0001}, //senHal_pContSenModesRegsArray[2][1]2 700012E4 + {0x0F12, 0x0001}, //senHal_pContSenModesRegsArray[2][2]2 700012E6 + {0x0F12, 0x0001}, //senHal_pContSenModesRegsArray[2][3]2 700012E8 + {0x0F12, 0x0885}, //senHal_pContSenModesRegsArray[3][0]2 700012EA + {0x0F12, 0x0467}, //senHal_pContSenModesRegsArray[3][1]2 700012EC + {0x0F12, 0x0501}, //senHal_pContSenModesRegsArray[3][2]2 700012EE + {0x0F12, 0x02A5}, //senHal_pContSenModesRegsArray[3][3]2 700012F0 + {0x0F12, 0x0001}, //senHal_pContSenModesRegsArray[4][0]2 700012F2 + {0x0F12, 0x046A}, //senHal_pContSenModesRegsArray[4][1]2 700012F4 + {0x0F12, 0x0001}, //senHal_pContSenModesRegsArray[4][2]2 700012F6 + {0x0F12, 0x02A8}, //senHal_pContSenModesRegsArray[4][3]2 700012F8 + {0x0F12, 0x0885}, //senHal_pContSenModesRegsArray[5][0]2 700012FA + {0x0F12, 0x08D0}, //senHal_pContSenModesRegsArray[5][1]2 700012FC + {0x0F12, 0x0501}, //senHal_pContSenModesRegsArray[5][2]2 700012FE + {0x0F12, 0x054C}, //senHal_pContSenModesRegsArray[5][3]2 70001300 + {0x0F12, 0x0006}, //senHal_pContSenModesRegsArray[6][0]2 70001302 + {0x0F12, 0x0020}, //senHal_pContSenModesRegsArray[6][1]2 70001304 + {0x0F12, 0x0006}, //senHal_pContSenModesRegsArray[6][2]2 70001306 + {0x0F12, 0x0020}, //senHal_pContSenModesRegsArray[6][3]2 70001308 + {0x0F12, 0x0881}, //senHal_pContSenModesRegsArray[7][0]2 7000130A + {0x0F12, 0x0463}, //senHal_pContSenModesRegsArray[7][1]2 7000130C + {0x0F12, 0x04FD}, //senHal_pContSenModesRegsArray[7][2]2 7000130E + {0x0F12, 0x02A1}, //senHal_pContSenModesRegsArray[7][3]2 70001310 + {0x0F12, 0x0006}, //senHal_pContSenModesRegsArray[8][0]2 70001312 + {0x0F12, 0x0489}, //senHal_pContSenModesRegsArray[8][1]2 70001314 + {0x0F12, 0x0006}, //senHal_pContSenModesRegsArray[8][2]2 70001316 + {0x0F12, 0x02C7}, //senHal_pContSenModesRegsArray[8][3]2 70001318 + {0x0F12, 0x0881}, //senHal_pContSenModesRegsArray[9][0]2 7000131A + {0x0F12, 0x08CC}, //senHal_pContSenModesRegsArray[9][1]2 7000131C + {0x0F12, 0x04FD}, //senHal_pContSenModesRegsArray[9][2]2 7000131E + {0x0F12, 0x0548}, //senHal_pContSenModesRegsArray[9][3]2 70001320 + {0x0F12, 0x03A2}, //senHal_pContSenModesRegsArray[10][0] 2 70001322 + {0x0F12, 0x01D3}, //senHal_pContSenModesRegsArray[10][1] 2 70001324 + {0x0F12, 0x01E0}, //senHal_pContSenModesRegsArray[10][2] 2 70001326 + {0x0F12, 0x00F2}, //senHal_pContSenModesRegsArray[10][3] 2 70001328 + {0x0F12, 0x03F2}, //senHal_pContSenModesRegsArray[11][0] 2 7000132A + {0x0F12, 0x0223}, //senHal_pContSenModesRegsArray[11][1] 2 7000132C + {0x0F12, 0x0230}, //senHal_pContSenModesRegsArray[11][2] 2 7000132E + {0x0F12, 0x0142}, //senHal_pContSenModesRegsArray[11][3] 2 70001330 + {0x0F12, 0x03A2}, //senHal_pContSenModesRegsArray[12][0] 2 70001332 + {0x0F12, 0x063C}, //senHal_pContSenModesRegsArray[12][1] 2 70001334 + {0x0F12, 0x01E0}, //senHal_pContSenModesRegsArray[12][2] 2 70001336 + {0x0F12, 0x0399}, //senHal_pContSenModesRegsArray[12][3] 2 70001338 + {0x0F12, 0x03F2}, //senHal_pContSenModesRegsArray[13][0] 2 7000133A + {0x0F12, 0x068C}, //senHal_pContSenModesRegsArray[13][1] 2 7000133C + {0x0F12, 0x0230}, //senHal_pContSenModesRegsArray[13][2] 2 7000133E + {0x0F12, 0x03E9}, //senHal_pContSenModesRegsArray[13][3] 2 70001340 + {0x0F12, 0x0002}, //senHal_pContSenModesRegsArray[14][0] 2 70001342 + {0x0F12, 0x0002}, //senHal_pContSenModesRegsArray[14][1] 2 70001344 + {0x0F12, 0x0002}, //senHal_pContSenModesRegsArray[14][2] 2 70001346 + {0x0F12, 0x0002}, //senHal_pContSenModesRegsArray[14][3] 2 70001348 + {0x0F12, 0x003C}, //senHal_pContSenModesRegsArray[15][0] 2 7000134A + {0x0F12, 0x003C}, //senHal_pContSenModesRegsArray[15][1] 2 7000134C + {0x0F12, 0x003C}, //senHal_pContSenModesRegsArray[15][2] 2 7000134E + {0x0F12, 0x003C}, //senHal_pContSenModesRegsArray[15][3] 2 70001350 + {0x0F12, 0x01D3}, //senHal_pContSenModesRegsArray[16][0] 2 70001352 + {0x0F12, 0x01D3}, //senHal_pContSenModesRegsArray[16][1] 2 70001354 + {0x0F12, 0x00F2}, //senHal_pContSenModesRegsArray[16][2] 2 70001356 + {0x0F12, 0x00F2}, //senHal_pContSenModesRegsArray[16][3] 2 70001358 + {0x0F12, 0x020B}, //senHal_pContSenModesRegsArray[17][0] 2 7000135A + {0x0F12, 0x024A}, //senHal_pContSenModesRegsArray[17][1] 2 7000135C + {0x0F12, 0x012A}, //senHal_pContSenModesRegsArray[17][2] 2 7000135E + {0x0F12, 0x0169}, //senHal_pContSenModesRegsArray[17][3] 2 70001360 + {0x0F12, 0x0002}, //senHal_pContSenModesRegsArray[18][0] 2 70001362 + {0x0F12, 0x046B}, //senHal_pContSenModesRegsArray[18][1] 2 70001364 + {0x0F12, 0x0002}, //senHal_pContSenModesRegsArray[18][2] 2 70001366 + {0x0F12, 0x02A9}, //senHal_pContSenModesRegsArray[18][3] 2 70001368 + {0x0F12, 0x0419}, //senHal_pContSenModesRegsArray[19][0] 2 7000136A + {0x0F12, 0x04A5}, //senHal_pContSenModesRegsArray[19][1] 2 7000136C + {0x0F12, 0x0257}, //senHal_pContSenModesRegsArray[19][2] 2 7000136E + {0x0F12, 0x02E3}, //senHal_pContSenModesRegsArray[19][3] 2 70001370 + {0x0F12, 0x0630}, //senHal_pContSenModesRegsArray[20][0] 2 70001372 + {0x0F12, 0x063C}, //senHal_pContSenModesRegsArray[20][1] 2 70001374 + {0x0F12, 0x038D}, //senHal_pContSenModesRegsArray[20][2] 2 70001376 + {0x0F12, 0x0399}, //senHal_pContSenModesRegsArray[20][3] 2 70001378 + {0x0F12, 0x0668}, //senHal_pContSenModesRegsArray[21][0] 2 7000137A + {0x0F12, 0x06B3}, //senHal_pContSenModesRegsArray[21][1] 2 7000137C + {0x0F12, 0x03C5}, //senHal_pContSenModesRegsArray[21][2] 2 7000137E + {0x0F12, 0x0410}, //senHal_pContSenModesRegsArray[21][3] 2 70001380 + {0x0F12, 0x0001}, //senHal_pContSenModesRegsArray[22][0] 2 70001382 + {0x0F12, 0x0001}, //senHal_pContSenModesRegsArray[22][1] 2 70001384 + {0x0F12, 0x0001}, //senHal_pContSenModesRegsArray[22][2] 2 70001386 + {0x0F12, 0x0001}, //senHal_pContSenModesRegsArray[22][3] 2 70001388 + {0x0F12, 0x03A2}, //senHal_pContSenModesRegsArray[23][0] 2 7000138A + {0x0F12, 0x01D3}, //senHal_pContSenModesRegsArray[23][1] 2 7000138C + {0x0F12, 0x01E0}, //senHal_pContSenModesRegsArray[23][2] 2 7000138E + {0x0F12, 0x00F2}, //senHal_pContSenModesRegsArray[23][3] 2 70001390 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[24][0] 2 70001392 + {0x0F12, 0x0461}, //senHal_pContSenModesRegsArray[24][1] 2 70001394 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[24][2] 2 70001396 + {0x0F12, 0x029F}, //senHal_pContSenModesRegsArray[24][3] 2 70001398 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[25][0] 2 7000139A + {0x0F12, 0x063C}, //senHal_pContSenModesRegsArray[25][1] 2 7000139C + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[25][2] 2 7000139E + {0x0F12, 0x0399}, //senHal_pContSenModesRegsArray[25][3] 2 700013A0 + {0x0F12, 0x003D}, //senHal_pContSenModesRegsArray[26][0] 2 700013A2 + {0x0F12, 0x003D}, //senHal_pContSenModesRegsArray[26][1] 2 700013A4 + {0x0F12, 0x003D}, //senHal_pContSenModesRegsArray[26][2] 2 700013A6 + {0x0F12, 0x003D}, //senHal_pContSenModesRegsArray[26][3] 2 700013A8 + {0x0F12, 0x01D0}, //senHal_pContSenModesRegsArray[27][0] 2 700013AA + {0x0F12, 0x01D0}, //senHal_pContSenModesRegsArray[27][1] 2 700013AC + {0x0F12, 0x00EF}, //senHal_pContSenModesRegsArray[27][2] 2 700013AE + {0x0F12, 0x00EF}, //senHal_pContSenModesRegsArray[27][3] 2 700013B0 + {0x0F12, 0x020C}, //senHal_pContSenModesRegsArray[28][0] 2 700013B2 + {0x0F12, 0x024B}, //senHal_pContSenModesRegsArray[28][1] 2 700013B4 + {0x0F12, 0x012B}, //senHal_pContSenModesRegsArray[28][2] 2 700013B6 + {0x0F12, 0x016A}, //senHal_pContSenModesRegsArray[28][3] 2 700013B8 + {0x0F12, 0x039F}, //senHal_pContSenModesRegsArray[29][0] 2 700013BA + {0x0F12, 0x045E}, //senHal_pContSenModesRegsArray[29][1] 2 700013BC + {0x0F12, 0x01DD}, //senHal_pContSenModesRegsArray[29][2] 2 700013BE + {0x0F12, 0x029C}, //senHal_pContSenModesRegsArray[29][3] 2 700013C0 + {0x0F12, 0x041A}, //senHal_pContSenModesRegsArray[30][0] 2 700013C2 + {0x0F12, 0x04A6}, //senHal_pContSenModesRegsArray[30][1] 2 700013C4 + {0x0F12, 0x0258}, //senHal_pContSenModesRegsArray[30][2] 2 700013C6 + {0x0F12, 0x02E4}, //senHal_pContSenModesRegsArray[30][3] 2 700013C8 + {0x0F12, 0x062D}, //senHal_pContSenModesRegsArray[31][0] 2 700013CA + {0x0F12, 0x0639}, //senHal_pContSenModesRegsArray[31][1] 2 700013CC + {0x0F12, 0x038A}, //senHal_pContSenModesRegsArray[31][2] 2 700013CE + {0x0F12, 0x0396}, //senHal_pContSenModesRegsArray[31][3] 2 700013D0 + {0x0F12, 0x0669}, //senHal_pContSenModesRegsArray[32][0] 2 700013D2 + {0x0F12, 0x06B4}, //senHal_pContSenModesRegsArray[32][1] 2 700013D4 + {0x0F12, 0x03C6}, //senHal_pContSenModesRegsArray[32][2] 2 700013D6 + {0x0F12, 0x0411}, //senHal_pContSenModesRegsArray[32][3] 2 700013D8 + {0x0F12, 0x087C}, //senHal_pContSenModesRegsArray[33][0] 2 700013DA + {0x0F12, 0x08C7}, //senHal_pContSenModesRegsArray[33][1] 2 700013DC + {0x0F12, 0x04F8}, //senHal_pContSenModesRegsArray[33][2] 2 700013DE + {0x0F12, 0x0543}, //senHal_pContSenModesRegsArray[33][3] 2 700013E0 + {0x0F12, 0x0040}, //senHal_pContSenModesRegsArray[34][0] 2 700013E2 + {0x0F12, 0x0040}, //senHal_pContSenModesRegsArray[34][1] 2 700013E4 + {0x0F12, 0x0040}, //senHal_pContSenModesRegsArray[34][2] 2 700013E6 + {0x0F12, 0x0040}, //senHal_pContSenModesRegsArray[34][3] 2 700013E8 + {0x0F12, 0x01D0}, //senHal_pContSenModesRegsArray[35][0] 2 700013EA + {0x0F12, 0x01D0}, //senHal_pContSenModesRegsArray[35][1] 2 700013EC + {0x0F12, 0x00EF}, //senHal_pContSenModesRegsArray[35][2] 2 700013EE + {0x0F12, 0x00EF}, //senHal_pContSenModesRegsArray[35][3] 2 700013F0 + {0x0F12, 0x020F}, //senHal_pContSenModesRegsArray[36][0] 2 700013F2 + {0x0F12, 0x024E}, //senHal_pContSenModesRegsArray[36][1] 2 700013F4 + {0x0F12, 0x012E}, //senHal_pContSenModesRegsArray[36][2] 2 700013F6 + {0x0F12, 0x016D}, //senHal_pContSenModesRegsArray[36][3] 2 700013F8 + {0x0F12, 0x039F}, //senHal_pContSenModesRegsArray[37][0] 2 700013FA + {0x0F12, 0x045E}, //senHal_pContSenModesRegsArray[37][1] 2 700013FC + {0x0F12, 0x01DD}, //senHal_pContSenModesRegsArray[37][2] 2 700013FE + {0x0F12, 0x029C}, //senHal_pContSenModesRegsArray[37][3] 2 70001400 + {0x0F12, 0x041D}, //senHal_pContSenModesRegsArray[38][0] 2 70001402 + {0x0F12, 0x04A9}, //senHal_pContSenModesRegsArray[38][1] 2 70001404 + {0x0F12, 0x025B}, //senHal_pContSenModesRegsArray[38][2] 2 70001406 + {0x0F12, 0x02E7}, //senHal_pContSenModesRegsArray[38][3] 2 70001408 + {0x0F12, 0x062D}, //senHal_pContSenModesRegsArray[39][0] 2 7000140A + {0x0F12, 0x0639}, //senHal_pContSenModesRegsArray[39][1] 2 7000140C + {0x0F12, 0x038A}, //senHal_pContSenModesRegsArray[39][2] 2 7000140E + {0x0F12, 0x0396}, //senHal_pContSenModesRegsArray[39][3] 2 70001410 + {0x0F12, 0x066C}, //senHal_pContSenModesRegsArray[40][0] 2 70001412 + {0x0F12, 0x06B7}, //senHal_pContSenModesRegsArray[40][1] 2 70001414 + {0x0F12, 0x03C9}, //senHal_pContSenModesRegsArray[40][2] 2 70001416 + {0x0F12, 0x0414}, //senHal_pContSenModesRegsArray[40][3] 2 70001418 + {0x0F12, 0x087C}, //senHal_pContSenModesRegsArray[41][0] 2 7000141A + {0x0F12, 0x08C7}, //senHal_pContSenModesRegsArray[41][1] 2 7000141C + {0x0F12, 0x04F8}, //senHal_pContSenModesRegsArray[41][2] 2 7000141E + {0x0F12, 0x0543}, //senHal_pContSenModesRegsArray[41][3] 2 70001420 + {0x0F12, 0x0040}, //senHal_pContSenModesRegsArray[42][0] 2 70001422 + {0x0F12, 0x0040}, //senHal_pContSenModesRegsArray[42][1] 2 70001424 + {0x0F12, 0x0040}, //senHal_pContSenModesRegsArray[42][2] 2 70001426 + {0x0F12, 0x0040}, //senHal_pContSenModesRegsArray[42][3] 2 70001428 + {0x0F12, 0x01D0}, //senHal_pContSenModesRegsArray[43][0] 2 7000142A + {0x0F12, 0x01D0}, //senHal_pContSenModesRegsArray[43][1] 2 7000142C + {0x0F12, 0x00EF}, //senHal_pContSenModesRegsArray[43][2] 2 7000142E + {0x0F12, 0x00EF}, //senHal_pContSenModesRegsArray[43][3] 2 70001430 + {0x0F12, 0x020F}, //senHal_pContSenModesRegsArray[44][0] 2 70001432 + {0x0F12, 0x024E}, //senHal_pContSenModesRegsArray[44][1] 2 70001434 + {0x0F12, 0x012E}, //senHal_pContSenModesRegsArray[44][2] 2 70001436 + {0x0F12, 0x016D}, //senHal_pContSenModesRegsArray[44][3] 2 70001438 + {0x0F12, 0x039F}, //senHal_pContSenModesRegsArray[45][0] 2 7000143A + {0x0F12, 0x045E}, //senHal_pContSenModesRegsArray[45][1] 2 7000143C + {0x0F12, 0x01DD}, //senHal_pContSenModesRegsArray[45][2] 2 7000143E + {0x0F12, 0x029C}, //senHal_pContSenModesRegsArray[45][3] 2 70001440 + {0x0F12, 0x041D}, //senHal_pContSenModesRegsArray[46][0] 2 70001442 + {0x0F12, 0x04A9}, //senHal_pContSenModesRegsArray[46][1] 2 70001444 + {0x0F12, 0x025B}, //senHal_pContSenModesRegsArray[46][2] 2 70001446 + {0x0F12, 0x02E7}, //senHal_pContSenModesRegsArray[46][3] 2 70001448 + {0x0F12, 0x062D}, //senHal_pContSenModesRegsArray[47][0] 2 7000144A + {0x0F12, 0x0639}, //senHal_pContSenModesRegsArray[47][1] 2 7000144C + {0x0F12, 0x038A}, //senHal_pContSenModesRegsArray[47][2] 2 7000144E + {0x0F12, 0x0396}, //senHal_pContSenModesRegsArray[47][3] 2 70001450 + {0x0F12, 0x066C}, //senHal_pContSenModesRegsArray[48][0] 2 70001452 + {0x0F12, 0x06B7}, //senHal_pContSenModesRegsArray[48][1] 2 70001454 + {0x0F12, 0x03C9}, //senHal_pContSenModesRegsArray[48][2] 2 70001456 + {0x0F12, 0x0414}, //senHal_pContSenModesRegsArray[48][3] 2 70001458 + {0x0F12, 0x087C}, //senHal_pContSenModesRegsArray[49][0] 2 7000145A + {0x0F12, 0x08C7}, //senHal_pContSenModesRegsArray[49][1] 2 7000145C + {0x0F12, 0x04F8}, //senHal_pContSenModesRegsArray[49][2] 2 7000145E + {0x0F12, 0x0543}, //senHal_pContSenModesRegsArray[49][3] 2 70001460 + {0x0F12, 0x003D}, //senHal_pContSenModesRegsArray[50][0] 2 70001462 + {0x0F12, 0x003D}, //senHal_pContSenModesRegsArray[50][1] 2 70001464 + {0x0F12, 0x003D}, //senHal_pContSenModesRegsArray[50][2] 2 70001466 + {0x0F12, 0x003D}, //senHal_pContSenModesRegsArray[50][3] 2 70001468 + {0x0F12, 0x01D2}, //senHal_pContSenModesRegsArray[51][0] 2 7000146A + {0x0F12, 0x01D2}, //senHal_pContSenModesRegsArray[51][1] 2 7000146C + {0x0F12, 0x00F1}, //senHal_pContSenModesRegsArray[51][2] 2 7000146E + {0x0F12, 0x00F1}, //senHal_pContSenModesRegsArray[51][3] 2 70001470 + {0x0F12, 0x020C}, //senHal_pContSenModesRegsArray[52][0] 2 70001472 + {0x0F12, 0x024B}, //senHal_pContSenModesRegsArray[52][1] 2 70001474 + {0x0F12, 0x012B}, //senHal_pContSenModesRegsArray[52][2] 2 70001476 + {0x0F12, 0x016A}, //senHal_pContSenModesRegsArray[52][3] 2 70001478 + {0x0F12, 0x03A1}, //senHal_pContSenModesRegsArray[53][0] 2 7000147A + {0x0F12, 0x0460}, //senHal_pContSenModesRegsArray[53][1] 2 7000147C + {0x0F12, 0x01DF}, //senHal_pContSenModesRegsArray[53][2] 2 7000147E + {0x0F12, 0x029E}, //senHal_pContSenModesRegsArray[53][3] 2 70001480 + {0x0F12, 0x041A}, //senHal_pContSenModesRegsArray[54][0] 2 70001482 + {0x0F12, 0x04A6}, //senHal_pContSenModesRegsArray[54][1] 2 70001484 + {0x0F12, 0x0258}, //senHal_pContSenModesRegsArray[54][2] 2 70001486 + {0x0F12, 0x02E4}, //senHal_pContSenModesRegsArray[54][3] 2 70001488 + {0x0F12, 0x062F}, //senHal_pContSenModesRegsArray[55][0] 2 7000148A + {0x0F12, 0x063B}, //senHal_pContSenModesRegsArray[55][1] 2 7000148C + {0x0F12, 0x038C}, //senHal_pContSenModesRegsArray[55][2] 2 7000148E + {0x0F12, 0x0398}, //senHal_pContSenModesRegsArray[55][3] 2 70001490 + {0x0F12, 0x0669}, //senHal_pContSenModesRegsArray[56][0] 2 70001492 + {0x0F12, 0x06B4}, //senHal_pContSenModesRegsArray[56][1] 2 70001494 + {0x0F12, 0x03C6}, //senHal_pContSenModesRegsArray[56][2] 2 70001496 + {0x0F12, 0x0411}, //senHal_pContSenModesRegsArray[56][3] 2 70001498 + {0x0F12, 0x087E}, //senHal_pContSenModesRegsArray[57][0] 2 7000149A + {0x0F12, 0x08C9}, //senHal_pContSenModesRegsArray[57][1] 2 7000149C + {0x0F12, 0x04FA}, //senHal_pContSenModesRegsArray[57][2] 2 7000149E + {0x0F12, 0x0545}, //senHal_pContSenModesRegsArray[57][3] 2 700014A0 + {0x0F12, 0x03A2}, //senHal_pContSenModesRegsArray[58][0] 2 700014A2 + {0x0F12, 0x01D3}, //senHal_pContSenModesRegsArray[58][1] 2 700014A4 + {0x0F12, 0x01E0}, //senHal_pContSenModesRegsArray[58][2] 2 700014A6 + {0x0F12, 0x00F2}, //senHal_pContSenModesRegsArray[58][3] 2 700014A8 + {0x0F12, 0x03AF}, //senHal_pContSenModesRegsArray[59][0] 2 700014AA + {0x0F12, 0x01E0}, //senHal_pContSenModesRegsArray[59][1] 2 700014AC + {0x0F12, 0x01ED}, //senHal_pContSenModesRegsArray[59][2] 2 700014AE + {0x0F12, 0x00FF}, //senHal_pContSenModesRegsArray[59][3] 2 700014B0 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[60][0] 2 700014B2 + {0x0F12, 0x0461}, //senHal_pContSenModesRegsArray[60][1] 2 700014B4 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[60][2] 2 700014B6 + {0x0F12, 0x029F}, //senHal_pContSenModesRegsArray[60][3] 2 700014B8 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[61][0] 2 700014BA + {0x0F12, 0x046E}, //senHal_pContSenModesRegsArray[61][1] 2 700014BC + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[61][2] 2 700014BE + {0x0F12, 0x02AC}, //senHal_pContSenModesRegsArray[61][3] 2 700014C0 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[62][0] 2 700014C2 + {0x0F12, 0x063C}, //senHal_pContSenModesRegsArray[62][1] 2 700014C4 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[62][2] 2 700014C6 + {0x0F12, 0x0399}, //senHal_pContSenModesRegsArray[62][3] 2 700014C8 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[63][0] 2 700014CA + {0x0F12, 0x0649}, //senHal_pContSenModesRegsArray[63][1] 2 700014CC + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[63][2] 2 700014CE + {0x0F12, 0x03A6}, //senHal_pContSenModesRegsArray[63][3] 2 700014D0 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[64][0] 2 700014D2 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[64][1] 2 700014D4 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[64][2] 2 700014D6 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[64][3] 2 700014D8 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[65][0] 2 700014DA + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[65][1] 2 700014DC + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[65][2] 2 700014DE + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[65][3] 2 700014E0 + {0x0F12, 0x03AA}, //senHal_pContSenModesRegsArray[66][0] 2 700014E2 + {0x0F12, 0x01DB}, //senHal_pContSenModesRegsArray[66][1] 2 700014E4 + {0x0F12, 0x01E8}, //senHal_pContSenModesRegsArray[66][2] 2 700014E6 + {0x0F12, 0x00FA}, //senHal_pContSenModesRegsArray[66][3] 2 700014E8 + {0x0F12, 0x03B7}, //senHal_pContSenModesRegsArray[67][0] 2 700014EA + {0x0F12, 0x01E8}, //senHal_pContSenModesRegsArray[67][1] 2 700014EC + {0x0F12, 0x01F5}, //senHal_pContSenModesRegsArray[67][2] 2 700014EE + {0x0F12, 0x0107}, //senHal_pContSenModesRegsArray[67][3] 2 700014F0 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[68][0] 2 700014F2 + {0x0F12, 0x0469}, //senHal_pContSenModesRegsArray[68][1] 2 700014F4 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[68][2] 2 700014F6 + {0x0F12, 0x02A7}, //senHal_pContSenModesRegsArray[68][3] 2 700014F8 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[69][0] 2 700014FA + {0x0F12, 0x0476}, //senHal_pContSenModesRegsArray[69][1] 2 700014FC + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[69][2] 2 700014FE + {0x0F12, 0x02B4}, //senHal_pContSenModesRegsArray[69][3] 2 70001500 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[70][0] 2 70001502 + {0x0F12, 0x0644}, //senHal_pContSenModesRegsArray[70][1] 2 70001504 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[70][2] 2 70001506 + {0x0F12, 0x03A1}, //senHal_pContSenModesRegsArray[70][3] 2 70001508 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[71][0] 2 7000150A + {0x0F12, 0x0651}, //senHal_pContSenModesRegsArray[71][1] 2 7000150C + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[71][2] 2 7000150E + {0x0F12, 0x03AE}, //senHal_pContSenModesRegsArray[71][3] 2 70001510 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[72][0] 2 70001512 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[72][1] 2 70001514 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[72][2] 2 70001516 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[72][3] 2 70001518 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[73][0] 2 7000151A + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[73][1] 2 7000151C + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[73][2] 2 7000151E + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[73][3] 2 70001520 + {0x0F12, 0x0001}, //senHal_pContSenModesRegsArray[74][0] 2 70001522 + {0x0F12, 0x0001}, //senHal_pContSenModesRegsArray[74][1] 2 70001524 + {0x0F12, 0x0001}, //senHal_pContSenModesRegsArray[74][2] 2 70001526 + {0x0F12, 0x0001}, //senHal_pContSenModesRegsArray[74][3] 2 70001528 + {0x0F12, 0x000F}, //senHal_pContSenModesRegsArray[75][0] 2 7000152A + {0x0F12, 0x000F}, //senHal_pContSenModesRegsArray[75][1] 2 7000152C + {0x0F12, 0x000F}, //senHal_pContSenModesRegsArray[75][2] 2 7000152E + {0x0F12, 0x000F}, //senHal_pContSenModesRegsArray[75][3] 2 70001530 + {0x0F12, 0x05AD}, //senHal_pContSenModesRegsArray[76][0] 2 70001532 + {0x0F12, 0x03DE}, //senHal_pContSenModesRegsArray[76][1] 2 70001534 + {0x0F12, 0x030A}, //senHal_pContSenModesRegsArray[76][2] 2 70001536 + {0x0F12, 0x021C}, //senHal_pContSenModesRegsArray[76][3] 2 70001538 + {0x0F12, 0x062F}, //senHal_pContSenModesRegsArray[77][0] 2 7000153A + {0x0F12, 0x0460}, //senHal_pContSenModesRegsArray[77][1] 2 7000153C + {0x0F12, 0x038C}, //senHal_pContSenModesRegsArray[77][2] 2 7000153E + {0x0F12, 0x029E}, //senHal_pContSenModesRegsArray[77][3] 2 70001540 + {0x0F12, 0x07FC}, //senHal_pContSenModesRegsArray[78][0] 2 70001542 + {0x0F12, 0x0847}, //senHal_pContSenModesRegsArray[78][1] 2 70001544 + {0x0F12, 0x0478}, //senHal_pContSenModesRegsArray[78][2] 2 70001546 + {0x0F12, 0x04C3}, //senHal_pContSenModesRegsArray[78][3] 2 70001548 + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[79][0] 2 7000154A + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[79][1] 2 7000154C + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[79][2] 2 7000154E + {0x0F12, 0x0000}, //senHal_pContSenModesRegsArray[79][3] 2 70001550 + + + //============================================================ + // AF Interface setting + //============================================================ + {0x0028, 0x7000},//DTS2012071201781: add by huyouhua 00136760 at 2012-7-20 + {0x002A, 0x01D4}, + {0x0F12, 0x0000}, //REG_TC_IPRM_AuxGpios : 0 - no Flash + {0x002A, 0x01DE}, + {0x0F12, 0x0003}, //REG_TC_IPRM_CM_Init_AfModeType : 3 - AFD_VCM_I2C + {0x0F12, 0x0000}, //REG_TC_IPRM_CM_Init_PwmConfig1 : 0 - no PWM + {0x002A, 0x01E4}, + {0x0F12, 0x0041}, //REG_TC_IPRM_CM_Init_GpioConfig1 : 4 - GPIO4 + {0x002A, 0x01E8}, + {0x0F12, 0x2A0C}, //REG_TC_IPRM_CM_Init_Mi2cBits : MSCL - GPIO1 MSDA - GPIO2 Device ID {0C} + {0x0F12, 0x0190}, //REG_TC_IPRM_CM_Init_Mi2cRateKhz : MI2C Speed - 400KHz + //BEGIN: DTS2012071201781: add by huyouhua 00136760 at 2012-7-20 + {0x002A, 0x1196}, //afd_usFlags 0100=low,0000=high + {0x0F12, 0x0000}, + //END: DTS2012071201781: add by huyouhua 00136760 at 2012-7-20 + //============================================================ + // AF Parameter setting + //============================================================ + // AF Window Settings + {0x002A, 0x025A}, + {0x0F12, 0x0100}, //#REG_TC_AF_FstWinStartX + {0x0F12, 0x00E3}, //#REG_TC_AF_FstWinStartY //DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x0200}, //#REG_TC_AF_FstWinSizeX + {0x0F12, 0x0238}, //#REG_TC_AF_FstWinSizeY + {0x0F12, 0x018C}, //#REG_TC_AF_ScndWinStartX + {0x0F12, 0x0166}, //#REG_TC_AF_ScndWinStartY //DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x00E6}, //#REG_TC_AF_ScndWinSizeX + {0x0F12, 0x0132}, //#REG_TC_AF_ScndWinSizeY + {0x0F12, 0x0001}, //#REG_TC_AF_WinSizesUpdated + + // AF Setot Settings + {0x002A, 0x0586}, + {0x0F12, 0x00FF}, //#skl_af_StatOvlpExpFactor + + // AF Scene Settings + {0x002A, 0x115E}, + {0x0F12, 0x0003}, //#af_scene_usSaturatedScene + + // AF Fine Search Settings + {0x002A, 0x10D4}, + {0x0F12, 0x1000}, //FineSearch Disable //#af_search_usSingleAfFlags + {0x002A, 0x10DE}, + {0x0F12, 0x0004}, //#af_search_usFinePeakCount + {0x002A, 0x106C}, + {0x0F12, 0x0202}, //#af_pos_usFineStepNumSize + + // AF Peak Threshold Setting + {0x002A, 0x10CA}, //#af_search_usPeakThr + {0x0F12, 0x00C0}, + + // AF Default Position + {0x002A, 0x1060}, + {0x0F12, 0x003C}, //#af_pos_usHomePos //DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x783C}, //#af_pos_usLowConfPos //DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + + // AF LowConfThr Setting + {0x002A, 0x10F4}, //LowEdgeBoth GRAD + {0x0F12, 0x0280}, + {0x002A, 0x1100}, //LowLight HPF + {0x0F12, 0x03A0}, + {0x0F12, 0x0320}, + + {0x002A, 0x1134}, + {0x0F12, 0x0030},//af_stat_usMinStatVal + + // AF low Br Th + {0x002A, 0x1154}, // normBrThr + {0x0F12, 0x0060}, + + // AF Policy + {0x002A, 0x10E2}, + {0x0F12, 0x0000}, //#af_search_usCapturePolicy: Focus_Priority, 0002 : Shutter_Priority_Fixed, 0001 : Shutter_Priority_Last_BFP 0000: Shutter_Priority_Current + {0x002A, 0x1072}, + {0x0F12, 0x003C}, //#af_pos_usCaptureFixedPo// 0x0008 + + // AF Lens Position Table Settings + {0x002A, 0x1074}, + //BEGIN: DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x0010}, //#af_pos_usTableLastInd// 16 Steps 091222 + {0x0F12, 0x003C}, //#af_pos_usTable_0_// af_pos_usTable + {0x0F12, 0x003F}, //#af_pos_usTable_1_ + {0x0F12, 0x0042}, //#af_pos_usTable_2_ + {0x0F12, 0x0045}, //#af_pos_usTable_3_ + {0x0F12, 0x0048}, //#af_pos_usTable_4_ + {0x0F12, 0x004B}, //#af_pos_usTable_5_ + {0x0F12, 0x004E}, //#af_pos_usTable_6_ + {0x0F12, 0x0051}, //#af_pos_usTable_7_ + {0x0F12, 0x0054}, //#af_pos_usTable_8_ + {0x0F12, 0x0057}, //#af_pos_usTable_9_ + {0x0F12, 0x005A}, //#af_pos_usTable_10_ + {0x0F12, 0x005E}, //#af_pos_usTable_11_ + {0x0F12, 0x0061}, //#af_pos_usTable_12_ + {0x0F12, 0x0064}, //#af_pos_usTable_13_ + {0x0F12, 0x0068}, //#af_pos_usTable_14_ + {0x0F12, 0x006C}, //#af_pos_usTable_15_ + {0x0F12, 0x0078}, //#af_pos_usTable_16_ + //END: DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x002A, 0x0252}, + {0x0F12, 0x0003}, //init + //BEGIN: DTS2012071201781: del by huyouhua 00136760 at 2012-7-20 + //{0x002A, 0x12B8}, //disable CINTR 0 + //{0x0F12, 0x1000}, + //END: DTS2012071201781: del by huyouhua 00136760 at 2012-7-20 + //============================================================ + // ISP-FE Setting + //============================================================ + {0x002A, 0x158A}, + {0x0F12, 0xEAF0}, + {0x002A, 0x15C6}, + {0x0F12, 0x0020}, + {0x0F12, 0x0060}, + {0x002A, 0x15BC}, + {0x0F12, 0x0200}, + + {0x002A, 0x1608}, + {0x0F12, 0x0100}, + {0x0F12, 0x0100}, + {0x0F12, 0x0100}, + {0x0F12, 0x0100}, + //BEGIN: DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x002A, 0x0530}, + {0x0F12, 0x5DC0}, //#lt_uMaxExp1 60ms + {0x0F12, 0x0000}, + {0x0F12, 0x6D60}, //#lt_uMaxExp2 70ms + {0x0F12, 0x0000}, + {0x002A, 0x167C}, + {0x0F12, 0x9C40}, //#evt1_lt_uMaxExp3 100ms + {0x0F12, 0x0000}, + {0x0F12, 0x3880},//BB80 //#evt1_lt_uMaxExp4 120ms + {0x0F12, 0x0001},//0000 + // Set capture exposure time + {0x002A, 0x0538}, + {0x0F12, 0x5DC0}, //#lt_uCapMaxExp160ms + {0x0F12, 0x0000}, + {0x0F12, 0x6D60}, //#lt_uCapMaxExp270ms + {0x0F12, 0x0000}, + {0x002A, 0x1684}, + {0x0F12, 0x9C40}, //#evt1_lt_uCapMaxExp3 100ms + {0x0F12, 0x0000}, + {0x0F12, 0xBB80}, //#evt1_lt_uCapMaxExp4 120ms + {0x0F12, 0x0000}, + // Set gain + {0x002A, 0x0540}, + {0x0F12, 0x0150}, //#lt_uMaxAnGain1 + {0x0F12, 0x0280}, //#lt_uMaxAnGain2 + {0x002A, 0x168C}, + {0x0F12, 0x02A0}, //#evt1_lt_uMaxAnGain3 + {0x0F12, 0x0800}, //#evt1_lt_uMaxAnGain4 + + {0x002A, 0x0544}, + {0x0F12, 0x0100}, //#lt_uMaxDigGain + {0x0F12, 0x0A00}, //#lt_uMaxTotGain + + {0x002A, 1694}, + {0x0F12, 0001}, //#evt1_senHal_bExpandForbid //expand forbidde zone + + //002A 051A + //0F12 0111 //#lt_uLimitHigh + //0F12 00F0 //#lt_uLimitLow + + //============================================================ + //Tuning part + //============================================================ + //Calibrations go here + //============================================================ + //Anti-Shading + //============================================================ + // param_start TVAR_ash_GASAlpha + {0x0028, 0x7000}, + {0x002A, 0x06CE}, + {0x0F12, 0x00FE}, //TVAR_ash_GASAlpha[0] + {0x0F12, 0x00E0}, //TVAR_ash_GASAlpha[1] + {0x0F12, 0x00F0}, //TVAR_ash_GASAlpha[2] + {0x0F12, 0x00FE}, //TVAR_ash_GASAlpha[3] + {0x0F12, 0x00F0}, //TVAR_ash_GASAlpha[4] + {0x0F12, 0x00E0}, //TVAR_ash_GASAlpha[5] + {0x0F12, 0x00C0}, //TVAR_ash_GASAlpha[6] + {0x0F12, 0x00E0}, //TVAR_ash_GASAlpha[7] + {0x0F12, 0x00EF}, //TVAR_ash_GASAlpha[8] + {0x0F12, 0x00FF}, //TVAR_ash_GASAlpha[9] + {0x0F12, 0x00F9}, //TVAR_ash_GASAlpha[10] + {0x0F12, 0x00E0}, //TVAR_ash_GASAlpha[11] + {0x0F12, 0x00CE}, //TVAR_ash_GASAlpha[12] + {0x0F12, 0x00FF}, //TVAR_ash_GASAlpha[13] + {0x0F12, 0x0100}, //TVAR_ash_GASAlpha[14] + {0x0F12, 0x00E0}, //TVAR_ash_GASAlpha[15] + {0x0F12, 0x00DF}, //TVAR_ash_GASAlpha[16] + {0x0F12, 0x00F4}, //TVAR_ash_GASAlpha[17] + {0x0F12, 0x00F3}, //TVAR_ash_GASAlpha[18] + {0x0F12, 0x00F5}, //TVAR_ash_GASAlpha[19] + {0x0F12, 0x00E0}, //TVAR_ash_GASAlpha[20] + {0x0F12, 0x00E9}, //TVAR_ash_GASAlpha[21] + {0x0F12, 0x00E6}, //TVAR_ash_GASAlpha[22] + {0x0F12, 0x00F6}, //TVAR_ash_GASAlpha[23] + {0x0F12, 0x00CE}, //TVAR_ash_GASAlpha[24] + {0x0F12, 0x00E9}, //TVAR_ash_GASAlpha[25] + {0x0F12, 0x00E6}, //TVAR_ash_GASAlpha[26] + {0x0F12, 0x00F6}, //TVAR_ash_GASAlpha[27] + // param_end TVAR_ash_GASAlpha + // param_start TVAR_ash_GASOutdoorAlpha + {0x002A, 0x0706}, + {0x0F12, 0x00E4}, //TVAR_ash_GASOutdoorAlpha[0] + {0x0F12, 0x00E9}, //TVAR_ash_GASOutdoorAlpha[1] + {0x0F12, 0x00E6}, //TVAR_ash_GASOutdoorAlpha[2] + {0x0F12, 0x00F6}, //TVAR_ash_GASOutdoorAlpha[3] + // param_end TVAR_ash_GASOutdoorAlpha + // param_start ash_GASBeta + {0x002A, 0x070E}, + {0x0F12, 0x0060}, //ash_GASBeta[0] + {0x0F12, 0x002B}, //ash_GASBeta[1] + {0x0F12, 0x002F}, //ash_GASBeta[2] + {0x0F12, 0x0000}, //ash_GASBeta[3] + {0x0F12, 0x0052}, //ash_GASBeta[4] + {0x0F12, 0x0026}, //ash_GASBeta[5] + {0x0F12, 0x0029}, //ash_GASBeta[6] + {0x0F12, 0x0000}, //ash_GASBeta[7] + {0x0F12, 0x0010}, //ash_GASBeta[8] + {0x0F12, 0x0026}, //ash_GASBeta[9] + {0x0F12, 0x0028}, //ash_GASBeta[10] + {0x0F12, 0x0000}, //ash_GASBeta[11] + {0x0F12, 0x0010}, //ash_GASBeta[12] + {0x0F12, 0x0026}, //ash_GASBeta[13] + {0x0F12, 0x0027}, //ash_GASBeta[14] + {0x0F12, 0x0000}, //ash_GASBeta[15] + {0x0F12, 0x0023}, //ash_GASBeta[16] + {0x0F12, 0x001F}, //ash_GASBeta[17] + {0x0F12, 0x001F}, //ash_GASBeta[18] + {0x0F12, 0x0000}, //ash_GASBeta[19] + {0x0F12, 0x0025}, //ash_GASBeta[20] + {0x0F12, 0x0017}, //ash_GASBeta[21] + {0x0F12, 0x0016}, //ash_GASBeta[22] + {0x0F12, 0x0000}, //ash_GASBeta[23] + {0x0F12, 0x0025}, //ash_GASBeta[24] + {0x0F12, 0x0017}, //ash_GASBeta[25] + {0x0F12, 0x0016}, //ash_GASBeta[26] + {0x0F12, 0x0000}, //ash_GASBeta[27] + // param_end ash_GASBeta + // param_start ash_GASOutdoorBeta + {0x002A, 0x0746}, + {0x0F12, 0x0025}, //ash_GASOutdoorBeta[0] + {0x0F12, 0x0017}, //ash_GASOutdoorBeta[1] + {0x0F12, 0x0016}, //ash_GASOutdoorBeta[2] + {0x0F12, 0x0000}, //ash_GASOutdoorBeta[3] + // param_end ash_GASOutdoorBeta + {0x002A, 0x075A}, + {0x0F12, 0x0000}, //ash_bParabolicEstimation + {0x0F12, 0x0400}, //ash_uParabolicCenterX + {0x0F12, 0x0300}, //ash_uParabolicCenterY + {0x0F12, 0x0010}, //ash_uParabolicScalingA + {0x0F12, 0x0011}, //ash_uParabolicScalingB + // param_start TVAR_ash_pGAS + {0x002A, 0x347C}, + {0x0F12, 0x025B}, //TVAR_ash_pGAS[0] + {0x0F12, 0x01B4}, //TVAR_ash_pGAS[1] + {0x0F12, 0x0156}, //TVAR_ash_pGAS[2] + {0x0F12, 0x0112}, //TVAR_ash_pGAS[3] + {0x0F12, 0x00EE}, //TVAR_ash_pGAS[4] + {0x0F12, 0x00D8}, //TVAR_ash_pGAS[5] + {0x0F12, 0x00CE}, //TVAR_ash_pGAS[6] + {0x0F12, 0x00D4}, //TVAR_ash_pGAS[7] + {0x0F12, 0x00E6}, //TVAR_ash_pGAS[8] + {0x0F12, 0x010B}, //TVAR_ash_pGAS[9] + {0x0F12, 0x0141}, //TVAR_ash_pGAS[10] + {0x0F12, 0x019F}, //TVAR_ash_pGAS[11] + {0x0F12, 0x027A}, //TVAR_ash_pGAS[12] + {0x0F12, 0x01CD}, //TVAR_ash_pGAS[13] + {0x0F12, 0x0174}, //TVAR_ash_pGAS[14] + {0x0F12, 0x0115}, //TVAR_ash_pGAS[15] + {0x0F12, 0x00D8}, //TVAR_ash_pGAS[16] + {0x0F12, 0x00B2}, //TVAR_ash_pGAS[17] + {0x0F12, 0x009C}, //TVAR_ash_pGAS[18] + {0x0F12, 0x0092}, //TVAR_ash_pGAS[19] + {0x0F12, 0x009A}, //TVAR_ash_pGAS[20] + {0x0F12, 0x00B0}, //TVAR_ash_pGAS[21] + {0x0F12, 0x00D9}, //TVAR_ash_pGAS[22] + {0x0F12, 0x0111}, //TVAR_ash_pGAS[23] + {0x0F12, 0x015F}, //TVAR_ash_pGAS[24] + {0x0F12, 0x01DD}, //TVAR_ash_pGAS[25] + {0x0F12, 0x0176}, //TVAR_ash_pGAS[26] + {0x0F12, 0x0128}, //TVAR_ash_pGAS[27] + {0x0F12, 0x00D1}, //TVAR_ash_pGAS[28] + {0x0F12, 0x0097}, //TVAR_ash_pGAS[29] + {0x0F12, 0x006F}, //TVAR_ash_pGAS[30] + {0x0F12, 0x0056}, //TVAR_ash_pGAS[31] + {0x0F12, 0x004D}, //TVAR_ash_pGAS[32] + {0x0F12, 0x0057}, //TVAR_ash_pGAS[33] + {0x0F12, 0x0073}, //TVAR_ash_pGAS[34] + {0x0F12, 0x009E}, //TVAR_ash_pGAS[35] + {0x0F12, 0x00D9}, //TVAR_ash_pGAS[36] + {0x0F12, 0x0122}, //TVAR_ash_pGAS[37] + {0x0F12, 0x0173}, //TVAR_ash_pGAS[38] + {0x0F12, 0x0144}, //TVAR_ash_pGAS[39] + {0x0F12, 0x00FE}, //TVAR_ash_pGAS[40] + {0x0F12, 0x00A9}, //TVAR_ash_pGAS[41] + {0x0F12, 0x006F}, //TVAR_ash_pGAS[42] + {0x0F12, 0x0043}, //TVAR_ash_pGAS[43] + {0x0F12, 0x0028}, //TVAR_ash_pGAS[44] + {0x0F12, 0x001F}, //TVAR_ash_pGAS[45] + {0x0F12, 0x002A}, //TVAR_ash_pGAS[46] + {0x0F12, 0x0049}, //TVAR_ash_pGAS[47] + {0x0F12, 0x0079}, //TVAR_ash_pGAS[48] + {0x0F12, 0x00B6}, //TVAR_ash_pGAS[49] + {0x0F12, 0x0102}, //TVAR_ash_pGAS[50] + {0x0F12, 0x014F}, //TVAR_ash_pGAS[51] + {0x0F12, 0x012D}, //TVAR_ash_pGAS[52] + {0x0F12, 0x00E7}, //TVAR_ash_pGAS[53] + {0x0F12, 0x0094}, //TVAR_ash_pGAS[54] + {0x0F12, 0x0056}, //TVAR_ash_pGAS[55] + {0x0F12, 0x0028}, //TVAR_ash_pGAS[56] + {0x0F12, 0x000E}, //TVAR_ash_pGAS[57] + {0x0F12, 0x0007}, //TVAR_ash_pGAS[58] + {0x0F12, 0x0011}, //TVAR_ash_pGAS[59] + {0x0F12, 0x0030}, //TVAR_ash_pGAS[60] + {0x0F12, 0x0063}, //TVAR_ash_pGAS[61] + {0x0F12, 0x00A6}, //TVAR_ash_pGAS[62] + {0x0F12, 0x00F2}, //TVAR_ash_pGAS[63] + {0x0F12, 0x013D}, //TVAR_ash_pGAS[64] + {0x0F12, 0x0126}, //TVAR_ash_pGAS[65] + {0x0F12, 0x00E1}, //TVAR_ash_pGAS[66] + {0x0F12, 0x008D}, //TVAR_ash_pGAS[67] + {0x0F12, 0x004E}, //TVAR_ash_pGAS[68] + {0x0F12, 0x0022}, //TVAR_ash_pGAS[69] + {0x0F12, 0x0007}, //TVAR_ash_pGAS[70] + {0x0F12, 0x0000}, //TVAR_ash_pGAS[71] + {0x0F12, 0x000A}, //TVAR_ash_pGAS[72] + {0x0F12, 0x0028}, //TVAR_ash_pGAS[73] + {0x0F12, 0x005E}, //TVAR_ash_pGAS[74] + {0x0F12, 0x00A3}, //TVAR_ash_pGAS[75] + {0x0F12, 0x00F0}, //TVAR_ash_pGAS[76] + {0x0F12, 0x013B}, //TVAR_ash_pGAS[77] + {0x0F12, 0x0133}, //TVAR_ash_pGAS[78] + {0x0F12, 0x00EE}, //TVAR_ash_pGAS[79] + {0x0F12, 0x0099}, //TVAR_ash_pGAS[80] + {0x0F12, 0x005A}, //TVAR_ash_pGAS[81] + {0x0F12, 0x002D}, //TVAR_ash_pGAS[82] + {0x0F12, 0x0013}, //TVAR_ash_pGAS[83] + {0x0F12, 0x000B}, //TVAR_ash_pGAS[84] + {0x0F12, 0x0016}, //TVAR_ash_pGAS[85] + {0x0F12, 0x0035}, //TVAR_ash_pGAS[86] + {0x0F12, 0x006C}, //TVAR_ash_pGAS[87] + {0x0F12, 0x00B2}, //TVAR_ash_pGAS[88] + {0x0F12, 0x0100}, //TVAR_ash_pGAS[89] + {0x0F12, 0x0148}, //TVAR_ash_pGAS[90] + {0x0F12, 0x0153}, //TVAR_ash_pGAS[91] + {0x0F12, 0x0107}, //TVAR_ash_pGAS[92] + {0x0F12, 0x00B4}, //TVAR_ash_pGAS[93] + {0x0F12, 0x0078}, //TVAR_ash_pGAS[94] + {0x0F12, 0x004B}, //TVAR_ash_pGAS[95] + {0x0F12, 0x0030}, //TVAR_ash_pGAS[96] + {0x0F12, 0x002A}, //TVAR_ash_pGAS[97] + {0x0F12, 0x0036}, //TVAR_ash_pGAS[98] + {0x0F12, 0x0057}, //TVAR_ash_pGAS[99] + {0x0F12, 0x008B}, //TVAR_ash_pGAS[100] + {0x0F12, 0x00D1}, //TVAR_ash_pGAS[101] + {0x0F12, 0x0121}, //TVAR_ash_pGAS[102] + {0x0F12, 0x016A}, //TVAR_ash_pGAS[103] + {0x0F12, 0x0189}, //TVAR_ash_pGAS[104] + {0x0F12, 0x0138}, //TVAR_ash_pGAS[105] + {0x0F12, 0x00DF}, //TVAR_ash_pGAS[106] + {0x0F12, 0x00A8}, //TVAR_ash_pGAS[107] + {0x0F12, 0x007E}, //TVAR_ash_pGAS[108] + {0x0F12, 0x0065}, //TVAR_ash_pGAS[109] + {0x0F12, 0x005F}, //TVAR_ash_pGAS[110] + {0x0F12, 0x006A}, //TVAR_ash_pGAS[111] + {0x0F12, 0x008C}, //TVAR_ash_pGAS[112] + {0x0F12, 0x00BF}, //TVAR_ash_pGAS[113] + {0x0F12, 0x00FE}, //TVAR_ash_pGAS[114] + {0x0F12, 0x0150}, //TVAR_ash_pGAS[115] + {0x0F12, 0x019E}, //TVAR_ash_pGAS[116] + {0x0F12, 0x01D5}, //TVAR_ash_pGAS[117] + {0x0F12, 0x0181}, //TVAR_ash_pGAS[118] + {0x0F12, 0x0125}, //TVAR_ash_pGAS[119] + {0x0F12, 0x00EA}, //TVAR_ash_pGAS[120] + {0x0F12, 0x00C7}, //TVAR_ash_pGAS[121] + {0x0F12, 0x00B2}, //TVAR_ash_pGAS[122] + {0x0F12, 0x00AC}, //TVAR_ash_pGAS[123] + {0x0F12, 0x00BA}, //TVAR_ash_pGAS[124] + {0x0F12, 0x00D5}, //TVAR_ash_pGAS[125] + {0x0F12, 0x0100}, //TVAR_ash_pGAS[126] + {0x0F12, 0x0140}, //TVAR_ash_pGAS[127] + {0x0F12, 0x019B}, //TVAR_ash_pGAS[128] + {0x0F12, 0x0217}, //TVAR_ash_pGAS[129] + {0x0F12, 0x0280}, //TVAR_ash_pGAS[130] + {0x0F12, 0x01CC}, //TVAR_ash_pGAS[131] + {0x0F12, 0x0176}, //TVAR_ash_pGAS[132] + {0x0F12, 0x0131}, //TVAR_ash_pGAS[133] + {0x0F12, 0x010E}, //TVAR_ash_pGAS[134] + {0x0F12, 0x00FF}, //TVAR_ash_pGAS[135] + {0x0F12, 0x00FC}, //TVAR_ash_pGAS[136] + {0x0F12, 0x0103}, //TVAR_ash_pGAS[137] + {0x0F12, 0x011B}, //TVAR_ash_pGAS[138] + {0x0F12, 0x0146}, //TVAR_ash_pGAS[139] + {0x0F12, 0x018B}, //TVAR_ash_pGAS[140] + {0x0F12, 0x01F8}, //TVAR_ash_pGAS[141] + {0x0F12, 0x02DD}, //TVAR_ash_pGAS[142] + {0x0F12, 0x0232}, //TVAR_ash_pGAS[143] + {0x0F12, 0x018A}, //TVAR_ash_pGAS[144] + {0x0F12, 0x0127}, //TVAR_ash_pGAS[145] + {0x0F12, 0x00EF}, //TVAR_ash_pGAS[146] + {0x0F12, 0x00CA}, //TVAR_ash_pGAS[147] + {0x0F12, 0x00B4}, //TVAR_ash_pGAS[148] + {0x0F12, 0x00AB}, //TVAR_ash_pGAS[149] + {0x0F12, 0x00B1}, //TVAR_ash_pGAS[150] + {0x0F12, 0x00C3}, //TVAR_ash_pGAS[151] + {0x0F12, 0x00E5}, //TVAR_ash_pGAS[152] + {0x0F12, 0x0118}, //TVAR_ash_pGAS[153] + {0x0F12, 0x0168}, //TVAR_ash_pGAS[154] + {0x0F12, 0x023A}, //TVAR_ash_pGAS[155] + {0x0F12, 0x019A}, //TVAR_ash_pGAS[156] + {0x0F12, 0x013E}, //TVAR_ash_pGAS[157] + {0x0F12, 0x00E5}, //TVAR_ash_pGAS[158] + {0x0F12, 0x00B1}, //TVAR_ash_pGAS[159] + {0x0F12, 0x008E}, //TVAR_ash_pGAS[160] + {0x0F12, 0x0079}, //TVAR_ash_pGAS[161] + {0x0F12, 0x0072}, //TVAR_ash_pGAS[162] + {0x0F12, 0x0078}, //TVAR_ash_pGAS[163] + {0x0F12, 0x008E}, //TVAR_ash_pGAS[164] + {0x0F12, 0x00B2}, //TVAR_ash_pGAS[165] + {0x0F12, 0x00E1}, //TVAR_ash_pGAS[166] + {0x0F12, 0x0121}, //TVAR_ash_pGAS[167] + {0x0F12, 0x019A}, //TVAR_ash_pGAS[168] + {0x0F12, 0x014D}, //TVAR_ash_pGAS[169] + {0x0F12, 0x0100}, //TVAR_ash_pGAS[170] + {0x0F12, 0x00AE}, //TVAR_ash_pGAS[171] + {0x0F12, 0x007F}, //TVAR_ash_pGAS[172] + {0x0F12, 0x005B}, //TVAR_ash_pGAS[173] + {0x0F12, 0x0043}, //TVAR_ash_pGAS[174] + {0x0F12, 0x003B}, //TVAR_ash_pGAS[175] + {0x0F12, 0x0045}, //TVAR_ash_pGAS[176] + {0x0F12, 0x005E}, //TVAR_ash_pGAS[177] + {0x0F12, 0x0083}, //TVAR_ash_pGAS[178] + {0x0F12, 0x00B4}, //TVAR_ash_pGAS[179] + {0x0F12, 0x00EF}, //TVAR_ash_pGAS[180] + {0x0F12, 0x0139}, //TVAR_ash_pGAS[181] + {0x0F12, 0x0120}, //TVAR_ash_pGAS[182] + {0x0F12, 0x00DB}, //TVAR_ash_pGAS[183] + {0x0F12, 0x008D}, //TVAR_ash_pGAS[184] + {0x0F12, 0x005D}, //TVAR_ash_pGAS[185] + {0x0F12, 0x0037}, //TVAR_ash_pGAS[186] + {0x0F12, 0x001F}, //TVAR_ash_pGAS[187] + {0x0F12, 0x0017}, //TVAR_ash_pGAS[188] + {0x0F12, 0x0022}, //TVAR_ash_pGAS[189] + {0x0F12, 0x003D}, //TVAR_ash_pGAS[190] + {0x0F12, 0x0066}, //TVAR_ash_pGAS[191] + {0x0F12, 0x009A}, //TVAR_ash_pGAS[192] + {0x0F12, 0x00D7}, //TVAR_ash_pGAS[193] + {0x0F12, 0x011A}, //TVAR_ash_pGAS[194] + {0x0F12, 0x0108}, //TVAR_ash_pGAS[195] + {0x0F12, 0x00C7}, //TVAR_ash_pGAS[196] + {0x0F12, 0x007B}, //TVAR_ash_pGAS[197] + {0x0F12, 0x004A}, //TVAR_ash_pGAS[198] + {0x0F12, 0x0023}, //TVAR_ash_pGAS[199] + {0x0F12, 0x000B}, //TVAR_ash_pGAS[200] + {0x0F12, 0x0005}, //TVAR_ash_pGAS[201] + {0x0F12, 0x000E}, //TVAR_ash_pGAS[202] + {0x0F12, 0x002A}, //TVAR_ash_pGAS[203] + {0x0F12, 0x0055}, //TVAR_ash_pGAS[204] + {0x0F12, 0x008D}, //TVAR_ash_pGAS[205] + {0x0F12, 0x00C9}, //TVAR_ash_pGAS[206] + {0x0F12, 0x0104}, //TVAR_ash_pGAS[207] + {0x0F12, 0x0100}, //TVAR_ash_pGAS[208] + {0x0F12, 0x00C0}, //TVAR_ash_pGAS[209] + {0x0F12, 0x0076}, //TVAR_ash_pGAS[210] + {0x0F12, 0x0044}, //TVAR_ash_pGAS[211] + {0x0F12, 0x001E}, //TVAR_ash_pGAS[212] + {0x0F12, 0x0006}, //TVAR_ash_pGAS[213] + {0x0F12, 0x0000}, //TVAR_ash_pGAS[214] + {0x0F12, 0x0009}, //TVAR_ash_pGAS[215] + {0x0F12, 0x0024}, //TVAR_ash_pGAS[216] + {0x0F12, 0x0052}, //TVAR_ash_pGAS[217] + {0x0F12, 0x008B}, //TVAR_ash_pGAS[218] + {0x0F12, 0x00C8}, //TVAR_ash_pGAS[219] + {0x0F12, 0x0104}, //TVAR_ash_pGAS[220] + {0x0F12, 0x0109}, //TVAR_ash_pGAS[221] + {0x0F12, 0x00C9}, //TVAR_ash_pGAS[222] + {0x0F12, 0x007F}, //TVAR_ash_pGAS[223] + {0x0F12, 0x004D}, //TVAR_ash_pGAS[224] + {0x0F12, 0x0027}, //TVAR_ash_pGAS[225] + {0x0F12, 0x0010}, //TVAR_ash_pGAS[226] + {0x0F12, 0x000A}, //TVAR_ash_pGAS[227] + {0x0F12, 0x0014}, //TVAR_ash_pGAS[228] + {0x0F12, 0x002F}, //TVAR_ash_pGAS[229] + {0x0F12, 0x005D}, //TVAR_ash_pGAS[230] + {0x0F12, 0x0098}, //TVAR_ash_pGAS[231] + {0x0F12, 0x00D7}, //TVAR_ash_pGAS[232] + {0x0F12, 0x010E}, //TVAR_ash_pGAS[233] + {0x0F12, 0x0125}, //TVAR_ash_pGAS[234] + {0x0F12, 0x00E0}, //TVAR_ash_pGAS[235] + {0x0F12, 0x0094}, //TVAR_ash_pGAS[236] + {0x0F12, 0x0066}, //TVAR_ash_pGAS[237] + {0x0F12, 0x0040}, //TVAR_ash_pGAS[238] + {0x0F12, 0x002A}, //TVAR_ash_pGAS[239] + {0x0F12, 0x0024}, //TVAR_ash_pGAS[240] + {0x0F12, 0x002F}, //TVAR_ash_pGAS[241] + {0x0F12, 0x004C}, //TVAR_ash_pGAS[242] + {0x0F12, 0x0078}, //TVAR_ash_pGAS[243] + {0x0F12, 0x00B3}, //TVAR_ash_pGAS[244] + {0x0F12, 0x00F4}, //TVAR_ash_pGAS[245] + {0x0F12, 0x012F}, //TVAR_ash_pGAS[246] + {0x0F12, 0x0153}, //TVAR_ash_pGAS[247] + {0x0F12, 0x0108}, //TVAR_ash_pGAS[248] + {0x0F12, 0x00B9}, //TVAR_ash_pGAS[249] + {0x0F12, 0x008D}, //TVAR_ash_pGAS[250] + {0x0F12, 0x006B}, //TVAR_ash_pGAS[251] + {0x0F12, 0x0055}, //TVAR_ash_pGAS[252] + {0x0F12, 0x0050}, //TVAR_ash_pGAS[253] + {0x0F12, 0x005D}, //TVAR_ash_pGAS[254] + {0x0F12, 0x007A}, //TVAR_ash_pGAS[255] + {0x0F12, 0x00A4}, //TVAR_ash_pGAS[256] + {0x0F12, 0x00D9}, //TVAR_ash_pGAS[257] + {0x0F12, 0x011D}, //TVAR_ash_pGAS[258] + {0x0F12, 0x015E}, //TVAR_ash_pGAS[259] + {0x0F12, 0x019C}, //TVAR_ash_pGAS[260] + {0x0F12, 0x0144}, //TVAR_ash_pGAS[261] + {0x0F12, 0x00F3}, //TVAR_ash_pGAS[262] + {0x0F12, 0x00C2}, //TVAR_ash_pGAS[263] + {0x0F12, 0x00A4}, //TVAR_ash_pGAS[264] + {0x0F12, 0x0093}, //TVAR_ash_pGAS[265] + {0x0F12, 0x008F}, //TVAR_ash_pGAS[266] + {0x0F12, 0x009C}, //TVAR_ash_pGAS[267] + {0x0F12, 0x00B5}, //TVAR_ash_pGAS[268] + {0x0F12, 0x00DA}, //TVAR_ash_pGAS[269] + {0x0F12, 0x010E}, //TVAR_ash_pGAS[270] + {0x0F12, 0x015E}, //TVAR_ash_pGAS[271] + {0x0F12, 0x01C9}, //TVAR_ash_pGAS[272] + {0x0F12, 0x0239}, //TVAR_ash_pGAS[273] + {0x0F12, 0x0186}, //TVAR_ash_pGAS[274] + {0x0F12, 0x0137}, //TVAR_ash_pGAS[275] + {0x0F12, 0x00FF}, //TVAR_ash_pGAS[276] + {0x0F12, 0x00DE}, //TVAR_ash_pGAS[277] + {0x0F12, 0x00CF}, //TVAR_ash_pGAS[278] + {0x0F12, 0x00CE}, //TVAR_ash_pGAS[279] + {0x0F12, 0x00D5}, //TVAR_ash_pGAS[280] + {0x0F12, 0x00ED}, //TVAR_ash_pGAS[281] + {0x0F12, 0x0113}, //TVAR_ash_pGAS[282] + {0x0F12, 0x014E}, //TVAR_ash_pGAS[283] + {0x0F12, 0x01B0}, //TVAR_ash_pGAS[284] + {0x0F12, 0x0285}, //TVAR_ash_pGAS[285] + {0x0F12, 0x020F}, //TVAR_ash_pGAS[286] + {0x0F12, 0x0173}, //TVAR_ash_pGAS[287] + {0x0F12, 0x0112}, //TVAR_ash_pGAS[288] + {0x0F12, 0x00DE}, //TVAR_ash_pGAS[289] + {0x0F12, 0x00BF}, //TVAR_ash_pGAS[290] + {0x0F12, 0x00AD}, //TVAR_ash_pGAS[291] + {0x0F12, 0x00A8}, //TVAR_ash_pGAS[292] + {0x0F12, 0x00B3}, //TVAR_ash_pGAS[293] + {0x0F12, 0x00CC}, //TVAR_ash_pGAS[294] + {0x0F12, 0x00F2}, //TVAR_ash_pGAS[295] + {0x0F12, 0x0126}, //TVAR_ash_pGAS[296] + {0x0F12, 0x0176}, //TVAR_ash_pGAS[297] + {0x0F12, 0x024B}, //TVAR_ash_pGAS[298] + {0x0F12, 0x0180}, //TVAR_ash_pGAS[299] + {0x0F12, 0x012F}, //TVAR_ash_pGAS[300] + {0x0F12, 0x00D5}, //TVAR_ash_pGAS[301] + {0x0F12, 0x00A7}, //TVAR_ash_pGAS[302] + {0x0F12, 0x0087}, //TVAR_ash_pGAS[303] + {0x0F12, 0x0075}, //TVAR_ash_pGAS[304] + {0x0F12, 0x0072}, //TVAR_ash_pGAS[305] + {0x0F12, 0x007E}, //TVAR_ash_pGAS[306] + {0x0F12, 0x0096}, //TVAR_ash_pGAS[307] + {0x0F12, 0x00BE}, //TVAR_ash_pGAS[308] + {0x0F12, 0x00EF}, //TVAR_ash_pGAS[309] + {0x0F12, 0x012F}, //TVAR_ash_pGAS[310] + {0x0F12, 0x01A7}, //TVAR_ash_pGAS[311] + {0x0F12, 0x013C}, //TVAR_ash_pGAS[312] + {0x0F12, 0x00F5}, //TVAR_ash_pGAS[313] + {0x0F12, 0x00A5}, //TVAR_ash_pGAS[314] + {0x0F12, 0x0078}, //TVAR_ash_pGAS[315] + {0x0F12, 0x0057}, //TVAR_ash_pGAS[316] + {0x0F12, 0x0042}, //TVAR_ash_pGAS[317] + {0x0F12, 0x003D}, //TVAR_ash_pGAS[318] + {0x0F12, 0x0049}, //TVAR_ash_pGAS[319] + {0x0F12, 0x0066}, //TVAR_ash_pGAS[320] + {0x0F12, 0x008F}, //TVAR_ash_pGAS[321] + {0x0F12, 0x00C0}, //TVAR_ash_pGAS[322] + {0x0F12, 0x00FD}, //TVAR_ash_pGAS[323] + {0x0F12, 0x0144}, //TVAR_ash_pGAS[324] + {0x0F12, 0x0115}, //TVAR_ash_pGAS[325] + {0x0F12, 0x00D6}, //TVAR_ash_pGAS[326] + {0x0F12, 0x0089}, //TVAR_ash_pGAS[327] + {0x0F12, 0x005B}, //TVAR_ash_pGAS[328] + {0x0F12, 0x0036}, //TVAR_ash_pGAS[329] + {0x0F12, 0x001F}, //TVAR_ash_pGAS[330] + {0x0F12, 0x0018}, //TVAR_ash_pGAS[331] + {0x0F12, 0x0024}, //TVAR_ash_pGAS[332] + {0x0F12, 0x0043}, //TVAR_ash_pGAS[333] + {0x0F12, 0x006F}, //TVAR_ash_pGAS[334] + {0x0F12, 0x00A5}, //TVAR_ash_pGAS[335] + {0x0F12, 0x00E0}, //TVAR_ash_pGAS[336] + {0x0F12, 0x0122}, //TVAR_ash_pGAS[337] + {0x0F12, 0x0104}, //TVAR_ash_pGAS[338] + {0x0F12, 0x00C7}, //TVAR_ash_pGAS[339] + {0x0F12, 0x007B}, //TVAR_ash_pGAS[340] + {0x0F12, 0x004A}, //TVAR_ash_pGAS[341] + {0x0F12, 0x0023}, //TVAR_ash_pGAS[342] + {0x0F12, 0x000B}, //TVAR_ash_pGAS[343] + {0x0F12, 0x0005}, //TVAR_ash_pGAS[344] + {0x0F12, 0x0010}, //TVAR_ash_pGAS[345] + {0x0F12, 0x002E}, //TVAR_ash_pGAS[346] + {0x0F12, 0x005B}, //TVAR_ash_pGAS[347] + {0x0F12, 0x0094}, //TVAR_ash_pGAS[348] + {0x0F12, 0x00D0}, //TVAR_ash_pGAS[349] + {0x0F12, 0x010C}, //TVAR_ash_pGAS[350] + {0x0F12, 0x0105}, //TVAR_ash_pGAS[351] + {0x0F12, 0x00C5}, //TVAR_ash_pGAS[352] + {0x0F12, 0x007A}, //TVAR_ash_pGAS[353] + {0x0F12, 0x0047}, //TVAR_ash_pGAS[354] + {0x0F12, 0x0021}, //TVAR_ash_pGAS[355] + {0x0F12, 0x0008}, //TVAR_ash_pGAS[356] + {0x0F12, 0x0000}, //TVAR_ash_pGAS[357] + {0x0F12, 0x0009}, //TVAR_ash_pGAS[358] + {0x0F12, 0x0026}, //TVAR_ash_pGAS[359] + {0x0F12, 0x0054}, //TVAR_ash_pGAS[360] + {0x0F12, 0x008E}, //TVAR_ash_pGAS[361] + {0x0F12, 0x00CA}, //TVAR_ash_pGAS[362] + {0x0F12, 0x0106}, //TVAR_ash_pGAS[363] + {0x0F12, 0x0116}, //TVAR_ash_pGAS[364] + {0x0F12, 0x00D3}, //TVAR_ash_pGAS[365] + {0x0F12, 0x0088}, //TVAR_ash_pGAS[366] + {0x0F12, 0x0054}, //TVAR_ash_pGAS[367] + {0x0F12, 0x002C}, //TVAR_ash_pGAS[368] + {0x0F12, 0x0012}, //TVAR_ash_pGAS[369] + {0x0F12, 0x0009}, //TVAR_ash_pGAS[370] + {0x0F12, 0x0013}, //TVAR_ash_pGAS[371] + {0x0F12, 0x002E}, //TVAR_ash_pGAS[372] + {0x0F12, 0x005C}, //TVAR_ash_pGAS[373] + {0x0F12, 0x0095}, //TVAR_ash_pGAS[374] + {0x0F12, 0x00D4}, //TVAR_ash_pGAS[375] + {0x0F12, 0x010D}, //TVAR_ash_pGAS[376] + {0x0F12, 0x013A}, //TVAR_ash_pGAS[377] + {0x0F12, 0x00EE}, //TVAR_ash_pGAS[378] + {0x0F12, 0x00A1}, //TVAR_ash_pGAS[379] + {0x0F12, 0x006F}, //TVAR_ash_pGAS[380] + {0x0F12, 0x0047}, //TVAR_ash_pGAS[381] + {0x0F12, 0x002C}, //TVAR_ash_pGAS[382] + {0x0F12, 0x0023}, //TVAR_ash_pGAS[383] + {0x0F12, 0x002D}, //TVAR_ash_pGAS[384] + {0x0F12, 0x0047}, //TVAR_ash_pGAS[385] + {0x0F12, 0x0072}, //TVAR_ash_pGAS[386] + {0x0F12, 0x00AB}, //TVAR_ash_pGAS[387] + {0x0F12, 0x00EB}, //TVAR_ash_pGAS[388] + {0x0F12, 0x0127}, //TVAR_ash_pGAS[389] + {0x0F12, 0x016C}, //TVAR_ash_pGAS[390] + {0x0F12, 0x011B}, //TVAR_ash_pGAS[391] + {0x0F12, 0x00CA}, //TVAR_ash_pGAS[392] + {0x0F12, 0x0099}, //TVAR_ash_pGAS[393] + {0x0F12, 0x0074}, //TVAR_ash_pGAS[394] + {0x0F12, 0x0059}, //TVAR_ash_pGAS[395] + {0x0F12, 0x0050}, //TVAR_ash_pGAS[396] + {0x0F12, 0x0057}, //TVAR_ash_pGAS[397] + {0x0F12, 0x0072}, //TVAR_ash_pGAS[398] + {0x0F12, 0x0099}, //TVAR_ash_pGAS[399] + {0x0F12, 0x00CB}, //TVAR_ash_pGAS[400] + {0x0F12, 0x0111}, //TVAR_ash_pGAS[401] + {0x0F12, 0x0155}, //TVAR_ash_pGAS[402] + {0x0F12, 0x01BA}, //TVAR_ash_pGAS[403] + {0x0F12, 0x015D}, //TVAR_ash_pGAS[404] + {0x0F12, 0x0107}, //TVAR_ash_pGAS[405] + {0x0F12, 0x00D3}, //TVAR_ash_pGAS[406] + {0x0F12, 0x00AE}, //TVAR_ash_pGAS[407] + {0x0F12, 0x0099}, //TVAR_ash_pGAS[408] + {0x0F12, 0x008F}, //TVAR_ash_pGAS[409] + {0x0F12, 0x0096}, //TVAR_ash_pGAS[410] + {0x0F12, 0x00AB}, //TVAR_ash_pGAS[411] + {0x0F12, 0x00CD}, //TVAR_ash_pGAS[412] + {0x0F12, 0x00FE}, //TVAR_ash_pGAS[413] + {0x0F12, 0x014D}, //TVAR_ash_pGAS[414] + {0x0F12, 0x01BC}, //TVAR_ash_pGAS[415] + {0x0F12, 0x025D}, //TVAR_ash_pGAS[416] + {0x0F12, 0x01A6}, //TVAR_ash_pGAS[417] + {0x0F12, 0x0151}, //TVAR_ash_pGAS[418] + {0x0F12, 0x0115}, //TVAR_ash_pGAS[419] + {0x0F12, 0x00F0}, //TVAR_ash_pGAS[420] + {0x0F12, 0x00DA}, //TVAR_ash_pGAS[421] + {0x0F12, 0x00D0}, //TVAR_ash_pGAS[422] + {0x0F12, 0x00D3}, //TVAR_ash_pGAS[423] + {0x0F12, 0x00E5}, //TVAR_ash_pGAS[424] + {0x0F12, 0x0108}, //TVAR_ash_pGAS[425] + {0x0F12, 0x013F}, //TVAR_ash_pGAS[426] + {0x0F12, 0x019E}, //TVAR_ash_pGAS[427] + {0x0F12, 0x0271}, //TVAR_ash_pGAS[428] + {0x0F12, 0x01B8}, //TVAR_ash_pGAS[429] + {0x0F12, 0x013B}, //TVAR_ash_pGAS[430] + {0x0F12, 0x00E6}, //TVAR_ash_pGAS[431] + {0x0F12, 0x00BB}, //TVAR_ash_pGAS[432] + {0x0F12, 0x00A5}, //TVAR_ash_pGAS[433] + {0x0F12, 0x009A}, //TVAR_ash_pGAS[434] + {0x0F12, 0x0096}, //TVAR_ash_pGAS[435] + {0x0F12, 0x00A0}, //TVAR_ash_pGAS[436] + {0x0F12, 0x00B1}, //TVAR_ash_pGAS[437] + {0x0F12, 0x00D0}, //TVAR_ash_pGAS[438] + {0x0F12, 0x00FE}, //TVAR_ash_pGAS[439] + {0x0F12, 0x0148}, //TVAR_ash_pGAS[440] + {0x0F12, 0x01EF}, //TVAR_ash_pGAS[441] + {0x0F12, 0x0133}, //TVAR_ash_pGAS[442] + {0x0F12, 0x00F9}, //TVAR_ash_pGAS[443] + {0x0F12, 0x00B0}, //TVAR_ash_pGAS[444] + {0x0F12, 0x008A}, //TVAR_ash_pGAS[445] + {0x0F12, 0x0074}, //TVAR_ash_pGAS[446] + {0x0F12, 0x0069}, //TVAR_ash_pGAS[447] + {0x0F12, 0x0068}, //TVAR_ash_pGAS[448] + {0x0F12, 0x0071}, //TVAR_ash_pGAS[449] + {0x0F12, 0x0085}, //TVAR_ash_pGAS[450] + {0x0F12, 0x00A4}, //TVAR_ash_pGAS[451] + {0x0F12, 0x00CC}, //TVAR_ash_pGAS[452] + {0x0F12, 0x0106}, //TVAR_ash_pGAS[453] + {0x0F12, 0x0161}, //TVAR_ash_pGAS[454] + {0x0F12, 0x00F6}, //TVAR_ash_pGAS[455] + {0x0F12, 0x00C0}, //TVAR_ash_pGAS[456] + {0x0F12, 0x0080}, //TVAR_ash_pGAS[457] + {0x0F12, 0x005F}, //TVAR_ash_pGAS[458] + {0x0F12, 0x0048}, //TVAR_ash_pGAS[459] + {0x0F12, 0x003B}, //TVAR_ash_pGAS[460] + {0x0F12, 0x0039}, //TVAR_ash_pGAS[461] + {0x0F12, 0x0043}, //TVAR_ash_pGAS[462] + {0x0F12, 0x0059}, //TVAR_ash_pGAS[463] + {0x0F12, 0x0078}, //TVAR_ash_pGAS[464] + {0x0F12, 0x00A0}, //TVAR_ash_pGAS[465] + {0x0F12, 0x00D5}, //TVAR_ash_pGAS[466] + {0x0F12, 0x0107}, //TVAR_ash_pGAS[467] + {0x0F12, 0x00CE}, //TVAR_ash_pGAS[468] + {0x0F12, 0x00A0}, //TVAR_ash_pGAS[469] + {0x0F12, 0x0063}, //TVAR_ash_pGAS[470] + {0x0F12, 0x0043}, //TVAR_ash_pGAS[471] + {0x0F12, 0x0029}, //TVAR_ash_pGAS[472] + {0x0F12, 0x001B}, //TVAR_ash_pGAS[473] + {0x0F12, 0x0018}, //TVAR_ash_pGAS[474] + {0x0F12, 0x0020}, //TVAR_ash_pGAS[475] + {0x0F12, 0x0037}, //TVAR_ash_pGAS[476] + {0x0F12, 0x0059}, //TVAR_ash_pGAS[477] + {0x0F12, 0x0082}, //TVAR_ash_pGAS[478] + {0x0F12, 0x00B6}, //TVAR_ash_pGAS[479] + {0x0F12, 0x00E5}, //TVAR_ash_pGAS[480] + {0x0F12, 0x00BC}, //TVAR_ash_pGAS[481] + {0x0F12, 0x008F}, //TVAR_ash_pGAS[482] + {0x0F12, 0x0054}, //TVAR_ash_pGAS[483] + {0x0F12, 0x0031}, //TVAR_ash_pGAS[484] + {0x0F12, 0x0017}, //TVAR_ash_pGAS[485] + {0x0F12, 0x0008}, //TVAR_ash_pGAS[486] + {0x0F12, 0x0006}, //TVAR_ash_pGAS[487] + {0x0F12, 0x000D}, //TVAR_ash_pGAS[488] + {0x0F12, 0x0022}, //TVAR_ash_pGAS[489] + {0x0F12, 0x0044}, //TVAR_ash_pGAS[490] + {0x0F12, 0x0070}, //TVAR_ash_pGAS[491] + {0x0F12, 0x00A3}, //TVAR_ash_pGAS[492] + {0x0F12, 0x00CF}, //TVAR_ash_pGAS[493] + {0x0F12, 0x00B7}, //TVAR_ash_pGAS[494] + {0x0F12, 0x008A}, //TVAR_ash_pGAS[495] + {0x0F12, 0x0051}, //TVAR_ash_pGAS[496] + {0x0F12, 0x002D}, //TVAR_ash_pGAS[497] + {0x0F12, 0x0013}, //TVAR_ash_pGAS[498] + {0x0F12, 0x0005}, //TVAR_ash_pGAS[499] + {0x0F12, 0x0000}, //TVAR_ash_pGAS[500] + {0x0F12, 0x0006}, //TVAR_ash_pGAS[501] + {0x0F12, 0x001A}, //TVAR_ash_pGAS[502] + {0x0F12, 0x003B}, //TVAR_ash_pGAS[503] + {0x0F12, 0x0069}, //TVAR_ash_pGAS[504] + {0x0F12, 0x009A}, //TVAR_ash_pGAS[505] + {0x0F12, 0x00C8}, //TVAR_ash_pGAS[506] + {0x0F12, 0x00C3}, //TVAR_ash_pGAS[507] + {0x0F12, 0x0093}, //TVAR_ash_pGAS[508] + {0x0F12, 0x005A}, //TVAR_ash_pGAS[509] + {0x0F12, 0x0036}, //TVAR_ash_pGAS[510] + {0x0F12, 0x001B}, //TVAR_ash_pGAS[511] + {0x0F12, 0x000D}, //TVAR_ash_pGAS[512] + {0x0F12, 0x0008}, //TVAR_ash_pGAS[513] + {0x0F12, 0x000D}, //TVAR_ash_pGAS[514] + {0x0F12, 0x0020}, //TVAR_ash_pGAS[515] + {0x0F12, 0x0041}, //TVAR_ash_pGAS[516] + {0x0F12, 0x006C}, //TVAR_ash_pGAS[517] + {0x0F12, 0x00A0}, //TVAR_ash_pGAS[518] + {0x0F12, 0x00CC}, //TVAR_ash_pGAS[519] + {0x0F12, 0x00DE}, //TVAR_ash_pGAS[520] + {0x0F12, 0x00AA}, //TVAR_ash_pGAS[521] + {0x0F12, 0x0070}, //TVAR_ash_pGAS[522] + {0x0F12, 0x004D}, //TVAR_ash_pGAS[523] + {0x0F12, 0x0032}, //TVAR_ash_pGAS[524] + {0x0F12, 0x0023}, //TVAR_ash_pGAS[525] + {0x0F12, 0x001E}, //TVAR_ash_pGAS[526] + {0x0F12, 0x0024}, //TVAR_ash_pGAS[527] + {0x0F12, 0x0036}, //TVAR_ash_pGAS[528] + {0x0F12, 0x0055}, //TVAR_ash_pGAS[529] + {0x0F12, 0x007E}, //TVAR_ash_pGAS[530] + {0x0F12, 0x00B3}, //TVAR_ash_pGAS[531] + {0x0F12, 0x00E3}, //TVAR_ash_pGAS[532] + {0x0F12, 0x010B}, //TVAR_ash_pGAS[533] + {0x0F12, 0x00D0}, //TVAR_ash_pGAS[534] + {0x0F12, 0x0091}, //TVAR_ash_pGAS[535] + {0x0F12, 0x0070}, //TVAR_ash_pGAS[536] + {0x0F12, 0x0058}, //TVAR_ash_pGAS[537] + {0x0F12, 0x0048}, //TVAR_ash_pGAS[538] + {0x0F12, 0x0044}, //TVAR_ash_pGAS[539] + {0x0F12, 0x0048}, //TVAR_ash_pGAS[540] + {0x0F12, 0x005A}, //TVAR_ash_pGAS[541] + {0x0F12, 0x0075}, //TVAR_ash_pGAS[542] + {0x0F12, 0x009A}, //TVAR_ash_pGAS[543] + {0x0F12, 0x00D2}, //TVAR_ash_pGAS[544] + {0x0F12, 0x010B}, //TVAR_ash_pGAS[545] + {0x0F12, 0x014F}, //TVAR_ash_pGAS[546] + {0x0F12, 0x010B}, //TVAR_ash_pGAS[547] + {0x0F12, 0x00C5}, //TVAR_ash_pGAS[548] + {0x0F12, 0x00A0}, //TVAR_ash_pGAS[549] + {0x0F12, 0x008A}, //TVAR_ash_pGAS[550] + {0x0F12, 0x007F}, //TVAR_ash_pGAS[551] + {0x0F12, 0x0079}, //TVAR_ash_pGAS[552] + {0x0F12, 0x007D}, //TVAR_ash_pGAS[553] + {0x0F12, 0x008A}, //TVAR_ash_pGAS[554] + {0x0F12, 0x00A1}, //TVAR_ash_pGAS[555] + {0x0F12, 0x00C6}, //TVAR_ash_pGAS[556] + {0x0F12, 0x0107}, //TVAR_ash_pGAS[557] + {0x0F12, 0x0164}, //TVAR_ash_pGAS[558] + {0x0F12, 0x01E0}, //TVAR_ash_pGAS[559] + {0x0F12, 0x014B}, //TVAR_ash_pGAS[560] + {0x0F12, 0x0107}, //TVAR_ash_pGAS[561] + {0x0F12, 0x00D7}, //TVAR_ash_pGAS[562] + {0x0F12, 0x00BF}, //TVAR_ash_pGAS[563] + {0x0F12, 0x00B2}, //TVAR_ash_pGAS[564] + {0x0F12, 0x00AE}, //TVAR_ash_pGAS[565] + {0x0F12, 0x00AF}, //TVAR_ash_pGAS[566] + {0x0F12, 0x00B8}, //TVAR_ash_pGAS[567] + {0x0F12, 0x00D1}, //TVAR_ash_pGAS[568] + {0x0F12, 0x00FE}, //TVAR_ash_pGAS[569] + {0x0F12, 0x014D}, //TVAR_ash_pGAS[570] + {0x0F12, 0x01FD}, //TVAR_ash_pGAS[571] + // param_end TVAR_ash_pGAS + {0x002A, 0x074E}, + {0x0F12, 0x0001}, //ash_bLumaMode + {0x002A, 0x0D30}, + {0x0F12, 0x025F}, //awbb_GLocusR + {0x002A, 0x0D32}, + {0x0F12, 0x0376}, //awbb_GLocusB + // param_start TVAR_ash_AwbAshCord + {0x002A, 0x06B8}, + {0x0F12, 0x00C0}, //TVAR_ash_AwbAshCord[0] + {0x0F12, 0x00E0}, //TVAR_ash_AwbAshCord[1] + {0x0F12, 0x00FA}, //TVAR_ash_AwbAshCord[2] + {0x0F12, 0x011D}, //TVAR_ash_AwbAshCord[3] + {0x0F12, 0x0144}, //TVAR_ash_AwbAshCord[4] + {0x0F12, 0x0173}, //TVAR_ash_AwbAshCord[5] + {0x0F12, 0x0180}, //TVAR_ash_AwbAshCord[6] + // param_end TVAR_ash_AwbAshCord + {0x002A, 0x0664}, + {0x0F12, 0x013E}, //seti_uContrastCenter + + //ash_CGrasAlphas + {0x002A, 0x06C6}, + {0x0F12, 0x010B}, //ash_CGrasAlphas[0] + {0x0F12, 0x0103}, //ash_CGrasAlphas[1] + {0x0F12, 0x00FC}, //ash_CGrasAlphas[2] + {0x0F12, 0x010C}, //ash_CGrasAlphas[3] + //============================================================ + //End GAS + //============================================================ + //White Balance + //============================================================ + // param_start awbb_IndoorGrZones_m_BGrid + {0x002A, 0x0C48}, + {0x0F12, 0x03C9}, //awbb_IndoorGrZones_m_BGrid[0] + {0x0F12, 0x040A}, //awbb_IndoorGrZones_m_BGrid[1] + {0x0F12, 0x038B}, //awbb_IndoorGrZones_m_BGrid[2] + {0x0F12, 0x0405}, //awbb_IndoorGrZones_m_BGrid[3] + {0x0F12, 0x0356}, //awbb_IndoorGrZones_m_BGrid[4] + {0x0F12, 0x0400}, //awbb_IndoorGrZones_m_BGrid[5] + {0x0F12, 0x0322}, //awbb_IndoorGrZones_m_BGrid[6] + {0x0F12, 0x03DF}, //awbb_IndoorGrZones_m_BGrid[7] + {0x0F12, 0x02E9}, //awbb_IndoorGrZones_m_BGrid[8] + {0x0F12, 0x03B0}, //awbb_IndoorGrZones_m_BGrid[9] + {0x0F12, 0x02B6}, //awbb_IndoorGrZones_m_BGrid[10] + {0x0F12, 0x0380}, //awbb_IndoorGrZones_m_BGrid[11] + {0x0F12, 0x0296}, //awbb_IndoorGrZones_m_BGrid[12] + {0x0F12, 0x034F}, //awbb_IndoorGrZones_m_BGrid[13] + {0x0F12, 0x027F}, //awbb_IndoorGrZones_m_BGrid[14] + {0x0F12, 0x031A}, //awbb_IndoorGrZones_m_BGrid[15] + {0x0F12, 0x026C}, //awbb_IndoorGrZones_m_BGrid[16] + {0x0F12, 0x02F5}, //awbb_IndoorGrZones_m_BGrid[17] + {0x0F12, 0x0256}, //awbb_IndoorGrZones_m_BGrid[18] + {0x0F12, 0x02DA}, //awbb_IndoorGrZones_m_BGrid[19] + {0x0F12, 0x0241}, //awbb_IndoorGrZones_m_BGrid[20] + {0x0F12, 0x02C4}, //awbb_IndoorGrZones_m_BGrid[21] + {0x0F12, 0x0228}, //awbb_IndoorGrZones_m_BGrid[22] + {0x0F12, 0x02AB}, //awbb_IndoorGrZones_m_BGrid[23] + {0x0F12, 0x0213}, //awbb_IndoorGrZones_m_BGrid[24] + {0x0F12, 0x0292}, //awbb_IndoorGrZones_m_BGrid[25] + {0x0F12, 0x01FF}, //awbb_IndoorGrZones_m_BGrid[26] + {0x0F12, 0x0278}, //awbb_IndoorGrZones_m_BGrid[27] + {0x0F12, 0x01F4}, //awbb_IndoorGrZones_m_BGrid[28] + {0x0F12, 0x025F}, //awbb_IndoorGrZones_m_BGrid[29] + {0x0F12, 0x0202}, //awbb_IndoorGrZones_m_BGrid[30] + {0x0F12, 0x0234}, //awbb_IndoorGrZones_m_BGrid[31] + {0x0F12, 0x0000}, //awbb_IndoorGrZones_m_BGrid[32] + {0x0F12, 0x0000}, //awbb_IndoorGrZones_m_BGrid[33] + {0x0F12, 0x0000}, //awbb_IndoorGrZones_m_BGrid[34] + {0x0F12, 0x0000}, //awbb_IndoorGrZones_m_BGrid[35] + {0x0F12, 0x0000}, //awbb_IndoorGrZones_m_BGrid[36] + {0x0F12, 0x0000}, //awbb_IndoorGrZones_m_BGrid[37] + {0x0F12, 0x0000}, //awbb_IndoorGrZones_m_BGrid[38] + {0x0F12, 0x0000}, //awbb_IndoorGrZones_m_BGrid[39] + // param_end awbb_IndoorGrZones_m_BGrid + {0x002A, 0x0C98}, + {0x0F12, 0x0005}, + {0x0F12, 0x0000}, //awbb_IndoorGrZones_m_GridStep + {0x002A, 0x0CA0}, + {0x0F12, 0x00E8}, + {0x0F12, 0x0000}, //awbb_IndoorGrZones_m_Boffs + // param_start awbb_LowBrGrZones_m_BGrid + {0x002A, 0x0CE0}, + {0x0F12, 0x03D4}, //awbb_LowBrGrZones_m_BGrid[0] // + {0x0F12, 0x043E}, //awbb_LowBrGrZones_m_BGrid[1] // + {0x0F12, 0x035C}, //awbb_LowBrGrZones_m_BGrid[2] // + {0x0F12, 0x0438}, //awbb_LowBrGrZones_m_BGrid[3] // + {0x0F12, 0x02F0}, //awbb_LowBrGrZones_m_BGrid[4] // + {0x0F12, 0x042D}, //awbb_LowBrGrZones_m_BGrid[5] // + {0x0F12, 0x029A}, //awbb_LowBrGrZones_m_BGrid[6] // + {0x0F12, 0x03EF}, //awbb_LowBrGrZones_m_BGrid[7] // + {0x0F12, 0x025E}, //awbb_LowBrGrZones_m_BGrid[8] // + {0x0F12, 0x0395}, //awbb_LowBrGrZones_m_BGrid[9] // + {0x0F12, 0x022E}, //awbb_LowBrGrZones_m_BGrid[10] // + {0x0F12, 0x0346}, //awbb_LowBrGrZones_m_BGrid[11] // + {0x0F12, 0x0200}, //awbb_LowBrGrZones_m_BGrid[12] // + {0x0F12, 0x02F6}, //awbb_LowBrGrZones_m_BGrid[13] // + {0x0F12, 0x01CE}, //awbb_LowBrGrZones_m_BGrid[14] // + {0x0F12, 0x02C8}, //awbb_LowBrGrZones_m_BGrid[15] // + {0x0F12, 0x01BB}, //awbb_LowBrGrZones_m_BGrid[16] // + {0x0F12, 0x0287}, //awbb_LowBrGrZones_m_BGrid[17] // + {0x0F12, 0x01E2}, //awbb_LowBrGrZones_m_BGrid[18] // + {0x0F12, 0x0239}, //awbb_LowBrGrZones_m_BGrid[19] // + {0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[20] // + {0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[21] // + {0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[22] // + {0x0F12, 0x0000}, //awbb_LowBrGrZones_m_BGrid[23] // + // param_end awbb_LowBrGrZones_m_BGrid + {0x002A, 0x0D10}, + {0x0F12, 0x0006}, + {0x0F12, 0x0000}, //awbb_LowBrGrZones_m_GridStep + {0x002A, 0x0D18}, + {0x0F12, 0x00AE}, + {0x0F12, 0x0000}, //awbb_LowBrGrZones_m_Boffs + // param_start awbb_OutdoorGrZones_m_BGrid + {0x002A, 0x0CA4}, + {0x0F12, 0x031A},//02A8 //awbb_OutdoorGrZones_m_BGrid[0] + {0x0F12, 0x0382},//02C2 //awbb_OutdoorGrZones_m_BGrid[1] + {0x0F12, 0x02E3},//0270 //awbb_OutdoorGrZones_m_BGrid[2] + {0x0F12, 0x038B},//02B4 //awbb_OutdoorGrZones_m_BGrid[3] + {0x0F12, 0x02B7},//025C //awbb_OutdoorGrZones_m_BGrid[4] + {0x0F12, 0x035D},//02A0 //awbb_OutdoorGrZones_m_BGrid[5] + {0x0F12, 0x0297},//0240 //awbb_OutdoorGrZones_m_BGrid[6] + {0x0F12, 0x032A},//0288 //awbb_OutdoorGrZones_m_BGrid[7] + {0x0F12, 0x0285},//0230 //awbb_OutdoorGrZones_m_BGrid[8] + {0x0F12, 0x0302},//026E //awbb_OutdoorGrZones_m_BGrid[9] + {0x0F12, 0x0271},//0222 //awbb_OutdoorGrZones_m_BGrid[10] + {0x0F12, 0x02DF},//025A //awbb_OutdoorGrZones_m_BGrid[11] + {0x0F12, 0x025D},//0220 //awbb_OutdoorGrZones_m_BGrid[12] + {0x0F12, 0x02C7},//023A //awbb_OutdoorGrZones_m_BGrid[13] + {0x0F12, 0x0241},//0000 //awbb_OutdoorGrZones_m_BGrid[14] + {0x0F12, 0x02B5},//0000 //awbb_OutdoorGrZones_m_BGrid[15] + {0x0F12, 0x0229},//0000 //awbb_OutdoorGrZones_m_BGrid[16] + {0x0F12, 0x029B},//0000 //awbb_OutdoorGrZones_m_BGrid[17] + {0x0F12, 0x0212},//0000 //awbb_OutdoorGrZones_m_BGrid[18] + {0x0F12, 0x0280},//0000 //awbb_OutdoorGrZones_m_BGrid[19] + {0x0F12, 0x0205},//0000 //awbb_OutdoorGrZones_m_BGrid[20] + {0x0F12, 0x026A},//0000 //awbb_OutdoorGrZones_m_BGrid[21] + {0x0F12, 0x020A},//0000 //awbb_OutdoorGrZones_m_BGrid[22] + {0x0F12, 0x023F},//0000 //awbb_OutdoorGrZones_m_BGrid[23] + // param_end awbb_OutdoorGrZones_m_BGrid + {0x002A, 0x0CD4}, + {0x0F12, 0x0005}, + {0x0F12, 0x0000}, //awbb_OutdoorGrZones_m_GridStep + {0x002A, 0x0CDC}, + {0x0F12, 0x0157}, //01FE + {0x0F12, 0x0000}, //awbb_OutdoorGrZones_m_Boffs + //Low illumiantion + {0x002A, 0x0D1C}, + {0x0F12, 0x037C}, + {0x0F12, 0x0000}, //awbb_CrclLowT_R_c + {0x002A, 0x0D20}, + {0x0F12, 0x0157}, + {0x0F12, 0x0000}, //awbb_CrclLowT_B_c + {0x002A, 0x0D24}, + {0x0F12, 0x3EB8}, + {0x0F12, 0x0000}, //awbb_CrclLowT_Rad_c + //White locus + {0x002A, 0x0D2C}, + {0x0F12, 0x013D}, //awbb_IntcR + {0x0F12, 0x011E}, //awbb_IntcB + {0x002A, 0x0D46}, + {0x0F12, 0x0396}, //04A2 //awbb_MvEq_RBthresh + {0x002A, 0x0D5C}, + {0x0F12, 0x0584}, //awbb_LowTempRB + + //Grid Correction + // param_start awbb_GridCorr_R + {0x002A, 0x0DD4}, + {0x0F12, 0x003C}, //awbb_GridCorr_R[0] + {0x0F12, 0x0050}, //awbb_GridCorr_R[1] + {0x0F12, 0x0064}, //awbb_GridCorr_R[2] + {0x0F12, 0x0000}, //awbb_GridCorr_R[3] + {0x0F12, 0x0014}, //awbb_GridCorr_R[4] + {0x0F12, 0x0014}, //awbb_GridCorr_R[5] + {0x0F12, 0x003C}, //awbb_GridCorr_R[6] + {0x0F12, 0x0050}, //awbb_GridCorr_R[7] + {0x0F12, 0x0064}, //awbb_GridCorr_R[8] + {0x0F12, 0x0000}, //awbb_GridCorr_R[9] + {0x0F12, 0x0014}, //awbb_GridCorr_R[10] + {0x0F12, 0x0014}, //awbb_GridCorr_R[11] + {0x0F12, 0x003C}, //awbb_GridCorr_R[12] + {0x0F12, 0x0050}, //awbb_GridCorr_R[13] + {0x0F12, 0x0064}, //awbb_GridCorr_R[14] + {0x0F12, 0x0000}, //awbb_GridCorr_R[15] + {0x0F12, 0x0014}, //awbb_GridCorr_R[16] + {0x0F12, 0x0014}, //awbb_GridCorr_R[17] + // param_end awbb_GridCorr_R + // param_start awbb_GridCorr_B + {0x002A, 0x0DF8}, + {0x0F12, 0xFFEC}, //awbb_GridCorr_B[0] + {0x0F12, 0xFFEC}, //awbb_GridCorr_B[1] + {0x0F12, 0x0078}, //awbb_GridCorr_B[2] + {0x0F12, 0xFFE2}, //awbb_GridCorr_B[3] + {0x0F12, 0xFFE2}, //awbb_GridCorr_B[4] + {0x0F12, 0xFFB0}, //awbb_GridCorr_B[5] + {0x0F12, 0xFFEC}, //awbb_GridCorr_B[6] + {0x0F12, 0xFFEC}, //awbb_GridCorr_B[7] + {0x0F12, 0x0078}, //awbb_GridCorr_B[8] + {0x0F12, 0xFFE2}, //awbb_GridCorr_B[9] + {0x0F12, 0xFFE2}, //awbb_GridCorr_B[10] + {0x0F12, 0xFFB0}, //awbb_GridCorr_B[11] + {0x0F12, 0xFFEC}, //awbb_GridCorr_B[12] + {0x0F12, 0xFFEC}, //awbb_GridCorr_B[13] + {0x0F12, 0x0078}, //awbb_GridCorr_B[14] + {0x0F12, 0xFFE2}, //awbb_GridCorr_B[15] + {0x0F12, 0xFFE2}, //awbb_GridCorr_B[16] + {0x0F12, 0xFFB0}, //awbb_GridCorr_B[17] + // param_end awbb_GridCorr_B + // param_start awbb_GridConst_1 + {0x002A, 0x0E1C}, + {0x0F12, 0x02D9}, //awbb_GridConst_1[0] + {0x0F12, 0x0357}, //awbb_GridConst_1[1] + {0x0F12, 0x03D1}, //awbb_GridConst_1[2] + // param_end awbb_GridConst_1 + // param_start awbb_GridConst_2 + {0x002A, 0x0E22}, + {0x0F12, 0x0DE9}, //awbb_GridConst_2[0] + {0x0F12, 0x0EDD}, //awbb_GridConst_2[1] + {0x0F12, 0x0F42}, //awbb_GridConst_2[2] + {0x0F12, 0x0F54}, //awbb_GridConst_2[3] + {0x0F12, 0x0FAE}, //awbb_GridConst_2[4] + {0x0F12, 0x1011}, //awbb_GridConst_2[5] + // param_end awbb_GridConst_2 + {0x002A, 0x0E2E}, + {0x0F12, 0x00BA}, //awbb_GridCoeff_R_1 + {0x0F12, 0x00AF}, //awbb_GridCoeff_B_1 + {0x0F12, 0x0049}, //awbb_GridCoeff_R_2 + {0x0F12, 0x00F5}, //awbb_GridCoeff_B_2 + + {0x002A, 0x0E4A}, + {0x0F12, 0x0002}, //awbb_GridEnable + //============================================================ + //End AWB + //============================================================ + //AE + //============================================================ + //AE variation + {0x002A, 0x051A}, + {0x0F12, 0x010E}, //lt_uLimitHigh + {0x0F12, 0x00F5}, //lt_uLimitLow + //disable contrast, enable illumination + {0x002A, 0x0F76}, + {0x0F12, 0x0001}, // + + {0x002A, 0x1034}, + {0x0F12, 0x00C0}, //SARR_IllumType[0] + {0x0F12, 0x00E0}, //SARR_IllumType[1] + {0x0F12, 0x00F0}, //SARR_IllumType[2] + {0x0F12, 0x0129}, //SARR_IllumType[3] + {0x0F12, 0x0156}, //SARR_IllumType[4] + {0x0F12, 0x017F}, //SARR_IllumType[5] + {0x0F12, 0x018F}, //SARR_IllumType[6] + + {0x002A, 0x1042}, + {0x0F12, 0x0120}, //SARR_IllumTypeF[0] + {0x0F12, 0x0120}, //SARR_IllumTypeF[1] + {0x0F12, 0x0120}, //SARR_IllumTypeF[2] + {0x0F12, 0x0100}, //SARR_IllumTypeF[3] + {0x0F12, 0x0100}, //SARR_IllumTypeF[4] + {0x0F12, 0x0100}, //SARR_IllumTypeF[5] + {0x0F12, 0x0100}, //SARR_IllumTypeF[6] + + //AE target + {0x002A, 0x0F70}, + {0x0F12, 0x0046}, //TVAR_ae_BrAve + //AE Weight + {0x0028, 0x7000}, + {0x002A, 0x0f7e}, //AE weight/ + {0x0F12, 0x0101},//0000 + {0x0F12, 0x0101},//0000 + {0x0F12, 0x0101},//0000 + {0x0F12, 0x0101},//0000 + {0x0F12, 0x0101},//0101 + {0x0F12, 0x0101},//0101 + {0x0F12, 0x0101},//0101 + {0x0F12, 0x0101},//0101 + {0x0F12, 0x0101},//0101 + {0x0F12, 0x0303},//0101 + {0x0F12, 0x0303},//0101 + {0x0F12, 0x0101},//0101 + {0x0F12, 0x0101},//0101 + {0x0F12, 0x0303},//0401 + {0x0F12, 0x0303},//0104 + {0x0F12, 0x0101},//0101 + {0x0F12, 0x0101},//0101 + {0x0F12, 0x0303},//0401 + {0x0F12, 0x0303},//0104 + {0x0F12, 0x0101},//0101 + {0x0F12, 0x0101},//0101 + {0x0F12, 0x0303},//0201 + {0x0F12, 0x0303},//0102 + {0x0F12, 0x0101},//0101 + {0x0F12, 0x0101},//0101 + {0x0F12, 0x0101},//0201 + {0x0F12, 0x0101},//0102 + {0x0F12, 0x0101},//0101 + {0x0F12, 0x0101},//0101 + {0x0F12, 0x0101},//0101 + {0x0F12, 0x0101},//0101 + {0x0F12, 0x0101},//0101 + //============================================================ + //Gamma + //============================================================ + {0x002A, 0x3288}, + {0x0F12, 0x0000}, //#SARR_usDualGammaLutRGBIndoor[0][0] 0000 + {0x0F12, 0x0008}, //#SARR_usDualGammaLutRGBIndoor[0][1] 0008 + {0x0F12, 0x0013}, //#SARR_usDualGammaLutRGBIndoor[0][2] 0013 + {0x0F12, 0x002C}, //#SARR_usDualGammaLutRGBIndoor[0][3] 002C + {0x0F12, 0x0061}, //#SARR_usDualGammaLutRGBIndoor[0][4] 0061 + {0x0F12, 0x00C8}, //#SARR_usDualGammaLutRGBIndoor[0][5] 00C8 + {0x0F12, 0x0113}, //#SARR_usDualGammaLutRGBIndoor[0][6] 0113 + {0x0F12, 0x0132}, //#SARR_usDualGammaLutRGBIndoor[0][7] 0132 + {0x0F12, 0x014C}, //#SARR_usDualGammaLutRGBIndoor[0][8] 014C + {0x0F12, 0x0179}, //#SARR_usDualGammaLutRGBIndoor[0][9] 0179 + {0x0F12, 0x01A4}, //#SARR_usDualGammaLutRGBIndoor[0][10] 01A4 + {0x0F12, 0x01CD}, //#SARR_usDualGammaLutRGBIndoor[0][11] 01CD + {0x0F12, 0x01F4}, //#SARR_usDualGammaLutRGBIndoor[0][12] 01F4 + {0x0F12, 0x0239}, //#SARR_usDualGammaLutRGBIndoor[0][13] 0239 + {0x0F12, 0x0278}, //#SARR_usDualGammaLutRGBIndoor[0][14] 0278 + {0x0F12, 0x02E0}, //#SARR_usDualGammaLutRGBIndoor[0][15] 02E0 + {0x0F12, 0x0333}, //#SARR_usDualGammaLutRGBIndoor[0][16] 0333 + {0x0F12, 0x037B}, //#SARR_usDualGammaLutRGBIndoor[0][17] 037B + {0x0F12, 0x03BF}, //#SARR_usDualGammaLutRGBIndoor[0][18] 03BF + {0x0F12, 0x03FF}, //#SARR_usDualGammaLutRGBIndoor[0][19] 03FF + {0x0F12, 0x0000}, //#SARR_usDualGammaLutRGBIndoor[1][0] 0000 + {0x0F12, 0x0008}, //#SARR_usDualGammaLutRGBIndoor[1][1] 0008 + {0x0F12, 0x0013}, //#SARR_usDualGammaLutRGBIndoor[1][2] 0013 + {0x0F12, 0x002C}, //#SARR_usDualGammaLutRGBIndoor[1][3] 002C + {0x0F12, 0x0061}, //#SARR_usDualGammaLutRGBIndoor[1][4] 0061 + {0x0F12, 0x00C8}, //#SARR_usDualGammaLutRGBIndoor[1][5] 00C8 + {0x0F12, 0x0113}, //#SARR_usDualGammaLutRGBIndoor[1][6] 0113 + {0x0F12, 0x0132}, //#SARR_usDualGammaLutRGBIndoor[1][7] 0132 + {0x0F12, 0x014C}, //#SARR_usDualGammaLutRGBIndoor[1][8] 014C + {0x0F12, 0x0179}, //#SARR_usDualGammaLutRGBIndoor[1][9] 0179 + {0x0F12, 0x01A4}, //#SARR_usDualGammaLutRGBIndoor[1][10] 01A4 + {0x0F12, 0x01CD}, //#SARR_usDualGammaLutRGBIndoor[1][11] 01CD + {0x0F12, 0x01F4}, //#SARR_usDualGammaLutRGBIndoor[1][12] 01F4 + {0x0F12, 0x0239}, //#SARR_usDualGammaLutRGBIndoor[1][13] 0239 + {0x0F12, 0x0278}, //#SARR_usDualGammaLutRGBIndoor[1][14] 0278 + {0x0F12, 0x02E0}, //#SARR_usDualGammaLutRGBIndoor[1][15] 02E0 + {0x0F12, 0x0333}, //#SARR_usDualGammaLutRGBIndoor[1][16] 0333 + {0x0F12, 0x037B}, //#SARR_usDualGammaLutRGBIndoor[1][17] 037B + {0x0F12, 0x03BF}, //#SARR_usDualGammaLutRGBIndoor[1][18] 03BF + {0x0F12, 0x03FF}, //#SARR_usDualGammaLutRGBIndoor[1][19] 03FF + {0x0F12, 0x0000}, //#SARR_usDualGammaLutRGBIndoor[2][0] 0000 + {0x0F12, 0x0008}, //#SARR_usDualGammaLutRGBIndoor[2][1] 0008 + {0x0F12, 0x0013}, //#SARR_usDualGammaLutRGBIndoor[2][2] 0013 + {0x0F12, 0x002C}, //#SARR_usDualGammaLutRGBIndoor[2][3] 002C + {0x0F12, 0x0061}, //#SARR_usDualGammaLutRGBIndoor[2][4] 0061 + {0x0F12, 0x00C8}, //#SARR_usDualGammaLutRGBIndoor[2][5] 00C8 + {0x0F12, 0x0113}, //#SARR_usDualGammaLutRGBIndoor[2][6] 0113 + {0x0F12, 0x0132}, //#SARR_usDualGammaLutRGBIndoor[2][7] 0132 + {0x0F12, 0x014C}, //#SARR_usDualGammaLutRGBIndoor[2][8] 014C + {0x0F12, 0x0179}, //#SARR_usDualGammaLutRGBIndoor[2][9] 0179 + {0x0F12, 0x01A4}, //#SARR_usDualGammaLutRGBIndoor[2][10] 01A4 + {0x0F12, 0x01CD}, //#SARR_usDualGammaLutRGBIndoor[2][11] 01CD + {0x0F12, 0x01F4}, //#SARR_usDualGammaLutRGBIndoor[2][12] 01F4 + {0x0F12, 0x0239}, //#SARR_usDualGammaLutRGBIndoor[2][13] 0239 + {0x0F12, 0x0278}, //#SARR_usDualGammaLutRGBIndoor[2][14] 0278 + {0x0F12, 0x02E0}, //#SARR_usDualGammaLutRGBIndoor[2][15] 02E0 + {0x0F12, 0x0333}, //#SARR_usDualGammaLutRGBIndoor[2][16] 0333 + {0x0F12, 0x037B}, //#SARR_usDualGammaLutRGBIndoor[2][17] 037B + {0x0F12, 0x03BF}, //#SARR_usDualGammaLutRGBIndoor[2][18] 03BF + {0x0F12, 0x03FF}, //#SARR_usDualGammaLutRGBIndoor[2][19] 03FF + + {0x002A, 0x3300}, + {0x0F12, 0x0000}, //#SARR_usDualGammaLutRGBOutdoor[0][0] 0000 + {0x0F12, 0x0008}, //#SARR_usDualGammaLutRGBOutdoor[0][1] 0008 + {0x0F12, 0x0013}, //#SARR_usDualGammaLutRGBOutdoor[0][2] 0013 + {0x0F12, 0x002C}, //#SARR_usDualGammaLutRGBOutdoor[0][3] 002C + {0x0F12, 0x0061}, //#SARR_usDualGammaLutRGBOutdoor[0][4] 0061 + {0x0F12, 0x00C8}, //#SARR_usDualGammaLutRGBOutdoor[0][5] 00C8 + {0x0F12, 0x0113}, //#SARR_usDualGammaLutRGBOutdoor[0][6] 0113 + {0x0F12, 0x0132}, //#SARR_usDualGammaLutRGBOutdoor[0][7] 0132 + {0x0F12, 0x014C}, //#SARR_usDualGammaLutRGBOutdoor[0][8] 014C + {0x0F12, 0x0179}, //#SARR_usDualGammaLutRGBOutdoor[0][9] 0179 + {0x0F12, 0x01A4}, //#SARR_usDualGammaLutRGBOutdoor[0][10] 01A4 + {0x0F12, 0x01CD}, //#SARR_usDualGammaLutRGBOutdoor[0][11] 01CD + {0x0F12, 0x01F4}, //#SARR_usDualGammaLutRGBOutdoor[0][12] 01F4 + {0x0F12, 0x0239}, //#SARR_usDualGammaLutRGBOutdoor[0][13] 0239 + {0x0F12, 0x0278}, //#SARR_usDualGammaLutRGBOutdoor[0][14] 0278 + {0x0F12, 0x02E0}, //#SARR_usDualGammaLutRGBOutdoor[0][15] 02E0 + {0x0F12, 0x0333}, //#SARR_usDualGammaLutRGBOutdoor[0][16] 0333 + {0x0F12, 0x037B}, //#SARR_usDualGammaLutRGBOutdoor[0][17] 037B + {0x0F12, 0x03BF}, //#SARR_usDualGammaLutRGBOutdoor[0][18] 03BF + {0x0F12, 0x03FF}, //#SARR_usDualGammaLutRGBOutdoor[0][19] 03FF + {0x0F12, 0x0000}, //#SARR_usDualGammaLutRGBOutdoor[1][0] 0000 + {0x0F12, 0x0008}, //#SARR_usDualGammaLutRGBOutdoor[1][1] 0008 + {0x0F12, 0x0013}, //#SARR_usDualGammaLutRGBOutdoor[1][2] 0013 + {0x0F12, 0x002C}, //#SARR_usDualGammaLutRGBOutdoor[1][3] 002C + {0x0F12, 0x0061}, //#SARR_usDualGammaLutRGBOutdoor[1][4] 0061 + {0x0F12, 0x00C8}, //#SARR_usDualGammaLutRGBOutdoor[1][5] 00C8 + {0x0F12, 0x0113}, //#SARR_usDualGammaLutRGBOutdoor[1][6] 0113 + {0x0F12, 0x0132}, //#SARR_usDualGammaLutRGBOutdoor[1][7] 0132 + {0x0F12, 0x014C}, //#SARR_usDualGammaLutRGBOutdoor[1][8] 014C + {0x0F12, 0x0179}, //#SARR_usDualGammaLutRGBOutdoor[1][9] 0179 + {0x0F12, 0x01A4}, //#SARR_usDualGammaLutRGBOutdoor[1][10] 01A4 + {0x0F12, 0x01CD}, //#SARR_usDualGammaLutRGBOutdoor[1][11] 01CD + {0x0F12, 0x01F4}, //#SARR_usDualGammaLutRGBOutdoor[1][12] 01F4 + {0x0F12, 0x0239}, //#SARR_usDualGammaLutRGBOutdoor[1][13] 0239 + {0x0F12, 0x0278}, //#SARR_usDualGammaLutRGBOutdoor[1][14] 0278 + {0x0F12, 0x02E0}, //#SARR_usDualGammaLutRGBOutdoor[1][15] 02E0 + {0x0F12, 0x0333}, //#SARR_usDualGammaLutRGBOutdoor[1][16] 0333 + {0x0F12, 0x037B}, //#SARR_usDualGammaLutRGBOutdoor[1][17] 037B + {0x0F12, 0x03BF}, //#SARR_usDualGammaLutRGBOutdoor[1][18] 03BF + {0x0F12, 0x03FF}, //#SARR_usDualGammaLutRGBOutdoor[1][19] 03FF + {0x0F12, 0x0000}, //#SARR_usDualGammaLutRGBOutdoor[2][0] 0000 + {0x0F12, 0x0008}, //#SARR_usDualGammaLutRGBOutdoor[2][1] 0008 + {0x0F12, 0x0013}, //#SARR_usDualGammaLutRGBOutdoor[2][2] 0013 + {0x0F12, 0x002C}, //#SARR_usDualGammaLutRGBOutdoor[2][3] 002C + {0x0F12, 0x0061}, //#SARR_usDualGammaLutRGBOutdoor[2][4] 0061 + {0x0F12, 0x00C8}, //#SARR_usDualGammaLutRGBOutdoor[2][5] 00C8 + {0x0F12, 0x0113}, //#SARR_usDualGammaLutRGBOutdoor[2][6] 0113 + {0x0F12, 0x0132}, //#SARR_usDualGammaLutRGBOutdoor[2][7] 0132 + {0x0F12, 0x014C}, //#SARR_usDualGammaLutRGBOutdoor[2][8] 014C + {0x0F12, 0x0179}, //#SARR_usDualGammaLutRGBOutdoor[2][9] 0179 + {0x0F12, 0x01A4}, //#SARR_usDualGammaLutRGBOutdoor[2][10] 01A4 + {0x0F12, 0x01CD}, //#SARR_usDualGammaLutRGBOutdoor[2][11] 01CD + {0x0F12, 0x01F4}, //#SARR_usDualGammaLutRGBOutdoor[2][12] 01F4 + {0x0F12, 0x0239}, //#SARR_usDualGammaLutRGBOutdoor[2][13] 0239 + {0x0F12, 0x0278}, //#SARR_usDualGammaLutRGBOutdoor[2][14] 0278 + {0x0F12, 0x02E0}, //#SARR_usDualGammaLutRGBOutdoor[2][15] 02E0 + {0x0F12, 0x0333}, //#SARR_usDualGammaLutRGBOutdoor[2][16] 0333 + {0x0F12, 0x037B}, //#SARR_usDualGammaLutRGBOutdoor[2][17] 037B + {0x0F12, 0x03BF}, //#SARR_usDualGammaLutRGBOutdoor[2][18] 03BF + {0x0F12, 0x03FF}, //#SARR_usDualGammaLutRGBOutdoor[2][19] 03FF + + //============================================================ + //CCM + //============================================================ + {0x002A, 0x06A6}, + {0x0F12, 0x00C0}, //SARR_AwbCcmCord[0] + {0x0F12, 0x00F8}, //SARR_AwbCcmCord[1] + {0x0F12, 0x0112}, //SARR_AwbCcmCord[2] + {0x0F12, 0x014A}, //SARR_AwbCcmCord[3] + {0x0F12, 0x0156}, //SARR_AwbCcmCord[4] + {0x0F12, 0x017F}, //SARR_AwbCcmCord[5] + + // param_start TVAR_wbt_pBaseCcms + // Horizon + {0x002A, 0x33A4}, + {0x0F12, 0x01C3},//02D5 //TVAR_wbt_pBaseCcms[0] + {0x0F12, 0xFF89},//FF53 //TVAR_wbt_pBaseCcms[1] + {0x0F12, 0xFFE5},//FF83 //TVAR_wbt_pBaseCcms[2] + {0x0F12, 0xFF26},//FEE9 //TVAR_wbt_pBaseCcms[3] + {0x0F12, 0x028E},//01A2 //TVAR_wbt_pBaseCcms[4] + {0x0F12, 0xFF80},//FDFE //TVAR_wbt_pBaseCcms[5] + {0x0F12, 0x0002},//FFFC //TVAR_wbt_pBaseCcms[6] + {0x0F12, 0xFFA8},//FF5F //TVAR_wbt_pBaseCcms[7] + {0x0F12, 0x01F0},//02AD //TVAR_wbt_pBaseCcms[8] + {0x0F12, 0x0125},//0125 //TVAR_wbt_pBaseCcms[9] + {0x0F12, 0x0119},//0119 //TVAR_wbt_pBaseCcms[10] + {0x0F12, 0xFE5A},//FE5A //TVAR_wbt_pBaseCcms[11] + {0x0F12, 0x0179},//00D9 //TVAR_wbt_pBaseCcms[12] + {0x0F12, 0xFF8A},//FF26 //TVAR_wbt_pBaseCcms[13] + {0x0F12, 0x0180},//013C //TVAR_wbt_pBaseCcms[14] + {0x0F12, 0xFEC2},//FEC0 //TVAR_wbt_pBaseCcms[15] + {0x0F12, 0x0176},//01F3 //TVAR_wbt_pBaseCcms[16] + {0x0F12, 0x0094},//0109 //TVAR_wbt_pBaseCcms[17] + //inca + {0x0F12, 0x01C3},//022B //TVAR_wbt_pBaseCcms[18] + {0x0F12, 0xFF89},//FF73 //TVAR_wbt_pBaseCcms[19] + {0x0F12, 0xFFE5},//FFC3 //TVAR_wbt_pBaseCcms[20] + {0x0F12, 0xFF26},//FEED //TVAR_wbt_pBaseCcms[21] + {0x0F12, 0x028E},//01B9 //TVAR_wbt_pBaseCcms[22] + {0x0F12, 0xFF80},//FF0D //TVAR_wbt_pBaseCcms[23] + {0x0F12, 0x0002},//FFE7 //TVAR_wbt_pBaseCcms[24] + {0x0F12, 0xFFA8},//FFD3 //TVAR_wbt_pBaseCcms[25] + {0x0F12, 0x01F0},//022F //TVAR_wbt_pBaseCcms[26] + {0x0F12, 0x0125},//0118 //TVAR_wbt_pBaseCcms[27] + {0x0F12, 0x0119},//012C //TVAR_wbt_pBaseCcms[28] + {0x0F12, 0xFE5A},//FED0 //TVAR_wbt_pBaseCcms[29] + {0x0F12, 0x0179},//0212 //TVAR_wbt_pBaseCcms[30] + {0x0F12, 0xFF8A},//FF46 //TVAR_wbt_pBaseCcms[31] + {0x0F12, 0x0180},//01F2 //TVAR_wbt_pBaseCcms[32] + {0x0F12, 0xFEC2},//FED4 //TVAR_wbt_pBaseCcms[33] + {0x0F12, 0x0176},//018C //TVAR_wbt_pBaseCcms[34] + {0x0F12, 0x0094},//013C //TVAR_wbt_pBaseCcms[35] + //WW + {0x0F12, 0x01CA},//0121 //TVAR_wbt_pBaseCcms[36] + {0x0F12, 0xFF89},//FF8D //TVAR_wbt_pBaseCcms[37] + {0x0F12, 0xFFE0},//FFA7 //TVAR_wbt_pBaseCcms[38] + {0x0F12, 0xFF26},//FF3D //TVAR_wbt_pBaseCcms[39] + {0x0F12, 0x028E},//02D0 //TVAR_wbt_pBaseCcms[40] + {0x0F12, 0xFF80},//FE31 //TVAR_wbt_pBaseCcms[41] + {0x0F12, 0x0020},//0016 //TVAR_wbt_pBaseCcms[42] + {0x0F12, 0xFFF8},//003B //TVAR_wbt_pBaseCcms[43] + {0x0F12, 0x01E0},//02E1 //TVAR_wbt_pBaseCcms[44] + {0x0F12, 0x0120},//0175 //TVAR_wbt_pBaseCcms[45] + {0x0F12, 0x00FA},//009C //TVAR_wbt_pBaseCcms[46] + {0x0F12, 0xFF12},//FE3A //TVAR_wbt_pBaseCcms[47] + {0x0F12, 0x0179},//0189 //TVAR_wbt_pBaseCcms[48] + {0x0F12, 0xFF8A},//FF6A //TVAR_wbt_pBaseCcms[49] + {0x0F12, 0x0180},//0298 //TVAR_wbt_pBaseCcms[50] + {0x0F12, 0xFEC2},//FF14 //TVAR_wbt_pBaseCcms[51] + {0x0F12, 0x0176},//01BD //TVAR_wbt_pBaseCcms[52] + {0x0F12, 0x0094},//00FB //TVAR_wbt_pBaseCcms[53] + //CWF + {0x0F12, 0x01CA},//018A//0262 //TVAR_wbt_pBaseCcms[54] + {0x0F12, 0xFF89},//FFC9//FFAB //TVAR_wbt_pBaseCcms[55] + {0x0F12, 0xFFE0},//0005//FFFB //TVAR_wbt_pBaseCcms[56] + {0x0F12, 0xFF26},//FFC1 //TVAR_wbt_pBaseCcms[57] + {0x0F12, 0x028E},//0292 //TVAR_wbt_pBaseCcms[58] + {0x0F12, 0xFF80},//FF81 //TVAR_wbt_pBaseCcms[59] + {0x0F12, 0x0020},//0069 //TVAR_wbt_pBaseCcms[60] + {0x0F12, 0xFFF8},//0057 //TVAR_wbt_pBaseCcms[61] + {0x0F12, 0x01E0},//0296 //TVAR_wbt_pBaseCcms[62] + {0x0F12, 0x0120},//00FF//015F //TVAR_wbt_pBaseCcms[63] + {0x0F12, 0x00FA},//00E2//0112 //TVAR_wbt_pBaseCcms[64] + {0x0F12, 0xFF12},//FF4D//FF17 //TVAR_wbt_pBaseCcms[65] + {0x0F12, 0x0179},//024E //TVAR_wbt_pBaseCcms[66] + {0x0F12, 0xFF8A},//0001 //TVAR_wbt_pBaseCcms[67] + {0x0F12, 0x0180},//0276 //TVAR_wbt_pBaseCcms[68] + {0x0F12, 0xFEC2},//FEE2 //TVAR_wbt_pBaseCcms[69] + {0x0F12, 0x0176},//0236 //TVAR_wbt_pBaseCcms[70] + {0x0F12, 0x0094},//014A //TVAR_wbt_pBaseCcms[71] + //D50 + //BEGIN: DTS2012071201781 modify by huyouhua at 2012-7-24 for D65 Sat too small + //{0x0F12, 0x018A},//01C5 //TVAR_wbt_pBaseCcms[72] + //{0x0F12, 0xFFC9},//FFA8 //TVAR_wbt_pBaseCcms[73] + //{0x0F12, 0x0005},//FFBA //TVAR_wbt_pBaseCcms[74] + {0x0F12, 0x01A9},//01C5 //TVAR_wbt_pBaseCcms[72] + {0x0F12, 0xFFB6},//FFA8 //TVAR_wbt_pBaseCcms[73] + {0x0F12, 0xFFF9},//FFBA //TVAR_wbt_pBaseCcms[74] + //END: DTS2012071201781 modify by huyouhua at 2012-7-24 for D65 Sat too small + {0x0F12, 0xFF56},//FF06 //TVAR_wbt_pBaseCcms[75] + {0x0F12, 0x0230},//0258 //TVAR_wbt_pBaseCcms[76] + {0x0F12, 0xFFA0},//FF52 //TVAR_wbt_pBaseCcms[77] + //BEGIN: DTS2012071201781 modify by huyouhua at 2012-7-24 for D65 Sat too small + //{0x0F12, 0x0020},//0036 //TVAR_wbt_pBaseCcms[78] + //{0x0F12, 0xFFF8},//FFFA //TVAR_wbt_pBaseCcms[79] + //{0x0F12, 0x01E0},//01D7 //TVAR_wbt_pBaseCcms[80] + //{0x0F12, 0x00FF},//00DE //TVAR_wbt_pBaseCcms[81] + //{0x0F12, 0x00E2},//013B //TVAR_wbt_pBaseCcms[82] + //{0x0F12, 0xFF4D},//FF30 //TVAR_wbt_pBaseCcms[83] + {0x0F12, 0x000E},//0036 //TVAR_wbt_pBaseCcms[78] + {0x0F12, 0xFFE0},//FFFA //TVAR_wbt_pBaseCcms[79] + {0x0F12, 0x020A},//01D7 //TVAR_wbt_pBaseCcms[80] + {0x0F12, 0x010C},//00DE //TVAR_wbt_pBaseCcms[81] + {0x0F12, 0x00EC},//013B //TVAR_wbt_pBaseCcms[82] + {0x0F12, 0xFF36},//FF30 //TVAR_wbt_pBaseCcms[83] + //END: DTS2012071201781 modify by huyouhua at 2012-7-24 for D65 Sat too small + {0x0F12, 0x0179},//0168 //TVAR_wbt_pBaseCcms[84] + {0x0F12, 0xFF8A},//FF6F //TVAR_wbt_pBaseCcms[85] + {0x0F12, 0x0180},//0164 //TVAR_wbt_pBaseCcms[86] + {0x0F12, 0xFEC2},//FEDB //TVAR_wbt_pBaseCcms[87] + {0x0F12, 0x0176},//0195 //TVAR_wbt_pBaseCcms[88] + {0x0F12, 0x0094},//00E7 //TVAR_wbt_pBaseCcms[89] + //D65 + //BEGIN: DTS2012071201781 modify by huyouhua at 2012-7-24 for D65 Sat too small + //{0x0F12, 0x018A},//019E //TVAR_wbt_pBaseCcms[90] + //{0x0F12, 0xFFC9},//FF8A //TVAR_wbt_pBaseCcms[91] + //{0x0F12, 0x0005},//FFCE //TVAR_wbt_pBaseCcms[92] + {0x0F12, 0x01A9},//019E //TVAR_wbt_pBaseCcms[90] + {0x0F12, 0xFFB6},//FF8A //TVAR_wbt_pBaseCcms[91] + {0x0F12, 0xFFF9},//FFCE //TVAR_wbt_pBaseCcms[92] + //END: DTS2012071201781 modify by huyouhua at 2012-7-24 for D65 Sat too small + {0x0F12, 0xFF56},//FF06 //TVAR_wbt_pBaseCcms[93] + {0x0F12, 0x0230},//0258 //TVAR_wbt_pBaseCcms[94] + {0x0F12, 0xFFA0},//FF52 //TVAR_wbt_pBaseCcms[95] + //BEGIN: DTS2012071201781 modify by huyouhua at 2012-7-24 for D65 Sat too small + //{0x0F12, 0x0020},//0036 //TVAR_wbt_pBaseCcms[96] + //{0x0F12, 0xFFF8},//FFFA //TVAR_wbt_pBaseCcms[97] + //{0x0F12, 0x01E0},//01D7 //TVAR_wbt_pBaseCcms[98] + //{0x0F12, 0x00FF},//00DE //TVAR_wbt_pBaseCcms[99] + //{0x0F12, 0x00E2},//013B //TVAR_wbt_pBaseCcms[100] + //{0x0F12, 0xFF4D},//FF30 //TVAR_wbt_pBaseCcms[101] + {0x0F12, 0x000E},//0036 //TVAR_wbt_pBaseCcms[96] + {0x0F12, 0xFFE0},//FFFA //TVAR_wbt_pBaseCcms[97] + {0x0F12, 0x020A},//01D7 //TVAR_wbt_pBaseCcms[98] + {0x0F12, 0x010C},//00DE //TVAR_wbt_pBaseCcms[99] + {0x0F12, 0x00EC},//013B //TVAR_wbt_pBaseCcms[100] + {0x0F12, 0xFF36},//FF30 //TVAR_wbt_pBaseCcms[101] + //END: DTS2012071201781 modify by huyouhua at 2012-7-24 for D65 Sat too small + {0x0F12, 0x0179},//0168 //TVAR_wbt_pBaseCcms[102] + {0x0F12, 0xFF8A},//FF6F //TVAR_wbt_pBaseCcms[103] + {0x0F12, 0x0180},//0164 //TVAR_wbt_pBaseCcms[104] + {0x0F12, 0xFEC2},//FEDB //TVAR_wbt_pBaseCcms[105] + {0x0F12, 0x0176},//0195 //TVAR_wbt_pBaseCcms[106] + {0x0F12, 0x0094},//00E7 //TVAR_wbt_pBaseCcms[107] + // param_end TVAR_wbt_pBaseCcms + // param_start TVAR_wbt_pOutdoorCcm + {0x002A, 0x3380}, + {0x0F12, 0x018A},//01C7 //TVAR_wbt_pOutdoorCcm[0] + {0x0F12, 0xFFC9},//FFA0 //TVAR_wbt_pOutdoorCcm[1] + {0x0F12, 0x0005},//FFE8 //TVAR_wbt_pOutdoorCcm[2] + {0x0F12, 0xFF26},//FF11 //TVAR_wbt_pOutdoorCcm[3] + {0x0F12, 0x028E},//01F4 //TVAR_wbt_pOutdoorCcm[4] + {0x0F12, 0xFF80},//FF38 //TVAR_wbt_pOutdoorCcm[5] + {0x0F12, 0x0020},//FFDF //TVAR_wbt_pOutdoorCcm[6] + {0x0F12, 0xFFF8},//FFD3 //TVAR_wbt_pOutdoorCcm[7] + {0x0F12, 0x01E0},//01CC //TVAR_wbt_pOutdoorCcm[8] + {0x0F12, 0x00FF},//011D //TVAR_wbt_pOutdoorCcm[9] + {0x0F12, 0x00E2},//0157 //TVAR_wbt_pOutdoorCcm[10] + {0x0F12, 0xFF4D},//FF16 //TVAR_wbt_pOutdoorCcm[11] + {0x0F12, 0x0179},//01DA //TVAR_wbt_pOutdoorCcm[12] + {0x0F12, 0xFF8A},//FF3A //TVAR_wbt_pOutdoorCcm[13] + {0x0F12, 0x0180},//01B6 //TVAR_wbt_pOutdoorCcm[14] + {0x0F12, 0xFEC2},//FF2A //TVAR_wbt_pOutdoorCcm[15] + {0x0F12, 0x0176},//0176 //TVAR_wbt_pOutdoorCcm[16] + {0x0F12, 0x0094},//0114 //TVAR_wbt_pOutdoorCcm[17] + // param_end TVAR_wbt_pOutdoorCcm + //============================================================ + //AFIT + //============================================================ + // param_start afit_uNoiseIndInDoor + //============================================================ + {0x002A, 0x0764}, + {0x0F12, 0x0041}, //afit_uNoiseIndInDoor[0] + {0x0F12, 0x00A5}, //afit_uNoiseIndInDoor[1] + {0x0F12, 0x016B}, //afit_uNoiseIndInDoor[2] + {0x0F12, 0x0226}, //afit_uNoiseIndInDoor[3] + {0x0F12, 0x02EA}, //afit_uNoiseIndInDoor[4] + // param_end afit_uNoiseIndInDoor + // param_start TVAR_afit_pBaseVals + {0x002A, 0x07C4}, + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[0] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[1] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[2] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[3] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[4] + {0x0F12, 0x001E}, //TVAR_afit_pBaseVals[5] + {0x0F12, 0x03FF}, //TVAR_afit_pBaseVals[6] + {0x0F12, 0x009C}, //TVAR_afit_pBaseVals[7] + {0x0F12, 0x017C}, //TVAR_afit_pBaseVals[8] + {0x0F12, 0x03FF}, //TVAR_afit_pBaseVals[9] + {0x0F12, 0x000C}, //TVAR_afit_pBaseVals[10] + {0x0F12, 0x0010}, //TVAR_afit_pBaseVals[11] + {0x0F12, 0x0104}, //TVAR_afit_pBaseVals[12] + {0x0F12, 0x03E8}, //TVAR_afit_pBaseVals[13] + {0x0F12, 0x0023}, //TVAR_afit_pBaseVals[14] + {0x0F12, 0x012C}, //TVAR_afit_pBaseVals[15] + {0x0F12, 0x0070}, //TVAR_afit_pBaseVals[16] + {0x0F12, 0x0004}, //TVAR_afit_pBaseVals[17] + {0x0F12, 0x0004}, //TVAR_afit_pBaseVals[18] + {0x0F12, 0x01AA}, //TVAR_afit_pBaseVals[19] + {0x0F12, 0x0064}, //TVAR_afit_pBaseVals[20] + {0x0F12, 0x0064}, //TVAR_afit_pBaseVals[21] + {0x0F12, 0x000A}, //TVAR_afit_pBaseVals[22] + {0x0F12, 0x000A}, //TVAR_afit_pBaseVals[23] + {0x0F12, 0x002A}, //TVAR_afit_pBaseVals[24] + {0x0F12, 0x0024}, //TVAR_afit_pBaseVals[25] + {0x0F12, 0x002A}, //TVAR_afit_pBaseVals[26] + {0x0F12, 0x0024}, //TVAR_afit_pBaseVals[27] + {0x0F12, 0x002A}, //TVAR_afit_pBaseVals[28] + {0x0F12, 0x0024}, //TVAR_afit_pBaseVals[29] + {0x0F12, 0x0A0F}, //TVAR_afit_pBaseVals[30] + {0x0F12, 0x1701}, //TVAR_afit_pBaseVals[31] + {0x0F12, 0x0229}, //TVAR_afit_pBaseVals[32] + {0x0F12, 0x1403}, //TVAR_afit_pBaseVals[33] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[34] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[35] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[36] + {0x0F12, 0x00FF}, //TVAR_afit_pBaseVals[37] + {0x0F12, 0x053B}, //TVAR_afit_pBaseVals[38] + {0x0F12, 0x0505}, //TVAR_afit_pBaseVals[39] + {0x0F12, 0x0301}, //TVAR_afit_pBaseVals[40] + {0x0F12, 0x8007}, //TVAR_afit_pBaseVals[41] + {0x0F12, 0x051E}, //TVAR_afit_pBaseVals[42] + {0x0F12, 0x0A1E}, //TVAR_afit_pBaseVals[43] + {0x0F12, 0x0F0F}, //TVAR_afit_pBaseVals[44] + {0x0F12, 0x0A05}, //TVAR_afit_pBaseVals[45] + {0x0F12, 0x103C}, //TVAR_afit_pBaseVals[46] + {0x0F12, 0x0A28}, //TVAR_afit_pBaseVals[47] + {0x0F12, 0x0002}, //TVAR_afit_pBaseVals[48] + {0x0F12, 0x00FF}, //TVAR_afit_pBaseVals[49] + {0x0F12, 0x1002}, //TVAR_afit_pBaseVals[50] + {0x0F12, 0x001D}, //TVAR_afit_pBaseVals[51] + {0x0F12, 0x0900}, //TVAR_afit_pBaseVals[52] + {0x0F12, 0x0600}, //TVAR_afit_pBaseVals[53] + {0x0F12, 0x0504}, //TVAR_afit_pBaseVals[54] + {0x0F12, 0x0305}, //TVAR_afit_pBaseVals[55] + {0x0F12, 0x5A03}, //TVAR_afit_pBaseVals[56] + {0x0F12, 0x006E}, //TVAR_afit_pBaseVals[57] + {0x0F12, 0x0A78}, //TVAR_afit_pBaseVals[58] + {0x0F12, 0x0080}, //TVAR_afit_pBaseVals[59] + {0x0F12, 0x3232}, //TVAR_afit_pBaseVals[60] + {0x0F12, 0x0101}, //TVAR_afit_pBaseVals[61] + {0x0F12, 0x5001}, //TVAR_afit_pBaseVals[62] + {0x0F12, 0x7850}, //TVAR_afit_pBaseVals[63] + {0x0F12, 0x2878}, //TVAR_afit_pBaseVals[64] + {0x0F12, 0x0A00}, //TVAR_afit_pBaseVals[65] + {0x0F12, 0x1403}, //TVAR_afit_pBaseVals[66] + {0x0F12, 0x1E07}, //TVAR_afit_pBaseVals[67] + {0x0F12, 0x070A}, //TVAR_afit_pBaseVals[68] + {0x0F12, 0x32FF}, //TVAR_afit_pBaseVals[69] + {0x0F12, 0x5004}, //TVAR_afit_pBaseVals[70] + {0x0F12, 0x0F40}, //TVAR_afit_pBaseVals[71] + {0x0F12, 0x400F}, //TVAR_afit_pBaseVals[72] + {0x0F12, 0x0204}, //TVAR_afit_pBaseVals[73] + {0x0F12, 0x3203}, //TVAR_afit_pBaseVals[74] + {0x0F12, 0x0132}, //TVAR_afit_pBaseVals[75] + {0x0F12, 0x0101}, //TVAR_afit_pBaseVals[76] + {0x0F12, 0x5050}, //TVAR_afit_pBaseVals[77] + {0x0F12, 0x7878}, //TVAR_afit_pBaseVals[78] + {0x0F12, 0x0028}, //TVAR_afit_pBaseVals[79] + {0x0F12, 0x030A}, //TVAR_afit_pBaseVals[80] + {0x0F12, 0x0714}, //TVAR_afit_pBaseVals[81] + {0x0F12, 0x0A1E}, //TVAR_afit_pBaseVals[82] + {0x0F12, 0xFF07}, //TVAR_afit_pBaseVals[83] + {0x0F12, 0x0432}, //TVAR_afit_pBaseVals[84] + {0x0F12, 0x4050}, //TVAR_afit_pBaseVals[85] + {0x0F12, 0x0F0F}, //TVAR_afit_pBaseVals[86] + {0x0F12, 0x0440}, //TVAR_afit_pBaseVals[87] + {0x0F12, 0x0302}, //TVAR_afit_pBaseVals[88] + {0x0F12, 0x3232}, //TVAR_afit_pBaseVals[89] + {0x0F12, 0x0101}, //TVAR_afit_pBaseVals[90] + {0x0F12, 0x5001}, //TVAR_afit_pBaseVals[91] + {0x0F12, 0x7850}, //TVAR_afit_pBaseVals[92] + {0x0F12, 0x2878}, //TVAR_afit_pBaseVals[93] + {0x0F12, 0x0A00}, //TVAR_afit_pBaseVals[94] + {0x0F12, 0x1403}, //TVAR_afit_pBaseVals[95] + {0x0F12, 0x1E07}, //TVAR_afit_pBaseVals[96] + {0x0F12, 0x070A}, //TVAR_afit_pBaseVals[97] + {0x0F12, 0x32FF}, //TVAR_afit_pBaseVals[98] + {0x0F12, 0x5004}, //TVAR_afit_pBaseVals[99] + {0x0F12, 0x0F40}, //TVAR_afit_pBaseVals[100] + {0x0F12, 0x400F}, //TVAR_afit_pBaseVals[101] + {0x0F12, 0x0204}, //TVAR_afit_pBaseVals[102] + {0x0F12, 0x0003}, //TVAR_afit_pBaseVals[103] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[104] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[105] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[106] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[107] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[108] + {0x0F12, 0x001E}, //TVAR_afit_pBaseVals[109] + {0x0F12, 0x03FF}, //TVAR_afit_pBaseVals[110] + {0x0F12, 0x009C}, //TVAR_afit_pBaseVals[111] + {0x0F12, 0x017C}, //TVAR_afit_pBaseVals[112] + {0x0F12, 0x03FF}, //TVAR_afit_pBaseVals[113] + {0x0F12, 0x000C}, //TVAR_afit_pBaseVals[114] + {0x0F12, 0x0010}, //TVAR_afit_pBaseVals[115] + {0x0F12, 0x0104}, //TVAR_afit_pBaseVals[116] + {0x0F12, 0x03E8}, //TVAR_afit_pBaseVals[117] + {0x0F12, 0x0023}, //TVAR_afit_pBaseVals[118] + {0x0F12, 0x012C}, //TVAR_afit_pBaseVals[119] + {0x0F12, 0x0070}, //TVAR_afit_pBaseVals[120] + {0x0F12, 0x0004}, //TVAR_afit_pBaseVals[121] + {0x0F12, 0x0004}, //TVAR_afit_pBaseVals[122] + {0x0F12, 0x01AA}, //TVAR_afit_pBaseVals[123] + {0x0F12, 0x001E}, //TVAR_afit_pBaseVals[124] + {0x0F12, 0x001E}, //TVAR_afit_pBaseVals[125] + {0x0F12, 0x0005}, //TVAR_afit_pBaseVals[126] + {0x0F12, 0x0005}, //TVAR_afit_pBaseVals[127] + {0x0F12, 0x002A}, //TVAR_afit_pBaseVals[128] + {0x0F12, 0x0024}, //TVAR_afit_pBaseVals[129] + {0x0F12, 0x002A}, //TVAR_afit_pBaseVals[130] + {0x0F12, 0x0024}, //TVAR_afit_pBaseVals[131] + {0x0F12, 0x002A}, //TVAR_afit_pBaseVals[132] + {0x0F12, 0x0024}, //TVAR_afit_pBaseVals[133] + {0x0F12, 0x0A0F}, //TVAR_afit_pBaseVals[134] + {0x0F12, 0x1701}, //TVAR_afit_pBaseVals[135] + {0x0F12, 0x0229}, //TVAR_afit_pBaseVals[136] + {0x0F12, 0x1403}, //TVAR_afit_pBaseVals[137] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[138] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[139] + {0x0F12, 0x0101}, //TVAR_afit_pBaseVals[140] + {0x0F12, 0x00FF}, //TVAR_afit_pBaseVals[141] + {0x0F12, 0x053B}, //TVAR_afit_pBaseVals[142] + {0x0F12, 0x0505}, //TVAR_afit_pBaseVals[143] + {0x0F12, 0x0301}, //TVAR_afit_pBaseVals[144] + {0x0F12, 0x8007}, //TVAR_afit_pBaseVals[145] + {0x0F12, 0x051E}, //TVAR_afit_pBaseVals[146] + {0x0F12, 0x0A1E}, //TVAR_afit_pBaseVals[147] + {0x0F12, 0x0F0F}, //TVAR_afit_pBaseVals[148] + {0x0F12, 0x0A04}, //TVAR_afit_pBaseVals[149] + {0x0F12, 0x103C}, //TVAR_afit_pBaseVals[150] + {0x0F12, 0x0A28}, //TVAR_afit_pBaseVals[151] + {0x0F12, 0x0002}, //TVAR_afit_pBaseVals[152] + {0x0F12, 0x00FF}, //TVAR_afit_pBaseVals[153] + {0x0F12, 0x1002}, //TVAR_afit_pBaseVals[154] + {0x0F12, 0x001D}, //TVAR_afit_pBaseVals[155] + {0x0F12, 0x0900}, //TVAR_afit_pBaseVals[156] + {0x0F12, 0x0600}, //TVAR_afit_pBaseVals[157] + {0x0F12, 0x0504}, //TVAR_afit_pBaseVals[158] + {0x0F12, 0x0305}, //TVAR_afit_pBaseVals[159] + {0x0F12, 0x5F03}, //TVAR_afit_pBaseVals[160] + {0x0F12, 0x0080}, //TVAR_afit_pBaseVals[161] + {0x0F12, 0x0080}, //TVAR_afit_pBaseVals[162] + {0x0F12, 0x0080}, //TVAR_afit_pBaseVals[163] + {0x0F12, 0x3232}, //TVAR_afit_pBaseVals[164] + {0x0F12, 0x0101}, //TVAR_afit_pBaseVals[165] + {0x0F12, 0x2A01}, //TVAR_afit_pBaseVals[166] + {0x0F12, 0x3232}, //TVAR_afit_pBaseVals[167] + {0x0F12, 0x2830}, //TVAR_afit_pBaseVals[168] + {0x0F12, 0x0A00}, //TVAR_afit_pBaseVals[169] + {0x0F12, 0x1403}, //TVAR_afit_pBaseVals[170] + {0x0F12, 0x1E07}, //TVAR_afit_pBaseVals[171] + {0x0F12, 0x070A}, //TVAR_afit_pBaseVals[172] + {0x0F12, 0x32FF}, //TVAR_afit_pBaseVals[173] + {0x0F12, 0x5004}, //TVAR_afit_pBaseVals[174] + {0x0F12, 0x0F40}, //TVAR_afit_pBaseVals[175] + {0x0F12, 0x400F}, //TVAR_afit_pBaseVals[176] + {0x0F12, 0x0204}, //TVAR_afit_pBaseVals[177] + {0x0F12, 0x3203}, //TVAR_afit_pBaseVals[178] + {0x0F12, 0x0132}, //TVAR_afit_pBaseVals[179] + {0x0F12, 0x0101}, //TVAR_afit_pBaseVals[180] + {0x0F12, 0x262A}, //TVAR_afit_pBaseVals[181] + {0x0F12, 0x3032}, //TVAR_afit_pBaseVals[182] + {0x0F12, 0x0028}, //TVAR_afit_pBaseVals[183] + {0x0F12, 0x030A}, //TVAR_afit_pBaseVals[184] + {0x0F12, 0x0714}, //TVAR_afit_pBaseVals[185] + {0x0F12, 0x0A1E}, //TVAR_afit_pBaseVals[186] + {0x0F12, 0xFF07}, //TVAR_afit_pBaseVals[187] + {0x0F12, 0x0432}, //TVAR_afit_pBaseVals[188] + {0x0F12, 0x4050}, //TVAR_afit_pBaseVals[189] + {0x0F12, 0x0F0F}, //TVAR_afit_pBaseVals[190] + {0x0F12, 0x0440}, //TVAR_afit_pBaseVals[191] + {0x0F12, 0x0302}, //TVAR_afit_pBaseVals[192] + {0x0F12, 0x3232}, //TVAR_afit_pBaseVals[193] + {0x0F12, 0x0101}, //TVAR_afit_pBaseVals[194] + {0x0F12, 0x2A01}, //TVAR_afit_pBaseVals[195] + {0x0F12, 0x3226}, //TVAR_afit_pBaseVals[196] + {0x0F12, 0x2830}, //TVAR_afit_pBaseVals[197] + {0x0F12, 0x0A00}, //TVAR_afit_pBaseVals[198] + {0x0F12, 0x1403}, //TVAR_afit_pBaseVals[199] + {0x0F12, 0x1E07}, //TVAR_afit_pBaseVals[200] + {0x0F12, 0x070A}, //TVAR_afit_pBaseVals[201] + {0x0F12, 0x32FF}, //TVAR_afit_pBaseVals[202] + {0x0F12, 0x5004}, //TVAR_afit_pBaseVals[203] + {0x0F12, 0x0F40}, //TVAR_afit_pBaseVals[204] + {0x0F12, 0x400F}, //TVAR_afit_pBaseVals[205] + {0x0F12, 0x0204}, //TVAR_afit_pBaseVals[206] + {0x0F12, 0x0003}, //TVAR_afit_pBaseVals[207] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[208] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[209] + {0x0F12, 0x000f}, //TVAR_afit_pBaseVals[210]//DTS2012071201781:modify by huyouhua at 2012-7-23 + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[211] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[212] + {0x0F12, 0x001E}, //TVAR_afit_pBaseVals[213] + {0x0F12, 0x03FF}, //TVAR_afit_pBaseVals[214] + {0x0F12, 0x009C}, //TVAR_afit_pBaseVals[215] + {0x0F12, 0x017C}, //TVAR_afit_pBaseVals[216] + {0x0F12, 0x03FF}, //TVAR_afit_pBaseVals[217] + {0x0F12, 0x000C}, //TVAR_afit_pBaseVals[218] + {0x0F12, 0x0010}, //TVAR_afit_pBaseVals[219] + {0x0F12, 0x012C}, //TVAR_afit_pBaseVals[220] + {0x0F12, 0x03E8}, //TVAR_afit_pBaseVals[221] + {0x0F12, 0x0041}, //TVAR_afit_pBaseVals[222] + {0x0F12, 0x005A}, //TVAR_afit_pBaseVals[223] + {0x0F12, 0x0070}, //TVAR_afit_pBaseVals[224] + {0x0F12, 0x0004}, //TVAR_afit_pBaseVals[225] + {0x0F12, 0x0004}, //TVAR_afit_pBaseVals[226] + {0x0F12, 0x01AA}, //TVAR_afit_pBaseVals[227] + {0x0F12, 0x001E}, //TVAR_afit_pBaseVals[228] + {0x0F12, 0x001E}, //TVAR_afit_pBaseVals[229] + {0x0F12, 0x000A}, //TVAR_afit_pBaseVals[230] + {0x0F12, 0x000A}, //TVAR_afit_pBaseVals[231] + {0x0F12, 0x0032}, //TVAR_afit_pBaseVals[232] + {0x0F12, 0x0028}, //TVAR_afit_pBaseVals[233] + {0x0F12, 0x0032}, //TVAR_afit_pBaseVals[234] + {0x0F12, 0x0028}, //TVAR_afit_pBaseVals[235] + {0x0F12, 0x0032}, //TVAR_afit_pBaseVals[236] + {0x0F12, 0x0028}, //TVAR_afit_pBaseVals[237] + {0x0F12, 0x0A0F}, //TVAR_afit_pBaseVals[238] + {0x0F12, 0x1701}, //TVAR_afit_pBaseVals[239] + {0x0F12, 0x0229}, //TVAR_afit_pBaseVals[240] + {0x0F12, 0x1403}, //TVAR_afit_pBaseVals[241] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[242] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[243] + {0x0F12, 0x0404}, //TVAR_afit_pBaseVals[244] + {0x0F12, 0x00FF}, //TVAR_afit_pBaseVals[245] + {0x0F12, 0x043B}, //TVAR_afit_pBaseVals[246] + {0x0F12, 0x0505}, //TVAR_afit_pBaseVals[247] + {0x0F12, 0x0301}, //TVAR_afit_pBaseVals[248] + {0x0F12, 0x8007}, //TVAR_afit_pBaseVals[249] + {0x0F12, 0x051E}, //TVAR_afit_pBaseVals[250] + {0x0F12, 0x0A1E}, //TVAR_afit_pBaseVals[251] + {0x0F12, 0x0F0F}, //TVAR_afit_pBaseVals[252] + {0x0F12, 0x0A03}, //TVAR_afit_pBaseVals[253] + {0x0F12, 0x0A3C}, //TVAR_afit_pBaseVals[254] + {0x0F12, 0x0528}, //TVAR_afit_pBaseVals[255] + {0x0F12, 0x0002}, //TVAR_afit_pBaseVals[256] + {0x0F12, 0x00FF}, //TVAR_afit_pBaseVals[257] + {0x0F12, 0x1002}, //TVAR_afit_pBaseVals[258] + {0x0F12, 0x001D}, //TVAR_afit_pBaseVals[259] + {0x0F12, 0x0900}, //TVAR_afit_pBaseVals[260] + {0x0F12, 0x0600}, //TVAR_afit_pBaseVals[261] + {0x0F12, 0x0504}, //TVAR_afit_pBaseVals[262] + {0x0F12, 0x0305}, //TVAR_afit_pBaseVals[263] + {0x0F12, 0x6902}, //TVAR_afit_pBaseVals[264] + {0x0F12, 0x0080}, //TVAR_afit_pBaseVals[265] + {0x0F12, 0x0080}, //TVAR_afit_pBaseVals[266] + {0x0F12, 0x0080}, //TVAR_afit_pBaseVals[267] + {0x0F12, 0x2D2D}, //TVAR_afit_pBaseVals[268] + {0x0F12, 0x0101}, //TVAR_afit_pBaseVals[269] + {0x0F12, 0x2001}, //TVAR_afit_pBaseVals[270] + {0x0F12, 0x2026}, //TVAR_afit_pBaseVals[271] + {0x0F12, 0x281E}, //TVAR_afit_pBaseVals[272] + {0x0F12, 0x0A00}, //TVAR_afit_pBaseVals[273] + {0x0F12, 0x0A03}, //TVAR_afit_pBaseVals[274] + {0x0F12, 0x1E0A}, //TVAR_afit_pBaseVals[275] + {0x0F12, 0x070A}, //TVAR_afit_pBaseVals[276] + {0x0F12, 0x32FF}, //TVAR_afit_pBaseVals[277] + {0x0F12, 0x5004}, //TVAR_afit_pBaseVals[278] + {0x0F12, 0x0F40}, //TVAR_afit_pBaseVals[279] + {0x0F12, 0x400F}, //TVAR_afit_pBaseVals[280] + {0x0F12, 0x0204}, //TVAR_afit_pBaseVals[281] + {0x0F12, 0x3203}, //TVAR_afit_pBaseVals[282] + {0x0F12, 0x0132}, //TVAR_afit_pBaseVals[283] + {0x0F12, 0x0101}, //TVAR_afit_pBaseVals[284] + {0x0F12, 0x1C20}, //TVAR_afit_pBaseVals[285] + {0x0F12, 0x1C1E}, //TVAR_afit_pBaseVals[286] + {0x0F12, 0x0028}, //TVAR_afit_pBaseVals[287] + {0x0F12, 0x030A}, //TVAR_afit_pBaseVals[288] + {0x0F12, 0x0A0A}, //TVAR_afit_pBaseVals[289] + {0x0F12, 0x0A1E}, //TVAR_afit_pBaseVals[290] + {0x0F12, 0xFF07}, //TVAR_afit_pBaseVals[291] + {0x0F12, 0x0432}, //TVAR_afit_pBaseVals[292] + {0x0F12, 0x4050}, //TVAR_afit_pBaseVals[293] + {0x0F12, 0x0F0F}, //TVAR_afit_pBaseVals[294] + {0x0F12, 0x0440}, //TVAR_afit_pBaseVals[295] + {0x0F12, 0x0302}, //TVAR_afit_pBaseVals[296] + {0x0F12, 0x3232}, //TVAR_afit_pBaseVals[297] + {0x0F12, 0x0101}, //TVAR_afit_pBaseVals[298] + {0x0F12, 0x2001}, //TVAR_afit_pBaseVals[299] + {0x0F12, 0x1E1C}, //TVAR_afit_pBaseVals[300] + {0x0F12, 0x281C}, //TVAR_afit_pBaseVals[301] + {0x0F12, 0x0A00}, //TVAR_afit_pBaseVals[302] + {0x0F12, 0x0A03}, //TVAR_afit_pBaseVals[303] + {0x0F12, 0x1E0A}, //TVAR_afit_pBaseVals[304] + {0x0F12, 0x070A}, //TVAR_afit_pBaseVals[305] + {0x0F12, 0x32FF}, //TVAR_afit_pBaseVals[306] + {0x0F12, 0x5004}, //TVAR_afit_pBaseVals[307] + {0x0F12, 0x0F40}, //TVAR_afit_pBaseVals[308] + {0x0F12, 0x400F}, //TVAR_afit_pBaseVals[309] + {0x0F12, 0x0204}, //TVAR_afit_pBaseVals[310] + {0x0F12, 0x0003}, //TVAR_afit_pBaseVals[311] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[312] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[313] + {0x0F12, 0x000f}, //TVAR_afit_pBaseVals[314]//DTS2012071201781:modify by huyouhua at 2012-7-23 + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[315] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[316] + {0x0F12, 0x001E}, //TVAR_afit_pBaseVals[317] + {0x0F12, 0x03FF}, //TVAR_afit_pBaseVals[318] + {0x0F12, 0x009C}, //TVAR_afit_pBaseVals[319] + {0x0F12, 0x017C}, //TVAR_afit_pBaseVals[320] + {0x0F12, 0x03FF}, //TVAR_afit_pBaseVals[321] + {0x0F12, 0x000C}, //TVAR_afit_pBaseVals[322] + {0x0F12, 0x0010}, //TVAR_afit_pBaseVals[323] + {0x0F12, 0x012C}, //TVAR_afit_pBaseVals[324] + {0x0F12, 0x03E8}, //TVAR_afit_pBaseVals[325] + {0x0F12, 0x0050}, //TVAR_afit_pBaseVals[326] + {0x0F12, 0x00C8}, //TVAR_afit_pBaseVals[327] + {0x0F12, 0x0070}, //TVAR_afit_pBaseVals[328] + {0x0F12, 0x0004}, //TVAR_afit_pBaseVals[329] + {0x0F12, 0x0004}, //TVAR_afit_pBaseVals[330] + {0x0F12, 0x01AA}, //TVAR_afit_pBaseVals[331] + {0x0F12, 0x0014}, //TVAR_afit_pBaseVals[332] + {0x0F12, 0x0014}, //TVAR_afit_pBaseVals[333] + {0x0F12, 0x000A}, //TVAR_afit_pBaseVals[334] + {0x0F12, 0x000A}, //TVAR_afit_pBaseVals[335] + {0x0F12, 0x0032}, //TVAR_afit_pBaseVals[336] + {0x0F12, 0x0023}, //TVAR_afit_pBaseVals[337] + {0x0F12, 0x0032}, //TVAR_afit_pBaseVals[338] + {0x0F12, 0x0028}, //TVAR_afit_pBaseVals[339] + {0x0F12, 0x0032}, //TVAR_afit_pBaseVals[340] + {0x0F12, 0x0028}, //TVAR_afit_pBaseVals[341] + {0x0F12, 0x0A0F}, //TVAR_afit_pBaseVals[342] + {0x0F12, 0x1701}, //TVAR_afit_pBaseVals[343] + {0x0F12, 0x0229}, //TVAR_afit_pBaseVals[344] + {0x0F12, 0x1403}, //TVAR_afit_pBaseVals[345] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[346] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[347] + {0x0F12, 0x0404}, //TVAR_afit_pBaseVals[348] + {0x0F12, 0x00FF}, //TVAR_afit_pBaseVals[349] + {0x0F12, 0x033B}, //TVAR_afit_pBaseVals[350] + {0x0F12, 0x0505}, //TVAR_afit_pBaseVals[351] + {0x0F12, 0x0301}, //TVAR_afit_pBaseVals[352] + {0x0F12, 0x8007}, //TVAR_afit_pBaseVals[353] + {0x0F12, 0x051E}, //TVAR_afit_pBaseVals[354] + {0x0F12, 0x0A1E}, //TVAR_afit_pBaseVals[355] + {0x0F12, 0x0F0F}, //TVAR_afit_pBaseVals[356] + {0x0F12, 0x0A03}, //TVAR_afit_pBaseVals[357] + {0x0F12, 0x0A3C}, //TVAR_afit_pBaseVals[358] + {0x0F12, 0x0828}, //TVAR_afit_pBaseVals[359] + {0x0F12, 0x0002}, //TVAR_afit_pBaseVals[360] + {0x0F12, 0x00FF}, //TVAR_afit_pBaseVals[361] + {0x0F12, 0x1002}, //TVAR_afit_pBaseVals[362] + {0x0F12, 0x001D}, //TVAR_afit_pBaseVals[363] + {0x0F12, 0x0900}, //TVAR_afit_pBaseVals[364] + {0x0F12, 0x0600}, //TVAR_afit_pBaseVals[365] + {0x0F12, 0x0504}, //TVAR_afit_pBaseVals[366] + {0x0F12, 0x0305}, //TVAR_afit_pBaseVals[367] + {0x0F12, 0x6F02}, //TVAR_afit_pBaseVals[368] + {0x0F12, 0x0080}, //TVAR_afit_pBaseVals[369] + {0x0F12, 0x0080}, //TVAR_afit_pBaseVals[370] + {0x0F12, 0x0080}, //TVAR_afit_pBaseVals[371] + {0x0F12, 0x323C}, //TVAR_afit_pBaseVals[372] + {0x0F12, 0x0101}, //TVAR_afit_pBaseVals[373] + {0x0F12, 0x1A01}, //TVAR_afit_pBaseVals[374] + {0x0F12, 0x1A1E}, //TVAR_afit_pBaseVals[375] + {0x0F12, 0x2818}, //TVAR_afit_pBaseVals[376] + {0x0F12, 0x0A00}, //TVAR_afit_pBaseVals[377] + {0x0F12, 0x1403}, //TVAR_afit_pBaseVals[378] + {0x0F12, 0x1905}, //TVAR_afit_pBaseVals[379] + {0x0F12, 0x060E}, //TVAR_afit_pBaseVals[380] + {0x0F12, 0x32FF}, //TVAR_afit_pBaseVals[381] + {0x0F12, 0x5004}, //TVAR_afit_pBaseVals[382] + {0x0F12, 0x1440}, //TVAR_afit_pBaseVals[383] + {0x0F12, 0x4015}, //TVAR_afit_pBaseVals[384] + {0x0F12, 0x0204}, //TVAR_afit_pBaseVals[385] + {0x0F12, 0x3C03}, //TVAR_afit_pBaseVals[386] + {0x0F12, 0x013C}, //TVAR_afit_pBaseVals[387] + {0x0F12, 0x0101}, //TVAR_afit_pBaseVals[388] + {0x0F12, 0x141A}, //TVAR_afit_pBaseVals[389] + {0x0F12, 0x181A}, //TVAR_afit_pBaseVals[390] + {0x0F12, 0x0028}, //TVAR_afit_pBaseVals[391] + {0x0F12, 0x030A}, //TVAR_afit_pBaseVals[392] + {0x0F12, 0x0614}, //TVAR_afit_pBaseVals[393] + {0x0F12, 0x0A19}, //TVAR_afit_pBaseVals[394] + {0x0F12, 0xFF06}, //TVAR_afit_pBaseVals[395] + {0x0F12, 0x0432}, //TVAR_afit_pBaseVals[396] + {0x0F12, 0x4050}, //TVAR_afit_pBaseVals[397] + {0x0F12, 0x1514}, //TVAR_afit_pBaseVals[398] + {0x0F12, 0x0440}, //TVAR_afit_pBaseVals[399] + {0x0F12, 0x0302}, //TVAR_afit_pBaseVals[400] + {0x0F12, 0x3C3C}, //TVAR_afit_pBaseVals[401] + {0x0F12, 0x0101}, //TVAR_afit_pBaseVals[402] + {0x0F12, 0x1A01}, //TVAR_afit_pBaseVals[403] + {0x0F12, 0x1A14}, //TVAR_afit_pBaseVals[404] + {0x0F12, 0x2818}, //TVAR_afit_pBaseVals[405] + {0x0F12, 0x0A00}, //TVAR_afit_pBaseVals[406] + {0x0F12, 0x1403}, //TVAR_afit_pBaseVals[407] + {0x0F12, 0x1906}, //TVAR_afit_pBaseVals[408] + {0x0F12, 0x060A}, //TVAR_afit_pBaseVals[409] + {0x0F12, 0x32FF}, //TVAR_afit_pBaseVals[410] + {0x0F12, 0x5004}, //TVAR_afit_pBaseVals[411] + {0x0F12, 0x1440}, //TVAR_afit_pBaseVals[412] + {0x0F12, 0x4015}, //TVAR_afit_pBaseVals[413] + {0x0F12, 0x0204}, //TVAR_afit_pBaseVals[414] + {0x0F12, 0x0003}, //TVAR_afit_pBaseVals[415] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[416] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[417] + {0x0F12, 0x000f}, //TVAR_afit_pBaseVals[418]//DTS2012071201781:modify by huyouhua at 2012-7-23 + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[419] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[420] + {0x0F12, 0x001E}, //TVAR_afit_pBaseVals[421] + {0x0F12, 0x03FF}, //TVAR_afit_pBaseVals[422] + {0x0F12, 0x009C}, //TVAR_afit_pBaseVals[423] + {0x0F12, 0x017C}, //TVAR_afit_pBaseVals[424] + {0x0F12, 0x03FF}, //TVAR_afit_pBaseVals[425] + {0x0F12, 0x000C}, //TVAR_afit_pBaseVals[426] + {0x0F12, 0x0010}, //TVAR_afit_pBaseVals[427] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[428] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[429] + {0x0F12, 0x0046}, //TVAR_afit_pBaseVals[430] + {0x0F12, 0x0050}, //TVAR_afit_pBaseVals[431] + {0x0F12, 0x0070}, //TVAR_afit_pBaseVals[432] + {0x0F12, 0x0004}, //TVAR_afit_pBaseVals[433] + {0x0F12, 0x0004}, //TVAR_afit_pBaseVals[434] + {0x0F12, 0x01AA}, //TVAR_afit_pBaseVals[435] + {0x0F12, 0x0014}, //TVAR_afit_pBaseVals[436] + {0x0F12, 0x0014}, //TVAR_afit_pBaseVals[437] + {0x0F12, 0x000A}, //TVAR_afit_pBaseVals[438] + {0x0F12, 0x000A}, //TVAR_afit_pBaseVals[439] + {0x0F12, 0x002D}, //TVAR_afit_pBaseVals[440] + {0x0F12, 0x0019}, //TVAR_afit_pBaseVals[441] + {0x0F12, 0x0023}, //TVAR_afit_pBaseVals[442] + {0x0F12, 0x0023}, //TVAR_afit_pBaseVals[443] + {0x0F12, 0x0023}, //TVAR_afit_pBaseVals[444] + {0x0F12, 0x0023}, //TVAR_afit_pBaseVals[445] + {0x0F12, 0x0A0F}, //TVAR_afit_pBaseVals[446] + {0x0F12, 0x1701}, //TVAR_afit_pBaseVals[447] + {0x0F12, 0x0229}, //TVAR_afit_pBaseVals[448] + {0x0F12, 0x1403}, //TVAR_afit_pBaseVals[449] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[450] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[451] + {0x0F12, 0x0606}, //TVAR_afit_pBaseVals[452] + {0x0F12, 0x00FF}, //TVAR_afit_pBaseVals[453] + {0x0F12, 0x033B}, //TVAR_afit_pBaseVals[454] + {0x0F12, 0x0505}, //TVAR_afit_pBaseVals[455] + {0x0F12, 0x0301}, //TVAR_afit_pBaseVals[456] + {0x0F12, 0x8007}, //TVAR_afit_pBaseVals[457] + {0x0F12, 0x051E}, //TVAR_afit_pBaseVals[458] + {0x0F12, 0x0A1E}, //TVAR_afit_pBaseVals[459] + {0x0F12, 0x0000}, //TVAR_afit_pBaseVals[460] + {0x0F12, 0x0A03}, //TVAR_afit_pBaseVals[461] + {0x0F12, 0x1E3C}, //TVAR_afit_pBaseVals[462] + {0x0F12, 0x1028}, //TVAR_afit_pBaseVals[463] + {0x0F12, 0x0002}, //TVAR_afit_pBaseVals[464] + {0x0F12, 0x00FF}, //TVAR_afit_pBaseVals[465] + {0x0F12, 0x1002}, //TVAR_afit_pBaseVals[466] + {0x0F12, 0x001E}, //TVAR_afit_pBaseVals[467] + {0x0F12, 0x0900}, //TVAR_afit_pBaseVals[468] + {0x0F12, 0x0600}, //TVAR_afit_pBaseVals[469] + {0x0F12, 0x0504}, //TVAR_afit_pBaseVals[470] + {0x0F12, 0x0305}, //TVAR_afit_pBaseVals[471] + {0x0F12, 0x8002}, //TVAR_afit_pBaseVals[472] + {0x0F12, 0x0080}, //TVAR_afit_pBaseVals[473] + {0x0F12, 0x0080}, //TVAR_afit_pBaseVals[474] + {0x0F12, 0x0080}, //TVAR_afit_pBaseVals[475] + {0x0F12, 0x4646}, //TVAR_afit_pBaseVals[476] + {0x0F12, 0x0101}, //TVAR_afit_pBaseVals[477] + {0x0F12, 0x1801}, //TVAR_afit_pBaseVals[478] + {0x0F12, 0x141C}, //TVAR_afit_pBaseVals[479] + {0x0F12, 0x2812}, //TVAR_afit_pBaseVals[480] + {0x0F12, 0x0A00}, //TVAR_afit_pBaseVals[481] + {0x0F12, 0x1003}, //TVAR_afit_pBaseVals[482] + {0x0F12, 0x1405}, //TVAR_afit_pBaseVals[483] + {0x0F12, 0x050C}, //TVAR_afit_pBaseVals[484] + {0x0F12, 0x32FF}, //TVAR_afit_pBaseVals[485] + {0x0F12, 0x5204}, //TVAR_afit_pBaseVals[486] + {0x0F12, 0x1440}, //TVAR_afit_pBaseVals[487] + {0x0F12, 0x4015}, //TVAR_afit_pBaseVals[488] + {0x0F12, 0x0204}, //TVAR_afit_pBaseVals[489] + {0x0F12, 0x5003}, //TVAR_afit_pBaseVals[490] + {0x0F12, 0x0150}, //TVAR_afit_pBaseVals[491] + {0x0F12, 0x0101}, //TVAR_afit_pBaseVals[492] + {0x0F12, 0x1418}, //TVAR_afit_pBaseVals[493] + {0x0F12, 0x1214}, //TVAR_afit_pBaseVals[494] + {0x0F12, 0x0028}, //TVAR_afit_pBaseVals[495] + {0x0F12, 0x030A}, //TVAR_afit_pBaseVals[496] + {0x0F12, 0x0A10}, //TVAR_afit_pBaseVals[497] + {0x0F12, 0x0819}, //TVAR_afit_pBaseVals[498] + {0x0F12, 0xFF05}, //TVAR_afit_pBaseVals[499] + {0x0F12, 0x0432}, //TVAR_afit_pBaseVals[500] + {0x0F12, 0x4052}, //TVAR_afit_pBaseVals[501] + {0x0F12, 0x1514}, //TVAR_afit_pBaseVals[502] + {0x0F12, 0x0440}, //TVAR_afit_pBaseVals[503] + {0x0F12, 0x0302}, //TVAR_afit_pBaseVals[504] + {0x0F12, 0x5050}, //TVAR_afit_pBaseVals[505] + {0x0F12, 0x0101}, //TVAR_afit_pBaseVals[506] + {0x0F12, 0x1801}, //TVAR_afit_pBaseVals[507] + {0x0F12, 0x1414}, //TVAR_afit_pBaseVals[508] + {0x0F12, 0x2812}, //TVAR_afit_pBaseVals[509] + {0x0F12, 0x0A00}, //TVAR_afit_pBaseVals[510] + {0x0F12, 0x1003}, //TVAR_afit_pBaseVals[511] + {0x0F12, 0x190A}, //TVAR_afit_pBaseVals[512] + {0x0F12, 0x0508}, //TVAR_afit_pBaseVals[513] + {0x0F12, 0x32FF}, //TVAR_afit_pBaseVals[514] + {0x0F12, 0x5204}, //TVAR_afit_pBaseVals[515] + {0x0F12, 0x1440}, //TVAR_afit_pBaseVals[516] + {0x0F12, 0x4015}, //TVAR_afit_pBaseVals[517] + {0x0F12, 0x0204}, //TVAR_afit_pBaseVals[518] + {0x0F12, 0x0003}, //TVAR_afit_pBaseVals[519] + // param_end TVAR_afit_pBaseVals + // param_start afit_pConstBaseVals + {0x002A, 0x0BD4}, + {0x0F12, 0x7F7A}, //afit_pConstBaseVals[0] + {0x0F12, 0x779D}, //afit_pConstBaseVals[1] + {0x0F12, 0xBE7E}, //afit_pConstBaseVals[2] + {0x0F12, 0xF7BC}, //afit_pConstBaseVals[3] + {0x0F12, 0x7E06}, //afit_pConstBaseVals[4] + {0x0F12, 0x0053}, //afit_pConstBaseVals[5] + // param_end afit_pConstBaseVals + + // Fill RAM with alternative op-codes + {0x0028, 0x7000}, // start add MSW + {0x002A, 0x2CE8}, // start add LSW + {0x0F12, 0x0007}, // Modify LSB to control AWBB_YThreshLow + {0x0F12, 0x00e2}, // + {0x0F12, 0x0005}, // Modify LSB to control AWBB_YThreshLowBrLow + {0x0F12, 0x00E2}, // + ////////////////////////////////////////////////////////////////////////// + //============================================================ + //END Tuning part + //END: DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + + //================================================================================================ + //SET PLL + //================================================================================================ + //How to set + //1. MCLK + //hex(CLK you want) * 1000) + //2. System CLK + //hex((CLK you want) * 1000 / 4) + //3. PCLK + //hex((CLK you want) * 1000 / 4) + //================================================================================================ + //Set input CLK //24MHz + {0x002A, 0x01CC}, + {0x0F12, 0x5DC0}, //5FB4 //5DC0=24MCLK #REG_TC_IPRM_InClockLSBs + {0x0F12, 0x0000}, //#REG_TC_IPRM_InClockMSBs + {0x002A, 0x01EE}, + {0x0F12, 0x0002}, //#REG_TC_IPRM_UseNPviClocks //Number of PLL setting + //Set system CLK //40MHz + {0x002A, 0x01F6}, + {0x0F12, 0x38a4 }, //2904 //2BF2 //#REG_TC_IPRM_OpClk4KHz_0 + {0x0F12, 0x37A4}, //3A88 //#REG_TC_IPRM_MinOutRate4KHz_0 + {0x0F12, 0x39A4}, //3AA8 //#REG_TC_IPRM_MaxOutRate4KHz_0 + {0x0F12, 0x38A4}, //2904 //2BF2 //#REG_TC_IPRM_OpClk4KHz_1 + //Set pixel CLK //60MHz (0x3A98) + {0x0F12, 0x2EA0}, //#REG_TC_IPRM_MinOutRate4KHz_1 + {0x0F12, 0x2EE0}, //#REG_TC_IPRM_MaxOutRate4KHz_1 + //Update PLL + {0x002A, 0x0208}, + {0x0F12, 0x0001}, //#REG_TC_IPRM_InitParamsUpdated + + {SEQUENCE_WAIT_MS,100},//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + //================================================================================================ + //SET PREVIEW CONFIGURATION_0 + //# Foramt : YUV422 + //# Size: 640x480 + //# FPS : 25fps + //================================================================================================ + {0x002A, 0x026C}, + {0x0F12, 0x0280}, //0400 //#REG_0TC_PCFG_usWidth//1024 + {0x0F12, 0x01E0}, //0300 //#REG_0TC_PCFG_usHeight //768 026E + {0x0F12, 0x0005}, //#REG_0TC_PCFG_Format 0270 + {0x0F12, 0x39a4}, //3AA8 //#REG_0TC_PCFG_usMaxOut4KHzRate 0272 + {0x0F12, 0x37a4}, //3A88 //#REG_0TC_PCFG_usMinOut4KHzRate 0274 + {0x0F12, 0x0100}, //#REG_0TC_PCFG_OutClkPerPix88 0276 + {0x0F12, 0x0800}, //#REG_0TC_PCFG_uMaxBpp88 027 + {0x0F12, 0x0052}, //#REG_0TC_PCFG_PVIMask //s0050 = FALSE in MSM6290 : s0052 = TRUE in MSM6800 //reg 027A + {0x0F12, 0x4000}, //#REG_0TC_PCFG_OIFMask + {0x0F12, 0x0400}, //0x01E0},//#REG_0TC_PCFG_usJpegPacketSize //DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x0000}, //#REG_0TC_PCFG_usJpegTotalPackets + {0x0F12, 0x0000}, //#REG_0TC_PCFG_uClockInd + {0x0F12, 0x0000}, //#REG_0TC_PCFG_usFrTimeType + {0x0F12, 0x0001}, //#REG_0TC_PCFG_FrRateQualityType + {0x0F12, 0x0190}, //03E8 #REG_0TC_PCFG_usMaxFrTimeMsecMult10 min 25fps + {0x0F12, 0x0190}, //029a #REG_0TC_PCFG_usMinFrTimeMsecMult10 max 25fps + {0x0F12, 0x0000}, //#REG_0TC_PCFG_bSmearOutput + {0x0F12, 0x0000}, //#REG_0TC_PCFG_sSaturation + {0x0F12, 0x0000}, //#REG_0TC_PCFG_sSharpBlur + {0x0F12, 0x0000}, //#REG_0TC_PCFG_sColorTemp + {0x0F12, 0x0000}, //#REG_0TC_PCFG_uDeviceGammaIndex + {0x0F12, 0x0003}, //#REG_0TC_PCFG_uPrevMirror + {0x0F12, 0x0003}, //#REG_0TC_PCFG_uCaptureMirror + {0x0F12, 0x0000}, //#REG_0TC_PCFG_uRotation + //================================================================================================ + //SET PREVIEW CONFIGURATION_1 + //# Foramt : YUV422 + //# Size: 1280x720 + //# FPS : 15~15fps + //================================================================================================ + {0x002A, 0x029C}, + {0x0F12, 0x0500}, //0400 //#REG_0TC_PCFG_usWidth//1024 + {0x0F12, 0x02D0}, //0300 //#REG_0TC_PCFG_usHeight //768 026E + {0x0F12, 0x0005}, //#REG_0TC_PCFG_Format 0270 + {0x0F12, 0x2ee0}, //3AA8 //#REG_0TC_PCFG_usMaxOut4KHzRate 0272 + {0x0F12, 0x2ea0}, //3A88 //#REG_0TC_PCFG_usMinOut4KHzRate 0274 + {0x0F12, 0x0100}, //#REG_0TC_PCFG_OutClkPerPix88 0276 + {0x0F12, 0x0800}, //#REG_0TC_PCFG_uMaxBpp88 027 + {0x0F12, 0x0052}, //#REG_0TC_PCFG_PVIMask //s0050 = FALSE in MSM6290 : s0052 = TRUE in MSM6800 //reg 027A + {0x0F12, 0x4000}, //#REG_0TC_PCFG_OIFMask + {0x0F12, 0x0400}, //0x01E0}, //#REG_0TC_PCFG_usJpegPacketSize//DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x0F12, 0x0000}, //#REG_0TC_PCFG_usJpegTotalPackets + {0x0F12, 0x0001}, //#REG_0TC_PCFG_uClockInd + {0x0F12, 0x0000}, //#REG_0TC_PCFG_usFrTimeType + {0x0F12, 0x0002}, //1 //#REG_0TC_PCFG_FrRateQualityType + {0x0F12, 0x029a}, //03E8 #REG_0TC_PCFG_usMaxFrTimeMsecMult10 //15fps + {0x0F12, 0x029a}, //029a #REG_0TC_PCFG_usMinFrTimeMsecMult10 //15fps + {0x0F12, 0x0000}, //#REG_0TC_PCFG_bSmearOutput + {0x0F12, 0x0000}, //#REG_0TC_PCFG_sSaturation + {0x0F12, 0x0000}, //#REG_0TC_PCFG_sSharpBlur + {0x0F12, 0x0000}, //#REG_0TC_PCFG_sColorTemp + {0x0F12, 0x0000}, //#REG_0TC_PCFG_uDeviceGammaIndex + {0x0F12, 0x0003}, //#REG_0TC_PCFG_uPrevMirror + {0x0F12, 0x0003}, //#REG_0TC_PCFG_uCaptureMirror + {0x0F12, 0x0000}, //#REG_0TC_PCFG_uRotation + //================================================================================================ + //APPLY PREVIEW CONFIGURATION & RUN PREVIEW + //================================================================================================ + {0x002A, 0x023C}, + {0x0F12, 0x0000}, //#REG_TC_GP_ActivePrevConfig //Select preview configuration_0 + {0x002A, 0x0240}, + {0x0F12, 0x0001}, //#REG_TC_GP_PrevOpenAfterChange + {0x002A, 0x0230}, + {0x0F12, 0x0001}, //#REG_TC_GP_NewConfigSync //Update preview configuration + {0x002A, 0x023E}, + {0x0F12, 0x0001}, //#REG_TC_GP_PrevConfigChanged + {0x002A, 0x0220}, + {0x0F12, 0x0001}, //#REG_TC_GP_EnablePreview //Start preview + {0x0F12, 0x0001}, //#REG_TC_GP_EnablePreviewChanged + //================================================================================================ + //SET CAPTURE CONFIGURATION_0 + //# Foramt :YUV + //# Size: QXGA + //# FPS : 5 ~ 7.5fps + //================================================================================================ + {0x002A, 0x035C}, + {0x0F12, 0x0000}, //#REG_0TC_CCFG_uCaptureModeJpEG + {0x0F12, 0x0800}, //#REG_0TC_CCFG_usWidth + {0x0F12, 0x0600}, //#REG_0TC_CCFG_usHeight + {0x0F12, 0x0005}, //#REG_0TC_CCFG_Format//5:YUV9:JPEG + //{0x0F12, 0x39ae}, //3AA8 //#REG_0TC_CCFG_usMaxOut4KHzRate + {0x0F12, 0x39a4}, //#REG_0TC_CCFG_usMaxOut4KHzRate//DTS2012071201781:modify by huyouhua at 2012-7-23 + {0x0F12, 0x37a4}, //3A88 //#REG_0TC_CCFG_usMinOut4KHzRate + {0x0F12, 0x0100}, //#REG_0TC_CCFG_OutClkPerPix88 + {0x0F12, 0x0800}, //#REG_0TC_CCFG_uMaxBpp88 + {0x0F12, 0x0052}, //#REG_0TC_CCFG_PVIMask + {0x0F12, 0x0050}, //#REG_0TC_CCFG_OIFMask edison + //BEGIN: DTS2012071201781 modify by huyouhua at 2012-7-23 + //{0x0F12, 0x01E0}, //#REG_0TC_CCFG_usJpegPacketSize + //{0x0F12, 0x08fc}, //#REG_0TC_CCFG_usJpegTotalPackets + {0x0F12, 0x03C0}, //#REG_0TC_CCFG_usJpegPacketSize + //END: DTS2012071201781 modify by huyouhua at 2012-7-23 + {0x0F12, 0x0000}, //#REG_0TC_CCFG_uClockInd + {0x0F12, 0x0000}, //#REG_0TC_CCFG_usFrTimeType + {0x0F12, 0x0000}, //#REG_0TC_CCFG_FrRateQualityType + {0x0F12, 0x0002}, //#REG_0TC_CCFG_FrRateQualityType//DTS2012071201781:add by huyouhua at 2012-7-23 + {0x0F12, 0x07D0}, //#REG_0TC_CCFG_usMaxFrTimeMsecMult10 //5fps + {0x0F12, 0x0535}, //#REG_0TC_CCFG_usMinFrTimeMsecMult10 //7.5fps + {0x0F12, 0x0000}, //#REG_0TC_CCFG_bSmearOutput + {0x0F12, 0x0000}, //#REG_0TC_CCFG_sSaturation + {0x0F12, 0x0000}, //#REG_0TC_CCFG_sSharpBlur + {0x0F12, 0x0000}, //#REG_0TC_CCFG_sColorTemp + {0x0F12, 0x0000}, //#REG_0TC_CCFG_uDeviceGammaIndex + //================================================================================================ + //SET CAPTURE CONFIGURATION_1 + //# Foramt : + //# Size: + //# FPS : + //================================================================================================ + //Not used + {0x0028, 0xD000}, + {0x002A, 0x1000}, + {0x0F12, 0x0001}, + + {SEQUENCE_WAIT_MS,50}, + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_720p[]= +{ + {0x0028, 0x7000}, + {0x002A, 0x01D6}, + {0x0F12, 0x0800}, + {0x0F12, 0x0600}, + {0x0F12, 0x0000}, + {0x0F12, 0x00C0}, + {0x002A, 0x0208}, + {0x0F12, 0x0001}, + + {0x002A, 0x023C}, + {0x0F12, 0x0001}, + {0x002A, 0x0240}, + {0x0F12, 0x0001}, + {0x002A, 0x0230}, + {0x0F12, 0x0001}, + {0x002A, 0x023E}, + {0x0F12, 0x0001}, + {0x002A, 0x0220}, + {0x0F12, 0x0001}, + {0x0F12, 0x0001}, + + {SEQUENCE_END, 0x00} +}; +static struct reginfo sensor_1080p[]= +{ + {SEQUENCE_END, 0x00} +}; +/* 2592X1944 QSXGA */ +static struct reginfo sensor_qsxga[] = +{ + {SEQUENCE_END, 0x00} +}; +/* 2048*1536 QXGA */ +static struct reginfo sensor_qxga[] = +{ + {0x0028 ,0x7000}, + {0x002a ,0x0244},//#REG_TC_GP_ActiveCapConfig num + {0x0f12 ,0x0000}, + {0x0f12 ,0x0001},//#REG_TC_GP_CapConfigChanged + {0x002a ,0x0230}, + {0x0f12 ,0x0001},//#REG_TC_GP_NewConfigSync + {0x002a ,0x0224}, + {0x0f12 ,0x0001},//#REG_TC_GP_EnableCapture + {0x0f12 ,0x0001},//#REG_TC_GP_EnableCaptureChanged + {SEQUENCE_END, 0x00} +}; + +/* 1600X1200 UXGA */ +static struct reginfo sensor_uxga[] = +{ + {SEQUENCE_END, 0x00} +}; + +/* 1280X1024 SXGA */ +static struct reginfo sensor_sxga[] = +{ + {SEQUENCE_END, 0x00} +}; +/* 1024X768 XGA */ +static struct reginfo sensor_xga[] = +{ + {SEQUENCE_END, 0x00} +}; +/* 800X600 SVGA*/ +static struct reginfo sensor_svga[] = +{ + {SEQUENCE_END, 0x0}, +}; + +/* 640X480 VGA */ +static struct reginfo sensor_vga[] = +{ + {0x0028, 0x7000}, + {0x002A, 0x01D6}, + {0x0F12, 0x0140}, + {0x0F12, 0x00F0}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x002A, 0x0208}, + {0x0F12, 0x0001}, + + {0x002A, 0x023C}, + {0x0F12, 0x0000}, + {0x002A, 0x0240}, + {0x0F12, 0x0001}, + {0x002A, 0x0230}, + {0x0F12, 0x0001}, + {0x002A, 0x023E}, + {0x0F12, 0x0001}, + {0x002A, 0x0220}, + {0x0F12, 0x0001}, + {0x0F12, 0x0001}, + + {SEQUENCE_END, 0x0}, +}; +/* 352X288 CIF */ +static struct reginfo sensor_cif[] = +{ + {SEQUENCE_END, 0x0}, +}; + +/* 320*240 QVGA */ +static struct reginfo sensor_qvga[] = +{ + {SEQUENCE_END, 0x0}, +}; + +/* 176X144 QCIF*/ +static struct reginfo sensor_qcif[] = +{ + {SEQUENCE_END, 0x0}, +}; + +static struct reginfo sensor_ClrFmt_YUYV[]= +{ + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_ClrFmt_UYVY[]= +{ + {SEQUENCE_END, 0x00} +}; + +#if CONFIG_SENSOR_WhiteBalance +static struct reginfo sensor_WhiteB_Auto[]= +{ + {0x0028, 0x7000}, + {0x002A, 0X04D2}, + //BEGIN: DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + //{0x0F12, 0x065F}, + {0x0F12, 0x067F}, + //END: DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {SEQUENCE_END, 0x00} +}; + +//incandescent +static struct reginfo sensor_WhiteB_TungstenLamp1[]= +{ + {0x0028, 0x7000}, + {0x002A, 0x04D2}, + //BEGIN: DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + //{0x0F12, 0x0657}, + {0x0F12, 0x0677}, + //END: DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x002A, 0x04A0}, + {0x0F12, 0x0380}, + {0x0F12, 0x0001}, + {0x0F12, 0x0400}, + {0x0F12, 0x0001}, + {0x0F12, 0x09C0}, + {0x0F12, 0x0001}, + + {SEQUENCE_END, 0x00} +}; + +//fluorescent鑽у厜2 +static struct reginfo sensor_WhiteB_TungstenLamp2[]= +{ + {0x0028, 0x7000}, + {0x002A, 0x04D2}, + {0x0F12, 0x0657}, + {0x002A, 0x04A0}, + {0x0F12, 0x0400}, + {0x0F12, 0x0001}, + {0x0F12, 0x0400}, + {0x0F12, 0x0001}, + {0x0F12, 0x083C}, + {0x0F12, 0x0001}, + + {SEQUENCE_END, 0x00} +}; + +//daylight鏃ュ厜3 +static struct reginfo sensor_WhiteB_ClearDay[]= +{ + {0x0028, 0x7000}, + {0x002A, 0x04D2}, + //BEGIN: DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + //{0x0F12, 0x0657}, + {0x0F12, 0x0677}, + //END: DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x002A, 0x04A0}, + {0x0F12, 0x05A0}, + {0x0F12, 0x0001}, + {0x0F12, 0x0400}, + {0x0F12, 0x0001}, + {0x0F12, 0x05F0}, + {0x0F12, 0x0001}, + + {SEQUENCE_END, 0x00} +}; + +//闃村ぉ4 +static struct reginfo sensor_WhiteB_Cloudy[]= +{ + {0x0028, 0x7000}, + {0x002A, 0x04D2}, + //BEGIN: DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + //{0x0F12, 0x0657}, + {0x0F12, 0x0677}, + //END: DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {0x002A, 0x04A0}, + {0x0F12, 0x0540}, + {0x0F12, 0x0001}, + {0x0F12, 0x0400}, + {0x0F12, 0x0001}, + {0x0F12, 0x0500}, + {0x0F12, 0x0001}, + + {SEQUENCE_END, 0x00} +}; + +static struct reginfo *sensor_WhiteBalanceSeqe[] = {sensor_WhiteB_Auto, sensor_WhiteB_TungstenLamp1,sensor_WhiteB_TungstenLamp2, + sensor_WhiteB_ClearDay, sensor_WhiteB_Cloudy, NULL,}; +#endif + +#if CONFIG_SENSOR_Brightness +static struct reginfo sensor_Brightness0[]= +{ + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_Brightness1[]= +{ + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_Brightness2[]= +{ + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_Brightness3[]= +{ + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_Brightness4[]= +{ + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_Brightness5[]= +{ + {SEQUENCE_END, 0x00} +}; +static struct reginfo *sensor_BrightnessSeqe[] = {sensor_Brightness0, sensor_Brightness1, sensor_Brightness2, sensor_Brightness3, + sensor_Brightness4, sensor_Brightness5,NULL, +}; + +#endif + +#if CONFIG_SENSOR_Effect +static struct reginfo sensor_Effect_Normal[] = +{ + {0x0028, 0x7000}, + {0x002A, 0x021E}, + {0x0F12, 0x0000}, + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_Effect_WandB[] = +{ + {0x0028, 0x7000}, + {0x002A, 0x021E}, + {0x0F12, 0x0001}, + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_Effect_Sepia[] = +{ + {0x0028, 0x7000}, + {0x002A, 0x021E}, + {0x0F12, 0x0004}, + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_Effect_Negative[] = +{ + {0x0028, 0x7000}, + {0x002A, 0x021E}, + //BEGIN: DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + //{0x0F12, 0x0002}, + {0x0F12, 0x0003}, + //END: DTS2012071201781: modify by huyouhua 00136760 at 2012-7-20 + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_Effect_Bluish[] = +{ + {0x0028, 0x7000}, + {0x002A, 0x021E}, + {0x0F12, 0x0003}, + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_Effect_Green[] = +{ + {0x0028, 0x7000}, + {0x002A, 0x021E}, + {0x0F12, 0x0005}, + {SEQUENCE_END, 0x00} +}; + +static struct reginfo *sensor_EffectSeqe[] = {sensor_Effect_Normal, sensor_Effect_WandB, sensor_Effect_Negative,sensor_Effect_Sepia, + sensor_Effect_Bluish, sensor_Effect_Green,NULL, +}; +#endif + +#if CONFIG_SENSOR_Exposure +static struct reginfo sensor_Exposure0[]= +{ + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_Exposure1[]= +{ + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_Exposure2[]= +{ + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_Exposure3[]= +{ + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_Exposure4[]= +{ + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_Exposure5[]= +{ + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_Exposure6[]= +{ + {SEQUENCE_END, 0x00} +}; + +static struct reginfo *sensor_ExposureSeqe[] = {sensor_Exposure0, sensor_Exposure1, sensor_Exposure2, sensor_Exposure3, + sensor_Exposure4, sensor_Exposure5,sensor_Exposure6,NULL, +}; +#endif +#if CONFIG_SENSOR_Saturation +static struct reginfo sensor_Saturation0[]= +{ + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_Saturation1[]= +{ + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_Saturation2[]= +{ + {SEQUENCE_END, 0x00} +}; +static struct reginfo *sensor_SaturationSeqe[] = {sensor_Saturation0, sensor_Saturation1, sensor_Saturation2, NULL,}; + +#endif +#if CONFIG_SENSOR_Contrast +static struct reginfo sensor_Contrast0[]= +{ + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_Contrast1[]= +{ + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_Contrast2[]= +{ + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_Contrast3[]= +{ + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_Contrast4[]= +{ + {SEQUENCE_END, 0x00} +}; + + +static struct reginfo sensor_Contrast5[]= +{ + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_Contrast6[]= +{ + {SEQUENCE_END, 0x00} +}; +static struct reginfo *sensor_ContrastSeqe[] = {sensor_Contrast0, sensor_Contrast1, sensor_Contrast2, sensor_Contrast3, + sensor_Contrast4, sensor_Contrast5, sensor_Contrast6, NULL, +}; + +#endif +#if CONFIG_SENSOR_Mirror +static struct reginfo sensor_MirrorOn[]= +{ + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_MirrorOff[]= +{ + {SEQUENCE_END, 0x00} +}; +static struct reginfo *sensor_MirrorSeqe[] = {sensor_MirrorOff, sensor_MirrorOn,NULL,}; +#endif +#if CONFIG_SENSOR_Flip +static struct reginfo sensor_FlipOn[]= +{ + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_FlipOff[]= +{ + {SEQUENCE_END, 0x00} +}; +static struct reginfo *sensor_FlipSeqe[] = {sensor_FlipOff, sensor_FlipOn,NULL,}; + +#endif + +#if CONFIG_SENSOR_Scene +static struct reginfo sensor_SceneNormal[] = +{ + {0x0028,0x7000}, + {0x002A,0x0288}, + {0x0F12,0X0190}, + {0x0F12,0X014D}, + {0x002A,0x023E}, + {0x0F12,0x0001}, + + {SEQUENCE_WAIT_MS,50}, + + {0x002A,0x023C}, + {0x0F12,0x0000}, + {0x002A,0x0240}, + {0x0F12,0x0001}, + {0x002A,0x0230}, + {0x0F12,0x0001}, + {0x002A,0x023E}, + {0x0F12,0x0001}, + {0x002A,0x0220}, + {0x0F12,0x0001}, + {0x0F12,0x0001}, + + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_SceneNight[] = +{ + {0x0028,0x7000}, + {0x002A,0x0288}, + {0x0F12,0X07D0}, + {0x0F12,0X029A}, + {0x002A,0x023E}, + {0x0F12,0x0001}, + + {SEQUENCE_WAIT_MS,50}, + + {0x002A,0x023C}, + {0x0F12,0x0000}, + {0x002A,0x0240}, + {0x0F12,0x0001}, + {0x002A,0x0230}, + {0x0F12,0x0001}, + {0x002A,0x023E}, + {0x0F12,0x0001}, + {0x002A,0x0220}, + {0x0F12,0x0001}, + {0x0F12,0x0001}, + + {SEQUENCE_END, 0x00} +}; +static struct reginfo *sensor_SceneSeqe[] = {sensor_SceneNormal, sensor_SceneNight, NULL,}; +#endif + +#if CONFIG_SENSOR_AntiBanding +static struct reginfo sensor_AntiBanding_50HZ[] = +{ + {0x0028, 0x7000}, + {0x002a, 0x04d2}, + {0x0f12, 0x065f}, + {0x002a, 0x04ba}, + {0x0f12, 0x0001}, + {0x002a, 0x04bc}, + {0x0f12, 0x0001}, + {SEQUENCE_END, 0x00} +}; + +static struct reginfo sensor_AntiBanding_60HZ[] = +{ + {0x0028, 0x7000}, + {0x002a, 0x04d2}, + {0x0f12, 0x065f}, + {0x002a, 0x04ba}, + {0x0f12, 0x0002}, + {0x002a, 0x04bc}, + {0x0f12, 0x0001}, + {SEQUENCE_END, 0x00} +}; +static struct reginfo *sensor_AntiBandingSeqe[] = {sensor_AntiBanding_50HZ, sensor_AntiBanding_60HZ, NULL,}; +#endif + +#if CONFIG_SENSOR_DigitalZoom +static struct reginfo sensor_Zoom0[] = +{ + {SEQUENCE_END, 0x0}, +}; + +static struct reginfo sensor_Zoom1[] = +{ + {SEQUENCE_END, 0x0}, +}; + +static struct reginfo sensor_Zoom2[] = +{ + {SEQUENCE_END, 0x0}, +}; + + +static struct reginfo sensor_Zoom3[] = +{ + {SEQUENCE_END, 0x0}, +}; +static struct reginfo *sensor_ZoomSeqe[] = {sensor_Zoom0, sensor_Zoom1, sensor_Zoom2, sensor_Zoom3, NULL,}; +#endif +static const struct v4l2_querymenu sensor_menus[] = +{ + #if CONFIG_SENSOR_WhiteBalance + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 0, .name = "auto", .reserved = 0, }, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 1, .name = "incandescent", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 2, .name = "fluorescent", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 3, .name = "daylight", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 4, .name = "cloudy-daylight", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Effect + { .id = V4L2_CID_EFFECT, .index = 0, .name = "none", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 1, .name = "mono", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 2, .name = "negative", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 3, .name = "sepia", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 4, .name = "posterize", .reserved = 0,} , + //{ .id = V4L2_CID_EFFECT, .index = 5, .name = "aqua", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Scene + { .id = V4L2_CID_SCENE, .index = 0, .name = "auto", .reserved = 0,}, + { .id = V4L2_CID_SCENE, .index = 1, .name = "night", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_AntiBanding + { .id = V4L2_CID_ANTIBANDING, .index = 0, .name = "50hz", .reserved = 0,}, + { .id = V4L2_CID_ANTIBANDING, .index = 1, .name = "60hz", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Flash + { .id = V4L2_CID_FLASH, .index = 0, .name = "off", .reserved = 0, }, { .id = V4L2_CID_FLASH, .index = 1, .name = "auto", .reserved = 0,}, + { .id = V4L2_CID_FLASH, .index = 2, .name = "on", .reserved = 0,}, { .id = V4L2_CID_FLASH, .index = 3, .name = "torch", .reserved = 0,}, + #endif +}; + +static const struct v4l2_queryctrl sensor_controls[] = +{ + #if CONFIG_SENSOR_WhiteBalance + { + .id = V4L2_CID_DO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "White Balance Control", + .minimum = 0, + .maximum = 4, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Brightness + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness Control", + .minimum = -3, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Effect + { + .id = V4L2_CID_EFFECT, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Effect Control", + .minimum = 0, + .maximum = 4, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Exposure + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure Control", + .minimum = 0, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Saturation + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation Control", + .minimum = 0, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Contrast + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast Control", + .minimum = -3, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Mirror + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + #endif + + #if CONFIG_SENSOR_Flip + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + #endif + + #if CONFIG_SENSOR_Scene + { + .id = V4L2_CID_SCENE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Scene Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_AntiBanding + { + .id = V4L2_CID_ANTIBANDING, + .type = V4L2_CTRL_TYPE_MENU, + .name = "AntiBanding Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_DigitalZoom + { + .id = V4L2_CID_ZOOM_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DigitalZoom Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_ZOOM_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DigitalZoom Control", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Focus + { + .id = V4L2_CID_FOCUS_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Focus Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_FOCUS_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Focus Control", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 125, + }, + #endif + + #if CONFIG_SENSOR_Flash + { + .id = V4L2_CID_FLASH, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Flash Control", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif +}; + +static int sensor_probe(struct i2c_client *client, const struct i2c_device_id *did); +static int sensor_video_probe(struct soc_camera_device *icd, struct i2c_client *client); +static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl); +static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl); +static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg); +static int sensor_resume(struct soc_camera_device *icd); +static int sensor_set_bus_param(struct soc_camera_device *icd,unsigned long flags); +static unsigned long sensor_query_bus_param(struct soc_camera_device *icd); +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +static int sensor_deactivate(struct i2c_client *client); + +static struct soc_camera_ops sensor_ops = +{ + .suspend = sensor_suspend, + .resume = sensor_resume, + .set_bus_param = sensor_set_bus_param, + .query_bus_param = sensor_query_bus_param, + .controls = sensor_controls, + .menus = sensor_menus, + .num_controls = ARRAY_SIZE(sensor_controls), + .num_menus = ARRAY_SIZE(sensor_menus), +}; + + +/* only one fixed colorspace per pixelcode */ +struct sensor_datafmt { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; +}; + +/* Find a data format by a pixel code in an array */ +static const struct sensor_datafmt *sensor_find_datafmt( + enum v4l2_mbus_pixelcode code, const struct sensor_datafmt *fmt, + int n) +{ + int i; + for (i = 0; i < n; i++) + if (fmt[i].code == code) + return fmt + i; + + return NULL; +} + +static const struct sensor_datafmt sensor_colour_fmts[] = { + {V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG} +}; +enum sensor_work_state +{ + sensor_work_ready = 0, + sensor_working, +}; +struct sensor_work +{ + struct i2c_client *client; + struct delayed_work dwork; + enum sensor_work_state state; +}; + +typedef struct sensor_info_priv_s +{ + int whiteBalance; + int brightness; + int contrast; + int saturation; + int effect; + int scene; + int antibanding; + int digitalzoom; + int focus; + int auto_focus; + int affm_reinit; + int flash; + int exposure; + unsigned char mirror; /* HFLIP */ + unsigned char flip; /* VFLIP */ + bool snap2preview; + bool video2preview; + int capture_w; + int capture_h; + int preview_w; + int preview_h; + struct reginfo *winseqe_cur_addr; + struct sensor_datafmt fmt; + unsigned int enable; + unsigned int funmodule_state; +} sensor_info_priv_t; + + + +struct sensor_parameter +{ + unsigned short int preview_maxlines; + unsigned short int preview_exposure; + unsigned short int preview_line_width; + unsigned short int preview_gain; + + unsigned short int capture_framerate; + unsigned short int preview_framerate; +}; + +struct sensor +{ + struct v4l2_subdev subdev; + struct i2c_client *client; + sensor_info_priv_t info_priv; + struct sensor_parameter parameter; + struct workqueue_struct *sensor_wq; + struct sensor_work sensor_wk; + struct mutex wq_lock; + int model; /* V4L2_IDENT_OV* codes from v4l2-chip-ident.h */ +#if CONFIG_SENSOR_I2C_NOSCHED + atomic_t tasklock_cnt; +#endif + struct rk29camera_platform_data *sensor_io_request; + struct rk29camera_gpio_res *sensor_gpio_res; +}; + +static struct sensor* to_sensor(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct sensor, subdev); +} + +static int sensor_task_lock(struct i2c_client *client, int lock) +{ +#if CONFIG_SENSOR_I2C_NOSCHED + int cnt = 3; + struct sensor *sensor = to_sensor(client); + + if (lock) { + if (atomic_read(&sensor->tasklock_cnt) == 0) { + while ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt>0)) { + SENSOR_TR("\n %s will obtain i2c in atomic, but i2c bus is locked! Wait...\n",SENSOR_NAME_STRING()); + msleep(35); + cnt--; + } + if ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt<=0)) { + SENSOR_TR("\n %s obtain i2c fail in atomic!!\n",SENSOR_NAME_STRING()); + goto sensor_task_lock_err; + } + preempt_disable(); + } + + atomic_add(1, &sensor->tasklock_cnt); + } else { + if (atomic_read(&sensor->tasklock_cnt) > 0) { + atomic_sub(1, &sensor->tasklock_cnt); + + if (atomic_read(&sensor->tasklock_cnt) == 0) + preempt_enable(); + } + } + return 0; +sensor_task_lock_err: + return -1; +#else + return 0; +#endif + +} + +/* sensor register write */ +static int sensor_write(struct i2c_client *client, u16 reg, u16 val) +{ + int err=0,cnt; + u8 buf[4]; + struct i2c_msg msg[1]; + + switch (reg) + { + case SEQUENCE_WAIT_MS: + { + //msleep(val); + mdelay(val); + break; + } + + case SEQUENCE_WAIT_US: + { + udelay(val); + break; + } + + case SEQUENCE_PROPERTY: + { + break; + } + default: + { + buf[0] = reg >> 8; + buf[1] = reg & 0xFF; + buf[2] = val >> 8; + buf[3] = val & 0xFF; + + msg->addr = client->addr; + msg->flags = client->flags; + msg->buf = buf; + msg->len = sizeof(buf); + msg->scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg->read_type = 0; /* fpga i2c:0==I2C_NORMAL : direct use number not enum for don't want include spi_fpga.h */ + + cnt = 3; + err = -EAGAIN; + + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + err = i2c_transfer(client->adapter, msg, 1); + + if (err >= 0) { + return 0; + } else { + SENSOR_TR("\n %s write reg(0x%x, val:0x%x) failed, try to write again!\n",SENSOR_NAME_STRING(),reg, val); + udelay(10); + } + } + } + } + return err; +} + +/* sensor register read */ +static int sensor_read(struct i2c_client *client, u16 reg, u16 *val) +{ + u8 buf[2]; + struct i2c_msg msg[2]; + int err = 0; + + buf[0] = (u8)reg >> 8; + buf[1] = (u8)reg & 0xFF; + + msg[0].addr = client->addr; + msg[0].flags = client->flags; + msg[0].buf = buf; + msg[0].len = sizeof(buf); + msg[0].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg[0].read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */ + + msg[1].addr = client->addr; + msg[1].flags = client->flags|I2C_M_RD; + msg[1].buf = buf; + msg[1].len = sizeof(buf); + msg[1].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg[1].read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */ + + err = i2c_transfer(client->adapter, msg, 2); + + if(err >= 0) { + *val = (buf[0] << 8)|(buf[1] & 0xFF); + SENSOR_DG("%s read reg(0x%x val:0x%x) success\n",SENSOR_NAME_STRING(),reg,*val); + return 0; + } else { + SENSOR_TR("%s read reg(0x%x) failed!",SENSOR_NAME_STRING(),reg); + } + + return err; +} + +/* write a array of registers */ +static int sensor_write_array(struct i2c_client *client, struct reginfo *regarray) +{ + int err = 0, cnt; + int i = 0; +#if CONFIG_SENSOR_I2C_RDWRCHK + char valchk; +#endif + + cnt = 0; + if (sensor_task_lock(client, 1) < 0) + goto sensor_write_array_end; + while (regarray[i].reg != SEQUENCE_END) + { + + err = sensor_write(client, regarray[i].reg, regarray[i].val); + if (err < 0) + { + if (cnt-- > 0) { + SENSOR_TR("%s..write failed current reg:0x%x, Write array again !\n", SENSOR_NAME_STRING(),regarray[i].reg); + i = 0; + continue; + } else { + SENSOR_TR("%s..write array failed!!!\n", SENSOR_NAME_STRING()); + err = -EPERM; + goto sensor_write_array_end; + } + } else { + #if CONFIG_SENSOR_I2C_RDWRCHK + sensor_read(client, regarray[i].reg, &valchk); + if (valchk != regarray[i].val) + SENSOR_TR("%s Reg:0x%x write(0x%x, 0x%x) fail\n",SENSOR_NAME_STRING(), regarray[i].reg, regarray[i].val, valchk); + #endif + } + + i++; + } + +sensor_write_array_end: + sensor_task_lock(client,0); + return err; +} + +#if CONFIG_SENSOR_I2C_RDWRCHK +static int sensor_readchk_array(struct i2c_client *client, struct reginfo *regarray) +{ + int cnt; + int i = 0; + char valchk; + + cnt = 0; + valchk = 0; + while (regarray[i].reg != SEQUENCE_END) + { + sensor_read(client, regarray[i].reg, &valchk); + if (valchk != regarray[i].val) + SENSOR_TR("%s Reg:0x%x read(0x%x, 0x%x) error\n",SENSOR_NAME_STRING(), regarray[i].reg, regarray[i].val, valchk); + + i++; + } + return 0; +} +#endif +#if CONFIG_SENSOR_Focus + +static int sensor_af_single(struct i2c_client *client) +{ + int ret = 0; + + +sensor_af_single_end: + return ret; +} + +static int sensor_af_const(struct i2c_client *client) +{ + int ret = 0; + +sensor_af_const_end: + return ret; +} + +static int sensor_af_zoneupdate(struct i2c_client *client) +{ + int ret = 0; + +sensor_af_zoneupdate_end: + return ret; +} + +static int sensor_af_init(struct i2c_client *client) +{ + int ret = 0; + + return ret; +} +#endif + +static int sensor_ioctrl(struct soc_camera_device *icd,enum rk29sensor_power_cmd cmd, int on) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + int ret = 0; + + switch (cmd) + { + case Sensor_Reset: + { + if (sensor->sensor_io_request && sensor->sensor_io_request->sensor_ioctrl) { + sensor->sensor_io_request->sensor_ioctrl(icd->pdev,Cam_Reset, on); + } + break; + } + case Sensor_PowerDown: + { + if (icl->powerdown) { + ret = icl->powerdown(icd->pdev, on); + if (ret == RK29_CAM_IO_SUCCESS) { + if (on == 0) { + mdelay(2); + if (icl->reset) + icl->reset(icd->pdev); + } + } else if (ret == RK29_CAM_EIO_REQUESTFAIL) { + ret = -ENODEV; + goto sensor_power_end; + } + } + break; + } + case Sensor_Flash: + { + if (sensor->sensor_io_request && sensor->sensor_io_request->sensor_ioctrl) { + sensor->sensor_io_request->sensor_ioctrl(icd->pdev,Cam_Flash, on); + } + break; + } + default: + { + SENSOR_TR("%s cmd(0x%x) is unknown!",SENSOR_NAME_STRING(),cmd); + break; + } + } + +sensor_power_end: + return ret; +} + +static int sensor_init(struct v4l2_subdev *sd, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + const struct sensor_datafmt *fmt; + int ret; + u16 pid = 0; + + SENSOR_DG("\n%s..%s.. \n",SENSOR_NAME_STRING(),__FUNCTION__); + + sensor_ioctrl(icd,Sensor_Reset, 1); + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + udelay(50); + sensor_ioctrl(icd,Sensor_Reset, 0); + mdelay(1); + /* soft reset */ + if (sensor_task_lock(client,1)<0) + goto sensor_INIT_ERR; + +#if (SENSOR_RESET_REG != SEQUENCE_END) + ret = sensor_write(client, SENSOR_RESET_REG, SENSOR_RESET_VAL); + if (ret != 0) { + SENSOR_TR("%s soft reset sensor failed\n",SENSOR_NAME_STRING()); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + mdelay(5); //delay 5 microseconds +#endif + + /* check if it is an sensor sensor */ +#if (SENSOR_ID_REG != SEQUENCE_END) + ret = sensor_read(client, SENSOR_ID_REG, &pid); + if (ret != 0) { + SENSOR_TR("read chip id failed\n"); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + SENSOR_DG("\n %s pid = 0x%x \n", SENSOR_NAME_STRING(), pid); +#else + pid = SENSOR_ID; +#endif + if (pid == SENSOR_ID) { + sensor->model = SENSOR_V4L2_IDENT; + } else { + SENSOR_TR("error: %s mismatched pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + ret = sensor_write_array(client, sensor_init_data); + if (ret != 0) + { + SENSOR_TR("error: %s initial failed\n",SENSOR_NAME_STRING()); + goto sensor_INIT_ERR; + } + sensor_task_lock(client,0); + sensor->info_priv.winseqe_cur_addr = SENSOR_INIT_WINSEQADR; + fmt = sensor_find_datafmt(SENSOR_INIT_PIXFMT,sensor_colour_fmts, ARRAY_SIZE(sensor_colour_fmts)); + if (!fmt) { + SENSOR_TR("error: %s initial array colour fmts is not support!!",SENSOR_NAME_STRING()); + ret = -EINVAL; + goto sensor_INIT_ERR; + } + sensor->info_priv.fmt = *fmt; + + /* sensor sensor information for initialization */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + if (qctrl) + sensor->info_priv.whiteBalance = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_BRIGHTNESS); + if (qctrl) + sensor->info_priv.brightness = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + if (qctrl) + sensor->info_priv.effect = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EXPOSURE); + if (qctrl) + sensor->info_priv.exposure = qctrl->default_value; + + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SATURATION); + if (qctrl) + sensor->info_priv.saturation = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_CONTRAST); + if (qctrl) + sensor->info_priv.contrast = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_HFLIP); + if (qctrl) + sensor->info_priv.mirror = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_VFLIP); + if (qctrl) + sensor->info_priv.flip = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SCENE); + if (qctrl) + sensor->info_priv.scene = qctrl->default_value; + #if CONFIG_SENSOR_AntiBanding + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ANTIBANDING); + if (qctrl) + sensor->info_priv.antibanding = qctrl->default_value; + #endif + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE); + if (qctrl) + sensor->info_priv.digitalzoom = qctrl->default_value; + + /* ddl@rock-chips.com : if sensor support auto focus and flash, programer must run focus and flash code */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FOCUS_ABSOLUTE); + if (qctrl) + sensor->info_priv.focus = qctrl->default_value; + + #if CONFIG_SENSOR_Flash + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FLASH); + if (qctrl) + sensor->info_priv.flash = qctrl->default_value; + #endif + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),((val == 0)?__FUNCTION__:"sensor_reinit"),icd->user_width,icd->user_height); +sensor_init_end: + sensor->info_priv.funmodule_state |= SENSOR_INIT_IS_OK; + return 0; +sensor_INIT_ERR: + sensor->info_priv.funmodule_state |= SENSOR_INIT_IS_OK; + sensor_task_lock(client,0); + sensor_deactivate(client); + return ret; +} + +static int sensor_deactivate(struct i2c_client *client) +{ + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + + SENSOR_DG("\n%s..%s.. Enter\n",SENSOR_NAME_STRING(),__FUNCTION__); + + /* ddl@rock-chips.com : all sensor output pin must change to input for other sensor */ + //sensor_task_lock(client, 1); + sensor_ioctrl(icd, Sensor_PowerDown, 1); + msleep(100); + + /* ddl@rock-chips.com : sensor config init width , because next open sensor quickly(soc_camera_open -> Try to configure with default parameters) */ + icd->user_width = SENSOR_INIT_WIDTH; + icd->user_height = SENSOR_INIT_HEIGHT; + sensor->info_priv.funmodule_state &= ~SENSOR_INIT_IS_OK; + + return 0; +} + +static struct reginfo sensor_suspend_sequence[]= +{ + {SEQUENCE_END,0x00} +}; + +static struct reginfo sensor_resume_sequence[]= +{ + {SEQUENCE_END,0x00} +}; +static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg) +{ + int ret; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if (pm_msg.event == PM_EVENT_SUSPEND) { + SENSOR_DG("\n %s Enter Suspend.. \n", SENSOR_NAME_STRING()); + ret = sensor_write_array(client, sensor_suspend_sequence) ; + if (ret != 0) { + SENSOR_TR("\n %s..%s WriteReg Fail.. \n", SENSOR_NAME_STRING(),__FUNCTION__); + return ret; + } else { + mdelay(100); + ret = sensor_ioctrl(icd, Sensor_PowerDown, 1); + if (ret < 0) { + SENSOR_TR("\n %s suspend fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + } + } else { + SENSOR_TR("\n %s cann't suppout Suspend..\n",SENSOR_NAME_STRING()); + return -EINVAL; + } + + return 0; +} + +static int sensor_resume(struct soc_camera_device *icd) +{ + int ret; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + ret = sensor_ioctrl(icd, Sensor_PowerDown, 0); + if (ret < 0) { + SENSOR_TR("\n %s resume fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; + } else { + udelay(5); + ret = sensor_write_array(client, sensor_resume_sequence) ; + if (ret != 0) { + SENSOR_TR("\n %s..%s WriteReg Fail.. \n", SENSOR_NAME_STRING(),__FUNCTION__); + return -EINVAL; + } + } + + SENSOR_DG("\n %s Enter Resume.. \n", SENSOR_NAME_STRING()); + + return 0; +} + +static int sensor_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + return 0; +} + +static unsigned long sensor_query_bus_param(struct soc_camera_device *icd) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + unsigned long flags = SENSOR_BUS_PARAM; + + return soc_camera_apply_sensor_flags(icl, flags); +} + +static int sensor_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + + mf->width = icd->user_width; + mf->height = icd->user_height; + mf->code = sensor->info_priv.fmt.code; + mf->colorspace = sensor->info_priv.fmt.colorspace; + mf->field = V4L2_FIELD_NONE; + + return 0; +} +static bool sensor_fmt_capturechk(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + bool ret = false; + + if ((mf->width == 1024) && (mf->height == 768)) { + ret = true; + } else if ((mf->width == 1280) && (mf->height == 1024)) { + ret = true; + } else if ((mf->width == 1600) && (mf->height == 1200)) { + ret = true; + } else if ((mf->width == 2048) && (mf->height == 1536)) { + ret = true; + } else if ((mf->width == 2592) && (mf->height == 1944)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is capture format\n", __FUNCTION__, mf->width, mf->height); + return ret; +} + +static bool sensor_fmt_videochk(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + bool ret = false; + + if ((mf->width == 1280) && (mf->height == 720)) { + ret = true; + } else if ((mf->width == 1920) && (mf->height == 1080)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is video format\n", __FUNCTION__, mf->width, mf->height); + return ret; +} +static struct reginfo* sensor_fmt_catch(int set_w, int set_h, int *ret_w, int *ret_h) +{ + struct reginfo *winseqe_set_addr = NULL; + + if (((set_w <= 176) && (set_h <= 144)) && (sensor_qcif[0].reg!=SEQUENCE_END)) { + winseqe_set_addr = sensor_qcif; + *ret_w = 176; + *ret_h = 144; + } else if (((set_w <= 320) && (set_h <= 240)) && (sensor_qvga[0].reg!=SEQUENCE_END)) { + winseqe_set_addr = sensor_qvga; + *ret_w = 320; + *ret_h = 240; + } else if (((set_w <= 352) && (set_h<= 288)) && (sensor_cif[0].reg!=SEQUENCE_END)) { + winseqe_set_addr = sensor_cif; + *ret_w = 352; + *ret_h = 288; + } else if (((set_w <= 640) && (set_h <= 480)) && (sensor_vga[0].reg!=SEQUENCE_END)) { + winseqe_set_addr = sensor_vga; + *ret_w = 640; + *ret_h = 480; + } +#if CONFIG_SENSOR_FOR_CTS + /**lzg@rockchip.com: forbid to preview with resolution 1280*1024*/ + else if (((set_w <= 800) && (set_h <= 600)) && (sensor_vga[0].reg!=SEQUENCE_END)) { + winseqe_set_addr = sensor_vga; + *ret_w = 640; + *ret_h = 480; + } +#else + else if (((set_w <= 800) && (set_h <= 600)) && (sensor_svga[0].reg!=SEQUENCE_END)) { + winseqe_set_addr = sensor_svga; + *ret_w = 800; + *ret_h = 600; + } +#endif + else if (((set_w <= 1024) && (set_h <= 768)) && (sensor_xga[0].reg!=SEQUENCE_END)) { + winseqe_set_addr = sensor_xga; + *ret_w = 1024; + *ret_h = 768; + } else if (((set_w <= 1280) && (set_h <= 720)) && (sensor_720p[0].reg!=SEQUENCE_END)) { + winseqe_set_addr = sensor_720p; + *ret_w = 1280; + *ret_h = 720; + } else if (((set_w <= 1280) && (set_h <= 1024)) && (sensor_sxga[0].reg!=SEQUENCE_END)) { + winseqe_set_addr = sensor_sxga; + *ret_w = 1280; + *ret_h = 1024; + } else if (((set_w <= 1600) && (set_h <= 1200)) && (sensor_uxga[0].reg!=SEQUENCE_END)) { + winseqe_set_addr = sensor_uxga; + *ret_w = 1600; + *ret_h = 1200; + } +#if CONFIG_SENSOR_FOR_CTS + /**lzg@rockchip.com: forbid to preview with resolution 1280*1024*/ + else if (((set_w <= 1920) && (set_h <= 1080)) && (sensor_vga[0].reg!=SEQUENCE_END)) { + winseqe_set_addr = sensor_vga; + *ret_w = 640; + *ret_h = 480; + } +#else + else if (((set_w <= 1920) && (set_h <= 1080)) && (sensor_1080p[0].reg!=SEQUENCE_END)) { + winseqe_set_addr = sensor_1080p; + *ret_w = 1920; + *ret_h = 1080; + } +#endif + else if (((set_w <= 2048) && (set_h <= 1536)) && (sensor_qxga[0].reg!=SEQUENCE_END)) { + winseqe_set_addr = sensor_qxga; + *ret_w = 2048; + *ret_h = 1536; + } else if (((set_w <= 2592) && (set_h <= 1944)) && (sensor_qsxga[0].reg!=SEQUENCE_END)) { + winseqe_set_addr = sensor_qsxga; + *ret_w = 2592; + *ret_h = 1944; + } + + return winseqe_set_addr; +} + +static int sensor_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + const struct sensor_datafmt *fmt; + struct sensor *sensor = to_sensor(client); + struct reginfo *winseqe_set_addr=NULL; + int ret=0, set_w,set_h; + + fmt = sensor_find_datafmt(mf->code, sensor_colour_fmts, + ARRAY_SIZE(sensor_colour_fmts)); + if (!fmt) { + ret = -EINVAL; + goto sensor_s_fmt_end; + } + + if (sensor->info_priv.fmt.code != mf->code) { + switch (mf->code) + { + case V4L2_MBUS_FMT_YUYV8_2X8: + { + winseqe_set_addr = sensor_ClrFmt_YUYV; + break; + } + case V4L2_MBUS_FMT_UYVY8_2X8: + { + winseqe_set_addr = sensor_ClrFmt_UYVY; + break; + } + default: + break; + } + if (winseqe_set_addr != NULL) { + sensor_write_array(client, winseqe_set_addr); + sensor->info_priv.fmt.code = mf->code; + sensor->info_priv.fmt.colorspace= mf->colorspace; + SENSOR_DG("%s v4l2_mbus_code:%d set success!\n", SENSOR_NAME_STRING(),mf->code); + } else { + SENSOR_TR("%s v4l2_mbus_code:%d is invalidate!\n", SENSOR_NAME_STRING(),mf->code); + } + } + + set_w = mf->width; + set_h = mf->height; + + winseqe_set_addr = sensor_fmt_catch(set_w, set_h, &set_w, &set_h); + + if ((winseqe_set_addr != sensor->info_priv.winseqe_cur_addr) && winseqe_set_addr) { + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,mf) == true) { /* ddl@rock-chips.com : Capture */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_On); + SENSOR_DG("%s flash on in capture!\n", SENSOR_NAME_STRING()); + } + } else { /* ddl@rock-chips.com : Video */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_DG("%s flash off in preivew!\n", SENSOR_NAME_STRING()); + } + } + #endif + ret |= sensor_write_array(client, winseqe_set_addr); + if (ret != 0) { + SENSOR_TR("%s set format capability failed\n", SENSOR_NAME_STRING()); + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,mf) == true) { + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_TR("%s Capture format set fail, flash off !\n", SENSOR_NAME_STRING()); + } + } + #endif + goto sensor_s_fmt_end; + } + + sensor->info_priv.winseqe_cur_addr = (unsigned int)winseqe_set_addr; + + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),__FUNCTION__,set_w,set_h); + } else { + SENSOR_TR("\n %s .. Current Format is validate. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),set_w,set_h); + } + + mf->width = set_w; + mf->height = set_h; + +sensor_s_fmt_end: + return ret; +} + +static int sensor_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct sensor *sensor = to_sensor(client); + const struct sensor_datafmt *fmt; + int ret = 0, set_w,set_h;; + + fmt = sensor_find_datafmt(mf->code, sensor_colour_fmts, + ARRAY_SIZE(sensor_colour_fmts)); + if (fmt == NULL) { + fmt = &sensor->info_priv.fmt; + mf->code = fmt->code; + } + + if (mf->height > SENSOR_MAX_HEIGHT) + mf->height = SENSOR_MAX_HEIGHT; + else if (mf->height < SENSOR_MIN_HEIGHT) + mf->height = SENSOR_MIN_HEIGHT; + + if (mf->width > SENSOR_MAX_WIDTH) + mf->width = SENSOR_MAX_WIDTH; + else if (mf->width < SENSOR_MIN_WIDTH) + mf->width = SENSOR_MIN_WIDTH; + + set_w = mf->width; + set_h = mf->height; + + if (((set_w <= 176) && (set_h <= 144)) && sensor_qcif[0].reg) + { + set_w = 176; + set_h = 144; + } + else if (((set_w <= 320) && (set_h <= 240)) && sensor_qvga[0].reg) + { + set_w = 320; + set_h = 240; + } + else if (((set_w <= 352) && (set_h<= 288)) && sensor_cif[0].reg) + { + set_w = 352; + set_h = 288; + } + else if (((set_w <= 640) && (set_h <= 480)) && sensor_vga[0].reg) + { + set_w = 640; + set_h = 480; + } + else if (((set_w <= 800) && (set_h <= 600)) && sensor_svga[0].reg) + { + set_w = 800; + set_h = 600; + } + else if (((set_w <= 1280) && (set_h <= 720)) && sensor_720p[0].reg) + { + set_w = 1280; + set_h = 720; + } + else if (((set_w <= 1024) && (set_h <= 768)) && sensor_xga[0].reg) + { + set_w = 1024; + set_h = 768; + } + else if (((set_w <= 1280) && (set_h <= 1024)) && sensor_sxga[0].reg) + { + set_w = 1280; + set_h = 1024; + } + else if (((set_w <= 1600) && (set_h <= 1200)) && sensor_uxga[0].reg) + { + set_w = 1600; + set_h = 1200; + } + else if (((set_w <= 2048) && (set_h <= 1536)) && sensor_qxga[0].reg) + { + set_w = 2048; + set_h = 1536; + } + else + { /* ddl@rock-chips.com : Sensor output smallest size if isn't support app */ + set_w = SENSOR_INIT_WIDTH; + set_h = SENSOR_INIT_HEIGHT; + } + mf->width = set_w; + mf->height = set_h; + mf->colorspace = fmt->colorspace; + + return ret; +} + + static int sensor_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *id) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) + return -EINVAL; + + if (id->match.addr != client->addr) + return -ENODEV; + + id->ident = SENSOR_V4L2_IDENT; /* ddl@rock-chips.com : Return s5k6aa identifier */ + id->revision = 0; + + return 0; +} +#if CONFIG_SENSOR_Brightness +static int sensor_set_brightness(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_BrightnessSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_BrightnessSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Effect +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_EffectSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_EffectSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Exposure +static int sensor_set_exposure(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_ExposureSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_ExposureSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Saturation +static int sensor_set_saturation(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_SaturationSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_SaturationSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Contrast +static int sensor_set_contrast(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_ContrastSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_ContrastSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Mirror +static int sensor_set_mirror(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_MirrorSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_MirrorSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Flip +static int sensor_set_flip(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_FlipSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_FlipSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Scene +static int sensor_set_scene(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_SceneSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_SceneSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_AntiBanding +static int sensor_set_antibanding(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_AntiBandingSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_AntiBandingSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_WhiteBalance +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_WhiteBalanceSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_WhiteBalanceSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_DigitalZoom +static int sensor_set_digitalzoom(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int *value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl_info; + int digitalzoom_cur, digitalzoom_total; + + qctrl_info = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE); + if (qctrl_info) + return -EINVAL; + + digitalzoom_cur = sensor->info_priv.digitalzoom; + digitalzoom_total = qctrl_info->maximum; + + if ((*value > 0) && (digitalzoom_cur >= digitalzoom_total)) + { + SENSOR_TR("%s digitalzoom is maximum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur); + return -EINVAL; + } + + if ((*value < 0) && (digitalzoom_cur <= qctrl_info->minimum)) + { + SENSOR_TR("%s digitalzoom is minimum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur); + return -EINVAL; + } + + if ((*value > 0) && ((digitalzoom_cur + *value) > digitalzoom_total)) + { + *value = digitalzoom_total - digitalzoom_cur; + } + + if ((*value < 0) && ((digitalzoom_cur + *value) < 0)) + { + *value = 0 - digitalzoom_cur; + } + + digitalzoom_cur += *value; + + if (sensor_ZoomSeqe[digitalzoom_cur] != NULL) + { + if (sensor_write_array(client, sensor_ZoomSeqe[digitalzoom_cur]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, *value); + return 0; + } + + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Flash +static int sensor_set_flash(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl_info; + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) { + if (value == 3) { /* ddl@rock-chips.com: torch */ + sensor_ioctrl(icd, Sensor_Flash, Flash_Torch); /* Flash On */ + } else { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + + qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + return -EINVAL; + } + + switch (ctrl->id) + { + case V4L2_CID_BRIGHTNESS: + { + ctrl->value = sensor->info_priv.brightness; + break; + } + case V4L2_CID_SATURATION: + { + ctrl->value = sensor->info_priv.saturation; + break; + } + case V4L2_CID_CONTRAST: + { + ctrl->value = sensor->info_priv.contrast; + break; + } + case V4L2_CID_DO_WHITE_BALANCE: + { + ctrl->value = sensor->info_priv.whiteBalance; + break; + } + case V4L2_CID_EXPOSURE: + { + ctrl->value = sensor->info_priv.exposure; + break; + } + case V4L2_CID_HFLIP: + { + ctrl->value = sensor->info_priv.mirror; + break; + } + case V4L2_CID_VFLIP: + { + ctrl->value = sensor->info_priv.flip; + break; + } + default : + break; + } + return 0; +} + + + +static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct sensor *sensor = to_sensor(client); + struct soc_camera_device *icd = client->dev.platform_data; + const struct v4l2_queryctrl *qctrl; + + + qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + return -EINVAL; + } + + switch (ctrl->id) + { +#if CONFIG_SENSOR_Brightness + case V4L2_CID_BRIGHTNESS: + { + if (ctrl->value != sensor->info_priv.brightness) + { + if (sensor_set_brightness(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.brightness = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Exposure + case V4L2_CID_EXPOSURE: + { + if (ctrl->value != sensor->info_priv.exposure) + { + if (sensor_set_exposure(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.exposure = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Saturation + case V4L2_CID_SATURATION: + { + if (ctrl->value != sensor->info_priv.saturation) + { + if (sensor_set_saturation(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.saturation = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Contrast + case V4L2_CID_CONTRAST: + { + if (ctrl->value != sensor->info_priv.contrast) + { + if (sensor_set_contrast(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.contrast = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_WhiteBalance + case V4L2_CID_DO_WHITE_BALANCE: + { + if (ctrl->value != sensor->info_priv.whiteBalance) + { + if (sensor_set_whiteBalance(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.whiteBalance = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Mirror + case V4L2_CID_HFLIP: + { + if (ctrl->value != sensor->info_priv.mirror) + { + if (sensor_set_mirror(icd, qctrl,ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.mirror = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Flip + case V4L2_CID_VFLIP: + { + if (ctrl->value != sensor->info_priv.flip) + { + if (sensor_set_flip(icd, qctrl,ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.flip = ctrl->value; + } + break; + } +#endif + default: + break; + } + + return 0; +} +static int sensor_g_ext_control(struct soc_camera_device *icd , struct v4l2_ext_control *ext_ctrl) +{ + const struct v4l2_queryctrl *qctrl; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + return -EINVAL; + } + + switch (ext_ctrl->id) + { + case V4L2_CID_SCENE: + { + ext_ctrl->value = sensor->info_priv.scene; + break; + } + #if CONFIG_SENSOR_AntiBanding + case V4L2_CID_ANTIBANDING: + { + ext_ctrl->value = sensor->info_priv.antibanding; + break; + } + #endif + case V4L2_CID_EFFECT: + { + ext_ctrl->value = sensor->info_priv.effect; + break; + } + case V4L2_CID_ZOOM_ABSOLUTE: + { + ext_ctrl->value = sensor->info_priv.digitalzoom; + break; + } + case V4L2_CID_ZOOM_RELATIVE: + { + return -EINVAL; + } + case V4L2_CID_FOCUS_ABSOLUTE: + { + ext_ctrl->value = sensor->info_priv.focus; + break; + } + case V4L2_CID_FOCUS_RELATIVE: + { + return -EINVAL; + } + case V4L2_CID_FLASH: + { + ext_ctrl->value = sensor->info_priv.flash; + break; + } + default : + break; + } + return 0; +} +static int sensor_s_ext_control(struct soc_camera_device *icd, struct v4l2_ext_control *ext_ctrl) +{ + const struct v4l2_queryctrl *qctrl; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + int val_offset; + + qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + return -EINVAL; + } + + val_offset = 0; + switch (ext_ctrl->id) + { +#if CONFIG_SENSOR_Scene + case V4L2_CID_SCENE: + { + if (ext_ctrl->value != sensor->info_priv.scene) + { + if (sensor_set_scene(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.scene = ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_AntiBanding + case V4L2_CID_ANTIBANDING: + { + if (ext_ctrl->value != sensor->info_priv.antibanding) + { + if (sensor_set_antibanding(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.antibanding = ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Effect + case V4L2_CID_EFFECT: + { + if (ext_ctrl->value != sensor->info_priv.effect) + { + if (sensor_set_effect(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.effect= ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_DigitalZoom + case V4L2_CID_ZOOM_ABSOLUTE: + { + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; + + if (ext_ctrl->value != sensor->info_priv.digitalzoom) + { + val_offset = ext_ctrl->value -sensor->info_priv.digitalzoom; + + if (sensor_set_digitalzoom(icd, qctrl,&val_offset) != 0) + return -EINVAL; + sensor->info_priv.digitalzoom += val_offset; + + SENSOR_DG("%s digitalzoom is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.digitalzoom); + } + + break; + } + case V4L2_CID_ZOOM_RELATIVE: + { + if (ext_ctrl->value) + { + if (sensor_set_digitalzoom(icd, qctrl,&ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.digitalzoom += ext_ctrl->value; + + SENSOR_DG("%s digitalzoom is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.digitalzoom); + } + break; + } +#endif +#if CONFIG_SENSOR_Focus + case V4L2_CID_FOCUS_ABSOLUTE: + { + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; + + if (ext_ctrl->value != sensor->info_priv.focus) + { + val_offset = ext_ctrl->value -sensor->info_priv.focus; + + sensor->info_priv.focus += val_offset; + } + + break; + } + case V4L2_CID_FOCUS_RELATIVE: + { + if (ext_ctrl->value) + { + sensor->info_priv.focus += ext_ctrl->value; + + SENSOR_DG("%s focus is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.focus); + } + break; + } +#endif +#if CONFIG_SENSOR_Flash + case V4L2_CID_FLASH: + { + if (sensor_set_flash(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.flash = ext_ctrl->value; + + SENSOR_DG("%s flash is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.flash); + break; + } +#endif + default: + break; + } + + return 0; +} + +static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + int i, error_cnt=0, error_idx=-1; + + + for (i=0; icount; i++) { + if (sensor_g_ext_control(icd, &ext_ctrl->controls[i]) != 0) { + error_cnt++; + error_idx = i; + } + } + + if (error_cnt > 1) + error_idx = ext_ctrl->count; + + if (error_idx != -1) { + ext_ctrl->error_idx = error_idx; + return -EINVAL; + } else { + return 0; + } +} + +static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + int i, error_cnt=0, error_idx=-1; + + + for (i=0; icount; i++) { + if (sensor_s_ext_control(icd, &ext_ctrl->controls[i]) != 0) { + error_cnt++; + error_idx = i; + } + } + + if (error_cnt > 1) + error_idx = ext_ctrl->count; + + if (error_idx != -1) { + ext_ctrl->error_idx = error_idx; + return -EINVAL; + } else { + return 0; + } +} +static int sensor_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct sensor *sensor = to_sensor(client); + + if (enable == 1) { + sensor->info_priv.enable = 1; + } else if (enable == 0) { + sensor->info_priv.enable = 0; + } + + return 0; +} +/* Interface active, can use i2c. If it fails, it can indeed mean, that + * this wasn't our capture interface, so, we wait for the right one */ +static int sensor_video_probe(struct soc_camera_device *icd, + struct i2c_client *client) +{ + int ret,pid = 0; + struct sensor *sensor = to_sensor(client); + + /* We must have a parent by now. And it cannot be a wrong one. + * So this entire test is completely redundant. */ + if (!icd->dev.parent || + to_soc_camera_host(icd->dev.parent)->nr != icd->iface) + return -ENODEV; + + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_video_probe_err; + } + + //if senor online + ret = sensor_write(client, 0x002c, 0x0000); + if (ret != 0) { + SENSOR_TR("%s soft reset sensor failed\n",SENSOR_NAME_STRING()); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + /* soft reset */ +#if (SENSOR_RESET_REG != SEQUENCE_END) + ret = sensor_write(client, SENSOR_RESET_REG, SENSOR_RESET_VAL); + if (ret != 0) { + SENSOR_TR("%s soft reset sensor failed\n",SENSOR_NAME_STRING()); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + mdelay(5); //delay 5 microseconds +#endif + + /* check if it is an sensor sensor */ +#if (SENSOR_ID_REG != SEQUENCE_END) + ret = sensor_read(client, SENSOR_ID_REG, &pid); + if (ret != 0) { + SENSOR_TR("read chip id failed\n"); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + SENSOR_DG("\n %s pid = 0x%x \n", SENSOR_NAME_STRING(), pid); +#else + pid = SENSOR_ID; +#endif + + if (pid == SENSOR_ID) { + sensor->model = SENSOR_V4L2_IDENT; + } else { + SENSOR_TR("error: %s mismatched pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + return 0; + +sensor_video_probe_err: + + return ret; +} +static long sensor_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + int ret = 0; +#if CONFIG_SENSOR_Flash + int i; +#endif + + SENSOR_DG("\n%s..%s..cmd:%x \n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + switch (cmd) + { + case RK29_CAM_SUBDEV_DEACTIVATE: + { + sensor_deactivate(client); + break; + } + case RK29_CAM_SUBDEV_IOREQUEST: + { + sensor->sensor_io_request = (struct rk29camera_platform_data*)arg; + if (sensor->sensor_io_request != NULL) { + if (sensor->sensor_io_request->gpio_res[0].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[0].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[0]; + } else if (sensor->sensor_io_request->gpio_res[1].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[1].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[1]; + } + } else { + SENSOR_TR("%s %s RK29_CAM_SUBDEV_IOREQUEST fail\n",SENSOR_NAME_STRING(),__FUNCTION__); + ret = -EINVAL; + goto sensor_ioctl_end; + } + /* ddl@rock-chips.com : if gpio_flash havn't been set in board-xxx.c, sensor driver must notify is not support flash control + for this project */ + #if CONFIG_SENSOR_Flash + if (sensor->sensor_gpio_res) { + if (sensor->sensor_gpio_res->gpio_flash == INVALID_GPIO) { + for (i = 0; i < icd->ops->num_controls; i++) { + if (V4L2_CID_FLASH == icd->ops->controls[i].id) { + memset(&icd->ops->controls[i],0x00,sizeof(struct v4l2_queryctrl)); + } + } + sensor->info_priv.flash = 0xff; + SENSOR_DG("%s flash gpio is invalidate!\n",SENSOR_NAME_STRING()); + } + } + #endif + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown !\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } +sensor_ioctl_end: + return ret; + +} +static int sensor_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + if (index >= ARRAY_SIZE(sensor_colour_fmts)) + return -EINVAL; + + *code = sensor_colour_fmts[index].code; + return 0; +} +static struct v4l2_subdev_core_ops sensor_subdev_core_ops = { + .init = sensor_init, + .g_ctrl = sensor_g_control, + .s_ctrl = sensor_s_control, + .g_ext_ctrls = sensor_g_ext_controls, + .s_ext_ctrls = sensor_s_ext_controls, + .g_chip_ident = sensor_g_chip_ident, + .ioctl = sensor_ioctl, +}; + +static struct v4l2_subdev_video_ops sensor_subdev_video_ops = { + .s_mbus_fmt = sensor_s_fmt, + .g_mbus_fmt = sensor_g_fmt, + .try_mbus_fmt = sensor_try_fmt, + .enum_mbus_fmt = sensor_enum_fmt, + .s_stream = sensor_s_stream, +}; +static struct v4l2_subdev_ops sensor_subdev_ops = { + .core = &sensor_subdev_core_ops, + .video = &sensor_subdev_video_ops, +}; + +static int sensor_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct sensor *sensor; + struct soc_camera_device *icd = client->dev.platform_data; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct soc_camera_link *icl; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + int ret; + + SENSOR_DG("\n%s..%s..%d..\n",__FUNCTION__,__FILE__,__LINE__); + if (!icd) { + dev_err(&client->dev, "%s: missing soc-camera data!\n",SENSOR_NAME_STRING()); + return -EINVAL; + } + + icl = to_soc_camera_link(icd); + if (!icl) { + dev_err(&client->dev, "%s driver needs platform data\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { + dev_warn(&adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_I2C\n"); + return -EIO; + } + + sensor = kzalloc(sizeof(struct sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + v4l2_i2c_subdev_init(&sensor->subdev, client, &sensor_subdev_ops); + + /* Second stage probe - when a capture adapter is there */ + icd->ops = &sensor_ops; + sensor->info_priv.fmt = sensor_colour_fmts[0]; + + ret = sensor_video_probe(icd, client); + if (ret) { + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + kfree(sensor); + } + + SENSOR_DG("\n%s..%s..%d ret = %x \n",__FUNCTION__,__FILE__,__LINE__,ret); + return ret; +} + +static int sensor_remove(struct i2c_client *client) +{ + struct sensor *sensor = to_sensor(client); + struct soc_camera_device *icd = client->dev.platform_data; + + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + client->driver = NULL; + kfree(sensor); + + return 0; +} + +static const struct i2c_device_id sensor_id[] = { + {SENSOR_NAME_STRING(), 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sensor_id); + +static struct i2c_driver sensor_i2c_driver = { + .driver = { + .name = SENSOR_NAME_STRING(), + }, + .probe = sensor_probe, + .remove = sensor_remove, + .id_table = sensor_id, +}; + +static int __init sensor_mod_init(void) +{ + //SENSOR_DG("\n%s..%s.. \n",__FUNCTION__,SENSOR_NAME_STRING()); + printk(">>>>>>>>>>\n%s..%s.. \n",__FUNCTION__,SENSOR_NAME_STRING()); + return i2c_add_driver(&sensor_i2c_driver); +} + +static void __exit sensor_mod_exit(void) +{ + i2c_del_driver(&sensor_i2c_driver); +} + +device_initcall_sync(sensor_mod_init); +module_exit(sensor_mod_exit); + +MODULE_DESCRIPTION(SENSOR_NAME_STRING(Camera sensor driver)); +MODULE_AUTHOR("ddl "); +MODULE_LICENSE("GPL"); + + diff --git a/drivers/media/video/s5k5ca.h b/drivers/media/video/s5k5ca.h new file mode 100755 index 000000000000..de1643ceb812 --- /dev/null +++ b/drivers/media/video/s5k5ca.h @@ -0,0 +1,242 @@ +#ifndef __S5K6AA_H__ +#define __S5K6AA_H__ + +struct reginfo +{ + u16 reg; + u16 val; +}; + +/* General purpose section */ +#define REG_TC_GP_SpecialEffects 0x01EE +#define REG_TC_GP_EnablePreview 0x01F0 +#define REG_TC_GP_EnablePreviewChanged 0x01F2 +#define REG_TC_GP_EnableCapture 0x01F4 +#define REG_TC_GP_EnableCaptureChanged 0x01F6 +#define REG_TC_GP_NewConfigSync 0x01F8 +#define REG_TC_GP_PrevReqInputWidth 0x01FA +#define REG_TC_GP_PrevReqInputHeight 0x01FC +#define REG_TC_GP_PrevInputWidthOfs 0x01FE +#define REG_TC_GP_PrevInputHeightOfs 0x0200 +#define REG_TC_GP_CapReqInputWidth 0x0202 +#define REG_TC_GP_CapReqInputHeight 0x0204 +#define REG_TC_GP_CapInputWidthOfs 0x0206 +#define REG_TC_GP_CapInputHeightOfs 0x0208 +#define REG_TC_GP_PrevZoomReqInputWidth 0x020A +#define REG_TC_GP_PrevZoomReqInputHeight 0x020C +#define REG_TC_GP_PrevZoomReqInputWidthOfs 0x020E +#define REG_TC_GP_PrevZoomReqInputHeightOfs 0x0210 +#define REG_TC_GP_CapZoomReqInputWidth 0x0212 +#define REG_TC_GP_CapZoomReqInputHeight 0x0214 +#define REG_TC_GP_CapZoomReqInputWidthOfs 0x0216 +#define REG_TC_GP_CapZoomReqInputHeightOfs 0x0218 +#define REG_TC_GP_InputsChangeRequest 0x021A +#define REG_TC_GP_ActivePrevConfig 0x021C +#define REG_TC_GP_PrevConfigChanged 0x021E +#define REG_TC_GP_PrevOpenAfterChange 0x0220 +#define REG_TC_GP_ErrorPrevConfig 0x0222 +#define REG_TC_GP_ActiveCapConfig 0x0224 +#define REG_TC_GP_CapConfigChanged 0x0226 +#define REG_TC_GP_ErrorCapConfig 0x0228 +#define REG_TC_GP_PrevConfigBypassChanged 0x022A +#define REG_TC_GP_CapConfigBypassChanged 0x022C +#define REG_TC_GP_SleepMode 0x022E +#define REG_TC_GP_SleepModeChanged 0x0230 +#define REG_TC_GP_SRA_AddLow 0x0232 +#define REG_TC_GP_SRA_AddHigh 0x0234 +#define REG_TC_GP_SRA_AccessType 0x0236 +#define REG_TC_GP_SRA_Changed 0x0238 +#define REG_TC_GP_PrevMinFrTimeMsecMult10 0x023A +#define REG_TC_GP_PrevOutKHzRate 0x023C +#define REG_TC_GP_CapMinFrTimeMsecMult10 0x023E +#define REG_TC_GP_CapOutKHzRate 0x0240 + +/* Image property control section */ +#define REG_TC_UserBrightness 0x01E4 +#define REG_TC_UserContrast 0x01E6 +#define REG_TC_UserSaturation 0x01E8 +#define REG_TC_UserSharpBlur 0x01EA +#define REG_TC_UserGlamour 0x01EC + +/* Flash control section */ +#define REG_TC_FLS_Mode 0x03B6 +#define REG_TC_FLS_Threshold 0x03B8 +#define REG_TC_FLS_Polarity 0x03BA +#define REG_TC_FLS_XenonMode 0x03BC +#define REG_TC_FLS_XenonPreFlashCnt 0x03BE + +/* Extended image property control section */ +#define REG_SF_USER_LeiLow 0x03C0 +#define REG_SF_USER_LeiHigh 0x03C2 +#define REG_SF_USER_LeiChanged 0x03C4 +#define REG_SF_USER_Exposure 0x03C6 +#define REG_SF_USER_ExposureChanged 0x03CA +#define REG_SF_USER_TotalGain 0x03CC +#define REG_SF_USER_TotalGainChanged 0x03CE +#define REG_SF_USER_Rgain 0x03D0 +#define REG_SF_USER_RgainChanged 0x03D2 +#define REG_SF_USER_Ggain 0x03D4 +#define REG_SF_USER_GgainChanged 0x03D6 +#define REG_SF_USER_Bgain 0x03D8 +#define REG_SF_USER_BgainChanged 0x03DA +#define REG_SF_USER_FlickerQuant 0x03DC +#define REG_SF_USER_FlickerQuantChanged 0x03DE +#define REG_SF_USER_GASRAlphaVal 0x03E0 +#define REG_SF_USER_GASRAlphaChanged 0x03E2 +#define REG_SF_USER_GASGAlphaVal 0x03E4 +#define REG_SF_USER_GASGAlphaChanged 0x03E6 +#define REG_SF_USER_GASBAlphaVal 0x03E8 +#define REG_SF_USER_GASBAlphaChanged 0x03EA +#define REG_SF_USER_DbgIdx 0x03EC +#define REG_SF_USER_DbgVal 0x03EE +#define REG_SF_USER_DbgChanged 0x03F0 +#define REG_SF_USER_aGain 0x03F2 +#define REG_SF_USER_aGainChanged 0x03F4 +#define REG_SF_USER_dGain 0x03F6 +#define REG_SF_USER_dGainChanged 0x03F8 + +/* Output interface control section */ +#define REG_TC_OIF_EnMipiLanes 0x03FA +#define REG_TC_OIF_EnPackets 0x03FC +#define REG_TC_OIF_CfgChanged 0x03FE + +/* Debug control section */ +#define REG_TC_DBG_AutoAlgEnBits 0x0400 +#define REG_TC_DBG_IspBypass 0x0402 +#define REG_TC_DBG_ReInitCmd 0x0404 + +/* Version information section */ +#define REG_FWdate 0x012C +#define REG_FWapiVer 0x012E +#define REG_FWrevision 0x0130 +#define REG_FWpid 0x0132 +#define REG_FWprjName 0x0134 +#define REG_FWcompDate 0x0140 +#define REG_FWSFC_VER 0x014C +#define REG_FWTC_VER 0x014E +#define REG_FWrealImageLine 0x0150 +#define REG_FWsenId 0x0152 +#define REG_FWusDevIdQaVersion 0x0154 +#define REG_FWusFwCompilationBits 0x0156 +#define REG_ulSVNrevision 0x0158 +#define REG_SVNpathRomAddress 0x015C +#define REG_TRAP_N_PATCH_START_ADD 0x1B00 + +#define setot_usForceClocksSettings 0x0AEA +#define setot_usConfigClocksSettings 0x0AEC + +#define REG_0TC_CCFG_uCaptureMode 0x030C +#define REG_0TC_CCFG_usWidth 0x030E +#define REG_0TC_CCFG_usHeight 0x0310 +#define REG_0TC_CCFG_Format 0x0312 +#define REG_0TC_CCFG_usMaxOut4KHzRate 0x0314 +#define REG_0TC_CCFG_usMinOut4KHzRate 0x0316 +#define REG_0TC_CCFG_PVIMask 0x0318 +#define REG_0TC_CCFG_uClockInd 0x031A +#define REG_0TC_CCFG_usFrTimeType 0x031C +#define REG_0TC_CCFG_FrRateQualityType 0x031E +#define REG_0TC_CCFG_usMaxFrTimeMsecMult10 0x0320 +#define REG_0TC_CCFG_usMinFrTimeMsecMult10 0x0322 +#define lt_uMaxAnGain2 0x049A +#define REG_TC_GP_ActivePrevConfig 0x021C +#define REG_TC_GP_PrevOpenAfterChange 0x0220 +#define REG_TC_GP_NewConfigSync 0x01F8 +#define REG_TC_GP_PrevConfigChanged 0x021E +#define REG_TC_GP_ActiveCapConfig 0x0224 +#define REG_TC_GP_CapConfigChanged 0x0226 +#define REG_TC_GP_EnableCapture 0x01F4 +#define REG_TC_GP_EnableCaptureChanged 0x01F6 + +#define lt_uMaxExp1 0x0488 // 0x9C40 +#define lt_uMaxExp2 0x048C // 0xE848 +#define lt_uCapMaxExp1 0x0490 // 0x9C40 +#define lt_uCapMaxExp2 0x0494 // 0xE848 +#define lt_uMaxDigGain 0x049C // 0x0200 +#define lt_uMaxAnGain1 0x0498 // 0x0200 +#define lt_uMaxAnGain2 0x049A // 0x0500 + + +#define REG_1TC_CCFG_uCaptureMode 0x032E // 0x0000 +#define REG_1TC_CCFG_Cfg 0x0330 // 0x0500 +#define REG_1TC_CCFG_usWidth 0x0330 // 0x0500 +#define REG_1TC_CCFG_usHeight 0x0332 // 0x03C0 +#define REG_1TC_CCFG_Format 0x0334 // 0x0009 +#define REG_1TC_CCFG_usMaxOut4KHzRate 0x0336 // 0x1770 +#define REG_1TC_CCFG_usMinOut4KHzRate 0x0338 // 0x05DC +#define REG_1TC_CCFG_PVIMask 0x033A // 0x0042 +#define REG_1TC_CCFG_uClockInd 0x033C // 0x0000 +#define REG_1TC_CCFG_usFrTimeType 0x033E // 0x0000 +#define REG_1TC_CCFG_FrRateQualityType 0x0340 // 0x0002 +#define REG_1TC_CCFG_usMaxFrTimeMsecMult10 0x0342 // 0x1964 +#define REG_1TC_CCFG_usMinFrTimeMsecMult10 0x0344 // 0x0000 +#define REG_1TC_CCFG_sSaturation 0x0346 // 0x0000 +#define REG_1TC_CCFG_sSharpBlur 0x0348 // 0x0000 +#define REG_1TC_CCFG_sGlamour 0x034A // 0x0000 +#define REG_1TC_CCFG_sColorTemp 0x034C // 0x0000 +#define REG_1TC_CCFG_uDeviceGammaIndex 0x034E // 0x0000 +#define REG_CapConfigControls_2_ 0x0350 // 0x0000 + + +#define REG_1TC_PCFG_usWidth 0x0268 +#define REG_1TC_PCFG_usHeight 0x026A +#define REG_1TC_PCFG_Format 0x026C +#define REG_1TC_PCFG_usMaxOut4KHzRate 0x026E +#define REG_1TC_PCFG_usMinOut4KHzRate 0x0270 +#define REG_1TC_PCFG_PVIMask 0x0272 +#define REG_1TC_PCFG_uClockInd 0x0274 +#define REG_1TC_PCFG_usFrTimeType 0x0276 +#define REG_1TC_PCFG_FrRateQualityType 0x0278 +#define REG_1TC_PCFG_usMaxFrTimeMsecMult10 0x027A +#define REG_1TC_PCFG_usMinFrTimeMsecMult10 0x027C + +#define AFC_Default60Hz 0x0B2A +#define REG_TC_DBG_AutoAlgEnBits 0x0400 +#define REG_SF_USER_FlickerQuant 0x03DC +#define REG_SF_USER_FlickerQuantChanged 0x03DE + + +#define REG_2TC_PCFG_usWidth 0x028E +#define REG_2TC_PCFG_usHeight 0x0290 +#define REG_2TC_PCFG_Format 0x0292 +#define REG_2TC_PCFG_usMaxOut4KHzRate 0x0294 +#define REG_2TC_PCFG_usMinOut4KHzRate 0x0296 +#define REG_2TC_PCFG_PVIMask 0x0298 +#define REG_2TC_PCFG_uClockInd 0x029A +#define REG_2TC_PCFG_usFrTimeType 0x029C +#define REG_2TC_PCFG_FrRateQualityType 0x029E +#define REG_2TC_PCFG_usMaxFrTimeMsecMult10 0x02A0 +#define REG_2TC_PCFG_usMinFrTimeMsecMult10 0x02A2 + +#define REG_3TC_PCFG_usWidth 0x02B4 +#define REG_3TC_PCFG_usHeight 0x02B6 +#define REG_3TC_PCFG_Format 0x02B8 +#define REG_3TC_PCFG_usMaxOut4KHzRate 0x02BA +#define REG_3TC_PCFG_usMinOut4KHzRate 0x02BC +#define REG_3TC_PCFG_PVIMask 0x02BE +#define REG_3TC_PCFG_uClockInd 0x02C0 +#define REG_3TC_PCFG_usFrTimeType 0x02C2 +#define REG_3TC_PCFG_FrRateQualityType 0x02C4 +#define REG_3TC_PCFG_usMaxFrTimeMsecMult10 0x02C6 +#define REG_3TC_PCFG_usMinFrTimeMsecMult10 0x02C8 + +#define SEQUENCE_INIT 0x00 +#define SEQUENCE_NORMAL 0x01 +#define SEQUENCE_CAPTURE 0x02 +#define SEQUENCE_PREVIEW 0x03 + +#define SEQUENCE_PROPERTY 0xFFF9 +#define SEQUENCE_WAIT_MS 0xFFFA +#define SEQUENCE_WAIT_US 0xFFFB +#define SEQUENCE_END (0xFFFF) +#define SEQUENCE_FAST_SETMODE_START (0xFFFD) +#define SEQUENCE_FAST_SETMODE_END (0xFFFC) + + +/*configure register for flipe and mirror during initial*/ +#define CONFIG_SENSOR_FLIPE 0 +#define CONFIG_SENSOR_MIRROR 1 +#define CONFIG_SENSOR_MIRROR_AND_FLIPE 0 +#define CONFIG_SENSOR_NONE_FLIP_MIRROR 0 +/**configure to indicate android cts****/ +#define CONFIG_SENSOR_FOR_CTS 1 +#endif \ No newline at end of file diff --git a/drivers/media/video/sp0838.c b/drivers/media/video/sp0838.c new file mode 100755 index 000000000000..0ec3dd7a4037 --- /dev/null +++ b/drivers/media/video/sp0838.c @@ -0,0 +1,2884 @@ + +/* +o* Driver for MT9M001 CMOS Image Sensor from Micron + * + * Copyright (C) 2008, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int debug=1; +module_param(debug, int, S_IRUGO|S_IWUSR); + +#define dprintk(level, fmt, arg...) do { \ + if (debug >= level) \ + printk(KERN_WARNING fmt , ## arg); } while (0) + +#define SENSOR_TR(format, ...) printk(KERN_ERR format, ## __VA_ARGS__) +#define SENSOR_DG(format, ...) dprintk(1, format, ## __VA_ARGS__) + + +#define _CONS(a,b) a##b +#define CONS(a,b) _CONS(a,b) + +#define __STR(x) #x +#define _STR(x) __STR(x) +#define STR(x) _STR(x) + +#define MIN(x,y) ((xy) ? x: y) + +/* Sensor Driver Configuration */ +#define SENSOR_NAME RK29_CAM_SENSOR_SP0838 +#define SENSOR_V4L2_IDENT V4L2_IDENT_SP0838 +#define SENSOR_ID 0x27 +#define SENSOR_ID_REG 0x02 +#define SENSOR_MIN_WIDTH 640//176 +#define SENSOR_MIN_HEIGHT 480//144 +#define SENSOR_MAX_WIDTH 640 +#define SENSOR_MAX_HEIGHT 480 +#define SENSOR_INIT_WIDTH 640 /* Sensor pixel size for sensor_init_data array */ +#define SENSOR_INIT_HEIGHT 480 +#define SENSOR_INIT_WINSEQADR sensor_vga +#define SENSOR_INIT_PIXFMT V4L2_MBUS_FMT_YUYV8_2X8 + +#define CONFIG_SENSOR_WhiteBalance 1 +#define CONFIG_SENSOR_Brightness 0 +#define CONFIG_SENSOR_Contrast 0 +#define CONFIG_SENSOR_Saturation 0 +#define CONFIG_SENSOR_Effect 1 +#define CONFIG_SENSOR_Scene 1 +#define CONFIG_SENSOR_DigitalZoom 0 +#define CONFIG_SENSOR_Focus 0 +#define CONFIG_SENSOR_Exposure 0 +#define CONFIG_SENSOR_Flash 0 +#define CONFIG_SENSOR_Mirror 0 +#define CONFIG_SENSOR_Flip 0 + +#define CONFIG_SENSOR_I2C_SPEED 100000 ///250000 /* Hz */ +/* Sensor write register continues by preempt_disable/preempt_enable for current process not be scheduled */ +#define CONFIG_SENSOR_I2C_NOSCHED 0 +#define CONFIG_SENSOR_I2C_RDWRCHK 0 + +#define SENSOR_BUS_PARAM (SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |\ + SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |\ + SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8 |SOCAM_MCLK_24MHZ) + +#define COLOR_TEMPERATURE_CLOUDY_DN 6500 +#define COLOR_TEMPERATURE_CLOUDY_UP 8000 +#define COLOR_TEMPERATURE_CLEARDAY_DN 5000 +#define COLOR_TEMPERATURE_CLEARDAY_UP 6500 +#define COLOR_TEMPERATURE_OFFICE_DN 3500 +#define COLOR_TEMPERATURE_OFFICE_UP 5000 +#define COLOR_TEMPERATURE_HOME_DN 2500 +#define COLOR_TEMPERATURE_HOME_UP 3500 + +#define SENSOR_NAME_STRING(a) STR(CONS(SENSOR_NAME, a)) +#define SENSOR_NAME_VARFUN(a) CONS(SENSOR_NAME, a) + +#define SENSOR_AF_IS_ERR (0x00<<0) +#define SENSOR_AF_IS_OK (0x01<<0) +#define SENSOR_INIT_IS_ERR (0x00<<28) +#define SENSOR_INIT_IS_OK (0x01<<28) + + +//HEQ +#define Pre_Value_P0_0xdd 0x70 +#define Pre_Value_P0_0xde 0x90 + + +struct reginfo +{ + u8 reg; + u8 val; +}; +///=========sp0838-modify by sp_yjp,20120529================= +/* init 640X480 VGA */ +static struct reginfo sensor_init_data[] = +{ + {0xfd , 0x00}, //P0 + {0x1B , 0x02}, + {0x1C , 0x07}, //add by sp_yjp,bit2: driver ability set(8mA) + + {0x27 , 0xe8}, + {0x28 , 0x0b}, // 0x0B pzt 2012-7-26 + {0x32 , 0x00}, + {0x22 , 0xc0}, + {0x26 , 0x10}, + {0x31 , 0x70},//0x10}, //Upside/mirr/Pclk inv/sub + + {0x5f , 0x11}, //Bayer order + {0xfd , 0x01}, //P1 + {0x25 , 0x1a}, //Awb start + {0x26 , 0xfb}, + {0x28 , 0x75}, + {0x29 , 0x4e}, + {0xfd , 0x00}, + {0xe7 , 0x03}, + {0xe7 , 0x00}, + {0xfd , 0x01}, + + {0x31 , 0x60},//64 + {0x32 , 0x18}, + {0x4d , 0xdc}, + {0x4e , 0x53}, + {0x41 , 0x8c}, + {0x42 , 0x57}, + {0x55 , 0xff}, + {0x56 , 0x00}, + {0x59 , 0x82}, + {0x5a , 0x00}, + {0x5d , 0xff}, + {0x5e , 0x6f}, + {0x57 , 0xff}, + {0x58 , 0x00}, + {0x5b , 0xff}, + {0x5c , 0xa8}, + {0x5f , 0x75}, + {0x60 , 0x00}, + {0x2d , 0x00}, + {0x2e , 0x00}, + {0x2f , 0x00}, + {0x30 , 0x00}, + {0x33 , 0x00}, + {0x34 , 0x00}, + {0x37 , 0x00}, + {0x38 , 0x00}, //awb end + {0xfd , 0x00}, //P0 + {0x33 , 0x6f}, //LSC BPC EN // 0x6f pzt 2012-7-26 + {0x51 , 0x3f}, //BPC debug start + {0x52 , 0x09}, + {0x53 , 0x00}, + {0x54 , 0x00}, + {0x55 , 0x10}, //BPC debug end + {0x4f , 0x08}, //blueedge + {0x50 , 0x08}, + {0x57 , 0x10}, //Raw filter debut start + {0x58 , 0x10}, + {0x59 , 0x10}, + {0x56 , 0x71}, //0x70 modify by sp_yjp,20120613 + {0x5a , 0x05}, //{0x5a , 0x02}, //0x05 modify by sp_yjp,20120613 + {0x5b , 0x06},// {0x5b , 0x02}, //0x05 modify by sp_yjp,20120613 + {0x5c , 0x30}, //Raw filter debut end //0x20 modify by sp_yjp,20120613 + + {0x65 , 0x03}, //Sharpness debug start + {0x66 , 0x01}, // {0x66 , 0x01},sp_wyq + {0x67 , 0x02},// {0x67 , 0x03}, //0x05 //modify by sp_yjp,20120613 + {0x68 , 0x42},// {0x68 , 0x46},//0x46 zch 20120725 + {0x69 , 0x7f}, + {0x6a , 0x01}, + {0x6b , 0x06},//{0x6b , 0x04}, + {0x6c , 0x01}, + {0x6d , 0x02}, //Edge gain normal {0x6d , 0x03}, //0x05 //modify by sp_yjp,20120613 + {0x6e , 0x42}, //Edge gain normal {0x6e , 0x46}, //0x46 zch 20120725 + {0x6f , 0x7f}, + {0x70 , 0x01}, + + {0x71 , 0x09}, //镲拷锟斤拷锟斤拷值 + {0x72 , 0x01}, //锟斤斤拷锟斤拷锟街? + {0x73 , 0x03}, //? //0x05 //modify by sp_yjp,20120613 + {0x74 , 0x43}, //锟//0x47? //modify by sp_yjp,20120613 + + + {0x75 , 0x7f}, //使拷拷位 + {0x76 , 0x01}, //Sharpness debug end + {0xcb , 0x07}, //HEQ&Saturation debug start + {0xcc , 0x04}, + {0xce , 0xff}, + {0xcf , 0x10}, + {0xd0 , 0x20}, + {0xd1 , 0x00}, + {0xd2 , 0x1c}, + {0xd3 , 0x16}, + {0xd4 , 0x00}, + {0xd6 , 0x1c}, + {0xd7 , 0x16}, + {0xdd , 0x70}, //Contrast //0x70 //modify by sp_yjp,20120613 + {0xde , 0x90}, //HEQ&Saturation debug end //0x90 //modify by sp_yjp,20120613 + {0x7f , 0xd7}, //Color Correction start + {0x80 , 0xbc}, + {0x81 , 0xed}, + {0x82 , 0xd7}, + {0x83 , 0xd4}, + {0x84 , 0xd6}, + {0x85 , 0xff}, + {0x86 , 0x89}, + {0x87 , 0xf8}, + {0x88 , 0x3c}, + {0x89 , 0x33}, + {0x8a , 0x0f}, //Color Correction end + {0x8b , 0x00}, //gamma start + {0x8c , 0x1a}, + {0x8d , 0x29}, + {0x8e , 0x41}, + {0x8f , 0x62}, + {0x90 , 0x7c}, + {0x91 , 0x90}, + {0x92 , 0xa2}, + {0x93 , 0xaf}, + {0x94 , 0xbc}, + {0x95 , 0xc5}, + {0x96 , 0xcd}, + {0x97 , 0xd5}, + {0x98 , 0xdd}, + {0x99 , 0xe5}, + {0x9a , 0xed}, + {0x9b , 0xf5}, + {0xfd , 0x01}, //P1 + {0x8d , 0xfd}, + {0x8e , 0xff}, //gamma end + {0xfd , 0x00}, //P0 + {0xca , 0xcf}, + {0xd8 , 0x48}, //UV outdoor + {0xd9 , 0x48}, //UV indoor + {0xda , 0x40}, //UV dummy //0x48 //modify by sp_yjp,20120613 + {0xdb , 0x38}, //UV lowlight //0x48 //modify by sp_yjp,20120613 + {0xb9 , 0x00}, //Ygamma start + {0xba , 0x04}, + {0xbb , 0x08}, + {0xbc , 0x10}, + {0xbd , 0x20}, + {0xbe , 0x30}, + {0xbf , 0x40}, + {0xc0 , 0x50}, + {0xc1 , 0x60}, + {0xc2 , 0x70}, + {0xc3 , 0x80}, + {0xc4 , 0x90}, + {0xc5 , 0xA0}, + {0xc6 , 0xB0}, + {0xc7 , 0xC0}, + {0xc8 , 0xD0}, + {0xc9 , 0xE0}, + {0xfd , 0x01}, //P1 + {0x89 , 0xf0}, + {0x8a , 0xff}, //Ygamma end + {0xfd , 0x00}, //P0 + {0xe8 , 0x30}, //AEdebug start + {0xe9 , 0x30}, + {0xea , 0x40}, //Alc Window sel + {0xf4 , 0x1b}, //outdoor mode sel + {0xf5 , 0x80}, + + ///{0xf7 , 0x78}, //AE target + ///{0xf8 , 0x63}, + ///{0xf9 , 0x68}, //AE target + ///{0xfa , 0x53}, + + {0xf7 , 0x80}, //AE target //modify by sp_yjp,20120613 + {0xf8 , 0x6b}, + {0xf9 , 0x70}, //AE target + {0xfa , 0x5b}, + + {0xfd , 0x01}, //P1 + {0x09 , 0x31}, //AE Step 3.0 + {0x0a , 0x85}, + {0x0b , 0x0b}, //AE Step 3.0 + {0x14 , 0x20}, + {0x15 , 0x0f}, + +/* + #if 0//24M 1div 50HZ 16-8fps //modify by sp_yjp,20120613 + {0xfd , 0x00}, + {0x05 , 0x0 }, + {0x06 , 0x0 }, + {0x09 , 0x2 }, + {0x0a , 0x9d}, + {0xf0 , 0x4f}, + {0xf1 , 0x0 }, + {0xf2 , 0x5b}, + {0xf5 , 0x74}, + {0xfd , 0x01}, + {0x00 , 0xae}, + {0x0f , 0x5c}, + {0x16 , 0x5c}, + {0x17 , 0x9e}, + {0x18 , 0xa6}, + {0x1b , 0x5c}, + {0x1c , 0xa6}, + {0xb4 , 0x21}, + {0xb5 , 0x3b}, + {0xb6 , 0x4b}, + {0xb9 , 0x40}, + {0xba , 0x4f}, + {0xbb , 0x47}, + {0xbc , 0x45}, + {0xbd , 0x43}, + {0xbe , 0x42}, + {0xbf , 0x42}, + {0xc0 , 0x42}, + {0xc1 , 0x41}, + {0xc2 , 0x41}, + {0xc3 , 0x41}, + {0xc4 , 0x41}, + {0xc5 , 0x70}, //0x70 + {0xc6 , 0x41}, + {0xca , 0x70}, //0x70 + {0xcb , 0xc }, + {0xfd , 0x00}, + #else//caprure preview daylight 24M 50hz 20-8FPS maxgain:0x70 + {0xfd , 0x00}, + {0x05 , 0x0 }, + {0x06 , 0x0 }, + {0x09 , 0x1 }, + {0x0a , 0x76}, + {0xf0 , 0x62}, + {0xf1 , 0x0 }, + {0xf2 , 0x5f}, + {0xf5 , 0x78}, + {0xfd , 0x01}, + {0x00 , 0xb2}, + {0x0f , 0x60}, + {0x16 , 0x60}, + {0x17 , 0xa2}, + {0x18 , 0xaa}, + {0x1b , 0x60}, + {0x1c , 0xaa}, + {0xb4 , 0x20}, + {0xb5 , 0x3a}, + {0xb6 , 0x5e}, + {0xb9 , 0x40}, + {0xba , 0x4f}, + {0xbb , 0x47}, + {0xbc , 0x45}, + {0xbd , 0x43}, + {0xbe , 0x42}, + {0xbf , 0x42}, + {0xc0 , 0x42}, + {0xc1 , 0x41}, + {0xc2 , 0x41}, + {0xc3 , 0x41}, + {0xc4 , 0x41}, + {0xc5 , 0x70}, + {0xc6 , 0x41}, + {0xca , 0x70}, + {0xcb , 0xc }, + {0xfd , 0x00}, +#endif +*/ +#if 1//zch 20120725 + //caprure preview daylight 24M 50hz 20-10FPS maxgain:0x70 + {0xfd,0x00}, + {0x05,0x00}, + {0x06,0x00}, + {0x07,0x00}, + {0x08,0x00}, + {0x09,0x01}, + {0x0a,0x76}, + {0xf0,0x62}, + {0xf1,0x00}, + {0xf2,0x5f}, + {0xf5,0x78}, + {0xfd,0x01}, + {0x00,0xae}, + {0x0f,0x60}, + {0x16,0x60}, + {0x17,0x9e}, + {0x18,0xa6}, + {0x1b,0x60}, + {0x1c,0xa6}, + {0xb4,0x20}, + {0xb5,0x3a}, + {0xb6,0x5e}, + {0xb9,0x40}, + {0xba,0x4f}, + {0xbb,0x47}, + {0xbc,0x45}, + {0xbd,0x43}, + {0xbe,0x42}, + {0xbf,0x42}, + {0xc0,0x42}, + {0xc1,0x41}, + {0xc2,0x41}, + {0xc3,0x70}, + {0xc4,0x41}, + {0xc5,0x41}, + {0xc6,0x41}, + {0xca,0x70}, + {0xcb,0x0a}, +#endif + + {0xfd , 0x00}, //P0 + {0x32 , 0x15}, //Auto_mode set + {0x34 , 0x66}, //Isp_mode set + {0x35 , 0x40}, //out format + {0xfd , 0x00}, //P0 + {0xff , 0xff} //out format +}; + + +///=========sp0838-modify by sp_yjp,20120529================= + +/* 1280X1024 SXGA */ +static struct reginfo sensor_sxga[] = +{ + {0xfd, 0x00},{0xff,0xff} +}; + +/* 800X600 SVGA*/ +static struct reginfo sensor_svga[] = +{ + {0xfd, 0x00},{0xff,0xff} +}; + +/* 640X480 VGA */ +static struct reginfo sensor_vga[] = +{ + {0x47, 0x00}, + {0x48, 0x00}, + {0x49, 0x01}, + {0x4a, 0xe0}, //e0 + {0x4b, 0x00}, + {0x4c, 0x00}, + {0x4d, 0x02}, + {0x4e, 0x80}, + {0xfd, 0x00},{0xff,0xff} +}; +///=========sp0838-modify by sp_yjp,20120529================= + +/* 352X288 CIF */ +static struct reginfo sensor_cif[] = +{ + {0xfd, 0x00},{0xff,0xff} +}; + +/* 320*240 QVGA */ +static struct reginfo sensor_qvga[] = +{ + {0xfd, 0x00},{0xff,0xff} +}; + +/* 176X144 QCIF*/ +static struct reginfo sensor_qcif[] = +{ + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_ClrFmt_YUYV[]= +{ + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_ClrFmt_UYVY[]= +{ + {0xfd, 0x00},{0xff,0xff} +}; + +///=========sp0838-modify by sp_yjp,20120529================= + +#if CONFIG_SENSOR_WhiteBalance +static struct reginfo sensor_WhiteB_Auto[]= +{ + //sp0838_reg_WB_auto 锟皆讹拷 + {0xfd, 0x01}, + {0x28, 0x75}, + {0x29, 0x4e}, + {0xfd, 0x00}, // AUTO 3000K~7000K + {0x32, 0x15}, + {0xfd, 0x00},{0xff,0xff} +}; +/* Cloudy Colour Temperature : 6500K - 8000K */ +static struct reginfo sensor_WhiteB_Cloudy[]= +{ + // sp0838_reg_WB_auto 锟斤拷锟斤拷 + {0xfd, 0x00}, + {0x32, 0x05}, + {0xfd, 0x01}, + {0x28, 0x71}, + {0x29, 0x41}, + {0xfd, 0x00},{0xff,0xff} +}; +/* ClearDay Colour Temperature : 5000K - 6500K */ +static struct reginfo sensor_WhiteB_ClearDay[]= +{ + //Sunny + // sp0838_reg_WB_auto 锟斤拷锟斤拷 + {0xfd, 0x00}, + {0x32, 0x05}, + {0xfd, 0x01}, + {0x28, 0x6b}, + {0x29, 0x48}, + {0xfd, 0x00},{0xff,0xff} +}; +/* Office Colour Temperature : 3500K - 5000K */ +static struct reginfo sensor_WhiteB_TungstenLamp1[]= +{ + //Office + //sp0838_reg_WB_auto 荧锟斤拷锟斤拷 + {0xfd, 0x00}, + {0x32, 0x05}, + {0xfd, 0x01}, + {0x28, 0x5a}, + {0x29, 0x62}, + {0xfd, 0x00},{0xff,0xff} + +}; +/* Home Colour Temperature : 2500K - 3500K */ +static struct reginfo sensor_WhiteB_TungstenLamp2[]= +{ + //Home + //sp0838_reg_WB_auto 锟阶筹拷锟斤拷 + {0xfd, 0x00}, + {0x32, 0x05}, + {0xfd, 0x01}, + {0x28, 0x41}, + {0x29, 0x71}, + {0xfd, 0x00},{0xff,0xff} +}; +static struct reginfo *sensor_WhiteBalanceSeqe[] = {sensor_WhiteB_Auto, sensor_WhiteB_TungstenLamp1,sensor_WhiteB_TungstenLamp2, + sensor_WhiteB_ClearDay, sensor_WhiteB_Cloudy,NULL, +}; +#endif + + +///=========sp0838-modify by sp_yjp,20120529================= +#if CONFIG_SENSOR_Brightness +static struct reginfo sensor_Brightness0[]= +{ + // Brightness -2 + {0xfd, 0x00}, + {0xdc, 0xe0}, + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_Brightness1[]= +{ + // Brightness -1 + {0xfd, 0x00}, + {0xdc, 0xf0}, + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_Brightness2[]= +{ + // Brightness 0 + {0xfd, 0x00}, + {0xdc, 0x00}, + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_Brightness3[]= +{ + // Brightness +1 + {0xfd, 0x00}, + {0xdc, 0x10}, + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_Brightness4[]= +{ + // Brightness +2 + {0xfd, 0x00}, + {0xdc, 0x20}, + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_Brightness5[]= +{ + // Brightness +3 + {0xfd, 0x00}, + {0xdc, 0x30}, + {0xfd, 0x00},{0xff,0xff} +}; +static struct reginfo *sensor_BrightnessSeqe[] = {sensor_Brightness0, sensor_Brightness1, sensor_Brightness2, sensor_Brightness3, + sensor_Brightness4, sensor_Brightness5,NULL, +}; + +#endif + +///=========sp0838-modify by sp_yjp,20120529================= +#if CONFIG_SENSOR_Effect +static struct reginfo sensor_Effect_Normal[] = +{ + {0xfd, 0x00}, + {0x62, 0x00}, + {0x63, 0x80}, + {0x64, 0x80}, + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_Effect_WandB[] = +{ + {0xfd, 0x00}, + {0x62, 0x40}, + {0x63, 0x80}, + {0x64, 0x80}, + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_Effect_Sepia[] = +{ + {0xfd, 0x00}, + {0x62, 0x20}, + {0x63, 0xc0}, + {0x64, 0x20}, + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_Effect_Negative[] = +{ + //Negative + {0xfd, 0x00}, + {0x62, 0x10}, + {0x63, 0x80}, + {0x64, 0x80}, + {0xfd, 0x00},{0xff,0xff} +}; +static struct reginfo sensor_Effect_Bluish[] = +{ + // Bluish + {0xfd, 0x00}, + {0x62, 0x20}, + {0x63, 0x20}, + {0x64, 0xf0}, + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_Effect_Green[] = +{ + // Greenish + {0xfd, 0x00}, + {0x62, 0x20}, + {0x63, 0x20}, + {0x64, 0x20}, + {0xfd, 0x00},{0xff,0xff} +}; +static struct reginfo *sensor_EffectSeqe[] = {sensor_Effect_Normal, sensor_Effect_WandB, sensor_Effect_Negative,sensor_Effect_Sepia, + sensor_Effect_Bluish, sensor_Effect_Green,NULL, +}; +#endif + +///=========sp0838-modify by sp_yjp,20120529================= +#if CONFIG_SENSOR_Exposure +static struct reginfo sensor_Exposure0[]= +{ + {0xfd, 0x00}, + {0xdc, 0xd0}, + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_Exposure1[]= +{ + {0xfd, 0x00}, + {0xdc, 0xe0}, + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_Exposure2[]= +{ + {0xfd, 0x00}, + {0xdc, 0xf0}, + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_Exposure3[]= +{ + {0xfd, 0x00}, + {0xdc, 0x00}, + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_Exposure4[]= +{ + {0xfd, 0x00}, + {0xdc, 0x10}, + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_Exposure5[]= +{ + {0xfd, 0x00}, + {0xdc, 0x20}, + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_Exposure6[]= +{ + {0xfd, 0x00}, + {0xdc, 0x30}, + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo *sensor_ExposureSeqe[] = {sensor_Exposure0, sensor_Exposure1, sensor_Exposure2, sensor_Exposure3, + sensor_Exposure4, sensor_Exposure5,sensor_Exposure6,NULL, +}; +#endif + +///=========sp0838-modify by sp_yjp,20120529================= +#if CONFIG_SENSOR_Saturation +static struct reginfo sensor_Saturation0[]= +{ + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_Saturation1[]= +{ + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_Saturation2[]= +{ + {0xfd, 0x00},{0xff,0xff} +}; +static struct reginfo *sensor_SaturationSeqe[] = {sensor_Saturation0, sensor_Saturation1, sensor_Saturation2, NULL,}; + +#endif + +///=========sp0838-modify by sp_yjp,20120529================= +#if CONFIG_SENSOR_Contrast +static struct reginfo sensor_Contrast0[]= +{ + {0xfd, 0x00}, + {0xdd, Pre_Value_P0_0xdd-0x30}, //level -3 + {0xde, Pre_Value_P0_0xde-0x30}, + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_Contrast1[]= +{ + {0xfd, 0x00}, + {0xdd, Pre_Value_P0_0xdd-0x20}, //level -2 + {0xde, Pre_Value_P0_0xde-0x20}, + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_Contrast2[]= +{ + {0xfd, 0x00}, + {0xdd, Pre_Value_P0_0xdd-0x10}, //level -1 + {0xde, Pre_Value_P0_0xde-0x10}, + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_Contrast3[]= +{ + {0xfd, 0x00}, + {0xdd, Pre_Value_P0_0xdd}, //level 0 + {0xde, Pre_Value_P0_0xde}, + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_Contrast4[]= +{ + {0xfd, 0x00}, + {0xdd, Pre_Value_P0_0xdd+0x10}, //level +1 + {0xde, Pre_Value_P0_0xde+0x10}, + {0xfd, 0x00},{0xff,0xff} +}; + + +static struct reginfo sensor_Contrast5[]= +{ + {0xfd, 0x00}, + {0xdd, Pre_Value_P0_0xdd+0x20}, //level +2 + {0xde, Pre_Value_P0_0xde+0x20} + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_Contrast6[]= +{ + {0xfd, 0x00}, + {0xdd, Pre_Value_P0_0xdd+0x30}, //level +-3 + {0xde, Pre_Value_P0_0xde+0x30} + {0xfd, 0x00},{0xff,0xff} +}; + + + + +static struct reginfo *sensor_ContrastSeqe[] = {sensor_Contrast0, sensor_Contrast1, sensor_Contrast2, sensor_Contrast3, + sensor_Contrast4, sensor_Contrast5, sensor_Contrast6, NULL, +}; + +#endif + + +///=========sp0838-modify by sp_yjp,20120529================= +#if CONFIG_SENSOR_Mirror +static struct reginfo sensor_MirrorOn[]= +{ + {0xfd, 0x00}, //page 0 + {0x31, 0x30}, //bit6:flip bit5:mirror bit4:pclk + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_MirrorOff[]= +{ + {0xfd, 0x00}, //page 0 + {0x31, 0x10}, + {0xfd, 0x00},{0xff,0xff} +}; +static struct reginfo *sensor_MirrorSeqe[] = {sensor_MirrorOff, sensor_MirrorOn,NULL,}; +#endif +#if CONFIG_SENSOR_Flip +static struct reginfo sensor_FlipOn[]= +{ + {0xfd, 0x00}, //page 0 + {0x31, 0x50}, + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_FlipOff[]= +{ + {0xfd, 0x00}, //page 0 + {0x31, 0x10}, + {0xfd, 0x00},{0xff,0xff} +}; +static struct reginfo *sensor_FlipSeqe[] = {sensor_FlipOff, sensor_FlipOn,NULL,}; + +#endif + +///=========sp0838-modify by sp_yjp,20120529================= +#if CONFIG_SENSOR_Scene//? zch +static struct reginfo sensor_SceneAuto[] = +{ +#if 0 + //caprure preview daylight 24M 50hz 20-8FPS maxgain:0x70 + {0xfd,0x00}, + {0x05,0x0 }, + {0x06,0x0 }, + {0x07,0x0 }, + {0x08,0x0 }, + {0x09,0x1 }, + {0x0a,0x76}, + {0xf0,0x62}, + {0xf1,0x0 }, + {0xf2,0x5f}, + {0xf5,0x78}, + {0xfd,0x01}, + {0x00,0xb2}, + {0x0f,0x60}, + {0x16,0x60}, + {0x17,0xa2}, + {0x18,0xaa}, + {0x1b,0x60}, + {0x1c,0xaa}, + {0xb4,0x20}, + {0xb5,0x3a}, + {0xb6,0x5e}, + {0xb9,0x40}, + {0xba,0x4f}, + {0xbb,0x47}, + {0xbc,0x45}, + {0xbd,0x43}, + {0xbe,0x42}, + {0xbf,0x42}, + {0xc0,0x42}, + {0xc1,0x41}, + {0xc2,0x41}, + {0xc3,0x41}, + {0xc4,0x41}, + {0xc5,0x70}, + {0xc6,0x41}, + {0xca,0x70}, + {0xcb,0xc }, + {0x14,0x20}, + {0x15,0x0f}, + {0xfd,0x00}, + {0xff,0xff} +#endif + + +#if 1 +//caprure preview daylight 24M 50hz 20-10FPS maxgain:0x70 +{0xfd,0x00}, +{0x05,0x00}, +{0x06,0x00}, +{0x07,0x00}, +{0x08,0x00}, +{0x09,0x01}, +{0x0a,0x76}, +{0xf0,0x62}, +{0xf1,0x00}, +{0xf2,0x5f}, +{0xf5,0x78}, +{0xfd,0x01}, +{0x00,0xae}, +{0x0f,0x60}, +{0x16,0x60}, +{0x17,0x9e}, +{0x18,0xa6}, +{0x1b,0x60}, +{0x1c,0xa6}, +{0xb4,0x20}, +{0xb5,0x3a}, +{0xb6,0x5e}, +{0xb9,0x40}, +{0xba,0x4f}, +{0xbb,0x47}, +{0xbc,0x45}, +{0xbd,0x43}, +{0xbe,0x42}, +{0xbf,0x42}, +{0xc0,0x42}, +{0xc1,0x41}, +{0xc2,0x41}, +{0xc3,0x70}, +{0xc4,0x41}, +{0xc5,0x41}, +{0xc6,0x41}, +{0xca,0x70}, +{0xcb,0x0a}, +{0x14,0x20}, +{0x15,0x0f}, +{0xfd,0x00}, +{0xff,0xff} +#endif +}; + +static struct reginfo sensor_SceneNight[] = +{ + //caprure preview night 24M 50hz 20-6FPS maxgain:0x78 + {0xfd,0x00}, + {0x05,0x0 }, + {0x06,0x0 }, + {0x09,0x1 }, + {0x0a,0x76}, + {0xf0,0x62}, + {0xf1,0x0 }, + {0xf2,0x5f}, + {0xf5,0x78}, + {0xfd,0x01}, + {0x00,0xc0}, + {0x0f,0x60}, + {0x16,0x60}, + {0x17,0xa8}, + {0x18,0xb0}, + {0x1b,0x60}, + {0x1c,0xb0}, + {0xb4,0x20}, + {0xb5,0x3a}, + {0xb6,0x5e}, + {0xb9,0x40}, + {0xba,0x4f}, + {0xbb,0x47}, + {0xbc,0x45}, + {0xbd,0x43}, + {0xbe,0x42}, + {0xbf,0x42}, + {0xc0,0x42}, + {0xc1,0x41}, + {0xc2,0x41}, + {0xc3,0x41}, + {0xc4,0x41}, + {0xc5,0x41}, + {0xc6,0x41}, + {0xca,0x78}, + {0xcb,0x10}, + {0x14,0x20}, + {0x15,0x1f}, + {0xfd,0x00}, + {0xff,0xff} +}; + + + +static struct reginfo *sensor_SceneSeqe[] = {sensor_SceneAuto, sensor_SceneNight,NULL,}; + +#endif + +///=========sp0838-modify by sp_yjp,20120529================= +#if CONFIG_SENSOR_DigitalZoom +static struct reginfo sensor_Zoom0[] = +{ + {0xfd,0x00}, + {0xff,0xff} +}; + +static struct reginfo sensor_Zoom1[] = +{ + {0xfd,0x00}, + {0xff,0xff} +}; + +static struct reginfo sensor_Zoom2[] = +{ + {0xfd,0x00}, + {0xff,0xff} +}; + + +static struct reginfo sensor_Zoom3[] = +{ + {0xfd,0x00}, + {0xff,0xff} +}; +static struct reginfo *sensor_ZoomSeqe[] = {sensor_Zoom0, sensor_Zoom1, sensor_Zoom2, sensor_Zoom3, NULL,}; +#endif + + +///=========sp0838-modify by sp_yjp,20120529================= +static const struct v4l2_querymenu sensor_menus[] = +{ + #if CONFIG_SENSOR_WhiteBalance + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 0, .name = "auto", .reserved = 0, }, { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 1, .name = "incandescent", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 2, .name = "fluorescent", .reserved = 0,}, { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 3, .name = "daylight", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 4, .name = "cloudy-daylight", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Effect + { .id = V4L2_CID_EFFECT, .index = 0, .name = "none", .reserved = 0, }, { .id = V4L2_CID_EFFECT, .index = 1, .name = "mono", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 2, .name = "negative", .reserved = 0,}, { .id = V4L2_CID_EFFECT, .index = 3, .name = "sepia", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 4, .name = "posterize", .reserved = 0,} ,{ .id = V4L2_CID_EFFECT, .index = 5, .name = "aqua", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Scene + { .id = V4L2_CID_SCENE, .index = 0, .name = "auto", .reserved = 0,} ,{ .id = V4L2_CID_SCENE, .index = 1, .name = "night", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Flash + { .id = V4L2_CID_FLASH, .index = 0, .name = "off", .reserved = 0, }, { .id = V4L2_CID_FLASH, .index = 1, .name = "auto", .reserved = 0,}, + { .id = V4L2_CID_FLASH, .index = 2, .name = "on", .reserved = 0,}, { .id = V4L2_CID_FLASH, .index = 3, .name = "torch", .reserved = 0,}, + #endif +}; + +static const struct v4l2_queryctrl sensor_controls[] = +{ + #if CONFIG_SENSOR_WhiteBalance + { + .id = V4L2_CID_DO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "White Balance Control", + .minimum = 0, + .maximum = 4, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Brightness + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness Control", + .minimum = -3, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Effect + { + .id = V4L2_CID_EFFECT, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Effect Control", + .minimum = 0, + .maximum = 5, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Exposure + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure Control", + .minimum = 0, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Saturation + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation Control", + .minimum = 0, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Contrast + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast Control", + .minimum = -3, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Mirror + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + #endif + + #if CONFIG_SENSOR_Flip + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + #endif + + #if CONFIG_SENSOR_Scene + { + .id = V4L2_CID_SCENE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Scene Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_DigitalZoom + { + .id = V4L2_CID_ZOOM_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DigitalZoom Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_ZOOM_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DigitalZoom Control", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Focus + { + .id = V4L2_CID_FOCUS_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Focus Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_FOCUS_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Focus Control", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 125, + }, + #endif + + #if CONFIG_SENSOR_Flash + { + .id = V4L2_CID_FLASH, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Flash Control", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif +}; + +static int sensor_probe(struct i2c_client *client, const struct i2c_device_id *did); +static int sensor_video_probe(struct soc_camera_device *icd, struct i2c_client *client); +static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl); +static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl); +static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg); +static int sensor_resume(struct soc_camera_device *icd); +static int sensor_set_bus_param(struct soc_camera_device *icd,unsigned long flags); +static unsigned long sensor_query_bus_param(struct soc_camera_device *icd); +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +static int sensor_deactivate(struct i2c_client *client); + +static struct soc_camera_ops sensor_ops = +{ + .suspend = sensor_suspend, + .resume = sensor_resume, + .set_bus_param = sensor_set_bus_param, + .query_bus_param = sensor_query_bus_param, + .controls = sensor_controls, + .menus = sensor_menus, + .num_controls = ARRAY_SIZE(sensor_controls), + .num_menus = ARRAY_SIZE(sensor_menus), +}; + +/* only one fixed colorspace per pixelcode */ +struct sensor_datafmt { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; +}; + +/* Find a data format by a pixel code in an array */ +static const struct sensor_datafmt *sensor_find_datafmt( + enum v4l2_mbus_pixelcode code, const struct sensor_datafmt *fmt, + int n) +{ + int i; + for (i = 0; i < n; i++) + if (fmt[i].code == code) + return fmt + i; + + return NULL; +} + +static const struct sensor_datafmt sensor_colour_fmts[] = { + {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG} +}; + +typedef struct sensor_info_priv_s +{ + int whiteBalance; + int brightness; + int contrast; + int saturation; + int effect; + int scene; + int digitalzoom; + int focus; + int flash; + int exposure; + bool snap2preview; + bool video2preview; + unsigned char mirror; /* HFLIP */ + unsigned char flip; /* VFLIP */ + unsigned int winseqe_cur_addr; + struct sensor_datafmt fmt; + unsigned int funmodule_state; +} sensor_info_priv_t; + +struct sensor +{ + struct v4l2_subdev subdev; + struct i2c_client *client; + sensor_info_priv_t info_priv; + int model; /* V4L2_IDENT_OV* codes from v4l2-chip-ident.h */ +#if CONFIG_SENSOR_I2C_NOSCHED + atomic_t tasklock_cnt; +#endif + struct rk29camera_platform_data *sensor_io_request; + struct rk29camera_gpio_res *sensor_gpio_res; +}; + +static struct sensor* to_sensor(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct sensor, subdev); +} + +static int sensor_task_lock(struct i2c_client *client, int lock) +{ +#if CONFIG_SENSOR_I2C_NOSCHED + int cnt = 3; + struct sensor *sensor = to_sensor(client); + + if (lock) { + if (atomic_read(&sensor->tasklock_cnt) == 0) { + while ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt>0)) { + SENSOR_TR("\n %s will obtain i2c in atomic, but i2c bus is locked! Wait...\n",SENSOR_NAME_STRING()); + msleep(35); + cnt--; + } + if ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt<=0)) { + SENSOR_TR("\n %s obtain i2c fail in atomic!!\n",SENSOR_NAME_STRING()); + goto sensor_task_lock_err; + } + preempt_disable(); + } + + atomic_add(1, &sensor->tasklock_cnt); + } else { + if (atomic_read(&sensor->tasklock_cnt) > 0) { + atomic_sub(1, &sensor->tasklock_cnt); + + if (atomic_read(&sensor->tasklock_cnt) == 0) + preempt_enable(); + } + } + return 0; +sensor_task_lock_err: + return -1; +#else + return 0; +#endif + +} + +/* sensor register write */ +static int sensor_write(struct i2c_client *client, u8 reg, u8 val) +{ + int err,cnt; + u8 buf[2]; + struct i2c_msg msg[1]; + + buf[0] = reg & 0xFF; + buf[1] = val; + + msg->addr = client->addr; + msg->flags = client->flags; + msg->buf = buf; + msg->len = sizeof(buf); + msg->scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg->read_type = 0; /* fpga i2c:0==I2C_NORMAL : direct use number not enum for don't want include spi_fpga.h */ + + cnt = 3; + err = -EAGAIN; + + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + err = i2c_transfer(client->adapter, msg, 1); + + if (err >= 0) { + return 0; + } else { + SENSOR_TR("\n %s write reg(0x%x, val:0x%x) failed, try to write again!\n",SENSOR_NAME_STRING(),reg, val); + udelay(10); + } + } + + return err; +} + +/* sensor register read */ +static int sensor_read(struct i2c_client *client, u8 reg, u8 *val) +{ + int err,cnt; + //u8 buf[2]; + u8 buf[1]; + struct i2c_msg msg[2]; + + //buf[0] = reg >> 8; + buf[0] = reg; + buf[1] = reg & 0xFF; + + msg[0].addr = client->addr; + msg[0].flags = client->flags; + msg[0].buf = buf; + msg[0].len = sizeof(buf); + msg[0].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg[0].read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */ + + msg[1].addr = client->addr; + msg[1].flags = client->flags|I2C_M_RD; + msg[1].buf = buf; + msg[1].len = 1; + msg[1].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg[1].read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */ + + cnt = 1; + err = -EAGAIN; + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + err = i2c_transfer(client->adapter, msg, 2); + + if (err >= 0) { + *val = buf[0]; + return 0; + } else { + SENSOR_TR("\n %s read reg(0x%x val:0x%x) failed, try to read again! \n",SENSOR_NAME_STRING(),reg, *val); + udelay(10); + } + } + + return err; +} + +/* write a array of registers */ +#if 1 +static int sensor_write_array(struct i2c_client *client, struct reginfo *regarray) +{ + int err; + int i = 0; + + //for(i=0; i < sizeof(sensor_init_data) / 2;i++) + while((regarray[i].reg != 0xff) || (regarray[i].val != 0xff)) + { + err = sensor_write(client, regarray[i].reg, regarray[i].val); + if (err != 0) + { + SENSOR_TR("%s..write failed current i = %d\n", SENSOR_NAME_STRING(),i); + return err; + } + i++; + } + + return 0; +} +#else +static int sensor_write_array(struct i2c_client *client, struct reginfo *regarray) +{ + int err; + int i = 0; + u8 val_read; + while (regarray[i].reg != 0) + { + err = sensor_write(client, regarray[i].reg, regarray[i].val); + if (err != 0) + { + SENSOR_TR("%s..write failed current i = %d\n", SENSOR_NAME_STRING(),i); + return err; + } + err = sensor_read(client, regarray[i].reg, &val_read); + SENSOR_TR("%s..reg[0x%x]=0x%x,0x%x\n", SENSOR_NAME_STRING(),regarray[i].reg, val_read, regarray[i].val); + i++; + } + return 0; +} +#endif + +#if CONFIG_SENSOR_I2C_RDWRCHK +static int sensor_check_array(struct i2c_client *client, struct reginfo *regarray) +{ + int ret; + int i = 0; + + u8 value; + + SENSOR_DG("%s >>>>>>>>>>>>>>>>>>>>>>\n",__FUNCTION__); + for(i=0;ipowerdown) { + ret = icl->powerdown(icd->pdev, on); + if (ret == RK29_CAM_IO_SUCCESS) { + if (on == 0) { + mdelay(2); + if (icl->reset) + icl->reset(icd->pdev); + } + } else if (ret == RK29_CAM_EIO_REQUESTFAIL) { + ret = -ENODEV; + goto sensor_power_end; + } + } + break; + } + case Sensor_Flash: + { + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + if (sensor->sensor_io_request && sensor->sensor_io_request->sensor_ioctrl) { + sensor->sensor_io_request->sensor_ioctrl(icd->pdev,Cam_Flash, on); + } + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown!",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } +sensor_power_end: + return ret; +} + +static int sensor_init(struct v4l2_subdev *sd, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + const struct sensor_datafmt *fmt; + int ret; + + SENSOR_DG("\n%s..%s.. \n",SENSOR_NAME_STRING(),__FUNCTION__); + + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + /* soft reset */ + if (sensor_task_lock(client,1)<0) + goto sensor_INIT_ERR; + /* ret = sensor_write(client, 0x12, 0x80); + if (ret != 0) + { + SENSOR_TR("%s soft reset sensor failed\n",SENSOR_NAME_STRING()); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + mdelay(5); */ //delay 5 microseconds + + ret = sensor_write_array(client, sensor_init_data); + if (ret != 0) + { + SENSOR_TR("error: %s initial failed\n",SENSOR_NAME_STRING()); + goto sensor_INIT_ERR; + } + + sensor_task_lock(client,0); + + sensor->info_priv.winseqe_cur_addr = (int)SENSOR_INIT_WINSEQADR; + fmt = sensor_find_datafmt(SENSOR_INIT_PIXFMT,sensor_colour_fmts, ARRAY_SIZE(sensor_colour_fmts)); + if (!fmt) { + SENSOR_TR("error: %s initial array colour fmts is not support!!",SENSOR_NAME_STRING()); + ret = -EINVAL; + goto sensor_INIT_ERR; + } + sensor->info_priv.fmt = *fmt; + + /* sensor sensor information for initialization */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + if (qctrl) + sensor->info_priv.whiteBalance = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_BRIGHTNESS); + if (qctrl) + sensor->info_priv.brightness = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + if (qctrl) + sensor->info_priv.effect = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EXPOSURE); + if (qctrl) + sensor->info_priv.exposure = qctrl->default_value; + + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SATURATION); + if (qctrl) + sensor->info_priv.saturation = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_CONTRAST); + if (qctrl) + sensor->info_priv.contrast = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_HFLIP); + if (qctrl) + sensor->info_priv.mirror = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_VFLIP); + if (qctrl) + sensor->info_priv.flip = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SCENE); + if (qctrl) + sensor->info_priv.scene = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE); + if (qctrl) + sensor->info_priv.digitalzoom = qctrl->default_value; + + /* ddl@rock-chips.com : if sensor support auto focus and flash, programer must run focus and flash code */ + #if CONFIG_SENSOR_Focus + sensor_set_focus(); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FOCUS_ABSOLUTE); + if (qctrl) + sensor->info_priv.focus = qctrl->default_value; + #endif + + #if CONFIG_SENSOR_Flash + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FLASH); + if (qctrl) + sensor->info_priv.flash = qctrl->default_value; + #endif + + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),((val == 0)?__FUNCTION__:"sensor_reinit"),icd->user_width,icd->user_height); + sensor->info_priv.funmodule_state |= SENSOR_INIT_IS_OK; + return 0; +sensor_INIT_ERR: + sensor->info_priv.funmodule_state &= ~SENSOR_INIT_IS_OK; + sensor_task_lock(client,0); + sensor_deactivate(client); + return ret; +} + +static int sensor_deactivate(struct i2c_client *client) +{ + struct soc_camera_device *icd = client->dev.platform_data; + //u8 reg_val; + struct sensor *sensor = to_sensor(client); + SENSOR_DG("\n%s..%s.. Enter\n",SENSOR_NAME_STRING(),__FUNCTION__); + + /* ddl@rock-chips.com : all sensor output pin must change to input for other sensor */ + sensor_ioctrl(icd, Sensor_PowerDown, 1); + msleep(100); + + /* ddl@rock-chips.com : sensor config init width , because next open sensor quickly(soc_camera_open -> Try to configure with default parameters) */ + icd->user_width = SENSOR_INIT_WIDTH; + icd->user_height = SENSOR_INIT_HEIGHT; + sensor->info_priv.funmodule_state &= ~SENSOR_INIT_IS_OK; + + return 0; +} +static struct reginfo sensor_power_down_sequence[]= +{ + {0xfd,0x00},{0xff,0xff} +}; +static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg) +{ + int ret; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if (pm_msg.event == PM_EVENT_SUSPEND) { + SENSOR_DG("\n %s Enter Suspend.. \n", SENSOR_NAME_STRING()); + ret = sensor_write_array(client, sensor_power_down_sequence) ; + if (ret != 0) { + SENSOR_TR("\n %s..%s WriteReg Fail.. \n", SENSOR_NAME_STRING(),__FUNCTION__); + return ret; + } else { + ret = sensor_ioctrl(icd, Sensor_PowerDown, 1); + if (ret < 0) { + SENSOR_TR("\n %s suspend fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + } + } else { + SENSOR_TR("\n %s cann't suppout Suspend..\n",SENSOR_NAME_STRING()); + return -EINVAL; + } + return 0; +} + +static int sensor_resume(struct soc_camera_device *icd) +{ + int ret; + + ret = sensor_ioctrl(icd, Sensor_PowerDown, 0); + if (ret < 0) { + SENSOR_TR("\n %s resume fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + + SENSOR_DG("\n %s Enter Resume.. \n", SENSOR_NAME_STRING()); + + return 0; + +} + +static int sensor_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + + return 0; +} + +static unsigned long sensor_query_bus_param(struct soc_camera_device *icd) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + unsigned long flags = SENSOR_BUS_PARAM; + + return soc_camera_apply_sensor_flags(icl, flags); +} + +static int sensor_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + + mf->width = icd->user_width; + mf->height = icd->user_height; + mf->code = sensor->info_priv.fmt.code; + mf->colorspace = sensor->info_priv.fmt.colorspace; + mf->field = V4L2_FIELD_NONE; + + return 0; +} +static bool sensor_fmt_capturechk(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + bool ret = false; + + if ((mf->width == 1024) && (mf->height == 768)) { + ret = true; + } else if ((mf->width == 1280) && (mf->height == 1024)) { + ret = true; + } else if ((mf->width == 1600) && (mf->height == 1200)) { + ret = true; + } else if ((mf->width == 2048) && (mf->height == 1536)) { + ret = true; + } else if ((mf->width == 2592) && (mf->height == 1944)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is capture format\n", __FUNCTION__, mf->width, mf->height); + return ret; +} + +static bool sensor_fmt_videochk(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + bool ret = false; + + if ((mf->width == 1280) && (mf->height == 720)) { + ret = true; + } else if ((mf->width == 1920) && (mf->height == 1080)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is video format\n", __FUNCTION__, mf->width, mf->height); + return ret; +} +static int sensor_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + const struct sensor_datafmt *fmt; + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + struct soc_camera_device *icd = client->dev.platform_data; + struct reginfo *winseqe_set_addr=NULL; + int ret=0, set_w,set_h; + + fmt = sensor_find_datafmt(mf->code, sensor_colour_fmts, + ARRAY_SIZE(sensor_colour_fmts)); + if (!fmt) { + ret = -EINVAL; + goto sensor_s_fmt_end; + } + + if (sensor->info_priv.fmt.code != mf->code) { + switch (mf->code) + { + case V4L2_MBUS_FMT_YUYV8_2X8: + { + winseqe_set_addr = sensor_ClrFmt_YUYV; + break; + } + case V4L2_MBUS_FMT_UYVY8_2X8: + { + winseqe_set_addr = sensor_ClrFmt_UYVY; + break; + } + default: + break; + } + if (winseqe_set_addr != NULL) { + sensor_write_array(client, winseqe_set_addr); + sensor->info_priv.fmt.code = mf->code; + sensor->info_priv.fmt.colorspace= mf->colorspace; + SENSOR_DG("%s v4l2_mbus_code:%d set success!\n", SENSOR_NAME_STRING(),mf->code); + } else { + SENSOR_TR("%s v4l2_mbus_code:%d is invalidate!\n", SENSOR_NAME_STRING(),mf->code); + } + } + + set_w = mf->width; + set_h = mf->height; + + if (((set_w <= 176) && (set_h <= 144)) && sensor_qcif[0].reg) + { + winseqe_set_addr = sensor_qcif; + set_w = 176; + set_h = 144; + } + else if (((set_w <= 320) && (set_h <= 240)) && sensor_qvga[0].reg) + { + winseqe_set_addr = sensor_qvga; + set_w = 320; + set_h = 240; + } + else if (((set_w <= 352) && (set_h<= 288)) && sensor_cif[0].reg) + { + winseqe_set_addr = sensor_cif; + set_w = 352; + set_h = 288; + } + else if (((set_w <= 640) && (set_h <= 480)) && sensor_vga[0].reg) + { + winseqe_set_addr = sensor_vga; + set_w = 640-16; + set_h = 480-16; + } + else if (((set_w <= 800) && (set_h <= 600)) && sensor_svga[0].reg) + { + winseqe_set_addr = sensor_svga; + set_w = 800; + set_h = 600; + } + else if (((set_w <= 1280) && (set_h <= 1024)) && sensor_sxga[0].reg) + { + winseqe_set_addr = sensor_sxga; + set_w = 1280; + set_h = 1024; + } + else + { + winseqe_set_addr = SENSOR_INIT_WINSEQADR; /* ddl@rock-chips.com : Sensor output smallest size if isn't support app */ + set_w = SENSOR_INIT_WIDTH; + set_h = SENSOR_INIT_HEIGHT; + SENSOR_TR("\n %s..%s Format is Invalidate. pix->width = %d.. pix->height = %d\n",SENSOR_NAME_STRING(),__FUNCTION__,mf->width,mf->height); + } + + if ((int)winseqe_set_addr != sensor->info_priv.winseqe_cur_addr) { + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,mf) == true) { /* ddl@rock-chips.com : Capture */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_On); + SENSOR_DG("%s flash on in capture!\n", SENSOR_NAME_STRING()); + } + } else { /* ddl@rock-chips.com : Video */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_DG("%s flash off in preivew!\n", SENSOR_NAME_STRING()); + } + } + #endif + ret |= sensor_write_array(client, winseqe_set_addr); + if (ret != 0) { + SENSOR_TR("%s set format capability failed\n", SENSOR_NAME_STRING()); + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,mf) == true) { + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_TR("%s Capture format set fail, flash off !\n", SENSOR_NAME_STRING()); + } + } + #endif + goto sensor_s_fmt_end; + } + + sensor->info_priv.winseqe_cur_addr = (int)winseqe_set_addr; + + if (sensor_fmt_capturechk(sd,mf) == true) { /* ddl@rock-chips.com : Capture */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + if (sensor->info_priv.whiteBalance != 0) { + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + } + sensor->info_priv.snap2preview = true; + } else if (sensor_fmt_videochk(sd,mf) == true) { /* ddl@rock-chips.com : Video */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + sensor->info_priv.video2preview = true; + } else if ((sensor->info_priv.snap2preview == true) || (sensor->info_priv.video2preview == true)) { + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + msleep(600); + sensor->info_priv.video2preview = false; + sensor->info_priv.snap2preview = false; + } + + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),__FUNCTION__,set_w,set_h); + } + else + { + SENSOR_DG("\n %s .. Current Format is validate. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),set_w,set_h); + } + + mf->width = set_w; + mf->height = set_h; + +sensor_s_fmt_end: + return ret; +} + +static int sensor_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd) +; + struct sensor *sensor = to_sensor(client); + const struct sensor_datafmt *fmt; + int ret = 0; + + fmt = sensor_find_datafmt(mf->code, sensor_colour_fmts, + ARRAY_SIZE(sensor_colour_fmts)); + if (fmt == NULL) { + fmt = &sensor->info_priv.fmt; + mf->code = fmt->code; + } + + if (mf->height > SENSOR_MAX_HEIGHT) + mf->height = SENSOR_MAX_HEIGHT; + else if (mf->height < SENSOR_MIN_HEIGHT) + mf->height = SENSOR_MIN_HEIGHT; + + if (mf->width > SENSOR_MAX_WIDTH) + mf->width = SENSOR_MAX_WIDTH; + else if (mf->width < SENSOR_MIN_WIDTH) + mf->width = SENSOR_MIN_WIDTH; + + mf->colorspace = fmt->colorspace; + + return ret; +} + + static int sensor_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *id) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) + return -EINVAL; + + if (id->match.addr != client->addr) + return -ENODEV; + + id->ident = SENSOR_V4L2_IDENT; /* ddl@rock-chips.com : Return OV9650 identifier */ + id->revision = 0; + + return 0; +} +#if CONFIG_SENSOR_Brightness +static int sensor_set_brightness(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_BrightnessSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_BrightnessSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Effect +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_EffectSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_EffectSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Exposure +static int sensor_set_exposure(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_ExposureSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_ExposureSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Saturation +static int sensor_set_saturation(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_SaturationSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_SaturationSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Contrast +static int sensor_set_contrast(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_ContrastSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_ContrastSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Mirror +static int sensor_set_mirror(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_MirrorSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_MirrorSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Flip +static int sensor_set_flip(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_FlipSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_FlipSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Scene +static int sensor_set_scene(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_SceneSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_SceneSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_WhiteBalance +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_WhiteBalanceSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_WhiteBalanceSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_DigitalZoom +static int sensor_set_digitalzoom(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int *value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl_info; + int digitalzoom_cur, digitalzoom_total; + + qctrl_info = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE); + if (qctrl_info) + return -EINVAL; + + digitalzoom_cur = sensor->info_priv.digitalzoom; + digitalzoom_total = qctrl_info->maximum; + + if ((*value > 0) && (digitalzoom_cur >= digitalzoom_total)) + { + SENSOR_TR("%s digitalzoom is maximum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur); + return -EINVAL; + } + + if ((*value < 0) && (digitalzoom_cur <= qctrl_info->minimum)) + { + SENSOR_TR("%s digitalzoom is minimum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur); + return -EINVAL; + } + + if ((*value > 0) && ((digitalzoom_cur + *value) > digitalzoom_total)) + { + *value = digitalzoom_total - digitalzoom_cur; + } + + if ((*value < 0) && ((digitalzoom_cur + *value) < 0)) + { + *value = 0 - digitalzoom_cur; + } + + digitalzoom_cur += *value; + + if (sensor_ZoomSeqe[digitalzoom_cur] != NULL) + { + if (sensor_write_array(client, sensor_ZoomSeqe[digitalzoom_cur]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, *value); + return 0; + } + + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Flash +static int sensor_set_flash(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) { + if (value == 3) { /* ddl@rock-chips.com: torch */ + sensor_ioctrl(icd, Sensor_Flash, Flash_Torch); /* Flash On */ + } else { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif + +static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + + qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + return -EINVAL; + } + + switch (ctrl->id) + { + case V4L2_CID_BRIGHTNESS: + { + ctrl->value = sensor->info_priv.brightness; + break; + } + case V4L2_CID_SATURATION: + { + ctrl->value = sensor->info_priv.saturation; + break; + } + case V4L2_CID_CONTRAST: + { + ctrl->value = sensor->info_priv.contrast; + break; + } + case V4L2_CID_DO_WHITE_BALANCE: + { + ctrl->value = sensor->info_priv.whiteBalance; + break; + } + case V4L2_CID_EXPOSURE: + { + ctrl->value = sensor->info_priv.exposure; + break; + } + case V4L2_CID_HFLIP: + { + ctrl->value = sensor->info_priv.mirror; + break; + } + case V4L2_CID_VFLIP: + { + ctrl->value = sensor->info_priv.flip; + break; + } + default : + break; + } + return 0; +} + + + +static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct sensor *sensor = to_sensor(client); + struct soc_camera_device *icd = client->dev.platform_data; + const struct v4l2_queryctrl *qctrl; + + + qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + return -EINVAL; + } + + switch (ctrl->id) + { +#if CONFIG_SENSOR_Brightness + case V4L2_CID_BRIGHTNESS: + { + if (ctrl->value != sensor->info_priv.brightness) + { + if (sensor_set_brightness(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.brightness = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Exposure + case V4L2_CID_EXPOSURE: + { + if (ctrl->value != sensor->info_priv.exposure) + { + if (sensor_set_exposure(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.exposure = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Saturation + case V4L2_CID_SATURATION: + { + if (ctrl->value != sensor->info_priv.saturation) + { + if (sensor_set_saturation(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.saturation = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Contrast + case V4L2_CID_CONTRAST: + { + if (ctrl->value != sensor->info_priv.contrast) + { + if (sensor_set_contrast(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.contrast = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_WhiteBalance + case V4L2_CID_DO_WHITE_BALANCE: + { + if (ctrl->value != sensor->info_priv.whiteBalance) + { + if (sensor_set_whiteBalance(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.whiteBalance = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Mirror + case V4L2_CID_HFLIP: + { + if (ctrl->value != sensor->info_priv.mirror) + { + if (sensor_set_mirror(icd, qctrl,ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.mirror = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Flip + case V4L2_CID_VFLIP: + { + if (ctrl->value != sensor->info_priv.flip) + { + if (sensor_set_flip(icd, qctrl,ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.flip = ctrl->value; + } + break; + } +#endif + default: + break; + } + + return 0; +} +static int sensor_g_ext_control(struct soc_camera_device *icd , struct v4l2_ext_control *ext_ctrl) +{ + const struct v4l2_queryctrl *qctrl; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + return -EINVAL; + } + + switch (ext_ctrl->id) + { + case V4L2_CID_SCENE: + { + ext_ctrl->value = sensor->info_priv.scene; + break; + } + case V4L2_CID_EFFECT: + { + ext_ctrl->value = sensor->info_priv.effect; + break; + } + case V4L2_CID_ZOOM_ABSOLUTE: + { + ext_ctrl->value = sensor->info_priv.digitalzoom; + break; + } + case V4L2_CID_ZOOM_RELATIVE: + { + return -EINVAL; + } + case V4L2_CID_FOCUS_ABSOLUTE: + { + ext_ctrl->value = sensor->info_priv.focus; + break; + } + case V4L2_CID_FOCUS_RELATIVE: + { + return -EINVAL; + } + case V4L2_CID_FLASH: + { + ext_ctrl->value = sensor->info_priv.flash; + break; + } + default : + break; + } + return 0; +} +static int sensor_s_ext_control(struct soc_camera_device *icd, struct v4l2_ext_control *ext_ctrl) +{ + const struct v4l2_queryctrl *qctrl; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + int val_offset; + + qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + return -EINVAL; + } + + val_offset = 0; + switch (ext_ctrl->id) + { +#if CONFIG_SENSOR_Scene + case V4L2_CID_SCENE: + { + if (ext_ctrl->value != sensor->info_priv.scene) + { + if (sensor_set_scene(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.scene = ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Effect + case V4L2_CID_EFFECT: + { + if (ext_ctrl->value != sensor->info_priv.effect) + { + if (sensor_set_effect(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.effect= ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_DigitalZoom + case V4L2_CID_ZOOM_ABSOLUTE: + { + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; + + if (ext_ctrl->value != sensor->info_priv.digitalzoom) + { + val_offset = ext_ctrl->value -sensor->info_priv.digitalzoom; + + if (sensor_set_digitalzoom(icd, qctrl,&val_offset) != 0) + return -EINVAL; + sensor->info_priv.digitalzoom += val_offset; + + SENSOR_DG("%s digitalzoom is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.digitalzoom); + } + + break; + } + case V4L2_CID_ZOOM_RELATIVE: + { + if (ext_ctrl->value) + { + if (sensor_set_digitalzoom(icd, qctrl,&ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.digitalzoom += ext_ctrl->value; + + SENSOR_DG("%s digitalzoom is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.digitalzoom); + } + break; + } +#endif +#if CONFIG_SENSOR_Focus + case V4L2_CID_FOCUS_ABSOLUTE: + { + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; + + if (ext_ctrl->value != sensor->info_priv.focus) + { + val_offset = ext_ctrl->value -sensor->info_priv.focus; + + sensor->info_priv.focus += val_offset; + } + + break; + } + case V4L2_CID_FOCUS_RELATIVE: + { + if (ext_ctrl->value) + { + sensor->info_priv.focus += ext_ctrl->value; + + SENSOR_DG("%s focus is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.focus); + } + break; + } +#endif +#if CONFIG_SENSOR_Flash + case V4L2_CID_FLASH: + { + if (sensor_set_flash(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.flash = ext_ctrl->value; + + SENSOR_DG("%s flash is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.flash); + break; + } +#endif + default: + break; + } + + return 0; +} + +static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + int i, error_cnt=0, error_idx=-1; + + + for (i=0; icount; i++) { + if (sensor_g_ext_control(icd, &ext_ctrl->controls[i]) != 0) { + error_cnt++; + error_idx = i; + } + } + + if (error_cnt > 1) + error_idx = ext_ctrl->count; + + if (error_idx != -1) { + ext_ctrl->error_idx = error_idx; + return -EINVAL; + } else { + return 0; + } +} + +static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + int i, error_cnt=0, error_idx=-1; + + + for (i=0; icount; i++) { + if (sensor_s_ext_control(icd, &ext_ctrl->controls[i]) != 0) { + error_cnt++; + error_idx = i; + } + } + + if (error_cnt > 1) + error_idx = ext_ctrl->count; + + if (error_idx != -1) { + ext_ctrl->error_idx = error_idx; + return -EINVAL; + } else { + return 0; + } +} + +/* Interface active, can use i2c. If it fails, it can indeed mean, that + * this wasn't our capture interface, so, we wait for the right one */ +static int sensor_video_probe(struct soc_camera_device *icd, + struct i2c_client *client) +{ + char pid = 0; + int ret; + struct sensor *sensor = to_sensor(client); + + /* We must have a parent by now. And it cannot be a wrong one. + * So this entire test is completely redundant. */ + if (!icd->dev.parent || + to_soc_camera_host(icd->dev.parent)->nr != icd->iface) + return -ENODEV; + + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_video_probe_err; + } + + /* soft reset */ + /* ret = sensor_write(client, 0x12, 0x80); + if (ret != 0) + { + SENSOR_TR("soft reset %s failed\n",SENSOR_NAME_STRING()); + return -ENODEV; + } + mdelay(50); *///delay 5 microseconds + + /* check if it is an sensor sensor */ + ////////ret = sensor_read(client, 0x00, &pid); + ret = sensor_read(client, SENSOR_ID_REG, &pid); + if (ret != 0) { + SENSOR_TR("%s read chip id high byte failed\n",SENSOR_NAME_STRING()); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + SENSOR_DG("\n %s pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + if (pid == SENSOR_ID) { + sensor->model = SENSOR_V4L2_IDENT; + } else { + SENSOR_TR("error: %s mismatched pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + return 0; + +sensor_video_probe_err: + + return ret; +} + +static long sensor_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd) +; + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + int ret = 0; +#if CONFIG_SENSOR_Flash + int i; +#endif + + SENSOR_DG("\n%s..%s..cmd:%x \n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + switch (cmd) + { + case RK29_CAM_SUBDEV_DEACTIVATE: + { + sensor_deactivate(client); + break; + } + + case RK29_CAM_SUBDEV_IOREQUEST: + { + sensor->sensor_io_request = (struct rk29camera_platform_data*)arg; + if (sensor->sensor_io_request != NULL) { + if (sensor->sensor_io_request->gpio_res[0].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[0].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[0]; + } else if (sensor->sensor_io_request->gpio_res[1].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[1].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[1]; + } + } else { + SENSOR_TR("%s %s RK29_CAM_SUBDEV_IOREQUEST fail\n",SENSOR_NAME_STRING(),__FUNCTION__); + ret = -EINVAL; + goto sensor_ioctl_end; + } + /* ddl@rock-chips.com : if gpio_flash havn't been set in board-xxx.c, sensor driver must notify is not support flash control + for this project */ + #if CONFIG_SENSOR_Flash + if (sensor->sensor_gpio_res) { + if (sensor->sensor_gpio_res->gpio_flash == INVALID_GPIO) { + for (i = 0; i < icd->ops->num_controls; i++) { + if (V4L2_CID_FLASH == icd->ops->controls[i].id) { + memset((char*)&icd->ops->controls[i],0x00,sizeof(struct v4l2_queryctrl)); + } + } + sensor->info_priv.flash = 0xff; + SENSOR_DG("%s flash gpio is invalidate!\n",SENSOR_NAME_STRING()); + } + } + #endif + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown !\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } +sensor_ioctl_end: + return ret; + +} +static int sensor_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + if (index >= ARRAY_SIZE(sensor_colour_fmts)) + return -EINVAL; + + *code = sensor_colour_fmts[index].code; + return 0; +} +static struct v4l2_subdev_core_ops sensor_subdev_core_ops = { + .init = sensor_init, + .g_ctrl = sensor_g_control, + .s_ctrl = sensor_s_control, + .g_ext_ctrls = sensor_g_ext_controls, + .s_ext_ctrls = sensor_s_ext_controls, + .g_chip_ident = sensor_g_chip_ident, + .ioctl = sensor_ioctl, +}; + +static struct v4l2_subdev_video_ops sensor_subdev_video_ops = { + .s_mbus_fmt = sensor_s_fmt, + .g_mbus_fmt = sensor_g_fmt, + .try_mbus_fmt = sensor_try_fmt, + .enum_mbus_fmt = sensor_enum_fmt, +}; + +static struct v4l2_subdev_ops sensor_subdev_ops = { + .core = &sensor_subdev_core_ops, + .video = &sensor_subdev_video_ops, +}; + +static int sensor_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct sensor *sensor; + struct soc_camera_device *icd = client->dev.platform_data; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct soc_camera_link *icl; + int ret; + + SENSOR_DG("\n%s..%s..%d..\n",__FUNCTION__,__FILE__,__LINE__); + if (!icd) { + dev_err(&client->dev, "%s: missing soc-camera data!\n",SENSOR_NAME_STRING()); + return -EINVAL; + } + + icl = to_soc_camera_link(icd); + if (!icl) { + dev_err(&client->dev, "%s driver needs platform data\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { + dev_warn(&adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_I2C\n"); + return -EIO; + } + + sensor = kzalloc(sizeof(struct sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + v4l2_i2c_subdev_init(&sensor->subdev, client, &sensor_subdev_ops); + + /* Second stage probe - when a capture adapter is there */ + icd->ops = &sensor_ops; + + sensor->info_priv.fmt = sensor_colour_fmts[0]; + + #if CONFIG_SENSOR_I2C_NOSCHED + atomic_set(&sensor->tasklock_cnt,0); + #endif + + ret = sensor_video_probe(icd, client); + if (ret < 0) { + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + kfree(sensor); + sensor = NULL; + } + SENSOR_DG("\n%s..%s..%d ret = %x \n",__FUNCTION__,__FILE__,__LINE__,ret); + return ret; +} + +static int sensor_remove(struct i2c_client *client) +{ + struct sensor *sensor = to_sensor(client); + struct soc_camera_device *icd = client->dev.platform_data; + + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + client->driver = NULL; + kfree(sensor); + sensor = NULL; + return 0; +} + +static const struct i2c_device_id sensor_id[] = { + {SENSOR_NAME_STRING(), 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sensor_id); + +static struct i2c_driver sensor_i2c_driver = { + .driver = { + .name = SENSOR_NAME_STRING(), + }, + .probe = sensor_probe, + .remove = sensor_remove, + .id_table = sensor_id, +}; + +static int __init sensor_mod_init(void) +{ + printk("\n*****************%s..%s.. \n",__FUNCTION__,SENSOR_NAME_STRING()); +#ifdef CONFIG_SOC_CAMERA_FCAM + return 0; +#else + return i2c_add_driver(&sensor_i2c_driver); +#endif +} + +static void __exit sensor_mod_exit(void) +{ + i2c_del_driver(&sensor_i2c_driver); +} + +device_initcall_sync(sensor_mod_init); +module_exit(sensor_mod_exit); + +MODULE_DESCRIPTION(SENSOR_NAME_STRING(Camera sensor driver)); +MODULE_AUTHOR("ddl "); +MODULE_LICENSE("GPL"); + diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h index f52d74d48be8..53724b2be00c 100755 --- a/include/media/v4l2-chip-ident.h +++ b/include/media/v4l2-chip-ident.h @@ -90,6 +90,7 @@ enum { /* Samsung sensors: reserved range 310-319 */ V4L2_IDENT_S5K66A = 310, /* ddl@rock-chips.com : s5k66a support */ + V4L2_IDENT_S5K5CA = 311, /* ddl@rock-chips.com : s5k5ca support */ /* Conexant MPEG encoder/decoders: reserved range 400-420 */ V4L2_IDENT_CX23418_843 = 403, /* Integrated A/V Decoder on the '418 */ @@ -349,6 +350,8 @@ enum { V4L2_IDENT_NT99250 = 64108, /* ddl@rock-chips.com : nt99250 support */ V4L2_IDENT_SID130B = 64109, /* ddl@rock-chips.com : sid130B support */ + V4L2_IDENT_SP0838 = 64110, /* ddl@rock-chips.com : SP0838 support */ + V4L2_IDENT_GC0329 = 64111, /* ddl@rock-chips.com : GC0329 support */ /* Don't just add new IDs at the end: KEEP THIS LIST ORDERED BY ID! */ }; From dadb0ed4e9432619a473f9a9bdd28c26df810540 Mon Sep 17 00:00:00 2001 From: "lw@rock-chips.com" Date: Tue, 31 Jul 2012 18:48:12 +0800 Subject: [PATCH 060/261] phonepad:modify pwm regulator and change tps65910 starting time --- arch/arm/mach-rk30/board-rk30-phonepad.c | 19 +++++---- arch/arm/mach-rk30/board-rk30-sdk-tps65910.c | 8 +--- drivers/mfd/tps65910.c | 2 +- drivers/regulator/rk30-pwm-regulator.c | 45 +++++++++++--------- drivers/regulator/tps65910-regulator.c | 2 +- drivers/rtc/rtc-tps65910.c | 2 +- include/linux/regulator/rk29-pwm-regulator.h | 4 ++ 7 files changed, 45 insertions(+), 37 deletions(-) mode change 100644 => 100755 include/linux/regulator/rk29-pwm-regulator.h diff --git a/arch/arm/mach-rk30/board-rk30-phonepad.c b/arch/arm/mach-rk30/board-rk30-phonepad.c index da846b986009..82a8f031d5ce 100755 --- a/arch/arm/mach-rk30/board-rk30-phonepad.c +++ b/arch/arm/mach-rk30/board-rk30-phonepad.c @@ -45,6 +45,7 @@ #include #include #include +#include #include "../../../drivers/headset_observe/rk_headset.h" #if defined(CONFIG_HDMI_RK30) @@ -1516,15 +1517,8 @@ static struct platform_device rk30_device_adc_battery = { }; #endif #if CONFIG_RK30_PWM_REGULATOR -struct pwm_platform_data { - int pwm_id; - int pwm_gpio; - //char pwm_iomux_name[50]; - char* pwm_iomux_name; - unsigned int pwm_iomux_pwm; - int pwm_iomux_gpio; - int pwm_voltage; - struct regulator_init_data *init_data; +const static int pwm_voltage_map[] = { + 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 1400000 }; static struct regulator_consumer_supply pwm_dcdc1_consumers[] = { @@ -1556,6 +1550,10 @@ static struct pwm_platform_data pwm_regulator_info[1] = { .pwm_iomux_pwm = GPIO0D_PWM3, .pwm_iomux_gpio = GPIO0D_GPIO0D6, .pwm_voltage = 1100000, + .min_uV = 1000000, + .max_uV = 1400000, + .duty_cycle = 455, //45.5% + .pwm_voltage_map = pwm_voltage_map, .init_data = &pwm_regulator_init_dcdc[0], }, }; @@ -1639,6 +1637,9 @@ static struct platform_device device_rfkill_rk = { #endif static struct platform_device *devices[] __initdata = { +#ifdef CONFIG_RK30_PWM_REGULATOR + &pwm_regulator_device[0], +#endif #ifdef CONFIG_BACKLIGHT_RK29_BL &rk29_device_backlight, #endif diff --git a/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c b/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c index 19677ddfedd2..ac2ee6b19f1f 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c +++ b/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c @@ -34,11 +34,7 @@ int tps65910_pre_init(struct tps65910 *tps65910){ int val = 0; int i = 0; int err = -1; - - #ifdef CONFIG_RK30_PWM_REGULATOR - platform_device_register(&pwm_regulator_device[0]); - #endif - + printk("%s,line=%d\n", __func__,__LINE__); //gpio_request(PMU_POWER_SLEEP, "NULL"); //gpio_direction_output(PMU_POWER_SLEEP, GPIO_HIGH); @@ -313,7 +309,7 @@ int tps65910_post_init(struct tps65910 *tps65910) #ifdef CONFIG_RK30_PWM_REGULATOR dcdc = regulator_get(NULL, "vdd_core"); // vdd_log - regulator_set_voltage(dcdc, 1150000, 1150000); + regulator_set_voltage(dcdc, 1100000, 1100000); regulator_enable(dcdc); printk("%s set vdd_core=%dmV end\n", __func__, regulator_get_voltage(dcdc)); regulator_put(dcdc); diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index cc8a29ad09cd..dd7813012b43 100755 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -364,7 +364,7 @@ static int __init tps65910_i2c_init(void) return i2c_add_driver(&tps65910_i2c_driver); } /* init early so consumer devices can complete system boot */ -module_init(tps65910_i2c_init); +subsys_initcall_sync(tps65910_i2c_init); static void __exit tps65910_i2c_exit(void) { diff --git a/drivers/regulator/rk30-pwm-regulator.c b/drivers/regulator/rk30-pwm-regulator.c index 7a89527b0b06..07ab738f1792 100755 --- a/drivers/regulator/rk30-pwm-regulator.c +++ b/drivers/regulator/rk30-pwm-regulator.c @@ -57,7 +57,7 @@ struct rk_pwm_dcdc { struct regulator_desc desc; int pwm_id; struct regulator_dev *regulator; - struct pwm_platform_data *pdata; + struct pwm_platform_data *pdata; }; @@ -70,7 +70,7 @@ struct rk_pwm_dcdc { #endif const static int pwm_voltage_map[] = { - 850000,875000,900000,925000,950000, 975000, 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000, 1325000 + 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 1400000 }; static struct clk *pwm_clk[2]; @@ -132,8 +132,9 @@ static int pwm_set_rate(struct pwm_platform_data *pdata,int nHz,u32 rate) static int pwm_regulator_list_voltage(struct regulator_dev *dev,unsigned int index) { - if (index < sizeof(pwm_voltage_map)/sizeof(int)) - return pwm_voltage_map[index]; + struct rk_pwm_dcdc *dcdc = rdev_get_drvdata(dev); + if (index < dcdc->desc.n_voltages) + return dcdc->pdata->pwm_voltage_map[index]; else return -1; } @@ -176,15 +177,14 @@ static int pwm_regulator_set_voltage(struct regulator_dev *dev, #endif { struct rk_pwm_dcdc *dcdc = rdev_get_drvdata(dev); - const int *voltage_map = pwm_voltage_map; - - int min_mV = min_uV, max_mA = max_uV; - - u32 size = sizeof(pwm_voltage_map)/sizeof(int), i, vol,pwm_value; + const int *voltage_map = dcdc->pdata->pwm_voltage_map; + int max = dcdc->pdata->max_uV; + int duty_cycle = dcdc->pdata->duty_cycle; + u32 size = dcdc->desc.n_voltages, i, vol,pwm_value; DBG("%s: min_uV = %d, max_uV = %d\n",__FUNCTION__, min_uV,max_uV); - if (min_mV < voltage_map[0] ||max_mA > voltage_map[size-1]) + if (min_uV < voltage_map[0] ||max_uV > voltage_map[size-1]) { printk("%s:voltage is out of table\n",__func__); return -EINVAL; @@ -192,7 +192,7 @@ static int pwm_regulator_set_voltage(struct regulator_dev *dev, for (i = 0; i < size; i++) { - if (voltage_map[i] >= min_mV) + if (voltage_map[i] >= min_uV) break; } @@ -201,9 +201,8 @@ static int pwm_regulator_set_voltage(struct regulator_dev *dev, dcdc->pdata->pwm_voltage = vol; - // VDD12 = 1.42 - 0.56*D , 其中D为PWM占空比, - pwm_value = (1325000-vol)/5800; // pwm_value % - + // VDD12 = 1.40 - 0.455*D , 其中D为PWM占空比, + pwm_value = (max-vol)/duty_cycle/10; // pwm_value %, duty_cycle = D*1000 if (pwm_set_rate(dcdc->pdata,1000*1000,pwm_value)!=0) { @@ -242,17 +241,25 @@ static int __devinit pwm_regulator_probe(struct platform_device *pdev) struct pwm_platform_data *pdata = pdev->dev.platform_data; struct rk_pwm_dcdc *dcdc; int pwm_id = pdata->pwm_id; - struct regulator_dev *rdev; int id = pdev->id; int ret ; - char gpio_name[20]; + char gpio_name[20]; if (!pdata) return -ENODEV; if (!pdata->pwm_voltage) - pdata->pwm_voltage = 1200000; // default 1.2v + pdata->pwm_voltage = 1100000; // default 1.1v + if(!pdata->pwm_voltage_map) + pdata->pwm_voltage_map = pwm_voltage_map; + + if(!pdata->max_uV) + pdata->max_uV = 1400000; + + if(!pdata->min_uV) + pdata->min_uV = 1000000; + dcdc = kzalloc(sizeof(struct rk_pwm_dcdc), GFP_KERNEL); if (dcdc == NULL) { dev_err(&pdev->dev, "Unable to allocate private data\n"); @@ -263,11 +270,11 @@ static int __devinit pwm_regulator_probe(struct platform_device *pdev) dcdc->desc.name = dcdc->name; dcdc->desc.id = id; dcdc->desc.type = REGULATOR_VOLTAGE; - dcdc->desc.n_voltages = 50; + dcdc->desc.n_voltages = ARRAY_SIZE(pwm_voltage_map); dcdc->desc.ops = &pwm_voltage_ops; dcdc->desc.owner = THIS_MODULE; dcdc->pdata = pdata; - + printk("%s:n_voltages=%d\n",__func__,dcdc->desc.n_voltages); dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev, pdata->init_data, dcdc); if (IS_ERR(dcdc->regulator)) { diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c index 0739da51efd2..22e06e2cb98e 100755 --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c @@ -1324,7 +1324,7 @@ static int __init tps65910_init(void) { return platform_driver_register(&tps65910_driver); } -module_init(tps65910_init); +subsys_initcall_sync(tps65910_init); static void __exit tps65910_cleanup(void) { diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index 43e9235c67c0..f6a8693cabcf 100755 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -681,7 +681,7 @@ static int __init tps65910_rtc_init(void) misc_register(&rtc_tps65910_test_misc); return platform_driver_register(&tps65910_rtc_driver); } -module_init(tps65910_rtc_init); +subsys_initcall_sync(tps65910_rtc_init); static void __exit tps65910_rtc_exit(void) { diff --git a/include/linux/regulator/rk29-pwm-regulator.h b/include/linux/regulator/rk29-pwm-regulator.h old mode 100644 new mode 100755 index e0a0487d2a85..a8c691727f47 --- a/include/linux/regulator/rk29-pwm-regulator.h +++ b/include/linux/regulator/rk29-pwm-regulator.h @@ -57,6 +57,10 @@ struct pwm_platform_data { unsigned int pwm_iomux_pwm; int pwm_iomux_gpio; int pwm_voltage; + int duty_cycle; + int min_uV; + int max_uV; + int *pwm_voltage_map; struct regulator_init_data *init_data; }; From af0ec2618c7bf6d8eb17c18ad56ba85d990837d0 Mon Sep 17 00:00:00 2001 From: lw Date: Tue, 31 Jul 2012 18:52:09 +0800 Subject: [PATCH 061/261] phonepad:add pwm regulator defconfig --- arch/arm/configs/rk30_phonepad_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/rk30_phonepad_defconfig b/arch/arm/configs/rk30_phonepad_defconfig index e12f52255428..a69c34ac4f2f 100644 --- a/arch/arm/configs/rk30_phonepad_defconfig +++ b/arch/arm/configs/rk30_phonepad_defconfig @@ -267,6 +267,7 @@ CONFIG_TEST_POWER=y CONFIG_MFD_TPS65910=y CONFIG_REGULATOR=y CONFIG_REGULATOR_TPS65910=y +CONFIG_RK30_PWM_REGULATOR=y CONFIG_MEDIA_SUPPORT=y CONFIG_VIDEO_DEV=y CONFIG_SOC_CAMERA=y From 8f002da463467a9af839293edea4dd65e1580699 Mon Sep 17 00:00:00 2001 From: lw Date: Tue, 31 Jul 2012 19:09:21 +0800 Subject: [PATCH 062/261] phonepad:modify pwm regulator struct definition --- arch/arm/mach-rk30/board-rk30-phonepad.c | 2 +- drivers/regulator/rk30-pwm-regulator.c | 4 ++-- include/linux/regulator/rk29-pwm-regulator.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-rk30/board-rk30-phonepad.c b/arch/arm/mach-rk30/board-rk30-phonepad.c index 82a8f031d5ce..6870e47d2995 100755 --- a/arch/arm/mach-rk30/board-rk30-phonepad.c +++ b/arch/arm/mach-rk30/board-rk30-phonepad.c @@ -1552,7 +1552,7 @@ static struct pwm_platform_data pwm_regulator_info[1] = { .pwm_voltage = 1100000, .min_uV = 1000000, .max_uV = 1400000, - .duty_cycle = 455, //45.5% + .coefficient = 455, //45.5% .pwm_voltage_map = pwm_voltage_map, .init_data = &pwm_regulator_init_dcdc[0], }, diff --git a/drivers/regulator/rk30-pwm-regulator.c b/drivers/regulator/rk30-pwm-regulator.c index 07ab738f1792..46bf1b75982e 100755 --- a/drivers/regulator/rk30-pwm-regulator.c +++ b/drivers/regulator/rk30-pwm-regulator.c @@ -179,7 +179,7 @@ static int pwm_regulator_set_voltage(struct regulator_dev *dev, struct rk_pwm_dcdc *dcdc = rdev_get_drvdata(dev); const int *voltage_map = dcdc->pdata->pwm_voltage_map; int max = dcdc->pdata->max_uV; - int duty_cycle = dcdc->pdata->duty_cycle; + int coefficient = dcdc->pdata->coefficient; u32 size = dcdc->desc.n_voltages, i, vol,pwm_value; DBG("%s: min_uV = %d, max_uV = %d\n",__FUNCTION__, min_uV,max_uV); @@ -202,7 +202,7 @@ static int pwm_regulator_set_voltage(struct regulator_dev *dev, dcdc->pdata->pwm_voltage = vol; // VDD12 = 1.40 - 0.455*D , 其中D为PWM占空比, - pwm_value = (max-vol)/duty_cycle/10; // pwm_value %, duty_cycle = D*1000 + pwm_value = (max-vol)/coefficient/10; // pwm_value %, coefficient *1000 if (pwm_set_rate(dcdc->pdata,1000*1000,pwm_value)!=0) { diff --git a/include/linux/regulator/rk29-pwm-regulator.h b/include/linux/regulator/rk29-pwm-regulator.h index a8c691727f47..70904dc447be 100755 --- a/include/linux/regulator/rk29-pwm-regulator.h +++ b/include/linux/regulator/rk29-pwm-regulator.h @@ -57,7 +57,7 @@ struct pwm_platform_data { unsigned int pwm_iomux_pwm; int pwm_iomux_gpio; int pwm_voltage; - int duty_cycle; + int coefficient; int min_uV; int max_uV; int *pwm_voltage_map; From c0515f8bfdefa8c9a6e8ce9158112bd73ce5a1af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=8B=E7=A7=80=E6=9D=B0?= Date: Tue, 31 Jul 2012 19:41:32 +0800 Subject: [PATCH 063/261] phonepad: add mclk2 for rt5623. --- arch/arm/configs/rk30_phonepad_defconfig | 1 + sound/soc/codecs/rt3261.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/arch/arm/configs/rk30_phonepad_defconfig b/arch/arm/configs/rk30_phonepad_defconfig index a69c34ac4f2f..a2f09e0c56db 100644 --- a/arch/arm/configs/rk30_phonepad_defconfig +++ b/arch/arm/configs/rk30_phonepad_defconfig @@ -299,6 +299,7 @@ CONFIG_SND=y # CONFIG_SND_ARM is not set CONFIG_SND_SOC=y CONFIG_SND_RK29_SOC=y +CONFIG_SND_RK_SOC_I2S2_2CH=y CONFIG_SND_I2S_DMA_EVENT_STATIC=y CONFIG_SND_RK29_SOC_RT5623=y CONFIG_SND_RK29_SOC_RT3261=y diff --git a/sound/soc/codecs/rt3261.c b/sound/soc/codecs/rt3261.c index c1c32acbb51a..dc3a678e0372 100644 --- a/sound/soc/codecs/rt3261.c +++ b/sound/soc/codecs/rt3261.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #define RT3261_PROC #ifdef RT3261_PROC @@ -2733,6 +2735,7 @@ static int rt3261_probe(struct snd_soc_codec *codec) { struct rt3261_priv *rt3261 = snd_soc_codec_get_drvdata(codec); int ret; + struct clk *iis_clk; pr_info("Codec driver version %s\n", VERSION); @@ -2745,6 +2748,19 @@ static int rt3261_probe(struct snd_soc_codec *codec) #ifdef RT3261_PROC rt3261_proc_init(); #endif + + //for rt5623 MCLK use + iis_clk = clk_get_sys("rk29_i2s.2", "i2s"); + if (IS_ERR(iis_clk)) { + printk("failed to get i2s clk\n"); + ret = PTR_ERR(iis_clk); + }else{ + printk("I2S2 got i2s clk ok!\n"); + clk_enable(iis_clk); + clk_set_rate(iis_clk, 11289600); + rk30_mux_api_set(GPIO0D0_I2S22CHCLK_SMCCSN0_NAME, GPIO0D_I2S2_2CH_CLK); + clk_put(iis_clk); + } rt3261_reset(codec); snd_soc_update_bits(codec, RT3261_PWR_ANLG1, From 3936fbfee6747d4eb720aa26645d82c16f109519 Mon Sep 17 00:00:00 2001 From: hzf Date: Wed, 1 Aug 2012 10:41:41 +0800 Subject: [PATCH 064/261] phone_pad: add sid130b and siv121d camera driver --- arch/arm/configs/rk30_phonepad_defconfig | 4 +- arch/arm/mach-rk30/board-rk30-phonepad.c | 24 +- arch/arm/plat-rk/include/plat/rk_camera.h | 13 +- drivers/media/video/Kconfig | 8 +- drivers/media/video/Makefile | 1 + drivers/media/video/sid130B.c | 719 +++++- drivers/media/video/siv121d.c | 2728 +++++++++++++++++++++ include/media/v4l2-chip-ident.h | 4 +- 8 files changed, 3469 insertions(+), 32 deletions(-) create mode 100755 drivers/media/video/siv121d.c diff --git a/arch/arm/configs/rk30_phonepad_defconfig b/arch/arm/configs/rk30_phonepad_defconfig index a2f09e0c56db..dc80af7bb5fa 100644 --- a/arch/arm/configs/rk30_phonepad_defconfig +++ b/arch/arm/configs/rk30_phonepad_defconfig @@ -271,8 +271,8 @@ CONFIG_RK30_PWM_REGULATOR=y CONFIG_MEDIA_SUPPORT=y CONFIG_VIDEO_DEV=y CONFIG_SOC_CAMERA=y -CONFIG_SOC_CAMERA_OV2659=y -CONFIG_SOC_CAMERA_OV5642=y +CONFIG_SOC_CAMERA_SIV121D=y +CONFIG_SOC_CAMERA_SID130B=y CONFIG_VIDEO_RK29=y CONFIG_VIDEO_RK29_CAMMEM_ION=y CONFIG_ION=y diff --git a/arch/arm/mach-rk30/board-rk30-phonepad.c b/arch/arm/mach-rk30/board-rk30-phonepad.c index 6870e47d2995..86020f098eb7 100755 --- a/arch/arm/mach-rk30/board-rk30-phonepad.c +++ b/arch/arm/mach-rk30/board-rk30-phonepad.c @@ -91,18 +91,18 @@ #ifdef CONFIG_VIDEO_RK29 /*---------------- Camera Sensor Macro Define Begin ------------------------*/ /*---------------- Camera Sensor Configuration Macro Begin ------------------------*/ -#define CONFIG_SENSOR_0 RK29_CAM_SENSOR_OV5642 /* back camera sensor */ -#define CONFIG_SENSOR_IIC_ADDR_0 0x78 -#define CONFIG_SENSOR_IIC_ADAPTER_ID_0 4 -#define CONFIG_SENSOR_CIF_INDEX_0 1 +#define CONFIG_SENSOR_0 RK29_CAM_SENSOR_SID130B /* back camera sensor */ +#define CONFIG_SENSOR_IIC_ADDR_0 0x6e +#define CONFIG_SENSOR_IIC_ADAPTER_ID_0 3 +#define CONFIG_SENSOR_CIF_INDEX_0 0 // 1 #define CONFIG_SENSOR_ORIENTATION_0 90 #define CONFIG_SENSOR_POWER_PIN_0 INVALID_GPIO #define CONFIG_SENSOR_RESET_PIN_0 INVALID_GPIO -#define CONFIG_SENSOR_POWERDN_PIN_0 RK30_PIN1_PD6 +#define CONFIG_SENSOR_POWERDN_PIN_0 RK30_PIN1_PB7 #define CONFIG_SENSOR_FALSH_PIN_0 INVALID_GPIO #define CONFIG_SENSOR_POWERACTIVE_LEVEL_0 RK29_CAM_POWERACTIVE_L #define CONFIG_SENSOR_RESETACTIVE_LEVEL_0 RK29_CAM_RESETACTIVE_L -#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_0 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_0 RK29_CAM_POWERDNACTIVE_L #define CONFIG_SENSOR_FLASHACTIVE_LEVEL_0 RK29_CAM_FLASHACTIVE_L #define CONFIG_SENSOR_QCIF_FPS_FIXED_0 15000 @@ -160,14 +160,14 @@ #define CONFIG_SENSOR_SVGA_FPS_FIXED_02 15000 #define CONFIG_SENSOR_720P_FPS_FIXED_02 30000 -#define CONFIG_SENSOR_1 RK29_CAM_SENSOR_OV2659 /* front camera sensor 0 */ -#define CONFIG_SENSOR_IIC_ADDR_1 0x60 +#define CONFIG_SENSOR_1 RK29_CAM_SENSOR_SIV121D /* front camera sensor 0 */ +#define CONFIG_SENSOR_IIC_ADDR_1 0x66 #define CONFIG_SENSOR_IIC_ADAPTER_ID_1 3 -#define CONFIG_SENSOR_CIF_INDEX_1 0 +#define CONFIG_SENSOR_CIF_INDEX_1 0 #define CONFIG_SENSOR_ORIENTATION_1 270 #define CONFIG_SENSOR_POWER_PIN_1 INVALID_GPIO #define CONFIG_SENSOR_RESET_PIN_1 INVALID_GPIO -#define CONFIG_SENSOR_POWERDN_PIN_1 RK30_PIN1_PB7 +#define CONFIG_SENSOR_POWERDN_PIN_1 RK30_PIN1_PB6 #define CONFIG_SENSOR_FALSH_PIN_1 INVALID_GPIO #define CONFIG_SENSOR_POWERACTIVE_LEVEL_1 RK29_CAM_POWERACTIVE_L #define CONFIG_SENSOR_RESETACTIVE_LEVEL_1 RK29_CAM_RESETACTIVE_L @@ -249,8 +249,8 @@ static void rk_cif_power(int on) { struct regulator *ldo_18,*ldo_28; - ldo_28 = regulator_get(NULL, "ldo7"); // vcc28_cif - ldo_18 = regulator_get(NULL, "ldo1"); // vcc18_cif + ldo_28 = regulator_get(NULL, "vmmc"); // vcc28_cif ldo7 + ldo_18 = regulator_get(NULL, "vdig1"); // vcc18_cif ldo1 if (ldo_28 == NULL || IS_ERR(ldo_28) || ldo_18 == NULL || IS_ERR(ldo_18)){ printk("get cif ldo failed!\n"); return; diff --git a/arch/arm/plat-rk/include/plat/rk_camera.h b/arch/arm/plat-rk/include/plat/rk_camera.h index 19ca16b0692d..39f31b11facb 100755 --- a/arch/arm/plat-rk/include/plat/rk_camera.h +++ b/arch/arm/plat-rk/include/plat/rk_camera.h @@ -60,14 +60,11 @@ #define RK29_CAM_SENSOR_GC0309 gc0309 #define RK29_CAM_SENSOR_GC2015 gc2015 #define RK29_CAM_SENSOR_SIV120B siv120b +#define RK29_CAM_SENSOR_SIV121D siv121d #define RK29_CAM_SENSOR_SID130B sid130B #define RK29_CAM_SENSOR_HI253 hi253 #define RK29_CAM_SENSOR_HI704 hi704 #define RK29_CAM_SENSOR_NT99250 nt99250 -#define RK29_CAM_SENSOR_SP0838 sp0838 -#define RK29_CAM_SENSOR_GC0329 gc0329 -#define RK29_CAM_SENSOR_S5K5CA s5k5ca - #define RK29_CAM_SENSOR_NAME_OV7675 "ov7675" #define RK29_CAM_SENSOR_NAME_OV9650 "ov9650" @@ -90,13 +87,11 @@ #define RK29_CAM_SENSOR_NAME_GC0309 "gc0309" #define RK29_CAM_SENSOR_NAME_GC2015 "gc2015" #define RK29_CAM_SENSOR_NAME_SIV120B "siv120b" +#define RK29_CAM_SENSOR_NAME_SIV121D "siv121d" #define RK29_CAM_SENSOR_NAME_SID130B "sid130B" #define RK29_CAM_SENSOR_NAME_HI253 "hi253" #define RK29_CAM_SENSOR_NAME_HI704 "hi704" #define RK29_CAM_SENSOR_NAME_NT99250 "nt99250" -#define RK29_CAM_SENSOR_NAME_SP0838 "sp0838" -#define RK29_CAM_SENSOR_NAME_GC0329 "gc0329" -#define RK29_CAM_SENSOR_NAME_S5K5CA "s5k5ca" #define ov7675_FULL_RESOLUTION 0x30000 // 0.3 megapixel #define ov9650_FULL_RESOLUTION 0x130000 // 1.3 megapixel @@ -118,13 +113,11 @@ #define gc0309_FULL_RESOLUTION 0x30000 // 0.3 megapixel #define gc2015_FULL_RESOLUTION 0x200000 // 2 megapixel #define siv120b_FULL_RESOLUTION 0x30000 // 0.3 megapixel +#define siv121d_FULL_RESOLUTION 0x30000 // 0.3 megapixel #define sid130B_FULL_RESOLUTION 0x200000 // 2 megapixel #define hi253_FULL_RESOLUTION 0x200000 // 2 megapixel #define hi704_FULL_RESOLUTION 0x30000 // 0.3 megapixel #define nt99250_FULL_RESOLUTION 0x200000 // 2 megapixel -#define sp0838_FULL_RESOLUTION 0x30000 // 0.3 megapixel -#define gc0329_FULL_RESOLUTION 0x30000 // 0.3 megapixel -#define s5k5ca_FULL_RESOLUTION 0x300000 // 3 megapixel /*---------------- Camera Sensor Must Define Macro End ------------------------*/ diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 08120f7a91da..f3d35931decd 100755 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -1194,7 +1194,13 @@ config SIV120B_USER_DEFINED_SERIES depends on SOC_CAMERA_SIV120B bool "SIV120B user defined init series" default n - + +config SOC_CAMERA_SIV121D + tristate "siv121d support for rockchip" + depends on SOC_CAMERA && I2C + help + This is a SIV121D camera driver for rockchip + config SOC_CAMERA_SID130B tristate "sid130b support for rockchip" depends on SOC_CAMERA && I2C diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index b96c68fdef76..30585000fc03 100755 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -108,6 +108,7 @@ obj-$(CONFIG_SOC_CAMERA_GC0309) += gc0309.o obj-$(CONFIG_SOC_CAMERA_GC0309_FOR_TD8801) += gc0309_for_td8801.o obj-$(CONFIG_SOC_CAMERA_GC2015) += gc2015.o obj-$(CONFIG_SOC_CAMERA_SIV120B) += siv120b.o +obj-$(CONFIG_SOC_CAMERA_SIV121D) += siv121d.o obj-$(CONFIG_SOC_CAMERA_SID130B) += sid130B.o obj-$(CONFIG_SOC_CAMERA_HI253) += hi253.o obj-$(CONFIG_SOC_CAMERA_HI704) += hi704.o diff --git a/drivers/media/video/sid130B.c b/drivers/media/video/sid130B.c index 4028cf199d56..13f75d6d51b9 100755 --- a/drivers/media/video/sid130B.c +++ b/drivers/media/video/sid130B.c @@ -50,9 +50,9 @@ module_param(debug, int, S_IRUGO|S_IWUSR); #define SENSOR_MIN_HEIGHT 144 #define SENSOR_MAX_WIDTH 1600 #define SENSOR_MAX_HEIGHT 1200 -#define SENSOR_INIT_WIDTH 640 /* Sensor pixel size for sensor_init_data array */ -#define SENSOR_INIT_HEIGHT 480 -#define SENSOR_INIT_WINSEQADR sensor_vga +#define SENSOR_INIT_WIDTH 800 /* Sensor pixel size for sensor_init_data array */ +#define SENSOR_INIT_HEIGHT 600 +#define SENSOR_INIT_WINSEQADR sensor_svga #define SENSOR_INIT_PIXFMT V4L2_MBUS_FMT_UYVY8_2X8 #define CONFIG_SENSOR_WhiteBalance 1 @@ -115,7 +115,8 @@ static struct flash_timer flash_off_timer; /* init 352X288 SVGA */ static struct reginfo sensor_init_data[] = { - {0x00, 0x00}, +#if 0 + {0x00, 0x00}, {0x04, 0x00}, //Group A 0x10 {0x05, 0x0F}, //UXGA Output {0x06, 0x86}, @@ -750,8 +751,716 @@ static struct reginfo sensor_init_data[] = {0x00, 0x02}, {0x10, 0xd3}, {0xff, 0xff}, +#else + + {0x00, 0x00}, + {0x04, 0x00}, //Group A 0x10 + {0x05, 0x0F}, //UXGA Output + {0x06, 0x86}, + {0x07, 0x08}, + {0x08, 0xa2}, //PLL on + {0x09, 0x12}, + {0x0A, 0x12}, + {0x10, 0x13},//17}, + {0x11, 0x01}, + {0x12, 0x8A}, + + {0x13, 0x1a},//16}, + {0x15, 0x22},//16}, + {0x14, 0x27},//16}, + {0x17, 0xcb},//CF}, + {0x18, 0x38},//34}, + {0x41, 0x17}, + {0x42, 0x52}, + + //Flicker - 50Hz - Still mode + {0x00, 0x00}, + {0x20, 0x00}, + {0x21, 0x02}, + {0x23, 0x29},//15}, + {0x00, 0x01}, + {0x35, 0x50},//3c}, + + //Flicker - 50Hz - Preview mode 24MHz MCLK + {0x00, 0x00}, + {0x24, 0x00}, + {0x25, 0xe6},//10}, + {0x27, 0x0d},//4b}, + {0x00, 0x01}, + {0x34, 0x80},//64}, + + //AE Block + {0x00, 0x01}, + {0x10, 0x80}, + {0x11, 0x0A}, + {0x12, 0x74}, + {0x13, 0x74}, + {0x14, 0x70}, + {0x17, 0xC4}, + {0x1c, 0x02}, + + {0x19, 0x00},//0x + {0x1A, 0x00},//0x + {0x1c, 0x02}, + + {0x36, 0x26}, + + {0x40, 0x40}, //M +#if 0 + {0x41, 0x28}, + {0x42, 0x28}, + {0x43, 0x08}, + {0x44, 0x08}, + {0x45, 0x09}, + {0x46, 0x17}, + {0x47, 0x1D}, + {0x48, 0x21}, + {0x49, 0x23}, + {0x4A, 0x24}, + {0x4B, 0x26}, + {0x4C, 0x27}, + {0x4D, 0x27}, + {0x4E, 0x1A}, + {0x4F, 0x14}, + {0x50, 0x11}, + {0x51, 0x0F}, + {0x52, 0x0D}, + {0x53, 0x0C}, + {0x54, 0x0A}, + {0x55, 0x09}, +#else + {0x41, 0x20}, + {0x42, 0x20}, + {0x43, 0x00}, + {0x44, 0x00}, + {0x45, 0x01}, + {0x46, 0x0c}, + {0x47, 0x11}, + {0x48, 0x15}, + {0x49, 0x17}, + {0x4A, 0x1a}, + {0x4B, 0x1c}, + {0x4C, 0x1e}, + {0x4D, 0x1e}, + {0x4E, 0x0f}, + {0x4F, 0x09}, + {0x50, 0x07}, + {0x51, 0x05}, + {0x52, 0x04}, + {0x53, 0x03}, + {0x54, 0x02}, + {0x55, 0x01}, + {0x60, 0x7e}, + {0x61, 0xff}, + {0x62, 0xff}, + {0x63, 0xff}, + {0x64, 0xff}, + {0x65, 0x7e}, + {0x66, 0x50}, + {0x67, 0x50}, + {0x68, 0x50}, + {0x69, 0x50}, + {0x6A, 0x50}, + {0x6B, 0x00}, + {0x6C, 0x06}, + {0x9a, 0x80}, + {0x6b, 0x80}, + + +#endif + + //AWB Block + {0x00, 0x02}, + {0x10, 0xD3}, + {0x11, 0x11}, + {0x13, 0x80}, + {0x14, 0x80}, + {0x15, 0xE0},//FE}, + {0x16, 0x88}, + {0x17, 0xD0}, + {0x18, 0x78}, + {0x19, 0x98}, + {0x1A, 0x68}, + {0x1B, 0x8d}, + {0x1C, 0x68}, + {0x1D, 0x8C}, + {0x1E, 0x74}, + {0x20, 0xF0}, + {0x21, 0x70}, + {0x22, 0xa8}, + {0x23, 0x10}, + {0x25, 0x20}, + {0x26, 0x05}, + {0x27, 0x63}, + {0x28, 0x63}, + {0x29, 0xA0}, + {0x2A, 0x89}, + {0x30, 0x00}, + {0x31, 0x10}, + {0x32, 0x00}, + {0x33, 0x10}, + {0x34, 0x06}, + {0x35, 0x30}, + {0x36, 0x04}, + {0x37, 0xA0}, + {0x40, 0x01}, + {0x41, 0x04}, + {0x42, 0x08}, + {0x43, 0x10}, + {0x44, 0x13}, + {0x45, 0x6B}, + {0x46, 0x82}, + {0x52, 0x82}, + + + + //CMA change -D65~A + {0x53, 0x86}, //A + {0x54, 0xA0}, //A + {0x55, 0x88}, //A + {0x56, 0x9F}, //A + {0x57, 0xA5}, //A + {0x58, 0x89}, //A + {0x59, 0xA6}, //A + {0x5A, 0x87}, //A + + {0x64, 0x00}, //T + {0x65, 0x00}, + {0x66, 0x00}, //T + {0x67, 0x00}, + {0x68, 0xA5}, //T + {0x69, 0xB4}, + {0x6A, 0xB3}, //T + {0x6B, 0xAC}, + {0x6C, 0xB7}, //T + {0x6D, 0x98}, + {0x6E, 0xBA}, //T + {0x6F, 0x90}, + {0x70, 0xBF}, //T + {0x71, 0x9B}, + {0x72, 0xCE}, //T + {0x73, 0x8C}, + + + //IDP + + + {0x74, 0x7F}, //T + {0x75, 0x8C}, //T + {0x76, 0xAD}, //T + {0x77, 0xBA}, //T + {0x78, 0x8F}, //T + {0x79, 0x9A}, //T + {0x7A, 0xA3}, //T + {0x7B, 0xAC}, //T + {0x7C, 0xA0}, //T + {0x7D, 0xA9}, //T + {0x7E, 0x95}, //T + {0x7F, 0xAC}, //T + {0x80, 0xAD}, //T + {0x81, 0xBC}, //T + {0x82, 0x98}, //T + {0x83, 0xA4}, //T + {0x84, 0x00}, //T + {0x85, 0x00}, //T + {0x86, 0x00}, //T + {0x87, 0x00}, //T + {0x88, 0xC9}, //T + {0x89, 0xD5}, //T + {0x8A, 0x70}, //T + {0x8B, 0x7B}, //T + {0x8C, 0xD0}, //T + {0x8D, 0xE5}, //T + {0x8E, 0x58}, //T + {0x8F, 0x70}, //T + + {0xB4, 0x05}, + {0xB5, 0x0F}, + {0xB6, 0x06}, + {0xB7, 0x06}, + {0xB8, 0x40}, + {0xB9, 0x10}, + {0xBA, 0x06}, + + //IDP + {0x00, 0x03}, + {0x10, 0xFF}, + {0x11, 0x1D}, + {0x12, 0x1D}, + {0x13, 0xFB}, + {0x14, 0x00}, + {0x15, 0xc0}, + + //DPC + {0x30, 0x88}, //D + {0x31, 0x14},//04}, //D + {0x32, 0x10}, //D + {0x33, 0x0C}, //D + {0x34, 0x08}, //D + {0x35, 0x04}, //D + {0x36, 0x44}, //D + {0x37, 0x66}, //D + {0x38, 0x00}, //0 + {0x39, 0x08}, //0 + {0x3A, 0x08}, //0 + {0x3B, 0x20}, //0 + {0x3C, 0x20}, // + {0x3D, 0x04}, //N + {0x3E, 0x08}, //N + {0x3F, 0x10}, //N + {0x40, 0x10}, //N + {0x41, 0x20}, //N + {0x42, 0xFF}, //N + {0x43, 0x40},//F0}, //N + {0x44, 0x40}, //B + {0x45, 0x06},//09}, //S + {0x46, 0x40}, //S + {0x47, 0x30}, //I + + //DPC + #if 0 + //Shading + {0x50, 0x24}, //R + {0x51, 0x44}, //R + {0x52, 0x20}, //R + {0x53, 0x30}, //R + + {0x54, 0x20}, //G + {0x55, 0x20}, //G + {0x56, 0x00}, //G + {0x57, 0x10}, //G + + {0x58, 0x20}, //G + {0x59, 0x20}, //G + {0x5A, 0x00}, //G + {0x5B, 0x10}, //G + + {0x5C, 0x34}, //B + {0x5D, 0x48}, //B + {0x5E, 0x18}, //B + {0x5F, 0x2a}, //B + + {0x60, 0x32}, //# + {0x61, 0x00}, //# + {0x62, 0x67}, //# + + {0x6B, 0x23}, + {0x6C, 0x44}, + {0x6D, 0x45}, + {0x6E, 0x67}, + {0x6F, 0x8a}, + {0x70, 0x89}, + + {0x71, 0x34}, + {0x72, 0x45}, + {0x73, 0x56}, + {0x74, 0x77}, + {0x75, 0x78}, + {0x76, 0x89}, + + {0x77, 0x34}, + {0x78, 0x45}, + {0x79, 0x56}, + {0x7A, 0x77}, + {0x7B, 0x78}, + {0x7C, 0x89}, + + {0x7D, 0x22}, + {0x7E, 0x32}, + {0x7F, 0x34}, + {0x80, 0x45}, + {0x81, 0x56}, + {0x82, 0x67}, + {0x83, 0x1f}, + {0x84, 0x50}, +#endif + + //Shading + {0x50, 0x0b}, //R + {0x51, 0x0b}, //R + {0x52, 0x19}, //R + {0x53, 0x18}, //R + + {0x54, 0x10}, //G + {0x55, 0x00}, //G + {0x56, 0x08}, //G + {0x57, 0x00}, //G + + {0x58, 0x10}, //G + {0x59, 0x00}, //G + {0x5A, 0x08}, //G + {0x5B, 0x00}, //G + + {0x5C, 0x14}, //B + {0x5D, 0x0f}, //B + {0x5E, 0x24}, //B + {0x5F, 0x12}, //B + + {0x60, 0x32}, //# + {0x61, 0x00}, //# + {0x62, 0x67}, //# + + {0x6B, 0x23}, + {0x6C, 0x44}, + {0x6D, 0x44}, + {0x6E, 0x45}, + {0x6F, 0x44}, + {0x70, 0x00}, + + {0x71, 0x23}, + {0x72, 0x44}, + {0x73, 0x55}, + {0x74, 0x55}, + {0x75, 0x55}, + {0x76, 0x00}, + + {0x77, 0x23}, + {0x78, 0x44}, + {0x79, 0x55}, + {0x7A, 0x55}, + {0x7B, 0x55}, + {0x7C, 0x00}, + + {0x7D, 0x23}, + {0x7E, 0x44}, + {0x7F, 0x34}, + {0x80, 0x43}, + {0x81, 0x44}, + {0x82, 0x00}, + {0x83, 0x12}, + {0x84, 0x14}, + + + //Interpolation + {0xA0, 0x2F}, + {0xA1, 0xB7}, + {0xA2, 0xB7}, + {0xA3, 0xB7}, + {0xA4, 0x04}, + {0xA5, 0xFF}, + {0xA6, 0x06}, + {0xA7, 0xFF}, + {0xA8, 0x00}, + {0xA9, 0x00}, + {0xAA, 0x00}, + {0xAB, 0x00}, + {0xAC, 0x60}, + {0xAD, 0x18}, + {0xAE, 0x0c}, + {0xAF, 0x14}, + {0xB0, 0x08}, + {0xB1, 0x00}, + + + //Color Matrix for D65 + {0xC0, 0xAF},// C + {0xC1, 0x66}, + {0xC2, 0xd4}, + {0xC3, 0x06}, + {0xC4, 0xf0}, + {0xC5, 0x5a}, + {0xC6, 0xF6}, + {0xC7, 0xF9}, + {0xC8, 0xbf}, + {0xC9, 0x88}, + {0xCA, 0x00}, + {0xCB, 0x00}, + {0xCC, 0x00}, + {0xCD, 0x00}, + {0xCE, 0x00}, + //Color Matrix for CWF + {0xD0, 0x2F}, + {0xD1, 0x72}, + {0xD2, 0xC9}, + {0xD3, 0x04}, + {0xD4, 0xE3}, + {0xD5, 0x60}, + {0xD6, 0xFC}, + {0xD7, 0xF5}, + {0xD8, 0xb0}, + {0xD9, 0x99}, + {0xDA, 0xC3}, + {0xDB, 0x14}, + {0xDC, 0x3A}, + {0xDD, 0xAD}, + {0xDE, 0x09}, + + //Color Matrix for A + {0xE0, 0x2F}, + {0xE1, 0x5C}, + {0xE2, 0xDD}, + {0xE3, 0x06}, + {0xE4, 0xE0}, + {0xE5, 0x69}, + {0xE6, 0xF6}, + {0xE7, 0xE5}, + {0xE8, 0xAB}, + {0xE9, 0xAE}, + {0xEA, 0x6A}, + {0xEB, 0x01}, + {0xEC, 0x2D}, + {0xED, 0xEE}, + {0xEE, 0x04}, + + //IDP 2 + {0x00, 0x04}, + + //Gamma - R + {0x10, 0x00}, + {0x11, 0x06}, + {0x12, 0x0e}, + {0x13, 0x20}, + {0x14, 0x40}, + {0x15, 0x5e}, + {0x16, 0x74}, + {0x17, 0x87}, + {0x18, 0x98}, + {0x19, 0xa6}, + {0x1A, 0xb3}, + {0x1B, 0xca}, + {0x1C, 0xde}, + {0x1D, 0xf0}, + {0x1E, 0xf8}, + {0x1F, 0xff}, + + + //Gamma - G + {0x20, 0x00}, + {0x21, 0x06}, + {0x22, 0x0e}, + {0x23, 0x20}, + {0x24, 0x40}, + {0x25, 0x5e}, + {0x26, 0x74}, + {0x27, 0x87}, + {0x28, 0x98}, + {0x29, 0xa6}, + {0x2A, 0xb3}, + {0x2B, 0xca}, + {0x2C, 0xde}, + {0x2D, 0xf0}, + {0x2E, 0xf8}, + {0x2F, 0xff}, + + //Gamma - B + {0x30, 0x00}, + {0x31, 0x06}, + {0x32, 0x0e}, + {0x33, 0x20}, + {0x34, 0x40}, + {0x35, 0x5e}, + {0x36, 0x74}, + {0x37, 0x87}, + {0x38, 0x98}, + {0x39, 0xa6}, + {0x3A, 0xb3}, + {0x3B, 0xca}, + {0x3C, 0xde}, + {0x3D, 0xf0}, + {0x3E, 0xf8}, + {0x3F, 0xff}, + + //CSC + {0x60, 0x33}, + {0x61, 0x20}, + {0x62, 0xE4}, + {0x63, 0xFA}, + {0x64, 0x13}, + {0x65, 0x25}, + {0x66, 0x07}, + {0x67, 0xF5}, + {0x68, 0xEA}, + {0x69, 0x20}, + {0x6A, 0xC8}, + {0x6B, 0xC4}, + {0x6C, 0x84}, + {0x6D, 0x04}, + {0x6E, 0x0C}, + {0x6F, 0x00}, + + + //Edge + {0x80, 0xa2}, + {0x81, 0x10}, + {0x82, 0x10}, + {0x83, 0x04}, + {0x84, 0x0a}, + {0x85, 0x06}, + {0x86, 0x00}, + {0x87, 0x04}, + {0x88, 0x0a}, + {0x89, 0x06}, + {0x8a, 0x10}, + {0x8b, 0x30}, + {0x8c, 0x30}, + {0X90, 0x16}, + {0x91, 0x03}, + {0x93, 0xE0}, + + //Cr/Cb Coring + {0x94, 0x00}, + {0x95, 0x00}, + {0x96, 0x4c}, + {0x97, 0x66}, + {0x9A, 0xf5}, + {0xA1, 0x08}, + {0xA2, 0x10}, + {0xA3, 0x16}, + {0xA4, 0x14}, + {0xA5, 0x18}, + {0xA6, 0xa0}, + {0xA7, 0x06}, + {0xA8, 0x40}, + + {0xA9, 0x20}, + {0xAA, 0x28}, + {0xAc, 0xff}, + {0xAd, 0x09}, + {0xAe, 0x18}, + {0xAf, 0x18}, + + {0xB2, 0x24}, + {0xB3, 0x54}, + {0xB6, 0x08}, + + //Color Saturation + {0xBC, 0x10}, + {0xBD, 0x10}, + {0xBE, 0x10}, + {0xBF, 0x10}, + {0xc2, 0x12}, + {0xc3, 0x12}, + + //IDP 3 + {0x00, 0x05}, + + //Memory + {0x40, 0x15}, + {0x41, 0x28}, + {0x42, 0x04}, + {0x43, 0x15}, + {0x44, 0x28}, + {0x45, 0x04}, + {0x46, 0x15}, + {0x47, 0x28}, + {0x48, 0x04}, + + //Knee + {0x90, 0x00}, // + {0x91, 0x00}, //k + {0x92, 0x00}, //k + {0x93, 0x00}, //K + {0x94, 0x00}, //[ + {0x95, 0x00}, //k + {0x96, 0x00}, //k + + //ADG + #if 0 + {0x99, 0xC0}, + {0xA0, 0x10}, + {0xA1, 0x22}, + {0xA2, 0x36}, + {0xA3, 0x49}, + {0xA4, 0x5D}, + {0xA5, 0x70}, + {0xA6, 0x82}, + {0xA7, 0x94}, + {0xA8, 0xA5}, + {0xA9, 0xB5}, + {0xAA, 0xC3}, + {0xAB, 0xD1}, + {0xAC, 0xDE}, + {0xAD, 0xEA}, + {0xAE, 0xF5}, + {0xAF, 0xFF}, + //YXGMA + {0xB0, 0xc0}, //Y + {0xB1, 0x04}, //Y + {0xB8, 0x0f}, //D + {0xB9, 0x10}, //D + //{0xBA, 0x38}, / + //{0xBB, 0x39}, / + {0xC0, 0x03}, + {0xC1, 0x0E}, + {0xC2, 0x16}, + {0xC3, 0x24}, + {0xC4, 0x3F}, + {0xC5, 0x56}, + {0xC6, 0x6A}, + {0xC7, 0x7C}, + {0xC8, 0x8C}, + {0xC9, 0x98}, + {0xCA, 0xA2}, + {0xCB, 0xB8}, + {0xCC, 0xCD}, + {0xCD, 0xE2}, + {0xCE, 0xF0}, + {0xCF, 0xFF}, + #else + {0x99, 0x00}, + {0xA0, 0x00}, + {0xA1, 0x00}, + {0xA2, 0x00}, + {0xA3, 0x00}, + {0xA4, 0x00}, + {0xA5, 0x00}, + {0xA6, 0x00}, + {0xA7, 0x00}, + {0xA8, 0x00}, + {0xA9, 0x00}, + {0xAA, 0x00}, + {0xAB, 0x00}, + {0xAC, 0x00}, + {0xAD, 0x00}, + {0xAE, 0x00}, + {0xAF, 0x00}, + + //YXGMA + {0xB0, 0x00}, //Y + {0xB1, 0x00}, //Y + {0xB8, 0x00}, //D + {0xB9, 0x00}, //D + //{0xBA, 0x38}, / + //{0xBB, 0x39}, / + {0xC0, 0x00}, + {0xC1, 0x00}, + {0xC2, 0x00}, + {0xC3, 0x00}, + {0xC4, 0x00}, + {0xC5, 0x00}, + {0xC6, 0x00}, + {0xC7, 0x00}, + {0xC8, 0x00}, + {0xC9, 0x00}, + {0xCA, 0x00}, + {0xCB, 0x00}, + {0xCC, 0x00}, + {0xCD, 0x00}, + {0xCE, 0x00}, + {0xCF, 0x00}, + {0xe0, 0x01}, + {0xe1, 0x03}, + {0xe2, 0x04}, + {0xe3, 0x0c}, + {0xe4, 0x11}, + {0xe5, 0x16}, + {0xe6, 0x1b}, + {0xe7, 0x24}, + {0xe8, 0x30}, + #endif + //Sensor on + {0x00, 0x00}, + {0x03, 0xc5}, + {0x00, 0x01}, + {0x10, 0x84}, + {0x00, 0x02}, + {0x10, 0xd3}, + {0xff, 0xff}, + + +#endif }; /* 1600X1200 UXGA */ @@ -1516,6 +2225,7 @@ static int sensor_write(struct i2c_client *client, u8 reg, u8 val) //buf[0] = reg >> 8; buf[0] = reg & 0xFF; buf[1] = val; + //printk("%s----%d-----\n",__func__,__LINE__); msg->addr = client->addr; msg->flags = client->flags; @@ -1767,6 +2477,7 @@ static int sensor_init(struct v4l2_subdev *sd, u32 val) goto sensor_INIT_ERR; } #endif + ret = sensor_write_array(client, sensor_init_data); if (ret != 0) { diff --git a/drivers/media/video/siv121d.c b/drivers/media/video/siv121d.c new file mode 100755 index 000000000000..41a06b867160 --- /dev/null +++ b/drivers/media/video/siv121d.c @@ -0,0 +1,2728 @@ + +/* +o* Driver for MT9M001 CMOS Image Sensor from Micron + * + * Copyright (C) 2008, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include + +static int debug; +module_param(debug, int, S_IRUGO|S_IWUSR); + +#define dprintk(level, fmt, arg...) do { \ + if (debug >= level) \ + printk(KERN_WARNING fmt , ## arg); } while (0) + +#define SENSOR_TR(format, ...) printk(KERN_ERR format, ## __VA_ARGS__) +#define SENSOR_DG(format, ...) dprintk(1, format, ## __VA_ARGS__) + + +#define _CONS(a,b) a##b +#define CONS(a,b) _CONS(a,b) + +#define __STR(x) #x +#define _STR(x) __STR(x) +#define STR(x) _STR(x) + +#define MIN(x,y) ((xy) ? x: y) + +/* Sensor Driver Configuration */ +#define SENSOR_NAME RK29_CAM_SENSOR_SIV121D +#define SENSOR_V4L2_IDENT V4L2_IDENT_SIV121D +#define SENSOR_ID 0xde +#define SENSOR_MIN_WIDTH 640//176 +#define SENSOR_MIN_HEIGHT 480//144 +#define SENSOR_MAX_WIDTH 640 +#define SENSOR_MAX_HEIGHT 480 +#define SENSOR_INIT_WIDTH 640 /* Sensor pixel size for sensor_init_data array */ +#define SENSOR_INIT_HEIGHT 480 +#define SENSOR_INIT_WINSEQADR sensor_vga +#define SENSOR_INIT_PIXFMT V4L2_MBUS_FMT_YUYV8_2X8 + +#define CONFIG_SENSOR_WhiteBalance 1 +#define CONFIG_SENSOR_Brightness 0 +#define CONFIG_SENSOR_Contrast 0 +#define CONFIG_SENSOR_Saturation 0 +#define CONFIG_SENSOR_Effect 1 +#define CONFIG_SENSOR_Scene 1 +#define CONFIG_SENSOR_DigitalZoom 0 +#define CONFIG_SENSOR_Focus 0 +#define CONFIG_SENSOR_Exposure 1 +#define CONFIG_SENSOR_Flash 0 +#define CONFIG_SENSOR_Mirror 0 +#define CONFIG_SENSOR_Flip 0 + +#define CONFIG_SENSOR_I2C_SPEED 250000 /* Hz */ +/* Sensor write register continues by preempt_disable/preempt_enable for current process not be scheduled */ +#define CONFIG_SENSOR_I2C_NOSCHED 0 +#define CONFIG_SENSOR_I2C_RDWRCHK 0 + +#define SENSOR_BUS_PARAM (SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |\ + SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW |\ + SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8 |SOCAM_MCLK_24MHZ) + +#define COLOR_TEMPERATURE_CLOUDY_DN 6500 +#define COLOR_TEMPERATURE_CLOUDY_UP 8000 +#define COLOR_TEMPERATURE_CLEARDAY_DN 5000 +#define COLOR_TEMPERATURE_CLEARDAY_UP 6500 +#define COLOR_TEMPERATURE_OFFICE_DN 3500 +#define COLOR_TEMPERATURE_OFFICE_UP 5000 +#define COLOR_TEMPERATURE_HOME_DN 2500 +#define COLOR_TEMPERATURE_HOME_UP 3500 + +#define SENSOR_NAME_STRING(a) STR(CONS(SENSOR_NAME, a)) +#define SENSOR_NAME_VARFUN(a) CONS(SENSOR_NAME, a) + +#define SENSOR_AF_IS_ERR (0x00<<0) +#define SENSOR_AF_IS_OK (0x01<<0) +#define SENSOR_INIT_IS_ERR (0x00<<28) +#define SENSOR_INIT_IS_OK (0x01<<28) + +struct reginfo +{ + u8 reg; + u8 val; +}; + +/* init 640X480 VGA */ +static struct reginfo sensor_init_data[] = +{ + {0x00, 0x01}, + {0x03, 0x0a}, + + {0x00, 0x00}, + {0x03, 0x04}, + {0x10, 0x85}, + {0x11, 0x74}, + + {0x00, 0x01}, + //{0x03, 0x0a}, + {0x04, 0x01}, + {0x06, 0x04}, + + {0x10, 0x46}, + {0x11, 0x23}, + {0x12, 0x21}, + + {0x17, 0x86}, //ABS 1.74V + {0x18, 0x00}, + + {0x20, 0x00}, + {0x21, 0x05}, + {0x22, 0x01}, + {0x23, 0x69}, + + {0x40, 0x0F}, + {0x41, 0x90}, + {0x42, 0xd2}, + {0x43, 0x00}, + + // AE + {0x00, 0x02}, + {0x11, 0x0c}, + {0x12, 0x64}, + {0x14, 0x60}, + {0x34, 0x96}, + {0x40, 0x48}, + {0x5f, 0x01}, + {0x41, 0x28}, + {0x42, 0x28}, + {0x44, 0x08}, + {0x45, 0x08}, + {0x46, 0x15}, + {0x47, 0x1c}, + {0x48, 0x20}, + {0x49, 0x21}, + {0x4a, 0x23}, + {0x4b, 0x24}, + {0x4c, 0x25}, + {0x4d, 0x28}, + {0x4e, 0x1c}, + {0x4f, 0x15}, + {0x50, 0x12}, + {0x51, 0x10}, + {0x52, 0x0e}, + {0x53, 0x0c}, + {0x54, 0x0b}, + {0x55, 0x0a}, + {0x90, 0x80}, + {0x91, 0x80}, + {0x10, 0x80}, + + // AWB + {0x00, 0x03}, + {0x10, 0xd0}, + {0x11, 0xc1}, + {0x13, 0x7e}, //Cr target + {0x14, 0x7d}, //Cb target + {0x15, 0xd8}, // R gain Top + {0x16, 0x7c}, // R gain bottom + {0x17, 0xe0}, // B gain Top + {0x18, 0x88}, // B gain bottom 0x80 + {0x19, 0x8c}, // Cr top value 0x90 + {0x1a, 0x64}, // Cr bottom value 0x70 + {0x1b, 0x98}, // Cb top value 0x90 + {0x1c, 0x6c}, // Cb bottom value 0x70 + {0x1d, 0x94}, // 0xa0 + {0x1e, 0x6c}, // 0x60 + {0x20, 0xe8}, // AWB luminous top value + {0x21, 0x30}, // AWB luminous bottom value 0x20 + {0x22, 0xb8}, + {0x23, 0x10}, + {0x25, 0x08}, + {0x26, 0x20}, + {0x27, 0x08}, // BRTSRT + {0x28, 0x0f}, // BRTEND + {0x29, 0xba}, // BRTRGNBOT + {0x2a, 0xa0}, // BRTBGNTOP + + {0x40, 0x01}, + {0x41, 0x03}, + {0x42, 0x08}, + {0x43, 0x10}, + {0x44, 0x13}, + {0x45, 0x8f}, + {0x46, 0xfc}, + + {0x62, 0x80}, + {0x63, 0x90}, // R D30 to D20 + {0x64, 0xd0}, // B D30 to D20 + {0x65, 0x98}, // R D20 to D30 + {0x66, 0xd0}, // B D20 to D30 + + // IDP + {0x00, 0x04}, + {0x10, 0xff}, + {0x11, 0x0d},//1 d}, + {0x12, 0xfd}, + + // DPCBNR + {0x18, 0xbe}, // DPCNRCTRL + {0x19, 0x00}, // DPCTHV + {0x1A, 0x00}, // DPCTHVSLP + {0x1B, 0x00}, // DPCTHVDIFSRT + {0x1C, 0x0f}, // DPCTHVDIFSLP + {0x1d, 0xFF}, // DPCTHVMAX + + {0x1E, 0x04}, // BNRTHV 0c + {0x1F, 0x04}, // BNRTHVSLPN 10 + {0x20, 0x10}, // BNRTHVSLPD + {0x21, 0x00}, // BNRNEICNT + {0x22, 0x10}, // STRTNOR + {0x23, 0x40}, // STRTDRK + {0x24, 0x00}, + + // Gamma + {0x31, 0x08}, //0x08 + {0x32, 0x12}, //0x10 + {0x33, 0x24}, //0x1B + {0x34, 0x47}, //0x37 + {0x35, 0x64}, //0x4D + {0x36, 0x7c}, //0x60 + {0x37, 0x8f}, //0x72 + {0x38, 0x9f}, //0x82 + {0x39, 0xad}, //0x91 + {0x3a, 0xba}, //0xA0 + {0x3b, 0xcf}, //0xBA + {0x3c, 0xe2}, //0xD3 + {0x3d, 0xf0}, //0xEA + + // Shading Register Setting + {0x40, 0x06}, + {0x41, 0x44}, + {0x42, 0x44}, + {0x43, 0x20}, + {0x44, 0x22}, // left R gain[7:4], right R gain[3:0] + {0x45, 0x22}, // top R gain[7:4], bottom R gain[3:0] + {0x46, 0x00}, // left G gain[7:4], right G gain[3:0] + {0x47, 0x11}, // top G gain[7:4], bottom G gain[3:0] + {0x48, 0x00}, // left B gain[7:4], right B gain[3:0] + {0x49, 0x00}, // top B gain[7:4], bottom B gain[3:0] + {0x4a, 0x04}, // X-axis center high[3:2], Y-axis center high[1:0] + {0x4b, 0x48}, // X-axis center low[7:0] + {0x4c, 0xe8}, // Y-axis center low[7:0] + {0x4d, 0x84}, // Shading Center Gain + {0x4e, 0x00}, // Shading R Offset + {0x4f, 0x00}, // Shading Gr Offset + {0x50, 0x00}, // Shading B Offset + + // Interpolation + {0x60, 0x7f}, + {0x61, 0x08}, // INTCTRL outdoor + + // Color matrix (D65) - Daylight + {0x71, 0x34}, + {0x72, 0xCE}, + {0x73, 0xFe}, + {0x74, 0x13}, + {0x75, 0x25}, + {0x76, 0x08}, + {0x77, 0xec}, + {0x78, 0xcd}, + {0x79, 0x47}, + + // Color matrix (D20) - A + {0x83, 0x38}, //0x3c + {0x84, 0xd1}, //0xc6 + {0x85, 0xf7}, //0xff + {0x86, 0x12}, //0x12 + {0x87, 0x25}, //0x24 + {0x88, 0x09}, //0x0a + {0x89, 0xed}, //0xed + {0x8a, 0xbb}, //0xc2 + {0x8b, 0x58}, //0x51 + + {0x8c, 0x10}, //CMA select + + //G Edge + {0x90, 0x18}, //Upper gain + {0x91, 0x28}, //down gain + {0x92, 0x55}, //[7:4] upper coring [3:0] down coring + {0x9a, 0x40}, + {0x9b, 0x40}, + {0x9c, 0x38}, //edge suppress start + {0x9d, 0x30}, //edge suppress slope + + {0xa9, 0x11}, + {0xaa, 0x11}, + + {0xb9, 0x30}, // nightmode 38 at gain 0x48 5fps + {0xba, 0x44}, // nightmode 80 at gain 0x48 5fps + + {0xc0, 0x24}, + {0xc1, 0x00}, + {0xc2, 0x80}, + {0xc3, 0x00}, + {0xc4, 0xe0}, + + {0xde, 0x80}, + + {0xe5, 0x15}, //MEMSPDA + {0xe6, 0x02}, //MEMSPDB + {0xe7, 0x04}, //MEMSPDC + + //Sensor On + {0x00, 0x01}, + {0x03, 0x01} // SNR Enable + //{0xff, 0xff} +}; + + +/* 1280X1024 SXGA */ +static struct reginfo sensor_sxga[] = +{ + {0x00,0x00} +}; + +/* 800X600 SVGA*/ +static struct reginfo sensor_svga[] = +{ + {0x0, 0x0}, +}; + +/* 640X480 VGA @30fps for both preview & capture. */ +static struct reginfo sensor_vga[] = +{ + {0x00, 0x01}, + {0x06, 0x04}, + {0x12, 0x3d}, + {0x00, 0x04}, + {0xc0, 0x24}, + {0xc1, 0x00}, + {0xc2, 0x80}, + {0xc3, 0x00}, + {0xc4, 0xe0}, +}; + +/* 352X288 CIF @30fps*/ +static struct reginfo sensor_cif[] = +{ + {0x00, 0x01}, + {0x06, 0x00}, + {0x12, 0x3d}, + {0x00, 0x04}, + {0xc0, 0x11}, + {0xc1, 0x00}, + {0xc2, 0x60}, + {0xc3, 0x00}, + {0xc4, 0x20}, +}; + +/* 320*240 QVGA */ +static struct reginfo sensor_qvga[] = +{ + {0x00, 0x01}, + {0x06, 0x06}, + {0x12, 0x3d}, + {0x00, 0x04}, + {0xc0, 0x10}, + {0xc1, 0x00}, + {0xc2, 0x40}, + {0xc3, 0x00}, + {0xc4, 0xf0}, +}; + +/* 176X144 QCIF*/ +static struct reginfo sensor_qcif[] = +{ + {0x00, 0x01}, + {0x06, 0x02}, + {0x00, 0x04}, + {0x12, 0x3d}, + {0xc0, 0x00}, + {0xc1, 0x00}, + {0xc2, 0xb0}, + {0xc3, 0x00}, + {0xc4, 0x90}, +}; + +static struct reginfo sensor_ClrFmt_YUYV[]= +{ + {0x00, 0x04}, + {0x12, 0x3d}, +}; + +static struct reginfo sensor_ClrFmt_UYVY[]= +{ + {0x00, 0x04}, + {0x12, 0xcd}, +}; + + +#if CONFIG_SENSOR_WhiteBalance +static struct reginfo sensor_WhiteB_Auto[]= +{ + {0x00, 0x03}, + {0x10, 0xd3}, + {0xff,0xff} +}; +/* Cloudy Colour Temperature : 6500K - 8000K */ +static struct reginfo sensor_WhiteB_Cloudy[]= +{ + {0x00, 0x03}, + {0x10, 0x00}, // disable AWB + {0x60, 0xb4}, + {0x61, 0x74}, + {0xff,0xff} + +}; +/* ClearDay Colour Temperature : 5000K - 6500K */ +static struct reginfo sensor_WhiteB_ClearDay[]= +{ + {0x00, 0x03}, + {0x10, 0x00}, // disable AWB + {0x60, 0xd8}, + {0x61, 0x90}, + {0xff,0xff} + +}; +/* Office Colour Temperature : 3500K - 5000K */ +static struct reginfo sensor_WhiteB_TungstenLamp1[]= +{ + {0x00, 0x03}, + {0x10, 0x00}, // disable AWB + {0x60, 0x80}, + {0x61, 0xe0}, + {0xff,0xff} +}; +/* Home Colour Temperature : 2500K - 3500K */ +static struct reginfo sensor_WhiteB_TungstenLamp2[]= +{ + {0x00, 0x03}, + {0x10, 0x00}, // disable AWB + {0x60, 0xb8}, + {0x61, 0xcc}, + {0xff,0xff} +}; +static struct reginfo *sensor_WhiteBalanceSeqe[] = {sensor_WhiteB_Auto, sensor_WhiteB_TungstenLamp1,sensor_WhiteB_TungstenLamp2, + sensor_WhiteB_ClearDay, sensor_WhiteB_Cloudy,NULL, +}; +#endif + +#if CONFIG_SENSOR_Brightness +static struct reginfo sensor_Brightness0[]= +{ + // Brightness -2 + {0x00, 0x04}, + {0xab, 0xb0}, + {0xff,0xff} +}; + +static struct reginfo sensor_Brightness1[]= +{ + // Brightness -1 + {0x00, 0x04}, + {0xab, 0xa0}, + {0xff,0xff} +}; + +static struct reginfo sensor_Brightness2[]= +{ + // Brightness 0 + {0x00, 0x04}, + {0xab, 0x82}, + {0xff,0xff} +}; + +static struct reginfo sensor_Brightness3[]= +{ + // Brightness +1 + {0x00, 0x04}, + {0xab, 0x00}, + {0xff,0xff} +}; + +static struct reginfo sensor_Brightness4[]= +{ + // Brightness +2 + {0x00, 0x04}, + {0xab, 0x10}, + {0xff,0xff} +}; + +static struct reginfo sensor_Brightness5[]= +{ + // Brightness +3 + {0x00, 0x04}, + {0xab, 0x20}, + {0xff,0xff} +}; +static struct reginfo *sensor_BrightnessSeqe[] = {sensor_Brightness0, sensor_Brightness1, sensor_Brightness2, sensor_Brightness3, + sensor_Brightness4, sensor_Brightness5,NULL, +}; + +#endif + +#if CONFIG_SENSOR_Effect +static struct reginfo sensor_Effect_Normal[] = +{ + {0x00,0x04}, + {0x90,0x14}, + {0x91,0x18}, + {0xb6,0x00}, + {0xff,0xff} +}; + +static struct reginfo sensor_Effect_WandB[] = +{ + //mono + {0x00,0x04}, + {0x90,0x14}, + {0x91,0x18}, + {0xb6,0x40}, + {0xff,0xff} +}; + +static struct reginfo sensor_Effect_Sepia[] = +{ + {0x00,0x04}, + {0x90, 0x14}, + {0x91, 0x18}, + {0xB6, 0x80}, + {0xB7, 0x58}, + {0xB8, 0x98}, + {0xff,0xff} +}; + +static struct reginfo sensor_Effect_Negative[] = +{ + //Negative + {0x00,0x04}, + {0x90, 0x18}, + {0x91, 0x18}, + {0xB6, 0x20}, + {0xff,0xff} +}; +static struct reginfo sensor_Effect_Bluish[] = +{ + {0x00,0x04}, + {0x90, 0x14}, + {0x91, 0x18}, + {0xB6, 0x80}, + {0xB7, 0xb8}, + {0xB8, 0x50}, + {0xff,0xff} +}; + +static struct reginfo sensor_Effect_Green[] = +{ + // Greenish + {0x00,0x04}, + {0x90, 0x14}, + {0x91, 0x18}, + {0xB6, 0x80}, + {0xB7, 0x68}, + {0xB8, 0x68}, + {0xff,0xff} +}; +static struct reginfo *sensor_EffectSeqe[] = {sensor_Effect_Normal, sensor_Effect_WandB, sensor_Effect_Negative,sensor_Effect_Sepia, + /*sensor_Effect_Bluish,*/ sensor_Effect_Green,NULL, +}; +#endif +#if CONFIG_SENSOR_Exposure +static struct reginfo sensor_Exposure0[]= +{ + {0x00,0x02}, + {0x12,0x44}, + {0x14,0x44}, + {0xff,0xff} +}; + +static struct reginfo sensor_Exposure1[]= +{ + {0x00,0x02}, + {0x12,0x54}, + {0x14,0x54}, + {0xff,0xff} +}; + +static struct reginfo sensor_Exposure2[]= +{ + {0x00,0x02}, + {0x12,0x54}, + {0x14,0x54}, + {0xff,0xff} +}; + +static struct reginfo sensor_Exposure3[]= +{ + {0x00,0x02}, + {0x12,0x78}, + {0x14,0x78}, + {0xff,0xff} +}; + +static struct reginfo sensor_Exposure4[]= +{ + {0x00,0x02}, + {0x12,0x84}, + {0x14,0x84}, + {0xff,0xff} +}; + +static struct reginfo sensor_Exposure5[]= +{ + {0x00,0x02}, + {0x12,0x94}, + {0x14,0x94}, + {0xff,0xff} +}; + +static struct reginfo sensor_Exposure6[]= +{ + {0x00,0x02}, + {0x12,0xa4}, + {0x14,0xa4}, + {0xff,0xff} +}; + +static struct reginfo *sensor_ExposureSeqe[] = {sensor_Exposure0, sensor_Exposure1, sensor_Exposure2, sensor_Exposure3, + sensor_Exposure4, sensor_Exposure5,sensor_Exposure6,NULL, +}; +#endif +#if CONFIG_SENSOR_Saturation +static struct reginfo sensor_Saturation0[]= +{ + {0x00, 0x00} +}; + +static struct reginfo sensor_Saturation1[]= +{ + {0x00, 0x00} +}; + +static struct reginfo sensor_Saturation2[]= +{ + {0x00, 0x00} +}; +static struct reginfo *sensor_SaturationSeqe[] = {sensor_Saturation0, sensor_Saturation1, sensor_Saturation2, NULL,}; + +#endif +#if CONFIG_SENSOR_Contrast +static struct reginfo sensor_Contrast0[]= +{ + // Brightness +3 + {0x00, 0x04}, + {0xa8, 0xb0}, + {0xff,0xff} +}; + +static struct reginfo sensor_Contrast1[]= +{ + // Brightness +3 + {0x00, 0x04}, + {0xa8, 0xa0}, + {0xff,0xff} +}; + +static struct reginfo sensor_Contrast2[]= +{ + // Brightness +3 + {0x00, 0x04}, + {0xa8, 0x90}, + {0xff,0xff} +}; + +static struct reginfo sensor_Contrast3[]= +{ + // Brightness +3 + {0x00, 0x04}, + {0xa8, 0x00}, + {0xff,0xff} +}; + +static struct reginfo sensor_Contrast4[]= +{ + // Brightness +3 + {0x00, 0x04}, + {0xa8, 0x10}, + {0xff,0xff} +}; + + +static struct reginfo sensor_Contrast5[]= +{ + // Brightness +3 + {0x00, 0x04}, + {0xa8, 0x20}, + {0xff,0xff} +}; + +static struct reginfo sensor_Contrast6[]= +{ + // Brightness +3 + {0x00, 0x04}, + {0xa8, 0x30}, + {0xff,0xff} +}; +static struct reginfo *sensor_ContrastSeqe[] = {sensor_Contrast0, sensor_Contrast1, sensor_Contrast2, sensor_Contrast3, + sensor_Contrast4, sensor_Contrast5, sensor_Contrast6, NULL, +}; + +#endif +#if CONFIG_SENSOR_Mirror +static struct reginfo sensor_MirrorOn[]= +{ + {0x00, 0x00}, + {0xff,0xff} + +}; + +static struct reginfo sensor_MirrorOff[]= +{ + {0x00, 0x00}, + {0xff,0xff} + +}; +static struct reginfo *sensor_MirrorSeqe[] = {sensor_MirrorOff, sensor_MirrorOn,NULL,}; +#endif +#if CONFIG_SENSOR_Flip +static struct reginfo sensor_FlipOn[]= +{ + {0x00, 0x00}, + {0xff,0xff} +}; + +static struct reginfo sensor_FlipOff[]= +{ + {0x00, 0x00}, + {0xff,0xff} +}; +static struct reginfo *sensor_FlipSeqe[] = {sensor_FlipOff, sensor_FlipOn,NULL,}; + +#endif +#if CONFIG_SENSOR_Scene +static struct reginfo sensor_SceneAuto[] = +{ + {0x00, 0x02}, + {0x40, 0x45}, + {0x00, 0x04}, + {0xab, 0x00}, + {0xff,0xff} +}; + +static struct reginfo sensor_SceneNight[] = +{ + {0x00, 0x02}, + {0x40, 0x60}, + {0x00, 0x04}, + {0xab, 0x30}, + {0xff,0xff} +}; +static struct reginfo *sensor_SceneSeqe[] = {sensor_SceneAuto, sensor_SceneNight,NULL,}; + +#endif +#if CONFIG_SENSOR_DigitalZoom +static struct reginfo sensor_Zoom0[] = +{ + {0x00, 0x00}, + {0xff,0xff} + +}; + +static struct reginfo sensor_Zoom1[] = +{ + {0x00, 0x00}, + {0xff,0xff} +}; + +static struct reginfo sensor_Zoom2[] = +{ + {0x00, 0x00}, + {0xff,0xff} +}; + + +static struct reginfo sensor_Zoom3[] = +{ + {0x00, 0x00}, + {0xff,0xff} +}; +static struct reginfo *sensor_ZoomSeqe[] = {sensor_Zoom0, sensor_Zoom1, sensor_Zoom2, sensor_Zoom3, NULL,}; +#endif +static const struct v4l2_querymenu sensor_menus[] = +{ + #if CONFIG_SENSOR_WhiteBalance + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 0, .name = "auto", .reserved = 0, }, { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 1, .name = "incandescent", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 2, .name = "fluorescent", .reserved = 0,}, { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 3, .name = "daylight", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 4, .name = "cloudy-daylight", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Effect + { .id = V4L2_CID_EFFECT, .index = 0, .name = "none", .reserved = 0, }, { .id = V4L2_CID_EFFECT, .index = 1, .name = "mono", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 2, .name = "negative", .reserved = 0,}, { .id = V4L2_CID_EFFECT, .index = 3, .name = "sepia", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 4, .name = "posterize", .reserved = 0,} ,{ .id = V4L2_CID_EFFECT, .index = 5, .name = "aqua", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Scene + { .id = V4L2_CID_SCENE, .index = 0, .name = "auto", .reserved = 0,} ,{ .id = V4L2_CID_SCENE, .index = 1, .name = "night", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Flash + { .id = V4L2_CID_FLASH, .index = 0, .name = "off", .reserved = 0, }, { .id = V4L2_CID_FLASH, .index = 1, .name = "auto", .reserved = 0,}, + { .id = V4L2_CID_FLASH, .index = 2, .name = "on", .reserved = 0,}, { .id = V4L2_CID_FLASH, .index = 3, .name = "torch", .reserved = 0,}, + #endif +}; + +static const struct v4l2_queryctrl sensor_controls[] = +{ + #if CONFIG_SENSOR_WhiteBalance + { + .id = V4L2_CID_DO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "White Balance Control", + .minimum = 0, + .maximum = 4, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Brightness + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness Control", + .minimum = -3, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Effect + { + .id = V4L2_CID_EFFECT, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Effect Control", + .minimum = 0, + .maximum = 5, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Exposure + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure Control", + .minimum = 0, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Saturation + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation Control", + .minimum = 0, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Contrast + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast Control", + .minimum = -3, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Mirror + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + #endif + + #if CONFIG_SENSOR_Flip + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + #endif + + #if CONFIG_SENSOR_Scene + { + .id = V4L2_CID_SCENE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Scene Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_DigitalZoom + { + .id = V4L2_CID_ZOOM_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DigitalZoom Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_ZOOM_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DigitalZoom Control", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Focus + { + .id = V4L2_CID_FOCUS_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Focus Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_FOCUS_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Focus Control", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 125, + }, + #endif + + #if CONFIG_SENSOR_Flash + { + .id = V4L2_CID_FLASH, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Flash Control", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif +}; + +static int sensor_probe(struct i2c_client *client, const struct i2c_device_id *did); +static int sensor_video_probe(struct soc_camera_device *icd, struct i2c_client *client); +static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl); +static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl); +static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg); +static int sensor_resume(struct soc_camera_device *icd); +static int sensor_set_bus_param(struct soc_camera_device *icd,unsigned long flags); +static unsigned long sensor_query_bus_param(struct soc_camera_device *icd); +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +static int sensor_deactivate(struct i2c_client *client); + +static struct soc_camera_ops sensor_ops = +{ + .suspend = sensor_suspend, + .resume = sensor_resume, + .set_bus_param = sensor_set_bus_param, + .query_bus_param = sensor_query_bus_param, + .controls = sensor_controls, + .menus = sensor_menus, + .num_controls = ARRAY_SIZE(sensor_controls), + .num_menus = ARRAY_SIZE(sensor_menus), +}; + +/* only one fixed colorspace per pixelcode */ +struct sensor_datafmt { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; +}; + +/* Find a data format by a pixel code in an array */ +static const struct sensor_datafmt *sensor_find_datafmt( + enum v4l2_mbus_pixelcode code, const struct sensor_datafmt *fmt, + int n) +{ + int i; + for (i = 0; i < n; i++) + if (fmt[i].code == code) + return fmt + i; + + return NULL; +} + +static const struct sensor_datafmt sensor_colour_fmts[] = { + {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG} +}; + +typedef struct sensor_info_priv_s +{ + int whiteBalance; + int brightness; + int contrast; + int saturation; + int effect; + int scene; + int digitalzoom; + int focus; + int flash; + int exposure; + bool snap2preview; + bool video2preview; + unsigned char mirror; /* HFLIP */ + unsigned char flip; /* VFLIP */ + unsigned int winseqe_cur_addr; + struct sensor_datafmt fmt; + unsigned int funmodule_state; +} sensor_info_priv_t; + +struct sensor +{ + struct v4l2_subdev subdev; + struct i2c_client *client; + sensor_info_priv_t info_priv; + int model; /* V4L2_IDENT_OV* codes from v4l2-chip-ident.h */ +#if CONFIG_SENSOR_I2C_NOSCHED + atomic_t tasklock_cnt; +#endif + struct rk29camera_platform_data *sensor_io_request; + struct rk29camera_gpio_res *sensor_gpio_res; +}; + +static struct sensor* to_sensor(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct sensor, subdev); +} + +static int sensor_task_lock(struct i2c_client *client, int lock) +{ +#if CONFIG_SENSOR_I2C_NOSCHED + int cnt = 3; + struct sensor *sensor = to_sensor(client); + + if (lock) { + if (atomic_read(&sensor->tasklock_cnt) == 0) { + while ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt>0)) { + SENSOR_TR("\n %s will obtain i2c in atomic, but i2c bus is locked! Wait...\n",SENSOR_NAME_STRING()); + msleep(35); + cnt--; + } + if ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt<=0)) { + SENSOR_TR("\n %s obtain i2c fail in atomic!!\n",SENSOR_NAME_STRING()); + goto sensor_task_lock_err; + } + preempt_disable(); + } + + atomic_add(1, &sensor->tasklock_cnt); + } else { + if (atomic_read(&sensor->tasklock_cnt) > 0) { + atomic_sub(1, &sensor->tasklock_cnt); + + if (atomic_read(&sensor->tasklock_cnt) == 0) + preempt_enable(); + } + } + return 0; +sensor_task_lock_err: + return -1; +#else + return 0; +#endif + +} + +/* sensor register write */ +static int sensor_write(struct i2c_client *client, u8 reg, u8 val) +{ + int err,cnt; + u8 buf[2]; + struct i2c_msg msg[1]; + + buf[0] = reg & 0xFF; + buf[1] = val; + + msg->addr = client->addr; + msg->flags = client->flags; + msg->buf = buf; + msg->len = sizeof(buf); + msg->scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg->read_type = 0; /* fpga i2c:0==I2C_NORMAL : direct use number not enum for don't want include spi_fpga.h */ + + cnt = 3; + err = -EAGAIN; + + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + err = i2c_transfer(client->adapter, msg, 1); + + if (err >= 0) { + return 0; + } else { + SENSOR_TR("\n %s write reg(0x%x, val:0x%x) failed, try to write again!\n",SENSOR_NAME_STRING(),reg, val); + udelay(10); + } + } + + return err; +} + +/* sensor register read */ +static int sensor_read(struct i2c_client *client, u8 reg, u8 *val) +{ + int err,cnt; + //u8 buf[2]; + u8 buf[1]; + struct i2c_msg msg[2]; + + //buf[0] = reg >> 8; + buf[0] = reg; + buf[1] = reg & 0xFF; + + msg[0].addr = client->addr; + msg[0].flags = client->flags; + msg[0].buf = buf; + msg[0].len = sizeof(buf); + msg[0].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg[0].read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */ + + msg[1].addr = client->addr; + msg[1].flags = client->flags|I2C_M_RD; + msg[1].buf = buf; + msg[1].len = 1; + msg[1].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg[1].read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */ + + cnt = 1; + err = -EAGAIN; + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + err = i2c_transfer(client->adapter, msg, 2); + + if (err >= 0) { + *val = buf[0]; + return 0; + } else { + SENSOR_TR("\n %s read reg(0x%x val:0x%x) failed, try to read again! \n",SENSOR_NAME_STRING(),reg, *val); + udelay(10); + } + } + + return err; +} +static int sensor_effect_write_array(struct i2c_client *client,struct reginfo *regarray) +{ + int err; + int i = 0; + + //for(i=0; i < sizeof(sensor_init_data) / 2;i++) + while((regarray[i].reg != 0xff) && (regarray[i].val != 0xff)) + { + err = sensor_write(client, regarray[i].reg, regarray[i].val); + if (err != 0) + { + SENSOR_TR("%s..write failed current i = %d\n", SENSOR_NAME_STRING(),i); + return err; + } + i++; + } + + return 0; + +} +/* write a array of registers */ +#if 1 +static int sensor_write_array(struct i2c_client *client, struct reginfo *regarray) +{ + int err; + int i = 0; + + for(i=0; i < sizeof(sensor_init_data) / 2;i++) + //while((regarray[i].reg != 0xff) && (regarray[i].val != 0xff)) + { + err = sensor_write(client, regarray[i].reg, regarray[i].val); + if (err != 0) + { + SENSOR_TR("%s..write failed current i = %d\n", SENSOR_NAME_STRING(),i); + return err; + } + //i++; + } + + return 0; +} +#else +static int sensor_write_array(struct i2c_client *client, struct reginfo *regarray) +{ + int err; + int i = 0; + u8 val_read; + while (regarray[i].reg != 0) + { + err = sensor_write(client, regarray[i].reg, regarray[i].val); + if (err != 0) + { + SENSOR_TR("%s..write failed current i = %d\n", SENSOR_NAME_STRING(),i); + return err; + } + err = sensor_read(client, regarray[i].reg, &val_read); + SENSOR_TR("%s..reg[0x%x]=0x%x,0x%x\n", SENSOR_NAME_STRING(),regarray[i].reg, val_read, regarray[i].val); + i++; + } + return 0; +} +#endif + +#if CONFIG_SENSOR_I2C_RDWRCHK +static int sensor_check_array(struct i2c_client *client, struct reginfo *regarray) +{ + int ret; + int i = 0; + + u8 value; + + SENSOR_DG("%s >>>>>>>>>>>>>>>>>>>>>>\n",__FUNCTION__); + for(i=0;ipowerdown) { + ret = icl->powerdown(icd->pdev, on); + if (ret == RK29_CAM_IO_SUCCESS) { + if (on == 0) { + mdelay(2); + if (icl->reset) + icl->reset(icd->pdev); + } + } else if (ret == RK29_CAM_EIO_REQUESTFAIL) { + ret = -ENODEV; + goto sensor_power_end; + } + } + break; + } + case Sensor_Flash: + { + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + if (sensor->sensor_io_request && sensor->sensor_io_request->sensor_ioctrl) { + sensor->sensor_io_request->sensor_ioctrl(icd->pdev,Cam_Flash, on); + } + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown!",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } +sensor_power_end: + return ret; +} + +static int sensor_init(struct v4l2_subdev *sd, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + const struct sensor_datafmt *fmt; + int ret; + + SENSOR_DG("\n%s..%s.. \n",SENSOR_NAME_STRING(),__FUNCTION__); + + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + /* soft reset */ + if (sensor_task_lock(client,1)<0) + goto sensor_INIT_ERR; + /* ret = sensor_write(client, 0x12, 0x80); + if (ret != 0) + { + SENSOR_TR("%s soft reset sensor failed\n",SENSOR_NAME_STRING()); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + mdelay(5); */ //delay 5 microseconds + + ret = sensor_write_array(client, sensor_init_data); + if (ret != 0) + { + SENSOR_TR("error: %s initial failed\n",SENSOR_NAME_STRING()); + goto sensor_INIT_ERR; + } + + sensor_task_lock(client,0); + + sensor->info_priv.winseqe_cur_addr = (int)SENSOR_INIT_WINSEQADR; + fmt = sensor_find_datafmt(SENSOR_INIT_PIXFMT,sensor_colour_fmts, ARRAY_SIZE(sensor_colour_fmts)); + if (!fmt) { + SENSOR_TR("error: %s initial array colour fmts is not support!!",SENSOR_NAME_STRING()); + ret = -EINVAL; + goto sensor_INIT_ERR; + } + sensor->info_priv.fmt = *fmt; + + /* sensor sensor information for initialization */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + if (qctrl) + sensor->info_priv.whiteBalance = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_BRIGHTNESS); + if (qctrl) + sensor->info_priv.brightness = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + if (qctrl) + sensor->info_priv.effect = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EXPOSURE); + if (qctrl) + sensor->info_priv.exposure = qctrl->default_value; + + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SATURATION); + if (qctrl) + sensor->info_priv.saturation = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_CONTRAST); + if (qctrl) + sensor->info_priv.contrast = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_HFLIP); + if (qctrl) + sensor->info_priv.mirror = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_VFLIP); + if (qctrl) + sensor->info_priv.flip = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SCENE); + if (qctrl) + sensor->info_priv.scene = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE); + if (qctrl) + sensor->info_priv.digitalzoom = qctrl->default_value; + + /* ddl@rock-chips.com : if sensor support auto focus and flash, programer must run focus and flash code */ + #if CONFIG_SENSOR_Focus + sensor_set_focus(); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FOCUS_ABSOLUTE); + if (qctrl) + sensor->info_priv.focus = qctrl->default_value; + #endif + + #if CONFIG_SENSOR_Flash + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FLASH); + if (qctrl) + sensor->info_priv.flash = qctrl->default_value; + #endif + + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),((val == 0)?__FUNCTION__:"sensor_reinit"),icd->user_width,icd->user_height); + sensor->info_priv.funmodule_state |= SENSOR_INIT_IS_OK; + return 0; +sensor_INIT_ERR: + sensor->info_priv.funmodule_state &= ~SENSOR_INIT_IS_OK; + sensor_task_lock(client,0); + sensor_deactivate(client); + return ret; +} + +static int sensor_deactivate(struct i2c_client *client) +{ + struct soc_camera_device *icd = client->dev.platform_data; + //u8 reg_val; + struct sensor *sensor = to_sensor(client); + SENSOR_DG("\n%s..%s.. Enter\n",SENSOR_NAME_STRING(),__FUNCTION__); + + /* ddl@rock-chips.com : all sensor output pin must change to input for other sensor */ + sensor_ioctrl(icd, Sensor_PowerDown, 1); + msleep(100); + + /* ddl@rock-chips.com : sensor config init width , because next open sensor quickly(soc_camera_open -> Try to configure with default parameters) */ + icd->user_width = SENSOR_INIT_WIDTH; + icd->user_height = SENSOR_INIT_HEIGHT; + sensor->info_priv.funmodule_state &= ~SENSOR_INIT_IS_OK; + + return 0; +} +static struct reginfo sensor_power_down_sequence[]= +{ + {0x00,0x00}, + {0x03,0x02} +}; +static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg) +{ + int ret; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if (pm_msg.event == PM_EVENT_SUSPEND) { + SENSOR_DG("\n %s Enter Suspend.. \n", SENSOR_NAME_STRING()); + ret = sensor_write_array(client, sensor_power_down_sequence) ; + if (ret != 0) { + SENSOR_TR("\n %s..%s WriteReg Fail.. \n", SENSOR_NAME_STRING(),__FUNCTION__); + return ret; + } else { + ret = sensor_ioctrl(icd, Sensor_PowerDown, 1); + if (ret < 0) { + SENSOR_TR("\n %s suspend fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + } + } else { + SENSOR_TR("\n %s cann't suppout Suspend..\n",SENSOR_NAME_STRING()); + return -EINVAL; + } + return 0; +} + +static int sensor_resume(struct soc_camera_device *icd) +{ + int ret; + + ret = sensor_ioctrl(icd, Sensor_PowerDown, 0); + if (ret < 0) { + SENSOR_TR("\n %s resume fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + + SENSOR_DG("\n %s Enter Resume.. \n", SENSOR_NAME_STRING()); + + return 0; + +} + +static int sensor_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + + return 0; +} + +static unsigned long sensor_query_bus_param(struct soc_camera_device *icd) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + unsigned long flags = SENSOR_BUS_PARAM; + + return soc_camera_apply_sensor_flags(icl, flags); +} + +static int sensor_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + + mf->width = icd->user_width; + mf->height = icd->user_height; + mf->code = sensor->info_priv.fmt.code; + mf->colorspace = sensor->info_priv.fmt.colorspace; + mf->field = V4L2_FIELD_NONE; + + return 0; +} +static bool sensor_fmt_capturechk(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + bool ret = false; + + if ((mf->width == 1024) && (mf->height == 768)) { + ret = true; + } else if ((mf->width == 1280) && (mf->height == 1024)) { + ret = true; + } else if ((mf->width == 1600) && (mf->height == 1200)) { + ret = true; + } else if ((mf->width == 2048) && (mf->height == 1536)) { + ret = true; + } else if ((mf->width == 2592) && (mf->height == 1944)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is capture format\n", __FUNCTION__, mf->width, mf->height); + return ret; +} + +static bool sensor_fmt_videochk(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + bool ret = false; + + if ((mf->width == 1280) && (mf->height == 720)) { + ret = true; + } else if ((mf->width == 1920) && (mf->height == 1080)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is video format\n", __FUNCTION__, mf->width, mf->height); + return ret; +} +static int sensor_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + const struct sensor_datafmt *fmt; + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + struct soc_camera_device *icd = client->dev.platform_data; + struct reginfo *winseqe_set_addr=NULL; + int ret=0, set_w,set_h; + + fmt = sensor_find_datafmt(mf->code, sensor_colour_fmts, + ARRAY_SIZE(sensor_colour_fmts)); + if (!fmt) { + ret = -EINVAL; + goto sensor_s_fmt_end; + } + + if (sensor->info_priv.fmt.code != mf->code) { + switch (mf->code) + { + case V4L2_MBUS_FMT_YUYV8_2X8: + { + winseqe_set_addr = sensor_ClrFmt_YUYV; + break; + } + case V4L2_MBUS_FMT_UYVY8_2X8: + { + winseqe_set_addr = sensor_ClrFmt_UYVY; + break; + } + default: + break; + } + if (winseqe_set_addr != NULL) { + sensor_write_array(client, winseqe_set_addr); + sensor->info_priv.fmt.code = mf->code; + sensor->info_priv.fmt.colorspace= mf->colorspace; + SENSOR_DG("%s v4l2_mbus_code:%d set success!\n", SENSOR_NAME_STRING(),mf->code); + } else { + SENSOR_TR("%s v4l2_mbus_code:%d is invalidate!\n", SENSOR_NAME_STRING(),mf->code); + } + } + + set_w = mf->width; + set_h = mf->height; + + if (((set_w <= 176) && (set_h <= 144)) && sensor_qcif[0].reg) + { + winseqe_set_addr = sensor_qcif; + set_w = 176; + set_h = 144; + } + else if (((set_w <= 320) && (set_h <= 240)) && sensor_qvga[0].reg) + { + winseqe_set_addr = sensor_qvga; + set_w = 320; + set_h = 240; + } + else if (((set_w <= 352) && (set_h<= 288)) && sensor_cif[0].reg) + { + winseqe_set_addr = sensor_cif; + set_w = 352; + set_h = 288; + } + else if (((set_w <= 640) && (set_h <= 480)) && sensor_vga[0].reg) + { + winseqe_set_addr = sensor_vga; + set_w = 640; + set_h = 480; + } + else if (((set_w <= 800) && (set_h <= 600)) && sensor_svga[0].reg) + { + winseqe_set_addr = sensor_svga; + set_w = 800; + set_h = 600; + } + else if (((set_w <= 1280) && (set_h <= 1024)) && sensor_sxga[0].reg) + { + winseqe_set_addr = sensor_sxga; + set_w = 1280; + set_h = 1024; + } + else + { + winseqe_set_addr = SENSOR_INIT_WINSEQADR; /* ddl@rock-chips.com : Sensor output smallest size if isn't support app */ + set_w = SENSOR_INIT_WIDTH; + set_h = SENSOR_INIT_HEIGHT; + SENSOR_TR("\n %s..%s Format is Invalidate. pix->width = %d.. pix->height = %d\n",SENSOR_NAME_STRING(),__FUNCTION__,mf->width,mf->height); + } + + if ((int)winseqe_set_addr != sensor->info_priv.winseqe_cur_addr) { + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,mf) == true) { /* ddl@rock-chips.com : Capture */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_On); + SENSOR_DG("%s flash on in capture!\n", SENSOR_NAME_STRING()); + } + } else { /* ddl@rock-chips.com : Video */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_DG("%s flash off in preivew!\n", SENSOR_NAME_STRING()); + } + } + #endif + ret |= sensor_write_array(client, winseqe_set_addr); + if (ret != 0) { + SENSOR_TR("%s set format capability failed\n", SENSOR_NAME_STRING()); + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,mf) == true) { + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_TR("%s Capture format set fail, flash off !\n", SENSOR_NAME_STRING()); + } + } + #endif + goto sensor_s_fmt_end; + } + + sensor->info_priv.winseqe_cur_addr = (int)winseqe_set_addr; + + if (sensor_fmt_capturechk(sd,mf) == true) { /* ddl@rock-chips.com : Capture */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + if (sensor->info_priv.whiteBalance != 0) { + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + } + sensor->info_priv.snap2preview = true; + } else if (sensor_fmt_videochk(sd,mf) == true) { /* ddl@rock-chips.com : Video */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + sensor->info_priv.video2preview = true; + } else if ((sensor->info_priv.snap2preview == true) || (sensor->info_priv.video2preview == true)) { + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + msleep(600); + sensor->info_priv.video2preview = false; + sensor->info_priv.snap2preview = false; + } + + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),__FUNCTION__,set_w,set_h); + } + else + { + SENSOR_DG("\n %s .. Current Format is validate. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),set_w,set_h); + } + + mf->width = set_w; + mf->height = set_h; + +sensor_s_fmt_end: + return ret; +} + +static int sensor_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct sensor *sensor = to_sensor(client); + const struct sensor_datafmt *fmt; + int ret = 0,set_w,set_h; + + fmt = sensor_find_datafmt(mf->code, sensor_colour_fmts, + ARRAY_SIZE(sensor_colour_fmts)); + if (fmt == NULL) { + fmt = &sensor->info_priv.fmt; + mf->code = fmt->code; + } + + if (mf->height > SENSOR_MAX_HEIGHT) + mf->height = SENSOR_MAX_HEIGHT; + else if (mf->height < SENSOR_MIN_HEIGHT) + mf->height = SENSOR_MIN_HEIGHT; + + if (mf->width > SENSOR_MAX_WIDTH) + mf->width = SENSOR_MAX_WIDTH; + else if (mf->width < SENSOR_MIN_WIDTH) + mf->width = SENSOR_MIN_WIDTH; + + set_w = mf->width; + set_h = mf->height; + + if (((set_w <= 176) && (set_h <= 144)) && sensor_qcif[0].reg) + { + set_w = 176; + set_h = 144; + } + else if (((set_w <= 320) && (set_h <= 240)) && sensor_qvga[0].reg) + { + set_w = 320; + set_h = 240; + } + else if (((set_w <= 352) && (set_h<= 288)) && sensor_cif[0].reg) + { + set_w = 352; + set_h = 288; + } + else if (((set_w <= 640) && (set_h <= 480)) && sensor_vga[0].reg) + { + set_w = 640; + set_h = 480; + } + else if (((set_w <= 800) && (set_h <= 600)) && sensor_svga[0].reg) + { + set_w = 800; + set_h = 600; + } + else if (((set_w <= 1280) && (set_h <= 1024)) && sensor_sxga[0].reg) + { + set_w = 1280; + set_h = 1024; + } + else + { + set_w = SENSOR_INIT_WIDTH; + set_h = SENSOR_INIT_HEIGHT; + } + + mf->width = set_w; + mf->height = set_h; + + mf->colorspace = fmt->colorspace; + + return ret; +} + + static int sensor_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *id) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) + return -EINVAL; + + if (id->match.addr != client->addr) + return -ENODEV; + + id->ident = SENSOR_V4L2_IDENT; /* ddl@rock-chips.com : Return OV9650 identifier */ + id->revision = 0; + + return 0; +} +#if CONFIG_SENSOR_Brightness +static int sensor_set_brightness(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_BrightnessSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_effect_write_array(client, sensor_BrightnessSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Effect +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_EffectSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_effect_write_array(client, sensor_EffectSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Exposure +static int sensor_set_exposure(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_ExposureSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_effect_write_array(client, sensor_ExposureSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Saturation +static int sensor_set_saturation(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_SaturationSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_effect_write_array(client, sensor_SaturationSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Contrast +static int sensor_set_contrast(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_ContrastSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_effect_write_array(client, sensor_ContrastSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Mirror +static int sensor_set_mirror(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_MirrorSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_effect_write_array(client, sensor_MirrorSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Flip +static int sensor_set_flip(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_FlipSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_effect_write_array(client, sensor_FlipSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Scene +static int sensor_set_scene(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_SceneSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_effect_write_array(client, sensor_SceneSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_WhiteBalance +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_WhiteBalanceSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_effect_write_array(client, sensor_WhiteBalanceSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_DigitalZoom +static int sensor_set_digitalzoom(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int *value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl_info; + int digitalzoom_cur, digitalzoom_total; + + qctrl_info = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE); + if (qctrl_info) + return -EINVAL; + + digitalzoom_cur = sensor->info_priv.digitalzoom; + digitalzoom_total = qctrl_info->maximum; + + if ((*value > 0) && (digitalzoom_cur >= digitalzoom_total)) + { + SENSOR_TR("%s digitalzoom is maximum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur); + return -EINVAL; + } + + if ((*value < 0) && (digitalzoom_cur <= qctrl_info->minimum)) + { + SENSOR_TR("%s digitalzoom is minimum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur); + return -EINVAL; + } + + if ((*value > 0) && ((digitalzoom_cur + *value) > digitalzoom_total)) + { + *value = digitalzoom_total - digitalzoom_cur; + } + + if ((*value < 0) && ((digitalzoom_cur + *value) < 0)) + { + *value = 0 - digitalzoom_cur; + } + + digitalzoom_cur += *value; + + if (sensor_ZoomSeqe[digitalzoom_cur] != NULL) + { + if (sensor_effect_write_array(client, sensor_ZoomSeqe[digitalzoom_cur]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, *value); + return 0; + } + + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Flash +static int sensor_set_flash(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) { + if (value == 3) { /* ddl@rock-chips.com: torch */ + sensor_ioctrl(icd, Sensor_Flash, Flash_Torch); /* Flash On */ + } else { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif + +static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + + qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + return -EINVAL; + } + + switch (ctrl->id) + { + case V4L2_CID_BRIGHTNESS: + { + ctrl->value = sensor->info_priv.brightness; + break; + } + case V4L2_CID_SATURATION: + { + ctrl->value = sensor->info_priv.saturation; + break; + } + case V4L2_CID_CONTRAST: + { + ctrl->value = sensor->info_priv.contrast; + break; + } + case V4L2_CID_DO_WHITE_BALANCE: + { + ctrl->value = sensor->info_priv.whiteBalance; + break; + } + case V4L2_CID_EXPOSURE: + { + ctrl->value = sensor->info_priv.exposure; + break; + } + case V4L2_CID_HFLIP: + { + ctrl->value = sensor->info_priv.mirror; + break; + } + case V4L2_CID_VFLIP: + { + ctrl->value = sensor->info_priv.flip; + break; + } + default : + break; + } + return 0; +} + + + +static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct sensor *sensor = to_sensor(client); + struct soc_camera_device *icd = client->dev.platform_data; + const struct v4l2_queryctrl *qctrl; + + + qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + return -EINVAL; + } + + switch (ctrl->id) + { +#if CONFIG_SENSOR_Brightness + case V4L2_CID_BRIGHTNESS: + { + if (ctrl->value != sensor->info_priv.brightness) + { + if (sensor_set_brightness(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.brightness = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Exposure + case V4L2_CID_EXPOSURE: + { + if (ctrl->value != sensor->info_priv.exposure) + { + if (sensor_set_exposure(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.exposure = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Saturation + case V4L2_CID_SATURATION: + { + if (ctrl->value != sensor->info_priv.saturation) + { + if (sensor_set_saturation(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.saturation = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Contrast + case V4L2_CID_CONTRAST: + { + if (ctrl->value != sensor->info_priv.contrast) + { + if (sensor_set_contrast(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.contrast = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_WhiteBalance + case V4L2_CID_DO_WHITE_BALANCE: + { + if (ctrl->value != sensor->info_priv.whiteBalance) + { + if (sensor_set_whiteBalance(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.whiteBalance = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Mirror + case V4L2_CID_HFLIP: + { + if (ctrl->value != sensor->info_priv.mirror) + { + if (sensor_set_mirror(icd, qctrl,ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.mirror = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Flip + case V4L2_CID_VFLIP: + { + if (ctrl->value != sensor->info_priv.flip) + { + if (sensor_set_flip(icd, qctrl,ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.flip = ctrl->value; + } + break; + } +#endif + default: + break; + } + + return 0; +} +static int sensor_g_ext_control(struct soc_camera_device *icd , struct v4l2_ext_control *ext_ctrl) +{ + const struct v4l2_queryctrl *qctrl; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + return -EINVAL; + } + + switch (ext_ctrl->id) + { + case V4L2_CID_SCENE: + { + ext_ctrl->value = sensor->info_priv.scene; + break; + } + case V4L2_CID_EFFECT: + { + ext_ctrl->value = sensor->info_priv.effect; + break; + } + case V4L2_CID_ZOOM_ABSOLUTE: + { + ext_ctrl->value = sensor->info_priv.digitalzoom; + break; + } + case V4L2_CID_ZOOM_RELATIVE: + { + return -EINVAL; + } + case V4L2_CID_FOCUS_ABSOLUTE: + { + ext_ctrl->value = sensor->info_priv.focus; + break; + } + case V4L2_CID_FOCUS_RELATIVE: + { + return -EINVAL; + } + case V4L2_CID_FLASH: + { + ext_ctrl->value = sensor->info_priv.flash; + break; + } + default : + break; + } + return 0; +} +static int sensor_s_ext_control(struct soc_camera_device *icd, struct v4l2_ext_control *ext_ctrl) +{ + const struct v4l2_queryctrl *qctrl; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + int val_offset; + + qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + return -EINVAL; + } + + val_offset = 0; + switch (ext_ctrl->id) + { +#if CONFIG_SENSOR_Scene + case V4L2_CID_SCENE: + { + if (ext_ctrl->value != sensor->info_priv.scene) + { + if (sensor_set_scene(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.scene = ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Effect + case V4L2_CID_EFFECT: + { + if (ext_ctrl->value != sensor->info_priv.effect) + { + if (sensor_set_effect(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.effect= ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_DigitalZoom + case V4L2_CID_ZOOM_ABSOLUTE: + { + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; + + if (ext_ctrl->value != sensor->info_priv.digitalzoom) + { + val_offset = ext_ctrl->value -sensor->info_priv.digitalzoom; + + if (sensor_set_digitalzoom(icd, qctrl,&val_offset) != 0) + return -EINVAL; + sensor->info_priv.digitalzoom += val_offset; + + SENSOR_DG("%s digitalzoom is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.digitalzoom); + } + + break; + } + case V4L2_CID_ZOOM_RELATIVE: + { + if (ext_ctrl->value) + { + if (sensor_set_digitalzoom(icd, qctrl,&ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.digitalzoom += ext_ctrl->value; + + SENSOR_DG("%s digitalzoom is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.digitalzoom); + } + break; + } +#endif +#if CONFIG_SENSOR_Focus + case V4L2_CID_FOCUS_ABSOLUTE: + { + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; + + if (ext_ctrl->value != sensor->info_priv.focus) + { + val_offset = ext_ctrl->value -sensor->info_priv.focus; + + sensor->info_priv.focus += val_offset; + } + + break; + } + case V4L2_CID_FOCUS_RELATIVE: + { + if (ext_ctrl->value) + { + sensor->info_priv.focus += ext_ctrl->value; + + SENSOR_DG("%s focus is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.focus); + } + break; + } +#endif +#if CONFIG_SENSOR_Flash + case V4L2_CID_FLASH: + { + if (sensor_set_flash(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.flash = ext_ctrl->value; + + SENSOR_DG("%s flash is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.flash); + break; + } +#endif + default: + break; + } + + return 0; +} + +static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + int i, error_cnt=0, error_idx=-1; + + + for (i=0; icount; i++) { + if (sensor_g_ext_control(icd, &ext_ctrl->controls[i]) != 0) { + error_cnt++; + error_idx = i; + } + } + + if (error_cnt > 1) + error_idx = ext_ctrl->count; + + if (error_idx != -1) { + ext_ctrl->error_idx = error_idx; + return -EINVAL; + } else { + return 0; + } +} + +static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + int i, error_cnt=0, error_idx=-1; + + + for (i=0; icount; i++) { + if (sensor_s_ext_control(icd, &ext_ctrl->controls[i]) != 0) { + error_cnt++; + error_idx = i; + } + } + + if (error_cnt > 1) + error_idx = ext_ctrl->count; + + if (error_idx != -1) { + ext_ctrl->error_idx = error_idx; + return -EINVAL; + } else { + return 0; + } +} + +/* Interface active, can use i2c. If it fails, it can indeed mean, that + * this wasn't our capture interface, so, we wait for the right one */ +static int sensor_video_probe(struct soc_camera_device *icd, + struct i2c_client *client) +{ + char pid = 0; + int ret; + struct sensor *sensor = to_sensor(client); + + /* We must have a parent by now. And it cannot be a wrong one. + * So this entire test is completely redundant. */ + if (!icd->dev.parent || + to_soc_camera_host(icd->dev.parent)->nr != icd->iface) + return -ENODEV; + + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_video_probe_err; + } + + /* soft reset */ + /* ret = sensor_write(client, 0x12, 0x80); + if (ret != 0) + { + SENSOR_TR("soft reset %s failed\n",SENSOR_NAME_STRING()); + return -ENODEV; + } + mdelay(50); *///delay 5 microseconds + sensor_write(client, 0x00, 0x01); + sensor_write(client, 0x03, 0x0a); + mdelay(100); //delay 5 microseconds + sensor_write(client, 0x00, 0x01); + sensor_write(client, 0x03, 0x0a); + mdelay(100); //delay 5 microseconds + + /* check if it is an sensor sensor */ + sensor_write(client, 0x00, 0x00); + + ret = sensor_read(client, 0x01, &pid); + if (ret != 0) { + SENSOR_TR("%s read chip id high byte failed\n",SENSOR_NAME_STRING()); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + SENSOR_DG("\n %s pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + if (pid == SENSOR_ID) { + sensor->model = SENSOR_V4L2_IDENT; + } else { + SENSOR_TR("error: %s mismatched pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + return 0; + +sensor_video_probe_err: + + return ret; +} + +static long sensor_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + int ret = 0; + + int i; + + + SENSOR_DG("\n%s..%s..cmd:%x \n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + switch (cmd) + { + case RK29_CAM_SUBDEV_DEACTIVATE: + { + sensor_deactivate(client); + break; + } + + case RK29_CAM_SUBDEV_IOREQUEST: + { + sensor->sensor_io_request = (struct rk29camera_platform_data*)arg; + if (sensor->sensor_io_request != NULL) { + sensor->sensor_gpio_res = NULL; + for (i=0; isensor_io_request->gpio_res[i].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[i].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[i]; + } + } + if (sensor->sensor_gpio_res == NULL) { + SENSOR_TR("%s %s obtain gpio resource failed when RK29_CAM_SUBDEV_IOREQUEST \n",SENSOR_NAME_STRING(),__FUNCTION__); + ret = -EINVAL; + goto sensor_ioctl_end; + } + } else { + SENSOR_TR("%s %s RK29_CAM_SUBDEV_IOREQUEST fail\n",SENSOR_NAME_STRING(),__FUNCTION__); + ret = -EINVAL; + goto sensor_ioctl_end; + } + /* ddl@rock-chips.com : if gpio_flash havn't been set in board-xxx.c, sensor driver must notify is not support flash control + for this project */ + #if CONFIG_SENSOR_Flash + if (sensor->sensor_gpio_res) { + if (sensor->sensor_gpio_res->gpio_flash == INVALID_GPIO) { + for (i = 0; i < icd->ops->num_controls; i++) { + if (V4L2_CID_FLASH == icd->ops->controls[i].id) { + memset((char*)&icd->ops->controls[i],0x00,sizeof(struct v4l2_queryctrl)); + } + } + sensor->info_priv.flash = 0xff; + SENSOR_DG("%s flash gpio is invalidate!\n",SENSOR_NAME_STRING()); + } + } + #endif + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown !\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } +sensor_ioctl_end: + return ret; + +} +static int sensor_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + if (index >= ARRAY_SIZE(sensor_colour_fmts)) + return -EINVAL; + + *code = sensor_colour_fmts[index].code; + return 0; +} +static struct v4l2_subdev_core_ops sensor_subdev_core_ops = { + .init = sensor_init, + .g_ctrl = sensor_g_control, + .s_ctrl = sensor_s_control, + .g_ext_ctrls = sensor_g_ext_controls, + .s_ext_ctrls = sensor_s_ext_controls, + .g_chip_ident = sensor_g_chip_ident, + .ioctl = sensor_ioctl, +}; + +static struct v4l2_subdev_video_ops sensor_subdev_video_ops = { + .s_mbus_fmt = sensor_s_fmt, + .g_mbus_fmt = sensor_g_fmt, + .try_mbus_fmt = sensor_try_fmt, + .enum_mbus_fmt = sensor_enum_fmt, +}; + +static struct v4l2_subdev_ops sensor_subdev_ops = { + .core = &sensor_subdev_core_ops, + .video = &sensor_subdev_video_ops, +}; + +static int sensor_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct sensor *sensor; + struct soc_camera_device *icd = client->dev.platform_data; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct soc_camera_link *icl; + int ret; + + SENSOR_DG("\n%s..%s..%d..\n",__FUNCTION__,__FILE__,__LINE__); + if (!icd) { + dev_err(&client->dev, "%s: missing soc-camera data!\n",SENSOR_NAME_STRING()); + return -EINVAL; + } + + icl = to_soc_camera_link(icd); + if (!icl) { + dev_err(&client->dev, "%s driver needs platform data\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { + dev_warn(&adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_I2C\n"); + return -EIO; + } + + sensor = kzalloc(sizeof(struct sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + v4l2_i2c_subdev_init(&sensor->subdev, client, &sensor_subdev_ops); + + /* Second stage probe - when a capture adapter is there */ + icd->ops = &sensor_ops; + + sensor->info_priv.fmt = sensor_colour_fmts[0]; + + #if CONFIG_SENSOR_I2C_NOSCHED + atomic_set(&sensor->tasklock_cnt,0); + #endif + + ret = sensor_video_probe(icd, client); + if (ret < 0) { + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + kfree(sensor); + sensor = NULL; + } + SENSOR_DG("\n%s..%s..%d ret = %x \n",__FUNCTION__,__FILE__,__LINE__,ret); + return ret; +} + +static int sensor_remove(struct i2c_client *client) +{ + struct sensor *sensor = to_sensor(client); + struct soc_camera_device *icd = client->dev.platform_data; + + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + client->driver = NULL; + kfree(sensor); + sensor = NULL; + return 0; +} + +static const struct i2c_device_id sensor_id[] = { + {SENSOR_NAME_STRING(), 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sensor_id); + +static struct i2c_driver sensor_i2c_driver = { + .driver = { + .name = SENSOR_NAME_STRING(), + }, + .probe = sensor_probe, + .remove = sensor_remove, + .id_table = sensor_id, +}; + +static int __init sensor_mod_init(void) +{ + SENSOR_DG("\n%s..%s.. \n",__FUNCTION__,SENSOR_NAME_STRING()); + return i2c_add_driver(&sensor_i2c_driver); +} + +static void __exit sensor_mod_exit(void) +{ + i2c_del_driver(&sensor_i2c_driver); +} + +device_initcall_sync(sensor_mod_init); +module_exit(sensor_mod_exit); + +MODULE_DESCRIPTION(SENSOR_NAME_STRING(Camera sensor driver)); +MODULE_AUTHOR("ddl "); +MODULE_LICENSE("GPL"); + + diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h index 53724b2be00c..a27a50910a6c 100755 --- a/include/media/v4l2-chip-ident.h +++ b/include/media/v4l2-chip-ident.h @@ -90,7 +90,6 @@ enum { /* Samsung sensors: reserved range 310-319 */ V4L2_IDENT_S5K66A = 310, /* ddl@rock-chips.com : s5k66a support */ - V4L2_IDENT_S5K5CA = 311, /* ddl@rock-chips.com : s5k5ca support */ /* Conexant MPEG encoder/decoders: reserved range 400-420 */ V4L2_IDENT_CX23418_843 = 403, /* Integrated A/V Decoder on the '418 */ @@ -349,9 +348,8 @@ enum { V4L2_IDENT_HI704 = 64107, /* ddl@rock-chips.com : hi704 support */ V4L2_IDENT_NT99250 = 64108, /* ddl@rock-chips.com : nt99250 support */ V4L2_IDENT_SID130B = 64109, /* ddl@rock-chips.com : sid130B support */ + V4L2_IDENT_SIV121D= 64109, /* ddl@rock-chips.com : sid130B support */ - V4L2_IDENT_SP0838 = 64110, /* ddl@rock-chips.com : SP0838 support */ - V4L2_IDENT_GC0329 = 64111, /* ddl@rock-chips.com : GC0329 support */ /* Don't just add new IDs at the end: KEEP THIS LIST ORDERED BY ID! */ }; From f99e7676f552590ff6bf17e02ff4782d259e801a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=99=B4?= Date: Wed, 1 Aug 2012 11:00:31 +0800 Subject: [PATCH 065/261] rk30:sdk:Support both of compatible pmic wm8326 and tps65910 --- arch/arm/mach-rk30/board-rk30-sdk-tps65910.c | 4 +- arch/arm/mach-rk30/board-rk30-sdk-wm8326.c | 3 +- arch/arm/mach-rk30/board-rk30-sdk.c | 77 ++++++++++++++++++++ drivers/mfd/tps65910.c | 2 + drivers/mfd/wm831x-core.c | 3 +- 5 files changed, 85 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c b/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c index ac2ee6b19f1f..8e1a6e28e7f8 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c +++ b/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c @@ -575,7 +575,7 @@ static struct regulator_init_data tps65910_ldo8 = { .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo8_supply), .consumer_supplies = tps65910_ldo8_supply, }; - +#ifdef PMIC_IS_TPS6591x void __sramfunc board_pmu_suspend(void) { grf_writel(GPIO6_PB1_DIR_OUT, GRF_GPIO6L_DIR_ADDR); @@ -593,7 +593,7 @@ void __sramfunc board_pmu_resume(void) sram_udelay(2000); #endif } - +#endif static struct tps65910_board tps65910_data = { .irq = (unsigned)TPS65910_HOST_IRQ, .irq_base = NR_GIC_IRQS + NR_GPIO_IRQS, diff --git a/arch/arm/mach-rk30/board-rk30-sdk-wm8326.c b/arch/arm/mach-rk30/board-rk30-sdk-wm8326.c index ce3050e7e6df..045b2c85089c 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk-wm8326.c +++ b/arch/arm/mach-rk30/board-rk30-sdk-wm8326.c @@ -773,7 +773,7 @@ static int wm831x_init_pin_type(struct wm831x *wm831x) out: return 0; } - +#ifdef PMIC_IS_WM831X void __sramfunc board_pmu_suspend(void) { cru_writel(CRU_CLKGATE5_GRFCLK_ON,CRU_CLKGATE5_CON_ADDR); //open grf clk @@ -792,6 +792,7 @@ void __sramfunc board_pmu_resume(void) sram_udelay(10000); #endif } +#endif static struct wm831x_pdata wm831x_platdata = { /** Called before subdevices are set up */ diff --git a/arch/arm/mach-rk30/board-rk30-sdk.c b/arch/arm/mach-rk30/board-rk30-sdk.c index 0b27edc772dd..4e5035e7253b 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk.c +++ b/arch/arm/mach-rk30/board-rk30-sdk.c @@ -44,6 +44,8 @@ #include #include #include +#include +#include #if defined(CONFIG_HDMI_RK30) #include "../../../drivers/video/rockchip/hdmi/rk_hdmi.h" #endif @@ -73,6 +75,9 @@ #define RK30_FB0_MEM_SIZE 8*SZ_1M #endif +int PMIC_IS_WM831X = 0; +int PMIC_IS_TPS6591x = 0; + #ifdef CONFIG_VIDEO_RK29 /*---------------- Camera Sensor Macro Define Begin ------------------------*/ /*---------------- Camera Sensor Configuration Macro Begin ------------------------*/ @@ -1335,6 +1340,59 @@ static struct platform_device rk30_device_adc_battery = { }; #endif +#if CONFIG_RK30_PWM_REGULATOR +const static int pwm_voltage_map[] = { + 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 1400000 +}; + +static struct regulator_consumer_supply pwm_dcdc1_consumers[] = { + { + .supply = "vdd_core", + } +}; + +struct regulator_init_data pwm_regulator_init_dcdc[1] = +{ + { + .constraints = { + .name = "PWM_DCDC1", + .min_uV = 600000, + .max_uV = 1800000, //0.6-1.8V + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(pwm_dcdc1_consumers), + .consumer_supplies = pwm_dcdc1_consumers, + }, +}; + +static struct pwm_platform_data pwm_regulator_info[1] = { + { + .pwm_id = 3, + .pwm_gpio = RK30_PIN0_PD7, + .pwm_iomux_name = GPIO0D7_PWM3_NAME, + .pwm_iomux_pwm = GPIO0D_PWM3, + .pwm_iomux_gpio = GPIO0D_GPIO0D6, + .pwm_voltage = 1100000, + .min_uV = 1000000, + .max_uV = 1400000, + .coefficient = 455, //45.5% + .pwm_voltage_map = pwm_voltage_map, + .init_data = &pwm_regulator_init_dcdc[0], + }, +}; + +struct platform_device pwm_regulator_device[1] = { + { + .name = "pwm-voltage-regulator", + .id = 0, + .dev = { + .platform_data = &pwm_regulator_info[0], + } + }, +}; +#endif + #ifdef CONFIG_RK29_VMAC #define PHY_PWR_EN_GPIO RK30_PIN1_PD6 #include "board-rk30-sdk-vmac.c" @@ -1403,6 +1461,9 @@ static struct platform_device device_rfkill_rk = { #endif static struct platform_device *devices[] __initdata = { +#ifdef CONFIG_RK30_PWM_REGULATOR + &pwm_regulator_device[0], +#endif #ifdef CONFIG_BACKLIGHT_RK29_BL &rk29_device_backlight, #endif @@ -1540,7 +1601,13 @@ static struct i2c_board_info __initdata i2c0_info[] = { #endif #ifdef CONFIG_I2C1_RK30 +#ifdef CONFIG_MFD_WM831X_I2C #include "board-rk30-sdk-wm8326.c" +#endif +#ifdef CONFIG_MFD_TPS65910 +#define TPS65910_HOST_IRQ RK30_PIN6_PA4 +#include "board-rk30-sdk-tps65910.c" +#endif static struct i2c_board_info __initdata i2c1_info[] = { #if defined (CONFIG_MFD_WM831X_I2C) @@ -1552,6 +1619,16 @@ static struct i2c_board_info __initdata i2c1_info[] = { .platform_data = &wm831x_platdata, }, #endif +#if defined (CONFIG_MFD_TPS65910) + { + .type = "tps65910", + .addr = TPS65910_I2C_ID0, + .flags = 0, + .irq = TPS65910_HOST_IRQ, + .platform_data = &tps65910_data, + }, +#endif + }; #endif diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index dd7813012b43..09ac6c3ca67b 100755 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -232,6 +232,7 @@ int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask) } EXPORT_SYMBOL_GPL(tps65910_clear_bits); +extern int PMIC_IS_TPS6591x; static int tps65910_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -293,6 +294,7 @@ static int tps65910_i2c_probe(struct i2c_client *i2c, } } printk("%s:irq=%d,irq_base=%d\n",__func__,init_data->irq,init_data->irq_base); + PMIC_IS_TPS6591x = 1; return ret; err: diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 504314e87de1..493b1ab52d84 100755 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -1461,7 +1461,7 @@ static struct mfd_cell backlight_devs[] = { .name = "wm831x-backlight", }, }; - +extern int PMIC_IS_WM831X; /* * Instantiate the generic non-control parts of the device. */ @@ -1729,6 +1729,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) goto err_irq; } } + PMIC_IS_WM831X = 1; return 0; From 9c3702facd0db15b1848fff778e5af1687ab1b84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Wed, 1 Aug 2012 11:14:03 +0800 Subject: [PATCH 066/261] Revert "rk30:sdk:Support both of compatible pmic wm8326 and tps65910" This reverts commit f99e7676f552590ff6bf17e02ff4782d259e801a. --- arch/arm/mach-rk30/board-rk30-sdk-tps65910.c | 4 +- arch/arm/mach-rk30/board-rk30-sdk-wm8326.c | 3 +- arch/arm/mach-rk30/board-rk30-sdk.c | 77 -------------------- drivers/mfd/tps65910.c | 2 - drivers/mfd/wm831x-core.c | 3 +- 5 files changed, 4 insertions(+), 85 deletions(-) diff --git a/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c b/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c index 8e1a6e28e7f8..ac2ee6b19f1f 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c +++ b/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c @@ -575,7 +575,7 @@ static struct regulator_init_data tps65910_ldo8 = { .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo8_supply), .consumer_supplies = tps65910_ldo8_supply, }; -#ifdef PMIC_IS_TPS6591x + void __sramfunc board_pmu_suspend(void) { grf_writel(GPIO6_PB1_DIR_OUT, GRF_GPIO6L_DIR_ADDR); @@ -593,7 +593,7 @@ void __sramfunc board_pmu_resume(void) sram_udelay(2000); #endif } -#endif + static struct tps65910_board tps65910_data = { .irq = (unsigned)TPS65910_HOST_IRQ, .irq_base = NR_GIC_IRQS + NR_GPIO_IRQS, diff --git a/arch/arm/mach-rk30/board-rk30-sdk-wm8326.c b/arch/arm/mach-rk30/board-rk30-sdk-wm8326.c index 045b2c85089c..ce3050e7e6df 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk-wm8326.c +++ b/arch/arm/mach-rk30/board-rk30-sdk-wm8326.c @@ -773,7 +773,7 @@ static int wm831x_init_pin_type(struct wm831x *wm831x) out: return 0; } -#ifdef PMIC_IS_WM831X + void __sramfunc board_pmu_suspend(void) { cru_writel(CRU_CLKGATE5_GRFCLK_ON,CRU_CLKGATE5_CON_ADDR); //open grf clk @@ -792,7 +792,6 @@ void __sramfunc board_pmu_resume(void) sram_udelay(10000); #endif } -#endif static struct wm831x_pdata wm831x_platdata = { /** Called before subdevices are set up */ diff --git a/arch/arm/mach-rk30/board-rk30-sdk.c b/arch/arm/mach-rk30/board-rk30-sdk.c index 4e5035e7253b..0b27edc772dd 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk.c +++ b/arch/arm/mach-rk30/board-rk30-sdk.c @@ -44,8 +44,6 @@ #include #include #include -#include -#include #if defined(CONFIG_HDMI_RK30) #include "../../../drivers/video/rockchip/hdmi/rk_hdmi.h" #endif @@ -75,9 +73,6 @@ #define RK30_FB0_MEM_SIZE 8*SZ_1M #endif -int PMIC_IS_WM831X = 0; -int PMIC_IS_TPS6591x = 0; - #ifdef CONFIG_VIDEO_RK29 /*---------------- Camera Sensor Macro Define Begin ------------------------*/ /*---------------- Camera Sensor Configuration Macro Begin ------------------------*/ @@ -1340,59 +1335,6 @@ static struct platform_device rk30_device_adc_battery = { }; #endif -#if CONFIG_RK30_PWM_REGULATOR -const static int pwm_voltage_map[] = { - 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 1400000 -}; - -static struct regulator_consumer_supply pwm_dcdc1_consumers[] = { - { - .supply = "vdd_core", - } -}; - -struct regulator_init_data pwm_regulator_init_dcdc[1] = -{ - { - .constraints = { - .name = "PWM_DCDC1", - .min_uV = 600000, - .max_uV = 1800000, //0.6-1.8V - .apply_uV = true, - .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, - }, - .num_consumer_supplies = ARRAY_SIZE(pwm_dcdc1_consumers), - .consumer_supplies = pwm_dcdc1_consumers, - }, -}; - -static struct pwm_platform_data pwm_regulator_info[1] = { - { - .pwm_id = 3, - .pwm_gpio = RK30_PIN0_PD7, - .pwm_iomux_name = GPIO0D7_PWM3_NAME, - .pwm_iomux_pwm = GPIO0D_PWM3, - .pwm_iomux_gpio = GPIO0D_GPIO0D6, - .pwm_voltage = 1100000, - .min_uV = 1000000, - .max_uV = 1400000, - .coefficient = 455, //45.5% - .pwm_voltage_map = pwm_voltage_map, - .init_data = &pwm_regulator_init_dcdc[0], - }, -}; - -struct platform_device pwm_regulator_device[1] = { - { - .name = "pwm-voltage-regulator", - .id = 0, - .dev = { - .platform_data = &pwm_regulator_info[0], - } - }, -}; -#endif - #ifdef CONFIG_RK29_VMAC #define PHY_PWR_EN_GPIO RK30_PIN1_PD6 #include "board-rk30-sdk-vmac.c" @@ -1461,9 +1403,6 @@ static struct platform_device device_rfkill_rk = { #endif static struct platform_device *devices[] __initdata = { -#ifdef CONFIG_RK30_PWM_REGULATOR - &pwm_regulator_device[0], -#endif #ifdef CONFIG_BACKLIGHT_RK29_BL &rk29_device_backlight, #endif @@ -1601,13 +1540,7 @@ static struct i2c_board_info __initdata i2c0_info[] = { #endif #ifdef CONFIG_I2C1_RK30 -#ifdef CONFIG_MFD_WM831X_I2C #include "board-rk30-sdk-wm8326.c" -#endif -#ifdef CONFIG_MFD_TPS65910 -#define TPS65910_HOST_IRQ RK30_PIN6_PA4 -#include "board-rk30-sdk-tps65910.c" -#endif static struct i2c_board_info __initdata i2c1_info[] = { #if defined (CONFIG_MFD_WM831X_I2C) @@ -1619,16 +1552,6 @@ static struct i2c_board_info __initdata i2c1_info[] = { .platform_data = &wm831x_platdata, }, #endif -#if defined (CONFIG_MFD_TPS65910) - { - .type = "tps65910", - .addr = TPS65910_I2C_ID0, - .flags = 0, - .irq = TPS65910_HOST_IRQ, - .platform_data = &tps65910_data, - }, -#endif - }; #endif diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index 09ac6c3ca67b..dd7813012b43 100755 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -232,7 +232,6 @@ int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask) } EXPORT_SYMBOL_GPL(tps65910_clear_bits); -extern int PMIC_IS_TPS6591x; static int tps65910_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -294,7 +293,6 @@ static int tps65910_i2c_probe(struct i2c_client *i2c, } } printk("%s:irq=%d,irq_base=%d\n",__func__,init_data->irq,init_data->irq_base); - PMIC_IS_TPS6591x = 1; return ret; err: diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 493b1ab52d84..504314e87de1 100755 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -1461,7 +1461,7 @@ static struct mfd_cell backlight_devs[] = { .name = "wm831x-backlight", }, }; -extern int PMIC_IS_WM831X; + /* * Instantiate the generic non-control parts of the device. */ @@ -1729,7 +1729,6 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) goto err_irq; } } - PMIC_IS_WM831X = 1; return 0; From 5a37c42ad377be8da380b2fdeb5da2103c16704c Mon Sep 17 00:00:00 2001 From: root Date: Wed, 1 Aug 2012 12:56:16 +0800 Subject: [PATCH 067/261] rk30 camera: disable 24M mclk, version update to 0.2.e. --- drivers/media/video/rk30_camera_oneframe.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/rk30_camera_oneframe.c b/drivers/media/video/rk30_camera_oneframe.c index 1d5e368d540d..7bdcfb27b93b 100755 --- a/drivers/media/video/rk30_camera_oneframe.c +++ b/drivers/media/video/rk30_camera_oneframe.c @@ -211,7 +211,7 @@ module_param(debug, int, S_IRUGO|S_IWUSR); 2. irq process is splitted to two step. *v0.x.e: fix bugs of early suspend when display_pd is closed. */ -#define RK_CAM_VERSION_CODE KERNEL_VERSION(0, 2, 0xc) +#define RK_CAM_VERSION_CODE KERNEL_VERSION(0, 2, 0xe) /* limit to rk29 hardware capabilities */ #define RK_CAM_BUS_PARAM (SOCAM_MASTER |\ @@ -924,7 +924,12 @@ static void rk_camera_deactivate(struct rk_camera_dev *pcdev) clk_disable(pcdev->hclk_cif); clk_disable(pcdev->cif_clk_in); + clk_disable(pcdev->cif_clk_out); + clk_enable(pcdev->cif_clk_out); + clk_set_rate(pcdev->cif_clk_out,48*1000*1000); + clk_disable(pcdev->cif_clk_out); + clk_disable(pcdev->pd_cif); return; } From 3b8800fc347b43eb4701271613963ad42f2c6625 Mon Sep 17 00:00:00 2001 From: ywj Date: Wed, 1 Aug 2012 13:20:17 +0800 Subject: [PATCH 068/261] factory develop for usb --- drivers/usb/gadget/android.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c index 703d281f0688..a2189fd4f0b1 100644 --- a/drivers/usb/gadget/android.c +++ b/drivers/usb/gadget/android.c @@ -590,8 +590,11 @@ static ssize_t mass_storage_inquiry_store(struct device *dev, struct mass_storage_function_config *config = f->config; if (size >= sizeof(config->common->inquiry_string)) return -EINVAL; - if (sscanf(buf, "%s", config->common->inquiry_string) != 1) - return -EINVAL; + //if (sscanf(buf, "%s", config->common->inquiry_string) != 1) + // return -EINVAL; + + memcpy(config->common->inquiry_string,buf,sizeof config->common->inquiry_string); + return size; } From 40ae8e60154b1d7aa7582db7e994cf1ac98c36ac Mon Sep 17 00:00:00 2001 From: ywj Date: Wed, 1 Aug 2012 14:07:04 +0800 Subject: [PATCH 069/261] kernel logo add sign for factory tool --- scripts/pnmtologo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/pnmtologo.c b/scripts/pnmtologo.c index 3b2698d427fc..92af1e58584f 100755 --- a/scripts/pnmtologo.c +++ b/scripts/pnmtologo.c @@ -76,6 +76,7 @@ unsigned char data_name[] = { }; unsigned char clut_name[] = { + 0x70, 0x70, 0x6c, 0x6C, 0x6F, 0x67, 0x6F, 0x5F, 0x52, 0x4B, 0x6C, 0x6F, From 1f0a3da031916aedcff51f2c666ee2833f89a468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=99=B4?= Date: Wed, 1 Aug 2012 17:13:56 +0800 Subject: [PATCH 070/261] rk30:Support both of compatible pmic wm8326 and tps65910 --- arch/arm/mach-rk30/board-rk30-phonepad.c | 45 ++++++++++++---- arch/arm/mach-rk30/board-rk30-sdk-tps65910.c | 7 ++- arch/arm/mach-rk30/board-rk30-sdk-wm8326.c | 10 ++-- arch/arm/mach-rk30/board-rk30-sdk.c | 55 ++++++++++++++++++-- 4 files changed, 97 insertions(+), 20 deletions(-) diff --git a/arch/arm/mach-rk30/board-rk30-phonepad.c b/arch/arm/mach-rk30/board-rk30-phonepad.c index 86020f098eb7..7680d9e6576d 100755 --- a/arch/arm/mach-rk30/board-rk30-phonepad.c +++ b/arch/arm/mach-rk30/board-rk30-phonepad.c @@ -1798,6 +1798,9 @@ static struct i2c_board_info __initdata i2c0_info[] = { }; #endif +#define PMIC_TYPE_WM8326 1 +#define PMIC_TYPE_TPS65910 2 +int __sramdata g_pmic_type = 0; #ifdef CONFIG_I2C1_RK30 #ifdef CONFIG_MFD_WM831X_I2C #include "board-rk30-sdk-wm8326.c" @@ -1829,6 +1832,25 @@ static struct i2c_board_info __initdata i2c1_info[] = { }; #endif + +void __sramfunc board_pmu_suspend(void) +{ + if(g_pmic_type == PMIC_TYPE_WM8326) + board_pmu_wm8326_suspend(); + else if(g_pmic_type == PMIC_TYPE_TPS65910) + board_pmu_tps65910_suspend(); + +} + +void __sramfunc board_pmu_resume(void) +{ + if(g_pmic_type == PMIC_TYPE_WM8326) + board_pmu_wm8326_resume(); + else if(g_pmic_type == PMIC_TYPE_TPS65910) + board_pmu_tps65910_resume(); +} + + #ifdef CONFIG_I2C2_RK30 static struct i2c_board_info __initdata i2c2_info[] = { #if defined (CONFIG_TOUCHSCREEN_GT8XX) @@ -1955,16 +1977,19 @@ void rk30_pm_power_off(void) arm_pm_restart(0, NULL); } #endif -#if PMIC_IS_WM831X -#if defined(CONFIG_MFD_WM831X) - wm831x_set_bits(Wm831x,WM831X_GPIO_LEVEL,0x0001,0x0000); //set sys_pwr 0 - wm831x_device_shutdown(Wm831x);//wm8326 shutdown -#endif -#else -#if defined(CONFIG_MFD_TPS65910) - tps65910_device_shutdown();//tps65910 shutdown -#endif -#endif + #if defined(CONFIG_MFD_WM831X) + if(g_pmic_type == PMIC_TYPE_WM8326) + { + wm831x_set_bits(Wm831x,WM831X_GPIO_LEVEL,0x0001,0x0000); //set sys_pwr 0 + wm831x_device_shutdown(Wm831x);//wm8326 shutdown + } + #endif + #if defined(CONFIG_MFD_TPS65910) + if(g_pmic_type == PMIC_TYPE_TPS65910) + { + tps65910_device_shutdown();//tps65910 shutdown + } + #endif gpio_direction_output(POWER_ON_PIN, GPIO_LOW); while(1); } diff --git a/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c b/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c index ac2ee6b19f1f..69e4afa8f076 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c +++ b/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c @@ -230,6 +230,9 @@ int tps65910_post_init(struct tps65910 *tps65910) struct regulator *ldo; printk("%s,line=%d\n", __func__,__LINE__); + g_pmic_type = PMIC_TYPE_TPS65910; + printk("%s:g_pmic_type=%d\n",__func__,g_pmic_type); + dcdc = regulator_get(NULL, "vio"); //vcc_io regulator_set_voltage(dcdc, 3000000, 3000000); regulator_enable(dcdc); @@ -576,13 +579,13 @@ static struct regulator_init_data tps65910_ldo8 = { .consumer_supplies = tps65910_ldo8_supply, }; -void __sramfunc board_pmu_suspend(void) +void __sramfunc board_pmu_tps65910_suspend(void) { grf_writel(GPIO6_PB1_DIR_OUT, GRF_GPIO6L_DIR_ADDR); grf_writel(GPIO6_PB1_DO_HIGH, GRF_GPIO6L_DO_ADDR); //set gpio6_b1 output low grf_writel(GPIO6_PB1_EN_MASK, GRF_GPIO6L_EN_ADDR); } -void __sramfunc board_pmu_resume(void) +void __sramfunc board_pmu_tps65910_resume(void) { grf_writel(GPIO6_PB1_DIR_OUT, GRF_GPIO6L_DIR_ADDR); grf_writel(GPIO6_PB1_DO_LOW, GRF_GPIO6L_DO_ADDR); //set gpio6_b1 output low diff --git a/arch/arm/mach-rk30/board-rk30-sdk-wm8326.c b/arch/arm/mach-rk30/board-rk30-sdk-wm8326.c index ce3050e7e6df..fbba1ea0aeb3 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk-wm8326.c +++ b/arch/arm/mach-rk30/board-rk30-sdk-wm8326.c @@ -182,7 +182,10 @@ int wm831x_post_init(struct wm831x *Wm831x) struct regulator *dcdc; struct regulator *ldo; - + + g_pmic_type = PMIC_TYPE_WM8326; + printk("%s:g_pmic_type=%d\n",__func__,g_pmic_type); + ldo = regulator_get(NULL, "ldo6"); //vcc_33 regulator_set_voltage(ldo, 3300000, 3300000); regulator_set_suspend_voltage(ldo, 3300000); @@ -774,14 +777,14 @@ static int wm831x_init_pin_type(struct wm831x *wm831x) return 0; } -void __sramfunc board_pmu_suspend(void) +void __sramfunc board_pmu_wm8326_suspend(void) { cru_writel(CRU_CLKGATE5_GRFCLK_ON,CRU_CLKGATE5_CON_ADDR); //open grf clk grf_writel(GPIO6_PB1_DIR_OUT, GRF_GPIO6L_DIR_ADDR); grf_writel(GPIO6_PB1_DO_HIGH, GRF_GPIO6L_DO_ADDR); //set gpio6_b1 output low grf_writel(GPIO6_PB1_EN_MASK, GRF_GPIO6L_EN_ADDR); } -void __sramfunc board_pmu_resume(void) +void __sramfunc board_pmu_wm8326_resume(void) { grf_writel(GPIO6_PB1_DIR_OUT, GRF_GPIO6L_DIR_ADDR); grf_writel(GPIO6_PB1_DO_LOW, GRF_GPIO6L_DO_ADDR); //set gpio6_b1 output high @@ -792,6 +795,7 @@ void __sramfunc board_pmu_resume(void) sram_udelay(10000); #endif } + static struct wm831x_pdata wm831x_platdata = { /** Called before subdevices are set up */ diff --git a/arch/arm/mach-rk30/board-rk30-sdk.c b/arch/arm/mach-rk30/board-rk30-sdk.c index 0b27edc772dd..1eaec78a1308 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk.c +++ b/arch/arm/mach-rk30/board-rk30-sdk.c @@ -1538,9 +1538,17 @@ static struct i2c_board_info __initdata i2c0_info[] = { }; #endif - +#define PMIC_TYPE_WM8326 1 +#define PMIC_TYPE_TPS65910 2 +int __sramdata g_pmic_type = 0; #ifdef CONFIG_I2C1_RK30 +#ifdef CONFIG_MFD_WM831X_I2C #include "board-rk30-sdk-wm8326.c" +#endif +#ifdef CONFIG_MFD_TPS65910 +#define TPS65910_HOST_IRQ RK30_PIN6_PA4 +#include "board-rk30-sdk-tps65910.c" +#endif static struct i2c_board_info __initdata i2c1_info[] = { #if defined (CONFIG_MFD_WM831X_I2C) @@ -1552,9 +1560,36 @@ static struct i2c_board_info __initdata i2c1_info[] = { .platform_data = &wm831x_platdata, }, #endif +#if defined (CONFIG_MFD_TPS65910) + { + .type = "tps65910", + .addr = TPS65910_I2C_ID0, + .flags = 0, + .irq = TPS65910_HOST_IRQ, + .platform_data = &tps65910_data, + }, +#endif }; #endif + +void __sramfunc board_pmu_suspend(void) +{ + if(g_pmic_type == PMIC_TYPE_WM8326) + board_pmu_wm8326_suspend(); + else if(g_pmic_type == PMIC_TYPE_TPS65910) + board_pmu_tps65910_suspend(); + +} + +void __sramfunc board_pmu_resume(void) +{ + if(g_pmic_type == PMIC_TYPE_WM8326) + board_pmu_wm8326_resume(); + else if(g_pmic_type == PMIC_TYPE_TPS65910) + board_pmu_tps65910_resume(); +} + #ifdef CONFIG_I2C2_RK30 static struct i2c_board_info __initdata i2c2_info[] = { #if defined (CONFIG_TOUCHSCREEN_GT8XX) @@ -1638,10 +1673,20 @@ static void rk30_pm_power_off(void) { printk(KERN_ERR "rk30_pm_power_off start...\n"); gpio_direction_output(POWER_ON_PIN, GPIO_LOW); -#if defined(CONFIG_MFD_WM831X) - wm831x_set_bits(Wm831x,WM831X_GPIO_LEVEL,0x0001,0x0000); //set sys_pwr 0 - wm831x_device_shutdown(Wm831x);//wm8326 shutdown -#endif + #if defined(CONFIG_MFD_WM831X) + if(g_pmic_type == PMIC_TYPE_WM8326) + { + wm831x_set_bits(Wm831x,WM831X_GPIO_LEVEL,0x0001,0x0000); //set sys_pwr 0 + wm831x_device_shutdown(Wm831x);//wm8326 shutdown + } + #endif + #if defined(CONFIG_MFD_TPS65910) + if(g_pmic_type == PMIC_TYPE_TPS65910) + { + tps65910_device_shutdown();//tps65910 shutdown + } + #endif + while (1); } From 7ab463de1ea6ee0d6a3128709108f94bdecd9c7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=99=B4?= Date: Wed, 1 Aug 2012 17:41:38 +0800 Subject: [PATCH 071/261] rk30:modify suspend func for 8326 and tps65910 --- arch/arm/mach-rk30/board-rk30-phonepad.c | 15 +++++++++++---- arch/arm/mach-rk30/board-rk30-sdk.c | 16 +++++++++++----- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-rk30/board-rk30-phonepad.c b/arch/arm/mach-rk30/board-rk30-phonepad.c index 7680d9e6576d..9ef6f09f2ad1 100755 --- a/arch/arm/mach-rk30/board-rk30-phonepad.c +++ b/arch/arm/mach-rk30/board-rk30-phonepad.c @@ -1835,19 +1835,26 @@ static struct i2c_board_info __initdata i2c1_info[] = { void __sramfunc board_pmu_suspend(void) { + #if defined (CONFIG_MFD_WM831X_I2C) if(g_pmic_type == PMIC_TYPE_WM8326) board_pmu_wm8326_suspend(); - else if(g_pmic_type == PMIC_TYPE_TPS65910) + #endif + #if defined (CONFIG_MFD_TPS65910) + if(g_pmic_type == PMIC_TYPE_TPS65910) board_pmu_tps65910_suspend(); - + #endif } void __sramfunc board_pmu_resume(void) { + #if defined (CONFIG_MFD_WM831X_I2C) if(g_pmic_type == PMIC_TYPE_WM8326) board_pmu_wm8326_resume(); - else if(g_pmic_type == PMIC_TYPE_TPS65910) - board_pmu_tps65910_resume(); + #endif + #if defined (CONFIG_MFD_TPS65910) + if(g_pmic_type == PMIC_TYPE_TPS65910) + board_pmu_tps65910_resume(); + #endif } diff --git a/arch/arm/mach-rk30/board-rk30-sdk.c b/arch/arm/mach-rk30/board-rk30-sdk.c index 1eaec78a1308..4865314c883f 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk.c +++ b/arch/arm/mach-rk30/board-rk30-sdk.c @@ -1572,22 +1572,28 @@ static struct i2c_board_info __initdata i2c1_info[] = { }; #endif - void __sramfunc board_pmu_suspend(void) { + #if defined (CONFIG_MFD_WM831X_I2C) if(g_pmic_type == PMIC_TYPE_WM8326) board_pmu_wm8326_suspend(); - else if(g_pmic_type == PMIC_TYPE_TPS65910) + #endif + #if defined (CONFIG_MFD_TPS65910) + if(g_pmic_type == PMIC_TYPE_TPS65910) board_pmu_tps65910_suspend(); - + #endif } void __sramfunc board_pmu_resume(void) { + #if defined (CONFIG_MFD_WM831X_I2C) if(g_pmic_type == PMIC_TYPE_WM8326) board_pmu_wm8326_resume(); - else if(g_pmic_type == PMIC_TYPE_TPS65910) - board_pmu_tps65910_resume(); + #endif + #if defined (CONFIG_MFD_TPS65910) + if(g_pmic_type == PMIC_TYPE_TPS65910) + board_pmu_tps65910_resume(); + #endif } #ifdef CONFIG_I2C2_RK30 From 78f5f645e4449b61cddafc654d03fc0ad233ef09 Mon Sep 17 00:00:00 2001 From: lw Date: Wed, 1 Aug 2012 19:21:24 +0800 Subject: [PATCH 072/261] phonepad:add wm831x config --- arch/arm/configs/rk30_phonepad_defconfig | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/arm/configs/rk30_phonepad_defconfig b/arch/arm/configs/rk30_phonepad_defconfig index dc80af7bb5fa..be3bdf5d9102 100644 --- a/arch/arm/configs/rk30_phonepad_defconfig +++ b/arch/arm/configs/rk30_phonepad_defconfig @@ -227,7 +227,6 @@ CONFIG_INPUT_KEYRESET=y CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TABLET=y CONFIG_INPUT_TOUCHSCREEN=y -CONFIG_TOUCHSCREEN_GT82X_IIC=y CONFIG_INPUT_MISC=y CONFIG_INPUT_KEYCHORD=y CONFIG_INPUT_UINPUT=y @@ -257,16 +256,20 @@ CONFIG_I2C2_CONTROLLER_RK30=y CONFIG_I2C3_CONTROLLER_RK30=y CONFIG_I2C4_CONTROLLER_RK30=y CONFIG_RK_HEADSET_IRQ_HOOK_ADC_DET=y +CONFIG_GPIO_WM831X=y CONFIG_EXPANDED_GPIO_NUM=0 CONFIG_EXPANDED_GPIO_IRQ_NUM=0 CONFIG_SPI_FPGA_GPIO_NUM=0 CONFIG_SPI_FPGA_GPIO_IRQ_NUM=0 CONFIG_POWER_SUPPLY=y -CONFIG_TEST_POWER=y +CONFIG_WM831X_BACKUP=y +CONFIG_WM8326_VBAT_LOW_DETECTION=y # CONFIG_HWMON is not set CONFIG_MFD_TPS65910=y +CONFIG_MFD_WM831X_I2C=y CONFIG_REGULATOR=y CONFIG_REGULATOR_TPS65910=y +CONFIG_REGULATOR_WM831X=y CONFIG_RK30_PWM_REGULATOR=y CONFIG_MEDIA_SUPPORT=y CONFIG_VIDEO_DEV=y @@ -382,6 +385,7 @@ CONFIG_LEDS_GPIO=y CONFIG_SWITCH=y CONFIG_SWITCH_GPIO=y CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_WM831X=y CONFIG_TPS65910_RTC=y CONFIG_STAGING=y CONFIG_ANDROID=y From db120561242604acd4cbf1ba1d9bb2cc0debf77f Mon Sep 17 00:00:00 2001 From: lw Date: Wed, 1 Aug 2012 20:07:50 +0800 Subject: [PATCH 073/261] phonepad:fix touch screen driver bug --- arch/arm/configs/rk30_phonepad_defconfig | 1 + drivers/input/touchscreen/goodix_touch_82x.c | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/configs/rk30_phonepad_defconfig b/arch/arm/configs/rk30_phonepad_defconfig index be3bdf5d9102..b9bf49c0d65e 100644 --- a/arch/arm/configs/rk30_phonepad_defconfig +++ b/arch/arm/configs/rk30_phonepad_defconfig @@ -227,6 +227,7 @@ CONFIG_INPUT_KEYRESET=y CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TABLET=y CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_GT82X_IIC=y CONFIG_INPUT_MISC=y CONFIG_INPUT_KEYCHORD=y CONFIG_INPUT_UINPUT=y diff --git a/drivers/input/touchscreen/goodix_touch_82x.c b/drivers/input/touchscreen/goodix_touch_82x.c index a665c033ea7d..b745f3c3e41a 100755 --- a/drivers/input/touchscreen/goodix_touch_82x.c +++ b/drivers/input/touchscreen/goodix_touch_82x.c @@ -804,7 +804,6 @@ static s32 goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id //Test I2C connection. // GTDEBUG_MSG("GT82X++++++ Testing I2C connection...\n"); for(retry = 0;retry < 3; retry++) - while(1) //For GTDEBUG use! { ret = i2c_pre_cmd(ts); if (ret > 0) @@ -815,7 +814,7 @@ static s32 goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id { dev_err(&client->dev, "Warnning: I2C communication might be ERROR!\n"); GTDEBUG_MSG("I2C test failed. I2C addr:%x\n", client->addr); - goodix_ts_remove(ts->client); kfree(ts); + goodix_ts_remove(ts->client); return -1; } // printk("gt82x---777777777777777\n"); @@ -832,7 +831,7 @@ static s32 goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id { ts->bad_data=1; GTDEBUG_MSG("Initialize failed!\n"); - goodix_ts_remove(ts->client); kfree(ts); + goodix_ts_remove(ts->client); return -1; } //Enable interrupt From af9a995342eeb5f3dc6bc09b38bc4237f6574ea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=8B=E7=A7=80=E6=9D=B0?= Date: Wed, 1 Aug 2012 20:36:03 +0800 Subject: [PATCH 074/261] phonepad: rt3261 fix suspend and resume i2c error --- sound/soc/codecs/rt3261.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt3261.c b/sound/soc/codecs/rt3261.c index dc3a678e0372..c49b3334f6c2 100644 --- a/sound/soc/codecs/rt3261.c +++ b/sound/soc/codecs/rt3261.c @@ -2850,7 +2850,7 @@ static int rt3261_suspend(struct snd_soc_codec *codec, pm_message_t state) * (3) DSP IIS interface power off * (4) Toggle pin of codec LDO1 to power off */ - rt3261_dsp_suspend(codec, state); + //rt3261_dsp_suspend(codec, state); #endif rt3261_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; @@ -2861,7 +2861,7 @@ static int rt3261_resume(struct snd_soc_codec *codec) rt3261_set_bias_level(codec, SND_SOC_BIAS_STANDBY); #if (CONFIG_SND_SOC_RT3261_MODULE | CONFIG_SND_SOC_RT3261) /* After opening LDO of codec, then close LDO of DSP. */ - rt3261_dsp_resume(codec); + //rt3261_dsp_resume(codec); #endif return 0; } From 5633de6473d58aa204ec8b29107d68c415477c97 Mon Sep 17 00:00:00 2001 From: kfx Date: Thu, 2 Aug 2012 10:17:01 +0800 Subject: [PATCH 075/261] rk2928: sdk init --- arch/arm/configs/rk2928_sdk_defconfig | 396 +++++ arch/arm/mach-rk2928/Makefile | 1 + arch/arm/mach-rk2928/board-rk2928-sdk-key.c | 65 + arch/arm/mach-rk2928/board-rk2928-sdk-sdmmc.c | 8 +- arch/arm/mach-rk2928/board-rk2928-sdk.c | 1277 +++++++++++++++++ arch/arm/mach-rk2928/common.c | 2 + arch/arm/mach-rk2928/devices.c | 3 + arch/arm/mach-rk2928/include/mach/board.h | 26 + drivers/input/touchscreen/eeti_egalax_i2c.c | 5 +- drivers/video/backlight/Kconfig | 2 +- drivers/video/backlight/rk29_backlight.c | 7 +- sound/soc/rk29/rk30_i2s.c | 8 +- 12 files changed, 1787 insertions(+), 13 deletions(-) create mode 100755 arch/arm/configs/rk2928_sdk_defconfig create mode 100755 arch/arm/mach-rk2928/board-rk2928-sdk-key.c create mode 100755 arch/arm/mach-rk2928/board-rk2928-sdk.c diff --git a/arch/arm/configs/rk2928_sdk_defconfig b/arch/arm/configs/rk2928_sdk_defconfig new file mode 100755 index 000000000000..fb18b35ad28e --- /dev/null +++ b/arch/arm/configs/rk2928_sdk_defconfig @@ -0,0 +1,396 @@ +CONFIG_EXPERIMENTAL=y +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_KERNEL_LZO=y +CONFIG_LOG_BUF_SHIFT=19 +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_CGROUP_SCHED=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_PANIC_TIMEOUT=1 +# CONFIG_SYSCTL_SYSCALL is not set +# CONFIG_ELF_CORE is not set +CONFIG_ASHMEM=y +# CONFIG_AIO is not set +CONFIG_EMBEDDED=y +# CONFIG_SLUB_DEBUG is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_ARCH_RK2928=y +CONFIG_WIFI_CONTROL_FUNC=y +CONFIG_RK_DEBUG_UART=2 +CONFIG_FIQ_DEBUGGER=y +CONFIG_FIQ_DEBUGGER_NO_SLEEP=y +CONFIG_FIQ_DEBUGGER_CONSOLE=y +CONFIG_FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +CONFIG_HIGHMEM=y +CONFIG_COMPACTION=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=32768 +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="console=ttyFIQ0 androidboot.console=ttyFIQ0 init=/init" +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_WAKELOCK=y +CONFIG_PM_RUNTIME=y +CONFIG_SUSPEND_TIME=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_INET_ESP=y +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_TUNNEL=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SIP=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_REJECT_SKERR=y +CONFIG_IP_NF_TARGET_LOG=y +CONFIG_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_TARGET_LOG=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_TARGET_REJECT_SKERR=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE=y +# CONFIG_BRIDGE_IGMP_SNOOPING is not set +CONFIG_PHONET=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_BT=y +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_HIDP=y +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIBCM4325=y +CONFIG_BT_AUTOSLEEP=y +CONFIG_RFKILL=y +CONFIG_RFKILL_RK=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_FIRMWARE_IN_KERNEL is not set +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_NAND_IDS=y +CONFIG_MTD_RKNAND=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_MISC_DEVICES=y +CONFIG_UID_STAT=y +CONFIG_APANIC=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_NETDEVICES=y +CONFIG_PHYLIB=y +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +CONFIG_WLAN_80211=y +CONFIG_RKWIFI=y +CONFIG_USB_USBNET=y +CONFIG_PPP=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_MPPE=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_KEYRESET=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_EETI_EGALAX=y +CONFIG_EETI_EGALAX_MAX_X=1087 +CONFIG_EETI_EGALAX_MAX_Y=800 +CONFIG_INPUT_MISC=y +CONFIG_INPUT_KEYCHORD=y +CONFIG_INPUT_UINPUT=y +CONFIG_COMPASS_AK8975=y +CONFIG_GS_MMA8452=y +CONFIG_GYRO_L3G4200D=y +CONFIG_LS_CM3217=y +CONFIG_SENSOR_DEVICE=y +CONFIG_GSENSOR_DEVICE=y +CONFIG_COMPASS_DEVICE=y +CONFIG_GYROSCOPE_DEVICE=y +CONFIG_LIGHT_DEVICE=y +# CONFIG_SERIO is not set +# CONFIG_CONSOLE_TRANSLATIONS is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_RK29=y +CONFIG_UART0_RK29=y +CONFIG_UART0_CTS_RTS_RK29=y +# CONFIG_HW_RANDOM is not set +CONFIG_I2C=y +# CONFIG_I2C_COMPAT is not set +CONFIG_I2C0_CONTROLLER_RK30=y +CONFIG_I2C1_CONTROLLER_RK30=y +CONFIG_I2C2_CONTROLLER_RK30=y +CONFIG_I2C3_CONTROLLER_RK30=y +CONFIG_ADC_RK30=y +CONFIG_EXPANDED_GPIO_NUM=0 +CONFIG_EXPANDED_GPIO_IRQ_NUM=0 +CONFIG_SPI_FPGA_GPIO_NUM=0 +CONFIG_SPI_FPGA_GPIO_IRQ_NUM=0 +CONFIG_POWER_SUPPLY=y +CONFIG_TEST_POWER=y +# CONFIG_HWMON is not set +CONFIG_MFD_WM831X_I2C=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_WM831X=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_VIDEO_DEV=y +CONFIG_SOC_CAMERA=y +CONFIG_SOC_CAMERA_OV2659=y +CONFIG_SOC_CAMERA_OV5642=y +CONFIG_VIDEO_RK29=y +CONFIG_VIDEO_RK29_CAMMEM_ION=y +CONFIG_ION=y +CONFIG_ION_ROCKCHIP=y +CONFIG_FB=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set +CONFIG_DISPLAY_SUPPORT=y +CONFIG_LCD_HSD100PXN=y +CONFIG_FB_ROCKCHIP=y +CONFIG_LCDC_RK2928=y +CONFIG_RK_HDMI=y +CONFIG_RGA_RK30=y +CONFIG_RK_LVDS=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +# CONFIG_SND_SUPPORT_OLD_API is not set +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_ARM is not set +CONFIG_SND_SOC=y +CONFIG_SND_RK29_SOC=y +CONFIG_SND_I2S_DMA_EVENT_STATIC=y +CONFIG_SND_RK_SOC_RK2928=y +CONFIG_SND_RK29_CODEC_SOC_SLAVE=y +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WALTOP=y +CONFIG_HID_GYRATION=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LCPOWER=y +CONFIG_HID_LOGITECH=y +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_LOGIWII_FF=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +CONFIG_HID_QUANTA=y +CONFIG_HID_ROCCAT_ARVO=y +CONFIG_HID_ROCCAT_KONE=y +CONFIG_HID_ROCCAT_KONEPLUS=y +CONFIG_HID_ROCCAT_KOVAPLUS=y +CONFIG_HID_ROCCAT_PYRA=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +CONFIG_GREENASIA_FF=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_THRUSTMASTER=y +CONFIG_THRUSTMASTER_FF=y +CONFIG_HID_WACOM=y +CONFIG_HID_ZEROPLUS=y +CONFIG_ZEROPLUS_FF=y +CONFIG_HID_ZYDACRON=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_OTG_BLACKLIST_HUB=y +CONFIG_USB_STORAGE=y +CONFIG_USB_SERIAL=y +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_OPTION=y +CONFIG_USB_GADGET=y +CONFIG_USB20_HOST=y +CONFIG_USB20_OTG=y +CONFIG_MMC=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_EMBEDDED_SDIO=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_SDMMC_RK29=y +CONFIG_SWITCH=y +CONFIG_SWITCH_GPIO=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_WM831X=y +CONFIG_STAGING=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOGGER=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +# CONFIG_CMMB is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_FS_XATTR is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_XATTR is not set +# CONFIG_DNOTIFY is not set +CONFIG_FUSE_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +# CONFIG_MISC_FILESYSTEMS is not set +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_EFI_PARTITION=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DETECT_HUNG_TASK=y +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_FTRACE is not set +CONFIG_CRYPTO_TWOFISH=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/arm/mach-rk2928/Makefile b/arch/arm/mach-rk2928/Makefile index 6a734d2980e3..a9df193cfc0a 100644 --- a/arch/arm/mach-rk2928/Makefile +++ b/arch/arm/mach-rk2928/Makefile @@ -7,3 +7,4 @@ obj-y += iomux.o obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_MACH_RK2928_FPGA) += board-rk2928-fpga.o board-rk2928-fpga-key.o +obj-$(CONFIG_MACH_RK2928_SDK) += board-rk2928-sdk.o board-rk2928-sdk-key.o diff --git a/arch/arm/mach-rk2928/board-rk2928-sdk-key.c b/arch/arm/mach-rk2928/board-rk2928-sdk-key.c new file mode 100755 index 000000000000..1074027e5515 --- /dev/null +++ b/arch/arm/mach-rk2928/board-rk2928-sdk-key.c @@ -0,0 +1,65 @@ +#include +#include + +#define EV_ENCALL KEY_F4 +#define EV_MENU KEY_F1 + +#define PRESS_LEV_LOW 1 +#define PRESS_LEV_HIGH 0 + +static struct rk29_keys_button key_button[] = { + { + .desc = "vol-", + .code = KEY_VOLUMEDOWN, + .gpio = RK2928_PIN0_PD1, + .active_low = PRESS_LEV_LOW, + }, + { + .desc = "play", + .code = KEY_POWER, + .gpio = RK2928_PIN3_PC5, + .active_low = PRESS_LEV_LOW, + //.code_long_press = EV_ENCALL, + .wakeup = 1, + }, + { + .desc = "vol+", + .code = KEY_VOLUMEUP, + .gpio = RK2928_PIN0_PD0, + .active_low = PRESS_LEV_LOW, + }, + { + .desc = "menu", + .code = EV_MENU, + .adc_value = 135, + .gpio = INVALID_GPIO, + .active_low = PRESS_LEV_LOW, + }, + { + .desc = "home", + .code = KEY_HOME, + .adc_value = 550, + .gpio = INVALID_GPIO, + .active_low = PRESS_LEV_LOW, + }, + { + .desc = "esc", + .code = KEY_BACK, + .adc_value = 334, + .gpio = INVALID_GPIO, + .active_low = PRESS_LEV_LOW, + }, + { + .desc = "camera", + .code = KEY_CAMERA, + .adc_value = 743, + .gpio = INVALID_GPIO, + .active_low = PRESS_LEV_LOW, + }, +}; +struct rk29_keys_platform_data rk29_keys_pdata = { + .buttons = key_button, + .nbuttons = ARRAY_SIZE(key_button), + .chn = 1, //chn: 0-7, if do not use ADC,set 'chn' -1 +}; + diff --git a/arch/arm/mach-rk2928/board-rk2928-sdk-sdmmc.c b/arch/arm/mach-rk2928/board-rk2928-sdk-sdmmc.c index 09395ed49c40..e74fb1ab7ab0 100644 --- a/arch/arm/mach-rk2928/board-rk2928-sdk-sdmmc.c +++ b/arch/arm/mach-rk2928/board-rk2928-sdk-sdmmc.c @@ -202,11 +202,7 @@ static void rk29_sdmmc_set_iomux(int device_id, unsigned int bus_width) //int rk29sdk_bt_power_state = 0; #ifdef CONFIG_WIFI_CONTROL_FUNC -//#define RK29SDK_WIFI_BT_GPIO_POWER_N RK30_PIN3_PD0 -//#define RK29SDK_WIFI_GPIO_RESET_N RK30_PIN3_PD0 -//#define RK29SDK_BT_GPIO_RESET_N RK30_PIN3_PD1 -#define RK30SDK_WIFI_GPIO_POWER_N RK30_PIN3_PD0 -//#define RK30SDK_BT_GPIO_POWER_N RK30_PIN3_PD1 +#define RK30SDK_WIFI_GPIO_POWER_N RK2928_PIN0_PD6 #define PREALLOC_WLAN_SEC_NUM 4 #define PREALLOC_WLAN_BUF_NUM 160 @@ -408,7 +404,7 @@ int rk29sdk_wifi_set_carddetect(int val) } EXPORT_SYMBOL(rk29sdk_wifi_set_carddetect); -#define WIFI_HOST_WAKE RK30_PIN3_PD2 +#define WIFI_HOST_WAKE RK2928_PIN3_PC0 static struct resource resources[] = { { diff --git a/arch/arm/mach-rk2928/board-rk2928-sdk.c b/arch/arm/mach-rk2928/board-rk2928-sdk.c new file mode 100755 index 000000000000..b01d4d92868b --- /dev/null +++ b/arch/arm/mach-rk2928/board-rk2928-sdk.c @@ -0,0 +1,1277 @@ +/* arch/arm/mach-rk2928/board-rk2928-fpga.c + * + * Copyright (C) 2012 ROCKCHIP, Inc. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +//#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_HDMI_RK30) + #include "../../../drivers/video/rockchip/hdmi/rk_hdmi.h" +#endif + +#if defined(CONFIG_SPIM_RK29) +#include "../../../drivers/spi/rk29_spim.h" +#endif + +#ifdef CONFIG_THREE_FB_BUFFER +#define RK30_FB0_MEM_SIZE 12*SZ_1M +#else +#define RK30_FB0_MEM_SIZE 8*SZ_1M +#endif +#ifdef CONFIG_VIDEO_RK29 +/*---------------- Camera Sensor Macro Define Begin ------------------------*/ +/*---------------- Camera Sensor Configuration Macro Begin ------------------------*/ +#define CONFIG_SENSOR_0 RK29_CAM_SENSOR_OV5642 /* back camera sensor */ +#define CONFIG_SENSOR_IIC_ADDR_0 0 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_0 4 +#define CONFIG_SENSOR_CIF_INDEX_0 0 +#define CONFIG_SENSOR_ORIENTATION_0 90 +#define CONFIG_SENSOR_POWER_PIN_0 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_0 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_0 RK2928_PIN3_PB3 +#define CONFIG_SENSOR_FALSH_PIN_0 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_0 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_0 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_0 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_0 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_0 30000 + +#define CONFIG_SENSOR_01 RK29_CAM_SENSOR_OV5642 /* back camera sensor 1 */ +#define CONFIG_SENSOR_IIC_ADDR_01 0x00 +#define CONFIG_SENSOR_CIF_INDEX_01 0 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_01 4 +#define CONFIG_SENSOR_ORIENTATION_01 90 +#define CONFIG_SENSOR_POWER_PIN_01 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_01 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_01 RK2928_PIN3_PB3 +#define CONFIG_SENSOR_FALSH_PIN_01 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_01 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_01 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_01 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_01 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_01 30000 + +#define CONFIG_SENSOR_02 RK29_CAM_SENSOR_OV5640 /* back camera sensor 2 */ +#define CONFIG_SENSOR_IIC_ADDR_02 0x00 +#define CONFIG_SENSOR_CIF_INDEX_02 0 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_02 4 +#define CONFIG_SENSOR_ORIENTATION_02 90 +#define CONFIG_SENSOR_POWER_PIN_02 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_02 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_02 RK2928_PIN3_PB3 +#define CONFIG_SENSOR_FALSH_PIN_02 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_02 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_02 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_02 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_02 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_02 30000 + +#define CONFIG_SENSOR_1 RK29_CAM_SENSOR_OV2659 /* front camera sensor 0 */ +#define CONFIG_SENSOR_IIC_ADDR_1 0x60 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_1 3 +#define CONFIG_SENSOR_CIF_INDEX_1 0 +#define CONFIG_SENSOR_ORIENTATION_1 270 +#define CONFIG_SENSOR_POWER_PIN_1 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_1 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_1 RK2928_PIN3_PB3 +#define CONFIG_SENSOR_FALSH_PIN_1 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_1 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_1 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_1 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_1 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_1 30000 + +#define CONFIG_SENSOR_11 RK29_CAM_SENSOR_OV2659 /* front camera sensor 1 */ +#define CONFIG_SENSOR_IIC_ADDR_11 0x00 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_11 3 +#define CONFIG_SENSOR_CIF_INDEX_11 0 +#define CONFIG_SENSOR_ORIENTATION_11 270 +#define CONFIG_SENSOR_POWER_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_FALSH_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_11 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_11 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_11 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_11 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_11 30000 + +#define CONFIG_SENSOR_12 RK29_CAM_SENSOR_OV2659//RK29_CAM_SENSOR_OV2655 /* front camera sensor 2 */ +#define CONFIG_SENSOR_IIC_ADDR_12 0x00 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_12 3 +#define CONFIG_SENSOR_CIF_INDEX_12 0 +#define CONFIG_SENSOR_ORIENTATION_12 270 +#define CONFIG_SENSOR_POWER_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_FALSH_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_12 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_12 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_12 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_12 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_12 30000 + + +#endif //#ifdef CONFIG_VIDEO_RK29 +/*---------------- Camera Sensor Configuration Macro End------------------------*/ +#include "../../../drivers/media/video/rk2928_camera.c" +/*---------------- Camera Sensor Macro Define End ---------*/ + +#define PMEM_CAM_SIZE PMEM_CAM_NECESSARY +/***************************************************************************************** + * camera devices + * author: ddl@rock-chips.com + *****************************************************************************************/ +#ifdef CONFIG_VIDEO_RK29 +#define CONFIG_SENSOR_POWER_IOCTL_USR 0 //define this refer to your board layout +#define CONFIG_SENSOR_RESET_IOCTL_USR 0 +#define CONFIG_SENSOR_POWERDOWN_IOCTL_USR 0 +#define CONFIG_SENSOR_FLASH_IOCTL_USR 0 + +static void rk_cif_power(int on) +{ + struct regulator *ldo_18,*ldo_28; + ldo_28 = regulator_get(NULL, "ldo7"); // vcc28_cif + ldo_18 = regulator_get(NULL, "ldo1"); // vcc18_cif + if (ldo_28 == NULL || IS_ERR(ldo_28) || ldo_18 == NULL || IS_ERR(ldo_18)){ + printk("get cif ldo failed!\n"); + return; + } + if(on == 0){ + regulator_disable(ldo_28); + regulator_put(ldo_28); + regulator_disable(ldo_18); + regulator_put(ldo_18); + mdelay(500); + } + else{ + regulator_set_voltage(ldo_28, 2800000, 2800000); + regulator_enable(ldo_28); + // printk("%s set ldo7 vcc28_cif=%dmV end\n", __func__, regulator_get_voltage(ldo_28)); + regulator_put(ldo_28); + + regulator_set_voltage(ldo_18, 1800000, 1800000); + // regulator_set_suspend_voltage(ldo, 1800000); + regulator_enable(ldo_18); + // printk("%s set ldo1 vcc18_cif=%dmV end\n", __func__, regulator_get_voltage(ldo_18)); + regulator_put(ldo_18); + } +} + +#if CONFIG_SENSOR_POWER_IOCTL_USR +static int sensor_power_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + //#error "CONFIG_SENSOR_POWER_IOCTL_USR is 1, sensor_power_usr_cb function must be writed!!"; + rk_cif_power(on); +} +#endif + +#if CONFIG_SENSOR_RESET_IOCTL_USR +static int sensor_reset_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + #error "CONFIG_SENSOR_RESET_IOCTL_USR is 1, sensor_reset_usr_cb function must be writed!!"; +} +#endif + +#if CONFIG_SENSOR_POWERDOWN_IOCTL_USR +static int sensor_powerdown_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + #error "CONFIG_SENSOR_POWERDOWN_IOCTL_USR is 1, sensor_powerdown_usr_cb function must be writed!!"; +} +#endif + +#if CONFIG_SENSOR_FLASH_IOCTL_USR +static int sensor_flash_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + #error "CONFIG_SENSOR_FLASH_IOCTL_USR is 1, sensor_flash_usr_cb function must be writed!!"; +} +#endif + +static struct rk29camera_platform_ioctl_cb sensor_ioctl_cb = { + #if CONFIG_SENSOR_POWER_IOCTL_USR + .sensor_power_cb = sensor_power_usr_cb, + #else + .sensor_power_cb = NULL, + #endif + + #if CONFIG_SENSOR_RESET_IOCTL_USR + .sensor_reset_cb = sensor_reset_usr_cb, + #else + .sensor_reset_cb = NULL, + #endif + + #if CONFIG_SENSOR_POWERDOWN_IOCTL_USR + .sensor_powerdown_cb = sensor_powerdown_usr_cb, + #else + .sensor_powerdown_cb = NULL, + #endif + + #if CONFIG_SENSOR_FLASH_IOCTL_USR + .sensor_flash_cb = sensor_flash_usr_cb, + #else + .sensor_flash_cb = NULL, + #endif +}; + +#if CONFIG_SENSOR_IIC_ADDR_0 +static struct reginfo_t rk_init_data_sensor_reg_0[] = +{ + {0x0000, 0x00,0,0} + }; +static struct reginfo_t rk_init_data_sensor_winseqreg_0[] ={ + {0x0000, 0x00,0,0} + }; +#endif + +#if CONFIG_SENSOR_IIC_ADDR_1 +static struct reginfo_t rk_init_data_sensor_reg_1[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_1[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_01 +static struct reginfo_t rk_init_data_sensor_reg_01[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_01[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_02 +static struct reginfo_t rk_init_data_sensor_reg_02[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_02[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_11 +static struct reginfo_t rk_init_data_sensor_reg_11[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_11[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_12 +static struct reginfo_t rk_init_data_sensor_reg_12[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_12[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +static rk_sensor_user_init_data_s rk_init_data_sensor[RK_CAM_NUM] = +{ + #if CONFIG_SENSOR_IIC_ADDR_0 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_0, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_0, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_0) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_0) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_1 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_1, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_1, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_1) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_1) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_01 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_01, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_01, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_01) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_01) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_02 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_02, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_02, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_02) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_02) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_11 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_11, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_11, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_11) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_11) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_12 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_12, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_12, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_12) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_12) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + + }; +#include "../../../drivers/media/video/rk2928_camera.c" + +#endif /* CONFIG_VIDEO_RK29 */ + +#if defined (CONFIG_EETI_EGALAX) +#define TOUCH_RESET_PIN RK2928_PIN3_PC3 +#define TOUCH_INT_PIN RK2928_PIN3_PC7 + +static int EETI_EGALAX_init_platform_hw(void) +{ + if(gpio_request(TOUCH_RESET_PIN,NULL) != 0){ + gpio_free(TOUCH_RESET_PIN); + printk("p1003_init_platform_hw gpio_request error\n"); + return -EIO; + } + + if(gpio_request(TOUCH_INT_PIN,NULL) != 0){ + gpio_free(TOUCH_INT_PIN); + printk("p1003_init_platform_hw gpio_request error\n"); + return -EIO; + } + gpio_pull_updown(TOUCH_INT_PIN, 1); + gpio_direction_output(TOUCH_RESET_PIN, 0); + msleep(500); + gpio_set_value(TOUCH_RESET_PIN,GPIO_LOW); + msleep(500); + gpio_set_value(TOUCH_RESET_PIN,GPIO_HIGH); + + return 0; +} + + +static struct eeti_egalax_platform_data eeti_egalax_info = { + .model= 1003, + .init_platform_hw= EETI_EGALAX_init_platform_hw, + .standby_pin = INVALID_GPIO, + //.standby_value = GPIO_HIGH, + .disp_on_pin = INVALID_GPIO, + //.disp_on_value = GPIO_HIGH, +}; +#endif + +static struct spi_board_info board_spi_devices[] = { +}; + +/*********************************************************** +* rk30 backlight +************************************************************/ +#ifdef CONFIG_BACKLIGHT_RK29_BL +#define PWM_ID 0 +#define PWM_MUX_NAME GPIO0D2_PWM_0_NAME +#define PWM_MUX_MODE GPIO0D_PWM_0 +#define PWM_MUX_MODE_GPIO GPIO0D_GPIO0D2 +#define PWM_GPIO RK2928_PIN0_PD2 +#define PWM_EFFECT_VALUE 1 + +#define LCD_DISP_ON_PIN + +#ifdef LCD_DISP_ON_PIN + +#define BL_EN_PIN RK2928_PIN3_PC4 +#define BL_EN_VALUE GPIO_HIGH +#endif +static int rk29_backlight_io_init(void) +{ + int ret = 0; + rk30_mux_api_set(PWM_MUX_NAME, PWM_MUX_MODE); +#ifdef LCD_DISP_ON_PIN + // rk30_mux_api_set(BL_EN_MUX_NAME, BL_EN_MUX_MODE); + + ret = gpio_request(BL_EN_PIN, NULL); + if (ret != 0) { + gpio_free(BL_EN_PIN); + } + + gpio_direction_output(BL_EN_PIN, 0); + gpio_set_value(BL_EN_PIN, BL_EN_VALUE); +#endif + return ret; +} + +static int rk29_backlight_io_deinit(void) +{ + int ret = 0; +#ifdef LCD_DISP_ON_PIN + gpio_free(BL_EN_PIN); +#endif + rk30_mux_api_set(PWM_MUX_NAME, PWM_MUX_MODE_GPIO); + return ret; +} + +static int rk29_backlight_pwm_suspend(void) +{ + int ret = 0; + rk30_mux_api_set(PWM_MUX_NAME, PWM_MUX_MODE_GPIO); + if (gpio_request(PWM_GPIO, NULL)) { + printk("func %s, line %d: request gpio fail\n", __FUNCTION__, __LINE__); + return -1; + } + gpio_direction_output(PWM_GPIO, GPIO_LOW); +#ifdef LCD_DISP_ON_PIN + gpio_direction_output(BL_EN_PIN, 0); + gpio_set_value(BL_EN_PIN, !BL_EN_VALUE); +#endif + + return ret; +} + +static int rk29_backlight_pwm_resume(void) +{ + gpio_free(PWM_GPIO); + rk30_mux_api_set(PWM_MUX_NAME, PWM_MUX_MODE); +#ifdef LCD_DISP_ON_PIN + msleep(30); + gpio_direction_output(BL_EN_PIN, 1); + gpio_set_value(BL_EN_PIN, BL_EN_VALUE); +#endif + return 0; +} + +static struct rk29_bl_info rk29_bl_info = { + .pwm_id = PWM_ID, + .bl_ref = PWM_EFFECT_VALUE, + .io_init = rk29_backlight_io_init, + .io_deinit = rk29_backlight_io_deinit, + .pwm_suspend = rk29_backlight_pwm_suspend, + .pwm_resume = rk29_backlight_pwm_resume, +}; + +static struct platform_device rk29_device_backlight = { + .name = "rk29_backlight", + .id = -1, + .dev = { + .platform_data = &rk29_bl_info, + } +}; + +#endif + +/*MMA8452 gsensor*/ +#if defined (CONFIG_GS_MMA8452) + +static int mma8452_init_platform_hw(void) +{ + return 0; +} + +static struct sensor_platform_data mma8452_info = { + .type = SENSOR_TYPE_ACCEL, + .irq_enable = 1, + .poll_delay_ms = 30, + .init_platform_hw = mma8452_init_platform_hw, + .orientation = {-1, 0, 0, 0, 0, 1, 0, -1, 0}, +}; +#endif +#if defined (CONFIG_COMPASS_AK8975) +static struct sensor_platform_data akm8975_info = +{ + .type = SENSOR_TYPE_COMPASS, + .irq_enable = 1, + .poll_delay_ms = 30, + .m_layout = + { + { + {1, 0, 0}, + {0, 1, 0}, + {0, 0, 1}, + }, + + { + {1, 0, 0}, + {0, 1, 0}, + {0, 0, 1}, + }, + + { + {1, 0, 0}, + {0, 1, 0}, + {0, 0, 1}, + }, + + { + {1, 0, 0}, + {0, 1, 0}, + {0, 0, 1}, + }, + } +}; + +#endif + +#if defined(CONFIG_GYRO_L3G4200D) + +#include + +static int l3g4200d_init_platform_hw(void) +{ + return 0; +} + +static struct sensor_platform_data l3g4200d_info = { + .type = SENSOR_TYPE_GYROSCOPE, + .irq_enable = 1, + .poll_delay_ms = 30, + .orientation = {0, 1, 0, -1, 0, 0, 0, 0, 1}, + .init_platform_hw = l3g4200d_init_platform_hw, + .x_min = 40,//x_min,y_min,z_min = (0-100) according to hardware + .y_min = 40, + .z_min = 20, +}; + +#endif + +#ifdef CONFIG_LS_CM3217 +static struct sensor_platform_data cm3217_info = { + .type = SENSOR_TYPE_LIGHT, + .irq_enable = 0, + .poll_delay_ms = 500, +}; + +#endif + +#ifdef CONFIG_FB_ROCKCHIP + +#define LCD_CABC_MUX_NAME GPIO2D1_LCDC0_D23_LCDC1_D23_NAME +#define LCD_CABC_GPIO_MODE GPIO2D_GPIO2D1 + +#define LCD_CABC_EN RK2928_PIN2_PD1 +#define LCD_CABC_EN_VALUE GPIO_HIGH + +static int rk_fb_io_init(struct rk29_fb_setting_info *fb_setting) +{ + int ret = 0; + + rk30_mux_api_set(LCD_CABC_MUX_NAME, LCD_CABC_GPIO_MODE); + + ret = gpio_request(LCD_CABC_EN, NULL); + if (ret != 0) + { + gpio_free(LCD_CABC_EN); + printk(KERN_ERR "request lcd cabc en pin fail!\n"); + return -1; + } + else + { + gpio_direction_output(LCD_CABC_EN, !LCD_CABC_EN_VALUE); //disable + } + return 0; +} +static int rk_fb_io_disable(void) +{ + return 0; +} +static int rk_fb_io_enable(void) +{ + return 0; +} + +#if defined(CONFIG_LCDC_RK2928) +struct rk29fb_info lcdc_screen_info = { + .prop = PRMRY, //primary display device + .io_init = rk_fb_io_init, + .io_disable = rk_fb_io_disable, + .io_enable = rk_fb_io_enable, + .set_screen_info = set_lcd_info, +}; +#endif + +static struct resource resource_fb[] = { + [0] = { + .name = "fb0 buf", + .start = 0, + .end = 0,//RK30_FB0_MEM_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "ipp buf", //for rotate + .start = 0, + .end = 0,//RK30_FB0_MEM_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [2] = { + .name = "fb2 buf", + .start = 0, + .end = 0,//RK30_FB0_MEM_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device device_fb = { + .name = "rk-fb", + .id = -1, + .num_resources = ARRAY_SIZE(resource_fb), + .resource = resource_fb, +}; +#endif + +#ifdef CONFIG_ION +#define ION_RESERVE_SIZE (80 * SZ_1M) +static struct ion_platform_data rk30_ion_pdata = { + .nr = 1, + .heaps = { + { + .type = ION_HEAP_TYPE_CARVEOUT, + .id = ION_NOR_HEAP_ID, + .name = "norheap", + .size = ION_RESERVE_SIZE, + } + }, +}; + +static struct platform_device device_ion = { + .name = "ion-rockchip", + .id = 0, + .dev = { + .platform_data = &rk30_ion_pdata, + }, +}; +#endif +/************************************************************************************************** + * SDMMC devices, include the module of SD,MMC,and sdio.noted by xbw at 2012-03-05 +**************************************************************************************************/ +#ifdef CONFIG_SDMMC_RK29 +#include "board-rk2928-sdk-sdmmc.c" + +#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) +#define SDMMC0_WRITE_PROTECT_PIN RK2928_PIN1_PA7 //According to your own project to set the value of write-protect-pin. +#endif + +#if defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT) +#define SDMMC1_WRITE_PROTECT_PIN RK2928_PIN0_PD5 //According to your own project to set the value of write-protect-pin. +#endif + +#define RK29SDK_WIFI_SDIO_CARD_DETECT_N RK2928_PIN0_PB2 + +#endif //endif ---#ifdef CONFIG_SDMMC_RK29 + +#ifdef CONFIG_SDMMC0_RK29 +static int rk29_sdmmc0_cfg_gpio(void) +{ + rk29_sdmmc_set_iomux(0, 0xFFFF); + + rk30_mux_api_set(GPIO1C1_MMC0_DETN_NAME, GPIO1C_MMC0_DETN); + +#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) + gpio_request(SDMMC0_WRITE_PROTECT_PIN, "sdmmc-wp"); + gpio_direction_input(SDMMC0_WRITE_PROTECT_PIN); +#endif + + return 0; +} + +#define CONFIG_SDMMC0_USE_DMA +struct rk29_sdmmc_platform_data default_sdmmc0_data = { + .host_ocr_avail = + (MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 | MMC_VDD_28_29 | + MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | + MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36), + .host_caps = + (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), + .io_init = rk29_sdmmc0_cfg_gpio, + +#if !defined(CONFIG_SDMMC_RK29_OLD) + .set_iomux = rk29_sdmmc_set_iomux, +#endif + + .dma_name = "sd_mmc", +#ifdef CONFIG_SDMMC0_USE_DMA + .use_dma = 1, +#else + .use_dma = 0, +#endif + .detect_irq = RK2928_PIN1_PC1, // INVALID_GPIO + .enable_sd_wakeup = 0, + +#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) + .write_prt = SDMMC0_WRITE_PROTECT_PIN, +#else + .write_prt = INVALID_GPIO, +#endif +}; +#endif // CONFIG_SDMMC0_RK29 + +#ifdef CONFIG_SDMMC1_RK29 +#define CONFIG_SDMMC1_USE_DMA +static int rk29_sdmmc1_cfg_gpio(void) +{ +#if defined(CONFIG_SDMMC_RK29_OLD) + rk30_mux_api_set(GPIO0B0_MMC1_CMD_NAME, GPIO0B_MMC1_CMD); + rk30_mux_api_set(GPIO0B1_MMC1_CLKOUT_NAME, GPIO0B_MMC1_CLKOUT); + rk30_mux_api_set(GPIO0B3_MMC1_D0_NAME, GPIO0B_MMC1_D0); + rk30_mux_api_set(GPIO0B4_MMC1_D1_NAME, GPIO0B_MMC1_D1); + rk30_mux_api_set(GPIO0B5_MMC1_D2_NAME, GPIO0B_MMC1_D2); + rk30_mux_api_set(GPIO0B6_MMC1_D3_NAME, GPIO0B_MMC1_D3); + //rk30_mux_api_set(GPIO0B2_MMC1_DETN_NAME, GPIO0B_MMC1_DETN); + +#else + +#if defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT) + gpio_request(SDMMC1_WRITE_PROTECT_PIN, "sdio-wp"); + gpio_direction_input(SDMMC1_WRITE_PROTECT_PIN); +#endif + +#endif + + return 0; +} + +struct rk29_sdmmc_platform_data default_sdmmc1_data = { + .host_ocr_avail = + (MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 | MMC_VDD_28_29 | + MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | + MMC_VDD_33_34), + +#if !defined(CONFIG_USE_SDMMC1_FOR_WIFI_DEVELOP_BOARD) + .host_caps = (MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ | + MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), +#else + .host_caps = + (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), +#endif + + .io_init = rk29_sdmmc1_cfg_gpio, + +#if !defined(CONFIG_SDMMC_RK29_OLD) + .set_iomux = rk29_sdmmc_set_iomux, +#endif + + .dma_name = "sdio", +#ifdef CONFIG_SDMMC1_USE_DMA + .use_dma = 1, +#else + .use_dma = 0, +#endif + +#if !defined(CONFIG_USE_SDMMC1_FOR_WIFI_DEVELOP_BOARD) +#ifdef CONFIG_WIFI_CONTROL_FUNC + .status = rk29sdk_wifi_status, + .register_status_notify = rk29sdk_wifi_status_register, +#endif +#if 0 + .detect_irq = RK29SDK_WIFI_SDIO_CARD_DETECT_N, +#endif + +#if defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT) + .write_prt = SDMMC1_WRITE_PROTECT_PIN, +#else + .write_prt = INVALID_GPIO, +#endif + +#else + .detect_irq = INVALID_GPIO, + .enable_sd_wakeup = 0, +#endif + +}; +#endif //endif--#ifdef CONFIG_SDMMC1_RK29 + +/************************************************************************************************** + * the end of setting for SDMMC devices +**************************************************************************************************/ + + + +#ifdef CONFIG_RFKILL_RK +// bluetooth rfkill device, its driver in net/rfkill/rfkill-rk.c +static struct rfkill_rk_platform_data rfkill_rk_platdata = { + .type = RFKILL_TYPE_BLUETOOTH, + + .poweron_gpio = { // BT_REG_ON + .io = INVALID_GPIO, + .enable = GPIO_HIGH, + .iomux = { + .name = NULL, + }, + }, + + .reset_gpio = { // BT_RST + .io = RK2928_PIN3_PD5, // set io to INVALID_GPIO for disable it + .enable = GPIO_LOW, + .iomux = { + .name = NULL, + }, + }, + + .wake_gpio = { // BT_WAKE, use to control bt's sleep and wakeup + .io = RK2928_PIN0_PC6, // set io to INVALID_GPIO for disable it + .enable = GPIO_HIGH, + .iomux = { + .name = NULL, + }, + }, + + .wake_host_irq = { // BT_HOST_WAKE, for bt wakeup host when it is in deep sleep + .gpio = { + .io = RK2928_PIN0_PC5, // set io to INVALID_GPIO for disable it + .enable = GPIO_LOW, // set GPIO_LOW for falling, set 0 for rising + .iomux = { + .name = NULL, + }, + }, + }, + + .rts_gpio = { // UART_RTS, enable or disable BT's data coming + .io = RK2928_PIN0_PC3, // set io to INVALID_GPIO for disable it + .enable = GPIO_LOW, + .iomux = { + .name = GPIO0C3_UART0_CTSN_NAME, + .fgpio = GPIO0C_GPIO0C3, + .fmux = GPIO0C_UART0_CTSN, + }, + }, +}; + +static struct platform_device device_rfkill_rk = { + .name = "rfkill_rk", + .id = -1, + .dev = { + .platform_data = &rfkill_rk_platdata, + }, +}; +#endif + +static struct platform_device *devices[] __initdata = { +#ifdef CONFIG_BACKLIGHT_RK29_BL + &rk29_device_backlight, +#endif +#ifdef CONFIG_FB_ROCKCHIP + &device_fb, +#endif +#ifdef CONFIG_ION + &device_ion, +#endif +#ifdef CONFIG_WIFI_CONTROL_FUNC + &rk29sdk_wifi_device, +#endif +#ifdef CONFIG_RFKILL_RK + &device_rfkill_rk, +#endif +}; +//i2c +#ifdef CONFIG_I2C0_RK30 +static struct i2c_board_info __initdata i2c0_info[] = { +#if defined (CONFIG_GS_MMA8452) + { + .type = "gs_mma8452", + .addr = 0x1d, + .flags = 0, + .irq = RK2928_PIN3_PD1, + .platform_data = &mma8452_info, + }, +#endif +#if defined (CONFIG_COMPASS_AK8975) + { + .type = "ak8975", + .addr = 0x0d, + .flags = 0, + .irq = RK2928_PIN3_PD2, + .platform_data = &akm8975_info, + }, +#endif +#if defined (CONFIG_GYRO_L3G4200D) + { + .type = "l3g4200d_gryo", + .addr = 0x69, + .flags = 0, + .irq = RK2928_PIN3_PD3, + .platform_data = &l3g4200d_info, + }, +#endif +}; +#endif +#ifdef CONFIG_I2C1_RK30 +static struct i2c_board_info __initdata i2c1_info[] = { +}; +#endif +#ifdef CONFIG_I2C2_RK30 +static struct i2c_board_info __initdata i2c2_info[] = { +#if defined (CONFIG_EETI_EGALAX) + { + .type = "egalax_i2c", + .addr = 0x04, + .flags = 0, + .irq = RK2928_PIN3_PC7, + .platform_data = &eeti_egalax_info, + }, +#endif +#if defined (CONFIG_LS_CM3217) + { + .type = "lightsensor", + .addr = 0x10, + .flags = 0, + .platform_data = &cm3217_info, + }, +#endif +}; +#endif +#ifdef CONFIG_I2C3_RK30 +static struct i2c_board_info __initdata i2c3_info[] = { +}; +#endif +#ifdef CONFIG_I2C_GPIO_RK30 +#define I2C_SDA_PIN INVALID_GPIO //set sda_pin here +#define I2C_SCL_PIN INVALID_GPIO //set scl_pin here +static int rk30_i2c_io_init(void) +{ + //set iomux (gpio) here + + return 0; +} +struct i2c_gpio_platform_data default_i2c_gpio_data = { + .sda_pin = I2C_SDA_PIN, + .scl_pin = I2C_SCL_PIN, + .udelay = 5, // clk = 500/udelay = 100Khz + .timeout = 100,//msecs_to_jiffies(100), + .bus_num = 5, + .io_init = rk30_i2c_io_init, +}; +static struct i2c_board_info __initdata i2c_gpio_info[] = { +}; +#endif +static void __init rk30_i2c_register_board_info(void) +{ +#ifdef CONFIG_I2C0_RK30 + i2c_register_board_info(0, i2c0_info, ARRAY_SIZE(i2c0_info)); +#endif +#ifdef CONFIG_I2C1_RK30 + i2c_register_board_info(1, i2c1_info, ARRAY_SIZE(i2c1_info)); +#endif +#ifdef CONFIG_I2C2_RK30 + i2c_register_board_info(2, i2c2_info, ARRAY_SIZE(i2c2_info)); +#endif +#ifdef CONFIG_I2C3_RK30 + i2c_register_board_info(3, i2c3_info, ARRAY_SIZE(i2c3_info)); +#endif +#ifdef CONFIG_I2C_GPIO_RK30 + i2c_register_board_info(4, i2c_gpio_info, ARRAY_SIZE(i2c_gpio_info)); +#endif +} +//end of i2c + +#define POWER_ON_PIN RK2928_PIN3_PC5 //power_hold +static void rk30_pm_power_off(void) +{ + printk(KERN_ERR "rk30_pm_power_off start...\n"); + gpio_direction_output(POWER_ON_PIN, GPIO_LOW); +}; + +static void __init rk2928_board_init(void) +{ + gpio_request(POWER_ON_PIN, "poweronpin"); + gpio_direction_output(POWER_ON_PIN, GPIO_HIGH); + + pm_power_off = rk30_pm_power_off; + + rk30_i2c_register_board_info(); + spi_register_board_info(board_spi_devices, ARRAY_SIZE(board_spi_devices)); + platform_add_devices(devices, ARRAY_SIZE(devices)); + //RK2928 USB DETECT IRQ: IRQ_OTG_BVALID + //board_usb_detect_init(RK30_PIN6_PA3); + +#ifdef CONFIG_WIFI_CONTROL_FUNC + rk29sdk_wifi_bt_gpio_control_init(); +#endif +} + +static void __init rk2928_reserve(void) +{ +#ifdef CONFIG_ION + rk30_ion_pdata.heaps[0].base = board_mem_reserve_add("ion", ION_RESERVE_SIZE); +#endif +#ifdef CONFIG_FB_ROCKCHIP + resource_fb[0].start = board_mem_reserve_add("fb0", RK30_FB0_MEM_SIZE); + resource_fb[0].end = resource_fb[0].start + RK30_FB0_MEM_SIZE - 1; +#if 0 + resource_fb[1].start = board_mem_reserve_add("ipp buf", RK30_FB0_MEM_SIZE); + resource_fb[1].end = resource_fb[1].start + RK30_FB0_MEM_SIZE - 1; + resource_fb[2].start = board_mem_reserve_add("fb2", RK30_FB0_MEM_SIZE); + resource_fb[2].end = resource_fb[2].start + RK30_FB0_MEM_SIZE - 1; +#endif +#endif +#ifdef CONFIG_VIDEO_RK29 + rk30_camera_request_reserve_mem(); +#endif + board_mem_reserved(); +} + +#if 1 +#include + +struct clk { + const char *name; + unsigned long rate; +}; + +static struct clk xin24m = { + .name = "xin24m", + .rate = 24000000, +}; + +#define CLK(dev, con, ck) \ + { \ + .dev_id = dev, \ + .con_id = con, \ + .clk = ck, \ + } + +static struct clk_lookup clks[] = { + CLK("rk30_i2c.0", "i2c", &xin24m), + CLK("rk30_i2c.1", "i2c", &xin24m), + CLK("rk30_i2c.2", "i2c", &xin24m), + CLK("rk30_i2c.3", "i2c", &xin24m), + CLK("rk29xx_spim.0", "spi", &xin24m), + CLK("rk29xx_spim.1", "spi", &xin24m), + + CLK("rk_serial.0", "uart_div", &xin24m), + CLK("rk_serial.0", "uart_frac_div", &xin24m), + CLK("rk_serial.0", "uart", &xin24m), + CLK("rk_serial.0", "pclk_uart", &xin24m), + CLK("rk_serial.1", "uart_div", &xin24m), + CLK("rk_serial.1", "uart_frac_div", &xin24m), + CLK("rk_serial.1", "uart", &xin24m), + CLK("rk_serial.1", "pclk_uart", &xin24m), + CLK("rk_serial.2", "uart_div", &xin24m), + CLK("rk_serial.2", "uart_frac_div", &xin24m), + CLK("rk_serial.2", "uart", &xin24m), + CLK("rk_serial.2", "pclk_uart", &xin24m), + + CLK("rk29_i2s.0", "i2s_div", &xin24m), + CLK("rk29_i2s.0", "i2s_frac_div", &xin24m), + CLK("rk29_i2s.0", "i2s", &xin24m), + CLK("rk29_i2s.0", "hclk_i2s", &xin24m), + CLK(NULL, "pd_lcdc0", &xin24m), + CLK(NULL, "hclk_lcdc0", &xin24m), + CLK(NULL, "aclk_lcdc0", &xin24m), + CLK(NULL, "dclk_lcdc0", &xin24m), + + CLK(NULL, "pd_cif0", &xin24m), + CLK(NULL, "aclk_cif0", &xin24m), + CLK(NULL, "hclk_cif0", &xin24m), + CLK(NULL, "cif0_in", &xin24m), + CLK(NULL, "cif0_out", &xin24m), +}; + +void __init rk30_clock_init(void) +{ + struct clk_lookup *lk; + + for (lk = clks; lk < clks + ARRAY_SIZE(clks); lk++) { + clkdev_add(lk); + } +} + +void __init board_clock_init(void) +{ + rk30_clock_init(); +} +#else +void __init board_clock_init(void) +{ +} +#endif + + +MACHINE_START(RK2928, "RK2928board") + .boot_params = PLAT_PHYS_OFFSET + 0x800, + .fixup = rk2928_fixup, + .reserve = &rk2928_reserve, + .map_io = rk2928_map_io, + .init_irq = rk2928_init_irq, + .timer = &rk2928_timer, + .init_machine = rk2928_board_init, +MACHINE_END diff --git a/arch/arm/mach-rk2928/common.c b/arch/arm/mach-rk2928/common.c index f7f96d0eec29..36b625dac57f 100644 --- a/arch/arm/mach-rk2928/common.c +++ b/arch/arm/mach-rk2928/common.c @@ -143,6 +143,8 @@ static __init u32 rk2928_get_ddr_size(void) { #ifdef CONFIG_MACH_RK2928_FPGA return SZ_64M; +#else + return SZ_512M; #endif } diff --git a/arch/arm/mach-rk2928/devices.c b/arch/arm/mach-rk2928/devices.c index eca32631660f..04038a26456b 100755 --- a/arch/arm/mach-rk2928/devices.c +++ b/arch/arm/mach-rk2928/devices.c @@ -770,6 +770,9 @@ static int __init rk2928_init_devices(void) rk2928_init_i2s(); #ifdef CONFIG_SND_SOC_RK2928 platform_device_register(&device_acodec); +#endif +#ifdef CONFIG_HDMI_RK2928 + platform_device_register(&device_hdmi); #endif return 0; } diff --git a/arch/arm/mach-rk2928/include/mach/board.h b/arch/arm/mach-rk2928/include/mach/board.h index fad769ca8b30..1e1059a7d3ba 100644 --- a/arch/arm/mach-rk2928/include/mach/board.h +++ b/arch/arm/mach-rk2928/include/mach/board.h @@ -32,4 +32,30 @@ void __sramfunc board_pmu_resume(void); extern struct sys_timer rk2928_timer; +#ifndef _LINUX_WLAN_PLAT_H_ +struct wifi_platform_data { + int (*set_power)(int val); + int (*set_reset)(int val); + int (*set_carddetect)(int val); + void *(*mem_prealloc)(int section, unsigned long size); + int (*get_mac_addr)(unsigned char *buf); +}; +#endif +#if defined (CONFIG_EETI_EGALAX) +struct eeti_egalax_platform_data{ + u16 model; + + int (*get_pendown_state)(void); + int (*init_platform_hw)(void); + int (*eeti_egalax_platform_sleep)(void); + int (*eeti_egalax_platform_wakeup)(void); + void (*exit_platform_hw)(void); + int standby_pin; + int standby_value; + int disp_on_pin; + int disp_on_value; + +}; +#endif + #endif diff --git a/drivers/input/touchscreen/eeti_egalax_i2c.c b/drivers/input/touchscreen/eeti_egalax_i2c.c index 8177406c9373..1714f18157ed 100755 --- a/drivers/input/touchscreen/eeti_egalax_i2c.c +++ b/drivers/input/touchscreen/eeti_egalax_i2c.c @@ -72,7 +72,7 @@ static int global_minor = 0; #define EGALAX_IOCWAKEUP _IO(EGALAX_IOC_MAGIC, 1) #define EGALAX_IOC_MAXNR 1 -#define EETI_EARLYSUSPEND_LEVEL 151 +#define EETI_EARLYSUSPEND_LEVEL (EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1) struct point_data { short Status; @@ -544,7 +544,7 @@ void egalax_i2c_set_standby(struct i2c_client *client, int enable) int display_on_pol = mach_info->disp_on_value; int lcd_standby_pol = mach_info->standby_value; - +#ifndef CONFIG_ARCH_RK2928 printk("%s : %s, enable = %d", __FILE__, __FUNCTION__,enable); if(display_on != INVALID_GPIO) { @@ -556,6 +556,7 @@ void egalax_i2c_set_standby(struct i2c_client *client, int enable) gpio_direction_output(lcd_standby, 0); gpio_set_value(lcd_standby, enable ? lcd_standby_pol : !lcd_standby_pol); } +#endif } #ifdef CONFIG_PM diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 4e7324b87588..2050685c42d3 100755 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -299,7 +299,7 @@ config BACKLIGHT_RK2818_BL config BACKLIGHT_RK29_BL bool "rk backlight driver" - depends on BACKLIGHT_CLASS_DEVICE && (ARCH_RK29 || ARCH_RK30 || ARCH_RK31) + depends on BACKLIGHT_CLASS_DEVICE && (ARCH_RK29 || ARCH_RK30 || ARCH_RK31 || ARCH_RK2928) default y help rk29 backlight support. diff --git a/drivers/video/backlight/rk29_backlight.c b/drivers/video/backlight/rk29_backlight.c index f8c251de5e8b..1221d6740927 100755 --- a/drivers/video/backlight/rk29_backlight.c +++ b/drivers/video/backlight/rk29_backlight.c @@ -41,6 +41,11 @@ #if defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) #define write_pwm_reg(id, addr, val) __raw_writel(val, addr+(RK30_PWM01_BASE+(id>>1)*0x20000)+id*0x10) #define read_pwm_reg(id, addr) __raw_readl(addr+(RK30_PWM01_BASE+(id>>1)*0x20000+id*0x10)) + +#elif defined(CONFIG_ARCH_RK2928) +#define write_pwm_reg(id, addr, val) __raw_writel(val, addr+(RK2928_PWM_BASE+id*0x10)) +#define read_pwm_reg(id, addr) __raw_readl(addr+(RK2928_PWM_BASE+id*0x10)) + #elif defined(CONFIG_ARCH_RK29) #define write_pwm_reg(id, addr, val) __raw_writel(val, addr+(RK29_PWM_BASE+id*0x10)) #define read_pwm_reg(id, addr) __raw_readl(addr+(RK29_PWM_BASE+id*0x10)) @@ -201,7 +206,7 @@ static int rk29_backlight_probe(struct platform_device *pdev) #if defined(CONFIG_ARCH_RK29) pwm_clk = clk_get(NULL, "pwm"); -#elif defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) +#elif defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) || defined(CONFIG_ARCH_RK2928) if (id == 0 || id == 1) pwm_clk = clk_get(NULL, "pwm01"); else if (id == 2 || id == 3) diff --git a/sound/soc/rk29/rk30_i2s.c b/sound/soc/rk29/rk30_i2s.c index 150c44770c75..e4a73bf88df6 100755 --- a/sound/soc/rk29/rk30_i2s.c +++ b/sound/soc/rk29/rk30_i2s.c @@ -515,12 +515,14 @@ static int rockchip_i2s_dai_probe(struct snd_soc_dai *dai) #endif #ifdef CONFIG_ARCH_RK2928 case 0: + #if 0 //iomux --> gps(.ko) rk30_mux_api_set(GPIO1A0_I2S_MCLK_NAME, GPIO1A_I2S_MCLK); rk30_mux_api_set(GPIO1A1_I2S_SCLK_NAME, GPIO1A_I2S_SCLK); - rk30_mux_api_set(GPIO1A2_I2S_LRCKRX_NAME, GPIO1A_I2S_LRCKRX); + rk30_mux_api_set(GPIO1A2_I2S_LRCKRX_GPS_CLK_NAME, GPIO1A_I2S_LRCKRX); rk30_mux_api_set(GPIO1A3_I2S_LRCKTX_NAME, GPIO1A_I2S_LRCKTX); - rk30_mux_api_set(GPIO1A4_I2S_SDO_NAME, GPIO1A_I2S_SDO); - rk30_mux_api_set(GPIO1A5_I2S_SDI_NAME, GPIO1A_I2S_SDI); + rk30_mux_api_set(GPIO1A4_I2S_SDO_GPS_MAG_NAME, GPIO1A_I2S_SDO); + rk30_mux_api_set(GPIO1A5_I2S_SDI_GPS_SIGN_NAME, GPIO1A_I2S_SDI); + #endif break; #endif default: From 5002650a99cc788985125e22d4d78b0179f298f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E8=BE=89?= Date: Thu, 2 Aug 2012 11:06:13 +0800 Subject: [PATCH 076/261] to run 360M ddr freq by default --- arch/arm/mach-rk30/include/mach/ddr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-rk30/include/mach/ddr.h b/arch/arm/mach-rk30/include/mach/ddr.h index d3fa29bc6ab5..b4c8aef5873b 100755 --- a/arch/arm/mach-rk30/include/mach/ddr.h +++ b/arch/arm/mach-rk30/include/mach/ddr.h @@ -22,7 +22,7 @@ #ifdef CONFIG_DDR_SDRAM_FREQ #define DDR_FREQ (CONFIG_DDR_SDRAM_FREQ) #else -#define DDR_FREQ 400 +#define DDR_FREQ 360 #endif #define DDR3_800D (0) // 5-5-5 From 394711f6ffd2241024f95be0bad4f601e31db40e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E8=BE=89?= Date: Thu, 2 Aug 2012 11:14:02 +0800 Subject: [PATCH 077/261] to enable temperature monitor function, and arm run on 1.4G freq in booting --- arch/arm/mach-rk30/cpufreq.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-rk30/cpufreq.c b/arch/arm/mach-rk30/cpufreq.c index d7d05d2c82fe..31b0f0f829c8 100755 --- a/arch/arm/mach-rk30/cpufreq.c +++ b/arch/arm/mach-rk30/cpufreq.c @@ -262,7 +262,7 @@ static int rk30_cpu_init(struct cpufreq_policy *policy) freq_wq = create_singlethread_workqueue("rk30_cpufreqd"); #ifdef CONFIG_RK30_CPU_FREQ_LIMIT_BY_TEMP if (rk30_cpufreq_is_ondemand_policy(policy)) { - queue_delayed_work(freq_wq, &rk30_cpufreq_temp_limit_work, 60*HZ); + queue_delayed_work(freq_wq, &rk30_cpufreq_temp_limit_work, 0*HZ); } cpufreq_register_notifier(¬ifier_policy_block, CPUFREQ_POLICY_NOTIFIER); #endif @@ -509,9 +509,18 @@ static void __exit ff_exit(void) static unsigned int cpufreq_scale_limt(unsigned int target_freq, struct cpufreq_policy *policy) { bool is_ondemand = rk30_cpufreq_is_ondemand_policy(policy); + static bool is_booting = true; if (is_ondemand && clk_get_rate(gpu_clk) > GPU_MAX_RATE) // high performance? return max_freq; + if (is_ondemand && is_booting && target_freq >= 1600 * 1000) { + s64 boottime_ms = ktime_to_ms(ktime_get_boottime()); + if (boottime_ms > 30 * MSEC_PER_SEC) { + is_booting = false; + } else { + target_freq = 1416 * 1000; + } + } #ifdef CONFIG_RK30_CPU_FREQ_LIMIT_BY_TEMP if (is_ondemand && target_freq > policy->cur && policy->cur >= TEMP_LIMIT_FREQ) { unsigned int i; From 6519f4a136452cb7b97ee94906293ea73e1fdf04 Mon Sep 17 00:00:00 2001 From: yangkai Date: Thu, 2 Aug 2012 11:24:17 +0800 Subject: [PATCH 078/261] update for rk29 config switch --- drivers/usb/dwc_otg/dwc_otg_cil.c | 4 ++-- drivers/usb/dwc_otg/dwc_otg_pcd.c | 6 +++++- drivers/usb/gadget/epautoconf.c | 7 ++++++- drivers/usb/gadget/f_adb.c | 2 +- 4 files changed, 14 insertions(+), 5 deletions(-) mode change 100644 => 100755 drivers/usb/gadget/epautoconf.c diff --git a/drivers/usb/dwc_otg/dwc_otg_cil.c b/drivers/usb/dwc_otg/dwc_otg_cil.c index ec4f27fb9981..9f44adc2796f 100755 --- a/drivers/usb/dwc_otg/dwc_otg_cil.c +++ b/drivers/usb/dwc_otg/dwc_otg_cil.c @@ -729,8 +729,8 @@ void dwc_otg_core_dev_init(dwc_otg_core_if_t *_core_if) dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[0], 0x01000130 ); //ep1 tx fifo dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[1], 0x00800230 ); //ep3 tx fifo dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[2], 0x008002b0 ); //ep5 tx fifo - dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[2], 0x00800330 ); //ep7 tx fifo - dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[2], 0x001003b0 ); //ep9 tx fifo + dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[3], 0x00800330 ); //ep7 tx fifo + dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[4], 0x001003b0 ); //ep9 tx fifo #endif if(_core_if->en_multiple_tx_fifo && _core_if->dma_enable) { diff --git a/drivers/usb/dwc_otg/dwc_otg_pcd.c b/drivers/usb/dwc_otg/dwc_otg_pcd.c index b6e4d28c4d66..6f6d975e09c6 100755 --- a/drivers/usb/dwc_otg/dwc_otg_pcd.c +++ b/drivers/usb/dwc_otg/dwc_otg_pcd.c @@ -304,7 +304,7 @@ static int dwc_otg_pcd_ep_enable(struct usb_ep *_ep, if(ep->dwc_ep.is_in) { -#ifdef CONFIG_ARCH_RK30 +#ifndef CONFIG_ARCH_RK29 if(!pcd->otg_dev->core_if->en_multiple_tx_fifo) { ep->dwc_ep.tx_fifo_num = 0; @@ -1353,7 +1353,11 @@ void dwc_otg_pcd_reinit(dwc_otg_pcd_t *_pcd) "ep2in", "ep3in", "ep4in", +#ifdef CONFIG_ARCH_RK29 + "ep5in-int", +#else "ep5in", +#endif "ep6in", "ep7in", "ep8in", diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c old mode 100644 new mode 100755 index 9b7360ff5aa7..23e3077a9196 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -94,7 +94,7 @@ ep_matches ( /* bulk endpoints handle interrupt transfers, * except the toggle-quirky iso-synch kind */ - if ('s' == tmp[2]) // == "-iso" + if ('n' != tmp[2]) // == "-int" return 0; /* for now, avoid PXA "interrupt-in"; * it's documented as never using DATA1. @@ -112,6 +112,10 @@ ep_matches ( return 0; } } else { +#ifdef CONFIG_ARCH_RK29 + if (USB_ENDPOINT_XFER_INT == type) + return 0; +#endif tmp = ep->name + strlen (ep->name); } @@ -145,6 +149,7 @@ ep_matches ( /* INT: limit 64 bytes full speed, 1024 high speed */ if (!gadget->is_dualspeed && max > 64) return 0; + break; /* FALLTHROUGH */ case USB_ENDPOINT_XFER_ISOC: diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c index 83e1f59385a2..076da888fae8 100755 --- a/drivers/usb/gadget/f_adb.c +++ b/drivers/usb/gadget/f_adb.c @@ -72,7 +72,7 @@ static struct usb_endpoint_descriptor adb_highspeed_in_desc = { .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(64), + .wMaxPacketSize = __constant_cpu_to_le16(512), }; static struct usb_endpoint_descriptor adb_highspeed_out_desc = { From f10c99c972609f38c70a738011a17039ea8c80f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Thu, 2 Aug 2012 11:49:42 +0800 Subject: [PATCH 079/261] rk: fat: quiet report invalid access to FAT --- fs/fat/fatent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c index 38cfeb1908a3..ee953113a53c 100644 --- a/fs/fat/fatent.c +++ b/fs/fat/fatent.c @@ -348,7 +348,7 @@ int fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry) if (entry < FAT_START_ENT || sbi->max_cluster <= entry) { fatent_brelse(fatent); - fat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", entry); + fat_fs_error_ratelimit(sb, "invalid access to FAT (entry 0x%08x)", entry); return -EIO; } From 8fa1cf2ff7d5faa3c5eaab7544604837a472fda1 Mon Sep 17 00:00:00 2001 From: "lw@rock-chips.com" Date: Thu, 2 Aug 2012 17:27:45 +0800 Subject: [PATCH 080/261] phonepad:modify rk30 pwm regulator suspend --- drivers/regulator/rk30-pwm-regulator.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/regulator/rk30-pwm-regulator.c b/drivers/regulator/rk30-pwm-regulator.c index 46bf1b75982e..7af504689ac5 100755 --- a/drivers/regulator/rk30-pwm-regulator.c +++ b/drivers/regulator/rk30-pwm-regulator.c @@ -101,9 +101,9 @@ static int pwm_set_rate(struct pwm_platform_data *pdata,int nHz,u32 rate) //disable pull up or down gpio_pull_updown(pdata->pwm_gpio,PullDisable); // set gpio to low level - gpio_set_value(pdata->pwm_gpio,GPIO_LOW); + gpio_direction_output(pdata->pwm_gpio,GPIO_LOW); } - else if (rate <= 100) + else if (rate < 100) { // iomux pwm rk29_mux_api_set(pdata->pwm_iomux_name, pdata->pwm_iomux_pwm); @@ -119,6 +119,16 @@ static int pwm_set_rate(struct pwm_platform_data *pdata,int nHz,u32 rate) pwm_write_reg(id,PWM_REG_CNTR,0); pwm_write_reg(id, PWM_REG_CTRL,pwm_read_reg(id,PWM_REG_CTRL)|PWM_DIV|PWM_ENABLE|PWM_TimeEN); } + else if (rate == 100) + { + // iomux pwm to gpio + rk29_mux_api_set(pdata->pwm_iomux_name, pdata->pwm_iomux_gpio); + //disable pull up or down + gpio_pull_updown(pdata->pwm_gpio,PullDisable); + // set gpio to low level + gpio_direction_output(pdata->pwm_gpio,GPIO_HIGH); + + } else { printk("%s:rate error\n",__func__); @@ -324,7 +334,7 @@ static int __devinit pwm_regulator_probe(struct platform_device *pdev) static int pwm_regulator_suspend(struct platform_device *pdev, pm_message_t state) { struct pwm_platform_data *pdata = pdev->dev.platform_data; - pwm_set_rate(pdata,1000*1000,0);//pwm clk will change to 24M after suspend + pwm_set_rate(pdata,1000*1000,100);//pwm clk will change to 24M after suspend DBG("%s,pwm_id=%d\n",__func__,pdata->pwm_id); return 0; } From ef2287b3595091cc1cff5d17e3f8cc74c4c4db14 Mon Sep 17 00:00:00 2001 From: ddl Date: Thu, 2 Aug 2012 17:28:57 +0800 Subject: [PATCH 081/261] camera : gc0329/sp0838/s5k5ca commit again --- arch/arm/plat-rk/include/plat/rk_camera.h | 10 ++++++++++ drivers/media/video/gc0329.c | 2 +- drivers/media/video/s5k5ca.c | 2 +- drivers/media/video/sp0838.c | 2 +- include/media/v4l2-chip-ident.h | 6 +++++- 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/arch/arm/plat-rk/include/plat/rk_camera.h b/arch/arm/plat-rk/include/plat/rk_camera.h index 39f31b11facb..2a1dca105a2f 100755 --- a/arch/arm/plat-rk/include/plat/rk_camera.h +++ b/arch/arm/plat-rk/include/plat/rk_camera.h @@ -65,6 +65,10 @@ #define RK29_CAM_SENSOR_HI253 hi253 #define RK29_CAM_SENSOR_HI704 hi704 #define RK29_CAM_SENSOR_NT99250 nt99250 +#define RK29_CAM_SENSOR_SP0838 sp0838 +#define RK29_CAM_SENSOR_GC0329 gc0329 +#define RK29_CAM_SENSOR_S5K5CA s5k5ca + #define RK29_CAM_SENSOR_NAME_OV7675 "ov7675" #define RK29_CAM_SENSOR_NAME_OV9650 "ov9650" @@ -92,6 +96,9 @@ #define RK29_CAM_SENSOR_NAME_HI253 "hi253" #define RK29_CAM_SENSOR_NAME_HI704 "hi704" #define RK29_CAM_SENSOR_NAME_NT99250 "nt99250" +#define RK29_CAM_SENSOR_NAME_SP0838 "sp0838" +#define RK29_CAM_SENSOR_NAME_GC0329 "gc0329" +#define RK29_CAM_SENSOR_NAME_S5K5CA "s5k5ca" #define ov7675_FULL_RESOLUTION 0x30000 // 0.3 megapixel #define ov9650_FULL_RESOLUTION 0x130000 // 1.3 megapixel @@ -118,6 +125,9 @@ #define hi253_FULL_RESOLUTION 0x200000 // 2 megapixel #define hi704_FULL_RESOLUTION 0x30000 // 0.3 megapixel #define nt99250_FULL_RESOLUTION 0x200000 // 2 megapixel +#define sp0838_FULL_RESOLUTION 0x30000 // 0.3 megapixel +#define gc0329_FULL_RESOLUTION 0x30000 // 0.3 megapixel +#define s5k5ca_FULL_RESOLUTION 0x300000 // 3 megapixel /*---------------- Camera Sensor Must Define Macro End ------------------------*/ diff --git a/drivers/media/video/gc0329.c b/drivers/media/video/gc0329.c index 9db5a4190ca7..bc5729971701 100755 --- a/drivers/media/video/gc0329.c +++ b/drivers/media/video/gc0329.c @@ -20,7 +20,7 @@ o* Driver for MT9M001 CMOS Image Sensor from Micron #include #include #include -#include +#include static int debug; module_param(debug, int, S_IRUGO|S_IWUSR); diff --git a/drivers/media/video/s5k5ca.c b/drivers/media/video/s5k5ca.c index 0b3e431ca4d0..dee10cd8e8ee 100755 --- a/drivers/media/video/s5k5ca.c +++ b/drivers/media/video/s5k5ca.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include "s5k5ca.h" diff --git a/drivers/media/video/sp0838.c b/drivers/media/video/sp0838.c index 0ec3dd7a4037..a828c2e527df 100755 --- a/drivers/media/video/sp0838.c +++ b/drivers/media/video/sp0838.c @@ -20,7 +20,7 @@ o* Driver for MT9M001 CMOS Image Sensor from Micron #include #include #include -#include +#include static int debug=1; module_param(debug, int, S_IRUGO|S_IWUSR); diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h index a27a50910a6c..8e69f2013d65 100755 --- a/include/media/v4l2-chip-ident.h +++ b/include/media/v4l2-chip-ident.h @@ -90,6 +90,7 @@ enum { /* Samsung sensors: reserved range 310-319 */ V4L2_IDENT_S5K66A = 310, /* ddl@rock-chips.com : s5k66a support */ + V4L2_IDENT_S5K5CA = 311, /* ddl@rock-chips.com : s5k5ca support */ /* Conexant MPEG encoder/decoders: reserved range 400-420 */ V4L2_IDENT_CX23418_843 = 403, /* Integrated A/V Decoder on the '418 */ @@ -348,7 +349,10 @@ enum { V4L2_IDENT_HI704 = 64107, /* ddl@rock-chips.com : hi704 support */ V4L2_IDENT_NT99250 = 64108, /* ddl@rock-chips.com : nt99250 support */ V4L2_IDENT_SID130B = 64109, /* ddl@rock-chips.com : sid130B support */ - V4L2_IDENT_SIV121D= 64109, /* ddl@rock-chips.com : sid130B support */ + V4L2_IDENT_SP0838 = 64110, /* ddl@rock-chips.com : SP0838 support */ + V4L2_IDENT_GC0329 = 64111, /* ddl@rock-chips.com : GC0329 support */ + + V4L2_IDENT_SIV121D= 64112, /* ddl@rock-chips.com : sid130B support */ /* Don't just add new IDs at the end: KEEP THIS LIST ORDERED BY ID! */ }; From 59bbb75276c8db67d3abb5c0649bb16be1be1472 Mon Sep 17 00:00:00 2001 From: lw Date: Fri, 3 Aug 2012 16:57:12 +0800 Subject: [PATCH 082/261] phonepad:modify tps65910 gpio base --- arch/arm/mach-rk30/board-rk30-sdk-tps65910.c | 1 + arch/arm/mach-rk30/include/mach/gpio.h | 17 ++++++++++++++--- drivers/mfd/tps65910.c | 8 ++++---- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c b/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c index 69e4afa8f076..b6d4c27d246b 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c +++ b/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c @@ -600,6 +600,7 @@ void __sramfunc board_pmu_tps65910_resume(void) static struct tps65910_board tps65910_data = { .irq = (unsigned)TPS65910_HOST_IRQ, .irq_base = NR_GIC_IRQS + NR_GPIO_IRQS, + .gpio_base = TPS65910_GPIO_EXPANDER_BASE, .pre_init = tps65910_pre_init, .post_init = tps65910_post_init, diff --git a/arch/arm/mach-rk30/include/mach/gpio.h b/arch/arm/mach-rk30/include/mach/gpio.h index 29463c9346e0..24660c3713cd 100755 --- a/arch/arm/mach-rk30/include/mach/gpio.h +++ b/arch/arm/mach-rk30/include/mach/gpio.h @@ -40,23 +40,34 @@ #else #define TCA6424_TOTOL_GPIO_NUM 0 #define TCA6424_TOTOL_GPIO_IRQ_NUM 0 +#define TCA6424_GPIO_EXPANDER_BASE GPIO_EXPANDER_BASE #endif #if defined(CONFIG_GPIO_WM831X) #define WM831X_TOTOL_GPIO_NUM 12 -#define WM831X_GPIO_EXPANDER_BASE (GPIO_EXPANDER_BASE+TCA6424_TOTOL_GPIO_NUM) +#define WM831X_GPIO_EXPANDER_BASE (TCA6424_GPIO_EXPANDER_BASE+TCA6424_TOTOL_GPIO_NUM) #else #define WM831X_TOTOL_GPIO_NUM 0 -#define WM831X_GPIO_EXPANDER_BASE (GPIO_EXPANDER_BASE+TCA6424_TOTOL_GPIO_NUM) +#define WM831X_GPIO_EXPANDER_BASE (TCA6424_GPIO_EXPANDER_BASE+TCA6424_TOTOL_GPIO_NUM) #endif #if defined (CONFIG_GPIO_WM8994) #define CONFIG_GPIO_WM8994_NUM 11 -#define WM8994_GPIO_EXPANDER_BASE (GPIO_EXPANDER_BASE+WM831X_TOTOL_GPIO_NUM) +#define WM8994_GPIO_EXPANDER_BASE (WM831X_GPIO_EXPANDER_BASE+WM831X_TOTOL_GPIO_NUM) #else #define CONFIG_GPIO_WM8994_NUM 0 +#define WM8994_GPIO_EXPANDER_BASE (WM831X_GPIO_EXPANDER_BASE+WM831X_TOTOL_GPIO_NUM) #endif +#if defined (CONFIG_GPIO_TPS65910) +#define CONFIG_GPIO_TPS65910_NUM 9 +#define TPS65910_GPIO_EXPANDER_BASE (WM8994_GPIO_EXPANDER_BASE+CONFIG_GPIO_WM8994_NUM) +#else +#define CONFIG_GPIO_TPS65910_NUM 0 +#define TPS65910_GPIO_EXPANDER_BASE (WM8994_GPIO_EXPANDER_BASE+CONFIG_GPIO_WM8994_NUM) +#endif + + //定义GPIO的PIN口最大数目。CONFIG_SPI_FPGA_GPIO_NUM表示FPGA的PIN脚数。 #define ARCH_NR_GPIOS (PIN_BASE + RK30_TOTOL_GPIO_NUM + TCA6424_TOTOL_GPIO_NUM + WM831X_TOTOL_GPIO_NUM + CONFIG_SPI_FPGA_GPIO_NUM+CONFIG_GPIO_WM8994_NUM) diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index dd7813012b43..42f1bd58afd6 100755 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -36,7 +36,7 @@ static struct mfd_cell tps65910s[] = { }, }; -#define TPS65910_SPEED 400 * 1000 +#define TPS65910_SPEED 200 * 1000 static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg, int bytes, void *dest) @@ -51,14 +51,14 @@ static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg, xfer[0].flags = 0; xfer[0].len = 1; xfer[0].buf = ® - xfer[0].scl_rate = 200*1000; + xfer[0].scl_rate = TPS65910_SPEED; /* Read data */ xfer[1].addr = i2c->addr; xfer[1].flags = I2C_M_RD; xfer[1].len = bytes; xfer[1].buf = dest; - xfer[1].scl_rate = 200*1000; + xfer[1].scl_rate = TPS65910_SPEED; ret = i2c_transfer(i2c->adapter, xfer, 2); //for(i=0;iirq,init_data->irq_base); + printk("%s:irq=%d,irq_base=%d,gpio_base=%d\n",__func__,init_data->irq,init_data->irq_base,pmic_plat_data->gpio_base); return ret; err: From f5e04b74f8936371ab910697751862f9366949ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=8B=E7=A7=80=E6=9D=B0?= Date: Fri, 3 Aug 2012 22:32:46 +0800 Subject: [PATCH 083/261] phonepad: update record and fix some bug. --- sound/soc/codecs/rt3261.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/rt3261.c b/sound/soc/codecs/rt3261.c index c49b3334f6c2..4caff8e702c9 100644 --- a/sound/soc/codecs/rt3261.c +++ b/sound/soc/codecs/rt3261.c @@ -85,7 +85,9 @@ static struct rt3261_init_reg init_list[] = { {RT3261_SPK_VOL , 0x8b8b},//SPKMIX -> SPKVOL {RT3261_HP_VOL , 0x8888}, {RT3261_OUTPUT , 0x8888},//unmute OUTVOLL/R - + {RT3261_SPO_CLSD_RATIO , 0x0001}, + {RT3261_I2S1_SDP , 0xe000}, + {RT3261_I2S2_SDP , 0x8040}, }; #define RT3261_INIT_REG_LEN ARRAY_SIZE(init_list) @@ -1892,6 +1894,10 @@ static const struct snd_soc_dapm_widget rt3261_dapm_widgets[] = { RT3261_PWR_DAC_R1_BIT, 0), SND_SOC_DAPM_DAC("DAC R2", NULL, RT3261_PWR_DIG1, RT3261_PWR_DAC_R2_BIT, 0), + SND_SOC_DAPM_PGA("DAC 1", SND_SOC_NOPM, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("DAC 2", SND_SOC_NOPM, + 0, 0, NULL, 0), /* SPK/OUT Mixer */ SND_SOC_DAPM_MIXER("SPK MIXL", RT3261_PWR_MIXER, RT3261_PWR_SM_L_BIT, 0, rt3261_spk_l_mix, ARRAY_SIZE(rt3261_spk_l_mix)), @@ -1914,14 +1920,14 @@ static const struct snd_soc_dapm_widget rt3261_dapm_widgets[] = { RT3261_PWR_HV_L_BIT, 0, NULL, 0), SND_SOC_DAPM_PGA("HPOVOL R", RT3261_PWR_VOL, RT3261_PWR_HV_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("HPOVOL", SND_SOC_NOPM, + 0, 0, NULL, 0), /* SPO/HPO/LOUT/Mono Mixer */ SND_SOC_DAPM_MIXER("SPOL MIX", SND_SOC_NOPM, 0, 0, rt3261_spo_l_mix, ARRAY_SIZE(rt3261_spo_l_mix)), SND_SOC_DAPM_MIXER("SPOR MIX", SND_SOC_NOPM, 0, 0, rt3261_spo_r_mix, ARRAY_SIZE(rt3261_spo_r_mix)), - SND_SOC_DAPM_MIXER("HPOL MIX", SND_SOC_NOPM, 0, 0, - rt3261_hpo_mix, ARRAY_SIZE(rt3261_hpo_mix)), - SND_SOC_DAPM_MIXER("HPOR MIX", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_MIXER("HPO MIX", SND_SOC_NOPM, 0, 0, rt3261_hpo_mix, ARRAY_SIZE(rt3261_hpo_mix)), SND_SOC_DAPM_MIXER("LOUT MIX", SND_SOC_NOPM, 0, 0, rt3261_lout_mix, ARRAY_SIZE(rt3261_lout_mix)), @@ -2238,12 +2244,15 @@ static const struct snd_soc_dapm_route rt3261_dapm_routes[] = { {"SPOR MIX", "SPKVOL R Switch", "SPKVOL R"}, {"SPOR MIX", "BST1 Switch", "BST1"}, - {"HPOL MIX", "DAC2 Switch", "DAC L2"}, - {"HPOL MIX", "DAC1 Switch", "DAC L1"}, - {"HPOL MIX", "HPVOL Switch", "HPOVOL L"}, - {"HPOR MIX", "DAC2 Switch", "DAC R2"}, - {"HPOR MIX", "DAC1 Switch", "DAC R1"}, - {"HPOR MIX", "HPVOL Switch", "HPOVOL R"}, + {"DAC 2", NULL, "DAC L2"}, + {"DAC 2", NULL, "DAC R2"}, + {"DAC 1", NULL, "DAC L1"}, + {"DAC 1", NULL, "DAC R1"}, + {"HPOVOL", NULL, "HPOVOL L"}, + {"HPOVOL", NULL, "HPOVOL R"}, + {"HPO MIX", "DAC2 Switch", "DAC 2"}, + {"HPO MIX", "DAC1 Switch", "DAC 1"}, + {"HPO MIX", "HPVOL Switch", "HPOVOL"}, {"LOUT MIX", "DAC L1 Switch", "DAC L1"}, {"LOUT MIX", "DAC R1 Switch", "DAC R1"}, @@ -2263,8 +2272,7 @@ static const struct snd_soc_dapm_route rt3261_dapm_routes[] = { {"SPORP", NULL, "SPK amp"}, {"SPORN", NULL, "SPK amp"}, - {"HP amp", NULL, "HPOL MIX"}, - {"HP amp", NULL, "HPOR MIX"}, + {"HP amp", NULL, "HPO MIX"}, {"HPOL", NULL, "HP amp"}, {"HPOR", NULL, "HP amp"}, From ad51d8c8bb764d307b7693d6d31258ffeff4e4ef Mon Sep 17 00:00:00 2001 From: "lw@rock-chips.com" Date: Sun, 5 Aug 2012 13:02:32 +0800 Subject: [PATCH 084/261] phonepad:modify tps65910_pre_init to fix rtc bug --- arch/arm/mach-rk30/board-rk30-sdk-tps65910.c | 163 ++++++++++--------- arch/arm/mach-rk30/include/mach/gpio.h | 2 +- drivers/mfd/tps65910.c | 11 +- include/linux/mfd/tps65910.h | 154 +----------------- 4 files changed, 94 insertions(+), 236 deletions(-) diff --git a/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c b/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c index b6d4c27d246b..906c04928d3a 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c +++ b/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c @@ -39,100 +39,99 @@ int tps65910_pre_init(struct tps65910 *tps65910){ //gpio_request(PMU_POWER_SLEEP, "NULL"); //gpio_direction_output(PMU_POWER_SLEEP, GPIO_HIGH); - val = tps65910_reg_read(tps65910, TPS65910_REG_DEVCTRL2); + val = tps65910_reg_read(tps65910, TPS65910_DEVCTRL2); if (val<0) { - printk(KERN_ERR "Unable to read TPS65910_REG_DEVCTRL2 reg\n"); + printk(KERN_ERR "Unable to read TPS65910_DEVCTRL2 reg\n"); return val; } /* Set sleep state active high and allow device turn-off after PWRON long press */ - val |= (TPS65910_DEV2_SLEEPSIG_POL | TPS65910_DEV2_PWON_LP_OFF); + val |= (DEVCTRL2_SLEEPSIG_POL_MASK | DEVCTRL2_PWON_LP_OFF_MASK); - err = tps65910_reg_write(tps65910, TPS65910_REG_DEVCTRL2, val); + err = tps65910_reg_write(tps65910, TPS65910_DEVCTRL2, val); if (err) { - printk(KERN_ERR "Unable to write TPS65910_REG_DEVCTRL2 reg\n"); + printk(KERN_ERR "Unable to write TPS65910_DEVCTRL2 reg\n"); return err; } #if 1 /* set PSKIP=0 */ - val = tps65910_reg_read(tps65910, TPS65910_REG_DCDCCTRL); + val = tps65910_reg_read(tps65910, TPS65910_DCDCCTRL); if (val<0) { - printk(KERN_ERR "Unable to read TPS65910_REG_DCDCCTRL reg\n"); + printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n"); return val; } - //val &= ~(1 << 4); - val &= 0xFC; - // val |= 0x03; - err = tps65910_reg_write(tps65910, TPS65910_REG_DCDCCTRL, val); + val &= ~DEVCTRL_DEV_OFF_MASK; + val &= ~DEVCTRL_DEV_SLP_MASK; + err = tps65910_reg_write(tps65910, TPS65910_DCDCCTRL, val); if (err) { - printk(KERN_ERR "Unable to write TPS65910_REG_DCDCCTRL reg\n"); + printk(KERN_ERR "Unable to write TPS65910_DCDCCTRL reg\n"); return err; } #endif /* Set the maxinum load current */ /* VDD1 */ - val = tps65910_reg_read(tps65910, TPS65910_REG_VDD1); + val = tps65910_reg_read(tps65910, TPS65910_VDD1); if (val<0) { - printk(KERN_ERR "Unable to read TPS65910_REG_VDD1 reg\n"); + printk(KERN_ERR "Unable to read TPS65910_VDD1 reg\n"); return val; } - val |= (1<<5); - val |= (0x07<<2); - err = tps65910_reg_write(tps65910, TPS65910_REG_VDD1, val); + val |= (1<<5); //when 1: 1.5 A + val |= (0x07<<2); //TSTEP[2:0] = 111 : 2.5 mV/μs(sampling 3 Mhz/5) + err = tps65910_reg_write(tps65910, TPS65910_VDD1, val); if (err) { - printk(KERN_ERR "Unable to write TPS65910_REG_VDD1 reg\n"); + printk(KERN_ERR "Unable to write TPS65910_VDD1 reg\n"); return err; } /* VDD2 */ - val = tps65910_reg_read(tps65910, TPS65910_REG_VDD2); + val = tps65910_reg_read(tps65910, TPS65910_VDD2); if (val<0) { - printk(KERN_ERR "Unable to read TPS65910_REG_VDD2 reg\n"); + printk(KERN_ERR "Unable to read TPS65910_VDD2 reg\n"); return val; } - val |= (1<<5); - err = tps65910_reg_write(tps65910, TPS65910_REG_VDD2, val); + val |= (1<<5); //when 1: 1.5 A + err = tps65910_reg_write(tps65910, TPS65910_VDD2, val); if (err) { - printk(KERN_ERR "Unable to write TPS65910_REG_VDD2 reg\n"); + printk(KERN_ERR "Unable to write TPS65910_VDD2 reg\n"); return err; } /* VIO */ - val = tps65910_reg_read(tps65910, TPS65910_REG_VIO); + val = tps65910_reg_read(tps65910, TPS65910_VIO); if (val<0) { - printk(KERN_ERR "Unable to read TPS65910_REG_VIO reg\n"); + printk(KERN_ERR "Unable to read TPS65910_VIO reg\n"); return -EIO; } - val |= (1<<6); - err = tps65910_reg_write(tps65910, TPS65910_REG_VIO, val); + val |= (1<<6); //when 01: 1.0 A + err = tps65910_reg_write(tps65910, TPS65910_VIO, val); if (err) { - printk(KERN_ERR "Unable to write TPS65910_REG_VIO reg\n"); + printk(KERN_ERR "Unable to write TPS65910_VIO reg\n"); return err; } #if 1 /* Mask ALL interrupts */ - err = tps65910_reg_write(tps65910,TPS65910_REG_INT_MSK, 0xFF); + err = tps65910_reg_write(tps65910,TPS65910_INT_MSK, 0xFF); if (err) { - printk(KERN_ERR "Unable to write TPS65910_REG_INT_MSK reg\n"); + printk(KERN_ERR "Unable to write TPS65910_INT_MSK reg\n"); return err; } - err = tps65910_reg_write(tps65910, TPS65910_REG_INT_MSK2, 0x03); + err = tps65910_reg_write(tps65910, TPS65910_INT_MSK2, 0x03); if (err) { - printk(KERN_ERR "Unable to write TPS65910_REG_INT_MSK2 reg\n"); + printk(KERN_ERR "Unable to write TPS65910_INT_MSK2 reg\n"); return err; } /* Set RTC Power, disable Smart Reflex in DEVCTRL_REG */ #if 1 val = 0; - val |= (TPS65910_SR_CTL_I2C_SEL); - err = tps65910_reg_write(tps65910, TPS65910_REG_DEVCTRL, val); + val |= (DEVCTRL_SR_CTL_I2C_SEL_MASK); + err = tps65910_reg_write(tps65910, TPS65910_DEVCTRL, val); if (err) { - printk(KERN_ERR "Unable to write TPS65910_REG_DEVCTRL reg\n"); + printk(KERN_ERR "Unable to write TPS65910_DEVCTRL reg\n"); return err; } printk(KERN_INFO "TPS65910 Set default voltage.\n"); @@ -141,9 +140,9 @@ int tps65910_pre_init(struct tps65910 *tps65910){ //read sleep control register for debug for(i=0; i<6; i++) { - err = tps65910_reg_read(tps65910, &val, TPS65910_REG_DEVCTRL+i); + err = tps65910_reg_read(tps65910, &val, TPS65910_DEVCTRL+i); if (err) { - printk(KERN_ERR "Unable to read TPS65910_REG_DCDCCTRL reg\n"); + printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n"); return -EIO; } else @@ -154,65 +153,72 @@ int tps65910_pre_init(struct tps65910 *tps65910){ #if 1 //sleep control register /*set func when in sleep mode */ - val = tps65910_reg_read(tps65910, TPS65910_REG_DEVCTRL); + val = tps65910_reg_read(tps65910, TPS65910_DEVCTRL); if (val<0) { - printk(KERN_ERR "Unable to read TPS65910_REG_DCDCCTRL reg\n"); + printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n"); return val; } - val |= (1 << 1); - err = tps65910_reg_write(tps65910, TPS65910_REG_DEVCTRL, val); - if (err) { - printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \ - \n", TPS65910_REG_VDIG1); - return err; - } - /* open ldo when in sleep mode */ - val = tps65910_reg_read(tps65910, TPS65910_REG_SLEEP_KEEP_LDO_ON); + + val |= (1 << 1); + err = tps65910_reg_write(tps65910, TPS65910_DEVCTRL, val); + if (err) { + printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \ + \n", TPS65910_VDIG1); + return err; + } + + /* open ldo when in sleep mode */ + val = tps65910_reg_read(tps65910, TPS65910_SLEEP_KEEP_LDO_ON); if (val<0) { - printk(KERN_ERR "Unable to read TPS65910_REG_DCDCCTRL reg\n"); + printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n"); return val; } - val &= 0; - err = tps65910_reg_write(tps65910, TPS65910_REG_SLEEP_KEEP_LDO_ON, val); - if (err) { - printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \ - \n", TPS65910_REG_VDIG1); - return err; - } - /*set dc mode when in sleep mode */ - val = tps65910_reg_read(tps65910, TPS65910_REG_SLEEP_KEEP_RES_ON); + + val &= 0; + err = tps65910_reg_write(tps65910, TPS65910_SLEEP_KEEP_LDO_ON, val); + if (err) { + printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \ + \n", TPS65910_VDIG1); + return err; + } + + /*set dc mode when in sleep mode */ + val = tps65910_reg_read(tps65910, TPS65910_SLEEP_KEEP_RES_ON); if (val<0) { - printk(KERN_ERR "Unable to read TPS65910_REG_DCDCCTRL reg\n"); + printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n"); return val; } - val |= 0xff; - err = tps65910_reg_write(tps65910, TPS65910_REG_SLEEP_KEEP_RES_ON, val); - if (err) { - printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \ - \n", TPS65910_REG_VDIG1); - return err; - } - /*close ldo when in sleep mode */ - val = tps65910_reg_read(tps65910, TPS65910_REG_SLEEP_SET_LDO_OFF); + + val |= 0xff; + err = tps65910_reg_write(tps65910, TPS65910_SLEEP_KEEP_RES_ON, val); + if (err) { + printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \ + \n", TPS65910_VDIG1); + return err; + } + + /*close ldo when in sleep mode */ + val = tps65910_reg_read(tps65910, TPS65910_SLEEP_SET_LDO_OFF); if (val<0) { - printk(KERN_ERR "Unable to read TPS65910_REG_DCDCCTRL reg\n"); + printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n"); return val; } - val |= 0x9B; - err = tps65910_reg_write(tps65910, TPS65910_REG_SLEEP_SET_LDO_OFF, val); - if (err) { - printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \ - \n", TPS65910_REG_VDIG1); - return err; - } + + val |= 0x9B; + err = tps65910_reg_write(tps65910, TPS65910_SLEEP_SET_LDO_OFF, val); + if (err) { + printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \ + \n", TPS65910_VDIG1); + return err; + } #endif #if 0 //read sleep control register for debug for(i=0; i<6; i++) { - err = tps65910_reg_read(tps65910, &val, TPS65910_REG_DEVCTRL+i); + err = tps65910_reg_read(tps65910, &val, TPS65910_DEVCTRL+i); if (err) { - printk(KERN_ERR "Unable to read TPS65910_REG_DCDCCTRL reg\n"); + printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n"); return -EIO; } else @@ -620,6 +626,7 @@ static struct tps65910_board tps65910_data = { .tps65910_pmic_init_data[TPS65910_REG_VAUX2] = &tps65910_ldo4, .tps65910_pmic_init_data[TPS65910_REG_VAUX33] = &tps65910_ldo5, .tps65910_pmic_init_data[TPS65910_REG_VMMC] = &tps65910_ldo6, + }; diff --git a/arch/arm/mach-rk30/include/mach/gpio.h b/arch/arm/mach-rk30/include/mach/gpio.h index 24660c3713cd..e2cc0ffc0fb8 100755 --- a/arch/arm/mach-rk30/include/mach/gpio.h +++ b/arch/arm/mach-rk30/include/mach/gpio.h @@ -69,7 +69,7 @@ //定义GPIO的PIN口最大数目。CONFIG_SPI_FPGA_GPIO_NUM表示FPGA的PIN脚数。 -#define ARCH_NR_GPIOS (PIN_BASE + RK30_TOTOL_GPIO_NUM + TCA6424_TOTOL_GPIO_NUM + WM831X_TOTOL_GPIO_NUM + CONFIG_SPI_FPGA_GPIO_NUM+CONFIG_GPIO_WM8994_NUM) +#define ARCH_NR_GPIOS (PIN_BASE + RK30_TOTOL_GPIO_NUM + TCA6424_TOTOL_GPIO_NUM + WM831X_TOTOL_GPIO_NUM + CONFIG_SPI_FPGA_GPIO_NUM+CONFIG_GPIO_WM8994_NUM+CONFIG_GPIO_TPS65910_NUM) #define INVALID_GPIO -1 diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index 42f1bd58afd6..6b16534548ad 100755 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -239,7 +239,7 @@ static int tps65910_i2c_probe(struct i2c_client *i2c, struct tps65910_board *pmic_plat_data; struct tps65910_platform_data *init_data; int ret = 0; - + pmic_plat_data = dev_get_platdata(&i2c->dev); if (!pmic_plat_data) return -EINVAL; @@ -292,6 +292,7 @@ static int tps65910_i2c_probe(struct i2c_client *i2c, goto err; } } + printk("%s:irq=%d,irq_base=%d,gpio_base=%d\n",__func__,init_data->irq,init_data->irq_base,pmic_plat_data->gpio_base); return ret; @@ -310,15 +311,15 @@ int tps65910_device_shutdown(void) printk("%s\n",__func__); - val = tps65910_reg_read(tps65910, TPS65910_REG_DEVCTRL); + val = tps65910_reg_read(tps65910, TPS65910_DEVCTRL); if (val<0) { printk(KERN_ERR "Unable to read TPS65910_REG_DCDCCTRL reg\n"); return -EIO; } - val |= (1 << 3)|(1 << 0); - val &= ~(1 << 6); //keep rtc - err = tps65910_reg_write(tps65910, TPS65910_REG_DEVCTRL, val); + val |= DEVCTRL_DEV_OFF_MASK; + val &= ~DEVCTRL_CK32K_CTRL_MASK; //keep rtc + err = tps65910_reg_write(tps65910, TPS65910_DEVCTRL, val); if (err) { printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \ \n", TPS65910_REG_VDIG1); diff --git a/include/linux/mfd/tps65910.h b/include/linux/mfd/tps65910.h index 40a56631a8cd..c093c477477b 100755 --- a/include/linux/mfd/tps65910.h +++ b/include/linux/mfd/tps65910.h @@ -368,7 +368,7 @@ #define DCDCCTRL_DCDCCKSYNC_SHIFT 0 -/*Register DEVCTRL (0x80) register.RegisterDescription */ +/*Register DEVCTRL (0x3F) register.RegisterDescription */ #define DEVCTRL_RTC_PWDN_MASK 0x40 #define DEVCTRL_RTC_PWDN_SHIFT 6 #define DEVCTRL_CK32K_CTRL_MASK 0x20 @@ -385,7 +385,7 @@ #define DEVCTRL_DEV_OFF_SHIFT 0 -/*Register DEVCTRL2 (0x80) register.RegisterDescription */ +/*Register DEVCTRL2 (0x40) register.RegisterDescription */ #define DEVCTRL2_TSLOT_LENGTH_MASK 0x30 #define DEVCTRL2_TSLOT_LENGTH_SHIFT 4 #define DEVCTRL2_SLEEPSIG_POL_MASK 0x08 @@ -790,157 +790,7 @@ -/* - * ---------------------------------------------------------------------------- - * Registers, all 8 bits - * ---------------------------------------------------------------------------- - */ -#define TPS65910_REG_SECONDS 0x00 -#define TPS65910_REG_MINUTES 0x01 -#define TPS65910_REG_HOURS 0x02 -#define TPS65910_REG_DAYS 0x03 -#define TPS65910_REG_MONTHS 0x04 -#define TPS65910_REG_YEARS 0x05 -#define TPS65910_REG_WEEKS 0x06 -#define TPS65910_REG_ALARM_SECONDS 0x08 -#define TPS65910_REG_ALARM_MINUTES 0x09 -#define TPS65910_REG_ALARM_HOURS 0x0A -#define TPS65910_REG_ALARM_DAYS 0x0B -#define TPS65910_REG_ALARM_MONTHS 0x0C -#define TPS65910_REG_ALARM_YEARS 0x0D -#define TPS65910_REG_RTC_CTRL 0x10 -#define TPS65910_REG_RTC_STATUS 0x11 -#define TPS65910_REG_RTC_INTERRUPTS 0x12 -#define TPS65910_REG_RTC_COMP_LSB 0x13 -#define TPS65910_REG_RTC_COMP_MSB 0x14 -#define TPS65910_REG_RTC_RES_PROG 0x15 -#define TPS65910_REG_RTC_RESET_STATUS 0x16 -#define TPS65910_REG_BCK1 0x17 -#define TPS65910_REG_BCK2 0x18 -#define TPS65910_REG_BCK3 0x19 -#define TPS65910_REG_BCK4 0x1A -#define TPS65910_REG_BCK5 0x1B -#define TPS65910_REG_PUADEN 0x1C -#define TPS65910_REG_REF 0x1D - -#define TPS65910_REG_THERM 0x38 -#define TPS65910_REG_BBCH 0x39 - -#define TPS65910_REG_DCDCCTRL 0x3E -#define TPS65910_REG_DEVCTRL 0x3F -#define TPS65910_REG_DEVCTRL2 0x40 -#define TPS65910_REG_SLEEP_KEEP_LDO_ON 0x41 -#define TPS65910_REG_SLEEP_KEEP_RES_ON 0x42 -#define TPS65910_REG_SLEEP_SET_LDO_OFF 0x43 -#define TPS65910_REG_SLEEP_SET_RES_OFF 0x44 -#define TPS65910_REG_EN1_LDO_ASS 0x45 -#define TPS65910_REG_EN1_SMPS_ASS 0x46 -#define TPS65910_REG_EN2_LDO_ASS 0x47 -#define TPS65910_REG_EN2_SMPS_ASS 0x48 -#define TPS65910_REG_EN3_LDO_ASS 0x49 -#define TPS65910_REG_SPARE 0x4A - -#define TPS65910_REG_INT_STS 0x50 -#define TPS65910_REG_INT_MSK 0x51 -#define TPS65910_REG_INT_STS2 0x52 -#define TPS65910_REG_INT_MSK2 0x53 -#define TPS65910_REG_INT_STS3 0x54 -#define TPS65910_REG_INT_MSK3 0x55 - -#define TPS65910_REG_GPIO0 0x60 - -#define TPS65910_REG_JTAGVERNUM 0x80 - -/* TPS65910 GPIO Specific flags */ -#define TPS65910_GPIO_INT_FALLING 0 -#define TPS65910_GPIO_INT_RISING 1 - -#define TPS65910_DEBOUNCE_91_5_MS 0 -#define TPS65910_DEBOUNCE_150_MS 1 - -#define TPS65910_GPIO_PUDIS (1 << 3) -#define TPS65910_GPIO_CFG_OUTPUT (1 << 2) - - - -/* TPS65910 Interrupt events */ - -/* RTC Driver */ -#define TPS65910_RTC_ALARM_IT 0x80 -#define TPS65910_RTC_PERIOD_IT 0x40 - -/*Core Driver */ -#define TPS65910_HOT_DIE_IT 0x20 -#define TPS65910_PWRHOLD_IT 0x10 -#define TPS65910_PWRON_LP_IT 0x08 -#define TPS65910_PWRON_IT 0x04 -#define TPS65910_VMBHI_IT 0x02 -#define TPS65910_VMBGCH_IT 0x01 - -/* GPIO driver */ -#define TPS65910_GPIO_F_IT 0x02 -#define TPS65910_GPIO_R_IT 0x01 - - -#define TPS65910_VRTC_OFFMASK (1<<3) - -/* Back-up battery charger control */ -#define TPS65910_BBCHEN 0x01 - -/* Back-up battery charger voltage */ -#define TPS65910_BBSEL_3P0 0x00 -#define TPS65910_BBSEL_2P52 0x02 -#define TPS65910_BBSEL_3P15 0x04 -#define TPS65910_BBSEL_VBAT 0x06 - -/* DEVCTRL_REG flags */ -#define TPS65910_RTC_PWDNN 0x40 -#define TPS65910_CK32K_CTRL 0x20 -#define TPS65910_SR_CTL_I2C_SEL 0x10 -#define TPS65910_DEV_OFF_RST 0x08 -#define TPS65910_DEV_ON 0x04 -#define TPS65910_DEV_SLP 0x02 -#define TPS65910_DEV_OFF 0x01 - -/* DEVCTRL2_REG flags */ -#define TPS65910_DEV2_TSLOT_LENGTH 0x30 -#define TPS65910_DEV2_SLEEPSIG_POL 0x08 -#define TPS65910_DEV2_PWON_LP_OFF 0x04 -#define TPS65910_DEV2_PWON_LP_RST 0x02 -#define TPS65910_DEV2_IT_POL 0x01 - -/* Number of step-down/up converters available */ -#define TPS65910_NUM_DCDC 4 - -/* Number of LDO voltage regulators available */ -#define TPS65910_NUM_LDO 9 - -/* Number of total regulators available */ -#define TPS65910_NUM_REGULATOR (TPS65910_NUM_DCDC + TPS65910_NUM_LDO) - - -/* Regulator Supply state */ -#define SUPPLY_STATE_FLAG 0x03 -/* OFF States */ -#define TPS65910_REG_OFF_00 0x00 -#define TPS65910_REG_OFF_10 0x02 -/* OHP - on High Power */ -#define TPS65910_REG_OHP 0x01 -/* OLP - on Low Power */ -#define TPS65910_REG_OLP 0x03 - -#define TPS65910_MAX_IRQS 10 -#define TPS65910_VMBDCH_IRQ 0 -#define TPS65910_VMBHI_IRQ 1 -#define TPS65910_PWRON_IRQ 2 -#define TPS65910_PWRON_LP_IRQ 3 -#define TPS65910_PWRHOLD_IRQ 4 -#define TPS65910_HOTDIE_IRQ 5 -#define TPS65910_RTC_ALARM_IRQ 6 -#define TPS65910_RTC_PERIOD_IRQ 7 -#define TPS65910_GPIO0_R_IRQ 8 -#define TPS65910_GPIO0_F_IRQ 9 /** From bdb57efe9301ecb050e38ee3cb49fdaa08652785 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E8=BE=89?= Date: Mon, 6 Aug 2012 10:51:40 +0800 Subject: [PATCH 085/261] fix board-rk30-ds1001b compile wm8326 error --- .../arm/mach-rk30/board-rk30-ds1001b-wm8326.c | 842 ++++++++++++++++++ arch/arm/mach-rk30/board-rk30-ds1001b.c | 2 +- 2 files changed, 843 insertions(+), 1 deletion(-) create mode 100755 arch/arm/mach-rk30/board-rk30-ds1001b-wm8326.c diff --git a/arch/arm/mach-rk30/board-rk30-ds1001b-wm8326.c b/arch/arm/mach-rk30/board-rk30-ds1001b-wm8326.c new file mode 100755 index 000000000000..ce3050e7e6df --- /dev/null +++ b/arch/arm/mach-rk30/board-rk30-ds1001b-wm8326.c @@ -0,0 +1,842 @@ +#include +#include +#include +#include +#include + +#include + +#define cru_readl(offset) readl_relaxed(RK30_CRU_BASE + offset) +#define cru_writel(v, offset) do { writel_relaxed(v, RK30_CRU_BASE + offset); dsb(); } while (0) + +#define grf_readl(offset) readl_relaxed(RK30_GRF_BASE + offset) +#define grf_writel(v, offset) do { writel_relaxed(v, RK30_GRF_BASE + offset); dsb(); } while (0) + +#define CRU_CLKGATE5_CON_ADDR 0x00e4 +#define GRF_GPIO6L_DIR_ADDR 0x0030 +#define GRF_GPIO6L_DO_ADDR 0x0068 +#define GRF_GPIO6L_EN_ADDR 0x00a0 +#define CRU_CLKGATE5_GRFCLK_ON 0x00100000 +#define CRU_CLKGATE5_GRFCLK_OFF 0x00100010 +#define GPIO6_PB1_DIR_OUT 0x02000200 +#define GPIO6_PB1_DO_LOW 0x02000000 +#define GPIO6_PB1_DO_HIGH 0x02000200 +#define GPIO6_PB1_EN_MASK 0x02000200 +#define GPIO6_PB1_UNEN_MASK 0x02000000 + +/* wm8326 pmu*/ +#if defined(CONFIG_GPIO_WM831X) +static struct rk29_gpio_expander_info wm831x_gpio_settinginfo[] = { + { + .gpio_num = WM831X_P01, // tp3 + .pin_type = GPIO_OUT, + .pin_value = GPIO_LOW, + }, + { + .gpio_num = WM831X_P02, //tp4 + .pin_type = GPIO_IN, + }, + { + .gpio_num = WM831X_P03, //tp2 + .pin_type = GPIO_OUT, + .pin_value = GPIO_HIGH, + }, + { + .gpio_num = WM831X_P04, //tp1 + .pin_type = GPIO_IN, + }, + { + .gpio_num = WM831X_P05, //tp1 + .pin_type = GPIO_IN, + }, + { + .gpio_num = WM831X_P06, //tp1 + .pin_type = GPIO_OUT, + .pin_value = GPIO_HIGH, + }, + { + .gpio_num = WM831X_P07, //tp1 + .pin_type = GPIO_IN, + }, + { + .gpio_num = WM831X_P08, //tp1 + .pin_type = GPIO_OUT, + .pin_value = GPIO_HIGH, + }, + { + .gpio_num = WM831X_P09, //tp1 + .pin_type = GPIO_OUT, + .pin_value = GPIO_HIGH, + }, + { + .gpio_num = WM831X_P10, //tp1 + .pin_type = GPIO_IN, + }, + { + .gpio_num = WM831X_P11, //tp1 + .pin_type = GPIO_OUT, + .pin_value = GPIO_HIGH, + }, + { + .gpio_num = WM831X_P12, + .pin_type = GPIO_OUT, + .pin_value = GPIO_HIGH, + }, +}; +#endif + +#if defined(CONFIG_MFD_WM831X) + +#define UNLOCK_SECURITY_KEY ~(0x1<<5) +#define LOCK_SECURITY_KEY 0x00 +#define PMU_POWER_SLEEP RK30_PIN6_PB1 +static struct wm831x *Wm831x; + +static int wm831x_pre_init(struct wm831x *parm) +{ + int ret; + Wm831x = parm; +// printk("%s\n", __func__); + gpio_request(PMU_POWER_SLEEP, "NULL"); + gpio_direction_output(PMU_POWER_SLEEP, GPIO_LOW); + + #ifdef CONFIG_WM8326_VBAT_LOW_DETECTION + #ifdef CONFIG_BATTERY_RK30_VOL3V8 + wm831x_set_bits(parm,WM831X_SYSVDD_CONTROL ,0xc077,0xc035); //pvdd power on dect vbat voltage + printk("+++The vbat is too low+++\n"); + #endif + #endif + + ret = wm831x_reg_read(parm, WM831X_POWER_STATE) & 0xffff; + wm831x_reg_write(parm, WM831X_POWER_STATE, (ret & 0xfff8) | 0x04); + + wm831x_set_bits(parm, WM831X_RTC_CONTROL, WM831X_RTC_ALAM_ENA_MASK, 0x0400);//enable rtc alam + //BATT_FET_ENA = 1 + wm831x_reg_write(parm, WM831X_SECURITY_KEY, 0x9716); // unlock security key + wm831x_set_bits(parm, WM831X_RESET_CONTROL, 0x1003, 0x1001); + ret = wm831x_reg_read(parm, WM831X_RESET_CONTROL) & 0xffff & UNLOCK_SECURITY_KEY; // enternal reset active in sleep +// printk("%s:WM831X_RESET_CONTROL=0x%x\n", __func__, ret); + wm831x_reg_write(parm, WM831X_RESET_CONTROL, ret); + + wm831x_set_bits(parm,WM831X_DC1_ON_CONFIG ,0x0300,0x0000); //set dcdc mode is FCCM + wm831x_set_bits(parm,WM831X_DC2_ON_CONFIG ,0x0300,0x0000); + wm831x_set_bits(parm,WM831X_DC3_ON_CONFIG ,0x0300,0x0000); + wm831x_set_bits(parm,0x4066,0x0300,0x0000); + +#ifndef CONFIG_MACH_RK3066_SDK + wm831x_set_bits(parm,WM831X_LDO10_CONTROL ,0x0040,0x0040);// set ldo10 in switch mode +#endif + wm831x_set_bits(parm,WM831X_STATUS_LED_1 ,0xc300,0xc100);// set led1 on(in manual mode) + wm831x_set_bits(parm,WM831X_STATUS_LED_2 ,0xc300,0xc000);//set led2 off(in manual mode) + + wm831x_set_bits(parm,WM831X_LDO5_SLEEP_CONTROL ,0xe000,0x2000);// set ldo5 is disable in sleep mode + wm831x_set_bits(parm,WM831X_LDO1_SLEEP_CONTROL ,0xe000,0x2000);// set ldo1 is disable in sleep mode + + wm831x_reg_write(parm, WM831X_SECURITY_KEY, LOCK_SECURITY_KEY); // lock security key + + return 0; +} +static int wm831x_mask_interrupt(struct wm831x *Wm831x) +{ + /**************************clear interrupt********************/ + wm831x_reg_write(Wm831x,WM831X_INTERRUPT_STATUS_1,0xffff); + wm831x_reg_write(Wm831x,WM831X_INTERRUPT_STATUS_2,0xffff); + wm831x_reg_write(Wm831x,WM831X_INTERRUPT_STATUS_3,0xffff); + wm831x_reg_write(Wm831x,WM831X_INTERRUPT_STATUS_4,0xffff); + wm831x_reg_write(Wm831x,WM831X_INTERRUPT_STATUS_5,0xffff); + + wm831x_reg_write(Wm831x,WM831X_SYSTEM_INTERRUPTS_MASK,0xbedc); //mask interrupt which not used + return 0; + /*****************************************************************/ +} + +#ifdef CONFIG_WM8326_VBAT_LOW_DETECTION +static int wm831x_low_power_detection(struct wm831x *wm831x) +{ + #ifdef CONFIG_BATTERY_RK30_VOL3V8 + wm831x_reg_write(wm831x,WM831X_SYSTEM_INTERRUPTS_MASK,0xbe5c); + wm831x_set_bits(wm831x,WM831X_INTERRUPT_STATUS_1_MASK,0x8000,0x0000); + wm831x_set_bits(wm831x,WM831X_SYSVDD_CONTROL ,0xc077,0x0035); //set pvdd low voltage is 3.1v hi voltage is 3.3v + #else + wm831x_reg_write(wm831x,WM831X_AUXADC_CONTROL,0x803f); //open adc + wm831x_reg_write(wm831x,WM831X_AUXADC_CONTROL,0xd03f); + wm831x_reg_write(wm831x,WM831X_AUXADC_SOURCE,0x0001); + + wm831x_reg_write(wm831x,WM831X_COMPARATOR_CONTROL,0x0001); + wm831x_reg_write(wm831x,WM831X_COMPARATOR_1,0x2844); //set the low power is 3.1v + + wm831x_reg_write(wm831x,WM831X_INTERRUPT_STATUS_1_MASK,0x99ee); + wm831x_set_bits(wm831x,WM831X_SYSTEM_INTERRUPTS_MASK,0x0100,0x0000); + if (wm831x_reg_read(wm831x,WM831X_AUXADC_DATA)< 0x1844){ + printk("The vbat is too low.\n"); + wm831x_device_shutdown(wm831x); + } + #endif + return 0; +} +#endif + +#define AVS_BASE 172 +int wm831x_post_init(struct wm831x *Wm831x) +{ + struct regulator *dcdc; + struct regulator *ldo; + + + ldo = regulator_get(NULL, "ldo6"); //vcc_33 + regulator_set_voltage(ldo, 3300000, 3300000); + regulator_set_suspend_voltage(ldo, 3300000); + regulator_enable(ldo); +// printk("%s set ldo6 vcc_33=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "ldo4"); // vdd_11 + regulator_set_voltage(ldo, 1100000, 1100000); + regulator_set_suspend_voltage(ldo, 1000000); + regulator_enable(ldo); +// printk("%s set ldo4 vdd_11=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "ldo5"); //vcc_25 + regulator_set_voltage(ldo, 2500000, 2500000); + regulator_set_suspend_voltage(ldo, 2500000); + regulator_enable(ldo); +// printk("%s set ldo5 vcc_25=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + + dcdc = regulator_get(NULL, "dcdc4"); // vcc_io +#ifdef CONFIG_MACH_RK3066_SDK + regulator_set_voltage(dcdc, 3300000, 3300000); + regulator_set_suspend_voltage(dcdc, 3100000); +#else + regulator_set_voltage(dcdc, 3000000, 3000000); + regulator_set_suspend_voltage(dcdc, 2800000); +#endif + regulator_enable(dcdc); +// printk("%s set dcdc4 vcc_io=%dmV end\n", __func__, regulator_get_voltage(dcdc)); + regulator_put(dcdc); + udelay(100); + + dcdc = regulator_get(NULL, "vdd_cpu"); // vdd_arm + regulator_set_voltage(dcdc, 1100000, 1100000); + regulator_set_suspend_voltage(dcdc, 1000000); + regulator_enable(dcdc); + printk("%s set dcdc2 vdd_cpu(vdd_arm)=%dmV end\n", __func__, regulator_get_voltage(dcdc)); + regulator_put(dcdc); + udelay(100); + + dcdc = regulator_get(NULL, "vdd_core"); // vdd_log + + /* Read avs value under logic 1.1V*/ + regulator_set_voltage(dcdc, 1100000, 1100000); + avs_init_val_get(1,1100000,"wm8326 init"); + udelay(600); + avs_set_scal_val(AVS_BASE); + + regulator_set_voltage(dcdc, 1150000, 1150000); + regulator_set_suspend_voltage(dcdc, 1000000); + regulator_enable(dcdc); + printk("%s set dcdc1 vdd_core(vdd_log)=%dmV end\n", __func__, regulator_get_voltage(dcdc)); + regulator_put(dcdc); + udelay(100); + + dcdc = regulator_get(NULL, "dcdc3"); // vcc_ddr + regulator_set_voltage(dcdc, 1150000, 1150000); + regulator_set_suspend_voltage(dcdc, 1150000); + regulator_enable(dcdc); +// printk("%s set dcdc3 vcc_ddr=%dmV end\n", __func__, regulator_get_voltage(dcdc)); + regulator_put(dcdc); + udelay(100); + + ldo = regulator_get(NULL, "ldo7"); // vcc28_cif + regulator_set_voltage(ldo, 2800000, 2800000); + regulator_set_suspend_voltage(ldo, 2800000); + regulator_enable(ldo); +// printk("%s set ldo7 vcc28_cif=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "ldo1"); // vcc18_cif + regulator_set_voltage(ldo, 1800000, 1800000); + regulator_set_suspend_voltage(ldo, 1800000); + regulator_enable(ldo); +// printk("%s set ldo1 vcc18_cif=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "ldo8"); // vcca_33 + regulator_set_voltage(ldo, 3300000, 3300000); + regulator_set_suspend_voltage(ldo, 3300000); + regulator_enable(ldo); +// printk("%s set ldo8 vcca_33=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "ldo2"); //vccio_wl + regulator_set_voltage(ldo, 1800000, 1800000); + regulator_set_suspend_voltage(ldo, 1800000); + regulator_enable(ldo); +// printk("%s set ldo2 vccio_wl=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "ldo10"); //flash io + regulator_set_voltage(ldo, 1800000, 1800000); + regulator_set_suspend_voltage(ldo, 1800000); + regulator_enable(ldo); +// printk("%s set ldo10 vcca_wl=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + +#ifdef CONFIG_MACH_RK3066_SDK + ldo = regulator_get(NULL, "ldo3"); //vdd11_hdmi + regulator_set_voltage(ldo, 1100000, 1100000); + regulator_set_suspend_voltage(ldo, 1100000); +#else + ldo = regulator_get(NULL, "ldo3"); //vdd_12 + regulator_set_voltage(ldo, 1200000, 1200000); + regulator_set_suspend_voltage(ldo, 1200000); +#endif + regulator_enable(ldo); +// printk("%s set ldo3 vdd_12=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "ldo9"); //vcc_tp + regulator_set_voltage(ldo, 3300000, 3300000); + regulator_set_suspend_voltage(ldo, 3300000); + regulator_enable(ldo); +// printk("%s set ldo9 vcc_tp=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + wm831x_mask_interrupt(Wm831x); + + #ifdef CONFIG_WM8326_VBAT_LOW_DETECTION + wm831x_low_power_detection(Wm831x); + #endif + + printk("wm831x_post_init end"); + return 0; +} + +static int wm831x_last_deinit(struct wm831x *Wm831x) +{ + struct regulator *ldo; + + printk("%s\n", __func__); + ldo = regulator_get(NULL, "ldo1"); + regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo2"); + regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo3"); + regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo4"); + //regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo5"); +// regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo6"); +// regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo7"); + regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo8"); + regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo9"); + regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo10"); + regulator_disable(ldo); + regulator_put(ldo); + + return 0; +} + +struct wm831x_status_pdata wm831x_status_platdata[WM831X_MAX_STATUS] = { + { + .default_src = WM831X_STATUS_OTP, + .name = "wm831x_status0", + .default_trigger = "wm831x_otp", + }, + { + .default_src = WM831X_STATUS_POWER, + .name = "wm831x_status1", + .default_trigger = "wm831x_power", + }, +}; + +static struct regulator_consumer_supply dcdc1_consumers[] = { + { + .supply = "vdd_core", + } +}; + +static struct regulator_consumer_supply dcdc2_consumers[] = { + { + .supply = "vdd_cpu", + } + +}; + +static struct regulator_consumer_supply dcdc3_consumers[] = { + { + .supply = "dcdc3", + } +}; + +static struct regulator_consumer_supply dcdc4_consumers[] = { + { + .supply = "dcdc4", + } +}; + +#if 0 +static struct regulator_consumer_supply epe1_consumers[] = { + { + .supply = "epe1", + } +}; + +static struct regulator_consumer_supply epe2_consumers[] = { + { + .supply = "epe2", + } +}; +#endif + +static struct regulator_consumer_supply ldo1_consumers[] = { + { + .supply = "ldo1", + } +}; + +static struct regulator_consumer_supply ldo2_consumers[] = { + { + .supply = "ldo2", + } +}; + +static struct regulator_consumer_supply ldo3_consumers[] = { + { + .supply = "ldo3", + } +}; + +static struct regulator_consumer_supply ldo4_consumers[] = { + { + .supply = "ldo4", + } +}; + +static struct regulator_consumer_supply ldo5_consumers[] = { + { + .supply = "ldo5", + } +}; + +static struct regulator_consumer_supply ldo6_consumers[] = { + { + .supply = "ldo6", + } +}; + +static struct regulator_consumer_supply ldo7_consumers[] = { + { + .supply = "ldo7", + } +}; + +static struct regulator_consumer_supply ldo8_consumers[] = { + { + .supply = "ldo8", + } +}; + +static struct regulator_consumer_supply ldo9_consumers[] = { + { + .supply = "ldo9", + } +}; + +static struct regulator_consumer_supply ldo10_consumers[] = { + { + .supply = "ldo10", + } +}; + +static struct regulator_consumer_supply ldo11_consumers[] = { + { + .supply = "ldo11", + } +}; + +struct regulator_init_data wm831x_regulator_init_dcdc[WM831X_MAX_DCDC] = { + { + .constraints = { + .name = "DCDC1", + .min_uV = 600000, + .max_uV = 1800000, //0.6-1.8V + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(dcdc1_consumers), + .consumer_supplies = dcdc1_consumers, + }, + { + .constraints = { + .name = "DCDC2", + .min_uV = 600000, + .max_uV = 1800000, //0.6-1.8V + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(dcdc2_consumers), + .consumer_supplies = dcdc2_consumers, + }, + { + .constraints = { + .name = "DCDC3", + .min_uV = 850000, + .max_uV = 3400000, //0.85-3.4V + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(dcdc3_consumers), + .consumer_supplies = dcdc3_consumers, + }, + { + .constraints = { + .name = "DCDC4", + .min_uV = 850000, + .max_uV = 3400000, //0.85-3.4V + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(dcdc4_consumers), + .consumer_supplies = dcdc4_consumers, + }, +}; + +#if 0 +struct regulator_init_data wm831x_regulator_init_epe[WM831X_MAX_EPE] = { + { + .constraints = { + .name = "EPE1", + .min_uV = 1200000, + .max_uV = 3000000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(epe1_consumers), + .consumer_supplies = epe1_consumers, + }, + { + .constraints = { + .name = "EPE2", + .min_uV = 1200000, + .max_uV = 3000000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(epe2_consumers), + .consumer_supplies = epe2_consumers, + }, +}; +#endif + +struct regulator_init_data wm831x_regulator_init_ldo[WM831X_MAX_LDO] = { + { + .constraints = { + .name = "LDO1", + .min_uV = 900000, + .max_uV = 3300000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo1_consumers), + .consumer_supplies = ldo1_consumers, + }, + { + .constraints = { + .name = "LDO2", + .min_uV = 900000, + .max_uV = 3300000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo2_consumers), + .consumer_supplies = ldo2_consumers, + }, + { + .constraints = { + .name = "LDO3", + .min_uV = 900000, + .max_uV = 3300000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo3_consumers), + .consumer_supplies = ldo3_consumers, + }, + { + .constraints = { + .name = "LDO4", + .min_uV = 900000, + .max_uV = 3300000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo4_consumers), + .consumer_supplies = ldo4_consumers, + }, + { + .constraints = { + .name = "LDO5", + .min_uV = 900000, + .max_uV = 3300000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo5_consumers), + .consumer_supplies = ldo5_consumers, + }, + { + .constraints = { + .name = "LDO6", + .min_uV = 900000, + .max_uV = 3300000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo6_consumers), + .consumer_supplies = ldo6_consumers, + }, + { + .constraints = { + .name = "LDO7", + .min_uV = 1000000, + .max_uV = 3500000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo7_consumers), + .consumer_supplies = ldo7_consumers, + }, + { + .constraints = { + .name = "LDO8", + .min_uV = 1000000, + .max_uV = 3500000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo8_consumers), + .consumer_supplies = ldo8_consumers, + }, + { + .constraints = { + .name = "LDO9", + .min_uV = 1000000, + .max_uV = 3500000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo9_consumers), + .consumer_supplies = ldo9_consumers, + }, + { + .constraints = { + .name = "LDO10", + .min_uV = 1000000, + .max_uV = 3500000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo10_consumers), + .consumer_supplies = ldo10_consumers, + }, + { + .constraints = { + .name = "LDO11", + .min_uV = 800000, + .max_uV = 1550000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo11_consumers), + .consumer_supplies = ldo11_consumers, + }, +}; + +static int wm831x_init_pin_type(struct wm831x *wm831x) +{ + struct wm831x_pdata *pdata; + struct rk29_gpio_expander_info *wm831x_gpio_settinginfo; + uint16_t wm831x_settingpin_num; + int i; + + if (!wm831x || !wm831x->dev) + goto out; + + pdata = wm831x->dev->platform_data; + if (!pdata) + goto out; + + wm831x_gpio_settinginfo = pdata->settinginfo; + if (!wm831x_gpio_settinginfo) + goto out; + + wm831x_settingpin_num = pdata->settinginfolen; + for (i = 0; i < wm831x_settingpin_num; i++) { + if (wm831x_gpio_settinginfo[i].pin_type == GPIO_IN) { + wm831x_set_bits(wm831x, + WM831X_GPIO1_CONTROL + i, + WM831X_GPN_DIR_MASK | WM831X_GPN_TRI_MASK, + 1 << WM831X_GPN_DIR_SHIFT | 1 << WM831X_GPN_TRI_SHIFT); + if (i == 1) { + wm831x_set_bits(wm831x, + WM831X_GPIO1_CONTROL + i, + WM831X_GPN_POL_MASK, + 0x0400); + wm831x_set_bits(wm831x, + WM831X_GPIO1_CONTROL + i, + WM831X_GPN_FN_MASK, + 0x0003); + } // set gpio2 sleep/wakeup + + if (i == 9) { + wm831x_set_bits(wm831x, + WM831X_GPIO1_CONTROL + i, + WM831X_GPN_PULL_MASK, + 0x0000); //disable pullup/down + wm831x_set_bits(wm831x, + WM831X_GPIO1_CONTROL + i, + WM831X_GPN_PWR_DOM_MASK, + 0x0800); + wm831x_set_bits(wm831x, + WM831X_GPIO1_CONTROL + i, + WM831X_GPN_ENA_MASK, + 0x0000); + } //set gpio10 as adc input + + } else { + wm831x_set_bits(wm831x, + WM831X_GPIO1_CONTROL + i, + WM831X_GPN_DIR_MASK | WM831X_GPN_TRI_MASK, + 1 << WM831X_GPN_TRI_SHIFT); + if (wm831x_gpio_settinginfo[i].pin_value == GPIO_HIGH) { + wm831x_set_bits(wm831x, WM831X_GPIO_LEVEL, 1 << i, 1 << i); + } else { + wm831x_set_bits(wm831x, WM831X_GPIO_LEVEL, 1 << i, 0 << i); + } + if (i == 2) { + wm831x_set_bits(wm831x, + WM831X_GPIO1_CONTROL + i, + WM831X_GPN_PWR_DOM_MASK | WM831X_GPN_POL_MASK |WM831X_GPN_FN_MASK, + 1 << WM831X_GPN_POL_SHIFT | 1 << WM831X_GPN_PWR_DOM_SHIFT | 1 << 0); + + } // set gpio3 as clkout output 32.768K + + } + } + +#if 0 + for (i = 0; i < pdata->gpio_pin_num; i++) { + wm831x_set_bits(wm831x, + WM831X_GPIO1_CONTROL + i, + WM831X_GPN_PULL_MASK | WM831X_GPN_POL_MASK | WM831X_GPN_OD_MASK | WM831X_GPN_TRI_MASK, + 1 << WM831X_GPN_POL_SHIFT | 1 << WM831X_GPN_TRI_SHIFT); + + ret = wm831x_reg_read(wm831x, WM831X_GPIO1_CONTROL + i); + printk("Gpio%d Pin Configuration = %x\n", i, ret); + } +#endif + +out: + return 0; +} + +void __sramfunc board_pmu_suspend(void) +{ + cru_writel(CRU_CLKGATE5_GRFCLK_ON,CRU_CLKGATE5_CON_ADDR); //open grf clk + grf_writel(GPIO6_PB1_DIR_OUT, GRF_GPIO6L_DIR_ADDR); + grf_writel(GPIO6_PB1_DO_HIGH, GRF_GPIO6L_DO_ADDR); //set gpio6_b1 output low + grf_writel(GPIO6_PB1_EN_MASK, GRF_GPIO6L_EN_ADDR); +} +void __sramfunc board_pmu_resume(void) +{ + grf_writel(GPIO6_PB1_DIR_OUT, GRF_GPIO6L_DIR_ADDR); + grf_writel(GPIO6_PB1_DO_LOW, GRF_GPIO6L_DO_ADDR); //set gpio6_b1 output high + grf_writel(GPIO6_PB1_EN_MASK, GRF_GPIO6L_EN_ADDR); +#ifdef CONFIG_CLK_SWITCH_TO_32K + sram_32k_udelay(10000); +#else + sram_udelay(10000); +#endif +} +static struct wm831x_pdata wm831x_platdata = { + + /** Called before subdevices are set up */ + .pre_init = wm831x_pre_init, + /** Called after subdevices are set up */ + .post_init = wm831x_post_init, + /** Called before subdevices are power down */ + .last_deinit = wm831x_last_deinit, + +#if defined(CONFIG_GPIO_WM831X) + .gpio_base = WM831X_GPIO_EXPANDER_BASE, + .gpio_pin_num = WM831X_TOTOL_GPIO_NUM, + .settinginfo = wm831x_gpio_settinginfo, + .settinginfolen = ARRAY_SIZE(wm831x_gpio_settinginfo), + .pin_type_init = wm831x_init_pin_type, + .irq_base = NR_GIC_IRQS + NR_GPIO_IRQS, +#endif + + /** LED1 = 0 and so on */ + .status = { &wm831x_status_platdata[0], &wm831x_status_platdata[1] }, + + /** DCDC1 = 0 and so on */ + .dcdc = { + &wm831x_regulator_init_dcdc[0], + &wm831x_regulator_init_dcdc[1], + &wm831x_regulator_init_dcdc[2], + &wm831x_regulator_init_dcdc[3], + }, + + /** EPE1 = 0 and so on */ + //.epe = { &wm831x_regulator_init_epe[0], &wm831x_regulator_init_epe[1] }, + + /** LDO1 = 0 and so on */ + .ldo = { + &wm831x_regulator_init_ldo[0], + &wm831x_regulator_init_ldo[1], + &wm831x_regulator_init_ldo[2], + &wm831x_regulator_init_ldo[3], + &wm831x_regulator_init_ldo[4], + &wm831x_regulator_init_ldo[5], + &wm831x_regulator_init_ldo[6], + &wm831x_regulator_init_ldo[7], + &wm831x_regulator_init_ldo[8], + &wm831x_regulator_init_ldo[9], + &wm831x_regulator_init_ldo[10], + }, +}; +#endif diff --git a/arch/arm/mach-rk30/board-rk30-ds1001b.c b/arch/arm/mach-rk30/board-rk30-ds1001b.c index 937cfbf3b13e..0b814178d6c5 100644 --- a/arch/arm/mach-rk30/board-rk30-ds1001b.c +++ b/arch/arm/mach-rk30/board-rk30-ds1001b.c @@ -1326,7 +1326,7 @@ static struct i2c_board_info __initdata i2c0_info[] = { #endif #ifdef CONFIG_I2C1_RK30 -#include "board-rk30-sdk-wm8326.c" +#include "board-rk30-ds1001b-wm8326.c" static struct i2c_board_info __initdata i2c1_info[] = { #if defined (CONFIG_MFD_WM831X_I2C) From 488d9051d16765559e62a5b89f766e343c37e1bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=8B=E7=A7=80=E6=9D=B0?= Date: Mon, 6 Aug 2012 13:09:03 +0800 Subject: [PATCH 086/261] phonepad: rt3261 add version information, first is RT3261_V1.0.0. --- sound/soc/codecs/rt3261.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt3261.c b/sound/soc/codecs/rt3261.c index 4caff8e702c9..aedd746de2fb 100644 --- a/sound/soc/codecs/rt3261.c +++ b/sound/soc/codecs/rt3261.c @@ -60,7 +60,7 @@ static struct snd_soc_codec *rt3261_codec; #define RT3261_REG_RW 1 /* for debug */ #define RT3261_DET_EXT_MIC 0 -#define VERSION "0.3.0 alsa 1.0.24" +#define VERSION "RT3261_V1.0.0" struct rt3261_init_reg { u8 reg; From 0f93e2344c6c7b1c91880645be2035fa2bb4d625 Mon Sep 17 00:00:00 2001 From: chenxing Date: Mon, 6 Aug 2012 14:51:32 +0800 Subject: [PATCH 087/261] rk2928:sdk: add clock support --- arch/arm/mach-rk2928/Makefile | 2 + arch/arm/mach-rk2928/board-rk2928-sdk.c | 73 +- arch/arm/mach-rk2928/clock.c | 754 +++++++ arch/arm/mach-rk2928/clock.h | 99 + arch/arm/mach-rk2928/clock_data.c | 2444 +++++++++++++++++++++ arch/arm/mach-rk2928/include/mach/board.h | 30 + arch/arm/mach-rk2928/include/mach/clock.h | 81 + arch/arm/mach-rk2928/include/mach/cru.h | 563 +++++ 8 files changed, 3974 insertions(+), 72 deletions(-) create mode 100755 arch/arm/mach-rk2928/clock.c create mode 100644 arch/arm/mach-rk2928/clock.h create mode 100644 arch/arm/mach-rk2928/clock_data.c create mode 100755 arch/arm/mach-rk2928/include/mach/clock.h create mode 100755 arch/arm/mach-rk2928/include/mach/cru.h diff --git a/arch/arm/mach-rk2928/Makefile b/arch/arm/mach-rk2928/Makefile index a9df193cfc0a..68053947e830 100644 --- a/arch/arm/mach-rk2928/Makefile +++ b/arch/arm/mach-rk2928/Makefile @@ -4,6 +4,8 @@ obj-y += reset.o obj-y += timer.o obj-y += devices.o obj-y += iomux.o +obj-y += clock.o +obj-y += clock_data.o obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_MACH_RK2928_FPGA) += board-rk2928-fpga.o board-rk2928-fpga-key.o diff --git a/arch/arm/mach-rk2928/board-rk2928-sdk.c b/arch/arm/mach-rk2928/board-rk2928-sdk.c index b01d4d92868b..2a433f41c3e8 100755 --- a/arch/arm/mach-rk2928/board-rk2928-sdk.c +++ b/arch/arm/mach-rk2928/board-rk2928-sdk.c @@ -1189,81 +1189,10 @@ static void __init rk2928_reserve(void) board_mem_reserved(); } -#if 1 -#include - -struct clk { - const char *name; - unsigned long rate; -}; - -static struct clk xin24m = { - .name = "xin24m", - .rate = 24000000, -}; - -#define CLK(dev, con, ck) \ - { \ - .dev_id = dev, \ - .con_id = con, \ - .clk = ck, \ - } - -static struct clk_lookup clks[] = { - CLK("rk30_i2c.0", "i2c", &xin24m), - CLK("rk30_i2c.1", "i2c", &xin24m), - CLK("rk30_i2c.2", "i2c", &xin24m), - CLK("rk30_i2c.3", "i2c", &xin24m), - CLK("rk29xx_spim.0", "spi", &xin24m), - CLK("rk29xx_spim.1", "spi", &xin24m), - - CLK("rk_serial.0", "uart_div", &xin24m), - CLK("rk_serial.0", "uart_frac_div", &xin24m), - CLK("rk_serial.0", "uart", &xin24m), - CLK("rk_serial.0", "pclk_uart", &xin24m), - CLK("rk_serial.1", "uart_div", &xin24m), - CLK("rk_serial.1", "uart_frac_div", &xin24m), - CLK("rk_serial.1", "uart", &xin24m), - CLK("rk_serial.1", "pclk_uart", &xin24m), - CLK("rk_serial.2", "uart_div", &xin24m), - CLK("rk_serial.2", "uart_frac_div", &xin24m), - CLK("rk_serial.2", "uart", &xin24m), - CLK("rk_serial.2", "pclk_uart", &xin24m), - - CLK("rk29_i2s.0", "i2s_div", &xin24m), - CLK("rk29_i2s.0", "i2s_frac_div", &xin24m), - CLK("rk29_i2s.0", "i2s", &xin24m), - CLK("rk29_i2s.0", "hclk_i2s", &xin24m), - CLK(NULL, "pd_lcdc0", &xin24m), - CLK(NULL, "hclk_lcdc0", &xin24m), - CLK(NULL, "aclk_lcdc0", &xin24m), - CLK(NULL, "dclk_lcdc0", &xin24m), - - CLK(NULL, "pd_cif0", &xin24m), - CLK(NULL, "aclk_cif0", &xin24m), - CLK(NULL, "hclk_cif0", &xin24m), - CLK(NULL, "cif0_in", &xin24m), - CLK(NULL, "cif0_out", &xin24m), -}; - -void __init rk30_clock_init(void) -{ - struct clk_lookup *lk; - - for (lk = clks; lk < clks + ARRAY_SIZE(clks); lk++) { - clkdev_add(lk); - } -} - void __init board_clock_init(void) { - rk30_clock_init(); + rk2928_clock_data_init(periph_pll_default, codec_pll_default, RK30_CLOCKS_DEFAULT_FLAGS); } -#else -void __init board_clock_init(void) -{ -} -#endif MACHINE_START(RK2928, "RK2928board") diff --git a/arch/arm/mach-rk2928/clock.c b/arch/arm/mach-rk2928/clock.c new file mode 100755 index 000000000000..02530f220ad0 --- /dev/null +++ b/arch/arm/mach-rk2928/clock.c @@ -0,0 +1,754 @@ +/* linux/arch/arm/mach-rk30/clock.c + * + * Copyright (C) 2012 ROCKCHIP, Inc. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "clock.h" +//#include +#include + +#define CLOCK_PRINTK_DBG(fmt, args...) pr_debug(fmt, ## args); +#define CLOCK_PRINTK_ERR(fmt, args...) pr_err(fmt, ## args); +#define CLOCK_PRINTK_LOG(fmt, args...) pr_debug(fmt, ## args); + +/* Clock flags */ +/* bit 0 is free */ +#define RATE_FIXED (1 << 1) /* Fixed clock rate */ +#define CONFIG_PARTICIPANT (1 << 10) /* Fundamental clock */ + +#define MHZ (1000*1000) +#define KHZ (1000) + +static void __clk_recalc(struct clk *clk); +static void __propagate_rate(struct clk *tclk); +static void __clk_reparent(struct clk *child, struct clk *parent); + +static LIST_HEAD(clocks); +static DEFINE_MUTEX(clocks_mutex); +static DEFINE_SPINLOCK(clockfw_lock); +static LIST_HEAD(root_clks); +static void clk_notify(struct clk *clk, unsigned long msg, + unsigned long old_rate, unsigned long new_rate); + +#define LOCK() do { WARN_ON(in_irq()); if (!irqs_disabled()) spin_lock_bh(&clockfw_lock); } while (0) +#define UNLOCK() do { if (!irqs_disabled()) spin_unlock_bh(&clockfw_lock); } while (0) +/**********************************************for clock data****************************************************/ +static struct clk *def_ops_clk=NULL; + +void clk_register_default_ops_clk(struct clk *clk) +{ + def_ops_clk=clk; +} + +static struct clk *clk_default_get_parent(struct clk *clk) +{ + if(def_ops_clk&&def_ops_clk->get_parent) + return def_ops_clk->get_parent(clk); + else return NULL; + + + +} +static int clk_default_set_parent(struct clk *clk, struct clk *parent) +{ + if(def_ops_clk&&def_ops_clk->set_parent) + return def_ops_clk->set_parent(clk,parent); + else + return -EINVAL; +} + +int __init clk_disable_unused(void) +{ + struct clk *ck; + list_for_each_entry(ck, &clocks, node) { + if (ck->usecount > 0 || ck->mode == NULL || (ck->flags & IS_PD)) + continue; + LOCK(); + clk_enable_nolock(ck); + clk_disable_nolock(ck); + UNLOCK(); + } + return 0; +} +/** + * recalculate_root_clocks - recalculate and propagate all root clocks + * + * Recalculates all root clocks (clocks with no parent), which if the + * clock's .recalc is set correctly, should also propagate their rates. + * Called at init. + */ +void clk_recalculate_root_clocks_nolock(void) +{ + struct clk *clkp; + + list_for_each_entry(clkp, &root_clks, sibling) { + __clk_recalc(clkp); + __propagate_rate(clkp); + } +} +/* +void clk_recalculate_root_clocks(void) +{ + LOCK(); + clk_recalculate_root_clocks_nolock(); + UNLOCK(); +}*/ + +/** + * clk_preinit - initialize any fields in the struct clk before clk init + * @clk: struct clk * to initialize + * + * Initialize any struct clk fields needed before normal clk initialization + * can run. No return value. + */ +int clk_register(struct clk *clk) +{ + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + //INIT_LIST_HEAD(&clk->sibling); + INIT_LIST_HEAD(&clk->children); + /* + * trap out already registered clocks + */ + if (clk->node.next || clk->node.prev) + return 0; + + mutex_lock(&clocks_mutex); + if (clk->get_parent) + clk->parent = clk->get_parent(clk); + else if (clk->parents) + clk->parent =clk_default_get_parent(clk); + + if (clk->parent){ + printk("clk has parent\n"); + list_add(&clk->sibling, &clk->parent->children); + } + else{ + printk("clk has no parent\n"); + list_add(&clk->sibling, &root_clks); + } + list_add(&clk->node, &clocks); + mutex_unlock(&clocks_mutex); + return 0; +} + +/************************************************************/ +static void __clk_recalc(struct clk *clk) +{ + if (unlikely(clk->flags & RATE_FIXED)) + return; + if (clk->recalc) + clk->rate = clk->recalc(clk); + else if (clk->parent) + clk->rate = clk->parent->rate; +} +static void __clk_reparent(struct clk *child, struct clk *parent) +{ + if (child->parent == parent) + return; + //CLOCK_PRINTK_DBG("%s reparent to %s (was %s)\n", child->name, parent->name, ((child->parent) ? child->parent->name : "NULL")); + + list_del_init(&child->sibling); + if (parent) + list_add(&child->sibling, &parent->children); + child->parent = parent; +} + +/* Propagate rate to children */ +static void __propagate_rate(struct clk *tclk) +{ + struct clk *clkp; + + //CLOCK_PRINTK_DBG("propagate_rate clk %s\n",clkp->name); + + list_for_each_entry(clkp, &tclk->children, sibling) { + __clk_recalc(clkp); + __propagate_rate(clkp); + } + //CLOCK_PRINTK_DBG("propagate_rate clk %s end\n",clkp->name); +} + +int clk_enable_nolock(struct clk *clk) +{ + int ret = 0; + + if (clk->usecount == 0) { + if (clk->parent) { + ret = clk_enable_nolock(clk->parent); + if (ret) + return ret; + } + + if (clk->notifier_count) + clk_notify(clk, CLK_PRE_ENABLE, clk->rate, clk->rate); + if (clk->mode) + ret = clk->mode(clk, 1); + if (clk->notifier_count) + clk_notify(clk, ret ? CLK_ABORT_ENABLE : CLK_POST_ENABLE, clk->rate, clk->rate); + if (ret) { + if (clk->parent) + clk_disable_nolock(clk->parent); + return ret; + } + //pr_debug("%s enabled\n", clk->name); + printk("%s enabled\n", clk->name); + } + clk->usecount++; + + return ret; +} + +void clk_disable_nolock(struct clk *clk) +{ + if (clk->usecount == 0) { + CLOCK_PRINTK_ERR(KERN_ERR "Trying disable clock %s with 0 usecount\n", clk->name); + WARN_ON(1); + return; + } + if (--clk->usecount == 0) { + int ret = 0; + if (clk->notifier_count) + clk_notify(clk, CLK_PRE_DISABLE, clk->rate, clk->rate); + if (clk->mode) + ret = clk->mode(clk, 0); + if (clk->notifier_count) + clk_notify(clk, ret ? CLK_ABORT_DISABLE : CLK_POST_DISABLE, clk->rate, clk->rate); + pr_debug("%s disabled\n", clk->name); + if (ret == 0 && clk->parent) + clk_disable_nolock(clk->parent); + } +} +/* Given a clock and a rate apply a clock specific rounding function */ +long clk_round_rate_nolock(struct clk *clk, unsigned long rate) +{ + if (clk->round_rate) + return clk->round_rate(clk, rate); + + if (clk->flags & RATE_FIXED) + CLOCK_PRINTK_ERR("clock: clk_round_rate called on fixed-rate clock %s\n", clk->name); + + return clk->rate; +} +int is_suport_round_rate(struct clk *clk) +{ + return (clk->round_rate) ? 0:(-1); +} + +int clk_set_rate_nolock(struct clk *clk, unsigned long rate) +{ + int ret; + unsigned long old_rate; + + if (rate == clk->rate) + return 0; + if (clk->flags & CONFIG_PARTICIPANT) + return -EINVAL; + + if (!clk->set_rate) + return -EINVAL; + + printk("**will set %s rate %lu\n", clk->name, rate); + + old_rate = clk->rate; + if (clk->notifier_count) + clk_notify(clk, CLK_PRE_RATE_CHANGE, old_rate, rate); + + ret = clk->set_rate(clk, rate); + + if (ret == 0) { + __clk_recalc(clk); + printk("**set %s rate recalc=%lu\n",clk->name,clk->rate); + __propagate_rate(clk); + } + + if (clk->notifier_count) + clk_notify(clk, ret ? CLK_ABORT_RATE_CHANGE : CLK_POST_RATE_CHANGE, old_rate, clk->rate); + + return ret; +} + +int clk_set_parent_nolock(struct clk *clk, struct clk *parent) +{ + int ret; + int enabled = clk->usecount > 0; + struct clk *old_parent = clk->parent; + + if (clk->parent == parent) + return 0; + + /* if clk is already enabled, enable new parent first and disable old parent later. */ + if (enabled) + clk_enable_nolock(parent); + + if (clk->set_parent) + ret = clk->set_parent(clk, parent); + else + ret = clk_default_set_parent(clk,parent); + + if (ret == 0) { + /* OK */ + + //CLOCK_PRINTK_DBG("set_parent %s reparent\n",clk->name,parent->name); + __clk_reparent(clk, parent); + __clk_recalc(clk); + __propagate_rate(clk); + if (enabled) + clk_disable_nolock(old_parent); + } else { + //CLOCK_PRINTK_DBG("set_parent err\n",clk->name,parent->name); + if (enabled) + clk_disable_nolock(parent); + } + + return ret; +} +/**********************************dvfs****************************************************/ +#if 0 +struct clk_node *clk_get_dvfs_info(struct clk *clk) +{ + return clk->dvfs_info; +} + +int clk_set_rate_locked(struct clk * clk,unsigned long rate) +{ + int ret; + //CLOCK_PRINTK_DBG("%s dvfs clk_set_locked\n",clk->name); + LOCK(); + ret=clk_set_rate_nolock(clk, rate);; + UNLOCK(); + return ret; + +} +void clk_register_dvfs(struct clk_node *dvfs_clk, struct clk *clk) +{ + clk->dvfs_info = dvfs_clk; +} +#endif + +/*------------------------------------------------------------------------- + * Optional clock functions defined in include/linux/clk.h + *-------------------------------------------------------------------------*/ +#ifdef RK30_CLK_OFFBOARD_TEST +long rk30_clk_round_rate(struct clk *clk, unsigned long rate) +#else +long clk_round_rate(struct clk *clk, unsigned long rate) +#endif +{ + long ret = 0; + + if (clk == NULL || IS_ERR(clk)) + return ret; + + LOCK(); + ret = clk_round_rate_nolock(clk, rate); + UNLOCK(); + + return ret; +} + +#ifdef RK30_CLK_OFFBOARD_TEST +EXPORT_SYMBOL(rk30_clk_round_rate); +#else +EXPORT_SYMBOL(clk_round_rate); +#endif + +#ifdef RK30_CLK_OFFBOARD_TEST +unsigned long rk30_clk_get_rate(struct clk *clk) +#else +unsigned long clk_get_rate(struct clk *clk) +#endif +{ + if (clk == NULL || IS_ERR(clk)) + return 0; + + return clk->rate; +} +#ifdef RK30_CLK_OFFBOARD_TEST +EXPORT_SYMBOL(rk30_clk_get_rate); +#else +EXPORT_SYMBOL(clk_get_rate); +#endif + + +/* Set the clock rate for a clock source */ +#ifdef RK30_CLK_OFFBOARD_TEST +int rk30_clk_set_rate(struct clk *clk, unsigned long rate) +#else +int clk_set_rate(struct clk *clk, unsigned long rate) +#endif +{ + int ret = -EINVAL; + if (clk == NULL || IS_ERR(clk)){ + return ret; + } + if (rate == clk->rate) + return 0; +#if 0 + if (clk->dvfs_info!=NULL&&is_support_dvfs(clk->dvfs_info)) + return dvfs_set_rate(clk, rate); +#endif + LOCK(); + ret = clk_set_rate_nolock(clk, rate); + UNLOCK(); + + return ret; +} +#ifdef RK30_CLK_OFFBOARD_TEST +EXPORT_SYMBOL(rk30_clk_set_rate); +#else +EXPORT_SYMBOL(clk_set_rate); +#endif + + +#ifdef RK30_CLK_OFFBOARD_TEST +int rk30_clk_set_parent(struct clk *clk, struct clk *parent) +#else +int clk_set_parent(struct clk *clk, struct clk *parent) +#endif +{ + int ret = -EINVAL; + + if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent)) + return ret; + + if (clk->set_parent==NULL||clk->parents == NULL) + return ret; + + LOCK(); + if (clk->usecount == 0) + ret = clk_set_parent_nolock(clk, parent); + else + ret = -EBUSY; + UNLOCK(); + + return ret; +} +int clk_set_parent_force(struct clk *clk, struct clk *parent) +{ + int ret = -EINVAL; + + if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent)) + return ret; + + if (clk->set_parent==NULL||clk->parents == NULL) + return ret; + LOCK(); + ret = clk_set_parent_nolock(clk, parent); + UNLOCK(); + return ret; +} + +#ifdef RK30_CLK_OFFBOARD_TEST +EXPORT_SYMBOL(rk30_clk_set_parent); +#else +EXPORT_SYMBOL(clk_set_parent); +#endif + +#ifdef RK30_CLK_OFFBOARD_TEST +struct clk *rk30_clk_get_parent(struct clk *clk) +#else +struct clk *clk_get_parent(struct clk *clk) +#endif +{ + if (clk == NULL || IS_ERR(clk)) { + return ERR_PTR(-EINVAL); + } + return clk->parent; +} + +#ifdef RK30_CLK_OFFBOARD_TEST +EXPORT_SYMBOL(rk30_clk_get_parent); +#else +EXPORT_SYMBOL(clk_get_parent); +#endif + +#ifdef RK30_CLK_OFFBOARD_TEST +void rk30_clk_disable(struct clk *clk) +#else +void clk_disable(struct clk *clk) +#endif +{ + if (clk == NULL || IS_ERR(clk)) + return; + + LOCK(); + clk_disable_nolock(clk); + UNLOCK(); +} +#ifdef RK30_CLK_OFFBOARD_TEST +EXPORT_SYMBOL(rk30_clk_disable); +#else +EXPORT_SYMBOL(clk_disable); +#endif + +#ifdef RK30_CLK_OFFBOARD_TEST +int rk30_clk_enable(struct clk *clk) +#else +int clk_enable(struct clk *clk) +#endif +{ + int ret = 0; + + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + + LOCK(); + ret = clk_enable_nolock(clk); + UNLOCK(); + + return ret; +} +#ifdef RK30_CLK_OFFBOARD_TEST +EXPORT_SYMBOL(rk30_clk_enable); +#else +EXPORT_SYMBOL(clk_enable); +#endif + +/* Clk notifier implementation */ + +/** + * struct clk_notifier - associate a clk with a notifier + * @clk: struct clk * to associate the notifier with + * @notifier_head: a raw_notifier_head for this clk + * @node: linked list pointers + * + * A list of struct clk_notifier is maintained by the notifier code. + * An entry is created whenever code registers the first notifier on a + * particular @clk. Future notifiers on that @clk are added to the + * @notifier_head. + */ +struct clk_notifier { + struct clk *clk; + struct raw_notifier_head notifier_head; + struct list_head node; +}; +static LIST_HEAD(clk_notifier_list); +/** + * _clk_free_notifier_chain - safely remove struct clk_notifier + * @cn: struct clk_notifier * + * + * Removes the struct clk_notifier @cn from the clk_notifier_list and + * frees it. + */ +static void _clk_free_notifier_chain(struct clk_notifier *cn) +{ + list_del(&cn->node); + kfree(cn); +} + +/** + * clk_notify - call clk notifier chain + * @clk: struct clk * that is changing rate + * @msg: clk notifier type (i.e., CLK_POST_RATE_CHANGE; see mach/clock.h) + * @old_rate: old rate + * @new_rate: new rate + * + * Triggers a notifier call chain on the post-clk-rate-change notifier + * for clock 'clk'. Passes a pointer to the struct clk and the + * previous and current rates to the notifier callback. Intended to be + * called by internal clock code only. No return value. + */ +static void clk_notify(struct clk *clk, unsigned long msg, + unsigned long old_rate, unsigned long new_rate) +{ + struct clk_notifier *cn; + struct clk_notifier_data cnd; + + cnd.clk = clk; + cnd.old_rate = old_rate; + cnd.new_rate = new_rate; + + UNLOCK(); + list_for_each_entry(cn, &clk_notifier_list, node) { + if (cn->clk == clk) { + pr_debug("%s msg %lu rate %lu -> %lu\n", clk->name, msg, old_rate, new_rate); + raw_notifier_call_chain(&cn->notifier_head, msg, &cnd); + break; + } + } + LOCK(); +} + +/** + * clk_notifier_register - add a clock parameter change notifier + * @clk: struct clk * to watch + * @nb: struct notifier_block * with callback info + * + * Request notification for changes to the clock 'clk'. This uses a + * blocking notifier. Callback code must not call into the clock + * framework, as clocks_mutex is held. Pre-notifier callbacks will be + * passed the previous and new rate of the clock. + * + * clk_notifier_register() must be called from process + * context. Returns -EINVAL if called with null arguments, -ENOMEM + * upon allocation failure; otherwise, passes along the return value + * of blocking_notifier_chain_register(). + */ +int rk30_clk_notifier_register(struct clk *clk, struct notifier_block *nb) +{ + struct clk_notifier *cn = NULL, *cn_new = NULL; + int r; + struct clk *clkp; + + if (!clk || IS_ERR(clk) || !nb) + return -EINVAL; + + mutex_lock(&clocks_mutex); + + list_for_each_entry(cn, &clk_notifier_list, node) + if (cn->clk == clk) + break; + + if (cn->clk != clk) { + cn_new = kzalloc(sizeof(struct clk_notifier), GFP_KERNEL); + if (!cn_new) { + r = -ENOMEM; + goto cnr_out; + }; + + cn_new->clk = clk; + RAW_INIT_NOTIFIER_HEAD(&cn_new->notifier_head); + + list_add(&cn_new->node, &clk_notifier_list); + cn = cn_new; + } + + r = raw_notifier_chain_register(&cn->notifier_head, nb); + if (!IS_ERR_VALUE(r)) { + clkp = clk; + do { + clkp->notifier_count++; + } while ((clkp = clkp->parent)); + } else { + if (cn_new) + _clk_free_notifier_chain(cn); + } + +cnr_out: + mutex_unlock(&clocks_mutex); + + return r; +} +EXPORT_SYMBOL(rk30_clk_notifier_register); + +/** + * clk_notifier_unregister - remove a clock change notifier + * @clk: struct clk * + * @nb: struct notifier_block * with callback info + * + * Request no further notification for changes to clock 'clk'. + * Returns -EINVAL if called with null arguments; otherwise, passes + * along the return value of blocking_notifier_chain_unregister(). + */ +int rk30_clk_notifier_unregister(struct clk *clk, struct notifier_block *nb) +{ + struct clk_notifier *cn = NULL; + struct clk *clkp; + int r = -EINVAL; + + if (!clk || IS_ERR(clk) || !nb) + return -EINVAL; + + mutex_lock(&clocks_mutex); + + list_for_each_entry(cn, &clk_notifier_list, node) + if (cn->clk == clk) + break; + + if (cn->clk != clk) { + r = -ENOENT; + goto cnu_out; + }; + + r = raw_notifier_chain_unregister(&cn->notifier_head, nb); + if (!IS_ERR_VALUE(r)) { + clkp = clk; + do { + clkp->notifier_count--; + } while ((clkp = clkp->parent)); + } + + /* + * XXX ugh, layering violation. There should be some + * support in the notifier code for this. + */ + if (!cn->notifier_head.head) + _clk_free_notifier_chain(cn); + +cnu_out: + mutex_unlock(&clocks_mutex); + + return r; +} +EXPORT_SYMBOL(rk30_clk_notifier_unregister); + +static struct clk_dump_ops *dump_def_ops; + +void clk_register_dump_ops(struct clk_dump_ops *ops) +{ + dump_def_ops=ops; +} + +static int proc_clk_show(struct seq_file *s, void *v) +{ + struct clk* clk; + + if(!dump_def_ops) + return 0; + + if(dump_def_ops->dump_clk) + { + mutex_lock(&clocks_mutex); + list_for_each_entry(clk, &clocks, node) { + if (!clk->parent) + { + dump_def_ops->dump_clk(s, clk, 0,&clocks); + } + } + mutex_unlock(&clocks_mutex); + } + if(dump_def_ops->dump_regs) + dump_def_ops->dump_regs(s); + return 0; +} + + +static int proc_clk_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_clk_show, NULL); +} + +static const struct file_operations proc_clk_fops = { + .open = proc_clk_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init clk_proc_init(void) +{ + proc_create("clocks", 0, NULL, &proc_clk_fops); + return 0; + +} +late_initcall(clk_proc_init); + diff --git a/arch/arm/mach-rk2928/clock.h b/arch/arm/mach-rk2928/clock.h new file mode 100644 index 000000000000..5e956f0c0705 --- /dev/null +++ b/arch/arm/mach-rk2928/clock.h @@ -0,0 +1,99 @@ +#ifndef __MACH_CLOCK_H__ +#define __MACH_CLOCK_H__ + +#ifndef CONFIG_ARCH_RK2928 +#define RK30_CLK_OFFBOARD_TEST +#endif + + +/* Clock flags */ +/* bit 0 is free */ +#define RATE_FIXED (1 << 1) /* Fixed clock rate */ +#define CONFIG_PARTICIPANT (1 << 10) /* Fundamental clock */ +#define IS_PD (1 << 2) /* Power Domain */ + +enum _clk_i2s_rate_support { + i2s_8192khz = 8192000, + i2s_11289_6khz = 11289600, + i2s_12288khz = 12288000, + i2s_22579_2khz = 22579200, + i2s_24576khz = 24576000,//HDMI + i2s_49152khz = 24576000,//HDMI +}; + +struct _pll_data{ + u8 id; + void *table; +}; +//struct clk_node; +struct clk { + struct list_head node; + const char *name; + struct clk *parent; + struct list_head children; + struct list_head sibling; /* node for children */ + + int (*mode)(struct clk *clk, int on); + unsigned long (*recalc)(struct clk *); /* if null, follow parent */ + int (*set_rate)(struct clk *, unsigned long); + long (*round_rate)(struct clk *, unsigned long); + struct clk* (*get_parent)(struct clk *); /* get clk's parent from the hardware. default is clksel_get_parent if parents present */ + int (*set_parent)(struct clk *, struct clk *); /* default is clksel_set_parent if parents present */ + + unsigned long rate; + u32 flags; + s16 usecount; + u16 notifier_count; + u8 gate_idx; + struct _pll_data *pll; + u32 clksel_con; + u32 div_mask; + u32 div_shift; + u32 div_max; + u32 src_mask; + u32 src_shift; + + struct clk **parents; + u8 parents_num; + struct clk_node *dvfs_info; + +}; + +int __init clk_disable_unused(void); +void clk_recalculate_root_clocks_nolock(void); +void clk_recalculate_root_clocks(void); +int clk_register(struct clk *clk); +void clk_register_default_ops_clk(struct clk *clk); + +int clk_enable_nolock(struct clk *clk); +void clk_disable_nolock(struct clk *clk); +long clk_round_rate_nolock(struct clk *clk, unsigned long rate); +int clk_set_rate_nolock(struct clk *clk, unsigned long rate); +int clk_set_parent_nolock(struct clk *clk, struct clk *parent); +int clk_set_rate_locked(struct clk * clk,unsigned long rate); +void clk_register_dvfs(struct clk_node *dvfs_clk, struct clk *clk); +struct clk_node *clk_get_dvfs_info(struct clk *clk); +int is_suport_round_rate(struct clk *clk); + +#ifdef RK30_CLK_OFFBOARD_TEST +#include +struct clk *rk30_clk_get(struct device *dev, const char *con_id); +#endif + +#ifdef CONFIG_PROC_FS +#include +#include + +struct clk_dump_ops { + void (*dump_clk)(struct seq_file *s, struct clk *clk, int deep,const struct list_head *root_clocks); + void (*dump_regs)(struct seq_file *s); +}; + +void clk_register_dump_ops(struct clk_dump_ops *ops); +#else +static void clk_register_dump_ops(struct clk_dump_ops *ops){ +} + +#endif + +#endif diff --git a/arch/arm/mach-rk2928/clock_data.c b/arch/arm/mach-rk2928/clock_data.c new file mode 100644 index 000000000000..8225d9d5b009 --- /dev/null +++ b/arch/arm/mach-rk2928/clock_data.c @@ -0,0 +1,2444 @@ +/* arch/arm/mach-rk2928/clock_data.c + * + * Copyright (C) 2012 ROCKCHIP, Inc. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "clock.h" +//#include + +#define MHZ (1000 * 1000) +#define KHZ (1000) +#define CLK_LOOPS_JIFFY_REF 11996091ULL +#define CLK_LOOPS_RATE_REF (1200) //Mhz +#define CLK_LOOPS_RECALC(new_rate) div_u64(CLK_LOOPS_JIFFY_REF*(new_rate),CLK_LOOPS_RATE_REF*MHZ) + + +struct apll_clk_set { + unsigned long rate; + u32 pllcon0; + u32 pllcon1; + u32 pllcon2; //nb=bwadj+1;0:11;nb=nf/2 + u32 clksel0; + u32 clksel1; + u32 rst_dly;//us + unsigned long lpj; //loop per jeffise +}; + +struct pll_clk_set { + unsigned long rate; + u32 pllcon0; + u32 pllcon1; + u32 pllcon2; //nb=bwadj+1;0:11;nb=nf/2 + u32 rst_dly;//us +}; +#if 1 +#define CLKDATA_DBG(fmt, args...) printk("CLOCK_DATA:\t"fmt, ## args) +#define CLKDATA_LOG(fmt, args...) printk("CLOCK_DATA:\t"fmt, ## args) +#else +#define CLKDATA_DBG(fmt, args...) do {} while(0) +#define CLKDATA_LOG(fmt, args...) do {} while(0) +#endif +#define CLKDATA_ERR(fmt, args...) pr_err(fmt, ## args) + +//#define RK2928_TEST_MODE +#ifndef RK2928_TEST_MODE +#define cru_readl(offset) readl_relaxed(RK2928_CRU_BASE + offset) +#define cru_writel(v, offset) do { writel_relaxed(v, RK2928_CRU_BASE + offset); dsb(); } while (0) +#else +u32 TEST_CRU_REGS[500] = {0}; +#define cru_readl(offset) (TEST_CRU_REGS[offset / 4]) +#define cru_writel(v, offset) do { TEST_CRU_REGS[offset / 4] = v; } while (0) +#endif + +#define rk_clock_udelay(a) udelay(a); + +#define PLLS_IN_NORM(pll_id) \ + (((cru_readl(CRU_MODE_CON) & PLL_MODE_MSK(pll_id)) == (PLL_MODE_NORM(pll_id) & PLL_MODE_MSK(pll_id)))\ + && !(cru_readl(PLL_CONS(pll_id, 0)) & PLL_BYPASS)) + +#define get_cru_bits(con, mask, shift)\ + ((cru_readl((con)) >> (shift)) & (mask)) + +#define CRU_DIV_SET(mask, shift, max) \ + .div_mask = (mask),\ +.div_shift = (shift),\ +.div_max = (max) + +#define CRU_SRC_SET(mask, shift ) \ + .src_mask = (mask),\ +.src_shift = (shift) + +#define CRU_PARENTS_SET(parents_array) \ + .parents = (parents_array),\ +.parents_num = ARRAY_SIZE((parents_array)) + +#define get_cru_bits(con,mask,shift)\ + ((cru_readl((con)) >> (shift)) & (mask)) + +#define set_cru_bits_w_msk(val,mask,shift,con)\ + cru_writel(((mask)<<(shift+16))|((val)<<(shift)),(con)) +#define regfile_readl(offset) readl_relaxed(RK2928_GRF_BASE + offset) +#define regfile_writel(v, offset) do { writel_relaxed(v, RK2928_GRF_BASE + offset); dsb(); } while (0) +#define cru_writel_frac(v,offset) cru_writel((v),(offset)) +/*******************PLL CON0 BITS***************************/ +#define SET_PLL_DATA(_pll_id,_table) \ +{\ + .id=(_pll_id),\ + .table=(_table),\ +} + +#define GATE_CLK(NAME,PARENT,ID) \ + static struct clk clk_##NAME = { \ + .name = #NAME, \ + .parent = &PARENT, \ + .mode = gate_mode, \ + .gate_idx = CLK_GATE_##ID, \ + } + +//FIXME +//lpj +#define _APLL_SET_CLKS(_mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac, \ + _periph_div, _aclk_core_div, _axi_div, _apb_div, _ahb_div) \ +{ \ + .rate = (_mhz) * MHZ, \ + .pllcon0 = PLL_SET_POSTDIV1(_postdiv1) | PLL_SET_FBDIV(_fbdiv), \ + .pllcon1 = PLL_SET_DSMPD(_dsmpd) | PLL_SET_POSTDIV2(_postdiv2) | PLL_SET_REFDIV(_refdiv), \ + .pllcon2 = PLL_SET_FRAC(_frac), \ + .clksel0 = ACLK_CPU_DIV(RATIO_##_axi_div) | CLK_CORE_DIV(RATIO_##_aclk_core_div),\ + .clksel1 = PCLK_CPU_DIV(RATIO_##_apb_div) | HCLK_CPU_DIV(RATIO_##_ahb_div) \ + | ACLK_CORE_DIV(RATIO_##_aclk_core_div) | CLK_CORE_PERI_DIV(RATIO_##_periph_div), \ + .lpj = 1500, \ +} +static const struct apll_clk_set apll_clks[] = { + _APLL_SET_CLKS(650, 6, 325, 2, 1, 1, 0, 41, 21, 81, 21, 21), +}; + +#define _PLL_SET_CLKS(_mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac) \ +{ \ + .rate = (_mhz) * KHZ, \ + .pllcon0 = PLL_SET_POSTDIV1(_postdiv1) | PLL_SET_FBDIV(_fbdiv), \ + .pllcon1 = PLL_SET_DSMPD(_dsmpd) | PLL_SET_POSTDIV2(_postdiv2) | PLL_SET_REFDIV(_refdiv), \ + .pllcon2 = PLL_SET_FRAC(_frac), \ +} +static const struct pll_clk_set cpll_clks[] = { + _PLL_SET_CLKS(798000, 4, 133, 1, 1, 0, 0), + _PLL_SET_CLKS(1064000, 3, 133, 1, 1, 0, 0), +}; + +static const struct pll_clk_set gpll_clks[] = { + _PLL_SET_CLKS(297000, 2, 99, 4, 1, 0, 0), +}; + +static u32 clk_gcd(u32 numerator, u32 denominator) +{ + u32 a, b; + + if (!numerator || !denominator) + return 0; + + if (numerator > denominator) { + a = numerator; + b = denominator; + } else { + a = denominator; + b = numerator; + } + + while (b != 0) { + int r = b; + b = a % b; + a = r; + } + + return a; +} + +static int frac_div_get_seting(unsigned long rate_out,unsigned long rate, + u32 *numerator,u32 *denominator) +{ + u32 gcd_vl; + gcd_vl = clk_gcd(rate, rate_out); + CLKDATA_DBG("frac_get_seting rate=%lu,parent=%lu,gcd=%d\n",rate_out,rate, gcd_vl); + + if (!gcd_vl) { + CLKDATA_ERR("gcd=0, i2s frac div is not be supported\n"); + return -ENOENT; + } + + *numerator = rate_out / gcd_vl; + *denominator = rate/ gcd_vl; + + CLKDATA_DBG("frac_get_seting numerator=%d,denominator=%d,times=%d\n", + *numerator, *denominator, *denominator / *numerator); + + if (*numerator > 0xffff || *denominator > 0xffff|| + (*denominator/(*numerator))<20) { + CLKDATA_ERR("can't get a available nume and deno\n"); + return -ENOENT; + } + + return 0; + +} +/************************option functions*****************/ +/************************clk recalc div rate**************/ + +//for free div +static unsigned long clksel_recalc_div(struct clk *clk) +{ + u32 div = get_cru_bits(clk->clksel_con, clk->div_mask, clk->div_shift) + 1; + unsigned long rate = clk->parent->rate / div; + + CLKDATA_DBG("ENTER %s clk=%s\n", __func__, clk->name); + CLKDATA_DBG("%s new clock rate is %lu (div %u)\n", clk->name, rate, div); + return rate; +} + +//for div 2^n +static unsigned long clksel_recalc_shift(struct clk *clk) +{ + u32 shift = get_cru_bits(clk->clksel_con, clk->div_mask, clk->div_shift); + unsigned long rate = clk->parent->rate >> shift; + CLKDATA_DBG("ENTER %s clk=%s\n", __func__, clk->name); + CLKDATA_DBG("%s new clock rate is %lu (shift %u)\n", clk->name, rate, shift); + return rate; +} + +//for rate equal to parent +static unsigned long clksel_recalc_equal_parent(struct clk *clk) +{ + unsigned long rate = clk->parent->rate; + CLKDATA_DBG("ENTER %s clk=%s\n", __func__, clk->name); + CLKDATA_DBG("%s new clock rate is %lu (equal to parent)\n", clk->name, rate); + + return clk->parent->rate; +} + +//for Fixed divide ratio +static unsigned long clksel_recalc_fixed_div2(struct clk *clk) +{ + unsigned long rate = clk->parent->rate >> 1; + CLKDATA_DBG("ENTER %s clk=%s\n", __func__, clk->name); + CLKDATA_DBG("%s new clock rate is %lu (div %u)\n", clk->name, rate, 2); + + return rate; +} + +static unsigned long clksel_recalc_fixed_div4(struct clk *clk) +{ + unsigned long rate = clk->parent->rate >> 2; + CLKDATA_DBG("ENTER %s clk=%s\n", __func__, clk->name); + CLKDATA_DBG("%s new clock rate is %lu (div %u)\n", clk->name, rate, 4); + + return rate; +} + +static unsigned long clksel_recalc_frac(struct clk *clk) +{ + unsigned long rate; + u64 rate64; + u32 r = cru_readl(clk->clksel_con), numerator, denominator; + CLKDATA_DBG("ENTER %s clk=%s\n", __func__, clk->name); + if (r == 0) // FPGA ? + return clk->parent->rate; + numerator = r >> 16; + denominator = r & 0xFFFF; + rate64 = (u64)clk->parent->rate * numerator; + do_div(rate64, denominator); + rate = rate64; + CLKDATA_DBG("%s new clock rate is %lu (frac %u/%u)\n", clk->name, rate, numerator, denominator); + return rate; +} + +#define FRAC_MODE 0 +static unsigned long pll_clk_recalc(u8 pll_id, unsigned long parent_rate) +{ + unsigned long rate; + unsigned int dsmp = 0; + u64 rate64 = 0, frac_rate64 = 0; + dsmp = PLL_GET_DSMPD(cru_readl(PLL_CONS(pll_id, 1))); + + if (PLLS_IN_NORM(pll_id)) { + u32 pll_con0 = cru_readl(PLL_CONS(pll_id, 0)); + u32 pll_con1 = cru_readl(PLL_CONS(pll_id, 1)); + //integer mode + rate64 = (u64)parent_rate * PLL_GET_FBDIV(pll_con1); + do_div(rate64, PLL_GET_REFDIV(pll_con1)); + + if (FRAC_MODE == dsmp) { + //fractional mode + frac_rate64 = (u64)parent_rate * PLL_GET_FRAC(pll_con1); + do_div(frac_rate64, PLL_GET_REFDIV(pll_con1)); + rate64 += frac_rate64 >> 24; + CLKDATA_DBG("%s id=%d frac_rate=%llu(0x%08x/2^24) by pass mode\n", + __func__, pll_id, frac_rate64, PLL_GET_FRAC(pll_con1)); + } + do_div(rate64, PLL_GET_POSTDIV1(pll_con0)); + do_div(rate64, PLL_GET_POSTDIV2(pll_con0)); + + rate = rate64; + } else { + rate = parent_rate; + CLKDATA_DBG("pll_clk_recalc id=%d rate=%lu by pass mode\n", pll_id, rate); + } + return rate; +} + +static unsigned long plls_clk_recalc(struct clk *clk) +{ + return pll_clk_recalc(clk->pll->id, clk->parent->rate); +} + +/************************clk set rate*********************************/ +static int clksel_set_rate_freediv(struct clk *clk, unsigned long rate) +{ + u32 div; + for (div = 0; div < clk->div_max; div++) { + u32 new_rate = clk->parent->rate / (div + 1); + if (new_rate <= rate) { + set_cru_bits_w_msk(div,clk->div_mask,clk->div_shift,clk->clksel_con); + //clk->rate = new_rate; + CLKDATA_DBG("clksel_set_rate_freediv for clock %s to rate %ld (div %d)\n", clk->name, rate, div + 1); + return 0; + } + } + return -ENOENT; +} + +//for div 1 2 4 2^n +static int clksel_set_rate_shift(struct clk *clk, unsigned long rate) +{ + u32 shift; + for (shift = 0; (1 << shift) < clk->div_max; shift++) { + u32 new_rate = clk->parent->rate >> shift; + if (new_rate <= rate) { + set_cru_bits_w_msk(shift,clk->div_mask,clk->div_shift,clk->clksel_con); + clk->rate = new_rate; + CLKDATA_DBG("clksel_set_rate_shift for clock %s to rate %ld (shift %d)\n", clk->name, rate, shift); + return 0; + } + } + return -ENOENT; +} +#if 0 +//for div 2 4 2^n +static int clksel_set_rate_shift_2(struct clk *clk, unsigned long rate) +{ + u32 shift; + + for (shift = 1; (1 << shift) < clk->div_max; shift++) { + u32 new_rate = clk->parent->rate >> shift; + if (new_rate <= rate) { + set_cru_bits_w_msk(shift-1,clk->div_mask,clk->div_shift,clk->clksel_con); + clk->rate = new_rate; + CLKDATA_DBG("clksel_set_rate_shift for clock %s to rate %ld (shift %d)\n", clk->name, rate, shift); + return 0; + } + } + return -ENOENT; +} +#endif +static u32 clk_get_freediv(unsigned long rate_out, unsigned long rate ,u32 div_max) +{ + u32 div; + unsigned long new_rate; + for (div = 0; div rate==rate) + return clk->parent; + for(i=0;i<2;i++) + { + div[i]=clk_get_freediv(rate,clk->parents[i]->rate,clk->div_max); + new_rate[i] = clk->parents[i]->rate/div[i]; + if(new_rate[i]==rate) + { + *div_out=div[i]; + return clk->parents[i]; + } + } + if(new_rate[0]parents[i]; +} + +static int clkset_rate_freediv_autosel_parents(struct clk *clk, unsigned long rate) +{ + struct clk *p_clk; + u32 div,old_div; + int ret=0; + if(clk->rate==rate) + return 0; + p_clk=get_freediv_parents_div(clk,rate,&div); + + if(!p_clk) + return -ENOENT; + + CLKDATA_DBG("%s %lu,form %s\n",clk->name,rate,p_clk->name); + if (clk->parent != p_clk) + { + old_div=CRU_GET_REG_BITS_VAL(cru_readl(clk->clksel_con),clk->div_shift,clk->div_mask)+1; + + if(div>old_div) + { + set_cru_bits_w_msk(div-1,clk->div_mask,clk->div_shift,clk->clksel_con); + } + ret=clk_set_parent_nolock(clk,p_clk); + if(ret) + { + CLKDATA_ERR("%s can't set %lu,reparent err\n",clk->name,rate); + return -ENOENT; + } + } + //set div + set_cru_bits_w_msk(div-1,clk->div_mask,clk->div_shift,clk->clksel_con); + return 0; +} +#if 0 +//rate==div rate //hdmi +static int clk_freediv_autosel_parents_set_fixed_rate(struct clk *clk, unsigned long rate) +{ + struct clk *p_clk; + u32 div,old_div; + int ret; + p_clk=get_freediv_parents_div(clk,rate,&div); + + if(!p_clk) + return -ENOENT; + + if((p_clk->rate/div)!=rate||(p_clk->rate%div)) + return -ENOENT; + + if (clk->parent != p_clk) + { + old_div=CRU_GET_REG_BITS_VAL(cru_readl(clk->clksel_con), + clk->div_shift,clk->div_mask)+1; + if(div>old_div) + { + set_cru_bits_w_msk(div-1,clk->div_mask,clk->div_shift,clk->clksel_con); + } + ret=clk_set_parent_nolock(clk,p_clk); + if (ret) + { + CLKDATA_DBG("%s can't get rate%lu,reparent err\n",clk->name,rate); + return ret; + } + } + //set div + set_cru_bits_w_msk(div-1,clk->div_mask,clk->div_shift,clk->clksel_con); + return 0; +} +#endif +/************************round functions*****************/ +static long clksel_freediv_round_rate(struct clk *clk, unsigned long rate) +{ + return clk->parent->rate/clk_get_freediv(rate,clk->parent->rate,clk->div_max); +} + +static long clk_freediv_round_autosel_parents_rate(struct clk *clk, unsigned long rate) +{ + u32 div; + struct clk *p_clk; + if(clk->rate == rate) + return clk->rate; + p_clk=get_freediv_parents_div(clk,rate,&div); + if(!p_clk) + return 0; + return p_clk->rate/div; +} + +static const struct apll_clk_set* apll_clk_get_best_pll_set(unsigned long rate, + struct apll_clk_set *tables) +{ + const struct apll_clk_set *ps, *pt; + + /* find the arm_pll we want. */ + ps = pt = tables; + while (pt->rate) { + if (pt->rate == rate) { + ps = pt; + break; + } + // we are sorted, and ps->rate > pt->rate. + if ((pt->rate > rate || (rate - pt->rate < ps->rate - rate))) + ps = pt; + if (pt->rate < rate) + break; + pt++; + } + //CLKDATA_DBG("arm pll best rate=%lu\n",ps->rate); + return ps; +} +static long apll_clk_round_rate(struct clk *clk, unsigned long rate) +{ + return apll_clk_get_best_pll_set(rate, clk->pll->table)->rate; +} + +/************************others functions*****************/ +static void pll_wait_lock(int pll_idx) +{ + u32 pll_state[4]={1,0,2,3}; + u32 bit = 0x10u << pll_state[pll_idx]; + int delay = 24000000; + while (delay > 0) { + if (!(cru_readl(PLL_CONS(pll_idx, 1)) & (0x1 << PLL_LOCK_SHIFT))) { + //printk("%s %08x\n", __func__, cru_readl(PLL_CONS(pll_idx, 1)) & (0x1 << PLL_LOCK_SHIFT)); + //printk("%s ! %08x\n", __func__, !(cru_readl(PLL_CONS(pll_idx, 1)) & (0x1 << PLL_LOCK_SHIFT))); + break; + } + delay--; + } + if (delay == 0) { + CLKDATA_ERR("wait pll bit 0x%x time out!\n", bit); + while(1); + } +} +static int pll_clk_mode(struct clk *clk, int on) +{ + u8 pll_id = clk->pll->id; + // FIXME here 500 must be changed + u32 dly = 1500; + + CLKDATA_DBG("pll_mode %s(%d)", clk->name, on); + //FIXME + if (on) { + cru_writel(CRU_W_MSK_SETBIT(PLL_PWR_ON, PLL_LOCK_SHIFT), PLL_CONS(pll_id, 0)); + rk_clock_udelay(dly); + pll_wait_lock(pll_id); + cru_writel(PLL_MODE_NORM(pll_id), CRU_MODE_CON); + } else { + cru_writel(PLL_MODE_SLOW(pll_id), CRU_MODE_CON); + cru_writel(CRU_W_MSK_SETBIT(PLL_PWR_DN, PLL_LOCK_SHIFT), PLL_CONS(pll_id, 0)); + } + return 0; +} +static struct clk* clksel_get_parent(struct clk *clk) +{ + return clk->parents[(cru_readl(clk->clksel_con) >> clk->src_shift) & clk->src_mask]; +} +static int clksel_set_parent(struct clk *clk, struct clk *parent) +{ + u32 i; + if (unlikely(!clk->parents)) + return -EINVAL; + for (i = 0; (i parents_num); i++) { + if (clk->parents[i]!= parent) + continue; + set_cru_bits_w_msk(i,clk->src_mask,clk->src_shift,clk->clksel_con); + return 0; + } + return -EINVAL; +} + +static int gate_mode(struct clk *clk, int on) +{ + int idx = clk->gate_idx; + CLKDATA_DBG("ENTER %s clk=%s, on=%d\n", __func__, clk->name, on); + if (idx >= CLK_GATE_MAX) + return -EINVAL; + if(on) { + cru_writel(CLK_GATE_W_MSK(idx) | CLK_UN_GATE(idx), CLK_GATE_CLKID_CONS(idx)); + } else { + cru_writel(CLK_GATE_W_MSK(idx) | CLK_GATE(idx), CLK_GATE_CLKID_CONS(idx)); + } + return 0; +} +#define PLL_INT_MODE 1 +#define PLL_FRAC_MODE 0 + +#define rk2928_clock_udelay(a) udelay(a); +static int pll_clk_set_rate(struct pll_clk_set *clk_set, u8 pll_id) +{ + //enter slowmode + cru_writel(PLL_MODE_SLOW(pll_id), CRU_MODE_CON); + + cru_writel(clk_set->pllcon0, PLL_CONS(pll_id,0)); + cru_writel(clk_set->pllcon1, PLL_CONS(pll_id,1)); + cru_writel(clk_set->pllcon2, PLL_CONS(pll_id,2)); + + //printk("id=%d,pllcon0%08x\n", pll_id, cru_readl(PLL_CONS(pll_id,0))); + //printk("id=%d,pllcon1%08x\n", pll_id, cru_readl(PLL_CONS(pll_id,1))); + //printk("id=%d,pllcon2%08x\n", pll_id, cru_readl(PLL_CONS(pll_id,2))); + //rk2928_clock_udelay(5); + + //wating lock state + rk2928_clock_udelay(clk_set->rst_dly); + pll_wait_lock(pll_id); + + //return form slow + cru_writel(PLL_MODE_NORM(pll_id), CRU_MODE_CON); + + return 0; +} +#define PLL_FREF_MIN (183*KHZ) +#define PLL_FREF_MAX (1500*MHZ) + +#define PLL_FVCO_MIN (300*MHZ) +#define PLL_FVCO_MAX (1500*MHZ) + +#define PLL_FOUT_MIN (18750*KHZ) +#define PLL_FOUT_MAX (1500*MHZ) + +#define PLL_NF_MAX (4096) +#define PLL_NR_MAX (64) +#define PLL_NO_MAX (16) + +static int pll_clk_check_legality(unsigned long fin_hz,unsigned long fout_hz, + u32 refdiv, u32 fbdiv, u32 postdiv1, u32 postdiv2) +{ + fin_hz /= MHZ; + if (fin_hz < 1 || fin_hz > 800) { + CLKDATA_ERR("%s fbdiv out of [1, 800]MHz\n", __func__); + return -1; + } + + if (fbdiv < 16 || fbdiv > 1600) { + CLKDATA_ERR("%s fbdiv out of [16, 1600]MHz\n", __func__); + return -1; + } + + if (fin_hz / refdiv < 1 || fin_hz / refdiv > 40) { + CLKDATA_ERR("%s fin / refdiv out of [1, 40]MHz\n", __func__); + return -1; + } + + if (fin_hz * fbdiv / refdiv < 400 || fin_hz * fbdiv / refdiv > 1600) { + CLKDATA_ERR("%s fin_hz * fbdiv / refdiv out of [400, 1600]MHz\n", __func__); + return -1; + } + + if (fin_hz * fbdiv / refdiv / postdiv1 / postdiv2 < 8 + || fin_hz * fbdiv / refdiv / postdiv1 / postdiv2 > 1600) { + CLKDATA_ERR("%s fin_hz * fbdiv / refdiv / postdiv1 / postdiv2 out of [8, 1600]MHz\n", __func__); + return -1; + } + +} + +static int pll_clk_check_legality_frac(unsigned long fin_hz,unsigned long fout_hz, + u32 refdiv, u32 fbdiv, u32 postdiv1, u32 postdiv2, u32 frac) +{ + fin_hz /= MHZ; + if (fin_hz < 10 || fin_hz > 800) { + CLKDATA_ERR("%s fin_hz out of [10, 800]MHz\n", __func__); + return -1; + } + if (fbdiv < 19 || fbdiv > 160) { + CLKDATA_ERR("%s fbdiv out of [19, 160]MHz\n", __func__); + return -1; + } + + if (fin_hz / refdiv < 1 || fin_hz / refdiv > 40) { + CLKDATA_ERR("%s fin / refdiv out of [1, 40]MHz\n", __func__); + return -1; + } + + if (fin_hz * fbdiv / refdiv < 400 || fin_hz * fbdiv / refdiv > 1600) { + CLKDATA_ERR("%s fin_hz * fbdiv / refdiv out of [400, 1600]MHz\n", __func__); + return -1; + } + + if (fin_hz * fbdiv / refdiv / postdiv1 / postdiv2 < 8 + || fin_hz * fbdiv / refdiv / postdiv1 / postdiv2 > 1600) { + CLKDATA_ERR("%s fin_hz * fbdiv / refdiv / postdiv1 / postdiv2 out of [8, 1600]MHz\n", __func__); + return -1; + } + +} +static int pll_clk_get_set(unsigned long fin_hz,unsigned long fout_hz, + u32 *refdiv, u32 *fbdiv, u32 *postdiv1, u32 *postdiv2, u32 *frac) +{ + // FIXME set postdiv1/2 always 1 + u32 gcd; + + if(!fin_hz || !fout_hz || fout_hz == fin_hz) + return -1; + + fin_hz /= MHZ; + fout_hz /= MHZ; + gcd = clk_gcd(fin_hz, fout_hz); + refdiv = gcd; + fbdiv = fout_hz / gcd; + postdiv1 = 1; + postdiv2 = 1; + + frac = 0; + + CLKDATA_DBG("fin=%lu,fout=%lu,gcd=%lu,refdiv=%lu,fbdiv=%lu,postdiv1=%lu,postdiv2=%lu,frac=%lu\n", + fin_hz, fout_hz, gcd, refdiv, fbdiv, postdiv1, postdiv2, frac); + + return 0; +} +static int pll_set_con(u8 id, u32 refdiv, u32 fbdiv, u32 postdiv1, u32 postdiv2, u32 frac) +{ + struct pll_clk_set temp_clk_set; + temp_clk_set.pllcon0 = PLL_SET_FBDIV(fbdiv) | PLL_SET_POSTDIV1(postdiv1) ; + temp_clk_set.pllcon1 = PLL_SET_REFDIV(refdiv) | PLL_SET_POSTDIV2(postdiv2); + temp_clk_set.pllcon2 = PLL_SET_FRAC(frac); + temp_clk_set.rst_dly = 1500; + printk("setting....\n"); + return pll_clk_set_rate(&temp_clk_set, id); +} +static int apll_clk_set_rate(struct clk *clk, unsigned long rate) +{ + // FIXME + u32 refdiv, fbdiv, postdiv1, postdiv2, frac; + printk("%s %s %d\n", __func__, clk->name, rate); + pll_clk_get_set(clk->parent->rate, rate, &refdiv, &fbdiv, &postdiv1, &postdiv2, &frac); + pll_set_con(clk->pll->id, refdiv, fbdiv, postdiv1, postdiv2, frac); + + printk("setting OK\n"); + return 0; +} + +static int dpll_clk_set_rate(struct clk *clk, unsigned long rate) +{ + // FIXME do nothing here + printk("setting OK\n"); + return 0; +} + +static int cpll_clk_set_rate(struct clk *clk, unsigned long rate) +{ + // FIXME + struct _pll_data *pll_data=clk->pll; + struct pll_clk_set *clk_set=(struct pll_clk_set*)pll_data->table; + struct pll_clk_set temp_clk_set; + + u32 fin_hz, fout_hz; + u32 refdiv, fbdiv, postdiv1, postdiv2, frac; + fin_hz = clk->parent->rate; + fout_hz = rate; + + while(clk_set->rate) { + if (clk_set->rate == rate) { + break; + } + clk_set++; + } + + if(clk_set->rate==rate) { + CLKDATA_DBG("cpll get a rate\n"); + pll_clk_set_rate(clk_set, pll_data->id); + + } else { + CLKDATA_DBG("cpll get auto calc a rate\n"); + if(pll_clk_get_set(clk->parent->rate, &rate, &refdiv, &fbdiv, &postdiv1, &postdiv2, &frac) != 0) { + pr_err("cpll auto set rate error\n"); + return -ENOENT; + } + CLKDATA_DBG("%s get fin=%d, fout=%d, refdiv=%lu, fbdiv=%lu, postdiv1=%lu, postdiv2=%d", + __func__, fin_hz, fout_hz, rate, refdiv, fbdiv, postdiv1, postdiv2); + pll_set_con(pll_data->id, refdiv, fbdiv, postdiv1, postdiv2, frac); + } + + printk("setting OK\n"); + return 0; +} + +static int gpll_clk_set_rate(struct clk *clk, unsigned long rate) +{ + // FIXME + struct _pll_data *pll_data=clk->pll; + struct pll_clk_set *clk_set=(struct pll_clk_set*)pll_data->table; + + printk("******%s\n", __func__); + while(clk_set->rate) + { + printk("******%s clk_set->rate=%d\n", __func__, clk_set->rate); + if (clk_set->rate == rate) { + break; + } + clk_set++; + } + if(clk_set->rate== rate) + { + pll_clk_set_rate(clk_set,pll_data->id); + //lpj_gpll = CLK_LOOPS_RECALC(rate); + } + else + { + CLKDATA_ERR("gpll is no corresponding rate=%lu\n", rate); + return -1; + } + printk("******%s end\n", __func__); + + return 0; +} + +/**********************pll datas*************************/ +static u32 rk2928_clock_flags = 0; +static struct _pll_data apll_data = SET_PLL_DATA(APLL_ID, (void *)apll_clks); +static struct _pll_data dpll_data = SET_PLL_DATA(DPLL_ID, NULL); +static struct _pll_data cpll_data = SET_PLL_DATA(CPLL_ID, (void *)cpll_clks); +static struct _pll_data gpll_data = SET_PLL_DATA(GPLL_ID, (void *)gpll_clks); +/*********************************************************/ +/************************clocks***************************/ +/*********************************************************/ + +static struct clk xin24m = { + .name = "xin24m", + .rate = 24 * MHZ, + .flags = RATE_FIXED, +}; + +static struct clk clk_12m = { + .name = "clk_12m", + .parent = &xin24m, + .rate = 12 * MHZ, + .flags = RATE_FIXED, +}; +/************************plls***********************/ +static struct clk arm_pll_clk = { + .name = "arm_pll", + .parent = &xin24m, + .mode = pll_clk_mode, + .recalc = plls_clk_recalc, + .set_rate = apll_clk_set_rate, + .round_rate = apll_clk_round_rate, + .pll = &apll_data, +}; + +static struct clk ddr_pll_clk = { + .name = "ddr_pll", + .parent = &xin24m, + .mode = pll_clk_mode, + .recalc = plls_clk_recalc, + .set_rate = dpll_clk_set_rate, + .pll = &dpll_data, +}; + +static struct clk codec_pll_clk = { + .name = "codec_pll", + .parent = &xin24m, + .mode = pll_clk_mode, + .recalc = plls_clk_recalc, + .set_rate = cpll_clk_set_rate, + .pll = &cpll_data, +}; + +static struct clk general_pll_clk = { + .name = "general_pll", + .parent = &xin24m, + .mode = pll_clk_mode, + .gate_idx = CLK_GATE_CPU_GPLL, + .recalc = plls_clk_recalc, + .set_rate = gpll_clk_set_rate, + .pll = &gpll_data, +}; +#define SELECT_FROM_2PLLS {&general_pll_clk, &codec_pll_clk} +/*********ddr******/ +static int ddr_clk_set_rate(struct clk *c, unsigned long rate) +{ + // need to do nothing + return 0; +} + +static struct clk clk_ddrphy2x = { + .name = "ddrphy2x", + .parent = &ddr_pll_clk, + .mode = gate_mode, + .gate_idx = CLK_GATE_DDRPHY_SRC, + .recalc = clksel_recalc_shift, + .set_rate = ddr_clk_set_rate, + .clksel_con = CRU_CLKSELS_CON(26), +}; + +static struct clk clk_ddrc = { + .name = "ddrc", + .parent = &clk_ddrphy2x, + .recalc = clksel_recalc_fixed_div2, +}; + +static struct clk clk_ddrphy = { + .name = "ddrphy", + .parent = &clk_ddrphy2x, + .recalc = clksel_recalc_fixed_div2, +}; + +/****************core*******************/ +#if 0 +static unsigned long core_clk_get_rate(struct clk *c) +{ + u32 div=(get_cru_bits(c->clksel_con,c->div_mask,c->div_shift)+1); + //c->parent->rate=c->parent->recalc(c->parent); + return c->parent->rate/div; +} +#endif +static long core_clk_round_rate(struct clk *clk, unsigned long rate) +{ + u32 div=(get_cru_bits(clk->clksel_con,clk->div_mask,clk->div_shift)+1); + return clk_round_rate_nolock(clk->parent,rate)/div; +} + +static int core_clksel_set_parent(struct clk *clk, struct clk *new_prt) +{ + // FIXME + u32 temp_div; + struct clk *old_prt; + + if(clk->parent==new_prt) + return 0; + if (unlikely(!clk->parents)) + return -EINVAL; + CLKDATA_DBG("%s,reparent %s\n",clk->name,new_prt->name); + //arm + old_prt=clk->parent; + + if(clk->parents[0]==new_prt) + { + new_prt->set_rate(new_prt,300*MHZ); + set_cru_bits_w_msk(0,clk->div_mask,clk->div_shift,clk->clksel_con); + } + else if(clk->parents[1]==new_prt) + { + + if(new_prt->rate>old_prt->rate) + { + temp_div=clk_get_freediv(old_prt->rate,new_prt->rate,clk->div_max); + set_cru_bits_w_msk(temp_div-1,clk->div_mask,clk->div_shift,clk->clksel_con); + } + set_cru_bits_w_msk(1,clk->src_mask,clk->src_shift,clk->clksel_con); + new_prt->set_rate(new_prt,300*MHZ); + } + else + return -1; + + return 0; +} + +static struct clk *clk_core_pre_parents[2] = {&arm_pll_clk, &general_pll_clk}; +// this clk is cpu? +static int arm_core_clk_set_rate(struct clk *c, unsigned long rate) +{ + int ret; + //set arm pll div 1 + //set_cru_bits_w_msk(0,c->div_mask,c->div_shift,c->clksel_con); + + CLKDATA_DBG("Failed to change clk pll %s to %lu\n",c->name,rate); + ret = clk_set_rate_nolock(c->parent, rate); + if (ret) { + CLKDATA_ERR("Failed to change clk pll %s to %lu\n",c->name,rate); + return ret; + } + CLKDATA_DBG("change clk pll %s to %lu OK\n",c->name,rate); + return 0; +} +static struct clk clk_core_pre = { + .name = "core_pre", + .parent = &arm_pll_clk, + .recalc = clksel_recalc_div, + .set_rate = arm_core_clk_set_rate, + .round_rate = core_clk_round_rate, + .set_parent = core_clksel_set_parent, + + .clksel_con = CRU_CLKSELS_CON(0), + CRU_DIV_SET(A9_CORE_DIV_MASK, A9_CORE_DIV_SHIFT, 32), + CRU_SRC_SET(0x1, CORE_CLK_PLL_SEL_SHIFT), + CRU_PARENTS_SET(clk_core_pre_parents), +}; + +static struct clk clk_core_periph = { + .name = "core_periph", + .parent = &clk_core_pre, + .mode = gate_mode, + .gate_idx = CLK_GATE_CORE_PERIPH, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .clksel_con = CRU_CLKSELS_CON(1), + CRU_DIV_SET(CORE_PERIPH_DIV_MASK, CORE_PERIPH_DIV_SHIFT, 16), +}; + +static struct clk clken_core_periph = { + .name = "core_periph_en", + .parent = &clk_core_periph, + .recalc = clksel_recalc_equal_parent, +}; + +static struct clk clk_l2c = { + .name = "l2c", + .parent = &clk_core_pre, + .mode = gate_mode, + .gate_idx = CLK_GATE_CLK_L2C, +}; + +static struct clk aclk_core_pre = { + .name = "aclk_core_pre", + .parent = &clk_core_pre, + .mode = gate_mode, + .gate_idx = CLK_GATE_ACLK_CORE, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .clksel_con = CRU_CLKSELS_CON(1), + CRU_DIV_SET(ACLK_CORE_DIV_MASK, ACLK_CORE_DIV_SHIFT, 2), +}; + +/****************cpu*******************/ + +static struct clk *clk_cpu_div_parents[] = {&arm_pll_clk, &general_pll_clk}; +/*seperate because of gating*/ +static struct clk clk_cpu_div = { + .name = "cpu_div", + .parent = &general_pll_clk, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .clksel_con = CRU_CLKSELS_CON(0), + CRU_DIV_SET(ACLK_CPU_DIV_MASK, ACLK_CPU_DIV_SHIFT, 32), + CRU_SRC_SET(0x1, CPU_CLK_PLL_SEL_SHIFT), + CRU_PARENTS_SET(clk_cpu_div_parents), +}; +static struct clk aclk_cpu_pre = { + .name = "aclk_cpu_pre", + .parent = &clk_cpu_div, + .mode = gate_mode, + .gate_idx = CLK_GATE_ACLK_CPU, + .recalc = clksel_recalc_equal_parent, +}; +static struct clk hclk_cpu_pre = { + .name = "hclk_cpu_pre", + .parent = &clk_cpu_div, + .mode = gate_mode, + .gate_idx = CLK_GATE_HCLK_CPU, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .clksel_con = CRU_CLKSELS_CON(1), + CRU_DIV_SET(HCLK_CPU_DIV_MASK, HCLK_CPU_DIV_SHIFT, 4), +}; +static struct clk pclk_cpu_pre = { + .name = "pclk_cpu_pre", + .parent = &clk_cpu_div, + .mode = gate_mode, + .gate_idx = CLK_GATE_PCLK_CPU, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .clksel_con = CRU_CLKSELS_CON(1), + CRU_DIV_SET(PCLK_CPU_DIV_MASK, PCLK_CPU_DIV_SHIFT, 8), +}; +/****************vcodec*******************/ +static struct clk *clk_aclk_vepu_parents[] = SELECT_FROM_2PLLS; +static struct clk *clk_aclk_vdpu_parents[] = SELECT_FROM_2PLLS; +static struct clk aclk_vepu = { + .name = "aclk_vepu", + .parent = &codec_pll_clk, + .mode = gate_mode, + .gate_idx = CLK_GATE_ACLK_VEPU_SRC, + .recalc = clksel_recalc_div, + .clksel_con = CRU_CLKSELS_CON(32), + .set_rate = clkset_rate_freediv_autosel_parents, + CRU_DIV_SET(0x1f, 0, 32), + CRU_SRC_SET(0x1, 7), + CRU_PARENTS_SET(clk_aclk_vepu_parents), +}; +static struct clk aclk_vdpu = { + .name = "aclk_vdpu", + .parent = &clk_cpu_div, + .mode = gate_mode, + .gate_idx = CLK_GATE_ACLK_VDPU_SRC, + .recalc = clksel_recalc_div, + .set_rate = clkset_rate_freediv_autosel_parents, + .clksel_con = CRU_CLKSELS_CON(32), + CRU_DIV_SET(0x1f, 8, 32), + CRU_SRC_SET(0x1, 15), + CRU_PARENTS_SET(clk_aclk_vdpu_parents), +}; +static struct clk hclk_vepu = { + .name = "hclk_vepu", + .parent = &aclk_vepu, + .mode = gate_mode, + .gate_idx = CLK_GATE_HCLK_VEPU, + .recalc = clksel_recalc_fixed_div4, +}; +static struct clk hclk_vdpu = { + .name = "hclk_vdpu", + .parent = &aclk_vdpu, + .mode = gate_mode, + .gate_idx = CLK_GATE_HCLK_VDPU, + .recalc = clksel_recalc_fixed_div4, +}; + +/****************vio*******************/ +// name: lcdc0_aclk +static struct clk *clk_aclk_vio_pre_parents[] = SELECT_FROM_2PLLS; +static struct clk aclk_vio_pre = { + .name = "aclk_vio_pre", + .parent = &clk_cpu_div, + .mode = gate_mode, + .gate_idx = CLK_GATE_ACLK_VIO_SRC, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .clksel_con = CRU_CLKSELS_CON(31), + CRU_DIV_SET(0x1f, 0, 32), + CRU_PARENTS_SET(clk_aclk_vio_pre_parents), +}; +static struct clk hclk_vio_pre = { + .name = "hclk_vio_pre", + .parent = &aclk_vio_pre, + .mode = gate_mode, + .gate_idx = CLK_GATE_HCLK_VIO_PRE, + .recalc = clksel_recalc_fixed_div4, +}; + +/****************periph*******************/ +static struct clk *peri_aclk_parents[] = SELECT_FROM_2PLLS; +static struct clk peri_aclk = { + .name = "peri_aclk", + .parent = &general_pll_clk, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .mode = gate_mode, + .gate_idx = CLK_GATE_PERIPH_SRC, + .clksel_con = CRU_CLKSELS_CON(10), + CRU_DIV_SET(PERI_ACLK_DIV_MASK, PERI_ACLK_DIV_SHIFT, 32), + CRU_SRC_SET(0x1, PERI_PLL_SEL_SHIFT), + CRU_PARENTS_SET(peri_aclk_parents), +}; + +static struct clk peri_hclk = { + .name = "peri_hclk", + .parent = &peri_aclk, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_shift, + .clksel_con = CRU_CLKSELS_CON(10), + CRU_DIV_SET(PERI_HCLK_DIV_MASK, PERI_HCLK_DIV_SHIFT, 8), +}; + +static struct clk peri_pclk = { + .name = "peri_pclk", + .parent = &peri_aclk, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_shift, + .clksel_con = CRU_CLKSELS_CON(10), + CRU_DIV_SET(PERI_PCLK_DIV_MASK, PERI_PCLK_DIV_SHIFT, 4), +}; + +static struct clk aclk_periph_pre = { + .name = "aclk_periph_pre", + .parent = &peri_aclk, + .mode = gate_mode, + .gate_idx = CLK_GATE_ACLK_PERIPH, + .recalc = clksel_recalc_equal_parent, +}; + +static struct clk hclk_periph_pre = { + .name = "hclk_periph_pre", + .parent = &peri_hclk, + .mode = gate_mode, + .gate_idx = CLK_GATE_HCLK_PERIPH, + .recalc = clksel_recalc_equal_parent, +}; + +static struct clk pclk_periph_pre = { + .name = "pclk_periph_pre", + .parent = &peri_pclk, + .mode = gate_mode, + .gate_idx = CLK_GATE_PCLK_PERIPH, + .recalc = clksel_recalc_equal_parent, +}; +/****************timer*******************/ +static struct clk *clk_timer0_parents[] = {&xin24m, &peri_pclk}; +static struct clk *clk_timer1_parents[] = {&xin24m, &peri_pclk}; +static struct clk clk_timer0 = { + .name = "timer0", + .parent = &xin24m, + .mode = gate_mode, + .gate_idx = CLK_GATE_TIMER0, + .recalc = clksel_recalc_equal_parent, + .clksel_con = CRU_CLKSELS_CON(10), + CRU_SRC_SET(0x1, 4), + CRU_PARENTS_SET(clk_timer0_parents), +}; +static struct clk clk_timer1 = { + .name = "timer1", + .parent = &xin24m, + .mode = gate_mode, + .gate_idx = CLK_GATE_TIMER1, + .recalc = clksel_recalc_equal_parent, + .clksel_con = CRU_CLKSELS_CON(10), + CRU_SRC_SET(0x1, 5), + CRU_PARENTS_SET(clk_timer1_parents), +}; +/****************spi*******************/ +static struct clk clk_spi = { + .name = "spi", + .parent = &peri_pclk, + .mode = gate_mode, + .gate_idx = CLK_GATE_SPI0_SRC, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .clksel_con = CRU_CLKSELS_CON(25), + CRU_DIV_SET(0x7f, 0, 128), +}; +/****************sdmmc*******************/ +static struct clk *clk_sdmmc0_parents[] = SELECT_FROM_2PLLS; +static struct clk clk_sdmmc0 = { + .name = "sdmmc0", + .parent = &general_pll_clk, + .mode = gate_mode, + .gate_idx = CLK_GATE_MMC0_SRC, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .clksel_con = CRU_CLKSELS_CON(11), + CRU_SRC_SET(0x1, 6), + CRU_DIV_SET(0x3f,0,64), + CRU_PARENTS_SET(clk_sdmmc0_parents), +}; +#if 0 +static struct clk clk_sdmmc0_sample = { + .name = "sdmmc0_sample", + .parent = &general_pll_clk, + .recalc = , + //.set_rate = , + .clksel_con = , + CRU_DIV_SET(,,), +}; +static struct clk clk_sdmmc0_drv = { + .name = "sdmmc0_drv", + .parent = &clk_sdmmc0, + .recalc = , + //.set_rate = , + .clksel_con = , + CRU_DIV_SET(,,), +}; +#endif +/****************sdio*******************/ +static struct clk *clk_sdio_parents[] = SELECT_FROM_2PLLS; +static struct clk clk_sdio = { + .name = "sdio", + .parent = &general_pll_clk, + .mode = gate_mode, + .gate_idx = CLK_GATE_SDIO_SRC, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .clksel_con = CRU_CLKSELS_CON(12), + CRU_DIV_SET(0x3f,0,64), + CRU_PARENTS_SET(clk_sdio_parents), +}; +#if 0 +static struct clk clk_sdio_sample = { + .name = "sdio_sample", + .parent = &general_pll_clk, + .recalc = , + //.set_rate = , + .clksel_con = , + CRU_DIV_SET(,,), +}; +static struct clk clk_sdio_drv = { + .name = "sdio_drv", + .parent = &clk_sdio, + .recalc = , + //.set_rate = , + .clksel_con = , + CRU_DIV_SET(,,), +}; +#endif +/****************emmc*******************/ +static struct clk *clk_emmc_parents[] = SELECT_FROM_2PLLS; +static struct clk clk_emmc = { + .name = "emmc", + .parent = &general_pll_clk, + .mode = gate_mode, + .gate_idx = CLK_GATE_EMMC_SRC, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .clksel_con =CRU_CLKSELS_CON(12), + CRU_DIV_SET(0x3f,8,64), + CRU_PARENTS_SET(clk_emmc_parents), +}; +#if 0 +static struct clk clk_emmc_sample = { + .name = "emmc_sample", + .parent = &general_pll_clk, + .recalc = , + //.set_rate = , + .clksel_con = , + CRU_DIV_SET(,,), +}; +static struct clk clk_emmc_drv = { + .name = "emmc_drv", + .parent = &clk_emmc, + .recalc = , + //.set_rate = , + .clksel_con = , + CRU_DIV_SET(,,), +}; +#endif +/****************lcdc*******************/ +static struct clk *dclk_lcdc_parents[] = {&arm_pll_clk, &general_pll_clk, &codec_pll_clk}; +static struct clk dclk_lcdc = { + .name = "dclk_lcdc", + .parent = &general_pll_clk, + .mode = gate_mode, + .gate_idx = CLK_GATE_DCLK_LCDC0_SRC, + .recalc = clksel_recalc_div, + .set_rate = clkset_rate_freediv_autosel_parents, + .clksel_con = CRU_CLKSELS_CON(27), + CRU_DIV_SET(0xff, 8, 256), + CRU_SRC_SET(0x3, 0), + CRU_PARENTS_SET(dclk_lcdc_parents), +}; +static struct clk *sclk_lcdc_parents[] = SELECT_FROM_2PLLS; +static struct clk sclk_lcdc = { + .name = "sclk_lcdc", + .parent = &general_pll_clk, + .mode = gate_mode, + .gate_idx = CLK_GATE_SCLK_LCDC_SRC, + .recalc = clksel_recalc_div, + .set_rate = clkset_rate_freediv_autosel_parents, + .clksel_con = CRU_CLKSELS_CON(28), + CRU_DIV_SET(0xff, 8, 256), + CRU_SRC_SET(0x1, 0), + CRU_PARENTS_SET(sclk_lcdc_parents), +}; +/****************gps*******************/ +#if 0 +static struct clk hclk_gps_parents = SELECT_FROM_2PLLS; +static struct clk hclk_gps = { + .name = "hclk_gps", + .parent = &general_pll_clk, + .recalc = , + //.set_rate = , + .clksel_con = , + CRU_DIV_SET(,,), +}; +#endif +/****************camera*******************/ +static struct clk *clk_cif_out_div_parents[] = SELECT_FROM_2PLLS; +static struct clk clk_cif_out_div = { + .name = "cif_out_div", + .parent = &general_pll_clk, + .mode = gate_mode, + .gate_idx = CLK_GATE_CIF_OUT_SRC, + .recalc = clksel_recalc_div, + .set_rate = clkset_rate_freediv_autosel_parents, + .clksel_con = CRU_CLKSELS_CON(29), + CRU_SRC_SET(0x1, 0), + CRU_DIV_SET(0x1f, 1, 32), + CRU_PARENTS_SET(clk_cif_out_div_parents), +}; +static struct clk *clk_cif_out_parents[] = {&xin24m, &clk_cif_out_div}; +static struct clk clk_cif_out = { + .name = "cif0_out", + .parent = &clk_cif_out_div, + .clksel_con = CRU_CLKSELS_CON(29), + CRU_SRC_SET(0x1, 7), + CRU_PARENTS_SET(clk_cif_out_parents), +}; + +/*External clock*/ +static struct clk pclkin_cif0 = { + .name = "pclkin_cif0", + .mode = gate_mode, + .mode = gate_mode, + .gate_idx = CLK_GATE_PCLKIN_CIF, +}; + +static struct clk inv_cif0 = { + .name = "inv_cif0", + .parent = &pclkin_cif0, +}; + +static struct clk *cif0_in_parents[] = {&pclkin_cif0, &inv_cif0}; +static struct clk cif0_in = { + .name = "cif0_in", + .parent = &pclkin_cif0, + .clksel_con = CRU_CLKSELS_CON(30), + CRU_SRC_SET(0x1, 8), + CRU_PARENTS_SET(cif0_in_parents), +}; + +/****************i2s*******************/ +#define I2S_SRC_12M (0x0) +#define I2S_SRC_DIV (0x1) +#define I2S_SRC_FRAC (0x2) + +static int i2s_set_rate(struct clk *clk, unsigned long rate) +{ + int ret = -EINVAL; + struct clk *parent; + + if (rate == clk->parents[I2S_SRC_12M]->rate){ + parent = clk->parents[I2S_SRC_12M]; + }else if((long)clk_round_rate_nolock(clk->parents[I2S_SRC_DIV],rate)==rate) + { + parent = clk->parents[I2S_SRC_DIV]; + } + else + { + parent =clk->parents[I2S_SRC_FRAC]; + } + + CLKDATA_DBG(" %s set rate=%lu parent %s(old %s)\n", + clk->name,rate,parent->name,clk->parent->name); + + if(parent!=clk->parents[I2S_SRC_12M]) + { + ret = clk_set_rate_nolock(parent,rate);//div 1:1 + if (ret) + { + CLKDATA_DBG("%s set rate%lu err\n",clk->name,rate); + return ret; + } + } + + if (clk->parent != parent) + { + ret = clk_set_parent_nolock(clk, parent); + if (ret) + { + CLKDATA_DBG("%s can't get rate%lu,reparent err\n",clk->name,rate); + return ret; + } + } + + return ret; +}; +static struct clk *clk_i2s_div_parents[] = SELECT_FROM_2PLLS; +static struct clk clk_i2s_pll = { + .name = "i2s_pll", + .parent = &general_pll_clk, + .clksel_con = CRU_CLKSELS_CON(2), + CRU_SRC_SET(0x1,15), + CRU_PARENTS_SET(clk_i2s_div_parents), +}; + +static struct clk clk_i2s_div = { + .name = "i2s_div", + .parent = &clk_i2s_pll, + .mode = gate_mode, + .gate_idx = CLK_GATE_I2S_SRC, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .round_rate = clksel_freediv_round_rate, + .clksel_con = CRU_CLKSELS_CON(3), + CRU_DIV_SET(0x7f, 0, 64), +}; +static struct clk clk_i2s_frac_div = { + .name = "i2s_frac_div", + .parent = &clk_i2s_div, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .round_rate = clksel_freediv_round_rate, + .mode = gate_mode, + .gate_idx = CLK_GATE_I2S_FRAC_SRC, + .clksel_con = CRU_CLKSELS_CON(7), +}; + +static struct clk *clk_i2s_parents[] = {&clk_12m, &clk_i2s_div, &clk_i2s_frac_div}; +static struct clk clk_i2s = { + .name = "i2s", + .parent = &clk_i2s_div, + .set_rate = i2s_set_rate, + .clksel_con = CRU_CLKSELS_CON(3), + CRU_SRC_SET(0x3, 8), + CRU_PARENTS_SET(clk_i2s_parents), +}; + +/****************otgphy*******************/ +#if 0 +static struct clk clk_otgphy0 = { + .name = "otgphy0", + .parent = &clk_12m, + .recalc = , + //.set_rate = , + .clksel_con = , + CRU_DIV_SET(,,), +}; +static struct clk clk_otgphy1 = { + .name = "otgphy1", + .parent = &clk_12m, + .recalc = , + //.set_rate = , + .clksel_con = , + CRU_DIV_SET(,,), +}; +#endif +GATE_CLK(otgphy0, clk_12m, OTGPHY0); +GATE_CLK(otgphy1, clk_12m, OTGPHY1); +/****************saradc*******************/ +static struct clk clk_saradc = { + .name = "saradc", + .parent = &xin24m, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .mode = gate_mode, + .gate_idx = CLK_GATE_SARADC_SRC, + .clksel_con = CRU_CLKSELS_CON(24), + CRU_DIV_SET(0xff,8,256), +}; +/****************gpu_pre*******************/ +// name: gpu_aclk +static struct clk *clk_gpu_pre_parents[] = SELECT_FROM_2PLLS; +static struct clk clk_gpu_pre = { + .name = "gpu_pre", + .parent = &general_pll_clk, + .mode = gate_mode, + .gate_idx = CLK_GATE_GPU_PRE, + .recalc = clksel_recalc_div, + .set_rate = clkset_rate_freediv_autosel_parents, + .round_rate = clk_freediv_round_autosel_parents_rate, + .clksel_con = CRU_CLKSELS_CON(34), + CRU_DIV_SET(0x1f, 0, 32), + CRU_PARENTS_SET(clk_gpu_pre_parents), +}; +/****************uart*******************/ +static int clk_uart_fracdiv_set_rate(struct clk *clk, unsigned long rate) +{ + u32 numerator, denominator; + //clk_uart0_div->clk_uart_pll->gpll/cpll + //clk->parent->parent + if(frac_div_get_seting(rate,clk->parent->parent->rate, + &numerator,&denominator)==0) + { + clk_set_rate_nolock(clk->parent,clk->parent->parent->rate);//PLL:DIV 1: + + cru_writel_frac(numerator << 16 | denominator, clk->clksel_con); + + CLKDATA_DBG("%s set rate=%lu,is ok\n",clk->name,rate); + } + else + { + CLKDATA_ERR("clk_frac_div can't get rate=%lu,%s\n",rate,clk->name); + return -ENOENT; + } + return 0; +} +#define UART_SRC_DIV 0 +#define UART_SRC_FRAC 1 +#define UART_SRC_24M 2 +static int clk_uart_set_rate(struct clk *clk, unsigned long rate) +{ + int ret = 0; + struct clk *parent; + + if(rate==clk->parents[UART_SRC_24M]->rate)//24m + { + parent = clk->parents[UART_SRC_24M]; + } + else if((long)clk_round_rate_nolock(clk->parents[UART_SRC_DIV], rate)==rate) + { + parent = clk->parents[UART_SRC_DIV]; + } + else + { + parent = clk->parents[UART_SRC_FRAC]; + } + + + + CLKDATA_DBG(" %s set rate=%lu parent %s(old %s)\n", + clk->name,rate,parent->name,clk->parent->name); + + + if(parent!=clk->parents[UART_SRC_24M]) + { + ret = clk_set_rate_nolock(parent,rate); + if (ret) + { + CLKDATA_DBG("%s set rate%lu err\n",clk->name,rate); + return ret; + } + } + + if (clk->parent != parent) + { + ret = clk_set_parent_nolock(clk, parent); + if (ret) + { + CLKDATA_DBG("%s can't get rate%lu,reparent err\n",clk->name,rate); + return ret; + } + } + + + return ret; +} + + +static struct clk *clk_uart_pll_src_parents[] = SELECT_FROM_2PLLS; +static struct clk clk_uart_pll = { + .name = "uart_pll", + .parent = &general_pll_clk, + .clksel_con = CRU_CLKSELS_CON(12), + CRU_SRC_SET(0x1, 15), + CRU_PARENTS_SET(clk_uart_pll_src_parents), +}; +//static struct clk clk_uart0_div_parents = SELECT_FROM_2PLLS; +//static struct clk clk_uart1_div_parents = SELECT_FROM_2PLLS; +//static struct clk clk_uart2_div_parents = SELECT_FROM_2PLLS; +static struct clk clk_uart0_div = { + .name = "uart0_div", + .parent = &clk_uart_pll, + .mode = gate_mode, + .gate_idx = CLK_GATE_UART0_SRC, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .round_rate = clksel_freediv_round_rate, + .clksel_con = CRU_CLKSELS_CON(13), + CRU_DIV_SET(0x7f, 0, 64), +}; +static struct clk clk_uart1_div = { + .name = "uart1_div", + .parent = &clk_uart_pll, + .mode = gate_mode, + .gate_idx = CLK_GATE_UART1_SRC, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .round_rate = clksel_freediv_round_rate, + .clksel_con = CRU_CLKSELS_CON(15), + CRU_DIV_SET(0x7f, 0, 64), +}; +static struct clk clk_uart2_div = { + .name = "uart2_div", + .parent = &clk_uart_pll, + .mode = gate_mode, + .gate_idx = CLK_GATE_UART2_SRC, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .round_rate = clksel_freediv_round_rate, + .clksel_con = CRU_CLKSELS_CON(15), + CRU_DIV_SET(0x7f, 0, 64), +}; +static struct clk clk_uart0_frac_div = { + .name = "uart0_frac_div", + .parent = &clk_uart0_div, + .mode = gate_mode, + .gate_idx = CLK_GATE_UART0_FRAC_SRC, + .recalc = clksel_recalc_frac, + .set_rate = clk_uart_fracdiv_set_rate, + .clksel_con = CRU_CLKSELS_CON(17), +}; +static struct clk clk_uart1_frac_div = { + .name = "uart1_frac_div", + .parent = &clk_uart1_div, + .mode = gate_mode, + .gate_idx = CLK_GATE_UART1_FRAC_SRC, + .recalc = clksel_recalc_frac, + .set_rate = clk_uart_fracdiv_set_rate, + .clksel_con = CRU_CLKSELS_CON(18), +}; +static struct clk clk_uart2_frac_div = { + .name = "uart2_frac_div", + .parent = &clk_uart2_div, + .mode = gate_mode, + .gate_idx = CLK_GATE_UART2_FRAC_SRC, + .recalc = clksel_recalc_frac, + .set_rate = clk_uart_fracdiv_set_rate, + .clksel_con = CRU_CLKSELS_CON(19), +}; + +static struct clk *clk_uart0_parents[] = {&clk_uart0_div, &clk_uart0_frac_div, &xin24m}; +static struct clk *clk_uart1_parents[] = {&clk_uart1_div, &clk_uart1_frac_div, &xin24m}; +static struct clk *clk_uart2_parents[] = {&clk_uart2_div, &clk_uart2_frac_div, &xin24m}; +static struct clk clk_uart0= { + .name = "uart0", + .parent = &xin24m, + .set_rate = clk_uart_set_rate, + .clksel_con = CRU_CLKSELS_CON(13), + CRU_SRC_SET(0x3, 8), + CRU_PARENTS_SET(clk_uart0_parents), +}; +static struct clk clk_uart1= { + .name = "uart1", + .parent = &xin24m, + .set_rate = clk_uart_set_rate, + .clksel_con = CRU_CLKSELS_CON(14), + CRU_SRC_SET(0x3, 8), + CRU_PARENTS_SET(clk_uart1_parents), +}; +static struct clk clk_uart2= { + .name = "uart2", + .parent = &xin24m, + .set_rate = clk_uart_set_rate, + .clksel_con = CRU_CLKSELS_CON(15), + CRU_SRC_SET(0x3, 8), + CRU_PARENTS_SET(clk_uart2_parents), +}; +/****************sub clock---pre*******************/ +/*************************aclk_cpu***********************/ +GATE_CLK(aclk_intmem, aclk_cpu_pre, ACLK_INTMEM); +GATE_CLK(aclk_strc_sys, aclk_cpu_pre, ACLK_STRC_SYS); + +/*************************hclk_cpu***********************/ +//FIXME +//GATE_CLK(hclk_cpubus, hclk_cpu_pre, HCLK_CPUBUS); +GATE_CLK(hclk_rom, hclk_cpu_pre, HCLK_ROM); + +/*************************pclk_cpu***********************/ +//FIXME +//GATE_CLK(pclk_hdmi, pclk_cpu_pre, PCLK_HDMI); +GATE_CLK(pclk_ddrupctl, pclk_cpu_pre, PCLK_DDRUPCTL); +GATE_CLK(pclk_grf, pclk_cpu_pre, PCLK_GRF); +GATE_CLK(pclk_acodec, pclk_cpu_pre, PCLK_ACODEC); + +/*************************aclk_periph********************/ +GATE_CLK(aclk_dma2, aclk_periph_pre, ACLK_DMAC2); +GATE_CLK(aclk_peri_niu, aclk_periph_pre, ACLK_PERI_NIU); +GATE_CLK(aclk_cpu_peri, aclk_periph_pre, ACLK_CPU_PERI); +GATE_CLK(aclk_peri_axi_matrix, aclk_periph_pre, ACLK_PERI_AXI_MATRIX); +//FIXME +//GATE_CLK(aclk_gps, aclk_periph_pre, ACLK_GPS); + +/*************************hclk_periph***********************/ +GATE_CLK(hclk_peri_axi_matrix, hclk_periph_pre, HCLK_PERI_AXI_MATRIX); +GATE_CLK(hclk_peri_ahb_arbi, hclk_periph_pre, HCLK_PERI_ARBI); +GATE_CLK(hclk_nandc, hclk_periph_pre, HCLK_NANDC); +GATE_CLK(hclk_usb_peri, hclk_periph_pre, HCLK_USB_PERI); +GATE_CLK(hclk_otg0, hclk_periph_pre, HCLK_OTG0); +GATE_CLK(hclk_otg1, hclk_periph_pre, HCLK_OTG1); +GATE_CLK(hclk_i2s, hclk_periph_pre, HCLK_I2S); +GATE_CLK(hclk_sdmmc0, hclk_periph_pre, HCLK_SDMMC0); +GATE_CLK(hclk_sdio, hclk_periph_pre, HCLK_SDIO); +GATE_CLK(hclk_emmc, hclk_periph_pre, HCLK_EMMC); + +/*************************pclk_periph***********************/ +GATE_CLK(pclk_peri_axi_matrix, pclk_periph_pre, PCLK_PERI_AXI_MATRIX); +GATE_CLK(pclk_pwm01, pclk_periph_pre, PCLK_PWM01); +GATE_CLK(pclk_wdt, pclk_periph_pre, PCLK_WDT); +GATE_CLK(pclk_spi0, pclk_periph_pre, PCLK_SPI0); +GATE_CLK(pclk_uart0, pclk_periph_pre, PCLK_UART0); +GATE_CLK(pclk_uart1, pclk_periph_pre, PCLK_UART1); +GATE_CLK(pclk_uart2, pclk_periph_pre, PCLK_UART2); +GATE_CLK(pclk_i2c0, pclk_periph_pre, PCLK_I2C0); +GATE_CLK(pclk_i2c1, pclk_periph_pre, PCLK_I2C1); +GATE_CLK(pclk_i2c2, pclk_periph_pre, PCLK_I2C2); +GATE_CLK(pclk_i2c3, pclk_periph_pre, PCLK_I2C3); +GATE_CLK(pclk_timer0, pclk_periph_pre, PCLK_TIMER0); +GATE_CLK(pclk_timer1, pclk_periph_pre, PCLK_TIMER1); +GATE_CLK(pclk_gpio0, pclk_periph_pre, PCLK_GPIO0); +GATE_CLK(pclk_gpio1, pclk_periph_pre, PCLK_GPIO1); +GATE_CLK(pclk_gpio2, pclk_periph_pre, PCLK_GPIO2); +GATE_CLK(pclk_gpio3, pclk_periph_pre, PCLK_GPIO3); +GATE_CLK(pclk_saradc, pclk_periph_pre, PCLK_SARADC); +GATE_CLK(pclk_efuse, pclk_periph_pre, PCLK_EFUSE); + +/*************************aclk_vio***********************/ +GATE_CLK(aclk_vio0, aclk_vio_pre, ACLK_VIO0); +GATE_CLK(aclk_lcdc0, aclk_vio_pre, ACLK_LCDC0); +GATE_CLK(aclk_cif0, aclk_vio_pre, ACLK_CIF); +GATE_CLK(aclk_rga, aclk_vio_pre, ACLK_RGA); + +/*************************hclk_vio***********************/ +GATE_CLK(hclk_lcdc0, hclk_vio_pre, HCLK_LCDC0); +GATE_CLK(hclk_cif0, hclk_vio_pre, HCLK_CIF); +GATE_CLK(hclk_rga, hclk_vio_pre, HCLK_RGA); +GATE_CLK(hclk_vio_bus, hclk_vio_pre, HCLK_VIO_BUS); + +/* Power domain, not exist in fact*/ +enum pmu_power_domain { + PD_A9_0 = 0, + PD_A9_1, + PD_ALIVE, + PD_RTC, + PD_SCU, + PD_CPU, + PD_PERI = 6, + PD_VIO, + PD_VIDEO, + PD_VCODEC = PD_VIDEO, + PD_GPU, + PD_DBG, +}; + +static int pm_off_mode(struct clk *clk, int on) +{ + return 0; +} +static struct clk pd_peri = { + .name = "pd_peri", + .flags = IS_PD, + .mode = pm_off_mode, + .gate_idx = PD_PERI, +}; + +static int pd_display_mode(struct clk *clk, int on) +{ + return 0; +} + +static struct clk pd_display = { + .name = "pd_display", + .flags = IS_PD, + .mode = pd_display_mode, + .gate_idx = PD_VIO, +}; + +static struct clk pd_lcdc0 = { + .parent = &pd_display, + .name = "pd_lcdc0", +}; +static struct clk pd_lcdc1 = { + .parent = &pd_display, + .name = "pd_lcdc1", +}; +static struct clk pd_cif0 = { + .parent = &pd_display, + .name = "pd_cif0", +}; +static struct clk pd_cif1 = { + .parent = &pd_display, + .name = "pd_cif1", +}; +static struct clk pd_rga = { + .parent = &pd_display, + .name = "pd_rga", +}; +static struct clk pd_ipp = { + .parent = &pd_display, + .name = "pd_ipp", +}; +static int pd_video_mode(struct clk *clk, int on) +{ + return 0; +} + +static struct clk pd_video = { + .name = "pd_video", + .flags = IS_PD, + .mode = pd_video_mode, + .gate_idx = PD_VIDEO, +}; + +static int pd_gpu_mode(struct clk *clk, int on) +{ + return 0; +} + +static struct clk pd_gpu = { + .name = "pd_gpu", + .flags = IS_PD, + .mode = pd_gpu_mode, + .gate_idx = PD_GPU, +}; +static struct clk pd_dbg = { + .name = "pd_dbg", + .flags = IS_PD, + .mode = pm_off_mode, + .gate_idx = PD_DBG, +}; + +#define PD_CLK(name) \ +{\ + .dev_id = NULL,\ + .con_id = #name,\ + .clk = &name,\ +} +/* Power domain END, not exist in fact*/ + +#define CLK(dev, con, ck) \ +{\ + .dev_id = dev,\ + .con_id = con,\ + .clk = ck,\ +} + +#define CLK_GATE_NODEV(name) \ +{\ + .dev_id = NULL,\ + .con_id = #name,\ + .clk = &clk_##name,\ +} + +static struct clk_lookup clks[] = { + CLK(NULL, "xin24m", &xin24m), + CLK(NULL, "xin12m", &clk_12m), + + CLK(NULL, "arm_pll", &arm_pll_clk), + CLK(NULL, "ddr_pll", &ddr_pll_clk), + CLK(NULL, "codec_pll", &codec_pll_clk), + CLK(NULL, "general_pll", &general_pll_clk), + + CLK(NULL, "ddrphy2x", &clk_ddrphy2x), + CLK(NULL, "ddrphy", &clk_ddrphy), + CLK(NULL, "ddrc", &clk_ddrc), + + CLK(NULL, "core_pre", &clk_core_pre), + CLK(NULL, "core_periph", &clk_core_periph), + CLK(NULL, "core_periph_en", &clken_core_periph), + CLK(NULL, "l2c", &clk_l2c), + CLK(NULL, "aclk_core_pre", &aclk_core_pre), + + CLK(NULL, "cpu_div", &clk_cpu_div), + CLK(NULL, "aclk_cpu_pre", &aclk_cpu_pre), + CLK(NULL, "pclk_cpu_pre", &pclk_cpu_pre), + CLK(NULL, "hclk_cpu_pre", &hclk_cpu_pre), + + CLK(NULL, "aclk_vepu", &aclk_vepu), + CLK(NULL, "aclk_vdpu", &aclk_vdpu), + CLK(NULL, "hclk_vepu", &hclk_vepu), + CLK(NULL, "hclk_vdpu", &hclk_vdpu), + + CLK(NULL, "aclk_vio_pre", &aclk_vio_pre), + CLK(NULL, "hclk_vio_pre", &hclk_vio_pre), + + CLK(NULL, "peri_aclk", &peri_aclk), + CLK(NULL, "peri_pclk", &peri_pclk), + CLK(NULL, "peri_hclk", &peri_hclk), + + CLK(NULL, "timer0", &clk_timer0), + CLK(NULL, "timer1", &clk_timer1), + + CLK("rk29xx_spim.0", "spi", &clk_spi), + + CLK("rk29_sdmmc.0", "mmc", &clk_sdmmc0), + //CLK("rk29_sdmmc.0", "mmc_sample", &clk_sdmmc0_sample), + //CLK("rk29_sdmmc.0", "mmc_drv", &clk_sdmmc0_drv), + + CLK("rk29_sdmmc.1", "mmc", &clk_sdio), + //CLK("rk29_sdmmc.1", "mmc_sample", &clk_sdio_sample), + //CLK("rk29_sdmmc.1", "mmc_drv", &clk_sdio_drv), + + CLK(NULL, "emmc", &clk_emmc), + //CLK(NULL, "emmc_sample", &clk_emmc_sample), + //CLK(NULL, "emmc_drv", &clk_emmc_drv), + + CLK(NULL, "dclk_lcdc0", &dclk_lcdc), + CLK(NULL, "sclk_lcdc0", &sclk_lcdc), + //FIXME + //CLK(NULL, "hclk_gps", &hclk_gps), + + CLK(NULL, "cif_out_div", &clk_cif_out_div), + CLK(NULL, "cif0_out", &clk_cif_out), + CLK(NULL, "pclkin_cif0", &pclkin_cif0), + CLK(NULL, "inv_cif0", &inv_cif0), + CLK(NULL, "cif0_in", &cif0_in), + + CLK(NULL, "i2s_pll", &clk_i2s_pll), + CLK("rk29_i2s.0", "i2s_div", &clk_i2s_div), + CLK("rk29_i2s.0", "i2s_frac_div", &clk_i2s_frac_div), + CLK("rk29_i2s.0", "i2s", &clk_i2s), + + CLK(NULL, "otgphy0", &clk_otgphy0), + CLK(NULL, "otgphy1", &clk_otgphy1), + CLK(NULL, "saradc", &clk_saradc), + CLK(NULL, "gpu_pre", &clk_gpu_pre), + + CLK(NULL, "uart_pll", &clk_uart_pll), + CLK("rk_serial.0", "uart_div", &clk_uart0_div), + CLK("rk_serial.1", "uart_div", &clk_uart1_div), + CLK("rk_serial.2", "uart_div", &clk_uart2_div), + CLK("rk_serial.0", "uart_frac_div", &clk_uart0_frac_div), + CLK("rk_serial.1", "uart_frac_div", &clk_uart1_frac_div), + CLK("rk_serial.2", "uart_frac_div", &clk_uart2_frac_div), + CLK("rk_serial.0", "uart", &clk_uart0), + CLK("rk_serial.1", "uart", &clk_uart1), + CLK("rk_serial.2", "uart", &clk_uart2), + + CLK(NULL, "aclk_periph_pre", &aclk_periph_pre), + CLK(NULL, "hclk_periph_pre", &hclk_periph_pre), + CLK(NULL, "pclk_periph_pre", &pclk_periph_pre), + + /*********fixed clock ******/ + CLK_GATE_NODEV(aclk_intmem), + CLK_GATE_NODEV(aclk_strc_sys), + + //FIXME + //CLK_GATE_NODEV(hclk_cpubus), + CLK_GATE_NODEV(hclk_rom), + + //FIXME + //CLK_GATE_NODEV(pclk_hdmi), + CLK_GATE_NODEV(pclk_ddrupctl), + CLK_GATE_NODEV(pclk_grf), + CLK_GATE_NODEV(pclk_acodec), + + CLK_GATE_NODEV(aclk_dma2), + CLK_GATE_NODEV(aclk_peri_niu), + CLK_GATE_NODEV(aclk_cpu_peri), + CLK_GATE_NODEV(aclk_peri_axi_matrix), + //FIXME + //CLK_GATE_NODEV(aclk_gps), + + CLK_GATE_NODEV(hclk_peri_axi_matrix), + CLK_GATE_NODEV(hclk_peri_ahb_arbi), + CLK_GATE_NODEV(hclk_nandc), + CLK_GATE_NODEV(hclk_usb_peri), + CLK_GATE_NODEV(hclk_otg0), + CLK_GATE_NODEV(hclk_otg1), + CLK_GATE_NODEV(hclk_i2s), + CLK("rk29_sdmmc.0", "hclk_mmc", &clk_hclk_sdmmc0), + CLK("rk29_sdmmc.1", "hclk_mmc", &clk_hclk_sdio), + CLK("rk29_sdmmc.2", "hclk_mmc", &clk_hclk_emmc), + + CLK_GATE_NODEV(pclk_peri_axi_matrix), + CLK(NULL, "pwm01", &clk_pclk_pwm01), + CLK_GATE_NODEV(pclk_wdt), + CLK_GATE_NODEV(pclk_spi0), + CLK("rk_serial.0", "pclk_uart", &clk_pclk_uart0), + CLK("rk_serial.1", "pclk_uart", &clk_pclk_uart1), + CLK("rk_serial.2", "pclk_uart", &clk_pclk_uart2), + CLK("rk30_i2c.0", "i2c", &clk_pclk_i2c0), + CLK("rk30_i2c.1", "i2c", &clk_pclk_i2c1), + CLK("rk30_i2c.2", "i2c", &clk_pclk_i2c2), + CLK("rk30_i2c.3", "i2c", &clk_pclk_i2c3), + CLK_GATE_NODEV(pclk_timer0), + CLK_GATE_NODEV(pclk_timer1), + CLK_GATE_NODEV(pclk_gpio0), + CLK_GATE_NODEV(pclk_gpio1), + CLK_GATE_NODEV(pclk_gpio2), + CLK_GATE_NODEV(pclk_gpio3), + CLK_GATE_NODEV(pclk_saradc), + CLK_GATE_NODEV(pclk_efuse), + + CLK_GATE_NODEV(aclk_vio0), + CLK_GATE_NODEV(aclk_lcdc0), + CLK_GATE_NODEV(aclk_cif0), + CLK_GATE_NODEV(aclk_rga), + + CLK_GATE_NODEV(hclk_lcdc0), + CLK_GATE_NODEV(hclk_cif0), + CLK_GATE_NODEV(hclk_rga), + CLK_GATE_NODEV(hclk_vio_bus), + + /* Power domain, not exist in fact*/ + PD_CLK(pd_peri), + PD_CLK(pd_display), + PD_CLK(pd_video), + PD_CLK(pd_lcdc0), + PD_CLK(pd_lcdc1), + PD_CLK(pd_cif0), + PD_CLK(pd_cif1), + PD_CLK(pd_rga), + PD_CLK(pd_ipp), + PD_CLK(pd_video), + PD_CLK(pd_gpu), + PD_CLK(pd_dbg), + +}; + +static void __init rk30_init_enable_clocks(void) +{ + CLKDATA_DBG("ENTER %s\n", __func__); + clk_enable_nolock(&clk_core_pre); //cpu + clk_enable_nolock(&clk_core_periph); + clk_enable_nolock(&aclk_cpu_pre); + clk_enable_nolock(&hclk_cpu_pre); + clk_enable_nolock(&pclk_cpu_pre); + + clk_enable_nolock(&aclk_periph_pre); + clk_enable_nolock(&pclk_periph_pre); + clk_enable_nolock(&hclk_periph_pre); + +#if CONFIG_RK_DEBUG_UART == 0 + clk_enable_nolock(&clk_uart0); + clk_enable_nolock(&clk_pclk_uart0); + +#elif CONFIG_RK_DEBUG_UART == 1 + clk_enable_nolock(&clk_uart1); + clk_enable_nolock(&clk_pclk_uart1); + +#elif CONFIG_RK_DEBUG_UART == 2 + clk_enable_nolock(&clk_uart2); + clk_enable_nolock(&clk_pclk_uart2); +#endif + + /*************************aclk_cpu***********************/ + clk_enable_nolock(&clk_aclk_intmem); + clk_enable_nolock(&clk_aclk_strc_sys); + + /*************************hclk_cpu***********************/ + clk_enable_nolock(&clk_hclk_rom); + + /*************************pclk_cpu***********************/ + clk_enable_nolock(&clk_pclk_ddrupctl); + clk_enable_nolock(&clk_pclk_grf); + + /*************************aclk_periph***********************/ + clk_enable_nolock(&clk_aclk_dma2); + clk_enable_nolock(&clk_aclk_peri_niu); + clk_enable_nolock(&clk_aclk_cpu_peri); + clk_enable_nolock(&clk_aclk_peri_axi_matrix); + + /*************************hclk_periph***********************/ + clk_enable_nolock(&clk_hclk_peri_axi_matrix); + clk_enable_nolock(&clk_hclk_peri_ahb_arbi); + clk_enable_nolock(&clk_hclk_nandc); + + /*************************pclk_periph***********************/ + clk_enable_nolock(&clk_pclk_peri_axi_matrix); + /*************************hclk_vio***********************/ + clk_enable_nolock(&clk_hclk_vio_bus); +} + +#ifdef CONFIG_PROC_FS + +static void dump_clock(struct seq_file *s, struct clk *clk, int deep,const struct list_head *root_clocks) +{ + struct clk* ck; + int i; + unsigned long rate = clk->rate; + //CLKDATA_DBG("dump_clock %s\n",clk->name); + for (i = 0; i < deep; i++) + seq_printf(s, " "); + + seq_printf(s, "%-11s ", clk->name); + + if ((clk->mode == gate_mode) && (clk->gate_idx < CLK_GATE_MAX)) { + int idx = clk->gate_idx; + u32 v; + v = cru_readl(CLK_GATE_CLKID_CONS(idx))&((0x1)<<(idx%16)); + seq_printf(s, "%s ", v ? "off" : "on "); + } + + if (clk->pll) + { + u32 pll_mode; + u32 pll_id=clk->pll->id; + pll_mode=cru_readl(CRU_MODE_CON)&PLL_MODE_MSK(pll_id); + if(pll_mode==PLL_MODE_SLOW(pll_id)) + seq_printf(s, "slow "); + else if(pll_mode==PLL_MODE_NORM(pll_id)) + seq_printf(s, "normal "); + if(cru_readl(PLL_CONS(pll_id,3)) & PLL_BYPASS) + seq_printf(s, "bypass "); + } + else if(clk == &ddr_pll_clk) { + rate = clk->recalc(clk); + } + + if (rate >= MHZ) { + if (rate % MHZ) + seq_printf(s, "%ld.%06ld MHz", rate / MHZ, rate % MHZ); + else + seq_printf(s, "%ld MHz", rate / MHZ); + } else if (rate >= KHZ) { + if (rate % KHZ) + seq_printf(s, "%ld.%03ld KHz", rate / KHZ, rate % KHZ); + else + seq_printf(s, "%ld KHz", rate / KHZ); + } else { + seq_printf(s, "%ld Hz", rate); + } + + seq_printf(s, " usecount = %d", clk->usecount); + + if (clk->parent) + seq_printf(s, " parent = %s", clk->parent->name); + + seq_printf(s, "\n"); + + list_for_each_entry(ck, root_clocks, node) { + if (ck->parent == clk) + dump_clock(s, ck, deep + 1,root_clocks); + } +} + +static void dump_regs(struct seq_file *s) +{ + int i=0; + seq_printf(s, "\nPLL(id=0 apll,id=1,dpll,id=2,cpll,id=3 cpll)\n"); + seq_printf(s, "\nPLLRegisters:\n"); + for(i=0;i>1; + pclk_p = aclk_p>>2; + break; + case 1188*MHZ: + aclk_p = aclk_p>>3;// 0 + hclk_p = aclk_p>>1; + pclk_p = aclk_p>>2; + + case 297 * MHZ: + aclk_p = ppll_rate>>1; + hclk_p = aclk_p>>0; + pclk_p = aclk_p>>1; + break; + + case 300 * MHZ: + aclk_p = ppll_rate>>1; + hclk_p = aclk_p>>0; + pclk_p = aclk_p>>1; + break; + default: + aclk_p = 150 * MHZ; + hclk_p = 150 * MHZ; + pclk_p = 75 * MHZ; + break; + } + clk_set_parent_nolock(&aclk_periph_pre, &general_pll_clk); + clk_set_rate_nolock(&aclk_periph_pre, aclk_p); + clk_set_rate_nolock(&hclk_periph_pre, hclk_p); + clk_set_rate_nolock(&pclk_periph_pre, pclk_p); +} + + +#define CLK_FLG_MAX_I2S_12288KHZ (1<<1) +#define CLK_FLG_MAX_I2S_22579_2KHZ (1<<2) +#define CLK_FLG_MAX_I2S_24576KHZ (1<<3) +#define CLK_FLG_MAX_I2S_49152KHZ (1<<4) + +void rk2928_clock_common_i2s_init(void) +{ + struct clk *max_clk,*min_clk; + unsigned long i2s_rate; + //20 times + if(rk2928_clock_flags&CLK_FLG_MAX_I2S_49152KHZ) + { + i2s_rate=49152000; + }else if(rk2928_clock_flags&CLK_FLG_MAX_I2S_24576KHZ) + { + i2s_rate=24576000; + } + else if(rk2928_clock_flags&CLK_FLG_MAX_I2S_22579_2KHZ) + { + i2s_rate=22579000; + } + else if(rk2928_clock_flags&CLK_FLG_MAX_I2S_12288KHZ) + { + i2s_rate=12288000; + } + else + { + i2s_rate=49152000; + } + + if(((i2s_rate*20)<=general_pll_clk.rate)||!(general_pll_clk.rate%i2s_rate)) + { + clk_set_parent_nolock(&clk_i2s_pll, &general_pll_clk); + } + else if(((i2s_rate*20)<=codec_pll_clk.rate)||!(codec_pll_clk.rate%i2s_rate)) + { + clk_set_parent_nolock(&clk_i2s_pll, &codec_pll_clk); + } + else + { + if(general_pll_clk.rate>codec_pll_clk.rate) + clk_set_parent_nolock(&clk_i2s_pll, &general_pll_clk); + else + clk_set_parent_nolock(&clk_i2s_pll, &codec_pll_clk); + } + +} +static void __init rk2928_clock_common_init(unsigned long gpll_rate,unsigned long cpll_rate) +{ + CLKDATA_DBG("ENTER %s\n", __func__); + + clk_set_rate_nolock(&clk_core_pre, 650 * MHZ);//816 + //general + clk_set_rate_nolock(&general_pll_clk, gpll_rate); + //code pll + clk_set_rate_nolock(&codec_pll_clk, cpll_rate); + //periph clk + periph_clk_set_init(); + + //i2s + rk2928_clock_common_i2s_init(); + + // spi + clk_set_rate_nolock(&clk_spi, clk_spi.parent->rate); + + // uart +#if 0 + clk_set_parent_nolock(&clk_uart_pll, &codec_pll_clk); +#else + clk_set_parent_nolock(&clk_uart_pll, &general_pll_clk); +#endif + //mac + // FIXME +#if 0 + if(!(gpll_rate%(50*MHZ))) + clk_set_parent_nolock(&clk_mac_pll_div, &general_pll_clk); + else if(!(ddr_pll_clk.rate%(50*MHZ))) + clk_set_parent_nolock(&clk_mac_pll_div, &ddr_pll_clk); + else + CRU_PRINTK_ERR("mac can't get 50mhz\n"); +#endif + //hsadc + //auto pll sel + //clk_set_parent_nolock(&clk_hsadc_pll_div, &general_pll_clk); + + //lcdc1 hdmi + //clk_set_parent_nolock(&dclk_lcdc1_div, &general_pll_clk); + + //lcdc0 lcd auto sel pll + //clk_set_parent_nolock(&dclk_lcdc0_div, &general_pll_clk); + + //cif + clk_set_parent_nolock(&clk_cif_out_div, &general_pll_clk); + + //axi lcdc auto sel + //clk_set_parent_nolock(&aclk_lcdc0, &general_pll_clk); + //clk_set_parent_nolock(&aclk_lcdc1, &general_pll_clk); + // FIXME +#if 0 + clk_set_rate_nolock(&aclk_lcdc0_ipp_parent, 300*MHZ); + clk_set_rate_nolock(&aclk_lcdc1_rga_parent, 300*MHZ); +#endif + //axi vepu auto sel + //clk_set_parent_nolock(&aclk_vepu, &general_pll_clk); + //clk_set_parent_nolock(&aclk_vdpu, &general_pll_clk); + + clk_set_rate_nolock(&aclk_vepu, 300*MHZ); + clk_set_rate_nolock(&aclk_vdpu, 300*MHZ); + //gpu auto sel + //clk_set_parent_nolock(&clk_gpu, &general_pll_clk); + // +} +void __init _rk2928_clock_data_init(unsigned long gpll,unsigned long cpll,int flags) +{ + struct clk_lookup *clk; + clk_register_dump_ops(&dump_ops); + clk_register_default_ops_clk(&def_ops_clk); + + rk2928_clock_flags = flags; + + CLKDATA_DBG("%s total %d clks\n", __func__, ARRAY_SIZE(clks)); + for (clk = clks; clk < clks + ARRAY_SIZE(clks); clk++) { + CLKDATA_DBG("%s add dev_id=%s, con_id=%s\n", + __func__, clk->dev_id ? clk->dev_id : "NULL", clk->con_id ? clk->con_id : "NULL"); + clkdev_add(clk); + clk_register(clk->clk); + } + + CLKDATA_DBG("clk_recalculate_root_clocks_nolock\n"); + clk_recalculate_root_clocks_nolock(); + + loops_per_jiffy = CLK_LOOPS_RECALC(arm_pll_clk.rate); + + /* + * Only enable those clocks we will need, let the drivers + * enable other clocks as necessary + */ + rk30_init_enable_clocks(); + + /* + * Disable any unused clocks left on by the bootloader + */ + //clk_disable_unused(); + CLKDATA_DBG("rk2928_clock_common_init, gpll=%lu, cpll=%lu\n", gpll, cpll); + rk2928_clock_common_init(gpll, cpll); + preset_lpj = loops_per_jiffy; + + CLKDATA_DBG("%s clks init finish\n", __func__); +} + + +void __init rk2928_clock_data_init(unsigned long gpll,unsigned long cpll,u32 flags) +{ + printk("version: 2012-8-6\n"); + _rk2928_clock_data_init(gpll,cpll,flags); + //rk2928_dvfs_init(); +} + diff --git a/arch/arm/mach-rk2928/include/mach/board.h b/arch/arm/mach-rk2928/include/mach/board.h index 1e1059a7d3ba..9292adca4591 100644 --- a/arch/arm/mach-rk2928/include/mach/board.h +++ b/arch/arm/mach-rk2928/include/mach/board.h @@ -57,5 +57,35 @@ struct eeti_egalax_platform_data{ }; #endif +enum _periph_pll { + periph_pll_1485mhz = 148500000, + periph_pll_297mhz = 297000000, + periph_pll_300mhz = 300000000, + periph_pll_1188mhz = 1188000000, /* for box*/ +}; +enum _codec_pll { + codec_pll_360mhz = 360000000, /* for HDMI */ + codec_pll_408mhz = 408000000, + codec_pll_456mhz = 456000000, + codec_pll_504mhz = 504000000, + codec_pll_552mhz = 552000000, /* for HDMI */ + codec_pll_600mhz = 600000000, + codec_pll_742_5khz = 742500000, + codec_pll_798mhz = 798000000, + codec_pll_1064mhz = 1064000000, + codec_pll_1188mhz = 1188000000, +}; + +//max i2s rate +#define CLK_FLG_MAX_I2S_12288KHZ (1<<1) +#define CLK_FLG_MAX_I2S_22579_2KHZ (1<<2) +#define CLK_FLG_MAX_I2S_24576KHZ (1<<3) +#define CLK_FLG_MAX_I2S_49152KHZ (1<<4) + +#define RK30_CLOCKS_DEFAULT_FLAGS (CLK_FLG_MAX_I2S_12288KHZ/*|CLK_FLG_EXT_27MHZ*/) +#define periph_pll_default periph_pll_297mhz +#define codec_pll_default codec_pll_798mhz +//#define codec_pll_default codec_pll_1064mhz + #endif diff --git a/arch/arm/mach-rk2928/include/mach/clock.h b/arch/arm/mach-rk2928/include/mach/clock.h new file mode 100755 index 000000000000..a94d6c851e3d --- /dev/null +++ b/arch/arm/mach-rk2928/include/mach/clock.h @@ -0,0 +1,81 @@ +/* arch/arm/mach-rk29/include/mach/clock.h + * + * Copyright (C) 2011 ROCKCHIP, Inc. + * + * 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. + * + */ + +#ifndef __ASM_ARCH_RK30_CLOCK_H +#define __ASM_ARCH_RK30_CLOCK_H + +/** + * struct clk_notifier_data - rate data to pass to the notifier callback + * @clk: struct clk * being changed + * @old_rate: previous rate of this clock + * @new_rate: new rate of this clock + * + * For a pre-notifier, old_rate is the clock's rate before this rate + * change, and new_rate is what the rate will be in the future. For a + * post-notifier, old_rate and new_rate are both set to the clock's + * current rate (this was done to optimize the implementation). + */ +struct clk_notifier_data { + struct clk *clk; + unsigned long old_rate; + unsigned long new_rate; +}; + +/* + * Clk notifier callback types + * + * Since the notifier is called with interrupts disabled, any actions + * taken by callbacks must be extremely fast and lightweight. + * + * CLK_PRE_RATE_CHANGE - called after all callbacks have approved the + * rate change, immediately before the clock rate is changed, to + * indicate that the rate change will proceed. Drivers must + * immediately terminate any operations that will be affected by + * the rate change. Callbacks must always return NOTIFY_DONE. + * + * CLK_ABORT_RATE_CHANGE: called if the rate change failed for some + * reason after CLK_PRE_RATE_CHANGE. In this case, all registered + * notifiers on the clock will be called with + * CLK_ABORT_RATE_CHANGE. Callbacks must always return + * NOTIFY_DONE. + * + * CLK_POST_RATE_CHANGE - called after the clock rate change has + * successfully completed. Callbacks must always return + * NOTIFY_DONE. + * + */ +#define CLK_PRE_RATE_CHANGE 1 +#define CLK_POST_RATE_CHANGE 2 +#define CLK_ABORT_RATE_CHANGE 3 + +#define CLK_PRE_ENABLE 4 +#define CLK_POST_ENABLE 5 +#define CLK_ABORT_ENABLE 6 + +#define CLK_PRE_DISABLE 7 +#define CLK_POST_DISABLE 8 +#define CLK_ABORT_DISABLE 9 + +struct notifier_block; + +extern int clk_notifier_register(struct clk *clk, struct notifier_block *nb); +extern int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb); + +#endif + + + + + diff --git a/arch/arm/mach-rk2928/include/mach/cru.h b/arch/arm/mach-rk2928/include/mach/cru.h new file mode 100755 index 000000000000..b22b9a7be564 --- /dev/null +++ b/arch/arm/mach-rk2928/include/mach/cru.h @@ -0,0 +1,563 @@ +#ifndef __MACH_CRU_H +#define __MACH_CRU_H + +enum rk_plls_id { + APLL_ID = 0, + DPLL_ID, + CPLL_ID, + GPLL_ID, + END_PLL_ID, +}; + +/*****cru reg offset*****/ + +#define CRU_MODE_CON 0x40 +#define CRU_CLKSEL_CON 0x44 +#define CRU_CLKGATE_CON 0xd0 +#define CRU_GLB_SRST_FST 0x100 +#define CRU_GLB_SRST_SND 0x104 +#define CRU_SOFTRST_CON 0x110 + +#define PLL_CONS(id, i) ((id) * 0x10 + ((i) * 4)) + +#define CRU_CLKSELS_CON_CNT (35) +#define CRU_CLKSELS_CON(i) (CRU_CLKSEL_CON + ((i) * 4)) + +#define CRU_CLKGATES_CON_CNT (10) +#define CRU_CLKGATES_CON(i) (CRU_CLKGATE_CON + ((i) * 4)) + +#define CRU_SOFTRSTS_CON_CNT (9) +#define CRU_SOFTRSTS_CON(i) (CRU_SOFTRST_CON + ((i) * 4)) + +#define CRU_MISC_CON (0x134) +#define CRU_GLB_CNT_TH (0x140) + +/*PLL_CON 0,1,2*/ +#define PLL_PWR_ON (1) +#define PLL_PWR_DN (0) +#define PLL_BYPASS (1 << 15) +#define PLL_NO_BYPASS (0 << 15) +//con0 +#define PLL_BYPASS_SHIFT (15) + +#define PLL_POSTDIV1_MASK (0x7) +#define PLL_POSTDIV1_SHIFT (12) +#define PLL_FBDIV_MASK (0xfff) +#define PLL_FBDIV_SHIFT (0) + +//con1 +#define PLL_RSTMODE_SHIFT (15) +#define PLL_RST_SHIFT (14) +#define PLL_PWR_DN_SHIFT (13) +#define PLL_DSMPD_SHIFT (12) +#define PLL_LOCK_SHIFT (10) + +#define PLL_POSTDIV2_MASK (0x7) +#define PLL_POSTDIV2_SHIFT (6) +#define PLL_REFDIV_MASK (0x3f) +#define PLL_REFDIV_SHIFT (0) + +//con2 +#define PLL_FOUT4PHASE_PWR_DN_SHIFT (27) +#define PLL_FOUTVCO_PWR_DN_SHIFT (26) +#define PLL_FOUTPOSTDIV_PWR_DN_SHIFT (25) +#define PLL_DAC_PWR_DN_SHIFT (24) + +#define PLL_FRAC_MASK (0xffffff) +#define PLL_FRAC_SHIFT (0) + +/********************************************************************/ +#define CRU_GET_REG_BIT_VAL(reg, bits_shift) (((reg) >> (bits_shift)) & (0x1)) +#define CRU_GET_REG_BITS_VAL(reg, bits_shift, msk) (((reg) >> (bits_shift)) & (msk)) +#define CRU_SET_BIT(val, bits_shift) (((val) & (0x1)) << (bits_shift)) +#define CRU_SET_BITS(val, bits_shift, msk) (((val) & (msk)) << (bits_shift)) +#define CRU_W_MSK(bits_shift, msk) ((msk) << ((bits_shift) + 16)) + +#define CRU_W_MSK_SETBITS(val, bits_shift, msk) (CRU_W_MSK(bits_shift, msk) \ + | CRU_SET_BITS(val, bits_shift, msk)) +#define CRU_W_MSK_SETBIT(val, bits_shift) (CRU_W_MSK(bits_shift, 0x1) \ + | CRU_SET_BIT(val, bits_shift)) + +#define PLL_SET_REFDIV(val) CRU_W_MSK_SETBITS(val, PLL_REFDIV_SHIFT, PLL_REFDIV_MASK) +#define PLL_SET_FBDIV(val) CRU_W_MSK_SETBITS(val, PLL_FBDIV_SHIFT, PLL_FBDIV_MASK) +#define PLL_SET_POSTDIV1(val) CRU_W_MSK_SETBITS(val, PLL_POSTDIV1_SHIFT, PLL_POSTDIV1_MASK) +#define PLL_SET_POSTDIV2(val) CRU_W_MSK_SETBITS(val, PLL_POSTDIV2_SHIFT, PLL_POSTDIV2_MASK) +#define PLL_SET_FRAC(val) CRU_SET_BITS(val, PLL_FRAC_SHIFT, PLL_FRAC_MASK) + +#define PLL_GET_REFDIV(reg) CRU_GET_REG_BITS_VAL(reg, PLL_REFDIV_SHIFT, PLL_REFDIV_MASK) +#define PLL_GET_FBDIV(reg) CRU_GET_REG_BITS_VAL(reg, PLL_FBDIV_SHIFT, PLL_FBDIV_MASK) +#define PLL_GET_POSTDIV1(reg) CRU_GET_REG_BITS_VAL(reg, PLL_POSTDIV1_SHIFT, PLL_POSTDIV1_MASK) +#define PLL_GET_POSTDIV2(reg) CRU_GET_REG_BITS_VAL(reg, PLL_POSTDIV2_SHIFT, PLL_POSTDIV2_MASK) +#define PLL_GET_FRAC(reg) CRU_GET_REG_BITS_VAL(reg, PLL_FRAC_SHIFT, PLL_FRAC_MASK) + +//#define APLL_SET_BYPASS(val) CRU_SET_BIT(val, PLL_BYPASS_SHIFT) +#define PLL_SET_DSMPD(val) CRU_SET_BIT(val, PLL_DSMPD_SHIFT) +#define PLL_GET_DSMPD(reg) CRU_GET_REG_BIT_VAL(reg, PLL_DSMPD_SHIFT) +/*******************MODE BITS***************************/ +#define PLL_MODE_MSK(id) (0x1 << ((id) * 4)) +#define PLL_MODE_SHIFT(id) ((id) * 4) +#define PLL_MODE_SLOW(id) (CRU_W_MSK_SETBIT(0x0, PLL_MODE_SHIFT(id))) +#define PLL_MODE_NORM(id) (CRU_W_MSK_SETBIT(0x1, PLL_MODE_SHIFT(id))) +/*******************CLKSEL0 BITS***************************/ +#define CLK_SET_DIV_CON_SUB1(val, bits_shift, msk) CRU_W_MSK_SETBITS((val - 1), bits_shift, msk) + +#define CPU_CLK_PLL_SEL_SHIFT (13) +#define CORE_CLK_PLL_SEL_SHIFT (7) +#define SEL_APLL (0) +#define SEL_GPLL (1) +#define CPU_SEL_PLL(plls) CRU_W_MSK_SETBIT(plls, CPU_CLK_PLL_SEL_SHIFT) +#define CORE_SEL_PLL(plls) CRU_W_MSK_SETBIT(plls, CORE_CLK_PLL_SEL_SHIFT) + +#define ACLK_CPU_DIV_MASK (0x1f) +#define ACLK_CPU_DIV_SHIFT (8) +#define A9_CORE_DIV_MASK (0x1f) +#define A9_CORE_DIV_SHIFT (0) + +#define ACLK_CPU_DIV(val) CLK_SET_DIV_CON_SUB1(val, ACLK_CPU_DIV_SHIFT, ACLK_CPU_DIV_MASK) +#define CLK_CORE_DIV(val) CLK_SET_DIV_CON_SUB1(val, A9_CORE_DIV_SHIFT, A9_CORE_DIV_MASK) +/*******************CLKSEL1 BITS***************************/ +#define PCLK_CPU_DIV_MASK (0x7) +#define PCLK_CPU_DIV_SHIFT (12) +#define HCLK_CPU_DIV_MASK (0x3) +#define HCLK_CPU_DIV_SHIFT (8) +#define ACLK_CORE_DIV_MASK (0x1) +#define ACLK_CORE_DIV_SHIFT (4) +#define CORE_PERIPH_DIV_MASK (0xf) +#define CORE_PERIPH_DIV_SHIFT (0) + +#define PCLK_CPU_DIV(val) CLK_SET_DIV_CON_SUB1(val, PCLK_CPU_DIV_SHIFT, PCLK_CPU_DIV_MASK) +#define HCLK_CPU_DIV(val) CLK_SET_DIV_CON_SUB1(val, HCLK_CPU_DIV_SHIFT, HCLK_CPU_DIV_MASK) +#define ACLK_CORE_DIV(val) CLK_SET_DIV_CON_SUB1(val, ACLK_CORE_DIV_SHIFT, ACLK_CORE_DIV_MASK) +#define CLK_CORE_PERI_DIV(val) CLK_SET_DIV_CON_SUB1(val, CORE_PERIPH_DIV_SHIFT, CORE_PERIPH_DIV_MASK) + +/*******************clksel10***************************/ +#define PERI_PLL_SEL_SHIFT 15 +#define PERI_PCLK_DIV_MASK (0x3) +#define PERI_PCLK_DIV_SHIFT (12) +#define PERI_HCLK_DIV_MASK (0x3) +#define PERI_HCLK_DIV_SHIFT (8) +#define PERI_ACLK_DIV_MASK (0x1f) +#define PERI_ACLK_DIV_SHIFT (0) + +#define SEL_2PLL_GPLL (0) +#define SEL_2PLL_CPLL (1) + +#define RATIO_11 (0) +#define RATIO_21 (1) +#define RATIO_41 (2) +#define RATIO_81 (3) + +#define PERI_CLK_SEL_PLL(plls) CRU_W_MSK_SETBIT(plls, PERI_PLL_SEL_SHIFT) +#define PERI_SET_A2P_RATIO(ratio) CRU_W_MSK_SETBITS(ratio, PERI_PCLK_DIV_SHIFT, PERI_PCLK_DIV_MASK) +#define PERI_SET_A2H_RATIO(ratio) CRU_W_MSK_SETBITS(ratio, PERI_HCLK_DIV_SHIFT, PERI_PCLK_DIV_MASK) +#define PERI_SET_ACLK_DIV(val) CRU_W_MSK_SETBITS(val, PERI_ACLK_DIV_SHIFT, PERI_ACLK_DIV_MASK) +/*******************gate BITS***************************/ +#define CLK_GATE_CLKID_CONS(i) CRU_CLKGATES_CON((i) / 16) + +#define CLK_GATE(i) (1 << ((i)%16)) +#define CLK_UN_GATE(i) (0) + +#define CLK_GATE_W_MSK(i) (1 << (((i) % 16) + 16)) +#define CLK_GATE_CLKID(i) (16 * (i)) + +enum cru_clk_gate { + /* SCU CLK GATE 0 CON */ + CLK_GATE_CORE_PERIPH = CLK_GATE_CLKID(0), + CLK_GATE_CPU_GPLL, + CLK_GATE_DDRPHY_SRC, + CLK_GATE_ACLK_CPU, + + CLK_GATE_HCLK_CPU, + CLK_GATE_PCLK_CPU, + CLK_GATE_0RES6, + CLK_GATE_ACLK_CORE, + + CLK_GATE_0RES8, + CLK_GATE_I2S_SRC, + CLK_GATE_I2S_FRAC_SRC, + CLK_GATE_HCLK_VIO_PRE, + + CLK_GATE_0RES12, + CLK_GATE_0RES13, + CLK_GATE_0RES14, + CLK_GATE_TESTCLK, + + CLK_GATE_TIMER0 = CLK_GATE_CLKID(1), + CLK_GATE_TIMER1, + CLK_GATE_1RES2, + CLK_GATE_JTAG, + + CLK_GATE_1RES4, + CLK_GATE_OTGPHY0, + CLK_GATE_OTGPHY1, + CLK_GATE_1RES7, + + CLK_GATE_UART0_SRC, + CLK_GATE_UART0_FRAC_SRC, + CLK_GATE_UART1_SRC, + CLK_GATE_UART1_FRAC_SRC, + + CLK_GATE_UART2_SRC, + CLK_GATE_UART2_FRAC_SRC, + CLK_GATE_1RES14, + CLK_GATE_1RES15, + + CLK_GATE_PERIPH_SRC = CLK_GATE_CLKID(2), + CLK_GATE_ACLK_PERIPH, + CLK_GATE_HCLK_PERIPH, + CLK_GATE_PCLK_PERIPH, + + CLK_GATE_2RES4, + CLK_GATE_2RES5, + CLK_GATE_2RES6, + CLK_GATE_2RES7, + + CLK_GATE_SARADC_SRC, + CLK_GATE_SPI0_SRC, + CLK_GATE_2RES10, + CLK_GATE_MMC0_SRC, + + CLK_GATE_2RES12, + CLK_GATE_SDIO_SRC, + CLK_GATE_EMMC_SRC, + CLK_GATE_2RES15, + + CLK_GATE_ACLK_VIO_SRC = CLK_GATE_CLKID(3), + CLK_GATE_DCLK_LCDC0_SRC, + CLK_GATE_SCLK_LCDC_SRC, + CLK_GATE_PCLKIN_CIF, + + CLK_GATE_ACLK_GPS, + CLK_GATE_3RES5, + CLK_GATE_3RES6, + CLK_GATE_CIF_OUT_SRC, + + CLK_GATE_PCLK_HDMI, + CLK_GATE_ACLK_VEPU_SRC, + CLK_GATE_HCLK_VEPU, + CLK_GATE_ACLK_VDPU_SRC, + + CLK_GATE_HCLK_VDPU, + CLK_GATE_GPU_PRE, + CLK_GATE_3RES14, + CLK_GATE_3RES15, + + CLK_GATE_HCLK_PERI_AXI_MATRIX = CLK_GATE_CLKID(4), + CLK_GATE_PCLK_PERI_AXI_MATRIX, + CLK_GATE_ACLK_CPU_PERI, + CLK_GATE_ACLK_PERI_AXI_MATRIX, + + CLK_GATE_4RES4, + CLK_GATE_4RES5, + CLK_GATE_4RES6, + CLK_GATE_4RES7, + + CLK_GATE_4RES8, + CLK_GATE_4RES9, + CLK_GATE_ACLK_STRC_SYS, + CLK_GATE_4RES11, + + CLK_GATE_ACLK_INTMEM, + CLK_GATE_4RES13, + CLK_GATE_4RES14, + CLK_GATE_4RES15, + + CLK_GATE_5RES0 = CLK_GATE_CLKID(5), + CLK_GATE_ACLK_DMAC2, + CLK_GATE_PCLK_EFUSE, + CLK_GATE_5RES3, + + CLK_GATE_PCLK_GRF, + CLK_GATE_5RES5, + CLK_GATE_HCLK_ROM, + CLK_GATE_PCLK_DDRUPCTL, + + CLK_GATE_5RES8, + CLK_GATE_HCLK_NANDC, + CLK_GATE_HCLK_SDMMC0, + CLK_GATE_HCLK_SDIO, + + CLK_GATE_5RES12, + CLK_GATE_HCLK_OTG0, + CLK_GATE_PCLK_ACODEC, + CLK_GATE_5RES15, + + CLK_GATE_ACLK_LCDC0 = CLK_GATE_CLKID(6), + CLK_GATE_HCLK_LCDC0, + CLK_GATE_6RES2, + CLK_GATE_6RES3, + + CLK_GATE_HCLK_CIF, + CLK_GATE_ACLK_CIF, + CLK_GATE_6RES6, + CLK_GATE_6RES7, + + CLK_GATE_6RES8, + CLK_GATE_6RES9, + CLK_GATE_HCLK_RGA, + CLK_GATE_ACLK_RGA, + + CLK_GATE_HCLK_VIO_BUS, + CLK_GATE_ACLK_VIO0, + CLK_GATE_6RES14, + CLK_GATE_6RES15, + + CLK_GATE_HCLK_EMMC = CLK_GATE_CLKID(7), + CLK_GATE_7RES1, + CLK_GATE_HCLK_I2S, + CLK_GATE_HCLK_OTG1, + + CLK_GATE_7RES4, + CLK_GATE_7RES5, + CLK_GATE_7RES6, + CLK_GATE_PCLK_TIMER0, + + CLK_GATE_PCLK_TIMER1, + CLK_GATE_7RES9, + CLK_GATE_PCLK_PWM01, + CLK_GATE_7RES11, + + CLK_GATE_PCLK_SPI0, + CLK_GATE_7RES13, + CLK_GATE_PCLK_SARADC, + CLK_GATE_PCLK_WDT, + + CLK_GATE_PCLK_UART0 = CLK_GATE_CLKID(8), + CLK_GATE_PCLK_UART1, + CLK_GATE_PCLK_UART2, + CLK_GATE_8RES3, + + CLK_GATE_PCLK_I2C0, + CLK_GATE_PCLK_I2C1, + CLK_GATE_PCLK_I2C2, + CLK_GATE_PCLK_I2C3, + + CLK_GATE_8RES8, + CLK_GATE_PCLK_GPIO0, + CLK_GATE_PCLK_GPIO1, + CLK_GATE_PCLK_GPIO2, + + CLK_GATE_PCLK_GPIO3, + CLK_GATE_8RES13, + CLK_GATE_8RES14, + CLK_GATE_8RES15, + + CLK_GATE_CLK_CORE_DBG = CLK_GATE_CLKID(9), + CLK_GATE_PCLK_DBG, + CLK_GATE_9RES2, + CLK_GATE_9RES3, + + CLK_GATE_CLK_L2C, + CLK_GATE_9RES5, + CLK_GATE_9RES6, + CLK_GATE_9RES7, + + CLK_GATE_9RES8, + CLK_GATE_9RES9, + CLK_GATE_HCLK_USB_PERI, + CLK_GATE_HCLK_PERI_ARBI, + + CLK_GATE_ACLK_PERI_NIU, + CLK_GATE_9RES13, + CLK_GATE_9RES14, + CLK_GATE_9RES15, + + CLK_GATE_MAX, +}; + +#define SOFT_RST_ID(i) (16 * (i)) + +enum cru_soft_reset { + SOFT_RST_CORE_SRST_WDT_SEL = SOFT_RST_ID(0), + SOFT_RST_ACLK_CORE, + SOFT_RST_MCORE, + SOFT_RST_0RES3, + + SOFT_RST_0RES4, + SOFT_RST_0RES5, + SOFT_RST_0RES6, + SOFT_RST_MCORE_DBG, + + SOFT_RST_0RES8, + SOFT_RST_0RES9, + SOFT_RST_0RES10, + SOFT_RST_0RES11, + + SOFT_RST_CORE0_WDT, + SOFT_RST_0RES13, + SOFT_RST_STRC_SYS_AXI, + SOFT_RST_0RES15, + + SOFT_RST_CPU_STRC_SYS_AXI = SOFT_RST_ID(1), + SOFT_RST_CPUSYS_AHB, + SOFT_RST_L2MEM_CON_AXI, + SOFT_RST_AHB2APB, + + SOFT_RST_1RES4, + SOFT_RST_INTMEM, + SOFT_RST_ROM, + SOFT_RST_PERI_NIU, + + SOFT_RST_I2S, + SOFT_RST_1RES9, + SOFT_RST_1RES10, + SOFT_RST_TIMER0, + + SOFT_RST_TIMER1, + SOFT_RST_1RES13, + SOFT_RST_EFUSE_APB, + SOFT_RST_ACODEC, + + SOFT_RST_GPIO0 = SOFT_RST_ID(2), + SOFT_RST_GPIO1, + SOFT_RST_GPIO2, + SOFT_RST_GPIO3, + + SOFT_RST_2RES4, + SOFT_RST_2RES5, + SOFT_RST_2RES6, + SOFT_RST_UART0, + + SOFT_RST_UART1, + SOFT_RST_UART2, + SOFT_RST_2RES10, + SOFT_RST_I2C0, + + SOFT_RST_I2C1, + SOFT_RST_I2C2, + SOFT_RST_I2C3, + SOFT_RST_2RES15, + + SOFT_RST_PWM0 = SOFT_RST_ID(3), + SOFT_RST_PWM1, + SOFT_RST_DAP_PO, + SOFT_RST_DAP, + + SOFT_RST_DAP_SYS, + SOFT_RST_3RES5, + SOFT_RST_3RES6, + SOFT_RST_GRF, + + SOFT_RST_I2C, + SOFT_RST_PERIPHSYS_AXI, + SOFT_RST_PERIPHSYS_AHB, + SOFT_RST_PERIPHSYS_APB, + + SOFT_RST_PWM2, + SOFT_RST_CPU_PERI, + SOFT_RST_EMEM_PERI, + SOFT_RST_USB_PERI, + + SOFT_RST_DMA2 = SOFT_RST_ID(4), + SOFT_RST_4RES1, + SOFT_RST_4RES2, + SOFT_RST_GPS, + + SOFT_RST_NANDC, + SOFT_RST_USBOTG0, + SOFT_RST_USBPHY0, + SOFT_RST_OTGC0, + + SOFT_RST_USBOTG1, + SOFT_RST_USBPHY1, + SOFT_RST_OTGC1, + SOFT_RST_4RES11, + + SOFT_RST_4RES12, + SOFT_RST_4RES13, + SOFT_RST_4RES14, + SOFT_RST_DDRMSCH, + + SOFT_RST_5RES0 = SOFT_RST_ID(5), + SOFT_RST_MMC0, + SOFT_RST_SDIO, + SOFT_RST_EMMC, + + SOFT_RST_SPI0, + SOFT_RST_5RES5, + SOFT_RST_WDT, + SOFT_RST_SARADC, + + SOFT_RST_DDRPHY, + SOFT_RST_DDRPHY_APB, + SOFT_RST_DDRCTRL, + SOFT_RST_DDRCTRL_APB, + + SOFT_RST_5RES12, + SOFT_RST_5RES13, + SOFT_RST_5RES14, + SOFT_RST_5RES15, + + SOFT_RST_HDMI_PCLK = SOFT_RST_ID(6), + SOFT_RST_HDMI_DCLK, + SOFT_RST_VIO0_AXI, + SOFT_RST_VIO_BUS_AHB, + + SOFT_RST_LCDC0_AXI, + SOFT_RST_LCDC0_AHB, + SOFT_RST_LCDC0_DCLK, + SOFT_RST_UTMI0, + + SOFT_RST_UTMI1, + SOFT_RST_USBPOR, + SOFT_RST_6RES10, + SOFT_RST_6RES11, + + SOFT_RST_RGA_AXI, + SOFT_RST_RGA_AHB, + SOFT_RST_CIF0, + SOFT_RST_LCDC_SCL, + + SOFT_RST_VCODEC_AXI = SOFT_RST_ID(7), + SOFT_RST_VCODEC_AHB, + SOFT_RST_VIO1_AXI, + SOFT_RST_CPU_VCODEC, + + SOFT_RST_VCODEC_NIU_AXI, + SOFT_RST_7RES5, + SOFT_RST_7RES6, + SOFT_RST_7RES7, + + SOFT_RST_GPU, + SOFT_RST_7RES9, + SOFT_RST_GPU_NIU_AXI, + SOFT_RST_7RES11, + + SOFT_RST_7RES12, + SOFT_RST_7RES13, + SOFT_RST_7RES14, + SOFT_RST_7RES15, + + SOFT_RST_8RES0 = SOFT_RST_ID(8), + SOFT_RST_8RES1, + SOFT_RST_CORE_DBG, + SOFT_RST_DBG_APB, + + SOFT_RST_8RES4, + SOFT_RST_8RES5, + SOFT_RST_8RES6, + SOFT_RST_8RES7, + + SOFT_RST_8RES8, + SOFT_RST_8RES9, + SOFT_RST_8RES10, + SOFT_RST_8RES11, + + SOFT_RST_8RES12, + SOFT_RST_8RES13, + SOFT_RST_8RES14, + SOFT_RST_8RES15, + + SOFT_RST_MAX, +}; + +/*****cru reg end*****/ +static inline void cru_set_soft_reset(enum cru_soft_reset idx, bool on) +{ + const void __iomem *reg = RK2928_CRU_BASE + CRU_SOFTRSTS_CON(idx >> 4); + u32 val = on ? 0x10001U << (idx & 0xf) : 0x10000U << (idx & 0xf); + writel_relaxed(val, reg); + dsb(); +} + +#endif From d18a181849e903e4a312040364f5c8fae7a03ce2 Mon Sep 17 00:00:00 2001 From: CMY Date: Mon, 6 Aug 2012 15:19:18 +0800 Subject: [PATCH 088/261] BT: for NH660 --- drivers/bluetooth/Kconfig | 11 +++++++++++ net/rfkill/rfkill-rk.c | 8 +++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index fdc472b7b2ab..cceaab11a091 100755 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -257,4 +257,15 @@ config BT_WILINK Say Y here to compile support for Texas Instrument's WiLink7 driver into the kernel or say M to compile it as module. + +if BCM4330 +choice + prompt "Select the bluetooth module" + default BT_MODULE_NH660 + + config BT_MODULE_NH660 + bool "AzureWave NH660" +endchoice +endif + endmenu diff --git a/net/rfkill/rfkill-rk.c b/net/rfkill/rfkill-rk.c index d5815ac06955..dfcb9727a6a8 100644 --- a/net/rfkill/rfkill-rk.c +++ b/net/rfkill/rfkill-rk.c @@ -103,7 +103,13 @@ struct rfkill_rk_data { static struct rfkill_rk_data *g_rfkill = NULL; static const char bt_name[] = -#if defined(CONFIG_RKWIFI) +#if defined (CONFIG_BCM4330) + #if defined (CONFIG_BT_MODULE_NH660) + "nh660" + #else + "bcm4330" + #endif +#elif defined (CONFIG_RK903) #if defined(CONFIG_RKWIFI_26M) "rk903_26M" #else From 5636fa417ed69a404b9855e4dfc0afb51763cb15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Mon, 6 Aug 2012 22:17:44 +0800 Subject: [PATCH 089/261] rk2928: clock: fix init --- arch/arm/mach-rk2928/clock_data.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-rk2928/clock_data.c b/arch/arm/mach-rk2928/clock_data.c index 8225d9d5b009..38aab641b19c 100644 --- a/arch/arm/mach-rk2928/clock_data.c +++ b/arch/arm/mach-rk2928/clock_data.c @@ -283,7 +283,7 @@ static unsigned long pll_clk_recalc(u8 pll_id, unsigned long parent_rate) u32 pll_con0 = cru_readl(PLL_CONS(pll_id, 0)); u32 pll_con1 = cru_readl(PLL_CONS(pll_id, 1)); //integer mode - rate64 = (u64)parent_rate * PLL_GET_FBDIV(pll_con1); + rate64 = (u64)parent_rate * PLL_GET_FBDIV(pll_con0); do_div(rate64, PLL_GET_REFDIV(pll_con1)); if (FRAC_MODE == dsmp) { @@ -295,7 +295,7 @@ static unsigned long pll_clk_recalc(u8 pll_id, unsigned long parent_rate) __func__, pll_id, frac_rate64, PLL_GET_FRAC(pll_con1)); } do_div(rate64, PLL_GET_POSTDIV1(pll_con0)); - do_div(rate64, PLL_GET_POSTDIV2(pll_con0)); + do_div(rate64, PLL_GET_POSTDIV2(pll_con1)); rate = rate64; } else { @@ -516,7 +516,7 @@ static void pll_wait_lock(int pll_idx) u32 bit = 0x10u << pll_state[pll_idx]; int delay = 24000000; while (delay > 0) { - if (!(cru_readl(PLL_CONS(pll_idx, 1)) & (0x1 << PLL_LOCK_SHIFT))) { + if ((cru_readl(PLL_CONS(pll_idx, 1)) & (0x1 << PLL_LOCK_SHIFT))) { //printk("%s %08x\n", __func__, cru_readl(PLL_CONS(pll_idx, 1)) & (0x1 << PLL_LOCK_SHIFT)); //printk("%s ! %08x\n", __func__, !(cru_readl(PLL_CONS(pll_idx, 1)) & (0x1 << PLL_LOCK_SHIFT))); break; @@ -534,16 +534,16 @@ static int pll_clk_mode(struct clk *clk, int on) // FIXME here 500 must be changed u32 dly = 1500; - CLKDATA_DBG("pll_mode %s(%d)", clk->name, on); + CLKDATA_DBG("pll_mode %s(%d)\n", clk->name, on); //FIXME if (on) { - cru_writel(CRU_W_MSK_SETBIT(PLL_PWR_ON, PLL_LOCK_SHIFT), PLL_CONS(pll_id, 0)); + cru_writel(CRU_W_MSK_SETBIT(PLL_PWR_ON, PLL_LOCK_SHIFT), PLL_CONS(pll_id, 1)); rk_clock_udelay(dly); pll_wait_lock(pll_id); cru_writel(PLL_MODE_NORM(pll_id), CRU_MODE_CON); } else { cru_writel(PLL_MODE_SLOW(pll_id), CRU_MODE_CON); - cru_writel(CRU_W_MSK_SETBIT(PLL_PWR_DN, PLL_LOCK_SHIFT), PLL_CONS(pll_id, 0)); + cru_writel(CRU_W_MSK_SETBIT(PLL_PWR_DN, PLL_LOCK_SHIFT), PLL_CONS(pll_id, 1)); } return 0; } From 9ea13292d1d315c16436748fd41265b07a8b8d14 Mon Sep 17 00:00:00 2001 From: kfx Date: Tue, 7 Aug 2012 09:55:59 +0800 Subject: [PATCH 090/261] rk2928: 'adc&keypad support' and 'lvds' and 'lcd' --- arch/arm/configs/rk2928_sdk_defconfig | 1 - arch/arm/mach-rk2928/board-rk2928-sdk.c | 1 + arch/arm/mach-rk2928/devices.c | 24 ++++++++++++++++++++ drivers/adc/plat/rk30_adc.c | 2 ++ drivers/input/keyboard/rk29_keys.c | 2 +- drivers/video/display/screen/lcd_hsd100pxn.c | 4 ++-- drivers/video/rockchip/lvds/rk_lvds.h | 2 +- 7 files changed, 31 insertions(+), 5 deletions(-) diff --git a/arch/arm/configs/rk2928_sdk_defconfig b/arch/arm/configs/rk2928_sdk_defconfig index fb18b35ad28e..32ceab278ca3 100755 --- a/arch/arm/configs/rk2928_sdk_defconfig +++ b/arch/arm/configs/rk2928_sdk_defconfig @@ -22,7 +22,6 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_ARCH_RK2928=y -CONFIG_WIFI_CONTROL_FUNC=y CONFIG_RK_DEBUG_UART=2 CONFIG_FIQ_DEBUGGER=y CONFIG_FIQ_DEBUGGER_NO_SLEEP=y diff --git a/arch/arm/mach-rk2928/board-rk2928-sdk.c b/arch/arm/mach-rk2928/board-rk2928-sdk.c index 2a433f41c3e8..06ac44d87620 100755 --- a/arch/arm/mach-rk2928/board-rk2928-sdk.c +++ b/arch/arm/mach-rk2928/board-rk2928-sdk.c @@ -1154,6 +1154,7 @@ static void __init rk2928_board_init(void) { gpio_request(POWER_ON_PIN, "poweronpin"); gpio_direction_output(POWER_ON_PIN, GPIO_HIGH); + gpio_free(POWER_ON_PIN); pm_power_off = rk30_pm_power_off; diff --git a/arch/arm/mach-rk2928/devices.c b/arch/arm/mach-rk2928/devices.c index 04038a26456b..2fba48058870 100755 --- a/arch/arm/mach-rk2928/devices.c +++ b/arch/arm/mach-rk2928/devices.c @@ -29,6 +29,27 @@ #include #include +#ifdef CONFIG_ADC_RK30 +static struct resource rk30_adc_resource[] = { + { + .start = IRQ_SARADC, + .end = IRQ_SARADC, + .flags = IORESOURCE_IRQ, + }, + { + .start = RK2928_SARADC_PHYS, + .end = RK2928_SARADC_PHYS + RK2928_SARADC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device device_adc = { + .name = "rk30-adc", + .id = -1, + .num_resources = ARRAY_SIZE(rk30_adc_resource), + .resource = rk30_adc_resource, +}; +#endif static u64 dma_dmamask = DMA_BIT_MASK(32); @@ -748,6 +769,9 @@ static int __init rk2928_init_devices(void) rk2928_init_uart(); rk2928_init_i2c(); rk2928_init_spim(); +#ifdef CONFIG_ADC_RK30 + platform_device_register(&device_adc); +#endif #ifdef CONFIG_KEYS_RK29 platform_device_register(&device_keys); #endif diff --git a/drivers/adc/plat/rk30_adc.c b/drivers/adc/plat/rk30_adc.c index fbfb26a940b5..a8536fce8ece 100755 --- a/drivers/adc/plat/rk30_adc.c +++ b/drivers/adc/plat/rk30_adc.c @@ -128,6 +128,7 @@ static int rk30_adc_probe(struct platform_device *pdev) struct resource *res; int ret; + printk("%s: start\n", __func__); adc = adc_alloc_host(&pdev->dev, sizeof(struct rk30_adc_device), SARADC_CHN_MASK); if (!adc) return -ENOMEM; @@ -266,6 +267,7 @@ static struct platform_driver rk30_adc_driver = { static int __init rk30_adc_init(void) { + printk("%s: start\n", __func__); return platform_driver_register(&rk30_adc_driver); } subsys_initcall(rk30_adc_init); diff --git a/drivers/input/keyboard/rk29_keys.c b/drivers/input/keyboard/rk29_keys.c index b5881d5b5e93..d184b51a1e0a 100755 --- a/drivers/input/keyboard/rk29_keys.c +++ b/drivers/input/keyboard/rk29_keys.c @@ -32,7 +32,7 @@ #define INVALID_ADVALUE 10 -#if 0 +#if 1 #define key_dbg(bdata, format, arg...) \ dev_printk(KERN_INFO , &bdata->input->dev , format , ## arg) #else diff --git a/drivers/video/display/screen/lcd_hsd100pxn.c b/drivers/video/display/screen/lcd_hsd100pxn.c index 4f07324430ba..c11fa732613c 100755 --- a/drivers/video/display/screen/lcd_hsd100pxn.c +++ b/drivers/video/display/screen/lcd_hsd100pxn.c @@ -8,11 +8,11 @@ /* Base */ -#define OUT_TYPE SCREEN_RGB +#define OUT_TYPE SCREEN_LVDS #define OUT_FACE OUT_D888_P666 #define OUT_CLK 65000000 -#define LCDC_ACLK 500000000//312000000 //29 lcdc axi DMA 频率 +#define LCDC_ACLK 300000000//312000000 //29 lcdc axi DMA 频率 /* Timing */ #define H_PW 10 diff --git a/drivers/video/rockchip/lvds/rk_lvds.h b/drivers/video/rockchip/lvds/rk_lvds.h index 3916fad54a90..f5289344d885 100644 --- a/drivers/video/rockchip/lvds/rk_lvds.h +++ b/drivers/video/rockchip/lvds/rk_lvds.h @@ -2,7 +2,7 @@ #define RK_LVDS_H #define LVDS_CON0_OFFSET 0x150 -#define LVDS_CON0_REG (RK2928_GRF_PHYS + LVDS_CON0_OFFSET) +#define LVDS_CON0_REG (RK2928_GRF_BASE + LVDS_CON0_OFFSET) #define LVDSRdReg() __raw_readl(LVDS_CON0_REG) #define LVDSWrReg(val) __raw_writel( val ,LVDS_CON0_REG) From 44c4c313fe3b977ebcf47ca2353ddf9125603323 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Tue, 7 Aug 2012 10:41:00 +0800 Subject: [PATCH 091/261] rk2928: clock: fix init again --- arch/arm/mach-rk2928/clock_data.c | 86 +++++++++++++++++++------ arch/arm/mach-rk2928/include/mach/cru.h | 10 +-- 2 files changed, 73 insertions(+), 23 deletions(-) diff --git a/arch/arm/mach-rk2928/clock_data.c b/arch/arm/mach-rk2928/clock_data.c index 38aab641b19c..5b72103ca044 100644 --- a/arch/arm/mach-rk2928/clock_data.c +++ b/arch/arm/mach-rk2928/clock_data.c @@ -125,7 +125,7 @@ u32 TEST_CRU_REGS[500] = {0}; .pllcon0 = PLL_SET_POSTDIV1(_postdiv1) | PLL_SET_FBDIV(_fbdiv), \ .pllcon1 = PLL_SET_DSMPD(_dsmpd) | PLL_SET_POSTDIV2(_postdiv2) | PLL_SET_REFDIV(_refdiv), \ .pllcon2 = PLL_SET_FRAC(_frac), \ - .clksel0 = ACLK_CPU_DIV(RATIO_##_axi_div) | CLK_CORE_DIV(RATIO_##_aclk_core_div),\ + .clksel0 = ACLK_CPU_DIV(RATIO_##_axi_div),\ .clksel1 = PCLK_CPU_DIV(RATIO_##_apb_div) | HCLK_CPU_DIV(RATIO_##_ahb_div) \ | ACLK_CORE_DIV(RATIO_##_aclk_core_div) | CLK_CORE_PERI_DIV(RATIO_##_periph_div), \ .lpj = 1500, \ @@ -142,12 +142,12 @@ static const struct apll_clk_set apll_clks[] = { .pllcon2 = PLL_SET_FRAC(_frac), \ } static const struct pll_clk_set cpll_clks[] = { - _PLL_SET_CLKS(798000, 4, 133, 1, 1, 0, 0), - _PLL_SET_CLKS(1064000, 3, 133, 1, 1, 0, 0), + _PLL_SET_CLKS(798000, 4, 133, 1, 1, 1, 0), + _PLL_SET_CLKS(1064000, 3, 133, 1, 1, 1, 0), }; static const struct pll_clk_set gpll_clks[] = { - _PLL_SET_CLKS(297000, 2, 99, 4, 1, 0, 0), + _PLL_SET_CLKS(297000, 2, 99, 4, 1, 1, 0), }; static u32 clk_gcd(u32 numerator, u32 denominator) @@ -591,9 +591,9 @@ static int pll_clk_set_rate(struct pll_clk_set *clk_set, u8 pll_id) cru_writel(clk_set->pllcon1, PLL_CONS(pll_id,1)); cru_writel(clk_set->pllcon2, PLL_CONS(pll_id,2)); - //printk("id=%d,pllcon0%08x\n", pll_id, cru_readl(PLL_CONS(pll_id,0))); - //printk("id=%d,pllcon1%08x\n", pll_id, cru_readl(PLL_CONS(pll_id,1))); - //printk("id=%d,pllcon2%08x\n", pll_id, cru_readl(PLL_CONS(pll_id,2))); + printk("id=%d,pllcon0%08x\n", pll_id, cru_readl(PLL_CONS(pll_id,0))); + printk("id=%d,pllcon1%08x\n", pll_id, cru_readl(PLL_CONS(pll_id,1))); + printk("id=%d,pllcon2%08x\n", pll_id, cru_readl(PLL_CONS(pll_id,2))); //rk2928_clock_udelay(5); //wating lock state @@ -692,15 +692,15 @@ static int pll_clk_get_set(unsigned long fin_hz,unsigned long fout_hz, fin_hz /= MHZ; fout_hz /= MHZ; gcd = clk_gcd(fin_hz, fout_hz); - refdiv = gcd; - fbdiv = fout_hz / gcd; - postdiv1 = 1; - postdiv2 = 1; + *refdiv = fin_hz / gcd; + *fbdiv = fout_hz / gcd; + *postdiv1 = 1; + *postdiv2 = 1; - frac = 0; + *frac = 0; CLKDATA_DBG("fin=%lu,fout=%lu,gcd=%lu,refdiv=%lu,fbdiv=%lu,postdiv1=%lu,postdiv2=%lu,frac=%lu\n", - fin_hz, fout_hz, gcd, refdiv, fbdiv, postdiv1, postdiv2, frac); + fin_hz, fout_hz, gcd, *refdiv, *fbdiv, *postdiv1, *postdiv2, *frac); return 0; } @@ -716,11 +716,61 @@ static int pll_set_con(u8 id, u32 refdiv, u32 fbdiv, u32 postdiv1, u32 postdiv2, } static int apll_clk_set_rate(struct clk *clk, unsigned long rate) { - // FIXME + struct _pll_data *pll_data=clk->pll; + struct apll_clk_set *clk_set=(struct apll_clk_set*)pll_data->table; + struct apll_clk_set temp_clk_set; + + u32 fin_hz, fout_hz; u32 refdiv, fbdiv, postdiv1, postdiv2, frac; + fin_hz = clk->parent->rate; + fout_hz = rate; + + while(clk_set->rate) { + if (clk_set->rate == rate) { + break; + } + clk_set++; + } + printk("%s %s %d\n", __func__, clk->name, rate); - pll_clk_get_set(clk->parent->rate, rate, &refdiv, &fbdiv, &postdiv1, &postdiv2, &frac); - pll_set_con(clk->pll->id, refdiv, fbdiv, postdiv1, postdiv2, frac); + printk("pllcon0 %08x\n", cru_readl(PLL_CONS(0,0))); + printk("pllcon1 %08x\n", cru_readl(PLL_CONS(0,1))); + printk("pllcon2 %08x\n", cru_readl(PLL_CONS(0,2))); + printk("pllcon3 %08x\n", cru_readl(PLL_CONS(0,3))); + printk("clksel0 %08x\n", cru_readl(CRU_CLKSELS_CON(0))); + printk("clksel1 %08x\n", cru_readl(CRU_CLKSELS_CON(1))); + if(clk_set->rate==rate) { + CLKDATA_DBG("apll get a rate\n"); + u8 pll_id = 0; + + //enter slowmode + cru_writel(PLL_MODE_SLOW(pll_id), CRU_MODE_CON); + + cru_writel(clk_set->pllcon0, PLL_CONS(pll_id,0)); + cru_writel(clk_set->pllcon1, PLL_CONS(pll_id,1)); + cru_writel(clk_set->pllcon2, PLL_CONS(pll_id,2)); + cru_writel(clk_set->clksel0, CRU_CLKSELS_CON(0)); + cru_writel(clk_set->clksel1, CRU_CLKSELS_CON(1)); + + printk("pllcon0 %08x\n", cru_readl(PLL_CONS(0,0))); + printk("pllcon1 %08x\n", cru_readl(PLL_CONS(0,1))); + printk("pllcon2 %08x\n", cru_readl(PLL_CONS(0,2))); + printk("pllcon3 %08x\n", cru_readl(PLL_CONS(0,3))); + printk("clksel0 %08x\n", cru_readl(CRU_CLKSELS_CON(0))); + printk("clksel1 %08x\n", cru_readl(CRU_CLKSELS_CON(1))); + //rk2928_clock_udelay(5); + + //wating lock state + rk2928_clock_udelay(clk_set->rst_dly); + pll_wait_lock(pll_id); + + //return form slow + cru_writel(PLL_MODE_NORM(pll_id), CRU_MODE_CON); + } else { + // FIXME + pll_clk_get_set(clk->parent->rate, rate, &refdiv, &fbdiv, &postdiv1, &postdiv2, &frac); + pll_set_con(clk->pll->id, refdiv, fbdiv, postdiv1, postdiv2, frac); + } printk("setting OK\n"); return 0; @@ -758,11 +808,11 @@ static int cpll_clk_set_rate(struct clk *clk, unsigned long rate) } else { CLKDATA_DBG("cpll get auto calc a rate\n"); - if(pll_clk_get_set(clk->parent->rate, &rate, &refdiv, &fbdiv, &postdiv1, &postdiv2, &frac) != 0) { + if(pll_clk_get_set(clk->parent->rate, rate, &refdiv, &fbdiv, &postdiv1, &postdiv2, &frac) != 0) { pr_err("cpll auto set rate error\n"); return -ENOENT; } - CLKDATA_DBG("%s get fin=%d, fout=%d, refdiv=%lu, fbdiv=%lu, postdiv1=%lu, postdiv2=%d", + CLKDATA_DBG("%s get fin=%d, fout=%d, rate=%lu, refdiv=%lu, fbdiv=%lu, postdiv1=%lu, postdiv2=%d", __func__, fin_hz, fout_hz, rate, refdiv, fbdiv, postdiv1, postdiv2); pll_set_con(pll_data->id, refdiv, fbdiv, postdiv1, postdiv2, frac); } diff --git a/arch/arm/mach-rk2928/include/mach/cru.h b/arch/arm/mach-rk2928/include/mach/cru.h index b22b9a7be564..4d5025cc325f 100755 --- a/arch/arm/mach-rk2928/include/mach/cru.h +++ b/arch/arm/mach-rk2928/include/mach/cru.h @@ -91,7 +91,7 @@ enum rk_plls_id { #define PLL_GET_FRAC(reg) CRU_GET_REG_BITS_VAL(reg, PLL_FRAC_SHIFT, PLL_FRAC_MASK) //#define APLL_SET_BYPASS(val) CRU_SET_BIT(val, PLL_BYPASS_SHIFT) -#define PLL_SET_DSMPD(val) CRU_SET_BIT(val, PLL_DSMPD_SHIFT) +#define PLL_SET_DSMPD(val) CRU_W_MSK_SETBIT(val, PLL_DSMPD_SHIFT) #define PLL_GET_DSMPD(reg) CRU_GET_REG_BIT_VAL(reg, PLL_DSMPD_SHIFT) /*******************MODE BITS***************************/ #define PLL_MODE_MSK(id) (0x1 << ((id) * 4)) @@ -142,10 +142,10 @@ enum rk_plls_id { #define SEL_2PLL_GPLL (0) #define SEL_2PLL_CPLL (1) -#define RATIO_11 (0) -#define RATIO_21 (1) -#define RATIO_41 (2) -#define RATIO_81 (3) +#define RATIO_11 (1) +#define RATIO_21 (2) +#define RATIO_41 (4) +#define RATIO_81 (8) #define PERI_CLK_SEL_PLL(plls) CRU_W_MSK_SETBIT(plls, PERI_PLL_SEL_SHIFT) #define PERI_SET_A2P_RATIO(ratio) CRU_W_MSK_SETBITS(ratio, PERI_PCLK_DIV_SHIFT, PERI_PCLK_DIV_MASK) From 0b7992563dfb836479717024e82330b25ee55c23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Tue, 7 Aug 2012 11:16:48 +0800 Subject: [PATCH 092/261] rk2928: iomux: fix init uart2 --- arch/arm/mach-rk2928/iomux.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-rk2928/iomux.c b/arch/arm/mach-rk2928/iomux.c index c931237c4661..774835541ed5 100755 --- a/arch/arm/mach-rk2928/iomux.c +++ b/arch/arm/mach-rk2928/iomux.c @@ -130,10 +130,10 @@ MUX_CFG(GPIO2C0_LCDC0_D14_LCDC1_D14_NAME, GPIO2C, 0, 2, 0, DEF MUX_CFG(GPIO2C1_LCDC0_D15_LCDC1_D15_NAME, GPIO2C, 2, 2, 0, DEFAULT) MUX_CFG(GPIO2C2_LCDC0_D16_LCDC1_D16_NAME, GPIO2C, 4, 2, 0, DEFAULT) MUX_CFG(GPIO2C3_LCDC0_D17_LCDC1_D17_NAME, GPIO2C, 6, 2, 0, DEFAULT) -MUX_CFG(GPIO2C4_LCDC0_D18_LCDC1_D18_I2C2_SDA_NAME,GPIO2C, 8, 3, 0, DEFAULT) -MUX_CFG(GPIO2C5_LCDC0_D19_LCDC1_D19_I2C2_SCL_NAME,GPIO2C, 10, 3, 0, DEFAULT) -MUX_CFG(GPIO2C6_LCDC0_D20_LCDC1_D20_UART2_SIN_NAME,GPIO2C, 12, 3, 0, DEFAULT) -MUX_CFG(GPIO2C7_LCDC0_D21_LCDC1_D21_UART2_SOUT_NAME,GPIO2C, 14, 3, 0, DEFAULT) +MUX_CFG(GPIO2C4_LCDC0_D18_LCDC1_D18_I2C2_SDA_NAME,GPIO2C, 8, 2, 0, DEFAULT) +MUX_CFG(GPIO2C5_LCDC0_D19_LCDC1_D19_I2C2_SCL_NAME,GPIO2C, 10, 2, 0, DEFAULT) +MUX_CFG(GPIO2C6_LCDC0_D20_LCDC1_D20_UART2_SIN_NAME,GPIO2C, 12, 2, 0, DEFAULT) +MUX_CFG(GPIO2C7_LCDC0_D21_LCDC1_D21_UART2_SOUT_NAME,GPIO2C, 14, 2, 0, DEFAULT) //gpio2d MUX_CFG(GPIO2D0_LCDC0_D22_LCDC1_D22_NAME, GPIO2D, 0, 2, 0, DEFAULT) @@ -195,11 +195,11 @@ int __init rk2928_iomux_init(void) #endif #if defined(CONFIG_UART2_RK29) || (CONFIG_RK_DEBUG_UART == 2) - rk30_mux_api_set(GPIO0D0_UART2_RTSN_NAME, GPIO0D_UART2_RTSN); - rk30_mux_api_set(GPIO0D1_UART2_CTSN_NAME, GPIO0D_UART2_CTSN); -#ifdef CONFIG_UART2_CTS_RTS_RK29 rk30_mux_api_set(GPIO2C6_LCDC0_D20_LCDC1_D20_UART2_SIN_NAME, GPIO2C_UART2_SIN); rk30_mux_api_set(GPIO2C7_LCDC0_D21_LCDC1_D21_UART2_SOUT_NAME, GPIO2C_UART2_SOUT); +#ifdef CONFIG_UART2_CTS_RTS_RK29 + rk30_mux_api_set(GPIO0D0_UART2_RTSN_NAME, GPIO0D_UART2_RTSN); + rk30_mux_api_set(GPIO0D1_UART2_CTSN_NAME, GPIO0D_UART2_CTSN); #endif #endif From e109d315f333f8c10232c2e609cdb5312a3de0e0 Mon Sep 17 00:00:00 2001 From: kfx Date: Tue, 7 Aug 2012 11:23:32 +0800 Subject: [PATCH 093/261] rk2928: lvds support, lcd support --- drivers/video/display/screen/lcd_hsd100pxn.c | 1 + drivers/video/rockchip/lvds/rk_lvds.c | 11 ++++++++++- drivers/video/rockchip/lvds/rk_lvds.h | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/video/display/screen/lcd_hsd100pxn.c b/drivers/video/display/screen/lcd_hsd100pxn.c index c11fa732613c..b840a51382e8 100755 --- a/drivers/video/display/screen/lcd_hsd100pxn.c +++ b/drivers/video/display/screen/lcd_hsd100pxn.c @@ -36,6 +36,7 @@ void set_lcd_info(struct rk29fb_screen *screen, struct rk29lcd_info *lcd_info ) /* screen type & face */ screen->type = OUT_TYPE; screen->face = OUT_FACE; + screen->hw_format = 1; /* Screen size */ screen->x_res = H_VD; diff --git a/drivers/video/rockchip/lvds/rk_lvds.c b/drivers/video/rockchip/lvds/rk_lvds.c index 0fd1656120cb..72885dfde55b 100644 --- a/drivers/video/rockchip/lvds/rk_lvds.c +++ b/drivers/video/rockchip/lvds/rk_lvds.c @@ -7,10 +7,16 @@ static void rk_output_lvds(rk_screen *screen) { - LVDSWrReg(m_PD_PLL(1)|m_PD_PLL(0)|m_PDN(1)|m_OEN(0) \ + printk("%s: %x\n", __func__, m_PDN_CBG(1)|m_PD_PLL(0)|m_PDN(1)|m_OEN(0) \ |m_DS(DS_10PF)|m_MSBSEL(DATA_D0_MSB) \ |m_OUT_FORMAT(screen->hw_format) \ |m_LCDC_SEL(FROM_LCDC0)); + LVDSWrReg(m_PDN_CBG(1)|m_PD_PLL(0)|m_PDN(1)|m_OEN(0) \ + |m_DS(DS_10PF)|m_MSBSEL(DATA_D0_MSB) \ + |m_OUT_FORMAT(screen->hw_format) \ + |m_LCDC_SEL(FROM_LCDC0)); + + printk("%s: reg = 0x%x\n", __func__, LVDSRdReg()); } static void rk_output_lvttl(rk_screen *screen) @@ -19,11 +25,13 @@ static void rk_output_lvttl(rk_screen *screen) |m_DS(DS_10PF)|m_MSBSEL(DATA_D0_MSB) \ |m_OUT_FORMAT(screen->hw_format) \ |m_LCDC_SEL(FROM_LCDC0)); + printk("%s: reg = 0x%x\n", __func__, LVDSRdReg()); } static void rk_output_disable(void) { LVDSWrReg(m_PD_PLL(0)|m_PD_PLL(0)|m_PDN(0)|m_OEN(0)); + printk("%s: reg = 0x%x\n", __func__, LVDSRdReg()); } static int rk_lvds_set_param(rk_screen *screen,bool enable ) @@ -32,6 +40,7 @@ static int rk_lvds_set_param(rk_screen *screen,bool enable ) switch(screen->type){ case SCREEN_LVDS: rk_output_lvds(screen); + break; case SCREEN_RGB: rk_output_lvttl(screen); diff --git a/drivers/video/rockchip/lvds/rk_lvds.h b/drivers/video/rockchip/lvds/rk_lvds.h index f5289344d885..4298433cb9da 100644 --- a/drivers/video/rockchip/lvds/rk_lvds.h +++ b/drivers/video/rockchip/lvds/rk_lvds.h @@ -8,7 +8,7 @@ #define LVDSWrReg(val) __raw_writel( val ,LVDS_CON0_REG) #define m_value(x,offset,mask) \ - ((mask<<(offset+8)) | (x&mask)< Date: Tue, 7 Aug 2012 11:52:51 +0800 Subject: [PATCH 094/261] rk2928: hdmi init --- .../rockchip/hdmi/chips/rk2928/rk2928_hdmi.c | 20 +++++++++++-------- drivers/video/rockchip/hdmi/rk_hdmi.h | 4 ++++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi.c b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi.c index 1ef14180bd6f..09b55b1c9d86 100755 --- a/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi.c +++ b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi.c @@ -111,7 +111,7 @@ static int __devinit rk2928_hdmi_probe (struct platform_device *pdev) hdmi = kmalloc(sizeof(struct hdmi), GFP_KERNEL); if(!hdmi) { - dev_err(&pdev->dev, ">>rk30 hdmi kmalloc fail!"); + dev_err(&pdev->dev, ">>rk2928 hdmi kmalloc fail!"); return -ENOMEM; } memset(hdmi, 0, sizeof(struct hdmi)); @@ -130,7 +130,7 @@ static int __devinit rk2928_hdmi_probe (struct platform_device *pdev) } hdmi->xscale = 95; hdmi->yscale = 95; - +#if 0 hdmi->hclk = clk_get(NULL,"hclk_hdmi"); if(IS_ERR(hdmi->hclk)) { @@ -139,7 +139,7 @@ static int __devinit rk2928_hdmi_probe (struct platform_device *pdev) goto err0; } clk_enable(hdmi->hclk); - +#endif res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(hdmi->dev, "Unable to get register resource\n"); @@ -206,7 +206,7 @@ static int __devinit rk2928_hdmi_probe (struct platform_device *pdev) goto err2; } - hdmi_dbg(hdmi->dev, "rk30 hdmi probe sucess.\n"); + dev_info(hdmi->dev, "rk2928 hdmi probe success.\n"); return 0; err2: #ifdef CONFIG_SWITCH @@ -219,9 +219,11 @@ static int __devinit rk2928_hdmi_probe (struct platform_device *pdev) iounmap((void*)hdmi->regbase); err1: release_mem_region(res->start,(res->end - res->start) + 1); +#if 0 clk_disable(hdmi->hclk); +#endif err0: - hdmi_dbg(hdmi->dev, "rk30 hdmi probe error.\n"); + hdmi_dbg(hdmi->dev, "rk2928 hdmi probe error.\n"); kfree(hdmi); hdmi = NULL; return ret; @@ -246,7 +248,9 @@ static int __devexit rk2928_hdmi_remove(struct platform_device *pdev) #endif iounmap((void*)hdmi->regbase); release_mem_region(hdmi->regbase_phy, hdmi->regsize_phy); + #if 0 clk_disable(hdmi->hclk); + #endif fb_destroy_modelist(&hdmi->edid.modelist); if(hdmi->edid.audio) kfree(hdmi->edid.audio); @@ -259,7 +263,7 @@ static int __devexit rk2928_hdmi_remove(struct platform_device *pdev) kfree(hdmi); hdmi = NULL; } - printk(KERN_INFO "rk30 hdmi removed.\n"); + printk(KERN_INFO "rk2928 hdmi removed.\n"); return 0; } @@ -270,14 +274,14 @@ static void rk2928_hdmi_shutdown(struct platform_device *pdev) unregister_early_suspend(&hdmi->early_suspend); #endif } - printk(KERN_INFO "rk30 hdmi shut down.\n"); + printk(KERN_INFO "rk2928 hdmi shut down.\n"); } static struct platform_driver rk2928_hdmi_driver = { .probe = rk2928_hdmi_probe, .remove = __devexit_p(rk2928_hdmi_remove), .driver = { - .name = "rk30-hdmi", + .name = "rk2928-hdmi", .owner = THIS_MODULE, }, .shutdown = rk2928_hdmi_shutdown, diff --git a/drivers/video/rockchip/hdmi/rk_hdmi.h b/drivers/video/rockchip/hdmi/rk_hdmi.h index cf6d34c6ce80..83d3925e482b 100755 --- a/drivers/video/rockchip/hdmi/rk_hdmi.h +++ b/drivers/video/rockchip/hdmi/rk_hdmi.h @@ -28,7 +28,11 @@ enum { }; /* default HDMI video source */ +#ifdef CONFIG_ARCH_RK2928 +#define HDMI_SOURCE_DEFAULT HDMI_SOURCE_LCDC0 +#else #define HDMI_SOURCE_DEFAULT HDMI_SOURCE_LCDC1 +#endif /* If HDMI_ENABLE, system will auto configure output mode according to EDID * If HDMI_DISABLE, system will output mode according to macro HDMI_VIDEO_DEFAULT_MODE */ From c00a76fd54c07b0603b9807026429242ea1faa62 Mon Sep 17 00:00:00 2001 From: "lw@rock-chips.com" Date: Tue, 7 Aug 2012 14:32:28 +0800 Subject: [PATCH 095/261] phonepad:modify touch driver --- drivers/input/touchscreen/goodix_touch_82x.c | 674 +++++++------------ 1 file changed, 245 insertions(+), 429 deletions(-) diff --git a/drivers/input/touchscreen/goodix_touch_82x.c b/drivers/input/touchscreen/goodix_touch_82x.c index b745f3c3e41a..8a8d0e1a145b 100755 --- a/drivers/input/touchscreen/goodix_touch_82x.c +++ b/drivers/input/touchscreen/goodix_touch_82x.c @@ -5,8 +5,6 @@ * Author: Scott * Date: 2012.01.05 */ - - #include #include #include @@ -33,7 +31,6 @@ #define TRIGGER_LOC 66 //#typedef s32 int //w++ - struct goodix_ts_data { uint16_t addr; struct i2c_client *client; @@ -56,15 +53,9 @@ struct goodix_ts_data { int irq_is_disable; int interrupt_port; int reset_port; - }; struct goodix_ts_data *ts82x_temp; //w++ - - - - - static struct workqueue_struct *goodix_wq; static const char *goodix_ts_name ="Goodix TouchScreen of Guitar ";//"Goodix Capacitive TouchScreen"; @@ -87,10 +78,9 @@ static void guitar_reset( struct goodix_ts_data *ts,u8 ms); #endif static int err_gt82x = 0; //w++璁拌浇鏈夋病鏈夋璁惧鐨勬娴 -//#define LONGPRESS_LOCK_SPECKEY //脢脟路帽脢鹿脫脙鲁鈧芭矫劼撑捗(脠莽search艗眉)脣酶脳隆鹿艩脛脺艗眉碌脛鹿艩脛脺 +//#define LONGPRESS_LOCK_SPECKEY #ifdef LONGPRESS_LOCK_SPECKEY #define KEY_LOCK KEY_F13 -//#define ORIGIN_KEY KEY_MENU #define LOCK_LONG_PRESS_CNT 20 static int Origin2LockPressCnt = 0; static int lockflag =0; @@ -105,13 +95,6 @@ struct timer_list longkey_timer_82x; #ifdef LONGPRESS_LOCK_SPECKEY static DRIVER_ATTR(get_lock_status, 0777, glock_status_show_gt82x, NULL); #endif -/* -struct goodix_i2c_rmi_platform_data { - uint32_t version; // Use this entry for panels with // - //reservation - -}; -*/ #if 0 #define TOUCH_MAX_HEIGHT 1024 //w++2 @@ -124,36 +107,20 @@ u16 TOUCH_MAX_WIDTH; #define GT828_I2C_RATE 200000 - -/******************************************************* -锟斤拷锟杰o拷 - 锟斤拷取锟接伙拷锟斤拷锟 - 每锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷i2c_msg锟斤拷桑锟斤拷锟1锟斤拷锟斤拷息锟斤拷锟节凤拷锟酵从伙拷锟街凤拷锟 - 锟斤拷2锟斤拷锟斤拷锟节凤拷锟酵讹拷取锟斤拷址锟斤拷取锟斤拷锟斤拷荩锟矫匡拷锟斤拷锟较⑶帮拷锟斤拷锟斤拷锟绞硷拷藕锟 -锟斤拷锟斤拷 - client: i2c锟借备锟斤拷锟斤拷锟借备锟斤拷址 - buf[0]~buf[1]锟斤拷 锟斤拷锟街斤拷为锟斤拷取锟斤拷址 - buf[2]~buf[len]锟斤拷锟斤拷莼锟斤拷锟斤拷锟 - len锟斤拷 锟斤拷取锟斤拷莩锟斤拷锟 -return锟斤拷 - 执锟斤拷锟斤拷息锟斤拷 -*********************************************************/ /*Function as i2c_master_send */ - static s32 i2c_read_bytes(struct i2c_client *client, u8 *buf, s32 len) { struct i2c_msg msgs[2]; s32 ret=-1; - //锟斤拷锟斤拷写锟斤拷址 - msgs[0].flags=!I2C_M_RD; //写锟斤拷息 + msgs[0].flags=!I2C_M_RD; msgs[0].addr=client->addr; msgs[0].len=2; msgs[0].buf=&buf[0]; msgs[0].scl_rate=100000; msgs[0].udelay=2000; - //锟斤拷锟斤拷锟斤拷锟 - msgs[1].flags=I2C_M_RD;//锟斤拷锟斤拷息 + + msgs[1].flags=I2C_M_RD; msgs[1].addr=client->addr; msgs[1].len=len - ADDR_LENGTH; msgs[1].buf=&buf[2]; @@ -165,26 +132,13 @@ static s32 i2c_read_bytes(struct i2c_client *client, u8 *buf, s32 len) return ret; } -/******************************************************* -锟斤拷锟杰o拷 - 锟斤拷踊锟叫达拷锟斤拷 -锟斤拷锟斤拷 - client: i2c锟借备锟斤拷锟斤拷锟借备锟斤拷址 - buf[0]~buf[1]锟斤拷 锟斤拷锟街斤拷为写锟斤拷址 - buf[2]~buf[len]锟斤拷锟斤拷莼锟斤拷锟斤拷锟 - len锟斤拷 锟斤拷莩锟斤拷锟 -return锟斤拷 - 执锟斤拷锟斤拷息锟斤拷 -*******************************************************/ /*Function as i2c_master_send */ - static s32 i2c_write_bytes(struct i2c_client *client,u8 *data,s32 len) { struct i2c_msg msg; s32 ret=-1; - //锟斤拷锟斤拷锟借备锟斤拷址 - msg.flags=!I2C_M_RD;//写锟斤拷息 + msg.flags=!I2C_M_RD; msg.addr=client->addr; msg.len=len; msg.buf=data; @@ -195,14 +149,6 @@ static s32 i2c_write_bytes(struct i2c_client *client,u8 *data,s32 len) return ret; } -/******************************************************* -锟斤拷锟杰o拷 - 锟斤拷锟斤拷前缀锟斤拷锟斤拷 - - ts: client私锟斤拷锟斤拷萁峁癸拷锟 -return锟斤拷 - 锟缴癸拷锟斤拷锟斤拷1 -*******************************************************/ static s32 i2c_pre_cmd(struct goodix_ts_data *ts) { s32 ret; @@ -212,14 +158,6 @@ static s32 i2c_pre_cmd(struct goodix_ts_data *ts) return ret;//*/ } -/******************************************************* -锟斤拷锟杰o拷 - 锟斤拷锟酵猴拷缀锟斤拷锟斤拷 - - ts: client私锟斤拷锟斤拷萁峁癸拷锟 -return锟斤拷 - 锟缴癸拷锟斤拷锟斤拷1 -*******************************************************/ static s32 i2c_end_cmd(struct goodix_ts_data *ts) { s32 ret; @@ -229,58 +167,80 @@ static s32 i2c_end_cmd(struct goodix_ts_data *ts) return ret;//*/ } -/******************************************************* -锟斤拷锟杰o拷 - Guitar锟斤拷始锟斤拷锟斤拷锟斤拷锟斤拷锟节凤拷锟斤拷锟斤拷锟斤拷锟斤拷息锟斤拷锟斤拷取锟芥本锟斤拷息 -锟斤拷锟斤拷 - ts: client私锟斤拷锟斤拷萁峁癸拷锟 -return锟斤拷 - 执锟叫斤拷锟斤拷耄0锟斤拷示锟斤拷执锟斤拷 -*******************************************************/ + s32 goodix_init_panel(struct goodix_ts_data *ts, u8 send) { s32 ret = -1; u8 config_info[]= { - 0x0F,0x80,/*config address*/ + 0x0F,0x80,/*config address*/ #if 1 -// 300-N3216E-A00 -//0x02,0x11,0x03,0x12,0x04,0x13,0x05,0x14,0x06,0x15,0x07,0x16,0x08,0x17,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x11,0x07,0x10,0x06,0x0F,0x05,0x0E,0x04,0x0D,0x03,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x03,0xE0,0x10,0x10,0x21,0x00,0x00,0x09,0x00,0x00,0x02,0x45,0x2D,0x1C,0x03,0x00,0x05,0x00,0x02,0x58,0x03,0x20,0x25,0x29,0x27,0x2B,0x25,0x00,0x06,0x19,0x25,0x14,0x10,0x00,0x13,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 +// 300-N3216E-A00 +/* + 0x02,0x11,0x03,0x12,0x04,0x13,0x05,0x14,0x06,0x15,0x07,0x16,0x08,0x17,0x09, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x11,0x07,0x10,0x06,0x0F,0x05,0x0E,0x04,0x0D,0x03,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x03,0xE0,0x10,0x10,0x21,0x00,0x00,0x09,0x00, + 0x00,0x02,0x45,0x2D,0x1C,0x03,0x00,0x05,0x00,0x02,0x58,0x03,0x20,0x25,0x29, + 0x27,0x2B,0x25,0x00,0x06,0x19,0x25,0x14,0x10,0x00,0x13,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01 +*/ //300-N3788E-A00-V1.0 1024*768 -//0x02,0x11,0x03,0x12,0x04,0x13,0x05,0x14,0x06,0x15,0x07,0x16,0x08,0x17,0x09,0x18,0x0A,0x19,0xFF,0x13,0xFF,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x12,0x08,0x11,0x07,0x10,0x06,0x0F,0x05,0x0E,0x04,0x0D,0x03,0xFF,0x00,0xFF,0x0E,0x0F,0x10,0x11,0x12,0x09,0x03,0x88,0x88,0x88,0x25,0x00,0x00,0x08,0x00,0x00,0x02,0x3C,0x28,0x1C,0x03,0x00,0x05,0x00,0x02,0x58,0x03,0x20,0x33,0x38,0x30,0x35,0x25,0x00,0x25,0x19,0x05,0x14,0x10,0x02,0x30,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 -0x02,0x11,0x03,0x12,0x04,0x13,0x05,0x14,0x06,0x15,0x07,0x16,0x08,0x17,0x09,0x18,0x0A,0x19,0x0B,0x1A,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x12,0x08,0x11,0x07,0x10,0x06,0x0F,0x05,0x0E,0x04,0x0D,0x03,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x03,0xE0,0x10,0x10,0x19,0x00,0x00,0x08,0x00,0x00,0x02,0x45,0x2D,0x1C,0x03,0x00,0x05,0x00,0x02,0x58,0x03,0x20,0x2D,0x38,0x2F,0x3B,0x25,0x00,0x06,0x19,0x25,0x14,0x10,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 +/* + 0x02,0x11,0x03,0x12,0x04,0x13,0x05,0x14,0x06,0x15,0x07,0x16,0x08,0x17,0x09, + 0x18,0x0A,0x19,0xFF,0x13,0xFF,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C, + 0x12,0x08,0x11,0x07,0x10,0x06,0x0F,0x05,0x0E,0x04,0x0D,0x03,0xFF,0x00,0xFF, + 0x0E,0x0F,0x10,0x11,0x12,0x09,0x03,0x88,0x88,0x88,0x25,0x00,0x00,0x08,0x00, + 0x00,0x02,0x3C,0x28,0x1C,0x03,0x00,0x05,0x00,0x02,0x58,0x03,0x20,0x33,0x38, + 0x30,0x35,0x25,0x00,0x25,0x19,0x05,0x14,0x10,0x02,0x30,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01 +*/ + 0x02,0x11,0x03,0x12,0x04,0x13,0x05,0x14,0x06,0x15,0x07,0x16,0x08,0x17,0x09, + 0x18,0x0A,0x19,0x0B,0x1A,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x12,0x08,0x11,0x07,0x10,0x06,0x0F,0x05,0x0E,0x04,0x0D,0x03,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x03,0xE0,0x10,0x10,0x19,0x00,0x00,0x08,0x00, + 0x00,0x02,0x45,0x2D,0x1C,0x03,0x00,0x05,0x00,0x02,0x58,0x03,0x20,0x2D,0x38, + 0x2F,0x3B,0x25,0x00,0x06,0x19,0x25,0x14,0x10,0x00,0x01,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01 #else -0x02,0x11,0x03,0x12,0x04,0x13,0x05,0x14,0x06,0x15,0x07,0x16,0x08,0x17,0x09,0x18,0x0A,0x19,0x0B,0x1A,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x12,0x08,0x11,0x07,0x10,0x06,0x0F,0x05,0x0E,0x04,0x0D,0x03,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x03,0xE0,0x10,0x10,0x19,0x00,0x00,0x08,0x00,0x00,0x02,0x45,0x2D,0x1C,0x03,0x00,0x05,0x00,0x02,0x58,0x03,0x20,0x2D,0x38,0x2F,0x3B,0x25,0x00,0x06,0x19,0x25,0x14,0x10,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 + 0x02,0x11,0x03,0x12,0x04,0x13,0x05,0x14,0x06,0x15,0x07,0x16,0x08,0x17,0x09, + 0x18,0x0A,0x19,0x0B,0x1A,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x12,0x08,0x11,0x07,0x10,0x06,0x0F,0x05,0x0E,0x04,0x0D,0x03,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x03,0xE0,0x10,0x10,0x19,0x00,0x00,0x08,0x00, + 0x00,0x02,0x45,0x2D,0x1C,0x03,0x00,0x05,0x00,0x02,0x58,0x03,0x20,0x2D,0x38, + 0x2F,0x3B,0x25,0x00,0x06,0x19,0x25,0x14,0x10,0x00,0x01,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01 #endif }; #ifdef AUTO_SET - TOUCH_MAX_WIDTH = ((config_info[RESOLUTION_LOC] << 8)|config_info[RESOLUTION_LOC + 1]); - TOUCH_MAX_HEIGHT = ((config_info[RESOLUTION_LOC + 2] << 8)|config_info[RESOLUTION_LOC + 3]); - - GTDEBUG_MSG("TOUCH_MAX_WIDTH : 0x%d\n", (s32)TOUCH_MAX_WIDTH); - GTDEBUG_MSG("TOUCH_MAX_HEIGHT : 0x%d\n", (s32)TOUCH_MAX_HEIGHT); + TOUCH_MAX_WIDTH = ((config_info[RESOLUTION_LOC] << 8)|config_info[RESOLUTION_LOC + 1]); + TOUCH_MAX_HEIGHT = ((config_info[RESOLUTION_LOC + 2] << 8)|config_info[RESOLUTION_LOC + 3]); + + GTDEBUG_MSG("TOUCH_MAX_WIDTH : 0x%d\n", (s32)TOUCH_MAX_WIDTH); + GTDEBUG_MSG("TOUCH_MAX_HEIGHT : 0x%d\n", (s32)TOUCH_MAX_HEIGHT); #else -/* config_info[RESOLUTION_LOC] = TOUCH_MAX_WIDTH >> 8; - config_info[RESOLUTION_LOC + 1] = TOUCH_MAX_WIDTH & 0xff; - config_info[RESOLUTION_LOC + 2] = TOUCH_MAX_HEIGHT >> 8; - config_info[RESOLUTION_LOC + 3] = TOUCH_MAX_HEIGHT & 0xff;*/ +/* + config_info[RESOLUTION_LOC] = TOUCH_MAX_WIDTH >> 8; + config_info[RESOLUTION_LOC + 1] = TOUCH_MAX_WIDTH & 0xff; + config_info[RESOLUTION_LOC + 2] = TOUCH_MAX_HEIGHT >> 8; + config_info[RESOLUTION_LOC + 3] = TOUCH_MAX_HEIGHT & 0xff; +*/ #endif - if (INT_TRIGGER == GT_IRQ_FALLING) - { + if (INT_TRIGGER == GT_IRQ_FALLING) { config_info[TRIGGER_LOC] &= 0xf7; - } - else if (INT_TRIGGER == GT_IRQ_RISING) - { + } else if (INT_TRIGGER == GT_IRQ_RISING) { config_info[TRIGGER_LOC] |= 0x08; } - if (send) - { + if (send) { ret=i2c_write_bytes(ts->client,config_info, (sizeof(config_info)/sizeof(config_info[0]))); - if (ret <= 0) - { + if (ret <= 0) { return fail; } i2c_end_cmd(ts); @@ -293,10 +253,8 @@ static s32 touch_num(u8 value, s32 max) { s32 tmp = 0; - while((tmp < max) && value) - { - if ((value & 0x01) == 1) - { + while((tmp < max) && value) { + if ((value & 0x01) == 1) { tmp++; } value = value >> 1; @@ -305,31 +263,21 @@ static s32 touch_num(u8 value, s32 max) return tmp; } -/******************************************************* -锟斤拷锟杰o拷 - 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷 - 锟斤拷锟叫断达拷锟斤拷锟斤拷锟斤拷锟斤拷1锟斤拷锟斤拷锟斤拷锟捷o拷校锟斤拷锟斤拷俜锟斤拷锟斤拷锟斤拷 -锟斤拷锟斤拷 - ts: client私锟斤拷锟斤拷萁峁癸拷锟 -return锟斤拷 - void -********************************************************/ #ifdef LONGPRESS_LOCK_SPECKEY //w++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ static void open_longkey_timer_82x(unsigned long data) { - if((++Origin2LockPressCnt>LOCK_LONG_PRESS_CNT)&&(Origin2LockPressCntinput_dev, KEY_LOCK, 1); - lockflag = (lockflag)? 0 : 1; - input_sync(ts82x_temp->input_dev); - //} - } - longkey_timer_82x.expires=jiffies+msecs_to_jiffies(100); - add_timer(&longkey_timer_82x); - printk("w++++++++ Origin2LockPressCnt = %d\n",Origin2LockPressCnt); - printk("lockflag = %d\n",lockflag); + if((++Origin2LockPressCnt>LOCK_LONG_PRESS_CNT)&&(Origin2LockPressCntinput_dev, KEY_LOCK, 1); + lockflag = (lockflag)? 0 : 1; + input_sync(ts82x_temp->input_dev); + //} + } + longkey_timer_82x.expires=jiffies+msecs_to_jiffies(100); + add_timer(&longkey_timer_82x); + printk("w++++++++ Origin2LockPressCnt = %d\n",Origin2LockPressCnt); + printk("lockflag = %d\n",lockflag); } #endif @@ -349,8 +297,8 @@ static void goodix_ts_work_func(struct work_struct *work) s32 i; u8 *coor_point; u8 touch_data[2 + 2 + 5*MAX_FINGER_NUM + 1] = {READ_TOUCH_ADDR_H,READ_TOUCH_ADDR_L,0, 0}; - static u8 finger_last[MAX_FINGER_NUM]={0}; //锟较次达拷锟斤拷锟斤拷锟斤拷锟斤拷锟街革拷锟斤拷锟 - u8 finger_current[MAX_FINGER_NUM] = {0}; //锟斤拷前锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟街革拷锟斤拷锟 + static u8 finger_last[MAX_FINGER_NUM]={0}; + u8 finger_current[MAX_FINGER_NUM] = {0}; struct goodix_ts_data *ts = container_of(work, struct goodix_ts_data, work); struct i2c_client *client = ts->client; @@ -359,17 +307,14 @@ static void goodix_ts_work_func(struct work_struct *work) #ifndef INT_PORT COORDINATE_POLL: #endif - if( tmp > 9) - { + if( tmp > 9) { dev_info(&(ts->client->dev), "Because of transfer error,touchscreen stop working.\n"); goto XFER_ERROR ; } - //锟斤拷锟介将锟斤拷锟揭伙拷锟斤拷远锟饺★拷锟 ret=i2c_read_bytes(ts->client, touch_data,sizeof(touch_data)/sizeof(touch_data[0])); i2c_end_cmd(ts); - if(ret <= 0) - { + if(ret <= 0) { dev_err(&(ts->client->dev),"I2C transfer error. Number:%d\n ", ret); ts->bad_data = 1; tmp ++; @@ -380,141 +325,109 @@ static void goodix_ts_work_func(struct work_struct *work) #endif } - if(ts->bad_data) - { + if(ts->bad_data) { //TODO:Is sending config once again (to reset the chip) useful? ts->bad_data = 0; msleep(20); } - if((touch_data[2]&0xC0)!=0x80) - { + if((touch_data[2]&0xC0)!=0x80) { goto DATA_NO_READY; } key = touch_data[3]&0x0f; // 1, 2, 4, 8 - if (key == 0x0f) - { - if (fail == goodix_init_panel(ts, 1)) - { -/**/ GTDEBUG_COOR("Reload config failed!\n"); - } - else - { - GTDEBUG_COOR("Reload config successfully!\n"); + if (key == 0x0f) { + if (fail == goodix_init_panel(ts, 1)) { + GTDEBUG_COOR("Reload config failed!\n"); + } else { + GTDEBUG_COOR("Reload config successfully!\n"); } goto XFER_ERROR; } finger = (u8)touch_num(touch_data[2]&0x1f, MAX_FINGER_NUM); -/**/GTDEBUG_COOR("touch num:%x\n", finger); + GTDEBUG_COOR("touch num:%x\n", finger); - for (i = 0;i < MAX_FINGER_NUM; i++) - { + for (i = 0;i < MAX_FINGER_NUM; i++) { finger_current[i] = !!(touch_data[2] & (0x01<<(i))); } - - //锟斤拷锟斤拷校锟斤拷锟 coor_point = &touch_data[4]; chk_sum = 0; - for ( i = 0; i < 5*finger; i++) - { + for ( i = 0; i < 5*finger; i++) { chk_sum += coor_point[i]; -/**/ // GTDEBUG_COOR("%5x", coor_point[i]); + //GTDEBUG_COOR("%5x", coor_point[i]); } -/**///GTDEBUG_COOR("\ncheck sum:%x\n", chk_sum); -/**///GTDEBUG_COOR("check sum byte:%x\n", coor_point[5*finger]); - if (chk_sum != coor_point[5*finger]) - { + //GTDEBUG_COOR("\ncheck sum:%x\n", chk_sum); + //GTDEBUG_COOR("check sum byte:%x\n", coor_point[5*finger]); + if (chk_sum != coor_point[5*finger]) { goto XFER_ERROR; } - //锟斤拷锟斤拷锟斤拷锟// - if (finger) - { - for(i = 0, position=0;position < MAX_FINGER_NUM; position++) - { - if(finger_current[position]) - { - X_value = (coor_point[i] << 8) | coor_point[i + 1]; - Y_value = (coor_point[i + 2] << 8) | coor_point[i + 3]; - - input_mt_slot(ts->input_dev, position); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, FLAG_DOWN); + if (finger) { + for(i = 0, position=0;position < MAX_FINGER_NUM; position++) { + if(finger_current[position]) { + X_value = (coor_point[i] << 8) | coor_point[i + 1]; + Y_value = (coor_point[i + 2] << 8) | coor_point[i + 3]; - // input_report_key(ts->input_dev, BTN_TOUCH, 1); - // input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, position - 1); - if(pdata->swap_xy){ + input_mt_slot(ts->input_dev, position); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, FLAG_DOWN); + + //input_report_key(ts->input_dev, BTN_TOUCH, 1); + //input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, position - 1); + if(pdata->swap_xy) { value_tmp = X_value; X_value = Y_value; Y_value = value_tmp; } //printk("goodix_touch_82x X_value=%d,Y_value=%d\n",X_value,Y_value); - if(pdata->xpol) + if(pdata->xpol) X_value = pdata->xmax - X_value; if(pdata->ypol) Y_value = pdata->ymax - Y_value; - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, X_value); //can change x-y!!! - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, Y_value); - // input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,15); - // input_mt_sync(ts->input_dev); - i += 5; + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, X_value); //can change x-y!!! + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, Y_value); + //input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,15); + //input_mt_sync(ts->input_dev); + i += 5; - // /**/ GTDEBUG_COOR("FI:%x X:%04d Y:%04d\n",position, (s32)Y_value,(s32)X_value); -// printk("-----------touch_num:%d;--------FI:%x----------- X:%04d ----------Y:%04d\n",finger,position, (s32)X_value,(s32)Y_value); - /**/ // GTDEBUG_COOR("Y:%d\n", (s32)Y_value); - } - else if(finger_last[position]) - { - input_mt_slot(ts->input_dev, position); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false); - GTDEBUG_COOR(" Finger %d release!!\n",position); - } - } - } - else - { - for(position=0;position < MAX_FINGER_NUM; position++) - { - if( finger_last[position]) - { - input_mt_slot(ts->input_dev, position); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false); - GTDEBUG_COOR(" Finger %d release!!\n",position); - } - } - } + //GTDEBUG_COOR("FI:%x X:%04d Y:%04d\n",position, (s32)Y_value,(s32)X_value); + //printk("-----------touch_num:%d;--------FI:%x----------- X:%04d ----------Y:%04d\n",finger,position, (s32)X_value,(s32)Y_value); + //GTDEBUG_COOR("Y:%d\n", (s32)Y_value); + } else if(finger_last[position]) { + input_mt_slot(ts->input_dev, position); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false); + GTDEBUG_COOR(" Finger %d release!!\n",position); + } + } + } else { + for(position=0;position < MAX_FINGER_NUM; position++) { + if( finger_last[position]) { + input_mt_slot(ts->input_dev, position); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false); + GTDEBUG_COOR(" Finger %d release!!\n",position); + } + } + } input_sync(ts->input_dev); - for(position=0;positionuse_irq && ts->irq_is_disable == 1) - { - ts->irq_is_disable = 0; - enable_irq(ts->client->irq); - } + if(ts->use_irq && ts->irq_is_disable == 1) { + ts->irq_is_disable = 0; + enable_irq(ts->client->irq); + } } -/******************************************************* -锟斤拷锟杰o拷 - 锟斤拷时锟斤拷锟斤拷应锟斤拷锟斤拷 - 锟缴硷拷时锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟饺达拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟叫o拷之锟斤拷锟斤拷锟铰硷拷时 -锟斤拷锟斤拷 - timer锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷募锟绞憋拷锟 -return锟斤拷 - 锟斤拷时锟斤拷锟斤拷锟斤拷模式锟斤拷HRTIMER_NORESTART锟斤拷示锟斤拷锟斤拷要锟皆讹拷锟斤拷锟斤拷 -********************************************************/ static enum hrtimer_restart goodix_ts_timer_func(struct hrtimer *timer) { struct goodix_ts_data *ts = container_of(timer, struct goodix_ts_data, timer); @@ -525,43 +438,24 @@ static enum hrtimer_restart goodix_ts_timer_func(struct hrtimer *timer) return HRTIMER_NORESTART; } -/******************************************************* -锟斤拷锟杰o拷 - 锟叫讹拷锟斤拷应锟斤拷锟斤拷 - 锟斤拷锟叫断达拷锟斤拷锟斤拷锟斤拷锟饺达拷锟斤拷锟斤拷锟斤拷锟?锟斤拷锟斤拷锟斤拷 -锟斤拷锟斤拷 -return锟斤拷 - IRQ_HANDLED:interrupt was handled by this device -********************************************************/ static irqreturn_t goodix_ts_irq_handler(s32 irq, void *dev_id) { - struct goodix_ts_data *ts = (struct goodix_ts_data*)dev_id; + struct goodix_ts_data *ts = (struct goodix_ts_data*)dev_id; - if (ts->use_irq && (!ts->irq_is_disable)) - { - disable_irq_nosync(ts->client->irq); - ts->irq_is_disable = 1; - } - - queue_work(goodix_wq, &ts->work); - - return IRQ_HANDLED; + if (ts->use_irq && (!ts->irq_is_disable)) { + disable_irq_nosync(ts->client->irq); + ts->irq_is_disable = 1; + } + + queue_work(goodix_wq, &ts->work); + + return IRQ_HANDLED; } -/******************************************************* -锟斤拷锟杰o拷 - 锟斤拷锟斤拷锟皆达拷锟斤拷锟斤拷锟絀C锟斤拷锟斤拷睡锟竭伙拷锟戒唤锟斤拷 -锟斤拷锟斤拷 - on: 0锟斤拷示使锟斤拷睡锟竭o拷1为锟斤拷锟斤拷 -return锟斤拷 - 锟角凤拷锟斤拷锟矫成癸拷锟斤拷success为锟缴癸拷 - 锟斤拷锟斤拷锟诫:-1为i2c锟斤拷锟斤拷-2为GPIO锟斤拷锟斤拷-EINVAL为锟斤拷锟斤拷on锟斤拷锟斤拷 -********************************************************/ //#if defined(INT_PORT) // 0 : sleep 1 wake up static s32 goodix_ts_power(struct goodix_ts_data * ts, s32 on) { s32 ret = -1; - u8 i2c_control_buf[3] = {0x0f,0xf2,0xc0}; //suspend cmd if(ts == NULL || !ts->use_irq) @@ -579,7 +473,6 @@ static s32 goodix_ts_power(struct goodix_ts_data * ts, s32 on) GPIO_SET_VALUE(ts->interrupt_port, 1); GPIO_DIRECTION_INPUT(ts->interrupt_port); GPIO_PULL_UPDOWN(ts->interrupt_port, 0); - return success; default: @@ -601,11 +494,10 @@ static s32 init_input_dev(struct goodix_ts_data *ts) return fail; } -// ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); -// ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); - // ts->input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);// absolute coor (x,y) - - + //ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + //ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + //ts->input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);// absolute coor (x,y) + goodix_init_panel(ts, 0); #ifdef GOODIX_MULTI_TOUCH @@ -617,12 +509,13 @@ static s32 init_input_dev(struct goodix_ts_data *ts) input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, TOUCH_MAX_HEIGHT, 0, 0); input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, TOUCH_MAX_WIDTH, 0, 0); - /* input_mt_init_slots(ts->input_dev, MAX_FINGER_NUM); - input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); - input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); - input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, TOUCH_MAX_HEIGHT, 0, 0); - input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, TOUCH_MAX_WIDTH, 0, 0); - */ + /* + input_mt_init_slots(ts->input_dev, MAX_FINGER_NUM); + input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, TOUCH_MAX_HEIGHT, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, TOUCH_MAX_WIDTH, 0, 0); + */ #else input_set_abs_params(ts->input_dev, ABS_X, 0, TOUCH_MAX_HEIGHT, 0, 0); input_set_abs_params(ts->input_dev, ABS_Y, 0, TOUCH_MAX_WIDTH, 0, 0); @@ -641,8 +534,7 @@ static s32 init_input_dev(struct goodix_ts_data *ts) set_bit(KEY_LOCK, ts->input_dev->keybit); #endif ret = input_register_device(ts->input_dev); - if (ret) - { + if (ret) { dev_err(&ts->client->dev,"Probe: Unable to register %s input device\n", ts->input_dev->name); input_free_device(ts->input_dev); return fail; @@ -656,46 +548,37 @@ static s32 set_pins(struct goodix_ts_data *ts) { s32 ret = -1; - // ts->client->irq=TS_INT; //If not defined in client - if (ts->client->irq) - { - ret = GPIO_REQUEST(ts->interrupt_port, "TS_INT"); //Request IO - if (ret < 0) - { - dev_err(&ts->client->dev, "Failed to request GPIO:%d, ERRNO:%d\n",(s32)ts->interrupt_port,ret); - goto err_gpio_request_failed; - } - GTDEBUG_MSG("Request int port successfully!\n"); - - GPIO_DIRECTION_INPUT(ts->interrupt_port); - GPIO_PULL_UPDOWN(ts->interrupt_port, 0); -// GPIO_CFG_PIN(INT_PORT, INT_CFG); //Set IO port function - - -ret = request_irq(gpio_to_irq(ts->interrupt_port), goodix_ts_irq_handler, + //ts->client->irq=TS_INT; //If not defined in client + if (ts->client->irq) { + ret = GPIO_REQUEST(ts->interrupt_port, "TS_INT"); //Request IO + if (ret < 0) { + dev_err(&ts->client->dev, "Failed to request GPIO:%d, ERRNO:%d\n",(s32)ts->interrupt_port,ret); + goto err_gpio_request_failed; + } + GTDEBUG_MSG("Request int port successfully!\n"); + + GPIO_DIRECTION_INPUT(ts->interrupt_port); + GPIO_PULL_UPDOWN(ts->interrupt_port, 0); + //GPIO_CFG_PIN(INT_PORT, INT_CFG); //Set IO port function + + ret = request_irq(gpio_to_irq(ts->interrupt_port), goodix_ts_irq_handler, IRQF_TRIGGER_FALLING, ts->client->name, ts); - // ret = request_irq(ts->client->irq, goodix_ts_irq_handler, INT_TRIGGER, ts->client->name, ts); - - if (ret != 0) - { - dev_err(&ts->client->dev,"Cannot allocate ts INT!ERRNO:%d\n", ret); - GPIO_DIRECTION_INPUT(ts->interrupt_port); - GPIO_FREE(ts->interrupt_port); - goto err_gpio_request_failed; - } - else - { - disable_irq(ts->client->irq); - ts->use_irq = 1; - ts->irq_is_disable = 1; - dev_dbg(&ts->client->dev, "Reques EIRQ %d successed on GPIO:%d\n", gpio_to_irq(ts->interrupt_port), ts->interrupt_port); - } - } + if (ret != 0) { + dev_err(&ts->client->dev,"Cannot allocate ts INT!ERRNO:%d\n", ret); + GPIO_DIRECTION_INPUT(ts->interrupt_port); + GPIO_FREE(ts->interrupt_port); + goto err_gpio_request_failed; + } else { + disable_irq(ts->client->irq); + ts->use_irq = 1; + ts->irq_is_disable = 1; + dev_dbg(&ts->client->dev, "Reques EIRQ %d successed on GPIO:%d\n", gpio_to_irq(ts->interrupt_port), ts->interrupt_port); + } + } err_gpio_request_failed: - if (!ts->use_irq) - { + if (!ts->use_irq) { hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ts->timer.function = goodix_ts_timer_func; hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); @@ -703,16 +586,13 @@ ret = request_irq(gpio_to_irq(ts->interrupt_port), goodix_ts_irq_handler, } ret = GPIO_REQUEST(ts->reset_port, "TS_RESET"); //Request IO - if (ret < 0) - { + if (ret < 0) { dev_err(&ts->client->dev, "Failed to request GPIO:%d, ERRNO:%d\n",(s32)ts->reset_port,ret); - } - else - { + } else { ts->use_reset = 1; GPIO_DIRECTION_OUTPUT(ts->reset_port,1); GPIO_PULL_UPDOWN(ts->reset_port, 0); - GTDEBUG_MSG("Request reset port successfully!\n"); + GTDEBUG_MSG("Request reset port successfully!\n"); } dev_info(&ts->client->dev,"Start %s in %s mode\n", @@ -721,49 +601,31 @@ ret = request_irq(gpio_to_irq(ts->interrupt_port), goodix_ts_irq_handler, return ts->use_irq; } -/******************************************************* -锟斤拷锟杰o拷 - 锟斤拷锟斤拷锟斤拷探锟解函锟斤拷 - 锟斤拷注锟斤拷锟斤拷时锟斤拷锟斤拷(要锟斤拷锟斤拷诙锟接︼拷锟絚lient)锟斤拷 - 锟斤拷锟斤拷IO,锟叫断碉拷锟斤拷源锟斤拷锟诫;锟借备注锟结;锟斤拷锟斤拷锟斤拷锟斤拷始锟斤拷锟饺癸拷锟斤拷 -锟斤拷锟斤拷 - client锟斤拷锟斤拷锟斤拷锟斤拷璞革拷峁癸拷锟 - id锟斤拷锟借备ID -return锟斤拷 - 执锟叫斤拷锟斤拷耄0锟斤拷示锟斤拷执锟斤拷 -********************************************************/ static s32 goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { s32 ret = 0; s32 retry=0; struct goodix_ts_data *ts = NULL; struct goodix_i2c_rmi_platform_data *pdata = client->dev.platform_data; - //struct ft5406_platform_data *pdata = pdata = client->dev.platform_data; + //struct ft5406_platform_data *pdata = pdata = client->dev.platform_data; printk("w++++++goodix_ts_probe gt28x "); - if (pdata->init_platform_hw) - { + if (pdata->init_platform_hw) { pdata->init_platform_hw(); } -// GTDEBUG("Start to install Goodix Capacitive TouchScreen driver.\n"); -// GTDEBUG("*DRIVER INFORMATION\n"); -// GTDEBUG("**RELEASE DATE:%s.\n", RELEASE_DATE); -// GTDEBUG("**COMPILE TIME:%s, %s.\n", __DATE__, __TIME__); -// printk("gt82x---0000000000000000\n"); + //printk("gt82x---0000000000000000\n"); //Check I2C function - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) - { + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, "Must have I2C_FUNC_I2C.\n"); return -ENODEV; } ts = kzalloc(sizeof(*ts), GFP_KERNEL); - if (ts == NULL) - { + if (ts == NULL) { return -ENOMEM; } - pdata = client->dev.platform_data; + pdata = client->dev.platform_data; INIT_WORK(&ts->work, goodix_ts_work_func); //init work_struct ts->client = client; @@ -776,8 +638,8 @@ static s32 goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id ts->reset_port=pdata->gpio_reset; i2c_set_clientdata(client, ts); - if (fail == init_input_dev(ts)) - { kfree(ts); + if (fail == init_input_dev(ts)) { + kfree(ts); return -1; } set_pins(ts); @@ -791,8 +653,7 @@ static s32 goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id init_wr_node(client); #endif #ifdef AUTO_UPDATE_GUITAR - if (0xff == init_update_proc(ts)) - { + if (0xff == init_update_proc(ts)) { GTDEBUG_MSG("Need update!\n"); return 0; } @@ -802,41 +663,35 @@ static s32 goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id #endif //Test I2C connection. -// GTDEBUG_MSG("GT82X++++++ Testing I2C connection...\n"); - for(retry = 0;retry < 3; retry++) - { - ret = i2c_pre_cmd(ts); - if (ret > 0) - break; - msleep(20); + //GTDEBUG_MSG("GT82X++++++ Testing I2C connection...\n"); + for(retry = 0;retry < 3; retry++) { + ret = i2c_pre_cmd(ts); + if (ret > 0) + break; + msleep(20); } - if(ret <= 0) - { - dev_err(&client->dev, "Warnning: I2C communication might be ERROR!\n"); - GTDEBUG_MSG("I2C test failed. I2C addr:%x\n", client->addr); - goodix_ts_remove(ts->client); - return -1; + if(ret <= 0) { + dev_err(&client->dev, "Warnning: I2C communication might be ERROR!\n"); + GTDEBUG_MSG("I2C test failed. I2C addr:%x\n", client->addr); + goodix_ts_remove(ts->client); + return -1; } -// printk("gt82x---777777777777777\n"); - //Send config - for (retry = 0; retry < 3; retry++) - { - if (success == goodix_init_panel(ts, 1)) - { - GTDEBUG_MSG("Initialize successfully!\n"); - break; - } - } - if (retry >= 3) - { + //printk("gt82x---777777777777777\n"); + //Send config + for (retry = 0; retry < 3; retry++) { + if (success == goodix_init_panel(ts, 1)) { + GTDEBUG_MSG("Initialize successfully!\n"); + break; + } + } + if (retry >= 3) { ts->bad_data=1; GTDEBUG_MSG("Initialize failed!\n"); goodix_ts_remove(ts->client); return -1; } //Enable interrupt - if(ts->use_irq && ts->irq_is_disable == 1) - { + if(ts->use_irq && ts->irq_is_disable == 1) { ts->irq_is_disable = 0; enable_irq(client->irq); } @@ -844,15 +699,6 @@ static s32 goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id return 0; } - -/******************************************************* -锟斤拷锟杰o拷 - 锟斤拷锟斤拷源锟酵凤拷 -锟斤拷锟斤拷 - client锟斤拷锟借备锟结构锟斤拷 -return锟斤拷 - 执锟叫斤拷锟斤拷耄瑂uccess锟斤拷示锟斤拷执锟斤拷 -********************************************************/ static s32 goodix_ts_remove(struct i2c_client *client) { struct goodix_ts_data *ts = i2c_get_clientdata(client); @@ -867,17 +713,15 @@ static s32 goodix_ts_remove(struct i2c_client *client) uninit_wr_node(); #endif - if (ts && ts->use_irq) - { + if (ts && ts->use_irq) { free_irq(client->irq, ts); GPIO_DIRECTION_INPUT(ts->interrupt_port); GPIO_FREE(ts->interrupt_port); - } - else if(ts) + } else if(ts) { hrtimer_cancel(&ts->timer); + } - if (ts && ts->use_reset) - { + if (ts && ts->use_reset) { GPIO_DIRECTION_INPUT(ts->reset_port); GPIO_FREE(ts->interrupt_port); } @@ -889,37 +733,30 @@ static s32 goodix_ts_remove(struct i2c_client *client) return success; } -//停锟斤拷锟借备 static s32 goodix_ts_suspend(struct i2c_client *client, pm_message_t mesg) { s32 ret; struct goodix_ts_data *ts = i2c_get_clientdata(client); - if (ts->irq_is_disable == 2) - { + if (ts->irq_is_disable == 2) { return 0; } - if (ts->use_irq) - { - if (!ts->irq_is_disable) - { + if (ts->use_irq) { + if (!ts->irq_is_disable) { disable_irq(client->irq); ts->irq_is_disable = 1; } - } - else - { + } else { hrtimer_cancel(&ts->timer); } - if (ts->power) - { + if (ts->power) { ret = ts->power(ts, 0); if (ret <= 0) GTDEBUG_MSG(KERN_ERR "goodix_ts_resume power off failed\n"); - } - printk("-----gt813------suspend.\n"); + } + printk("-----gt813------suspend.\n"); return 0; } @@ -928,28 +765,23 @@ static s32 goodix_ts_resume(struct i2c_client *client) s32 ret; struct goodix_ts_data *ts = i2c_get_clientdata(client); - if (ts->irq_is_disable == 2) - { + if (ts->irq_is_disable == 2) { return 0; } - if (ts->power) - { + if (ts->power) { ret = ts->power(ts, 1); if (ret <= 0) GTDEBUG_MSG(KERN_ERR "goodix_ts_resume power on failed\n"); } - if (ts->use_irq) - { + if (ts->use_irq) { ts->irq_is_disable = 0; enable_irq(client->irq); - } - else - { + } else { hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); } - printk("-----gt813------goodix_ts_resume.\n"); + printk("-----gt813------goodix_ts_resume.\n"); return success; } @@ -969,17 +801,16 @@ static void goodix_ts_late_resume(struct early_suspend *h) goodix_ts_resume(ts->client); } #endif -//******************************Begin of firmware update surpport******************************* +//******************************Begin of firmware update surpport******************************* #ifndef AUTO_UPDATE_GUITAR static void guitar_reset( struct goodix_ts_data *ts,u8 ms) { - GPIO_DIRECTION_OUTPUT(ts->reset_port, 0); GPIO_SET_VALUE(ts->reset_port, 0); msleep(ms); - // GPIO_DIRECTION_OUTPUT(ts->reset_port); + //GPIO_DIRECTION_OUTPUT(ts->reset_port); GPIO_SET_VALUE(ts->reset_port, 1); GPIO_PULL_UPDOWN(ts->reset_port, 0); @@ -989,15 +820,12 @@ static void guitar_reset( struct goodix_ts_data *ts,u8 ms) } #endif - -//锟斤拷锟斤拷锟节革拷锟斤拷锟 锟借备锟斤拷锟借备ID 锟叫憋拷 //only one client static const struct i2c_device_id goodix_ts_id[] = { {"Goodix-TS-82X", 0 }, { } }; -//锟借备锟斤拷峁癸拷锟 static struct i2c_driver goodix_ts_driver = { .probe = goodix_ts_probe, .remove = goodix_ts_remove, @@ -1011,27 +839,21 @@ static struct i2c_driver goodix_ts_driver = { .owner = THIS_MODULE, }, }; -/******************************************************* -锟斤拷锟杰o拷 - 锟斤拷锟斤拷睾锟斤拷锟 -return锟斤拷 - 执锟叫斤拷锟斤拷耄0锟斤拷示锟斤拷执锟斤拷 -********************************************************/ + static s32 __devinit goodix_ts_init(void) { int ret; - printk("+++++++++++++++++++++++++++++liqing.\n"); + + printk("+++++++++++++++++++++++++++++liqing.\n"); goodix_wq = create_workqueue("goodix_wq"); //create a work queue and worker thread - if (!goodix_wq) - { - GTDEBUG_MSG(KERN_ALERT "creat workqueue faiked\n"); - return -ENOMEM; + if (!goodix_wq) { + GTDEBUG_MSG(KERN_ALERT "creat workqueue faiked\n"); + return -ENOMEM; } ret = i2c_add_driver(&goodix_ts_driver); - if (ret) - { - printk("Register raydium_ts driver failed gt82x.\n"); - return ret; //w++ + if (ret) { + printk("Register raydium_ts driver failed gt82x.\n"); + return ret; //w++ } #ifdef LONGPRESS_LOCK_SPECKEY if(err_gt82x>=0) //w++ @@ -1041,24 +863,18 @@ static s32 __devinit goodix_ts_init(void) return ret; } -/******************************************************* -锟斤拷锟杰o拷 - 锟斤拷卸锟截猴拷锟斤拷 -锟斤拷锟斤拷 - client锟斤拷锟借备锟结构锟斤拷 -********************************************************/ static void __exit goodix_ts_exit(void) { - GTDEBUG_MSG(KERN_ALERT "Touchscreen driver of guitar exited.\n"); - i2c_del_driver(&goodix_ts_driver); - if (goodix_wq) - destroy_workqueue(goodix_wq); //release our work queue + GTDEBUG_MSG(KERN_ALERT "Touchscreen driver of guitar exited.\n"); + i2c_del_driver(&goodix_ts_driver); + if (goodix_wq) + destroy_workqueue(goodix_wq); //release our work queue #ifdef LONGPRESS_LOCK_SPECKEY //w++ driver_remove_file(&goodix_ts_driver.driver, &driver_attr_get_lock_status); #endif } -module_init(goodix_ts_init); //锟斤拷锟斤拷始锟斤拷锟斤拷 +module_init(goodix_ts_init); module_exit(goodix_ts_exit); MODULE_DESCRIPTION("Goodix Touchscreen Driver"); From 365c2280152515951c5c62c0f1edb8a5aa344186 Mon Sep 17 00:00:00 2001 From: Zhaoyifeng Date: Tue, 7 Aug 2012 15:27:26 +0800 Subject: [PATCH 096/261] nand driver: add 2928 nand driver. --- arch/arm/mach-rk2928/devices.c | 19 ++ drivers/mtd/rknand/Makefile | 1 - drivers/mtd/rknand/api_flash.h | 2 +- drivers/mtd/rknand/epphal.h | 500 ---------------------------- drivers/mtd/rknand/nand_config.h | 77 ----- drivers/mtd/rknand/rknand_base.h | 2 + drivers/mtd/rknand/rknand_base_ko.c | 28 +- drivers/mtd/rknand/typedef.h | 62 ---- 8 files changed, 45 insertions(+), 646 deletions(-) delete mode 100755 drivers/mtd/rknand/epphal.h delete mode 100755 drivers/mtd/rknand/nand_config.h delete mode 100755 drivers/mtd/rknand/typedef.h diff --git a/arch/arm/mach-rk2928/devices.c b/arch/arm/mach-rk2928/devices.c index 2fba48058870..1dc4df27e90b 100755 --- a/arch/arm/mach-rk2928/devices.c +++ b/arch/arm/mach-rk2928/devices.c @@ -544,6 +544,22 @@ static void __init rk2928_init_spim(void) #endif } +#ifdef CONFIG_MTD_NAND_RK29XX +static struct resource resources_nand[] = { + { + .start = RK2928_NANDC_PHYS, + .end = RK2928_NANDC_PHYS + RK2928_NANDC_SIZE - 1, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device device_nand = { + .name = "rk29xxnand", + .id = -1, + .resource = resources_nand, + .num_resources = ARRAY_SIZE(resources_nand), +}; +#endif #ifdef CONFIG_HDMI_RK2928 static struct resource resource_hdmi[] = { [0] = { @@ -769,6 +785,9 @@ static int __init rk2928_init_devices(void) rk2928_init_uart(); rk2928_init_i2c(); rk2928_init_spim(); +#ifdef CONFIG_MTD_NAND_RK29XX + platform_device_register(&device_nand); +#endif #ifdef CONFIG_ADC_RK30 platform_device_register(&device_adc); #endif diff --git a/drivers/mtd/rknand/Makefile b/drivers/mtd/rknand/Makefile index bdda17ab8b26..964ea55489f3 100755 --- a/drivers/mtd/rknand/Makefile +++ b/drivers/mtd/rknand/Makefile @@ -4,6 +4,5 @@ # $Id: Makefile,v 1.3 2011/01/21 10:12:56 Administrator Exp $ # obj-$(CONFIG_MTD_NAND_RK29XX) += rknand_base_ko.o -#obj-$(CONFIG_MTD_RKNAND_BUFFER) += rk30xxnand_ko.o diff --git a/drivers/mtd/rknand/api_flash.h b/drivers/mtd/rknand/api_flash.h index fe004ded9be0..2340d4bb9c0d 100755 --- a/drivers/mtd/rknand/api_flash.h +++ b/drivers/mtd/rknand/api_flash.h @@ -184,7 +184,7 @@ int FtlPageRead(int Index, int nSec, void *buf); 入口参数:pbuf 出口参数: 调用函数: -注意信息:需要在FTLInit后才能调用,pbuf大小需要大于等于512 bytes,返回信息为512 +注意信息:需要在flash 驱动加载后才能调用,pbuf大小需要大于等于512 bytes,返回信息为512 bytes。 ***************************************************************************/ char GetSNSectorInfo(char * pbuf); diff --git a/drivers/mtd/rknand/epphal.h b/drivers/mtd/rknand/epphal.h deleted file mode 100755 index b966cea8a404..000000000000 --- a/drivers/mtd/rknand/epphal.h +++ /dev/null @@ -1,500 +0,0 @@ -/******************************************************************************** -********************************************************************************* - COPYRIGHT (c) 2004 BY ROCK-CHIP FUZHOU - -- ALL RIGHTS RESERVED -- - -File Name: epphal.h -Author: XUESHAN LIN -Created: 1st Dec 2008 -Modified: -Revision: 1.00 -******************************************************************************** -********************************************************************************/ -#ifndef _EPPHAL_H -#define _EPPHAL_H -#define read_XDATA32(address) (*((uint32 volatile*)(address))) -#define write_XDATA32(address, value) (*((uint32 volatile*)(address)) = value) - -typedef enum _CLK_GATE -{ - /* SCU CLK GATE 0 CON */ - CLK_GATE_CORE = 0, - CLK_GATE_CORE_APB, - CLK_GATE_CORE_ATB, - CLK_GATE_CPU_AXI, - CLK_GATE_CPU_AXI2, - CLK_GATE_CPU_AHB, - CLK_GATE_CPU_MATRIX1_AHB, - CLK_GATE_CPU_APB, - CLK_GATE_CPU_ATB, - CLK_GATE_DMA0, - CLK_GATE_DMA1, - CLK_GATE_GIC, - CLK_GATE_IMEM, - CLK_GATE_EBROM = 14, - CLK_GATE_I2S0, - CLK_GATE_I2S1, - CLK_GATE_SPDIF, - CLK_GATE_DDR_PHY, - CLK_GATE_DDR_REG, - CLK_GATE_DDR_CPU, - CLK_GATE_EFUSE, - CLK_GATE_TZPC, - CLK_GATE_TIMER0, - CLK_GATE_GPIO0, - CLK_GATE_UART0, - CLK_GATE_I2C0, - CLK_GATE_DEBUG, - CLK_GATE_TPIU, - CLK_GATE_RTC, - CLK_GATE_PMU, - CLK_GATE_GRF, - - /* SCU CLK GATE 1 CON */ - CLK_GATE_PEIRPH_AXI = 32, - CLK_GATE_PEIRPH_AHB, - CLK_GATE_PEIRPH_APB, - CLK_GATE_EMEM, - CLK_GATE_USB, - CLK_GATE_DMA2, - CLK_GATE_DDR_PERIPH, - CLK_GATE_PERIPH, - - /* FIXME */ - CLK_GATE_SMC_AXI, - CLK_GATE_SMC, - CLK_GATE_MAC_AHB = 43, - CLK_GATE_MAC_PHY, - CLK_GATE_MAC_TX, - CLK_GATE_MAC_RX, - CLK_GATE_HIF, - CLK_GATE_NANDC, - CLK_GATE_HSADC_AHB, - CLK_GATE_HSADC, - CLK_GATE_SDMMC0_AHB, - CLK_GATE_SDMMC0, - CLK_GATE_SDMMC1_AHB, - CLK_GATE_SDMMC1, - CLK_GATE_EMMC_AHB, - CLK_GATE_EMMC, - CLK_GATE_USBOTG0, - CLK_GATE_USBPHY0, - CLK_GATE_USBOTG1, - CLK_GATE_USBPHY1, - CLK_GATE_UHOST_AHB, - CLK_GATE_UHOST, - CLK_GATE_PID_FILTER, - - /* SCU CLK GATE 2 CON */ - CLK_GATE_UART1 = 64, - CLK_GATE_UART2, - CLK_GATE_UART3, - CLK_GATE_TIMER1, - CLK_GATE_TIMER2, - CLK_GATE_TIMER3, - CLK_GATE_GPIO1, - CLK_GATE_GPIO2, - CLK_GATE_GPIO3, - CLK_GATE_GPIO4, - CLK_GATE_GPIO5, - CLK_GATE_GPIO6, - CLK_GATE_I2C1, - CLK_GATE_I2C2, - CLK_GATE_I2C3, - CLK_GATE_SPI0, - CLK_GATE_SPI1, - CLK_GATE_VIP_SLAVE = 82, - CLK_GATE_WDT, - CLK_GATE_SARADC, - CLK_GATE_PWM, - CLK_GATE_VIP_BUS, - CLK_GATE_VIP_MATRIX, - CLK_GATE_VIP, - CLK_GATE_VIP_INPUT, - CLK_GATE_JTAG, - - /* CRU CLK GATE 3 CON */ - CLK_GATE_LCDC_AXI = 96, - CLK_GATE_DDR_LCDC_AXI, - CLK_GATE_LCDC_AHB, - CLK_GATE_LCDC, - CLK_GATE_IPP_AXI, - CLK_GATE_IPP_AHB, - CLK_GATE_EBOOK_AHB, - CLK_GATE_EBOOK, - CLK_GATE_DISPLAY_MATRIX_AXI, - CLK_GATE_DISPLAY_MATRIX_AHB, - CLK_GAET_VEPU_AXI, - CLK_GATE_DDR_VEDU_AXI, - CLK_GATE_VDPU_AXI, - CLK_GATE_DDR_VDPU_AXI, - CLK_GATE_GPU, - CLK_GATE_GPU_AXI, - CLK_GATE_DDR_GPU_AXI, - CLK_GATE_GPU_AHB, - CLK_GATE_VEPU_AHB, - CLK_GATE_VDPU_AHB, - CLK_GATE_CPU_VCODEC_AHB, - CLK_GATE_CPU_DISPLAY_AHB, - CLK_GATE_MAX -}eCLK_GATE; - - -//1寄存器结构定义 -//INTC Registers -typedef volatile struct tagGICD_REG -{ - uint32 ICDDCR ; //0x000 - uint32 ICDICTR ; //0x004 - uint32 ICDIIDR ; //0x008 - uint32 RESERVED0[29] ; - uint32 ICDISR[4] ; // 0x080 - uint32 RESERVED1[28] ; - uint32 ICDISER[4] ; // 0x100 - uint32 RESERVED2[28] ; - uint32 ICDICER[4] ; //0x180 - uint32 RESERVED3[28] ; - uint32 ICDISPR[4] ; //0x200 - uint32 RESERVED4[28] ; - uint32 ICDICPR[4] ; //0x280 - uint32 RESERVED5[28] ; - uint32 ICDIABR[4] ; //0x300 - uint32 RESERVED6[60] ; - uint32 ICDIPR_SGI[4] ; // 0x400 - uint32 ICDIPR_PPI[4] ; // 0x410 - uint32 ICDIPR_SPI[18] ; //0x420 - uint32 RESERVED57[486] ; - uint32 ICDICFR[7] ; //0xc00 - uint32 RESERVED8[185] ; - uint32 ICDSGIR ; //0xf00 -}GICD_REG, *pGICD_REG; -typedef volatile struct tagGICC_REG -{ - uint32 ICCICR ; //0x00 - uint32 ICCPMR ; //0x04 - uint32 ICCBPR ; //0x08 - uint32 ICCIAR ; //0x0c - uint32 ICCEOIR ; //0x10 - uint32 ICCRPR ; //0x14 - uint32 ICCHPIR ; //0x18 - uint32 ICCABPR ; //0x1c - uint32 RESERVED0[55]; - uint32 ICCIIDR ; //0xfc -}GICC_REG, *pGICC_REG; - - -//SCU Registers -typedef volatile struct tagCRU_REG -{ - uint32 CRU_APLL_CON;//[3];//0:arm 1:ddr 2:codec - uint32 CRU_DPLL_CON; - uint32 CRU_CPLL_CON; - uint32 CRU_PPLL_CON; - uint32 CRU_MODE_CON; - uint32 CRU_CLKSEL0_CON; - uint32 CRU_CLKSEL1_CON; - uint32 CRU_CLKSEL2_CON; - uint32 CRU_CLKSEL3_CON; - uint32 CRU_CLKSEL4_CON; - uint32 CRU_CLKSEL5_CON; - uint32 CRU_CLKSEL6_CON; - uint32 CRU_CLKSEL7_CON; - uint32 CRU_CLKSEL8_CON; - uint32 CRU_CLKSEL9_CON; - uint32 CRU_CLKSEL10_CON; - uint32 CRU_CLKSEL11_CON; - uint32 CRU_CLKSEL12_CON; - uint32 CRU_CLKSEL13_CON; - uint32 CRU_CLKSEL14_CON; - uint32 CRU_CLKSEL15_CON; - uint32 CRU_CLKSEL16_CON; - uint32 CRU_CLKSEL17_CON; - uint32 CRU_CLKGATE0_CON; - uint32 CRU_CLKGATE1_CON; - uint32 CRU_CLKGATE2_CON; - uint32 CRU_CLKGATE3_CON; - uint32 CRU_SOFTRST0_CON; - uint32 CRU_SOFTRST1_CON; - uint32 CRU_SOFTRST2_CON; -}CRU_REG,*pCRU_REG; - -//SDMMC0 -typedef enum -{ -IOMUX_SDMMC_1BIT = 0, -IOMUX_SDMMC_4BIT, //default -IOMUX_SDMMC_8BIT, -IOMUX_SDMMC_OTHER -}eIOMUX_SDMMC; -typedef enum _IRQ_NUM -{ - INT_SGI0 , - INT_SGI1 , - INT_SGI2 , - INT_SGI3 , - INT_SGI4 , - INT_SGI5 , - INT_SGI6 , - INT_SGI7 , - INT_SGI8 , - INT_SGI9 , - INT_SGI10 , - INT_SGI11 , - INT_SGI12 , - INT_SGI13 , - INT_SGI14 , - INT_SGI15 , - INT_PPI0 , - INT_PPI1 , - INT_PPI2 , - INT_PPI3 , - INT_PPI4 , - INT_PPI5 , - INT_PPI6 , - INT_PPI7 , - INT_PPI8 , - INT_PPI9 , - INT_PPI10 , - INT_PPI11 , - INT_PPI12 , - INT_PPI13 , - INT_PPI14 , - INT_PPI15 , - - INT_DMAC0_0 , - INT_DMAC0_1 , - INT_DMAC0_2 , - INT_DMAC0_3 , - INT_DMAC2_0 , - INT_DMAC2_1 , - INT_DMAC2_2 , - INT_DMAC2_3 , - INT_DMAC2_4 , - INT_GPU , - INT_VEPU , - INT_VDPU , - INT_VIP , - INT_LCDC , - INT_IPP , - INT_EBC , - INT_USB_OTG0 , - INT_USB_OTG1 , - INT_USB_Host , - INT_MAC , - INT_HIF0 , - INT_HIF1 , - INT_HSADC_TSI , - INT_SDMMC , - INT_SDIO , - INT_eMMC , - INT_SARADC , - INT_NandC , - INT_NandCRDY , - INT_SMC , - INT_PID_FILTER , - INT_I2S_PCM_8CH , - INT_I2S_PCM_2CH , - INT_SPDIF , - INT_UART0 , - INT_UART1 , - INT_UART2 , - INT_UART3 , - INT_SPI0 , - INT_SPI1 , - INT_I2C0 , - INT_I2C1 , - INT_I2C2 , - INT_I2C3 , - INT_TIMER0 , - INT_TIMER1 , - INT_TIMER2 , - INT_TIMER3 , - INT_PWM0 , - INT_PWM1 , - INT_PWM2 , - INT_PWM3 , - INT_WDT , - INT_RTC , - INT_PMU , - INT_GPIO0 , - INT_GPIO1 , - INT_GPIO2 , - INT_GPIO3 , - INT_GPIO4 , - INT_GPIO5 , - INT_GPIO6 , - INT_USB_AHB_ARB , - INT_PERI_AHB_ARB, - INT_A8IRQ0 , - INT_A8IRQ1 , - INT_A8IRQ2 , - INT_A8IRQ3 , - INT_MAXNUM -}eINT_NUM; - -typedef enum _CRU_RST -{ -//cru_rst_con0 - CRU_RST_ARMCORE = 0, - CRU_RST_CPUSUBSYS_INT1AXI, - CRU_RST_CPUSUBSYS_INT1AHB, - CRU_RST_CPUSUBSYS_INT1APB, - CRU_RST_CPUSUBSYS_INT1ATB, - CRU_RST_CPUSUBSYS_INT2, - CRU_RST_DMA0, - CRU_RST_DMA1, - CRU_RST_GIC, - CRU_RST_INMEM, - CRU_RST_TZPC=11, - CRU_RST_ROM, - CRU_RST_I2S0, - CRU_RST_I2S1, - CRU_RST_SPDIF, - CRU_RST_UART0, - CRU_RST_RTC, - CRU_RST_DDRPHY, - CRU_RST_DDRDLL_B0, - CRU_RST_DDRDLL_B1, - CRU_RST_DDRDLL_B2, - CRU_RST_DDRDLL_B3, - CRU_RST_DDRDLL_CMD, - CRU_RST_DDR_CON, - CRU_RST_ARMCORE_DEBUG, - CRU_RST_DAP_DBG, - CRU_RST_CPU_VODEC_A2A, - CRU_RST_CPU_DISPLAY_A2A, - CRU_RST_DAP_SYS, - -// cru_softrst1_con - CRU_RST_PERIPH_INT1_AXI=32, - CRU_RST_PERIPH_INT1_AHB, - CRU_RST_PERIPH_INT1_APB, - CRU_RST_PERIPH_EMEM=36, - CRU_RST_PERIPH_USB, - CRU_RST_DMA2, - CRU_RST_MAC, - CRU_RST_HIF, - CRU_RST_NANDC, - CRU_RST_SMC, - CRU_RST_RESERVED1, - CRU_RST_LSADC, - CRU_RST_SDMMC0, - CRU_RST_SDMMC1, - CRU_RST_EMMC, - CRU_RST_USBOTG0_AHB, - CRU_RST_USBPHY0, - CRU_RST_USBOTG0_CON, - CRU_RST_USBOTG1_AHB, - CRU_RST_USBPHY1, - CRU_RST_USBOTG1_CON, - CRU_RST_UHOST, - CRU_RST_VIP, - CRU_RST_VIP_AHB, - CRU_RST_SPI0, - CRU_RST_SPI1, - CRU_RST_SARADC, - CRU_RST_UART1, - CRU_RST_UART2, - CRU_RST_UART3, - CRU_RST_PWM, - -//CRU_SOFTRST2_CON - CRU_RST_DISPLAY_AXI=64, - CRU_RST_DISPLAY_AHB, - CRU_RST_LCDC, - CRU_RST_IPP, - CRU_RST_EBOOK, - CRU_RST_RESERVED2, - CRU_RST_RESERVED3, - CRU_RST_GPU, - CRU_RST_DDR_REG, - CRU_RST_DDR_CPU, - CRU_RST_PERIPH_CPU_AXI, - CRU_RST_DDR_PERIPH, - CRU_RST_DDR_LCDC, - CRU_RST_RESERVED4, - CRU_RST_RESERVED5, - CRU_RST_DDR_VCODEC, - CRU_RST_DDR_GPU, - CRU_RST_PID_FILTER, - CRU_RST_VCODEC_AXI, - CRU_RST_VCODEC_AHB, - CRU_RST_TIMER0, - CRU_RST_TIMER1, - CRU_RST_TIMER2, - CRU_RST_TIMER3, - - CRU_RST_MAX -}eCRU_RST; - -//GRF Registers - typedef struct tagGPIO_LH - { - uint32 GPIOL; - uint32 GPIOH; - }GPIO_LH_T; - - typedef struct tagGPIO_IOMUX - { - uint32 GPIOA_IOMUX; - uint32 GPIOB_IOMUX; - uint32 GPIOC_IOMUX; - uint32 GPIOD_IOMUX; - }GPIO_IOMUX_T; - //REG FILE registers - typedef volatile struct tagGRF_REG - { - GPIO_LH_T GRF_GPIO_DIR[7]; - GPIO_LH_T GRF_GPIO_DO[7]; - GPIO_LH_T GRF_GPIO_EN[7]; - GPIO_IOMUX_T GRF_GPIO_IOMUX[7]; - GPIO_LH_T GRF_GPIO_PULL[7]; - uint32 GRF_SOC_CON[3]; - uint32 GRF_SOC_STATUS0; - uint32 GRF_DMAC1_CON[3]; - uint32 GRF_DMAC2_CON[4]; - uint32 GRF_UOC0_CON[3]; - uint32 GRF_UOC1_CON[4]; - uint32 GRF_DDRC_CON0; - uint32 GRF_DDRC_STAT; - uint32 reserved[(0x1c8-0x1a0)/4]; - uint32 GRF_OS_REG[4]; - } GRF_REG, *pGRF_REG; - -//TIMER Registers -typedef volatile struct tagTIMER_STRUCT -{ - uint32 TIMER_LOAD_COUNT; - uint32 TIMER_CURR_VALUE; - uint32 TIMER_CTRL_REG; - uint32 TIMER_EOI; - uint32 TIMER_INT_STATUS; -}TIMER_REG,*pTIMER_REG; - -typedef volatile struct tagPMU_REG -{ - uint32 PMU_WAKEUP_EN0; - uint32 PMU_WAKEUP_EN1; - uint32 PMU_WAKEUP_EN2; - uint32 reserved1; - uint32 PMU_PG_CON; - uint32 PMU_MISC_CON; - uint32 PMU_PLL_CNT; - uint32 PMU_PD_ST; - uint32 PMU_INT_ST; -}PMU_REG,*pPMU_REG; - -typedef struct tagSCU_CLK_INFO -{ - uint32 armFreq; //ARM PLL FREQ - uint32 dspFreq; //DSP PLL FREQ - uint32 AuxFreq; //AUX PLL FREQ - uint32 ahbDiv; - uint32 apbDiv; - uint32 armFreqLast; -}SCU_CLK_INFO,*pSCU_CLK_INFO; - -#define g_cruReg ((pCRU_REG)RK29_CRU_REG_BASE) - -#endif - diff --git a/drivers/mtd/rknand/nand_config.h b/drivers/mtd/rknand/nand_config.h deleted file mode 100755 index 1cb460eb6864..000000000000 --- a/drivers/mtd/rknand/nand_config.h +++ /dev/null @@ -1,77 +0,0 @@ -/******************************************************************************** -********************************************************************************* - COPYRIGHT (c) 2004 BY ROCK-CHIP FUZHOU - -- ALL RIGHTS RESERVED -- - -File Name: nand_config.h -Author: RK28XX Driver Develop Group -Created: 25th OCT 2008 -Modified: -Revision: 1.00 -******************************************************************************** -********************************************************************************/ -#ifndef _NAND_CONFIG_H -#define _NAND_CONFIG_H -#define DRIVERS_NAND -#define LINUX - -#include -#include -#include -#include -#include -#include -#include -#include -#include "typedef.h" - -#ifdef CONFIG_ARCH_RK30 -#include -#include -#endif -#ifdef CONFIG_ARCH_RK29 -#include -#include -#endif - -#include -#include "epphal.h" - -//#include "epphal.h" -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -#ifndef NULL -#define NULL (void*)0 -#endif - -#include "FTL_OSDepend.h" -#include "flash.h" -#include "ftl.h" - -#ifdef CONFIG_MTD_NAND_RK29XX_DEBUG -#undef RKNAND_DEBUG -#define DEBUG_MSG -#define RKNAND_DEBUG(format, arg...) \ - printk(KERN_NOTICE format, ## arg); -#else -#undef RKNAND_DEBUG -#define RKNAND_DEBUG(n, arg...) -#endif - -extern void rk29_power_reset(void); -extern void rkNand_cond_resched(void); - -#define COND_RESCHED() rkNand_cond_resched()//cond_resched() - -extern unsigned long rk_dma_mem_alloc(int size); -extern unsigned long rk_dma_mem_free(unsigned long buf); -#undef PRINTF -#define PRINTF RKNAND_DEBUG -#endif - diff --git a/drivers/mtd/rknand/rknand_base.h b/drivers/mtd/rknand/rknand_base.h index e74761a8a323..b7fa95ab0b84 100755 --- a/drivers/mtd/rknand/rknand_base.h +++ b/drivers/mtd/rknand/rknand_base.h @@ -70,6 +70,8 @@ struct rknand_info { int emmc_clk_power_save_en; char *pdmaBuf; void (*nand_timing_config)(unsigned long AHBnKHz); + void (*rknand_suspend)(void); + void (*rknand_resume)(void); int reserved[20]; }; diff --git a/drivers/mtd/rknand/rknand_base_ko.c b/drivers/mtd/rknand/rknand_base_ko.c index 7043d2d68734..ea49e277ea8a 100755 --- a/drivers/mtd/rknand/rknand_base_ko.c +++ b/drivers/mtd/rknand/rknand_base_ko.c @@ -23,10 +23,11 @@ //#include "api_flash.h" #include "rknand_base.h" #include +#include #define DRIVER_NAME "rk29xxnand" -const char rknand_base_version[] = "rknand_base.c version: 4.34 20120401"; +const char rknand_base_version[] = "rknand_base.c version: 4.38 20120717"; #define NAND_DEBUG_LEVEL0 0 #define NAND_DEBUG_LEVEL1 1 #define NAND_DEBUG_LEVEL2 2 @@ -67,10 +68,23 @@ static char grknand_trac_buf[MAX_TRAC_BUFFER_SIZE]; static char *ptrac_buf = grknand_trac_buf; void trac_log(long lba,int len, int mod) { + unsigned long long t; + unsigned long nanosec_rem; + t = cpu_clock(UINT_MAX); + nanosec_rem = do_div(t, 1000000000); if(mod) - ptrac_buf += sprintf(ptrac_buf,"W %d %d \n",lba,len); + ptrac_buf += sprintf(ptrac_buf,"[%5lu.%06lu] W %d %d \n",(unsigned long) t, nanosec_rem / 1000,lba,len); else - ptrac_buf += sprintf(ptrac_buf,"R %d %d \n",lba,len); + ptrac_buf += sprintf(ptrac_buf,"[%5lu.%06lu] R %d %d \n",(unsigned long) t, nanosec_rem / 1000,lba,len); +} + +void trac_logs(char *s) +{ + unsigned long long t; + unsigned long nanosec_rem; + t = cpu_clock(UINT_MAX); + nanosec_rem = do_div(t, 1000000000); + ptrac_buf += sprintf(ptrac_buf,"[%5lu.%06lu] %s\n",(unsigned long) t, nanosec_rem / 1000,s); } static int rkNand_trac_read(char *page, char **start, off_t off, int count, int *eof, @@ -80,7 +94,7 @@ static int rkNand_trac_read(char *page, char **start, off_t off, int count, int int len; len = ptrac_buf - grknand_trac_buf - off; - printk("rkNand_trac_read: page=%x,off=%x,count=%x ,len=%x \n",(int)page,(int)off,count,len); + //printk("rkNand_trac_read: page=%x,off=%x,count=%x ,len=%x \n",(int)page,(int)off,count,len); if (len < 0) len = 0; @@ -321,7 +335,7 @@ static int rknand_nand_timing_cfg(void) if(gpNandInfo->nand_timing_config) { nandc_clk_rate = newclk; - gpNandInfo->nand_timing_config( nandc_clk_rate / 1000); // KHz + //gpNandInfo->nand_timing_config( nandc_clk_rate / 1000); // KHz } } return 0; @@ -493,12 +507,16 @@ static int rknand_probe(struct platform_device *pdev) static int rknand_suspend(struct platform_device *pdev, pm_message_t state) { gpNandInfo->rknand.rknand_schedule_enable = 0; + if(gpNandInfo->rknand_suspend) + gpNandInfo->rknand_suspend(); NAND_DEBUG(NAND_DEBUG_LEVEL0,"rknand_suspend: \n"); return 0; } static int rknand_resume(struct platform_device *pdev) { + if(gpNandInfo->rknand_resume) + gpNandInfo->rknand_resume(); gpNandInfo->rknand.rknand_schedule_enable = 1; NAND_DEBUG(NAND_DEBUG_LEVEL0,"rknand_resume: \n"); return 0; diff --git a/drivers/mtd/rknand/typedef.h b/drivers/mtd/rknand/typedef.h deleted file mode 100755 index 6b7ad87ec3a6..000000000000 --- a/drivers/mtd/rknand/typedef.h +++ /dev/null @@ -1,62 +0,0 @@ - -#ifndef __TYPEDEF_H -#define __TYPEDEF_H - -typedef volatile unsigned int REG32; -typedef volatile unsigned short REG16; -typedef volatile unsigned char REG8; - -typedef int BOOLEAN; -typedef BOOLEAN BOOL; -typedef void (*pFunc)(void); //定义函数指针, 用于调用绝对地址 -typedef void (*pFunc1)(unsigned int); //定义函数指针, 用于调用绝对地址 -typedef void (*pFunc2)(unsigned int,pFunc); //定义函数指针, 用于调用绝对地址 - - -#define FALSE 0 -#define TRUE (!FALSE) -#ifndef NULL - #define NULL 0 -#endif -#define OK 0 -#define ERROR !0 - -//typedef char * va_list; - - -typedef unsigned long uint32; -typedef unsigned long UINT32; -typedef unsigned short UINT16; -typedef unsigned char UINT8; -typedef int INT32; -typedef short INT16; -typedef char INT8; - -typedef unsigned char INT8U; -typedef signed char INT8S; -typedef unsigned short INT16U; -typedef signed short INT16S; -typedef int INT32S; -typedef unsigned int INT32U; - -typedef unsigned long L32U; -typedef signed long L32S; - -typedef unsigned char BYTE; - -//typedef volatile unsigned int data_t; -//typedef volatile unsigned int* addr_t; - -//typedef void (*pFunc)(void); //定义函数指针, 用于调用绝对地址 - -typedef unsigned char uint8; -typedef signed char int8; -typedef unsigned short uint16; -typedef signed short int16; -typedef signed long int32; -typedef unsigned long long uint64; -typedef signed long long int64; -//typedef unsigned char bool; -typedef unsigned short WCHAR; - -#endif /*__TYPEDEF_H */ From 716545a07b474cb7d2bd09083ff42baebe3643f7 Mon Sep 17 00:00:00 2001 From: chenxing Date: Tue, 7 Aug 2012 15:53:32 +0800 Subject: [PATCH 097/261] rk2928:sdk: closd clock debug msg and fix pclk_hdmi, gpu, ddrc problems --- arch/arm/mach-rk2928/clock.c | 12 ++-- arch/arm/mach-rk2928/clock_data.c | 112 ++++++++++++++---------------- 2 files changed, 56 insertions(+), 68 deletions(-) diff --git a/arch/arm/mach-rk2928/clock.c b/arch/arm/mach-rk2928/clock.c index 02530f220ad0..9fe7ae46d5b1 100755 --- a/arch/arm/mach-rk2928/clock.c +++ b/arch/arm/mach-rk2928/clock.c @@ -139,11 +139,8 @@ int clk_register(struct clk *clk) clk->parent =clk_default_get_parent(clk); if (clk->parent){ - printk("clk has parent\n"); list_add(&clk->sibling, &clk->parent->children); - } - else{ - printk("clk has no parent\n"); + } else { list_add(&clk->sibling, &root_clks); } list_add(&clk->node, &clocks); @@ -209,8 +206,7 @@ int clk_enable_nolock(struct clk *clk) clk_disable_nolock(clk->parent); return ret; } - //pr_debug("%s enabled\n", clk->name); - printk("%s enabled\n", clk->name); + pr_debug("%s enabled\n", clk->name); } clk->usecount++; @@ -266,7 +262,7 @@ int clk_set_rate_nolock(struct clk *clk, unsigned long rate) if (!clk->set_rate) return -EINVAL; - printk("**will set %s rate %lu\n", clk->name, rate); + pr_debug("**will set %s rate %lu\n", clk->name, rate); old_rate = clk->rate; if (clk->notifier_count) @@ -276,7 +272,7 @@ int clk_set_rate_nolock(struct clk *clk, unsigned long rate) if (ret == 0) { __clk_recalc(clk); - printk("**set %s rate recalc=%lu\n",clk->name,clk->rate); + pr_debug("**set %s rate recalc=%lu\n",clk->name,clk->rate); __propagate_rate(clk); } diff --git a/arch/arm/mach-rk2928/clock_data.c b/arch/arm/mach-rk2928/clock_data.c index 5b72103ca044..9651a2379618 100644 --- a/arch/arm/mach-rk2928/clock_data.c +++ b/arch/arm/mach-rk2928/clock_data.c @@ -52,24 +52,17 @@ struct pll_clk_set { u32 pllcon2; //nb=bwadj+1;0:11;nb=nf/2 u32 rst_dly;//us }; -#if 1 -#define CLKDATA_DBG(fmt, args...) printk("CLOCK_DATA:\t"fmt, ## args) -#define CLKDATA_LOG(fmt, args...) printk("CLOCK_DATA:\t"fmt, ## args) +#if 0 +#define CLKDATA_DBG(fmt, args...) printk(KERN_DEBUG "CLKDATA_DBG:\t"fmt, ##args) +#define CLKDATA_LOG(fmt, args...) printk(KERN_INFO "CLKDATA_LOG:\t"fmt, ##args) #else #define CLKDATA_DBG(fmt, args...) do {} while(0) #define CLKDATA_LOG(fmt, args...) do {} while(0) #endif -#define CLKDATA_ERR(fmt, args...) pr_err(fmt, ## args) +#define CLKDATA_ERR(fmt, args...) printk(KERN_ERR "CLKDATA_ERR:\t"fmt, ##args) -//#define RK2928_TEST_MODE -#ifndef RK2928_TEST_MODE #define cru_readl(offset) readl_relaxed(RK2928_CRU_BASE + offset) #define cru_writel(v, offset) do { writel_relaxed(v, RK2928_CRU_BASE + offset); dsb(); } while (0) -#else -u32 TEST_CRU_REGS[500] = {0}; -#define cru_readl(offset) (TEST_CRU_REGS[offset / 4]) -#define cru_writel(v, offset) do { TEST_CRU_REGS[offset / 4] = v; } while (0) -#endif #define rk_clock_udelay(a) udelay(a); @@ -232,7 +225,7 @@ static unsigned long clksel_recalc_equal_parent(struct clk *clk) CLKDATA_DBG("ENTER %s clk=%s\n", __func__, clk->name); CLKDATA_DBG("%s new clock rate is %lu (equal to parent)\n", clk->name, rate); - return clk->parent->rate; + return rate; } //for Fixed divide ratio @@ -517,8 +510,8 @@ static void pll_wait_lock(int pll_idx) int delay = 24000000; while (delay > 0) { if ((cru_readl(PLL_CONS(pll_idx, 1)) & (0x1 << PLL_LOCK_SHIFT))) { - //printk("%s %08x\n", __func__, cru_readl(PLL_CONS(pll_idx, 1)) & (0x1 << PLL_LOCK_SHIFT)); - //printk("%s ! %08x\n", __func__, !(cru_readl(PLL_CONS(pll_idx, 1)) & (0x1 << PLL_LOCK_SHIFT))); + //CLKDATA_DBG("%s %08x\n", __func__, cru_readl(PLL_CONS(pll_idx, 1)) & (0x1 << PLL_LOCK_SHIFT)); + //CLKDATA_DBG("%s ! %08x\n", __func__, !(cru_readl(PLL_CONS(pll_idx, 1)) & (0x1 << PLL_LOCK_SHIFT))); break; } delay--; @@ -591,9 +584,9 @@ static int pll_clk_set_rate(struct pll_clk_set *clk_set, u8 pll_id) cru_writel(clk_set->pllcon1, PLL_CONS(pll_id,1)); cru_writel(clk_set->pllcon2, PLL_CONS(pll_id,2)); - printk("id=%d,pllcon0%08x\n", pll_id, cru_readl(PLL_CONS(pll_id,0))); - printk("id=%d,pllcon1%08x\n", pll_id, cru_readl(PLL_CONS(pll_id,1))); - printk("id=%d,pllcon2%08x\n", pll_id, cru_readl(PLL_CONS(pll_id,2))); + CLKDATA_DBG("id=%d,pllcon0%08x\n", pll_id, cru_readl(PLL_CONS(pll_id,0))); + CLKDATA_DBG("id=%d,pllcon1%08x\n", pll_id, cru_readl(PLL_CONS(pll_id,1))); + CLKDATA_DBG("id=%d,pllcon2%08x\n", pll_id, cru_readl(PLL_CONS(pll_id,2))); //rk2928_clock_udelay(5); //wating lock state @@ -699,7 +692,7 @@ static int pll_clk_get_set(unsigned long fin_hz,unsigned long fout_hz, *frac = 0; - CLKDATA_DBG("fin=%lu,fout=%lu,gcd=%lu,refdiv=%lu,fbdiv=%lu,postdiv1=%lu,postdiv2=%lu,frac=%lu\n", + CLKDATA_DBG("fin=%lu,fout=%lu,gcd=%u,refdiv=%u,fbdiv=%u,postdiv1=%u,postdiv2=%u,frac=%u\n", fin_hz, fout_hz, gcd, *refdiv, *fbdiv, *postdiv1, *postdiv2, *frac); return 0; @@ -711,17 +704,18 @@ static int pll_set_con(u8 id, u32 refdiv, u32 fbdiv, u32 postdiv1, u32 postdiv2, temp_clk_set.pllcon1 = PLL_SET_REFDIV(refdiv) | PLL_SET_POSTDIV2(postdiv2); temp_clk_set.pllcon2 = PLL_SET_FRAC(frac); temp_clk_set.rst_dly = 1500; - printk("setting....\n"); + CLKDATA_DBG("setting....\n"); return pll_clk_set_rate(&temp_clk_set, id); } static int apll_clk_set_rate(struct clk *clk, unsigned long rate) { struct _pll_data *pll_data=clk->pll; struct apll_clk_set *clk_set=(struct apll_clk_set*)pll_data->table; - struct apll_clk_set temp_clk_set; u32 fin_hz, fout_hz; u32 refdiv, fbdiv, postdiv1, postdiv2, frac; + u8 pll_id = pll_data->id; + fin_hz = clk->parent->rate; fout_hz = rate; @@ -732,16 +726,15 @@ static int apll_clk_set_rate(struct clk *clk, unsigned long rate) clk_set++; } - printk("%s %s %d\n", __func__, clk->name, rate); - printk("pllcon0 %08x\n", cru_readl(PLL_CONS(0,0))); - printk("pllcon1 %08x\n", cru_readl(PLL_CONS(0,1))); - printk("pllcon2 %08x\n", cru_readl(PLL_CONS(0,2))); - printk("pllcon3 %08x\n", cru_readl(PLL_CONS(0,3))); - printk("clksel0 %08x\n", cru_readl(CRU_CLKSELS_CON(0))); - printk("clksel1 %08x\n", cru_readl(CRU_CLKSELS_CON(1))); + CLKDATA_DBG("%s %s %lu\n", __func__, clk->name, rate); + CLKDATA_DBG("pllcon0 %08x\n", cru_readl(PLL_CONS(0,0))); + CLKDATA_DBG("pllcon1 %08x\n", cru_readl(PLL_CONS(0,1))); + CLKDATA_DBG("pllcon2 %08x\n", cru_readl(PLL_CONS(0,2))); + CLKDATA_DBG("pllcon3 %08x\n", cru_readl(PLL_CONS(0,3))); + CLKDATA_DBG("clksel0 %08x\n", cru_readl(CRU_CLKSELS_CON(0))); + CLKDATA_DBG("clksel1 %08x\n", cru_readl(CRU_CLKSELS_CON(1))); if(clk_set->rate==rate) { CLKDATA_DBG("apll get a rate\n"); - u8 pll_id = 0; //enter slowmode cru_writel(PLL_MODE_SLOW(pll_id), CRU_MODE_CON); @@ -752,12 +745,12 @@ static int apll_clk_set_rate(struct clk *clk, unsigned long rate) cru_writel(clk_set->clksel0, CRU_CLKSELS_CON(0)); cru_writel(clk_set->clksel1, CRU_CLKSELS_CON(1)); - printk("pllcon0 %08x\n", cru_readl(PLL_CONS(0,0))); - printk("pllcon1 %08x\n", cru_readl(PLL_CONS(0,1))); - printk("pllcon2 %08x\n", cru_readl(PLL_CONS(0,2))); - printk("pllcon3 %08x\n", cru_readl(PLL_CONS(0,3))); - printk("clksel0 %08x\n", cru_readl(CRU_CLKSELS_CON(0))); - printk("clksel1 %08x\n", cru_readl(CRU_CLKSELS_CON(1))); + CLKDATA_DBG("pllcon0 %08x\n", cru_readl(PLL_CONS(0,0))); + CLKDATA_DBG("pllcon1 %08x\n", cru_readl(PLL_CONS(0,1))); + CLKDATA_DBG("pllcon2 %08x\n", cru_readl(PLL_CONS(0,2))); + CLKDATA_DBG("pllcon3 %08x\n", cru_readl(PLL_CONS(0,3))); + CLKDATA_DBG("clksel0 %08x\n", cru_readl(CRU_CLKSELS_CON(0))); + CLKDATA_DBG("clksel1 %08x\n", cru_readl(CRU_CLKSELS_CON(1))); //rk2928_clock_udelay(5); //wating lock state @@ -772,14 +765,14 @@ static int apll_clk_set_rate(struct clk *clk, unsigned long rate) pll_set_con(clk->pll->id, refdiv, fbdiv, postdiv1, postdiv2, frac); } - printk("setting OK\n"); + CLKDATA_DBG("setting OK\n"); return 0; } static int dpll_clk_set_rate(struct clk *clk, unsigned long rate) { // FIXME do nothing here - printk("setting OK\n"); + CLKDATA_DBG("setting OK\n"); return 0; } @@ -788,9 +781,8 @@ static int cpll_clk_set_rate(struct clk *clk, unsigned long rate) // FIXME struct _pll_data *pll_data=clk->pll; struct pll_clk_set *clk_set=(struct pll_clk_set*)pll_data->table; - struct pll_clk_set temp_clk_set; - u32 fin_hz, fout_hz; + unsigned long fin_hz, fout_hz; u32 refdiv, fbdiv, postdiv1, postdiv2, frac; fin_hz = clk->parent->rate; fout_hz = rate; @@ -812,12 +804,12 @@ static int cpll_clk_set_rate(struct clk *clk, unsigned long rate) pr_err("cpll auto set rate error\n"); return -ENOENT; } - CLKDATA_DBG("%s get fin=%d, fout=%d, rate=%lu, refdiv=%lu, fbdiv=%lu, postdiv1=%lu, postdiv2=%d", + CLKDATA_DBG("%s get fin=%lu, fout=%lu, rate=%lu, refdiv=%u, fbdiv=%u, postdiv1=%u, postdiv2=%u", __func__, fin_hz, fout_hz, rate, refdiv, fbdiv, postdiv1, postdiv2); pll_set_con(pll_data->id, refdiv, fbdiv, postdiv1, postdiv2, frac); } - printk("setting OK\n"); + CLKDATA_DBG("setting OK\n"); return 0; } @@ -827,10 +819,10 @@ static int gpll_clk_set_rate(struct clk *clk, unsigned long rate) struct _pll_data *pll_data=clk->pll; struct pll_clk_set *clk_set=(struct pll_clk_set*)pll_data->table; - printk("******%s\n", __func__); + CLKDATA_DBG("******%s\n", __func__); while(clk_set->rate) { - printk("******%s clk_set->rate=%d\n", __func__, clk_set->rate); + CLKDATA_DBG("******%s clk_set->rate=%lu\n", __func__, clk_set->rate); if (clk_set->rate == rate) { break; } @@ -846,7 +838,7 @@ static int gpll_clk_set_rate(struct clk *clk, unsigned long rate) CLKDATA_ERR("gpll is no corresponding rate=%lu\n", rate); return -1; } - printk("******%s end\n", __func__); + CLKDATA_DBG("******%s end\n", __func__); return 0; } @@ -1750,7 +1742,7 @@ GATE_CLK(hclk_rom, hclk_cpu_pre, HCLK_ROM); /*************************pclk_cpu***********************/ //FIXME -//GATE_CLK(pclk_hdmi, pclk_cpu_pre, PCLK_HDMI); +GATE_CLK(pclk_hdmi, pclk_cpu_pre, PCLK_HDMI); GATE_CLK(pclk_ddrupctl, pclk_cpu_pre, PCLK_DDRUPCTL); GATE_CLK(pclk_grf, pclk_cpu_pre, PCLK_GRF); GATE_CLK(pclk_acodec, pclk_cpu_pre, PCLK_ACODEC); @@ -1936,7 +1928,7 @@ static struct clk_lookup clks[] = { CLK(NULL, "ddrphy", &clk_ddrphy), CLK(NULL, "ddrc", &clk_ddrc), - CLK(NULL, "core_pre", &clk_core_pre), + CLK(NULL, "cpu", &clk_core_pre), CLK(NULL, "core_periph", &clk_core_periph), CLK(NULL, "core_periph_en", &clken_core_periph), CLK(NULL, "l2c", &clk_l2c), @@ -1995,7 +1987,7 @@ static struct clk_lookup clks[] = { CLK(NULL, "otgphy0", &clk_otgphy0), CLK(NULL, "otgphy1", &clk_otgphy1), CLK(NULL, "saradc", &clk_saradc), - CLK(NULL, "gpu_pre", &clk_gpu_pre), + CLK(NULL, "gpu", &clk_gpu_pre), CLK(NULL, "uart_pll", &clk_uart_pll), CLK("rk_serial.0", "uart_div", &clk_uart0_div), @@ -2021,7 +2013,7 @@ static struct clk_lookup clks[] = { CLK_GATE_NODEV(hclk_rom), //FIXME - //CLK_GATE_NODEV(pclk_hdmi), + CLK_GATE_NODEV(pclk_hdmi), CLK_GATE_NODEV(pclk_ddrupctl), CLK_GATE_NODEV(pclk_grf), CLK_GATE_NODEV(pclk_acodec), @@ -2246,36 +2238,36 @@ static void dump_regs(struct seq_file *s) void rk30_clk_dump_regs(void) { int i=0; - printk("\nPLL(id=0 apll,id=1,dpll,id=2,cpll,id=3 cpll)\n"); - printk("\nPLLRegisters:\n"); + CLKDATA_DBG("\nPLL(id=0 apll,id=1,dpll,id=2,cpll,id=3 cpll)\n"); + CLKDATA_DBG("\nPLLRegisters:\n"); for(i=0;i Date: Tue, 7 Aug 2012 02:00:30 -0700 Subject: [PATCH 098/261] rk2928: hdmi: fixed reg wr --- drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.h b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.h index 6fd0f957a1ad..fcc6be786bd7 100644 --- a/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.h +++ b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.h @@ -237,11 +237,11 @@ enum { #define PHY_PLL_LDO_PWR 0xe7 #define v_LDO_PWR_DOWN(n) (n << 2) -#define HDMIRdReg(addr) __raw_readl(hdmi->regbase + addr) -#define HDMIWrReg(addr, val) __raw_writel((val), hdmi->regbase + addr); +#define HDMIRdReg(addr) readl_relaxed(hdmi->regbase + (addr) * 0x04) +#define HDMIWrReg(addr, val) writel_relaxed((val), hdmi->regbase + (addr) * 0x04); #define HDMIMskReg(temp, addr, msk, val) \ - temp = __raw_readl(hdmi->regbase + addr) & (0xFF - (msk)) ; \ - __raw_writel(temp | ( (val) & (msk) ), hdmi->regbase + addr); + temp = readl_relaxed(hdmi->regbase + (addr) * 0x04) & (0xFF - (msk)) ; \ + writel_relaxed(temp | ( (val) & (msk) ), hdmi->regbase + (addr) * 0x04); extern int rk2928_hdmi_initial(void); From 47bec5f329b61a6088164fecf0206cc131cf23ca Mon Sep 17 00:00:00 2001 From: zwp Date: Tue, 7 Aug 2012 18:13:44 +0800 Subject: [PATCH 099/261] phonepad: 1.add power detection using adc. 2.add Battery charging Icon displaying. --- arch/arm/configs/rk30_phonepad_defconfig | 4 ++++ 1 file changed, 4 insertions(+) mode change 100644 => 100755 arch/arm/configs/rk30_phonepad_defconfig diff --git a/arch/arm/configs/rk30_phonepad_defconfig b/arch/arm/configs/rk30_phonepad_defconfig old mode 100644 new mode 100755 index b9bf49c0d65e..b2b8959c5206 --- a/arch/arm/configs/rk30_phonepad_defconfig +++ b/arch/arm/configs/rk30_phonepad_defconfig @@ -264,6 +264,10 @@ CONFIG_SPI_FPGA_GPIO_NUM=0 CONFIG_SPI_FPGA_GPIO_IRQ_NUM=0 CONFIG_POWER_SUPPLY=y CONFIG_WM831X_BACKUP=y +CONFIG_BATTERY_RK30_ADC=y +CONFIG_BATTERY_RK30_AC_CHARGE=y +CONFIG_BATTERY_RK30_VOL3V8=y +CONFIG_POWER_ON_CHARGER_DISPLAY=y CONFIG_WM8326_VBAT_LOW_DETECTION=y # CONFIG_HWMON is not set CONFIG_MFD_TPS65910=y From bf3ef90c3468895100143380f4a68afccdf755c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Tue, 7 Aug 2012 19:36:13 +0800 Subject: [PATCH 100/261] rk2928: fix rk2928_cpu_axi_init --- arch/arm/mach-rk2928/common.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-rk2928/common.c b/arch/arm/mach-rk2928/common.c index 36b625dac57f..5585deb22ce0 100644 --- a/arch/arm/mach-rk2928/common.c +++ b/arch/arm/mach-rk2928/common.c @@ -18,21 +18,15 @@ static void __init rk2928_cpu_axi_init(void) { -#if 0 writel_relaxed(0x0, RK2928_CPU_AXI_BUS_BASE + 0x0088); // cpu0 - writel_relaxed(0x0, RK2928_CPU_AXI_BUS_BASE + 0x0108); // dmac1 writel_relaxed(0x0, RK2928_CPU_AXI_BUS_BASE + 0x0188); // cpu1r writel_relaxed(0x0, RK2928_CPU_AXI_BUS_BASE + 0x0388); // cpu1w writel_relaxed(0x0, RK2928_CPU_AXI_BUS_BASE + 0x4008); // peri writel_relaxed(0x0, RK2928_CPU_AXI_BUS_BASE + 0x5008); // gpu writel_relaxed(0x0, RK2928_CPU_AXI_BUS_BASE + 0x6008); // vpu - writel_relaxed(0xa, RK2928_CPU_AXI_BUS_BASE + 0x7008); // lcdc0 - writel_relaxed(0x0, RK2928_CPU_AXI_BUS_BASE + 0x7088); // cif0 - writel_relaxed(0x0, RK2928_CPU_AXI_BUS_BASE + 0x7108); // ipp - writel_relaxed(0xa, RK2928_CPU_AXI_BUS_BASE + 0x7188); // lcdc1 - writel_relaxed(0x0, RK2928_CPU_AXI_BUS_BASE + 0x7208); // cif1 + writel_relaxed(0xa, RK2928_CPU_AXI_BUS_BASE + 0x7188); // lcdc + writel_relaxed(0x0, RK2928_CPU_AXI_BUS_BASE + 0x7208); // cif writel_relaxed(0x0, RK2928_CPU_AXI_BUS_BASE + 0x7288); // rga -#endif writel_relaxed(0x3f, RK2928_CPU_AXI_BUS_BASE + 0x0014); // memory scheduler read latency dsb(); } From 0b843f131e34f543fa6fb6755b65a3485973e9b1 Mon Sep 17 00:00:00 2001 From: kfx Date: Tue, 7 Aug 2012 07:09:57 -0700 Subject: [PATCH 101/261] rk2928: sdmmc: f_max = 24M(normal sd) --- drivers/mmc/host/rk29_sdmmc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mmc/host/rk29_sdmmc.c b/drivers/mmc/host/rk29_sdmmc.c index 952b51c1dde1..09eb4058d038 100755 --- a/drivers/mmc/host/rk29_sdmmc.c +++ b/drivers/mmc/host/rk29_sdmmc.c @@ -3326,7 +3326,11 @@ static int rk29_sdmmc_probe(struct platform_device *pdev) #else if(RK29_CTRL_SDMMC_ID== host->pdev->id) { +#ifdef CONFIG_ARCH_RK2928 + mmc->f_max = SD_FPP_FREQ; +#else mmc->f_max = SDHC_FPP_FREQ; +#endif } else { From 7617d4a3e601feafa85fb658f59c0493d73b48f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Wed, 8 Aug 2012 09:51:32 +0800 Subject: [PATCH 102/261] rk2928: clock: fix calculation of loops_per_jiffy --- arch/arm/mach-rk2928/clock_data.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-rk2928/clock_data.c b/arch/arm/mach-rk2928/clock_data.c index 9651a2379618..b00b33bc034f 100644 --- a/arch/arm/mach-rk2928/clock_data.c +++ b/arch/arm/mach-rk2928/clock_data.c @@ -32,6 +32,7 @@ #define CLK_LOOPS_JIFFY_REF 11996091ULL #define CLK_LOOPS_RATE_REF (1200) //Mhz #define CLK_LOOPS_RECALC(new_rate) div_u64(CLK_LOOPS_JIFFY_REF*(new_rate),CLK_LOOPS_RATE_REF*MHZ) +#define LPJ_24M (CLK_LOOPS_JIFFY_REF * 24) / CLK_LOOPS_RATE_REF struct apll_clk_set { @@ -121,10 +122,12 @@ struct pll_clk_set { .clksel0 = ACLK_CPU_DIV(RATIO_##_axi_div),\ .clksel1 = PCLK_CPU_DIV(RATIO_##_apb_div) | HCLK_CPU_DIV(RATIO_##_ahb_div) \ | ACLK_CORE_DIV(RATIO_##_aclk_core_div) | CLK_CORE_PERI_DIV(RATIO_##_periph_div), \ - .lpj = 1500, \ + .lpj = (CLK_LOOPS_JIFFY_REF * _mhz) / CLK_LOOPS_RATE_REF, \ } + static const struct apll_clk_set apll_clks[] = { - _APLL_SET_CLKS(650, 6, 325, 2, 1, 1, 0, 41, 21, 81, 21, 21), + _APLL_SET_CLKS( 650, 6, 325, 2, 1, 1, 0, 41, 21, 81, 21, 21), + _APLL_SET_CLKS(1000, 3, 125, 1, 1, 1, 0, 41, 21, 41, 21, 21), }; #define _PLL_SET_CLKS(_mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac) \ @@ -709,6 +712,7 @@ static int pll_set_con(u8 id, u32 refdiv, u32 fbdiv, u32 postdiv1, u32 postdiv2, } static int apll_clk_set_rate(struct clk *clk, unsigned long rate) { + unsigned long flags; struct _pll_data *pll_data=clk->pll; struct apll_clk_set *clk_set=(struct apll_clk_set*)pll_data->table; @@ -737,13 +741,16 @@ static int apll_clk_set_rate(struct clk *clk, unsigned long rate) CLKDATA_DBG("apll get a rate\n"); //enter slowmode + local_irq_save(flags); cru_writel(PLL_MODE_SLOW(pll_id), CRU_MODE_CON); + loops_per_jiffy = LPJ_24M; cru_writel(clk_set->pllcon0, PLL_CONS(pll_id,0)); cru_writel(clk_set->pllcon1, PLL_CONS(pll_id,1)); cru_writel(clk_set->pllcon2, PLL_CONS(pll_id,2)); cru_writel(clk_set->clksel0, CRU_CLKSELS_CON(0)); cru_writel(clk_set->clksel1, CRU_CLKSELS_CON(1)); + local_irq_restore(flags); CLKDATA_DBG("pllcon0 %08x\n", cru_readl(PLL_CONS(0,0))); CLKDATA_DBG("pllcon1 %08x\n", cru_readl(PLL_CONS(0,1))); @@ -758,7 +765,10 @@ static int apll_clk_set_rate(struct clk *clk, unsigned long rate) pll_wait_lock(pll_id); //return form slow + local_irq_save(flags); cru_writel(PLL_MODE_NORM(pll_id), CRU_MODE_CON); + loops_per_jiffy = clk_set->lpj; + local_irq_restore(flags); } else { // FIXME pll_clk_get_set(clk->parent->rate, rate, &refdiv, &fbdiv, &postdiv1, &postdiv2, &frac); From 64340b93df27c256053ab01a0e5dafabd1fe1d8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Wed, 8 Aug 2012 11:25:30 +0800 Subject: [PATCH 103/261] rk2928: l2 data ram latency, write 1 cycle, read 3 cycles, setup 2 cycles --- arch/arm/mach-rk2928/common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-rk2928/common.c b/arch/arm/mach-rk2928/common.c index 5585deb22ce0..1236dca8f1e4 100644 --- a/arch/arm/mach-rk2928/common.c +++ b/arch/arm/mach-rk2928/common.c @@ -49,8 +49,8 @@ static void __init rk2928_l2_cache_init(void) writel_relaxed(L2_LY_SET(1,L2_LY_SP_OFF) |L2_LY_SET(1,L2_LY_RD_OFF) |L2_LY_SET(1,L2_LY_WR_OFF), RK2928_L2C_BASE + L2X0_TAG_LATENCY_CTRL); - writel_relaxed(L2_LY_SET(4,L2_LY_SP_OFF) - |L2_LY_SET(6,L2_LY_RD_OFF) + writel_relaxed(L2_LY_SET(2,L2_LY_SP_OFF) + |L2_LY_SET(3,L2_LY_RD_OFF) |L2_LY_SET(1,L2_LY_WR_OFF), RK2928_L2C_BASE + L2X0_DATA_LATENCY_CTRL); /* L2X0 Prefetch Control */ From 54132e31888572a99572a071bdd3d28fbf7c82db Mon Sep 17 00:00:00 2001 From: chenxing Date: Wed, 8 Aug 2012 11:53:57 +0800 Subject: [PATCH 104/261] rk2928:sdk: fix i2s frac div error --- arch/arm/mach-rk2928/clock_data.c | 40 +++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/arch/arm/mach-rk2928/clock_data.c b/arch/arm/mach-rk2928/clock_data.c index b00b33bc034f..e43d3be8bd24 100644 --- a/arch/arm/mach-rk2928/clock_data.c +++ b/arch/arm/mach-rk2928/clock_data.c @@ -1434,9 +1434,9 @@ static struct clk cif0_in = { }; /****************i2s*******************/ -#define I2S_SRC_12M (0x0) -#define I2S_SRC_DIV (0x1) -#define I2S_SRC_FRAC (0x2) +#define I2S_SRC_DIV (0x0) +#define I2S_SRC_FRAC (0x1) +#define I2S_SRC_12M (0x2) static int i2s_set_rate(struct clk *clk, unsigned long rate) { @@ -1454,8 +1454,8 @@ static int i2s_set_rate(struct clk *clk, unsigned long rate) parent =clk->parents[I2S_SRC_FRAC]; } - CLKDATA_DBG(" %s set rate=%lu parent %s(old %s)\n", - clk->name,rate,parent->name,clk->parent->name); + CLKDATA_DBG("%s %s set rate=%lu parent %s(old %s)\n", + __func__, clk->name,rate,parent->name,clk->parent->name); if(parent!=clk->parents[I2S_SRC_12M]) { @@ -1487,6 +1487,26 @@ static struct clk clk_i2s_pll = { CRU_SRC_SET(0x1,15), CRU_PARENTS_SET(clk_i2s_div_parents), }; +static int i2s_fracdiv_set_rate(struct clk *clk, unsigned long rate) +{ + u32 numerator, denominator; + //clk_i2s_div->clk_i2s_pll->gpll/cpll + //clk->parent->parent + if(frac_div_get_seting(rate,clk->parent->parent->rate, + &numerator,&denominator)==0) + { + clk_set_rate_nolock(clk->parent,clk->parent->parent->rate);//PLL:DIV 1: + cru_writel_frac(numerator << 16 | denominator, clk->clksel_con); + CLKDATA_DBG("%s set rate=%lu,is ok\n",clk->name,rate); + } + else + { + CLKDATA_DBG("clk_frac_div can't get rate=%lu,%s\n",rate,clk->name); + return -ENOENT; + } + return 0; +} + static struct clk clk_i2s_div = { .name = "i2s_div", @@ -1495,22 +1515,22 @@ static struct clk clk_i2s_div = { .gate_idx = CLK_GATE_I2S_SRC, .recalc = clksel_recalc_div, .set_rate = clksel_set_rate_freediv, - .round_rate = clksel_freediv_round_rate, + //.round_rate = clksel_freediv_round_rate, .clksel_con = CRU_CLKSELS_CON(3), CRU_DIV_SET(0x7f, 0, 64), }; static struct clk clk_i2s_frac_div = { .name = "i2s_frac_div", .parent = &clk_i2s_div, - .recalc = clksel_recalc_div, - .set_rate = clksel_set_rate_freediv, - .round_rate = clksel_freediv_round_rate, + .recalc = clksel_recalc_frac, + .set_rate = i2s_fracdiv_set_rate, + //.round_rate = clksel_freediv_round_rate, .mode = gate_mode, .gate_idx = CLK_GATE_I2S_FRAC_SRC, .clksel_con = CRU_CLKSELS_CON(7), }; -static struct clk *clk_i2s_parents[] = {&clk_12m, &clk_i2s_div, &clk_i2s_frac_div}; +static struct clk *clk_i2s_parents[] = {&clk_i2s_div, &clk_i2s_frac_div, &clk_12m}; static struct clk clk_i2s = { .name = "i2s", .parent = &clk_i2s_div, From 3403ddf5b23539e42c9cf1788b5d18f2985c0bd0 Mon Sep 17 00:00:00 2001 From: "lw@rock-chips.com" Date: Wed, 8 Aug 2012 14:59:10 +0800 Subject: [PATCH 105/261] modify sensors driver to support selecting all items one time --- drivers/input/sensors/accel/kxtik.c | 15 ++++---- drivers/input/sensors/accel/lis3dh.c | 15 ++++---- drivers/input/sensors/accel/mma8452.c | 15 ++++---- drivers/input/sensors/compass/ak8975.c | 16 ++++----- drivers/input/sensors/gyro/l3g4200d.c | 15 ++++---- drivers/input/sensors/lsensor/cm3217.c | 15 ++++---- drivers/input/sensors/lsensor/ls_al3006.c | 15 ++++---- drivers/input/sensors/lsensor/ls_stk3171.c | 15 ++++---- drivers/input/sensors/psensor/ps_al3006.c | 15 ++++---- drivers/input/sensors/psensor/ps_stk3171.c | 16 ++++----- drivers/input/sensors/sensor-dev.c | 42 ++++++++++++++++------ include/linux/sensor-dev.h | 2 ++ 12 files changed, 103 insertions(+), 93 deletions(-) diff --git a/drivers/input/sensors/accel/kxtik.c b/drivers/input/sensors/accel/kxtik.c index ba131f729536..d251f44c0a8b 100755 --- a/drivers/input/sensors/accel/kxtik.c +++ b/drivers/input/sensors/accel/kxtik.c @@ -216,7 +216,7 @@ static int sensor_report_value(struct i2c_client *client) return ret; } -struct sensor_operate gsensor_ops = { +struct sensor_operate gsensor_kxtik_ops = { .name = "kxtik", .type = SENSOR_TYPE_ACCEL, //sensor type and it should be correct .id_i2c = ACCEL_ID_KXTIK, //i2c id number @@ -237,14 +237,13 @@ struct sensor_operate gsensor_ops = { /****************operate according to sensor chip:end************/ //function name should not be changed -struct sensor_operate *gsensor_get_ops(void) +static struct sensor_operate *gsensor_get_ops(void) { - return &gsensor_ops; + return &gsensor_kxtik_ops; } -EXPORT_SYMBOL(gsensor_get_ops); -static int __init gsensor_init(void) +static int __init gsensor_kxtik_init(void) { struct sensor_operate *ops = gsensor_get_ops(); int result = 0; @@ -254,7 +253,7 @@ static int __init gsensor_init(void) return result; } -static void __exit gsensor_exit(void) +static void __exit gsensor_kxtik_exit(void) { struct sensor_operate *ops = gsensor_get_ops(); int type = ops->type; @@ -262,7 +261,7 @@ static void __exit gsensor_exit(void) } -module_init(gsensor_init); -module_exit(gsensor_exit); +module_init(gsensor_kxtik_init); +module_exit(gsensor_kxtik_exit); diff --git a/drivers/input/sensors/accel/lis3dh.c b/drivers/input/sensors/accel/lis3dh.c index ac9c059f71ad..8ce14bbe6cd6 100755 --- a/drivers/input/sensors/accel/lis3dh.c +++ b/drivers/input/sensors/accel/lis3dh.c @@ -293,7 +293,7 @@ static int sensor_report_value(struct i2c_client *client) return ret; } -struct sensor_operate gsensor_ops = { +struct sensor_operate gsensor_lis3dh_ops = { .name = "lis3dh", .type = SENSOR_TYPE_ACCEL, //sensor type and it should be correct .id_i2c = ACCEL_ID_LIS3DH, //i2c id number @@ -314,14 +314,13 @@ struct sensor_operate gsensor_ops = { /****************operate according to sensor chip:end************/ //function name should not be changed -struct sensor_operate *gsensor_get_ops(void) +static struct sensor_operate *gsensor_get_ops(void) { - return &gsensor_ops; + return &gsensor_lis3dh_ops; } -EXPORT_SYMBOL(gsensor_get_ops); -static int __init gsensor_init(void) +static int __init gsensor_lis3dh_init(void) { struct sensor_operate *ops = gsensor_get_ops(); int result = 0; @@ -331,7 +330,7 @@ static int __init gsensor_init(void) return result; } -static void __exit gsensor_exit(void) +static void __exit gsensor_lis3dh_exit(void) { struct sensor_operate *ops = gsensor_get_ops(); int type = ops->type; @@ -339,7 +338,7 @@ static void __exit gsensor_exit(void) } -module_init(gsensor_init); -module_exit(gsensor_exit); +module_init(gsensor_lis3dh_init); +module_exit(gsensor_lis3dh_exit); diff --git a/drivers/input/sensors/accel/mma8452.c b/drivers/input/sensors/accel/mma8452.c index a5e5f40f2e1a..c489c95ce54a 100755 --- a/drivers/input/sensors/accel/mma8452.c +++ b/drivers/input/sensors/accel/mma8452.c @@ -253,7 +253,7 @@ static int sensor_report_value(struct i2c_client *client) } -struct sensor_operate gsensor_ops = { +struct sensor_operate gsensor_mma8452_ops = { .name = "mma8452", .type = SENSOR_TYPE_ACCEL, //sensor type and it should be correct .id_i2c = ACCEL_ID_MMA845X, //i2c id number @@ -274,14 +274,13 @@ struct sensor_operate gsensor_ops = { /****************operate according to sensor chip:end************/ //function name should not be changed -struct sensor_operate *gsensor_get_ops(void) +static struct sensor_operate *gsensor_get_ops(void) { - return &gsensor_ops; + return &gsensor_mma8452_ops; } -EXPORT_SYMBOL(gsensor_get_ops); -static int __init gsensor_init(void) +static int __init gsensor_mma8452_init(void) { struct sensor_operate *ops = gsensor_get_ops(); int result = 0; @@ -291,7 +290,7 @@ static int __init gsensor_init(void) return result; } -static void __exit gsensor_exit(void) +static void __exit gsensor_mma8452_exit(void) { struct sensor_operate *ops = gsensor_get_ops(); int type = ops->type; @@ -299,8 +298,8 @@ static void __exit gsensor_exit(void) } -module_init(gsensor_init); -module_exit(gsensor_exit); +module_init(gsensor_mma8452_init); +module_exit(gsensor_mma8452_exit); diff --git a/drivers/input/sensors/compass/ak8975.c b/drivers/input/sensors/compass/ak8975.c index a8fbf21efe20..3319618705ae 100755 --- a/drivers/input/sensors/compass/ak8975.c +++ b/drivers/input/sensors/compass/ak8975.c @@ -693,7 +693,7 @@ static struct miscdevice compass_dev_device = .fops = &compass_dev_fops, }; -struct sensor_operate akm8975_ops = { +struct sensor_operate akm8975_akm8975_ops = { .name = "akm8975", .type = SENSOR_TYPE_COMPASS, //it is important .id_i2c = COMPASS_ID_AK8975, @@ -715,15 +715,13 @@ struct sensor_operate akm8975_ops = { /****************operate according to sensor chip:end************/ //function name should not be changed -struct sensor_operate *compass_get_ops(void) +static struct sensor_operate *compass_get_ops(void) { - return &akm8975_ops; + return &akm8975_akm8975_ops; } -EXPORT_SYMBOL(compass_get_ops); - -static int __init compass_init(void) +static int __init compass_akm8975_init(void) { struct sensor_operate *ops = compass_get_ops(); int result = 0; @@ -748,7 +746,7 @@ static int __init compass_init(void) return result; } -static void __exit compass_exit(void) +static void __exit compass_akm8975_exit(void) { struct sensor_operate *ops = compass_get_ops(); int type = ops->type; @@ -756,7 +754,7 @@ static void __exit compass_exit(void) } -module_init(compass_init); -module_exit(compass_exit); +module_init(compass_akm8975_init); +module_exit(compass_akm8975_exit); diff --git a/drivers/input/sensors/gyro/l3g4200d.c b/drivers/input/sensors/gyro/l3g4200d.c index 45acad2bb9db..03a0d264fe14 100755 --- a/drivers/input/sensors/gyro/l3g4200d.c +++ b/drivers/input/sensors/gyro/l3g4200d.c @@ -213,7 +213,7 @@ static int sensor_report_value(struct i2c_client *client) } -struct sensor_operate gyro_ops = { +struct sensor_operate gyro_l3g4200d_ops = { .name = "l3g4200d", .type = SENSOR_TYPE_GYROSCOPE,//sensor type and it should be correct .id_i2c = GYRO_ID_L3G4200D, //i2c id number @@ -234,14 +234,13 @@ struct sensor_operate gyro_ops = { /****************operate according to sensor chip:end************/ //function name should not be changed -struct sensor_operate *gyro_get_ops(void) +static struct sensor_operate *gyro_get_ops(void) { - return &gyro_ops; + return &gyro_l3g4200d_ops; } -EXPORT_SYMBOL(gyro_get_ops); -static int __init gyro_init(void) +static int __init gyro_l3g4200d_init(void) { struct sensor_operate *ops = gyro_get_ops(); int result = 0; @@ -251,7 +250,7 @@ static int __init gyro_init(void) return result; } -static void __exit gyro_exit(void) +static void __exit gyro_l3g4200d_exit(void) { struct sensor_operate *ops = gyro_get_ops(); int type = ops->type; @@ -259,7 +258,7 @@ static void __exit gyro_exit(void) } -module_init(gyro_init); -module_exit(gyro_exit); +module_init(gyro_l3g4200d_init); +module_exit(gyro_l3g4200d_exit); diff --git a/drivers/input/sensors/lsensor/cm3217.c b/drivers/input/sensors/lsensor/cm3217.c index b51f27154ebe..31f09b02d0fc 100755 --- a/drivers/input/sensors/lsensor/cm3217.c +++ b/drivers/input/sensors/lsensor/cm3217.c @@ -186,7 +186,7 @@ static int sensor_report_value(struct i2c_client *client) } -struct sensor_operate light_ops = { +struct sensor_operate light_cm3217_ops = { .name = "cm3217", .type = SENSOR_TYPE_LIGHT, //sensor type and it should be correct .id_i2c = LIGHT_ID_CM3217, //i2c id number @@ -207,14 +207,13 @@ struct sensor_operate light_ops = { /****************operate according to sensor chip:end************/ //function name should not be changed -struct sensor_operate *light_get_ops(void) +static struct sensor_operate *light_get_ops(void) { - return &light_ops; + return &light_cm3217_ops; } -EXPORT_SYMBOL(light_get_ops); -static int __init light_init(void) +static int __init light_cm3217_init(void) { struct sensor_operate *ops = light_get_ops(); int result = 0; @@ -224,7 +223,7 @@ static int __init light_init(void) return result; } -static void __exit light_exit(void) +static void __exit light_cm3217_exit(void) { struct sensor_operate *ops = light_get_ops(); int type = ops->type; @@ -232,7 +231,7 @@ static void __exit light_exit(void) } -module_init(light_init); -module_exit(light_exit); +module_init(light_cm3217_init); +module_exit(light_cm3217_exit); diff --git a/drivers/input/sensors/lsensor/ls_al3006.c b/drivers/input/sensors/lsensor/ls_al3006.c index 4b12770215c4..e9a1f52852f8 100755 --- a/drivers/input/sensors/lsensor/ls_al3006.c +++ b/drivers/input/sensors/lsensor/ls_al3006.c @@ -251,7 +251,7 @@ static int sensor_report_value(struct i2c_client *client) return result; } -struct sensor_operate light_ops = { +struct sensor_operate light_al3006_ops = { .name = "ls_al3006", .type = SENSOR_TYPE_LIGHT, //sensor type and it should be correct .id_i2c = LIGHT_ID_AL3006, //i2c id number @@ -272,14 +272,13 @@ struct sensor_operate light_ops = { /****************operate according to sensor chip:end************/ //function name should not be changed -struct sensor_operate *light_get_ops(void) +static struct sensor_operate *light_get_ops(void) { - return &light_ops; + return &light_al3006_ops; } -EXPORT_SYMBOL(light_get_ops); -static int __init light_init(void) +static int __init light_al3006_init(void) { struct sensor_operate *ops = light_get_ops(); int result = 0; @@ -289,7 +288,7 @@ static int __init light_init(void) return result; } -static void __exit light_exit(void) +static void __exit light_al3006_exit(void) { struct sensor_operate *ops = light_get_ops(); int type = ops->type; @@ -297,7 +296,7 @@ static void __exit light_exit(void) } -module_init(light_init); -module_exit(light_exit); +module_init(light_al3006_init); +module_exit(light_al3006_exit); diff --git a/drivers/input/sensors/lsensor/ls_stk3171.c b/drivers/input/sensors/lsensor/ls_stk3171.c index ef4f1fc3f048..9edd1bff906b 100755 --- a/drivers/input/sensors/lsensor/ls_stk3171.c +++ b/drivers/input/sensors/lsensor/ls_stk3171.c @@ -270,7 +270,7 @@ static int sensor_report_value(struct i2c_client *client) return result; } -struct sensor_operate light_ops = { +struct sensor_operate light_stk3171_ops = { .name = "ls_stk3171", .type = SENSOR_TYPE_LIGHT, //sensor type and it should be correct .id_i2c = LIGHT_ID_STK3171, //i2c id number @@ -291,14 +291,13 @@ struct sensor_operate light_ops = { /****************operate according to sensor chip:end************/ //function name should not be changed -struct sensor_operate *light_get_ops(void) +static struct sensor_operate *light_get_ops(void) { - return &light_ops; + return &light_stk3171_ops; } -EXPORT_SYMBOL(light_get_ops); -static int __init light_init(void) +static int __init light_stk3171_init(void) { struct sensor_operate *ops = light_get_ops(); int result = 0; @@ -308,7 +307,7 @@ static int __init light_init(void) return result; } -static void __exit light_exit(void) +static void __exit light_stk3171_exit(void) { struct sensor_operate *ops = light_get_ops(); int type = ops->type; @@ -316,7 +315,7 @@ static void __exit light_exit(void) } -module_init(light_init); -module_exit(light_exit); +module_init(light_stk3171_init); +module_exit(light_stk3171_exit); diff --git a/drivers/input/sensors/psensor/ps_al3006.c b/drivers/input/sensors/psensor/ps_al3006.c index b78e08dc8061..83be85d6572c 100755 --- a/drivers/input/sensors/psensor/ps_al3006.c +++ b/drivers/input/sensors/psensor/ps_al3006.c @@ -213,7 +213,7 @@ static int sensor_report_value(struct i2c_client *client) return result; } -struct sensor_operate proximity_ops = { +struct sensor_operate proximity_al3006_ops = { .name = "ps_al3006", .type = SENSOR_TYPE_PROXIMITY,//sensor type and it should be correct .id_i2c = PROXIMITY_ID_AL3006, //i2c id number @@ -234,14 +234,13 @@ struct sensor_operate proximity_ops = { /****************operate according to sensor chip:end************/ //function name should not be changed -struct sensor_operate *proximity_get_ops(void) +static struct sensor_operate *proximity_get_ops(void) { - return &proximity_ops; + return &proximity_al3006_ops; } -EXPORT_SYMBOL(proximity_get_ops); -static int __init proximity_init(void) +static int __init proximity_al3006_init(void) { struct sensor_operate *ops = proximity_get_ops(); int result = 0; @@ -251,7 +250,7 @@ static int __init proximity_init(void) return result; } -static void __exit proximity_exit(void) +static void __exit proximity_al3006_exit(void) { struct sensor_operate *ops = proximity_get_ops(); int type = ops->type; @@ -259,7 +258,7 @@ static void __exit proximity_exit(void) } -module_init(proximity_init); -module_exit(proximity_exit); +module_init(proximity_al3006_init); +module_exit(proximity_al3006_exit); diff --git a/drivers/input/sensors/psensor/ps_stk3171.c b/drivers/input/sensors/psensor/ps_stk3171.c index c7ce75dd7861..431b8f7a90fa 100755 --- a/drivers/input/sensors/psensor/ps_stk3171.c +++ b/drivers/input/sensors/psensor/ps_stk3171.c @@ -220,7 +220,7 @@ static int sensor_report_value(struct i2c_client *client) return result; } -struct sensor_operate proximity_ops = { +struct sensor_operate proximity_stk3171_ops = { .name = "ps_stk3171", .type = SENSOR_TYPE_PROXIMITY, //sensor type and it should be correct .id_i2c = PROXIMITY_ID_STK3171, //i2c id number @@ -241,14 +241,12 @@ struct sensor_operate proximity_ops = { /****************operate according to sensor chip:end************/ //function name should not be changed -struct sensor_operate *proximity_get_ops(void) +static struct sensor_operate *proximity_get_ops(void) { - return &proximity_ops; + return &proximity_stk3171_ops; } -EXPORT_SYMBOL(proximity_get_ops); - -static int __init proximity_init(void) +static int __init proximity_stk3171_init(void) { struct sensor_operate *ops = proximity_get_ops(); int result = 0; @@ -258,7 +256,7 @@ static int __init proximity_init(void) return result; } -static void __exit proximity_exit(void) +static void __exit proximity_stk3171_exit(void) { struct sensor_operate *ops = proximity_get_ops(); int type = ops->type; @@ -266,7 +264,7 @@ static void __exit proximity_exit(void) } -module_init(proximity_init); -module_exit(proximity_exit); +module_init(proximity_stk3171_init); +module_exit(proximity_stk3171_exit); diff --git a/drivers/input/sensors/sensor-dev.c b/drivers/input/sensors/sensor-dev.c index 2dc9b8676d52..4e7d0683ec4b 100755 --- a/drivers/input/sensors/sensor-dev.c +++ b/drivers/input/sensors/sensor-dev.c @@ -46,7 +46,7 @@ #endif struct sensor_private_data *g_sensor[SENSOR_NUM_TYPES]; -static struct sensor_operate *sensor_ops[SENSOR_NUM_TYPES]; +static struct sensor_operate *sensor_ops[SENSOR_NUM_ID]; static int sensor_get_id(struct i2c_client *client, int *value) { @@ -106,7 +106,7 @@ static int sensor_chip_init(struct i2c_client *client) { struct sensor_private_data *sensor = (struct sensor_private_data *) i2c_get_clientdata(client); - struct sensor_operate *ops = sensor_ops[sensor->type]; + struct sensor_operate *ops = sensor_ops[(int)sensor->i2c_id->driver_data]; int result = 0; if(ops) @@ -120,9 +120,9 @@ static int sensor_chip_init(struct i2c_client *client) goto error; } - if(sensor->type != ops->type) + if((sensor->type != ops->type) || ((int)sensor->i2c_id->driver_data != ops->id_i2c)) { - printk("%s:type is different:%d,%d\n",__func__,sensor->type, sensor->type); + printk("%s:type or id is different:type=%d,%d,id=%d,%d\n",__func__,sensor->type, ops->type, (int)sensor->i2c_id->driver_data, ops->id_i2c); result = -1; goto error; } @@ -137,11 +137,11 @@ static int sensor_chip_init(struct i2c_client *client) result = sensor_get_id(sensor->client, &sensor->devid);//get id if(result < 0) { - printk("%s:fail to read devid:0x%x\n",__func__,sensor->devid); + printk("%s:fail to read %s devid:0x%x\n",__func__, sensor->i2c_id->name, sensor->devid); goto error; } - printk("%s:sensor->devid=0x%x,ops=0x%p\n",__func__,sensor->devid,sensor->ops); + printk("%s:%s:devid=0x%x,ops=0x%p\n",__func__, sensor->i2c_id->name, sensor->devid,sensor->ops); result = sensor_initial(sensor->client); //init sensor if(result < 0) @@ -1027,8 +1027,14 @@ int sensor_register_slave(int type,struct i2c_client *client, struct sensor_operate *(*get_sensor_ops)(void)) { int result = 0; - sensor_ops[type] = get_sensor_ops(); - printk("%s:%s\n",__func__,sensor_ops[type]->name); + struct sensor_operate *ops = get_sensor_ops(); + if((ops->id_i2c >= SENSOR_NUM_ID) || (ops->id_i2c <= ID_INVALID)) + { + printk("%s:%s id is error %d\n", __func__, ops->name, ops->id_i2c); + return -1; + } + sensor_ops[ops->id_i2c] = ops; + printk("%s:%s,id=%d\n",__func__,sensor_ops[ops->id_i2c]->name, ops->id_i2c); return result; } @@ -1038,8 +1044,14 @@ int sensor_unregister_slave(int type,struct i2c_client *client, struct sensor_operate *(*get_sensor_ops)(void)) { int result = 0; - printk("%s:%s\n",__func__,sensor_ops[type]->name); - sensor_ops[type] = NULL; + struct sensor_operate *ops = get_sensor_ops(); + if((ops->id_i2c >= SENSOR_NUM_ID) || (ops->id_i2c <= ID_INVALID)) + { + printk("%s:%s id is error %d\n", __func__, ops->name, ops->id_i2c); + return -1; + } + printk("%s:%s,id=%d\n",__func__,sensor_ops[ops->id_i2c]->name, ops->id_i2c); + sensor_ops[ops->id_i2c] = NULL; return result; } @@ -1080,6 +1092,13 @@ int sensor_probe(struct i2c_client *client, const struct i2c_device_id *devid) result = -EFAULT; goto out_no_free; } + + if(((int)devid->driver_data >= SENSOR_NUM_ID) || ((int)devid->driver_data <= ID_INVALID)) + { + dev_err(&client->adapter->dev, "sensor id is error %d\n", (int)devid->driver_data); + result = -EFAULT; + goto out_no_free; + } i2c_set_clientdata(client, sensor); sensor->client = client; @@ -1226,7 +1245,7 @@ int sensor_probe(struct i2c_client *client, const struct i2c_device_id *devid) } #endif - printk("%s:initialized ok,sensor name:%s,type:%d\n",__func__,sensor->ops->name,type); + printk("%s:initialized ok,sensor name:%s,type:%d,id=%d\n\n",__func__,sensor->ops->name,type,(int)sensor->i2c_id->driver_data); return result; @@ -1285,6 +1304,7 @@ static const struct i2c_device_id sensor_id[] = { {"k3g", GYRO_ID_K3G}, /*light sensor*/ {"lightsensor", LIGHT_ID_ALL}, + {"light_cm3217", LIGHT_ID_CM3217}, {"light_al3006", LIGHT_ID_AL3006}, {"ls_stk3171", LIGHT_ID_STK3171}, /*proximity sensor*/ diff --git a/include/linux/sensor-dev.h b/include/linux/sensor-dev.h index c087b1bcf8b1..710ce1e36614 100755 --- a/include/linux/sensor-dev.h +++ b/include/linux/sensor-dev.h @@ -52,6 +52,7 @@ enum sensor_id { ACCEL_ID_ADXL34X, ACCEL_ID_MMA8450, ACCEL_ID_MMA845X, + ACCEL_ID_MMA7660, ACCEL_ID_MPU6050, COMPASS_ID_ALL, @@ -84,6 +85,7 @@ enum sensor_id { PRESSURE_ID_ALL, PRESSURE_ID_BMA085, + SENSOR_NUM_ID, }; From 7f9c327eea06dcb36b5d41844cf5dfb3d8e0ff1e Mon Sep 17 00:00:00 2001 From: lw Date: Wed, 8 Aug 2012 15:16:23 +0800 Subject: [PATCH 106/261] rk30sdk:select all sensor items --- arch/arm/configs/rk30_sdk_defconfig | 7 ++ arch/arm/mach-rk30/board-rk30-sdk.c | 101 +++++++++++++++++++++++++++- 2 files changed, 107 insertions(+), 1 deletion(-) diff --git a/arch/arm/configs/rk30_sdk_defconfig b/arch/arm/configs/rk30_sdk_defconfig index 8f168b32c02d..d2f2685c37d7 100644 --- a/arch/arm/configs/rk30_sdk_defconfig +++ b/arch/arm/configs/rk30_sdk_defconfig @@ -229,13 +229,20 @@ CONFIG_INPUT_KEYCHORD=y CONFIG_INPUT_UINPUT=y CONFIG_COMPASS_AK8975=y CONFIG_GS_MMA8452=y +CONFIG_GS_LIS3DH=y CONFIG_GYRO_L3G4200D=y CONFIG_LS_CM3217=y CONFIG_SENSOR_DEVICE=y CONFIG_GSENSOR_DEVICE=y +CONFIG_GS_KXTIK=y CONFIG_COMPASS_DEVICE=y CONFIG_GYROSCOPE_DEVICE=y CONFIG_LIGHT_DEVICE=y +CONFIG_LS_AL3006=y +CONFIG_LS_STK3171=y +CONFIG_PROXIMITY_DEVICE=y +CONFIG_PS_AL3006=y +CONFIG_PS_STK3171=y # CONFIG_SERIO is not set # CONFIG_CONSOLE_TRANSLATIONS is not set # CONFIG_LEGACY_PTYS is not set diff --git a/arch/arm/mach-rk30/board-rk30-sdk.c b/arch/arm/mach-rk30/board-rk30-sdk.c index 4865314c883f..78c84866a2d8 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk.c +++ b/arch/arm/mach-rk30/board-rk30-sdk.c @@ -865,6 +865,25 @@ static struct sensor_platform_data lis3dh_info = { .init_platform_hw = lis3dh_init_platform_hw, .orientation = {-1, 0, 0, 0, 0, 1, 0, -1, 0}, }; +#endif +#if defined (CONFIG_GS_KXTIK) +#define KXTIK_INT_PIN RK30_PIN4_PC0 + +static int kxtik_init_platform_hw(void) +{ + rk30_mux_api_set(GPIO4C0_SMCDATA0_TRACEDATA0_NAME, GPIO4C_GPIO4C0); + + return 0; +} + +static struct sensor_platform_data kxtik_info = { + .type = SENSOR_TYPE_ACCEL, + .irq_enable = 1, + .poll_delay_ms = 30, + .init_platform_hw = kxtik_init_platform_hw, + .orientation = {0, 1, 0, 0, 0, -1, 1, 0, 0}, +}; + #endif #if defined (CONFIG_COMPASS_AK8975) static struct sensor_platform_data akm8975_info = @@ -936,6 +955,38 @@ static struct sensor_platform_data cm3217_info = { #endif +#if defined(CONFIG_PS_AL3006) +static struct sensor_platform_data proximity_al3006_info = { + .type = SENSOR_TYPE_PROXIMITY, + .irq_enable = 1, + .poll_delay_ms = 200, +}; +#endif + +#if defined(CONFIG_PS_STK3171) +static struct sensor_platform_data proximity_stk3171_info = { + .type = SENSOR_TYPE_PROXIMITY, + .irq_enable = 1, + .poll_delay_ms = 200, +}; +#endif + + +#if defined(CONFIG_LS_AL3006) +static struct sensor_platform_data light_al3006_info = { + .type = SENSOR_TYPE_LIGHT, + .irq_enable = 1, + .poll_delay_ms = 200, +}; +#endif + +#if defined(CONFIG_LS_STK3171) +static struct sensor_platform_data light_stk3171_info = { + .type = SENSOR_TYPE_LIGHT, + .irq_enable = 1, + .poll_delay_ms = 200, +}; +#endif #ifdef CONFIG_FB_ROCKCHIP #define LCD_CS_MUX_NAME GPIO4C7_SMCDATA7_TRACEDATA7_NAME @@ -1468,6 +1519,15 @@ static struct i2c_board_info __initdata i2c0_info[] = { .platform_data = &lis3dh_info, }, #endif +#if defined (CONFIG_GS_KXTIK) + { + .type = "gs_kxtik", + .addr = 0x0F, + .flags = 0, + .irq = KXTIK_INT_PIN, + .platform_data = &kxtik_info, + }, +#endif #if defined (CONFIG_COMPASS_AK8975) { .type = "ak8975", @@ -1486,6 +1546,45 @@ static struct i2c_board_info __initdata i2c0_info[] = { .platform_data = &l3g4200d_info, }, #endif +#if defined (CONFIG_LS_AL3006) + { + .type = "light_al3006", + .addr = 0x1c, //sel = 0; if sel =1, then addr = 0x1D + .flags = 0, + .irq = RK30_PIN6_PA2, + .platform_data = &light_al3006_info, + }, +#endif +#if defined (CONFIG_LS_STK3171) + { + .type = "ls_stk3171", + .addr = 0x48, + .flags = 0, + .irq = RK30_PIN6_PA2, + .platform_data = &light_stk3171_info, + }, +#endif + + +#if defined (CONFIG_PS_AL3006) + { + .type = "proximity_al3006", + .addr = 0x1c, //sel = 0; if sel =1, then addr = 0x1D + .flags = 0, + .irq = RK30_PIN6_PA2, + .platform_data = &proximity_al3006_info, + }, +#endif + +#if defined (CONFIG_PS_STK3171) + { + .type = "ps_stk3171", + .addr = 0x48, + .flags = 0, + .irq = RK30_PIN6_PA2, + .platform_data = &proximity_stk3171_info, + }, +#endif #if defined (CONFIG_SND_SOC_RK1000) { .type = "rk1000_i2c_codec", @@ -1609,7 +1708,7 @@ static struct i2c_board_info __initdata i2c2_info[] = { #endif #if defined (CONFIG_LS_CM3217) { - .type = "lightsensor", + .type = "light_cm3217", .addr = 0x10, .flags = 0, .platform_data = &cm3217_info, From d05eca05cfb6eed8dd5ae93d58fec84b3a1b77a3 Mon Sep 17 00:00:00 2001 From: lw Date: Wed, 8 Aug 2012 15:37:33 +0800 Subject: [PATCH 107/261] rk30_phone:select all sensor items --- arch/arm/configs/rk30_phone_defconfig | 6 +- arch/arm/mach-rk30/board-rk30-phone.c | 139 +++++++++++++++++--------- 2 files changed, 95 insertions(+), 50 deletions(-) diff --git a/arch/arm/configs/rk30_phone_defconfig b/arch/arm/configs/rk30_phone_defconfig index 00b8439ef87b..dbdc703b2f36 100755 --- a/arch/arm/configs/rk30_phone_defconfig +++ b/arch/arm/configs/rk30_phone_defconfig @@ -23,9 +23,9 @@ CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_ARCH_RK30=y CONFIG_DDR_SDRAM_FREQ=300 +CONFIG_CLK_SWITCH_TO_32K=y CONFIG_WIFI_CONTROL_FUNC=y CONFIG_MACH_RK30_PHONE=y -CONFIG_CLK_SWITCH_TO_32K=y # CONFIG_SWP_EMULATE is not set CONFIG_FIQ_DEBUGGER=y CONFIG_FIQ_DEBUGGER_NO_SLEEP=y @@ -234,13 +234,17 @@ CONFIG_INPUT_TWL6030_PWRBUTTON=y CONFIG_INPUT_UINPUT=y CONFIG_COMPASS_AK8975=y CONFIG_GS_MMA8452=y +CONFIG_GS_LIS3DH=y CONFIG_GYRO_L3G4200D=y +CONFIG_LS_CM3217=y CONFIG_SENSOR_DEVICE=y CONFIG_GSENSOR_DEVICE=y +CONFIG_GS_KXTIK=y CONFIG_COMPASS_DEVICE=y CONFIG_GYROSCOPE_DEVICE=y CONFIG_LIGHT_DEVICE=y CONFIG_LS_AL3006=y +CONFIG_LS_STK3171=y # CONFIG_SERIO is not set # CONFIG_CONSOLE_TRANSLATIONS is not set # CONFIG_LEGACY_PTYS is not set diff --git a/arch/arm/mach-rk30/board-rk30-phone.c b/arch/arm/mach-rk30/board-rk30-phone.c index 6d040538c0ae..cd7016f15580 100755 --- a/arch/arm/mach-rk30/board-rk30-phone.c +++ b/arch/arm/mach-rk30/board-rk30-phone.c @@ -876,15 +876,37 @@ static int lis3dh_init_platform_hw(void) return 0; } -static struct gsensor_platform_data lis3dh_info = { - .model = lis3dh, - .swap_xy = 0, - .swap_xyz = 1, +static struct sensor_platform_data lis3dh_info = { + .type = SENSOR_TYPE_ACCEL, + .irq_enable = 1, + .poll_delay_ms = 30, .init_platform_hw = lis3dh_init_platform_hw, - .orientation = {-1, 0, 0, 0, 0, 1, 0, -1, 0}, + .orientation = {0, 1, 0, 0, 0, -1, 1, 0, 0}, }; + #endif +#if defined (CONFIG_GS_KXTIK) +#define KXTIK_INT_PIN RK30_PIN4_PC0 + +static int kxtik_init_platform_hw(void) +{ + rk30_mux_api_set(GPIO4C0_SMCDATA0_TRACEDATA0_NAME, GPIO4C_GPIO4C0); + + return 0; +} + +static struct sensor_platform_data kxtik_info = { + .type = SENSOR_TYPE_ACCEL, + .irq_enable = 1, + .poll_delay_ms = 30, + .init_platform_hw = kxtik_init_platform_hw, + .orientation = {0, 1, 0, 0, 0, -1, 1, 0, 0}, +}; + +#endif + + #if defined (CONFIG_RK_HEADSET_DET) || defined (CONFIG_RK_HEADSET_IRQ_HOOK_ADC_DET) @@ -980,63 +1002,51 @@ static struct sensor_platform_data l3g4200d_info = { #endif + #ifdef CONFIG_LS_CM3217 - -#define CM3217_POWER_PIN INVALID_GPIO -#define CM3217_IRQ_PIN INVALID_GPIO -static int cm3217_init_hw(void) -{ -#if 0 - if (gpio_request(CM3217_POWER_PIN, NULL) != 0) { - gpio_free(CM3217_POWER_PIN); - printk("%s: request cm3217 power pin error\n", __func__); - return -EIO; - } - gpio_pull_updown(CM3217_POWER_PIN, PullDisable); - - if (gpio_request(CM3217_IRQ_PIN, NULL) != 0) { - gpio_free(CM3217_IRQ_PIN); - printk("%s: request cm3217 int pin error\n", __func__); - return -EIO; - } - gpio_pull_updown(CM3217_IRQ_PIN, PullDisable); -#endif - return 0; -} - -static void cm3217_exit_hw(void) -{ -#if 0 - gpio_free(CM3217_POWER_PIN); - gpio_free(CM3217_IRQ_PIN); -#endif - return; -} - -static struct cm3217_platform_data cm3217_info = { - .irq_pin = CM3217_IRQ_PIN, - .power_pin = CM3217_POWER_PIN, - .init_platform_hw = cm3217_init_hw, - .exit_platform_hw = cm3217_exit_hw, +static struct sensor_platform_data cm3217_info = { + .type = SENSOR_TYPE_LIGHT, + .irq_enable = 0, + .poll_delay_ms = 500, }; + #endif + #if defined(CONFIG_PS_AL3006) -static struct sensor_platform_data proximity_info = { +static struct sensor_platform_data proximity_al3006_info = { .type = SENSOR_TYPE_PROXIMITY, .irq_enable = 1, .poll_delay_ms = 200, }; #endif +#if defined(CONFIG_PS_STK3171) +static struct sensor_platform_data proximity_stk3171_info = { + .type = SENSOR_TYPE_PROXIMITY, + .irq_enable = 1, + .poll_delay_ms = 200, +}; +#endif + + #if defined(CONFIG_LS_AL3006) -static struct sensor_platform_data light_info = { +static struct sensor_platform_data light_al3006_info = { .type = SENSOR_TYPE_LIGHT, .irq_enable = 1, .poll_delay_ms = 200, }; #endif +#if defined(CONFIG_LS_STK3171) +static struct sensor_platform_data light_stk3171_info = { + .type = SENSOR_TYPE_LIGHT, + .irq_enable = 1, + .poll_delay_ms = 200, +}; +#endif + + #ifdef CONFIG_FB_ROCKCHIP @@ -1685,7 +1695,7 @@ static struct i2c_board_info __initdata i2c0_info[] = { #endif #if defined (CONFIG_GS_LIS3DH) { - .type = "lis3dh", + .type = "gs_lis3dh", .addr = 0x19, .flags = 0, .irq = LIS3DH_INT_PIN, @@ -1693,6 +1703,17 @@ static struct i2c_board_info __initdata i2c0_info[] = { }, #endif +#if defined (CONFIG_GS_KXTIK) + { + .type = "gs_kxtik", + .addr = 0x0F, + .flags = 0, + .irq = KXTIK_INT_PIN, + .platform_data = &kxtik_info, + }, +#endif + + #if defined (CONFIG_COMPASS_AK8975) { .type = "ak8975", @@ -1726,9 +1747,19 @@ static struct i2c_board_info __initdata i2c0_info[] = { .addr = 0x1c, //sel = 0; if sel =1, then addr = 0x1D .flags = 0, .irq = RK30_PIN6_PA2, - .platform_data = &light_info, + .platform_data = &light_al3006_info, }, #endif +#if defined (CONFIG_LS_STK3171) + { + .type = "ls_stk3171", + .addr = 0x48, + .flags = 0, + .irq = RK30_PIN6_PA2, + .platform_data = &light_stk3171_info, + }, +#endif + #if defined (CONFIG_PS_AL3006) { @@ -1736,10 +1767,21 @@ static struct i2c_board_info __initdata i2c0_info[] = { .addr = 0x1c, //sel = 0; if sel =1, then addr = 0x1D .flags = 0, .irq = RK30_PIN6_PA2, - .platform_data = &proximity_info, + .platform_data = &proximity_al3006_info, }, #endif +#if defined (CONFIG_PS_STK3171) + { + .type = "ps_stk3171", + .addr = 0x48, + .flags = 0, + .irq = RK30_PIN6_PA2, + .platform_data = &proximity_stk3171_info, + }, +#endif + + #if defined (CONFIG_SND_SOC_RK1000) { .type = "rk1000_i2c_codec", @@ -1848,10 +1890,9 @@ static struct i2c_board_info __initdata i2c2_info[] = { #if defined (CONFIG_LS_CM3217) { - .type = "lightsensor", + .type = "light_cm3217", .addr = 0x10, .flags = 0, - .irq = CM3217_IRQ_PIN, .platform_data = &cm3217_info, }, #endif From 96ceebb48f3202b5fd8df31f628136abc2eb7def Mon Sep 17 00:00:00 2001 From: hzf Date: Wed, 8 Aug 2012 16:21:50 +0800 Subject: [PATCH 108/261] phone_pad:set headset in level is low --- arch/arm/mach-rk30/board-rk30-phonepad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-rk30/board-rk30-phonepad.c b/arch/arm/mach-rk30/board-rk30-phonepad.c index 9ef6f09f2ad1..8df5a38004ec 100755 --- a/arch/arm/mach-rk30/board-rk30-phonepad.c +++ b/arch/arm/mach-rk30/board-rk30-phonepad.c @@ -620,7 +620,7 @@ static int rk_headset_io_init(int gpio, char *iomux_name, int iomux_mode) struct rk_headset_pdata rk_headset_info = { .Headset_gpio = RK30_PIN0_PC7, - .headset_in_type = HEADSET_IN_HIGH, + .headset_in_type = HEADSET_IN_LOW, .Hook_adc_chn = 2, .hook_key_code = KEY_MEDIA, .headset_gpio_info = {GPIO0C7_TRACECTL_SMCADDR3_NAME, GPIO0C_GPIO0C7}, From 8e978b14e911de074b1bc7146acfb5bb34aa04e1 Mon Sep 17 00:00:00 2001 From: chenxing Date: Wed, 8 Aug 2012 16:45:17 +0800 Subject: [PATCH 109/261] rk2928:sdk: fix clk parents order problem --- arch/arm/mach-rk2928/clock_data.c | 44 ++++++++++++++++--------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/arch/arm/mach-rk2928/clock_data.c b/arch/arm/mach-rk2928/clock_data.c index e43d3be8bd24..651c3ef27135 100644 --- a/arch/arm/mach-rk2928/clock_data.c +++ b/arch/arm/mach-rk2928/clock_data.c @@ -913,7 +913,8 @@ static struct clk general_pll_clk = { .set_rate = gpll_clk_set_rate, .pll = &gpll_data, }; -#define SELECT_FROM_2PLLS {&general_pll_clk, &codec_pll_clk} +#define SELECT_FROM_2PLLS_GC {&general_pll_clk, &codec_pll_clk} +#define SELECT_FROM_2PLLS_CG {&codec_pll_clk, &general_pll_clk} /*********ddr******/ static int ddr_clk_set_rate(struct clk *c, unsigned long rate) { @@ -1102,8 +1103,8 @@ static struct clk pclk_cpu_pre = { CRU_DIV_SET(PCLK_CPU_DIV_MASK, PCLK_CPU_DIV_SHIFT, 8), }; /****************vcodec*******************/ -static struct clk *clk_aclk_vepu_parents[] = SELECT_FROM_2PLLS; -static struct clk *clk_aclk_vdpu_parents[] = SELECT_FROM_2PLLS; +static struct clk *clk_aclk_vepu_parents[] = SELECT_FROM_2PLLS_CG; +static struct clk *clk_aclk_vdpu_parents[] = SELECT_FROM_2PLLS_CG; static struct clk aclk_vepu = { .name = "aclk_vepu", .parent = &codec_pll_clk, @@ -1145,7 +1146,7 @@ static struct clk hclk_vdpu = { /****************vio*******************/ // name: lcdc0_aclk -static struct clk *clk_aclk_vio_pre_parents[] = SELECT_FROM_2PLLS; +static struct clk *clk_aclk_vio_pre_parents[] = SELECT_FROM_2PLLS_CG; static struct clk aclk_vio_pre = { .name = "aclk_vio_pre", .parent = &clk_cpu_div, @@ -1166,7 +1167,7 @@ static struct clk hclk_vio_pre = { }; /****************periph*******************/ -static struct clk *peri_aclk_parents[] = SELECT_FROM_2PLLS; +static struct clk *peri_aclk_parents[] = SELECT_FROM_2PLLS_GC; static struct clk peri_aclk = { .name = "peri_aclk", .parent = &general_pll_clk, @@ -1230,7 +1231,7 @@ static struct clk clk_timer0 = { .mode = gate_mode, .gate_idx = CLK_GATE_TIMER0, .recalc = clksel_recalc_equal_parent, - .clksel_con = CRU_CLKSELS_CON(10), + .clksel_con = CRU_CLKSELS_CON(2), CRU_SRC_SET(0x1, 4), CRU_PARENTS_SET(clk_timer0_parents), }; @@ -1240,7 +1241,7 @@ static struct clk clk_timer1 = { .mode = gate_mode, .gate_idx = CLK_GATE_TIMER1, .recalc = clksel_recalc_equal_parent, - .clksel_con = CRU_CLKSELS_CON(10), + .clksel_con = CRU_CLKSELS_CON(2), CRU_SRC_SET(0x1, 5), CRU_PARENTS_SET(clk_timer1_parents), }; @@ -1256,7 +1257,7 @@ static struct clk clk_spi = { CRU_DIV_SET(0x7f, 0, 128), }; /****************sdmmc*******************/ -static struct clk *clk_sdmmc0_parents[] = SELECT_FROM_2PLLS; +static struct clk *clk_sdmmc0_parents[] = SELECT_FROM_2PLLS_CG; static struct clk clk_sdmmc0 = { .name = "sdmmc0", .parent = &general_pll_clk, @@ -1288,7 +1289,7 @@ static struct clk clk_sdmmc0_drv = { }; #endif /****************sdio*******************/ -static struct clk *clk_sdio_parents[] = SELECT_FROM_2PLLS; +static struct clk *clk_sdio_parents[] = SELECT_FROM_2PLLS_CG; static struct clk clk_sdio = { .name = "sdio", .parent = &general_pll_clk, @@ -1297,6 +1298,7 @@ static struct clk clk_sdio = { .recalc = clksel_recalc_div, .set_rate = clksel_set_rate_freediv, .clksel_con = CRU_CLKSELS_CON(12), + CRU_SRC_SET(0x1, 6), CRU_DIV_SET(0x3f,0,64), CRU_PARENTS_SET(clk_sdio_parents), }; @@ -1319,7 +1321,7 @@ static struct clk clk_sdio_drv = { }; #endif /****************emmc*******************/ -static struct clk *clk_emmc_parents[] = SELECT_FROM_2PLLS; +static struct clk *clk_emmc_parents[] = SELECT_FROM_2PLLS_CG; static struct clk clk_emmc = { .name = "emmc", .parent = &general_pll_clk, @@ -1328,6 +1330,7 @@ static struct clk clk_emmc = { .recalc = clksel_recalc_div, .set_rate = clksel_set_rate_freediv, .clksel_con =CRU_CLKSELS_CON(12), + CRU_SRC_SET(0x1, 7), CRU_DIV_SET(0x3f,8,64), CRU_PARENTS_SET(clk_emmc_parents), }; @@ -1350,7 +1353,8 @@ static struct clk clk_emmc_drv = { }; #endif /****************lcdc*******************/ -static struct clk *dclk_lcdc_parents[] = {&arm_pll_clk, &general_pll_clk, &codec_pll_clk}; +// DO NOT USE ARM_PLL +static struct clk *dclk_lcdc_parents[] = {&codec_pll_clk, &general_pll_clk}; static struct clk dclk_lcdc = { .name = "dclk_lcdc", .parent = &general_pll_clk, @@ -1363,7 +1367,7 @@ static struct clk dclk_lcdc = { CRU_SRC_SET(0x3, 0), CRU_PARENTS_SET(dclk_lcdc_parents), }; -static struct clk *sclk_lcdc_parents[] = SELECT_FROM_2PLLS; +static struct clk *sclk_lcdc_parents[] = SELECT_FROM_2PLLS_CG; static struct clk sclk_lcdc = { .name = "sclk_lcdc", .parent = &general_pll_clk, @@ -1378,7 +1382,7 @@ static struct clk sclk_lcdc = { }; /****************gps*******************/ #if 0 -static struct clk hclk_gps_parents = SELECT_FROM_2PLLS; +static struct clk hclk_gps_parents = SELECT_FROM_2PLLS_CG; static struct clk hclk_gps = { .name = "hclk_gps", .parent = &general_pll_clk, @@ -1389,7 +1393,7 @@ static struct clk hclk_gps = { }; #endif /****************camera*******************/ -static struct clk *clk_cif_out_div_parents[] = SELECT_FROM_2PLLS; +static struct clk *clk_cif_out_div_parents[] = SELECT_FROM_2PLLS_CG; static struct clk clk_cif_out_div = { .name = "cif_out_div", .parent = &general_pll_clk, @@ -1402,7 +1406,7 @@ static struct clk clk_cif_out_div = { CRU_DIV_SET(0x1f, 1, 32), CRU_PARENTS_SET(clk_cif_out_div_parents), }; -static struct clk *clk_cif_out_parents[] = {&xin24m, &clk_cif_out_div}; +static struct clk *clk_cif_out_parents[] = {&clk_cif_out_div, &xin24m}; static struct clk clk_cif_out = { .name = "cif0_out", .parent = &clk_cif_out_div, @@ -1479,7 +1483,7 @@ static int i2s_set_rate(struct clk *clk, unsigned long rate) return ret; }; -static struct clk *clk_i2s_div_parents[] = SELECT_FROM_2PLLS; +static struct clk *clk_i2s_div_parents[] = SELECT_FROM_2PLLS_GC; static struct clk clk_i2s_pll = { .name = "i2s_pll", .parent = &general_pll_clk, @@ -1574,7 +1578,7 @@ static struct clk clk_saradc = { }; /****************gpu_pre*******************/ // name: gpu_aclk -static struct clk *clk_gpu_pre_parents[] = SELECT_FROM_2PLLS; +static struct clk *clk_gpu_pre_parents[] = SELECT_FROM_2PLLS_CG; static struct clk clk_gpu_pre = { .name = "gpu_pre", .parent = &general_pll_clk, @@ -1584,6 +1588,7 @@ static struct clk clk_gpu_pre = { .set_rate = clkset_rate_freediv_autosel_parents, .round_rate = clk_freediv_round_autosel_parents_rate, .clksel_con = CRU_CLKSELS_CON(34), + CRU_SRC_SET(0x1, 8), CRU_DIV_SET(0x1f, 0, 32), CRU_PARENTS_SET(clk_gpu_pre_parents), }; @@ -1661,7 +1666,7 @@ static int clk_uart_set_rate(struct clk *clk, unsigned long rate) } -static struct clk *clk_uart_pll_src_parents[] = SELECT_FROM_2PLLS; +static struct clk *clk_uart_pll_src_parents[] = SELECT_FROM_2PLLS_GC; static struct clk clk_uart_pll = { .name = "uart_pll", .parent = &general_pll_clk, @@ -1669,9 +1674,6 @@ static struct clk clk_uart_pll = { CRU_SRC_SET(0x1, 15), CRU_PARENTS_SET(clk_uart_pll_src_parents), }; -//static struct clk clk_uart0_div_parents = SELECT_FROM_2PLLS; -//static struct clk clk_uart1_div_parents = SELECT_FROM_2PLLS; -//static struct clk clk_uart2_div_parents = SELECT_FROM_2PLLS; static struct clk clk_uart0_div = { .name = "uart0_div", .parent = &clk_uart_pll, From e5d9f10ca328b63135e021e9d61bdcf15f61a83a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=99=B4?= Date: Wed, 8 Aug 2012 17:01:21 +0800 Subject: [PATCH 110/261] rk30:phonepad:support i2c transmission in sram --- arch/arm/mach-rk30/Makefile | 1 + arch/arm/mach-rk30/i2c_sram.c | 344 +++++++++++++++++++++++++++ arch/arm/mach-rk30/include/mach/io.h | 1 + arch/arm/mach-rk30/io.c | 2 + arch/arm/mach-rk30/pm.c | 15 +- arch/arm/plat-rk/Kconfig | 4 + 6 files changed, 364 insertions(+), 3 deletions(-) create mode 100755 arch/arm/mach-rk30/i2c_sram.c mode change 100644 => 100755 arch/arm/mach-rk30/include/mach/io.h mode change 100644 => 100755 arch/arm/mach-rk30/io.c mode change 100644 => 100755 arch/arm/mach-rk30/pm.c diff --git a/arch/arm/mach-rk30/Makefile b/arch/arm/mach-rk30/Makefile index 3871da30b5f3..2167eef284c7 100755 --- a/arch/arm/mach-rk30/Makefile +++ b/arch/arm/mach-rk30/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_CPU_FREQ) += cpufreq.o obj-$(CONFIG_DVFS) += dvfs.o obj-$(CONFIG_DDR_FREQ) += ddr_freq.o +obj-$(CONFIG_RK30_I2C_INSRAM) += i2c_sram.o obj-$(CONFIG_MACH_RK3066_SDK) += board-rk30-sdk.o board-rk30-sdk-key.o obj-$(CONFIG_MACH_RK30_SDK) += board-rk30-sdk.o board-rk30-sdk-key.o diff --git a/arch/arm/mach-rk30/i2c_sram.c b/arch/arm/mach-rk30/i2c_sram.c new file mode 100755 index 000000000000..03fc85e150b1 --- /dev/null +++ b/arch/arm/mach-rk30/i2c_sram.c @@ -0,0 +1,344 @@ +#include +#include +#include +#include +#include +#include +#include + +#define cru_readl(offset) readl_relaxed(RK30_CRU_BASE + offset) +#define cru_writel(v, offset) do { writel_relaxed(v, RK30_CRU_BASE + offset); dsb(); } while (0) + +#if defined(CONFIG_RK30_I2C_INSRAM) + +/******************need set when you use i2c*************************/ +#define I2C_SPEED 100 +#define I2C_SADDR (0x2D) /* slave address ,wm8310 addr is 0x34*/ +#define SRAM_I2C_CH 1 //CH==0, i2c0,CH==1, i2c1,CH==2, i2c2,CH==3, i2c3 +#define SRAM_I2C_ADDRBASE (RK30_I2C1_BASE + SZ_4K )//RK29_I2C0_BASE\RK29_I2C2_BASE\RK29_I2C3_BASE +#define I2C_SLAVE_ADDR_LEN 1 // 2:slav addr is 10bit ,1:slav addr is 7bit +#define I2C_SLAVE_REG_LEN 1 // 2:slav reg addr is 16 bit ,1:is 8 bit +#define SRAM_I2C_DATA_BYTE 1 //i2c transmission data is 1bit(8wei) or 2bit(16wei) +#define GRF_GPIO_IOMUX 0xd4 //GRF_GPIO2D_IOMUX +/*ch=0:GRF_GPIO2L_IOMUX,ch=1:GRF_GPIO1L_IOMUX,ch=2:GRF_GPIO5H_IOMUX,ch=3:GRF_GPIO2L_IOMUX*/ +#define I2C_GRF_GPIO_IOMUX (0x01<<14)|(0x01<<12) +/*CH=0:(~(0x03<<30))&(~(0x03<<28))|(0x01<<30)|(0x01<<28),CH=1:(~(0x03<<14))&(~(0x03<<12))|(0x01<<14)|(0x01<<12), +CH=2:(~(0x03<<24))&(~(0x03<<22))|(0x01<<24)|(0x01<<22),CH=3:(~(0x03<<26))&(~(0x03<<24))|(0x02<<26)|(0x02<<24)*/ +/***************************************/ + +#define I2C_SLAVE_TYPE (((I2C_SLAVE_ADDR_LEN-1)<<4)|((I2C_SLAVE_REG_LEN-1))) + +#define uint8 unsigned char +#define uint16 unsigned short +#define uint32 unsigned int +uint32 __sramdata data[5]; + +#define CRU_CLKGATE0_CON 0xd0 +#define CRU_CLKGATE8_CON 0xf0 +#define CRU_CLKSEL1_CON 0x48 +#define GRF_GPIO5H_IOMUX 0x74 +#define GRF_GPIO2L_IOMUX 0x58 +#define GRF_GPIO1L_IOMUX 0x50 + +#define COMPLETE_READ (1< Date: Wed, 8 Aug 2012 17:01:58 +0800 Subject: [PATCH 111/261] rk2928:sdk: setup arm clk 1GHz --- arch/arm/mach-rk2928/clock_data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-rk2928/clock_data.c b/arch/arm/mach-rk2928/clock_data.c index 651c3ef27135..229272289feb 100644 --- a/arch/arm/mach-rk2928/clock_data.c +++ b/arch/arm/mach-rk2928/clock_data.c @@ -2409,7 +2409,7 @@ static void __init rk2928_clock_common_init(unsigned long gpll_rate,unsigned lon { CLKDATA_DBG("ENTER %s\n", __func__); - clk_set_rate_nolock(&clk_core_pre, 650 * MHZ);//816 + clk_set_rate_nolock(&clk_core_pre, 1000 * MHZ);//816 //general clk_set_rate_nolock(&general_pll_clk, gpll_rate); //code pll From 776fea4daf61dd7631b3b5df36209ba8580dee54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Wed, 8 Aug 2012 18:20:43 +0800 Subject: [PATCH 112/261] rk2928: add reset support --- arch/arm/mach-rk2928/common.c | 13 +++---------- arch/arm/mach-rk2928/reset.c | 25 +++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-rk2928/common.c b/arch/arm/mach-rk2928/common.c index 1236dca8f1e4..54a3c8da29d8 100644 --- a/arch/arm/mach-rk2928/common.c +++ b/arch/arm/mach-rk2928/common.c @@ -11,7 +11,7 @@ #include #include #include -//#include +#include #include //#include //#include @@ -86,18 +86,11 @@ static void __init rk2928_l2_cache_init(void) static int boot_mode; static void __init rk2928_boot_mode_init(void) { -#if 0 - u32 boot_flag = readl_relaxed(RK2928_PMU_BASE + PMU_SYS_REG0); - boot_mode = readl_relaxed(RK2928_PMU_BASE + PMU_SYS_REG1); + u32 boot_flag = 0; + boot_mode = readl_relaxed(RK2928_GRF_BASE + GRF_OS_REG1); - if (boot_flag == (SYS_KERNRL_REBOOT_FLAG | BOOT_RECOVER)) { - boot_mode = BOOT_MODE_RECOVERY; - } else if (strstr(boot_command_line, "(parameter)")) { - boot_mode = BOOT_MODE_RECOVERY; - } if (boot_mode || boot_flag) printk("Boot mode: %d flag: 0x%08x\n", boot_mode, boot_flag); -#endif } int board_boot_mode(void) diff --git a/arch/arm/mach-rk2928/reset.c b/arch/arm/mach-rk2928/reset.c index 24b088e9a1c2..5a0fb4cd00ed 100644 --- a/arch/arm/mach-rk2928/reset.c +++ b/arch/arm/mach-rk2928/reset.c @@ -1,11 +1,32 @@ #include #include -#include #include +#include +#include +#include +#include static void rk2928_arch_reset(char mode, const char *cmd) { - while (1); + u32 boot_flag = 0; + u32 boot_mode = BOOT_MODE_REBOOT; + + if (cmd) { + if (!strcmp(cmd, "charge")) + boot_mode = BOOT_MODE_CHARGE; + } else { + if (system_state != SYSTEM_RESTART) + boot_mode = BOOT_MODE_PANIC; + } + writel_relaxed(0xffff0000 | boot_mode, RK2928_GRF_BASE + GRF_OS_REG1); // for linux + dsb(); + /* disable remap */ + writel_relaxed(1 << (12 + 16), RK2928_GRF_BASE + GRF_SOC_CON0); + /* pll enter slow mode */ + writel_relaxed(PLL_MODE_SLOW(APLL_ID) | PLL_MODE_SLOW(CPLL_ID) | PLL_MODE_SLOW(GPLL_ID), RK2928_CRU_BASE + CRU_MODE_CON); + dsb(); + writel_relaxed(0xeca8, RK2928_CRU_BASE + CRU_GLB_SRST_SND); + dsb(); } void (*arch_reset)(char, const char *) = rk2928_arch_reset; From 63a3712679d7b1f46aab1d8b028bb524cd476436 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Wed, 8 Aug 2012 19:58:09 +0800 Subject: [PATCH 113/261] rk: sram: remove gap between code and data --- arch/arm/kernel/vmlinux.lds.S | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index 29aef560359f..1a76c2ef2188 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -271,12 +271,6 @@ SECTIONS __sram_code_start = .; } - /* - * Link these to the ITCM RAM - * Put VMA to the TCM address and LMA to the common RAM - * and we'll upload the contents from RAM to TCM and free - * the used RAM after that. - */ .text_sram_code SRAM_CODE_OFFSET : AT(__sram_code_start) { __ssram_code_text = .; @@ -288,7 +282,7 @@ SECTIONS /* * Reset the dot pointer, this is needed to create the - * relative __dtcm_start below (to be used as extern in code). + * relative __sram_data_start below (to be used as extern in code). */ . = ADDR(.sram_start) + SIZEOF(.sram_start) + SIZEOF(.text_sram_code); @@ -297,7 +291,7 @@ SECTIONS } /* TODO: add remainder of ITCM as well, that can be used for data! */ - .data_sram SRAM_DATA_OFFSET : AT(__sram_data_start) + .data_sram SRAM_CODE_OFFSET + SIZEOF(.text_sram_code) : AT(__sram_data_start) { . = ALIGN(4); __ssram_data = .; @@ -311,9 +305,10 @@ SECTIONS /* End marker for freeing TCM copy in linked object */ .sram_end : AT(ADDR(.sram_data_start) + SIZEOF(.data_sram)){ - . = ALIGN(PAGE_SIZE); __sram_end = .; } + + . = ALIGN(PAGE_SIZE); #endif NOTES From 1a943c63b596b6509b52a00573b5beaffe5bba9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Wed, 8 Aug 2012 20:02:22 +0800 Subject: [PATCH 114/261] rk: sram: build sram.c use Thumb instruction set --- arch/arm/plat-rk/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/plat-rk/Makefile b/arch/arm/plat-rk/Makefile index bc9832edc8e0..acd4bff21f16 100644 --- a/arch/arm/plat-rk/Makefile +++ b/arch/arm/plat-rk/Makefile @@ -7,4 +7,5 @@ obj-$(CONFIG_FIQ_DEBUGGER) += rk_fiq_debugger.o obj-$(CONFIG_RK_EARLY_PRINTK) += early_printk.o ../kernel/debug.o obj-y += mem_reserve.o obj-y += sram.o +CFLAGS_sram.o += -Os -mthumb obj-$(CONFIG_DDR_TEST) += memtester.o From 1b01d0add7fbe4bf6178566d11950ba96a801295 Mon Sep 17 00:00:00 2001 From: yxj Date: Wed, 8 Aug 2012 20:02:16 +0800 Subject: [PATCH 115/261] lcd screen hsd100pxn: invert dclk --- drivers/video/display/screen/lcd_hsd100pxn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/display/screen/lcd_hsd100pxn.c b/drivers/video/display/screen/lcd_hsd100pxn.c index b840a51382e8..b0215a213953 100755 --- a/drivers/video/display/screen/lcd_hsd100pxn.c +++ b/drivers/video/display/screen/lcd_hsd100pxn.c @@ -28,7 +28,7 @@ #define LCD_WIDTH 202 #define LCD_HEIGHT 152 /* Other */ -#define DCLK_POL 0 +#define DCLK_POL 1 #define SWAP_RB 0 void set_lcd_info(struct rk29fb_screen *screen, struct rk29lcd_info *lcd_info ) From 2870dd639e6ce7129d5cab478e1a5ac6f15af732 Mon Sep 17 00:00:00 2001 From: zsq Date: Wed, 8 Aug 2012 21:06:16 +0800 Subject: [PATCH 116/261] add soft reset for rga alpha mode can't use current --- drivers/video/rockchip/rga/rga_drv.c | 28 ++++++++++------- drivers/video/rockchip/rga/rga_reg_info.c | 38 ++++++++++++++++++++++- 2 files changed, 54 insertions(+), 12 deletions(-) diff --git a/drivers/video/rockchip/rga/rga_drv.c b/drivers/video/rockchip/rga/rga_drv.c index 65f17f4e412e..06fdf674639e 100755 --- a/drivers/video/rockchip/rga/rga_drv.c +++ b/drivers/video/rockchip/rga/rga_drv.c @@ -136,7 +136,7 @@ static inline u32 rga_read(u32 r) return __raw_readl(drvdata->rga_base + r); } -#if defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) +#if 1//defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) static void rga_soft_reset(void) { u32 i; @@ -590,6 +590,8 @@ static void rga_try_set_reg(void) #elif defined(CONFIG_ARCH_RK31) rga_soft_reset(); #endif + + rga_soft_reset(); rga_write(0, RGA_MMU_CTRL); @@ -652,6 +654,10 @@ static void print_info(struct rga_req *req) printk("clip.xmin = %d, clip.xmax = %d. clip.ymin = %d, clip.ymax = %d\n", req->clip.xmin, req->clip.xmax, req->clip.ymin, req->clip.ymax); + + printk("alpha_rop_flag = %.8x\n", req->alpha_rop_flag); + printk("alpha_rop_mode = %.8x\n", req->alpha_rop_mode); + printk("PD_mode = %.8x\n", req->PD_mode); } #endif @@ -778,7 +784,7 @@ static int rga_blit(rga_session *session, struct rga_req *req) sah = req->src.act_h; daw = req->dst.act_w; dah = req->dst.act_h; - + do { if((req->render_mode == bitblt_mode) && (((saw>>1) >= daw) || ((sah>>1) >= dah))) @@ -1055,7 +1061,7 @@ static irqreturn_t rga_irq_thread(int irq, void *dev_id) rga_del_running_list(); rga_try_set_reg(); } - printk("****** rga irq prc avil ******\n"); + //printk("****** rga irq prc avil ******\n"); mutex_unlock(&rga_service.lock); return IRQ_HANDLED; @@ -1252,7 +1258,7 @@ static int __init rga_init(void) return ret; } - // rga_test_0(); + //rga_test_0(); INFO("Module initialized.\n"); @@ -1291,8 +1297,8 @@ EXPORT_SYMBOL(rk_direct_fb_show); #endif -unsigned int src_buf[1920*1080]; -unsigned int dst_buf[1920*1080]; +unsigned int src_buf[320*240]; +unsigned int dst_buf[1024*768]; void rga_test_0(void) { @@ -1319,7 +1325,7 @@ void rga_test_0(void) src = src_buf; dst = dst_buf; - memset(src_buf, 0xff, 1920*1080*4); + memset(src_buf, 0xff, 320*240*4); dmac_flush_range(&src_buf[0], &src_buf[1920*1080]); outer_flush_range(virt_to_phys(&src_buf[0]),virt_to_phys(&src_buf[1024*1024])); @@ -1345,8 +1351,8 @@ void rga_test_0(void) req.dst.act_w = 320; req.dst.act_h = 240; - req.dst.vir_w = 800; - req.dst.vir_h = 480; + req.dst.vir_w = 1024; + req.dst.vir_h = 768; req.dst.x_offset = 0; req.dst.y_offset = 0; req.dst.yrgb_addr = (uint32_t)virt_to_phys(dst); @@ -1354,9 +1360,9 @@ void rga_test_0(void) //req.dst.format = RK_FORMAT_RGB_565; req.clip.xmin = 0; - req.clip.xmax = 799; + req.clip.xmax = 1023; req.clip.ymin = 0; - req.clip.ymax = 479; + req.clip.ymax = 767; //req.render_mode = color_fill_mode; //req.fg_color = 0x80ffffff; diff --git a/drivers/video/rockchip/rga/rga_reg_info.c b/drivers/video/rockchip/rga/rga_reg_info.c index f45e710ae526..055827e55752 100755 --- a/drivers/video/rockchip/rga/rga_reg_info.c +++ b/drivers/video/rockchip/rga/rga_reg_info.c @@ -1,6 +1,36 @@ //#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "rga_reg_info.h" #include "rga_rop.h" #include "rga.h" @@ -704,7 +734,11 @@ s32 RGA_set_dst(u8 *base, const struct rga_req *msg) rop_mask_stride = (((msg->src.vir_w + 7)>>3) + 3) & (~3);//not dst_vir.w,hxx,2011.7.21 reg = (stride >> 2) & 0xffff; - reg = reg | ((rop_mask_stride>>2) << 16); + reg = reg | ((rop_mask_stride>>2) << 16); + + #if defined(CONFIG_ARCH_RK2928) + reg = reg | ((msg->alpha_rop_mode & 3) << 28); + #endif if (msg->render_mode == line_point_drawing_mode) { @@ -1057,6 +1091,8 @@ RGA_set_bitblt_reg_info(u8 *base, const struct rga_req * msg, TILE_INFO *tile) stride = (msg->dst.vir_w * pixel_width + 3) & (~3); *bRGA_DST_MST = (u32)msg->dst.yrgb_addr + (tile->dst_ctrl.y_off * stride) + (tile->dst_ctrl.x_off * pixel_width); *bRGA_DST_CTR_INFO = (tile->dst_ctrl.w) | ((tile->dst_ctrl.h) << 16); + + *bRGA_DST_CTR_INFO |= (1<<29); } From cd8286834147da92be4ded7a746a6f8e79fc9ce1 Mon Sep 17 00:00:00 2001 From: yxj Date: Wed, 8 Aug 2012 22:19:05 +0800 Subject: [PATCH 117/261] rkfb : layer and fb map soc independently ,add sys node for fb and layer remap --- drivers/video/rockchip/rk_fb.c | 34 ++++++------------ drivers/video/rockchip/rkfb_sysfs.c | 56 +++++++++++++++++++++++++++-- include/linux/rk_fb.h | 18 ++++++++++ 3 files changed, 81 insertions(+), 27 deletions(-) diff --git a/drivers/video/rockchip/rk_fb.c b/drivers/video/rockchip/rk_fb.c index a07940b493a2..2711cdcde8fc 100644 --- a/drivers/video/rockchip/rk_fb.c +++ b/drivers/video/rockchip/rk_fb.c @@ -62,25 +62,7 @@ defautl:we alloc three buffer,one for fb0 and fb2 display ui,one for ipp rotate pass the phy addr to fix.smem_start by ioctl ****************************************************************************/ -int get_fb_layer_id(struct fb_fix_screeninfo *fix) -{ - int layer_id; - if(!strcmp(fix->id,"fb1")||!strcmp(fix->id,"fb3")) - { - layer_id = 0; - } - else if(!strcmp(fix->id,"fb0")||!strcmp(fix->id,"fb2")) - { - layer_id = 1; - } - else - { - printk(KERN_ERR "unsupported %s",fix->id); - layer_id = -ENODEV; - } - return layer_id; -} /********************************************************************** this is for hdmi @@ -103,7 +85,7 @@ static int rk_fb_open(struct fb_info *info,int user) struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )info->par; int layer_id; - layer_id = get_fb_layer_id(&info->fix); + layer_id = dev_drv->fb_get_layer(dev_drv,info->fix.id); if(dev_drv->layer_par[layer_id]->state) { return 0; // if this layer aready opened ,no need to reopen @@ -178,7 +160,7 @@ static int rk_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) u32 xvir = var->xres_virtual; u8 data_format = var->nonstd&0xff; - layer_id = get_fb_layer_id(fix); + layer_id = dev_drv->fb_get_layer(dev_drv,info->fix.id); if(layer_id < 0) { return -ENODEV; @@ -246,7 +228,7 @@ static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd,unsigned long arg) struct fb_fix_screeninfo *fix = &info->fix; struct rk_lcdc_device_driver *dev_drv = (struct rk_lcdc_device_driver * )info->par; u32 yuv_phy[2]; - int layer_id = get_fb_layer_id(&info->fix); + int layer_id = dev_drv->fb_get_layer(dev_drv,info->fix.id); int enable; // enable fb:1 enable;0 disable int ovl; //overlay:0 win1 on the top of win0;1,win0 on the top of win1 int num_buf; //buffer_number @@ -315,7 +297,7 @@ static int rk_fb_blank(int blank_mode, struct fb_info *info) struct fb_fix_screeninfo *fix = &info->fix; int layer_id; - layer_id = get_fb_layer_id(fix); + layer_id = dev_drv->fb_get_layer(dev_drv,info->fix.id); if(layer_id < 0) { return -ENODEV; @@ -388,7 +370,7 @@ static int rk_fb_set_par(struct fb_info *info) } #endif #endif - layer_id = get_fb_layer_id(fix); + layer_id = dev_drv->fb_get_layer(dev_drv,info->fix.id); if(layer_id < 0) { return -ENODEV; @@ -642,7 +624,7 @@ int rk_fb_switch_screen(rk_screen *screen ,int enable ,int lcdc_id) info = inf->fb[2]; } - layer_id = get_fb_layer_id(&info->fix); + layer_id = dev_drv->fb_get_layer(dev_drv,info->fix.id); if(!enable) { if(dev_drv->layer_par[layer_id]->state) @@ -874,9 +856,13 @@ static int init_lcdc_device_driver(struct rk_lcdc_device_driver *dev_drv, dev_drv->get_disp_info = def_drv->get_disp_info; dev_drv->ovl_mgr = def_drv->ovl_mgr; dev_drv->fps_mgr = def_drv->fps_mgr; + dev_drv->fb_get_layer = def_drv->fb_get_layer; + dev_drv->fb_layer_remap = def_drv->fb_layer_remap; init_layer_par(dev_drv); init_completion(&dev_drv->frame_done); spin_lock_init(&dev_drv->cpl_lock); + mutex_init(&dev_drv->fb_win_id_mutex); + dev_drv->fb_layer_remap(dev_drv,FB_DEFAULT_ORDER); //102 dev_drv->first_frame = 1; return 0; diff --git a/drivers/video/rockchip/rkfb_sysfs.c b/drivers/video/rockchip/rkfb_sysfs.c index 46bd7720a47b..92309a3ef7e7 100644 --- a/drivers/video/rockchip/rkfb_sysfs.c +++ b/drivers/video/rockchip/rkfb_sysfs.c @@ -56,7 +56,7 @@ static ssize_t show_disp_info(struct device *dev, struct fb_info *fbi = dev_get_drvdata(dev); struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )fbi->par; - int layer_id = get_fb_layer_id(&fbi->fix); + int layer_id = dev_drv->fb_get_layer(dev_drv,fbi->fix.id); if(dev_drv->get_disp_info) dev_drv->get_disp_info(dev_drv,layer_id); @@ -86,7 +86,7 @@ static ssize_t show_fb_state(struct device *dev, struct fb_info *fbi = dev_get_drvdata(dev); struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )fbi->par; - int layer_id = get_fb_layer_id(&fbi->fix); + int layer_id = dev_drv->fb_get_layer(dev_drv,fbi->fix.id); int state = dev_drv->get_layer_state(dev_drv,layer_id); return snprintf(buf, PAGE_SIZE, "%s\n",state?"enabled":"disabled"); @@ -97,7 +97,7 @@ static ssize_t set_fb_state(struct device *dev,struct device_attribute *attr, struct fb_info *fbi = dev_get_drvdata(dev); struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )fbi->par; - int layer_id = get_fb_layer_id(&fbi->fix); + int layer_id = dev_drv->fb_get_layer(dev_drv,fbi->fix.id); int state; int ret; ret = kstrtoint(buf, 0, &state); @@ -188,6 +188,55 @@ static ssize_t set_fps(struct device *dev,struct device_attribute *attr, return count; } +static ssize_t show_fb_win_map(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + struct fb_info *fbi = dev_get_drvdata(dev); + struct rk_lcdc_device_driver * dev_drv = + (struct rk_lcdc_device_driver * )fbi->par; + + mutex_lock(&dev_drv->fb_win_id_mutex); + ret = snprintf(buf, PAGE_SIZE,"fb0:win%d\nfb1:win%d\nfb2:win%d\n",dev_drv->fb0_win_id,dev_drv->fb1_win_id, + dev_drv->fb2_win_id); + mutex_unlock(&dev_drv->fb_win_id_mutex); + + return ret; + +} + +static ssize_t set_fb_win_map(struct device *dev,struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fbi = dev_get_drvdata(dev); + struct rk_lcdc_device_driver * dev_drv = + (struct rk_lcdc_device_driver * )fbi->par; + int order; + int ret; + ret = kstrtoint(buf, 0, &order); + if((order != FB0_WIN2_FB1_WIN1_FB2_WIN0) && (order != FB0_WIN1_FB1_WIN2_FB2_WIN0 ) && + (order != FB0_WIN2_FB1_WIN0_FB2_WIN1) && (order != FB0_WIN0_FB1_WIN2_FB2_WIN1 ) && + (order != FB0_WIN0_FB1_WIN1_FB2_WIN2) && (order != FB0_WIN1_FB1_WIN0_FB2_WIN2 )) + { + printk(KERN_ERR "un support map\nyou can use the following order: \ + \n201:\nfb0-win1\nfb1-win0\nfb2-win2\n \ + \n210:\nfb0-win0\nfb1-win1\nfb2-win2\n \ + \n120:\nfb0-win0\nfb1-win2\nfb2-win1\n \ + \n102:\nfb0-win2\nfb1-win0\nfb2-win1\n \ + \n021:\nfb0-win1\nfb1-win2\nfb2-win0\n \ + \n012:\nfb0-win2\nfb1-win1\nfb2-win0\n"); + return count; + } + else + { + dev_drv->fb_layer_remap(dev_drv,order); + } + + return count; + + +} + static struct device_attribute rkfb_attrs[] = { __ATTR(phys_addr, S_IRUGO, show_phys, NULL), __ATTR(virt_addr, S_IRUGO, show_virt, NULL), @@ -196,6 +245,7 @@ static struct device_attribute rkfb_attrs[] = { __ATTR(enable, S_IRUGO | S_IWUSR, show_fb_state, set_fb_state), __ATTR(overlay, S_IRUGO | S_IWUSR, show_overlay, set_overlay), __ATTR(fps, S_IRUGO | S_IWUSR, show_fps, set_fps), + __ATTR(map, S_IRUGO | S_IWUSR, show_fb_win_map, set_fb_win_map), }; int rkfb_create_sysfs(struct fb_info *fbi) diff --git a/include/linux/rk_fb.h b/include/linux/rk_fb.h index 1b8663626f45..9c1aa1518bbd 100644 --- a/include/linux/rk_fb.h +++ b/include/linux/rk_fb.h @@ -142,6 +142,16 @@ enum data_format{ YUV444, }; +enum fb_win_map_order{ + FB_DEFAULT_ORDER = 0, + FB0_WIN2_FB1_WIN1_FB2_WIN0 = 012, + FB0_WIN1_FB1_WIN2_FB2_WIN0 = 021, + FB0_WIN2_FB1_WIN0_FB2_WIN1 = 102, + FB0_WIN0_FB1_WIN2_FB2_WIN1 = 120, + FB0_WIN0_FB1_WIN1_FB2_WIN2 = 210, + FB0_WIN1_FB1_WIN0_FB2_WIN2 = 201, +}; + struct rk_fb_rgb { struct fb_bitfield red; struct fb_bitfield green; @@ -196,6 +206,12 @@ struct rk_lcdc_device_driver{ rk_screen *screen; u32 pixclock; + + char fb0_win_id; + char fb1_win_id; + char fb2_win_id; + struct mutex fb_win_id_mutex; + struct completion frame_done; //sync for pan_display,whe we set a new frame address to lcdc register,we must make sure the frame begain to display spinlock_t cpl_lock; //lock for completion frame done int first_frame ; @@ -214,6 +230,8 @@ struct rk_lcdc_device_driver{ int (*get_layer_state)(struct rk_lcdc_device_driver *dev_drv,int layer_id); int (*ovl_mgr)(struct rk_lcdc_device_driver *dev_drv,int swap,bool set); //overlay manager int (*fps_mgr)(struct rk_lcdc_device_driver *dev_drv,int fps,bool set); + int (*fb_get_layer)(struct rk_lcdc_device_driver *dev_drv,const char *id); //find layer for fb + int (*fb_layer_remap)(struct rk_lcdc_device_driver *dev_drv,enum fb_win_map_order order); }; From 4ec1ebc0916777af2223d552688bad987d62dd84 Mon Sep 17 00:00:00 2001 From: yxj Date: Wed, 8 Aug 2012 22:19:58 +0800 Subject: [PATCH 118/261] rk2928 lcdc:support fb and layer remap interface --- drivers/video/rockchip/chips/rk2928_lcdc.c | 49 ++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/drivers/video/rockchip/chips/rk2928_lcdc.c b/drivers/video/rockchip/chips/rk2928_lcdc.c index 71146072f545..df7b28ee423d 100755 --- a/drivers/video/rockchip/chips/rk2928_lcdc.c +++ b/drivers/video/rockchip/chips/rk2928_lcdc.c @@ -685,6 +685,53 @@ static int rk2928_lcdc_fps_mgr(struct rk_lcdc_device_driver *dev_drv,int fps,boo screen->ft = 1000/fps ; //one frame time in ms return fps; } + + +static int rk2928_fb_layer_remap(struct rk_lcdc_device_driver *dev_drv, + enum fb_win_map_order order) +{ + mutex_lock(&dev_drv->fb_win_id_mutex); + if(order == FB_DEFAULT_ORDER) + { + order = FB0_WIN0_FB1_WIN1_FB2_WIN2; + } + dev_drv->fb2_win_id = order/100; + dev_drv->fb1_win_id = (order/10)%10; + dev_drv->fb0_win_id = order%10; + mutex_unlock(&dev_drv->fb_win_id_mutex); + + printk("fb0:win%d\nfb1:win%d\nfb2:win%d\n",dev_drv->fb0_win_id,dev_drv->fb1_win_id, + dev_drv->fb2_win_id); + + return 0; +} + +static int rk2928_fb_get_layer(struct rk_lcdc_device_driver *dev_drv,const char *id) +{ + int layer_id = 0; + mutex_lock(&dev_drv->fb_win_id_mutex); + if(!strcmp(id,"fb0")) + { + layer_id = dev_drv->fb0_win_id; + } + else if(!strcmp(id,"fb1")) + { + layer_id = dev_drv->fb1_win_id; + } + else if(!strcmp(id,"fb2")) + { + layer_id = dev_drv->fb2_win_id; + } + else + { + printk(KERN_ERR "%s>>un supported %s\n",__func__,id); + layer_id = -1; + } + mutex_unlock(&dev_drv->fb_win_id_mutex); + + return layer_id; +} + int rk2928_lcdc_early_suspend(struct rk_lcdc_device_driver *dev_drv) { struct rk2928_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk2928_lcdc_device,driver); @@ -792,6 +839,8 @@ static struct rk_lcdc_device_driver lcdc_driver = { .ovl_mgr = rk2928_lcdc_ovl_mgr, .get_disp_info = rk2928_lcdc_get_disp_info, .fps_mgr = rk2928_lcdc_fps_mgr, + .fb_get_layer = rk2928_fb_get_layer, + .fb_layer_remap = rk2928_fb_layer_remap, }; #ifdef CONFIG_PM static int rk2928_lcdc_suspend(struct platform_device *pdev, pm_message_t state) From f9bde47dcf6c0e49dbe43daf33e293e5ab1155a6 Mon Sep 17 00:00:00 2001 From: hxy Date: Thu, 9 Aug 2012 10:01:50 +0800 Subject: [PATCH 119/261] update iomux for rk31 --- arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c | 99 +++- arch/arm/mach-rk30/board-rk31-fpga.c | 32 +- arch/arm/mach-rk30/include/mach/iomux.h | 627 +++++++++++++++++++--- arch/arm/mach-rk30/iomux.c | 148 ++++- drivers/media/video/rk30_camera.c | 2 + drivers/mmc/host/rk29_sdmmc.c | 7 +- 6 files changed, 807 insertions(+), 108 deletions(-) diff --git a/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c b/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c index df39601eaf4b..1a1dd79c0d75 100644 --- a/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c +++ b/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c @@ -25,17 +25,26 @@ static void rk29_sdmmc_gpio_open(int device_id, int on) #ifdef CONFIG_SDMMC0_RK29 if(on) { + #if defined(CONFIG_ARCH_RK30) gpio_direction_output(GPIO3B_GPIO3B0,GPIO_HIGH);//set mmc0-clk to high gpio_direction_output(GPIO3B_GPIO3B1,GPIO_HIGH);// set mmc0-cmd to high. gpio_direction_output(GPIO3B_GPIO3B2,GPIO_HIGH);//set mmc0-data0 to high. gpio_direction_output(GPIO3B_GPIO3B3,GPIO_HIGH);//set mmc0-data1 to high. gpio_direction_output(GPIO3B_GPIO3B4,GPIO_HIGH);//set mmc0-data2 to high. gpio_direction_output(GPIO3B_GPIO3B5,GPIO_HIGH);//set mmc0-data3 to high. - + #elif defined(CONFIG_ARCH_RK31) + gpio_direction_output(RK30_PIN3_PA2,GPIO_HIGH);//set mmc0-clk to high + gpio_direction_output(RK30_PIN3_PA3,GPIO_HIGH);// set mmc0-cmd to high. + gpio_direction_output(RK30_PIN3_PA4,GPIO_HIGH);//set mmc0-data0 to high. + gpio_direction_output(RK30_PIN3_PA5,GPIO_HIGH);//set mmc0-data1 to high. + gpio_direction_output(RK30_PIN3_PA6,GPIO_HIGH);//set mmc0-data2 to high. + gpio_direction_output(RK30_PIN3_PA7,GPIO_HIGH);//set mmc0-data3 to high. + #endif mdelay(30); } else { + #if defined(CONFIG_ARCH_RK30) rk30_mux_api_set(GPIO3B0_SDMMC0CLKOUT_NAME, GPIO3B_GPIO3B0); gpio_request(RK30_PIN3_PB0, "mmc0-clk"); gpio_direction_output(RK30_PIN3_PB0,GPIO_LOW);//set mmc0-clk to low. @@ -59,7 +68,31 @@ static void rk29_sdmmc_gpio_open(int device_id, int on) rk30_mux_api_set(GPIO3B5_SDMMC0DATA3_NAME, GPIO3B_GPIO3B5); gpio_request(RK30_PIN3_PB5, "mmc0-data3"); gpio_direction_output(RK30_PIN3_PB5,GPIO_LOW);//set mmc0-data3 to low. + #elif defined(CONFIG_ARCH_RK31) + rk30_mux_api_set(GPIO3A2_SDMMC0CLKOUT_NAME, GPIO3A_GPIO3A2); + gpio_request(RK30_PIN3_PA2, "mmc0-clk"); + gpio_direction_output(RK30_PIN3_PA2,GPIO_LOW);//set mmc0-clk to low. + rk30_mux_api_set(GPIO3A3_SDMMC0CMD_NAME, GPIO3A_GPIO3A3); + gpio_request(RK30_PIN3_PA3, "mmc0-cmd"); + gpio_direction_output(RK30_PIN3_PA3,GPIO_LOW);//set mmc0-cmd to low. + + rk30_mux_api_set(GPIO3A4_SDMMC0DATA0_NAME, GPIO3A_GPIO3A4); + gpio_request(RK30_PIN3_PA4, "mmc0-data0"); + gpio_direction_output(RK30_PIN3_PA4,GPIO_LOW);//set mmc0-data0 to low. + + rk30_mux_api_set(GPIO3A5_SDMMC0DATA1_NAME, GPIO3A_GPIO3A5); + gpio_request(RK30_PIN3_PA5, "mmc0-data1"); + gpio_direction_output(RK30_PIN3_PA5,GPIO_LOW);//set mmc0-data1 to low. + + rk30_mux_api_set(GPIO3A6_SDMMC0DATA2_NAME, GPIO3A_GPIO3A6); + gpio_request(RK30_PIN3_PA6, "mmc0-data2"); + gpio_direction_output(RK30_PIN3_PA6,GPIO_LOW);//set mmc0-data2 to low. + + rk30_mux_api_set(GPIO3A7_SDMMC0DATA3_NAME, GPIO3A_GPIO3A7); + gpio_request(RK30_PIN3_PA7, "mmc0-data3"); + gpio_direction_output(RK30_PIN3_PA7,GPIO_LOW);//set mmc0-data3 to low. + #endif mdelay(30); } #endif @@ -81,6 +114,7 @@ static void rk29_sdmmc_gpio_open(int device_id, int on) } else { + #if defined(CONFIG_ARCH_RK30) rk30_mux_api_set(GPIO3C5_SDMMC1CLKOUT_NAME, GPIO3C_GPIO3C5); gpio_request(RK30_PIN3_PC5, "mmc1-clk"); gpio_direction_output(RK30_PIN3_PC5,GPIO_LOW);//set mmc1-clk to low. @@ -92,7 +126,19 @@ static void rk29_sdmmc_gpio_open(int device_id, int on) rk30_mux_api_set(GPIO3C1_SDMMC1DATA0_NAME, GPIO3C_GPIO3C1); gpio_request(RK30_PIN3_PC1, "mmc1-data0"); gpio_direction_output(RK30_PIN3_PC1,GPIO_LOW);//set mmc1-data0 to low. + #elif defined(CONFIG_ARCH_RK31) + rk30_mux_api_set(GPIO3C5_SDMMC1CLKOUT_RMIICLKOUT_RMIICLKIN_NAME, GPIO3C_GPIO3C5); + gpio_request(RK30_PIN3_PC5, "mmc1-clk"); + gpio_direction_output(RK30_PIN3_PC5,GPIO_LOW);//set mmc1-clk to low. + rk30_mux_api_set(GPIO3C0_SDMMC1CMD_RMIITXEN_NAME, GPIO3C_GPIO3C0); + gpio_request(RK30_PIN3_PC0, "mmc1-cmd"); + gpio_direction_output(RK30_PIN3_PC0,GPIO_LOW);//set mmc1-cmd to low. + + rk30_mux_api_set(GPIO3C1_SDMMC1DATA0_RMIITXD1_NAME, GPIO3C_GPIO3C1); + gpio_request(RK30_PIN3_PC1, "mmc1-data0"); + gpio_direction_output(RK30_PIN3_PC1,GPIO_LOW);//set mmc1-data0 to low. + #endif mdelay(100); } #endif @@ -114,9 +160,15 @@ static void rk29_sdmmc_set_iomux_mmc0(unsigned int bus_width) case 1://SDMMC_CTYPE_4BIT: { + #if defined(CONFIG_ARCH_RK30) rk30_mux_api_set(GPIO3B3_SDMMC0DATA1_NAME, GPIO3B_SDMMC0_DATA1); rk30_mux_api_set(GPIO3B4_SDMMC0DATA2_NAME, GPIO3B_SDMMC0_DATA2); rk30_mux_api_set(GPIO3B5_SDMMC0DATA3_NAME, GPIO3B_SDMMC0_DATA3); + #elif defined(CONFIG_ARCH_RK31) + rk30_mux_api_set(GPIO3A5_SDMMC0DATA1_NAME, GPIO3A_SDMMC0DATA1); + rk30_mux_api_set(GPIO3A6_SDMMC0DATA2_NAME, GPIO3A_SDMMC0DATA2); + rk30_mux_api_set(GPIO3A7_SDMMC0DATA3_NAME, GPIO3A_SDMMC0DATA3); + #endif } break; @@ -124,6 +176,7 @@ static void rk29_sdmmc_set_iomux_mmc0(unsigned int bus_width) break; case 0xFFFF: //gpio_reset { + #if defined(CONFIG_ARCH_RK30) rk30_mux_api_set(GPIO3A7_SDMMC0PWREN_NAME, GPIO3A_GPIO3A7); gpio_request(RK30_PIN3_PA7,"sdmmc-power"); gpio_direction_output(RK30_PIN3_PA7,GPIO_HIGH); //power-off @@ -133,14 +186,26 @@ static void rk29_sdmmc_set_iomux_mmc0(unsigned int bus_width) gpio_direction_output(RK30_PIN3_PA7,GPIO_LOW); //power-on rk29_sdmmc_gpio_open(0, 1); + #elif defined(CONFIG_ARCH_RK31) + rk30_mux_api_set(GPIO3A1_SDMMC0PWREN_NAME, GPIO3A_GPIO3A1); + gpio_request(RK30_PIN3_PA1,"sdmmc-power"); + gpio_direction_output(RK30_PIN3_PA1,GPIO_HIGH); //power-off + + rk29_sdmmc_gpio_open(0, 0); + + gpio_direction_output(RK30_PIN3_PA1,GPIO_LOW); //power-on + + rk29_sdmmc_gpio_open(0, 1); + #endif } break; default: //case 0://SDMMC_CTYPE_1BIT: { - rk30_mux_api_set(GPIO3B1_SDMMC0CMD_NAME, GPIO3B_SDMMC0_CMD); - rk30_mux_api_set(GPIO3B0_SDMMC0CLKOUT_NAME, GPIO3B_SDMMC0_CLKOUT); - rk30_mux_api_set(GPIO3B2_SDMMC0DATA0_NAME, GPIO3B_SDMMC0_DATA0); + #if defined(CONFIG_ARCH_RK30) + rk30_mux_api_set(GPIO3B1_SDMMC0CMD_NAME, GPIO3B_SDMMC0_CMD); + rk30_mux_api_set(GPIO3B0_SDMMC0CLKOUT_NAME, GPIO3B_SDMMC0_CLKOUT); + rk30_mux_api_set(GPIO3B2_SDMMC0DATA0_NAME, GPIO3B_SDMMC0_DATA0); rk30_mux_api_set(GPIO3B3_SDMMC0DATA1_NAME, GPIO3B_GPIO3B3); gpio_request(RK30_PIN3_PB3, "mmc0-data1"); @@ -153,6 +218,23 @@ static void rk29_sdmmc_set_iomux_mmc0(unsigned int bus_width) rk30_mux_api_set(GPIO3B5_SDMMC0DATA3_NAME, GPIO3B_GPIO3B5); gpio_request(RK30_PIN3_PB5, "mmc0-data3"); gpio_direction_output(RK30_PIN3_PB5,GPIO_HIGH);//set mmc0-data3 to high. + #elif defined(CONFIG_ARCH_RK31) + rk30_mux_api_set(GPIO3A3_SDMMC0CMD_NAME, GPIO3A_SDMMC0CMD); + rk30_mux_api_set(GPIO3A2_SDMMC0CLKOUT_NAME, GPIO3A_SDMMC0CLKOUT); + rk30_mux_api_set(GPIO3A4_SDMMC0DATA0_NAME, GPIO3A_SDMMC0DATA0); + + rk30_mux_api_set(GPIO3A5_SDMMC0DATA1_NAME, GPIO3A_GPIO3A5); + gpio_request(RK30_PIN3_PA5, "mmc0-data1"); + gpio_direction_output(RK30_PIN3_PA5,GPIO_HIGH);//set mmc0-data1 to high. + + rk30_mux_api_set(GPIO3A6_SDMMC0DATA2_NAME, GPIO3A_GPIO3A6); + gpio_request(RK30_PIN3_PA5, "mmc0-data2"); + gpio_direction_output(RK30_PIN3_PA5,GPIO_HIGH);//set mmc0-data2 to high. + + rk30_mux_api_set(GPIO3A7_SDMMC0DATA3_NAME, GPIO3A_GPIO3A7); + gpio_request(RK30_PIN3_PA7, "mmc0-data3"); + gpio_direction_output(RK30_PIN3_PA7,GPIO_HIGH);//set mmc0-data3 to high. + #endif } break; } @@ -160,12 +242,21 @@ static void rk29_sdmmc_set_iomux_mmc0(unsigned int bus_width) static void rk29_sdmmc_set_iomux_mmc1(unsigned int bus_width) { +#if defined(CONFIG_ARCH_RK30) rk30_mux_api_set(GPIO3C0_SMMC1CMD_NAME, GPIO3C_SMMC1_CMD); rk30_mux_api_set(GPIO3C5_SDMMC1CLKOUT_NAME, GPIO3C_SDMMC1_CLKOUT); rk30_mux_api_set(GPIO3C1_SDMMC1DATA0_NAME, GPIO3C_SDMMC1_DATA0); rk30_mux_api_set(GPIO3C2_SDMMC1DATA1_NAME, GPIO3C_SDMMC1_DATA1); rk30_mux_api_set(GPIO3C3_SDMMC1DATA2_NAME, GPIO3C_SDMMC1_DATA2); rk30_mux_api_set(GPIO3C4_SDMMC1DATA3_NAME, GPIO3C_SDMMC1_DATA3); +#elif defined(CONFIG_ARCH_RK31) + rk30_mux_api_set(GPIO3C0_SDMMC1CMD_RMIITXEN_NAME, GPIO3C_SDMMC1CMD); + rk30_mux_api_set(GPIO3C5_SDMMC1CLKOUT_RMIICLKOUT_RMIICLKIN_NAME, GPIO3C_SDMMC1CLKOUT); + rk30_mux_api_set(GPIO3C1_SDMMC1DATA0_RMIITXD1_NAME, GPIO3C_SDMMC1DATA0); + rk30_mux_api_set(GPIO3C2_SDMMC1DATA1_RMIITXD0_NAME, GPIO3C_SDMMC1DATA1); + rk30_mux_api_set(GPIO3C3_SDMMC1DATA2_RMIIRXD0_NAME, GPIO3C_SDMMC1DATA2); + rk30_mux_api_set(GPIO3C4_SDMMC1DATA3_RMIIRXD1_NAME, GPIO3C_SDMMC1DATA3); +#endif } static void rk29_sdmmc_set_iomux_mmc2(unsigned int bus_width) diff --git a/arch/arm/mach-rk30/board-rk31-fpga.c b/arch/arm/mach-rk30/board-rk31-fpga.c index fcde79e30f81..bc4a3c22f344 100644 --- a/arch/arm/mach-rk30/board-rk31-fpga.c +++ b/arch/arm/mach-rk30/board-rk31-fpga.c @@ -494,18 +494,18 @@ static rk_sensor_user_init_data_s rk_init_data_sensor[RK_CAM_NUM] = #define RK_FB_MEM_SIZE 3*SZ_1M #if defined(CONFIG_FB_ROCKCHIP) -#define LCD_CS_MUX_NAME GPIO4C7_SMCDATA7_TRACEDATA7_NAME -#define LCD_CS_PIN RK30_PIN4_PC7 +#define LCD_CS_MUX_NAME GPIO2A7_LCDC1DATA7_SMCDATA7_TRACEDATA7_NAME +#define LCD_CS_PIN RK30_PIN2_PA7 #define LCD_CS_VALUE GPIO_HIGH -#define LCD_EN_MUX_NAME GPIO4C7_SMCDATA7_TRACEDATA7_NAME -#define LCD_EN_PIN RK30_PIN6_PB4 +#define LCD_EN_MUX_NAME GPIO2D7_TESTCLOCKOUT_NAME +#define LCD_EN_PIN RK30_PIN2_PD7 #define LCD_EN_VALUE GPIO_LOW static int rk_fb_io_init(struct rk29_fb_setting_info *fb_setting) { int ret = 0; - rk30_mux_api_set(LCD_CS_MUX_NAME, GPIO4C_GPIO4C7); + rk30_mux_api_set(LCD_CS_MUX_NAME, GPIO2A_GPIO2A7); ret = gpio_request(LCD_CS_PIN, NULL); if (ret != 0) { @@ -772,23 +772,23 @@ static struct platform_device *devices[] __initdata = { static int rk29_sdmmc0_cfg_gpio(void) { #ifdef CONFIG_SDMMC_RK29_OLD - rk30_mux_api_set(GPIO3B1_SDMMC0CMD_NAME, GPIO3B_SDMMC0_CMD); - rk30_mux_api_set(GPIO3B0_SDMMC0CLKOUT_NAME, GPIO3B_SDMMC0_CLKOUT); - rk30_mux_api_set(GPIO3B2_SDMMC0DATA0_NAME, GPIO3B_SDMMC0_DATA0); - rk30_mux_api_set(GPIO3B3_SDMMC0DATA1_NAME, GPIO3B_SDMMC0_DATA1); - rk30_mux_api_set(GPIO3B4_SDMMC0DATA2_NAME, GPIO3B_SDMMC0_DATA2); - rk30_mux_api_set(GPIO3B5_SDMMC0DATA3_NAME, GPIO3B_SDMMC0_DATA3); + rk30_mux_api_set(GPIO3A3_SDMMC0CMD_NAME, GPIO3A_SDMMC0CMD); + rk30_mux_api_set(GPIO3A2_SDMMC0CLKOUT_NAME, GPIO3A_SDMMC0CLKOUT); + rk30_mux_api_set(GPIO3A4_SDMMC0DATA0_NAME, GPIO3A_SDMMC0DATA0); + rk30_mux_api_set(GPIO3A5_SDMMC0DATA1_NAME, GPIO3A_SDMMC0DATA1); + rk30_mux_api_set(GPIO3A6_SDMMC0DATA2_NAME, GPIO3A_SDMMC0DATA2); + rk30_mux_api_set(GPIO3A7_SDMMC0DATA3_NAME, GPIO3A_SDMMC0DATA3); - rk30_mux_api_set(GPIO3B6_SDMMC0DETECTN_NAME, GPIO3B_GPIO3B6); + rk30_mux_api_set(GPIO3B0_SDMMC0DETECTN_NAME, GPIO3B_GPIO3B0); - rk30_mux_api_set(GPIO3A7_SDMMC0PWREN_NAME, GPIO3A_GPIO3A7); - gpio_request(RK30_PIN3_PA7, "sdmmc-power"); - gpio_direction_output(RK30_PIN3_PA7, GPIO_LOW); + rk30_mux_api_set(GPIO3A1_SDMMC0PWREN_NAME, GPIO3A_GPIO3A1); + gpio_request(RK30_PIN3_PA1, "sdmmc-power"); + gpio_direction_output(RK30_PIN3_PA1, GPIO_LOW); #else rk29_sdmmc_set_iomux(0, 0xFFFF); - rk30_mux_api_set(GPIO3B6_SDMMC0DETECTN_NAME, GPIO3B_SDMMC0_DETECT_N); + rk30_mux_api_set(GPIO3B0_SDMMC0DETECTN_NAME, GPIO3B_SDMMC0DETECTN); #if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) gpio_request(SDMMC0_WRITE_PROTECT_PIN, "sdmmc-wp"); diff --git a/arch/arm/mach-rk30/include/mach/iomux.h b/arch/arm/mach-rk30/include/mach/iomux.h index 6e2f2c7e5e28..00857dc4c0aa 100755 --- a/arch/arm/mach-rk30/include/mach/iomux.h +++ b/arch/arm/mach-rk30/include/mach/iomux.h @@ -18,6 +18,8 @@ #include + +#if defined(CONFIG_ARCH_RK30) //GPIO0A #define GPIO0A_GPIO0A7 0 #define GPIO0A_I2S_8CH_SDI 1 @@ -482,89 +484,6 @@ #define GPIO6B_GPIO6B7 0 #define GPIO6B_TEST_CLOCK_OUT 1 - -#define DEFAULT 0 -#define INITIAL 1 - -#if defined(CONFIG_ARCH_RK31) - -#define GRF_GPIO0L_DIR 0x0000 -#define GRF_GPIO0H_DIR 0x0004 -#define GRF_GPIO1L_DIR 0x0008 -#define GRF_GPIO1H_DIR 0x000c -#define GRF_GPIO2L_DIR 0x0010 -#define GRF_GPIO2H_DIR 0x0014 -#define GRF_GPIO3L_DIR 0x0018 -#define GRF_GPIO3H_DIR 0x001c -#define GRF_GPIO0L_DO 0x0020 -#define GRF_GPIO0H_DO 0x0024 -#define GRF_GPIO1L_DO 0x0028 -#define GRF_GPIO1H_DO 0x002c -#define GRF_GPIO2L_DO 0x0030 -#define GRF_GPIO2H_DO 0x0034 -#define GRF_GPIO3L_DO 0x0038 -#define GRF_GPIO3H_DO 0x003c -#define GRF_GPIO0L_EN 0x0040 -#define GRF_GPIO0H_EN 0x0044 -#define GRF_GPIO1L_EN 0x0048 -#define GRF_GPIO1H_EN 0x004c -#define GRF_GPIO2L_EN 0x0050 -#define GRF_GPIO2H_EN 0x0054 -#define GRF_GPIO3L_EN 0x0058 -#define GRF_GPIO3H_EN 0x005c -#define GRF_GPIO0A_IOMUX RK30_GRF_BASE+0x0060 -#define GRF_GPIO0B_IOMUX RK30_GRF_BASE+0x0064 -#define GRF_GPIO0C_IOMUX RK30_GRF_BASE+0x0068 -#define GRF_GPIO0D_IOMUX RK30_GRF_BASE+0x006c -#define GRF_GPIO1A_IOMUX RK30_GRF_BASE+0x0070 -#define GRF_GPIO1B_IOMUX RK30_GRF_BASE+0x0074 -#define GRF_GPIO1C_IOMUX RK30_GRF_BASE+0x0078 -#define GRF_GPIO1D_IOMUX RK30_GRF_BASE+0x007c -#define GRF_GPIO2A_IOMUX RK30_GRF_BASE+0x0080 -#define GRF_GPIO2B_IOMUX RK30_GRF_BASE+0x0084 -#define GRF_GPIO2C_IOMUX RK30_GRF_BASE+0x0088 -#define GRF_GPIO2D_IOMUX RK30_GRF_BASE+0x008c -#define GRF_GPIO3A_IOMUX RK30_GRF_BASE+0x0090 -#define GRF_GPIO3B_IOMUX RK30_GRF_BASE+0x0094 -#define GRF_GPIO3C_IOMUX RK30_GRF_BASE+0x0098 -#define GRF_GPIO3D_IOMUX RK30_GRF_BASE+0x009c -#define GRF_SOC_CON0 0x00a0 -#define GRF_SOC_CON1 0x00a4 -#define GRF_SOC_CON2 0x00a8 -#define GRF_SOC_STATUS0 0x00ac -#define GRF_DMAC1_CON0 0x00b0 -#define GRF_DMAC1_CON1 0x00b4 -#define GRF_DMAC1_CON2 0x00b8 -#define GRF_DMAC2_CON0 0x00bc -#define GRF_DMAC2_CON1 0x00c0 -#define GRF_DMAC2_CON2 0x00c4 -#define GRF_DMAC2_CON3 0x00c8 -#define GRF_UOC0_CON0 0x010c -#define GRF_UOC0_CON1 0x0110 -#define GRF_UOC0_CON2 0x0114 -#define GRF_UOC0_CON3 0x0118 -#define GRF_UOC1_CON0 0x011c -#define GRF_UOC1_CON1 0x0120 -#define GRF_UOC1_CON2 0x0124 -#define GRF_UOC1_CON3 0x0128 -#define GRF_UOC2_CON0 0x012c -#define GRF_UOC2_CON1 0x0130 -#define GRF_UOC3_CON0 0x0138 -#define GRF_UOC3_CON1 0x013c -#define GRF_HSIC_STAT 0x0140 -#define GRF_DDRC_CON0 0x00ec -#define GRF_DDRC_STAT 0x00f0 -#define GRF_OS_REG0 0x0144 -#define GRF_OS_REG1 0x0148 -#define GRF_OS_REG2 0x014c -#define GRF_OS_REG3 0x0150 -#define GRF_OS_REG4 0x0154 -#define GRF_OS_REG5 0x0158 -#define GRF_OS_REG6 0x015c -#define GRF_OS_REG7 0x0160 - -#else - #define GRF_GPIO0L_DIR 0x0000 #define GRF_GPIO0H_DIR 0x0004 #define GRF_GPIO1L_DIR 0x0008 @@ -655,8 +574,6 @@ #define GRF_OS_REG2 0x01d0 #define GRF_OS_REG3 0x01d4 -#endif - //GPIO0A #define GPIO0A7_I2S8CHSDI_NAME "gpio0a7_i2s8chsdi_name" @@ -885,6 +802,546 @@ //GPIO6B #define GPIO6B7_TESTCLOCKOUT_NAME "gpio6b7_testclockout_name" + +#elif defined(CONFIG_ARCH_RK31) + +//GPIO0C +#define GPIO0C_GPIO0C0 0 +#define GPIO0C_FLASHDATA8 1 +#define GPIO0C_GPIO0C1 0 +#define GPIO0C_FLASHDATA9 1 +#define GPIO0C_GPIO0C2 0 +#define GPIO0C_FLASHDATA10 1 +#define GPIO0C_GPIO0C3 0 +#define GPIO0C_FLASHDATA11 1 +#define GPIO0C_GPIO0C4 0 +#define GPIO0C_FLASHDATA12 1 +#define GPIO0C_GPIO0C5 0 +#define GPIO0C_FLASHDATA13 1 +#define GPIO0C_GPIO0C6 0 +#define GPIO0C_FLASHDATA14 1 +#define GPIO0C_GPIO0C7 0 +#define GPIO0C_FLASHDATA15 1 + +//GPIO0D +#define GPIO0D_GPIO0D0 0 +#define GPIO0D_FLASHDQS 1 +#define GPIO0D_EMMCCLKOUT 2 +#define GPIO0D_GPIO0D1 0 +#define GPIO0D_FLASHCSN1 1 +#define GPIO0D_GPIO0D2 0 +#define GPIO0D_FLASHCSN2 1 +#define GPIO0D_EMMCCMD 2 +#define GPIO0D_GPIO0D3 0 +#define GPIO0D_FLASHCSN3 1 +#define GPIO0D_EMMCRSTNOUT 2 +#define GPIO0D_GPIO0D4 0 +#define GPIO0D_SPI1RXD 1 +#define GPIO0D_GPIO0D5 0 +#define GPIO0D_SPI1TXD 1 +#define GPIO0D_GPIO0D6 0 +#define GPIO0D_SPI1CLK 1 +#define GPIO0D_GPIO0D7 0 +#define GPIO0D_SPI1CSN0 1 + +//GPIO1A +#define GPIO1A_GPIO1A0 0 +#define GPIO1A_UART0SIN 1 +#define GPIO1A_GPIO1A1 0 +#define GPIO1A_UART0SOUT 1 +#define GPIO1A_GPIO1A2 0 +#define GPIO1A_UART0CTSN 1 +#define GPIO1A_GPIO1A3 0 +#define GPIO1A_UART0RTSN 1 +#define GPIO1A_GPIO1A4 0 +#define GPIO1A_UART1SIN 1 +#define GPIO1A_SPI0RXD 2 +#define GPIO1A_GPIO1A5 0 +#define GPIO1A_UART1SOUT 1 +#define GPIO1A_SPI0TXD 2 +#define GPIO1A_GPIO1A6 0 +#define GPIO1A_UART1CTSN 1 +#define GPIO1A_SPI0CLK 2 +#define GPIO1A_GPIO1A7 0 +#define GPIO1A_UART1RTSN 1 +#define GPIO1A_SPI0CSN0 2 + +//GPIO1B +#define GPIO1B_GPIO1B0 0 +#define GPIO1B_UART2SIN 1 +#define GPIO1B_JTAGTDI 2 +#define GPIO1B_GPIO1B1 0 +#define GPIO1B_UART2SOUT 1 +#define GPIO1B_JTAGTDO 2 +#define GPIO1B_GPIO1B2 0 +#define GPIO1B_UART3SIN 1 +#define GPIO1B_GPSMAG 2 +#define GPIO1B_GPIO1B3 0 +#define GPIO1B_UART3SOUT 1 +#define GPIO1B_GPSSIG 2 +#define GPIO1B_GPIO1B4 0 +#define GPIO1B_UART3CTSN 1 +#define GPIO1B_GPSRFCLK 2 +#define GPIO1B_GPIO1B5 0 +#define GPIO1B_UART3RTSN 1 +#define GPIO1B_GPIO1B6 0 +#define GPIO1B_SPDIFTX 1 +#define GPIO1B_SPI1CSN1 2 +#define GPIO1B_GPIO1B7 0 +#define GPIO1B_SPI0CSN1 1 + +//GPIO1C +#define GPIO1C_GPIO1C0 0 +#define GPIO1C_I2SCLK 1 +#define GPIO1C_GPIO1C1 0 +#define GPIO1C_I2SSCLK 1 +#define GPIO1C_GPIO1C2 0 +#define GPIO1C_I2SLRCLKRX 1 +#define GPIO1C_GPIO1C3 0 +#define GPIO1C_I2SLRCLKTX 1 +#define GPIO1C_GPIO1C4 0 +#define GPIO1C_I2SSDI 1 +#define GPIO1C_GPIO1C5 0 +#define GPIO1C_I2SSDO 1 + +//GPIO1D +#define GPIO1D_GPIO1D0 0 +#define GPIO1D_I2C0SDA 1 +#define GPIO1D_GPIO1D1 0 +#define GPIO1D_I2C0SCL 1 +#define GPIO1D_GPIO1D2 0 +#define GPIO1D_I2C1SDA 1 +#define GPIO1D_GPIO1D3 0 +#define GPIO1D_I2C1SCL 1 +#define GPIO1D_GPIO1D4 0 +#define GPIO1D_I2C2SDA 1 +#define GPIO1D_GPIO1D5 0 +#define GPIO1D_I2C2SCL 1 +#define GPIO1D_GPIO1D6 0 +#define GPIO1D_I2C4SDA 1 +#define GPIO1D_GPIO1D7 0 +#define GPIO1D_I2C4SCL 1 + +//GPIO2A +#define GPIO2A_GPIO2A0 0 +#define GPIO2A_LCDC1DATA0 1 +#define GPIO2A_SMCDATA0 2 +#define GPIO2A_TRACEDATA0 3 +#define GPIO2A_GPIO2A1 0 +#define GPIO2A_LCDC1DATA1 1 +#define GPIO2A_SMCDATA1 2 +#define GPIO2A_TRACEDATA1 3 +#define GPIO2A_GPIO2A2 0 +#define GPIO2A_LCDC1DATA2 1 +#define GPIO2A_SMCDATA2 2 +#define GPIO2A_TRACEDATA2 3 +#define GPIO2A_GPIO2A3 0 +#define GPIO2A_LCDC1DATA3 1 +#define GPIO2A_SMCDATA3 2 +#define GPIO2A_TRACEDATA3 3 +#define GPIO2A_GPIO2A4 0 +#define GPIO2A_LCDC1DATA4 1 +#define GPIO2A_SMCDATA4 2 +#define GPIO2A_TRACEDATA4 3 +#define GPIO2A_GPIO2A5 0 +#define GPIO2A_LCDC1DATA5 1 +#define GPIO2A_SMCDATA5 2 +#define GPIO2A_TRACEDATA5 3 +#define GPIO2A_GPIO2A6 0 +#define GPIO2A_LCDC1DATA6 1 +#define GPIO2A_SMCDATA6 2 +#define GPIO2A_TRACEDATA6 3 +#define GPIO2A_GPIO2A7 0 +#define GPIO2A_LCDC1DATA7 1 +#define GPIO2A_SMCDATA7 2 +#define GPIO2A_TRACEDATA7 3 + +//GPIO2B +#define GPIO2B_GPIO2B0 0 +#define GPIO2B_LCDC1DATA8 1 +#define GPIO2B_SMCDATA8 2 +#define GPIO2B_TRACEDATA8 3 +#define GPIO2B_GPIO2B1 0 +#define GPIO2B_LCDC1DATA9 1 +#define GPIO2B_SMCDATA9 2 +#define GPIO2B_TRACEDATA9 3 +#define GPIO2B_GPIO2B2 0 +#define GPIO2B_LCDC1DATA10 1 +#define GPIO2B_SMCDATA10 2 +#define GPIO2B_TRACEDATA10 3 +#define GPIO2B_GPIO2B3 0 +#define GPIO2B_LCDC1DATA11 1 +#define GPIO2B_SMCDATA11 2 +#define GPIO2B_TRACEDATA11 3 +#define GPIO2B_GPIO2B4 0 +#define GPIO2B_LCDC1DATA12 1 +#define GPIO2B_SMCDATA12 2 +#define GPIO2B_TRACEDATA12 3 +#define GPIO2B_GPIO2B5 0 +#define GPIO2B_LCDC1DATA13 1 +#define GPIO2B_SMCDATA13 2 +#define GPIO2B_TRACEDATA13 3 +#define GPIO2B_GPIO2B6 0 +#define GPIO2B_LCDC1DATA14 1 +#define GPIO2B_SMCDATA14 2 +#define GPIO2B_TRACEDATA14 3 +#define GPIO2B_GPIO2B7 0 +#define GPIO2B_LCDC1DATA15 1 +#define GPIO2B_SMCDATA15 2 +#define GPIO2B_TRACEDATA15 3 + +//GPIO2C +#define GPIO2C_GPIO2C0 0 +#define GPIO2C_LCDC1DATA16 1 +#define GPIO2C_SMCADDR0 2 +#define GPIO2C_GPIO2C1 0 +#define GPIO2C_LCDC1DATA17 1 +#define GPIO2C_SMCADDR1 2 +#define GPIO2C_GPIO2C2 0 +#define GPIO2C_LCDC1DATA18 1 +#define GPIO2C_SMCADDR2 2 +#define GPIO2C_GPIO2C3 0 +#define GPIO2C_LCDC1DATA19 1 +#define GPIO2C_SMCADDR3 2 +#define GPIO2C_GPIO2C4 0 +#define GPIO2C_LCDC1DATA20 1 +#define GPIO2C_SMCADDR4 2 +#define GPIO2C_GPIO2C5 0 +#define GPIO2C_LCDC1DATA21 1 +#define GPIO2C_SMCADDR5 2 +#define GPIO2C_GPIO2C6 0 +#define GPIO2C_LCDC1DATA22 1 +#define GPIO2C_SMCADDR6 2 +#define GPIO2C_GPIO2C7 0 +#define GPIO2C_LCDC1DATA23 1 +#define GPIO2C_SMCADDR7 2 + +//GPIO2D +#define GPIO2D_GPIO2D0 0 +#define GPIO2D_LCDC1DCLK 1 +#define GPIO2D_SMCCSN0 2 +#define GPIO2D_GPIO2D1 0 +#define GPIO2D_LCDC1DEN 1 +#define GPIO2D_SMCWEN 2 +#define GPIO2D_GPIO2D2 0 +#define GPIO2D_LCDC1HSYNC 1 +#define GPIO2D_SMCOEN 2 +#define GPIO2D_GPIO2D3 0 +#define GPIO2D_LCDC1VSYNC 1 +#define GPIO2D_SMCADVN 2 +#define GPIO2D_GPIO2D4 0 +#define GPIO2D_SMCBLSN0 1 +#define GPIO2D_GPIO2D5 0 +#define GPIO2D_SMCBLSN1 1 +#define GPIO2D_GPIO2D6 0 +#define GPIO2D_SMCCSN1 1 +#define GPIO2D_GPIO2D7 0 +#define GPIO2D_TESTCLOCKOUT 1 + +//GPIO3A +#define GPIO3A_GPIO3A0 0 +#define GPIO3A_SDMMC0RSTNOUT 1 +#define GPIO3A_GPIO3A1 0 +#define GPIO3A_SDMMC0PWREN 1 +#define GPIO3A_GPIO3A2 0 +#define GPIO3A_SDMMC0CLKOUT 1 +#define GPIO3A_GPIO3A3 0 +#define GPIO3A_SDMMC0CMD 1 +#define GPIO3A_GPIO3A4 0 +#define GPIO3A_SDMMC0DATA0 1 +#define GPIO3A_GPIO3A5 0 +#define GPIO3A_SDMMC0DATA1 1 +#define GPIO3A_GPIO3A6 0 +#define GPIO3A_SDMMC0DATA2 1 +#define GPIO3A_GPIO3A7 0 +#define GPIO3A_SDMMC0DATA3 1 + +//GPIO3B +#define GPIO3B_GPIO3B0 0 +#define GPIO3B_SDMMC0DETECTN 1 +#define GPIO3B_GPIO3B1 0 +#define GPIO3B_SDMMC0WRITEPRT 1 +#define GPIO3B_GPIO3B3 0 +#define GPIO3B_CIFCLKOUT 1 +#define GPIO3B_GPIO3B4 0 +#define GPIO3B_CIFDATA0 1 +#define GPIO3B_HSADCDATA8 2 +#define GPIO3B_GPIO3B5 0 +#define GPIO3B_CIFDATA1 1 +#define GPIO3B_HSADCDATA9 2 +#define GPIO3B_GPIO3B6 0 +#define GPIO3B_CIFDATA10 1 +#define GPIO3B_I2C3SDA 2 +#define GPIO3B_GPIO3B7 0 +#define GPIO3B_CIFDATA11 1 +#define GPIO3B_I2C3SCL 2 + +//GPIO3C +#define GPIO3C_GPIO3C0 0 +#define GPIO3C_SDMMC1CMD 1 +#define GPIO3C_RMIITXEN 2 +#define GPIO3C_GPIO3C1 0 +#define GPIO3C_SDMMC1DATA0 1 +#define GPIO3C_RMIITXD1 2 +#define GPIO3C_GPIO3C2 0 +#define GPIO3C_SDMMC1DATA1 1 +#define GPIO3C_RMIITXD0 2 +#define GPIO3C_GPIO3C3 0 +#define GPIO3C_SDMMC1DATA2 1 +#define GPIO3C_RMIIRXD0 2 +#define GPIO3C_GPIO3C4 0 +#define GPIO3C_SDMMC1DATA3 1 +#define GPIO3C_RMIIRXD1 2 +#define GPIO3C_GPIO3C5 0 +#define GPIO3C_SDMMC1CLKOUT 1 +#define GPIO3C_RMIICLKOUT 2 +#define GPIO3C_RMIICLKIN 3 +#define GPIO3C_GPIO3C6 0 +#define GPIO3C_SDMMC1DETECTN 1 +#define GPIO3C_RMIIRXERR 2 +#define GPIO3C_GPIO3C7 0 +#define GPIO3C_SDMMC1WRITEPRT 1 +#define GPIO3C_RMIICRS 2 + +//GPIO3D +#define GPIO3D_GPIO3D0 0 +#define GPIO3D_SDMMC1PWREN 1 +#define GPIO3D_MIIMD 2 +#define GPIO3D_GPIO3D1 0 +#define GPIO3D_SDMMC1BACKENPWR 1 +#define GPIO3D_MIIMDCLK 2 +#define GPIO3D_GPIO3D2 0 +#define GPIO3D_SDMMC1INTN 1 +#define GPIO3D_GPIO3D3 0 +#define GPIO3D_PWM0 1 +#define GPIO3D_GPIO3D4 0 +#define GPIO3D_PWM1 1 +#define GPIO3D_JTAGTRSTN 2 +#define GPIO3D_GPIO3D5 0 +#define GPIO3D_PWM2 1 +#define GPIO3D_JTAGTCK 2 +#define GPIO3D_OTGDRVVBUS 3 +#define GPIO3D_GPIO3D6 0 +#define GPIO3D_PWM3 1 +#define GPIO3D_JTAGTMS 2 +#define GPIO3D_HOSTDRVVBUS 3 + +#define GRF_GPIO0L_DIR 0x0000 +#define GRF_GPIO0H_DIR 0x0004 +#define GRF_GPIO1L_DIR 0x0008 +#define GRF_GPIO1H_DIR 0x000c +#define GRF_GPIO2L_DIR 0x0010 +#define GRF_GPIO2H_DIR 0x0014 +#define GRF_GPIO3L_DIR 0x0018 +#define GRF_GPIO3H_DIR 0x001c +#define GRF_GPIO0L_DO 0x0020 +#define GRF_GPIO0H_DO 0x0024 +#define GRF_GPIO1L_DO 0x0028 +#define GRF_GPIO1H_DO 0x002c +#define GRF_GPIO2L_DO 0x0030 +#define GRF_GPIO2H_DO 0x0034 +#define GRF_GPIO3L_DO 0x0038 +#define GRF_GPIO3H_DO 0x003c +#define GRF_GPIO0L_EN 0x0040 +#define GRF_GPIO0H_EN 0x0044 +#define GRF_GPIO1L_EN 0x0048 +#define GRF_GPIO1H_EN 0x004c +#define GRF_GPIO2L_EN 0x0050 +#define GRF_GPIO2H_EN 0x0054 +#define GRF_GPIO3L_EN 0x0058 +#define GRF_GPIO3H_EN 0x005c +#define GRF_GPIO0A_IOMUX RK30_GRF_BASE+0x0060 +#define GRF_GPIO0B_IOMUX RK30_GRF_BASE+0x0064 +#define GRF_GPIO0C_IOMUX RK30_GRF_BASE+0x0068 +#define GRF_GPIO0D_IOMUX RK30_GRF_BASE+0x006c +#define GRF_GPIO1A_IOMUX RK30_GRF_BASE+0x0070 +#define GRF_GPIO1B_IOMUX RK30_GRF_BASE+0x0074 +#define GRF_GPIO1C_IOMUX RK30_GRF_BASE+0x0078 +#define GRF_GPIO1D_IOMUX RK30_GRF_BASE+0x007c +#define GRF_GPIO2A_IOMUX RK30_GRF_BASE+0x0080 +#define GRF_GPIO2B_IOMUX RK30_GRF_BASE+0x0084 +#define GRF_GPIO2C_IOMUX RK30_GRF_BASE+0x0088 +#define GRF_GPIO2D_IOMUX RK30_GRF_BASE+0x008c +#define GRF_GPIO3A_IOMUX RK30_GRF_BASE+0x0090 +#define GRF_GPIO3B_IOMUX RK30_GRF_BASE+0x0094 +#define GRF_GPIO3C_IOMUX RK30_GRF_BASE+0x0098 +#define GRF_GPIO3D_IOMUX RK30_GRF_BASE+0x009c +#define GRF_SOC_CON0 0x00a0 +#define GRF_SOC_CON1 0x00a4 +#define GRF_SOC_CON2 0x00a8 +#define GRF_SOC_STATUS0 0x00ac +#define GRF_DMAC1_CON0 0x00b0 +#define GRF_DMAC1_CON1 0x00b4 +#define GRF_DMAC1_CON2 0x00b8 +#define GRF_DMAC2_CON0 0x00bc +#define GRF_DMAC2_CON1 0x00c0 +#define GRF_DMAC2_CON2 0x00c4 +#define GRF_DMAC2_CON3 0x00c8 +#define GRF_UOC0_CON0 0x010c +#define GRF_UOC0_CON1 0x0110 +#define GRF_UOC0_CON2 0x0114 +#define GRF_UOC0_CON3 0x0118 +#define GRF_UOC1_CON0 0x011c +#define GRF_UOC1_CON1 0x0120 +#define GRF_UOC1_CON2 0x0124 +#define GRF_UOC1_CON3 0x0128 +#define GRF_UOC2_CON0 0x012c +#define GRF_UOC2_CON1 0x0130 +#define GRF_UOC3_CON0 0x0138 +#define GRF_UOC3_CON1 0x013c +#define GRF_HSIC_STAT 0x0140 +#define GRF_DDRC_CON0 0x00ec +#define GRF_DDRC_STAT 0x00f0 +#define GRF_OS_REG0 0x0144 +#define GRF_OS_REG1 0x0148 +#define GRF_OS_REG2 0x014c +#define GRF_OS_REG3 0x0150 +#define GRF_OS_REG4 0x0154 +#define GRF_OS_REG5 0x0158 +#define GRF_OS_REG6 0x015c +#define GRF_OS_REG7 0x0160 + +//GPIO0C +#define GPIO0C0_FLASHDATA8_NAME "gpio0c0_flashdata8_name" +#define GPIO0C1_FLASHDATA9_NAME "gpio0c1_flashdata9_name" +#define GPIO0C2_FLASHDATA10_NAME "gpio0c2_flashdata10_name" +#define GPIO0C3_FLASHDATA11_NAME "gpio0c3_flashdata11_name" +#define GPIO0C4_FLASHDATA12_NAME "gpio0c4_flashdata12_name" +#define GPIO0C5_FLASHDATA13_NAME "gpio0c5_flashdata13_name" +#define GPIO0C6_FLASHDATA14_NAME "gpio0c6_flashdata14_name" +#define GPIO0C7_FLASHDATA15_NAME "gpio0c7_flashdata15_name" + +//GPIO0D +#define GPIO0D0_FLASHDQS_EMMCCLKOUT_NAME "gpio0d0_flashdqs_emmcclkout_name" +#define GPIO0D1_FLASHCSN1_NAME "gpio0d1_flashcsn1_name" +#define GPIO0D2_FLASHCSN2_EMMCCMD_NAME "gpio0d2_flashcsn2_emmccmd_name" +#define GPIO0D3_FLASHCSN3_EMMCRSTNOUT_NAME "gpio0d3_flashcsn3_emmcrstnout_name" +#define GPIO0D4_SPI1RXD_NAME "gpio0d4_spi1rxd_name" +#define GPIO0D5_SPI1TXD_NAME "gpio0d5_spi1txd_name" +#define GPIO0D6_SPI1CLK_NAME "gpio0d6_spi1clk_name" +#define GPIO0D7_SPI1CSN0_NAME "gpio0d7_spi1csn0_name" + +//GPIO1A +#define GPIO1A0_UART0SIN_NAME "gpio1a0_uart0sin_name" +#define GPIO1A1_UART0SOUT_NAME "gpio1a1_uart0sout_name" +#define GPIO1A2_UART0CTSN_NAME "gpio1a2_uart0ctsn_name" +#define GPIO1A3_UART0RTSN_NAME "gpio1a3_uart0rtsn_name" +#define GPIO1A4_UART1SIN_SPI0RXD_NAME "gpio1a4_uart1sin_spi0rxd_name" +#define GPIO1A5_UART1SOUT_SPI0TXD_NAME "gpio1a5_uart1sout_spi0txd_name" +#define GPIO1A6_UART1CTSN_SPI0CLK_NAME "gpio1a6_uart1ctsn_spi0clk_name" +#define GPIO1A7_UART1RTSN_SPI0CSN0_NAME "gpio1a7_uart1rtsn_spi0csn0_name" + +//GPIO1B +#define GPIO1B0_UART2SIN_JTAGTDI_NAME "gpio1b0_uart2sin_jtagtdi_name" +#define GPIO1B1_UART2SOUT_JTAGTDO_NAME "gpio1b1_uart2sout_jtagtdo_name" +#define GPIO1B2_UART3SIN_GPSMAG_NAME "gpio1b2_uart3sin_gpsmag_name" +#define GPIO1B3_UART3SOUT_GPSSIG_NAME "gpio1b3_uart3sout_gpssig_name" +#define GPIO1B4_UART3CTSN_GPSRFCLK_NAME "gpio1b4_uart3ctsn_gpsrfclk_name" +#define GPIO1B5_UART3RTSN_NAME "gpio1b5_uart3rtsn_name" +#define GPIO1B6_SPDIFTX_SPI1CSN1_NAME "gpio1b6_spdiftx_spi1csn1_name" +#define GPIO1B7_SPI0CSN1_NAME "gpio1b7_spi0csn1_name" + +//GPIO1C +#define GPIO1C0_I2SCLK_NAME "gpio1c0_i2sclk_name" +#define GPIO1C1_I2SSCLK_NAME "gpio1c1_i2ssclk_name" +#define GPIO1C2_I2SLRCLKRX_NAME "gpio1c2_i2slrclkrx_name" +#define GPIO1C3_I2SLRCLKTX_NAME "gpio1c3_i2slrclktx_name" +#define GPIO1C4_I2SSDI_NAME "gpio1c4_i2ssdi_name" +#define GPIO1C5_I2SSDO_NAME "gpio1c5_i2ssdo_name" + +//GPIO1D +#define GPIO1D0_I2C0SDA_NAME "gpio1d0_i2c0sda_name" +#define GPIO1D1_I2C0SCL_NAME "gpio1d1_i2c0scl_name" +#define GPIO1D2_I2C1SDA_NAME "gpio1d2_i2c1sda_name" +#define GPIO1D3_I2C1SCL_NAME "gpio1d3_i2c1scl_name" +#define GPIO1D4_I2C2SDA_NAME "gpio1d4_i2c2sda_name" +#define GPIO1D5_I2C2SCL_NAME "gpio1d5_i2c2scl_name" +#define GPIO1D6_I2C4SDA_NAME "gpio1d6_i2c4sda_name" +#define GPIO1D7_I2C4SCL_NAME "gpio1d7_i2c4scl_name" + +//GPIO2A +#define GPIO2A0_LCDC1DATA0_SMCDATA0_TRACEDATA0_NAME "gpio2a0_lcdc1data0_smcdata0_tracedata0_name" +#define GPIO2A1_LCDC1DATA1_SMCDATA1_TRACEDATA1_NAME "gpio2a1_lcdc1data1_smcdata1_tracedata1_name" +#define GPIO2A2_LCDC1DATA2_SMCDATA2_TRACEDATA2_NAME "gpio2a2_lcdc1data2_smcdata2_tracedata2_name" +#define GPIO2A3_LCDC1DATA3_SMCDATA3_TRACEDATA3_NAME "gpio2a3_lcdc1data3_smcdata3_tracedata3_name" +#define GPIO2A4_LCDC1DATA4_SMCDATA4_TRACEDATA4_NAME "gpio2a4_lcdc1data4_smcdata4_tracedata4_name" +#define GPIO2A5_LCDC1DATA5_SMCDATA5_TRACEDATA5_NAME "gpio2a5_lcdc1data5_smcdata5_tracedata5_name" +#define GPIO2A6_LCDC1DATA6_SMCDATA6_TRACEDATA6_NAME "gpio2a6_lcdc1data6_smcdata6_tracedata6_name" +#define GPIO2A7_LCDC1DATA7_SMCDATA7_TRACEDATA7_NAME "gpio2a7_lcdc1data7_smcdata7_tracedata7_name" + +//GPIO2B +#define GPIO2B0_LCDC1DATA8_SMCDATA8_TRACEDATA8_NAME "gpio2b0_lcdc1data8_smcdata8_tracedata8_name" +#define GPIO2B1_LCDC1DATA9_SMCDATA9_TRACEDATA9_NAME "gpio2b1_lcdc1data9_smcdata9_tracedata9_name" +#define GPIO2B2_LCDC1DATA10_SMCDATA10_TRACEDATA10_NAME "gpio2b2_lcdc1data10_smcdata10_tracedata10_name" +#define GPIO2B3_LCDC1DATA11_SMCDATA11_TRACEDATA11_NAME "gpio2b3_lcdc1data11_smcdata11_tracedata11_name" +#define GPIO2B4_LCDC1DATA12_SMCDATA12_TRACEDATA12_NAME "gpio2b4_lcdc1data12_smcdata12_tracedata12_name" +#define GPIO2B5_LCDC1DATA13_SMCDATA13_TRACEDATA13_NAME "gpio2b5_lcdc1data13_smcdata13_tracedata13_name" +#define GPIO2B6_LCDC1DATA14_SMCDATA14_TRACEDATA14_NAME "gpio2b6_lcdc1data14_smcdata14_tracedata14_name" +#define GPIO2B7_LCDC1DATA15_SMCDATA15_TRACEDATA15_NAME "gpio2b7_lcdc1data15_smcdata15_tracedata15_name" + +//GPIO2C +#define GPIO2C0_LCDC1DATA16_SMCADDR0_TRACECLK_NAME "gpio2c0_lcdc1data16_smcaddr0_traceclk_name" +#define GPIO2C1_LCDC1DATA17_SMCADDR1_TRACECTL_NAME "gpio2c1_lcdc1data17_smcaddr1_tracectl_name" +#define GPIO2C2_LCDC1DATA18_SMCADDR2_NAME "gpio2c2_lcdc1data18_smcaddr2_name" +#define GPIO2C3_LCDC1DATA19_SMCADDR3_NAME "gpio2c3_lcdc1data19_smcaddr3_name" +#define GPIO2C4_LCDC1DATA20_SMCADDR4_NAME "gpio2c4_lcdc1data20_smcaddr4_name" +#define GPIO2C5_LCDC1DATA21_SMCADDR5_NAME "gpio2c5_lcdc1data21_smcaddr5_name" +#define GPIO2C6_LCDC1DATA22_SMCADDR6_NAME "gpio2c6_lcdc1data22_smcaddr6_name" +#define GPIO2C7_LCDC1DATA23_SMCADDR7_NAME "gpio2c7_lcdc1data23_smcaddr7_name" + +//GPIO2D +#define GPIO2D0_LCDC1DCLK_SMCCSN0_NAME "gpio2d0_lcdc1dclk_smccsn0_name" +#define GPIO2D1_LCDC1DEN_SMCWEN_NAME "gpio2d1_lcdc1den_smcwen_name" +#define GPIO2D2_LCDC1HSYNC_SMCOEN_NAME "gpio2d2_lcdc1hsync_smcoen_name" +#define GPIO2D3_LCDC1VSYNC_SMCADVN_NAME "gpio2d3_lcdc1vsync_smcadvn_name" +#define GPIO2D4_SMCBLSN0_NAME "gpio2d4_smcblsn0_name" +#define GPIO2D5_SMCBLSN1_NAME "gpio2d5_smcblsn1_name" +#define GPIO2D6_SMCCSN1_NAME "gpio2d6_smccsn1_name" +#define GPIO2D7_TESTCLOCKOUT_NAME "gpio2d7_testclockout_name" + +//GPIO3A +#define GPIO3A0_SDMMC0RSTNOUT_NAME "gpio3a0_sdmmc0rstnout_name" +#define GPIO3A1_SDMMC0PWREN_NAME "gpio3a1_sdmmc0pwren_name" +#define GPIO3A2_SDMMC0CLKOUT_NAME "gpio3a2_sdmmc0clkout_name" +#define GPIO3A3_SDMMC0CMD_NAME "gpio3a3_sdmmc0cmd_name" +#define GPIO3A4_SDMMC0DATA0_NAME "gpio3a4_sdmmc0data0_name" +#define GPIO3A5_SDMMC0DATA1_NAME "gpio3a5_sdmmc0data1_name" +#define GPIO3A6_SDMMC0DATA2_NAME "gpio3a6_sdmmc0data2_name" +#define GPIO3A7_SDMMC0DATA3_NAME "gpio3a7_sdmmc0data3_name" + +//GPIO3B +#define GPIO3B0_SDMMC0DETECTN_NAME "gpio3b0_sdmmc0detectn_name" +#define GPIO3B1_SDMMC0WRITEPRT_NAME "gpio3b1_sdmmc0writeprt_name" +#define GPIO3B3_CIFCLKOUT_NAME "gpio3b3_cifclkout_name" +#define GPIO3B4_CIFDATA0_HSADCDATA8_NAME "gpio3b4_cifdata0_hsadcdata8_name" +#define GPIO3B5_CIFDATA1_HSADCDATA9_NAME "gpio3b5_cifdata1_hsadcdata9_name" +#define GPIO3B6_CIFDATA10_I2C3SDA_NAME "gpio3b6_cifdata10_i2c3sda_name" +#define GPIO3B7_CIFDATA11_I2C3SCL_NAME "gpio3b7_cifdata11_i2c3scl_name" + +//GPIO3C +#define GPIO3C0_SDMMC1CMD_RMIITXEN_NAME "gpio3c0_sdmmc1cmd_rmiitxen_name" +#define GPIO3C1_SDMMC1DATA0_RMIITXD1_NAME "gpio3c1_sdmmc1data0_rmiitxd1_name" +#define GPIO3C2_SDMMC1DATA1_RMIITXD0_NAME "gpio3c2_sdmmc1data1_rmiitxd0_name" +#define GPIO3C3_SDMMC1DATA2_RMIIRXD0_NAME "gpio3c3_sdmmc1data2_rmiirxd0_name" +#define GPIO3C4_SDMMC1DATA3_RMIIRXD1_NAME "gpio3c4_sdmmc1data3_rmiirxd1_name" +#define GPIO3C5_SDMMC1CLKOUT_RMIICLKOUT_RMIICLKIN_NAME "gpio3c5_sdmmc1clkout_rmiiclkout_rmiiclkin_name" +#define GPIO3C6_SDMMC1DETECTN_RMIIRXERR_NAME "gpio3c6_sdmmc1detectn_rmiirxerr_name" +#define GPIO3C7_SDMMC1WRITEPRT_RMIICRS_NAME "gpio3c7_sdmmc1writeprt_rmiicrs_name" + +//GPIO3D +#define GPIO3D0_SDMMC1PWREN_MIIMD_NAME "gpio3d0_sdmmc1pwren_miimd_name" +#define GPIO3D1_SDMMC1BACKENDPWR_MIIMDCLK_NAME "gpio3d1_sdmmc1backendpwr_miimdclk_name" +#define GPIO3D2_SDMMC1INTN_NAME "gpio3d2_sdmmc1intn_name" +#define GPIO3D3_PWM0_NAME "gpio3d3_pwm0_name" +#define GPIO3D4_PWM1_JTAGTRSTN_NAME "gpio3d4_pwm1_jtagtrstn_name" +#define GPIO3D5_PWM2_JTAGTCK_OTGDRVVBUS_NAME "gpio3d5_pwm2_jtagtck_otgdrvvbus_name" +#define GPIO3D6_PWM3_JTAGTMS_HOSTDRVVBUS_NAME "gpio3d6_pwm3_jtagtms_hostdrvvbus_name" + +#endif + +#define DEFAULT 0 +#define INITIAL 1 + #define MUX_CFG(desc,reg,off,interl,mux_mode,bflags) \ { \ .name = desc, \ diff --git a/arch/arm/mach-rk30/iomux.c b/arch/arm/mach-rk30/iomux.c index 9c2f237fe11d..c38cc27660c2 100755 --- a/arch/arm/mach-rk30/iomux.c +++ b/arch/arm/mach-rk30/iomux.c @@ -28,7 +28,8 @@ static struct mux_config rk30_muxs[] = { /* * description mux mode mux mux * reg offset inter mode - */ + */ +#if defined(CONFIG_ARCH_RK30) //GPIO0A MUX_CFG(GPIO0A7_I2S8CHSDI_NAME, GPIO0A, 14, 1, 0, DEFAULT) MUX_CFG(GPIO0A6_HOSTDRVVBUS_NAME, GPIO0A, 12, 1, 0, DEFAULT) @@ -189,7 +190,6 @@ MUX_CFG(GPIO3D2_SDMMC1INTN_NAME, GPIO3D, 4, 1, 0, DEFAULT) MUX_CFG(GPIO3D1_SDMMC1BACKENDPWR_NAME, GPIO3D, 2, 1, 0, DEFAULT) MUX_CFG(GPIO3D0_SDMMC1PWREN_NAME, GPIO3D, 0, 1, 0, DEFAULT) -#if defined(CONFIG_ARCH_RK30) //GPIO4A MUX_CFG(GPIO4A7_FLASHDATA15_NAME, GPIO4A, 14, 1, 0, DEFAULT) MUX_CFG(GPIO4A6_FLASHDATA14_NAME, GPIO4A, 12, 1, 0, DEFAULT) @@ -233,6 +233,144 @@ MUX_CFG(GPIO4D0_SMCDATA8_TRACEDATA8_NAME, GPIO4D, 0, 2, 0, DEFAULT) //GPIO6B MUX_CFG(GPIO6B7_TESTCLOCKOUT_NAME, GPIO6B, 14, 1, 0, DEFAULT) +#elif defined(CONFIG_ARCH_RK31) + +//GPIO0C +MUX_CFG(GPIO0C7_FLASHDATA15_NAME, GPIO0C, 14, 1, 0, DEFAULT) +MUX_CFG(GPIO0C6_FLASHDATA14_NAME, GPIO0C, 12, 1, 0, DEFAULT) +MUX_CFG(GPIO0C5_FLASHDATA13_NAME, GPIO0C, 10, 1, 0, DEFAULT) +MUX_CFG(GPIO0C4_FLASHDATA12_NAME, GPIO0C, 8, 1, 0, DEFAULT) +MUX_CFG(GPIO0C3_FLASHDATA11_NAME, GPIO0C, 6, 1, 0, DEFAULT) +MUX_CFG(GPIO0C2_FLASHDATA10_NAME, GPIO0C, 4, 1, 0, DEFAULT) +MUX_CFG(GPIO0C1_FLASHDATA9_NAME, GPIO0C, 2, 1, 0, DEFAULT) +MUX_CFG(GPIO0C0_FLASHDATA8_NAME, GPIO0C, 0, 1, 0, DEFAULT) + +//GPIO0D +MUX_CFG(GPIO0D7_SPI1CSN0_NAME, GPIO0D, 14, 1, 0, DEFAULT) +MUX_CFG(GPIO0D6_SPI1CLK_NAME, GPIO0D, 12, 1, 0, DEFAULT) +MUX_CFG(GPIO0D5_SPI1TXD_NAME, GPIO0D, 10, 1, 0, DEFAULT) +MUX_CFG(GPIO0D4_SPI1RXD_NAME, GPIO0D, 8, 1, 0, DEFAULT) +MUX_CFG(GPIO0D3_FLASHCSN3_EMMCRSTNOUT_NAME, GPIO0D, 6, 2, 0, DEFAULT) +MUX_CFG(GPIO0D2_FLASHCSN2_EMMCCMD_NAME, GPIO0D, 4, 2, 0, DEFAULT) +MUX_CFG(GPIO0D1_FLASHCSN1_NAME, GPIO0D, 2, 2, 0, DEFAULT) +MUX_CFG(GPIO0D0_FLASHDQS_EMMCCLKOUT_NAME, GPIO0D, 0, 2, 0, DEFAULT) + +//GPIO1A +MUX_CFG(GPIO1A7_UART1RTSN_SPI0CSN0_NAME, GPIO1A, 14, 2, 0, DEFAULT) +MUX_CFG(GPIO1A6_UART1CTSN_SPI0CLK_NAME, GPIO1A, 12, 2, 0, DEFAULT) +MUX_CFG(GPIO1A5_UART1SOUT_SPI0TXD_NAME, GPIO1A, 10, 2, 0, DEFAULT) +MUX_CFG(GPIO1A4_UART1SIN_SPI0RXD_NAME, GPIO1A, 8, 2, 0, DEFAULT) +MUX_CFG(GPIO1A3_UART0RTSN_NAME, GPIO1A, 6, 1, 0, DEFAULT) +MUX_CFG(GPIO1A2_UART0CTSN_NAME, GPIO1A, 4, 1, 0, DEFAULT) +MUX_CFG(GPIO1A1_UART0SOUT_NAME, GPIO1A, 2, 1, 0, DEFAULT) +MUX_CFG(GPIO1A0_UART0SIN_NAME, GPIO1A, 0, 1, 0, DEFAULT) + +//GPIO1B +MUX_CFG(GPIO1B7_SPI0CSN1_NAME, GPIO1B, 14, 1, 0, DEFAULT) +MUX_CFG(GPIO1B6_SPDIFTX_SPI1CSN1_NAME, GPIO1B, 12, 2, 0, DEFAULT) +MUX_CFG(GPIO1B5_UART3RTSN_NAME, GPIO1B, 10, 2, 0, DEFAULT) +MUX_CFG(GPIO1B4_UART3CTSN_GPSRFCLK_NAME, GPIO1B, 8, 2, 0, DEFAULT) +MUX_CFG(GPIO1B3_UART3SOUT_GPSSIG_NAME, GPIO1B, 6, 2, 0, DEFAULT) +MUX_CFG(GPIO1B2_UART3SIN_GPSMAG_NAME, GPIO1B, 4, 2, 0, DEFAULT) +MUX_CFG(GPIO1B1_UART2SOUT_JTAGTDO_NAME, GPIO1B, 2, 2, 0, DEFAULT) +MUX_CFG(GPIO1B0_UART2SIN_JTAGTDI_NAME, GPIO1B, 0, 2, 0, DEFAULT) + +//GPIO1C +MUX_CFG(GPIO1C5_I2SSDO_NAME, GPIO1C, 10, 1, 0, DEFAULT) +MUX_CFG(GPIO1C4_I2SSDI_NAME, GPIO1C, 8, 1, 0, DEFAULT) +MUX_CFG(GPIO1C3_I2SLRCLKTX_NAME, GPIO1C, 6, 1, 0, DEFAULT) +MUX_CFG(GPIO1C2_I2SLRCLKRX_NAME, GPIO1C, 4, 1, 0, DEFAULT) +MUX_CFG(GPIO1C1_I2SSCLK_NAME, GPIO1C, 2, 1, 0, DEFAULT) +MUX_CFG(GPIO1C0_I2SCLK_NAME, GPIO1C, 0, 1, 0, DEFAULT) + +//GPIO1D +MUX_CFG(GPIO1D7_I2C4SCL_NAME, GPIO1D, 14, 1, 0, DEFAULT) +MUX_CFG(GPIO1D6_I2C4SDA_NAME, GPIO1D, 12, 1, 0, DEFAULT) +MUX_CFG(GPIO1D5_I2C2SCL_NAME, GPIO1D, 10, 1, 0, DEFAULT) +MUX_CFG(GPIO1D4_I2C2SDA_NAME, GPIO1D, 8, 1, 0, DEFAULT) +MUX_CFG(GPIO1D3_I2C1SCL_NAME, GPIO1D, 6, 1, 0, DEFAULT) +MUX_CFG(GPIO1D2_I2C1SDA_NAME, GPIO1D, 4, 1, 0, DEFAULT) +MUX_CFG(GPIO1D1_I2C0SCL_NAME, GPIO1D, 2, 1, 0, DEFAULT) +MUX_CFG(GPIO1D0_I2C0SDA_NAME, GPIO1D, 0, 1, 0, DEFAULT) + +//GPIO2A +MUX_CFG(GPIO2A7_LCDC1DATA7_SMCDATA7_TRACEDATA7_NAME, GPIO2A, 14, 2, 0, DEFAULT) +MUX_CFG(GPIO2A6_LCDC1DATA6_SMCDATA6_TRACEDATA6_NAME, GPIO2A, 12, 2, 0, DEFAULT) +MUX_CFG(GPIO2A5_LCDC1DATA5_SMCDATA5_TRACEDATA5_NAME, GPIO2A, 10, 2, 0, DEFAULT) +MUX_CFG(GPIO2A4_LCDC1DATA4_SMCDATA4_TRACEDATA4_NAME, GPIO2A, 8, 2, 0, DEFAULT) +MUX_CFG(GPIO2A3_LCDC1DATA3_SMCDATA3_TRACEDATA3_NAME, GPIO2A, 6, 2, 0, DEFAULT) +MUX_CFG(GPIO2A2_LCDC1DATA2_SMCDATA2_TRACEDATA2_NAME, GPIO2A, 4, 2, 0, DEFAULT) +MUX_CFG(GPIO2A1_LCDC1DATA1_SMCDATA1_TRACEDATA1_NAME, GPIO2A, 2, 2, 0, DEFAULT) +MUX_CFG(GPIO2A0_LCDC1DATA0_SMCDATA0_TRACEDATA0_NAME, GPIO2A, 0, 2, 0, DEFAULT) + +//GPIO2B +MUX_CFG(GPIO2B7_LCDC1DATA15_SMCDATA15_TRACEDATA15_NAME, GPIO2B, 14, 2, 0, DEFAULT) +MUX_CFG(GPIO2B6_LCDC1DATA14_SMCDATA14_TRACEDATA14_NAME, GPIO2B, 12, 2, 0, DEFAULT) +MUX_CFG(GPIO2B5_LCDC1DATA13_SMCDATA13_TRACEDATA13_NAME, GPIO2B, 10, 2, 0, DEFAULT) +MUX_CFG(GPIO2B4_LCDC1DATA12_SMCDATA12_TRACEDATA12_NAME, GPIO2B, 8, 2, 0, DEFAULT) +MUX_CFG(GPIO2B3_LCDC1DATA11_SMCDATA11_TRACEDATA11_NAME, GPIO2B, 6, 2, 0, DEFAULT) +MUX_CFG(GPIO2B2_LCDC1DATA10_SMCDATA10_TRACEDATA10_NAME, GPIO2B, 4, 2, 0, DEFAULT) +MUX_CFG(GPIO2B1_LCDC1DATA9_SMCDATA9_TRACEDATA9_NAME, GPIO2B, 2, 2, 0, DEFAULT) +MUX_CFG(GPIO2B0_LCDC1DATA8_SMCDATA8_TRACEDATA8_NAME, GPIO2B, 0, 2, 0, DEFAULT) + +//GPIO2C +MUX_CFG(GPIO2C7_LCDC1DATA23_SMCADDR7_NAME, GPIO2C, 14, 2, 0, DEFAULT) +MUX_CFG(GPIO2C6_LCDC1DATA22_SMCADDR6_NAME, GPIO2C, 12, 2, 0, DEFAULT) +MUX_CFG(GPIO2C5_LCDC1DATA21_SMCADDR5_NAME, GPIO2C, 10, 2, 0, DEFAULT) +MUX_CFG(GPIO2C4_LCDC1DATA20_SMCADDR4_NAME, GPIO2C, 8, 2, 0, DEFAULT) +MUX_CFG(GPIO2C3_LCDC1DATA19_SMCADDR3_NAME, GPIO2C, 6, 2, 0, DEFAULT) +MUX_CFG(GPIO2C2_LCDC1DATA18_SMCADDR2_NAME, GPIO2C, 4, 2, 0, DEFAULT) +MUX_CFG(GPIO2C1_LCDC1DATA17_SMCADDR1_TRACECTL_NAME, GPIO2C, 2, 2, 0, DEFAULT) +MUX_CFG(GPIO2C0_LCDC1DATA16_SMCADDR0_TRACECLK_NAME, GPIO2C, 0, 2, 0, DEFAULT) + +//GPIO2D +MUX_CFG(GPIO2D7_TESTCLOCKOUT_NAME, GPIO2D, 14, 1, 0, DEFAULT) +MUX_CFG(GPIO2D6_SMCCSN1_NAME, GPIO2D, 12, 1, 0, DEFAULT) +MUX_CFG(GPIO2D5_SMCBLSN1_NAME, GPIO2D, 10, 1, 0, DEFAULT) +MUX_CFG(GPIO2D4_SMCBLSN0_NAME, GPIO2D, 8, 1, 0, DEFAULT) +MUX_CFG(GPIO2D3_LCDC1VSYNC_SMCADVN_NAME, GPIO2D, 6, 2, 0, DEFAULT) +MUX_CFG(GPIO2D2_LCDC1HSYNC_SMCOEN_NAME, GPIO2D, 4, 2, 0, DEFAULT) +MUX_CFG(GPIO2D1_LCDC1DEN_SMCWEN_NAME, GPIO2D, 2, 2, 0, DEFAULT) +MUX_CFG(GPIO2D0_LCDC1DCLK_SMCCSN0_NAME, GPIO2D, 0, 2, 0, DEFAULT) + +//GPIO3A +MUX_CFG(GPIO3A7_SDMMC0DATA3_NAME, GPIO3A, 14, 1, 0, DEFAULT) +MUX_CFG(GPIO3A6_SDMMC0DATA2_NAME, GPIO3A, 12, 1, 0, DEFAULT) +MUX_CFG(GPIO3A5_SDMMC0DATA1_NAME, GPIO3A, 10, 1, 0, DEFAULT) +MUX_CFG(GPIO3A4_SDMMC0DATA0_NAME, GPIO3A, 8, 1, 0, DEFAULT) +MUX_CFG(GPIO3A3_SDMMC0CMD_NAME, GPIO3A, 6, 1, 0, DEFAULT) +MUX_CFG(GPIO3A2_SDMMC0CLKOUT_NAME, GPIO3A, 4, 1, 0, DEFAULT) +MUX_CFG(GPIO3A1_SDMMC0PWREN_NAME, GPIO3A, 2, 1, 0, DEFAULT) +MUX_CFG(GPIO3A0_SDMMC0RSTNOUT_NAME, GPIO3A, 0, 1, 0, DEFAULT) + +//GPIO3B +MUX_CFG(GPIO3B7_CIFDATA11_I2C3SCL_NAME, GPIO3B, 14, 2, 0, DEFAULT) +MUX_CFG(GPIO3B6_CIFDATA10_I2C3SDA_NAME, GPIO3B, 12, 2, 0, DEFAULT) +MUX_CFG(GPIO3B5_CIFDATA1_HSADCDATA9_NAME, GPIO3B, 10, 2, 0, DEFAULT) +MUX_CFG(GPIO3B4_CIFDATA0_HSADCDATA8_NAME, GPIO3B, 8, 2, 0, DEFAULT) +MUX_CFG(GPIO3B3_CIFCLKOUT_NAME, GPIO3B, 6, 1, 0, DEFAULT) +MUX_CFG(GPIO3B1_SDMMC0WRITEPRT_NAME, GPIO3B, 2, 1, 0, DEFAULT) +MUX_CFG(GPIO3B0_SDMMC0DETECTN_NAME, GPIO3B, 0, 1, 0, DEFAULT) + +//GPIO3C +MUX_CFG(GPIO3C7_SDMMC1WRITEPRT_RMIICRS_NAME, GPIO3C, 14, 2, 0, DEFAULT) +MUX_CFG(GPIO3C6_SDMMC1DETECTN_RMIIRXERR_NAME, GPIO3C, 12, 2, 0, DEFAULT) +MUX_CFG(GPIO3C5_SDMMC1CLKOUT_RMIICLKOUT_RMIICLKIN_NAME, GPIO3C, 10, 2, 0, DEFAULT) +MUX_CFG(GPIO3C4_SDMMC1DATA3_RMIIRXD1_NAME, GPIO3C, 8, 2, 0, DEFAULT) +MUX_CFG(GPIO3C3_SDMMC1DATA2_RMIIRXD0_NAME, GPIO3C, 6, 2, 0, DEFAULT) +MUX_CFG(GPIO3C2_SDMMC1DATA1_RMIITXD0_NAME, GPIO3C, 4, 2, 0, DEFAULT) +MUX_CFG(GPIO3C1_SDMMC1DATA0_RMIITXD1_NAME, GPIO3C, 2, 2, 0, DEFAULT) +MUX_CFG(GPIO3C0_SDMMC1CMD_RMIITXEN_NAME, GPIO3C, 0, 2, 0, DEFAULT) + +//GPIO3D +MUX_CFG(GPIO3D6_PWM3_JTAGTMS_HOSTDRVVBUS_NAME, GPIO3D, 12, 2, 0, DEFAULT) +MUX_CFG(GPIO3D5_PWM2_JTAGTCK_OTGDRVVBUS_NAME, GPIO3D, 10, 2, 0, DEFAULT) +MUX_CFG(GPIO3D4_PWM1_JTAGTRSTN_NAME, GPIO3D, 8, 2, 0, DEFAULT) +MUX_CFG(GPIO3D3_PWM0_NAME, GPIO3D, 6, 1, 0, DEFAULT) +MUX_CFG(GPIO3D2_SDMMC1INTN_NAME, GPIO3D, 4, 1, 0, DEFAULT) +MUX_CFG(GPIO3D1_SDMMC1BACKENDPWR_MIIMDCLK_NAME, GPIO3D, 2, 2, 0, DEFAULT) +MUX_CFG(GPIO3D0_SDMMC1PWREN_MIIMD_NAME, GPIO3D, 0, 2, 0, DEFAULT) + #endif }; @@ -265,6 +403,8 @@ int __init rk30_iomux_init(void) rk30_mux_set(&rk30_muxs[i]); } +#if defined(CONFIG_ARCH_RK30) + #if defined(CONFIG_UART0_RK29) || (CONFIG_RK_DEBUG_UART == 0) rk30_mux_api_set(GPIO1A1_UART0SOUT_NAME, GPIO1A_UART0_SOUT); rk30_mux_api_set(GPIO1A0_UART0SIN_NAME, GPIO1A_UART0_SIN); @@ -347,6 +487,10 @@ int __init rk30_iomux_init(void) rk30_mux_api_set(GPIO1D1_CIF1HREF_MIIMDCLK_NAME, GPIO1D_MII_MDCLK); rk30_mux_api_set(GPIO1D0_CIF1VSYNC_MIIMD_NAME, GPIO1D_MII_MD); +#endif + +#elif defined(CONFIG_ARCH_RK31) + #endif return 0; diff --git a/drivers/media/video/rk30_camera.c b/drivers/media/video/rk30_camera.c index 3b4d3217518c..dba7ff4fbdd8 100644 --- a/drivers/media/video/rk30_camera.c +++ b/drivers/media/video/rk30_camera.c @@ -14,6 +14,7 @@ static int rk_sensor_iomux(int pin) { +#if defined(CONFIG_ARCH_RK30) switch (pin) { case RK30_PIN0_PA0: @@ -846,6 +847,7 @@ static int rk_sensor_iomux(int pin) break; } } +#endif return 0; } #define PMEM_CAM_BASE 0 //just for compile ,no meaning diff --git a/drivers/mmc/host/rk29_sdmmc.c b/drivers/mmc/host/rk29_sdmmc.c index 09eb4058d038..3f6f330ead0e 100755 --- a/drivers/mmc/host/rk29_sdmmc.c +++ b/drivers/mmc/host/rk29_sdmmc.c @@ -55,7 +55,7 @@ #define SD_DETECT_NAME GPIO2A2_SDMMC0DETECTN_NAME #define SD_DETECT_GPIO_MODE GPIO2L_GPIO2A2 #define SD_DETECT_DET_MODE GPIO2L_SDMMC0_DETECT_N -#elif defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) +#elif defined(CONFIG_ARCH_RK30) #define SD_DETECT_PIN RK30_PIN3_PB6 #define SD_DETECT_NAME GPIO3B6_SDMMC0DETECTN_NAME #define SD_DETECT_GPIO_MODE GPIO3B_GPIO3B6 @@ -65,6 +65,11 @@ #define SD_DETECT_NAME GPIO1C1_MMC0_DETN_NAME #define SD_DETECT_GPIO_MODE GPIO1C_GPIO1C1 #define SD_DETECT_DET_MODE GPIO1C_MMC0_DETN +#elif defined(CONFIG_ARCH_RK31) +#define SD_DETECT_PIN RK30_PIN3_PB0 +#define SD_DETECT_NAME GPIO3B0_SDMMC0DETECTN_NAME +#define SD_DETECT_GPIO_MODE GPIO3B_GPIO3B0 +#define SD_DETECT_DET_MODE GPIO3B_SDMMC0DETECTN #endif #define RK29_SDMMC_xbw_Debug 0 From afd099f45c57a72e9e2e46f6e62baaeaa6cf701d Mon Sep 17 00:00:00 2001 From: yzq Date: Thu, 9 Aug 2012 11:00:22 +0800 Subject: [PATCH 120/261] rk2928: hdmi driver work OK --- .../rockchip/hdmi/chips/rk2928/rk2928_hdmi.c | 18 +++---- .../hdmi/chips/rk2928/rk2928_hdmi_hw.c | 48 ++++++++++--------- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi.c b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi.c index 09b55b1c9d86..e3d4bcc5763d 100755 --- a/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi.c +++ b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi.c @@ -65,8 +65,8 @@ static void hdmi_early_suspend(struct early_suspend *h) flush_delayed_work(&hdmi->delay_work); // When HDMI 1.1V and 2.5V power off, DDC channel will be pull down, current is produced // from VCC_IO which is pull up outside soc. We need to switch DDC IO to GPIO. -// rk2928_mux_api_set(GPIO0A7_I2C3_SDA_HDMI_DDCSDA_NAME, GPIO0A_GPIO0A7); -// rk2928_mux_api_set(GPIO0A6_I2C3_SCL_HDMI_DDCSCL_NAME, GPIO0A_GPIO0A6); + rk30_mux_api_set(GPIO0A7_I2C3_SDA_HDMI_DDCSDA_NAME, GPIO0A_GPIO0A7); + rk30_mux_api_set(GPIO0A6_I2C3_SCL_HDMI_DDCSCL_NAME, GPIO0A_GPIO0A6); return; } @@ -75,8 +75,8 @@ static void hdmi_early_resume(struct early_suspend *h) hdmi_dbg(hdmi->dev, "hdmi exit early resume\n"); mutex_lock(&hdmi->enable_mutex); -// rk2928_mux_api_set(GPIO0A7_I2C3_SDA_HDMI_DDCSDA_NAME, GPIO0A_HDMI_DDCSDA); -// rk2928_mux_api_set(GPIO0A6_I2C3_SCL_HDMI_DDCSCL_NAME, GPIO0A_HDMI_DDCSCL); + rk30_mux_api_set(GPIO0A7_I2C3_SDA_HDMI_DDCSDA_NAME, GPIO0A_HDMI_DDCSDA); + rk30_mux_api_set(GPIO0A6_I2C3_SCL_HDMI_DDCSCL_NAME, GPIO0A_HDMI_DDCSCL); hdmi->suspend = 0; rk2928_hdmi_initial(); @@ -93,9 +93,9 @@ static inline void hdmi_io_remap(void) unsigned int value; // Remap HDMI IO Pin -// rk2928_mux_api_set(GPIO0A7_I2C3_SDA_HDMI_DDCSDA_NAME, GPIO0A_HDMI_DDCSDA); -// rk2928_mux_api_set(GPIO0A6_I2C3_SCL_HDMI_DDCSCL_NAME, GPIO0A_HDMI_DDCSCL); -// rk2928_mux_api_set(GPIO0B7_HDMI_HOTPLUGIN_NAME, GPIO0B_HDMI_HOTPLUGIN); + rk30_mux_api_set(GPIO0A7_I2C3_SDA_HDMI_DDCSDA_NAME, GPIO0A_HDMI_DDCSDA); + rk30_mux_api_set(GPIO0A6_I2C3_SCL_HDMI_DDCSCL_NAME, GPIO0A_HDMI_DDCSCL); + rk30_mux_api_set(GPIO0B7_HDMI_HOTPLUGIN_NAME, GPIO0B_HDMI_HOTPLUGIN); // Select LCDC0 as video source and enabled. // value = (HDMI_SOURCE_DEFAULT << 14) | (1 << 30); @@ -130,8 +130,8 @@ static int __devinit rk2928_hdmi_probe (struct platform_device *pdev) } hdmi->xscale = 95; hdmi->yscale = 95; -#if 0 - hdmi->hclk = clk_get(NULL,"hclk_hdmi"); +#if 1 + hdmi->hclk = clk_get(NULL,"pclk_hdmi"); if(IS_ERR(hdmi->hclk)) { dev_err(hdmi->dev, "Unable to get hdmi hclk\n"); diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.c b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.c index 4f6e636cc956..fb1c0686cbef 100755 --- a/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.c +++ b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.c @@ -33,17 +33,19 @@ static void rk2928_hdmi_sys_power_down(void) static void rk2928_hdmi_set_pwr_mode(int mode) { + int c=0; hdmi_dbg(hdmi->dev,"%s \n",__FUNCTION__); if(hdmi->pwr_mode == mode) - return; + return; switch(mode){ case NORMAL: rk2928_hdmi_sys_power_down(); - HDMIWrReg(0xe3, 0x82); - HDMIWrReg(0xe5, 0x00); - HDMIWrReg(0xe4, 0x00); - HDMIWrReg(0xe7, 0x00); - HDMIWrReg(0xe1, 0x8e); + HDMIWrReg(0xe0, 0x0a); + HDMIWrReg(0xe1, 0x03); + HDMIWrReg(0xe2, 0x99); + HDMIWrReg(0xe3, 0x0f); + HDMIWrReg(0xe4, 0x00); + HDMIWrReg(0xec, 0x02); HDMIWrReg(0xce, 0x00); HDMIWrReg(0xce, 0x01); rk2928_hdmi_av_mute(1); @@ -53,11 +55,12 @@ static void rk2928_hdmi_set_pwr_mode(int mode) case LOWER_PWR: rk2928_hdmi_av_mute(0); rk2928_hdmi_sys_power_down(); - HDMIWrReg(0xe3, 0x02); - HDMIWrReg(0xe5, 0x1c); - HDMIWrReg(0xe1, 0x8c); - HDMIWrReg(0xe7, 0x04); - HDMIWrReg(0xe4, 0x03); + HDMIWrReg(0xe0, 0x0a); + HDMIWrReg(0xe1, 0x03); + HDMIWrReg(0xe2, 0x99); + HDMIWrReg(0xe3, 0x0f); + HDMIWrReg(0xe4, 0x00); + HDMIWrReg(0xec, 0x02); break; default: hdmi_dbg(hdmi->dev,"unkown rk2928 hdmi pwr mode %d\n",mode); @@ -266,13 +269,6 @@ static int rk2928_hdmi_config_video(struct hdmi_video_para *vpara) else { hdmi_dbg(hdmi->dev, "[%s] sucess output DVI.\n", __FUNCTION__); } - // Power on TMDS - HDMIWrReg(PHY_PRE_EMPHASIS, v_PRE_EMPHASIS(0) | v_TMDS_PWRDOWN(0)); // TMDS power on - - // Enable TMDS - value = HDMIRdReg(PHY_DRIVER); - value |= v_TX_ENABLE(1); - HDMIWrReg(PHY_DRIVER, value); return 0; } @@ -412,8 +408,8 @@ irqreturn_t hdmi_irq(int irq, void *priv) interrupt1 = HDMIRdReg(INTERRUPT_STATUS1); HDMIWrReg(INTERRUPT_STATUS1, interrupt1); #if 1 - hdmi_dbg(hdmi->dev, "[%s] interrupt1 %02x interrupt2 %02x \n",\ - __FUNCTION__, interrupt1, interrupt2); + hdmi_dbg(hdmi->dev, "[%s] interrupt1 %02x \n",\ + __FUNCTION__, interrupt1); #endif if(interrupt1 & m_INT_HOTPLUG ){ if(hdmi->state == HDMI_SLEEP) @@ -435,6 +431,14 @@ irqreturn_t hdmi_irq(int irq, void *priv) return IRQ_HANDLED; } +static void rk2928_hdmi_reset(void) +{ + writel_relaxed(0x00010001,RK2928_CRU_BASE+ 0x128); + msleep(100); + writel_relaxed(0x00010000, RK2928_CRU_BASE + 0x128); + rk2928_hdmi_set_pwr_mode(NORMAL); +} + int rk2928_hdmi_initial(void) { int rc = HDMI_ERROR_SUCESS; @@ -446,8 +450,8 @@ int rk2928_hdmi_initial(void) hdmi->config_audio = rk2928_hdmi_config_audio; hdmi->detect_hotplug = rk2928_hdmi_detect_hotplug; hdmi->read_edid = rk2928_hdmi_read_edid; - // internal hclk = hdmi_hclk/20 - //HDMIWrReg(0x800, HDMI_INTERANL_CLK_DIV); + + rk2928_hdmi_reset(); if(hdmi->hdcp_power_on_cb) rc = hdmi->hdcp_power_on_cb(); From 864efa14152255e349744f2dcaaf4ac43ed936b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Thu, 9 Aug 2012 12:05:09 +0800 Subject: [PATCH 121/261] rk2928: add empty pmu.h, make driver happy --- arch/arm/mach-rk2928/include/mach/pmu.h | 40 +++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 arch/arm/mach-rk2928/include/mach/pmu.h diff --git a/arch/arm/mach-rk2928/include/mach/pmu.h b/arch/arm/mach-rk2928/include/mach/pmu.h new file mode 100644 index 000000000000..a57612280bc6 --- /dev/null +++ b/arch/arm/mach-rk2928/include/mach/pmu.h @@ -0,0 +1,40 @@ +#ifndef __MACH_PMU_H +#define __MACH_PMU_H + +enum pmu_power_domain { + PD_A9_0 = 0, + PD_A9_1, + PD_ALIVE, + PD_RTC, + PD_SCU, + PD_CPU, + PD_PERI = 6, + PD_VIO, + PD_VIDEO, + PD_VCODEC = PD_VIDEO, + PD_GPU, + PD_DBG, +}; + +static inline bool pmu_power_domain_is_on(enum pmu_power_domain pd) +{ + return true; +} + +static inline void pmu_set_power_domain(enum pmu_power_domain pd, bool on) +{ +} + +enum pmu_idle_req { + IDLE_REQ_CPU = 0, + IDLE_REQ_PERI, + IDLE_REQ_GPU, + IDLE_REQ_VIDEO, + IDLE_REQ_VIO, +}; + +static inline void pmu_set_idle_request(enum pmu_idle_req req, bool idle) +{ +} + +#endif From 1e24535f8e0ff147dc3928f8a764633cb6a8d114 Mon Sep 17 00:00:00 2001 From: chm Date: Thu, 9 Aug 2012 14:18:07 +0800 Subject: [PATCH 122/261] rk2928: modify vpu_service file for compile --- arch/arm/plat-rk/Kconfig | 2 +- arch/arm/plat-rk/include/plat/vpu_service.h | 2 +- arch/arm/plat-rk/vpu_service.c | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm/plat-rk/Kconfig b/arch/arm/plat-rk/Kconfig index 58e73499aea2..44e2df19011a 100644 --- a/arch/arm/plat-rk/Kconfig +++ b/arch/arm/plat-rk/Kconfig @@ -121,7 +121,7 @@ config WIFI_CONTROL_FUNC config RK29_VPU tristate "VPU (Video Processing Unit) service driver in kernel" - depends on ARCH_RK29 || ARCH_RK30 + depends on ARCH_RK29 || ARCH_RK30 || ARCH_RK2928 default m config RK29_LAST_LOG diff --git a/arch/arm/plat-rk/include/plat/vpu_service.h b/arch/arm/plat-rk/include/plat/vpu_service.h index 523c5dd72134..1ec121559670 100644 --- a/arch/arm/plat-rk/include/plat/vpu_service.h +++ b/arch/arm/plat-rk/include/plat/vpu_service.h @@ -39,7 +39,7 @@ #define VPU_REG_NUM_PP (41) // client type: decoder plus post-process:101 registers, size 404B #define VPU_REG_NUM_DEC_PP (VPU_REG_NUM_DEC+VPU_REG_NUM_PP) -#if defined(CONFIG_ARCH_RK29) +#if defined(CONFIG_ARCH_RK29) || defined(CONFIG_ARCH_RK2928) // client type: encoder only: 96 registers, size 384B for rk29 #define VPU_REG_NUM_ENC (96) #elif defined(CONFIG_ARCH_RK30) diff --git a/arch/arm/plat-rk/vpu_service.c b/arch/arm/plat-rk/vpu_service.c index f4c333f3fe6e..e254a9b71657 100644 --- a/arch/arm/plat-rk/vpu_service.c +++ b/arch/arm/plat-rk/vpu_service.c @@ -57,7 +57,7 @@ #define REG_NUM_DEC (60) #define REG_NUM_PP (41) -#if defined(CONFIG_ARCH_RK29) +#if defined(CONFIG_ARCH_RK29) || defined(CONFIG_ARCH_RK2928) #define REG_NUM_ENC (96) #elif defined(CONFIG_ARCH_RK30) #define REG_NUM_ENC (164) @@ -66,14 +66,14 @@ #define SIZE_REG(reg) ((reg)*4) #define DEC_IO_SIZE ((100 + 1) * 4) /* bytes */ -#if defined(CONFIG_ARCH_RK29) +#if defined(CONFIG_ARCH_RK29) || defined(CONFIG_ARCH_RK2928) #define ENC_IO_SIZE (96 * 4) /* bytes */ #elif defined(CONFIG_ARCH_RK30) #define ENC_IO_SIZE (164 * 4) /* bytes */ #endif #define REG_NUM_DEC_PP (REG_NUM_DEC+REG_NUM_PP) static const u16 dec_hw_ids[] = { 0x8190, 0x8170, 0x9170, 0x9190, 0x6731 }; -#if defined(CONFIG_ARCH_RK29) +#if defined(CONFIG_ARCH_RK29) || defined(CONFIG_ARCH_RK2928) static const u16 enc_hw_ids[] = { 0x6280, 0x7280, 0x8270 }; #define DEC_PHY_OFFSET 0x200 #elif defined(CONFIG_ARCH_RK30) @@ -290,7 +290,7 @@ static void vpu_service_power_off(void) } printk("vpu: power off..."); -#ifdef CONFIG_ARCH_RK29 +#if defined(CONFIG_ARCH_RK29) pmu_set_power_domain(PD_VCODEC, false); #else clk_disable(pd_video); @@ -334,7 +334,7 @@ static void vpu_service_power_on(void) clk_enable(hclk_vepu); clk_enable(hclk_cpu_vcodec); udelay(10); -#ifdef CONFIG_ARCH_RK29 +#if defined(CONFIG_ARCH_RK29) pmu_set_power_domain(PD_VCODEC, true); #else clk_enable(pd_video); From 79794223ea6b8e1f6d99e54aeb8074c3fb816e05 Mon Sep 17 00:00:00 2001 From: chm Date: Thu, 9 Aug 2012 14:25:13 +0800 Subject: [PATCH 123/261] rk2928: fix RK29_VCODEC_PHYS definition compile error --- arch/arm/plat-rk/vpu_service.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/plat-rk/vpu_service.c b/arch/arm/plat-rk/vpu_service.c index e254a9b71657..4d3ffc16a524 100644 --- a/arch/arm/plat-rk/vpu_service.c +++ b/arch/arm/plat-rk/vpu_service.c @@ -76,6 +76,9 @@ static const u16 dec_hw_ids[] = { 0x8190, 0x8170, 0x9170, 0x9190, 0x6731 }; #if defined(CONFIG_ARCH_RK29) || defined(CONFIG_ARCH_RK2928) static const u16 enc_hw_ids[] = { 0x6280, 0x7280, 0x8270 }; #define DEC_PHY_OFFSET 0x200 +#if defined(CONFIG_ARCH_RK2928) +#define RK29_VCODEC_PHYS RK2928_VCODEC_PHYS +#endif #elif defined(CONFIG_ARCH_RK30) static const u16 enc_hw_ids[] = { 0x6280, 0x7280, 0x8270, 0x8290, 0x4831 }; #define DEC_PHY_OFFSET 0x400 From 858af30eb268e68558ffcc25ecabd3d81c0fe7ab Mon Sep 17 00:00:00 2001 From: chm Date: Thu, 9 Aug 2012 15:36:59 +0800 Subject: [PATCH 124/261] rk2928: add vpu reset --- arch/arm/plat-rk/vpu_service.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/plat-rk/vpu_service.c b/arch/arm/plat-rk/vpu_service.c index 4d3ffc16a524..9782c76cef48 100644 --- a/arch/arm/plat-rk/vpu_service.c +++ b/arch/arm/plat-rk/vpu_service.c @@ -211,7 +211,7 @@ static void vpu_reset(void) cru_set_soft_reset(SOFT_RST_DDR_VCODEC_PORT, false); cru_set_soft_reset(SOFT_RST_CPU_VODEC_A2A_AHB, false); clk_enable(aclk_ddr_vepu); -#elif defined(CONFIG_ARCH_RK30) +#elif defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK2928) pmu_set_idle_request(IDLE_REQ_VIDEO, true); cru_set_soft_reset(SOFT_RST_CPU_VCODEC, true); cru_set_soft_reset(SOFT_RST_VCODEC_NIU_AXI, true); From 5df44a542d64fd3036910ceb0dd20de0df53e21c Mon Sep 17 00:00:00 2001 From: lw Date: Thu, 9 Aug 2012 16:27:14 +0800 Subject: [PATCH 125/261] phonepad:add suspend and resume voltage setting function --- arch/arm/mach-rk30/board-rk30-phonepad.c | 1 + drivers/regulator/rk30-pwm-regulator.c | 81 +++++++++++++++++++- include/linux/regulator/rk29-pwm-regulator.h | 1 + 3 files changed, 79 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-rk30/board-rk30-phonepad.c b/arch/arm/mach-rk30/board-rk30-phonepad.c index 8df5a38004ec..e4b2da4abd33 100755 --- a/arch/arm/mach-rk30/board-rk30-phonepad.c +++ b/arch/arm/mach-rk30/board-rk30-phonepad.c @@ -1550,6 +1550,7 @@ static struct pwm_platform_data pwm_regulator_info[1] = { .pwm_iomux_pwm = GPIO0D_PWM3, .pwm_iomux_gpio = GPIO0D_GPIO0D6, .pwm_voltage = 1100000, + .suspend_voltage = 1050000, .min_uV = 1000000, .max_uV = 1400000, .coefficient = 455, //45.5% diff --git a/drivers/regulator/rk30-pwm-regulator.c b/drivers/regulator/rk30-pwm-regulator.c index 7af504689ac5..f046b4496c0c 100755 --- a/drivers/regulator/rk30-pwm-regulator.c +++ b/drivers/regulator/rk30-pwm-regulator.c @@ -74,6 +74,7 @@ const static int pwm_voltage_map[] = { }; static struct clk *pwm_clk[2]; +static struct rk_pwm_dcdc *g_dcdc; static int pwm_set_rate(struct pwm_platform_data *pdata,int nHz,u32 rate) { @@ -270,6 +271,12 @@ static int __devinit pwm_regulator_probe(struct platform_device *pdev) if(!pdata->min_uV) pdata->min_uV = 1000000; + if(pdata->suspend_voltage < pdata->min_uV) + pdata->suspend_voltage = pdata->min_uV; + + if(pdata->suspend_voltage > pdata->max_uV) + pdata->suspend_voltage = pdata->max_uV; + dcdc = kzalloc(sizeof(struct rk_pwm_dcdc), GFP_KERNEL); if (dcdc == NULL) { dev_err(&pdev->dev, "Unable to allocate private data\n"); @@ -315,9 +322,9 @@ static int __devinit pwm_regulator_probe(struct platform_device *pdev) clk_enable(pwm_clk[1]); } #endif - - - platform_set_drvdata(pdev, dcdc); + + g_dcdc = dcdc; + platform_set_drvdata(pdev, dcdc); printk(KERN_INFO "pwm_regulator.%d: driver initialized\n",id); return 0; @@ -331,10 +338,73 @@ static int __devinit pwm_regulator_probe(struct platform_device *pdev) } +static int __sramdata g_PWM_REG_LRC = 0; +static int __sramdata g_PWM_REG_HRC = 0; +void pwm_suspend_voltage(void) +{ + struct rk_pwm_dcdc *dcdc = g_dcdc; + int suspend_voltage = 0; + int pwm_id = 0; + + if(!dcdc) + return; + pwm_id = dcdc->pdata->pwm_id; + suspend_voltage = dcdc->pdata->suspend_voltage; + + g_PWM_REG_LRC = pwm_read_reg(pwm_id, PWM_REG_LRC); + g_PWM_REG_HRC = pwm_read_reg(pwm_id,PWM_REG_HRC); + + switch(suspend_voltage) + { + case 1000000: + pwm_write_reg(pwm_id, PWM_REG_LRC, 0x25); + pwm_write_reg(pwm_id,PWM_REG_HRC,0x20); // 1 .00 + break; + + case 1050000: + pwm_write_reg(pwm_id, PWM_REG_LRC, 0x25); + pwm_write_reg(pwm_id,PWM_REG_HRC,0x1c); // 1 .05 + break; + + case 1100000: + pwm_write_reg(pwm_id, PWM_REG_LRC, 0x25); + pwm_write_reg(pwm_id,PWM_REG_HRC,0x18); // 1 .1 + break; + + case 1150000: + pwm_write_reg(pwm_id, PWM_REG_LRC, 0x25); + pwm_write_reg(pwm_id,PWM_REG_HRC,0x13); // 1 .15 + break; + + default: + pwm_write_reg(pwm_id, PWM_REG_LRC, 0x25); + pwm_write_reg(pwm_id,PWM_REG_HRC,0x20); // 1 .00 + break; + + } + +} + +void pwm_resume_voltage(void) + { + struct rk_pwm_dcdc *dcdc = g_dcdc; + int pwm_id = 0; + + if(!dcdc) + return; + pwm_id = dcdc->pdata->pwm_id; + pwm_write_reg(pwm_id, PWM_REG_LRC, g_PWM_REG_LRC); + pwm_write_reg(pwm_id,PWM_REG_HRC, g_PWM_REG_HRC); + +} + + static int pwm_regulator_suspend(struct platform_device *pdev, pm_message_t state) { struct pwm_platform_data *pdata = pdev->dev.platform_data; - pwm_set_rate(pdata,1000*1000,100);//pwm clk will change to 24M after suspend + //struct rk_pwm_dcdc *dcdc = platform_get_drvdata(pdev); + //unsigned selector = 0; + //pwm_regulator_set_voltage(dcdc->regulator, 1100000, 1100000, &selector); DBG("%s,pwm_id=%d\n",__func__,pdata->pwm_id); return 0; } @@ -342,6 +412,9 @@ static int pwm_regulator_suspend(struct platform_device *pdev, pm_message_t stat static int pwm_regulator_resume(struct platform_device *pdev) { struct pwm_platform_data *pdata = pdev->dev.platform_data; + //struct rk_pwm_dcdc *dcdc = platform_get_drvdata(pdev); + //unsigned selector = 0; + //pwm_regulator_set_voltage(dcdc->regulator, 1150000, 1150000, &selector); DBG("%s,pwm_id=%d\n",__func__,pdata->pwm_id); return 0; } diff --git a/include/linux/regulator/rk29-pwm-regulator.h b/include/linux/regulator/rk29-pwm-regulator.h index 70904dc447be..e74b812f73d3 100755 --- a/include/linux/regulator/rk29-pwm-regulator.h +++ b/include/linux/regulator/rk29-pwm-regulator.h @@ -57,6 +57,7 @@ struct pwm_platform_data { unsigned int pwm_iomux_pwm; int pwm_iomux_gpio; int pwm_voltage; + int suspend_voltage; int coefficient; int min_uV; int max_uV; From 0a75238e77ea92ec6ab256061ae16ab201a682b5 Mon Sep 17 00:00:00 2001 From: zsq Date: Thu, 9 Aug 2012 17:20:52 +0800 Subject: [PATCH 126/261] del rga soft reset && add use MMU hardware map --- drivers/video/rockchip/rga/rga_drv.c | 365 +++++++++++++++++++--- drivers/video/rockchip/rga/rga_mmu_info.c | 93 +++--- 2 files changed, 354 insertions(+), 104 deletions(-) diff --git a/drivers/video/rockchip/rga/rga_drv.c b/drivers/video/rockchip/rga/rga_drv.c index 06fdf674639e..507751400069 100755 --- a/drivers/video/rockchip/rga/rga_drv.c +++ b/drivers/video/rockchip/rga/rga_drv.c @@ -577,22 +577,19 @@ static void rga_try_set_reg(void) reg = list_entry(rga_service.waiting.next, struct rga_reg, status_link); rga_power_on(); - udelay(3); + udelay(1); rga_copy_reg(reg, 0); - rga_reg_from_wait_to_run(reg); + rga_reg_from_wait_to_run(reg); dmac_flush_range(&rga_service.cmd_buff[0], &rga_service.cmd_buff[28]); outer_flush_range(virt_to_phys(&rga_service.cmd_buff[0]),virt_to_phys(&rga_service.cmd_buff[28])); #if defined(CONFIG_ARCH_RK30) rga_soft_reset(); - #elif defined(CONFIG_ARCH_RK31) - rga_soft_reset(); #endif - rga_soft_reset(); - + rga_write(0x0, RGA_SYS_CTRL); rga_write(0, RGA_MMU_CTRL); /* CMD buff */ @@ -604,7 +601,7 @@ static void rga_try_set_reg(void) uint32_t i; uint32_t *p; p = rga_service.cmd_buff; - printk(KERN_DEBUG "CMD_REG\n"); + printk("CMD_REG\n"); for (i=0; i<7; i++) printk("%.8x %.8x %.8x %.8x\n", p[0 + i*4], p[1+i*4], p[2 + i*4], p[3 + i*4]); } @@ -622,17 +619,13 @@ static void rga_try_set_reg(void) #if RGA_TEST { uint32_t i; - printk(KERN_DEBUG "CMD_READ_BACK_REG\n"); + printk("CMD_READ_BACK_REG\n"); for (i=0; i<7; i++) - printk(KERN_DEBUG "%.8x %.8x %.8x %.8x\n", rga_read(0x100 + i*16 + 0), + printk("%.8x %.8x %.8x %.8x\n", rga_read(0x100 + i*16 + 0), rga_read(0x100 + i*16 + 4), rga_read(0x100 + i*16 + 8), rga_read(0x100 + i*16 + 12)); } #endif } -// else -// { -// rga_power_off(); -// } } } @@ -774,12 +767,10 @@ static int rga_blit(rga_session *session, struct rga_req *req) int ret = -1; int num = 0; struct rga_reg *reg; - struct rga_req *req2; + struct rga_req req2; uint32_t saw, sah, daw, dah; - req2 = NULL; - saw = req->src.act_w; sah = req->src.act_h; daw = req->dst.act_w; @@ -789,11 +780,7 @@ static int rga_blit(rga_session *session, struct rga_req *req) { if((req->render_mode == bitblt_mode) && (((saw>>1) >= daw) || ((sah>>1) >= dah))) { - /* generate 2 cmd for pre scale */ - req2 = kzalloc(sizeof(struct rga_req), GFP_KERNEL); - if(NULL == req2) { - return -EFAULT; - } + /* generate 2 cmd for pre scale */ ret = rga_check_param(req); if(ret == -EINVAL) { @@ -801,7 +788,7 @@ static int rga_blit(rga_session *session, struct rga_req *req) break; } - ret = RGA_gen_two_pro(req, req2); + ret = RGA_gen_two_pro(req, &req2); if(ret == -EINVAL) { break; } @@ -812,22 +799,18 @@ static int rga_blit(rga_session *session, struct rga_req *req) break; } - ret = rga_check_param(req2); + ret = rga_check_param(&req2); if(ret == -EINVAL) { printk("req 2 argument is inval\n"); break; } - reg = rga_reg_init_2(session, req, req2); + reg = rga_reg_init_2(session, req, &req2); if(reg == NULL) { break; } num = 2; - - if(NULL != req2) - { - kfree(req2); - } + } else { @@ -859,11 +842,6 @@ static int rga_blit(rga_session *session, struct rga_req *req) } while(0); - if(NULL != req2) - { - kfree(req2); - } - return -EFAULT; } @@ -973,7 +951,7 @@ static long rga_ioctl(struct file *file, uint32_t cmd, unsigned long arg) } else { - ret = rga_blit_async(session, req); + ret = rga_blit_sync(session, req); } break; case RGA_FLUSH: @@ -1104,8 +1082,6 @@ static int __devinit rga_drv_probe(struct platform_device *pdev) rga_service.last_prc_src_format = 1; /* default is yuv first*/ rga_service.enable = false; - printk("rga_drv_probe\n"); - data = kzalloc(sizeof(struct rga_drvdata), GFP_KERNEL); if(NULL == data) { @@ -1305,6 +1281,9 @@ void rga_test_0(void) struct rga_req req; rga_session session; unsigned int *src, *dst; + uint32_t i, j; + uint8_t *p; + uint8_t t; struct fb_info *fb; @@ -1325,11 +1304,12 @@ void rga_test_0(void) src = src_buf; dst = dst_buf; - memset(src_buf, 0xff, 320*240*4); + memset(src_buf, 0x80, 320*240*4); - dmac_flush_range(&src_buf[0], &src_buf[1920*1080]); - outer_flush_range(virt_to_phys(&src_buf[0]),virt_to_phys(&src_buf[1024*1024])); + dmac_flush_range(&src_buf[0], &src_buf[320*240]); + outer_flush_range(virt_to_phys(&src_buf[0]),virt_to_phys(&src_buf[320*240])); + #if 0 memset(src_buf, 0x80, 800*480*4); memset(dst_buf, 0xcc, 800*480*4); @@ -1343,7 +1323,7 @@ void rga_test_0(void) req.src.vir_w = 320; req.src.vir_h = 240; - req.src.yrgb_addr = (uint32_t)virt_to_phys(src); + req.src.yrgb_addr = (uint32_t)src; req.src.uv_addr = (uint32_t)virt_to_phys(src); req.src.v_addr = (uint32_t)virt_to_phys(src); req.src.format = 0; @@ -1355,7 +1335,7 @@ void rga_test_0(void) req.dst.vir_h = 768; req.dst.x_offset = 0; req.dst.y_offset = 0; - req.dst.yrgb_addr = (uint32_t)virt_to_phys(dst); + req.dst.yrgb_addr = (uint32_t)dst; //req.dst.format = RK_FORMAT_RGB_565; @@ -1370,22 +1350,311 @@ void rga_test_0(void) //req.rotate_mode = 1; //req.scale_mode = 2; - //req.alpha_rop_flag = 0; - //req.alpha_rop_mode = 0x1; + //req.alpha_rop_flag = 1; + //req.alpha_rop_mode = 0x19; + req.PD_mode = 3; req.sina = 0; req.cosa = 65536; - //req.mmu_info.mmu_flag = 0x21; - //req.mmu_info.mmu_en = 1; + req.mmu_info.mmu_flag = 0x21; + req.mmu_info.mmu_en = 1; rga_blit_sync(&session, &req); + dmac_inv_range(&dst_buf[0], &dst_buf[320*240]); + outer_inv_range(virt_to_phys(&dst_buf[0]),virt_to_phys(&dst_buf[320*240])); + + for(j=0; j<17; j++) + { + for(i=0; i<8; i++) + { + printk("%.8x, ", dst_buf[j*16 + i]); + } + printk("\n"); + + for(i=8; i<16; i++) + { + printk("%.8x, ", dst_buf[j*16 + i]); + } + printk("\n"); + } + + p = (uint8_t *)src_buf; + p = p + 16 * 4; + + for(i=0; i<16; i++) + src_buf[i] = 0; + + for(j=0; j<16; j++) + { + for(i=0; i<16; i++) + { + t = j*16 + i; + src_buf[(j+1)*16 + i] = (t<<24)|(t<<16)|(t<<8)|t; + } + } + + dmac_flush_range(&src_buf[0], &src_buf[320*240]); + outer_flush_range(virt_to_phys(&src_buf[0]),virt_to_phys(&src_buf[320*240])); + + dmac_inv_range(&src_buf[0], &src_buf[320*240]); + outer_inv_range(virt_to_phys(&src_buf[0]),virt_to_phys(&src_buf[320*240])); + + printk("SRC DATA \n"); + for(j=0; j<17; j++) + { + for(i=0; i<8; i++) + { + printk("%.8x, ", src_buf[j*16 + i]); + } + printk("\n"); + + for(i=8; i<16; i++) + { + printk("%.8x, ", src_buf[j*16 + i]); + } + printk("\n"); + } + + req.src.act_w = 320; + req.src.act_h = 240; + + req.src.vir_w = 320; + req.src.vir_h = 240; + req.src.yrgb_addr = (uint32_t)src; + req.src.uv_addr = (uint32_t)virt_to_phys(src); + req.src.v_addr = (uint32_t)virt_to_phys(src); + req.src.format = 0; + + req.dst.act_w = 320; + req.dst.act_h = 240; + + req.dst.vir_w = 1024; + req.dst.vir_h = 768; + req.dst.x_offset = 0; + req.dst.y_offset = 0; + req.dst.yrgb_addr = (uint32_t)(dst); + + //req.dst.format = RK_FORMAT_RGB_565; + + req.clip.xmin = 0; + req.clip.xmax = 1023; + req.clip.ymin = 0; + req.clip.ymax = 767; + + //req.render_mode = color_fill_mode; + //req.fg_color = 0x80ffffff; + + //req.rotate_mode = 1; + //req.scale_mode = 2; + + req.alpha_rop_flag = 0x19; + req.alpha_rop_mode = 0x1; + req.PD_mode = 3; + + req.sina = 0; + req.cosa = 65536; + + req.mmu_info.mmu_flag = 0x21; + req.mmu_info.mmu_en = 1; + + rga_blit_sync(&session, &req); + + dmac_inv_range(&dst_buf[0], &dst_buf[320*240]); + outer_inv_range(virt_to_phys(&dst_buf[0]),virt_to_phys(&dst_buf[320*240])); + + for(j=0; j<17; j++) + { + for(i=0; i<8; i++) + { + printk("%.8x, ", dst_buf[j*16 + i]); + } + printk("\n"); + for(i=8; i<16; i++) + { + printk("%.8x, ", dst_buf[j*16 + i]); + } + printk("\n"); + } + + memset(src_buf, 0x80, 320*240*4); + + dmac_flush_range(&src_buf[0], &src_buf[320*240]); + outer_flush_range(virt_to_phys(&src_buf[0]),virt_to_phys(&src_buf[320*240])); + + + #if 0 + memset(src_buf, 0x80, 800*480*4); + memset(dst_buf, 0xcc, 800*480*4); + + dmac_flush_range(&dst_buf[0], &dst_buf[800*480]); + outer_flush_range(virt_to_phys(&dst_buf[0]),virt_to_phys(&dst_buf[800*480])); + #endif + + req.src.act_w = 320; + req.src.act_h = 240; + + req.src.vir_w = 320; + req.src.vir_h = 240; + req.src.yrgb_addr = (uint32_t)(src); + req.src.uv_addr = (uint32_t)virt_to_phys(src); + req.src.v_addr = (uint32_t)virt_to_phys(src); + req.src.format = 0; + + req.dst.act_w = 320; + req.dst.act_h = 240; + + req.dst.vir_w = 1024; + req.dst.vir_h = 768; + req.dst.x_offset = 0; + req.dst.y_offset = 0; + req.dst.yrgb_addr = (uint32_t)(dst); + + //req.dst.format = RK_FORMAT_RGB_565; + + req.clip.xmin = 0; + req.clip.xmax = 1023; + req.clip.ymin = 0; + req.clip.ymax = 767; + + //req.render_mode = color_fill_mode; + //req.fg_color = 0x80ffffff; + + //req.rotate_mode = 1; + //req.scale_mode = 2; + + req.alpha_rop_flag = 0; + req.alpha_rop_mode = 0x0; + + req.sina = 0; + req.cosa = 65536; + + req.mmu_info.mmu_flag = 0x21; + req.mmu_info.mmu_en = 1; + + rga_blit_sync(&session, &req); + + dmac_inv_range(&dst_buf[0], &dst_buf[320*240]); + outer_inv_range(virt_to_phys(&dst_buf[0]),virt_to_phys(&dst_buf[320*240])); + + for(j=0; j<17; j++) + { + for(i=0; i<8; i++) + { + printk("%.8x, ", dst_buf[j*16 + i]); + } + printk("\n"); + + for(i=8; i<16; i++) + { + printk("%.8x, ", dst_buf[j*16 + i]); + } + printk("\n"); + } + + p = (uint8_t *)src_buf; + p = p + 16 * 4; + + for(i=0; i<16; i++) + src_buf[i] = 0; + + for(j=0; j<16; j++) + { + for(i=0; i<16; i++) + { + t = j*16 + i; + src_buf[(j+1)*16 + i] = (t<<24)|(t<<16)|(t<<8)|t; + } + } + + dmac_inv_range(&src_buf[0], &src_buf[320*240]); + outer_inv_range(virt_to_phys(&src_buf[0]),virt_to_phys(&src_buf[320*240])); + printk("SRC DATA \n"); + for(j=0; j<17; j++) + { + for(i=0; i<8; i++) + { + printk("%.8x, ", src_buf[j*16 + i]); + } + printk("\n"); + + for(i=8; i<16; i++) + { + printk("%.8x, ", src_buf[j*16 + i]); + } + printk("\n"); + } + + dmac_flush_range(&src_buf[0], &src_buf[320*240]); + outer_flush_range(virt_to_phys(&src_buf[0]),virt_to_phys(&src_buf[320*240])); + + req.src.act_w = 320; + req.src.act_h = 240; + + req.src.vir_w = 320; + req.src.vir_h = 240; + req.src.yrgb_addr = (uint32_t)(src); + req.src.uv_addr = (uint32_t)virt_to_phys(src); + req.src.v_addr = (uint32_t)virt_to_phys(src); + req.src.format = 0; + + req.dst.act_w = 320; + req.dst.act_h = 240; + + req.dst.vir_w = 1024; + req.dst.vir_h = 768; + req.dst.x_offset = 0; + req.dst.y_offset = 0; + req.dst.yrgb_addr = (uint32_t)(dst); + + //req.dst.format = RK_FORMAT_RGB_565; + + req.clip.xmin = 0; + req.clip.xmax = 1023; + req.clip.ymin = 0; + req.clip.ymax = 767; + + //req.render_mode = color_fill_mode; + //req.fg_color = 0x80ffffff; + + //req.rotate_mode = 1; + //req.scale_mode = 2; + + req.alpha_rop_flag = 0x19; + req.alpha_rop_mode = 0x1; + req.PD_mode = 3; + + req.sina = 0; + req.cosa = 65536; + + req.mmu_info.mmu_flag = 0x21; + req.mmu_info.mmu_en = 1; + + rga_blit_sync(&session, &req); + + dmac_inv_range(&dst_buf[0], &dst_buf[320*240]); + outer_inv_range(virt_to_phys(&dst_buf[0]),virt_to_phys(&dst_buf[320*240])); + + for(j=0; j<17; j++) + { + for(i=0; i<8; i++) + { + printk("%.8x, ", dst_buf[j*16 + i]); + } + printk("\n"); + for(i=8; i<16; i++) + { + printk("%.8x, ", dst_buf[j*16 + i]); + } + printk("\n"); + } + #if 1 fb->var.bits_per_pixel = 32; - fb->var.xres = 800; - fb->var.yres = 480; + fb->var.xres = 1024; + fb->var.yres = 768; fb->var.red.length = 8; fb->var.red.offset = 0; diff --git a/drivers/video/rockchip/rga/rga_mmu_info.c b/drivers/video/rockchip/rga/rga_mmu_info.c index 677e6d8d0c5b..212231e42408 100755 --- a/drivers/video/rockchip/rga/rga_mmu_info.c +++ b/drivers/video/rockchip/rga/rga_mmu_info.c @@ -24,8 +24,34 @@ extern rga_service_info rga_service; #define KERNEL_SPACE_VALID 0xc0000000 +#define V7_VATOPA_SUCESS_MASK (0x1) +#define V7_VATOPA_GET_PADDR(X) (X & 0xFFFFF000) +#define V7_VATOPA_GET_INER(X) ((X>>4) & 7) +#define V7_VATOPA_GET_OUTER(X) ((X>>2) & 3) +#define V7_VATOPA_GET_SH(X) ((X>>7) & 1) +#define V7_VATOPA_GET_NS(X) ((X>>9) & 1) +#define V7_VATOPA_GET_SS(X) ((X>>1) & 1) + + int mmu_flag = 0; +unsigned int armv7_va_to_pa(unsigned int v_addr) +{ + unsigned int p_addr; + __asm__ volatile ( "mcr p15, 0, %1, c7, c8, 0\n" + "isb\n" + "dsb\n" + "mrc p15, 0, %0, c7, c4, 0\n" + : "=r" (p_addr) + : "r" (v_addr) + : "cc"); + + if (p_addr & V7_VATOPA_SUCESS_MASK) + return 0xFFFFFFFF; + else + return (V7_VATOPA_GET_SS(p_addr) ? 0xFFFFFFFF : V7_VATOPA_GET_PADDR(p_addr)); +} + static int rga_mem_size_cal(uint32_t Mem, uint32_t MemSize, uint32_t *StartAddr) { uint32_t start, end; @@ -222,6 +248,7 @@ static int rga_MapUserMemory(struct page **pages, uint32_t i; uint32_t status; uint32_t Address; + uint32_t temp; status = 0; Address = 0; @@ -238,71 +265,25 @@ static int rga_MapUserMemory(struct page **pages, NULL ); up_read(¤t->mm->mmap_sem); - + if(result <= 0 || result < pageCount) { - struct vm_area_struct *vma; + status = 0; for(i=0; imm, (Memory + i) << PAGE_SHIFT); - - if (vma && (vma->vm_flags & VM_PFNMAP) ) - { - do - { - pte_t * pte; - spinlock_t * ptl; - unsigned long pfn; - pgd_t * pgd; - pud_t * pud; - - pgd = pgd_offset(current->mm, (Memory + i) << PAGE_SHIFT); - - if(pgd_val(*pgd) == 0) - { - printk("pgd value is zero \n"); - break; - } - - pud = pud_offset(pgd, (Memory + i) << PAGE_SHIFT); - if (pud) - { - pmd_t * pmd = pmd_offset(pud, (Memory + i) << PAGE_SHIFT); - if (pmd) - { - pte = pte_offset_map_lock(current->mm, pmd, (Memory + i) << PAGE_SHIFT, &ptl); - if (!pte) - { - break; - } - } - else - { - break; - } - } - else - { - break; - } - - pfn = pte_pfn(*pte); - Address = ((pfn << PAGE_SHIFT) | (((unsigned long)((Memory + i) << PAGE_SHIFT)) & ~PAGE_MASK)); - pte_unmap_unlock(pte, ptl); - } - while (0); - - pageTable[i] = Address; - } - else + { + temp = armv7_va_to_pa((Memory + i) << PAGE_SHIFT); + if (temp == 0xffffffff) { + printk("rga find mmu phy ddr error\n "); status = RGA_OUT_OF_RESOURCES; break; - } + } + + pageTable[i] = temp; } - return 0; + return status; } for (i = 0; i < pageCount; i++) From 90243aa8ca5ba59390dd1a418515b8eed4e92939 Mon Sep 17 00:00:00 2001 From: lw Date: Thu, 9 Aug 2012 17:35:21 +0800 Subject: [PATCH 127/261] phonepad:add CONFIG_RK30_I2C_INSRAM --- arch/arm/configs/rk30_phonepad_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/rk30_phonepad_defconfig b/arch/arm/configs/rk30_phonepad_defconfig index b2b8959c5206..76c29f1ca897 100755 --- a/arch/arm/configs/rk30_phonepad_defconfig +++ b/arch/arm/configs/rk30_phonepad_defconfig @@ -23,6 +23,7 @@ CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_ARCH_RK30=y CONFIG_CLK_SWITCH_TO_32K=y +CONFIG_RK30_I2C_INSRAM=y CONFIG_WIFI_CONTROL_FUNC=y CONFIG_MACH_RK30_PHONE_PAD=y # CONFIG_SWP_EMULATE is not set From 032cf430a741d44e2cb665438f558663c3b2cb55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E7=9B=9B=E9=A3=9E?= Date: Thu, 9 Aug 2012 17:39:00 +0800 Subject: [PATCH 128/261] rk30phonepad: step down the voltage of VDD_LOG --- arch/arm/mach-rk30/board-rk30-phonepad.c | 46 ++++++++++++++++++++++++ arch/arm/mach-rk30/include/mach/board.h | 7 ++++ arch/arm/mach-rk30/pm.c | 23 +++++++++--- 3 files changed, 72 insertions(+), 4 deletions(-) mode change 100755 => 100644 arch/arm/mach-rk30/board-rk30-phonepad.c mode change 100755 => 100644 arch/arm/mach-rk30/include/mach/board.h mode change 100755 => 100644 arch/arm/mach-rk30/pm.c diff --git a/arch/arm/mach-rk30/board-rk30-phonepad.c b/arch/arm/mach-rk30/board-rk30-phonepad.c old mode 100755 new mode 100644 index e4b2da4abd33..873249de77ec --- a/arch/arm/mach-rk30/board-rk30-phonepad.c +++ b/arch/arm/mach-rk30/board-rk30-phonepad.c @@ -1858,6 +1858,52 @@ void __sramfunc board_pmu_resume(void) #endif } + int __sramdata gpio0d7_iomux,gpio0d7_do,gpio0d7_dir,gpio0d7_en; + +void __sramfunc rk30_pwm_logic_suspend_voltage(void) +{ +#ifdef CONFIG_RK30_PWM_REGULATOR + +// int gpio0d7_iomux,gpio0d7_do,gpio0d7_dir,gpio0d7_en; + sram_udelay(10000); + gpio0d7_iomux = readl_relaxed(GRF_GPIO0D_IOMUX); + gpio0d7_do = grf_readl(GRF_GPIO0H_DO); + gpio0d7_dir = grf_readl(GRF_GPIO0H_DIR); + gpio0d7_en = grf_readl(GRF_GPIO0H_EN); + + writel_relaxed((1<<30), GRF_GPIO0D_IOMUX); + grf_writel((1<<31)|(1<<15), GRF_GPIO0H_DIR); + grf_writel((1<<31)|(1<<15), GRF_GPIO0H_DO); + grf_writel((1<<31)|(1<<15), GRF_GPIO0H_EN); +#endif +} +void __sramfunc rk30_pwm_logic_resume_voltage(void) +{ +#ifdef CONFIG_RK30_PWM_REGULATOR + writel_relaxed((1<<30)|gpio0d7_iomux, GRF_GPIO0D_IOMUX); + grf_writel((1<<31)|gpio0d7_en, GRF_GPIO0H_EN); + grf_writel((1<<31)|gpio0d7_dir, GRF_GPIO0H_DIR); + grf_writel((1<<31)|gpio0d7_do, GRF_GPIO0H_DO); + sram_udelay(10000); + +#endif + +} +extern void pwm_suspend_voltage(void); +extern void pwm_resume_voltage(void); +void rk30_pwm_suspend_voltage_set(void) +{ +#ifdef CONFIG_RK30_PWM_REGULATOR + pwm_suspend_voltage(); +#endif +} +void rk30_pwm_resume_voltage_set(void) +{ +#ifdef CONFIG_RK30_PWM_REGULATOR + pwm_resume_voltage(); +#endif +} + #ifdef CONFIG_I2C2_RK30 static struct i2c_board_info __initdata i2c2_info[] = { diff --git a/arch/arm/mach-rk30/include/mach/board.h b/arch/arm/mach-rk30/include/mach/board.h old mode 100755 new mode 100644 index 0db8c627c18a..d2a17e483efe --- a/arch/arm/mach-rk30/include/mach/board.h +++ b/arch/arm/mach-rk30/include/mach/board.h @@ -91,6 +91,13 @@ void board_gpio_resume(void); void __sramfunc board_pmu_suspend(void); void __sramfunc board_pmu_resume(void); +#ifdef CONFIG_RK30_PWM_REGULATOR +void rk30_pwm_suspend_voltage_set(void); +void rk30_pwm_resume_voltage_set(void); +void __sramfunc rk30_pwm_logic_suspend_voltage(void); + void __sramfunc rk30_pwm_logic_resume_voltage(void); +#endif + extern struct sys_timer rk30_timer; enum _periph_pll { diff --git a/arch/arm/mach-rk30/pm.c b/arch/arm/mach-rk30/pm.c old mode 100755 new mode 100644 index 95db9e08e4fa..464667b9e587 --- a/arch/arm/mach-rk30/pm.c +++ b/arch/arm/mach-rk30/pm.c @@ -341,6 +341,13 @@ __weak void __sramfunc board_pmu_suspend(void) {} __weak void __sramfunc board_pmu_resume(void) {} __weak void __sramfunc rk30_suspend_voltage_set(unsigned int vol){} __weak void __sramfunc rk30_suspend_voltage_resume(unsigned int vol){} + +__weak void rk30_pwm_suspend_voltage_set(void){} +__weak void rk30_pwm_resume_voltage_set(void){} + +__weak void __sramfunc rk30_pwm_logic_suspend_voltage(void){} +__weak void __sramfunc rk30_pwm_logic_resume_voltage(void){} + static void __sramfunc rk30_sram_suspend(void) { u32 cru_clksel0_con; @@ -352,6 +359,7 @@ static void __sramfunc rk30_sram_suspend(void) ddr_suspend(); sram_printch('6'); rk30_suspend_voltage_set(1000000); + rk30_pwm_logic_suspend_voltage(); sram_printch('7'); @@ -383,6 +391,7 @@ static void __sramfunc rk30_sram_suspend(void) | (1 << CLK_GATE_PCLK_GRF % 16) | (1 << CLK_GATE_PCLK_PMU % 16) , clkgt_regs[5], CRU_CLKGATES_CON(5), 0xffff); + gate_save_soc_clk(0 , clkgt_regs[7], CRU_CLKGATES_CON(7), 0xffff); gate_save_soc_clk(0 | (1 << CLK_GATE_CLK_L2C % 16) | (1 << CLK_GATE_ACLK_INTMEM0 % 16) @@ -420,7 +429,9 @@ static void __sramfunc rk30_sram_suspend(void) } sram_printch('7'); + rk30_pwm_logic_resume_voltage(); rk30_suspend_voltage_resume(1100000); + sram_printch('6'); ddr_resume(); sram_printch('5'); @@ -454,11 +465,11 @@ static int rk30_pm_enter(suspend_state_t state) pmu_pwrdn_st = pmu_readl(PMU_PWRDN_ST); rk30_pm_set_power_domain(pmu_pwrdn_st, false); - #ifdef CONFIG_DDR_TEST +#ifdef CONFIG_DDR_TEST // memory tester if (ddr_debug != 0) ddr_testmode(); - #endif + #endif sram_printch('1'); local_fiq_disable(); @@ -480,6 +491,7 @@ static int rk30_pm_enter(suspend_state_t state) gate_save_soc_clk(0 | (1 << CLK_GATE_PEIRPH_SRC % 16) | (1 << CLK_GATE_PCLK_PEIRPH % 16) + | (1 << CLK_GATE_ACLK_PEIRPH % 16) , clkgt_regs[2], CRU_CLKGATES_CON(2), 0xffff); gate_save_soc_clk(0, clkgt_regs[3], CRU_CLKGATES_CON(3), 0xff9f); gate_save_soc_clk(0 @@ -499,7 +511,9 @@ static int rk30_pm_enter(suspend_state_t state) | (1 << CLK_GATE_PCLK_DDRUPCTL % 16) , clkgt_regs[5], CRU_CLKGATES_CON(5), 0xffff); gate_save_soc_clk(0, clkgt_regs[6], CRU_CLKGATES_CON(6), 0xffff); - gate_save_soc_clk(0, clkgt_regs[7], CRU_CLKGATES_CON(7), 0xffff); + gate_save_soc_clk(0 + |(1 << CLK_GATE_PCLK_PWM23%16) + , clkgt_regs[7], CRU_CLKGATES_CON(7), 0xffff); gate_save_soc_clk(0 , clkgt_regs[8], CRU_CLKGATES_CON(8), 0x01ff); gate_save_soc_clk(0 | (1 << CLK_GATE_CLK_L2C % 16) @@ -544,6 +558,7 @@ static int rk30_pm_enter(suspend_state_t state) cru_writel(PLL_PWR_DN_W_MSK | PLL_PWR_DN, PLL_CONS(APLL_ID, 3)); sram_printch('3'); + rk30_pwm_suspend_voltage_set(); board_gpio_suspend(); @@ -554,7 +569,7 @@ static int rk30_pm_enter(suspend_state_t state) sram_printch('4'); board_gpio_resume(); - + rk30_pwm_resume_voltage_set(); sram_printch('3'); //apll From 426997197d3a971fee38e27f36eb6c8aab2b52a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=99=B4?= Date: Thu, 9 Aug 2012 18:07:51 +0800 Subject: [PATCH 129/261] rk2928:support pmic tps65910 --- arch/arm/configs/rk2928_sdk_defconfig | 7 +- arch/arm/mach-rk2928/board-rk2928-sdk.c | 18 + .../arm/mach-rk2928/board-rk30-sdk-tps65910.c | 633 ++++++++++++++++ drivers/gpio/Kconfig | 6 + drivers/gpio/Makefile | 3 +- drivers/gpio/gpio-tps65910.c | 118 +++ drivers/gpio/tps65910-gpio.c | 0 drivers/mfd/Kconfig | 52 +- drivers/mfd/Makefile | 5 + drivers/mfd/tps65910-irq.c | 30 +- drivers/mfd/tps65910.c | 168 ++++- drivers/mfd/tps65911-comparator.c | 0 drivers/regulator/Kconfig | 17 +- drivers/regulator/Makefile | 1 + drivers/regulator/tps65910-regulator.c | 592 +++++++++++---- drivers/rtc/Kconfig | 5 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-tps65910.c | 695 ++++++++++++++++++ include/linux/mfd/tps65910.h | 113 ++- 19 files changed, 2287 insertions(+), 177 deletions(-) create mode 100755 arch/arm/mach-rk2928/board-rk30-sdk-tps65910.c create mode 100755 drivers/gpio/gpio-tps65910.c mode change 100644 => 100755 drivers/gpio/tps65910-gpio.c mode change 100644 => 100755 drivers/mfd/tps65910-irq.c mode change 100644 => 100755 drivers/mfd/tps65910.c mode change 100644 => 100755 drivers/mfd/tps65911-comparator.c mode change 100644 => 100755 drivers/regulator/tps65910-regulator.c create mode 100755 drivers/rtc/rtc-tps65910.c mode change 100644 => 100755 include/linux/mfd/tps65910.h diff --git a/arch/arm/configs/rk2928_sdk_defconfig b/arch/arm/configs/rk2928_sdk_defconfig index 32ceab278ca3..32f9084f6244 100755 --- a/arch/arm/configs/rk2928_sdk_defconfig +++ b/arch/arm/configs/rk2928_sdk_defconfig @@ -247,9 +247,10 @@ CONFIG_SPI_FPGA_GPIO_IRQ_NUM=0 CONFIG_POWER_SUPPLY=y CONFIG_TEST_POWER=y # CONFIG_HWMON is not set -CONFIG_MFD_WM831X_I2C=y +CONFIG_MFD_TPS65910=y +CONFIG_MFD_TPS65090=y CONFIG_REGULATOR=y -CONFIG_REGULATOR_WM831X=y +CONFIG_REGULATOR_TPS65910=y CONFIG_MEDIA_SUPPORT=y CONFIG_VIDEO_DEV=y CONFIG_SOC_CAMERA=y @@ -359,7 +360,7 @@ CONFIG_SDMMC_RK29=y CONFIG_SWITCH=y CONFIG_SWITCH_GPIO=y CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_WM831X=y +CONFIG_TPS65910_RTC=y CONFIG_STAGING=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y diff --git a/arch/arm/mach-rk2928/board-rk2928-sdk.c b/arch/arm/mach-rk2928/board-rk2928-sdk.c index 06ac44d87620..604a79d7c685 100755 --- a/arch/arm/mach-rk2928/board-rk2928-sdk.c +++ b/arch/arm/mach-rk2928/board-rk2928-sdk.c @@ -44,6 +44,8 @@ #include #include #include +#include +#include #if defined(CONFIG_HDMI_RK30) #include "../../../drivers/video/rockchip/hdmi/rk_hdmi.h" #endif @@ -821,6 +823,7 @@ static struct platform_device device_ion = { }, }; #endif + /************************************************************************************************** * SDMMC devices, include the module of SD,MMC,and sdio.noted by xbw at 2012-03-05 **************************************************************************************************/ @@ -1075,7 +1078,22 @@ static struct i2c_board_info __initdata i2c0_info[] = { }; #endif #ifdef CONFIG_I2C1_RK30 +#ifdef CONFIG_MFD_TPS65910 +#define TPS65910_HOST_IRQ RK2928_PIN3_PC6 +#include "board-rk30-sdk-tps65910.c" +#endif static struct i2c_board_info __initdata i2c1_info[] = { + +#if defined (CONFIG_MFD_TPS65910) + { + .type = "tps65910", + .addr = TPS65910_I2C_ID0, + .flags = 0, + .irq = TPS65910_HOST_IRQ, + .platform_data = &tps65910_data, + }, +#endif + }; #endif #ifdef CONFIG_I2C2_RK30 diff --git a/arch/arm/mach-rk2928/board-rk30-sdk-tps65910.c b/arch/arm/mach-rk2928/board-rk30-sdk-tps65910.c new file mode 100755 index 000000000000..7ec12c302a3a --- /dev/null +++ b/arch/arm/mach-rk2928/board-rk30-sdk-tps65910.c @@ -0,0 +1,633 @@ +#include +#include +#include +#include +#include + +#include +#include + +#define grf_readl(offset) readl_relaxed(RK30_GRF_BASE + offset) +#define grf_writel(v, offset) do { writel_relaxed(v, RK30_GRF_BASE + offset); dsb(); } while (0) + +#define CRU_CLKGATE5_CON_ADDR 0x00e4 +#define GRF_GPIO6L_DIR_ADDR 0x0030 +#define GRF_GPIO6L_DO_ADDR 0x0068 +#define GRF_GPIO6L_EN_ADDR 0x00a0 +#define GPIO6_PB3_DIR_OUT 0x08000800 +#define GPIO6_PB3_DO_LOW 0x08000000 +#define GPIO6_PB3_DO_HIGH 0x08000800 +#define GPIO6_PB3_EN_MASK 0x08000800 +#define GPIO6_PB3_UNEN_MASK 0x08000000 +#define GPIO6_PB1_DIR_OUT 0x02000200 +#define GPIO6_PB1_DO_LOW 0x02000000 +#define GPIO6_PB1_DO_HIGH 0x02000200 +#define GPIO6_PB1_EN_MASK 0x02000200 +#define GPIO6_PB1_UNEN_MASK 0x02000000 + +#ifdef CONFIG_MFD_TPS65910 +#define PMU_POWER_SLEEP RK2928_PIN3_PD2 +extern int platform_device_register(struct platform_device *pdev); + +int tps65910_pre_init(struct tps65910 *tps65910){ + + int val = 0; + int i = 0; + int err = -1; + + printk("%s,line=%d\n", __func__,__LINE__); + gpio_request(PMU_POWER_SLEEP, "NULL"); + gpio_direction_output(PMU_POWER_SLEEP, GPIO_LOW); + + val = tps65910_reg_read(tps65910, TPS65910_DEVCTRL2); + if (val<0) { + printk(KERN_ERR "Unable to read TPS65910_DEVCTRL2 reg\n"); + return val; + } + /* Set sleep state active high and allow device turn-off after PWRON long press */ + val |= (DEVCTRL2_SLEEPSIG_POL_MASK | DEVCTRL2_PWON_LP_OFF_MASK); + + err = tps65910_reg_write(tps65910, TPS65910_DEVCTRL2, val); + if (err) { + printk(KERN_ERR "Unable to write TPS65910_DEVCTRL2 reg\n"); + return err; + } + #if 1 + /* set PSKIP=0 */ + val = tps65910_reg_read(tps65910, TPS65910_DCDCCTRL); + if (val<0) { + printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n"); + return val; + } + + val &= ~DEVCTRL_DEV_OFF_MASK; + val &= ~DEVCTRL_DEV_SLP_MASK; + err = tps65910_reg_write(tps65910, TPS65910_DCDCCTRL, val); + if (err) { + printk(KERN_ERR "Unable to write TPS65910_DCDCCTRL reg\n"); + return err; + } + #endif + /* Set the maxinum load current */ + /* VDD1 */ + val = tps65910_reg_read(tps65910, TPS65910_VDD1); + if (val<0) { + printk(KERN_ERR "Unable to read TPS65910_VDD1 reg\n"); + return val; + } + + val |= (1<<5); //when 1: 1.5 A + val |= (0x07<<2); //TSTEP[2:0] = 111 : 2.5 mV/|ìs(sampling 3 Mhz/5) + err = tps65910_reg_write(tps65910, TPS65910_VDD1, val); + if (err) { + printk(KERN_ERR "Unable to write TPS65910_VDD1 reg\n"); + return err; + } + + /* VDD2 */ + val = tps65910_reg_read(tps65910, TPS65910_VDD2); + if (val<0) { + printk(KERN_ERR "Unable to read TPS65910_VDD2 reg\n"); + return val; + } + + val |= (1<<5); //when 1: 1.5 A + err = tps65910_reg_write(tps65910, TPS65910_VDD2, val); + if (err) { + printk(KERN_ERR "Unable to write TPS65910_VDD2 reg\n"); + return err; + } + + /* VIO */ + val = tps65910_reg_read(tps65910, TPS65910_VIO); + if (val<0) { + printk(KERN_ERR "Unable to read TPS65910_VIO reg\n"); + return -EIO; + } + + val |= (1<<6); //when 01: 1.0 A + err = tps65910_reg_write(tps65910, TPS65910_VIO, val); + if (err) { + printk(KERN_ERR "Unable to write TPS65910_VIO reg\n"); + return err; + } + #if 1 + /* Mask ALL interrupts */ + err = tps65910_reg_write(tps65910,TPS65910_INT_MSK, 0xFF); + if (err) { + printk(KERN_ERR "Unable to write TPS65910_INT_MSK reg\n"); + return err; + } + + err = tps65910_reg_write(tps65910, TPS65910_INT_MSK2, 0x03); + if (err) { + printk(KERN_ERR "Unable to write TPS65910_INT_MSK2 reg\n"); + return err; + } + + /* Set RTC Power, disable Smart Reflex in DEVCTRL_REG */ + #if 1 + val = 0; + val |= (DEVCTRL_SR_CTL_I2C_SEL_MASK); + err = tps65910_reg_write(tps65910, TPS65910_DEVCTRL, val); + if (err) { + printk(KERN_ERR "Unable to write TPS65910_DEVCTRL reg\n"); + return err; + } + printk(KERN_INFO "TPS65910 Set default voltage.\n"); + #endif + #if 0 + //read sleep control register for debug + for(i=0; i<6; i++) + { + err = tps65910_reg_read(tps65910, &val, TPS65910_DEVCTRL+i); + if (err) { + printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n"); + return -EIO; + } + else + printk("%s.......is 0x%04x\n",__FUNCTION__,val); + } + #endif + + #if 1 + //sleep control register + /*set func when in sleep mode */ + val = tps65910_reg_read(tps65910, TPS65910_DEVCTRL); + if (val<0) { + printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n"); + return val; + } + + val |= (1 << 1); + err = tps65910_reg_write(tps65910, TPS65910_DEVCTRL, val); + if (err) { + printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \ + \n", TPS65910_VDIG1); + return err; + } + + /* open ldo when in sleep mode */ + val = tps65910_reg_read(tps65910, TPS65910_SLEEP_KEEP_LDO_ON); + if (val<0) { + printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n"); + return val; + } + + val &= 0; + err = tps65910_reg_write(tps65910, TPS65910_SLEEP_KEEP_LDO_ON, val); + if (err) { + printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \ + \n", TPS65910_VDIG1); + return err; + } + + /*set dc mode when in sleep mode */ + val = tps65910_reg_read(tps65910, TPS65910_SLEEP_KEEP_RES_ON); + if (val<0) { + printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n"); + return val; + } + + val |= 0xff; + err = tps65910_reg_write(tps65910, TPS65910_SLEEP_KEEP_RES_ON, val); + if (err) { + printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \ + \n", TPS65910_VDIG1); + return err; + } + + /*close ldo when in sleep mode */ + val = tps65910_reg_read(tps65910, TPS65910_SLEEP_SET_LDO_OFF); + if (val<0) { + printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n"); + return val; + } + + val |= 0x9B; + err = tps65910_reg_write(tps65910, TPS65910_SLEEP_SET_LDO_OFF, val); + if (err) { + printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \ + \n", TPS65910_VDIG1); + return err; + } + + #endif + #if 0 + //read sleep control register for debug + for(i=0; i<6; i++) + { + err = tps65910_reg_read(tps65910, &val, TPS65910_DEVCTRL+i); + if (err) { + printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n"); + return -EIO; + } + else + printk("%s.......is 0x%4x\n",__FUNCTION__,val); + } + #endif + #endif + + printk("%s,line=%d\n", __func__,__LINE__); + return 0; + +} +int tps65910_post_init(struct tps65910 *tps65910) +{ + struct regulator *dcdc; + struct regulator *ldo; + printk("%s,line=%d\n", __func__,__LINE__); + + dcdc = regulator_get(NULL, "vio"); //vcc_io + regulator_set_voltage(dcdc, 3300000, 3300000); + regulator_enable(dcdc); + printk("%s set vio vcc_io=%dmV end\n", __func__, regulator_get_voltage(dcdc)); + regulator_put(dcdc); + udelay(100); + + ldo = regulator_get(NULL, "vpll"); // vcc25 + regulator_set_voltage(ldo, 2500000, 2500000); + regulator_enable(ldo); + printk("%s set vpll vcc25=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "vdig2"); // vdd11 + regulator_set_voltage(ldo, 1200000, 1200000); + regulator_enable(ldo); + printk("%s set vdig2 vdd11=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "vaux33"); //vcc_tp + regulator_set_voltage(ldo, 3300000, 3300000); + regulator_enable(ldo); + printk("%s set vaux33 vcc_tp=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + dcdc = regulator_get(NULL, "vdd_cpu"); //vdd_cpu + regulator_set_voltage(dcdc, 1200000, 1200000); + regulator_enable(dcdc); + printk("%s set vdd1 vdd_cpu=%dmV end\n", __func__, regulator_get_voltage(dcdc)); + regulator_put(dcdc); + udelay(100); + + dcdc = regulator_get(NULL, "vdd2"); //vcc_ddr + regulator_set_voltage(dcdc, 1200000, 1200000); // 1.5*4/5 = 1.2 and Vout=1.5v + regulator_enable(dcdc); + printk("%s set vdd2 vcc_ddr=%dmV end\n", __func__, regulator_get_voltage(dcdc)); + regulator_put(dcdc); + udelay(100); + + ldo = regulator_get(NULL, "vdig1"); //vcc18_cif + regulator_set_voltage(ldo, 1800000, 1800000); + regulator_enable(ldo); + printk("%s set vdig1 vcc18_cif=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + dcdc = regulator_get(NULL, "vaux1"); //vcc25_hdmi + regulator_set_voltage(dcdc,2500000,2500000); + regulator_enable(dcdc); + printk("%s set vaux1 vcc25_hdmi=%dmV end\n", __func__, regulator_get_voltage(dcdc)); + regulator_put(dcdc); + udelay(100); + + ldo = regulator_get(NULL, "vaux2"); //vcca33 + regulator_set_voltage(ldo, 3300000, 3300000); + regulator_enable(ldo); + printk("%s set vaux2 vcca33=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "vdac"); // vccio_wl + regulator_set_voltage(ldo,1800000,1800000); + regulator_enable(ldo); + printk("%s set vdac vccio_wl=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "vmmc"); //vcc28_cif + regulator_set_voltage(ldo,2800000,2800000); + regulator_enable(ldo); + printk("%s set vmmc vcc28_cif=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + #ifdef CONFIG_RK30_PWM_REGULATOR + dcdc = regulator_get(NULL, "vdd_core"); // vdd_log + regulator_set_voltage(dcdc, 1100000, 1100000); + regulator_enable(dcdc); + printk("%s set vdd_core=%dmV end\n", __func__, regulator_get_voltage(dcdc)); + regulator_put(dcdc); + udelay(100); + #endif + + printk("%s,line=%d END\n", __func__,__LINE__); + + return 0; +} + +static struct regulator_consumer_supply tps65910_smps1_supply[] = { + { + .supply = "vdd1", + }, + { + .supply = "vdd_cpu", + }, +}; +static struct regulator_consumer_supply tps65910_smps2_supply[] = { + { + .supply = "vdd2", + }, + +}; +static struct regulator_consumer_supply tps65910_smps3_supply[] = { + { + .supply = "vdd3", + }, +}; +static struct regulator_consumer_supply tps65910_smps4_supply[] = { + { + .supply = "vio", + }, +}; +static struct regulator_consumer_supply tps65910_ldo1_supply[] = { + { + .supply = "vdig1", + }, +}; +static struct regulator_consumer_supply tps65910_ldo2_supply[] = { + { + .supply = "vdig2", + }, +}; + +static struct regulator_consumer_supply tps65910_ldo3_supply[] = { + { + .supply = "vaux1", + }, +}; +static struct regulator_consumer_supply tps65910_ldo4_supply[] = { + { + .supply = "vaux2", + }, +}; +static struct regulator_consumer_supply tps65910_ldo5_supply[] = { + { + .supply = "vaux33", + }, +}; +static struct regulator_consumer_supply tps65910_ldo6_supply[] = { + { + .supply = "vmmc", + }, +}; +static struct regulator_consumer_supply tps65910_ldo7_supply[] = { + { + .supply = "vdac", + }, +}; + +static struct regulator_consumer_supply tps65910_ldo8_supply[] = { + { + .supply = "vpll", + }, +}; + +static struct regulator_init_data tps65910_smps1 = { + .constraints = { + .name = "VDD1", + .min_uV = 600000, + .max_uV = 1500000, + .apply_uV = 1, + .always_on = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + + }, + .num_consumer_supplies = ARRAY_SIZE(tps65910_smps1_supply), + .consumer_supplies = tps65910_smps1_supply, +}; + +/* */ +static struct regulator_init_data tps65910_smps2 = { + .constraints = { + .name = "VDD2", + .min_uV = 600000, + .max_uV = 1500000, + .apply_uV = 1, + .always_on = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + + }, + .num_consumer_supplies = ARRAY_SIZE(tps65910_smps2_supply), + .consumer_supplies = tps65910_smps2_supply, +}; + +/* */ +static struct regulator_init_data tps65910_smps3 = { + .constraints = { + .name = "VDD3", + .min_uV = 1000000, + .max_uV = 1400000, + .apply_uV = 1, + .always_on = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + + }, + .num_consumer_supplies = ARRAY_SIZE(tps65910_smps3_supply), + .consumer_supplies = tps65910_smps3_supply, +}; + +static struct regulator_init_data tps65910_smps4 = { + .constraints = { + .name = "VIO", + .min_uV = 1800000, + .max_uV = 3300000, + .apply_uV = 1, + .always_on = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + + }, + .num_consumer_supplies = ARRAY_SIZE(tps65910_smps4_supply), + .consumer_supplies = tps65910_smps4_supply, +}; +static struct regulator_init_data tps65910_ldo1 = { + .constraints = { + .name = "VDIG1", + .min_uV = 1200000, + .max_uV = 2700000, + .apply_uV = 1, + + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + + }, + .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo1_supply), + .consumer_supplies = tps65910_ldo1_supply, +}; + +/* */ +static struct regulator_init_data tps65910_ldo2 = { + .constraints = { + .name = "VDIG2", + .min_uV = 1000000, + .max_uV = 1800000, + .apply_uV = 1, + + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + + }, + .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo2_supply), + .consumer_supplies = tps65910_ldo2_supply, +}; + +/* */ +static struct regulator_init_data tps65910_ldo3 = { + .constraints = { + .name = "VAUX1", + .min_uV = 1800000, + .max_uV = 3300000, + .apply_uV = 1, + + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + + }, + .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo3_supply), + .consumer_supplies = tps65910_ldo3_supply, +}; + +/* */ +static struct regulator_init_data tps65910_ldo4 = { + .constraints = { + .name = "VAUX2", + .min_uV = 1800000, + .max_uV = 3300000, + .apply_uV = 1, + + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + + }, + .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo4_supply), + .consumer_supplies = tps65910_ldo4_supply, +}; + +/* */ +static struct regulator_init_data tps65910_ldo5 = { + .constraints = { + .name = "VAUX33", + .min_uV = 1800000, + .max_uV = 3300000, + .apply_uV = 1, + + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + + }, + .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo5_supply), + .consumer_supplies = tps65910_ldo5_supply, +}; + +/* */ +static struct regulator_init_data tps65910_ldo6 = { + .constraints = { + .name = "VMMC", + .min_uV = 1800000, + .max_uV = 3300000, + .apply_uV = 1, + + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + + }, + .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo6_supply), + .consumer_supplies = tps65910_ldo6_supply, +}; + +/* */ +static struct regulator_init_data tps65910_ldo7 = { + .constraints = { + .name = "VDAC", + .min_uV = 1800000, + .max_uV = 2850000, + .apply_uV = 1, + + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + + }, + .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo7_supply), + .consumer_supplies = tps65910_ldo7_supply, +}; + +/* */ +static struct regulator_init_data tps65910_ldo8 = { + .constraints = { + .name = "VPLL", + .min_uV = 1000000, + .max_uV = 2500000, + .apply_uV = 1, + .always_on = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + + }, + .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo8_supply), + .consumer_supplies = tps65910_ldo8_supply, +}; +/* +void __sramfunc board_pmu_tps65910_suspend(void) +{ + grf_writel(GPIO6_PB1_DIR_OUT, GRF_GPIO6L_DIR_ADDR); + grf_writel(GPIO6_PB1_DO_HIGH, GRF_GPIO6L_DO_ADDR); //set gpio6_b1 output low + grf_writel(GPIO6_PB1_EN_MASK, GRF_GPIO6L_EN_ADDR); +} +void __sramfunc board_pmu_tps65910_resume(void) +{ + grf_writel(GPIO6_PB1_DIR_OUT, GRF_GPIO6L_DIR_ADDR); + grf_writel(GPIO6_PB1_DO_LOW, GRF_GPIO6L_DO_ADDR); //set gpio6_b1 output low + grf_writel(GPIO6_PB1_EN_MASK, GRF_GPIO6L_EN_ADDR); + #ifdef CONFIG_CLK_SWITCH_TO_32K //switch clk to 24M + sram_32k_udelay(10000); + #else + sram_udelay(2000); + #endif +} +*/ +static struct tps65910_board tps65910_data = { + .irq = (unsigned)TPS65910_HOST_IRQ, + .irq_base = NR_GIC_IRQS + NR_GPIO_IRQS, +// .gpio_base = TPS65910_GPIO_EXPANDER_BASE, + + .pre_init = tps65910_pre_init, + .post_init = tps65910_post_init, + + //TPS65910_NUM_REGS = 13 + // Regulators + .tps65910_pmic_init_data[TPS65910_REG_VRTC] = NULL, + .tps65910_pmic_init_data[TPS65910_REG_VIO] = &tps65910_smps4, + .tps65910_pmic_init_data[TPS65910_REG_VDD1] = &tps65910_smps1, + .tps65910_pmic_init_data[TPS65910_REG_VDD2] = &tps65910_smps2, + .tps65910_pmic_init_data[TPS65910_REG_VDD3] = &tps65910_smps3, + .tps65910_pmic_init_data[TPS65910_REG_VDIG1] = &tps65910_ldo1, + .tps65910_pmic_init_data[TPS65910_REG_VDIG2] = &tps65910_ldo2, + .tps65910_pmic_init_data[TPS65910_REG_VPLL] = &tps65910_ldo8, + .tps65910_pmic_init_data[TPS65910_REG_VDAC] = &tps65910_ldo7, + .tps65910_pmic_init_data[TPS65910_REG_VAUX1] = &tps65910_ldo3, + .tps65910_pmic_init_data[TPS65910_REG_VAUX2] = &tps65910_ldo4, + .tps65910_pmic_init_data[TPS65910_REG_VAUX33] = &tps65910_ldo5, + .tps65910_pmic_init_data[TPS65910_REG_VMMC] = &tps65910_ldo6, + + +}; + +#endif + diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 3b8f6043bf0c..9876d32c8173 100755 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -261,6 +261,12 @@ config GPIO_TC3589X This enables support for the GPIOs found on the TC3589X I/O Expander. +config GPIO_TPS65912 + tristate "TI TPS65912 GPIO" + depends on (MFD_TPS65912_I2C || MFD_TPS65912_SPI) + help + This driver supports TPS65912 gpio chip + config GPIO_TWL4030 tristate "TWL4030, TWL5030, and TPS659x0 GPIOs" depends on TWL4030_CORE diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 46508ae87340..9a470d2235f7 100755 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -54,4 +54,5 @@ obj-$(CONFIG_GPIO_SX150X) += sx150x.o obj-$(CONFIG_GPIO_VX855) += vx855_gpio.o obj-$(CONFIG_GPIO_ML_IOH) += ml_ioh_gpio.o obj-$(CONFIG_AB8500_GPIO) += ab8500-gpio.o -obj-$(CONFIG_GPIO_TPS65910) += tps65910-gpio.o +obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o +obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c new file mode 100755 index 000000000000..7eef648a3351 --- /dev/null +++ b/drivers/gpio/gpio-tps65910.c @@ -0,0 +1,118 @@ +/* + * TI TPS6591x GPIO driver + * + * Copyright 2010 Texas Instruments Inc. + * + * Author: Graeme Gregory + * Author: Jorge Eduardo Candelaria jedu@slimlogic.co.uk> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include + +static int tps65910_gpio_get(struct gpio_chip *gc, unsigned offset) +{ + struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio); + uint8_t val; + + tps65910->read(tps65910, TPS65910_GPIO0 + offset, 1, &val); + + if (val & GPIO_STS_MASK) + return 1; + + return 0; +} + +static void tps65910_gpio_set(struct gpio_chip *gc, unsigned offset, + int value) +{ + struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio); + + if (value) + tps65910_set_bits(tps65910, TPS65910_GPIO0 + offset, + GPIO_SET_MASK); + else + tps65910_clear_bits(tps65910, TPS65910_GPIO0 + offset, + GPIO_SET_MASK); +} + +static int tps65910_gpio_output(struct gpio_chip *gc, unsigned offset, + int value) +{ + struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio); + + /* Set the initial value */ + tps65910_gpio_set(gc, offset, value); + + return tps65910_set_bits(tps65910, TPS65910_GPIO0 + offset, + GPIO_CFG_MASK); +} + +static int tps65910_gpio_input(struct gpio_chip *gc, unsigned offset) +{ + struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio); + + return tps65910_clear_bits(tps65910, TPS65910_GPIO0 + offset, + GPIO_CFG_MASK); +} + +void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base) +{ + int ret; + struct tps65910_board *board_data; + + if (!gpio_base) + return; + + tps65910->gpio.owner = THIS_MODULE; + tps65910->gpio.label = tps65910->i2c_client->name; + tps65910->gpio.dev = tps65910->dev; + tps65910->gpio.base = gpio_base; + + switch(tps65910_chip_id(tps65910)) { + case TPS65910: + tps65910->gpio.ngpio = TPS65910_NUM_GPIO; + break; + case TPS65911: + tps65910->gpio.ngpio = TPS65911_NUM_GPIO; + break; + default: + return; + } + tps65910->gpio.can_sleep = 1; + + tps65910->gpio.direction_input = tps65910_gpio_input; + tps65910->gpio.direction_output = tps65910_gpio_output; + tps65910->gpio.set = tps65910_gpio_set; + tps65910->gpio.get = tps65910_gpio_get; + + /* Configure sleep control for gpios */ + board_data = dev_get_platdata(tps65910->dev); + if (board_data) { + int i; + for (i = 0; i < tps65910->gpio.ngpio; ++i) { + if (board_data->en_gpio_sleep[i]) { + ret = tps65910_set_bits(tps65910, + TPS65910_GPIO0 + i, GPIO_SLEEP_MASK); + if (ret < 0) + dev_warn(tps65910->dev, + "GPIO Sleep setting failed\n"); + } + } + } + + ret = gpiochip_add(&tps65910->gpio); + + if (ret) + dev_warn(tps65910->dev, "GPIO registration failed: %d\n", ret); +} diff --git a/drivers/gpio/tps65910-gpio.c b/drivers/gpio/tps65910-gpio.c old mode 100644 new mode 100755 diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 35ff8fe22183..43c5d038be13 100755 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -171,6 +171,37 @@ config MFD_TPS6586X This driver can also be built as a module. If so, the module will be called tps6586x. +config MFD_TPS65910 + bool "TPS65910 Power Management chip" + depends on I2C=y && GPIOLIB + select MFD_CORE + select GPIO_TPS65910 + select REGMAP_I2C + help + if you say yes here you get support for the TPS65910 series of + Power Management chips. + +config MFD_TPS65912 + bool + depends on GPIOLIB + +config MFD_TPS65912_I2C + bool "TPS65912 Power Management chip with I2C" + select MFD_CORE + select MFD_TPS65912 + depends on I2C=y && GPIOLIB + help + If you say yes here you get support for the TPS65912 series of + PM chips with I2C interface. + +config MFD_TPS65912_SPI + bool "TPS65912 Power Management chip with SPI" + select MFD_CORE + select MFD_TPS65912 + depends on SPI_MASTER && GPIOLIB + help + If you say yes here you get support for the TPS65912 series of + PM chips with SPI interface. config MENELAUS bool "Texas Instruments TWL92330/Menelaus PM chip" depends on I2C=y && ARCH_OMAP2 @@ -769,18 +800,21 @@ config MFD_PM8XXX_IRQ This is required to use certain other PM 8xxx features, such as GPIO and MPP. -config MFD_TPS65910 - bool "TPS65910 Power Management chip" - depends on I2C=y && GPIOLIB - select MFD_CORE - select GPIO_TPS65910 - help - if you say yes here you get support for the TPS65910 series of - Power Management chips. - config TPS65911_COMPARATOR tristate +config MFD_TPS65090 + bool "TPS65090 Power Management chips" + depends on I2C=y && GENERIC_HARDIRQS + select MFD_CORE + select REGMAP_I2C + help + If you say yes here you get support for the TPS65090 series of + Power Management chips. + This driver provides common support for accessing the device, + additional drivers must be enabled in order to use the + functionality of the device. + config MFD_RK610 bool "RK610(Jetta) Multimedia support" depends on I2C=y && GPIOLIB diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index bd569e97306c..59d550bfe573 100755 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -36,6 +36,11 @@ obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o obj-$(CONFIG_TPS6105X) += tps6105x.o obj-$(CONFIG_TPS65010) += tps65010.o obj-$(CONFIG_TPS6507X) += tps6507x.o +obj-$(CONFIG_MFD_TPS65910) += tps65910.o tps65910-irq.o +tps65912-objs := tps65912-core.o tps65912-irq.o +obj-$(CONFIG_MFD_TPS65912) += tps65912.o +obj-$(CONFIG_MFD_TPS65912_I2C) += tps65912-i2c.o +obj-$(CONFIG_MFD_TPS65912_SPI) += tps65912-spi.o obj-$(CONFIG_MENELAUS) += menelaus.o obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o diff --git a/drivers/mfd/tps65910-irq.c b/drivers/mfd/tps65910-irq.c old mode 100644 new mode 100755 index a56be931551c..bcec38371c94 --- a/drivers/mfd/tps65910-irq.c +++ b/drivers/mfd/tps65910-irq.c @@ -45,7 +45,7 @@ static irqreturn_t tps65910_irq(int irq, void *irq_data) u32 irq_mask; u8 reg; int i; - + tps65910->read(tps65910, TPS65910_INT_STS, 1, ®); irq_sts = reg; tps65910->read(tps65910, TPS65910_INT_STS2, 1, ®); @@ -145,12 +145,23 @@ static void tps65910_irq_disable(struct irq_data *data) tps65910->irq_mask |= ( 1 << irq_to_tps65910_irq(tps65910, data->irq)); } +#ifdef CONFIG_PM_SLEEP +static int tps65910_irq_set_wake(struct irq_data *data, unsigned int enable) +{ + struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); + return irq_set_irq_wake(tps65910->chip_irq, enable); +} +#else +#define tps65910_irq_set_wake NULL +#endif + static struct irq_chip tps65910_irq_chip = { .name = "tps65910", .irq_bus_lock = tps65910_irq_lock, .irq_bus_sync_unlock = tps65910_irq_sync_unlock, .irq_disable = tps65910_irq_disable, .irq_enable = tps65910_irq_enable, + .irq_set_wake = tps65910_irq_set_wake, }; int tps65910_irq_init(struct tps65910 *tps65910, int irq, @@ -158,17 +169,27 @@ int tps65910_irq_init(struct tps65910 *tps65910, int irq, { int ret, cur_irq; int flags = IRQF_ONESHOT; + u8 reg; if (!irq) { dev_warn(tps65910->dev, "No interrupt support, no core IRQ\n"); - return -EINVAL; + return 0; } if (!pdata || !pdata->irq_base) { dev_warn(tps65910->dev, "No interrupt support, no IRQ base\n"); - return -EINVAL; + return 0; } + /* Clear unattended interrupts */ + tps65910->read(tps65910, TPS65910_INT_STS, 1, ®); + tps65910->write(tps65910, TPS65910_INT_STS, 1, ®); + tps65910->read(tps65910, TPS65910_INT_STS2, 1, ®); + tps65910->write(tps65910, TPS65910_INT_STS2, 1, ®); + tps65910->read(tps65910, TPS65910_INT_STS3, 1, ®); + tps65910->write(tps65910, TPS65910_INT_STS3, 1, ®); + + /* Mask top level interrupts */ tps65910->irq_mask = 0xFFFFFF; mutex_init(&tps65910->irq_lock); @@ -215,6 +236,7 @@ int tps65910_irq_init(struct tps65910 *tps65910, int irq, int tps65910_irq_exit(struct tps65910 *tps65910) { - free_irq(tps65910->chip_irq, tps65910); + if (tps65910->chip_irq) + free_irq(tps65910->chip_irq, tps65910); return 0; } diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c old mode 100644 new mode 100755 index 2229e66d80db..6b16534548ad --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -22,6 +22,8 @@ #include #include +struct tps65910 *g_tps65910; + static struct mfd_cell tps65910s[] = { { .name = "tps65910-pmic", @@ -34,6 +36,7 @@ static struct mfd_cell tps65910s[] = { }, }; +#define TPS65910_SPEED 200 * 1000 static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg, int bytes, void *dest) @@ -41,25 +44,30 @@ static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg, struct i2c_client *i2c = tps65910->i2c_client; struct i2c_msg xfer[2]; int ret; + //int i; /* Write register */ xfer[0].addr = i2c->addr; xfer[0].flags = 0; xfer[0].len = 1; xfer[0].buf = ® + xfer[0].scl_rate = TPS65910_SPEED; /* Read data */ xfer[1].addr = i2c->addr; xfer[1].flags = I2C_M_RD; xfer[1].len = bytes; xfer[1].buf = dest; + xfer[1].scl_rate = TPS65910_SPEED; ret = i2c_transfer(i2c->adapter, xfer, 2); + //for(i=0;i= 0) ret = -EIO; - + return ret; } @@ -70,21 +78,114 @@ static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg, /* we add 1 byte for device register */ u8 msg[TPS65910_MAX_REGISTER + 1]; int ret; - + //int i; + if (bytes > TPS65910_MAX_REGISTER) return -EINVAL; - + msg[0] = reg; memcpy(&msg[1], src, bytes); + //for(i=0;iread(tps65910, reg, 1, &val); + if (err < 0) + return err; + + return val; +} + +static inline int tps65910_write(struct tps65910 *tps65910, u8 reg, u8 val) +{ + return tps65910->write(tps65910, reg, 1, &val); +} + +int tps65910_reg_read(struct tps65910 *tps65910, u8 reg) +{ + int data; + + mutex_lock(&tps65910->io_mutex); + + data = tps65910_read(tps65910, reg); + if (data < 0) + dev_err(tps65910->dev, "Read from reg 0x%x failed\n", reg); + + mutex_unlock(&tps65910->io_mutex); + return data; +} +EXPORT_SYMBOL_GPL(tps65910_reg_read); + +int tps65910_reg_write(struct tps65910 *tps65910, u8 reg, u8 val) +{ + int err; + + mutex_lock(&tps65910->io_mutex); + + err = tps65910_write(tps65910, reg, val); + if (err < 0) + dev_err(tps65910->dev, "Write for reg 0x%x failed\n", reg); + + mutex_unlock(&tps65910->io_mutex); + return err; +} +EXPORT_SYMBOL_GPL(tps65910_reg_write); + +/** + * tps65910_bulk_read: Read multiple tps65910 registers + * + * @tps65910: Device to read from + * @reg: First register + * @count: Number of registers + * @buf: Buffer to fill. + */ +int tps65910_bulk_read(struct tps65910 *tps65910, u8 reg, + int count, u8 *buf) +{ + int ret; + + mutex_lock(&tps65910->io_mutex); + + ret = tps65910->read(tps65910, reg, count, buf); + + mutex_unlock(&tps65910->io_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(tps65910_bulk_read); + +int tps65910_bulk_write(struct tps65910 *tps65910, u8 reg, + int count, u8 *buf) +{ + int ret; + + mutex_lock(&tps65910->io_mutex); + + ret = tps65910->write(tps65910, reg, count, buf); + + mutex_unlock(&tps65910->io_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(tps65910_bulk_write); + + + + int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask) { u8 data; @@ -93,14 +194,14 @@ int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask) mutex_lock(&tps65910->io_mutex); err = tps65910_i2c_read(tps65910, reg, 1, &data); if (err) { - dev_err(tps65910->dev, "read from reg %x failed\n", reg); + dev_err(tps65910->dev, "%s:read from reg %x failed\n", __func__,reg); goto out; } data |= mask; err = tps65910_i2c_write(tps65910, reg, 1, &data); if (err) - dev_err(tps65910->dev, "write to reg %x failed\n", reg); + dev_err(tps65910->dev, "%s:write to reg %x failed\n", __func__,reg); out: mutex_unlock(&tps65910->io_mutex); @@ -120,7 +221,7 @@ int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask) goto out; } - data &= mask; + data &= ~mask; err = tps65910_i2c_write(tps65910, reg, 1, &data); if (err) dev_err(tps65910->dev, "write to reg %x failed\n", reg); @@ -138,7 +239,7 @@ static int tps65910_i2c_probe(struct i2c_client *i2c, struct tps65910_board *pmic_plat_data; struct tps65910_platform_data *init_data; int ret = 0; - + pmic_plat_data = dev_get_platdata(&i2c->dev); if (!pmic_plat_data) return -EINVAL; @@ -148,7 +249,7 @@ static int tps65910_i2c_probe(struct i2c_client *i2c, return -ENOMEM; init_data->irq = pmic_plat_data->irq; - init_data->irq_base = pmic_plat_data->irq; + init_data->irq_base = pmic_plat_data->irq_base; tps65910 = kzalloc(sizeof(struct tps65910), GFP_KERNEL); if (tps65910 == NULL) @@ -167,6 +268,16 @@ static int tps65910_i2c_probe(struct i2c_client *i2c, NULL, 0); if (ret < 0) goto err; + + g_tps65910 = tps65910; + + if (pmic_plat_data && pmic_plat_data->pre_init) { + ret = pmic_plat_data->pre_init(tps65910); + if (ret != 0) { + dev_err(tps65910->dev, "pre_init() failed: %d\n", ret); + goto err; + } + } tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base); @@ -174,6 +285,15 @@ static int tps65910_i2c_probe(struct i2c_client *i2c, if (ret < 0) goto err; + if (pmic_plat_data && pmic_plat_data->post_init) { + ret = pmic_plat_data->post_init(tps65910); + if (ret != 0) { + dev_err(tps65910->dev, "post_init() failed: %d\n", ret); + goto err; + } + } + + printk("%s:irq=%d,irq_base=%d,gpio_base=%d\n",__func__,init_data->irq,init_data->irq_base,pmic_plat_data->gpio_base); return ret; err: @@ -182,6 +302,36 @@ static int tps65910_i2c_probe(struct i2c_client *i2c, return ret; } + +int tps65910_device_shutdown(void) +{ + int val = 0; + int err = -1; + struct tps65910 *tps65910 = g_tps65910; + + printk("%s\n",__func__); + + val = tps65910_reg_read(tps65910, TPS65910_DEVCTRL); + if (val<0) { + printk(KERN_ERR "Unable to read TPS65910_REG_DCDCCTRL reg\n"); + return -EIO; + } + + val |= DEVCTRL_DEV_OFF_MASK; + val &= ~DEVCTRL_CK32K_CTRL_MASK; //keep rtc + err = tps65910_reg_write(tps65910, TPS65910_DEVCTRL, val); + if (err) { + printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \ + \n", TPS65910_REG_VDIG1); + return err; + } + + return 0; +} +EXPORT_SYMBOL_GPL(tps65910_device_shutdown); + + + static int tps65910_i2c_remove(struct i2c_client *i2c) { struct tps65910 *tps65910 = i2c_get_clientdata(i2c); @@ -215,7 +365,7 @@ static int __init tps65910_i2c_init(void) return i2c_add_driver(&tps65910_i2c_driver); } /* init early so consumer devices can complete system boot */ -subsys_initcall(tps65910_i2c_init); +subsys_initcall_sync(tps65910_i2c_init); static void __exit tps65910_i2c_exit(void) { diff --git a/drivers/mfd/tps65911-comparator.c b/drivers/mfd/tps65911-comparator.c old mode 100644 new mode 100755 diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 90c87c9797c5..b425fd61c4b2 100755 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -125,6 +125,17 @@ config REGULATOR_MAX8998 via I2C bus. The provided regulator is suitable for S3C6410 and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages. +config REGULATOR_TPS65910 + tristate "TI TPS65910/TPS65911 Power Regulators" + depends on MFD_TPS65910 + help + This driver supports TPS65910/TPS65911 voltage regulator chips. + +config REGULATOR_TPS65912 + tristate "TI TPS65912 Power regulator" + depends on (MFD_TPS65912_I2C || MFD_TPS65912_SPI) + help + This driver supports TPS65912 voltage regulator chip. config REGULATOR_TWL4030 bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC" depends on TWL4030_CORE @@ -324,11 +335,7 @@ config REGULATOR_TPS6524X serial interface currently supported on the sequencer serial port controller. -config REGULATOR_TPS65910 - tristate "TI TPS65910 Power Regulator" - depends on MFD_TPS65910 - help - This driver supports TPS65910 voltage regulator chips. + endif diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 68db7129f878..d4f86bae7bf9 100755 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o +obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o obj-$(CONFIG_REGULATOR_ACT8891) += act8891.o ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c old mode 100644 new mode 100755 index 425aab38981e..22e06e2cb98e --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c @@ -25,45 +25,51 @@ #include #include -#define TPS65910_REG_VRTC 0 -#define TPS65910_REG_VIO 1 -#define TPS65910_REG_VDD1 2 -#define TPS65910_REG_VDD2 3 -#define TPS65910_REG_VDD3 4 -#define TPS65910_REG_VDIG1 5 -#define TPS65910_REG_VDIG2 6 -#define TPS65910_REG_VPLL 7 -#define TPS65910_REG_VDAC 8 -#define TPS65910_REG_VAUX1 9 -#define TPS65910_REG_VAUX2 10 -#define TPS65910_REG_VAUX33 11 -#define TPS65910_REG_VMMC 12 - -#define TPS65911_REG_VDDCTRL 4 -#define TPS65911_REG_LDO1 5 -#define TPS65911_REG_LDO2 6 -#define TPS65911_REG_LDO3 7 -#define TPS65911_REG_LDO4 8 -#define TPS65911_REG_LDO5 9 -#define TPS65911_REG_LDO6 10 -#define TPS65911_REG_LDO7 11 -#define TPS65911_REG_LDO8 12 - -#define TPS65910_NUM_REGULATOR 13 #define TPS65910_SUPPLY_STATE_ENABLED 0x1 +#define EXT_SLEEP_CONTROL (TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1 | \ + TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2 | \ + TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3 | \ + TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP) /* supported VIO voltages in milivolts */ static const u16 VIO_VSEL_table[] = { 1500, 1800, 2500, 3300, }; -/* VSEL tables for TPS65910 specific LDOs and dcdc's */ - -/* supported VDD3 voltages in milivolts */ -static const u16 VDD3_VSEL_table[] = { - 5000, +/* TPS65910 VDD1 and VDD2 */ +/* value round off 12.5 is made as 12 */ +static const u16 VDD1_VSEL_table[] = { + 0, 600, 600, 600, 612, 625, 637, 650, + 662, 675, 687, 700, 712, 725, 737, 750, + 762, 775, 787, 800, 812, 825, 837, 850, + 862, 875, 887, 900, 912, 925, 937, 950, + 962, 975, 987, 1000, 1012, 1025, 1037, 1050, + 1062, 1075, 1087, 1100, 1112, 1125, 1137, 1150, + 1162, 1175, 1187, 1200, 1212, 1225, 1237, 1250, + 1262, 1275, 1287, 1300, 1312, 1325, 1337, 1350, + 1362, 1375, 1387, 1400, 1412, 1425, 1437, 1450, + 1462, 1475, 1487, 1500, }; +static const u16 VDD2_VSEL_table[] = { + 0, 600, 600, 600, 612, 625, 637, 650, + 662, 675, 687, 700, 712, 725, 737, 750, + 762, 775, 787, 800, 812, 825, 837, 850, + 862, 875, 887, 900, 912, 925, 937, 950, + 962, 975, 987, 1000, 1012, 1025, 1037, 1050, + 1062, 1075, 1087, 1100, 1112, 1125, 1137, 1150, + 1162, 1175, 1187, 1200, 1212, 1225, 1237, 1250, + 1262, 1275, 1287, 1300, 1312, 1325, 1337, 1350, + 1362, 1375, 1387, 1400, 1412, 1425, 1437, 1450, + 1462, 1475, 1487, 1500, +}; + +/* TPS65910 VDD3 */ +static const u16 VDD3_VSEL_table[] = { + 1000,1400 +}; + + /* supported VDIG1 voltages in milivolts */ static const u16 VDIG1_VSEL_table[] = { 1200, 1500, 1800, 2700, @@ -108,169 +114,250 @@ struct tps_info { const char *name; unsigned min_uV; unsigned max_uV; - u8 table_len; - const u16 *table; + u8 n_voltages; + const u16 *voltage_table; + int enable_time_us; }; static struct tps_info tps65910_regs[] = { { .name = "VRTC", + .enable_time_us = 2200, }, { .name = "VIO", .min_uV = 1500000, .max_uV = 3300000, - .table_len = ARRAY_SIZE(VIO_VSEL_table), - .table = VIO_VSEL_table, + .n_voltages = ARRAY_SIZE(VIO_VSEL_table), + .voltage_table = VIO_VSEL_table, + .enable_time_us = 350, }, { .name = "VDD1", .min_uV = 600000, - .max_uV = 4500000, + .max_uV = 1500000, + .n_voltages = ARRAY_SIZE(VDD1_VSEL_table), + .voltage_table = VDD1_VSEL_table, + .enable_time_us = 350, }, { .name = "VDD2", .min_uV = 600000, - .max_uV = 4500000, + .max_uV = 1500000, + .n_voltages = ARRAY_SIZE(VDD2_VSEL_table), + .voltage_table = VDD2_VSEL_table, + .enable_time_us = 350, }, { .name = "VDD3", - .min_uV = 5000000, - .max_uV = 5000000, - .table_len = ARRAY_SIZE(VDD3_VSEL_table), - .table = VDD3_VSEL_table, + .min_uV = 1000000, + .max_uV = 1400000, + .n_voltages = ARRAY_SIZE(VDD3_VSEL_table), + .voltage_table = VDD3_VSEL_table, + .enable_time_us = 200, }, { .name = "VDIG1", .min_uV = 1200000, .max_uV = 2700000, - .table_len = ARRAY_SIZE(VDIG1_VSEL_table), - .table = VDIG1_VSEL_table, + .n_voltages = ARRAY_SIZE(VDIG1_VSEL_table), + .voltage_table = VDIG1_VSEL_table, + .enable_time_us = 100, }, { .name = "VDIG2", .min_uV = 1000000, .max_uV = 1800000, - .table_len = ARRAY_SIZE(VDIG2_VSEL_table), - .table = VDIG2_VSEL_table, + .n_voltages = ARRAY_SIZE(VDIG2_VSEL_table), + .voltage_table = VDIG2_VSEL_table, + .enable_time_us = 100, }, { .name = "VPLL", .min_uV = 1000000, .max_uV = 2500000, - .table_len = ARRAY_SIZE(VPLL_VSEL_table), - .table = VPLL_VSEL_table, + .n_voltages = ARRAY_SIZE(VPLL_VSEL_table), + .voltage_table = VPLL_VSEL_table, + .enable_time_us = 100, }, { .name = "VDAC", .min_uV = 1800000, .max_uV = 2850000, - .table_len = ARRAY_SIZE(VDAC_VSEL_table), - .table = VDAC_VSEL_table, + .n_voltages = ARRAY_SIZE(VDAC_VSEL_table), + .voltage_table = VDAC_VSEL_table, + .enable_time_us = 100, }, { .name = "VAUX1", .min_uV = 1800000, .max_uV = 2850000, - .table_len = ARRAY_SIZE(VAUX1_VSEL_table), - .table = VAUX1_VSEL_table, + .n_voltages = ARRAY_SIZE(VAUX1_VSEL_table), + .voltage_table = VAUX1_VSEL_table, + .enable_time_us = 100, }, { .name = "VAUX2", .min_uV = 1800000, .max_uV = 3300000, - .table_len = ARRAY_SIZE(VAUX2_VSEL_table), - .table = VAUX2_VSEL_table, + .n_voltages = ARRAY_SIZE(VAUX2_VSEL_table), + .voltage_table = VAUX2_VSEL_table, + .enable_time_us = 100, }, { .name = "VAUX33", .min_uV = 1800000, .max_uV = 3300000, - .table_len = ARRAY_SIZE(VAUX33_VSEL_table), - .table = VAUX33_VSEL_table, + .n_voltages = ARRAY_SIZE(VAUX33_VSEL_table), + .voltage_table = VAUX33_VSEL_table, + .enable_time_us = 100, }, { .name = "VMMC", .min_uV = 1800000, .max_uV = 3300000, - .table_len = ARRAY_SIZE(VMMC_VSEL_table), - .table = VMMC_VSEL_table, + .n_voltages = ARRAY_SIZE(VMMC_VSEL_table), + .voltage_table = VMMC_VSEL_table, + .enable_time_us = 100, }, }; static struct tps_info tps65911_regs[] = { + { + .name = "VRTC", + .enable_time_us = 2200, + }, { .name = "VIO", .min_uV = 1500000, .max_uV = 3300000, - .table_len = ARRAY_SIZE(VIO_VSEL_table), - .table = VIO_VSEL_table, + .n_voltages = ARRAY_SIZE(VIO_VSEL_table), + .voltage_table = VIO_VSEL_table, + .enable_time_us = 350, }, { .name = "VDD1", .min_uV = 600000, .max_uV = 4500000, + .n_voltages = 73, + .enable_time_us = 350, }, { .name = "VDD2", .min_uV = 600000, .max_uV = 4500000, + .n_voltages = 73, + .enable_time_us = 350, }, { .name = "VDDCTRL", .min_uV = 600000, .max_uV = 1400000, + .n_voltages = 65, + .enable_time_us = 900, }, { .name = "LDO1", .min_uV = 1000000, .max_uV = 3300000, + .n_voltages = 47, + .enable_time_us = 420, }, { .name = "LDO2", .min_uV = 1000000, .max_uV = 3300000, + .n_voltages = 47, + .enable_time_us = 420, }, { .name = "LDO3", .min_uV = 1000000, .max_uV = 3300000, + .n_voltages = 24, + .enable_time_us = 230, }, { .name = "LDO4", .min_uV = 1000000, .max_uV = 3300000, + .n_voltages = 47, + .enable_time_us = 230, }, { .name = "LDO5", .min_uV = 1000000, .max_uV = 3300000, + .n_voltages = 24, + .enable_time_us = 230, }, { .name = "LDO6", .min_uV = 1000000, .max_uV = 3300000, + .n_voltages = 24, + .enable_time_us = 230, }, { .name = "LDO7", .min_uV = 1000000, .max_uV = 3300000, + .n_voltages = 24, + .enable_time_us = 230, }, { .name = "LDO8", .min_uV = 1000000, .max_uV = 3300000, + .n_voltages = 24, + .enable_time_us = 230, }, }; +#define EXT_CONTROL_REG_BITS(id, regs_offs, bits) (((regs_offs) << 8) | (bits)) +static unsigned int tps65910_ext_sleep_control[] = { + 0, + EXT_CONTROL_REG_BITS(VIO, 1, 0), + EXT_CONTROL_REG_BITS(VDD1, 1, 1), + EXT_CONTROL_REG_BITS(VDD2, 1, 2), + EXT_CONTROL_REG_BITS(VDD3, 1, 3), + EXT_CONTROL_REG_BITS(VDIG1, 0, 1), + EXT_CONTROL_REG_BITS(VDIG2, 0, 2), + EXT_CONTROL_REG_BITS(VPLL, 0, 6), + EXT_CONTROL_REG_BITS(VDAC, 0, 7), + EXT_CONTROL_REG_BITS(VAUX1, 0, 3), + EXT_CONTROL_REG_BITS(VAUX2, 0, 4), + EXT_CONTROL_REG_BITS(VAUX33, 0, 5), + EXT_CONTROL_REG_BITS(VMMC, 0, 0), +}; + +static unsigned int tps65911_ext_sleep_control[] = { + 0, + EXT_CONTROL_REG_BITS(VIO, 1, 0), + EXT_CONTROL_REG_BITS(VDD1, 1, 1), + EXT_CONTROL_REG_BITS(VDD2, 1, 2), + EXT_CONTROL_REG_BITS(VDDCTRL, 1, 3), + EXT_CONTROL_REG_BITS(LDO1, 0, 1), + EXT_CONTROL_REG_BITS(LDO2, 0, 2), + EXT_CONTROL_REG_BITS(LDO3, 0, 7), + EXT_CONTROL_REG_BITS(LDO4, 0, 6), + EXT_CONTROL_REG_BITS(LDO5, 0, 3), + EXT_CONTROL_REG_BITS(LDO6, 0, 0), + EXT_CONTROL_REG_BITS(LDO7, 0, 5), + EXT_CONTROL_REG_BITS(LDO8, 0, 4), +}; + struct tps65910_reg { - struct regulator_desc desc[TPS65910_NUM_REGULATOR]; + struct regulator_desc *desc; struct tps65910 *mfd; - struct regulator_dev *rdev[TPS65910_NUM_REGULATOR]; - struct tps_info *info[TPS65910_NUM_REGULATOR]; + struct regulator_dev **rdev; + struct tps_info **info; struct mutex mutex; + int num_regulators; int mode; int (*get_ctrl_reg)(int); + unsigned int *ext_sleep_control; + unsigned int board_ext_control[TPS65910_NUM_REGS]; }; static inline int tps65910_read(struct tps65910_reg *pmic, u8 reg) @@ -315,7 +402,7 @@ static int tps65910_modify_bits(struct tps65910_reg *pmic, u8 reg, return err; } -static int tps65910_reg_read(struct tps65910_reg *pmic, u8 reg) +static int tps65910_pmic_reg_read(struct tps65910_reg *pmic, u8 reg) { int data; @@ -329,7 +416,7 @@ static int tps65910_reg_read(struct tps65910_reg *pmic, u8 reg) return data; } -static int tps65910_reg_write(struct tps65910_reg *pmic, u8 reg, u8 val) +static int tps65910_pmic_reg_write(struct tps65910_reg *pmic, u8 reg, u8 val) { int err; @@ -420,7 +507,7 @@ static int tps65910_is_enabled(struct regulator_dev *dev) if (reg < 0) return reg; - value = tps65910_reg_read(pmic, reg); + value = tps65910_pmic_reg_read(pmic, reg); if (value < 0) return value; @@ -453,6 +540,12 @@ static int tps65910_disable(struct regulator_dev *dev) return tps65910_clear_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED); } +static int tps65910_enable_time(struct regulator_dev *dev) +{ + struct tps65910_reg *pmic = rdev_get_drvdata(dev); + int id = rdev_get_id(dev); + return pmic->info[id]->enable_time_us; +} static int tps65910_set_mode(struct regulator_dev *dev, unsigned int mode) { @@ -487,11 +580,11 @@ static unsigned int tps65910_get_mode(struct regulator_dev *dev) if (reg < 0) return reg; - value = tps65910_reg_read(pmic, reg); + value = tps65910_pmic_reg_read(pmic, reg); if (value < 0) return value; - if (value & LDO_ST_ON_BIT) + if (!(value & LDO_ST_ON_BIT)) return REGULATOR_MODE_STANDBY; else if (value & LDO_ST_MODE_BIT) return REGULATOR_MODE_IDLE; @@ -499,36 +592,36 @@ static unsigned int tps65910_get_mode(struct regulator_dev *dev) return REGULATOR_MODE_NORMAL; } -static int tps65910_get_voltage_dcdc(struct regulator_dev *dev) +static int tps65910_get_voltage_dcdc_sel(struct regulator_dev *dev) { struct tps65910_reg *pmic = rdev_get_drvdata(dev); - int id = rdev_get_id(dev), voltage = 0; + int id = rdev_get_id(dev); int opvsel = 0, srvsel = 0, vselmax = 0, mult = 0, sr = 0; switch (id) { case TPS65910_REG_VDD1: - opvsel = tps65910_reg_read(pmic, TPS65910_VDD1_OP); - mult = tps65910_reg_read(pmic, TPS65910_VDD1); + opvsel = tps65910_pmic_reg_read(pmic, TPS65910_VDD1_OP); + mult = tps65910_pmic_reg_read(pmic, TPS65910_VDD1); mult = (mult & VDD1_VGAIN_SEL_MASK) >> VDD1_VGAIN_SEL_SHIFT; - srvsel = tps65910_reg_read(pmic, TPS65910_VDD1_SR); + srvsel = tps65910_pmic_reg_read(pmic, TPS65910_VDD1_SR); sr = opvsel & VDD1_OP_CMD_MASK; opvsel &= VDD1_OP_SEL_MASK; srvsel &= VDD1_SR_SEL_MASK; vselmax = 75; break; case TPS65910_REG_VDD2: - opvsel = tps65910_reg_read(pmic, TPS65910_VDD2_OP); - mult = tps65910_reg_read(pmic, TPS65910_VDD2); + opvsel = tps65910_pmic_reg_read(pmic, TPS65910_VDD2_OP); + mult = tps65910_pmic_reg_read(pmic, TPS65910_VDD2); mult = (mult & VDD2_VGAIN_SEL_MASK) >> VDD2_VGAIN_SEL_SHIFT; - srvsel = tps65910_reg_read(pmic, TPS65910_VDD2_SR); + srvsel = tps65910_pmic_reg_read(pmic, TPS65910_VDD2_SR); sr = opvsel & VDD2_OP_CMD_MASK; opvsel &= VDD2_OP_SEL_MASK; srvsel &= VDD2_SR_SEL_MASK; vselmax = 75; break; case TPS65911_REG_VDDCTRL: - opvsel = tps65910_reg_read(pmic, TPS65911_VDDCTRL_OP); - srvsel = tps65910_reg_read(pmic, TPS65911_VDDCTRL_SR); + opvsel = tps65910_pmic_reg_read(pmic, TPS65911_VDDCTRL_OP); + srvsel = tps65910_pmic_reg_read(pmic, TPS65911_VDDCTRL_SR); sr = opvsel & VDDCTRL_OP_CMD_MASK; opvsel &= VDDCTRL_OP_SEL_MASK; srvsel &= VDDCTRL_SR_SEL_MASK; @@ -546,9 +639,7 @@ static int tps65910_get_voltage_dcdc(struct regulator_dev *dev) srvsel = 3; if (srvsel > vselmax) srvsel = vselmax; - srvsel -= 3; - - voltage = (srvsel * VDD1_2_OFFSET + VDD1_2_MIN_VOLT) * 100; + return srvsel - 3; } else { /* normalise to valid range*/ @@ -556,14 +647,9 @@ static int tps65910_get_voltage_dcdc(struct regulator_dev *dev) opvsel = 3; if (opvsel > vselmax) opvsel = vselmax; - opvsel -= 3; - - voltage = (opvsel * VDD1_2_OFFSET + VDD1_2_MIN_VOLT) * 100; + return opvsel - 3; } - - voltage *= mult; - - return voltage; + return -EINVAL; } static int tps65910_get_voltage(struct regulator_dev *dev) @@ -575,7 +661,7 @@ static int tps65910_get_voltage(struct regulator_dev *dev) if (reg < 0) return reg; - value = tps65910_reg_read(pmic, reg); + value = tps65910_pmic_reg_read(pmic, reg); if (value < 0) return value; @@ -596,7 +682,7 @@ static int tps65910_get_voltage(struct regulator_dev *dev) return -EINVAL; } - voltage = pmic->info[id]->table[value] * 1000; + voltage = pmic->info[id]->voltage_table[value] * 1000; return voltage; } @@ -614,7 +700,7 @@ static int tps65911_get_voltage(struct regulator_dev *dev) reg = pmic->get_ctrl_reg(id); - value = tps65910_reg_read(pmic, reg); + value = tps65910_pmic_reg_read(pmic, reg); switch (id) { case TPS65911_REG_LDO1: @@ -646,8 +732,9 @@ static int tps65911_get_voltage(struct regulator_dev *dev) step_mv = 100; break; case TPS65910_REG_VIO: - return pmic->info[id]->table[value] * 1000; - break; + value &= LDO_SEL_MASK; + value >>= LDO_SEL_SHIFT; + return pmic->info[id]->voltage_table[value] * 1000; default: return -EINVAL; } @@ -655,8 +742,8 @@ static int tps65911_get_voltage(struct regulator_dev *dev) return (LDO_MIN_VOLT + value * step_mv) * 1000; } -static int tps65910_set_voltage_dcdc(struct regulator_dev *dev, - unsigned selector) +static int tps65910_set_voltage_dcdc_sel(struct regulator_dev *dev, + unsigned selector) { struct tps65910_reg *pmic = rdev_get_drvdata(dev); int id = rdev_get_id(dev), vsel; @@ -664,36 +751,37 @@ static int tps65910_set_voltage_dcdc(struct regulator_dev *dev, switch (id) { case TPS65910_REG_VDD1: - dcdc_mult = (selector / VDD1_2_NUM_VOLTS) + 1; + dcdc_mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1; if (dcdc_mult == 1) dcdc_mult--; - vsel = (selector % VDD1_2_NUM_VOLTS) + 3; + vsel = (selector % VDD1_2_NUM_VOLT_FINE) + 3; tps65910_modify_bits(pmic, TPS65910_VDD1, (dcdc_mult << VDD1_VGAIN_SEL_SHIFT), VDD1_VGAIN_SEL_MASK); - tps65910_reg_write(pmic, TPS65910_VDD1_OP, vsel); + tps65910_pmic_reg_write(pmic, TPS65910_VDD1_OP, vsel); break; case TPS65910_REG_VDD2: - dcdc_mult = (selector / VDD1_2_NUM_VOLTS) + 1; + dcdc_mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1; if (dcdc_mult == 1) dcdc_mult--; - vsel = (selector % VDD1_2_NUM_VOLTS) + 3; + vsel = (selector % VDD1_2_NUM_VOLT_FINE) + 3; tps65910_modify_bits(pmic, TPS65910_VDD2, (dcdc_mult << VDD2_VGAIN_SEL_SHIFT), VDD1_VGAIN_SEL_MASK); - tps65910_reg_write(pmic, TPS65910_VDD2_OP, vsel); + tps65910_pmic_reg_write(pmic, TPS65910_VDD2_OP, vsel); break; case TPS65911_REG_VDDCTRL: - vsel = selector; - tps65910_reg_write(pmic, TPS65911_VDDCTRL_OP, vsel); + vsel = selector + 3; + tps65910_pmic_reg_write(pmic, TPS65911_VDDCTRL_OP, vsel); } return 0; } -static int tps65910_set_voltage(struct regulator_dev *dev, unsigned selector) +static int tps65910_set_voltage_sel(struct regulator_dev *dev, + unsigned selector) { struct tps65910_reg *pmic = rdev_get_drvdata(dev); int reg, id = rdev_get_id(dev); @@ -719,7 +807,8 @@ static int tps65910_set_voltage(struct regulator_dev *dev, unsigned selector) return -EINVAL; } -static int tps65911_set_voltage(struct regulator_dev *dev, unsigned selector) +static int tps65911_set_voltage_sel(struct regulator_dev *dev, + unsigned selector) { struct tps65910_reg *pmic = rdev_get_drvdata(dev); int reg, id = rdev_get_id(dev); @@ -739,9 +828,11 @@ static int tps65911_set_voltage(struct regulator_dev *dev, unsigned selector) case TPS65911_REG_LDO6: case TPS65911_REG_LDO7: case TPS65911_REG_LDO8: - case TPS65910_REG_VIO: return tps65910_modify_bits(pmic, reg, (selector << LDO_SEL_SHIFT), LDO3_SEL_MASK); + case TPS65910_REG_VIO: + return tps65910_modify_bits(pmic, reg, + (selector << LDO_SEL_SHIFT), LDO_SEL_MASK); } return -EINVAL; @@ -756,9 +847,9 @@ static int tps65910_list_voltage_dcdc(struct regulator_dev *dev, switch (id) { case TPS65910_REG_VDD1: case TPS65910_REG_VDD2: - mult = (selector / VDD1_2_NUM_VOLTS) + 1; + mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1; volt = VDD1_2_MIN_VOLT + - (selector % VDD1_2_NUM_VOLTS) * VDD1_2_OFFSET; + (selector % VDD1_2_NUM_VOLT_FINE) * VDD1_2_OFFSET; break; case TPS65911_REG_VDDCTRL: volt = VDDCTRL_MIN_VOLT + (selector * VDDCTRL_OFFSET); @@ -780,11 +871,11 @@ static int tps65910_list_voltage(struct regulator_dev *dev, if (id < TPS65910_REG_VIO || id > TPS65910_REG_VMMC) return -EINVAL; - if (selector >= pmic->info[id]->table_len) + if (selector >= pmic->info[id]->n_voltages) return -EINVAL; else - voltage = pmic->info[id]->table[selector] * 1000; - + voltage = pmic->info[id]->voltage_table[selector] * 1000; + return voltage; } @@ -819,7 +910,7 @@ static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector) step_mv = 100; break; case TPS65910_REG_VIO: - return pmic->info[id]->table[selector] * 1000; + return pmic->info[id]->voltage_table[selector] * 1000; default: return -EINVAL; } @@ -827,15 +918,42 @@ static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector) return (LDO_MIN_VOLT + selector * step_mv) * 1000; } +static int tps65910_set_voltage_dcdc_time_sel(struct regulator_dev *dev, + unsigned int old_selector, unsigned int new_selector) +{ + int id = rdev_get_id(dev); + int old_volt, new_volt; + + old_volt = tps65910_list_voltage_dcdc(dev, old_selector); + if (old_volt < 0) + return old_volt; + + new_volt = tps65910_list_voltage_dcdc(dev, new_selector); + if (new_volt < 0) + return new_volt; + + /* VDD1 and VDD2 are 12.5mV/us, VDDCTRL is 100mV/20us */ + switch (id) { + case TPS65910_REG_VDD1: + case TPS65910_REG_VDD2: + return DIV_ROUND_UP(abs(old_volt - new_volt), 12500); + case TPS65911_REG_VDDCTRL: + return DIV_ROUND_UP(abs(old_volt - new_volt), 5000); + } + return -EINVAL; +} + /* Regulator ops (except VRTC) */ static struct regulator_ops tps65910_ops_dcdc = { .is_enabled = tps65910_is_enabled, .enable = tps65910_enable, .disable = tps65910_disable, + .enable_time = tps65910_enable_time, .set_mode = tps65910_set_mode, .get_mode = tps65910_get_mode, - .get_voltage = tps65910_get_voltage_dcdc, - .set_voltage_sel = tps65910_set_voltage_dcdc, + .get_voltage_sel = tps65910_get_voltage_dcdc_sel, + .set_voltage_sel = tps65910_set_voltage_dcdc_sel, + .set_voltage_time_sel = tps65910_set_voltage_dcdc_time_sel, .list_voltage = tps65910_list_voltage_dcdc, }; @@ -843,6 +961,7 @@ static struct regulator_ops tps65910_ops_vdd3 = { .is_enabled = tps65910_is_enabled, .enable = tps65910_enable, .disable = tps65910_disable, + .enable_time = tps65910_enable_time, .set_mode = tps65910_set_mode, .get_mode = tps65910_get_mode, .get_voltage = tps65910_get_voltage_vdd3, @@ -853,10 +972,11 @@ static struct regulator_ops tps65910_ops = { .is_enabled = tps65910_is_enabled, .enable = tps65910_enable, .disable = tps65910_disable, + .enable_time = tps65910_enable_time, .set_mode = tps65910_set_mode, .get_mode = tps65910_get_mode, .get_voltage = tps65910_get_voltage, - .set_voltage_sel = tps65910_set_voltage, + .set_voltage_sel = tps65910_set_voltage_sel, .list_voltage = tps65910_list_voltage, }; @@ -864,13 +984,147 @@ static struct regulator_ops tps65911_ops = { .is_enabled = tps65910_is_enabled, .enable = tps65910_enable, .disable = tps65910_disable, + .enable_time = tps65910_enable_time, .set_mode = tps65910_set_mode, .get_mode = tps65910_get_mode, .get_voltage = tps65911_get_voltage, - .set_voltage_sel = tps65911_set_voltage, + .set_voltage_sel = tps65911_set_voltage_sel, .list_voltage = tps65911_list_voltage, }; +static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic, + int id, int ext_sleep_config) +{ + struct tps65910 *mfd = pmic->mfd; + u8 regoffs = (pmic->ext_sleep_control[id] >> 8) & 0xFF; + u8 bit_pos = (1 << pmic->ext_sleep_control[id] & 0xFF); + int ret; + + /* + * Regulator can not be control from multiple external input EN1, EN2 + * and EN3 together. + */ + if (ext_sleep_config & EXT_SLEEP_CONTROL) { + int en_count; + en_count = ((ext_sleep_config & + TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1) != 0); + en_count += ((ext_sleep_config & + TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2) != 0); + en_count += ((ext_sleep_config & + TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3) != 0); + en_count += ((ext_sleep_config & + TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP) != 0); + if (en_count > 1) { + dev_err(mfd->dev, + "External sleep control flag is not proper\n"); + return -EINVAL; + } + } + + pmic->board_ext_control[id] = ext_sleep_config; + + /* External EN1 control */ + if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1) + ret = tps65910_set_bits(mfd, + TPS65910_EN1_LDO_ASS + regoffs, bit_pos); + else + ret = tps65910_clear_bits(mfd, + TPS65910_EN1_LDO_ASS + regoffs, bit_pos); + if (ret < 0) { + dev_err(mfd->dev, + "Error in configuring external control EN1\n"); + return ret; + } + + /* External EN2 control */ + if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2) + ret = tps65910_set_bits(mfd, + TPS65910_EN2_LDO_ASS + regoffs, bit_pos); + else + ret = tps65910_clear_bits(mfd, + TPS65910_EN2_LDO_ASS + regoffs, bit_pos); + if (ret < 0) { + dev_err(mfd->dev, + "Error in configuring external control EN2\n"); + return ret; + } + + /* External EN3 control for TPS65910 LDO only */ + if ((tps65910_chip_id(mfd) == TPS65910) && + (id >= TPS65910_REG_VDIG1)) { + if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3) + ret = tps65910_set_bits(mfd, + TPS65910_EN3_LDO_ASS + regoffs, bit_pos); + else + ret = tps65910_clear_bits(mfd, + TPS65910_EN3_LDO_ASS + regoffs, bit_pos); + if (ret < 0) { + dev_err(mfd->dev, + "Error in configuring external control EN3\n"); + return ret; + } + } + + /* Return if no external control is selected */ + if (!(ext_sleep_config & EXT_SLEEP_CONTROL)) { + /* Clear all sleep controls */ + ret = tps65910_clear_bits(mfd, + TPS65910_SLEEP_KEEP_LDO_ON + regoffs, bit_pos); + if (!ret) + ret = tps65910_clear_bits(mfd, + TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos); + if (ret < 0) + dev_err(mfd->dev, + "Error in configuring SLEEP register\n"); + return ret; + } + + /* + * For regulator that has separate operational and sleep register make + * sure that operational is used and clear sleep register to turn + * regulator off when external control is inactive + */ + if ((id == TPS65910_REG_VDD1) || + (id == TPS65910_REG_VDD2) || + ((id == TPS65911_REG_VDDCTRL) && + (tps65910_chip_id(mfd) == TPS65911))) { + int op_reg_add = pmic->get_ctrl_reg(id) + 1; + int sr_reg_add = pmic->get_ctrl_reg(id) + 2; + int opvsel = tps65910_pmic_reg_read(pmic, op_reg_add); + int srvsel = tps65910_pmic_reg_read(pmic, sr_reg_add); + if (opvsel & VDD1_OP_CMD_MASK) { + u8 reg_val = srvsel & VDD1_OP_SEL_MASK; + ret = tps65910_pmic_reg_write(pmic, op_reg_add, reg_val); + if (ret < 0) { + dev_err(mfd->dev, + "Error in configuring op register\n"); + return ret; + } + } + ret = tps65910_pmic_reg_write(pmic, sr_reg_add, 0); + if (ret < 0) { + dev_err(mfd->dev, "Error in settting sr register\n"); + return ret; + } + } + + ret = tps65910_clear_bits(mfd, + TPS65910_SLEEP_KEEP_LDO_ON + regoffs, bit_pos); + if (!ret) { + if (ext_sleep_config & TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP) + ret = tps65910_set_bits(mfd, + TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos); + else + ret = tps65910_clear_bits(mfd, + TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos); + } + if (ret < 0) + dev_err(mfd->dev, + "Error in configuring SLEEP register\n"); + + return ret; +} + static __devinit int tps65910_probe(struct platform_device *pdev) { struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); @@ -885,8 +1139,6 @@ static __devinit int tps65910_probe(struct platform_device *pdev) if (!pmic_plat_data) return -EINVAL; - reg_data = pmic_plat_data->tps65910_pmic_init_data; - pmic = kzalloc(sizeof(*pmic), GFP_KERNEL); if (!pmic) return -ENOMEM; @@ -902,27 +1154,64 @@ static __devinit int tps65910_probe(struct platform_device *pdev) switch(tps65910_chip_id(tps65910)) { case TPS65910: pmic->get_ctrl_reg = &tps65910_get_ctrl_register; + pmic->num_regulators = ARRAY_SIZE(tps65910_regs); + pmic->ext_sleep_control = tps65910_ext_sleep_control; info = tps65910_regs; break; case TPS65911: pmic->get_ctrl_reg = &tps65911_get_ctrl_register; + pmic->num_regulators = ARRAY_SIZE(tps65911_regs); + pmic->ext_sleep_control = tps65911_ext_sleep_control; info = tps65911_regs; break; default: pr_err("Invalid tps chip version\n"); + kfree(pmic); return -ENODEV; } - for (i = 0; i < TPS65910_NUM_REGULATOR; i++, info++, reg_data++) { + pmic->desc = kcalloc(pmic->num_regulators, + sizeof(struct regulator_desc), GFP_KERNEL); + if (!pmic->desc) { + err = -ENOMEM; + goto err_free_pmic; + } + + pmic->info = kcalloc(pmic->num_regulators, + sizeof(struct tps_info *), GFP_KERNEL); + if (!pmic->info) { + err = -ENOMEM; + goto err_free_desc; + } + + pmic->rdev = kcalloc(pmic->num_regulators, + sizeof(struct regulator_dev *), GFP_KERNEL); + if (!pmic->rdev) { + err = -ENOMEM; + goto err_free_info; + } + + for (i = 0; i < pmic->num_regulators && i < TPS65910_NUM_REGS; + i++, info++) { + + reg_data = pmic_plat_data->tps65910_pmic_init_data[i]; + + /* Regulator API handles empty constraints but not NULL + * constraints */ + if (!reg_data) + continue; + /* Register the regulators */ pmic->info[i] = info; pmic->desc[i].name = info->name; pmic->desc[i].id = i; - pmic->desc[i].n_voltages = info->table_len; + pmic->desc[i].n_voltages = info->n_voltages; if (i == TPS65910_REG_VDD1 || i == TPS65910_REG_VDD2) { pmic->desc[i].ops = &tps65910_ops_dcdc; + pmic->desc[i].n_voltages = VDD1_2_NUM_VOLT_FINE * + VDD1_2_NUM_VOLT_COARSE; } else if (i == TPS65910_REG_VDD3) { if (tps65910_chip_id(tps65910) == TPS65910) pmic->desc[i].ops = &tps65910_ops_vdd3; @@ -935,6 +1224,16 @@ static __devinit int tps65910_probe(struct platform_device *pdev) pmic->desc[i].ops = &tps65911_ops; } + err = tps65910_set_ext_sleep_config(pmic, i, + pmic_plat_data->regulator_ext_sleep_control[i]); + /* + * Failing on regulator for configuring externally control + * is not a serious issue, just throw warning. + */ + if (err < 0) + dev_warn(tps65910->dev, + "Failed to initialise ext control config\n"); + pmic->desc[i].type = REGULATOR_VOLTAGE; pmic->desc[i].owner = THIS_MODULE; @@ -945,7 +1244,7 @@ static __devinit int tps65910_probe(struct platform_device *pdev) "failed to register %s regulator\n", pdev->name); err = PTR_ERR(rdev); - goto err; + goto err_unregister_regulator; } /* Save regulator for cleanup */ @@ -953,26 +1252,64 @@ static __devinit int tps65910_probe(struct platform_device *pdev) } return 0; -err: +err_unregister_regulator: while (--i >= 0) regulator_unregister(pmic->rdev[i]); - + kfree(pmic->rdev); +err_free_info: + kfree(pmic->info); +err_free_desc: + kfree(pmic->desc); +err_free_pmic: kfree(pmic); return err; } static int __devexit tps65910_remove(struct platform_device *pdev) { - struct tps65910_reg *tps65910_reg = platform_get_drvdata(pdev); + struct tps65910_reg *pmic = platform_get_drvdata(pdev); int i; - for (i = 0; i < TPS65910_NUM_REGULATOR; i++) - regulator_unregister(tps65910_reg->rdev[i]); + for (i = 0; i < pmic->num_regulators; i++) + regulator_unregister(pmic->rdev[i]); - kfree(tps65910_reg); + kfree(pmic->rdev); + kfree(pmic->info); + kfree(pmic->desc); + kfree(pmic); return 0; } +static void tps65910_shutdown(struct platform_device *pdev) +{ + struct tps65910_reg *pmic = platform_get_drvdata(pdev); + int i; + + /* + * Before bootloader jumps to kernel, it makes sure that required + * external control signals are in desired state so that given rails + * can be configure accordingly. + * If rails are configured to be controlled from external control + * then before shutting down/rebooting the system, the external + * control configuration need to be remove from the rails so that + * its output will be available as per register programming even + * if external controls are removed. This is require when the POR + * value of the control signals are not in active state and before + * bootloader initializes it, the system requires the rail output + * to be active for booting. + */ + for (i = 0; i < pmic->num_regulators; i++) { + int err; + if (!pmic->rdev[i]) + continue; + + err = tps65910_set_ext_sleep_config(pmic, i, 0); + if (err < 0) + dev_err(&pdev->dev, + "Error in clearing external control\n"); + } +} + static struct platform_driver tps65910_driver = { .driver = { .name = "tps65910-pmic", @@ -980,13 +1317,14 @@ static struct platform_driver tps65910_driver = { }, .probe = tps65910_probe, .remove = __devexit_p(tps65910_remove), + .shutdown = tps65910_shutdown, }; static int __init tps65910_init(void) { return platform_driver_register(&tps65910_driver); } -subsys_initcall(tps65910_init); +subsys_initcall_sync(tps65910_init); static void __exit tps65910_cleanup(void) { @@ -995,6 +1333,6 @@ static void __exit tps65910_cleanup(void) module_exit(tps65910_cleanup); MODULE_AUTHOR("Graeme Gregory "); -MODULE_DESCRIPTION("TPS6507x voltage regulator driver"); +MODULE_DESCRIPTION("TPS65910/TPS65911 voltage regulator driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:tps65910-pmic"); diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index a567a8e131e7..bfa8a408fb33 100755 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1110,5 +1110,10 @@ config RTC_DRV_PUV3 This drive can also be built as a module. If so, the module will be called rtc-puv3. +config TPS65910_RTC + tristate "tps65910 rtc for rk" + depends on MFD_TPS65910 + help + enable tps65910 rtc for system endif # RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 3f5e0685673b..6d4c945e6b42 100755 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -115,3 +115,4 @@ obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o obj-$(CONFIG_RTC_HYM8563) += rtc-HYM8563.o obj-$(CONFIG_RTC_M41T66) += rtc-m41t66.o +obj-$(CONFIG_TPS65910_RTC) += rtc-tps65910.o diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c new file mode 100755 index 000000000000..f6a8693cabcf --- /dev/null +++ b/drivers/rtc/rtc-tps65910.c @@ -0,0 +1,695 @@ +/* + * Real Time Clock driver for Wolfson Microelectronics tps65910 + * + * Copyright (C) 2009 Wolfson Microelectronics PLC. + * + * Author: Mark Brown + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* RTC Definitions */ +/* RTC_CTRL_REG bitfields */ +#define BIT_RTC_CTRL_REG_STOP_RTC_M 0x01 +#define BIT_RTC_CTRL_REG_ROUND_30S_M 0x02 +#define BIT_RTC_CTRL_REG_AUTO_COMP_M 0x04 +#define BIT_RTC_CTRL_REG_MODE_12_24_M 0x08 +#define BIT_RTC_CTRL_REG_TEST_MODE_M 0x10 +#define BIT_RTC_CTRL_REG_SET_32_COUNTER_M 0x20 +#define BIT_RTC_CTRL_REG_GET_TIME_M 0x40 +#define BIT_RTC_CTRL_REG_RTC_V_OPT_M 0x80 + +/* RTC_STATUS_REG bitfields */ +#define BIT_RTC_STATUS_REG_RUN_M 0x02 +#define BIT_RTC_STATUS_REG_1S_EVENT_M 0x04 +#define BIT_RTC_STATUS_REG_1M_EVENT_M 0x08 +#define BIT_RTC_STATUS_REG_1H_EVENT_M 0x10 +#define BIT_RTC_STATUS_REG_1D_EVENT_M 0x20 +#define BIT_RTC_STATUS_REG_ALARM_M 0x40 +#define BIT_RTC_STATUS_REG_POWER_UP_M 0x80 + +/* RTC_INTERRUPTS_REG bitfields */ +#define BIT_RTC_INTERRUPTS_REG_EVERY_M 0x03 +#define BIT_RTC_INTERRUPTS_REG_IT_TIMER_M 0x04 +#define BIT_RTC_INTERRUPTS_REG_IT_ALARM_M 0x08 + +/* DEVCTRL bitfields */ +#define BIT_RTC_PWDN 0x40 + +/* REG_SECONDS_REG through REG_YEARS_REG is how many registers? */ +#define ALL_TIME_REGS 7 +#define ALL_ALM_REGS 6 + + +#define RTC_SET_TIME_RETRIES 5 +#define RTC_GET_TIME_RETRIES 5 + + +struct tps65910_rtc { + struct tps65910 *tps65910; + struct rtc_device *rtc; + unsigned int alarm_enabled:1; +}; + +/* + * Read current time and date in RTC + */ +static int tps65910_rtc_readtime(struct device *dev, struct rtc_time *tm) +{ + struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(dev); + struct tps65910 *tps65910 = tps65910_rtc->tps65910; + int ret; + int count = 0; + unsigned char rtc_data[ALL_TIME_REGS + 1]; + u8 rtc_ctl; + + /*Dummy read*/ + ret = tps65910_reg_read(tps65910, TPS65910_RTC_CTRL); + + /* Has the RTC been programmed? */ + ret = tps65910_reg_read(tps65910, TPS65910_RTC_CTRL); + if (ret < 0) { + dev_err(dev, "Failed to read RTC control: %d\n", ret); + return ret; + } + + rtc_ctl = ret & (~BIT_RTC_CTRL_REG_RTC_V_OPT_M); + + ret = tps65910_reg_write(tps65910, TPS65910_RTC_CTRL, rtc_ctl); + if (ret < 0) { + dev_err(dev, "Failed to write RTC control: %d\n", ret); + return ret; + } + + + /* Read twice to make sure we don't read a corrupt, partially + * incremented, value. + */ + do { + ret = tps65910_bulk_read(tps65910, TPS65910_SECONDS, + ALL_TIME_REGS, rtc_data); + if (ret != 0) + continue; + + tm->tm_sec = bcd2bin(rtc_data[0]); + tm->tm_min = bcd2bin(rtc_data[1]); + tm->tm_hour = bcd2bin(rtc_data[2]); + tm->tm_mday = bcd2bin(rtc_data[3]); + tm->tm_mon = bcd2bin(rtc_data[4]) - 1; + tm->tm_year = bcd2bin(rtc_data[5]) + 100; + tm->tm_wday = bcd2bin(rtc_data[6]); + + dev_dbg(dev, "RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", + 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, tm->tm_wday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + return ret; + + } while (++count < RTC_GET_TIME_RETRIES); + dev_err(dev, "Timed out reading current time\n"); + + return -EIO; + +} + +/* + * Set current time and date in RTC + */ +static int tps65910_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(dev); + struct tps65910 *tps65910 = tps65910_rtc->tps65910; + int ret; + u8 rtc_ctl; + unsigned char rtc_data[ALL_TIME_REGS + 1]; + + rtc_data[0] = bin2bcd(tm->tm_sec); + rtc_data[1] = bin2bcd(tm->tm_min); + rtc_data[2] = bin2bcd(tm->tm_hour); + rtc_data[3] = bin2bcd(tm->tm_mday); + rtc_data[4] = bin2bcd(tm->tm_mon + 1); + rtc_data[5] = bin2bcd(tm->tm_year - 100); + rtc_data[6] = bin2bcd(tm->tm_wday); + + /*Dummy read*/ + ret = tps65910_reg_read(tps65910, TPS65910_RTC_CTRL); + + /* Stop RTC while updating the TC registers */ + ret = tps65910_reg_read(tps65910, TPS65910_RTC_CTRL); + if (ret < 0) { + dev_err(dev, "Failed to read RTC control: %d\n", ret); + return ret; + } + + rtc_ctl = ret & (~BIT_RTC_CTRL_REG_STOP_RTC_M); + + ret = tps65910_reg_write(tps65910, TPS65910_RTC_CTRL, rtc_ctl); + if (ret < 0) { + dev_err(dev, "Failed to write RTC control: %d\n", ret); + return ret; + } + + /* update all the time registers in one shot */ + ret = tps65910_bulk_write(tps65910, TPS65910_SECONDS, + ALL_TIME_REGS, rtc_data); + if (ret < 0) { + dev_err(dev, "Failed to read RTC times: %d\n", ret); + return ret; + } + + /*Dummy read*/ + ret = tps65910_reg_read(tps65910, TPS65910_RTC_CTRL); + + /* Start RTC again */ + ret = tps65910_reg_read(tps65910, TPS65910_RTC_CTRL); + if (ret < 0) { + dev_err(dev, "Failed to read RTC control: %d\n", ret); + return ret; + } + + rtc_ctl = ret | BIT_RTC_CTRL_REG_STOP_RTC_M; + + ret = tps65910_reg_write(tps65910, TPS65910_RTC_CTRL, rtc_ctl); + if (ret < 0) { + dev_err(dev, "Failed to write RTC control: %d\n", ret); + return ret; + } + + return 0; +} + +/* + * Read alarm time and date in RTC + */ +static int tps65910_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(dev); + int ret; + unsigned char alrm_data[ALL_ALM_REGS + 1]; + + ret = tps65910_bulk_read(tps65910_rtc->tps65910, TPS65910_ALARM_SECONDS, + ALL_ALM_REGS, alrm_data); + if (ret != 0) { + dev_err(dev, "Failed to read alarm time: %d\n", ret); + return ret; + } + + /* some of these fields may be wildcard/"match all" */ + alrm->time.tm_sec = bcd2bin(alrm_data[0]); + alrm->time.tm_min = bcd2bin(alrm_data[1]); + alrm->time.tm_hour = bcd2bin(alrm_data[2]); + alrm->time.tm_mday = bcd2bin(alrm_data[3]); + alrm->time.tm_mon = bcd2bin(alrm_data[4]) - 1; + alrm->time.tm_year = bcd2bin(alrm_data[5]) + 100; + + ret = tps65910_reg_read(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS); + if (ret < 0) { + dev_err(dev, "Failed to read RTC control: %d\n", ret); + return ret; + } + + if (ret & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M) + alrm->enabled = 1; + else + alrm->enabled = 0; + + return 0; +} + +static int tps65910_rtc_stop_alarm(struct tps65910_rtc *tps65910_rtc) +{ + tps65910_rtc->alarm_enabled = 0; + + return tps65910_clear_bits(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS, + BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); + +} + +static int tps65910_rtc_start_alarm(struct tps65910_rtc *tps65910_rtc) +{ + tps65910_rtc->alarm_enabled = 1; + + return tps65910_set_bits(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS, + BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); + +} + +static int tps65910_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(dev); + int ret; + unsigned char alrm_data[ALL_TIME_REGS + 1]; + + ret = tps65910_rtc_stop_alarm(tps65910_rtc); + if (ret < 0) { + dev_err(dev, "Failed to stop alarm: %d\n", ret); + return ret; + } + + alrm_data[0] = bin2bcd(alrm->time.tm_sec); + alrm_data[1] = bin2bcd(alrm->time.tm_min); + alrm_data[2] = bin2bcd(alrm->time.tm_hour); + alrm_data[3] = bin2bcd(alrm->time.tm_mday); + alrm_data[4] = bin2bcd(alrm->time.tm_mon + 1); + alrm_data[5] = bin2bcd(alrm->time.tm_year - 100); + + ret = tps65910_bulk_write(tps65910_rtc->tps65910, TPS65910_ALARM_SECONDS, + ALL_ALM_REGS, alrm_data); + if (ret != 0) { + dev_err(dev, "Failed to read alarm time: %d\n", ret); + return ret; + } + + if (alrm->enabled) { + ret = tps65910_rtc_start_alarm(tps65910_rtc); + if (ret < 0) { + dev_err(dev, "Failed to start alarm: %d\n", ret); + return ret; + } + } + + return 0; +} + +static int tps65910_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(dev); + + if (enabled) + return tps65910_rtc_start_alarm(tps65910_rtc); + else + return tps65910_rtc_stop_alarm(tps65910_rtc); +} + +static int tps65910_rtc_update_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(dev); + + if (enabled) + return tps65910_set_bits(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS, + BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); + else + return tps65910_clear_bits(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS, + BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); +} + +/* + * We will just handle setting the frequency and make use the framework for + * reading the periodic interupts. + * + * @freq: Current periodic IRQ freq: + * bit 0: every second + * bit 1: every minute + * bit 2: every hour + * bit 3: every day + */ +static int tps65910_rtc_irq_set_freq(struct device *dev, int freq) +{ + struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(dev); + int ret; + u8 rtc_ctl; + + if (freq < 0 || freq > 3) + return -EINVAL; + + ret = tps65910_reg_read(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS); + if (ret < 0) { + dev_err(dev, "Failed to read RTC interrupt: %d\n", ret); + return ret; + } + + rtc_ctl = ret | freq; + + ret = tps65910_reg_write(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS, rtc_ctl); + if (ret < 0) { + dev_err(dev, "Failed to write RTC control: %d\n", ret); + return ret; + } + + return ret; +} + + + +static irqreturn_t tps65910_alm_irq(int irq, void *data) +{ + struct tps65910_rtc *tps65910_rtc = data; + + rtc_update_irq(tps65910_rtc->rtc, 1, RTC_IRQF | RTC_AF); + + return IRQ_HANDLED; +} + +static irqreturn_t tps65910_per_irq(int irq, void *data) +{ + struct tps65910_rtc *tps65910_rtc = data; + + rtc_update_irq(tps65910_rtc->rtc, 1, RTC_IRQF | RTC_UF); + + //printk("%s:irq=%d\n",__func__,irq); + return IRQ_HANDLED; +} + +static const struct rtc_class_ops tps65910_rtc_ops = { + .read_time = tps65910_rtc_readtime, + //.set_mmss = tps65910_rtc_set_mmss, + .set_time = tps65910_rtc_set_time, + .read_alarm = tps65910_rtc_readalarm, + .set_alarm = tps65910_rtc_setalarm, + .alarm_irq_enable = tps65910_rtc_alarm_irq_enable, + //.update_irq_enable = tps65910_rtc_update_irq_enable, + //.irq_set_freq = tps65910_rtc_irq_set_freq, +}; + +#ifdef CONFIG_PM +/* Turn off the alarm if it should not be a wake source. */ +static int tps65910_rtc_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(&pdev->dev); + int ret; + + if (tps65910_rtc->alarm_enabled && device_may_wakeup(&pdev->dev)) + ret = tps65910_rtc_start_alarm(tps65910_rtc); + else + ret = tps65910_rtc_stop_alarm(tps65910_rtc); + + if (ret != 0) + dev_err(&pdev->dev, "Failed to update RTC alarm: %d\n", ret); + + return 0; +} + +/* Enable the alarm if it should be enabled (in case it was disabled to + * prevent use as a wake source). + */ +static int tps65910_rtc_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(&pdev->dev); + int ret; + + if (tps65910_rtc->alarm_enabled) { + ret = tps65910_rtc_start_alarm(tps65910_rtc); + if (ret != 0) + dev_err(&pdev->dev, + "Failed to restart RTC alarm: %d\n", ret); + } + + return 0; +} + +/* Unconditionally disable the alarm */ +static int tps65910_rtc_freeze(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(&pdev->dev); + int ret; + + ret = tps65910_rtc_stop_alarm(tps65910_rtc); + if (ret != 0) + dev_err(&pdev->dev, "Failed to stop RTC alarm: %d\n", ret); + + return 0; +} +#else +#define tps65910_rtc_suspend NULL +#define tps65910_rtc_resume NULL +#define tps65910_rtc_freeze NULL +#endif + +struct platform_device *g_pdev; +static int tps65910_rtc_probe(struct platform_device *pdev) +{ + struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); + struct tps65910_rtc *tps65910_rtc; + int per_irq; + int alm_irq; + int ret = 0; + u8 rtc_ctl; + + struct rtc_time tm; + struct rtc_time tm_def = { // 2012.1.1 12:00:00 Saturday + .tm_wday = 6, + .tm_year = 111, + .tm_mon = 0, + .tm_mday = 1, + .tm_hour = 12, + .tm_min = 0, + .tm_sec = 0, + }; + + tps65910_rtc = kzalloc(sizeof(*tps65910_rtc), GFP_KERNEL); + if (tps65910_rtc == NULL) + return -ENOMEM; + + platform_set_drvdata(pdev, tps65910_rtc); + tps65910_rtc->tps65910 = tps65910; + per_irq = tps65910->irq_base + TPS65910_IRQ_RTC_PERIOD; + alm_irq = tps65910->irq_base + TPS65910_IRQ_RTC_ALARM; + + /* Take rtc out of reset */ + ret = tps65910_reg_read(tps65910, TPS65910_DEVCTRL); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to read TPS65910_DEVCTRL: %d\n", ret); + return ret; + } + + if(ret & BIT_RTC_PWDN) + { + rtc_ctl = ret & (~BIT_RTC_PWDN); + + ret = tps65910_reg_write(tps65910, TPS65910_DEVCTRL, rtc_ctl); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to write RTC control: %d\n", ret); + return ret; + } + } + + /*start rtc default*/ + ret = tps65910_reg_read(tps65910, TPS65910_RTC_CTRL); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to read RTC control: %d\n", ret); + return ret; + } + + if(!(ret & BIT_RTC_CTRL_REG_STOP_RTC_M)) + { + rtc_ctl = ret | BIT_RTC_CTRL_REG_STOP_RTC_M; + + ret = tps65910_reg_write(tps65910, TPS65910_RTC_CTRL, rtc_ctl); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to write RTC control: %d\n", ret); + return ret; + } + } + + ret = tps65910_reg_read(tps65910, TPS65910_RTC_STATUS); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to read RTC status: %d\n", ret); + return ret; + } + + /*set init time*/ + ret = tps65910_rtc_readtime(&pdev->dev, &tm); + if (ret) + { + dev_err(&pdev->dev, "Failed to read RTC time\n"); + return ret; + } + + ret = rtc_valid_tm(&tm); + if (ret) { + dev_err(&pdev->dev,"invalid date/time and init time\n"); + tps65910_rtc_set_time(&pdev->dev, &tm_def); // 2011-01-01 12:00:00 + dev_info(&pdev->dev, "set RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", + 1900 + tm_def.tm_year, tm_def.tm_mon + 1, tm_def.tm_mday, tm_def.tm_wday, + tm_def.tm_hour, tm_def.tm_min, tm_def.tm_sec); + } + + device_init_wakeup(&pdev->dev, 1); + + tps65910_rtc->rtc = rtc_device_register("tps65910", &pdev->dev, + &tps65910_rtc_ops, THIS_MODULE); + if (IS_ERR(tps65910_rtc->rtc)) { + ret = PTR_ERR(tps65910_rtc->rtc); + goto err; + } + + /*request rtc and alarm irq of tps65910*/ + ret = request_threaded_irq(per_irq, NULL, tps65910_per_irq, + IRQF_TRIGGER_RISING, "RTC period", + tps65910_rtc); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to request periodic IRQ %d: %d\n", + per_irq, ret); + } + + ret = request_threaded_irq(alm_irq, NULL, tps65910_alm_irq, + IRQF_TRIGGER_RISING, "RTC alarm", + tps65910_rtc); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n", + alm_irq, ret); + } + + //for rtc irq test + //tps65910_set_bits(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS, + // BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); + + g_pdev = pdev; + + printk("%s:ok\n",__func__); + + return 0; + +err: + kfree(tps65910_rtc); + return ret; +} + +static int __devexit tps65910_rtc_remove(struct platform_device *pdev) +{ + struct tps65910_rtc *tps65910_rtc = platform_get_drvdata(pdev); + int per_irq = tps65910_rtc->tps65910->irq_base + TPS65910_IRQ_RTC_PERIOD; + int alm_irq = tps65910_rtc->tps65910->irq_base + TPS65910_IRQ_RTC_ALARM; + + free_irq(alm_irq, tps65910_rtc); + free_irq(per_irq, tps65910_rtc); + rtc_device_unregister(tps65910_rtc->rtc); + kfree(tps65910_rtc); + + return 0; +} + +static const struct dev_pm_ops tps65910_rtc_pm_ops = { + .suspend = tps65910_rtc_suspend, + .resume = tps65910_rtc_resume, + + .freeze = tps65910_rtc_freeze, + .thaw = tps65910_rtc_resume, + .restore = tps65910_rtc_resume, + + .poweroff = tps65910_rtc_suspend, +}; + +static struct platform_driver tps65910_rtc_driver = { + .probe = tps65910_rtc_probe, + .remove = __devexit_p(tps65910_rtc_remove), + .driver = { + .name = "tps65910-rtc", + .pm = &tps65910_rtc_pm_ops, + }, +}; + +static ssize_t rtc_tps65910_test_write(struct file *file, + const char __user *buf, size_t count, loff_t *offset) +{ + char nr_buf[8]; + int nr = 0, ret; + struct platform_device *pdev; + struct rtc_time tm; + + if(count > 3) + return -EFAULT; + ret = copy_from_user(nr_buf, buf, count); + if(ret < 0) + return -EFAULT; + + sscanf(nr_buf, "%d", &nr); + if(nr >= 2 || nr < 0) + { + printk("%s:data is error\n",__func__); + return -EFAULT; + } + + if(!g_pdev) + return -EFAULT; + else + pdev = g_pdev; + + if(nr == 0) + { + tm.tm_wday = 6; + tm.tm_year = 111; + tm.tm_mon = 0; + tm.tm_mday = 1; + tm.tm_hour = 12; + tm.tm_min = 0; + tm.tm_sec = 0; + + ret = tps65910_rtc_set_time(&pdev->dev, &tm); // 2011-01-01 12:00:00 + if (ret) + { + dev_err(&pdev->dev, "Failed to set RTC time\n"); + return -EFAULT; + } + + } + + /*set init time*/ + ret = tps65910_rtc_readtime(&pdev->dev, &tm); + if (ret) + dev_err(&pdev->dev, "Failed to read RTC time\n"); + else + dev_info(&pdev->dev, "RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", + 1900 + tm.tm_year, tm.tm_mon + 1, tm.tm_mday, tm.tm_wday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + + if(!ret) + printk("%s:ok\n",__func__); + else + printk("%s:error\n",__func__); + + return count; +} + +static const struct file_operations rtc_tps65910_test_fops = { + .write = rtc_tps65910_test_write, +}; + +static struct miscdevice rtc_tps65910_test_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "rtc_tps65910_test", + .fops = &rtc_tps65910_test_fops, +}; + + +static int __init tps65910_rtc_init(void) +{ + misc_register(&rtc_tps65910_test_misc); + return platform_driver_register(&tps65910_rtc_driver); +} +subsys_initcall_sync(tps65910_rtc_init); + +static void __exit tps65910_rtc_exit(void) +{ + misc_deregister(&rtc_tps65910_test_misc); + platform_driver_unregister(&tps65910_rtc_driver); +} +module_exit(tps65910_rtc_exit); + +MODULE_DESCRIPTION("RTC driver for the tps65910 series PMICs"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:tps65910-rtc"); diff --git a/include/linux/mfd/tps65910.h b/include/linux/mfd/tps65910.h old mode 100644 new mode 100755 index 8bb85b930c07..c093c477477b --- a/include/linux/mfd/tps65910.h +++ b/include/linux/mfd/tps65910.h @@ -17,6 +17,8 @@ #ifndef __LINUX_MFD_TPS65910_H #define __LINUX_MFD_TPS65910_H +#include + /* TPS chip id list */ #define TPS65910 0 #define TPS65911 1 @@ -25,6 +27,10 @@ #define REGULATOR_LDO 0 #define REGULATOR_DCDC 1 +/* I2C Slave Address 7-bit */ +#define TPS65910_I2C_ID0 0x2D /* general-purpose */ +#define TPS65910_I2C_ID1 0x12 /* Smart Reflex */ + /* * List of registers for component TPS65910 * @@ -243,7 +249,8 @@ /*Registers VDD1, VDD2 voltage values definitions */ -#define VDD1_2_NUM_VOLTS 73 +#define VDD1_2_NUM_VOLT_FINE 73 +#define VDD1_2_NUM_VOLT_COARSE 3 #define VDD1_2_MIN_VOLT 6000 #define VDD1_2_OFFSET 125 @@ -269,7 +276,7 @@ #define LDO1_SEL_MASK 0xFC #define LDO3_SEL_MASK 0x7C #define LDO_MIN_VOLT 1000 -#define LDO_MAX_VOLT 3300; +#define LDO_MAX_VOLT 3300 /*Register VDIG1 (0x80) register.RegisterDescription */ @@ -361,7 +368,7 @@ #define DCDCCTRL_DCDCCKSYNC_SHIFT 0 -/*Register DEVCTRL (0x80) register.RegisterDescription */ +/*Register DEVCTRL (0x3F) register.RegisterDescription */ #define DEVCTRL_RTC_PWDN_MASK 0x40 #define DEVCTRL_RTC_PWDN_SHIFT 6 #define DEVCTRL_CK32K_CTRL_MASK 0x20 @@ -378,7 +385,7 @@ #define DEVCTRL_DEV_OFF_SHIFT 0 -/*Register DEVCTRL2 (0x80) register.RegisterDescription */ +/*Register DEVCTRL2 (0x40) register.RegisterDescription */ #define DEVCTRL2_TSLOT_LENGTH_MASK 0x30 #define DEVCTRL2_TSLOT_LENGTH_SHIFT 4 #define DEVCTRL2_SLEEPSIG_POL_MASK 0x08 @@ -656,6 +663,8 @@ /*Register GPIO (0x80) register.RegisterDescription */ +#define GPIO_SLEEP_MASK 0x80 +#define GPIO_SLEEP_SHIFT 7 #define GPIO_DEB_MASK 0x10 #define GPIO_DEB_SHIFT 4 #define GPIO_PUEN_MASK 0x08 @@ -739,19 +748,50 @@ #define TPS65910_GPIO_STS BIT(1) #define TPS65910_GPIO_SET BIT(0) -/** - * struct tps65910_board - * Board platform data may be used to initialize regulators. - */ +/* Max number of TPS65910/11 GPIOs */ +#define TPS65910_NUM_GPIO 6 +#define TPS65911_NUM_GPIO 9 +#define TPS6591X_MAX_NUM_GPIO 9 + +/* Regulator Index Definitions */ +#define TPS65910_REG_VRTC 0 +#define TPS65910_REG_VIO 1 +#define TPS65910_REG_VDD1 2 +#define TPS65910_REG_VDD2 3 +#define TPS65910_REG_VDD3 4 +#define TPS65910_REG_VDIG1 5 +#define TPS65910_REG_VDIG2 6 +#define TPS65910_REG_VPLL 7 +#define TPS65910_REG_VDAC 8 +#define TPS65910_REG_VAUX1 9 +#define TPS65910_REG_VAUX2 10 +#define TPS65910_REG_VAUX33 11 +#define TPS65910_REG_VMMC 12 + +#define TPS65911_REG_VDDCTRL 4 +#define TPS65911_REG_LDO1 5 +#define TPS65911_REG_LDO2 6 +#define TPS65911_REG_LDO3 7 +#define TPS65911_REG_LDO4 8 +#define TPS65911_REG_LDO5 9 +#define TPS65911_REG_LDO6 10 +#define TPS65911_REG_LDO7 11 +#define TPS65911_REG_LDO8 12 + +/* Max number of TPS65910/11 regulators */ +#define TPS65910_NUM_REGS 13 + +/* External sleep controls through EN1/EN2/EN3/SLEEP inputs */ +#define TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1 0x1 +#define TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2 0x2 +#define TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3 0x4 +#define TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP 0x8 + + + + + -struct tps65910_board { - int gpio_base; - int irq; - int irq_base; - int vmbch_threshold; - int vmbch2_threshold; - struct regulator_init_data *tps65910_pmic_init_data; -}; /** * struct tps65910 - tps65910 sub-driver chip access routines @@ -760,15 +800,16 @@ struct tps65910_board { struct tps65910 { struct device *dev; struct i2c_client *i2c_client; + struct regmap *regmap; struct mutex io_mutex; unsigned int id; int (*read)(struct tps65910 *tps65910, u8 reg, int size, void *dest); int (*write)(struct tps65910 *tps65910, u8 reg, int size, void *src); /* Client devices */ - struct tps65910_pmic *pmic; - struct tps65910_rtc *rtc; - struct tps65910_power *power; + //struct tps65910_pmic *pmic; + //struct tps65910_rtc *rtc; + //struct tps65910_power *power; /* GPIO Handling */ struct gpio_chip gpio; @@ -786,11 +827,45 @@ struct tps65910_platform_data { int irq_base; }; + +/** + * struct tps65910_board + * Board platform data may be used to initialize regulators. + */ + +struct tps65910_board { + int gpio_base; + int irq; + int irq_base; + int vmbch_threshold; + int vmbch2_threshold; + bool en_gpio_sleep[TPS6591X_MAX_NUM_GPIO]; + unsigned long regulator_ext_sleep_control[TPS65910_NUM_REGS]; + struct regulator_init_data *tps65910_pmic_init_data[TPS65910_NUM_REGS]; + + /** Called before subdevices are set up */ + int (*pre_init)(struct tps65910 *tps65910); + /** Called after subdevices are set up */ + int (*post_init)(struct tps65910 *tps65910); + /** Called before subdevices are power down */ + int (*last_deinit)(struct tps65910 *tps65910); +}; + + int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask); int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask); void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base); int tps65910_irq_init(struct tps65910 *tps65910, int irq, struct tps65910_platform_data *pdata); +int tps65910_irq_exit(struct tps65910 *tps65910); +int tps65910_reg_read(struct tps65910 *tps65910, u8 reg); +int tps65910_reg_write(struct tps65910 *tps65910, u8 reg, u8 val); +int tps65910_bulk_read(struct tps65910 *tps65910, u8 reg, + int count, u8 *buf); +int tps65910_bulk_write(struct tps65910 *tps65910, u8 reg, + int count, u8 *buf); +int tps65910_device_shutdown(void); + static inline int tps65910_chip_id(struct tps65910 *tps65910) { From 68e8ac6ea57647e40e9e0ef52170d65ea2d00750 Mon Sep 17 00:00:00 2001 From: hhb Date: Thu, 9 Aug 2012 18:25:20 +0800 Subject: [PATCH 130/261] rk_serial: update serial driver --- drivers/tty/serial/Kconfig | 32 +- drivers/tty/serial/rk_serial.c | 736 +++++++++++++++++---------------- 2 files changed, 406 insertions(+), 362 deletions(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 4763420c6a4a..d3c690a3ddf9 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1526,9 +1526,13 @@ config UART0_CTS_RTS_RK29 depends on UART0_RK29 config UART0_DMA_RK29 - bool "Serial port 0 DMA support (EXPERIMENTAL)" + int "Serial port 0 DMA support (EXPERIMENTAL)" depends on UART0_RK29 - + default 0 + help + 1:enable dma tx + 2:enable dma rx + 3:both enable dma tx and rx config UART1_RK29 bool "Serial port 1 support" depends on SERIAL_RK29 @@ -1538,9 +1542,13 @@ config UART1_CTS_RTS_RK29 depends on UART1_RK29 && !ARCH_RK29 config UART1_DMA_RK29 - bool "Serial port 1 DMA support (EXPERIMENTAL)" + int "Serial port 1 DMA support (EXPERIMENTAL)" depends on UART1_RK29 - + default 0 + help + 1:enable dma tx + 2:enable dma rx + 3:both enable dma tx and rx config UART2_RK29 bool "Serial port 2 support" depends on SERIAL_RK29 @@ -1550,9 +1558,13 @@ config UART2_CTS_RTS_RK29 depends on UART2_RK29 && !ARCH_RK30 config UART2_DMA_RK29 - bool "Serial port 2 DMA support (EXPERIMENTAL)" + int "Serial port 2 DMA support (EXPERIMENTAL)" depends on UART2_RK29 - + default 0 + help + 1:enable dma tx + 2:enable dma rx + 3:both enable dma tx and rx config UART3_RK29 bool "Serial port 3 support" depends on SERIAL_RK29 @@ -1562,9 +1574,13 @@ config UART3_CTS_RTS_RK29 depends on UART3_RK29 config UART3_DMA_RK29 - bool "Serial port 3 DMA support (EXPERIMENTAL)" + int "Serial port 3 DMA support (EXPERIMENTAL)" depends on UART3_RK29 - + default 0 + help + 1:enable dma tx + 2:enable dma rx + 3:both enable dma tx and rx config SERIAL_RK29_CONSOLE bool "Serial console support" depends on SERIAL_RK29=y diff --git a/drivers/tty/serial/rk_serial.c b/drivers/tty/serial/rk_serial.c index b4d4756c80fd..7b41d278ec5c 100644 --- a/drivers/tty/serial/rk_serial.c +++ b/drivers/tty/serial/rk_serial.c @@ -24,7 +24,6 @@ #define SUPPORT_SYSRQ #endif -//#define DEBUG #include #include #include @@ -38,7 +37,6 @@ #include #include #include -#include #include #include #include @@ -50,6 +48,16 @@ #include #include +/* +* Driver Version Note +* +*v0.0 : this driver is 2.6.32 kernel driver; +*v0.1 : this driver is 3.0.8 kernel driver; +*v1.0 : 1.modify dma dirver; +* 2.enable Programmable THRE Interrupt Mode, so we can just judge ((up->iir & 0x0f) == 0x02) when transmit +* 3.reset uart and set it to loopback state to ensure setting baud rate sucessfully +*/ +#define VERSION_AND_TIME "rk_serial.c v1.0 2012-08-09" #define PORT_RK 90 #define UART_USR 0x1F /* UART Status Register */ @@ -58,36 +66,45 @@ #define UART_LSR_RFE 0x80 /* receive fifo error */ #define UART_SRR 0x22 /* software reset register */ #define UART_RESET 0x01 -#define RX_TIMEOUT (3000*10) //uint ms #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) #define UART_NR 4 //uart port number -#define POWER_MANEGEMENT 1 -/* configurate whether the port transmit-receive by DMA */ +/* configurate whether the port transmit-receive by DMA in menuconfig*/ #define OPEN_DMA 1 #define CLOSE_DMA 0 -#ifdef CONFIG_UART0_DMA_RK29 -#define UART0_USE_DMA OPEN_DMA +#define TX_DMA (1) +#define RX_DMA (2) + +#ifdef CONFIG_UART0_DMA_RK29 +#define UART0_USE_DMA CONFIG_UART0_DMA_RK29 #else #define UART0_USE_DMA CLOSE_DMA #endif - +#ifdef CONFIG_UART1_DMA_RK29 +#define UART1_USE_DMA CONFIG_UART1_DMA_RK29 +#else +#define UART1_USE_DMA CLOSE_DMA +#endif #ifdef CONFIG_UART2_DMA_RK29 -#define UART2_USE_DMA OPEN_DMA +#define UART2_USE_DMA CONFIG_UART2_DMA_RK29 #else #define UART2_USE_DMA CLOSE_DMA #endif - #ifdef CONFIG_UART3_DMA_RK29 -#define UART3_USE_DMA OPEN_DMA +#define UART3_USE_DMA CONFIG_UART3_DMA_RK29 #else #define UART3_USE_DMA CLOSE_DMA #endif -#define UART1_USE_DMA CLOSE_DMA +#define USE_TIMER 1 // use timer for dma transport +#define POWER_MANEGEMENT 1 +#define RX_TIMEOUT (3000*3) //uint ms +#define DMA_TX_TRRIGE_LEVEL 128 +#define SERIAL_CIRC_CNT_TO_END(xmit) CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE) + #define USE_DMA (UART0_USE_DMA | UART1_USE_DMA | UART2_USE_DMA | UART3_USE_DMA) #if USE_DMA @@ -98,25 +115,24 @@ #endif #endif -#define DMA_TX_TRRIGE_LEVEL 30 -#define USE_TIMER 1 // use timer for dma transport -#define THRE_MODE 0X00 //0yhh static struct uart_driver serial_rk_reg; /* * Debugging. */ +#ifdef CONFIG_ARCH_RK29 #define DBG_PORT 1 //DBG_PORT which uart is used to print log message - +#else +#define DBG_PORT -1 //DBG_PORT which uart is used to print log message +#endif #ifdef CONFIG_SERIAL_CORE_CONSOLE #define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line) #else #define uart_console(port) (0) #endif -#define DEBUG 0 extern void printascii(const char *); static void dbg(const char *fmt, ...) @@ -131,8 +147,13 @@ static void dbg(const char *fmt, ...) printascii(buff); } +//enable log output +#define DEBUG 1 +static int log_port = -1; +module_param(log_port, int, S_IRUGO|S_IWUSR); + #if DEBUG -#define DEBUG_INTR(fmt...) if (!uart_console(&up->port)) dbg(fmt) +#define DEBUG_INTR(fmt...) if (up->port.line == log_port && !uart_console(&up->port)) dbg(fmt) #else #define DEBUG_INTR(fmt...) do { } while (0) #endif @@ -141,31 +162,36 @@ static void dbg(const char *fmt, ...) #if USE_DMA /* added by hhb@rock-chips.com for uart dma transfer */ -struct rk29_uart_dma_t { +struct rk_uart_dma { u32 use_dma; //1:used - u32 rx_dma_start; enum dma_ch rx_dmach; enum dma_ch tx_dmach; - u32 tx_dma_inited; - u32 rx_dma_inited; + + //receive and transfer buffer + char * rx_buffer; //visual memory + char * tx_buffer; + dma_addr_t rx_phy_addr; //physical memory + dma_addr_t tx_phy_addr; + u32 rb_size; //buffer size + u32 tb_size; + + //regard the rx buffer as a circular buffer + u32 rb_head; + u32 rb_tail; + u32 rx_size; + spinlock_t tx_lock; spinlock_t rx_lock; - char * rx_buffer; - char * tx_buffer; - dma_addr_t rx_phy_addr; - dma_addr_t tx_phy_addr; - u32 rx_buffer_size; - u32 tx_buffer_size; - u32 rb_cur_pos; - u32 rb_pre_pos; - u32 rx_size; - char use_timer; - char tx_dma_used; + char tx_dma_inited; //1:dma tx channel has been init + char rx_dma_inited; //1:dma rx channel has been init + char tx_dma_used; //1:dma tx is working + char rx_dma_used; //1:dma rx is working + /* timer to poll activity on rx dma */ - struct timer_list rx_timer; - int rx_timeout; - + char use_timer; + int rx_timeout; + struct timer_list rx_timer; }; #endif @@ -193,27 +219,28 @@ struct uart_rk_port { #endif char name[12]; - char fifo[32]; + char fifo[64]; char fifo_size; unsigned long port_activity; struct work_struct uart_work; struct work_struct uart_work_rx; struct workqueue_struct *uart_wq; #if USE_DMA - struct rk29_uart_dma_t *prk29_uart_dma_t; + struct rk_uart_dma *dma; #endif }; #if USE_DMA static void serial_rk_release_dma_tx(struct uart_port *port); static int serial_rk_start_tx_dma(struct uart_port *port); -static void serial_rk_rx_timeout(unsigned long uart); +//static void serial_rk_rx_timeout(unsigned long uart); static void serial_rk_release_dma_rx(struct uart_port *port); static int serial_rk_start_rx_dma(struct uart_port *port); #else static inline int serial_rk_start_tx_dma(struct uart_port *port) { return 0; } #endif static int serial_rk_startup(struct uart_port *port); + static inline unsigned int serial_in(struct uart_rk_port *up, int offset) { offset = offset << 2; @@ -254,24 +281,25 @@ static inline int serial_dl_read(struct uart_rk_port *up) static int serial_dl_write(struct uart_rk_port *up, unsigned int value) { unsigned int tmout = 100; - if(up->port.line != DBG_PORT) - { - while(!(serial_in(up, UART_LCR) & UART_LCR_DLAB)){ - if (--tmout == 0){ - dbg("set serial.%d baudrate fail with DLAB not set\n", up->port.line); - return -1; - } - } - tmout = 15000; - while(serial_in(up, UART_USR) & UART_USR_BUSY){ - if (--tmout == 0){ - dbg("set serial.%d baudrate timeout\n", up->port.line); - return -1; - } + while(!(serial_in(up, UART_LCR) & UART_LCR_DLAB)){ + if (--tmout == 0){ + if(up->port.line != DBG_PORT) + dbg("set serial.%d baudrate fail with DLAB not set\n", up->port.line); + return -1; } } + tmout = 15000; + while(serial_in(up, UART_USR) & UART_USR_BUSY){ + if (--tmout == 0){ + if(up->port.line != DBG_PORT) + dbg("set serial.%d baudrate timeout\n", up->port.line); + return -1; + } + udelay(1); + } + serial_out(up, UART_DLL, value & 0xff); serial_out(up, UART_DLM, value >> 8 & 0xff); @@ -283,16 +311,13 @@ static int serial_lcr_write(struct uart_rk_port *up, unsigned char value) { unsigned int tmout = 15000; - if(up->port.line != DBG_PORT) - { - while(serial_in(up, UART_USR) & UART_USR_BUSY){ - - if (--tmout == 0){ + while(serial_in(up, UART_USR) & UART_USR_BUSY){ + if (--tmout == 0){ + if(up->port.line != DBG_PORT) dbg("set serial.%d lc r = 0x%02x timeout\n", up->port.line, value); - return -1; - } - udelay(1); + return -1; } + udelay(1); } serial_out(up, UART_LCR, value); @@ -316,7 +341,7 @@ static inline void serial_rk_disable_ier_thri(struct uart_rk_port *up) serial_out(up, UART_IER, up->ier); } } -#if 0 + static int rk29_uart_dump_register(struct uart_rk_port *up){ unsigned int reg_value = 0; @@ -338,7 +363,6 @@ static int rk29_uart_dump_register(struct uart_rk_port *up){ return 0; } -#endif /* * FIFO support. @@ -364,13 +388,13 @@ static void serial_rk_stop_tx(struct uart_port *port) struct uart_rk_port *up = container_of(port, struct uart_rk_port, port); #if USE_DMA - struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t; - - if(OPEN_DMA == prk29_uart_dma_t->use_dma){ + struct rk_uart_dma *uart_dma = up->dma; + if(uart_dma->use_dma & TX_DMA){ serial_rk_release_dma_tx(port); } #endif __stop_tx(up); + } @@ -379,11 +403,16 @@ static void serial_rk_start_tx(struct uart_port *port) struct uart_rk_port *up = container_of(port, struct uart_rk_port, port); - - if(0 == serial_rk_start_tx_dma(port)){ +#if USE_DMA + if(up->dma->use_dma & TX_DMA) { + if(!up->dma->tx_dma_used) + serial_rk_enable_ier_thri(up); + }else { serial_rk_enable_ier_thri(up); } - +#else + serial_rk_enable_ier_thri(up); +#endif } @@ -392,9 +421,8 @@ static void serial_rk_stop_rx(struct uart_port *port) struct uart_rk_port *up = container_of(port, struct uart_rk_port, port); #if USE_DMA - struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t; - - if(OPEN_DMA == prk29_uart_dma_t->use_dma){ + struct rk_uart_dma *uart_dma = up->dma; + if(uart_dma->use_dma & RX_DMA){ serial_rk_release_dma_rx(port); } #endif @@ -425,17 +453,17 @@ static void serial_rk_enable_ms(struct uart_port *port) #define DMA_SERIAL_BUFFER_SIZE UART_XMIT_SIZE /* added by hhb@rock-chips.com for uart dma transfer*/ -static struct rk29_uart_dma_t rk29_uart_ports_dma_t[] = { - {UART0_USE_DMA, 0, DMACH_UART0_RX, DMACH_UART0_TX}, - {UART1_USE_DMA, 0, DMACH_UART1_RX, DMACH_UART1_TX}, - {UART2_USE_DMA, 0, DMACH_UART2_RX, DMACH_UART2_TX}, - {UART3_USE_DMA, 0, DMACH_UART3_RX, DMACH_UART3_TX}, +static struct rk_uart_dma rk29_uart_ports_dma[] = { + {UART0_USE_DMA, DMACH_UART0_RX, DMACH_UART0_TX}, + {UART1_USE_DMA, DMACH_UART1_RX, DMACH_UART1_TX}, + {UART2_USE_DMA, DMACH_UART2_RX, DMACH_UART2_TX}, + {UART3_USE_DMA, DMACH_UART3_RX, DMACH_UART3_TX}, }; /* DMAC PL330 add by hhb@rock-chips.com */ static struct rk29_dma_client rk29_uart_dma_client = { - .name = "rk29xx-uart-dma", + .name = "rk-uart-dma", }; /*TX*/ @@ -444,13 +472,14 @@ static void serial_rk_release_dma_tx(struct uart_port *port) { struct uart_rk_port *up = container_of(port, struct uart_rk_port, port); - struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t; + struct rk_uart_dma *uart_dma = up->dma; if(!port){ return; } - if(prk29_uart_dma_t && prk29_uart_dma_t->tx_dma_inited) { - rk29_dma_free(prk29_uart_dma_t->tx_dmach, &rk29_uart_dma_client); - prk29_uart_dma_t->tx_dma_inited = 0; + if(uart_dma && uart_dma->tx_dma_inited) { + rk29_dma_free(uart_dma->tx_dmach, &rk29_uart_dma_client); + uart_dma->tx_dma_inited = 0; + uart_dma->tx_dma_used = 0; } } @@ -461,21 +490,21 @@ static void serial_rk_dma_txcb(void *buf, int size, enum rk29_dma_buffresult res struct circ_buf *xmit = &port->state->xmit; if(result != RK29_RES_OK){ + printk(">>>>%s:%d result:%d\n", __func__, __LINE__, result); + up->dma->tx_dma_used = 0; return; } - port->icount.tx += size; + //spin_lock(&(up->dma->rx_lock)); xmit->tail = (xmit->tail + size) & (UART_XMIT_SIZE - 1); - + port->icount.tx += size; if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&up->port); - spin_lock(&(up->prk29_uart_dma_t->tx_lock)); - up->prk29_uart_dma_t->tx_dma_used = 0; - spin_unlock(&(up->prk29_uart_dma_t->tx_lock)); - if (!uart_circ_empty(xmit)) { - serial_rk_start_tx_dma(port); - } + //spin_lock(&(up->dma->tx_lock)); + up->dma->tx_dma_used = 0; + //spin_unlock(&(up->dma->tx_lock)); + serial_rk_enable_ier_thri(up); up->port_activity = jiffies; // dev_info(up->port.dev, "s:%d\n", size); } @@ -484,35 +513,38 @@ static int serial_rk_init_dma_tx(struct uart_port *port) { struct uart_rk_port *up = container_of(port, struct uart_rk_port, port); - struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t; - if(!port || !prk29_uart_dma_t){ + struct rk_uart_dma *uart_dma = up->dma; + + if(!port || !uart_dma){ dev_info(up->port.dev, "serial_rk_init_dma_tx fail\n"); return -1; } - if(prk29_uart_dma_t->tx_dma_inited) { + if(uart_dma->tx_dma_inited) { return 0; } - if (rk29_dma_request(prk29_uart_dma_t->tx_dmach, &rk29_uart_dma_client, NULL) == -EBUSY) { + if (rk29_dma_request(uart_dma->tx_dmach, &rk29_uart_dma_client, NULL) == -EBUSY) { dev_info(up->port.dev, "rk29_dma_request tx fail\n"); return -1; } - if (rk29_dma_set_buffdone_fn(prk29_uart_dma_t->tx_dmach, serial_rk_dma_txcb)) { + if (rk29_dma_set_buffdone_fn(uart_dma->tx_dmach, serial_rk_dma_txcb)) { dev_info(up->port.dev, "rk29_dma_set_buffdone_fn tx fail\n"); return -1; } - if (rk29_dma_devconfig(prk29_uart_dma_t->tx_dmach, RK29_DMASRC_MEM, (unsigned long)(port->iobase + UART_TX))) { + + if (rk29_dma_devconfig(uart_dma->tx_dmach, RK29_DMASRC_MEM, (unsigned long)(port->iobase + UART_TX))) { dev_info(up->port.dev, "rk29_dma_devconfig tx fail\n"); return -1; } - if (rk29_dma_config(prk29_uart_dma_t->tx_dmach, 1, 1)) { + + if (rk29_dma_config(uart_dma->tx_dmach, 1, 16)) { dev_info(up->port.dev, "rk29_dma_config tx fail\n"); return -1; } - prk29_uart_dma_t->tx_dma_inited = 1; + uart_dma->tx_dma_inited = 1; dev_info(up->port.dev, "serial_rk_init_dma_tx sucess\n"); return 0; @@ -520,39 +552,37 @@ static int serial_rk_init_dma_tx(struct uart_port *port) { static int serial_rk_start_tx_dma(struct uart_port *port) { - + int count = 0; struct circ_buf *xmit = &port->state->xmit; struct uart_rk_port *up = container_of(port, struct uart_rk_port, port); - struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t; + struct rk_uart_dma *uart_dma = up->dma; - if(0 == prk29_uart_dma_t->use_dma){ - return CLOSE_DMA; - } - - if(-1 == serial_rk_init_dma_tx(port)){ + if(!uart_dma->use_dma) goto err_out; - } - if (1 == prk29_uart_dma_t->tx_dma_used){ + if(-1 == serial_rk_init_dma_tx(port)) + goto err_out; + + if (1 == uart_dma->tx_dma_used) return 1; - } - if(!uart_circ_empty(xmit)){ - if (rk29_dma_enqueue(prk29_uart_dma_t->tx_dmach, port, - prk29_uart_dma_t->tx_phy_addr + xmit->tail, - CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE))) { + +// spin_lock(&(uart_dma->tx_lock)); + __stop_tx(up); + + count = SERIAL_CIRC_CNT_TO_END(xmit); + count -= count%16; + if(count >= DMA_TX_TRRIGE_LEVEL) { + if (rk29_dma_enqueue(uart_dma->tx_dmach, port, uart_dma->tx_phy_addr + xmit->tail , count)) { goto err_out; } + rk29_dma_ctrl(uart_dma->tx_dmach, RK29_DMAOP_START); + up->dma->tx_dma_used = 1; } - rk29_dma_ctrl(prk29_uart_dma_t->tx_dmach, RK29_DMAOP_START); - spin_lock(&(prk29_uart_dma_t->tx_lock)); - up->prk29_uart_dma_t->tx_dma_used = 1; - spin_unlock(&(prk29_uart_dma_t->tx_lock)); - +// spin_unlock(&(uart_dma->tx_lock)); return 1; err_out: dev_info(up->port.dev, "-serial_rk_start_tx_dma-error-\n"); return -1; - } @@ -560,23 +590,25 @@ static int serial_rk_start_tx_dma(struct uart_port *port) /*RX*/ static void serial_rk_dma_rxcb(void *buf, int size, enum rk29_dma_buffresult result) { - + //printk(">>%s:%d\n", __func__, result); } static void serial_rk_release_dma_rx(struct uart_port *port) { struct uart_rk_port *up = container_of(port, struct uart_rk_port, port); - struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t; + struct rk_uart_dma *uart_dma = up->dma; + if(!port){ return; } - if(prk29_uart_dma_t && prk29_uart_dma_t->rx_dma_inited) { - del_timer(&prk29_uart_dma_t->rx_timer); - rk29_dma_free(prk29_uart_dma_t->rx_dmach, &rk29_uart_dma_client); - prk29_uart_dma_t->rb_pre_pos = 0; - prk29_uart_dma_t->rx_dma_inited = 0; - prk29_uart_dma_t->rx_dma_start = 0; + + if(uart_dma && uart_dma->rx_dma_inited) { + del_timer(&uart_dma->rx_timer); + rk29_dma_free(uart_dma->rx_dmach, &rk29_uart_dma_client); + uart_dma->rb_tail = 0; + uart_dma->rx_dma_inited = 0; + uart_dma->rx_dma_used = 0; } } @@ -585,37 +617,40 @@ static int serial_rk_init_dma_rx(struct uart_port *port) { struct uart_rk_port *up = container_of(port, struct uart_rk_port, port); - struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t; - if(!port || !prk29_uart_dma_t){ + struct rk_uart_dma *uart_dma = up->dma; + + if(!port || !uart_dma){ dev_info(up->port.dev, "serial_rk_init_dma_rx: port fail\n"); return -1; } - if(prk29_uart_dma_t->rx_dma_inited) { + + if(uart_dma->rx_dma_inited) { return 0; } - if (rk29_dma_request(prk29_uart_dma_t->rx_dmach, &rk29_uart_dma_client, NULL) == -EBUSY) { + if (rk29_dma_request(uart_dma->rx_dmach, &rk29_uart_dma_client, NULL) == -EBUSY) { dev_info(up->port.dev, "rk29_dma_request fail rx \n"); return -1; } - if (rk29_dma_set_buffdone_fn(prk29_uart_dma_t->rx_dmach, serial_rk_dma_rxcb)) { + if (rk29_dma_set_buffdone_fn(uart_dma->rx_dmach, serial_rk_dma_rxcb)) { dev_info(up->port.dev, "rk29_dma_set_buffdone_fn rx fail\n"); return -1; } - if (rk29_dma_devconfig(prk29_uart_dma_t->rx_dmach, RK29_DMASRC_HW, (unsigned long)(port->iobase + UART_RX))) { + + if (rk29_dma_devconfig(uart_dma->rx_dmach, RK29_DMASRC_HW, (unsigned long)(port->iobase + UART_RX))) { dev_info(up->port.dev, "rk29_dma_devconfig rx fail\n"); return -1; } - if (rk29_dma_config(prk29_uart_dma_t->rx_dmach, 1, 1)) { - dev_info(up->port.dev, "rk29_dma_config rx fail\n"); + if (rk29_dma_config(uart_dma->rx_dmach, 1, 1)) { + dev_info(up->port.dev, "rk29_dma_config rx fail 1 1 \n"); return -1; } - rk29_dma_setflags(prk29_uart_dma_t->rx_dmach, RK29_DMAF_CIRCULAR); + rk29_dma_setflags(uart_dma->rx_dmach, RK29_DMAF_CIRCULAR); - prk29_uart_dma_t->rx_dma_inited = 1; + uart_dma->rx_dma_inited = 1; dev_info(up->port.dev, "serial_rk_init_dma_rx sucess\n"); return 0; @@ -625,38 +660,34 @@ static int serial_rk_start_rx_dma(struct uart_port *port) { struct uart_rk_port *up = container_of(port, struct uart_rk_port, port); - struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t; - if(0 == prk29_uart_dma_t->use_dma){ + struct rk_uart_dma *uart_dma = up->dma; + if(!uart_dma->use_dma) return 0; - } - if(prk29_uart_dma_t->rx_dma_start == 1){ + if(uart_dma->rx_dma_used == 1) return 0; - } if(-1 == serial_rk_init_dma_rx(port)){ dev_info(up->port.dev, "*******serial_rk_init_dma_rx*******error*******\n"); return -1; } - if (rk29_dma_enqueue(prk29_uart_dma_t->rx_dmach, (void *)up, prk29_uart_dma_t->rx_phy_addr, - prk29_uart_dma_t->rx_buffer_size/2)) { + if (rk29_dma_enqueue(uart_dma->rx_dmach, (void *)up, uart_dma->rx_phy_addr, + uart_dma->rb_size/2)) { dev_info(up->port.dev, "*******rk29_dma_enqueue fail*****\n"); return -1; } - if (rk29_dma_enqueue(prk29_uart_dma_t->rx_dmach, (void *)up, - prk29_uart_dma_t->rx_phy_addr+prk29_uart_dma_t->rx_buffer_size/2, - prk29_uart_dma_t->rx_buffer_size/2)) { + if (rk29_dma_enqueue(uart_dma->rx_dmach, (void *)up, + uart_dma->rx_phy_addr+uart_dma->rb_size/2, uart_dma->rb_size/2)) { dev_info(up->port.dev, "*******rk29_dma_enqueue fail*****\n"); return -1; } - rk29_dma_ctrl(prk29_uart_dma_t->rx_dmach, RK29_DMAOP_START); - prk29_uart_dma_t->rx_dma_start = 1; - if(prk29_uart_dma_t->use_timer == 1){ - mod_timer(&prk29_uart_dma_t->rx_timer, jiffies + - msecs_to_jiffies(prk29_uart_dma_t->rx_timeout)); + rk29_dma_ctrl(uart_dma->rx_dmach, RK29_DMAOP_START); + uart_dma->rx_dma_used = 1; + if(uart_dma->use_timer == 1){ + mod_timer(&uart_dma->rx_timer, jiffies + msecs_to_jiffies(uart_dma->rx_timeout)); } up->port_activity = jiffies; return 1; @@ -665,113 +696,76 @@ static int serial_rk_start_rx_dma(struct uart_port *port) static void serial_rk_update_rb_addr(struct uart_rk_port *up){ dma_addr_t current_pos = 0; dma_addr_t rx_current_pos = 0; - struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t; - spin_lock(&(up->prk29_uart_dma_t->rx_lock)); - rk29_dma_getposition(prk29_uart_dma_t->rx_dmach, ¤t_pos, &rx_current_pos); - - prk29_uart_dma_t->rb_cur_pos = (rx_current_pos - prk29_uart_dma_t->rx_phy_addr); - prk29_uart_dma_t->rx_size = CIRC_CNT(prk29_uart_dma_t->rb_cur_pos, - prk29_uart_dma_t->rb_pre_pos, prk29_uart_dma_t->rx_buffer_size); - - spin_unlock(&(up->prk29_uart_dma_t->rx_lock)); + struct rk_uart_dma *uart_dma = up->dma; + //spin_lock(&(up->dma->rx_lock)); + uart_dma->rx_size = 0; + if(uart_dma->rx_dma_used == 1){ + rk29_dma_getposition(uart_dma->rx_dmach, ¤t_pos, &rx_current_pos); + uart_dma->rb_head = (rx_current_pos - uart_dma->rx_phy_addr); + uart_dma->rx_size = CIRC_CNT(uart_dma->rb_head, uart_dma->rb_tail, uart_dma->rb_size); + } + //spin_unlock(&(up->dma->rx_lock)); } static void serial_rk_report_dma_rx(unsigned long uart) { + int count, flip = 0; struct uart_rk_port *up = (struct uart_rk_port *)uart; - struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t; - if(prk29_uart_dma_t->use_timer == 1){ - serial_rk_update_rb_addr(up); - } - if(prk29_uart_dma_t->rx_size > 0) { - spin_lock(&(up->prk29_uart_dma_t->rx_lock)); + struct rk_uart_dma *uart_dma = up->dma; - if(prk29_uart_dma_t->rb_cur_pos > prk29_uart_dma_t->rb_pre_pos){ - tty_insert_flip_string(up->port.state->port.tty, prk29_uart_dma_t->rx_buffer - + prk29_uart_dma_t->rb_pre_pos, prk29_uart_dma_t->rx_size); - tty_flip_buffer_push(up->port.state->port.tty); - } - else if(prk29_uart_dma_t->rb_cur_pos < prk29_uart_dma_t->rb_pre_pos){ + if(!uart_dma->rx_dma_used || !up->port.state->port.tty) + return; - tty_insert_flip_string(up->port.state->port.tty, prk29_uart_dma_t->rx_buffer - + prk29_uart_dma_t->rb_pre_pos, CIRC_CNT_TO_END(prk29_uart_dma_t->rb_cur_pos, - prk29_uart_dma_t->rb_pre_pos, prk29_uart_dma_t->rx_buffer_size)); - tty_flip_buffer_push(up->port.state->port.tty); + serial_rk_update_rb_addr(up); - if(prk29_uart_dma_t->rb_cur_pos != 0){ - tty_insert_flip_string(up->port.state->port.tty, prk29_uart_dma_t->rx_buffer, - prk29_uart_dma_t->rb_cur_pos); - tty_flip_buffer_push(up->port.state->port.tty); - } - } - - prk29_uart_dma_t->rb_pre_pos = (prk29_uart_dma_t->rb_pre_pos + prk29_uart_dma_t->rx_size) - & (prk29_uart_dma_t->rx_buffer_size - 1); - up->port.icount.rx += prk29_uart_dma_t->rx_size; - spin_unlock(&(up->prk29_uart_dma_t->rx_lock)); - prk29_uart_dma_t->rx_timeout = 7; + while(1) { + count = CIRC_CNT_TO_END(uart_dma->rb_head, uart_dma->rb_tail, uart_dma->rb_size); + if(count <= 0) + break; + up->port.icount.rx += count; + flip = tty_insert_flip_string(up->port.state->port.tty, uart_dma->rx_buffer + + uart_dma->rb_tail, count); + tty_flip_buffer_push(up->port.state->port.tty); + uart_dma->rb_tail = (uart_dma->rb_tail + count) & (uart_dma->rb_size - 1); up->port_activity = jiffies; } + //if (uart_dma->rx_size > 0) + // printk("rx_size:%d ADDR:%x\n", uart_dma->rx_size, uart_dma->rb_head); -#if 1 - if (jiffies_to_msecs(jiffies - up->port_activity) < RX_TIMEOUT) { - if(prk29_uart_dma_t->use_timer == 1){ - mod_timer(&prk29_uart_dma_t->rx_timer, jiffies + msecs_to_jiffies(prk29_uart_dma_t->rx_timeout)); - } - } else { - -#if 1 - - - prk29_uart_dma_t->rx_timeout = 20; - mod_timer(&prk29_uart_dma_t->rx_timer, jiffies + msecs_to_jiffies(prk29_uart_dma_t->rx_timeout)); -#else -// serial_out(up, 0x2a, 0x01); - serial_rk_release_dma_rx(&up->port); - serial_out(up, 0x2a, 0x01); - up->ier |= (UART_IER_RDI | UART_IER_RLSI); - serial_out(up, UART_IER, up->ier); -// serial_out(up, 0x22, 0x01); - dev_info(up->port.dev, "*****enable recv int*****\n"); - - //serial_rk_start_rx_dma(&up->port); -#endif + if(uart_dma->use_timer == 1){ + mod_timer(&uart_dma->rx_timer, jiffies + msecs_to_jiffies(uart_dma->rx_timeout)); } - -#else - if(prk29_uart_dma_t->use_timer == 1){ - mod_timer(&prk29_uart_dma_t->rx_timer, jiffies + msecs_to_jiffies(prk29_uart_dma_t->rx_timeout)); - } -#endif - } - +#if 0 static void serial_rk_rx_timeout(unsigned long uart) { struct uart_rk_port *up = (struct uart_rk_port *)uart; - //serial_rk_report_dma_rx(up); - queue_work(up->uart_wq, &up->uart_work); + serial_rk_report_dma_rx(up); + //queue_work(up->uart_wq, &up->uart_work); } static void serial_rk_report_revdata_workfunc(struct work_struct *work) { struct uart_rk_port *up = container_of(work, struct uart_rk_port, uart_work); + serial_rk_report_dma_rx((unsigned long)up); - spin_lock(&(up->prk29_uart_dma_t->rx_lock)); - if(up->prk29_uart_dma_t->use_timer == 1){ + //spin_lock(&(up->dma->rx_lock)); + + if(up->port.state->port.tty && up->dma->use_timer != 1 && up->fifo_size > 0){ - }else{ tty_insert_flip_string(up->port.state->port.tty, up->fifo, up->fifo_size); tty_flip_buffer_push(up->port.state->port.tty); up->port.icount.rx += up->fifo_size; + up->ier |= UART_IER_RDI; + serial_out(up, UART_IER, up->ier); } - spin_unlock(&(up->prk29_uart_dma_t->rx_lock)); + //spin_unlock(&(up->dma->rx_lock)); } @@ -780,10 +774,15 @@ static void serial_rk_start_dma_rx(struct work_struct *work) { struct uart_rk_port *up = container_of(work, struct uart_rk_port, uart_work_rx); - serial_rk_start_rx_dma(&up->port); -} -#endif /* USE_DMA */ + //mod_timer(&up->dma->rx_timer, jiffies + msecs_to_jiffies(up->dma->rx_timeout)); + //rk29_dma_ctrl(up->dma->rx_dmach, RK29_DMAOP_START); + //serial_rk_start_rx_dma(&up->port); + +} +#endif + +#endif /* USE_DMA */ static void @@ -883,8 +882,16 @@ static void transmit_chars(struct uart_rk_port *up) __stop_tx(up); return; } - - count = up->tx_loadsz; +#if USE_DMA + //hhb + if(up->dma->use_dma & TX_DMA){ + if(SERIAL_CIRC_CNT_TO_END(xmit) >= DMA_TX_TRRIGE_LEVEL){ + serial_rk_start_tx_dma(&up->port); + return; + } + } +#endif + count = up->port.fifosize - serial_in(up , 0x20); do { serial_out(up, UART_TX, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); @@ -897,7 +904,9 @@ static void transmit_chars(struct uart_rk_port *up) uart_write_wakeup(&up->port); DEBUG_INTR("THRE..."); - +#if USE_DMA + up->port_activity = jiffies; +#endif if (uart_circ_empty(xmit)) __stop_tx(up); } @@ -940,29 +949,33 @@ static void serial_rk_handle_port(struct uart_rk_port *up) /* reading UART_LSR can automatically clears PE FE OE bits, except receive fifo error bit*/ status = serial_in(up, UART_LSR); - DEBUG_INTR("status = %x...", status); + DEBUG_INTR("status = %x...\n", status); #if USE_DMA /* DMA mode enable */ - if(up->prk29_uart_dma_t->use_dma == 1) { + if(up->dma->use_dma) { - if(up->iir & UART_IIR_RLSI){ - if (status & (UART_LSR_DR | UART_LSR_BI)) { - up->port_activity = jiffies; - up->ier &= ~UART_IER_RLSI; - up->ier &= ~UART_IER_RDI; - serial_out(up, UART_IER, up->ier); - //receive_chars(up, &status); - //mod_timer(&up->prk29_uart_dma_t->rx_timer, jiffies + - //msecs_to_jiffies(up->prk29_uart_dma_t->rx_timeout)); - if(serial_rk_start_rx_dma(&up->port) == -1){ - receive_chars(up, &status); - } + if (status & UART_LSR_RFE) { + if(up->port.line != DBG_PORT){ + dev_info(up->port.dev, "error:lsr=0x%x\n", status); + status = serial_in(up, UART_LSR); + DEBUG_INTR("error:lsr=0x%x\n", status); } } - } else + if (status & 0x02) { + if(up->port.line != DBG_PORT){ + dev_info(up->port.dev, "error:lsr=0x%x\n", status); + status = serial_in(up, UART_LSR); + DEBUG_INTR("error:lsr=0x%x\n", status); + } + } + + if ((up->iir & 0x0f) == 0x02) { + transmit_chars(up); + } + } else #endif - { //dma mode disable + { //dma mode disable /* * when uart receive a serial of data which doesn't have stop bit and so on, that causes frame error,and @@ -972,25 +985,25 @@ static void serial_rk_handle_port(struct uart_rk_port *up) */ if (status & UART_LSR_RFE) { - if(up->port.line != DBG_PORT){ - status = serial_in(up, UART_LSR); dev_info(up->port.dev, "error:lsr=0x%x\n", status); + status = serial_in(up, UART_LSR); + DEBUG_INTR("error:lsr=0x%x\n", status); + rk29_uart_dump_register(up); } - - - // rk29_uart_dump_register(up); } if (status & (UART_LSR_DR | UART_LSR_BI)) { receive_chars(up, &status); } check_modem_status(up); - if (status & UART_LSR_THRE) { + //hhb@rock-chips.com when FIFO and THRE mode both are enabled,and FIFO TX empty trigger is set to larger than 1, + //,we need to add ((up->iir & 0x0f) == 0x02) to transmit_chars,because when entering interrupt,the FIFO and THR + //might not be 1. + if ((up->iir & 0x0f) == 0x02) { transmit_chars(up); } } - spin_unlock_irqrestore(&up->port.lock, flags); } @@ -1007,7 +1020,6 @@ static irqreturn_t serial_rk_interrupt(int irq, void *dev_id) iir = serial_in(up, UART_IIR); DEBUG_INTR("%s(%d) iir = 0x%02x\n", __func__, irq, iir); - up->iir = iir; if (!(iir & UART_IIR_NO_INT)) { @@ -1190,8 +1202,8 @@ static int serial_rk_startup(struct uart_port *port) struct uart_rk_port *up = container_of(port, struct uart_rk_port, port); unsigned long flags; - int retval; - + int retval, fifosize = 0; + dev_dbg(port->dev, "%s\n", __func__); @@ -1214,6 +1226,13 @@ static int serial_rk_startup(struct uart_port *port) */ serial_rk_clear_fifos(up); + //read uart fifo size hhb@rock-chips.com + fifosize = __raw_readl(up->port.membase + 0xf4); + up->port.fifosize = ((fifosize >> 16) & 0xff) << 4; + if(up->port.fifosize <= 0) + up->port.fifosize = 32; + //printk("fifo size:%d :%08x\n", up->port.fifosize, fifosize); + /* * Clear the interrupt registers. */ @@ -1253,26 +1272,14 @@ static int serial_rk_startup(struct uart_port *port) #if 0 up->msr_saved_flags = 0; #endif - #if USE_DMA - if (1 == up->prk29_uart_dma_t->use_dma) { - - if(up->port.state->xmit.buf != up->prk29_uart_dma_t->tx_buffer){ + if (up->dma->use_dma & TX_DMA) { + if(up->port.state->xmit.buf != up->dma->tx_buffer){ free_page((unsigned long)up->port.state->xmit.buf); - up->port.state->xmit.buf = up->prk29_uart_dma_t->tx_buffer; + up->port.state->xmit.buf = up->dma->tx_buffer; } - -#if 1 - serial_rk_start_rx_dma(&up->port); -#else - up->ier |= UART_IER_RDI; - up->ier |= UART_IER_RLSI; - serial_out(up, UART_IER, up->ier); + } else #endif - up->port_activity = jiffies; - - } else -#endif /* USE_DMA */ { up->ier = 0; serial_out(up, UART_IER, up->ier); @@ -1316,7 +1323,10 @@ static void serial_rk_shutdown(struct uart_port *port) * Read data port to reset things, and then free the irq */ (void) serial_in(up, UART_RX); - +#if USE_DMA + //if (up->dma->use_dma & TX_DMA) + // up->port.state->xmit.buf = NULL; +#endif free_irq(up->port.irq, up); clk_disable(up->clk); clk_disable(up->pclk); @@ -1328,10 +1338,9 @@ serial_rk_set_termios(struct uart_port *port, struct ktermios *termios, { struct uart_rk_port *up = container_of(port, struct uart_rk_port, port); - unsigned char cval, fcr = 0; + unsigned char cval = 0, fcr = 0, mcr = 0; unsigned long flags; unsigned int baud, quot; - int timeout = 1000000; dev_dbg(port->dev, "+%s\n", __func__); switch (termios->c_cflag & CSIZE) { @@ -1373,44 +1382,36 @@ serial_rk_set_termios(struct uart_port *port, struct ktermios *termios, port->uartclk / 16); quot = uart_get_divisor(port, baud); - - dev_info(up->port.dev, "baud:%d\n", baud); -// dev_info(up->port.dev, "quot:%d\n", quot); - - /* - * To wait long enough to avoid writting lcr when the uart is busy - * because of data communication, so that we can set lcr and baud rate - * successfully. added by hhb@rock-chips.com - */ - - while(serial_in(up, UART_USR) & UART_USR_BUSY){ - if(--timeout == 0){ - if(port->line != DBG_PORT){ - serial_out(up, UART_SRR, UART_RESET); - } - dbg("rk_serial_set_termios uart.%d timeout,irq=%d,ret=0x%x AND uart is reseted\n", - port->line, port->irq, serial_in(up, UART_USR)); - break; - } - cpu_relax(); - } - - - printk("serial.%d timeout:%d\n", up->port.line,timeout); - + //dev_info(up->port.dev, "uartclk:%d\n", port->uartclk/16); + //dev_info(up->port.dev, "baud:%d\n", baud); + //dev_info(up->port.dev, "quot:%d\n", quot); if (baud < 2400){ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; } else{ + fcr = UART_FCR_ENABLE_FIFO; #if USE_DMA //added by hhb@rock-chips.com - if(up->prk29_uart_dma_t->use_timer == 1){ - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_01; + if(up->dma->use_dma & TX_DMA){ + fcr |= UART_FCR_T_TRIG_01; } else #endif { - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | UART_FCR_T_TRIG_01; + fcr |= UART_FCR_T_TRIG_01; + } + +#if USE_DMA + //added by hhb@rock-chips.com + if(up->dma->use_dma & RX_DMA){ + fcr |= UART_FCR_R_TRIG_00; + } else +#endif + { + if (termios->c_cflag & CRTSCTS) + fcr |= UART_FCR_R_TRIG_11; + else + fcr |= UART_FCR_R_TRIG_00; } } @@ -1475,44 +1476,65 @@ serial_rk_set_termios(struct uart_port *port, struct ktermios *termios, up->ier |= UART_IER_MSI; #endif + //to avoid uart busy when set baud rate hhb@rock-chips.com + serial_out(up, UART_SRR, UART_RESET); + mcr = serial_in(up, UART_MCR); + serial_out(up, UART_MCR, mcr | 0x10); //loopback mode + up->lcr = cval; /* Save LCR */ /* set DLAB */ - if(serial_lcr_write(up, cval | UART_LCR_DLAB)){ - dbg("serial.%d set DLAB fail\n", up->port.line); + if(serial_lcr_write(up, cval | UART_LCR_DLAB)) { + if(up->port.line != DBG_PORT) + dbg("serial.%d set DLAB fail\n", up->port.line); serial_out(up, UART_SRR, UART_RESET); goto fail; } /* set uart baud rate */ - if(serial_dl_write(up, quot)){ - dbg("serial.%d set dll fail\n", up->port.line); + if(serial_dl_write(up, quot)) { + if(up->port.line != DBG_PORT) + dbg("serial.%d set dll fail\n", up->port.line); serial_out(up, UART_SRR, UART_RESET); goto fail; } /* reset DLAB */ - if(serial_lcr_write(up, cval)){ - dbg("serial.%d reset DLAB fail\n", up->port.line); + if(serial_lcr_write(up, cval)) { + if(up->port.line != DBG_PORT) + dbg("serial.%d reset DLAB fail\n", up->port.line); serial_out(up, UART_SRR, UART_RESET); goto fail; } - else{ + else { serial_rk_set_mctrl(&up->port, up->port.mctrl); - serial_out(up, UART_FCR, fcr); /* set fcr */ up->fcr = fcr; - /* enable the uart interrupt last */ - up->ier |= UART_IER_RDI; - up->ier |= UART_IER_RLSI; + serial_out(up, UART_FCR, up->fcr); /* set fcr */ + up->ier = 0; + //start serial receive data +#if USE_DMA + if (up->dma->use_dma) { + up->ier |= UART_IER_RLSI; + up->ier |= UART_IER_PTIME; //Programmable THRE Interrupt Mode Enable + serial_rk_start_rx_dma(&up->port); + } else +#endif + { + // not use dma receive + up->ier |= UART_IER_RDI; + up->ier |= UART_IER_RLSI; + if(up->port.line != DBG_PORT) + up->ier |= UART_IER_PTIME; //Programmable THRE Interrupt Mode Enable + + } serial_out(up, UART_IER, up->ier); } - + spin_unlock_irqrestore(&up->port.lock, flags); /* Don't rewrite B0 */ if (tty_termios_baud_rate(termios)) tty_termios_encode_baud_rate(termios, baud, baud); dev_dbg(port->dev, "-%s baud %d\n", __func__, baud); - return; fail: @@ -1743,6 +1765,7 @@ static int __devinit serial_rk_probe(struct platform_device *pdev) struct resource *mem; int irq; int ret = -ENOSPC; + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { dev_err(&pdev->dev, "no mem resource?\n"); @@ -1777,7 +1800,7 @@ static int __devinit serial_rk_probe(struct platform_device *pdev) } up->tx_loadsz = 30; #if USE_DMA - up->prk29_uart_dma_t = &rk29_uart_ports_dma_t[pdev->id]; + up->dma = &rk29_uart_ports_dma[pdev->id]; #endif up->port.dev = &pdev->dev; up->port.type = PORT_RK; @@ -1785,6 +1808,7 @@ static int __devinit serial_rk_probe(struct platform_device *pdev) up->port.iotype = UPIO_DWAPB; up->port.regshift = 2; + //fifo size default is 32, but it will be updated later when start_up up->port.fifosize = 32; up->port.ops = &serial_rk_pops; up->port.line = pdev->id; @@ -1800,54 +1824,56 @@ static int __devinit serial_rk_probe(struct platform_device *pdev) #if USE_DMA /* set dma config */ - if(1 == up->prk29_uart_dma_t->use_dma) { + if(up->dma->use_dma & RX_DMA) { pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - //timer - up->prk29_uart_dma_t->use_timer = USE_TIMER; - up->prk29_uart_dma_t->rx_timer.function = serial_rk_rx_timeout; - up->prk29_uart_dma_t->rx_timer.data = (unsigned long)up; - up->prk29_uart_dma_t->rx_timeout = 7; - up->prk29_uart_dma_t->rx_timer.expires = jiffies + msecs_to_jiffies(up->prk29_uart_dma_t->rx_timeout); - init_timer(&up->prk29_uart_dma_t->rx_timer); - //tx buffer - up->prk29_uart_dma_t->tx_buffer_size = UART_XMIT_SIZE; - up->prk29_uart_dma_t->tx_buffer = dmam_alloc_coherent(up->port.dev, up->prk29_uart_dma_t->tx_buffer_size, - &up->prk29_uart_dma_t->tx_phy_addr, DMA_MEMORY_MAP); - if(!up->prk29_uart_dma_t->tx_buffer){ - dev_info(up->port.dev, "dmam_alloc_coherent dma_tx_buffer fail\n"); - } - else{ - dev_info(up->port.dev, "dma_tx_buffer 0x%08x\n", (unsigned) up->prk29_uart_dma_t->tx_buffer); - dev_info(up->port.dev, "dma_tx_phy 0x%08x\n", (unsigned) up->prk29_uart_dma_t->tx_phy_addr); - } + up->dma->use_timer = USE_TIMER; + up->dma->rx_timer.function = serial_rk_report_dma_rx; + up->dma->rx_timer.data = (unsigned long)up; + up->dma->rx_timeout = 10; + up->dma->rx_timer.expires = jiffies + msecs_to_jiffies(up->dma->rx_timeout); + init_timer(&up->dma->rx_timer); + //rx buffer - up->prk29_uart_dma_t->rx_buffer_size = UART_XMIT_SIZE*32; - up->prk29_uart_dma_t->rx_buffer = dmam_alloc_coherent(up->port.dev, up->prk29_uart_dma_t->rx_buffer_size, - &up->prk29_uart_dma_t->rx_phy_addr, DMA_MEMORY_MAP); - up->prk29_uart_dma_t->rb_pre_pos = 0; - if(!up->prk29_uart_dma_t->rx_buffer){ + up->dma->rb_size = UART_XMIT_SIZE*8; + up->dma->rx_buffer = dmam_alloc_coherent(up->port.dev, up->dma->rb_size, + &up->dma->rx_phy_addr, DMA_MEMORY_MAP); + up->dma->rb_tail = 0; + + if(!up->dma->rx_buffer){ dev_info(up->port.dev, "dmam_alloc_coherent dma_rx_buffer fail\n"); } else { - dev_info(up->port.dev, "dma_rx_buffer 0x%08x\n", (unsigned) up->prk29_uart_dma_t->rx_buffer); - dev_info(up->port.dev, "up 0x%08x\n", (unsigned)up->prk29_uart_dma_t); + dev_info(up->port.dev, "dma_rx_buffer 0x%08x\n", (unsigned) up->dma->rx_buffer); + dev_info(up->port.dev, "up 0x%08x\n", (unsigned)up->dma); } // work queue - INIT_WORK(&up->uart_work, serial_rk_report_revdata_workfunc); - INIT_WORK(&up->uart_work_rx, serial_rk_start_dma_rx); - up->uart_wq = create_singlethread_workqueue("uart_workqueue"); - up->prk29_uart_dma_t->rx_dma_start = 0; - spin_lock_init(&(up->prk29_uart_dma_t->tx_lock)); - spin_lock_init(&(up->prk29_uart_dma_t->rx_lock)); + //INIT_WORK(&up->uart_work, serial_rk_report_revdata_workfunc); + //INIT_WORK(&up->uart_work_rx, serial_rk_start_dma_rx); + //up->uart_wq = create_singlethread_workqueue("uart_workqueue"); + up->dma->rx_dma_used = 0; + spin_lock_init(&(up->dma->rx_lock)); serial_rk_init_dma_rx(&up->port); - serial_rk_init_dma_tx(&up->port); - up->ier |= THRE_MODE; // enable THRE interrupt mode - serial_out(up, UART_IER, up->ier); } -#endif + if(up->dma->use_dma & TX_DMA){ + //tx buffer + up->dma->tb_size = UART_XMIT_SIZE; + up->dma->tx_buffer = dmam_alloc_coherent(up->port.dev, up->dma->tb_size, + &up->dma->tx_phy_addr, DMA_MEMORY_MAP); + if(!up->dma->tx_buffer){ + dev_info(up->port.dev, "dmam_alloc_coherent dma_tx_buffer fail\n"); + } + else{ + dev_info(up->port.dev, "dma_tx_buffer 0x%08x\n", (unsigned) up->dma->tx_buffer); + dev_info(up->port.dev, "dma_tx_phy 0x%08x\n", (unsigned) up->dma->tx_phy_addr); + } + spin_lock_init(&(up->dma->tx_lock)); + serial_rk_init_dma_tx(&up->port); + } + +#endif serial_rk_add_console_port(up); ret = uart_add_one_port(&serial_rk_reg, &up->port); if (ret != 0) @@ -1939,6 +1965,8 @@ static struct platform_driver serial_rk_driver = { static int __init serial_rk_init(void) { int ret; + //hhb@rock-chips.com + printk("%s\n", VERSION_AND_TIME); ret = uart_register_driver(&serial_rk_reg); if (ret) From 8cbbc34b0b3d46745f2a82f94bf691cb55a02658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=99=B4?= Date: Thu, 9 Aug 2012 18:28:30 +0800 Subject: [PATCH 131/261] rk30:phonepad:modify vdd_cpu(arm voltage) when resume --- arch/arm/mach-rk30/i2c_sram.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-rk30/i2c_sram.c b/arch/arm/mach-rk30/i2c_sram.c index 03fc85e150b1..184ab9a63c90 100755 --- a/arch/arm/mach-rk30/i2c_sram.c +++ b/arch/arm/mach-rk30/i2c_sram.c @@ -32,6 +32,7 @@ CH=2:(~(0x03<<24))&(~(0x03<<22))|(0x01<<24)|(0x01<<22),CH=3:(~(0x03<<26))&(~(0x0 #define uint16 unsigned short #define uint32 unsigned int uint32 __sramdata data[5]; +uint8 __sramdata arm_voltage = 0; #define CRU_CLKGATE0_CON 0xd0 #define CRU_CLKGATE8_CON 0xf0 @@ -308,7 +309,7 @@ void __sramfunc rk30_suspend_voltage_set(unsigned int vol) data = 0x23; //set arm 1.0v sram_i2c_init(); //init i2c device -// ret = sram_i2c_read(slaveaddr, slavereg); + arm_voltage = sram_i2c_read(slaveaddr, slavereg); // sram_printhex(ret); sram_i2c_write(slaveaddr, slavereg, data);// sram_i2c_deinit(); //deinit i2c device @@ -322,10 +323,16 @@ void __sramfunc rk30_suspend_voltage_resume(unsigned int vol) uint8 data,ret; slaveaddr = I2C_SADDR; //slave device addr slavereg = 0x22; // reg addr - data = 0x2b; - + sram_i2c_init(); //init i2c device -// ret = sram_i2c_read(slaveaddr, slavereg); + if (arm_voltage >= 0x3b ){ // set arm <= 1.3v + data = 0x3b; + } + else if(arm_voltage <= 0x1f){ + data = 0x1f; // set arm >= 0.95v + } + else + data = arm_voltage; sram_i2c_write(slaveaddr, slavereg, data); sram_i2c_deinit(); //deinit i2c device } From b50c4c8955f04f15c36c20d69e575a0132f47d00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=99=B4?= Date: Thu, 9 Aug 2012 18:32:39 +0800 Subject: [PATCH 132/261] rk30:phonepad:open codec powerdomain when pmu enter sleep --- arch/arm/mach-rk30/board-rk30-sdk-tps65910.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c b/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c index 906c04928d3a..d1fb1cfd80ed 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c +++ b/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c @@ -204,7 +204,7 @@ int tps65910_pre_init(struct tps65910 *tps65910){ return val; } - val |= 0x9B; + val |= 0x0b; err = tps65910_reg_write(tps65910, TPS65910_SLEEP_SET_LDO_OFF, val); if (err) { printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \ From 34e285616f0478ac44da7b7fc801e77d414a22b7 Mon Sep 17 00:00:00 2001 From: hhb Date: Thu, 9 Aug 2012 18:36:03 +0800 Subject: [PATCH 133/261] add dma pl330 memcpy test --- arch/arm/plat-rk/Kconfig | 4 + arch/arm/plat-rk/Makefile | 1 + arch/arm/plat-rk/dma_memcpy_test.c | 235 +++++++++++++++++++++++++++++ 3 files changed, 240 insertions(+) create mode 100644 arch/arm/plat-rk/dma_memcpy_test.c diff --git a/arch/arm/plat-rk/Kconfig b/arch/arm/plat-rk/Kconfig index 5c7a0859c981..0e8c497183dc 100644 --- a/arch/arm/plat-rk/Kconfig +++ b/arch/arm/plat-rk/Kconfig @@ -166,5 +166,9 @@ config RK_PL330_DMA select PL330 help DMA API Driver for PL330 DMAC + +config RK_PL330_DMA_TEST + bool "pl330 DMA memcpy test" + depends on RK_PL330_DMA endif diff --git a/arch/arm/plat-rk/Makefile b/arch/arm/plat-rk/Makefile index bc9832edc8e0..18c7fd90b035 100644 --- a/arch/arm/plat-rk/Makefile +++ b/arch/arm/plat-rk/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_RK29_LAST_LOG) += last_log.o obj-$(CONFIG_USB_GADGET) += usb_detect.o obj-$(CONFIG_RK29_VPU) += vpu_service.o obj-$(CONFIG_RK_PL330_DMA) += dma-pl330.o +obj-$(CONFIG_RK_PL330_DMA_TEST) += dma_memcpy_test.o obj-$(CONFIG_FIQ) += fiq.o obj-$(CONFIG_FIQ_DEBUGGER) += rk_fiq_debugger.o obj-$(CONFIG_RK_EARLY_PRINTK) += early_printk.o ../kernel/debug.o diff --git a/arch/arm/plat-rk/dma_memcpy_test.c b/arch/arm/plat-rk/dma_memcpy_test.c new file mode 100644 index 000000000000..be658680dae4 --- /dev/null +++ b/arch/arm/plat-rk/dma_memcpy_test.c @@ -0,0 +1,235 @@ +/* + * + * arch/arm/plat-rk/dma_memcpy_test.c + * + * Copyright (C) 2012 Rochchip. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Author: hhb@rock-chips.com + * Date: 2012.03.26 + * + * HOW TO USE IT? + * enter the follow command at command line + * echo 1 > sys/module/dma_memcpy_test/parameters/debug enable log output,default is enable + * echo 1 > sys/module/dma_memcpy_test/parameters/dmac1 set dmac1 memcpy + * echo 1 > sys/module/dma_memcpy_test/parameters/dmac2 set dmac2 memcpy + * echo 1000 > sys/module/dma_memcpy_test/parameters/interval set dma transfer interval, default is 1000ms + * echo 1 > /sys/devices/platform/dma_memcpy.0/dmamemcpy to start the dma test + * + */ + + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DMA_TEST_BUFFER_SIZE 4096 +static DECLARE_WAIT_QUEUE_HEAD(wq); +static int wq_condition = 0; + +struct Dma_MemToMem { + dma_addr_t SrcAddr; //phy address + dma_addr_t DstAddr; + unsigned char* src; //virtual address + unsigned char* dst; + int MenSize; +}; +//wait_queue_head_t dma_memcpy_wait; + +//enable log output +static int debug = 1; +module_param(debug,int,S_IRUGO|S_IWUSR); +//set dma transfer interval time (unit ms) +static int interval = 1000; +module_param(interval,int,S_IRUGO|S_IWUSR); + +static int dmac1 = 1; +module_param(dmac1,int,S_IRUGO|S_IWUSR); + +static int dmac2 = -1; +module_param(dmac2,int,S_IRUGO|S_IWUSR); + + +static struct Dma_MemToMem DmaMemInfo1; +static struct Dma_MemToMem DmaMemInfo2; + + +#define MEMCPY_DMA_DBG(fmt...) {if(debug > 0) printk(fmt);} + + +static struct rk29_dma_client rk29_dma_memcpy_client = { + .name = "rk29-dma-memcpy", +}; + + + +static void rk29_dma_memcpy_callback1(void *buf_id, int size, enum rk29_dma_buffresult result) +{ + if(result != RK29_RES_OK){ + return; + } + MEMCPY_DMA_DBG("rk29_dma_memcpy_callback1 ok\n"); + if(wq_condition == 0){ + wq_condition = 1; + wake_up_interruptible(&wq); + } + //wake_up_interruptible(&dma_memcpy_wait); +} + +static void rk29_dma_memcpy_callback2(void *buf_id, int size, enum rk29_dma_buffresult result) +{ + if(result != RK29_RES_OK){ + return; + } + MEMCPY_DMA_DBG("rk29_dma_memcpy_callback2 ok\n"); + if(wq_condition == 0){ + wq_condition = 1; + wake_up_interruptible(&wq); + } + //wake_up_interruptible(&dma_memcpy_wait); +} + +//int slecount = 0; +static ssize_t memcpy_dma_read(struct device *device,struct device_attribute *attr, char *argv) +{ + + return 0; +} + +static ssize_t memcpy_dma_write(struct device *device, struct device_attribute *attr, const char *argv, size_t count) +{ + int rt, i; + // struct Dma_MemToMem *DmaMemInfo1 = (struct Dma_MemToMem *)argv; + MEMCPY_DMA_DBG("memcpy_dma_write\n"); + + //dmac1 + if(dmac1 > 0) { + memset(DmaMemInfo1.src, 0x55, DMA_TEST_BUFFER_SIZE); + memset(DmaMemInfo1.dst, 0x0, DMA_TEST_BUFFER_SIZE); + rt = rk29_dma_devconfig(DMACH_DMAC1_MEMTOMEM, RK29_DMASRC_MEMTOMEM, DmaMemInfo1.SrcAddr); + rt = rk29_dma_enqueue(DMACH_DMAC1_MEMTOMEM, NULL, DmaMemInfo1.DstAddr, DmaMemInfo1.MenSize); + rt = rk29_dma_ctrl(DMACH_DMAC1_MEMTOMEM, RK29_DMAOP_START); + } + + //dmac2 + if(dmac2 > 0) { + memset(DmaMemInfo2.src, 0xaa, DMA_TEST_BUFFER_SIZE); + memset(DmaMemInfo2.dst, 0x0, DMA_TEST_BUFFER_SIZE); + rt = rk29_dma_devconfig(DMACH_DMAC2_MEMTOMEM, RK29_DMASRC_MEMTOMEM, DmaMemInfo2.SrcAddr); + rt = rk29_dma_enqueue(DMACH_DMAC2_MEMTOMEM, NULL, DmaMemInfo2.DstAddr, DmaMemInfo2.MenSize); + rt = rk29_dma_ctrl(DMACH_DMAC2_MEMTOMEM, RK29_DMAOP_START); + } + + if(dmac2 > 0 || dmac1 > 0) + wait_event_interruptible_timeout(wq, wq_condition, 500); + + if(dmac1 > 0) { + for(i = 0; i < 16; i++) { + MEMCPY_DMA_DBG("dmac1 src1:%x", *(DmaMemInfo1.src + i*(DMA_TEST_BUFFER_SIZE/16))); + MEMCPY_DMA_DBG(" -> dst1:%x\n", *(DmaMemInfo1.dst + i*(DMA_TEST_BUFFER_SIZE/16))); + } + } + + if(dmac2 > 0) { + for(i = 0; i < 16; i++) { + MEMCPY_DMA_DBG("dmac2 src2:%x", *(DmaMemInfo2.src + i*(DMA_TEST_BUFFER_SIZE/16))); + MEMCPY_DMA_DBG(" -> dst2:%x\n", *(DmaMemInfo2.dst + i*(DMA_TEST_BUFFER_SIZE/16))); + } + } + msleep(interval); + wq_condition = 0; + //init_waitqueue_head(&dma_memcpy_wait); + //interruptible_sleep_on(&dma_memcpy_wait); + return 0; +} + +static DEVICE_ATTR(dmamemcpy, S_IRUGO|S_IALLUGO, memcpy_dma_read, memcpy_dma_write); + + +static int __devinit dma_memcpy_probe(struct platform_device *pdev) +{ + int ret; + + ret = device_create_file(&pdev->dev, &dev_attr_dmamemcpy); + printk(">>>>>>>>>>>>>>>>>>>>> dam_test_probe <<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); + + //dmac1 + if (rk29_dma_request(DMACH_DMAC1_MEMTOMEM, &rk29_dma_memcpy_client, NULL) == -EBUSY) { + printk("DMACH_DMAC1_MEMTOMEM request fail\n"); + } else { + rk29_dma_config(DMACH_DMAC1_MEMTOMEM, 8, 16); + rk29_dma_set_buffdone_fn(DMACH_DMAC1_MEMTOMEM, rk29_dma_memcpy_callback1); + DmaMemInfo1.src = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo1.SrcAddr, GFP_KERNEL); + DmaMemInfo1.dst = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo1.DstAddr, GFP_KERNEL); + DmaMemInfo1.MenSize = DMA_TEST_BUFFER_SIZE; + printk("DMACH_DMAC1_MEMTOMEM request sucess\n"); + } + + //dmac2 + if (rk29_dma_request(DMACH_DMAC2_MEMTOMEM, &rk29_dma_memcpy_client, NULL) == -EBUSY) { + printk("DMACH_DMAC2_MEMTOMEM request fail\n"); + } else { + rk29_dma_config(DMACH_DMAC2_MEMTOMEM, 8, 16); + rk29_dma_set_buffdone_fn(DMACH_DMAC2_MEMTOMEM, rk29_dma_memcpy_callback2); + DmaMemInfo2.src = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo2.SrcAddr, GFP_KERNEL); + DmaMemInfo2.dst = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo2.DstAddr, GFP_KERNEL); + DmaMemInfo2.MenSize = DMA_TEST_BUFFER_SIZE; + printk("DMACH_DMAC2_MEMTOMEM request sucess\n"); + } + return 0; +} + +static int __devexit dma_memcpy_remove(struct platform_device *pdev) +{ + device_remove_file(&pdev->dev, &dev_attr_dmamemcpy); + + return 0; +} + +static struct platform_driver dma_mempcy_driver = { + .driver = { + .name = "dma_memcpy", + .owner = THIS_MODULE, + }, + .probe = dma_memcpy_probe, + .remove = __devexit_p(dma_memcpy_remove), +}; + +struct platform_device rk29_device_dma_cpy = { + .name = "dma_memcpy", + .id = 0, + +}; + + +static int __init dma_test_init(void) +{ + platform_device_register(&rk29_device_dma_cpy); + return platform_driver_register(&dma_mempcy_driver); +} + +static void __exit dma_test_exit(void) +{ + platform_driver_unregister(&dma_mempcy_driver); +} + +late_initcall(dma_test_init); +module_exit(dma_test_exit); + +MODULE_DESCRIPTION("RK29 PL330 Dma Test Deiver"); +MODULE_LICENSE("GPL V2"); +MODULE_AUTHOR("ZhenFu Fang "); From 7bbcfdf7f1edc130e6e00d211f15a61b1d8e0006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=99=B4?= Date: Thu, 9 Aug 2012 18:42:58 +0800 Subject: [PATCH 134/261] rk30:phonepad:Remove debug print --- arch/arm/mach-rk30/i2c_sram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-rk30/i2c_sram.c b/arch/arm/mach-rk30/i2c_sram.c index 184ab9a63c90..e871a5b0218c 100755 --- a/arch/arm/mach-rk30/i2c_sram.c +++ b/arch/arm/mach-rk30/i2c_sram.c @@ -147,7 +147,7 @@ void __sramfunc sram_i2c_init() divh = divl = rk30_ceil(div, 2); writel_relaxed(I2C_CLKDIV_VAL(divl, divh), SRAM_I2C_ADDRBASE + I2C_CLKDIV); data[3] = readl_relaxed(SRAM_I2C_ADDRBASE + I2C_CLKDIV); - sram_printhex(data[3]); + } From 5c0b03403ef01772a6d0831c956df93a6a4ee614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=99=B4?= Date: Fri, 10 Aug 2012 10:11:17 +0800 Subject: [PATCH 135/261] rk2928:support pmic tp65910 gpio function --- arch/arm/mach-rk2928/board-rk30-sdk-tps65910.c | 2 +- arch/arm/mach-rk2928/include/mach/gpio.h | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) mode change 100644 => 100755 arch/arm/mach-rk2928/include/mach/gpio.h diff --git a/arch/arm/mach-rk2928/board-rk30-sdk-tps65910.c b/arch/arm/mach-rk2928/board-rk30-sdk-tps65910.c index 7ec12c302a3a..51cf60dc2029 100755 --- a/arch/arm/mach-rk2928/board-rk30-sdk-tps65910.c +++ b/arch/arm/mach-rk2928/board-rk30-sdk-tps65910.c @@ -605,7 +605,7 @@ void __sramfunc board_pmu_tps65910_resume(void) static struct tps65910_board tps65910_data = { .irq = (unsigned)TPS65910_HOST_IRQ, .irq_base = NR_GIC_IRQS + NR_GPIO_IRQS, -// .gpio_base = TPS65910_GPIO_EXPANDER_BASE, + .gpio_base = TPS65910_GPIO_EXPANDER_BASE, .pre_init = tps65910_pre_init, .post_init = tps65910_post_init, diff --git a/arch/arm/mach-rk2928/include/mach/gpio.h b/arch/arm/mach-rk2928/include/mach/gpio.h old mode 100644 new mode 100755 index 0b0a76f31335..3a0c2631345a --- a/arch/arm/mach-rk2928/include/mach/gpio.h +++ b/arch/arm/mach-rk2928/include/mach/gpio.h @@ -55,8 +55,18 @@ #define WM8994_GPIO_EXPANDER_BASE (GPIO_EXPANDER_BASE+WM831X_TOTOL_GPIO_NUM) #else #define CONFIG_GPIO_WM8994_NUM 0 +#define WM8994_GPIO_EXPANDER_BASE (GPIO_EXPANDER_BASE+WM831X_TOTOL_GPIO_NUM) #endif +#if defined (CONFIG_GPIO_TPS65910) +#define CONFIG_GPIO_TPS65910_NUM 9 +#define TPS65910_GPIO_EXPANDER_BASE (WM8994_GPIO_EXPANDER_BASE+CONFIG_GPIO_WM8994_NUM) +#else +#define CONFIG_GPIO_TPS65910_NUM 0 +#define TPS65910_GPIO_EXPANDER_BASE (WM8994_GPIO_EXPANDER_BASE+CONFIG_GPIO_WM8994_NUM) +#endif + + //定义GPIO的PIN口最大数目。CONFIG_SPI_FPGA_GPIO_NUM表示FPGA的PIN脚数。 #define ARCH_NR_GPIOS (PIN_BASE + RK2928_TOTOL_GPIO_NUM + TCA6424_TOTOL_GPIO_NUM + WM831X_TOTOL_GPIO_NUM + CONFIG_SPI_FPGA_GPIO_NUM + CONFIG_GPIO_WM8994_NUM) From acfecf602c2c120f9ae3991bf39c5e4f9f6e4ec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=99=B4?= Date: Fri, 10 Aug 2012 10:24:55 +0800 Subject: [PATCH 136/261] rk2928:modify gpio numbers --- arch/arm/mach-rk2928/include/mach/gpio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-rk2928/include/mach/gpio.h b/arch/arm/mach-rk2928/include/mach/gpio.h index 3a0c2631345a..24f2b08b9f1f 100755 --- a/arch/arm/mach-rk2928/include/mach/gpio.h +++ b/arch/arm/mach-rk2928/include/mach/gpio.h @@ -68,7 +68,7 @@ //定义GPIO的PIN口最大数目。CONFIG_SPI_FPGA_GPIO_NUM表示FPGA的PIN脚数。 -#define ARCH_NR_GPIOS (PIN_BASE + RK2928_TOTOL_GPIO_NUM + TCA6424_TOTOL_GPIO_NUM + WM831X_TOTOL_GPIO_NUM + CONFIG_SPI_FPGA_GPIO_NUM + CONFIG_GPIO_WM8994_NUM) +#define ARCH_NR_GPIOS (PIN_BASE + RK2928_TOTOL_GPIO_NUM + TCA6424_TOTOL_GPIO_NUM + WM831X_TOTOL_GPIO_NUM + CONFIG_SPI_FPGA_GPIO_NUM + CONFIG_GPIO_WM8994_NUM + CONFIG_GPIO_TPS65910_NUM) #define INVALID_GPIO -1 From 1212dde6b8ad0020bd42349c3a97ed43849a8458 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=8B=E7=A7=80=E6=9D=B0?= Date: Fri, 10 Aug 2012 10:26:17 +0800 Subject: [PATCH 137/261] phonepad: rk29_rt3261.c set BT incall clock. --- sound/soc/rk29/rk29_rt3261.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/sound/soc/rk29/rk29_rt3261.c b/sound/soc/rk29/rk29_rt3261.c index ff9d3f0995d4..c4573578ba13 100644 --- a/sound/soc/rk29/rk29_rt3261.c +++ b/sound/soc/rk29/rk29_rt3261.c @@ -1,7 +1,7 @@ /* - * rk29_rt5625.c -- SoC audio for rockchip + * rk29_rt3261.c -- SoC audio for rockchip * - * Driver for rockchip rt5625 audio + * Driver for rockchip rt3261 audio * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -101,7 +101,7 @@ static int rk29_hw_params(struct snd_pcm_substream *substream, ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN); if (ret < 0) { - DBG("rk29_hw_params_rt5625:failed to set the sysclk for codec side\n"); + DBG("rk29_hw_params_rt3261:failed to set the sysclk for codec side\n"); return ret; } @@ -125,19 +125,8 @@ static int rt3261_voice_hw_params(struct snd_pcm_substream *substream, DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); - /* set codec DAI configuration */ - //#if defined (CONFIG_SND_CODEC_SOC_SLAVE) - DBG("Enter::%s----codec slave\n",__FUNCTION__); - - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS); - /*#endif - //#if defined (CONFIG_SND_CODEC_SOC_MASTER) - DBG("Enter::%s----codec master\n",__FUNCTION__); - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBM_CFM ); - #endif*/ switch(params_rate(params)) { case 8000: @@ -158,17 +147,24 @@ static int rt3261_voice_hw_params(struct snd_pcm_substream *substream, break; } - //snd_soc_dai_set_pll(codec_dai, RT5625_PLL_MCLK_TO_VSYSCLK, 0, pll_out, 24576000);??????? + DBG("Enter:%s, %d, rate=%d\n", __FUNCTION__, __LINE__, params_rate(params)); /*Set the system clk for codec*/ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, 24576000, SND_SOC_CLOCK_IN); + snd_soc_dai_set_pll(codec_dai, 0, RT3261_PLL1_S_MCLK, pll_out, 256 * 8000); + + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 256 * 8000, SND_SOC_CLOCK_IN); + if (ret < 0) { - printk("rk29_hw_params_rt5625:failed to set the sysclk for codec side\n"); + printk("rk29_hw_params_rt3261:failed to set the sysclk for codec side\n"); return ret; } - ret = snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0); + snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0); + snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1); + snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3); + + DBG("Enter:%s, %d, pll_out/4/params_rate(params) = %d \n", __FUNCTION__, __LINE__, (pll_out/4)/params_rate(params)); return 0; } From b479d89814a79dc655f82642edb76af2a2236e6f Mon Sep 17 00:00:00 2001 From: xbw Date: Fri, 10 Aug 2012 11:09:32 +0800 Subject: [PATCH 138/261] =?UTF-8?q?SDMMC:=201=E3=80=81modify=20the=20bug,s?= =?UTF-8?q?ome=20High=20speed=20card=20run=20in=20low=20speed.=202?= =?UTF-8?q?=E3=80=81fix=20the=20crash,due=20to=20the=20sdmmc=20interrupt?= =?UTF-8?q?=20occur=20during=20the=20machine=20power-on.=203=E3=80=81fix?= =?UTF-8?q?=20the=20crash,=20due=20to=20the=20Timeout=20timer=20and=20inte?= =?UTF-8?q?rrupt=20at=20the=20same=20time=20to.=204.=20add=20the=20sdio-IN?= =?UTF-8?q?T=20from=20gpio=20interrupt=20for=20wake-up=20host.=205.=20add?= =?UTF-8?q?=20the=20CONFIG=5FWIFI=5FCOMBO=5FMODULE=5FCONTROL=5FFUNC=20for?= =?UTF-8?q?=20combo-module.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arch/arm/mach-rk30/Makefile | 5 + arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c | 280 +++++++++++++++++++++- arch/arm/mach-rk30/board-rk30-sdk.c | 19 +- arch/arm/plat-rk/Kconfig | 13 + arch/arm/plat-rk/include/plat/board.h | 1 + drivers/mmc/card/block.c | 4 + drivers/mmc/core/core.c | 5 + drivers/mmc/host/rk29_sdmmc.c | 220 ++++++++++++++--- 8 files changed, 508 insertions(+), 39 deletions(-) mode change 100644 => 100755 arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c mode change 100644 => 100755 arch/arm/plat-rk/Kconfig diff --git a/arch/arm/mach-rk30/Makefile b/arch/arm/mach-rk30/Makefile index 2167eef284c7..c9be090a0d2f 100755 --- a/arch/arm/mach-rk30/Makefile +++ b/arch/arm/mach-rk30/Makefile @@ -22,7 +22,12 @@ obj-$(CONFIG_DDR_FREQ) += ddr_freq.o obj-$(CONFIG_RK30_I2C_INSRAM) += i2c_sram.o obj-$(CONFIG_MACH_RK3066_SDK) += board-rk30-sdk.o board-rk30-sdk-key.o + +ifeq ($(CONFIG_WIFI_COMBO_MODULE_CONTROL_FUNC),y) obj-$(CONFIG_MACH_RK30_SDK) += board-rk30-sdk.o board-rk30-sdk-key.o +else +obj-$(CONFIG_MACH_RK30_SDK) += board-rk30-sdk.o board-rk30-sdk-key.o board-rk30-sdk-rfkill.o +endif obj-$(CONFIG_MACH_RK30_PHONE) += board-rk30-phone.o board-rk30-phone-key.o obj-$(CONFIG_MACH_RK30_PHONE_PAD) += board-rk30-phonepad.o board-rk30-phonepad-key.o board-rk30-phonepad-rfkill.o obj-$(CONFIG_MACH_RK30_PHONE_LOQUAT) += board-rk30-phone-loquat.o board-rk30-phone-loquat-key.o diff --git a/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c b/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c old mode 100644 new mode 100755 index df39601eaf4b..928959d0c514 --- a/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c +++ b/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c @@ -92,7 +92,19 @@ static void rk29_sdmmc_gpio_open(int device_id, int on) rk30_mux_api_set(GPIO3C1_SDMMC1DATA0_NAME, GPIO3C_GPIO3C1); gpio_request(RK30_PIN3_PC1, "mmc1-data0"); gpio_direction_output(RK30_PIN3_PC1,GPIO_LOW);//set mmc1-data0 to low. + #if defined(CONFIG_WIFI_COMBO_MODULE_CONTROL_FUNC) + rk29_mux_api_set(GPIO3C2_SDMMC1DATA1_NAME, GPIO3C_GPIO3C2); + gpio_request(RK30_PIN3_PC2, "mmc1-data1"); + gpio_direction_output(RK30_PIN3_PC2,GPIO_LOW);//set mmc1-data1 to low. + rk29_mux_api_set(GPIO3C3_SDMMC1DATA2_NAME, GPIO3C_GPIO3C3); + gpio_request(RK30_PIN3_PC3, "mmc1-data2"); + gpio_direction_output(RK30_PIN3_PC3,GPIO_LOW);//set mmc1-data2 to low. + + rk29_mux_api_set(GPIO3C4_SDMMC1DATA3_NAME, GPIO3C_GPIO3C4); + gpio_request(RK30_PIN3_PC4, "mmc1-data3"); + gpio_direction_output(RK30_PIN3_PC4,GPIO_LOW);//set mmc1-data3 to low. + #endif mdelay(100); } #endif @@ -197,9 +209,23 @@ static void rk29_sdmmc_set_iomux(int device_id, unsigned int bus_width) #endif +static int rk29sdk_wifi_status(struct device *dev); +static int rk29sdk_wifi_status_register(void (*callback)(int card_presend, void *dev_id), void *dev_id); -//int rk29sdk_wifi_power_state = 0; -//int rk29sdk_bt_power_state = 0; +#if defined(CONFIG_WIFI_COMBO_MODULE_CONTROL_FUNC) +static int rk29sdk_wifi_mmc0_status(struct device *dev); +static int rk29sdk_wifi_mmc0_status_register(void (*callback)(int card_presend, void *dev_id), void *dev_id); +static int rk29sdk_wifi_mmc0_cd = 0; /* wifi virtual 'card detect' status */ +static void (*wifi_mmc0_status_cb)(int card_present, void *dev_id); +static void *wifi_mmc0_status_cb_devid; + +int rk29sdk_wifi_power_state = 0; +int rk29sdk_bt_power_state = 0; +#endif + +static int rk29sdk_wifi_cd = 0; /* wifi virtual 'card detect' status */ +static void (*wifi_status_cb)(int card_present, void *dev_id); +static void *wifi_status_cb_devid; #ifdef CONFIG_WIFI_CONTROL_FUNC //#define RK29SDK_WIFI_BT_GPIO_POWER_N RK30_PIN3_PD0 @@ -284,10 +310,6 @@ static int __init rk29sdk_init_wifi_mem(void) return -ENOMEM; } -static int rk29sdk_wifi_cd = 0; /* wifi virtual 'card detect' status */ -static void (*wifi_status_cb)(int card_present, void *dev_id); -static void *wifi_status_cb_devid; - static int rk29sdk_wifi_status(struct device *dev) { return rk29sdk_wifi_cd; @@ -418,6 +440,220 @@ static struct resource resources[] = { }, }; + +/////////////////////////////////////////////////////////////////////////////////// +#elif defined(CONFIG_WIFI_COMBO_MODULE_CONTROL_FUNC) + + #if defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD) + #define USE_SDMMC_CONTROLLER_FOR_WIFI 0 + #define RK29SDK_WIFI_COMBO_GPIO_POWER_N RK30_PIN4_PD2 + #define RK29SDK_WIFI_COMBO_GPIO_RESET_N RK30_PIN4_PD1 + #define RK29SDK_WIFI_COMBO_GPIO_VDDIO RK30_PIN1_PA6 + #define RK29SDK_WIFI_COMBO_GPIO_BGF_INT_B RK30_PIN1_PA7 + #define RK29SDK_WIFI_COMBO_GPS_SYNC RK30_PIN3_PC7 + + #else + #define USE_SDMMC_CONTROLLER_FOR_WIFI 1 + #define RK29SDK_WIFI_COMBO_GPIO_POWER_N RK30_PIN3_PD0 + #define RK29SDK_WIFI_COMBO_GPIO_RESET_N RK30_PIN3_PD1 + #define RK29SDK_WIFI_COMBO_GPIO_WIFI_INT_B RK30_PIN3_PD2 + + #define RK29SDK_WIFI_COMBO_GPIO_VDDIO RK30_PIN6_PB4 + #define RK29SDK_WIFI_COMBO_GPIO_BGF_INT_B RK30_PIN3_PC6 + #define RK29SDK_WIFI_COMBO_GPS_SYNC RK30_PIN3_PC7 + #endif + + +#define debug_combo_system 0 + +int rk29sdk_wifi_combo_get_BGFgpio(void) +{ + return RK29SDK_WIFI_COMBO_GPIO_BGF_INT_B; +} +EXPORT_SYMBOL(rk29sdk_wifi_combo_get_BGFgpio); + + +int rk29sdk_wifi_combo_get_GPS_SYNC_gpio(void) +{ + return RK29SDK_WIFI_COMBO_GPS_SYNC; +} +EXPORT_SYMBOL(rk29sdk_wifi_combo_get_GPS_SYNC_gpio); + + +static int rk29sdk_wifi_combo_module_gpio_init(void) +{ + if (gpio_request(RK29SDK_WIFI_COMBO_GPIO_RESET_N, "combo-RST")) + { + pr_info("%s:request combo-RST failed\n", __func__); + return -1; + } + gpio_direction_output(RK29SDK_WIFI_COMBO_GPIO_RESET_N, GPIO_LOW); + + if (gpio_request(RK29SDK_WIFI_COMBO_GPIO_POWER_N, "combo-PMUEN")) + { + pr_info("%s:request combo-PMUEN failed\n", __func__); + return -1; + } + + //gpio_pull_updown(RK29SDK_WIFI_COMBO_GPIO_POWER_N,0); + //gpio_direction_input(RK29SDK_WIFI_COMBO_GPIO_POWER_N); + gpio_direction_output(RK29SDK_WIFI_COMBO_GPIO_POWER_N, GPIO_LOW); + return 0; +} + + +int rk29sdk_wifi_combo_module_power(int on) +{ + if(on) + { + //gpio_set_value(RK29SDK_WIFI_COMBO_GPIO_VDDIO, GPIO_HIGH); + //mdelay(10); + gpio_set_value(RK29SDK_WIFI_COMBO_GPIO_POWER_N, GPIO_HIGH); + mdelay(10); + pr_info("combo-module turn on power\n"); + } + else + { + gpio_set_value(RK29SDK_WIFI_COMBO_GPIO_POWER_N, GPIO_LOW); + mdelay(10); + //gpio_set_value(RK29SDK_WIFI_COMBO_GPIO_VDDIO, GPIO_LOW); + pr_info("combo-module turn off power\n"); + } + return 0; + +} +EXPORT_SYMBOL(rk29sdk_wifi_combo_module_power); + + +int rk29sdk_wifi_combo_module_reset(int on) +{ + if(on) + { + gpio_set_value(RK29SDK_WIFI_COMBO_GPIO_RESET_N, GPIO_HIGH); + pr_info("combo-module reset out 1\n"); + } + else + { + gpio_set_value(RK29SDK_WIFI_COMBO_GPIO_RESET_N, GPIO_LOW); + pr_info("combo-module reset out 0\n"); + } + + return 0; +} +EXPORT_SYMBOL(rk29sdk_wifi_combo_module_reset); + + +static int rk29sdk_wifi_mmc0_status(struct device *dev) +{ + return rk29sdk_wifi_mmc0_cd; +} + +static int rk29sdk_wifi_mmc0_status_register(void (*callback)(int card_present, void *dev_id), void *dev_id) +{ + if(wifi_mmc0_status_cb) + return -EAGAIN; + wifi_mmc0_status_cb = callback; + wifi_mmc0_status_cb_devid = dev_id; + return 0; +} + + +static int rk29sdk_wifi_status(struct device *dev) +{ + return rk29sdk_wifi_cd; +} + +static int rk29sdk_wifi_status_register(void (*callback)(int card_present, void *dev_id), void *dev_id) +{ + if(wifi_status_cb) + return -EAGAIN; + wifi_status_cb = callback; + wifi_status_cb_devid = dev_id; + return 0; +} +extern unsigned int sdio_irq_global; + +int rk29sdk_wifi_power(int on) +{ + pr_info("%s: %d\n", __func__, on); + if (on){ + + #if defined(CONFIG_SDMMC1_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + + #if defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD) + rk29_sdmmc_gpio_open(0, 1); + #else + rk29_sdmmc_gpio_open(1, 0); + mdelay(10); + rk29_sdmmc_gpio_open(1, 1); + #endif + #endif + + mdelay(100); + pr_info("wifi turn on power\n"); + } + else + { +#if defined(CONFIG_SDMMC1_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + #if defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD) + rk29_sdmmc_gpio_open(0, 0); + #else + rk29_sdmmc_gpio_open(1, 0); + #endif +#endif + mdelay(100); + pr_info("wifi shut off power\n"); + + } + + rk29sdk_wifi_power_state = on; + return 0; + +} +EXPORT_SYMBOL(rk29sdk_wifi_power); + + +int rk29sdk_wifi_reset(int on) +{ + return 0; +} +EXPORT_SYMBOL(rk29sdk_wifi_reset); + + +#if defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD) +int rk29sdk_wifi_set_carddetect(int val) +{ + pr_info("%s:%d\n", __func__, val); + rk29sdk_wifi_mmc0_cd = val; + if (wifi_mmc0_status_cb){ + wifi_mmc0_status_cb(val, wifi_mmc0_status_cb_devid); + }else { + pr_warning("%s,in mmc0 nobody to notify\n", __func__); + } + return 0; +} + +#else +int rk29sdk_wifi_set_carddetect(int val) +{ + pr_info("%s:%d\n", __func__, val); + rk29sdk_wifi_cd = val; + if (wifi_status_cb){ + wifi_status_cb(val, wifi_status_cb_devid); + }else { + pr_warning("%s,in mmc1 nobody to notify\n", __func__); + } + return 0; +} +#endif + +EXPORT_SYMBOL(rk29sdk_wifi_set_carddetect); + +#endif /// #endif ---#elif defined(CONFIG_WIFI_COMBO_MODULE_CONTROL_FUNC) + + + +#if 1//defined(CONFIG_WIFI_CONTROL_FUNC) static struct wifi_platform_data rk29sdk_wifi_control = { .set_power = rk29sdk_wifi_power, .set_reset = rk29sdk_wifi_reset, @@ -434,6 +670,38 @@ static struct platform_device rk29sdk_wifi_device = { .platform_data = &rk29sdk_wifi_control, }, }; + +#elif defined(CONFIG_WIFI_COMBO_MODULE_CONTROL_FUNC) + + #if debug_combo_system + static struct combo_module_platform_data rk29sdk_combo_module_control = { + .set_power = rk29sdk_wifi_combo_module_power, + .set_reset = rk29sdk_wifi_combo_module_reset, + }; + + static struct platform_device rk29sdk_combo_module_device = { + .name = "combo-system", + .id = 1, + .dev = { + .platform_data = &rk29sdk_combo_module_control, + }, + }; + #endif + +static struct wifi_platform_data rk29sdk_wifi_control = { + .set_power = rk29sdk_wifi_power, + .set_reset = rk29sdk_wifi_reset, + .set_carddetect = rk29sdk_wifi_set_carddetect, +}; + +static struct platform_device rk29sdk_wifi_device = { + .name = "combo-wifi", + .id = 1, + .dev = { + .platform_data = &rk29sdk_wifi_control, + }, +}; + #endif diff --git a/arch/arm/mach-rk30/board-rk30-sdk.c b/arch/arm/mach-rk30/board-rk30-sdk.c index 78c84866a2d8..c9dc5095026e 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk.c +++ b/arch/arm/mach-rk30/board-rk30-sdk.c @@ -1214,14 +1214,15 @@ static struct platform_device device_ion = { #include "board-rk30-sdk-sdmmc.c" #if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) -#define SDMMC0_WRITE_PROTECT_PIN RK30_PIN3_PB7 //According to your own project to set the value of write-protect-pin. +#define SDMMC0_WRITE_PROTECT_PIN RK30_PIN3_PB2 //According to your own project to set the value of write-protect-pin. #endif #if defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT) -#define SDMMC1_WRITE_PROTECT_PIN RK30_PIN3_PC7 //According to your own project to set the value of write-protect-pin. +#define SDMMC1_WRITE_PROTECT_PIN RK30_PIN3_PB3 //According to your own project to set the value of write-protect-pin. #endif #define RK29SDK_WIFI_SDIO_CARD_DETECT_N RK30_PIN6_PB2 +#define RK29SDK_WIFI_SDIO_CARD_INT RK30_PIN3_PD2 #endif //endif ---#ifdef CONFIG_SDMMC_RK29 @@ -1277,6 +1278,12 @@ struct rk29_sdmmc_platform_data default_sdmmc0_data = { #else .use_dma = 0, #endif + +#if defined(CONFIG_WIFI_COMBO_MODULE_CONTROL_FUNC) + .status = rk29sdk_wifi_mmc0_status, + .register_status_notify = rk29sdk_wifi_mmc0_status_register, +#endif + .detect_irq = RK30_PIN3_PB6, // INVALID_GPIO .enable_sd_wakeup = 0, @@ -1341,7 +1348,7 @@ struct rk29_sdmmc_platform_data default_sdmmc1_data = { #endif #if !defined(CONFIG_USE_SDMMC1_FOR_WIFI_DEVELOP_BOARD) -#ifdef CONFIG_WIFI_CONTROL_FUNC +#if defined(CONFIG_WIFI_CONTROL_FUNC) || defined(CONFIG_WIFI_COMBO_MODULE_CONTROL_FUNC) .status = rk29sdk_wifi_status, .register_status_notify = rk29sdk_wifi_status_register, #endif @@ -1355,6 +1362,10 @@ struct rk29_sdmmc_platform_data default_sdmmc1_data = { .write_prt = INVALID_GPIO, #endif +#if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) + .sdio_INT_gpio = RK29SDK_WIFI_SDIO_CARD_INT, +#endif + #else .detect_irq = INVALID_GPIO, .enable_sd_wakeup = 0, @@ -1472,7 +1483,7 @@ static struct platform_device *devices[] __initdata = { #ifdef CONFIG_RK_IRDA &irda_device, #endif -#ifdef CONFIG_WIFI_CONTROL_FUNC +#if defined(CONFIG_WIFI_CONTROL_FUNC)||defined(CONFIG_WIFI_COMBO_MODULE_CONTROL_FUNC) &rk29sdk_wifi_device, #endif #ifdef CONFIG_RK29_SUPPORT_MODEM diff --git a/arch/arm/plat-rk/Kconfig b/arch/arm/plat-rk/Kconfig old mode 100644 new mode 100755 index 0e8c497183dc..81f2ecdeb0dc --- a/arch/arm/plat-rk/Kconfig +++ b/arch/arm/plat-rk/Kconfig @@ -118,11 +118,24 @@ config RK30_I2C_INSRAM endmenu endif + +choice WIFI_CONTROL + prompt "wifi control func Type." + default WIFI_CONTROL_FUNC + config WIFI_CONTROL_FUNC bool "Enable WiFi control function abstraction" help Enables Power/Reset/Carddetect function abstraction +config WIFI_COMBO_MODULE_CONTROL_FUNC + bool "Enable WiFi_combo_module control function abstraction" + help + Enables Power/Reset/Carddetect function abstraction + +endchoice + + config RK29_VPU tristate "VPU (Video Processing Unit) service driver in kernel" depends on ARCH_RK29 || ARCH_RK30 diff --git a/arch/arm/plat-rk/include/plat/board.h b/arch/arm/plat-rk/include/plat/board.h index 0ab4dbc48116..36013e75c6b2 100755 --- a/arch/arm/plat-rk/include/plat/board.h +++ b/arch/arm/plat-rk/include/plat/board.h @@ -95,6 +95,7 @@ struct rk29_sdmmc_platform_data { int detect_irq; int enable_sd_wakeup; int write_prt; + unsigned int sdio_INT_gpio; //add gpio INT for sdio interrupt.Modifed by xbw at 2012-08-09 }; struct gsensor_platform_data { diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index f7f7a3c9f3cd..99a4909b1d09 100755 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -843,6 +843,10 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req) brq.mrq.cmd = &brq.cmd; brq.mrq.data = &brq.data; + #if defined(CONFIG_SDMMC_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + brq.cmd.retries = 2; //suppot retry read-write; added by xbw@2012-07-14 + #endif + brq.cmd.arg = blk_rq_pos(req); if (!mmc_card_blockaddr(card)) brq.cmd.arg <<= 9; diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 21332db0e5d4..87bf16383c2e 100755 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2010,6 +2010,10 @@ int mmc_suspend_host(struct mmc_host *host) if (host->bus_ops && !host->bus_dead) { if (host->bus_ops->suspend) err = host->bus_ops->suspend(host); + +#if defined(CONFIG_SDMMC_RK29) && defined(CONFIG_SDMMC_RK29_OLD) + //deleted all detail code. //fix the crash bug when error occur during suspend. Modiefyed by xbw at 2012-08-09 +#else if (err == -ENOSYS || !host->bus_ops->resume) { /* * We simply "remove" the card in this case. @@ -2023,6 +2027,7 @@ int mmc_suspend_host(struct mmc_host *host) host->pm_flags = 0; err = 0; } +#endif } mmc_bus_put(host); diff --git a/drivers/mmc/host/rk29_sdmmc.c b/drivers/mmc/host/rk29_sdmmc.c index b7028a0408e6..4b92b9ade2ba 100755 --- a/drivers/mmc/host/rk29_sdmmc.c +++ b/drivers/mmc/host/rk29_sdmmc.c @@ -84,7 +84,7 @@ int debug_level = 5; #define RK29_SDMMC_WAIT_DTO_INTERNVAL 4500 //The time interval from the CMD_DONE_INT to DTO_INT #define RK29_SDMMC_REMOVAL_DELAY 2000 //The time interval from the CD_INT to detect_timer react. -#define RK29_SDMMC_VERSION "Ver.3.07 The last modify date is 2012-04-23" +#define RK29_SDMMC_VERSION "Ver.4.01 The last modify date is 2012-08-09" #if !defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD) #define RK29_CTRL_SDMMC_ID 0 //mainly used by SDMMC @@ -102,7 +102,7 @@ int debug_level = 5; //#define RK29_SDMMC_LIST_QUEUE /* use list-queue for multi-card*/ #define RK29_SDMMC_DEFAULT_SDIO_FREQ 0 // 1--run in default frequency(50Mhz); 0---run in 25Mhz, -#define RK29_MAX_SDIO_FREQ 25000000 //set max-sdio-frequency 25Mhz at the present time。 +#define RK29_MAX_SDIO_FREQ 45000000 //set max-sdio-frequency 25Mhz at the present time enum { EVENT_CMD_COMPLETE = 0, @@ -225,6 +225,11 @@ struct rk29_sdmmc { int gpio_det; #endif +#ifdef CONFIG_RK29_SDIO_IRQ_FROM_GPIO + unsigned int sdio_INT_gpio; + unsigned int sdio_irq; +#endif + #if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) || defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT) int write_protect; #endif @@ -964,6 +969,9 @@ static void rk29_sdmmc_control_host_dma(struct rk29_sdmmc *host, bool enable) static void send_stop_cmd(struct rk29_sdmmc *host) { int ret; + int timeout = 250; + unsigned int value; + if(host->mrq->cmd->error) { @@ -983,8 +991,41 @@ static void send_stop_cmd(struct rk29_sdmmc *host) __FUNCTION__, __LINE__, host->dma_name); } } - - mod_timer(&host->request_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_SEND_START_TIMEOUT+1500)); + + while (--timeout > 0) + { + value = rk29_sdmmc_read(host->regs, SDMMC_STATUS); + if ((value & SDMMC_STAUTS_DATA_BUSY) == 0 &&(value & SDMMC_CMD_FSM_MASK) == SDMMC_CMD_FSM_IDLE) + { + break; + } + mdelay(1); + } + + if(!timeout) + { + printk(KERN_ERR "%d... cmd=%d(arg=0x%x),blksz=%d,blocks=%d,errorStep=0x%x, host->state=%x [%s]\n",\ + __LINE__,host->cmd->opcode, host->cmd->arg, host->cmd->data->blksz, host->cmd->data->blocks,host->errorstep,host->state,host->dma_name); + + //stop DMA + if(host->dodma) + { + rk29_sdmmc_stop_dma(host); + rk29_sdmmc_control_host_dma(host, FALSE); + + host->dodma = 0; + } + + ret= rk29_sdmmc_clear_fifo(host); + if(SDM_SUCCESS != ret) + { + xbwprintk(3, "%s..%d.. clear fifo error before call CMD_STOP [%s]\n", \ + __FUNCTION__, __LINE__, host->dma_name); + } + } + + host->errorstep = 0xe1; + mod_timer(&host->request_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_SEND_START_TIMEOUT+2500)); host->stopcmd.opcode = MMC_STOP_TRANSMISSION; host->stopcmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;; @@ -1005,9 +1046,10 @@ static void send_stop_cmd(struct rk29_sdmmc *host) { rk29_sdmmc_start_error(host); - host->state = STATE_IDLE; + //host->state = STATE_IDLE; host->complete_done = 4; } + host->errorstep = 0xe2; } @@ -1043,7 +1085,11 @@ static int rk29_sdmmc_submit_data_dma(struct rk29_sdmmc *host, struct mmc_data * } if (data->blksz & 3) + { + printk(KERN_WARNING "%s..%d... data_len not aligned to 4bytes. [%s]\n", __FUNCTION__, __LINE__, host->dma_name); return -EINVAL; + } + for_each_sg(data->sg, sg, data->sg_len, i) { if (sg->offset & 3 || sg->length & 3) @@ -1440,6 +1486,10 @@ static int rk29_sdmmc_get_cd(struct mmc_host *mmc) break; } +#if defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD) + set_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); + return 1; +#endif return cdetect; } @@ -1523,7 +1573,11 @@ int rk29_sdmmc_reset_controller(struct rk29_sdmmc *host) if(0== host->pdev->id) { #if !defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD) + #if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) + rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA); + #else rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA | SDMMC_INT_SDIO); + #endif #else rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA); #endif @@ -1531,14 +1585,22 @@ int rk29_sdmmc_reset_controller(struct rk29_sdmmc *host) else if(1== host->pdev->id) { #if !defined(CONFIG_USE_SDMMC1_FOR_WIFI_DEVELOP_BOARD) + #if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) + rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA); + #else rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA | SDMMC_INT_SDIO); + #endif #else rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA); #endif } else { + #if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) + rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA); + #else rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA | SDMMC_INT_SDIO); + #endif } } } @@ -1553,7 +1615,11 @@ int rk29_sdmmc_reset_controller(struct rk29_sdmmc *host) if(0== host->pdev->id) { #if !defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD) + #if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) + rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEIO); + #else rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEIO | SDMMC_INT_SDIO); + #endif #else rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEIO); #endif @@ -1561,14 +1627,22 @@ int rk29_sdmmc_reset_controller(struct rk29_sdmmc *host) else if(1== host->pdev->id) { #if !defined(CONFIG_USE_SDMMC1_FOR_WIFI_DEVELOP_BOARD) + #if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) + rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEIO); + #else rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEIO | SDMMC_INT_SDIO); + #endif #else rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEIO); #endif } else { - rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA | SDMMC_INT_SDIO); + #if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) + rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEIO); + #else + rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEIO | SDMMC_INT_SDIO); + #endif } } } @@ -1821,6 +1895,9 @@ static void rk29_sdmmc_dealwith_timeout(struct rk29_sdmmc *host) host->cmd->data->error = -EILSEQ; rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_DTO); // clear interrupt rk29_sdmmc_set_pending(host, EVENT_DATA_COMPLETE); +#if SDMMC_USE_INT_UNBUSY + rk29_sdmmc_set_pending(host, EVENT_DATA_UNBUSY); +#endif tasklet_schedule(&host->tasklet); break; #if SDMMC_USE_INT_UNBUSY @@ -1851,20 +1928,20 @@ static void rk29_sdmmc_INT_CMD_DONE_timeout(unsigned long host_data) { struct rk29_sdmmc *host = (struct rk29_sdmmc *) host_data; - //spin_lock(&host->lock); + rk29_sdmmc_enable_irq(host, false); if(STATE_SENDING_CMD == host->state) { if(0==host->cmd->retries) { - printk(KERN_WARNING "%s..%d... cmd=%d, INT_CMD_DONE timeout, errorStep=0x%x, host->state=%x [%s]\n",\ - __FUNCTION__, __LINE__,host->cmd->opcode, host->errorstep,host->state,host->dma_name); + printk(KERN_WARNING "%d... cmd=%d, INT_CMD_DONE timeout, errorStep=0x%x, host->state=%x [%s]\n",\ + __LINE__,host->cmd->opcode, host->errorstep,host->state,host->dma_name); } - + rk29_sdmmc_dealwith_timeout(host); } - //spin_unlock(&host->lock); + rk29_sdmmc_enable_irq(host, true); } @@ -1872,7 +1949,7 @@ static void rk29_sdmmc_INT_DTO_timeout(unsigned long host_data) { struct rk29_sdmmc *host = (struct rk29_sdmmc *) host_data; - //spin_lock(&host->lock); + rk29_sdmmc_enable_irq(host, false); #if SDMMC_USE_INT_UNBUSY if( (host->cmdr & SDMMC_CMD_DAT_EXP) &&((STATE_DATA_BUSY == host->state)||(STATE_DATA_UNBUSY == host->state) )) @@ -1888,8 +1965,7 @@ static void rk29_sdmmc_INT_DTO_timeout(unsigned long host_data) rk29_sdmmc_dealwith_timeout(host); } - //spin_unlock(&host->lock); - + rk29_sdmmc_enable_irq(host, true); } @@ -2332,22 +2408,49 @@ static int rk29_sdmmc_get_ro(struct mmc_host *mmc) } +#if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) +static irqreturn_t rk29_sdmmc_sdio_irq_cb(int irq, void *dev_id) +{ + struct rk29_sdmmc *host = dev_id; + //printk("%d..%s: sdio_gpio_int callback. ====[%s]==\n", __LINE__, __FUNCTION__, host->dma_name); + + //rk28_send_wakeup_key(); //wake up backlight + + if(host && host->mmc) + mmc_signal_sdio_irq(host->mmc); + + return IRQ_HANDLED; +} +#endif + static void rk29_sdmmc_enable_sdio_irq(struct mmc_host *mmc, int enable) { - u32 intmask; +#if !defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) + u32 intmask; unsigned long flags; +#endif struct rk29_sdmmc *host = mmc_priv(mmc); - + +#if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) + if(enable) + enable_irq(host->sdio_irq); + //enable_irq_wake(host->sdio_irq); + else + disable_irq_nosync(host->sdio_irq); + +#else spin_lock_irqsave(&host->lock, flags); - - intmask = rk29_sdmmc_read(host->regs, SDMMC_INTMASK); - + + intmask = rk29_sdmmc_read(host->regs, SDMMC_INTMASK); if(enable) rk29_sdmmc_write(host->regs, SDMMC_INTMASK, intmask | SDMMC_INT_SDIO); else rk29_sdmmc_write(host->regs, SDMMC_INTMASK, intmask & ~SDMMC_INT_SDIO); - spin_unlock_irqrestore(&host->lock, flags); + + spin_unlock_irqrestore(&host->lock, flags); +#endif + } @@ -2710,7 +2813,6 @@ static void rk29_sdmmc_tasklet_func(unsigned long priv) struct mmc_data *data = host->cmd->data; enum rk29_sdmmc_state state = host->state; int pending_flag, stopflag; - unsigned long iflags; rk29_sdmmc_enable_irq(host, false); spin_lock(&host->lock);//spin_lock_irqsave(&host->lock, iflags); @@ -2734,7 +2836,11 @@ static void rk29_sdmmc_tasklet_func(unsigned long priv) { xbwprintk(7, "%s..%d.. prev_state= STATE_SENDING_CMD, pendingEvernt=0x%lu [%s]\n",\ __FUNCTION__, __LINE__,host->completed_events, host->dma_name); - + if(host->cmd->error) + { + del_timer_sync(&host->request_timer); + } + if (!rk29_sdmmc_test_and_clear_pending(host, EVENT_CMD_COMPLETE)) break; host->errorstep = 0xfb; @@ -2799,7 +2905,7 @@ static void rk29_sdmmc_tasklet_func(unsigned long priv) ** use DTO_timer for waiting for INT_UNBUSY. ** max 250ms in specification, but adapt 500 for the compatibility of all kinds of sick sdcard. */ - mod_timer(&host->DTO_timer, jiffies + msecs_to_jiffies(500)); + mod_timer(&host->DTO_timer, jiffies + msecs_to_jiffies(2000)); } else { @@ -2902,6 +3008,7 @@ static void rk29_sdmmc_tasklet_func(unsigned long priv) xbwprintk(3,"%d: call send_stop_cmd== %d, completedone=%d, doneflag=%d, hoststate=%x, statusReg=0x%x \n", \ __LINE__,stopflag, host->complete_done, host->mmc->doneflag, state, rk29_sdmmc_read(host->regs, SDMMC_STATUS)); + host->errorstep = 0xe0; state = STATE_SENDING_CMD; send_stop_cmd(host); //Moidfyed by xbw at 2011-09-08 } @@ -2911,6 +3018,13 @@ static void rk29_sdmmc_tasklet_func(unsigned long priv) if(0==host->complete_done) { host->errorstep = 0xf2; + + if(12==host->cmd->opcode) + { + printk(KERN_ERR "%d... cmd=%d(arg=0x%x),blksz=%d,blocks=%d,errorStep=0x%x,\n host->state=%x, statusReg=0x%x [%s]\n",\ + __LINE__,host->mrq->cmd->opcode, host->mrq->cmd->arg, host->mrq->cmd->data->blksz, host->mrq->cmd->data->blocks,\ + host->errorstep,host->state,rk29_sdmmc_read(host->regs, SDMMC_STATUS),host->dma_name); + } spin_unlock(&host->lock);//spin_unlock_irqrestore(&host->lock, iflags); rk29_sdmmc_enable_irq(host, true); @@ -3035,6 +3149,7 @@ static irqreturn_t rk29_sdmmc_interrupt(int irq, void *dev_id) goto Exit_INT; } +#if !defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) if(pending & SDMMC_INT_SDIO) { xbwprintk(7, "%s..%d.. INT_SDIO INT=0x%x [%s]\n", \ @@ -3045,7 +3160,7 @@ static irqreturn_t rk29_sdmmc_interrupt(int irq, void *dev_id) goto Exit_INT; } - +#endif if(pending & SDMMC_INT_RTO) { @@ -3220,6 +3335,10 @@ static int rk29_sdmmc_probe(struct platform_device *pdev) //int irq; int ret = 0; +#if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) + unsigned long trigger_flags; +#endif + /* must have platform data */ pdata = pdev->dev.platform_data; if (!pdata) { @@ -3260,12 +3379,20 @@ static int rk29_sdmmc_probe(struct platform_device *pdev) host->retryfunc = 0; host->mrq = NULL; host->new_mrq = NULL; + host->irq_state = true; #ifdef CONFIG_PM host->gpio_det = pdata->detect_irq; #endif host->set_iomux = pdata->set_iomux; +#if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) + if(RK29_CTRL_SDIO1_ID == host->pdev->id) + { + host->sdio_INT_gpio = pdata->sdio_INT_gpio; + } +#endif + if(pdata->io_init) pdata->io_init(); @@ -3399,8 +3526,12 @@ static int rk29_sdmmc_probe(struct platform_device *pdev) ret = rk29_dma_config(host->dma_info.chn, 4, 16); } else - { - ret = rk29_dma_config(host->dma_info.chn, 4, 1); + { + #if defined(CONFIG_ARCH_RK30) + ret = rk29_dma_config(host->dma_info.chn, 4, 16); // a unified set the burst value to 16 in RK30,noted at 2012-07-16 + #else + ret = rk29_dma_config(host->dma_info.chn, 4, 1); // to maintain set this value to 1 in RK29,noted at 2012-07-16 + #endif } #endif if(ret < 0) @@ -3427,7 +3558,11 @@ static int rk29_sdmmc_probe(struct platform_device *pdev) host->write_protect = pdata->write_prt; #endif - rk29_sdmmc_hw_init(host); + + if(RK29_CTRL_SDMMC_ID != host->pdev->id) + { + rk29_sdmmc_hw_init(host); + } ret = request_irq(host->irq, rk29_sdmmc_interrupt, 0, dev_name(&pdev->dev), host); if (ret) @@ -3438,8 +3573,35 @@ static int rk29_sdmmc_probe(struct platform_device *pdev) host->errorstep = 0x8C; goto err_dmaunmap; } - - host->irq_state = true; + +#if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) + if(RK29_CTRL_SDIO1_ID == host->pdev->id) + { + gpio_request(host->sdio_INT_gpio, "sdio_interrupt"); + + // intput + pull_Up, + gpio_direction_input(host->sdio_INT_gpio); + //gpio_direction_output(host->sdio_INT_gpio, GPIO_HIGH); + gpio_pull_updown(host->sdio_INT_gpio, 0); //disable default internal pull-down + + host->sdio_irq = gpio_to_irq(host->sdio_INT_gpio); + trigger_flags = IRQF_TRIGGER_LOW; + //printk("%d..%s sdio interrupt gpio level=%lu ====[%s]====\n", __LINE__, __FUNCTION__, trigger_flags, host->dma_name); + ret = request_irq(host->sdio_irq, rk29_sdmmc_sdio_irq_cb, + trigger_flags, + "sdio_interrupt", + host); + if (ret) + { + + printk("%s..%d.. sdio_request_INT_irq error=%d ====xbw[%s]====\n", \ + __FUNCTION__, __LINE__, ret, host->dma_name); + host->errorstep = 0x8D; + goto err_dmaunmap; + } + disable_irq_nosync(host->sdio_irq); + } +#endif /* setup sdmmc1 wifi card detect change */ if (pdata->register_status_notify) { From b1be4be2e6a87feeb3ecce933df6fd8f06bb834d Mon Sep 17 00:00:00 2001 From: chenxing Date: Fri, 10 Aug 2012 11:11:02 +0800 Subject: [PATCH 139/261] rk2928:sdk: add cif set rate interface --- arch/arm/mach-rk2928/clock_data.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/arch/arm/mach-rk2928/clock_data.c b/arch/arm/mach-rk2928/clock_data.c index 229272289feb..8584e6d4d955 100644 --- a/arch/arm/mach-rk2928/clock_data.c +++ b/arch/arm/mach-rk2928/clock_data.c @@ -1393,6 +1393,24 @@ static struct clk hclk_gps = { }; #endif /****************camera*******************/ +static int cif_out_set_rate(struct clk *clk, unsigned long rate) +{ + int ret = 0; + struct clk *parent; + + if (rate == 24 * MHZ) { + parent =clk->parents[1]; + } else { + parent=clk->parents[0]; + ret = clk_set_rate_nolock(parent, rate); + if (ret) + return ret; + } + if (clk->parent != parent) + ret = clk_set_parent_nolock(clk, parent); + + return ret; +} static struct clk *clk_cif_out_div_parents[] = SELECT_FROM_2PLLS_CG; static struct clk clk_cif_out_div = { .name = "cif_out_div", @@ -1410,6 +1428,7 @@ static struct clk *clk_cif_out_parents[] = {&clk_cif_out_div, &xin24m}; static struct clk clk_cif_out = { .name = "cif0_out", .parent = &clk_cif_out_div, + .set_rate = cif_out_set_rate, .clksel_con = CRU_CLKSELS_CON(29), CRU_SRC_SET(0x1, 7), CRU_PARENTS_SET(clk_cif_out_parents), From 4644fe5e5b3b638dace97adddec4f3673710254f Mon Sep 17 00:00:00 2001 From: xbw Date: Fri, 10 Aug 2012 12:31:57 +0800 Subject: [PATCH 140/261] revert the mach-rk30-Makefie. commit error in b479d89814a79dc655f82642edb76af2a2236e6f --- arch/arm/mach-rk30/Makefile | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/arm/mach-rk30/Makefile b/arch/arm/mach-rk30/Makefile index c9be090a0d2f..2167eef284c7 100755 --- a/arch/arm/mach-rk30/Makefile +++ b/arch/arm/mach-rk30/Makefile @@ -22,12 +22,7 @@ obj-$(CONFIG_DDR_FREQ) += ddr_freq.o obj-$(CONFIG_RK30_I2C_INSRAM) += i2c_sram.o obj-$(CONFIG_MACH_RK3066_SDK) += board-rk30-sdk.o board-rk30-sdk-key.o - -ifeq ($(CONFIG_WIFI_COMBO_MODULE_CONTROL_FUNC),y) obj-$(CONFIG_MACH_RK30_SDK) += board-rk30-sdk.o board-rk30-sdk-key.o -else -obj-$(CONFIG_MACH_RK30_SDK) += board-rk30-sdk.o board-rk30-sdk-key.o board-rk30-sdk-rfkill.o -endif obj-$(CONFIG_MACH_RK30_PHONE) += board-rk30-phone.o board-rk30-phone-key.o obj-$(CONFIG_MACH_RK30_PHONE_PAD) += board-rk30-phonepad.o board-rk30-phonepad-key.o board-rk30-phonepad-rfkill.o obj-$(CONFIG_MACH_RK30_PHONE_LOQUAT) += board-rk30-phone-loquat.o board-rk30-phone-loquat-key.o From a2809576eed3bb270f46465d9bd7c1f1564af1f4 Mon Sep 17 00:00:00 2001 From: xbw Date: Fri, 10 Aug 2012 13:58:23 +0800 Subject: [PATCH 141/261] sdmmc: continue with commit b479d89814a79dc655f82642edb76af2a2236e6f. --- arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c | 2 +- drivers/mmc/host/Kconfig | 10 ++++++++++ drivers/mmc/host/rk29_sdmmc.c | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c b/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c index 928959d0c514..817269750485 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c +++ b/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c @@ -653,7 +653,7 @@ EXPORT_SYMBOL(rk29sdk_wifi_set_carddetect); -#if 1//defined(CONFIG_WIFI_CONTROL_FUNC) +#if defined(CONFIG_WIFI_CONTROL_FUNC) static struct wifi_platform_data rk29sdk_wifi_control = { .set_power = rk29sdk_wifi_power, .set_reset = rk29sdk_wifi_reset, diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index bb2c399c89b9..fabf9737c020 100755 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -54,6 +54,16 @@ if SDMMC_RK29 You will add the feature of write-protect for sdio-card if you say Yes. Please note that this feature requires hardware support. + config RK29_SDIO_IRQ_FROM_GPIO + bool "sdio-irq from gpio" + default n + depends on SDMMC1_RK29 + help + You will generate sdio interrupt from gpio if you say Yes. + Please note that this feature requires hardware support. + + + # config USE_SDMMC1_FOR_WIFI_DEVELOP_BOARD # depends on SDMMC1_RK29 # bool "Switch the driver SDMMC1 for the debug of wifi_develop_board." diff --git a/drivers/mmc/host/rk29_sdmmc.c b/drivers/mmc/host/rk29_sdmmc.c index 4b92b9ade2ba..d2d600ab7e53 100755 --- a/drivers/mmc/host/rk29_sdmmc.c +++ b/drivers/mmc/host/rk29_sdmmc.c @@ -3019,7 +3019,7 @@ static void rk29_sdmmc_tasklet_func(unsigned long priv) { host->errorstep = 0xf2; - if(12==host->cmd->opcode) + if(0) //(12==host->cmd->opcode) { printk(KERN_ERR "%d... cmd=%d(arg=0x%x),blksz=%d,blocks=%d,errorStep=0x%x,\n host->state=%x, statusReg=0x%x [%s]\n",\ __LINE__,host->mrq->cmd->opcode, host->mrq->cmd->arg, host->mrq->cmd->data->blksz, host->mrq->cmd->data->blocks,\ From 17f39ed917874e77e80411f33faba1b7ee8138c8 Mon Sep 17 00:00:00 2001 From: xbw Date: Fri, 10 Aug 2012 14:02:20 +0800 Subject: [PATCH 142/261] add MTK-combo-module --- arch/arm/mach-rk30/board-rk30-sdk.c | 13 +++++++++++++ drivers/Kconfig | 2 ++ drivers/Makefile | 1 + drivers/gpio/gpiolib.c | 23 ++++++++++++++++------- drivers/net/wireless/Kconfig | 10 ++++++++++ include/net/cfg80211.h | 5 +++++ net/bluetooth/hci_core.c | 2 ++ 7 files changed, 49 insertions(+), 7 deletions(-) mode change 100644 => 100755 drivers/gpio/gpiolib.c mode change 100644 => 100755 drivers/net/wireless/Kconfig mode change 100644 => 100755 include/net/cfg80211.h mode change 100644 => 100755 net/bluetooth/hci_core.c diff --git a/arch/arm/mach-rk30/board-rk30-sdk.c b/arch/arm/mach-rk30/board-rk30-sdk.c index c9dc5095026e..dc753d662cff 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk.c +++ b/arch/arm/mach-rk30/board-rk30-sdk.c @@ -67,6 +67,10 @@ #include "../../../drivers/staging/android/timed_gpio.h" #endif +#if defined(CONFIG_MT6620) +#include +#endif + #ifdef CONFIG_THREE_FB_BUFFER #define RK30_FB0_MEM_SIZE 12*SZ_1M #else @@ -1486,6 +1490,11 @@ static struct platform_device *devices[] __initdata = { #if defined(CONFIG_WIFI_CONTROL_FUNC)||defined(CONFIG_WIFI_COMBO_MODULE_CONTROL_FUNC) &rk29sdk_wifi_device, #endif + +#if defined(CONFIG_MT6620) + &mt3326_device_gps, +#endif + #ifdef CONFIG_RK29_SUPPORT_MODEM &rk30_device_modem, #endif @@ -1822,6 +1831,10 @@ static void __init machine_rk30_board_init(void) #ifdef CONFIG_WIFI_CONTROL_FUNC rk29sdk_wifi_bt_gpio_control_init(); #endif + +#if defined(CONFIG_MT6620) + clk_set_rate(clk_get_sys("rk_serial.0", "uart"), 16*1000000); +#endif } static void __init rk30_reserve(void) diff --git a/drivers/Kconfig b/drivers/Kconfig index a95047a6fe0a..fd5737ef1600 100755 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -140,4 +140,6 @@ source "drivers/smc/Kconfig" source "drivers/cir/Kconfig" +source "drivers/mtk_wcn_combo/Kconfig" + endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 12345dd77085..bb738dfc653a 100755 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -130,3 +130,4 @@ obj-$(CONFIG_TEST_CODE) += testcode/ obj-y += smc/ obj-y += cir/ obj-$(CONFIG_ARCH_RK29) += dbg/ +obj-$(CONFIG_MTK_COMBO) += mtk_wcn_combo/ diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c old mode 100644 new mode 100755 index 05c523cd2694..95a097256c97 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1225,7 +1225,7 @@ int gpio_request(unsigned gpio, const char *label) spin_unlock_irqrestore(&gpio_lock, flags); return status; } -EXPORT_SYMBOL_GPL(gpio_request); +EXPORT_SYMBOL(gpio_request);//EXPORT_SYMBOL_GPL(gpio_request); void gpio_free(unsigned gpio) { @@ -1262,7 +1262,9 @@ void gpio_free(unsigned gpio) spin_unlock_irqrestore(&gpio_lock, flags); } -EXPORT_SYMBOL_GPL(gpio_free); +//EXPORT_SYMBOL_GPL(gpio_free); +EXPORT_SYMBOL(gpio_free); + /** * gpio_request_one - request a single GPIO with initial configuration @@ -1418,7 +1420,9 @@ int gpio_direction_input(unsigned gpio) __func__, gpio, status); return status; } -EXPORT_SYMBOL_GPL(gpio_direction_input); +//EXPORT_SYMBOL_GPL(gpio_direction_input); +EXPORT_SYMBOL(gpio_direction_input); + int gpio_direction_output(unsigned gpio, int value) { @@ -1475,7 +1479,8 @@ int gpio_direction_output(unsigned gpio, int value) __func__, gpio, status); return status; } -EXPORT_SYMBOL_GPL(gpio_direction_output); +//EXPORT_SYMBOL_GPL(gpio_direction_output); +EXPORT_SYMBOL(gpio_direction_output); /* gpio pull up or pull down @@ -1536,7 +1541,8 @@ int gpio_pull_updown(unsigned gpio, unsigned value) __func__, gpio, status); return status; } -EXPORT_SYMBOL_GPL(gpio_pull_updown); +//EXPORT_SYMBOL_GPL(gpio_pull_updown); +EXPORT_SYMBOL(gpio_pull_updown); /** * gpio_set_debounce - sets @debounce time for a @gpio @@ -1626,7 +1632,9 @@ int __gpio_get_value(unsigned gpio) trace_gpio_value(gpio, 1, value); return value; } -EXPORT_SYMBOL_GPL(__gpio_get_value); +//EXPORT_SYMBOL_GPL(__gpio_get_value); +EXPORT_SYMBOL(__gpio_get_value); + /** * __gpio_set_value() - assign a gpio's value @@ -1650,7 +1658,8 @@ void __gpio_set_value(unsigned gpio, int value) trace_gpio_value(gpio, 0, value); chip->set(chip, gpio - chip->base, value); } -EXPORT_SYMBOL_GPL(__gpio_set_value); +//EXPORT_SYMBOL_GPL(__gpio_set_value); +EXPORT_SYMBOL(__gpio_set_value); /** * __gpio_cansleep() - report whether gpio value access will sleep diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig old mode 100644 new mode 100755 index 59c5914ddf52..792268c67c2e --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -55,6 +55,16 @@ choice ---help--- A library for Broadcom BCM4319 SDIO WLAN devices. + config MT6620 + depends on WLAN_80211 && MMC && MTK_COMBO + select WIRELESS_EXT + select WEXT_PRIV + select IEEE80211 + select FW_LOADER + bool "MTK MT6620 WiFi SDIO" + ---help--- + A library for MTK_wcn_combo SDIO WLAN devices. + config MV8686 depends on WLAN_80211 && MMC select WIRELESS_EXT diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h old mode 100644 new mode 100755 index 396e8fc8910e..fc55a37ea6ae --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -558,6 +558,11 @@ struct station_info { struct sta_bss_parameters bss_param; int generation; + +#if defined(CONFIG_MT6620) + const u8 *assoc_req_ies; + size_t assoc_req_ies_len; +#endif }; /** diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c old mode 100644 new mode 100755 index 3b3919864078..ca8e80e6e5df --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1530,6 +1530,7 @@ int hci_register_dev(struct hci_dev *hdev) hci_register_sysfs(hdev); +#if !defined(CONFIG_MT6620) hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev, RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, hdev); if (hdev->rfkill) { @@ -1542,6 +1543,7 @@ int hci_register_dev(struct hci_dev *hdev) set_bit(HCI_AUTO_OFF, &hdev->flags); set_bit(HCI_SETUP, &hdev->flags); queue_work(hdev->workqueue, &hdev->power_on); +#endif hci_notify(hdev, HCI_DEV_REG); From cc865eecde1edc66b3cb21607e0135590f860309 Mon Sep 17 00:00:00 2001 From: Zhaoyifeng Date: Fri, 10 Aug 2012 14:06:55 +0800 Subject: [PATCH 143/261] add reboot cmd save in grf os reg. --- arch/arm/mach-rk29/include/mach/loader.h | 0 arch/arm/mach-rk2928/include/mach/iomux.h | 4 ++++ arch/arm/mach-rk2928/reset.c | 15 +++++++++++---- 3 files changed, 15 insertions(+), 4 deletions(-) mode change 100644 => 100755 arch/arm/mach-rk29/include/mach/loader.h mode change 100644 => 100755 arch/arm/mach-rk2928/reset.c diff --git a/arch/arm/mach-rk29/include/mach/loader.h b/arch/arm/mach-rk29/include/mach/loader.h old mode 100644 new mode 100755 diff --git a/arch/arm/mach-rk2928/include/mach/iomux.h b/arch/arm/mach-rk2928/include/mach/iomux.h index 6e7ab6a2fee9..b5a2eb40b08b 100755 --- a/arch/arm/mach-rk2928/include/mach/iomux.h +++ b/arch/arm/mach-rk2928/include/mach/iomux.h @@ -448,6 +448,10 @@ #define GRF_OS_REG1 0x01cc #define GRF_OS_REG2 0x01d0 #define GRF_OS_REG3 0x01d4 +#define GRF_OS_REG4 0x01d8 +#define GRF_OS_REG5 0x01dc +#define GRF_OS_REG6 0x01e0 +#define GRF_OS_REG7 0x01e4 #define MUX_CFG(desc,reg,off,interl,mux_mode,bflags) \ { \ diff --git a/arch/arm/mach-rk2928/reset.c b/arch/arm/mach-rk2928/reset.c old mode 100644 new mode 100755 index 5a0fb4cd00ed..b851b92fa6b5 --- a/arch/arm/mach-rk2928/reset.c +++ b/arch/arm/mach-rk2928/reset.c @@ -1,10 +1,11 @@ #include #include +#include #include -#include #include #include -#include +#include +#include static void rk2928_arch_reset(char mode, const char *cmd) { @@ -12,13 +13,19 @@ static void rk2928_arch_reset(char mode, const char *cmd) u32 boot_mode = BOOT_MODE_REBOOT; if (cmd) { - if (!strcmp(cmd, "charge")) + if (!strcmp(cmd, "loader") || !strcmp(cmd, "bootloader")) + boot_flag = SYS_LOADER_REBOOT_FLAG + BOOT_LOADER; + else if(!strcmp(cmd, "recovery")) + boot_flag = SYS_LOADER_REBOOT_FLAG + BOOT_RECOVER; + else if (!strcmp(cmd, "charge")) boot_mode = BOOT_MODE_CHARGE; } else { if (system_state != SYSTEM_RESTART) boot_mode = BOOT_MODE_PANIC; } - writel_relaxed(0xffff0000 | boot_mode, RK2928_GRF_BASE + GRF_OS_REG1); // for linux + writel_relaxed(0xffff0000 | (boot_flag&0xFFFFuL), RK2928_GRF_BASE + GRF_OS_REG4); // for loader + writel_relaxed(0xffff0000 | ((boot_flag>>16)&0xFFFFuL), RK2928_GRF_BASE + GRF_OS_REG5); // for loader + writel_relaxed(0xffff0000 | boot_mode, RK2928_GRF_BASE + GRF_OS_REG6); // for linux dsb(); /* disable remap */ writel_relaxed(1 << (12 + 16), RK2928_GRF_BASE + GRF_SOC_CON0); From c0652393eb928fd0003f86a5dd13598858032ec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Fri, 10 Aug 2012 14:22:32 +0800 Subject: [PATCH 144/261] rk: move loader.h from mach-rk30 to plat-rk --- arch/arm/mach-rk2928/include/mach/loader.h | 1 + arch/arm/mach-rk30/include/mach/loader.h | 36 +--------------------- arch/arm/plat-rk/include/plat/loader.h | 21 +++++++++++++ 3 files changed, 23 insertions(+), 35 deletions(-) create mode 100644 arch/arm/mach-rk2928/include/mach/loader.h create mode 100644 arch/arm/plat-rk/include/plat/loader.h diff --git a/arch/arm/mach-rk2928/include/mach/loader.h b/arch/arm/mach-rk2928/include/mach/loader.h new file mode 100644 index 000000000000..6549ed217341 --- /dev/null +++ b/arch/arm/mach-rk2928/include/mach/loader.h @@ -0,0 +1 @@ +#include diff --git a/arch/arm/mach-rk30/include/mach/loader.h b/arch/arm/mach-rk30/include/mach/loader.h index f0006b94a684..6549ed217341 100644 --- a/arch/arm/mach-rk30/include/mach/loader.h +++ b/arch/arm/mach-rk30/include/mach/loader.h @@ -1,35 +1 @@ -/* arch/arm/mach-rk29/include/mach/loader.h - * - * Copyright (C) 2011 ROCKCHIP, Inc. - * - * 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. - * - */ -#ifndef __ASM_ARCH_RK30_LOADER_H -#define __ASM_ARCH_RK30_LOADER_H - -#define SYS_LOADER_REBOOT_FLAG 0x5242C300 //high 24 bits is tag, low 8 bits is type -#define SYS_KERNRL_REBOOT_FLAG 0xC3524200 //high 24 bits is tag, low 8 bits is type - -enum { - BOOT_NORMAL = 0, /* normal boot */ - BOOT_LOADER, /* enter loader rockusb mode */ - BOOT_MASKROM, /* enter maskrom rockusb mode (not support now) */ - BOOT_RECOVER, /* enter recover */ - BOOT_NORECOVER, /* do not enter recover */ - BOOT_SECONDOS, /* boot second OS (not support now)*/ - BOOT_WIPEDATA, /* enter recover and wipe data. */ - BOOT_WIPEALL, /* enter recover and wipe all data. */ - BOOT_CHECKIMG, /* check firmware img with backup part(in loader mode)*/ - BOOT_FASTBOOT, /* enter fast boot mode (not support now) */ - BOOT_MAX /* MAX VALID BOOT TYPE.*/ -}; - -#endif +#include diff --git a/arch/arm/plat-rk/include/plat/loader.h b/arch/arm/plat-rk/include/plat/loader.h new file mode 100644 index 000000000000..bb83a86b4452 --- /dev/null +++ b/arch/arm/plat-rk/include/plat/loader.h @@ -0,0 +1,21 @@ +#ifndef __PLAT_LOADER_H +#define __PLAT_LOADER_H + +#define SYS_LOADER_REBOOT_FLAG 0x5242C300 //high 24 bits is tag, low 8 bits is type +#define SYS_KERNRL_REBOOT_FLAG 0xC3524200 //high 24 bits is tag, low 8 bits is type + +enum { + BOOT_NORMAL = 0, /* normal boot */ + BOOT_LOADER, /* enter loader rockusb mode */ + BOOT_MASKROM, /* enter maskrom rockusb mode (not support now) */ + BOOT_RECOVER, /* enter recover */ + BOOT_NORECOVER, /* do not enter recover */ + BOOT_SECONDOS, /* boot second OS (not support now)*/ + BOOT_WIPEDATA, /* enter recover and wipe data. */ + BOOT_WIPEALL, /* enter recover and wipe all data. */ + BOOT_CHECKIMG, /* check firmware img with backup part(in loader mode)*/ + BOOT_FASTBOOT, /* enter fast boot mode (not support now) */ + BOOT_MAX /* MAX VALID BOOT TYPE.*/ +}; + +#endif From ddb1decf73a2573c43f5d0a2dafc88755dad1515 Mon Sep 17 00:00:00 2001 From: xbw Date: Fri, 10 Aug 2012 14:27:55 +0800 Subject: [PATCH 145/261] add MTK-combo-module,continue with commit 17f39ed917874e77e80411f33faba1b7ee8138c8 --- .../mach-rk30/include/mach/mtk_wcn_cmb_stub.h | 213 + drivers/mtk_wcn_combo/Kconfig | 141 + drivers/mtk_wcn_combo/Makefile | 60 + drivers/mtk_wcn_combo/common/Makefile | 92 + .../mtk_wcn_combo/common/include/core_exp.h | 253 + .../common/include/mtk_wcn_cmb_hw.h | 165 + drivers/mtk_wcn_combo/common/include/osal.h | 429 + .../mtk_wcn_combo/common/include/stp_exp.h | 303 + drivers/mtk_wcn_combo/common/include/wmt.h | 8 + .../mtk_wcn_combo/common/include/wmt_exp.h | 320 + .../mtk_wcn_combo/common/include/wmt_plat.h | 260 + drivers/mtk_wcn_combo/common/linux/hif_sdio.c | 2357 ++++ .../common/linux/hw_chrdev_test.c | 611 + .../common/linux/hw_sdio_client.c | 233 + .../common/linux/include/hif_sdio.h | 350 + .../common/linux/include/hw_test.h | 146 + .../common/linux/include/mtk_wcn_cmb_stub.h | 213 + .../common/linux/include/osal_linux.h | 120 + .../common/linux/include/osal_typedef.h | 98 + .../common/linux/include/wmt_dev.h | 50 + drivers/mtk_wcn_combo/common/linux/osal.c | 1567 +++ .../common/linux/stp_chrdev_bt.c | 527 + .../common/linux/stp_chrdev_gps.c | 442 + drivers/mtk_wcn_combo/common/linux/stp_exp.c | 304 + drivers/mtk_wcn_combo/common/linux/stp_uart.c | 1250 ++ .../common/linux/wmt_chrdev_wifi.c | 209 + drivers/mtk_wcn_combo/common/linux/wmt_dev.c | 906 ++ drivers/mtk_wcn_combo/common/linux/wmt_exp.c | 384 + .../platform/rockchip/mtk_wcn_cmb_hw_6620.c | 346 + .../rockchip/mtk_wcn_cmb_stub_rockchip.c | 348 + .../platform/rockchip/wmt_plat_rockchip.c | 906 ++ drivers/mtk_wcn_combo/drv_bt/Makefile | 43 + .../mtk_wcn_combo/drv_bt/include/hci_stp.h | 204 + drivers/mtk_wcn_combo/drv_bt/linux/hci_stp.c | 1708 +++ drivers/mtk_wcn_combo/drv_fm/Makefile | 47 + drivers/mtk_wcn_combo/drv_fm/include/fm.h | 520 + drivers/mtk_wcn_combo/drv_fm/private/Makefile | 51 + drivers/mtk_wcn_combo/drv_fm/private/mtk_fm.h | 116 + drivers/mtk_wcn_combo/drv_fm/public/Makefile | 47 + .../mtk_wcn_combo/drv_fm/public/mt6620_fm.c | 5257 ++++++++ .../mtk_wcn_combo/drv_fm/public/mt6620_fm.h | 597 + .../drv_fm/public/mt6620_fm_lib.c | 1486 +++ .../drv_fm/public/mt6620_fm_lib.h | 94 + .../drv_fm/public/mt6620_fm_reg.h | 65 + .../mtk_wcn_combo/drv_fm/public/mt6620_rds.c | 1878 +++ drivers/mtk_wcn_combo/drv_wlan/Makefile | 49 + drivers/mtk_wcn_combo/drv_wlan/p2p/Makefile | 120 + .../drv_wlan/p2p/common/wlan_p2p.c | 1867 +++ .../drv_wlan/p2p/include/mgmt/p2p_assoc.h | 104 + .../drv_wlan/p2p/include/mgmt/p2p_bss.h | 105 + .../drv_wlan/p2p/include/mgmt/p2p_fsm.h | 2664 ++++ .../drv_wlan/p2p/include/mgmt/p2p_func.h | 284 + .../drv_wlan/p2p/include/mgmt/p2p_ie.h | 28 + .../drv_wlan/p2p/include/mgmt/p2p_rlm.h | 149 + .../drv_wlan/p2p/include/mgmt/p2p_rlm_obss.h | 133 + .../drv_wlan/p2p/include/mgmt/p2p_scan.h | 167 + .../drv_wlan/p2p/include/mgmt/p2p_state.h | 88 + .../drv_wlan/p2p/include/nic/p2p.h | 235 + .../drv_wlan/p2p/include/nic/p2p_cmd_buf.h | 137 + .../drv_wlan/p2p/include/nic/p2p_mac.h | 263 + .../drv_wlan/p2p/include/nic/p2p_nic.h | 114 + .../p2p/include/nic/p2p_nic_cmd_event.h | 113 + .../drv_wlan/p2p/include/p2p_precomp.h | 265 + .../drv_wlan/p2p/include/wlan_p2p.h | 454 + .../drv_wlan/p2p/mgmt/p2p_assoc.c | 139 + .../mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_bss.c | 125 + .../mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_fsm.c | 3155 +++++ .../drv_wlan/p2p/mgmt/p2p_func.c | 2940 +++++ .../mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_ie.c | 73 + .../mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_rlm.c | 1048 ++ .../drv_wlan/p2p/mgmt/p2p_rlm_obss.c | 414 + .../drv_wlan/p2p/mgmt/p2p_scan.c | 865 ++ .../drv_wlan/p2p/mgmt/p2p_state.c | 544 + .../mtk_wcn_combo/drv_wlan/p2p/nic/p2p_nic.c | 243 + .../drv_wlan/p2p/os/linux/gl_p2p.c | 5405 ++++++++ .../drv_wlan/p2p/os/linux/gl_p2p_cfg80211.c | 1755 +++ .../drv_wlan/p2p/os/linux/gl_p2p_init.c | 709 ++ .../drv_wlan/p2p/os/linux/gl_p2p_kal.c | 1509 +++ .../p2p/os/linux/include/gl_p2p_ioctl.h | 1085 ++ .../p2p/os/linux/include/gl_p2p_kal.h | 421 + .../drv_wlan/p2p/os/linux/include/gl_p2p_os.h | 206 + drivers/mtk_wcn_combo/drv_wlan/wlan/Makefile | 154 + .../mtk_wcn_combo/drv_wlan/wlan/common/dump.c | 583 + .../drv_wlan/wlan/common/wlan_bow.c | 3962 ++++++ .../drv_wlan/wlan/common/wlan_lib.c | 4934 ++++++++ .../drv_wlan/wlan/common/wlan_oid.c | 10556 ++++++++++++++++ .../drv_wlan/wlan/include/CFG_Wifi_File.h | 284 + .../drv_wlan/wlan/include/config.h | 1410 +++ .../drv_wlan/wlan/include/debug.h | 566 + .../drv_wlan/wlan/include/link.h | 458 + .../drv_wlan/wlan/include/mgmt/aa_fsm.h | 295 + .../drv_wlan/wlan/include/mgmt/ais_fsm.h | 719 ++ .../drv_wlan/wlan/include/mgmt/assoc.h | 191 + .../drv_wlan/wlan/include/mgmt/auth.h | 219 + .../drv_wlan/wlan/include/mgmt/bow_fsm.h | 234 + .../drv_wlan/wlan/include/mgmt/bss.h | 457 + .../drv_wlan/wlan/include/mgmt/cnm.h | 362 + .../drv_wlan/wlan/include/mgmt/cnm_mem.h | 1196 ++ .../drv_wlan/wlan/include/mgmt/cnm_scan.h | 250 + .../drv_wlan/wlan/include/mgmt/cnm_timer.h | 318 + .../drv_wlan/wlan/include/mgmt/hem_mbox.h | 486 + .../drv_wlan/wlan/include/mgmt/mib.h | 201 + .../drv_wlan/wlan/include/mgmt/privacy.h | 332 + .../drv_wlan/wlan/include/mgmt/rate.h | 155 + .../drv_wlan/wlan/include/mgmt/rlm.h | 498 + .../drv_wlan/wlan/include/mgmt/rlm_domain.h | 395 + .../drv_wlan/wlan/include/mgmt/rlm_obss.h | 208 + .../wlan/include/mgmt/rlm_protection.h | 170 + .../drv_wlan/wlan/include/mgmt/roaming_fsm.h | 245 + .../drv_wlan/wlan/include/mgmt/rsn.h | 424 + .../drv_wlan/wlan/include/mgmt/scan.h | 896 ++ .../drv_wlan/wlan/include/mgmt/sec_fsm.h | 328 + .../drv_wlan/wlan/include/mgmt/swcr.h | 220 + .../drv_wlan/wlan/include/mgmt/wapi.h | 164 + .../drv_wlan/wlan/include/mgmt/wlan_typedef.h | 128 + .../drv_wlan/wlan/include/nic/adapter.h | 1447 +++ .../drv_wlan/wlan/include/nic/bow.h | 366 + .../drv_wlan/wlan/include/nic/cmd_buf.h | 220 + .../drv_wlan/wlan/include/nic/hal.h | 654 + .../drv_wlan/wlan/include/nic/hif_emu.h | 308 + .../drv_wlan/wlan/include/nic/hif_rx.h | 271 + .../drv_wlan/wlan/include/nic/hif_tx.h | 269 + .../drv_wlan/wlan/include/nic/mac.h | 2178 ++++ .../drv_wlan/wlan/include/nic/mt5931_reg.h | 340 + .../drv_wlan/wlan/include/nic/mt6620_reg.h | 330 + .../drv_wlan/wlan/include/nic/nic.h | 764 ++ .../drv_wlan/wlan/include/nic/nic_rx.h | 577 + .../drv_wlan/wlan/include/nic/nic_tx.h | 679 + .../drv_wlan/wlan/include/nic/que_mgt.h | 1185 ++ .../drv_wlan/wlan/include/nic/wlan_def.h | 1056 ++ .../drv_wlan/wlan/include/nic_cmd_event.h | 1824 +++ .../wlan/include/nic_init_cmd_event.h | 225 + .../drv_wlan/wlan/include/p2p_typedef.h | 310 + .../drv_wlan/wlan/include/precomp.h | 385 + .../drv_wlan/wlan/include/pwr_mgt.h | 191 + .../drv_wlan/wlan/include/queue.h | 233 + .../drv_wlan/wlan/include/rftest.h | 361 + .../drv_wlan/wlan/include/typedef.h | 281 + .../drv_wlan/wlan/include/wlan_bow.h | 591 + .../drv_wlan/wlan/include/wlan_lib.h | 987 ++ .../drv_wlan/wlan/include/wlan_oid.h | 2058 +++ .../drv_wlan/wlan/mgmt/aaa_fsm.c | 1552 +++ .../drv_wlan/wlan/mgmt/ais_fsm.c | 4582 +++++++ .../mtk_wcn_combo/drv_wlan/wlan/mgmt/assoc.c | 2087 +++ .../mtk_wcn_combo/drv_wlan/wlan/mgmt/auth.c | 1398 ++ .../mtk_wcn_combo/drv_wlan/wlan/mgmt/bss.c | 3103 +++++ .../mtk_wcn_combo/drv_wlan/wlan/mgmt/cnm.c | 814 ++ .../drv_wlan/wlan/mgmt/cnm_mem.c | 1339 ++ .../drv_wlan/wlan/mgmt/cnm_timer.c | 575 + .../drv_wlan/wlan/mgmt/hem_mbox.c | 844 ++ .../mtk_wcn_combo/drv_wlan/wlan/mgmt/mib.c | 146 + .../drv_wlan/wlan/mgmt/privacy.c | 1069 ++ .../mtk_wcn_combo/drv_wlan/wlan/mgmt/rate.c | 591 + .../mtk_wcn_combo/drv_wlan/wlan/mgmt/rlm.c | 1788 +++ .../drv_wlan/wlan/mgmt/rlm_domain.c | 713 ++ .../drv_wlan/wlan/mgmt/rlm_obss.c | 502 + .../drv_wlan/wlan/mgmt/rlm_protection.c | 152 + .../drv_wlan/wlan/mgmt/roaming_fsm.c | 625 + .../mtk_wcn_combo/drv_wlan/wlan/mgmt/rsn.c | 2653 ++++ .../drv_wlan/wlan/mgmt/saa_fsm.c | 2056 +++ .../mtk_wcn_combo/drv_wlan/wlan/mgmt/scan.c | 3002 +++++ .../drv_wlan/wlan/mgmt/scan_fsm.c | 1159 ++ .../drv_wlan/wlan/mgmt/sec_fsm.c | 1306 ++ .../mtk_wcn_combo/drv_wlan/wlan/mgmt/swcr.c | 1213 ++ .../mtk_wcn_combo/drv_wlan/wlan/mgmt/wapi.c | 568 + .../mtk_wcn_combo/drv_wlan/wlan/nic/cmd_buf.c | 262 + drivers/mtk_wcn_combo/drv_wlan/wlan/nic/nic.c | 4370 +++++++ .../drv_wlan/wlan/nic/nic_cmd_event.c | 1588 +++ .../drv_wlan/wlan/nic/nic_pwr_mgt.c | 825 ++ .../mtk_wcn_combo/drv_wlan/wlan/nic/nic_rx.c | 3568 ++++++ .../mtk_wcn_combo/drv_wlan/wlan/nic/nic_tx.c | 2020 +++ .../mtk_wcn_combo/drv_wlan/wlan/nic/que_mgt.c | 4786 +++++++ .../drv_wlan/wlan/os/linux/gl_bow.c | 1459 +++ .../drv_wlan/wlan/os/linux/gl_init.c | 2810 ++++ .../drv_wlan/wlan/os/linux/gl_kal.c | 3660 ++++++ .../drv_wlan/wlan/os/linux/gl_proc.c | 855 ++ .../drv_wlan/wlan/os/linux/gl_rst.c | 517 + .../drv_wlan/wlan/os/linux/gl_wext.c | 4548 +++++++ .../drv_wlan/wlan/os/linux/gl_wext_priv.c | 2292 ++++ .../drv_wlan/wlan/os/linux/hif/sdio/arm.c | 68 + .../wlan/os/linux/hif/sdio/include/hif.h | 269 + .../wlan/os/linux/hif/sdio/include/hif_sdio.h | 311 + .../os/linux/hif/sdio/include/mtk_porting.h | 53 + .../drv_wlan/wlan/os/linux/hif/sdio/sdio.S | 0 .../drv_wlan/wlan/os/linux/hif/sdio/sdio.c | 1281 ++ .../drv_wlan/wlan/os/linux/hif/sdio/x86.c | 68 + .../drv_wlan/wlan/os/linux/include/gl_kal.h | 1988 +++ .../drv_wlan/wlan/os/linux/include/gl_os.h | 1093 ++ .../drv_wlan/wlan/os/linux/include/gl_rst.h | 171 + .../drv_wlan/wlan/os/linux/include/gl_sec.h | 64 + .../wlan/os/linux/include/gl_typedef.h | 320 + .../drv_wlan/wlan/os/linux/include/gl_wext.h | 413 + .../wlan/os/linux/include/gl_wext_priv.h | 439 + .../drv_wlan/wlan/os/linux/platform.c | 694 + .../mtk_wcn_combo/drv_wlan/wlan/os/version.h | 197 + drivers/mtk_wcn_combo/gps/Makefile | 49 + drivers/mtk_wcn_combo/gps/gps.c | 1117 ++ include/linux/gps.h | 25 + 198 files changed, 179804 insertions(+) create mode 100755 arch/arm/mach-rk30/include/mach/mtk_wcn_cmb_stub.h create mode 100755 drivers/mtk_wcn_combo/Kconfig create mode 100755 drivers/mtk_wcn_combo/Makefile create mode 100755 drivers/mtk_wcn_combo/common/Makefile create mode 100755 drivers/mtk_wcn_combo/common/include/core_exp.h create mode 100755 drivers/mtk_wcn_combo/common/include/mtk_wcn_cmb_hw.h create mode 100755 drivers/mtk_wcn_combo/common/include/osal.h create mode 100755 drivers/mtk_wcn_combo/common/include/stp_exp.h create mode 100755 drivers/mtk_wcn_combo/common/include/wmt.h create mode 100755 drivers/mtk_wcn_combo/common/include/wmt_exp.h create mode 100755 drivers/mtk_wcn_combo/common/include/wmt_plat.h create mode 100755 drivers/mtk_wcn_combo/common/linux/hif_sdio.c create mode 100755 drivers/mtk_wcn_combo/common/linux/hw_chrdev_test.c create mode 100755 drivers/mtk_wcn_combo/common/linux/hw_sdio_client.c create mode 100755 drivers/mtk_wcn_combo/common/linux/include/hif_sdio.h create mode 100755 drivers/mtk_wcn_combo/common/linux/include/hw_test.h create mode 100755 drivers/mtk_wcn_combo/common/linux/include/mtk_wcn_cmb_stub.h create mode 100755 drivers/mtk_wcn_combo/common/linux/include/osal_linux.h create mode 100755 drivers/mtk_wcn_combo/common/linux/include/osal_typedef.h create mode 100755 drivers/mtk_wcn_combo/common/linux/include/wmt_dev.h create mode 100755 drivers/mtk_wcn_combo/common/linux/osal.c create mode 100755 drivers/mtk_wcn_combo/common/linux/stp_chrdev_bt.c create mode 100755 drivers/mtk_wcn_combo/common/linux/stp_chrdev_gps.c create mode 100755 drivers/mtk_wcn_combo/common/linux/stp_exp.c create mode 100755 drivers/mtk_wcn_combo/common/linux/stp_uart.c create mode 100755 drivers/mtk_wcn_combo/common/linux/wmt_chrdev_wifi.c create mode 100755 drivers/mtk_wcn_combo/common/linux/wmt_dev.c create mode 100755 drivers/mtk_wcn_combo/common/linux/wmt_exp.c create mode 100755 drivers/mtk_wcn_combo/common/platform/rockchip/mtk_wcn_cmb_hw_6620.c create mode 100755 drivers/mtk_wcn_combo/common/platform/rockchip/mtk_wcn_cmb_stub_rockchip.c create mode 100755 drivers/mtk_wcn_combo/common/platform/rockchip/wmt_plat_rockchip.c create mode 100755 drivers/mtk_wcn_combo/drv_bt/Makefile create mode 100755 drivers/mtk_wcn_combo/drv_bt/include/hci_stp.h create mode 100755 drivers/mtk_wcn_combo/drv_bt/linux/hci_stp.c create mode 100755 drivers/mtk_wcn_combo/drv_fm/Makefile create mode 100755 drivers/mtk_wcn_combo/drv_fm/include/fm.h create mode 100755 drivers/mtk_wcn_combo/drv_fm/private/Makefile create mode 100755 drivers/mtk_wcn_combo/drv_fm/private/mtk_fm.h create mode 100755 drivers/mtk_wcn_combo/drv_fm/public/Makefile create mode 100755 drivers/mtk_wcn_combo/drv_fm/public/mt6620_fm.c create mode 100755 drivers/mtk_wcn_combo/drv_fm/public/mt6620_fm.h create mode 100755 drivers/mtk_wcn_combo/drv_fm/public/mt6620_fm_lib.c create mode 100755 drivers/mtk_wcn_combo/drv_fm/public/mt6620_fm_lib.h create mode 100755 drivers/mtk_wcn_combo/drv_fm/public/mt6620_fm_reg.h create mode 100755 drivers/mtk_wcn_combo/drv_fm/public/mt6620_rds.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/Makefile create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/Makefile create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/common/wlan_p2p.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_assoc.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_bss.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_fsm.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_func.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_ie.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_rlm.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_rlm_obss.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_scan.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_state.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/include/nic/p2p.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/include/nic/p2p_cmd_buf.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/include/nic/p2p_mac.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/include/nic/p2p_nic.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/include/nic/p2p_nic_cmd_event.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/include/p2p_precomp.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/include/wlan_p2p.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_assoc.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_bss.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_fsm.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_func.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_ie.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_rlm.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_rlm_obss.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_scan.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_state.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/nic/p2p_nic.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/gl_p2p.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/gl_p2p_cfg80211.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/gl_p2p_init.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/gl_p2p_kal.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/include/gl_p2p_ioctl.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/include/gl_p2p_kal.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/include/gl_p2p_os.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/Makefile create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/common/dump.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/common/wlan_bow.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/common/wlan_lib.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/common/wlan_oid.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/CFG_Wifi_File.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/config.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/debug.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/link.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/aa_fsm.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/ais_fsm.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/assoc.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/auth.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/bow_fsm.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/bss.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/cnm.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/cnm_mem.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/cnm_scan.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/cnm_timer.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/hem_mbox.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/mib.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/privacy.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/rate.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/rlm.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/rlm_domain.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/rlm_obss.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/rlm_protection.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/roaming_fsm.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/rsn.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/scan.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/sec_fsm.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/swcr.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/wapi.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/wlan_typedef.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/adapter.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/bow.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/cmd_buf.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/hal.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/hif_emu.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/hif_rx.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/hif_tx.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/mac.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/mt5931_reg.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/mt6620_reg.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/nic.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/nic_rx.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/nic_tx.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/que_mgt.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/wlan_def.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic_cmd_event.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic_init_cmd_event.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/p2p_typedef.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/precomp.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/pwr_mgt.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/queue.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/rftest.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/typedef.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/wlan_bow.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/wlan_lib.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/include/wlan_oid.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/aaa_fsm.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/ais_fsm.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/assoc.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/auth.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/bss.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/cnm.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/cnm_mem.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/cnm_timer.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/hem_mbox.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/mib.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/privacy.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/rate.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/rlm.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/rlm_domain.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/rlm_obss.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/rlm_protection.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/roaming_fsm.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/rsn.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/saa_fsm.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/scan.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/scan_fsm.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/sec_fsm.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/swcr.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/wapi.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/nic/cmd_buf.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/nic/nic.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/nic/nic_cmd_event.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/nic/nic_pwr_mgt.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/nic/nic_rx.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/nic/nic_tx.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/nic/que_mgt.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_bow.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_init.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_kal.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_proc.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_rst.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_wext.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_wext_priv.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/arm.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/include/hif.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/include/hif_sdio.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/include/mtk_porting.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/sdio.S create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/sdio.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/x86.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_kal.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_os.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_rst.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_sec.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_typedef.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_wext.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_wext_priv.h create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/platform.c create mode 100755 drivers/mtk_wcn_combo/drv_wlan/wlan/os/version.h create mode 100755 drivers/mtk_wcn_combo/gps/Makefile create mode 100755 drivers/mtk_wcn_combo/gps/gps.c create mode 100755 include/linux/gps.h diff --git a/arch/arm/mach-rk30/include/mach/mtk_wcn_cmb_stub.h b/arch/arm/mach-rk30/include/mach/mtk_wcn_cmb_stub.h new file mode 100755 index 000000000000..18682c0d69ec --- /dev/null +++ b/arch/arm/mach-rk30/include/mach/mtk_wcn_cmb_stub.h @@ -0,0 +1,213 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +#ifndef _MTK_WCN_CMB_STUB_H_ +#define _MTK_WCN_CMB_STUB_H_ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum { + CMB_STUB_AIF_0 = 0, /* 0000: BT_PCM_OFF & FM analog (line in/out) */ + CMB_STUB_AIF_1 = 1, /* 0001: BT_PCM_ON & FM analog (in/out) */ + CMB_STUB_AIF_2 = 2, /* 0010: BT_PCM_OFF & FM digital (I2S) */ + CMB_STUB_AIF_3 = 3, /* 0011: BT_PCM_ON & FM digital (I2S) (invalid in 73evb & 1.2 phone configuration) */ + CMB_STUB_AIF_MAX = 4, +} CMB_STUB_AIF_X; + +/*COMBO_CHIP_AUDIO_PIN_CTRL*/ +typedef enum { + CMB_STUB_AIF_CTRL_DIS = 0, + CMB_STUB_AIF_CTRL_EN = 1, + CMB_STUB_AIF_CTRL_MAX = 2, +} CMB_STUB_AIF_CTRL; + +#if 1 /* copied from mt_combo.h */ +typedef enum { + COMBO_AUDIO_STATE_0 = 0, /* 0000: BT_PCM_OFF & FM analog (line in/out) */ + COMBO_AUDIO_STATE_1 = 1, /* 0001: BT_PCM_ON & FM analog (in/out) */ + COMBO_AUDIO_STATE_2 = 2, /* 0010: BT_PCM_OFF & FM digital (I2S) */ + COMBO_AUDIO_STATE_3 = 3, /* 0011: BT_PCM_ON & FM digital (I2S) (invalid in 73evb & 1.2 phone configuration) */ + COMBO_AUDIO_STATE_MAX = 4, +} COMBO_AUDIO_STATE; + +typedef enum { + COMBO_FUNC_TYPE_BT = 0, + COMBO_FUNC_TYPE_FM = 1, + COMBO_FUNC_TYPE_GPS = 2, + COMBO_FUNC_TYPE_WIFI = 3, + COMBO_FUNC_TYPE_WMT = 4, + COMBO_FUNC_TYPE_STP = 5, + COMBO_FUNC_TYPE_NUM = 6 +} COMBO_FUNC_TYPE; + +typedef enum { + COMBO_IF_UART = 0, + COMBO_IF_MSDC = 1, + COMBO_IF_MAX, +} COMBO_IF; +#endif + +typedef void (*wmt_bgf_eirq_cb)(void); +typedef int (*wmt_aif_ctrl_cb)(CMB_STUB_AIF_X, CMB_STUB_AIF_CTRL); +typedef void (*wmt_func_ctrl_cb)(unsigned int, unsigned int); + +typedef struct _CMB_STUB_CB_ { + unsigned int size; //structure size + /*wmt_bgf_eirq_cb bgf_eirq_cb;*//* remove bgf_eirq_cb from stub. handle it in platform */ + wmt_aif_ctrl_cb aif_ctrl_cb; + wmt_func_ctrl_cb func_ctrl_cb; +} CMB_STUB_CB, *P_CMB_STUB_CB; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +extern int mtk_wcn_cmb_stub_reg (P_CMB_STUB_CB p_stub_cb); +extern int mtk_wcn_cmb_stub_unreg (void); + +extern int mtk_wcn_cmb_stub_aif_ctrl (CMB_STUB_AIF_X state, CMB_STUB_AIF_CTRL ctrl); + +#if 0 /* remove obsolete audio_ctrl APIs. Use stub_aif_ctrl()! */ +/* [GeorgeKuo] Stub functions for other kernel built-in modules to call. + * Keep them unchanged temporarily. Move mt_combo functions to mtk_wcn_combo. + */ +extern int mtk_wcn_cmb_stub_audio_ctrl_ex(COMBO_AUDIO_STATE state, u32 clt_ctrl); +static inline int mtk_wcn_cmb_stub_audio_ctrl(COMBO_AUDIO_STATE state) { + return mtk_wcn_cmb_stub_audio_ctrl_ex(state, 1); +} +#endif + +/* Use new mtk_wcn_stub APIs instead of old mt_combo ones for kernel to control + * function on/off. + */ +extern void mtk_wcn_cmb_stub_func_ctrl (unsigned int type, unsigned int on); + +extern int mt_combo_plt_enter_deep_idle(COMBO_IF src); +extern int mt_combo_plt_exit_deep_idle(COMBO_IF src); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _MTK_WCN_CMB_STUB_H_ */ + diff --git a/drivers/mtk_wcn_combo/Kconfig b/drivers/mtk_wcn_combo/Kconfig new file mode 100755 index 000000000000..c63cd2ce6687 --- /dev/null +++ b/drivers/mtk_wcn_combo/Kconfig @@ -0,0 +1,141 @@ +menu "MediaTek Connectivity Combo Chip Config" + +config MTK_COMBO + bool "MediaTek Connectivity Combo Chip Support" + help + MTK connectivity combo chip driver for MT6620 + +# +# MTK Combo Chip Selection +# +choice + prompt "Select Chip" + depends on MTK_COMBO + +config MTK_COMBO_CHIP_MT6620 + bool "MT6620" + +#config MTK_COMBO_CHIP_MT6628 +# bool "MT6628" +endchoice + +# +# Target Platform Selection +# +config MTK_COMBO_PLAT_PATH + string "Platform folder name" + depends on MTK_COMBO + default "sample" if MTK_COMBO_PLAT_SAMPLE + help + Specify platform folder under common driver platform folder: + mtk_wcn_combo/common/platform/* + +# +# MTK COMBO Chip Configuration +# +config MTK_COMBO_COMM + depends on MTK_COMBO + tristate "MediaTek Combo Chip Common part driver" + help + MediaTek combo chip common part driver + +#config MTK_COMBO_COMM_PS +# depends on MTK_COMBO_COMM +# bool "Enable PS support" +# default n +# help +# Enable PS support of common UART interface + +config MTK_COMBO_COMM_UART + depends on MTK_COMBO_COMM + tristate "Common interface UART" + help + Use UART for common part interface type + +#config MTK_COMBO_COMM_SDIO +# depends on MTK_COMBO_COMM +# tristate "Common interface SDIO" +# help +# Use SDIO for common part interface type + +config MTK_COMBO_BT_HW_TEST + tristate "MediaTek Combo Chip BT Hardware Test driver" + depends on MTK_COMBO + help + MTK BT /dev/stpbt driver for autobt hardware test tool (mtk_stp_bt.ko) + +config MTK_COMBO_BT_HCI + tristate "MediaTek Combo Chip BlueZ driver" + depends on BT && MTK_COMBO + help + MTK BT driver for BlueZ (hci_stp.ko) + +config MTK_COMBO_FM + tristate "MediaTek Combo Chip FM driver" + depends on MTK_COMBO + help + MTK FM /dev/fm driver (mt6620_fm_drv.ko, mtk_fm_priv.ko) + +config MTK_COMBO_WIFI + tristate "MediaTek Combo Chip Wi-Fi support" + depends on MTK_COMBO + depends on MMC + depends on IPV6 + select WIRELESS_EXT + select WEXT_PRIV + help + This module adds support for wireless adapters based on + MTK MT6620 chipset. + + This driver uses the kernel's wireless extensions subsystem. + + If you choose to build a module, it'll be called dhd. Say M if + unsure. + +#config MTK_COMBO_WIFI_FW_PATH +# depends on MTK_COMBO_WIFI +# string "Firmware path" +# default "/system/etc/firmware/WIFI_RAM_CODE" +# help +# Path to the firmware file + +config MTK_COMBO_WIFI_DEBUG + depends on MTK_COMBO_WIFI + bool "Enable debug output from MT6620 driver" + help + Enable debug messages output from MT6620 driver + +config MTK_COMBO_WIFI_PROC + depends on MTK_COMBO_WIFI + bool "Enable procfs support" + help + Enable procfs support. + +#config MTK_WAPI_SUPPORT +# depends on MTK_COMBO_WIFI +# bool "Enable WAPI support in MT6620 driver" +# help +# Enable WAPI support for devices using MT6620 + +choice + prompt "Host Interface" + depends on MTK_COMBO_WIFI + +config MTK_COMBO_WIFI_HIF_SDIO1 + bool "SDIO #1" + depends on MTK_COMBO_WIFI +endchoice + + +config MTK_GPS + tristate "MediaTek GPS Support" + help + MTK GPS /dev/gps driver (mtk_gps.ko) + +config MTK_COMBO_GPS + tristate "MediaTek Combo Chip GPS driver" + depends on MTK_COMBO && MTK_GPS + help + MTK GPS /dev/stpgps driver (mtk_stp_gps.ko) + +endmenu diff --git a/drivers/mtk_wcn_combo/Makefile b/drivers/mtk_wcn_combo/Makefile new file mode 100755 index 000000000000..7d1689039149 --- /dev/null +++ b/drivers/mtk_wcn_combo/Makefile @@ -0,0 +1,60 @@ +# Copyright Statement: +# +# This software/firmware and related documentation ("MediaTek Software") are +# protected under relevant copyright laws. The information contained herein +# is confidential and proprietary to MediaTek Inc. and/or its licensors. +# Without the prior written permission of MediaTek inc. and/or its licensors, +# any reproduction, modification, use or disclosure of MediaTek Software, +# and information contained herein, in whole or in part, shall be strictly prohibited. +# +# MediaTek Inc. (C) 2010. All rights reserved. +# +# BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES +# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") +# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON +# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. +# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE +# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR +# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH +# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES +# THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES +# CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK +# SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR +# STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND +# CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, +# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, +# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO +# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +# +# The following software/firmware and/or related documentation ("MediaTek Software") +# have been modified by MediaTek Inc. All revisions are subject to any receiver's +# applicable license agreements with MediaTek Inc. + + +# combo driver: MT6620 +# If KERNELRELEASE is defined, we've been invoked from the +# kernel build system and can use its language. +ifneq ($(KERNELRELEASE),) + #subdir-ccflags-y can be used in 2.6.34 in the future + #subdir-ccflags-y += -I$(src)/common/include -I$(src)/common/linux/include + #used for binary release script + #KERNEL_PATH := $(pwd) + #OBJ_PATH := $(pwd) + obj-$(CONFIG_MTK_COMBO) += common/ + obj-$(CONFIG_MTK_COMBO_FM) += drv_fm/ + obj-$(CONFIG_MTK_COMBO_WIFI) += drv_wlan/ + + #Use BT HCI driver + obj-$(CONFIG_MTK_COMBO_BT_HCI) += drv_bt/ + obj-$(CONFIG_MTK_GPS) += gps/ + +# Otherwise we were called directly from the command +# line; invoke the kernel build system. +else + KERNELDIR ?= /lib/modules/$(shell uname -r)/build + PWD := $(shell pwd) +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules +endif diff --git a/drivers/mtk_wcn_combo/common/Makefile b/drivers/mtk_wcn_combo/common/Makefile new file mode 100755 index 000000000000..32608e8a605c --- /dev/null +++ b/drivers/mtk_wcn_combo/common/Makefile @@ -0,0 +1,92 @@ +# Copyright Statement: +# +# This software/firmware and related documentation ("MediaTek Software") are +# protected under relevant copyright laws. The information contained herein +# is confidential and proprietary to MediaTek Inc. and/or its licensors. +# Without the prior written permission of MediaTek inc. and/or its licensors, +# any reproduction, modification, use or disclosure of MediaTek Software, +# and information contained herein, in whole or in part, shall be strictly prohibited. +# +# MediaTek Inc. (C) 2010. All rights reserved. +# +# BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES +# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") +# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON +# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. +# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE +# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR +# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH +# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES +# THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES +# CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK +# SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR +# STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND +# CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, +# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, +# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO +# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +# +# The following software/firmware and/or related documentation ("MediaTek Software") +# have been modified by MediaTek Inc. All revisions are subject to any receiver's +# applicable license agreements with MediaTek Inc. + +#always := $(shell tar -zxf $(src)/core.tar.gz -C $(src)) +always := $(shell if [ -f $(src)/core.tar.gz ]; then tar -zxf $(src)/core.tar.gz -C $(src); fi) +#always := $(shell tar -zxf $(src)/linux/pri.tar.gz -C $(src)/linux) +#always := $(shell if [ -f $(src)/linux/pri.tar.gz ]; then tar -zxf $(src)/linux/pri.tar.gz -C $(src)/linux; fi) + +ccflags-y += -I$(src)/include -I$(src)/linux/include -I$(src)/core/include + +# WMT DRIVER +obj-$(CONFIG_MTK_COMBO_COMM) += mtk_stp_wmt.o +# WMT DRIVER-core part +mtk_stp_wmt-y := core/wmt_core.o core/wmt_ctrl.o core/wmt_conf.o +mtk_stp_wmt-y += core/wmt_dbg.o core/wmt_func.o core/wmt_lib.o +mtk_stp_wmt-y += core/btm_core.o +mtk_stp_wmt-y += core/psm_core.o # to be removed +mtk_stp_wmt-y += core/stp_core.o core/stp_dbg.o +mtk_stp_wmt-$(CONFIG_MTK_COMBO_CHIP_MT6620) += core/wmt_ic_6620.o +#mtk_stp_wmt-$(CONFIG_MTK_COMBO_CHIP_MT6628) += core/wmt_ic_6628.o + +# WMT DRIVER-linux part +mtk_stp_wmt-y += linux/wmt_dev.o linux/wmt_exp.o linux/stp_exp.o +# WMT DRIVER-OSAL +mtk_stp_wmt-y += linux/osal.o + +# WMT DRIVER-platform part, specified by string CONFIG_MTK_COMBO_PLAT_PATH +PLAT := $(shell echo $(CONFIG_MTK_COMBO_PLAT_PATH)) +mtk_stp_wmt-y += platform/$(PLAT)/wmt_plat_$(PLAT).o +# WMT DRIVER-platform chip part. Select desired hw according to project configuration +mtk_stp_wmt-$(CONFIG_MTK_COMBO_CHIP_MT6620) += platform/$(PLAT)/mtk_wcn_cmb_hw_6620.o +mtk_stp_wmt-$(CONFIG_MTK_COMBO_CHIP_MT6628) += platform/$(PLAT)/mtk_wcn_cmb_hw_6628.o + +# WMT stub part (built-in kernel image) +obj-y += platform/$(PLAT)/mtk_wcn_cmb_stub_$(PLAT).o + +# HIF-SDIO DRIVER +obj-$(CONFIG_MTK_COMBO_COMM) += mtk_hif_sdio.o +mtk_hif_sdio-y := linux/hif_sdio.o + +# STP-UART DRIVER +obj-$(CONFIG_MTK_COMBO_COMM_UART) += mtk_stp_uart.o +mtk_stp_uart-y := linux/stp_uart.o + +# STP-SDIO DRIVER +#obj-$(CONFIG_MTK_COMBO_COMM_SDIO) += mtk_stp_sdio.o +#mtk_stp_sdio-y := linux/pri/stp_sdio.o + +# MTK BT HW TEST DRIVER +obj-$(CONFIG_MTK_COMBO_BT_HW_TEST) += mtk_stp_bt.o +mtk_stp_bt-y := linux/stp_chrdev_bt.o + +# STP-GPS DIVER +obj-$(CONFIG_MTK_COMBO_GPS) += mtk_stp_gps.o +mtk_stp_gps-y := linux/stp_chrdev_gps.o + +# WMT-WIFI DIVER +obj-$(CONFIG_MTK_COMBO_WIFI) += mtk_wmt_wifi.o +mtk_wmt_wifi-y := linux/wmt_chrdev_wifi.o + + diff --git a/drivers/mtk_wcn_combo/common/include/core_exp.h b/drivers/mtk_wcn_combo/common/include/core_exp.h new file mode 100755 index 000000000000..1b6c711e5d46 --- /dev/null +++ b/drivers/mtk_wcn_combo/common/include/core_exp.h @@ -0,0 +1,253 @@ + +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +#ifndef _CORE_EXP_H_ +#define _CORE_EXP_H_ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +#define CFG_WMT_DBG_SUPPORT (1) + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "osal.h" +#include "wmt_exp.h" + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define MAX_WIFI_ON_TIME (5500) // in ms? +#define WMT_LIB_RX_TIMEOUT (2000) // in ms? + +#define WMT_PWRON_RTY_DFT (2) +#define MAX_RETRY_TIME_DUE_TO_RX_TIMEOUT (WMT_PWRON_RTY_DFT * WMT_LIB_RX_TIMEOUT) +#define MAX_EACH_FUNC_ON_WHEN_CHIP_POWER_ON_ALREADY (WMT_LIB_RX_TIMEOUT) /*each WMT command*/ +#define MAX_FUNC_ON_TIME (MAX_WIFI_ON_TIME + MAX_RETRY_TIME_DUE_TO_RX_TIMEOUT + MAX_EACH_FUNC_ON_WHEN_CHIP_POWER_ON_ALREADY * 3) + +#define MAX_EACH_FUNC_OFF (WMT_LIB_RX_TIMEOUT + 1000) /*1000->WMT_LIB_RX_TIMEOUT + 1000, logical judgement*/ +#define MAX_FUNC_OFF_TIME (MAX_EACH_FUNC_OFF * 4) + +#define MAX_EACH_WMT_CMD (WMT_LIB_RX_TIMEOUT + 1000) + +#define OP_FUNCTION_ACTIVE (0) + + +#define STATUS_OP_INVALID (0) +#define STATUS_FUNCTION_INVALID (1) + +#define STATUS_FUNCTION_ACTIVE (31) +#define STATUS_FUNCTION_INACTIVE (32) + +#define defaultPatchName "mt66xx_patch_hdr.bin" +#define BCNT_PATCH_BUF_HEADROOM (8) +#define DWCNT_HIF_CONF (4) +#define DWCNT_STRAP_CONF (4) +#define DWCNT_RESERVED (8) +#define DWCNT_CTRL_DATA (16) + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_WMT_OPID_T { + WMT_OPID_HIF_CONF = 0, + WMT_OPID_PWR_ON = 1, + WMT_OPID_PWR_OFF = 2, + WMT_OPID_FUNC_ON = 3, + WMT_OPID_FUNC_OFF = 4, + WMT_OPID_REG_RW = 5, // TODO:[ChangeFeature][George] is this OP obsoleted? + WMT_OPID_EXIT = 6, + WMT_OPID_PWR_SV = 7, + WMT_OPID_DSNS = 8, + WMT_OPID_LPBK = 9, + WMT_OPID_CMD_TEST = 10, + WMT_OPID_HW_RST = 11, + WMT_OPID_SW_RST = 12, + WMT_OPID_BAUD_RST = 13, + WMT_OPID_STP_RST = 14, + WMT_OPID_THERM_CTRL = 15, + WMT_OPID_EFUSE_RW = 16, + WMT_OPID_GPIO_CTRL = 17, + WMT_OPID_SDIO_CTRL = 18, + WMT_OPID_MAX +} ENUM_WMT_OPID_T, *P_ENUM_WMT_OPID_T; + +typedef enum _ENUM_WMT_UART_FC_T +{ + WMT_UART_NO_FC = 0, + WMT_UART_MTK_SW_FC = 1, + WMT_UART_LUX_SW_FC = 2, + WMT_UART_HW_FC = 3, + WMT_UART_MAX +} ENUM_WMT_UART_FC_T, *P_ENUM_UART_FC_T; + + +typedef OSAL_OP_DAT WMT_OP; +typedef P_OSAL_OP_DAT P_WMT_OP; + + +typedef INT32 (*IF_TX)(const UINT8 *data, const UINT32 size, UINT32 *written_size); +/* event/signal */ +typedef INT32 (*EVENT_SET)(UINT8 function_type); +typedef INT32 (*EVENT_TX_RESUME)(UINT8 winspace); +typedef INT32 (*FUNCTION_STATUS)(UINT8 type, UINT8 op); + + +typedef struct +{ + /* common interface */ + IF_TX cb_if_tx; + /* event/signal */ + EVENT_SET cb_event_set; + EVENT_TX_RESUME cb_event_tx_resume; + FUNCTION_STATUS cb_check_funciton_status; +}mtkstp_callback; + +typedef struct _WMT_HIF_CONF { + UINT32 hifType; // HIF Type + UINT32 uartFcCtrl; // UART FC config + UINT32 au4HifConf[DWCNT_HIF_CONF]; // HIF Config + UINT32 au4StrapConf[DWCNT_STRAP_CONF]; // Strap Config +} WMT_HIF_CONF, *P_WMT_HIF_CONF; + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +extern INT32 wmt_lib_init(VOID); +extern INT32 wmt_lib_deinit(VOID); +extern P_OSAL_OP wmt_lib_get_free_op (VOID); +extern MTK_WCN_BOOL wmt_lib_put_act_op (P_OSAL_OP pOp); +extern INT32 wmt_lib_host_awake_get(VOID); +extern INT32 wmt_lib_host_awake_put(VOID); +extern VOID wmt_lib_disable_psm_monitor(VOID); +extern VOID wmt_lib_enable_psm_monitor(VOID); +extern MTK_WCN_BOOL wmt_lib_is_therm_ctrl_support (VOID); +extern MTK_WCN_BOOL wmt_lib_is_dsns_ctrl_support (VOID); +extern INT32 wmt_lib_msgcb_reg (ENUM_WMTDRV_TYPE_T eType,PF_WMT_CB pCb); + +extern INT32 wmt_lib_msgcb_unreg (ENUM_WMTDRV_TYPE_T eType); + +extern VOID wmt_lib_ps_set_sdio_psop (PF_WMT_SDIO_PSOP own_cb); +extern ENUM_WMTHWVER_TYPE_T wmt_lib_get_hwver (VOID); +extern VOID wmt_lib_flush_rx(VOID); +extern INT32 wmt_lib_trigger_cmd_signal (INT32 result); +extern UCHAR *wmt_lib_get_cmd(VOID); +extern P_OSAL_EVENT wmt_lib_get_cmd_event(VOID); +extern MTK_WCN_BOOL wmt_lib_get_cmd_status(VOID); +extern INT32 wmt_lib_set_patch_name(UCHAR *cPatchName); + +extern INT32 wmt_lib_set_hif(ULONG hifconf); +extern P_WMT_HIF_CONF wmt_lib_get_hif(VOID); + + +extern INT32 stp_drv_init(VOID); +extern VOID stp_drv_exit(VOID); +extern INT32 mtk_wcn_stp_init(const mtkstp_callback * const cb_func); +extern INT32 mtk_wcn_stp_deinit(VOID); +extern VOID mtk_wcn_stp_flush_rx_queue(UINT32 type); +extern INT32 mtk_wcn_stp_send_data_raw(const UINT8 *buffer, const UINT32 length, const UINT8 type); + + +extern INT32 wmt_dbg_proc_read(CHAR *page, CHAR **start, LONG off, INT32 count, INT32 *eof, VOID *data); +extern INT32 wmt_dbg_proc_write(CHAR *buffer); + + +#endif + diff --git a/drivers/mtk_wcn_combo/common/include/mtk_wcn_cmb_hw.h b/drivers/mtk_wcn_combo/common/include/mtk_wcn_cmb_hw.h new file mode 100755 index 000000000000..4b6aadd3b5f7 --- /dev/null +++ b/drivers/mtk_wcn_combo/common/include/mtk_wcn_cmb_hw.h @@ -0,0 +1,165 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +#ifndef _MTK_WCN_CMB_HW_H_ +#define _MTK_WCN_CMB_HW_H_ + +#include "osal_typedef.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef struct _PWR_SEQ_TIME_ +{ + UINT32 rtcStableTime; + UINT32 ldoStableTime; + UINT32 rstStableTime; + UINT32 offStableTime; + UINT32 onStableTime; +}PWR_SEQ_TIME, *P_PWR_SEQ_TIME; + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + + + + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +extern INT32 mtk_wcn_cmb_hw_pwr_off (VOID); +extern INT32 mtk_wcn_cmb_hw_pwr_on (VOID); +extern INT32 mtk_wcn_cmb_hw_rst (VOID); +extern INT32 mtk_wcn_cmb_hw_init (P_PWR_SEQ_TIME pPwrSeqTime); +extern INT32 mtk_wcn_cmb_hw_deinit (VOID); + + +#endif /* _MTK_WCN_CMB_HW_H_ */ + diff --git a/drivers/mtk_wcn_combo/common/include/osal.h b/drivers/mtk_wcn_combo/common/include/osal.h new file mode 100755 index 000000000000..9913ecea7ed6 --- /dev/null +++ b/drivers/mtk_wcn_combo/common/include/osal.h @@ -0,0 +1,429 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +#ifndef _OSAL_H_ +#define _OSAL_H_ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +#define OS_BIT_OPS_SUPPORT (1) + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "osal_typedef.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define MAX_THREAD_NAME_LEN (16) +#define MAX_WAKE_LOCK_NAME_LEN (16) +#define OSAL_OP_BUF_SIZE (64) +#define OSAL_OP_DATA_SIZE (32) +#define DBG_LOG_STR_SIZE (512) + +#define OSAL_NAME_MAX (256) + + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +#define osal_sizeof(x) sizeof(x) +#define osal_array_size(x) sizeof(x)/sizeof(x[0]) + + +#define WMT_OP_BIT(x) (0x1UL << x) +#define WMT_OP_HIF_BIT WMT_OP_BIT(0) + + +#define RB_SIZE(prb) ((prb)->size) +#define RB_MASK(prb) (RB_SIZE(prb) - 1) +#define RB_COUNT(prb) ((prb)->write - (prb)->read) +#define RB_FULL(prb) (RB_COUNT(prb) >= RB_SIZE(prb)) +#define RB_EMPTY(prb) ((prb)->write == (prb)->read) + +#define RB_INIT(prb, qsize) \ + { \ + (prb)->read = (prb)->write = 0; \ + (prb)->size = (qsize); \ + } + +#define RB_PUT(prb, value) \ +{ \ + if (!RB_FULL( prb )) { \ + (prb)->queue[ (prb)->write & RB_MASK(prb) ] = value; \ + ++((prb)->write); \ + } \ + else { \ + osal_assert(!RB_FULL(prb)); \ + } \ +} + +#define RB_GET(prb, value) \ +{ \ + if (!RB_EMPTY(prb)) { \ + value = (prb)->queue[ (prb)->read & RB_MASK(prb) ]; \ + ++((prb)->read); \ + if (RB_EMPTY(prb)) { \ + (prb)->read = (prb)->write = 0; \ + } \ + } \ + else { \ + value = NULL; \ + osal_assert(!RB_EMPTY(prb)); \ + } \ +} + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef VOID (*P_TIMEOUT_HANDLER)(ULONG); +typedef INT32 (*P_COND)(VOID *); + +typedef struct _OSAL_TIMER_ +{ + TIMER_REF pTimer; + P_TIMEOUT_HANDLER timeoutHandler; + ULONG timeroutHandlerData; +}OSAL_TIMER, *P_OSAL_TIMER; + +typedef struct _OSAL_UNSLEEPABLE_LOCK_ +{ + SPINLOCK_REF pLock; + ULONG flag; +}OSAL_UNSLEEPABLE_LOCK, *P_OSAL_UNSLEEPABLE_LOCK; + +typedef struct _OSAL_SLEEPABLE_LOCK_ +{ + MUTEX_REF pLock; +}OSAL_SLEEPABLE_LOCK, *P_OSAL_SLEEPABLE_LOCK; + + +typedef struct _OSAL_SIGNAL_ +{ + COMPLETION_REF pComp; + UINT32 timeoutValue; +}OSAL_SIGNAL, *P_OSAL_SIGNAL; + + +typedef struct _OSAL_EVENT_ +{ + WAITQUEUE_REF pWaitQueue; + UINT32 timeoutValue; + INT32 waitFlag; + +}OSAL_EVENT, *P_OSAL_EVENT; + +typedef struct _OSAL_THREAD_ +{ + THREAD_REF pThread; + VOID *pThreadFunc; + VOID *pThreadData; + char threadName[MAX_THREAD_NAME_LEN]; +}OSAL_THREAD, *P_OSAL_THREAD; + +typedef struct _OSAL_FIFO_ +{ + /*fifo definition*/ + VOID *pFifoBody; + SPINLOCK_REF fifoSpinlock; + /*fifo operations*/ + INT32 (*FifoInit)(struct _OSAL_FIFO_ *pFifo, UINT8 *buf, UINT32); + INT32 (*FifoDeInit)(struct _OSAL_FIFO_ *pFifo); + INT32 (*FifoReset)(struct _OSAL_FIFO_ *pFifo); + INT32 (*FifoSz)(struct _OSAL_FIFO_ *pFifo); + INT32 (*FifoAvailSz)(struct _OSAL_FIFO_ *pFifo); + INT32 (*FifoLen)(struct _OSAL_FIFO_ *pFifo); + INT32 (*FifoIsEmpty)(struct _OSAL_FIFO_ *pFifo); + INT32 (*FifoIsFull)(struct _OSAL_FIFO_ *pFifo); + INT32 (*FifoDataIn)(struct _OSAL_FIFO_ *pFifo, const VOID *buf, UINT32 len); + INT32 (*FifoDataOut)(struct _OSAL_FIFO_ *pFifo, VOID *buf, UINT32 len); +} OSAL_FIFO, *P_OSAL_FIFO; + +typedef struct _OSAL_FIRMWARE_ +{ + UINT32 size; + const UINT8 *data; +}OSAL_FIRMWARE,*P_OSAL_FIRMWARE; + +typedef struct _OSAL_OP_DAT { + UINT32 opId; // Event ID + UINT32 u4InfoBit; // Reserved + UINT32 au4OpData[OSAL_OP_DATA_SIZE]; // OP Data +} OSAL_OP_DAT, *P_OSAL_OP_DAT; + +typedef struct _OSAL_LXOP_ { + OSAL_OP_DAT op; + OSAL_SIGNAL signal; + INT32 result; +} OSAL_OP, *P_OSAL_OP; + +typedef struct _OSAL_LXOP_Q { + OSAL_SLEEPABLE_LOCK sLock; + UINT32 write; + UINT32 read; + UINT32 size; + P_OSAL_OP queue[OSAL_OP_BUF_SIZE]; +} OSAL_OP_Q, *P_OSAL_OP_Q; + +typedef struct _OSAL_WAKE_LOCK_ +{ + WAKELOCK_REF pWakeLock; + UINT8 name[MAX_WAKE_LOCK_NAME_LEN]; +} OSAL_WAKE_LOCK, *P_OSAL_WAKE_LOCK; + +typedef enum{ + OSAL_RETURN_OK = 0, + OSAL_RETIRN_BAD_ADDRESS = -14, +}OSAL_RETURN_ERR; + +typedef struct _OSAL_BIT_OP_VAR_ +{ + ULONG data; + OSAL_UNSLEEPABLE_LOCK opLock; +}OSAL_BIT_OP_VAR, *P_OSAL_BIT_OP_VAR; + +typedef UINT32 (*P_OSAL_EVENT_CHECKER)(P_OSAL_THREAD pThread); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + + + + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +extern UINT32 osal_strlen(const char *str); +extern INT32 osal_strcmp(const char *dst, const char *src); +extern INT32 osal_strncmp(const char *dst, const char *src, UINT32 len); +extern char * osal_strcpy(char *dst, const char *src); +extern char * osal_strncpy(char *dst, const char *src, UINT32 len); +extern char * osal_strcat(char *dst, const char *src); +extern char * osal_strncat(char *dst, const char *src, UINT32 len); +extern char * osal_strchr(const char *str, UINT8 c); +extern char * osal_strsep(char **str, const char *c); +extern LONG osal_strtol(const char *str, char **c, UINT32 adecimal); +extern INT32 osal_snprintf(char *buf, UINT32 len, const char*fmt, ...); + +extern INT32 osal_print(const char *str, ...); +extern INT32 osal_dbg_print(const char *str, ...); +extern INT32 osal_err_print(const char *str, ...); +extern INT32 osal_info_print(const char *str, ...); +extern INT32 osal_warn_print(const char *str, ...); +extern INT32 osal_loud_print(const char *str, ...); + + +extern INT32 osal_dbg_assert(INT32 expr, const char *file, INT32 line); +extern INT32 osal_sprintf(char *str, const char *format, ...); +extern VOID* osal_malloc(UINT32 size); +extern VOID osal_vfree(const VOID *dst); +extern VOID osal_kfree(const VOID *dst); +extern VOID* osal_memset(VOID *buf, INT32 i, UINT32 len); +extern VOID* osal_memcpy(VOID *dst, const VOID *src, UINT32 len); +extern INT32 osal_memcmp(const VOID *buf1, const VOID *buf2, UINT32 len); +extern VOID * osal_kzalloc_sleep(UINT32 size); +extern VOID* osal_kzalloc_unsleep(UINT32 size); + +extern INT32 osal_msleep(UINT32 ms); + +extern INT32 osal_timer_create(P_OSAL_TIMER); +extern INT32 osal_timer_start(P_OSAL_TIMER, UINT32); +extern INT32 osal_timer_stop(P_OSAL_TIMER); +extern INT32 osal_timer_stop_sync(P_OSAL_TIMER pTimer); +extern INT32 osal_timer_modify(P_OSAL_TIMER, UINT32); +extern INT32 osal_timer_delete(P_OSAL_TIMER); + +extern INT32 osal_fifo_init(P_OSAL_FIFO pFifo, UINT8 *buffer, UINT32 size); +extern VOID osal_fifo_deinit(P_OSAL_FIFO pFifo); +extern INT32 osal_fifo_reset(P_OSAL_FIFO pFifo); +extern UINT32 osal_fifo_in(P_OSAL_FIFO pFifo, PUINT8 buffer, UINT32 size); +extern UINT32 osal_fifo_out(P_OSAL_FIFO pFifo, PUINT8 buffer, UINT32 size); +extern UINT32 osal_fifo_len(P_OSAL_FIFO pFifo); +extern UINT32 osal_fifo_sz(P_OSAL_FIFO pFifo); +extern UINT32 osal_fifo_avail(P_OSAL_FIFO pFifo); +extern UINT32 osal_fifo_is_empty(P_OSAL_FIFO pFifo); +extern UINT32 osal_fifo_is_full(P_OSAL_FIFO pFifo); + +extern INT32 osal_wake_lock_init(P_OSAL_WAKE_LOCK plock); +extern INT32 osal_wake_lock_deinit(P_OSAL_WAKE_LOCK plock); +extern INT32 osal_wake_lock(P_OSAL_WAKE_LOCK plock); +extern INT32 osal_wake_unlock(P_OSAL_WAKE_LOCK plock); +extern INT32 osal_wake_lock_count(P_OSAL_WAKE_LOCK plock); + +extern INT32 osal_unsleepable_lock_init (P_OSAL_UNSLEEPABLE_LOCK ); +extern INT32 osal_lock_unsleepable_lock (P_OSAL_UNSLEEPABLE_LOCK ); +extern INT32 osal_unlock_unsleepable_lock (P_OSAL_UNSLEEPABLE_LOCK ); +extern INT32 osal_unsleepable_lock_deinit (P_OSAL_UNSLEEPABLE_LOCK ); + +extern INT32 osal_sleepable_lock_init (P_OSAL_SLEEPABLE_LOCK ); +extern INT32 osal_lock_sleepable_lock (P_OSAL_SLEEPABLE_LOCK ); +extern INT32 osal_unlock_sleepable_lock (P_OSAL_SLEEPABLE_LOCK ); +extern INT32 osal_sleepable_lock_deinit (P_OSAL_SLEEPABLE_LOCK ); + +extern INT32 osal_signal_init (P_OSAL_SIGNAL); +extern INT32 osal_wait_for_signal (P_OSAL_SIGNAL); +extern INT32 +osal_wait_for_signal_timeout ( + P_OSAL_SIGNAL + ); +extern INT32 +osal_raise_signal ( + P_OSAL_SIGNAL + ); +extern INT32 +osal_signal_deinit ( + P_OSAL_SIGNAL + ); + +extern INT32 osal_event_init(P_OSAL_EVENT); +extern INT32 osal_wait_for_event(P_OSAL_EVENT, P_COND , void *); +extern INT32 osal_wait_for_event_timeout(P_OSAL_EVENT , P_COND , void *); +extern INT32 osal_trigger_event(P_OSAL_EVENT); + +extern INT32 osal_event_deinit (P_OSAL_EVENT); + +extern INT32 osal_thread_create(P_OSAL_THREAD); +extern INT32 osal_thread_run(P_OSAL_THREAD); +extern INT32 osal_thread_should_stop(P_OSAL_THREAD); +extern INT32 osal_thread_stop(P_OSAL_THREAD); +/*extern INT32 osal_thread_wait_for_event(P_OSAL_THREAD, P_OSAL_EVENT);*/ +extern INT32 osal_thread_wait_for_event(P_OSAL_THREAD, P_OSAL_EVENT, P_OSAL_EVENT_CHECKER); + +/*check pOsalLxOp and OSAL_THREAD_SHOULD_STOP*/ +extern INT32 osal_thread_destroy(P_OSAL_THREAD); + +extern INT32 osal_clear_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData); +extern INT32 osal_set_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData); +extern INT32 osal_test_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData); +extern INT32 osal_test_and_clear_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData); +extern INT32 osal_test_and_set_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData); + +extern INT32 osal_dbg_assert_aee(const char *module, const char *detail_description); +extern INT32 osal_gettimeofday(PINT32 sec, PINT32 usec); +extern INT32 osal_printtimeofday(const PUINT8 prefix); + +extern VOID +osal_buffer_dump ( + const UINT8 *buf, + const UINT8 *title, + UINT32 len, + UINT32 limit + ); + +extern UINT32 osal_op_get_id(P_OSAL_OP pOp); +extern MTK_WCN_BOOL osal_op_is_wait_for_signal(P_OSAL_OP pOp); +extern VOID osal_op_raise_signal(P_OSAL_OP pOp, INT32 result); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#define osal_assert(condition) if (!(condition)) {osal_err_print("%s, %d, (%s)\n", __FILE__, __LINE__, #condition);} + +#endif /* _OSAL_H_ */ + diff --git a/drivers/mtk_wcn_combo/common/include/stp_exp.h b/drivers/mtk_wcn_combo/common/include/stp_exp.h new file mode 100755 index 000000000000..6bad140302f1 --- /dev/null +++ b/drivers/mtk_wcn_combo/common/include/stp_exp.h @@ -0,0 +1,303 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +#ifndef _STP_EXP_H_ +#define _STP_EXP_H_ + +#include "osal_typedef.h" +#include "osal.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define BT_TASK_INDX (0) +#define FM_TASK_INDX (1) +#define GPS_TASK_INDX (2) +#define WIFI_TASK_INDX (3) +#define WMT_TASK_INDX (4) +#define STP_TASK_INDX (5) +#define INFO_TASK_INDX (6) +#define MTKSTP_MAX_TASK_NUM (7) + +#define MTKSTP_BUFFER_SIZE (16384) //Size of RX Queue + + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef void (*MTK_WCN_STP_EVENT_CB)(void); +typedef INT32 (*MTK_WCN_STP_IF_TX)(const UINT8 *data, const UINT32 size, UINT32 *written_size); +/* export for HIF driver */ +typedef void (*MTK_WCN_STP_IF_RX)(const UINT8 *data, INT32 size); + +typedef enum { + STP_UART_IF_TX = 0, + STP_SDIO_IF_TX, + STP_MAX_IF_TX +}ENUM_STP_TX_IF_TYPE; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_receive_data +* DESCRIPTION +* receive data from serial protocol engine +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* RETURNS +* INT32 >= 0: size of data received; < 0: error +*****************************************************************************/ +extern INT32 mtk_wcn_stp_receive_data(UINT8 *buffer, UINT32 length, UINT8 type); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_send_data +* DESCRIPTION +* subfunction send data through STP +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* type [IN] subfunction type +* RETURNS +* INT32 >= 0: length transmitted; < 0: error +*****************************************************************************/ +extern INT32 mtk_wcn_stp_send_data(const UINT8 *buffer, const UINT32 length, const UINT8 type); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_rxqueue_empty +* DESCRIPTION +* Is certain rx queue empty? +* PARAMETERS +* type [IN] subfunction type +* RETURNS +* INT32 0: queue is NOT empyt; !0: queue is empty +*****************************************************************************/ +extern MTK_WCN_BOOL mtk_wcn_stp_is_rxqueue_empty(UINT8 type); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_enable +* DESCRIPTION +* Is STP ready? +* PARAMETERS +* none. +* RETURNS +* MTK_WCN_BOOL TRUE:ready, FALSE:not ready +*****************************************************************************/ +extern MTK_WCN_BOOL mtk_wcn_stp_is_ready(void); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_parser_data +* DESCRIPTION +* push data to serial transport protocol parser engine +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* RETURNS +* void +*****************************************************************************/ +extern INT32 mtk_wcn_stp_parser_data(UINT8 *buffer, UINT32 length); + +/***************************************************************************** +* FUNCTION +* set_bluetooth_rx_interface +* DESCRIPTION +* Set bluetooth rx interface +* PARAMETERS +* rx interface type +* RETURNS +* void +*****************************************************************************/ +extern void mtk_wcn_stp_set_bluez(MTK_WCN_BOOL sdio_flag); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_register_tx_event_cb +* DESCRIPTION +* regiter Tx event callback function +* PARAMETERS +* func +* RETURNS +* int: 0:successful , -1: fail +*****************************************************************************/ +extern int mtk_wcn_stp_register_tx_event_cb(int type, MTK_WCN_STP_EVENT_CB func); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_register_event_cb +* DESCRIPTION +* regiter Rx event callback function +* PARAMETERS +* func +* RETURNS +* int: 0:successful , -1: fail +*****************************************************************************/ +extern int mtk_wcn_stp_register_event_cb(int type, MTK_WCN_STP_EVENT_CB func); + + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_register_if_tx +* DESCRIPTION +* regiter Tx event callback function +* PARAMETERS +* stp_if: SDIO or UART, fnnc: Call back function +* RETURNS +* int: 0:successful , -1: fail +*****************************************************************************/ +extern int mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func); + + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_register_if_rx +* DESCRIPTION +* regiter Rx event callback function +* PARAMETERS +* stp_if: SDIO or UART, fnnc: Call back function +* RETURNS +* int: 0:successful , -1: fail +*****************************************************************************/ +extern int mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _WMT_EXP_H_ */ + + + + + + + + + + + + + diff --git a/drivers/mtk_wcn_combo/common/include/wmt.h b/drivers/mtk_wcn_combo/common/include/wmt.h new file mode 100755 index 000000000000..f4931871f339 --- /dev/null +++ b/drivers/mtk_wcn_combo/common/include/wmt.h @@ -0,0 +1,8 @@ + +#ifndef _MTKWMT_H_ +#define _MTKWMT_H_ +#include "wmt_core.h" + + + +#endif /*_MTKWMT_H_*/ diff --git a/drivers/mtk_wcn_combo/common/include/wmt_exp.h b/drivers/mtk_wcn_combo/common/include/wmt_exp.h new file mode 100755 index 000000000000..c68bb10646d0 --- /dev/null +++ b/drivers/mtk_wcn_combo/common/include/wmt_exp.h @@ -0,0 +1,320 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +#ifndef _WMT_EXP_H_ +#define _WMT_EXP_H_ + +#include +#include "osal.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +#if 0 +/* moved from wmt_lib.h */ +#ifdef CONFIG_MTK_COMBO_COMM_PS +/* Enable common i/f power saving handling support */ +/* FixMe SDIO power saving is to be integrated */ +#define CFG_WMT_PS_SUPPORT 1 +#else +#define CFG_WMT_PS_SUPPORT 0 +#endif +#endif + +#define CFG_WMT_PS_SUPPORT 1 + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#if 1 /* moved from wmt_lib.h */ +#ifndef DFT_TAG +#define DFT_TAG "[WMT-DFT]" +#endif + +#define WMT_LOUD_FUNC(fmt, arg...) if (gWmtDbgLvl >= WMT_LOG_LOUD) { osal_loud_print(DFT_TAG "[L]%s:" fmt, __FUNCTION__ ,##arg);} +#define WMT_DBG_FUNC(fmt, arg...) if (gWmtDbgLvl >= WMT_LOG_DBG) { osal_dbg_print(DFT_TAG "[D]%s:" fmt, __FUNCTION__ ,##arg);} +#define WMT_INFO_FUNC(fmt, arg...) if (gWmtDbgLvl >= WMT_LOG_INFO) { osal_info_print(DFT_TAG "[I]%s:" fmt, __FUNCTION__ ,##arg);} +#define WMT_WARN_FUNC(fmt, arg...) if (gWmtDbgLvl >= WMT_LOG_WARN) { osal_warn_print(DFT_TAG "[W]%s:" fmt, __FUNCTION__ ,##arg);} +#define WMT_ERR_FUNC(fmt, arg...) if (gWmtDbgLvl >= WMT_LOG_ERR) { osal_err_print(DFT_TAG "[E]%s(%d):" fmt, __FUNCTION__ , __LINE__, ##arg);} +#define WMT_TRC_FUNC(f) if (gWmtDbgLvl >= WMT_LOG_DBG) { osal_dbg_print(DFT_TAG "<%s> <%d>\n", __FUNCTION__, __LINE__);} +#endif + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#if 1 /* moved from wmt_lib.h */ +extern UINT32 gWmtDbgLvl ; +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#if 1 /* moved from wmt_lib.h */ +#define WMT_LOG_LOUD 4 +#define WMT_LOG_DBG 3 +#define WMT_LOG_INFO 2 +#define WMT_LOG_WARN 1 +#define WMT_LOG_ERR 0 +#endif + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_WMTDRV_TYPE_T { + WMTDRV_TYPE_BT = 0, + WMTDRV_TYPE_FM = 1, + WMTDRV_TYPE_GPS = 2, + WMTDRV_TYPE_WIFI = 3, + WMTDRV_TYPE_WMT = 4, + WMTDRV_TYPE_STP = 5, + WMTDRV_TYPE_SDIO1 = 6, + WMTDRV_TYPE_SDIO2 = 7, + WMTDRV_TYPE_LPBK = 8, + WMTDRV_TYPE_MAX +} ENUM_WMTDRV_TYPE_T, *P_ENUM_WMTDRV_TYPE_T; + +// TODO: [ChangeFeature][GeorgeKuo] Reconsider usage of this type +// TODO: how do we extend for new chip and newer revision? +// TODO: This way is hard to extend +typedef enum _ENUM_WMTHWVER_TYPE_T{ + WMTHWVER_MT6620_E1 = 0x0, + WMTHWVER_MT6620_E2 = 0x1, + WMTHWVER_MT6620_E3 = 0x2, + WMTHWVER_MT6620_E4 = 0x3, + WMTHWVER_MT6620_E5 = 0x4, + WMTHWVER_MT6620_E6 = 0x5, + WMTHWVER_MT6620_E7 = 0x6, + WMTHWVER_MT6620_MAX, + WMTHWVER_INVALID = 0xff +} ENUM_WMTHWVER_TYPE_T, *P_ENUM_WMTHWVER_TYPE_T; + +typedef enum _ENUM_WMTDSNS_TYPE_T{ + WMTDSNS_FM_DISABLE = 0, + WMTDSNS_FM_ENABLE = 1, + WMTDSNS_MAX +} ENUM_WMTDSNS_TYPE_T, *P_ENUM_WMTDSNS_TYPE_T; + +typedef enum _ENUM_WMTTHERM_TYPE_T{ + WMTTHERM_ZERO = 0, + WMTTHERM_ENABLE = WMTTHERM_ZERO + 1, + WMTTHERM_READ = WMTTHERM_ENABLE + 1, + WMTTHERM_DISABLE = WMTTHERM_READ + 1, + WMTTHERM_MAX +}ENUM_WMTTHERM_TYPE_T, *P_ENUM_WMTTHERM_TYPE_T; + +typedef enum _ENUM_WMTMSG_TYPE_T { + WMTMSG_TYPE_POWER_ON = 0, + WMTMSG_TYPE_POWER_OFF = 1, + WMTMSG_TYPE_RESET = 2, + WMTMSG_TYPE_STP_RDY= 3, + WMTMSG_TYPE_HW_FUNC_ON= 4, + WMTMSG_TYPE_MAX +} ENUM_WMTMSG_TYPE_T, *P_ENUM_WMTMSG_TYPE_T; + +typedef enum _ENUM_WMTRSTMSG_TYPE_T{ + WMTRSTMSG_RESET_START = 0x0, + WMTRSTMSG_RESET_END = 0x1, + WMTRSTMSG_RESET_MAX, + WMTRSTMSG_RESET_INVALID = 0xff +} ENUM_WMTRSTMSG_TYPE_T, *P_ENUM_WMTRSTMSG_TYPE_T; + +typedef void (*PF_WMT_CB)( + ENUM_WMTDRV_TYPE_T, /* Source driver type */ + ENUM_WMTDRV_TYPE_T, /* Destination driver type */ + ENUM_WMTMSG_TYPE_T, /* Message type */ + VOID *, /* READ-ONLY buffer. Buffer is allocated and freed by WMT_drv. Client + can't touch this buffer after this function return. */ + UINT32 /* Buffer size in unit of byte */ +); + +typedef enum _SDIO_PS_OP{ + OWN_SET = 0, + OWN_CLR = 1 +} SDIO_PS_OP; + + +typedef INT32 (*PF_WMT_SDIO_PSOP)(SDIO_PS_OP); + +#if 1 /* moved from wmt_core.h */ +typedef enum { + WMT_SDIO_SLOT_INVALID = 0, + WMT_SDIO_SLOT_SDIO1 = 1, /* Wi-Fi dedicated SDIO1*/ + WMT_SDIO_SLOT_SDIO2 = 2, + WMT_SDIO_SLOT_MAX +} WMT_SDIO_SLOT_NUM; + +typedef enum { + WMT_SDIO_FUNC_STP = 0, + WMT_SDIO_FUNC_WIFI = 1, + WMT_SDIO_FUNC_MAX +} WMT_SDIO_FUNC_TYPE; +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + + + + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*subsystem function ctrl APIs*/ +extern MTK_WCN_BOOL +mtk_wcn_wmt_func_off ( + ENUM_WMTDRV_TYPE_T type + ); + +extern MTK_WCN_BOOL +mtk_wcn_wmt_func_on ( + ENUM_WMTDRV_TYPE_T type + ); + +extern MTK_WCN_BOOL mtk_wcn_wmt_dsns_ctrl ( + ENUM_WMTDSNS_TYPE_T eType + ); + +extern INT32 mtk_wcn_wmt_msgcb_reg ( + ENUM_WMTDRV_TYPE_T eType, + PF_WMT_CB pCb + ); + +extern INT32 mtk_wcn_wmt_msgcb_unreg ( + ENUM_WMTDRV_TYPE_T eType + ); + +extern INT32 +mtk_wcn_stp_wmt_sdio_op_reg ( + PF_WMT_SDIO_PSOP own_cb + ); + +/* +return value: +enable/disable thermal sensor function: true(1)/false(0) +read thermal sensor function: thermal value + +*/ +extern INT8 +mtk_wcn_wmt_therm_ctrl ( + ENUM_WMTTHERM_TYPE_T eType + ); + +extern ENUM_WMTHWVER_TYPE_T +mtk_wcn_wmt_hwver_get (VOID); + +extern INT32 wmt_lib_set_aif ( + CMB_STUB_AIF_X aif, + MTK_WCN_BOOL share + ); /* set AUDIO interface options */ + +extern VOID +wmt_lib_ps_irq_cb(VOID); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _WMT_EXP_H_ */ + + + + + + + diff --git a/drivers/mtk_wcn_combo/common/include/wmt_plat.h b/drivers/mtk_wcn_combo/common/include/wmt_plat.h new file mode 100755 index 000000000000..1972b53ce149 --- /dev/null +++ b/drivers/mtk_wcn_combo/common/include/wmt_plat.h @@ -0,0 +1,260 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +#ifndef _WMT_PLAT_H_ +#define _WMT_PLAT_H_ +#include "osal_typedef.h" +#include "osal.h" +#include +#include "mtk_wcn_cmb_hw.h" + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#if 0 /* [GeorgeKuo] remove COMBO_AUDIO FLAG */ +#define COMBO_AUDIO_BT_MASK (0x1UL) +#define COMBO_AUDIO_BT_PCM_ON (0x1UL << 0) +#define COMBO_AUDIO_BT_PCM_OFF (0x0UL << 0) + +#define COMBO_AUDIO_FM_MASK (0x2UL) +#define COMBO_AUDIO_FM_LINEIN (0x0UL << 1) +#define COMBO_AUDIO_FM_I2S (0x1UL << 1) + +#define COMBO_AUDIO_PIN_MASK (0x4UL) +#define COMBO_AUDIO_PIN_SHARE (0x1UL << 2) +#define COMBO_AUDIO_PIN_SEPARATE (0x0UL << 2) +#endif + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef enum _ENUM_FUNC_STATE_{ + FUNC_OFF = 0, + FUNC_ON = 1, + FUNC_RST = 2, + FUNC_CTRL_MAX, +} ENUM_FUNC_STATE, *P_ENUM_FUNC_STATE; + +typedef enum _ENUM_PIN_ID_{ + PIN_LDO = 0, + PIN_PMU = 1, + PIN_RTC = 2, + PIN_RST = 3, + PIN_BGF_EINT = 4, + PIN_WIFI_EINT = 5, + PIN_ALL_EINT = 6, + PIN_UART_GRP = 7, + PIN_PCM_GRP = 8, + PIN_I2S_GRP = 9, + PIN_SDIO_GRP = 10, + PIN_GPS_SYNC = 11, + PIN_GPS_LNA = 12, + PIN_ID_MAX +} ENUM_PIN_ID, *P_ENUM_PIN_ID; + +typedef enum _ENUM_PIN_STATE_{ + PIN_STA_INIT = 0, + PIN_STA_OUT_L = 1, + PIN_STA_OUT_H = 2, + PIN_STA_IN_L = 3, + PIN_STA_MUX = 4, + PIN_STA_EINT_EN = 5, + PIN_STA_EINT_DIS = 6, + PIN_STA_DEINIT = 7, + PIN_STA_MAX +} ENUM_PIN_STATE, *P_ENUM_PIN_STATE; + +typedef enum _CMB_IF_TYPE_{ + CMB_IF_UART = 0, + CMB_IF_WIFI_SDIO = 1, + CMB_IF_BGF_SDIO = 2, + CMB_IF_BGWF_SDIO = 3, + CMB_IF_TYPE_MAX +} CMB_IF_TYPE, *P_CMB_IF_TYPE; + +typedef INT32 (*fp_set_pin)(ENUM_PIN_STATE); + +typedef enum _ENUM_WL_OP_{ + WL_OP_GET = 0, + WL_OP_PUT = 1, + WL_OP_MAX +} ENUM_WL_OP, *P_ENUM_WL_OP; + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +INT32 +wmt_plat_init (P_PWR_SEQ_TIME pPwrSeqTime); + +INT32 +wmt_plat_deinit (VOID); + +#if 0 +INT32 +wmt_plat_irq_ctrl ( + ENUM_FUNC_STATE state + ); +#endif + +INT32 +wmt_plat_pwr_ctrl ( + ENUM_FUNC_STATE state + ); + +INT32 +wmt_plat_ps_ctrl ( + ENUM_FUNC_STATE state + ); + +INT32 +wmt_plat_gpio_ctrl ( + ENUM_PIN_ID id, + ENUM_PIN_STATE state + ); + +INT32 +wmt_plat_eirq_ctrl ( + ENUM_PIN_ID id, + ENUM_PIN_STATE state + ); + +INT32 +wmt_plat_audio_ctrl ( + CMB_STUB_AIF_X state, + CMB_STUB_AIF_CTRL ctrl + ); + +INT32 +wmt_plat_sdio_ctrl ( + UINT32 sdioPortNum, + ENUM_FUNC_STATE on + ); + + +INT32 +wmt_plat_wake_lock_ctrl( + ENUM_WL_OP opId + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _WMT_PLAT_H_ */ + diff --git a/drivers/mtk_wcn_combo/common/linux/hif_sdio.c b/drivers/mtk_wcn_combo/common/linux/hif_sdio.c new file mode 100755 index 000000000000..a49ffea8f00c --- /dev/null +++ b/drivers/mtk_wcn_combo/common/linux/hif_sdio.c @@ -0,0 +1,2357 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + + +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + */ +/* MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +/* +** $Id: $ +*/ + +/*! \file "hif_sdio.c" + * \brief + * + * detailed description +*/ + +/* +** $Log: $ + * + * 07 25 2010 george.kuo + * + * Move hif_sdio driver to linux directory. + * + * 07 23 2010 george.kuo + * + * Add MT6620 driver source tree + * , including char device driver (wmt, bt, gps), stp driver, interface driver (tty ldisc and hif_sdio), and bt hci driver. +** +** +*/ + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +#define HIF_SDIO_UPDATE (1) + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "hif_sdio.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +//#define DRV_NAME "[hif_sdio]" + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +/*! + * \brief A macro used to generate hif_sdio client's context + * + * Generate a context for hif_sdio client based on the following input parameters + * |<-card id (16bits)->|<-block size in unit of 256 bytes(8 bits)->|<-function number(4bits)->|<-index(4bits)->| + * + * \param manf the 16 bit manufacturer id + * \param card the 16 bit card id + * \param func the 16 bit function number + * \param b_sz the 16 bit function block size + */ +#define CLTCTX(cid, func, blk_sz, idx) \ + (MTK_WCN_HIF_SDIO_CLTCTX)( (((UINT32)(cid) & 0xFFFFUL) << 16) | \ + (((UINT32)(func) & 0xFUL) << 4) | \ + (((UINT32)(blk_sz) & 0xFF00UL) << 0) | \ + (((UINT32)idx & 0xFUL) << 0) ) + +/*! + * \brief A set of macros used to get information out of an hif_sdio client context + * + * Generate a context for hif_sdio client based on the following input parameters + */ +#define CLTCTX_CID(ctx) (((ctx) >> 16) & 0xFFFF) +#define CLTCTX_FUNC(ctx) (((ctx) >> 4) & 0xF) +#define CLTCTX_BLK_SZ(ctx) (((ctx) >> 0) & 0xFF00) +#define CLTCTX_IDX(ctx) ((ctx) & 0xF) +#define CLTCTX_IDX_VALID(idx) ((idx >= 0) && (idx < CFG_CLIENT_COUNT)) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static int hif_sdio_probe ( + struct sdio_func *func, + const struct sdio_device_id *id + ); + +static void hif_sdio_remove ( + struct sdio_func *func + ); + +static void hif_sdio_irq ( + struct sdio_func *func + ); + +static int hif_sdio_clt_probe_func ( + MTK_WCN_HIF_SDIO_REGISTINFO *registinfo_p, + INT8 probe_idx + ); + +static void hif_sdio_clt_probe_worker( + struct work_struct *work + ); + +static int hif_sdio_find_probed_list_index_by_func( + struct sdio_func *func + ); + +static int hif_sdio_find_probed_list_index_by_id_func( + UINT16 vendor, + UINT16 device, + UINT16 func_num + ); + +static void hif_sdio_init_clt_list( + INT32 index + ); + +static int hif_sdio_find_clt_list_index ( + UINT16 vendor, + UINT16 device, + UINT16 func_num + ); + +static int hif_sdio_check_supported_sdio_id( + UINT16 vendor, + UINT16 device + ); + +static int hif_sdio_check_duplicate_sdio_id( + UINT16 vendor, + UINT16 device, + UINT16 func_num + ); + +static int hif_sdio_add_clt_list( + INT32* clt_index_p, + const MTK_WCN_HIF_SDIO_CLTINFO *pinfo, + UINT32 tbl_index + ); + +static INT32 hif_sdio_stp_on( + void + ); + +static INT32 hif_sdio_stp_off( + void + ); + +static INT32 hif_sdio_wifi_on( + void + ); + +static INT32 hif_sdio_wifi_off( + void + ); + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/* Supported SDIO device table */ +static const struct sdio_device_id mtk_sdio_id_tbl[] = { + /* MT6618 */ /* Not an SDIO standard class device */ + { SDIO_DEVICE(0x037A, 0x018A) }, /* SDIO1:WIFI */ + { SDIO_DEVICE(0x037A, 0x018B) }, /* SDIO2:FUNC1:BT+FM */ + { SDIO_DEVICE(0x037A, 0x018C) }, /* 2-function (SDIO2:FUNC1:BT+FM, FUNC2:WIFI) */ + + /* MT6619 */ /* Not an SDIO standard class device */ + { SDIO_DEVICE(0x037A, 0x6619) }, /* SDIO2:FUNC1:BT+FM+GPS */ + + /* MT6620 */ /* Not an SDIO standard class device */ + { SDIO_DEVICE(0x037A, 0x020A) }, /* SDIO1:FUNC1:WIFI */ + { SDIO_DEVICE(0x037A, 0x020B) }, /* SDIO2:FUNC1:BT+FM+GPS */ + { SDIO_DEVICE(0x037A, 0x020C) }, /* 2-function (SDIO2:FUNC1:BT+FM+GPS, FUNC2:WIFI) */ + + /* MT5921 */ /* Not an SDIO standard class device */ + { SDIO_DEVICE(0x037A, 0x5921) }, + { /* end: all zeroes */ }, +}; + +static struct sdio_driver mtk_sdio_client_drv = { + .name = "mtk_sdio_client", /* MTK SDIO Client Driver */ + .id_table = mtk_sdio_id_tbl, /* all supported struct sdio_device_id table */ + .probe = hif_sdio_probe, + .remove = hif_sdio_remove, +}; + +/* Registered client driver list */ +/* static list g_hif_sdio_clt_drv_list */ +static MTK_WCN_HIF_SDIO_REGISTINFO g_hif_sdio_clt_drv_list[CFG_CLIENT_COUNT]; + +/* MMC probed function list */ +/* static list g_hif_sdio_probed_func_list */ +static MTK_WCN_HIF_SDIO_PROBEINFO g_hif_sdio_probed_func_list[CFG_CLIENT_COUNT]; + +/* spin lock info for g_hif_sdio_clt_drv_list and g_hif_sdio_probed_func_list */ +static MTK_WCN_HIF_SDIO_LOCKINFO g_hif_sdio_lock_info; + +/* reference count, debug information? */ +static int gRefCount; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("MediaTek Inc WCN_SE_CS3"); +MODULE_DESCRIPTION("MediaTek MT6620 HIF SDIO Driver"); + +MODULE_DEVICE_TABLE(sdio, mtk_sdio_id_tbl); + +UINT32 gHifSdioDbgLvl = HIF_SDIO_LOG_ERR;//HIF_SDIO_LOG_INFO; Modify loglevel + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*! + * \brief Translate CLTCTX into a pointer to struct sdio_func if it is valid + * + * Translate a CLTCTX into a pointer to struct sdio_func if it is + * 1) probed by mmc_core, and + * 2) client driver is registered, and + * 3) clt_idx of client driver is valid + * + * \param ctx a context provided by client driver + * + * \retval null if any condition is not valie + * \retval a pointer to a struct sdio_func mapped by provided ctx + */ +static inline struct sdio_func* hif_sdio_ctx_to_func ( + MTK_WCN_HIF_SDIO_CLTCTX ctx) +{ + UINT32 probe_index; + + //4 <1> check if ctx is valid, registered, and probed + probe_index = CLTCTX_IDX(ctx); + if (unlikely(!CLTCTX_IDX_VALID(probe_index))) /* invalid index in CLTCTX */ + { + HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx); + return NULL; + } + else + { + if (unlikely(g_hif_sdio_probed_func_list[probe_index].clt_idx < 0)) /* the client has not been registered */ + { + HIF_SDIO_WARN_FUNC("can't find client idx in probed list!ctx(0x%x) prob_idx(%d) clt_idx(%d)\n", + ctx, probe_index, g_hif_sdio_probed_func_list[probe_index].clt_idx); + return NULL; + } + } + return g_hif_sdio_probed_func_list[probe_index].func; +} + +/*! + * \brief MTK hif sdio client registration function + * + * Client uses this function to register itself to hif_sdio driver + * + * \param pinfo a pointer of client's information + * + * \retval 0 register successfully + * \retval < 0 list error code here + */ +INT32 mtk_wcn_hif_sdio_client_reg ( + const MTK_WCN_HIF_SDIO_CLTINFO *pinfo + ) +{ + INT32 ret = -HIF_SDIO_ERR_FAIL; + INT32 clt_index = -1; + UINT32 i = 0; + UINT32 j = 0; + MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO *clt_probe_worker_info = 0; + + HIF_SDIO_INFO_FUNC("start!\n"); + + //4 <1> check input pointer is valid + HIF_SDIO_ASSERT( pinfo ); + + //4 <2> check if input parameters are all supported and valid + for ( i=0; ifunc_tbl_size; i++ ) + { + ret = hif_sdio_check_supported_sdio_id( pinfo->func_tbl[i].manf_id, pinfo->func_tbl[i].card_id ); + if(ret) + { + HIF_SDIO_WARN_FUNC("vendor id(0x%x) and device id(0x%x) of sdio_func are not supported in mtk_sdio_id_tbl!\n", + pinfo->func_tbl[i].manf_id, + pinfo->func_tbl[i].card_id); + goto out; + } + } + HIF_SDIO_DBG_FUNC("hif_sdio_check_supported_sdio_id() done!\n"); + + //4 <3> check if the specific {manf id, card id, function number} tuple is + //4 already resigstered + for ( i=0; ifunc_tbl_size; i++ ) + { + ret = hif_sdio_check_duplicate_sdio_id( pinfo->func_tbl[i].manf_id, pinfo->func_tbl[i].card_id, pinfo->func_tbl[i].func_num ); + if(ret) + { + HIF_SDIO_WARN_FUNC("vendor id(0x%x), device id(0x%x), and fun_num(%d) of sdio_func are duplicated in g_hif_sdio_clt_drv_list!\n", + pinfo->func_tbl[i].manf_id, + pinfo->func_tbl[i].card_id, + pinfo->func_tbl[i].func_num ); + goto out; + } + } + HIF_SDIO_DBG_FUNC("hif_sdio_check_duplicate_sdio_id() done!\n"); + + //4 <4> add the specified {manf id, card id, function number} tuple to registered client list + HIF_SDIO_DBG_FUNC("pinfo->func_tbl_size:%d\n", pinfo->func_tbl_size); + for ( i=0; ifunc_tbl_size; i++ ) + { + ret = hif_sdio_add_clt_list( &clt_index, pinfo, i ); + if(ret) + { + HIF_SDIO_WARN_FUNC("client's info are added in registed client list failed (buffer is full)!\n"); + goto out; + } + HIF_SDIO_DBG_FUNC("hif_sdio_add_clt_list() done (gRefCount=%d)!\n", gRefCount); + + //4 <5> if the specific {manf id, card id, function number} tuple has already + //4 been probed by mmc, schedule another task to call client's .hif_clt_probe() + for ( j=0; jmanf_id == g_hif_sdio_probed_func_list[j].func->vendor) &&\ + (g_hif_sdio_clt_drv_list[clt_index].func_info->card_id == g_hif_sdio_probed_func_list[j].func->device) &&\ + (g_hif_sdio_clt_drv_list[clt_index].func_info->func_num == g_hif_sdio_probed_func_list[j].func->num) ) + { + g_hif_sdio_probed_func_list[j].clt_idx = clt_index; + // probed spin unlock + spin_unlock_bh( &g_hif_sdio_lock_info.probed_list_lock ); + + /* use worker thread to perform the client's .hif_clt_probe() */ + clt_probe_worker_info = vmalloc( sizeof(MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO) ); + INIT_WORK( &clt_probe_worker_info->probe_work, hif_sdio_clt_probe_worker ); + clt_probe_worker_info->registinfo_p = &g_hif_sdio_clt_drv_list[clt_index]; + clt_probe_worker_info->probe_idx = j; + schedule_work( &clt_probe_worker_info->probe_work ); + + //4 <5.1> remember to do claim_irq for the func if it's irq had been released. + if ( !(g_hif_sdio_probed_func_list[j].func->irq_handler) ) + { + sdio_claim_host(g_hif_sdio_probed_func_list[j].func); + ret = sdio_claim_irq(g_hif_sdio_probed_func_list[j].func, hif_sdio_irq); + sdio_release_host(g_hif_sdio_probed_func_list[j].func); + HIF_SDIO_INFO_FUNC("sdio_claim_irq for func(0x%p) j(%d) v(0x%x) d(0x%x) ok\n", + g_hif_sdio_probed_func_list[j].func, j, + g_hif_sdio_probed_func_list[j].func->vendor, + g_hif_sdio_probed_func_list[j].func->device + ); + } + //4 <5.2> Reset the block size of the function provided by client + HIF_SDIO_INFO_FUNC("Reset sdio block size: %d!\n", g_hif_sdio_clt_drv_list[clt_index].func_info->blk_sz); + sdio_claim_host(g_hif_sdio_probed_func_list[j].func); + ret = sdio_set_block_size(g_hif_sdio_probed_func_list[j].func,\ + g_hif_sdio_clt_drv_list[clt_index].func_info->blk_sz); + sdio_release_host(g_hif_sdio_probed_func_list[j].func); + } + else + { + // probed spin unlock + spin_unlock_bh( &g_hif_sdio_lock_info.probed_list_lock ); + } + } + HIF_SDIO_DBG_FUNC("map g_hif_sdio_clt_drv_list to g_hif_sdio_probed_func_list done!\n"); + } + ret = HIF_SDIO_ERR_SUCCESS; + gRefCount++; + +out: + //4 error handling + + HIF_SDIO_DBG_FUNC("end!\n"); + return ret; +} /* end of mtk_wcn_hif_sdio_client_reg() */ + +/*! + * \brief MTK hif sdio client un-registration function + * + * Client uses this function to un-register itself + * + * \param pinfo a pointer of client's information + * + * \retval 0 register successfully + * \retval < 0 list error code here + */ +INT32 mtk_wcn_hif_sdio_client_unreg ( + const MTK_WCN_HIF_SDIO_CLTINFO *pinfo + ) +{ + INT32 ret = -HIF_SDIO_ERR_FAIL; + INT32 clt_list_index = 0; + UINT32 i = 0; + UINT32 j = 0; + + HIF_SDIO_INFO_FUNC("start!\n"); + + //4 <1> check if input pointer is valid + HIF_SDIO_ASSERT( pinfo ); + + //4 <2> check if input parameters are all supported and valid + for ( i=0; ifunc_tbl_size; i++ ) + { + ret = hif_sdio_check_supported_sdio_id( pinfo->func_tbl[i].manf_id, pinfo->func_tbl[i].card_id ); + if(ret) + { + HIF_SDIO_WARN_FUNC("vendor id(0x%x) and device id(0x%x) of sdio_func are not supported in mtk_sdio_id_tbl!\n", + pinfo->func_tbl[i].manf_id, + pinfo->func_tbl[i].card_id); + goto out; + } + } + + //4 <3> check if the specific {manf id, card id, function number} tuple is already resigstered + //4 and find the corresponding client ctx and call client's .hif_clt_remove() in THIS context + for ( i=0; ifunc_tbl_size; i++ ) + { + clt_list_index = hif_sdio_find_clt_list_index(pinfo->func_tbl[i].manf_id, pinfo->func_tbl[i].card_id, pinfo->func_tbl[i].func_num); + if ( clt_list_index < 0 ) + { + HIF_SDIO_WARN_FUNC("vendor id(0x%x), device id(0x%x), and fun_num(%d) client info is not in the client's registed list!\n", + pinfo->func_tbl[i].manf_id, + pinfo->func_tbl[i].card_id, + pinfo->func_tbl[i].func_num ); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } + + //4 <4> mark the specified {manf id, card id, function number} tuple as + //4 un-registered and invalidate client's context + hif_sdio_init_clt_list( clt_list_index ); + + /* un-map g_hif_sdio_clt_drv_list index in g_hif_sdio_probed_func_list */ + for ( j=0; j check if ctx is valid, registered, and probed +#if HIF_SDIO_UPDATE + ret = -HIF_SDIO_ERR_FAIL; + func = hif_sdio_ctx_to_func(ctx); + if (!func) { + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } +#else + probe_index = CLTCTX_IDX(ctx); + if( probe_index < 0 ) /* the function has not been probed */ + { + HIF_SDIO_WARN_FUNC("can't find client in probed list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } + else + { + if ( g_hif_sdio_probed_func_list[probe_index].clt_idx < 0 ) /* the client has not been registered */ + { + HIF_SDIO_WARN_FUNC("can't find client in registered list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } + } + func = g_hif_sdio_probed_func_list[probe_index].func; +#endif + + //4 <2> + sdio_claim_host(func); + *pvb = sdio_readb(func, offset, &ret); + sdio_release_host(func); + + //4 <3> check result code and return proper error code + +out: + HIF_SDIO_DBG_FUNC("end!\n"); + return ret; +} /* end of mtk_wcn_hif_sdio_client_unreg() */ + +/*! + * \brief + * + * detailed descriptions + * + * \param ctx client's context variable + * + * \retval 0 register successfully + * \retval < 0 list error code here + */ +INT32 mtk_wcn_hif_sdio_writeb ( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + UINT32 offset, + UINT8 vb + ) +{ +#if HIF_SDIO_UPDATE + INT32 ret; + struct sdio_func* func; +#else + INT32 ret = -HIF_SDIO_ERR_FAIL; + int probe_index = -1; + struct sdio_func* func = 0; +#endif + + HIF_SDIO_DBG_FUNC("start!\n"); + + //4 <1> check if ctx is valid, registered, and probed +#if HIF_SDIO_UPDATE + ret = -HIF_SDIO_ERR_FAIL; + func = hif_sdio_ctx_to_func(ctx); + if (!func) { + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } +#else + probe_index = CLTCTX_IDX(ctx); + if( probe_index < 0 ) /* the function has not been probed */ + { + HIF_SDIO_WARN_FUNC("can't find client in probed list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } + else + { + if ( g_hif_sdio_probed_func_list[probe_index].clt_idx < 0 ) /* the client has not been registered */ + { + HIF_SDIO_WARN_FUNC("can't find client in registered list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } + } + func = g_hif_sdio_probed_func_list[probe_index].func; +#endif + + //4 <1.1> check if input parameters are valid + + //4 <2> + sdio_claim_host(func); + sdio_writeb(func, vb, offset, &ret); + sdio_release_host(func); + + //4 <3> check result code and return proper error code + +out: + HIF_SDIO_DBG_FUNC("end!\n"); + return ret; +} /* end of mtk_wcn_hif_sdio_client_unreg() */ + +/*! + * \brief + * + * detailed descriptions + * + * \param ctx client's context variable + * + * \retval 0 register successfully + * \retval < 0 list error code here + */ +INT32 mtk_wcn_hif_sdio_readl ( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + UINT32 offset, + PUINT32 pvl + ) +{ +#if HIF_SDIO_UPDATE + INT32 ret; + struct sdio_func* func; +#else + INT32 ret = -HIF_SDIO_ERR_FAIL; + int probe_index = -1; + struct sdio_func* func = 0; +#endif + + HIF_SDIO_DBG_FUNC("start!\n"); + HIF_SDIO_ASSERT( pvl ); + + //4 <1> check if ctx is valid, registered, and probed +#if HIF_SDIO_UPDATE + ret = -HIF_SDIO_ERR_FAIL; + func = hif_sdio_ctx_to_func(ctx); + if (!func) { + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } +#else + probe_index = CLTCTX_IDX(ctx); + if( probe_index < 0 ) /* the function has not been probed */ + { + HIF_SDIO_WARN_FUNC("can't find client in probed list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } + else + { + if ( g_hif_sdio_probed_func_list[probe_index].clt_idx < 0 ) /* the client has not been registered */ + { + HIF_SDIO_WARN_FUNC("can't find client in registered list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } + } + func = g_hif_sdio_probed_func_list[probe_index].func; +#endif + //4 <1.1> check if input parameters are valid + + //4 <2> + sdio_claim_host(func); + *pvl = sdio_readl(func, offset, &ret); + sdio_release_host(func); + + //4 <3> check result code and return proper error code + +out: + HIF_SDIO_DBG_FUNC("end!\n"); + return ret; +} /* end of mtk_wcn_hif_sdio_client_unreg() */ + +/*! + * \brief + * + * detailed descriptions + * + * \param ctx client's context variable + * + * \retval 0 register successfully + * \retval < 0 list error code here + */ +INT32 mtk_wcn_hif_sdio_writel ( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + UINT32 offset, + UINT32 vl + ) +{ +#if HIF_SDIO_UPDATE + INT32 ret; + struct sdio_func* func; +#else + INT32 ret = -HIF_SDIO_ERR_FAIL; + int probe_index = -1; + struct sdio_func* func = 0; +#endif + + HIF_SDIO_DBG_FUNC("start!\n"); + + //4 <1> check if ctx is valid, registered, and probed +#if HIF_SDIO_UPDATE + ret = -HIF_SDIO_ERR_FAIL; + func = hif_sdio_ctx_to_func(ctx); + if (!func) { + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } +#else + probe_index = CLTCTX_IDX(ctx); + if( probe_index < 0 ) /* the function has not been probed */ + { + HIF_SDIO_WARN_FUNC("can't find client in probed list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } + else + { + if ( g_hif_sdio_probed_func_list[probe_index].clt_idx < 0 ) /* the client has not been registered */ + { + HIF_SDIO_WARN_FUNC("can't find client in registered list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } + } + func = g_hif_sdio_probed_func_list[probe_index].func; +#endif + //4 <1.1> check if input parameters are valid + + //4 <2> + sdio_claim_host(func); + sdio_writel(func, vl, offset, &ret); + sdio_release_host(func); + + //4 <3> check result code and return proper error code + +out: + HIF_SDIO_DBG_FUNC("end!\n"); + return ret; +} /* end of mtk_wcn_hif_sdio_client_unreg() */ + +/*! + * \brief + * + * detailed descriptions + * + * \param ctx client's context variable + * + * \retval 0 register successfully + * \retval < 0 list error code here + */ +INT32 mtk_wcn_hif_sdio_read_buf ( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + UINT32 offset, + PUINT32 pbuf, + UINT32 len + ) +{ +#if HIF_SDIO_UPDATE + INT32 ret; + struct sdio_func* func; +#else + INT32 ret = -HIF_SDIO_ERR_FAIL; + int probe_index = -1; + struct sdio_func* func = 0; +#endif + + HIF_SDIO_DBG_FUNC("start!\n"); + HIF_SDIO_ASSERT( pbuf ); + + //4 <1> check if ctx is valid, registered, and probed +#if HIF_SDIO_UPDATE + ret = -HIF_SDIO_ERR_FAIL; + func = hif_sdio_ctx_to_func(ctx); + if (!func) { + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } +#else + probe_index = CLTCTX_IDX(ctx); + if( probe_index < 0 ) /* the function has not been probed */ + { + HIF_SDIO_WARN_FUNC("can't find client in probed list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } + else + { + if ( g_hif_sdio_probed_func_list[probe_index].clt_idx < 0 ) /* the client has not been registered */ + { + HIF_SDIO_WARN_FUNC("can't find client in registered list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } + } + func = g_hif_sdio_probed_func_list[probe_index].func; +#endif + //4 <1.1> check if input parameters are valid + + //4 <2> + sdio_claim_host(func); + ret = sdio_readsb(func, pbuf, offset, len); + sdio_release_host(func); + + //4 <3> check result code and return proper error code + +out: + HIF_SDIO_DBG_FUNC("end!\n"); + return ret; +} /* end of mtk_wcn_hif_sdio_read_buf() */ + + +/*! + * \brief + * + * detailed descriptions + * + * \param ctx client's context variable + * + * \retval 0 register successfully + * \retval < 0 list error code here + */ +INT32 mtk_wcn_hif_sdio_write_buf ( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + UINT32 offset, + PUINT32 pbuf, + UINT32 len + ) +{ +#if HIF_SDIO_UPDATE + INT32 ret; + struct sdio_func* func; +#else + INT32 ret = -HIF_SDIO_ERR_FAIL; + int probe_index = -1; + struct sdio_func* func = 0; +#endif + + HIF_SDIO_DBG_FUNC("start!\n"); + HIF_SDIO_ASSERT( pbuf ); + + //4 <1> check if ctx is valid, registered, and probed +#if HIF_SDIO_UPDATE + ret = -HIF_SDIO_ERR_FAIL; + func = hif_sdio_ctx_to_func(ctx); + if (!func) { + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } +#else + probe_index = CLTCTX_IDX(ctx); + if( probe_index < 0 ) /* the function has not been probed */ + { + HIF_SDIO_WARN_FUNC("can't find client in probed list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } + else + { + if ( g_hif_sdio_probed_func_list[probe_index].clt_idx < 0 ) /* the client has not been registered */ + { + HIF_SDIO_WARN_FUNC("can't find client in registered list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } + } + func = g_hif_sdio_probed_func_list[probe_index].func; +#endif + //4 <1.1> check if input parameters are valid + + //4 <2> + sdio_claim_host(func); + ret = sdio_writesb(func, offset, pbuf, len); + sdio_release_host(func); + + //4 <3> check result code and return proper error code + +out: + HIF_SDIO_DBG_FUNC("ret(%d) end!\n", ret); + + return ret; +} /* end of mtk_wcn_hif_sdio_write_buf() */ + +/*! + * \brief store client driver's private data function. + * + * + * \param clent's MTK_WCN_HIF_SDIO_CLTCTX. + * + * \retval none. + */ +void mtk_wcn_hif_sdio_set_drvdata( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + void* private_data_p + ) +{ + UINT8 probed_idx = CLTCTX_IDX(ctx); + + if (unlikely(!CLTCTX_IDX_VALID(probed_idx))) { /* invalid index in CLTCTX */ + HIF_SDIO_WARN_FUNC("invalid idx in ctx(0x%x), private_data_p not stored!\n", ctx); + } + else { + /* store client driver's private data to dev driver */ + g_hif_sdio_probed_func_list[probed_idx].private_data_p = private_data_p; + HIF_SDIO_DBG_FUNC("private_data_p(0x%p) for ctx(0x%x) probed idx(%d) stored!\n", + private_data_p, ctx, probed_idx); + } +} + +/*! + * \brief get client driver's private data function. + * + * + * \param clent's MTK_WCN_HIF_SDIO_CLTCTX. + * + * \retval private data pointer. + */ +void* mtk_wcn_hif_sdio_get_drvdata( + MTK_WCN_HIF_SDIO_CLTCTX ctx + ) +{ + UINT8 probed_idx = CLTCTX_IDX(ctx); + + /* get client driver's private data to dev driver */ + if (likely(CLTCTX_IDX_VALID(probed_idx))) + { + return g_hif_sdio_probed_func_list[probed_idx].private_data_p; + } + else + { + /* invalid index in CLTCTX */ + HIF_SDIO_WARN_FUNC("invalid idx in ctx(0x%x), return null!\n", ctx); + return NULL; + } +} + +/*! + * \brief control stp/wifi on/off from wmt. + * + * + * \param (1)control function type, (2)on/off control. + * + * \retval (1)control results ,(2)unknow type: -5. + * \retval 0:success, -11:not probed, -12:already on, -13:not registered, other errors. + */ +INT32 +mtk_wcn_hif_sdio_wmt_control ( + WMT_SDIO_FUNC_TYPE func_type, + MTK_WCN_BOOL is_on + ) +{ + // TODO:[FixMe][George]: return value of this function shall distinguish + // 1) not probed by mmc_core yet or + // 2) probed by mmc_core but init fail... + switch (func_type) { + case WMT_SDIO_FUNC_STP: + if (is_on == MTK_WCN_BOOL_TRUE) { + return hif_sdio_stp_on(); + } + else { + return hif_sdio_stp_off(); + } + break; + + case WMT_SDIO_FUNC_WIFI: + if (is_on == MTK_WCN_BOOL_TRUE) { + return hif_sdio_wifi_on(); + } + else { + return hif_sdio_wifi_off(); + } + break; + + default: + HIF_SDIO_WARN_FUNC("unknown type(%d)\n", func_type); + return HIF_SDIO_ERR_INVALID_PARAM; + } +} + +/*! + * \brief ??? + * + * \detail ??? + * + * \param ctx a context provided by client driver + * \param struct device ** ??? + * + * \retval none + */ +void mtk_wcn_hif_sdio_get_dev( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + struct device **dev + ) +{ +#if HIF_SDIO_UPDATE + struct sdio_func* func; +#else + UINT8 probe_index = CLTCTX_IDX(ctx); +#endif + +#if HIF_SDIO_UPDATE + *dev = NULL; //ensure we does not return any invalid value back. + func = hif_sdio_ctx_to_func(ctx); + if (unlikely(!func)) { + HIF_SDIO_WARN_FUNC("no valid *func with ctx(0x%x)\n", ctx); + return; + } + else { + *dev = &(func->dev); + HIF_SDIO_DBG_FUNC("return *dev(0x%p) for ctx(0x%x)\n", *dev, ctx); + } +#else + if (probe_index < 0) { + HIF_SDIO_WARN_FUNC("func not probed, probe_index = %d", probe_index); + return; + } + else{ + *dev = &g_hif_sdio_probed_func_list[probe_index].func->dev; + } +#endif +} + +/*! + * \brief enable irq handling for client function driver + * + * \detail ??? + * + * \param ctx a context provided by client driver + * \param struct device ** ??? + * + * \retval none + */ +void mtk_wcn_hif_sdio_enable_irq( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + MTK_WCN_BOOL enable + ) +{ + UINT8 probed_idx = CLTCTX_IDX(ctx); + + if (unlikely(!CLTCTX_IDX_VALID(probed_idx))) { /* invalid index in CLTCTX */ + HIF_SDIO_WARN_FUNC("invalid idx in ctx(0x%x), sdio_irq no change\n", ctx); + return; + } + + /* store client driver's private data to dev driver */ + g_hif_sdio_probed_func_list[probed_idx].sdio_irq_enabled = enable; + smp_wmb(); + HIF_SDIO_INFO_FUNC("ctx(0x%x) sdio irq enable(%d)\n", + ctx, (MTK_WCN_BOOL_FALSE == enable) ? 0 : 1); + +} + +/*! + * \brief client's probe() function. + * + * + * \param work queue structure. + * + * \retval none. + */ +static int hif_sdio_clt_probe_func ( + MTK_WCN_HIF_SDIO_REGISTINFO *registinfo_p, + INT8 probe_idx + ) +{ + UINT16 card_id = 0; + UINT16 func_num = 0; + UINT16 blk_sz = 0; + int ret; + + HIF_SDIO_DBG_FUNC("start!\n"); + HIF_SDIO_ASSERT( registinfo_p ); + if (!registinfo_p) { + HIF_SDIO_WARN_FUNC("registinfo_p NULL!!!\n"); + return -1; + } + + /* special case handling: if the clt's unregister is called during probe procedures */ + if ( !registinfo_p->func_info || !registinfo_p->sdio_cltinfo) { + HIF_SDIO_WARN_FUNC("client's registinfo_p is cleared !!!\n"); + return -1; + } + + card_id = registinfo_p->func_info->card_id; + func_num = registinfo_p->func_info->func_num; + blk_sz = registinfo_p->func_info->blk_sz; + ret = registinfo_p->sdio_cltinfo->hif_clt_probe( CLTCTX(card_id, func_num, blk_sz, probe_idx),\ + registinfo_p->func_info ); + + HIF_SDIO_INFO_FUNC("clt_probe_func card_id(%x) func_num(%x) blk_sz(%d) prob_idx(%x) ret(%d) %s\n", + card_id, func_num, blk_sz, probe_idx, ret, (ret) ? "fail" : "ok"); + + return ret; +} + +/*! + * \brief client's probe() worker. + * + * + * \param work queue structure. + * + * \retval none. + */ +static void hif_sdio_clt_probe_worker( + struct work_struct *work + ) +{ + MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO *clt_worker_info_p = 0; + UINT16 card_id = 0; + UINT16 func_num = 0; + UINT16 blk_sz = 0; + INT8 prob_idx = 0; + + HIF_SDIO_DBG_FUNC("start!\n"); + + HIF_SDIO_ASSERT( work ); + + /* get client's information */ + clt_worker_info_p = container_of( work, MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO, probe_work ); + HIF_SDIO_ASSERT( clt_worker_info_p ); + HIF_SDIO_ASSERT( clt_worker_info_p->registinfo_p ); + + /* special case handling: if the clt's unregister is called during probe procedures */ + if ( (clt_worker_info_p->registinfo_p->func_info == 0) || (clt_worker_info_p->registinfo_p->sdio_cltinfo==0) ) + { + HIF_SDIO_WARN_FUNC("client's registinfo_p is cleared !!!\n"); + vfree( clt_worker_info_p ); + return; + } + + card_id = clt_worker_info_p->registinfo_p->func_info->card_id; + func_num = clt_worker_info_p->registinfo_p->func_info->func_num; + blk_sz = clt_worker_info_p->registinfo_p->func_info->blk_sz; + prob_idx = clt_worker_info_p->probe_idx; + + /* Execute client's probe() func */ + clt_worker_info_p->registinfo_p->sdio_cltinfo->hif_clt_probe( CLTCTX(card_id, func_num, blk_sz, prob_idx),\ + clt_worker_info_p->registinfo_p->func_info ); + + vfree( clt_worker_info_p ); + + HIF_SDIO_DBG_FUNC("card_id(0x%x) func_num(0x%x) blk_sz(0x%x) prob_idx(0x%x)\n", card_id, func_num, blk_sz, prob_idx); + HIF_SDIO_DBG_FUNC("end!\n"); +} + +/*! + * \brief client's probe() worker. + * + * + * \param work queue structure. + * + * \retval none. + */ +static void +hif_sdio_dump_probe_list (void) +{ + int i; + + HIF_SDIO_DBG_FUNC("== DUMP probed list start ==\n"); + + for (i = 0; i < CFG_CLIENT_COUNT; i++) { + if (g_hif_sdio_probed_func_list[i].func) { + HIF_SDIO_DBG_FUNC("index(%d) func(0x%p) clt_idx(%d)\n", + i, g_hif_sdio_probed_func_list[i].func, + g_hif_sdio_probed_func_list[i].clt_idx); + + HIF_SDIO_DBG_FUNC("vendor(0x%x) device(0x%x) num(0x%x) state(%d)\n", + g_hif_sdio_probed_func_list[i].func->vendor, + g_hif_sdio_probed_func_list[i].func->device, + g_hif_sdio_probed_func_list[i].func->num, + g_hif_sdio_probed_func_list[i].on_by_wmt); + + } + } + + HIF_SDIO_DBG_FUNC("== DUMP probed list end ==\n"); +} + + +/*! + * \brief Initialize g_hif_sdio_probed_func_list + * + * + * \param index of g_hif_sdio_probed_func_list. + * + * \retval none. + */ +static void hif_sdio_init_probed_list( + INT32 index + ) +{ + if ( (index >= 0) && (index < CFG_CLIENT_COUNT) ) + { + /* probed spin lock */ + spin_lock_bh( &g_hif_sdio_lock_info.probed_list_lock ); + g_hif_sdio_probed_func_list[index].func = 0; + g_hif_sdio_probed_func_list[index].clt_idx = -1; + g_hif_sdio_probed_func_list[index].private_data_p = 0; + g_hif_sdio_probed_func_list[index].on_by_wmt = MTK_WCN_BOOL_FALSE; + /* probed spin unlock */ + spin_unlock_bh( &g_hif_sdio_lock_info.probed_list_lock ); + } + else + { + HIF_SDIO_ERR_FUNC("index is out of g_hif_sdio_probed_func_list[] boundary!\n"); + } +} + + +/*! + * \brief Initialize g_hif_sdio_clt_drv_list + * + * + * \param index of g_hif_sdio_clt_drv_list. + * + * \retval none. + */ +static void hif_sdio_init_clt_list( + INT32 index + ) +{ + // client list spin lock + spin_lock_bh( &g_hif_sdio_lock_info.clt_list_lock ); + if ( (index >= 0) && (index < CFG_CLIENT_COUNT) ) + { + g_hif_sdio_clt_drv_list[index].sdio_cltinfo = 0; + g_hif_sdio_clt_drv_list[index].func_info = 0; + } + else + { + HIF_SDIO_ERR_FUNC("index is out of g_hif_sdio_clt_drv_list[] boundary!\n"); + } + // client list spin unlock + spin_unlock_bh( &g_hif_sdio_lock_info.clt_list_lock ); +} + + +/*! + * \brief find matched g_hif_sdio_probed_func_list index from sdio function handler + * + * + * \param sdio function handler + * + * \retval -1 index not found + * \retval >= 0 return found index + */ +static int hif_sdio_find_probed_list_index_by_func( + struct sdio_func* func + ) +{ + int i = 0; + + HIF_SDIO_ASSERT( func ); + + for( i=0; i= 0 return found index + */ +static int hif_sdio_find_probed_list_index_by_id_func( + UINT16 vendor, + UINT16 device, + UINT16 func_num + ) +{ + int i; + for (i = 0; i < CFG_CLIENT_COUNT; i++) { + if (g_hif_sdio_probed_func_list[i].func) { + HIF_SDIO_DBG_FUNC("probed entry: vendor(0x%x) device(0x%x) num(0x%x)\n", + g_hif_sdio_probed_func_list[i].func->vendor, + g_hif_sdio_probed_func_list[i].func->device, + g_hif_sdio_probed_func_list[i].func->num); + } + } + for (i = 0; i < CFG_CLIENT_COUNT; i++) { + if (!g_hif_sdio_probed_func_list[i].func) { + continue; + } + else if ( (g_hif_sdio_probed_func_list[i].func->vendor == vendor) && + (g_hif_sdio_probed_func_list[i].func->device == device) && + (g_hif_sdio_probed_func_list[i].func->num == func_num) ) + { + return i; + } + } + + if (i == CFG_CLIENT_COUNT ) { + /* + printk(KERN_INFO DRV_NAME "Cannot find vendor:0x%x, device:0x%x, func_num:0x%x, i=%d\n", + vendor, device, func_num, i); + */ + /* client func has not been probed */ + return -1; + } + return -1; +} + +/*! + * \brief find matched g_hif_sdio_clt_drv_list index + * + * find the matched g_hif_sdio_clt_drv_list index from card_id and function number. + * + * \param vendor id, device id, and function number of the sdio card + * + * \retval -1 index not found + * \retval >= 0 return found index + */ +static int hif_sdio_find_clt_list_index ( + UINT16 vendor, + UINT16 device, + UINT16 func_num + ) +{ + int i = 0; + + for( i=0; imanf_id == vendor ) &&\ + (g_hif_sdio_clt_drv_list[i].func_info->card_id == device ) &&\ + (g_hif_sdio_clt_drv_list[i].func_info->func_num == func_num ) ) + { + return i; + } + } + } + + return -1; +} + + +/*! + * \brief check if the vendor, device ids are supported in mtk_sdio_id_tbl. + * + * + * \param vendor id and device id of the sdio card + * + * \retval (-HIF_SDIO_ERR_FAIL) vendor, device ids are not suppported + * \retval HIF_SDIO_ERR_SUCCESS vendor, device ids are suppported + */ +static int hif_sdio_check_supported_sdio_id( + UINT16 vendor, + UINT16 device + ) +{ + int i = 0; + + for ( i=0; imanf_id == vendor ) &&\ + ( g_hif_sdio_clt_drv_list[i].func_info->card_id == device ) &&\ + ( g_hif_sdio_clt_drv_list[i].func_info->func_num == func_num ) ) + { + return (-HIF_SDIO_ERR_DUPLICATED); /* duplicated */ + } + } + } + return HIF_SDIO_ERR_SUCCESS; /* Not duplicated */ +} + + +/*! + * \brief Add the client info into g_hif_sdio_clt_drv_list. + * + * + * \param [output] client's index pointer. + * \param MTK_WCN_HIF_SDIO_CLTINFO of client's contex. + * + * \retval (-HIF_SDIO_ERR_FAIL) Add to clt_list successfully + * \retval HIF_SDIO_ERR_SUCCESS Add to clt_list failed (buffer is full) + */ +static int hif_sdio_add_clt_list( + INT32* clt_index_p, + const MTK_WCN_HIF_SDIO_CLTINFO *pinfo, + UINT32 tbl_index + ) +{ + int i = 0; + + HIF_SDIO_ASSERT( clt_index_p ); + HIF_SDIO_ASSERT( pinfo ); + + for( i=0; ifunc_tbl[tbl_index]); + g_hif_sdio_clt_drv_list[i].sdio_cltinfo = pinfo; + // client list spin unlock + spin_unlock_bh( &g_hif_sdio_lock_info.clt_list_lock ); + *clt_index_p = i; + return HIF_SDIO_ERR_SUCCESS; /* Add to client list successfully */ + } + // client list spin unlock + spin_unlock_bh( &g_hif_sdio_lock_info.clt_list_lock ); + } + return (-HIF_SDIO_ERR_FAIL); /* Add to client list failed (buffer is full) */ +} + + +/*! + * \brief hif_sdio probe function + * + * hif_sdio probe function called by mmc driver when any matched SDIO function + * is detected by it. + * + * \param func + * \param id + * + * \retval 0 register successfully + * \retval < 0 list error code here + */ +static int hif_sdio_probe ( + struct sdio_func *func, + const struct sdio_device_id *id + ) +{ + int ret = 0; + int i = 0; + MTK_WCN_HIF_SDIO_PROBEINFO* hif_sdio_probed_funcp = 0; + INT32 probe_index = -1; +#if 0 + INT32 clt_index = -1; + MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO *clt_probe_worker_info = 0; +#endif + + HIF_SDIO_INFO_FUNC("start!\n"); + HIF_SDIO_ASSERT( func ); + + //4 <0> display debug information + HIF_SDIO_INFO_FUNC("vendor(0x%x) device(0x%x) num(0x%x)\n", func->vendor, func->device, func->num); + for (i = 0;i < func->card->num_info;i++) { + HIF_SDIO_INFO_FUNC("card->info[%d]: %s\n", i, func->card->info[i]); + } + + //4 <1> Check if this is supported by us (mtk_sdio_id_tbl) + ret = hif_sdio_check_supported_sdio_id( func->vendor, func->device ); + if (ret) { + HIF_SDIO_WARN_FUNC("vendor id and device id of sdio_func are not supported in mtk_sdio_id_tbl!\n"); + goto out; + } + + //4 <2> Add this struct sdio_func *func to g_hif_sdio_probed_func_list + for( i=0; ifunc = func; + hif_sdio_probed_funcp->clt_idx = hif_sdio_find_clt_list_index(func->vendor, func->device, func->num); + hif_sdio_probed_funcp->on_by_wmt = MTK_WCN_BOOL_FALSE; + /* probed spin unlock */ + spin_unlock_bh( &g_hif_sdio_lock_info.probed_list_lock ); + probe_index = i; + break; + } + else + { + /* probed spin unlock */ + spin_unlock_bh( &g_hif_sdio_lock_info.probed_list_lock ); + } + } + if ( (probe_index < 0) || (probe_index >= CFG_CLIENT_COUNT) ) + { + HIF_SDIO_ERR_FUNC("probe function list if full!\n"); + goto out; + } + + //4 <3> Initialize this function + if ( g_hif_sdio_probed_func_list[probe_index].clt_idx < 0 ) + { + for( i=0; imanf_id, g_hif_sdio_clt_drv_list[i].func_info->card_id, g_hif_sdio_clt_drv_list[i].func_info->func_num ); + if ( (g_hif_sdio_clt_drv_list[i].func_info->manf_id == g_hif_sdio_probed_func_list[probe_index].func->vendor)&&\ + (g_hif_sdio_clt_drv_list[i].func_info->card_id == g_hif_sdio_probed_func_list[probe_index].func->device)&&\ + (g_hif_sdio_clt_drv_list[i].func_info->func_num == g_hif_sdio_probed_func_list[probe_index].func->num) ) + { + g_hif_sdio_probed_func_list[probe_index].clt_idx = i; + // client list spin unlock + spin_unlock_bh( &g_hif_sdio_lock_info.clt_list_lock ); + break; + } + else + { + // client list spin unlock + spin_unlock_bh( &g_hif_sdio_lock_info.clt_list_lock ); + } + } + HIF_SDIO_INFO_FUNC("map to g_hif_sdio_clt_drv_list[] done: %d\n", g_hif_sdio_probed_func_list[probe_index].clt_idx ); + } + + //4 <3.1> enable this function + sdio_claim_host(func); + ret = sdio_enable_func(func); + sdio_release_host(func); + if (ret) { + HIF_SDIO_ERR_FUNC("sdio_enable_func failed!\n"); + goto out; + } + + //4 <3.2> set block size according to the table storing function characteristics + if ( hif_sdio_probed_funcp == 0 ) + { + HIF_SDIO_ERR_FUNC("hif_sdio_probed_funcp is null!\n"); + goto out; + } + if ( hif_sdio_probed_funcp->clt_idx >= 0 ) /* The clt contex has been registed */ + { + sdio_claim_host(func); + ret = sdio_set_block_size(func, g_hif_sdio_clt_drv_list[hif_sdio_probed_funcp->clt_idx].func_info->blk_sz); + sdio_release_host(func); + } + else /* The clt contex has not been registed */ + { + sdio_claim_host(func); + ret = sdio_set_block_size(func, HIF_DEFAULT_BLK_SIZE); + sdio_release_host(func); + } + if (ret) { + HIF_SDIO_ERR_FUNC("set sdio block size failed!\n"); + goto out; + } + + HIF_SDIO_INFO_FUNC("cur_blksize(%d) max(%d), host max blk_size(%d) blk_count(%d)\n", + func->cur_blksize, func->max_blksize, + func->card->host->max_blk_size, func->card->host->max_blk_count + ); + + // TODO:[ChangeFeature][George]: explain why this block is marked +#if 0 + //4 <3.3> claim irq for this function + sdio_claim_host(func); + ret = sdio_claim_irq(func, hif_sdio_irq); + sdio_release_host(func); + printk(KERN_INFO "sdio_claim_irq ret=%d\n", ret); + + //4 <3.4> If this struct sdio_func *func is supported by any driver in + //4 g_hif_sdio_clt_drv_list, schedule another task to call client's .hif_clt_probe() + if ( (clt_index = g_hif_sdio_probed_func_list[probe_index].clt_idx) >= 0 ) /* the function has been registered */ + { + /* use worker thread to perform the client's .hif_clt_probe() */ + clt_probe_worker_info = vmalloc( sizeof(MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO) ); + INIT_WORK( &clt_probe_worker_info->probe_work, hif_sdio_clt_probe_worker ); + clt_probe_worker_info->registinfo_p = &g_hif_sdio_clt_drv_list[clt_index]; + clt_probe_worker_info->probe_idx = probe_index; + schedule_work( &clt_probe_worker_info->probe_work ); + } +#endif + + hif_sdio_dump_probe_list(); + +out: + //4 error handling + return ret; +} + + +/*! + * \brief hif_sdio remove function + * + * hif_sdio probe function called by mmc driver when the probed func should be + * removed. + * + * \param func + * + */ +static void hif_sdio_remove ( + struct sdio_func *func + ) +{ + int probed_list_index = 0; +#if 0 + int registed_list_index = 0; +#endif + + HIF_SDIO_INFO_FUNC("start!\n"); + HIF_SDIO_ASSERT( func ); + + //4 <1> check input parameter is valid and has been probed previously + if (func == NULL) { + HIF_SDIO_ERR_FUNC("func null(%p)\n", func); + return; + } + + //4 <2> if this function has been initialized by any client driver, + //4 call client's .hif_clt_remove() call back in THIS context. + probed_list_index = hif_sdio_find_probed_list_index_by_func( func ); + if ( probed_list_index < 0 ) + { + HIF_SDIO_WARN_FUNC("sdio function pointer is not in g_hif_sdio_probed_func_list!\n"); + return; + } +#if 0 + registed_list_index = g_hif_sdio_probed_func_list[probed_list_index].clt_idx; + if ( registed_list_index >= 0 ) + { + g_hif_sdio_clt_drv_list[registed_list_index].sdio_cltinfo->hif_clt_remove( CLTCTX(func->device, func->num,\ + func->cur_blksize, probed_list_index) ); + } +#endif + + //4 <3> mark this function as de-initialized and invalidate client's context + hif_sdio_init_probed_list(probed_list_index); + +#if 0 + //4 <4> release irq for this function + sdio_claim_host(func); + sdio_release_irq(func); + sdio_release_host(func); +#endif + + //4 <5> disable this function + sdio_claim_host(func); + sdio_disable_func(func); + sdio_release_host(func); + + //4 <6> mark this function as removed + + HIF_SDIO_INFO_FUNC("sdio func(0x%p) is removed successfully!\n", func); +} + +/*! + * \brief hif_sdio interrupt handler + * + * detailed descriptions + * + * \param ctx client's context variable + * + */ +static void hif_sdio_irq ( + struct sdio_func *func + ) +{ + int probed_list_index = -1; + int registed_list_index = -1; + + HIF_SDIO_DBG_FUNC("start!\n"); + HIF_SDIO_DBG_FUNC("add by zhiguo%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"); + //4 <1> check if func is valid + HIF_SDIO_ASSERT( func ); + + //4 <2> if func has valid corresponding hif_sdio client's context, mark it + //4 host-locked, use it to call client's .hif_clt_irq() callback function in + //4 THIS context. + probed_list_index = hif_sdio_find_probed_list_index_by_func( func ); + if ( (probed_list_index < 0) || (probed_list_index >= CFG_CLIENT_COUNT) ) + { + HIF_SDIO_ERR_FUNC("probed_list_index not found!\n"); + return; + } + + registed_list_index = g_hif_sdio_probed_func_list[probed_list_index].clt_idx; +// g_hif_sdio_probed_func_list[probed_list_index].interrupted = MTK_WCN_BOOL_TRUE; + if ( (registed_list_index >= 0) + && (registed_list_index < CFG_CLIENT_COUNT) ) { + g_hif_sdio_clt_drv_list[registed_list_index].sdio_cltinfo->hif_clt_irq( CLTCTX(func->device,\ + func->num, func->cur_blksize, probed_list_index) ); + } + else { + //4 <3> if func has no VALID hif_sdio client's context, release irq for this + //4 func and mark it in g_hif_sdio_probed_func_list (remember: donnot claim host in irq contex). + HIF_SDIO_WARN_FUNC("release irq (func:0x%p) v(0x%x) d(0x%x) n(0x%x)\n", + func, func->vendor, func->device, func->num); + sdio_release_irq(func); + } + + return; +} + +/*! + * \brief hif_sdio init function + * + * detailed descriptions + * + * \retval + */ +static int __init hif_sdio_init(void) +{ + int ret = 0; + INT32 i = 0; + + HIF_SDIO_INFO_FUNC("start!\n"); + + //4 <1> init all private variables + /* init reference count to 0 */ + gRefCount = 0; + + /* init spin lock information */ + spin_lock_init( &g_hif_sdio_lock_info.probed_list_lock ); + spin_lock_init( &g_hif_sdio_lock_info.clt_list_lock ); + + /* init probed function list and g_hif_sdio_clt_drv_list */ + for ( i=0; i register to mmc driver + ret = sdio_register_driver(&mtk_sdio_client_drv); + HIF_SDIO_INFO_FUNC("sdio_register_driver() ret=%d\n", ret); + + HIF_SDIO_DBG_FUNC("end!\n"); + return ret; +} + +/*! + * \brief hif_sdio init function + * + * detailed descriptions + * + * \retval + */ +static VOID __exit hif_sdio_exit(void) +{ + HIF_SDIO_INFO_FUNC("start!\n"); + + //4 <0> if client driver is not removed yet, we shall NOT be called... + + //4 <1> check reference count + if ( gRefCount !=0 ) + { + HIF_SDIO_WARN_FUNC("gRefCount=%d !!!\n", gRefCount); + } + + //4 <2> check if there is any hif_sdio-registered clients. There should be + //4 no registered client... + + //4 <3> Reregister with mmc driver. Our remove handler hif_sdio_remove() + //4 will be called later by mmc_core. Clean up driver resources there. + sdio_unregister_driver(&mtk_sdio_client_drv); + + HIF_SDIO_DBG_FUNC("end!\n"); + return; +} /* end of exitWlan() */ + +/*! + * \brief stp on by wmt (probe client driver). + * + * + * \param none. + * + * \retval 0:success, -11:not probed, -12:already on, -13:not registered, other errors. + */ +INT32 hif_sdio_stp_on( + void + ) +{ +#if 0 + MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO *clt_probe_worker_info = 0; +#endif + INT32 clt_index = -1; + INT32 probe_index = -1; + struct sdio_func *func = 0; + int ret; + int ret2; + + HIF_SDIO_INFO_FUNC("start!\n"); + + //4 <1> If stp client drv has not been probed, return error code + /* MT6620 */ + if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020B, 1)) >= 0 ) + { + goto stp_on_exist; + } + if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020C, 1)) >= 0 ) + { + goto stp_on_exist; + } + + /* MT6619 */ + if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6619, 1)) >= 0 ) + { + goto stp_on_exist; + } + + /* MT6618 */ + if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018B, 1)) >= 0 ) + { + goto stp_on_exist; + } + if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018C, 1)) >= 0 ) + { + goto stp_on_exist; + } + else + { + //4 <2> If stp client drv has not been probed, return error code + /* client func has not been probed */ + HIF_SDIO_INFO_FUNC("no supported func probed \n"); + return HIF_SDIO_ERR_NOT_PROBED; + } + +stp_on_exist: + //4 <3> If stp client drv has been on by wmt, return error code + if (MTK_WCN_BOOL_FALSE != g_hif_sdio_probed_func_list[probe_index].on_by_wmt) { + HIF_SDIO_INFO_FUNC("already on...\n"); + return HIF_SDIO_ERR_ALRDY_ON; + } + else { + g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_TRUE; + } + + if ( (clt_index = g_hif_sdio_probed_func_list[probe_index].clt_idx) >= 0 ) /* the function has been registered */ + { + /* [George] mark disabled before sdio_claim_irq(), set enabled later by + * client driver call mtk_wcn_hif_sdio_enable_irq() in their probe(). + */ + g_hif_sdio_probed_func_list[probe_index].sdio_irq_enabled = MTK_WCN_BOOL_FALSE; + smp_wmb(); + HIF_SDIO_DBG_FUNC("probe_index(%d) sdio irq enable(0)\n", probe_index); + + //4 <4> claim irq for this function + func = g_hif_sdio_probed_func_list[probe_index].func; + sdio_claim_host(func); + ret = sdio_claim_irq(func, hif_sdio_irq); + sdio_release_host(func); + if (ret) { + HIF_SDIO_WARN_FUNC("sdio_claim_irq() for stp fail(%d)\n", ret); + return ret; + } + HIF_SDIO_INFO_FUNC("sdio_claim_irq() for stp ok\n"); + + //4 <5> If this struct sdio_func *func is supported by any driver in + //4 g_hif_sdio_clt_drv_list, schedule another task to call client's .hif_clt_probe() + // TODO: [FixMe][George] WHY probe worker is removed??? +#if 1 + /* Call client's .hif_clt_probe() */ + ret = hif_sdio_clt_probe_func(&g_hif_sdio_clt_drv_list[clt_index], probe_index); + if (ret) { + HIF_SDIO_WARN_FUNC("clt_probe_func() for stp fail(%d) release irq\n", ret); + sdio_claim_host(func); + ret2 = sdio_release_irq(func); + sdio_release_host(func); + if (ret2) { + HIF_SDIO_WARN_FUNC("sdio_release_irq() for stp fail(%d)\n", ret2); + } + + g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_FALSE; + return ret; + } + HIF_SDIO_INFO_FUNC("ok!\n"); + + return 0; +#else + /* use worker thread to perform the client's .hif_clt_probe() */ + clt_probe_worker_info = vmalloc( sizeof(MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO) ); + INIT_WORK( &clt_probe_worker_info->probe_work, hif_sdio_clt_probe_worker ); + clt_probe_worker_info->registinfo_p = &g_hif_sdio_clt_drv_list[clt_index]; + clt_probe_worker_info->probe_idx = probe_index; + schedule_work( &clt_probe_worker_info->probe_work ); +#endif + } + else { + // TODO: [FixMe][George] check if clt_index is cleared in client's unregister function + HIF_SDIO_WARN_FUNC("probed but not registered yet (%d)\n", ret); + return HIF_SDIO_ERR_CLT_NOT_REG; + } +} + +/*! + * \brief stp off by wmt (remove client driver). + * + * + * \param none. + * + * \retval 0:success, -11:not probed, -12:already off, -13:not registered, other errors. + */ +INT32 hif_sdio_stp_off( + void + ) +{ + INT32 clt_index = -1; + INT32 probe_index = -1; + struct sdio_func *func = 0; + int ret = -1; + int ret2 = -1; + + HIF_SDIO_INFO_FUNC("start!\n"); + + //4 <1> If stp client drv has not been probed, return error code + /* MT6620 */ + if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020B, 1)) >= 0 ) + { + goto stp_off_exist; + } + if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020C, 1)) >= 0 ) + { + goto stp_off_exist; + } + + /* MT6619 */ + if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6619, 1)) >= 0 ) + { + goto stp_off_exist; + } + + /* MT6618 */ + if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018B, 1)) >= 0 ) + { + goto stp_off_exist; + } + if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018C, 1)) >= 0 ) + { + goto stp_off_exist; + } + else + { + //4 <2> If stp client drv has not been probed, return error code + /* client func has not been probed */ + return HIF_SDIO_ERR_NOT_PROBED; + } + +stp_off_exist: + //4 <3> If stp client drv has been off by wmt, return error code + if (MTK_WCN_BOOL_FALSE == g_hif_sdio_probed_func_list[probe_index].on_by_wmt) { + HIF_SDIO_WARN_FUNC("already off...\n"); + return HIF_SDIO_ERR_ALRDY_OFF; + } + else { + g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_FALSE; + } + +#if 0 // TODO: [FixMe][George] moved below as done in stp_on. + //4 <4> release irq for this function + func = g_hif_sdio_probed_func_list[probe_index].func; + sdio_claim_host(func); + ret = sdio_release_irq(func); + sdio_release_host(func); + if (ret) { + printk(KERN_WARNING DRV_NAME "sdio_release_irq for stp fail(%d)\n", ret); + } + else { + printk(KERN_INFO DRV_NAME "sdio_release_irq for stp ok\n"); + } +#endif + + if ( (clt_index = g_hif_sdio_probed_func_list[probe_index].clt_idx) >= 0 ) /* the function has been registered */ + { + //4 <4> release irq for this function + func = g_hif_sdio_probed_func_list[probe_index].func; + sdio_claim_host(func); + ret = sdio_release_irq(func); + sdio_release_host(func); + + if (ret) { + HIF_SDIO_WARN_FUNC("sdio_release_irq() for stp fail(%d)\n", ret); + } + else { + HIF_SDIO_INFO_FUNC("sdio_release_irq() for stp ok\n"); + } + /* [George] mark disabled after sdio_release_irq(). */ + g_hif_sdio_probed_func_list[probe_index].sdio_irq_enabled = MTK_WCN_BOOL_FALSE; + smp_wmb(); + HIF_SDIO_DBG_FUNC("probe_index(%d) sdio irq enable(0)\n", probe_index); + + //4 <5> Callback to client driver's remove() func + ret2 = g_hif_sdio_clt_drv_list[clt_index].sdio_cltinfo->hif_clt_remove( + CLTCTX(func->device, func->num, func->cur_blksize, probe_index) ); + if (ret2) { + HIF_SDIO_WARN_FUNC("clt_remove for stp fail(%d)\n", ret2); + } + else { + HIF_SDIO_INFO_FUNC("ok!\n"); + } + + return (ret + ret2); + } + else { + // TODO: [FixMe][George] check if clt_index is cleared in client's unregister function + HIF_SDIO_WARN_FUNC("probed but not registered yet (%d)\n", ret); + return HIF_SDIO_ERR_CLT_NOT_REG; + } +} + +/*! + * \brief wifi on by wmt (probe client driver). + * + * + * \param none. + * + * \retval 0:success, -11:not probed, -12:already on, -13:not registered, other errors. + */ +INT32 +hif_sdio_wifi_on (void) +{ +#if 0 + MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO *clt_probe_worker_info = 0; +#endif + INT32 clt_index = -1; + INT32 probe_index = -1; + struct sdio_func *func = 0; + int ret; + int ret2; + + HIF_SDIO_INFO_FUNC("start!\n"); + + //4 <1> If wifi client drv has not been probed, return error code + /* MT6620 */ + if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020A, 1)) >= 0 ) + { + goto wifi_on_exist; + } + if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020C, 2)) >= 0 ) + { + goto wifi_on_exist; + } + + /* MT6618 */ + if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018A, 1)) >= 0 ) + { + goto wifi_on_exist; + } + if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018C, 2)) >= 0 ) + { + goto wifi_on_exist; + } + else + { + //4 <2> If wifi client drv has not been probed, return error code + /* client func has not been probed */ + return HIF_SDIO_ERR_NOT_PROBED; + } + +wifi_on_exist: + //4 <3> If wifi client drv has been on by wmt, return error code + if (g_hif_sdio_probed_func_list[probe_index].on_by_wmt) { + HIF_SDIO_INFO_FUNC("probe_index (%d), already on...\n", probe_index); + return HIF_SDIO_ERR_ALRDY_ON; + } + + if ( (clt_index = g_hif_sdio_probed_func_list[probe_index].clt_idx) >= 0 ) /* the function has been registered */ + { + /* [George] mark disabled before sdio_claim_irq(), set enabled later by + * client driver call mtk_wcn_hif_sdio_enable_irq() in their probe(). + */ + g_hif_sdio_probed_func_list[probe_index].sdio_irq_enabled = MTK_WCN_BOOL_FALSE; + smp_wmb(); + HIF_SDIO_DBG_FUNC("probe_index(%d) sdio irq enable(0)\n", probe_index); + + //4 <4> claim irq for this function + func = g_hif_sdio_probed_func_list[probe_index].func; + sdio_claim_host(func); + ret = sdio_claim_irq(func, hif_sdio_irq); + sdio_release_host(func); + if (ret) { + HIF_SDIO_WARN_FUNC("sdio_claim_irq() for wifi fail(%d)\n", ret); + return ret; + } + HIF_SDIO_INFO_FUNC("sdio_claim_irq() for wifi ok\n"); + + //4 <5> If this struct sdio_func *func is supported by any driver in + //4 g_hif_sdio_clt_drv_list, schedule another task to call client's .hif_clt_probe() + // TODO: [FixMe][George] WHY probe worker is removed??? +#if 1 + /* Call client's .hif_clt_probe() */ + ret = hif_sdio_clt_probe_func(&g_hif_sdio_clt_drv_list[clt_index], probe_index); + if (ret) { + HIF_SDIO_WARN_FUNC("clt_probe_func() for wifi fail(%d) release irq\n", ret); + sdio_claim_host(func); + ret2 = sdio_release_irq(func); + sdio_release_host(func); + if (ret2) { + HIF_SDIO_WARN_FUNC("sdio_release_irq() for wifi fail(%d)\n", ret2); + } + + g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_FALSE; + return ret; + } + else + { + g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_TRUE; + } + HIF_SDIO_INFO_FUNC("ok!\n"); + return 0; +#else + /* use worker thread to perform the client's .hif_clt_probe() */ + clt_probe_worker_info = vmalloc( sizeof(MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO) ); + INIT_WORK( &clt_probe_worker_info->probe_work, hif_sdio_clt_probe_worker ); + clt_probe_worker_info->registinfo_p = &g_hif_sdio_clt_drv_list[clt_index]; + clt_probe_worker_info->probe_idx = probe_index; + schedule_work( &clt_probe_worker_info->probe_work ); +#endif + } + else { + // TODO: [FixMe][George] check if clt_index is cleared in client's unregister function + HIF_SDIO_WARN_FUNC("probed but not registered yet (%d)\n", ret); + return HIF_SDIO_ERR_CLT_NOT_REG; + } +} + +/*! + * \brief wifi off by wmt (remove client driver). + * + * + * \param none. + * + * \retval 0:success, -11:not probed, -12:already off, -13:not registered, other errors. + */ +INT32 hif_sdio_wifi_off( + void + ) +{ + INT32 clt_index = -1; + INT32 probe_index = -1; + struct sdio_func *func = 0; + int ret = -1; + int ret2 = -1; + + HIF_SDIO_INFO_FUNC("start!\n"); + + //4 <1> If wifi client drv has not been probed, return error code + /* MT6620 */ + if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020A, 1)) >= 0 ) + { + goto wifi_off_exist; + } + if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020C, 2)) >= 0 ) + { + goto wifi_off_exist; + } + + /* MT6618 */ + if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018A, 1)) >= 0 ) + { + goto wifi_off_exist; + } + if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018C, 2)) >= 0 ) + { + goto wifi_off_exist; + } + else + { + //4 <2> If wifi client drv has not been probed, return error code + /* client func has not been probed */ + return HIF_SDIO_ERR_NOT_PROBED; + } + +wifi_off_exist: + //4 <3> If wifi client drv has been off by wmt, return error code + if (MTK_WCN_BOOL_FALSE == g_hif_sdio_probed_func_list[probe_index].on_by_wmt) { + HIF_SDIO_WARN_FUNC("already off...\n"); + return HIF_SDIO_ERR_ALRDY_OFF; + } + else { + g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_FALSE; + } + +#if 0 // TODO: [FixMe][George] moved below as done in wifi_on. + //4 <4> release irq for this function + func = g_hif_sdio_probed_func_list[probe_index].func; + sdio_claim_host(func); + ret = sdio_release_irq(func); + sdio_release_host(func); + if (ret) { + printk(KERN_WARNING DRV_NAME "sdio_release_irq for wifi fail(%d)\n", ret); + } + else { + printk(KERN_INFO DRV_NAME "sdio_release_irq for wifi ok\n"); + } +#endif + + if ( (clt_index = g_hif_sdio_probed_func_list[probe_index].clt_idx) >= 0 ) /* the function has been registered */ + { + //4 <4> release irq for this function + func = g_hif_sdio_probed_func_list[probe_index].func; + sdio_claim_host(func); + ret = sdio_release_irq(func); + sdio_release_host(func); + if (ret) { + HIF_SDIO_WARN_FUNC("sdio_release_irq() for wifi fail(%d)\n", ret); + } + else { + HIF_SDIO_INFO_FUNC("sdio_release_irq() for wifi ok\n"); + } + /* [George] mark disabled after sdio_release_irq(). */ + g_hif_sdio_probed_func_list[probe_index].sdio_irq_enabled = MTK_WCN_BOOL_FALSE; + smp_wmb(); + HIF_SDIO_DBG_FUNC("probe_index(%d) sdio irq enable(0)\n", probe_index); + + //4 <5> Callback to client driver's remove() func + ret2 = g_hif_sdio_clt_drv_list[clt_index].sdio_cltinfo->hif_clt_remove( + CLTCTX(func->device, func->num, func->cur_blksize, probe_index) ); + if (ret2) { + HIF_SDIO_WARN_FUNC("clt_remove for wifi fail(%d)\n", ret2); + } + else { + HIF_SDIO_INFO_FUNC("ok!\n"); + } + + return (ret + ret2); + } + else { + // TODO: [FixMe][George] check if clt_index is cleared in client's unregister function + HIF_SDIO_WARN_FUNC("probed but not registered yet (%d)\n", ret); + return HIF_SDIO_ERR_CLT_NOT_REG; + } +} + +module_init(hif_sdio_init); +module_exit(hif_sdio_exit); + +EXPORT_SYMBOL(mtk_wcn_hif_sdio_client_reg); +EXPORT_SYMBOL(mtk_wcn_hif_sdio_client_unreg); +EXPORT_SYMBOL(mtk_wcn_hif_sdio_readb); +EXPORT_SYMBOL(mtk_wcn_hif_sdio_writeb); +EXPORT_SYMBOL(mtk_wcn_hif_sdio_readl); +EXPORT_SYMBOL(mtk_wcn_hif_sdio_writel); +EXPORT_SYMBOL(mtk_wcn_hif_sdio_read_buf); +EXPORT_SYMBOL(mtk_wcn_hif_sdio_write_buf); +EXPORT_SYMBOL(mtk_wcn_hif_sdio_set_drvdata); +EXPORT_SYMBOL(mtk_wcn_hif_sdio_get_drvdata); +EXPORT_SYMBOL(mtk_wcn_hif_sdio_wmt_control); +EXPORT_SYMBOL(mtk_wcn_hif_sdio_get_dev); +EXPORT_SYMBOL(mtk_wcn_hif_sdio_enable_irq); + diff --git a/drivers/mtk_wcn_combo/common/linux/hw_chrdev_test.c b/drivers/mtk_wcn_combo/common/linux/hw_chrdev_test.c new file mode 100755 index 000000000000..98f4641d9f6e --- /dev/null +++ b/drivers/mtk_wcn_combo/common/linux/hw_chrdev_test.c @@ -0,0 +1,611 @@ +/****************************************************************************** +* C O M P I L E R F L A G S +******************************************************************************* +*/ + +/****************************************************************************** +* E X T E R N A L R E F E R E N C E S +******************************************************************************* +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//for mtk +//#include +//#include +//#include +//end for mtk + +//for Ingenic +#include +#include +#include +#include +//end for Ingenic + +#include "hw_test.h" + +/****************************************************************************** +* C O N S T A N T S +******************************************************************************* +*/ +#define GPIO_PMU_PIN GPD27 +#define GPIO_RST_PIN GPD29 +#define GPIO_RTC_PIN GPD14 +#define GPIO_BGF_INT GPF20 +#define GPIO_WIF_INT GPF21 + +#define HWTEST_DEV_MAJOR 194 // never used number +#define HWTEST_DEV_NUM 1 + +/* Linux char device */ +static int HWTEST_major = HWTEST_DEV_MAJOR; +static struct cdev HWTEST_cdev; +static atomic_t HWTEST_ref_cnt = ATOMIC_INIT(0); + +unsigned char** g_read_card_info_bysdio; +unsigned char** g_test; + +UINT8 g_read_current_io_isready_from_sdio_card; +UINT16 g_read_function_blksize_from_sdio_card; +UINT32 g_read_int_from_sdio_card; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#define HWTEST_SUPPORT_PHONE 0 +#define HWTEST_SUPPORT_SDIO 1 + + +int porting_6620_sdio_card_detect() +{ + int ret = -1; + //for MTK + //ret = mt_combo_sdio_ctrl(2,1); + //end for MTK + //for Ingenic + ret = sdio_card_detect(); + //end for Ingenic + if(!ret){ + return 0; + }else{ + HWTEST_INFO_FUNC("sdio card detect fail"); + return -1; + } +} +int porting_6620_sdio_card_remove() +{ + int ret = -1; + //for MTK + //ret = mt_combo_sdio_ctrl(2,0); + //end for MTK + //for Ingenic + ret = sdio_card_remove(); + //end for Ingenic + if(!ret){ + return 0; + }else{ + HWTEST_INFO_FUNC("sdio card remove fail"); + return -1; + } +} +//end for Ingenic + +int chip_power_on(void) +{ + //int ret = -1; +#define MT6620_OFF_TIME (10) /* in ms, workable value */ +#define MT6620_RST_TIME (30) /* in ms, workable value */ +#define MT6620_STABLE_TIME (30) /* in ms, workable value */ +#define MT6620_EXT_INT_TIME (5) /* in ms, workable value */ +#define MT6620_32K_STABLE_TIME (100) /* in ms, test value */ + +#if 0 +#if (HWTEST_SUPPORT_PHONE) + /* disable pull */ + mt_set_gpio_pull_enable(GPIO_COMBO_6620_LDO_EN_PIN, GPIO_PULL_DISABLE); + /* set output */ + mt_set_gpio_dir(GPIO_COMBO_6620_LDO_EN_PIN, GPIO_DIR_OUT); + /* set gpio mode */ + mt_set_gpio_mode(GPIO_COMBO_6620_LDO_EN_PIN, GPIO_MODE_GPIO); + /* external LDO_EN high */ + mt_set_gpio_out(GPIO_COMBO_6620_LDO_EN_PIN, GPIO_OUT_ONE); +#endif + +#if (HWTEST_SUPPORT_SDIO) && (CONFIG_MTK_COMBO_SDIO_SLOT == 0) + printk(KERN_INFO "[mt6620] pull up sd0 bus(gpio169~gpio175(exclude gpio174))\n"); + mt_set_gpio_pull_enable(GPIO172, GPIO_PULL_ENABLE); //->CLK + mt_set_gpio_pull_select(GPIO172, GPIO_PULL_UP); + mt_set_gpio_pull_enable(GPIO171, GPIO_PULL_ENABLE); //->CMD + mt_set_gpio_pull_select(GPIO171, GPIO_PULL_UP); + mt_set_gpio_pull_enable(GPIO175, GPIO_PULL_ENABLE); //->DAT0 + mt_set_gpio_pull_select(GPIO175, GPIO_PULL_UP); + mt_set_gpio_pull_enable(GPIO173, GPIO_PULL_ENABLE); //->DAT1 + mt_set_gpio_pull_select(GPIO173, GPIO_PULL_UP); + mt_set_gpio_pull_enable(GPIO169, GPIO_PULL_ENABLE); //->DAT2 + mt_set_gpio_pull_select(GPIO169, GPIO_PULL_UP); + mt_set_gpio_pull_enable(GPIO170, GPIO_PULL_ENABLE); //->DAT3 + mt_set_gpio_pull_select(GPIO170, GPIO_PULL_UP); +#elif (CONFIG_MTK_COMBO_SDIO_SLOT == 1) + #error "error:MSDC1 is not reserved for MT6620 on MT6575EVB" +#elif (CONFIG_MTK_COMBO_SDIO_SLOT == 2) + printk(KERN_INFO "[mt6620] pull up sd2 bus(gpio182~187)\n"); + mt_set_gpio_pull_enable(GPIO182, GPIO_PULL_ENABLE); //->CLK + mt_set_gpio_pull_select(GPIO182, GPIO_PULL_UP); + mt_set_gpio_pull_enable(GPIO184, GPIO_PULL_ENABLE); //->CMD + mt_set_gpio_pull_select(GPIO184, GPIO_PULL_UP); + mt_set_gpio_pull_enable(GPIO186, GPIO_PULL_ENABLE); //->DAT0 + mt_set_gpio_pull_select(GPIO186, GPIO_PULL_UP); + mt_set_gpio_pull_enable(GPIO187, GPIO_PULL_ENABLE); //->DAT1 + mt_set_gpio_pull_select(GPIO187, GPIO_PULL_UP); + mt_set_gpio_pull_enable(GPIO185, GPIO_PULL_ENABLE); //->DAT2 + mt_set_gpio_pull_select(GPIO185, GPIO_PULL_UP); + mt_set_gpio_pull_enable(GPIO183, GPIO_PULL_ENABLE); //->DAT3 + mt_set_gpio_pull_select(GPIO183, GPIO_PULL_UP); +#elif (CONFIG_MTK_COMBO_SDIO_SLOT == 3) + printk(KERN_INFO "[mt6620] pull up sd3 bus (GPIO89~GPIO94)\n"); + mt_set_gpio_pull_enable(GPIO92, GPIO_PULL_ENABLE); //->CLK + mt_set_gpio_pull_select(GPIO92, GPIO_PULL_UP); + mt_set_gpio_pull_enable(GPIO91, GPIO_PULL_ENABLE); //->CMD + mt_set_gpio_pull_select(GPIO91, GPIO_PULL_UP); + mt_set_gpio_pull_enable(GPIO94, GPIO_PULL_ENABLE); //->DAT0 + mt_set_gpio_pull_select(GPIO94, GPIO_PULL_UP); + mt_set_gpio_pull_enable(GPIO90, GPIO_PULL_ENABLE); //->DAT1 + mt_set_gpio_pull_select(GPIO90, GPIO_PULL_UP); + mt_set_gpio_pull_enable(GPIO89, GPIO_PULL_ENABLE); //->DAT2 + mt_set_gpio_pull_select(GPIO89, GPIO_PULL_UP); + mt_set_gpio_pull_enable(GPIO93, GPIO_PULL_ENABLE); //->DAT3 + mt_set_gpio_pull_select(GPIO93, GPIO_PULL_UP); +#else + #error "error:unsupported CONFIG_MTK_COMBO_SDIO_SLOT" CONFIG_MTK_COMBO_SDIO_SLOT +#endif + + /* UART Mode */ + ret = mt_set_gpio_mode(GPIO_UART_URXD3_PIN, GPIO_UART_URXD3_PIN_M_URXD);//GPIO_MODE_01->GPIO_UART_URXD3_PIN_M_URXD + ret += mt_set_gpio_mode(GPIO_UART_UTXD3_PIN, GPIO_UART_UTXD3_PIN_M_UTXD);//GPIO_MODE_01->GPIO_UART_UTXD3_PIN_M_UTXD + //printk(KERN_INFO "[mt6620] set UART GPIO Mode [%d]\n", result); + + /* disable pull */ +#if (HWTEST_SUPPORT_PHONE) + mt_set_gpio_pull_enable(GPIO25, GPIO_PULL_DISABLE); +#endif + ret += mt_set_gpio_pull_enable(GPIO_COMBO_PMU_EN_PIN, GPIO_PULL_DISABLE); + ret += mt_set_gpio_pull_enable(GPIO_COMBO_RST_PIN, GPIO_PULL_DISABLE); + + /* set output */ +#if (HWTEST_SUPPORT_PHONE) + mt_set_gpio_dir(GPIO25, GPIO_DIR_OUT); +#endif + ret += mt_set_gpio_dir(GPIO_COMBO_PMU_EN_PIN, GPIO_DIR_OUT); + ret += mt_set_gpio_dir(GPIO_COMBO_RST_PIN, GPIO_DIR_OUT); + + /* set gpio mode */ +#if defined(HWTEST_SUPPORT_PHONE) + mt_set_gpio_mode(GPIO25, GPIO_MODE_GPIO); +#endif + ret += mt_set_gpio_mode(GPIO_COMBO_PMU_EN_PIN, GPIO_MODE_GPIO); + ret += mt_set_gpio_mode(GPIO_COMBO_RST_PIN, GPIO_MODE_GPIO); + + /* SYSRST_B low */ + ret += mt_set_gpio_out(GPIO_COMBO_RST_PIN, GPIO_OUT_ZERO); + /* PMU_EN low */ +#if (HWTEST_SUPPORT_PHONE) + mt_set_gpio_out(GPIO25, GPIO_OUT_ZERO); +#endif + ret += mt_set_gpio_out(GPIO_COMBO_PMU_EN_PIN, GPIO_OUT_ZERO); + + msleep(MT6620_OFF_TIME); + + /* PMU_EN high, SYSRST_B low */ +#if (HWTEST_SUPPORT_PHONE) + mt_set_gpio_out(GPIO25, GPIO_OUT_ONE); +#endif + ret += mt_set_gpio_out(GPIO_COMBO_PMU_EN_PIN, GPIO_OUT_ONE); + msleep(MT6620_RST_TIME); + + /* SYSRST_B high */ + ret += mt_set_gpio_out(GPIO_COMBO_RST_PIN, GPIO_OUT_ONE); + msleep(MT6620_STABLE_TIME); +#endif + + //for Ingenic + rtc_enable_clk32k(); + msleep(MT6620_32K_STABLE_TIME); + __gpio_as_uart2(); + msleep(30); + + //PMU_EN-->0 + __gpio_enable_pull(GPIO_PMU_PIN); + __gpio_as_output(GPIO_PMU_PIN); + __gpio_clear_pin(GPIO_PMU_PIN); + //RST-->0 + __gpio_enable_pull(GPIO_RST_PIN); + __gpio_as_output(GPIO_RST_PIN); + __gpio_clear_pin(GPIO_RST_PIN); + + msleep(MT6620_OFF_TIME); + //PMU_EN-->1 + __gpio_set_pin(GPIO_PMU); + msleep(MT6620_RST_TIME); + + __gpio_enable_pull(GPIO_RST_PIN); + __gpio_as_output(GPIO_RST_PIN); + __gpio_set_pin(GPIO_RST_PIN); + + msleep(MT6620_STABLE_TIME); + printk(KERN_INFO "[mt6620] power on \n"); + + return 0; +} + + +int chip_power_off(void) +{ + //int ret = -1; + printk(KERN_INFO "[mt6620] power off\n"); +#if 0 + /* SYSRST_B low */ + mt_set_gpio_out(GPIO_COMBO_RST_PIN, GPIO_OUT_ZERO); + /* PMU_EN low */ +#if (HWTEST_SUPPORT_PHONE) + mt_set_gpio_out(GPIO25, GPIO_OUT_ZERO); +#endif + mt_set_gpio_out(GPIO_COMBO_PMU_EN_PIN, GPIO_OUT_ZERO); + +#if (HWTEST_SUPPORT_SDIO) && (CONFIG_MTK_COMBO_SDIO_SLOT == 0) + printk(KERN_INFO "[mt6620] pull down sd0 bus(gpio169~gpio175(exclude gpio174))\n"); + mt_set_gpio_pull_enable(GPIO172, GPIO_PULL_DOWN); //->CLK + mt_set_gpio_pull_select(GPIO172, GPIO_PULL_ENABLE); + mt_set_gpio_pull_enable(GPIO171, GPIO_PULL_DOWN); //->CMD + mt_set_gpio_pull_select(GPIO171, GPIO_PULL_ENABLE); + mt_set_gpio_pull_enable(GPIO175, GPIO_PULL_DOWN); //->DAT0 + mt_set_gpio_pull_select(GPIO175, GPIO_PULL_ENABLE); + mt_set_gpio_pull_enable(GPIO173, GPIO_PULL_DOWN); //->DAT1 + mt_set_gpio_pull_select(GPIO173, GPIO_PULL_ENABLE); + mt_set_gpio_pull_enable(GPIO169, GPIO_PULL_DOWN); //->DAT2 + mt_set_gpio_pull_select(GPIO169, GPIO_PULL_ENABLE); + mt_set_gpio_pull_enable(GPIO170, GPIO_PULL_DOWN); //->DAT3 + mt_set_gpio_pull_select(GPIO170, GPIO_PULL_ENABLE); +#elif (CONFIG_MTK_COMBO_SDIO_SLOT == 1) + #error "error:MSDC1 is not reserved for MT6620 on MT6575EVB" +#elif (CONFIG_MTK_COMBO_SDIO_SLOT == 2) + printk(KERN_INFO "[mt6620] pull down sd2 bus(gpio182~187)\n"); + mt_set_gpio_pull_enable(GPIO182, GPIO_PULL_DOWN); //->CLK + mt_set_gpio_pull_select(GPIO182, GPIO_PULL_ENABLE); + mt_set_gpio_pull_enable(GPIO184, GPIO_PULL_DOWN); //->CMD + mt_set_gpio_pull_select(GPIO184, GPIO_PULL_ENABLE); + mt_set_gpio_pull_enable(GPIO186, GPIO_PULL_DOWN); //->DAT0 + mt_set_gpio_pull_select(GPIO186, GPIO_PULL_ENABLE); + mt_set_gpio_pull_enable(GPIO187, GPIO_PULL_DOWN); //->DAT1 + mt_set_gpio_pull_select(GPIO187, GPIO_PULL_ENABLE); + mt_set_gpio_pull_enable(GPIO185, GPIO_PULL_DOWN); //->DAT2 + mt_set_gpio_pull_select(GPIO185, GPIO_PULL_ENABLE); + mt_set_gpio_pull_enable(GPIO183, GPIO_PULL_DOWN); //->DAT3 + mt_set_gpio_pull_select(GPIO183, GPIO_PULL_ENABLE); +#elif (CONFIG_MTK_COMBO_SDIO_SLOT == 3) + printk(KERN_INFO "[mt6620] pull down sd3 bus (GPIO89~GPIO94)\n"); + mt_set_gpio_pull_enable(GPIO92, GPIO_PULL_DOWN); //->CLK + mt_set_gpio_pull_select(GPIO92, GPIO_PULL_ENABLE); + mt_set_gpio_pull_enable(GPIO91, GPIO_PULL_DOWN); //->CMD + mt_set_gpio_pull_select(GPIO91, GPIO_PULL_ENABLE); + mt_set_gpio_pull_enable(GPIO94, GPIO_PULL_DOWN); //->DAT0 + mt_set_gpio_pull_select(GPIO94, GPIO_PULL_ENABLE); + mt_set_gpio_pull_enable(GPIO90, GPIO_PULL_DOWN); //->DAT1 + mt_set_gpio_pull_select(GPIO90, GPIO_PULL_ENABLE); + mt_set_gpio_pull_enable(GPIO89, GPIO_PULL_DOWN); //->DAT2 + mt_set_gpio_pull_select(GPIO89, GPIO_PULL_ENABLE); + mt_set_gpio_pull_enable(GPIO93, GPIO_PULL_DOWN); //->DAT3 + mt_set_gpio_pull_select(GPIO93, GPIO_PULL_ENABLE); +#else + #error "error:unsupported CONFIG_MTK_COMBO_SDIO_SLOT" CONFIG_MTK_COMBO_SDIO_SLOT +#endif + + + //printk(KERN_INFO "[mt6620] set UART GPIO Mode output 0\n"); + ret = mt_set_gpio_mode(GPIO_UART_URXD3_PIN, GPIO_UART_URXD3_PIN_M_GPIO); + ret += mt_set_gpio_dir(GPIO_UART_URXD3_PIN, GPIO_DIR_OUT); + ret += mt_set_gpio_out(GPIO_UART_URXD3_PIN, GPIO_OUT_ZERO); + + ret += mt_set_gpio_mode(GPIO_UART_UTXD3_PIN, GPIO_UART_UTXD3_PIN_M_GPIO); + ret += mt_set_gpio_dir(GPIO_UART_UTXD3_PIN, GPIO_DIR_OUT); + ret += mt_set_gpio_out(GPIO_UART_UTXD3_PIN, GPIO_OUT_ZERO); + +#if (HWTEST_SUPPORT_PHONE) + mt_set_gpio_out(GPIO_COMBO_6620_LDO_EN_PIN, GPIO_OUT_ZERO); +#endif +#endif + //for Ingenic + printk(KERN_INFO "[mt6620] power off\n"); + __gpio_clear_pin(GPIO_RST_PIN); + __gpio_clear_pin(GPIO_PMU_PIN); + rtc_disable_clk32k(); + return 0; +} + +ssize_t HWTEST_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) +{ + return 0; +} + +ssize_t HWTEST_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + int i = 0; + char local_buf[256] = {'\0'}; + + HWTEST_INFO_FUNC("read card by sdio!\n"); + + if(!g_sdio_init_count){ + HWTEST_INFO_FUNC("sdio card still not initiliaztion yet!\n"); + return -1; + } + if(!g_read_card_info_bysdio[0][0]){ + HWTEST_INFO_FUNC("read sdio card buffer is null\n"); + return -2; + } + HWTEST_INFO_FUNC("%s,%s",g_read_card_info_bysdio[0],g_read_card_info_bysdio[1]); + sprintf(local_buf,"%s\n%s",g_read_card_info_bysdio[0],g_read_card_info_bysdio[1]); + //strncpy(local_buf,g_read_card_info_bysdio[0],strlen(g_read_card_info_bysdio[0])); + + if(copy_to_user(buf,local_buf,strlen(g_read_card_info_bysdio[0]) + 1 + strlen(g_read_card_info_bysdio[1]))){ + + HWTEST_INFO_FUNC("copy info to user error!\n"); + return -3; + } + return strlen(g_read_card_info_bysdio[0]) + strlen(g_read_card_info_bysdio[1])+1; +} + +unsigned int HWTEST_poll(struct file *filp, poll_table *wait) +{ + return 0; +} +//retval:odd is exception,even is error! +int HWTEST_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int retval = 0; + int ret; + + HWTEST_INFO_FUNC("cmd (0x%04x), arg (%d)\n", cmd, (int)arg); + + switch(cmd) { + case HWTEST_IOCTL_POWER_ON: + HWTEST_INFO_FUNC("power on!\n"); + if(g_state_flag){ + HWTEST_INFO_FUNC("already power on!\n"); + retval = 1; + }else{ + ret = chip_power_on(); + if(!ret){ + g_state_flag = 1; + HWTEST_INFO_FUNC("power on OK!\n"); + }else{ + HWTEST_INFO_FUNC("power on fail!\n"); + retval = 2; + } + } + break; + + case HWTEST_IOCTL_POWER_OFF: + HWTEST_INFO_FUNC("power off!\n"); + if(!g_state_flag){ + HWTEST_INFO_FUNC("already power off!\n"); + retval = 3; + }else{ + ret = chip_power_off(); + if(!ret){ + g_state_flag = 0; + HWTEST_INFO_FUNC("power off OK!\n"); + }else{ + HWTEST_INFO_FUNC("power off fail!\n"); + retval = 4; + } + } + break; + + case HWTEST_IOCTL_CHIP_RESET: + HWTEST_INFO_FUNC("chip reset!\n"); + if(g_state_flag){ + ret = chip_power_off(); + ret += chip_power_on(); + if(!ret){ + HWTEST_INFO_FUNC("chip reset OK!\n"); + }else{ + HWTEST_INFO_FUNC("chip rest fail!\n"); + retval = 6; + } + }else{ + HWTEST_INFO_FUNC("chip is power off now!\n"); + retval = 5; + } + break; + case HWTEST_IOCTL_SDIO_INIT: + HWTEST_INFO_FUNC("init sdio card!\n"); + if(g_sdio_init_count){ + HWTEST_INFO_FUNC("SDIO card already exist!\n"); + retval = 7; + }else{ + ret = porting_6620_sdio_card_detect(); + if(!ret){ + HWTEST_INFO_FUNC("hwtest sdio init finish!\n"); + }else{ + HWTEST_INFO_FUNC("hwtest sdio init fail!\n"); + retval = 8; + } + g_sdio_init_count = 1; + } + break; + case HWTEST_IOCTL_SDIO_REMOVE: + HWTEST_INFO_FUNC("remove sdio card!\n"); + if(!g_sdio_init_count){ + HWTEST_INFO_FUNC("sdio card not exist!\n"); + retval = 9; + }else{ + ret = porting_6620_sdio_card_remove(); + if(!ret){ + HWTEST_INFO_FUNC("hwtest sdio card remove finish!\n"); + }else{ + HWTEST_INFO_FUNC("hwtest sdio card remove fail!\n"); + retval = 10; + } + g_sdio_init_count = 0; + } + break; + case HWTEST_IOCTL_SDIO_READ_IOISREADY: + if(!g_read_current_io_isready_from_sdio_card){ + HWTEST_INFO_FUNC("sdio card current io is not ready!\n"); + retval = 11; + }else{ + if (copy_to_user((void *)arg, &g_read_current_io_isready_from_sdio_card, sizeof(g_read_current_io_isready_from_sdio_card)) < 0) { + HWTEST_INFO_FUNC("copy to user space fail!\n"); + retval = 12; + } + } + break; + case HWTEST_IOCTL_SDIO_READ_BLKSIZE: + if(!g_read_function_blksize_from_sdio_card){ + HWTEST_INFO_FUNC("sdio card current function blksize is not set!\n"); + retval = 13; + }else{ + if (copy_to_user((void *)arg, &g_read_function_blksize_from_sdio_card, sizeof(g_read_function_blksize_from_sdio_card)) < 0) { + HWTEST_INFO_FUNC("copy to user space fail!\n"); + retval = 14; + } + } + break; + case HWTEST_IOCTL_SDIO_READ_INT: + if(!g_read_int_from_sdio_card){ + HWTEST_INFO_FUNC("sdio card current register has not valuse!\n"); + retval = 15; + }else{ + if (copy_to_user((void *)arg, &g_read_int_from_sdio_card, sizeof(g_read_int_from_sdio_card)) < 0) { + HWTEST_INFO_FUNC("copy to user space fail!\n"); + retval = 16; + } + } + break; + default: + retval = -17; + HWTEST_INFO_FUNC("unknown cmd (%d)\n", cmd); + break; + } + + HWTEST_INFO_FUNC("retval = (%d)\n",retval); + return retval; +} + + + +static int HWTEST_open(struct inode *inode, struct file *file) +{ + HWTEST_INFO_FUNC("major %d minor %d (pid %d)\n", + imajor(inode), + iminor(inode), + current->pid + ); + + if (atomic_inc_return(&HWTEST_ref_cnt) == 1) { + HWTEST_INFO_FUNC("1st call \n"); + } + + return 0; +} + +static int HWTEST_close(struct inode *inode, struct file *file) +{ + HWTEST_INFO_FUNC("major %d minor %d (pid %d)\n", + imajor(inode), + iminor(inode), + current->pid + ); + + if (atomic_dec_return(&HWTEST_ref_cnt) == 0) { + HWTEST_INFO_FUNC("last call \n"); + } + + return 0; +} + + +struct file_operations HWTEST_fops = { + .open = HWTEST_open, + .release = HWTEST_close, + .read = HWTEST_read, + .write = HWTEST_write, + .unlocked_ioctl = HWTEST_unlocked_ioctl, + .poll = HWTEST_poll, +}; + + +static int HWTEST_init(void) +{ + dev_t dev = MKDEV(HWTEST_major, 0); + int cdev_err = -1; + INT32 ret = -1; + /* Prepare a char device */ + /*static allocate chrdev*/ + ret = register_chrdev_region(dev, HWTEST_DEV_NUM, HWTEST_DRIVER_NAME); + if (ret) { + HWTEST_ERR_FUNC("fail to register chrdev\n"); + return ret; + } + + cdev_init(&HWTEST_cdev, &HWTEST_fops); + HWTEST_cdev.owner = THIS_MODULE; + + cdev_err = cdev_add(&HWTEST_cdev, dev, HWTEST_DEV_NUM); + if (cdev_err) { + HWTEST_ERR_FUNC("cdev_add() fails (%d) \n", cdev_err); + goto error; + } + + HWTEST_INFO_FUNC("driver(major %d) installed \n", HWTEST_major); + + HWTEST_INFO_FUNC("success \n"); + return 0; + +error: + + if (cdev_err == 0) { + cdev_del(&HWTEST_cdev); + } + + if (ret == 0) { + unregister_chrdev_region(dev, HWTEST_DEV_NUM); + HWTEST_major = -1; + } + g_state_flag = 0; + HWTEST_ERR_FUNC("fail \n"); + + return -1; +} + +static void HWTEST_exit (void) +{ + dev_t dev = MKDEV(HWTEST_major, 0); + cdev_del(&HWTEST_cdev); + unregister_chrdev_region(dev, HWTEST_DEV_NUM); + HWTEST_major = -1; + g_state_flag = 0; + g_sdio_init_count = 0; + HWTEST_INFO_FUNC("done\n"); +} + +MODULE_LICENSE("GPL"); +EXPORT_SYMBOL_GPL(g_read_card_info_bysdio); +EXPORT_SYMBOL_GPL(g_read_current_io_isready_from_sdio_card); +EXPORT_SYMBOL_GPL(g_read_function_blksize_from_sdio_card); +EXPORT_SYMBOL_GPL(g_read_int_from_sdio_card); + + +module_init(HWTEST_init); +module_exit(HWTEST_exit); + diff --git a/drivers/mtk_wcn_combo/common/linux/hw_sdio_client.c b/drivers/mtk_wcn_combo/common/linux/hw_sdio_client.c new file mode 100755 index 000000000000..ae123f8934de --- /dev/null +++ b/drivers/mtk_wcn_combo/common/linux/hw_sdio_client.c @@ -0,0 +1,233 @@ + +#include +#include +#include +#include + +#include +#include +#include + +#include "hw_test.h" + + + +extern unsigned char** g_read_card_info_bysdio; +extern UINT8 g_read_current_io_isready_from_sdio_card; +extern UINT16 g_read_function_blksize_from_sdio_card; +extern UINT32 g_read_int_from_sdio_card; + +static const struct sdio_device_id hw_sdio_id_tbl[] = { + + /* MT6620 */ /* Not an SDIO standard class device */ + { SDIO_DEVICE(0x037A, 0x020A) }, /* SDIO1:FUNC1:WIFI */ + { SDIO_DEVICE(0x037A, 0x020B) }, /* SDIO2:FUNC1:BT+FM+GPS */ + { SDIO_DEVICE(0x037A, 0x020C) }, /* 2-function (SDIO2:FUNC1:BT+FM+GPS, FUNC2:WIFI) */ + {}, +}; + +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(sdio, hw_sdio_id_tbl); + +static int hw_sdio_probe ( + struct sdio_func *func, + const struct sdio_device_id *id + ); + +static void hw_sdio_remove ( + struct sdio_func *func + ); +INT32 read_card_info(struct sdio_func * func,UINT32 offset,PUINT32 pbuf,UINT32 len); + +static struct sdio_driver hw_sdio_client_drv = { + .name = "hw_sdio_client", /* MTK SDIO Client Driver */ + .id_table = hw_sdio_id_tbl, /* all supported struct sdio_device_id table */ + .probe = hw_sdio_probe, + .remove = hw_sdio_remove, +}; + +UINT8 read_sdio_card_register_by_cmd52(struct sdio_func * func) +{ + UINT8 val; + INT32 ret = -1; + + sdio_claim_host(func); + val = sdio_f0_readb(func,0x03,&ret); + sdio_release_host(func); + if(val == 0xff){ + HWTEST_INFO_FUNC("read CCCR I/O ready register by cmd52 fail!\n"); + return -1; + }else{ + HWTEST_INFO_FUNC("read CCCR I/O ready register by cmd52:0x%08x\n",val); + return val; + } +} + +UINT32 read_sdio_card_register_by_cmd53(struct sdio_func * func) +{ + UINT32 val; + INT32 ret = -1; + sdio_claim_host(func); + val = sdio_readl(func,0x0000,&ret); + sdio_release_host(func); + if(val == 0xffffffff){ + HWTEST_INFO_FUNC("read sdio register by cmd53 fail!\n"); + return -1; + }else{ + HWTEST_INFO_FUNC("read sdio register by cmd53:0x%08x\n",val); + return val; + } +} + +UINT16 read_sdio_card_cccr_register(struct sdio_func * func) +{ + UINT8 val1, val2; + INT32 ret = -1; + UINT16 result = 0; + + sdio_claim_host(func); + val1 = sdio_f0_readb(func,0x110,&ret); + sdio_release_host(func); + if(val1 == 0xff){ + HWTEST_INFO_FUNC("read sdio cccr register fail!\n"); + return -1; + }else{ + HWTEST_INFO_FUNC("read current function blksize_first byte:0x%08x\n",val1); + } + + sdio_claim_host(func); + val2 = sdio_f0_readb(func,0x111,&ret); + sdio_release_host(func); + if(val2 == 0xff){ + HWTEST_INFO_FUNC("read sdio cccr register fail!\n"); + return -1; + }else{ + HWTEST_INFO_FUNC("read current function blksize_second byte:0x%08x\n",val2); + } + result = val2 << 8; + result |= val1; + return result; +} + +static int hw_sdio_probe (struct sdio_func *func,const struct sdio_device_id *id) +{ + int i = 0; + char buf[128]; + + HWTEST_INFO_FUNC("%s start \n",__FUNCTION__); + if(!func){ + HWTEST_INFO_FUNC("func pointer is null!\n"); + return -1; + } + + //4 <0> display debug information + HWTEST_INFO_FUNC("vendor(0x%x) device(0x%x) num(0x%x)\n", func->vendor, func->device, func->num); + for (i = 0;i < func->card->num_info;i++) { + HWTEST_INFO_FUNC("card->info[%d]: %s\n", i, func->card->info[i]); + } + g_read_card_info_bysdio = (char **)kmalloc((func->card->num_info) * sizeof(char*),GFP_KERNEL); + + + + for(i = 0; i < func->card->num_info;i++){ + + HWTEST_INFO_FUNC("card info str(%d) strlen = %d\n",i,strlen(func->card->info[i])); + + if(!g_read_card_info_bysdio[i]){ + HWTEST_INFO_FUNC("kmalloc buffer fail!\n"); + return -2; + } + if(0 != strlen(func->card->info[i])){ + g_read_card_info_bysdio[i] = kmalloc(strlen(func->card->info[i]) * sizeof(char),GFP_KERNEL); + strcpy(g_read_card_info_bysdio[i],func->card->info[i]); + HWTEST_INFO_FUNC("g_read_card_info_bysdio[%d] = %s\n",i,g_read_card_info_bysdio[i]); + } + else{ + g_read_card_info_bysdio[i] = kmalloc(128,GFP_KERNEL); + memset(g_read_card_info_bysdio[i],0,128); + } + } + + + sprintf(buf,"verdor is 0x%x,device is 0x%x,func number is 0x%x",func->vendor,func->device,func->num); + HWTEST_INFO_FUNC("buf = %s\n",buf); + for(i = 0; i < func->card->num_info;i++){ + if(!g_read_card_info_bysdio[i][0]){ + strcpy(g_read_card_info_bysdio[i],buf); + break; + } + } + + + sdio_claim_host(func); + sdio_enable_func(func); + sdio_release_host(func); + + sdio_claim_host(func); + sdio_set_block_size(func, 512); + sdio_release_host(func); + + g_read_current_io_isready_from_sdio_card = read_sdio_card_register_by_cmd52(func); + g_read_function_blksize_from_sdio_card = read_sdio_card_cccr_register(func); + g_read_int_from_sdio_card = read_sdio_card_register_by_cmd53(func); + + HWTEST_INFO_FUNC("%s end\n", __FUNCTION__); + return 0; +} + +static void hw_sdio_remove (struct sdio_func *func) +{ + int i = 0; + HWTEST_INFO_FUNC("%s start \n",__FUNCTION__); + + if(!func){ + HWTEST_INFO_FUNC("func pointer is null!\n"); + return; + } + + for(i = 0; i < func->card->num_info;i++){ + + if(g_read_card_info_bysdio[i]){ + kfree(g_read_card_info_bysdio[i]); + } + } + + kfree(g_read_card_info_bysdio); + + HWTEST_INFO_FUNC("%s:sdio func(0x%p) is removed successfully!\n", __FUNCTION__, func); + + HWTEST_INFO_FUNC("%s end\n", __FUNCTION__); +} + + +static int __init hw_sdio_init(void) +{ + int ret = 0; + + HWTEST_INFO_FUNC("%s start \n",__FUNCTION__); + + //register to mmc driver + ret = sdio_register_driver(&hw_sdio_client_drv); + + HWTEST_INFO_FUNC("sdio_register_driver() ret=%d\n", ret); + HWTEST_INFO_FUNC("%s end\n", __FUNCTION__); + + return ret; +} + +static void __exit hw_sdio_exit(void) +{ + int ret = 0; + + HWTEST_INFO_FUNC("%s start \n", __FUNCTION__); + + sdio_unregister_driver(&hw_sdio_client_drv); + + + HWTEST_INFO_FUNC("%s end\n", __FUNCTION__); + return; +} + +module_init(hw_sdio_init); +module_exit(hw_sdio_exit); + diff --git a/drivers/mtk_wcn_combo/common/linux/include/hif_sdio.h b/drivers/mtk_wcn_combo/common/linux/include/hif_sdio.h new file mode 100755 index 000000000000..0618d8e7cd17 --- /dev/null +++ b/drivers/mtk_wcn_combo/common/linux/include/hif_sdio.h @@ -0,0 +1,350 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + + +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + */ +/* MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +/* +** $Id: $ +*/ + +/*! \file "hif_sdio.h" + \brief + + +*/ + +/* +** $Log: $ + * + * 07 25 2010 george.kuo + * + * Move hif_sdio driver to linux directory. + * + * 07 23 2010 george.kuo + * + * Add MT6620 driver source tree + * , including char device driver (wmt, bt, gps), stp driver, interface driver (tty ldisc and hif_sdio), and bt hci driver. +** +** +*/ + +#ifndef _HIF_SDIO_H +#define _HIF_SDIO_H +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +#define HIF_SDIO_DEBUG (0) /* 0:trun off debug msg and assert, 1:trun off debug msg and assert */ +#define SDIO_TAG "[HIF-SDIO]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "osal_linux.h" +#include "osal.h" +#include "wmt_exp.h" + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define CFG_CLIENT_COUNT (9) + +#define HIF_DEFAULT_BLK_SIZE (256) +#define HIF_DEFAULT_VENDOR (0x037A) + +#define HIF_SDIO_LOG_LOUD 4 +#define HIF_SDIO_LOG_DBG 3 +#define HIF_SDIO_LOG_INFO 2 +#define HIF_SDIO_LOG_WARN 1 +#define HIF_SDIO_LOG_ERR 0 + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/* Function info provided by client driver */ +typedef struct _MTK_WCN_HIF_SDIO_FUNCINFO MTK_WCN_HIF_SDIO_FUNCINFO; + +/* Client context provided by hif_sdio driver for the following function call */ +typedef UINT32 MTK_WCN_HIF_SDIO_CLTCTX; + +/* Callback functions provided by client driver */ +typedef INT32 (*MTK_WCN_HIF_SDIO_PROBE)(MTK_WCN_HIF_SDIO_CLTCTX, const MTK_WCN_HIF_SDIO_FUNCINFO *); +typedef INT32 (*MTK_WCN_HIF_SDIO_REMOVE)(MTK_WCN_HIF_SDIO_CLTCTX); +typedef INT32 (*MTK_WCN_HIF_SDIO_IRQ)(MTK_WCN_HIF_SDIO_CLTCTX); + +/* Function info provided by client driver */ +struct _MTK_WCN_HIF_SDIO_FUNCINFO { + UINT16 manf_id; /* TPLMID_MANF: manufacturer ID */ + UINT16 card_id; /* TPLMID_CARD: card ID */ + UINT16 func_num; /* Function Number */ + UINT16 blk_sz; /* Function block size */ +}; + +/* Client info provided by client driver */ +typedef struct _MTK_WCN_HIF_SDIO_CLTINFO { + const MTK_WCN_HIF_SDIO_FUNCINFO *func_tbl; /* supported function info table */ + UINT32 func_tbl_size; /* supported function table info element number */ + MTK_WCN_HIF_SDIO_PROBE hif_clt_probe; /* callback function for probing */ + MTK_WCN_HIF_SDIO_REMOVE hif_clt_remove; /* callback function for removing */ + MTK_WCN_HIF_SDIO_IRQ hif_clt_irq; /* callback function for interrupt handling */ +} MTK_WCN_HIF_SDIO_CLTINFO; + +/* function info provided by registed function */ +typedef struct _MTK_WCN_HIF_SDIO_REGISTINFO { + const MTK_WCN_HIF_SDIO_CLTINFO *sdio_cltinfo; /* client's MTK_WCN_HIF_SDIO_CLTINFO pointer */ + const MTK_WCN_HIF_SDIO_FUNCINFO *func_info; /* supported function info pointer */ +} MTK_WCN_HIF_SDIO_REGISTINFO; + +/* Card info provided by probed function */ +typedef struct _MTK_WCN_HIF_SDIO_PROBEINFO { + struct sdio_func* func; /* probed sdio function pointer */ + void* private_data_p; /* clt's private data pointer */ + MTK_WCN_BOOL on_by_wmt; /* TRUE: on by wmt, FALSE: not on by wmt */ + /* added for sdio irq sync and mmc single_irq workaround */ + MTK_WCN_BOOL sdio_irq_enabled; /* TRUE: can handle sdio irq; FALSE: no sdio irq handling */ + INT8 clt_idx; /* registered function table info element number (initial value is -1) */ +} MTK_WCN_HIF_SDIO_PROBEINFO; + +/* work queue info needed by worker */ +typedef struct _MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO { + struct work_struct probe_work; /* work queue structure */ + MTK_WCN_HIF_SDIO_REGISTINFO *registinfo_p; /* MTK_WCN_HIF_SDIO_REGISTINFO pointer of the client */ + INT8 probe_idx; /* probed function table info element number (initial value is -1) */ +} MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO; + +/* global resource locks info of hif_sdio drv */ +typedef struct _MTK_WCN_HIF_SDIO_LOCKINFO { + spinlock_t probed_list_lock; /* spin lock for probed list */ + spinlock_t clt_list_lock; /* spin lock for client registed list */ +} MTK_WCN_HIF_SDIO_LOCKINFO; + +/* error code returned by hif_sdio driver (use NEGATIVE number) */ +typedef enum { + HIF_SDIO_ERR_SUCCESS = 0, + HIF_SDIO_ERR_FAIL = HIF_SDIO_ERR_SUCCESS - 1, /* generic error */ + HIF_SDIO_ERR_INVALID_PARAM = HIF_SDIO_ERR_FAIL - 1, + HIF_SDIO_ERR_DUPLICATED = HIF_SDIO_ERR_INVALID_PARAM - 1, + HIF_SDIO_ERR_UNSUP_MANF_ID = HIF_SDIO_ERR_DUPLICATED - 1, + HIF_SDIO_ERR_UNSUP_CARD_ID = HIF_SDIO_ERR_UNSUP_MANF_ID - 1, + HIF_SDIO_ERR_INVALID_FUNC_NUM = HIF_SDIO_ERR_UNSUP_CARD_ID - 1, + HIF_SDIO_ERR_INVALID_BLK_SZ = HIF_SDIO_ERR_INVALID_FUNC_NUM - 1, + HIF_SDIO_ERR_NOT_PROBED = HIF_SDIO_ERR_INVALID_BLK_SZ - 1, + HIF_SDIO_ERR_ALRDY_ON = HIF_SDIO_ERR_NOT_PROBED -1, + HIF_SDIO_ERR_ALRDY_OFF = HIF_SDIO_ERR_ALRDY_ON -1, + HIF_SDIO_ERR_CLT_NOT_REG = HIF_SDIO_ERR_ALRDY_OFF - 1, +} MTK_WCN_HIF_SDIO_ERR ; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + + +/*! + * \brief A macro used to describe an SDIO function + * + * Fill an MTK_WCN_HIF_SDIO_FUNCINFO structure with function-specific information + * + * \param manf the 16 bit manufacturer id + * \param card the 16 bit card id + * \param func the 16 bit function number + * \param b_sz the 16 bit function block size + */ +#define MTK_WCN_HIF_SDIO_FUNC(manf, card, func, b_sz) \ + .manf_id = (manf), .card_id = (card), .func_num = (func), .blk_sz = (b_sz) + +#define HIF_SDIO_LOUD_FUNC(fmt, arg...) if (gHifSdioDbgLvl >= HIF_SDIO_LOG_LOUD) { printk(KERN_INFO SDIO_TAG"[L]%s:" fmt, __FUNCTION__ ,##arg);} +#define HIF_SDIO_DBG_FUNC(fmt, arg...) if (gHifSdioDbgLvl >= HIF_SDIO_LOG_DBG) { printk(KERN_INFO SDIO_TAG"[D]%s:" fmt, __FUNCTION__ ,##arg);} +#define HIF_SDIO_INFO_FUNC(fmt, arg...) if (gHifSdioDbgLvl >= HIF_SDIO_LOG_INFO) { printk(KERN_INFO SDIO_TAG"[I]%s:" fmt, __FUNCTION__ ,##arg);} +#define HIF_SDIO_WARN_FUNC(fmt, arg...) if (gHifSdioDbgLvl >= HIF_SDIO_LOG_WARN) { printk(KERN_WARNING SDIO_TAG"[W]%s(%d):" fmt, __FUNCTION__ , __LINE__, ##arg);} +#define HIF_SDIO_ERR_FUNC(fmt, arg...) if (gHifSdioDbgLvl >= HIF_SDIO_LOG_ERR) { printk(KERN_WARNING SDIO_TAG"[E]%s(%d):" fmt, __FUNCTION__ , __LINE__, ##arg);} + +/*! + * \brief ASSERT function definition. + * + */ +#if HIF_SDIO_DEBUG +#define HIF_SDIO_ASSERT(expr) if ( !(expr) ) { \ + printk("assertion failed! %s[%d]: %s\n",\ + __FUNCTION__, __LINE__, #expr); \ + BUG_ON( !(expr) );\ + } +#else +#define HIF_SDIO_ASSERT(expr) do {} while(0) +#endif + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/*! + * \brief MTK hif sdio client registration function + * + * Client uses this function to do hif sdio registration + * + * \param pinfo a pointer of client's information + * + * \retval 0 register successfully + * \retval < 0 error code + */ +extern INT32 mtk_wcn_hif_sdio_client_reg ( + const MTK_WCN_HIF_SDIO_CLTINFO *pinfo + ); + +extern INT32 mtk_wcn_hif_sdio_client_unreg ( + const MTK_WCN_HIF_SDIO_CLTINFO *pinfo + ); + +extern INT32 mtk_wcn_hif_sdio_readb ( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + UINT32 offset, + PUINT8 pvb + ); + +extern INT32 mtk_wcn_hif_sdio_writeb ( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + UINT32 offset, + UINT8 vb + ); + +extern INT32 mtk_wcn_hif_sdio_readl ( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + UINT32 offset, + PUINT32 pvl + ); + +extern INT32 mtk_wcn_hif_sdio_writel ( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + UINT32 offset, + UINT32 vl + ); + +extern INT32 mtk_wcn_hif_sdio_read_buf ( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + UINT32 offset, + PUINT32 pbuf, + UINT32 len + ); + +extern INT32 mtk_wcn_hif_sdio_write_buf ( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + UINT32 offset, + PUINT32 pbuf, + UINT32 len + ); + +extern void mtk_wcn_hif_sdio_set_drvdata( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + void* private_data_p + ); + +extern void* mtk_wcn_hif_sdio_get_drvdata( + MTK_WCN_HIF_SDIO_CLTCTX ctx + ); + +extern INT32 mtk_wcn_hif_sdio_wmt_control( + WMT_SDIO_FUNC_TYPE func_type, + MTK_WCN_BOOL is_on + ); + +extern void mtk_wcn_hif_sdio_get_dev( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + struct device **dev + ); + +extern void mtk_wcn_hif_sdio_enable_irq( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + MTK_WCN_BOOL enable + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#endif /* _HIF_SDIO_H */ + + diff --git a/drivers/mtk_wcn_combo/common/linux/include/hw_test.h b/drivers/mtk_wcn_combo/common/linux/include/hw_test.h new file mode 100755 index 000000000000..3068ea19c4dc --- /dev/null +++ b/drivers/mtk_wcn_combo/common/linux/include/hw_test.h @@ -0,0 +1,146 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + + +/*! \file hw_test.h + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _HW_TEST_H +#define _HW_TEST_H + +/******************************************************************************* +* G L O B A L F L A G S +******************************************************************************** +*/ + + +static unsigned int g_state_flag = 0;//power on and power off +static unsigned int g_sdio_init_count = 0;//if it is the 1st init sdio card + +//extern unsigned char* g_read_card_info_bysdio[8]; +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define HWTEST_DRIVER_NAME "mtk_hw_test" + + +/* debug information */ +#define PFX "[HWTEST]" +#define DBG_NAME "[hw_test]" +#define HWTEST_LOG_LOUD 4 +#define HWTEST_LOG_DBG 3 +#define HWTEST_LOG_INFO 2 +#define HWTEST_LOG_WARN 1 +#define HWTEST_LOG_ERR 0 + +static unsigned int gHWDbgLvl = HWTEST_LOG_INFO; + +#define HWTEST_IOCTL_MAGIC 0xc4 + +#define HWTEST_IOCTL_POWER_ON _IO(HWTEST_IOCTL_MAGIC,0) +#define HWTEST_IOCTL_POWER_OFF _IO(HWTEST_IOCTL_MAGIC,1) +#define HWTEST_IOCTL_CHIP_RESET _IO(HWTEST_IOCTL_MAGIC,2) +#define HWTEST_IOCTL_SDIO_INIT _IO(HWTEST_IOCTL_MAGIC,3) +#define HWTEST_IOCTL_SDIO_REMOVE _IO(HWTEST_IOCTL_MAGIC,4) +#define HWTEST_IOCTL_SDIO_READ_IOISREADY _IOR(HWTEST_IOCTL_MAGIC,5,UINT8) +#define HWTEST_IOCTL_SDIO_READ_BLKSIZE _IOR(HWTEST_IOCTL_MAGIC,6,UINT16) +#define HWTEST_IOCTL_SDIO_READ_INT _IOR(HWTEST_IOCTL_MAGIC,7,UINT32) + + + + + +/******************************************************************************* +* D A T A T Y P E S +********************************************************************************/ +/* Type definition for signed integers */ +typedef signed int INT32, *PINT32; +typedef signed char INT8, *PINT8; +typedef signed short INT16, *PINT16; +/* Type definition for unsigned integers */ +typedef unsigned int UINT32, *PUINT32; +typedef unsigned char UINT8, *PUINT8; +typedef unsigned short UINT16,*PUINT16; + +typedef enum{ + HWTEST_POWER_ON = 0, + HWTEST_POWER_OFF = 1, + HWTEST_HW_REST = 2, + HWTEST_SDIO_INIT = 3, + HWTEST_CMD_MAX +}HWTEST_CMD; + +typedef enum _HWTEST_CHIPVERSION{ + HWVER_MT6620_E1 = 0x0, + HWVER_MT6620_E2 = 0x1, + HWVER_MT6620_E3 = 0x2, + HWVER_MT6620_E4 = 0x3, + HWVER_MT6620_E5 = 0x4, + HWVER_MT6620_E6 = 0x5, + HWVER_MT6620_MAX, + HWVER_INVALID = 0xff +} ENUM_HWTEST_CHIPVERSION_T; + +/* bit field offset definition */ +typedef enum { + HWTEST_STAT_PWRON = 0, /* is powered on */ + HWTEST_STAT_PWROFF = 1, + HWTEST_STAT_SDIO1_ON = 2, /* is SDIO1 on */ + HWTEST_STAT_SDIO2_ON = 3, /* is SDIO2 on */ + HWTEST_STAT_MAX +} HWTEST_STAT; + + +/* FIXME: apply KERN_* definition? */ +#define HWTEST_LOUD_FUNC(fmt, arg...) if (gHWDbgLvl >= HWTEST_LOG_LOUD) { printk(DBG_NAME"%s:" fmt, __FUNCTION__ ,##arg);} +#define HWTEST_DBG_FUNC(fmt, arg...) if (gHWDbgLvl >= HWTEST_LOG_DBG) { printk(DBG_NAME "%s:" fmt, __FUNCTION__ ,##arg);} +#define HWTEST_INFO_FUNC(fmt, arg...) if (gHWDbgLvl >= HWTEST_LOG_INFO) { printk(DBG_NAME "%s:" fmt, __FUNCTION__ ,##arg);} +#define HWTEST_WARN_FUNC(fmt, arg...) if (gHWDbgLvl >= HWTEST_LOG_WARN) { printk(DBG_NAME "%s:" fmt, __FUNCTION__ ,##arg);} +#define HWTEST_ERR_FUNC(fmt, arg...) if (gHWDbgLvl >= HWTEST_LOG_ERR) { printk(DBG_NAME "%s(%d):" fmt, __FUNCTION__ , __LINE__, ##arg);} +#define HWTEST_TRC_FUNC(f) if (gHWDbgLvl >= HWTEST_LOG_DBG) { printk(DBG_NAME "<%s> <%d>\n", __FUNCTION__, __LINE__);} +// for Ingenic +#define GPIO_PMU (32 * 3 + 3) /* GPD3*/ +#define GPIO_RST (32 * 3 + 0) /* GPD0 */ + +extern int sdio_card_detect(); +extern int sdio_card_remove(); +// end for Ingenic + +#endif /* _HW_TETS_H */ + diff --git a/drivers/mtk_wcn_combo/common/linux/include/mtk_wcn_cmb_stub.h b/drivers/mtk_wcn_combo/common/linux/include/mtk_wcn_cmb_stub.h new file mode 100755 index 000000000000..18682c0d69ec --- /dev/null +++ b/drivers/mtk_wcn_combo/common/linux/include/mtk_wcn_cmb_stub.h @@ -0,0 +1,213 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +#ifndef _MTK_WCN_CMB_STUB_H_ +#define _MTK_WCN_CMB_STUB_H_ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum { + CMB_STUB_AIF_0 = 0, /* 0000: BT_PCM_OFF & FM analog (line in/out) */ + CMB_STUB_AIF_1 = 1, /* 0001: BT_PCM_ON & FM analog (in/out) */ + CMB_STUB_AIF_2 = 2, /* 0010: BT_PCM_OFF & FM digital (I2S) */ + CMB_STUB_AIF_3 = 3, /* 0011: BT_PCM_ON & FM digital (I2S) (invalid in 73evb & 1.2 phone configuration) */ + CMB_STUB_AIF_MAX = 4, +} CMB_STUB_AIF_X; + +/*COMBO_CHIP_AUDIO_PIN_CTRL*/ +typedef enum { + CMB_STUB_AIF_CTRL_DIS = 0, + CMB_STUB_AIF_CTRL_EN = 1, + CMB_STUB_AIF_CTRL_MAX = 2, +} CMB_STUB_AIF_CTRL; + +#if 1 /* copied from mt_combo.h */ +typedef enum { + COMBO_AUDIO_STATE_0 = 0, /* 0000: BT_PCM_OFF & FM analog (line in/out) */ + COMBO_AUDIO_STATE_1 = 1, /* 0001: BT_PCM_ON & FM analog (in/out) */ + COMBO_AUDIO_STATE_2 = 2, /* 0010: BT_PCM_OFF & FM digital (I2S) */ + COMBO_AUDIO_STATE_3 = 3, /* 0011: BT_PCM_ON & FM digital (I2S) (invalid in 73evb & 1.2 phone configuration) */ + COMBO_AUDIO_STATE_MAX = 4, +} COMBO_AUDIO_STATE; + +typedef enum { + COMBO_FUNC_TYPE_BT = 0, + COMBO_FUNC_TYPE_FM = 1, + COMBO_FUNC_TYPE_GPS = 2, + COMBO_FUNC_TYPE_WIFI = 3, + COMBO_FUNC_TYPE_WMT = 4, + COMBO_FUNC_TYPE_STP = 5, + COMBO_FUNC_TYPE_NUM = 6 +} COMBO_FUNC_TYPE; + +typedef enum { + COMBO_IF_UART = 0, + COMBO_IF_MSDC = 1, + COMBO_IF_MAX, +} COMBO_IF; +#endif + +typedef void (*wmt_bgf_eirq_cb)(void); +typedef int (*wmt_aif_ctrl_cb)(CMB_STUB_AIF_X, CMB_STUB_AIF_CTRL); +typedef void (*wmt_func_ctrl_cb)(unsigned int, unsigned int); + +typedef struct _CMB_STUB_CB_ { + unsigned int size; //structure size + /*wmt_bgf_eirq_cb bgf_eirq_cb;*//* remove bgf_eirq_cb from stub. handle it in platform */ + wmt_aif_ctrl_cb aif_ctrl_cb; + wmt_func_ctrl_cb func_ctrl_cb; +} CMB_STUB_CB, *P_CMB_STUB_CB; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +extern int mtk_wcn_cmb_stub_reg (P_CMB_STUB_CB p_stub_cb); +extern int mtk_wcn_cmb_stub_unreg (void); + +extern int mtk_wcn_cmb_stub_aif_ctrl (CMB_STUB_AIF_X state, CMB_STUB_AIF_CTRL ctrl); + +#if 0 /* remove obsolete audio_ctrl APIs. Use stub_aif_ctrl()! */ +/* [GeorgeKuo] Stub functions for other kernel built-in modules to call. + * Keep them unchanged temporarily. Move mt_combo functions to mtk_wcn_combo. + */ +extern int mtk_wcn_cmb_stub_audio_ctrl_ex(COMBO_AUDIO_STATE state, u32 clt_ctrl); +static inline int mtk_wcn_cmb_stub_audio_ctrl(COMBO_AUDIO_STATE state) { + return mtk_wcn_cmb_stub_audio_ctrl_ex(state, 1); +} +#endif + +/* Use new mtk_wcn_stub APIs instead of old mt_combo ones for kernel to control + * function on/off. + */ +extern void mtk_wcn_cmb_stub_func_ctrl (unsigned int type, unsigned int on); + +extern int mt_combo_plt_enter_deep_idle(COMBO_IF src); +extern int mt_combo_plt_exit_deep_idle(COMBO_IF src); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _MTK_WCN_CMB_STUB_H_ */ + diff --git a/drivers/mtk_wcn_combo/common/linux/include/osal_linux.h b/drivers/mtk_wcn_combo/common/linux/include/osal_linux.h new file mode 100755 index 000000000000..7d52fc6f7a8c --- /dev/null +++ b/drivers/mtk_wcn_combo/common/linux/include/osal_linux.h @@ -0,0 +1,120 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +#ifndef _OSAL_LINUX_H_ +#define _OSAL_LINUX_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef WMT_PLAT_ALPS +#include +#endif +#include +#include +#include + + +#endif diff --git a/drivers/mtk_wcn_combo/common/linux/include/osal_typedef.h b/drivers/mtk_wcn_combo/common/linux/include/osal_typedef.h new file mode 100755 index 000000000000..55b0b40451ef --- /dev/null +++ b/drivers/mtk_wcn_combo/common/linux/include/osal_typedef.h @@ -0,0 +1,98 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2011. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + + +#ifndef _OSAL_TYPEDEF_H_ +#define _OSAL_TYPEDEF_H_ + +typedef void VOID; +typedef void *PVOID; + +typedef char CHAR; +typedef char *PCHAR; +typedef signed char INT8; +typedef signed char *PINT8; +typedef unsigned char UINT8; +typedef unsigned char *PUINT8; +typedef unsigned char UCHAR; +typedef unsigned char *PUCHAR; + +typedef signed short INT16; +typedef signed short *PINT16; +typedef unsigned short UINT16; +typedef unsigned short *PUINT16; + +typedef signed long LONG; +typedef signed long *PLONG; + +typedef signed int INT32; +typedef signed int *PINT32; +typedef unsigned int UINT32; +typedef unsigned int *PUINT32; + +typedef unsigned long ULONG; +typedef unsigned long *PULONG; + +typedef int MTK_WCN_BOOL; + +#ifndef MTK_WCN_BOOL_TRUE +#define MTK_WCN_BOOL_FALSE ((MTK_WCN_BOOL) 0) +#define MTK_WCN_BOOL_TRUE ((MTK_WCN_BOOL) 1) +#endif + +#ifndef NULL +#define NULL ((VOID *)0) +#endif + +typedef VOID *TIMER_REF; +typedef VOID *SPINLOCK_REF; +typedef VOID *MUTEX_REF; +typedef VOID *WAITQUEUE_REF; +typedef VOID *FIRMWARE_REF; +typedef VOID *PROCENTRY_REF; +typedef VOID *COMPLETION_REF; +typedef VOID *THREAD_REF; +typedef VOID *WAKELOCK_REF; + + +#endif /*_OSAL_TYPEDEF_H_*/ + diff --git a/drivers/mtk_wcn_combo/common/linux/include/wmt_dev.h b/drivers/mtk_wcn_combo/common/linux/include/wmt_dev.h new file mode 100755 index 000000000000..ff753bf90150 --- /dev/null +++ b/drivers/mtk_wcn_combo/common/linux/include/wmt_dev.h @@ -0,0 +1,50 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +#ifndef _WMT_DEV_H_ +#define _WMT_DEV_H_ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "osal.h" + +extern INT32 wmt_dev_patch_get (UCHAR *pPatchName, OSAL_FIRMWARE **ppPatch,INT32 padSzBuf); +extern INT32 wmt_dev_patch_put(OSAL_FIRMWARE **ppPatch); + +#endif /*_WMT_DEV_H_*/ + diff --git a/drivers/mtk_wcn_combo/common/linux/osal.c b/drivers/mtk_wcn_combo/common/linux/osal.c new file mode 100755 index 000000000000..ef6d7051213d --- /dev/null +++ b/drivers/mtk_wcn_combo/common/linux/osal.c @@ -0,0 +1,1567 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "osal_linux.h" +#include "osal.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + + + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + + + + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*string operations*/ +UINT32 osal_strlen(const char *str) +{ + return strlen(str); +} + +INT32 osal_strcmp(const char *dst, const char *src) +{ + return strcmp(dst, src); +} + +INT32 osal_strncmp(const char *dst, const char *src, UINT32 len) +{ + return strncmp(dst, src, len); +} + +char * osal_strcpy(char *dst, const char *src) +{ + return strcpy(dst, src); +} + +char * osal_strncpy(char *dst, const char *src, UINT32 len) +{ + return strncpy(dst, src, len); +} + + +char * osal_strcat(char *dst, const char *src) +{ + return strcat(dst, src); +} + +char * osal_strncat(char *dst, const char *src, UINT32 len) +{ + return strncat(dst, src, len); +} + +char * osal_strchr(const char *str, UINT8 c) +{ + return strchr(str, c); +} + + +char * osal_strsep(char **str, const char *c) +{ + return strsep(str, c); +} + + +LONG osal_strtol(const char *str, char **c, UINT32 adecimal) +{ + return simple_strtol(str, c, adecimal); +} + +INT32 osal_snprintf(char *buf, UINT32 len, const char*fmt, ...) +{ + INT32 iRet = 0; + va_list args; + + /*va_start(args, fmt);*/ + va_start(args, fmt); + /*iRet = snprintf(buf, len, fmt, args);*/// TODO: [FixMe][GeorgeKuo] BUG? + iRet = vsnprintf(buf, len, fmt, args); + va_end(args); + + return iRet; +} + +INT32 osal_print(const char *str, ...) +{ + va_list args; + char tempString[DBG_LOG_STR_SIZE]; + + va_start(args, str); + vsnprintf(tempString, DBG_LOG_STR_SIZE, str, args); + va_end(args); + + printk("%s",tempString); + + return 0; +} + + +INT32 osal_dbg_print(const char *str, ...) +{ + va_list args; + char tempString[DBG_LOG_STR_SIZE]; + + va_start(args, str); + vsnprintf(tempString, DBG_LOG_STR_SIZE, str, args); + va_end(args); + + printk(KERN_DEBUG "%s",tempString); + + return 0; +} + +INT32 osal_err_print(const char *str, ...) +{ + va_list args; + char tempString[DBG_LOG_STR_SIZE]; + + va_start(args, str); + vsnprintf(tempString, DBG_LOG_STR_SIZE, str, args); + va_end(args); + + printk(KERN_ERR "%s",tempString); + + return 0; +} + +INT32 osal_info_print(const char *str, ...) +{ + va_list args; + char tempString[DBG_LOG_STR_SIZE]; + + va_start(args, str); + vsnprintf(tempString, DBG_LOG_STR_SIZE, str, args); + va_end(args); + + printk(KERN_INFO "%s",tempString); + + return 0; +} + +INT32 osal_warn_print(const char *str, ...) +{ + va_list args; + char tempString[DBG_LOG_STR_SIZE]; + + va_start(args, str); + vsnprintf(tempString, DBG_LOG_STR_SIZE, str, args); + va_end(args); + + printk(KERN_WARNING "%s",tempString); + + return 0; +} + +INT32 osal_loud_print(const char *str, ...) +{ + va_list args; + char tempString[DBG_LOG_STR_SIZE]; + + va_start(args, str); + vsnprintf(tempString, DBG_LOG_STR_SIZE, str, args); + va_end(args); + + printk(KERN_DEBUG "%s",tempString); + + return 0; +} +/* +EXPORT_SYMBOL(osal_dbg_print); +EXPORT_SYMBOL(osal_err_print); +EXPORT_SYMBOL(osal_info_print); +EXPORT_SYMBOL(osal_warn_print); +EXPORT_SYMBOL(osal_loud_print); +*/ + +INT32 osal_dbg_assert(INT32 expr, const char *file, INT32 line) +{ + if (!expr){ + printk("%s (%d)\n", file, line); + /*BUG_ON(!expr);*/ +#ifdef CFG_COMMON_GPIO_DBG_PIN +//package this part + mt_set_gpio_out(GPIO70, GPIO_OUT_ZERO); + printk("toggle GPIO70\n"); + udelay(10); + mt_set_gpio_out(GPIO70, GPIO_OUT_ONE); +#endif + return 1; + } + return 0; + + +} + +INT32 osal_dbg_assert_aee(const char *module, const char *detail_description){ + osal_err_print("[WMT-ASSERT]""[E][Module]:%s, [INFO]%s\n", module, detail_description); +#ifdef WMT_PLAT_ALPS + aee_kernel_warning( + module, + detail_description); +#endif + + return 0; +} + +INT32 osal_sprintf(char *str, const char *format, ...) +{ + INT32 iRet = 0; + va_list args; + + va_start(args, format); + iRet = vsnprintf(str, DBG_LOG_STR_SIZE, format, args); + va_end(args); + + return iRet; +} + +VOID* osal_malloc(UINT32 size) +{ + return vmalloc(size); +} + + +VOID osal_vfree(const VOID *dst) +{ + vfree(dst); +} + +VOID osal_kfree(const VOID *dst) +{ + kfree(dst); +} + +VOID* osal_memset(VOID *buf, INT32 i, UINT32 len) +{ + return memset(buf, i, len); +} + + +VOID* osal_memcpy(VOID *dst, const VOID *src, UINT32 len) +{ + return memcpy(dst, src, len); +} + + +INT32 osal_memcmp(const VOID *buf1, const VOID *buf2, UINT32 len) +{ + return memcmp(buf1, buf2, len); +} + +VOID* osal_kzalloc_sleep(UINT32 size) +{ + return kzalloc(size,GFP_KERNEL); +} + +VOID* osal_kzalloc_unsleep(UINT32 size) +{ + return kzalloc(size,GFP_ATOMIC); +} + + +/* + *OSAL layer Thread Opeartion releated APIs + * + * +*/ +INT32 +osal_thread_create ( + P_OSAL_THREAD pThread + ) +{ + //pThread->pThread = NULL; /* [FIXME] why? */ + if(pThread) + { + pThread->pThread = (struct task_struct *)kthread_create(pThread->pThreadFunc, + pThread->pThreadData, + pThread->threadName); + if (NULL == pThread->pThread) { + return -1; + } + return 0; + } + else + { + return -2; + } +} +INT32 +osal_thread_run ( + P_OSAL_THREAD pThread + ) +{ + if (pThread->pThread) { + wake_up_process((struct task_struct *)pThread->pThread); + return 0; + } + else { + return -1; + } +} + +INT32 +osal_thread_stop ( + P_OSAL_THREAD pThread + ) +{ + INT32 iRet; + if ( (pThread) && (pThread->pThread) ) { + iRet = kthread_stop((struct task_struct *)pThread->pThread); + //pThread->pThread = NULL; + return iRet; + } + return -1; +} + + +INT32 +osal_thread_should_stop ( + P_OSAL_THREAD pThread + ) +{ + if ( (pThread) && (pThread->pThread) ) { + return kthread_should_stop(); + } + else { + return 1; + } +} + + +INT32 +osal_thread_wait_for_event ( + P_OSAL_THREAD pThread, + P_OSAL_EVENT pEvent, + P_OSAL_EVENT_CHECKER pChecker + ) +{ +/* P_DEV_WMT pDevWmt;*/ + + if ( (pThread) && (pThread->pThread) && (pEvent) && (pChecker)) { +/* pDevWmt = (P_DEV_WMT)(pThread->pThreadData);*/ + return wait_event_interruptible((*(wait_queue_head_t *)pEvent->pWaitQueue), + (/*!RB_EMPTY(&pDevWmt->rActiveOpQ) ||*/ osal_thread_should_stop(pThread) || (*pChecker)(pThread))); + } + return -1; +} + +INT32 +osal_thread_destroy ( + P_OSAL_THREAD pThread + ) +{ + if (pThread && (pThread->pThread)) { + kthread_stop((struct task_struct *)pThread->pThread); + pThread->pThread = NULL; + } + return 0; +} + +/* + *OSAL layer Signal Opeartion releated APIs + *initialization + *wait for signal + *wait for signal timerout + *raise signal + *destroy a signal + * +*/ + +INT32 +osal_signal_init ( + P_OSAL_SIGNAL pSignal + ) +{ + if (pSignal) { + //pSignal->pComp = NULL; + pSignal->pComp = kzalloc(sizeof(struct completion),GFP_KERNEL); + if (!pSignal->pComp){ + osal_info_print("%s:completion memory allocate fail!\n",__func__); + return -1; + } + init_completion((struct completion *)pSignal->pComp); + return 0; + } + else { + return -2; + } +} + +INT32 +osal_wait_for_signal ( + P_OSAL_SIGNAL pSignal + ) +{ + if (pSignal) { + wait_for_completion_interruptible((struct completion *)pSignal->pComp); + return 0; + } + else { + return -1; + } +} + +INT32 +osal_wait_for_signal_timeout ( + P_OSAL_SIGNAL pSignal + ) +{ + /* return wait_for_completion_interruptible_timeout(&pSignal->comp, msecs_to_jiffies(pSignal->timeoutValue));*/ + /* [ChangeFeature][George] gps driver may be closed by -ERESTARTSYS. + * Avoid using *interruptible" version in order to complete our jobs, such + * as function off gracefully. + */ + return wait_for_completion_timeout((struct completion *)pSignal->pComp, msecs_to_jiffies(pSignal->timeoutValue)); +} + +INT32 +osal_raise_signal ( + P_OSAL_SIGNAL pSignal + ) +{ + // TODO:[FixMe][GeorgeKuo]: DO sanity check here!!! + if(pSignal && pSignal->pComp){ + complete((struct completion *)pSignal->pComp); + return 0; + } + else + { + return -1; + } +} + +INT32 +osal_signal_deinit ( + P_OSAL_SIGNAL pSignal + ) +{ + // TODO:[FixMe][GeorgeKuo]: DO sanity check here!!! + if(pSignal) + { + if (pSignal->pComp){ + kfree(pSignal->pComp); + pSignal->pComp = NULL; + } + pSignal->timeoutValue = 0; + return 0; + } + else + { + return -1; + } +} + + +/* + *OSAL layer Event Opeartion releated APIs + *initialization + *wait for signal + *wait for signal timerout + *raise signal + *destroy a signal + * +*/ + +INT32 osal_event_init ( + P_OSAL_EVENT pEvent + ) +{ + //pEvent->pWaitQueue = NULL; /* [FIXME] why? */ + pEvent->pWaitQueue = kzalloc(sizeof(wait_queue_head_t),GFP_KERNEL); + if (!pEvent->pWaitQueue){ + osal_info_print("%s:waitqueue memory allocate fail!\n",__func__); + return -1; + } + init_waitqueue_head((wait_queue_head_t *)pEvent->pWaitQueue); + + return 0; +} + +INT32 osal_wait_for_event( + P_OSAL_EVENT pEvent, + INT32 (*condition)(PVOID), + void *cond_pa + ) +{ + return wait_event_interruptible((*(wait_queue_head_t *)pEvent->pWaitQueue), condition(cond_pa)); +} + +INT32 osal_wait_for_event_timeout( + P_OSAL_EVENT pEvent, + INT32 (*condition)(PVOID), + void *cond_pa + ) +{ + return wait_event_interruptible_timeout((*(wait_queue_head_t *)pEvent->pWaitQueue), condition(cond_pa), msecs_to_jiffies(pEvent->timeoutValue)); +} + +INT32 osal_trigger_event( + P_OSAL_EVENT pEvent + ) +{ + INT32 ret = 0; + wake_up_interruptible((wait_queue_head_t *)pEvent->pWaitQueue); + return ret; +} + +INT32 +osal_event_deinit ( + P_OSAL_EVENT pEvent + ) +{ + if (pEvent->pWaitQueue){ + kfree(pEvent->pWaitQueue); + pEvent->pWaitQueue = NULL; + } + return 0; +} + +LONG osal_wait_for_event_bit_set(P_OSAL_EVENT pEvent, PULONG pState, UINT32 bitOffset) +{ + UINT32 ms = pEvent->timeoutValue; + if (ms != 0) + { + return wait_event_interruptible_timeout((*(wait_queue_head_t *)pEvent->pWaitQueue), test_bit(bitOffset, pState), msecs_to_jiffies(ms)); + } + else + { + return wait_event_interruptible((*(wait_queue_head_t *)pEvent->pWaitQueue), test_bit(bitOffset, pState)); + } + +} + +LONG osal_wait_for_event_bit_clr(P_OSAL_EVENT pEvent, PULONG pState, UINT32 bitOffset) +{ + UINT32 ms = pEvent->timeoutValue; + if (ms != 0) + { + return wait_event_interruptible_timeout((*(wait_queue_head_t *)pEvent->pWaitQueue), !test_bit(bitOffset, pState), msecs_to_jiffies(ms)); + } + else + { + return wait_event_interruptible((*(wait_queue_head_t *)pEvent->pWaitQueue), !test_bit(bitOffset, pState)); + } + +} + +/* + *bit test and set/clear operations APIs + * + * +*/ +#if OS_BIT_OPS_SUPPORT +#define osal_bit_op_lock(x) +#define osal_bit_op_unlock(x) +#else + +INT32 osal_bit_op_lock(P_OSAL_UNSLEEPABLE_LOCK pLock) +{ + + return 0; +} + +INT32 osal_bit_op_unlock(P_OSAL_UNSLEEPABLE_LOCK pLock) +{ + + return 0; +} +#endif +INT32 osal_clear_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData) +{ + osal_bit_op_lock(&(pData->opLock)); + clear_bit(bitOffset, &pData->data); + osal_bit_op_unlock(&(pData->opLock)); + return 0; +} + +INT32 osal_set_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData) +{ + osal_bit_op_lock(&(pData->opLock)); + set_bit(bitOffset, &pData->data); + osal_bit_op_unlock(&(pData->opLock)); + return 0; +} + +INT32 osal_test_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData) +{ + UINT32 iRet = 0; + osal_bit_op_lock(&(pData->opLock)); + iRet = test_bit(bitOffset, &pData->data); + osal_bit_op_unlock(&(pData->opLock)); + return iRet; +} + +INT32 osal_test_and_clear_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData) +{ + UINT32 iRet = 0; + osal_bit_op_lock(&(pData->opLock)); + iRet = test_and_clear_bit(bitOffset, &pData->data); + osal_bit_op_unlock(&(pData->opLock)); + return iRet; + +} + +INT32 osal_test_and_set_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData) +{ + UINT32 iRet = 0; + osal_bit_op_lock(&(pData->opLock)); + iRet = test_and_set_bit(bitOffset, &pData->data); + osal_bit_op_unlock(&(pData->opLock)); + return iRet; +} + + +/* + *tiemr operations APIs + *create + *stop + * modify + *create + *delete + * +*/ + +INT32 osal_timer_create(P_OSAL_TIMER pTimer) +{ + struct timer_list *timer = NULL; + pTimer->pTimer = kzalloc(sizeof(struct timer_list),GFP_KERNEL); + if (!pTimer->pTimer){ + osal_info_print("%s:timer memory allocate fail!\n",__func__); + return -1; + } + timer = (struct timer_list *)pTimer->pTimer; + init_timer(timer); + timer->function = pTimer->timeoutHandler; + timer->data = (unsigned long)pTimer->timeroutHandlerData; + return 0; +} +INT32 osal_timer_start(P_OSAL_TIMER pTimer, UINT32 ms) +{ + + struct timer_list *timer = (struct timer_list *)pTimer->pTimer; + timer->expires = jiffies + msecs_to_jiffies(ms); + add_timer(timer); + return 0; +} + +INT32 osal_timer_stop(P_OSAL_TIMER pTimer) +{ + struct timer_list *timer = (struct timer_list *)pTimer->pTimer; + del_timer(timer); + return 0; +} + +INT32 osal_timer_stop_sync(P_OSAL_TIMER pTimer) +{ + struct timer_list *timer = (struct timer_list *)pTimer->pTimer; + del_timer_sync(timer); + return 0; +} + +INT32 osal_timer_modify(P_OSAL_TIMER pTimer, UINT32 ms) +{ + mod_timer((struct timer_list *)pTimer->pTimer, jiffies + msecs_to_jiffies(ms)); + return 0; +} + +INT32 osal_timer_delete(P_OSAL_TIMER pTimer) +{ + if (pTimer->pTimer){ + kfree(pTimer->pTimer); + pTimer->pTimer = NULL; + } + return 0; +} + +INT32 _osal_fifo_init(OSAL_FIFO *pFifo, UINT8 *buf, UINT32 size) +{ + struct kfifo *fifo = NULL; + INT32 ret = -1; + + if (!pFifo || pFifo->pFifoBody) + { + printk (KERN_ERR "pFifo must be !NULL, pFifo->pFifoBody must be NULL\n"); + printk (KERN_ERR "pFifo(0x%p), pFifo->pFifoBody(0x%p)\n", pFifo, pFifo->pFifoBody); + return -1; + } + + pFifo->fifoSpinlock = NULL; + + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) + pFifo->fifoSpinlock = kzalloc(sizeof(spinlock_t),GFP_ATOMIC); + if (!pFifo->fifoSpinlock){ + osal_info_print("%s:fifo spinlock allocate memory fail!",__func__); + return -2; + } + spin_lock_init((spinlock_t *)pFifo->fifoSpinlock); + fifo = kfifo_alloc(size, /*GFP_KERNEL*/GFP_ATOMIC, (spinlock_t *)pFifo->fifoSpinlock); + if (NULL == fifo) + { + ret = -3; + } + else + { + ret = 0; + } + #else + fifo = kzalloc(sizeof(struct kfifo), GFP_ATOMIC); + if (!buf) + { + /*fifo's buffer is not ready, we allocate automatically*/ + ret = kfifo_alloc(fifo, size, /*GFP_KERNEL*/GFP_ATOMIC); + } + else + { + if (is_power_of_2(size)) + { + kfifo_init(fifo, buf, size); + ret = 0; + } + else + { + kfifo_free(fifo); + fifo = NULL; + ret = -1; + } + } + #endif + pFifo->pFifoBody = fifo; + return (ret < 0) ? (-1) : (0); +} + +INT32 _osal_fifo_deinit(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + + if (!pFifo || !pFifo->pFifoBody) + { + printk("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + { + kfifo_free(fifo); + } + + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) + if (pFifo->fifoSpinlock) + { + kfree(pFifo->fifoSpinlock); + pFifo->fifoSpinlock = NULL; + } + #endif + return 0; +} + +INT32 _osal_fifo_size(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + INT32 ret = 0; + + if (!pFifo || !pFifo->pFifoBody) + { + printk("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + { + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) + ret = fifo->size; + #else + ret = kfifo_size(fifo); + #endif + + } + + return ret; +} + +/*returns unused bytes in fifo*/ +INT32 _osal_fifo_avail_size(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + INT32 ret = 0; + + if (!pFifo || !pFifo->pFifoBody) + { + printk("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + { + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) + ret = fifo->size - kfifo_len(fifo); + #else + ret = kfifo_avail(fifo); + #endif + } + + return ret; +} + +/*returns used bytes in fifo*/ +INT32 _osal_fifo_len(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + INT32 ret = 0; + + if (!pFifo || !pFifo->pFifoBody) + { + printk("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + { + ret = kfifo_len(fifo); + } + + return ret; +} + +INT32 _osal_fifo_is_empty(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + INT32 ret = 0; + + if (!pFifo || !pFifo->pFifoBody) + { + printk("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + { + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) + ret = (fifo->in == fifo->out); + #else + ret = kfifo_is_empty(fifo); + #endif + } + + return ret; +} + +INT32 _osal_fifo_is_full(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + INT32 ret = 0; + + if (!pFifo || !pFifo->pFifoBody) + { + printk("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + { + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) + ret = (fifo->size == _osal_fifo_len(pFifo)); + #else + ret = kfifo_is_full(fifo); + #endif + } + + return ret; +} + +INT32 _osal_fifo_data_in(OSAL_FIFO *pFifo, const VOID *buf, UINT32 len) +{ + struct kfifo *fifo = NULL; + INT32 ret = 0; + + if (!pFifo || !pFifo->pFifoBody) + { + printk("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo && buf && (len <= _osal_fifo_avail_size(pFifo))) + { + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) + ret = kfifo_put(fifo, buf, len); + #else + ret = kfifo_in(fifo, buf, len); + #endif + + } + else + { + printk("%s: kfifo_in, error, len = %d, _osal_fifo_avail_size = %d, buf=%p\n", + __func__, len, _osal_fifo_avail_size(pFifo), buf); + + ret = 0; + } + + return ret; +} + +INT32 _osal_fifo_data_out(OSAL_FIFO *pFifo, void *buf, UINT32 len) +{ + struct kfifo *fifo = NULL; + INT32 ret = 0; + + if (!pFifo || !pFifo->pFifoBody) + { + printk("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo && buf && (len <= _osal_fifo_len(pFifo))) + { + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) + ret = kfifo_get(fifo, buf, len); + #else + ret = kfifo_out(fifo, buf, len); + #endif + } + else + { + printk("%s: kfifo_out, error, len = %d, osal_fifo_len = %d, buf=%p\n", + __func__, len, _osal_fifo_len(pFifo), buf); + + ret = 0; + } + + return ret; +} + +INT32 _osal_fifo_reset(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + + if (!pFifo || !pFifo->pFifoBody) + { + printk("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + { + kfifo_reset(fifo); + } + + return 0; +} + +INT32 osal_fifo_init(P_OSAL_FIFO pFifo, UINT8 *buffer, UINT32 size) +{ + if (!pFifo) + { + printk("%s:pFifo = NULL, error\n", __func__); + return -1; + } + + pFifo->FifoInit = _osal_fifo_init; + pFifo->FifoDeInit = _osal_fifo_deinit; + pFifo->FifoSz = _osal_fifo_size; + pFifo->FifoAvailSz = _osal_fifo_avail_size; + pFifo->FifoLen = _osal_fifo_len; + pFifo->FifoIsEmpty = _osal_fifo_is_empty; + pFifo->FifoIsFull = _osal_fifo_is_full; + pFifo->FifoDataIn = _osal_fifo_data_in; + pFifo->FifoDataOut = _osal_fifo_data_out; + pFifo->FifoReset = _osal_fifo_reset; + + if (NULL != pFifo->pFifoBody) + { + printk("%s:Becasue pFifo room is avialable, we clear the room and allocate them again.\n", __func__); + pFifo->FifoDeInit(pFifo->pFifoBody); + pFifo->pFifoBody = NULL; + } + + pFifo->FifoInit(pFifo, buffer, size); + + return 0; +} + +VOID osal_fifo_deinit(P_OSAL_FIFO pFifo) +{ + if (pFifo) + { + pFifo->FifoDeInit(pFifo); + } + else + { + printk("%s:pFifo = NULL, error\n", __func__); + } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) + +#else + + if (pFifo->pFifoBody) + { + kfree(pFifo->pFifoBody); + } +#endif +} + +INT32 osal_fifo_reset(P_OSAL_FIFO pFifo) +{ + if (pFifo) + { + return pFifo->FifoReset(pFifo); + } + else + { + printk("%s:pFifo = NULL, error\n", __func__); + return -1; + } +} + +UINT32 osal_fifo_in(P_OSAL_FIFO pFifo, PUINT8 buffer, UINT32 size) +{ + if (pFifo) + { + return pFifo->FifoDataIn(pFifo, buffer, size); + } + else + { + printk("%s:pFifo = NULL, error\n", __func__); + return 0; + } +} + +UINT32 osal_fifo_out(P_OSAL_FIFO pFifo, PUINT8 buffer, UINT32 size) +{ + if (pFifo) + { + return pFifo->FifoDataOut(pFifo, buffer, size); + } + else + { + printk("%s:pFifo = NULL, error\n", __func__); + return 0; + } +} + +UINT32 osal_fifo_len(P_OSAL_FIFO pFifo) +{ + if (pFifo) + { + return pFifo->FifoLen(pFifo); + } + else + { + printk("%s:pFifo = NULL, error\n", __func__); + return 0; + } +} + +UINT32 osal_fifo_sz(P_OSAL_FIFO pFifo) +{ + if (pFifo) + { + return pFifo->FifoSz(pFifo); + } + else + { + printk("%s:pFifo = NULL, error\n", __func__); + return 0; + } +} + +UINT32 osal_fifo_avail(P_OSAL_FIFO pFifo) +{ + if (pFifo) + { + return pFifo->FifoAvailSz(pFifo); + } + else + { + printk("%s:pFifo = NULL, error\n", __func__); + return 0; + } +} + +UINT32 osal_fifo_is_empty(P_OSAL_FIFO pFifo) +{ + if (pFifo) + { + return pFifo->FifoIsEmpty(pFifo); + } + else + { + printk("%s:pFifo = NULL, error\n", __func__); + return 0; + } +} + +UINT32 osal_fifo_is_full(P_OSAL_FIFO pFifo) +{ + if (pFifo) + { + return pFifo->FifoIsFull(pFifo); + } + else + { + printk("%s:pFifo = NULL, error\n", __func__); + return 0; + } +} + +INT32 osal_wake_lock_init(P_OSAL_WAKE_LOCK pLock) +{ + if (!pLock) + { + return -1; + } + else + { + pLock->pWakeLock = kzalloc(sizeof(struct wake_lock), GFP_KERNEL); + if (!pLock->pWakeLock) + { + osal_info_print("%s:wake lock memory allocate fail!\n",__func__); + return -2; + } + wake_lock_init((struct wake_lock *)pLock->pWakeLock, WAKE_LOCK_SUSPEND, pLock->name); + + return 0; + } +} + +INT32 osal_wake_lock_deinit(P_OSAL_WAKE_LOCK pLock) +{ + if (!pLock) + { + return -1; + } + else + { + wake_lock_destroy((struct wake_lock *)pLock->pWakeLock); + if (pLock->pWakeLock) + { + kfree(pLock->pWakeLock); + pLock->pWakeLock = NULL; + } + return 0; + } +} + +INT32 osal_wake_lock(P_OSAL_WAKE_LOCK pLock) +{ + if (!pLock) + { + return -1; + } + else + { + wake_lock((struct wake_lock *)pLock->pWakeLock); + + return 0; + } +} + + +INT32 osal_wake_unlock(P_OSAL_WAKE_LOCK pLock) +{ + if (!pLock) + { + return -1; + } + else + { + wake_unlock((struct wake_lock *)pLock->pWakeLock); + + return 0; + } +} + +INT32 osal_wake_lock_count(P_OSAL_WAKE_LOCK pLock) +{ + INT32 count = 0; + + if (!pLock) + { + return -1; + } + else + { + count = wake_lock_active((struct wake_lock *)pLock->pWakeLock); + return count; + } +} + +/* + *sleepable lock operations APIs + *init + *lock + *unlock + *destroy + * +*/ + +INT32 osal_unsleepable_lock_init (P_OSAL_UNSLEEPABLE_LOCK pUSL) +{ + /* sanity check on input parameter */ + if (!pUSL || pUSL->pLock) { + printk(KERN_WARNING "ERROR!!pUSL(0x%p)->pLock(0x%p)!\n", + pUSL, (pUSL) ? pUSL->pLock : 0x0); + return -1; + } + + pUSL->pLock = kzalloc(sizeof(spinlock_t),GFP_ATOMIC); + if (!pUSL->pLock){ + osal_info_print("%s:spinlock memory allocate fail!\n",__func__); + return -1; + } + + spin_lock_init((spinlock_t *)pUSL->pLock); + return 0; +} + +INT32 osal_lock_unsleepable_lock (P_OSAL_UNSLEEPABLE_LOCK pUSL) +{ + /* sanity check on input parameter */ + if (!pUSL || !pUSL->pLock) { + printk(KERN_WARNING "ERROR!!pUSL(0x%p)->pLock(0x%p)!\n", + pUSL, (pUSL) ? pUSL->pLock : 0x0); + return -1; + } + + spin_lock_irqsave((spinlock_t *)pUSL->pLock, pUSL->flag); + return 0; +} + +INT32 osal_unlock_unsleepable_lock (P_OSAL_UNSLEEPABLE_LOCK pUSL) +{ + /* sanity check on input parameter */ + if (!pUSL || !pUSL->pLock) { + printk(KERN_WARNING "ERROR!!pUSL(0x%p)->pLock(0x%p)!\n", + pUSL, (pUSL) ? pUSL->pLock : 0x0); + return -1; + } + + spin_unlock_irqrestore((spinlock_t *)pUSL->pLock, pUSL->flag); + return 0; +} + +extern INT32 osal_unsleepable_lock_deinit (P_OSAL_UNSLEEPABLE_LOCK pUSL) +{ + /* sanity check on input parameter */ + if (!pUSL || !pUSL->pLock) { + printk(KERN_WARNING "ERROR!!pUSL(0x%p)->pLock(0x%p)!\n", + pUSL, (pUSL) ? pUSL->pLock : 0x0); + return -1; + } + + if (pUSL->pLock){ + kfree(pUSL->pLock); + pUSL->pLock = NULL; + } + + return 0; +} + +/* + *unsleepable operations APIs + *init + *lock + *unlock + *destroy + + * +*/ + +INT32 osal_sleepable_lock_init (P_OSAL_SLEEPABLE_LOCK pSL) +{ + /* sanity check on input parameter */ + if (!pSL || pSL->pLock) { + printk(KERN_WARNING "ERROR!!pSL(0x%p)->pLock(0x%p)!\n", + pSL, (pSL) ? pSL->pLock : 0x0); + return -1; + } + + pSL->pLock = kzalloc(sizeof(struct mutex),GFP_KERNEL); + if (!pSL->pLock){ + osal_info_print("%s:mutex memory allocate fail!\n",__func__); + return -1; + } + + mutex_init ((struct mutex *)pSL->pLock); + return 0; +} + +INT32 osal_lock_sleepable_lock (P_OSAL_SLEEPABLE_LOCK pSL) +{ + /* sanity check on input parameter */ + if (!pSL || !pSL->pLock) { + printk(KERN_WARNING "ERROR!!pSL(0x%p)->pLock(0x%p)!\n", + pSL, (pSL) ? pSL->pLock : 0x0); + return -1; + } + + return mutex_lock_interruptible((struct mutex *)pSL->pLock); +} + +INT32 osal_unlock_sleepable_lock (P_OSAL_SLEEPABLE_LOCK pSL) +{ + /* sanity check on input parameter */ + if (!pSL || !pSL->pLock) { + printk(KERN_WARNING "ERROR!!pSL(0x%p)->pLock(0x%p)!\n", + pSL, (pSL) ? pSL->pLock : 0x0); + return -1; + } + + mutex_unlock((struct mutex *)pSL->pLock); + return 0; +} + + +INT32 osal_sleepable_lock_deinit (P_OSAL_SLEEPABLE_LOCK pSL) +{ + /* sanity check on input parameter */ + if (!pSL || !pSL->pLock) { + printk(KERN_WARNING "ERROR!!pSL(0x%p)->pLock(0x%p)!\n", + pSL, (pSL) ? pSL->pLock : 0x0); + return -1; + } + + mutex_destroy ((struct mutex *)pSL->pLock); + + if (pSL->pLock){ + kfree(pSL->pLock); + pSL->pLock = NULL; + } + + return 0; +} + +INT32 osal_msleep(UINT32 ms) +{ + msleep(ms); + return 0; +} + +INT32 osal_gettimeofday(PINT32 sec, PINT32 usec) +{ + INT32 ret = 0; + struct timeval now; + + do_gettimeofday(&now); + + if (sec != NULL) + *sec = now.tv_sec; + else + ret = -1; + + if (usec != NULL) + *usec = now.tv_usec; + else + ret = -1; + + return ret; +} + +INT32 osal_printtimeofday(const PUINT8 prefix) +{ + INT32 ret; + INT32 sec; + INT32 usec; + + ret = osal_gettimeofday(&sec, &usec); + ret += osal_dbg_print("%s>sec=%d, usec=%d\n",prefix, sec, usec); + + return ret; +} + +VOID +osal_buffer_dump ( + const UINT8 *buf, + const UINT8 *title, + const UINT32 len, + const UINT32 limit + ) +{ + INT32 k; + UINT32 dump_len; + + printk("start of dump>[%s] len=%d, limit=%d,", title, len, limit); + + dump_len = ((0 != limit) && (len > limit)) ? limit : len; +#if 0 + if (limit != 0) + { + len = (len > limit)? (limit) : (len); + } +#endif + + for (k = 0; k < dump_len ; k++) { + if ((k != 0) && ( k % 16 == 0)) printk("\n"); + printk("0x%02x ", buf[k]); + } + printk("op.opId : 0xFFFFFFFF; +} + +MTK_WCN_BOOL osal_op_is_wait_for_signal(P_OSAL_OP pOp) +{ + return (pOp && pOp->signal.timeoutValue) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE; +} + +VOID osal_op_raise_signal(P_OSAL_OP pOp, INT32 result) +{ + if (pOp) + { + pOp->result = result; + osal_raise_signal(&pOp->signal); + } +} + + diff --git a/drivers/mtk_wcn_combo/common/linux/stp_chrdev_bt.c b/drivers/mtk_wcn_combo/common/linux/stp_chrdev_bt.c new file mode 100755 index 000000000000..e7b6ddc50947 --- /dev/null +++ b/drivers/mtk_wcn_combo/common/linux/stp_chrdev_bt.c @@ -0,0 +1,527 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "stp_exp.h" +#include "wmt_exp.h" + +MODULE_LICENSE("Dual BSD/GPL"); + +#define BT_DRIVER_NAME "mtk_stp_BT_chrdev" +#define BT_DEV_MAJOR 192 // never used number + +#define PFX "[MTK-BT] " +#define BT_LOG_DBG 3 +#define BT_LOG_INFO 2 +#define BT_LOG_WARN 1 +#define BT_LOG_ERR 0 + +#define COMBO_IOC_BT_HWVER 6 + +unsigned int gDbgLevel = BT_LOG_ERR;//BT_LOG_INFO; //Modify loglevel + +#define BT_DBG_FUNC(fmt, arg...) if(gDbgLevel >= BT_LOG_DBG){ printk(PFX "%s: " fmt, __FUNCTION__ ,##arg);} +#define BT_INFO_FUNC(fmt, arg...) if(gDbgLevel >= BT_LOG_INFO){ printk(PFX "%s: " fmt, __FUNCTION__ ,##arg);} +#define BT_WARN_FUNC(fmt, arg...) if(gDbgLevel >= BT_LOG_WARN){ printk(PFX "%s: " fmt, __FUNCTION__ ,##arg);} +#define BT_ERR_FUNC(fmt, arg...) if(gDbgLevel >= BT_LOG_ERR){ printk(PFX "%s: " fmt, __FUNCTION__ ,##arg);} +#define BT_TRC_FUNC(f) if(gDbgLevel >= BT_LOG_DBG){printk(PFX "<%s> <%d>\n", __FUNCTION__, __LINE__);} + +#define VERSION "1.0" +#define BT_NVRAM_CUSTOM_NAME "/data/BT_Addr" + +static int BT_devs = 1; /* device count */ +static int BT_major = BT_DEV_MAJOR; /* dynamic allocation */ +module_param(BT_major, uint, 0); +static struct cdev BT_cdev; + +static unsigned char i_buf[MTKSTP_BUFFER_SIZE]; // input buffer of read() +static unsigned char o_buf[MTKSTP_BUFFER_SIZE]; // output buffer of write() +static struct semaphore wr_mtx, rd_mtx; +static wait_queue_head_t inq; /* read queues */ +static DECLARE_WAIT_QUEUE_HEAD(BT_wq); +static int flag = 0; +volatile int retflag = 0; + +unsigned char g_bt_bd_addr[10]={0x01,0x1a,0xfc,0x06,0x00,0x55,0x66,0x77,0x88,0x00}; +unsigned char g_nvram_btdata[8]; + +static int nvram_read(char *filename, char *buf, ssize_t len, int offset) +{ + struct file *fd; + //ssize_t ret; + int retLen = -1; + + mm_segment_t old_fs = get_fs(); + set_fs(KERNEL_DS); + + fd = filp_open(filename, O_WRONLY|O_CREAT, 0644); + + if(IS_ERR(fd)) { + BT_ERR_FUNC("failed to open!!\n"); + return -1; + } + do{ + if ((fd->f_op == NULL) || (fd->f_op->read == NULL)) + { + BT_ERR_FUNC("file can not be read!!\n"); + break; + } + + if (fd->f_pos != offset) { + if (fd->f_op->llseek) { + if(fd->f_op->llseek(fd, offset, 0) != offset) { + BT_ERR_FUNC("[nvram_read] : failed to seek!!\n"); + break; + } + } else { + fd->f_pos = offset; + } + } + + retLen = fd->f_op->read(fd, + buf, + len, + &fd->f_pos); + + }while(false); + + filp_close(fd, NULL); + + set_fs(old_fs); + + return retLen; +} + + +int platform_load_nvram_data( char * filename, char * buf, int len) +{ + //int ret; + BT_INFO_FUNC("platform_load_nvram_data ++ BDADDR\n"); + + return nvram_read( filename, buf, len, 0); +} + +static void bt_cdev_rst_cb( + ENUM_WMTDRV_TYPE_T src, + ENUM_WMTDRV_TYPE_T dst, + ENUM_WMTMSG_TYPE_T type, + void *buf, + unsigned int sz){ + + /* + To handle reset procedure please + */ + ENUM_WMTRSTMSG_TYPE_T rst_msg; + + BT_INFO_FUNC("sizeof(ENUM_WMTRSTMSG_TYPE_T) = %d\n", sizeof(ENUM_WMTRSTMSG_TYPE_T)); + if(sz <= sizeof(ENUM_WMTRSTMSG_TYPE_T)){ + memcpy((char *)&rst_msg, (char *)buf, sz); + BT_INFO_FUNC("src = %d, dst = %d, type = %d, buf = 0x%x sz = %d, max = %d\n", src, dst, type, rst_msg, sz, WMTRSTMSG_RESET_MAX); + if((src == WMTDRV_TYPE_WMT) && + (dst == WMTDRV_TYPE_BT) && + (type == WMTMSG_TYPE_RESET)){ + if(rst_msg == WMTRSTMSG_RESET_START){ + BT_INFO_FUNC("BT restart start!\n"); + retflag = 1; + wake_up_interruptible(&inq); + /*reset_start message handling*/ + + } else if(rst_msg == WMTRSTMSG_RESET_END){ + BT_INFO_FUNC("BT restart end!\n"); + retflag = 2; + wake_up_interruptible(&inq); + /*reset_end message handling*/ + } + } + } else { + /*message format invalid*/ + BT_INFO_FUNC("message format invalid!\n"); + } +} + +void BT_event_cb(void) +{ + BT_DBG_FUNC("BT_event_cb() \n"); + + flag = 1; + wake_up(&BT_wq); + + /* finally, awake any reader */ + wake_up_interruptible(&inq); /* blocked in read() and select() */ + + return; +} + +unsigned int BT_poll(struct file *filp, poll_table *wait) +{ + unsigned int mask = 0; + +// down(&wr_mtx); + /* + * The buffer is circular; it is considered full + * if "wp" is right behind "rp". "left" is 0 if the + * buffer is empty, and it is "1" if it is completely full. + */ + if (mtk_wcn_stp_is_rxqueue_empty(BT_TASK_INDX)) + { + poll_wait(filp, &inq, wait); + + /* empty let select sleep */ + if((!mtk_wcn_stp_is_rxqueue_empty(BT_TASK_INDX)) || retflag) + { + mask |= POLLIN | POLLRDNORM; /* readable */ + } + } + else + { + mask |= POLLIN | POLLRDNORM; /* readable */ + } + + /* do we need condition? */ + mask |= POLLOUT | POLLWRNORM; /* writable */ +// up(&wr_mtx); + return mask; +} + + +ssize_t BT_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) +{ + int retval = 0; + int written = 0; + down(&wr_mtx); + + BT_DBG_FUNC("%s: count %d pos %lld\n", __func__, count, *f_pos); + if(retflag) + { + if (retflag == 1) //reset start + { + retval = -88; + BT_INFO_FUNC("MT6620 reset Write: start\n"); + } + else if (retflag == 2) // reset end + { + retval = -99; + BT_INFO_FUNC("MT6620 reset Write: end\n"); + } + goto OUT; + } + + if (count > 0) + { + int copy_size = (count < MTKSTP_BUFFER_SIZE) ? count : MTKSTP_BUFFER_SIZE; + if (copy_from_user(&o_buf[0], &buf[0], copy_size)) + { + retval = -EFAULT; + goto OUT; + } + //printk("%02x ", val); + + written = mtk_wcn_stp_send_data(&o_buf[0], copy_size, BT_TASK_INDX); + if(0 == written) + { + retval = -ENOSPC; + /*no windowspace in STP is available, native process should not call BT_write with no delay at all*/ + BT_ERR_FUNC("target packet length:%d, write success length:%d, retval = %d.\n", count, written, retval); + } + else + { + retval = written; + } + + }else + { + retval = -EFAULT; + BT_ERR_FUNC("target packet length:%d is not allowed, retval = %d.\n", count, retval); + } + +OUT: + up(&wr_mtx); + return (retval); +} + +ssize_t BT_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + int retval = 0; + + down(&rd_mtx); + + BT_DBG_FUNC("BT_read(): count %d pos %lld\n", count, *f_pos); + if(retflag) + { + if (retflag == 1) //reset start + { + retval = -88; + BT_INFO_FUNC("MT6620 reset Read: start\n"); + } + else if (retflag == 2) // reset end + { + retval = -99; + BT_INFO_FUNC("MT6620 reset Read: end\n"); + } + goto OUT; + } + + if(count > MTKSTP_BUFFER_SIZE) + { + count = MTKSTP_BUFFER_SIZE; + } + retval = mtk_wcn_stp_receive_data(i_buf, count, BT_TASK_INDX); + + while(retval == 0) // got nothing, wait for STP's signal + { + /*If nonblocking mode, return directly O_NONBLOCK is specified during open() */ + if (filp->f_flags & O_NONBLOCK){ + BT_DBG_FUNC("Non-blocking BT_read() \n"); + retval = -EAGAIN; + goto OUT; + } + + BT_DBG_FUNC("BT_read(): wait_event 1\n"); + wait_event(BT_wq, flag != 0); + BT_DBG_FUNC("BT_read(): wait_event 2\n"); + flag = 0; + retval = mtk_wcn_stp_receive_data(i_buf, count, BT_TASK_INDX); + BT_DBG_FUNC("BT_read(): mtk_wcn_stp_receive_data() = %d\n", retval); + } + + // we got something from STP driver + if (copy_to_user(buf, i_buf, retval)) + { + retval = -EFAULT; + goto OUT; + } + +OUT: + up(&rd_mtx); + BT_DBG_FUNC("BT_read(): retval = %d\n", retval); + return (retval); +} + +//int BT_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +long BT_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int retval = 0; + + + ENUM_WMTHWVER_TYPE_T hw_ver_sym = WMTHWVER_INVALID; + BT_DBG_FUNC("BT_ioctl(): cmd (%d)\n", cmd); + + switch(cmd) + { +#if 0 + case 0: // enable/disable STP + /* George: STP is controlled by WMT only */ + /* mtk_wcn_stp_enable(arg); */ + break; +#endif + case 1: // send raw data + BT_DBG_FUNC("BT_ioctl(): disable raw data from BT dev \n"); + retval = -EINVAL; + break; + case COMBO_IOC_BT_HWVER: + /*get combo hw version*/ + hw_ver_sym = mtk_wcn_wmt_hwver_get(); + + BT_INFO_FUNC("BT_ioctl(): get hw version = %d, sizeof(hw_ver_sym) = %d\n", hw_ver_sym, sizeof(hw_ver_sym)); + if(copy_to_user((int __user *)arg, &hw_ver_sym, sizeof(hw_ver_sym))){ + retval = -EFAULT; + } + break; + default: + retval = -EFAULT; + BT_DBG_FUNC("BT_ioctl(): unknown cmd (%d)\n", cmd); + break; + } + + return retval; +} + +static int BT_open(struct inode *inode, struct file *file) +{ + BT_INFO_FUNC("%s: major %d minor %d (pid %d)\n", __func__, + imajor(inode), + iminor(inode), + current->pid + ); + +#if 1 /* GeorgeKuo: turn on function before check stp ready */ + /* turn on BT */ + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_BT)) { + BT_WARN_FUNC("WMT turn on BT fail!\n"); + return -ENODEV; + }else{ + retflag = 0; + mtk_wcn_wmt_msgcb_reg(WMTDRV_TYPE_BT, bt_cdev_rst_cb); + BT_INFO_FUNC("WMT register BT rst cb!\n"); + } +#endif + + if (mtk_wcn_stp_is_ready()) { +#if 0 /* GeorgeKuo: turn on function before check stp ready */ + /* turn on BT */ + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_BT)) { + BT_WARN_FUNC("WMT turn on BT fail!\n"); + return -ENODEV; + } +#endif + mtk_wcn_stp_set_bluez(0); + + BT_INFO_FUNC("Now it's in MTK Bluetooth Mode\n"); + BT_INFO_FUNC("WMT turn on BT OK!\n"); + BT_INFO_FUNC("STP is ready!\n"); + platform_load_nvram_data(BT_NVRAM_CUSTOM_NAME, + (char *)&g_nvram_btdata, sizeof(g_nvram_btdata)); + + BT_INFO_FUNC("Read NVRAM : BD address %02x%02x%02x%02x%02x%02x Cap 0x%02x Codec 0x%02x\n", + g_nvram_btdata[0], g_nvram_btdata[1], g_nvram_btdata[2], + g_nvram_btdata[3], g_nvram_btdata[4], g_nvram_btdata[5], + g_nvram_btdata[6], g_nvram_btdata[7]); + + mtk_wcn_stp_register_event_cb(BT_TASK_INDX, BT_event_cb); + } + else { + BT_ERR_FUNC("STP is not ready\n"); + + /*return error code*/ + return -ENODEV; + } + +// init_MUTEX(&wr_mtx); + sema_init(&wr_mtx, 1); +// init_MUTEX(&rd_mtx); + sema_init(&rd_mtx, 1); + + return 0; +} + +static int BT_close(struct inode *inode, struct file *file) +{ + BT_INFO_FUNC("%s: major %d minor %d (pid %d)\n", __func__, + imajor(inode), + iminor(inode), + current->pid + ); + retflag = 0; + mtk_wcn_wmt_msgcb_unreg(WMTDRV_TYPE_BT); + mtk_wcn_stp_register_event_cb(BT_TASK_INDX, NULL); + + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_off(WMTDRV_TYPE_BT)) { + BT_INFO_FUNC("WMT turn off BT fail!\n"); + return -EIO; //mostly, native programmer will not check this return value. + } + else { + BT_INFO_FUNC("WMT turn off BT OK!\n"); + } + + return 0; +} + +struct file_operations BT_fops = { + .open = BT_open, + .release = BT_close, + .read = BT_read, + .write = BT_write, +// .ioctl = BT_ioctl, + .unlocked_ioctl = BT_unlocked_ioctl, + .poll = BT_poll +}; + +static int BT_init(void) +{ + dev_t dev = MKDEV(BT_major, 0); + int alloc_ret = 0; + int cdev_err = 0; + + /*static allocate chrdev*/ + alloc_ret = register_chrdev_region(dev, 1, BT_DRIVER_NAME); + if (alloc_ret) { + BT_ERR_FUNC("fail to register chrdev\n"); + return alloc_ret; + } + + cdev_init(&BT_cdev, &BT_fops); + BT_cdev.owner = THIS_MODULE; + + cdev_err = cdev_add(&BT_cdev, dev, BT_devs); + if (cdev_err) + goto error; + + BT_INFO_FUNC("%s driver(major %d) installed.\n", BT_DRIVER_NAME, BT_major); + retflag = 0; + mtk_wcn_stp_register_event_cb(BT_TASK_INDX, NULL); + + /* init wait queue */ + init_waitqueue_head(&(inq)); + + return 0; + +error: + if (cdev_err == 0) + cdev_del(&BT_cdev); + + if (alloc_ret == 0) + unregister_chrdev_region(dev, BT_devs); + + return -1; +} + +static void BT_exit(void) +{ + dev_t dev = MKDEV(BT_major, 0); + retflag = 0; + mtk_wcn_stp_register_event_cb(BT_TASK_INDX, NULL); // unregister event callback function + + cdev_del(&BT_cdev); + unregister_chrdev_region(dev, BT_devs); + + BT_INFO_FUNC("%s driver removed.\n", BT_DRIVER_NAME); +} + +module_init(BT_init); +module_exit(BT_exit); + + diff --git a/drivers/mtk_wcn_combo/common/linux/stp_chrdev_gps.c b/drivers/mtk_wcn_combo/common/linux/stp_chrdev_gps.c new file mode 100755 index 000000000000..2ade72e50c63 --- /dev/null +++ b/drivers/mtk_wcn_combo/common/linux/stp_chrdev_gps.c @@ -0,0 +1,442 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + + +/** $Log: stp_chrdev_gps.c $ + * + * 12 13 2010 Sean.Wang + * (1) Add GPS_DEBUG_TRACE_GPIO to disable GPIO debugging trace + * (2) Add GPS_DEBUG_DUMP to support GPS data dump + * (3) Add mtk_wcn_stp_is_ready() check in GPS_open() +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stp_exp.h" +#include "wmt_exp.h" + +MODULE_LICENSE("GPL"); + +#define GPS_DRIVER_NAME "mtk_stp_GPS_chrdev" +#define GPS_DEV_MAJOR 191 // never used number +#define GPS_DEBUG_TRACE_GPIO 0 +#define GPS_DEBUG_DUMP 0 + +#define PFX "[GPS] " +#define GPS_LOG_DBG 3 +#define GPS_LOG_INFO 2 +#define GPS_LOG_WARN 1 +#define GPS_LOG_ERR 0 + +#define COMBO_IOC_GPS_HWVER 6 + +unsigned int gDbgLevel = GPS_LOG_INFO;/*GPS_LOG_DBG*/ + +#define GPS_DBG_FUNC(fmt, arg...) if(gDbgLevel >= GPS_LOG_DBG){ printk(PFX "%s: " fmt, __FUNCTION__ ,##arg);} +#define GPS_INFO_FUNC(fmt, arg...) if(gDbgLevel >= GPS_LOG_INFO){ printk(PFX "%s: " fmt, __FUNCTION__ ,##arg);} +#define GPS_WARN_FUNC(fmt, arg...) if(gDbgLevel >= GPS_LOG_WARN){ printk(PFX "%s: " fmt, __FUNCTION__ ,##arg);} +#define GPS_ERR_FUNC(fmt, arg...) if(gDbgLevel >= GPS_LOG_ERR){ printk(PFX "%s: " fmt, __FUNCTION__ ,##arg);} +#define GPS_TRC_FUNC(f) if(gDbgLevel >= GPS_LOG_DBG){ printk(PFX "<%s> <%d>\n", __FUNCTION__, __LINE__);} + + +static int GPS_devs = 1; /* device count */ +static int GPS_major = GPS_DEV_MAJOR; /* dynamic allocation */ +module_param(GPS_major, uint, 0); +static struct cdev GPS_cdev; + +static unsigned char i_buf[MTKSTP_BUFFER_SIZE]; // input buffer of read() +static unsigned char o_buf[MTKSTP_BUFFER_SIZE]; // output buffer of write() +static struct semaphore wr_mtx, rd_mtx; +static DECLARE_WAIT_QUEUE_HEAD(GPS_wq); +static int flag = 0; + +static void GPS_event_cb(void); + +ssize_t GPS_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) +{ + int retval = 0; + int written = 0; + down(&wr_mtx); + + //GPS_TRC_FUNC(); + + /*printk("%s: count %d pos %lld\n", __func__, count, *f_pos);*/ + if (count > 0) + { + int copy_size = (count < MTKSTP_BUFFER_SIZE) ? count : MTKSTP_BUFFER_SIZE; + if (copy_from_user(&o_buf[0], &buf[0], copy_size)) + { + retval = -EFAULT; + goto out; + } + //printk("%02x ", val); +#if GPS_DEBUG_TRACE_GPIO + mtk_wcn_stp_debug_gpio_assert(IDX_GPS_TX, DBG_TIE_LOW); +#endif + written = mtk_wcn_stp_send_data(&o_buf[0], copy_size, GPS_TASK_INDX); +#if GPS_DEBUG_TRACE_GPIO + mtk_wcn_stp_debug_gpio_assert(IDX_GPS_TX, DBG_TIE_HIGH); +#endif + +#if GPS_DEBUG_DUMP +{ + unsigned char *buf_ptr = &o_buf[0]; + int k=0; + printk("--[GPS-WRITE]--"); + for(k=0; k < 10 ; k++){ + if(k%16 == 0) printk("\n"); + printk("0x%02x ", o_buf[k]); + } + printk("\n"); +} +#endif + /* + If cannot send successfully, enqueue again + + if (written != copy_size) { + // George: FIXME! Move GPS retry handling from app to driver + } + */ + if(0 == written) + { + retval = -ENOSPC; + /*no windowspace in STP is available, native process should not call GPS_write with no delay at all*/ + GPS_ERR_FUNC("target packet length:%d, write success length:%d, retval = %d.\n", count, written, retval); + } + else + { + retval = written; + } + } + else + { + retval = -EFAULT; + GPS_ERR_FUNC("target packet length:%d is not allowed, retval = %d.\n", count, retval); + } +out: + up(&wr_mtx); + return (retval); +} + +ssize_t GPS_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + long val = 0; + int retval; + + down(&rd_mtx); + +/* printk("GPS_read(): count %d pos %lld\n", count, *f_pos);*/ + + if(count > MTKSTP_BUFFER_SIZE) + { + count = MTKSTP_BUFFER_SIZE; + } + +#if GPS_DEBUG_TRACE_GPIO + mtk_wcn_stp_debug_gpio_assert(IDX_GPS_RX, DBG_TIE_LOW); +#endif + retval = mtk_wcn_stp_receive_data(i_buf, count, GPS_TASK_INDX); +#if GPS_DEBUG_TRACE_GPIO + mtk_wcn_stp_debug_gpio_assert(IDX_GPS_RX, DBG_TIE_HIGH); +#endif + + while(retval == 0) // got nothing, wait for STP's signal + { + /*wait_event(GPS_wq, flag != 0);*/ /* George: let signal wake up */ + val = wait_event_interruptible(GPS_wq, flag != 0); + flag = 0; + +#if GPS_DEBUG_TRACE_GPIO + mtk_wcn_stp_debug_gpio_assert(IDX_GPS_RX, DBG_TIE_LOW); +#endif + + retval = mtk_wcn_stp_receive_data(i_buf, count, GPS_TASK_INDX); + +#if GPS_DEBUG_TRACE_GPIO + mtk_wcn_stp_debug_gpio_assert(IDX_GPS_RX, DBG_TIE_HIGH); +#endif + /* if we are signaled */ + if (val) { + if (-ERESTARTSYS == val) { + GPS_INFO_FUNC("signaled by -ERESTARTSYS(%ld) \n ", val); + } + else { + GPS_INFO_FUNC("signaled by %ld \n ", val); + } + break; + } + } + +#if GPS_DEBUG_DUMP +{ + unsigned char *buf_ptr = &i_buf[0]; + int k=0; + printk("--[GPS-READ]--"); + for(k=0; k < 10 ; k++){ + if(k%16 == 0) printk("\n"); + printk("0x%02x ", i_buf[k]); + } + printk("--\n"); +} +#endif + + if (retval) { + // we got something from STP driver + if (copy_to_user(buf, i_buf, retval)) { + retval = -EFAULT; + goto OUT; + } + else { + /* success */ + } + } + else { + // we got nothing from STP driver, being signaled + retval = val; + } + +OUT: + up(&rd_mtx); +/* printk("GPS_read(): retval = %d\n", retval);*/ + return (retval); +} + +//int GPS_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +long GPS_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int retval = 0; + ENUM_WMTHWVER_TYPE_T hw_ver_sym = WMTHWVER_INVALID; + + GPS_DBG_FUNC("cmd (0x%x)\n", cmd); + + switch (cmd) + { + case COMBO_IOC_GPS_HWVER: + /*get combo hw version*/ + hw_ver_sym = mtk_wcn_wmt_hwver_get(); + GPS_INFO_FUNC("get hw version = %d, sizeof(hw_ver_sym) = %d\n", hw_ver_sym, sizeof(hw_ver_sym)); + if (copy_to_user((int __user *)arg, &hw_ver_sym, sizeof(hw_ver_sym))) { + retval = -EFAULT; + } + break; + + default: + retval = -EFAULT; + GPS_DBG_FUNC(KERN_INFO "GPS_ioctl(): unknown cmd (0x%x)\n", cmd); + break; + } + + return retval; +} + +static void gps_cdev_rst_cb( + ENUM_WMTDRV_TYPE_T src, + ENUM_WMTDRV_TYPE_T dst, + ENUM_WMTMSG_TYPE_T type, + void *buf, + unsigned int sz){ + + /* + To handle reset procedure please + */ + ENUM_WMTRSTMSG_TYPE_T rst_msg; + + GPS_INFO_FUNC("sizeof(ENUM_WMTRSTMSG_TYPE_T) = %d\n", sizeof(ENUM_WMTRSTMSG_TYPE_T)); + if(sz <= sizeof(ENUM_WMTRSTMSG_TYPE_T)){ + memcpy((char *)&rst_msg, (char *)buf, sz); + GPS_INFO_FUNC("src = %d, dst = %d, type = %d, buf = 0x%x sz = %d, max = %d\n", src, dst, type, rst_msg, sz, WMTRSTMSG_RESET_MAX); + if((src==WMTDRV_TYPE_WMT) && + (dst == WMTDRV_TYPE_GPS) && + (type == WMTMSG_TYPE_RESET)){ + if(rst_msg == WMTRSTMSG_RESET_START){ + GPS_INFO_FUNC("gps restart start!\n"); + + /*reset_start message handling*/ + + } else if(rst_msg == WMTRSTMSG_RESET_END){ + GPS_INFO_FUNC("gps restart end!\n"); + + /*reset_end message handling*/ + } + } + } else { + /*message format invalid*/ + } +} + +static int GPS_open(struct inode *inode, struct file *file) +{ + GPS_INFO_FUNC("major %d minor %d (pid %d)\n", + imajor(inode), + iminor(inode), + current->pid + ); + +#if 1 /* GeorgeKuo: turn on function before check stp ready */ + /* turn on BT */ + + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_GPS)) { + GPS_WARN_FUNC("WMT turn on GPS fail!\n"); + return -ENODEV; + } else { + mtk_wcn_wmt_msgcb_reg(WMTDRV_TYPE_GPS, gps_cdev_rst_cb); + GPS_INFO_FUNC("WMT turn on GPS OK!\n"); + } +#endif + + if (mtk_wcn_stp_is_ready()) { +#if 0 + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_GPS)) { + GPS_WARN_FUNC("WMT turn on GPS fail!\n"); + return -ENODEV; + } + GPS_INFO_FUNC("WMT turn on GPS OK!\n"); +#endif + mtk_wcn_stp_register_event_cb(GPS_TASK_INDX, GPS_event_cb); + } else { + GPS_ERR_FUNC("STP is not ready, Cannot open GPS Devices\n\r"); + + /*return error code*/ + return -ENODEV; + } + + //init_MUTEX(&wr_mtx); + sema_init(&wr_mtx, 1); + //init_MUTEX(&rd_mtx); + sema_init(&rd_mtx, 1); + + return 0; +} + +static int GPS_close(struct inode *inode, struct file *file) +{ + GPS_INFO_FUNC("major %d minor %d (pid %d)\n", + imajor(inode), + iminor(inode), + current->pid + ); + + /*Flush Rx Queue*/ + mtk_wcn_stp_register_event_cb(GPS_TASK_INDX, 0x0); // unregister event callback function + mtk_wcn_wmt_msgcb_unreg(WMTDRV_TYPE_GPS); + + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_off(WMTDRV_TYPE_GPS)) { + GPS_WARN_FUNC("WMT turn off GPS fail!\n"); + return -EIO; //mostly, native programer does not care this return vlaue, but we still return error code. + } + else { + GPS_INFO_FUNC("WMT turn off GPS OK!\n"); + } + + return 0; +} + +struct file_operations GPS_fops = { + .open = GPS_open, + .release = GPS_close, + .read = GPS_read, + .write = GPS_write, +// .ioctl = GPS_ioctl + .unlocked_ioctl = GPS_unlocked_ioctl, +}; + +void GPS_event_cb(void) +{ +/* printk("GPS_event_cb() \n");*/ + + flag = 1; + wake_up(&GPS_wq); + + return; +} + +static int GPS_init(void) +{ + dev_t dev = MKDEV(GPS_major, 0); + int alloc_ret = 0; + int cdev_err = 0; + + /*static allocate chrdev*/ + alloc_ret = register_chrdev_region(dev, 1, GPS_DRIVER_NAME); + if (alloc_ret) { + printk("fail to register chrdev\n"); + return alloc_ret; + } + + cdev_init(&GPS_cdev, &GPS_fops); + GPS_cdev.owner = THIS_MODULE; + + cdev_err = cdev_add(&GPS_cdev, dev, GPS_devs); + if (cdev_err) + goto error; + + printk(KERN_ALERT "%s driver(major %d) installed.\n", GPS_DRIVER_NAME, GPS_major); + + return 0; + +error: + if (cdev_err == 0) + cdev_del(&GPS_cdev); + + if (alloc_ret == 0) + unregister_chrdev_region(dev, GPS_devs); + + return -1; +} + +static void GPS_exit(void) +{ + dev_t dev = MKDEV(GPS_major, 0); + + cdev_del(&GPS_cdev); + unregister_chrdev_region(dev, GPS_devs); + + printk(KERN_ALERT "%s driver removed.\n", GPS_DRIVER_NAME); +} + +module_init(GPS_init); +module_exit(GPS_exit); + +EXPORT_SYMBOL(GPS_event_cb); + diff --git a/drivers/mtk_wcn_combo/common/linux/stp_exp.c b/drivers/mtk_wcn_combo/common/linux/stp_exp.c new file mode 100755 index 000000000000..b423fbbe14b2 --- /dev/null +++ b/drivers/mtk_wcn_combo/common/linux/stp_exp.c @@ -0,0 +1,304 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +/***************************************************************************** +* Copyright Statement: +* -------------------- +* This software is protected by Copyright and the information contained +* herein is confidential. The software may not be copied and the information +* contained herein may not be used or disclosed except with the written +* permission of MediaTek Inc. (C) 2008 +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES +* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") +* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON +* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. +* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE +* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR +* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH +* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO +* NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S +* SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, +* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, +* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO +* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF +* LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND +* RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER +* THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC). +* +*****************************************************************************/ +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "osal_linux.h" +#include "core_exp.h" +#include "stp_exp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +static MTK_WCN_STP_IF_TX stp_uart_if_tx = NULL; +static MTK_WCN_STP_IF_TX stp_sdio_if_tx = NULL; +static ENUM_STP_TX_IF_TYPE g_stp_if_type = STP_MAX_IF_TX; +static MTK_WCN_STP_IF_RX stp_if_rx = NULL; +static MTK_WCN_STP_EVENT_CB event_callback_tbl[MTKSTP_MAX_TASK_NUM] = {0x0}; +static MTK_WCN_STP_EVENT_CB tx_event_callback_tbl[MTKSTP_MAX_TASK_NUM] = {0x0}; + +/****************************************************************************** +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************* +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +INT32 mtk_wcn_sys_if_rx(UINT8 *data, INT32 size) +{ + if (stp_if_rx == 0x0) + { + return (-1); + } + else + { + (*stp_if_rx)(data, size); + return 0; + } +} + +static INT32 mtk_wcn_sys_if_tx ( + const UINT8 *data, + const UINT32 size, + UINT32 *written_size + ) +{ + + if (STP_UART_IF_TX == g_stp_if_type) { + return stp_uart_if_tx != NULL ? (*stp_uart_if_tx)(data, size, written_size) : -1; + } + else if (STP_SDIO_IF_TX == g_stp_if_type) { + return stp_sdio_if_tx != NULL ? (*stp_sdio_if_tx)(data, size, written_size) : -1; + } + else { + /*if (g_stp_if_type >= STP_MAX_IF_TX) */ /* George: remove ALWAYS TRUE condition */ + return (-1); + } +} + +static INT32 mtk_wcn_sys_event_set(UINT8 function_type) +{ + if ((function_type < MTKSTP_MAX_TASK_NUM) && (event_callback_tbl[function_type] != 0x0)) + { + (*event_callback_tbl[function_type])(); + } + else { + /* FIXME: error handling */ + printk(KERN_INFO "[%s] STP set event fail. It seems the function is not active.\n", __func__); + } + + return 0; +} + +static INT32 mtk_wcn_sys_event_tx_resume(UINT8 winspace) +{ + INT32 type = 0; + + for(type = 0 ; type < MTKSTP_MAX_TASK_NUM ; type ++ ) + { + if (tx_event_callback_tbl[type]) + { + tx_event_callback_tbl[type](); + } + } + + return 0; +} + +static INT32 mtk_wcn_sys_check_function_status(UINT8 type, UINT8 op){ + + /*op == FUNCTION_ACTIVE, to check if funciton[type] is active ?*/ + if (!(type >= 0 && type < MTKSTP_MAX_TASK_NUM)) + { + return STATUS_FUNCTION_INVALID; + } + + if (op == OP_FUNCTION_ACTIVE) + { + if (event_callback_tbl[type] != 0x0) + { + return STATUS_FUNCTION_ACTIVE; + } + else + { + return STATUS_FUNCTION_INACTIVE; + } + } + /*you can define more operation here ..., to queury function's status/information*/ + + return STATUS_OP_INVALID; +} + +INT32 mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func) +{ + stp_if_rx = func; + + return 0; +} + +VOID mtk_wcn_stp_set_if_tx_type ( + ENUM_STP_TX_IF_TYPE stp_if_type + ) +{ + g_stp_if_type = stp_if_type; + printk(KERN_INFO "[%s] set STP_IF_TX to %s.\n", + __FUNCTION__, + (STP_UART_IF_TX == stp_if_type)? "UART" : ((STP_SDIO_IF_TX == stp_if_type) ? "SDIO" : "NULL")); +} + +INT32 mtk_wcn_stp_register_if_tx ( + ENUM_STP_TX_IF_TYPE stp_if, + MTK_WCN_STP_IF_TX func + ) +{ + if (STP_UART_IF_TX == stp_if) + { + stp_uart_if_tx = func; + } + else if (STP_SDIO_IF_TX == stp_if) + { + stp_sdio_if_tx = func; + } + else + { + printk(KERN_WARNING "[%s] STP_IF_TX(%d) out of boundary.\n", __FUNCTION__, stp_if); + return -1; + } + + return 0; +} + +INT32 mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) +{ + if (type < MTKSTP_MAX_TASK_NUM) + { + event_callback_tbl[type] = func; + + /*clear rx queue*/ + //printk("Flush type = %d Rx Queue\n", type); + mtk_wcn_stp_flush_rx_queue(type); + } + + return 0; +} + +INT32 mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) +{ + if (type < MTKSTP_MAX_TASK_NUM) + { + tx_event_callback_tbl[type] = func; + } + else + { + BUG_ON(0); + } + + return 0; +} + +INT32 stp_drv_init(VOID) +{ + mtkstp_callback cb = + { + .cb_if_tx = mtk_wcn_sys_if_tx, + .cb_event_set = mtk_wcn_sys_event_set, + .cb_event_tx_resume = mtk_wcn_sys_event_tx_resume, + .cb_check_funciton_status = mtk_wcn_sys_check_function_status + }; + + return mtk_wcn_stp_init(&cb); +} + +VOID stp_drv_exit(VOID) +{ + mtk_wcn_stp_deinit(); + + return; +} + +EXPORT_SYMBOL(mtk_wcn_stp_register_if_tx); +EXPORT_SYMBOL(mtk_wcn_stp_register_if_rx); +EXPORT_SYMBOL(mtk_wcn_stp_register_event_cb); +EXPORT_SYMBOL(mtk_wcn_stp_register_tx_event_cb); +EXPORT_SYMBOL(mtk_wcn_stp_parser_data); +EXPORT_SYMBOL(mtk_wcn_stp_send_data); +EXPORT_SYMBOL(mtk_wcn_stp_send_data_raw); +EXPORT_SYMBOL(mtk_wcn_stp_receive_data); +EXPORT_SYMBOL(mtk_wcn_stp_is_rxqueue_empty); +EXPORT_SYMBOL(mtk_wcn_stp_set_bluez); +EXPORT_SYMBOL(mtk_wcn_stp_is_ready); + + + + + + diff --git a/drivers/mtk_wcn_combo/common/linux/stp_uart.c b/drivers/mtk_wcn_combo/common/linux/stp_uart.c new file mode 100755 index 000000000000..5269d7c80a1d --- /dev/null +++ b/drivers/mtk_wcn_combo/common/linux/stp_uart.c @@ -0,0 +1,1250 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +#define LDISC_LOW_LATENCY (0) +/* 1: set low_latency to tty; rx may be called in hw_irq context; +* 0: rx may be called in kernel global workqueue context (kthread) +*/ + +/* ldisc rx and do stp data parsing context options: + * LDISC_RX_TASKLET: + * use rx tasklet to process rx data in bh + * cons: can't sleep, priority too high. + * LDISC_RX_TTY_CB: + * process rx data directly in tty's recv callback context + * (ldisc.receive_buf). Real context type depends on LDISC_LOW_LATENCY: + * 1:interrupt context + * 0: thread context. + * cons: rx data may come too late. + * LDISC_RX_WORK (default): + * schedule another work_struct to handle + */ +#define LDISC_RX_TASKLET (0) +#define LDISC_RX_TTY_CB (1) +#define LDISC_RX_WORK (2) +/* Select LDISC RX Method */ +#define LDISC_RX (LDISC_RX_WORK) + +/* More detailed options */ +#if (LDISC_RX == LDISC_RX_TASKLET) +#define LDISC_RX_TASKLET_RWLOCK (0) +/* 1: use rwlock to protect rx kfifo (APEX default) for LDISC_RX_TASKLET + * 0: use _NO_ rwlock +*/ +#elif (LDISC_RX == LDISC_RX_WORK) +/* enable low latency mechanism */ +#undef LDISC_LOW_LATENCY +#define LDISC_LOW_LATENCY (1) +#endif + +/* ldisc tx context options: + * LDISC_TX_OLD: + * Do uart tx in the caller thread (STP-CORE). Handle local tx buffer + * in old way. + * LDISC_TX_CALLER_THRD: + * Do uart tx in the caller thread (STP-CORE). Handle tx using caller's + * buffer directly. + */ +#define LDISC_TX_OLD (0) +#define LDISC_TX_CALLER_THRD (1) + +/* Select LDISC TX Method */ +#define LDISC_TX (LDISC_TX_CALLER_THRD) + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include /* vmalloc, vzalloc */ +#include /* INIT_WORK, schedule_work */ + +#include "stp_exp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define N_MTKSTP (15 + 1) /* refer to linux tty.h use N_HCI. */ +#define HCIUARTSETPROTO (_IOW('U', 200, int)) + +#define PFX "[STP-U]" +#define UART_LOG_LOUD (4) +#define UART_LOG_DBG (3) +#define UART_LOG_INFO (2) +#define UART_LOG_WARN (1) +#define UART_LOG_ERR (0) + +#define MAX_PACKET_ALLOWED (2000) + +#if (LDISC_RX == LDISC_RX_TASKLET) +#define LDISC_RX_FIFO_SIZE (0x20000/*0x2000*/) /* 128K or 8K bytes? */ + +#elif (LDISC_RX == LDISC_RX_WORK) +#define LDISC_RX_FIFO_SIZE (0x4000) /* 16K bytes shall be enough...... */ +#define LDISC_RX_BUF_SIZE (2048) /* 2K bytes in one shot is enough */ + +#endif + +#if (LDISC_TX == LDISC_TX_OLD) +/* no additional allocated for tx using caller's thread */ +//#define STP_UART_TX_BUF_SIZE (MTKSTP_BUFFER_SIZE) +#define STP_UART_TX_BUF_SIZE (4096) /* 16K or 4K bytes is enough? */ + +#elif (LDISC_TX == LDISC_TX_CALLER_THRD) + +#define LDISC_TX_CALLER_THRD_RTY_LMT (10) +#define LDISC_TX_CALLER_THRD_RTY_MIN_DLY (3) +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +unsigned int gStpDbgLevel = UART_LOG_ERR;//UART_LOG_INFO;//modify loglevel + +struct tty_struct *stp_tty = NULL; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +#if (LDISC_RX == LDISC_RX_TASKLET) +struct kfifo *g_stp_uart_rx_fifo = NULL; +spinlock_t g_stp_uart_rx_fifo_spinlock; +struct tasklet_struct g_stp_uart_rx_fifo_tasklet; + #if LDISC_RX_TASKLET_RWLOCK +static DEFINE_RWLOCK(g_stp_uart_rx_handling_lock); + #endif +#endif + +#if (LDISC_RX == LDISC_RX_WORK) +UINT8 *g_stp_uart_rx_buf; /* for stp rx data parsing */ +struct kfifo *g_stp_uart_rx_fifo = NULL; /* for uart tty data receiving */ +spinlock_t g_stp_uart_rx_fifo_spinlock; /* fifo spinlock */ +struct workqueue_struct *g_stp_uart_rx_wq; /* rx work queue (do not use system_wq) */ +struct work_struct *g_stp_uart_rx_work; /* rx work */ +#endif + +/* Private info for each Tx method */ +#if (LDISC_TX == LDISC_TX_OLD) +static unsigned char tx_buf[STP_UART_TX_BUF_SIZE] = {0x0}; +static unsigned int rd_idx = 0; /* the position next to read */ +static unsigned int wr_idx = 0; /* the position next to write */ +/* tx_buf in STP-UART is protected by caller(STP-CORE) locking mechanism. */ +//struct semaphore buf_mtx; /* unused */ +//static spinlock_t buf_lock; /* unused */ + +#elif (LDISC_TX == LDISC_TX_CALLER_THRD) +static int tx_retry_limit = LDISC_TX_CALLER_THRD_RTY_LMT; +static int tx_retry_delay_ms = LDISC_TX_CALLER_THRD_RTY_MIN_DLY; + +#else +#error "UNSUPPORTED LDISC_TX" LDISC_TX +#endif + +//static unsigned int tx_count = 0; /* drop tx data test? */ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +//#define MAX(a,b) ((a) > (b) ? (a) : (b)) //unused +//#define MIN(a,b) ((a) < (b) ? (a) : (b)) //unused + +#define UART_LOUD_FUNC(fmt, arg...) if(gStpDbgLevel >= UART_LOG_LOUD){ printk(PFX "[L]%s:" fmt, __FUNCTION__ ,##arg);} +#define UART_DBG_FUNC(fmt, arg...) if(gStpDbgLevel >= UART_LOG_DBG){ printk(PFX "[D]%s:" fmt, __FUNCTION__ ,##arg);} +#define UART_INFO_FUNC(fmt, arg...) if(gStpDbgLevel >= UART_LOG_INFO){ printk(PFX "[I]%s:" fmt, __FUNCTION__ ,##arg);} +#define UART_WARN_FUNC(fmt, arg...) if(gStpDbgLevel >= UART_LOG_WARN){ printk(PFX "[W]%s:" fmt, __FUNCTION__ ,##arg);} +#define UART_ERR_FUNC(fmt, arg...) if(gStpDbgLevel >= UART_LOG_ERR){ printk(PFX "[E]%s:" fmt, __FUNCTION__ ,##arg);} +#define UART_TRC_FUNC(f) if(gStpDbgLevel >= UART_LOG_DBG){ printk(PFX "<%s/%d>\n", __FUNCTION__, __LINE__);} + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static INT32 mtk_wcn_uart_tx ( + const UINT8 *data, + const UINT32 size, + UINT32 *written_size + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#if (LDISC_TX == LDISC_TX_OLD) +static int stp_uart_tty_tx_init (void) +{ + //init_MUTEX(&buf_mtx); + //spin_lock_init(&buf_lock); + rd_idx = wr_idx = 0; + return 0; +} + +static int stp_uart_tty_tx_deinit (void) +{ + rd_idx = wr_idx = 0; + return 0; +} + +/* stp_uart_tty_open + * + * Arguments: + * tty pointer to tty info structure + * data pointer to data buffer to be written + * size data buffer length to be written + * Return Value: + * > 0 if success, otherwise error code + */ +static int stp_uart_tty_tx_write ( + struct tty_struct *tty, + const UINT8 *data, + const UINT32 size + ) +{ + int ret; + int len; + int written; + int written_count; + int room; + unsigned old_wr; + unsigned old_rd; + //unsigned long flags; + + UART_LOUD_FUNC("++\n"); + + /* Phase-I: put data into STP-UART ring buffer "tx_buf" */ + /* wr_idx : the position next to write + * rd_idx : the position next to read + */ + + //down(&buf_mtx); + /* [PatchNeed] spin_lock_irqsave is redundant */ + //spin_lock_irqsave(&buf_lock, flags); + old_wr = wr_idx; + old_rd = rd_idx; + + /* check left room size */ + room = (wr_idx >= rd_idx) + ? (STP_UART_TX_BUF_SIZE - (wr_idx - rd_idx) - 1) + : (rd_idx - wr_idx - 1); + UART_DBG_FUNC("before data in:r(%d)s(%d)wr_i(%d)rd_i(%d)\n", + room, size, wr_idx, rd_idx); + + if (unlikely(size > room)) { + UART_ERR_FUNC("buf unavailable FAIL#1,size(%d),wr_idx(%d),rd_idx(%d),room(%d),pid[%d/%s]\n", + size, wr_idx, rd_idx, room, current->pid, current->comm); + //up(&buf_mtx); + /* [PatchNeed] spin_lock_irqsave is redundant */ + //spin_unlock_irqrestore(&buf_lock, flags); + return -1; + } + else { + len = min(size, STP_UART_TX_BUF_SIZE - (unsigned int)wr_idx); + memcpy(&tx_buf[wr_idx], &data[0], len); + memcpy(&tx_buf[0], &data[len], size - len); + wr_idx = (wr_idx + size) % STP_UART_TX_BUF_SIZE; + UART_DBG_FUNC("after data in: r(%d)s(%d)wr_i(%d)rd_i(%d)\n", + room, size, wr_idx, rd_idx); + } + //up(&buf_mtx); + /* [PatchNeed] spin_lock_irqsave is redundant */ + //spin_unlock_irqrestore(&buf_lock, flags); + + /* Phase-II: get data from the buffer and send to tty UART. + * May be seperated into another context. + */ + + //down(&buf_mtx); + /* [PatchNeed] spin_lock_irqsave is redundant */ + //spin_lock_irqsave(&buf_lock, flags); + written_count = 0; + + len = (wr_idx >= rd_idx) ? (wr_idx - rd_idx) : (STP_UART_TX_BUF_SIZE - rd_idx); + if (likely(len > 0 && len < MAX_PACKET_ALLOWED)) + { + /* TTY_DO_WRITE_WAKEUP is used for "Call write_wakeup after queuing new" + * but stp_uart_tty_wakeup() is empty and unused now! + */ + //set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + + /* + * ops->write is called by the kernel to write a series of + * characters to the tty device. The characters may come from + * user space or kernel space. This routine will return the + * number of characters actually accepted for writing. + */ + written = tty->ops->write(tty, &tx_buf[rd_idx], len); + if (written != len) { + UART_ERR_FUNC("tty-ops->write FAIL#2,len(%d)wr(%d)wr_i(%d)rd_i(%d),pid[%d/%s]\n", + len, written, wr_idx, rd_idx, current->pid, current->comm); + ret = -2; + goto tx_write_out_unlock_old; + } + written_count = written; + rd_idx = ((rd_idx + written) % STP_UART_TX_BUF_SIZE); + + // all data is accepted by UART driver, check again in case roll over + len = (wr_idx >= rd_idx) ? (wr_idx - rd_idx) : (STP_UART_TX_BUF_SIZE - rd_idx); + if (len > 0 && len < MAX_PACKET_ALLOWED) + { + /* TTY_DO_WRITE_WAKEUP is used for "Call write_wakeup after queuing new" + * but stp_uart_tty_wakeup() is empty and unused now! + */ + //set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + + written = tty->ops->write(tty, &tx_buf[rd_idx], len); + if (unlikely(written != len)) + { + UART_ERR_FUNC("tty-ops->write FAIL#3,len(%d)wr(%d)wr_i(%d)rd_i(%d),pid[%d/%s]\n", + len, written, wr_idx, rd_idx, current->pid, current->comm); + ret = -3; + goto tx_write_out_unlock_old; + } + rd_idx = ((rd_idx + written) % STP_UART_TX_BUF_SIZE); + written_count += written; + } + else if (unlikely(len < 0 || len >= MAX_PACKET_ALLOWED)) + { + UART_ERR_FUNC("FAIL#4,len(%d)wr_i(%d)rd_i(%d),pid[%d/%s]\n", + len, wr_idx, rd_idx, + current->pid, current->comm); + ret = -4; + goto tx_write_out_unlock_old; + } + } + else + { + UART_ERR_FUNC("FAIL#5,len(%d)wr_i(%d)rd_i(%d),pid[%d/%s]\n", + len, wr_idx, rd_idx, + current->pid, current->comm); + ret = -5; + goto tx_write_out_unlock_old; + } + + /* success case */ + ret = written_count; + + +tx_write_out_unlock_old: + if (unlikely(ret < 0)) { + //reset read and write index of tx_buffer, is there any risk? + wr_idx = rd_idx = 0; + UART_ERR_FUNC("err(%d)reset fifo idx\n", ret); + } + + if (unlikely(wr_idx != rd_idx)) { + UART_WARN_FUNC("--wr(%d)rd(%d)size(%d)old wr(%d)rd(%d)\n", + wr_idx, rd_idx, size, old_wr, old_rd); + + } + else { + UART_LOUD_FUNC("--wr(%d) rd(%d)\n", wr_idx, rd_idx); + } + //up(&buf_mtx); + //spin_unlock_irqrestore(&buf_lock, flags); + + return ret; +} + +/* end of (LDISC_TX == LDISC_TX_OLD) */ + +#elif (LDISC_TX == LDISC_TX_CALLER_THRD) +static inline int stp_uart_tty_tx_init (void) +{ + /* nothing to be done */ + return 0; +} + +static inline int stp_uart_tty_tx_deinit (void) +{ + /* nothing to be done */ + return 0; +} + +static int stp_uart_tty_tx_write ( + struct tty_struct *tty, + const UINT8 *data, + const UINT32 size + ) +{ + int written; + int wr_count; + int retry_left; + int retry_delay_ms; + + wr_count = tty->ops->write(tty, data, size); + if (likely(wr_count == size)) { + /* perfect case! */ + return wr_count; + } + + UART_DBG_FUNC("tty write FAIL#1,size(%d)wr(%d)pid[%d/%s]\n", + size, written, current->pid, current->comm); + + /* error handling */ + retry_left = tx_retry_limit; + retry_delay_ms = tx_retry_delay_ms; + while ( (retry_left--) && (wr_count < size)) { + /* do msleep if and only if STP-CORE using process context (caller's or + * any other task) instead of any irq context (hardirq, softirq, tasklet + * , timer, etc). + */ + msleep(retry_delay_ms); + // TODO: to be refined by considering wr_count, current baud rate, etc. + retry_delay_ms *= 2; + written = tty->ops->write(tty, data + wr_count, size - wr_count); + wr_count += written; + } + + if (likely(wr_count == size)) { + UART_INFO_FUNC("recovered,size(%d)retry_left(%d)delay(%d)\n", + size, retry_left, retry_delay_ms); + /* workable case! */ + return wr_count; + } + + /* return -written_count as error code and let caller to further error handle */ + UART_ERR_FUNC("tty write FAIL#2,size(%d)wr(%d)retry_left(%d)pid[%d/%s]\n", + size, wr_count, retry_left, current->pid, current->comm); + + return -wr_count; +} +#else +#error "unknown LDISC_TX" LDISC_TX +#endif + +#if (LDISC_RX == LDISC_RX_TASKLET) +static int stp_uart_fifo_init(void) +{ + int err = 0; + + /*add rx fifo*/ + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) + { + spin_lock_init(&g_stp_uart_rx_fifo_spinlock); + g_stp_uart_rx_fifo = kfifo_alloc(LDISC_RX_FIFO_SIZE, GFP_ATOMIC, &g_stp_uart_rx_fifo_spinlock); + if (NULL == g_stp_uart_rx_fifo) + { + UART_ERR_FUNC("kfifo_alloc failed (kernel version < 2.6.33)\n"); + err = -1; + } + } + #else + { + g_stp_uart_rx_fifo = kzalloc(sizeof(struct kfifo), GFP_ATOMIC); + if (NULL == g_stp_uart_rx_fifo) + { + err = -2; + UART_ERR_FUNC("kzalloc for g_stp_uart_rx_fifo failed (kernel version > 2.6.33)\n"); + } + err = kfifo_alloc(g_stp_uart_rx_fifo, LDISC_RX_FIFO_SIZE, GFP_ATOMIC); + if (0 != err) + { + UART_ERR_FUNC("kfifo_alloc failed, errno(%d)(kernel version > 2.6.33)\n", err); + kfree(g_stp_uart_rx_fifo); + g_stp_uart_rx_fifo = NULL; + err = -3; + } + } + #endif + + if (0 == err) + { + if (NULL != g_stp_uart_rx_fifo) + { + kfifo_reset(g_stp_uart_rx_fifo); + UART_ERR_FUNC("stp_uart_fifo_init() success.\n"); + } + else + { + err = -4; + UART_ERR_FUNC("abnormal case, err = 0 but g_stp_uart_rx_fifo = NULL, set err to %d\n", err); + } + } + else + { + UART_ERR_FUNC("stp_uart_fifo_init() failed.\n"); + } + return err; +} + +static int stp_uart_fifo_deinit(void) +{ + if (NULL != g_stp_uart_rx_fifo) + { + kfifo_free(g_stp_uart_rx_fifo); + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) + //do nothing + #else + kfree(g_stp_uart_rx_fifo); + #endif + g_stp_uart_rx_fifo = NULL; + } + return 0; +} + +static void stp_uart_rx_handling(unsigned long func_data){ + #define LOCAL_BUFFER_LEN 1024 + unsigned char data[LOCAL_BUFFER_LEN]; + unsigned int how_much_get = 0; + unsigned int how_much_to_get = 0; + unsigned int flag = 0; + +#if LDISC_RX_TASKLET_RWLOCK + read_lock(&g_stp_uart_rx_handling_lock); +#endif + + how_much_to_get = kfifo_len(g_stp_uart_rx_fifo); + + if (how_much_to_get >= LOCAL_BUFFER_LEN) + { + flag = 1; + UART_INFO_FUNC ("fifolen(%d)\n", how_much_to_get); + } + + do { + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) + how_much_get= kfifo_get(g_stp_uart_rx_fifo, data, LOCAL_BUFFER_LEN); + #else + how_much_get= kfifo_out(g_stp_uart_rx_fifo, data, LOCAL_BUFFER_LEN); + #endif + UART_INFO_FUNC ("fifoget(%d)\n", how_much_get); + mtk_wcn_stp_parser_data((UINT8 *)data, how_much_get); + how_much_to_get = kfifo_len(g_stp_uart_rx_fifo); + }while(how_much_to_get > 0); + +#if LDISC_RX_TASKLET_RWLOCK + read_unlock(&g_stp_uart_rx_handling_lock); +#endif + + if (1 == flag) + { + UART_INFO_FUNC ("finish, fifolen(%d)\n", kfifo_len(g_stp_uart_rx_fifo)); + } +} + +/* stp_uart_tty_receive() + * + * Called by tty low level driver when receive data is + * available. + * + * Arguments: tty pointer to tty isntance data + * data pointer to received data + * flags pointer to flags for data + * count count of received data in bytes + * + * Return Value: None + */ +static void stp_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count) +{ + unsigned int fifo_avail_len;/* = LDISC_RX_FIFO_SIZE - kfifo_len(g_stp_uart_rx_fifo);*/ + unsigned int how_much_put = 0; + +#if 0 + { + struct timeval now; + do_gettimeofday(&now); + printk("[+STP][ ][R] %4d --> sec = %lu, --> usec --> %lu\n", + count, now.tv_sec, now.tv_usec); + } +#endif + +#if LDISC_RX_TASKLET_RWLOCK + write_lock(&g_stp_uart_rx_handling_lock); +#endif + + if (count > 2000) { + /*this is abnormal*/ + UART_ERR_FUNC("abnormal: buffer count = %d\n", count); + } + /*How much empty seat?*/ + fifo_avail_len = LDISC_RX_FIFO_SIZE - kfifo_len(g_stp_uart_rx_fifo); + if (fifo_avail_len > 0) { + //UART_INFO_FUNC ("fifo left(%d), count(%d)\n", fifo_avail_len, count); + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) + how_much_put = kfifo_put(g_stp_uart_rx_fifo,(unsigned char *) data, count); + #else + how_much_put = kfifo_in(g_stp_uart_rx_fifo,(unsigned char *) data, count); + #endif + +#if LDISC_RX_TASKLET_RWLOCK + /* George Test */ + write_unlock(&g_stp_uart_rx_handling_lock); +#endif + + /*schedule it!*/ + tasklet_schedule(&g_stp_uart_rx_fifo_tasklet); + } + else { + UART_ERR_FUNC("stp_uart_tty_receive rxfifo is full!!\n"); + } + +#if 0 + { + struct timeval now; + do_gettimeofday(&now); + printk("[-STP][ ][R] %4d --> sec = %lu, --> usec --> %lu\n", + count, now.tv_sec, now.tv_usec); + } +#endif + +#if LDISC_RX_TASKLET_RWLOCK + /* George Test */ + //write_unlock(&g_stp_uart_rx_handling_lock); +#endif + +} + +#elif (LDISC_RX == LDISC_RX_TTY_CB) +/* stp_uart_tty_receive() + * + * Called by tty low level driver when receive data is + * available. + * + * Arguments: tty pointer to tty isntance data + * data pointer to received data + * flags pointer to flags for data + * count count of received data in bytes + * + * Return Value: None + */ +static void stp_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count) +{ + //UART_INFO_FUNC("count = %d\n", count); + + if (count > 2000){ + /*this is abnormal*/ + UART_WARN_FUNC("count = %d\n", count); + } + +#if 0 + { + struct timeval now; + + do_gettimeofday(&now); + + printk("[+STP][ ][R] %4d --> sec = %d, --> usec --> %d\n", + count, now.tv_sec, now.tv_usec); + } +#endif + + + /*There are multi-context to access here? Need to spinlock?*/ + /*Only one context: flush_to_ldisc in tty_buffer.c*/ + mtk_wcn_stp_parser_data((UINT8 *)data, (UINT32)count); + + /* George Test: useless? */ + /*tty_unthrottle(tty);*/ + +#if 0 + { + struct timeval now; + + do_gettimeofday(&now); + + printk("[-STP][ ][R] %4d --> sec = %d, --> usec --> %d\n", + count, now.tv_sec, now.tv_usec); + } +#endif + return; +} + +#elif (LDISC_RX == LDISC_RX_WORK) +static int stp_uart_fifo_init(void) +{ + int err = 0; + + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) + g_stp_uart_rx_buf = vzalloc(LDISC_RX_BUF_SIZE); + if (!g_stp_uart_rx_buf) { + UART_ERR_FUNC("kfifo_alloc failed (kernel version >= 2.6.37)\n"); + err = -4; + goto fifo_init_end; + } + #else + g_stp_uart_rx_buf = vmalloc(LDISC_RX_BUF_SIZE); + if (!g_stp_uart_rx_buf) { + UART_ERR_FUNC("kfifo_alloc failed (kernel version < 2.6.37)\n"); + err = -4; + goto fifo_init_end; + } + memset(g_stp_uart_rx_buf, 0, LDISC_RX_BUF_SIZE); + #endif + + UART_LOUD_FUNC("g_stp_uart_rx_buf alloc ok(0x%p, %d)\n", + g_stp_uart_rx_buf, LDISC_RX_BUF_SIZE); + + /*add rx fifo*/ + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) + spin_lock_init(&g_stp_uart_rx_fifo_spinlock); + g_stp_uart_rx_fifo = kfifo_alloc(LDISC_RX_FIFO_SIZE, GFP_KERNEL, &g_stp_uart_rx_fifo_spinlock); + if (NULL == g_stp_uart_rx_fifo) { + UART_ERR_FUNC("kfifo_alloc failed (kernel version < 2.6.33)\n"); + err = -1; + goto fifo_init_end; + } + #else + /* allocate struct kfifo first */ + g_stp_uart_rx_fifo = kzalloc(sizeof(struct kfifo), GFP_KERNEL); + if (NULL == g_stp_uart_rx_fifo) { + err = -2; + UART_ERR_FUNC("kzalloc struct kfifo failed (kernel version > 2.6.33)\n"); + goto fifo_init_end; + } + + /* allocate kfifo data buffer then */ + err = kfifo_alloc(g_stp_uart_rx_fifo, LDISC_RX_FIFO_SIZE, GFP_KERNEL); + if (0 != err) { + UART_ERR_FUNC("kfifo_alloc failed, err(%d)(kernel version > 2.6.33)\n", err); + kfree(g_stp_uart_rx_fifo); + g_stp_uart_rx_fifo = NULL; + err = -3; + goto fifo_init_end; + } + #endif + UART_LOUD_FUNC("g_stp_uart_rx_fifo alloc ok\n"); + +fifo_init_end: + + if (0 == err) { + /* kfifo init ok */ + kfifo_reset(g_stp_uart_rx_fifo); + UART_DBG_FUNC("g_stp_uart_rx_fifo init success\n"); + } + else { + UART_ERR_FUNC("stp_uart_fifo_init() fail(%d)\n", err); + if (g_stp_uart_rx_buf) { + UART_ERR_FUNC("free g_stp_uart_rx_buf\n"); + vfree(g_stp_uart_rx_buf); + g_stp_uart_rx_buf = NULL; + } + } + + return err; +} + +static int stp_uart_fifo_deinit(void) +{ + if (g_stp_uart_rx_buf) { + vfree(g_stp_uart_rx_buf); + g_stp_uart_rx_buf = NULL; + } + + if (NULL != g_stp_uart_rx_fifo) { + kfifo_free(g_stp_uart_rx_fifo); + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) + //do nothing + #else + kfree(g_stp_uart_rx_fifo); + #endif + g_stp_uart_rx_fifo = NULL; + } + return 0; +} + +static void stp_uart_rx_worker (struct work_struct *work) +{ + unsigned int read; + + if (unlikely(!g_stp_uart_rx_fifo)) { + UART_ERR_FUNC("NULL rx fifo!\n"); + return; + } + if (unlikely(!g_stp_uart_rx_buf)) { + UART_ERR_FUNC("NULL rx buf!\n"); + return; + } + + /* run until fifo becomes empty */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) + while (kfifo_len(g_stp_uart_rx_fifo)) { + read = kfifo_get(g_stp_uart_rx_fifo, g_stp_uart_rx_buf, LDISC_RX_BUF_SIZE); + //UART_LOUD_FUNC("kfifo_get(%d)\n", read); + if (likely(read)) { + mtk_wcn_stp_parser_data((UINT8 *)g_stp_uart_rx_buf, read); + } + } +#else + while (!kfifo_is_empty(g_stp_uart_rx_fifo)) { + read = kfifo_out(g_stp_uart_rx_fifo, g_stp_uart_rx_buf, LDISC_RX_BUF_SIZE); + UART_DBG_FUNC("kfifo_out(%d)\n", read); + if (likely(read)) { + //UART_LOUD_FUNC("->%d\n", read); + mtk_wcn_stp_parser_data((UINT8 *)g_stp_uart_rx_buf, read); + //UART_LOUD_FUNC("<-\n", read); + } + } +#endif + + return; +} + +/* stp_uart_tty_receive() + * + * Called by tty low level driver when receive data is + * available. + * + * Arguments: tty pointer to tty isntance data + * data pointer to received data + * flags pointer to flags for data + * count count of received data in bytes + * + * Return Value: None + */ +static void stp_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count) +{ + unsigned int written; + + //UART_LOUD_FUNC("URX:%d\n", count); + if (unlikely(count > 2000)) { + UART_WARN_FUNC("abnormal: buffer count = %d\n", count); + } + + if (unlikely(!g_stp_uart_rx_fifo || !g_stp_uart_rx_work || !g_stp_uart_rx_wq)) { + UART_ERR_FUNC("abnormal g_stp_uart_rx_fifo(0x%p),g_stp_uart_rx_work(0x%p),g_stp_uart_rx_wq(0x%p)\n", + g_stp_uart_rx_fifo, g_stp_uart_rx_work, g_stp_uart_rx_wq); + return; + } + + /* need to check available buffer size? skip! */ + + /* need to lock fifo? skip for single writer single reader! */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) + written = kfifo_put(g_stp_uart_rx_fifo, (unsigned char *) data, count); +#else + written = kfifo_in(g_stp_uart_rx_fifo, (unsigned char *) data, count); +#endif + queue_work(g_stp_uart_rx_wq, g_stp_uart_rx_work); + + if (unlikely(written != count)) { + UART_ERR_FUNC("c(%d),w(%d) bytes dropped\n", count, written); + } + + return; +} + +#else +#error "unknown LDISC_RX!" LDISC_RX +#endif + +/* ------ LDISC part ------ */ +/* stp_uart_tty_open + * + * Called when line discipline changed to HCI_UART. + * + * Arguments: + * tty pointer to tty info structure + * Return Value: + * 0 if success, otherwise error code + */ +static int stp_uart_tty_open(struct tty_struct *tty) +{ + UART_DBG_FUNC("original receive_room(%d) low_latency(%d) in tty(%p)\n", + tty->receive_room, tty->low_latency, tty); + + tty->receive_room = 65536; +#if LDISC_LOW_LATENCY + tty->low_latency = 1; +#endif + UART_DBG_FUNC("set receive_room(%d) low_latency(%d) to tty(%p)\n", + tty->receive_room, tty->low_latency, tty); + + /* Flush any pending characters in the driver and line discipline. */ + + /* FIXME: why is this needed. Note don't use ldisc_ref here as the + open path is before the ldisc is referencable */ + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29) + /* definition changed!! */ + if (tty->ldisc->ops->flush_buffer) { + tty->ldisc->ops->flush_buffer(tty); + } +#else + if (tty->ldisc.ops->flush_buffer) { + tty->ldisc.ops->flush_buffer(tty); + } +#endif + + tty_driver_flush_buffer(tty); + + stp_uart_tty_tx_init(); + + stp_tty = tty; + + /* Register to STP-CORE */ + mtk_wcn_stp_register_if_tx(STP_UART_IF_TX, mtk_wcn_uart_tx); + + return 0; +} + +/* stp_uart_tty_close() + * + * Called when the line discipline is changed to something + * else, the tty is closed, or the tty detects a hangup. + */ +static void stp_uart_tty_close(struct tty_struct *tty) +{ + UART_DBG_FUNC("stp_uart_tty_close(): tty %p\n", tty); + mtk_wcn_stp_register_if_tx(STP_UART_IF_TX, NULL); + + stp_uart_tty_tx_deinit(); + + return; +} + +/* stp_uart_tty_wakeup() + * + * Callback for transmit wakeup. Called when low level + * device driver can accept more send data. + * + * Arguments: tty pointer to associated tty instance data + * Return Value: None + */ +static void stp_uart_tty_wakeup(struct tty_struct *tty) +{ + /* + UART_INFO_FUNC("in\n"); + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + stp_uart_tx_wakeup(tty); + */ + + return; +} + +/* stp_uart_tty_ioctl() + * + * Process IOCTL system call for the tty device. + * + * Arguments: + * + * tty pointer to tty instance data + * file pointer to open file object for device + * cmd IOCTL command code + * arg argument for IOCTL call (cmd dependent) + * + * Return Value: Command dependent + */ +static int stp_uart_tty_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + int err = 0; + + UART_LOUD_FUNC("++ ll(%d)\n", tty->low_latency); + + switch (cmd) { + case HCIUARTSETPROTO: +#if LDISC_LOW_LATENCY + UART_INFO_FUNC("set low_latency to 1\n"); + tty->low_latency = 1; +#endif + break; + default: + UART_LOUD_FUNC("redirect to n_tty_ioctl_helper\n"); + err = n_tty_ioctl_helper(tty, file, cmd, arg); + UART_LOUD_FUNC("n_tty_ioctl_helper result(0x%x %d)\n", cmd, err); + break; + }; + + UART_LOUD_FUNC("--\n"); + return err; +} + +/* + * We don't provide read/write/poll interface for user space. + */ +static ssize_t stp_uart_tty_read(struct tty_struct *tty, struct file *file, + unsigned char __user *buf, size_t nr) +{ + return 0; +} + +static ssize_t stp_uart_tty_write(struct tty_struct *tty, struct file *file, + const unsigned char *data, size_t count) +{ + return 0; +} + +static unsigned int stp_uart_tty_poll(struct tty_struct *tty, + struct file *filp, poll_table *wait) +{ + return 0; +} + +static INT32 mtk_wcn_uart_tx ( + const UINT8 *data, + const UINT32 size, + UINT32 *written_size + ) +{ + INT32 ret; + int tx_len; + + if (unlikely(0 == size)) { + /* special case for STP-CORE, return ASAP. */ + if (likely(written_size)) { + *written_size = 0; + } + return 0; + } + + UART_LOUD_FUNC("++\n"); + + /* input sanity checks */ + if (unlikely(stp_tty == NULL)) { + UART_ERR_FUNC("NULL stp_tty,pid[%d/%s]\n", current->pid, current->comm); + ret = -1; + goto uart_tx_out; + } + + if (unlikely((data == NULL) || (written_size == NULL))) { + UART_ERR_FUNC("NULL data(0x%p) or written(0x%p),pid[%d/%s]\n", + data, written_size, current->pid, current->comm); + ret = -2; + goto uart_tx_out; + } + + *written_size = 0; + + /* Do size checking. Only 1~MAX_PACKET_ALLOWED-1 is allowed */ + if (unlikely(MAX_PACKET_ALLOWED <= size)) { + UART_ERR_FUNC("abnormal size(%d),skip tx,pid[%d/%s]\n", + size, current->pid, current->comm); + dump_stack(); + ret = -3; + goto uart_tx_out; + } + +#if 0 /* drop data test */ + if ((tx_count > 1000) && (tx_count % 5)== 0) { + UART_INFO_FUNC("i=(%d), ****** drop data from uart******\n", i); + ++tx_count; + return 0; + } +#endif + + tx_len = stp_uart_tty_tx_write(stp_tty, data, size); + if (unlikely(tx_len < 0)) { + UART_WARN_FUNC("stp_uart_tty_tx_write err(%d)\n", tx_len); + *written_size = 0; + ret = -4; + } + else { + *written_size = tx_len; + ret = 0; + } + +uart_tx_out: + UART_LOUD_FUNC("--(%d, %d)\n", ret, *written_size); + + return ret; +} + +static int __init mtk_wcn_stp_uart_init(void) +{ + static struct tty_ldisc_ops stp_uart_ldisc; + int err; + int fifo_init_done; + + UART_INFO_FUNC("MTK STP UART driver\n"); + + fifo_init_done = 0; + +#if (LDISC_RX == LDISC_RX_TASKLET) + err = stp_uart_fifo_init(); + if (err != 0) { + UART_ERR_FUNC("stp_uart_fifo_init(TASKLET) error(%d)\n", err); + err = -EFAULT; + goto init_err; + } + fifo_init_done = 1; + + /*init rx tasklet*/ + tasklet_init(&g_stp_uart_rx_fifo_tasklet, stp_uart_rx_handling, (unsigned long) 0); + +#elif (LDISC_RX == LDISC_RX_WORK) + err = stp_uart_fifo_init(); + if (err != 0) { + UART_ERR_FUNC("stp_uart_fifo_init(WORK) error(%d)\n", err); + err = -EFAULT; + goto init_err; + } + fifo_init_done = 1; + + g_stp_uart_rx_work = vmalloc(sizeof(struct work_struct)); + if (!g_stp_uart_rx_work) { + UART_ERR_FUNC("vmalloc work_struct(%d) fail\n", sizeof(struct work_struct)); + err = -ENOMEM; + goto init_err; + } + + g_stp_uart_rx_wq = create_singlethread_workqueue("mtk_urxd"); + if (!g_stp_uart_rx_wq) { + UART_ERR_FUNC("create_singlethread_workqueue fail\n"); + err = -ENOMEM; + goto init_err; + } + + /* init rx work */ + INIT_WORK(g_stp_uart_rx_work, stp_uart_rx_worker); +#endif + + /* Register the tty discipline */ + memset(&stp_uart_ldisc, 0, sizeof (stp_uart_ldisc)); + stp_uart_ldisc.magic = TTY_LDISC_MAGIC; + stp_uart_ldisc.name = "n_mtkstp"; + stp_uart_ldisc.open = stp_uart_tty_open; + stp_uart_ldisc.close = stp_uart_tty_close; + stp_uart_ldisc.read = stp_uart_tty_read; + stp_uart_ldisc.write = stp_uart_tty_write; + stp_uart_ldisc.ioctl = stp_uart_tty_ioctl; + stp_uart_ldisc.poll = stp_uart_tty_poll; + stp_uart_ldisc.receive_buf = stp_uart_tty_receive; + stp_uart_ldisc.write_wakeup = stp_uart_tty_wakeup; + stp_uart_ldisc.owner = THIS_MODULE; + + err = tty_register_ldisc(N_MTKSTP, &stp_uart_ldisc); + if (err) { + UART_ERR_FUNC("MTK STP line discipline(%d) registration failed. (%d)\n", N_MTKSTP, err); + goto init_err; + } + + /* init ok */ + return 0; + +init_err: + +#if (LDISC_RX == LDISC_RX_TASKLET) + /* nothing */ + if (fifo_init_done) { + stp_uart_fifo_deinit(); + } +#elif (LDISC_RX == LDISC_RX_WORK) + if (g_stp_uart_rx_wq) { + destroy_workqueue(g_stp_uart_rx_wq); + g_stp_uart_rx_wq = NULL; + } + if (g_stp_uart_rx_work) { + vfree(g_stp_uart_rx_work); + } + if (fifo_init_done) { + stp_uart_fifo_deinit(); + } +#endif + UART_ERR_FUNC("init fail, return(%d)\n", err); + + return err; +} + +static void __exit mtk_wcn_stp_uart_exit(void) +{ + int err; + + mtk_wcn_stp_register_if_tx(STP_UART_IF_TX, NULL); // unregister if_tx function + + /* Release tty registration of line discipline */ + if ((err = tty_unregister_ldisc(N_MTKSTP))) + { + UART_ERR_FUNC("Can't unregister MTK STP line discipline (%d)\n", err); + } + +#if (LDISC_RX == LDISC_RX_TASKLET) + tasklet_kill(&g_stp_uart_rx_fifo_tasklet); + stp_uart_fifo_deinit(); +#elif (LDISC_RX == LDISC_RX_WORK) + if (g_stp_uart_rx_work) { + cancel_work_sync(g_stp_uart_rx_work); + } + if (g_stp_uart_rx_wq) { + destroy_workqueue(g_stp_uart_rx_wq); + g_stp_uart_rx_wq = NULL; + } + if (g_stp_uart_rx_work) { + vfree(g_stp_uart_rx_work); + g_stp_uart_rx_work = NULL; + } + stp_uart_fifo_deinit(); +#endif + + return; +} + +module_init(mtk_wcn_stp_uart_init); +module_exit(mtk_wcn_stp_uart_exit); + +//MODULE_LICENSE("Proprietary"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("MediaTek Inc WCN_SE_CS3"); +MODULE_DESCRIPTION("STP-HIF UART Interface"); + diff --git a/drivers/mtk_wcn_combo/common/linux/wmt_chrdev_wifi.c b/drivers/mtk_wcn_combo/common/linux/wmt_chrdev_wifi.c new file mode 100755 index 000000000000..7c95cd4b8541 --- /dev/null +++ b/drivers/mtk_wcn_combo/common/linux/wmt_chrdev_wifi.c @@ -0,0 +1,209 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OWIFIAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wmt_exp.h" + +MODULE_LICENSE("Dual BSD/GPL"); + +#define WIFI_DRIVER_NAME "mtk_wmt_WIFI_chrdev" +#define WIFI_DEV_MAJOR 194 // never used number + +#define PFX "[MTK-WIFI] " +#define WIFI_LOG_DBG 3 +#define WIFI_LOG_INFO 2 +#define WIFI_LOG_WARN 1 +#define WIFI_LOG_ERR 0 + + +unsigned int gDbgLevel = WIFI_LOG_ERR;//WIFI_LOG_INFO;//modify loglevel + +#define WIFI_DBG_FUNC(fmt, arg...) if (gDbgLevel >= WIFI_LOG_DBG) { printk(PFX "%s: " fmt, __FUNCTION__ ,##arg);} +#define WIFI_INFO_FUNC(fmt, arg...) if (gDbgLevel >= WIFI_LOG_INFO) { printk(PFX "%s: " fmt, __FUNCTION__ ,##arg);} +#define WIFI_WARN_FUNC(fmt, arg...) if (gDbgLevel >= WIFI_LOG_WARN) { printk(PFX "%s: " fmt, __FUNCTION__ ,##arg);} +#define WIFI_ERR_FUNC(fmt, arg...) if (gDbgLevel >= WIFI_LOG_ERR) { printk(PFX "%s: " fmt, __FUNCTION__ ,##arg);} +#define WIFI_TRC_FUNC(f) if (gDbgLevel >= WIFI_LOG_DBG) {printk(PFX "<%s> <%d>\n", __FUNCTION__, __LINE__);} + +#define VERSION "1.0" + +static int WIFI_devs = 1; /* device count */ +static int WIFI_major = WIFI_DEV_MAJOR; /* dynamic allocation */ +module_param(WIFI_major, uint, 0); +static struct cdev WIFI_cdev; +volatile int retflag = 0; +static struct semaphore wr_mtx; + +static int WIFI_open(struct inode *inode, struct file *file) +{ + WIFI_INFO_FUNC("%s: major %d minor %d (pid %d)\n", __func__, + imajor(inode), + iminor(inode), + current->pid + ); + + return 0; +} + +static int WIFI_close(struct inode *inode, struct file *file) +{ + WIFI_INFO_FUNC("%s: major %d minor %d (pid %d)\n", __func__, + imajor(inode), + iminor(inode), + current->pid + ); + retflag = 0; + + return 0; +} + +ssize_t WIFI_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) +{ + int retval = -EIO; + char local[4] = {0}; + static int opened = 0; + + down(&wr_mtx); + + if (count > 0) { + + if (0 == copy_from_user(local, buf, (count > 4) ? 4 : count)) { + WIFI_INFO_FUNC("WIFI_write %c\n", local[0]); + if (local[0] == '0' && opened == 1) { + //TODO + //Configure the EINT pin to GPIO mode. + + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_off(WMTDRV_TYPE_WIFI)) { + WIFI_INFO_FUNC("WMT turn off WIFI fail!\n"); + } + else { + WIFI_INFO_FUNC("WMT turn off WIFI OK!\n"); + opened = 0; + retval = count; + } + } + else if (local[0] == '1' && opened == 0) { + //TODO + //Disable EINT(external interrupt), and set the GPIO to EINT mode. + + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_WIFI)) { + WIFI_WARN_FUNC("WMT turn on WIFI fail!\n"); + } + else { + opened = 1; + retval = count; + WIFI_INFO_FUNC("WMT turn on WIFI success!\n"); + } + } + + } + } + + up(&wr_mtx); + return (retval); +} + + +struct file_operations WIFI_fops = { + .open = WIFI_open, + .release = WIFI_close, + .write = WIFI_write, +}; + +static int WIFI_init(void) +{ + dev_t dev = MKDEV(WIFI_major, 0); + int alloc_ret = 0; + int cdev_err = 0; + + /*static allocate chrdev*/ + alloc_ret = register_chrdev_region(dev, 1, WIFI_DRIVER_NAME); + if (alloc_ret) { + WIFI_ERR_FUNC("fail to register chrdev\n"); + return alloc_ret; + } + + cdev_init(&WIFI_cdev, &WIFI_fops); + WIFI_cdev.owner = THIS_MODULE; + + cdev_err = cdev_add(&WIFI_cdev, dev, WIFI_devs); + if (cdev_err) { + goto error; + } + + sema_init(&wr_mtx, 1); + + WIFI_INFO_FUNC("%s driver(major %d) installed.\n", WIFI_DRIVER_NAME, WIFI_major); + retflag = 0; + + return 0; + +error: + if (cdev_err == 0) { + cdev_del(&WIFI_cdev); + } + + if (alloc_ret == 0) { + unregister_chrdev_region(dev, WIFI_devs); + } + + return -1; +} + +static void WIFI_exit(void) +{ + dev_t dev = MKDEV(WIFI_major, 0); + retflag = 0; + + cdev_del(&WIFI_cdev); + unregister_chrdev_region(dev, WIFI_devs); + + WIFI_INFO_FUNC("%s driver removed.\n", WIFI_DRIVER_NAME); +} + +module_init(WIFI_init); +module_exit(WIFI_exit); + diff --git a/drivers/mtk_wcn_combo/common/linux/wmt_dev.c b/drivers/mtk_wcn_combo/common/linux/wmt_dev.c new file mode 100755 index 000000000000..39b27c397291 --- /dev/null +++ b/drivers/mtk_wcn_combo/common/linux/wmt_dev.c @@ -0,0 +1,906 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + + +/*! \file + \brief brief description + + Detailed descriptions here. + +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-DEV]" + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "osal_linux.h" +#include "osal_typedef.h" +#include "osal.h" +#include "wmt_dev.h" +#include "core_exp.h" + + +#define MTK_WMT_VERSION "Combo WMT Driver - v1.0" +#define MTK_WMT_DATE "2011/10/04" +#define WMT_DEV_MAJOR 190 // never used number +#define WMT_DEV_NUM 1 + +#define WMT_DEV_INIT_TO_MS (2 * 1000) // 2000 ms + +#if CFG_WMT_DBG_SUPPORT +#define WMT_DBG_PROCNAME "driver/wmt_dbg" +#endif + +#define WMT_DRIVER_NAME "mtk_stp_wmt" + + +/* Linux UCHAR device */ +static int gWmtMajor = WMT_DEV_MAJOR; +static struct cdev gWmtCdev; +static atomic_t gWmtRefCnt = ATOMIC_INIT(0); +/* WMT driver information */ +static UINT8 gLpbkBuf[1024] = {0}; +static UINT32 gLpbkBufLog; // George LPBK debug +static int gWmtInitDone = 0; +static wait_queue_head_t gWmtInitWq; + +#if CFG_WMT_DBG_SUPPORT +static struct proc_dir_entry *gWmtDbgEntry = NULL; +#endif + + +#if CFG_WMT_DBG_SUPPORT + +static INT32 wmt_dev_dbg_read(CHAR *page, CHAR **start, LONG off, INT32 count, INT32 *eof, VOID *data) +{ + return wmt_dbg_proc_read(page,start,off,count,eof,data); +} + + +static INT32 wmt_dev_dbg_write(struct file *file, const CHAR *buffer, ULONG count, VOID *data){ + + CHAR buf[256]; + CHAR *pBuf; + ULONG len = count; + + WMT_INFO_FUNC("write parameter len = %d\n\r", (int)len); + if (len >= osal_sizeof(buf)){ + WMT_ERR_FUNC("input handling fail!\n"); + len = osal_sizeof(buf) - 1; + return -1; + } + + if (copy_from_user(buf,buffer,len)/*copy_from_user(buf, buffer, len)*/){ + return -EFAULT; + } + buf[len] = '\0'; + WMT_INFO_FUNC("write parameter data = %s\n\r", buf); + pBuf = buf; + wmt_dbg_proc_write(pBuf); + return len; +} + +INT32 wmt_dev_dbg_setup(VOID) +{ + gWmtDbgEntry = create_proc_entry(WMT_DBG_PROCNAME, 0666, NULL); + if (gWmtDbgEntry == NULL){ + WMT_ERR_FUNC("Unable to create /proc entry\n\r"); + return -1; + } + gWmtDbgEntry->read_proc = wmt_dev_dbg_read; + gWmtDbgEntry->write_proc = wmt_dev_dbg_write; + return 0; +} + +INT32 wmt_dev_dbg_remove(VOID) +{ + if (NULL != gWmtDbgEntry) + { + remove_proc_entry(WMT_DBG_PROCNAME, NULL); + } + return 0; +} + +#endif + +INT32 wmt_dev_read_file ( + UCHAR *pName, + const u8 **ppBufPtr, + INT32 offset, + INT32 padSzBuf + ) +{ + INT32 iRet = -1; + struct file *fd; + //ssize_t iRet; + INT32 file_len; + INT32 read_len; + void *pBuf; + + //struct cred *cred = get_task_cred(current); + const struct cred *cred = get_current_cred(); + + if (!ppBufPtr ) { + WMT_ERR_FUNC("invalid ppBufptr!\n"); + return -1; + } + *ppBufPtr = NULL; + + WMT_INFO_FUNC("open (%s) O_RDONLY, 0\n", pName); + fd = filp_open(pName, O_RDONLY, 0); + if (!fd || IS_ERR(fd) || !fd->f_op || !fd->f_op->read) { + WMT_ERR_FUNC("failed to open or read!(0x%p, %d, %d)\n", fd, cred->fsuid, cred->fsgid); + return -1; + } + + file_len = fd->f_path.dentry->d_inode->i_size; + pBuf = vmalloc((file_len + BCNT_PATCH_BUF_HEADROOM + 3) & ~0x3UL); + if (!pBuf) { + WMT_ERR_FUNC("failed to vmalloc(%d)\n", (INT32)((file_len + 3) & ~0x3UL)); + goto read_file_done; + } + + do { + if (fd->f_pos != offset) { + if (fd->f_op->llseek) { + if (fd->f_op->llseek(fd, offset, 0) != offset) { + WMT_ERR_FUNC("failed to seek!!\n"); + goto read_file_done; + } + } + else { + fd->f_pos = offset; + } + } + + read_len = fd->f_op->read(fd, pBuf + padSzBuf, file_len, &fd->f_pos); + if (read_len != file_len) { + WMT_WARN_FUNC("read abnormal: read_len(%d), file_len(%d)\n", read_len, file_len); + } + } while (false); + + iRet = 0; + *ppBufPtr = pBuf; + +read_file_done: + if (iRet) { + if (pBuf) { + vfree(pBuf); + } + } + + filp_close(fd, NULL); + + return (iRet) ? iRet : read_len; +} + +// TODO: [ChangeFeature][George] refine this function name for general filesystem read operation, not patch only. +INT32 wmt_dev_patch_get ( + UCHAR *pPatchName, + OSAL_FIRMWARE **ppPatch, + INT32 padSzBuf + ) +{ + INT32 iRet = -1; + uid_t orig_uid; + gid_t orig_gid; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) + //struct cred *cred = get_task_cred(current); + struct cred *cred = (struct cred *)get_current_cred(); +#endif + + mm_segment_t orig_fs = get_fs(); + + if (*ppPatch) { + WMT_WARN_FUNC("f/w patch already exists \n"); + if ((*ppPatch)->data) { + vfree((*ppPatch)->data); + } + kfree(*ppPatch); + *ppPatch = NULL; + } + + if (!osal_strlen(pPatchName)) { + WMT_ERR_FUNC("empty f/w name\n"); + osal_assert((osal_strlen(pPatchName) > 0)); + return -1; + } + + *ppPatch = (OSAL_FIRMWARE *)kzalloc(sizeof(OSAL_FIRMWARE), /*GFP_KERNEL*/GFP_ATOMIC); + if (!(*ppPatch)) { + WMT_ERR_FUNC("kzalloc(%d) fail\n", sizeof(OSAL_FIRMWARE)); + return -2; + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) + orig_uid = cred->fsuid; + orig_gid = cred->fsgid; + cred->fsuid = cred->fsgid = 0; +#else + orig_uid = current->fsuid; + orig_gid = current->fsgid; + current->fsuid = current->fsgid = 0; +#endif + + set_fs(get_ds()); + + /* load patch file from fs */ + iRet = wmt_dev_read_file(pPatchName, &((*ppPatch)->data), 0, padSzBuf); + set_fs(orig_fs); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) + cred->fsuid = orig_uid; + cred->fsgid = orig_gid; +#else + current->fsuid = orig_uid; + current->fsgid = orig_gid; +#endif + + if (iRet > 0) { + (*ppPatch)->size = iRet; + WMT_DBG_FUNC("load (%s) to addr(0x%p) success\n", pPatchName, (*ppPatch)->data); + return 0; + } + else { + kfree((*ppPatch)); + *ppPatch = NULL; + WMT_ERR_FUNC("load file (%s) fail, iRet(%d) \n", pPatchName, iRet); + return -1; + } +} + +//INT32 wmt_dev_patch_put(osal_firmware **ppPatch) +INT32 wmt_dev_patch_put(OSAL_FIRMWARE **ppPatch) + +{ + if (NULL != *ppPatch ) + { + if ((*ppPatch)->data) { + vfree((*ppPatch)->data); + (*ppPatch)->data = NULL; + } + kfree(*ppPatch); + *ppPatch = NULL; + } + return 0; + +} + +MTK_WCN_BOOL wmt_dev_is_file_exist(UCHAR *pFileName) +{ + struct file *fd = NULL; + //ssize_t iRet; + INT32 fileLen = -1; + const struct cred *cred = get_current_cred(); + if (pFileName == NULL) + { + WMT_ERR_FUNC("invalid file name pointer(%p)\n", pFileName); + return MTK_WCN_BOOL_FALSE; + } + if (osal_strlen(pFileName) < osal_strlen(defaultPatchName)) + { + WMT_ERR_FUNC("invalid file name(%s)\n", pFileName); + return MTK_WCN_BOOL_FALSE; + } + + + //struct cred *cred = get_task_cred(current); + + fd = filp_open(pFileName, O_RDONLY, 0); + if (!fd || IS_ERR(fd) || !fd->f_op || !fd->f_op->read) { + WMT_ERR_FUNC("failed to open or read(%s)!(0x%p, %d, %d)\n", pFileName, fd, cred->fsuid, cred->fsgid); + return MTK_WCN_BOOL_FALSE; + } + fileLen = fd->f_path.dentry->d_inode->i_size; + filp_close(fd, NULL); + fd = NULL; + if (fileLen <= 0) + { + WMT_ERR_FUNC("invalid file(%s), length(%d)\n", pFileName, fileLen); + return MTK_WCN_BOOL_FALSE; + } + WMT_ERR_FUNC("valid file(%s), length(%d)\n", pFileName, fileLen); + return true; + +} + + +ssize_t +WMT_write ( + struct file *filp, + const char __user *buf, + size_t count, + loff_t *f_pos + ) +{ + INT32 iRet = 0; + UCHAR wrBuf[OSAL_NAME_MAX+1] = {0}; + INT32 copySize = (count < OSAL_NAME_MAX) ? count : OSAL_NAME_MAX; + + WMT_LOUD_FUNC("count:%d copySize:%d\n", count, copySize); + + if (copySize > 0) { + if (copy_from_user(wrBuf, buf, copySize)) { + iRet = -EFAULT; + goto write_done; + } + iRet = copySize; + wrBuf[OSAL_NAME_MAX] = '\0'; + + if (!strncasecmp(wrBuf, "ok", OSAL_NAME_MAX)) { + WMT_DBG_FUNC("resp str ok\n"); + //pWmtDevCtx->cmd_result = 0; + wmt_lib_trigger_cmd_signal(0); + } + else { + WMT_WARN_FUNC("warning resp str (%s)\n", wrBuf); + //pWmtDevCtx->cmd_result = -1; + wmt_lib_trigger_cmd_signal(-1); + } + //complete(&pWmtDevCtx->cmd_comp); + + } + +write_done: + return iRet; +} + +ssize_t +WMT_read ( + struct file *filp, + char __user *buf, + size_t count, + loff_t *f_pos + ) +{ + INT32 iRet = 0; + PUCHAR pCmd = NULL; + UINT32 cmdLen = 0; + pCmd = wmt_lib_get_cmd(); + + if (pCmd != NULL) + { + cmdLen = osal_strlen(pCmd) < OSAL_NAME_MAX ? osal_strlen(pCmd) : OSAL_NAME_MAX; + WMT_DBG_FUNC("cmd str(%s)\n", pCmd); + if (copy_to_user(buf, pCmd, cmdLen)) { + iRet = -EFAULT; + } + else + { + iRet = cmdLen; + } + } +#if 0 + if (test_and_clear_bit(WMT_STAT_CMD, &pWmtDevCtx->state)) { + iRet = osal_strlen(localBuf) < OSAL_NAME_MAX ? osal_strlen(localBuf) : OSAL_NAME_MAX; + // we got something from STP driver + WMT_DBG_FUNC("copy cmd to user by read:%s\n", localBuf); + if (copy_to_user(buf, localBuf, iRet)) { + iRet = -EFAULT; + goto read_done; + } + } +#endif + return iRet; +} + +unsigned int WMT_poll(struct file *filp, poll_table *wait) +{ + UINT32 mask = 0; + P_OSAL_EVENT pEvent = wmt_lib_get_cmd_event(); + + poll_wait(filp, (wait_queue_head_t *)pEvent->pWaitQueue, wait); + /* empty let select sleep */ + if (MTK_WCN_BOOL_TRUE == wmt_lib_get_cmd_status()) + { + mask |= POLLIN | POLLRDNORM; /* readable */ + } +#if 0 + if (test_bit(WMT_STAT_CMD, &pWmtDevCtx->state)) { + mask |= POLLIN | POLLRDNORM; /* readable */ + } +#endif + mask |= POLLOUT | POLLWRNORM; /* writable */ + return mask; +} + +//INT32 WMT_ioctl(struct inode *inode, struct file *filp, UINT32 cmd, unsigned long arg) +long +WMT_unlocked_ioctl ( + struct file *filp, + unsigned int cmd, + unsigned long arg + ) +{ + INT32 iRet = 0; + WMT_DBG_FUNC("cmd (%u), arg (0x%lx)\n", cmd, arg); + + switch(cmd) { + case 4: /* patch location */ + { +#if 0 + WMT_DBG_FUNC("old patch file: %s \n", pWmtDevCtx->cPatchName); + if (copy_from_user(pWmtDevCtx->cPatchName, (void *)arg, OSAL_NAME_MAX)) { + iRet = -EFAULT; + break; + } + pWmtDevCtx->cPatchName[OSAL_NAME_MAX] = '\0'; + WMT_DBG_FUNC("new patch file name: %s \n", pWmtDevCtx->cPatchName); +#endif + UCHAR cPatchName[OSAL_NAME_MAX + 1]; + if (copy_from_user(cPatchName, (void *)arg, OSAL_NAME_MAX)) { + iRet = -EFAULT; + break; + } + cPatchName[OSAL_NAME_MAX] = '\0'; + wmt_lib_set_patch_name(cPatchName); + } + break; + + case 5: /* stp/hif/fm mode */ + + /* set hif conf */ + do { + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal = NULL; + P_WMT_HIF_CONF pHif = NULL; + + iRet = wmt_lib_set_hif(arg); + if (0 != iRet) + { + WMT_INFO_FUNC("wmt_lib_set_hif fail\n"); + break; + } + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_INFO_FUNC("get_free_lxop fail\n"); + break; + } + pSignal = &pOp->signal; + pOp->op.opId = WMT_OPID_HIF_CONF; + + pHif = wmt_lib_get_hif(); + + osal_memcpy(&pOp->op.au4OpData[0], pHif, sizeof(WMT_HIF_CONF)); + pOp->op.u4InfoBit = WMT_OP_HIF_BIT; + pSignal->timeoutValue = 0; + + bRet = wmt_lib_put_act_op(pOp); + WMT_DBG_FUNC("WMT_OPID_HIF_CONF result(%d) \n", bRet); + iRet = (MTK_WCN_BOOL_FALSE == bRet) ? -EFAULT : 0; + } while (0); + + break; + + case 6: /* test turn on/off func */ + + do { + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + if (arg & 0x80000000) + { + bRet = mtk_wcn_wmt_func_on(arg & 0xF); + } + else + { + bRet = mtk_wcn_wmt_func_off(arg & 0xF); + } + iRet = (MTK_WCN_BOOL_FALSE == bRet) ? -EFAULT : 0; + } while (0); + + break; + + case 7: + /*switch Loopback function on/off + arg: bit0 = 1:turn loopback function on + bit0 = 0:turn loopback function off + */ + do{ + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + if (arg & 0x01) + { + bRet = mtk_wcn_wmt_func_on(WMTDRV_TYPE_LPBK); + } + else + { + bRet = mtk_wcn_wmt_func_off(WMTDRV_TYPE_LPBK); + } + iRet = (MTK_WCN_BOOL_FALSE == bRet) ? -EFAULT : 0; + }while(0); + + + break; + + + case 8: + do { + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + UINT32 u4Wait; + //UINT8 lpbk_buf[1024] = {0}; + UINT32 effectiveLen = 0; + P_OSAL_SIGNAL pSignal = NULL; + + if (copy_from_user(&effectiveLen, (void *)arg, sizeof(effectiveLen))) { + iRet = -EFAULT; + WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__); + break; + } + if (effectiveLen > sizeof(gLpbkBuf)) + { + iRet = -EFAULT; + WMT_ERR_FUNC("length is too long\n"); + break; + } + WMT_DBG_FUNC("len = %d\n", effectiveLen); + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail \n"); + iRet = -EFAULT; + break; + } + u4Wait = 2000; + if (copy_from_user(&gLpbkBuf[0], (void *)arg + sizeof(unsigned long), effectiveLen)) { + WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__); + iRet = -EFAULT; + break; + } + pSignal = &pOp->signal; + pOp->op.opId = WMT_OPID_LPBK; + pOp->op.au4OpData[0] = effectiveLen; //packet length + pOp->op.au4OpData[1] = (UINT32)&gLpbkBuf[0]; //packet buffer pointer + memcpy(&gLpbkBufLog, &gLpbkBuf[((effectiveLen >=4) ? effectiveLen-4:0)], 4); + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + WMT_DBG_FUNC("OPID(%d)type(%d)start\n", + pOp->op.opId, + pOp->op.au4OpData[0]); + wmt_lib_disable_psm_monitor(); + bRet = wmt_lib_put_act_op(pOp); + wmt_lib_enable_psm_monitor(); + if (MTK_WCN_BOOL_FALSE == bRet) { + WMT_WARN_FUNC("OPID(%d) type(%d) buf tail(0x%08x) fail\n", + pOp->op.opId, + pOp->op.au4OpData[0], + gLpbkBufLog); + iRet = -1; + break; + } + else { + WMT_DBG_FUNC("OPID(%d)length(%d) ok\n", + pOp->op.opId, pOp->op.au4OpData[0]); + iRet = pOp->op.au4OpData[0] ; + if (copy_to_user((void *)arg + sizeof(ULONG) + sizeof(UCHAR[2048]), gLpbkBuf, iRet)) { + iRet = -EFAULT; + break; + } + } + }while(0); + + break; +#if 0 + case 9: + { + #define LOG_BUF_SZ 300 + UCHAR buf[LOG_BUF_SZ]; + INT32 len = 0; + INT32 remaining = 0; + + remaining = mtk_wcn_stp_btm_get_dmp(buf, &len); + + if (remaining == 0){ + WMT_DBG_FUNC("waiting dmp \n"); + wait_event_interruptible(dmp_wq, dmp_flag != 0); + dmp_flag = 0; + remaining = mtk_wcn_stp_btm_get_dmp(buf, &len); + + //WMT_INFO_FUNC("len = %d ###%s#\n", len, buf); + } else { + WMT_LOUD_FUNC("no waiting dmp \n"); + } + + if (unlikely((len+sizeof(INT32)) >= LOG_BUF_SZ)){ + WMT_ERR_FUNC("len is larger buffer\n"); + iRet = -EFAULT; + goto fail_exit; + } + + buf[sizeof(INT32)+len]='\0'; + + if (copy_to_user((void *)arg, (UCHAR *)&len, sizeof(INT32))){ + iRet = -EFAULT; + goto fail_exit; + } + + if (copy_to_user((void *)arg + sizeof(INT32), buf, len)){ + iRet = -EFAULT; + goto fail_exit; + } + } + break; + + case 10: + { + WMT_INFO_FUNC("Enable combo trace32 dump\n"); + wmt_cdev_t32dmp_enable(); + WMT_INFO_FUNC("Enable STP debugging mode\n"); + mtk_wcn_stp_dbg_enable(); + } + break; + + case 11: + { + WMT_INFO_FUNC("Disable combo trace32 dump\n"); + wmt_cdev_t32dmp_disable(); + WMT_INFO_FUNC("Disable STP debugging mode\n"); + mtk_wcn_stp_dbg_disable(); + } + break; +#endif + default: + iRet = -EINVAL; + WMT_WARN_FUNC("unknown cmd (%d)\n", cmd); + break; + } + + + return iRet; +} + +static int WMT_open(struct inode *inode, struct file *file) +{ + WMT_INFO_FUNC("major %d minor %d (pid %d)\n", + imajor(inode), + iminor(inode), + current->pid + ); + + if (atomic_inc_return(&gWmtRefCnt) == 1) { + WMT_INFO_FUNC("1st call \n"); + } + + return 0; +} + +static int WMT_close(struct inode *inode, struct file *file) +{ + WMT_INFO_FUNC("major %d minor %d (pid %d)\n", + imajor(inode), + iminor(inode), + current->pid + ); + + if (atomic_dec_return(&gWmtRefCnt) == 0) { + WMT_INFO_FUNC("last call \n"); + } + + return 0; +} + +ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); +ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); +long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); + +struct file_operations gWmtFops = { + .open = WMT_open, + .release = WMT_close, + .read = WMT_read, + .write = WMT_write, +// .ioctl = WMT_ioctl, + .unlocked_ioctl = WMT_unlocked_ioctl, + .poll = WMT_poll, +}; + + +static int WMT_init(void) +{ + dev_t devID = MKDEV(gWmtMajor, 0); + INT32 cdevErr = -1; + INT32 ret = -1; + + /* init start */ + gWmtInitDone = 0; + init_waitqueue_head((wait_queue_head_t *)&gWmtInitWq); + + WMT_INFO_FUNC("WMT Version= %s DATE=%s\n" , MTK_WMT_VERSION, MTK_WMT_DATE); + /* Prepare a UCHAR device */ + /*static allocate chrdev*/ + + stp_drv_init(); + + ret = register_chrdev_region(devID, WMT_DEV_NUM, WMT_DRIVER_NAME); + if (ret) { + WMT_ERR_FUNC("fail to register chrdev\n"); + return ret; + } + + cdev_init(&gWmtCdev, &gWmtFops); + gWmtCdev.owner = THIS_MODULE; + + cdevErr = cdev_add(&gWmtCdev, devID, WMT_DEV_NUM); + if (cdevErr) { + WMT_ERR_FUNC("cdev_add() fails (%d) \n", cdevErr); + goto error; + } + WMT_INFO_FUNC("driver(major %d) installed \n", gWmtMajor); + + +#if 0 + pWmtDevCtx = wmt_drv_create(); + if (!pWmtDevCtx) { + WMT_ERR_FUNC("wmt_drv_create() fails \n"); + goto error; + } + + ret = wmt_drv_init(pWmtDevCtx); + if (ret) { + WMT_ERR_FUNC("wmt_drv_init() fails (%d) \n", ret); + goto error; + } + + WMT_INFO_FUNC("stp_btmcb_reg\n"); + wmt_cdev_btmcb_reg(); + + ret = wmt_drv_start(pWmtDevCtx); + if (ret) { + WMT_ERR_FUNC("wmt_drv_start() fails (%d) \n", ret); + goto error; + } +#endif + ret = wmt_lib_init(); + if (ret) { + WMT_ERR_FUNC("wmt_lib_init() fails (%d) \n", ret); + goto error; + } +#if CFG_WMT_DBG_SUPPORT + wmt_dev_dbg_setup(); +#endif + + + WMT_INFO_FUNC("success \n"); + return 0; + +error: + + wmt_lib_deinit(); +#if CFG_WMT_DBG_SUPPORT + wmt_dev_dbg_remove(); + +#endif + if (cdevErr == 0) { + cdev_del(&gWmtCdev); + } + + if (ret == 0) { + unregister_chrdev_region(devID, WMT_DEV_NUM); + gWmtMajor = -1; + } + + stp_drv_exit(); + + WMT_ERR_FUNC("fail \n"); + + return -1; +} + +static void WMT_exit (void) +{ + dev_t dev = MKDEV(gWmtMajor, 0); + + + wmt_lib_deinit(); + +#if CFG_WMT_DBG_SUPPORT + wmt_dev_dbg_remove(); +#endif + + cdev_del(&gWmtCdev); + unregister_chrdev_region(dev, WMT_DEV_NUM); + gWmtMajor = -1; + + stp_drv_exit(); + + WMT_INFO_FUNC("done\n"); +} + +module_init(WMT_init); +module_exit(WMT_exit); +MODULE_LICENSE("Proprietary"); +MODULE_AUTHOR("MediaTek Inc WCN"); +MODULE_DESCRIPTION("MTK WCN combo driver for WMT character device"); + +module_param(gWmtMajor, uint, 0); + + diff --git a/drivers/mtk_wcn_combo/common/linux/wmt_exp.c b/drivers/mtk_wcn_combo/common/linux/wmt_exp.c new file mode 100755 index 000000000000..ca29f7e5430b --- /dev/null +++ b/drivers/mtk_wcn_combo/common/linux/wmt_exp.c @@ -0,0 +1,384 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-EXP]" + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "osal_typedef.h" +#include +#include +#include "core_exp.h" + + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +static MTK_WCN_BOOL +mtk_wcn_wmt_func_ctrl ( + ENUM_WMTDRV_TYPE_T type, + ENUM_WMT_OPID_T opId + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +static MTK_WCN_BOOL +mtk_wcn_wmt_func_ctrl ( + ENUM_WMTDRV_TYPE_T type, + ENUM_WMT_OPID_T opId + ) +{ + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + + pSignal = &pOp->signal; + + pOp->op.opId = opId; + pOp->op.au4OpData[0] = type; + pSignal->timeoutValue= (WMT_OPID_FUNC_ON == pOp->op.opId) ? MAX_FUNC_ON_TIME : MAX_FUNC_OFF_TIME; + + WMT_INFO_FUNC("OPID(%d) type(%d) start\n", + pOp->op.opId, + pOp->op.au4OpData[0]); + + /*do not check return value, we will do this either way*/ + wmt_lib_host_awake_get(); + /*wake up chip first*/ + wmt_lib_disable_psm_monitor(); + bRet = wmt_lib_put_act_op(pOp); + wmt_lib_enable_psm_monitor(); + wmt_lib_host_awake_put(); + + if (MTK_WCN_BOOL_FALSE == bRet) { + WMT_WARN_FUNC("OPID(%d) type(%d) fail\n", + pOp->op.opId, + pOp->op.au4OpData[0]); + } + else { + WMT_INFO_FUNC("OPID(%d) type(%d) ok\n", + pOp->op.opId, + pOp->op.au4OpData[0]); + } + return bRet; +} + +MTK_WCN_BOOL +mtk_wcn_wmt_func_off ( + ENUM_WMTDRV_TYPE_T type + ) +{ + return mtk_wcn_wmt_func_ctrl(type, WMT_OPID_FUNC_OFF); +} +EXPORT_SYMBOL(mtk_wcn_wmt_func_off); + +MTK_WCN_BOOL +mtk_wcn_wmt_func_on ( + ENUM_WMTDRV_TYPE_T type + ) +{ + return mtk_wcn_wmt_func_ctrl(type, WMT_OPID_FUNC_ON); +} +EXPORT_SYMBOL(mtk_wcn_wmt_func_on); + +/* +return value: +enable/disable thermal sensor function: true(1)/false(0) +read thermal sensor function:thermal value + +*/ +INT8 +mtk_wcn_wmt_therm_ctrl ( + ENUM_WMTTHERM_TYPE_T eType + ) +{ + P_OSAL_OP pOp; + P_WMT_OP pOpData; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + /*parameter validation check*/ + if( WMTTHERM_MAX < eType || WMTTHERM_ENABLE > eType){ + WMT_ERR_FUNC("invalid thermal control command (%d)\n", eType); + return MTK_WCN_BOOL_FALSE; + } + + /*check if chip support thermal control function or not*/ + bRet = wmt_lib_is_therm_ctrl_support(); + if (MTK_WCN_BOOL_FALSE == bRet) { + WMT_ERR_FUNC("thermal ctrl function not supported\n"); + return MTK_WCN_BOOL_FALSE; + } + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail \n"); + return MTK_WCN_BOOL_FALSE; + } + + pSignal = &pOp->signal; + pOpData = &pOp->op; + pOpData->opId = WMT_OPID_THERM_CTRL; + /*parameter fill*/ + pOpData->au4OpData[0] = eType; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + + WMT_INFO_FUNC("OPID(%d) type(%d) start\n", + pOp->op.opId, + pOp->op.au4OpData[0]); + + wmt_lib_disable_psm_monitor(); + bRet = wmt_lib_put_act_op(pOp); + wmt_lib_enable_psm_monitor(); + + if (MTK_WCN_BOOL_FALSE == bRet) { + WMT_WARN_FUNC("OPID(%d) type(%d) fail\n\n", + pOpData->opId, + pOpData->au4OpData[0]); + /*0xFF means read error occurs*/ + pOpData->au4OpData[1] = (eType == WMTTHERM_READ) ? 0xFF : MTK_WCN_BOOL_FALSE;/*will return to function driver*/ + } + else { + WMT_INFO_FUNC("OPID(%d) type(%d) return(%d) ok\n\n", + pOpData->opId, + pOpData->au4OpData[0], + pOpData->au4OpData[1]); + } + /*return value will be put to lxop->op.au4OpData[1]*/ + WMT_DBG_FUNC("therm ctrl type(%d), iRet(0x%08x) \n", eType, pOpData->au4OpData[1]); + return (INT8)pOpData->au4OpData[1]; +} +EXPORT_SYMBOL(mtk_wcn_wmt_therm_ctrl); + +ENUM_WMTHWVER_TYPE_T +mtk_wcn_wmt_hwver_get (VOID) +{ + // TODO: [ChangeFeature][GeorgeKuo] Reconsider usage of this type + // TODO: how do we extend for new chip and newer revision? + // TODO: This way is hard to extend + return wmt_lib_get_hwver(); +} +EXPORT_SYMBOL(mtk_wcn_wmt_hwver_get); + +MTK_WCN_BOOL +mtk_wcn_wmt_dsns_ctrl ( + ENUM_WMTDSNS_TYPE_T eType + ) +{ + P_OSAL_OP pOp; + P_WMT_OP pOpData; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + if (WMTDSNS_MAX <= eType) { + WMT_ERR_FUNC("invalid desense control command (%d)\n", eType); + return MTK_WCN_BOOL_FALSE; + } + + /*check if chip support thermal control function or not*/ + bRet = wmt_lib_is_dsns_ctrl_support(); + if (MTK_WCN_BOOL_FALSE == bRet) { + WMT_ERR_FUNC("thermal ctrl function not supported\n"); + return MTK_WCN_BOOL_FALSE; + } + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail \n"); + return MTK_WCN_BOOL_FALSE; + } + + pSignal = &pOp->signal; + pOpData = &pOp->op; + pOpData->opId = WMT_OPID_DSNS; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + /*parameter fill*/ + if (WMTDSNS_FM_DISABLE == eType) { + pOpData->au4OpData[0] = WMTDRV_TYPE_FM; + pOpData->au4OpData[1] = 0x0; + } + else { /* input sanity had been verified *//*if (eType == WMTDSNS_FM_ENABLE)*/ + pOpData->au4OpData[0] = WMTDRV_TYPE_FM; + pOpData->au4OpData[1] = 0x1; + } + + WMT_INFO_FUNC("OPID(%d) type(%d) start\n", + pOp->op.opId, + pOp->op.au4OpData[0]); + + wmt_lib_disable_psm_monitor(); + bRet = wmt_lib_put_act_op(pOp); + wmt_lib_enable_psm_monitor(); + + if (MTK_WCN_BOOL_FALSE == bRet) { + WMT_WARN_FUNC("OPID(%d) type(%d) fail\n\n", + pOpData->opId, + pOpData->au4OpData[0]); + } + else { + WMT_INFO_FUNC("OPID(%d) type(%d) ok\n\n", + pOpData->opId, + pOpData->au4OpData[0]); + } + + return bRet; +} +EXPORT_SYMBOL(mtk_wcn_wmt_dsns_ctrl); + +INT32 +mtk_wcn_wmt_msgcb_reg ( + ENUM_WMTDRV_TYPE_T eType, + PF_WMT_CB pCb + ) +{ + return (INT32)wmt_lib_msgcb_reg(eType, pCb); +} +EXPORT_SYMBOL(mtk_wcn_wmt_msgcb_reg); + +INT32 +mtk_wcn_wmt_msgcb_unreg ( + ENUM_WMTDRV_TYPE_T eType + ) +{ + return (INT32)wmt_lib_msgcb_unreg(eType); +} +EXPORT_SYMBOL(mtk_wcn_wmt_msgcb_unreg); + +INT32 +mtk_wcn_stp_wmt_sdio_op_reg ( + PF_WMT_SDIO_PSOP own_cb + ) +{ + wmt_lib_ps_set_sdio_psop(own_cb); + return 0; +} +EXPORT_SYMBOL(mtk_wcn_stp_wmt_sdio_op_reg); + diff --git a/drivers/mtk_wcn_combo/common/platform/rockchip/mtk_wcn_cmb_hw_6620.c b/drivers/mtk_wcn_combo/common/platform/rockchip/mtk_wcn_cmb_hw_6620.c new file mode 100755 index 000000000000..47bf98d277dc --- /dev/null +++ b/drivers/mtk_wcn_combo/common/platform/rockchip/mtk_wcn_cmb_hw_6620.c @@ -0,0 +1,346 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-CMB-HW]" + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "osal.h" +#include "mtk_wcn_cmb_hw.h" +#include "wmt_plat.h" +#include "wmt_exp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define DFT_RTC_STABLE_TIME 100 +#define DFT_LDO_STABLE_TIME 100 +#define DFT_RST_STABLE_TIME 30 +#define DFT_OFF_STABLE_TIME 10 +#define DFT_ON_STABLE_TIME 30 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +PWR_SEQ_TIME gPwrSeqTime; + + + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +INT32 +mtk_wcn_cmb_hw_pwr_off (VOID) +{ + INT32 iRet = 0; + WMT_INFO_FUNC("CMB-HW, hw_pwr_off start\n"); + + /*1. disable irq --> should be done when do wmt-ic swDeinit period*/ + // TODO:[FixMe][GeorgeKuo] clarify this + + /*2. set bgf eint/all eint to deinit state, namely input low state*/ + iRet += wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); + WMT_INFO_FUNC("CMB-HW, BGF_EINT IRQ unregistered and disabled\n"); + iRet += wmt_plat_gpio_ctrl(PIN_BGF_EINT, PIN_STA_DEINIT); + /* 2.1 set ALL_EINT pin to correct state even it is not used currently */ + iRet += wmt_plat_eirq_ctrl(PIN_ALL_EINT, PIN_STA_EINT_DIS); + WMT_INFO_FUNC("CMB-HW, ALL_EINT IRQ unregistered and disabled\n"); + iRet += wmt_plat_gpio_ctrl(PIN_ALL_EINT, PIN_STA_DEINIT); + /* 2.2 deinit gps sync */ + iRet += wmt_plat_gpio_ctrl(PIN_GPS_SYNC, PIN_STA_DEINIT); + + /*3. set audio interface to CMB_STUB_AIF_0, BT PCM OFF, I2S OFF*/ + iRet += wmt_plat_audio_ctrl(CMB_STUB_AIF_0, CMB_STUB_AIF_CTRL_DIS); + + /*4. set control gpio into deinit state, namely input low state*/ + iRet += wmt_plat_gpio_ctrl(PIN_SDIO_GRP, PIN_STA_DEINIT); + iRet += wmt_plat_gpio_ctrl(PIN_RST, PIN_STA_OUT_L); + iRet += wmt_plat_gpio_ctrl(PIN_PMU, PIN_STA_OUT_L); + + /*5. set uart tx/rx into deinit state, namely input low state*/ + iRet += wmt_plat_gpio_ctrl(PIN_UART_GRP, PIN_STA_DEINIT); + + /* 6. Last, LDO output low */ + iRet += wmt_plat_gpio_ctrl(PIN_LDO, PIN_STA_OUT_L); + + /*7. deinit gps_lna*/ + iRet += wmt_plat_gpio_ctrl(PIN_GPS_LNA, PIN_STA_DEINIT); + + WMT_INFO_FUNC("CMB-HW, hw_pwr_off finish\n"); + return iRet; +} + +INT32 +mtk_wcn_cmb_hw_pwr_on (VOID) +{ + static UINT32 _pwr_first_time = 1; + INT32 iRet = 0; + + WMT_INFO_FUNC("CMB-HW, hw_pwr_on start\n"); +#if 0 //IRQ should in inact state before power on, so this step is not needed + /* disable interrupt firstly */ + iRet += wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); + iRet += wmt_plat_eirq_ctrl(PIN_ALL_EINT, PIN_STA_EINT_DIS); +#endif + /*set all control and eint gpio to init state, namely input low mode*/ + iRet += wmt_plat_gpio_ctrl(PIN_LDO, PIN_STA_INIT); + iRet += wmt_plat_gpio_ctrl(PIN_PMU, PIN_STA_INIT); + iRet += wmt_plat_gpio_ctrl(PIN_RST, PIN_STA_INIT); + iRet += wmt_plat_gpio_ctrl(PIN_SDIO_GRP, PIN_STA_INIT); + iRet += wmt_plat_gpio_ctrl(PIN_BGF_EINT, PIN_STA_INIT); + iRet += wmt_plat_gpio_ctrl(PIN_ALL_EINT, PIN_STA_INIT); + iRet += wmt_plat_gpio_ctrl(PIN_GPS_SYNC, PIN_STA_INIT); + iRet += wmt_plat_gpio_ctrl(PIN_GPS_LNA, PIN_STA_INIT); + // wmt_plat_gpio_ctrl(PIN_WIFI_EINT, PIN_STA_INIT); /* WIFI_EINT is controlled by SDIO host driver */ + // TODO: [FixMe][George]:WIFI_EINT is used in common SDIO + + /*1. pull high LDO to supply power to chip*/ + iRet += wmt_plat_gpio_ctrl(PIN_LDO, PIN_STA_OUT_H); + osal_msleep(gPwrSeqTime.ldoStableTime); + + /* 2. export RTC clock to chip*/ + if (_pwr_first_time) { + /* rtc clock should be output all the time, so no need to enable output again*/ + iRet += wmt_plat_gpio_ctrl(PIN_RTC, PIN_STA_INIT); + osal_msleep(gPwrSeqTime.rtcStableTime); + WMT_INFO_FUNC("CMB-HW, rtc clock exported\n"); + } + + /*3. set UART Tx/Rx to UART mode*/ + iRet += wmt_plat_gpio_ctrl(PIN_UART_GRP, PIN_STA_INIT); + + /*4. PMU->output low, RST->output low, sleep off stable time*/ + iRet += wmt_plat_gpio_ctrl(PIN_PMU, PIN_STA_OUT_L); + iRet += wmt_plat_gpio_ctrl(PIN_RST, PIN_STA_OUT_L); + osal_msleep(gPwrSeqTime.offStableTime); + + /*5. PMU->output high, sleep rst stable time*/ + iRet += wmt_plat_gpio_ctrl(PIN_PMU, PIN_STA_OUT_H); + osal_msleep(gPwrSeqTime.rstStableTime); + + /*6. RST->output high, sleep on stable time*/ + iRet += wmt_plat_gpio_ctrl(PIN_RST, PIN_STA_OUT_H); + osal_msleep(gPwrSeqTime.onStableTime); + + /*7. set audio interface to CMB_STUB_AIF_1, BT PCM ON, I2S OFF*/ + /* BT PCM bus default mode. Real control is done by audio */ + iRet += wmt_plat_audio_ctrl(CMB_STUB_AIF_1, CMB_STUB_AIF_CTRL_DIS); + + /*8. set EINT< -ommited-> move this to WMT-IC module, where common sdio interface will be identified and do proper operation*/ + // TODO: [FixMe][GeorgeKuo] double check if BGF_INT is implemented ok + iRet += wmt_plat_gpio_ctrl(PIN_BGF_EINT, PIN_STA_MUX); + iRet += wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_INIT); + iRet += wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); + WMT_INFO_FUNC("CMB-HW, BGF_EINT IRQ registered and disabled \n"); + + /* 8.1 set ALL_EINT pin to correct state even it is not used currently */ + iRet += wmt_plat_gpio_ctrl(PIN_ALL_EINT, PIN_STA_MUX); + iRet += wmt_plat_eirq_ctrl(PIN_ALL_EINT, PIN_STA_INIT); + iRet += wmt_plat_eirq_ctrl(PIN_ALL_EINT, PIN_STA_EINT_DIS); + WMT_INFO_FUNC("CMB-HW, hw_pwr_on finish (%d)\n", iRet); + + _pwr_first_time = 0; + return iRet; + +} + +INT32 +mtk_wcn_cmb_hw_rst (VOID) +{ + INT32 iRet = 0; + WMT_INFO_FUNC("CMB-HW, hw_rst start, eirq should be disabled before this step\n"); + + /*1. PMU->output low, RST->output low, sleep off stable time*/ + iRet += wmt_plat_gpio_ctrl(PIN_PMU, PIN_STA_OUT_L); + iRet += wmt_plat_gpio_ctrl(PIN_RST, PIN_STA_OUT_L); + osal_msleep(gPwrSeqTime.offStableTime); + + /*2. PMU->output high, sleep rst stable time*/ + iRet += wmt_plat_gpio_ctrl(PIN_PMU, PIN_STA_OUT_H); + osal_msleep(gPwrSeqTime.rstStableTime); + + /*3. RST->output high, sleep on stable time*/ + iRet += wmt_plat_gpio_ctrl(PIN_RST, PIN_STA_OUT_H); + osal_msleep(gPwrSeqTime.onStableTime); + WMT_INFO_FUNC("CMB-HW, hw_rst finish, eirq should be enabled after this step\n"); + return 0; +} + +static VOID +mtk_wcn_cmb_hw_dmp_seq (VOID) +{ + PUINT32 pTimeSlot = (PUINT32)&gPwrSeqTime; + WMT_INFO_FUNC("combo chip power on sequence time, RTC (%d), LDO (%d), RST(%d), OFF(%d), ON(%d)\n", + pTimeSlot[0], /**pTimeSlot++,*/ + pTimeSlot[1], + pTimeSlot[2], + pTimeSlot[3], + pTimeSlot[4] + ); + return; +} + +INT32 +mtk_wcn_cmb_hw_init ( + P_PWR_SEQ_TIME pPwrSeqTime + ) +{ + if (NULL != pPwrSeqTime && + pPwrSeqTime->ldoStableTime > 0 && + pPwrSeqTime->rtcStableTime > 0 && + pPwrSeqTime->offStableTime > DFT_OFF_STABLE_TIME && + pPwrSeqTime->onStableTime > DFT_ON_STABLE_TIME && + pPwrSeqTime->rstStableTime > DFT_RST_STABLE_TIME + ) { + /*memcpy may be more performance*/ + WMT_DBG_FUNC("setting hw init sequence parameters\n"); + osal_memcpy(&gPwrSeqTime, pPwrSeqTime, osal_sizeof(gPwrSeqTime)); + } + else { + WMT_WARN_FUNC("invalid pPwrSeqTime parameter, use default hw init sequence parameters\n"); + gPwrSeqTime.ldoStableTime = DFT_LDO_STABLE_TIME; + gPwrSeqTime.offStableTime = DFT_OFF_STABLE_TIME; + gPwrSeqTime.onStableTime = DFT_ON_STABLE_TIME; + gPwrSeqTime.rstStableTime = DFT_RST_STABLE_TIME; + gPwrSeqTime.rtcStableTime = DFT_RTC_STABLE_TIME; + } + mtk_wcn_cmb_hw_dmp_seq(); + return 0; +} + +INT32 +mtk_wcn_cmb_hw_deinit (VOID) +{ + + WMT_WARN_FUNC("mtk_wcn_cmb_hw_deinit start, set to default hw init sequence parameters\n"); + gPwrSeqTime.ldoStableTime = DFT_LDO_STABLE_TIME; + gPwrSeqTime.offStableTime = DFT_OFF_STABLE_TIME; + gPwrSeqTime.onStableTime = DFT_ON_STABLE_TIME; + gPwrSeqTime.rstStableTime = DFT_RST_STABLE_TIME; + gPwrSeqTime.rtcStableTime = DFT_RTC_STABLE_TIME; + WMT_WARN_FUNC("mtk_wcn_cmb_hw_deinit finish\n"); + return 0; +} + diff --git a/drivers/mtk_wcn_combo/common/platform/rockchip/mtk_wcn_cmb_stub_rockchip.c b/drivers/mtk_wcn_combo/common/platform/rockchip/mtk_wcn_cmb_stub_rockchip.c new file mode 100755 index 000000000000..69546c061c29 --- /dev/null +++ b/drivers/mtk_wcn_combo/common/platform/rockchip/mtk_wcn_cmb_stub_rockchip.c @@ -0,0 +1,348 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define CMB_STUB_LOG_INFO(fmt, arg...) printk(KERN_INFO fmt, ##arg) +#define CMB_STUB_LOG_WARN(fmt, arg...) printk(KERN_WARNING fmt, ##arg) +#define CMB_STUB_LOG_DBG(fmt, arg...) printk(KERN_DEBUG fmt, ##arg) + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include +#include +//#include +//#include /* clr_device_working_ability, MT65XX_PDN_PERI_UART3, DEEP_IDLE_STATE, MT65XX_PDN_PERI_MSDC2 */ +//#include +// TODO: [FixMe][GeorgeKuo] keep prototype unchanged temporarily. Replace it +// when integrate MT6628 & ALPS & other built-in modules, such as AUDIO. +//#include + +#include + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + + + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +static wmt_aif_ctrl_cb cmb_stub_aif_ctrl_cb = NULL; +static wmt_func_ctrl_cb cmb_stub_func_ctrl_cb = NULL; +static CMB_STUB_AIF_X cmb_stub_aif_stat = CMB_STUB_AIF_0; + +/* A temp translation table between COMBO_AUDIO_STATE_X and CMB_STUB_AIF_X. + * This is used for ALPS backward compatible ONLY!!! Remove this table, related + * functions, and type definition after modifying other kernel built-in modules, + * such as AUDIO. [FixMe][GeorgeKuo] + */ +static CMB_STUB_AIF_X audio2aif[] = { + [COMBO_AUDIO_STATE_0] = CMB_STUB_AIF_0, + [COMBO_AUDIO_STATE_1] = CMB_STUB_AIF_1, + [COMBO_AUDIO_STATE_2] = CMB_STUB_AIF_2, + [COMBO_AUDIO_STATE_3] = CMB_STUB_AIF_3, +}; + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*! + * \brief A registration function for WMT-PLAT to register itself to CMB-STUB. + * + * An MTK-WCN-CMB-STUB registration function provided to WMT-PLAT to register + * itself and related callback functions when driver being loaded into kernel. + * + * \param p_stub_cb a pointer carrying CMB_STUB_CB information + * + * \retval 0 operation success + * \retval -1 invalid parameters + */ +int +mtk_wcn_cmb_stub_reg (P_CMB_STUB_CB p_stub_cb) +{ + if ( (!p_stub_cb ) + || (p_stub_cb->size != sizeof(CMB_STUB_CB)) ) { + CMB_STUB_LOG_WARN( "[cmb_stub] invalid p_stub_cb:0x%p size(%d)\n", + p_stub_cb, (p_stub_cb) ? p_stub_cb->size: 0); + return -1; + } + + CMB_STUB_LOG_DBG( "[cmb_stub] registered, p_stub_cb:0x%p size(%d)\n", + p_stub_cb, p_stub_cb->size); + + cmb_stub_aif_ctrl_cb = p_stub_cb->aif_ctrl_cb; + cmb_stub_func_ctrl_cb = p_stub_cb->func_ctrl_cb; + + return 0; +} +EXPORT_SYMBOL(mtk_wcn_cmb_stub_reg); + +/*! + * \brief A unregistration function for WMT-PLAT to unregister from CMB-STUB. + * + * An MTK-WCN-CMB-STUB unregistration function provided to WMT-PLAT to + * unregister itself and clear callback function references. + * + * \retval 0 operation success + */ +int +mtk_wcn_cmb_stub_unreg (void) +{ + cmb_stub_aif_ctrl_cb = NULL; + cmb_stub_func_ctrl_cb = NULL; + + CMB_STUB_LOG_INFO("[cmb_stub] unregistered \n"); /* KERN_DEBUG */ + + return 0; +} +EXPORT_SYMBOL(mtk_wcn_cmb_stub_unreg); + +/* stub functions for kernel to control audio path pin mux */ +int mtk_wcn_cmb_stub_aif_ctrl (CMB_STUB_AIF_X state, CMB_STUB_AIF_CTRL ctrl) +{ + int ret; + + if ( (CMB_STUB_AIF_MAX <= state) + || (CMB_STUB_AIF_CTRL_MAX <= ctrl) ) { + + CMB_STUB_LOG_WARN("[cmb_stub] aif_ctrl invalid (%d, %d)\n", state, ctrl); + return -1; + } + + /* avoid the early interrupt before we register the eirq_handler */ + if (cmb_stub_aif_ctrl_cb){ + ret = (*cmb_stub_aif_ctrl_cb)(state, ctrl); + CMB_STUB_LOG_INFO( "[cmb_stub] aif_ctrl_cb state(%d->%d) ctrl(%d) ret(%d)\n", + cmb_stub_aif_stat , state, ctrl, ret); /* KERN_DEBUG */ + + cmb_stub_aif_stat = state; + return ret; + } + else { + CMB_STUB_LOG_WARN("[cmb_stub] aif_ctrl_cb null \n"); + return -2; + } +} +EXPORT_SYMBOL(mtk_wcn_cmb_stub_aif_ctrl); + +/* Use a temp translation table between COMBO_AUDIO_STATE_X and CMB_STUB_AIF_X + * for ALPS backward compatible ONLY!!! Remove this table, related functions, + * and type definition after modifying other kernel built-in modules, such as + * AUDIO. [FixMe][GeorgeKuo] + */ +int +mt_combo_audio_ctrl_ex (COMBO_AUDIO_STATE state, u32 clt_ctrl) +{ + /* input sanity check */ + if (COMBO_AUDIO_STATE_MAX < state) { + CMB_STUB_LOG_WARN("[cmb_stub] invalid COMBO_AUDIO_STATE(%d)\n", state); + return -1; + } + + return mtk_wcn_cmb_stub_aif_ctrl(audio2aif[state], + (clt_ctrl) ? CMB_STUB_AIF_CTRL_EN : CMB_STUB_AIF_CTRL_DIS ); +} +EXPORT_SYMBOL(mt_combo_audio_ctrl_ex); + +void mtk_wcn_cmb_stub_func_ctrl (unsigned int type, unsigned int on) { + if (cmb_stub_func_ctrl_cb) { + (*cmb_stub_func_ctrl_cb)(type, on); + } + else { + CMB_STUB_LOG_WARN("[cmb_stub] func_ctrl_cb null \n"); + } +} +EXPORT_SYMBOL(mtk_wcn_cmb_stub_func_ctrl); + +/*platform-related APIs*/ +//void clr_device_working_ability(UINT32 clockId, MT6573_STATE state); +//void set_device_working_ability(UINT32 clockId, MT6573_STATE state); + +static int +_mt_combo_plt_do_deep_idle(COMBO_IF src, int enter) { + int ret = -1; + + const char *combo_if_name[] = + { "COMBO_IF_UART", + "COMBO_IF_MSDC" + }; + + if(src != COMBO_IF_UART && src!= COMBO_IF_MSDC){ + CMB_STUB_LOG_WARN("src = %d is error\n", src); + return ret; + } + + if(src >= 0 && src < COMBO_IF_MAX){ + CMB_STUB_LOG_INFO("src = %s, to enter deep idle? %d \n", + combo_if_name[src], + enter); + } + + /*TODO: For Common SDIO configuration, we need to do some judgement between STP and WIFI + to decide if the msdc will enter deep idle safely*/ + + switch(src){ + case COMBO_IF_UART: + if(enter == 0){ + //clr_device_working_ability(MT65XX_PDN_PERI_UART3, DEEP_IDLE_STATE); + //disable_dpidle_by_bit(MT65XX_PDN_PERI_UART2); + } else { + //set_device_working_ability(MT65XX_PDN_PERI_UART3, DEEP_IDLE_STATE); + //enable_dpidle_by_bit(MT65XX_PDN_PERI_UART2); + } + ret = 0; + break; + + case COMBO_IF_MSDC: + if(enter == 0){ + //clr_device_working_ability(MT65XX_PDN_PERI_MSDC2, DEEP_IDLE_STATE); + } else { + //set_device_working_ability(MT65XX_PDN_PERI_MSDC2, DEEP_IDLE_STATE); + } + ret = 0; + break; + + default: + ret = -1; + break; + } + + return ret; +} + +int +mt_combo_plt_enter_deep_idle ( + COMBO_IF src + ) { + //return 0; + // TODO: [FixMe][GeorgeKuo] handling this depends on common UART or common SDIO + return _mt_combo_plt_do_deep_idle(src, 1); +} +EXPORT_SYMBOL(mt_combo_plt_enter_deep_idle); + +int +mt_combo_plt_exit_deep_idle ( + COMBO_IF src + ) { + //return 0; + // TODO: [FixMe][GeorgeKuo] handling this depends on common UART or common SDIO + return _mt_combo_plt_do_deep_idle(src, 0); +} +EXPORT_SYMBOL(mt_combo_plt_exit_deep_idle); + diff --git a/drivers/mtk_wcn_combo/common/platform/rockchip/wmt_plat_rockchip.c b/drivers/mtk_wcn_combo/common/platform/rockchip/wmt_plat_rockchip.c new file mode 100755 index 000000000000..22731d927bc0 --- /dev/null +++ b/drivers/mtk_wcn_combo/common/platform/rockchip/wmt_plat_rockchip.c @@ -0,0 +1,906 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#if CONFIG_HAS_WAKELOCK +#include +#define CFG_WMT_WAKELOCK_SUPPORT 1 +#endif + + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-PLAT]" + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/*s5p headers*/ +#include +#include + +/* MTK_WCN_COMBO header files */ +#include "wmt_plat.h" +#include "wmt_exp.h" +#include "mtk_wcn_cmb_hw.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +static VOID wmt_plat_func_ctrl (UINT32 type, UINT32 on); +static VOID wmt_plat_bgf_eirq_cb (VOID); + +static INT32 wmt_plat_ldo_ctrl (ENUM_PIN_STATE state); +static INT32 wmt_plat_pmu_ctrl (ENUM_PIN_STATE state); +static INT32 wmt_plat_rtc_ctrl (ENUM_PIN_STATE state); +static INT32 wmt_plat_rst_ctrl (ENUM_PIN_STATE state); +static INT32 wmt_plat_bgf_eint_ctrl (ENUM_PIN_STATE state); +static INT32 wmt_plat_wifi_eint_ctrl (ENUM_PIN_STATE state); +static INT32 wmt_plat_all_eint_ctrl (ENUM_PIN_STATE state); +static INT32 wmt_plat_uart_ctrl (ENUM_PIN_STATE state); +static INT32 wmt_plat_pcm_ctrl (ENUM_PIN_STATE state); +static INT32 wmt_plat_i2s_ctrl (ENUM_PIN_STATE state); +static INT32 wmt_plat_sdio_pin_ctrl (ENUM_PIN_STATE state); +static INT32 wmt_plat_gps_sync_ctrl (ENUM_PIN_STATE state); +static INT32 wmt_plat_gps_lna_ctrl (ENUM_PIN_STATE state); + +static INT32 wmt_plat_dump_pin_conf (VOID); + + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + + + + +#if CFG_WMT_WAKELOCK_SUPPORT +static OSAL_SLEEPABLE_LOCK gOsSLock; +static struct wake_lock wmtWakeLock; +#endif + +const static fp_set_pin gfp_set_pin_table[] = +{ + [PIN_LDO] = wmt_plat_ldo_ctrl, + [PIN_PMU] = wmt_plat_pmu_ctrl, + [PIN_RTC] = wmt_plat_rtc_ctrl, + [PIN_RST] = wmt_plat_rst_ctrl, + [PIN_BGF_EINT] = wmt_plat_bgf_eint_ctrl, + [PIN_WIFI_EINT] = wmt_plat_wifi_eint_ctrl, + [PIN_ALL_EINT] = wmt_plat_all_eint_ctrl, + [PIN_UART_GRP] = wmt_plat_uart_ctrl, + [PIN_PCM_GRP] = wmt_plat_pcm_ctrl, + [PIN_I2S_GRP] = wmt_plat_i2s_ctrl, + [PIN_SDIO_GRP] = wmt_plat_sdio_pin_ctrl, + [PIN_GPS_SYNC] = wmt_plat_gps_sync_ctrl, + [PIN_GPS_LNA] = wmt_plat_gps_lna_ctrl, + +}; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*! + * \brief audio control callback function for CMB_STUB on ALPS + * + * A platform function required for dynamic binding with CMB_STUB on ALPS. + * + * \param state desired audio interface state to use + * \param flag audio interface control options + * + * \retval 0 operation success + * \retval -1 invalid parameters + * \retval < 0 error for operation fail + */ +INT32 wmt_plat_audio_ctrl (CMB_STUB_AIF_X state, CMB_STUB_AIF_CTRL ctrl) +{ + INT32 iRet = 0; + UINT32 pinShare; + + /* input sanity check */ + if ( (CMB_STUB_AIF_MAX <= state) + || (CMB_STUB_AIF_CTRL_MAX <= ctrl) ) { + iRet = -1; + WMT_ERR_FUNC("WMT-PLAT: invalid para, state(%d), ctrl(%d),iRet(%d) \n", state, ctrl, iRet); + return iRet; + } + if (0/*I2S/PCM share pin*/) { + // TODO: [FixMe][GeorgeKuo] how about MT6575? The following is applied to MT6573E1 only!! + pinShare = 1; + WMT_INFO_FUNC( "PCM/I2S pin share\n"); + } + else{ //E1 later + pinShare = 0; + WMT_INFO_FUNC( "PCM/I2S pin seperate\n"); + } + + iRet = 0; + + /* set host side first */ + switch (state) { + case CMB_STUB_AIF_0: + /* BT_PCM_OFF & FM line in/out */ + iRet += wmt_plat_gpio_ctrl(PIN_PCM_GRP, PIN_STA_DEINIT); + iRet += wmt_plat_gpio_ctrl(PIN_I2S_GRP, PIN_STA_DEINIT); + break; + + case CMB_STUB_AIF_1: + iRet += wmt_plat_gpio_ctrl(PIN_PCM_GRP, PIN_STA_INIT); + iRet += wmt_plat_gpio_ctrl(PIN_I2S_GRP, PIN_STA_DEINIT); + break; + + case CMB_STUB_AIF_2: + iRet += wmt_plat_gpio_ctrl(PIN_PCM_GRP, PIN_STA_DEINIT); + iRet += wmt_plat_gpio_ctrl(PIN_I2S_GRP, PIN_STA_INIT); + break; + + case CMB_STUB_AIF_3: + iRet += wmt_plat_gpio_ctrl(PIN_PCM_GRP, PIN_STA_INIT); + iRet += wmt_plat_gpio_ctrl(PIN_I2S_GRP, PIN_STA_INIT); + break; + + default: + /* FIXME: move to cust folder? */ + WMT_ERR_FUNC("invalid state [%d]\n", state); + return -1; + break; + } + + if (CMB_STUB_AIF_CTRL_EN == ctrl) { + WMT_INFO_FUNC("call chip aif setting \n"); + /* need to control chip side GPIO */ + iRet += wmt_lib_set_aif(state, (pinShare) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE); + } + else { + WMT_INFO_FUNC("skip chip aif setting \n"); + } + return iRet; + +} + +static VOID wmt_plat_func_ctrl (UINT32 type, UINT32 on) +{ + if (on) { + mtk_wcn_wmt_func_on((ENUM_WMTDRV_TYPE_T)type); + } + else { + mtk_wcn_wmt_func_off((ENUM_WMTDRV_TYPE_T)type); + } + return; +} + +#if CFG_WMT_PS_SUPPORT +irqreturn_t irq_handler(int i, void *arg) +{ + wmt_plat_bgf_eirq_cb(); + return IRQ_HANDLED; +} +#endif + +static VOID +wmt_plat_bgf_eirq_cb (VOID) +{ +#if CFG_WMT_PS_SUPPORT +//#error "need to disable EINT here" + WMT_INFO_FUNC("WMT-PLAT:BGFInt (++) \n"); + wmt_lib_ps_irq_cb(); + WMT_INFO_FUNC("WMT-PLAT:BGFInt (++) \n"); + +#else + return; +#endif + +} + +INT32 +wmt_plat_init (P_PWR_SEQ_TIME pPwrSeqTime) +{ + CMB_STUB_CB stub_cb; + /*PWR_SEQ_TIME pwr_seq_time;*/ + INT32 iret; + + stub_cb.aif_ctrl_cb = wmt_plat_audio_ctrl; + stub_cb.func_ctrl_cb = wmt_plat_func_ctrl; + stub_cb.size = sizeof(stub_cb); + + /* register to cmb_stub */ + iret = mtk_wcn_cmb_stub_reg(&stub_cb); + + /* init cmb_hw */ + iret += mtk_wcn_cmb_hw_init(pPwrSeqTime); + + /*init wmt function ctrl wakelock if wake lock is supported by host platform*/ + #ifdef CFG_WMT_WAKELOCK_SUPPORT + wake_lock_init(&wmtWakeLock, WAKE_LOCK_SUSPEND, "wmtFuncCtrl"); + osal_sleepable_lock_init(&gOsSLock); + #endif + + WMT_DBG_FUNC("WMT-PLAT: ALPS platform init (%d)\n", iret); + + return 0; +} + + +INT32 +wmt_plat_deinit (VOID) +{ + INT32 iret; + + /* 1. de-init cmb_hw */ + iret = mtk_wcn_cmb_hw_deinit(); + /* 2. unreg to cmb_stub */ + iret += mtk_wcn_cmb_stub_unreg(); + /*3. wmt wakelock deinit*/ + #ifdef CFG_WMT_WAKELOCK_SUPPORT + wake_lock_destroy(&wmtWakeLock); + osal_sleepable_lock_deinit(&gOsSLock); + WMT_DBG_FUNC("destroy wmtWakeLock\n"); + #endif + WMT_DBG_FUNC("WMT-PLAT: ALPS platform init (%d)\n", iret); + + return 0; +} + +INT32 wmt_plat_sdio_ctrl (WMT_SDIO_SLOT_NUM sdioPortType, ENUM_FUNC_STATE on) +{ + if (FUNC_OFF == on) { + /* add control logic here to generate SDIO CARD REMOVAL event to mmc/sd + * controller. SDIO card removal operation and remove success messages + * are expected. + */ + } + else { + /* add control logic here to generate SDIO CARD INSERTION event to mmc/sd + * controller. SDIO card detection operation and detect success messages + * are expected. + */ + } + return 0; +} + +INT32 +wmt_plat_irq_ctrl ( + ENUM_FUNC_STATE state + ) +{ + return -1; +} + + +static INT32 +wmt_plat_dump_pin_conf (VOID) +{ + WMT_INFO_FUNC( "[WMT-PLAT]=>dump wmt pin configuration start<=\n"); + WMT_INFO_FUNC( "[WMT-PLAT]=>dump wmt pin configuration emds<=\n"); + return 0; +} + + +INT32 wmt_plat_pwr_ctrl ( + ENUM_FUNC_STATE state + ) +{ + INT32 ret = -1; + + switch (state) { + case FUNC_ON: + // TODO:[ChangeFeature][George] always output this or by request throuth /proc or sysfs? + wmt_plat_dump_pin_conf(); + ret = mtk_wcn_cmb_hw_pwr_on(); + break; + + case FUNC_OFF: + ret = mtk_wcn_cmb_hw_pwr_off(); + break; + + case FUNC_RST: + ret = mtk_wcn_cmb_hw_rst(); + break; + + default: + WMT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) in pwr_ctrl\n", state); + break; + } + + return ret; +} + +INT32 wmt_plat_ps_ctrl (ENUM_FUNC_STATE state) +{ + return -1; +} + +INT32 +wmt_plat_eirq_ctrl ( + ENUM_PIN_ID id, + ENUM_PIN_STATE state + ) +{ + INT32 iRet; + + // TODO: [ChangeFeature][GeorgeKuo]: use another function to handle this, as done in gpio_ctrls + + if ( (PIN_STA_INIT != state ) + && (PIN_STA_DEINIT != state ) + && (PIN_STA_EINT_EN != state ) + && (PIN_STA_EINT_DIS != state ) ) { + iRet = -1; + WMT_WARN_FUNC("WMT-PLAT:invalid PIN_STATE(%d) in eirq_ctrl for PIN(%d), ret(%d) \n", state, id, iRet); + return iRet; + } + + iRet = -2; + switch (id) { + case PIN_BGF_EINT: + if (PIN_STA_INIT == state) { + + WMT_INFO_FUNC("WMT-PLAT:BGFInt (init) \n"); + } + else if (PIN_STA_EINT_EN == state) { + WMT_INFO_FUNC("WMT-PLAT:BGFInt (en) \n"); + } + else if (PIN_STA_EINT_DIS == state) { + WMT_INFO_FUNC("WMT-PLAT:BGFInt (dis) \n"); + } + else { + /* de-init: nothing to do in ALPS, such as un-registration... */ + WMT_INFO_FUNC("WMT-PLAT:BGFInt (deinit) \n"); + + } + iRet = 0; + break; + + case PIN_ALL_EINT: +#if 0 + if (PIN_STA_INIT == state) { + + WMT_DBG_FUNC("WMT-PLAT:ALLInt (INIT but not used yet) \n"); + } + else if (PIN_STA_EINT_EN == state) { + WMT_DBG_FUNC("WMT-PLAT:ALLInt (EN but not used yet) \n"); + } + else if (PIN_STA_EINT_DIS == state) { + WMT_DBG_FUNC("WMT-PLAT:ALLInt (DIS but not used yet) \n"); + } + else { + + WMT_DBG_FUNC("WMT-PLAT:ALLInt (DEINIT but not used yet) \n"); + /* de-init: nothing to do in ALPS, such as un-registration... */ + } +#else + WMT_DBG_FUNC("WMT-PLAT:ALLInt (not used yet) \n"); +#endif + iRet = 0; + break; + + default: + WMT_WARN_FUNC("WMT-PLAT:unsupported EIRQ(PIN_ID:%d) in eirq_ctrl, ret (%d)\n", id, iRet); + iRet = -1; + break; + } + + return iRet; +} + +INT32 wmt_plat_gpio_ctrl ( + ENUM_PIN_ID id, + ENUM_PIN_STATE state + ) +{ + if ( (PIN_ID_MAX > id) + && (PIN_STA_MAX > state) ) { + + // TODO: [FixMe][GeorgeKuo] do sanity check to const function table when init and skip checking here + if (gfp_set_pin_table[id]) { + return (*(gfp_set_pin_table[id]))(state); /* .handler */ + } + else { + WMT_WARN_FUNC("WMT-PLAT: null fp for gpio_ctrl(%d)\n", id); + return -2; + } + } + WMT_ERR_FUNC("WMT-PLAT:[out of range] id(%d), state (%d)\n", id, state); + return -1; +} + +INT32 +wmt_plat_ldo_ctrl ( + ENUM_PIN_STATE state + ) +{ + switch(state) + { + case PIN_STA_INIT: + /*set to gpio output low, disable pull*/ + WMT_DBG_FUNC("WMT-PLAT:LDO init (out 0) \n"); + break; + + case PIN_STA_OUT_H: + WMT_DBG_FUNC("WMT-PLAT:LDO (out 1) \n"); + break; + + case PIN_STA_OUT_L: + WMT_DBG_FUNC("WMT-PLAT:LDO (out 0) \n"); + break; + + case PIN_STA_IN_L: + case PIN_STA_DEINIT: + /*set to gpio input low, pull down enable*/ + WMT_DBG_FUNC("WMT-PLAT:LDO deinit (in pd) \n"); + break; + + default: + WMT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on LDO\n", state); + break; + } + return 0; +} + +INT32 +wmt_plat_pmu_ctrl ( + ENUM_PIN_STATE state + ) +{ + switch(state) + { + case PIN_STA_INIT: + /*set to gpio output low, disable pull*/ + WMT_DBG_FUNC("WMT-PLAT:PMU init (out 0) \n"); + break; + + case PIN_STA_OUT_H: + WMT_DBG_FUNC("WMT-PLAT:PMU (out 1) \n"); + break; + + case PIN_STA_OUT_L: + WMT_DBG_FUNC("WMT-PLAT:PMU (out 0) \n"); + break; + + case PIN_STA_IN_L: + case PIN_STA_DEINIT: + /*set to gpio input low, pull down enable*/ + WMT_DBG_FUNC("WMT-PLAT:PMU deinit (in pd) \n"); + break; + + default: + WMT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on PMU\n", state); + break; + } + + return 0; +} + +INT32 +wmt_plat_rtc_ctrl ( + ENUM_PIN_STATE state + ) +{ + switch(state) + { + case PIN_STA_INIT: + WMT_DBG_FUNC("WMT-PLAT:RTC init \n"); + break; + + default: + WMT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on RTC\n", state); + break; + } + return 0; +} + + +INT32 +wmt_plat_rst_ctrl ( + ENUM_PIN_STATE state + ) +{ + switch(state) + { + case PIN_STA_INIT: + /*set to gpio output low, disable pull*/ + WMT_DBG_FUNC("WMT-PLAT:RST init (out 0) \n"); + break; + + case PIN_STA_OUT_H: + WMT_DBG_FUNC("WMT-PLAT:RST (out 1) \n"); + break; + + case PIN_STA_OUT_L: + WMT_DBG_FUNC("WMT-PLAT:RST (out 0) \n"); + break; + + case PIN_STA_IN_L: + case PIN_STA_DEINIT: + /*set to gpio input low, pull down enable*/ + WMT_DBG_FUNC("WMT-PLAT:RST deinit (in pd) \n"); + break; + + default: + WMT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on RST\n", state); + break; + } + + return 0; +} + +INT32 +wmt_plat_bgf_eint_ctrl ( + ENUM_PIN_STATE state + ) +{ + switch(state) + { + case PIN_STA_INIT: + /*set to gpio input low, pull down eanble*/ + WMT_DBG_FUNC("WMT-PLAT:BGFInt init(in pd) \n"); + break; + + case PIN_STA_MUX: + /*set to gpio EINT mode, pull down enable*/ + WMT_DBG_FUNC("WMT-PLAT:BGFInt mux (eint) \n"); + break; + + case PIN_STA_IN_L: + case PIN_STA_DEINIT: + /*set to gpio input low, pull down enable*/ + WMT_DBG_FUNC("WMT-PLAT:BGFInt deinit(in pd) \n"); + break; + + default: + WMT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on BGF EINT\n", state); + break; + } + return 0; +} + + +INT32 wmt_plat_wifi_eint_ctrl(ENUM_PIN_STATE state) +{ +#if 0 + switch(state) + { + case PIN_STA_INIT: + break; + case PIN_STA_MUX: + + break; + case PIN_STA_EINT_EN: + break; + case PIN_STA_EINT_DIS: + break; + case PIN_STA_IN_L: + case PIN_STA_DEINIT: + /*set to gpio input low, pull down enable*/ + break; + default: + WMT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on WIFI EINT\n", state); + break; + } +#else + WMT_INFO_FUNC("WMT-PLAT:WIFI EINT is controlled by MSDC driver \n"); +#endif + return 0; +} + + +INT32 +wmt_plat_all_eint_ctrl ( + ENUM_PIN_STATE state + ) +{ + switch(state) + { + case PIN_STA_INIT: + /*set to gpio input low, pull down eanble*/ + WMT_DBG_FUNC("WMT-PLAT:ALLInt init(in pd) \n"); + break; + + case PIN_STA_MUX: + /*set to gpio EINT mode, pull down enable*/ + break; + + case PIN_STA_IN_L: + case PIN_STA_DEINIT: + /*set to gpio input low, pull down enable*/ + break; + + default: + WMT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on ALL EINT\n", state); + break; + } + return 0; +} + +INT32 wmt_plat_uart_ctrl(ENUM_PIN_STATE state) +{ + switch(state) + { + case PIN_STA_MUX: + case PIN_STA_INIT: + WMT_DBG_FUNC("WMT-PLAT:UART init (mode_01, uart) \n"); + break; + case PIN_STA_IN_L: + case PIN_STA_DEINIT: + WMT_DBG_FUNC("WMT-PLAT:UART deinit (out 0) \n"); + break; + + default: + WMT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on UART Group\n", state); + break; + } + + return 0; +} + + +INT32 wmt_plat_pcm_ctrl(ENUM_PIN_STATE state) +{ + switch(state) + { + case PIN_STA_MUX: + case PIN_STA_INIT: + /*set to PCM function*/ + WMT_DBG_FUNC("WMT-PLAT:PCM init (pcm) \n"); + break; + + case PIN_STA_IN_L: + case PIN_STA_DEINIT: + WMT_DBG_FUNC("WMT-PLAT:PCM deinit (out 0) \n"); + break; + + default: + WMT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on PCM Group\n", state); + break; + } + return 0; +} + + +INT32 wmt_plat_i2s_ctrl(ENUM_PIN_STATE state) +{ +#ifndef FM_ANALOG_INPUT + switch(state) + { + case PIN_STA_INIT: + case PIN_STA_MUX: + /*set to I2S function*/ + WMT_DBG_FUNC("WMT-PLAT:I2S init \n"); + break; + case PIN_STA_IN_L: + case PIN_STA_DEINIT: + /*set to gpio input low, pull down enable*/ + WMT_DBG_FUNC("WMT-PLAT:I2S deinit (out 0) \n"); + break; + default: + WMT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on I2S Group\n", state); + break; + } +#else + WMT_INFO_FUNC( "[MT6620]warnning:FM analog mode is set, no I2S GPIO settings should be modified by combo driver\n"); +#endif + + return 0; +} + +INT32 +wmt_plat_sdio_pin_ctrl ( + ENUM_PIN_STATE state + ) +{ + switch (state) { + case PIN_STA_INIT: + case PIN_STA_MUX: + break; + case PIN_STA_DEINIT: + break; + default: + WMT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on SDIO Group\n", state); + break; + } + return 0; +} + +static INT32 +wmt_plat_gps_sync_ctrl ( + ENUM_PIN_STATE state + ) +{ + switch (state) { + case PIN_STA_INIT: + case PIN_STA_DEINIT: + /*set GPS_SYNC GPIO to GPIO mode, pull disable,output low*/ + break; + + case PIN_STA_MUX: + /*set GPS_SYNC GPIO to GPS_SYNC function*/ + break; + + default: + break; + } + return 0; +} + + +static INT32 +wmt_plat_gps_lna_ctrl ( + ENUM_PIN_STATE state + ) +{ + switch (state) { + case PIN_STA_INIT: + case PIN_STA_DEINIT: + /*set GPS_LNA GPIO to GPIO mode, pull disable,output low*/ + break; + case PIN_STA_OUT_H: + /*set GPS_LNA GPIO to GPIO mode, pull disable,output high*/ + break; + case PIN_STA_OUT_L: + /*set GPS_LNA GPIO to GPIO mode, pull disable,output low*/ + break; + + default: + WMT_WARN_FUNC("%d mode not defined for gps lna pin !!!\n", state); + break; + } + return 0; + +} + + + +INT32 wmt_plat_wake_lock_ctrl(ENUM_WL_OP opId) +{ +#ifdef CFG_WMT_WAKELOCK_SUPPORT + static INT32 counter = 0; + + + osal_lock_sleepable_lock( &gOsSLock); + if (WL_OP_GET == opId) + { + ++counter; + }else if (WL_OP_PUT == opId) + { + --counter; + } + osal_unlock_sleepable_lock( &gOsSLock); + if (WL_OP_GET == opId && counter == 1) + { + wake_lock(&wmtWakeLock); + WMT_DBG_FUNC("WMT-PLAT: after wake_lock(%d), counter(%d)\n", wake_lock_active(&wmtWakeLock), counter); + + } + else if (WL_OP_PUT == opId && counter == 0) + { + wake_unlock(&wmtWakeLock); + WMT_DBG_FUNC("WMT-PLAT: after wake_unlock(%d), counter(%d)\n", wake_lock_active(&wmtWakeLock), counter); + } + else + { + WMT_WARN_FUNC("WMT-PLAT: wakelock status(%d), counter(%d)\n", wake_lock_active(&wmtWakeLock), counter); + } + return 0; +#else + WMT_WARN_FUNC("WMT-PLAT: host awake function is not supported."); + return 0; + +#endif +} + diff --git a/drivers/mtk_wcn_combo/drv_bt/Makefile b/drivers/mtk_wcn_combo/drv_bt/Makefile new file mode 100755 index 000000000000..9cd070acd71a --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_bt/Makefile @@ -0,0 +1,43 @@ +# Copyright Statement: +# +# This software/firmware and related documentation ("MediaTek Software") are +# protected under relevant copyright laws. The information contained herein +# is confidential and proprietary to MediaTek Inc. and/or its licensors. +# Without the prior written permission of MediaTek inc. and/or its licensors, +# any reproduction, modification, use or disclosure of MediaTek Software, +# and information contained herein, in whole or in part, shall be strictly prohibited. +# +# MediaTek Inc. (C) 2010. All rights reserved. +# +# BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES +# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") +# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON +# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. +# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE +# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR +# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH +# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES +# THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES +# CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK +# SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR +# STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND +# CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, +# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, +# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO +# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +# +# The following software/firmware and/or related documentation ("MediaTek Software") +# have been modified by MediaTek Inc. All revisions are subject to any receiver's +# applicable license agreements with MediaTek Inc. + + +# +# Makefile for the Linux Bluetooth HCI device drivers. +# +ccflags-y := -I$(src)/include -I$(src)/../common/include -I$(src)/../common/linux/include + +obj-$(CONFIG_MTK_COMBO_BT_HCI) += hci_stp.o +hci_stp-objs := linux/hci_stp.o + diff --git a/drivers/mtk_wcn_combo/drv_bt/include/hci_stp.h b/drivers/mtk_wcn_combo/drv_bt/include/hci_stp.h new file mode 100755 index 000000000000..adcd24d14fb3 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_bt/include/hci_stp.h @@ -0,0 +1,204 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +/* + * + * Bluetooth HCI UART driver + * + * Copyright (C) 2000-2001 Qualcomm Incorporated + * Copyright (C) 2002-2003 Maxim Krasnyansky + * Copyright (C) 2004-2005 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +#ifndef _HCI_STP_H +#define _HCI_STP_H + +#define HCI_STP_TX_TASKLET (0) /* do tx in a tasklet context */ +#define HCI_STP_TX_THRD (1) /* do tx in an init thread context */ + +/* select tx context */ +#define HCI_STP_TX (HCI_STP_TX_THRD) + +#if (HCI_STP_TX == HCI_STP_TX_TASKLET) +#define HCI_STP_TX_TASKLET_RWLOCK (0) /* use rwlock_t */ +#define HCI_STP_TX_TASKLET_SPINLOCK (1) /* use spinlock_t */ + +/* select txq protection method */ +#define HCI_STP_TX_TASKLET_LOCK (HCI_STP_TX_TASKLET_SPINLOCK) +#endif + +#define HCI_STP_DEV_INIT_OPEN_CTX (0) /* do init in hci_dev->open context, checked ok */ +#define HCI_STP_DEV_INIT_THRD (1) /* do init in another thread context */ + +/* select init context */ +#define HCI_STP_DEV_INIT (HCI_STP_DEV_INIT_THRD) + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* debugging */ +#include +#include + +/* constant of kernel version */ +#include + +/* kthread APIs */ +#include + +#include +#include + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/* HCI-STP flag bits */ +#define HCI_STP_PROTO_SET (0) +/* HCI-STP flag TX states bits */ +#define HCI_STP_SENDING (1) +#define HCI_STP_TX_WAKEUP (2) + +#if (HCI_STP_DEV_INIT == HCI_STP_DEV_INIT_THRD) +#define HCI_STP_INIT_TO_MSEC (5000) /* required time to finish init sequence */ +#endif + +/* maximum delay required */ +#define BT_CMD_DELAY_MS_COMM (50) +#define BT_CMD_DELAY_MS_RESET (500) +#define BT_CMD_DELAY_SAFE_GUARD (20) /*(2)*/ + +/* HCI-STP safer hci_reset handling */ +#define HCI_STP_SAFE_RESET (1) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +struct hci_stp_init_cmd { + unsigned char *hci_cmd; + unsigned int cmdSz; + unsigned char *hci_evt; + unsigned int evtSz; + char *str; +}; + +struct hci_stp { + struct hci_dev *hdev; + unsigned long flags; + + struct sk_buff_head txq; /* used to queue TX packets */ + unsigned long tx_state; + +#if (HCI_STP_DEV_INIT == HCI_STP_DEV_INIT_THRD) + struct work_struct init_work; + struct completion *p_init_comp; + wait_queue_head_t *p_init_evt_wq; + spinlock_t init_lock; /* protect init variables: comp and wq */ + unsigned int init_cmd_idx; + int init_evt_rx_flag; /* init result of last sent cmd */ +#endif + +#if HCI_STP_SAFE_RESET + wait_queue_head_t reset_wq; + atomic_t reset_count; /* !0: reset in progress */ +#endif + //void *priv; /* unused? */ + //struct sk_buff *tx_skb; /* unused? */ + //spinlock_t rx_lock; /* unused? */ +}; + +struct btradio_conf_data { + unsigned char addr[6]; + unsigned char voice[2]; + unsigned char codec[4]; + unsigned char radio[6]; + unsigned char sleep[7]; + unsigned char feature[2]; + unsigned char tx_pwr_offset[3]; +}; +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define hci_stp_init_entry(c) {.hci_cmd=c, .cmdSz=sizeof(c), .hci_evt=c##_evt, .evtSz=sizeof(c##_evt), .str=#c} + +#endif /* end of _HCI_STP_H */ + diff --git a/drivers/mtk_wcn_combo/drv_bt/linux/hci_stp.c b/drivers/mtk_wcn_combo/drv_bt/linux/hci_stp.c new file mode 100755 index 000000000000..84c5e10ffe4b --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_bt/linux/hci_stp.c @@ -0,0 +1,1708 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +/* + * + * Bluetooth HCI UART driver + * + * Copyright (C) 2000-2001 Qualcomm Incorporated + * Copyright (C) 2002-2003 Maxim Krasnyansky + * Copyright (C) 2004-2005 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +/* move compile flags to hci_stp.h file. */ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "hci_stp.h" +#include "stp_exp.h" +#include "wmt_exp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/* Debugging Purpose */ +#define PFX "[HCI-STP]" +#define BT_LOG_LOUD (4) +#define BT_LOG_DBG (3) +#define BT_LOG_INFO (2) +#define BT_LOG_WARN (1) +#define BT_LOG_ERR (0) + +#define VERSION "1.0" +#define CUSTOM_BT_CFG_FILE "/data/BT.cfg" +#define INTERNAL_BT_CFG_FILE "/data/bluetooth/BT.cfg" +#define BUILTIN_BT_CFG_FILE "/system/etc/firmware/BT.cfg" + +/* H4 receiver States */ +#define H4_W4_PACKET_TYPE (0) +#define H4_W4_EVENT_HDR (1) +#define H4_W4_ACL_HDR (2) +#define H4_W4_SCO_HDR (3) +#define H4_W4_DATA (4) + +#define HCI_STP_TXQ_IN_BLZ (0) +/* access txq in BlueZ tx tasklet context */ +#define HCI_STP_TXQ_IN_HCISTP (1) +/* access txq in HCI-STP context, defined by compile flag: HCI_STP_TX */ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +unsigned int gHciStpDbgLevel = BT_LOG_ERR;//Modify loglevel + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +/* Allow one BT driver */ +static struct hci_dev *hdev = NULL; +static int reset = 0; + +/* maybe struct hci_stp is a better place to put these data */ +#if (HCI_STP_TX == HCI_STP_TX_TASKLET) +static struct tasklet_struct hci_tx_tasklet; + +#if (HCI_STP_TX_TASKLET_LOCK == HCI_STP_TX_TASKLET_RWLOCK) +static DEFINE_RWLOCK(hci_stp_txqlock); + +#elif (HCI_STP_TX_TASKLET_LOCK == HCI_STP_TX_TASKLET_SPINLOCK) +static spinlock_t hci_stp_txqlock; + +#endif +#endif + +#if (HCI_STP_TX == HCI_STP_TX_THRD) +static spinlock_t hci_stp_txqlock; +struct task_struct * hci_stp_tx_thrd = NULL; +wait_queue_head_t hci_stp_tx_thrd_wq; +#endif + +/* oringinal code path: +system/bluetooth/bluedroid/bluetooth.c +external/bluetooth/bluez/tools/hciattach.c +mtk/src/custom/mt6516_evb/kernel/core/src/board.c // set power gpio configuration +*/ +static unsigned char bt_bd_addr[10] = + {0x01, 0x1a, 0xfc, 0x06, 0x01, 0x20, 0x66, 0x46, 0x00, 0x00}; +static unsigned char bt_bd_addr_evt[] = + {0x04, 0x0e, 0x04, 0x01, 0x1a, 0xfc, 0x00}; +static unsigned char bt_link_key_type[5]= + {0x01, 0x1b, 0xfc, 0x01, 0x01}; +static unsigned char bt_link_key_type_evt[] = + {0x04, 0x0e, 0x04, 0x01, 0x1b, 0xfc, 0x00}; +static unsigned char bt_unit_key[20] = + {0x01, 0x75, 0xfc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static unsigned char bt_unit_key_evt[] = + {0x04, 0x0e, 0x04, 0x01, 0x75, 0xfc, 0x00}; +static unsigned char bt_encrypt[7] = + {0x01, 0x76, 0xfc, 0x03, 0x00, 0x02, 0x10}; +static unsigned char bt_encrypt_evt[] = + {0x04, 0x0e, 0x04, 0x01, 0x76, 0xfc, 0x00}; +static unsigned char bt_pin_code_type[5] = + {0x01, 0x0a, 0x0c, 0x01, 0x00}; +static unsigned char bt_pin_code_type_evt[] = + {0x04, 0x0e, 0x04, 0x01, 0x0a, 0x0c, 0x00}; +static unsigned char bt_voice[6] = + {0x01, 0x26, 0x0c, 0x02, 0x60, 0x00}; +static unsigned char bt_voice_evt[] = + {0x04, 0x0e, 0x04, 0x01, 0x26, 0x0c, 0x00}; +static unsigned char bt_codec[8] = + {0x01, 0x72, 0xfc, 0x04, 0x23, 0x10, 0x00, 0x00}; +static unsigned char bt_codec_evt[] = + {0x04, 0x0e, 0x04, 0x01, 0x72, 0xfc, 0x00}; +static unsigned char bt_radio[10] = + {0x01, 0x79, 0xfc, 0x06, 0x06, 0x80, 0x00, 0x06, 0x03, 0x06}; +static unsigned char bt_radio_evt[] = + {0x04, 0x0e, 0x04, 0x01, 0x79, 0xfc, 0x00}; +static unsigned char bt_tx_pwr_offset[7] = + {0x01, 0x93, 0xfc, 0x03, 0xff, 0xff, 0xff}; +static unsigned char bt_tx_pwr_offset_evt[] = + {0x04, 0x0e, 0x04, 0x01, 0x93, 0xfc, 0x00}; +static unsigned char bt_sleep[11] = + {0x01, 0x7a, 0xfc, 0x07, 0x03, 0x40, 0x1f, 0x40, 0x1f, 0x00, 0x04}; +static unsigned char bt_sleep_evt[] = + {0x04, 0x0e, 0x04, 0x01, 0x7a, 0xfc, 0x00}; +static unsigned char bt_feature[6] = + {0x01, 0x7d, 0xfc, 0x02, 0x80, 0x0}; +static unsigned char bt_feature_evt[] = + {0x04, 0x0e, 0x04, 0x01, 0x7d, 0xfc, 0x00}; +static unsigned char bt_OSC[9] = + {0x01, 0x7b, 0xfc, 0x05, 0x01, 0x01, 0x14, 0x0a, 0x05}; +static unsigned char bt_OSC_evt[] = + {0x04, 0x0e, 0x04, 0x01, 0x7b, 0xfc, 0x00}; +static unsigned char bt_LPO[14] = + {0x01, 0x7c, 0xfc, 0x0a, 0x01, 0xfa, 0x0a, 0x02, 0x00, 0xa6, 0x0e, 0x00, 0x40, 0x00}; +static unsigned char bt_LPO_evt[] = + {0x04, 0x0e, 0x04, 0x01, 0x7c, 0xfc, 0x00}; +static unsigned char bt_legacy_PTA[14] = + {0x01, 0x74, 0xfc, 0x0a, 0xc9, 0x8b, 0xbf, 0x00, 0x00, 0x52, 0x0e, 0x0e, 0x1f, 0x1b}; +static unsigned char bt_legacy_PTA_evt[] = + {0x04, 0x0e, 0x04, 0x01, 0x74, 0xfc, 0x00}; +static unsigned char bt_BLE_PTA[9] = + {0x01, 0xfc, 0xfc, 0x05, 0x16, 0x0e, 0x0e, 0x00, 0x07}; +static unsigned char bt_BLE_PTA_evt[] = + {0x04, 0x0e, 0x04, 0x01, 0xfc, 0xfc, 0x00}; +static unsigned char bt_RF_desence[10] = + {0x01, 0x20, 0xfc, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; +static unsigned char bt_RF_desence_evt[] = + {0x04, 0x0e, 0x04, 0x01, 0x20, 0xfc, 0x00}; +static unsigned char bt_reset[4] = + {0x01, 0x03, 0x0c, 0x0}; +static unsigned char bt_reset_evt[] = + {0x04, 0x0e, 0x04, 0x01, 0x03, 0x0c, 0x00}; +static unsigned char bt_intern_PTA_1[19] = + {0x01, 0xfb, 0xfc, 0x0f, 0x00, 0x01, 0x0f, 0x0f, 0x01, 0x0f, 0x0f, 0x01, 0x0f, 0x0f, 0x01, 0x0f, 0x0f, 0x02, 0x01}; +static unsigned char bt_intern_PTA_1_evt[] = + {0x04, 0x0e, 0x04, 0x01, 0xfb, 0xfc, 0x00}; +static unsigned char bt_intern_PTA_2[11] = + {0x01, 0xfb, 0xfc, 0x07, 0x01, 0x19, 0x19, 0x07, 0xd0, 0x00, 0x01}; +static unsigned char bt_intern_PTA_2_evt[] = + {0x04, 0x0e, 0x04, 0x01, 0xfb, 0xfc, 0x00}; +static unsigned char bt_SLP_control_reg[12] = + {0x01, 0xd0, 0xfc, 0x08, 0x74, 0x00, 0x01, 0x81, 0xe2, 0x29, 0x0, 0x0}; +static unsigned char bt_SLP_control_reg_evt[] = + {0x04, 0x0e, 0x04, 0x01, 0xd0, 0xfc, 0x00}; +static unsigned char bt_SLP_LDOD_reg[12] = + {0x01, 0xd0, 0xfc, 0x08, 0x1c, 0x00, 0x02, 0x81, 0x79, 0x08, 0x0, 0x0}; +static unsigned char bt_SLP_LDOD_reg_evt[] = + {0x04, 0x0e, 0x04, 0x01, 0xd0, 0xfc, 0x00}; +static unsigned char bt_RF_reg[10] = + {0x01, 0xb0, 0xfc, 0x06, 0x64, 0x01, 0x02, 0x00, 0x00, 0x00}; +static unsigned char bt_RF_reg_evt[] = + {0x04, 0x0e, 0x04, 0x01, 0xb0, 0xfc, 0x00}; + +#if (HCI_STP_DEV_INIT == HCI_STP_DEV_INIT_THRD) +/* use this array to store received event content temporarily */ +static struct hci_stp_init_cmd init_table[] = +{ + /* do init in sequence, cmd and cmd##_evt array */ + hci_stp_init_entry(bt_bd_addr), + hci_stp_init_entry(bt_link_key_type), + hci_stp_init_entry(bt_unit_key), + hci_stp_init_entry(bt_encrypt), + hci_stp_init_entry(bt_pin_code_type), + hci_stp_init_entry(bt_voice), + hci_stp_init_entry(bt_codec), + hci_stp_init_entry(bt_radio), + hci_stp_init_entry(bt_tx_pwr_offset), + hci_stp_init_entry(bt_sleep), + hci_stp_init_entry(bt_feature), + hci_stp_init_entry(bt_OSC), + hci_stp_init_entry(bt_LPO), + hci_stp_init_entry(bt_legacy_PTA), + hci_stp_init_entry(bt_BLE_PTA), + hci_stp_init_entry(bt_RF_desence), + hci_stp_init_entry(bt_reset), + hci_stp_init_entry(bt_intern_PTA_1), + hci_stp_init_entry(bt_intern_PTA_2), + hci_stp_init_entry(bt_SLP_control_reg), + hci_stp_init_entry(bt_SLP_LDOD_reg), + hci_stp_init_entry(bt_RF_reg), +}; +#endif + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define BT_LOUD_FUNC(fmt, arg...) if(gHciStpDbgLevel >= BT_LOG_LOUD){ printk(PFX "[L]%s:" fmt, __FUNCTION__ ,##arg);} +#define BT_DBG_FUNC(fmt, arg...) if(gHciStpDbgLevel >= BT_LOG_DBG){ printk(PFX "[D]%s:" fmt, __FUNCTION__ ,##arg);} +#define BT_INFO_FUNC(fmt, arg...) if(gHciStpDbgLevel >= BT_LOG_INFO){ printk(PFX "[I]%s:" fmt, __FUNCTION__ ,##arg);} +#define BT_WARN_FUNC(fmt, arg...) if(gHciStpDbgLevel >= BT_LOG_WARN){ printk(PFX "[W]%s:" fmt, __FUNCTION__ ,##arg);} +#define BT_ERR_FUNC(fmt, arg...) if(gHciStpDbgLevel >= BT_LOG_ERR){ printk(PFX "[E]%s:" fmt, __FUNCTION__ ,##arg);} +#define BT_TRC_FUNC(f) if(gHciStpDbgLevel >= BT_LOG_LOUD){printk(PFX "[T]%s:%d\n", __FUNCTION__, __LINE__);} + +#if HCI_STP_SAFE_RESET +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) +/* HCI_RESET bit definition in linux/include/net/bluetooth/hci.h since 2.6.39: + http://lxr.free-electrons.com/source/include/net/bluetooth/hci.h?v=2.6.39;a=arm +*/ +#define BT_GET_HDEV_RST_FG(hdev) (test_bit(HCI_RESET, &hdev->flags)) +#else +#define BT_GET_HDEV_RST_FG(hdev) (0) /* no HCI_RESET bit available */ +#endif +#endif + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/* Functions to be implemted by all HCI_STP_TX_* methods */ +void hci_stp_tx_init (struct hci_stp *hu); +void hci_stp_tx_deinit (struct hci_stp *hu); +void hci_stp_txq_lock (unsigned int ctx); +void hci_stp_txq_unlock (unsigned int ctx); +void hci_stp_tx_kick (void); + +/* Functions to be implemented by all HCI_STP_INIT_* methods*/ +static int hci_stp_dev_init (struct hci_stp *phu); + +#if (HCI_STP_TX == HCI_STP_TX_TASKLET) +static int hci_stp_tx_wakeup (struct hci_stp *hu); +static void hci_stp_tx_tasklet_func (unsigned long data); +#endif + +#if (HCI_STP_TX == HCI_STP_TX_THRD) +static int hci_stp_tx_thrd_func (void *pdata); +#endif + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +static inline void hci_stp_tx_skb_comp (struct hci_stp *hu, struct sk_buff *skb) +{ + struct hci_dev *hdev; + int pkt_type; + + + hdev = hu->hdev; + hdev->stat.byte_tx += skb->len; + + pkt_type = bt_cb(skb)->pkt_type; + /* Update HCI stat counters */ + switch (pkt_type) { + case HCI_COMMAND_PKT: + hdev->stat.cmd_tx++; + break; + + case HCI_ACLDATA_PKT: + hdev->stat.acl_tx++; + break; + + case HCI_SCODATA_PKT: + hdev->stat.cmd_tx++; + break; + } +} + +#if (HCI_STP_TX == HCI_STP_TX_TASKLET) +void hci_stp_tx_init (struct hci_stp *hu) +{ + tasklet_init(&hci_tx_tasklet, hci_stp_tx_tasklet_func, (unsigned long)hu); + + #if (HCI_STP_TX_TASKLET_LOCK == HCI_STP_TX_TASKLET_RWLOCK) + rwlock_init(&hci_stp_txqlock); + #elif (HCI_STP_TX_TASKLET_LOCK == HCI_STP_TX_TASKLET_SPINLOCK) + spin_lock_init(&hci_stp_txqlock); + #endif +} + +void hci_stp_tx_deinit (struct hci_stp *hu) +{ + tasklet_kill(&hci_tx_tasklet); + + return; +} + +void hci_stp_txq_lock (unsigned int ctx) +{ + if (ctx == HCI_STP_TXQ_IN_BLZ) { + /* lock txq in BlueZ tx tasklet context */ + #if (HCI_STP_TX_TASKLET_LOCK == HCI_STP_TX_TASKLET_RWLOCK) + write_lock_bh(&hci_stp_txqlock); + #elif (HCI_STP_TX_TASKLET_LOCK == HCI_STP_TX_TASKLET_SPINLOCK) + spin_lock_bh(&hci_stp_txqlock); + #else + #error "HCI_STP_TX_TASKLET_LOCK" + #endif + } + else { + /* lock txq in HCI-STP context(defined by compile flag: HCI_STP_TX) */ + #if (HCI_STP_TX_TASKLET_LOCK == HCI_STP_TX_TASKLET_RWLOCK) + write_lock_bh(&hci_stp_txqlock); + #elif (HCI_STP_TX_TASKLET_LOCK == HCI_STP_TX_TASKLET_SPINLOCK) + spin_lock_bh(&hci_stp_txqlock); + #else + #error "HCI_STP_TX_TASKLET_LOCK" + #endif + } +} + +void hci_stp_txq_unlock (unsigned int ctx) +{ + if (ctx == HCI_STP_TXQ_IN_BLZ) { + /* lock txq in BlueZ tx tasklet context with hci_stp_tx */ + #if (HCI_STP_TX_TASKLET_LOCK == HCI_STP_TX_TASKLET_RWLOCK) + write_unlock_bh(&hci_stp_txqlock); + #elif (HCI_STP_TX_TASKLET_LOCK == HCI_STP_TX_TASKLET_SPINLOCK) + spin_unlock_bh(&hci_stp_txqlock); + #else + #error "HCI_STP_TX_TASKLET_LOCK" + #endif + } + else { + /* lock txq in HCI-STP context(defined by compile flag: HCI_STP_TX) */ + #if (HCI_STP_TX_TASKLET_LOCK == HCI_STP_TX_TASKLET_RWLOCK) + write_unlock_bh(&hci_stp_txqlock); + #elif (HCI_STP_TX_TASKLET_LOCK == HCI_STP_TX_TASKLET_SPINLOCK) + spin_unlock_bh(&hci_stp_txqlock); + #else + #error "HCI_STP_TX_TASKLET_LOCK" + #endif + } +} + +void hci_stp_tx_kick (void) +{ + tasklet_schedule(&hci_tx_tasklet); +} + +static void hci_stp_tx_tasklet_func(unsigned long data) { + + struct hci_stp *hu = (struct hci_stp *)data; + + /* sanity check to see if status is still correct? */ + if (unlikely(hdev == NULL)) { + BT_ERR_FUNC("Null hdev!\n"); + BUG_ON(hdev == NULL); + return; + } + + if (unlikely(hu != hdev->driver_data)) { + BT_ERR_FUNC("hu(0x%p) != hdev->driver_data(0x%p)\n", + hu, hdev->driver_data); + BUG_ON(hu != hdev->driver_data); + return; + } + + //read_lock(&hci_stp_txq_lock); + hci_stp_txq_lock(HCI_STP_TXQ_IN_HCISTP); + + hci_stp_tx_wakeup(hu); + + //read_unlock(&hci_stp_txq_lock); + hci_stp_txq_unlock(HCI_STP_TXQ_IN_HCISTP); +} + +/* George: HCI_STP_SENDING and HCI_STP_TX_WAKEUP flags in this function seem +* to be redundant. +*/ +static int hci_stp_tx_wakeup(struct hci_stp *hu) +{ +// struct hci_dev *hdev = hu->hdev; + struct sk_buff *skb; + int j = 0; + + BT_TRC_FUNC(); + + if (test_and_set_bit(HCI_STP_SENDING, &hu->tx_state)) { + set_bit(HCI_STP_TX_WAKEUP, &hu->tx_state); + printk("[BT] enqueue and return\n"); + return 0; + } + + BT_DBG_FUNC("hci_stp_tx_wakeup %d\n", __LINE__); + +restart: + clear_bit(HCI_STP_TX_WAKEUP, &hu->tx_state); + + while ((skb = skb_dequeue(&hu->txq))) { + int len; + BT_DBG_FUNC("dqueue times = %d\n", ++j); + + /* hci reset cmd check */ +#if HCI_STP_SAFE_RESET + if (unlikely(skb->len == ARRAY_SIZE(bt_reset))) { + if (unlikely(!memcmp(bt_reset, skb->data, ARRAY_SIZE(bt_reset)))) { + atomic_inc(&hu->reset_count); + BT_DBG_FUNC("hci reset cmd,f(%d),c(%d)\n", + BT_GET_HDEV_RST_FG(hdev), + atomic_read(&hu->reset_count)); + } + } +#endif + + if ((len = mtk_wcn_stp_send_data(skb->data, skb->len, BT_TASK_INDX)) == 0 ) { + /* can not send */ + BT_ERR_FUNC("mtk_wcn_stp_send_data can not send\n"); + BT_ERR_FUNC("Error %s %d\n", __FUNCTION__, __LINE__); + + skb_queue_head(&hu->txq, skb);//Put back to queue head + goto END; + } + + //hdev->stat.byte_tx += len; // moved into hci_stp_tx_skb_comp() + //hci_stp_tx_skb_comp(hu, bt_cb(skb)->pkt_type); + hci_stp_tx_skb_comp(hu, skb); + kfree_skb(skb); + } + +END: + if (test_bit(HCI_STP_TX_WAKEUP, &hu->tx_state)) + goto restart; + + clear_bit(HCI_STP_SENDING, &hu->tx_state); + + return 0; +} + + +#elif (HCI_STP_TX == HCI_STP_TX_THRD) + +void hci_stp_tx_init (struct hci_stp *hu) +{ + BT_DBG_FUNC("start:0x%p\n", hu); + + spin_lock_init(&hci_stp_txqlock); + init_waitqueue_head(&hci_stp_tx_thrd_wq); + + hci_stp_tx_thrd = kthread_create(hci_stp_tx_thrd_func, (void *)hu, "hci_stpd"); + if (NULL == hci_stp_tx_thrd) { + BT_ERR_FUNC("kthread_create hci_stpd fail!\n"); + } + wake_up_process(hci_stp_tx_thrd); + + BT_DBG_FUNC("done\n"); + return; +} + +void hci_stp_tx_deinit (struct hci_stp *hu) +{ + BT_DBG_FUNC("start:0x%p\n", hu); + + kthread_stop(hci_stp_tx_thrd); + hci_stp_tx_thrd = NULL; + + BT_DBG_FUNC("done\n"); + return; +} + +void hci_stp_txq_lock (unsigned int ctx) +{ + if (ctx == HCI_STP_TXQ_IN_BLZ) { + /* lock txq in BlueZ tx tasklet context */ + spin_lock(&hci_stp_txqlock); + } + else { + /* lock txq in HCI-STP context(defined by compile flag: HCI_STP_TX) */ + spin_lock_bh(&hci_stp_txqlock); + } +} + +void hci_stp_txq_unlock (unsigned int ctx) +{ + if (ctx == HCI_STP_TXQ_IN_BLZ) { + spin_unlock(&hci_stp_txqlock); + } + else { + /* lock txq in HCI-STP context(defined by compile flag: HCI_STP_TX) */ + spin_unlock_bh(&hci_stp_txqlock); + } +} + +static int +hci_stp_tx_thrd_func (void *pdata) +{ + struct hci_stp *hu; + struct hci_dev *hdev; + struct sk_buff *skb; + int len; + + hu = (struct hci_stp *)pdata; + hdev = hu->hdev; + + /* sanity check to see if status is still correct? */ + if (unlikely(hdev == NULL)) { + BT_ERR_FUNC("Null hdev!\n"); + BUG_ON(hdev == NULL); + return -1; + } + + if (unlikely(hu != hdev->driver_data)) { + BT_ERR_FUNC("hu(0x%p) != hdev->driver_data(0x%p)\n", + hu, hdev->driver_data); + BUG_ON(hu != hdev->driver_data); + return -1; + } + + smp_mb(); /* sync shared data */ + + for (;;) { + wait_event_interruptible(hci_stp_tx_thrd_wq, + (!skb_queue_empty(&hu->txq) || kthread_should_stop())); + + if (unlikely(kthread_should_stop())) { + BT_INFO_FUNC("hci_stpd thread should stop now... \n"); + break; + } + + hci_stp_txq_lock(HCI_STP_TXQ_IN_HCISTP); + while ((skb = skb_dequeue(&hu->txq))) { + /* protect txq only */ + hci_stp_txq_unlock(HCI_STP_TXQ_IN_HCISTP); + + /* hci reset cmd check */ + #if HCI_STP_SAFE_RESET + if (unlikely(skb->len == ARRAY_SIZE(bt_reset))) { + if (unlikely(!memcmp(bt_reset, skb->data, ARRAY_SIZE(bt_reset)))) { + atomic_inc(&hu->reset_count); + BT_DBG_FUNC("hci reset cmd,f(%d),c(%d)\n", + BT_GET_HDEV_RST_FG(hdev), + atomic_read(&hu->reset_count)); + } + } + #endif + + len = mtk_wcn_stp_send_data(skb->data, skb->len, BT_TASK_INDX); + if (unlikely(len != skb->len)) { + /* can not send */ + BT_ERR_FUNC("mtk_wcn_stp_send_data fail, enqueue again!(%d, %d)\n", + len, skb->len); + + hci_stp_txq_lock(HCI_STP_TXQ_IN_HCISTP); + skb_queue_head(&hu->txq, skb);//Put back to queue head + /* do hci_stp_txq_unlock outside while loop */ + break; + } + //hdev->stat.byte_tx += len; // moved into hci_stp_tx_skb_comp() + hci_stp_tx_skb_comp(hu, skb); + kfree_skb(skb); + + hci_stp_txq_lock(HCI_STP_TXQ_IN_HCISTP); + } + hci_stp_txq_unlock(HCI_STP_TXQ_IN_HCISTP); + + /* back to wait */ + } + + BT_INFO_FUNC("hci_stpd stop!\n"); + return 0; +} + +void hci_stp_tx_kick (void) +{ + wake_up_interruptible(&hci_stp_tx_thrd_wq); +} + +#else +#error "Not implemented HCI_STP_TX" +#endif + +#if (HCI_STP_DEV_INIT == HCI_STP_DEV_INIT_OPEN_CTX) +static int hci_stp_dev_init (struct hci_stp *phu) +{ + BT_INFO_FUNC("Reset bd_addr =>\n"); + mtk_wcn_stp_send_data(bt_bd_addr, 10, BT_TASK_INDX); + msleep(BT_CMD_DELAY_MS_COMM); + BT_INFO_FUNC("Reset bd_addr <=\n"); + + BT_INFO_FUNC("Reset bt_link_key_type =>\n"); + mtk_wcn_stp_send_data(bt_link_key_type, 5, BT_TASK_INDX); + msleep(BT_CMD_DELAY_MS_COMM); + BT_INFO_FUNC("Reset bt_link_key_type <=\n"); + + BT_INFO_FUNC("Reset bt_unit_key =>\n"); + mtk_wcn_stp_send_data(bt_unit_key, 20, BT_TASK_INDX); + msleep(BT_CMD_DELAY_MS_COMM); + BT_INFO_FUNC("Reset bt_unit_key <=\n"); + + BT_INFO_FUNC("Reset bt_encrypt =>\n"); + mtk_wcn_stp_send_data(bt_encrypt, 7, BT_TASK_INDX); + msleep(BT_CMD_DELAY_MS_COMM); + BT_INFO_FUNC("Reset bt_encrypt <=\n"); + + BT_INFO_FUNC("Reset bt_pin_code_type =>\n"); + mtk_wcn_stp_send_data(bt_pin_code_type, 5, BT_TASK_INDX); + msleep(BT_CMD_DELAY_MS_COMM); + BT_INFO_FUNC("Reset bt_pin_code_type <=\n"); + + BT_INFO_FUNC("Reset bt_voice =>\n"); + mtk_wcn_stp_send_data(bt_voice, 6, BT_TASK_INDX); + msleep(BT_CMD_DELAY_MS_COMM); + BT_INFO_FUNC("Reset bt_voice <=\n"); + + BT_INFO_FUNC("Reset bt_codec =>\n"); + mtk_wcn_stp_send_data(bt_codec, 8, BT_TASK_INDX); + msleep(BT_CMD_DELAY_MS_COMM); + BT_INFO_FUNC("Reset bt_codec <=\n"); + + BT_INFO_FUNC("Reset bt_radio =>\n"); + mtk_wcn_stp_send_data(bt_radio, 10, BT_TASK_INDX); + msleep(BT_CMD_DELAY_MS_COMM); + BT_INFO_FUNC("Reset bt_radio <=\n"); + + BT_INFO_FUNC("Reset bt_tx_pwr_offset =>\n"); + mtk_wcn_stp_send_data(bt_tx_pwr_offset, 7, BT_TASK_INDX); + msleep(BT_CMD_DELAY_MS_COMM); + BT_INFO_FUNC("Reset bt_tx_pwr_offset <=\n"); + + BT_INFO_FUNC("Reset bt_sleep =>\n"); + mtk_wcn_stp_send_data(bt_sleep, 11, BT_TASK_INDX); + msleep(BT_CMD_DELAY_MS_COMM); + BT_INFO_FUNC("Reset bt_sleep <=\n"); + + BT_INFO_FUNC("Reset bt_feature =>\n"); + mtk_wcn_stp_send_data(bt_feature, 6, BT_TASK_INDX); + msleep(BT_CMD_DELAY_MS_COMM); + BT_INFO_FUNC("Reset bt_feature <=\n"); + + BT_INFO_FUNC("Reset bt_OSC =>\n"); + mtk_wcn_stp_send_data(bt_OSC, 9, BT_TASK_INDX); + msleep(BT_CMD_DELAY_MS_COMM); + BT_INFO_FUNC("Reset bt_OSC <=\n"); + + BT_INFO_FUNC("Reset bt_LPO =>\n"); + mtk_wcn_stp_send_data(bt_LPO, 14, BT_TASK_INDX); + msleep(BT_CMD_DELAY_MS_COMM); + BT_INFO_FUNC("Reset bt_LPO <=\n"); + + BT_INFO_FUNC("Reset bt_legacy_PTA =>\n"); + mtk_wcn_stp_send_data(bt_legacy_PTA, 14, BT_TASK_INDX); + msleep(BT_CMD_DELAY_MS_COMM); + BT_INFO_FUNC("Reset bt_legacy_PTA <=\n"); + + BT_INFO_FUNC("Reset bt_BLE_PTA =>\n"); + mtk_wcn_stp_send_data(bt_BLE_PTA, 9, BT_TASK_INDX); + msleep(BT_CMD_DELAY_MS_COMM); + BT_INFO_FUNC("Reset bt_BLE_PTA <=\n"); + + BT_INFO_FUNC("Reset bt_RF_desence =>\n"); + mtk_wcn_stp_send_data(bt_RF_desence, 10, BT_TASK_INDX); + msleep(BT_CMD_DELAY_MS_COMM); + BT_INFO_FUNC("Reset bt_RF_desence <=\n"); + + BT_INFO_FUNC("Reset bt_reset =>\n"); + mtk_wcn_stp_send_data(bt_reset, 4, BT_TASK_INDX); + msleep(BT_CMD_DELAY_MS_RESET); + BT_INFO_FUNC("Reset bt_reset <=\n"); + + BT_INFO_FUNC("Reset bt_intern_PTA_1 =>\n"); + mtk_wcn_stp_send_data(bt_intern_PTA_1, 19, BT_TASK_INDX); + msleep(BT_CMD_DELAY_MS_COMM); + BT_INFO_FUNC("Reset bt_intern_PTA_1 <=\n"); + + BT_INFO_FUNC("Reset bt_intern_PTA_2 =>\n"); + mtk_wcn_stp_send_data(bt_intern_PTA_2, 11, BT_TASK_INDX); + msleep(BT_CMD_DELAY_MS_COMM); + BT_INFO_FUNC("Reset bt_intern_PTA_2 <=\n"); + + BT_INFO_FUNC("Reset bt_SLP_control_reg =>\n"); + mtk_wcn_stp_send_data(bt_SLP_control_reg, 12, BT_TASK_INDX); + msleep(BT_CMD_DELAY_MS_COMM); + BT_INFO_FUNC("Reset bt_SLP_control_reg <=\n"); + + BT_INFO_FUNC("Reset bt_SLP_LDOD_reg =>\n"); + mtk_wcn_stp_send_data(bt_SLP_LDOD_reg, 12, BT_TASK_INDX); + msleep(BT_CMD_DELAY_MS_COMM); + BT_INFO_FUNC("Reset bt_SLP_LDOD_reg <=\n"); + + BT_INFO_FUNC("Reset bt_RF_reg =>\n"); + mtk_wcn_stp_send_data(bt_RF_reg, 10, BT_TASK_INDX); + msleep(BT_CMD_DELAY_MS_COMM); + BT_INFO_FUNC("Reset bt_RF_reg <=\n"); + + return 0; +} + +#elif (HCI_STP_DEV_INIT == HCI_STP_DEV_INIT_THRD) + +void hci_stp_dev_init_rx_cb (const UINT8 *data, INT32 count) +{ + struct hci_stp *hu; + unsigned int idx; + + if (unlikely(!hdev)) { + BT_ERR_FUNC("null hdev!\n"); + return; + } + if (unlikely(!hdev->driver_data)) { + BT_ERR_FUNC("null hdev->driver_data!\n"); + return; + } + + /* get hci_stp from global variable */ + hu = (struct hci_stp *)hdev->driver_data; + idx = hu->init_cmd_idx; + + if (unlikely(count != init_table[idx].evtSz)) { + hu->init_evt_rx_flag = -1; /* size mismatch */ + } + else if (unlikely(memcmp(data, init_table[idx].hci_evt, count))) { + hu->init_evt_rx_flag = -2; /* content mismatch */ + } + else { + hu->init_evt_rx_flag = 1; /* ok */ + BT_DBG_FUNC("EVT i(%d),rx(%d) ok\n", idx, count); + } + + if (unlikely(1 != hu->init_evt_rx_flag)) { + int i; + BT_WARN_FUNC("EVT i(%d),rx(%d)buf:[", idx, count); + for (i = 0; i < count; ++i) { + printk("0x%02x ", data[i]); + } + printk("]\n"); + BT_WARN_FUNC("EVT i(%d),exp(%d)buf:[", idx, init_table[idx].evtSz); + for (i = 0; i < count; ++i) { + printk("0x%02x ", init_table[idx].hci_evt[i]); + } + printk("]\n"); + + } + + smp_mb(); /* sync shared data */ + wake_up(hu->p_init_evt_wq); /* wake up dev_init_work */ +} + +static void hci_stp_dev_init_work (struct work_struct *work) +{ + struct hci_stp *phu; + unsigned int idx; + long ret; + long to; + + BT_DBG_FUNC("++\n"); + + /* get client's information */ + phu = container_of(work, struct hci_stp, init_work); + + for (idx = 0; idx < ARRAY_SIZE(init_table); ++idx) { + phu->init_cmd_idx = idx; + phu->init_evt_rx_flag = 0; + to = (init_table[idx].hci_cmd == bt_reset) ? BT_CMD_DELAY_MS_RESET : BT_CMD_DELAY_MS_COMM; + /* safe waiting time in case running on a busy system */ + to = msecs_to_jiffies(to * BT_CMD_DELAY_SAFE_GUARD); + + BT_DBG_FUNC("CMD(%d),(%s),t/o(%ld))=>\n", idx, init_table[idx].str, to); + smp_wmb(); /* sync shared data */ + + /* Send hci command */ + mtk_wcn_stp_send_data(init_table[idx].hci_cmd, init_table[idx].cmdSz, BT_TASK_INDX); + /* Wait rx hci event */ + /* no need to lock init_lock here for wq, for that it will be freed + * only after we call complete(phu->p_init_comp); in this function. + */ + ret = wait_event_timeout((*phu->p_init_evt_wq), phu->init_evt_rx_flag != 0, to); + + /* Check result */ + if (likely(1 == phu->init_evt_rx_flag)) { + BT_DBG_FUNC("EVT(%d) ret(%u) ok<=\n", idx, jiffies_to_msecs(ret)); + /* process next cmd */ + continue; + } + else { + BT_WARN_FUNC("EVT(%d) ret(%u) to(%ld) fg(%d)<=\n", + idx, jiffies_to_msecs(ret), to, phu->init_evt_rx_flag); + /* stop processing and skip next cmd */ + break; + } + } + + if (phu->p_init_comp) { + complete(phu->p_init_comp); + } + + BT_DBG_FUNC("--\n"); +} + +static int hci_stp_dev_init (struct hci_stp *phu) +{ + DECLARE_COMPLETION_ONSTACK(hci_stp_dev_init_comp); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(hci_stp_dev_init_wq); + + spin_lock(&phu->init_lock); + phu->p_init_comp = &hci_stp_dev_init_comp; + phu->p_init_evt_wq = &hci_stp_dev_init_wq; + spin_unlock(&phu->init_lock); + + /* unregister rx event callback */ + mtk_wcn_stp_register_event_cb(BT_TASK_INDX, NULL); + /* register direct rx callback for init only */ + mtk_wcn_stp_register_if_rx(hci_stp_dev_init_rx_cb); + /* use bluez mode */ + mtk_wcn_stp_set_bluez(1); + + /* Schedule to call hci_stp_dev_init_work(). init_work is initialized in + * hci_stp_init(). + */ + schedule_work(&phu->init_work); + + //ret = wait_for_completion_interruptible_timeout(&hci_stp_dev_init_comp, msecs_to_jiffies(HCI_STP_INIT_TO_MSEC)); /* 3 seconds? */ + wait_for_completion(&hci_stp_dev_init_comp); + + spin_lock(&phu->init_lock); + /* clear references to stack variables */ + phu->p_init_comp = NULL; + phu->p_init_evt_wq = NULL; + spin_unlock(&phu->init_lock); + + /* check result */ + /* flag: (to be replaced by a constant value) + 1 rx event correctly, + 0 no response in time, + -1 unequal rx event length, + -2 unequal rx event content. + */ + if (likely(1 == phu->init_evt_rx_flag)) { + return 0; + } + else { + /* return non-zero value for error */ + return (phu->init_evt_rx_flag + 256); + } +} +#else +#error "Not implemented HCI_STP_DEV_INIT" +#endif + + +static ssize_t file_read(char *filename, char *buf, size_t len, loff_t *offset) +{ + struct file *fp; + mm_segment_t old_fs; + ssize_t retLen; + + fp = filp_open(filename, O_RDONLY, 0); + if (IS_ERR(fp)) { + BT_ERR_FUNC("Failed to open %s!\n", filename); + return -1; + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + if ((fp->f_op == NULL) || (fp->f_op->read == NULL)){ + BT_ERR_FUNC("File can not be read!\n"); + set_fs(old_fs); + filp_close(fp, NULL); + return -1; + } + + retLen = fp->f_op->read(fp, buf, len, offset); + + set_fs(old_fs); + filp_close(fp, NULL); + + return retLen; +} + +static ssize_t file_write(char *filename, char *buf, size_t len, loff_t *offset) +{ + struct file *fp; + mm_segment_t old_fs; + ssize_t retLen; + + fp = filp_open(filename, O_WRONLY | O_CREAT, 0644); + if (IS_ERR(fp)) { + BT_ERR_FUNC("Failed to open %s!\n", filename); + return -1; + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + if ((fp->f_op == NULL) || (fp->f_op->write == NULL)){ + BT_ERR_FUNC("File can not be write!\n"); + set_fs(old_fs); + filp_close(fp, NULL); + return -1; + } + + retLen = fp->f_op->write(fp, buf, len, offset); + + set_fs(old_fs); + filp_close(fp, NULL); + + return retLen; +} + +int load_custom_bt_conf(struct btradio_conf_data *cfg) +{ + /* + This method depends on customer's platform configuration data + store machenism. + Customer may use NVRAM, data file, or other patterns. + Here RECOMMEND and GIVE AN EXAMPLE to push configuration data + under /data/BT.cfg + */ + + struct btradio_conf_data temp; + loff_t pos = 0; + ssize_t retLen; + + retLen = file_read(CUSTOM_BT_CFG_FILE, + (char*)&temp, + sizeof(temp), + &pos); + + if (retLen < 0) + return -1; + + if(retLen < sizeof(temp)){ + BT_ERR_FUNC("File read length error %d\n", retLen); + return -1; + } + + memcpy(cfg, &temp, retLen); + + return 0; +} + +int load_internal_bt_conf(struct btradio_conf_data *cfg) +{ + struct btradio_conf_data temp; + loff_t pos = 0; + ssize_t retLen; + ssize_t written; + + // default BD_ADDR + unsigned char addr[6] = {0x00, 0x00, 0x46, 0x66, 0x20, 0x01}; + unsigned long randNum; + + retLen = file_read(INTERNAL_BT_CFG_FILE, + (char*)&temp, + sizeof(temp), + &pos); + + if (retLen < 0){ + BT_INFO_FUNC("No internal BT config file, generate from built-in BT config\n"); + + pos = 0; + retLen = file_read(BUILTIN_BT_CFG_FILE, + (char*)&temp, + sizeof(temp), + &pos); + if (retLen < 0){ + BT_ERR_FUNC("Try to read built-in BT config, error\n"); + return -1; + } + else if(retLen < sizeof(temp)){ + BT_ERR_FUNC("File read length error %d\n", retLen); + return -1; + } + + if (0 == memcmp(temp.addr, addr, 6)){ + BT_DBG_FUNC("Built-in config use default BD address, enable auto-gen mechanism!\n"); + get_random_bytes(&randNum, sizeof(unsigned long)); + BT_DBG_FUNC("Get random number: %lu\n", randNum); + + temp.addr[0] = (((randNum>>24 | randNum>>16) & (0xFE)) | (0x02)); + temp.addr[1] = ((randNum>>8) & 0xFF); + temp.addr[5] = (randNum & 0xFF); + + // Generate internal BT config file + pos = 0; + written = file_write(INTERNAL_BT_CFG_FILE, + (char*)&temp, + sizeof(temp), + &pos); + if (written < 0){ + BT_ERR_FUNC("Try to create internal BT config, error\n"); + } + else if(written < sizeof(temp)){ + BT_ERR_FUNC("File write length error %d\n", written); + } + else{ + BT_INFO_FUNC("Internal BT config generated\n"); + } + } + } + else if(retLen < sizeof(temp)){ + BT_ERR_FUNC("File read length error %d\n", retLen); + return -1; + } + + memcpy(cfg, &temp, retLen); + + return 0; +} + +/* Invoked when there is ONE received BT packet */ +void stp_tx_event_cb(void) +{ +#if 0 + struct hci_stp *hu; + if (unlikely(hdev == NULL)) { + BT_ERR_FUNC("Null hdev!\n"); + BUG_ON(hdev == NULL); + return; + } + hu = (struct hci_stp *) hdev->driver_data; +#endif + /* George: [FixMe] can we call hci_stp_tx_wakeup() directly in STP-CORE's + * context? It seems to be dangerous! Replace it with suitable one according + * to HCI_STP_TX compile flag. + */ + hci_stp_tx_kick(); /* George: adapt different tx_kick function */ +} + +/* + Direct delivery of bluez not changed hands through the stp buffer +*/ +void stp_rx_event_cb_directly(const UINT8 *data, INT32 count) +{ + register const UINT8 *ptr; + struct hci_event_hdr *eh; + struct hci_acl_hdr *ah; + struct hci_sco_hdr *sh; + register int len, type, dlen; + int while_count; /* = 0; Is while_count redundant? */ + //static unsigned long rx_count; /* Is it ok w/o an initial value??? */ + static unsigned int rx_count = 0; + //static unsigned long rx_state; /* Is it ok w/o an initial value??? */ + static unsigned int rx_state = H4_W4_PACKET_TYPE; + struct sk_buff *rx_skb = NULL; /* Is it ok to use non-static skb??? */ + register int room; +#if HCI_STP_SAFE_RESET + struct hci_stp *hu; +#endif + + BT_LOUD_FUNC("count(%d)rx_state(%d)rx_count(%d)\n", + count, rx_state, rx_count); + + if (data == NULL) { + BT_ERR_FUNC("Data is Null\n"); + return; + } + + if (count > 5000) { + BT_WARN_FUNC("abnormal count(%d)\n", count); + } + + ptr = data; + /*Add statistic*/ + hdev->stat.byte_rx += count; + +#if HCI_STP_SAFE_RESET + hu = (struct hci_stp *)hdev->driver_data; + /* is waiting hci reset event? */ + if (unlikely(atomic_read(&hu->reset_count))) { + if (count == ARRAY_SIZE(bt_reset_evt)) { + if (!memcmp(bt_reset_evt, data, ARRAY_SIZE(bt_reset_evt))) { + BT_DBG_FUNC("hci reset evt,f(%d),c(%d)\n", + BT_GET_HDEV_RST_FG(hdev), + atomic_read(&hu->reset_count)); + + atomic_dec(&hu->reset_count); + wake_up(&hu->reset_wq); + } + } + } +#endif + + while_count = 0; + while (count > 0) { /* while (count) */ + /* Is while_count redundant? */ + //while_count++; + if (++while_count > 5000) { + BT_WARN_FUNC("abnormal while_count(%d)\n", while_count); + } + + if (rx_count) { + len = min_t(unsigned int, rx_count, count); + memcpy(skb_put(rx_skb, len), ptr, len); + rx_count -= len; + count -= len; + ptr += len; + + if (rx_count) + continue; + /* rx_count==0, ready to indicate to hci_core */ + + switch (rx_state) { + case H4_W4_DATA: + BT_LOUD_FUNC("Complete data\n"); + hci_recv_frame(rx_skb); + rx_state = H4_W4_PACKET_TYPE; + rx_skb = NULL; + continue; + + case H4_W4_EVENT_HDR: + eh = hci_event_hdr(rx_skb); + //BT_DBG_FUNC("Event header:evt(0x%2.2x)plen(%d)\n", eh->evt, eh->plen); + room = skb_tailroom(rx_skb); + //BT_DBG_FUNC("len(%d)room(%d)\n", eh->plen, room); + BT_LOUD_FUNC("Event header:evt(0x%2.2x)plen(%d)room(%d)\n", + eh->evt, eh->plen, room); + + if (!eh->plen) { + hci_recv_frame(rx_skb); + rx_state = H4_W4_PACKET_TYPE; + rx_skb = NULL; + rx_count = 0; /* redundant? here rx_count is 0 already */ + } + else if (eh->plen > room) { + //BT_ERR("Data length is too large\n"); + BT_ERR_FUNC("too large data length:eh->plen(%d)>room(%d)\n", + eh->plen, room); + kfree_skb(rx_skb); + rx_state = H4_W4_PACKET_TYPE; + rx_skb = NULL; + rx_count = 0; /* redundant? here rx_count is 0 already */ + } + else { + rx_state = H4_W4_DATA; + rx_count = eh->plen; + } + continue; + + case H4_W4_ACL_HDR: + ah = hci_acl_hdr(rx_skb); + dlen = __le16_to_cpu(ah->dlen); + + room = skb_tailroom(rx_skb); + BT_LOUD_FUNC("ACL header:dlen(%d)room(%d)\n", dlen, room); + if (!dlen) { + hci_recv_frame(rx_skb); + rx_state = H4_W4_PACKET_TYPE; + rx_skb = NULL; + rx_count = 0; + } + else if (dlen > room) { + //BT_ERR_FUNC("Data length is too large\n"); + BT_ERR_FUNC("too large data length:dlen(%d)>room(%d)\n", + dlen, room); + kfree_skb(rx_skb); + rx_state = H4_W4_PACKET_TYPE; + rx_skb = NULL; + rx_count = 0; + } + else { + rx_state = H4_W4_DATA; + rx_count = dlen; + } + continue; + + case H4_W4_SCO_HDR: + sh = hci_sco_hdr(rx_skb); + room = skb_tailroom(rx_skb); + BT_LOUD_FUNC("SCO header:dlen(%d)room(%d)\n", sh->dlen, room); + + if (!sh->dlen) { + hci_recv_frame(rx_skb); + rx_state = H4_W4_PACKET_TYPE; + rx_skb = NULL; + rx_count = 0; + } + else if (sh->dlen > room) { + BT_ERR_FUNC("Data length is too large\n"); + BT_ERR_FUNC("too large data length:sh->dlen(%d)>room(%d)\n", + sh->dlen , room); + kfree_skb(rx_skb); + rx_state = H4_W4_PACKET_TYPE; + rx_skb = NULL; + rx_count = 0; + } + else { + rx_state = H4_W4_DATA; + rx_count = sh->dlen; + } + continue; + } + } + + /* H4_W4_PACKET_TYPE */ + switch (*ptr) { + case HCI_EVENT_PKT: + BT_LOUD_FUNC("Event packet\n"); + rx_state = H4_W4_EVENT_HDR; + rx_count = HCI_EVENT_HDR_SIZE; + type = HCI_EVENT_PKT; + break; + + case HCI_ACLDATA_PKT: + BT_LOUD_FUNC("ACL packet\n"); + rx_state = H4_W4_ACL_HDR; + rx_count = HCI_ACL_HDR_SIZE; + type = HCI_ACLDATA_PKT; + break; + + case HCI_SCODATA_PKT: + BT_LOUD_FUNC("SCO packet\n"); + rx_state = H4_W4_SCO_HDR; + rx_count = HCI_SCO_HDR_SIZE; + type = HCI_SCODATA_PKT; + break; + + default: + BT_ERR_FUNC("Unknown HCI packet type %2.2x\n", (__u8)*ptr); + ++(hdev->stat.err_rx); + ++ptr; + --count; + continue; + }; + + ++ptr; + --count; + + /* Allocate packet */ + rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); + if (!rx_skb) { + BT_ERR_FUNC("bt_skb_alloc(%d, GFP_ATOMIC) fail!\n", HCI_MAX_FRAME_SIZE); + rx_state = H4_W4_PACKET_TYPE; + rx_count = 0; + return; + } + + rx_skb->dev = (void *) hdev; + bt_cb(rx_skb)->pkt_type = type; + } + + return; +} + +/* ------- Interface to HCI layer ------ */ +/* Initialize device */ +static int hci_stp_open(struct hci_dev *hdev) +{ + struct hci_stp *hu; + struct btradio_conf_data cfg; + int ret; + + if (unlikely(!hdev)) { + BT_ERR_FUNC("null hdev\n"); + return -ENODEV; + } + + if (unlikely(!hdev->driver_data)) { + BT_ERR_FUNC("null hdev\n"); + return -ENODEV; + } + + hu = (struct hci_stp *)hdev->driver_data; + BT_INFO_FUNC("%s(0x%p)\n", hdev->name, hdev); + + /* clear txq and free all skb in it */ + hci_stp_txq_lock(HCI_STP_TXQ_IN_BLZ); + skb_queue_purge(&hu->txq); + hci_stp_txq_unlock(HCI_STP_TXQ_IN_BLZ); + + /* turn on BT */ + if (unlikely(MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_BT))) { + BT_WARN_FUNC("WMT turn on BT fail!\n"); + return -ENODEV; + } + + BT_INFO_FUNC("WMT turn on BT OK!\n"); + + if (likely(mtk_wcn_stp_is_ready())) { + + BT_LOUD_FUNC("STP is ready!\n"); + + memset(&cfg, 0, sizeof(struct btradio_conf_data)); + if (load_custom_bt_conf(&cfg) < 0){ + BT_INFO_FUNC("No custom BT config\n"); + + if (load_internal_bt_conf(&cfg) < 0){ + BT_ERR_FUNC("Load internal BT config failed!\n"); + goto init_start; + } + else{ + BT_INFO_FUNC("Load internal BT config success\n"); + } + } + else{ + BT_INFO_FUNC("Load custom BT config success\n"); + } +#if 1 /* refine output format */ + BT_DBG_FUNC("Read BT config data:\n"); + BT_DBG_FUNC("[BD addr %02x-%02x-%02x-%02x-%02x-%02x]\n", + cfg.addr[0], cfg.addr[1], cfg.addr[2], cfg.addr[3], cfg.addr[4], cfg.addr[5]); + BT_DBG_FUNC("[voice %02x %02x][codec %02x %02x %02x %02x]\n", + cfg.voice[0], cfg.voice[1], + cfg.codec[0], cfg.codec[1], cfg.codec[2], cfg.codec[3]); + BT_DBG_FUNC("[radio %02x %02x %02x %02x %02x %02x]\n", + cfg.radio[0], cfg.radio[1], cfg.radio[2], cfg.radio[3], cfg.radio[4], cfg.radio[5]); + BT_DBG_FUNC("[sleep %02x %02x %02x %02x %02x %02x %02x]\n", + cfg.sleep[0], cfg.sleep[1], cfg.sleep[2], cfg.sleep[3], cfg.sleep[4], cfg.sleep[5], cfg.sleep[6]); + BT_DBG_FUNC("[feature %02x %02x][tx power offset %02x %02x %02x]\n", + cfg.feature[0], cfg.feature[1], + cfg.tx_pwr_offset[0], cfg.tx_pwr_offset[1], cfg.tx_pwr_offset[2]); +#else + BT_DBG_FUNC("Read BT config data: [BD addr %02x-%02x-%02x-%02x-%02x-%02x][voice %02x %02x] \ + [codec %02x %02x %02x %02x][radio %02x %02x %02x %02x %02x %02x] \ + [sleep %02x %02x %02x %02x %02x %02x %02x][feature %02x %02x] \ + [tx power offset %02x %02x %02x]\n", + cfg.addr[0], cfg.addr[1], cfg.addr[2], cfg.addr[3], cfg.addr[4], cfg.addr[5], + cfg.voice[0], cfg.voice[1], cfg.codec[0], cfg.codec[1], cfg.codec[2], cfg.codec[3], + cfg.radio[0], cfg.radio[1], cfg.radio[2], cfg.radio[3], cfg.radio[4], cfg.radio[5], + cfg.sleep[0], cfg.sleep[1], cfg.sleep[2], cfg.sleep[3], cfg.sleep[4], cfg.sleep[5], cfg.sleep[6], + cfg.feature[0], cfg.feature[1], + cfg.tx_pwr_offset[0], cfg.tx_pwr_offset[1], cfg.tx_pwr_offset[2]); +#endif + bt_bd_addr[4] = cfg.addr[5]; + bt_bd_addr[5] = cfg.addr[4]; + bt_bd_addr[6] = cfg.addr[3]; + bt_bd_addr[7] = cfg.addr[2]; + bt_bd_addr[8] = cfg.addr[1]; + bt_bd_addr[9] = cfg.addr[0]; + memcpy(&bt_voice[4], cfg.voice, 2); + memcpy(&bt_codec[4], cfg.codec, 4); + memcpy(&bt_radio[4], cfg.radio, 6); + memcpy(&bt_tx_pwr_offset[4], cfg.tx_pwr_offset, 3); + memcpy(&bt_sleep[4], cfg.sleep, 7); + memcpy(&bt_feature[4], cfg.feature, 2); + +init_start: + + ret = hci_stp_dev_init(hu); + /* error handling: turn of BT */ + if (unlikely(ret)) { + BT_WARN_FUNC("hci_stp_dev_init fail(%d)!\n", ret); + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_off(WMTDRV_TYPE_BT)) { + BT_WARN_FUNC("WMT turn off BT fail!\n"); + } + else { + BT_INFO_FUNC("WMT turn off BT ok!\n"); + } + return -ENODEV; + } + + BT_INFO_FUNC("hci_stp_dev_init ok\n"); + + set_bit(HCI_RUNNING, &hdev->flags); + + /*registered tx/rx path*/ + mtk_wcn_stp_register_if_rx(stp_rx_event_cb_directly); + + mtk_wcn_stp_register_event_cb(BT_TASK_INDX, NULL); + mtk_wcn_stp_register_tx_event_cb(BT_TASK_INDX, stp_tx_event_cb); + + /*use bluez*/ + mtk_wcn_stp_set_bluez(1); + + return 0; + } + else { + BT_WARN_FUNC("STP is not ready!\n"); + return -ENODEV; + } +} + +/* Reset device */ +static int hci_stp_flush(struct hci_dev *hdev) +{ + struct hci_stp *hu; + + BT_DBG_FUNC("start\n"); + if (!hdev || !hdev->driver_data) { + BT_WARN_FUNC("invalid hdev(0x%p) or drv data(0x%p)\n", + hdev, (hdev) ? hdev->driver_data : hdev); + return -EFAULT; + } + + hu = (struct hci_stp *)hdev->driver_data; + + /* clear txq and free all skb in it */ + hci_stp_txq_lock(HCI_STP_TXQ_IN_BLZ); + skb_queue_purge(&hu->txq); + hci_stp_txq_unlock(HCI_STP_TXQ_IN_BLZ); + + BT_INFO_FUNC("done\n"); + return 0; +} + +/* Close device */ +static int hci_stp_close(struct hci_dev *hdev) +{ +#if HCI_STP_SAFE_RESET + struct hci_stp *hu; + long ret; +#endif + + BT_INFO_FUNC("hdev(0x%p)\n", hdev); + + if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) { + return 0; + } + + hci_stp_flush(hdev); + hdev->flush = NULL; + +#if HCI_STP_SAFE_RESET + hu = (struct hci_stp *)hdev->driver_data; + if (hu) { + /* double waiting time in case of busy system */ + ret = wait_event_timeout((hu->reset_wq), + (atomic_read(&hu->reset_count) == 0), + msecs_to_jiffies(BT_CMD_DELAY_MS_RESET*2)); + if ( (!ret) || (atomic_read(&hu->reset_count) != 0) ) { + BT_WARN_FUNC("wait on-going reset finish fail,f(%d),c(%d),ret(%u)\n", + BT_GET_HDEV_RST_FG(hdev), + atomic_read(&hu->reset_count), + jiffies_to_msecs(ret)); + } + else { + BT_DBG_FUNC("check reset log,f(%d),c(%d),ret(%u)\n", + BT_GET_HDEV_RST_FG(hdev), + atomic_read(&hu->reset_count), + jiffies_to_msecs(ret)); + } + } +#endif + + /* clear txq and free all skb in it */ + hci_stp_txq_lock(HCI_STP_TXQ_IN_BLZ); + skb_queue_purge(&hu->txq); + hci_stp_txq_unlock(HCI_STP_TXQ_IN_BLZ); + + /*unregistered tx/rx path*/ + mtk_wcn_stp_register_if_rx(NULL); + + mtk_wcn_stp_register_event_cb(BT_TASK_INDX, NULL); + mtk_wcn_stp_register_tx_event_cb(BT_TASK_INDX, NULL); + + /*not use bluez*/ + mtk_wcn_stp_set_bluez(0); + + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_off(WMTDRV_TYPE_BT)) { + BT_WARN_FUNC("WMT turn off BT fail!\n"); + } + else { + BT_INFO_FUNC("WMT turn off BT OK!\n"); + } + + return 0; +} + +/* Send frames from HCI layer */ +static int hci_stp_send_frame(struct sk_buff *skb) +{ + struct hci_dev* hdev = (struct hci_dev *) skb->dev; + struct hci_stp *hu; + + BT_TRC_FUNC(); + if (!hdev) { + BT_ERR_FUNC("Null hdev in skb\n"); + return -ENODEV; + } + + if (!test_bit(HCI_RUNNING, &hdev->flags)) { + BT_ERR_FUNC("no HCI_RUNNING in hdev->flags(0x%lx)\n", hdev->flags); + return -EBUSY; + } + + hu = (struct hci_stp *) hdev->driver_data; + + BT_LOUD_FUNC("%s:type(%d)len(%d)\n", + hdev->name, bt_cb(skb)->pkt_type, skb->len); + +#if 0 /* just timestamp?? */ + if (gHciStpDbgLevel >= BT_LOG_DBG) + { + struct timeval now; + do_gettimeofday(&now); + printk("%s: sec = %ld, --> usec --> %ld\n", + __FUNCTION__, now.tv_sec, now.tv_usec); + } +#endif + + /* Prepend skb with frame type. Is it safe to do skb_push? */ + memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); + + /* George: is no lock ok?? Add hci_stp_txq_lock and unlock! */ + hci_stp_txq_lock(HCI_STP_TXQ_IN_BLZ); + /*Queue a buffer at the end of a list. This function takes no locks + * and you must therefore hold required locks before calling it. + */ + skb_queue_tail(&hu->txq, skb); + hci_stp_txq_unlock(HCI_STP_TXQ_IN_BLZ); + + /* George: adapt different tx_kick function */ + hci_stp_tx_kick(); + + return 0; +} + +static void hci_stp_destruct(struct hci_dev *hdev) +{ + BT_INFO_FUNC("start hdev(0x%p)\n", hdev); + if (!hdev) { + return; + } + + BT_DBG_FUNC("%s\n", hdev->name); + hci_stp_tx_deinit((struct hci_stp *)hdev->driver_data); + kfree(hdev->driver_data); + + BT_DBG_FUNC("done\n"); +} + +static int __init hci_stp_init(void) +{ + struct hci_stp *hu = NULL; + + BT_DBG_FUNC("HCI STP driver ver %s\n", VERSION); + + if (!(hu = kzalloc(sizeof(struct hci_stp), /*GFP_KERNEL*/GFP_ATOMIC))) { + BT_ERR_FUNC("Can't allocate control structure\n"); + return -ENOMEM; + } + + BT_DBG_FUNC("hu 0x%08x\n", (int)hu); + + /* + used to stored pending skb + */ + skb_queue_head_init(&hu->txq); + + /* + Initialize and register HCI device + */ + hdev = hci_alloc_dev(); + if (!hdev) { + if (hu){ + kfree(hu); + hu = NULL; + } + + BT_ERR_FUNC("Can't allocate HCI device\n"); + return -ENOMEM; + } + + hu->hdev = hdev; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34)) + hdev->type = HCI_UART; +#else + hdev->bus = HCI_UART; + hdev->dev_type = HCI_BREDR; +#endif + hdev->driver_data = hu; + + BT_DBG_FUNC("hdev->driver_data 0x%08x\n", (int)hdev->driver_data); + hdev->open = hci_stp_open; + hdev->close = hci_stp_close; + hdev->flush = hci_stp_flush; + hdev->send = hci_stp_send_frame; + hdev->destruct = hci_stp_destruct; + + hdev->owner = THIS_MODULE; + + BT_DBG_FUNC("HCI_QUIRK_NO_RESET\n"); + + set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); + + if (hci_register_dev(hdev) < 0) { + BT_ERR_FUNC("Can't register HCI device\n"); + kfree(hu); + hu = NULL; + hci_free_dev(hdev); + hdev = NULL; + return -ENODEV; + } + +#if HCI_STP_SAFE_RESET + atomic_set(&hu->reset_count, 0); + init_waitqueue_head(&hu->reset_wq); +#endif + + /* George: adapt different tx_init function */ + hci_stp_tx_init(hu); + +#if (HCI_STP_DEV_INIT == HCI_STP_DEV_INIT_THRD) + /* init_work in heap */ + INIT_WORK(&hu->init_work, hci_stp_dev_init_work); + spin_lock_init(&hu->init_lock); +#endif + + mtk_wcn_stp_register_if_rx(NULL); + mtk_wcn_stp_register_event_cb(BT_TASK_INDX, NULL); + mtk_wcn_stp_register_tx_event_cb(BT_TASK_INDX, NULL); + + BT_INFO_FUNC("HCI-STP Drv(%s),dev(0x%p),data(0x%p) init done\n", VERSION, hdev, hdev->driver_data); + return 0; +} + +static void __exit hci_stp_exit(void) +{ + struct hci_stp *hu = (struct hci_stp *)hdev->driver_data; + BT_TRC_FUNC(); + + mtk_wcn_stp_register_event_cb(BT_TASK_INDX, NULL); + mtk_wcn_stp_register_tx_event_cb(BT_TASK_INDX, NULL); + + hci_unregister_dev(hdev); + + /* George: adapt different tx_deinit function */ + //tasklet_kill(&hci_tx_tasklet); + + skb_queue_purge(&hu->txq); + + /* hci_stp_destruct does this */ + /*kfree(hdev->driver_data);*/ + hci_free_dev(hdev); + + hdev = NULL; + BT_INFO_FUNC("done\n"); +} + +module_init(hci_stp_init); +module_exit(hci_stp_exit); + +module_param(reset, bool, 0644); +MODULE_PARM_DESC(reset, "Send HCI reset command on initialization"); + +MODULE_AUTHOR("Mediatek Inc."); +MODULE_DESCRIPTION("Bluetooth HCI STP driver ver " VERSION); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL"); + + diff --git a/drivers/mtk_wcn_combo/drv_fm/Makefile b/drivers/mtk_wcn_combo/drv_fm/Makefile new file mode 100755 index 000000000000..8ba480620967 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_fm/Makefile @@ -0,0 +1,47 @@ +# Copyright Statement: +# +# This software/firmware and related documentation ("MediaTek Software") are +# protected under relevant copyright laws. The information contained herein +# is confidential and proprietary to MediaTek Inc. and/or its licensors. +# Without the prior written permission of MediaTek inc. and/or its licensors, +# any reproduction, modification, use or disclosure of MediaTek Software, +# and information contained herein, in whole or in part, shall be strictly prohibited. +# +# MediaTek Inc. (C) 2010. All rights reserved. +# +# BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES +# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") +# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON +# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. +# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE +# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR +# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH +# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES +# THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES +# CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK +# SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR +# STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND +# CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, +# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, +# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO +# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +# +# The following software/firmware and/or related documentation ("MediaTek Software") +# have been modified by MediaTek Inc. All revisions are subject to any receiver's +# applicable license agreements with MediaTek Inc. + + +# Makefile generated by Mediatek +# fm support +MTK_FM_SUPPORT = yes +CUSTOM_KERNEL_FM = mt6620 +ifeq ($(MTK_FM_SUPPORT), yes) +ifeq ($(CUSTOM_KERNEL_FM), mt6620) + +obj-$(CONFIG_MTK_COMBO_FM) += private/ +obj-$(CONFIG_MTK_COMBO_FM) += public/ + +endif +endif \ No newline at end of file diff --git a/drivers/mtk_wcn_combo/drv_fm/include/fm.h b/drivers/mtk_wcn_combo/drv_fm/include/fm.h new file mode 100755 index 000000000000..fbabe94e88f5 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_fm/include/fm.h @@ -0,0 +1,520 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + */ +/* MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +/* alps/ALPS_SW/TRUNK/MAIN/alps/kernel/arch/arm/mach-mt6516/include/mach/fm.h + * + * (C) Copyright 2009 + * MediaTek + * William Chung + * + * MT6516 AR10x0 FM Radio Driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __FM_H__ +#define __FM_H__ + +//#define FMDEBUG + +#include +#include + +//scan sort ways +enum{ + FM_SCAN_SORT_NON = 0, + FM_SCAN_SORT_UP, + FM_SCAN_SORT_DOWN, + FM_SCAN_SORT_MAX +}; + +//***************************************************************************************** +//***********************************FM config for customer *********************************** +//***************************************************************************************** +//RX +#define FMR_RSSI_TH_LONG 0x0301 //FM radio long antenna RSSI threshold(11.375dBuV) +#define FMR_RSSI_TH_SHORT 0x02E0 //FM radio short antenna RSSI threshold(-1dBuV) +#define FMR_CQI_TH 0x00E9 //FM radio Channel quality indicator threshold(0x0000~0x00FF) +#define FMR_SEEK_SPACE 1 //FM radio seek space,1:100KHZ; 2:200KHZ +#define FMR_SCAN_CH_SIZE 40 //FM radio scan max channel size +#define FMR_BAND 1 //FM radio band, 1:87.5MHz~108.0MHz; 2:76.0MHz~90.0MHz; 3:76.0MHz~108.0MHz; 4:special +#define FMR_BAND_FREQ_L 875 //FM radio special band low freq(Default 87.5MHz) +#define FMR_BAND_FREQ_H 1080 //FM radio special band high freq(Default 108.0MHz) +#define FM_SCAN_SORT_SELECT FM_SCAN_SORT_DOWN + +//TX +#define FMTX_PWR_LEVEL_MAX 120 //FM transmitter power level, rang: 85db~120db, default 120db + +//***************************************************************************************** +//***********************************FM config for engineer *********************************** +//***************************************************************************************** +//RX +#define FMR_MR_TH 0x01BD //FM radio MR threshold +#define ADDR_SCAN_TH 0xE0 //scan thrshold register +#define ADDR_CQI_TH 0xE1 //scan CQI register + +//TX +#define FMTX_SCAN_HOLE_LOW 923 //92.3MHz~95.4MHz should not show to user +#define FMTX_SCAN_HOLE_HIGH 954 //92.3MHz~95.4MHz should not show to user +//***************************************************************************************** + +#define FM_NAME "fm" +#define FM_DEVICE_NAME "/dev/fm" + +// errno +#define FM_SUCCESS 0 +#define FM_FAILED 1 +#define FM_EPARM 2 +#define FM_BADSTATUS 3 +#define FM_TUNE_FAILED 4 +#define FM_SEEK_FAILED 5 +#define FM_BUSY 6 +#define FM_SCAN_FAILED 7 + +// band + +#define FM_BAND_UNKNOWN 0 +#define FM_BAND_UE 1 // US/Europe band 87.5MHz ~ 108MHz (DEFAULT) +#define FM_BAND_JAPAN 2 // Japan band 76MHz ~ 90MHz +#define FM_BAND_JAPANW 3 // Japan wideband 76MHZ ~ 108MHz +#define FM_BAND_SPECIAL 4 // special band between 76MHZ and 108MHz +#define FM_BAND_DEFAULT FM_BAND_UE +#define FM_FREQ_MIN FMR_BAND_FREQ_L +#define FM_FREQ_MAX FMR_BAND_FREQ_H +#define FM_RAIDO_BAND FM_BAND_UE +// space +#define FM_SPACE_UNKNOWN 0 +#define FM_SPACE_100K 1 +#define FM_SPACE_200K 2 +#define FM_SPACE_DEFAULT FMR_SEEK_SPACE +#define FM_SEEK_SPACE FMR_SEEK_SPACE + +//max scan chl num +#define FM_MAX_CHL_SIZE FMR_SCAN_CH_SIZE +// auto HiLo +#define FM_AUTO_HILO_OFF 0 +#define FM_AUTO_HILO_ON 1 + +// seek direction +#define FM_SEEK_UP 0 +#define FM_SEEK_DOWN 1 + +#define FM_CHIP_AR1000 0x1000 +#define FM_CHIP_MT5192 0x91 +#define FM_CHIP_MT5193 0x92 +#define FM_CHIP_MT6616 0x6616 +#define FM_CHIP_MT6620 0x6620 +#define FM_CHIP_MT6626 0x6626 +#define FM_CHIP_MT6628 0x6628 +#define FM_CHIP_UNSUPPORTED 0xffff + +// seek threshold +#define FM_SEEKTH_LEVEL_DEFAULT 4 + +#define FM_IOC_MAGIC 0xf5 // FIXME: any conflict? + +struct fm_tune_parm { + uint8_t err; + uint8_t band; + uint8_t space; + uint8_t hilo; + uint16_t freq; // IN/OUT parameter +}; + +struct fm_seek_parm { + uint8_t err; + uint8_t band; + uint8_t space; + uint8_t hilo; + uint8_t seekdir; + uint8_t seekth; + uint16_t freq; // IN/OUT parameter +}; + +struct fm_scan_parm { + uint8_t err; + uint8_t band; + uint8_t space; + uint8_t hilo; + uint16_t freq; // OUT parameter + uint16_t ScanTBL[16]; //need no less than the chip + uint16_t ScanTBLSize; //IN/OUT parameter +}; + +struct fm_ch_rssi{ + uint16_t freq; + int rssi; +}; + +struct fm_rssi_req{ + uint16_t num; + uint16_t read_cnt; + struct fm_ch_rssi cr[16*16]; +}; + +struct fm_hw_info{ + int chip_id; //chip ID, eg. 6620 + int eco_ver; //chip ECO version, eg. E3 + int rom_ver; //FM DSP rom code version, eg. V2 + int patch_ver; //FM DSP patch version, eg. 1.11 + int reserve; +}; + +//For RDS feature +typedef struct +{ + uint8_t TP; + uint8_t TA; + uint8_t Music; + uint8_t Stereo; + uint8_t Artificial_Head; + uint8_t Compressed; + uint8_t Dynamic_PTY; + uint8_t Text_AB; + uint32_t flag_status; +}RDSFlag_Struct; + +typedef struct +{ + uint16_t Month; + uint16_t Day; + uint16_t Year; + uint16_t Hour; + uint16_t Minute; + uint8_t Local_Time_offset_signbit; + uint8_t Local_Time_offset_half_hour; +}CT_Struct; + +typedef struct +{ + int16_t AF_Num; + int16_t AF[2][25]; //100KHz + uint8_t Addr_Cnt; + uint8_t isMethod_A; + uint8_t isAFNum_Get; +}AF_Info; + +typedef struct +{ + uint8_t PS[3][8]; + uint8_t Addr_Cnt; +}PS_Info; + +typedef struct +{ + uint8_t TextData[4][64]; + uint8_t GetLength; + uint8_t isRTDisplay; + uint8_t TextLength; + uint8_t isTypeA; + uint8_t BufCnt; + uint16_t Addr_Cnt; +}RT_Info; + +struct rds_raw_data +{ + int dirty; //indicate if the data changed or not + int len; //the data len form chip + uint8_t data[146]; +}; + +struct rds_group_cnt +{ + unsigned long total; + unsigned long groupA[16]; //RDS groupA counter + unsigned long groupB[16]; //RDS groupB counter +}; + +enum rds_group_cnt_opcode +{ + RDS_GROUP_CNT_READ = 0, + RDS_GROUP_CNT_WRITE, + RDS_GROUP_CNT_RESET, + RDS_GROUP_CNT_MAX +}; + +struct rds_group_cnt_req +{ + int err; + enum rds_group_cnt_opcode op; + struct rds_group_cnt gc; +}; + +typedef struct +{ + CT_Struct CT; + RDSFlag_Struct RDSFlag; + uint16_t PI; + uint8_t Switch_TP; + uint8_t PTY; + AF_Info AF_Data; + AF_Info AFON_Data; + uint8_t Radio_Page_Code; + uint16_t Program_Item_Number_Code; + uint8_t Extend_Country_Code; + uint16_t Language_Code; + PS_Info PS_Data; + uint8_t PS_ON[8]; + RT_Info RT_Data; + //uint16_t Block_Backup[32][4]; + //uint16_t Group_Cnt[32]; + //uint8_t EINT_Flag; + //uint8_t RDS_Flag; + uint16_t event_status; //will use RDSFlag_Struct RDSFlag->flag_status to check which event, is that ok? +} RDSData_Struct; + + +//Need care the following definition. +//valid Rds Flag for notify +typedef enum { + RDS_FLAG_IS_TP = 0x0001, // Program is a traffic program + RDS_FLAG_IS_TA = 0x0002, // Program currently broadcasts a traffic ann. + RDS_FLAG_IS_MUSIC = 0x0004, // Program currently broadcasts music + RDS_FLAG_IS_STEREO = 0x0008, // Program is transmitted in stereo + RDS_FLAG_IS_ARTIFICIAL_HEAD = 0x0010, // Program is an artificial head recording + RDS_FLAG_IS_COMPRESSED = 0x0020, // Program content is compressed + RDS_FLAG_IS_DYNAMIC_PTY = 0x0040, // Program type can change + RDS_FLAG_TEXT_AB = 0x0080 // If this flag changes state, a new radio text string begins +} RdsFlag; + +typedef enum { + RDS_EVENT_FLAGS = 0x0001, // One of the RDS flags has changed state + RDS_EVENT_PI_CODE = 0x0002, // The program identification code has changed + RDS_EVENT_PTY_CODE = 0x0004, // The program type code has changed + RDS_EVENT_PROGRAMNAME = 0x0008, // The program name has changed + RDS_EVENT_UTCDATETIME = 0x0010, // A new UTC date/time is available + RDS_EVENT_LOCDATETIME = 0x0020, // A new local date/time is available + RDS_EVENT_LAST_RADIOTEXT = 0x0040, // A radio text string was completed + RDS_EVENT_AF = 0x0080, // Current Channel RF signal strength too weak, need do AF switch + RDS_EVENT_AF_LIST = 0x0100, // An alternative frequency list is ready + RDS_EVENT_AFON_LIST = 0x0200, // An alternative frequency list is ready + RDS_EVENT_TAON = 0x0400, // Other Network traffic announcement start + RDS_EVENT_TAON_OFF = 0x0800, // Other Network traffic announcement finished. + RDS_EVENT_RDS = 0x2000, // RDS Interrupt had arrived durint timer period + RDS_EVENT_NO_RDS = 0x4000, // RDS Interrupt not arrived durint timer period + RDS_EVENT_RDS_TIMER = 0x8000 // Timer for RDS Bler Check. ---- BLER block error rate +} RdsEvent; + +struct fm_rds_tx_parm { + uint8_t err; + uint16_t pi; + uint16_t ps[12]; // 4 ps + uint16_t other_rds[87]; // 0~29 other groups + uint8_t other_rds_cnt; // # of other group +}; + +typedef struct fm_rds_tx_req{ + unsigned char pty; // 0~31 integer + unsigned char rds_rbds; // 0:RDS, 1:RBDS + unsigned char dyn_pty; // 0:static, 1:dynamic + unsigned short pi_code; // 2-byte hex + unsigned char ps_buf[8]; // hex buf of PS + unsigned char ps_len; // length of PS, must be 0 / 8" + unsigned char af; // 0~204, 0:not used, 1~204:(87.5+0.1*af)MHz + unsigned char ah; // Artificial head, 0:no, 1:yes + unsigned char stereo; // 0:mono, 1:stereo + unsigned char compress; // Audio compress, 0:no, 1:yes + unsigned char tp; // traffic program, 0:no, 1:yes + unsigned char ta; // traffic announcement, 0:no, 1:yes + unsigned char speech; // 0:music, 1:speech +}fm_rds_tx_req; + +#define TX_SCAN_MAX 10 +#define TX_SCAN_MIN 1 +struct fm_tx_scan_parm { + uint8_t err; + uint8_t band; //87.6~108MHz + uint8_t space; + uint8_t hilo; + uint16_t freq; // start freq, if less than band min freq, then will use band min freq + uint8_t scandir; + uint16_t ScanTBL[TX_SCAN_MAX]; //need no less than the chip + uint16_t ScanTBLSize; //IN: desired size, OUT: scan result size +}; + +struct fm_gps_rtc_info{ + int err; //error number, 0: success, other: err code + int retryCnt; //GPS mnl can decide retry times + int ageThd; //GPS 3D fix time diff threshold + int driftThd; //GPS RTC drift threshold + struct timeval tvThd; //time value diff threshold + int age; //GPS 3D fix time diff + int drift; //GPS RTC drift + union{ + unsigned long stamp; //time stamp in jiffies + struct timeval tv; //time stamp value in RTC + }; + int flag; //rw flag +}; + +typedef enum +{ + FM_I2S_ON = 0, + FM_I2S_OFF +}fm_i2s_state; + +typedef enum +{ + FM_I2S_MASTER = 0, + FM_I2S_SLAVE +}fm_i2s_mode; + +typedef enum +{ + FM_I2S_32K = 0, + FM_I2S_44K, + FM_I2S_48K +}fm_i2s_sample; + +struct fm_i2s_setting{ + int onoff; + int mode; + int sample; +}; + +typedef enum{ + FM_RX = 0, + FM_TX = 1 +}FM_PWR_T; + +#define FM_IOCTL_POWERUP _IOWR(FM_IOC_MAGIC, 0, struct fm_tune_parm*) +#define FM_IOCTL_POWERDOWN _IOWR(FM_IOC_MAGIC, 1, int32_t*) +#define FM_IOCTL_TUNE _IOWR(FM_IOC_MAGIC, 2, struct fm_tune_parm*) +#define FM_IOCTL_SEEK _IOWR(FM_IOC_MAGIC, 3, struct fm_seek_parm*) +#define FM_IOCTL_SETVOL _IOWR(FM_IOC_MAGIC, 4, uint32_t*) +#define FM_IOCTL_GETVOL _IOWR(FM_IOC_MAGIC, 5, uint32_t*) +#define FM_IOCTL_MUTE _IOWR(FM_IOC_MAGIC, 6, uint32_t*) +#define FM_IOCTL_GETRSSI _IOWR(FM_IOC_MAGIC, 7, uint32_t*) +#define FM_IOCTL_SCAN _IOWR(FM_IOC_MAGIC, 8, struct fm_scan_parm*) +#define FM_IOCTL_STOP_SCAN _IO(FM_IOC_MAGIC, 9) +#define FM_IOCTL_POWERUP_TX _IOWR(FM_IOC_MAGIC, 20, struct fm_tune_parm*) +#define FM_IOCTL_TUNE_TX _IOWR(FM_IOC_MAGIC, 21, struct fm_tune_parm*) +#define FM_IOCTL_RDS_TX _IOWR(FM_IOC_MAGIC, 22, struct fm_rds_tx_parm*) + +//IOCTL and struct for test +#define FM_IOCTL_GETCHIPID _IOWR(FM_IOC_MAGIC, 10, uint16_t*) +#define FM_IOCTL_EM_TEST _IOWR(FM_IOC_MAGIC, 11, struct fm_em_parm*) +#define FM_IOCTL_RW_REG _IOWR(FM_IOC_MAGIC, 12, struct fm_ctl_parm*) +#define FM_IOCTL_GETMONOSTERO _IOWR(FM_IOC_MAGIC, 13, uint16_t*) +#define FM_IOCTL_GETCURPAMD _IOWR(FM_IOC_MAGIC, 14, uint16_t*) +#define FM_IOCTL_GETGOODBCNT _IOWR(FM_IOC_MAGIC, 15, uint16_t*) +#define FM_IOCTL_GETBADBNT _IOWR(FM_IOC_MAGIC, 16, uint16_t*) +#define FM_IOCTL_GETBLERRATIO _IOWR(FM_IOC_MAGIC, 17, uint16_t*) + + +//IOCTL for RDS +#define FM_IOCTL_RDS_ONOFF _IOWR(FM_IOC_MAGIC, 18, uint16_t*) +#define FM_IOCTL_RDS_SUPPORT _IOWR(FM_IOC_MAGIC, 19, int32_t*) + +#define FM_IOCTL_RDS_SIM_DATA _IOWR(FM_IOC_MAGIC, 23, uint32_t*) +#define FM_IOCTL_IS_FM_POWERED_UP _IOWR(FM_IOC_MAGIC, 24, uint32_t*) + +//IOCTL for FM Tx +#define FM_IOCTL_TX_SUPPORT _IOWR(FM_IOC_MAGIC, 25, int32_t*) +#define FM_IOCTL_RDSTX_SUPPORT _IOWR(FM_IOC_MAGIC, 26, int32_t*) +#define FM_IOCTL_RDSTX_ENABLE _IOWR(FM_IOC_MAGIC, 27, int32_t*) +#define FM_IOCTL_TX_SCAN _IOWR(FM_IOC_MAGIC, 28, struct fm_tx_scan_parm*) + +//IOCTL for FM over BT +#define FM_IOCTL_OVER_BT_ENABLE _IOWR(FM_IOC_MAGIC, 29, int32_t*) + +//IOCTL for FM ANTENNA SWITCH +#define FM_IOCTL_ANA_SWITCH _IOWR(FM_IOC_MAGIC, 30, int32_t*) +#define FM_IOCTL_GETCAPARRAY _IOWR(FM_IOC_MAGIC, 31, int32_t*) + +//IOCTL for FM compensation by GPS RTC +#define FM_IOCTL_GPS_RTC_DRIFT _IOWR(FM_IOC_MAGIC, 32, struct fm_gps_rtc_info*) + +//IOCTL for FM I2S Setting +#define FM_IOCTL_I2S_SETTING _IOWR(FM_IOC_MAGIC, 33, struct fm_i2s_setting*) + +#define FM_IOCTL_RDS_GROUPCNT _IOWR(FM_IOC_MAGIC, 34, struct rds_group_cnt_req*) +#define FM_IOCTL_RDS_GET_LOG _IOWR(FM_IOC_MAGIC, 35, struct rds_raw_data*) + +#define FM_IOCTL_SCAN_GETRSSI _IOWR(FM_IOC_MAGIC, 36, struct fm_rssi_req*) +#define FM_IOCTL_SETMONOSTERO _IOWR(FM_IOC_MAGIC, 37, int32_t) +#define FM_IOCTL_GET_HW_INFO _IOWR(FM_IOC_MAGIC, 38, struct fm_hw_info*) + +#define FM_IOCTL_DUMP_REG _IO(FM_IOC_MAGIC, 0xFF) + +enum group_idx { + mono=0, + stereo, + RSSI_threshold, + HCC_Enable, + PAMD_threshold, + Softmute_Enable, + De_emphasis, + HL_Side, + Demod_BW, + Dynamic_Limiter, + Softmute_Rate, + AFC_Enable, + Softmute_Level, + Analog_Volume, + GROUP_TOTAL_NUMS +}; + +enum item_idx { + Sblend_OFF=0, + Sblend_ON, + ITEM_TOTAL_NUMS +}; + +struct fm_ctl_parm { + uint8_t err; + uint8_t addr; + uint16_t val; + uint16_t rw_flag;//0:write, 1:read +}; + +struct fm_em_parm { + uint16_t group_idx; + uint16_t item_idx; + uint32_t item_value; +}; +#endif // __FM_H__ diff --git a/drivers/mtk_wcn_combo/drv_fm/private/Makefile b/drivers/mtk_wcn_combo/drv_fm/private/Makefile new file mode 100755 index 000000000000..0b5ee405053f --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_fm/private/Makefile @@ -0,0 +1,51 @@ +# Copyright Statement: +# +# This software/firmware and related documentation ("MediaTek Software") are +# protected under relevant copyright laws. The information contained herein +# is confidential and proprietary to MediaTek Inc. and/or its licensors. +# Without the prior written permission of MediaTek inc. and/or its licensors, +# any reproduction, modification, use or disclosure of MediaTek Software, +# and information contained herein, in whole or in part, shall be strictly prohibited. +# +# MediaTek Inc. (C) 2010. All rights reserved. +# +# BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES +# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") +# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON +# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. +# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE +# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR +# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH +# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES +# THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES +# CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK +# SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR +# STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND +# CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, +# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, +# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO +# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +# +# The following software/firmware and/or related documentation ("MediaTek Software") +# have been modified by MediaTek Inc. All revisions are subject to any receiver's +# applicable license agreements with MediaTek Inc. + + +# Makefile generated by Mediatek +# fm support +MTK_FM_SUPPORT=yes +CUSTOM_KERNEL_FM=mt6620 +ifeq ($(MTK_FM_SUPPORT), yes) +ifeq ($(CUSTOM_KERNEL_FM), mt6620) +ccflags-y := -I$(src)/../include -I$(src)/../../common/include -I$(src)/../../common/linux/include -I$(src)/../public/ +KERNEL_PATH := $(src) +OBJ_PATH := $(src) + +obj-$(CONFIG_MTK_COMBO_FM) += mtk_fm_priv.o +mtk_fm_priv-objs := mtk_fm.o +always := $(shell cp -f $(KERNEL_PATH)/mtk_fm.o.new $(OBJ_PATH)/mtk_fm.o) + +endif +endif diff --git a/drivers/mtk_wcn_combo/drv_fm/private/mtk_fm.h b/drivers/mtk_wcn_combo/drv_fm/private/mtk_fm.h new file mode 100755 index 000000000000..4e20119c5b27 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_fm/private/mtk_fm.h @@ -0,0 +1,116 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +#ifndef __MTK_FM_H__ +#define __MTK_FM_H__ + +#include + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +//#define HiSideTableSize 1 +#define FM_TX_PWR_CTRL_FREQ_THR 890 +#define FM_TX_PWR_CTRL_TMP_THR_UP 45 +#define FM_TX_PWR_CTRL_TMP_THR_DOWN 0 + +#define FM_TX_TRACKING_TIME_MAX 10000 //TX VCO tracking time, default 100ms + +enum fm_priv_state{ + UNINITED, + INITED +}; + +enum fm_adpll_state{ + FM_ADPLL_ON, + FM_ADPLL_OFF +}; + +enum fm_adpll_clk{ + FM_ADPLL_16M, + FM_ADPLL_15M +}; + +enum fm_mcu_desense{ + FM_MCU_DESENSE_ENABLE, + FM_MCU_DESENSE_DISABLE +}; + +struct fm_priv_cb { + //Basic functions. + int (*hl_side)(uint16_t freq, int *hl); + int (*adpll_freq_avoid)(uint16_t freq, int *freqavoid); + int (*mcu_freq_avoid)(uint16_t freq, int *freqavoid); + int (*tx_pwr_ctrl)(uint16_t freq, int *ctr); + int (*rtc_drift_ctrl)(uint16_t freq, int *ctr); + int (*tx_desense_wifi)(uint16_t freq, int *ctr); +}; + +struct fm_priv{ + int state; + void *data; + struct fm_priv_cb priv_tbl; +}; + +struct fm_op_cb { + //Basic functions. + int (*read)(uint8_t addr, uint16_t *val); + int (*write)(uint8_t addr, uint16_t val); + int (*setbits)(uint8_t addr, uint16_t bits, uint16_t mask); + int (*rampdown)(void); +}; + +struct fm_op{ + int state; + void *data; + struct fm_op_cb op_tbl; +}; + +#define FMR_ASSERT(a) { \ + if ((a) == NULL) { \ + printk("%s,invalid pointer\n", __func__);\ + return -ERR_INVALID_BUF; \ + } \ + } + +int fm_priv_register(struct fm_priv *pri, struct fm_op *op); +int fm_priv_unregister(struct fm_priv *pri, struct fm_op *op); + +#endif //__MTK_FM_H__ diff --git a/drivers/mtk_wcn_combo/drv_fm/public/Makefile b/drivers/mtk_wcn_combo/drv_fm/public/Makefile new file mode 100755 index 000000000000..9860d86feea7 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_fm/public/Makefile @@ -0,0 +1,47 @@ +# Copyright Statement: +# +# This software/firmware and related documentation ("MediaTek Software") are +# protected under relevant copyright laws. The information contained herein +# is confidential and proprietary to MediaTek Inc. and/or its licensors. +# Without the prior written permission of MediaTek inc. and/or its licensors, +# any reproduction, modification, use or disclosure of MediaTek Software, +# and information contained herein, in whole or in part, shall be strictly prohibited. +# +# MediaTek Inc. (C) 2010. All rights reserved. +# +# BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES +# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") +# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON +# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. +# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE +# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR +# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH +# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES +# THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES +# CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK +# SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR +# STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND +# CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, +# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, +# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO +# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +# +# The following software/firmware and/or related documentation ("MediaTek Software") +# have been modified by MediaTek Inc. All revisions are subject to any receiver's +# applicable license agreements with MediaTek Inc. + + +# Makefile generated by Mediatek +# fm support +MTK_FM_SUPPORT=yes +CUSTOM_KERNEL_FM=mt6620 +ifeq ($(MTK_FM_SUPPORT), yes) +ifeq ($(CUSTOM_KERNEL_FM), mt6620) +ccflags-y := -I$(src)/../include -I$(src)/../../common/include -I$(src)/../../common/linux/include + +obj-$(CONFIG_MTK_COMBO_FM) += mt6620_fm_drv.o +mt6620_fm_drv-objs := mt6620_fm.o mt6620_fm_lib.o mt6620_rds.o +endif +endif \ No newline at end of file diff --git a/drivers/mtk_wcn_combo/drv_fm/public/mt6620_fm.c b/drivers/mtk_wcn_combo/drv_fm/public/mt6620_fm.c new file mode 100755 index 000000000000..981b68fe001b --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_fm/public/mt6620_fm.c @@ -0,0 +1,5257 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +#include + +#ifdef FM_TASK_INFO_DEBUG +#include +#endif + +#include +#include + +#include +#include +#include +#include // udelay() +#include // device_create() +#include +#include +#include +#include +#include + +#include // get_user() + +#include "fm.h" +//#include +#ifdef MT6573 +#include +#endif +//#include + +#include "stp_exp.h" +#include "wmt_exp.h" + +#include "mt6620_fm.h" +#include "mt6620_fm_lib.h" +#include "../private/mtk_fm.h" +#include "mt6620_fm_reg.h" + +#ifdef CTP_CHECK_FM +extern void tpd_get_fm_frequency(int16_t freq); +#endif + +#define FM_VOL_MAX 0x2B // 43 volume(0-15) + +#define FM_DEV_MAJOR 193 +static int FM_major = FM_DEV_MAJOR; /* dynamic allocation */ + +#define FM_PROC_FILE "fm" +static struct proc_dir_entry *g_fm_proc = NULL; + +#define FM_PROC_CONFIG "fmconfig" +static struct fm_config g_fm_config; + +uint32_t g_dbg_level = 0xfffffff5; // Debug level of FM + +static struct fm *fm_cb = NULL; //fm main data structure +struct fm_priv priv; //fm priv data, and will be linked to fm main data structure + +volatile int16_t _current_frequency = 0xFFFF; +static unsigned char *tx_buf = NULL; + +volatile uint16_t seek_result = 0; +uint16_t scan_result[MT6620_SCANTBL_SIZE] = {0}; +struct rds_rx rds_rx_result; +volatile uint16_t rds_rx_size = 0; +static volatile uint32_t flag = 0; +static spinlock_t flag_lock; + +static volatile uint16_t fspi_rd = 0; + +static struct fm_gps_rtc_info gps_rtc_info; + +extern uint32_t gBLER_CHK_INTERVAL; +extern uint16_t GOOD_BLK_CNT; +extern uint16_t BAD_BLK_CNT; +extern uint8_t BAD_BLK_RATIO; + +static struct timer_list fm_timer; +static struct fm_timer_sys timer_sys; + +static volatile int chip_rst_state = FM_WHOLECHIP_RST_OFF; +static volatile int subsys_rst_state = FM_SUBSYS_RST_OFF; +static struct fm_context *fm_cxt; + +#ifndef DECLARE_MUTEX +#define DECLARE_MUTEX(name) DEFINE_SEMAPHORE(name) +#endif +static DECLARE_WAIT_QUEUE_HEAD(fm_wq); +static DECLARE_MUTEX(fm_ops_mutex); //protect FM ops: open, close, read, ioctl +static DECLARE_MUTEX(fm_read_mutex); //protect RDS good/bad block global val +static DECLARE_MUTEX(fm_rds_mutex); //protec RDS ps/rt ... +static DECLARE_MUTEX(fm_timer_mutex); //protec FM timer +static DECLARE_MUTEX(fm_cmd_mutex); //protect FM HW access +static DECLARE_MUTEX(fm_rtc_mutex); //protect FM GPS RTC drift info +static DECLARE_MUTEX(fm_rxtx_mutex); //protect FM RX TX mode switch + +/****************************************************************************** + * FUNCTION PROTOTYPES + *****************************************************************************/ +//schedule func +void stp_rx_event_cb(void); //called by stp driver +static void fm_timer_func(unsigned long data); //called by timer timeout + +//worker func +static void fm_rx_worker_func(struct work_struct *work); //scheduled by stp_rx_event_cb +static void fm_rds_reset_worker_func(struct work_struct *work); //scheduled by fm_timer_func +static void fm_tx_rtc_ctrl_worker_func(struct work_struct *work); // +static void fm_tx_power_ctrl_worker_func(struct work_struct *work); +static void fm_tx_desense_wifi_worker_func(struct work_struct *work); +static void fm_rst_recover_worker_func(struct work_struct *work); +static void fm_subsys_recover_worker_func(struct work_struct *work); + +//normal func +static int fm_enable_rds_BlerCheck(struct fm *fm); +static int fm_disable_rds_BlerCheck(void); + +static int fm_hw_reset(void); +static int fm_recover_func(struct fm *fm, struct fm_context *cxt); + +static int fm_tx_scan(struct fm *fm, struct fm_tx_scan_parm *parm); +int fm_send_wait_timeout(unsigned char* tx_buf, + uint16_t pkt_size, + int flag_mask, + int retry_cnt, + int timeout); + +static int MT6620_TxScan_SetFreq(uint16_t freq); +static int MT6620_TxScan_GetCQI(int16_t *pRSSI, int16_t *pPAMD, int16_t *pMR); +static int MT6620_TxScan_IsEmptyChannel(int16_t RSSI, int16_t PAMD, int16_t MR, int *empty); +static int MT6620_TxScan(uint16_t min_freq, uint16_t max_freq, uint16_t *pFreq, uint16_t *pScanTBL, uint16_t *ScanTBLsize, uint16_t scandir, uint16_t space); +extern int MT6620_RDS_BlerCheck(struct fm *fm); +extern int MT6620_RDS_Eint_Handler(struct fm *fm, struct rds_rx *rds_raw, int rds_size); +extern int MT6620_RDS_OnOff(struct fm *fm, bool bFlag); +extern int rds_group_counter_get(struct rds_group_cnt *dst, struct rds_group_cnt *src); +extern int rds_group_counter_reset(struct rds_group_cnt *gc); + +int Delayms(uint32_t data); +int Delayus(uint32_t data); +int MT6620_read(uint8_t addr, uint16_t *val); +int MT6620_write(uint8_t addr, uint16_t val); +int MT6620_set_bits(uint8_t addr, uint16_t bits, uint16_t mask); +static int MT6620_Mute(bool mute); +static int MT6620_RampDown(void); +static int MT6620_RampDown_Tx(void); +static int MT6620_SetFreq(uint16_t freq); // functionality tune +static int MT6620_Fast_SetFreq(uint16_t freq); +static int MT6620_SetFreq_Tx(uint16_t freq); // functionality tune +static int MT6620_Seek( + uint16_t min_freq, uint16_t max_freq, + uint16_t *pFreq, + uint16_t seekdir, + uint16_t space); +static int MT6620_Scan( + uint16_t min_freq, uint16_t max_freq, + uint16_t *pFreq, //get the valid freq after scan + uint16_t *pScanTBL, + uint16_t *ScanTBLsize, + uint16_t scandir, + uint16_t space); +static int MT6620_ScanForceStop(void); +static int MT6620_GetCurRSSI(int *pRSSI); +static int MT6620_SetVol(uint8_t vol); +static int MT6620_GetVol(uint8_t *pVol); +#ifdef FMDEBUG +static int MT6620_dump_reg(void); +#endif +static int MT6620_GetMonoStereo(uint16_t *pMonoStereo); +static int MT6620_SetMonoStereo(int MonoStereo); +static int MT6620_GetCapArray(int *caparray); +static int MT6620_GetCurPamd(uint16_t *pPamdLevl); +static int MT6620_em_test(uint16_t group_idx, uint16_t item_idx, uint32_t item_value); +static int MT6620_Rds_Tx_Enable(uint8_t enable); +static int MT6620_Rds_Tx(uint16_t pi, uint16_t *ps, uint16_t *other_rds, uint8_t other_rds_cnt); +static int MT6620_I2S_Setting(int onoff, int mode, int sample); +static int MT6620_FMOverBT(int enable); +static int MT6620_ANA_SWITCH(int antenna); + +static int fm_setup_cdev(struct fm *fm); +static long fm_ops_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +static loff_t fm_ops_lseek(struct file *filp, loff_t off, int whence); +static ssize_t fm_ops_read(struct file *filp, char *buf, size_t len, loff_t *off); +static int fm_ops_open(struct inode *inode, struct file *filp); +static int fm_ops_release(struct inode *inode, struct file *filp); + +static int fm_get_process_path(struct fm *fm); +static int fm_get_gps_rtc_info(struct fm_gps_rtc_info *dst, struct fm_gps_rtc_info *src); +static int fm_rtc_compensation_init(struct fm *fm, struct fm_gps_rtc_info *rtc); +static int fm_timer_init(struct fm *fm, struct fm_timer_sys *fmtimer, struct timer_list *timer); + +static int fm_init(void); +static int fm_destroy(struct fm *fm); +static int fm_powerup(struct fm *fm, struct fm_tune_parm *parm); +static int fm_antenna_switch(struct fm *fm, int antenna); +static int fm_powerup_tx(struct fm *fm, struct fm_tune_parm *parm); +static int fm_powerdown(struct fm *fm, int type); +static int fm_tune(struct fm *fm, struct fm_tune_parm *parm); +static int fm_tune_tx(struct fm *fm, struct fm_tune_parm *parm); +static int fm_seek(struct fm *fm, struct fm_seek_parm *parm); +static int fm_scan(struct fm *fm, struct fm_scan_parm *parm); +static int fm_get_rssi_after_scan(struct fm *fm, struct fm_rssi_req *req); +static int fm_get_hw_info(struct fm *pfm, struct fm_hw_info *req); +static int fm_setvol(struct fm *fm, uint32_t vol); +static int fm_getvol(struct fm *fm, uint32_t *vol); +static int fm_getrssi(struct fm *fm, int *rssi); +static int fm_rds_tx(struct fm *fm, struct fm_rds_tx_parm *parm); +static int fm_over_bt(struct fm *fm, int enable); +static int fm_proc_read(char *page, char **start, off_t off, + int count, int *eof, void *data); +static int fm_proc_write(struct file *file, const char *buffer, + unsigned long count, void *data); +static int fmconfig_proc_read(char *page, char **start, off_t off, + int count, int *eof, void *data); +static int fmconfig_proc_write(struct file *file, const char *buffer, + unsigned long count, void *data); + +static struct file_operations fm_ops = { + .owner = THIS_MODULE, + .unlocked_ioctl = fm_ops_ioctl, + .llseek = fm_ops_lseek, + .read = fm_ops_read, + .open = fm_ops_open, + .release = fm_ops_release, +}; + +/****************************************************************************** + *****************************************************************************/ + +/* + * delay ms + */ +int Delayms(uint32_t data) +{ + msleep(data); + FM_LOG_DBG(D_CMD,"delay %dms\n", data); + return 0; +} + +/* + * delay us + */ +int Delayus(uint32_t data) +{ + udelay(data); + FM_LOG_DBG(D_CMD,"delay %dus\n", data); + return 0; +} + +/*********************************************************** +Function: fm_send_wait_timeout() + +Description: send cmd to FM firmware and wait event + +Para: tx_buf--->send buffer + pkt_size--->the length of cmd + flag_mask--->the event flag mask + retry_cnt--->the retry conter + timeout--->timeout per cmd + +Return: 0, if success; error code, if failed +***********************************************************/ +int fm_send_wait_timeout(unsigned char* tx_buf, + uint16_t pkt_size, + int flag_mask, + int retry_cnt, + int timeout) +{ + int ret_val = 0; + int ret_time = 0; + + if((NULL == tx_buf) || (pkt_size < 0) || (0 == flag_mask) + || (retry_cnt > SW_RETRY_CNT_MAX) || (timeout > SW_WAIT_TIMEOUT_MAX)){ + FM_LOG_ERR(D_ALL,"%s():invalid para\n", __func__); + ret_val = -ERR_INVALID_PARA; + goto out; + } + FM_LOG_DBG(D_MAIN,"0,flag_mask=0x%08x\n", flag_mask); +sw_retry: + //FM_LOG_DBG(D_MAIN,"0,flag_mask=0x%08x\n", flag_mask); + if(mtk_wcn_stp_send_data(tx_buf, pkt_size, FM_TASK_INDX) == 0){ + FM_LOG_ERR(D_MAIN,"%s():send data over stp failed\n", __func__); + ret_val = -ERR_STP; //stp error is the most serious error, wo can do nothing but info APP + goto out; + }else{ + //FM_LOG_DBG(D_MAIN,"1,flag_mask=0x%08x\n", flag_mask); + ret_time = wait_event_timeout(fm_wq, ((flag & flag_mask) == flag_mask), timeout*HZ); + FM_LOG_DBG(D_MAIN,"[flag=0x%08x]\n", flag); + if(!ret_time){ + if(0 < retry_cnt--){ + FM_LOG_WAR(D_MAIN,"%s():wait even timeout, [retry_cnt=%d]\n", __func__, retry_cnt); + goto sw_retry; + }else{ + FM_LOG_ERR(D_MAIN,"%s():fatal error, SW retry failed, reset HW\n", __func__); + ret_val = -ERR_FW_NORES; //return fatal error + goto out; + } + } + FM_LOG_DBG(D_MAIN,"2,flag_mask=0x%08x\n", flag_mask); + spin_lock(&flag_lock); + flag &= ~flag_mask; + spin_unlock(&flag_lock); + } +out: + return ret_val; +} + +/* + * MT6620_read + */ +int MT6620_read(uint8_t addr, uint16_t *val) +{ + int ret_val = 0; + uint16_t pkt_size; + + FM_LOG_DBG(D_CMD,"+%s(): [addr=0x%02x]\n", __func__, addr); + FM_LOG_INF(D_CMD,"-fm_cmd_mutex\n"); + if (down_interruptible(&fm_cmd_mutex)){ + FM_LOG_ERR(D_CMD|D_ALL, "%s(): get mutex failed\n", __func__); + ret_val = -ERR_GET_MUTEX; + goto out1; + } + + if(tx_buf == NULL){ + FM_LOG_ERR(D_CMD|D_ALL, "%s(): invalid tx_buf\n", __func__); + ret_val = -ERR_INVALID_BUF; + goto out; + } + memset(tx_buf, 0, TX_BUF_SIZE); + + pkt_size = mt6620_get_reg(tx_buf, TX_BUF_SIZE, addr); + ret_val = fm_send_wait_timeout(tx_buf, pkt_size, + FLAG_FSPI_RD, SW_RETRY_CNT, FSPI_RD_TIMEOUT); + if(!ret_val){ + *val = fspi_rd; + } +out: + up(&fm_cmd_mutex); + FM_LOG_INF(D_CMD,"+fm_cmd_mutex\n"); + +out1: + FM_LOG_DBG(D_CMD,"-%s(): [val=0x%02x]\n", __func__, fspi_rd); + return ret_val; +} + +/* + * MT6620_write + */ +int MT6620_write(uint8_t addr, uint16_t val) +{ + int ret_val = 0; + uint16_t pkt_size; + + FM_LOG_DBG(D_CMD,"+%s(): [addr=0x%02x]\n", __func__, addr); + FM_LOG_INF(D_CMD,"-fm_cmd_mutex\n"); + if (down_interruptible(&fm_cmd_mutex)){ + FM_LOG_ERR(D_CMD|D_ALL,"%s(): get mutex failed\n", __func__); + ret_val = -ERR_GET_MUTEX; + goto out1; + } + + if(tx_buf == NULL){ + FM_LOG_ERR(D_CMD|D_ALL,"%s(): invalid tx_buf\n", __func__); + ret_val = -ERR_INVALID_BUF; + goto out; + } + memset(tx_buf, 0, TX_BUF_SIZE); + pkt_size = mt6620_set_reg(tx_buf, TX_BUF_SIZE, addr, val); + ret_val = fm_send_wait_timeout(tx_buf, pkt_size, + FLAG_FSPI_WR, SW_RETRY_CNT, FSPI_WR_TIMEOUT); +out: + up(&fm_cmd_mutex); + FM_LOG_INF(D_CMD,"+fm_cmd_mutex\n"); + +out1: + FM_LOG_DBG(D_CMD,"-%s(): [addr=0x%02x]\n", __func__, addr); + return ret_val; +} + +int MT6620_set_bits(uint8_t addr, uint16_t bits, uint16_t mask) +{ + int ret = 0; + uint16_t val; + + FM_LOG_DBG(D_CMD,"+%s(): [addr=0x%02x],[bits=0x%04x],[mask=0x%04x]\n", __func__, addr, bits, mask); + ret = MT6620_read(addr, &val); + if (ret) + goto out; + + val = ((val & (mask)) | bits); + + ret = MT6620_write(addr, val); + +out: + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +/* + * MT6620_Mute + * + * 1.Mute/Unmute audio, enable/disable rgf mute + * 2.Record mute status for FM recover context + */ +static int MT6620_Mute(bool mute) +{ + int ret = 0; + + FM_LOG_DBG(D_CMD,"+%s():[mute=%d]\n", __func__, mute); + fm_cxt->rxcxt.mute = mute; + + if(mute){ + ret = MT6620_set_bits(0x9C, 0x0008, 0xFFF7); //1:9C D3 = 1 + }else{ + ret = MT6620_set_bits(0x9c, 0x0000, 0xFFF7); //1:9C D3 = 0 + } + + FM_LOG_NTC(D_CMD,"%s\n", mute ? "mute" : "unmute"); + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +/* + * MT6620_RampDown + * + * 1.Mute audio, enable rgf mute + * 2.Set softmute to fast mode + * 3.Clear all hw control requests + * + * Before return, we need check STC_DONE status flag (not the interrupt flag!) + * to ensure the sounds has now fully muted. + */ +static int MT6620_RampDown() +{ + int ret = 0; + uint16_t pkt_size = 0; + + FM_LOG_DBG(D_CMD,"+%s():\n", __func__); + FM_LOG_INF(D_CMD,"-fm_cmd_mutex\n"); + if (down_interruptible(&fm_cmd_mutex)){ + FM_LOG_ERR(D_CMD|D_ALL,"%s(): get mutex failed\n", __func__); + ret = -ERR_GET_MUTEX; + goto out1; + } + + if(tx_buf == NULL){ + FM_LOG_ERR(D_CMD|D_ALL,"%s(): invalid tx_buf\n", __func__); + ret = -ERR_INVALID_BUF; + goto out; + } + memset(tx_buf, 0, TX_BUF_SIZE); + + pkt_size = mt6620_rampdown(tx_buf, TX_BUF_SIZE); + ret = fm_send_wait_timeout(tx_buf, pkt_size, + FLAG_RAMPDOWN, SW_RETRY_CNT, RAMPDOWN_TIMEOUT); +out: + up(&fm_cmd_mutex); + FM_LOG_INF(D_CMD,"+fm_cmd_mutex\n"); + +out1: + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +static int MT6620_RampDown_Tx() +{ + int ret = 0; + uint16_t pkt_size = 0; + + FM_LOG_DBG(D_CMD,"+%s():\n", __func__); + FM_LOG_INF(D_CMD,"-fm_cmd_mutex\n"); + if (down_interruptible(&fm_cmd_mutex)){ + FM_LOG_ERR(D_CMD|D_ALL,"%s(): get mutex failed\n", __func__); + ret = -ERR_GET_MUTEX; + goto out1; + } + + if(tx_buf == NULL){ + FM_LOG_ERR(D_CMD|D_ALL,"%s(): invalid tx_buf\n", __func__); + ret = -ERR_INVALID_BUF; + goto out; + } + memset(tx_buf, 0, TX_BUF_SIZE); + pkt_size = mt6620_rampdown_tx(tx_buf, TX_BUF_SIZE); + ret = fm_send_wait_timeout(tx_buf, pkt_size, + FLAG_RAMPDOWN, SW_RETRY_CNT, RAMPDOWN_TIMEOUT); + +out: + up(&fm_cmd_mutex); + FM_LOG_INF(D_CMD,"+fm_cmd_mutex\n"); + +out1: + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +static int MT6620_SetFreq(uint16_t freq) +{ + int ret = 0; + uint16_t pkt_size = 0; + + FM_LOG_DBG(D_CMD,"+%s():[freq=%d]\n", __func__, freq); + FM_LOG_INF(D_CMD,"-fm_cmd_mutex\n"); + if (down_interruptible(&fm_cmd_mutex)){ + FM_LOG_ERR(D_CMD|D_ALL,"%s(): get mutex failed\n", __func__); + ret = -ERR_GET_MUTEX; + goto out1; + } + + if(tx_buf == NULL){ + FM_LOG_ERR(D_CMD|D_ALL,"%s(): invalid tx_buf\n", __func__); + ret = -ERR_INVALID_BUF; + goto out; + } + memset(tx_buf, 0, TX_BUF_SIZE); + + pkt_size = mt6620_tune_1(tx_buf, TX_BUF_SIZE, freq); + ret = fm_send_wait_timeout(tx_buf, pkt_size, + FLAG_TUNE, SW_RETRY_CNT, TUNE_TIMEOUT); + Delayms(200); + pkt_size = mt6620_tune_2(tx_buf, TX_BUF_SIZE, freq); + ret = fm_send_wait_timeout(tx_buf, pkt_size, + FLAG_TUNE, SW_RETRY_CNT, TUNE_TIMEOUT); + Delayms(35); + pkt_size = mt6620_tune_3(tx_buf, TX_BUF_SIZE, freq); + ret = fm_send_wait_timeout(tx_buf, pkt_size, + FLAG_TUNE, SW_RETRY_CNT, TUNE_TIMEOUT); + _current_frequency = freq; + FM_LOG_NTC(D_CMD,"tune[freq=%d]\n", freq); +#ifdef CTP_CHECK_FM + tpd_get_fm_frequency(_current_frequency); +#endif + +out: + up(&fm_cmd_mutex); + FM_LOG_INF(D_CMD,"+fm_cmd_mutex\n"); + +out1: + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +static int MT6620_Fast_SetFreq(uint16_t freq) +{ + int ret = 0; + uint16_t pkt_size = 0; + + if (down_interruptible(&fm_cmd_mutex)){ + FM_LOG_ERR(D_CMD, "%s(): get mutex failed\n", __func__); + return -ERR_GET_MUTEX; + } + + if(!tx_buf){ + FM_LOG_ERR(D_CMD, "%s():invalid tx_buf\n", __func__); + ret = -ERR_INVALID_BUF; + goto release_mutex; + } + memset(tx_buf, 0, TX_BUF_SIZE); + + pkt_size = mt6620_fast_tune(tx_buf, TX_BUF_SIZE, freq); + ret = fm_send_wait_timeout(tx_buf, pkt_size, FLAG_TUNE, SW_RETRY_CNT, TUNE_TIMEOUT); + +release_mutex: + up(&fm_cmd_mutex); + return ret; +} + +static int MT6620_SetFreq_Tx(uint16_t freq) +{ + int ret = 0; + uint16_t pkt_size = 0; + + FM_LOG_DBG(D_CMD,"+%s():[freq=%d]\n", __func__, freq); + FM_LOG_INF(D_CMD,"-fm_cmd_mutex\n"); + if (down_interruptible(&fm_cmd_mutex)){ + FM_LOG_ERR(D_CMD|D_ALL,"%s(): get mutex failed\n", __func__); + ret = -ERR_GET_MUTEX; + goto out1; + } + + if(tx_buf == NULL){ + FM_LOG_ERR(D_CMD|D_ALL,"%s(): invalid tx_buf\n", __func__); + ret = -ERR_INVALID_BUF; + goto out; + } + memset(tx_buf, 0, TX_BUF_SIZE); + + pkt_size = mt6620_tune_tx(tx_buf, TX_BUF_SIZE, freq); + ret = fm_send_wait_timeout(tx_buf, pkt_size, + FLAG_TUNE, SW_RETRY_CNT, TUNE_TIMEOUT); + + Delayms(125); + _current_frequency = freq; + +out: + up(&fm_cmd_mutex); + FM_LOG_INF(D_CMD,"+fm_cmd_mutex\n"); + +out1: + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +/* +* MT6620_Seek +* pFreq: IN/OUT parm, IN start freq/OUT seek valid freq +* return true:seek success; false:seek failed +*/ +static int MT6620_Seek(uint16_t min_freq, uint16_t max_freq, uint16_t *pFreq, uint16_t seekdir, uint16_t space) +{ + int ret = 0; + uint16_t pkt_size = 0; + uint16_t startfreq = *pFreq; + + FM_LOG_DBG(D_CMD,"+%s():[startfreq=%d]\n", __func__, startfreq); + + if((ret = MT6620_RampDown())){ + FM_LOG_ERR(D_CMD|D_ALL,"%s():RampDown failed\n", __func__); + goto out1; + } + + FM_LOG_INF(D_CMD,"-fm_cmd_mutex\n"); + if (down_interruptible(&fm_cmd_mutex)){ + FM_LOG_ERR(D_CMD|D_ALL,"%s(): get mutex failed\n", __func__); + ret = -ERR_GET_MUTEX; + goto out1; + } + + if(tx_buf == NULL){ + FM_LOG_ERR(D_CMD|D_ALL,"%s(): invalid tx_buf\n", __func__); + ret = -ERR_INVALID_BUF; + goto out; + } + memset(tx_buf, 0, TX_BUF_SIZE); + + pkt_size = mt6620_seek_1(tx_buf, TX_BUF_SIZE, seekdir, space, max_freq, min_freq); + ret = fm_send_wait_timeout(tx_buf, pkt_size, + FLAG_SEEK | FLAG_SEEK_DONE, SW_RETRY_CNT, SEEK_TIMEOUT); + if(!ret){ + *pFreq = seek_result; + _current_frequency = seek_result; + FM_LOG_NTC(D_CMD,"seek[freq=%d]\n", seek_result); + Delayms(35); +#ifdef CTP_CHECK_FM + tpd_get_fm_frequency(_current_frequency); +#endif + }else{ + FM_LOG_WAR(D_CMD,"Rx Seek Failed\n"); + } + pkt_size = mt6620_seek_2(tx_buf, TX_BUF_SIZE, seekdir, space, max_freq, min_freq); + ret = fm_send_wait_timeout(tx_buf, pkt_size, + FLAG_SEEK, SW_RETRY_CNT, SEEK_TIMEOUT); +out: + up(&fm_cmd_mutex); + FM_LOG_INF(D_CMD,"+fm_cmd_mutex\n"); + +out1: + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +static int MT6620_TxScan_SetFreq(uint16_t freq) +{ + int ret = 0; + uint16_t pkt_size = 0; + + FM_LOG_DBG(D_CMD,"+%s():[freq=%d]\n", __func__, freq); + FM_LOG_INF(D_CMD,"-fm_cmd_mutex\n"); + if (down_interruptible(&fm_cmd_mutex)){ + FM_LOG_ERR(D_CMD|D_ALL,"%s(): get mutex failed\n", __func__); + ret = -ERR_GET_MUTEX; + goto out1; + } + + if(tx_buf == NULL){ + FM_LOG_ERR(D_CMD|D_ALL,"%s(): invalid tx_buf\n", __func__); + ret = -ERR_INVALID_BUF; + goto out; + } + memset(tx_buf, 0, TX_BUF_SIZE); + + pkt_size = mt6620_tune_txscan(tx_buf, TX_BUF_SIZE, freq); + ret = fm_send_wait_timeout(tx_buf, pkt_size, + FLAG_TUNE, SW_RETRY_CNT, TUNE_TIMEOUT); + + //Delayms(125); + _current_frequency = freq; +out: + up(&fm_cmd_mutex); + FM_LOG_INF(D_CMD,"+fm_cmd_mutex\n"); + +out1: + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +static int MT6620_TxScan_GetCQI(int16_t *pRSSI, int16_t *pPAMD, int16_t *pMR) +{ + int cnt = 0; + int ret = 0; + int16_t tmp_reg = 0; + int16_t aRSSI = 0; + int16_t aPAMD = 0; + int16_t aMR = 0; + + FM_LOG_DBG(D_CMD,"+%s():\n", __func__); + + if((pRSSI == NULL) || (pPAMD == NULL) || (pMR == NULL)){ + FM_LOG_ERR(D_CMD|D_ALL,"%s():para error, [pRSSI=%p],[aPAMD=%p],[pMR=%p]\n", + __func__, pRSSI, pPAMD, pMR); + ret = -ERR_INVALID_PARA; + goto out; + } + + for(cnt = 0; cnt < 8; cnt++){ + Delayms(3); + if((ret = MT6620_read(FM_ADDR_RSSI, &tmp_reg))) + goto out; + tmp_reg = tmp_reg&0x03ff; + tmp_reg = (tmp_reg > 511) ? ((int16_t)(tmp_reg-1024)) : tmp_reg; + aRSSI += tmp_reg; + + if((ret = MT6620_read(FM_ADDR_PAMD, &tmp_reg))) + goto out; + tmp_reg = tmp_reg&0x00ff; + tmp_reg = (tmp_reg > 127) ? ((int16_t)(tmp_reg-256)) : tmp_reg; + aPAMD += tmp_reg; + + if((ret = MT6620_read(FM_ADDR_MR, &tmp_reg))) + goto out; + tmp_reg = tmp_reg&0x01ff; + tmp_reg = (tmp_reg > 255) ? ((int16_t)(tmp_reg-512)) : tmp_reg; + aMR += tmp_reg; + } + + *pRSSI = aRSSI>>3; + *pPAMD = aPAMD>>3; + *pMR = aMR>>3; + + FM_LOG_DBG(D_CMD,"%s():[RSSI=%d],[PAMD=%d],[MR=%d]\n", + __func__, *pRSSI, *pPAMD, *pMR); + +out: + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +static int MT6620_TxScan_IsEmptyChannel(int16_t RSSI, int16_t PAMD, int16_t MR, int *empty) +{ + int ret = 0; + + FM_LOG_DBG(D_CMD,"+%s():[RSSI=%d],[PAMD=%d],[MR=%d]\n", __func__, RSSI, PAMD, MR); + + if(empty == NULL){ + FM_LOG_DBG(D_CMD,"invalid pointer [empty=0x%x]!\n", (unsigned int)empty); + ret = -ERR_INVALID_PARA; + goto out; + } + + *empty = TRUE; + if(RSSI > FM_TXSCAN_RSSI_TH){ + *empty = FALSE; + goto out; + } + + if(PAMD < FM_TXSCAN_PAMD_TH){ + *empty = FALSE; + goto out; + } + + if(MR < FM_TXSCAN_MR_TH){ + *empty = FALSE; + goto out; + } + +out: + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +static int MT6620_TxScan( + uint16_t min_freq, uint16_t max_freq, + uint16_t *pFreq, + uint16_t *pScanTBL, + uint16_t *ScanTBLsize, + uint16_t scandir, + uint16_t space) +{ + int ret = 0; + uint16_t freq = *pFreq; + uint16_t scan_cnt = *ScanTBLsize; + uint16_t cnt = 0; + int16_t rssi = 0; + int16_t pamd = 0; + int16_t mr = 0; + int counter = 0; + int empty = -1; + + FM_LOG_DBG(D_CMD,"+%s():\n", __func__); + + if((!pScanTBL) || (*ScanTBLsize < TX_SCAN_MIN) || (*ScanTBLsize > TX_SCAN_MAX)){ + FM_LOG_ERR(D_CMD|D_ALL,"+%s():invalid scan table\n", __func__); + ret = -ERR_INVALID_PARA; + goto out; + } + + FM_LOG_DBG(D_CMD, "[freq=%d], [max_freq=%d],[min_freq=%d],[scan BTL size=%d],[scandir=%d],[space=%d]\n", + *pFreq, max_freq, min_freq, *ScanTBLsize, scandir, space); + + cnt = 0; + while(!(!(cnt < scan_cnt) || (freq > max_freq) || (freq < min_freq))){ + //MT6620_RampDown(); + //Set desired channel, tune to the channel, and perform fast AGC + counter++; //just for debug + + ret = MT6620_TxScan_SetFreq(freq); + if(ret){ + FM_LOG_ERR(D_CMD|D_ALL,"%s():set freq failed\n", __func__); + goto out; + } + + //wait 8~10ms for RF setting + Delayms(10); + //wait 4 AAGC period for AAGC setting, AAGC period = 1024/480k = 2.13ms + Delayms(9); + + ret = MT6620_TxScan_GetCQI(&rssi, &pamd, &mr); + if(ret){ + FM_LOG_ERR(D_CMD|D_ALL,"%s():get CQI failed\n", __func__); + goto out; + } + + ret = MT6620_TxScan_IsEmptyChannel(rssi, pamd, mr, &empty); + if(!ret){ + if((empty == TRUE) && ((freq < FMTX_SCAN_HOLE_LOW) || (freq > FMTX_SCAN_HOLE_HIGH))){ + *(pScanTBL + cnt) = freq; //strore the valid empty channel + cnt++; + FM_LOG_NTC(D_CMD|D_ALL,"empty channel:[freq=%d] [cnt=%d]\n", freq, cnt); + } + }else{ + FM_LOG_ERR(D_CMD|D_ALL,"%s():IsEmptyChannel failed\n", __func__); + goto out; + } + + if(scandir == SCAN_UP){ + if(freq == FMTX_SCAN_HOLE_LOW){ + freq += (FMTX_SCAN_HOLE_HIGH - FMTX_SCAN_HOLE_LOW + 1); + }else{ + freq += space; + } + }else if(scandir == SCAN_DOWN){ + if(freq == FMTX_SCAN_HOLE_HIGH){ + freq -= (FMTX_SCAN_HOLE_HIGH - FMTX_SCAN_HOLE_LOW + 1); + }else{ + freq -= space; + } + }else{ + FM_LOG_ERR(D_CMD|D_ALL,"%s():scandir para error\n", __func__); + ret = -ERR_INVALID_PARA; + goto out; + } + } + + *ScanTBLsize = cnt; + *pFreq = *(pScanTBL + cnt); + FM_LOG_DBG(D_CMD, "completed, [cnt=%d],[freq=%d],[counter=%d]\n", cnt, freq, counter); + FM_LOG_INF(D_CMD, "--time end[%d]\n", jiffies_to_msecs(jiffies)); + +out: + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +/* + * MT6620_Scan + * + * Steps: + * 1.We should mute FM, and clear all hw control requests, so do Ramp_Down + * 2.Set scan direction, channel spacing + * (If need, set scan lower and upper Freq before step 3) + * 3.Enable hardware controlled scanning sequence + * 4.Check STC_DONE interrupt status flag, then clear the STC_DONE interrupt status flag + * 5.Read back channel scan bit_map information + * (IF need sorting by RSSI jump to Get RSSI after scan page) + * 6.Disable mute, Set softmute to normal mode. + */ +static int MT6620_Scan( + uint16_t min_freq, uint16_t max_freq, + uint16_t *pFreq, + uint16_t *pScanTBL, + uint16_t *ScanTBLsize, + uint16_t scandir, + uint16_t space) +{ + int ret = 0; + uint16_t pkt_size = 0; + uint16_t offset = 0; + uint16_t tmp_scanTBLsize = *ScanTBLsize; + + FM_LOG_DBG(D_CMD,"+%s():\n", __func__); + + if((!pScanTBL) || (tmp_scanTBLsize < MT6620_SCANTBL_SIZE)){ + FM_LOG_ERR(D_ALL,"+%s():invalid scan table\n", __func__); + ret = -ERR_INVALID_PARA; + goto out1; + } + + FM_LOG_INF(D_CMD, "[freq=%d], [max_freq=%d],[min_freq=%d],[scan BTL size=%d],[scandir=%d],[space=%d]\n", + *pFreq, max_freq, min_freq, *ScanTBLsize, scandir, space); + if(tmp_scanTBLsize > MT6620_SCANTBL_SIZE){ + tmp_scanTBLsize = MT6620_SCANTBL_SIZE; + } + + MT6620_RampDown(); + + //Clear "FLAG_SCAN" & "FLAG_SCAN_DONE" to make sure we do make a new scan + spin_lock(&flag_lock); + flag &= ~(FLAG_SCAN | FLAG_SCAN_DONE); + spin_unlock(&flag_lock); + FM_LOG_INF(D_CMD,"-fm_cmd_mutex\n"); + if (down_interruptible(&fm_cmd_mutex)){ + FM_LOG_ERR(D_CMD|D_ALL,"%s(): get mutex failed\n", __func__); + ret = -ERR_GET_MUTEX; + goto out1; + } + + if(tx_buf == NULL){ + FM_LOG_ERR(D_CMD|D_ALL,"%s(): invalid tx_buf\n", __func__); + ret = -ERR_INVALID_BUF; + goto out; + } + memset(tx_buf, 0, TX_BUF_SIZE); + + pkt_size = mt6620_scan_1(tx_buf, TX_BUF_SIZE, scandir, space, max_freq, min_freq); + ret = fm_send_wait_timeout(tx_buf, pkt_size, + FLAG_SCAN | FLAG_SCAN_DONE, SW_RETRY_CNT, SCAN_TIMEOUT); + if(!ret){ + memcpy(pScanTBL, scan_result, sizeof(uint16_t)*MT6620_SCANTBL_SIZE); + FM_LOG_INF(D_CMD,"Rx Scan Result:\n"); + for(offset = 0; offset < tmp_scanTBLsize; offset++){ + FM_LOG_INF(D_CMD,"%d: %04x\n", (int)offset, *(pScanTBL+offset)); + } + *ScanTBLsize = tmp_scanTBLsize; + Delayms(35); + }else{ + FM_LOG_WAR(D_CMD,"Rx Scan Failed\n"); + } + pkt_size = mt6620_scan_2(tx_buf, TX_BUF_SIZE, scandir, space, max_freq, min_freq); + ret = fm_send_wait_timeout(tx_buf, pkt_size, + FLAG_SCAN, SW_RETRY_CNT, SCAN_TIMEOUT); +out: + up(&fm_cmd_mutex); + FM_LOG_INF(D_CMD,"+fm_cmd_mutex\n"); + +out1: + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +static int MT6620_ScanForceStop() +{ + int ret = 0; + + FM_LOG_DBG(D_CMD,"+%s():\n", __func__); + + spin_lock(&flag_lock); + flag |= FLAG_SCAN_DONE; + spin_unlock(&flag_lock); + memset(scan_result, 0, sizeof(uint16_t) * MT6620_SCANTBL_SIZE); + FM_LOG_DBG(D_CMD,"[flag=0x%08x]\n", flag); + wake_up(&fm_wq); + + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +static int MT6620_GetCurRSSI(int *pRSSI) +{ + uint16_t tmp_reg; + int ret = 0; + + FM_LOG_DBG(D_CMD,"+%s():\n", __func__); + + if((ret = MT6620_read(FM_ADDR_RSSI, &tmp_reg))) + goto out; + FM_LOG_DBG(D_CMD,"[addr=0x%02x],[val=0x%04x]\n",\ + FM_ADDR_RSSI, tmp_reg); + + tmp_reg = tmp_reg&0x03ff; + //RS=RSSI + //If RS>511, then RSSI(dBm)= (RS-1024)/16*6 + // else RSSI(dBm)= RS/16*6 + // dBm + if (pRSSI){ + *pRSSI = (tmp_reg>511) ? (((tmp_reg-1024)*6)>>4):((tmp_reg*6)>>4); + } + FM_LOG_DBG(D_CMD,"[RSSI=%d]\n", *pRSSI); +out: + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +static int MT6620_SetVol(uint8_t vol) +{ + int ret = 0; + uint8_t tmp_vol = vol&0x3f; + + FM_LOG_DBG(D_CMD,"+%s():\n", __func__); + + if(tmp_vol > FM_VOL_MAX) + tmp_vol = FM_VOL_MAX; + + if((ret = MT6620_set_bits(0x9C, (tmp_vol<<8), 0xC0FF))) + goto out; + FM_LOG_DBG(D_CMD,"[vol=%d]\n", tmp_vol); + +out: + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +static int MT6620_GetVol(uint8_t *pVol) +{ + uint16_t tmp_reg; + int ret = 0; + + FM_LOG_DBG(D_CMD,"+%s():\n", __func__); + + if((ret = MT6620_read(0x9C, &tmp_reg))) + goto out; + + *pVol = (tmp_reg>>8) & 0x3f; + FM_LOG_DBG(D_CMD,"[vol=%d]\n", *pVol); + +out: + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + + +/*********************************************************** +Function: MT6620_I2S_Setting() + +Description: set the I2S state on MT6620 + +Para: onoff--->I2S on/off + mode--->I2S mode: Master or Slave + +Return: 0, if success; error code, if failed +***********************************************************/ +static int MT6620_I2S_Setting(int onoff, int mode, int sample) +{ + uint16_t tmp_state = 0; + uint16_t tmp_mode = 0; + uint16_t tmp_sample = 0; + int ret = 0; + + FM_LOG_DBG(D_CMD,"+%s():\n", __func__); + + if(onoff == FM_I2S_ON){ + tmp_state = 0x01; //I2S Frequency tracking on + }else if(onoff == FM_I2S_OFF){ + tmp_state = 0x00; //I2S Frequency tracking off + }else{ + FM_LOG_ERR(D_CMD|D_ALL,"%s():[onoff=%d]\n", __func__, onoff); + ret = -ERR_INVALID_PARA; + goto out; + } + + if(mode == FM_I2S_MASTER){ + tmp_mode = 0x03; //6620 as I2S master + }else if(mode == FM_I2S_SLAVE){ + tmp_mode = 0x0B; //6620 as I2S slave + }else{ + FM_LOG_ERR(D_CMD|D_ALL,"%s():[mode=%d]\n", __func__, mode); + ret = -ERR_INVALID_PARA; + goto out; + } + + if(sample == FM_I2S_32K){ + tmp_sample = 0x0000; //6620 I2S 32KHz sample rate + }else if(sample == FM_I2S_44K){ + tmp_sample = 0x0800; //6620 I2S 44.1KHz sample rate + }else if(sample == FM_I2S_48K){ + tmp_sample = 0x1000; //6620 I2S 48KHz sample rate + }else{ + FM_LOG_ERR(D_CMD|D_ALL,"%s():[sample=%d]\n", __func__, sample); + ret = -ERR_INVALID_PARA; + goto out; + } + if((ret = MT6620_set_bits(0x5F, tmp_sample, 0xE7FF))) + goto out; + if((ret = MT6620_write(0x9B, tmp_mode))) + goto out; + if((ret = MT6620_write(0x56, tmp_state))) + goto out; + + FM_LOG_NTC(D_CMD,"[onoff=%s][mode=%s][sample=%d](0)33KHz,(1)44.1KHz,(2)48KHz\n", + (onoff == FM_I2S_ON) ? "On" : "Off", + (mode == FM_I2S_MASTER) ? "Master" : "Slave", + sample); + +out: + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +static int MT6620_FMOverBT(int enable) +{ + int ret = 0; + static uint16_t state = 0; + static uint16_t mode = 0; + static uint16_t sample = 0; + static uint16_t inited = false; + + FM_LOG_DBG(D_CMD,"+%s():\n", __func__); + if(inited == false){ + // record priv val + if((ret = MT6620_read(0x56, &state))) + goto out; + if((ret = MT6620_read(0x9B, &mode))) + goto out; + if((ret = MT6620_read(0x5F, &sample))) + goto out; + inited = true; + FM_LOG_NTC(D_MAIN,"init, record priv seetings\n"); + } + + if(enable == TRUE){ + //disable analog output when FM over BT + if((ret = MT6620_set_bits(0x3A, 0, MASK(2)))) + goto out; + //set FM over BT + if((ret = MT6620_write(0x56, 0x0001))) + goto out; + if((ret = MT6620_write(0x9B, 0x000b))) + goto out; + if((ret = MT6620_write(0x5F, 0x1175))) + goto out; + FM_LOG_NTC(D_MAIN,"set FM via BT controller\n"); + }else if(enable == FALSE){ + //enable analog output when FM normal mode + if((ret = MT6620_set_bits(0x3A, BITn(2), MASK(2)))) + goto out; + //recover to priv val + if((ret = MT6620_write(0x56, state))) + goto out; + if((ret = MT6620_write(0x9B, mode))) + goto out; + if((ret = MT6620_write(0x5F, sample))) + goto out; + FM_LOG_NTC(D_MAIN,"set FM via Host\n"); + }else{ + FM_LOG_ERR(D_CMD|D_ALL,"%s()\n", __func__); + ret = -ERR_INVALID_PARA; + goto out; + } +out: + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +static int MT6620_ANA_SWITCH(int antenna) +{ + int ret = 0; + + FM_LOG_DBG(D_CMD,"+%s():\n", __func__); + FM_LOG_NTC(D_CMD,"Switch to %s atenna\n", (antenna == FM_LONG_ANA) ? "Long" : "Short"); + if(antenna == FM_LONG_ANA){ + //Long Antenna RSSI threshold, 0xE0 D0~D9 + if((ret = MT6620_write(0xE0, ((0xA301 & 0xFC00) | (FMR_RSSI_TH_LONG & 0x03FF))))) + goto out; + //Turn on Short Antenna LNA and Off TR Switch + if((ret = MT6620_write(0x04, 0x0142))) + goto out; + //Turn off the Short Antenna Capbank biasing + if((ret = MT6620_write(0x05, 0x00E7))) + goto out; + //Turn off the Short Antenna Capbank biasing + if((ret = MT6620_write(0x26, 0x0004))) + goto out; + //Disable concurrent calibration for VCO and SCAL + if((ret = MT6620_write(0x2E, 0x0008))) + goto out; + }else if(antenna == FM_SHORT_ANA){ + //Short Antenna RSSI threshold, 0xE0 D0~D9 + if((ret = MT6620_write(0xE0, ((0xA2E0 & 0xFC00) | (FMR_RSSI_TH_SHORT & 0x03FF))))) + goto out; + //Turn on Short Antenna LNA and TR Switch + if((ret = MT6620_write(0x04, 0x0145))) + goto out; + //Turn on the Short Antenna Capbank biasing + if((ret = MT6620_write(0x05, 0x00FF))) + goto out; + //Turn on the Short Antenna Capbank biasing + if((ret = MT6620_write(0x26, 0x0024))) + goto out; + //Enable concurrent calibration for VCO and SCAL + if((ret = MT6620_write(0x2E, 0x0000))) + goto out; + }else{ + FM_LOG_ERR(D_CMD|D_ALL,"%s()\n", __func__); + ret = -ERR_INVALID_PARA; + goto out; + } +out: + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +#ifdef FMDEBUG +static int MT6620_dump_reg(void) +{ + int i; + int ret = 0; + uint16_t val; + + FM_LOG_DBG(D_CMD,"+%s():\n", __func__); + + if((ret = MT6620_write(FM_MAIN_PGSEL, 0x0001))) + goto out; + for (i = 0; i < MT6620_SCANTBL_SIZE; i++){ + val = 0; + ret = MT6620_read(FM_MAIN_BITMAP0+i, &val); + if (ret == 0){ + FM_LOG_DBG(D_CMD,"%2d\t%04x\n", i, val); + }else{ + FM_LOG_DBG(D_CMD|D_ALL,"%2d\tXXXX\n", i); + goto out; + } + } + ret = MT6620_write(FM_MAIN_PGSEL, 0x0); + +out: + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} +#endif // FMDEBUG + +static int MT6620_GetMonoStereo(uint16_t *pMonoStereo) +{ + uint16_t tmp_reg; + int ret = 0; + + FM_LOG_DBG(D_CMD,"+%s():\n", __func__); + + if((ret = MT6620_write(FM_MAIN_PGSEL, 0x01))) + goto out; + + if((ret = MT6620_read(0xF8, &tmp_reg))) + goto out; + + if((ret = MT6620_write(FM_MAIN_PGSEL, 0x0))) + goto out; + + tmp_reg = (tmp_reg&0x400)>>10; + if(!tmp_reg){ + tmp_reg = 1; + }else{ + tmp_reg = 0; + } + *pMonoStereo = tmp_reg;//0:stereo, 1:mono + FM_LOG_DBG(D_CMD,"[MonoStereo=%d]\n", *pMonoStereo); + +out: + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +/* + * MT6620_SetMonoStereo + * Force set to stero/mono mode + * @MonoStereo -- 0, auto; 1, force mono + * If success, return 0; else error code + */ +static int MT6620_SetMonoStereo(int MonoStereo) +{ + uint16_t tmp_reg; + int ret = 0; + + if((ret = MT6620_write(FM_MAIN_PGSEL, FM_PG1))) + goto out; + + tmp_reg = MonoStereo ? BITn(1) : 0; //MonoStereo, 1: force mono; 0:auto + if((ret = MT6620_set_bits(FM_STEROMONO_CTR, tmp_reg, MASK(1))))//set E0 D1=0 + goto out; + + if((ret = MT6620_write(FM_MAIN_PGSEL, FM_PG0))) + goto out; + + FM_LOG_DBG(D_CMD,"set to %s\n", MonoStereo ? "auto" : "force mono"); + +out: + return ret; +} + +static int MT6620_GetCapArray(int *caparray) +{ + uint16_t tmp_reg; + int ret = 0; + + FM_LOG_DBG(D_CMD,"+%s():\n", __func__); + + if((ret = MT6620_read(0x26, &tmp_reg))) + goto out; + + *caparray = (int)tmp_reg; + FM_LOG_DBG(D_CMD,"[caparray=%d]\n", *caparray); + +out: + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +static int MT6620_GetCurPamd(uint16_t *pPamdLevl) +{ + uint16_t tmp_reg; + int ret = 0; + + FM_LOG_DBG(D_CMD,"+%s():\n", __func__); + if((ret = MT6620_read(0xE9, &tmp_reg))) + goto out; + tmp_reg &= 0x00FF; + /*PA=PAMD + *If PA>511 then PAMD(dB)= (PA-1024)/16*6, + * else PAMD(dB)=PA/16*6 + */ + *pPamdLevl = (tmp_reg>127) ? ((256-tmp_reg)*6/16):0; + +out: + FM_LOG_DBG(D_CMD,"[PamdLevl=%d]\n", (int)*pPamdLevl); + return ret; +} + +static int MT6620_em_test(uint16_t group_idx, uint16_t item_idx, uint32_t item_value) +{ + int ret = 0; + + FM_LOG_DBG(D_CMD,"+%s():[group_idx=%d],[item_idx=%d],[item_value=%d]\n", + __func__, group_idx, item_idx, item_value); + + switch (group_idx){ + case mono: + if((ret = MT6620_write(FM_MAIN_PGSEL, 0x01))) + goto out; + + if(item_value == 1){ + if((ret = MT6620_set_bits(0xE0, 0x02, 0xFFFF))) + goto out; + }else{ + if((ret = MT6620_set_bits(0xE0, 0x0, 0xFFFD))) + goto out; + } + if((ret = MT6620_write(FM_MAIN_PGSEL, 0x0))) + goto out; + break; + case stereo: + if((ret = MT6620_write(FM_MAIN_PGSEL, 0x01))) + goto out; + if(item_value == 0){ + if((ret = MT6620_set_bits(0xE0, 0x0, 0xFFFD))) + goto out; + }else{ + switch (item_idx){ + case Sblend_ON: + if((ret = MT6620_set_bits(0xD8, item_idx<<15, 0x7FFF))) + goto out; + break; + case Sblend_OFF: + if((ret = MT6620_set_bits(0xD8, 0, 0x7FFF))) + goto out; + break; + } + } + if((ret = MT6620_write(FM_MAIN_PGSEL, 0x0))) + goto out; + break; + case RSSI_threshold: + if((ret = MT6620_set_bits(0xe0, item_value, 0xFC00))) + goto out; + break; + case HCC_Enable: + if((ret = MT6620_write(FM_MAIN_PGSEL, 0x01))) + goto out; + if(item_idx){ + if((ret = MT6620_set_bits(0xCF, 0x10, 0xFFFF))) + goto out; + }else{ + if((ret = MT6620_set_bits(0xCF, 0x0, 0xFFEF))) + goto out; + } + if((ret = MT6620_write(FM_MAIN_PGSEL, 0x0))) + goto out; + break; + case PAMD_threshold: + if((ret = MT6620_set_bits(0xE1, item_value, 0xFF00))) + goto out; + break; + case Softmute_Enable: + if((ret = MT6620_write(FM_MAIN_PGSEL, 0x01))) + goto out; + if(item_idx){ + if((ret = MT6620_set_bits(0xCF, 0x0020, 0xFFFF))) //1:CF[5] = 1 + goto out; + }else{ + if((ret = MT6620_set_bits(0xCF, 0x0000, 0xFFDF))) //1:CF[5] = 0 + goto out; + } + if((ret = MT6620_write(FM_MAIN_PGSEL, 0x0))) + goto out; + break; + case De_emphasis: + if((ret = MT6620_write(FM_MAIN_PGSEL, 0x01))) + goto out; + if(item_idx == 2){ + if((ret = MT6620_set_bits(0xd4, 0x2000, 0xCFFF))) + goto out; + }else if(item_idx == 1){ + if((ret = MT6620_set_bits(0xd4, 0x1000, 0xCFFF))) + goto out; + }else if(item_idx == 0){ + if((ret = MT6620_set_bits(0xd4, 0x0000, 0xCFFF))) + goto out; + } + if((ret = MT6620_write(FM_MAIN_PGSEL, 0x0))) + goto out; + break; + case HL_Side: + if(item_idx == 2){ + //H-Side + if((ret = MT6620_set_bits(0xCB, 0x11, 0xFFFE))) + goto out; + if((ret = MT6620_set_bits(0xF, 0x0400, 0xFBFF))) + goto out; + }else if(item_idx == 1){ + //L-Side + if((ret = MT6620_set_bits(0xCB, 0x10, 0xFFFE))) + goto out; + if((ret = MT6620_set_bits(0xF, 0x0, 0xFBFF))) + goto out; + } + break; + + case Dynamic_Limiter: + if((ret = MT6620_write(FM_MAIN_PGSEL, 0x01))) + goto out; + if(item_idx){ + if((ret = MT6620_set_bits(0xFA, 0x0, 0xFFF7))) + goto out; + }else{ + if((ret = MT6620_set_bits(0xFA, 0x08, 0xFFF7))) + goto out; + } + if((ret = MT6620_write(FM_MAIN_PGSEL, 0x0))) + goto out; + break; + + case Softmute_Rate: + if((ret = MT6620_write(FM_MAIN_PGSEL, 0x01))) + goto out; + if((ret = MT6620_set_bits(0xc8, item_value<<8, 0x80FF))) + goto out; + if((ret = MT6620_write(FM_MAIN_PGSEL, 0x0))) + goto out; + break; + + case AFC_Enable: + if (item_idx){ + if((ret = MT6620_set_bits(0x63, 0x0400, 0xFBFF))) + goto out; + }else{ + if((ret = MT6620_set_bits(0x63, 0x0, 0xFBFF))) + goto out; + } + break; + +#if 0 + case Softmute_Level: + MT6620_write(FM_MAIN_PGSEL, 0x01); + if(item_value > 0x24) + item_value = 0x24; + MT6620_set_bits(0xD1, item_value, 0xFFC0); + MT6620_write(FM_MAIN_PGSEL, 0x0); + break; +#endif + case Analog_Volume: + if((ret = MT6620_set_bits(0x9C, item_value<<8, 0xC0FF))) + goto out; + break; + + default: + break; + } + +out: + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +static int MT6620_Rds_Tx_Enable(uint8_t enable) +{ + int ret = 0; + + FM_LOG_NTC(D_CMD,"+%s(): %s\n", __func__, enable ? "Enable" : "Disable"); + + if(enable == 1){ + if((ret = MT6620_write(0x9F, 0x0000))) + goto out; + if((ret = MT6620_write(0xAB, 0x3872))) + goto out; + if((ret = MT6620_write(0xAC, 0x3B3A))) + goto out; + if((ret = MT6620_write(0xAD, 0x0113))) + goto out; + if((ret = MT6620_write(0xAE, 0x03B2))) + goto out; + if((ret = MT6620_write(0xAF, 0x0001))) + goto out; + if((ret = MT6620_write(0xB1, 0x63EB))) + goto out; + if((ret = MT6620_write(0xF4, 0x0020))) + goto out; + if((ret = MT6620_write(0xF5, 0x3222))) + goto out; + }else{ + if((ret = MT6620_write(0x9F, 0x0000))) + goto out; + if((ret = MT6620_write(0xAB, 0x39B6))) + goto out; + if((ret = MT6620_write(0xAC, 0x3C3E))) + goto out; + if((ret = MT6620_write(0xAD, 0x0000))) + goto out; + if((ret = MT6620_write(0xAE, 0x03C2))) + goto out; + if((ret = MT6620_write(0xAF, 0x0001))) + goto out; + if((ret = MT6620_write(0xF4, 0x0020))) + goto out; + if((ret = MT6620_write(0xF5, 0xBF16))) + goto out; + ret = MT6620_write(0xB1, 0x623D); + } + +out: + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +static int MT6620_Rds_Tx(uint16_t pi, uint16_t *ps, uint16_t *other_rds, uint8_t other_rds_cnt) +{ + int ret = 0; + uint16_t pkt_size = 0; + + FM_LOG_DBG(D_CMD,"+%s():PI=0x%04x, PS=0x%04x/0x%04x/0x%04x, other_rds_cnt=%d \n", + __func__, pi, ps[0], ps[1], ps[2], other_rds_cnt); + FM_LOG_INF(D_CMD,"-fm_cmd_mutex\n"); + if (down_interruptible(&fm_cmd_mutex)){ + FM_LOG_ERR(D_CMD|D_ALL,"%s():get mutex failed\n", __func__); + ret = -ERR_GET_MUTEX; + goto out1; + } + + if(tx_buf == NULL){ + FM_LOG_ERR(D_CMD|D_ALL,"%s():invalid tx_buf\n", __func__); + ret = -ERR_INVALID_BUF; + goto out; + } + memset(tx_buf, 0, TX_BUF_SIZE); + pkt_size = mt6620_rds_tx(tx_buf, TX_BUF_SIZE, pi, ps, other_rds, other_rds_cnt); + ret = fm_send_wait_timeout(tx_buf, pkt_size, + FLAG_RDS_TX, SW_RETRY_CNT, RDS_TX_TIMEOUT); + +out: + up(&fm_cmd_mutex); + FM_LOG_INF(D_CMD,"+fm_cmd_mutex\n"); + +out1: + FM_LOG_DBG(D_CMD,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +static int fm_enable_rds_BlerCheck(struct fm *fm) +{ + int ret = 0; + ret = down_interruptible(&fm_timer_mutex); + if(ret){ + FM_LOG_ERR(D_MAIN,"down fm_timer_mutex failed[ret=%d]\n", ret); + goto out; + } + timer_sys.rds_reset_en = FM_RDS_RST_ENABLE; + FM_LOG_DBG(D_TIMER,"enable RDS reset func\n"); + up(&fm_timer_mutex); + +out: + return ret; +} + +static int fm_disable_rds_BlerCheck() +{ + int ret = 0; + ret = down_interruptible(&fm_timer_mutex); + if(ret){ + FM_LOG_ERR(D_MAIN,"down fm_timer_mutex failed[ret=%d]\n", ret); + goto out; + } + timer_sys.rds_reset_en = FM_RDS_RST_DISABLE; + FM_LOG_DBG(D_TIMER,"disable RDS reset func\n"); + up(&fm_timer_mutex); + +out: + return ret; +} + +/* +************************************************************************************ +Function: fm_get_gps_rtc_info() + +Description: get GPS RTC drift info, and this function should not block + +Date: 2011/04/10 + +Return Value: success:0, failed: error coe +************************************************************************************ +*/ +static int fm_get_gps_rtc_info(struct fm_gps_rtc_info *dst, struct fm_gps_rtc_info *src) +{ + int ret = 0; + int retry_cnt = 0; + //struct fm *fm = (struct fm*)fm_cb; + + FMR_ASSERT(src); + FMR_ASSERT(dst); + + if(src->retryCnt > 0){ + dst->retryCnt = src->retryCnt; + FM_LOG_DBG(D_MAIN,"%s, new [retryCnt=%d]\n", __func__, dst->retryCnt); + } + if(src->ageThd > 0){ + dst->ageThd = src->ageThd; + FM_LOG_DBG(D_MAIN,"%s, new [ageThd=%d]\n", __func__, dst->ageThd); + } + if(src->driftThd > 0){ + dst->driftThd = src->driftThd; + FM_LOG_DBG(D_MAIN,"%s, new [driftThd=%d]\n", __func__, dst->driftThd); + } + if(src->tvThd.tv_sec > 0){ + dst->tvThd.tv_sec = src->tvThd.tv_sec; + FM_LOG_DBG(D_MAIN,"%s, new [tvThd=%d]\n", __func__, (int)dst->tvThd.tv_sec); + } + + while(down_trylock(&fm_rtc_mutex)){ + FM_LOG_WAR(D_MAIN,"down_trylock failed\n"); + if(++retry_cnt < dst->retryCnt){ + FM_LOG_WAR(D_MAIN,"[retryCnt=%d]\n", retry_cnt); + msleep_interruptible(50); + continue; + }else{ + FM_LOG_WAR(D_MAIN,"down_trylock retry failed\n"); + ret = -EFAULT; + goto out; + } + } + + dst->age = src->age; + dst->drift = src->drift; + dst->stamp = jiffies; //get curren time stamp + dst->flag = FM_GPS_RTC_INFO_NEW; + + up(&fm_rtc_mutex); + + /* + //send event to info fm_tx_rtc_ctrl_work + if(timer_sys.tx_rtc_ctrl_en == FM_TX_RTC_CTRL_ENABLE){ + FM_LOG_DBG(D_TIMER,"fm_tx_rtc_ctrl_work, ticks:%d\n", jiffies_to_msecs(jiffies)); + queue_work(fm->fm_timer_workqueue, &fm->fm_tx_rtc_ctrl_work); + } + */ + +out: + return ret; +} +static int fm_hw_reset(void) +{ + int ret = 0; + FM_LOG_DBG(D_MAIN,"+%s():\n", __func__); + + //check if we are resetting + if(subsys_rst_state != FM_SUBSYS_RST_OFF){ + FM_LOG_NTC(D_MAIN, "FM subsys resetting is ongoing!!!\n"); + goto out; + } + + //set rst state start + subsys_rst_state = FM_SUBSYS_RST_START; + + //disable FM timer + timer_sys.onoff = FM_TIMER_SYS_OFF; + + //wake up waiting wq, all flag set true, force all operations exit + spin_lock(&flag_lock); + flag = 0xFFFFFFFF; + spin_unlock(&flag_lock); + wake_up(&fm_wq); + + //FM subsys OFF + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_off(WMTDRV_TYPE_FM)){ + FM_LOG_ERR(D_MAIN,"WMT turn off FM fail!\n"); + ret = -ERR_STP; + }else{ + FM_LOG_NTC(D_MAIN,"WMT turn off FM OK!\n"); + } + + //change FM pwr state + fm_cb->powerup = FM_PWR_OFF; + fm_cb->chipon = false; + mtk_wcn_stp_register_event_cb(FM_TASK_INDX, NULL); + + //wake up recover work if need + queue_work(fm_cb->fm_timer_workqueue, &fm_cb->fm_subsys_recover_work); + +out: + FM_LOG_DBG(D_MAIN,"-%s():[ret=%d]\n", __func__, ret); + return ret; +} + + +//fm timer will timeout every sencod +static void fm_timer_func(unsigned long data) +{ + int ret = 0; + struct fm *fm = (struct fm*)fm_cb; + struct fm_timer_sys *timer = &timer_sys; + int vco_cycle = 1; + + if(!fm) + goto out; + if(!timer) + goto out; + //FM_LOG_DBG(D_TIMER,"+%s():\n", __func__); + ret = down_interruptible(&fm_timer_mutex); + if(ret){ + FM_LOG_ERR(D_MAIN,"down fm_timer_mutex failed[ret=%d]\n", ret); + goto out; + } + if (timer->onoff == FM_TIMER_SYS_OFF){ + up(&fm_timer_mutex); + goto out; + } + timer->count++; + + //FM_LOG_DBG(D_TIMER,"+T:%d\n", jiffies_to_msecs(jiffies)); + //schedule RDS reset work if need + if(g_fm_config.rdsrst < 1){ + FM_LOG_WAR(D_TIMER,"rds rst time err\n"); + g_fm_config.rdsrst = FM_RDS_RST_INVAL_MIN; + } + if((timer->rds_reset_en == FM_RDS_RST_ENABLE) && (timer->count%g_fm_config.rdsrst == 0)){ + FM_LOG_DBG(D_TIMER,"fm_rds_reset_work, ticks:%d\n", jiffies_to_msecs(jiffies)); + queue_work(fm->fm_timer_workqueue, &fm->fm_rds_reset_work); + } + //schedule tx pwr ctrl work if need + if(g_fm_config.txpwrctl < 1){ + FM_LOG_WAR(D_TIMER,"tx power ctl time err\n"); + g_fm_config.txpwrctl = FM_TX_PWR_CTRL_INVAL_MIN; + } + if((timer->tx_pwr_ctrl_en == FM_TX_PWR_CTRL_ENABLE) && (timer->count%g_fm_config.txpwrctl == 0)){ + FM_LOG_DBG(D_TIMER,"fm_tx_power_ctrl_work, ticks:%d\n", jiffies_to_msecs(jiffies)); + queue_work(fm->fm_timer_workqueue, &fm->fm_tx_power_ctrl_work); + } + /* + //schedule tx RTC ctrl work if need + if((timer->tx_rtc_ctrl_en == FM_TX_RTC_CTRL_ENABLE)&& (timer->count%FM_TX_RTC_CTRL_INTERVAL == 0)){ + FM_LOG_DBG(D_TIMER,"fm_tx_rtc_ctrl_work, ticks:%d\n", jiffies_to_msecs(jiffies)); + queue_work(fm->fm_timer_workqueue, &fm->fm_tx_rtc_ctrl_work); + }*/ + //schedule tx desense with wifi/bt work if need + if(g_fm_config.vcooff < 1){ + FM_LOG_WAR(D_TIMER,"vco tracking time err\n"); + g_fm_config.vcooff = FM_TX_VCO_OFF_MIN; + } + vco_cycle = g_fm_config.vcooff + g_fm_config.vcoon/1000; + if((timer->tx_desense_en == FM_TX_DESENSE_ENABLE) && (timer->count%vco_cycle == 0)){ + FM_LOG_DBG(D_TIMER,"fm_tx_desense_wifi_work, ticks:%d\n", jiffies_to_msecs(jiffies)); + queue_work(fm->fm_timer_workqueue, &fm->fm_tx_desense_wifi_work); + } + up(&fm_timer_mutex); + + //update timer + if(g_fm_config.timer < 1000){ + FM_LOG_WAR(D_TIMER,"timersys time err\n"); + g_fm_config.timer = FM_TIMER_TIMEOUT_MIN; + } + mod_timer(&fm_timer, jiffies + g_fm_config.timer/(1000/HZ)); + FM_LOG_DBG(D_TIMER,"-T:%d,mod timer\n", jiffies_to_msecs(jiffies)); + +out: + //FM_LOG_DBG(D_TIMER,"-%s():[onoff=%d]\n", __func__, timer->onoff); + return; +} +static void fm_tx_rtc_ctrl_worker_func(struct work_struct *work) +{ + int ret = 0; + int ctrl = 0; + struct fm_gps_rtc_info rtcInfo; + //struct timeval curTime; + //struct fm *fm = (struct fm*)fm_cb; + unsigned long curTime = 0; + + FM_LOG_DBG(D_TIMER,"+%s():\n", __func__); + + ret = down_interruptible(&fm_rtc_mutex); + if(ret){ + FM_LOG_ERR(D_MAIN,"down fm_rtc_mutex failed[ret=%d]\n", ret); + goto out; + } + + if(gps_rtc_info.flag == FM_GPS_RTC_INFO_NEW){ + memcpy(&rtcInfo, &gps_rtc_info, sizeof(struct fm_gps_rtc_info)); + gps_rtc_info.flag = FM_GPS_RTC_INFO_OLD; + up(&fm_rtc_mutex); + }else{ + FM_LOG_DBG(D_MAIN,"there's no new rtc drift info\n"); + up(&fm_rtc_mutex); + goto out; + } + + if(rtcInfo.age > rtcInfo.ageThd){ + FM_LOG_WAR(D_MAIN,"age over it's threshlod\n"); + goto out; + } + if((rtcInfo.drift <= rtcInfo.driftThd) && (rtcInfo.drift >= -rtcInfo.driftThd)){ + FM_LOG_WAR(D_MAIN,"drift over it's MIN threshlod\n"); + goto out; + } + + if(rtcInfo.drift > FM_GPS_RTC_DRIFT_MAX){ + FM_LOG_WAR(D_MAIN,"drift over it's +MAX threshlod\n"); + rtcInfo.drift = FM_GPS_RTC_DRIFT_MAX; + goto out; + }else if(rtcInfo.drift < -FM_GPS_RTC_DRIFT_MAX){ + FM_LOG_WAR(D_MAIN,"drift over it's -MAX threshlod\n"); + rtcInfo.drift = -FM_GPS_RTC_DRIFT_MAX; + goto out; + } + /* + //get current time + do_gettimeofday(&curTime); + if((curTime.tv_sec - rtcInfo.tv.tv_sec) > rtcInfo.tvThd.tv_sec){ + FM_LOG_WAR(D_MAIN,"time diff over it's threshlod\n"); + goto out; + }*/ + curTime = jiffies; + if(((long)curTime - (long)rtcInfo.stamp)/HZ > rtcInfo.tvThd.tv_sec){ + FM_LOG_WAR(D_MAIN,"time diff over it's threshlod\n"); + goto out; + } + if(priv.state == INITED){ + FM_LOG_INF(D_TIMER,"%s, RTC_drift_ctrl[0x%08x]\n", __func__, (unsigned int)priv.priv_tbl.rtc_drift_ctrl); + if(priv.priv_tbl.rtc_drift_ctrl != NULL){ + ctrl = rtcInfo.drift; + if((ret = priv.priv_tbl.rtc_drift_ctrl(_current_frequency, &ctrl))) + goto out; + } + } +out: + FM_LOG_DBG(D_TIMER,"-%s():[T=%d]\n", __func__, jiffies_to_msecs(jiffies)); + return; +} + +static void fm_tx_power_ctrl_worker_func(struct work_struct *work) +{ + int ret = 0; + int ctrl = 0; + struct fm *fm = (struct fm*)fm_cb; + + FM_LOG_DBG(D_TIMER,"+%s():\n", __func__); + + if(down_interruptible(&fm_rxtx_mutex)){ + FM_LOG_ERR(D_TIMER, "%s(): get rx/tx mutex failed\n", __func__); + return; + } + + if(!fm){ + FM_LOG_ERR(D_TIMER,"err, [fm=0x%08x]\n", (int)fm); + goto out; + } + + if(fm->powerup != FM_PWR_TX_ON){ + FM_LOG_NTC(D_TIMER,"FM is not on TX mode\n"); + goto out; + } + + if(priv.state == INITED){ + if(priv.priv_tbl.tx_pwr_ctrl != NULL){ + ctrl = fm->tx_pwr; + FM_LOG_INF(D_TIMER,"tx pwr %ddb\n", ctrl); + if((ret = priv.priv_tbl.tx_pwr_ctrl(_current_frequency, &ctrl))) + goto out; + } + } + +out: + up(&fm_rxtx_mutex); + FM_LOG_DBG(D_TIMER,"-%s():[T=%d]\n", __func__, jiffies_to_msecs(jiffies)); + return; +} + +static void fm_tx_desense_wifi_worker_func(struct work_struct *work) +{ + int ret = 0; + int ctrl = 0; + struct fm *fm = (struct fm*)fm_cb; + + FM_LOG_DBG(D_TIMER,"+%s():\n", __func__); + + if(down_interruptible(&fm_rxtx_mutex)){ + FM_LOG_ERR(D_TIMER, "%s(): get rx/tx mutex failed\n", __func__); + return; + } + + if(!fm){ + FM_LOG_ERR(D_TIMER,"err, [fm=0x%08x]\n", (int)fm); + goto out; + } + + if(fm->powerup != FM_PWR_TX_ON){ + FM_LOG_NTC(D_TIMER,"FM is not on TX mode\n"); + goto out; + } + + fm_tx_rtc_ctrl_worker_func(work); + + ctrl = g_fm_config.vcoon; + if(priv.state == INITED){ + FM_LOG_INF(D_TIMER,"%s, tx_desense_wifi[0x%08x]\n", __func__, (unsigned int)priv.priv_tbl.tx_desense_wifi); + if(priv.priv_tbl.tx_desense_wifi != NULL){ + if((ret = priv.priv_tbl.tx_desense_wifi(_current_frequency, &ctrl))) + goto out; + } + } + +out: + up(&fm_rxtx_mutex); + FM_LOG_DBG(D_TIMER,"-%s():[T=%d]\n", __func__, jiffies_to_msecs(jiffies)); + return; +} + +static void fm_rds_reset_worker_func(struct work_struct *work) +{ + struct fm *fm = fm_cb; + int ret = 0; + + FM_LOG_DBG(D_TIMER,"+%s():[T=%d]\n", __func__, jiffies_to_msecs(jiffies)); + + if(down_interruptible(&fm_rxtx_mutex)){ + FM_LOG_ERR(D_TIMER, "%s(): get rx/tx mutex failed\n", __func__); + return; + } + + if(!fm){ + FM_LOG_ERR(D_TIMER,"err, [fm=0x%08x]\n", (int)fm); + goto out; + } + + if(fm->powerup != FM_PWR_RX_ON){ + FM_LOG_NTC(D_TIMER,"FM is not on RX mode\n"); + goto out; + } + + FM_LOG_INF(D_TIMER,"%s():-fm_read_mutex\n", __func__); + if (down_interruptible(&fm_read_mutex)){ + FM_LOG_ERR(D_ALL,"fm_rds_reset_worker_func can't get mutex"); + goto out; + } + + ret = MT6620_RDS_BlerCheck(fm); + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_TIMER|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + up(&fm_read_mutex); + FM_LOG_INF(D_TIMER,"%s():+fm_read_mutex\n", __func__); + +out: + up(&fm_rxtx_mutex); + FM_LOG_DBG(D_TIMER,"-%s():[T=%d]\n", __func__, jiffies_to_msecs(jiffies)); + return; +} + +void stp_rx_event_cb(void) +{ + struct fm *fm = fm_cb; + static int cnt1 = 0; + queue_work(fm->fm_workqueue, &fm->fm_rx_work); + FM_LOG_DBG(D_MAIN,"cnt1=%d\n", ++cnt1); + FM_LOG_DBG(D_MAIN,"%s()\n", __func__); +} + +static void fm_wholechip_rst_cb(ENUM_WMTDRV_TYPE_T src, + ENUM_WMTDRV_TYPE_T dst, + ENUM_WMTMSG_TYPE_T type, + void *buf, + unsigned int sz) +{ + int ret = 0; + //To handle reset procedure please + ENUM_WMTRSTMSG_TYPE_T rst_msg; + + FM_LOG_DBG(D_MAIN,"+%s()\n", __func__); + if(sz <= sizeof(ENUM_WMTRSTMSG_TYPE_T)){ + memcpy((char *)&rst_msg, (char *)buf, sz); + FM_LOG_DBG(D_MAIN, "[src=%d], [dst=%d], [type=%d], [buf=0x%x], [sz=%d], [max=%d]\n", src, dst, type, rst_msg, sz, WMTRSTMSG_RESET_MAX); + if((src==WMTDRV_TYPE_WMT) && (dst == WMTDRV_TYPE_FM) && (type == WMTMSG_TYPE_RESET)){ + if(rst_msg == WMTRSTMSG_RESET_START){ + FM_LOG_NTC(D_MAIN, "FM restart start!\n"); + /*reset_start message handling*/ + //check if we are resetting + if(chip_rst_state != FM_WHOLECHIP_RST_OFF){ + FM_LOG_NTC(D_MAIN, "FM resetting is ongoing!!!\n"); + return; + } + + //set rst state start + chip_rst_state = FM_WHOLECHIP_RST_START; + + //Record current context + + //disable FM timer + ret = down_interruptible(&fm_timer_mutex); + if(ret){ + FM_LOG_WAR(D_MAIN, "down fm_timer_mutex failed!\n"); + //FIX ME, how to handle this case? + return; + }else{ + timer_sys.onoff = FM_TIMER_SYS_OFF; + up(&fm_timer_mutex); + } + + //wake up waiting wq, all flag set true, force all operations exit + spin_lock(&flag_lock); + flag = 0xFFFFFFFF; + spin_unlock(&flag_lock); + wake_up(&fm_wq); + + //change FM pwr state + ret = down_interruptible(&fm_ops_mutex); + if(ret){ + FM_LOG_WAR(D_MAIN, "down fm_ops_mutex failed!\n"); + //FIX ME, how to handle this case? + return; + }else{ + fm_cb->powerup = FM_PWR_OFF; + fm_cb->chipon = false; + up(&fm_ops_mutex); + } + + //Unregister FM main Callback + mtk_wcn_stp_register_event_cb(FM_TASK_INDX, NULL); + } else if(rst_msg == WMTRSTMSG_RESET_END){ + FM_LOG_NTC(D_MAIN, "FM restart end!\n"); + /*reset_end message handling*/ + //check if we have get start event + if(chip_rst_state != FM_WHOLECHIP_RST_START){ + FM_LOG_NTC(D_MAIN, "Wrong event, there's no start!!!\n"); + return; + } + + //set all event flag false + spin_lock(&flag_lock); + flag = 0x0; + spin_unlock(&flag_lock); + + //wake up recover work if need + queue_work(fm_cb->fm_timer_workqueue, &fm_cb->fm_rst_recover_work); + + //set rst state end + chip_rst_state = FM_WHOLECHIP_RST_END; + } + } + } else { + /*message format invalid*/ + FM_LOG_WAR(D_MAIN, "message format invalid!\n"); + } +} + +static int fm_recover_func(struct fm *fm, struct fm_context *cxt) +{ + int ret = 0; + struct fm_tune_parm parm; + + FM_LOG_NTC(D_MAIN,"+%s():\n", __func__); + if(cxt->ref < 1){ + FM_LOG_NTC(D_MAIN,"FM not in use, no need recover\n"); + goto out; + }else{ + //FM func on + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_FM)){ + FM_LOG_WAR(D_MAIN, "FM mtk_wcn_wmt_func_on failed!\n"); + //FIX ME, how to handle this case? + goto out; + } + + //change FM Subsys state + ret = down_interruptible(&fm_ops_mutex); + if(ret){ + FM_LOG_WAR(D_MAIN, "down fm_ops_mutex failed!\n"); + //FIX ME, how to handle this case? + goto out; + }else{ + fm->chipon = true; + up(&fm_ops_mutex); + } + + //Register FM main Callback + mtk_wcn_stp_register_event_cb(FM_TASK_INDX, stp_rx_event_cb); + + //Check stp ready after turn on function + if(FALSE == mtk_wcn_stp_is_ready()){ + FM_LOG_ERR(D_ALL,"6620 stp is not ready, please retry later\n"); + goto out; + } + + //power on FM, recover the context + switch(cxt->powerup){ + case FM_PWR_RX_ON: + fm_powerdown(fm, FM_RX); + //power on FM RX + parm.band = fm->band; + parm.freq = cxt->freq; + parm.space = FM_SPACE_100K; + ret = fm_powerup(fm, &parm); + FM_LOG_NTC(D_MAIN, "[band=%d][freq=%d]\n", parm.band, parm.freq); + if(ret){ + FM_LOG_WAR(D_MAIN, "fm_powerup failed!\n"); + //FIX ME, how to handle this case? + goto out; + } + + /*//set FM RX vol + ret = fm_setvol(fm, cxt->rxcxt.vol); + if(ret){ + FM_LOG_WAR(D_MAIN, "fm_setvol failed!\n"); + //FIX ME, how to handle this case? + goto out; + }*/ + //set mute if need + FM_LOG_NTC(D_MAIN, "[rxcxt.mute=%d]\n", cxt->rxcxt.mute); + ret = MT6620_Mute(cxt->rxcxt.mute); + if(ret){ + FM_LOG_WAR(D_MAIN, "MT6620_Mute failed!\n"); + //FIX ME, how to handle this case? + goto out; + } + + //set FM antenna type + FM_LOG_NTC(D_MAIN, "[rxcxt.ana=%d]\n", cxt->rxcxt.ana); + ret = fm_antenna_switch(fm, cxt->rxcxt.ana); + if(ret){ + FM_LOG_WAR(D_MAIN, "fm_antenna_switch failed!\n"); + //FIX ME, how to handle this case? + goto out; + } + + //set FM over bt + FM_LOG_NTC(D_MAIN, "[rxcxt.ViaBt=%d]\n", cxt->rxcxt.ViaBt); + ret = fm_over_bt(fm, cxt->rxcxt.ViaBt); + if(ret){ + FM_LOG_WAR(D_MAIN, "fm_over_bt failed!\n"); + //FIX ME, how to handle this case? + goto out; + } + + //set FM RDS on/off + FM_LOG_NTC(D_MAIN, "[rxcxt.rdsOn=%d]\n", cxt->rxcxt.rdsOn); + cxt->rxcxt.rdsOn = true; //XHC. just for test + if(fm_cxt->rxcxt.rdsOn == true){ + timer_sys.rds_reset_en = FM_RDS_RST_ENABLE; + } + ret = MT6620_RDS_OnOff(fm, cxt->rxcxt.rdsOn); + if(ret){ + FM_LOG_WAR(D_MAIN, "MT6620_RDS_OnOff failed!\n"); + //FIX ME, how to handle this case? + goto out; + } + + //set audio path to I2S +#ifdef FM_DIGITAL_INPUT + mt_combo_audio_ctrl(COMBO_AUDIO_STATE_2); +#endif + break; + case FM_PWR_TX_ON: + fm_powerdown(fm, FM_TX); + parm.band = fm->band; + parm.freq = cxt->freq; + parm.space = FM_SPACE_100K; + ret = fm_powerup_tx(fm, &parm); + if(ret){ + FM_LOG_WAR(D_MAIN, "fm_powerup_tx failed!\n"); + //FIX ME, how to handle this case? + goto out; + } + //set audio path to I2S +#ifdef FM_DIGITAL_OUTPUT + mt_combo_audio_ctrl(COMBO_AUDIO_STATE_2); +#endif + //RDS TX + ret = MT6620_Rds_Tx_Enable(1); + if(ret){ + FM_LOG_WAR(D_MAIN, "MT6620_Rds_Tx_Enable failed!\n"); + //FIX ME, how to handle this case? + goto out; + } + ret = MT6620_Rds_Tx(cxt->txcxt.pi, cxt->txcxt.ps, cxt->txcxt.other_rds, cxt->txcxt.other_rds_cnt); + if(ret){ + FM_LOG_WAR(D_MAIN, "MT6620_Rds_Tx failed!\n"); + //FIX ME, how to handle this case? + goto out; + } + break; + case FM_PWR_OFF: + FM_LOG_WAR(D_MAIN, "fm was pwr down, no need powerup!\n"); + break; + default: + FM_LOG_ERR(D_MAIN, "error para!\n"); + break; + } + } +out: + FM_LOG_NTC(D_MAIN,"-%s():[T=%d]\n", __func__, jiffies_to_msecs(jiffies)); + return ret; +} + +static void fm_rst_recover_worker_func(struct work_struct *work) +{ + int ret = 0; + + FM_LOG_NTC(D_MAIN,"+%s():\n", __func__); + + fm_cxt->ref = fm_cb->ref; + fm_cxt->freq = _current_frequency; + + //set all event flag false + spin_lock(&flag_lock); + flag = 0x0; + spin_unlock(&flag_lock); + ret = fm_recover_func(fm_cb, fm_cxt); + if(ret){ + FM_LOG_ERR(D_MAIN,"fm_recover_func failed\n"); + } + + chip_rst_state = FM_WHOLECHIP_RST_OFF; + FM_LOG_NTC(D_MAIN,"-%s():[T=%d]\n", __func__, jiffies_to_msecs(jiffies)); + return; +} + +static void fm_subsys_recover_worker_func(struct work_struct *work) +{ + int ret = 0; + + FM_LOG_NTC(D_MAIN,"+%s():\n", __func__); + if(chip_rst_state != FM_WHOLECHIP_RST_OFF){ + FM_LOG_WAR(D_MAIN,"FM whole chip resetting\n"); + goto out; + } + fm_cxt->ref = fm_cb->ref; + fm_cxt->freq = _current_frequency; + //set all event flag false + spin_lock(&flag_lock); + flag = 0x0; + spin_unlock(&flag_lock); + ret = fm_recover_func(fm_cb, fm_cxt); + if(ret){ + FM_LOG_ERR(D_MAIN,"fm_recover_func failed\n"); + } + +out: + subsys_rst_state = FM_SUBSYS_RST_OFF; + FM_LOG_NTC(D_MAIN,"-%s():[T=%d]\n", __func__, jiffies_to_msecs(jiffies)); + return; +} + +static void fm_rx_worker_func(struct work_struct *work) +{ + int len; + int i = 0; + static volatile fm_task_parser_state state = FM_TASK_RX_PARSER_PKT_TYPE; + uint8_t opcode = 0; + uint16_t length = 0; + unsigned char ch; + unsigned char rx_buf[RX_BUF_SIZE + 10] = {0}; //the 10 bytes are protect gaps + struct fm *fm = fm_cb; + RDSData_Struct *pstRDSData = fm->pstRDSData; + static int cnt2 = 0; + + FM_LOG_DBG(D_MAIN,"cnt2=%d\n", ++cnt2); + len = mtk_wcn_stp_receive_data(rx_buf, RX_BUF_SIZE, FM_TASK_INDX); + FM_LOG_DBG(D_RX,"+%s():[len=%d],[CMD=0x%02x 0x%02x 0x%02x 0x%02x]\n", __func__, len, rx_buf[0], rx_buf[1], rx_buf[2], rx_buf[3]); + + while (i < len){ + ch = rx_buf[i]; + + switch (state){ + case FM_TASK_RX_PARSER_PKT_TYPE: + if(ch == FM_TASK_EVENT_PKT_TYPE){ + if((i+5) < RX_BUF_SIZE){ + FM_LOG_DBG(D_RX,"0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x \n", rx_buf[i], rx_buf[i+1], rx_buf[i+2], rx_buf[i+3], rx_buf[i+4], rx_buf[i+5]); + }else{ + FM_LOG_DBG(D_RX,"0x%02x 0x%02x\n", rx_buf[i], rx_buf[i+1]); + } + state = FM_TASK_RX_PARSER_OPCODE; + }else{ + FM_LOG_ERR(D_RX,"%s(): event pkt type error (rx_buf[%d] = 0x%02x)\n", __func__, i, ch); + } + i++; + break; + + case FM_TASK_RX_PARSER_OPCODE: + i++; + opcode = ch; + state = FM_TASK_RX_PARSER_PKT_LEN_1; + break; + + case FM_TASK_RX_PARSER_PKT_LEN_1: + i++; + length = ch; + state = FM_TASK_RX_PARSER_PKT_LEN_2; + break; + + case FM_TASK_RX_PARSER_PKT_LEN_2: + i++; + length |= (uint16_t)(ch << 0x8); + if(length > 0){ + state = FM_TASK_RX_PARSER_PKT_PAYLOAD; + }else{ + spin_lock(&flag_lock); + flag |= (1 << opcode); + spin_unlock(&flag_lock); + state = FM_TASK_RX_PARSER_PKT_TYPE; + FM_LOG_DBG(D_RX,"[flag=0x%08x]\n", flag); + wake_up(&fm_wq); + } + break; + + case FM_TASK_RX_PARSER_PKT_PAYLOAD: + switch(opcode){ + case FM_SEEK_OPCODE: + spin_lock(&flag_lock); + flag |= FLAG_SEEK_DONE; + spin_unlock(&flag_lock); + if((i+1) < RX_BUF_SIZE){ + seek_result = (rx_buf[i] + (rx_buf[i+1] << 8)) / 10; + } + FM_LOG_DBG(D_RX,"[flag=0x%08x]\n", flag); + wake_up(&fm_wq); + break; + + case FM_SCAN_OPCODE: + spin_lock(&flag_lock); + flag |= FLAG_SCAN_DONE; + spin_unlock(&flag_lock); + //check if the result data is long enough + if((RX_BUF_SIZE - i) < (sizeof(uint16_t) * MT6620_SCANTBL_SIZE)){ + FM_LOG_ERR(D_RX,"FM_SCAN_OPCODE err, [tblsize=%d],[bufsize=%d]\n", (sizeof(uint16_t) * MT6620_SCANTBL_SIZE), (RX_BUF_SIZE - i)); + wake_up(&fm_wq); + return; + } + memcpy(scan_result, &rx_buf[i], sizeof(uint16_t) * MT6620_SCANTBL_SIZE); + FM_LOG_DBG(D_RX,"[flag=0x%08x]\n", flag); + wake_up(&fm_wq); + break; + + case FSPI_READ_OPCODE: + spin_lock(&flag_lock); + flag |= (1 << opcode); + spin_unlock(&flag_lock); + if((i+1) < RX_BUF_SIZE){ + fspi_rd = (rx_buf[i] + (rx_buf[i+1] << 8)); + } + FM_LOG_DBG(D_RX,"[flag=0x%08x]\n", flag); + wake_up(&fm_wq); + break; + + case RDS_RX_DATA_OPCODE: + spin_lock(&flag_lock); + flag |= (1 << opcode); + spin_unlock(&flag_lock); + FM_LOG_INF(D_RX,"-fm_rds_mutex\n"); + if (down_interruptible(&fm_rds_mutex)){ + FM_LOG_ERR(D_RX,"Handle RDS: down rds mutex failed\n"); + return; + } + rds_rx_size = length; + //check if the rds data is long enough + if((RX_BUF_SIZE - i) < rds_rx_size){ + FM_LOG_ERR(D_RX,"RDS_RX_DATA_OPCODE err, [rdsrxsize=%d],[bufsize=%d]\n", (int)rds_rx_size, (RX_BUF_SIZE - i)); + goto rds_out; + } + memcpy(&rds_rx_result, &rx_buf[i], rds_rx_size); + FM_LOG_DBG(D_RX,"[rds_rx_size=%d]\n", rds_rx_size); + #if 0 //RDS Rx verification + { + int grp; + int j = 4; + unsigned char *ptr = &rx_buf[i]; + + printk("%lu\t", jiffies * 1000 / HZ); + FM_LOG_NTC(D_RX,"%lu\t", jiffies * 1000 / HZ); + for(grp = 0; grp < 6; grp++, j+=12){ + FM_LOG_NTC(D_RX,"%02x%02x%02x%02x%02x%02x%02x%02x\t%02x%02x%02x%02x\t", ptr[j], ptr[j+1], ptr[j+2], ptr[j+3], ptr[j+4], ptr[j+5], ptr[j+6], ptr[j+7], ptr[j+8], ptr[j+9], ptr[j+10], ptr[j+11]); + } + FM_LOG_NTC(D_RX,"\n"); + } + #endif + + /*Handle the RDS data that we get*/ + MT6620_RDS_Eint_Handler(fm, &rds_rx_result, rds_rx_size); +rds_out: + up(&fm_rds_mutex); + FM_LOG_INF(D_RX,"+fm_rds_mutex\n"); + + //loop pstRDSData->event_status then act + //if(pstRDSData->event_status != 0) + if((pstRDSData->event_status != 0) && (pstRDSData->event_status + != RDS_EVENT_AF_LIST)){ + FM_LOG_DBG(D_RX,"Notify user to read, [event:%04x]\n", pstRDSData->event_status); + fm->RDS_Data_ready = true; + wake_up_interruptible(&fm->read_wait); + } + + FM_LOG_DBG(D_RX,"%s():[flag=0x%08x]\n", __func__, flag); + wake_up(&fm_wq); + break; + + default: + spin_lock(&flag_lock); + flag |= (1 << opcode); + spin_unlock(&flag_lock); + FM_LOG_DBG(D_RX,"[flag=0x%08x]\n", flag); + wake_up(&fm_wq); + break; + } + state = FM_TASK_RX_PARSER_PKT_TYPE; + i += length; + break; + + default: + break; + } + } + FM_LOG_DBG(D_RX,"-%s():\n", __func__); +} + +static int fm_setup_cdev(struct fm *fm) +{ + int err; + int alloc_ret = 0; + + /*static allocate chrdev*/ + fm->dev_t = MKDEV(FM_major, 0); + alloc_ret = register_chrdev_region(fm->dev_t, 1, FM_NAME); + if (alloc_ret){ + FM_LOG_ERR(D_ALL,"%s():fail to register chrdev\n", __func__); + return alloc_ret; + } +#if 0 + //dynamic allocate chrdev + err = alloc_chrdev_region(&fm->dev_t, 0, 1, FM_NAME); + if (err) { + FM_LOG_ERR(D_MAIN,"alloc dev_t failed\n"); + return -1; + } +#endif + FM_LOG_NTC(D_MAIN,"alloc %s:%d:%d\n", FM_NAME, MAJOR(fm->dev_t), MINOR(fm->dev_t)); + cdev_init(&fm->cdev, &fm_ops); + + fm->cdev.owner = THIS_MODULE; + fm->cdev.ops = &fm_ops; + + err = cdev_add(&fm->cdev, fm->dev_t, 1); + if (err){ + FM_LOG_ERR(D_ALL,"%s():alloc dev_t failed\n", __func__); + return -1; + } + + return 0; +} + +/* + * fm_ops_ioctl + * + * ioctl system call interface changed, in order to enhance system performance, + * Linux kernel 3.0 will not support ioctl(), so we shoud use unlocked_ioctl(). + * We should be care of race condition, and lock is a valid way to protect our data. + * + * @filp - current strcut file's pointer, we can get dentry and inode info by it + * @cmd - ioctl command that was send by ioctl caller + * @arg - usually it's the pointer of a data structure defined in user space + * + * If success, return 0; else error code + */ +static long fm_ops_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + struct fm *fm = container_of(filp->f_dentry->d_inode->i_cdev, struct fm, cdev); + + FM_LOG_INF(D_MAIN,"%s():\n", __func__); + + //check if we are resetting + if(chip_rst_state != FM_WHOLECHIP_RST_OFF){ + FM_LOG_WAR(D_MAIN, "whole chip is resetting, retry later\n"); + ret = -ERR_WHOLECHIP_RST; + //ret = 0; + return ret; + } + + if(subsys_rst_state != FM_SUBSYS_RST_OFF){ + FM_LOG_WAR(D_MAIN, "FM subsys is resetting, retry later\n"); + ret = -ERR_SUBSYS_RST; + //ret = 0; + return ret; + } + + switch(cmd){ + case FM_IOCTL_POWERUP:{ + struct fm_tune_parm parm; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_POWERUP......\n"); +// FIXME!! +// if (!capable(CAP_SYS_ADMIN)) +// return -EPERM; + if (copy_from_user(&parm, (void*)arg, sizeof(struct fm_tune_parm))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_from_user error\n"); + return -EFAULT; + } + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + ret = fm_powerup(fm, &parm); + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + if (copy_to_user((void*)arg, &parm, sizeof(struct fm_tune_parm))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_to_user error\n"); + return -EFAULT; + } + + break; + } + + case FM_IOCTL_POWERDOWN:{ + int32_t type = -1; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_POWERDOWN......\n"); + FM_LOG_DBG(D_IOCTL,"[chipon=%d],[powerup=%d],[ref=%d]\n", + fm->chipon, + fm->powerup, + fm->ref); +// FIXME!! +// if (!capable(CAP_SYS_ADMIN)) +// return -EPERM; + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip already is off\n"); + return -EFAULT; + } + if (copy_from_user(&type, (void*)arg, sizeof(int32_t))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_from_user error\n"); + return -EFAULT; + } + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + ret = fm_powerdown(fm, type); + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + break; + } + + // tune (frequency, auto Hi/Lo ON/OFF ) + case FM_IOCTL_TUNE:{ + struct fm_tune_parm parm; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_TUNE......\n"); +// FIXME! +// if (!capable(CAP_SYS_ADMIN)) +// return -EPERM; + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + if (copy_from_user(&parm, (void*)arg, sizeof(struct fm_tune_parm))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_from_user error\n"); + return -EFAULT; + } + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + ret = fm_tune(fm, &parm); + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + + if (copy_to_user((void*)arg, &parm, sizeof(struct fm_tune_parm))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_to_user error\n"); + return -EFAULT; + } + break; + } + + case FM_IOCTL_SEEK:{ + struct fm_seek_parm parm; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_SEEK......\n"); +// FIXME!! +// if (!capable(CAP_SYS_ADMIN)) +// return -EPERM; + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + + if (copy_from_user(&parm, (void*)arg, sizeof(struct fm_seek_parm))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_from_user error\n"); + return -EFAULT; + } + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + ret = fm_seek(fm, &parm); + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + + if (copy_to_user((void*)arg, &parm, sizeof(struct fm_seek_parm))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_to_user error\n"); + return -EFAULT; + } + break; + } + + case FM_IOCTL_SCAN:{ + struct fm_scan_parm parm; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_SCAN......\n"); + + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + if(copy_from_user(&parm, (void*)arg, sizeof(struct fm_scan_parm))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_from_user error\n"); + return -EFAULT; + } + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + ret = fm_scan(fm, &parm); + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + + if(copy_to_user((void*)arg, &parm, sizeof(struct fm_scan_parm))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_to_user error\n"); + return -EFAULT; + } + //XHC + //ret = 0; + break; + } + + case FM_IOCTL_SCAN_GETRSSI:{ + struct fm_rssi_req *req; + if(!(req = kzalloc(sizeof(struct fm_rssi_req), GFP_KERNEL))){ + FM_LOG_ERR(D_INIT,"kzalloc(fm) -ENOMEM\n"); + return -EFAULT; + } + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_SCAN_GETRSSI......\n"); + FM_COM_ASSERT(TRUE == fm->chipon); + if(copy_from_user(req, (void*)arg, sizeof(struct fm_rssi_req))){ + FM_LOG_ERR(D_IOCTL, "copy_from_user error\n"); + kfree(req); + return -EFAULT; + } + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL, "get fm_ops_mutex error\n"); + kfree(req); + return -EFAULT; + } + ret = fm_get_rssi_after_scan(fm, req); + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL, "fw no response, do hw reset\n"); + fm_hw_reset(); + } + up(&fm_ops_mutex); + if(copy_to_user((void*)arg, req, sizeof(struct fm_rssi_req))){ + FM_LOG_ERR(D_IOCTL, "copy_to_user error\n"); + kfree(req); + return -EFAULT; + } + kfree(req); + break; + } + + case FM_IOCTL_SETVOL:{ + uint32_t vol; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_SETVOL......\n"); +// FIXME!! +// if (!capable(CAP_SYS_ADMIN)) +// return -EPERM; + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + + if(copy_from_user(&vol, (void*)arg, sizeof(uint32_t))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_from_user error\n"); + return -EFAULT; + } + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + FM_LOG_DBG(D_IOCTL,"FM_IOCTL_SETVOL, [vol=%d]\n", vol); + ret = fm_setvol(fm, vol); + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + break; + } + case FM_IOCTL_GETVOL:{ + uint32_t vol; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_GETVOL......\n"); +// FIXME!! +// if (!capable(CAP_SYS_ADMIN)) +// return -EPERM; + + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + ret = fm_getvol(fm, &vol); + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + if (copy_to_user((void*)arg, &vol, sizeof(uint32_t))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_to_user error\n"); + return -EFAULT; + } + break; + } + + case FM_IOCTL_IS_FM_POWERED_UP:{ + uint32_t pwredup = 0; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_IS_FM_POWERED_UP......\n"); + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + pwredup = fm->powerup; + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + FM_LOG_DBG(D_IOCTL,"FM_IOCTL_IS_FM_POWERED_UP,[powerup=%d]\n", pwredup); + if (copy_to_user((void*)arg, &pwredup, sizeof(uint32_t))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_to_user error\n"); + return -EFAULT; + } + break; + } + + case FM_IOCTL_MUTE:{ + uint32_t bmute; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_MUTE......\n"); +// FIXME!! +// if (!capable(CAP_SYS_ADMIN)) +// return -EPERM; + if (copy_from_user(&bmute, (void*)arg, sizeof(uint32_t))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_from_user error\n"); + return -EFAULT; + } + FM_LOG_DBG(D_IOCTL,"FM_IOCTL_MUTE:[mute=%d]\n", bmute); + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + if (bmute){ + ret = MT6620_Mute(true); + }else{ + ret = MT6620_Mute(false); + } + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + break; + } + + case FM_IOCTL_GETRSSI:{ + int rssi = 0; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_GETRSSI......\n"); +// FIXME!! +// if (!capable(CAP_SYS_ADMIN)) +// return -EPERM; + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + ret = fm_getrssi(fm, &rssi); + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + if (copy_to_user((void*)arg, &rssi, sizeof(int))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_to_user error\n"); + return -EFAULT; + } + break; + } + + case FM_IOCTL_RW_REG:{ + struct fm_ctl_parm parm_ctl; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_RW_REG......\n"); +// FIXME!! +// if (!capable(CAP_SYS_ADMIN)) +// return -EPERM; + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + + if (copy_from_user(&parm_ctl, (void*)arg, sizeof(struct fm_ctl_parm))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_from_user error\n"); + return -EFAULT; + } + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + + //write + if(parm_ctl.rw_flag == 0){ + FM_LOG_DBG(D_IOCTL,"Write Reg %02x:%04x\n", parm_ctl.addr, parm_ctl.val); + ret = MT6620_write(parm_ctl.addr, parm_ctl.val); + }else{ + ret = MT6620_read(parm_ctl.addr, &parm_ctl.val); + FM_LOG_DBG(D_IOCTL,"Read Reg %02x:%04x, [ret=%d]\n", parm_ctl.addr, parm_ctl.val, ret); + } + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + + // Read success. + if ((parm_ctl.rw_flag == 0x01) && (!ret)){ + if (copy_to_user((void*)arg, &parm_ctl, sizeof(struct fm_ctl_parm))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_to_user error\n"); + return -EFAULT; + } + } + break; + } + + case FM_IOCTL_GETCHIPID:{ + uint16_t chipid; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_GETCHIPID......\n"); + + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + + //ret = MT6620_read(0x62, &chipid); + chipid = fm->chip_id; + FM_LOG_DBG(D_IOCTL,"FM_IOCTL_GETCHIPID:%04x\n", chipid); + + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + + if (copy_to_user((void*)arg, &chipid, sizeof(uint16_t))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_to_user error\n"); + return -EFAULT; + } + + break; + } + + case FM_IOCTL_GETMONOSTERO:{ + uint16_t usStereoMono; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_GETMONOSTERO......\n"); + + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + + ret = MT6620_GetMonoStereo(&usStereoMono); + FM_LOG_DBG(D_IOCTL,"FM_IOCTL_GETMONOSTERO:%04x\n", usStereoMono); + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + + if (copy_to_user((void*)arg, &usStereoMono, sizeof(uint16_t))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_to_user error\n"); + return -EFAULT; + } + + break; + } + + case FM_IOCTL_SETMONOSTERO:{ + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_SETMONOSTERO......\n"); + FM_COM_ASSERT(TRUE == fm->chipon); + ret = MT6620_SetMonoStereo((int)arg); + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + break; + } + + case FM_IOCTL_GETCURPAMD:{ + uint16_t PamdLevl; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_GETCURPAMD......\n"); + + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + + ret = MT6620_GetCurPamd(&PamdLevl); + FM_LOG_DBG(D_MAIN,"FM_IOCTL_GETCURPAMD:%d\n", PamdLevl); + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + + if (copy_to_user((void*)arg, &PamdLevl, sizeof(uint16_t))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_to_user error\n"); + return -EFAULT; + } + + break; + } + + case FM_IOCTL_EM_TEST:{ + struct fm_em_parm parm_em; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_EM_TEST......\n"); +// FIXME!! +// if (!capable(CAP_SYS_ADMIN)) +// return -EPERM; + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + + if (copy_from_user(&parm_em, (void*)arg, sizeof(struct fm_em_parm))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_from_user error\n"); + return -EFAULT; + } + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + + ret = MT6620_em_test(parm_em.group_idx, parm_em.item_idx, parm_em.item_value); + + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + + break; + } + + case FM_IOCTL_RDS_SUPPORT:{ + int support; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_RDS_SUPPORT......\n"); + + support = FM_RDS_ENABLE; + if (copy_to_user((void*)arg, &support, sizeof(int32_t))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_to_user error\n"); + return -EFAULT; + } + break; + } + + case FM_IOCTL_RDS_ONOFF:{ + uint16_t rds_onoff = 0;; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_RDS_ONOFF......\n"); + FM_LOG_DBG(D_IOCTL,"[chipon=%d] [powerup=%d] [ref=%d]\n", + fm->chipon, + fm->powerup, + fm->ref); + + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + + if (copy_from_user(&rds_onoff, (void*)arg, sizeof(uint16_t))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_from_user error\n"); + return -EFAULT; + } + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + + if(rds_onoff){ + if((ret = MT6620_RDS_OnOff(fm, true))){ + FM_LOG_ERR(D_IOCTL,"FM_IOCTL_RDS_ONOFF faield\n"); + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + return -EPERM; + } + //fm_enable_eint(); + fm_enable_rds_BlerCheck(fm); + fm_cxt->rxcxt.rdsOn = true; + FM_LOG_DBG(D_MAIN,"FM_IOCTL_RDS_ON:%d\n", jiffies_to_msecs(jiffies)); + }else{ + //fm_disable_eint(); + fm->RDS_Data_ready = true; + memset(fm->pstRDSData, 0, sizeof(RDSData_Struct)); + wake_up_interruptible(&fm->read_wait); + fm_disable_rds_BlerCheck(); + ret = MT6620_RDS_OnOff(fm, false); + fm_cxt->rxcxt.rdsOn = false; + FM_LOG_DBG(D_MAIN,"FM_IOCTL_RDS_OFF:%d\n", jiffies_to_msecs(jiffies)); + } + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + break; + } + + case FM_IOCTL_GETGOODBCNT:{ + uint16_t uGBLCNT = 0; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_GETGOODBCNT......\n"); + + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + + FM_LOG_INF(D_IOCTL,"-fm_read_mutex\n"); + if (down_interruptible(&fm_read_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + uGBLCNT = GOOD_BLK_CNT; + up(&fm_read_mutex); + FM_LOG_INF(D_IOCTL,"+fm_read_mutex\n"); + FM_LOG_DBG(D_IOCTL,"FM_IOCTL_GETGOODBCNT:%d\n", uGBLCNT); + if (copy_to_user((void*)arg, &uGBLCNT, sizeof(uint16_t))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_to_user error\n"); + return -EFAULT; + } + break; + } + case FM_IOCTL_GETBADBNT:{ + uint16_t uBadBLCNT = 0; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_GETBADBNT......\n"); + + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + + FM_LOG_INF(D_IOCTL,"-fm_read_mutex\n"); + if (down_interruptible(&fm_read_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + uBadBLCNT = BAD_BLK_CNT; + up(&fm_read_mutex); + FM_LOG_INF(D_IOCTL,"+fm_read_mutex\n"); + + FM_LOG_DBG(D_IOCTL,"FM_IOCTL_GETBADBNT:%d\n", uBadBLCNT); + if (copy_to_user((void*)arg, &uBadBLCNT, sizeof(uint16_t))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_to_user error\n"); + return -EFAULT; + } + break; + } + + case FM_IOCTL_GETBLERRATIO:{ + uint16_t uBlerRatio = 0; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_GETBLERRATIO......\n"); + + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_read_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + uBlerRatio = (uint16_t)BAD_BLK_RATIO; + up(&fm_read_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + + FM_LOG_DBG(D_IOCTL,"FM_IOCTL_GETBLERRATIO:%d\n", uBlerRatio); + if (copy_to_user((void*)arg, &uBlerRatio, sizeof(uint16_t))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_to_user error\n"); + return -EFAULT; + } + break; + } + + #ifdef FMDEBUG + case FM_IOCTL_DUMP_REG:{ + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_DUMP_REG......\n"); + + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + ret = MT6620_dump_reg(); + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + break; + } + #endif + + case FM_IOCTL_POWERUP_TX:{ + struct fm_tune_parm parm; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_POWERUP_TX......\n"); +// FIXME!! +// if (!capable(CAP_SYS_ADMIN)) +// return -EPERM; + if (copy_from_user(&parm, (void*)arg, sizeof(struct fm_tune_parm))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_from_user error\n"); + return -EFAULT; + } + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + ret = fm_powerup_tx(fm, &parm); + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + if (copy_to_user((void*)arg, &parm, sizeof(struct fm_tune_parm))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_to_user error\n"); + return -EFAULT; + } + break; + } + + // tune (frequency, auto Hi/Lo ON/OFF ) + case FM_IOCTL_TUNE_TX:{ + struct fm_tune_parm parm; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_TUNE_TX......\n"); +// FIXME! +// if (!capable(CAP_SYS_ADMIN)) +// return -EPERM; + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + + if (copy_from_user(&parm, (void*)arg, sizeof(struct fm_tune_parm))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_from_user error\n"); + return -EFAULT; + } + + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + ret = fm_tune_tx(fm, &parm); + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + + if (copy_to_user((void*)arg, &parm, sizeof(struct fm_tune_parm))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_to_user error\n"); + return -EFAULT; + } + break; + } + + case FM_IOCTL_TX_SUPPORT:{ + int32_t tx_support = -1; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_TX_SUPPORT......\n"); +// FIXME!! +// if (!capable(CAP_SYS_ADMIN)) +// return -EPERM; + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + + if(FM_TX_SUPPORT == atomic_read(&fm->tx_support)){ + tx_support = 1; + }else if(FM_TX_NOT_SUPPORT == atomic_read(&fm->tx_support)){ + tx_support = 0; + }else{ + tx_support = -1; + FM_LOG_ERR(D_IOCTL,"FM_IOCTL_TX_SUPPORT:invalid flag[fm->tx_support=%d]\n", + atomic_read(&fm->tx_support)); + ret = -1; + } + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + if (copy_to_user((void*)arg, &tx_support, sizeof(int32_t))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_to_user error\n"); + return -EFAULT; + } + break; + } + + case FM_IOCTL_RDSTX_ENABLE:{ + int32_t rds_tx_enable = -1; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_RDSTX_ENABLE......\n"); +// FIXME!! +// if (!capable(CAP_SYS_ADMIN)) +// return -EPERM; + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + if(copy_from_user(&rds_tx_enable, (void*)arg, sizeof(int32_t))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_from_user error\n"); + return -EFAULT; + } + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + + if(FM_RDS_TX_ENABLE == rds_tx_enable){ + atomic_set(&fm->rds_tx_enable, FM_RDS_TX_ENABLE); + }else if(FM_RDS_TX_DISENABLE == rds_tx_enable){ + atomic_set(&fm->rds_tx_enable, FM_RDS_TX_DISENABLE); + }else{ + FM_LOG_ERR(D_IOCTL,"FM_IOCTL_RDSTX_ENABLE:invalid para[rds_tx_enable=%d]\n", + rds_tx_enable); + ret = -1; + } + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + break; + } + + case FM_IOCTL_RDSTX_SUPPORT:{ + int32_t rds_tx_support = -1; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_RDSTX_SUPPORT......\n"); +// FIXME!! +// if (!capable(CAP_SYS_ADMIN)) +// return -EPERM; + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + + if(FM_RDS_TX_SUPPORT == atomic_read(&fm->rds_tx_support)){ + rds_tx_support = 1; + }else if(FM_RDS_TX_NOT_SUPPORT == atomic_read(&fm->rds_tx_support)){ + rds_tx_support = 0; + }else{ + rds_tx_support = -1; + FM_LOG_ERR(D_IOCTL,"FM_IOCTL_RDSTX_SUPPORT:invalid flag[fm->rds_tx_support=%d]\n", + atomic_read(&fm->rds_tx_support)); + ret = -1; + } + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + if (copy_to_user((void*)arg, &rds_tx_support, sizeof(int32_t))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_to_user error\n"); + return -EFAULT; + } + break; + } + + case FM_IOCTL_TX_SCAN:{ + struct fm_tx_scan_parm parm; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_TX_SCAN......\n"); +// FIXME!! +// if (!capable(CAP_SYS_ADMIN)) +// return -EPERM; + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + + if (copy_from_user(&parm, (void*)arg, sizeof(struct fm_tx_scan_parm))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_from_user error\n"); + return -EFAULT; + } + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + + ret = fm_tx_scan(fm, &parm); + if(ret < 0){ + FM_LOG_ERR(D_MAIN,"FM_IOCTL_TX_SCAN failed\n"); + } + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + if (copy_to_user((void*)arg, &parm, sizeof(struct fm_tx_scan_parm))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_to_user error\n"); + return -EFAULT; + } + break; + } + case FM_IOCTL_RDS_TX:{ + struct fm_rds_tx_parm parm; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_RDS_TX......\n"); +// FIXME!! +// if (!capable(CAP_SYS_ADMIN)) +// return -EPERM; + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + + if (copy_from_user(&parm, (void*)arg, sizeof(struct fm_rds_tx_parm))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_from_user error\n"); + return -EFAULT; + } + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + ret = fm_rds_tx(fm, &parm); + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + if (copy_to_user((void*)arg, &parm, sizeof(struct fm_rds_tx_parm))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_to_user error\n"); + return -EFAULT; + } + break; + } + + case FM_IOCTL_OVER_BT_ENABLE:{ + int32_t fm_via_bt = -1; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_OVER_BT_ENABLE......\n"); + + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + if(copy_from_user(&fm_via_bt, (void*)arg, sizeof(int32_t))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_from_user error\n"); + return -EFAULT; + } + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + + ret = fm_over_bt(fm, fm_via_bt); + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + if(FM_OVER_BT_ENABLE == fm_via_bt){ + atomic_set(&fm->over_bt_enable, FM_OVER_BT_ENABLE); + }else if(FM_OVER_BT_DISABLE == fm_via_bt){ + atomic_set(&fm->over_bt_enable, FM_OVER_BT_DISABLE); + }else{ + FM_LOG_ERR(D_IOCTL,"FM_IOCTL_OVER_BT_ENABLE:invalid para[fm_over_bt=%d]\n", + fm_via_bt); + ret = -1; + } + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + break; + } + + case FM_IOCTL_ANA_SWITCH:{ + int32_t antenna = -1; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_ANA_SWITCH......\n"); + + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + if(copy_from_user(&antenna, (void*)arg, sizeof(int32_t))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_from_user error\n"); + return -EFAULT; + } + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + + ret = fm_antenna_switch(fm, antenna); + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + break; + } + + case FM_IOCTL_GETCAPARRAY:{ + int caparray; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_GETCAPARRAY......\n"); + + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + + ret = MT6620_GetCapArray(&caparray); + FM_LOG_DBG(D_IOCTL,"FM_IOCTL_GETMONOSTERO:%x\n", caparray); + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fw no response, do hw reset\n"); + fm_hw_reset(); + } + + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + + if (copy_to_user((void*)arg, &caparray, sizeof(int32_t))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_to_user error\n"); + return -EFAULT; + } + break; + } + + case FM_IOCTL_GPS_RTC_DRIFT:{ + struct fm_gps_rtc_info rtc_info; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_GPS_RTC_DRIFT......\n"); + + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + if(copy_from_user(&rtc_info, (void*)arg, sizeof(struct fm_gps_rtc_info))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_from_user error\n"); + return -EFAULT; + } + + ret = fm_get_gps_rtc_info(&gps_rtc_info, &rtc_info); + if(ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"fm_get_gps_rtc_info error\n"); + return ret; + } + break; + } + + case FM_IOCTL_I2S_SETTING:{ + struct fm_i2s_setting i2s_cfg; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_I2S_SETTING......\n"); + + if (FALSE == fm->chipon){ + FM_LOG_ERR(D_IOCTL,"ERROR, FM chip is OFF\n"); + return -EFAULT; + } + if(copy_from_user(&i2s_cfg, (void*)arg, sizeof(struct fm_i2s_setting))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_from_user error\n"); + return -EFAULT; + } + + ret = MT6620_I2S_Setting(i2s_cfg.onoff, i2s_cfg.mode, i2s_cfg.sample); + if(ret){ + FM_LOG_ERR(D_IOCTL|D_ALL,"MT6620_I2S_Setting error\n"); + return ret; + } + break; + } + case FM_IOCTL_RDS_GROUPCNT:{ + struct rds_group_cnt_req gc_req; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_RDS_GROUPCNT......\n"); + if (copy_from_user(&gc_req, (void*)arg, sizeof(struct rds_group_cnt_req))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_from_user error\n"); + return -EFAULT; + } + FM_LOG_INF(D_IOCTL,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + //handle group counter request + switch(gc_req.op){ + case RDS_GROUP_CNT_READ: + rds_group_counter_get(&gc_req.gc, &fm->rds_gc); + break; + case RDS_GROUP_CNT_WRITE: + break; + case RDS_GROUP_CNT_RESET: + rds_group_counter_reset(&fm->rds_gc); + break; + default: + break; + } + up(&fm_ops_mutex); + FM_LOG_INF(D_IOCTL,"+fm_ops_mutex\n"); + if (copy_to_user((void*)arg, &gc_req, sizeof(struct rds_group_cnt_req))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_to_user error\n"); + return -EFAULT; + } + break; + } + case FM_IOCTL_RDS_GET_LOG:{ + struct rds_raw_data rds_log; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_RDS_GET_LOG......\n"); + rds_log.dirty = TRUE; + rds_log.len = rds_rx_size; + memcpy(&rds_log.data[0], (const void*)&rds_rx_result, sizeof(struct rds_rx)); + if (copy_to_user((void*)arg, &rds_log, sizeof(struct rds_raw_data))){ + FM_LOG_ERR(D_IOCTL|D_ALL,"copy_to_user error\n"); + return -EFAULT; + } + break; + } + + case FM_IOCTL_GET_HW_INFO:{ + struct fm_hw_info info; + FM_LOG_DBG(D_IOCTL,"......FM_IOCTL_GET_HW_INFO......\n"); + FM_COM_ASSERT(TRUE == fm->chipon); + + if(down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL, "get hw info, get fm_ops_mutex error\n"); + return -EFAULT; + } + ret = fm_get_hw_info(fm, &info); + if(-ERR_FW_NORES == ret){ + FM_LOG_ERR(D_IOCTL, "get hw info, fw no response, do hw reset\n"); + fm_hw_reset(); + } + up(&fm_ops_mutex); + if(copy_to_user((void*)arg, &info, sizeof(struct fm_hw_info))){ + FM_LOG_ERR(D_IOCTL, "get hw info, copy_to_user error\n"); + return -EFAULT; + } + break; + } + + default: + FM_LOG_ERR(D_IOCTL,"Invalid IOCTL[cmd=%d], please check!\n", cmd); + return -EPERM; + } + return ret; +} + +static loff_t fm_ops_lseek(struct file *filp, loff_t off, int whence) +{ + if(whence == SEEK_END){ + MT6620_ScanForceStop(); + } + return off; +} + +static ssize_t fm_ops_read(struct file *filp, char *buf, size_t len, loff_t *off) +{ + struct fm *fm = filp->private_data; + int copy_len = 0, left = 0; + uint8_t indx; + + indx = 0; + FM_LOG_DBG(D_MAIN,"+%s():\n", __func__); + if (!fm){ + FM_LOG_ERR(D_MAIN,"%s():invalid fm pointer\n", __func__); + return 0; + } + + if(!buf || len < sizeof(RDSData_Struct)){ + FM_LOG_ERR(D_ALL,"%s():invalid buf\n", __func__); + return 0; + } + copy_len = sizeof(RDSData_Struct); + +RESTART: + if((fm->RDS_Data_ready == true) || (fm->powerup == FM_PWR_OFF)){ + + //block when FM is resetting + while((chip_rst_state != FM_WHOLECHIP_RST_OFF) || (subsys_rst_state != FM_SUBSYS_RST_OFF)){ + msleep_interruptible(100); + } + + FM_LOG_INF(D_MAIN,"-fm_rds_mutex\n"); + if (down_interruptible(&fm_rds_mutex)){ + FM_LOG_ERR(D_MAIN,"get fm_rds_mutex error\n"); + return 0; + } + + if(fm->powerup == FM_PWR_OFF){ + memset(fm->pstRDSData, 0, sizeof(RDSData_Struct)); + } + + if((left = copy_to_user((void *)buf, fm->pstRDSData, (unsigned long)copy_len))){ + FM_LOG_ERR(D_MAIN,"%s():copy_to_user failed\n", __func__); + } + FM_LOG_DBG(D_MAIN,"copy len=%d\n", (copy_len-left)); + //Clear + if(left == 0){ + fm->pstRDSData->event_status = 0x0; + } + fm->RDS_Data_ready = false; + up(&fm_rds_mutex); + FM_LOG_INF(D_MAIN,"+fm_rds_mutex\n"); + }else{ + FM_LOG_DBG(D_MAIN,"wait event\n"); + if (wait_event_interruptible(fm->read_wait, (fm->RDS_Data_ready == true)) == 0){ + FM_LOG_DBG(D_MAIN,"wait event success[%d]\n", fm->RDS_Data_ready); + goto RESTART; + }else { + FM_LOG_ERR(D_MAIN,"%s():wait event err[%d]\n", __func__, fm->RDS_Data_ready); + fm->RDS_Data_ready = false; + return 0; + } + } + + FM_LOG_DBG(D_MAIN,"-%s():\n", __func__); + return (copy_len-left); +} + +static int fm_ops_open(struct inode *inode, struct file *filp) +{ + int ret = 0; + struct fm *fm = container_of(inode->i_cdev, struct fm, cdev); + + fm_get_process_path(fm); + + FM_LOG_DBG(D_MAIN,"+%s():[T=%d]\n", __func__, jiffies_to_msecs(jiffies)); + + //check if we are resetting + if(chip_rst_state != FM_WHOLECHIP_RST_OFF){ + FM_LOG_WAR(D_MAIN, "FM is resetting, please open later\n"); + ret = -ERR_WHOLECHIP_RST; + return ret; + } + + if(subsys_rst_state != FM_SUBSYS_RST_OFF){ + FM_LOG_WAR(D_MAIN, "FM subsys is resetting, retry later\n"); + ret = -ERR_SUBSYS_RST; + return ret; + } + + FM_LOG_INF(D_MAIN,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_IOCTL|D_ALL,"get fm_ops_mutex error\n"); + return -EFAULT; + } + + fm->ref++; + FM_LOG_NTC(D_MAIN,"%s [fm->ref=%d]\n", __func__, fm->ref); + //Audio driver will open first handle, for save power. + if(fm->ref > 0){ + if(FALSE == fm->chipon){ + //Turn on FM on 6620 chip by WMT driver + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_FM)) { + FM_LOG_ERR(D_MAIN,"%s WMT turn on FM fail!\n", __func__); + ret = -ENODEV; + goto out; + } + fm->chipon = true; + fm_cxt->chipon = true; + spin_lock(&flag_lock); + flag = 0; //FM info flag + spin_unlock(&flag_lock); + /* GeorgeKuo: turn on function before check stp ready */ + if(FALSE == mtk_wcn_stp_is_ready()){ + fm->chipon = false; + fm_cxt->chipon = false; + fm->ref--; + FM_LOG_ERR(D_MAIN,"6620 stp is not ready, please retry later\n"); + ret = -ENODEV; + goto out; + } + //Register the main Callback func that will get data form 6620 FM firware + mtk_wcn_stp_register_event_cb(FM_TASK_INDX, stp_rx_event_cb); + mtk_wcn_wmt_msgcb_reg(WMTDRV_TYPE_FM, fm_wholechip_rst_cb); + FM_LOG_NTC(D_MAIN,"%s WMT turn on FM OK, [fm->chipon=%d]!\n", __func__, fm->chipon); + } + } + +out: + up(&fm_ops_mutex); + FM_LOG_INF(D_MAIN,"+fm_ops_mutex\n"); + filp->private_data = fm; + FM_LOG_DBG(D_MAIN,"-%s():[T=%d]\n", __func__, jiffies_to_msecs(jiffies)); + return ret; +} + +static int fm_ops_release(struct inode *inode, struct file *filp) +{ + int ret = 0; + struct fm *fm = container_of(inode->i_cdev, struct fm, cdev); + + FM_LOG_DBG(D_MAIN,"+%s()\n", __func__); + FM_LOG_INF(D_MAIN,"-fm_ops_mutex\n"); + if (down_interruptible(&fm_ops_mutex)){ + FM_LOG_ERR(D_MAIN,"get fm_ops_mutex error\n"); + return -EFAULT; + } + + if(fm->ref > 0){ + fm->ref--; + }else{ + FM_LOG_ERR(D_MAIN,"%s():open and close FM unmatch\n", __func__); + ret = -EFAULT; + } + FM_LOG_NTC(D_MAIN,"%s [fm->ref=%d]\n", __func__, fm->ref); + + //check if we are resetting + if(chip_rst_state != FM_WHOLECHIP_RST_OFF){ + FM_LOG_WAR(D_MAIN, "FM is resetting, only ref--\n"); + ret = -ERR_WHOLECHIP_RST; + up(&fm_ops_mutex); + FM_LOG_INF(D_MAIN,"+fm_ops_mutex\n"); + return ret; + } + + if(subsys_rst_state != FM_SUBSYS_RST_OFF){ + FM_LOG_WAR(D_MAIN, "FM subsys is resetting, only ref--\n"); + ret = -ERR_SUBSYS_RST; + up(&fm_ops_mutex); + FM_LOG_INF(D_MAIN,"+fm_ops_mutex\n"); + return ret; + } + if(fm->ref < 1){ + + fm_disable_rds_BlerCheck(); + ret = MT6620_RDS_OnOff(fm, FALSE); + + if(FM_PWR_RX_ON == fm->powerup){ + ret = fm_powerdown(fm, FM_RX); + }else if(FM_PWR_TX_ON == fm->powerup){ + ret = fm_powerdown(fm, FM_TX); + } + + if (TRUE == fm->chipon){ + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_off(WMTDRV_TYPE_FM)){ + FM_LOG_ERR(D_MAIN,"WMT turn off FM fail!\n"); + ret = -EFAULT; + }else{ + FM_LOG_NTC(D_MAIN,"WMT turn off FM OK!\n"); + } + fm->chipon = FALSE; + fm_cxt->chipon = false; + //Unregister FM main Callback + mtk_wcn_stp_register_event_cb(FM_TASK_INDX, NULL); + mtk_wcn_wmt_msgcb_unreg(WMTDRV_TYPE_FM); + } + } + + up(&fm_ops_mutex); + FM_LOG_INF(D_MAIN,"+fm_ops_mutex\n"); + FM_LOG_DBG(D_MAIN,"-%s()[ret=%d]\n", __func__, ret); + return ret; +} + +static int fm_get_process_path(struct fm *fm) +{ + int ret = 0; + +#ifdef FM_TASK_INFO_DEBUG + struct dentry *dnty = NULL; + FM_LOG_NTC(D_MAIN,"[TaskName=%s],[TaskId=%d]\n", current->comm, current->pid); + dnty = current->mm->mmap->vm_file->f_path.dentry; + printk("[%s]", dnty->d_name.name); + while(strcmp(dnty->d_name.name, "/")){ + dnty = dnty->d_parent; + printk("[%s]", dnty->d_name.name); + } + printk("\n"); +#endif + + return ret; +} + +static int fm_timer_init(struct fm *fm, struct fm_timer_sys *fmtimer, struct timer_list *timer) +{ + int ret = 0; + + fmtimer->onoff = FM_TIMER_SYS_OFF; + fmtimer->count = 0; + fmtimer->rds_reset_en = FM_RDS_RST_DISABLE; + fmtimer->tx_pwr_ctrl_en = FM_TX_PWR_CTRL_DISABLE; + fmtimer->tx_rtc_ctrl_en = FM_TX_RTC_CTRL_DISABLE; + fmtimer->tx_desense_en = FM_TX_DESENSE_DISABLE; + + init_timer(timer); + timer->expires = jiffies + FM_TIMER_TIMEOUT_MIN/(1000/HZ); + timer->function = fm_timer_func; + timer->data = (unsigned long)fm; + add_timer(timer); + + return ret; +} +static int fm_rtc_compensation_init(struct fm *fm, struct fm_gps_rtc_info *rtc) +{ + int ret = 0; + + rtc->err = 0; + rtc->age = 0; + rtc->drift = 0; + rtc->tv.tv_sec = 0; + rtc->tv.tv_usec = 0; + rtc->ageThd = FM_GPS_RTC_AGE_TH; + rtc->driftThd = FM_GPS_RTC_DRIFT_TH; + rtc->tvThd.tv_sec = FM_GPS_RTC_TIME_DIFF_TH; + rtc->retryCnt = FM_GPS_RTC_RETRY_CNT; + rtc->flag = FM_GPS_RTC_INFO_OLD; + + return ret; +} + +static int fm_print_cfg_info(struct fm *fm, void* data) +{ + int ret = 0; + + FM_LOG_NTC(D_INIT,"******fm config info******\n"); + FM_LOG_NTC(D_INIT,"***chip:\tMT6620\t\n"); + FM_LOG_NTC(D_INIT,"***band:\t%d\t\n", FMR_BAND); + FM_LOG_NTC(D_INIT,"***freq_min:\t%d\t\n", FMR_BAND_FREQ_L); + FM_LOG_NTC(D_INIT,"***freq_max:\t%d\t\n", FMR_BAND_FREQ_H); + FM_LOG_NTC(D_INIT,"***scan_tbl:\t%d\t\n", FMR_SCAN_CH_SIZE); + FM_LOG_NTC(D_INIT,"***space:\t%d\t\n", FMR_SEEK_SPACE); + FM_LOG_NTC(D_INIT,"***rssi_long:\t0x%04x\t\n", FMR_RSSI_TH_LONG); + FM_LOG_NTC(D_INIT,"***rssi_short:\t0x%04x\t\n", FMR_RSSI_TH_SHORT); + FM_LOG_NTC(D_INIT,"***CQI:\t0x%04x\t\n", FMR_CQI_TH); + FM_LOG_NTC(D_INIT,"******fm config end******\n"); + + return ret; +} + +static int fm_init() +{ + int err; + struct fm *fm = NULL; + + if (!(fm = kzalloc(sizeof(struct fm), GFP_KERNEL))){ + FM_LOG_ERR(D_INIT,"kzalloc(fm) -ENOMEM\n"); + err = -ENOMEM; + goto fm_alloc_err; + } + + if (!(tx_buf = kzalloc(TX_BUF_SIZE + 1, GFP_KERNEL))){ + FM_LOG_ERR(D_INIT,"kzalloc(tx_buf) -ENOMEM\n"); + err = -ENOMEM; + goto tx_alloc_err; + } + + if (!(fm_cxt = kzalloc(sizeof(struct fm_context), GFP_KERNEL))){ + FM_LOG_ERR(D_INIT,"kzalloc(fm_cxt) -ENOMEM\n"); + err = -ENOMEM; + goto tx_alloc_err; + } + + fm->ref = 0; + atomic_set(&fm->tx_support, FM_TX_SUPPORT); + atomic_set(&fm->rds_tx_support, FM_RDS_TX_SUPPORT); + atomic_set(&fm->rds_tx_enable, FM_RDS_TX_ENABLE); + atomic_set(&fm->over_bt_enable, FM_OVER_BT_DISABLE); + fm->chipon = false; + fm->powerup = FM_PWR_OFF; + fm->chip_id = 0x6620; + fm->tx_pwr = FMTX_PWR_LEVEL_MAX; + + if ((err = fm_setup_cdev(fm))){ + FM_LOG_ERR(D_INIT,"fm_setup_cdev() failed\n"); + goto setup_cdev_err; + } + + init_waitqueue_head(&fm->read_wait); + if (!(fm->pstRDSData = kmalloc(sizeof(RDSData_Struct), GFP_KERNEL))){ + FM_LOG_ERR(D_INIT,"-ENOMEM for RDS\n"); + err = -ENOMEM; + goto alloc_rds_err; + } + + fm->fm_workqueue = create_singlethread_workqueue("fm_workqueue"); + if(!fm->fm_workqueue){ + FM_LOG_ERR(D_INIT,"-ENOMEM for fm_workqueue\n"); + err = -ENOMEM; + goto rx_wq_err; + } + + + fm->fm_timer_workqueue = create_singlethread_workqueue("fm_timer_workqueue"); + if(!fm->fm_timer_workqueue){ + FM_LOG_ERR(D_INIT,"-ENOMEM for fm_timer_workqueue\n"); + err = -ENOMEM; + goto rds_reset_wq_err; + } + + + INIT_WORK(&fm->fm_rx_work, fm_rx_worker_func); + INIT_WORK(&fm->fm_rds_reset_work, fm_rds_reset_worker_func); + INIT_WORK(&fm->fm_tx_power_ctrl_work, fm_tx_power_ctrl_worker_func); + INIT_WORK(&fm->fm_tx_rtc_ctrl_work, fm_tx_rtc_ctrl_worker_func); + INIT_WORK(&fm->fm_tx_desense_wifi_work, fm_tx_desense_wifi_worker_func); + INIT_WORK(&fm->fm_rst_recover_work, fm_rst_recover_worker_func); + INIT_WORK(&fm->fm_subsys_recover_work, fm_subsys_recover_worker_func); + + fm_cb = fm; + + fm_rtc_compensation_init(fm_cb, &gps_rtc_info); + fm_timer_init(fm_cb, &timer_sys, &fm_timer); + + /*Add porc file system*/ + g_fm_proc = create_proc_entry(FM_PROC_FILE, 0666, NULL); + if (g_fm_proc == NULL){ + FM_LOG_ERR(D_INIT,"create_proc_entry failed\n"); + err = -ENOMEM; + goto rds_reset_wq_err; + }else{ + g_fm_proc->read_proc = fm_proc_read; + g_fm_proc->write_proc = fm_proc_write; + FM_LOG_NTC(D_INIT,"create_proc_entry success\n"); + } + + /*Add fm config porc file*/ + g_fm_config.proc = create_proc_entry(FM_PROC_CONFIG, 0666, NULL); + if (g_fm_config.proc == NULL){ + FM_LOG_ERR(D_INIT,"create_config_entry failed\n"); + err = -ENOMEM; + goto rds_reset_wq_err; + }else{ + g_fm_config.proc->read_proc = fmconfig_proc_read; + g_fm_config.proc->write_proc = fmconfig_proc_write; + FM_LOG_NTC(D_INIT,"create_config_entry success\n"); + } + + g_fm_config.vcooff = FM_TX_VCO_OFF_DEFAULT; //TX RTC VCO tracking interval(s) + g_fm_config.vcoon = FM_TX_VCO_ON_DEFAULT; //TX VCO tracking ON duiration(ms) + g_fm_config.rdsrst = FM_RDS_RST_INVAL_DEFAULT; //RDS RX Good/Bad block reset interval(s) + g_fm_config.txpwrctl = FM_TX_PWR_CTRL_INVAL_DEFAULT; //TX power contrl interval(s) + g_fm_config.timer = FM_TIMER_TIMEOUT_DEFAULT; //FM timer system time out interval(ms) + + err = fm_print_cfg_info(fm, NULL); + if(err){ + FM_LOG_ERR(D_INIT,"print fm cfg info failed\n"); + } + return 0; + +rds_reset_wq_err: + destroy_workqueue(fm->fm_workqueue); + +rx_wq_err: + kfree(fm->pstRDSData); + +alloc_rds_err: + cdev_del(&fm->cdev); + +setup_cdev_err: + kfree(tx_buf); + +tx_alloc_err: + kfree(fm); + +fm_alloc_err: + return err; +} + +static int fm_destroy(struct fm *fm) +{ + int err = 0; + + FM_LOG_NTC(D_INIT, "%s\n", __func__); + remove_proc_entry(FM_PROC_CONFIG, NULL); + remove_proc_entry(FM_PROC_FILE, NULL); + + if(NULL == fm){ + FM_LOG_ERR(D_INIT,"%s Invalid pointer fm\n", __func__); + err = -1; + } + del_timer(&fm_timer); + cdev_del(&fm->cdev); + unregister_chrdev_region(fm->dev_t, 1); + + flush_scheduled_work(); + + // FIXME: any other hardware configuration ? + + if(fm->fm_timer_workqueue){ + destroy_workqueue(fm->fm_timer_workqueue); + } + + if(fm->fm_workqueue){ + destroy_workqueue(fm->fm_workqueue); + } + + if (fm->pstRDSData){ + kfree(fm->pstRDSData); + fm->pstRDSData = NULL; + } + + // free all memory + if(fm_cxt){ + kfree(fm_cxt); + fm_cxt = NULL; + } + + if(tx_buf){ + kfree(tx_buf); + tx_buf = NULL; + } + + if(fm){ + kfree(fm); + } + fm_cb = NULL; + return err; +} + +static int do_cmd_send(struct fm *fm, unsigned char *buf, int len, int opcode, void* data){ + int ret = 0; + int pkt_size = 0; + + if (down_interruptible(&fm_cmd_mutex)){ + FM_LOG_ERR(D_MAIN,"%s(): get mutex failed\n", __func__); + ret = -ERR_GET_MUTEX; + return ret; + } + + //special defined cmd + if(buf && (len > 4) && (len < TX_BUF_SIZE)){ + FM_LOG_NTC(D_MAIN,"sending special cmd[len=%d]\n", len); + ret = fm_send_wait_timeout(buf, (uint16_t)len, + FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT); + if(ret){ + FM_LOG_ERR(D_MAIN,"send special cmd failed\n"); + goto out; + } + } + + //additional cmd for normal case + if(tx_buf == NULL){ + FM_LOG_ERR(D_MAIN,"%s(): invalid tx_buf\n", __func__); + ret = -ERR_INVALID_BUF; + goto out; + } + memset(tx_buf, 0, TX_BUF_SIZE); + pkt_size = mt6620_com(tx_buf, TX_BUF_SIZE, opcode, NULL); + if(pkt_size < 0){ + FM_LOG_ERR(D_MAIN,"unsupported cmd\n"); + goto out; + } + FM_LOG_NTC(D_MAIN,"sending additional cmd[len=%d]\n", pkt_size); + ret = fm_send_wait_timeout(tx_buf, (uint16_t)pkt_size, + FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT); + if(ret){ + FM_LOG_ERR(D_MAIN,"send additional cmd failed\n"); + } + +out: + up(&fm_cmd_mutex); + return ret; +} + +/* + * fm_powerup + */ +static int fm_powerup(struct fm *fm, struct fm_tune_parm *parm) +{ + int ret = 0; + uint16_t pkt_size = 0; + + if(FM_PWR_RX_ON == fm->powerup){ + //FM RX already on + FM_LOG_NTC(D_MAIN,"%s, FM Rx already powered up\n", __func__); + parm->err = FM_BADSTATUS; + return 0; + }else if(FM_PWR_TX_ON == fm->powerup){ + //if Tx is on, we need pwr down TX first + ret = fm_powerdown(fm, FM_TX); + if(ret){ + FM_LOG_ERR(D_MAIN,"FM pwr down Tx fail!\n"); + return ret; + } + } + + //We should make chip on first before do Power on + if (FALSE == fm->chipon){ + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_FM)){ + FM_LOG_ERR(D_MAIN,"WMT turn on FM fail!\n"); + return -ENODEV; + } + FM_LOG_NTC(D_MAIN,"WMT turn on FM OK!\n"); + fm->chipon = TRUE; + } + + FM_LOG_INF(D_MAIN,"+MT6620 power on procedure\n"); + if (down_interruptible(&fm_cmd_mutex)){ + FM_LOG_ERR(D_MAIN,"%s(): get mutex failed\n", __func__); + ret = -ERR_GET_MUTEX; + return ret; + } + + if(tx_buf == NULL){ + FM_LOG_ERR(D_MAIN,"%s(): invalid tx_buf\n", __func__); + ret = -ERR_INVALID_BUF; + goto release_mutex; + } + memset(tx_buf, 0, TX_BUF_SIZE); + + pkt_size = mt6620_off_2_longANA(tx_buf, TX_BUF_SIZE); + ret = fm_send_wait_timeout(tx_buf, pkt_size, + FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT); + if(ret){ + FM_LOG_ERR(D_MAIN,"%s(): mt6620_off_2_longANA failed\n", __func__); + goto release_mutex; + } + + pkt_size = mt6620_rx_digital_init(tx_buf, TX_BUF_SIZE); + ret = fm_send_wait_timeout(tx_buf, pkt_size, + FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT); + if(ret){ + FM_LOG_ERR(D_MAIN,"%s(): mt6620_rx_digital_init failed\n", __func__); + goto release_mutex; + } + +release_mutex: + up(&fm_cmd_mutex); + + if(ret) + return ret; + +#ifdef FM_DIGITAL_INPUT + #ifdef MT6573 //for MT6573 + if(get_chip_eco_ver() == CHIP_E1){ + ret = MT6620_I2S_Setting(FM_I2S_ON, FM_I2S_MASTER, FM_I2S_48K); + }else{ + ret = MT6620_I2S_Setting(FM_I2S_ON, FM_I2S_SLAVE, FM_I2S_48K); + } + #else //for MT6575 + ret = MT6620_I2S_Setting(FM_I2S_ON, FM_I2S_SLAVE, FM_I2S_48K); + #endif + if(ret){ + FM_LOG_ERR(D_MAIN,"pwron set I2S on error\n"); + return ret; + } + //we will disable 6620 fm chip analog output when use I2S path, set 0x3A bit2 = 0 + //MT6620_set_bits(0x3A, 0, MASK(2)); + FM_LOG_DBG(D_MAIN,"pwron set I2S on ok\n"); +#endif + + FM_LOG_INF(D_MAIN,"-MT6620 power on procedure\n"); + FM_LOG_NTC(D_MAIN,"pwron RX ok\n"); + + fm->powerup = FM_PWR_RX_ON; + fm_cxt->powerup = FM_PWR_RX_ON; + ret = down_interruptible(&fm_timer_mutex); + if(ret){ + FM_LOG_ERR(D_MAIN,"down fm_timer_mutex failed[ret=%d]\n", ret); + goto out; + } + timer_sys.onoff = FM_TIMER_SYS_ON; + //update timer + if(g_fm_config.timer < 1000){ + FM_LOG_WAR(D_TIMER,"timersys time err\n"); + g_fm_config.timer = FM_TIMER_TIMEOUT_DEFAULT; + } + mod_timer(&fm_timer, jiffies + g_fm_config.timer/(1000/HZ)); + up(&fm_timer_mutex); + //Tune to desired channel + if ((ret = fm_tune(fm, parm))){ + FM_LOG_ERR(D_MAIN,"Power on RX tune failed\n"); + return ret; + } + parm->err = FM_SUCCESS; + +out: + return ret; +} + +static int fm_antenna_switch(struct fm *fm, int antenna) +{ + int ret = 0; + + ret = MT6620_ANA_SWITCH(antenna); + if(ret){ + FM_LOG_ERR(D_MAIN,"Switch antenna failed\n"); + } + fm_cxt->rxcxt.ana = antenna; + FM_LOG_DBG(D_MAIN,"%s(),[ret=%d]!\n", __func__, ret); + return ret; +} + +/* + * fm_powerup_tx + */ +static int fm_powerup_tx(struct fm *fm, struct fm_tune_parm *parm) +{ + int ret = 0; + uint16_t pkt_size = 0; + + if(FM_PWR_TX_ON == fm->powerup){ + //FM TX already on + FM_LOG_NTC(D_MAIN,"%s, FM Tx already powered up\n", __func__); + parm->err = FM_BADSTATUS; + return 0; + }else if(FM_PWR_RX_ON == fm->powerup){ + //if Rx is on, we need pwr down RX first + ret = fm_powerdown(fm, FM_RX); + if(ret){ + FM_LOG_ERR(D_MAIN,"FM pwr down Rx fail!\n"); + return ret; + } + } + //for normal case + if (FALSE == fm->chipon){ + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_FM)) { + FM_LOG_ERR(D_MAIN,"WMT turn on FM fail!\n"); + return -ENODEV; + } + FM_LOG_DBG(D_MAIN,"WMT turn on FM OK!\n"); + fm->chipon = TRUE; + } + + FM_LOG_INF(D_MAIN,"+MT6620 power on tx procedure\n"); + if (down_interruptible(&fm_cmd_mutex)){ + FM_LOG_ERR(D_MAIN,"%s(): get mutex failed\n", __func__); + ret = -ERR_GET_MUTEX; + return ret; + } + + if(tx_buf == NULL){ + FM_LOG_ERR(D_MAIN,"%s(): invalid tx_buf\n", __func__); + ret = -ERR_INVALID_BUF; + goto release_mutex; + } + memset(tx_buf, 0, TX_BUF_SIZE); + + pkt_size = mt6620_off_2_tx_shortANA(tx_buf, TX_BUF_SIZE); + ret = fm_send_wait_timeout(tx_buf, pkt_size, + FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT); + if(ret){ + FM_LOG_ERR(D_MAIN,"%s(): mt6620_off_2_tx_shortANA failed\n", __func__); + goto release_mutex; + } + + pkt_size = mt6620_dig_init(tx_buf, TX_BUF_SIZE); + ret = fm_send_wait_timeout(tx_buf, pkt_size, + FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT); + if(ret){ + FM_LOG_ERR(D_MAIN,"%s(): mt6620_dig_init failed\n", __func__); + goto release_mutex; + } +release_mutex: + up(&fm_cmd_mutex); + + if(ret) + return ret; + + FM_LOG_INF(D_MAIN,"-MT6620 power on tx procedure\n"); + FM_LOG_NTC(D_MAIN,"pwron tx ok\n"); + + fm->powerup = FM_PWR_TX_ON; + fm_cxt->powerup = FM_PWR_TX_ON; + ret = down_interruptible(&fm_timer_mutex); + if(ret){ + FM_LOG_ERR(D_MAIN,"down fm_timer_mutex failed[ret=%d]\n", ret); + goto out; + } + //update timer + if(g_fm_config.timer < 1000){ + FM_LOG_WAR(D_TIMER,"timersys time err\n"); + g_fm_config.timer = FM_TIMER_TIMEOUT_DEFAULT; + } + mod_timer(&fm_timer, jiffies + g_fm_config.timer/(1000/HZ)); + timer_sys.onoff = FM_TIMER_SYS_ON; + timer_sys.tx_pwr_ctrl_en = FM_TX_PWR_CTRL_ENABLE; + timer_sys.tx_rtc_ctrl_en = FM_TX_RTC_CTRL_ENABLE; + timer_sys.tx_desense_en = FM_TX_DESENSE_ENABLE; + up(&fm_timer_mutex); + //get temprature + if(mtk_wcn_wmt_therm_ctrl(WMTTHERM_ENABLE) != TRUE){ + FM_LOG_ERR(D_MAIN,"wmt_therm_ctrl, WMTTHERM_ENABLE failed\n"); + ret = -ERR_STP; + return ret; + } + if ((ret = fm_tune_tx(fm, parm))){ + FM_LOG_ERR(D_MAIN,"PowerUp Tx(), tune failed\n"); + return ret; + } + +#ifdef FM_DIGITAL_OUTPUT + #ifdef MT6573 //for MT6573 + if(get_chip_eco_ver() == CHIP_E1){ + ret = MT6620_I2S_Setting(FM_I2S_ON, FM_I2S_SLAVE, FM_I2S_48K); + }else{ + ret = MT6620_I2S_Setting(FM_I2S_ON, FM_I2S_SLAVE, FM_I2S_48K); + } + #else // for MT6575 + ret = MT6620_I2S_Setting(FM_I2S_ON, FM_I2S_SLAVE, FM_I2S_48K); + #endif + if(ret){ + FM_LOG_ERR(D_MAIN,"pwron Tx set I2S on error\n"); + return ret; + } + FM_LOG_DBG(D_MAIN,"pwron Tx set I2S on ok\n"); +#endif + + parm->err = FM_SUCCESS; + +out: + return ret; +} +/* + * fm_powerdown + */ +static int fm_powerdown(struct fm *fm, int type) +{ + int ret = 0; + uint16_t pkt_size = 0; + + FM_LOG_DBG(D_MAIN,"%s \n", __func__); + + if(down_interruptible(&fm_rxtx_mutex)){ + FM_LOG_ERR(D_TIMER, "%s(): get rx/tx mutex failed\n", __func__); + return -ERR_GET_MUTEX; + } + + if(((fm->powerup == FM_PWR_TX_ON) && (type == FM_RX)) || ((fm->powerup == FM_PWR_RX_ON) && (type == FM_TX))){ + FM_LOG_NTC(D_MAIN,"no need do pwr down\n"); + ret = 0; + goto out; + } + +#if (defined(FM_DIGITAL_INPUT) || defined(FM_DIGITAL_OUTPUT)) + if(MT6620_I2S_Setting(FM_I2S_OFF, FM_I2S_MASTER, FM_I2S_48K)){ + FM_LOG_ERR(D_MAIN,"pwrdown set I2S off error\n"); + goto out; + } + //MT6620_set_bits(0x3A, BITn(2), MASK(2)); + FM_LOG_DBG(D_MAIN,"pwrdown set I2S off ok\n"); +#endif + + if (down_interruptible(&fm_cmd_mutex)){ + FM_LOG_ERR(D_CMD|D_ALL, "%s(): get mutex failed\n", __func__); + ret = -ERR_GET_MUTEX; + goto out; + } + if(tx_buf == NULL){ + FM_LOG_ERR(D_MAIN,"invalid tx_buf\n"); + up(&fm_cmd_mutex); + goto out; + } + memset(tx_buf, 0, TX_BUF_SIZE); + pkt_size = mt6620_powerdown(tx_buf, TX_BUF_SIZE); + ret = fm_send_wait_timeout(tx_buf, pkt_size, + FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT); + up(&fm_cmd_mutex); + FM_LOG_INF(D_CMD,"+fm_cmd_mutex\n"); + if(ret){ + FM_LOG_ERR(D_MAIN,"%s(): pwrdown failed\n", __func__); + goto out; + } + + ret = down_interruptible(&fm_timer_mutex); + if(ret){ + FM_LOG_ERR(D_MAIN,"down fm_timer_mutex failed[ret=%d]\n", ret); + goto out; + } + timer_sys.onoff = FM_TIMER_SYS_OFF; + timer_sys.rds_reset_en = FM_RDS_RST_DISABLE; + timer_sys.tx_pwr_ctrl_en = FM_TX_PWR_CTRL_DISABLE; + timer_sys.tx_rtc_ctrl_en = FM_TX_RTC_CTRL_DISABLE; + timer_sys.tx_desense_en = FM_TX_DESENSE_DISABLE; + up(&fm_timer_mutex); + if(fm->powerup == FM_PWR_TX_ON){ + if(mtk_wcn_wmt_therm_ctrl(WMTTHERM_DISABLE) != TRUE){ + FM_LOG_ERR(D_MAIN,"wmt_therm_ctrl, WMTTHERM_DISABLE failed\n"); + ret = -ERR_STP; + } + } + fm->RDS_Data_ready = true; //info FM APP to stop read RDS + memset(fm->pstRDSData, 0, sizeof(RDSData_Struct)); + wake_up_interruptible(&fm->read_wait); + fm->powerup = FM_PWR_OFF; + fm_cxt->powerup = FM_PWR_OFF; + FM_LOG_NTC(D_MAIN,"pwrdown %s ok\n", (type==FM_TX)? "TX" : "RX"); +out: + up(&fm_rxtx_mutex); + return ret; +} + +/* + * fm_seek + */ +static int fm_seek(struct fm *fm, struct fm_seek_parm *parm) +{ + int ret = 0; + uint16_t seekdir, space; + + if (!fm->powerup){ + parm->err = FM_BADSTATUS; + return -EPERM; + } + + if (parm->space == FM_SPACE_100K){ + space = MT6620_FM_SPACE_100K; + }else if (parm->space == FM_SPACE_200K) { + space = MT6620_FM_SPACE_200K; + }else{ + //default + space = MT6620_FM_SPACE_100K; + } + + if (parm->band == FM_BAND_UE){ + fm->min_freq = 875; + fm->max_freq = 1080; + }else if (parm->band == FM_BAND_JAPAN){ + fm->min_freq = 760; + fm->max_freq = 900; + }else if (parm->band == FM_BAND_JAPANW){ + fm->min_freq = 760; + fm->max_freq = 1080; + }else if(parm->band == FM_BAND_SPECIAL){ + fm->min_freq = FMR_BAND_FREQ_L; + fm->max_freq = FMR_BAND_FREQ_H; + }else{ + FM_LOG_ERR(D_MAIN,"band:%d out of range\n", parm->band); + parm->err = FM_EPARM; + return -EPERM; + } + + if (parm->freq < fm->min_freq || parm->freq > fm->max_freq){ + FM_LOG_ERR(D_MAIN,"freq:%d out of range\n", parm->freq); + parm->err = FM_EPARM; + return -EPERM; + } + + if (parm->seekdir == FM_SEEK_UP){ + seekdir = MT6620_FM_SEEK_UP; + }else{ + seekdir = MT6620_FM_SEEK_DOWN; + } + +#ifdef FMDEBUG + if (parm->seekdir == FM_SEEK_UP) + FM_LOG_DBG(D_MAIN,"seek %d up\n", parm->freq); + else + FM_LOG_DBG(D_MAIN,"seek %d down\n", parm->freq); +#endif + + // seek successfully + if(!(ret = MT6620_Seek(fm->min_freq, fm->max_freq, &(parm->freq), seekdir, space))){ + parm->err = FM_SUCCESS; + }else{ + parm->err = FM_SEEK_FAILED; + } + + //ret = do_cmd_send(fm, NULL, 0, FM_COM_CMD_SEEK, NULL); + + return ret; +} + +/* + * fm_scan + */ +static int fm_scan(struct fm *fm, struct fm_scan_parm *parm) +{ + int ret = 0; + uint16_t scandir = MT6620_FM_SCAN_UP, space; + + if (!fm->powerup){ + parm->err = FM_BADSTATUS; + return -EPERM; + } + + if (parm->space == FM_SPACE_100K){ + space = MT6620_FM_SPACE_100K; + }else if (parm->space == FM_SPACE_200K) { + space = MT6620_FM_SPACE_200K; + }else{ + //default + space = MT6620_FM_SPACE_100K; + } + + if(parm->band == FM_BAND_UE){ + fm->min_freq = 875; + fm->max_freq = 1080; + }else if(parm->band == FM_BAND_JAPAN){ + fm->min_freq = 760; + fm->max_freq = 900; + }else if(parm->band == FM_BAND_JAPANW){ + fm->min_freq = 760; + fm->max_freq = 1080; + }else if(parm->band == FM_BAND_SPECIAL){ + fm->min_freq = FMR_BAND_FREQ_L; + fm->max_freq = FMR_BAND_FREQ_H; + }else{ + FM_LOG_ERR(D_ALL,"fm_scan band:%d out of range\n", parm->band); + parm->err = FM_EPARM; + return -EPERM; + } + + if(!(ret = MT6620_Scan(fm->min_freq, fm->max_freq, &(parm->freq), + parm->ScanTBL, &(parm->ScanTBLSize), scandir, space))){ + parm->err = FM_SUCCESS; + }else{ + FM_LOG_ERR(D_MAIN,"fm_scan failed\n"); + parm->err = FM_SEEK_FAILED; + } + + return ret; +} + +/* + * fm_get_rssi_after_scan + * + * get the rssi per channel, we need only use fast tune instead of normal tune to save time + * @fm -- main data struct of fm driver + * @req -- input freq, and output rssi + * + */ +static int fm_get_rssi_after_scan(struct fm *fm, struct fm_rssi_req *req) +{ + int ret = 0; + int i, j; + int tmp = 0; + int total = 0; + + req->num = (req->num > sizeof(req->cr)) ? sizeof(req->cr) : req->num; + for(i = 0; i < req->num; i++){ + ret = MT6620_Fast_SetFreq(req->cr[i].freq); + if(ret) + return ret; + //get rssi, if need multi read, do it and get the average val + req->read_cnt = (req->read_cnt < 1) ? 1 : req->read_cnt; + req->read_cnt = (req->read_cnt > 10) ? 10 : req->read_cnt; + tmp = 0; + total = 0; + for(j = 0; j < req->read_cnt; j++){ + ret = MT6620_GetCurRSSI(&tmp); + if(ret) + return ret; + Delayms(2); + total += tmp; + } + req->cr[i].rssi = total/req->read_cnt; + } + + return ret; +} + +static int fm_get_hw_info(struct fm *pfm, struct fm_hw_info *req) +{ + int ret = 0; + ENUM_WMTHWVER_TYPE_T eco_ver; + + eco_ver = mtk_wcn_wmt_hwver_get(); + req->chip_id = 0x00006620; + req->eco_ver = (int)eco_ver; + req->rom_ver = 0x00000002; + req->patch_ver = 0x00000111; + req->reserve = 0x00000000; + + return ret; +} + +//volume?[0~15] +static int fm_setvol(struct fm *fm, uint32_t vol) +{ + uint8_t tmp_vol; + int ret = 0; + + tmp_vol = vol*3; + ret = MT6620_SetVol(tmp_vol); + fm_cxt->rxcxt.vol = vol; + + return ret; +} + +static int fm_getvol(struct fm *fm, uint32_t *vol) +{ + uint8_t tmp_vol; + int ret = 0; + + ret = MT6620_GetVol(&tmp_vol); + if(tmp_vol == FM_VOL_MAX) + *vol = 15; + else + *vol = (tmp_vol/3); + + return ret; +} + +static int fm_getrssi(struct fm *fm, int *rssi) +{ + int ret = 0; + + ret = MT6620_GetCurRSSI(rssi); + + return ret; +} + +/* + * fm_print_curCQI -- print cur freq's CQI + * @cur_freq, current frequency + * If OK, return 0, else error code + */ +static int fm_print_curCQI(uint16_t cur_freq) +{ + int ret = 0; + uint16_t rssi = 0; + uint16_t pamd = 0; + uint16_t mr = 0; + + if((ret = MT6620_write(FM_PGSEL, FM_PG0))) + return ret; + if((ret = MT6620_read(FM_RSSI_IND, &rssi))) + return ret; + if((ret = MT6620_read(FM_PAMD_IND, &pamd))) + return ret; + if((ret = MT6620_read(FM_MR_IND, &mr))) + return ret; + + FM_LOG_NTC(D_MAIN,"FREQ=%d, RSSI=0x%04x, PAMD=0x%04x, MR=0x%04x\n", (int)cur_freq, rssi, pamd, mr); + return ret; +} + +/* + * fm_tune + */ +static int fm_tune(struct fm *fm, struct fm_tune_parm *parm) +{ + int ret = 0; + int hl_side = -1; + int freq_avoid = -1; + ENUM_WMTHWVER_TYPE_T hw_ver; + + FM_LOG_DBG(D_MAIN,"%s\n", __func__); + + if (!fm->powerup){ + parm->err = FM_BADSTATUS; + return -ERR_INVALID_PARA; + } + + if (parm->band == FM_BAND_UE){ + fm->min_freq = 875; + fm->max_freq = 1080; + }else if (parm->band == FM_BAND_JAPAN){ + fm->min_freq = 760; + fm->max_freq = 900; + }else if (parm->band == FM_BAND_JAPANW){ + fm->min_freq = 760; + fm->max_freq = 1080; + }else{ + parm->err = FM_EPARM; + return -ERR_INVALID_PARA; + } + fm->band = parm->band; + + if (unlikely(parm->freq < fm->min_freq || parm->freq > fm->max_freq)){ + parm->err = FM_EPARM; + return -ERR_INVALID_PARA; + } + + if((ret = MT6620_RampDown())) + return ret; + + //high low side switch + //adpll freq avoid + //mcu freq avoid + if(priv.state == INITED){ + FM_LOG_INF(D_MAIN,"%s, hl_side switch[0x%08x]\n", __func__, (unsigned int)priv.priv_tbl.hl_side); + if(priv.priv_tbl.hl_side != NULL){ + if((ret = priv.priv_tbl.hl_side(parm->freq, &hl_side))) + return ret; + } + FM_LOG_NTC(D_MAIN,"%s, [hl_side=%d]\n", __func__, hl_side); + + FM_LOG_INF(D_MAIN,"%s, adpll freq avoid[0x%08x]\n", __func__, (unsigned int)priv.priv_tbl.adpll_freq_avoid); + if(priv.priv_tbl.adpll_freq_avoid != NULL){ + if((ret = priv.priv_tbl.adpll_freq_avoid(parm->freq, &freq_avoid))) + return ret; + } + FM_LOG_NTC(D_MAIN,"%s, adpll [freq_avoid=%d]\n", __func__, freq_avoid); + + hw_ver = mtk_wcn_wmt_hwver_get(); + if(hw_ver >= WMTHWVER_MT6620_E3){ + FM_LOG_INF(D_MAIN,"%s, mcu freq avoid[0x%08x]\n", __func__, (unsigned int)priv.priv_tbl.mcu_freq_avoid); + if(priv.priv_tbl.mcu_freq_avoid != NULL){ + if((ret = priv.priv_tbl.mcu_freq_avoid(parm->freq, &freq_avoid))) + return ret; + } + FM_LOG_NTC(D_MAIN,"%s, mcu [freq_avoid=%d]\n", __func__, freq_avoid); + }else{ + FM_LOG_NTC(D_MAIN,"%s, no need do mcu freq avoid[hw_ver=%d]\n", __func__, hw_ver); + } + } + + ret = MT6620_SetFreq(parm->freq); + + ret = fm_print_curCQI(_current_frequency); + + return ret; +} + +/* + * fm_tune_tx + */ +static int fm_tune_tx(struct fm *fm, struct fm_tune_parm *parm) +{ + int ret = 0; + FM_LOG_DBG(D_MAIN,"%s\n", __func__); + + if (!fm->powerup){ + parm->err = FM_BADSTATUS; + return -EPERM; + } + + if (parm->band == FM_BAND_UE){ + fm->min_freq = 875; + fm->max_freq = 1080; + }else if (parm->band == FM_BAND_JAPAN){ + fm->min_freq = 760; + fm->max_freq = 900; + }else if (parm->band == FM_BAND_JAPANW){ + fm->min_freq = 760; + fm->max_freq = 1080; + }else{ + parm->err = FM_EPARM; + return -ERR_INVALID_PARA; + } + + if (unlikely(parm->freq < fm->min_freq || parm->freq > fm->max_freq)){ + parm->err = FM_EPARM; + return -ERR_INVALID_PARA; + } + + //we will do rampdown in tune sequence, it's do nothing here + while(0){ + if((ret = MT6620_RampDown_Tx())) + return ret; + } + + //tune to desired channel + ret = MT6620_SetFreq_Tx(parm->freq); + return ret; +} + +/*********************************************************** +Function: fm_tx_scan() + +Description: get the valid channels for fm tx function + +Para: fm--->fm driver global info + parm--->input/output paramater + +Return: 0, if success; error code, if failed +***********************************************************/ +static int fm_tx_scan(struct fm *fm, struct fm_tx_scan_parm *parm) +{ + int ret = 0; + uint16_t scandir = 0; + uint16_t space = FM_SPACE_100K; + + if (!fm->powerup){ + parm->err = FM_BADSTATUS; + FM_LOG_ERR(D_ALL,"fm_tx_scan failed, [fm->powerup=%d]\n", fm->powerup); + return -EPERM; + } + + if(FM_TX_SUPPORT != atomic_read(&fm->tx_support)){ + parm->err = FM_BADSTATUS; + FM_LOG_ERR(D_ALL,"fm_tx_scan failed, [fm->tx_support=%d]\n", atomic_read(&fm->tx_support)); + return -EPERM; + } + + switch(parm->scandir){ + case MT6620_FM_SCAN_UP: + scandir = 0; + break; + case MT6620_FM_SCAN_DOWN: + scandir = 1; + break; + default: + scandir = 0; + break; + } + + switch(parm->space){ + case FM_SPACE_100K: + space = 1; + break; + case FM_SPACE_200K: + space = 2; + break; + default: + space = 1; + break; + } + + switch(parm->band){ + case FM_BAND_UE: + fm->min_freq = 875; + fm->max_freq = 1080; + break; + case FM_BAND_JAPAN: + fm->min_freq = 760; + fm->max_freq = 900; + break; + case FM_BAND_JAPANW: + fm->min_freq = 760; + fm->max_freq = 1080; + break; + default: + parm->err = FM_EPARM; + FM_LOG_ERR(D_ALL,"fm_tx_scan: bad band para\n"); + return -EPERM; + break; + } + + if (unlikely((parm->freq < fm->min_freq) || (parm->freq > fm->max_freq))){ + parm->err = FM_EPARM; + return -EPERM; + } + + if (unlikely(parm->ScanTBLSize < TX_SCAN_MIN || parm->ScanTBLSize > TX_SCAN_MAX)){ + parm->err = FM_EPARM; + return -EPERM; + } + + //make sure use short antenna, and you can't use "fm_antenna_switch()" because it will record ana context for RX + ret = MT6620_ANA_SWITCH(FM_SHORT_ANA); + if(ret){ + FM_LOG_ERR(D_MAIN,"switch to short ana failed\n"); + return ret; + } + + //do tx scan + if(!(ret = MT6620_TxScan(fm->min_freq, fm->max_freq, &(parm->freq), + parm->ScanTBL, &(parm->ScanTBLSize), scandir, space))){ + parm->err = FM_SUCCESS; + }else{ + FM_LOG_ERR(D_MAIN,"fm_tx_scan failed\n"); + parm->err = FM_SCAN_FAILED; + } + return ret; +} + +static int fm_rds_tx(struct fm *fm, struct fm_rds_tx_parm *parm) +{ + int ret = 0; + FM_LOG_DBG(D_RDS,"+%s()\n", __func__); + if(parm->other_rds_cnt > 29){ + parm->err = FM_EPARM; + FM_LOG_WAR(D_RDS,"%s(), [other_rds_cnt=%d]\n", __func__, parm->other_rds_cnt); + ret = -ERR_INVALID_PARA; + goto out; + } + + ret = MT6620_Rds_Tx_Enable(1); + if(ret){ + FM_LOG_WAR(D_RDS,"%s(), MT6620_Rds_Tx_Enable failed!\n", __func__); + goto out; + } + ret = MT6620_Rds_Tx(parm->pi, parm->ps, parm->other_rds, parm->other_rds_cnt); + fm_cxt->txcxt.rdsTxOn = true; + fm_cxt->txcxt.pi = parm->pi; + memcpy(fm_cxt->txcxt.ps, parm->ps,sizeof(parm->ps)); + memcpy(fm_cxt->txcxt.other_rds, parm->other_rds,sizeof(parm->other_rds)); + fm_cxt->txcxt.other_rds_cnt = parm->other_rds_cnt; +out: + FM_LOG_DBG(D_RDS,"-%s()\n", __func__); + return ret; +} + +static int fm_over_bt(struct fm *fm, int enable) +{ + int ret = 0; + + ret = MT6620_FMOverBT(enable); + if(ret){ + FM_LOG_WAR(D_MAIN,"%s(),failed!\n", __func__); + } + fm_cxt->rxcxt.ViaBt = enable; + FM_LOG_DBG(D_MAIN,"%s(),[ret=%d]!\n", __func__, ret); + return ret; +} + +static int fm_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int cnt = 0; + struct fm *fm = fm_cb; + + FM_LOG_DBG(D_MAIN, "Enter fm_proc_read.\n"); + if(off != 0) + return 0; + if (fm != NULL && fm->chipon){ + if(fm->powerup == FM_PWR_TX_ON){ + cnt = sprintf(page, "2\n"); + }else if(fm->powerup == FM_PWR_RX_ON){ + cnt = sprintf(page, "1\n"); + } + } else { + cnt = sprintf(page, "0\n"); + } + *eof = 1; + FM_LOG_DBG(D_MAIN, "Leave fm_proc_read. FM_on = %s\n", page); + return cnt; +} + +static int fm_proc_write(struct file *file, const char *buffer, unsigned long count, void *data) +{ + char tmp_buf[11] = {0}; + uint32_t copysize; + + copysize = (count < (sizeof(tmp_buf) - 1)) ? count : (sizeof(tmp_buf) - 1); + if (copy_from_user(tmp_buf, buffer, copysize)){ + FM_LOG_ERR(D_ALL, "failed copy_from_user\n"); + return -EFAULT; + } + + if (sscanf(tmp_buf, "%x", &g_dbg_level) != 1){ + FM_LOG_ERR(D_ALL, "failed g_dbg_level = 0x%x\n", g_dbg_level); + return -EFAULT; + } + + FM_LOG_WAR(D_MAIN, "success g_dbg_level = 0x%x\n", g_dbg_level); + return count; +} + +static int fmconfig_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int cnt = 0; + //struct fm *fm = fm_cb; + + FM_LOG_DBG(D_MAIN, "Enter fm_config_proc_read.\n"); + if(off != 0) + return 0; + cnt = sprintf(page, "[t]timerSys: %d ms\n", g_fm_config.timer); + cnt += sprintf(page+cnt, "[v]vcoOff: %d s\n", g_fm_config.vcooff); + cnt += sprintf(page+cnt, "[v]vcoOn: %d ms\n", g_fm_config.vcoon); + cnt += sprintf(page+cnt, "[p]pwrctlTx: %d s\n", g_fm_config.txpwrctl); + cnt += sprintf(page+cnt, "[r]rdsRst: %d s\n", g_fm_config.rdsrst); + *eof = 1; + FM_LOG_DBG(D_MAIN, "Leave fm_config_proc_read. Config = %s\n", page); + return cnt; +} + +static int fmconfig_proc_write(struct file *file, const char *buffer, unsigned long count, void *data) +{ + char tmp_buf[100] = {0}; + uint32_t copysize; + + copysize = (count < (sizeof(tmp_buf) - 1)) ? count : (sizeof(tmp_buf) - 1); + if (copy_from_user(tmp_buf, buffer, copysize)){ + FM_LOG_ERR(D_ALL, "failed copy_from_user\n"); + return -EFAULT; + } + + switch(tmp_buf[0]){ + case 'v': + switch(tmp_buf[1]){ + case 'u': + //FM TX vco tracking ON duiration setting + if (sscanf(&tmp_buf[2], "%d", &g_fm_config.vcoon) != 1){ + FM_LOG_ERR(D_ALL, "failed vcoon = %d\n", g_fm_config.vcoon); + return -EFAULT; + } + g_fm_config.vcoon = (g_fm_config.vcoon < FM_TX_VCO_ON_MIN) ? FM_TX_VCO_ON_MIN : g_fm_config.vcoon; + g_fm_config.vcoon = (g_fm_config.vcoon > FM_TX_VCO_ON_MAX) ? FM_TX_VCO_ON_MAX : g_fm_config.vcoon; + FM_LOG_WAR(D_MAIN, "success vcoon = %d\n", g_fm_config.vcoon); + break; + case 'd': + //FM TX vco tracking OFF duiration setting + if (sscanf(&tmp_buf[2], "%d", &g_fm_config.vcooff) != 1){ + FM_LOG_ERR(D_ALL, "failed vcooff = %d\n", g_fm_config.vcooff); + return -EFAULT; + } + g_fm_config.vcooff = (g_fm_config.vcooff < FM_TX_VCO_OFF_MIN) ? FM_TX_VCO_OFF_MIN : g_fm_config.vcooff; + g_fm_config.vcooff = (g_fm_config.vcooff > FM_TX_VCO_OFF_MAX) ? FM_TX_VCO_OFF_MAX : g_fm_config.vcooff; + FM_LOG_WAR(D_MAIN, "success vcooff = %d\n", g_fm_config.vcooff); + break; + default: + FM_LOG_ERR(D_MAIN, "Para 2 error\n"); + break; + } + break; + case 't': + if (sscanf(&tmp_buf[1], "%d", &g_fm_config.timer) != 1){ + FM_LOG_ERR(D_ALL, "failed timer = %d\n", g_fm_config.timer); + return -EFAULT; + } + g_fm_config.timer = (g_fm_config.timer < FM_TIMER_TIMEOUT_MIN) ? FM_TIMER_TIMEOUT_MIN : g_fm_config.timer; + g_fm_config.timer = (g_fm_config.timer > FM_TIMER_TIMEOUT_MAX) ? FM_TIMER_TIMEOUT_MAX : g_fm_config.timer; + FM_LOG_WAR(D_MAIN, "success timer = %d\n", g_fm_config.timer); + break; + case 'r': + if (sscanf(&tmp_buf[1], "%d", &g_fm_config.rdsrst) != 1){ + FM_LOG_ERR(D_ALL, "failed rdsrst = %d\n", g_fm_config.rdsrst); + return -EFAULT; + } + g_fm_config.rdsrst = (g_fm_config.rdsrst < FM_RDS_RST_INVAL_MIN) ? FM_RDS_RST_INVAL_MIN : g_fm_config.rdsrst; + g_fm_config.rdsrst = (g_fm_config.rdsrst > FM_RDS_RST_INVAL_MAX) ? FM_RDS_RST_INVAL_MAX : g_fm_config.rdsrst; + FM_LOG_WAR(D_MAIN, "success rdsrst = %d\n", g_fm_config.rdsrst); + break; + case 'p': + if (sscanf(&tmp_buf[1], "%d", &g_fm_config.txpwrctl) != 1){ + FM_LOG_ERR(D_ALL, "failed txpwrctl = %d\n", g_fm_config.txpwrctl); + return -EFAULT; + } + g_fm_config.txpwrctl = (g_fm_config.txpwrctl < FM_RDS_RST_INVAL_MIN) ? FM_RDS_RST_INVAL_MIN : g_fm_config.txpwrctl; + g_fm_config.txpwrctl = (g_fm_config.txpwrctl > FM_RDS_RST_INVAL_MAX) ? FM_RDS_RST_INVAL_MAX : g_fm_config.txpwrctl; + FM_LOG_WAR(D_MAIN, "success txpwrctl = %d\n", g_fm_config.txpwrctl); + break; + case 's': + fm_hw_reset(); + FM_LOG_WAR(D_MAIN, "do fm_hw_reset\n"); + break; + case 'm': + do_cmd_send(NULL, NULL, 0, FM_COM_CMD_TEST, NULL); + break; + default: + FM_LOG_ERR(D_MAIN, "Para 1 error\n"); + break; + } + return count; +} + +int fm_priv_register(struct fm_priv *pri, struct fm_op *op) +{ + int ret = 0; + //Basic functions. + + FM_LOG_NTC(D_INIT,"%s(), [pri=0x%08x][op=0x%08x]\n", __func__, (unsigned int)pri, (unsigned int)op); + FMR_ASSERT(pri); + FMR_ASSERT(op); + + priv.priv_tbl.hl_side = pri->priv_tbl.hl_side; + priv.priv_tbl.adpll_freq_avoid = pri->priv_tbl.adpll_freq_avoid; + priv.priv_tbl.mcu_freq_avoid = pri->priv_tbl.mcu_freq_avoid; + priv.priv_tbl.tx_pwr_ctrl = pri->priv_tbl.tx_pwr_ctrl; + priv.priv_tbl.rtc_drift_ctrl = pri->priv_tbl.rtc_drift_ctrl; + priv.priv_tbl.tx_desense_wifi = pri->priv_tbl.tx_desense_wifi; + priv.state = INITED; + priv.data = NULL; + + op->op_tbl.read = MT6620_read; + op->op_tbl.write = MT6620_write; + op->op_tbl.setbits = MT6620_set_bits; + op->op_tbl.rampdown = MT6620_RampDown; + op->state = INITED; + op->data = NULL; + + return ret; +} + +int fm_priv_unregister(struct fm_priv *pri, struct fm_op *op) +{ + int ret = 0; + //Basic functions. + + FM_LOG_NTC(D_INIT,"%s(), [pri=0x%08x][op=0x%08x]\n", __func__, (unsigned int)pri, (unsigned int)op); + + FMR_ASSERT(pri); + FMR_ASSERT(op); + + priv.priv_tbl.hl_side = NULL; + priv.priv_tbl.adpll_freq_avoid = NULL; + priv.priv_tbl.mcu_freq_avoid = NULL; + priv.priv_tbl.tx_pwr_ctrl = NULL; + priv.priv_tbl.rtc_drift_ctrl = NULL; + priv.priv_tbl.tx_desense_wifi = NULL; + priv.state = UNINITED; + priv.data = NULL; + + op->op_tbl.read = NULL; + op->op_tbl.write = NULL; + op->op_tbl.setbits = NULL; + op->op_tbl.rampdown = NULL; + op->state = UNINITED; + op->data = NULL; + + return ret; +} + +static int __init mt_fm_probe(void) +{ + int err = -1; + FM_LOG_NTC(D_INIT,"%s()\n", __func__); + + spin_lock_init(&flag_lock); + + if ((err = fm_init())){ + FM_LOG_ALT(D_ALL, "fm_init ERR:%d\n", err); + } + + return err; +} + +static void __exit mt_fm_remove(void) +{ + FM_LOG_NTC(D_INIT,"%s()\n", __func__); + fm_destroy(fm_cb); + + return; +} + +EXPORT_SYMBOL(fm_priv_register); +EXPORT_SYMBOL(fm_priv_unregister); +EXPORT_SYMBOL(g_dbg_level); + +module_init(mt_fm_probe); +module_exit(mt_fm_remove); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MediaTek MT6620 FM Driver"); +MODULE_AUTHOR("Mike "); + diff --git a/drivers/mtk_wcn_combo/drv_fm/public/mt6620_fm.h b/drivers/mtk_wcn_combo/drv_fm/public/mt6620_fm.h new file mode 100755 index 000000000000..4b76d84a3aca --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_fm/public/mt6620_fm.h @@ -0,0 +1,597 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +#ifndef __MT6620_FM_H__ +#define __MT6620_FM_H__ + +#include +#include +#include +#include "fm.h" + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define RDS_RX_BLOCK_PER_GROUP (4) +#define RDS_RX_GROUP_SIZE (2*RDS_RX_BLOCK_PER_GROUP) +#define MAX_RDS_RX_GROUP_CNT (12) +#define FM_RDS_ENABLE 0x01 // 1: enable RDS, 0:disable RDS + + +/******************DBG level added by DDB************************/ +#define D_BASE 4 +#define D_IOCTL (1 << (D_BASE+0)) +#define D_RX (1 << (D_BASE+1)) +#define D_TIMER (1 << (D_BASE+2)) +#define D_BLKC (1 << (D_BASE+3)) +#define D_G0 (1 << (D_BASE+4)) +#define D_G1 (1 << (D_BASE+5)) +#define D_G2 (1 << (D_BASE+6)) +#define D_G3 (1 << (D_BASE+7)) +#define D_G4 (1 << (D_BASE+8)) +#define D_G14 (1 << (D_BASE+9)) +#define D_RAW (1 << (D_BASE+10)) +#define D_RDS (1 << (D_BASE+11)) +#define D_INIT (1 << (D_BASE+12)) +#define D_MAIN (1 << (D_BASE+13)) +#define D_CMD (1 << (D_BASE+14)) +#define D_ALL 0xfffffff0 + +#define L0 0x00000000 // EMERG, system will crush +#define L1 0x00000001 // ALERT, need action in time +#define L2 0x00000002 // CRIT, important HW or SW operation failed +#define L3 0x00000003 // ERR, normal HW or SW ERR +#define L4 0x00000004 // WARNING, importan path or somewhere may occurs err +#define L5 0x00000005 // NOTICE, normal case +#define L6 0x00000006 // INFO, print info if need +#define L7 0x00000007 // DEBUG, for debug info + +#define FM_EMERG L0 +#define FM_ALERT L1 +#define FM_CRIT L2 +#define FM_ERR L3 +#define FM_WARNING L4 +#define FM_NOTICE L5 +#define FM_INFO L6 +#define FM_DEBUG L7 + +extern uint32_t g_dbg_level; + +#if 0 +#define WCN_DBG(flag, fmt, args...) \ + do { \ + if ((((flag)&0x0000000f)<=(g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0)& g_dbg_level) { \ + printk(KERN_ALERT "[" #flag "]" fmt, ## args); \ + } \ + } while(0) +#endif + +//#define FM_USE_XLOG + +#ifdef FM_USE_XLOG +#include +#define FM_DRV_LOG_TAG "FM_DRV" + +#define FM_LOG_DBG(flag, fmt, args...) \ + do{ \ + if((FM_DEBUG <= (g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0)& g_dbg_level) { \ + xlog_printk(ANDROID_LOG_INFO, FM_DRV_LOG_TAG, "[" #flag "]" fmt, ## args); \ + } \ + } while(0) + +#define FM_LOG_INF(flag, fmt, args...) \ + do{ \ + if((FM_INFO <= (g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0)& g_dbg_level) { \ + xlog_printk(ANDROID_LOG_INFO, FM_DRV_LOG_TAG, "[" #flag "]" fmt, ## args); \ + } \ + } while(0) + +#define FM_LOG_NTC(flag, fmt, args...) \ + do{ \ + if((FM_NOTICE <= (g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0)& g_dbg_level) { \ + xlog_printk(ANDROID_LOG_WARN, FM_DRV_LOG_TAG, "[" #flag "]" fmt, ## args); \ + } \ + } while(0) + +#define FM_LOG_WAR(flag, fmt, args...) \ + do{ \ + if((FM_WARNING <= (g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0)& g_dbg_level) { \ + xlog_printk(ANDROID_LOG_WARN, FM_DRV_LOG_TAG, "[" #flag "]" fmt, ## args); \ + } \ + } while(0) + +#define FM_LOG_ERR(flag, fmt, args...) \ + do{ \ + if((FM_ERR <= (g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0)& g_dbg_level) { \ + xlog_printk(ANDROID_LOG_ERROR, FM_DRV_LOG_TAG, "[" #flag "]" fmt, ## args); \ + } \ + } while(0) + +#define FM_LOG_CRT(flag, fmt, args...) \ + do{ \ + if((FM_CRIT <= (g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0)& g_dbg_level) { \ + xlog_printk(ANDROID_LOG_FATAL, FM_DRV_LOG_TAG, "[" #flag "]" fmt, ## args); \ + } \ + } while(0) + +#define FM_LOG_ALT(flag, fmt, args...) \ + do{ \ + if((FM_ALERT <= (g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0)& g_dbg_level) { \ + xlog_printk(ANDROID_LOG_FATAL, FM_DRV_LOG_TAG, "[" #flag "]" fmt, ## args); \ + } \ + } while(0) + +#define FM_LOG_EMG(flag, fmt, args...) \ + do{ \ + if((FM_EMERG <= (g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0)& g_dbg_level) { \ + xlog_printk(ANDROID_LOG_FATAL, FM_DRV_LOG_TAG, "[" #flag "]" fmt, ## args); \ + } \ + } while(0) + +#else + +#define FM_LOG_DBG(flag, fmt, args...) \ + do{ \ + if((FM_DEBUG <= (g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0)& g_dbg_level) { \ + printk(KERN_DEBUG "[" #flag "]" fmt, ## args); \ + } \ + } while(0) + +#define FM_LOG_INF(flag, fmt, args...) \ + do{ \ + if((FM_INFO <= (g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0)& g_dbg_level) { \ + printk(KERN_INFO "[" #flag "]" fmt, ## args); \ + } \ + } while(0) + +#define FM_LOG_NTC(flag, fmt, args...) \ + do{ \ + if((FM_NOTICE <= (g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0)& g_dbg_level) { \ + printk(KERN_NOTICE "[" #flag "]" fmt, ## args); \ + } \ + } while(0) + +#define FM_LOG_WAR(flag, fmt, args...) \ + do{ \ + if((FM_WARNING <= (g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0)& g_dbg_level) { \ + printk(KERN_WARNING "[" #flag "]" fmt, ## args); \ + } \ + } while(0) + +#define FM_LOG_ERR(flag, fmt, args...) \ + do{ \ + if((FM_ERR <= (g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0)& g_dbg_level) { \ + printk(KERN_ERR "[" #flag "]" fmt, ## args); \ + } \ + } while(0) + +#define FM_LOG_CRT(flag, fmt, args...) \ + do{ \ + if((FM_CRIT <= (g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0)& g_dbg_level) { \ + printk(KERN_CRIT "[" #flag "]" fmt, ## args); \ + } \ + } while(0) + +#define FM_LOG_ALT(flag, fmt, args...) \ + do{ \ + if((FM_ALERT <= (g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0)& g_dbg_level) { \ + printk(KERN_ALERT "[" #flag "]" fmt, ## args); \ + } \ + } while(0) + +#define FM_LOG_EMG(flag, fmt, args...) \ + do{ \ + if((FM_EMERG <= (g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0)& g_dbg_level) { \ + printk(KERN_EMERG "[" #flag "]" fmt, ## args); \ + } \ + } while(0) +#endif + +#define BITn(n) (uint16_t)(1<<(n)) +#define MASK(n) (uint16_t)(~(1<<(n))) + +#define FM_COM_ASSERT(n) {\ + if(!(n)){\ + FM_LOG_ERR(D_ALL, "%s(), %d\n", __func__, __LINE__);\ + return -EFAULT;\ + }\ + } + + +typedef enum +{ + FM_TX_NOT_SUPPORT = 0, + FM_TX_SUPPORT +}fm_tx_support_flag; + +typedef enum +{ + FM_RDS_TX_NOT_SUPPORT = 0, + FM_RDS_TX_SUPPORT +}fm_rds_tx_support_flag; + +typedef enum +{ + FM_RDS_TX_DISENABLE = 0, + FM_RDS_TX_ENABLE +}fm_rds_tx_enable_state; + +typedef enum +{ + FM_OVER_BT_DISABLE = 0, + FM_OVER_BT_ENABLE +}fm_over_bt_enable_state; + +typedef enum +{ + FM_LONG_ANA = 0, + FM_SHORT_ANA +}fm_antenna_type; + +typedef struct +{ + uint16_t blkA; + uint16_t blkB; + uint16_t blkC; + uint16_t blkD; + uint16_t cbc; //correct bit cnt + uint16_t crc; //crc checksum +}rds_packet_struct; + +struct rds_rx +{ + uint16_t sin; + uint16_t cos; + rds_packet_struct data[MAX_RDS_RX_GROUP_CNT]; +}; + +typedef enum fm_pwr_status{ + FM_PWR_OFF = 0, + FM_PWR_RX_ON = 1, + FM_PWR_TX_ON = 2, + FM_PWR_MAX +}fm_pwr_status; + +struct fm { + volatile uint ref; + volatile bool chipon; //MT6620 chip power state + volatile fm_pwr_status powerup; //FM module power state + atomic_t tx_support; //FM Tx support flag, 1: support, 0: not support + int tx_pwr; + atomic_t rds_tx_support; //FM RDS Tx support flag, 1: support, 0: not support + atomic_t rds_tx_enable; //FM RDS Tx enable state, 1:enable RDS Tx function, 0:disable + atomic_t over_bt_enable; //FM over BT enable state, 1:enable, 0:disable + uint16_t chip_id; + uint16_t device_id; + dev_t dev_t; + uint16_t min_freq; // KHz + uint16_t max_freq; // KHz + uint8_t band; // TODO + struct class *cls; + struct device *dev; + struct cdev cdev; + wait_queue_head_t read_wait; + volatile bool RDS_Data_ready; + RDSData_Struct *pstRDSData; + struct rds_group_cnt rds_gc; + struct workqueue_struct *fm_workqueue; /* fm rx handling */ + struct workqueue_struct *fm_timer_workqueue; /* fm rds reset handling */ + struct work_struct fm_rds_reset_work; + struct work_struct fm_tx_power_ctrl_work; + struct work_struct fm_tx_rtc_ctrl_work; + struct work_struct fm_tx_desense_wifi_work; + struct work_struct fm_rst_recover_work; + struct work_struct fm_subsys_recover_work; + struct work_struct fm_rx_work; +}; + +struct fm_rx_cxt{ + int audioPath; //I2S or Analog + int vol; + int mute; + int rdsOn; + int ana; //long/short antenna + int ViaBt; //FM over bt controller +}; + +struct fm_tx_cxt{ + int audioPath; //I2S or Analog + int rdsTxOn; + uint16_t pi; + uint16_t ps[12]; // 4 ps + uint16_t other_rds[87]; // 0~29 other groups + uint8_t other_rds_cnt; // # of other group +}; + +struct fm_context{ + volatile int ref; + volatile bool chipon; + fm_pwr_status powerup; + volatile int16_t freq; + struct fm_rx_cxt rxcxt; + struct fm_tx_cxt txcxt; +}; + +struct fm_config{ + struct proc_dir_entry *proc; + uint32_t vcoon; + uint32_t vcooff; + uint32_t timer; + uint32_t txpwrctl; + uint32_t rdsrst; +}; + +typedef struct fm_timer_sys{ + volatile uint32_t count; + volatile uint8_t onoff; + volatile uint8_t rds_reset_en; + volatile uint8_t tx_pwr_ctrl_en; + volatile uint8_t tx_rtc_ctrl_en; + volatile uint8_t tx_desense_en; +}fm_timer_sys; + +enum{ + FM_TIMER_SYS_OFF, + FM_TIMER_SYS_ON, + FM_TIMER_SYS_MAX +}; + +enum{ + FM_RDS_RST_DISABLE, + FM_RDS_RST_ENABLE, + FM_RDS_RST_MAX +}; + +enum{ + FM_TX_PWR_CTRL_DISABLE, + FM_TX_PWR_CTRL_ENABLE, + FM_TX_PWR_CTRL_MAX +}; + +enum{ + FM_TX_RTC_CTRL_DISABLE, + FM_TX_RTC_CTRL_ENABLE, + FM_TX_RTC_CTRL_MAX +}; + +enum{ + FM_TX_DESENSE_DISABLE, + FM_TX_DESENSE_ENABLE, + FM_TX_DESENSE_MAX +}; + +enum{ + FM_WHOLECHIP_RST_OFF, + FM_WHOLECHIP_RST_START, + FM_WHOLECHIP_RST_END, + FM_WHOLECHIP_RST_MAX +}; + +enum{ + FM_SUBSYS_RST_OFF, + FM_SUBSYS_RST_START, + FM_SUBSYS_RST_END, + FM_SUBSYS_RST_MAX +}; + +#define FM_TIMER_TIMEOUT_DEFAULT 1000 +#define FM_TIMER_TIMEOUT_MIN 1000 +#define FM_TIMER_TIMEOUT_MAX 1000000 + +#define FM_RDS_RST_INVAL_DEFAULT 5 +#define FM_RDS_RST_INVAL_MIN 5 +#define FM_RDS_RST_INVAL_MAX 10000 + +#define FM_TX_PWR_CTRL_INVAL_DEFAULT 10 +#define FM_TX_PWR_CTRL_INVAL_MIN 5 +#define FM_TX_PWR_CTRL_INVAL_MAX 10000 + +#define FM_TX_VCO_OFF_DEFAULT 5 +#define FM_TX_VCO_OFF_MIN 1 +#define FM_TX_VCO_OFF_MAX 10000 + +#define FM_TX_VCO_ON_DEFAULT 100 +#define FM_TX_VCO_ON_MIN 10 +#define FM_TX_VCO_ON_MAX 10000 + +#define FM_TX_RTC_CTRL_INTERVAL 10 + +#define FM_GPS_RTC_AGE_TH 2 +#define FM_GPS_RTC_DRIFT_TH 0 +#define FM_GPS_RTC_TIME_DIFF_TH 10 +#define FM_GPS_RTC_RETRY_CNT 1 +#define FM_GPS_RTC_DRIFT_MAX 5000 +enum{ + FM_GPS_RTC_INFO_OLD = 0, + FM_GPS_RTC_INFO_NEW = 1, + FM_GPS_RTC_INFO_MAX +}; +// MUST sync with FM f/w definitions (eg. sys_fm_6620.h) +/* FM opcode */ +#define FM_STP_TEST_OPCODE (0x00) +#define FSPI_ENABLE_OPCODE (0x01) +#define FSPI_MUX_SEL_OPCODE (0x02) +#define FSPI_READ_OPCODE (0x03) +#define FSPI_WRITE_OPCODE (0x04) +#define FI2C_READ_OPCODE (0x05) +#define FI2C_WRITE_OPCODE (0x06) +#define FM_ENABLE_OPCODE (0x07) +#define FM_RESET_OPCODE (0x08) +#define FM_TUNE_OPCODE (0x09) +#define FM_SEEK_OPCODE (0x0a) +#define FM_SCAN_OPCODE (0x0b) +#define RDS_RX_ENABLE_OPCODE (0x0c) +#define RDS_RX_DATA_OPCODE (0x0d) +#define FM_RAMPDOWN_OPCODE (0x0e) +#define FM_MCUCLK_SEL_OPCODE (0x0f) +#define FM_MODEMCLK_SEL_OPCODE (0x10) +#define RDS_TX_OPCODE (0x11) +#define FM_MAX_OPCODE (0x12) + +#define FM_COM_CMD_BASE 0 +typedef enum{ + FM_COM_CMD_TEST = FM_COM_CMD_BASE + 0, + FM_COM_CMD_SEEK, + FM_COM_CMD_SCAN, + FM_COM_CMD_MAX +}fm_com_cmd_t; + +#define SW_RETRY_CNT (2) +#define SW_RETRY_CNT_MAX (5) +#define SW_WAIT_TIMEOUT_MAX (100) +typedef enum +{ + ERR_SUCCESS = 1000, + ERR_INVALID_BUF, + ERR_INVALID_PARA, + ERR_STP, + ERR_GET_MUTEX, + ERR_FW_NORES, + ERR_RDS_CRC, + ERR_WHOLECHIP_RST, + ERR_SUBSYS_RST, + ERR_MAX +}fm_drv_error_t; + +// FM operation timeout define for error handle +#define TEST_TIMEOUT (3) +#define FSPI_EN_TIMEOUT (3) +#define FSPI_MUXSEL_TIMEOUT (3) +#define FSPI_RD_TIMEOUT (3) +#define FSPI_WR_TIMEOUT (3) +#define I2C_RD_TIMEOUT (3) +#define I2C_WR_TIMEOUT (3) +#define EN_TIMEOUT (5) +#define RST_TIMEOUT (3) +#define TUNE_TIMEOUT (3) +#define SEEK_TIMEOUT (10) +#define SCAN_TIMEOUT (15) //usualy scan will cost 10 seconds +#define RDS_RX_EN_TIMEOUT (3) +#define RDS_DATA_TIMEOUT (100) +#define RAMPDOWN_TIMEOUT (3) +#define MCUCLK_TIMEOUT (3) +#define MODEMCLK_TIMEOUT (3) +#define RDS_TX_TIMEOUT (3) +#define POWERON_TIMEOUT (3) +#define POWEROFF_TIMEOUT (3) +#define SEEK_DONE_TIMEOUT (3) +#define SCAN_DONE_TIMEOUT (3) + + +/* FM basic-operation's opcode */ +#define FM_BOP_BASE (0x80) +#define FM_WRITE_BASIC_OP (FM_BOP_BASE + 0x00) +#define FM_UDELAY_BASIC_OP (FM_BOP_BASE + 0x01) +#define FM_RD_UNTIL_BASIC_OP (FM_BOP_BASE + 0x02) +#define FM_MODIFY_BASIC_OP (FM_BOP_BASE + 0x03) +#define FM_MSLEEP_BASIC_OP (FM_BOP_BASE + 0x04) +#define FM_MAX_BASIC_OP (FM_BOP_BASE + 0x05) + +/* FM BOP's size */ +#define FM_WRITE_BASIC_OP_SIZE (3) +#define FM_UDELAY_BASIC_OP_SIZE (4) +#define FM_RD_UNTIL_BASIC_OP_SIZE (5) +#define FM_MODIFY_BASIC_OP_SIZE (5) +#define FM_MSLEEP_BASIC_OP_SIZE (4) + +#define RX_BUF_SIZE 128 +#define TX_BUF_SIZE 1024 + +typedef enum +{ + FM_TASK_RX_PARSER_PKT_TYPE = 0, + FM_TASK_RX_PARSER_OPCODE, + FM_TASK_RX_PARSER_PKT_LEN_1, + FM_TASK_RX_PARSER_PKT_LEN_2, + FM_TASK_RX_PARSER_PKT_PAYLOAD, + FM_TASK_RX_PARSER_BUFFER_CONGESTION +} fm_task_parser_state; + +#define FM_ADDR_RSSI (0xE8) //D9~D0 10bits +#define FM_ADDR_PAMD (0xE9) //D7~D0 8bits +#define FM_ADDR_MR (0xF2) //D8~D0 9bits + +#define FM_TXSCAN_RSSI_TH (-250) +#define FM_TXSCAN_PAMD_TH (-20) +#define FM_TXSCAN_MR_TH (-38) + +#define SCAN_UP (0) +#define SCAN_DOWN (1) + +#define MT6620_SCANTBL_SIZE 16 //16*uinit16_t + +#define FM_TASK_COMMAND_PKT_TYPE 0x01 +#define FM_TASK_EVENT_PKT_TYPE 0x04 + +#define MT6620_FM_SEEK_UP 0x0 +#define MT6620_FM_SEEK_DOWN 0x01 +#define MT6620_FM_SCAN_UP 0x0 +#define MT6620_FM_SCAN_DOWN 0x01 +#define MT6620_FM_SPACE_INVALID 0x0 +#define MT6620_FM_SPACE_50K 0x01 +#define MT6620_FM_SPACE_100K 0x02 +#define MT6620_FM_SPACE_200K 0x04 + +#define FLAG_TEST (1 << 0) +#define FLAG_FSPI_EN (1 << 1) +#define FLAG_FSPI_MUXSEL (1 << 2) +#define FLAG_FSPI_RD (1 << 3) +#define FLAG_FSPI_WR (1 << 4) +#define FLAG_I2C_RD (1 << 5) +#define FLAG_I2C_WR (1 << 6) +#define FLAG_EN (1 << 7) +#define FLAG_RST (1 << 8) +#define FLAG_TUNE (1 << 9) +#define FLAG_SEEK (1 << 10) +#define FLAG_SCAN (1 << 11) +#define FLAG_RDS_RX_EN (1 << 12) +#define FLAG_RDS_DATA (1 << 13) +#define FLAG_RAMPDOWN (1 << 14) +#define FLAG_MCUCLK (1 << 15) +#define FLAG_MODEMCLK (1 << 16) +#define FLAG_RDS_TX (1 << 17) +#define FLAG_OP_MAX (1 << 18) +#define FLAG_POWERON (1 << 19) +#define FLAG_POWEROFF (1 << 20) +#define FLAG_SEEK_DONE (1 << 21) +#define FLAG_SCAN_DONE (1 << 22) +#define FLAG_TERMINATE (1 << 31) + +#endif //__MT6620_FM_H__ diff --git a/drivers/mtk_wcn_combo/drv_fm/public/mt6620_fm_lib.c b/drivers/mtk_wcn_combo/drv_fm/public/mt6620_fm_lib.c new file mode 100755 index 000000000000..b1d92e6521f7 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_fm/public/mt6620_fm_lib.c @@ -0,0 +1,1486 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +#include +#include +#include "fm.h" +#include "mt6620_fm.h" +#include "mt6620_fm_lib.h" + +//#define MT6620E1 +//#define MT6620_FM_USE_SHORT_ANTENNA + +int fm_bop_write(uint8_t addr, uint16_t value, unsigned char *buf, int size) +{ + if(size < (FM_WRITE_BASIC_OP_SIZE+2)){ + return (-1); + } + + if(buf == NULL){ + return (-2); + } + + buf[0] = FM_WRITE_BASIC_OP; + buf[1] = FM_WRITE_BASIC_OP_SIZE; + buf[2] = addr; + buf[3] = (uint8_t)((value) & 0x00FF); + buf[4] = (uint8_t)((value >> 8) & 0x00FF); + + FM_LOG_DBG(D_MAIN,"%02x %02x %02x %02x %02x \n", buf[0], buf[1], buf[2], buf[3], buf[4]); + + return (FM_WRITE_BASIC_OP_SIZE+2); +} + +int fm_bop_udelay(uint32_t value, unsigned char *buf, int size) +{ + if(size < (FM_UDELAY_BASIC_OP_SIZE+2)){ + return (-1); + } + + if(buf == NULL){ + return (-2); + } + + buf[0] = FM_UDELAY_BASIC_OP; + buf[1] = FM_UDELAY_BASIC_OP_SIZE; + buf[2] = (uint8_t)((value) & 0x000000FF); + buf[3] = (uint8_t)((value >> 8) & 0x000000FF); + buf[4] = (uint8_t)((value >> 16) & 0x000000FF); + buf[5] = (uint8_t)((value >> 24) & 0x000000FF); + + FM_LOG_DBG(D_MAIN,"%02x %02x %02x %02x %02x %02x \n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + + return (FM_UDELAY_BASIC_OP_SIZE+2); +} + +int fm_bop_rd_until(uint8_t addr, uint16_t mask, uint16_t value, unsigned char *buf, int size) +{ + if(size < (FM_RD_UNTIL_BASIC_OP_SIZE+2)){ + return (-1); + } + + if(buf == NULL){ + return (-2); + } + + buf[0] = FM_RD_UNTIL_BASIC_OP; + buf[1] = FM_RD_UNTIL_BASIC_OP_SIZE; + buf[2] = addr; + buf[3] = (uint8_t)((mask) & 0x00FF); + buf[4] = (uint8_t)((mask >> 8) & 0x00FF); + buf[5] = (uint8_t)((value) & 0x00FF); + buf[6] = (uint8_t)((value >> 8) & 0x00FF); + + FM_LOG_DBG(D_MAIN,"%02x %02x %02x %02x %02x %02x %02x \n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); + + return (FM_RD_UNTIL_BASIC_OP_SIZE+2); +} + +int fm_bop_modify(uint8_t addr, uint16_t mask_and, uint16_t mask_or, unsigned char *buf, int size) +{ + if(size < (FM_MODIFY_BASIC_OP_SIZE+2)){ + return (-1); + } + + if(buf == NULL){ + return (-2); + } + + buf[0] = FM_MODIFY_BASIC_OP; + buf[1] = FM_MODIFY_BASIC_OP_SIZE; + buf[2] = addr; + buf[3] = (uint8_t)((mask_and) & 0x00FF); + buf[4] = (uint8_t)((mask_and >> 8) & 0x00FF); + buf[5] = (uint8_t)((mask_or) & 0x00FF); + buf[6] = (uint8_t)((mask_or >> 8) & 0x00FF); + + FM_LOG_DBG(D_MAIN,"%02x %02x %02x %02x %02x %02x %02x \n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); + + return (FM_MODIFY_BASIC_OP_SIZE+2); +} + +int fm_bop_msleep(uint32_t value, unsigned char *buf, int size) +{ + if(size < (FM_MSLEEP_BASIC_OP_SIZE+2)){ + return (-1); + } + + if(buf == NULL){ + return (-2); + } + + buf[0] = FM_MSLEEP_BASIC_OP; + buf[1] = FM_MSLEEP_BASIC_OP_SIZE; + buf[2] = (uint8_t)((value) & 0x000000FF); + buf[3] = (uint8_t)((value >> 8) & 0x000000FF); + buf[4] = (uint8_t)((value >> 16) & 0x000000FF); + buf[5] = (uint8_t)((value >> 24) & 0x000000FF); + + FM_LOG_DBG(D_MAIN,"%02x %02x %02x %02x %02x %02x \n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + + return (FM_MSLEEP_BASIC_OP_SIZE+2); +} + +//MT6620 IC +int mt6620_off_2_longANA(unsigned char *tx_buf, int tx_buf_size) +{ + int pkt_size = 0; + + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE; + tx_buf[1] = FM_ENABLE_OPCODE; + pkt_size = 4; + + //A01 Turn on the bandgap and central biasing core + pkt_size += fm_bop_write(0x01, 0x4A00, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 1 4A00 + pkt_size += fm_bop_udelay(30, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 30 + pkt_size += fm_bop_write(0x01, 0x6A00, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 1 6A00 + pkt_size += fm_bop_udelay(50, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 50 + //A02 Initialise the LDO's Output + pkt_size += fm_bop_write(0x02, 0x299C, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 2 299C + //A03 Enable RX, ADC and ADPLL LDO + pkt_size += fm_bop_write(0x01, 0x6B82, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 1 6B82 + //A04 Update FMRF optimized register settings + pkt_size += fm_bop_write(0x04, 0x0142, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 4 0142 + pkt_size += fm_bop_write(0x05, 0x00E7, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 5 00E7 + pkt_size += fm_bop_write(0x0A, 0x0060, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a 0060 + pkt_size += fm_bop_write(0x0C, 0xA88C, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr c A88C + pkt_size += fm_bop_write(0x0D, 0x0888, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr d 0888 + pkt_size += fm_bop_write(0x10, 0x1E8D, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 10 1E8D + pkt_size += fm_bop_write(0x27, 0x0005, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 27 0005 + pkt_size += fm_bop_write(0x0E, 0x0040, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr e 0040 + pkt_size += fm_bop_write(0x03, 0x50F0, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 3 50f0 + pkt_size += fm_bop_write(0x3F, 0xAD06, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 3f AD06 + pkt_size += fm_bop_write(0x3E, 0x3280, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 3e 3280 + pkt_size += fm_bop_write(0x06, 0x0124, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 6 0124 + pkt_size += fm_bop_write(0x08, 0x15B8, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 8 15B8 + //A05 Enable RX related blocks + pkt_size += fm_bop_write(0x28, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 28 0000 + pkt_size += fm_bop_write(0x00, 0x0166, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 0 0166 + pkt_size += fm_bop_write(0x3A, 0x0004, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 3a 0004 + pkt_size += fm_bop_write(0x37, 0x2590, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 37 2590 + // FM ADPLL Power Up + // () for 16.384M mode, otherwise 15.36M + pkt_size += fm_bop_write(0x25, 0x040F, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 25 040f + pkt_size += fm_bop_write(0x20, 0x2720, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 20 2720 + //XHC, 2011/03/18, [wr 22 9980->6680] + pkt_size += fm_bop_write(0x22, 0x6680, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 22 9980 + pkt_size += fm_bop_write(0x25, 0x080F, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 25 080f + pkt_size += fm_bop_write(0x1E, 0x0863, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 1e 0863(0A63) + pkt_size += fm_bop_udelay(5000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 5000 + pkt_size += fm_bop_write(0x1E, 0x0865, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 1e 0865 (0A65) + pkt_size += fm_bop_udelay(5000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 5000 + pkt_size += fm_bop_write(0x1E, 0x0871, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 1e 0871 (0A71) + pkt_size += fm_bop_udelay(100000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 100000 + pkt_size += fm_bop_write(0x2A, 0x1026, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 2a 1026 + // FM RC Calibration + pkt_size += fm_bop_write(0x00, 0x01E6, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 0 01E6 + pkt_size += fm_bop_udelay(1, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 1 + pkt_size += fm_bop_write(0x1B, 0x0094, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 1b 0094 + pkt_size += fm_bop_write(0x1B, 0x0095, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 1b 0095 + pkt_size += fm_bop_udelay(200, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 200 + pkt_size += fm_bop_write(0x1B, 0x0094, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 1b 0094 + pkt_size += fm_bop_write(0x00, 0x0166, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 0 0166 + // FM VCO Enable + pkt_size += fm_bop_write(0x01, 0x6B8A, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 1 6B8A + pkt_size += fm_bop_udelay(1, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 1 + pkt_size += fm_bop_write(0x00, 0xC166, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 0 C166 + pkt_size += fm_bop_udelay(3000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 3000 + pkt_size += fm_bop_write(0x00, 0xF166, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 0 F166 + pkt_size += fm_bop_write(0x09, 0x2964, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9 2964 + // FM RFDIG settings + pkt_size += fm_bop_write(0x2E, 0x0008, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 2e 8 + pkt_size += fm_bop_write(0x2B, 0x0064, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 2b 64 + pkt_size += fm_bop_write(0x2C, 0x0032, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 2c 32 + pkt_size += fm_bop_write(0x11, 0x17d4, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 11 17d4 + //Update dynamic subband switching setting, XHC 2011/05/17 + pkt_size += fm_bop_write(0x13, 0xFA00, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 13 FA00 + pkt_size += fm_bop_write(0x14, 0x0580, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 14 0580 + pkt_size += fm_bop_write(0x15, 0xFA80, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 15 FA80 + pkt_size += fm_bop_write(0x16, 0x0580, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 16 0580 + pkt_size += fm_bop_write(0x33, 0x0008, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 33 0008 + // FM DCOC Calibration + pkt_size += fm_bop_write(0x64, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 64 1 + pkt_size += fm_bop_write(0x63, 0x0020, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 63 20 + pkt_size += fm_bop_write(0x9C, 0x0044, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9C 0044 + //pkt_size += fm_bop_write(0x6B, 0x0100, &tx_buf[pkt_size], tx_buf_size - pkt_size);//"Disable other interrupts except for STC_DONE(dependent on interrupt output source selection)" + pkt_size += fm_bop_write(0x0F, 0x1A08, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr F 1A08 + pkt_size += fm_bop_write(0x63, 0x0021, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 63 21 + pkt_size += fm_bop_rd_until(0x69, 0x0001, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);//Poll fm_intr_stc_done (69H D0) = 1 + pkt_size += fm_bop_write(0x69, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 69 1 + pkt_size += fm_bop_write(0x63, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 63 0 + pkt_size += fm_bop_rd_until(0x6F, 0x0001, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//Poll stc_done (6FH D0)= 0 + // Others + pkt_size += fm_bop_write(0x00, 0xF167, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 0 F167 + pkt_size += fm_bop_udelay(50000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 50000 + + tx_buf[2] = (uint8_t)((pkt_size-4) & 0x00FF); + tx_buf[3] = (uint8_t)(((pkt_size-4) >> 8) & 0x00FF); + + return pkt_size; +} + +int mt6620_off_2_longANA_ack(unsigned char *tx_buf, int tx_buf_size) +{ + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_EVENT_PKT_TYPE; + tx_buf[1] = FM_ENABLE_OPCODE; + tx_buf[2] = 0x00; + tx_buf[3] = 0x00; + + return 4; +} + +int mt6620_rx_digital_init(unsigned char *tx_buf, int tx_buf_size) +{ + int pkt_size = 0; + + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE; + tx_buf[1] = FM_ENABLE_OPCODE; + pkt_size = 4; + + // fm_rgf_maincon + //rd 62 + pkt_size += fm_bop_write(0x65, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 65 0 + pkt_size += fm_bop_write(0x64, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 64 1 + pkt_size += fm_bop_write(0x63, 0x0480, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 63 480 + pkt_size += fm_bop_write(0x6D, 0x1AB2, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 6d 1ab2 + pkt_size += fm_bop_write(0x6B, 0x2100, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 6b 2100 + pkt_size += fm_bop_write(0x68, 0xE100, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 68 E100 + pkt_size += fm_bop_udelay(10000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 10000 + pkt_size += fm_bop_write(0x68, 0xE000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 68 E000 + // fm_rgf_dac + pkt_size += fm_bop_write(0x9C, 0xab48, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9c ab48 + pkt_size += fm_bop_write(0x9E, 0x000C, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9e c + pkt_size += fm_bop_write(0x71, 0x807f, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 71 807f + pkt_size += fm_bop_write(0x72, 0x878f, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 72 878f + //XHC, 2011/04/29 update 0x73 form 0x07C3 to 0x07C1 speed up I/Q calibration + pkt_size += fm_bop_write(0x73, 0x07c1, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 73 7c3 + // fm_rgf_front + pkt_size += fm_bop_write(0x9F, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9f 0 + pkt_size += fm_bop_write(0xCB, 0x00B0, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr cb b0 + //XHC, 2011/05/06 FM RSSI config + pkt_size += fm_bop_write(0xE0, ((0xA301 & 0xFC00) | (FMR_RSSI_TH_LONG & 0x03FF)), &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr e0 a301 + pkt_size += fm_bop_write(0xE1, ((0x00E9 & 0xFF00) | (FMR_CQI_TH & 0x00FF)), &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr e1 D0~D7, PAMD TH + //XHC, 2011/04/15 update search MR threshold + pkt_size += fm_bop_write(0xE3, FMR_MR_TH, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr e3 1B0 + pkt_size += fm_bop_write(0xE4, 0x008F, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr e4 8f + pkt_size += fm_bop_write(0xCC, 0x0488, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr cc 488 + pkt_size += fm_bop_write(0xD6, 0x036A, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr d6 36a + pkt_size += fm_bop_write(0xD7, 0x836a, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr d7 836a + pkt_size += fm_bop_write(0xDD, 0x0080, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr dd 80 + pkt_size += fm_bop_write(0xB0, 0xcd00, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr b0 cd00 + //XHC, 2011/03/18 Update AFC gain[wr 96 41E2->4000][wr 97 049A->021F] + //[wr 98 0B66->0D00][wr 99 0E1E->0E7F][wr D0 8233->8192][wr D1 20BC->2086] + //[wr 90 03FF->0192][wr 91 01BE->0086][wr 92 03FF->0192][wr 93 0354->0086] + //[wr 94 03FF->0192][wr 95 0354->0086][wr 52 17F3] + pkt_size += fm_bop_write(0x96, 0x4000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 96 41E2 + pkt_size += fm_bop_write(0x97, 0x021F, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 97 049A + pkt_size += fm_bop_write(0x98, 0x0D00, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 98 0B66 + pkt_size += fm_bop_write(0x99, 0x0E7F, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 99 0E1E + pkt_size += fm_bop_write(0xD0, 0x8192, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr D0 8233 + pkt_size += fm_bop_write(0xD1, 0x2086, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr D1 20BC + pkt_size += fm_bop_write(0x90, 0x0192, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 90 03ff + pkt_size += fm_bop_write(0x91, 0x0086, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 91 01BE + pkt_size += fm_bop_write(0x92, 0x0192, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 92 03FF + pkt_size += fm_bop_write(0x93, 0x0086, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 93 0354 + pkt_size += fm_bop_write(0x94, 0x0192, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 94 03FF + pkt_size += fm_bop_write(0x95, 0x0086, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 95 0354 + pkt_size += fm_bop_write(0x52, 0x17F3, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 95 0354 + // fm_rgf_fmx + pkt_size += fm_bop_write(0x9F, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9f 1 + pkt_size += fm_bop_write(0xDE, 0x3388, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr de 3388 + pkt_size += fm_bop_write(0xC2, 0x0180, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr c2 180 + pkt_size += fm_bop_write(0xC3, 0x0180, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr c3 180 + pkt_size += fm_bop_write(0xDB, 0x0181, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr db 181 + pkt_size += fm_bop_write(0xDC, 0x0184, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr dc 184 + pkt_size += fm_bop_write(0xA2, 0x03C0, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a2 3c0 + pkt_size += fm_bop_write(0xA3, 0x03C0, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a3 3c0 + pkt_size += fm_bop_write(0xA4, 0x03C0, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a4 3c0 + pkt_size += fm_bop_write(0xA5, 0x03C0, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a5 3c0 + pkt_size += fm_bop_write(0xA6, 0x03C0, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a6 3c0 + pkt_size += fm_bop_write(0xA7, 0x03C0, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a7 3c0 + pkt_size += fm_bop_write(0xE3, 0x0280, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr e3 280 + pkt_size += fm_bop_write(0xE4, 0x0280, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr e4 280 + pkt_size += fm_bop_write(0xE5, 0x0280, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr e5 280 + pkt_size += fm_bop_write(0xE6, 0x026C, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr e6 26c + pkt_size += fm_bop_write(0xE7, 0x026C, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr e7 26c + pkt_size += fm_bop_write(0xEA, 0x026C, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr ea 26c + pkt_size += fm_bop_udelay(1000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 1000 + pkt_size += fm_bop_write(0xB6, 0x03FC, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr b6 3fc + pkt_size += fm_bop_write(0xB7, 0x02C1, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr b7 2c1 + pkt_size += fm_bop_write(0xA8, 0x0820, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 820 + pkt_size += fm_bop_write(0xAC, 0x065E, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr ac 65e + pkt_size += fm_bop_write(0xAD, 0x09AD, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr ad 9ad + pkt_size += fm_bop_write(0xAE, 0x0CF8, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr ae cf8 + pkt_size += fm_bop_write(0xAF, 0x0302, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr af 302 + pkt_size += fm_bop_write(0xB0, 0x04A6, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr b0 4a6 + pkt_size += fm_bop_write(0xB1, 0x062C, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr b1 62c + pkt_size += fm_bop_write(0xEC, 0x014A, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr ec 14a + pkt_size += fm_bop_write(0xC8, 0x0232, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr c8 232 + pkt_size += fm_bop_write(0xC7, 0x0184, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr c7 0184 + pkt_size += fm_bop_write(0xD8, 0x00E8, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr d8 0e8 + pkt_size += fm_bop_write(0xFB, 0x051F, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr fb 51f + pkt_size += fm_bop_udelay(1000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 1000 + //XHC,2011/03/18 [wr C9 01F0][wr CA 0250][wr D4 2657] + pkt_size += fm_bop_write(0xC9, 0x01F0, &tx_buf[pkt_size], tx_buf_size - pkt_size); + pkt_size += fm_bop_write(0xCA, 0x0250, &tx_buf[pkt_size], tx_buf_size - pkt_size); + pkt_size += fm_bop_write(0xD4, 0x2657, &tx_buf[pkt_size], tx_buf_size - pkt_size); + pkt_size += fm_bop_write(0x9F, 0x0002, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9f 2 + pkt_size += fm_bop_write(0xA8, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 0 + pkt_size += fm_bop_write(0xA8, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 0 + pkt_size += fm_bop_write(0xA8, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 0 + pkt_size += fm_bop_write(0xA8, 0xFF80, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 ff80 + pkt_size += fm_bop_write(0xA8, 0x0061, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 61 + pkt_size += fm_bop_write(0xA8, 0xFF22, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 ff22 + pkt_size += fm_bop_write(0xA8, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 0 + pkt_size += fm_bop_write(0xA8, 0x0100, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 100 + pkt_size += fm_bop_write(0xA8, 0x009A, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 9a + pkt_size += fm_bop_write(0xA8, 0xFF80, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 ff80 + pkt_size += fm_bop_write(0xA8, 0x0140, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 140 + pkt_size += fm_bop_write(0xA8, 0xFF42, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 ff42 + pkt_size += fm_bop_write(0xA8, 0xFFE0, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 ffe0 + pkt_size += fm_bop_write(0xA8, 0x0114, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 114 + pkt_size += fm_bop_write(0xA8, 0xFF4E, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 ff4e + pkt_size += fm_bop_write(0xA8, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 0 + pkt_size += fm_bop_write(0xA8, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 0 + pkt_size += fm_bop_write(0xA8, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 0 + pkt_size += fm_bop_write(0xA8, 0x003E, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 3e + pkt_size += fm_bop_write(0xA8, 0xFF6E, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 ff6e + pkt_size += fm_bop_write(0xA8, 0x0087, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 87 + pkt_size += fm_bop_write(0xA8, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 0 + pkt_size += fm_bop_write(0xA8, 0xFEDC, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 fedc + pkt_size += fm_bop_write(0xA8, 0x0015, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 15 + pkt_size += fm_bop_write(0xA8, 0x00CF, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 cf + pkt_size += fm_bop_write(0xA8, 0xFF6B, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 ff6b + pkt_size += fm_bop_write(0xA8, 0x0164, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 164 + pkt_size += fm_bop_write(0xA8, 0x002B, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 2b + pkt_size += fm_bop_write(0xA8, 0xFF7E, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 ff7e + pkt_size += fm_bop_write(0xA8, 0x0065, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a8 65 + pkt_size += fm_bop_udelay(10000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 10000 + pkt_size += fm_bop_write(0x9F, 0x0002, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9f 2 + pkt_size += fm_bop_write(0xA9, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a9 0 + pkt_size += fm_bop_write(0xA9, 0xFFEE, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a9 ffee + pkt_size += fm_bop_write(0xA9, 0xFF81, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a9 ff81 + //XHC,2011/03/18 [wr A9 FFC3] + pkt_size += fm_bop_write(0xA9, 0xFFC3, &tx_buf[pkt_size], tx_buf_size - pkt_size); + pkt_size += fm_bop_write(0xA9, 0x0022, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a9 22 + pkt_size += fm_bop_write(0xA9, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a9 0 + pkt_size += fm_bop_write(0xA9, 0xFFCC, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a9 ffcc + pkt_size += fm_bop_write(0xA9, 0x0023, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a9 23 + pkt_size += fm_bop_write(0xA9, 0xFFDA, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a9 ffda + pkt_size += fm_bop_write(0xA9, 0xFFF7, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a9 fff7 + pkt_size += fm_bop_udelay(10, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 10 + pkt_size += fm_bop_write(0x9F, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9f 1 + pkt_size += fm_bop_write(0xD3, 0x250b, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr d3 250b + pkt_size += fm_bop_write(0xBB, 0x2320, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr bb 2320 + pkt_size += fm_bop_write(0xD0, 0x02f8, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr d0 02f8 + pkt_size += fm_bop_write(0xEC, 0x019a, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr ec 19a + pkt_size += fm_bop_write(0xFE, 0x2140, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr fe 2140 + pkt_size += fm_bop_write(0x9F, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9f 0 + // fm_rgf_rds + pkt_size += fm_bop_write(0x9F, 0x0003, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9f 3 + pkt_size += fm_bop_write(0xBD, 0x37EB, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr bd 37eb + pkt_size += fm_bop_write(0xBC, 0x0808, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr bc 808 + pkt_size += fm_bop_write(0x9F, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9f 0 + + tx_buf[2] = (uint8_t)((pkt_size-4) & 0x00FF); + tx_buf[3] = (uint8_t)(((pkt_size-4) >> 8) & 0x00FF); + + return pkt_size; +} + +int mt6620_rx_digital_init_ack(unsigned char *tx_buf, int tx_buf_size) +{ + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_EVENT_PKT_TYPE; + tx_buf[1] = FM_ENABLE_OPCODE; + tx_buf[2] = 0x00; + tx_buf[3] = 0x00; + + return 4; +} + +// TBD for IC +int mt6620_powerdown(unsigned char *tx_buf, int tx_buf_size) +{ + int pkt_size = 0; + + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE; + tx_buf[1] = FM_ENABLE_OPCODE; + pkt_size = 4; + +//Digital Modem Power Down + pkt_size += fm_bop_write(0x63, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 63 0 + pkt_size += fm_bop_modify(0x6E, 0xFFFC, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);// clear 0x6e[1:0], round1 + pkt_size += fm_bop_modify(0x6E, 0xFFFC, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);// clear 0x6e[1:0], round2 + pkt_size += fm_bop_modify(0x6E, 0xFFFC, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);// clear 0x6e[1:0], round3 + pkt_size += fm_bop_modify(0x6E, 0xFFFC, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);// clear 0x6e[1:0], round4 +//ADPLL Power Off Sequence + pkt_size += fm_bop_write(0x2A, 0x0022, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 2a 22 + pkt_size += fm_bop_write(0x1E, 0x0860, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 1E 0860 + pkt_size += fm_bop_write(0x20, 0x0720, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 20 0720 + pkt_size += fm_bop_write(0x20, 0x2720, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 20 2720 +//ANALOG/RF Power Off Sequence + pkt_size += fm_bop_write(0x00, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 0 0 + pkt_size += fm_bop_write(0x01, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 1 0 + pkt_size += fm_bop_write(0x04, 0x0141, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 4 0141 + pkt_size += fm_bop_write(0x09, 0x0964, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9 0964 + pkt_size += fm_bop_write(0x0C, 0x288C, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr c 288c + pkt_size += fm_bop_write(0x26, 0x0004, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 26 0004 + pkt_size += fm_bop_write(0x3A, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 3A 0000 + pkt_size += fm_bop_write(0x3B, 0x00C3, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 3B 00C3 + pkt_size += fm_bop_write(0x3E, 0x3280, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 3E 3280 + pkt_size += fm_bop_write(0x3F, 0x4E16, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 3F 4E16 + pkt_size += fm_bop_write(0x41, 0x0004, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 41 0004 + //clear TX settings + pkt_size += fm_bop_write(0x12, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 12 0000 + pkt_size += fm_bop_write(0x47, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 47 0000 + tx_buf[2] = (uint8_t)((pkt_size-4) & 0x00FF); + tx_buf[3] = (uint8_t)(((pkt_size-4) >> 8) & 0x00FF); + + return pkt_size; +} + +int mt6620_powerdown_ack(unsigned char *tx_buf, int tx_buf_size) +{ + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_EVENT_PKT_TYPE; + tx_buf[1] = FM_ENABLE_OPCODE; + tx_buf[2] = 0x00; + tx_buf[3] = 0x00; + + return 4; +} + +int mt6620_rampdown(unsigned char *tx_buf, int tx_buf_size) +{ + int pkt_size = 0; + + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE; + tx_buf[1] = FM_RAMPDOWN_OPCODE; + pkt_size = 4; + + //XHC, 2011/04/06 ramp 125ms -> 34ms + pkt_size += fm_bop_modify(0x9C, 0xFF87, 0x0068, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9c[3] = 1, ramp down + pkt_size += fm_bop_write(0x9F, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9f 1 + pkt_size += fm_bop_write(0xC8, 0x0101, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr c8 101 + pkt_size += fm_bop_write(0xDD, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr dd 0 + pkt_size += fm_bop_write(0xD8, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr d8 0 + pkt_size += fm_bop_write(0x9F, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9f 0 + pkt_size += fm_bop_udelay(35000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 35000 + //disable interrupt before rampdown + pkt_size += fm_bop_write(0x6B, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 6b 0000 + pkt_size += fm_bop_modify(0x63, 0xFFF0, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 63[3:0] = 0, ramp down + pkt_size += fm_bop_rd_until(0x6f, 0x0001, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//Poll 6f[0] = b'0 + pkt_size += fm_bop_write(0x6B, 0x2100, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 6b 2100 + //enable interrupt after rampdown + + tx_buf[2] = (uint8_t)((pkt_size-4) & 0x00FF); + tx_buf[3] = (uint8_t)(((pkt_size-4) >> 8) & 0x00FF); + + return pkt_size; +} + +int mt6620_rampdown_tx(unsigned char *tx_buf, int tx_buf_size) +{ + int pkt_size = 0; + + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE; + tx_buf[1] = FM_RAMPDOWN_OPCODE; + pkt_size = 4; + + pkt_size += fm_bop_write(0x3B, 0x0500, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 3b 0500 + pkt_size += fm_bop_write(0x3A, 0x00FF, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 3a ff + pkt_size += fm_bop_write(0x65, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 65 1 + pkt_size += fm_bop_write(0x48, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 48 0 + + tx_buf[2] = (uint8_t)((pkt_size-4) & 0x00FF); + tx_buf[3] = (uint8_t)(((pkt_size-4) >> 8) & 0x00FF); + + return pkt_size; +} + +int mt6620_rampdown_ack(unsigned char *tx_buf, int tx_buf_size) +{ + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_EVENT_PKT_TYPE; + tx_buf[1] = FM_RAMPDOWN_OPCODE; + tx_buf[2] = 0x00; + tx_buf[3] = 0x00; + + return 4; +} + +// freq: 760 ~ 1080, 100KHz unit, step 1 +int mt6620_tune_1(unsigned char *tx_buf, int tx_buf_size, uint16_t freq) +{ + int pkt_size = 0; + + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + freq = (freq - 640) * 2; + + tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE; + tx_buf[1] = FM_TUNE_OPCODE; + pkt_size = 4; + + pkt_size += fm_bop_modify(0x0F, 0xFC00, freq, &tx_buf[pkt_size], tx_buf_size - pkt_size);// set 0x0F[9:0] = 0x029e, => ((97.5 - 64) * 20) + pkt_size += fm_bop_modify(0x63, 0xFFFF, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);// set 0x63[0] = 1 + + tx_buf[2] = (uint8_t)((pkt_size-4) & 0x00FF); + tx_buf[3] = (uint8_t)(((pkt_size-4) >> 8) & 0x00FF); + + return pkt_size; +} + +// freq: 760 ~ 1080, 100KHz unit, step 2 +int mt6620_tune_2(unsigned char *tx_buf, int tx_buf_size, uint16_t freq) +{ + int pkt_size = 0; + + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + freq = (freq - 640) * 2; + + tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE; + tx_buf[1] = FM_TUNE_OPCODE; + pkt_size = 4; + + pkt_size += fm_bop_modify(0x9C, 0xFFF7, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);// set 0x9C[3] = 0 + + tx_buf[2] = (uint8_t)((pkt_size-4) & 0x00FF); + tx_buf[3] = (uint8_t)(((pkt_size-4) >> 8) & 0x00FF); + + return pkt_size; +} + +// freq: 760 ~ 1080, 100KHz unit, step 3 +int mt6620_tune_3(unsigned char *tx_buf, int tx_buf_size, uint16_t freq) +{ + int pkt_size = 0; + + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + freq = (freq - 640) * 2; + + tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE; + tx_buf[1] = FM_TUNE_OPCODE; + pkt_size = 4; + + pkt_size += fm_bop_write(0x9F, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9F 1 + pkt_size += fm_bop_write(0xC8, 0x0232, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr C8 232 + pkt_size += fm_bop_write(0xDD, 0x8833, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr DD 8833 + pkt_size += fm_bop_write(0xD8, 0x00E8, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr D8 E8 + pkt_size += fm_bop_write(0x9F, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9F 0 + + tx_buf[2] = (uint8_t)((pkt_size-4) & 0x00FF); + tx_buf[3] = (uint8_t)(((pkt_size-4) >> 8) & 0x00FF); + + return pkt_size; +} + +int mt6620_fast_tune(unsigned char *tx_buf, int tx_buf_size, uint16_t freq) +{ + int pkt_size = 0; + + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + freq = (freq - 640) * 2; + + tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE; + tx_buf[1] = FM_TUNE_OPCODE; + pkt_size = 4; + + pkt_size += fm_bop_modify(0x63, 0xFFF0, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);// set 0x63[3:0] = 0 + pkt_size += fm_bop_modify(0x6F, 0xFFFE, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);// set 0x6F[0] = 0 + pkt_size += fm_bop_modify(0x0F, 0xFC00, freq, &tx_buf[pkt_size], tx_buf_size - pkt_size);// set 0x0F[9:0] = 0x029e, => ((97.5 - 64) * 20) + //disable interrupt before rampdown + pkt_size += fm_bop_write(0x6B, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 6b 0000 + pkt_size += fm_bop_modify(0x63, 0xFFFE, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);// set 0x63[0] = 1 + pkt_size += fm_bop_rd_until(0x69, 0x0001, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);//Poll 69[0] = b'1 + pkt_size += fm_bop_modify(0x69, 0xFFFE, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);// set 0x69[0] = 1 + pkt_size += fm_bop_write(0x6B, 0x2100, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 6b 2100 + //enable interrupt after rampdown + + tx_buf[2] = (uint8_t)((pkt_size-4) & 0x00FF); + tx_buf[3] = (uint8_t)(((pkt_size-4) >> 8) & 0x00FF); + + return pkt_size; +} + +// freq: 760 ~ 1080, 100KHz unit +int mt6620_tune_tx(unsigned char *tx_buf, int tx_buf_size, uint16_t freq) +{ + int pkt_size = 0; + + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + freq = (freq - 640) * 2; + + tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE; + tx_buf[1] = FM_TUNE_OPCODE; + pkt_size = 4; + + //XHC, 2011/04/20, ramp down before tune + pkt_size += fm_bop_write(0x3B, 0x0500, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 3b 0500 + pkt_size += fm_bop_write(0x3A, 0x00FF, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 3a ff + pkt_size += fm_bop_write(0x65, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 65 1 + pkt_size += fm_bop_write(0x48, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 48 0 + //XHC, 2011/04/14 + pkt_size += fm_bop_modify(0x41, 0xFFFE, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);// set 0x41[0] = 1 + //XHC, 2011/04/18 + pkt_size += fm_bop_modify(0x12, 0x7FFF, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);// set 0x12[15] = 0 + //XHC, 2011/04/22, clear RTC compensation info + pkt_size += fm_bop_modify(0x47, 0x003F, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);// set 0x47[15:6] = 0 + pkt_size += fm_bop_modify(0x0F, 0xFC00, freq, &tx_buf[pkt_size], tx_buf_size - pkt_size);// set 0x0F[9:0] = freq + pkt_size += fm_bop_write(0x26, 0x002C, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 26 002C --> SCAL Related --> SCAL_EN and SCAL_GM_EN + pkt_size += fm_bop_udelay(1000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 1000us + pkt_size += fm_bop_write(0x26, 0x003C, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 26 003C --> SCAL_BUF_EN + pkt_size += fm_bop_udelay(1000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 1000us + pkt_size += fm_bop_write(0x10, 0x1E8D, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 10 1e8d + pkt_size += fm_bop_udelay(1000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 1000us + pkt_size += fm_bop_write(0x10, 0x9E8D, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 10 9e8d + pkt_size += fm_bop_udelay(10000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 10000us + pkt_size += fm_bop_write(0x26, 0x0024, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 26 0024 --> Turn off SCAL gm and BUF + pkt_size += fm_bop_write(0x65, 0x400F, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 65 400f + pkt_size += fm_bop_write(0x48, 0x8000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 48 8000 + pkt_size += fm_bop_write(0x3B, 0x0420, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 3b 0420 + pkt_size += fm_bop_write(0x3A, 0x01FF, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 3a 1ff + //XHC, 2011/04/14 + //pkt_size += fm_bop_udelay(10000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 10000us + //pkt_size += fm_bop_modify(0x41, 0xFFFE, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);// set 0x41[0] = 0 + + tx_buf[2] = (uint8_t)((pkt_size-4) & 0x00FF); + tx_buf[3] = (uint8_t)(((pkt_size-4) >> 8) & 0x00FF); + + return pkt_size; +} + +// freq: 760 ~ 1080, 100KHz unit +int mt6620_tune_txscan(unsigned char *tx_buf, int tx_buf_size, uint16_t freq) +{ + int pkt_size = 0; + + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + freq = (freq - 640) * 2; + + tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE; + tx_buf[1] = FM_TUNE_OPCODE; + pkt_size = 4; + + //rampdown + //disable interrupt before rampdown + pkt_size += fm_bop_write(0x6B, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 6b 0000 + pkt_size += fm_bop_modify(0x63, 0xFFF0, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 63[3:0] = 0, ramp down + pkt_size += fm_bop_rd_until(0x6f, 0x0001, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//Poll 6f[0] = b'0 + pkt_size += fm_bop_modify(0x9C, 0xFFFF, 0x0008, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9c[3] = 1, ramp down + pkt_size += fm_bop_write(0x6B, 0x2100, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 6b 2100 + //enable interrupt after rampdown + + //set desired channel + pkt_size += fm_bop_modify(0x0F, 0xFC00, freq, &tx_buf[pkt_size], tx_buf_size - pkt_size);// set 0x0F[9:0] = 0x029e, => ((97.5 - 64) * 20) + + //only for short antennal tune +#ifdef MT6620_FM_USE_SHORT_ANTENNA + pkt_size += fm_bop_write(0x28, 0x3800, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 28 3800 + pkt_size += fm_bop_write(0x03, 0x90F0, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 3 90f0 + pkt_size += fm_bop_write(0x2E, 0x0028, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 2e 28 + pkt_size += fm_bop_write(0x2F, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 2f 0 + pkt_size += fm_bop_write(0x26, 0x003C, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 26 3c + pkt_size += fm_bop_write(0x2E, 0x002C, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 2e 2c + pkt_size += fm_bop_udelay(10000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wait 10ms + pkt_size += fm_bop_write(0x26, 0x0024, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 26 24 + pkt_size += fm_bop_write(0x28, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 28 00 +#endif + + //only for E1 +#ifdef MT6620E1 + pkt_size += fm_bop_write(0x9F, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9F 0 + pkt_size += fm_bop_write(0xAF, 0x2210, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr AF 2210 +#endif + + //mask STC_DONE interrupt, 6a(D0) 0 + //pkt_size += fm_bop_modify(0x6A, 0xFFFE, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size); + + //enable hardware are controlled tuning sequence + pkt_size += fm_bop_modify(0x63, 0xFFFF, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);// set rgf_tune (63H D0) =1 + + //check STC_DONE interrupt status flag + //pkt_size += fm_bop_rd_until(0x69, 0x0001, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);//Poll fm_intr_stc_done (69H D0) = 1 + + //write 1 clear the STC_DONE status flag + //pkt_size += fm_bop_modify(0x69, 0xFFFF, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);// set stc_done (6FH D0) =1 + + //unmask STC_DONE interrupt, 6a(D0) 1 + //pkt_size += fm_bop_modify(0x6A, 0xFFFF, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size); + + //only for E1 +#ifdef MT6620E1 + //pkt_size += fm_bop_write(0xAF, 0x7710, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr AF 7710 +#endif + + tx_buf[2] = (uint8_t)((pkt_size-4) & 0x00FF); + tx_buf[3] = (uint8_t)(((pkt_size-4) >> 8) & 0x00FF); + + return pkt_size; +} + +int mt6620_tune_ack(unsigned char *tx_buf, int tx_buf_size) +{ + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_EVENT_PKT_TYPE; + tx_buf[1] = FM_TUNE_OPCODE; + tx_buf[2] = 0x00; + tx_buf[3] = 0x00; + + return 4; +} + +// TBD for IC +int mt6620_seek_1(unsigned char *tx_buf, int tx_buf_size, uint16_t seekdir, uint16_t space, uint16_t max_freq, uint16_t min_freq) +{ + int pkt_size = 0; + + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE; + tx_buf[1] = FM_SEEK_OPCODE; + pkt_size = 4; + + //A1 Program seek direction, 0x66[10]: 0=seek up, 1=seek down + if(seekdir == MT6620_FM_SEEK_UP){ + pkt_size += fm_bop_modify(0x66, 0xFBFF, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//0x66[10] = 0, seek up + }else{ + pkt_size += fm_bop_modify(0x66, 0xFFFF, 0x0400, &tx_buf[pkt_size], tx_buf_size - pkt_size);//0x66[10] = 1, seek down + } + //0x66[11] 0=no wrarp, 1=wrap + pkt_size += fm_bop_modify(0x66, 0xFFFF, 0x0800, &tx_buf[pkt_size], tx_buf_size - pkt_size);//0x66[11] = 1, wrap + //A2 Program scan channel spacing, 0x66[14:12] step 50KHz:001/100KHz:010/200KHz:100 + if(space == MT6620_FM_SPACE_50K){ + pkt_size += fm_bop_modify(0x66, 0x8FFF, 0x1000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//clear 0x66[14:12] then 0x66[14:12]=001 + }else if(space == MT6620_FM_SPACE_100K){ + pkt_size += fm_bop_modify(0x66, 0x8FFF, 0x2000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//clear 0x66[14:12] then 0x66[14:12]=010 + }else if(space == MT6620_FM_SPACE_200K){ + pkt_size += fm_bop_modify(0x66, 0x8FFF, 0x4000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//clear 0x66[14:12] then 0x66[14:12]=100 + } + + //0x66[9:0] freq upper bound + max_freq = (max_freq - 640) * 2; + pkt_size += fm_bop_modify(0x66, 0xFC00, max_freq, &tx_buf[pkt_size], tx_buf_size - pkt_size); + + //0x67[9:0] freq lower bound + min_freq = (min_freq - 640) * 2; + pkt_size += fm_bop_modify(0x67, 0xFC00, min_freq, &tx_buf[pkt_size], tx_buf_size - pkt_size); + //A3 Enable hardware controlled seeking sequence + pkt_size += fm_bop_modify(0x63, 0xFFFF, 0x0002, &tx_buf[pkt_size], tx_buf_size - pkt_size);//0x63[1] = 1 + + tx_buf[2] = (uint8_t)((pkt_size-4) & 0x00FF); + tx_buf[3] = (uint8_t)(((pkt_size-4) >> 8) & 0x00FF); + + return pkt_size; +} + +int mt6620_seek_2(unsigned char *tx_buf, int tx_buf_size, uint16_t seekdir, uint16_t space, uint16_t max_freq, uint16_t min_freq) +{ + int pkt_size = 0; + + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE; + tx_buf[1] = FM_SEEK_OPCODE; + pkt_size = 4; + + //A10 Set softmute to normal mode + pkt_size += fm_bop_write(0x9F, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9F 1 + pkt_size += fm_bop_write(0xC8, 0x0232, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr C8 232 + pkt_size += fm_bop_write(0xDD, 0x8833, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr DD 8833 + pkt_size += fm_bop_write(0xD8, 0x00E8, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr D8 E8 + pkt_size += fm_bop_write(0x9F, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9F 0 + + tx_buf[2] = (uint8_t)((pkt_size-4) & 0x00FF); + tx_buf[3] = (uint8_t)(((pkt_size-4) >> 8) & 0x00FF); + + return pkt_size; +} + +int mt6620_seek_ack(unsigned char *tx_buf, int tx_buf_size) +{ + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_EVENT_PKT_TYPE; + tx_buf[1] = FM_SEEK_OPCODE; + tx_buf[2] = 0x00; + tx_buf[3] = 0x00; + + return 4; +} + +int mt6620_scan_1(unsigned char *tx_buf, int tx_buf_size, uint16_t scandir, uint16_t space, uint16_t max_freq, uint16_t min_freq) +{ + int pkt_size = 0; + + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE; + tx_buf[1] = FM_SCAN_OPCODE; + pkt_size = 4; + + //A1 Program scan direction, 0x66[10]: 0=seek up, 1=seek down + if(scandir == MT6620_FM_SCAN_UP){ + pkt_size += fm_bop_modify(0x66, 0xFBFF, 0x0000, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);//0x66[10] = 0, seek up + }else{ + pkt_size += fm_bop_modify(0x66, 0xFFFF, 0x0400, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);//0x66[10] = 1, seek down + } + //0x66[11] 0=no wrarp, 1=wrap + pkt_size += fm_bop_modify(0x66, 0xFFFF, 0x0800, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);//0x66[11] = 1, wrap + //A2 Program scan channel spacing, 0x66[14:12] step 50KHz:001/100KHz:010/200KHz:100 + if(space == MT6620_FM_SPACE_50K){ + pkt_size += fm_bop_modify(0x66, 0x8FFF, 0x1000, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);//clear 0x66[14:12] then 0x66[14:12]=001 + }else if(space == MT6620_FM_SPACE_100K){ + pkt_size += fm_bop_modify(0x66, 0x8FFF, 0x2000, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);//clear 0x66[14:12] then 0x66[14:12]=010 + }else if(space == MT6620_FM_SPACE_200K){ + pkt_size += fm_bop_modify(0x66, 0x8FFF, 0x4000, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);//clear 0x66[14:12] then 0x66[14:12]=100 + } + + //0x66[9:0] freq upper bound + max_freq = (max_freq - 640) * 2; + pkt_size += fm_bop_modify(0x66, 0xFC00, max_freq, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size); + + //0x67[9:0] freq lower bound + min_freq = (min_freq - 640) * 2; + pkt_size += fm_bop_modify(0x67, 0xFC00, min_freq, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size); + + //A3 Enable hardware controlled scanning sequence + pkt_size += fm_bop_modify(0x63, 0xFFFF, 0x0004, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);//0x63[2] = 1 + + tx_buf[2] = (uint8_t)((pkt_size-4) & 0x00FF); + tx_buf[3] = (uint8_t)(((pkt_size-4) >> 8) & 0x00FF); + + return pkt_size; +} + +int mt6620_scan_2(unsigned char *tx_buf, int tx_buf_size, uint16_t scandir, uint16_t space, uint16_t max_freq, uint16_t min_freq) +{ + int pkt_size = 0; + + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE; + tx_buf[1] = FM_SCAN_OPCODE; + pkt_size = 4; + + //A10 Set softmute to normal mode + pkt_size += fm_bop_write(0x9F, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9F 1 + pkt_size += fm_bop_write(0xC8, 0x0232, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr C8 232 + pkt_size += fm_bop_write(0xDD, 0x8833, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr DD 8833 + pkt_size += fm_bop_write(0xD8, 0x00E8, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr D8 E8 + pkt_size += fm_bop_write(0x9F, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9F 0 + + tx_buf[2] = (uint8_t)((pkt_size-4) & 0x00FF); + tx_buf[3] = (uint8_t)(((pkt_size-4) >> 8) & 0x00FF); + + return pkt_size; +} + +int mt6620_com(unsigned char *tx_buf, int tx_buf_size, int opcode, void* data) +{ + int pkt_size = 0; + + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE; + tx_buf[1] = FM_ENABLE_OPCODE; //FM_ENABLE_OPCODE can be used by other user + pkt_size = 4; + + switch(opcode){ + case FM_COM_CMD_TEST: + //disable mute + pkt_size += fm_bop_modify(0x9C, 0xFFF7, 0x0000, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);//0x9c[3] = 0 + break; + case FM_COM_CMD_SCAN: + //A7 Set to read page 1 + pkt_size += fm_bop_modify(0x9F, 0xFFFC, 0x0001, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);//0x9F D0~D1 = 01 + //A8 Read back channel scan bit_map information + //A9 disable mute + pkt_size += fm_bop_modify(0x9C, 0xFFF7, 0x0000, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);//0x9c[3] = 0 + pkt_size += fm_bop_udelay(35000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 35ms + //A10 Set softmute to normal mode + pkt_size += fm_bop_write(0x9F, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9F 1 + pkt_size += fm_bop_write(0xC8, 0x0232, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr C8 232 + pkt_size += fm_bop_write(0xDD, 0x8833, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr DD 8833 + pkt_size += fm_bop_write(0xD8, 0x00E8, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr D8 E8 + pkt_size += fm_bop_write(0x9F, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9F 0 + break; + case FM_COM_CMD_SEEK: + //A7 Set to read page 1 + pkt_size += fm_bop_modify(0x9F, 0xFFFC, 0x0001, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);//0x9F D0~D1 = 01 + //A8 Read back channel scan bit_map information + //A9 disable mute + pkt_size += fm_bop_modify(0x9C, 0xFFF7, 0x0000, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);//0x9c[3] = 0 + pkt_size += fm_bop_udelay(35000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 35ms + //A10 Set softmute to normal mode + pkt_size += fm_bop_write(0x9F, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9F 1 + pkt_size += fm_bop_write(0xC8, 0x0232, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr C8 232 + pkt_size += fm_bop_write(0xDD, 0x8833, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr DD 8833 + pkt_size += fm_bop_write(0xD8, 0x00E8, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr D8 E8 + pkt_size += fm_bop_write(0x9F, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9F 0 + break; + default: + return -1; + break; + } + + tx_buf[2] = (uint8_t)((pkt_size-4) & 0x00FF); + tx_buf[3] = (uint8_t)(((pkt_size-4) >> 8) & 0x00FF); + + return pkt_size; +} + +int mt6620_scan_ack(unsigned char *tx_buf, int tx_buf_size) +{ + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_EVENT_PKT_TYPE; + tx_buf[1] = FM_SCAN_OPCODE; + tx_buf[2] = 0x00; + tx_buf[3] = 0x00; + + return 4; +} + +int mt6620_rds_rx_enable(unsigned char *tx_buf, int tx_buf_size) //IC version +{ + int pkt_size = 0; + + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE; + tx_buf[1] = RDS_RX_ENABLE_OPCODE; + pkt_size = 4; + + pkt_size += fm_bop_write(0x9F, 0x0003, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 0x9f 3 + pkt_size += fm_bop_write(0xCB, 0xE016, &tx_buf[pkt_size], tx_buf_size - pkt_size);//Wr 0xcb e016 + pkt_size += fm_bop_write(0x9F, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 0x9f 0 + pkt_size += fm_bop_write(0x63, 0x0491, &tx_buf[pkt_size], tx_buf_size - pkt_size);//Wr 0x63 491 + pkt_size += fm_bop_modify(0x6B, 0xFFFF, 0x2000, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);//Wr 0x6b [13] = 1 + + tx_buf[2] = (uint8_t)((pkt_size-4) & 0x00FF); + tx_buf[3] = (uint8_t)(((pkt_size-4) >> 8) & 0x00FF); + + return pkt_size; +} + +int mt6620_rds_rx_enable_ack(unsigned char *tx_buf, int tx_buf_size) //IC version +{ + int pkt_size = 0; + + pkt_size = 0; + + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_EVENT_PKT_TYPE; + tx_buf[1] = RDS_RX_ENABLE_OPCODE; + tx_buf[2] = 0x00; + tx_buf[3] = 0x00; + + return 4; +} + +int mt6620_rds_rx_disable(unsigned char *tx_buf, int tx_buf_size) //IC version +{ + int pkt_size = 0; + + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE; + tx_buf[1] = RDS_RX_ENABLE_OPCODE; + pkt_size = 4; + + pkt_size += fm_bop_modify(0x6B, 0xDFFF, 0x0000, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);//Wr 0x6b [13] = 0 + pkt_size += fm_bop_write(0x63, 0x0481, &tx_buf[pkt_size], tx_buf_size - pkt_size);//Wr 0x63 481 + + + tx_buf[2] = (uint8_t)((pkt_size-4) & 0x00FF); + tx_buf[3] = (uint8_t)(((pkt_size-4) >> 8) & 0x00FF); + + return pkt_size; +} + +int mt6620_rds_rx_disable_ack(unsigned char *tx_buf, int tx_buf_size) //IC version +{ + int pkt_size = 0; + + pkt_size = 0; + + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_EVENT_PKT_TYPE; + tx_buf[1] = RDS_RX_ENABLE_OPCODE; + tx_buf[2] = 0x00; + tx_buf[3] = 0x00; + + return 4; +} + +// TBD for IC +int mt6620_rds_tx(unsigned char *tx_buf, int tx_buf_size, uint16_t pi, uint16_t *ps, uint16_t *other_rds, uint8_t other_rds_cnt) +{ + int pkt_size = 0; + int i; + + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + if(other_rds_cnt > 29){ + return (-2); + } + + tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE; + tx_buf[1] = RDS_TX_OPCODE; + pkt_size = 4; + + //RDS Tx config + pkt_size += fm_bop_modify(0x65, 0xFFFF, 0x0010, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);//wr 65[4] = b'1, enable RDS Tx + pkt_size += fm_bop_write(0x9F, 0x0003, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9F 3 + pkt_size += fm_bop_write(0xA2, 0x0005, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a2 5, repeat + PI_reg mode + pkt_size += fm_bop_write(0xA1, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a1 0 + //pkt_size += fm_bop_write(0xA0, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a0 1 + pkt_size += fm_bop_write(0xA4, pi, &tx_buf[pkt_size], tx_buf_size - pkt_size);//write PI to PI_reg + //program PS buf + pkt_size += fm_bop_rd_until(0xAA, 0x0001, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);// rd until aa[0] = b'0, ptr in normal buf + //program normal buf, workaround that PS buf can't work while normal buf is empty + for(i = 0; i < 12; i++) + { + pkt_size += fm_bop_write(0xA8, ps[i], &tx_buf[pkt_size], tx_buf_size - pkt_size);//a8 = RDS Tx data + } + pkt_size += fm_bop_modify(0xA2, 0xFFFF, 0x0002, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);//wr a2[1] = b'1, mem_addr mode + for(i = 0; i < 12; i++) + { + pkt_size += fm_bop_write(0xA7, (0x0063+i), &tx_buf[pkt_size], tx_buf_size - pkt_size);//a7 = mem_addr + pkt_size += fm_bop_write(0xA8, ps[i], &tx_buf[pkt_size], tx_buf_size - pkt_size);//a8 = RDS Tx data + } + pkt_size += fm_bop_modify(0xA2, 0xFFFF, 0x0010, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);//wr a2[4] = b'1, switch to ps buf + //program normal buf + pkt_size += fm_bop_rd_until(0xAA, 0x0001, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);// rd until aa[0] = b'1, ptr in ps buf + pkt_size += fm_bop_modify(0xA2, 0xFFFD, 0x0000, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);//wr a2[1] = b'0, h/w addr mode + for(i = 0; i < 12; i++) + { + pkt_size += fm_bop_write(0xA8, ps[i], &tx_buf[pkt_size], tx_buf_size - pkt_size);//a8 = RDS Tx data + } + for(i = 0; i < (other_rds_cnt * 3); i++) + { + pkt_size += fm_bop_write(0xA8, other_rds[i], &tx_buf[pkt_size], tx_buf_size - pkt_size);//a8 = RDS Tx data + } + pkt_size += fm_bop_modify(0xA2, 0xFFEF, 0x0000, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);//wr a2[4] = b'0, switch to normal buf + pkt_size += fm_bop_write(0x9F, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9F 0 + + tx_buf[2] = (uint8_t)((pkt_size-4) & 0x00FF); + tx_buf[3] = (uint8_t)(((pkt_size-4) >> 8) & 0x00FF); + + return pkt_size; +} + +int mt6620_rds_tx_ack(unsigned char *tx_buf, int tx_buf_size) +{ + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_EVENT_PKT_TYPE; + tx_buf[1] = RDS_TX_OPCODE; + tx_buf[2] = 0x00; + tx_buf[3] = 0x00; + + return 4; +} + +int mt6620_get_reg(unsigned char *tx_buf, int tx_buf_size, uint8_t addr) +{ + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE; + tx_buf[1] = FSPI_READ_OPCODE; + tx_buf[2] = 0x01; + tx_buf[3] = 0x00; + tx_buf[4] = addr; + + return 5; +} + +int mt6620_set_reg(unsigned char *tx_buf, int tx_buf_size, uint8_t addr, uint16_t value) +{ + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE; + tx_buf[1] = FSPI_WRITE_OPCODE; + tx_buf[2] = 0x03; + tx_buf[3] = 0x00; + tx_buf[4] = addr; + tx_buf[5] = (uint8_t)((value) & 0x00FF); + tx_buf[6] = (uint8_t)((value >> 8) & 0x00FF); + + return 7; +} + +int mt6620_set_reg_ack(unsigned char *tx_buf, int tx_buf_size) +{ + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_EVENT_PKT_TYPE; + tx_buf[1] = FSPI_WRITE_OPCODE; + tx_buf[2] = 0x00; + tx_buf[3] = 0x00; + + return 4; +} + +// TBD for IC +int mt6620_off_2_tx_shortANA(unsigned char *tx_buf, int tx_buf_size) +{ + int pkt_size = 0; + + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE; + tx_buf[1] = FM_ENABLE_OPCODE; + pkt_size = 4; + + pkt_size += fm_bop_write(0x01, 0x4A00, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 1 4A00 --> Turn on Central Bias + FC + pkt_size += fm_bop_udelay(30, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 30 + pkt_size += fm_bop_write(0x01, 0x6A00, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 1 6A00 --> Turn off FC + pkt_size += fm_bop_udelay(50, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 50 + pkt_size += fm_bop_write(0x02, 0x299C, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 2 299C --> Set the LDOs Output Voltages + pkt_size += fm_bop_write(0x01, 0x6B82, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 1 6B82 --> Turn on DCO, RX and ADDA LDO + pkt_size += fm_bop_write(0x3B, 0x0500, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 3B 0500 --> Turn on PA LDO --> LDO PA = 2.5V [0000 010x xxx0 000] {xxxx} - 0001 = 2.5V + pkt_size += fm_bop_write(0x04, 0x0548, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 4 0548 --> Set the RX LDO to Low Power Mode + TR Switch Off + pkt_size += fm_bop_write(0x37, 0x2000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 37 2000 --> Set the Short Antenna Bias + pkt_size += fm_bop_write(0x42, 0xC002, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 42 C002 --> Set the Short Antenna Bias + pkt_size += fm_bop_write(0x0A, 0x0060, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr A 0060 --> Update AFCDAC LPF Setting + pkt_size += fm_bop_write(0x0E, 0x0040, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr E 0040 --> Update SX_VDC_CBANK + pkt_size += fm_bop_write(0x0C, 0xA88C, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr c A88C + pkt_size += fm_bop_write(0x10, 0x1E8D, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 10 1e8d + pkt_size += fm_bop_write(0x27, 0x0005, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 27 0005 --> Update ACAL and Enable RMS_DET + pkt_size += fm_bop_write(0x11, 0x07D8, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 11 07D8 --> Set VCO_DIVRST_N = 0 + pkt_size += fm_bop_write(0x41, 0x0003, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 41 0003 --> Set TX_FVCO_EN = 1 and FVCO_SEL=1 + pkt_size += fm_bop_write(0x08, 0x25B8, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 8 25b8 --> ADC = TX Mode (AU_ADC) + pkt_size += fm_bop_write(0x09, 0x2964, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9 2964 --> ADC DWA ON + pkt_size += fm_bop_write(0x3F, 0xAD86, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 3F AD86 --> TX DAc RX_TX_SEL = TX MOde + pkt_size += fm_bop_write(0x3A, 0x01EF, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 3A 01EF --> Turn on TX Chain [PA+D2S+HRM+AUPGA+TXDAC+LODIV] + pkt_size += fm_bop_write(0x3E, 0x3181, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 3E 3181 --> TX LPF EN + CSEL from RCCAL + pkt_size += fm_bop_write(0x00, 0x0100, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 0 0100 --> Turn on SDADC + pkt_size += fm_bop_write(0x37, 0x2000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 37 2000 --> Control Signal for DAC_CK output clock gate + //FM ADPLL Power Up + pkt_size += fm_bop_write(0x25, 0x040F, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 25 040f --> Turn off DIG_CK_EN + pkt_size += fm_bop_write(0x20, 0x2720, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 20 2720 --> Turn on ADPLL 2320 CW32 + //XHC,2011/03/18, [wr 22 9980-> 6680] + pkt_size += fm_bop_write(0x22, 0x6680, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 22 9980 --> Update DLF Gain + pkt_size += fm_bop_write(0x25, 0x080F, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 25 080f --> Update I_CODE_CCAL + ADC_CK_EN + 32KCLKPLL_EN 0803 CW37 + pkt_size += fm_bop_write(0x1E, 0x0863, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 1e 0863 --> Turn on DCO + CAL_COARSE_EN + pkt_size += fm_bop_udelay(5000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 5000 + pkt_size += fm_bop_write(0x1E, 0x0865, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 1e 0865 --> Change the CAL_COARSE to CAL_FINE + pkt_size += fm_bop_udelay(5000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 5000 + pkt_size += fm_bop_write(0x1E, 0x0871, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 1e 0871 --> Off the CAL_COARSE and CAL_FINE + Turn on PLL + pkt_size += fm_bop_udelay(100000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 100000 + pkt_size += fm_bop_write(0x2A, 0x1026, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 2a 1022 --> Enable TOP_CG + //FM RC Calibration + pkt_size += fm_bop_write(0x00, 0x0080, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 0 0080 --> RCCAL + pkt_size += fm_bop_udelay(1, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 1000 + pkt_size += fm_bop_write(0x1B, 0x0094, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 1b 0094 --> Update RCCAL Target Count + pkt_size += fm_bop_write(0x1B, 0x0095, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 1b 0095 --> Start RCCAL + pkt_size += fm_bop_udelay(200, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 1000 + pkt_size += fm_bop_write(0x1B, 0x0094, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 1b 0094 --> Off RCCAL + pkt_size += fm_bop_write(0x00, 0x0100, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 0 0100 --> Turn off RCCAL Analog Block + //FM VCO Enable + pkt_size += fm_bop_write(0x01, 0x6B8A, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 1 6B8A --> Turn on VCO LDO + pkt_size += fm_bop_udelay(1, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 1000 + pkt_size += fm_bop_write(0x00, 0xC100, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 0 C100 --> Turn on VCO, AFCDAC + pkt_size += fm_bop_write(0x0C, 0xB88C, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr c B88c --> Turn on Const gm + pkt_size += fm_bop_udelay(3000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 3000 + pkt_size += fm_bop_write(0x3A, 0x01FF, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 3A 01FF --> Enable TX Divider + //Short Antenna Setting + pkt_size += fm_bop_write(0x42, 0xF002, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 42 F002 --> MSB of HRM_Gain <5> ****>> For Max Pout + pkt_size += fm_bop_write(0x3C, 0xABE9, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 3C ABE9 --> Max HRM Gain<4:0> - xxxxx [1010 10xx xxx0 1001] + pkt_size += fm_bop_write(0x3D, 0x027E, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 3D 027E --> Max PA Gain<4:0> - [0000 0010 0xxx xx10] + pkt_size += fm_bop_write(0x33, 0x0008, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 33 0008 --> Use old VCO calibration routine to save calibration time + pkt_size += fm_bop_write(0x28, 0xFFFF, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 28 FFFF + pkt_size += fm_bop_write(0x2E, 0x0020, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 2E 0020 --> Turn on SCAL_HWTRIG_DIS --> VCO CAL and SCAL are done separately + pkt_size += fm_bop_write(0x2F, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 2F 0000 --> Disable Capbank manual enter mode [4A40 previously] + pkt_size += fm_bop_write(0x44, 0x006E, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 44 6e + pkt_size += fm_bop_write(0x46, 0xDC22, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 46 DC22 + pkt_size += fm_bop_write(0x49, 0x0080, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 49 80 + pkt_size += fm_bop_write(0x4A, 0x0004, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 4A 4 + pkt_size += fm_bop_write(0x4B, 0x0040, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 4B 40 + + tx_buf[2] = (uint8_t)((pkt_size-4) & 0x00FF); + tx_buf[3] = (uint8_t)(((pkt_size-4) >> 8) & 0x00FF); + + return pkt_size; +} + +int mt6620_off_2_tx_shortANA_ack(unsigned char *tx_buf, int tx_buf_size) +{ + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_EVENT_PKT_TYPE; + tx_buf[1] = FM_ENABLE_OPCODE; + tx_buf[2] = 0x00; + tx_buf[3] = 0x00; + + return 4; +} + +// TBD for IC +int mt6620_dig_init(unsigned char *tx_buf, int tx_buf_size) +{ + int pkt_size = 0; + + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE; + tx_buf[1] = FM_ENABLE_OPCODE; + pkt_size = 4; + +//fm_rgf_maincon + pkt_size += fm_bop_write(0x64, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 64 0 + pkt_size += fm_bop_write(0x65, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 65 1 + pkt_size += fm_bop_write(0x68, 0xE100, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 68 E100 + pkt_size += fm_bop_udelay(10000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//delay 10000 + pkt_size += fm_bop_write(0x68, 0xE000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 68 E000 +//fm_rgf_dac + pkt_size += fm_bop_write(0x9F, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9F 0 + pkt_size += fm_bop_write(0x9E, 0x001C, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9E 1C + pkt_size += fm_bop_write(0x9C, 0xA540, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9c A540 +//fm_rgf_front + pkt_size += fm_bop_write(0x9F, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9f 0 --> start rgf_front + pkt_size += fm_bop_write(0xB8, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr b8 1 + pkt_size += fm_bop_write(0xAB, 0x39B6, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr ab 39b6 + pkt_size += fm_bop_write(0xAC, 0x3C3E, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr ac 3c3e + pkt_size += fm_bop_write(0xAD, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr ad 0 + pkt_size += fm_bop_write(0xAE, 0x03C2, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr ae 3c2 + pkt_size += fm_bop_write(0xAF, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr af 1 + pkt_size += fm_bop_write(0xB1, 0x623D, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr b1 623d + pkt_size += fm_bop_write(0xF4, 0x0020, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr f4 20 + pkt_size += fm_bop_write(0xF5, 0xBF16, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr f5 bf16 + pkt_size += fm_bop_write(0xB9, 0x0050, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr b9 0050 + pkt_size += fm_bop_write(0xBA, 0x00C3, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr ba 00c3 + pkt_size += fm_bop_write(0xBB, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr bb 0 + pkt_size += fm_bop_write(0xBC, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr bc 0 + pkt_size += fm_bop_write(0xBD, 0x0056, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr bd 56 + pkt_size += fm_bop_write(0xBE, 0x0089, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr be 89 + pkt_size += fm_bop_write(0xBF, 0x004C, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr bf 4c + pkt_size += fm_bop_write(0xC0, 0x0171, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr c0 171 + pkt_size += fm_bop_write(0xC1, 0x002B, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr c1 2b + pkt_size += fm_bop_write(0xC2, 0x001F, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr c2 1f + pkt_size += fm_bop_write(0xC3, 0x0066, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr c3 66 + pkt_size += fm_bop_write(0xC4, 0x00F6, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr c4 f6 + pkt_size += fm_bop_write(0xC5, 0x0066, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr c5 66 + pkt_size += fm_bop_write(0xC6, 0x001F, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr c6 1f + pkt_size += fm_bop_write(0xC7, 0x0007, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr c7 7 + pkt_size += fm_bop_write(0xFE, 0x0039, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr fe 39 + pkt_size += fm_bop_write(0xFF, 0x3907, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr ff 3907 +//fm_rgf_fmx + pkt_size += fm_bop_write(0x9F, 0x0001, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9f 1 --> start rgf_outer + pkt_size += fm_bop_write(0xC0, 0x076C, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr c0 76c + pkt_size += fm_bop_write(0xB7, 0x0004, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr b7 4 + pkt_size += fm_bop_write(0xD8, 0x006A, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr d8 6a + pkt_size += fm_bop_write(0xC8, 0x2828, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr c8 2828 + pkt_size += fm_bop_write(0xCE, 0x0090, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr ce 90 + pkt_size += fm_bop_write(0xFE, 0x000F, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr fe f + pkt_size += fm_bop_write(0xA2, 0x0100, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a2 100 + pkt_size += fm_bop_write(0xA3, 0x0111, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a3 111 + pkt_size += fm_bop_write(0xA4, 0x0122, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a4 122 + pkt_size += fm_bop_write(0xA5, 0x0135, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a5 135 + pkt_size += fm_bop_write(0xA6, 0x0149, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a6 149 + pkt_size += fm_bop_write(0xA7, 0x015E, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a7 15e + pkt_size += fm_bop_write(0xDB, 0x0174, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr db 174 + pkt_size += fm_bop_write(0xDC, 0x018D, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr dc 18d + pkt_size += fm_bop_write(0xC9, 0x01A6, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr c9 1a6 + pkt_size += fm_bop_write(0xCA, 0x01C1, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr ca 1c1 + pkt_size += fm_bop_write(0xCB, 0x01DE, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr cb 1de + pkt_size += fm_bop_write(0xCC, 0x01FD, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr cc 1fd + pkt_size += fm_bop_write(0xD4, 0x2657, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr d4 2657 + pkt_size += fm_bop_write(0xA0, 0x85B2, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr a0 85b2 + pkt_size += fm_bop_write(0x9F, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 9f 0 + + tx_buf[2] = (uint8_t)((pkt_size-4) & 0x00FF); + tx_buf[3] = (uint8_t)(((pkt_size-4) >> 8) & 0x00FF); + + return pkt_size; +} + +int mt6620_dig_init_ack(unsigned char *tx_buf, int tx_buf_size) +{ + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_EVENT_PKT_TYPE; + tx_buf[1] = FM_ENABLE_OPCODE; + tx_buf[2] = 0x00; + tx_buf[3] = 0x00; + + return 4; +} + +// TBD for IC +int mt6620_ant_switch(unsigned char *tx_buf, int tx_buf_size, int dir) // dir: 0=long2short / 1=short2long +{ + int pkt_size = 0; + + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE; + tx_buf[1] = FM_ENABLE_OPCODE; + pkt_size = 4; + + if(dir == 0){ + // long2short + pkt_size += fm_bop_write(0x04, 0x0145, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 4 0145 + pkt_size += fm_bop_write(0x05, 0x00FF, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 5 00FF + pkt_size += fm_bop_write(0x26, 0x0024, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 26 0024 + pkt_size += fm_bop_write(0x2E, 0x0000, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 2E 0000 + }else{ + // short2long + pkt_size += fm_bop_write(0x04, 0x0142, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 4 0142 + pkt_size += fm_bop_write(0x05, 0x00E7, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 5 00E7 + pkt_size += fm_bop_write(0x26, 0x0004, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 26 0004 + pkt_size += fm_bop_write(0x2E, 0x0008, &tx_buf[pkt_size], tx_buf_size - pkt_size);//wr 2E 0008 + } + + tx_buf[2] = (uint8_t)((pkt_size-4) & 0x00FF); + tx_buf[3] = (uint8_t)(((pkt_size-4) >> 8) & 0x00FF); + + return pkt_size; +} + +int mt6620_ant_switch_ack(unsigned char *tx_buf, int tx_buf_size) +{ + if(tx_buf_size < TX_BUF_SIZE){ + return (-1); + } + + tx_buf[0] = FM_TASK_EVENT_PKT_TYPE; + tx_buf[1] = FM_ENABLE_OPCODE; + tx_buf[2] = 0x00; + tx_buf[3] = 0x00; + + return 4; +} + diff --git a/drivers/mtk_wcn_combo/drv_fm/public/mt6620_fm_lib.h b/drivers/mtk_wcn_combo/drv_fm/public/mt6620_fm_lib.h new file mode 100755 index 000000000000..17b40d723154 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_fm/public/mt6620_fm_lib.h @@ -0,0 +1,94 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +#include + +//#define MT6620_FPGA + +#define FM_MAIN_PGSEL (0x9F) +#define FM_MAIN_BASE (0x0) +#define FM_MAIN_BITMAP0 (FM_MAIN_BASE + 0x80) +#define FM_MAIN_BITMAP1 (FM_MAIN_BASE + 0x81) +#define FM_MAIN_BITMAP2 (FM_MAIN_BASE + 0x82) +#define FM_MAIN_BITMAP3 (FM_MAIN_BASE + 0x83) +#define FM_MAIN_BITMAP4 (FM_MAIN_BASE + 0x84) +#define FM_MAIN_BITMAP5 (FM_MAIN_BASE + 0x85) +#define FM_MAIN_BITMAP6 (FM_MAIN_BASE + 0x86) +#define FM_MAIN_BITMAP7 (FM_MAIN_BASE + 0x87) +#define FM_MAIN_BITMAP8 (FM_MAIN_BASE + 0x88) +#define FM_MAIN_BITMAP9 (FM_MAIN_BASE + 0x89) +#define FM_MAIN_BITMAPA (FM_MAIN_BASE + 0x8a) +#define FM_MAIN_BITMAPB (FM_MAIN_BASE + 0x8b) +#define FM_MAIN_BITMAPC (FM_MAIN_BASE + 0x8c) +#define FM_MAIN_BITMAPD (FM_MAIN_BASE + 0x8d) +#define FM_MAIN_BITMAPE (FM_MAIN_BASE + 0x8e) +#define FM_MAIN_BITMAPF (FM_MAIN_BASE + 0x8f) + +int mt6620_off_2_longANA(unsigned char *tx_buf, int tx_buf_size); +int mt6620_off_2_longANA_ack(unsigned char *tx_buf, int tx_buf_size); +int mt6620_rx_digital_init(unsigned char *tx_buf, int tx_buf_size); +int mt6620_rx_digital_init_ack(unsigned char *tx_buf, int tx_buf_size); +int mt6620_powerdown(unsigned char *tx_buf, int tx_buf_size); +int mt6620_powerdown_ack(unsigned char *tx_buf, int tx_buf_size); +int mt6620_rampdown(unsigned char *tx_buf, int tx_buf_size); +int mt6620_rampdown_tx(unsigned char *tx_buf, int tx_buf_size); +int mt6620_rampdown_ack(unsigned char *tx_buf, int tx_buf_size); +int mt6620_tune_1(unsigned char *tx_buf, int tx_buf_size, uint16_t freq); +int mt6620_tune_2(unsigned char *tx_buf, int tx_buf_size, uint16_t freq); +int mt6620_tune_3(unsigned char *tx_buf, int tx_buf_size, uint16_t freq); +int mt6620_fast_tune(unsigned char *tx_buf, int tx_buf_size, uint16_t freq); +int mt6620_tune_txscan(unsigned char *tx_buf, int tx_buf_size, uint16_t freq); +int mt6620_tune_tx(unsigned char *tx_buf, int tx_buf_size, uint16_t freq); +int mt6620_tune_ack(unsigned char *tx_buf, int tx_buf_size); +int mt6620_seek_1(unsigned char *tx_buf, int tx_buf_size, uint16_t seekdir, uint16_t space, uint16_t max_freq, uint16_t min_freq); +int mt6620_seek_2(unsigned char *tx_buf, int tx_buf_size, uint16_t seekdir, uint16_t space, uint16_t max_freq, uint16_t min_freq); +int mt6620_seek_ack(unsigned char *tx_buf, int tx_buf_size); +int mt6620_scan_1(unsigned char *tx_buf, int tx_buf_size, uint16_t scandir, uint16_t space, uint16_t max_freq, uint16_t min_freq); +int mt6620_scan_2(unsigned char *tx_buf, int tx_buf_size, uint16_t scandir, uint16_t space, uint16_t max_freq, uint16_t min_freq); +int mt6620_scan_ack(unsigned char *tx_buf, int tx_buf_size); +int mt6620_rds_rx_enable(unsigned char *tx_buf, int tx_buf_size); +int mt6620_rds_rx_enable_ack(unsigned char *tx_buf, int tx_buf_size); +int mt6620_rds_rx_disable(unsigned char *tx_buf, int tx_buf_size); +int mt6620_rds_rx_disable_ack(unsigned char *tx_buf, int tx_buf_size); +int mt6620_rds_tx(unsigned char *tx_buf, int tx_buf_size, uint16_t pi, uint16_t *ps, uint16_t *other_rds, uint8_t other_rds_cnt); +int mt6620_rds_tx_ack(unsigned char *tx_buf, int tx_buf_size); +int mt6620_get_reg(unsigned char *tx_buf, int tx_buf_size, uint8_t addr); +int mt6620_set_reg(unsigned char *tx_buf, int tx_buf_size, uint8_t addr, uint16_t value); +int mt6620_set_reg_ack(unsigned char *tx_buf, int tx_buf_size); +int mt6620_off_2_tx_shortANA(unsigned char *tx_buf, int tx_buf_size); +int mt6620_off_2_tx_shortANA_ack(unsigned char *tx_buf, int tx_buf_size); +int mt6620_dig_init(unsigned char *tx_buf, int tx_buf_size); +int mt6620_dig_init_ack(unsigned char *tx_buf, int tx_buf_size); +int mt6620_com(unsigned char *tx_buf, int tx_buf_size, int opcode, void* data); diff --git a/drivers/mtk_wcn_combo/drv_fm/public/mt6620_fm_reg.h b/drivers/mtk_wcn_combo/drv_fm/public/mt6620_fm_reg.h new file mode 100755 index 000000000000..2f1e9c3ff3b3 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_fm/public/mt6620_fm_reg.h @@ -0,0 +1,65 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +#ifndef __MT6620_FM_REG_H__ +#define __MT6620_FM_REG_H__ + +//private chip define +#define MT6620_FM_PGSEL (0x9F) +#define MT6620_FM_RSSI_IND (0xE8) +#define MT6620_FM_PAMD_IND (0xE9) +#define MT6620_FM_MR_IND (0xF2) +#define MT6620_FM_STEROMONO_IND (0xF8) +#define MT6620_FM_STEROMONO_CTR (0xE0) + +//common define +#define FM_PGSEL MT6620_FM_PGSEL +#define FM_RSSI_IND MT6620_FM_RSSI_IND +#define FM_PAMD_IND MT6620_FM_PAMD_IND +#define FM_MR_IND MT6620_FM_MR_IND +#define FM_STEROMONO_IND MT6620_FM_STEROMONO_IND +#define FM_STEROMONO_CTR MT6620_FM_STEROMONO_CTR + +//FM reg page +enum FM_PAGE{ + FM_PG0 = 0, + FM_PG1, + FM_PG2, + FM_PG3, + FM_PGMAX +}; + +#endif //__MT6620_FM_REG_H__ + diff --git a/drivers/mtk_wcn_combo/drv_fm/public/mt6620_rds.c b/drivers/mtk_wcn_combo/drv_fm/public/mt6620_rds.c new file mode 100755 index 000000000000..c848ff57be5b --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_fm/public/mt6620_rds.c @@ -0,0 +1,1878 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +#include +#include +#include +#include // udelay() +#include // device_create() +#include +#include +#include +#include + +#include // get_user() + +#include "fm.h" +#include "mt6620_fm.h" +#include "mt6620_fm_lib.h" + +/****************************************************************************** + * GLOBAL DATA + *****************************************************************************/ +#define MT6620_RDS_BLER_TH1 90 +#define MT6620_RDS_BLER_TH2 60 +#define MT6620_RDS_BLER_C1 12 +#define MT6620_RDS_BLER_C2 6 +#define MT6620_RDS_BLER_T1 5000 +#define MT6620_RDS_BLER_T2 5000 + +//FM_RDS_DATA_CRC_FFOST(0xB2) +#define FM_RDS_GDBK_IND_A (0x08) +#define FM_RDS_GDBK_IND_B (0x04) +#define FM_RDS_GDBK_IND_C (0x02) +#define FM_RDS_GDBK_IND_D (0x01) +#define FM_RDS_DCO_FIFO_OFST (0x01E0) +#define FM_RDS_READ_DELAY (0x80) + + +/****************************************************************************** + * GLOBAL VARIABLE + *****************************************************************************/ +static bool bRDS_FirstIn = false; +static uint16_t RDS_Sync_Cnt = 0, RDS_Block_Reset_Cnt = 0; + +extern int16_t _current_frequency; +uint32_t gBLER_CHK_INTERVAL = 5000; +static int16_t preAF_Num = 0; +static int16_t preAFON_Num = 0; +uint16_t GOOD_BLK_CNT = 0, BAD_BLK_CNT = 0; +uint8_t BAD_BLK_RATIO = 0; + +#ifndef FM_ASSERT +#define FM_ASSERT(a) { \ + if ((a) == NULL) { \ + printk("%s, invalid buf\n", __func__);\ + return -ERR_INVALID_BUF; \ + } \ + } +#endif + +#define RDS_RT_MULTI_REV_TH 16 +enum +{ + RDS_GRP_VER_A = 0, //group version A + RDS_GRP_VER_B +}; + +typedef enum RDS_RT_STATE_MACHINE +{ + RDS_RT_START = 0, + RDS_RT_DECISION, + RDS_RT_GETLEN, + RDS_RT_DISPLAY, + RDS_RT_FINISH, + RDS_RT_MAX +}RDS_RT_STATE_MACHINE; + +typedef enum RDS_BLK_T +{ + RDS_BLK_A = 0, + RDS_BLK_B, + RDS_BLK_C, + RDS_BLK_D, + RDS_BLK_MAX +}RDS_BLK_T; + +static RDS_RT_STATE_MACHINE rt_state_machine = RDS_RT_START; + +/****************************************************************************** + * Local function extern + *****************************************************************************/ +static int MT6620_RDS_enable(void); +static int MT6620_RDS_disable(void); +static int MT6620_RDS_Get_GoodBlock_Counter(uint16_t* pCnt); +static int MT6620_RDS_Get_BadBlock_Counter(uint16_t* pCnt); +static int MT6620_RDS_Reset_Block_Counter(void); +static int MT6620_RDS_Reset(void); +static int MT6620_RDS_Reset_Block(void); +static int MT6620_RDS_Init_Data(RDSData_Struct *pstRDSData); +static int MT6620_RDS_RetrieveGroup0(uint16_t *block_data, uint8_t SubType, RDSData_Struct *pstRDSData); +static int MT6620_RDS_RetrieveGroup1(uint16_t *block_data, uint8_t SubType, RDSData_Struct *pstRDSData); +static int MT6620_RDS_RetrieveGroup2(uint16_t *block_data, uint8_t SubType, RDSData_Struct *pstRDSData); +static int MT6620_RDS_RetrieveGroup4(uint16_t *block_data, uint8_t SubType, RDSData_Struct *pstRDSData); +static int MT6620_RDS_RetrieveGroup14(uint16_t *block_data, uint8_t SubType, RDSData_Struct *pstRDSData); +extern int MT6620_read(uint8_t addr, uint16_t *val); +extern int MT6620_write(uint8_t addr, uint16_t val); +extern int MT6620_set_bits(uint8_t addr, uint16_t bits, uint16_t mask); +extern int Delayms(uint32_t data); +extern int Delayus(uint32_t data); + +/* + * rds_cnt_get + * To get rds group count form raw data + * If success return 0, else return error code +*/ +static int rds_cnt_get(struct rds_rx *rds_raw, int raw_size, int *cnt){ + int ret = 0; + int gap = sizeof(rds_raw->cos) + sizeof(rds_raw->sin); + + FM_ASSERT(rds_raw); + FM_ASSERT(cnt); + *cnt = (raw_size - gap)/sizeof(rds_packet_struct); + FM_LOG_INF(D_RDS,"group cnt=%d\n", *cnt); + + return ret; +} + +/* + * rds_group_get + * To get rds group[n] data form raw data with index + * If success return 0, else return error code +*/ +static int rds_group_get(uint16_t *dst, struct rds_rx *raw, int idx){ + int ret = 0; + + FM_ASSERT(dst); + FM_ASSERT(raw); + if(idx > (MAX_RDS_RX_GROUP_CNT - 1)){ + ret = -ERR_INVALID_PARA; + return ret; + } + dst[0] = raw->data[idx].blkA; + dst[1] = raw->data[idx].blkB; + dst[2] = raw->data[idx].blkC; + dst[3] = raw->data[idx].blkD; + dst[4] = raw->data[idx].crc; + dst[5] = raw->data[idx].cbc; + + FM_LOG_INF(D_RDS,"BLOCK:%04x %04x %04x %04x, CRC:%04x\n", dst[0], dst[1], dst[2], dst[3], dst[4]); + + return ret; +} + +/* + * rds_checksum_check + * To check CRC rerult, if OK, *valid=TRUE, else *valid=FALSE + * If success return 0, else return error code +*/ +static int rds_checksum_check(uint16_t crc, int mask, bool *valid){ + int ret = 0; + + FM_ASSERT(valid); + if((crc & mask) == mask){ + *valid = TRUE; + }else{ + *valid = FALSE; + } + + return ret; +} + +/* + * rds_cbc_get - To get block_n's correct bit count form cbc + * @cbc, the group's correct bit count + * @blk, target the block + * + * If success, return block_n's cbc, else error code +*/ +static int rds_cbc_get(uint16_t cbc, enum RDS_BLK_T blk){ + int ret = 0; + + switch(blk){ + case RDS_BLK_A: + ret = (cbc & 0xF000) >> 12; + break; + case RDS_BLK_B: + ret = (cbc & 0x0F00) >> 8; + break; + case RDS_BLK_C: + ret = (cbc & 0x00F0) >> 4; + break; + case RDS_BLK_D: + ret = (cbc & 0x000F) >> 0; + break; + default: + break; + } + FM_LOG_INF(D_RDS,"group cbc=0x%04x\n", cbc); + return ret; +} + +/* + * rds_event_set + * To set rds event, and user space can use this flag to juge which event happened + * If success return 0, else return error code +*/ +static int rds_event_set(uint16_t *events, int event_mask){ + int ret = 0; + + FM_ASSERT(events); + *events |= event_mask; + + return ret; +} + +/* + * rds_flag_set + * To set rds event flag, and user space can use this flag to juge which event happened + * If success return 0, else return error code +*/ +static int rds_flag_set(uint32_t *flags, int flag_mask){ + int ret = 0; + + FM_ASSERT(flags); + *flags |= flag_mask; + + return ret; +} + +/* + * rds_group_type_get + * To get rds group type form blockB + * If success return 0, else return error code +*/ +static int rds_group_type_get(uint16_t crc, uint16_t blk, uint8_t *type, uint8_t *subtype){ + int ret = 0; + bool valid = FALSE; + + FM_ASSERT(type); + FM_ASSERT(subtype); + //to get the group type from block B + ret = rds_checksum_check(crc, FM_RDS_GDBK_IND_B, &valid); + if(valid == TRUE){ + *type = (blk & 0xF000)>>12; //Group type(4bits) + *subtype = (blk & 0x0800)>>11; //version code(1bit), 0=vesionA, 1=versionB + }else{ + FM_LOG_WAR(D_RDS,"Block1 CRC err\n"); + return -ERR_RDS_CRC; + } + + FM_LOG_INF(D_RDS,"Type=%d, subtype:%s\n", (int)*type, *subtype ? "version B" : "version A"); + return ret; +} + +/* + * rds_group_counter_add + * @type -- group type, rang: 0~15 + * @subtype -- sub group type, rang:0~1 + * + * add group counter, group0a~group15b + * we use type value as the index + * If success return 0, else return error code +*/ +static int rds_group_counter_add(uint8_t type, uint8_t subtype, struct rds_group_cnt *gc) +{ + FM_ASSERT(gc); + + if(type > 15){ + return -ERR_INVALID_PARA; + } + switch(subtype){ + case RDS_GRP_VER_A: + gc->groupA[type]++; + break; + case RDS_GRP_VER_B: + gc->groupB[type]++; + break; + default: + return -ERR_INVALID_PARA; + break; + } + gc->total++; + FM_LOG_INF(D_RDS,"group counter:%d\n", (int)gc->total); + return 0; +} + +/* + * rds_group_counter_get + * + * read group counter , group0a~group15b + * If success return 0, else return error code +*/ +extern int rds_group_counter_get(struct rds_group_cnt *dst, struct rds_group_cnt *src) +{ + FM_ASSERT(dst); + FM_ASSERT(src); + memcpy(dst, src, sizeof(struct rds_group_cnt)); + return 0; +} + +/* + * rds_group_counter_reset + * + * clear group counter to 0, group0a~group15b + * If success return 0, else return error code +*/ +extern int rds_group_counter_reset(struct rds_group_cnt *gc) +{ + FM_ASSERT(gc); + memset(gc, 0, sizeof(struct rds_group_cnt)); + return 0; +} + +/* + * rds_group_pi_get + * To get rds group pi code form blockA + * If success return 0, else return error code +*/ +static int rds_group_pi_get(uint16_t crc, uint16_t blk, uint16_t *pi, bool *dirty){ + int ret = 0; + bool valid = FALSE; + + FM_ASSERT(pi); + FM_ASSERT(dirty); + + //to get the group pi code from block A + ret = rds_checksum_check(crc, FM_RDS_GDBK_IND_A, &valid); + if(valid == TRUE){ + if(*pi != blk){ + //PI=program Identication + *pi = blk; + *dirty = TRUE; // yes, we got new PI code + }else{ + *dirty = FALSE; // PI is the same as last one + } + }else{ + FM_LOG_WAR(D_RDS,"Block0 CRC err\n"); + return -ERR_RDS_CRC; + } + + FM_LOG_INF(D_RDS,"PI=0x%04x, %s\n", *pi, *dirty ? "new" : "old"); + return ret; +} + +/* + * rds_group_pty_get + * To get rds group pty code form blockB + * If success return 0, else return error code +*/ +static int rds_group_pty_get(uint16_t crc, uint16_t blk, uint8_t *pty, bool *dirty){ + int ret = 0; + bool valid = FALSE; + + FM_ASSERT(pty); + FM_ASSERT(dirty); + + //to get PTY code from block B + ret = rds_checksum_check(crc, FM_RDS_GDBK_IND_B, &valid); + if(valid == FALSE){ + FM_LOG_WAR(D_RDS,"Block1 CRC err\n"); + return -ERR_RDS_CRC; + } + + if(*pty != ((blk & 0x03E0)>>5)){ + //PTY=Program Type Code + *pty = (blk&0x03E0)>>5; + *dirty = TRUE; // yes, we got new PTY code + }else{ + *dirty = FALSE; // PTY is the same as last one + } + + FM_LOG_INF(D_RDS,"PTY=%d, %s\n", (int)*pty, *dirty ? "new" : "old"); + return ret; +} + +/* + * rds_group_tp_get + * To get rds group tp code form blockB + * If success return 0, else return error code +*/ +static int rds_group_tp_get(uint16_t crc, uint16_t blk, uint8_t *tp, bool *dirty){ + int ret = 0; + bool valid = FALSE; + + FM_ASSERT(tp); + FM_ASSERT(dirty); + + //to get TP code from block B + ret = rds_checksum_check(crc, FM_RDS_GDBK_IND_B, &valid); + if(valid == FALSE){ + FM_LOG_WAR(D_RDS,"Block1 CRC err\n"); + return -ERR_RDS_CRC; + } + + if(*tp != ((blk&0x0400)>>10)){ + //Tranfic Program Identification + *tp = (blk&0x0400)>>10; + *dirty = TRUE; // yes, we got new TP code + }else{ + *dirty = FALSE; // TP is the same as last one + } + + FM_LOG_INF(D_RDS,"TP=%d, %s\n", (int)*tp, *dirty ? "new" : "old"); + return ret; +} + +/* + * rds_group0_ta_get + * To get rds group ta code form blockB + * If success return 0, else return error code +*/ +static int rds_group0_ta_get(uint16_t blk, uint8_t *ta, bool *dirty){ + int ret = 0; + + FM_ASSERT(ta); + FM_ASSERT(dirty); + //TA=Traffic Announcement code + if(*ta != ((blk & 0x0010)>>4)){ + *ta = (blk & 0x0010)>>4; + *dirty = TRUE; // yes, we got new TA code + }else{ + *dirty = FALSE; // TA is the same as last one + } + + FM_LOG_INF(D_G0,"TA=%d, %s\n", (int)*ta, *dirty ? "new" : "old"); + return ret; +} + +/* + * rds_group0_music_get + * To get music-speech switch code form blockB + * If success return 0, else return error code +*/ +static int rds_group0_music_get(uint16_t blk, uint8_t *music, bool *dirty){ + int ret = 0; + + FM_ASSERT(music); + FM_ASSERT(dirty); + //M/S=music speech switch code + if(*music != ((blk & 0x0008)>>3)){ + *music = (blk & 0x0008)>>3; + *dirty = TRUE; // yes, we got new music code + }else{ + *dirty = FALSE; // music is the same as last one + } + + FM_LOG_INF(D_G0,"Music=%d, %s\n", (int)*music, *dirty ? "new" : "old"); + return ret; +} + +/* + * rds_group2_rt_addr_get + * To get rt addr form blockB + * If success return 0, else return error code +*/ +static int rds_group2_rt_addr_get(uint16_t blk, uint8_t *addr){ + int ret = 0; + + FM_ASSERT(addr); + *addr = (uint8_t)blk & 0x0F; + + FM_LOG_INF(D_G2,"addr=0x%02x\n", *addr); + return ret; +} + +static int rds_group2_txtAB_get(uint16_t blk, uint8_t *txtAB, bool *dirty){ + int ret = 0; + + FM_ASSERT(txtAB); + FM_ASSERT(dirty); + + if(*txtAB != ((blk&0x0010)>>4)){ + *txtAB = (blk&0x0010)>>4; + *dirty = TRUE; // yes, we got new txtAB code + }else{ + *dirty = FALSE; // txtAB is the same as last one + } + + FM_LOG_INF(D_G2,"txtAB=%d, %s\n", *txtAB, *dirty ? "new" : "old"); + return ret; +} + +static int rds_group2_rt_get(uint16_t crc, uint8_t subtype, uint16_t blkC, uint16_t blkD, uint8_t addr, uint8_t *buf){ + int ret = 0; + bool valid = FALSE; + int idx = 0; + + FM_ASSERT(buf); + //text segment addr rang 0~15 + if(addr > 0xFF){ + FM_LOG_ERR(D_RDS,"addr invalid(0x%02x)\n", addr); + ret = -ERR_INVALID_PARA; + return ret; + } + switch(subtype){ + case RDS_GRP_VER_A: + idx = 4*addr; + ret = rds_checksum_check(crc, FM_RDS_GDBK_IND_C | FM_RDS_GDBK_IND_D, &valid); + if(valid == TRUE){ + buf[idx] = blkC>>8; + buf[idx+1] = blkC&0xFF; + buf[idx+2] = blkD>>8; + buf[idx+3] = blkD&0xFF; + }else{ + FM_LOG_ERR(D_RDS,"rt crc check err\n"); + ret = -ERR_RDS_CRC; + } + break; + case RDS_GRP_VER_B: + idx = 2*addr; + ret = rds_checksum_check(crc, FM_RDS_GDBK_IND_D, &valid); + if(valid == TRUE){ + buf[idx] = blkD>>8; + buf[idx+1] = blkD&0xFF; + }else{ + FM_LOG_ERR(D_RDS,"rt crc check err\n"); + ret = -ERR_RDS_CRC; + } + break; + default: + break; + } + + FM_LOG_INF(D_G2,"addr[%02x]:0x%02x 0x%02x 0x%02x 0x%02x\n", addr, buf[idx], buf[idx+1], buf[idx+2], buf[idx+3]); + return ret; +} + +static int rds_group2_rt_get_len(uint8_t subtype, int pos, int *len){ + int ret = 0; + + FM_ASSERT(len); + if(subtype == RDS_GRP_VER_A){ + *len = 4*(pos+1); + }else{ + *len = 2*(pos+1); + } + + return ret; +} + +/* + * rds_group2_rt_cmp + * this function is the most importent flow for RT parsing + * 1.Compare fresh buf with once buf per byte, if eque copy this byte to twice buf, else copy it to once buf + * 2.Check wether we got a full segment, for typeA if copyed 4bytes to twice buf, for typeB 2bytes copyed to twice buf + * 3.Check wether we got the end of RT, if we got 0x0D + * 4.If we got the end, then caculate the RT lenth + * If success return 0, else return error code +*/ +static int rds_group2_rt_cmp(uint8_t addr, uint16_t cbc, uint8_t subtype, uint8_t *fresh, + uint8_t *once, uint8_t *twice, bool *valid, bool *end, int *len){ + int ret = 0; + int i = 0; + int j = 0; + int cnt = 0; + + FM_ASSERT(fresh); + FM_ASSERT(once); + FM_ASSERT(twice); + FM_ASSERT(valid); + FM_ASSERT(end); + + j = (subtype == RDS_GRP_VER_A) ? 4 : 2; // RT segment width + if(subtype == RDS_GRP_VER_A){ + if(rds_cbc_get(cbc, RDS_BLK_C) == 0){ + once[j*addr+0] = fresh[j*addr+0]; + once[j*addr+1] = fresh[j*addr+1]; + } + if(rds_cbc_get(cbc, RDS_BLK_D) == 0){ + once[j*addr+2] = fresh[j*addr+2]; + once[j*addr+3] = fresh[j*addr+3]; + } + }else if(subtype == RDS_GRP_VER_B){ + if(rds_cbc_get(cbc, RDS_BLK_D) == 0){ + once[j*addr+0] = fresh[j*addr+0]; + once[j*addr+1] = fresh[j*addr+1]; + } + } + + for(i = 0; i < j; i++){ + if(fresh[j*addr+i] == once[j*addr+i]){ + twice[j*addr+i] = once[j*addr+i]; //get the same byte 2 times + cnt++; + }else{ + once[j*addr+i] = fresh[j*addr+i]; //use new val + } + + //if we got 0x0D twice, it means a RT end + if(twice[j*addr+i] == 0x0D){ + *end = TRUE; + *len = j*addr+i+1; //record the length of RT + } + } + + //check if we got a valid segment 4bytes for typeA, 2bytes for typeB + if(cnt == j){ + *valid = TRUE; + }else{ + *valid = FALSE; + } + FM_LOG_INF(D_G2,"RT seg=%s\n", *valid == TRUE ? "TRUE" : "FALSE"); + FM_LOG_INF(D_G2,"RT end=%s\n", *end == TRUE ? "TRUE" : "FALSE"); + FM_LOG_INF(D_G2,"RT len=%d\n", *len); + return ret; +} + +static uint16_t rds_group2_rt_addr_bitmap_get(uint16_t bitmap){ + return bitmap; +} + +static int rds_group2_rt_addr_bitmap_get_pos(uint16_t bitmap){ + int i = 15; + while(!(bitmap & (1< -1)){ + i--; + } + return i; +} + +#if 0 +static bool rds_group2_rt_addr_bitmap_test(uint16_t bitmap, uint8_t addr){ + return (bitmap & (1< bitmap2, return positive(+) + * If bitmap1 = bitmap2, return 0 + * If bitmap1 < bitmap2, return nagotive(-) + */ +static int rds_group2_rt_addr_bitmap_cmp(uint16_t bitmap1, uint16_t bitmap2) +{ + return (int)(bitmap1 - bitmap2); +} + +static int rds_group2_rt_addr_bitmap_set(uint16_t *bitmap, int *bm_cnt, uint8_t addr){ + int ret = 0; + uint16_t bm_old = 0; + + FM_ASSERT(bitmap); + FM_ASSERT(bm_cnt); + //text segment addr rang 0~15 + if(addr > 0xFF){ + FM_LOG_ERR(D_RDS,"addr invalid(0x%02x)\n", addr); + ret = -ERR_INVALID_PARA; + return ret; + } + bm_old = *bitmap; + *bitmap |= (1< 0){ + (*bm_cnt)--; + } + FM_LOG_NTC(D_G2,"RT bitmap=0x%04x, bmcnt=%d\n", *bitmap, *bm_cnt); + return ret; +} + +static RDS_RT_STATE_MACHINE rds_rt_state_get(void){ + return rt_state_machine; +} + +static RDS_RT_STATE_MACHINE rds_rt_state_set(RDS_RT_STATE_MACHINE state_new){ + rt_state_machine = state_new; + return rt_state_machine; +} + +#if 0 +static bool rds_group2_is_rt_finished(uint16_t *event){ + FM_ASSERT(event); + if(*event&RDS_EVENT_LAST_RADIOTEXT){ + return TRUE; + }else{ + return FALSE; + } +} +#endif + +static int MT6620_RDS_enable(void) +{ + uint16_t page; + int ret = 0; + + if((ret = MT6620_read(FM_MAIN_PGSEL, &page))) + return ret; + + if((ret = MT6620_write(0x9F, 0x0003))) + return ret; + if((ret = MT6620_write(0xCB, 0xE016))) + return ret; + if((ret = MT6620_write(0x9F, 0x0000))) + return ret; + if((ret = MT6620_write(0x63, 0x0491))) + return ret; + if((ret = MT6620_set_bits(0x6B, 0x2000, 0xFFFF))) + return ret; + + ret = MT6620_write(FM_MAIN_PGSEL, page); + + return ret; +} + +static int MT6620_RDS_disable(void) +{ + int ret = 0; + if((ret = MT6620_set_bits(0x6B, 0x0000, 0xDFFF))) + return ret; + ret = MT6620_write(0x63, 0x0481); + + return ret; +} + +static int MT6620_RDS_Get_GoodBlock_Counter(uint16_t* pCnt) +{ + uint16_t tmp_reg; + uint16_t page; + int ret = 0; + + if(NULL == pCnt) + return -ERR_INVALID_BUF; + + if((ret = MT6620_read(FM_MAIN_PGSEL, &page))) + return ret; + + if((ret = MT6620_write(0x9F, 0x0003))) + return ret; + if((ret = MT6620_read(0xC6, &tmp_reg))) + return ret; + + ret = MT6620_write(FM_MAIN_PGSEL, page); + + *pCnt = tmp_reg; + return ret; +} + +static int MT6620_RDS_Get_BadBlock_Counter(uint16_t* pCnt) +{ + uint16_t tmp_reg; + uint16_t page; + int ret = 0; + + if(NULL == pCnt) + return -ERR_INVALID_BUF; + + if((ret = MT6620_read(FM_MAIN_PGSEL, &page))) + return ret; + + if((ret = MT6620_write(0x9F, 0x0003))) + return ret; + if((ret = MT6620_read(0xC7, &tmp_reg))) + return ret; + + ret = MT6620_write(FM_MAIN_PGSEL, page); + + *pCnt = tmp_reg; + return ret; +} + + +static int MT6620_RDS_Reset_Block_Counter(void) +{ + uint16_t page; + int ret = 0; + + if((ret = MT6620_read(FM_MAIN_PGSEL, &page))) + return ret; + + if((ret = MT6620_write(0x9F, 0x0003))) + return ret; + if((ret = MT6620_write(0xC8, 0x0001))) + return ret; + if((ret = MT6620_write(0xC8, 0x0002))) + return ret; + + ret = MT6620_write(FM_MAIN_PGSEL, page); + + return ret; +} + +static int MT6620_RDS_Reset(void) +{ + uint16_t page; + int ret = 0; + + if((ret = MT6620_read(FM_MAIN_PGSEL, &page))) + return ret; + + if((ret = MT6620_write(0x9F, 0x0003))) + return ret; + if((ret = MT6620_write(0xB0, 0x0001))) + return ret; + + ret = MT6620_write(FM_MAIN_PGSEL, page); + + return ret; +} + +static int MT6620_RDS_Reset_Block(void) +{ + uint16_t page; + int ret = 0; + + if((ret = MT6620_read(FM_MAIN_PGSEL, &page))) + return ret; + + if((ret = MT6620_write(0x9F, 0x0003))) + return ret; + if((ret = MT6620_write(0xDD, 0x0001))) + return ret; + + ret = MT6620_write(FM_MAIN_PGSEL, page); + + return ret; +} + +int MT6620_RDS_BlerCheck(struct fm *fm) +{ + RDSData_Struct *pstRDSData = fm->pstRDSData; + uint16_t TOTAL_CNT; + int ret = 0; + + FM_LOG_DBG(D_BLKC,"+T:%d, MT6620_RDS_BlerCheck\n", jiffies_to_msecs(jiffies)); + + if(pstRDSData->AF_Data.Addr_Cnt == 0xFF){ + //AF List Finished + pstRDSData->event_status |= RDS_EVENT_AF; //Need notfiy application + //loop pstRDSData->event_status then act + if(pstRDSData->event_status != 0){ + fm->RDS_Data_ready = true; + wake_up_interruptible(&fm->read_wait); + FM_LOG_DBG(D_BLKC,"RDS_EVENT_AF, trigger read\n"); + } + } + + gBLER_CHK_INTERVAL = MT6620_RDS_BLER_T1; + if((ret = MT6620_RDS_Get_GoodBlock_Counter(&GOOD_BLK_CNT))) + return ret; + FM_LOG_DBG(D_BLKC,"-T:%d, GOOD_BLK_CNT:%d\n", jiffies_to_msecs(jiffies), GOOD_BLK_CNT); + if((ret = MT6620_RDS_Get_BadBlock_Counter(&BAD_BLK_CNT))) + return ret; + TOTAL_CNT = GOOD_BLK_CNT + BAD_BLK_CNT; + if((ret = MT6620_RDS_Reset_Block_Counter())) + return ret; + FM_LOG_DBG(D_BLKC,"BLER: TOTAL_CNT:%d BAD_BLK_CNT:%d, RDS_Sync_Cnt:%d\n", TOTAL_CNT, BAD_BLK_CNT, RDS_Sync_Cnt); + + if((GOOD_BLK_CNT==0)&&(BAD_BLK_CNT==0)){ + BAD_BLK_RATIO = 0; + }else{ + BAD_BLK_RATIO = (BAD_BLK_CNT*100)/TOTAL_CNT; + } + + //MT6620_RDS_BLER_TH1 90 + //MT6620_RDS_BLER_TH2 60 + //MT6620_RDS_BLER_C1 12 + //MT6620_RDS_BLER_C2 6 + //MT6620_RDS_BLER_T2 5000 + if((BAD_BLK_RATIO < MT6620_RDS_BLER_TH2)&&(RDS_Sync_Cnt > MT6620_RDS_BLER_C1)){ + gBLER_CHK_INTERVAL = MT6620_RDS_BLER_T2; + if(RDS_Block_Reset_Cnt > 1) + RDS_Block_Reset_Cnt--; + }else{ + if(BAD_BLK_RATIO > MT6620_RDS_BLER_TH1){ + //>90% + if((ret = MT6620_RDS_Reset_Block_Counter())) + return ret; + RDS_Sync_Cnt = 0; //need clear or not, Question, LCH. + RDS_Block_Reset_Cnt++; + if((RDS_Block_Reset_Cnt > MT6620_RDS_BLER_C2)||bRDS_FirstIn){ + if(bRDS_FirstIn) + bRDS_FirstIn = false; + if((ret = MT6620_RDS_Reset())) + return ret; + RDS_Block_Reset_Cnt = 0; + FM_LOG_DBG(D_BLKC,"RDS Reset, blk_cnt:%d, RDS_FirstIn:%d\n", RDS_Block_Reset_Cnt, bRDS_FirstIn); + }else if(TOTAL_CNT > 12){ + //LCH question 2, why 12??? + FM_LOG_DBG(D_BLKC,"RDS Block Reset: %x\n", RDS_Block_Reset_Cnt); + if((ret = MT6620_RDS_Reset_Block())) + return ret; + } + }else{ + RDS_Sync_Cnt++; //(60%-90%) + FM_LOG_DBG(D_BLKC,"RDS Sync Cnt: %d\n", RDS_Block_Reset_Cnt); + if(RDS_Block_Reset_Cnt > 1) + RDS_Block_Reset_Cnt--; + if(RDS_Sync_Cnt > MT6620_RDS_BLER_C1){ + gBLER_CHK_INTERVAL = MT6620_RDS_BLER_T2; + } + } + } + + return ret; +} + +static int MT6620_RDS_Init_Data(RDSData_Struct *pstRDSData) +{ + uint8_t indx; + int ret = 0; + + memset(pstRDSData, 0 ,sizeof(RDSData_Struct)); + bRDS_FirstIn = true; + + pstRDSData->PTY = 0xFF; //to avoid "rx PTY == 0" case, this will cause no PTY event + + for(indx = 0; indx < 64; indx++){ + pstRDSData->RT_Data.TextData[0][indx]=0x20; + pstRDSData->RT_Data.TextData[1][indx]=0x20; + } + for(indx = 0; indx < 8; indx++){ + pstRDSData->PS_Data.PS[0][indx] = '\0'; + pstRDSData->PS_Data.PS[1][indx] = '\0'; + pstRDSData->PS_Data.PS[2][indx] = '\0'; + pstRDSData->PS_ON[indx] = 0x20; + } + + return ret; +} + +static int MT6620_RDS_RetrieveGroup0(uint16_t *block_data, uint8_t SubType, RDSData_Struct *pstRDSData) +{ + uint8_t indx, indx2, DI_Code, DI_Flag, PS_Num, AF_H, AF_L, num; + int ret = 0; + bool valid = FALSE; + bool dirty = FALSE; + uint16_t *event = &pstRDSData->event_status; + uint32_t *flag = &pstRDSData->RDSFlag.flag_status; + + ret = rds_checksum_check(block_data[4], FM_RDS_GDBK_IND_D, &valid); + if(valid == FALSE){ + FM_LOG_WAR(D_G0,"Group0 BlockD crc err\n"); + return -ERR_RDS_CRC; + } + + ret = rds_group0_ta_get(block_data[1], &pstRDSData->RDSFlag.TA, &dirty); + if(ret){ + FM_LOG_WAR(D_G0,"get ta failed[ret=%d]\n", ret); + }else if(dirty == TRUE){ + ret = rds_event_set(event, RDS_EVENT_FLAGS); // yes, we got new TA code + ret = rds_flag_set(flag, RDS_FLAG_IS_TA); + } + + ret = rds_group0_music_get(block_data[1], &pstRDSData->RDSFlag.Music, &dirty); + if(ret){ + FM_LOG_WAR(D_G0,"get music failed[ret=%d]\n", ret); + }else if(dirty == TRUE){ + ret = rds_event_set(event, RDS_EVENT_FLAGS); // yes, we got new MUSIC code + ret = rds_flag_set(flag, RDS_FLAG_IS_MUSIC); + } + + if((pstRDSData->Switch_TP)&&(pstRDSData->RDSFlag.TP)&&!(pstRDSData->RDSFlag.TA)){ + ret = rds_event_set(event, RDS_EVENT_TAON_OFF); + } + + if(!SubType){ + //Type A + ret = rds_checksum_check(block_data[4], FM_RDS_GDBK_IND_C, &valid); + if(valid == FALSE){ + FM_LOG_WAR(D_G0,"Group0 BlockC crc err\n"); + return -ERR_RDS_CRC; + }else{ + AF_H = (block_data[2]&0xFF00)>>8; + AF_L= block_data[2]&0x00FF; + + if((AF_H > 224)&&(AF_H < 250)){ + //Followed AF Number, see RDS spec Table 11, valid(224-249) + FM_LOG_DBG(D_G0,"RetrieveGroup0 AF_H:%d, AF_L:%d\n", AF_H, AF_L); + pstRDSData->AF_Data.isAFNum_Get = 0; + preAF_Num = AF_H - 224; //AF Number + if(preAF_Num != pstRDSData->AF_Data.AF_Num){ + pstRDSData->AF_Data.AF_Num = preAF_Num; + }else{ + //Get the same AFNum two times + pstRDSData->AF_Data.isAFNum_Get = 1; + } + + if((AF_L < 205) && (AF_L > 0)){ + //See RDS Spec table 10, valid VHF + pstRDSData->AF_Data.AF[0][0] = AF_L+875; //convert to 100KHz + FM_LOG_DBG(D_G0,"RetrieveGroup0 AF[0][0]:%d\n", pstRDSData->AF_Data.AF[0][0]); + if((pstRDSData->AF_Data.AF[0][0]) != (pstRDSData->AF_Data.AF[1][0])){ + pstRDSData->AF_Data.AF[1][0] = pstRDSData->AF_Data.AF[0][0]; + }else{ + if(pstRDSData->AF_Data.AF[1][0] != _current_frequency) + pstRDSData->AF_Data.isMethod_A = 1; + else + pstRDSData->AF_Data.isMethod_A = 0; + } + + FM_LOG_DBG(D_G0,"RetrieveGroup0 isAFNum_Get:%d, isMethod_A:%d\n", pstRDSData->AF_Data.isAFNum_Get, pstRDSData->AF_Data.isMethod_A); + + //only one AF handle + if((pstRDSData->AF_Data.isAFNum_Get)&& (pstRDSData->AF_Data.AF_Num == 1)){ + pstRDSData->AF_Data.Addr_Cnt = 0xFF; + pstRDSData->event_status |= RDS_EVENT_AF_LIST; + FM_LOG_DBG(D_G0,"RetrieveGroup0 RDS_EVENT_AF_LIST update\n"); + } + } + } + else if((pstRDSData->AF_Data.isAFNum_Get)&&(pstRDSData->AF_Data.Addr_Cnt != 0xFF)){ + //AF Num correct + num = pstRDSData->AF_Data.AF_Num; + num = num>>1; + FM_LOG_DBG(D_G0,"RetrieveGroup0 +num:%d\n", num); + + //Put AF freq into buffer and check if AF freq is repeat again + for(indx = 1; indx < (num+1); indx++){ + if((AF_H == (pstRDSData->AF_Data.AF[0][2*num-1]))&&(AF_L == (pstRDSData->AF_Data.AF[0][2*indx]))){ + FM_LOG_ERR(D_G0|D_ALL,"RetrieveGroup0 AF same as indx:%d\n", indx); + break; + }else if(!(pstRDSData->AF_Data.AF[0][2*indx-1])){ + //null buffer + pstRDSData->AF_Data.AF[0][2*indx-1] = AF_H+875; //convert to 100KHz + pstRDSData->AF_Data.AF[0][2*indx] = AF_L+875; + FM_LOG_DBG(D_G0,"RetrieveGroup0 AF[0][%d]:%d, AF[0][%d]:%d\n", + 2*indx-1, pstRDSData->AF_Data.AF[0][2*indx-1], 2*indx, pstRDSData->AF_Data.AF[0][2*indx]); + break; + } + } + num = pstRDSData->AF_Data.AF_Num; + FM_LOG_DBG(D_G0,"RetrieveGroup0 ++num:%d\n", num); + if(num > 0){ + if((pstRDSData->AF_Data.AF[0][num-1]) != 0){ + num = num>>1; + FM_LOG_DBG(D_G0,"RetrieveGroup0 +++num:%d\n", num); + //arrange frequency from low to high:start + for(indx = 1; indx < num; indx++){ + for(indx2 = indx+1; indx2 < (num+1); indx2++){ + AF_H = pstRDSData->AF_Data.AF[0][2*indx-1]; + AF_L = pstRDSData->AF_Data.AF[0][2*indx]; + if(AF_H > (pstRDSData->AF_Data.AF[0][2*indx2-1])){ + pstRDSData->AF_Data.AF[0][2*indx-1] = pstRDSData->AF_Data.AF[0][2*indx2-1]; + pstRDSData->AF_Data.AF[0][2*indx] = pstRDSData->AF_Data.AF[0][2*indx2]; + pstRDSData->AF_Data.AF[0][2*indx2-1] = AF_H; + pstRDSData->AF_Data.AF[0][2*indx2] = AF_L; + }else if(AF_H == (pstRDSData->AF_Data.AF[0][2*indx2-1])){ + if(AF_L > (pstRDSData->AF_Data.AF[0][2*indx2])){ + pstRDSData->AF_Data.AF[0][2*indx-1] = pstRDSData->AF_Data.AF[0][2*indx2-1]; + pstRDSData->AF_Data.AF[0][2*indx] = pstRDSData->AF_Data.AF[0][2*indx2]; + pstRDSData->AF_Data.AF[0][2*indx2-1] = AF_H; + pstRDSData->AF_Data.AF[0][2*indx2] = AF_L; + } + } + } + } + //arrange frequency from low to high:end + //compare AF buff0 and buff1 data:start + num = pstRDSData->AF_Data.AF_Num; + indx2 = 0; + + for(indx = 0; indx < num; indx++){ + if((pstRDSData->AF_Data.AF[1][indx]) == (pstRDSData->AF_Data.AF[0][indx])){ + if(pstRDSData->AF_Data.AF[1][indx] != 0) + indx2++; + }else + pstRDSData->AF_Data.AF[1][indx] = pstRDSData->AF_Data.AF[0][indx]; + } + FM_LOG_DBG(D_G0,"RetrieveGroup0 indx2:%d, num:%d\n", indx2, num); + //compare AF buff0 and buff1 data:end + if(indx2 == num){ + pstRDSData->AF_Data.Addr_Cnt = 0xFF; + pstRDSData->event_status |= RDS_EVENT_AF_LIST; + FM_LOG_DBG(D_G0,"RetrieveGroup0 AF_Num:%d\n", pstRDSData->AF_Data.AF_Num); + for(indx = 0; indx < num; indx++){ + if((pstRDSData->AF_Data.AF[1][indx]) == 0){ + pstRDSData->AF_Data.Addr_Cnt = 0x0F; + pstRDSData->event_status &= (~RDS_EVENT_AF_LIST); + } + } + } + else + pstRDSData->AF_Data.Addr_Cnt = 0x0F; + } + } + } + } + } + + /*DI_Code[1:0]: "00" = d3 * + * "01" = d2 * + * "10" = d1 * + * "11" = d0 */ + + DI_Code = block_data[1]&0x0003; //DI=decoder identification code. + DI_Flag = (block_data[1]&0x0004)>>2; + + switch(DI_Code){ + case 3: + if(pstRDSData->RDSFlag.Stereo != DI_Flag){ + pstRDSData->RDSFlag.Stereo = DI_Flag; + pstRDSData->event_status |= RDS_EVENT_FLAGS; + pstRDSData->RDSFlag.flag_status |= RDS_FLAG_IS_STEREO; + } + break; + case 2: + if(pstRDSData->RDSFlag.Artificial_Head != DI_Flag){ + pstRDSData->RDSFlag.Artificial_Head = DI_Flag; + pstRDSData->event_status |= RDS_EVENT_FLAGS; + pstRDSData->RDSFlag.flag_status |= RDS_FLAG_IS_ARTIFICIAL_HEAD; + } + break; + case 1: + if(pstRDSData->RDSFlag.Compressed != DI_Flag){ + pstRDSData->RDSFlag.Compressed = DI_Flag; + pstRDSData->event_status |= RDS_EVENT_FLAGS; + pstRDSData->RDSFlag.flag_status |= RDS_FLAG_IS_COMPRESSED; + } + break; + case 0: + if(pstRDSData->RDSFlag.Dynamic_PTY != DI_Flag){ + pstRDSData->RDSFlag.Dynamic_PTY = DI_Flag; + pstRDSData->event_status |= RDS_EVENT_FLAGS; + pstRDSData->RDSFlag.flag_status |= RDS_FLAG_IS_DYNAMIC_PTY; + } + break; + default: + break; + } + + PS_Num = block_data[1]&0x0003; //Figure 12 Type 0 group. + AF_H = pstRDSData->PS_Data.PS[0][2*PS_Num]; + AF_L = pstRDSData->PS_Data.PS[0][2*PS_Num+1]; + if((AF_H == (block_data[3])>>8)&&(AF_L == (block_data[3]&0xFF))){ + if((!((pstRDSData->event_status)&RDS_EVENT_PROGRAMNAME))&&((PS_Num == 0)||(pstRDSData->PS_Data.Addr_Cnt))){ + pstRDSData->PS_Data.PS[1][2*PS_Num]=(block_data[3])>>8; + pstRDSData->PS_Data.PS[1][2*PS_Num+1] = (block_data[3])&0xFF; + FM_LOG_DBG(D_G0,"RetrieveGroup0 PS second time, NUM:%x H:%x L:%x\n", + PS_Num, pstRDSData->PS_Data.PS[1][2*PS_Num], pstRDSData->PS_Data.PS[1][2*PS_Num+1]); + + //Need clear buff0, LCH question 1, should clear not not? + if((PS_Num == 0)&&(pstRDSData->PS_Data.Addr_Cnt == 0)){ + for(indx = 2; indx < 8; indx++){ + pstRDSData->PS_Data.PS[0][indx] = '\0'; //clear buff0 + } + } + pstRDSData->PS_Data.Addr_Cnt |= 1<PS_Data.Addr_Cnt); + if(pstRDSData->PS_Data.Addr_Cnt == 0x0F){ + //Avoid PS transient:Start + num = 0; + for(indx = 0; indx < 8; indx++){ + if(pstRDSData->PS_Data.PS[0][indx] == pstRDSData->PS_Data.PS[1][indx]) + num++; + } + pstRDSData->PS_Data.Addr_Cnt = 0; + //Avoid PS transient:END + + if(num == 8){ + // get same data 2 times + num = 0; + for(indx = 0; indx < 8; indx++){ + if(pstRDSData->PS_Data.PS[1][indx] == pstRDSData->PS_Data.PS[2][indx]) + num++; + } + //if(num != 8) //get same data 2 times, and not same as the last show. + pstRDSData->event_status |= RDS_EVENT_PROGRAMNAME; + + for(indx = 0; indx < 8; indx++){ + pstRDSData->PS_Data.PS[2][indx] = pstRDSData->PS_Data.PS[1][indx]; + pstRDSData->PS_Data.PS[1][indx] = '\0'; + pstRDSData->PS_Data.PS[0][indx] = '\0'; + } + }else{ + pstRDSData->PS_Data.Addr_Cnt |= 1<PS_Data.PS[0][2*PS_Num]=(block_data[3])>>8; + pstRDSData->PS_Data.PS[0][2*PS_Num+1] = (block_data[3])&0xFF; + FM_LOG_DBG(D_G0,"RetrieveGroup0 PS, NUM:%x H:%x L:%x\n", + PS_Num, pstRDSData->PS_Data.PS[0][2*PS_Num], pstRDSData->PS_Data.PS[0][2*PS_Num+1]); + } + + if((pstRDSData->event_status)&RDS_EVENT_PROGRAMNAME){ + PS_Num = 0; + for(num = 0; num < 8;num++){ + if(pstRDSData->PS_Data.PS[2][num] == '\0') + PS_Num |= 1<event_status &= (~RDS_EVENT_PROGRAMNAME); + } + } + + return ret; +} + +static int MT6620_RDS_RetrieveGroup1(uint16_t *block_data, uint8_t SubType, RDSData_Struct *pstRDSData) +{ + uint8_t variant_code = (block_data[2]&0x7000)>>12; + int ret = 0; + + if(variant_code == 0){ + pstRDSData->Extend_Country_Code = (uint8_t)block_data[2]&0xFF; + FM_LOG_DBG(D_G1,"Extend_Country_Code:%d\n", pstRDSData->Extend_Country_Code); + }else if(variant_code == 3){ + pstRDSData->Language_Code = block_data[2]&0xFFF; + FM_LOG_DBG(D_G1,"Language_Code:%d\n", pstRDSData->Language_Code); + } + + pstRDSData->Radio_Page_Code = block_data[1]&0x001F; + pstRDSData->Program_Item_Number_Code = block_data[3]; + + return ret; +} + +#ifdef FM_RDS_G2_USE_OLD +static bool PreTextABFlag; + +static int MT6620_RDS_RetrieveGroup2(uint16_t *block_data, uint8_t SubType, RDSData_Struct *pstRDSData) +{ + uint8_t TextAddr, indx, indx2, space, byte0, byte1; + uint16_t addrcnt; + int i = 0; + int ret = 0; + + TextAddr = (uint8_t)block_data[1]&0x0F; + + if(pstRDSData->RDSFlag.Text_AB != ((block_data[1]&0x0010)>>4)){ + pstRDSData->RDSFlag.Text_AB = (block_data[1]&0x0010)>>4; + pstRDSData->event_status |= RDS_EVENT_FLAGS; + pstRDSData->RDSFlag.flag_status |= RDS_FLAG_TEXT_AB; + } + FM_LOG_DBG(D_G2,"RT RetrieveGroup2 TextABFlag: %x --> %x\n", PreTextABFlag, pstRDSData->RDSFlag.Text_AB); + + if(PreTextABFlag != pstRDSData->RDSFlag.Text_AB){ // Text A/B changed, clear old RT, and get new RT + /*DDB:Some station don't send 0x0D, it just switch TextAB if it want to send next message.*/ + if (pstRDSData->RT_Data.isRTDisplay == 0) { + FM_LOG_WAR(D_G2,"RT_Data.isRTDisplay == 0, and TextAB changed\n"); + pstRDSData->event_status |= RDS_EVENT_LAST_RADIOTEXT; + space = 0; + for(indx = 0; indx < 64; indx++){ + /*DDB:Why TextData[1][0] NOT TextData[2][0], Because some station just send a message one time, and then change TextAB, send another message, SUCH As Beijing 90.0*/ + if(pstRDSData->RT_Data.TextData[1][indx] == 0x20) + space++; + } + if(space == 64) + pstRDSData->event_status &= (~RDS_EVENT_LAST_RADIOTEXT); + + if (pstRDSData->event_status & RDS_EVENT_LAST_RADIOTEXT){ + /*DDB:Why TextData[1][0] NOT TextData[2][0], Because some station just send a message one time, and then change TextAB, send another message, SUCH As Beijing 90.0*/ + memcpy(&(pstRDSData->RT_Data.TextData[3][0]), &(pstRDSData->RT_Data.TextData[1][0]), sizeof(pstRDSData->RT_Data.TextData[3])); + FM_LOG_WAR(D_G2,"RT_Data.isRTDisplay = 1, no 0x0D case.\n"); + pstRDSData->RT_Data.isRTDisplay = 1; + } + } + + //to get Radio text length + pstRDSData->RT_Data.TextLength = 0; + i = 15; + while(!(pstRDSData->RT_Data.Addr_Cnt & (1< -1)){ + i--; + } + if(!SubType){ + pstRDSData->RT_Data.TextLength = 4*(i+1); + }else{ + pstRDSData->RT_Data.TextLength = 2*(i+1); + } + FM_LOG_INF(D_G2,"RDS RT Get Len: [AddrMap=0x%x] [Length=0x%x]\n", pstRDSData->RT_Data.Addr_Cnt, pstRDSData->RT_Data.TextLength); + + /*DDB, end*/ + //clear the buffer because Text A/B changed + memset(&(pstRDSData->RT_Data.TextData[0][0]), 0x20, sizeof(pstRDSData->RT_Data.TextData[0])); + memset(&(pstRDSData->RT_Data.TextData[1][0]), 0x20, sizeof(pstRDSData->RT_Data.TextData[1])); + memset(&(pstRDSData->RT_Data.TextData[2][0]), 0x20, sizeof(pstRDSData->RT_Data.TextData[2])); + PreTextABFlag = pstRDSData->RDSFlag.Text_AB; + pstRDSData->RT_Data.GetLength = 0; + pstRDSData->RT_Data.Addr_Cnt = 0; + //pstRDSData->RT_Data.isRTDisplay = 0; + } + + if(!SubType){ + //Type A + //WCN_DBG(FM_ALERT|D_MAIN,"RetrieveGroup2 Type A RT TextAddr: 0x%x Text: 0x%x 0x%x", TextAddr, block_data[2], block_data[3]); + FM_LOG_NTC(D_G2,"%04x %04x %04x %04x %04x", block_data[0], block_data[1], block_data[2], block_data[3], block_data[4]); + pstRDSData->RT_Data.isTypeA = 1; + //to get the 4bytes RadioText + if(block_data[4]&(FM_RDS_GDBK_IND_C|FM_RDS_GDBK_IND_D)){ + pstRDSData->RT_Data.TextData[0][4*TextAddr] = block_data[2]>>8; + pstRDSData->RT_Data.TextData[0][4*TextAddr+1] = block_data[2]&0xFF; + pstRDSData->RT_Data.TextData[0][4*TextAddr+2] = block_data[3]>>8; + pstRDSData->RT_Data.TextData[0][4*TextAddr+3] = block_data[3]&0xFF; + space = 0; + + for(indx = 0; indx < 4;indx++){ + byte0 = pstRDSData->RT_Data.TextData[0][4*TextAddr+indx]; + byte1 = pstRDSData->RT_Data.TextData[1][4*TextAddr+indx]; + if (TextAddr == 0){ + //WCN_DBG(FM_ALERT|D_MAIN,"RT_Data.isRTDisplay = 0\n"); + pstRDSData->RT_Data.isRTDisplay = 0; + } + if((!(pstRDSData->event_status&RDS_EVENT_LAST_RADIOTEXT))&&(byte0 == byte1)){ + //get the same byte 2 times + space++; + pstRDSData->RT_Data.TextData[2][4*TextAddr+indx] = byte0; + }else{ + pstRDSData->RT_Data.TextData[1][4*TextAddr+indx] = byte0; + } + } + + if(space == 4){ + addrcnt = pstRDSData->RT_Data.Addr_Cnt; + pstRDSData->RT_Data.Addr_Cnt |= (1<RT_Data.Addr_Cnt); + + if(addrcnt == pstRDSData->RT_Data.Addr_Cnt){ + pstRDSData->RT_Data.BufCnt++; + }else if(pstRDSData->RT_Data.BufCnt > 0){ + pstRDSData->RT_Data.BufCnt--; + } + } + } else { + FM_LOG_ERR(D_G2|D_ALL,"RT %04x %04x %04x %04x %04x CRC error.", block_data[0], block_data[1], block_data[2], block_data[3], block_data[4]); + } + for(indx = 0; indx < 4; indx++){ + if(pstRDSData->RT_Data.TextData[2][4*TextAddr+indx] == 0x0D){ + pstRDSData->RT_Data.TextLength = 4*TextAddr+indx+1; //Add terminate charater + pstRDSData->RT_Data.TextData[2][4*TextAddr+indx] = '\0'; + pstRDSData->RT_Data.GetLength = 1; + }else if((4*TextAddr+indx) == 63 && pstRDSData->RT_Data.Addr_Cnt == 0xffff){ + //type A full data. /*add by dongbo, make sure it's TextData[2], Not TextData[1]*/ + pstRDSData->RT_Data.TextLength = 4*TextAddr+indx+1; //no terminal character + pstRDSData->RT_Data.GetLength = 1; + } + } + }else{ + //FM_LOG_DBG(D_MAIN,"RetrieveGroup2 Type B RT NUM: 0x%x Text: 0x%x", TextAddr, block_data[3]); + FM_LOG_DBG(D_G2,"RT %04x %04x %04x %04x %04x", block_data[0], block_data[1], block_data[2], block_data[3], block_data[4]); + pstRDSData->RT_Data.isTypeA = 0; + if(block_data[4]&FM_RDS_GDBK_IND_D){ + pstRDSData->RT_Data.TextData[0][2*TextAddr] = block_data[3]>>8; + pstRDSData->RT_Data.TextData[0][2*TextAddr+1] = block_data[3]&0xFF; + space = 0; + + for(indx = 0; indx < 2; indx++){ + byte0 = pstRDSData->RT_Data.TextData[0][2*TextAddr+indx]; + byte1 = pstRDSData->RT_Data.TextData[1][2*TextAddr+indx]; + + if((!((pstRDSData->event_status)&RDS_EVENT_LAST_RADIOTEXT))&&(byte0 == byte1)){ + space++; + pstRDSData->RT_Data.TextData[2][2*TextAddr+indx] = byte0; + }else{ + pstRDSData->RT_Data.TextData[1][2*TextAddr+indx] = byte0; + } + } + if(space == 2){ + addrcnt = pstRDSData->RT_Data.Addr_Cnt; + pstRDSData->RT_Data.Addr_Cnt |= (1<RT_Data.Addr_Cnt); + + if(addrcnt == pstRDSData->RT_Data.Addr_Cnt){ + pstRDSData->RT_Data.BufCnt++; + }else if(pstRDSData->RT_Data.BufCnt > 0){ + pstRDSData->RT_Data.BufCnt--; + } + } + } else { + FM_LOG_DBG(D_G2,"RT %04x %04x %04x %04x %04x CRC error.", block_data[0], block_data[1], block_data[2], block_data[3], block_data[4]); + } + + for(indx = 0; indx < 2; indx++){ + if((pstRDSData->RT_Data.TextData[2][2*TextAddr+indx]) == 0x0D){ + //0x0D=end code + pstRDSData->RT_Data.TextLength = 2*TextAddr+indx+1; //Add terminate charater + pstRDSData->RT_Data.TextData[2][2*TextAddr+indx] = '\0'; + pstRDSData->RT_Data.GetLength = 1; + }else if((2*TextAddr+indx) == 31){ + //full data + pstRDSData->RT_Data.TextLength = 2*TextAddr+indx+1; //Add terminate charater + pstRDSData->RT_Data.TextData[2][2*TextAddr+indx] = '\0'; + pstRDSData->RT_Data.GetLength = 1; + } + } + } + + //Check if text is fully received + indx = TextAddr; + if(pstRDSData->RT_Data.GetLength == 1){ + addrcnt = 0xFFFF>>(0x0F-indx); + }else if(pstRDSData->RT_Data.BufCnt > 100){ + pstRDSData->RT_Data.BufCnt = 0; + for(indx = 15; indx >= 0; indx--){ + addrcnt = (pstRDSData->RT_Data.Addr_Cnt)&(1<RT_Data.isTypeA){ + for(indx2 = 0; indx2 < 4; indx2++){ + if(pstRDSData->RT_Data.TextData[2][4*indx+indx2] == 0x0D){ + pstRDSData->RT_Data.TextLength = 4*indx+indx2+1; + pstRDSData->RT_Data.TextData[2][4*indx+indx2] = '\0'; + } + } + }else{ + for(indx2 = 0; indx2 < 2; indx2++){ + if(pstRDSData->RT_Data.TextData[2][2*indx+indx2] == 0x0D){ + pstRDSData->RT_Data.TextLength = 2*indx+indx2+1; + pstRDSData->RT_Data.TextData[2][2*indx+indx2] = '\0'; + } + } + + } + addrcnt = 0xFFFF>>(0x0F-indx); + }else{ + if(pstRDSData->RT_Data.TextLength > 64){ + pstRDSData->RT_Data.TextLength = 64; + } + addrcnt = 0xFFFF; + } + + FM_LOG_NTC(D_G2,"RetrieveGroup2 RDS RT: Addr_Cnt: 0x%x Length: 0x%x addrcnt: 0x%x\n", pstRDSData->RT_Data.Addr_Cnt, pstRDSData->RT_Data.TextLength, addrcnt); + + if(((((pstRDSData->RT_Data.Addr_Cnt)&addrcnt) == addrcnt)||((TextAddr == 0x0f) && (pstRDSData->RT_Data.Addr_Cnt == 0xffff)))){ + //&&(pstRDSData->RT_Data.isRTDisplay == 0)) + pstRDSData->RT_Data.Addr_Cnt = 0; + //pstRDSData->RT_Data.isRTDisplay = 1; + pstRDSData->event_status |= RDS_EVENT_LAST_RADIOTEXT; + FM_LOG_DBG(D_G2,"RT RetrieveGroup2 isRTDisplay:%d\n", pstRDSData->RT_Data.isRTDisplay); + space = 0; + for(indx = 0; indx < 64; indx++){ + if(pstRDSData->RT_Data.TextData[2][indx] == 0x20) + space++; + } + if(space == 64) + pstRDSData->event_status &= (~RDS_EVENT_LAST_RADIOTEXT); + + memset(&(pstRDSData->RT_Data.TextData[1][0]), 0x20, sizeof(pstRDSData->RT_Data.TextData[1])); + memset(&(pstRDSData->RT_Data.TextData[0][0]), 0x20, sizeof(pstRDSData->RT_Data.TextData[0])); + + if (pstRDSData->event_status & RDS_EVENT_LAST_RADIOTEXT){ + memcpy(&(pstRDSData->RT_Data.TextData[3][0]), &(pstRDSData->RT_Data.TextData[2][0]), sizeof(pstRDSData->RT_Data.TextData[3])); + FM_LOG_WAR(D_G2,"RT_Data.isRTDisplay = 1\n"); + pstRDSData->RT_Data.isRTDisplay = 1; + } + } + + return ret; +} +#else +static int MT6620_RDS_RetrieveGroup2(uint16_t *source, uint8_t subtype, RDSData_Struct *target) +{ + int ret = 0; + uint16_t crc, cbc; + uint16_t blkA, blkB, blkC, blkD; + uint8_t *fresh, *once, *twice, *display; + uint16_t *event; + uint32_t *flag; + + uint8_t rt_addr = 0; + bool txtAB_change = FALSE; //text AB flag 0 --> 1 or 1-->0 meas new RT incoming + bool txt_end = FALSE; //0x0D means text end + bool seg_ok = 0; + static uint16_t bitmap_twice; + static int bitmap_cnt; + int pos = 0; + int rt_len = 0; + int bufsize = 0; + + FM_ASSERT(source); + FM_ASSERT(target); + //source + blkA = source[0]; + blkB = source[1]; + blkC = source[2]; + blkD = source[3]; + crc = source[4]; + cbc = source[5]; + //target + fresh = target->RT_Data.TextData[0]; + once = target->RT_Data.TextData[1]; + twice = target->RT_Data.TextData[2]; + display = target->RT_Data.TextData[3]; + event = &target->event_status; + flag = &target->RDSFlag.flag_status; + bufsize = sizeof(target->RT_Data.TextData[0]); + + //get basic info: addr, txtAB + if(rds_group2_rt_addr_get(blkB, &rt_addr)) + return ret; + if(rds_group2_txtAB_get(blkB, &target->RDSFlag.Text_AB, &txtAB_change)) + return ret; + + //RT parsing state machine run + while(1){ + switch(rds_rt_state_get()){ + case RDS_RT_START: + if(txtAB_change == TRUE){ + rds_rt_state_set(RDS_RT_DECISION); + break; + }else{ + if(rds_group2_rt_get(crc, subtype, blkC, blkD, rt_addr, fresh)){ + rds_rt_state_set(RDS_RT_FINISH); //if CRC error, we should not do parsing + break; + } + rds_group2_rt_cmp(rt_addr, cbc, subtype, fresh, once, twice, + &seg_ok, &txt_end, &rt_len); + if(seg_ok == TRUE){ + rds_group2_rt_addr_bitmap_set(&bitmap_twice, &bitmap_cnt, rt_addr); + } + rds_rt_state_set(RDS_RT_DECISION); + break; + } + case RDS_RT_DECISION: + if(txt_end == TRUE){ + rds_rt_state_set(RDS_RT_GETLEN); //find 0x0D, and the lenth has been recorded when do rds_group2_rt_cmp() + }else if(rds_group2_rt_addr_bitmap_get(bitmap_twice) == 0xFFFF //get max 64 chars + || (txtAB_change == TRUE) //text AB changed, + || (bitmap_cnt > RDS_RT_MULTI_REV_TH)){ //repeate many times, but no end char get + pos = rds_group2_rt_addr_bitmap_get_pos(bitmap_twice); + rds_group2_rt_get_len(subtype, pos, &rt_len); + rds_rt_state_set(RDS_RT_GETLEN); + }else{ + rds_rt_state_set(RDS_RT_FINISH); + } + break; + case RDS_RT_GETLEN: + memcpy(display, twice, bufsize); + target->RT_Data.TextLength = rt_len; + rds_event_set(event, RDS_EVENT_LAST_RADIOTEXT); //yes we got a new RT + FM_LOG_NTC(D_G2,"Yes, get an RT! [len=%d]\n", rt_len); + + rds_group2_rt_addr_bitmap_clear(&bitmap_twice, &bitmap_cnt); + //clear buf + memset(fresh, 0x20, bufsize); + memset(once, 0x20, bufsize); + memset(twice, 0x20, bufsize); + if(txtAB_change == TRUE){ + txtAB_change = FALSE; + //we need get new RT after show the old RT to the display + rds_rt_state_set(RDS_RT_START); + }else{ + rds_rt_state_set(RDS_RT_FINISH); + } + break; + case RDS_RT_FINISH: + rds_rt_state_set(RDS_RT_START); + goto out; + break; + default: + break; + } + } +out: + return ret; +} +#endif + +static int MT6620_RDS_RetrieveGroup4(uint16_t *block_data, uint8_t SubType, RDSData_Struct *pstRDSData) +{ + uint16_t year, month, k=0, D2, minute; + uint32_t MJD, D1; + int ret = 0; + FM_LOG_DBG(D_G4,"RetrieveGroup4 %d\n", SubType); + if(!SubType){ + //Type A + if((block_data[4]&FM_RDS_GDBK_IND_C)&&(block_data[4]&FM_RDS_GDBK_IND_D)){ + MJD = (uint32_t) (((block_data[1]&0x0003)<<15) + ((block_data[2]&0xFFFE)>>1)); + year = (MJD*100 - 1507820)/36525; + month = (MJD*10000-149561000-3652500*year)/306001; + if((month == 14)||(month == 15)) + k = 1; + D1 = (uint32_t)((36525*year)/100); + D2 = (uint16_t)((306001*month)/10000); + pstRDSData->CT.Year = 1900 + year + k; + pstRDSData->CT.Month = month - 1 - k*12; + pstRDSData->CT.Day = (uint16_t)(MJD - 14956 - D1 - D2); + pstRDSData->CT.Hour = ((block_data[2]&0x0001)<<4)+((block_data[3]&0xF000)>>12); + minute = (block_data[3]&0x0FC0)>>6; + + if(block_data[3]&0x0020){ + pstRDSData->CT.Local_Time_offset_signbit = 1; //0=+, 1=- + } + pstRDSData->CT.Local_Time_offset_half_hour = block_data[3]&0x001F; + if(pstRDSData->CT.Minute != minute){ + pstRDSData->CT.Minute = (block_data[3]&0x0FC0)>>6; + pstRDSData->event_status |= RDS_EVENT_UTCDATETIME; + } + } + } + + return ret; +} + +static int MT6620_RDS_RetrieveGroup14(uint16_t *block_data, uint8_t SubType, RDSData_Struct *pstRDSData) +{ + uint8_t TP_ON, TA_ON, PI_ON, PS_Num, AF_H, AF_L, indx, indx2, num; + int ret = 0; + FM_LOG_DBG(D_G14,"RetrieveGroup14 %d\n", SubType); + //SubType = (*(block_data+1)&0x0800)>>11; + PI_ON = block_data[3]; + TP_ON = block_data[1]&0x0010; + if((!SubType) && (block_data[4]&FM_RDS_GDBK_IND_C)){ + //Type A + PS_Num= block_data[1]&0x000F; + if(PS_Num <4){ + for(indx = 0; indx < 2; indx++){ + pstRDSData->PS_ON[2*PS_Num] = block_data[2]>>8; + pstRDSData->PS_ON[2*PS_Num+1] = block_data[2]&0xFF; + } + }else if(PS_Num == 4){ + AF_H = (block_data[2]&0xFF00)>>8; + AF_L = block_data[2]&0x00FF; + if((AF_H > 223)&&(AF_H < 250)){ + //Followed AF Number + pstRDSData->AFON_Data.isAFNum_Get = 0; + preAFON_Num = AF_H - 224; + if(pstRDSData->AFON_Data.AF_Num != preAFON_Num){ + pstRDSData->AFON_Data.AF_Num = preAFON_Num; + }else + pstRDSData->AFON_Data.isAFNum_Get= 1; + + if(AF_L < 205){ + pstRDSData->AFON_Data.AF[0][0] = AF_L+875; + if((pstRDSData->AFON_Data.AF[0][0]) != (pstRDSData->AFON_Data.AF[1][0])){ + pstRDSData->AFON_Data.AF[1][0] = pstRDSData->AFON_Data.AF[0][0]; + }else{ + pstRDSData->AFON_Data.isMethod_A = 1; + } + } + }else if((pstRDSData->AFON_Data.isAFNum_Get)&&((pstRDSData->AFON_Data.Addr_Cnt) != 0xFF)){ + //AF Num correct + num = pstRDSData->AFON_Data.AF_Num; + num = num>>1; + //Put AF freq into buffer and check if AF freq is repeat again + for(indx = 1; indx < (num+1); indx++){ + if((AF_H == (pstRDSData->AFON_Data.AF[0][2*indx-1]))&&(AF_L == (pstRDSData->AFON_Data.AF[0][2*indx]))){ + FM_LOG_NTC(D_G14,"RetrieveGroup14 AFON same as indx:%d\n", indx); + break; + }else if(!(pstRDSData->AFON_Data.AF[0][2*indx-1])){ + //null buffer + pstRDSData->AFON_Data.AF[0][2*indx-1] = AF_H+875; + pstRDSData->AFON_Data.AF[0][2*indx] = AF_L+875; + break; + } + } + num = pstRDSData->AFON_Data.AF_Num; + if(num > 0){ + if((pstRDSData->AFON_Data.AF[0][num-1]) != 0){ + num = num>> 1; + //arrange frequency from low to high:start + for(indx = 1; indx < num; indx++){ + for(indx2 = indx+1; indx2 < (num+1); indx2++){ + AF_H = pstRDSData->AFON_Data.AF[0][2*indx-1]; + AF_L = pstRDSData->AFON_Data.AF[0][2*indx]; + if(AF_H > (pstRDSData->AFON_Data.AF[0][2*indx2-1])){ + pstRDSData->AFON_Data.AF[0][2*indx-1] = pstRDSData->AFON_Data.AF[0][2*indx2-1]; + pstRDSData->AFON_Data.AF[0][2*indx] = pstRDSData->AFON_Data.AF[0][2*indx2]; + pstRDSData->AFON_Data.AF[0][2*indx2-1] = AF_H; + pstRDSData->AFON_Data.AF[0][2*indx2] = AF_L; + }else if(AF_H == (pstRDSData->AFON_Data.AF[0][2*indx2-1])){ + if(AF_L > (pstRDSData->AFON_Data.AF[0][2*indx2])){ + pstRDSData->AFON_Data.AF[0][2*indx-1] = pstRDSData->AFON_Data.AF[0][2*indx2-1]; + pstRDSData->AFON_Data.AF[0][2*indx] = pstRDSData->AFON_Data.AF[0][2*indx2]; + pstRDSData->AFON_Data.AF[0][2*indx2-1] = AF_H; + pstRDSData->AFON_Data.AF[0][2*indx2] = AF_L; + } + } + } + } + //arrange frequency from low to high:end + //compare AF buff0 and buff1 data:start + num = pstRDSData->AFON_Data.AF_Num; + indx2 = 0; + for(indx = 0; indx < num; indx++){ + if((pstRDSData->AFON_Data.AF[1][indx]) == (pstRDSData->AFON_Data.AF[0][indx])){ + if(pstRDSData->AFON_Data.AF[1][indx] != 0) + indx2++; + }else + pstRDSData->AFON_Data.AF[1][indx] = pstRDSData->AFON_Data.AF[0][indx]; + } + //compare AF buff0 and buff1 data:end + if(indx2 == num){ + pstRDSData->AFON_Data.Addr_Cnt = 0xFF; + pstRDSData->event_status |= RDS_EVENT_AFON_LIST; + for(indx = 0; indx < num; indx++){ + if((pstRDSData->AFON_Data.AF[1][indx]) == 0){ + pstRDSData->AFON_Data.Addr_Cnt = 0x0F; + pstRDSData->event_status &= (~RDS_EVENT_AFON_LIST); + } + } + }else + pstRDSData->AFON_Data.Addr_Cnt = 0x0F; + } + } + } + } + }else{ + //Type B + TA_ON = block_data[1]&0x0008; + FM_LOG_DBG(D_G14,"TA group14 typeB pstRDSData->RDSFlag.TP=%d pstRDSData->RDSFlag.TA=%d TP_ON=%d TA_ON=%d\n", pstRDSData->RDSFlag.TP, pstRDSData->RDSFlag.TA, TP_ON, TA_ON); + if((!pstRDSData->RDSFlag.TP)&&(pstRDSData->RDSFlag.TA)&&TP_ON&&TA_ON){ + int TA_num=0; + for (num=0;num<25;num++){ + if (pstRDSData->AFON_Data.AF[1][num] != 0){ + TA_num++; + } else { + break; + } + } + FM_LOG_NTC(D_G14,"TA set RDS_EVENT_TAON"); + if (TA_num == pstRDSData->AFON_Data.AF_Num){ + pstRDSData->event_status |= RDS_EVENT_TAON; + } + } + } + + return ret; +} + +int MT6620_RDS_OnOff(struct fm *fm, bool bFlag) +{ + int ret = 0; + RDSData_Struct *pstRDSData = fm->pstRDSData; + + if(bFlag){ + if((ret = MT6620_RDS_Init_Data(pstRDSData))) + return ret; + if((ret = MT6620_RDS_enable())) + return ret; + }else { + if((ret = MT6620_RDS_disable())) + return ret; + } + + return ret; +} + +/* + Block0: PI code(16bits) + Block1: Group type(4bits), B0=version code(1bit), TP=traffic program code(1bit), + PTY=program type code(5bits), other(5bits) + Block2: 16bits + Block3: 16bits +*/ +int MT6620_RDS_Eint_Handler(struct fm *fm, struct rds_rx *rds_raw, int rds_size) +{ + int ret = 0; + uint16_t block_data[6]; + uint8_t GroupType, SubType = 0; + int rds_cnt = 0; + int i = 0; + bool dirty = FALSE; + //target to fill the result in + RDSData_Struct *pstRDSData = fm->pstRDSData; + uint16_t *event = &pstRDSData->event_status; + uint32_t *flag = &pstRDSData->RDSFlag.flag_status; + + ret = rds_cnt_get(rds_raw, rds_size, &rds_cnt); + if(ret){ + FM_LOG_WAR(D_RDS,"get cnt err[ret=%d]\n", ret); + return ret; + } + //pstRDSData->EINT_Flag = 1; + while(rds_cnt > 0){ + ret = rds_group_get(&block_data[0], rds_raw, i); + if(ret){ + FM_LOG_WAR(D_RDS,"get group err[ret=%d]\n", ret); + goto do_next; + } + + ret = rds_group_type_get(block_data[4], block_data[1], &GroupType, &SubType); + if(ret){ + FM_LOG_WAR(D_RDS,"get group type err[ret=%d]\n", ret); + goto do_next; + } + + ret = rds_group_counter_add(GroupType, SubType, &fm->rds_gc); + + ret = rds_group_pi_get(block_data[4], block_data[0], &pstRDSData->PI, &dirty); + if(ret){ + FM_LOG_WAR(D_RDS,"get group pi err[ret=%d]\n", ret); + goto do_next; + }else if(dirty == TRUE){ + ret = rds_event_set(event, RDS_EVENT_PI_CODE); //yes, we got new PI code + } + + ret = rds_group_pty_get(block_data[4], block_data[1], &pstRDSData->PTY, &dirty); + if(ret){ + FM_LOG_WAR(D_RDS,"get group pty err[ret=%d]\n", ret); + goto do_next; + }else if(dirty == TRUE){ + ret = rds_event_set(event, RDS_EVENT_PTY_CODE); // yes, we got new PTY code + } + + ret = rds_group_tp_get(block_data[4], block_data[1], &pstRDSData->RDSFlag.TP, &dirty); + if(ret){ + FM_LOG_WAR(D_RDS,"get group tp err[ret=%d]\n", ret); + goto do_next; + }else if(dirty == TRUE){ + ret = rds_event_set(event, RDS_EVENT_FLAGS); // yes, we got new TP code + ret = rds_flag_set(flag, RDS_FLAG_IS_TP); + } + + switch(GroupType){ + case 0: + if((ret = MT6620_RDS_RetrieveGroup0(&block_data[0], SubType, pstRDSData))) + goto do_next; + break; + case 1: + if((ret = MT6620_RDS_RetrieveGroup1(&block_data[0], SubType, pstRDSData))) + goto do_next; + break; + case 2: + if((ret = MT6620_RDS_RetrieveGroup2(&block_data[0], SubType, pstRDSData))) + goto do_next; + break; + case 4: + if((ret = MT6620_RDS_RetrieveGroup4(&block_data[0], SubType, pstRDSData))) + goto do_next; + break; + case 14: + if((ret = MT6620_RDS_RetrieveGroup14(&block_data[0], SubType, pstRDSData))) + goto do_next; + break; + default: + break; + } + +do_next: + if(ret && (ret != -ERR_RDS_CRC)){ + FM_LOG_ERR(D_RDS,"parsing err[ret=%d]\n", ret); + return ret; + } + rds_cnt--; + i++; + } + + return ret; +} + diff --git a/drivers/mtk_wcn_combo/drv_wlan/Makefile b/drivers/mtk_wcn_combo/drv_wlan/Makefile new file mode 100755 index 000000000000..20820c11333f --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/Makefile @@ -0,0 +1,49 @@ +# Copyright Statement: +# +# This software/firmware and related documentation ("MediaTek Software") are +# protected under relevant copyright laws. The information contained herein +# is confidential and proprietary to MediaTek Inc. and/or its licensors. +# Without the prior written permission of MediaTek inc. and/or its licensors, +# any reproduction, modification, use or disclosure of MediaTek Software, +# and information contained herein, in whole or in part, shall be strictly prohibited. +# +# MediaTek Inc. (C) 2010. All rights reserved. +# +# BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES +# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") +# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON +# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. +# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE +# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR +# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH +# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES +# THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES +# CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK +# SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR +# STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND +# CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, +# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, +# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO +# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +# +# The following software/firmware and/or related documentation ("MediaTek Software") +# have been modified by MediaTek Inc. All revisions are subject to any receiver's +# applicable license agreements with MediaTek Inc. + + +obj-$(CONFIG_MTK_COMBO_WIFI) += wlan/ +obj-$(CONFIG_MTK_COMBO_WIFI) += p2p/ +#BUILD_P2P=n + +#ifeq ($(MTK_WIFI_HOTSPOT_SUPPORT), yes) +#BUILD_P2P=y +#endif +#ifeq ($(MTK_WIFI_P2P_SUPPORT), yes) +#BUILD_P2P=y +#endif + +#ifeq ($(BUILD_P2P), y) +#obj-$(CONFIG_MTK_COMBO_WIFI) += p2p/ +#endif diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/Makefile b/drivers/mtk_wcn_combo/drv_wlan/p2p/Makefile new file mode 100755 index 000000000000..a0bd71282a7a --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/Makefile @@ -0,0 +1,120 @@ +# Copyright Statement: +# +# This software/firmware and related documentation ("MediaTek Software") are +# protected under relevant copyright laws. The information contained herein +# is confidential and proprietary to MediaTek Inc. and/or its licensors. +# Without the prior written permission of MediaTek inc. and/or its licensors, +# any reproduction, modification, use or disclosure of MediaTek Software, +# and information contained herein, in whole or in part, shall be strictly prohibited. +# +# MediaTek Inc. (C) 2010. All rights reserved. +# +# BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES +# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") +# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON +# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. +# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE +# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR +# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH +# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES +# THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES +# CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK +# SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR +# STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND +# CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, +# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, +# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO +# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +# +# The following software/firmware and/or related documentation ("MediaTek Software") +# have been modified by MediaTek Inc. All revisions are subject to any receiver's +# applicable license agreements with MediaTek Inc. + + +# --------------------------------------------------- +# Compile Options +# --------------------------------------------------- +ccflags-y += -DLINUX -DMT6620 + +ifeq ($(MTK_WAPI_SUPPORT), yes) + ccflags-y += -DCFG_SUPPORT_WAPI=1 +else + ccflags-y += -DCFG_SUPPORT_WAPI=0 +endif + +ifeq ($(HAVE_XLOG_FEATURE), yes) + ccflags-y += -DCFG_SUPPORT_XLOG=1 +else + ccflags-y += -DCFG_SUPPORT_XLOG=0 +endif + +#ifeq ($(CONFIG_MTK_COMBO_WIFI_HIF_SDIO1), y) +# ccflags-y += -D_HIF_SDIO=1 +#endif +ccflags-y += -D_HIF_SDIO=1 + +#ccflags-y += -DDBG=0 +ccflags-y += -DDBG=0 +ccflags-y += -I$(src)/os -I$(src)/os/linux/include +ccflags-y += -I$(src)/include -I$(src)/include/nic -I$(src)/include/mgmt + +ccflags-y += -I$(src)/../wlan/os -I$(src)/../wlan/os/linux/include -I$(src)/../wlan/os/linux/hif/sdio/include +ccflags-y += -I$(src)/../wlan/include -I$(src)/../wlan/include/nic -I$(src)/../wlan/include/mgmt + +obj-$(CONFIG_MTK_COMBO_WIFI) += p2p.o + +# --------------------------------------------------- +# Directory List +# --------------------------------------------------- +COMMON_DIR := common/ +OS_DIR := os/linux/ +NIC_DIR := nic/ +MGMT_DIR := mgmt/ + +#always := $(shell cp -f ../mediatek/source/kernel/drivers/combo/drv_wlan/wlan/$(OS_DIR)gl_sec.o.new ../mediatek/source/kernel/drivers/combo/drv_wlan/wlan/$(OS_DIR)gl_sec.o) +#always := $(touch ../mediatek/source/kernel/drivers/combo/drv_wlan/wlan/$(OS_DIR)gl_sec.o) + +# --------------------------------------------------- +# Objects List +# --------------------------------------------------- + +COMMON_OBJS := $(COMMON_DIR)wlan_p2p.o + +NIC_OBJS := $(NIC_DIR)p2p_nic.o + +OS_OBJS := $(OS_DIR)gl_p2p.o \ + $(OS_DIR)gl_p2p_cfg80211.o \ + $(OS_DIR)gl_p2p_init.o \ + $(OS_DIR)gl_p2p_kal.o + +MGMT_OBJS :=$(MGMT_DIR)p2p_fsm.o \ + $(MGMT_DIR)p2p_scan.o \ + $(MGMT_DIR)p2p_rlm.o \ + $(MGMT_DIR)p2p_rlm_obss.o\ + $(MGMT_DIR)p2p_bss.o\ + $(MGMT_DIR)p2p_assoc.o\ + $(MGMT_DIR)p2p_func.o\ + $(MGMT_DIR)p2p_state.o\ + $(MGMT_DIR)p2p_ie.o + +#ifeq ($(MTK_WAPI_SUPPORT), yes) +#MGMT_OBJS += $(MGMT_DIR)wapi.o +#OS_OBJS += $(OS_DIR)gl_sec.o +#endif + +#ifeq ($(WLAN_PROC), y) +#OS_OBJS += gl_proc.o +#endif + +#HIF_OBJS := $(HIF_DIR)arm.o \ +# $(HIF_DIR)sdio.o + +p2p-objs += $(COMMON_OBJS) +p2p-objs += $(NIC_OBJS) +p2p-objs += $(OS_OBJS) +p2p-objs += $(HIF_OBJS) +p2p-objs += $(MGMT_OBJS) + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/common/wlan_p2p.c b/drivers/mtk_wcn_combo/drv_wlan/p2p/common/wlan_p2p.c new file mode 100755 index 000000000000..e69dbb83fe36 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/common/wlan_p2p.c @@ -0,0 +1,1867 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/WIFI_P2P_DRIVER_V2_2/common/wlan_p2p.c#5 $ +*/ + +/*! \file wlan_bow.c + \brief This file contains the Wi-Fi Direct commands processing routines for + MediaTek Inc. 802.11 Wireless LAN Adapters. +*/ + +/****************************************************************************** +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************* +*/ + +/****************************************************************************** +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************* +*/ + +/* +** $Log: wlan_p2p.c $ + * + * 01 31 2012 yuche.tsai + * NULL + * Fix compile error & del beacon scenario. + * + * 01 26 2012 yuche.tsai + * NULL + * Fix compile warning. + * + * 01 19 2012 chinglan.wang + * NULL + * Support the WPA-PSK TKIP security mode for the tethering. + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Hot Spot Tethering for ICS ALPHA testing version. + * + * 11 24 2011 yuche.tsai + * NULL + * Fix P2P IOCTL of multicast address bug, add low power driver stop control. + * + * 11 22 2011 yuche.tsai + * NULL + * Update RSSI link quality of P2P Network query method. (Bug fix) + * + * 11 19 2011 yuche.tsai + * NULL + * Add RSSI support for P2P network. + * + * 11 08 2011 yuche.tsai + * [WCXRP00001094] [Volunteer Patch][Driver] Driver version & supplicant version query & set support for service discovery version check. + * Add support for driver version query & p2p supplicant verseion set. + * For new service discovery mechanism sync. + * + * 10 18 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Support Channle Query. + * + * 10 18 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * New 2.1 branch + + * + * 08 23 2011 yuche.tsai + * NULL + * Fix Multicast Issue of P2P. + * + * 04 27 2011 george.huang + * [WCXRP00000684] [MT6620 Wi-Fi][Driver] Support P2P setting ARP filter + * Support P2P ARP filter setting on early suspend/ late resume + * + * 04 08 2011 george.huang + * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode + * separate settings of P2P and AIS + * + * 03 22 2011 george.huang + * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command + * link with supplicant commands + * + * 03 19 2011 terry.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 p2p driver release based on label "MT6620_WIFI_P2P_DRIVER_V2_0_2100_0319_2011" from main trunk. + * + * 03 17 2011 wh.su + * [WCXRP00000571] [MT6620 Wi-Fi] [Driver] Not check the p2p role during set key + * Skip the p2p role for adding broadcast key issue. + * + * 03 16 2011 wh.su + * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done + * fixed compiling error while enable dbg. + * + * 03 08 2011 yuche.tsai + * [WCXRP00000480] [Volunteer Patch][MT6620][Driver] WCS IE format issue[WCXRP00000509] [Volunteer Patch][MT6620][Driver] Kernal panic when remove p2p module. + * . + * + * 03 07 2011 terry.wu + * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message + * Toggle non-standard debug messages to comments. + * + * 03 07 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * rename the define to anti_pviracy. + * + * 03 05 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * add the code to get the check rsponse and indicate to app. + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * Add Security check related code. + * + * 03 02 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Fix SD Request Query Length issue. + * + * 03 02 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Service Discovery Request. + * + * 03 01 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Update Service Discovery Wlan OID related function. + * + * 03 01 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Update Service Discovery Related wlanoid function. + * + * 02 09 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Add Service Discovery Indication Related code. + * + * 01 26 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Add Service Discovery Function. + * + * 01 05 2011 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service Discovery + * ioctl implementations for P2P Service Discovery + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease physically continous memory demands + * separate kalMemAlloc() into virtually-continous and physically-continous type to ease slab system pressure + * + * 12 22 2010 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service Discovery + * 1. header file restructure for more clear module isolation + * 2. add function interface definition for implementing Service Discovery callbacks + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by ENUM_NETWORK_TYPE_INDEX_T only + * remove ENUM_NETWORK_TYPE_T definitions + * + * 09 28 2010 wh.su + * NULL + * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. + * + * 09 21 2010 kevin.huang + * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface + * Isolate P2P related function for Hardware Software Bundle + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 23 2010 cp.wu + * NULL + * revise constant definitions to be matched with implementation (original cmd-event definition is deprecated) + * + * 08 16 2010 cp.wu + * NULL + * add subroutines for P2P to set multicast list. + * + * 08 16 2010 george.huang + * NULL + * . + * + * 08 16 2010 george.huang + * NULL + * support wlanoidSetP2pPowerSaveProfile() in P2P + * + * 08 16 2010 george.huang + * NULL + * Support wlanoidSetNetworkAddress() for P2P + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 25 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add API in que_mgt to retrieve sta-rec index for security frames. + * + * 06 24 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * 1) add timeout handler mechanism for pending command packets + * 2) add p2p add/removal key + * +** +*/ + +/****************************************************************************** +* C O M P I L E R F L A G S +******************************************************************************* +*/ + +/****************************************************************************** +* E X T E R N A L R E F E R E N C E S +******************************************************************************* +*/ +#include "p2p_precomp.h" + +/****************************************************************************** +* C O N S T A N T S +******************************************************************************* +*/ + +/****************************************************************************** +* D A T A T Y P E S +******************************************************************************* +*/ + +/****************************************************************************** +* P U B L I C D A T A +******************************************************************************* +*/ + +/****************************************************************************** +* P R I V A T E D A T A +******************************************************************************* +*/ + +/****************************************************************************** +* M A C R O S +******************************************************************************* +*/ + +/****************************************************************************** +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************* +*/ + +/****************************************************************************** +* F U N C T I O N S +******************************************************************************* +*/ +/*----------------------------------------------------------------------------*/ +/*! +* \brief command packet generation utility +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] ucCID Command ID +* \param[in] fgSetQuery Set or Query +* \param[in] fgNeedResp Need for response +* \param[in] pfCmdDoneHandler Function pointer when command is done +* \param[in] u4SetQueryInfoLen The length of the set/query buffer +* \param[in] pucInfoBuffer Pointer to set/query buffer +* +* +* \retval WLAN_STATUS_PENDING +* \retval WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSendSetQueryP2PCmd ( + IN P_ADAPTER_T prAdapter, + UINT_8 ucCID, + BOOLEAN fgSetQuery, + BOOLEAN fgNeedResp, + BOOLEAN fgIsOid, + PFN_CMD_DONE_HANDLER pfCmdDoneHandler, + PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, + UINT_32 u4SetQueryInfoLen, + PUINT_8 pucInfoBuffer, + OUT PVOID pvSetQueryBuffer, + IN UINT_32 u4SetQueryBufferLen + ) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + UINT_8 ucCmdSeqNum; + + ASSERT(prAdapter); + + prGlueInfo = prAdapter->prGlueInfo; + ASSERT(prGlueInfo); + + DEBUGFUNC("wlanoidSendSetQueryP2PCmd"); + DBGLOG(REQ, TRACE, ("Command ID = 0x%08X\n", ucCID)); + + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + u4SetQueryInfoLen)); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, ("Allocate CMD_INFO_T ==> FAILED.\n")); + return WLAN_STATUS_FAILURE; + } + + // increase command sequence number + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + DBGLOG(REQ, TRACE, ("ucCmdSeqNum =%d\n", ucCmdSeqNum)); + + // Setup common CMD Info Packet + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->eNetworkType = NETWORK_TYPE_P2P_INDEX; + prCmdInfo->u2InfoBufLen = (UINT_16)(CMD_HDR_SIZE + u4SetQueryInfoLen); + prCmdInfo->pfCmdDoneHandler = pfCmdDoneHandler; + prCmdInfo->pfCmdTimeoutHandler = pfCmdTimeoutHandler; + prCmdInfo->fgIsOid = fgIsOid; + prCmdInfo->ucCID = ucCID; + prCmdInfo->fgSetQuery = fgSetQuery; + prCmdInfo->fgNeedResp = fgNeedResp; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = u4SetQueryInfoLen; + prCmdInfo->pvInformationBuffer = pvSetQueryBuffer; + prCmdInfo->u4InformationBufferLength = u4SetQueryBufferLen; + + // Setup WIFI_CMD_T (no payload) + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + if(u4SetQueryInfoLen > 0 && pucInfoBuffer != NULL) { + kalMemCopy(prWifiCmd->aucBuffer, pucInfoBuffer, u4SetQueryInfoLen); + } + + // insert into prCmdQueue + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + + // wakeup txServiceThread later + GLUE_SET_EVENT(prGlueInfo); + return WLAN_STATUS_PENDING; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set a key to Wi-Fi Direct driver +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetAddP2PKey( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + CMD_802_11_KEY rCmdKey; + P_PARAM_KEY_T prNewKey; + + DEBUGFUNC("wlanoidSetAddP2PKey"); + DBGLOG(REQ, INFO, ("\n")); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + prNewKey = (P_PARAM_KEY_T) pvSetBuffer; + + /* Verify the key structure length. */ + if (prNewKey->u4Length > u4SetBufferLen) { + DBGLOG(REQ, WARN, ("Invalid key structure length (%d) greater than total buffer length (%d)\n", + (UINT_8)prNewKey->u4Length, + (UINT_8)u4SetBufferLen)); + + *pu4SetInfoLen = u4SetBufferLen; + return WLAN_STATUS_INVALID_LENGTH; + } + /* Verify the key material length for key material buffer */ + else if (prNewKey->u4KeyLength > prNewKey->u4Length - OFFSET_OF(PARAM_KEY_T, aucKeyMaterial)) { + DBGLOG(REQ, WARN, ("Invalid key material length (%d)\n", (UINT_8)prNewKey->u4KeyLength)); + *pu4SetInfoLen = u4SetBufferLen; + return WLAN_STATUS_INVALID_DATA; + } + /* Exception check */ + else if (prNewKey->u4KeyIndex & 0x0fffff00) { + return WLAN_STATUS_INVALID_DATA; + } + /* Exception check, pairwise key must with transmit bit enabled */ + else if ((prNewKey->u4KeyIndex & BITS(30,31)) == IS_UNICAST_KEY) { + return WLAN_STATUS_INVALID_DATA; + } + else if (!(prNewKey->u4KeyLength == CCMP_KEY_LEN) && !(prNewKey->u4KeyLength == TKIP_KEY_LEN)) { + return WLAN_STATUS_INVALID_DATA; + } + /* Exception check, pairwise key must with transmit bit enabled */ + else if ((prNewKey->u4KeyIndex & BITS(30,31)) == BITS(30,31)) { + if (((prNewKey->u4KeyIndex & 0xff) != 0) || + ((prNewKey->arBSSID[0] == 0xff) && (prNewKey->arBSSID[1] == 0xff) && (prNewKey->arBSSID[2] == 0xff) && + (prNewKey->arBSSID[3] == 0xff) && (prNewKey->arBSSID[4] == 0xff) && (prNewKey->arBSSID[5] == 0xff))) { + return WLAN_STATUS_INVALID_DATA; + } + } + + *pu4SetInfoLen = u4SetBufferLen; + + // fill CMD_802_11_KEY + kalMemZero(&rCmdKey, sizeof(CMD_802_11_KEY)); + rCmdKey.ucAddRemove = 1; /* add */ + rCmdKey.ucTxKey = ((prNewKey->u4KeyIndex & IS_TRANSMIT_KEY) == IS_TRANSMIT_KEY) ? 1 : 0; + rCmdKey.ucKeyType = ((prNewKey->u4KeyIndex & IS_UNICAST_KEY) == IS_UNICAST_KEY) ? 1 : 0; + if(kalP2PGetRole(prAdapter->prGlueInfo) == 1) { /* group client */ + rCmdKey.ucIsAuthenticator = 0; + } + else { /* group owner */ + rCmdKey.ucIsAuthenticator = 1; + } + COPY_MAC_ADDR(rCmdKey.aucPeerAddr, prNewKey->arBSSID); + rCmdKey.ucNetType = NETWORK_TYPE_P2P_INDEX; + if(prNewKey->u4KeyLength == CCMP_KEY_LEN) + rCmdKey.ucAlgorithmId = CIPHER_SUITE_CCMP; // AES + else if(prNewKey->u4KeyLength == TKIP_KEY_LEN) + rCmdKey.ucAlgorithmId = CIPHER_SUITE_TKIP; // TKIP + rCmdKey.ucKeyId = (UINT_8)(prNewKey->u4KeyIndex & 0xff); + rCmdKey.ucKeyLen = (UINT_8)prNewKey->u4KeyLength; + kalMemCopy(rCmdKey.aucKeyMaterial, (PUINT_8)prNewKey->aucKeyMaterial, rCmdKey.ucKeyLen); + + return wlanoidSendSetQueryP2PCmd(prAdapter, + CMD_ID_ADD_REMOVE_KEY, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + NULL, + sizeof(CMD_802_11_KEY), + (PUINT_8)&rCmdKey, + pvSetBuffer, + u4SetBufferLen + ); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to request Wi-Fi Direct driver to remove keys +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetRemoveP2PKey( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + CMD_802_11_KEY rCmdKey; + P_PARAM_REMOVE_KEY_T prRemovedKey; + + DEBUGFUNC("wlanoidSetRemoveP2PKey"); + ASSERT(prAdapter); + + if (u4SetBufferLen < sizeof(PARAM_REMOVE_KEY_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + prRemovedKey = (P_PARAM_REMOVE_KEY_T)pvSetBuffer; + + /* Check bit 31: this bit should always 0 */ + if (prRemovedKey->u4KeyIndex & IS_TRANSMIT_KEY) { + /* Bit 31 should not be set */ + DBGLOG(REQ, ERROR, ("invalid key index: 0x%08lx\n", + prRemovedKey->u4KeyIndex)); + return WLAN_STATUS_INVALID_DATA; + } + + /* Check bits 8 ~ 29 should always be 0 */ + if (prRemovedKey->u4KeyIndex & BITS(8, 29)) { + /* Bit 31 should not be set */ + DBGLOG(REQ, ERROR, ("invalid key index: 0x%08lx\n", + prRemovedKey->u4KeyIndex)); + return WLAN_STATUS_INVALID_DATA; + } + + /* There should not be any key operation for P2P Device */ + if(kalP2PGetRole(prAdapter->prGlueInfo) == 0) { + // return WLAN_STATUS_NOT_ACCEPTED; + } + + kalMemZero((PUINT_8)&rCmdKey, sizeof(CMD_802_11_KEY)); + + rCmdKey.ucAddRemove = 0; // remove + if(kalP2PGetRole(prAdapter->prGlueInfo) == 1) { /* group client */ + rCmdKey.ucIsAuthenticator = 0; + } + else { /* group owner */ + rCmdKey.ucIsAuthenticator = 1; + } + kalMemCopy(rCmdKey.aucPeerAddr, (PUINT_8)prRemovedKey->arBSSID, MAC_ADDR_LEN); + rCmdKey.ucNetType = NETWORK_TYPE_P2P_INDEX; + rCmdKey.ucKeyId = (UINT_8)(prRemovedKey->u4KeyIndex & 0x000000ff); + + return wlanoidSendSetQueryP2PCmd(prAdapter, + CMD_ID_ADD_REMOVE_KEY, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + NULL, + sizeof(CMD_802_11_KEY), + (PUINT_8)&rCmdKey, + pvSetBuffer, + u4SetBufferLen + ); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Setting the IP address for pattern search function. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \return WLAN_STATUS_SUCCESS +* \return WLAN_STATUS_ADAPTER_NOT_READY +* \return WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetP2pNetworkAddress( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 i, j; + P_CMD_SET_NETWORK_ADDRESS_LIST prCmdNetworkAddressList; + P_PARAM_NETWORK_ADDRESS_LIST prNetworkAddressList = (P_PARAM_NETWORK_ADDRESS_LIST)pvSetBuffer; + P_PARAM_NETWORK_ADDRESS prNetworkAddress; + P_PARAM_NETWORK_ADDRESS_IP prNetAddrIp; + UINT_32 u4IpAddressCount, u4CmdSize; + + DEBUGFUNC("wlanoidSetP2pNetworkAddress"); + DBGLOG(INIT, TRACE, ("\n")); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = 4; + + if (u4SetBufferLen < sizeof(PARAM_NETWORK_ADDRESS_LIST)) { + return WLAN_STATUS_INVALID_DATA; + } + + *pu4SetInfoLen = 0; + u4IpAddressCount = 0; + + prNetworkAddress = prNetworkAddressList->arAddress; + for ( i = 0 ; i < prNetworkAddressList->u4AddressCount ; i++) { + if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && + prNetworkAddress->u2AddressLength == sizeof(PARAM_NETWORK_ADDRESS_IP)) { + u4IpAddressCount++; + } + + prNetworkAddress = (P_PARAM_NETWORK_ADDRESS) ((UINT_32) prNetworkAddress + + (UINT_32) (prNetworkAddress->u2AddressLength + OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress))); + } + + // construct payload of command packet + u4CmdSize = OFFSET_OF(CMD_SET_NETWORK_ADDRESS_LIST, arNetAddress) + + sizeof(IPV4_NETWORK_ADDRESS) * u4IpAddressCount; + + prCmdNetworkAddressList = (P_CMD_SET_NETWORK_ADDRESS_LIST) kalMemAlloc(u4CmdSize, VIR_MEM_TYPE); + + if(prCmdNetworkAddressList == NULL) + return WLAN_STATUS_FAILURE; + + // fill P_CMD_SET_NETWORK_ADDRESS_LIST + prCmdNetworkAddressList->ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; + prCmdNetworkAddressList->ucAddressCount = (UINT_8)u4IpAddressCount; + prNetworkAddress = prNetworkAddressList->arAddress; + for (i = 0, j = 0 ; i < prNetworkAddressList->u4AddressCount ; i++) { + if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && + prNetworkAddress->u2AddressLength == sizeof(PARAM_NETWORK_ADDRESS_IP)) { + prNetAddrIp = (P_PARAM_NETWORK_ADDRESS_IP)prNetworkAddress->aucAddress; + + kalMemCopy(prCmdNetworkAddressList->arNetAddress[j].aucIpAddr, + &(prNetAddrIp->in_addr), + sizeof(UINT_32)); + + j++; + } + + prNetworkAddress = (P_PARAM_NETWORK_ADDRESS) ((UINT_32) prNetworkAddress + + (UINT_32) (prNetworkAddress->u2AddressLength + OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress))); + } + + rStatus = wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_IP_ADDRESS, + TRUE, + FALSE, + TRUE, + nicCmdEventSetIpAddress, + nicOidCmdTimeoutCommon, + u4CmdSize, + (PUINT_8)prCmdNetworkAddressList, + pvSetBuffer, + u4SetBufferLen + ); + + kalMemFree(prCmdNetworkAddressList, VIR_MEM_TYPE, u4CmdSize); + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to query the power save profile. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \return WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryP2pPowerSaveProfile ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryP2pPowerSaveProfile"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + if (u4QueryBufferLen!=0) { + ASSERT(pvQueryBuffer); + + *(PPARAM_POWER_MODE) pvQueryBuffer = (PARAM_POWER_MODE)(prAdapter->rWlanInfo.arPowerSaveMode[NETWORK_TYPE_P2P_INDEX].ucPsProfile); + *pu4QueryInfoLen = sizeof(PARAM_POWER_MODE); + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to set the power save profile. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetP2pPowerSaveProfile ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + WLAN_STATUS status; + PARAM_POWER_MODE ePowerMode; + DEBUGFUNC("wlanoidSetP2pPowerSaveProfile"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_POWER_MODE); + if (u4SetBufferLen < sizeof(PARAM_POWER_MODE)) { + DBGLOG(REQ, WARN, ("Invalid length %ld\n", u4SetBufferLen)); + return WLAN_STATUS_INVALID_LENGTH; + } + else if (*(PPARAM_POWER_MODE) pvSetBuffer >= Param_PowerModeMax) { + WARNLOG(("Invalid power mode %d\n", + *(PPARAM_POWER_MODE) pvSetBuffer)); + return WLAN_STATUS_INVALID_DATA; + } + + ePowerMode = *(PPARAM_POWER_MODE) pvSetBuffer; + + if (prAdapter->fgEnCtiaPowerMode) { + if (ePowerMode == Param_PowerModeCAM) { + + } else { + // User setting to PS mode (Param_PowerModeMAX_PSP or Param_PowerModeFast_PSP) + + if (prAdapter->u4CtiaPowerMode == 0) { + // force to keep in CAM mode + ePowerMode = Param_PowerModeCAM; + } else if (prAdapter->u4CtiaPowerMode == 1) { + ePowerMode = Param_PowerModeMAX_PSP; + } else if (prAdapter->u4CtiaPowerMode == 2) { + ePowerMode = Param_PowerModeFast_PSP; + } + } + } + + status = nicConfigPowerSaveProfile( + prAdapter, + NETWORK_TYPE_P2P_INDEX, + ePowerMode, + TRUE); + return status; +} /* end of wlanoidSetP2pPowerSaveProfile() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to set the power save profile. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetP2pSetNetworkAddress ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 i, j; + P_CMD_SET_NETWORK_ADDRESS_LIST prCmdNetworkAddressList; + P_PARAM_NETWORK_ADDRESS_LIST prNetworkAddressList = (P_PARAM_NETWORK_ADDRESS_LIST)pvSetBuffer; + P_PARAM_NETWORK_ADDRESS prNetworkAddress; + P_PARAM_NETWORK_ADDRESS_IP prNetAddrIp; + UINT_32 u4IpAddressCount, u4CmdSize; + PUINT_8 pucBuf = (PUINT_8)pvSetBuffer; + + DEBUGFUNC("wlanoidSetP2pSetNetworkAddress"); + DBGLOG(INIT, TRACE, ("\n")); + printk("wlanoidSetP2pSetNetworkAddress (%d)\n", (INT_16)u4SetBufferLen); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = 4; + + if (u4SetBufferLen < sizeof(PARAM_NETWORK_ADDRESS_LIST)) { + return WLAN_STATUS_INVALID_DATA; + } + + *pu4SetInfoLen = 0; + u4IpAddressCount = 0; + + prNetworkAddress = prNetworkAddressList->arAddress; + for ( i = 0 ; i < prNetworkAddressList->u4AddressCount ; i++) { + if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && + prNetworkAddress->u2AddressLength == sizeof(PARAM_NETWORK_ADDRESS_IP)) { + u4IpAddressCount++; + } + + prNetworkAddress = (P_PARAM_NETWORK_ADDRESS) ((UINT_32) prNetworkAddress + + (UINT_32) (prNetworkAddress->u2AddressLength + OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress))); + } + + // construct payload of command packet + u4CmdSize = OFFSET_OF(CMD_SET_NETWORK_ADDRESS_LIST, arNetAddress) + + sizeof(IPV4_NETWORK_ADDRESS) * u4IpAddressCount; + + if (u4IpAddressCount == 0) { + u4CmdSize = sizeof(CMD_SET_NETWORK_ADDRESS_LIST); + } + + prCmdNetworkAddressList = (P_CMD_SET_NETWORK_ADDRESS_LIST) kalMemAlloc(u4CmdSize, VIR_MEM_TYPE); + + if(prCmdNetworkAddressList == NULL) + return WLAN_STATUS_FAILURE; + + // fill P_CMD_SET_NETWORK_ADDRESS_LIST + prCmdNetworkAddressList->ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; + + /* only to set IP address to FW once ARP filter is enabled */ + if (prAdapter->fgEnArpFilter) { + prCmdNetworkAddressList->ucAddressCount = (UINT_8)u4IpAddressCount; + prNetworkAddress = prNetworkAddressList->arAddress; + + printk("u4IpAddressCount (%ld) \n", (INT_32)u4IpAddressCount); + for (i = 0, j = 0 ; i < prNetworkAddressList->u4AddressCount ; i++) { + if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && + prNetworkAddress->u2AddressLength == sizeof(PARAM_NETWORK_ADDRESS_IP)) { + prNetAddrIp = (P_PARAM_NETWORK_ADDRESS_IP)prNetworkAddress->aucAddress; + + kalMemCopy(prCmdNetworkAddressList->arNetAddress[j].aucIpAddr, + &(prNetAddrIp->in_addr), + sizeof(UINT_32)); + + j++; + + pucBuf = (PUINT_8)&prNetAddrIp->in_addr; + printk("prNetAddrIp->in_addr:%d:%d:%d:%d\n", (UINT_8)pucBuf[0], (UINT_8)pucBuf[1], (UINT_8)pucBuf[2], (UINT_8)pucBuf[3]); + } + + prNetworkAddress = (P_PARAM_NETWORK_ADDRESS) ((UINT_32) prNetworkAddress + + (UINT_32) (prNetworkAddress->u2AddressLength + OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress))); + } + + } else { + prCmdNetworkAddressList->ucAddressCount = 0; + } + + rStatus = wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_IP_ADDRESS, + TRUE, + FALSE, + TRUE, + nicCmdEventSetIpAddress, + nicOidCmdTimeoutCommon, + u4CmdSize, + (PUINT_8)prCmdNetworkAddressList, + pvSetBuffer, + u4SetBufferLen + ); + + kalMemFree(prCmdNetworkAddressList, VIR_MEM_TYPE, u4CmdSize); + return rStatus; +} /* end of wlanoidSetP2pSetNetworkAddress() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set Multicast Address List. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_MULTICAST_FULL +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetP2PMulticastList( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + CMD_MAC_MCAST_ADDR rCmdMacMcastAddr; + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + /* The data must be a multiple of the Ethernet address size. */ + if ((u4SetBufferLen % MAC_ADDR_LEN)) { + DBGLOG(REQ, WARN, ("Invalid MC list length %ld\n", u4SetBufferLen)); + + *pu4SetInfoLen = (((u4SetBufferLen + MAC_ADDR_LEN) - 1) / + MAC_ADDR_LEN) * MAC_ADDR_LEN; + + return WLAN_STATUS_INVALID_LENGTH; + } + + *pu4SetInfoLen = u4SetBufferLen; + + /* Verify if we can support so many multicast addresses. */ + if ((u4SetBufferLen / MAC_ADDR_LEN) > MAX_NUM_GROUP_ADDR) { + DBGLOG(REQ, WARN, ("Too many MC addresses\n")); + + return WLAN_STATUS_MULTICAST_FULL; + } + + /* NOTE(Kevin): Windows may set u4SetBufferLen == 0 && + * pvSetBuffer == NULL to clear exist Multicast List. + */ + if (u4SetBufferLen) { + ASSERT(pvSetBuffer); + } + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in set multicast list! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + rCmdMacMcastAddr.u4NumOfGroupAddr = u4SetBufferLen / MAC_ADDR_LEN; + rCmdMacMcastAddr.ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; + kalMemCopy(rCmdMacMcastAddr.arAddress, pvSetBuffer, u4SetBufferLen); + + return wlanoidSendSetQueryP2PCmd(prAdapter, + CMD_ID_MAC_MCAST_ADDR, + TRUE, + FALSE, + FALSE, // This CMD response is no need to complete the OID. Or the event would unsync. + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_MAC_MCAST_ADDR), + (PUINT_8)&rCmdMacMcastAddr, + pvSetBuffer, + u4SetBufferLen + ); + +} /* end of wlanoidSetP2PMulticastList() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to send GAS frame for P2P Service Discovery Request +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_MULTICAST_FULL +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSendP2PSDRequest( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen) { + ASSERT(pvSetBuffer); + } + + if (u4SetBufferLen < sizeof(PARAM_P2P_SEND_SD_REQUEST)) { + *pu4SetInfoLen = sizeof(PARAM_P2P_SEND_SD_REQUEST); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + +// rWlanStatus = p2pFsmRunEventSDRequest(prAdapter, (P_PARAM_P2P_SEND_SD_REQUEST)pvSetBuffer); + + return rWlanStatus; +} /* end of wlanoidSendP2PSDRequest() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to send GAS frame for P2P Service Discovery Response +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_MULTICAST_FULL +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSendP2PSDResponse( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen) { + ASSERT(pvSetBuffer); + } + + if (u4SetBufferLen < sizeof(PARAM_P2P_SEND_SD_RESPONSE)) { + *pu4SetInfoLen = sizeof(PARAM_P2P_SEND_SD_RESPONSE); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + +// rWlanStatus = p2pFsmRunEventSDResponse(prAdapter, (P_PARAM_P2P_SEND_SD_RESPONSE)pvSetBuffer); + + return rWlanStatus; +} /* end of wlanoidGetP2PSDRequest() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to get GAS frame for P2P Service Discovery Request +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_MULTICAST_FULL +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidGetP2PSDRequest( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + PUINT_8 pucPacketBuffer = NULL, pucTA = NULL; +// PUINT_8 pucChannelNum = NULL; + PUINT_16 pu2PacketLength = NULL; + P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T)NULL; + UINT_8 ucVersionNum = 0; +// UINT_8 ucChannelNum = 0, ucSeqNum = 0; + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + if (u4QueryBufferLen < sizeof(PARAM_P2P_GET_SD_REQUEST)) { + *pu4QueryInfoLen = sizeof(PARAM_P2P_GET_SD_REQUEST); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + DBGLOG(P2P, TRACE, ("Get Service Discovery Request\n")); +#if 0 + if ((ucVersionNum = p2pFuncGetVersionNumOfSD(prAdapter)) == 0) { + P_PARAM_P2P_GET_SD_REQUEST prP2pGetSdReq = (P_PARAM_P2P_GET_SD_REQUEST)pvQueryBuffer; + + pucPacketBuffer = prP2pGetSdReq->aucPacketContent; + pu2PacketLength = &prP2pGetSdReq->u2PacketLength; + pucTA = &prP2pGetSdReq->rTransmitterAddr; + } + else { + P_PARAM_P2P_GET_SD_REQUEST_EX prP2pGetSdReqEx = (P_PARAM_P2P_GET_SD_REQUEST_EX)NULL; + + prP2pGetSdReqEx = (P_PARAM_P2P_GET_SD_REQUEST)pvQueryBuffer; + pucPacketBuffer = prP2pGetSdReqEx->aucPacketContent; + pu2PacketLength = &prP2pGetSdReqEx->u2PacketLength; + pucTA = &prP2pGetSdReqEx->rTransmitterAddr; + pucChannelNum = &prP2pGetSdReqEx->ucChannelNum; + ucSeqNum = prP2pGetSdReqEx->ucSeqNum; + } + + + rWlanStatus = p2pFuncGetServiceDiscoveryFrame(prAdapter, + pucPacketBuffer, + (u4QueryBufferLen - sizeof(PARAM_P2P_GET_SD_REQUEST)), + (PUINT_32)pu2PacketLength, + pucChannelNum, + ucSeqNum); +#else + *pu4QueryInfoLen = 0; + return rWlanStatus; +#endif + + prWlanHdr = (P_WLAN_MAC_HEADER_T)pucPacketBuffer; + + kalMemCopy(pucTA, prWlanHdr->aucAddr2, MAC_ADDR_LEN); + + if (pu4QueryInfoLen) { + if (ucVersionNum == 0) { + *pu4QueryInfoLen = (UINT_32)(sizeof(PARAM_P2P_GET_SD_REQUEST) + (*pu2PacketLength)); + } + else { + *pu4QueryInfoLen = (UINT_32)(sizeof(PARAM_P2P_GET_SD_REQUEST_EX) + (*pu2PacketLength)); + } + + } + + return rWlanStatus; +} /* end of wlanoidGetP2PSDRequest() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to get GAS frame for P2P Service Discovery Response +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_MULTICAST_FULL +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidGetP2PSDResponse( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T)NULL; + //UINT_8 ucSeqNum = 0, + UINT_8 ucVersionNum = 0; + PUINT_8 pucPacketContent = (PUINT_8)NULL, pucTA = (PUINT_8)NULL; + PUINT_16 pu2PacketLength = (PUINT_16)NULL; + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + if (u4QueryBufferLen < sizeof(PARAM_P2P_GET_SD_RESPONSE)) { + *pu4QueryInfoLen = sizeof(PARAM_P2P_GET_SD_RESPONSE); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + DBGLOG(P2P, TRACE, ("Get Service Discovery Response\n")); + +#if 0 + if ((ucVersionNum = p2pFuncGetVersionNumOfSD(prAdapter)) == 0) { + P_PARAM_P2P_GET_SD_RESPONSE prP2pGetSdRsp = (P_PARAM_P2P_GET_SD_RESPONSE)NULL; + + prP2pGetSdRsp = (P_PARAM_P2P_GET_SD_REQUEST)pvQueryBuffer; + pucPacketContent = prP2pGetSdRsp->aucPacketContent; + pucTA = &prP2pGetSdRsp->rTransmitterAddr; + pu2PacketLength = &prP2pGetSdRsp->u2PacketLength; + } + else { + P_PARAM_P2P_GET_SD_RESPONSE_EX prP2pGetSdRspEx = (P_PARAM_P2P_GET_SD_RESPONSE_EX)NULL; + + prP2pGetSdRspEx = (P_PARAM_P2P_GET_SD_RESPONSE_EX)pvQueryBuffer; + pucPacketContent = prP2pGetSdRspEx->aucPacketContent; + pucTA = &prP2pGetSdRspEx->rTransmitterAddr; + pu2PacketLength = &prP2pGetSdRspEx->u2PacketLength; + ucSeqNum = prP2pGetSdRspEx->ucSeqNum; + } + + +// rWlanStatus = p2pFuncGetServiceDiscoveryFrame(prAdapter, +// pucPacketContent, +// (u4QueryBufferLen - sizeof(PARAM_P2P_GET_SD_RESPONSE)), +// (PUINT_32)pu2PacketLength, +// NULL, +// ucSeqNum); +#else + *pu4QueryInfoLen = 0; + return rWlanStatus; +#endif + prWlanHdr = (P_WLAN_MAC_HEADER_T)pucPacketContent; + + kalMemCopy(pucTA, prWlanHdr->aucAddr2, MAC_ADDR_LEN); + + + if (pu4QueryInfoLen) { + if (ucVersionNum == 0) { + *pu4QueryInfoLen = (UINT_32)(sizeof(PARAM_P2P_GET_SD_RESPONSE) + *pu2PacketLength); + } + else { + *pu4QueryInfoLen = (UINT_32)(sizeof(PARAM_P2P_GET_SD_RESPONSE_EX) + *pu2PacketLength); + } + } + + return rWlanStatus; +} /* end of wlanoidGetP2PSDResponse() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to terminate P2P Service Discovery Phase +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_MULTICAST_FULL +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetP2PTerminateSDPhase( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + P_PARAM_P2P_TERMINATE_SD_PHASE prP2pTerminateSD = (P_PARAM_P2P_TERMINATE_SD_PHASE)NULL; + UINT_8 aucNullAddr[] = NULL_MAC_ADDR; + + do { + if ((prAdapter == NULL) || (pu4SetInfoLen == NULL)) { + break; + } + + + if ((u4SetBufferLen) && (pvSetBuffer == NULL)) { + break; + } + + if (u4SetBufferLen < sizeof(PARAM_P2P_TERMINATE_SD_PHASE)) { + *pu4SetInfoLen = sizeof(PARAM_P2P_TERMINATE_SD_PHASE); + rWlanStatus = WLAN_STATUS_BUFFER_TOO_SHORT; + break; + } + + prP2pTerminateSD = (P_PARAM_P2P_TERMINATE_SD_PHASE)pvSetBuffer; + + if (EQUAL_MAC_ADDR(prP2pTerminateSD->rPeerAddr, aucNullAddr)) { + DBGLOG(P2P, TRACE, ("Service Discovery Version 2.0\n")); +// p2pFuncSetVersionNumOfSD(prAdapter, 2); + } + + //rWlanStatus = p2pFsmRunEventSDAbort(prAdapter); + + } while (FALSE); + + + + + + return rWlanStatus; +} /* end of wlanoidSetP2PTerminateSDPhase() */ + + +#if CFG_SUPPORT_ANTI_PIRACY +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_MULTICAST_FULL +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetSecCheckRequest( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen) { + ASSERT(pvSetBuffer); + } + + return wlanoidSendSetQueryP2PCmd(prAdapter, + CMD_ID_SEC_CHECK, + FALSE, + TRUE, + TRUE, + NULL, + nicOidCmdTimeoutCommon, + u4SetBufferLen, + (PUINT_8)pvSetBuffer, + pvSetBuffer, + u4SetBufferLen + ); + +} /* end of wlanoidSetSecCheckRequest() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_MULTICAST_FULL +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidGetSecCheckResponse( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + //P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T)NULL; + P_GLUE_INFO_T prGlueInfo; + + prGlueInfo = prAdapter->prGlueInfo; + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + if (u4QueryBufferLen > 256) { + u4QueryBufferLen = 256; + } + + *pu4QueryInfoLen = u4QueryBufferLen; + + #if DBG + DBGLOG_MEM8(SEC, LOUD, prGlueInfo->prP2PInfo->aucSecCheckRsp, u4QueryBufferLen); + #endif + kalMemCopy((PUINT_8)(pvQueryBuffer + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer)), prGlueInfo->prP2PInfo->aucSecCheckRsp, u4QueryBufferLen); + + return rWlanStatus; +} /* end of wlanoidGetSecCheckResponse() */ +#endif + +WLAN_STATUS +wlanoidSetNoaParam ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_PARAM_CUSTOM_NOA_PARAM_STRUC_T prNoaParam; + CMD_CUSTOM_NOA_PARAM_STRUC_T rCmdNoaParam; + + DEBUGFUNC("wlanoidSetNoaParam"); + DBGLOG(INIT, TRACE,("\n")); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_NOA_PARAM_STRUC_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_NOA_PARAM_STRUC_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prNoaParam = (P_PARAM_CUSTOM_NOA_PARAM_STRUC_T)pvSetBuffer; + + kalMemZero(&rCmdNoaParam, sizeof(CMD_CUSTOM_NOA_PARAM_STRUC_T)); + rCmdNoaParam.u4NoaDurationMs = prNoaParam->u4NoaDurationMs; + rCmdNoaParam.u4NoaIntervalMs = prNoaParam->u4NoaIntervalMs; + rCmdNoaParam.u4NoaCount = prNoaParam->u4NoaCount; + +#if 0 + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_NOA_PARAM, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_CUSTOM_NOA_PARAM_STRUC_T), + (PUINT_8)&rCmdNoaParam, + pvSetBuffer, + u4SetBufferLen + ); +#else + return wlanoidSendSetQueryP2PCmd(prAdapter, + CMD_ID_SET_NOA_PARAM, + TRUE, + FALSE, + TRUE, + NULL, + nicOidCmdTimeoutCommon, + sizeof(CMD_CUSTOM_NOA_PARAM_STRUC_T), + (PUINT_8)&rCmdNoaParam, + pvSetBuffer, + u4SetBufferLen + ); + +#endif + +} + +WLAN_STATUS +wlanoidSetOppPsParam ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_PARAM_CUSTOM_OPPPS_PARAM_STRUC_T prOppPsParam; + CMD_CUSTOM_OPPPS_PARAM_STRUC_T rCmdOppPsParam; + + DEBUGFUNC("wlanoidSetOppPsParam"); + DBGLOG(INIT, TRACE,("\n")); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_OPPPS_PARAM_STRUC_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_OPPPS_PARAM_STRUC_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prOppPsParam = (P_PARAM_CUSTOM_OPPPS_PARAM_STRUC_T)pvSetBuffer; + + kalMemZero(&rCmdOppPsParam, sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUC_T)); + rCmdOppPsParam.u4CTwindowMs = prOppPsParam->u4CTwindowMs; + +#if 0 + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_OPPPS_PARAM, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUC_T), + (PUINT_8)&rCmdOppPsParam, + pvSetBuffer, + u4SetBufferLen + ); +#else + return wlanoidSendSetQueryP2PCmd(prAdapter, + CMD_ID_SET_NOA_PARAM, + TRUE, + FALSE, + TRUE, + NULL, + nicOidCmdTimeoutCommon, + sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUC_T), + (PUINT_8)&rCmdOppPsParam, + pvSetBuffer, + u4SetBufferLen + ); + +#endif + +} + +WLAN_STATUS +wlanoidSetUApsdParam ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_PARAM_CUSTOM_UAPSD_PARAM_STRUC_T prUapsdParam; + CMD_CUSTOM_UAPSD_PARAM_STRUC_T rCmdUapsdParam; + P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo; + P_BSS_INFO_T prBssInfo; + + + DEBUGFUNC("wlanoidSetUApsdParam"); + DBGLOG(INIT, TRACE,("\n")); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_UAPSD_PARAM_STRUC_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_UAPSD_PARAM_STRUC_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; + + prUapsdParam = (P_PARAM_CUSTOM_UAPSD_PARAM_STRUC_T)pvSetBuffer; + + kalMemZero(&rCmdUapsdParam, sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUC_T)); + rCmdUapsdParam.fgEnAPSD = prUapsdParam->fgEnAPSD; + prAdapter->rWifiVar.fgSupportUAPSD = prUapsdParam->fgEnAPSD; + + rCmdUapsdParam.fgEnAPSD_AcBe = prUapsdParam->fgEnAPSD_AcBe; + rCmdUapsdParam.fgEnAPSD_AcBk = prUapsdParam->fgEnAPSD_AcBk; + rCmdUapsdParam.fgEnAPSD_AcVo = prUapsdParam->fgEnAPSD_AcVo; + rCmdUapsdParam.fgEnAPSD_AcVi = prUapsdParam->fgEnAPSD_AcVi; + prPmProfSetupInfo->ucBmpDeliveryAC = + ((prUapsdParam->fgEnAPSD_AcBe << 0) | + (prUapsdParam->fgEnAPSD_AcBk << 1) | + (prUapsdParam->fgEnAPSD_AcVi << 2) | + (prUapsdParam->fgEnAPSD_AcVo << 3)); + prPmProfSetupInfo->ucBmpTriggerAC = + ((prUapsdParam->fgEnAPSD_AcBe << 0) | + (prUapsdParam->fgEnAPSD_AcBk << 1) | + (prUapsdParam->fgEnAPSD_AcVi << 2) | + (prUapsdParam->fgEnAPSD_AcVo << 3)); + + rCmdUapsdParam.ucMaxSpLen = prUapsdParam->ucMaxSpLen; + prPmProfSetupInfo->ucUapsdSp = prUapsdParam->ucMaxSpLen; + +#if 0 + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_UAPSD_PARAM, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUC_T), + (PUINT_8)&rCmdUapsdParam, + pvSetBuffer, + u4SetBufferLen + ); + #else + return wlanoidSendSetQueryP2PCmd(prAdapter, + CMD_ID_SET_UAPSD_PARAM, + TRUE, + FALSE, + TRUE, + NULL, + nicOidCmdTimeoutCommon, + sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUC_T), + (PUINT_8)&rCmdUapsdParam, + pvSetBuffer, + u4SetBufferLen + ); + +#endif +} + + + +WLAN_STATUS +wlanoidQueryP2pOpChannel ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + + WLAN_STATUS rResult = WLAN_STATUS_FAILURE; +// PUINT_8 pucOpChnl = (PUINT_8)pvQueryBuffer; + + do { + if ((prAdapter == NULL) || (pu4QueryInfoLen == NULL)) { + break; + } + + + if ((u4QueryBufferLen) && (pvQueryBuffer == NULL)) { + break; + } + + if (u4QueryBufferLen < sizeof(UINT_8)) { + *pu4QueryInfoLen = sizeof(UINT_8); + rResult = WLAN_STATUS_BUFFER_TOO_SHORT; + break; + } + +#if 0 + if (!p2pFuncGetCurrentOpChnl(prAdapter, pucOpChnl)) { + rResult = WLAN_STATUS_INVALID_DATA; + break; + } +#else + rResult = WLAN_STATUS_INVALID_DATA; + break; +#endif + + *pu4QueryInfoLen = sizeof(UINT_8); + rResult = WLAN_STATUS_SUCCESS; + + } while (FALSE); + + return rResult; +} /* wlanoidQueryP2pOpChannel */ + +WLAN_STATUS +wlanoidQueryP2pVersion ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + WLAN_STATUS rResult = WLAN_STATUS_FAILURE; +// PUINT_8 pucVersionNum = (PUINT_8)pvQueryBuffer; + + do { + if ((prAdapter == NULL) || (pu4QueryInfoLen == NULL)) { + break; + } + + + if ((u4QueryBufferLen) && (pvQueryBuffer == NULL)) { + break; + } + + if (u4QueryBufferLen < sizeof(UINT_8)) { + *pu4QueryInfoLen = sizeof(UINT_8); + rResult = WLAN_STATUS_BUFFER_TOO_SHORT; + break; + } + + } while (FALSE); + + return rResult; +} /* wlanoidQueryP2pVersion */ + +WLAN_STATUS +wlanoidSetP2pSupplicantVersion ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + WLAN_STATUS rResult = WLAN_STATUS_FAILURE; + UINT_8 ucVersionNum; + + do { + if ((prAdapter == NULL) || (pu4SetInfoLen == NULL)) { + + rResult = WLAN_STATUS_INVALID_DATA; + break; + } + + if ((u4SetBufferLen) && (pvSetBuffer == NULL)) { + rResult = WLAN_STATUS_INVALID_DATA; + break; + } + + *pu4SetInfoLen = sizeof(UINT_8); + + if (u4SetBufferLen < sizeof(UINT_8)) { + rResult = WLAN_STATUS_INVALID_LENGTH; + break; + } + + + ucVersionNum = *((PUINT_8)pvSetBuffer); + + + rResult = WLAN_STATUS_SUCCESS; + } while (FALSE); + + return rResult; +} /* wlanoidSetP2pSupplicantVersion */ + +#if CFG_SUPPORT_P2P_RSSI_QUERY +WLAN_STATUS +wlanoidQueryP2pRssi ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryP2pRssi"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(PARAM_RSSI); + + /* Check for query buffer length */ + if (u4QueryBufferLen < *pu4QueryInfoLen) { + DBGLOG(REQ, WARN, ("Too short length %ld\n", u4QueryBufferLen)); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + if (prAdapter->fgIsP2pLinkQualityValid == TRUE && + (kalGetTimeTick() - prAdapter->rP2pLinkQualityUpdateTime) <= CFG_LINK_QUALITY_VALID_PERIOD) { + PARAM_RSSI rRssi; + + rRssi = (PARAM_RSSI)prAdapter->rP2pLinkQuality.cRssi; // ranged from (-128 ~ 30) in unit of dBm + + if(rRssi > PARAM_WHQL_RSSI_MAX_DBM) + rRssi = PARAM_WHQL_RSSI_MAX_DBM; + else if(rRssi < PARAM_WHQL_RSSI_MIN_DBM) + rRssi = PARAM_WHQL_RSSI_MIN_DBM; + + kalMemCopy(pvQueryBuffer, &rRssi, sizeof(PARAM_RSSI)); + return WLAN_STATUS_SUCCESS; + } + + #ifdef LINUX + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_LINK_QUALITY, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryLinkQuality, + nicOidCmdTimeoutCommon, + *pu4QueryInfoLen, + pvQueryBuffer, + pvQueryBuffer, + u4QueryBufferLen + ); + #else + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_LINK_QUALITY, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryLinkQuality, + nicOidCmdTimeoutCommon, + 0, + NULL, + pvQueryBuffer, + u4QueryBufferLen + ); + + #endif +} /* wlanoidQueryP2pRssi */ +#endif + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_assoc.h b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_assoc.h new file mode 100755 index 000000000000..17450b6965a0 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_assoc.h @@ -0,0 +1,104 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/WIFI_P2P_DRIVER_V2_2/include/mgmt/p2p_assoc.h#1 $ +*/ + +/*! \file p2p_assoc.h + \brief This file contains the Wi-Fi Direct ASSOC REQ/RESP of + IEEE 802.11 family for MediaTek 802.11 Wireless LAN Adapters. +*/ + + +/******************************************************************************* +* Copyright (c) 2010 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +#ifndef _P2P_ASSOC_H +#define _P2P_ASSOC_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +PUINT_8 +p2pBuildReAssocReqFrameCommonIEs ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN PUINT_8 pucBuffer + ); + + +#endif diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_bss.h b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_bss.h new file mode 100755 index 000000000000..c32740e66d0f --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_bss.h @@ -0,0 +1,105 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/WIFI_P2P_DRIVER_V2_2/include/mgmt/p2p_bss.h#1 $ +*/ + +/*! \file "p2p_bss.h" + \brief In this file we define the function prototype used in p2p BSS/IBSS. + + The file contains the function declarations and defines for used in BSS/IBSS. +*/ + + +/******************************************************************************* +* Copyright (c) 2010 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + + +#ifndef _P2P_BSS_H +#define _P2P_BSS_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +UINT_32 +p2pGetTxProbRspIeTableSize( + VOID + ); + +#endif + diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_fsm.h b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_fsm.h new file mode 100755 index 000000000000..d658dc8a973d --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_fsm.h @@ -0,0 +1,2664 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/WIFI_P2P_DRIVER_V2_2/include/mgmt/p2p_fsm.h#11 $ +*/ + +/*! \file p2p_fsm.h + \brief Declaration of functions and finite state machine for P2P Module. + + Declaration of functions and finite state machine for P2P Module. +*/ + +/******************************************************************************* +* Copyright (c) 2010 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: p2p_fsm.h $ + * + * 02 24 2012 yuche.tsai + * [ALPS00240756] [WiFi direct]After accept PBC request,DVT pops Kernel Defect.Powering off DVT causes DVT reboots automatcially and pops up KE(once) + * Fix GO dissolving issue to avoid FW assert. + * + * 02 22 2012 yuche.tsai + * [ALPS00240483] [Wifi P2P]Run Sigma tool of A69. Always run fail on 5.1.2. No get correct connection from Realtek. + * Fix assoc response without P2P IE issue for Sigma test. + * + * 02 14 2012 yuche.tsai + * [ALPS00118350] [ALPS.ICS][WiFi Direct] Dirver update for wifi direct connection + * Replace Beacon/Probe Response IE by driver generating instead of from supplicant. + * + * 01 27 2012 yuche.tsai + * NULL + * Update for GC connection . + * + * 01 18 2012 yuche.tsai + * NULL + * Add get station info API. + * TX deauth before start beacon. + * + * 01 17 2012 yuche.tsai + * NULL + * Update mgmt frame filter setting. + * Please also update FW 2.1 + * + * 01 16 2012 yuche.tsai + * NULL + * Update Driver for wifi driect gc join IE update issue. + * + * 01 16 2012 yuche.tsai + * NULL + * Add join timer. + * + * 01 16 2012 yuche.tsai + * NULL + * Update P2P driver code for GC Join. + * + * 01 15 2012 yuche.tsai + * NULL + * ICS P2P Driver Update. + * + * 01 15 2012 yuche.tsai + * NULL + * Fix scan bug. + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Direct Driver Update for ICS. + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Hot Spot Tethering for ICS ALPHA testing version. + * + * 12 02 2011 yuche.tsai + * NULL + * Resolve class 3 error issue under AP mode. + * + * data frame may TX before Assoc Response TX. + * + * 11 11 2011 yuche.tsai + * NULL + * Fix work thread cancel issue. + * + * 11 11 2011 yuche.tsai + * NULL + * Fix default device name issue. + * + * 11 09 2011 yuche.tsai + * [WCXRP00001093] [Need Patch][Volunteer Patch] Service Discovery 2.0 state transition issue. + * Fix SD2.0 issue which may cause KE. (Monkey test) + * + * 11 08 2011 yuche.tsai + * [WCXRP00001094] [Volunteer Patch][Driver] Driver version & supplicant version query & set support for service discovery version check. + * Add support for driver version query & p2p supplicant verseion set. + * For new service discovery mechanism sync. + * + * 10 18 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Support Channle Query. + * + * 10 18 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * New 2.1 branch + + * + * 09 01 2011 yuche.tsai + * NULL + * Fix channel stay interval. + * Sync channel stay interval & channel request interval under AP mode.. + * + * 08 30 2011 yuche.tsai + * [WCXRP00000953] [Volunteer Patch][Driver] Hot Spot Channel ASSERT issue. + * Fix hot spot FW assert issue when under concurrent case. (DBG enable only) + * + * 08 16 2011 cp.wu + * [WCXRP00000934] [MT6620 Wi-Fi][Driver][P2P] Wi-Fi hot spot with auto sparse channel residence + * auto channel decision for 2.4GHz hot spot mode + * + * 08 16 2011 yuche.tsai + * NULL + * Fix scan policy for Active LISTEN scan. + * + * 08 09 2011 yuche.tsai + * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. + * Invitation Feature add on. + * + * 08 02 2011 yuche.tsai + * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, TX deauth to a disconnecting device issue. + * Support TX Deauth Issue. + * + * 07 26 2011 yuche.tsai + * [WCXRP00000875] [Volunteer Patch][WiFi Direct][Driver] MT6620 IOT issue with realtek test bed solution. + * Turn off persistent group support for V2.0 release. + * + * 07 18 2011 yuche.tsai + * [WCXRP00000856] [Volunteer Patch][WiFi Direct][Driver] MT6620 WiFi Direct IOT Issue with BCM solution. + * Fix compile error. + * + * 07 18 2011 yuche.tsai + * [WCXRP00000856] [Volunteer Patch][WiFi Direct][Driver] MT6620 WiFi Direct IOT Issue with BCM solution. + * Fix MT6620 WiFi Direct IOT Issue with BCM solution. + * + * 07 11 2011 yuche.tsai + * [WCXRP00000845] [Volunteer Patch][WiFi Direct] WiFi Direct Device Connection Robustness + * Enhance Connection Robustness. + * + * 07 08 2011 yuche.tsai + * [WCXRP00000841] [Volunteer Patch][WiFi Direct] Group Owner Setting. + * Update GO configure parameter. + * + * 07 05 2011 yuche.tsai + * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue + * Disable enhancement II for debugging. + * + * 07 05 2011 yuche.tsai + * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue + * Refine compile flag. + * + * 07 05 2011 yuche.tsai + * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue + * Add WiFi Direct Connection Enhancement. + * + * 06 20 2011 yuche.tsai + * [WCXRP00000799] [Volunteer Patch][MT6620][Driver] Connection Indication Twice Issue. + * Fix connection indication twice issue. + * + * 06 07 2011 yuche.tsai + * [WCXRP00000763] [Volunteer Patch][MT6620][Driver] RX Service Discovery Frame under AP mode Issue + * Fix RX SD request under AP mode issue. + * + * 05 04 2011 yuche.tsai + * NULL + * Support partial persistent group function. + * + * 04 20 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove CFG_WIFI_DIRECT_MOVED. + * + * 04 10 2011 yuche.tsai + * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. + * Add device discoverability support. (Phase I) + * + * 03 25 2011 yuche.tsai + * NULL + * Improve some error handleing. + * + * 03 22 2011 george.huang + * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command + * link with supplicant commands + * + * 03 22 2011 yuche.tsai + * NULL + * 1. Fix formation policy issue. + * 2. Fix LISTEN channel issue. + * 3. Fix Target IF address in-correct issue when being GO. + * + * 03 21 2011 yuche.tsai + * NULL + * Connection Flow Modification. + * + * 03 19 2011 terry.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 p2p driver release based on label "MT6620_WIFI_P2P_DRIVER_V2_0_2100_0319_2011" from main trunk. + * + * 03 19 2011 yuche.tsai + * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. + * Add beacon timeout support. + * + * 03 19 2011 yuche.tsai + * [WCXRP00000581] [Volunteer Patch][MT6620][Driver] P2P IE in Assoc Req Issue + * Append P2P IE in Assoc Req, so that GC can be discovered in probe response of GO. + * + * 03 18 2011 yuche.tsai + * [WCXRP00000574] [Volunteer Patch][MT6620][Driver] Modify P2P FSM Connection Flow + * Modify connection flow after Group Formation Complete, or device connect to a GO. + * Instead of request channel & connect directly, we use scan to allocate channel bandwidth & connect after RX BCN. + * + * 03 15 2011 yuche.tsai + * [WCXRP00000560] [Volunteer Patch][MT6620][Driver] P2P Connection from UI using KEY/DISPLAY issue + * Fix some configure method issue. + * + * 03 10 2011 yuche.tsai + * NULL + * Add P2P API. + * + * 03 07 2011 yuche.tsai + * [WCXRP00000502] [Volunteer Patch][MT6620][Driver] Fix group ID issue when doing Group Formation. + * . + * + * 03 07 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * rename the define to anti_pviracy. + * + * 03 05 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * add the code to get the check rsponse and indicate to app. + * + * 03 01 2011 yuche.tsai + * [WCXRP00000501] [Volunteer Patch][MT6620][Driver] No common channel issue when doing GO formation + * Update channel issue when doing GO formation.. + * + * 03 01 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Update Service Discovery Related wlanoid function. + * + * 02 18 2011 wh.su + * [WCXRP00000471] [MT6620 Wi-Fi][Driver] Add P2P Provison discovery append Config Method attribute at WSC IE + * fixed the ioctl setting that index not map to spec defined config method. + * + * 02 18 2011 yuche.tsai + * [WCXRP00000480] [Volunteer Patch][MT6620][Driver] WCS IE format issue + * Fix WSC IE BE format issue. + * + * 02 17 2011 wh.su + * [WCXRP00000471] [MT6620 Wi-Fi][Driver] Add P2P Provison discovery append Config Method attribute at WSC IE + * append the WSC IE config method attribute at provision discovery request. + * + * 02 11 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Add two function prototype. + * + * 02 10 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Support Disassoc & Deauthentication for Hot-Spot. + * + * 02 09 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. + +2. Provision Discovery Request/Response + + * Add Service Discovery Indication Related code. + * + * 02 09 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Add Support for MLME deauthentication for Hot-Spot. + * + * 02 09 2011 yuche.tsai + * [WCXRP00000429] [Volunteer Patch][MT6620][Driver] Hot Spot Client Limit Issue + * Fix Client Limit Issue. + * + * 01 26 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. + +2. Provision Discovery Request/Response + + * Add Service Discovery Function. + * + * 01 25 2011 terry.wu + * [WCXRP00000393] [MT6620 Wi-Fi][Driver] Add new module insert parameter + * Add a new module parameter to indicate current runnig mode, P2P or AP. + * + * 01 19 2011 george.huang + * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability + * Null NOA attribute setting when no related parameters. + * + * 01 12 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Modify some behavior of AP mode. + * + * 12 22 2010 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Fix Compile Error. + * + * 12 15 2010 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Refine Connection Flow. + * + * 12 08 2010 yuche.tsai + * [WCXRP00000244] [MT6620][Driver] Add station record type for each client when in AP mode. + * Change STA Type under AP mode. We would tell if client is a P2P device or a legacy client by checking the P2P IE in assoc req frame. + * + * 12 02 2010 yuche.tsai + * NULL + * Update P2P Connection Policy for Invitation. + * + * 12 02 2010 yuche.tsai + * NULL + * Update P2P Connection Policy for Invitation & Provision Discovery. + * + * 11 30 2010 yuche.tsai + * NULL + * Invitation & Provision Discovery Indication. + * + * 11 30 2010 yuche.tsai + * NULL + * Update Configure Method indication & selection for Provision Discovery & GO_NEGO_REQ + * + * 11 29 2010 yuche.tsai + * NULL + * Update P2P related function for INVITATION & PROVISION DISCOVERY. + * + * 11 26 2010 george.huang + * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function + * Update P2P PS for NOA function. + * + * 11 25 2010 yuche.tsai + * NULL + * Update Code for Invitation Related Function. + * + * 11 17 2010 wh.su + * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID[WCXRP00000179] [MT6620 Wi-Fi][FW] Set the Tx lowest rate at wlan table for normal operation + * fixed some ASSERT check. + * + * 11 04 2010 wh.su + * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID + * adding the p2p random ssid support. + * + * 10 20 2010 wh.su + * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group + * Add the code to support disconnect p2p group + * + * 10 08 2010 wh.su + * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine + * update the frog's new p2p state machine. + * + * 10 04 2010 wh.su + * [WCXRP00000081] [MT6620][Driver] Fix the compiling error at WinXP while enable P2P + * fixed compiling error while enable p2p. + * + * 09 21 2010 kevin.huang + * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface + * Isolate P2P related function for Hardware Software Bundle + * + * 09 10 2010 wh.su + * NULL + * fixed the compiling error at WinXP. + * + * 09 07 2010 wh.su + * NULL + * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 26 2010 yuche.tsai + * NULL + * Add connection abort message event prototype. + * + * 08 20 2010 kevin.huang + * NULL + * Modify AAA Module for changing STA STATE 3 at p2p/bowRunEventAAAComplete() + * + * 08 16 2010 yuche.tsai + * NULL + * Fix P2P Intended Interface Address Bug. + * Extend GO Nego Timeout Time. + * + * 08 16 2010 yuche.tsai + * NULL + * Extend Listen Interval default value & remove deprecated variable. + * + * 08 16 2010 kevin.huang + * NULL + * Refine AAA functions + * + * 08 12 2010 kevin.huang + * NULL + * Refine bssProcessProbeRequest() and bssSendBeaconProbeResponse() + * + * 08 12 2010 yuche.tsai + * NULL + * Add function prototype for join complete. + * + * 08 11 2010 yuche.tsai + * NULL + * Add some function proto type for P2P FSM under provisioning phase.. + * + * 08 11 2010 yuche.tsai + * NULL + * Change P2P data structure for supporting + * 1. P2P Device discovery. + * 2. P2P Group Negotiation. + * 3. P2P JOIN + * + * 08 05 2010 yuche.tsai + * NULL + * Check-in P2P Device Discovery Feature. + * + * 08 03 2010 george.huang + * NULL + * handle event for updating NOA parameters indicated from FW + * + * 08 02 2010 yuche.tsai + * NULL + * P2P Group Negotiation Code Check in. + * + * 07 26 2010 yuche.tsai + * + * Update P2P FSM header file. + * + * 07 23 2010 cp.wu + * + * P2P/RSN/WAPI IEs need to be declared with compact structure. + * + * 07 21 2010 yuche.tsai + * + * Add for P2P Scan Result Parsing & Saving. + * + * 07 19 2010 yuche.tsai + * + * Update P2P FSM header file. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Fix some P2P function prototype. + * + * 06 17 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * First draft for migration P2P FSM from FW to Driver. + * + * 03 18 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Rename CFG flag for P2P + * + * 02 26 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Modify parameter of p2pStartGO + * + * 02 23 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add Wi-Fi Direct SSID and P2P GO Test Mode + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup +*/ + +#ifndef _P2P_FSM_H +#define _P2P_FSM_H + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +#define CID52_53_54 0 + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + + + + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_P2P_STATE_T { + P2P_STATE_IDLE = 0, + P2P_STATE_SCAN, + P2P_STATE_AP_CHANNEL_DETECT, + P2P_STATE_REQING_CHANNEL, + P2P_STATE_CHNL_ON_HAND, /* Requesting Channel to Send Specific Frame. */ + P2P_STATE_GC_JOIN, /* Sending Specific Frame. May extending channel by other event. */ + P2P_STATE_NUM +} ENUM_P2P_STATE_T, *P_ENUM_P2P_STATE_T; + + +typedef enum _ENUM_CHANNEL_REQ_TYPE_T { + CHANNEL_REQ_TYPE_REMAIN_ON_CHANNEL, + CHANNEL_REQ_TYPE_GC_JOIN_REQ, + CHANNEL_REQ_TYPE_GO_START_BSS +} +ENUM_CHANNEL_REQ_TYPE_T, *P_ENUM_CHANNEL_REQ_TYPE_T; + + +typedef struct _P2P_SSID_STRUCT_T { + UINT_8 aucSsid[32]; + UINT_8 ucSsidLen; +} P2P_SSID_STRUCT_T, *P_P2P_SSID_STRUCT_T; + +typedef struct _P2P_STATION_INFO_T { + UINT_32 u4InactiveTime; + UINT_32 u4RxBytes; // TODO: + UINT_32 u4TxBytes; // TODO: + UINT_32 u4RxPackets; // TODO: + UINT_32 u4TxPackets; // TODO: + // TODO: Add more for requirement. +} +P2P_STATION_INFO_T, *P_P2P_STATION_INFO_T; + + +/*-------------------- P2P FSM ACTION STRUCT ---------------------*/ +typedef struct _P2P_CHNL_REQ_INFO_T { + BOOLEAN fgIsChannelRequested; + UINT_8 ucSeqNumOfChReq; + UINT_64 u8Cookie; + UINT_8 ucReqChnlNum; + ENUM_BAND_T eBand; + ENUM_CHNL_EXT_T eChnlSco; + UINT_32 u4MaxInterval; + ENUM_CHANNEL_REQ_TYPE_T eChannelReqType; +} P2P_CHNL_REQ_INFO_T, *P_P2P_CHNL_REQ_INFO_T; + +typedef struct _P2P_SCAN_REQ_INFO_T { + ENUM_SCAN_TYPE_T eScanType; + ENUM_SCAN_CHANNEL eChannelSet; + UINT_16 u2PassiveDewellTime; + UINT_8 ucSeqNumOfScnMsg; + BOOLEAN fgIsAbort; + BOOLEAN fgIsScanRequest; + UINT_8 ucNumChannelList; + RF_CHANNEL_INFO_T arScanChannelList[MAXIMUM_OPERATION_CHANNEL_LIST]; + UINT_32 u4BufLength; + UINT_8 aucIEBuf[MAX_IE_LENGTH]; + P2P_SSID_STRUCT_T rSsidStruct; // Currently we can only take one SSID scan request +} +P2P_SCAN_REQ_INFO_T, *P_P2P_SCAN_REQ_INFO_T; + +typedef struct _P2P_CONNECTION_REQ_INFO_T { + + BOOLEAN fgIsConnRequest; + P2P_SSID_STRUCT_T rSsidStruct; + UINT_8 aucBssid[MAC_ADDR_LEN]; + /* For ASSOC Req. */ + UINT_32 u4BufLength; + UINT_8 aucIEBuf[MAX_IE_LENGTH]; +} P2P_CONNECTION_REQ_INFO_T, *P_P2P_CONNECTION_REQ_INFO_T; + +typedef struct _P2P_MGMT_TX_REQ_INFO_T { + BOOLEAN fgIsMgmtTxRequested; + P_MSDU_INFO_T prMgmtTxMsdu; + UINT_64 u8Cookie; +} P2P_MGMT_TX_REQ_INFO_T, *P_P2P_MGMT_TX_REQ_INFO_T; + +typedef struct _P2P_BEACON_UPDATE_INFO_T { + PUINT_8 pucBcnHdr; + UINT_32 u4BcnHdrLen; + PUINT_8 pucBcnBody; + UINT_32 u4BcnBodyLen; +} +P2P_BEACON_UPDATE_INFO_T, *P_P2P_BEACON_UPDATE_INFO_T; + +typedef struct _P2P_JOIN_INFO_T { + UINT_32 ucSeqNumOfReqMsg; + UINT_8 ucAvailableAuthTypes; + P_STA_RECORD_T prTargetStaRec; + P2P_SSID_STRUCT_T rSsidStruct; + BOOLEAN fgIsJoinComplete; + /* For ASSOC Rsp. */ + UINT_32 u4BufLength; + UINT_8 aucIEBuf[MAX_IE_LENGTH]; +} +P2P_JOIN_INFO_T, *P_P2P_JOIN_INFO_T; + +struct _P2P_FSM_INFO_T { + /* State related. */ + ENUM_P2P_STATE_T ePreviousState; + ENUM_P2P_STATE_T eCurrentState; + + /* Channel related. */ + P2P_CHNL_REQ_INFO_T rChnlReqInfo; + + /* Scan related. */ + P2P_SCAN_REQ_INFO_T rScanReqInfo; + + /* Connection related. */ + P2P_CONNECTION_REQ_INFO_T rConnReqInfo; + + /* Mgmt tx related. */ + P2P_MGMT_TX_REQ_INFO_T rMgmtTxInfo; + + /* Beacon related. */ + P2P_BEACON_UPDATE_INFO_T rBcnContentInfo; + + /* GC Join related. */ + P2P_JOIN_INFO_T rJoinInfo; + + /* FSM Timer */ + TIMER_T rP2pFsmTimeoutTimer; + + + /* GC Target BSS. */ + P_BSS_DESC_T prTargetBss; + + /* GC Connection Request. */ + BOOLEAN fgIsConnectionRequested; + + BOOLEAN fgIsApMode; + + /* Channel grant interval. */ + UINT_32 u4GrantInterval; + + /* Packet filter for P2P module. */ + UINT_32 u4P2pPacketFilter; + + //vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv Prepare for use vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv + /* Msg event queue. */ + LINK_T rMsgEventQueue; + +}; + + +/*---------------- Messages -------------------*/ +typedef struct _MSG_P2P_SCAN_REQUEST_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + P_P2P_SSID_STRUCT_T prSSID; + INT_32 i4SsidNum; + UINT_32 u4NumChannel; + PUINT_8 pucIEBuf; + UINT_32 u4IELen; + BOOLEAN fgIsAbort; + RF_CHANNEL_INFO_T arChannelListInfo[1]; +} MSG_P2P_SCAN_REQUEST_T, *P_MSG_P2P_SCAN_REQUEST_T; + +typedef struct _MSG_P2P_CHNL_REQUEST_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_64 u8Cookie; + UINT_32 u4Duration; + ENUM_CHNL_EXT_T eChnlSco; + RF_CHANNEL_INFO_T rChannelInfo; +} MSG_P2P_CHNL_REQUEST_T, *P_MSG_P2P_CHNL_REQUEST_T; + +typedef struct _MSG_P2P_CHNL_ABORT_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_64 u8Cookie; +} MSG_P2P_CHNL_ABORT_T, *P_MSG_P2P_CHNL_ABORT_T; + + +typedef struct _MSG_P2P_CONNECTION_REQUEST_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + P2P_SSID_STRUCT_T rSsid; + UINT_8 aucBssid[MAC_ADDR_LEN]; + ENUM_CHNL_EXT_T eChnlSco; + RF_CHANNEL_INFO_T rChannelInfo; + UINT_32 u4IELen; + UINT_8 aucIEBuf[1]; + // TODO: Auth Type, OPEN, SHARED, FT, EAP... +} MSG_P2P_CONNECTION_REQUEST_T, *P_MSG_P2P_CONNECTION_REQUEST_T; + + +typedef struct _MSG_P2P_CONNECTION_ABORT_T { + MSG_HDR_T rMsgHdr; /* Must be the first member. */ + UINT_8 aucTargetID[MAC_ADDR_LEN]; + UINT_16 u2ReasonCode; + BOOLEAN fgSendDeauth; +} MSG_P2P_CONNECTION_ABORT_T, *P_MSG_P2P_CONNECTION_ABORT_T; + +typedef struct _MSG_P2P_MGMT_TX_REQUEST_T { + MSG_HDR_T rMsgHdr; + P_MSDU_INFO_T prMgmtMsduInfo; + UINT_64 u8Cookie; /* For indication. */ +} MSG_P2P_MGMT_TX_REQUEST_T, *P_MSG_P2P_MGMT_TX_REQUEST_T; + + +typedef struct _MSG_P2P_BEACON_UPDATE_T { + MSG_HDR_T rMsgHdr; + UINT_32 u4DtimPeriod; + UINT_32 u4BcnInterval; + UINT_32 u4BcnHdrLen; + UINT_32 u4BcnBodyLen; + PUINT_8 pucBcnHdr; + PUINT_8 pucBcnBody; + UINT_8 aucBuffer[1]; /* Header & Body are put here. */ +} +MSG_P2P_BEACON_UPDATE_T, *P_MSG_P2P_BEACON_UPDATE_T; + +typedef struct _MSG_P2P_SWITCH_OP_MODE_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + ENUM_OP_MODE_T eOpMode; +} MSG_P2P_SWITCH_OP_MODE_T, *P_MSG_P2P_SWITCH_OP_MODE_T; + +typedef struct _MSG_P2P_MGMT_FRAME_REGISTER_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_16 u2FrameType; + BOOLEAN fgIsRegister; +} +MSG_P2P_MGMT_FRAME_REGISTER_T, *P_MSG_P2P_MGMT_FRAME_REGISTER_T; + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + + +VOID +p2pFsmRunEventAbort( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo + ); + + +VOID +p2pFsmRunEventScanRequest( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + +VOID +p2pFsmRunEventMgmtFrameTx( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + +VOID +p2pFsmRunEventBeaconUpdate( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + + +VOID +p2pFsmRunEventBeaconAbort( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + +VOID +p2pFsmRunEventChannelRequest( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + + +VOID +p2pFsmRunEventChannelAbort( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + + +VOID +p2pFsmRunEventDissolve( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + + +VOID +p2pFsmRunEventSwitchOPMode( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + + +WLAN_STATUS +p2pFsmRunEventMgmtFrameTxDone( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus + ); + + +VOID +p2pFsmRunEventMgmtFrameRegister( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + + +#if 0 +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#endif + +//3 /* --------------- WFA P2P DEFAULT PARAMETERS --------------- */ +#define P2P_WILDCARD_SSID "DIRECT-" +#define P2P_WILDCARD_SSID_LEN 7 +#define P2P_GROUP_ID_LEN 9 + +#define P2P_DRIVER_VERSION 2 /* Update when needed. */ + +#define P2P_DEFAULT_DEV_NAME "Wireless Client" +#define P2P_DEFAULT_DEV_NAME_LEN 15 +#define P2P_DEFAULT_PRIMARY_CATEGORY_ID 10 +#define P2P_DEFAULT_PRIMARY_SUB_CATEGORY_ID 5 +#define P2P_DEFAULT_CONFIG_METHOD (WPS_ATTRI_CFG_METHOD_PUSH_BUTTON | WPS_ATTRI_CFG_METHOD_KEYPAD | WPS_ATTRI_CFG_METHOD_DISPLAY) +#define P2P_DEFAULT_LISTEN_CHANNEL 1 + +#define P2P_MAX_SUPPORTED_SEC_DEV_TYPE_COUNT 0 /* NOTE(Kevin): Shall <= 16 */ +#define P2P_MAX_SUPPORTED_CHANNEL_LIST_COUNT 13 + +#define P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE 51 /* Contains 6 sub-band. */ + +#define P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT 8 /* NOTE(Kevin): Shall <= 16 */ + +#define P2P_MAXIMUM_CLIENT_COUNT 8 +#define P2P_MAXIMUM_NOA_COUNT 8 + + +#define P2P_MAXIMUM_ATTRIBUTE_LEN 251 + +#define P2P_CTWINDOW_DEFAULT 25 /* in TU=(1024usec) */ + +#define P2P_MAXIMUM_ATTRIBUTES_CACHE_SIZE 768 + +/* P2P 3.1.2.1.3 - Find Phase */ +#define P2P_MAX_DISCOVERABLE_INTERVAL 8 //3//3 +#define P2P_MIN_DISCOVERABLE_INTERVAL 5 // 1 + +#define P2P_LISTEN_SCAN_UNIT 100 // MS + +/* FSM Time Related constrain. */ +#define P2P_SERACH_STATE_PERIOD_MS 1000 // Deprecated. + +#define P2P_GO_CHANNEL_STAY_INTERVAL 1000 + +#define P2P_GO_NEGO_TIMEOUT_MS 500 +#define P2P_CONNECTION_TIMEOUT_SEC 120 + +#define P2P_INVITAION_TIMEOUT_MS 500 /* Timeout Wait Invitation Resonse. */ +#define P2P_PROVISION_DISCOVERY_TIMEOUT_MS 500 /* Timeout Wait Provision Discovery Resonse. */ + +//3 /* --------------- WFA P2P IE --------------- */ +/* P2P 4.1.1 - P2P IE format */ +#define P2P_OUI_TYPE_LEN 4 +#define P2P_IE_OUI_HDR (ELEM_HDR_LEN + P2P_OUI_TYPE_LEN) /* == OFFSET_OF(IE_P2P_T, aucP2PAttributes[0]) */ + +/* P2P 4.1.1 - General P2P Attribute */ +#define P2P_ATTRI_HDR_LEN 3 /* ID(1 octet) + Length(2 octets) */ + +/* P2P 4.1.1 - P2P Attribute ID definitions */ +#define P2P_ATTRI_ID_STATUS 0 +#define P2P_ATTRI_ID_REASON_CODE 1 +#define P2P_ATTRI_ID_P2P_CAPABILITY 2 +#define P2P_ATTRI_ID_P2P_DEV_ID 3 +#define P2P_ATTRI_ID_GO_INTENT 4 +#define P2P_ATTRI_ID_CFG_TIMEOUT 5 +#define P2P_ATTRI_ID_LISTEN_CHANNEL 6 +#define P2P_ATTRI_ID_P2P_GROUP_BSSID 7 +#define P2P_ATTRI_ID_EXT_LISTEN_TIMING 8 +#define P2P_ATTRI_ID_INTENDED_P2P_IF_ADDR 9 +#define P2P_ATTRI_ID_P2P_MANAGEABILITY 10 +#define P2P_ATTRI_ID_CHANNEL_LIST 11 +#define P2P_ATTRI_ID_NOTICE_OF_ABSENCE 12 +#define P2P_ATTRI_ID_P2P_DEV_INFO 13 +#define P2P_ATTRI_ID_P2P_GROUP_INFO 14 +#define P2P_ATTRI_ID_P2P_GROUP_ID 15 +#define P2P_ATTRI_ID_P2P_INTERFACE 16 +#define P2P_ATTRI_ID_OPERATING_CHANNEL 17 +#define P2P_ATTRI_ID_INVITATION_FLAG 18 +#define P2P_ATTRI_ID_VENDOR_SPECIFIC 221 + +/* Maximum Length of P2P Attributes */ +#define P2P_ATTRI_MAX_LEN_STATUS 1 /* 0 */ +#define P2P_ATTRI_MAX_LEN_REASON_CODE 1 /* 1 */ +#define P2P_ATTRI_MAX_LEN_P2P_CAPABILITY 2 /* 2 */ +#define P2P_ATTRI_MAX_LEN_P2P_DEV_ID 6 /* 3 */ +#define P2P_ATTRI_MAX_LEN_GO_INTENT 1 /* 4 */ +#define P2P_ATTRI_MAX_LEN_CFG_TIMEOUT 2 /* 5 */ +#if CID52_53_54 + #define P2P_ATTRI_MAX_LEN_LISTEN_CHANNEL 5 /* 6 */ +#else + #define P2P_ATTRI_MAX_LEN_LISTEN_CHANNEL 5 /* 6 */ +#endif +#define P2P_ATTRI_MAX_LEN_P2P_GROUP_BSSID 6 /* 7 */ +#define P2P_ATTRI_MAX_LEN_EXT_LISTEN_TIMING 4 /* 8 */ +#define P2P_ATTRI_MAX_LEN_INTENDED_P2P_IF_ADDR 6 /* 9 */ +#define P2P_ATTRI_MAX_LEN_P2P_MANAGEABILITY 1 /* 10 */ +//#define P2P_ATTRI_MAX_LEN_CHANNEL_LIST 3 + (n* (2 + num_of_ch)) /* 11 */ +#define P2P_ATTRI_LEN_CHANNEL_LIST 3 /* 11 */ +#define P2P_ATTRI_LEN_CHANNEL_ENTRY 2 /* 11 */ + + +//#define P2P_ATTRI_MAX_LEN_NOTICE_OF_ABSENCE 2 + (n* (13)) /* 12 */ +#define P2P_ATTRI_MAX_LEN_NOTICE_OF_ABSENCE (2 + (P2P_MAXIMUM_NOA_COUNT*(13))) /* 12 */ + +#define P2P_ATTRI_MAX_LEN_P2P_DEV_INFO 17 + (8 * (8)) + 36 /* 13 */ +//#define P2P_ATTRI_MAX_LEN_P2P_GROUP_INFO n* (25 + (m* (8)) + 32) /* 14 */ +#define P2P_ATTRI_MAX_LEN_P2P_GROUP_ID 38 /* 15 */ +#define P2P_ATTRI_MAX_LEN_P2P_INTERFACE 253 // 7 + 6* [0~41] /* 16 */ +#if CID52_53_54 + #define P2P_ATTRI_MAX_LEN_OPERATING_CHANNEL 5 /* 17 */ +#else + #define P2P_ATTRI_MAX_LEN_OPERATING_CHANNEL 5 /* 17 */ +#endif +#define P2P_ATTRI_MAX_LEN_INVITATION_FLAGS 1 /* 18 */ + +/* P2P 4.1.2 - P2P Status definitions */ +#define P2P_STATUS_SUCCESS 0 +#define P2P_STATUS_FAIL_INFO_IS_CURRENTLY_UNAVAILABLE 1 +#define P2P_STATUS_FAIL_INCOMPATIBLE_PARAM 2 +#define P2P_STATUS_FAIL_LIMIT_REACHED 3 +#define P2P_STATUS_FAIL_INVALID_PARAM 4 +#define P2P_STATUS_FAIL_UNABLE_ACCOMMODATE_REQ 5 +#define P2P_STATUS_FAIL_PREVIOUS_PROTOCOL_ERR 6 +#define P2P_STATUS_FAIL_NO_COMMON_CHANNELS 7 +#define P2P_STATUS_FAIL_UNKNOWN_P2P_GROUP 8 +#define P2P_STATUS_FAIL_SAME_INTENT_VALUE_15 9 +#define P2P_STATUS_FAIL_INCOMPATIBLE_PROVISION_METHOD 10 +#define P2P_STATUS_FAIL_REJECTED_BY_USER 11 + + +/* P2P 4.1.3 - P2P Minor Reason Code definitions */ +#define P2P_REASON_SUCCESS 0 +#define P2P_REASON_DISASSOCIATED_DUE_CROSS_CONNECTION 1 +#define P2P_REASON_DISASSOCIATED_DUE_UNMANAGEABLE 2 +#define P2P_REASON_DISASSOCIATED_DUE_NO_P2P_COEXIST_PARAM 3 +#define P2P_REASON_DISASSOCIATED_DUE_MANAGEABLE 4 + + +/* P2P 4.1.4 - Device Capability Bitmap definitions */ +#define P2P_DEV_CAPABILITY_SERVICE_DISCOVERY BIT(0) +#define P2P_DEV_CAPABILITY_CLIENT_DISCOVERABILITY BIT(1) +#define P2P_DEV_CAPABILITY_CONCURRENT_OPERATION BIT(2) +#define P2P_DEV_CAPABILITY_P2P_INFRA_MANAGED BIT(3) +#define P2P_DEV_CAPABILITY_P2P_DEVICE_LIMIT BIT(4) +#define P2P_DEV_CAPABILITY_P2P_INVITATION_PROCEDURE BIT(5) + + +/* P2P 4.1.4 - Group Capability Bitmap definitions */ +#define P2P_GROUP_CAPABILITY_P2P_GROUP_OWNER BIT(0) +#define P2P_GROUP_CAPABILITY_PERSISTENT_P2P_GROUP BIT(1) +#define P2P_GROUP_CAPABILITY_P2P_GROUP_LIMIT BIT(2) +#define P2P_GROUP_CAPABILITY_INTRA_BSS_DISTRIBUTION BIT(3) +#define P2P_GROUP_CAPABILITY_CROSS_CONNECTION BIT(4) +#define P2P_GROUP_CAPABILITY_PERSISTENT_RECONNECT BIT(5) +#define P2P_GROUP_CAPABILITY_GROUP_FORMATION BIT(6) + +/* P2P 4.1.6 - GO Intent field definitions */ +#define P2P_GO_INTENT_TIE_BREAKER_FIELD BIT(0) +#define P2P_GO_INTENT_VALUE_MASK BITS(1,7) +#define P2P_GO_INTENT_VALUE_OFFSET 1 + +/* P2P 4.1.12 - Manageability Bitmap definitions */ +#define P2P_DEVICE_MANAGEMENT BIT(0) + +/* P2P 4.1.14 - CTWindow and OppPS Parameters definitions */ +#define P2P_CTW_OPPPS_PARAM_OPPPS_FIELD BIT(7) +#define P2P_CTW_OPPPS_PARAM_CTWINDOW_MASK BITS(0,6) + + +#define ELEM_MAX_LEN_P2P_FOR_PROBE_REQ \ + (P2P_OUI_TYPE_LEN + \ + (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_P2P_CAPABILITY) + \ + (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_P2P_DEV_ID) + \ + (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_LISTEN_CHANNEL) + \ + (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_OPERATING_CHANNEL)) + +#define ELEM_MAX_LEN_P2P_FOR_ASSOC_REQ \ + (P2P_OUI_TYPE_LEN + \ + (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_P2P_CAPABILITY) + \ + (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_EXT_LISTEN_TIMING) + \ + (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_P2P_DEV_INFO)) + + +/* P2P 4.1.16 - P2P Client Infor Descriptor */ +#define P2P_CLIENT_INFO_DESC_HDR_LEN 1 /* Length(1 octets) */ + +/* P2P 4.1.20 - P2P Invitation Flags Attribute*/ +#define P2P_INVITATION_FLAGS_INVITATION_TYPE BIT(0) +#define P2P_INVITATION_TYPE_INVITATION 0 +#define P2P_INVITATION_TYPE_REINVOKE 1 +//3 /* --------------- WPS Data Element Definitions --------------- */ +/* P2P 4.2.2 - General WSC Attribute */ +#define WSC_ATTRI_HDR_LEN 4 /* ID(2 octet) + Length(2 octets) */ +#define WSC_ATTRI_MAX_LEN_VERSION 1 +#define WSC_ATTRI_MAX_LEN_DEVICE_PASSWORD_ID 2 +#define WSC_ATTRI_LEN_CONFIG_METHOD 2 + +/* WPS 11 - Data Element Definitions */ +#define WPS_ATTRI_ID_VERSION 0x104A +#define WPS_ATTRI_ID_CONFIGURATION_METHODS 0x1008 +#define WPS_ATTRI_ID_DEVICE_PASSWORD 0x1012 +#define WPS_ATTRI_ID_DEVICE_NAME 0x1011 +#define WPS_ATTRI_ID_PRI_DEVICE_TYPE 0x1054 +#define WPS_ATTRI_ID_SEC_DEVICE_TYPE 0x1055 + +#define WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE 300 + +#define WPS_ATTRI_MAX_LEN_DEVICE_NAME 32 /* 0x1011 */ + +#define WPS_ATTRI_CFG_METHOD_USBA BIT(0) +#define WPS_ATTRI_CFG_METHOD_ETHERNET BIT(1) +#define WPS_ATTRI_CFG_METHOD_LABEL BIT(2) +#define WPS_ATTRI_CFG_METHOD_DISPLAY BIT(3) +#define WPS_ATTRI_CFG_METHOD_EXT_NFC BIT(4) +#define WPS_ATTRI_CFG_METHOD_INT_NFC BIT(5) +#define WPS_ATTRI_CFG_METHOD_NFC_IF BIT(6) +#define WPS_ATTRI_CFG_METHOD_PUSH_BUTTON BIT(7) +#define WPS_ATTRI_CFG_METHOD_KEYPAD BIT(8) + + +#define P2P_FLAGS_PROVISION_COMPLETE 0x00000001 +#define P2P_FLAGS_PROVISION_DISCOVERY_COMPLETE 0x00000002 +#define P2P_FLAGS_PROVISION_DISCOVERY_WAIT_RESPONSE 0x00000004 +#define P2P_FLAGS_PROVISION_DISCOVERY_RESPONSE_WAIT 0x00000008 +#define P2P_FLAGS_MASK_PROVISION 0x00000017 +#define P2P_FLAGS_MASK_PROVISION_COMPLETE 0x00000015 +#define P2P_FLAGS_PROVISION_DISCOVERY_INDICATED 0x00000010 +#define P2P_FLAGS_INVITATION_TOBE_GO 0x00000100 +#define P2P_FLAGS_INVITATION_TOBE_GC 0x00000200 +#define P2P_FLAGS_INVITATION_SUCCESS 0x00000400 +#define P2P_FLAGS_INVITATION_WAITING_TARGET 0x00000800 +#define P2P_FLAGS_MASK_INVITATION 0x00000F00 +#define P2P_FLAGS_FORMATION_ON_GOING 0x00010000 +#define P2P_FLAGS_FORMATION_LOCAL_PWID_RDY 0x00020000 +#define P2P_FLAGS_FORMATION_TARGET_PWID_RDY 0x00040000 +#define P2P_FLAGS_FORMATION_COMPLETE 0x00080000 +#define P2P_FLAGS_MASK_FORMATION 0x000F0000 +#define P2P_FLAGS_DEVICE_DISCOVER_REQ 0x00100000 +#define P2P_FLAGS_DEVICE_DISCOVER_DONE 0x00200000 +#define P2P_FLAGS_DEVICE_INVITATION_WAIT 0x00400000 +#define P2P_FLAGS_DEVICE_SERVICE_DISCOVER_WAIT 0x00800000 +#define P2P_FLAGS_MASK_DEVICE_DISCOVER 0x00F00000 + +#define P2P_FLAGS_DEVICE_FORMATION_REQUEST 0x01000000 + + +/* MACRO for flag operation */ +#define SET_FLAGS(_FlagsVar, _BitsToSet) \ + (_FlagsVar) = ((_FlagsVar) | (_BitsToSet)) + +#define TEST_FLAGS(_FlagsVar, _BitsToCheck) \ + (((_FlagsVar) & (_BitsToCheck)) == (_BitsToCheck)) + +#define CLEAR_FLAGS(_FlagsVar, _BitsToClear) \ + (_FlagsVar) &= ~(_BitsToClear) + + + +#define CFG_DISABLE_WIFI_DIRECT_ENHANCEMENT_I 0 + +#define CFG_DISABLE_WIFI_DIRECT_ENHANCEMENT_II 0 + +#define CFG_DISABLE_WIFI_DIRECT_ENHANCEMENT_III 0 + +#define CFG_DISABLE_WIFI_DIRECT_ENHANCEMENT_IV 0 + +#define CFG_DISABLE_DELAY_PROVISION_DISCOVERY 0 + +#define CFG_CONNECTION_POLICY_2_0 0 + +/* Device Password ID */ +enum wps_dev_password_id { + DEV_PW_DEFAULT = 0x0000, + DEV_PW_USER_SPECIFIED = 0x0001, + DEV_PW_MACHINE_SPECIFIED = 0x0002, + DEV_PW_REKEY = 0x0003, + DEV_PW_PUSHBUTTON = 0x0004, + DEV_PW_REGISTRAR_SPECIFIED = 0x0005 +}; + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +#if defined(WINDOWS_DDK) || defined(WINDOWS_CE) +#pragma pack(1) +#endif + +//3 /* --------------- WFA P2P IE and Attributes --------------- */ + +/* P2P 4.1.1 - P2P Information Element */ +typedef struct _IE_P2P_T { + UINT_8 ucId; /* Element ID */ + UINT_8 ucLength; /* Length */ + UINT_8 aucOui[3]; /* OUI */ + UINT_8 ucOuiType; /* OUI Type */ + UINT_8 aucP2PAttributes[1]; /* P2P Attributes */ +} __KAL_ATTRIB_PACKED__ IE_P2P_T, *P_IE_P2P_T; + +/* P2P 4.1.1 - General P2P Attribute */ +typedef struct _P2P_ATTRIBUTE_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 aucBody[1]; /* Body field */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRIBUTE_T, *P_P2P_ATTRIBUTE_T; + + +/* P2P 4.1.2 - P2P Status Attribute */ +typedef struct _P2P_ATTRI_STATUS_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 ucStatusCode; /* Status Code */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_STATUS_T, *P_P2P_ATTRI_STATUS_T; + + +/* P2P 4.1.3 - P2P Minor Reason Code Attribute */ +typedef struct _P2P_ATTRI_REASON_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 ucMinorReasonCode; /* Minor Reason Code */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_REASON_T, *P_P2P_ATTRI_REASON_T; + + +/* P2P 4.1.4 - P2P Capability Attribute */ +typedef struct _P2P_ATTRI_CAPABILITY_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 ucDeviceCap; /* Device Capability Bitmap */ + UINT_8 ucGroupCap; /* Group Capability Bitmap */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_CAPABILITY_T, *P_P2P_ATTRI_CAPABILITY_T; + + +/* P2P 4.1.5 - P2P Device ID Attribute */ +typedef struct _P2P_ATTRI_DEV_ID_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_DEV_ID_T, *P_P2P_ATTRI_DEV_ID_T; + + +/* P2P 4.1.6 - Group Owner Intent Attribute */ +typedef struct _P2P_ATTRI_GO_INTENT_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 ucGOIntent; /* Group Owner Intent */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_GO_INTENT_T, *P_P2P_ATTRI_GO_INTENT_T; + + +/* P2P 4.1.7 - Configuration Timeout Attribute */ +typedef struct _P2P_ATTRI_CFG_TIMEOUT_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 ucGOCfgTimeout; /* GO Configuration Timeout */ + UINT_8 ucClientCfgTimeout; /* Client Configuration Timeout */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_CFG_TIMEOUT_T, *P_P2P_ATTRI_CFG_TIMEOUT_T; + + +/* P2P 4.1.8 - Listen Channel Attribute */ +typedef struct _P2P_ATTRI_LISTEN_CHANNEL_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 aucCountryString[3]; /* Country String */ + UINT_8 ucOperatingClass; /* Operating Class from 802.11 Annex J/P802.11 REVmb 3.0 */ + UINT_8 ucChannelNumber; /* Channel Number */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_LISTEN_CHANNEL_T, *P_P2P_ATTRI_LISTEN_CHANNEL_T; + + +/* P2P 4.1.9 - P2P Group BSSID Attribute */ +typedef struct _P2P_ATTRI_GROUP_BSSID_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 aucBssid[MAC_ADDR_LEN]; /* P2P Group BSSID */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_GROUP_BSSID_T, *P_P2P_ATTRI_GROUP_BSSID_T; + + +/* P2P 4.1.10 - Extended Listen Timing Attribute */ +typedef struct _P2P_ATTRI_EXT_LISTEN_TIMING_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_16 u2AvailPeriod; /* Availability Period */ + UINT_16 u2AvailInterval; /* Availability Interval */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_EXT_LISTEN_TIMING_T, *P_P2P_ATTRI_EXT_LISTEN_TIMING_T; + + +/* P2P 4.1.11 - Intended P2P Interface Address Attribute */ +typedef struct _P2P_ATTRI_INTENDED_IF_ADDR_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 aucIfAddr[MAC_ADDR_LEN];/* P2P Interface Address */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_INTENDED_IF_ADDR_T, *P_P2P_ATTRI_INTENDED_IF_ADDR_T; + + +/* P2P 4.1.12 - P2P Manageability Attribute */ +typedef struct _P2P_ATTRI_MANAGEABILITY_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 ucManageability; /* P2P Manageability Bitmap */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_MANAGEABILITY_T, *P_P2P_ATTRI_MANAGEABILITY_T; + + +/* P2P 4.1.13 - Channel List Attribute */ +typedef struct _P2P_ATTRI_CHANNEL_LIST_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 aucCountryString[3]; /* Country String */ + UINT_8 aucChannelEntry[1]; /* Channel Entry List */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_CHANNEL_T, *P_P2P_ATTRI_CHANNEL_T; + +typedef struct _CHANNEL_ENTRY_FIELD_T { + UINT_8 ucRegulatoryClass; /* Regulatory Class */ + UINT_8 ucNumberOfChannels; /* Number Of Channels */ + UINT_8 aucChannelList[1]; /* Channel List */ +} __KAL_ATTRIB_PACKED__ CHANNEL_ENTRY_FIELD_T, *P_CHANNEL_ENTRY_FIELD_T; + + +/* P2P 4.1.14 - Notice of Absence Attribute */ +typedef struct _P2P_ATTRI_NOA_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 ucIndex; /* Index */ + UINT_8 ucCTWOppPSParam; /* CTWindow and OppPS Parameters */ + UINT_8 aucNoADesc[1]; /* NoA Descriptor */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_NOA_T, *P_P2P_ATTRI_NOA_T; + +typedef struct _NOA_DESCRIPTOR_T { + UINT_8 ucCountType; /* Count/Type */ + UINT_32 u4Duration; /* Duration */ + UINT_32 u4Interval; /* Interval */ + UINT_32 u4StartTime; /* Start Time */ +} __KAL_ATTRIB_PACKED__ NOA_DESCRIPTOR_T, *P_NOA_DESCRIPTOR_T; + +typedef struct _P2P_ATTRI_DEV_INFO_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ + UINT_16 u2ConfigMethodsBE; /* Config Method */ + DEVICE_TYPE_T rPrimaryDevTypeBE; /* Primary Device Type */ + UINT_8 ucNumOfSecondaryDevType; /* Number of Secondary Device Types */ + DEVICE_TYPE_T arSecondaryDevTypeListBE[1]; /* Secondary Device Type List */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_DEV_INFO_T, *P_P2P_ATTRI_DEV_INFO_T; + +/* WPS 7.1 & 11 WPS TLV Data Format - Device Name */ +typedef struct _DEVICE_NAME_TLV_T { + UINT_16 u2Id; /* WPS Attribute Type */ + UINT_16 u2Length; /* Data Length */ + UINT_8 aucName[32]; /* Device Name */ // TODO: Fixme +} __KAL_ATTRIB_PACKED__ DEVICE_NAME_TLV_T, *P_DEVICE_NAME_TLV_T; + + +/* P2P 4.1.16 - P2P Group Info Attribute */ +typedef struct _P2P_CLIENT_INFO_DESC_T { + UINT_8 ucLength; /* Length */ + UINT_8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ + UINT_8 aucIfAddr[MAC_ADDR_LEN]; /* P2P Interface Address */ + UINT_8 ucDeviceCap; /* Device Capability Bitmap */ + UINT_16 u2ConfigMethodsBE; /* Config Method */ + DEVICE_TYPE_T rPrimaryDevTypeBE; /* Primary Device Type */ + UINT_8 ucNumOfSecondaryDevType; /* Number of Secondary Device Types */ + DEVICE_TYPE_T arSecondaryDevTypeListBE[1]; /* Secondary Device Type List */ +} __KAL_ATTRIB_PACKED__ P2P_CLIENT_INFO_DESC_T, *P_P2P_CLIENT_INFO_DESC_T; + +typedef struct _P2P_ATTRI_GROUP_INFO_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + P2P_CLIENT_INFO_DESC_T arClientDesc[1]; /* P2P Client Info Descriptors */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_GROUP_INFO_T, *P_P2P_ATTRI_GROUP_INFO_T; + + +/* P2P 4.1.17 - P2P Group ID Attribute */ +typedef struct _P2P_ATTRI_GROUP_ID_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ + UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; /* SSID */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_GROUP_ID_T, *P_P2P_ATTRI_GROUP_ID_T; + + +/* P2P 4.1.18 - P2P Interface Attribute */ +typedef struct _P2P_ATTRI_INTERFACE_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ + UINT_8 ucIfAddrCount; /* P2P Interface Address Count */ + UINT_8 aucIfAddrList[MAC_ADDR_LEN];/* P2P Interface Address List */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_INTERFACE_T, *P_P2P_ATTRI_INTERFACE_T; + + +/* P2P 4.1.19 - Operating Channel Attribute */ +typedef struct _P2P_ATTRI_OPERATING_CHANNEL_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 aucCountryString[3]; /* Country String */ + UINT_8 ucOperatingClass; /* Operating Class from 802.11 Annex J/P802.11 REVmb 3.0 */ + UINT_8 ucChannelNumber; /* Channel Number */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_OPERATING_CHANNEL_T, *P_P2P_ATTRI_OPERATING_CHANNEL_T; + +/* P2P 4.1.20 - Invitation Flags Attribute */ +typedef struct _P2P_ATTRI_INVITATION_FLAG_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 ucInviteFlagsBitmap; /* Invitation Flags Bitmap */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_INVITATION_FLAG_T, *P_P2P_ATTRI_INVITATION_FLAG_T; + + + +/* P2P 4.1.1 - General WSC Attribute */ +typedef struct _WSC_ATTRIBUTE_T { + UINT_16 u2Id; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 aucBody[1]; /* Body field */ +} __KAL_ATTRIB_PACKED__ WSC_ATTRIBUTE_T, *P_WSC_ATTRIBUTE_T; + +/* WSC 1.0 Table 28 */ +typedef struct _WSC_ATTRI_VERSION_T { + UINT_16 u2Id; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 ucVersion; /* Version 1.0 or 1.1 */ +} __KAL_ATTRIB_PACKED__ WSC_ATTRI_VERSION_T, *P_WSC_ATTRI_VERSION_T; + +typedef struct _WSC_ATTRI_DEVICE_PASSWORD_ID_T { + UINT_16 u2Id; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_16 u2DevPasswordId; /* Device Password ID */ +} __KAL_ATTRIB_PACKED__ WSC_ATTRI_DEVICE_PASSWORD_ID_T, *P_WSC_ATTRI_DEVICE_PASSWORD_ID_T; + + +typedef struct _WSC_ATTRI_CONFIGURATION_METHOD_T { + UINT_16 u2Id; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_16 u2ConfigMethods; /* Configure Methods */ +} __KAL_ATTRIB_PACKED__ WSC_ATTRI_CONFIGURATION_METHOD_T, *P_WSC_ATTRI_CONFIGURATION_METHOD_T; + + + +#if defined(WINDOWS_DDK) || defined(WINDOWS_CE) +#pragma pack() +#endif + + +//3 /* --------------- WFA P2P Attributes Handler prototype --------------- */ +typedef UINT_32 (*PFN_APPEND_ATTRI_FUNC)(P_ADAPTER_T, BOOLEAN, PUINT_16, PUINT_8, UINT_16); + +typedef VOID (*PFN_HANDLE_ATTRI_FUNC)(P_SW_RFB_T, P_P2P_ATTRIBUTE_T); + +typedef VOID (*PFN_VERIFY_ATTRI_FUNC)(P_SW_RFB_T, P_P2P_ATTRIBUTE_T, PUINT_16); + +typedef UINT_32 (*PFN_CALCULATE_VAR_ATTRI_LEN_FUNC)(P_ADAPTER_T, P_STA_RECORD_T); + + +typedef struct _APPEND_VAR_ATTRI_ENTRY_T { + UINT_16 u2EstimatedFixedAttriLen; /* For fixed length */ + PFN_CALCULATE_VAR_ATTRI_LEN_FUNC pfnCalculateVariableAttriLen; + PFN_APPEND_ATTRI_FUNC pfnAppendAttri; +} APPEND_VAR_ATTRI_ENTRY_T, *P_APPEND_VAR_ATTRI_ENTRY_T; + +typedef enum _ENUM_CONFIG_METHOD_SEL { + ENUM_CONFIG_METHOD_SEL_AUTO, + ENUM_CONFIG_METHOD_SEL_USER, + ENUM_CONFIG_METHOD_SEL_NUM +} ENUM_CONFIG_METHOD_SEL, *P_ENUM_CONFIG_METHOD_SEL; + +typedef enum _ENUM_P2P_FORMATION_POLICY { + ENUM_P2P_FORMATION_POLICY_AUTO = 0, + ENUM_P2P_FORMATION_POLICY_PASSIVE, /* Device would wait GO NEGO REQ instead of sending it actively. */ + ENUM_P2P_FORMATION_POLICY_NUM +} ENUM_P2P_FORMATION_POLICY, P_ENUM_P2P_FORMATION_POLICY; + +typedef enum _ENUM_P2P_INVITATION_POLICY { + ENUM_P2P_INVITATION_POLICY_USER = 0, + ENUM_P2P_INVITATION_POLICY_ACCEPT_FIRST, + ENUM_P2P_INVITATION_POLICY_DENY_ALL, + ENUM_P2P_INVITATION_POLICY_NUM +} ENUM_P2P_INVITATION_POLICY, P_ENUM_P2P_INVITATION_POLICY; + +//3 /* --------------- Data Structure for P2P Operation --------------- */ +//3 /* Session for CONNECTION SETTINGS of P2P */ +struct _P2P_CONNECTION_SETTINGS_T { + UINT_8 ucDevNameLen; + UINT_8 aucDevName[WPS_ATTRI_MAX_LEN_DEVICE_NAME]; + + DEVICE_TYPE_T rPrimaryDevTypeBE; + + ENUM_P2P_FORMATION_POLICY eFormationPolicy; /* Formation Policy. */ + + /*------------WSC Related Param---------------*/ + UINT_16 u2ConfigMethodsSupport; /* Prefered configure method. + * Some device may not have keypad. + */ + ENUM_CONFIG_METHOD_SEL eConfigMethodSelType; + UINT_16 u2TargetConfigMethod; /* Configure method selected by user or auto. */ + UINT_16 u2LocalConfigMethod; /* Configure method of target. */ + BOOLEAN fgIsPasswordIDRdy; + /*------------WSC Related Param---------------*/ + + UINT_8 ucClientConfigTimeout; + UINT_8 ucGoConfigTimeout; + + UINT_8 ucSecondaryDevTypeCount; +#if P2P_MAX_SUPPORTED_SEC_DEV_TYPE_COUNT + DEVICE_TYPE_T arSecondaryDevTypeBE[P2P_MAX_SUPPORTED_SEC_DEV_TYPE_COUNT]; +#endif + + +#if 0 + UINT_8 ucRfChannelListCount; +#if P2P_MAX_SUPPORTED_CHANNEL_LIST_COUNT + UINT_8 aucChannelList[P2P_MAX_SUPPORTED_CHANNEL_LIST_COUNT]; /* Channel Numbering depends on 802.11mb Annex J. */ + +#endif +#else + UINT_8 ucRfChannelListSize; +#if P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE + UINT_8 aucChannelEntriesField[P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE]; +#endif +#endif + + /* Go Intent */ + UINT_8 ucTieBreaker; + UINT_8 ucGoIntent; + + /* For Device Capability */ + BOOLEAN fgSupportServiceDiscovery; + BOOLEAN fgSupportClientDiscoverability; + BOOLEAN fgSupportConcurrentOperation; + BOOLEAN fgSupportInfraManaged; + BOOLEAN fgSupportInvitationProcedure; + + /* For Group Capability */ + BOOLEAN fgSupportPersistentP2PGroup; + BOOLEAN fgSupportIntraBSSDistribution; + BOOLEAN fgSupportCrossConnection; + BOOLEAN fgSupportPersistentReconnect; + + BOOLEAN fgP2pGroupLimit; + + BOOLEAN fgSupportOppPS; + UINT_16 u2CTWindow; + + BOOLEAN fgIsScanReqIssued; + BOOLEAN fgIsServiceDiscoverIssued; + + + /*============ Target Device Connection Settings ============*/ + + /* Discover Target Device Info. */ + BOOLEAN fgIsDevId; + BOOLEAN fgIsDevType; + + /* Encryption mode of Target Device */ + ENUM_PARAM_AUTH_MODE_T eAuthMode; + + /* SSID + * 1. AP Mode, this is the desired SSID user specified. + * 2. Client Mode, this is the target SSID to be connected to. + */ + UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; + UINT_8 ucSSIDLen; + + /* Operating channel requested. */ + UINT_8 ucOperatingChnl; + ENUM_BAND_T eBand; + + /* Linten channel requested. */ + UINT_8 ucListenChnl; + + /* For device discover address/type. */ + UINT_8 aucTargetDevAddr[MAC_ADDR_LEN]; /* P2P Device Address, for P2P Device Discovery & P2P Connection. */ + +#if CFG_ENABLE_WIFI_DIRECT + P_P2P_DEVICE_DESC_T prTargetP2pDesc; +#endif + + UINT_8 ucLastStatus; /* P2P FSM would append status attribute according to this field. */ + + +#if !CFG_DISABLE_DELAY_PROVISION_DISCOVERY + UINT_8 ucLastDialogToken; + UINT_8 aucIndicateDevAddr[MAC_ADDR_LEN]; +#endif + +#if 0 + UINT_8 ucTargetRfChannelListCount; +#if P2P_MAX_SUPPORTED_CHANNEL_LIST_COUNT + UINT_8 aucTargetChannelList[P2P_MAX_SUPPORTED_CHANNEL_LIST_COUNT]; /* Channel Numbering depends on 802.11mb Annex J. */ +#endif +#endif + +}; + + +typedef struct _NOA_TIMING_T { + BOOLEAN fgIsInUse; /* Indicate if this entry is in use or not */ + UINT_8 ucCount; /* Count */ + + UINT_8 aucReserved[2]; + + UINT_32 u4Duration; /* Duration */ + UINT_32 u4Interval; /* Interval */ + UINT_32 u4StartTime; /* Start Time */ +} NOA_TIMING_T, *P_NOA_TIMING_T; + +typedef enum _ENUM_P2P_IOCTL_T { + P2P_IOCTL_IDLE = 0, + P2P_IOCTL_DEV_DISCOVER, + P2P_IOCTL_INVITATION_REQ, + P2P_IOCTL_SERV_DISCOVER, + P2P_IOCTL_WAITING, + P2P_IOCTL_NUM +} ENUM_P2P_IOCTL_T; + + + +/*---------------- Service Discovery Related -------------------*/ +typedef enum _ENUM_SERVICE_TX_TYPE_T { + ENUM_SERVICE_TX_TYPE_BY_DA, + ENUM_SERVICE_TX_TYPE_BY_CHNL, + ENUM_SERVICE_TX_TYPE_NUM +} ENUM_SERVICE_TX_TYPE_T; + + +typedef struct _SERVICE_DISCOVERY_FRAME_DATA_T { + QUE_ENTRY_T rQueueEntry; + P_MSDU_INFO_T prSDFrame; + ENUM_SERVICE_TX_TYPE_T eServiceType; + UINT_8 ucSeqNum; + union { + + UINT_8 ucChannelNum; + UINT_8 aucPeerAddr[MAC_ADDR_LEN]; + } uTypeData; + BOOLEAN fgIsTxDoneIndicate; +} SERVICE_DISCOVERY_FRAME_DATA_T, *P_SERVICE_DISCOVERY_FRAME_DATA_T; + + + + +struct _P2P_FSM_INFO_T_DEPRECATED { + /* P2P FSM State */ + ENUM_P2P_STATE_T eCurrentState; + + /* Channel */ + BOOLEAN fgIsChannelRequested; + + + + + + + + + + + ENUM_P2P_STATE_T ePreviousState; + + ENUM_P2P_STATE_T eReturnState; /* Return state after current activity finished or abort. */ + + UINT_8 aucTargetIfAddr[PARAM_MAC_ADDR_LEN]; + P_BSS_DESC_T prTargetBss; /* BSS of target P2P Device. For Connection/Service Discovery */ + + P_STA_RECORD_T prTargetStaRec; + + BOOLEAN fgIsRsponseProbe; /* Indicate if P2P FSM can response probe request frame. */ + + /* Sequence number of requested message. */ + UINT_8 ucSeqNumOfReqMsg; /* Used for SAA FSM request message. */ + + /* Channel Privilege */ + UINT_8 ucSeqNumOfChReq; /* Used for Channel Request message. */ + + + UINT_8 ucSeqNumOfScnMsg; /* Used for SCAN FSM request message. */ + UINT_8 ucSeqNumOfCancelMsg; + + UINT_8 ucDialogToken; + UINT_8 ucRxDialogToken; + + /* Timer */ + TIMER_T rDeviceDiscoverTimer; /* For device discovery time of each discovery request from user.*/ + TIMER_T rOperationListenTimer; /* For Find phase under operational state. */ + TIMER_T rFSMTimer; /* A timer used for Action frame timeout usage. */ + + TIMER_T rRejoinTimer; /* A timer used for Action frame timeout usage. */ + + + /* Flag to indicate Provisioning */ + BOOLEAN fgIsConnectionRequested; + + /* Current IOCTL. */ + ENUM_P2P_IOCTL_T eP2pIOCTL; + + UINT_8 ucAvailableAuthTypes; /* Used for AUTH_MODE_AUTO_SWITCH */ + + /*--------SERVICE DISCOVERY--------*/ + QUE_T rQueueGASRx; /* Input Request/Response. */ + QUE_T rQueueGASTx; /* Output Response. */ + P_SERVICE_DISCOVERY_FRAME_DATA_T prSDRequest; + UINT_8 ucVersionNum; /* GAS packet sequence number for...Action Frame? */ + UINT_8 ucGlobalSeqNum; /* Sequence Number of RX SD packet. */ + /*--------Service DISCOVERY--------*/ + + /*--------DEVICE DISCOVERY---------*/ + UINT_8 aucTargetGroupID[PARAM_MAC_ADDR_LEN]; + UINT_16 u2TargetGroupSsidLen; + UINT_8 aucTargetSsid[32]; + UINT_8 aucSearchingP2pDevice[PARAM_MAC_ADDR_LEN]; + UINT_8 ucDLToken; + /*----------------------------------*/ + + /* Indicating Peer Status. */ + UINT_32 u4Flags; + + /*Indicating current running mode.*/ + BOOLEAN fgIsApMode; + + + /*------------INVITATION------------*/ + ENUM_P2P_INVITATION_POLICY eInvitationRspPolicy; + /*----------------------------------*/ + +}; + + + +struct _P2P_SPECIFIC_BSS_INFO_T { + /* For GO(AP) Mode - Compose TIM IE */ + UINT_16 u2SmallestAID; + UINT_16 u2LargestAID; + UINT_8 ucBitmapCtrl; + //UINT_8 aucPartialVirtualBitmap[MAX_LEN_TIM_PARTIAL_BMP]; + + /* For GC/GO OppPS */ + BOOLEAN fgEnableOppPS; + UINT_16 u2CTWindow; + + /* For GC/GO NOA */ + UINT_8 ucNoAIndex; + UINT_8 ucNoATimingCount; /* Number of NoA Timing */ + NOA_TIMING_T arNoATiming[P2P_MAXIMUM_NOA_COUNT]; + + BOOLEAN fgIsNoaAttrExisted; + + /* For P2P Device */ + UINT_8 ucRegClass; /* Regulatory Class for channel. */ + UINT_8 ucListenChannel; /* Linten Channel only on channels 1, 6 and 11 in the 2.4 GHz. */ + + UINT_8 ucPreferredChannel; /* Operating Channel, should be one of channel list in p2p connection settings. */ + ENUM_CHNL_EXT_T eRfSco; + ENUM_BAND_T eRfBand; + + /* Extened Listen Timing. */ + UINT_16 u2AvailabilityPeriod; + UINT_16 u2AvailabilityInterval; + + UINT_16 u2AttributeLen; + UINT_8 aucAttributesCache[P2P_MAXIMUM_ATTRIBUTES_CACHE_SIZE]; + + UINT_16 u2WscAttributeLen; + UINT_8 aucWscAttributesCache[WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE]; + + UINT_8 aucGroupID[MAC_ADDR_LEN]; + UINT_16 u2GroupSsidLen; + UINT_8 aucGroupSsid[ELEM_MAX_LEN_SSID]; + + PARAM_CUSTOM_NOA_PARAM_STRUC_T rNoaParam; + PARAM_CUSTOM_OPPPS_PARAM_STRUC_T rOppPsParam; + +}; + + + + + + + +typedef struct _MSG_P2P_DEVICE_DISCOVER_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_32 u4DevDiscoverTime; /* 0: Infinite, 1~X: in unit of MS. */ + BOOLEAN fgIsSpecificType; +#if CFG_ENABLE_WIFI_DIRECT + P2P_DEVICE_TYPE_T rTargetDeviceType; +#endif + UINT_8 aucTargetDeviceID[MAC_ADDR_LEN]; +} MSG_P2P_DEVICE_DISCOVER_T, *P_MSG_P2P_DEVICE_DISCOVER_T; + + + +typedef struct _MSG_P2P_INVITATION_REQUEST_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 aucDeviceID[MAC_ADDR_LEN]; /* Target Device ID to be invited. */ +} MSG_P2P_INVITATION_REQUEST_T, *P_MSG_P2P_INVITATION_REQUEST_T; + +typedef struct _MSG_P2P_FUNCTION_SWITCH_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + BOOLEAN fgIsFuncOn; +} MSG_P2P_FUNCTION_SWITCH_T, *P_MSG_P2P_FUNCTION_SWITCH_T; + +typedef struct _MSG_P2P_SERVICE_DISCOVERY_REQUEST_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 aucDeviceID[MAC_ADDR_LEN]; + BOOLEAN fgNeedTxDoneIndicate; + UINT_8 ucSeqNum; +} MSG_P2P_SERVICE_DISCOVERY_REQUEST_T, *P_MSG_P2P_SERVICE_DISCOVERY_REQUEST_T; + + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define p2pChangeMediaState(_prAdapter, _eNewMediaState) \ + (_prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].eConnectionState = (_eNewMediaState)); + +#define ATTRI_ID(_fp) (((P_P2P_ATTRIBUTE_T) _fp)->ucId) +#define ATTRI_LEN(_fp) \ + (((UINT_16) ((PUINT_8)&((P_P2P_ATTRIBUTE_T) _fp)->u2Length)[0]) | \ + ((UINT_16) ((PUINT_8)&((P_P2P_ATTRIBUTE_T) _fp)->u2Length)[1] << 8)) + + +#define ATTRI_SIZE(_fp) (P2P_ATTRI_HDR_LEN + ATTRI_LEN(_fp)) + +#define ATTRI_FOR_EACH(_pucAttriBuf, _u2AttriBufLen, _u2Offset) \ + for ((_u2Offset) = 0; ((_u2Offset) < (_u2AttriBufLen)); \ + (_u2Offset) += ATTRI_SIZE(_pucAttriBuf), ((_pucAttriBuf) += ATTRI_SIZE(_pucAttriBuf)) ) + + +#define P2P_IE(_fp) ((P_IE_P2P_T) _fp) + + +#define WSC_ATTRI_ID(_fp) \ + (((UINT_16) ((PUINT_8)&((P_WSC_ATTRIBUTE_T) _fp)->u2Id)[0] << 8) | \ + ((UINT_16) ((PUINT_8)&((P_WSC_ATTRIBUTE_T) _fp)->u2Id)[1])) + +#define WSC_ATTRI_LEN(_fp) \ + (((UINT_16) ((PUINT_8)&((P_WSC_ATTRIBUTE_T) _fp)->u2Length)[0] << 8) | \ + ((UINT_16) ((PUINT_8)&((P_WSC_ATTRIBUTE_T) _fp)->u2Length)[1])) + + +#define WSC_ATTRI_SIZE(_fp) (WSC_ATTRI_HDR_LEN + WSC_ATTRI_LEN(_fp)) + +#define WSC_ATTRI_FOR_EACH(_pucAttriBuf, _u2AttriBufLen, _u2Offset) \ + for ((_u2Offset) = 0; ((_u2Offset) < (_u2AttriBufLen)); \ + (_u2Offset) += WSC_ATTRI_SIZE(_pucAttriBuf), ((_pucAttriBuf) += WSC_ATTRI_SIZE(_pucAttriBuf)) ) + +#define WSC_IE(_fp) ((P_IE_P2P_T) _fp) + + + +#if DBG + #define ASSERT_BREAK(_exp) \ + { \ + if (!(_exp)) { \ + ASSERT(FALSE); \ + break; \ + } \ + } + +#else + #define ASSERT_BREAK(_exp) +#endif + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/*======P2P State======*/ +VOID +p2pStateInit_LISTEN( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN P_P2P_SPECIFIC_BSS_INFO_T prSP2pBssInfo, + IN UINT_8 ucListenChannel + ); + +VOID +p2pStateAbort_LISTEN( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsChannelExtenstion + ); + +VOID +p2pStateAbort_SEARCH_SCAN( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsChannelExtenstion + ); + +VOID +p2pStateAbort_GO_OPERATION( + IN P_ADAPTER_T prAdapter + ); + +VOID +p2pStateAbort_GC_OPERATION( + IN P_ADAPTER_T prAdapter + ); + +VOID +p2pStateInit_CONFIGURATION( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN P_BSS_INFO_T prP2pBssInfo, + IN P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecBssInfo + ); + +VOID +p2pStateAbort_CONFIGURATION( + IN P_ADAPTER_T prAdapter + ); + +VOID +p2pStateInit_JOIN( + IN P_ADAPTER_T prAdapter + ); + +VOID +p2pStateAbort_JOIN( + IN P_ADAPTER_T prAdapter + ); + +/*====== P2P Functions ======*/ + + +VOID +p2pFuncInitGO( + IN P_ADAPTER_T prAdapter + ); + + + + + +VOID +p2pFuncDisconnect( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN BOOLEAN fgSendDeauth, + IN UINT_16 u2ReasonCode + ); + +VOID +p2pFuncSwitchOPMode( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN ENUM_OP_MODE_T eOpMode, + IN BOOLEAN fgSyncToFW + ); + +VOID +p2pFuncRunEventProvisioningComplete( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + +WLAN_STATUS +p2pFuncSetGroupID( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucGroupID, + IN PUINT_8 pucSsid, + IN UINT_8 ucSsidLen + ); + + +WLAN_STATUS +p2pFuncSendDeviceDiscoverabilityReqFrame( + IN P_ADAPTER_T prAdapter, + IN UINT_8 aucDestAddr[], + IN UINT_8 ucDialogToken + ); + +WLAN_STATUS +p2pFuncSendDeviceDiscoverabilityRspFrame( + IN P_ADAPTER_T prAdapter, + IN UINT_8 aucDestAddr[], + IN UINT_8 ucDialogToken + ); + + +UINT_8 +p2pFuncGetVersionNumOfSD( + IN P_ADAPTER_T prAdapter + ); + +/*====== P2P FSM ======*/ +VOID +p2pFsmRunEventConnectionRequest( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + +VOID +p2pFsmRunEventDeviceDiscoveryRequest( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + +VOID +p2pFsmRunEventDeviceDiscoveryAbort( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + +VOID +p2pFsmRunEventRxGroupNegotiationReqFrame( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + +WLAN_STATUS +p2pFsmRunEventGroupNegotiationRequestTxDone( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus + ); + +WLAN_STATUS +p2pFsmRunEventGroupNegotiationResponseTxDone( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus + ); + +WLAN_STATUS +p2pFsmRunEventGroupNegotiationConfirmTxDone( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus + ); + +WLAN_STATUS +p2pFsmRunEventProvisionDiscoveryRequestTxDone( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus + ); + +WLAN_STATUS +p2pFsmRunEventProvisionDiscoveryResponseTxDone( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus + ); + + +WLAN_STATUS +p2pFsmRunEventInvitationRequestTxDone ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus + ); + + + +VOID +p2pFsmRunEventRxDeauthentication( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prSwRfb + ); + +VOID +p2pFsmRunEventRxDisassociation( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prSwRfb + ); + +VOID +p2pFsmRunEventBeaconTimeout( + IN P_ADAPTER_T prAdapter + ); + + + +WLAN_STATUS +p2pFsmRunEventDeauthTxDone( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus + ); + + +#if 1 +#endif + + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +/*======Mail Box Event Message=====*/ + + +VOID +p2pFsmRunEventConnectionAbort( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + +VOID +p2pFsmRunEventConnectionTrigger( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + + +VOID +p2pFsmRunEventP2PFunctionSwitch( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + +VOID +p2pFsmRunEventChGrant( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + +VOID +p2pFsmRunEventJoinComplete( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + +VOID +p2pFsmRunEventConnectionPause( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + +VOID +p2pIndicationOfMediaStateToHost( + IN P_ADAPTER_T prAdapter, + IN ENUM_PARAM_MEDIA_STATE_T eConnectionState, + IN UINT_8 aucTargetAddr[] + ); + +VOID +p2pUpdateBssInfoForJOIN( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prAssocRspSwRfb + ); + +/*======Mail Box Event Message=====*/ + + +VOID +p2pFsmInit( + IN P_ADAPTER_T prAdapter + ); + +VOID +p2pFsmUninit( + IN P_ADAPTER_T prAdapter + ); + +VOID +p2pFsmSteps( + IN P_ADAPTER_T prAdapter, + IN ENUM_P2P_STATE_T eNextState + ); + +VOID +p2pStartGO( + IN P_ADAPTER_T prAdapter + ); + +VOID +p2pAssignSsid( + IN PUINT_8 pucSsid, + IN PUINT_8 pucSsidLen + ); + +VOID +p2pFsmRunEventScanDone( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + +VOID +p2pFsmRunEventIOReqTimeout( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Param + ); + +VOID +p2pFsmRunEventSearchPeriodTimeout( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Param + ); + +VOID +p2pFsmRunEventFsmTimeout( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Param + ); + +VOID +p2pFsmRunEventRejoinTimeout( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Parm + ); + + + + +/*=============== P2P Function Related ================*/ + +/*=============== P2P Function Related ================*/ + + +#if CFG_TEST_WIFI_DIRECT_GO +VOID +p2pTest( + IN P_ADAPTER_T prAdapter + ); +#endif /* CFG_TEST_WIFI_DIRECT_GO */ + + + + +VOID +p2pGenerateP2P_IEForBeacon( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + +VOID +p2pGenerateP2P_IEForAssocReq( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + +VOID +p2pGenerateP2P_IEForAssocRsp( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + + +VOID +p2pGenerateP2P_IEForProbeReq( + IN P_ADAPTER_T prAdapter, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + + + + +UINT_32 +p2pCalculateP2P_IELenForBeacon( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec + ); + +UINT_32 +p2pCalculateP2P_IELenForAssocRsp( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec + ); + + +UINT_32 +p2pCalculateP2P_IELenForProbeReq( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec + ); + + + +VOID +p2pGenerateWSC_IEForProbeResp( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + +VOID +p2pGenerateWSC_IEForProbeReq( + IN P_ADAPTER_T prAdapter, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + + + +UINT_16 +p2pCalculateWSC_IELenForProbeReq( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex + ); + +UINT_32 +p2pCalculateWSC_IELenForProbeResp( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec + ); + +UINT_32 +p2pAppendAttriStatus( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + + + +UINT_32 +p2pAppendAttriCapability( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + +UINT_32 +p2pAppendAttriGoIntent( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + +UINT_32 +p2pAppendAttriCfgTimeout( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + +UINT_32 +p2pAppendAttriGroupBssid( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + + +UINT_32 +p2pAppendAttriDeviceIDForBeacon( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + +UINT_32 +p2pAppendAttriDeviceIDForProbeReq( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + +UINT_32 +p2pAppendAttriDeviceIDForDeviceDiscoveryReq( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + +UINT_32 +p2pAppendAttriListenChannel( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + +UINT_32 +p2pAppendAttriIntendP2pIfAddr( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + + +UINT_32 +p2pAppendAttriChannelList( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + +UINT_32 +p2pCalculateAttriLenChannelList( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ); + +UINT_32 +p2pAppendAttriNoA( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + +UINT_32 +p2pAppendAttriDeviceInfo( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + +UINT_32 +p2pCalculateAttriLenDeviceInfo( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ); + +UINT_32 +p2pAppendAttriGroupInfo( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + +UINT_32 +p2pCalculateAttriLenGroupInfo( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ); + + +UINT_32 +p2pAppendAttriP2pGroupID( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + +UINT_32 +p2pAppendAttriOperatingChannel( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + +UINT_32 +p2pAppendAttriInvitationFlag( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + + +VOID +p2pGenerateWscIE ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucOuiType, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize, + IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], + IN UINT_32 u4AttriTableSize + ); + +UINT_32 +p2pAppendAttriWSCConfigMethod ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + +UINT_32 +p2pAppendAttriWSCVersion ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + +UINT_32 +p2pAppendAttriWSCGONegReqDevPasswordId ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + +UINT_32 +p2pAppendAttriWSCGONegRspDevPasswordId ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + +WLAN_STATUS +p2pGetWscAttriList( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucOuiType, + IN PUINT_8 pucIE, + IN UINT_16 u2IELength, + OUT PPUINT_8 ppucAttriList, + OUT PUINT_16 pu2AttriListLen + ); + +WLAN_STATUS +p2pGetAttriList ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucOuiType, + IN PUINT_8 pucIE, + IN UINT_16 u2IELength, + OUT PPUINT_8 ppucAttriList, + OUT PUINT_16 pu2AttriListLen + ); + +VOID +p2pRunEventAAATxFail ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ); + +WLAN_STATUS +p2pRunEventAAASuccess ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ); + + +WLAN_STATUS +p2pRunEventAAAComplete ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ); + +WLAN_STATUS +p2pSendProbeResponseFrame( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + +BOOLEAN +p2pFsmRunEventRxProbeRequestFrame( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + +VOID +p2pFsmRunEventRxProbeResponseFrame( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN P_BSS_DESC_T prBssDesc + ); + +WLAN_STATUS +p2pRxPublicActionFrame( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + +WLAN_STATUS +p2pRxActionFrame( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + +VOID +p2pFsmRunEventRxGroupNegotiationRspFrame( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + +VOID +p2pFsmRunEventRxGroupNegotiationCfmFrame( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + + +#if 0 // frog +BOOLEAN +scanMatchFilterOfP2P ( + IN P_SW_RFB_T prSWRfb, + IN PP_BSS_DESC_T pprBssDesc + ); +#endif // frog + +VOID +p2pProcessEvent_UpdateNOAParam ( + IN P_ADAPTER_T prAdapter, + UINT_8 ucNetTypeIndex, + P_EVENT_UPDATE_NOA_PARAMS_T prEventUpdateNoaParam + ); + +VOID +p2pFuncCompleteIOCTL( + IN P_ADAPTER_T prAdapter, + IN WLAN_STATUS rWlanStatus + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#ifndef _lint +/* Kevin: we don't have to call following function to inspect the data structure. + * It will check automatically while at compile time. + * We'll need this for porting driver to different RTOS. + */ +__KAL_INLINE__ VOID +p2pDataTypeCheck ( + VOID + ) +{ + DATA_STRUC_INSPECTING_ASSERT(sizeof(IE_P2P_T) == (2+4+1)); // all UINT_8 + DATA_STRUC_INSPECTING_ASSERT(sizeof(P2P_ATTRIBUTE_T) == (3+1)); + DATA_STRUC_INSPECTING_ASSERT(sizeof(P2P_ATTRI_STATUS_T) == (3+1)); + DATA_STRUC_INSPECTING_ASSERT(sizeof(P2P_ATTRI_REASON_T) == (3+1)); + DATA_STRUC_INSPECTING_ASSERT(sizeof(P2P_ATTRI_CAPABILITY_T) == (3+2)); + DATA_STRUC_INSPECTING_ASSERT(sizeof(P2P_ATTRI_DEV_ID_T) == (3+6)); + DATA_STRUC_INSPECTING_ASSERT(sizeof(P2P_ATTRI_GO_INTENT_T) == (3+1)); + DATA_STRUC_INSPECTING_ASSERT(sizeof(P2P_ATTRI_CFG_TIMEOUT_T) == (3+2)); +#if CID52_53_54 + DATA_STRUC_INSPECTING_ASSERT(sizeof(P2P_ATTRI_LISTEN_CHANNEL_T) == (3+5)); +#else + DATA_STRUC_INSPECTING_ASSERT(sizeof(P2P_ATTRI_LISTEN_CHANNEL_T) == (3+5)); +#endif + DATA_STRUC_INSPECTING_ASSERT(sizeof(P2P_ATTRI_GROUP_BSSID_T) == (3+6)); + DATA_STRUC_INSPECTING_ASSERT(sizeof(P2P_ATTRI_EXT_LISTEN_TIMING_T) == (3+4)); + DATA_STRUC_INSPECTING_ASSERT(sizeof(P2P_ATTRI_INTENDED_IF_ADDR_T) == (3+6)); + DATA_STRUC_INSPECTING_ASSERT(sizeof(P2P_ATTRI_MANAGEABILITY_T) == (3+1)); + + DATA_STRUC_INSPECTING_ASSERT(sizeof(P2P_ATTRI_CHANNEL_T) == (3+4)); + DATA_STRUC_INSPECTING_ASSERT(sizeof(CHANNEL_ENTRY_FIELD_T) == 3); + DATA_STRUC_INSPECTING_ASSERT(sizeof(P2P_ATTRI_NOA_T) == (3+3)); + DATA_STRUC_INSPECTING_ASSERT(sizeof(NOA_DESCRIPTOR_T) == 13); + DATA_STRUC_INSPECTING_ASSERT(sizeof(DEVICE_TYPE_T) == 8); + DATA_STRUC_INSPECTING_ASSERT(sizeof(P2P_ATTRI_DEV_INFO_T) == (3+6+2+8+1+8)); + DATA_STRUC_INSPECTING_ASSERT(sizeof(DEVICE_NAME_TLV_T) == (4+32)); + DATA_STRUC_INSPECTING_ASSERT(sizeof(P2P_CLIENT_INFO_DESC_T) == (1+6+6+1+2+8+1+8)); + DATA_STRUC_INSPECTING_ASSERT(sizeof(P2P_ATTRI_GROUP_INFO_T) == (3+(1+6+6+1+2+8+1+8))); + DATA_STRUC_INSPECTING_ASSERT(sizeof(P2P_ATTRI_GROUP_ID_T) == (3+38)); + DATA_STRUC_INSPECTING_ASSERT(sizeof(P2P_ATTRI_INTERFACE_T) == (3+13)); +#if CID52_53_54 + DATA_STRUC_INSPECTING_ASSERT(sizeof(P2P_ATTRI_OPERATING_CHANNEL_T) == (3+5)); +#else + DATA_STRUC_INSPECTING_ASSERT(sizeof(P2P_ATTRI_OPERATING_CHANNEL_T) == (3+5)); +#endif + + + return; +} +#endif /* _lint */ + +#endif /* _P2P_FSM_H */ + + + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_func.h b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_func.h new file mode 100755 index 000000000000..524d100ad457 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_func.h @@ -0,0 +1,284 @@ + + + +#ifndef _P2P_FUNC_H +#define _P2P_FUNC_H + + +VOID +p2pFuncRequestScan( + IN P_ADAPTER_T prAdapter, + IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo + ); + +VOID +p2pFuncCancelScan( + IN P_ADAPTER_T prAdapter, + IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo + ); + + + +VOID +p2pFuncStartGO( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN PUINT_8 pucSsidBuf, + IN UINT_8 ucSsidLen, + IN UINT_8 ucChannelNum, + IN ENUM_BAND_T eBand, + IN ENUM_CHNL_EXT_T eSco, + IN BOOLEAN fgIsPureAP + ); + + + +VOID +p2pFuncAcquireCh( + IN P_ADAPTER_T prAdapter, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo + ); + + +VOID +p2pFuncReleaseCh( + IN P_ADAPTER_T prAdapter, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo + ); + +VOID +p2pFuncSetChannel( + IN P_ADAPTER_T prAdapter, + IN P_RF_CHANNEL_INFO_T prRfChannelInfo + ); + + +BOOLEAN +p2pFuncRetryJOIN( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_P2P_JOIN_INFO_T prJoinInfo + ); + +VOID +p2pFuncUpdateBssInfoForJOIN ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prAssocRspSwRfb + ); + + +WLAN_STATUS +p2pFuncTxMgmtFrame( + IN P_ADAPTER_T prAdapter, + IN P_P2P_MGMT_TX_REQ_INFO_T prMgmtTxReqInfo, + IN P_MSDU_INFO_T prMgmtTxMsdu, + IN UINT_64 u8Cookie + ); + +WLAN_STATUS +p2pFuncBeaconUpdate( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN P_P2P_BEACON_UPDATE_INFO_T prBcnUpdateInfo, + IN PUINT_8 pucNewBcnHdr, + IN UINT_32 u4NewHdrLen, + IN PUINT_8 pucNewBcnBody, + IN UINT_32 u4NewBodyLen + ); + + +BOOLEAN +p2pFuncValidateAuth( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN PP_STA_RECORD_T pprStaRec, + OUT PUINT_16 pu2StatusCode + ); + +BOOLEAN +p2pFuncValidateAssocReq( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT PUINT_16 pu2StatusCode + ); + + +VOID +p2pFuncResetStaRecStatus( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ); + +VOID +p2pFuncInitConnectionSettings( + IN P_ADAPTER_T prAdapter, + IN P_P2P_CONNECTION_SETTINGS_T prP2PConnSettings + ); + + +BOOLEAN +p2pFuncParseCheckForP2PInfoElem( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucBuf, + OUT PUINT_8 pucOuiType + ); + + +BOOLEAN +p2pFuncValidateProbeReq( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT PUINT_32 pu4ControlFlags + ); + +VOID +p2pFuncValidateRxActionFrame( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + +BOOLEAN +p2pFuncIsAPMode( + IN P_P2P_FSM_INFO_T prP2pFsmInfo + ); + + +VOID +p2pFuncParseBeaconContent( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN PUINT_8 pucIEInfo, + IN UINT_32 u4IELen + ); + + +P_BSS_DESC_T +p2pFuncKeepOnConnection( + + IN P_ADAPTER_T prAdapter, + IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, + IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo + ); + + +VOID +p2pFuncStoreAssocRspIEBuffer( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + + +VOID +p2pFuncMgmtFrameRegister( + IN P_ADAPTER_T prAdapter, + IN UINT_16 u2FrameType, + IN BOOLEAN fgIsRegistered, + OUT PUINT_32 pu4P2pPacketFilter + ); + +VOID +p2pFuncGetStationInfo( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucMacAddr, + OUT P_P2P_STATION_INFO_T prStaInfo + ); + +P_MSDU_INFO_T +p2pFuncProcessP2pProbeRsp( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMgmtTxMsdu + ); + +UINT_32 +p2pFuncCalculateP2p_IELenForBeacon( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec + ); + + +VOID +p2pFuncGenerateP2p_IEForBeacon( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + +UINT_32 +p2pFuncCalculateP2p_IELenForAssocRsp( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec + ); + +VOID +p2pFuncGenerateP2p_IEForAssocRsp( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + +UINT_32 +p2pFuncCalculateWSC_IELenForBeacon( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec + ); + +VOID +p2pFuncGenerateWSC_IEForBeacon( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + +UINT_32 +p2pFuncCalculateP2P_IELen( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec, + IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], + IN UINT_32 u4AttriTableSize + ); + +VOID +p2pFuncGenerateP2P_IE( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize, + IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], + IN UINT_32 u4AttriTableSize + ); + + + +UINT_32 +p2pFuncAppendAttriStatusForAssocRsp( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + + +UINT_32 +p2pFuncAppendAttriExtListenTiming( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ); + +VOID +p2pFuncDissolve( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN BOOLEAN fgSendDeauth, + IN UINT_16 u2ReasonCode + ); + +#endif diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_ie.h b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_ie.h new file mode 100755 index 000000000000..fe0dc1bd3a26 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_ie.h @@ -0,0 +1,28 @@ + + + + + +#ifndef _P2P_IE_H +#define _P2P_IE_H + + +UINT_32 +p2pCalculate_IEForAssocReq( + + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec + ); + + +VOID +p2pGenerate_IEForAssocReq( + + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + + + +#endif diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_rlm.h b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_rlm.h new file mode 100755 index 000000000000..5f1a02cb173e --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_rlm.h @@ -0,0 +1,149 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/WIFI_P2P_DRIVER_V2_2/include/mgmt/p2p_rlm.h#1 $ +*/ + +/*! \file "rlm.h" + \brief +*/ + +/******************************************************************************* +* Copyright (c) 2010 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + + +#ifndef _P2P_RLM_H +#define _P2P_RLM_H + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +VOID +rlmBssInitForAP( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo + ); + +BOOLEAN +rlmUpdateBwByChListForAP ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo + ); + +VOID +rlmUpdateParamsForAP ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + BOOLEAN fgUpdateBeacon + ); + +VOID +rlmFuncInitialChannelList( + IN P_ADAPTER_T prAdapter + ); + +VOID +rlmFuncCommonChannelList( + IN P_ADAPTER_T prAdapter, + IN P_CHANNEL_ENTRY_FIELD_T prChannelEntryII, + IN UINT_8 ucChannelListSize + ); + +UINT_8 +rlmFuncFindOperatingClass( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucChannelNum + ); + +BOOLEAN +rlmFuncFindAvailableChannel( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucCheckChnl, + IN PUINT_8 pucSuggestChannel, + IN BOOLEAN fgIsSocialChannel, + IN BOOLEAN fgIsDefaultChannel + ); + +ENUM_CHNL_EXT_T +rlmDecideScoForAP ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo + ); + +#endif diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_rlm_obss.h b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_rlm_obss.h new file mode 100755 index 000000000000..2773c152d7e9 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_rlm_obss.h @@ -0,0 +1,133 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/WIFI_P2P_DRIVER_V2_2/include/mgmt/p2p_rlm_obss.h#1 $ +*/ + +/*! \file "rlm_obss.h" + \brief +*/ + +/******************************************************************************* +* Copyright (c) 2010 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +#ifndef _P2P_RLM_OBSS_H +#define _P2P_RLM_OBSS_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +VOID +rlmRspGenerateObssScanIE ( + P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo + ); + +VOID +rlmProcessPublicAction ( + P_ADAPTER_T prAdapter, + P_SW_RFB_T prSwRfb + ); + +VOID +rlmProcessHtAction ( + P_ADAPTER_T prAdapter, + P_SW_RFB_T prSwRfb + ); + +VOID +rlmHandleObssStatusEventPkt ( + P_ADAPTER_T prAdapter, + P_EVENT_AP_OBSS_STATUS_T prObssStatus + ); + +UINT_8 +rlmObssChnlLevel ( + P_BSS_INFO_T prBssInfo, + ENUM_BAND_T eBand, + UINT_8 ucPriChannel, + ENUM_CHNL_EXT_T eExtend + ); + +VOID +rlmObssScanExemptionRsp ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_SW_RFB_T prSwRfb + ); + +#endif diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_scan.h b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_scan.h new file mode 100755 index 000000000000..96a306378245 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_scan.h @@ -0,0 +1,167 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/WIFI_P2P_DRIVER_V2_2/include/mgmt/p2p_scan.h#2 $ +*/ + +/*! \file "scan.h" + \brief + +*/ + + +/******************************************************************************* +* Copyright (c) 2010 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +#ifndef _P2P_SCAN_H +#define _P2P_SCAN_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +WLAN_STATUS +scanSendDeviceDiscoverEvent ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc, + IN P_SW_RFB_T prSwRfb + ); + +P_P2P_DEVICE_DESC_T +scanSearchTargetP2pDesc( + IN P_ADAPTER_T prAdapter, + IN UINT_8 aucDeviceID[], + IN PP_BSS_DESC_T pprBssDesc + ); + +P_P2P_DEVICE_DESC_T +scanFindP2pDeviceDesc( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc, + IN UINT_8 aucMacAddr[], + IN BOOLEAN fgIsDeviceAddr, + IN BOOLEAN fgAddIfNoFound + ); + +P_P2P_DEVICE_DESC_T +scanGetP2pDeviceDesc( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc + ); + +VOID +scnEventReturnChannel( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucScnSeqNum + ); + +BOOLEAN +scanUpdateP2pDeviceDesc ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc + ); + +VOID +scanP2pProcessBeaconAndProbeResp( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN P_WLAN_STATUS prStatus, + IN P_BSS_DESC_T prBssDesc, + IN P_WLAN_BEACON_FRAME_T prWlanBeaconFrame + ); + +VOID +scanRemoveAllP2pBssDesc( + P_ADAPTER_T prAdapter + ); + +VOID +scanRemoveP2pBssDesc( + P_ADAPTER_T prAdapter, + P_BSS_DESC_T prBssDesc + ); + + +P_BSS_DESC_T +scanP2pSearchDesc( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo + ); + + + +#endif diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_state.h b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_state.h new file mode 100755 index 000000000000..0fccdcdcb14c --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/mgmt/p2p_state.h @@ -0,0 +1,88 @@ + +#ifndef _P2P_STATE_H +#define _P2P_STATE_H + +BOOLEAN +p2pStateInit_IDLE( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN P_BSS_INFO_T prP2pBssInfo, + OUT P_ENUM_P2P_STATE_T peNextState + ); + + +VOID +p2pStateAbort_IDLE( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN ENUM_P2P_STATE_T eNextState + ); + +VOID +p2pStateInit_SCAN( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo + ); + +VOID +p2pStateAbort_SCAN( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN ENUM_P2P_STATE_T eNextState + ); + +VOID +p2pStateInit_AP_CHANNEL_DETECT( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo + ); + +VOID +p2pStateAbort_AP_CHANNEL_DETECT( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo, + IN ENUM_P2P_STATE_T eNextState + ); + +VOID +p2pStateInit_CHNL_ON_HAND( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo + ); + +VOID +p2pStateAbort_CHNL_ON_HAND( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN ENUM_P2P_STATE_T eNextState + ); + + +VOID +p2pStateAbort_REQING_CHANNEL( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN ENUM_P2P_STATE_T eNextState + ); + + +VOID +p2pStateInit_GC_JOIN( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN P_BSS_INFO_T prP2pBssInfo, + IN P_P2P_JOIN_INFO_T prJoinInfo, + IN P_BSS_DESC_T prBssDesc + ); + +VOID +p2pStateAbort_GC_JOIN( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN P_P2P_JOIN_INFO_T prJoinInfo, + IN ENUM_P2P_STATE_T eNextState + ); + +#endif + diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/include/nic/p2p.h b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/nic/p2p.h new file mode 100755 index 000000000000..c63fae0a9930 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/nic/p2p.h @@ -0,0 +1,235 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/WIFI_P2P_DRIVER_V2_2/include/nic/p2p.h#1 $ +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: p2p.h $ + * + * 03 19 2011 terry.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 p2p driver release based on label "MT6620_WIFI_P2P_DRIVER_V2_0_2100_0319_2011" from main trunk. + * + * 10 20 2010 wh.su + * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group + * Add the code to support disconnect p2p group + * + * 09 21 2010 kevin.huang + * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface + * Isolate P2P related function for Hardware Software Bundle + * + * 08 03 2010 cp.wu + * NULL + * [Wi-Fi Direct] add framework for driver hooks + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 23 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * p2p interface revised to be sync. with HAL + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 18 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add parameter to control: + * 1) auto group owner + * 2) P2P-PS parameter (CTWindow, NoA descriptors) + * + * 05 18 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * correct WPS Device Password ID definition. + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * implement get scan result. + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add basic handling framework for wireless extension ioctls. + * + * 05 14 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add ioctl framework for Wi-Fi Direct by reusing wireless extension ioctls as well + * + * 05 11 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * p2p ioctls revised. + * + * 05 10 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * implement basic wi-fi direct framework + * + * 05 07 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add basic framework for implementating P2P driver hook. + * + * +*/ + +#ifndef _P2P_H +#define _P2P_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +// refer to 'Config Methods' in WPS +#define WPS_CONFIG_USBA 0x0001 +#define WPS_CONFIG_ETHERNET 0x0002 +#define WPS_CONFIG_LABEL 0x0004 +#define WPS_CONFIG_DISPLAY 0x0008 +#define WPS_CONFIG_EXT_NFC 0x0010 +#define WPS_CONFIG_INT_NFC 0x0020 +#define WPS_CONFIG_NFC 0x0040 +#define WPS_CONFIG_PBC 0x0080 +#define WPS_CONFIG_KEYPAD 0x0100 + +// refer to 'Device Password ID' in WPS +#define WPS_DEV_PASSWORD_ID_PIN 0x0000 +#define WPS_DEV_PASSWORD_ID_USER 0x0001 +#define WPS_DEV_PASSWORD_ID_MACHINE 0x0002 +#define WPS_DEV_PASSWORD_ID_REKEY 0x0003 +#define WPS_DEV_PASSWORD_ID_PUSHBUTTON 0x0004 +#define WPS_DEV_PASSWORD_ID_REGISTRAR 0x0005 + + +#define P2P_DEVICE_TYPE_NUM 2 +#define P2P_DEVICE_NAME_LENGTH 32 +#define P2P_NETWORK_NUM 8 +#define P2P_MEMBER_NUM 8 + +#define P2P_WILDCARD_SSID "DIRECT-" + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +struct _P2P_INFO_T { + UINT_32 u4DeviceNum; + EVENT_P2P_DEV_DISCOVER_RESULT_T arP2pDiscoverResult[CFG_MAX_NUM_BSS_LIST]; + PUINT_8 pucCurrIePtr; + UINT_8 aucCommIePool[CFG_MAX_COMMON_IE_BUF_LEN]; /* A common pool for IE of all scan results. */ +}; + +typedef enum { + ENUM_P2P_PEER_GROUP, + ENUM_P2P_PEER_DEVICE, + ENUM_P2P_PEER_NUM +} ENUM_P2P_PEER_TYPE, *P_ENUM_P2P_PEER_TYPE; + +typedef struct _P2P_DEVICE_INFO { + UINT_8 aucDevAddr[PARAM_MAC_ADDR_LEN]; + UINT_8 aucIfAddr[PARAM_MAC_ADDR_LEN]; + UINT_8 ucDevCapabilityBitmap; + INT_32 i4ConfigMethod; + UINT_8 aucPrimaryDeviceType[8]; + UINT_8 aucSecondaryDeviceType[8]; + UINT_8 aucDeviceName[P2P_DEVICE_NAME_LENGTH]; +} P2P_DEVICE_INFO, *P_P2P_DEVICE_INFO; + +typedef struct _P2P_GROUP_INFO { + PARAM_SSID_T rGroupID; + P2P_DEVICE_INFO rGroupOwnerInfo; + UINT_8 ucMemberNum; + P2P_DEVICE_INFO arMemberInfo[P2P_MEMBER_NUM]; +} P2P_GROUP_INFO, *P_P2P_GROUP_INFO; + +typedef struct _P2P_NETWORK_INFO { + ENUM_P2P_PEER_TYPE eNodeType; + + union { + P2P_GROUP_INFO rGroupInfo; + P2P_DEVICE_INFO rDeviceInfo; + } node; + +} P2P_NETWORK_INFO, *P_P2P_NETWORK_INFO; + +typedef struct _P2P_NETWORK_LIST { + UINT_8 ucNetworkNum; + P2P_NETWORK_INFO rP2PNetworkInfo[P2P_NETWORK_NUM]; +} P2P_NETWORK_LIST, *P_P2P_NETWORK_LIST; + +typedef struct _P2P_DISCONNECT_INFO { + UINT_8 ucRole; + UINT_8 ucRsv[3]; +} P2P_DISCONNECT_INFO, *P_P2P_DISCONNECT_INFO; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +#endif /*_P2P_H */ diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/include/nic/p2p_cmd_buf.h b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/nic/p2p_cmd_buf.h new file mode 100755 index 000000000000..cd91f339b59a --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/nic/p2p_cmd_buf.h @@ -0,0 +1,137 @@ +/* +** $Id: +*/ + +/*! \file "p2p_cmd_buf.h" + \brief In this file we define the structure for Command Packet. + + In this file we define the structure for Command Packet and the control unit + of MGMT Memory Pool. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: p2p_cmd_buf.h $ + * + * 11 24 2011 yuche.tsai + * NULL + * Fix P2P IOCTL of multicast address bug, add low power driver stop control. + * + * 03 19 2011 terry.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 p2p driver release based on label "MT6620_WIFI_P2P_DRIVER_V2_0_2100_0319_2011" from main trunk. + * + * 12 22 2010 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service Discovery + * 1. header file restructure for more clear module isolation + * 2. add function interface definition for implementing Service Discovery callbacks +*/ + +#ifndef _P2P_CMD_BUF_H +#define _P2P_CMD_BUF_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/*--------------------------------------------------------------*/ +/* Firmware Command Packer */ +/*--------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSendSetQueryP2PCmd ( + IN P_ADAPTER_T prAdapter, + UINT_8 ucCID, + BOOLEAN fgSetQuery, + BOOLEAN fgNeedResp, + BOOLEAN fgIsOid, + PFN_CMD_DONE_HANDLER pfCmdDoneHandler, + PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, + UINT_32 u4SetQueryInfoLen, + PUINT_8 pucInfoBuffer, + OUT PVOID pvSetQueryBuffer, + IN UINT_32 u4SetQueryBufferLen + ); + + + + +#endif /* _P2P_CMD_BUF_H */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/include/nic/p2p_mac.h b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/nic/p2p_mac.h new file mode 100755 index 000000000000..e52e8da45205 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/nic/p2p_mac.h @@ -0,0 +1,263 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/WIFI_P2P_DRIVER_V2_2/include/nic/p2p_mac.h#1 $ +*/ + +/*! \file "p2p_mac.h" + \brief Brief description. + + Detail description. +*/ + + +/******************************************************************************* +* Copyright (c) 2010 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + + +#ifndef _P2P_MAC_H +#define _P2P_MAC_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define ACTION_PUBLIC_WIFI_DIRECT 9 +#define ACTION_GAS_INITIAL_REQUEST 10 +#define ACTION_GAS_INITIAL_RESPONSE 11 +#define ACTION_GAS_COMEBACK_REQUEST 12 +#define ACTION_GAS_COMEBACK_RESPONSE 13 + + +/* P2P 4.2.8.1 - P2P Public Action Frame Type. */ +#define P2P_PUBLIC_ACTION_GO_NEGO_REQ 0 +#define P2P_PUBLIC_ACTION_GO_NEGO_RSP 1 +#define P2P_PUBLIC_ACTION_GO_NEGO_CFM 2 +#define P2P_PUBLIC_ACTION_INVITATION_REQ 3 +#define P2P_PUBLIC_ACTION_INVITATION_RSP 4 +#define P2P_PUBLIC_ACTION_DEV_DISCOVER_REQ 5 +#define P2P_PUBLIC_ACTION_DEV_DISCOVER_RSP 6 +#define P2P_PUBLIC_ACTION_PROV_DISCOVERY_REQ 7 +#define P2P_PUBLIC_ACTION_PROV_DISCOVERY_RSP 8 + +/* P2P 4.2.9.1 - P2P Action Frame Type */ +#define P2P_ACTION_NOTICE_OF_ABSENCE 0 +#define P2P_ACTION_P2P_PRESENCE_REQ 1 +#define P2P_ACTION_P2P_PRESENCE_RSP 2 +#define P2P_ACTION_GO_DISCOVER_REQ 3 + +#define P2P_PUBLIC_ACTION_FRAME_LEN (WLAN_MAC_MGMT_HEADER_LEN+8) +#define P2P_ACTION_FRAME_LEN (WLAN_MAC_MGMT_HEADER_LEN+7) + + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +/* P2P 4.2.8.2 P2P Public Action Frame Format */ +typedef struct _P2P_PUBLIC_ACTION_FRAME_T { + /* MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* P2P Public Action Frame Body */ + UINT_8 ucCategory; /* Category, 0x04 */ + UINT_8 ucAction; /* Action Value, 0x09 */ + UINT_8 aucOui[3]; /* 0x50, 0x6F, 0x9A */ + UINT_8 ucOuiType; /* 0x09 */ + UINT_8 ucOuiSubtype; /* GO Nego Req/Rsp/Cfm, P2P Invittion Req/Rsp, Device Discoverability Req/Rsp */ + UINT_8 ucDialogToken; /* Dialog Token. */ + UINT_8 aucInfoElem[1]; /* P2P IE, WSC IE. */ +} __KAL_ATTRIB_PACKED__ P2P_PUBLIC_ACTION_FRAME_T, *P_P2P_PUBLIC_ACTION_FRAME_T; + + +/* P2P 4.2.9.1 - General Action Frame Format. */ +typedef struct _P2P_ACTION_FRAME_T { + /* MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* P2P Action Frame Body */ + UINT_8 ucCategory; // 0x7F + UINT_8 aucOui[3]; // 0x50, 0x6F, 0x9A + UINT_8 ucOuiType; // 0x09 + UINT_8 ucOuiSubtype; // + UINT_8 ucDialogToken; + UINT_8 aucInfoElem[1]; +} __KAL_ATTRIB_PACKED__ P2P_ACTION_FRAME_T, *P_P2P_ACTION_FRAME_T; + +/* P2P C.1 GAS Public Action Initial Request Frame Format */ +typedef struct _GAS_PUBLIC_ACTION_INITIAL_REQUEST_FRAME_T { + /* MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* P2P Public Action Frame Body */ + UINT_8 ucCategory; /* Category, 0x04 */ + UINT_8 ucAction; /* Action Value, 0x09 */ + UINT_8 ucDialogToken; /* Dialog Token. */ + UINT_8 aucInfoElem[1]; /* Advertisement IE. */ +} __KAL_ATTRIB_PACKED__ GAS_PUBLIC_ACTION_INITIAL_REQUEST_FRAME_T, *P_GAS_PUBLIC_ACTION_INITIAL_REQUEST_FRAME_T; + +/* P2P C.2 GAS Public Action Initial Response Frame Format */ +typedef struct _GAS_PUBLIC_ACTION_INITIAL_RESPONSE_FRAME_T { + /* MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* P2P Public Action Frame Body */ + UINT_8 ucCategory; /* Category, 0x04 */ + UINT_8 ucAction; /* Action Value, 0x09 */ + UINT_8 ucDialogToken; /* Dialog Token. */ + UINT_16 u2StatusCode; /* Initial Response. */ + UINT_16 u2ComebackDelay; /* Initial Response. */ /* In unit of TU. */ + UINT_8 aucInfoElem[1]; /* Advertisement IE. */ +} __KAL_ATTRIB_PACKED__ GAS_PUBLIC_ACTION_INITIAL_RESPONSE_FRAME_T, *P_GAS_PUBLIC_ACTION_INITIAL_RESPONSE_FRAME_T; + + +/* P2P C.3-1 GAS Public Action Comeback Request Frame Format */ +typedef struct _GAS_PUBLIC_ACTION_COMEBACK_REQUEST_FRAME_T { + /* MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* P2P Public Action Frame Body */ + UINT_8 ucCategory; /* Category, 0x04 */ + UINT_8 ucAction; /* Action Value, 0x09 */ + UINT_8 ucDialogToken; /* Dialog Token. */ +} __KAL_ATTRIB_PACKED__ GAS_PUBLIC_ACTION_COMEBACK_REQUEST_FRAME_T, *P_GAS_PUBLIC_ACTION_COMEBACK_REQUEST_FRAME_T; + +/* P2P C.3-2 GAS Public Action Comeback Response Frame Format */ +typedef struct _GAS_PUBLIC_ACTION_COMEBACK_RESPONSE_FRAME_T { + /* MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* P2P Public Action Frame Body */ + UINT_8 ucCategory; /* Category, 0x04 */ + UINT_8 ucAction; /* Action Value, 0x09 */ + UINT_8 ucDialogToken; /* Dialog Token. */ + UINT_16 u2StatusCode; /* Comeback Response. */ + UINT_8 ucFragmentID; /*Comeback Response. */ + UINT_16 u2ComebackDelay; /* Comeback Response. */ + UINT_8 aucInfoElem[1]; /* Advertisement IE. */ +} __KAL_ATTRIB_PACKED__ GAS_PUBLIC_ACTION_COMEBACK_RESPONSE_FRAME_T, *P_GAS_PUBLIC_ACTION_COMEBACK_RESPONSE_FRAME_T; + + + + +typedef struct _P2P_SD_VENDER_SPECIFIC_CONTENT_T { + /* Service Discovery Vendor-specific Content. */ + UINT_8 ucOuiSubtype; // 0x09 + UINT_16 u2ServiceUpdateIndicator; + UINT_8 aucServiceTLV[1]; +} __KAL_ATTRIB_PACKED__ P2P_SD_VENDER_SPECIFIC_CONTENT_T, *P_P2P_SD_VENDER_SPECIFIC_CONTENT_T; + + +typedef struct _P2P_SERVICE_REQUEST_TLV_T { + UINT_16 u2Length; + UINT_8 ucServiceProtocolType; + UINT_8 ucServiceTransID; + UINT_8 aucQueryData[1]; +} __KAL_ATTRIB_PACKED__ P2P_SERVICE_REQUEST_TLV_T, *P_P2P_SERVICE_REQUEST_TLV_T; + + + +typedef struct _P2P_SERVICE_RESPONSE_TLV_T { + UINT_16 u2Length; + UINT_8 ucServiceProtocolType; + UINT_8 ucServiceTransID; + UINT_8 ucStatusCode; + UINT_8 aucResponseData[1]; +} __KAL_ATTRIB_PACKED__ P2P_SERVICE_RESPONSE_TLV_T, *P_P2P_SERVICE_RESPONSE_TLV_T; + + +#endif diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/include/nic/p2p_nic.h b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/nic/p2p_nic.h new file mode 100755 index 000000000000..67ec009dc44b --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/nic/p2p_nic.h @@ -0,0 +1,114 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/WIFI_P2P_DRIVER_V2_2/include/nic/p2p_nic.h#1 $ +*/ + +/*! \file "p2p_nic.h" + \brief The declaration of nic functions + + Detail description. +*/ + + +/******************************************************************************* +* Copyright (c) 2010 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + + +#ifndef _P2P_NIC_H +#define _P2P_NIC_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +VOID +nicP2pMediaStateChange( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType, + IN P_EVENT_CONNECTION_STATUS prConnectionStatus + ); + +VOID +nicRxAddP2pDevice( + IN P_ADAPTER_T prAdapter, + IN P_EVENT_P2P_DEV_DISCOVER_RESULT_T prP2pResult, + IN PUINT_8 pucRxIEBuf, + IN UINT_16 u2RxIELength + ); + +#endif diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/include/nic/p2p_nic_cmd_event.h b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/nic/p2p_nic_cmd_event.h new file mode 100755 index 000000000000..e80a69ad8c00 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/nic/p2p_nic_cmd_event.h @@ -0,0 +1,113 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/WIFI_P2P_DRIVER_V2_2/include/nic/p2p_nic_cmd_event.h#1 $ +*/ + +/*! \file p2p_nic_cmd_event.h + \brief +*/ + +/******************************************************************************* +* Copyright (c) 2010 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +#ifndef _P2P_NIC_CMD_EVENT_H +#define _P2P_NIC_CMD_EVENT_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +typedef struct _EVENT_P2P_DEV_DISCOVER_RESULT_T { +// UINT_8 aucCommunicateAddr[MAC_ADDR_LEN]; // Deprecated. + UINT_8 aucDeviceAddr[MAC_ADDR_LEN]; /* Device Address. */ + UINT_8 aucInterfaceAddr[MAC_ADDR_LEN]; /* Device Address. */ + UINT_8 ucDeviceCapabilityBitmap; + UINT_8 ucGroupCapabilityBitmap; + UINT_16 u2ConfigMethod; /* Configure Method. */ + P2P_DEVICE_TYPE_T rPriDevType; + UINT_8 ucSecDevTypeNum; + P2P_DEVICE_TYPE_T arSecDevType[2]; + UINT_16 u2NameLength; + UINT_8 aucName[32]; + PUINT_8 pucIeBuf; + UINT_16 u2IELength; + UINT_8 aucBSSID[MAC_ADDR_LEN]; + // TODO: Service Information or PasswordID valid? +} EVENT_P2P_DEV_DISCOVER_RESULT_T, *P_EVENT_P2P_DEV_DISCOVER_RESULT_T; + +#endif \ No newline at end of file diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/include/p2p_precomp.h b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/p2p_precomp.h new file mode 100755 index 000000000000..b5f0de652798 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/p2p_precomp.h @@ -0,0 +1,265 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/WIFI_P2P_DRIVER_V2_2/include/p2p_precomp.h#4 $ +*/ + +/*! \file p2p_precomp.h + \brief Collection of most compiler flags for p2p driver are described here. + + In this file we collect all compiler flags and detail the p2p driver behavior if + enable/disable such switch or adjust numeric parameters. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +#ifndef _P2P_PRECOMP_H +#define _P2P_PRECOMP_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "gl_os.h" // Include "config.h" + +#include "gl_p2p_os.h" + +#include "debug.h" + +#include "link.h" +#include "queue.h" + + +/*------------------------------------------------------------------------------ + * .\include\mgmt + *------------------------------------------------------------------------------ + */ +#include "wlan_typedef.h" + + +#include "mac.h" + +/* Dependency: mac.h (MAC_ADDR_LEN) */ +#include "wlan_def.h" + +#include "roaming_fsm.h" + + +/*------------------------------------------------------------------------------ + * .\include\nic + *------------------------------------------------------------------------------ + */ +/* Dependency: wlan_def.h (ENUM_NETWORK_TYPE_T) */ +#include "cmd_buf.h" + + +/* Dependency: mac.h (MAC_ADDR_LEN) */ +#include "nic_cmd_event.h" + + +/* Dependency: nic_cmd_event.h (P_EVENT_CONNECTION_STATUS) */ +#include "nic.h" + +#include "nic_init_cmd_event.h" + +#include "hif_rx.h" +#include "hif_tx.h" + +#include "nic_tx.h" + +/* Dependency: hif_rx.h (P_HIF_RX_HEADER_T) */ +#include "nic_rx.h" + +#include "que_mgt.h" + +#if CFG_ENABLE_WIFI_DIRECT +#include "p2p_typedef.h" +#include "p2p_cmd_buf.h" +#include "p2p_nic_cmd_event.h" +#include "p2p_mac.h" +#include "p2p_nic.h" +#endif + + +/*------------------------------------------------------------------------------ + * .\include\mgmt + *------------------------------------------------------------------------------ + */ + +#include "hem_mbox.h" + +#include "scan.h" +#include "bss.h" + +#include "wlan_lib.h" +#include "wlan_oid.h" +#include "wlan_bow.h" + +#include "wlan_p2p.h" + + + + +#include "hal.h" + +#if defined(MT6620) + #include "mt6620_reg.h" +#elif defined(MT5931) + #include "mt5931_reg.h" +#endif + +#include "rlm.h" +#include "rlm_domain.h" +#include "rlm_protection.h" +#include "rlm_obss.h" +#include "rate.h" + + +#include "aa_fsm.h" + +#include "cnm_timer.h" + +#if CFG_ENABLE_BT_OVER_WIFI +#include "bow.h" +#include "bow_fsm.h" +#endif + +#include "pwr_mgt.h" + + +#include "cnm.h" +/* Dependency: aa_fsm.h (ENUM_AA_STATE_T), p2p_fsm.h (WPS_ATTRI_MAX_LEN_DEVICE_NAME) */ +#include "cnm_mem.h" +#include "cnm_scan.h" + +#include "p2p_rlm_obss.h" +#include "p2p_bss.h" +#include "p2p.h" +/* Dependency: cnm_timer.h (TIMER_T) */ +#include "p2p_fsm.h" +#include "p2p_scan.h" +#include "p2p_state.h" +#include "p2p_func.h" +#include "p2p_rlm.h" +#include "p2p_assoc.h" +#include "p2p_ie.h" + + +#include "privacy.h" + +#include "mib.h" + +#include "auth.h" +#include "assoc.h" + + +#include "ais_fsm.h" + + +#include "adapter.h" + + +#include "que_mgt.h" +#include "rftest.h" + + +#if CFG_RSN_MIGRATION +#include "rsn.h" +#include "sec_fsm.h" +#endif + +#if CFG_SUPPORT_WAPI +#include "wapi.h" +#endif + +/*------------------------------------------------------------------------------ + * NVRAM structure + *------------------------------------------------------------------------------ + */ +#include "CFG_Wifi_File.h" + +#include "gl_p2p_kal.h" + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /*_P2P_PRECOMP_H */ + + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/include/wlan_p2p.h b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/wlan_p2p.h new file mode 100755 index 000000000000..c725a0d4e6d1 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/include/wlan_p2p.h @@ -0,0 +1,454 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/WIFI_P2P_DRIVER_V2_2/include/wlan_p2p.h#3 $ +*/ + +/*! \file "wlan_p2p.h" + \brief This file contains the declairations of Wi-Fi Direct command + processing routines for MediaTek Inc. 802.11 Wireless LAN Adapters. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: wlan_p2p.h $ + * + * 02 23 2012 chinglan.wang + * [ALPS00240621] [Wifi P2P]Run Sigma tool of A69. Always run fail on 7.1.3. sniffer check Sta-IsActive-No-Frames-With-PowerMgmt-1 + * . + * + * 01 17 2012 wh.su + * [WCXRP00001173] [MT6620 Wi-Fi][Driver] Adding the ICS Tethering WPA2-PSK supporting + * adding the code to fix the add key function. + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Hot Spot Tethering for ICS ALPHA testing version. + * + * 11 19 2011 yuche.tsai + * NULL + * Add RSSI support for P2P network. + * + * 11 08 2011 yuche.tsai + * [WCXRP00001094] [Volunteer Patch][Driver] Driver version & supplicant version query & set support for service discovery version check. + * Add support for driver version query & p2p supplicant verseion set. + * For new service discovery mechanism sync. + * + * 10 18 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Support Channle Query. + * + * 10 18 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * New 2.1 branch + + * + * 04 27 2011 george.huang + * [WCXRP00000684] [MT6620 Wi-Fi][Driver] Support P2P setting ARP filter + * Support P2P ARP filter setting on early suspend/ late resume + * + * 04 08 2011 george.huang + * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode + * separate settings of P2P and AIS + * + * 03 22 2011 george.huang + * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command + * link with supplicant commands + * + * 03 19 2011 terry.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 p2p driver release based on label "MT6620_WIFI_P2P_DRIVER_V2_0_2100_0319_2011" from main trunk. + * + * 03 07 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * rename the define to anti_pviracy. + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * Add Security check related code. + * + * 01 05 2011 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service Discovery + * ioctl implementations for P2P Service Discovery + * + * 12 22 2010 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service Discovery + * 1. header file restructure for more clear module isolation + * 2. add function interface definition for implementing Service Discovery callbacks + * + * 09 21 2010 kevin.huang + * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface + * Isolate P2P related function for Hardware Software Bundle + * + * 08 16 2010 cp.wu + * NULL + * add subroutines for P2P to set multicast list. + * + * 08 16 2010 george.huang + * NULL + * support wlanoidSetP2pPowerSaveProfile() in P2P + * + * 08 16 2010 george.huang + * NULL + * Support wlanoidSetNetworkAddress() for P2P + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * MT6620 is not supporting NDIS_PACKET_TYPE_PROMISCUOUS. + * + + * +** +*/ + +#ifndef _WLAN_P2P_H +#define _WLAN_P2P_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#if CFG_ENABLE_WIFI_DIRECT +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/* Service Discovery */ +typedef struct _PARAM_P2P_SEND_SD_RESPONSE { + PARAM_MAC_ADDRESS rReceiverAddr; + UINT_8 fgNeedTxDoneIndication; + UINT_8 ucChannelNum; + UINT_16 u2PacketLength; + UINT_8 aucPacketContent[0]; /*native 802.11*/ +} PARAM_P2P_SEND_SD_RESPONSE, *P_PARAM_P2P_SEND_SD_RESPONSE; + +typedef struct _PARAM_P2P_GET_SD_REQUEST { + PARAM_MAC_ADDRESS rTransmitterAddr; + UINT_16 u2PacketLength; + UINT_8 aucPacketContent[0]; /*native 802.11*/ +} PARAM_P2P_GET_SD_REQUEST, *P_PARAM_P2P_GET_SD_REQUEST; + +typedef struct _PARAM_P2P_GET_SD_REQUEST_EX { + PARAM_MAC_ADDRESS rTransmitterAddr; + UINT_16 u2PacketLength; + UINT_8 ucChannelNum; /* Channel Number Where SD Request is received. */ + UINT_8 ucSeqNum; /* Get SD Request by sequence number. */ + UINT_8 aucPacketContent[0]; /*native 802.11*/ +} PARAM_P2P_GET_SD_REQUEST_EX, *P_PARAM_P2P_GET_SD_REQUEST_EX; + +typedef struct _PARAM_P2P_SEND_SD_REQUEST { + PARAM_MAC_ADDRESS rReceiverAddr; + UINT_8 fgNeedTxDoneIndication; + UINT_8 ucVersionNum; /* Indicate the Service Discovery Supplicant Version. */ + UINT_16 u2PacketLength; + UINT_8 aucPacketContent[0]; /*native 802.11*/ +} PARAM_P2P_SEND_SD_REQUEST, *P_PARAM_P2P_SEND_SD_REQUEST; + +/* Service Discovery 1.0. */ +typedef struct _PARAM_P2P_GET_SD_RESPONSE { + PARAM_MAC_ADDRESS rTransmitterAddr; + UINT_16 u2PacketLength; + UINT_8 aucPacketContent[0]; /*native 802.11*/ +} PARAM_P2P_GET_SD_RESPONSE, *P_PARAM_P2P_GET_SD_RESPONSE; + +/* Service Discovery 2.0. */ +typedef struct _PARAM_P2P_GET_SD_RESPONSE_EX { + PARAM_MAC_ADDRESS rTransmitterAddr; + UINT_16 u2PacketLength; + UINT_8 ucSeqNum; /* Get SD Response by sequence number. */ + UINT_8 aucPacketContent[0]; /*native 802.11*/ +} PARAM_P2P_GET_SD_RESPONSE_EX, *P_PARAM_P2P_GET_SD_RESPONSE_EX; + + +typedef struct _PARAM_P2P_TERMINATE_SD_PHASE { + PARAM_MAC_ADDRESS rPeerAddr; +} PARAM_P2P_TERMINATE_SD_PHASE, *P_PARAM_P2P_TERMINATE_SD_PHASE; + + +/*! \brief Key mapping of BSSID */ +typedef struct _P2P_PARAM_KEY_T +{ + UINT_32 u4Length; /*!< Length of structure */ + UINT_32 u4KeyIndex; /*!< KeyID */ + UINT_32 u4KeyLength; /*!< Key length in bytes */ + PARAM_MAC_ADDRESS arBSSID; /*!< MAC address */ + PARAM_KEY_RSC rKeyRSC; + UINT_8 aucKeyMaterial[32]; /*!< Key content by above setting */ +} P2P_PARAM_KEY_T, *P_P2P_PARAM_KEY_T; + +#if CONFIG_NL80211_TESTMODE + +typedef struct _NL80211_DRIVER_TEST_PARAMS { + UINT_16 idx_mode; + UINT_16 idx; + UINT_32 value; +} NL80211_DRIVER_TEST_PARAMS, *P_NL80211_DRIVER_TEST_PARAMS; + +#endif + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/*--------------------------------------------------------------*/ +/* Routines to handle command */ +/*--------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetAddP2PKey( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidSetRemoveP2PKey( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidSetNetworkAddress( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidSetP2PMulticastList( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +/*--------------------------------------------------------------*/ +/* Service Discovery Subroutines */ +/*--------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSendP2PSDRequest( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidSendP2PSDResponse( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidGetP2PSDRequest( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidGetP2PSDResponse( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 puQueryInfoLen + ); + +WLAN_STATUS +wlanoidSetP2PTerminateSDPhase( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +#if CFG_SUPPORT_ANTI_PIRACY +WLAN_STATUS +wlanoidSetSecCheckRequest( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidGetSecCheckResponse( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); +#endif + +WLAN_STATUS +wlanoidSetNoaParam ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidSetOppPsParam ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidSetUApsdParam ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryP2pPowerSaveProfile ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetP2pPowerSaveProfile ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidSetP2pSetNetworkAddress ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryP2pOpChannel( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidQueryP2pVersion( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetP2pSupplicantVersion( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +#if CFG_SUPPORT_P2P_RSSI_QUERY +WLAN_STATUS +wlanoidQueryP2pRssi( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); +#endif + + +/*--------------------------------------------------------------*/ +/* Callbacks for event indication */ +/*--------------------------------------------------------------*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif +#endif /* _WLAN_P2P_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_assoc.c b/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_assoc.c new file mode 100755 index 000000000000..4f20f5caf0d4 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_assoc.c @@ -0,0 +1,139 @@ +/* +** $Id: @(#) p2p_assoc.c@@ +*/ + +/*! \file "p2p_assoc.c" + \brief This file includes the Wi-Fi Direct association-related functions. + + This file includes the association-related functions. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "p2p_precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to compose Common Information Elements for P2P Association +* Request Frame. +* +* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +PUINT_8 +p2pBuildReAssocReqFrameCommonIEs( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN PUINT_8 pucBuffer + ) +{ + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T)NULL; + + prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + + /* Fill the SSID element. */ + SSID_IE(pucBuffer)->ucId = ELEM_ID_SSID; + + /* NOTE(Kevin): We copy the SSID from CONNECTION_SETTINGS for the case of + * Passive Scan and the target BSS didn't broadcast SSID on its Beacon Frame. + */ + + COPY_SSID(SSID_IE(pucBuffer)->aucSSID, + SSID_IE(pucBuffer)->ucLength, + prP2pConnSettings->aucSSID, + prP2pConnSettings->ucSSIDLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + return pucBuffer; +} + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_bss.c b/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_bss.c new file mode 100755 index 000000000000..bde305b3f704 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_bss.c @@ -0,0 +1,125 @@ +/* +** $Id: @(#) p2p_bss.c@@ +*/ + +/*! \file "p2p_bss.c" + \brief This file contains the functions for creating p2p BSS(AP). + + This file contains the functions for BSS(AP). We may create a BSS + network, or merge with exist IBSS network and sending Beacon Frame or reply + the Probe Response Frame for received Probe Request Frame. +*/ + + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "p2p_precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +APPEND_VAR_IE_ENTRY_T txProbRspIETableWIP2P[] = { + { (ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)), NULL, bssGenerateExtSuppRate_IE } /* 50 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, rlmRspGenerateHtCapIE } /* 45 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP), NULL, rlmRspGenerateHtOpIE } /* 61 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN), NULL, rlmRspGenerateObssScanIE } /* 74 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, rlmRspGenerateExtCapIE } /* 127 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_RSN), NULL, rsnGenerateRSNIE } /* 48 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWpaNoneIE } /* 221 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_PARAM), NULL, mqmGenerateWmmParamIE } /* 221 */ +}; + + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +UINT_32 +p2pGetTxProbRspIeTableSize( + VOID + ) +{ + return (sizeof(txProbRspIETableWIP2P)/sizeof(APPEND_VAR_IE_ENTRY_T)); +} + + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_fsm.c b/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_fsm.c new file mode 100755 index 000000000000..2dbf121a30d4 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_fsm.c @@ -0,0 +1,3155 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/WIFI_P2P_DRIVER_V2_2/mgmt/p2p_fsm.c#24 $ +*/ + +/*! \file "p2p_fsm.c" + \brief This file defines the FSM for P2P Module. + + This file defines the FSM for P2P Module. +*/ + +/******************************************************************************* +* Copyright (c) 2010 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: p2p_fsm.c $ + * + * 02 24 2012 yuche.tsai + * [ALPS00240756] [WiFi direct]After accept PBC request,DVT pops Kernel Defect.Powering off DVT causes DVT reboots automatcially and pops up KE(once) + * Fix GO dissolving issue to avoid FW assert. + * + * 02 22 2012 yuche.tsai + * [ALPS00240483] [Wifi P2P]Run Sigma tool of A69. Always run fail on 5.1.2. No get correct connection from Realtek. + * Fix assoc response without P2P IE issue for Sigma test. + * + * 02 21 2012 yuche.tsai + * [ALPS00240187] [WiFi direct]When turn on WiFi Direct,phone reboots automatically and KE(KERNEL-PANIC) pos up + * Add driver pointer check to avoid KE in wifi direct driver. + * + * 02 15 2012 yuche.tsai + * [ALPS00118350] [ALPS.ICS][WiFi Direct] Dirver update for wifi direct connection + * Fix P2P response rate issue under P2P device mode. + * + * 02 09 2012 yuche.tsai + * [ALPS00233018] [klocwork 9.1] in p2p_fsm.c, line 1633 + * After fix error. + * + * 02 09 2012 yuche.tsai + * [ALPS00233018] [klocwork 9.1] in p2p_fsm.c, line 1633 + * Before fix error. + * + * 02 08 2012 yuche.tsai + * [ALPS00118350] [ALPS.ICS][WiFi Direct] Dirver update for wifi direct connection + * Try to fix clockwork warning. + * + * 02 06 2012 yuche.tsai + * [ALPS00118350] [ALPS.ICS][WiFi Direct] Dirver update for wifi direct connection + * Small bug fix for CNM memory usage, scan SSID search issue, P2P network deactivate issue. + * + * 02 02 2012 yuche.tsai + * NULL + * Big fix. + * + * 01 31 2012 yuche.tsai + * NULL + * Fix compile error & del beacon scenario. + * + * 01 27 2012 yuche.tsai + * NULL + * Update for GC connection . + * + * 01 26 2012 yuche.tsai + * NULL + * Fix compile warning. + * + * 01 20 2012 yuche.tsai + * NULL + * Update for RX probe request. + * + * 01 19 2012 yuche.tsai + * NULL + * Update WiFi Direct RX probe request issue. + * + * 01 19 2012 yuche.tsai + * NULL + * Fix scan p2p IE issue. + * + * 01 18 2012 yuche.tsai + * NULL + * Bug fix for memory allocation. + * + * 01 18 2012 yuche.tsai + * NULL + * Fix bug of BSS info indication. + * + * 01 18 2012 yuche.tsai + * NULL + * Add get station info API. + * TX deauth before start beacon. + * + * 01 17 2012 yuche.tsai + * NULL + * Update mgmt frame filter setting. + * Please also update FW 2.1 + * + * 01 16 2012 yuche.tsai + * NULL + * Update Driver for wifi driect gc join IE update issue. + * + * 01 16 2012 yuche.tsai + * NULL + * Add join timer. + * + * 01 16 2012 yuche.tsai + * NULL + * Update P2P driver code for GC Join. + * + * 01 15 2012 yuche.tsai + * NULL + * ICS P2P Driver Update. + * + * 01 15 2012 yuche.tsai + * NULL + * Fix scan bug. + * + * 01 13 2012 yuche.tsai + * NULL + * Update WiFi tethering driver for ICS. + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Direct Driver Update for ICS. + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Hot Spot Tethering for ICS ALPHA testing version. + * + * 07 05 2011 yuche.tsai + * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue + * Fix the compile flag of enhancement. + * + * 07 05 2011 yuche.tsai + * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue + * Refine compile flag. + * + * 07 05 2011 yuche.tsai + * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue + * Add WiFi Direct Connection Enhancement. + * + * 07 05 2011 yuche.tsai + * [WCXRP00000833] [Volunteer Patch][WiFi Direct][Driver] Service Discovery Frame RX Indicate Issue + * Solve Service Discovery Response Race Condition issue. + * + * 06 28 2011 yuche.tsai + * [WCXRP00000820] [Volunteer Patch][MT6620][WiFi Direct][Driver] GO can not connect to the third device issue + * Fix GO can not activly connect to the third P2P device issue. + * + * 06 23 2011 cp.wu + * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module + * follow-ups for frequency-shifted WAPI AP support + * + * 06 22 2011 yuche.tsai + * [WCXRP00000808] [Volunteer Patch][MT6620][Driver/FW] Device discoverability issue fix + * Fix some device discoverability issue. + * + * 06 21 2011 yuche.tsai + * [WCXRP00000799] [Volunteer Patch][MT6620][Driver] Connection Indication Twice Issue. + * Fix some issue of accepting connection of GO. + * + * 06 21 2011 yuche.tsai + * [WCXRP00000775] [Volunteer Patch][MT6620][Driver] Dynamic enable SD capability + * Drop GAS frame when SD is not enabled. + * + * 06 20 2011 yuche.tsai + * [WCXRP00000799] [Volunteer Patch][MT6620][Driver] Connection Indication Twice Issue. + * Fix connection indication twice issue. + * + * 06 20 2011 yuche.tsai + * [WCXRP00000796] [Volunteer Patch][MT6620][Driver] Add BC deauth frame TX feature. + * Add feature to send BC deauth frame when under AP/GO mode. + * + * 06 20 2011 yuche.tsai + * [WCXRP00000795] [Volunteer Patch][MT6620][Driver] GO can not connect second device issue + * Solve GO can not formation with second device issue. + * + * 06 14 2011 yuche.tsai + * NULL + * Add compile flag to disable persistent group support. + * + * 06 10 2011 yuche.tsai + * [WCXRP00000776] [Need Patch][MT6620][Driver] MT6620 response probe request of P2P device with P2P IE under Hot Spot mode. + * Driver should not reponse probe request of P2P device under Hot Spot mode. + * + * 06 10 2011 yuche.tsai + * [WCXRP00000775] [Volunteer Patch][MT6620][Driver] Dynamic enable SD capability + * Support Dynamic enable SD capability. + * + * 06 07 2011 yuche.tsai + * [WCXRP00000763] [Volunteer Patch][MT6620][Driver] RX Service Discovery Frame under AP mode Issue + * Fix RX SD request under AP mode issue. + * + * 06 02 2011 cp.wu + * [WCXRP00000681] [MT5931][Firmware] HIF code size reduction + * eliminate unused parameters for SAA-FSM + * + * 05 26 2011 yuche.tsai + * [WCXRP00000745] Support accepting connection after one Group Connection Lost. + +After Group Formation & lost connection, if MT6620 behave as: + +1. GO: It would keep under GO state until been dissolved by supplicant. + + At this time, other P2P device can use join method to join this group. + + +2. GC: It would keep on searching target GO or target device until been dissolved by supplicant. + +At this time, it would ignore other P2P device formation request. + + +-- + +Modification: Make driver to accept GO NEGO REQ at this time, to let user decide to accept new connection or not. + + * [Volunteer Patch][MT6620][Driver] + * Accept other p2p device connection if the original one is lost. + * + * 05 18 2011 yuche.tsai + * NULL + * Fix compile error. A new feature would not be included in v2.0 p2p driver + * + * 05 18 2011 yuche.tsai + * [WCXRP00000728] [Volunteer Patch][MT6620][Driver] Service Discovery Request TX issue. + * A solution for both connection request & iocontrol request. + * + * 05 17 2011 yuche.tsai + * [WCXRP00000728] [Volunteer Patch][MT6620][Driver] Service Discovery Request TX issue. + * The solution has some issue, still working. + * + * 05 16 2011 yuche.tsai + * [WCXRP00000728] [Volunteer Patch][MT6620][Driver] Service Discovery Request TX issue. + * Fix SD Request can not TX issue. + * + * 05 09 2011 terry.wu + * [WCXRP00000711] [MT6620 Wi-Fi][Driver] Set Initial value of StaType in StaRec for Hotspot Client + * Set initial value of StaType in StaRec for hotspot client. + * + * 05 04 2011 yuche.tsai + * [WCXRP00000697] [Volunteer Patch][MT6620][Driver] + * Bug fix for BSS descriptor is found first before p2p descriptor. + * + * 05 04 2011 yuche.tsai + * [WCXRP00000696] [Volunteer Patch][MT6620][Driver] Infinite loop issue when RX invitation response. + * Add an end condition in while loop of invitation response frame checking function. + * + * 05 02 2011 yuche.tsai + * [WCXRP00000693] [Volunteer Patch][MT6620][Driver] Clear Formation Flag after TX lifetime timeout. + * Clear flag after Tx lifetime timeout of GO NEGO frame. + * + * 04 20 2011 yuche.tsai + * [WCXRP00000668] [Volunteer Patch][MT6620][Driver] Possible race condition when add scan & query scan result at the same time. + * Fix side effect while starting ATGO. + * + * 04 20 2011 yuche.tsai + * NULL + * Fix ASSERT issue in FW, side effect of last change. + * + * 04 19 2011 yuche.tsai + * NULL + * Workaround for multiple device connection, before invitation ready. + * + * 04 19 2011 yuche.tsai + * [WCXRP00000665] [Wifi Direct][MT6620 E4] When use Ralink's dongle to establish wifi direct connection with PBC. But 6573 always not pop accept option to establish connection. + * Support connection indication when GO NEGO REQ only has Password ID instead of Configure method. + * + * 04 18 2011 yuche.tsai + * NULL + * Fix error. + * + * 04 14 2011 yuche.tsai + * [WCXRP00000646] [Volunteer Patch][MT6620][FW/Driver] Sigma Test Modification for some test case. + * Fix a connection issue. + * + * 04 14 2011 yuche.tsai + * [WCXRP00000646] [Volunteer Patch][MT6620][FW/Driver] Sigma Test Modification for some test case. + * Fix the channel issue of AP mode.. + * + * 04 14 2011 yuche.tsai + * [WCXRP00000646] [Volunteer Patch][MT6620][FW/Driver] Sigma Test Modification for some test case. + * Refine P2P connection flow for Sigma Test.. + * + * 04 10 2011 yuche.tsai + * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. + * Add device discoverability support. (Phase I) + * + * 03 28 2011 yuche.tsai + * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. + * Fix a possible issue for retry join when media status connected. + * + * 03 25 2011 yuche.tsai + * NULL + * Improve some error handleing. + * + * 03 24 2011 yuche.tsai + * NULL + * Assign AID before sync station state to FW. + * + * 03 23 2011 yuche.tsai + * NULL + * Fix Response Rate Issue when TX Auth Rsp Frame under P2P Mode.. + * + * 03 23 2011 yuche.tsai + * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. + * Fix issue of connection to one GC.. + * + * 03 23 2011 yuche.tsai + * NULL + * Fix ASSERT issue under Hot-Spot mode. + * + * 03 22 2011 yuche.tsai + * NULL + * When Target Information is not available, change to passive mode.. + * + * 03 22 2011 yuche.tsai + * NULL + * Fix one connection issue while using Keypad to connect GO. + * + * 03 22 2011 yuche.tsai + * NULL + * Fix two issues that may cause kernel panic. + * + * 03 22 2011 yuche.tsai + * NULL + * Fix GC connect to other device issue. + * + * 03 22 2011 yuche.tsai + * NULL + * 1. Fix formation policy issue. + * 2. Fix LISTEN channel issue. + * 3. Fix Target IF address in-correct issue when being GO. + * + * 03 21 2011 yuche.tsai + * NULL + * Connection Flow Modification. + * + * 03 19 2011 terry.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 p2p driver release based on label "MT6620_WIFI_P2P_DRIVER_V2_0_2100_0319_2011" from main trunk. + * + * 03 19 2011 yuche.tsai + * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. + * Add beacon timeout support. + * + * 03 19 2011 yuche.tsai + * [WCXRP00000583] [Volunteer Patch][MT6620][Driver] P2P connection of the third peer issue + * Indicate the correct Group SSID when join on Group. + * + * 03 19 2011 yuche.tsai + * [WCXRP00000583] [Volunteer Patch][MT6620][Driver] P2P connection of the third peer issue + * Support the third P2P device to join GO/GC group. + * + * 03 19 2011 yuche.tsai + * [WCXRP00000581] [Volunteer Patch][MT6620][Driver] P2P IE in Assoc Req Issue + * Append P2P IE in Assoc Req, so that GC can be discovered in probe response of GO. + * + * 03 18 2011 yuche.tsai + * [WCXRP00000578] [Volunteer Patch][MT6620][Driver] Separate Connection Request from general IOCTL + * Separate connection request from general IOCTL. + * + * 03 18 2011 yuche.tsai + * [WCXRP00000574] [Volunteer Patch][MT6620][Driver] Modify P2P FSM Connection Flow + * Modify connection flow after Group Formation Complete, or device connect to a GO. + * Instead of request channel & connect directly, we use scan to allocate channel bandwidth & connect after RX BCN. + * + * 03 17 2011 yuche.tsai + * NULL + * When AIS is connect to an AP, Hot Spot would be enabled under fixed same channel. + * + * 03 17 2011 yuche.tsai + * NULL + * Solve the Group Info IE in Probe Response incorrect issue. + * + * 03 17 2011 yuche.tsai + * NULL + * Release Channel after Join Complete. + * + * 03 16 2011 wh.su + * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done + * enable the protected while at P2P start GO, and skip some security check . + * + * 03 15 2011 yuche.tsai + * [WCXRP00000560] [Volunteer Patch][MT6620][Driver] P2P Connection from UI using KEY/DISPLAY issue + * Fix local configure method issue. + * + * 03 15 2011 yuche.tsai + * [WCXRP00000560] [Volunteer Patch][MT6620][Driver] P2P Connection from UI using KEY/DISPLAY issue + * Fix some configure method issue. + * + * 03 14 2011 yuche.tsai + * NULL + * . + * + * 03 14 2011 yuche.tsai + * NULL + * Fix password ID issue. + * + * 03 10 2011 yuche.tsai + * NULL + * Add P2P API. + * + * 03 08 2011 yuche.tsai + * [WCXRP00000480] [Volunteer Patch][MT6620][Driver] WCS IE format issue[WCXRP00000509] [Volunteer Patch][MT6620][Driver] Kernal panic when remove p2p module. + * . + * + * 03 07 2011 yuche.tsai + * [WCXRP00000502] [Volunteer Patch][MT6620][Driver] Fix group ID issue when doing Group Formation. + * . + * + * 03 07 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * rename the define to anti_pviracy. + * + * 03 05 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * add the code to get the check rsponse and indicate to app. + * + * 03 04 2011 wh.su + * [WCXRP00000510] [MT6620 Wi-Fi] [Driver] Fixed the CTIA enter test mode issue + * fixed the p2p action frame type check for device request indication. + * + * 03 02 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Fix Service Discovery RX packet buffer pointer. + * + * 03 01 2011 yuche.tsai + * [WCXRP00000501] [Volunteer Patch][MT6620][Driver] No common channel issue when doing GO formation + * Update channel issue when doing GO formation.. + * + * 03 01 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Update Service Discovery Related wlanoid function. + * + * 02 21 2011 yuche.tsai + * [WCXRP00000481] [Volunteer Patch][MT6620][FW] Scan hang under concurrent case. + * Fix all BE issue of WSC or P2P IE. + * + * 02 18 2011 wh.su + * [WCXRP00000471] [MT6620 Wi-Fi][Driver] Add P2P Provison discovery append Config Method attribute at WSC IE + * fixed the wsc config method mapping to driver used config method issue. + * + * 02 18 2011 yuche.tsai + * [WCXRP00000479] [Volunteer Patch][MT6620][Driver] Probe Response of P2P using 11b rate. + * Update basic rate to FW, after P2P is initialed. + * + * 02 18 2011 yuche.tsai + * [WCXRP00000478] [Volunteer Patch][MT6620][Driver] Probe request frame during search phase do not contain P2P wildcard SSID. + * Use P2P Wildcard SSID when scan type of P2P_WILDCARD_SSID is set. + * + * 02 18 2011 yuche.tsai + * [WCXRP00000480] [Volunteer Patch][MT6620][Driver] WCS IE format issue + * Fix WSC IE BE format issue. + * + * 02 17 2011 wh.su + * [WCXRP00000471] [MT6620 Wi-Fi][Driver] Add P2P Provison discovery append Config Method attribute at WSC IE + * append the WSC IE config method attribute at provision discovery request. + * + * 02 16 2011 wh.su + * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request + * fixed the probe request send out without WSC IE issue (at P2P). + * + * 02 16 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * If two station connected to the Hot-Spot and one disconnect, FW would get into an infinite loop + * + * 02 15 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Fix re-connection issue after RX deauthentication. + * + * 02 15 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Fix conneciton issue after disconnect with AP. + * + * 02 12 2011 yuche.tsai + * [WCXRP00000441] [Volunteer Patch][MT6620][Driver] BoW can not create desired station type when Hot Spot is enabled. + * P2P Create Station Type according to Target BSS capability. + * + * 02 10 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Support Disassoc & Deauthentication for Hot-Spot. + * + * 02 09 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Add Service Discovery Indication Related code. + * + * 02 09 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Add Support for MLME deauthentication for Hot-Spot. + * + * 02 09 2011 yuche.tsai + * [WCXRP00000429] [Volunteer Patch][MT6620][Driver] Hot Spot Client Limit Issue + * Fix Client Limit Issue. + * + * 02 08 2011 yuche.tsai + * [WCXRP00000419] [Volunteer Patch][MT6620/MT5931][Driver] Provide function of disconnect to target station for AAA module. + * Disconnect every station client when disolve on P2P group. + * + * 02 08 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * 1. Fix Service Disocvery Logical issue. + * 2. Fix a NULL pointer access violation issue when sending deauthentication packet to a class error station. + * + * 02 08 2011 yuche.tsai + * [WCXRP00000419] [Volunteer Patch][MT6620/MT5931][Driver] Provide function of disconnect to target station for AAA module. + * Workaround of disable P2P network. + * + * 02 08 2011 yuche.tsai + * [WCXRP00000421] [Volunteer Patch][MT6620][Driver] Fix incorrect SSID length Issue + * 1. Fixed SSID wrong length issue. + * 2. Under Hot Spot configuration, there won't be any P2P IE. + * 3. Under Hot Spot configuration, P2P FSM won't get into LISTEN state first. + * + * 01 27 2011 yuche.tsai + * [WCXRP00000399] [Volunteer Patch][MT6620/MT5931][Driver] Fix scan side effect after P2P module separate. + * Modify Start GO flow. + * + * 01 27 2011 yuche.tsai + * [WCXRP00000399] [Volunteer Patch][MT6620/MT5931][Driver] Fix scan side effect after P2P module separate. + * Fix desire phy type set issue. + * + * 01 27 2011 yuche.tsai + * [WCXRP00000399] [Volunteer Patch][MT6620/MT5931][Driver] Fix scan side effect after P2P module separate. + * Add desire phy type set phase I. + * + * 01 26 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Fix P2P Disconnect Issue. + * + * 01 26 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Add Service Discovery Function. + * + * 01 26 2011 cm.chang + * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument + * . + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Fix compile error when DBG is disabled. + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Change Station Type Definition. + * + * 01 19 2011 yuche.tsai + * [WCXRP00000353] [Volunteer Patch][MT6620][Driver] Desired Non-HT Rate Set update when STA record is created under AP Mode. + * Add P2P QoS Support. + * + * 01 19 2011 george.huang + * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability + * Null NOA attribute setting when no related parameters. + * + * 01 14 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Modify AAA flow according to CM's comment. + * + * 01 13 2011 yuche.tsai + * [WCXRP00000353] [Volunteer Patch][MT6620][Driver] Desired Non-HT Rate Set update when STA record is created under AP Mode. + * Resolve Channel ZERO issue. (Uninitialized default channel) + * + * 01 13 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Update P2P State Debug Message. + * + * 01 12 2011 yuche.tsai + * [WCXRP00000353] [Volunteer Patch][MT6620][Driver] Desired Non-HT Rate Set update when STA record is created under AP Mode. + * Fix bug when allocating message buffer. + * + * 01 12 2011 yuche.tsai + * [WCXRP00000353] [Volunteer Patch][MT6620][Driver] Desired Non-HT Rate Set update when STA record is created under AP Mode. + * Update Phy Type Set. When legacy client is connected, it can use 11b rate, + * but if the P2P device is connected, 11b rate is not allowed. + * + * 01 12 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * 1. Modify Channel Acquire Time of AP mode from 5s to 1s. + * 2. Call cnmP2pIsPermit() before active P2P network. + * 3. Add channel selection support for AP mode. + * + * 01 12 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Fix Bug of reference to NULL pointer. + * + * 01 12 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Modify some behavior of AP mode. + * + * 01 12 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Fix bug of wrong pointer check. + * + * 01 12 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Fix Compile Error. + * + * 01 11 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Add station record into client list before change it state from STATE_2 to STATE_3. + * + * 01 05 2011 yuche.tsai + * [WCXRP00000345] [MT6620][Volunteer Patch] P2P may issue a SSID specified scan request, but the SSID length is still invalid. + * Specify SSID Type when issue a scan request. + * + * 01 05 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease physically continous memory demands + * correct typo + * + * 01 05 2011 george.huang + * [WCXRP00000343] [MT6620 Wi-Fi] Add TSF reset path for concurrent operation + * modify NOA update path for preventing assertion false alarm. + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease physically continous memory demands + * separate kalMemAlloc() into virtually-continous and physically-continous type to ease slab system pressure + * + * 01 03 2011 wh.su + * [WCXRP00000326] [MT6620][Wi-Fi][Driver] check in the binary format gl_sec.o.new instead of use change type!!! + * let the p2p ap mode acept a legacy device join. + * + * 12 22 2010 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Fix Compile Error. + * + * 12 15 2010 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Refine Connection Flow. + * + * 12 08 2010 yuche.tsai + * [WCXRP00000245] [MT6620][Driver] Invitation & Provision Discovery Feature Check-in + * [WCXRP000000245][MT6620][Driver] Invitation Request Feature Add + * + * 12 08 2010 yuche.tsai + * [WCXRP00000244] [MT6620][Driver] Add station record type for each client when in AP mode. + * Change STA Type under AP mode. We would tell if client is a P2P device or a legacy client by checking the P2P IE in assoc req frame. + * + * 12 07 2010 cm.chang + * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk + * The order of invoking nicUpdateBss() and rlm functions + * + * 12 02 2010 yuche.tsai + * NULL + * Update P2P Connection Policy for Invitation. + * + * 12 02 2010 yuche.tsai + * NULL + * Update P2P Connection Policy for Invitation & Provision Discovery. + * + * 11 30 2010 yuche.tsai + * NULL + * Invitation & Provision Discovery Indication. + * + * 11 30 2010 yuche.tsai + * NULL + * Update Configure Method indication & selection for Provision Discovery & GO_NEGO_REQ + * + * 11 30 2010 yuche.tsai + * NULL + * Update RCIP value when RX assoc request frame. + * + * 11 29 2010 yuche.tsai + * NULL + * Update P2P related function for INVITATION & PROVISION DISCOVERY. + * + * 11 26 2010 george.huang + * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function + * Update P2P PS for NOA function. + * + * 11 25 2010 yuche.tsai + * NULL + * Update Code for Invitation Related Function. + * + * 11 17 2010 wh.su + * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID[WCXRP00000179] [MT6620 Wi-Fi][FW] Set the Tx lowest rate at wlan table for normal operation + * fixed some ASSERT check. + * + * 11 05 2010 wh.su + * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID + * fixed the p2p role code error. + * + * 11 04 2010 wh.su + * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID + * adding the p2p random ssid support. + * + * 10 20 2010 wh.su + * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group + * fixed the ASSERT check error + * + * 10 20 2010 wh.su + * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group + * Add the code to support disconnect p2p group + * + * 10 19 2010 wh.su + * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine[WCXRP00000102] [MT6620 Wi-Fi] [FW] Add a compiling flag and code for support Direct GO at Android + * fixed the compiling error. + * + * 10 14 2010 wh.su + * [WCXRP00000102] [MT6620 Wi-Fi] [FW] Add a compiling flag and code for support Direct GO at Android + * adding a code to support Direct GO with a compiling flag . + * + * 10 08 2010 cp.wu + * [WCXRP00000087] [MT6620 Wi-Fi][Driver] Cannot connect to 5GHz AP, driver will cause FW assert. + * correct erroneous logic: specifying eBand with incompatible eSco + * + * 10 08 2010 wh.su + * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine + * fixed the compiling error. + * + * 10 08 2010 wh.su + * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine + * update the frog's new p2p state machine. + * + * 09 10 2010 wh.su + * NULL + * fixed the compiling error at WinXP. + * + * 09 07 2010 yuche.tsai + * NULL + * Reset Common IE Buffer of P2P INFO when scan request is issued. + * If an action frame other than public action frame is received, return direcly. + * + * 09 07 2010 wh.su + * NULL + * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. + * + * 09 06 2010 wh.su + * NULL + * let the p2p can set the privacy bit at beacon and rsn ie at assoc req at key handshake state. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 26 2010 yuche.tsai + * NULL + * Add P2P Connection Abort Event Message handler. + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 08 23 2010 yuche.tsai + * NULL + * 1. Fix Interface Address from GO Nego Req/Rsp is not correct. + * 2. Fix GO mode does not change media state after station connected. + * 3. Fix STA don't response probe request when there is a connection request. + * + * 08 20 2010 cm.chang + * NULL + * Migrate RLM code to host from FW + * + * 08 20 2010 kevin.huang + * NULL + * Modify AAA Module for changing STA STATE 3 at p2p/bowRunEventAAAComplete() + * + * 08 20 2010 yuche.tsai + * NULL + * Add Glue Layer indication. + * + * 08 17 2010 yuche.tsai + * NULL + * Fix compile warning under Linux. + * + * 08 17 2010 yuche.tsai + * NULL + * Fix some P2P FSM bug. + * + * 08 16 2010 yuche.tsai + * NULL + * Add random Interface Address Generation support. + * + * 08 16 2010 yuche.tsai + * NULL + * Fix some P2P FSM bug. + * + * 08 16 2010 yuche.tsai + * NULL + * Update P2P FSM code for GO Nego. + * + * 08 16 2010 kevin.huang + * NULL + * Refine AAA functions + * + * 08 12 2010 kevin.huang + * NULL + * Refine bssProcessProbeRequest() and bssSendBeaconProbeResponse() + * + * 08 12 2010 yuche.tsai + * NULL + * Join complete indication. + * + * 08 11 2010 yuche.tsai + * NULL + * Add two boolean in connection request. + * Based on these two boolean value, P2P FSM should + * decide to do invitation or group formation or start a GO directly. + * + * 08 11 2010 yuche.tsai + * NULL + * Update P2P FSM, currently P2P Device Discovery is verified. + * + * 08 05 2010 yuche.tsai + * NULL + * Update P2P FSM for group formation. + * + * 08 03 2010 george.huang + * NULL + * handle event for updating NOA parameters indicated from FW + * + * 08 03 2010 cp.wu + * NULL + * limit build always needs spin-lock declaration. + * + * 08 02 2010 yuche.tsai + * NULL + * P2P Group Negotiation Code Check in. + * + * 07 26 2010 yuche.tsai + * + * Add P2P FSM code check in. + * + * 07 21 2010 yuche.tsai + * + * Add P2P Scan & Scan Result Parsing & Saving. + * + * 07 19 2010 yuche.tsai + * + * Update P2P FSM. + * + * 07 09 2010 george.huang + * + * [WPD00001556] Migrate PM variables from FW to driver: for composing QoS Info + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Fix compile error while enable WIFI_DIRECT support. + * + * 06 21 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Update P2P Function call. + * + * 06 17 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * First draft for migration P2P FSM from FW to Driver. + * + * 04 19 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * Add Beacon Timeout Support and will send Null frame to diagnose connection + * + * 03 18 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Rename CFG flag for P2P + * + * 02 26 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add code to test P2P GO + * + * 02 23 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add Wi-Fi Direct SSID and P2P GO Test Mode + * + * 02 05 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Modify code due to BAND_24G define was changed + * + * 02 05 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Revise data structure to share the same BSS_INFO_T for avoiding coding error + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "p2p_precomp.h" + +#if CFG_ENABLE_WIFI_DIRECT + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +#if DBG +/*lint -save -e64 Type mismatch */ +static PUINT_8 apucDebugP2pState[P2P_STATE_NUM] = { + (PUINT_8)DISP_STRING("P2P_STATE_IDLE"), + (PUINT_8)DISP_STRING("P2P_STATE_SCAN"), + (PUINT_8)DISP_STRING("P2P_STATE_AP_CHANNEL_DETECT"), + (PUINT_8)DISP_STRING("P2P_STATE_REQING_CHANNEL"), + (PUINT_8)DISP_STRING("P2P_STATE_CHNL_ON_HAND"), + (PUINT_8)DISP_STRING("P2P_STATE_GC_JOIN") +}; +/*lint -restore */ +#endif /* DBG */ + + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/* p2pStateXXX : Processing P2P FSM related action. + * p2pFSMXXX : Control P2P FSM flow. + * p2pFuncXXX : Function for doing one thing. + */ +VOID +p2pFsmInit ( + IN P_ADAPTER_T prAdapter + ) +{ + + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + + do { + ASSERT_BREAK(prAdapter != NULL); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + ASSERT_BREAK(prP2pFsmInfo != NULL); + + LINK_INITIALIZE(&(prP2pFsmInfo->rMsgEventQueue)); + + prP2pFsmInfo->eCurrentState = prP2pFsmInfo->ePreviousState = P2P_STATE_IDLE; + prP2pFsmInfo->prTargetBss = NULL; + + cnmTimerInitTimer(prAdapter, + &(prP2pFsmInfo->rP2pFsmTimeoutTimer), + (PFN_MGMT_TIMEOUT_FUNC)p2pFsmRunEventFsmTimeout, + (UINT_32)prP2pFsmInfo); + + //4 <2> Initiate BSS_INFO_T - common part + BSS_INFO_INIT(prAdapter, NETWORK_TYPE_P2P_INDEX); + + + //4 <2.1> Initiate BSS_INFO_T - Setup HW ID + prP2pBssInfo->ucConfigAdHocAPMode = AP_MODE_11G_P2P; + prP2pBssInfo->ucHwDefaultFixedRateCode = RATE_OFDM_6M; + + + prP2pBssInfo->ucNonHTBasicPhyType = (UINT_8) + rNonHTApModeAttributes[prP2pBssInfo->ucConfigAdHocAPMode].ePhyTypeIndex; + prP2pBssInfo->u2BSSBasicRateSet = + rNonHTApModeAttributes[prP2pBssInfo->ucConfigAdHocAPMode].u2BSSBasicRateSet; + + prP2pBssInfo->u2OperationalRateSet = + rNonHTPhyAttributes[prP2pBssInfo->ucNonHTBasicPhyType].u2SupportedRateSet; + + rateGetDataRatesFromRateSet(prP2pBssInfo->u2OperationalRateSet, + prP2pBssInfo->u2BSSBasicRateSet, + prP2pBssInfo->aucAllSupportedRates, + &prP2pBssInfo->ucAllSupportedRatesLen); + + prP2pBssInfo->prBeacon = cnmMgtPktAlloc(prAdapter, + OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem[0]) + MAX_IE_LENGTH); + + if (prP2pBssInfo->prBeacon) { + prP2pBssInfo->prBeacon->eSrc = TX_PACKET_MGMT; + prP2pBssInfo->prBeacon->ucStaRecIndex = 0xFF; /* NULL STA_REC */ + prP2pBssInfo->prBeacon->ucNetworkType = NETWORK_TYPE_P2P_INDEX; + } + else { + /* Out of memory. */ + ASSERT(FALSE); + } + + prP2pBssInfo->eCurrentOPMode = OP_MODE_NUM; + + prP2pBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC = PM_UAPSD_ALL; + prP2pBssInfo->rPmProfSetupInfo.ucBmpTriggerAC = PM_UAPSD_ALL; + prP2pBssInfo->rPmProfSetupInfo.ucUapsdSp = WMM_MAX_SP_LENGTH_2; + prP2pBssInfo->ucPrimaryChannel = P2P_DEFAULT_LISTEN_CHANNEL; + prP2pBssInfo->eBand = BAND_2G4; + prP2pBssInfo->eBssSCO = CHNL_EXT_SCN; + + if (prAdapter->rWifiVar.fgSupportQoS) { + prP2pBssInfo->fgIsQBSS = TRUE; + } + else { + prP2pBssInfo->fgIsQBSS = FALSE; + } + + + } while (FALSE); + + return; +} /* p2pFsmInit */ + + + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief The function is used to uninitialize the value in P2P_FSM_INFO_T for +* P2P FSM operation +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFsmUninit ( + IN P_ADAPTER_T prAdapter + ) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + + do { + ASSERT_BREAK(prAdapter != NULL); + + DEBUGFUNC("p2pFsmUninit()"); + DBGLOG(P2P, INFO, ("->p2pFsmUninit()\n")); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + p2pFsmRunEventAbort(prAdapter, prP2pFsmInfo); + + p2pFuncSwitchOPMode(prAdapter, prP2pBssInfo, OP_MODE_P2P_DEVICE, TRUE); + + UNSET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); + + wlanAcquirePowerControl(prAdapter); + + /* Release all pending CMD queue. */ + wlanProcessCommandQueue(prAdapter, &prAdapter->prGlueInfo->rCmdQueue); + + wlanReleasePowerControl(prAdapter); + + /* Clear PendingCmdQue*/ + wlanReleasePendingCMDbyNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); + + if (prP2pBssInfo->prBeacon) { + nicTxReturnMsduInfo(prAdapter, prP2pBssInfo->prBeacon); + prP2pBssInfo->prBeacon = NULL; + } + + } while (FALSE); + + return; + +} /* end of p2pFsmUninit() */ + +VOID +p2pFsmStateTransition ( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN ENUM_P2P_STATE_T eNextState + ) +{ + BOOLEAN fgIsTransOut = (BOOLEAN)FALSE; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); + DBGLOG(P2P, STATE, ("p2pFsmStateTransition \n")); + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; + + if (!IS_BSS_ACTIVE(prP2pBssInfo)) { + SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); + } + + fgIsTransOut = fgIsTransOut?FALSE:TRUE; + + if (!fgIsTransOut) { +#if DBG + DBGLOG(P2P, STATE, ("TRANSITION: [%s] -> [%s]\n", + apucDebugP2pState[prP2pFsmInfo->eCurrentState], + apucDebugP2pState[eNextState])); +#endif + /* Transition into current state. */ + prP2pFsmInfo->ePreviousState = prP2pFsmInfo->eCurrentState; + prP2pFsmInfo->eCurrentState = eNextState; + } + + + switch (prP2pFsmInfo->eCurrentState) { + case P2P_STATE_IDLE: + if (fgIsTransOut) { + + p2pStateAbort_IDLE(prAdapter, + prP2pFsmInfo, + eNextState); + } + else { + fgIsTransOut = p2pStateInit_IDLE(prAdapter, + prP2pFsmInfo, + prP2pBssInfo, + &eNextState); + } + + break; + case P2P_STATE_SCAN: + if (fgIsTransOut) { + + // Scan done / scan canceled. + p2pStateAbort_SCAN(prAdapter, prP2pFsmInfo, eNextState); + } + else { + // Initial scan request. + p2pStateInit_SCAN(prAdapter, prP2pFsmInfo); + } + + break; + case P2P_STATE_AP_CHANNEL_DETECT: + if (fgIsTransOut) { + // Scan done + // Get sparse channel result. + p2pStateAbort_AP_CHANNEL_DETECT(prAdapter, + prP2pFsmInfo, + prP2pSpecificBssInfo, + eNextState); + } + + else { + // Initial passive scan request. + p2pStateInit_AP_CHANNEL_DETECT(prAdapter, prP2pFsmInfo); + } + + break; + case P2P_STATE_REQING_CHANNEL: + if (fgIsTransOut) { + + // Channel on hand / Channel canceled. + p2pStateAbort_REQING_CHANNEL(prAdapter, prP2pFsmInfo, eNextState); + } + else { + // Initial channel request. + p2pFuncAcquireCh(prAdapter, &(prP2pFsmInfo->rChnlReqInfo)); + } + + break; + case P2P_STATE_CHNL_ON_HAND: + if (fgIsTransOut) { + + p2pStateAbort_CHNL_ON_HAND(prAdapter, prP2pFsmInfo, eNextState); + } + else { + // Initial channel ready. + // Send channel ready event. + // Start a FSM timer. + p2pStateInit_CHNL_ON_HAND(prAdapter, prP2pFsmInfo); + } + + break; + case P2P_STATE_GC_JOIN: + if (fgIsTransOut) { + + // Join complete / join canceled. + p2pStateAbort_GC_JOIN(prAdapter, + prP2pFsmInfo, + &(prP2pFsmInfo->rJoinInfo), + eNextState); + } + else { + ASSERT(prP2pFsmInfo->prTargetBss != NULL); + + // Send request to SAA module. + p2pStateInit_GC_JOIN(prAdapter, + prP2pFsmInfo, + prP2pBssInfo, + &(prP2pFsmInfo->rJoinInfo), + prP2pFsmInfo->prTargetBss); + } + + break; + default: + break; + } + + } while (fgIsTransOut); + +} /* p2pFsmStateTransition */ + + +VOID +p2pFsmRunEventSwitchOPMode ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + P_MSG_P2P_SWITCH_OP_MODE_T prSwitchOpMode = (P_MSG_P2P_SWITCH_OP_MODE_T)prMsgHdr; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prSwitchOpMode != NULL)); + + DBGLOG(P2P, TRACE, ("p2pFsmRunEventSwitchOPMode\n")); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + + if (prSwitchOpMode->eOpMode >= OP_MODE_NUM) { + ASSERT(FALSE); + break; + } + + /* P2P Device / GC. */ + p2pFuncSwitchOPMode(prAdapter, + prP2pBssInfo, + prSwitchOpMode->eOpMode, + TRUE); + + } while (FALSE); + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } + + +} /* p2pFsmRunEventSwitchOPMode */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is used to handle scan done event during Device Discovery. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFsmRunEventScanDone ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + P_P2P_SCAN_REQ_INFO_T prScanReqInfo = (P_P2P_SCAN_REQ_INFO_T)NULL; + P_MSG_SCN_SCAN_DONE prScanDoneMsg = (P_MSG_SCN_SCAN_DONE)NULL; + ENUM_P2P_STATE_T eNextState = P2P_STATE_NUM; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + + /* This scan done event is either for "SCAN" phase or "SEARCH" state or "LISTEN" state. + * The scan done for SCAN phase & SEARCH state doesn't imply Device + * Discovery over. + */ + DBGLOG(P2P, TRACE, ("P2P Scan Done Event\n")); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + prScanReqInfo = &(prP2pFsmInfo->rScanReqInfo); + prScanDoneMsg = (P_MSG_SCN_SCAN_DONE)prMsgHdr; + + if (prScanDoneMsg->ucSeqNum != prScanReqInfo->ucSeqNumOfScnMsg) { + /* Scan Done message sequence number mismatch. + * Ignore this event. (P2P FSM issue two scan events.) + */ + /* The scan request has been cancelled. + * Ignore this message. It is possible. + */ + DBGLOG(P2P, TRACE, ("P2P Scan Don SeqNum:%d <-> P2P Fsm SCAN Msg:%d\n", + prScanDoneMsg->ucSeqNum, + prScanReqInfo->ucSeqNumOfScnMsg)); + + break; + } + + + switch (prP2pFsmInfo->eCurrentState) { + case P2P_STATE_SCAN: + { + P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo = &(prP2pFsmInfo->rConnReqInfo); + + prScanReqInfo->fgIsAbort = FALSE; + + if (prConnReqInfo->fgIsConnRequest) { + + if ((prP2pFsmInfo->prTargetBss = p2pFuncKeepOnConnection(prAdapter, + &prP2pFsmInfo->rConnReqInfo, + &prP2pFsmInfo->rChnlReqInfo, + &prP2pFsmInfo->rScanReqInfo)) == NULL) { + eNextState = P2P_STATE_SCAN; + } + else { + eNextState = P2P_STATE_REQING_CHANNEL; + } + + } + else { + eNextState = P2P_STATE_IDLE; + } + + } + break; + case P2P_STATE_AP_CHANNEL_DETECT: + eNextState = P2P_STATE_REQING_CHANNEL; + break; + default: + /* Unexpected channel scan done event without being chanceled. */ + ASSERT(FALSE); + break; + } + + prScanReqInfo->fgIsScanRequest = FALSE; + + p2pFsmStateTransition(prAdapter, + prP2pFsmInfo, + eNextState); + + } while (FALSE); + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } + + return; +} /* p2pFsmRunEventScanDone */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is call when channel is granted by CNM module from FW. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFsmRunEventChGrant ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T)NULL; + P_MSG_CH_GRANT_T prMsgChGrant = (P_MSG_CH_GRANT_T)NULL; + UINT_8 ucTokenID = 0; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + DBGLOG(P2P, TRACE, ("P2P Run Event Channel Grant\n")); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + prMsgChGrant = (P_MSG_CH_GRANT_T)prMsgHdr; + ucTokenID = prMsgChGrant->ucTokenID; + prP2pFsmInfo->u4GrantInterval = prMsgChGrant->u4GrantInterval; + + prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); + + if (ucTokenID == prChnlReqInfo->ucSeqNumOfChReq) { + ENUM_P2P_STATE_T eNextState = P2P_STATE_NUM; + + switch (prP2pFsmInfo->eCurrentState) { + case P2P_STATE_REQING_CHANNEL: + switch (prChnlReqInfo->eChannelReqType) { + case CHANNEL_REQ_TYPE_REMAIN_ON_CHANNEL: + eNextState = P2P_STATE_CHNL_ON_HAND; + break; + case CHANNEL_REQ_TYPE_GC_JOIN_REQ: + eNextState = P2P_STATE_GC_JOIN; + break; + case CHANNEL_REQ_TYPE_GO_START_BSS: + eNextState = P2P_STATE_IDLE; + break; + default: + break; + } + + p2pFsmStateTransition(prAdapter, + prP2pFsmInfo, + eNextState); + break; + default: + /* Channel is granted under unexpected state. + * Driver should cancel channel privileagea before leaving the states. + */ + ASSERT(FALSE); + break; + } + + } + else { + /* Channel requsted, but released. */ + ASSERT(!prChnlReqInfo->fgIsChannelRequested); + } + } while (FALSE); + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } + + return; + +} /* p2pFsmRunEventChGrant */ + + +VOID +p2pFsmRunEventChannelRequest ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T)NULL; + P_MSG_P2P_CHNL_REQUEST_T prP2pChnlReqMsg = (P_MSG_P2P_CHNL_REQUEST_T)NULL; + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + ENUM_P2P_STATE_T eNextState = P2P_STATE_NUM; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + prP2pChnlReqMsg = (P_MSG_P2P_CHNL_REQUEST_T)prMsgHdr; + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); + + DBGLOG(P2P, TRACE, ("p2pFsmRunEventChannelRequest\n")); + + /* Special case of time renewing for same frequency. */ + if ((prP2pFsmInfo->eCurrentState == P2P_STATE_CHNL_ON_HAND) && + (prChnlReqInfo->ucReqChnlNum == prP2pChnlReqMsg->rChannelInfo.ucChannelNum) && + (prChnlReqInfo->eBand == prP2pChnlReqMsg->rChannelInfo.eBand) && + (prChnlReqInfo->eChnlSco == prP2pChnlReqMsg->eChnlSco)) { + + ASSERT(prChnlReqInfo->fgIsChannelRequested == TRUE); + ASSERT(prChnlReqInfo->eChannelReqType == CHANNEL_REQ_TYPE_REMAIN_ON_CHANNEL); + + prChnlReqInfo->u8Cookie = prP2pChnlReqMsg->u8Cookie; + prChnlReqInfo->u4MaxInterval = prP2pChnlReqMsg->u4Duration; + + /* Re-enter the state. */ + eNextState = P2P_STATE_CHNL_ON_HAND; + } + else { + + // Make sure the state is in IDLE state. + p2pFsmRunEventAbort(prAdapter, prP2pFsmInfo); + + prChnlReqInfo->u8Cookie = prP2pChnlReqMsg->u8Cookie; /* Cookie can only be assign after abort.(for indication) */ + prChnlReqInfo->ucReqChnlNum = prP2pChnlReqMsg->rChannelInfo.ucChannelNum; + prChnlReqInfo->eBand = prP2pChnlReqMsg->rChannelInfo.eBand; + prChnlReqInfo->eChnlSco = prP2pChnlReqMsg->eChnlSco; + prChnlReqInfo->u4MaxInterval = prP2pChnlReqMsg->u4Duration; + prChnlReqInfo->eChannelReqType = CHANNEL_REQ_TYPE_REMAIN_ON_CHANNEL; + + eNextState = P2P_STATE_REQING_CHANNEL; + } + +#if 1 + prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].ucPrimaryChannel = prP2pChnlReqMsg->rChannelInfo.ucChannelNum; + prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].eBand = prP2pChnlReqMsg->rChannelInfo.eBand; + +#endif + + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, eNextState); + + } while (FALSE); + + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } + + return; +} /* p2pFsmRunEventChannelRequest */ + + +VOID +p2pFsmRunEventChannelAbort ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + P_MSG_P2P_CHNL_ABORT_T prChnlAbortMsg = (P_MSG_P2P_CHNL_ABORT_T)NULL; + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + prChnlAbortMsg = (P_MSG_P2P_CHNL_ABORT_T)prMsgHdr; + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + prChnlReqInfo = &prP2pFsmInfo->rChnlReqInfo; + + DBGLOG(P2P, TRACE, ("p2pFsmRunEventChannelAbort\n")); + + if ((prChnlAbortMsg->u8Cookie == prChnlReqInfo->u8Cookie) && + (prChnlReqInfo->fgIsChannelRequested)) { + + DBGLOG(P2P, TRACE, ("prP2pFsmInfo->eCurrentState:%d \n", + prP2pFsmInfo->eCurrentState)); + + ASSERT((prP2pFsmInfo->eCurrentState == P2P_STATE_REQING_CHANNEL || + (prP2pFsmInfo->eCurrentState == P2P_STATE_CHNL_ON_HAND))); + + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); + } + + } while (FALSE); + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } + + return; +} /* p2pFsmRunEventChannelAbort */ + + + +VOID +p2pFsmRunEventScanRequest ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + P_MSG_P2P_SCAN_REQUEST_T prP2pScanReqMsg = (P_MSG_P2P_SCAN_REQUEST_T)NULL; + P_P2P_SCAN_REQ_INFO_T prScanReqInfo = (P_P2P_SCAN_REQ_INFO_T)NULL; + UINT_32 u4ChnlListSize = 0; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + prP2pScanReqMsg = (P_MSG_P2P_SCAN_REQUEST_T)prMsgHdr; + prScanReqInfo = &(prP2pFsmInfo->rScanReqInfo); + + DBGLOG(P2P, TRACE, ("p2pFsmRunEventScanRequest\n")); + + // Make sure the state is in IDLE state. + p2pFsmRunEventAbort(prAdapter, prP2pFsmInfo); + + ASSERT(prScanReqInfo->fgIsScanRequest == FALSE); + + prScanReqInfo->fgIsAbort = TRUE; + prScanReqInfo->eScanType = SCAN_TYPE_ACTIVE_SCAN; + prScanReqInfo->eChannelSet = SCAN_CHANNEL_SPECIFIED; + + // Channel List + prScanReqInfo->ucNumChannelList = prP2pScanReqMsg->u4NumChannel; + DBGLOG(P2P, TRACE, ("Scan Request Channel List Number: %d\n", prScanReqInfo->ucNumChannelList)); + if (prScanReqInfo->ucNumChannelList > MAXIMUM_OPERATION_CHANNEL_LIST) { + DBGLOG(P2P, TRACE, ("Channel List Number Overloaded: %d, change to: %d\n", + prScanReqInfo->ucNumChannelList, + MAXIMUM_OPERATION_CHANNEL_LIST)); + prScanReqInfo->ucNumChannelList = MAXIMUM_OPERATION_CHANNEL_LIST; + } + + u4ChnlListSize = sizeof(RF_CHANNEL_INFO_T) * prScanReqInfo->ucNumChannelList; + kalMemCopy(prScanReqInfo->arScanChannelList, prP2pScanReqMsg->arChannelListInfo, u4ChnlListSize); + + // TODO: I only take the first SSID. Multiple SSID may be needed in the future. + // SSID + if (prP2pScanReqMsg->i4SsidNum >= 1) { + + kalMemCopy(&(prScanReqInfo->rSsidStruct), + prP2pScanReqMsg->prSSID, + sizeof(P2P_SSID_STRUCT_T)); + } + else { + prScanReqInfo->rSsidStruct.ucSsidLen = 0; + } + + // IE Buffer + kalMemCopy(prScanReqInfo->aucIEBuf, + prP2pScanReqMsg->pucIEBuf, + prP2pScanReqMsg->u4IELen); + + prScanReqInfo->u4BufLength = prP2pScanReqMsg->u4IELen; + + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_SCAN); + + + + } while (FALSE); + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } + + +} /* p2pFsmRunEventScanRequest */ + + +VOID +p2pFsmRunEventScanAbort ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + + do { + ASSERT_BREAK(prAdapter != NULL); + + DBGLOG(P2P, TRACE, ("p2pFsmRunEventScanAbort\n")); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + if (prP2pFsmInfo->eCurrentState == P2P_STATE_SCAN) { + P_P2P_SCAN_REQ_INFO_T prScanReqInfo = &(prP2pFsmInfo->rScanReqInfo); + + prScanReqInfo->fgIsAbort = TRUE; + + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); + } + + } while (FALSE); + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } + + return; +} /* p2pFsmRunEventScanAbort */ + + + + + +VOID +p2pFsmRunEventAbort ( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo + ) +{ + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); + + DBGLOG(P2P, TRACE, ("p2pFsmRunEventAbort\n")); + + if (prP2pFsmInfo->eCurrentState != P2P_STATE_IDLE) { + + if (prP2pFsmInfo->eCurrentState == P2P_STATE_SCAN) { + + P_P2P_SCAN_REQ_INFO_T prScanReqInfo = &(prP2pFsmInfo->rScanReqInfo); + + prScanReqInfo->fgIsAbort = TRUE; + } + // For other state, is there any special action that should be take before leaving? + + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); + } + else { + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); + + if (prChnlReqInfo->fgIsChannelRequested) { + cnmTimerStopTimer(prAdapter, &(prP2pFsmInfo->rP2pFsmTimeoutTimer)); + } + } + + + } while (FALSE); + + return; +} /* p2pFsmRunEventAbort */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is used to handle FSM Timeout. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFsmRunEventFsmTimeout ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Param + ) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)u4Param; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); + + DBGLOG(P2P, TRACE, ("P2P FSM Timeout Event\n")); + + switch (prP2pFsmInfo->eCurrentState) { + case P2P_STATE_IDLE: + { + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = &prP2pFsmInfo->rChnlReqInfo; + if (prChnlReqInfo->fgIsChannelRequested) { + p2pFuncReleaseCh(prAdapter, prChnlReqInfo); + } + } + break; + +// case P2P_STATE_SCAN: +// break; +// case P2P_STATE_AP_CHANNEL_DETECT: +// break; +// case P2P_STATE_REQING_CHANNEL: +// break; + case P2P_STATE_CHNL_ON_HAND: + { + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); + } + break; +// case P2P_STATE_GC_JOIN: +// break; + default: + break; + } + + } while (FALSE); + + return; +} /* p2pFsmRunEventFsmTimeout */ + +VOID +p2pFsmRunEventMgmtFrameTx ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + P_MSG_P2P_MGMT_TX_REQUEST_T prMgmtTxMsg = (P_MSG_P2P_MGMT_TX_REQUEST_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + DBGLOG(P2P, TRACE, ("p2pFsmRunEventMgmtFrameTx\n")); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + prMgmtTxMsg = (P_MSG_P2P_MGMT_TX_REQUEST_T)prMsgHdr; + + p2pFuncTxMgmtFrame(prAdapter, + &prP2pFsmInfo->rMgmtTxInfo, + prMgmtTxMsg->prMgmtMsduInfo, + prMgmtTxMsg->u8Cookie); + + + + } while (FALSE); + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } + + return; + +} +/* p2pFsmRunEventMgmtTx */ + + +VOID +p2pFsmRunEventBeaconUpdate ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + P_MSG_P2P_BEACON_UPDATE_T prBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + DBGLOG(P2P, TRACE, ("p2pFsmRunEventBeaconUpdate\n")); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + DBGLOG(P2P, TRACE, ("p2pFsmRunEventBeaconUpdate 0001\n")); + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + DBGLOG(P2P, TRACE, ("p2pFsmRunEventBeaconUpdate 0002\n")); + prBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T)prMsgHdr; + DBGLOG(P2P, TRACE, ("p2pFsmRunEventBeaconUpdate 0003\n")); + if (prBcnUpdateMsg->u4BcnInterval) { + DBGLOG(P2P, TRACE, ("Beacon interval updated to :%ld \n", prBcnUpdateMsg->u4BcnInterval)); + prP2pBssInfo->u2BeaconInterval = (UINT_16)prBcnUpdateMsg->u4BcnInterval; + } + else if (prP2pBssInfo->u2BeaconInterval == 0) { + prP2pBssInfo->u2BeaconInterval = DOT11_BEACON_PERIOD_DEFAULT; + } + if (prBcnUpdateMsg->u4DtimPeriod) { + DBGLOG(P2P, TRACE, ("DTIM interval updated to :%ld \n", prBcnUpdateMsg->u4DtimPeriod)); + prP2pBssInfo->ucDTIMPeriod = (UINT_8)prBcnUpdateMsg->u4DtimPeriod; + } + else if (prP2pBssInfo->ucDTIMPeriod == 0) { + prP2pBssInfo->ucDTIMPeriod = DOT11_DTIM_PERIOD_DEFAULT; + } + DBGLOG(P2P, TRACE, ("p2pFsmRunEventBeaconUpdate 0004\n")); + p2pFuncBeaconUpdate(prAdapter, + prP2pBssInfo, + &prP2pFsmInfo->rBcnContentInfo, + prBcnUpdateMsg->pucBcnHdr, + prBcnUpdateMsg->u4BcnHdrLen, + prBcnUpdateMsg->pucBcnBody, + prBcnUpdateMsg->u4BcnBodyLen); + DBGLOG(P2P, TRACE, ("p2pFsmRunEventBeaconUpdate 0005\n")); + + if ((prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) && + (prP2pBssInfo->eIntendOPMode == OP_MODE_NUM)) { + /* AP is created, Beacon Update. */ + nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_P2P_INDEX); + + nicPmIndicateBssCreated(prAdapter, NETWORK_TYPE_P2P_INDEX); + DBGLOG(P2P, TRACE, ("AP is created, Beacon Update\n")); + } + else { + UINT_8 ucPreferedChnl = 0; + ENUM_BAND_T eBand = BAND_NULL; + ENUM_CHNL_EXT_T eSco = CHNL_EXT_SCN; + ENUM_P2P_STATE_T eNextState = P2P_STATE_SCAN; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + + + if(prP2pFsmInfo->eCurrentState != P2P_STATE_SCAN && + prP2pFsmInfo->eCurrentState != P2P_STATE_IDLE) { + // Make sure the state is in IDLE state. + p2pFsmRunEventAbort(prAdapter, prP2pFsmInfo); + } + + // 20120118: Moved to p2pFuncSwitchOPMode(). + //SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); + + /* Leave IDLE state. */ + SET_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); + + // sync with firmware + //DBGLOG(P2P, INFO, ("Activate P2P Network. \n")); + //nicActivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); + + + /* Key to trigger P2P FSM to allocate channel for AP mode. */ + prP2pBssInfo->eIntendOPMode = OP_MODE_ACCESS_POINT; + + /* Sparse Channel to decide which channel to use. */ + if ((cnmPreferredChannel(prAdapter, + &eBand, + &ucPreferedChnl, + &eSco) == FALSE) && (prP2pConnSettings->ucOperatingChnl == 0)) { + // Sparse Channel Detection using passive mode. + eNextState = P2P_STATE_AP_CHANNEL_DETECT; + } + else { + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = &prP2pFsmInfo->rChnlReqInfo; + + +#if 1 + /* 2012-01-27: frog - Channel set from upper layer is the first priority. */ + /* Becuase the channel & beacon is decided by p2p_supplicant. */ + if (prP2pConnSettings->ucOperatingChnl != 0) { + prP2pSpecificBssInfo->ucPreferredChannel = prP2pConnSettings->ucOperatingChnl; + prP2pSpecificBssInfo->eRfBand = prP2pConnSettings->eBand; + } + else { + ASSERT(ucPreferedChnl != 0); + prP2pSpecificBssInfo->ucPreferredChannel = ucPreferedChnl; + prP2pSpecificBssInfo->eRfBand = eBand; + } +#else + if (ucPreferedChnl) { + prP2pSpecificBssInfo->ucPreferredChannel = ucPreferedChnl; + prP2pSpecificBssInfo->eRfBand = eBand; + } + else { + ASSERT(prP2pConnSettings->ucOperatingChnl != 0); + prP2pSpecificBssInfo->ucPreferredChannel = prP2pConnSettings->ucOperatingChnl; + prP2pSpecificBssInfo->eRfBand = prP2pConnSettings->eBand; + } + +#endif + prChnlReqInfo->ucReqChnlNum = prP2pSpecificBssInfo->ucPreferredChannel; + prChnlReqInfo->eBand = prP2pSpecificBssInfo->eRfBand; + prChnlReqInfo->eChannelReqType = CHANNEL_REQ_TYPE_GO_START_BSS; + } + /* If channel is specified, use active scan to shorten the scan time. */ + p2pFsmStateTransition(prAdapter, + prAdapter->rWifiVar.prP2pFsmInfo, + eNextState); + } + + + } while (FALSE); + + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } + +} /* p2pFsmRunEventBeaconUpdate */ + + +VOID +p2pFsmRunEventBeaconAbort ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL)); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + DBGLOG(P2P, TRACE, ("p2pFsmRunEventBeaconAbort\n")); + + if ((prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT)) { + /* AP is created, Beacon Update. */ + DBGLOG(P2P, TRACE, ("Stop Beaconing\n")); + nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_P2P_INDEX); + + /* Reset RLM related field of BSSINFO. */ + rlmBssAborted(prAdapter, prP2pBssInfo); + } + + // 20120118: Moved to p2pFuncSwitchOPMode(). + //UNSET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); + + /* Enter IDLE state. */ + SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_P2P_INDEX); + + DBGLOG(P2P, INFO, ("Re activate P2P Network. \n")); + nicDeactivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); + + nicActivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); + + } while (FALSE); + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } + +} /* p2pFsmRunEventBeaconAbort */ + +VOID +p2pFsmRunEventConnectionRequest ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T)NULL; + P_MSG_P2P_CONNECTION_REQUEST_T prConnReqMsg = (P_MSG_P2P_CONNECTION_REQUEST_T)NULL; + P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo = (P_P2P_CONNECTION_REQ_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + prConnReqMsg = (P_MSG_P2P_CONNECTION_REQUEST_T)prMsgHdr; + + prConnReqInfo = &(prP2pFsmInfo->rConnReqInfo); + prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); + + DBGLOG(P2P, TRACE, ("p2pFsmRunEventConnectionRequest\n")); + + if (prP2pBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) { + break; + } + // Make sure the state is in IDLE state. + p2pFsmRunEventAbort(prAdapter, prP2pFsmInfo); + + // Update connection request information. + prConnReqInfo->fgIsConnRequest = TRUE; + COPY_MAC_ADDR(prConnReqInfo->aucBssid, prConnReqMsg->aucBssid); + kalMemCopy(&(prConnReqInfo->rSsidStruct), &(prConnReqMsg->rSsid), sizeof(P2P_SSID_STRUCT_T)); + kalMemCopy(prConnReqInfo->aucIEBuf, prConnReqMsg->aucIEBuf, prConnReqMsg->u4IELen); + prConnReqInfo->u4BufLength = prConnReqMsg->u4IELen; + + /* Find BSS Descriptor first. */ + prP2pFsmInfo->prTargetBss = scanP2pSearchDesc(prAdapter, + prP2pBssInfo, + prConnReqInfo); + + if (prP2pFsmInfo->prTargetBss == NULL) { + /* Update scan parameter... to scan target device. */ + P_P2P_SCAN_REQ_INFO_T prScanReqInfo = &(prP2pFsmInfo->rScanReqInfo); + + prScanReqInfo->ucNumChannelList = 1; + prScanReqInfo->eScanType = SCAN_TYPE_ACTIVE_SCAN; + prScanReqInfo->eChannelSet = SCAN_CHANNEL_SPECIFIED; + prScanReqInfo->arScanChannelList[0].ucChannelNum = prConnReqMsg->rChannelInfo.ucChannelNum; + kalMemCopy(&(prScanReqInfo->rSsidStruct), &(prConnReqMsg->rSsid), sizeof(P2P_SSID_STRUCT_T)); + prScanReqInfo->u4BufLength = 0; /* Prevent other P2P ID in IE. */ + prScanReqInfo->fgIsAbort = TRUE; + + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_SCAN); + } + else { + prChnlReqInfo->u8Cookie = 0; + prChnlReqInfo->ucReqChnlNum = prConnReqMsg->rChannelInfo.ucChannelNum; + prChnlReqInfo->eBand = prConnReqMsg->rChannelInfo.eBand; + prChnlReqInfo->eChnlSco = prConnReqMsg->eChnlSco; + prChnlReqInfo->u4MaxInterval = AIS_JOIN_CH_REQUEST_INTERVAL; + prChnlReqInfo->eChannelReqType = CHANNEL_REQ_TYPE_GC_JOIN_REQ; + + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_REQING_CHANNEL); + } + + + } while (FALSE); + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } + + return; + +} /* p2pFsmRunEventConnectionRequest */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is used to handle Connection Request from Supplicant. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFsmRunEventConnectionAbort ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + P_MSG_P2P_CONNECTION_ABORT_T prDisconnMsg = (P_MSG_P2P_CONNECTION_ABORT_T)NULL; + + do { + + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + DBGLOG(P2P, TRACE, ("p2pFsmRunEventConnectionAbort: Connection Abort.\n")); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + prDisconnMsg = (P_MSG_P2P_CONNECTION_ABORT_T)prMsgHdr; + + switch (prP2pBssInfo->eCurrentOPMode) { + case OP_MODE_INFRASTRUCTURE: + { + UINT_8 aucBCBSSID[] = BC_BSSID; + + kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, NULL, NULL, 0, 0); + + if (!prP2pBssInfo->prStaRecOfAP) { + DBGLOG(P2P, TRACE, ("GO's StaRec is NULL\n")); + break; + } + if (UNEQUAL_MAC_ADDR(prP2pBssInfo->prStaRecOfAP->aucMacAddr, prDisconnMsg->aucTargetID) && + UNEQUAL_MAC_ADDR(prDisconnMsg->aucTargetID, aucBCBSSID)) { + DBGLOG(P2P, TRACE, ("Unequal MAC ADDR ["MACSTR":"MACSTR"]\n", + MAC2STR(prP2pBssInfo->prStaRecOfAP->aucMacAddr), + MAC2STR(prDisconnMsg->aucTargetID))); + break; + } + + /* Stop rejoin timer if it is started. */ + // TODO: If it has. + + p2pFuncDisconnect(prAdapter, prP2pBssInfo->prStaRecOfAP, prDisconnMsg->fgSendDeauth, prDisconnMsg->u2ReasonCode); + + } + break; + case OP_MODE_ACCESS_POINT: + { + P_LINK_T prStaRecOfClientList = &prP2pBssInfo->rStaRecOfClientList; + /* Search specific client device, and disconnect. */ + /* 1. Send deauthentication frame. */ + /* 2. Indication: Device disconnect. */ + P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T)NULL; + P_STA_RECORD_T prCurrStaRec = (P_STA_RECORD_T)NULL; + + DBGLOG(P2P, TRACE, ("Disconnecting with Target ID: "MACSTR"\n", MAC2STR(prDisconnMsg->aucTargetID))); + + LINK_FOR_EACH(prLinkEntry, prStaRecOfClientList) { + prCurrStaRec = LINK_ENTRY(prLinkEntry, STA_RECORD_T, rLinkEntry); + + ASSERT(prCurrStaRec); + + if (EQUAL_MAC_ADDR(prCurrStaRec->aucMacAddr, prDisconnMsg->aucTargetID)) { + + DBGLOG(P2P, TRACE, ("Disconnecting: "MACSTR"\n", MAC2STR(prCurrStaRec->aucMacAddr))); + + /* Remove STA from client list. */ + LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, &prCurrStaRec->rLinkEntry); + + /* Glue layer indication. */ + kalP2PGOStationUpdate(prAdapter->prGlueInfo, prCurrStaRec, FALSE); + + /* Send deauth & do indication. */ + p2pFuncDisconnect(prAdapter, prCurrStaRec, prDisconnMsg->fgSendDeauth, prDisconnMsg->u2ReasonCode); + + break; + } + } + + } + break; + case OP_MODE_P2P_DEVICE: + default: + ASSERT(FALSE); + break; + } + + } while (FALSE); + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } + + return; +} /* p2pFsmRunEventConnectionAbort */ + + +VOID +p2pFsmRunEventDissolve ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + + // TODO: + + DBGLOG(P2P, TRACE, ("p2pFsmRunEventDissolve\n")); + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } + + return; +} +WLAN_STATUS +p2pFsmRunEventDeauthTxDone ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus + ) +{ + + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + ENUM_PARAM_MEDIA_STATE_T eOriMediaStatus; + + do { + + ASSERT_BREAK((prAdapter != NULL) && + (prMsduInfo != NULL)); + + DBGLOG(P2P, TRACE, ("Deauth TX Done\n")); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if (prStaRec == NULL) { + DBGLOG(P2P, TRACE, ("Station Record NULL, Index:%d\n", prMsduInfo->ucStaRecIndex)); + break; + } + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + eOriMediaStatus = prP2pBssInfo->eConnectionState; + + /* Change station state. */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + + /* Reset Station Record Status. */ + p2pFuncResetStaRecStatus(prAdapter, prStaRec); + + if ((prP2pBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) || + (prP2pBssInfo->rStaRecOfClientList.u4NumElem == 0)) { + DBGLOG(P2P, TRACE, ("No More Client, Media Status DISCONNECTED\n")); + p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); + } + + if (eOriMediaStatus != prP2pBssInfo->eConnectionState) { + /* Update Disconnected state to FW. */ + nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); + } + + + } while (FALSE); + + return WLAN_STATUS_SUCCESS; +} /* p2pFsmRunEventDeauthTxDone */ + + +WLAN_STATUS +p2pFsmRunEventMgmtFrameTxDone ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus + ) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + P_P2P_MGMT_TX_REQ_INFO_T prMgmtTxReqInfo = (P_P2P_MGMT_TX_REQ_INFO_T)NULL; + BOOLEAN fgIsSuccess = FALSE; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + prMgmtTxReqInfo = &(prP2pFsmInfo->rMgmtTxInfo); + + if (rTxDoneStatus != TX_RESULT_SUCCESS) { + DBGLOG(P2P, TRACE, ("Mgmt Frame TX Fail, Status:%d.\n", rTxDoneStatus)); + } + else { + fgIsSuccess = TRUE; + DBGLOG(P2P, TRACE, ("Mgmt Frame TX Done.\n")); + } + + + if (prMgmtTxReqInfo->prMgmtTxMsdu == prMsduInfo) { + kalP2PIndicateMgmtTxStatus(prAdapter->prGlueInfo, + prMgmtTxReqInfo->u8Cookie, + fgIsSuccess, + prMsduInfo->prPacket, + (UINT_32)prMsduInfo->u2FrameLength); + + prMgmtTxReqInfo->prMgmtTxMsdu = NULL; + } + + } while (FALSE); + + return WLAN_STATUS_SUCCESS; + +} /* p2pFsmRunEventMgmtFrameTxDone */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called when JOIN complete message event is received from SAA. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFsmRunEventJoinComplete ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + P_P2P_JOIN_INFO_T prJoinInfo = (P_P2P_JOIN_INFO_T)NULL; + P_MSG_JOIN_COMP_T prJoinCompMsg = (P_MSG_JOIN_COMP_T)NULL; + P_SW_RFB_T prAssocRspSwRfb = (P_SW_RFB_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + DBGLOG(P2P, TRACE, ("P2P Join Complete\n")); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + prJoinInfo = &(prP2pFsmInfo->rJoinInfo); + prJoinCompMsg = (P_MSG_JOIN_COMP_T)prMsgHdr; + prAssocRspSwRfb = prJoinCompMsg->prSwRfb; + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + if (prP2pBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + + prStaRec = prJoinCompMsg->prStaRec; + + /* Check SEQ NUM */ + if (prJoinCompMsg->ucSeqNum == prJoinInfo->ucSeqNumOfReqMsg) { + ASSERT(prStaRec == prJoinInfo->prTargetStaRec); + prJoinInfo->fgIsJoinComplete = TRUE; + + if (prJoinCompMsg->rJoinStatus == WLAN_STATUS_SUCCESS) { + + //4 <1.1> Change FW's Media State immediately. + p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); + + //4 <1.2> Deactivate previous AP's STA_RECORD_T in Driver if have. + if ((prP2pBssInfo->prStaRecOfAP) && + (prP2pBssInfo->prStaRecOfAP != prStaRec)) { + cnmStaRecChangeState(prAdapter, prP2pBssInfo->prStaRecOfAP, STA_STATE_1); + } + + //4 <1.3> Update BSS_INFO_T + p2pFuncUpdateBssInfoForJOIN(prAdapter, prP2pFsmInfo->prTargetBss, prStaRec, prAssocRspSwRfb); + + //4 <1.4> Activate current AP's STA_RECORD_T in Driver. + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + +#if CFG_SUPPORT_P2P_RSSI_QUERY + //<1.5> Update RSSI if necessary + nicUpdateRSSI(prAdapter, NETWORK_TYPE_P2P_INDEX, (INT_8)(RCPI_TO_dBm(prStaRec->ucRCPI)), 0); +#endif + + //4 <1.6> Indicate Connected Event to Host immediately. + /* Require BSSID, Association ID, Beacon Interval.. from AIS_BSS_INFO_T */ + //p2pIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_CONNECTED, prStaRec->aucMacAddr); + kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, + &prP2pFsmInfo->rConnReqInfo, + prJoinInfo->aucIEBuf, + prJoinInfo->u4BufLength, + prStaRec->u2StatusCode); + + } + else { + /* Join Fail*/ + //4 <2.1> Redo JOIN process with other Auth Type if possible + if (p2pFuncRetryJOIN(prAdapter, prStaRec, prJoinInfo) == FALSE) { + P_BSS_DESC_T prBssDesc; + + /* Increase Failure Count */ + prStaRec->ucJoinFailureCount++; + + prBssDesc = prP2pFsmInfo->prTargetBss; + + ASSERT(prBssDesc); + ASSERT(prBssDesc->fgIsConnecting); + + prBssDesc->fgIsConnecting = FALSE; + + kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, + &prP2pFsmInfo->rConnReqInfo, + prJoinInfo->aucIEBuf, + prJoinInfo->u4BufLength, + prStaRec->u2StatusCode); + + } + + } + } + } + + if (prAssocRspSwRfb) { + nicRxReturnRFB(prAdapter, prAssocRspSwRfb); + } + + if (prP2pFsmInfo->eCurrentState == P2P_STATE_GC_JOIN) { + /* Return to IDLE state. */ + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); + } + + } while (FALSE); + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } + + return; + +} /* p2pFsmRunEventJoinComplete */ + + + +VOID +p2pFsmRunEventMgmtFrameRegister ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_MSG_P2P_MGMT_FRAME_REGISTER_T prMgmtFrameRegister = (P_MSG_P2P_MGMT_FRAME_REGISTER_T)NULL; + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + prMgmtFrameRegister = (P_MSG_P2P_MGMT_FRAME_REGISTER_T)prMsgHdr; + + p2pFuncMgmtFrameRegister(prAdapter, + prMgmtFrameRegister->u2FrameType, + prMgmtFrameRegister->fgIsRegister, + &prP2pFsmInfo->u4P2pPacketFilter); + + + } while (FALSE); + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } + + return; +} /* p2pFsmRunEventMgmtFrameRegister */ + + + + +#if 0 +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#endif + + + + + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is call when RX deauthentication frame from the AIR. +* If we are under STA mode, we would go back to P2P Device. +* If we are under AP mode, we would stay in AP mode until disconnect event from HOST. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFsmRunEventRxDeauthentication ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prSwRfb + ) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + UINT_16 u2ReasonCode = 0; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); + + if (prStaRec == NULL) { + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + } + + + prP2pBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; + + if (prStaRec->ucStaState == STA_STATE_1) { + break; + } + + DBGLOG(P2P, TRACE, ("RX Deauth\n")); + + switch (prP2pBssInfo->eCurrentOPMode) { + case OP_MODE_INFRASTRUCTURE: + if (authProcessRxDeauthFrame(prSwRfb, + prStaRec->aucMacAddr, + &u2ReasonCode) == WLAN_STATUS_SUCCESS) { + P_WLAN_DEAUTH_FRAME_T prDeauthFrame = (P_WLAN_DEAUTH_FRAME_T)prSwRfb->pvHeader; + UINT_16 u2IELength = 0; + + prStaRec->u2ReasonCode = u2ReasonCode; + u2IELength = prSwRfb->u2PacketLen - (WLAN_MAC_HEADER_LEN + REASON_CODE_FIELD_LEN); + + ASSERT(prP2pBssInfo->prStaRecOfAP == prStaRec); + + /* Indicate disconnect to Host. */ + kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, + NULL, + prDeauthFrame->aucInfoElem, + u2IELength, + u2ReasonCode); + + p2pFuncDisconnect(prAdapter, prStaRec, FALSE, u2ReasonCode); + } + break; + case OP_MODE_ACCESS_POINT: + /* Delete client from client list. */ + if (authProcessRxDeauthFrame(prSwRfb, + prP2pBssInfo->aucBSSID, + &u2ReasonCode) == WLAN_STATUS_SUCCESS) { + P_LINK_T prStaRecOfClientList = (P_LINK_T)NULL; + P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T)NULL; + P_STA_RECORD_T prCurrStaRec = (P_STA_RECORD_T)NULL; + + prStaRecOfClientList = &prP2pBssInfo->rStaRecOfClientList; + + LINK_FOR_EACH(prLinkEntry, prStaRecOfClientList) { + prCurrStaRec = LINK_ENTRY(prLinkEntry, STA_RECORD_T, rLinkEntry); + + ASSERT(prCurrStaRec); + + if (EQUAL_MAC_ADDR(prCurrStaRec->aucMacAddr, prStaRec->aucMacAddr)) { + + /* Remove STA from client list. */ + LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, &prCurrStaRec->rLinkEntry); + + /* Indicate to Host. */ + kalP2PGOStationUpdate(prAdapter->prGlueInfo, prStaRec, FALSE); + + /* Indicate disconnect to Host. */ + p2pFuncDisconnect(prAdapter, prStaRec, FALSE, u2ReasonCode); + + break; + } + } + } + break; + case OP_MODE_P2P_DEVICE: + default: + /* Findout why someone sent deauthentication frame to us. */ + ASSERT(FALSE); + break; + } + + DBGLOG(P2P, TRACE, ("Deauth Reason:%d\n", u2ReasonCode)); + + } while (FALSE); + + + return; +} /* p2pFsmRunEventRxDeauthentication */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is call when RX deauthentication frame from the AIR. +* If we are under STA mode, we would go back to P2P Device. +* If we are under AP mode, we would stay in AP mode until disconnect event from HOST. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFsmRunEventRxDisassociation ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prSwRfb + ) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + UINT_16 u2ReasonCode = 0; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); + + if (prStaRec == NULL) { + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + } + + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + if (prStaRec->ucStaState == STA_STATE_1) { + + break; + } + + DBGLOG(P2P, TRACE, ("RX Disassoc\n")); + + switch (prP2pBssInfo->eCurrentOPMode) { + case OP_MODE_INFRASTRUCTURE: + if (assocProcessRxDisassocFrame(prAdapter, + prSwRfb, + prStaRec->aucMacAddr, + &prStaRec->u2ReasonCode) == WLAN_STATUS_SUCCESS) { + P_WLAN_DISASSOC_FRAME_T prDisassocFrame = (P_WLAN_DISASSOC_FRAME_T)prSwRfb->pvHeader; + UINT_16 u2IELength = 0; + + ASSERT(prP2pBssInfo->prStaRecOfAP == prStaRec); + + u2IELength = prSwRfb->u2PacketLen - (WLAN_MAC_HEADER_LEN + REASON_CODE_FIELD_LEN); + + /* Indicate disconnect to Host. */ + kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, + NULL, + prDisassocFrame->aucInfoElem, + u2IELength, + prStaRec->u2ReasonCode); + } + break; + case OP_MODE_ACCESS_POINT: + /* Delete client from client list. */ + if (assocProcessRxDisassocFrame(prAdapter, + prSwRfb, + prP2pBssInfo->aucBSSID, + &u2ReasonCode) == WLAN_STATUS_SUCCESS) { + P_LINK_T prStaRecOfClientList = (P_LINK_T)NULL; + P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T)NULL; + P_STA_RECORD_T prCurrStaRec = (P_STA_RECORD_T)NULL; + + prStaRecOfClientList = &prP2pBssInfo->rStaRecOfClientList; + + LINK_FOR_EACH(prLinkEntry, prStaRecOfClientList) { + prCurrStaRec = LINK_ENTRY(prLinkEntry, STA_RECORD_T, rLinkEntry); + + ASSERT(prCurrStaRec); + + if (EQUAL_MAC_ADDR(prCurrStaRec->aucMacAddr, prStaRec->aucMacAddr)) { + + /* Remove STA from client list. */ + LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, &prCurrStaRec->rLinkEntry); + + /* Indicate to Host. */ + kalP2PGOStationUpdate(prAdapter->prGlueInfo, prStaRec, FALSE); + + /* Indicate disconnect to Host. */ + p2pFuncDisconnect(prAdapter, prStaRec, FALSE, u2ReasonCode); + + break; + } + } + } + break; + case OP_MODE_P2P_DEVICE: + default: + ASSERT(FALSE); + break; + } + + + } while (FALSE); + + return; +} /* p2pFsmRunEventRxDisassociation */ + + + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called when a probe request frame is received. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return boolean value if probe response frame is accepted & need cancel scan request. +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFsmRunEventRxProbeResponseFrame ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN P_BSS_DESC_T prBssDesc + ) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T)NULL; + P_WLAN_MAC_MGMT_HEADER_T prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL) && (prBssDesc != NULL)); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + prP2pBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; + + /* There is a connection request. */ + prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T)prSwRfb->pvHeader; + + } while (FALSE); + + return; +} /* p2pFsmRunEventRxProbeResponseFrame */ + + + + + + +VOID +p2pFsmRunEventBeaconTimeout ( + IN P_ADAPTER_T prAdapter + ) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + + do { + ASSERT_BREAK(prAdapter != NULL); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + DBGLOG(P2P, TRACE, ("p2pFsmRunEventBeaconTimeout: Beacon Timeout\n")); + + /* Only client mode would have beacon lost event. */ + ASSERT(prP2pBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE); + + if (prP2pBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + /* Indicate disconnect to Host. */ + kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, + NULL, + NULL, + 0, + REASON_CODE_DISASSOC_INACTIVITY); + + if (prP2pBssInfo->prStaRecOfAP != NULL) { + p2pFuncDisconnect(prAdapter, prP2pBssInfo->prStaRecOfAP, FALSE, REASON_CODE_DISASSOC_INACTIVITY); + } + } + } while (FALSE); + + return; +} /* p2pFsmRunEventBeaconTimeout */ + + + + + + + + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to generate P2P IE for Beacon frame. +* +* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pGenerateP2P_IEForAssocReq ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if (IS_STA_P2P_TYPE(prStaRec)) { + // TODO: + } + + } while (FALSE); + + return; + +} /* end of p2pGenerateP2P_IEForAssocReq() */ + + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to generate P2P IE for Probe Request frame. +* +* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pGenerateP2P_IEForProbeReq ( + IN P_ADAPTER_T prAdapter, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ) +{ + ASSERT(prAdapter); + ASSERT(pucBuf); + + // TODO: + + return; + +} /* end of p2pGenerateP2P_IEForProbReq() */ + + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to calculate P2P IE length for Beacon frame. +* +* @param[in] eNetTypeIndex Specify which network +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return The length of P2P IE added +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 +p2pCalculateP2P_IELenForProbeReq ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec + ) +{ + + if (eNetTypeIndex != NETWORK_TYPE_P2P_INDEX) { + return 0; + } + + // TODO: + + return 0; + +} /* end of p2pCalculateP2P_IELenForProbeReq() */ + + + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indiate the Event of Tx Fail of AAA Module. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pRunEventAAATxFail ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ) +{ + P_BSS_INFO_T prBssInfo; + + + ASSERT(prAdapter); + ASSERT(prStaRec); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + p2pFuncDisconnect(prAdapter, prStaRec, FALSE, REASON_CODE_UNSPECIFIED); + + bssRemoveStaRecFromClientList(prAdapter, prBssInfo, prStaRec); + + return; +} /* p2pRunEventAAATxFail */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indiate the Event of Successful Completion of AAA Module. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +p2pRunEventAAAComplete ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + ENUM_PARAM_MEDIA_STATE_T eOriMediaState; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prStaRec != NULL)); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + eOriMediaState = prP2pBssInfo->eConnectionState; + + bssRemoveStaRecFromClientList(prAdapter, prP2pBssInfo, prStaRec); + + if (prP2pBssInfo->rStaRecOfClientList.u4NumElem >= P2P_MAXIMUM_CLIENT_COUNT) { + rStatus = WLAN_STATUS_RESOURCES; + break; + } + + bssAddStaRecToClientList(prAdapter, prP2pBssInfo, prStaRec); + + prStaRec->u2AssocId = bssAssignAssocID(prStaRec); + + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + + p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); + + /* Update Connected state to FW. */ + if (eOriMediaState != prP2pBssInfo->eConnectionState) { + nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); + } + + } while (FALSE); + + return rStatus; +} /* p2pRunEventAAAComplete */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indiate the Event of Successful Completion of AAA Module. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +p2pRunEventAAASuccess ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prStaRec != NULL)); + + /* Glue layer indication. */ + kalP2PGOStationUpdate(prAdapter->prGlueInfo, prStaRec, TRUE); + + } while (FALSE); + + return rStatus; +} /* p2pRunEventAAASuccess */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +p2pRxPublicActionFrame ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + P_P2P_PUBLIC_ACTION_FRAME_T prPublicActionFrame = (P_P2P_PUBLIC_ACTION_FRAME_T)NULL; + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + + ASSERT(prSwRfb); + ASSERT(prAdapter); + + + + prPublicActionFrame = (P_P2P_PUBLIC_ACTION_FRAME_T)prSwRfb->pvHeader; + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + DBGLOG(P2P, TRACE, ("RX Public Action Frame Token:%d.\n", prPublicActionFrame->ucDialogToken)); + + if (prPublicActionFrame->ucCategory != CATEGORY_PUBLIC_ACTION) { + return rWlanStatus; + } + + switch (prPublicActionFrame->ucAction) { + case ACTION_PUBLIC_WIFI_DIRECT: + break; + case ACTION_GAS_INITIAL_REQUEST: + case ACTION_GAS_INITIAL_RESPONSE: + case ACTION_GAS_COMEBACK_REQUEST: + case ACTION_GAS_COMEBACK_RESPONSE: + break; + default: + break; + } + + return rWlanStatus; +} /* p2pRxPublicActionFrame */ + + + +WLAN_STATUS +p2pRxActionFrame ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + P_P2P_ACTION_FRAME_T prP2pActionFrame = (P_P2P_ACTION_FRAME_T)NULL; + UINT_8 aucOui[3] = VENDOR_OUI_WFA_SPECIFIC; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); + + prP2pActionFrame = (P_P2P_ACTION_FRAME_T)prSwRfb->pvHeader; + + if (prP2pActionFrame->ucCategory != CATEGORY_VENDOR_SPECIFIC_ACTION) { + DBGLOG(P2P, TRACE, ("RX Action Frame but not vendor specific.\n")); + break; + } + + + if ((prP2pActionFrame->ucOuiType != VENDOR_OUI_TYPE_P2P) || + (prP2pActionFrame->aucOui[0] != aucOui[0]) || + (prP2pActionFrame->aucOui[1] != aucOui[1]) || + (prP2pActionFrame->aucOui[2] != aucOui[2])) { + DBGLOG(P2P, TRACE, ("RX Vendor Specific Action Frame but not P2P Type or not WFA OUI.\n")); + break; + } + + } while (FALSE); + + return rWlanStatus; +} /* p2pRxActionFrame */ + + +VOID +p2pProcessEvent_UpdateNOAParam ( + IN P_ADAPTER_T prAdapter, + UINT_8 ucNetTypeIndex, + P_EVENT_UPDATE_NOA_PARAMS_T prEventUpdateNoaParam + ) +{ + P_BSS_INFO_T prBssInfo = (P_BSS_INFO_T)NULL; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo; + UINT_32 i; + BOOLEAN fgNoaAttrExisted = FALSE; + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[ucNetTypeIndex]); + prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; + + prP2pSpecificBssInfo->fgEnableOppPS = prEventUpdateNoaParam->fgEnableOppPS; + prP2pSpecificBssInfo->u2CTWindow = prEventUpdateNoaParam->u2CTWindow; + prP2pSpecificBssInfo->ucNoAIndex = prEventUpdateNoaParam->ucNoAIndex; + prP2pSpecificBssInfo->ucNoATimingCount = prEventUpdateNoaParam->ucNoATimingCount; + + fgNoaAttrExisted |= prP2pSpecificBssInfo->fgEnableOppPS; + + + ASSERT(prP2pSpecificBssInfo->ucNoATimingCount <= P2P_MAXIMUM_NOA_COUNT); + + for (i = 0; i < prP2pSpecificBssInfo->ucNoATimingCount; i++) { + // in used + prP2pSpecificBssInfo->arNoATiming[i].fgIsInUse = + prEventUpdateNoaParam->arEventNoaTiming[i].fgIsInUse; + // count + prP2pSpecificBssInfo->arNoATiming[i].ucCount = + prEventUpdateNoaParam->arEventNoaTiming[i].ucCount; + // duration + prP2pSpecificBssInfo->arNoATiming[i].u4Duration = + prEventUpdateNoaParam->arEventNoaTiming[i].u4Duration; + // interval + prP2pSpecificBssInfo->arNoATiming[i].u4Interval = + prEventUpdateNoaParam->arEventNoaTiming[i].u4Interval; + // start time + prP2pSpecificBssInfo->arNoATiming[i].u4StartTime = + prEventUpdateNoaParam->arEventNoaTiming[i].u4StartTime; + + fgNoaAttrExisted |= prP2pSpecificBssInfo->arNoATiming[i].fgIsInUse; + } + + prP2pSpecificBssInfo->fgIsNoaAttrExisted = fgNoaAttrExisted; + + // update beacon content by the change + bssUpdateBeaconContent(prAdapter, ucNetTypeIndex); +} + +#endif /* CFG_ENABLE_WIFI_DIRECT */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_func.c b/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_func.c new file mode 100755 index 000000000000..67defd59bda0 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_func.c @@ -0,0 +1,2940 @@ +#include "p2p_precomp.h" + +APPEND_VAR_ATTRI_ENTRY_T txAssocRspAttributesTable[] = { + { (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_STATUS) , NULL, p2pFuncAppendAttriStatusForAssocRsp } /* 0 */ // Status + ,{ (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_EXT_LISTEN_TIMING), NULL, p2pFuncAppendAttriExtListenTiming } /* 8 */ +}; + + +APPEND_VAR_IE_ENTRY_T txProbeRspIETable[] = { + { (ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)), NULL, bssGenerateExtSuppRate_IE } /* 50 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_ERP), NULL, rlmRspGenerateErpIE } /* 42 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, rlmRspGenerateHtCapIE } /* 45 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP), NULL, rlmRspGenerateHtOpIE } /* 61 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_RSN), NULL, rsnGenerateRSNIE } /* 48 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN), NULL, rlmRspGenerateObssScanIE } /* 74 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, rlmRspGenerateExtCapIE } /* 127 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWpaNoneIE } /* 221 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_PARAM), NULL, mqmGenerateWmmParamIE } /* 221 */ +}; + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Function for requesting scan. There is an option to do ACTIVE or PASSIVE scan. +* +* @param eScanType - Specify the scan type of the scan request. It can be an ACTIVE/PASSIVE +* Scan. +* eChannelSet - Specify the prefered channel set. +* A FULL scan would request a legacy full channel normal scan.(usually ACTIVE). +* A P2P_SOCIAL scan would scan 1+6+11 channels.(usually ACTIVE) +* A SPECIFIC scan would only 1/6/11 channels scan. (Passive Listen/Specific Search) +* ucChannelNum - A specific channel number. (Only when channel is specified) +* eBand - A specific band. (Only when channel is specified) +* +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFuncRequestScan ( + IN P_ADAPTER_T prAdapter, + IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo + ) +{ + + P_MSG_SCN_SCAN_REQ prScanReq = (P_MSG_SCN_SCAN_REQ)NULL; + + DEBUGFUNC("p2pFuncRequestScan()"); + DBGLOG(P2P, TRACE, ("p2pFuncRequestScan() \n")); + + do { + ASSERT_BREAK((prAdapter != NULL) && + (prScanReqInfo != NULL)); + + if (prScanReqInfo->eChannelSet == SCAN_CHANNEL_SPECIFIED) { + ASSERT_BREAK(prScanReqInfo->ucNumChannelList > 0); + DBGLOG(P2P, LOUD, ("P2P Scan Request Channel:%d\n", prScanReqInfo->arScanChannelList[0].ucChannelNum)); + } + + prScanReq = (P_MSG_SCN_SCAN_REQ)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_REQ)); + if (!prScanReq) { + ASSERT(0); // Can't trigger SCAN FSM + break; + } + + prScanReq->rMsgHdr.eMsgId = MID_P2P_SCN_SCAN_REQ; + prScanReq->ucSeqNum = ++prScanReqInfo->ucSeqNumOfScnMsg; + prScanReq->ucNetTypeIndex = (UINT_8)NETWORK_TYPE_P2P_INDEX; + prScanReq->eScanType = prScanReqInfo->eScanType; + prScanReq->eScanChannel = prScanReqInfo->eChannelSet; + prScanReq->u2IELen = 0; + + /* Copy IE for Probe Request. */ + kalMemCopy(prScanReq->aucIE, prScanReqInfo->aucIEBuf, prScanReqInfo->u4BufLength); + prScanReq->u2IELen = (UINT_16)prScanReqInfo->u4BufLength; + + prScanReq->u2ChannelDwellTime = prScanReqInfo->u2PassiveDewellTime; + + switch (prScanReqInfo->eChannelSet) { + case SCAN_CHANNEL_SPECIFIED: + { + UINT_32 u4Idx = 0; + P_RF_CHANNEL_INFO_T prDomainInfo = (P_RF_CHANNEL_INFO_T)prScanReqInfo->arScanChannelList; + + if (prScanReqInfo->ucNumChannelList > MAXIMUM_OPERATION_CHANNEL_LIST) { + prScanReqInfo->ucNumChannelList = MAXIMUM_OPERATION_CHANNEL_LIST; + } + + + for (u4Idx = 0; u4Idx < prScanReqInfo->ucNumChannelList; u4Idx++) { + prScanReq->arChnlInfoList[u4Idx].ucChannelNum = prDomainInfo->ucChannelNum; + prScanReq->arChnlInfoList[u4Idx].eBand = prDomainInfo->eBand; + prDomainInfo++; + } + + prScanReq->ucChannelListNum = prScanReqInfo->ucNumChannelList; + } + case SCAN_CHANNEL_FULL: + case SCAN_CHANNEL_2G4: + case SCAN_CHANNEL_P2P_SOCIAL: + { + UINT_8 aucP2pSsid[] = P2P_WILDCARD_SSID; + + COPY_SSID(prScanReq->aucSSID, + prScanReq->ucSSIDLength, + prScanReqInfo->rSsidStruct.aucSsid, + prScanReqInfo->rSsidStruct.ucSsidLen); + + /* For compatible. */ + if (EQUAL_SSID(aucP2pSsid, P2P_WILDCARD_SSID_LEN, prScanReq->aucSSID, prScanReq->ucSSIDLength)) { + prScanReq->ucSSIDType = SCAN_REQ_SSID_P2P_WILDCARD; + } + else if (prScanReq->ucSSIDLength != 0) { + prScanReq->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; + } + DBGLOG(P2P, TRACE, ("p2pFuncRequestScan():set prScanReq \n")); + } + break; + default: + /* Currently there is no other scan channel set. */ + ASSERT(FALSE); + break; + } + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T)prScanReq, + MSG_SEND_METHOD_BUF); + + } while (FALSE); + + return; +} /* p2pFuncRequestScan */ + +VOID +p2pFuncCancelScan ( + IN P_ADAPTER_T prAdapter, + IN P_P2P_SCAN_REQ_INFO_T prScanInfo + ) +{ + P_MSG_SCN_SCAN_CANCEL prScanCancelMsg = (P_MSG_SCN_SCAN_CANCEL)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prScanInfo != NULL)); + + if (!prScanInfo->fgIsScanRequest) { + break; + } + + + if (prScanInfo->ucSeqNumOfScnMsg) { + /* There is a channel privilege on hand. */ + DBGLOG(P2P, TRACE, ("P2P Cancel Scan\n")); + + prScanCancelMsg = (P_MSG_SCN_SCAN_CANCEL)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_CANCEL)); + if (!prScanCancelMsg) { + /* Buffer not enough, can not cancel scan request. */ + DBGLOG(P2P, TRACE, ("Buffer not enough, can not cancel scan.\n")); + ASSERT(FALSE); + break; + } + + prScanCancelMsg->rMsgHdr.eMsgId = MID_P2P_SCN_SCAN_CANCEL; + prScanCancelMsg->ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; + prScanCancelMsg->ucSeqNum = prScanInfo->ucSeqNumOfScnMsg++; + prScanCancelMsg->fgIsChannelExt = FALSE; + prScanInfo->fgIsScanRequest = FALSE; + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T)prScanCancelMsg, + MSG_SEND_METHOD_BUF); + + + } + + + } while (FALSE); + + return; +} /* p2pFuncCancelScan */ + + +VOID +p2pFuncSwitchOPMode ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN ENUM_OP_MODE_T eOpMode, + IN BOOLEAN fgSyncToFW + ) +{ + do { + ASSERT_BREAK((prAdapter != NULL) && + (prP2pBssInfo != NULL) && + (eOpMode < OP_MODE_NUM)); + + if (prP2pBssInfo->eCurrentOPMode != eOpMode) { + DBGLOG(P2P, TRACE, ("p2pFuncSwitchOPMode: Switch to from %d, to %d.\n", prP2pBssInfo->eCurrentOPMode, eOpMode)); + + switch (prP2pBssInfo->eCurrentOPMode) { + case OP_MODE_ACCESS_POINT: + p2pFuncDissolve(prAdapter, prP2pBssInfo, TRUE, REASON_CODE_DEAUTH_LEAVING_BSS); + + p2pFsmRunEventBeaconAbort(prAdapter, NULL); + break; + default: + break; + } + + + prP2pBssInfo->eIntendOPMode = eOpMode; + prP2pBssInfo->eCurrentOPMode = eOpMode; + switch (eOpMode) { + case OP_MODE_INFRASTRUCTURE: + DBGLOG(P2P, TRACE, ("p2pFuncSwitchOPMode: Switch to Client.\n")); + case OP_MODE_ACCESS_POINT: + if (!IS_BSS_ACTIVE(prP2pBssInfo)) { + SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); + } + + /* Change interface address. */ + if (eOpMode == OP_MODE_ACCESS_POINT) { + DBGLOG(P2P, TRACE, ("p2pFuncSwitchOPMode: Switch to AP.\n")); + } + + COPY_MAC_ADDR(prP2pBssInfo->aucOwnMacAddr, prAdapter->rWifiVar.aucInterfaceAddress); + COPY_MAC_ADDR(prP2pBssInfo->aucBSSID, prAdapter->rWifiVar.aucInterfaceAddress); + + + break; + case OP_MODE_P2P_DEVICE: + { + /* Change device address. */ + DBGLOG(P2P, TRACE, ("p2pFuncSwitchOPMode: Switch back to P2P Device.\n")); + + if (!IS_BSS_ACTIVE(prP2pBssInfo)) { + SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); + } + + p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); + + COPY_MAC_ADDR(prP2pBssInfo->aucOwnMacAddr, prAdapter->rWifiVar.aucDeviceAddress); + COPY_MAC_ADDR(prP2pBssInfo->aucBSSID, prAdapter->rWifiVar.aucDeviceAddress); + + + } + break; + default: + if (IS_BSS_ACTIVE(prP2pBssInfo)) { + UNSET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); + } + ASSERT(FALSE); + break; + } + + if (1) { + P2P_DISCONNECT_INFO rP2PDisInfo; + + rP2PDisInfo.ucRole = 2; + wlanSendSetQueryCmd(prAdapter, + CMD_ID_P2P_ABORT, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(P2P_DISCONNECT_INFO), + (PUINT_8)&rP2PDisInfo, + NULL, + 0); + } + + + DBGLOG(P2P, TRACE, ("The device address is changed to " MACSTR " \n", MAC2STR(prP2pBssInfo->aucOwnMacAddr))); + DBGLOG(P2P, TRACE, ("The BSSID is changed to " MACSTR " \n", MAC2STR(prP2pBssInfo->aucBSSID))); + + /* Update BSS INFO to FW. */ + if ((fgSyncToFW) && (eOpMode != OP_MODE_ACCESS_POINT)) { + nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); + DBGLOG(P2P, TRACE, ("Update BSS INFO to FW in nicUpdateBss \n")); + } + } + + } while (FALSE); + + return; +} /* p2pFuncSwitchOPMode */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will start a P2P Group Owner and send Beacon Frames. +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFuncStartGO ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN PUINT_8 pucSsidBuf, + IN UINT_8 ucSsidLen, + IN UINT_8 ucChannelNum, + IN ENUM_BAND_T eBand, + IN ENUM_CHNL_EXT_T eSco, + IN BOOLEAN fgIsPureAP + ) +{ + do { + ASSERT_BREAK((prAdapter != NULL) && (prBssInfo != NULL)); + + ASSERT(prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT); + + DBGLOG(P2P, TRACE, ("p2pFuncStartGO:\n")); + + /* AP mode started. */ + p2pFuncSwitchOPMode(prAdapter, prBssInfo, prBssInfo->eIntendOPMode, FALSE); + + prBssInfo->eIntendOPMode = OP_MODE_NUM; + + //4 <1.1> Assign SSID + COPY_SSID(prBssInfo->aucSSID, + prBssInfo->ucSSIDLen, + pucSsidBuf, + ucSsidLen); + + DBGLOG(P2P, TRACE, ("GO SSID:%s \n", prBssInfo->aucSSID)); + + //4 <1.2> Clear current AP's STA_RECORD_T and current AID + prBssInfo->prStaRecOfAP = (P_STA_RECORD_T)NULL; + prBssInfo->u2AssocId = 0; + + + //4 <1.3> Setup Channel, Band and Phy Attributes + prBssInfo->ucPrimaryChannel = ucChannelNum; + prBssInfo->eBand = eBand; + prBssInfo->eBssSCO = eSco; + + DBGLOG(P2P, TRACE, ("GO Channel:%d \n", ucChannelNum)); + + + if (fgIsPureAP) { + if (prBssInfo->eBand == BAND_5G) { + prBssInfo->ucPhyTypeSet = (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11AN); /* Depend on eBand */ + prBssInfo->ucConfigAdHocAPMode = AP_MODE_11A; /* Depend on eCurrentOPMode and ucPhyTypeSet */ + } + else { + prBssInfo->ucPhyTypeSet = (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11BGN); /* Depend on eBand */ + prBssInfo->ucConfigAdHocAPMode = AP_MODE_MIXED_11BG; /* Depend on eCurrentOPMode and ucPhyTypeSet */ + } + } + else { + prBssInfo->ucPhyTypeSet = (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11GN); /* Depend on eBand */ + prBssInfo->ucConfigAdHocAPMode = AP_MODE_11G_P2P; /* Depend on eCurrentOPMode and ucPhyTypeSet */ + } + + + prBssInfo->ucNonHTBasicPhyType = (UINT_8) + rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode].ePhyTypeIndex; + prBssInfo->u2BSSBasicRateSet = + rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode].u2BSSBasicRateSet; + prBssInfo->u2OperationalRateSet = + rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType].u2SupportedRateSet; + + if (prBssInfo->ucAllSupportedRatesLen == 0) { + rateGetDataRatesFromRateSet(prBssInfo->u2OperationalRateSet, + prBssInfo->u2BSSBasicRateSet, + prBssInfo->aucAllSupportedRates, + &prBssInfo->ucAllSupportedRatesLen); + } + + //4 <1.5> Setup MIB for current BSS + prBssInfo->u2ATIMWindow = 0; + prBssInfo->ucBeaconTimeoutCount = 0; + + //3 <2> Update BSS_INFO_T common part +#if CFG_SUPPORT_AAA + if (!fgIsPureAP) { + prBssInfo->fgIsProtection = TRUE; /* Always enable protection at P2P GO */ + kalP2PSetCipher(prAdapter->prGlueInfo, IW_AUTH_CIPHER_CCMP); + } + else { + if (kalP2PGetCipher(prAdapter->prGlueInfo)) + prBssInfo->fgIsProtection = TRUE; + } + + // 20120106 frog: I want separate OP_Mode & Beacon TX Function. + //p2pFuncSwitchOPMode(prAdapter, prBssInfo, OP_MODE_ACCESS_POINT, FALSE); + + bssInitForAP(prAdapter, prBssInfo, FALSE); + + nicQmUpdateWmmParms(prAdapter, NETWORK_TYPE_P2P_INDEX); +#endif /* CFG_SUPPORT_AAA */ + + + //3 <3> Set MAC HW + //4 <3.1> Setup channel and bandwidth + rlmBssInitForAPandIbss(prAdapter, prBssInfo); + + //4 <3.2> Reset HW TSF Update Mode and Beacon Mode + nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); + + //4 <3.3> Setup BSSID + nicPmIndicateBssCreated(prAdapter, NETWORK_TYPE_P2P_INDEX); + + } while (FALSE); + + return; +} /* p2pFuncStartGO() */ + + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is to inform CNM that channel privilege +* has been released +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFuncReleaseCh ( + IN P_ADAPTER_T prAdapter, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo + ) +{ + P_MSG_CH_ABORT_T prMsgChRelease = (P_MSG_CH_ABORT_T)NULL; + + DEBUGFUNC("p2pFuncReleaseCh()"); + + do { + ASSERT_BREAK((prAdapter != NULL) && (prChnlReqInfo != NULL)); + + if (!prChnlReqInfo->fgIsChannelRequested) { + break; + } + else { + DBGLOG(P2P, TRACE, ("P2P Release Channel\n")); + prChnlReqInfo->fgIsChannelRequested = FALSE; + } + + /* 1. return channel privilege to CNM immediately */ + prMsgChRelease = (P_MSG_CH_ABORT_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_ABORT_T)); + if (!prMsgChRelease) { + ASSERT(0); // Can't release Channel to CNM + break; + } + + prMsgChRelease->rMsgHdr.eMsgId = MID_MNY_CNM_CH_ABORT; + prMsgChRelease->ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; + prMsgChRelease->ucTokenID = prChnlReqInfo->ucSeqNumOfChReq++; + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prMsgChRelease, + MSG_SEND_METHOD_BUF); + + } while (FALSE); + + return; +} /* p2pFuncReleaseCh */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process of CHANNEL_REQ_JOIN Initial. Enter CHANNEL_REQ_JOIN State. +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFuncAcquireCh ( + IN P_ADAPTER_T prAdapter, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo + ) +{ + P_MSG_CH_REQ_T prMsgChReq = (P_MSG_CH_REQ_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prChnlReqInfo != NULL)); + + p2pFuncReleaseCh(prAdapter, prChnlReqInfo); + + /* send message to CNM for acquiring channel */ + prMsgChReq = (P_MSG_CH_REQ_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_REQ_T)); + + if (!prMsgChReq) { + ASSERT(0); // Can't indicate CNM for channel acquiring + break; + } + + prMsgChReq->rMsgHdr.eMsgId = MID_MNY_CNM_CH_REQ; + prMsgChReq->ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; + prMsgChReq->ucTokenID = ++prChnlReqInfo->ucSeqNumOfChReq; + prMsgChReq->eReqType = CH_REQ_TYPE_JOIN; + prMsgChReq->u4MaxInterval = prChnlReqInfo->u4MaxInterval; + + prMsgChReq->ucPrimaryChannel = prChnlReqInfo->ucReqChnlNum; + prMsgChReq->eRfSco = prChnlReqInfo->eChnlSco; + prMsgChReq->eRfBand = prChnlReqInfo->eBand; + + kalMemZero(prMsgChReq->aucBSSID, MAC_ADDR_LEN); + + /* Channel request join BSSID. */ + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prMsgChReq, + MSG_SEND_METHOD_BUF); + + prChnlReqInfo->fgIsChannelRequested = TRUE; + + } while (FALSE); + + return; +} /* p2pFuncAcquireCh */ + +#if 0 +WLAN_STATUS +p2pFuncBeaconUpdate( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucBcnHdr, + IN UINT_32 u4HdrLen, + IN PUINT_8 pucBcnBody, + IN UINT_32 u4BodyLen, + IN UINT_32 u4DtimPeriod, + IN UINT_32 u4BcnInterval) +{ + WLAN_STATUS rResultStatus = WLAN_STATUS_INVALID_DATA; + P_WLAN_BEACON_FRAME_T prBcnFrame = (P_WLAN_BEACON_FRAME_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + P_MSDU_INFO_T prBcnMsduInfo = (P_MSDU_INFO_T)NULL; + PUINT_8 pucTIMBody = (PUINT_8)NULL; + UINT_16 u2FrameLength = 0, UINT_16 u2OldBodyLen = 0; + UINT_8 aucIEBuf[MAX_IE_LENGTH]; + + do { + ASSERT_BREAK(prAdapter != NULL); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prBcnMsduInfo = prP2pBssInfo->prBeacon + + ASSERT_BREAK(prBcnMsduInfo != NULL); + + /* TODO: Find TIM IE pointer. */ + prBcnFrame = prBcnMsduInfo->prPacket; + + ASSERT_BREAK(prBcnFrame != NULL); + + do { + /* Ori header. */ + UINT_16 u2IELength = 0, u2Offset = 0; + PUINT_8 pucIEBuf = prBcnFrame->aucInfoElem; + + u2IELength = prBcnMsduInfo->u2FrameLength - prBcnMsduInfo->ucMacHeaderLength; + + IE_FOR_EACH(pucIEBuf, u2IELength, u2Offset) { + if ((IE_ID(pucIEBuf) == ELEM_ID_TIM) || + ((IE_ID(pucIEBuf) > ELEM_ID_IBSS_PARAM_SET)) { + pucTIMBody = pucIEBuf; + break + } + u2FrameLength += IE_SIZE(pucIEBuf); + } + + if (pucTIMBody == NULL) { + pucTIMBody = pucIEBuf; + } + + /* Body not change. */ + u2OldBodyLen = (UINT_16)((UINT_32)pucTIMBody - (UINT_32)prBcnFrame->aucInfoElem); + + // Move body. + kalMemCmp(aucIEBuf, pucTIMBody, u2OldBodyLen); + } while (FALSE); + + + if (pucBcnHdr) { + kalMemCopy(prBcnMsduInfo->prPacket, pucBcnHdr, u4HdrLen); + + pucTIMBody = (PUINT_8)((UINT_32)prBcnMsduInfo->prPacket + u4HdrLen); + + prBcnMsduInfo->ucMacHeaderLength = (WLAN_MAC_MGMT_HEADER_LEN + + (TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN)); + + u2FrameLength = u4HdrLen; /* Header + Partial Body. */ + + } + else { + /* Header not change. */ + u2FrameLength += prBcnMsduInfo->ucMacHeaderLength; + } + + + if (pucBcnBody) { + kalMemCopy(pucTIMBody, pucBcnBody, u4BodyLen); + u2FrameLength += (UINT_16)u4BodyLen; + } + else { + kalMemCopy(pucTIMBody, aucIEBuf, u2OldBodyLen); + u2FrameLength += u2OldBodyLen; + } + + /* Frame Length */ + prBcnMsduInfo->u2FrameLength = u2FrameLength; + + prBcnMsduInfo->fgIs802_11 = TRUE; + prBcnMsduInfo->ucNetworkType = NETWORK_TYPE_P2P_INDEX; + + prP2pBssInfo->u2BeaconInterval = (UINT_16)u4BcnInterval; + prP2pBssInfo->ucDTIMPeriod = (UINT_8)u4DtimPeriod; + prP2pBssInfo->u2CapInfo = prBcnFrame->u2CapInfo; + prBcnMsduInfo->ucPacketType = 3; + + rResultStatus = nicUpdateBeaconIETemplate(prAdapter, + IE_UPD_METHOD_UPDATE_ALL, + NETWORK_TYPE_P2P_INDEX, + prP2pBssInfo->u2CapInfo, + (PUINT_8)prBcnFrame->aucInfoElem, + prBcnMsduInfo->u2FrameLength - OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem)); + + if (prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + /* AP is created, Beacon Update. */ + nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_P2P_INDEX); + + nicPmIndicateBssCreated(prAdapter, NETWORK_TYPE_P2P_INDEX); + } + + } while (FALSE); + + return rResultStatus; +} /* p2pFuncBeaconUpdate */ + +#else +WLAN_STATUS +p2pFuncBeaconUpdate ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN P_P2P_BEACON_UPDATE_INFO_T prBcnUpdateInfo, + IN PUINT_8 pucNewBcnHdr, + IN UINT_32 u4NewHdrLen, + IN PUINT_8 pucNewBcnBody, + IN UINT_32 u4NewBodyLen + ) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + P_WLAN_BEACON_FRAME_T prBcnFrame = (P_WLAN_BEACON_FRAME_T)NULL; + P_MSDU_INFO_T prBcnMsduInfo = (P_MSDU_INFO_T)NULL; + PUINT_8 pucIEBuf = (PUINT_8)NULL; + UINT_8 aucIEBuf[MAX_IE_LENGTH]; + DBGLOG(P2P, TRACE, ("p2pFuncBeaconUpdate \n")); + + do { + ASSERT_BREAK((prAdapter != NULL) && + (prP2pBssInfo != NULL) && + (prBcnUpdateInfo != NULL)); + DBGLOG(P2P, TRACE, ("p2pFuncBeaconUpdate: 0001 \n")); + prBcnMsduInfo = prP2pBssInfo->prBeacon; +#if DBG + DBGLOG(P2P, TRACE, ("p2pFuncBeaconUpdate: 0001.1 \n")); + if (prBcnUpdateInfo->pucBcnHdr != NULL) { + DBGLOG(P2P, TRACE, ("p2pFuncBeaconUpdate: 0001.2 \n")); + ASSERT((UINT_32)prBcnUpdateInfo->pucBcnHdr == ((UINT_32)prBcnMsduInfo->prPacket + MAC_TX_RESERVED_FIELD)); + DBGLOG(P2P, TRACE, ("p2pFuncBeaconUpdate: 0001.3 \n")); + } + DBGLOG(P2P, TRACE, ("p2pFuncBeaconUpdate: 0002 \n")); + if (prBcnUpdateInfo->pucBcnBody != NULL) { + ASSERT((UINT_32)prBcnUpdateInfo->pucBcnBody == ((UINT_32)prBcnUpdateInfo->pucBcnHdr + (UINT_32)prBcnUpdateInfo->u4BcnHdrLen)); + } +#endif + DBGLOG(P2P, TRACE, ("p2pFuncBeaconUpdate: 0003 \n")); + + + prBcnFrame = (P_WLAN_BEACON_FRAME_T)((UINT_32)prBcnMsduInfo->prPacket + MAC_TX_RESERVED_FIELD); + DBGLOG(P2P, TRACE, ("p2pFuncBeaconUpdate: 0004 \n")); + if (!pucNewBcnBody) { + /* Old body. */ + pucNewBcnBody = prBcnUpdateInfo->pucBcnBody; + ASSERT(u4NewBodyLen == 0); + u4NewBodyLen = prBcnUpdateInfo->u4BcnBodyLen; + DBGLOG(P2P, TRACE, ("p2pFuncBeaconUpdate: 0005-1 \n")); + } + else { + prBcnUpdateInfo->u4BcnBodyLen = u4NewBodyLen; + DBGLOG(P2P, TRACE, ("p2pFuncBeaconUpdate: 0005-2 \n")); + } + + /* Temp buffer body part. */ + kalMemCopy(aucIEBuf, pucNewBcnBody, u4NewBodyLen); + DBGLOG(P2P, TRACE, ("p2pFuncBeaconUpdate: 0006 \n")); + if (pucNewBcnHdr) { + kalMemCopy(prBcnFrame, pucNewBcnHdr, u4NewHdrLen); + prBcnUpdateInfo->pucBcnHdr = (PUINT_8)prBcnFrame; + prBcnUpdateInfo->u4BcnHdrLen = u4NewHdrLen; + DBGLOG(P2P, TRACE, ("p2pFuncBeaconUpdate: 0007 \n")); + } + + pucIEBuf = (PUINT_8)((UINT_32)prBcnUpdateInfo->pucBcnHdr + (UINT_32)prBcnUpdateInfo->u4BcnHdrLen); + kalMemCopy(pucIEBuf, aucIEBuf, u4NewBodyLen); + prBcnUpdateInfo->pucBcnBody = pucIEBuf; + DBGLOG(P2P, TRACE, ("p2pFuncBeaconUpdate: 0008 \n")); + /* Frame Length */ + prBcnMsduInfo->u2FrameLength = (UINT_16)(prBcnUpdateInfo->u4BcnHdrLen + prBcnUpdateInfo->u4BcnBodyLen); + + prBcnMsduInfo->ucPacketType = 3; + prBcnMsduInfo->fgIs802_11 = TRUE; + prBcnMsduInfo->ucNetworkType = NETWORK_TYPE_P2P_INDEX; + + DBGLOG(P2P, TRACE, ("p2pFuncBeaconUpdate: 0009 \n")); + /* Update BSS INFO related information. */ + COPY_MAC_ADDR(prP2pBssInfo->aucOwnMacAddr, prBcnFrame->aucSrcAddr); + COPY_MAC_ADDR(prP2pBssInfo->aucBSSID, prBcnFrame->aucBSSID); + prP2pBssInfo->u2CapInfo = prBcnFrame->u2CapInfo; + DBGLOG(P2P, TRACE, ("p2pFuncBeaconUpdate: 0010 \n")); + p2pFuncParseBeaconContent(prAdapter, + prP2pBssInfo, + (PUINT_8)prBcnFrame->aucInfoElem, + (prBcnMsduInfo->u2FrameLength - OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem))); + DBGLOG(P2P, TRACE, ("p2pFuncBeaconUpdate: 0011 \n")); +#if 1 + DBGLOG(P2P, TRACE, ("p2pFuncBeaconUpdate: 0012 \n")); + bssUpdateBeaconContent(prAdapter, NETWORK_TYPE_P2P_INDEX); +#else + nicUpdateBeaconIETemplate(prAdapter, + IE_UPD_METHOD_UPDATE_ALL, + NETWORK_TYPE_P2P_INDEX, + prBcnFrame->u2CapInfo, + (PUINT_8)prBcnFrame->aucInfoElem, + (prBcnMsduInfo->u2FrameLength - OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem))); +#endif + DBGLOG(P2P, TRACE, ("p2pFuncBeaconUpdate: 0013 \n")); + } while (FALSE); + + return rWlanStatus; +} /* p2pFuncBeaconUpdate */ + +#endif + +// TODO: We do not apply IE in deauth frame set from upper layer now. +WLAN_STATUS +p2pFuncDeauth ( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucPeerMacAddr, + IN UINT_16 u2ReasonCode, + IN PUINT_8 pucIEBuf, + IN UINT_16 u2IELen, + IN BOOLEAN fgSendDeauth + ) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_FAILURE; + P_STA_RECORD_T prCliStaRec = (P_STA_RECORD_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + BOOLEAN fgIsStaFound = FALSE; + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucPeerMacAddr != NULL)); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + prCliStaRec = cnmGetStaRecByAddress(prAdapter, + NETWORK_TYPE_P2P_INDEX, + pucPeerMacAddr); + + switch (prP2pBssInfo->eCurrentOPMode) { + case OP_MODE_ACCESS_POINT: + { + P_LINK_T prStaRecOfClientList = (P_LINK_T)NULL; + P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T)NULL; + + prStaRecOfClientList = &(prP2pBssInfo->rStaRecOfClientList); + + LINK_FOR_EACH(prLinkEntry, prStaRecOfClientList) { + if ((UINT_32)prCliStaRec == (UINT_32)prLinkEntry) { + LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, &prCliStaRec->rLinkEntry); + fgIsStaFound = TRUE; + break; + } + } + + } + break; + case OP_MODE_INFRASTRUCTURE: + ASSERT(prCliStaRec == prP2pBssInfo->prStaRecOfAP); + if (prCliStaRec != prP2pBssInfo->prStaRecOfAP) { + break; + } + fgIsStaFound = TRUE; + break; + default: + break; + } + + if (fgIsStaFound) { + p2pFuncDisconnect(prAdapter, prCliStaRec, fgSendDeauth, u2ReasonCode); + } + + rWlanStatus = WLAN_STATUS_SUCCESS; + } while (FALSE); + + return rWlanStatus; +} /* p2pFuncDeauth */ + +// TODO: We do not apply IE in disassoc frame set from upper layer now. +WLAN_STATUS +p2pFuncDisassoc ( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucPeerMacAddr, + IN UINT_16 u2ReasonCode, + IN PUINT_8 pucIEBuf, + IN UINT_16 u2IELen, + IN BOOLEAN fgSendDisassoc + ) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_FAILURE; + P_STA_RECORD_T prCliStaRec = (P_STA_RECORD_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + BOOLEAN fgIsStaFound = FALSE; + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucPeerMacAddr != NULL)); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + prCliStaRec = cnmGetStaRecByAddress(prAdapter, + NETWORK_TYPE_P2P_INDEX, + pucPeerMacAddr); + + switch (prP2pBssInfo->eCurrentOPMode) { + case OP_MODE_ACCESS_POINT: + { + P_LINK_T prStaRecOfClientList = (P_LINK_T)NULL; + P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T)NULL; + + prStaRecOfClientList = &(prP2pBssInfo->rStaRecOfClientList); + + LINK_FOR_EACH(prLinkEntry, prStaRecOfClientList) { + if ((UINT_32)prCliStaRec == (UINT_32)prLinkEntry) { + LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, &prCliStaRec->rLinkEntry); + fgIsStaFound = TRUE; + break; + } + } + + } + break; + case OP_MODE_INFRASTRUCTURE: + ASSERT(prCliStaRec == prP2pBssInfo->prStaRecOfAP); + if (prCliStaRec != prP2pBssInfo->prStaRecOfAP) { + break; + } + fgIsStaFound = TRUE; + break; + default: + break; + } + + if (fgIsStaFound) { + if (fgSendDisassoc) { + assocSendDisAssocFrame(prAdapter, prCliStaRec, u2ReasonCode); + } + + p2pFuncDisconnect(prAdapter, prCliStaRec, FALSE, u2ReasonCode); + + } + + rWlanStatus = WLAN_STATUS_SUCCESS; + } while (FALSE); + + return rWlanStatus; +} /* p2pFuncDisassoc */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to dissolve from group or one group. (Would not change P2P FSM.) +* 1. GC: Disconnect from AP. (Send Deauth) +* 2. GO: Disconnect all STA +* +* @param[in] prAdapter Pointer to the adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFuncDissolve ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN BOOLEAN fgSendDeauth, + IN UINT_16 u2ReasonCode + ) +{ + DEBUGFUNC("p2pFuncDissolve()"); + + do { + + ASSERT_BREAK((prAdapter != NULL) && (prP2pBssInfo != NULL)); + + switch (prP2pBssInfo->eCurrentOPMode) { + case OP_MODE_INFRASTRUCTURE: + /* Reset station record status. */ + if (prP2pBssInfo->prStaRecOfAP) { + // 2012/02/14 frog: After formation before join group, prStaRecOfAP is NULL. + p2pFuncDisconnect(prAdapter, + prP2pBssInfo->prStaRecOfAP, + fgSendDeauth, + u2ReasonCode); + } + + prP2pBssInfo->prStaRecOfAP = NULL; + + break; + case OP_MODE_ACCESS_POINT: + /* Under AP mode, we would net send deauthentication frame to each STA. + * We only stop the Beacon & let all stations timeout. + */ + { + P_LINK_T prStaRecOfClientList = (P_LINK_T)NULL; + + /* Send deauth. */ + authSendDeauthFrame(prAdapter, + NULL, + (P_SW_RFB_T)NULL, + u2ReasonCode, + (PFN_TX_DONE_HANDLER)NULL); + + prStaRecOfClientList = &prP2pBssInfo->rStaRecOfClientList; + + while (!LINK_IS_EMPTY(prStaRecOfClientList)) { + P_STA_RECORD_T prCurrStaRec; + + LINK_REMOVE_HEAD(prStaRecOfClientList, prCurrStaRec, P_STA_RECORD_T); + + p2pFuncDisconnect(prAdapter, prCurrStaRec, TRUE, u2ReasonCode); + + } + + } + + break; + default: + return; // 20110420 -- alreay in Device Mode. + } + + /* Make the deauth frame send to FW ASAP. */ + wlanAcquirePowerControl(prAdapter); + wlanProcessCommandQueue(prAdapter, &prAdapter->prGlueInfo->rCmdQueue); + wlanReleasePowerControl(prAdapter); + + kalMdelay(100); + + /* Change Connection Status. */ + p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); + + } while (FALSE); + + return; +} /* p2pFuncDissolve */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to dissolve from group or one group. (Would not change P2P FSM.) +* 1. GC: Disconnect from AP. (Send Deauth) +* 2. GO: Disconnect all STA +* +* @param[in] prAdapter Pointer to the adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFuncDisconnect ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN BOOLEAN fgSendDeauth, + IN UINT_16 u2ReasonCode + ) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + ENUM_PARAM_MEDIA_STATE_T eOriMediaStatus; + + DBGLOG(P2P, TRACE, ("p2pFuncDisconnect()")); + + do { + ASSERT_BREAK((prAdapter != NULL) && (prStaRec != NULL)); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + eOriMediaStatus = prP2pBssInfo->eConnectionState; + + /* Indicate disconnect. */ + // TODO: +// kalP2PGOStationUpdate +// kalP2PGCIndicateConnectionStatus + //p2pIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED, prStaRec->aucMacAddr); + + if (fgSendDeauth) { + /* Send deauth. */ + authSendDeauthFrame(prAdapter, + prStaRec, + (P_SW_RFB_T)NULL, + u2ReasonCode, + (PFN_TX_DONE_HANDLER)p2pFsmRunEventDeauthTxDone); + } + else { + /* Change station state. */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + + /* Reset Station Record Status. */ + p2pFuncResetStaRecStatus(prAdapter, prStaRec); + + if ((prP2pBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) || + (prP2pBssInfo->rStaRecOfClientList.u4NumElem == 0)) { + DBGLOG(P2P, TRACE, ("No More Client, Media Status DISCONNECTED\n")); + p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); + } + + if (eOriMediaStatus != prP2pBssInfo->eConnectionState) { + /* Update Disconnected state to FW. */ + nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); + } + + } + + if (prP2pBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) { + /* GO: It would stop Beacon TX. GC: Stop all BSS related PS function. */ + nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_P2P_INDEX); + + /* Reset RLM related field of BSSINFO. */ + rlmBssAborted(prAdapter, prP2pBssInfo); + } + + } while (FALSE); + + return; + +} /* p2pFuncDisconnect */ + + + + + + +WLAN_STATUS +p2pFuncTxMgmtFrame ( + IN P_ADAPTER_T prAdapter, + IN P_P2P_MGMT_TX_REQ_INFO_T prMgmtTxReqInfo, + IN P_MSDU_INFO_T prMgmtTxMsdu, + IN UINT_64 u8Cookie + ) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + P_MSDU_INFO_T prTxMsduInfo = (P_MSDU_INFO_T)NULL; + P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T)NULL; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMgmtTxReqInfo != NULL)); + + if (prMgmtTxReqInfo->fgIsMgmtTxRequested) { + + // 1. prMgmtTxReqInfo->prMgmtTxMsdu != NULL + /* Packet on driver, not done yet, drop it. */ + if ((prTxMsduInfo = prMgmtTxReqInfo->prMgmtTxMsdu) != NULL) { + + kalP2PIndicateMgmtTxStatus(prAdapter->prGlueInfo, + prMgmtTxReqInfo->u8Cookie, + FALSE, + prTxMsduInfo->prPacket, + (UINT_32)prTxMsduInfo->u2FrameLength); + + // Leave it to TX Done handler. + //cnmMgtPktFree(prAdapter, prTxMsduInfo); + prMgmtTxReqInfo->prMgmtTxMsdu = NULL; + } + + // 2. prMgmtTxReqInfo->prMgmtTxMsdu == NULL + /* Packet transmitted, wait tx done. (cookie issue) */ + // 20120105 frog - use another u8cookie to store this value. + + } + + ASSERT(prMgmtTxReqInfo->prMgmtTxMsdu == NULL); + + + + prWlanHdr = (P_WLAN_MAC_HEADER_T)((UINT_32)prMgmtTxMsdu->prPacket + MAC_TX_RESERVED_FIELD); + prStaRec = cnmGetStaRecByAddress(prAdapter, NETWORK_TYPE_P2P_INDEX, prWlanHdr->aucAddr1); + prMgmtTxMsdu->ucNetworkType = (UINT_8)NETWORK_TYPE_P2P_INDEX; + + switch (prWlanHdr->u2FrameCtrl & MASK_FRAME_TYPE) { + case MAC_FRAME_PROBE_RSP: + prMgmtTxMsdu = p2pFuncProcessP2pProbeRsp(prAdapter, prMgmtTxMsdu); + break; + default: + break; + } + + + prMgmtTxReqInfo->u8Cookie = u8Cookie; + prMgmtTxReqInfo->prMgmtTxMsdu = prMgmtTxMsdu; + prMgmtTxReqInfo->fgIsMgmtTxRequested = TRUE; + + prMgmtTxMsdu->eSrc = TX_PACKET_MGMT; + prMgmtTxMsdu->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; + prMgmtTxMsdu->ucStaRecIndex = (prStaRec != NULL)?(prStaRec->ucIndex):(0xFF); + prMgmtTxMsdu->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; // TODO: undcertain. + prMgmtTxMsdu->fgIs802_1x = FALSE; + prMgmtTxMsdu->fgIs802_11 = TRUE; + prMgmtTxMsdu->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMgmtTxMsdu->pfTxDoneHandler = p2pFsmRunEventMgmtFrameTxDone; + prMgmtTxMsdu->fgIsBasicRate = TRUE; + + nicTxEnqueueMsdu(prAdapter, prMgmtTxMsdu); + + } while (FALSE); + + return rWlanStatus; +} /* p2pFuncTxMgmtFrame */ + + + +VOID +p2pFuncSetChannel ( + IN P_ADAPTER_T prAdapter, + IN P_RF_CHANNEL_INFO_T prRfChannelInfo + ) +{ + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prRfChannelInfo != NULL)); + + prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + + prP2pConnSettings->ucOperatingChnl = prRfChannelInfo->ucChannelNum; + prP2pConnSettings->eBand = prRfChannelInfo->eBand; + + + } while (FALSE); + + return; +} +/* p2pFuncSetChannel */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Retry JOIN for AUTH_MODE_AUTO_SWITCH +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @retval TRUE We will retry JOIN +* @retval FALSE We will not retry JOIN +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +p2pFuncRetryJOIN ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_P2P_JOIN_INFO_T prJoinInfo + ) +{ + P_MSG_JOIN_REQ_T prJoinReqMsg = (P_MSG_JOIN_REQ_T)NULL; + BOOLEAN fgRetValue = FALSE; + + do { + ASSERT_BREAK((prAdapter != NULL) && + (prStaRec != NULL) && + (prJoinInfo != NULL)); + + /* Retry other AuthType if possible */ + if (!prJoinInfo->ucAvailableAuthTypes) { + break; + } + + if (prJoinInfo->ucAvailableAuthTypes & + (UINT_8)AUTH_TYPE_SHARED_KEY) { + + DBGLOG(P2P, INFO, ("RETRY JOIN INIT: Retry Authentication with AuthType == SHARED_KEY.\n")); + + prJoinInfo->ucAvailableAuthTypes &= + ~(UINT_8)AUTH_TYPE_SHARED_KEY; + + prStaRec->ucAuthAlgNum = (UINT_8)AUTH_ALGORITHM_NUM_SHARED_KEY; + } + else { + DBGLOG(P2P, ERROR, ("RETRY JOIN INIT: Retry Authentication with Unexpected AuthType.\n")); + ASSERT(0); + break; + } + + prJoinInfo->ucAvailableAuthTypes = 0; /* No more available Auth Types */ + + /* Trigger SAA to start JOIN process. */ + prJoinReqMsg = (P_MSG_JOIN_REQ_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_REQ_T)); + if (!prJoinReqMsg) { + ASSERT(0); // Can't trigger SAA FSM + break; + } + + prJoinReqMsg->rMsgHdr.eMsgId = MID_P2P_SAA_FSM_START; + prJoinReqMsg->ucSeqNum = ++prJoinInfo->ucSeqNumOfReqMsg; + prJoinReqMsg->prStaRec = prStaRec; + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prJoinReqMsg, + MSG_SEND_METHOD_BUF); + + + fgRetValue = TRUE; + } while (FALSE); + + return fgRetValue; + + + +}/* end of p2pFuncRetryJOIN() */ + + + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will update the contain of BSS_INFO_T for AIS network once +* the association was completed. +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] prAssocRspSwRfb Pointer to SW RFB of ASSOC RESP FRAME. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFuncUpdateBssInfoForJOIN ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prAssocRspSwRfb + ) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T)NULL; + P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T)NULL; + UINT_16 u2IELength; + PUINT_8 pucIE; + + DEBUGFUNC("p2pUpdateBssInfoForJOIN()"); + + ASSERT(prAdapter); + ASSERT(prStaRec); + ASSERT(prAssocRspSwRfb); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) prAssocRspSwRfb->pvHeader; + + DBGLOG(P2P, INFO, ("Update P2P_BSS_INFO_T and apply settings to MAC\n")); + + //3 <1> Update BSS_INFO_T from AIS_FSM_INFO_T or User Settings + //4 <1.1> Setup Operation Mode + prP2pBssInfo->eCurrentOPMode = OP_MODE_INFRASTRUCTURE; + + //4 <1.2> Setup SSID + COPY_SSID(prP2pBssInfo->aucSSID, + prP2pBssInfo->ucSSIDLen, + prP2pConnSettings->aucSSID, + prP2pConnSettings->ucSSIDLen); + + if (prBssDesc == NULL) { + /* Target BSS NULL. */ + DBGLOG(P2P, TRACE,("Target BSS NULL\n")); + return; + } + + + if (UNEQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAssocRspFrame->aucBSSID)) { + ASSERT(FALSE); + } + + //4 <1.3> Setup Channel, Band + prP2pBssInfo->ucPrimaryChannel = prBssDesc->ucChannelNum; + prP2pBssInfo->eBand = prBssDesc->eBand; + + + //3 <2> Update BSS_INFO_T from STA_RECORD_T + //4 <2.1> Save current AP's STA_RECORD_T and current AID + prP2pBssInfo->prStaRecOfAP = prStaRec; + prP2pBssInfo->u2AssocId = prStaRec->u2AssocId; + + //4 <2.2> Setup Capability + prP2pBssInfo->u2CapInfo = prStaRec->u2CapInfo; /* Use AP's Cap Info as BSS Cap Info */ + + if (prP2pBssInfo->u2CapInfo & CAP_INFO_SHORT_PREAMBLE) { + prP2pBssInfo->fgIsShortPreambleAllowed = TRUE; + } + else { + prP2pBssInfo->fgIsShortPreambleAllowed = FALSE; + } + + //4 <2.3> Setup PHY Attributes and Basic Rate Set/Operational Rate Set + prP2pBssInfo->ucPhyTypeSet = prStaRec->ucDesiredPhyTypeSet; + + prP2pBssInfo->ucNonHTBasicPhyType = prStaRec->ucNonHTBasicPhyType; + + prP2pBssInfo->u2OperationalRateSet = prStaRec->u2OperationalRateSet; + prP2pBssInfo->u2BSSBasicRateSet = prStaRec->u2BSSBasicRateSet; + + + //3 <3> Update BSS_INFO_T from SW_RFB_T (Association Resp Frame) + //4 <3.1> Setup BSSID + COPY_MAC_ADDR(prP2pBssInfo->aucBSSID, prAssocRspFrame->aucBSSID); + + + u2IELength = (UINT_16) ((prAssocRspSwRfb->u2PacketLen - prAssocRspSwRfb->u2HeaderLen) - + (OFFSET_OF(WLAN_ASSOC_RSP_FRAME_T, aucInfoElem[0]) - WLAN_MAC_MGMT_HEADER_LEN)); + pucIE = prAssocRspFrame->aucInfoElem; + + + //4 <3.2> Parse WMM and setup QBSS flag + /* Parse WMM related IEs and configure HW CRs accordingly */ + mqmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); + + prP2pBssInfo->fgIsQBSS = prStaRec->fgIsQoS; + + //3 <4> Update BSS_INFO_T from BSS_DESC_T + ASSERT(prBssDesc); + + prBssDesc->fgIsConnecting = FALSE; + prBssDesc->fgIsConnected = TRUE; + + //4 <4.1> Setup MIB for current BSS + prP2pBssInfo->u2BeaconInterval = prBssDesc->u2BeaconInterval; + /* NOTE: Defer ucDTIMPeriod updating to when beacon is received after connection */ + prP2pBssInfo->ucDTIMPeriod = 0; + prP2pBssInfo->u2ATIMWindow = 0; + + prP2pBssInfo->ucBeaconTimeoutCount = AIS_BEACON_TIMEOUT_COUNT_INFRA; + + //4 <4.2> Update HT information and set channel + /* Record HT related parameters in rStaRec and rBssInfo + * Note: it shall be called before nicUpdateBss() + */ + rlmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); + + //4 <4.3> Sync with firmware for BSS-INFO + nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); + + //4 <4.4> *DEFER OPERATION* nicPmIndicateBssConnected() will be invoked + //inside scanProcessBeaconAndProbeResp() after 1st beacon is received + + return; +} /* end of p2pUpdateBssInfoForJOIN() */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will validate the Rx Auth Frame and then return +* the status code to AAA to indicate if need to perform following actions +* when the specified conditions were matched. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[in] pprStaRec Pointer to pointer of STA_RECORD_T structure. +* @param[out] pu2StatusCode The Status Code of Validation Result +* +* @retval TRUE Reply the Auth +* @retval FALSE Don't reply the Auth +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +p2pFuncValidateAuth ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN PP_STA_RECORD_T pprStaRec, + OUT PUINT_16 pu2StatusCode + ) +{ + BOOLEAN fgReplyAuth = TRUE; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + P_WLAN_AUTH_FRAME_T prAuthFrame = (P_WLAN_AUTH_FRAME_T)NULL; + + DBGLOG(P2P, TRACE, ("p2pValidate Authentication Frame\n")) + + do { + ASSERT_BREAK((prAdapter != NULL) && + (prSwRfb != NULL) && + (pprStaRec != NULL) && + (pu2StatusCode != NULL)); + + /* P2P 3.2.8 */ + *pu2StatusCode = STATUS_CODE_REQ_DECLINED; + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prAuthFrame = (P_WLAN_AUTH_FRAME_T)prSwRfb->pvHeader; + + + if (prP2pBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) { + /* We are not under AP Mode yet. */ + fgReplyAuth = FALSE; + DBGLOG(P2P, WARN, ("Current OP mode is not under AP mode. (%d)\n", prP2pBssInfo->eCurrentOPMode)); + break; + } + + prStaRec = cnmGetStaRecByAddress(prAdapter, + (UINT_8) NETWORK_TYPE_P2P_INDEX, + prAuthFrame->aucSrcAddr); + + if (!prStaRec) { + prStaRec = cnmStaRecAlloc(prAdapter, + (UINT_8) NETWORK_TYPE_P2P_INDEX); + + /* TODO(Kevin): Error handling of allocation of STA_RECORD_T for + * exhausted case and do removal of unused STA_RECORD_T. + */ + /* Sent a message event to clean un-used STA_RECORD_T. */ + ASSERT(prStaRec); + + COPY_MAC_ADDR(prStaRec->aucMacAddr, prAuthFrame->aucSrcAddr); + + prSwRfb->ucStaRecIdx = prStaRec->ucIndex; + + prStaRec->u2BSSBasicRateSet = prP2pBssInfo->u2BSSBasicRateSet; + + prStaRec->u2DesiredNonHTRateSet = RATE_SET_ERP_P2P; + + prStaRec->u2OperationalRateSet = RATE_SET_ERP_P2P; + prStaRec->ucPhyTypeSet = PHY_TYPE_SET_802_11GN; + prStaRec->eStaType = STA_TYPE_P2P_GC; + + /* NOTE(Kevin): Better to change state here, not at TX Done */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + } + else { + prSwRfb->ucStaRecIdx = prStaRec->ucIndex; + + if ((prStaRec->ucStaState > STA_STATE_1) && (IS_STA_IN_P2P(prStaRec))) { + + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + + p2pFuncResetStaRecStatus(prAdapter, prStaRec); + + bssRemoveStaRecFromClientList(prAdapter, prP2pBssInfo, prStaRec); + } + + } + + if (prP2pBssInfo->rStaRecOfClientList.u4NumElem >= P2P_MAXIMUM_CLIENT_COUNT) { + /* GROUP limit full. */ + /* P2P 3.2.8 */ + DBGLOG(P2P, WARN, ("Group Limit Full. (%d)\n", (INT_16)prP2pBssInfo->rStaRecOfClientList.u4NumElem)); + cnmStaRecFree(prAdapter, prStaRec, FALSE); + break; + } + else { + // TODO: /* Black List. */ + } + + //prStaRec->eStaType = STA_TYPE_INFRA_CLIENT; + prStaRec->eStaType = STA_TYPE_P2P_GC; + + prStaRec->ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; + + /* Update Station Record - Status/Reason Code */ + prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; + + prStaRec->ucJoinFailureCount = 0; + + *pprStaRec = prStaRec; + + *pu2StatusCode = STATUS_CODE_SUCCESSFUL; + + } while (FALSE); + + + return fgReplyAuth; + +} /* p2pFuncValidateAuth */ + + + + +VOID +p2pFuncResetStaRecStatus ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ) +{ + do { + if ((prAdapter == NULL) || (prStaRec == NULL)) { + ASSERT(FALSE); + break; + } + + + prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; + prStaRec->u2ReasonCode = REASON_CODE_RESERVED; + prStaRec->ucJoinFailureCount = 0; + prStaRec->fgTransmitKeyExist = FALSE; + + prStaRec->fgSetPwrMgtBit = FALSE; + + } while (FALSE); + + return; +} /* p2pFuncResetStaRecStatus */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief The function is used to initialize the value of the connection settings for +* P2P network +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFuncInitConnectionSettings ( + IN P_ADAPTER_T prAdapter, + IN P_P2P_CONNECTION_SETTINGS_T prP2PConnSettings + ) +{ + P_DEVICE_TYPE_T prDevType; + UINT_8 aucDefaultDevName[] = P2P_DEFAULT_DEV_NAME; + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; + + ASSERT(prP2PConnSettings); + + /* Setup Default Device Name */ + prP2PConnSettings->ucDevNameLen = P2P_DEFAULT_DEV_NAME_LEN; + kalMemCopy(prP2PConnSettings->aucDevName, aucDefaultDevName, sizeof(aucDefaultDevName)); + + /* Setup Primary Device Type (Big-Endian) */ + prDevType = &prP2PConnSettings->rPrimaryDevTypeBE; + + prDevType->u2CategoryId = HTONS(P2P_DEFAULT_PRIMARY_CATEGORY_ID); + prDevType->u2SubCategoryId = HTONS(P2P_DEFAULT_PRIMARY_SUB_CATEGORY_ID); + + prDevType->aucOui[0] = aucWfaOui[0]; + prDevType->aucOui[1] = aucWfaOui[1]; + prDevType->aucOui[2] = aucWfaOui[2]; + prDevType->aucOui[3] = VENDOR_OUI_TYPE_WPS; + + /* Setup Secondary Device Type */ + prP2PConnSettings->ucSecondaryDevTypeCount = 0; + + /* Setup Default Config Method */ + prP2PConnSettings->eConfigMethodSelType = ENUM_CONFIG_METHOD_SEL_AUTO; + prP2PConnSettings->u2ConfigMethodsSupport = P2P_DEFAULT_CONFIG_METHOD; + prP2PConnSettings->u2TargetConfigMethod = 0; + prP2PConnSettings->u2LocalConfigMethod = 0; + prP2PConnSettings->fgIsPasswordIDRdy = FALSE; + + /* For Device Capability */ + prP2PConnSettings->fgSupportServiceDiscovery = FALSE; + prP2PConnSettings->fgSupportClientDiscoverability = TRUE; + prP2PConnSettings->fgSupportConcurrentOperation = TRUE; + prP2PConnSettings->fgSupportInfraManaged = FALSE; + prP2PConnSettings->fgSupportInvitationProcedure = FALSE; + + /* For Group Capability */ +#if CFG_SUPPORT_PERSISTENT_GROUP + prP2PConnSettings->fgSupportPersistentP2PGroup = TRUE; +#else + prP2PConnSettings->fgSupportPersistentP2PGroup = FALSE; +#endif + prP2PConnSettings->fgSupportIntraBSSDistribution = TRUE; + prP2PConnSettings->fgSupportCrossConnection = TRUE; + prP2PConnSettings->fgSupportPersistentReconnect = FALSE; + + prP2PConnSettings->fgSupportOppPS = FALSE; + prP2PConnSettings->u2CTWindow = P2P_CTWINDOW_DEFAULT; + + /* For Connection Settings. */ + prP2PConnSettings->eAuthMode = AUTH_MODE_OPEN; + + prP2PConnSettings->prTargetP2pDesc = NULL; + prP2PConnSettings->ucSSIDLen = 0; + + /* Misc */ + prP2PConnSettings->fgIsScanReqIssued = FALSE; + prP2PConnSettings->fgIsServiceDiscoverIssued = FALSE; + prP2PConnSettings->fgP2pGroupLimit = FALSE; + prP2PConnSettings->ucOperatingChnl = 0; + prP2PConnSettings->ucListenChnl = 0; + prP2PConnSettings->ucTieBreaker = (UINT_8)(kalRandomNumber() & 0x1); + + prP2PConnSettings->eFormationPolicy = ENUM_P2P_FORMATION_POLICY_AUTO; + + return; +} /* p2pFuncInitConnectionSettings */ + + + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will validate the Rx Assoc Req Frame and then return +* the status code to AAA to indicate if need to perform following actions +* when the specified conditions were matched. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[out] pu2StatusCode The Status Code of Validation Result +* +* @retval TRUE Reply the Assoc Resp +* @retval FALSE Don't reply the Assoc Resp +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +p2pFuncValidateAssocReq ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT PUINT_16 pu2StatusCode + ) +{ + BOOLEAN fgReplyAssocResp = TRUE; + P_WLAN_ASSOC_REQ_FRAME_T prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T)NULL; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + + /* TODO(Kevin): Call P2P functions to check .. + 2. Check we can accept connection from thsi peer + a. If we are in PROVISION state, only accept the peer we do the GO formation previously. + b. If we are in OPERATION state, only accept the other peer when P2P_GROUP_LIMIT is 0. + 3. Check Black List here. + */ + + do { + ASSERT_BREAK((prAdapter != NULL) && + (prSwRfb != NULL) && + (pu2StatusCode != NULL)); + + *pu2StatusCode = STATUS_CODE_REQ_DECLINED; + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T)prSwRfb->pvHeader; + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + if (prStaRec == NULL) { + /* Station record should be ready while RX AUTH frame. */ + fgReplyAssocResp = FALSE; + ASSERT(FALSE); + break; + } + else { + prStaRec->ucRCPI = prSwRfb->prHifRxHdr->ucRcpi; + } + + prStaRec->u2DesiredNonHTRateSet &= prP2pBssInfo->u2OperationalRateSet; + prStaRec->ucDesiredPhyTypeSet = prStaRec->ucPhyTypeSet & prP2pBssInfo->ucPhyTypeSet; + + if (prStaRec->ucDesiredPhyTypeSet == 0) { + /* The station only support 11B rate. */ + *pu2StatusCode = STATUS_CODE_ASSOC_DENIED_RATE_NOT_SUPPORTED; + break; + } + + *pu2StatusCode = STATUS_CODE_SUCCESSFUL; + + } while (FALSE); + + return fgReplyAssocResp; + +} /* p2pFuncValidateAssocReq */ + + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to check the P2P IE +* +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +p2pFuncParseCheckForP2PInfoElem ( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucBuf, + OUT PUINT_8 pucOuiType + ) +{ + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; + P_IE_WFA_T prWfaIE = (P_IE_WFA_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL) && (pucOuiType != NULL)); + + prWfaIE = (P_IE_WFA_T)pucBuf; + + if (IE_LEN(pucBuf) <= ELEM_MIN_LEN_WFA_OUI_TYPE_SUBTYPE) { + break; + } + else if (prWfaIE->aucOui[0] != aucWfaOui[0] || + prWfaIE->aucOui[1] != aucWfaOui[1] || + prWfaIE->aucOui[2] != aucWfaOui[2]) { + break; + } + + *pucOuiType = prWfaIE->ucOuiType; + + return TRUE; + } while (FALSE); + + return FALSE; +} /* p2pFuncParseCheckForP2PInfoElem */ + + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will validate the Rx Probe Request Frame and then return +* result to BSS to indicate if need to send the corresponding Probe Response +* Frame if the specified conditions were matched. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[out] pu4ControlFlags Control flags for replying the Probe Response +* +* @retval TRUE Reply the Probe Response +* @retval FALSE Don't reply the Probe Response +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +p2pFuncValidateProbeReq ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT PUINT_32 pu4ControlFlags + ) +{ + BOOLEAN fgIsReplyProbeRsp = FALSE; + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + + DEBUGFUNC("p2pFuncValidateProbeReq"); + + do { + + ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + if (prP2pFsmInfo->u4P2pPacketFilter & PARAM_PACKET_FILTER_PROBE_REQ) { + /* Leave the probe response to p2p_supplicant. */ + kalP2PIndicateRxMgmtFrame(prAdapter->prGlueInfo, prSwRfb); + } + + } while (FALSE); + + return fgIsReplyProbeRsp; + +} /* end of p2pFuncValidateProbeReq() */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will validate the Rx Probe Request Frame and then return +* result to BSS to indicate if need to send the corresponding Probe Response +* Frame if the specified conditions were matched. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[out] pu4ControlFlags Control flags for replying the Probe Response +* +* @retval TRUE Reply the Probe Response +* @retval FALSE Don't reply the Probe Response +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFuncValidateRxActionFrame ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + + DEBUGFUNC("p2pFuncValidateProbeReq"); + + do { + + ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + if (prP2pFsmInfo->u4P2pPacketFilter & PARAM_PACKET_FILTER_ACTION_FRAME) { + /* Leave the probe response to p2p_supplicant. */ + kalP2PIndicateRxMgmtFrame(prAdapter->prGlueInfo, prSwRfb); + } + + } while (FALSE); + + return; + +} /* p2pFuncValidateRxMgmtFrame */ + + + + +BOOLEAN +p2pFuncIsAPMode ( + IN P_P2P_FSM_INFO_T prP2pFsmInfo + ) +{ + if (prP2pFsmInfo) { + return prP2pFsmInfo->fgIsApMode; + } + else { + return FALSE; + } +} +/* p2pFuncIsAPMode */ + + + +VOID +p2pFuncParseBeaconContent ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN PUINT_8 pucIEInfo, + IN UINT_32 u4IELen + ) +{ + PUINT_8 pucIE = (PUINT_8)NULL; + UINT_16 u2Offset = 0; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T)NULL; + BOOL ucNewSecMode = FALSE; + BOOL ucOldSecMode = FALSE; + + do { + ASSERT_BREAK((prAdapter != NULL) && + (prP2pBssInfo != NULL)); + + if (u4IELen == 0) { + break; + } + + prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; + prP2pSpecificBssInfo->u2AttributeLen = 0; + + ASSERT_BREAK(pucIEInfo != NULL); + + pucIE = pucIEInfo; + + ucOldSecMode = kalP2PGetCipher(prAdapter->prGlueInfo); + + IE_FOR_EACH(pucIE, u4IELen, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_SSID: /* 0 */ /* V */ /* Done */ + { + DBGLOG(P2P, TRACE, ("SSID update\n")); + + /* Update when starting GO. */ + COPY_SSID(prP2pBssInfo->aucSSID, + prP2pBssInfo->ucSSIDLen, + SSID_IE(pucIE)->aucSSID, + SSID_IE(pucIE)->ucLength); + + COPY_SSID(prP2pSpecificBssInfo->aucGroupSsid, + prP2pSpecificBssInfo->u2GroupSsidLen, + SSID_IE(pucIE)->aucSSID, + SSID_IE(pucIE)->ucLength); + + } + break; + case ELEM_ID_SUP_RATES: /* 1 */ /* V */ /* Done */ + { + DBGLOG(P2P, TRACE, ("Support Rate IE\n")); + kalMemCopy(prP2pBssInfo->aucAllSupportedRates, + SUP_RATES_IE(pucIE)->aucSupportedRates, + SUP_RATES_IE(pucIE)->ucLength); + + prP2pBssInfo->ucAllSupportedRatesLen = SUP_RATES_IE(pucIE)->ucLength; + + DBGLOG_MEM8(P2P, TRACE, SUP_RATES_IE(pucIE)->aucSupportedRates, SUP_RATES_IE(pucIE)->ucLength); + } + break; + case ELEM_ID_DS_PARAM_SET: /* 3 */ /* V */ /* Done */ + { + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + + DBGLOG(P2P, TRACE, ("DS PARAM IE\n")); + + ASSERT(prP2pConnSettings->ucOperatingChnl == DS_PARAM_IE(pucIE)->ucCurrChnl); + + if (prP2pConnSettings->eBand != BAND_2G4) { + ASSERT(FALSE); + break; + } + + prP2pBssInfo->ucPrimaryChannel = DS_PARAM_IE(pucIE)->ucCurrChnl; + + prP2pBssInfo->eBand = BAND_2G4; + } + break; + case ELEM_ID_TIM: /* 5 */ /* V */ + DBGLOG(P2P, TRACE, ("TIM IE\n")); + TIM_IE(pucIE)->ucDTIMPeriod = prP2pBssInfo->ucDTIMPeriod; + break; + case ELEM_ID_ERP_INFO: /* 42 */ /* V */ + { +#if 1 + /* This IE would dynamic change due to FW detection change is required. */ + DBGLOG(P2P, TRACE, ("ERP IE will be over write by driver\n")); + DBGLOG(P2P, TRACE, (" ucERP: %x. \n", ERP_INFO_IE(pucIE)->ucERP)); + +#else + /* This IE would dynamic change due to FW detection change is required. */ + DBGLOG(P2P, TRACE, ("ERP IE.\n")); + + prP2pBssInfo->ucPhyTypeSet |= PHY_TYPE_SET_802_11GN; + + ASSERT(prP2pBssInfo->eBand == BAND_2G4); + + prP2pBssInfo->fgObssErpProtectMode = ((ERP_INFO_IE(pucIE)->ucERP & ERP_INFO_USE_PROTECTION)? TRUE : FALSE); + + prP2pBssInfo->fgErpProtectMode = ((ERP_INFO_IE(pucIE)->ucERP & (ERP_INFO_USE_PROTECTION | ERP_INFO_NON_ERP_PRESENT))? TRUE : FALSE); +#endif + + } + break; + case ELEM_ID_HT_CAP: /* 45 */ /* V */ + { +#if 1 + DBGLOG(P2P, TRACE, ("HT CAP IE would be overwritten by driver\n")); + + DBGLOG(P2P, TRACE, ("HT Cap Info:%x, AMPDU Param:%x\n", HT_CAP_IE(pucIE)->u2HtCapInfo, HT_CAP_IE(pucIE)->ucAmpduParam)); + + DBGLOG(P2P, TRACE, ("HT Extended Cap Info:%x, TX Beamforming Cap Info:%lx, Ant Selection Cap Info%x \n", + HT_CAP_IE(pucIE)->u2HtExtendedCap, + HT_CAP_IE(pucIE)->u4TxBeamformingCap, + HT_CAP_IE(pucIE)->ucAselCap)); +#else + prP2pBssInfo->ucPhyTypeSet |= PHY_TYPE_SET_802_11N; + + /* u2HtCapInfo */ + if ((HT_CAP_IE(pucIE)->u2HtCapInfo & + (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_DSSS_CCK_IN_40M)) == 0) { + prP2pBssInfo->fgAssoc40mBwAllowed = FALSE; + } + else { + prP2pBssInfo->fgAssoc40mBwAllowed = TRUE; + } + + if ((HT_CAP_IE(pucIE)->u2HtCapInfo & + (HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M)) == 0) { + prAdapter->rWifiVar.rConnSettings.fgRxShortGIDisabled = TRUE; + } + else { + prAdapter->rWifiVar.rConnSettings.fgRxShortGIDisabled = FALSE; + } + + /* ucAmpduParam */ + DBGLOG(P2P, TRACE, ("AMPDU setting from supplicant:0x%x, & default value:0x%x\n", (UINT_8)HT_CAP_IE(pucIE)->ucAmpduParam, (UINT_8)AMPDU_PARAM_DEFAULT_VAL)); + + /* rSupMcsSet */ + /* Can do nothing. the field is default value from other configuration. */ + //HT_CAP_IE(pucIE)->rSupMcsSet; + + /* u2HtExtendedCap */ + ASSERT(HT_CAP_IE(pucIE)->u2HtExtendedCap == (HT_EXT_CAP_DEFAULT_VAL & ~(HT_EXT_CAP_PCO | HT_EXT_CAP_PCO_TRANS_TIME_NONE))); + + /* u4TxBeamformingCap */ + ASSERT(HT_CAP_IE(pucIE)->u4TxBeamformingCap == TX_BEAMFORMING_CAP_DEFAULT_VAL); + + /* ucAselCap */ + ASSERT(HT_CAP_IE(pucIE)->ucAselCap == ASEL_CAP_DEFAULT_VAL); +#endif + } + break; + case ELEM_ID_RSN: /* 48 */ /* V */ + { + RSN_INFO_T rRsnIe; + + DBGLOG(P2P, TRACE, ("RSN IE\n")); + kalP2PSetCipher(prAdapter->prGlueInfo, IW_AUTH_CIPHER_CCMP); + ucNewSecMode = TRUE; + + if (rsnParseRsnIE(prAdapter, RSN_IE(pucIE), &rRsnIe)) { + prP2pBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; + prP2pBssInfo->u4RsnSelectedGroupCipher = RSN_CIPHER_SUITE_CCMP; + prP2pBssInfo->u4RsnSelectedPairwiseCipher = RSN_CIPHER_SUITE_CCMP; + prP2pBssInfo->u4RsnSelectedAKMSuite = RSN_AKM_SUITE_PSK; + prP2pBssInfo->u2RsnSelectedCapInfo = rRsnIe.u2RsnCap; + } + } + break; + case ELEM_ID_EXTENDED_SUP_RATES: /* 50 */ /* V */ + /* Be attention, ELEM_ID_SUP_RATES should be placed before ELEM_ID_EXTENDED_SUP_RATES. */ + DBGLOG(P2P, TRACE, ("Ex Support Rate IE\n")); + kalMemCopy(&(prP2pBssInfo->aucAllSupportedRates[prP2pBssInfo->ucAllSupportedRatesLen]), + EXT_SUP_RATES_IE(pucIE)->aucExtSupportedRates, + EXT_SUP_RATES_IE(pucIE)->ucLength); + + DBGLOG_MEM8(P2P, TRACE, EXT_SUP_RATES_IE(pucIE)->aucExtSupportedRates, EXT_SUP_RATES_IE(pucIE)->ucLength); + + prP2pBssInfo->ucAllSupportedRatesLen += EXT_SUP_RATES_IE(pucIE)->ucLength; + break; + case ELEM_ID_HT_OP: /* 61 */ /* V */ // TODO: + { +#if 1 + DBGLOG(P2P, TRACE, ("HT OP IE would be overwritten by driver\n")); + + DBGLOG(P2P, TRACE, (" Primary Channel: %x, Info1: %x, Info2: %x, Info3: %x\n", + HT_OP_IE(pucIE)->ucPrimaryChannel, + HT_OP_IE(pucIE)->ucInfo1, + HT_OP_IE(pucIE)->u2Info2, + HT_OP_IE(pucIE)->u2Info3)); +#else + UINT_16 u2Info2 = 0; + prP2pBssInfo->ucPhyTypeSet |= PHY_TYPE_SET_802_11N; + + DBGLOG(P2P, TRACE, ("HT OP IE\n")); + + /* ucPrimaryChannel. */ + ASSERT(HT_OP_IE(pucIE)->ucPrimaryChannel == prP2pBssInfo->ucPrimaryChannel); + + /* ucInfo1 */ + prP2pBssInfo->ucHtOpInfo1 = HT_OP_IE(pucIE)->ucInfo1; + + /* u2Info2 */ + u2Info2 = HT_OP_IE(pucIE)->u2Info2; + + if (u2Info2 & HT_OP_INFO2_NON_GF_HT_STA_PRESENT) { + ASSERT(prP2pBssInfo->eGfOperationMode != GF_MODE_NORMAL); + u2Info2 &= ~HT_OP_INFO2_NON_GF_HT_STA_PRESENT; + } + + if (u2Info2 & HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT) { + prP2pBssInfo->eObssHtProtectMode = HT_PROTECT_MODE_NON_MEMBER; + u2Info2 &= ~HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT; + } + + switch (u2Info2 & HT_OP_INFO2_HT_PROTECTION) { + case HT_PROTECT_MODE_NON_HT: + prP2pBssInfo->eHtProtectMode = HT_PROTECT_MODE_NON_HT; + break; + case HT_PROTECT_MODE_NON_MEMBER: + prP2pBssInfo->eHtProtectMode = HT_PROTECT_MODE_NONE; + prP2pBssInfo->eObssHtProtectMode = HT_PROTECT_MODE_NON_MEMBER; + break; + default: + prP2pBssInfo->eHtProtectMode = HT_OP_IE(pucIE)->u2Info2; + break; + } + + /* u2Info3 */ + prP2pBssInfo->u2HtOpInfo3 = HT_OP_IE(pucIE)->u2Info3; + + /* aucBasicMcsSet */ + DBGLOG_MEM8(P2P, TRACE, HT_OP_IE(pucIE)->aucBasicMcsSet, 16); +#endif + } + break; + case ELEM_ID_OBSS_SCAN_PARAMS: /* 74 */ /* V */ + { + DBGLOG(P2P, TRACE, ("ELEM_ID_OBSS_SCAN_PARAMS IE would be replaced by driver\n")); + } + break; + case ELEM_ID_EXTENDED_CAP: /* 127 */ /* V */ + { + DBGLOG(P2P, TRACE, ("ELEM_ID_EXTENDED_CAP IE would be replaced by driver\n")); + } + break; + case ELEM_ID_VENDOR: /* 221 */ /* V */ + DBGLOG(P2P, TRACE, ("Vender Specific IE\n")); + { + UINT_8 ucOuiType; + UINT_16 u2SubTypeVersion; + if (rsnParseCheckForWFAInfoElem(prAdapter, pucIE, &ucOuiType, &u2SubTypeVersion)) { + if ((ucOuiType == VENDOR_OUI_TYPE_WPA) && + (u2SubTypeVersion == VERSION_WPA)) { + kalP2PSetCipher(prAdapter->prGlueInfo, IW_AUTH_CIPHER_TKIP); + ucNewSecMode = TRUE; + } + else if ((ucOuiType == VENDOR_OUI_TYPE_WPS)) { + kalP2PUpdateWSC_IE(prAdapter->prGlueInfo, 0, pucIE, IE_SIZE(pucIE)); + } + + // WMM here. + } + else if (p2pFuncParseCheckForP2PInfoElem(prAdapter, pucIE, &ucOuiType)) { + // TODO Store the whole P2P IE & generate later. + // Be aware that there may be one or more P2P IE. + if (ucOuiType == VENDOR_OUI_TYPE_P2P) { + kalMemCopy(&prP2pSpecificBssInfo->aucAttributesCache[prP2pSpecificBssInfo->u2AttributeLen], + pucIE, + IE_SIZE(pucIE)); + + prP2pSpecificBssInfo->u2AttributeLen += IE_SIZE(pucIE); + } + } + else { + + kalMemCopy(&prP2pSpecificBssInfo->aucAttributesCache[prP2pSpecificBssInfo->u2AttributeLen], + pucIE, + IE_SIZE(pucIE)); + + prP2pSpecificBssInfo->u2AttributeLen += IE_SIZE(pucIE); + DBGLOG(P2P, TRACE, ("Driver unprocessed Vender Specific IE\n")); + ASSERT(FALSE); + } + + // TODO: Store other Vender IE except for WMM Param. + } + break; + default: + DBGLOG(P2P, TRACE, ("Unprocessed element ID:%d \n", IE_ID(pucIE))); + break; + } + } + + if (!ucNewSecMode && ucOldSecMode) + kalP2PSetCipher(prAdapter->prGlueInfo, IW_AUTH_CIPHER_NONE); + + } while (FALSE); + + return; +} /* p2pFuncParseBeaconContent */ + + + + +P_BSS_DESC_T +p2pFuncKeepOnConnection ( + IN P_ADAPTER_T prAdapter, + IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, + IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo + ) +{ + P_BSS_DESC_T prTargetBss = (P_BSS_DESC_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && + (prConnReqInfo != NULL) && + (prChnlReqInfo != NULL) && + (prScanReqInfo != NULL)); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + if (prP2pBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) { + break; + } + + // Update connection request information. + ASSERT(prConnReqInfo->fgIsConnRequest == TRUE); + + /* Find BSS Descriptor first. */ + prTargetBss = scanP2pSearchDesc(prAdapter, + prP2pBssInfo, + prConnReqInfo); + + if (prTargetBss == NULL) { + /* Update scan parameter... to scan target device. */ + prScanReqInfo->ucNumChannelList = 1; + prScanReqInfo->eScanType = SCAN_TYPE_ACTIVE_SCAN; + prScanReqInfo->eChannelSet = SCAN_CHANNEL_FULL; + prScanReqInfo->u4BufLength = 0; /* Prevent other P2P ID in IE. */ + prScanReqInfo->fgIsAbort = TRUE; + } + else { + prChnlReqInfo->u8Cookie = 0; + prChnlReqInfo->ucReqChnlNum = prTargetBss->ucChannelNum; + prChnlReqInfo->eBand = prTargetBss->eBand; + prChnlReqInfo->eChnlSco = prTargetBss->eSco; + prChnlReqInfo->u4MaxInterval = AIS_JOIN_CH_REQUEST_INTERVAL; + prChnlReqInfo->eChannelReqType = CHANNEL_REQ_TYPE_GC_JOIN_REQ; + } + + } while (FALSE); + + return prTargetBss; +} /* p2pFuncKeepOnConnection */ + +/* Currently Only for ASSOC Response Frame. */ +VOID +p2pFuncStoreAssocRspIEBuffer ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + P_P2P_JOIN_INFO_T prJoinInfo = (P_P2P_JOIN_INFO_T)NULL; + P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T)NULL; + INT_16 i2IELen = 0; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); + + prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T)prSwRfb->pvHeader; + + if (prAssocRspFrame->u2FrameCtrl != MAC_FRAME_ASSOC_RSP) { + break; + } + + i2IELen = prSwRfb->u2PacketLen - (WLAN_MAC_HEADER_LEN + + CAP_INFO_FIELD_LEN + + STATUS_CODE_FIELD_LEN + + AID_FIELD_LEN); + + + if (i2IELen <= 0) { + break; + } + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + prJoinInfo = &(prP2pFsmInfo->rJoinInfo); + prJoinInfo->u4BufLength = (UINT_32)i2IELen; + + kalMemCopy(prJoinInfo->aucIEBuf, prAssocRspFrame->aucInfoElem, prJoinInfo->u4BufLength); + + } while (FALSE); + + + return; +} /* p2pFuncStoreAssocRspIEBuffer */ + + + + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set Packet Filter. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_NOT_SUPPORTED +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFuncMgmtFrameRegister ( + IN P_ADAPTER_T prAdapter, + IN UINT_16 u2FrameType, + IN BOOLEAN fgIsRegistered, + OUT PUINT_32 pu4P2pPacketFilter + ) +{ + UINT_32 u4NewPacketFilter = 0; + + DEBUGFUNC("p2pFuncMgmtFrameRegister"); + + do { + ASSERT_BREAK(prAdapter != NULL); + + if (pu4P2pPacketFilter) { + u4NewPacketFilter = *pu4P2pPacketFilter; + } + + switch (u2FrameType) { + case MAC_FRAME_PROBE_REQ: + if (fgIsRegistered) { + u4NewPacketFilter |= PARAM_PACKET_FILTER_PROBE_REQ; + DBGLOG(P2P, TRACE, ("Open packet filer probe request\n")); + } + else { + u4NewPacketFilter &= ~PARAM_PACKET_FILTER_PROBE_REQ; + DBGLOG(P2P, TRACE, ("Close packet filer probe request\n")); + } + break; + case MAC_FRAME_ACTION: + if (fgIsRegistered) { + u4NewPacketFilter |= PARAM_PACKET_FILTER_ACTION_FRAME; + DBGLOG(P2P, TRACE, ("Open packet filer action frame.\n")); + } + else { + u4NewPacketFilter &= ~PARAM_PACKET_FILTER_ACTION_FRAME; + DBGLOG(P2P, TRACE, ("Close packet filer action frame.\n")); + } + break; + default: + DBGLOG(P2P, TRACE, ("Ask frog to add code for mgmt:%x\n", u2FrameType)); + break; + } + + if (pu4P2pPacketFilter) { + *pu4P2pPacketFilter = u4NewPacketFilter; + } + +// u4NewPacketFilter |= prAdapter->u4OsPacketFilter; + + prAdapter->u4OsPacketFilter &= ~PARAM_PACKET_FILTER_P2P_MASK; + prAdapter->u4OsPacketFilter |= u4NewPacketFilter; + + DBGLOG(P2P, TRACE, ("P2P Set PACKET filter:0x%lx\n", prAdapter->u4OsPacketFilter)); + + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_RX_FILTER, + TRUE, + FALSE, + FALSE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(UINT_32), + (PUINT_8)&prAdapter->u4OsPacketFilter, + &u4NewPacketFilter, + sizeof(u4NewPacketFilter) + ); + + } while (FALSE); + + return; +} /* p2pFuncMgmtFrameRegister */ + + +VOID +p2pFuncGetStationInfo ( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucMacAddr, + OUT P_P2P_STATION_INFO_T prStaInfo + ) +{ + + do { + ASSERT_BREAK((prAdapter != NULL) && + (pucMacAddr != NULL) && + (prStaInfo != NULL)); + + prStaInfo->u4InactiveTime = 0; + prStaInfo->u4RxBytes = 0; + prStaInfo->u4TxBytes = 0; + prStaInfo->u4RxPackets = 0; + prStaInfo->u4TxPackets = 0; + // TODO: + + } while (FALSE); + + return; +} /* p2pFuncGetStationInfo */ + +P_MSDU_INFO_T +p2pFuncProcessP2pProbeRsp ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMgmtTxMsdu + ) +{ + P_MSDU_INFO_T prRetMsduInfo = prMgmtTxMsdu; + P_WLAN_PROBE_RSP_FRAME_T prProbeRspFrame = (P_WLAN_PROBE_RSP_FRAME_T)NULL; + PUINT_8 pucIEBuf = (PUINT_8)NULL; + UINT_16 u2Offset = 0, u2IELength = 0, u2ProbeRspHdrLen = 0; + BOOLEAN fgIsP2PIE = FALSE, fgIsWSCIE = FALSE; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + UINT_16 u2EstimateSize = 0, u2EstimatedExtraIELen = 0; + UINT_32 u4IeArraySize = 0, u4Idx = 0; + + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMgmtTxMsdu != NULL)); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + //3 Make sure this is probe response frame. + prProbeRspFrame = (P_WLAN_PROBE_RSP_FRAME_T)((UINT_32)prMgmtTxMsdu->prPacket + MAC_TX_RESERVED_FIELD); + ASSERT_BREAK((prProbeRspFrame->u2FrameCtrl & MASK_FRAME_TYPE) == MAC_FRAME_PROBE_RSP); + + //3 Get the importent P2P IE. + u2ProbeRspHdrLen = (WLAN_MAC_MGMT_HEADER_LEN + TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN); + pucIEBuf = prProbeRspFrame->aucInfoElem; + u2IELength = prMgmtTxMsdu->u2FrameLength - u2ProbeRspHdrLen; + IE_FOR_EACH(pucIEBuf, u2IELength, u2Offset) { + switch (IE_ID(pucIEBuf)) { + case ELEM_ID_SSID: + { + + COPY_SSID(prP2pBssInfo->aucSSID, + prP2pBssInfo->ucSSIDLen, + SSID_IE(pucIEBuf)->aucSSID, + SSID_IE(pucIEBuf)->ucLength); + } + break; + case ELEM_ID_VENDOR: + { + UINT_8 ucOuiType = 0; + UINT_16 u2SubTypeVersion = 0; + if (rsnParseCheckForWFAInfoElem(prAdapter, pucIEBuf, &ucOuiType, &u2SubTypeVersion)) { + if (ucOuiType == VENDOR_OUI_TYPE_WPS) { + kalP2PUpdateWSC_IE(prAdapter->prGlueInfo, 2, pucIEBuf, IE_SIZE(pucIEBuf)); + fgIsWSCIE = TRUE; + } + + } + + else if (p2pFuncParseCheckForP2PInfoElem(prAdapter, pucIEBuf, &ucOuiType)) { + if (ucOuiType == VENDOR_OUI_TYPE_P2P) { + //2 Note(frog): I use WSC IE buffer for Probe Request to store the P2P IE for Probe Response. + kalP2PUpdateWSC_IE(prAdapter->prGlueInfo, 1, pucIEBuf, IE_SIZE(pucIEBuf)); + fgIsP2PIE = TRUE; + } + + } + + } + break; + default: + break; + } + + } + + + //3 Check the total size & current frame. + u2EstimateSize = WLAN_MAC_MGMT_HEADER_LEN + \ + TIMESTAMP_FIELD_LEN + \ + BEACON_INTERVAL_FIELD_LEN + \ + CAP_INFO_FIELD_LEN + \ + (ELEM_HDR_LEN + ELEM_MAX_LEN_SSID) + \ + (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + \ + (ELEM_HDR_LEN + ELEM_MAX_LEN_DS_PARAMETER_SET); + + u2EstimatedExtraIELen = 0; + + u4IeArraySize = sizeof(txProbeRspIETable)/sizeof(APPEND_VAR_IE_ENTRY_T); + for (u4Idx = 0; u4Idx < u4IeArraySize; u4Idx++) { + if (txProbeRspIETable[u4Idx].u2EstimatedFixedIELen) { + u2EstimatedExtraIELen += txProbeRspIETable[u4Idx].u2EstimatedFixedIELen; + } + + else { + ASSERT(txProbeRspIETable[u4Idx].pfnCalculateVariableIELen); + + u2EstimatedExtraIELen += (UINT_16)(txProbeRspIETable[u4Idx].pfnCalculateVariableIELen(prAdapter, + NETWORK_TYPE_P2P_INDEX, + NULL)); + } + + } + + + if (fgIsWSCIE) { + u2EstimatedExtraIELen += kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 2); + } + + if (fgIsP2PIE) { + u2EstimatedExtraIELen += kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 1); + } + + + + + if ((u2EstimateSize += u2EstimatedExtraIELen) > (prRetMsduInfo->u2FrameLength)) { + prRetMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimateSize); + + if (prRetMsduInfo == NULL) { + DBGLOG(P2P, WARN, ("No packet for sending new probe response, use original one\n")); + prRetMsduInfo = prMgmtTxMsdu; + break; + } + + + prRetMsduInfo->ucNetworkType = NETWORK_TYPE_P2P_INDEX; + } + + + //3 Compose / Re-compose probe response frame. + bssComposeBeaconProbeRespFrameHeaderAndFF( + (PUINT_8)((UINT_32)(prRetMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + prProbeRspFrame->aucDestAddr, + prProbeRspFrame->aucSrcAddr, + prProbeRspFrame->aucBSSID, + prProbeRspFrame->u2BeaconInterval, + prProbeRspFrame->u2CapInfo); + + prRetMsduInfo->u2FrameLength = (WLAN_MAC_MGMT_HEADER_LEN + TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN); + + bssBuildBeaconProbeRespFrameCommonIEs(prRetMsduInfo, + prP2pBssInfo, + prProbeRspFrame->aucDestAddr); + + + for (u4Idx = 0; u4Idx < u4IeArraySize; u4Idx++) { + if (txProbeRspIETable[u4Idx].pfnAppendIE) { + txProbeRspIETable[u4Idx].pfnAppendIE(prAdapter, prRetMsduInfo); + } + + } + + + if (fgIsWSCIE) { + kalP2PGenWSC_IE(prAdapter->prGlueInfo, + 2, + (PUINT_8)((UINT_32)prRetMsduInfo->prPacket + (UINT_32)prRetMsduInfo->u2FrameLength)); + + prRetMsduInfo->u2FrameLength += (UINT_16)kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 2); + } + + if (fgIsP2PIE) { + kalP2PGenWSC_IE(prAdapter->prGlueInfo, + 1, + (PUINT_8)((UINT_32)prRetMsduInfo->prPacket + (UINT_32)prRetMsduInfo->u2FrameLength)); + + prRetMsduInfo->u2FrameLength += (UINT_16)kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 1); + } + + + } +while (FALSE); + + if (prRetMsduInfo != prMgmtTxMsdu) { + cnmMgtPktFree(prAdapter, prMgmtTxMsdu); + } + + + return prRetMsduInfo; +} /* p2pFuncProcessP2pProbeRsp */ + +UINT_32 +p2pFuncCalculateP2p_IELenForBeacon ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec + ) +{ + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpeBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T)NULL; + UINT_32 u4IELen = 0; + + do { + ASSERT_BREAK((prAdapter != NULL) && (eNetTypeIndex == NETWORK_TYPE_P2P_INDEX)); + + prP2pSpeBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; + + u4IELen = prP2pSpeBssInfo->u2AttributeLen; + + } while (FALSE); + + return u4IELen; +} /* p2pFuncCalculateP2p_IELenForBeacon */ + + +VOID +p2pFuncGenerateP2p_IEForBeacon ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ) +{ + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpeBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T)NULL; + PUINT_8 pucIEBuf = (PUINT_8)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); + + prP2pSpeBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; + + pucIEBuf = (PUINT_8)((UINT_32)prMsduInfo->prPacket + (UINT_32)prMsduInfo->u2FrameLength); + + kalMemCopy(pucIEBuf, prP2pSpeBssInfo->aucAttributesCache, prP2pSpeBssInfo->u2AttributeLen); + + prMsduInfo->u2FrameLength += prP2pSpeBssInfo->u2AttributeLen; + + } while (FALSE); + + return; +} /* p2pFuncGenerateP2p_IEForBeacon */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to calculate P2P IE length for Beacon frame. +* +* @param[in] eNetTypeIndex Specify which network +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return The length of P2P IE added +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 +p2pFuncCalculateP2p_IELenForAssocRsp ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec + ) +{ + + if (eNetTypeIndex != NETWORK_TYPE_P2P_INDEX) { + return 0; + } + + return p2pFuncCalculateP2P_IELen(prAdapter, + eNetTypeIndex, + prStaRec, + txAssocRspAttributesTable, + sizeof(txAssocRspAttributesTable)/sizeof(APPEND_VAR_ATTRI_ENTRY_T)); + +} /* p2pFuncCalculateP2p_IELenForAssocRsp */ + + + + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to generate P2P IE for Beacon frame. +* +* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFuncGenerateP2p_IEForAssocRsp ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if (IS_STA_P2P_TYPE(prStaRec)) { + DBGLOG(P2P, TRACE, ("Generate NULL P2P IE for Assoc Rsp.\n")); + + p2pFuncGenerateP2P_IE(prAdapter, + TRUE, + &prMsduInfo->u2FrameLength, + prMsduInfo->prPacket, + 1500, + txAssocRspAttributesTable, + sizeof(txAssocRspAttributesTable)/sizeof(APPEND_VAR_ATTRI_ENTRY_T)); + } + else { + + DBGLOG(P2P, TRACE, ("Legacy device, no P2P IE.\n")); + } + + } while (FALSE); + + return; + +} /* p2pFuncGenerateP2p_IEForAssocRsp */ + + + + +UINT_32 +p2pFuncCalculateWSC_IELenForBeacon ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec + ) +{ + if (eNetTypeIndex != NETWORK_TYPE_P2P_INDEX) { + return 0; + } + + return kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 0); +} /* p2pFuncCalculateP2p_IELenForBeacon */ + + +VOID +p2pFuncGenerateWSC_IEForBeacon ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ) +{ + PUINT_8 pucBuffer; + UINT_16 u2IELen = 0; + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + if (prMsduInfo->ucNetworkType != NETWORK_TYPE_P2P_INDEX) { + return; + } + + u2IELen = (UINT_16)kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 0); + + pucBuffer = (PUINT_8)((UINT_32)prMsduInfo->prPacket + + (UINT_32)prMsduInfo->u2FrameLength); + + ASSERT(pucBuffer); + + // TODO: Check P2P FSM State. + kalP2PGenWSC_IE(prAdapter->prGlueInfo, + 0, + pucBuffer); + + prMsduInfo->u2FrameLength += u2IELen; + + return; +} /* p2pFuncGenerateP2p_IEForBeacon */ + +UINT_32 +p2pFuncCalculateP2P_IELen ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec, + IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], + IN UINT_32 u4AttriTableSize + ) +{ + + UINT_32 u4OverallAttriLen, u4Dummy; + UINT_16 u2EstimatedFixedAttriLen; + UINT_32 i; + + + /* Overall length of all Attributes */ + u4OverallAttriLen = 0; + + for (i = 0; i < u4AttriTableSize; i++) { + u2EstimatedFixedAttriLen = arAppendAttriTable[i].u2EstimatedFixedAttriLen; + + if (u2EstimatedFixedAttriLen) { + u4OverallAttriLen += u2EstimatedFixedAttriLen; + } + else { + ASSERT(arAppendAttriTable[i].pfnCalculateVariableAttriLen); + + u4OverallAttriLen += + arAppendAttriTable[i].pfnCalculateVariableAttriLen(prAdapter, prStaRec); + } + } + + u4Dummy = u4OverallAttriLen; + u4OverallAttriLen += P2P_IE_OUI_HDR; + + for (;(u4Dummy > P2P_MAXIMUM_ATTRIBUTE_LEN);) { + u4OverallAttriLen += P2P_IE_OUI_HDR; + u4Dummy -= P2P_MAXIMUM_ATTRIBUTE_LEN; + } + + return u4OverallAttriLen; +} /* p2pFuncCalculateP2P_IELen */ + + +VOID +p2pFuncGenerateP2P_IE ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize, + IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], + IN UINT_32 u4AttriTableSize + ) +{ + PUINT_8 pucBuffer = (PUINT_8)NULL; + P_IE_P2P_T prIeP2P = (P_IE_P2P_T)NULL; + UINT_32 u4OverallAttriLen; + UINT_32 u4AttriLen; + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; + UINT_8 aucTempBuffer[P2P_MAXIMUM_ATTRIBUTE_LEN]; + UINT_32 i; + + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL)); + + pucBuffer = (PUINT_8)((UINT_32)pucBuf + (*pu2Offset)); + + ASSERT_BREAK(pucBuffer != NULL); + + /* Check buffer length is still enough. */ + ASSERT_BREAK((u2BufSize - (*pu2Offset)) >= P2P_IE_OUI_HDR); + + prIeP2P = (P_IE_P2P_T)pucBuffer; + + prIeP2P->ucId = ELEM_ID_P2P; + + prIeP2P->aucOui[0] = aucWfaOui[0]; + prIeP2P->aucOui[1] = aucWfaOui[1]; + prIeP2P->aucOui[2] = aucWfaOui[2]; + prIeP2P->ucOuiType = VENDOR_OUI_TYPE_P2P; + + (*pu2Offset) += P2P_IE_OUI_HDR; + + /* Overall length of all Attributes */ + u4OverallAttriLen = 0; + + + for (i = 0; i < u4AttriTableSize; i++) { + + if (arAppendAttriTable[i].pfnAppendAttri) { + u4AttriLen = arAppendAttriTable[i].pfnAppendAttri(prAdapter, fgIsAssocFrame, pu2Offset, pucBuf, u2BufSize); + + u4OverallAttriLen += u4AttriLen; + + if (u4OverallAttriLen > P2P_MAXIMUM_ATTRIBUTE_LEN) { + u4OverallAttriLen -= P2P_MAXIMUM_ATTRIBUTE_LEN; + + prIeP2P->ucLength = (VENDOR_OUI_TYPE_LEN + P2P_MAXIMUM_ATTRIBUTE_LEN); + + pucBuffer = (PUINT_8)((UINT_32)prIeP2P + (VENDOR_OUI_TYPE_LEN + P2P_MAXIMUM_ATTRIBUTE_LEN)); + + prIeP2P = (P_IE_P2P_T)((UINT_32)prIeP2P + + (ELEM_HDR_LEN + (VENDOR_OUI_TYPE_LEN + P2P_MAXIMUM_ATTRIBUTE_LEN))); + + kalMemCopy(aucTempBuffer, pucBuffer, u4OverallAttriLen); + + prIeP2P->ucId = ELEM_ID_P2P; + + prIeP2P->aucOui[0] = aucWfaOui[0]; + prIeP2P->aucOui[1] = aucWfaOui[1]; + prIeP2P->aucOui[2] = aucWfaOui[2]; + prIeP2P->ucOuiType = VENDOR_OUI_TYPE_P2P; + + kalMemCopy(prIeP2P->aucP2PAttributes, aucTempBuffer, u4OverallAttriLen); + (*pu2Offset) += P2P_IE_OUI_HDR; + } + + } + + } + + prIeP2P->ucLength = (UINT_8)(VENDOR_OUI_TYPE_LEN + u4OverallAttriLen); + + + } +while (FALSE); + + return; +} /* p2pFuncGenerateP2P_IE */ + +UINT_32 +p2pFuncAppendAttriStatusForAssocRsp ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ) +{ + PUINT_8 pucBuffer; + P_P2P_ATTRI_STATUS_T prAttriStatus; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T)NULL; + UINT_32 u4AttriLen = 0; + + ASSERT(prAdapter); + ASSERT(pucBuf); + + prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + + if (fgIsAssocFrame) { + return u4AttriLen; + } + + // TODO: For assoc request P2P IE check in driver & return status in P2P IE. + + pucBuffer = (PUINT_8)((UINT_32)pucBuf + + (UINT_32)(*pu2Offset)); + + ASSERT(pucBuffer); + prAttriStatus = (P_P2P_ATTRI_STATUS_T)pucBuffer; + + ASSERT(u2BufSize >= ((*pu2Offset) + (UINT_16)u4AttriLen)); + + + + + prAttriStatus->ucId = P2P_ATTRI_ID_STATUS; + WLAN_SET_FIELD_16(&prAttriStatus->u2Length, P2P_ATTRI_MAX_LEN_STATUS); + + prAttriStatus->ucStatusCode = P2P_STATUS_FAIL_PREVIOUS_PROTOCOL_ERR; + + u4AttriLen = (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_STATUS); + + (*pu2Offset) += (UINT_16)u4AttriLen; + + return u4AttriLen; +} /* p2pFuncAppendAttriStatusForAssocRsp */ + +UINT_32 +p2pFuncAppendAttriExtListenTiming ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize + ) +{ + UINT_32 u4AttriLen = 0; + P_P2P_ATTRI_EXT_LISTEN_TIMING_T prP2pExtListenTiming = (P_P2P_ATTRI_EXT_LISTEN_TIMING_T)NULL; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T)NULL; + PUINT_8 pucBuffer = NULL; + + ASSERT(prAdapter); + ASSERT(pucBuf); + + if (fgIsAssocFrame) { + return u4AttriLen; + } + + // TODO: For extend listen timing. + + prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; + + u4AttriLen = (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_EXT_LISTEN_TIMING); + + ASSERT(u2BufSize >= ((*pu2Offset) + (UINT_16)u4AttriLen)); + + pucBuffer = (PUINT_8)((UINT_32)pucBuf + + (UINT_32)(*pu2Offset)); + + ASSERT(pucBuffer); + + prP2pExtListenTiming = (P_P2P_ATTRI_EXT_LISTEN_TIMING_T)pucBuffer; + + prP2pExtListenTiming->ucId = P2P_ATTRI_ID_EXT_LISTEN_TIMING; + WLAN_SET_FIELD_16(&prP2pExtListenTiming->u2Length, P2P_ATTRI_MAX_LEN_EXT_LISTEN_TIMING); + WLAN_SET_FIELD_16(&prP2pExtListenTiming->u2AvailInterval, prP2pSpecificBssInfo->u2AvailabilityInterval); + WLAN_SET_FIELD_16(&prP2pExtListenTiming->u2AvailPeriod, prP2pSpecificBssInfo->u2AvailabilityPeriod); + + (*pu2Offset) += (UINT_16)u4AttriLen; + + return u4AttriLen; +} /* p2pFuncAppendAttriExtListenTiming */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_ie.c b/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_ie.c new file mode 100755 index 000000000000..8d85f7504511 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_ie.c @@ -0,0 +1,73 @@ + +#include "p2p_precomp.h" + + + +UINT_32 +p2pCalculate_IEForAssocReq ( + + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec + ) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo = (P_P2P_CONNECTION_REQ_INFO_T)NULL; + UINT_32 u4RetValue = 0; + + do { + ASSERT_BREAK((eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) && (prAdapter != NULL)); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + prConnReqInfo = &(prP2pFsmInfo->rConnReqInfo); + + u4RetValue = prConnReqInfo->u4BufLength; + + } +while (FALSE); + + return u4RetValue; +} /* p2pCalculate_IEForAssocReq */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to generate P2P IE for Beacon frame. +* +* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pGenerate_IEForAssocReq ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo = (P_P2P_CONNECTION_REQ_INFO_T)NULL; + PUINT_8 pucIEBuf = (PUINT_8)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + prConnReqInfo = &(prP2pFsmInfo->rConnReqInfo); + + pucIEBuf = (PUINT_8)((UINT_32)prMsduInfo->prPacket + (UINT_32)prMsduInfo->u2FrameLength); + + kalMemCopy(pucIEBuf, prConnReqInfo->aucIEBuf, prConnReqInfo->u4BufLength); + + prMsduInfo->u2FrameLength += prConnReqInfo->u4BufLength; + + } while (FALSE); + + return; + +} /* p2pGenerate_IEForAssocReq */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_rlm.c b/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_rlm.c new file mode 100755 index 000000000000..913429d20dba --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_rlm.c @@ -0,0 +1,1048 @@ +/* +** $Id: @(#) p2p_rlm.c@@ +*/ + +/*! \file "p2p_rlm.c" + \brief + +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "p2p_precomp.h" + +extern VOID +rlmSyncOperationParams ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo + ); + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Init AP Bss +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmBssInitForAP( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo + ) +{ + ENUM_BAND_T eBand; + UINT_8 ucChannel; + ENUM_CHNL_EXT_T eSCO; + + ASSERT(prAdapter); + ASSERT(prBssInfo); + + if (prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) { + return; + } + + /* Operation band, channel shall be ready before invoking this function. + * Bandwidth may be ready if other network is connected + */ + prBssInfo->fg40mBwAllowed = FALSE; + prBssInfo->fgAssoc40mBwAllowed = FALSE; + prBssInfo->eBssSCO = CHNL_EXT_SCN; + + if (RLM_AP_IS_BW_40_ALLOWED(prAdapter, prBssInfo)) { + /* In this case, the first BSS's SCO is 40MHz and known, so AP can + * apply 40MHz bandwidth, but the first BSS's SCO may be changed + * later if its Beacon lost timeout occurs + */ + if (cnmPreferredChannel(prAdapter, &eBand, &ucChannel, &eSCO) && + eSCO != CHNL_EXT_SCN && ucChannel == prBssInfo->ucPrimaryChannel && + eBand == prBssInfo->eBand) { + prBssInfo->eBssSCO = eSCO; + } + else if (cnmBss40mBwPermitted(prAdapter, prBssInfo->ucNetTypeIndex)) { + prBssInfo->eBssSCO = rlmDecideScoForAP(prAdapter, prBssInfo); + } + + if (prBssInfo->eBssSCO != CHNL_EXT_SCN) { + prBssInfo->fg40mBwAllowed = TRUE; + prBssInfo->fgAssoc40mBwAllowed = TRUE; + + prBssInfo->ucHtOpInfo1 = (UINT_8) + (((UINT_32) prBssInfo->eBssSCO) | HT_OP_INFO1_STA_CHNL_WIDTH); + + rlmUpdateBwByChListForAP(prAdapter, prBssInfo); + } + } + + DBGLOG(RLM, INFO, ("WLAN AP SCO=%d\n", prBssInfo->eBssSCO)); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief For probe response (GO, IBSS) and association response +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmRspGenerateObssScanIE ( + P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo + ) +{ + P_BSS_INFO_T prBssInfo; + P_IE_OBSS_SCAN_PARAM_T prObssScanIe; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + ASSERT(IS_NET_ACTIVE(prAdapter, prMsduInfo->ucNetworkType)); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; + ASSERT(prBssInfo); + + if (RLM_NET_IS_11N(prBssInfo) && !RLM_NET_IS_BOW(prBssInfo) && + prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT && + (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N)) && + prBssInfo->eBand == BAND_2G4 && + prBssInfo->eBssSCO != CHNL_EXT_SCN) { + + prObssScanIe = (P_IE_OBSS_SCAN_PARAM_T) + (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); + + /* Add 20/40 BSS coexistence IE */ + prObssScanIe->ucId = ELEM_ID_OBSS_SCAN_PARAMS; + prObssScanIe->ucLength = sizeof(IE_OBSS_SCAN_PARAM_T) - ELEM_HDR_LEN; + + prObssScanIe->u2ScanPassiveDwell = + dot11OBSSScanPassiveDwell; + prObssScanIe->u2ScanActiveDwell = + dot11OBSSScanActiveDwell; + prObssScanIe->u2TriggerScanInterval = + dot11BSSWidthTriggerScanInterval; + prObssScanIe->u2ScanPassiveTotalPerChnl = + dot11OBSSScanPassiveTotalPerChannel; + prObssScanIe->u2ScanActiveTotalPerChnl = + dot11OBSSScanActiveTotalPerChannel; + prObssScanIe->u2WidthTransDelayFactor = + dot11BSSWidthChannelTransitionDelayFactor; + prObssScanIe->u2ScanActivityThres = + dot11OBSSScanActivityThreshold; + + ASSERT(IE_SIZE(prObssScanIe) <= (ELEM_HDR_LEN+ ELEM_MAX_LEN_OBSS_SCAN)); + + prMsduInfo->u2FrameLength += IE_SIZE(prObssScanIe); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P GO. +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +rlmUpdateBwByChListForAP ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo + ) +{ + UINT_8 ucLevel; + BOOLEAN fgBwChange; + + ASSERT(prAdapter); + ASSERT(prBssInfo); + + fgBwChange = FALSE; + + if (prBssInfo->eBssSCO == CHNL_EXT_SCN) { + return fgBwChange; + } + + ucLevel = rlmObssChnlLevel(prBssInfo, prBssInfo->eBand, + prBssInfo->ucPrimaryChannel, prBssInfo->eBssSCO); + + if (ucLevel == CHNL_LEVEL0) { + /* Forced to 20MHz, so extended channel is SCN and STA width is zero */ + prBssInfo->fgObssActionForcedTo20M = TRUE; + + if (prBssInfo->ucHtOpInfo1 != (UINT_8) CHNL_EXT_SCN) { + prBssInfo->ucHtOpInfo1 = (UINT_8) CHNL_EXT_SCN; + fgBwChange = TRUE; + } + + cnmTimerStartTimer(prAdapter, &prBssInfo->rObssScanTimer, + OBSS_20_40M_TIMEOUT * MSEC_PER_SEC); + } + + /* Clear up all channel lists */ + prBssInfo->auc2G_20mReqChnlList[0] = 0; + prBssInfo->auc2G_NonHtChnlList[0] = 0; + prBssInfo->auc2G_PriChnlList[0] = 0; + prBssInfo->auc2G_SecChnlList[0] = 0; + prBssInfo->auc5G_20mReqChnlList[0] = 0; + prBssInfo->auc5G_NonHtChnlList[0] = 0; + prBssInfo->auc5G_PriChnlList[0] = 0; + prBssInfo->auc5G_SecChnlList[0] = 0; + + return fgBwChange; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmProcessPublicAction ( + P_ADAPTER_T prAdapter, + P_SW_RFB_T prSwRfb + ) +{ + P_ACTION_20_40_COEXIST_FRAME prRxFrame; + P_IE_20_40_COEXIST_T prCoexist; + P_IE_INTOLERANT_CHNL_REPORT_T prChnlReport; + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + PUINT_8 pucIE; + UINT_16 u2IELength, u2Offset; + UINT_8 i, j; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prRxFrame = (P_ACTION_20_40_COEXIST_FRAME) prSwRfb->pvHeader; + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + if (prRxFrame->ucAction != ACTION_PUBLIC_20_40_COEXIST || + !prStaRec || prStaRec->ucStaState != STA_STATE_3 || + prSwRfb->u2PacketLen < (WLAN_MAC_MGMT_HEADER_LEN + 5) || + HIF_RX_HDR_GET_NETWORK_IDX(prSwRfb->prHifRxHdr) != + NETWORK_TYPE_P2P_INDEX) { + return; + } + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; + ASSERT(prBssInfo); + + if (!IS_BSS_ACTIVE(prBssInfo) || + prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT || + prBssInfo->eBssSCO == CHNL_EXT_SCN) { + return; + } + + prCoexist = &prRxFrame->rBssCoexist; + if (prCoexist->ucData & (BSS_COEXIST_40M_INTOLERANT|BSS_COEXIST_20M_REQ)) { + ASSERT(prBssInfo->auc2G_20mReqChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_20mReqChnlList[0] && + i <= CHNL_LIST_SZ_2G; i++) { + if (prBssInfo->auc2G_20mReqChnlList[i] == + prBssInfo->ucPrimaryChannel) { + break; + } + } + if ((i > prBssInfo->auc2G_20mReqChnlList[0]) && + (i <= CHNL_LIST_SZ_2G)){ + prBssInfo->auc2G_20mReqChnlList[i] = prBssInfo->ucPrimaryChannel; + prBssInfo->auc2G_20mReqChnlList[0]++; + } + } + + /* Process intolerant channel report IE */ + pucIE = (PUINT_8) &prRxFrame->rChnlReport; + u2IELength = prSwRfb->u2PacketLen - (WLAN_MAC_MGMT_HEADER_LEN + 5); + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_20_40_INTOLERANT_CHNL_REPORT: + prChnlReport = (P_IE_INTOLERANT_CHNL_REPORT_T) pucIE; + + if (prChnlReport->ucLength <= 1) { + break; + } + + /* To do: process regulatory class. Now we assume 2.4G band */ + + for (j = 0; j < prChnlReport->ucLength - 1; j++) { + /* Update non-HT channel list */ + ASSERT(prBssInfo->auc2G_NonHtChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_NonHtChnlList[0] && + i <= CHNL_LIST_SZ_2G; i++) { + if (prBssInfo->auc2G_NonHtChnlList[i] == + prChnlReport->aucChannelList[j]) { + break; + } + } + if ((i > prBssInfo->auc2G_NonHtChnlList[0]) && + (i <= CHNL_LIST_SZ_2G)) { + prBssInfo->auc2G_NonHtChnlList[i] = + prChnlReport->aucChannelList[j]; + prBssInfo->auc2G_NonHtChnlList[0]++; + } + } + break; + + default: + break; + } + } /* end of IE_FOR_EACH */ + + if (rlmUpdateBwByChListForAP(prAdapter, prBssInfo)) { + bssUpdateBeaconContent(prAdapter, prBssInfo->ucNetTypeIndex); + rlmSyncOperationParams(prAdapter, prBssInfo); + } + + /* Check if OBSS scan exemption response should be sent */ + if (prCoexist->ucData & BSS_COEXIST_OBSS_SCAN_EXEMPTION_REQ) { + rlmObssScanExemptionRsp(prAdapter, prBssInfo, prSwRfb); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmProcessHtAction ( + P_ADAPTER_T prAdapter, + P_SW_RFB_T prSwRfb + ) +{ + P_ACTION_NOTIFY_CHNL_WIDTH_FRAME prRxFrame; + P_STA_RECORD_T prStaRec; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prRxFrame = (P_ACTION_NOTIFY_CHNL_WIDTH_FRAME) prSwRfb->pvHeader; + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + if (prRxFrame->ucAction != ACTION_HT_NOTIFY_CHANNEL_WIDTH || + !prStaRec || prStaRec->ucStaState != STA_STATE_3 || + prSwRfb->u2PacketLen < sizeof(ACTION_NOTIFY_CHNL_WIDTH_FRAME)) { + return; + } + + /* To do: depending regulation class 13 and 14 based on spec + * Note: (ucChannelWidth==1) shall restored back to original capability, + * not current setting to 40MHz BW here + */ + if (prRxFrame->ucChannelWidth == 0) { + prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_SUP_CHNL_WIDTH; + } + else if (prRxFrame->ucChannelWidth == 1) { + prStaRec->u2HtCapInfo |= HT_CAP_INFO_SUP_CHNL_WIDTH; + } + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmHandleObssStatusEventPkt ( + P_ADAPTER_T prAdapter, + P_EVENT_AP_OBSS_STATUS_T prObssStatus + ) +{ + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + ASSERT(prObssStatus); + ASSERT(prObssStatus->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX); + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prObssStatus->ucNetTypeIndex]; + ASSERT(prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT); + + prBssInfo->fgObssErpProtectMode = + (BOOLEAN) prObssStatus->ucObssErpProtectMode; + prBssInfo->eObssHtProtectMode = + (ENUM_HT_PROTECT_MODE_T) prObssStatus->ucObssHtProtectMode; + prBssInfo->eObssGfOperationMode = + (ENUM_GF_MODE_T) prObssStatus->ucObssGfOperationMode; + prBssInfo->fgObssRifsOperationMode = + (BOOLEAN) prObssStatus->ucObssRifsOperationMode; + prBssInfo->fgObssBeaconForcedTo20M = + (BOOLEAN) prObssStatus->ucObssBeaconForcedTo20M; + + /* Check if Beacon content need to be updated */ + rlmUpdateParamsForAP(prAdapter, prBssInfo, TRUE); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief It is only for AP mode in NETWORK_TYPE_P2P_INDEX. +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmUpdateParamsForAP ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + BOOLEAN fgUpdateBeacon + ) +{ + P_LINK_T prStaList; + P_STA_RECORD_T prStaRec; + BOOLEAN fgErpProtectMode, fgSta40mIntolerant; + BOOLEAN fgUseShortPreamble, fgUseShortSlotTime; + ENUM_HT_PROTECT_MODE_T eHtProtectMode; + ENUM_GF_MODE_T eGfOperationMode; + UINT_8 ucHtOpInfo1; + + ASSERT(prAdapter); + ASSERT(prBssInfo); + + if (!IS_BSS_ACTIVE(prBssInfo) || + prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) { + return; + } + + fgErpProtectMode = FALSE; + eHtProtectMode = HT_PROTECT_MODE_NONE; + eGfOperationMode = GF_MODE_NORMAL; + fgSta40mIntolerant = FALSE; + fgUseShortPreamble = prBssInfo->fgIsShortPreambleAllowed; + fgUseShortSlotTime = TRUE; + ucHtOpInfo1 = (UINT_8) CHNL_EXT_SCN; + + prStaList = &prBssInfo->rStaRecOfClientList; + + LINK_FOR_EACH_ENTRY(prStaRec, prStaList, rLinkEntry, STA_RECORD_T) { + ASSERT(prStaRec); + if (prStaRec->fgIsInUse && prStaRec->ucStaState == STA_STATE_3 && + prStaRec->ucNetTypeIndex == prBssInfo->ucNetTypeIndex) { + if (!(prStaRec->ucPhyTypeSet & + (PHY_TYPE_SET_802_11GN | PHY_TYPE_SET_802_11A))) { + /* B-only mode, so mode 1 (ERP protection) */ + fgErpProtectMode = TRUE; + } + + if (!(prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N)) { + /* BG-only or A-only */ + eHtProtectMode = HT_PROTECT_MODE_NON_HT; + } + else if (!(prStaRec->u2HtCapInfo & HT_CAP_INFO_SUP_CHNL_WIDTH)) { + /* 20MHz-only */ + if (eHtProtectMode == HT_PROTECT_MODE_NONE) { + eHtProtectMode = HT_PROTECT_MODE_20M; + } + } + + if (!(prStaRec->u2HtCapInfo & HT_CAP_INFO_HT_GF)) { + eGfOperationMode = GF_MODE_PROTECT; + } + + if (!(prStaRec->u2CapInfo & CAP_INFO_SHORT_PREAMBLE)) { + fgUseShortPreamble = FALSE; + } + + if (!(prStaRec->u2CapInfo & CAP_INFO_SHORT_SLOT_TIME)) { + fgUseShortSlotTime = FALSE; + } + + if (prStaRec->u2HtCapInfo & HT_CAP_INFO_40M_INTOLERANT) { + fgSta40mIntolerant = TRUE; + } + } + } /* end of LINK_FOR_EACH_ENTRY */ + + /* Check if HT operation IE about 20/40M bandwidth shall be updated */ + if (prBssInfo->eBssSCO != CHNL_EXT_SCN) { + if (/*!LINK_IS_EMPTY(prStaList) && */ !fgSta40mIntolerant && + !prBssInfo->fgObssActionForcedTo20M && + !prBssInfo->fgObssBeaconForcedTo20M) { + + ucHtOpInfo1 = (UINT_8) + (((UINT_32) prBssInfo->eBssSCO) | HT_OP_INFO1_STA_CHNL_WIDTH); + } + } + + /* Check if any new parameter may be updated */ + if (prBssInfo->fgErpProtectMode != fgErpProtectMode || + prBssInfo->eHtProtectMode != eHtProtectMode || + prBssInfo->eGfOperationMode != eGfOperationMode || + prBssInfo->ucHtOpInfo1 != ucHtOpInfo1 || + prBssInfo->fgUseShortPreamble != fgUseShortPreamble || + prBssInfo->fgUseShortSlotTime != fgUseShortSlotTime) { + + prBssInfo->fgErpProtectMode = fgErpProtectMode; + prBssInfo->eHtProtectMode = eHtProtectMode; + prBssInfo->eGfOperationMode = eGfOperationMode; + prBssInfo->ucHtOpInfo1 = ucHtOpInfo1; + prBssInfo->fgUseShortPreamble = fgUseShortPreamble; + prBssInfo->fgUseShortSlotTime = fgUseShortSlotTime; + + if (fgUseShortSlotTime) { + prBssInfo->u2CapInfo |= CAP_INFO_SHORT_SLOT_TIME; + } + else { + prBssInfo->u2CapInfo &= ~CAP_INFO_SHORT_SLOT_TIME; + } + + rlmSyncOperationParams(prAdapter, prBssInfo); + fgUpdateBeacon = TRUE; + } + + /* Update Beacon content if related IE content is changed */ + if (fgUpdateBeacon) { + bssUpdateBeaconContent(prAdapter, prBssInfo->ucNetTypeIndex); + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Initial the channel list from the domain information. +* This function is called after P2P initial and Domain information changed. +* Make sure the device is disconnected while changing domain information. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return boolean value if probe response frame is +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmFuncInitialChannelList ( + IN P_ADAPTER_T prAdapter + ) +{ + P_P2P_CONNECTION_SETTINGS_T prP2pConnSetting = (P_P2P_CONNECTION_SETTINGS_T)NULL; + P_DOMAIN_INFO_ENTRY prDomainInfoEntry = (P_DOMAIN_INFO_ENTRY)NULL; + P_DOMAIN_SUBBAND_INFO prDomainSubBand = (P_DOMAIN_SUBBAND_INFO)NULL; + P_CHANNEL_ENTRY_FIELD_T prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T)NULL; + UINT_32 u4Idx = 0, u4IdxII = 0; + UINT_8 ucBufferSize = P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE; +#if 0 + UINT_8 ucSocialChnlSupport = 0, ucAutoChnl = 0; +#endif + + do { + ASSERT_BREAK(prAdapter != NULL); + + prP2pConnSetting = prAdapter->rWifiVar.prP2PConnSettings; +#if 0 + ucAutoChnl = prP2pConnSetting->ucOperatingChnl; +#endif + + prDomainInfoEntry = rlmDomainGetDomainInfo(prAdapter); + + ASSERT_BREAK((prDomainInfoEntry != NULL) && (prP2pConnSetting != NULL)); + + prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T)prP2pConnSetting->aucChannelEntriesField; + + for (u4Idx = 0; u4Idx < MAX_SUBBAND_NUM; u4Idx++) { + prDomainSubBand = &prDomainInfoEntry->rSubBand[u4Idx]; + + + if (((prDomainSubBand->ucBand == BAND_5G) && (!prAdapter->fgEnable5GBand)) || + (prDomainSubBand->ucBand == BAND_NULL)) { + continue; + } + + + if (ucBufferSize < (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryField->ucNumberOfChannels)) { + /* Buffer is not enough to include all supported channels. */ + break; // for + } + + prChannelEntryField->ucRegulatoryClass = prDomainSubBand->ucRegClass; + prChannelEntryField->ucNumberOfChannels = prDomainSubBand->ucNumChannels; + + for (u4IdxII = 0; u4IdxII < prDomainSubBand->ucNumChannels; u4IdxII++) { + prChannelEntryField->aucChannelList[u4IdxII] = prDomainSubBand->ucFirstChannelNum + + (u4IdxII * prDomainSubBand->ucChannelSpan); + +#if 0 + switch (prChannelEntryField->aucChannelList[u4IdxII]) { + case 1: + ucSocialChnlSupport = 1; + break; + case 6: + ucSocialChnlSupport = 6; + break; + case 11: + ucSocialChnlSupport = 11; + break; + default: + break; + } + +#endif + } + + ucBufferSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryField->ucNumberOfChannels); + + prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T)((UINT_32)prChannelEntryField + + P2P_ATTRI_LEN_CHANNEL_ENTRY + + (UINT_32)prChannelEntryField->ucNumberOfChannels); + + } + +#if 0 + if (prP2pConnSetting->ucListenChnl == 0) { + prP2pConnSetting->ucListenChnl = P2P_DEFAULT_LISTEN_CHANNEL; + + if (ucSocialChnlSupport != 0) { + /* 1. User Not Set LISTEN channel. + * 2. Social channel is not empty. + */ + prP2pConnSetting->ucListenChnl = ucSocialChnlSupport; + } + } + +#endif + + // TODO: 20110921 frog - + /* If LISTEN channel is not set, + * a random supported channel would be set. + * If no social channel is supported, DEFAULT channel would be set. + */ + + prP2pConnSetting->ucRfChannelListSize = P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE - ucBufferSize; + +#if 0 + if (prP2pConnSetting->ucOperatingChnl == 0) { /* User not set OPERATE channel. */ + + if (scnQuerySparseChannel(prAdapter, NULL, &ucAutoChnl)) { + break; // while + } + + ucBufferSize = prP2pConnSetting->ucRfChannelListSize; + + prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T)prP2pConnSetting->aucChannelEntriesField; + + while (ucBufferSize != 0) { + if (prChannelEntryField->ucNumberOfChannels != 0) { + ucAutoChnl = prChannelEntryField->aucChannelList[0]; + break; // while + } + + else { + prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T)((UINT_32)prChannelEntryField + + P2P_ATTRI_LEN_CHANNEL_ENTRY + + (UINT_32)prChannelEntryField->ucNumberOfChannels); + + ucBufferSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryField->ucNumberOfChannels); + } + + } + + + + } + +#endif + /* We assume user would not set a channel not in the channel list. + * If so, the operating channel still depends on target deivce supporting capability. + */ + + // TODO: 20110921 frog - + /* If the Operating channel is not set, a channel from supported channel list is set automatically. + * If there is no supported channel in channel list, a DEFAULT channel is set. + */ + + } while (FALSE); + +#if 0 + prP2pConnSetting->ucOperatingChnl = ucAutoChnl; +#endif + return; +} /* rlmFuncInitialChannelList */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Find a common channel list from the local channel list info & target channel list info. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return boolean value if probe response frame is +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmFuncCommonChannelList ( + IN P_ADAPTER_T prAdapter, + IN P_CHANNEL_ENTRY_FIELD_T prChannelEntryII, + IN UINT_8 ucChannelListSize + ) +{ + P_P2P_CONNECTION_SETTINGS_T prP2pConnSetting = (P_P2P_CONNECTION_SETTINGS_T)NULL; + P_CHANNEL_ENTRY_FIELD_T prChannelEntryI = (P_CHANNEL_ENTRY_FIELD_T)NULL, prChannelEntryIII = (P_CHANNEL_ENTRY_FIELD_T)NULL; + UINT_8 aucCommonChannelList[P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE]; + UINT_8 ucOriChnlSize = 0, ucNewChnlSize = 0; + + + do { + + ASSERT_BREAK(prAdapter != NULL); + + prP2pConnSetting = prAdapter->rWifiVar.prP2PConnSettings; + + prChannelEntryIII = (P_CHANNEL_ENTRY_FIELD_T)aucCommonChannelList; + + while (ucChannelListSize > 0) { + + prChannelEntryI = (P_CHANNEL_ENTRY_FIELD_T)prP2pConnSetting->aucChannelEntriesField; + ucOriChnlSize = prP2pConnSetting->ucRfChannelListSize; + + while (ucOriChnlSize > 0) { + if (prChannelEntryI->ucRegulatoryClass == prChannelEntryII->ucRegulatoryClass) { + prChannelEntryIII->ucRegulatoryClass = prChannelEntryI->ucRegulatoryClass; + // TODO: Currently we assume that the regulatory class the same, the channels are the same. + kalMemCopy(prChannelEntryIII->aucChannelList, prChannelEntryII->aucChannelList, prChannelEntryII->ucNumberOfChannels); + prChannelEntryIII->ucNumberOfChannels = prChannelEntryII->ucNumberOfChannels; + + ucNewChnlSize += P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryIII->ucNumberOfChannels; + + prChannelEntryIII = (P_CHANNEL_ENTRY_FIELD_T)((UINT_32)prChannelEntryIII + + P2P_ATTRI_LEN_CHANNEL_ENTRY + + (UINT_32)prChannelEntryIII->ucNumberOfChannels); + } + + ucOriChnlSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryI->ucNumberOfChannels); + + prChannelEntryI = (P_CHANNEL_ENTRY_FIELD_T)((UINT_32)prChannelEntryI + + P2P_ATTRI_LEN_CHANNEL_ENTRY + + (UINT_32)prChannelEntryI->ucNumberOfChannels); + + + } + + + ucChannelListSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryII->ucNumberOfChannels); + + prChannelEntryII = (P_CHANNEL_ENTRY_FIELD_T)((UINT_32)prChannelEntryII + + P2P_ATTRI_LEN_CHANNEL_ENTRY + + (UINT_32)prChannelEntryII->ucNumberOfChannels); + + + } + + + kalMemCopy(prP2pConnSetting->aucChannelEntriesField, aucCommonChannelList, ucNewChnlSize); + prP2pConnSetting->ucRfChannelListSize = ucNewChnlSize; + + } while (FALSE); + + return; +} /* rlmFuncCommonChannelList */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 +rlmFuncFindOperatingClass ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucChannelNum + ) +{ + UINT_8 ucRegulatoryClass = 0, ucBufferSize = 0; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSetting = (P_P2P_CONNECTION_SETTINGS_T)NULL; + P_CHANNEL_ENTRY_FIELD_T prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T)NULL; + UINT_32 u4Idx = 0; + + do { + ASSERT_BREAK(prAdapter != NULL); + + prP2pConnSetting = prAdapter->rWifiVar.prP2PConnSettings; + ucBufferSize = prP2pConnSetting->ucRfChannelListSize; + prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T)prP2pConnSetting->aucChannelEntriesField; + + while (ucBufferSize != 0) { + + for (u4Idx = 0; u4Idx < prChannelEntryField->ucNumberOfChannels; u4Idx++) { + if (prChannelEntryField->aucChannelList[u4Idx] == ucChannelNum) { + ucRegulatoryClass = prChannelEntryField->ucRegulatoryClass; + break; + } + + } + + + if (ucRegulatoryClass != 0) { + break; //while + } + else { + prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T)((UINT_32)prChannelEntryField + + P2P_ATTRI_LEN_CHANNEL_ENTRY + + (UINT_32)prChannelEntryField->ucNumberOfChannels); + + ucBufferSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryField->ucNumberOfChannels); + } + + } + + + } while (FALSE); + + return ucRegulatoryClass; +} /* rlmFuncFindOperatingClass */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +rlmFuncFindAvailableChannel ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucCheckChnl, + IN PUINT_8 pucSuggestChannel, + IN BOOLEAN fgIsSocialChannel, + IN BOOLEAN fgIsDefaultChannel + ) +{ + BOOLEAN fgIsResultAvailable = FALSE; + P_CHANNEL_ENTRY_FIELD_T prChannelEntry = (P_CHANNEL_ENTRY_FIELD_T)NULL; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSetting = (P_P2P_CONNECTION_SETTINGS_T)NULL; + UINT_8 ucBufferSize = 0, ucIdx = 0, ucChannelSelected = 0; + + do { + ASSERT_BREAK(prAdapter != NULL); + + if (fgIsDefaultChannel) { + ucChannelSelected = P2P_DEFAULT_LISTEN_CHANNEL; + } + + + prP2pConnSetting = prAdapter->rWifiVar.prP2PConnSettings; + ucBufferSize = prP2pConnSetting->ucRfChannelListSize; + prChannelEntry = (P_CHANNEL_ENTRY_FIELD_T)prP2pConnSetting->aucChannelEntriesField; + + while ((ucBufferSize != 0) && (!fgIsResultAvailable)) { + + for (ucIdx = 0; ucIdx < prChannelEntry->ucNumberOfChannels; ucIdx++) { + if ((!fgIsSocialChannel) || + (prChannelEntry->aucChannelList[ucIdx] == 1) || + (prChannelEntry->aucChannelList[ucIdx] == 6) || + (prChannelEntry->aucChannelList[ucIdx] == 11)) { + + if (prChannelEntry->aucChannelList[ucIdx] <= 11) { + /* 2.4G. */ + ucChannelSelected = prChannelEntry->aucChannelList[ucIdx]; + } + else if ((prChannelEntry->aucChannelList[ucIdx] < 52) && + (prChannelEntry->aucChannelList[ucIdx] > 14)) { + /* 2.4G + 5G. */ + ucChannelSelected = prChannelEntry->aucChannelList[ucIdx]; + } + + if (ucChannelSelected == ucCheckChnl) { + fgIsResultAvailable = TRUE; + break; + } + } + + } + + + ucBufferSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntry->ucNumberOfChannels); + + prChannelEntry = (P_CHANNEL_ENTRY_FIELD_T)((UINT_32)prChannelEntry + + P2P_ATTRI_LEN_CHANNEL_ENTRY + + (UINT_32)prChannelEntry->ucNumberOfChannels); + + } + + + + if ((!fgIsResultAvailable) && (pucSuggestChannel != NULL)) { + DBGLOG(P2P, TRACE, ("The request channel %d is not available, sugguested channel:%d\n", ucCheckChnl, ucChannelSelected)); + // Given a suggested channel. + *pucSuggestChannel = ucChannelSelected; + } + + + } while (FALSE); + + return fgIsResultAvailable; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +ENUM_CHNL_EXT_T +rlmDecideScoForAP ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo + ) +{ + P_DOMAIN_SUBBAND_INFO prSubband; + P_DOMAIN_INFO_ENTRY prDomainInfo; + UINT_8 ucSecondChannel, i, j; + ENUM_CHNL_EXT_T eSCO; + + eSCO = CHNL_EXT_SCN; + + if (prBssInfo->eBand == BAND_2G4) { + if (prBssInfo->ucPrimaryChannel != 14) { + eSCO = (prBssInfo->ucPrimaryChannel > 7) ? + CHNL_EXT_SCB : CHNL_EXT_SCA; + } + } + else { + prDomainInfo = rlmDomainGetDomainInfo(prAdapter); + ASSERT(prDomainInfo); + + for (i = 0; i < MAX_SUBBAND_NUM; i++) { + prSubband = &prDomainInfo->rSubBand[i]; + if (prSubband->ucBand == prBssInfo->eBand) { + for (j = 0; j < prSubband->ucNumChannels; j++) { + if ((prSubband->ucFirstChannelNum + j*prSubband->ucChannelSpan) + == prBssInfo->ucPrimaryChannel) { + eSCO = (j & 1) ? CHNL_EXT_SCB : CHNL_EXT_SCA; + break; + } + } + + if (j < prSubband->ucNumChannels) { + break; /* Found */ + } + } + } + } + + /* Check if it is boundary channel and 40MHz BW is permitted */ + if (eSCO != CHNL_EXT_SCN) { + ucSecondChannel = (eSCO == CHNL_EXT_SCA) ? + (prBssInfo->ucPrimaryChannel+ 4) : (prBssInfo->ucPrimaryChannel- 4); + + if (!rlmDomainIsLegalChannel(prAdapter, prBssInfo->eBand, ucSecondChannel)){ + eSCO = CHNL_EXT_SCN; + } + } + + return eSCO; +} + diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_rlm_obss.c b/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_rlm_obss.c new file mode 100755 index 000000000000..f4ada2e6f27e --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_rlm_obss.c @@ -0,0 +1,414 @@ +/* +** $Id: @(#) gl_p2p_cfg80211.c@@ +*/ + +/*! \file gl_p2p_cfg80211.c + \brief Main routines of Linux driver interface for Wi-Fi Direct + using cfg80211 interface + + This file contains the main routines of Linux driver for MediaTek Inc. 802.11 + Wireless LAN Adapters. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + + +#include "p2p_precomp.h" + + +static UINT_8 +rlmObssChnlLevelIn2G4 ( + P_BSS_INFO_T prBssInfo, + UINT_8 ucPriChannel, + ENUM_CHNL_EXT_T eExtend + ); + +static UINT_8 +rlmObssChnlLevelIn5G ( + P_BSS_INFO_T prBssInfo, + UINT_8 ucPriChannel, + ENUM_CHNL_EXT_T eExtend + ); + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Different concurrent network has itself channel lists, and +* concurrent networks should have been recorded in channel lists. +* If role of active P2P is GO, assume associated AP of AIS will +* record our Beacon for P2P GO because of same channel. +* +* Note: If we have scenario of different channel in the future, +* the internal FW communication channel shall be established. +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 +rlmObssChnlLevel ( + P_BSS_INFO_T prBssInfo, + ENUM_BAND_T eBand, + UINT_8 ucPriChannel, + ENUM_CHNL_EXT_T eExtend + ) +{ + UINT_8 ucChannelLevel; + + ASSERT(prBssInfo); + + if (eBand == BAND_2G4) { + ucChannelLevel = rlmObssChnlLevelIn2G4(prBssInfo, ucPriChannel,eExtend); + + /* (TBD) If concurrent networks permit different channel, extra + * channel judgement should be added. Please refer to + * previous version of this file. + */ + } + else if (eBand == BAND_5G) { + ucChannelLevel = rlmObssChnlLevelIn5G(prBssInfo, ucPriChannel,eExtend); + + /* (TBD) If concurrent networks permit different channel, extra + * channel judgement should be added. Please refer to + * previous version of this file. + */ + } + else { + ucChannelLevel = CHNL_LEVEL0; + } + + return ucChannelLevel; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +static UINT_8 +rlmObssChnlLevelIn2G4 ( + P_BSS_INFO_T prBssInfo, + UINT_8 ucPriChannel, + ENUM_CHNL_EXT_T eExtend + ) +{ + UINT_8 i, ucChannelLevel; + UINT_8 ucSecChannel, ucCenterChannel; + UINT_8 ucAffectedChnl_L, ucAffectedChnl_H; + + ASSERT(prBssInfo); + + ucChannelLevel = CHNL_LEVEL2; + + /* Calculate center channel for 2.4G band */ + if (eExtend == CHNL_EXT_SCA) { + ucCenterChannel = ucPriChannel + 2; + ucSecChannel = ucPriChannel + 4; + } + else if (eExtend == CHNL_EXT_SCB) { + ucCenterChannel = ucPriChannel - 2; + ucSecChannel = ucPriChannel - 4; + } + else { + return CHNL_LEVEL0; + } + ASSERT(ucCenterChannel >= 1 && ucCenterChannel <= 14); + + /* Calculated low/upper channels in affected freq range */ + ucAffectedChnl_L = (ucCenterChannel <= AFFECTED_CHNL_OFFSET) ? + 1 : (ucCenterChannel - AFFECTED_CHNL_OFFSET); + + ucAffectedChnl_H = (ucCenterChannel >= (14 - AFFECTED_CHNL_OFFSET)) ? + 14 : (ucCenterChannel + AFFECTED_CHNL_OFFSET); + + + /* Check intolerant (Non-HT) channel list */ + ASSERT(prBssInfo->auc2G_NonHtChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_NonHtChnlList[0] && + i <= CHNL_LIST_SZ_2G; i++) { + if ((prBssInfo->auc2G_NonHtChnlList[i] >= ucAffectedChnl_L && + prBssInfo->auc2G_NonHtChnlList[i] <= ucAffectedChnl_H) && + prBssInfo->auc2G_NonHtChnlList[i] != ucPriChannel) { + + ucChannelLevel = CHNL_LEVEL0; + goto L_2G4_level_end; + } + } + + /* Check 20M BW request channel list */ + ASSERT(prBssInfo->auc2G_20mReqChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_20mReqChnlList[0] && + i <= CHNL_LIST_SZ_2G; i++) { + if ((prBssInfo->auc2G_20mReqChnlList[i] >= ucAffectedChnl_L && + prBssInfo->auc2G_20mReqChnlList[i] <= ucAffectedChnl_H)) { + + ucChannelLevel = CHNL_LEVEL0; + goto L_2G4_level_end; + } + } + + /* Check 2.4G primary channel list */ + ASSERT(prBssInfo->auc2G_PriChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_PriChnlList[0] && + i <= CHNL_LIST_SZ_2G; i++) { + if ((prBssInfo->auc2G_PriChnlList[i] >= ucAffectedChnl_L && + prBssInfo->auc2G_PriChnlList[i] <= ucAffectedChnl_H) && + prBssInfo->auc2G_PriChnlList[i] != ucPriChannel) { + + ucChannelLevel = CHNL_LEVEL0; + goto L_2G4_level_end; + } + } + + /* Check 2.4G secondary channel list */ + ASSERT(prBssInfo->auc2G_SecChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_SecChnlList[0] && + i <= CHNL_LIST_SZ_2G; i++) { + if ((prBssInfo->auc2G_SecChnlList[i] >= ucAffectedChnl_L && + prBssInfo->auc2G_SecChnlList[i] <= ucAffectedChnl_H) && + prBssInfo->auc2G_SecChnlList[i] != ucSecChannel) { + + ucChannelLevel = CHNL_LEVEL0; + goto L_2G4_level_end; + } + } + +L_2G4_level_end: + + return ucChannelLevel; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +static UINT_8 +rlmObssChnlLevelIn5G ( + P_BSS_INFO_T prBssInfo, + UINT_8 ucPriChannel, + ENUM_CHNL_EXT_T eExtend + ) +{ + UINT_8 i, ucChannelLevel; + UINT_8 ucSecChannel; + + ASSERT(prBssInfo); + + ucChannelLevel = CHNL_LEVEL2; + + /* Calculate center channel for 2.4G band */ + if (eExtend == CHNL_EXT_SCA) { + ucSecChannel = ucPriChannel + 4; + } + else if (eExtend == CHNL_EXT_SCB) { + ucSecChannel = ucPriChannel - 4; + } + else { + return CHNL_LEVEL0; + } + ASSERT(ucSecChannel >= 36); + + /* Check 5G primary channel list */ + ASSERT(prBssInfo->auc5G_PriChnlList[0] <= CHNL_LIST_SZ_5G); + for (i = 1; i <= prBssInfo->auc5G_PriChnlList[0] && + i <= CHNL_LIST_SZ_5G; i++) { + if (prBssInfo->auc5G_PriChnlList[i] == ucSecChannel) { + + ucChannelLevel = CHNL_LEVEL0; + goto L_5G_level_end; + } + else if (prBssInfo->auc5G_PriChnlList[i] == ucPriChannel) { + ucChannelLevel = CHNL_LEVEL1; + } + } + + /* Check non-HT channel list */ + ASSERT(prBssInfo->auc5G_NonHtChnlList[0] <= CHNL_LIST_SZ_5G); + for (i = 1; i <= prBssInfo->auc5G_NonHtChnlList[0] && + i <= CHNL_LIST_SZ_5G; i++) { + if (prBssInfo->auc5G_NonHtChnlList[i] == ucSecChannel) { + + ucChannelLevel = CHNL_LEVEL0; + goto L_5G_level_end; + } + else if (prBssInfo->auc5G_NonHtChnlList[i] == ucPriChannel) { + ucChannelLevel = CHNL_LEVEL1; + } + } + + /* Check secondary channel list */ + ASSERT(prBssInfo->auc5G_SecChnlList[0] <= CHNL_LIST_SZ_5G); + for (i = 1; i <= prBssInfo->auc5G_SecChnlList[0] && + i <= CHNL_LIST_SZ_5G; i++) { + if (prBssInfo->auc5G_SecChnlList[i] == ucPriChannel) { + + ucChannelLevel = CHNL_LEVEL0; + goto L_5G_level_end; + } + } + +L_5G_level_end: + + return ucChannelLevel; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmObssScanExemptionRsp ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_SW_RFB_T prSwRfb + ) +{ + P_MSDU_INFO_T prMsduInfo; + P_ACTION_20_40_COEXIST_FRAME prTxFrame; + + /* To do: need an algorithm to do judgement. Now always reject request */ + + prMsduInfo = (P_MSDU_INFO_T) + cnmMgtPktAlloc(prAdapter, PUBLIC_ACTION_MAX_LEN); + if (prMsduInfo == NULL) { + return; + } + + DBGLOG(RLM, INFO, ("Send 20/40 coexistence rsp frame!\n")); + + prTxFrame = (P_ACTION_20_40_COEXIST_FRAME) prMsduInfo->prPacket; + + prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; + COPY_MAC_ADDR(prTxFrame->aucDestAddr, + ((P_ACTION_20_40_COEXIST_FRAME) prSwRfb->pvHeader)->aucSrcAddr); + COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); + COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); + + prTxFrame->ucCategory = CATEGORY_PUBLIC_ACTION; + prTxFrame->ucAction = ACTION_PUBLIC_20_40_COEXIST; + + /* To do: find correct algorithm */ + prTxFrame->rBssCoexist.ucId = ELEM_ID_20_40_BSS_COEXISTENCE; + prTxFrame->rBssCoexist.ucLength = 1; + prTxFrame->rBssCoexist.ucData = 0; + + ASSERT((WLAN_MAC_HEADER_LEN + 5) <= PUBLIC_ACTION_MAX_LEN); + + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; + prMsduInfo->ucStaRecIndex =prSwRfb->ucStaRecIdx; + prMsduInfo->ucNetworkType = prBssInfo->ucNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_HTC_LEN + 5; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = NULL; + prMsduInfo->fgIsBasicRate = FALSE; + + /* Send them to HW queue */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); +} + + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_scan.c b/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_scan.c new file mode 100755 index 000000000000..0d7337286127 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_scan.c @@ -0,0 +1,865 @@ +/* +** $Id: @(#) p2p_scan.c@@ +*/ + +/*! \file "p2p_scan.c" + \brief This file defines the p2p scan profile and the processing function of + scan result for SCAN Module. + + The SCAN Profile selection is part of SCAN MODULE and responsible for defining + SCAN Parameters - e.g. MIN_CHANNEL_TIME, number of scan channels. + In this file we also define the process of SCAN Result including adding, searching + and removing SCAN record from the list. +*/ + + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "p2p_precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +P_P2P_DEVICE_DESC_T +scanSearchTargetP2pDesc ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 aucDeviceID[], + IN PP_BSS_DESC_T pprBssDesc + ) +{ + + P_P2P_DEVICE_DESC_T prTargetP2pDesc = (P_P2P_DEVICE_DESC_T)NULL; + P_SCAN_INFO_T prScanInfo = (P_SCAN_INFO_T)NULL; + P_LINK_T prBSSDescList; + P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T)NULL; + + + ASSERT(prAdapter); + ASSERT(aucDeviceID); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prBSSDescList = &prScanInfo->rBSSDescList; + + //4 <1> The outer loop to search for a candidate. + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { + + /* Loop for each prBssDesc */ + prTargetP2pDesc = scanFindP2pDeviceDesc(prAdapter, + prBssDesc, + aucDeviceID, + TRUE, + FALSE); + + if (prTargetP2pDesc != NULL) { + break; + } + } + + if ((pprBssDesc) && (prTargetP2pDesc != NULL)) { + /* Only valid if prTargetP2pDesc is not NULL. */ + *pprBssDesc = prBssDesc; + } + + return prTargetP2pDesc; +} /* scanSearchTargetP2pDesc */ + + + + +VOID +scanInvalidAllP2pClientDevice ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc + ) +{ + P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T)NULL; + P_P2P_DEVICE_DESC_T prTargetDesc = (P_P2P_DEVICE_DESC_T)NULL; + + LINK_FOR_EACH(prLinkEntry, &prBssDesc->rP2pDeviceList) { + prTargetDesc = LINK_ENTRY(prLinkEntry, P2P_DEVICE_DESC_T, rLinkEntry); + + if (prTargetDesc->fgDevInfoValid) { + prTargetDesc->fgDevInfoValid = FALSE; + } + } + + return; +} /* scanRenewP2pClientDevice */ + +VOID +scanRemoveInvalidP2pClientDevice ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc + ) +{ + P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T)NULL, prNexEntry = (P_LINK_ENTRY_T)NULL; + P_P2P_DEVICE_DESC_T prTargetDesc = (P_P2P_DEVICE_DESC_T)NULL; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T)NULL; + + prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + + LINK_FOR_EACH_SAFE(prLinkEntry, prNexEntry, &prBssDesc->rP2pDeviceList) { + prTargetDesc = LINK_ENTRY(prLinkEntry, P2P_DEVICE_DESC_T, rLinkEntry); + + if (!prTargetDesc->fgDevInfoValid) { + LINK_REMOVE_KNOWN_ENTRY(&prBssDesc->rP2pDeviceList, prLinkEntry); + if ((prP2pConnSettings) && + (prP2pConnSettings->prTargetP2pDesc == prTargetDesc)) { + prP2pConnSettings->prTargetP2pDesc = NULL; + } + kalMemFree(prTargetDesc, VIR_MEM_TYPE, sizeof(P2P_DEVICE_DESC_T)); + } + } + + return; +} /* scanRenewP2pClientDevice */ + + + +P_P2P_DEVICE_DESC_T +scanFindP2pDeviceDesc ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc, + IN UINT_8 aucMacAddr[], + IN BOOLEAN fgIsDeviceAddr, + IN BOOLEAN fgAddIfNoFound + ) +{ + + P_P2P_DEVICE_DESC_T prTargetDesc = (P_P2P_DEVICE_DESC_T)NULL; + P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && + (prBssDesc != NULL) && + (aucMacAddr != NULL)); + + LINK_FOR_EACH(prLinkEntry, &prBssDesc->rP2pDeviceList) { + prTargetDesc = LINK_ENTRY(prLinkEntry, P2P_DEVICE_DESC_T, rLinkEntry); + + if (fgIsDeviceAddr) { + if (EQUAL_MAC_ADDR(prTargetDesc->aucDeviceAddr, aucMacAddr)) { + break; + } + } + else { + if (EQUAL_MAC_ADDR(prTargetDesc->aucInterfaceAddr, aucMacAddr)) { + break; + } + } + + prTargetDesc = NULL; + } + + if ((fgAddIfNoFound) && (prTargetDesc == NULL)) { + /* Target Not Found. */ + // TODO: Use memory pool in the future. + prTargetDesc = kalMemAlloc(sizeof(P2P_DEVICE_DESC_T), VIR_MEM_TYPE); + + if (prTargetDesc) { + kalMemZero(prTargetDesc, sizeof(P2P_DEVICE_DESC_T)); + LINK_ENTRY_INITIALIZE(&(prTargetDesc->rLinkEntry)); + COPY_MAC_ADDR(prTargetDesc->aucDeviceAddr, aucMacAddr); + LINK_INSERT_TAIL(&prBssDesc->rP2pDeviceList, &prTargetDesc->rLinkEntry); + prTargetDesc->fgDevInfoValid = TRUE; + } + else { + ASSERT(FALSE); + } + } + + } while (FALSE); + + return prTargetDesc; +} /* scanFindP2pDeviceDesc */ + + +P_P2P_DEVICE_DESC_T +scanGetP2pDeviceDesc ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc + ) +{ + + P_P2P_DEVICE_DESC_T prTargetDesc = (P_P2P_DEVICE_DESC_T)NULL; + + ASSERT(prAdapter); + ASSERT(prBssDesc); + + if (prBssDesc->prP2pDesc == NULL) { + + prTargetDesc = kalMemAlloc(sizeof(P2P_DEVICE_DESC_T), VIR_MEM_TYPE); + + if (prTargetDesc) { + kalMemZero(prTargetDesc, sizeof(P2P_DEVICE_DESC_T)); + LINK_ENTRY_INITIALIZE(&(prTargetDesc->rLinkEntry)); + LINK_INSERT_TAIL(&prBssDesc->rP2pDeviceList, &prTargetDesc->rLinkEntry); + prTargetDesc->fgDevInfoValid = TRUE; + prBssDesc->prP2pDesc = prTargetDesc; + /* We are not sure the SrcAddr is Device Address or Interface Address. */ + COPY_MAC_ADDR(prTargetDesc->aucDeviceAddr, prBssDesc->aucSrcAddr); + COPY_MAC_ADDR(prTargetDesc->aucInterfaceAddr, prBssDesc->aucSrcAddr); + } + else { + + ASSERT(FALSE); + } + } + else { + prTargetDesc = prBssDesc->prP2pDesc; + } + + + return prTargetDesc; + +} /* scanFindP2pDeviceDesc */ + + +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* @brief Convert the Beacon or ProbeResp Frame in SW_RFB_T to Event Packet +* +* @param[in] prSwRfb Pointer to the receiving SW_RFB_T structure. +* +* @retval WLAN_STATUS_SUCCESS It is a valid Scan Result and been sent to the host. +* @retval WLAN_STATUS_FAILURE It is not a valid Scan Result. +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +scanUpdateP2pDeviceDesc ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc + ) +{ + P_P2P_DEVICE_DESC_T prP2pDesc = (P_P2P_DEVICE_DESC_T)NULL; + P_P2P_ATTRIBUTE_T prP2pAttribute = (P_P2P_ATTRIBUTE_T)NULL; + UINT_16 u2AttributeLen = 0; + UINT_32 u4Idx = 0; + BOOLEAN fgUpdateDevInfo = FALSE; + + P_DEVICE_NAME_TLV_T prP2pDevName = (P_DEVICE_NAME_TLV_T)NULL; + P_P2P_ATTRI_GROUP_INFO_T prP2pAttriGroupInfo = (P_P2P_ATTRI_GROUP_INFO_T)NULL; + + ASSERT(prAdapter); + + prP2pDesc = scanGetP2pDeviceDesc(prAdapter, prBssDesc); + + if (!prP2pDesc) { + ASSERT(FALSE); + return fgUpdateDevInfo; + } + + p2pGetP2PAttriList(prAdapter, prBssDesc->aucIEBuf, prBssDesc->u2IELength, (PPUINT_8)&prP2pAttribute, &u2AttributeLen); + + while (u2AttributeLen >= P2P_ATTRI_HDR_LEN) { + switch (prP2pAttribute->ucId) { + case P2P_ATTRI_ID_P2P_CAPABILITY: /* Beacon, Probe Response */ + { + P_P2P_ATTRI_CAPABILITY_T prP2pAttriCapability = (P_P2P_ATTRI_CAPABILITY_T)NULL; + + prP2pAttriCapability = (P_P2P_ATTRI_CAPABILITY_T)prP2pAttribute; + ASSERT(prP2pAttriCapability->u2Length == 2); + + prP2pDesc->ucDeviceCapabilityBitmap = prP2pAttriCapability->ucDeviceCap; + prP2pDesc->ucGroupCapabilityBitmap = prP2pAttriCapability->ucGroupCap; + } + break; + case P2P_ATTRI_ID_P2P_DEV_ID: /* Beacon */ + { + P_P2P_ATTRI_DEV_ID_T prP2pAttriDevID = (P_P2P_ATTRI_DEV_ID_T)NULL; + + prP2pAttriDevID = (P_P2P_ATTRI_DEV_ID_T)prP2pAttribute; + ASSERT(prP2pAttriDevID->u2Length == P2P_ATTRI_MAX_LEN_P2P_DEV_ID); + + kalMemCopy(prP2pDesc->aucDeviceAddr, prP2pAttriDevID->aucDevAddr, MAC_ADDR_LEN); + } + break; + case P2P_ATTRI_ID_P2P_DEV_INFO: /* Probe Response */ + { + P_P2P_ATTRI_DEV_INFO_T prP2pAttriDevInfo = (P_P2P_ATTRI_DEV_INFO_T)NULL; + P_P2P_DEVICE_TYPE_T prP2pDevType = (P_P2P_DEVICE_TYPE_T)NULL; + UINT_16 u2NameLen = 0, u2Id = 0; + + fgUpdateDevInfo = TRUE; + + prP2pAttriDevInfo = (P_P2P_ATTRI_DEV_INFO_T)prP2pAttribute; + + kalMemCopy(prP2pDesc->aucDeviceAddr, prP2pAttriDevInfo->aucDevAddr, MAC_ADDR_LEN); + + WLAN_GET_FIELD_BE16(&prP2pAttriDevInfo->u2ConfigMethodsBE, &prP2pDesc->u2ConfigMethod); + + prP2pDevType = &prP2pDesc->rPriDevType; + WLAN_GET_FIELD_BE16(&prP2pAttriDevInfo->rPrimaryDevTypeBE.u2CategoryId, &prP2pDevType->u2CategoryID); + WLAN_GET_FIELD_BE16(&prP2pAttriDevInfo->rPrimaryDevTypeBE.u2SubCategoryId, &prP2pDevType->u2SubCategoryID); + + ASSERT(prP2pAttriDevInfo->ucNumOfSecondaryDevType <= P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT); // TODO: Fixme if secondary device type is more than 2. + prP2pDesc->ucSecDevTypeNum = 0; + for (u4Idx = 0; u4Idx < prP2pAttriDevInfo->ucNumOfSecondaryDevType; u4Idx++) { + if (u4Idx < P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT) { + prP2pDevType = &(prP2pDesc->arSecDevType[u4Idx]); + WLAN_GET_FIELD_BE16(&prP2pAttriDevInfo->arSecondaryDevTypeListBE[u4Idx].u2CategoryId, &prP2pDevType->u2CategoryID); + WLAN_GET_FIELD_BE16(&prP2pAttriDevInfo->arSecondaryDevTypeListBE[u4Idx].u2SubCategoryId, &prP2pDevType->u2SubCategoryID); + prP2pDesc->ucSecDevTypeNum++; + } + + } + prP2pDevName = (P_DEVICE_NAME_TLV_T)((PUINT_8)prP2pAttriDevInfo->arSecondaryDevTypeListBE + (u4Idx * sizeof(DEVICE_TYPE_T))); + WLAN_GET_FIELD_BE16(&prP2pDevName->u2Length, &u2NameLen); + WLAN_GET_FIELD_BE16(&prP2pDevName->u2Id, &u2Id); + ASSERT(u2Id == WPS_ATTRI_ID_DEVICE_NAME); + if (u2NameLen > WPS_ATTRI_MAX_LEN_DEVICE_NAME) { + u2NameLen = WPS_ATTRI_MAX_LEN_DEVICE_NAME; + } + prP2pDesc->u2NameLength = u2NameLen; + kalMemCopy(prP2pDesc->aucName, prP2pDevName->aucName, prP2pDesc->u2NameLength); + } + break; + case P2P_ATTRI_ID_P2P_GROUP_INFO: /* Probe Response */ + prP2pAttriGroupInfo = (P_P2P_ATTRI_GROUP_INFO_T)prP2pAttribute; + break; + case P2P_ATTRI_ID_NOTICE_OF_ABSENCE: + break; + case P2P_ATTRI_ID_EXT_LISTEN_TIMING: + // TODO: Not implement yet. + //ASSERT(FALSE); + break; + default: + break; + } + + u2AttributeLen -= (prP2pAttribute->u2Length + P2P_ATTRI_HDR_LEN); + + prP2pAttribute = (P_P2P_ATTRIBUTE_T)((UINT_32)prP2pAttribute + (prP2pAttribute->u2Length + P2P_ATTRI_HDR_LEN)); + + } + + + if (prP2pAttriGroupInfo != NULL) { + P_P2P_CLIENT_INFO_DESC_T prClientInfoDesc = (P_P2P_CLIENT_INFO_DESC_T)NULL; + P_P2P_DEVICE_TYPE_T prP2pDevType = (P_P2P_DEVICE_TYPE_T)NULL; + + scanInvalidAllP2pClientDevice(prAdapter, prBssDesc); + + /* GO/Device itself. */ + prP2pDesc->fgDevInfoValid = TRUE; + + prClientInfoDesc = (P_P2P_CLIENT_INFO_DESC_T)prP2pAttriGroupInfo->arClientDesc; + u2AttributeLen = prP2pAttriGroupInfo->u2Length; + + + while (u2AttributeLen > 0) { + prP2pDesc = scanFindP2pDeviceDesc(prAdapter, prBssDesc, prClientInfoDesc->aucDevAddr, TRUE, TRUE); + + if (!prP2pDesc) { + ASSERT(FALSE); + break; /* while */ + } + + prP2pDesc->fgDevInfoValid = TRUE; + + /* Basic size for P2P client info descriptor. */ + ASSERT(u2AttributeLen >= 25); + if (u2AttributeLen < 25) { + DBGLOG(P2P, WARN, ("Length incorrect warning.\n")); + break; + } + COPY_MAC_ADDR(prP2pDesc->aucInterfaceAddr, prClientInfoDesc->aucIfAddr); + + prP2pDesc->ucDeviceCapabilityBitmap = prClientInfoDesc->ucDeviceCap; + + WLAN_GET_FIELD_BE16(&prClientInfoDesc->u2ConfigMethodsBE, &prP2pDesc->u2ConfigMethod); + + prP2pDevType = &(prP2pDesc->rPriDevType); + WLAN_GET_FIELD_BE16(&prClientInfoDesc->rPrimaryDevTypeBE.u2CategoryId, &prP2pDevType->u2CategoryID); + WLAN_GET_FIELD_BE16(&prClientInfoDesc->rPrimaryDevTypeBE.u2SubCategoryId, &prP2pDevType->u2SubCategoryID); + + ASSERT(prClientInfoDesc->ucNumOfSecondaryDevType <= P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT); + prP2pDesc->ucSecDevTypeNum = 0; + for (u4Idx = 0; u4Idx < prClientInfoDesc->ucNumOfSecondaryDevType; u4Idx++) { + if (u4Idx < P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT) { + prP2pDevType = &(prP2pDesc->arSecDevType[u4Idx]); + WLAN_GET_FIELD_BE16(&prClientInfoDesc->arSecondaryDevTypeListBE[u4Idx].u2CategoryId, &prP2pDevType->u2CategoryID); + WLAN_GET_FIELD_BE16(&prClientInfoDesc->arSecondaryDevTypeListBE[u4Idx].u2SubCategoryId, &prP2pDevType->u2SubCategoryID); + prP2pDesc->ucSecDevTypeNum++; + } + + } + prP2pDevName = (P_DEVICE_NAME_TLV_T)(prClientInfoDesc->arSecondaryDevTypeListBE + (u4Idx * sizeof(DEVICE_TYPE_T))); + WLAN_GET_FIELD_BE16(&prP2pDevName->u2Length, &prP2pDesc->u2NameLength); + if (prP2pDesc->u2NameLength > WPS_ATTRI_MAX_LEN_DEVICE_NAME) { + prP2pDesc->u2NameLength = WPS_ATTRI_MAX_LEN_DEVICE_NAME; + } + + kalMemCopy(prP2pDesc->aucName, prP2pDevName->aucName, prP2pDesc->u2NameLength); + + u2AttributeLen -= (prClientInfoDesc->ucLength + P2P_CLIENT_INFO_DESC_HDR_LEN); + prClientInfoDesc = (P_P2P_CLIENT_INFO_DESC_T)((UINT_32)prClientInfoDesc + (UINT_32)prClientInfoDesc->ucLength + P2P_CLIENT_INFO_DESC_HDR_LEN); + } + + scanRemoveInvalidP2pClientDevice(prAdapter, prBssDesc); + } + + return fgUpdateDevInfo; +} /* end of scanAddP2pDeviceInfo() */ + +#endif + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Convert the Beacon or ProbeResp Frame in SW_RFB_T to Event Packet +* +* @param[in] prSwRfb Pointer to the receiving SW_RFB_T structure. +* +* @retval WLAN_STATUS_SUCCESS It is a valid Scan Result and been sent to the host. +* @retval WLAN_STATUS_FAILURE It is not a valid Scan Result. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +scanSendDeviceDiscoverEvent ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc, + IN P_SW_RFB_T prSwRfb + ) +{ + EVENT_P2P_DEV_DISCOVER_RESULT_T rEventDevInfo; +#if 1 + P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T)NULL; + P_P2P_DEVICE_DESC_T prTargetDesc = (P_P2P_DEVICE_DESC_T)NULL; + + LINK_FOR_EACH(prLinkEntry, &prBssDesc->rP2pDeviceList) { + prTargetDesc = LINK_ENTRY(prLinkEntry, P2P_DEVICE_DESC_T, rLinkEntry); + + COPY_MAC_ADDR(rEventDevInfo.aucDeviceAddr, prTargetDesc->aucDeviceAddr); + COPY_MAC_ADDR(rEventDevInfo.aucInterfaceAddr, prTargetDesc->aucInterfaceAddr); + + rEventDevInfo.ucDeviceCapabilityBitmap = prTargetDesc->ucDeviceCapabilityBitmap; + rEventDevInfo.ucGroupCapabilityBitmap = prTargetDesc->ucGroupCapabilityBitmap; + rEventDevInfo.u2ConfigMethod = prTargetDesc->u2ConfigMethod; + + kalMemCopy(&rEventDevInfo.rPriDevType, + &prTargetDesc->rPriDevType, + sizeof(P2P_DEVICE_TYPE_T)); + + kalMemCopy(rEventDevInfo.arSecDevType, + prTargetDesc->arSecDevType, + (prTargetDesc->ucSecDevTypeNum * sizeof(P2P_DEVICE_TYPE_T))); + + rEventDevInfo.ucSecDevTypeNum = prTargetDesc->ucSecDevTypeNum; + + rEventDevInfo.u2NameLength = prTargetDesc->u2NameLength; + kalMemCopy(rEventDevInfo.aucName, + prTargetDesc->aucName, + prTargetDesc->u2NameLength); + + COPY_MAC_ADDR(rEventDevInfo.aucBSSID, prBssDesc->aucBSSID); + + if (prTargetDesc == prBssDesc->prP2pDesc) { + nicRxAddP2pDevice(prAdapter, + &rEventDevInfo, + prBssDesc->aucIEBuf, + prBssDesc->u2IELength); + } + else { + nicRxAddP2pDevice(prAdapter, + &rEventDevInfo, + NULL, + 0); + } + } + + kalP2PIndicateFound(prAdapter->prGlueInfo); + +#else + + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T)NULL; + P_P2P_ATTRIBUTE_T prP2pAttribute = (P_P2P_ATTRIBUTE_T)NULL; + UINT_16 u2AttributeLen = 0; + UINT_32 u4Idx = 0; + P_P2P_ATTRI_GROUP_INFO_T prP2pAttriGroupInfo = (P_P2P_ATTRI_GROUP_INFO_T)NULL; + P_DEVICE_NAME_TLV_T prP2pDevName = (P_DEVICE_NAME_TLV_T)NULL; + + ASSERT(prAdapter); + + prP2pSpecificBssInfo = &prAdapter->rWifiVar.rP2pSpecificBssInfo; + +#if 1 + p2pGetP2PAttriList(prAdapter, prBssDesc->aucIEBuf, prBssDesc->u2IELength, (PPUINT_8)&prP2pAttribute, &u2AttributeLen); +#else + prP2pAttribute = (P_P2P_ATTRIBUTE_T)&prP2pSpecificBssInfo->aucAttributesCache[0]; + u2AttributeLen = prP2pSpecificBssInfo->u2AttributeLen; +#endif + rEventDevInfo.fgDevInfoValid = FALSE; + + while (u2AttributeLen >= P2P_ATTRI_HDR_LEN) { + switch (prP2pAttribute->ucId) { + case P2P_ATTRI_ID_P2P_CAPABILITY: + { + P_P2P_ATTRI_CAPABILITY_T prP2pAttriCapability = (P_P2P_ATTRI_CAPABILITY_T)NULL; + + prP2pAttriCapability = (P_P2P_ATTRI_CAPABILITY_T)prP2pAttribute; + ASSERT(prP2pAttriCapability->u2Length == 2); + rEventDevInfo.ucDeviceCapabilityBitmap = prP2pAttriCapability->ucDeviceCap; + rEventDevInfo.ucGroupCapabilityBitmap = prP2pAttriCapability->ucGroupCap; + } + break; + case P2P_ATTRI_ID_P2P_DEV_ID: + { + P_P2P_ATTRI_DEV_ID_T prP2pAttriDevID = (P_P2P_ATTRI_DEV_ID_T)NULL; + + prP2pAttriDevID = (P_P2P_ATTRI_DEV_ID_T)prP2pAttribute; + ASSERT(prP2pAttriDevID->u2Length == 6); + kalMemCopy(rEventDevInfo.aucCommunicateAddr, prP2pAttriDevID->aucDevAddr, MAC_ADDR_LEN); + } + break; + case P2P_ATTRI_ID_P2P_DEV_INFO: + { + P_P2P_ATTRI_DEV_INFO_T prP2pAttriDevInfo = (P_P2P_ATTRI_DEV_INFO_T)NULL; + P_P2P_DEVICE_TYPE_T prP2pDevType = (P_P2P_DEVICE_TYPE_T)NULL; + + prP2pAttriDevInfo = (P_P2P_ATTRI_DEV_INFO_T)prP2pAttribute; + rEventDevInfo.fgDevInfoValid = TRUE; + kalMemCopy(rEventDevInfo.aucCommunicateAddr, prP2pAttriDevInfo->aucDevAddr, MAC_ADDR_LEN); + rEventDevInfo.u2ConfigMethod = prP2pAttriDevInfo->u2ConfigMethodsBE; + + prP2pDevType = &rEventDevInfo.rPriDevType; + prP2pDevType->u2CategoryID = prP2pAttriDevInfo->rPrimaryDevTypeBE.u2CategoryId; + prP2pDevType->u2SubCategoryID = prP2pAttriDevInfo->rPrimaryDevTypeBE.u2SubCategoryId; + + ASSERT(prP2pAttriDevInfo->ucNumOfSecondaryDevType <= 2); // TODO: Fixme if secondary device type is more than 2. + for (u4Idx = 0; u4Idx < prP2pAttriDevInfo->ucNumOfSecondaryDevType; u4Idx++) { + // TODO: Current sub device type can only support 2. + prP2pDevType = &rEventDevInfo.arSecDevType[u4Idx]; + prP2pDevType->u2CategoryID = prP2pAttriDevInfo->rPrimaryDevTypeBE.u2CategoryId; + prP2pDevType->u2SubCategoryID = prP2pAttriDevInfo->rPrimaryDevTypeBE.u2SubCategoryId; + } + + prP2pDevName = (P_DEVICE_NAME_TLV_T)(prP2pAttriDevInfo->arSecondaryDevTypeListBE + (u4Idx * sizeof(DEVICE_TYPE_T))); + ASSERT(prP2pDevName->u2Id == 0x1011); + ASSERT(prP2pDevName->u2Length <= 32); // TODO: Fixme if device name length is longer than 32 bytes. + kalMemCopy(rEventDevInfo.aucName, prP2pDevName->aucName, prP2pDevName->u2Length); + } + break; + case P2P_ATTRI_ID_P2P_GROUP_INFO: + prP2pAttriGroupInfo = (P_P2P_ATTRI_GROUP_INFO_T)prP2pAttribute; + break; + } + + u2AttributeLen -= (prP2pAttribute->u2Length + P2P_ATTRI_HDR_LEN); + + prP2pAttribute = (P_P2P_ATTRIBUTE_T)((UINT_32)prP2pAttribute + (prP2pAttribute->u2Length + P2P_ATTRI_HDR_LEN)); + + } + + nicRxAddP2pDevice(prAdapter, + &rEventDevInfo); + + if (prP2pAttriGroupInfo != NULL) { + P_P2P_CLIENT_INFO_DESC_T prClientInfoDesc = (P_P2P_CLIENT_INFO_DESC_T)NULL; + P_P2P_DEVICE_TYPE_T prP2pDevType = (P_P2P_DEVICE_TYPE_T)NULL; + + prClientInfoDesc = prP2pAttriGroupInfo->arClientDesc; + u2AttributeLen = prP2pAttriGroupInfo->u2Length; + + while (u2AttributeLen > 0) { + /* Basic size for P2P client info descriptor. */ + ASSERT(u2AttributeLen >= 25); + rEventDevInfo.fgDevInfoValid = TRUE; + kalMemCopy(rEventDevInfo.aucCommunicateAddr, prClientInfoDesc->aucIfAddr, MAC_ADDR_LEN); + rEventDevInfo.ucDeviceCapabilityBitmap = prClientInfoDesc->ucDeviceCap; + rEventDevInfo.u2ConfigMethod = prClientInfoDesc->u2ConfigMethodsBE; + + prP2pDevType = &rEventDevInfo.rPriDevType; + prP2pDevType->u2CategoryID = prClientInfoDesc->rPrimaryDevTypeBE.u2CategoryId; + prP2pDevType->u2SubCategoryID = prClientInfoDesc->rPrimaryDevTypeBE.u2SubCategoryId; + + ASSERT(prClientInfoDesc->ucNumOfSecondaryDevType <= 2); // TODO: Fixme if secondary device type is more than 2. + for (u4Idx = 0; u4Idx < prClientInfoDesc->ucNumOfSecondaryDevType; u4Idx++) { + // TODO: Current sub device type can only support 2. + prP2pDevType = &rEventDevInfo.arSecDevType[u4Idx]; + prP2pDevType->u2CategoryID = prClientInfoDesc->arSecondaryDevTypeListBE[u4Idx].u2CategoryId; + prP2pDevType->u2SubCategoryID = prClientInfoDesc->arSecondaryDevTypeListBE[u4Idx].u2SubCategoryId; + } + + prP2pDevName = (P_DEVICE_NAME_TLV_T)(prClientInfoDesc->arSecondaryDevTypeListBE + (u4Idx * sizeof(DEVICE_TYPE_T))); + ASSERT(prP2pDevName->u2Id == 0x1011); + ASSERT(prP2pDevName->u2Length <= 32); // TODO: Fixme if device name length is longer than 32 bytes. + kalMemCopy(&rEventDevInfo.aucName, prP2pDevName->aucName, prP2pDevName->u2Length); + + nicRxAddP2pDevice(prAdapter, + &rEventDevInfo); + + u2AttributeLen -= prP2pAttriGroupInfo->u2Length; + prP2pAttriGroupInfo = prP2pAttriGroupInfo + prP2pAttriGroupInfo->u2Length + 1; + } + + } +#endif + return WLAN_STATUS_SUCCESS; +} /* scanSendDeviceDiscoverEvent */ + +VOID +scanP2pProcessBeaconAndProbeResp( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN P_WLAN_STATUS prStatus, + IN P_BSS_DESC_T prBssDesc, + IN P_WLAN_BEACON_FRAME_T prWlanBeaconFrame + ) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T)NULL; + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + + if (prBssDesc->fgIsP2PPresent) { + + if ((!prP2pBssInfo->ucDTIMPeriod) && // First time. + (prP2pBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) && // P2P GC + (prP2pBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) && // Connected + ((prWlanBeaconFrame->u2FrameCtrl & MASK_FRAME_TYPE) == MAC_FRAME_BEACON) && // TX Beacon + EQUAL_SSID(prBssDesc->aucSSID, // SSID Match + prBssDesc->ucSSIDLen, + prP2pConnSettings->aucSSID, + prP2pConnSettings->ucSSIDLen)) { + + + prP2pBssInfo->ucDTIMPeriod = prBssDesc->ucDTIMPeriod; + nicPmIndicateBssConnected(prAdapter, NETWORK_TYPE_P2P_INDEX); + } + + do { + RF_CHANNEL_INFO_T rChannelInfo; + + ASSERT_BREAK((prSwRfb != NULL) && (prBssDesc != NULL)); + + rChannelInfo.ucChannelNum = prBssDesc->ucChannelNum; + rChannelInfo.eBand = prBssDesc->eBand; + + kalP2PIndicateBssInfo(prAdapter->prGlueInfo, + (PUINT_8)prSwRfb->pvHeader, + (UINT_32)prSwRfb->u2PacketLen, + &rChannelInfo, + RCPI_TO_dBm(prBssDesc->ucRCPI)); + + + } while (FALSE); + } +} + +VOID +scnEventReturnChannel ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucScnSeqNum + ) +{ + + CMD_SCAN_CANCEL rCmdScanCancel; + + /* send cancel message to firmware domain */ + rCmdScanCancel.ucSeqNum = ucScnSeqNum; + rCmdScanCancel.ucIsExtChannel = (UINT_8) FALSE; + + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SCAN_CANCEL, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(CMD_SCAN_CANCEL), + (PUINT_8)&rCmdScanCancel, + NULL, + 0); + + return; +} /* scnEventReturnChannel */ + +VOID +scanRemoveAllP2pBssDesc( + IN P_ADAPTER_T prAdapter + ) +{ + P_LINK_T prBSSDescList; + P_BSS_DESC_T prBssDesc; + P_BSS_DESC_T prBSSDescNext; + + ASSERT(prAdapter); + + prBSSDescList = &(prAdapter->rWifiVar.rScanInfo.rBSSDescList); + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, rLinkEntry, BSS_DESC_T) { + scanRemoveP2pBssDesc(prAdapter, prBssDesc); + } +} /* scanRemoveAllP2pBssDesc */ + +VOID +scanRemoveP2pBssDesc( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc + ) +{ + + return; +} /* scanRemoveP2pBssDesc */ + + +P_BSS_DESC_T +scanP2pSearchDesc ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo + ) +{ + P_BSS_DESC_T prCandidateBssDesc = (P_BSS_DESC_T)NULL, prBssDesc = (P_BSS_DESC_T)NULL; + P_LINK_T prBssDescList = (P_LINK_T)NULL; + + do { + if ((prAdapter == NULL) || + (prP2pBssInfo == NULL) || + (prConnReqInfo == NULL)) { + break; + } + + + prBssDescList = &(prAdapter->rWifiVar.rScanInfo.rBSSDescList); + + DBGLOG(P2P, LOUD, ("Connecting to BSSID: "MACSTR"\n", MAC2STR(prConnReqInfo->aucBssid))); + DBGLOG(P2P, LOUD, ("Connecting to SSID:%s, length:%d\n", + prConnReqInfo->rSsidStruct.aucSsid, + prConnReqInfo->rSsidStruct.ucSsidLen)); + + LINK_FOR_EACH_ENTRY(prBssDesc, prBssDescList, rLinkEntry, BSS_DESC_T) { + DBGLOG(P2P, LOUD, ("Checking BSS: "MACSTR"\n", MAC2STR(prBssDesc->aucBSSID))); + + if (prBssDesc->eBSSType != BSS_TYPE_INFRASTRUCTURE) { + DBGLOG(P2P, LOUD, ("Ignore mismatch BSS type.\n")); + continue; + } + + + if (UNEQUAL_MAC_ADDR(prBssDesc->aucBSSID, prConnReqInfo->aucBssid)) { + DBGLOG(P2P, LOUD, ("Ignore mismatch BSSID.\n")); + continue; + } + + + /* SSID should be the same? SSID is vary for each connection. so... */ + if (UNEQUAL_SSID(prConnReqInfo->rSsidStruct.aucSsid, + prConnReqInfo->rSsidStruct.ucSsidLen, + prBssDesc->aucSSID, + prBssDesc->ucSSIDLen)) { + + DBGLOG(P2P, TRACE, ("Connecting to BSSID: "MACSTR"\n", MAC2STR(prConnReqInfo->aucBssid))); + DBGLOG(P2P, TRACE, ("Connecting to SSID:%s, length:%d\n", + prConnReqInfo->rSsidStruct.aucSsid, + prConnReqInfo->rSsidStruct.ucSsidLen)); + DBGLOG(P2P, TRACE, ("Checking SSID:%s, length:%d\n", + prBssDesc->aucSSID, + prBssDesc->ucSSIDLen)); + DBGLOG(P2P, TRACE, ("Ignore mismatch SSID, (But BSSID match).\n")); + ASSERT(FALSE); + break; + } + + /* Final decision. */ + prCandidateBssDesc = prBssDesc; + break; + } + + + + } while (FALSE); + + return prCandidateBssDesc; +} /* scanP2pSearchDesc */ + + + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_state.c b/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_state.c new file mode 100755 index 000000000000..cf108f3cb1a3 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/mgmt/p2p_state.c @@ -0,0 +1,544 @@ + +#include "p2p_precomp.h" + + +BOOLEAN +p2pStateInit_IDLE ( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN P_BSS_INFO_T prP2pBssInfo, + OUT P_ENUM_P2P_STATE_T peNextState + ) +{ + BOOLEAN fgIsTransOut = FALSE; + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && + (prP2pFsmInfo != NULL) && + (prP2pBssInfo != NULL) && + (peNextState != NULL)); + DBGLOG(P2P, TRACE, ("p2pStateInit_IDLE \n")); + if ((prP2pBssInfo->eIntendOPMode == OP_MODE_ACCESS_POINT) && IS_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX)) { + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); + + fgIsTransOut = TRUE; + prChnlReqInfo->eChannelReqType = CHANNEL_REQ_TYPE_GO_START_BSS; + *peNextState = P2P_STATE_REQING_CHANNEL; + DBGLOG(P2P, TRACE, ("p2pStateInit_IDLE: peNextState = P2P_STATE_REQING_CHANNEL \n")); + + } + else { + prChnlReqInfo = &prP2pFsmInfo->rChnlReqInfo; + + if (prChnlReqInfo->fgIsChannelRequested) { + /* Start a timer for return channel. */ + DBGLOG(P2P, TRACE, ("start a GO channel timer.\n")); + cnmTimerStartTimer(prAdapter, &(prP2pFsmInfo->rP2pFsmTimeoutTimer), 5000); + } + + } + + + } while (FALSE); + + return fgIsTransOut; +} /* p2pStateInit_IDLE */ + + +VOID +p2pStateAbort_IDLE ( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN ENUM_P2P_STATE_T eNextState + ) +{ + + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && + (prP2pFsmInfo != NULL)); + DBGLOG(P2P, TRACE, ("p2pStateAbort_IDLE \n")); + prChnlReqInfo = &prP2pFsmInfo->rChnlReqInfo; + + if (prChnlReqInfo->fgIsChannelRequested) { + /* Stop timer for leaving this state. */ + cnmTimerStopTimer(prAdapter, &(prP2pFsmInfo->rP2pFsmTimeoutTimer)); + + /* Release channel before timeout. */ + p2pFuncReleaseCh(prAdapter, prChnlReqInfo); + DBGLOG(P2P, TRACE, ("p2pStateAbort_IDLE: Release channel \n")); + } + + + + } while (FALSE); + + return; +} /* p2pStateAbort_IDLE */ + + + +VOID +p2pStateInit_CHNL_ON_HAND ( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo + ) +{ + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); + + prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); + + DBGLOG(P2P, TRACE, ("start a channel on hand timer.\n")); + cnmTimerStartTimer(prAdapter, + &(prP2pFsmInfo->rP2pFsmTimeoutTimer), + prChnlReqInfo->u4MaxInterval); + + kalP2PIndicateChannelReady(prAdapter->prGlueInfo, + prChnlReqInfo->u8Cookie, + prChnlReqInfo->ucReqChnlNum, + prChnlReqInfo->eBand, + prChnlReqInfo->eChnlSco, + prChnlReqInfo->u4MaxInterval); + + } while (FALSE); + + return; +} /* p2pStateInit_CHNL_ON_HAND */ + + +VOID +p2pStateAbort_CHNL_ON_HAND ( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN ENUM_P2P_STATE_T eNextState + ) +{ + + cnmTimerStopTimer(prAdapter, &(prP2pFsmInfo->rP2pFsmTimeoutTimer)); + + if (eNextState != P2P_STATE_CHNL_ON_HAND) { + /* Indicate channel return. */ + kalP2PIndicateChannelExpired(prAdapter->prGlueInfo, &prP2pFsmInfo->rChnlReqInfo); + + // Return Channel. + p2pFuncReleaseCh(prAdapter, &(prP2pFsmInfo->rChnlReqInfo)); + } + + return; +} /* p2pStateAbort_CHNL_ON_HAND */ + + +VOID +p2pStateAbort_REQING_CHANNEL ( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN ENUM_P2P_STATE_T eNextState + ) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T)NULL; + + do { + + ASSERT_BREAK((prAdapter != NULL) && + (prP2pFsmInfo != NULL) && + (eNextState < P2P_STATE_NUM)); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; + + if (eNextState == P2P_STATE_IDLE) { + if (prP2pBssInfo->eIntendOPMode == OP_MODE_ACCESS_POINT) { + /* Intend to be AP. */ + /* Setup for AP mode. */ + p2pFuncStartGO(prAdapter, + prP2pBssInfo, + prP2pSpecificBssInfo->aucGroupSsid, + prP2pSpecificBssInfo->u2GroupSsidLen, + prP2pSpecificBssInfo->ucPreferredChannel, + prP2pSpecificBssInfo->eRfBand, + prP2pSpecificBssInfo->eRfSco, + prP2pFsmInfo->fgIsApMode); + + } + else { + // Return Channel. + p2pFuncReleaseCh(prAdapter, &(prP2pFsmInfo->rChnlReqInfo)); + } + + } + + + } while (FALSE); + + return; +} /* p2pStateInit_AP_CHANNEL_DETECT */ + + +VOID +p2pStateInit_AP_CHANNEL_DETECT ( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo + ) +{ + P_P2P_SCAN_REQ_INFO_T prScanReqInfo = (P_P2P_SCAN_REQ_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); + + prScanReqInfo = &(prP2pFsmInfo->rScanReqInfo); + + prScanReqInfo->eScanType = SCAN_TYPE_PASSIVE_SCAN; + prScanReqInfo->eChannelSet = SCAN_CHANNEL_2G4; + prScanReqInfo->u2PassiveDewellTime = 50; // 50ms for passive channel load detection + prScanReqInfo->fgIsAbort = TRUE; + prScanReqInfo->fgIsScanRequest = TRUE; + prScanReqInfo->ucNumChannelList = 0; + prScanReqInfo->u4BufLength = 0; + prScanReqInfo->rSsidStruct.ucSsidLen = 0; + + p2pFuncRequestScan(prAdapter, prScanReqInfo); + + } while (FALSE); + + return; +} /* p2pStateInit_AP_CHANNEL_DETECT */ + + + +VOID +p2pStateAbort_AP_CHANNEL_DETECT ( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo, + IN ENUM_P2P_STATE_T eNextState + ) +{ + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T)NULL; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T)NULL; + + do { + + if (eNextState == P2P_STATE_REQING_CHANNEL) { + UINT_8 ucPreferedChnl = 0; + ENUM_BAND_T eBand = BAND_NULL; + ENUM_CHNL_EXT_T eSco = CHNL_EXT_SCN; + + prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); + + /* Determine the channel for AP. */ + if (cnmPreferredChannel(prAdapter, + &eBand, + &ucPreferedChnl, + &eSco) == FALSE) { + + prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + + if ((ucPreferedChnl = prP2pConnSettings->ucOperatingChnl) == 0) { + + if (scnQuerySparseChannel(prAdapter, &eBand, &ucPreferedChnl) == FALSE) { + + // What to do? + ASSERT(FALSE); + // TODO: Pick up a valid channel from channel list. + } + } + } + + + prChnlReqInfo->eChannelReqType = CHANNEL_REQ_TYPE_GO_START_BSS; + prChnlReqInfo->ucReqChnlNum = prP2pSpecificBssInfo->ucPreferredChannel = ucPreferedChnl; + prChnlReqInfo->eBand = prP2pSpecificBssInfo->eRfBand = eBand; + prChnlReqInfo->eChnlSco = prP2pSpecificBssInfo->eRfSco = eSco; + } + else { + p2pFuncCancelScan(prAdapter, &(prP2pFsmInfo->rScanReqInfo)); + } + + + } while (FALSE); + + return; +} /* p2pStateAbort_AP_CHANNEL_DETECT */ + + +VOID +p2pStateInit_SCAN ( + + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo + ) +{ + P_P2P_SCAN_REQ_INFO_T prScanReqInfo = (P_P2P_SCAN_REQ_INFO_T)NULL; + + do { + + ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); + DBGLOG(P2P, TRACE, ("p2pStateInit_SCAN \n")); + prScanReqInfo = &prP2pFsmInfo->rScanReqInfo; + + prScanReqInfo->fgIsScanRequest = TRUE; + + p2pFuncRequestScan(prAdapter, prScanReqInfo); + + } while (FALSE); + return; +} /* p2pStateInit_SCAN */ + + +VOID +p2pStateAbort_SCAN ( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN ENUM_P2P_STATE_T eNextState + ) +{ + do { + ASSERT_BREAK(prAdapter != NULL); + + // 1. Scan cancel. (Make sure the scan request is invalid. + p2pFuncCancelScan(prAdapter, &(prP2pFsmInfo->rScanReqInfo)); + + // Scan done indication. + kalP2PIndicateScanDone(prAdapter->prGlueInfo, prP2pFsmInfo->rScanReqInfo.fgIsAbort); + } while (FALSE); + + return; +} /* p2pStateAbort_SCAN */ + + +VOID +p2pStateInit_GC_JOIN ( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN P_BSS_INFO_T prP2pBssInfo, + IN P_P2P_JOIN_INFO_T prJoinInfo, + IN P_BSS_DESC_T prBssDesc + ) +{ + P_MSG_JOIN_REQ_T prJoinReqMsg = (P_MSG_JOIN_REQ_T)NULL; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && + (prP2pFsmInfo != NULL) && + (prP2pBssInfo != NULL) && + (prJoinInfo != NULL) && + (prBssDesc != NULL)); + + prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + + if (prBssDesc->ucSSIDLen) { + COPY_SSID(prP2pConnSettings->aucSSID, + prP2pConnSettings->ucSSIDLen, + prBssDesc->aucSSID, + prBssDesc->ucSSIDLen); + } + + + // Setup a join timer. + DBGLOG(P2P, TRACE, ("Start a join init timer\n")); + cnmTimerStartTimer(prAdapter, + &(prP2pFsmInfo->rP2pFsmTimeoutTimer), + (prP2pFsmInfo->u4GrantInterval - AIS_JOIN_CH_GRANT_THRESHOLD)); + + //2 <1> We are goin to connect to this BSS + prBssDesc->fgIsConnecting = TRUE; + + //2 <2> Setup corresponding STA_RECORD_T + prStaRec = bssCreateStaRecFromBssDesc(prAdapter, + (prBssDesc->fgIsP2PPresent?(STA_TYPE_P2P_GO):(STA_TYPE_LEGACY_AP)), + NETWORK_TYPE_P2P_INDEX, + prBssDesc); + + if (prStaRec == NULL) { + DBGLOG(P2P, TRACE, ("Create station record fail\n")); + break; + } + + + prJoinInfo->prTargetStaRec = prStaRec; + prJoinInfo->fgIsJoinComplete = FALSE; + prJoinInfo->u4BufLength = 0; + + //2 <2.1> Sync. to FW domain + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + + + if (prP2pBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T)NULL; + + prStaRec->fgIsReAssoc = FALSE; + + prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + + switch (prP2pConnSettings->eAuthMode) { + case AUTH_MODE_OPEN: /* Note: Omit break here. */ + case AUTH_MODE_WPA: + case AUTH_MODE_WPA_PSK: + case AUTH_MODE_WPA2: + case AUTH_MODE_WPA2_PSK: + prJoinInfo->ucAvailableAuthTypes = (UINT_8)AUTH_TYPE_OPEN_SYSTEM; + break; + case AUTH_MODE_SHARED: + prJoinInfo->ucAvailableAuthTypes = (UINT_8)AUTH_TYPE_SHARED_KEY; + break; + case AUTH_MODE_AUTO_SWITCH: + DBGLOG(P2P, LOUD, ("JOIN INIT: eAuthMode == AUTH_MODE_AUTO_SWITCH\n")); + prJoinInfo->ucAvailableAuthTypes = (UINT_8)(AUTH_TYPE_OPEN_SYSTEM | + AUTH_TYPE_SHARED_KEY); + break; + default: + ASSERT(!(prP2pConnSettings->eAuthMode == AUTH_MODE_WPA_NONE)); + DBGLOG(P2P, ERROR, ("JOIN INIT: Auth Algorithm : %d was not supported by JOIN\n", + prP2pConnSettings->eAuthMode)); + /* TODO(Kevin): error handling ? */ + return; + } + prStaRec->ucTxAuthAssocRetryLimit = TX_AUTH_ASSOCI_RETRY_LIMIT; + } + else { + ASSERT(FALSE); + // TODO: Shall we considering ROAMIN case for P2P Device?. + } + + + //2 <4> Use an appropriate Authentication Algorithm Number among the ucAvailableAuthTypes. + if (prJoinInfo->ucAvailableAuthTypes & + (UINT_8)AUTH_TYPE_OPEN_SYSTEM) { + + DBGLOG(P2P, TRACE, ("JOIN INIT: Try to do Authentication with AuthType == OPEN_SYSTEM.\n")); + + prJoinInfo->ucAvailableAuthTypes &= + ~(UINT_8)AUTH_TYPE_OPEN_SYSTEM; + + prStaRec->ucAuthAlgNum = (UINT_8)AUTH_ALGORITHM_NUM_OPEN_SYSTEM; + } + else if (prJoinInfo->ucAvailableAuthTypes & + (UINT_8)AUTH_TYPE_SHARED_KEY) { + + DBGLOG(P2P, TRACE, ("JOIN INIT: Try to do Authentication with AuthType == SHARED_KEY.\n")); + + prJoinInfo->ucAvailableAuthTypes &= + ~(UINT_8)AUTH_TYPE_SHARED_KEY; + + prStaRec->ucAuthAlgNum = (UINT_8)AUTH_ALGORITHM_NUM_SHARED_KEY; + } + else if (prJoinInfo->ucAvailableAuthTypes & + (UINT_8)AUTH_TYPE_FAST_BSS_TRANSITION) { + + DBGLOG(P2P, TRACE, ("JOIN INIT: Try to do Authentication with AuthType == FAST_BSS_TRANSITION.\n")); + + prJoinInfo->ucAvailableAuthTypes &= + ~(UINT_8)AUTH_TYPE_FAST_BSS_TRANSITION; + + prStaRec->ucAuthAlgNum = (UINT_8)AUTH_ALGORITHM_NUM_FAST_BSS_TRANSITION; + } + else { + ASSERT(0); + } + + + //4 <5> Overwrite Connection Setting for eConnectionPolicy == ANY (Used by Assoc Req) + if (prBssDesc->ucSSIDLen) { + COPY_SSID(prJoinInfo->rSsidStruct.aucSsid, + prJoinInfo->rSsidStruct.ucSsidLen, + prBssDesc->aucSSID, + prBssDesc->ucSSIDLen); + } + + //2 <5> Backup desired channel. + + //2 <6> Send a Msg to trigger SAA to start JOIN process. + prJoinReqMsg = (P_MSG_JOIN_REQ_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_REQ_T)); + + if (!prJoinReqMsg) { + DBGLOG(P2P, TRACE, ("Allocation Join Message Fail\n")); + ASSERT(FALSE); + return; + } + + prJoinReqMsg->rMsgHdr.eMsgId = MID_P2P_SAA_FSM_START; + prJoinReqMsg->ucSeqNum = ++prJoinInfo->ucSeqNumOfReqMsg; + prJoinReqMsg->prStaRec = prStaRec; + + // TODO: Consider fragmentation info in station record. + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T)prJoinReqMsg, + MSG_SEND_METHOD_BUF); + + + + + } while (FALSE); + + return; +} /* p2pStateInit_GC_JOIN */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process of JOIN Abort. Leave JOIN State & Abort JOIN. +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pStateAbort_GC_JOIN ( + IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN P_P2P_JOIN_INFO_T prJoinInfo, + IN ENUM_P2P_STATE_T eNextState + ) +{ + P_MSG_JOIN_ABORT_T prJoinAbortMsg = (P_MSG_JOIN_ABORT_T)NULL; + + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL) && (prJoinInfo != NULL)); + + if (prJoinInfo->fgIsJoinComplete == FALSE) { + + prJoinAbortMsg = (P_MSG_JOIN_ABORT_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_ABORT_T)); + if (!prJoinAbortMsg) { + DBGLOG(P2P, TRACE, ("Fail to allocate join abort message buffer\n")); + ASSERT(FALSE); + return; + } + + prJoinAbortMsg->rMsgHdr.eMsgId = MID_P2P_SAA_FSM_ABORT; + prJoinAbortMsg->ucSeqNum = prJoinInfo->ucSeqNumOfReqMsg; + prJoinAbortMsg->prStaRec = prJoinInfo->prTargetStaRec; + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T)prJoinAbortMsg, + MSG_SEND_METHOD_BUF); + + } + + /* Stop Join Timer. */ + cnmTimerStopTimer(prAdapter, &(prP2pFsmInfo->rP2pFsmTimeoutTimer)); + + /* Release channel requested. */ + p2pFuncReleaseCh(prAdapter, &(prP2pFsmInfo->rChnlReqInfo)); + + } while (FALSE); + + return; + +} /* p2pStateAbort_GC_JOIN */ + + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/nic/p2p_nic.c b/drivers/mtk_wcn_combo/drv_wlan/p2p/nic/p2p_nic.c new file mode 100755 index 000000000000..08240eb03e93 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/nic/p2p_nic.c @@ -0,0 +1,243 @@ +/* +** $Id: @(#) p2p_nic.c@@ +*/ + +/*! \file p2p_nic.c + \brief Wi-Fi Direct Functions that provide operation in NIC's (Network Interface Card) point of view. + + This file includes functions which unite multiple hal(Hardware) operations + and also take the responsibility of Software Resource Management in order + to keep the synchronization with Hardware Manipulation. +*/ + + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "p2p_precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief When Probe Rsp & Beacon frame is received and decide a P2P device, +* this function will be invoked to buffer scan result +* +* @param prAdapter Pointer to the Adapter structure. +* @param prEventScanResult Pointer of EVENT_SCAN_RESULT_T. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicRxAddP2pDevice ( + IN P_ADAPTER_T prAdapter, + IN P_EVENT_P2P_DEV_DISCOVER_RESULT_T prP2pResult, + IN PUINT_8 pucRxIEBuf, + IN UINT_16 u2RxIELength + ) +{ + P_P2P_INFO_T prP2pInfo = (P_P2P_INFO_T)NULL; + P_EVENT_P2P_DEV_DISCOVER_RESULT_T prTargetResult = (P_EVENT_P2P_DEV_DISCOVER_RESULT_T)NULL; + UINT_32 u4Idx = 0; + BOOLEAN bUpdate = FALSE; + + PUINT_8 pucIeBuf = (PUINT_8)NULL; + UINT_16 u2IELength = 0; + UINT_8 zeroMac[] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; + + ASSERT(prAdapter); + + prP2pInfo = prAdapter->prP2pInfo; + + for (u4Idx = 0; u4Idx < prP2pInfo->u4DeviceNum; u4Idx++) { + prTargetResult = &prP2pInfo->arP2pDiscoverResult[u4Idx]; + + if (EQUAL_MAC_ADDR(prTargetResult->aucDeviceAddr, prP2pResult->aucDeviceAddr)) { + bUpdate = TRUE; + + /* Backup OLD buffer result. */ + pucIeBuf = prTargetResult->pucIeBuf; + u2IELength = prTargetResult->u2IELength; + + /* Update Device Info. */ + // zero + kalMemZero(prTargetResult, sizeof(EVENT_P2P_DEV_DISCOVER_RESULT_T)); + + // then buffer + kalMemCopy(prTargetResult, + (PVOID)prP2pResult, + sizeof(EVENT_P2P_DEV_DISCOVER_RESULT_T)); + + /* See if new IE length is longer or not. */ + if ((u2RxIELength > u2IELength) && (u2IELength != 0)) { + /* Buffer is not enough. */ + u2RxIELength = u2IELength; + } + else if ((u2IELength == 0) && (u2RxIELength != 0)) { + /* RX new IE buf. */ + ASSERT(pucIeBuf == NULL); + pucIeBuf = prP2pInfo->pucCurrIePtr; + + if (((UINT_32)prP2pInfo->pucCurrIePtr + (UINT_32)u2RxIELength) > + (UINT_32)&prP2pInfo->aucCommIePool[CFG_MAX_COMMON_IE_BUF_LEN]) { + /* Common Buffer is no enough. */ + u2RxIELength = (UINT_16)((UINT_32)&prP2pInfo->aucCommIePool[CFG_MAX_COMMON_IE_BUF_LEN] - (UINT_32)prP2pInfo->pucCurrIePtr); + } + + /* Step to next buffer address. */ + prP2pInfo->pucCurrIePtr = (PUINT_8)((UINT_32)prP2pInfo->pucCurrIePtr + (UINT_32)u2RxIELength); + } + + /* Restore buffer pointer. */ + prTargetResult->pucIeBuf = pucIeBuf; + + if (pucRxIEBuf) { + /* If new received IE is availabe. + * Replace the old one & update new IE length. + */ + kalMemCopy(pucIeBuf, pucRxIEBuf, u2RxIELength); + prTargetResult->u2IELength = u2RxIELength; + } + else { + /* There is no new IE information, keep the old one. */ + prTargetResult->u2IELength = u2IELength; + } + } + } + + if (!bUpdate) { + /* We would flush the whole scan result after each scan request is issued. + * If P2P device is too many, it may over the scan list. + */ + if ((u4Idx < CFG_MAX_NUM_BSS_LIST) && (UNEQUAL_MAC_ADDR(zeroMac, prP2pResult->aucDeviceAddr))) { /* whsu:XXX */ + prTargetResult = &prP2pInfo->arP2pDiscoverResult[u4Idx]; + + // zero + kalMemZero(prTargetResult, sizeof(EVENT_P2P_DEV_DISCOVER_RESULT_T)); + + // then buffer + kalMemCopy(prTargetResult, + (PVOID)prP2pResult, + sizeof(EVENT_P2P_DEV_DISCOVER_RESULT_T)); + + //printk("DVC FND %d " MACSTR", " MACSTR "\n", prP2pInfo->u4DeviceNum, MAC2STR(prP2pResult->aucDeviceAddr), MAC2STR(prTargetResult->aucDeviceAddr)); + + if (u2RxIELength) { + prTargetResult->pucIeBuf = prP2pInfo->pucCurrIePtr; + + if (((UINT_32)prP2pInfo->pucCurrIePtr + (UINT_32)u2RxIELength) > + (UINT_32)&prP2pInfo->aucCommIePool[CFG_MAX_COMMON_IE_BUF_LEN]) { + /* Common Buffer is no enough. */ + u2IELength = (UINT_16)((UINT_32)&prP2pInfo->aucCommIePool[CFG_MAX_COMMON_IE_BUF_LEN] - (UINT_32)prP2pInfo->pucCurrIePtr); + } + else { + u2IELength = u2RxIELength; + } + + prP2pInfo->pucCurrIePtr = (PUINT_8)((UINT_32)prP2pInfo->pucCurrIePtr + (UINT_32)u2IELength); + + kalMemCopy((PVOID)prTargetResult->pucIeBuf, (PVOID)pucRxIEBuf, (UINT_32)u2IELength); + prTargetResult->u2IELength = u2IELength; + } + else { + prTargetResult->pucIeBuf = NULL; + prTargetResult->u2IELength = 0; + } + + prP2pInfo->u4DeviceNum++; + + } + else { + // TODO: Fixme to replace an old one. (?) + ASSERT(FALSE); + } + } +} /* nicRxAddP2pDevice */ + + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/gl_p2p.c b/drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/gl_p2p.c new file mode 100755 index 000000000000..beae128dcad4 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/gl_p2p.c @@ -0,0 +1,5405 @@ +/* +** $Id: @(#) gl_p2p.c@@ +*/ + +/*! \file gl_p2p.c + \brief Main routines of Linux driver interface for Wi-Fi Direct + + This file contains the main routines of Linux driver for MediaTek Inc. 802.11 + Wireless LAN Adapters. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: gl_p2p.c $ + * + * 03 26 2012 yuche.tsai + * [ALPS00255551] [WiFi direct][Google Issue]GC can't send picture to GO sometimes,GO and GC can't ping each other + * Avoid ran out of driver resource when starting GO. + * + * 02 24 2012 yuche.tsai + * [ALPS00240756] [WiFi direct]After accept PBC request,DVT pops Kernel Defect.Powering off DVT causes DVT reboots automatcially and pops up KE(once) + * Fix GO dissolving issue to avoid FW assert. + * + * 02 23 2012 chinglan.wang + * [ALPS00240621] [Wifi P2P]Run Sigma tool of A69. Always run fail on 7.1.3. sniffer check Sta-IsActive-No-Frames-With-PowerMgmt-1 + * . + * + * 02 21 2012 yuche.tsai + * [ALPS00239729] [Monkey][WiFi Direct][Driver] Avoid invalid function access after driver unload + * Refine error fix. + * + * 02 21 2012 yuche.tsai + * [ALPS00239729] [Monkey][WiFi Direct][Driver] Avoid invalid function access after driver unload + * Refine error fix of net device operation unregister. + * + * 02 21 2012 yuche.tsai + * [ALPS00239729] [Monkey][WiFi Direct][Driver] Avoid invalid function access after driver unload + * Avoid the net device operations been referenced by the kernel after device un-registered. + * + * 02 14 2012 yuche.tsai + * [ALPS00118350] [ALPS.ICS][WiFi Direct] Dirver update for wifi direct connection + * Replace Beacon/Probe Response IE by driver generating instead of from supplicant. + * + * 02 09 2012 yuche.tsai + * [ALPS00233022] [klocwork 9.1] in gl_p2p.c, line 4338 + * After code fix. + * + * 02 09 2012 yuche.tsai + * [ALPS00118350] [ALPS.ICS][WiFi Direct] Dirver update for wifi direct connection + * Before code fix. + * + * 02 09 2012 yuche.tsai + * [ALPS00233021] [klocwork 9.1] in gl_p2p.c, line 1895 + * After code fix. + * + * 02 09 2012 yuche.tsai + * [ALPS00233021] [klocwork 9.1] in gl_p2p.c, line 1895 + * Before fix. + * + * 02 09 2012 yuche.tsai + * [ALPS00233019] [klocwork 9.1] in gl_p2p.c, line 1832 + * After code fix. + * + * 02 09 2012 yuche.tsai + * [ALPS00233019] [klocwork 9.1] in gl_p2p.c, line 1832 + * Before fixing warning code. + * + * 02 08 2012 yuche.tsai + * [ALPS00118350] [ALPS.ICS][WiFi Direct] Dirver update for wifi direct connection + * Try to fix clockwork warning. + * + * 02 06 2012 yuche.tsai + * [ALPS00118350] [ALPS.ICS][WiFi Direct] Dirver update for wifi direct connection + * Small bug fix for CNM memory usage, scan SSID search issue, P2P network deactivate issue. + * + * 01 31 2012 yuche.tsai + * NULL + * Fix compile error & del beacon scenario. + * + * 01 26 2012 yuche.tsai + * NULL + * Fix compile warning. + * + * 01 18 2012 yuche.tsai + * NULL + * Add get station info API. + * TX deauth before start beacon. + * + * 01 16 2012 chinglan.wang + * NULL + * Update security code.. + * + * 01 16 2012 yuche.tsai + * NULL + * Update security code. + * + * 01 15 2012 yuche.tsai + * NULL + * ICS P2P Driver Update. + * + * 01 15 2012 yuche.tsai + * NULL + * ICS Wi-Fi Direct Update. + * + * 01 13 2012 yuche.tsai + * NULL + * Update driver/p2p driver for ICS tethering mode. + * Fix FW reply probe request issue. + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Tethering for ICS code update. - fix KE when indicate Probe Request. + * + * 01 13 2012 yuche.tsai + * NULL + * Update WiFi tethering driver for ICS. + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Hot Spot Tethering for ICS ALPHA testing version. + * + * 01 09 2012 terry.wu + * [WCXRP00001166] [Wi-Fi] [Driver] cfg80211 integration for p2p newtork + * cfg80211 integration for p2p network. + * + * 12 19 2011 terry.wu + * [WCXRP00001142] [Wi-Fi] [P2P Driver] XOR local admin bit to generate p2p net device MAC + * XOR local administrated bit to generate net device MAC of p2p network. + * + * 12 02 2011 yuche.tsai + * NULL + * Fix possible KE when unload p2p. + * + * 11 24 2011 yuche.tsai + * NULL + * Fix P2P IOCTL of multicast address bug, add low power driver stop control. + * + * 11 22 2011 yuche.tsai + * NULL + * Update RSSI link quality of P2P Network query method. (Bug fix) + * + * 11 19 2011 yuche.tsai + * NULL + * Add RSSI support for P2P network. + * + * 11 16 2011 yuche.tsai + * [WCXRP00001107] [Volunteer Patch][Driver] Large Network Type index assert in FW issue. + * Avoid using work thread in set p2p multicast address callback. + * + * 11 11 2011 yuche.tsai + * NULL + * Fix work thread cancel issue. + * + * 11 11 2011 yuche.tsai + * NULL + * Fix default device name issue. + * + * 11 08 2011 yuche.tsai + * [WCXRP00001094] [Volunteer Patch][Driver] Driver version & supplicant version query & set support for service discovery version check. + * Add support for driver version query & p2p supplicant verseion set. + * For new service discovery mechanism sync. + * + * 11 07 2011 yuche.tsai + * NULL + * [ALPS 00087243] KE in worker thread. + * The multicast address list is scheduled in worker thread. + * Before the worker thread is excuted, if P2P is unloaded, a KE may occur. + * + * 10 26 2011 terry.wu + * [WCXRP00001066] [MT6620 Wi-Fi] [P2P Driver] Fix P2P Oid Issue + * Fix some P2P OID functions didn't raise its flag "fgIsP2pOid" issue. + * + * 10 25 2011 cm.chang + * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode + * . + * + * 10 18 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Support Channle Query. + * + * 10 18 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * New 2.1 branch + + * + * 08 26 2011 yuche.tsai + * NULL + * Fix bug of parsing secondary device list type issue. + * + * 08 24 2011 yuche.tsai + * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. + * Invitation Abort. + * + * 08 23 2011 yuche.tsai + * NULL + * Fix multicast address list issue of P2P. + * + * 08 22 2011 chinglan.wang + * NULL + * Fix invitation indication bug.. + * + * 08 16 2011 cp.wu + * [WCXRP00000934] [MT6620 Wi-Fi][Driver][P2P] Wi-Fi hot spot with auto sparse channel residence + * auto channel decision for 2.4GHz hot spot mode + * + * 08 16 2011 chinglan.wang + * NULL + * Add the group id information in the invitation indication. + * + * 08 09 2011 yuche.tsai + * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. + * Invitation Feature add on. + * + * 08 05 2011 yuche.tsai + * [WCXRP00000856] [Volunteer Patch][WiFi Direct][Driver] MT6620 WiFi Direct IOT Issue with BCM solution. + * Add Password ID check for quick connection. + * Also modify some connection policy. + * + * 07 18 2011 chinglan.wang + * NULL + * Add IOC_P2P_GO_WSC_IE (p2p capability). + * + * 06 14 2011 yuche.tsai + * NULL + * Add compile flag to disable persistent group support. + * + * 05 04 2011 chinglan.wang + * [WCXRP00000698] [MT6620 Wi-Fi][P2P][Driver] Add p2p invitation command for the p2p driver + * . + * + * 05 02 2011 yuche.tsai + * [WCXRP00000693] [Volunteer Patch][MT6620][Driver] Clear Formation Flag after TX lifetime timeout. + * Clear flag after Tx lifetime timeout of GO NEGO frame. + * + * 04 22 2011 george.huang + * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode + * . + * + * 04 21 2011 george.huang + * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode + * 1. Revise P2P power mode setting. + * 2. Revise fast-PS for concurrent + * + * 04 19 2011 wh.su + * NULL + * Adding length check before doing WPA & WPS IE parsing. + * + * 04 10 2011 yuche.tsai + * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. + * Rix retest 6.1.10 fail issue. + * + * 04 10 2011 yuche.tsai + * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. + * Add device discoverability support. (Phase I) + * + * 04 08 2011 george.huang + * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode + * separate settings of P2P and AIS + * + * 04 07 2011 terry.wu + * [WCXRP00000619] [MT6620 Wi-Fi][Driver] fix kernel panic may occur when removing wlan + * Fix kernel panic may occur when removing wlan driver. + * + * 03 31 2011 wh.su + * [WCXRP00000614] [MT6620 Wi-Fi][Driver] P2P: Update beacon content while setting WSC IE + * Update the wsc ie to beacon content. + * + * 03 29 2011 wh.su + * [WCXRP00000095] [MT6620 Wi-Fi] [FW] Refine the P2P GO send broadcast protected code + * add the set power and get power function sample. + * + * 03 25 2011 yuche.tsai + * NULL + * Improve some error handleing. + * + * 03 22 2011 george.huang + * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command + * link with supplicant commands + * + * 03 22 2011 yuche.tsai + * NULL + * 1. Fix formation policy issue. + * 2. Fix LISTEN channel issue. + * 3. Fix Target IF address in-correct issue when being GO. + * + * 03 19 2011 terry.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 p2p driver release based on label "MT6620_WIFI_P2P_DRIVER_V2_0_2100_0319_2011" from main trunk. + * + * 03 18 2011 yuche.tsai + * [WCXRP00000574] [Volunteer Patch][MT6620][Driver] Modify P2P FSM Connection Flow + * Modify connection flow after Group Formation Complete, or device connect to a GO. + * Instead of request channel & connect directly, we use scan to allocate channel bandwidth & connect after RX BCN. + * + * 03 15 2011 wh.su + * [WCXRP00000563] [MT6620 Wi-Fi] [P2P] Set local config method while set password Id ready + * set lccal config method method while set password Id ready. + * + * 03 15 2011 yuche.tsai + * [WCXRP00000560] [Volunteer Patch][MT6620][Driver] P2P Connection from UI using KEY/DISPLAY issue + * Fix some configure method issue. + * + * 03 15 2011 jeffrey.chang + * [WCXRP00000558] [MT6620 Wi-Fi][MT6620 Wi-Fi][Driver] refine the queue selection algorithm for WMM + * refine queue_select function + * + * 03 13 2011 wh.su + * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done + * add code for avoid compiling warning. + * + * 03 10 2011 yuche.tsai + * NULL + * Add P2P API. + * + * 03 10 2011 terry.wu + * [WCXRP00000505] [MT6620 Wi-Fi][Driver/FW] WiFi Direct Integration + * Remove unnecessary assert and message. + * + * 03 08 2011 wh.su + * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver + * support the power save related p2p setting. + * + * 03 07 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * rename the define to anti_pviracy. + * + * 03 05 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * add the code to get the check rsponse and indicate to app. + * + * 03 03 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * support concurrent network + * + * 03 03 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * modify P2P's netdevice functions to support multiple H/W queues + * + * 03 03 2011 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service Discovery + * for get request, the buffer length to be copied is header + payload. + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * add code to let the beacon and probe response for Auto GO WSC . + * + * 03 02 2011 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service Discovery + * add a missed break. + * + * 03 01 2011 yuche.tsai + * [WCXRP00000501] [Volunteer Patch][MT6620][Driver] No common channel issue when doing GO formation + * Update channel issue when doing GO formation.. + * + * 02 25 2011 wh.su + * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver + * add the Operation channel setting. + * + * 02 23 2011 wh.su + * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver + * fixed the set int ioctl set index and value map to driver issue. + * + * 02 22 2011 wh.su + * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver + * adding the ioctl set int from supplicant, and can used to set the p2p paramters + * + * 02 21 2011 terry.wu + * [WCXRP00000476] [MT6620 Wi-Fi][Driver] Clean P2P scan list while removing P2P + * Clean P2P scan list while removing P2P. + * + * 02 18 2011 wh.su + * [WCXRP00000471] [MT6620 Wi-Fi][Driver] Add P2P Provison discovery append Config Method attribute at WSC IE + * fixed the ioctl setting that index not map to spec defined config method. + * + * 02 17 2011 wh.su + * [WCXRP00000471] [MT6620 Wi-Fi][Driver] Add P2P Provison discovery append Config Method attribute at WSC IE + * append the WSC IE config method attribute at provision discovery request. + * + * 02 17 2011 wh.su + * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request + * modify the structure pointer for set WSC IE. + * + * 02 16 2011 wh.su + * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request + * fixed the probe request send out without WSC IE issue (at P2P). + * + * 02 09 2011 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service Discovery + * fix typo + * + * 02 09 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Add Support for MLME deauthentication for Hot-Spot. + * + * 01 25 2011 terry.wu + * [WCXRP00000393] [MT6620 Wi-Fi][Driver] Add new module insert parameter + * Add a new module parameter to indicate current runnig mode, P2P or AP. + * + * 01 12 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * 1. Modify Channel Acquire Time of AP mode from 5s to 1s. + * 2. Call cnmP2pIsPermit() before active P2P network. + * 3. Add channel selection support for AP mode. + * + * 01 05 2011 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service Discovery + * ioctl implementations for P2P Service Discovery + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease physically continous memory demands + * separate kalMemAlloc() into virtually-continous and physically-continous type to ease slab system pressure + * + * 12 22 2010 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service Discovery + * 1. header file restructure for more clear module isolation + * 2. add function interface definition for implementing Service Discovery callbacks + * + * 12 15 2010 cp.wu + * NULL + * invoke nicEnableInterrupt() before leaving from wlanAdapterStart() + * + * 12 08 2010 yuche.tsai + * [WCXRP00000245] [MT6620][Driver] Invitation & Provision Discovery Feature Check-in + * [WCXRP000000245][MT6620][Driver] Invitation Request Feature Add + * + * 11 30 2010 yuche.tsai + * NULL + * Invitation & Provision Discovery Indication. + * + * 11 17 2010 wh.su + * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID[WCXRP00000179] [MT6620 Wi-Fi][FW] Set the Tx lowest rate at wlan table for normal operation + * fixed some ASSERT check. + * + * 11 04 2010 wh.su + * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID + * adding the p2p random ssid support. + * + * 10 20 2010 wh.su + * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group + * Add the code to support disconnect p2p group + * + * 10 04 2010 wh.su + * [WCXRP00000081] [MT6620][Driver] Fix the compiling error at WinXP while enable P2P + * add a kal function for set cipher. + * + * 10 04 2010 wh.su + * [WCXRP00000081] [MT6620][Driver] Fix the compiling error at WinXP while enable P2P + * fixed compiling error while enable p2p. + * + * 09 28 2010 wh.su + * NULL + * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. + * + * 09 21 2010 kevin.huang + * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface + * Isolate P2P related function for Hardware Software Bundle + * + * 09 21 2010 kevin.huang + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * Eliminate Linux Compile Warning + * + * 09 10 2010 george.huang + * NULL + * update iwpriv LP related + * + * 09 10 2010 wh.su + * NULL + * fixed the compiling error at win XP. + * + * 09 09 2010 cp.wu + * NULL + * add WPS/WPA/RSN IE for Wi-Fi Direct scanning result. + * + * 09 07 2010 wh.su + * NULL + * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. + * + * 09 06 2010 wh.su + * NULL + * let the p2p can set the privacy bit at beacon and rsn ie at assoc req at key handshake state. + * + * 08 25 2010 cp.wu + * NULL + * add netdev_ops(NDO) for linux kernel 2.6.31 or greater + * + * 08 23 2010 cp.wu + * NULL + * revise constant definitions to be matched with implementation (original cmd-event definition is deprecated) + * + * 08 20 2010 cp.wu + * NULL + * correct typo. + * + * 08 20 2010 yuche.tsai + * NULL + * Invert Connection request provision status parameter. + * + * 08 19 2010 cp.wu + * NULL + * add set mac address interface for further possibilities of wpa_supplicant overriding interface address. + * + * 08 18 2010 cp.wu + * NULL + * modify pwp ioctls attribution by removing FIXED_SIZE. + * + * 08 18 2010 jeffrey.chang + * NULL + * support multi-function sdio + * + * 08 17 2010 cp.wu + * NULL + * correct p2p net device registration with NULL pointer access issue. + * + * 08 16 2010 cp.wu + * NULL + * P2P packets are now marked when being queued into driver, and identified later without checking MAC address + * + * 08 16 2010 cp.wu + * NULL + * add subroutines for P2P to set multicast list. + * + * 08 16 2010 george.huang + * NULL + * add wext handlers to link P2P set PS profile/ network address function (TBD) + * + * 08 16 2010 cp.wu + * NULL + * revised implementation of Wi-Fi Direct io controls. + * + * 08 12 2010 cp.wu + * NULL + * follow-up with ioctl interface update for Wi-Fi Direct application + * + * 08 06 2010 cp.wu + * NULL + * driver hook modifications corresponding to ioctl interface change. + * + * 08 03 2010 cp.wu + * NULL + * add basic support for ioctl of getting scan result. (only address and SSID are reporterd though) + * + * 08 03 2010 cp.wu + * NULL + * [Wi-Fi Direct Driver Hook] change event indication API to be consistent with supplicant + * + * 08 03 2010 cp.wu + * NULL + * surpress compilation warning. + * + * 08 03 2010 cp.wu + * NULL + * [Wi-Fi Direct] add framework for driver hooks + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 23 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * p2p interface revised to be sync. with HAL + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 06 01 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add ioctl to configure scan mode for p2p connection + * + * 05 31 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add cfg80211 interface, which is to replace WE, for further extension + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * implement private io controls for Wi-Fi Direct + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * implement get scan result. + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add basic handling framework for wireless extension ioctls. + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * 1) add timeout handler mechanism for pending command packets + * 2) add p2p add/removal key + * + * 05 14 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * implement wireless extension ioctls in iw_handler form. + * + * 05 14 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add ioctl framework for Wi-Fi Direct by reusing wireless extension ioctls as well + * + * 05 11 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * p2p ioctls revised. + * + * 05 11 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add ioctl for controlling p2p scan phase parameters + * + * 05 10 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * implement basic wi-fi direct framework + * + * 05 07 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add basic framework for implementating P2P driver hook. + * +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "gl_os.h" +#include "debug.h" +#include "wlan_lib.h" +#include "gl_wext.h" +#include + +#include +//#include +#include "gl_p2p_ioctl.h" + +#include "p2p_precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define ARGV_MAX_NUM (4) + +/*For CFG80211 - wiphy parameters*/ +#define MAX_SCAN_LIST_NUM (1) +#define MAX_SCAN_IE_LEN (512) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 +/* for cfg80211 - frequency table */ +/* default channel table for p2p network and WILL BE UPDATED based on device country code */ +static struct ieee80211_channel mtk_2ghz_channels[] = { + CHAN2G(1, 2412, 0), + CHAN2G(2, 2417, 0), + CHAN2G(3, 2422, 0), + CHAN2G(4, 2427, 0), + CHAN2G(5, 2432, 0), + CHAN2G(6, 2437, 0), + CHAN2G(7, 2442, 0), + CHAN2G(8, 2447, 0), + CHAN2G(9, 2452, 0), + CHAN2G(10, 2457, 0), + CHAN2G(11, 2462, 0), + CHAN2G(12, 2467, 0), + CHAN2G(13, 2472, 0), + CHAN2G(14, 2484, 0), +}; + +static struct ieee80211_channel mtk_5ghz_a_channels[] = { + CHAN5G(34, 0), CHAN5G(36, 0), + CHAN5G(38, 0), CHAN5G(40, 0), + CHAN5G(42, 0), CHAN5G(44, 0), + CHAN5G(46, 0), CHAN5G(48, 0), + CHAN5G(52, 0), CHAN5G(56, 0), + CHAN5G(60, 0), CHAN5G(64, 0), + CHAN5G(100, 0), CHAN5G(104, 0), + CHAN5G(108, 0), CHAN5G(112, 0), + CHAN5G(116, 0), CHAN5G(120, 0), + CHAN5G(124, 0), CHAN5G(128, 0), + CHAN5G(132, 0), CHAN5G(136, 0), + CHAN5G(140, 0), CHAN5G(149, 0), + CHAN5G(153, 0), CHAN5G(157, 0), + CHAN5G(161, 0), CHAN5G(165, 0), + CHAN5G(169, 0), CHAN5G(173, 0), + CHAN5G(184, 0), CHAN5G(188, 0), + CHAN5G(192, 0), CHAN5G(196, 0), + CHAN5G(200, 0), CHAN5G(204, 0), + CHAN5G(208, 0), CHAN5G(212, 0), + CHAN5G(216, 0), +}; + +/* for cfg80211 - rate table */ +static struct ieee80211_rate mtk_rates[] = { + RATETAB_ENT(10, 0x1000, 0), + RATETAB_ENT(20, 0x1001, 0), + RATETAB_ENT(55, 0x1002, 0), + RATETAB_ENT(110, 0x1003, 0), /* 802.11b */ + RATETAB_ENT(60, 0x2000, 0), + RATETAB_ENT(90, 0x2001, 0), + RATETAB_ENT(120, 0x2002, 0), + RATETAB_ENT(180, 0x2003, 0), + RATETAB_ENT(240, 0x2004, 0), + RATETAB_ENT(360, 0x2005, 0), + RATETAB_ENT(480, 0x2006, 0), + RATETAB_ENT(540, 0x2007, 0), /* 802.11a/g */ +}; + +#define mtk_a_rates (mtk_rates + 4) +#define mtk_a_rates_size (sizeof(mtk_rates) / sizeof(mtk_rates[0]) - 4) +#define mtk_g_rates (mtk_rates + 0) +#define mtk_g_rates_size (sizeof(mtk_rates) / sizeof(mtk_rates[0]) - 0) + +#define MT6620_MCS_INFO \ +{ \ + /* MCS1~7*/ \ + .rx_mask = {0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0},\ + .rx_highest = 0, \ + .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \ +} + +#if 0 +/*Bandwidth 20Mhz Only*/ +#define MT6620_HT_CAP \ +{ \ + .ht_supported = true, \ + .cap = IEEE80211_HT_CAP_SM_PS \ + | IEEE80211_HT_CAP_GRN_FLD \ + | IEEE80211_HT_CAP_SGI_20, \ + .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, \ + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE, \ + .mcs = MT6620_MCS_INFO, \ +} +#else +/*Bandwidth 20/40Mhz*/ +#define MT6620_HT_CAP \ +{ \ + .ht_supported = true, \ + .cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 \ + | IEEE80211_HT_CAP_SM_PS \ + | IEEE80211_HT_CAP_GRN_FLD \ + | IEEE80211_HT_CAP_SGI_20 \ + | IEEE80211_HT_CAP_SGI_40, \ + .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, \ + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE, \ + .mcs = MT6620_MCS_INFO, \ +} +#endif + +static struct ieee80211_supported_band mtk_band_2ghz = { + .band = IEEE80211_BAND_2GHZ, + .channels = mtk_2ghz_channels, + .n_channels = ARRAY_SIZE(mtk_2ghz_channels), + .bitrates = mtk_g_rates, + .n_bitrates = mtk_g_rates_size, + .ht_cap = MT6620_HT_CAP, +}; + +static struct ieee80211_supported_band mtk_band_5ghz = { + .band = IEEE80211_BAND_5GHZ, + .channels = mtk_5ghz_a_channels, + .n_channels = ARRAY_SIZE(mtk_5ghz_a_channels), + .bitrates = mtk_a_rates, + .n_bitrates = mtk_a_rates_size, + .ht_cap = MT6620_HT_CAP, +}; + +static const UINT_32 cipher_suites[] = { + /* keep WEP first, it may be removed below */ + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, + + /* keep last -- depends on hw flags! */ + WLAN_CIPHER_SUITE_AES_CMAC +}; + +static struct cfg80211_ops mtk_p2p_config_ops = { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && (CFG_ENABLE_WIFI_DIRECT_CFG_80211 != 0) + /* Froyo */ + .change_virtual_intf = mtk_p2p_cfg80211_change_iface, // 1 st + .change_bss = mtk_p2p_cfg80211_change_bss, + .scan = mtk_p2p_cfg80211_scan, + .remain_on_channel = mtk_p2p_cfg80211_remain_on_channel, + .cancel_remain_on_channel = mtk_p2p_cfg80211_cancel_remain_on_channel, + .mgmt_tx = mtk_p2p_cfg80211_mgmt_tx, + .connect = mtk_p2p_cfg80211_connect, + .disconnect = mtk_p2p_cfg80211_disconnect, + .deauth = mtk_p2p_cfg80211_deauth, + .disassoc = mtk_p2p_cfg80211_disassoc, + .add_beacon = mtk_p2p_cfg80211_add_set_beacon, + .set_beacon = mtk_p2p_cfg80211_add_set_beacon, + .del_beacon = mtk_p2p_cfg80211_del_beacon, + .set_wiphy_params = mtk_p2p_cfg80211_set_wiphy_params, + .del_station = mtk_p2p_cfg80211_del_station, + .set_channel = mtk_p2p_cfg80211_set_channel, + .set_bitrate_mask = mtk_p2p_cfg80211_set_bitrate_mask, + .mgmt_frame_register = mtk_p2p_cfg80211_mgmt_frame_register, + .get_station = mtk_p2p_cfg80211_get_station, + // ================ + .add_key = mtk_p2p_cfg80211_add_key, + .get_key = mtk_p2p_cfg80211_get_key, + .del_key = mtk_p2p_cfg80211_del_key, + .set_default_key = mtk_p2p_cfg80211_set_default_key, + .join_ibss = mtk_p2p_cfg80211_join_ibss, + .leave_ibss = mtk_p2p_cfg80211_leave_ibss, + .set_tx_power = mtk_p2p_cfg80211_set_txpower, + .get_tx_power = mtk_p2p_cfg80211_get_txpower, + .set_power_mgmt = mtk_p2p_cfg80211_set_power_mgmt, + #ifdef CONFIG_NL80211_TESTMODE + .testmode_cmd = mtk_p2p_cfg80211_testmode_cmd, + #endif +#endif +}; + + + +/* There isn't a lot of sense in it, but you can transmit anything you like */ +static const struct ieee80211_txrx_stypes +mtk_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { + [NL80211_IFTYPE_ADHOC] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_STATION] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_AP] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_AP_VLAN] = { + /* copy AP */ + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_P2P_CLIENT] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_P2P_GO] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4) + } +}; + + + +#endif + +/* the legacy wireless extension stuff */ +static const iw_handler rP2PIwStandardHandler[] = { + [SIOCGIWPRIV - SIOCIWFIRST] = mtk_p2p_wext_get_priv, + [SIOCGIWSCAN - SIOCIWFIRST] = mtk_p2p_wext_discovery_results, + [SIOCSIWESSID - SIOCIWFIRST] = mtk_p2p_wext_reconnect, + [SIOCSIWAUTH - SIOCIWFIRST] = mtk_p2p_wext_set_auth, + [SIOCSIWENCODEEXT - SIOCIWFIRST] = mtk_p2p_wext_set_key, + [SIOCSIWPOWER - SIOCIWFIRST] = mtk_p2p_wext_set_powermode, + [SIOCGIWPOWER - SIOCIWFIRST] = mtk_p2p_wext_get_powermode, + [SIOCSIWTXPOW - SIOCIWFIRST] = mtk_p2p_wext_set_txpow, +#if CFG_SUPPORT_P2P_RSSI_QUERY + [SIOCGIWSTATS - SIOCIWFIRST] = mtk_p2p_wext_get_rssi, +#endif + [SIOCSIWMLME - SIOCIWFIRST] = mtk_p2p_wext_mlme_handler, +}; + +static const iw_handler rP2PIwPrivHandler[] = { + [IOC_P2P_CFG_DEVICE - SIOCIWFIRSTPRIV] = mtk_p2p_wext_set_local_dev_info, + [IOC_P2P_PROVISION_COMPLETE - SIOCIWFIRSTPRIV] = mtk_p2p_wext_set_provision_complete, + [IOC_P2P_START_STOP_DISCOVERY - SIOCIWFIRSTPRIV] = mtk_p2p_wext_start_stop_discovery, + [IOC_P2P_DISCOVERY_RESULTS - SIOCIWFIRSTPRIV] = mtk_p2p_wext_discovery_results, + [IOC_P2P_WSC_BEACON_PROBE_RSP_IE - SIOCIWFIRSTPRIV] = mtk_p2p_wext_wsc_ie, + [IOC_P2P_CONNECT_DISCONNECT - SIOCIWFIRSTPRIV] = mtk_p2p_wext_connect_disconnect, + [IOC_P2P_PASSWORD_READY - SIOCIWFIRSTPRIV] = mtk_p2p_wext_password_ready, +// [IOC_P2P_SET_PWR_MGMT_PARAM - SIOCIWFIRSTPRIV] = mtk_p2p_wext_set_pm_param, + [IOC_P2P_SET_INT - SIOCIWFIRSTPRIV] = mtk_p2p_wext_set_int, + [IOC_P2P_GET_STRUCT - SIOCIWFIRSTPRIV] = mtk_p2p_wext_get_struct, + [IOC_P2P_SET_STRUCT - SIOCIWFIRSTPRIV] = mtk_p2p_wext_set_struct, + [IOC_P2P_GET_REQ_DEVICE_INFO - SIOCIWFIRSTPRIV] = mtk_p2p_wext_request_dev_info, +}; + + +static const struct iw_priv_args rP2PIwPrivTable[] = { + { + .cmd = IOC_P2P_CFG_DEVICE, + .set_args = IW_PRIV_TYPE_BYTE | (__u16)sizeof(IW_P2P_CFG_DEVICE_TYPE), + .get_args = IW_PRIV_TYPE_NONE, + .name = "P2P_CFG_DEVICE" + }, + { + .cmd = IOC_P2P_START_STOP_DISCOVERY, + .set_args = IW_PRIV_TYPE_BYTE | (__u16)sizeof(IW_P2P_REQ_DEVICE_TYPE), + .get_args = IW_PRIV_TYPE_NONE, + .name = "P2P_DISCOVERY" + }, + { + .cmd = IOC_P2P_DISCOVERY_RESULTS, + .set_args = IW_PRIV_TYPE_NONE, + .get_args = IW_PRIV_TYPE_NONE, + .name = "P2P_RESULT" + }, + { + .cmd = IOC_P2P_WSC_BEACON_PROBE_RSP_IE, + .set_args = IW_PRIV_TYPE_BYTE | (__u16)sizeof(IW_P2P_HOSTAPD_PARAM), + .get_args = IW_PRIV_TYPE_NONE, + .name = "P2P_WSC_IE" + }, + { + .cmd = IOC_P2P_CONNECT_DISCONNECT, + .set_args = IW_PRIV_TYPE_BYTE | (__u16)sizeof(IW_P2P_CONNECT_DEVICE), + .get_args = IW_PRIV_TYPE_NONE, + .name = "P2P_CONNECT" + }, + { + .cmd = IOC_P2P_PASSWORD_READY, + .set_args = IW_PRIV_TYPE_BYTE | (__u16)sizeof(IW_P2P_PASSWORD_READY), + .get_args = IW_PRIV_TYPE_NONE, + .name = "P2P_PASSWD_RDY" + }, + { + .cmd = IOC_P2P_GET_STRUCT, + .set_args = IW_PRIV_TYPE_NONE, + .get_args = 256, + .name = "P2P_GET_STRUCT" + }, + { + .cmd = IOC_P2P_SET_STRUCT, + .set_args = 256, + .get_args = IW_PRIV_TYPE_NONE, + .name = "P2P_SET_STRUCT" + }, + { + .cmd = IOC_P2P_GET_REQ_DEVICE_INFO, + .set_args = IW_PRIV_TYPE_NONE, + .get_args = IW_PRIV_TYPE_BYTE | (__u16)sizeof(IW_P2P_DEVICE_REQ), + .name = "P2P_GET_REQDEV" + }, + { + /* SET STRUCT sub-ioctls commands */ + .cmd = PRIV_CMD_OID, + .set_args = 256, + .get_args = IW_PRIV_TYPE_NONE, + .name = "set_oid" + }, + { + /* GET STRUCT sub-ioctls commands */ + .cmd = PRIV_CMD_OID, + .set_args = IW_PRIV_TYPE_NONE, + .get_args = 256, + .name = "get_oid" + } +}; + +const struct iw_handler_def mtk_p2p_wext_handler_def = { + .num_standard = (__u16)sizeof(rP2PIwStandardHandler)/sizeof(iw_handler), + .num_private = (__u16)sizeof(rP2PIwPrivHandler)/sizeof(iw_handler), + .num_private_args = (__u16)sizeof(rP2PIwPrivTable)/sizeof(struct iw_priv_args), + .standard = rP2PIwStandardHandler, + .private = rP2PIwPrivHandler, + .private_args = rP2PIwPrivTable, +#if CFG_SUPPORT_P2P_RSSI_QUERY + .get_wireless_stats = mtk_p2p_wext_get_wireless_stats, +#else + .get_wireless_stats = NULL, +#endif +}; + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/* for IE Searching */ +extern BOOLEAN +wextSrchDesiredWPAIE ( + IN PUINT_8 pucIEStart, + IN INT_32 i4TotalIeLen, + IN UINT_8 ucDesiredElemId, + OUT PUINT_8 *ppucDesiredIE + ); + +#if CFG_SUPPORT_WPS +extern BOOLEAN +wextSrchDesiredWPSIE ( + IN PUINT_8 pucIEStart, + IN INT_32 i4TotalIeLen, + IN UINT_8 ucDesiredElemId, + OUT PUINT_8 *ppucDesiredIE + ); +#endif + +/* Net Device Hooks */ +static int +p2pOpen( + IN struct net_device *prDev + ); + +static int +p2pStop( + IN struct net_device *prDev + ); + +static struct net_device_stats * +p2pGetStats ( + IN struct net_device *prDev + ); + +static void +p2pSetMulticastList( + IN struct net_device *prDev + ); + +static int +p2pHardStartXmit( + IN struct sk_buff *prSkb, + IN struct net_device *prDev + ); + +static int +p2pDoIOCTL( + struct net_device *prDev, + struct ifreq *prIFReq, + int i4Cmd + ); + +static int +p2pSetMACAddress( + IN struct net_device *prDev, + void *addr + ); + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Override the implementation of select queue +* +* \param[in] dev Pointer to struct net_device +* \param[in] skb Pointer to struct skb_buff +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ + +unsigned int _p2p_cfg80211_classify8021d(struct sk_buff *skb) +{ + unsigned int dscp = 0; + + /* skb->priority values from 256->263 are magic values + * directly indicate a specific 802.1d priority. This is + * to allow 802.1d priority to be passed directly in from + * tags + */ + + if (skb->priority >= 256 && skb->priority <= 263) { + return skb->priority - 256; + } + switch (skb->protocol) { + case htons(ETH_P_IP): + dscp = ip_hdr(skb)->tos & 0xfc; + break; + } + return dscp >> 5; +} + + +static const UINT_16 au16Wlan1dToQueueIdx[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; + +static UINT_16 +p2pSelectQueue( + struct net_device *dev, + struct sk_buff *skb) +{ + skb->priority = _p2p_cfg80211_classify8021d(skb); + + return au16Wlan1dToQueueIdx[skb->priority]; +} + +static struct net_device *g_P2pPrDev; + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief A function for prDev->init +* +* \param[in] prDev Pointer to struct net_device. +* +* \retval 0 The execution of wlanInit succeeds. +* \retval -ENXIO No such device. +*/ +/*----------------------------------------------------------------------------*/ +static int +p2pInit( + struct net_device *prDev + ) +{ + if (!prDev) { + return -ENXIO; + } + + return 0; /* success */ +} /* end of p2pInit() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief A function for prDev->uninit +* +* \param[in] prDev Pointer to struct net_device. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static void +p2pUninit ( + IN struct net_device *prDev + ) +{ + + + return; +} /* end of p2pUninit() */ + + + + + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) +static const struct net_device_ops p2p_netdev_ops = { + .ndo_open = p2pOpen, + .ndo_stop = p2pStop, + .ndo_set_mac_address = p2pSetMACAddress, + .ndo_set_multicast_list = p2pSetMulticastList, + .ndo_get_stats = p2pGetStats, + .ndo_do_ioctl = p2pDoIOCTL, + .ndo_start_xmit = p2pHardStartXmit, + .ndo_select_queue = p2pSelectQueue, + .ndo_init = p2pInit, + .ndo_uninit = p2pUninit, +}; + +static const struct net_device_ops p2p_null_ops = { + .ndo_open = NULL, + .ndo_stop = NULL, + .ndo_set_mac_address = NULL, + .ndo_set_multicast_list = NULL, + .ndo_get_stats = NULL, + .ndo_do_ioctl = NULL, + .ndo_start_xmit = NULL, + .ndo_select_queue = NULL, + .ndo_init = NULL, + .ndo_uninit = NULL, +}; + +#endif + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Allocate memory for P2P_INFO, GL_P2P_INFO, P2P_CONNECTION_SETTINGS +* P2P_SPECIFIC_BSS_INFO, P2P_FSM_INFO +* +* \param[in] prGlueInfo Pointer to glue info +* +* \return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +p2PAllocInfo( + P_GLUE_INFO_T prGlueInfo + ) +{ + P_ADAPTER_T prAdapter = NULL; + P_WIFI_VAR_T prWifiVar = NULL; + + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + prWifiVar = &(prAdapter->rWifiVar); + + ASSERT(prAdapter); + ASSERT(prWifiVar); + + /*alloc memory for p2p info */ + prGlueInfo->prP2PInfo = + kalMemAlloc(sizeof(GL_P2P_INFO_T), VIR_MEM_TYPE); + prAdapter->prP2pInfo = + kalMemAlloc(sizeof(P2P_INFO_T), VIR_MEM_TYPE); + prWifiVar->prP2PConnSettings = + kalMemAlloc(sizeof(P2P_CONNECTION_SETTINGS_T),VIR_MEM_TYPE); + prWifiVar->prP2pFsmInfo = + kalMemAlloc(sizeof(P2P_FSM_INFO_T),VIR_MEM_TYPE); + prWifiVar->prP2pSpecificBssInfo = + kalMemAlloc(sizeof(P2P_SPECIFIC_BSS_INFO_T),VIR_MEM_TYPE); + + /*MUST set memory to 0 */ + kalMemZero(prGlueInfo->prP2PInfo, sizeof(GL_P2P_INFO_T)); + kalMemZero(prAdapter->prP2pInfo, sizeof(P2P_INFO_T)); + kalMemZero(prWifiVar->prP2PConnSettings, sizeof(P2P_CONNECTION_SETTINGS_T)); + kalMemZero(prWifiVar->prP2pFsmInfo, sizeof(P2P_FSM_INFO_T)); + kalMemZero(prWifiVar->prP2pSpecificBssInfo, sizeof(P2P_SPECIFIC_BSS_INFO_T)); + + /* chk if alloc successful or not*/ + if (prGlueInfo->prP2PInfo && + prGlueInfo->prAdapter->prP2pInfo && + prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings && + prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo && + prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo) + { + return TRUE; + } + else { + return FALSE; + } + +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Free memory for P2P_INFO, GL_P2P_INFO, P2P_CONNECTION_SETTINGS +* P2P_SPECIFIC_BSS_INFO, P2P_FSM_INFO +* +* \param[in] prGlueInfo Pointer to glue info +* +* \return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +p2PFreeInfo( + P_GLUE_INFO_T prGlueInfo + ) +{ + + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prAdapter); + + /* free memory after p2p module is ALREADY unregistered */ + if(prGlueInfo->prAdapter->fgIsP2PRegistered == FALSE) { + + kalMemFree(prGlueInfo->prAdapter->prP2pInfo, VIR_MEM_TYPE, sizeof(P2P_INFO_T)); + kalMemFree(prGlueInfo->prP2PInfo, VIR_MEM_TYPE, sizeof(GL_P2P_INFO_T)); + kalMemFree(prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings, VIR_MEM_TYPE, sizeof(P2P_CONNECTION_SETTINGS_T)); + kalMemFree(prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo, VIR_MEM_TYPE, sizeof(P2P_FSM_INFO_T)); + kalMemFree(prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo, VIR_MEM_TYPE, sizeof(P2P_SPECIFIC_BSS_INFO_T)); + + /*Reomve p2p bss scan list*/ + scanRemoveAllP2pBssDesc(prGlueInfo->prAdapter); + + /*reset all pointer to NULL */ + prGlueInfo->prP2PInfo = NULL; + prGlueInfo->prAdapter->prP2pInfo = NULL; + prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings = NULL; + prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo = NULL; + prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo = NULL; + + return TRUE; + } + else { + return FALSE; + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Enable Channel for cfg80211 for Wi-Fi Direct based on current country code +* +* \param[in] prGlueInfo Pointer to glue info +* +* \return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pEnableChannel( + PUINT_8 pucChIdx, + UINT_8 ucChannelNum, + struct ieee80211_channel *mtk_channels, + UINT_8 mtk_channel_sz +) +{ + UINT_8 ucCurChIdx = *pucChIdx; + + while(TRUE) { + (*pucChIdx)++; + (*pucChIdx) %= mtk_channel_sz; + + if(ucChannelNum == mtk_channels[*pucChIdx].hw_value) { + mtk_channels[*pucChIdx].flags &= ~IEEE80211_CHAN_DISABLED; + break; + } + + if(*pucChIdx == ucCurChIdx) { + printk(KERN_ALERT DRV_NAME "Orphan channel [%d]\n", ucChannelNum); + break; + } + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Update Channel table for cfg80211 for Wi-Fi Direct based on current country code +* +* \param[in] prGlueInfo Pointer to glue info +* +* \return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pUpdateChannelTableByDomain( + P_GLUE_INFO_T prGlueInfo + ) +{ + UINT_8 i, uc2gChIdx, uc5gChIdx; + UINT_8 ucMaxChannelNum = ARRAY_SIZE(mtk_2ghz_channels) + ARRAY_SIZE(mtk_5ghz_a_channels); + UINT_8 ucNumOfChannel = ucMaxChannelNum; + RF_CHANNEL_INFO_T aucChannelList[ucMaxChannelNum]; + + uc2gChIdx = uc5gChIdx = 0; + + // 1. Disable all channel + for(i = 0; i < ARRAY_SIZE(mtk_2ghz_channels); i++) { + mtk_2ghz_channels[i].flags |= IEEE80211_CHAN_DISABLED; + } + for(i = 0; i < ARRAY_SIZE(mtk_5ghz_a_channels); i++) { + mtk_5ghz_a_channels[i].flags |= IEEE80211_CHAN_DISABLED; + } + + // 2. Get current domain channel list + rlmDomainGetChnlList(prGlueInfo->prAdapter, BAND_NULL, ucMaxChannelNum, &ucNumOfChannel, aucChannelList); + + // 3. Enable specific channel based on domain channel list + for(i = 0; i < ucNumOfChannel; i++) { + switch(aucChannelList[i].eBand) { + case BAND_2G4: + p2pEnableChannel(&uc2gChIdx, aucChannelList[i].ucChannelNum, mtk_2ghz_channels, ARRAY_SIZE(mtk_2ghz_channels)); + break; + + case BAND_5G: + p2pEnableChannel(&uc5gChIdx, aucChannelList[i].ucChannelNum, mtk_5ghz_a_channels, ARRAY_SIZE(mtk_5ghz_a_channels)); + break; + + default: + printk(KERN_ALERT DRV_NAME "Unknow band.\n"); + break; + + } + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Register for cfg80211 for Wi-Fi Direct +* +* \param[in] prGlueInfo Pointer to glue info +* +* \return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +glRegisterP2P( + P_GLUE_INFO_T prGlueInfo, + const char *prDevName, + BOOLEAN fgIsApMode + ) +{ + P_ADAPTER_T prAdapter = NULL; + P_GL_HIF_INFO_T prHif = NULL; + PARAM_MAC_ADDRESS rMacAddr; +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + struct device *prDev; +#endif + + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + prHif = &prGlueInfo->rHifInfo; + ASSERT(prHif); + + /*0. allocate p2pinfo */ + if(!p2PAllocInfo(prGlueInfo)) { + printk(KERN_ALERT DRV_NAME "Allocate memory for p2p FAILED\n"); + ASSERT(0); + return FALSE; + } +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + /* 1. allocate WIPHY */ + prGlueInfo->prP2PInfo->wdev.wiphy = wiphy_new(&mtk_p2p_config_ops, sizeof(P_GLUE_INFO_T)); + if (!prGlueInfo->prP2PInfo->wdev.wiphy) { + printk(KERN_ALERT DRV_NAME "unable to allocate wiphy for p2p\n"); + + goto err_alloc_wiphy; + } + + /* 1.1 fill wiphy parameters */ +#if MTK_WCN_HIF_SDIO + mtk_wcn_hif_sdio_get_dev(prHif->cltCtx, &prDev); + if(!prDev) { + printk(KERN_ALERT DRV_NAME "unable to get struct dev for p2p\n"); + } +#else + prDev = &(prHif->func->dev); +#endif + set_wiphy_dev(prGlueInfo->prP2PInfo->wdev.wiphy, prDev); + + prGlueInfo->prP2PInfo->wdev.wiphy->interface_modes = BIT(NL80211_IFTYPE_AP) + | BIT(NL80211_IFTYPE_P2P_CLIENT) + | BIT(NL80211_IFTYPE_P2P_GO) + | BIT(NL80211_IFTYPE_STATION); + + p2pUpdateChannelTableByDomain(prGlueInfo); + prGlueInfo->prP2PInfo->wdev.wiphy->bands[IEEE80211_BAND_2GHZ] = &mtk_band_2ghz; + if(prAdapter->fgEnable5GBand) { + prGlueInfo->prP2PInfo->wdev.wiphy->bands[IEEE80211_BAND_5GHZ] = &mtk_band_5ghz; + } + + prGlueInfo->prP2PInfo->wdev.wiphy->mgmt_stypes = mtk_cfg80211_default_mgmt_stypes; + prGlueInfo->prP2PInfo->wdev.wiphy->max_remain_on_channel_duration = 5000; + prGlueInfo->prP2PInfo->wdev.wiphy->n_cipher_suites = 5; + prGlueInfo->prP2PInfo->wdev.wiphy->cipher_suites = (const u32*)cipher_suites; + prGlueInfo->prP2PInfo->wdev.wiphy->flags = WIPHY_FLAG_CUSTOM_REGULATORY; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) + prGlueInfo->prP2PInfo->wdev.wiphy->max_scan_ssids = MAX_SCAN_LIST_NUM; + prGlueInfo->prP2PInfo->wdev.wiphy->max_scan_ie_len = MAX_SCAN_IE_LEN; + prGlueInfo->prP2PInfo->wdev.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; +#endif + + /* 2. Register WIPHY */ + if(wiphy_register(prGlueInfo->prP2PInfo->wdev.wiphy) < 0) { + printk(KERN_ALERT DRV_NAME "Couldn't register wiphy device for p2p\n"); + + goto err_reg_wiphy; + } + + /* 2.1 set priv as pointer to glue structure */ + *((P_GLUE_INFO_T *) wiphy_priv(prGlueInfo->prP2PInfo->wdev.wiphy)) = prGlueInfo; + + /* 2.2 wdev initialization */ + if(fgIsApMode) { + prGlueInfo->prP2PInfo->wdev.iftype = NL80211_IFTYPE_AP; + } else { + prGlueInfo->prP2PInfo->wdev.iftype = NL80211_IFTYPE_P2P_CLIENT; + } + +#endif /* CFG_ENABLE_WIFI_DIRECT_CFG_80211 */ + + /* 3. allocate netdev */ + prGlueInfo->prP2PInfo->prDevHandler = alloc_netdev_mq(sizeof(P_GLUE_INFO_T), prDevName, ether_setup, CFG_MAX_TXQ_NUM); + if (!prGlueInfo->prP2PInfo->prDevHandler) { + printk(KERN_ALERT DRV_NAME "unable to allocate netdevice for p2p\n"); + + goto err_alloc_netdev; + } + + /* 4. setup netdev */ + /* 4.1 Point to shared glue structure */ + *((P_GLUE_INFO_T *) netdev_priv(prGlueInfo->prP2PInfo->prDevHandler)) = prGlueInfo; + + /* 4.2 fill hardware address */ + COPY_MAC_ADDR(rMacAddr, prAdapter->rMyMacAddr); + rMacAddr[0] ^= 0x2; // change to local administrated address + memcpy(prGlueInfo->prP2PInfo->prDevHandler->dev_addr, rMacAddr, ETH_ALEN); + memcpy(prGlueInfo->prP2PInfo->prDevHandler->perm_addr, prGlueInfo->prP2PInfo->prDevHandler->dev_addr, ETH_ALEN); + + /* 4.3 register callback functions */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) + prGlueInfo->prP2PInfo->prDevHandler->netdev_ops = &p2p_netdev_ops; +#else + prGlueInfo->prP2PInfo->prDevHandler->open = p2pOpen; + prGlueInfo->prP2PInfo->prDevHandler->stop = p2pStop; + prGlueInfo->prP2PInfo->prDevHandler->get_stats = p2pGetStats; + prGlueInfo->prP2PInfo->prDevHandler->set_multicast_list = p2pSetMulticastList; + prGlueInfo->prP2PInfo->prDevHandler->hard_start_xmit = p2pHardStartXmit; + prGlueInfo->prP2PInfo->prDevHandler->do_ioctl = p2pDoIOCTL; + prGlueInfo->prP2PInfo->prDevHandler->set_mac_address = p2pSetMACAddress; +#endif +// prGlueInfo->prP2PInfo->prDevHandler->wireless_handlers = &mtk_p2p_wext_handler_def; + +#if (MTK_WCN_HIF_SDIO == 0) + SET_NETDEV_DEV(prGlueInfo->prP2PInfo->prDevHandler, &(prHif->func->dev)); +#endif + + +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + prGlueInfo->prP2PInfo->prDevHandler->ieee80211_ptr = &(prGlueInfo->prP2PInfo->wdev); + prGlueInfo->prP2PInfo->wdev.netdev = prGlueInfo->prP2PInfo->prDevHandler; +#endif + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + prGlueInfo->prP2PInfo->prDevHandler->features = NETIF_F_IP_CSUM; +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + + /* 7. net device initialize */ + netif_carrier_off(prGlueInfo->prP2PInfo->prDevHandler); + netif_tx_stop_all_queues(prGlueInfo->prP2PInfo->prDevHandler); + + /* 8. register for net device */ + if (register_netdev(prGlueInfo->prP2PInfo->prDevHandler) < 0) { + printk(KERN_ALERT DRV_NAME "unable to register netdevice for p2p\n"); + + goto err_reg_netdev; + } + + /* 9. setup running mode*/ + prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->fgIsApMode = fgIsApMode; + + /* 10. finish */ + p2pFsmInit(prAdapter); + + p2pFuncInitConnectionSettings(prAdapter, prAdapter->rWifiVar.prP2PConnSettings); + + nicActivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); + + return TRUE; + +err_reg_netdev: + free_netdev(prGlueInfo->prP2PInfo->prDevHandler); + +err_alloc_netdev: +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + wiphy_unregister(prGlueInfo->prP2PInfo->wdev.wiphy); + +err_reg_wiphy: + wiphy_free(prGlueInfo->prP2PInfo->wdev.wiphy); + prGlueInfo->prP2PInfo->wdev.wiphy = NULL; + +err_alloc_wiphy: +#endif + + return FALSE; +} /* end of glRegisterP2P() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Unregister Net Device for Wi-Fi Direct +* +* \param[in] prGlueInfo Pointer to glue info +* +* \return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +glUnregisterP2P( + P_GLUE_INFO_T prGlueInfo + ) +{ + ASSERT(prGlueInfo); + + p2pFsmUninit(prGlueInfo->prAdapter); + + nicDeactivateNetwork(prGlueInfo->prAdapter, NETWORK_TYPE_P2P_INDEX); + +#if 0 + /* Release command, mgmt and security frame belong to P2P network in + * prGlueInfo->prCmdQue + * prAdapter->rPendingCmdQueue + * prAdapter->rTxCtrl.rTxMgmtTxingQueue + * To ensure there is no pending CmdDone/TxDone handler to be executed after p2p module is removed. + */ + + /* Clear CmdQue*/ + kalClearMgmtFramesByNetType(prGlueInfo, NETWORK_TYPE_P2P_INDEX); + kalClearSecurityFramesByNetType(prGlueInfo, NETWORK_TYPE_P2P_INDEX); + /* Clear PendingCmdQue*/ + wlanReleasePendingCMDbyNetwork(prGlueInfo->prAdapter, NETWORK_TYPE_P2P_INDEX); + /* Clear PendingTxMsdu */ + nicFreePendingTxMsduInfoByNetwork(prGlueInfo->prAdapter, NETWORK_TYPE_P2P_INDEX); +#endif + + /* prepare for removal */ + if(netif_carrier_ok(prGlueInfo->prP2PInfo->prDevHandler)) { + netif_carrier_off(prGlueInfo->prP2PInfo->prDevHandler); + } + + netif_tx_stop_all_queues(prGlueInfo->prP2PInfo->prDevHandler); + + /* netdevice unregistration & free */ + unregister_netdev(prGlueInfo->prP2PInfo->prDevHandler); + +#if 1 // 20120221 frog: Avoid been referenced by netlink after net device unregistered. +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) + prGlueInfo->prP2PInfo->prDevHandler->netdev_ops = &p2p_null_ops; +#endif +#endif + + free_netdev(prGlueInfo->prP2PInfo->prDevHandler); + prGlueInfo->prP2PInfo->prDevHandler = NULL; + +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + wiphy_unregister(prGlueInfo->prP2PInfo->wdev.wiphy); + wiphy_free(prGlueInfo->prP2PInfo->wdev.wiphy); + prGlueInfo->prP2PInfo->wdev.wiphy = NULL; +#endif + + /* Free p2p memory */ + if(!p2PFreeInfo(prGlueInfo)) { + printk(KERN_ALERT DRV_NAME "Free memory for p2p FAILED\n"); + ASSERT(0); + return FALSE; + } + return TRUE; + +} /* end of glUnregisterP2P() */ + + +/*----------------------------------------------------------------------------*/ +/*! + * \brief A function for stop p2p fsm immediate + * + * \param[in] prGlueInfo Pointer to struct P_GLUE_INFO_T. + * + * \retval TRUE The execution succeeds. + * \retval FALSE The execution failed. + */ +/*----------------------------------------------------------------------------*/ +BOOLEAN +p2pStopImmediate( + P_GLUE_INFO_T prGlueInfo + ) +{ +// P_ADAPTER_T prAdapter = NULL; +// P_MSG_P2P_FUNCTION_SWITCH_T prFuncSwitch; + + ASSERT(prGlueInfo); + +// prAdapter = prGlueInfo->prAdapter; +// ASSERT(prAdapter); + + /* 1. stop TX queue */ + netif_tx_stop_all_queues(prGlueInfo->prP2PInfo->prDevHandler); + + +#if 0 + /* 2. switch P2P-FSM off */ + /* 2.1 allocate for message */ + prFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T) cnmMemAlloc( + prAdapter, + RAM_TYPE_MSG, + sizeof(MSG_P2P_FUNCTION_SWITCH_T)); + + if (!prFuncSwitch) { + ASSERT(0); // Can't trigger P2P FSM + printk(KERN_ALERT DRV_NAME "Allocate for p2p mesasage FAILED\n"); + //return -ENOMEM; + } + + /* 2.2 fill message */ + prFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; + prFuncSwitch->fgIsFuncOn = FALSE; + + /* 2.3 send message */ + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prFuncSwitch, + MSG_SEND_METHOD_UNBUF); + +#endif + + /* 3. stop queue and turn off carrier */ + prGlueInfo->prP2PInfo->eState = PARAM_MEDIA_STATE_DISCONNECTED; + + return TRUE; +} /* end of p2pStop() */ + + +/* Net Device Hooks */ +/*----------------------------------------------------------------------------*/ +/*! + * \brief A function for net_device open (ifup) + * + * \param[in] prDev Pointer to struct net_device. + * + * \retval 0 The execution succeeds. + * \retval < 0 The execution failed. + */ +/*----------------------------------------------------------------------------*/ +static int +p2pOpen( + IN struct net_device *prDev + ) +{ +// P_GLUE_INFO_T prGlueInfo = NULL; +// P_ADAPTER_T prAdapter = NULL; +// P_MSG_P2P_FUNCTION_SWITCH_T prFuncSwitch; + + ASSERT(prDev); + +#if 0 // Move after device name set. (mtk_p2p_set_local_dev_info) + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + /* 1. switch P2P-FSM on */ + /* 1.1 allocate for message */ + prFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T) cnmMemAlloc(prAdapter, + RAM_TYPE_MSG, + sizeof(MSG_P2P_FUNCTION_SWITCH_T)); + + if (!prFuncSwitch) { + ASSERT(0); // Can't trigger P2P FSM + return -ENOMEM; + } + + /* 1.2 fill message */ + prFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; + prFuncSwitch->fgIsFuncOn = TRUE; + + /* 1.3 send message */ + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prFuncSwitch, + MSG_SEND_METHOD_BUF); +#endif + + /* 2. carrier on & start TX queue */ + netif_carrier_on(prDev); + netif_tx_start_all_queues(prDev); + + return 0; /* success */ +} /* end of p2pOpen() */ + + +/*----------------------------------------------------------------------------*/ +/*! + * \brief A function for net_device stop (ifdown) + * + * \param[in] prDev Pointer to struct net_device. + * + * \retval 0 The execution succeeds. + * \retval < 0 The execution failed. + */ +/*----------------------------------------------------------------------------*/ +static int +p2pStop( + IN struct net_device *prDev + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; +// P_MSG_P2P_FUNCTION_SWITCH_T prFuncSwitch; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + /* 1. stop TX queue */ + netif_tx_stop_all_queues(prDev); +#if 0 + /* 2. switch P2P-FSM off */ + /* 2.1 allocate for message */ + prFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T) cnmMemAlloc(prAdapter, + RAM_TYPE_MSG, + sizeof(MSG_P2P_FUNCTION_SWITCH_T)); + + if (!prFuncSwitch) { + ASSERT(0); // Can't trigger P2P FSM + return -ENOMEM; + } + + /* 2.2 fill message */ + prFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; + prFuncSwitch->fgIsFuncOn = FALSE; + + /* 2.3 send message */ + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prFuncSwitch, + MSG_SEND_METHOD_BUF); +#endif + /* 3. stop queue and turn off carrier */ + prGlueInfo->prP2PInfo->eState = PARAM_MEDIA_STATE_DISCONNECTED; + + netif_tx_stop_all_queues(prDev); + if(netif_carrier_ok(prDev)) { + netif_carrier_off(prDev); + } + + return 0; +} /* end of p2pStop() */ + + +/*----------------------------------------------------------------------------*/ +/*! + * \brief A method of struct net_device, to get the network interface statistical + * information. + * + * Whenever an application needs to get statistics for the interface, this method + * is called. This happens, for example, when ifconfig or netstat -i is run. + * + * \param[in] prDev Pointer to struct net_device. + * + * \return net_device_stats buffer pointer. + */ +/*----------------------------------------------------------------------------*/ +struct net_device_stats * +p2pGetStats ( + IN struct net_device *prDev + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + + //@FIXME + prGlueInfo->prP2PInfo->rNetDevStats.rx_packets = 0; + prGlueInfo->prP2PInfo->rNetDevStats.tx_packets = 0; + prGlueInfo->prP2PInfo->rNetDevStats.tx_errors = 0; + prGlueInfo->prP2PInfo->rNetDevStats.rx_errors = 0; + prGlueInfo->prP2PInfo->rNetDevStats.rx_bytes = 0; + prGlueInfo->prP2PInfo->rNetDevStats.tx_bytes = 0; + prGlueInfo->prP2PInfo->rNetDevStats.rx_errors = 0; + prGlueInfo->prP2PInfo->rNetDevStats.multicast = 0; + + return &prGlueInfo->prP2PInfo->rNetDevStats; +} /* end of p2pGetStats() */ + + + + +static void +p2pSetMulticastList ( + IN struct net_device *prDev + ) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + + prGlueInfo = (NULL != prDev) ? *((P_GLUE_INFO_T *) netdev_priv(prDev)) : NULL; + + ASSERT(prDev); + ASSERT(prGlueInfo); + if (!prDev || !prGlueInfo) { + printk(KERN_WARNING DRV_NAME" abnormal dev or skb: prDev(0x%p), prGlueInfo(0x%p)\n", prDev, prGlueInfo); + return; + } + + + g_P2pPrDev = prDev; + + //4 Mark HALT, notify main thread to finish current job + prGlueInfo->u4Flag |= GLUE_FLAG_SUB_MOD_MULTICAST; + /* wake up main thread */ + wake_up_interruptible(&prGlueInfo->waitq); + +} /* p2pSetMulticastList */ + + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is to set multicast list and set rx mode. + * + * \param[in] prDev Pointer to struct net_device + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void +mtk_p2p_wext_set_Multicastlist ( + P_GLUE_INFO_T prGlueInfo + ) +{ + UINT_32 u4SetInfoLen = 0; + struct net_device *prDev = g_P2pPrDev; + + prGlueInfo = (NULL != prDev) ? *((P_GLUE_INFO_T *) netdev_priv(prDev)) : NULL; + + ASSERT(prDev); + ASSERT(prGlueInfo); + if (!prDev || !prGlueInfo) { + printk(KERN_WARNING DRV_NAME" abnormal dev or skb: prDev(0x%p), prGlueInfo(0x%p)\n", prDev, prGlueInfo); + return; + } + + + if (prDev->flags & IFF_PROMISC) { + prGlueInfo->prP2PInfo->u4PacketFilter |= PARAM_PACKET_FILTER_PROMISCUOUS; + } + + if (prDev->flags & IFF_BROADCAST) { + prGlueInfo->prP2PInfo->u4PacketFilter |= PARAM_PACKET_FILTER_BROADCAST; + } + + if (prDev->flags & IFF_MULTICAST) { + if ((prDev->flags & IFF_ALLMULTI) || +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) + (netdev_mc_count(prDev) > MAX_NUM_GROUP_ADDR)) { +#else + (prDev->mc_count > MAX_NUM_GROUP_ADDR)) { +#endif + prGlueInfo->prP2PInfo->u4PacketFilter |= PARAM_PACKET_FILTER_ALL_MULTICAST; + } + else { + prGlueInfo->prP2PInfo->u4PacketFilter |= PARAM_PACKET_FILTER_MULTICAST; + } + } + + if (prGlueInfo->prP2PInfo->u4PacketFilter & PARAM_PACKET_FILTER_MULTICAST) { + /* Prepare multicast address list */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) + struct netdev_hw_addr *ha; +#else + struct dev_mc_list *prMcList; +#endif + UINT_32 i = 0; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) + netdev_for_each_mc_addr(ha, prDev) { + if(i < MAX_NUM_GROUP_ADDR) { + COPY_MAC_ADDR(&(prGlueInfo->prP2PInfo->aucMCAddrList[i]), ha->addr); + i++; + } + } +#else + for (i = 0, prMcList = prDev->mc_list; + (prMcList) && (i < prDev->mc_count) && (i < MAX_NUM_GROUP_ADDR); + i++, prMcList = prMcList->next) { + COPY_MAC_ADDR(&(prGlueInfo->prP2PInfo->aucMCAddrList[i]), prMcList->dmi_addr); + } +#endif + + DBGLOG(P2P, TRACE, ("SEt Multicast Address List\n")); + + if (i >= MAX_NUM_GROUP_ADDR) { + return; + } + + wlanoidSetP2PMulticastList(prGlueInfo->prAdapter, + &(prGlueInfo->prP2PInfo->aucMCAddrList[0]), + (i * ETH_ALEN), + &u4SetInfoLen); + + } + + return; +} /* end of p2pSetMulticastList() */ + + +/*----------------------------------------------------------------------------*/ +/*! + * * \brief This function is TX entry point of NET DEVICE. + * * + * * \param[in] prSkb Pointer of the sk_buff to be sent + * * \param[in] prDev Pointer to struct net_device + * * + * * \retval NETDEV_TX_OK - on success. + * * \retval NETDEV_TX_BUSY - on failure, packet will be discarded by upper layer. + * */ +/*----------------------------------------------------------------------------*/ +int +p2pHardStartXmit( + IN struct sk_buff *prSkb, + IN struct net_device *prDev + ) +{ + P_QUE_ENTRY_T prQueueEntry = NULL; + P_QUE_T prTxQueue = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + UINT_16 u2QueueIdx = 0; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prSkb); + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + + if (prGlueInfo->u4Flag & GLUE_FLAG_HALT) { + printk(KERN_INFO DRV_NAME"GLUE_FLAG_HALT skip tx\n"); + dev_kfree_skb(prSkb); + return NETDEV_TX_OK; + } + + // mark as P2P packets + GLUE_SET_PKT_FLAG_P2P(prSkb); + + prQueueEntry = (P_QUE_ENTRY_T) GLUE_GET_PKT_QUEUE_ENTRY(prSkb); + prTxQueue = &prGlueInfo->rTxQueue; + + if (wlanProcessSecurityFrame(prGlueInfo->prAdapter, (P_NATIVE_PACKET) prSkb) == FALSE) { + + u2QueueIdx = skb_get_queue_mapping(prSkb); + ASSERT(u2QueueIdx < CFG_MAX_TXQ_NUM); + + if (u2QueueIdx >= CFG_MAX_TXQ_NUM) { + printk(KERN_INFO DRV_NAME"Incorrect queue index, skip this frame\n"); + dev_kfree_skb(prSkb); + return NETDEV_TX_OK; + } + + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + QUEUE_INSERT_TAIL(prTxQueue, prQueueEntry); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + + GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingFrameNum); + GLUE_INC_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_P2P_INDEX][u2QueueIdx]); + + if (prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_P2P_INDEX][u2QueueIdx] >= CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD) { + netif_stop_subqueue(prDev, u2QueueIdx); + } + } + else { + GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingSecurityFrameNum); + } + + kalSetEvent(prGlueInfo); + + return NETDEV_TX_OK; +} /* end of p2pHardStartXmit() */ + + +/*----------------------------------------------------------------------------*/ +/*! + * \brief A method of struct net_device, a primary SOCKET interface to configure + * the interface lively. Handle an ioctl call on one of our devices. + * Everything Linux ioctl specific is done here. Then we pass the contents + * of the ifr->data to the request message handler. + * + * \param[in] prDev Linux kernel netdevice + * + * \param[in] prIFReq Our private ioctl request structure, typed for the generic + * struct ifreq so we can use ptr to function + * + * \param[in] cmd Command ID + * + * \retval WLAN_STATUS_SUCCESS The IOCTL command is executed successfully. + * \retval OTHER The execution of IOCTL command is failed. + */ +/*----------------------------------------------------------------------------*/ +int +p2pDoIOCTL( + struct net_device *prDev, + struct ifreq *prIFReq, + int i4Cmd + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + int ret = 0; + char *prExtraBuf = NULL; + UINT_32 u4ExtraSize = 0; + struct iwreq *prIwReq = (struct iwreq *)prIFReq; + struct iw_request_info rIwReqInfo; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + + if (prGlueInfo->u4ReadyFlag == 0) { + // adapter not ready yet + return -EINVAL; + } + + // fill rIwReqInfo + rIwReqInfo.cmd = (__u16)i4Cmd; + rIwReqInfo.flags = 0; + + switch(i4Cmd) { + case SIOCSIWENCODEEXT: + /* Set Encryption Material after 4-way handshaking is done */ + if (prIwReq->u.encoding.pointer) { + u4ExtraSize = prIwReq->u.encoding.length; + prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); + + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + if (copy_from_user(prExtraBuf, + prIwReq->u.encoding.pointer, + prIwReq->u.encoding.length)) { + ret = -EFAULT; + } + } + else if (prIwReq->u.encoding.length != 0) { + ret = -EINVAL; + break; + } + + if(ret == 0) { + ret = mtk_p2p_wext_set_key(prDev, &rIwReqInfo, &(prIwReq->u), prExtraBuf); + } + + kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); + prExtraBuf = NULL; + break; + + case SIOCSIWMLME: + /* IW_MLME_DISASSOC used for disconnection*/ + if (prIwReq->u.data.length != sizeof(struct iw_mlme)) { + printk(KERN_INFO "MLME buffer strange:%d\n", prIwReq->u.data.length); + ret = -EINVAL; + break; + } + + if (!prIwReq->u.data.pointer) { + ret = -EINVAL; + break; + } + + prExtraBuf = kalMemAlloc(sizeof(struct iw_mlme), VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = - ENOMEM; + break; + } + + if (copy_from_user(prExtraBuf, prIwReq->u.data.pointer, sizeof(struct iw_mlme))) { + ret = -EFAULT; + } + else { + ret = mtk_p2p_wext_mlme_handler(prDev, &rIwReqInfo, &(prIwReq->u), prExtraBuf); + } + + kalMemFree(prExtraBuf, VIR_MEM_TYPE, sizeof(struct iw_mlme)); + prExtraBuf = NULL; + break; + + case SIOCGIWPRIV: + /* This ioctl is used to list all IW privilege ioctls */ + ret = mtk_p2p_wext_get_priv(prDev, &rIwReqInfo, &(prIwReq->u), NULL); + break; + + case SIOCGIWSCAN: + ret = mtk_p2p_wext_discovery_results(prDev, &rIwReqInfo, &(prIwReq->u), NULL); + break; + + case SIOCSIWAUTH: + ret = mtk_p2p_wext_set_auth(prDev, &rIwReqInfo, &(prIwReq->u), NULL); + break; + + case IOC_P2P_CFG_DEVICE: + case IOC_P2P_PROVISION_COMPLETE: + case IOC_P2P_START_STOP_DISCOVERY: + case IOC_P2P_DISCOVERY_RESULTS: + case IOC_P2P_WSC_BEACON_PROBE_RSP_IE: + case IOC_P2P_CONNECT_DISCONNECT: + case IOC_P2P_PASSWORD_READY: + case IOC_P2P_GET_STRUCT: + case IOC_P2P_SET_STRUCT: + case IOC_P2P_GET_REQ_DEVICE_INFO: + ret = rP2PIwPrivHandler[i4Cmd - SIOCIWFIRSTPRIV](prDev, &rIwReqInfo, &(prIwReq->u), (char *)&(prIwReq->u)); + break; +#if CFG_SUPPORT_P2P_RSSI_QUERY + case SIOCGIWSTATS: + ret = mtk_p2p_wext_get_rssi(prDev, &rIwReqInfo, &(prIwReq->u), NULL); + break; +#endif + default: + ret = -ENOTTY; + } + + return ret; +} /* end of p2pDoIOCTL() */ + + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To report the private supported IOCTLs table to user space. + * + * \param[in] prDev Net device requested. + * \param[out] prIfReq Pointer to ifreq structure, content is copied back to + * user space buffer in gl_iwpriv_table. + * + * \retval 0 For success. + * \retval -E2BIG For user's buffer size is too small. + * \retval -EFAULT For fail. + * + */ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_get_priv ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + struct iw_point *prData= (struct iw_point *)&wrqu->data; + UINT_16 u2BufferSize = 0; + + ASSERT(prDev); + + u2BufferSize = prData->length; + + /* update our private table size */ + prData->length = (__u16)sizeof(rP2PIwPrivTable)/sizeof(struct iw_priv_args); + + if (u2BufferSize < prData->length) { + return -E2BIG; + } + + if (prData->length) { + if (copy_to_user(prData->pointer, rP2PIwPrivTable, sizeof(rP2PIwPrivTable))) { + return -EFAULT; + } + } + + return 0; +} /* end of mtk_p2p_wext_get_priv() */ + + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To indicate P2P-FSM for re-associate to the connecting device + * + * \param[in] prDev Net device requested. + * \param[inout] wrqu Pointer to iwreq_data + * + * \retval 0 For success. + * \retval -EFAULT For fail. + * + */ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_reconnect ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ +#if 0 + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_MSG_HDR_T prMsgHdr; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + // indicate P2P-FSM with MID_MNY_P2P_CONNECTION_TRIGGER + prMsgHdr = (P_MSG_HDR_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_HDR_T)); + if (!prMsgHdr) { + ASSERT(0); // Can't trigger P2P FSM + return -ENOMEM; + } + + /* 1.2 fill message */ + prMsgHdr->eMsgId = MID_MNY_P2P_CONNECTION_TRIGGER; + + DBGLOG(P2P, TRACE, ("mtk_p2p_wext_reconnect: P2P Reconnect\n")); + + /* 1.3 send message */ + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prMsgHdr, + MSG_SEND_METHOD_BUF); +#endif + return 0; +} /* end of mtk_p2p_wext_reconnect() */ + + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief MLME command handler +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_mlme_handler( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ +#if 0 + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + struct iw_mlme *mlme = (struct iw_mlme *)extra; + P_MSG_P2P_CONNECTION_ABORT_T prMsgP2PConnAbt = (P_MSG_P2P_CONNECTION_ABORT_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + DBGLOG(P2P, TRACE, ("mtk_p2p_wext_mlme_handler:\n")); + + switch (mlme->cmd) { + case IW_MLME_DISASSOC: + // indicate P2P-FSM with MID_MNY_P2P_CONNECTION_PAUSE + prMsgP2PConnAbt = (P_MSG_HDR_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_CONNECTION_ABORT_T)); + if (!prMsgP2PConnAbt) { + ASSERT(0); // Can't trigger P2P FSM + return -ENOMEM; + } + + COPY_MAC_ADDR(prMsgP2PConnAbt->aucTargetID, mlme->addr.sa_data); + + prMsgP2PConnAbt->u2ReasonCode = mlme->reason_code; + + + if (EQUAL_MAC_ADDR(prMsgP2PConnAbt->aucTargetID, prP2pBssInfo->aucOwnMacAddr)) { + DBGLOG(P2P, TRACE, ("P2P Connection Abort:\n")); + + /* 1.2 fill message */ + prMsgP2PConnAbt->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_ABORT; + } + else { + DBGLOG(P2P, TRACE, ("P2P Connection Pause:\n")); + + /* 1.2 fill message */ + prMsgP2PConnAbt->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_PAUSE; + } + + /* 1.3 send message */ + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prMsgP2PConnAbt, + MSG_SEND_METHOD_BUF); + + break; + + default: + return -EOPNOTSUPP; + } +#endif + return 0; +} /* end of mtk_p2p_wext_mlme_handler() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_PROVISION_COMPLETE) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_set_provision_complete( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ +#if 0 + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + struct iw_point *prData= (struct iw_point *)&wrqu->data; + P_MSG_HDR_T prMsgHdr; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + switch(prData->flags) { + case P2P_PROVISIONING_SUCCESS: + /* indicate P2P-FSM with MID_MNY_P2P_PROVISION_COMPLETE */ + prMsgHdr = (P_MSG_HDR_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_HDR_T)); + if (!prMsgHdr) { + ASSERT(0); // Can't trigger P2P FSM + return -ENOMEM; + } + + /* 1.2 fill message */ + prMsgHdr->eMsgId = MID_MNY_P2P_PROVISION_COMPLETE; + + prGlueInfo->prP2PInfo->u4CipherPairwise = IW_AUTH_CIPHER_CCMP; + + /* 1.3 send message */ + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prMsgHdr, + MSG_SEND_METHOD_BUF); + + break; + + case P2P_PROVISIONING_FAIL: + /* @TODO: send to P2P-FSM with MID_MNY_P2P_PROVISION_COMPLETE, with fail code */ + + break; + + default: + return -EOPNOTSUPP; + } +#endif + + return 0; +} /* end of mtk_p2p_wext_set_provision_complete() */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_START_STOP_DISCOVERY) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_start_stop_discovery( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ +#if 0 + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + struct iw_point *prData= (struct iw_point *)&wrqu->data; + P_IW_P2P_REQ_DEVICE_TYPE prReqDeviceType = (P_IW_P2P_REQ_DEVICE_TYPE) extra; + UINT_8 au4IeBuf[MAX_IE_LENGTH]; + P_MSG_HDR_T prMsgHdr; + P_MSG_P2P_DEVICE_DISCOVER_T prDiscoverMsg; + P_P2P_CONNECTION_SETTINGS_T prConnSettings; + UINT_8 aucNullAddr[] = NULL_MAC_ADDR; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + prConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + + if(prData->flags == P2P_STOP_DISCOVERY) { + // indicate P2P-FSM with MID_MNY_P2P_DISCOVERY_ABORT + prMsgHdr = (P_MSG_HDR_T) cnmMemAlloc(prAdapter, + RAM_TYPE_MSG, + sizeof(MSG_HDR_T)); + + if (!prMsgHdr) { + ASSERT(0); // Can't trigger P2P FSM + return -ENOMEM; + } + + prMsgHdr->eMsgId = MID_MNY_P2P_DISCOVERY_ABORT; + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prMsgHdr, + MSG_SEND_METHOD_BUF); + } + else if(prData->flags == P2P_START_DISCOVERY) { + + /* retrieve IE for Probe Response */ + if(prReqDeviceType->probe_rsp_len > 0) { + if(prReqDeviceType->probe_rsp_len <= MAX_IE_LENGTH) { + if(copy_from_user(prGlueInfo->prP2PInfo->aucWSCIE[2], prReqDeviceType->probe_rsp_ie, prReqDeviceType->probe_rsp_len)) { + return -EFAULT; + } + prGlueInfo->prP2PInfo->u2WSCIELen[2] = prReqDeviceType->probe_rsp_len; + } + else { + return -E2BIG; + } + } + + /* retrieve IE for Probe Request */ + if(prReqDeviceType->probe_req_len > 0) { + if(prReqDeviceType->probe_req_len <= MAX_IE_LENGTH) { + if(copy_from_user(prGlueInfo->prP2PInfo->aucWSCIE[1], prReqDeviceType->probe_req_ie, prReqDeviceType->probe_req_len)) { + return -EFAULT; + } + prGlueInfo->prP2PInfo->u2WSCIELen[1] = prReqDeviceType->probe_req_len; + } + else { + return -E2BIG; + } + } + /* update IE for Probe Request */ + + if(prReqDeviceType->scan_type == P2P_LISTEN) { + /* update listening parameter */ + + /* @TODO: update prConnSettings for Probe Response IE */ + } + else { + // indicate P2P-FSM with MID_MNY_P2P_DEVICE_DISCOVERY + prDiscoverMsg = (P_MSG_P2P_DEVICE_DISCOVER_T) cnmMemAlloc(prAdapter, + RAM_TYPE_MSG, + sizeof(MSG_P2P_DEVICE_DISCOVER_T)); + + if (!prDiscoverMsg) { + ASSERT(0); // Can't trigger P2P FSM + return -ENOMEM; + } + + prDiscoverMsg->rMsgHdr.eMsgId = MID_MNY_P2P_DEVICE_DISCOVERY; + prDiscoverMsg->u4DevDiscoverTime = 0; // unlimited + prDiscoverMsg->fgIsSpecificType = TRUE; + prDiscoverMsg->rTargetDeviceType.u2CategoryID = *(PUINT_16)(&(prReqDeviceType->pri_device_type[0])); + prDiscoverMsg->rTargetDeviceType.u2SubCategoryID = *(PUINT_16)(&(prReqDeviceType->pri_device_type[6]));; + COPY_MAC_ADDR(prDiscoverMsg->aucTargetDeviceID, aucNullAddr); + + /* @FIXME: parameter to be refined, where to pass IE buffer ? */ + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prDiscoverMsg, + MSG_SEND_METHOD_BUF); + } + } + else { + return -EINVAL; + } +#endif + + return 0; +} /* end of mtk_p2p_wext_start_stop_discovery() */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_SET_INT) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Setting parameters not support. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_invitation_request ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + int i4Status = 0; +#if 0 + P_ADAPTER_T prAdapter = (P_ADAPTER_T)NULL; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + struct iw_point *prData = (struct iw_point*)&wrqu->data; + P_IW_P2P_IOCTL_INVITATION_STRUCT prIoctlInvitation = (P_IW_P2P_IOCTL_INVITATION_STRUCT)NULL; + + do { + if ((prDev == NULL) || (extra == NULL)) { + ASSERT(FALSE); + i4Status = -EINVAL; + break; + } + + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prDev)); + prIoctlInvitation = (P_IW_P2P_IOCTL_INVITATION_STRUCT)extra; + + if (prGlueInfo == NULL) { + i4Status = -EINVAL; + break; + } + + + prAdapter = prGlueInfo->prAdapter; + + if (prAdapter == NULL) { + i4Status = -EINVAL; + break; + } + + + if (prIoctlInvitation->ucReinvoke == 1) { + // TODO: Set Group ID + p2pFuncSetGroupID(prAdapter, prIoctlInvitation->aucGroupID, prIoctlInvitation->aucSsid, prIoctlInvitation->u4SsidLen); + } + + else { + P_MSG_P2P_INVITATION_REQUEST_T prMsgP2PInvitationReq = (P_MSG_P2P_INVITATION_REQUEST_T)NULL; + + // TODO: Do Invitation. + prMsgP2PInvitationReq = (P_MSG_P2P_INVITATION_REQUEST_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_INVITATION_REQUEST_T)); + if (!prMsgP2PInvitationReq) { + ASSERT(0); // Can't trigger P2P FSM + i4Status = -ENOMEM; + break; + } + + /* 1.2 fill message */ + prMsgP2PInvitationReq->rMsgHdr.eMsgId = MID_MNY_P2P_INVITATION_REQ; + kalMemCopy(prMsgP2PInvitationReq->aucDeviceID, prIoctlInvitation->aucDeviceID, MAC_ADDR_LEN); + + DBGLOG(P2P, TRACE, ("mtk_p2p_wext_invitation_request: P2P Invitation Req\n")); + + /* 1.3 send message */ + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T)prMsgP2PInvitationReq, + MSG_SEND_METHOD_BUF); + + } + + + + } while (FALSE); +#endif + + return i4Status; + +} +/* mtk_p2p_wext_invitation_request */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_SET_INT) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Setting parameters not support. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_invitation_abort ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + int i4Status = 0; +#if 0 + P_ADAPTER_T prAdapter = (P_ADAPTER_T)NULL; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + struct iw_point *prData = (struct iw_point*)&wrqu->data; + P_IW_P2P_IOCTL_ABORT_INVITATION prIoctlInvitationAbort = (P_IW_P2P_IOCTL_ABORT_INVITATION)NULL; + + UINT_8 bssid[MAC_ADDR_LEN]; + + do { + if ((prDev == NULL) || (extra == NULL)) { + ASSERT(FALSE); + i4Status = -EINVAL; + break; + } + + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prDev)); + prIoctlInvitationAbort = (P_IW_P2P_IOCTL_ABORT_INVITATION)extra; + + if (prGlueInfo == NULL) { + i4Status = -EINVAL; + break; + } + + + prAdapter = prGlueInfo->prAdapter; + + if (prAdapter == NULL) { + i4Status = -EINVAL; + break; + } + else { + P_MSG_P2P_INVITATION_REQUEST_T prMsgP2PInvitationAbort = (P_MSG_P2P_INVITATION_REQUEST_T)NULL; + + prMsgP2PInvitationAbort = (P_MSG_P2P_INVITATION_REQUEST_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_INVITATION_REQUEST_T)); + + if (!prMsgP2PInvitationAbort) { + ASSERT(0); // Can't trigger P2P FSM + i4Status = -ENOMEM; + break; + } + + + /* 1.2 fill message */ + prMsgP2PInvitationAbort->rMsgHdr.eMsgId = MID_MNY_P2P_INVITATION_ABORT; + kalMemCopy(prMsgP2PInvitationAbort->aucDeviceID, prIoctlInvitationAbort->dev_addr, MAC_ADDR_LEN); + + DBGLOG(P2P, TRACE, ("mtk_p2p_wext_invitation_request: P2P Invitation Req\n")); + + /* 1.3 send message */ + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T)prMsgP2PInvitationAbort, + MSG_SEND_METHOD_BUF); + + } + + + } while (FALSE); +#endif + + return i4Status; + +} +/* mtk_p2p_wext_invitation_abort */ + + + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To override p2p interface address + * + * \param[in] prDev Net device requested. + * \param[in] addr Pointer to address + * + * \retval 0 For success. + * \retval -E2BIG For user's buffer size is too small. + * \retval -EFAULT For fail. + * + */ +/*----------------------------------------------------------------------------*/ +int +p2pSetMACAddress( + IN struct net_device *prDev, + void *addr + ) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + //@FIXME + return eth_mac_addr(prDev, addr); +} + + + + + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set encryption cipher suite +* +* \param[in] prDev Net device requested. +* \param[out] +* +* \retval 0 Success. +* \retval -EINVAL Invalid parameter +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_set_auth ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + struct iw_param *prAuth = (struct iw_param *)wrqu; + + ASSERT(prDev); + ASSERT(prAuth); + if (FALSE == GLUE_CHK_PR2(prDev, prAuth)) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + + /* Save information to glue info and process later when ssid is set. */ + switch(prAuth->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + break; + case IW_AUTH_CIPHER_PAIRWISE: + prGlueInfo->prP2PInfo->u4CipherPairwise = prAuth->value; + break; + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_KEY_MGMT: + case IW_AUTH_TKIP_COUNTERMEASURES: + case IW_AUTH_DROP_UNENCRYPTED: + case IW_AUTH_80211_AUTH_ALG: + case IW_AUTH_WPA_ENABLED: + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + case IW_AUTH_ROAMING_CONTROL: + case IW_AUTH_PRIVACY_INVOKED: + default: + //@TODO + break; + } + + return 0; +} /* end of mtk_p2p_wext_set_auth() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set encryption cipher and key. +* +* \param[in] prDev Net device requested. +* \param[out] prIfReq Pointer to ifreq structure, content is copied back to +* user space buffer in gl_iwpriv_table. +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note Securiry information is stored in pEnc. +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_set_key( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + int ret = 0; + struct iw_encode_ext *prIWEncExt; + struct iw_point *prEnc; + char *prExtraBuf = NULL; + UINT_32 u4ExtraSize = 0; + UINT_8 keyStructBuf[100]; + P_PARAM_REMOVE_KEY_T prRemoveKey = (P_PARAM_REMOVE_KEY_T) keyStructBuf; + P_PARAM_KEY_T prKey = (P_PARAM_KEY_T) keyStructBuf; + P_GLUE_INFO_T prGlueInfo; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + + do { + if (wrqu->encoding.pointer) { + u4ExtraSize = wrqu->encoding.length; + prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); + + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + if (copy_from_user(prExtraBuf, + wrqu->encoding.pointer, + wrqu->encoding.length)) { + ret = -EFAULT; + break; + } + } + else if (wrqu->encoding.length != 0) { + ret = -EINVAL; + break; + } + + prEnc = &wrqu->encoding; + prIWEncExt = (struct iw_encode_ext *) prExtraBuf; + + if (GLUE_CHK_PR3(prDev, prEnc, prExtraBuf) == TRUE) { + memset(keyStructBuf, 0, sizeof(keyStructBuf)); + + if ((prEnc->flags & IW_ENCODE_MODE) == IW_ENCODE_DISABLED) { // Key Removal + prRemoveKey->u4Length = sizeof(*prRemoveKey); + memcpy(prRemoveKey->arBSSID, prIWEncExt->addr.sa_data, 6); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetRemoveP2PKey, + prRemoveKey, + prRemoveKey->u4Length, + FALSE, + FALSE, + TRUE, + TRUE, + &u4BufLen); + + if(rStatus != WLAN_STATUS_SUCCESS) + ret = -EFAULT; + } + else { + if(prIWEncExt->alg == IW_ENCODE_ALG_CCMP) { + /* KeyID */ + prKey->u4KeyIndex = (prEnc->flags & IW_ENCODE_INDEX) ? + ((prEnc->flags & IW_ENCODE_INDEX) - 1) : 0; + if (prKey->u4KeyIndex <= 3) { + /* bit(31) and bit(30) are shared by pKey and pRemoveKey */ + /* Tx Key Bit(31)*/ + if (prIWEncExt->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + prKey->u4KeyIndex |= 0x1UL << 31; + } + + /* Pairwise Key Bit(30) */ + if (prIWEncExt->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + /* group key */ + } + else { + /* pairwise key */ + prKey->u4KeyIndex |= 0x1UL << 30; + } + + /* Rx SC Bit(29) */ + if (prIWEncExt->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { + prKey->u4KeyIndex |= 0x1UL << 29; + memcpy(&prKey->rKeyRSC, prIWEncExt->rx_seq, IW_ENCODE_SEQ_MAX_SIZE); + } + + /* BSSID */ + memcpy(prKey->arBSSID, prIWEncExt->addr.sa_data, 6); + memcpy(prKey->aucKeyMaterial, prIWEncExt->key, prIWEncExt->key_len); + + prKey->u4KeyLength = prIWEncExt->key_len; + prKey->u4Length = ((UINT_32)&(((P_PARAM_KEY_T)0)->aucKeyMaterial)) + prKey->u4KeyLength; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetAddP2PKey, + prKey, + prKey->u4Length, + FALSE, + FALSE, + TRUE, + TRUE, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + ret = -EFAULT; + } + } + else { + ret = -EINVAL; + } + } + else { + ret = -EINVAL; + } + } + } + else + ret = -EINVAL; + + } while(FALSE); + + if (prExtraBuf) { + kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); + prExtraBuf = NULL; + } + + return ret; +} /* end of mtk_p2p_wext_set_key() */ + + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief set the p2p gc power mode +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_set_powermode( + IN struct net_device *prNetDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + //printk("set_powermode = %d, value = %d\n", wrqu->power.disabled, wrqu->power.value); + struct iw_param *prPower = (struct iw_param*)&wrqu->power; +#if 1 + PARAM_POWER_MODE ePowerMode; + INT_32 i4PowerValue; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prPower); + if (FALSE == GLUE_CHK_PR2(prNetDev, prPower)) { + return -EINVAL; + } + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + //printk(KERN_INFO "wext_set_power value(%d) disabled(%d) flag(0x%x)\n", + // prPower->value, prPower->disabled, prPower->flags); + + if(prPower->disabled){ + ePowerMode = Param_PowerModeCAM; + } + else { + i4PowerValue = prPower->value; +#if WIRELESS_EXT < 21 + i4PowerValue /= 1000000; +#endif + if (i4PowerValue == 0) { + ePowerMode = Param_PowerModeCAM; + } else if (i4PowerValue == 1) { + ePowerMode = Param_PowerModeMAX_PSP; + } else if (i4PowerValue == 2) { + ePowerMode = Param_PowerModeFast_PSP; + } + else { + printk(KERN_DEBUG "%s(): unsupported power management mode value = %d.\n", + __FUNCTION__, + prPower->value); + + return -EINVAL; + } + } + + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetP2pPowerSaveProfile, + &ePowerMode, + sizeof(ePowerMode), + FALSE, + FALSE, + TRUE, + TRUE, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + //printk(KERN_INFO DRV_NAME"wlanoidSet802dot11PowerSaveProfile fail 0x%lx\n", rStatus); + return -EFAULT; + } + +#endif + + return 0; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief get the p2p gc power mode +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_get_powermode( + IN struct net_device *prNetDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + //printk("mtk_p2p_wext_get_powermode\n"); + //wrqu->power.disabled = 0; + //wrqu->power.value = 1; + + struct iw_param *prPower = (struct iw_param*)&wrqu->power; + PARAM_POWER_MODE ePowerMode; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prPower); + if (FALSE == GLUE_CHK_PR2(prNetDev, prPower)) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + ASSERT(prGlueInfo); + + +#if 1 + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryP2pPowerSaveProfile, + &ePowerMode, + sizeof(ePowerMode), + TRUE, + FALSE, + FALSE, + TRUE, + &u4BufLen); +#else + rStatus = wlanQueryInformation(prGlueInfo->prAdapter, + wlanoidQueryP2pPowerSaveProfile, + &ePowerMode, + sizeof(ePowerMode), + &u4BufLen); +#endif + + prPower->value = 0; + prPower->disabled = 1; + + if (Param_PowerModeCAM == ePowerMode) { + prPower->value = 0; + prPower->disabled = 1; + } + else if (Param_PowerModeMAX_PSP == ePowerMode ) { + prPower->value = 1; + prPower->disabled = 0; + } + else if (Param_PowerModeFast_PSP == ePowerMode ) { + prPower->value = 2; + prPower->disabled = 0; + } + + prPower->flags = IW_POWER_PERIOD | IW_POWER_RELATIVE; +#if WIRELESS_EXT < 21 + prPower->value *= 1000000; +#endif + + + return 0; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_CFG_DEVICE) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_set_local_dev_info( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_IW_P2P_CFG_DEVICE_TYPE prDeviceCfg = (P_IW_P2P_CFG_DEVICE_TYPE) extra; + P_P2P_CONNECTION_SETTINGS_T prConnSettings; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T)NULL; + //P_MSG_P2P_FUNCTION_SWITCH_T prFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T)NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + prConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; + + // update connection settings for P2P-FSM + // 1. update SSID + if(prDeviceCfg->ssid_len > ELEM_MAX_LEN_SSID) { + prConnSettings->ucSSIDLen = ELEM_MAX_LEN_SSID; + } + else { + prConnSettings->ucSSIDLen = prDeviceCfg->ssid_len; + } + + if(copy_from_user(prConnSettings->aucSSID, prDeviceCfg->ssid, prConnSettings->ucSSIDLen)) { + return -EFAULT; + } + + // 2. update device type (WPS IE) + kalMemCopy(&(prConnSettings->rPrimaryDevTypeBE), &(prDeviceCfg->pri_device_type), sizeof(DEVICE_TYPE_T)); +#if P2P_MAX_SUPPORTED_SEC_DEV_TYPE_COUNT + kalMemCopy(&(prConnSettings->arSecondaryDevTypeBE[0]), &(prDeviceCfg->snd_device_type), sizeof(DEVICE_TYPE_T)); +#endif + + // 3. update device name + if(prDeviceCfg->device_name_len > WPS_ATTRI_MAX_LEN_DEVICE_NAME) { + prConnSettings->ucDevNameLen = WPS_ATTRI_MAX_LEN_DEVICE_NAME; + } + else { + prConnSettings->ucDevNameLen = prDeviceCfg->device_name_len; + } + if(copy_from_user(prConnSettings->aucDevName, prDeviceCfg->device_name, prConnSettings->ucDevNameLen)) { + return -EFAULT; + } + + // 4. update GO intent + prConnSettings->ucGoIntent = prDeviceCfg->intend; + + + /* Preferred channel bandwidth */ + prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode = + prDeviceCfg->ch_width ? CONFIG_BW_20_40M : CONFIG_BW_20M; + prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode = + prDeviceCfg->ch_width ? CONFIG_BW_20_40M : CONFIG_BW_20M; + +#if 0 + /* 1. switch P2P-FSM on */ + /* 1.1 allocate for message */ + prFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T) cnmMemAlloc(prAdapter, + RAM_TYPE_MSG, + sizeof(MSG_P2P_FUNCTION_SWITCH_T)); + + if (!prFuncSwitch) { + ASSERT(0); // Can't trigger P2P FSM + return -ENOMEM; + } + + /* 1.2 fill message */ + prFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; + prFuncSwitch->fgIsFuncOn = TRUE; + + /* 1.3 send message */ + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prFuncSwitch, + MSG_SEND_METHOD_BUF); +#endif + return 0; +} /* end of mtk_p2p_wext_set_local_dev_info() */ + + + + + + +/*----------------------------------------------------------------------------*/ +/*! + * \brief I/O Control handler for both + * IOC_P2P_START_STOP_DISCOVERY & SIOCGIWSCAN + * + * \param[in] prDev Net device requested. + * \param[inout] wrqu Pointer to iwreq_data + * + * \retval 0 Success. + * \retval -EFAULT Setting parameters to driver fail. + * \retval -EOPNOTSUPP Key size not supported. + * + * \note + */ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_discovery_results( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + struct iw_event iwe; + char *current_ev = extra; + UINT_32 i; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + P_P2P_INFO_T prP2PInfo = (P_P2P_INFO_T)NULL; + P_EVENT_P2P_DEV_DISCOVER_RESULT_T prTargetResult = (P_EVENT_P2P_DEV_DISCOVER_RESULT_T)NULL; + P_PARAM_VARIABLE_IE_T prDesiredIE = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + prP2PInfo = prAdapter->prP2pInfo; + + for(i = 0 ; i < prP2PInfo->u4DeviceNum ; i++) { + prTargetResult = &prP2PInfo->arP2pDiscoverResult[i]; + + /* SIOCGIWAP */ + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, + prTargetResult->aucInterfaceAddr, + 6); + + current_ev = iwe_stream_add_event(info, current_ev, + extra + IW_SCAN_MAX_DATA, + &iwe, IW_EV_ADDR_LEN); + + + /* SIOCGIWESSID */ + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; + iwe.u.data.length = prTargetResult->u2NameLength; + + current_ev = iwe_stream_add_point(info, current_ev, + extra + IW_SCAN_MAX_DATA, + &iwe, prTargetResult->aucName); + + /* IWEVGENIE for WPA IE */ + if(prTargetResult->u2IELength <= 600 && wextSrchDesiredWPAIE(prTargetResult->pucIeBuf, + prTargetResult->u2IELength, + 0xDD, + (PUINT_8 *)&prDesiredIE)) { + + iwe.cmd = IWEVGENIE; + iwe.u.data.flags = 1; + iwe.u.data.length = 2 + (__u16)prDesiredIE->ucLength; + + current_ev = iwe_stream_add_point(info, current_ev, + extra + IW_SCAN_MAX_DATA, + &iwe, (char *)prDesiredIE); + } + +#if CFG_SUPPORT_WPS + + /* IWEVGENIE for WPS IE */ + if((prTargetResult->u2IELength <= 600) && wextSrchDesiredWPSIE(prTargetResult->pucIeBuf, + prTargetResult->u2IELength, + 0xDD, + (PUINT_8 *)&prDesiredIE)) { + + iwe.cmd = IWEVGENIE; + iwe.u.data.flags = 1; + iwe.u.data.length = 2 + (__u16)prDesiredIE->ucLength; + + current_ev = iwe_stream_add_point(info, current_ev, + extra + IW_SCAN_MAX_DATA, + &iwe, (char *)prDesiredIE); + } + +#endif + + /* IWEVGENIE for RSN IE */ + if((prTargetResult->u2IELength <= 600) && wextSrchDesiredWPAIE(prTargetResult->pucIeBuf, + prTargetResult->u2IELength, + 0x30, + (PUINT_8 *)&prDesiredIE)) { + + iwe.cmd = IWEVGENIE; + iwe.u.data.flags = 1; + iwe.u.data.length = 2 + (__u16)prDesiredIE->ucLength; + + current_ev = iwe_stream_add_point(info, current_ev, + extra + IW_SCAN_MAX_DATA, + &iwe, (char *)prDesiredIE); + } + + /* IOC_P2P_GO_WSC_IE */ +#if 1 + /* device capability */ + if (1) { + UINT_8 data[40]; + + iwe.cmd = IWEVCUSTOM; + iwe.u.data.flags = 0; + iwe.u.data.length = 8 + sizeof("p2p_cap="); + + snprintf(data, iwe.u.data.length, "p2p_cap=%02x%02x%02x%02x%c", + prTargetResult->ucDeviceCapabilityBitmap, prTargetResult->ucGroupCapabilityBitmap, + (UINT_8)prTargetResult->u2ConfigMethod, (UINT_8)(prTargetResult->u2ConfigMethod >> 8), '\0' ); + current_ev = iwe_stream_add_point(info, current_ev, + extra + IW_SCAN_MAX_DATA, + &iwe, (char *)data); + + //printk("%s\n", data); + kalMemZero(data, 40); + + iwe.cmd = IWEVCUSTOM; + iwe.u.data.flags = 0; + iwe.u.data.length = 12 + sizeof("p2p_dev_type="); + + snprintf(data, iwe.u.data.length, "p2p_dev_type=%02x%02x%02x%02x%02x%02x%c", + (UINT_8)prTargetResult->rPriDevType.u2CategoryID,(UINT_8)prTargetResult->rPriDevType.u2SubCategoryID, + (UINT_8)prTargetResult->arSecDevType[0].u2CategoryID,(UINT_8)prTargetResult->arSecDevType[0].u2SubCategoryID, + (UINT_8)prTargetResult->arSecDevType[1].u2CategoryID,(UINT_8)prTargetResult->arSecDevType[1].u2SubCategoryID, + '\0'); + current_ev = iwe_stream_add_point(info, current_ev, + extra + IW_SCAN_MAX_DATA, + &iwe, (char *)data); + //printk("%s\n", data); + + kalMemZero(data, 40); + + iwe.cmd = IWEVCUSTOM; + iwe.u.data.flags = 0; + iwe.u.data.length = 17 + sizeof("p2p_grp_bssid="); + + snprintf(data, iwe.u.data.length, "p2p_grp_bssid="MACSTR"%c", + MAC2STR(prTargetResult->aucBSSID), '\0'); + current_ev = iwe_stream_add_point(info, current_ev, + extra + IW_SCAN_MAX_DATA, + &iwe, (char *)data); + //printk("%s\n", data); + + } +#endif + } + + /* Length of data */ + wrqu->data.length = (current_ev - extra); + wrqu->data.flags = 0; + + return 0; +} /* end of mtk_p2p_wext_discovery_results() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_WSC_BEACON_PROBE_RSP_IE) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_wsc_ie( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_IW_P2P_HOSTAPD_PARAM prHostapdParam = (P_IW_P2P_HOSTAPD_PARAM)extra; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prDev)); + ASSERT(prGlueInfo); + + if (prHostapdParam->len > 0) { + if (prHostapdParam->len <= MAX_WSC_IE_LENGTH) { + if (copy_from_user(prGlueInfo->prP2PInfo->aucWSCIE[0], prHostapdParam->data, prHostapdParam->len)) { + return -EFAULT; + } + if (copy_from_user(prGlueInfo->prP2PInfo->aucWSCIE[2], prHostapdParam->data, prHostapdParam->len)) { + return -EFAULT; + } + } + else { + return -E2BIG; + } + } + + prGlueInfo->prP2PInfo->u2WSCIELen[0] = prHostapdParam->len; + prGlueInfo->prP2PInfo->u2WSCIELen[2] = prHostapdParam->len; + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + bssUpdateBeaconContent(prAdapter, NETWORK_TYPE_P2P_INDEX); + + //@TODO: send message to P2P-FSM + + return 0; +} /* end of mtk_p2p_wext_wsc_ie() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_CONNECT_DISCONNECT) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_connect_disconnect( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + struct iw_point *prData= (struct iw_point *)&wrqu->data; +// P_IW_P2P_CONNECT_DEVICE prConnectDevice = (P_IW_P2P_CONNECT_DEVICE)extra; +// P_MSG_HDR_T prMsgHdr; +// P_MSG_P2P_CONNECTION_REQUEST_T prMsgP2PConnReq; +// P_MSG_P2P_CONNECTION_ABORT_T prMsgP2PConnAbt; +// UINT_8 aucBCAddr[] = BC_MAC_ADDR; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + if (prData->flags == P2P_CONNECT) { +#if 0 + // indicate P2P-FSM with MID_MNY_P2P_CONNECTION_REQ + prMsgP2PConnReq = (P_MSG_P2P_CONNECTION_REQUEST_T) cnmMemAlloc(prAdapter, + RAM_TYPE_MSG, + sizeof(MSG_P2P_CONNECTION_REQUEST_T)); + + if (!prMsgP2PConnReq) { + ASSERT(0); // Can't trigger P2P FSM + return -ENOMEM; + } + + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prMsgP2PConnReq, + MSG_SEND_METHOD_BUF); +#endif + } + else if(prData->flags == P2P_DISCONNECT) { +#if 0 + // indicate P2P-FSM with MID_MNY_P2P_CONNECTION_ABORT + prMsgP2PConnAbt = (P_MSG_HDR_T) cnmMemAlloc(prAdapter, + RAM_TYPE_MSG, + sizeof(MSG_P2P_CONNECTION_ABORT_T)); + + if (!prMsgP2PConnAbt) { + ASSERT(0); // Can't trigger P2P FSM + return -ENOMEM; + } + + COPY_MAC_ADDR(prMsgP2PConnAbt->aucTargetID, prConnectDevice->sta_addr); + + prMsgP2PConnAbt->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_ABORT; + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prMsgP2PConnAbt, + MSG_SEND_METHOD_BUF); +#endif + } + else { + return -EINVAL; + } + + return 0; +} /* end of mtk_p2p_wext_connect_disconnect() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_PASSWORD_READY) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_password_ready( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_IW_P2P_PASSWORD_READY prPasswordReady = (P_IW_P2P_PASSWORD_READY)extra; + P_P2P_CONNECTION_SETTINGS_T prConnSettings; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + prConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + + /* retrieve IE for Probe Request */ + if (prPasswordReady->probe_req_len > 0) { + if (prPasswordReady->probe_req_len <= MAX_WSC_IE_LENGTH) { + if (copy_from_user(prGlueInfo->prP2PInfo->aucWSCIE[1], prPasswordReady->probe_req_ie, prPasswordReady->probe_req_len)) { + return -EFAULT; + } + } + else { + return -E2BIG; + } + } + + prGlueInfo->prP2PInfo->u2WSCIELen[1] = prPasswordReady->probe_req_len; + + /* retrieve IE for Probe Response */ + if (prPasswordReady->probe_rsp_len > 0) { + if (prPasswordReady->probe_rsp_len <= MAX_WSC_IE_LENGTH) { + if (copy_from_user(prGlueInfo->prP2PInfo->aucWSCIE[2], prPasswordReady->probe_rsp_ie, prPasswordReady->probe_rsp_len)) { + return -EFAULT; + } + } + else { + return -E2BIG; + } + } + + prGlueInfo->prP2PInfo->u2WSCIELen[2] = prPasswordReady->probe_rsp_len; + + switch (prPasswordReady->active_config_method) { + case 1: + prConnSettings->u2LocalConfigMethod = WPS_ATTRI_CFG_METHOD_PUSH_BUTTON; + break; + case 2: + prConnSettings->u2LocalConfigMethod = WPS_ATTRI_CFG_METHOD_KEYPAD; + break; + case 3: + prConnSettings->u2LocalConfigMethod = WPS_ATTRI_CFG_METHOD_DISPLAY; + break; + default: + break; + } + + prConnSettings->fgIsPasswordIDRdy = TRUE; + return 0; +} /* end of mtk_p2p_wext_password_ready() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_GET_REQ_DEVICE_INFO) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_request_dev_info( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_IW_P2P_DEVICE_REQ prDeviceReq = (P_IW_P2P_DEVICE_REQ)extra; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + // specify data length + wrqu->data.length = sizeof(IW_P2P_DEVICE_REQ); + + // copy to upper-layer supplied buffer + kalMemCopy(prDeviceReq->name, prGlueInfo->prP2PInfo->aucConnReqDevName, prGlueInfo->prP2PInfo->u4ConnReqNameLength); + prDeviceReq->name_len = prGlueInfo->prP2PInfo->u4ConnReqNameLength; + prDeviceReq->name[prDeviceReq->name_len]='\0'; + COPY_MAC_ADDR(prDeviceReq->device_addr, prGlueInfo->prP2PInfo->rConnReqPeerAddr); + prDeviceReq->device_type = prGlueInfo->prP2PInfo->ucConnReqDevType; + prDeviceReq->config_method = prGlueInfo->prP2PInfo->i4ConnReqConfigMethod; + prDeviceReq->active_config_method = prGlueInfo->prP2PInfo->i4ConnReqActiveConfigMethod; + + return 0; +} /* end of mtk_p2p_wext_request_dev_info() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_GET_STRUCT) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_invitation_indicate( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_IW_P2P_IOCTL_INVITATION_INDICATE prInvIndicate = (P_IW_P2P_IOCTL_INVITATION_INDICATE)extra; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + // specify data length + wrqu->data.length = sizeof(IW_P2P_IOCTL_INVITATION_INDICATE); + + // copy to upper-layer supplied buffer + kalMemCopy(prInvIndicate->dev_name, prGlueInfo->prP2PInfo->aucConnReqDevName, prGlueInfo->prP2PInfo->u4ConnReqNameLength); + kalMemCopy(prInvIndicate->group_bssid, prGlueInfo->prP2PInfo->rConnReqGroupAddr, MAC_ADDR_LEN); + prInvIndicate->name_len = prGlueInfo->prP2PInfo->u4ConnReqNameLength; + prInvIndicate->dev_name[prInvIndicate->name_len]='\0'; + COPY_MAC_ADDR(prInvIndicate->dev_addr, prGlueInfo->prP2PInfo->rConnReqPeerAddr); + prInvIndicate->config_method = prGlueInfo->prP2PInfo->i4ConnReqConfigMethod; + prInvIndicate->operating_channel = prGlueInfo->prP2PInfo->ucOperatingChnl; + prInvIndicate->invitation_type = prGlueInfo->prP2PInfo->ucInvitationType; + + return 0; +} /* end of mtk_p2p_wext_invitation_indicate() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_GET_STRUCT) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_invitation_status( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_IW_P2P_IOCTL_INVITATION_STATUS prInvStatus = (P_IW_P2P_IOCTL_INVITATION_STATUS)extra; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + // specify data length + wrqu->data.length = sizeof(IW_P2P_IOCTL_INVITATION_STATUS); + + // copy to upper-layer supplied buffer + prInvStatus->status_code = prGlueInfo->prP2PInfo->u4InvStatus; + + return 0; +} /* end of mtk_p2p_wext_invitation_status() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief indicate an event to supplicant for device found +* +* \param[in] prGlueInfo Pointer of GLUE_INFO_T +* +* \retval TRUE Success. +* \retval FALSE Failure +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +kalP2PIndicateFound( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + union iwreq_data evt; + UINT_8 aucBuffer[IW_CUSTOM_MAX]; + + ASSERT(prGlueInfo); + + memset(&evt, 0, sizeof(evt)); + + snprintf(aucBuffer, IW_CUSTOM_MAX-1, "P2P_DVC_FND"); + evt.data.length = strlen(aucBuffer); + + /* indicate IWEVP2PDVCFND event */ + wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, + IWEVCUSTOM, + &evt, + aucBuffer); + + return FALSE; +} /* end of kalP2PIndicateFound() */ + +int +mtk_p2p_wext_set_network_address ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + //@TODO: invoke wlan_p2p functions +#if 0 + rStatus = kalIoctl(prGlueInfo, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetP2pNetworkAddress, + prKey, + prKey->u4Length, + FALSE, + FALSE, + TRUE, + &u4BufLen); +#endif + + return 0; + +} + +int +mtk_p2p_wext_set_ps_profile ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + //@TODO: invoke wlan_p2p functions +#if 0 + rStatus = kalIoctl(prGlueInfo, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetP2pPowerSaveProfile, + prKey, + prKey->u4Length, + FALSE, + FALSE, + TRUE, + &u4BufLen); +#endif + + return 0; + +} + +int +mtk_p2p_wext_set_pm_param ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + //@TODO: invoke wlan_p2p functions +#if 0 + rStatus = kalIoctl(prGlueInfo, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetP2pPowerSaveProfile, + prKey, + prKey->u4Length, + FALSE, + FALSE, + TRUE, + &u4BufLen); +#endif + + return 0; + +} + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_SET_INT) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Setting parameters not support. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_start_formation ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + int i4Status = 0; + P_ADAPTER_T prAdapter = (P_ADAPTER_T)NULL; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; +// struct iw_point *prData = (struct iw_point*)&wrqu->data; + P_IW_P2P_IOCTL_START_FORMATION prIoctlStartFormation = (P_IW_P2P_IOCTL_START_FORMATION)NULL; + + do { + if ((prDev == NULL) || (extra == NULL)) { + ASSERT(FALSE); + i4Status = -EINVAL; + break; + } + + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prDev)); + prIoctlStartFormation = (P_IW_P2P_IOCTL_START_FORMATION)extra; + + if (prGlueInfo == NULL) { + i4Status = -EINVAL; + break; + } + + + prAdapter = prGlueInfo->prAdapter; + + if (prAdapter == NULL) { + i4Status = -EINVAL; + break; + } + + + } while (FALSE); + + return i4Status; + +} +/* mtk_p2p_wext_start_formation */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_SET_INT) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Setting parameters not support. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_set_int ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + int status = 0; + UINT_32 u4SubCmd = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + UINT_32 index; + INT_32 value; + PUINT_32 pu4IntBuf; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T)NULL; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T)NULL; + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + UINT_32 u4Leng; + + ASSERT(prDev); + ASSERT(wrqu); + + //printk("mtk_p2p_wext_set_int\n"); + pu4IntBuf = (PUINT_32) extra; + + if (FALSE == GLUE_CHK_PR2(prDev, wrqu)) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prP2pSpecificBssInfo = prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo; + prP2pConnSettings = prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings; + prP2pFsmInfo = prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo; + + u4SubCmd = (UINT_32) wrqu->mode; + index = pu4IntBuf[1]; + value = pu4IntBuf[2]; + + printk("set parameter, u4SubCmd=%d idx=%d value=%lu\n", (INT_16)u4SubCmd, (INT_16)index, value); + + switch (u4SubCmd) { + case PRIV_CMD_INT_P2P_SET: + switch (index) { + case 0: /* Listen CH */ + { + UINT_8 ucSuggestChnl = 0; + + prP2pConnSettings->ucListenChnl = value; + + // 20110920 - frog: User configurations are placed in ConnSettings. + if (rlmFuncFindAvailableChannel(prGlueInfo->prAdapter, value, &ucSuggestChnl, TRUE, TRUE)) { + prP2pSpecificBssInfo->ucListenChannel = value; + } + else { + prP2pSpecificBssInfo->ucListenChannel = ucSuggestChnl; + } + + + break; + } + case 1: /* P2p mode */ + break; + case 4: /* Noa duration */ + prP2pSpecificBssInfo->rNoaParam.u4NoaDurationMs = value; + // only to apply setting when setting NOA count + //status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); + break; + case 5: /* Noa interval */ + prP2pSpecificBssInfo->rNoaParam.u4NoaIntervalMs = value; + // only to apply setting when setting NOA count + //status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); + break; + case 6: /* Noa count */ + prP2pSpecificBssInfo->rNoaParam.u4NoaCount = value; + status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); + break; + case 100: /* Oper CH */ + // 20110920 - frog: User configurations are placed in ConnSettings. + prP2pConnSettings->ucOperatingChnl = value; + break; + case 101: /* Local config Method, for P2P SDK */ + //prP2pConnSettings->u2LocalConfigMethod; + break; + case 102: /* Sigma P2p reset */ + kalMemZero(prP2pConnSettings->aucTargetDevAddr, MAC_ADDR_LEN); + //prP2pConnSettings->eConnectionPolicy = ENUM_P2P_CONNECTION_POLICY_AUTO; + break; + case 103: /* WPS MODE */ + kalP2PSetWscMode(prGlueInfo, value); + break; + case 104: /* P2p send persence, duration */ + break; + case 105: /* P2p send persence, interval */ + break; + case 106: /* P2P set sleep */ + value = 1; + kalIoctl(prGlueInfo, + wlanoidSetP2pPowerSaveProfile, + &value, + sizeof(value), + FALSE, + FALSE, + TRUE, + TRUE, + &u4Leng); + break; + case 107: /* P2P set opps, CTWindowl */ + prP2pSpecificBssInfo->rOppPsParam.u4CTwindowMs = value; + status = mtk_p2p_wext_set_oppps_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rOppPsParam); + break; + case 108: /* p2p_set_power_save */ + kalIoctl(prGlueInfo, + wlanoidSetP2pPowerSaveProfile, + &value, + sizeof(value), + FALSE, + FALSE, + TRUE, + TRUE, + &u4Leng); + + break; + + default: + break; + } + break; + default: + break; + } + + return status; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_SET_STRUCT) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_set_struct ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + int status = 0; + UINT_32 u4SubCmd = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + P_IW_P2P_TRANSPORT_STRUCT prP2PReq = NULL; + + ASSERT(prDev); + ASSERT(wrqu); + + if (FALSE == GLUE_CHK_PR2(prDev, wrqu)) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + u4SubCmd = (UINT_32) wrqu->data.flags; + + kalMemZero(&prGlueInfo->prP2PInfo->aucOidBuf[0], + sizeof(prGlueInfo->prP2PInfo->aucOidBuf)); + + switch (u4SubCmd) { + case PRIV_CMD_OID: + if (copy_from_user(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), + wrqu->data.pointer, + wrqu->data.length)) { + status = -EFAULT; + break; + } + + if (!kalMemCmp(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), extra, wrqu->data.length)) { + printk(KERN_INFO DRV_NAME"extra buffer is valid\n"); + } + else { + printk(KERN_INFO DRV_NAME"extra 0x%p\n", extra); + } + + prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) (&(prGlueInfo->prP2PInfo->aucOidBuf[0])); + switch(prP2PReq->u4CmdId) { + case P2P_CMD_ID_SEND_SD_RESPONSE: + status = mtk_p2p_wext_send_service_discovery_response(prDev, info, wrqu, (char *)prP2PReq); + break; + + case P2P_CMD_ID_SEND_SD_REQUEST: + status = mtk_p2p_wext_send_service_discovery_request(prDev, info, wrqu, (char *)prP2PReq); + break; + + case P2P_CMD_ID_TERMINATE_SD_PHASE: + status = mtk_p2p_wext_terminate_service_discovery_phase(prDev, info, wrqu, (char *)prP2PReq); + break; + + case P2P_CMD_ID_INVITATION: + if (prP2PReq->inBufferLength == sizeof(IW_P2P_IOCTL_INVITATION_STRUCT)) { +// status = mtk_p2p_wext_invitation_request(prDev, info, wrqu, (char *)(prP2PReq->aucBuffer)); + } + break; + + case P2P_CMD_ID_INVITATION_ABORT: + if (prP2PReq->inBufferLength == sizeof(IW_P2P_IOCTL_ABORT_INVITATION)) { +// status = mtk_p2p_wext_invitation_abort(prDev, info, wrqu, (char *)(prP2PReq->aucBuffer)); + } + break; + + case P2P_CMD_ID_START_FORMATION: + if (prP2PReq->inBufferLength == sizeof(IW_P2P_IOCTL_START_FORMATION)) { + status = mtk_p2p_wext_start_formation(prDev, info, wrqu, (char *)(prP2PReq->aucBuffer)); + } + break; + default: + status = -EOPNOTSUPP; + } + + break; +#if CFG_SUPPORT_ANTI_PIRACY + case PRIV_SEC_CHECK_OID: + if (wrqu->data.length > 256) { + status = -EOPNOTSUPP; + break; + } + if (copy_from_user(&(prGlueInfo->prP2PInfo->aucSecCheck[0]), + wrqu->data.pointer, + wrqu->data.length)) { + status = -EFAULT; + break; + } + + if (!kalMemCmp(&(prGlueInfo->prP2PInfo->aucSecCheck[0]), extra, wrqu->data.length)) { + printk(KERN_INFO DRV_NAME"extra buffer is valid\n"); + } + else { + printk(KERN_INFO DRV_NAME"extra 0x%p\n", extra); + } + prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) (&(prGlueInfo->prP2PInfo->aucSecCheck[0])); + + switch(prP2PReq->u4CmdId) { + case P2P_CMD_ID_SEC_CHECK: + status = mtk_p2p_wext_set_sec_check_request(prDev, info, wrqu, (char *)prP2PReq); + break; + default: + status = -EOPNOTSUPP; + } + break; +#endif + case PRIV_CMD_P2P_VERSION: + if (copy_from_user(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), + wrqu->data.pointer, + wrqu->data.length)) { + status = -EFAULT; + break; + } + + if (!kalMemCmp(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), extra, wrqu->data.length)) { + printk(KERN_INFO DRV_NAME"extra buffer is valid\n"); + } + else { + printk(KERN_INFO DRV_NAME"extra 0x%p\n", extra); + } + + prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) (&(prGlueInfo->prP2PInfo->aucOidBuf[0])); + switch (prP2PReq->u4CmdId) { + case P2P_CMD_ID_P2P_VERSION: + status = mtk_p2p_wext_set_p2p_version(prDev, info, wrqu, (char *)prP2PReq); + break; + default: + status = -EOPNOTSUPP; + break; + } + break; + default: + status = -EOPNOTSUPP; + break; + } + + return status; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_GET_STRUCT) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_get_struct ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + int status = 0; + UINT_32 u4SubCmd = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + P_IW_P2P_TRANSPORT_STRUCT prP2PReq = NULL; + + ASSERT(prDev); + ASSERT(wrqu); + + if (!prDev || !wrqu) { + printk(KERN_INFO DRV_NAME "%s(): invalid param(0x%p, 0x%p)\n", + __func__, + prDev, + wrqu); + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + u4SubCmd = (UINT_32) wrqu->data.flags; + + kalMemZero(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), + sizeof(prGlueInfo->prP2PInfo->aucOidBuf)); + + switch (u4SubCmd) { + case PRIV_CMD_OID: + if (copy_from_user(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), + wrqu->data.pointer, + sizeof(IW_P2P_TRANSPORT_STRUCT))) { + printk(KERN_NOTICE "%s() copy_from_user oidBuf fail\n", __func__); + return -EFAULT; + } + + prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) (&(prGlueInfo->prP2PInfo->aucOidBuf[0])); + + switch(prP2PReq->u4CmdId) { + case P2P_CMD_ID_GET_SD_REQUEST: + status = mtk_p2p_wext_get_service_discovery_request(prDev, info, wrqu, (char *)prP2PReq); + break; + + case P2P_CMD_ID_GET_SD_RESPONSE: + status = mtk_p2p_wext_get_service_discovery_response(prDev, info, wrqu, (char *)prP2PReq); + break; + + case P2P_CMD_ID_INVITATION_INDICATE: + { + status = mtk_p2p_wext_invitation_indicate(prDev, info, wrqu, (char *)(prP2PReq->aucBuffer)); + prP2PReq->outBufferLength = wrqu->data.length; + if (copy_to_user(wrqu->data.pointer, + &(prGlueInfo->prP2PInfo->aucOidBuf[0]), + wrqu->data.length + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { + printk(KERN_NOTICE "%s() copy_to_user() fail\n", __func__); + return -EIO; + } + else { + return 0; + } + break; + } + case P2P_CMD_ID_INVITATION_STATUS: + { + status = mtk_p2p_wext_invitation_status(prDev, info, wrqu, (char *)(prP2PReq->aucBuffer)); + prP2PReq->outBufferLength = wrqu->data.length; + if (copy_to_user(wrqu->data.pointer, + &(prGlueInfo->prP2PInfo->aucOidBuf[0]), + wrqu->data.length + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { + printk(KERN_NOTICE "%s() copy_to_user() fail\n", __func__); + return -EIO; + } + else { + return 0; + } + break; + } + case P2P_CMD_ID_GET_CH_LIST: + { + UINT_16 i; + UINT_8 NumOfChannel = 50; + RF_CHANNEL_INFO_T aucChannelList[50]; + UINT_8 ucMaxChannelNum = 50; + PUINT_8 pucChnlList = (PUINT_8)prP2PReq->aucBuffer; + + kalGetChnlList(prGlueInfo, BAND_NULL, ucMaxChannelNum, &NumOfChannel, aucChannelList); + if (NumOfChannel > 50) + NumOfChannel = 50; + prP2PReq->outBufferLength = NumOfChannel; + + for (i=0; iaucBuffer[i] = aucChannelList[i].ucChannelNum; +#else + *pucChnlList = aucChannelList[i].ucChannelNum; + pucChnlList++; +#endif + } + if(copy_to_user(wrqu->data.pointer, + &(prGlueInfo->prP2PInfo->aucOidBuf[0]), + NumOfChannel + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { + printk(KERN_NOTICE "%s() copy_to_user() fail\n", __func__); + return -EIO; + } + else { + return 0; + } + break; + } + + case P2P_CMD_ID_GET_OP_CH: + { + prP2PReq->inBufferLength = 4; + + status = wlanoidQueryP2pOpChannel(prGlueInfo->prAdapter, + prP2PReq->aucBuffer, + prP2PReq->inBufferLength, + &prP2PReq->outBufferLength); + + if (status == 0) { // WLAN_STATUS_SUCCESS + if (copy_to_user(wrqu->data.pointer, + &(prGlueInfo->prP2PInfo->aucOidBuf[0]), + prP2PReq->outBufferLength + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { + printk(KERN_NOTICE "%s() copy_to_user() fail\n", __func__); + return -EIO; + } + } + else { + if (copy_to_user(wrqu->data.pointer, + &(prGlueInfo->prP2PInfo->aucOidBuf[0]), + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { + printk(KERN_NOTICE "%s() copy_to_user() fail\n", __func__); + return -EIO; + } + } + break; + } + + default: + status = -EOPNOTSUPP; + } + + break; +#if CFG_SUPPORT_ANTI_PIRACY + case PRIV_SEC_CHECK_OID: + if (wrqu->data.length > 256) { + status = -EOPNOTSUPP; + break; + } + if (copy_from_user(&(prGlueInfo->prP2PInfo->aucSecCheck[0]), + wrqu->data.pointer, + sizeof(IW_P2P_TRANSPORT_STRUCT))) { + printk(KERN_NOTICE "%s() copy_from_user oidBuf fail\n", __func__); + return -EFAULT; + } + + prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) (&(prGlueInfo->prP2PInfo->aucSecCheck[0])); + + switch(prP2PReq->u4CmdId) { + case P2P_CMD_ID_SEC_CHECK: + status = mtk_p2p_wext_get_sec_check_response(prDev, info, wrqu, (char *)prP2PReq); + break; + default: + status = -EOPNOTSUPP; + } + break; +#endif + case PRIV_CMD_P2P_VERSION: + if (copy_from_user(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), + wrqu->data.pointer, + sizeof(IW_P2P_TRANSPORT_STRUCT))) { + printk(KERN_NOTICE "%s() copy_from_user oidBuf fail\n", __func__); + return -EFAULT; + } + + prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) (&(prGlueInfo->prP2PInfo->aucOidBuf[0])); + + switch (prP2PReq->u4CmdId) { + case P2P_CMD_ID_P2P_VERSION: + status = mtk_p2p_wext_get_p2p_version(prDev, info, wrqu, (char *)prP2PReq); + break; + default: + status = -EOPNOTSUPP; + break; + } + + + /* Copy queried data to user. */ + if (status == 0) { // WLAN_STATUS_SUCCESS + if(copy_to_user(wrqu->data.pointer, + &(prGlueInfo->prP2PInfo->aucOidBuf[0]), + prP2PReq->outBufferLength + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { + printk(KERN_NOTICE "%s() copy_to_user() fail\n", __func__); + return -EIO; + } + } + + else { + if(copy_to_user(wrqu->data.pointer, + &(prGlueInfo->prP2PInfo->aucOidBuf[0]), + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { + printk(KERN_NOTICE "%s() copy_to_user() fail\n", __func__); + return -EIO; + } + } + + break; + default: + return -EOPNOTSUPP; + } + + return status; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler for +* getting service discovery request frame from driver +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_get_service_discovery_request ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4QueryInfoLen; + P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT)extra; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + rStatus = kalIoctl(prGlueInfo, + wlanoidGetP2PSDRequest, + prP2PReq->aucBuffer, + prP2PReq->outBufferLength, + TRUE, + FALSE, + TRUE, + TRUE, + &u4QueryInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + else { + prP2PReq->outBufferLength = u4QueryInfoLen; + + if(copy_to_user(wrqu->data.pointer, + &(prGlueInfo->prP2PInfo->aucOidBuf[0]), + u4QueryInfoLen + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { + printk(KERN_NOTICE "%s() copy_to_user() fail\n", __func__); + return -EIO; + } + else { + return 0; + } + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler for +* getting service discovery response frame from driver +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_get_service_discovery_response ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4QueryInfoLen; + P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT)extra; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + rStatus = kalIoctl(prGlueInfo, + wlanoidGetP2PSDResponse, + prP2PReq->aucBuffer, + prP2PReq->outBufferLength, + TRUE, + FALSE, + TRUE, + TRUE, + &u4QueryInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + else { + prP2PReq->outBufferLength = u4QueryInfoLen; + + if(copy_to_user(wrqu->data.pointer, + &(prGlueInfo->prP2PInfo->aucOidBuf[0]), + u4QueryInfoLen + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { + printk(KERN_NOTICE "%s() copy_to_user() fail\n", __func__); + return -EIO; + } + else { + return 0; + } + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler for +* sending service discovery request frame +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_send_service_discovery_request ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4SetInfoLen; + P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT)extra; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSendP2PSDRequest, + prP2PReq->aucBuffer, + prP2PReq->inBufferLength, + FALSE, + FALSE, + TRUE, + TRUE, + &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + else { + return 0; + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler for +* sending service discovery response frame +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_send_service_discovery_response ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4SetInfoLen; + P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT)extra; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSendP2PSDResponse, + prP2PReq->aucBuffer, + prP2PReq->inBufferLength, + FALSE, + FALSE, + TRUE, + TRUE, + &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + else { + return 0; + } +} + +#if CFG_SUPPORT_ANTI_PIRACY +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler for +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_set_sec_check_request ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4SetInfoLen; + P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT)extra; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetSecCheckRequest, + prP2PReq->aucBuffer, + prP2PReq->inBufferLength, + FALSE, + FALSE, + TRUE, + TRUE, + &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + else { + return 0; + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler for +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_get_sec_check_response ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4QueryInfoLen; + P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT)extra; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + printk("mtk_p2p_wext_get_sec_check_response\n"); + rStatus = kalIoctl(prGlueInfo, + wlanoidGetSecCheckResponse, + prP2PReq->aucBuffer, + prP2PReq->outBufferLength, + TRUE, + FALSE, + TRUE, + TRUE, + &u4QueryInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + else { + prP2PReq->outBufferLength = u4QueryInfoLen; + + if(copy_to_user(wrqu->data.pointer, + prP2PReq->aucBuffer, + u4QueryInfoLen + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { + printk(KERN_NOTICE "%s() copy_to_user() fail\n", __func__); + return -EIO; + } + else { + return 0; + } + } +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler for +* terminating service discovery phase +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_terminate_service_discovery_phase ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4SetInfoLen; + P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT)extra; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetP2PTerminateSDPhase, + prP2PReq->aucBuffer, + prP2PReq->inBufferLength, + FALSE, + FALSE, + TRUE, + TRUE, + &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + else { + return 0; + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler for +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_set_noa_param ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4SetInfoLen; + //P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT)extra; + P_PARAM_CUSTOM_NOA_PARAM_STRUC_T prNoaParam = (P_PARAM_CUSTOM_NOA_PARAM_STRUC_T)extra; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + printk("mtk_p2p_wext_set_noa_param\n"); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetNoaParam, + prNoaParam, //prP2PReq->aucBuffer, + sizeof(PARAM_CUSTOM_NOA_PARAM_STRUC_T),//prP2PReq->inBufferLength, + FALSE, + FALSE, + TRUE, + TRUE, + &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + else { + return 0; + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler for +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_set_oppps_param ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4SetInfoLen; +// P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT)extra; + P_PARAM_CUSTOM_OPPPS_PARAM_STRUC_T prOppPsParam = (P_PARAM_CUSTOM_OPPPS_PARAM_STRUC_T)extra; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + printk("mtk_p2p_wext_set_oppps_param\n"); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetOppPsParam, + prOppPsParam, //prP2PReq->aucBuffer, + sizeof(PARAM_CUSTOM_OPPPS_PARAM_STRUC_T), //prP2PReq->inBufferLength, + FALSE, + FALSE, + TRUE, + TRUE, + &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + else { + return 0; + } +} + + +int +mtk_p2p_wext_set_p2p_version ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_GLUE_INFO_T prGlueInfo = NULL; + P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT)extra; + UINT_32 u4SetInfoLen; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetP2pSupplicantVersion, + prP2PReq->aucBuffer, + prP2PReq->inBufferLength, + FALSE, + FALSE, + TRUE, + TRUE, + &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + else { + return rStatus; + } + + +} +/* mtk_p2p_wext_set_p2p_version */ + +int +mtk_p2p_wext_get_p2p_version ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4QueryInfoLen; + P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT)extra; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryP2pVersion, + prP2PReq->aucBuffer, + prP2PReq->outBufferLength, + TRUE, + FALSE, + TRUE, + TRUE, + &u4QueryInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + else { + return rStatus; + } + + +} /* mtk_p2p_wext_get_p2p_version */ + +#if CFG_SUPPORT_P2P_RSSI_QUERY + +int +mtk_p2p_wext_get_rssi ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4QueryInfoLen; + struct iw_point *prData= (struct iw_point *)&wrqu->data; + UINT_16 u2BufferSize = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + INT_32 i4Rssi; + struct iw_statistics *pStats = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + if (!prGlueInfo) { + rStatus = WLAN_STATUS_FAILURE; + goto stat_out; + } + + pStats = (struct iw_statistics *) (&(prGlueInfo->rP2pIwStats)); + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryP2pRssi, + &i4Rssi, + sizeof(i4Rssi), + TRUE, + TRUE, + TRUE, + TRUE, + &u4QueryInfoLen); + + u2BufferSize = prData->length; + + if (u2BufferSize < sizeof(struct iw_statistics)) { + return -E2BIG; + } + + + if (copy_to_user(prData->pointer, pStats, sizeof(struct iw_statistics))) { + rStatus = WLAN_STATUS_FAILURE; + } + + +stat_out: + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + else { + return rStatus; + } + +} /* mtk_p2p_wext_get_rssi */ + +struct iw_statistics * +mtk_p2p_wext_get_wireless_stats ( + struct net_device *prDev + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + P_GLUE_INFO_T prGlueInfo = NULL; + struct iw_statistics *pStats = NULL; + INT_32 i4Rssi; + UINT_32 bufLen = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prDev)); + ASSERT(prGlueInfo); + if (!prGlueInfo) { + goto stat_out; + } + + pStats = (struct iw_statistics *) (&(prGlueInfo->rP2pIwStats)); + + if (!prDev || !netif_carrier_ok(prDev)) { + /* network not connected */ + goto stat_out; + } + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryP2pRssi, + &i4Rssi, + sizeof(i4Rssi), + TRUE, + TRUE, + TRUE, + TRUE, + &bufLen); + +stat_out: + return pStats; +} /* mtk_p2p_wext_get_wireless_stats */ + + +#endif /* CFG_SUPPORT_P2P_RSSI_QUERY */ + + +int +mtk_p2p_wext_set_txpow ( + IN struct net_device *prDev, + IN struct iw_request_info *prIwrInfo, + IN OUT union iwreq_data *prTxPow, + IN char *pcExtra + ) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + P_ADAPTER_T prAdapter = (P_ADAPTER_T)NULL; +#if 0 + P_MSG_P2P_FUNCTION_SWITCH_T prMsgFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T)NULL; +#endif + int i4Ret = 0; + + ASSERT(prDev); + ASSERT(prTxPow); + + do { + if ((!prDev) || (!prTxPow)) { + i4Ret = -EINVAL; + break; + } + + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prDev)); + + if (!prGlueInfo) { + i4Ret = -EINVAL; + break; + } + + + prAdapter = prGlueInfo->prAdapter; +#if 0 + prMsgFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_FUNCTION_SWITCH_T)); + if (!prMsgFuncSwitch) { + ASSERT(0); + return -ENOMEM; + } + + prMsgFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; + + if (prTxPow->disabled) { + /* Dissolve. */ + prMsgFuncSwitch->fgIsFuncOn = FALSE; + } + else { + + /* Re-enable function. */ + prMsgFuncSwitch->fgIsFuncOn = TRUE; + } + + /* 1.3 send message */ + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prMsgFuncSwitch, + MSG_SEND_METHOD_BUF); +#endif + + } while (FALSE); + + return i4Ret; +} /* mtk_p2p_wext_set_txpow */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/gl_p2p_cfg80211.c b/drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/gl_p2p_cfg80211.c new file mode 100755 index 000000000000..868aeb032555 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/gl_p2p_cfg80211.c @@ -0,0 +1,1755 @@ +/* +** $Id: @(#) gl_p2p_cfg80211.c@@ +*/ + +/*! \file gl_p2p_cfg80211.c + \brief Main routines of Linux driver interface for Wi-Fi Direct + using cfg80211 interface + + This file contains the main routines of Linux driver for MediaTek Inc. 802.11 + Wireless LAN Adapters. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: gl_p2p_cfg80211.c $ + * + * 02 23 2012 chinglan.wang + * [ALPS00240621] [Wifi P2P]Run Sigma tool of A69. Always run fail on 7.1.3. sniffer check Sta-IsActive-No-Frames-With-PowerMgmt-1 + * . + * + * 02 06 2012 yuche.tsai + * [ALPS00118350] [ALPS.ICS][WiFi Direct] Dirver update for wifi direct connection + * Small bug fix for CNM memory usage, scan SSID search issue, P2P network deactivate issue. + * + * 01 31 2012 yuche.tsai + * NULL + * Fix compile error & del beacon scenario. + * + * 01 27 2012 yuche.tsai + * NULL + * Update for GC connection . + * + * 01 26 2012 yuche.tsai + * NULL + * Fix compile warning. + * + * 01 18 2012 yuche.tsai + * NULL + * Bug fix for memory allocation. + * + * 01 18 2012 yuche.tsai + * NULL + * Change debug log from printk to DBGLOG. + * Fix probe request issue. + * + * 01 18 2012 yuche.tsai + * NULL + * Add get station info API. + * TX deauth before start beacon. + * + * 01 17 2012 wh.su + * [WCXRP00001173] [MT6620 Wi-Fi][Driver] Adding the ICS Tethering WPA2-PSK supporting + * adding the code to fix the add key function. + * + * 01 17 2012 yuche.tsai + * NULL + * Update mgmt frame filter setting. + * Please also update FW 2.1 + * + * 01 16 2012 yuche.tsai + * NULL + * Update Driver for wifi driect gc join IE update issue. + * + * 01 16 2012 chinglan.wang + * NULL + * Update security code.. + * + * 01 16 2012 yuche.tsai + * NULL + * Fix wifi direct scan bug. + * + * 01 15 2012 yuche.tsai + * NULL + * Update P2P scan issue for ICS. + * + * 01 15 2012 yuche.tsai + * NULL + * ICS P2P Driver Update. + * + * 01 15 2012 yuche.tsai + * NULL + * Fix p2p scan bug. + * + * 01 15 2012 yuche.tsai + * NULL + * Fix scan bug. + * + * 01 15 2012 yuche.tsai + * NULL + * ICS Wi-Fi Direct Update. + * + * 01 13 2012 yuche.tsai + * NULL + * Update driver/p2p driver for ICS tethering mode. + * Fix FW reply probe request issue. + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Tethering for ICS code update. - fix KE when indicate Probe Request. + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Direct Driver Update for ICS. + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Hot Spot Tethering for ICS ALPHA testing version. + * + * 01 09 2012 terry.wu + * [WCXRP00001166] [Wi-Fi] [Driver] cfg80211 integration for p2p newtork + * cfg80211 integration for p2p network. + * + * 03 19 2011 terry.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 p2p driver release based on label "MT6620_WIFI_P2P_DRIVER_V2_0_2100_0319_2011" from main trunk. + * + * 09 21 2010 kevin.huang + * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface + * Isolate P2P related function for Hardware Software Bundle + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 31 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add cfg80211 interface, which is to replace WE, for further extension + * +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "config.h" + +#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_WIFI_DIRECT_CFG_80211 +#include +#include +#include +#include +#include + +#include "p2p_precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +#if 0 +static add_set_beacon_count = 0; +#endif +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +BOOLEAN +mtk_p2p_cfg80211func_channel_format_switch( + IN struct ieee80211_channel *channel, + IN enum nl80211_channel_type channel_type, + IN P_RF_CHANNEL_INFO_T prRfChnlInfo, + IN P_ENUM_CHNL_EXT_T prChnlSco + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) +int mtk_p2p_cfg80211_add_key( + struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, + bool pairwise, + const u8 *mac_addr, + struct key_params *params + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + INT_32 i4Rslt = -EINVAL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + P2P_PARAM_KEY_T rKey; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + kalMemZero(&rKey, sizeof(P2P_PARAM_KEY_T)); + + rKey.u4KeyIndex = key_index; + if(mac_addr) { + memcpy(rKey.arBSSID, mac_addr, ETH_ALEN); + if (rKey.arBSSID[1] == 0x00) { + rKey.arBSSID[0] = 0xff; + rKey.arBSSID[1] = 0xff; + rKey.arBSSID[2] = 0xff; + rKey.arBSSID[3] = 0xff; + rKey.arBSSID[4] = 0xff; + rKey.arBSSID[5] = 0xff; + } + if (rKey.arBSSID[0] != 0xFF) { + rKey.u4KeyIndex |= BIT(31); + if (/* rKey.arBSSID[0] != 0x00 && */ + rKey.arBSSID[1] != 0x00 ) + rKey.u4KeyIndex |= BIT(30); + } + } + else { + rKey.arBSSID[0] = 0xff; + rKey.arBSSID[1] = 0xff; + rKey.arBSSID[2] = 0xff; + rKey.arBSSID[3] = 0xff; + rKey.arBSSID[4] = 0xff; + rKey.arBSSID[5] = 0xff; + rKey.u4KeyIndex |= BIT(31); //???? + } + if(params->key) + { + //rKey.aucKeyMaterial[0] = kalMemAlloc(params->key_len, VIR_MEM_TYPE); + kalMemCopy(rKey.aucKeyMaterial, params->key, params->key_len); + } + rKey.u4KeyLength = params->key_len; + rKey.u4Length = ((UINT_32)&(((P_P2P_PARAM_KEY_T)0)->aucKeyMaterial)) + rKey.u4KeyLength; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetAddP2PKey, + &rKey, + rKey.u4Length, + FALSE, + FALSE, + TRUE, + TRUE, + &u4BufLen); + if (rStatus == WLAN_STATUS_SUCCESS) + i4Rslt = 0; + + return i4Rslt; +} + + +int mtk_p2p_cfg80211_get_key( + struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, + bool pairwise, + const u8 *mac_addr, + void *cookie, + void (*callback)(void *cookie, struct key_params*) + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + // not implemented yet + + return -EINVAL; +} + +int mtk_p2p_cfg80211_del_key( + struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, + bool pairwise, + const u8 *mac_addr + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_REMOVE_KEY_T prRemoveKey; + INT_32 i4Rslt = -EINVAL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + kalMemZero(&prRemoveKey, sizeof(PARAM_REMOVE_KEY_T)); + if(mac_addr) + memcpy(prRemoveKey.arBSSID, mac_addr, PARAM_MAC_ADDR_LEN); + prRemoveKey.u4KeyIndex = key_index; + prRemoveKey.u4Length = sizeof(PARAM_REMOVE_KEY_T); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetRemoveP2PKey, + &prRemoveKey, + prRemoveKey.u4Length, + FALSE, + FALSE, + TRUE, + TRUE, + &u4BufLen); + + if (rStatus == WLAN_STATUS_SUCCESS) + i4Rslt = 0; + + return i4Rslt; +} + + +int +mtk_p2p_cfg80211_set_default_key ( + struct wiphy *wiphy, + struct net_device *netdev, + u8 key_index, + bool unicast, + bool multicast + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + // not implemented yet + + return -EINVAL; +} + +int mtk_p2p_cfg80211_get_station( + struct wiphy *wiphy, + struct net_device *ndev, + u8 *mac, + struct station_info *sinfo + ) +{ + INT_32 i4RetRslt = -EINVAL; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + P_GL_P2P_INFO_T prP2pGlueInfo = (P_GL_P2P_INFO_T)NULL; + P2P_STATION_INFO_T rP2pStaInfo; + + ASSERT(wiphy); + + do { + if ((wiphy == NULL) || + (ndev == NULL) || + (sinfo == NULL) || + (mac == NULL)) { + break; + } + + + DBGLOG(P2P, TRACE, ("mtk_p2p_cfg80211_get_station\n")); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + prP2pGlueInfo = prGlueInfo->prP2PInfo; + + sinfo->filled = 0; + + /* Get station information. */ + /* 1. Inactive time? */ + p2pFuncGetStationInfo(prGlueInfo->prAdapter, + mac, + &rP2pStaInfo); + + /* Inactive time. */ + sinfo->filled |= STATION_INFO_INACTIVE_TIME; + sinfo->inactive_time = rP2pStaInfo.u4InactiveTime; + sinfo->generation = prP2pGlueInfo->i4Generation; + + i4RetRslt = 0; + } while (FALSE); + + return i4RetRslt; +} + +int +mtk_p2p_cfg80211_scan ( + struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_scan_request *request + ) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + P_GL_P2P_INFO_T prP2pGlueInfo = (P_GL_P2P_INFO_T)NULL; + P_MSG_P2P_SCAN_REQUEST_T prMsgScanRequest = (P_MSG_P2P_SCAN_REQUEST_T)NULL; + UINT_32 u4MsgSize = 0, u4Idx = 0; + INT_32 i4RetRslt = -EINVAL; + P_RF_CHANNEL_INFO_T prRfChannelInfo = (P_RF_CHANNEL_INFO_T)NULL; + P_P2P_SSID_STRUCT_T prSsidStruct = (P_P2P_SSID_STRUCT_T)NULL; + struct ieee80211_channel *prChannel = NULL; + struct cfg80211_ssid *prSsid = NULL; + + /* [---------Channel---------] [---------SSID---------][---------IE---------] */ + + + do { + if ((wiphy == NULL) || (request == NULL)) { + break; + } + + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + prP2pGlueInfo = prGlueInfo->prP2PInfo; + + if (prP2pGlueInfo == NULL) { + + ASSERT(FALSE); + break; + } + + DBGLOG(P2P, TRACE, ("mtk_p2p_cfg80211_scan.\n")); + + + if (prP2pGlueInfo->prScanRequest != NULL) { + /* There have been a scan request on-going processing. */ + DBGLOG(P2P, TRACE, ("There have been a scan request on-going processing.\n")); + break; + } + + + prP2pGlueInfo->prScanRequest = request; + + /* Should find out why the n_channels so many? */ + if (request->n_channels > MAXIMUM_OPERATION_CHANNEL_LIST) { + request->n_channels = MAXIMUM_OPERATION_CHANNEL_LIST; + DBGLOG(P2P, TRACE, ("Channel list exceed the maximun support.\n")); + } + + + u4MsgSize = sizeof(MSG_P2P_SCAN_REQUEST_T) + + (request->n_channels * sizeof(RF_CHANNEL_INFO_T)) + + (request->n_ssids * sizeof(PARAM_SSID_T)) + + request->ie_len; + + prMsgScanRequest = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, u4MsgSize); + + if (prMsgScanRequest == NULL) { + ASSERT(FALSE); + i4RetRslt = -ENOMEM; + break; + } + + + DBGLOG(P2P, TRACE, ("Generating scan request message.\n")); + + prMsgScanRequest->rMsgHdr.eMsgId = MID_MNY_P2P_DEVICE_DISCOVERY; + + + + DBGLOG(P2P, TRACE, ("Requesting channel number:%d.\n", request->n_channels)); + + for (u4Idx = 0; u4Idx < request->n_channels; u4Idx++) { + /* Translate Freq from MHz to channel number. */ + prRfChannelInfo = &(prMsgScanRequest->arChannelListInfo[u4Idx]); + prChannel = request->channels[u4Idx]; + + prRfChannelInfo->ucChannelNum = nicFreq2ChannelNum(prChannel->center_freq * 1000); + DBGLOG(P2P, TRACE, ("Scanning Channel:%d, freq: %d\n", + prRfChannelInfo->ucChannelNum, + prChannel->center_freq)); + switch (prChannel->band) { + case IEEE80211_BAND_2GHZ: + prRfChannelInfo->eBand = BAND_2G4; + break; + case IEEE80211_BAND_5GHZ: + prRfChannelInfo->eBand = BAND_5G; + break; + default: + DBGLOG(P2P, TRACE, ("UNKNOWN Band info from supplicant\n")); + prRfChannelInfo->eBand = BAND_NULL; + break; + } + + + /* Iteration. */ + prRfChannelInfo++; + } + + prMsgScanRequest->u4NumChannel = request->n_channels; + + DBGLOG(P2P, TRACE, ("Finish channel list.\n")); + + /* SSID */ + prSsid = request->ssids; + prSsidStruct = (P_P2P_SSID_STRUCT_T)prRfChannelInfo; + if (request->n_ssids) { + ASSERT(prSsidStruct == &(prMsgScanRequest->arChannelListInfo[u4Idx])); + prMsgScanRequest->prSSID = prSsidStruct; + } + + + for (u4Idx = 0; u4Idx < request->n_ssids; u4Idx++) { + COPY_SSID(prSsidStruct->aucSsid, + prSsidStruct->ucSsidLen, + request->ssids->ssid, + request->ssids->ssid_len); + + prSsidStruct++; + prSsid++; + } + + + DBGLOG(P2P, TRACE, ("Finish SSID list.\n")); + + /* IE BUFFERS */ + prMsgScanRequest->pucIEBuf = (PUINT_8)prSsidStruct; + if (request->ie_len) { + kalMemCopy(prMsgScanRequest->pucIEBuf, request->ie, request->ie_len); + prMsgScanRequest->u4IELen = request->ie_len; + } + + + DBGLOG(P2P, TRACE, ("Finish IE Buffer.\n")); + + + mboxSendMsg(prGlueInfo->prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T)prMsgScanRequest, + MSG_SEND_METHOD_BUF); + + i4RetRslt = 0; + } while (FALSE); + + return i4RetRslt; +} /* mtk_p2p_cfg80211_scan */ + +int mtk_p2p_cfg80211_set_wiphy_params( + struct wiphy *wiphy, + u32 changed + ) +{ + INT_32 i4Rslt = -EINVAL; + P_GLUE_INFO_T prGlueInfo = NULL; + + + do { + if (wiphy == NULL) { + break; + } + + + DBGLOG(P2P, TRACE, ("mtk_p2p_cfg80211_set_wiphy_params\n")); + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + if (changed & WIPHY_PARAM_RETRY_SHORT) { + // TODO: + DBGLOG(P2P, TRACE, ("The RETRY short param is changed.\n")); + } + + + if (changed & WIPHY_PARAM_RETRY_LONG) { + // TODO: + DBGLOG(P2P, TRACE, ("The RETRY long param is changed.\n")); + } + + + + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { + // TODO: + DBGLOG(P2P, TRACE, ("The RETRY fragmentation threshold is changed.\n")); + } + + + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { + // TODO: + DBGLOG(P2P, TRACE, ("The RETRY RTS threshold is changed.\n")); + } + + + if (changed & WIPHY_PARAM_COVERAGE_CLASS) { + // TODO: + DBGLOG(P2P, TRACE, ("The coverage class is changed???\n")); + } + + + i4Rslt = 0; + } while (FALSE); + + + + + return i4Rslt; +} /* mtk_p2p_cfg80211_set_wiphy_params */ + + + +int +mtk_p2p_cfg80211_join_ibss( + struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ibss_params *params + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + // not implemented yet + + return -EINVAL; +} + +int +mtk_p2p_cfg80211_leave_ibss( + struct wiphy *wiphy, + struct net_device *dev + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + // not implemented yet + + return -EINVAL; +} + +int +mtk_p2p_cfg80211_set_txpower( + struct wiphy *wiphy, + enum nl80211_tx_power_setting type, + int mbm + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + // not implemented yet + + return -EINVAL; +} + +int +mtk_p2p_cfg80211_get_txpower( + struct wiphy *wiphy, + int *dbm + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + // not implemented yet + + return -EINVAL; +} + +int +mtk_p2p_cfg80211_set_power_mgmt( + struct wiphy *wiphy, + struct net_device *dev, + bool enabled, + int timeout + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + // not implemented yet + + return -EINVAL; +} + +//&&&&&&&&&&&&&&&&&&&&&&&&&& Add for ICS Wi-Fi Direct Support. &&&&&&&&&&&&&&&&&&&&&&& + +int +mtk_p2p_cfg80211_add_set_beacon ( + struct wiphy *wiphy, + struct net_device *dev, + struct beacon_parameters *info + ) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + INT_32 i4Rslt = -EINVAL; + P_MSG_P2P_BEACON_UPDATE_T prP2pBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T)NULL; + PUINT_8 pucBuffer = (PUINT_8)NULL; + + do { + if ((wiphy == NULL) || (info == NULL)) { + break; + } + #if 0 + if (add_set_beacon_count >= 1) { + break; + } + #endif + + + + DBGLOG(P2P, TRACE, ("mtk_p2p_cfg80211_add_set_beacon.\n")); + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + + prP2pBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T)cnmMemAlloc( + prGlueInfo->prAdapter, + RAM_TYPE_MSG, + (sizeof(MSG_P2P_BEACON_UPDATE_T) + info->head_len + info->tail_len)); + + if (prP2pBcnUpdateMsg == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + + #if 0 + add_set_beacon_count += 1; + #endif + prP2pBcnUpdateMsg->rMsgHdr.eMsgId = MID_MNY_P2P_BEACON_UPDATE; + pucBuffer = prP2pBcnUpdateMsg->aucBuffer; + + if (info->head_len != 0) { + kalMemCopy(pucBuffer, info->head, info->head_len); + + prP2pBcnUpdateMsg->u4BcnHdrLen = info->head_len; + + prP2pBcnUpdateMsg->pucBcnHdr = pucBuffer; + + pucBuffer = (PUINT_8)((UINT_32)pucBuffer + (UINT_32)info->head_len); + } + else { + prP2pBcnUpdateMsg->u4BcnHdrLen = 0; + + prP2pBcnUpdateMsg->pucBcnHdr = NULL; + } + + if (info->tail_len != 0) { + UINT_8 ucLen = info->tail_len; + + prP2pBcnUpdateMsg->pucBcnBody = pucBuffer; + + /*Add TIM IE*/ + // IEEE 802.11 2007 - 7.3.2.6 + TIM_IE(pucBuffer)->ucId = ELEM_ID_TIM; + TIM_IE(pucBuffer)->ucLength = (3 + MAX_LEN_TIM_PARTIAL_BMP)/*((u4N2 - u4N1) + 4)*/; // NOTE: fixed PVB length (AID is allocated from 8 ~ 15 only) + TIM_IE(pucBuffer)->ucDTIMCount = 0/*prBssInfo->ucDTIMCount*/; // will be overwrite by FW + TIM_IE(pucBuffer)->ucDTIMPeriod = 1; + TIM_IE(pucBuffer)->ucBitmapControl = 0/*ucBitmapControl | (UINT_8)u4N1*/; // will be overwrite by FW + ucLen += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + + kalMemCopy(pucBuffer, info->tail, info->tail_len); + + prP2pBcnUpdateMsg->u4BcnBodyLen = ucLen; + } + + else { + prP2pBcnUpdateMsg->u4BcnBodyLen = 0; + + prP2pBcnUpdateMsg->pucBcnBody = NULL; + } + + prP2pBcnUpdateMsg->u4BcnInterval = info->interval; + + prP2pBcnUpdateMsg->u4DtimPeriod = info->dtim_period; + + + mboxSendMsg(prGlueInfo->prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T)prP2pBcnUpdateMsg, + MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + + } while (FALSE); + + return i4Rslt; +} + + +int +mtk_p2p_cfg80211_del_beacon ( + struct wiphy *wiphy, + struct net_device *dev + ) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + INT_32 i4Rslt = -EINVAL; + P_MSG_P2P_SWITCH_OP_MODE_T prP2pSwitchMode = (P_MSG_P2P_SWITCH_OP_MODE_T)NULL; + + do { + if (wiphy == NULL) { + break; + } + + + + DBGLOG(P2P, TRACE, ("mtk_p2p_cfg80211_del_beacon.\n")); + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + // Switch OP MOde. + prP2pSwitchMode = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_SWITCH_OP_MODE_T)); + + if (prP2pSwitchMode == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + + + prP2pSwitchMode->rMsgHdr.eMsgId = MID_MNY_P2P_BEACON_DEL; + + mboxSendMsg(prGlueInfo->prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T)prP2pSwitchMode, + MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + } while (FALSE); + + + return i4Rslt; +} /* mtk_p2p_cfg80211_del_beacon */ + +// TODO: +int +mtk_p2p_cfg80211_deauth ( + struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_deauth_request *req, + void *cookie + ) +{ + + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + // not implemented yet + DBGLOG(P2P, TRACE, ("mtk_p2p_cfg80211_deauth.\n")); + + return -EINVAL; +} /* mtk_p2p_cfg80211_deauth */ + + +// TODO: +int +mtk_p2p_cfg80211_disassoc ( + struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_disassoc_request *req, + void *cookie + ) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + DBGLOG(P2P, TRACE, ("mtk_p2p_cfg80211_disassoc.\n")); + + // not implemented yet + + return -EINVAL; +} /* mtk_p2p_cfg80211_disassoc */ + + +int +mtk_p2p_cfg80211_remain_on_channel ( + struct wiphy *wiphy, + struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + unsigned int duration, + u64 *cookie + ) +{ + INT_32 i4Rslt = -EINVAL; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T)NULL; + P_MSG_P2P_CHNL_REQUEST_T prMsgChnlReq = (P_MSG_P2P_CHNL_REQUEST_T)NULL; + + + do { + if ((wiphy == NULL) || + (dev == NULL) || + (chan == NULL) || + (cookie == NULL)) { + break; + } + + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + prGlueP2pInfo = prGlueInfo->prP2PInfo; + + *cookie = prGlueP2pInfo->u8Cookie++; + + prMsgChnlReq = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_CHNL_REQUEST_T)); + + if (prMsgChnlReq == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + + + DBGLOG(P2P, TRACE, ("mtk_p2p_cfg80211_remain_on_channel\n")); + + prMsgChnlReq->rMsgHdr.eMsgId = MID_MNY_P2P_CHNL_REQ; + prMsgChnlReq->u8Cookie = *cookie; + prMsgChnlReq->u4Duration = duration; + + + mtk_p2p_cfg80211func_channel_format_switch(chan, + channel_type, + &prMsgChnlReq->rChannelInfo, + &prMsgChnlReq->eChnlSco); + + mboxSendMsg(prGlueInfo->prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T)prMsgChnlReq, + MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + + i4Rslt = 0; + } while (FALSE); + + + return i4Rslt; +} +/* mtk_p2p_cfg80211_remain_on_channel */ + + +int +mtk_p2p_cfg80211_cancel_remain_on_channel ( + struct wiphy *wiphy, + struct net_device *dev, + u64 cookie + ) +{ + INT_32 i4Rslt = -EINVAL; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + P_MSG_P2P_CHNL_ABORT_T prMsgChnlAbort = (P_MSG_P2P_CHNL_ABORT_T)NULL; + + do { + if ((wiphy == NULL) || (dev == NULL)) { + break; + } + + + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + prMsgChnlAbort = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_CHNL_ABORT_T)); + + if (prMsgChnlAbort == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + + + DBGLOG(P2P, TRACE, ("mtk_p2p_cfg80211_cancel_remain_on_channel\n")); + + prMsgChnlAbort->rMsgHdr.eMsgId = MID_MNY_P2P_CHNL_ABORT; + prMsgChnlAbort->u8Cookie = cookie; + + + mboxSendMsg(prGlueInfo->prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T)prMsgChnlAbort, + MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + } while (FALSE); + + return i4Rslt; +} /* mtk_p2p_cfg80211_cancel_remain_on_channel */ + +int +mtk_p2p_cfg80211_mgmt_tx ( + struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *chan, bool offchan, + enum nl80211_channel_type channel_type, + bool channel_type_valid, unsigned int wait, + const u8 *buf, + size_t len, + u64 *cookie + ) +{ + + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T)NULL; + INT_32 i4Rslt = -EINVAL; + P_MSG_P2P_MGMT_TX_REQUEST_T prMsgTxReq = (P_MSG_P2P_MGMT_TX_REQUEST_T)NULL; + P_MSDU_INFO_T prMgmtFrame = (P_MSDU_INFO_T)NULL; + PUINT_8 pucFrameBuf = (PUINT_8)NULL; + + do { + if ((wiphy == NULL) || + (buf == NULL) || + (len == 0) || + (dev == NULL) || + (cookie == NULL)) { + break; + } + + + DBGLOG(P2P, TRACE, ("mtk_p2p_cfg80211_mgmt_tx\n")); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + prGlueP2pInfo = prGlueInfo->prP2PInfo; + + *cookie = prGlueP2pInfo->u8Cookie++; + + /* Channel & Channel Type & Wait time are ignored. */ + prMsgTxReq = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_MGMT_TX_REQUEST_T)); + + if (prMsgTxReq == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + + + prMgmtFrame = cnmMgtPktAlloc(prGlueInfo->prAdapter, (UINT_32)(len + MAC_TX_RESERVED_FIELD)); + + if ((prMsgTxReq->prMgmtMsduInfo = prMgmtFrame) == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + + + prMsgTxReq->u8Cookie = *cookie; + prMsgTxReq->rMsgHdr.eMsgId = MID_MNY_P2P_MGMT_TX; + + pucFrameBuf = (PUINT_8)((UINT_32)prMgmtFrame->prPacket + MAC_TX_RESERVED_FIELD); + + kalMemCopy(pucFrameBuf, buf, len); + + prMgmtFrame->u2FrameLength = len; + + mboxSendMsg(prGlueInfo->prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T)prMsgTxReq, + MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + } while (FALSE); + + if ((i4Rslt != 0) && (prMsgTxReq != NULL)) { + if (prMsgTxReq->prMgmtMsduInfo != NULL) { + cnmMgtPktFree(prGlueInfo->prAdapter, prMsgTxReq->prMgmtMsduInfo); + } + + + cnmMemFree(prGlueInfo->prAdapter, prMsgTxReq); + } + + + return i4Rslt; +} /* mtk_p2p_cfg80211_mgmt_tx */ + + + +int +mtk_p2p_cfg80211_change_bss ( + struct wiphy *wiphy, + struct net_device *dev, + struct bss_parameters *params + ) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + INT_32 i4Rslt = -EINVAL; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + + switch (params->use_cts_prot) { + case -1: + DBGLOG(P2P, TRACE, ("CTS protection no change\n")); + break; + case 0: + DBGLOG(P2P, TRACE, ("CTS protection disable.\n")); + break; + case 1: + DBGLOG(P2P, TRACE, ("CTS protection enable\n")); + break; + default: + DBGLOG(P2P, TRACE, ("CTS protection unknown\n")); + break; + } + + + + + switch (params->use_short_preamble) { + case -1: + DBGLOG(P2P, TRACE, ("Short prreamble no change\n")); + break; + case 0: + DBGLOG(P2P, TRACE, ("Short prreamble disable.\n")); + break; + case 1: + DBGLOG(P2P, TRACE, ("Short prreamble enable\n")); + break; + default: + DBGLOG(P2P, TRACE, ("Short prreamble unknown\n")); + break; + } + + + + +#if 0 + // not implemented yet + p2pFuncChangeBssParam(prGlueInfo->prAdapter, + prBssInfo->fgIsProtection, + prBssInfo->fgIsShortPreambleAllowed, + prBssInfo->fgUseShortSlotTime, + // Basic rates + // basic rates len + // ap isolate + // ht opmode. + ); +#else + i4Rslt = 0; +#endif + + return i4Rslt; +} /* mtk_p2p_cfg80211_change_bss */ + + + +int +mtk_p2p_cfg80211_del_station ( + struct wiphy *wiphy, + struct net_device *dev, + u8 *mac + ) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + INT_32 i4Rslt = -EINVAL; + P_MSG_P2P_CONNECTION_ABORT_T prDisconnectMsg = (P_MSG_P2P_CONNECTION_ABORT_T)NULL; + + + do { + if ((wiphy == NULL) || + (dev == NULL) || + (mac == NULL)) { + break; + } + + + DBGLOG(P2P, TRACE, ("mtk_p2p_cfg80211_del_station.\n")); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + //prDisconnectMsg = (P_MSG_P2P_CONNECTION_ABORT_T)kalMemAlloc(sizeof(MSG_P2P_CONNECTION_ABORT_T), VIR_MEM_TYPE); + prDisconnectMsg = (P_MSG_P2P_CONNECTION_ABORT_T)cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_CONNECTION_ABORT_T)); + + if (prDisconnectMsg == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + + + prDisconnectMsg->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_ABORT; + COPY_MAC_ADDR(prDisconnectMsg->aucTargetID, mac); + prDisconnectMsg->u2ReasonCode = REASON_CODE_UNSPECIFIED; + + mboxSendMsg(prGlueInfo->prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T)prDisconnectMsg, + MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + } while (FALSE); + + return i4Rslt; + +} /* mtk_p2p_cfg80211_del_station */ + + +int mtk_p2p_cfg80211_connect ( + struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_connect_params *sme + ) +{ + INT_32 i4Rslt = -EINVAL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_MSG_P2P_CONNECTION_REQUEST_T prConnReqMsg = (P_MSG_P2P_CONNECTION_REQUEST_T)NULL; + + + do { + if ((wiphy == NULL) || + (dev == NULL) || + (sme == NULL)) { + break; + } + + + DBGLOG(P2P, TRACE, ("mtk_p2p_cfg80211_connect.\n")); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + prConnReqMsg = (P_MSG_P2P_CONNECTION_REQUEST_T)cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, (sizeof(MSG_P2P_CONNECTION_REQUEST_T) + sme->ie_len)); + + if (prConnReqMsg == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + + + prConnReqMsg->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_REQ; + + COPY_SSID(prConnReqMsg->rSsid.aucSsid, + prConnReqMsg->rSsid.ucSsidLen, + sme->ssid, + sme->ssid_len); + + COPY_MAC_ADDR(prConnReqMsg->aucBssid, sme->bssid); + + kalMemCopy(prConnReqMsg->aucIEBuf, sme->ie, sme->ie_len); + prConnReqMsg->u4IELen = sme->ie_len; + + mtk_p2p_cfg80211func_channel_format_switch(sme->channel, + NL80211_CHAN_NO_HT, + &prConnReqMsg->rChannelInfo, + &prConnReqMsg->eChnlSco); + + mboxSendMsg(prGlueInfo->prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T)prConnReqMsg, + MSG_SEND_METHOD_BUF); + + + i4Rslt = 0; + } while (FALSE); + + return i4Rslt; +} + +int mtk_p2p_cfg80211_disconnect( + struct wiphy *wiphy, + struct net_device *dev, + u16 reason_code + ) +{ + INT_32 i4Rslt = -EINVAL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_MSG_P2P_CONNECTION_ABORT_T prDisconnMsg = (P_MSG_P2P_CONNECTION_ABORT_T)NULL; + UINT_8 aucBCAddr[] = BC_MAC_ADDR; + + do { + if ((wiphy == NULL) || + (dev == NULL)) { + break; + } + + + DBGLOG(P2P, TRACE, ("mtk_p2p_cfg80211_disconnect.\n")); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + +// prDisconnMsg = (P_MSG_P2P_CONNECTION_ABORT_T)kalMemAlloc(sizeof(P_MSG_P2P_CONNECTION_ABORT_T), VIR_MEM_TYPE); + prDisconnMsg = (P_MSG_P2P_CONNECTION_ABORT_T)cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_CONNECTION_ABORT_T)); + + if (prDisconnMsg == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + + + prDisconnMsg->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_ABORT; + prDisconnMsg->u2ReasonCode = reason_code; + COPY_MAC_ADDR(prDisconnMsg->aucTargetID, aucBCAddr); + + mboxSendMsg(prGlueInfo->prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T)prDisconnMsg, + MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + } while (FALSE); + + return i4Rslt; +} + + +int +mtk_p2p_cfg80211_change_iface ( + IN struct wiphy *wiphy, + IN struct net_device *ndev, + IN enum nl80211_iftype type, + IN u32 *flags, + IN struct vif_params *params + ) +{ + + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + INT_32 i4Rslt = -EINVAL; + P_MSG_P2P_SWITCH_OP_MODE_T prSwitchModeMsg = (P_MSG_P2P_SWITCH_OP_MODE_T)NULL; + + do { + if ((wiphy == NULL) || + (ndev == NULL)) { + break; + } + + + DBGLOG(P2P, TRACE, ("mtk_p2p_cfg80211_change_iface.\n")); + + if (ndev->ieee80211_ptr) { + ndev->ieee80211_ptr->iftype = type; + } + + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + + // Switch OP MOde. + prSwitchModeMsg = (P_MSG_P2P_SWITCH_OP_MODE_T)cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_SWITCH_OP_MODE_T)); + + if (prSwitchModeMsg == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + + + prSwitchModeMsg->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; + + switch (type) { + case NL80211_IFTYPE_P2P_CLIENT: + DBGLOG(P2P, TRACE, ("NL80211_IFTYPE_P2P_CLIENT.\n")); + case NL80211_IFTYPE_STATION: + if (type == NL80211_IFTYPE_STATION) { + DBGLOG(P2P, TRACE, ("NL80211_IFTYPE_STATION.\n")); + } + prSwitchModeMsg->eOpMode = OP_MODE_INFRASTRUCTURE; + break; + case NL80211_IFTYPE_AP: + DBGLOG(P2P, TRACE, ("NL80211_IFTYPE_AP.\n")); + case NL80211_IFTYPE_P2P_GO: + if (type == NL80211_IFTYPE_P2P_GO) { + DBGLOG(P2P, TRACE, ("NL80211_IFTYPE_P2P_GO not AP.\n")); + } + + prSwitchModeMsg->eOpMode = OP_MODE_ACCESS_POINT; + break; + default: + DBGLOG(P2P, TRACE, ("Other type :%d .\n", type)); + prSwitchModeMsg->eOpMode = OP_MODE_P2P_DEVICE; + break; + } + + + + mboxSendMsg(prGlueInfo->prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T)prSwitchModeMsg, + MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + + } while (FALSE); + + return i4Rslt; + +} /* mtk_p2p_cfg80211_change_iface */ + + +int +mtk_p2p_cfg80211_set_channel ( + IN struct wiphy *wiphy, + IN struct net_device *dev, + IN struct ieee80211_channel *chan, + IN enum nl80211_channel_type channel_type) +{ + INT_32 i4Rslt = -EINVAL; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + RF_CHANNEL_INFO_T rRfChnlInfo; + + do { + if ((wiphy == NULL) || + (dev == NULL) || + (chan == NULL)) { + break; + } + + + DBGLOG(P2P, TRACE, ("mtk_p2p_cfg80211_set_channel.\n")); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + mtk_p2p_cfg80211func_channel_format_switch(chan, + channel_type, + &rRfChnlInfo, + NULL); + + p2pFuncSetChannel(prGlueInfo->prAdapter, &rRfChnlInfo); + + i4Rslt = 0; + } +while (FALSE); + + return i4Rslt; + +} + +int +mtk_p2p_cfg80211_set_bitrate_mask ( + IN struct wiphy *wiphy, + IN struct net_device *dev, + IN const u8 *peer, + IN const struct cfg80211_bitrate_mask *mask + ) +{ + INT_32 i4Rslt = -EINVAL; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + + do { + if ((wiphy == NULL) || + (dev == NULL) || + (mask == NULL)) { + break; + } + + + DBGLOG(P2P, TRACE, ("mtk_p2p_cfg80211_set_bitrate_mask\n")); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + // TODO: Set bitrate mask of the peer? + + i4Rslt = 0; + } +while (FALSE); + + return i4Rslt; +} /* mtk_p2p_cfg80211_set_bitrate_mask */ + + +void +mtk_p2p_cfg80211_mgmt_frame_register ( + IN struct wiphy *wiphy, + IN struct net_device *dev, + IN u16 frame_type, + IN bool reg + ) +{ + P_MSG_P2P_MGMT_FRAME_REGISTER_T prMgmtFrameRegister = (P_MSG_P2P_MGMT_FRAME_REGISTER_T)NULL; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + + do { + if ((wiphy == NULL) || + (dev == NULL)) { + break; + } + + + DBGLOG(P2P, TRACE, ("mtk_p2p_cfg80211_mgmt_frame_register\n")); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + prMgmtFrameRegister = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_MGMT_FRAME_REGISTER_T)); + + if (prMgmtFrameRegister == NULL) { + ASSERT(FALSE); + break; + } + + + prMgmtFrameRegister->rMsgHdr.eMsgId = MID_MNY_P2P_MGMT_FRAME_REGISTER; + + prMgmtFrameRegister->u2FrameType = frame_type; + prMgmtFrameRegister->fgIsRegister = reg; + + mboxSendMsg(prGlueInfo->prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T)prMgmtFrameRegister, + MSG_SEND_METHOD_BUF); + + } while (FALSE); + + + return; +} /* mtk_p2p_cfg80211_mgmt_frame_register */ + + +BOOLEAN +mtk_p2p_cfg80211func_channel_format_switch ( + IN struct ieee80211_channel *channel, + IN enum nl80211_channel_type channel_type, + IN P_RF_CHANNEL_INFO_T prRfChnlInfo, + IN P_ENUM_CHNL_EXT_T prChnlSco + ) +{ + BOOLEAN fgIsValid = FALSE; + + do { + if (channel == NULL) { + break; + } + + + if (prRfChnlInfo) { + prRfChnlInfo->ucChannelNum = nicFreq2ChannelNum(channel->center_freq * 1000); + + switch (channel->band) { + case IEEE80211_BAND_2GHZ: + prRfChnlInfo->eBand = BAND_2G4; + break; + case IEEE80211_BAND_5GHZ: + prRfChnlInfo->eBand = BAND_5G; + break; + default: + prRfChnlInfo->eBand = BAND_2G4; + break; + } + + } + + + if (prChnlSco) { + + switch (channel_type) { + case NL80211_CHAN_NO_HT: + *prChnlSco = CHNL_EXT_SCN; + break; + case NL80211_CHAN_HT20: + *prChnlSco = CHNL_EXT_SCN; + break; + case NL80211_CHAN_HT40MINUS: + *prChnlSco = CHNL_EXT_SCA; + break; + case NL80211_CHAN_HT40PLUS: + *prChnlSco = CHNL_EXT_SCB; + break; + default: + ASSERT(FALSE); + *prChnlSco = CHNL_EXT_SCN; + break; + } + + } + + fgIsValid = TRUE; + } +while (FALSE); + + return fgIsValid; +} +/* mtk_p2p_cfg80211func_channel_format_switch */ + +#if CONFIG_NL80211_TESTMODE +int mtk_p2p_cfg80211_testmode_cmd( + IN struct wiphy *wiphy, + IN void *data, + IN int len + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + NL80211_DRIVER_TEST_PARAMS rParams; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T)NULL; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T)NULL; + UINT_32 index_mode; + UINT_32 index; + INT_32 value; + int status = 0; + UINT_32 u4Leng; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + kalMemZero(&rParams, sizeof(NL80211_DRIVER_TEST_PARAMS)); + + prP2pSpecificBssInfo = prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo; + prP2pConnSettings = prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings; + + DBGLOG(P2P, TRACE, ("mtk_p2p_cfg80211_testmode_cmd\n")); + + if(data && len) + memcpy(&rParams, data, len); + + DBGLOG(P2P, TRACE, ("NL80211_ATTR_TESTDATA,idx_mode=%d idx=%d value=%lu\n", + (INT_16)rParams.idx_mode, (INT_16)rParams.idx, rParams.value)); + + index_mode = rParams.idx_mode; + index = rParams.idx; + value = rParams.value; + + switch (index) { + case 0: /* Listen CH */ + break; + case 1: /* P2p mode */ + break; + case 4: /* Noa duration */ + prP2pSpecificBssInfo->rNoaParam.u4NoaDurationMs = value; + // only to apply setting when setting NOA count + //status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); + break; + case 5: /* Noa interval */ + prP2pSpecificBssInfo->rNoaParam.u4NoaIntervalMs = value; + // only to apply setting when setting NOA count + //status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); + break; + case 6: /* Noa count */ + prP2pSpecificBssInfo->rNoaParam.u4NoaCount = value; + //status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); + break; + case 100: /* Oper CH */ + // 20110920 - frog: User configurations are placed in ConnSettings. + // prP2pConnSettings->ucOperatingChnl = value; + break; + case 101: /* Local config Method, for P2P SDK */ + prP2pConnSettings->u2LocalConfigMethod = value; + break; + case 102: /* Sigma P2p reset */ + //kalMemZero(prP2pConnSettings->aucTargetDevAddr, MAC_ADDR_LEN); + //prP2pConnSettings->eConnectionPolicy = ENUM_P2P_CONNECTION_POLICY_AUTO; + break; + case 103: /* WPS MODE */ + kalP2PSetWscMode(prGlueInfo, value); + break; + case 104: /* P2p send persence, duration */ + break; + case 105: /* P2p send persence, interval */ + break; + case 106: /* P2P set sleep */ + value = 1; + kalIoctl(prGlueInfo, + wlanoidSetP2pPowerSaveProfile, + &value, + sizeof(value), + FALSE, + FALSE, + TRUE, + TRUE, + &u4Leng); + break; + case 107: /* P2P set opps, CTWindowl */ + prP2pSpecificBssInfo->rOppPsParam.u4CTwindowMs = value; + //status = mtk_p2p_wext_set_oppps_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rOppPsParam); + break; + case 108: /* p2p_set_power_save */ + kalIoctl(prGlueInfo, + wlanoidSetP2pPowerSaveProfile, + &value, + sizeof(value), + FALSE, + FALSE, + TRUE, + TRUE, + &u4Leng); + + break; + default: + break; + } + + return status; + +} +#endif + + +#endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) + +#endif // CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_WIFI_DIRECT_CFG_80211 diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/gl_p2p_init.c b/drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/gl_p2p_init.c new file mode 100755 index 000000000000..6a6152ce6172 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/gl_p2p_init.c @@ -0,0 +1,709 @@ +/* +** $Id: @(#) gl_p2p_init.c@@ +*/ + +/*! \file gl_p2p_init.c + \brief init and exit routines of Linux driver interface for Wi-Fi Direct + + This file contains the main routines of Linux driver for MediaTek Inc. 802.11 + Wireless LAN Adapters. +*/ + +/******************************************************************************* +* Copyright (c) 2011 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "p2p_precomp.h" + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define P2P_MODE_INF_NAME "p2p%d"; +#define AP_MODE_INF_NAME "ap%d"; +//#define MAX_INF_NAME_LEN 15 +//#define MIN_INF_NAME_LEN 1 + +#define RUNNING_P2P_MODE 0 +#define RUNNING_AP_MODE 1 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +MODULE_AUTHOR(NIC_AUTHOR); +MODULE_DESCRIPTION(NIC_DESC); +MODULE_SUPPORTED_DEVICE(NIC_NAME); + +#if MTK_WCN_HIF_SDIO + MODULE_LICENSE("MTK Propietary"); +#else + MODULE_LICENSE("GPL"); +#endif + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/* Get interface name and running mode from module insertion parameter +* Usage: insmod p2p.ko mode=1 +* default: interface name is p2p%d +* running mode is P2P +*/ +static PUCHAR ifname = P2P_MODE_INF_NAME; +static UINT_16 mode = RUNNING_P2P_MODE; + +//module_param(ifname, charp, 0000); +//MODULE_PARM_DESC(ifname, "P2P Interface Name"); + +module_param(mode, ushort, 0000); +MODULE_PARM_DESC(mode, "Running Mode"); + + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +extern int glRegisterEarlySuspend( + struct early_suspend *prDesc, + early_suspend_callback wlanSuspend, + late_resume_callback wlanResume); + +extern int glUnregisterEarlySuspend(struct early_suspend *prDesc); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief check interface name parameter is valid or not +* if invalid, set ifname to P2P_MODE_INF_NAME +* +* +* \retval +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pCheckInterfaceName( + VOID + ) +{ + + if(mode) { + mode = RUNNING_AP_MODE; + ifname = AP_MODE_INF_NAME; + } +#if 0 + UINT_32 ifLen = 0; + + if(ifname) { + ifLen = strlen(ifname); + + if(ifLen > MAX_INF_NAME_LEN) { + ifname[MAX_INF_NAME_LEN] = '\0'; + } + else if( ifLen < MIN_INF_NAME_LEN ) { + ifname = P2P_MODE_INF_NAME; + } + } else { + ifname = P2P_MODE_INF_NAME; + } +#endif +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* register p2p pointer to wlan module +* +* +* \retval 1 Success +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +p2pRegisterToWlan( + P_GLUE_INFO_T prGlueInfo + ) +{ + P_P2P_FUNCTION_LINKER prFuncLkr = (P_P2P_FUNCTION_LINKER)NULL; + extern APPEND_VAR_IE_ENTRY_T txProbRspIETableWIP2P[]; + extern P_APPEND_VAR_IE_ENTRY_T prTxProbRspIETableWIP2P; + extern MSG_HNDL_ENTRY_T arMsgMapTable[]; + + printk(KERN_INFO DRV_NAME "P2P register to wlan\n"); + + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prAdapter); + + if(prGlueInfo) { + + prFuncLkr = &(prGlueInfo->prAdapter->rP2pFuncLkr); + + /*set p2p function pointer to its function*/ + prFuncLkr->prKalP2pGetCipher = kalP2PGetCipher; // TODO: Leave to Maggie. + prFuncLkr->prKalP2pGetTkipCipher = kalP2PGetTkipCipher; // TODO: Leave to Maggie. + prFuncLkr->prKalP2pGetCcmpCipher = kalP2PGetCcmpCipher; // TODO: Leave to Maggie. + prFuncLkr->prKalP2pGetWscMode = kalP2PGetWscMode; // TODO: Leave to Maggie. + prFuncLkr->prKalP2pGetDevHdlr = kalP2PGetDevHdlr; + prFuncLkr->prKalP2pUpdateAssocInfo = kalP2PUpdateAssocInfo; + prFuncLkr->prP2pValidateAuth = p2pFuncValidateAuth; + prFuncLkr->prP2pValidateAssocReq = p2pFuncValidateAssocReq; + + prFuncLkr->prP2pRunEventAAATxFail = p2pRunEventAAATxFail; + prFuncLkr->prP2pRunEventAAAComplete = p2pRunEventAAAComplete; + prFuncLkr->prP2pRunEventAAASuccess = p2pRunEventAAASuccess; + prFuncLkr->prP2pParseCheckForP2pInfoElem = p2pFuncParseCheckForP2PInfoElem; + prFuncLkr->prP2pProcessEvent_UpdateNOAParam = p2pProcessEvent_UpdateNOAParam; // TODO: Leave to George. + prFuncLkr->prScanP2pProcessBeaconAndProbeResp = scanP2pProcessBeaconAndProbeResp; + prFuncLkr->prP2pRxPublicActionFrame = p2pFuncValidateRxActionFrame; + prFuncLkr->prP2pRxActionFrame = p2pFuncValidateRxActionFrame; + prFuncLkr->prRlmRspGenerateObssScanIE = rlmRspGenerateObssScanIE; // TODO: Leave to CM. + prFuncLkr->prRlmProcessPublicAction = rlmProcessPublicAction; // TODO: Leave to CM. + prFuncLkr->prRlmProcessHtAction = rlmProcessHtAction; // TODO: Leave to CM. + prFuncLkr->prRlmHandleObssStatusEventPkt = rlmHandleObssStatusEventPkt; // TODO: Leave to CM. + + prFuncLkr->prP2pCalculateP2p_IELenForBeacon = p2pFuncCalculateP2p_IELenForBeacon; + prFuncLkr->prP2pGenerateP2p_IEForBeacon = p2pFuncGenerateP2p_IEForBeacon; + + prFuncLkr->prP2pCalculateWSC_IELenForBeacon = p2pFuncCalculateWSC_IELenForBeacon; + prFuncLkr->prP2pGenerateWSC_IEForBeacon = p2pFuncGenerateWSC_IEForBeacon; + + prFuncLkr->prP2pCalculateP2p_IELenForAssocRsp = p2pFuncCalculateP2p_IELenForAssocRsp; + prFuncLkr->prP2pGenerateP2p_IEForAssocRsp = p2pFuncGenerateP2p_IEForAssocRsp; + + prFuncLkr->prP2pFuncValidateProbeReq = p2pFuncValidateProbeReq; + prFuncLkr->prRlmBssInitForAP = rlmBssInitForAP; // TODO: Leave to CM. + prFuncLkr->prP2pGetTxProbRspIETAbleSize = p2pGetTxProbRspIeTableSize; // TODO: It should not be called. + prFuncLkr->prRlmUpdateParamsForAp = rlmUpdateParamsForAP; // TODO: Leave to CM. + prFuncLkr->prP2pBuildReassocReqFrameCommIEs = p2pBuildReAssocReqFrameCommonIEs; + prFuncLkr->prP2pFuncDisconnect = p2pFuncDisconnect; + prFuncLkr->prP2pFsmRunEventRxDeauthentication = p2pFsmRunEventRxDeauthentication; + prFuncLkr->prP2pFsmRunEventRxDisassociation = p2pFsmRunEventRxDisassociation; + prFuncLkr->prP2pFuncIsApMode = p2pFuncIsAPMode; + prFuncLkr->prP2pFsmRunEventBeaconTimeout = p2pFsmRunEventBeaconTimeout; + prFuncLkr->prP2pSetMulticastListWorkQueue = mtk_p2p_wext_set_Multicastlist; + prFuncLkr->prP2pFuncStoreAssocRspIeBuffer = p2pFuncStoreAssocRspIEBuffer; + prFuncLkr->prP2pCalculate_IELenForAssocReq = p2pCalculate_IEForAssocReq; + prFuncLkr->prP2pGenerate_IEForAssocReq = p2pGenerate_IEForAssocReq; + /*set this pointer to the FIRST entry of rsp IE table*/ + prTxProbRspIETableWIP2P = &(txProbRspIETableWIP2P[0]); + + /*replace arMsgMapTable mboxDummy to real p2p handler*/ + arMsgMapTable[MID_P2P_SAA_FSM_START].pfMsgHndl = saaFsmRunEventStart; + arMsgMapTable[MID_P2P_SAA_FSM_ABORT].pfMsgHndl = saaFsmRunEventAbort; + arMsgMapTable[MID_CNM_P2P_CH_GRANT].pfMsgHndl = p2pFsmRunEventChGrant; + arMsgMapTable[MID_SCN_P2P_SCAN_DONE].pfMsgHndl = p2pFsmRunEventScanDone; + arMsgMapTable[MID_SAA_P2P_JOIN_COMPLETE].pfMsgHndl = p2pFsmRunEventJoinComplete; + arMsgMapTable[MID_MNY_P2P_FUN_SWITCH].pfMsgHndl = p2pFsmRunEventSwitchOPMode; + arMsgMapTable[MID_MNY_P2P_DEVICE_DISCOVERY].pfMsgHndl = p2pFsmRunEventScanRequest; + arMsgMapTable[MID_MNY_P2P_CONNECTION_REQ].pfMsgHndl = p2pFsmRunEventConnectionRequest; + arMsgMapTable[MID_MNY_P2P_CONNECTION_ABORT].pfMsgHndl = p2pFsmRunEventConnectionAbort; + arMsgMapTable[MID_MNY_P2P_MGMT_TX].pfMsgHndl = p2pFsmRunEventMgmtFrameTx; + arMsgMapTable[MID_MNY_P2P_BEACON_UPDATE].pfMsgHndl = p2pFsmRunEventBeaconUpdate; + arMsgMapTable[MID_MNY_P2P_BEACON_DEL].pfMsgHndl = p2pFsmRunEventBeaconAbort; + arMsgMapTable[MID_MNY_P2P_CHNL_REQ].pfMsgHndl = p2pFsmRunEventChannelRequest; + arMsgMapTable[MID_MNY_P2P_CHNL_ABORT].pfMsgHndl = p2pFsmRunEventChannelAbort; + arMsgMapTable[MID_MNY_P2P_GROUP_DISSOLVE].pfMsgHndl = p2pFsmRunEventDissolve; + arMsgMapTable[MID_MNY_P2P_MGMT_FRAME_REGISTER].pfMsgHndl = p2pFsmRunEventMgmtFrameRegister; + + return TRUE; + } + else { + ASSERT(FALSE); + return FALSE; + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* unregiester p2p pointer to wlan module +* +* +* \retval 1 Success +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +p2pUnregisterToWlan( + P_GLUE_INFO_T prGlueInfo + ) +{ + + P_P2P_FUNCTION_LINKER prFuncLkr = (P_P2P_FUNCTION_LINKER)NULL; + extern P_APPEND_VAR_IE_ENTRY_T prTxProbRspIETableWIP2P; + extern MSG_HNDL_ENTRY_T arMsgMapTable[]; + + printk(KERN_INFO DRV_NAME "P2P UNregister to wlan\n"); + + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prAdapter); + + if(prGlueInfo) { + + prFuncLkr = &(prGlueInfo->prAdapter->rP2pFuncLkr); + + /*reset all p2p function linker pointer to NULL*/ + kalMemZero(prFuncLkr, sizeof(P2P_FUNCTION_LINKER)); + + prTxProbRspIETableWIP2P = NULL; + + /*set p2p MsgMapTable entry to mbox dummy*/ + arMsgMapTable[MID_P2P_SAA_FSM_START].pfMsgHndl = mboxDummy; + arMsgMapTable[MID_P2P_SAA_FSM_ABORT].pfMsgHndl = mboxDummy; + arMsgMapTable[MID_CNM_P2P_CH_GRANT].pfMsgHndl = mboxDummy; + arMsgMapTable[MID_SCN_P2P_SCAN_DONE].pfMsgHndl = mboxDummy; + arMsgMapTable[MID_SAA_P2P_JOIN_COMPLETE].pfMsgHndl = mboxDummy; + arMsgMapTable[MID_MNY_P2P_FUN_SWITCH].pfMsgHndl = mboxDummy; + arMsgMapTable[MID_MNY_P2P_DEVICE_DISCOVERY].pfMsgHndl = mboxDummy; + arMsgMapTable[MID_MNY_P2P_CONNECTION_REQ].pfMsgHndl = mboxDummy; + arMsgMapTable[MID_MNY_P2P_CONNECTION_ABORT].pfMsgHndl = mboxDummy; + arMsgMapTable[MID_MNY_P2P_MGMT_TX].pfMsgHndl = mboxDummy; + arMsgMapTable[MID_MNY_P2P_BEACON_UPDATE].pfMsgHndl = mboxDummy; + arMsgMapTable[MID_MNY_P2P_BEACON_DEL].pfMsgHndl = mboxDummy; + arMsgMapTable[MID_MNY_P2P_CHNL_REQ].pfMsgHndl = mboxDummy; + arMsgMapTable[MID_MNY_P2P_CHNL_ABORT].pfMsgHndl = mboxDummy; + arMsgMapTable[MID_MNY_P2P_GROUP_DISSOLVE].pfMsgHndl = mboxDummy; + arMsgMapTable[MID_MNY_P2P_MGMT_FRAME_REGISTER].pfMsgHndl = mboxDummy; + + return TRUE; + } + else { + ASSERT(FALSE); + return FALSE; + } + +} + + +UINT_8 g_aucBufIpAddr[32] = {0}; + +static void wlanP2PEarlySuspend(void) +{ + struct net_device *prDev = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + UINT_8 ip[4] = { 0 }; + UINT_32 u4NumIPv4 = 0; +#ifdef CONFIG_IPV6 + UINT_8 ip6[16] = { 0 }; // FIX ME: avoid to allocate large memory in stack + UINT_32 u4NumIPv6 = 0; +#endif + UINT_32 i; + P_PARAM_NETWORK_ADDRESS_IP prParamIpAddr; + + printk(KERN_INFO "*********p2pEarlySuspend************\n"); + + if(!wlanExportGlueInfo(&prGlueInfo)) { + printk(KERN_INFO "*********p2pEarlySuspend ignored************\n"); + return; + } + + ASSERT(prGlueInfo); + // <1> Sanity check and acquire the net_device + prDev = prGlueInfo->prP2PInfo->prDevHandler; + ASSERT(prDev); + + // <3> get the IPv4 address + if(!prDev || !(prDev->ip_ptr)||\ + !((struct in_device *)(prDev->ip_ptr))->ifa_list||\ + !(&(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local))){ + printk(KERN_INFO "ip is not avaliable.\n"); + return; + } + + // <4> copy the IPv4 address + kalMemCopy(ip, &(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local), sizeof(ip)); + printk(KERN_INFO"ip is %d.%d.%d.%d\n", + ip[0],ip[1],ip[2],ip[3]); + + // todo: traverse between list to find whole sets of IPv4 addresses + if (!((ip[0] == 0) && + (ip[1] == 0) && + (ip[2] == 0) && + (ip[3] == 0))) { + u4NumIPv4++; + } + +#ifdef CONFIG_IPV6 + // <5> get the IPv6 address + if(!prDev || !(prDev->ip6_ptr)||\ + !((struct in_device *)(prDev->ip6_ptr))->ifa_list||\ + !(&(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local))){ + printk(KERN_INFO "ipv6 is not avaliable.\n"); + return; + } + // <6> copy the IPv6 address + kalMemCopy(ip6, &(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local), sizeof(ip6)); + printk(KERN_INFO"ipv6 is %d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d\n", + ip6[0],ip6[1],ip6[2],ip6[3], + ip6[4],ip6[5],ip6[6],ip6[7], + ip6[8],ip6[9],ip6[10],ip6[11], + ip6[12],ip6[13],ip6[14],ip6[15] + ); + // todo: traverse between list to find whole sets of IPv6 addresses + + if (!((ip6[0] == 0) && + (ip6[1] == 0) && + (ip6[2] == 0) && + (ip6[3] == 0) && + (ip6[4] == 0) && + (ip6[5] == 0))) { + } + +#endif + // <7> set up the ARP filter + { + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + UINT_32 u4SetInfoLen = 0; +// UINT_8 aucBuf[32] = {0}; + UINT_32 u4Len = OFFSET_OF(PARAM_NETWORK_ADDRESS_LIST, arAddress); + P_PARAM_NETWORK_ADDRESS_LIST prParamNetAddrList = (P_PARAM_NETWORK_ADDRESS_LIST)g_aucBufIpAddr;//aucBuf; + P_PARAM_NETWORK_ADDRESS prParamNetAddr = prParamNetAddrList->arAddress; + + kalMemZero(g_aucBufIpAddr, sizeof(g_aucBufIpAddr)); + + prParamNetAddrList->u4AddressCount = u4NumIPv4 + u4NumIPv6; + prParamNetAddrList->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; + for (i = 0; i < u4NumIPv4; i++) { + prParamNetAddr->u2AddressLength = sizeof(PARAM_NETWORK_ADDRESS_IP);//4;; + prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP;; +#if 0 + kalMemCopy(prParamNetAddr->aucAddress, ip, sizeof(ip)); + prParamNetAddr = (P_PARAM_NETWORK_ADDRESS)((UINT_32)prParamNetAddr + sizeof(ip)); + u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(ip); +#else + prParamIpAddr = (P_PARAM_NETWORK_ADDRESS_IP)prParamNetAddr->aucAddress; + kalMemCopy(&prParamIpAddr->in_addr, ip, sizeof(ip)); + +// prParamNetAddr = (P_PARAM_NETWORK_ADDRESS)((UINT_32)prParamNetAddr + sizeof(PARAM_NETWORK_ADDRESS)); // TODO: frog. The pointer is not right. + + prParamNetAddr = (P_PARAM_NETWORK_ADDRESS) ((UINT_32) prParamNetAddr + + (UINT_32) (prParamNetAddr->u2AddressLength + OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress))); + + u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(PARAM_NETWORK_ADDRESS_IP); +#endif + } +#ifdef CONFIG_IPV6 + for (i = 0; i < u4NumIPv6; i++) { + prParamNetAddr->u2AddressLength = 6;; + prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP;; + kalMemCopy(prParamNetAddr->aucAddress, ip6, sizeof(ip6)); +// prParamNetAddr = (P_PARAM_NETWORK_ADDRESS)((UINT_32)prParamNetAddr + sizeof(ip6)); + + prParamNetAddr = (P_PARAM_NETWORK_ADDRESS) ((UINT_32) prParamNetAddr + + (UINT_32) (prParamNetAddr->u2AddressLength + OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress))); + + u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(ip6); + } +#endif + ASSERT(u4Len <= sizeof(g_aucBufIpAddr/*aucBuf*/)); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetP2pSetNetworkAddress, + (PVOID)prParamNetAddrList, + u4Len, + FALSE, + FALSE, + TRUE, + TRUE, + &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + printk(KERN_INFO DRV_NAME"set HW pattern filter fail 0x%lx\n", rStatus); + } + } +} + + +static void wlanP2PLateResume(void) +{ + struct net_device *prDev = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + UINT_8 ip[4] = { 0 }; +#ifdef CONFIG_IPV6 + UINT_8 ip6[16] = { 0 }; // FIX ME: avoid to allocate large memory in stack +#endif + + printk(KERN_INFO "*********wlanP2PLateResume************\n"); + if(!wlanExportGlueInfo(&prGlueInfo)) { + printk(KERN_INFO "*********p2pLateResume ignored************\n"); + return; + } + + ASSERT(prGlueInfo); + // <1> Sanity check and acquire the net_device + prDev = prGlueInfo->prP2PInfo->prDevHandler; + ASSERT(prDev); + + // <3> get the IPv4 address + if(!prDev || !(prDev->ip_ptr)||\ + !((struct in_device *)(prDev->ip_ptr))->ifa_list||\ + !(&(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local))){ + printk(KERN_INFO "ip is not avaliable.\n"); + return; + } + + // <4> copy the IPv4 address + kalMemCopy(ip, &(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local), sizeof(ip)); + printk(KERN_INFO"ip is %d.%d.%d.%d\n", + ip[0],ip[1],ip[2],ip[3]); + +#ifdef CONFIG_IPV6 + // <5> get the IPv6 address + if(!prDev || !(prDev->ip6_ptr)||\ + !((struct in_device *)(prDev->ip6_ptr))->ifa_list||\ + !(&(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local))){ + printk(KERN_INFO "ipv6 is not avaliable.\n"); + return; + } + // <6> copy the IPv6 address + kalMemCopy(ip6, &(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local), sizeof(ip6)); + printk(KERN_INFO"ipv6 is %d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d\n", + ip6[0],ip6[1],ip6[2],ip6[3], + ip6[4],ip6[5],ip6[6],ip6[7], + ip6[8],ip6[9],ip6[10],ip6[11], + ip6[12],ip6[13],ip6[14],ip6[15] + ); +#endif + // <7> clear the ARP filter + { + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + UINT_32 u4SetInfoLen = 0; +// UINT_8 aucBuf[32] = {0}; + UINT_32 u4Len = sizeof(PARAM_NETWORK_ADDRESS_LIST); + P_PARAM_NETWORK_ADDRESS_LIST prParamNetAddrList = (P_PARAM_NETWORK_ADDRESS_LIST)g_aucBufIpAddr;//aucBuf; + + kalMemZero(g_aucBufIpAddr, sizeof(g_aucBufIpAddr)); + + prParamNetAddrList->u4AddressCount = 0; + prParamNetAddrList->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; + + ASSERT(u4Len <= sizeof(g_aucBufIpAddr/*aucBuf*/)); + rStatus = kalIoctl(prGlueInfo, + wlanoidSetP2pSetNetworkAddress, + (PVOID)prParamNetAddrList, + u4Len, + FALSE, + FALSE, + TRUE, + TRUE, + &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + printk(KERN_INFO DRV_NAME"set HW pattern filter fail 0x%lx\n", rStatus); + } + } +} + +static struct early_suspend mt6620_p2p_early_suspend_desc = { + .level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN, +}; + +static void p2p_early_suspend(struct early_suspend *h) +{ + printk(KERN_INFO "*********wlanP2P_early_suspend************\n"); + wlanP2PEarlySuspend(); +} + +static void p2p_late_resume(struct early_suspend *h) +{ + printk(KERN_INFO "*********wlanP2P_late_resume************\n"); + wlanP2PLateResume(); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* run p2p init procedure, include register pointer to wlan +* glue register p2p +* set p2p registered flag +* \retval 1 Success +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +p2pLaunch( + P_GLUE_INFO_T prGlueInfo + ) +{ + if(prGlueInfo->prAdapter->fgIsP2PRegistered == TRUE) { + return FALSE; + } + else if(p2pRegisterToWlan(prGlueInfo) + && glRegisterP2P(prGlueInfo, ifname, (BOOLEAN)mode)) { + prGlueInfo->prAdapter->fgIsP2PRegistered = TRUE; + /*p2p is launched successfully*/ + + /* Here, we register the early suspend and resume callback */ + glRegisterEarlySuspend(&mt6620_p2p_early_suspend_desc, p2p_early_suspend, p2p_late_resume); + return TRUE; + } + return FALSE; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* run p2p exit procedure, include unregister pointer to wlan +* glue unregister p2p +* set p2p registered flag + +* \retval 1 Success +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +p2pRemove( + P_GLUE_INFO_T prGlueInfo + ) +{ + if(prGlueInfo->prAdapter->fgIsP2PRegistered == FALSE) { + return FALSE; + } + else { + + glUnregisterEarlySuspend(&mt6620_p2p_early_suspend_desc); + + /*Check p2p fsm is stop or not. If not then stop now*/ + if(IS_P2P_ACTIVE(prGlueInfo->prAdapter)) { + p2pStopImmediate(prGlueInfo); + } + prGlueInfo->prAdapter->fgIsP2PRegistered = FALSE; + glUnregisterP2P(prGlueInfo); + p2pUnregisterToWlan(prGlueInfo); + /*p2p is removed successfully*/ + return TRUE; + } + return FALSE; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Driver entry point when the driver is configured as a Linux Module, and +* is called once at module load time, by the user-level modutils +* application: insmod or modprobe. +* +* \retval 0 Success +*/ +/*----------------------------------------------------------------------------*/ +//1 Module Entry Point +static int __init initP2P(void) +{ + P_GLUE_INFO_T prGlueInfo; + + /*check interface name validation*/ + p2pCheckInterfaceName(); + + printk( KERN_INFO DRV_NAME "InitP2P, Ifname: %s, Mode: %s\n", ifname, mode ? "AP":"P2P"); + + /*register p2p init & exit function to wlan sub module handler*/ + wlanSubModRegisterInitExit(p2pLaunch, p2pRemove, P2P_MODULE); + + /*if wlan is not start yet, do nothing + * p2pLaunch will be called by txthread while wlan start + */ + /*if wlan is not started yet, return FALSE*/ + if(wlanExportGlueInfo(&prGlueInfo)) { + wlanSubModInit(prGlueInfo); + return ( prGlueInfo->prAdapter->fgIsP2PRegistered? 0: -EIO); + } + + return 0; +} /* end of initP2P() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Driver exit point when the driver as a Linux Module is removed. Called +* at module unload time, by the user level modutils application: rmmod. +* This is our last chance to clean up after ourselves. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +//1 Module Leave Point +static VOID __exit exitP2P(void) +{ + P_GLUE_INFO_T prGlueInfo; + + printk( KERN_INFO DRV_NAME "ExitP2P\n"); + + /*if wlan is not started yet, return FALSE*/ + if(wlanExportGlueInfo(&prGlueInfo)) { + wlanSubModExit(prGlueInfo); + } + /*UNregister p2p init & exit function to wlan sub module handler*/ + wlanSubModRegisterInitExit(NULL, NULL, P2P_MODULE); +} /* end of exitP2P() */ + +module_init(initP2P); +module_exit(exitP2P); + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/gl_p2p_kal.c b/drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/gl_p2p_kal.c new file mode 100755 index 000000000000..0c656128fff6 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/gl_p2p_kal.c @@ -0,0 +1,1509 @@ +/* +** $Id: @(#) gl_p2p_cfg80211.c@@ +*/ + +/*! \file gl_p2p_kal.c + \brief + +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "net/cfg80211.h" +#include "p2p_precomp.h" + +extern BOOLEAN +wextSrchDesiredWPAIE ( + IN PUINT_8 pucIEStart, + IN INT_32 i4TotalIeLen, + IN UINT_8 ucDesiredElemId, + OUT PUINT_8 *ppucDesiredIE + ); + +#if CFG_SUPPORT_WPS +extern BOOLEAN +wextSrchDesiredWPSIE ( + IN PUINT_8 pucIEStart, + IN INT_32 i4TotalIeLen, + IN UINT_8 ucDesiredElemId, + OUT PUINT_8 *ppucDesiredIE + ); +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +BOOLEAN +kalP2pFuncGetChannelType( + IN ENUM_CHNL_EXT_T rChnlSco, + OUT enum nl80211_channel_type *channel_type + ); + + +struct ieee80211_channel * +kalP2pFuncGetChannelEntry( + IN P_GL_P2P_INFO_T prP2pInfo, + IN P_RF_CHANNEL_INFO_T prChannelInfo + ); + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to retrieve Wi-Fi Direct state from glue layer +* +* \param[in] +* prGlueInfo +* rPeerAddr +* \return +* ENUM_BOW_DEVICE_STATE +*/ +/*----------------------------------------------------------------------------*/ +ENUM_PARAM_MEDIA_STATE_T +kalP2PGetState ( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + ASSERT(prGlueInfo); + + return prGlueInfo->prP2PInfo->eState; +} /* end of kalP2PGetState() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to update the assoc req to p2p +* +* \param[in] +* prGlueInfo +* pucFrameBody +* u4FrameBodyLen +* fgReassocRequest +* \return +* none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalP2PUpdateAssocInfo ( + IN P_GLUE_INFO_T prGlueInfo, + IN PUINT_8 pucFrameBody, + IN UINT_32 u4FrameBodyLen, + IN BOOLEAN fgReassocRequest + ) +{ + union iwreq_data wrqu; + unsigned char *pucExtraInfo = NULL; + unsigned char *pucDesiredIE = NULL; +// unsigned char aucExtraInfoBuf[200]; + PUINT_8 cp; + + memset(&wrqu, 0, sizeof(wrqu)); + + if (fgReassocRequest) { + if (u4FrameBodyLen < 15) { + /* + printk(KERN_WARNING "frameBodyLen too short:%ld\n", frameBodyLen); + */ + return; + } + } + else { + if (u4FrameBodyLen < 9) { + /* + printk(KERN_WARNING "frameBodyLen too short:%ld\n", frameBodyLen); + */ + return; + } + } + + cp = pucFrameBody; + + if (fgReassocRequest) { + /* Capability information field 2 */ + /* Listen interval field 2*/ + /* Current AP address 6 */ + cp += 10; + u4FrameBodyLen -= 10; + } + else { + /* Capability information field 2 */ + /* Listen interval field 2*/ + cp += 4; + u4FrameBodyLen -= 4; + } + + /* do supplicant a favor, parse to the start of WPA/RSN IE */ + if (wextSrchDesiredWPSIE(cp, u4FrameBodyLen, 0xDD, &pucDesiredIE)) { + //printk("wextSrchDesiredWPSIE!!\n"); + /* WPS IE found */ + } + else if (wextSrchDesiredWPAIE(cp, u4FrameBodyLen, 0x30, &pucDesiredIE)) { + //printk("wextSrchDesiredWPAIE!!\n"); + /* RSN IE found */ + } + else if (wextSrchDesiredWPAIE(cp, u4FrameBodyLen, 0xDD, &pucDesiredIE)) { + //printk("wextSrchDesiredWPAIE!!\n"); + /* WPA IE found */ + } + else { + /* no WPA/RSN IE found, skip this event */ + goto skip_indicate_event; + } + + /* IWEVASSOCREQIE, indicate binary string */ + pucExtraInfo = pucDesiredIE; + wrqu.data.length = pucDesiredIE[1] + 2; + + /* Send event to user space */ + wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVASSOCREQIE, &wrqu, pucExtraInfo); + +skip_indicate_event: + return; + +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to set Wi-Fi Direct state in glue layer +* +* \param[in] +* prGlueInfo +* eBowState +* rPeerAddr +* \return +* none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalP2PSetState ( + IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_PARAM_MEDIA_STATE_T eState, + IN PARAM_MAC_ADDRESS rPeerAddr, + IN UINT_8 ucRole + ) +{ + union iwreq_data evt; + UINT_8 aucBuffer[IW_CUSTOM_MAX]; + + ASSERT(prGlueInfo); + + memset(&evt, 0, sizeof(evt)); + + if(eState == PARAM_MEDIA_STATE_CONNECTED) { + prGlueInfo->prP2PInfo->eState = PARAM_MEDIA_STATE_CONNECTED; + + snprintf(aucBuffer, IW_CUSTOM_MAX-1, "P2P_STA_CONNECT="MACSTR, MAC2STR(rPeerAddr)); + evt.data.length = strlen(aucBuffer); + + /* indicate in IWECUSTOM event */ + wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, + IWEVCUSTOM, + &evt, + aucBuffer); + + } + else if(eState == PARAM_MEDIA_STATE_DISCONNECTED) { + snprintf(aucBuffer, IW_CUSTOM_MAX-1, "P2P_STA_DISCONNECT="MACSTR, MAC2STR(rPeerAddr)); + evt.data.length = strlen(aucBuffer); + + /* indicate in IWECUSTOM event */ + wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, + IWEVCUSTOM, + &evt, + aucBuffer); + } + else { + ASSERT(0); + } + + return; +} /* end of kalP2PSetState() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to retrieve Wi-Fi Direct operating frequency +* +* \param[in] +* prGlueInfo +* +* \return +* in unit of KHz +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 +kalP2PGetFreqInKHz( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + ASSERT(prGlueInfo); + + return prGlueInfo->prP2PInfo->u4FreqInKHz; +} /* end of kalP2PGetFreqInKHz() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to retrieve Bluetooth-over-Wi-Fi role +* +* \param[in] +* prGlueInfo +* +* \return +* 0: P2P Device +* 1: Group Client +* 2: Group Owner +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 +kalP2PGetRole( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + ASSERT(prGlueInfo); + + return prGlueInfo->prP2PInfo->ucRole; +} /* end of kalP2PGetRole() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to set Wi-Fi Direct role +* +* \param[in] +* prGlueInfo +* ucResult +* 0: successful +* 1: error +* ucRole +* 0: P2P Device +* 1: Group Client +* 2: Group Owner +* +* \return +* none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalP2PSetRole( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_8 ucResult, + IN PUINT_8 pucSSID, + IN UINT_8 ucSSIDLen, + IN UINT_8 ucRole + ) +{ + union iwreq_data evt; + UINT_8 aucBuffer[IW_CUSTOM_MAX]; + + ASSERT(prGlueInfo); + ASSERT(ucRole <= 2); + + memset(&evt, 0, sizeof(evt)); + + if(ucResult == 0) { + prGlueInfo->prP2PInfo->ucRole = ucRole; + } + + if (pucSSID) + snprintf(aucBuffer, IW_CUSTOM_MAX-1, "P2P_FORMATION_RST=%d%d%d%c%c", ucResult, ucRole, 1/* persistence or not */, pucSSID[7], pucSSID[8]); + else + snprintf(aucBuffer, IW_CUSTOM_MAX-1, "P2P_FORMATION_RST=%d%d%d%c%c", ucResult, ucRole, 1/* persistence or not */, '0', '0'); + + evt.data.length = strlen(aucBuffer); + + //if (pucSSID) + // printk("P2P GO SSID DIRECT-%c%c\n", pucSSID[7], pucSSID[8]); + + /* indicate in IWECUSTOM event */ + wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, + IWEVCUSTOM, + &evt, + aucBuffer); + + return; +} /* end of kalP2PSetRole() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to set the cipher for p2p +* +* \param[in] +* prGlueInfo +* u4Cipher +* +* \return +* none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalP2PSetCipher( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_32 u4Cipher + ) +{ + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prP2PInfo); + + prGlueInfo->prP2PInfo->u4CipherPairwise = u4Cipher; + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to get the cipher, return for cipher is ccmp +* +* \param[in] +* prGlueInfo +* +* \return +* TRUE: cipher is ccmp +* FALSE: cipher is none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +kalP2PGetCipher ( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prP2PInfo); + + if (prGlueInfo->prP2PInfo->u4CipherPairwise == IW_AUTH_CIPHER_CCMP) + return TRUE; + + if (prGlueInfo->prP2PInfo->u4CipherPairwise == IW_AUTH_CIPHER_TKIP) + return TRUE; + + return FALSE; +} + +BOOLEAN +kalP2PGetCcmpCipher ( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prP2PInfo); + + if (prGlueInfo->prP2PInfo->u4CipherPairwise == IW_AUTH_CIPHER_CCMP) + return TRUE; + + if (prGlueInfo->prP2PInfo->u4CipherPairwise == IW_AUTH_CIPHER_TKIP) + return FALSE; + + return FALSE; +} + + +BOOLEAN +kalP2PGetTkipCipher ( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prP2PInfo); + + if (prGlueInfo->prP2PInfo->u4CipherPairwise == IW_AUTH_CIPHER_CCMP) + return FALSE; + + if (prGlueInfo->prP2PInfo->u4CipherPairwise == IW_AUTH_CIPHER_TKIP) + return TRUE; + + return FALSE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to set the status of WSC +* +* \param[in] +* prGlueInfo +* +* \return +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalP2PSetWscMode ( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_8 ucWscMode + ) +{ + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prP2PInfo); + + prGlueInfo->prP2PInfo->ucWSCRunning = ucWscMode; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to get the status of WSC +* +* \param[in] +* prGlueInfo +* +* \return +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 +kalP2PGetWscMode ( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prP2PInfo); + + return (prGlueInfo->prP2PInfo->ucWSCRunning); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to get the wsc ie length +* +* \param[in] +* prGlueInfo +* ucType : 0 for beacon, 1 for probe req, 2 for probe resp +* +* \return +* The WSC IE length +*/ +/*----------------------------------------------------------------------------*/ +UINT_16 +kalP2PCalWSC_IELen ( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_8 ucType + ) +{ + ASSERT(prGlueInfo); + + ASSERT(ucType < 3); + + return prGlueInfo->prP2PInfo->u2WSCIELen[ucType]; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to copy the wsc ie setting from p2p supplicant +* +* \param[in] +* prGlueInfo +* +* \return +* The WPS IE length +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalP2PGenWSC_IE ( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_8 ucType, + IN PUINT_8 pucBuffer + ) +{ + P_GL_P2P_INFO_T prGlP2pInfo = (P_GL_P2P_INFO_T)NULL; + + do { + if ((prGlueInfo == NULL) || + (ucType >= 3) || + (pucBuffer == NULL)) { + break; + } + + + prGlP2pInfo = prGlueInfo->prP2PInfo; + + kalMemCopy(pucBuffer, prGlP2pInfo->aucWSCIE[ucType], prGlP2pInfo->u2WSCIELen[ucType]); + + } while (FALSE); + + return; +} + + +VOID +kalP2PUpdateWSC_IE ( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_8 ucType, + IN PUINT_8 pucBuffer, + IN UINT_16 u2BufferLength + ) +{ + P_GL_P2P_INFO_T prGlP2pInfo = (P_GL_P2P_INFO_T)NULL; + + do { + if ((prGlueInfo == NULL) || + (ucType >= 3) || + ((u2BufferLength > 0) && (pucBuffer == NULL))) { + break; + } + + + if (u2BufferLength > 400) { + DBGLOG(P2P, ERROR, ("Buffer length is not enough, GLUE only 400 bytes but %d received\n", u2BufferLength)); + ASSERT(FALSE); + break; + } + + + prGlP2pInfo = prGlueInfo->prP2PInfo; + + kalMemCopy(prGlP2pInfo->aucWSCIE[ucType], pucBuffer, u2BufferLength); + + prGlP2pInfo->u2WSCIELen[ucType] = u2BufferLength; + + + } while (FALSE); + + return; +} /* kalP2PUpdateWSC_IE */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief indicate an event to supplicant for device connection request +* +* \param[in] prGlueInfo Pointer of GLUE_INFO_T +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalP2PIndicateConnReq( + IN P_GLUE_INFO_T prGlueInfo, + IN PUINT_8 pucDevName, + IN INT_32 u4NameLength, + IN PARAM_MAC_ADDRESS rPeerAddr, + IN UINT_8 ucDevType, /* 0: P2P Device / 1: GC / 2: GO */ + IN INT_32 i4ConfigMethod, + IN INT_32 i4ActiveConfigMethod + ) +{ + union iwreq_data evt; + UINT_8 aucBuffer[IW_CUSTOM_MAX]; + + ASSERT(prGlueInfo); + + /* buffer peer information for later IOC_P2P_GET_REQ_DEVICE_INFO access */ + prGlueInfo->prP2PInfo->u4ConnReqNameLength = u4NameLength > 32 ? 32 : u4NameLength; + kalMemCopy(prGlueInfo->prP2PInfo->aucConnReqDevName, + pucDevName, + prGlueInfo->prP2PInfo->u4ConnReqNameLength); + COPY_MAC_ADDR(prGlueInfo->prP2PInfo->rConnReqPeerAddr, rPeerAddr); + prGlueInfo->prP2PInfo->ucConnReqDevType = ucDevType; + prGlueInfo->prP2PInfo->i4ConnReqConfigMethod = i4ConfigMethod; + prGlueInfo->prP2PInfo->i4ConnReqActiveConfigMethod = i4ActiveConfigMethod; + + // prepare event structure + memset(&evt, 0, sizeof(evt)); + + snprintf(aucBuffer, IW_CUSTOM_MAX-1, "P2P_DVC_REQ"); + evt.data.length = strlen(aucBuffer); + + /* indicate in IWEVCUSTOM event */ + wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, + IWEVCUSTOM, + &evt, + aucBuffer); + + return; +} /* end of kalP2PIndicateConnReq() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Indicate an event to supplicant for device connection request from other device. +* +* \param[in] prGlueInfo Pointer of GLUE_INFO_T +* \param[in] pucGroupBssid Only valid when invitation Type equals to 0. +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalP2PInvitationIndication ( + IN P_GLUE_INFO_T prGlueInfo, + IN P_P2P_DEVICE_DESC_T prP2pDevDesc, + IN PUINT_8 pucSsid, + IN UINT_8 ucSsidLen, + IN UINT_8 ucOperatingChnl, + IN UINT_8 ucInvitationType, + IN PUINT_8 pucGroupBssid + ) +{ +#if 1 + union iwreq_data evt; + UINT_8 aucBuffer[IW_CUSTOM_MAX]; + + ASSERT(prGlueInfo); + + /* buffer peer information for later IOC_P2P_GET_STRUCT access */ + prGlueInfo->prP2PInfo->u4ConnReqNameLength = (UINT_32)((prP2pDevDesc->u2NameLength > 32)? 32 : prP2pDevDesc->u2NameLength); + kalMemCopy(prGlueInfo->prP2PInfo->aucConnReqDevName, + prP2pDevDesc->aucName, + prGlueInfo->prP2PInfo->u4ConnReqNameLength); + COPY_MAC_ADDR(prGlueInfo->prP2PInfo->rConnReqPeerAddr, prP2pDevDesc->aucDeviceAddr); + COPY_MAC_ADDR(prGlueInfo->prP2PInfo->rConnReqGroupAddr, pucGroupBssid); + prGlueInfo->prP2PInfo->i4ConnReqConfigMethod = (INT_32)(prP2pDevDesc->u2ConfigMethod); + prGlueInfo->prP2PInfo->ucOperatingChnl = ucOperatingChnl; + prGlueInfo->prP2PInfo->ucInvitationType = ucInvitationType; + + // prepare event structure + memset(&evt, 0, sizeof(evt)); + + snprintf(aucBuffer, IW_CUSTOM_MAX-1, "P2P_INV_INDICATE"); + evt.data.length = strlen(aucBuffer); + + /* indicate in IWEVCUSTOM event */ + wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, + IWEVCUSTOM, + &evt, + aucBuffer); + return; + +#else + P_MSG_P2P_CONNECTION_REQUEST_T prP2pConnReq = (P_MSG_P2P_CONNECTION_REQUEST_T)NULL; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T)NULL; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T)NULL; + + do { + ASSERT_BREAK((prGlueInfo != NULL) && (prP2pDevDesc != NULL)); + + + // Not a real solution + + prP2pSpecificBssInfo = prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo; + prP2pConnSettings = prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings; + + prP2pConnReq = (P_MSG_P2P_CONNECTION_REQUEST_T)cnmMemAlloc(prGlueInfo->prAdapter, + RAM_TYPE_MSG, + sizeof(MSG_P2P_CONNECTION_REQUEST_T)); + + if (prP2pConnReq == NULL) { + break; + } + + + kalMemZero(prP2pConnReq, sizeof(MSG_P2P_CONNECTION_REQUEST_T)); + + prP2pConnReq->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_REQ; + + prP2pConnReq->eFormationPolicy = ENUM_P2P_FORMATION_POLICY_AUTO; + + COPY_MAC_ADDR(prP2pConnReq->aucDeviceID, prP2pDevDesc->aucDeviceAddr); + + prP2pConnReq->u2ConfigMethod = prP2pDevDesc->u2ConfigMethod; + + if (ucInvitationType == P2P_INVITATION_TYPE_INVITATION) { + prP2pConnReq->fgIsPersistentGroup = FALSE; + prP2pConnReq->fgIsTobeGO = FALSE; + + } + + else if (ucInvitationType == P2P_INVITATION_TYPE_REINVOKE) { + DBGLOG(P2P, TRACE, ("Re-invoke Persistent Group\n")); + prP2pConnReq->fgIsPersistentGroup = TRUE; + prP2pConnReq->fgIsTobeGO = (prGlueInfo->prP2PInfo->ucRole == 2)?TRUE:FALSE; + + } + + + p2pFsmRunEventDeviceDiscoveryAbort(prGlueInfo->prAdapter, NULL); + + if (ucOperatingChnl != 0) { + prP2pSpecificBssInfo->ucPreferredChannel = ucOperatingChnl; + } + + if ((ucSsidLen < 32) && (pucSsid != NULL)) { + COPY_SSID(prP2pConnSettings->aucSSID, + prP2pConnSettings->ucSSIDLen, + pucSsid, + ucSsidLen); + } + + mboxSendMsg(prGlueInfo->prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T)prP2pConnReq, + MSG_SEND_METHOD_BUF); + + + + } while (FALSE); + + // frog add. + // TODO: Invitation Indication + + return; +#endif + +} /* kalP2PInvitationIndication */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Indicate an status to supplicant for device invitation status. +* +* \param[in] prGlueInfo Pointer of GLUE_INFO_T +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalP2PInvitationStatus ( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_32 u4InvStatus + ) +{ + union iwreq_data evt; + UINT_8 aucBuffer[IW_CUSTOM_MAX]; + + ASSERT(prGlueInfo); + + /* buffer peer information for later IOC_P2P_GET_STRUCT access */ + prGlueInfo->prP2PInfo->u4InvStatus = u4InvStatus; + + // prepare event structure + memset(&evt, 0, sizeof(evt)); + + snprintf(aucBuffer, IW_CUSTOM_MAX-1, "P2P_INV_STATUS"); + evt.data.length = strlen(aucBuffer); + + /* indicate in IWEVCUSTOM event */ + wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, + IWEVCUSTOM, + &evt, + aucBuffer); + + return; +} /* kalP2PInvitationStatus */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Indicate an event to supplicant for Service Discovery request from other device. +* +* \param[in] prGlueInfo Pointer of GLUE_INFO_T +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalP2PIndicateSDRequest( + IN P_GLUE_INFO_T prGlueInfo, + IN PARAM_MAC_ADDRESS rPeerAddr, + IN UINT_8 ucSeqNum + ) +{ + union iwreq_data evt; + UINT_8 aucBuffer[IW_CUSTOM_MAX]; + + ASSERT(prGlueInfo); + + memset(&evt, 0, sizeof(evt)); + + snprintf(aucBuffer, IW_CUSTOM_MAX-1, "P2P_SD_REQ %d", ucSeqNum); + evt.data.length = strlen(aucBuffer); + + /* indicate IWEVP2PSDREQ event */ + wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, + IWEVCUSTOM, + &evt, + aucBuffer); + + return; +} /* end of kalP2PIndicateSDRequest() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Indicate an event to supplicant for Service Discovery response +* from other device. +* +* \param[in] prGlueInfo Pointer of GLUE_INFO_T +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +void +kalP2PIndicateSDResponse( + IN P_GLUE_INFO_T prGlueInfo, + IN PARAM_MAC_ADDRESS rPeerAddr, + IN UINT_8 ucSeqNum + ) +{ + union iwreq_data evt; + UINT_8 aucBuffer[IW_CUSTOM_MAX]; + + ASSERT(prGlueInfo); + + memset(&evt, 0, sizeof(evt)); + + snprintf(aucBuffer, IW_CUSTOM_MAX-1, "P2P_SD_RESP %d", ucSeqNum); + evt.data.length = strlen(aucBuffer); + + /* indicate IWEVP2PSDREQ event */ + wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, + IWEVCUSTOM, + &evt, + aucBuffer); + + return; +} /* end of kalP2PIndicateSDResponse() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Indicate an event to supplicant for Service Discovery TX Done +* from other device. +* +* \param[in] prGlueInfo Pointer of GLUE_INFO_T +* \param[in] ucSeqNum Sequence number of the frame +* \param[in] ucStatus Status code for TX +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalP2PIndicateTXDone( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_8 ucSeqNum, + IN UINT_8 ucStatus + ) +{ + union iwreq_data evt; + UINT_8 aucBuffer[IW_CUSTOM_MAX]; + + ASSERT(prGlueInfo); + + memset(&evt, 0, sizeof(evt)); + + snprintf(aucBuffer, IW_CUSTOM_MAX-1, "P2P_SD_XMITTED: %d %d", ucSeqNum, ucStatus); + evt.data.length = strlen(aucBuffer); + + /* indicate IWEVP2PSDREQ event */ + wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, + IWEVCUSTOM, + &evt, + aucBuffer); + + return; +} /* end of kalP2PIndicateSDResponse() */ + + +struct net_device* +kalP2PGetDevHdlr( + P_GLUE_INFO_T prGlueInfo + ) +{ + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prP2PInfo); + return prGlueInfo->prP2PInfo->prDevHandler; +} + +#if CFG_SUPPORT_ANTI_PIRACY +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalP2PIndicateSecCheckRsp ( + IN P_GLUE_INFO_T prGlueInfo, + IN PUINT_8 pucRsp, + IN UINT_16 u2RspLen + ) +{ + union iwreq_data evt; + UINT_8 aucBuffer[IW_CUSTOM_MAX]; + + ASSERT(prGlueInfo); + + memset(&evt, 0, sizeof(evt)); + snprintf(aucBuffer, IW_CUSTOM_MAX-1, "P2P_SEC_CHECK_RSP="); + + kalMemCopy(prGlueInfo->prP2PInfo->aucSecCheckRsp, pucRsp, u2RspLen); + evt.data.length = strlen(aucBuffer); + +#if DBG + DBGLOG_MEM8(SEC, LOUD, prGlueInfo->prP2PInfo->aucSecCheckRsp, u2RspLen); +#endif + /* indicate in IWECUSTOM event */ + wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, + IWEVCUSTOM, + &evt, + aucBuffer); + return; +} /* p2pFsmRunEventRxDisassociation */ +#endif + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalGetChnlList( + IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_BAND_T eSpecificBand, + IN UINT_8 ucMaxChannelNum, + IN PUINT_8 pucNumOfChannel, + IN P_RF_CHANNEL_INFO_T paucChannelList + ) +{ + rlmDomainGetChnlList(prGlueInfo->prAdapter, + eSpecificBand, + ucMaxChannelNum, + pucNumOfChannel, + paucChannelList); +} /* kalGetChnlList */ + +//////////////////////////////////////ICS SUPPORT////////////////////////////////////// + +VOID +kalP2PIndicateChannelReady ( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_64 u8SeqNum, + IN UINT_32 u4ChannelNum, + IN ENUM_BAND_T eBand, + IN ENUM_CHNL_EXT_T eSco, + IN UINT_32 u4Duration + ) +{ + struct ieee80211_channel *prIEEE80211ChnlStruct = (struct ieee80211_channel *)NULL; + RF_CHANNEL_INFO_T rChannelInfo; + enum nl80211_channel_type eChnlType = NL80211_CHAN_NO_HT; + + do { + if (prGlueInfo == NULL) { + break; + } + + + kalMemZero(&rChannelInfo, sizeof(RF_CHANNEL_INFO_T)); + + rChannelInfo.ucChannelNum = u4ChannelNum; + rChannelInfo.eBand = eBand; + + prIEEE80211ChnlStruct = kalP2pFuncGetChannelEntry(prGlueInfo->prP2PInfo, &rChannelInfo); + + kalP2pFuncGetChannelType(eSco, &eChnlType); + + cfg80211_ready_on_channel(prGlueInfo->prP2PInfo->prDevHandler, //struct net_device * dev, + u8SeqNum, //u64 cookie, + prIEEE80211ChnlStruct, //struct ieee80211_channel * chan, + eChnlType, //enum nl80211_channel_type channel_type, + u4Duration, //unsigned int duration, + GFP_KERNEL); //gfp_t gfp /* allocation flags */ + + } while (FALSE); + +} /* kalP2PIndicateChannelReady */ + +VOID +kalP2PIndicateChannelExpired ( + IN P_GLUE_INFO_T prGlueInfo, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo + ) +{ + + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T)NULL; + struct ieee80211_channel *prIEEE80211ChnlStruct = (struct ieee80211_channel *)NULL; + enum nl80211_channel_type eChnlType = NL80211_CHAN_NO_HT; + RF_CHANNEL_INFO_T rRfChannelInfo; + + do { + if ((prGlueInfo == NULL) || (prChnlReqInfo == NULL)) { + + ASSERT(FALSE); + break; + } + + prGlueP2pInfo = prGlueInfo->prP2PInfo; + + if (prGlueP2pInfo == NULL) { + ASSERT(FALSE); + break; + } + + + DBGLOG(P2P, TRACE, ("kalP2PIndicateChannelExpired\n")); + + rRfChannelInfo.eBand = prChnlReqInfo->eBand; + rRfChannelInfo.ucChannelNum = prChnlReqInfo->ucReqChnlNum; + + prIEEE80211ChnlStruct = kalP2pFuncGetChannelEntry(prGlueP2pInfo, &rRfChannelInfo); + + + kalP2pFuncGetChannelType(prChnlReqInfo->eChnlSco, + &eChnlType); + + + cfg80211_remain_on_channel_expired(prGlueP2pInfo->prDevHandler, //struct net_device * dev, + prChnlReqInfo->u8Cookie, + prIEEE80211ChnlStruct, + eChnlType, + GFP_KERNEL); + + } while (FALSE); + +} /* kalP2PIndicateChannelExpired */ + +VOID +kalP2PIndicateScanDone ( + IN P_GLUE_INFO_T prGlueInfo, + IN BOOLEAN fgIsAbort + ) +{ + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T)NULL; + + do { + if (prGlueInfo == NULL) { + + ASSERT(FALSE); + break; + } + + prGlueP2pInfo = prGlueInfo->prP2PInfo; + + if (prGlueP2pInfo == NULL) { + ASSERT(FALSE); + break; + } + + + if (prGlueP2pInfo->prScanRequest) { + cfg80211_scan_done(prGlueP2pInfo->prScanRequest, + fgIsAbort); + + prGlueP2pInfo->prScanRequest = NULL; + } + + } while (FALSE); + + +} /* kalP2PIndicateScanDone */ + +VOID +kalP2PIndicateBssInfo ( + IN P_GLUE_INFO_T prGlueInfo, + IN PUINT_8 pucFrameBuf, + IN UINT_32 u4BufLen, + IN P_RF_CHANNEL_INFO_T prChannelInfo, + IN INT_32 i4SignalStrength + ) +{ + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T)NULL; + struct ieee80211_channel *prChannelEntry = (struct ieee80211_channel *)NULL; + struct ieee80211_mgmt *prBcnProbeRspFrame = (struct ieee80211_mgmt *)pucFrameBuf; + + do { + if ((prGlueInfo == NULL) || (pucFrameBuf == NULL) || (prChannelInfo == NULL)) { + ASSERT(FALSE); + break; + } + + prGlueP2pInfo = prGlueInfo->prP2PInfo; + + if (prGlueP2pInfo == NULL) { + ASSERT(FALSE); + break; + } + + + prChannelEntry = kalP2pFuncGetChannelEntry(prGlueP2pInfo, prChannelInfo); + + if (prChannelEntry == NULL) { + DBGLOG(P2P, TRACE, ("Unknown channel info\n")); + break; + } + + + //rChannelInfo.center_freq = nicChannelNum2Freq((UINT_32)prChannelInfo->ucChannelNum) / 1000; + + cfg80211_inform_bss_frame(prGlueP2pInfo->wdev.wiphy, //struct wiphy * wiphy, + prChannelEntry, + prBcnProbeRspFrame, + u4BufLen, + i4SignalStrength, + GFP_KERNEL); + + } while (FALSE); + + return; + +} /* kalP2PIndicateBssInfo */ + +VOID +kalP2PIndicateMgmtTxStatus ( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_64 u8Cookie, + IN BOOLEAN fgIsAck, + IN PUINT_8 pucFrameBuf, + IN UINT_32 u4FrameLen + ) +{ + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T)NULL; + + do { + if ((prGlueInfo == NULL) || + (pucFrameBuf == NULL) || + (u4FrameLen == 0)) { + DBGLOG(P2P, TRACE, ("Unexpected pointer PARAM. 0x%lx, 0x%lx, %ld.", prGlueInfo, pucFrameBuf, u4FrameLen)); + ASSERT(FALSE); + break; + } + + prGlueP2pInfo = prGlueInfo->prP2PInfo; + + cfg80211_mgmt_tx_status(prGlueP2pInfo->prDevHandler, //struct net_device * dev, + u8Cookie, + pucFrameBuf, + u4FrameLen, + fgIsAck, + GFP_KERNEL); + + } while (FALSE); + +} /* kalP2PIndicateMgmtTxStatus */ + +VOID +kalP2PIndicateRxMgmtFrame ( + IN P_GLUE_INFO_T prGlueInfo, + IN P_SW_RFB_T prSwRfb + ) +{ +#define DBG_P2P_MGMT_FRAME_INDICATION 0 + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T)NULL; + INT_32 i4Freq = 0; + UINT_8 ucChnlNum = 0; +#if DBG_P2P_MGMT_FRAME_INDICATION + P_WLAN_MAC_HEADER_T prWlanHeader = (P_WLAN_MAC_HEADER_T)NULL; +#endif + + + do { + if ((prGlueInfo == NULL) || (prSwRfb == NULL)) { + ASSERT(FALSE); + break; + } + + prGlueP2pInfo = prGlueInfo->prP2PInfo; + + ucChnlNum = prSwRfb->prHifRxHdr->ucHwChannelNum; + +#if DBG_P2P_MGMT_FRAME_INDICATION + + prWlanHeader = (P_WLAN_MAC_HEADER_T)prSwRfb->pvHeader; + + switch (prWlanHeader->u2FrameCtrl) { + case MAC_FRAME_PROBE_REQ: + DBGLOG(P2P, TRACE, ("RX Probe Req at channel %d ", ucChnlNum)); + break; + case MAC_FRAME_PROBE_RSP: + DBGLOG(P2P, TRACE, ("RX Probe Rsp at channel %d ", ucChnlNum)); + break; + case MAC_FRAME_ACTION: + DBGLOG(P2P, TRACE, ("RX Action frame at channel %d ", ucChnlNum)); + break; + default: + DBGLOG(P2P, TRACE, ("RX Packet:%d at channel %d ", prWlanHeader->u2FrameCtrl, ucChnlNum)); + break; + } + + DBGLOG(P2P, TRACE, ("from: "MACSTR"\n", MAC2STR(prWlanHeader->aucAddr2))); +#endif + i4Freq = nicChannelNum2Freq(ucChnlNum) / 1000; + + cfg80211_rx_mgmt(prGlueP2pInfo->prDevHandler, //struct net_device * dev, + i4Freq, + prSwRfb->pvHeader, + prSwRfb->u2PacketLen, + GFP_KERNEL); + + } while (FALSE); + +} /* kalP2PIndicateRxMgmtFrame */ + +VOID +kalP2PGCIndicateConnectionStatus ( + IN P_GLUE_INFO_T prGlueInfo, + IN P_P2P_CONNECTION_REQ_INFO_T prP2pConnInfo, + IN PUINT_8 pucRxIEBuf, + IN UINT_16 u2RxIELen, + IN UINT_16 u2StatusReason + ) +{ + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T)NULL; + + do { + if (prGlueInfo == NULL) { + ASSERT(FALSE); + break; + } + + + prGlueP2pInfo = prGlueInfo->prP2PInfo; + + if (prP2pConnInfo) { + cfg80211_connect_result(prGlueP2pInfo->prDevHandler, //struct net_device * dev, + prP2pConnInfo->aucBssid, + prP2pConnInfo->aucIEBuf, + prP2pConnInfo->u4BufLength, + pucRxIEBuf, + u2RxIELen, + u2StatusReason, + GFP_KERNEL); //gfp_t gfp /* allocation flags */ + prP2pConnInfo->fgIsConnRequest = FALSE; + } + else { + /* Disconnect, what if u2StatusReason == 0? */ + cfg80211_disconnected(prGlueP2pInfo->prDevHandler, //struct net_device * dev, + u2StatusReason, + pucRxIEBuf, + u2RxIELen, + GFP_KERNEL); + } + + + + } while (FALSE); + + +} /* kalP2PGCIndicateConnectionStatus */ + + +VOID +kalP2PGOStationUpdate ( + IN P_GLUE_INFO_T prGlueInfo, + IN P_STA_RECORD_T prCliStaRec, + IN BOOLEAN fgIsNew + ) +{ + P_GL_P2P_INFO_T prP2pGlueInfo = (P_GL_P2P_INFO_T)NULL; + struct station_info rStationInfo; + + do { + if ((prGlueInfo == NULL) || (prCliStaRec == NULL)) { + break; + } + + + prP2pGlueInfo = prGlueInfo->prP2PInfo; + + if (fgIsNew) { + rStationInfo.filled = 0; + rStationInfo.generation = ++prP2pGlueInfo->i4Generation; + + rStationInfo.assoc_req_ies = prCliStaRec->pucAssocReqIe; + rStationInfo.assoc_req_ies_len = prCliStaRec->u2AssocReqIeLen; +// rStationInfo.filled |= STATION_INFO_ASSOC_REQ_IES; + + cfg80211_new_sta(prGlueInfo->prP2PInfo->prDevHandler, //struct net_device * dev, + prCliStaRec->aucMacAddr, + &rStationInfo, + GFP_KERNEL); + } + else { + ++prP2pGlueInfo->i4Generation; + + cfg80211_del_sta(prGlueInfo->prP2PInfo->prDevHandler, //struct net_device * dev, + prCliStaRec->aucMacAddr, + GFP_KERNEL); + } + + + } while (FALSE); + + return; + +} /* kalP2PGOStationUpdate */ + + + + +BOOLEAN +kalP2pFuncGetChannelType( + IN ENUM_CHNL_EXT_T rChnlSco, + OUT enum nl80211_channel_type *channel_type + ) +{ + BOOLEAN fgIsValid = FALSE; + + do { + if (channel_type) { + + switch (rChnlSco) { + case CHNL_EXT_SCN: + *channel_type = NL80211_CHAN_NO_HT; + break; + case CHNL_EXT_SCA: + *channel_type = NL80211_CHAN_HT40MINUS; + break; + case CHNL_EXT_SCB: + *channel_type = NL80211_CHAN_HT40PLUS; + break; + default: + ASSERT(FALSE); + *channel_type = NL80211_CHAN_NO_HT; + break; + } + + } + + fgIsValid = TRUE; + } while (FALSE); + + return fgIsValid; +} /* kalP2pFuncGetChannelType */ + + + + +struct ieee80211_channel * +kalP2pFuncGetChannelEntry ( + IN P_GL_P2P_INFO_T prP2pInfo, + IN P_RF_CHANNEL_INFO_T prChannelInfo + ) +{ + struct ieee80211_channel *prTargetChannelEntry = (struct ieee80211_channel *)NULL; + UINT_32 u4TblSize = 0, u4Idx = 0; + + do { + if ((prP2pInfo == NULL) || (prChannelInfo == NULL)) { + break; + } + + + switch (prChannelInfo->eBand) { + case BAND_2G4: + prTargetChannelEntry = prP2pInfo->wdev.wiphy->bands[IEEE80211_BAND_2GHZ]->channels; + u4TblSize = prP2pInfo->wdev.wiphy->bands[IEEE80211_BAND_2GHZ]->n_channels; + break; + case BAND_5G: + prTargetChannelEntry = prP2pInfo->wdev.wiphy->bands[IEEE80211_BAND_5GHZ]->channels; + u4TblSize = prP2pInfo->wdev.wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels; + break; + default: + break; + } + + + if (prTargetChannelEntry == NULL) { + break; + } + + + + for (u4Idx = 0; u4Idx < u4TblSize; u4Idx++, prTargetChannelEntry++) { + if (prTargetChannelEntry->hw_value == prChannelInfo->ucChannelNum) { + break; + } + + } + + + if (u4Idx == u4TblSize) { + prTargetChannelEntry = NULL; + break; + } + + + } while (FALSE); + + return prTargetChannelEntry; +} /* kalP2pFuncGetChannelEntry */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/include/gl_p2p_ioctl.h b/drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/include/gl_p2p_ioctl.h new file mode 100755 index 000000000000..dbcfd270b695 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/include/gl_p2p_ioctl.h @@ -0,0 +1,1085 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/WIFI_P2P_DRIVER_V2_2/os/linux/include/gl_p2p_ioctl.h#7 $ +*/ + +/*! \file gl_p2p_ioctl.h + \brief This file is for custom ioctls for Wi-Fi Direct only +*/ + +/******************************************************************************* +* Copyright (c) 2010 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: gl_p2p_ioctl.h $ + * + * 02 23 2012 chinglan.wang + * [ALPS00240621] [Wifi P2P]Run Sigma tool of A69. Always run fail on 7.1.3. sniffer check Sta-IsActive-No-Frames-With-PowerMgmt-1 + * . + * + * 01 31 2012 yuche.tsai + * NULL + * Fix compile error & del beacon scenario. + * + * 01 26 2012 yuche.tsai + * NULL + * Fix compile warning. + * + * 01 16 2012 chinglan.wang + * NULL + * Update security code.. + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Tethering for ICS code update. - fix KE when indicate Probe Request. + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Hot Spot Tethering for ICS ALPHA testing version. + * + * 01 09 2012 terry.wu + * [WCXRP00001166] [Wi-Fi] [Driver] cfg80211 integration for p2p newtork + * cfg80211 integration for p2p network. + * + * 11 24 2011 yuche.tsai + * NULL + * Fix P2P IOCTL of multicast address bug, add low power driver stop control. + * + * 11 22 2011 yuche.tsai + * NULL + * Update RSSI link quality of P2P Network query method. (Bug fix) + * + * 11 19 2011 yuche.tsai + * NULL + * Add RSSI support for P2P network. + * + * 11 11 2011 yuche.tsai + * NULL + * Fix work thread cancel issue. + * + * 11 08 2011 yuche.tsai + * [WCXRP00001094] [Volunteer Patch][Driver] Driver version & supplicant version query & set support for service discovery version check. + * Add support for driver version query & p2p supplicant verseion set. + * For new service discovery mechanism sync. + * + * 10 25 2011 cm.chang + * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode + * . + * + * 10 18 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * New 2.1 branch + + * + * 08 16 2011 chinglan.wang + * NULL + * Add the group id information in the invitation indication. + * + * 08 09 2011 yuche.tsai + * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. + * Invitation Feature add on. + * + * 05 04 2011 chinglan.wang + * [WCXRP00000698] [MT6620 Wi-Fi][P2P][Driver] Add p2p invitation command for the p2p driver + * . + * + * 03 29 2011 wh.su + * [WCXRP00000095] [MT6620 Wi-Fi] [FW] Refine the P2P GO send broadcast protected code + * add the set power and get power function sample. + * + * 03 22 2011 george.huang + * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command + * link with supplicant commands + * + * 03 19 2011 terry.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 p2p driver release based on label "MT6620_WIFI_P2P_DRIVER_V2_0_2100_0319_2011" from main trunk. + * + * 03 07 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * rename the define to anti_pviracy. + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * Add Security check related code. + * + * 03 01 2011 wh.su + * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver + * fixed the ioctl sumcmd to meet the p2p_supplicant setting. + * + * 02 23 2011 wh.su + * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver + * adding the ioctl set int define for p2p parameter. + * + * 02 22 2011 wh.su + * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver + * adding the ioctl set int from supplicant, and can used to set the p2p paramters + * + * 02 17 2011 wh.su + * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request + * adjust the set wsc ie structure. + * + * 01 05 2011 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service Discovery + * ioctl implementations for P2P Service Discovery + * + * 12 22 2010 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service Discovery + * 1. header file restructure for more clear module isolation + * 2. add function interface definition for implementing Service Discovery callbacks + * + * 12 15 2010 cp.wu + * NULL + * invoke nicEnableInterrupt() before leaving from wlanAdapterStart() + * + * 12 07 2010 cp.wu + * [WCXRP00000237] [MT6620 Wi-Fi][Wi-Fi Direct][Driver] Add interface for supporting service discovery + * define a pair of i/o control for multiplexing layer + * + * 11 04 2010 wh.su + * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID + * adding the p2p random ssid support. + * + * 10 20 2010 wh.su + * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group + * Add the code to support disconnect p2p group + * + * 09 21 2010 kevin.huang + * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface + * Isolate P2P related function for Hardware Software Bundle + * + * 09 10 2010 george.huang + * NULL + * update iwpriv LP related + * + * 09 07 2010 wh.su + * NULL + * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. + * + * 08 25 2010 cp.wu + * NULL + * add netdev_ops(NDO) for linux kernel 2.6.31 or greater + * + * 08 20 2010 yuche.tsai + * NULL + * Refine a function parameter name. + * + * 08 19 2010 cp.wu + * NULL + * add set mac address interface for further possibilities of wpa_supplicant overriding interface address. + * + * 08 16 2010 george.huang + * NULL + * add wext handlers to link P2P set PS profile/ network address function (TBD) + * + * 08 16 2010 cp.wu + * NULL + * revised implementation of Wi-Fi Direct io controls. + * + * 08 12 2010 cp.wu + * NULL + * follow-up with ioctl interface update for Wi-Fi Direct application + * + * 08 06 2010 cp.wu + * NULL + * driver hook modifications corresponding to ioctl interface change. + * + * 08 03 2010 cp.wu + * NULL + * [Wi-Fi Direct] add framework for driver hooks + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 06 01 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add ioctl to configure scan mode for p2p connection + * + * 05 31 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add cfg80211 interface, which is to replace WE, for further extension + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * implement get scan result. + * + * 05 14 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * implement wireless extension ioctls in iw_handler form. + * + * 05 14 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add ioctl framework for Wi-Fi Direct by reusing wireless extension ioctls as well + * + * 05 11 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * p2p ioctls revised. + * + * 05 11 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add ioctl for controlling p2p scan phase parameters + * +*/ + +#ifndef _GL_P2P_IOCTL_H +#define _GL_P2P_IOCTL_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include +#include +#include +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + #include + #include +#endif + +#include "wlan_oid.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +// (WirelessExtension) Private I/O Controls +#define IOC_P2P_CFG_DEVICE (SIOCIWFIRSTPRIV+0) +#define IOC_P2P_PROVISION_COMPLETE (SIOCIWFIRSTPRIV+2) +#define IOC_P2P_START_STOP_DISCOVERY (SIOCIWFIRSTPRIV+4) +#define IOC_P2P_DISCOVERY_RESULTS (SIOCIWFIRSTPRIV+5) +#define IOC_P2P_WSC_BEACON_PROBE_RSP_IE (SIOCIWFIRSTPRIV+6) +#define IOC_P2P_GO_WSC_IE IOC_P2P_WSC_BEACON_PROBE_RSP_IE +#define IOC_P2P_CONNECT_DISCONNECT (SIOCIWFIRSTPRIV+8) +#define IOC_P2P_PASSWORD_READY (SIOCIWFIRSTPRIV+10) +//#define IOC_P2P_SET_PWR_MGMT_PARAM (SIOCIWFIRSTPRIV+12) +#define IOC_P2P_SET_INT (SIOCIWFIRSTPRIV+12) +#define IOC_P2P_GET_STRUCT (SIOCIWFIRSTPRIV+13) +#define IOC_P2P_SET_STRUCT (SIOCIWFIRSTPRIV+14) +#define IOC_P2P_GET_REQ_DEVICE_INFO (SIOCIWFIRSTPRIV+15) + +#define PRIV_CMD_INT_P2P_SET 0 + +// IOC_P2P_PROVISION_COMPLETE (iw_point . flags) +#define P2P_PROVISIONING_SUCCESS 0 +#define P2P_PROVISIONING_FAIL 1 + +// IOC_P2P_START_STOP_DISCOVERY (iw_point . flags) +#define P2P_STOP_DISCOVERY 0 +#define P2P_START_DISCOVERY 1 + +// IOC_P2P_CONNECT_DISCONNECT (iw_point . flags) +#define P2P_CONNECT 0 +#define P2P_DISCONNECT 1 + +// IOC_P2P_START_STOP_DISCOVERY (scan_type) +#define P2P_SCAN_FULL_AND_FIND 0 +#define P2P_SCAN_FULL 1 +#define P2P_SCAN_SEARCH_AND_LISTEN 2 +#define P2P_LISTEN 3 + +// IOC_P2P_GET_STRUCT/IOC_P2P_SET_STRUCT +#define P2P_SEND_SD_RESPONSE 0 +#define P2P_GET_SD_REQUEST 1 +#define P2P_SEND_SD_REQUEST 2 +#define P2P_GET_SD_RESPONSE 3 +#define P2P_TERMINATE_SD_PHASE 4 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Wireless Extension: Private I/O Control */ +/*----------------------------------------------------------------------------*/ +typedef struct iw_p2p_cfg_device_type { + void __user *ssid; + UINT_8 ssid_len; + UINT_8 pri_device_type[8]; + UINT_8 snd_device_type[8]; + void __user *device_name; + UINT_8 device_name_len; + UINT_8 intend; + UINT_8 persistence; + UINT_8 sec_mode; + UINT_8 ch; + UINT_8 ch_width; /* 0: 20 Mhz 1:20/40 Mhz auto */ + UINT_8 max_scb; +} IW_P2P_CFG_DEVICE_TYPE, *P_IW_P2P_CFG_DEVICE_TYPE; + +typedef struct iw_p2p_hostapd_param { + UINT_8 cmd; + UINT_8 rsv[3]; + UINT_8 sta_addr[6]; + void __user *data; + UINT_16 len; +} IW_P2P_HOSTAPD_PARAM, *P_IW_P2P_HOSTAPD_PARAM; + +typedef struct iw_p2p_req_device_type { + UINT_8 scan_type; /* 0: Full scan + Find + * 1: Full scan + * 2: Scan (Search +Listen) + * 3: Listen + * other : reserved + */ + UINT_8 pri_device_type[8]; + void __user *probe_req_ie; + UINT_16 probe_req_len; + void __user *probe_rsp_ie; + UINT_16 probe_rsp_len; +} IW_P2P_REQ_DEVICE_TYPE, *P_IW_P2P_REQ_DEVICE_TYPE; + +typedef struct iw_p2p_connect_device { + UINT_8 sta_addr[6]; + UINT_8 p2pRole; /* 0: P2P Device, 1:GC, 2: GO */ + UINT_8 needProvision; /* 0: Don't needed provision, 1: doing the wsc provision first */ + UINT_8 authPeer; /* 1: auth peer invitation request */ + UINT_8 intend_config_method; /* Request Peer Device used config method */ +} IW_P2P_CONNECT_DEVICE, *P_IW_P2P_CONNECT_DEVICE; + +typedef struct iw_p2p_password_ready { + UINT_8 active_config_method; + void __user *probe_req_ie; + UINT_16 probe_req_len; + void __user *probe_rsp_ie; + UINT_16 probe_rsp_len; +} IW_P2P_PASSWORD_READY, *P_IW_P2P_PASSWORD_READY; + +typedef struct iw_p2p_device_req { + UINT_8 name[33]; + UINT_32 name_len; + UINT_8 device_addr[6]; + UINT_8 device_type; + INT_32 config_method; + INT_32 active_config_method; +} IW_P2P_DEVICE_REQ, *P_IW_P2P_DEVICE_REQ; + +typedef struct iw_p2p_transport_struct { + UINT_32 u4CmdId; + UINT_32 inBufferLength; + UINT_32 outBufferLength; + UINT_8 aucBuffer[16]; +} IW_P2P_TRANSPORT_STRUCT, *P_IW_P2P_TRANSPORT_STRUCT; + +// For Invitation +typedef struct iw_p2p_ioctl_invitation_struct { + UINT_8 aucDeviceID[6]; + UINT_8 aucGroupID[6]; // BSSID + UINT_8 aucSsid[32]; + UINT_32 u4SsidLen; + UINT_8 ucReinvoke; +} IW_P2P_IOCTL_INVITATION_STRUCT, *P_IW_P2P_IOCTL_INVITATION_STRUCT; + +typedef struct iw_p2p_ioctl_abort_invitation { + UINT_8 dev_addr[6]; +} IW_P2P_IOCTL_ABORT_INVITATION, *P_IW_P2P_IOCTL_ABORT_INVITATION; + +typedef struct iw_p2p_ioctl_invitation_indicate { + UINT_8 dev_addr[6]; + UINT_8 group_bssid[6]; + INT_32 config_method; /* peer device supported config method */ + UINT_8 dev_name[32]; /* for reinvoke */ + UINT_32 name_len; + UINT_8 operating_channel; /* for re-invoke, target operating channel */ + UINT_8 invitation_type; /* invitation or re-invoke */ +} IW_P2P_IOCTL_INVITATION_INDICATE, *P_IW_P2P_IOCTL_INVITATION_INDICATE; + +typedef struct iw_p2p_ioctl_invitation_status { + UINT_32 status_code; +} IW_P2P_IOCTL_INVITATION_STATUS, *P_IW_P2P_IOCTL_INVITATION_STATUS; + +//For Formation +typedef struct iw_p2p_ioctl_start_formation { + UINT_8 dev_addr[6]; /* bssid */ + UINT_8 role; /* 0: P2P Device, 1:GC, 2: GO */ + UINT_8 needProvision; /* 0: Don't needed provision, 1: doing the wsc provision first */ + UINT_8 auth; /* 1: auth peer invitation request */ + UINT_8 config_method; /* Request Peer Device used config method */ +}IW_P2P_IOCTL_START_FORMATION, *P_IW_P2P_IOCTL_START_FORMATION; + +/* SET_STRUCT / GET_STRUCT */ +typedef enum _ENUM_P2P_CMD_ID_T { + P2P_CMD_ID_SEND_SD_RESPONSE = 0, /* 0x00 (Set) */ + P2P_CMD_ID_GET_SD_REQUEST, /* 0x01 (Get) */ + P2P_CMD_ID_SEND_SD_REQUEST, /* 0x02 (Set) */ + P2P_CMD_ID_GET_SD_RESPONSE, /* 0x03 (Get) */ + P2P_CMD_ID_TERMINATE_SD_PHASE, /* 0x04 (Set) */ +#if 1 /* CFG_SUPPORT_ANTI_PIRACY */ + P2P_CMD_ID_SEC_CHECK, /* 0x05(Set) */ +#endif + P2P_CMD_ID_INVITATION, /* 0x06 (Set) */ + P2P_CMD_ID_INVITATION_INDICATE, /* 0x07 (Get) */ + P2P_CMD_ID_INVITATION_STATUS, /* 0x08 (Get) */ + P2P_CMD_ID_INVITATION_ABORT, /* 0x09 (Set) */ + P2P_CMD_ID_START_FORMATION, /* 0x0A (Set) */ + P2P_CMD_ID_P2P_VERSION, /* 0x0B (Set/Get) */ + P2P_CMD_ID_GET_CH_LIST = 12, /* 0x0C (Get) */ + P2P_CMD_ID_GET_OP_CH = 14 /* 0x0E (Get) */ +} ENUM_P2P_CMD_ID_T, *P_ENUM_P2P_CMD_ID_T; + +/* Service Discovery */ +typedef struct iw_p2p_cmd_send_sd_response { + PARAM_MAC_ADDRESS rReceiverAddr; + UINT_8 fgNeedTxDoneIndication; + UINT_8 ucSeqNum; + UINT_16 u2PacketLength; + UINT_8 aucPacketContent[0]; /*native 802.11*/ +} IW_P2P_CMD_SEND_SD_RESPONSE, *P_IW_P2P_CMD_SEND_SD_RESPONSE; + +typedef struct iw_p2p_cmd_get_sd_request { + PARAM_MAC_ADDRESS rTransmitterAddr; + UINT_16 u2PacketLength; + UINT_8 aucPacketContent[0]; /*native 802.11*/ +} IW_P2P_CMD_GET_SD_REQUEST, *P_IW_P2P_CMD_GET_SD_REQUEST; + +typedef struct iw_p2p_cmd_send_service_discovery_request { + PARAM_MAC_ADDRESS rReceiverAddr; + UINT_8 fgNeedTxDoneIndication; + UINT_8 ucSeqNum; + UINT_16 u2PacketLength; + UINT_8 aucPacketContent[0]; /*native 802.11*/ +} IW_P2P_CMD_SEND_SD_REQUEST, *P_IW_P2P_CMD_SEND_SD_REQUEST; + +typedef struct iw_p2p_cmd_get_sd_response { + PARAM_MAC_ADDRESS rTransmitterAddr; + UINT_16 u2PacketLength; + UINT_8 aucPacketContent[0]; /*native 802.11*/ +} IW_P2P_CMD_GET_SD_RESPONSE, *P_IW_P2P_CMD_GET_SD_RESPONSE; + +typedef struct iw_p2p_cmd_terminate_sd_phase { + PARAM_MAC_ADDRESS rPeerAddr; +} IW_P2P_CMD_TERMINATE_SD_PHASE, *P_IW_P2P_CMD_TERMINATE_SD_PHASE; + +typedef struct iw_p2p_version { + UINT_32 u4Version; +} IW_P2P_VERSION, *P_IW_P2P_VERSION; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +/* Macros used for cfg80211 */ +#define RATETAB_ENT(_rate, _rateid, _flags) \ + { \ + .bitrate = (_rate), \ + .hw_value = (_rateid), \ + .flags = (_flags), \ + } + +#define CHAN2G(_channel, _freq, _flags) \ + { \ + .band = IEEE80211_BAND_2GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_channel), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ + } + +#define CHAN5G(_channel, _flags) \ + { \ + .band = IEEE80211_BAND_5GHZ, \ + .center_freq = 5000 + (5 * (_channel)), \ + .hw_value = (_channel), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ + } + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && (CFG_ENABLE_WIFI_DIRECT_CFG_80211 != 0) +int mtk_p2p_cfg80211_change_iface( + struct wiphy *wiphy, + struct net_device *ndev, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params + ); + +int mtk_p2p_cfg80211_add_key( + struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, + bool pairwise, + const u8 *mac_addr, + struct key_params *params + ); + +int mtk_p2p_cfg80211_get_key( + struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, + bool pairwise, + const u8 *mac_addr, + void *cookie, + void (*callback)(void *cookie, struct key_params*) + ); + +int mtk_p2p_cfg80211_del_key( + struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, + bool pairwise, + const u8 *mac_addr + ); + +int +mtk_p2p_cfg80211_set_default_key( + struct wiphy *wiphy, + struct net_device *netdev, + u8 key_index, + bool unicast, + bool multicast + ); + + +int mtk_p2p_cfg80211_get_station( + struct wiphy *wiphy, + struct net_device *ndev, + u8 *mac, + struct station_info *sinfo + ); + +int mtk_p2p_cfg80211_scan( + struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_scan_request *request + ); + +int mtk_p2p_cfg80211_set_wiphy_params( + struct wiphy *wiphy, + u32 changed + ); + +int mtk_p2p_cfg80211_connect( + struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_connect_params *sme + ); + +int mtk_p2p_cfg80211_disconnect( + struct wiphy *wiphy, + struct net_device *dev, + u16 reason_code + ); + +int mtk_p2p_cfg80211_join_ibss( + struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ibss_params *params + ); + +int mtk_p2p_cfg80211_leave_ibss( + struct wiphy *wiphy, + struct net_device *dev + ); + +int mtk_p2p_cfg80211_set_txpower( + struct wiphy *wiphy, + enum nl80211_tx_power_setting type, + int mbm + ); + +int mtk_p2p_cfg80211_get_txpower( + struct wiphy *wiphy, + int *dbm + ); + +int mtk_p2p_cfg80211_set_power_mgmt( + struct wiphy *wiphy, + struct net_device *dev, + bool enabled, + int timeout + ); + +int +mtk_p2p_cfg80211_change_bss( + struct wiphy * wiphy, + struct net_device * dev, + struct bss_parameters * params + ); + +int +mtk_p2p_cfg80211_remain_on_channel( + struct wiphy * wiphy, + struct net_device * dev, + struct ieee80211_channel * chan, + enum nl80211_channel_type channel_type, + unsigned int duration, + u64 * cookie + ); + +int +mtk_p2p_cfg80211_cancel_remain_on_channel( + struct wiphy * wiphy, + struct net_device * dev, + u64 cookie + ); + +int +mtk_p2p_cfg80211_mgmt_tx( + struct wiphy * wiphy, + struct net_device * dev, + struct ieee80211_channel * chan, + bool offchan, + enum nl80211_channel_type channel_type, + bool channel_type_valid, + unsigned int wait, + const u8 * buf, + size_t len, + u64 *cookie + ); + +int +mtk_p2p_cfg80211_deauth( + struct wiphy * wiphy, + struct net_device * dev, + struct cfg80211_deauth_request * req, + void * cookie + ); + + +int +mtk_p2p_cfg80211_disassoc( + struct wiphy * wiphy, + struct net_device * dev, + struct cfg80211_disassoc_request * req, + void * cookie + ); + +int +mtk_p2p_cfg80211_add_set_beacon( + struct wiphy *wiphy, + struct net_device *dev, + struct beacon_parameters *info + ); + +int +mtk_p2p_cfg80211_del_beacon( + struct wiphy * wiphy, + struct net_device * dev + ); + +int +mtk_p2p_cfg80211_del_station( + struct wiphy * wiphy, + struct net_device * dev, + u8 * mac + ); + +int +mtk_p2p_cfg80211_set_channel( + IN struct wiphy * wiphy, + IN struct net_device * dev, + IN struct ieee80211_channel * chan, + IN enum nl80211_channel_type channel_type + ); + +int +mtk_p2p_cfg80211_set_bitrate_mask( + IN struct wiphy *wiphy, + IN struct net_device *dev, + IN const u8 *peer, + IN const struct cfg80211_bitrate_mask *mask + ); + + +void +mtk_p2p_cfg80211_mgmt_frame_register( + IN struct wiphy *wiphy, + IN struct net_device *dev, + IN u16 frame_type, + IN bool reg + ); + +#if CONFIG_NL80211_TESTMODE +int +mtk_p2p_cfg80211_testmode_cmd( + IN struct wiphy *wiphy, + IN void *data, + IN int len + ); +#else + #error "Please ENABLE kernel config (CONFIG_NL80211_TESTMODE) to support Wi-Fi Direct" +#endif + +#endif + +/* I/O control handlers */ + +int +mtk_p2p_wext_get_priv ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_reconnect ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_set_auth ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_set_key ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_mlme_handler( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_set_powermode( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_get_powermode( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +/* Private Wireless I/O Controls takes use of iw_handler */ +int +mtk_p2p_wext_set_local_dev_info( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_set_provision_complete( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_start_stop_discovery( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_discovery_results( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_wsc_ie( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_connect_disconnect( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_password_ready( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_request_dev_info( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_invitation_indicate( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_invitation_status( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_set_pm_param ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_set_ps_profile ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_set_network_address ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_set_int ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +/* Private Wireless I/O Controls for IOC_SET_STRUCT/IOC_GET_STRUCT */ +int +mtk_p2p_wext_set_struct ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_get_struct ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +/* IOC_SET_STRUCT/IOC_GET_STRUCT: Service Discovery */ +int +mtk_p2p_wext_get_service_discovery_request ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_get_service_discovery_response ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_send_service_discovery_request ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_send_service_discovery_response ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_terminate_service_discovery_phase ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +#if CFG_SUPPORT_ANTI_PIRACY +int +mtk_p2p_wext_set_sec_check_request ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_get_sec_check_response ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); +#endif + +int +mtk_p2p_wext_set_noa_param ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_set_oppps_param ( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_set_p2p_version( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +int +mtk_p2p_wext_get_p2p_version( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + + +void +mtk_p2p_wext_set_Multicastlist( + IN P_GLUE_INFO_T prGlueInfo + ); + +#if CFG_SUPPORT_P2P_RSSI_QUERY +int +mtk_p2p_wext_get_rssi( + IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra + ); + +struct iw_statistics * +mtk_p2p_wext_get_wireless_stats( + struct net_device *prDev + ); + +#endif + +int +mtk_p2p_wext_set_txpow( + IN struct net_device *prDev, + IN struct iw_request_info *prIwrInfo, + IN OUT union iwreq_data *prTxPow, + IN char *pcExtra + ); + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _GL_P2P_IOCTL_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/include/gl_p2p_kal.h b/drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/include/gl_p2p_kal.h new file mode 100755 index 000000000000..85de7564a080 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/include/gl_p2p_kal.h @@ -0,0 +1,421 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/WIFI_P2P_DRIVER_V2_2/os/linux/include/gl_p2p_kal.h#3 $ +*/ + +/*! \file gl_p2p_kal.h + \brief Declaration of KAL functions for Wi-Fi Direct support + - kal*() which is provided by GLUE Layer. + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: gl_p2p_kal.h $ + * + * 02 14 2012 yuche.tsai + * [ALPS00118350] [ALPS.ICS][WiFi Direct] Dirver update for wifi direct connection + * Replace Beacon/Probe Response IE by driver generating instead of from supplicant. + * + * 01 20 2012 chinglan.wang + * NULL + * Fix the WPA-PSK TKIP and WPA2-PSK AES security mode bug.. + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Hot Spot Tethering for ICS ALPHA testing version. + * + * 10 18 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * New 2.1 branch + + * + * 08 15 2011 yuche.tsai + * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. + * Add group BSSID in invitation request indication. + * The BSSID is used for APP to decide the configure method. + * + * 08 09 2011 yuche.tsai + * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. + * Invitation Feature add on. + * + * 03 19 2011 terry.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 p2p driver release based on label "MT6620_WIFI_P2P_DRIVER_V2_0_2100_0319_2011" from main trunk. + * + * 03 07 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * rename the define to anti_pviracy. + * + * 03 05 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * add the code to get the check rsponse and indicate to app. + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * Add Security check related code. + * + * 12 22 2010 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service Discovery + * 1. header file restructure for more clear module isolation + * 2. add function interface definition for implementing Service Discovery callbacks + * +*/ + +#ifndef _GL_P2P_KAL_H +#define _GL_P2P_KAL_H + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "config.h" +#include "gl_typedef.h" +#include "gl_os.h" +#include "wlan_lib.h" +#include "wlan_oid.h" +#include "wlan_p2p.h" +#include "gl_kal.h" +#include "gl_wext_priv.h" +#include "gl_p2p_ioctl.h" +#include "nic/p2p.h" + + +#if DBG + extern int allocatedMemSize; +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/* Service Discovery */ +VOID +kalP2PIndicateSDRequest( + IN P_GLUE_INFO_T prGlueInfo, + IN PARAM_MAC_ADDRESS rPeerAddr, + IN UINT_8 ucSeqNum + ); + +void +kalP2PIndicateSDResponse( + IN P_GLUE_INFO_T prGlueInfo, + IN PARAM_MAC_ADDRESS rPeerAddr, + IN UINT_8 ucSeqNum + ); + +VOID +kalP2PIndicateTXDone( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_8 ucSeqNum, + IN UINT_8 ucStatus + ); + +/*----------------------------------------------------------------------------*/ +/* Wi-Fi Direct handling */ +/*----------------------------------------------------------------------------*/ +ENUM_PARAM_MEDIA_STATE_T +kalP2PGetState ( + IN P_GLUE_INFO_T prGlueInfo + ); + +VOID +kalP2PSetState ( + IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_PARAM_MEDIA_STATE_T eState, + IN PARAM_MAC_ADDRESS rPeerAddr, + IN UINT_8 ucRole + ); + +VOID +kalP2PUpdateAssocInfo( + IN P_GLUE_INFO_T prGlueInfo, + IN PUINT_8 pucFrameBody, + IN UINT_32 u4FrameBodyLen, + IN BOOLEAN fgReassocRequest + ); + +UINT_32 +kalP2PGetFreqInKHz( + IN P_GLUE_INFO_T prGlueInfo + ); + +UINT_8 +kalP2PGetRole( + IN P_GLUE_INFO_T prGlueInfo + ); + +VOID +kalP2PSetRole( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_8 ucResult, + IN PUINT_8 pucSSID, + IN UINT_8 ucSSIDLen, + IN UINT_8 ucRole + ); + +VOID +kalP2PSetCipher( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_32 u4Cipher + ); + +BOOLEAN +kalP2PGetCipher( + IN P_GLUE_INFO_T prGlueInfo + ); + +BOOLEAN +kalP2PGetTkipCipher( + IN P_GLUE_INFO_T prGlueInfo + ); + + +BOOLEAN +kalP2PGetCcmpCipher( + IN P_GLUE_INFO_T prGlueInfo + ); + + +VOID +kalP2PSetWscMode ( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_8 ucWscMode + ); + +UINT_8 +kalP2PGetWscMode( + IN P_GLUE_INFO_T prGlueInfo + ); + +UINT_16 +kalP2PCalWSC_IELen( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_8 ucType + ); + +VOID +kalP2PGenWSC_IE( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_8 ucType, + IN PUINT_8 pucBuffer + ); + + +VOID +kalP2PUpdateWSC_IE( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_8 ucType, + IN PUINT_8 pucBuffer, + IN UINT_16 u2BufferLength + ); + + + +BOOLEAN +kalP2PIndicateFound( + IN P_GLUE_INFO_T prGlueInfo + ); + +VOID +kalP2PIndicateConnReq( + IN P_GLUE_INFO_T prGlueInfo, + IN PUINT_8 pucDevName, + IN INT_32 u4NameLength, + IN PARAM_MAC_ADDRESS rPeerAddr, + IN UINT_8 ucDevType, /* 0: P2P Device / 1: GC / 2: GO */ + IN INT_32 i4ConfigMethod, + IN INT_32 i4ActiveConfigMethod + ); + +VOID +kalP2PInvitationStatus ( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_32 u4InvStatus + ); + +VOID +kalP2PInvitationIndication( + IN P_GLUE_INFO_T prGlueInfo, + IN P_P2P_DEVICE_DESC_T prP2pDevDesc, + IN PUINT_8 pucSsid, + IN UINT_8 ucSsidLen, + IN UINT_8 ucOperatingChnl, + IN UINT_8 ucInvitationType, + IN PUINT_8 pucGroupBssid + ); + + +struct net_device* +kalP2PGetDevHdlr( + P_GLUE_INFO_T prGlueInfo + ); + +VOID +kalGetChnlList( + IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_BAND_T eSpecificBand, + IN UINT_8 ucMaxChannelNum, + IN PUINT_8 pucNumOfChannel, + IN P_RF_CHANNEL_INFO_T paucChannelList + ); + +#if CFG_SUPPORT_ANTI_PIRACY +VOID +kalP2PIndicateSecCheckRsp( + IN P_GLUE_INFO_T prGlueInfo, + IN PUINT_8 pucRsp, + IN UINT_16 u2RspLen + ); +#endif + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +VOID +kalP2PIndicateChannelReady( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_64 u8SeqNum, + IN UINT_32 u4ChannelNum, + IN ENUM_BAND_T eBand, + IN ENUM_CHNL_EXT_T eSco, + IN UINT_32 u4Duration + ); + +VOID +kalP2PIndicateScanDone( + IN P_GLUE_INFO_T prGlueInfo, + IN BOOLEAN fgIsAbort + ); + +VOID +kalP2PIndicateBssInfo( + IN P_GLUE_INFO_T prGlueInfo, + IN PUINT_8 pucFrameBuf, + IN UINT_32 u4BufLen, + IN P_RF_CHANNEL_INFO_T prChannelInfo, + IN INT_32 i4SignalStrength + ); + +VOID +kalP2PIndicateRxMgmtFrame( + IN P_GLUE_INFO_T prGlueInfo, + IN P_SW_RFB_T prSwRfb + ); + +VOID +kalP2PIndicateMgmtTxStatus( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_64 u8Cookie, + IN BOOLEAN fgIsAck, + IN PUINT_8 pucFrameBuf, + IN UINT_32 u4FrameLen + ); + +VOID +kalP2PIndicateChannelExpired( + IN P_GLUE_INFO_T prGlueInfo, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo + ); + +VOID +kalP2PGCIndicateConnectionStatus( + IN P_GLUE_INFO_T prGlueInfo, + IN P_P2P_CONNECTION_REQ_INFO_T prP2pConnInfo, + IN PUINT_8 pucRxIEBuf, + IN UINT_16 u2RxIELen, + IN UINT_16 u2StatusReason + ); + + +VOID +kalP2PGOStationUpdate( + IN P_GLUE_INFO_T prGlueInfo, + IN P_STA_RECORD_T prCliStaRec, + IN BOOLEAN fgIsNew + ); + + + + + + + + +#endif /* _GL_P2P_KAL_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/include/gl_p2p_os.h b/drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/include/gl_p2p_os.h new file mode 100755 index 000000000000..e37a1270236f --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/p2p/os/linux/include/gl_p2p_os.h @@ -0,0 +1,206 @@ +/* +** $Id: +//Department/DaVinci/TRUNK/MT6620_5931_WiFi_Driver/os/linux/include/gl_p2p_os.h#28 $ +*/ + +/*! \file gl_p2p_os.h + \brief List the external reference to OS for p2p GLUE Layer. + + In this file we define the data structure - GLUE_INFO_T to store those objects + we acquired from OS - e.g. TIMER, SPINLOCK, NET DEVICE ... . And all the + external reference (header file, extern func() ..) to OS for GLUE Layer should + also list down here. +*/ + + +/******************************************************************************* +* Copyright (c) 2010 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + + +#ifndef _GL_P2P_OS_H +#define _GL_P2P_OS_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +struct _GL_P2P_INFO_T { + + /* Device handle */ + struct net_device *prDevHandler; + + #if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + /* cfg80211 */ + struct wireless_dev wdev; + + struct cfg80211_scan_request *prScanRequest; + + UINT_64 u8Cookie; + + /* Generation for station list update. */ + INT_32 i4Generation; + + #endif + + /* Device statistics */ + struct net_device_stats rNetDevStats; + + /* glue layer variables */ + /*move to glueinfo->adapter*/ + // BOOLEAN fgIsRegistered; + UINT_32 u4FreqInKHz; /* frequency */ + UINT_8 ucRole; /* 0: P2P Device, 1: Group Client, 2: Group Owner */ + UINT_8 ucIntent; /* range: 0-15 */ + UINT_8 ucScanMode; /* 0: Search & Listen, 1: Scan without probe response */ + + ENUM_PARAM_MEDIA_STATE_T eState; + UINT_32 u4PacketFilter; + PARAM_MAC_ADDRESS aucMCAddrList[MAX_NUM_GROUP_ADDR]; + + /* connection-requested peer information */ + UINT_8 aucConnReqDevName[32]; + INT_32 u4ConnReqNameLength; + PARAM_MAC_ADDRESS rConnReqPeerAddr; + PARAM_MAC_ADDRESS rConnReqGroupAddr; /* For invitation group. */ + UINT_8 ucConnReqDevType; + INT_32 i4ConnReqConfigMethod; + INT_32 i4ConnReqActiveConfigMethod; + + UINT_32 u4CipherPairwise; + UINT_8 ucWSCRunning; + + UINT_8 aucWSCIE[3][400]; /* 0 for beacon, 1 for probe req, 2 for probe response */ + UINT_16 u2WSCIELen[3]; + + UINT_8 ucOperatingChnl; + UINT_8 ucInvitationType; + + UINT_32 u4InvStatus; + + /* For SET_STRUCT/GET_STRUCT */ + UINT_8 aucOidBuf[4096]; + +#if 1 /* CFG_SUPPORT_ANTI_PIRACY */ + UINT_8 aucSecCheck[256]; + UINT_8 aucSecCheckRsp[256]; +#endif + +}; + + +BOOLEAN +p2pRegisterToWlan( + P_GLUE_INFO_T prGlueInfo + ); + +BOOLEAN +p2pUnregisterToWlan( + P_GLUE_INFO_T prGlueInfo + ); + +BOOLEAN +p2pLaunch( + P_GLUE_INFO_T prGlueInfo + ); + +BOOLEAN +p2pRemove( + P_GLUE_INFO_T prGlueInfo + ); + +BOOLEAN +glRegisterP2P( + P_GLUE_INFO_T prGlueInfo, + const char *prDevName, + BOOLEAN fgIsApMode + ); + +BOOLEAN +glUnregisterP2P( + P_GLUE_INFO_T prGlueInfo + ); + +BOOLEAN +p2pStopImmediate( + P_GLUE_INFO_T prGlueInfo + ); + + + +#endif diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/Makefile b/drivers/mtk_wcn_combo/drv_wlan/wlan/Makefile new file mode 100755 index 000000000000..c5add8fcfd75 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/Makefile @@ -0,0 +1,154 @@ +# Copyright Statement: +# +# This software/firmware and related documentation ("MediaTek Software") are +# protected under relevant copyright laws. The information contained herein +# is confidential and proprietary to MediaTek Inc. and/or its licensors. +# Without the prior written permission of MediaTek inc. and/or its licensors, +# any reproduction, modification, use or disclosure of MediaTek Software, +# and information contained herein, in whole or in part, shall be strictly prohibited. +# +# MediaTek Inc. (C) 2010. All rights reserved. +# +# BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES +# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") +# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON +# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. +# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE +# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR +# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH +# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES +# THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES +# CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK +# SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR +# STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND +# CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, +# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, +# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO +# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +# +# The following software/firmware and/or related documentation ("MediaTek Software") +# have been modified by MediaTek Inc. All revisions are subject to any receiver's +# applicable license agreements with MediaTek Inc. + + +# --------------------------------------------------- +# Compile Options +# --------------------------------------------------- +ccflags-y += -DLINUX -DMT6620 +#for the kernel module inserted issue +ccflags-y += -fno-pic + +#MTK_WAPI_SUPPORT = yes + +ifeq ($(MTK_WAPI_SUPPORT), yes) + ccflags-y += -DCFG_SUPPORT_WAPI=1 +else + ccflags-y += -DCFG_SUPPORT_WAPI=0 +endif + +ifeq ($(HAVE_XLOG_FEATURE), yes) + ccflags-y += -DCFG_SUPPORT_XLOG=1 +else + ccflags-y += -DCFG_SUPPORT_XLOG=0 +endif + +#ifeq ($(CONFIG_MTK_COMBO_WIFI_HIF_SDIO1), y) +# ccflags-y += -D_HIF_SDIO=1 +#endif +ccflags-y += -D_HIF_SDIO=1 + +ccflags-y += -DDBG=0 +#ccflags-y += -DDBG=1 +ccflags-y += -I$(src)/os -I$(src)/os/linux/include -I$(src)/os/linux/hif/sdio/include +ccflags-y += -I$(src)/include -I$(src)/include/nic -I$(src)/include/mgmt + +ccflags-y += -O2 +obj-$(CONFIG_MTK_COMBO_WIFI) += wlan.o + +# --------------------------------------------------- +# Directory List +# --------------------------------------------------- +COMMON_DIR := common/ +OS_DIR := ./os/linux/ +HIF_DIR := os/linux/hif/sdio/ +NIC_DIR := nic/ +MGMT_DIR := mgmt/ +WAPI_DIR :=./os/linux/ + +ifeq ($(MTK_WAPI_SUPPORT), yes) +always := $(shell cp -f $(WAPI_DIR)gl_sec.o.new $(WAPI_DIR)gl_sec.o) +always := $(touch $(OS_DIR)gl_sec.o) +endif +always := $(@echo *********** $$(src)) + + +# --------------------------------------------------- +# Objects List +# --------------------------------------------------- + +COMMON_OBJS := $(COMMON_DIR)dump.o \ + $(COMMON_DIR)wlan_lib.o \ + $(COMMON_DIR)wlan_oid.o \ + $(COMMON_DIR)wlan_bow.o + +NIC_OBJS := $(NIC_DIR)nic.o \ + $(NIC_DIR)nic_tx.o \ + $(NIC_DIR)nic_rx.o \ + $(NIC_DIR)nic_pwr_mgt.o \ + $(NIC_DIR)cmd_buf.o \ + $(NIC_DIR)que_mgt.o \ + $(NIC_DIR)nic_cmd_event.o + +OS_OBJS := $(OS_DIR)gl_init.o \ + $(OS_DIR)gl_kal.o \ + $(OS_DIR)gl_bow.o \ + $(OS_DIR)gl_wext.o \ + $(OS_DIR)gl_wext_priv.o \ + $(OS_DIR)gl_rst.o \ + $(OS_DIR)platform.o + +MGMT_OBJS := $(MGMT_DIR)ais_fsm.o \ + $(MGMT_DIR)aaa_fsm.o \ + $(MGMT_DIR)assoc.o \ + $(MGMT_DIR)auth.o \ + $(MGMT_DIR)bss.o \ + $(MGMT_DIR)cnm.o \ + $(MGMT_DIR)cnm_timer.o \ + $(MGMT_DIR)cnm_mem.o \ + $(MGMT_DIR)hem_mbox.o \ + $(MGMT_DIR)mib.o \ + $(MGMT_DIR)privacy.o \ + $(MGMT_DIR)rate.o \ + $(MGMT_DIR)rlm.o \ + $(MGMT_DIR)rlm_domain.o \ + $(MGMT_DIR)rlm_obss.o \ + $(MGMT_DIR)rlm_protection.o \ + $(MGMT_DIR)rsn.o \ + $(MGMT_DIR)saa_fsm.o \ + $(MGMT_DIR)scan.o \ + $(MGMT_DIR)scan_fsm.o \ + $(MGMT_DIR)sec_fsm.o \ + $(MGMT_DIR)swcr.o \ + $(MGMT_DIR)roaming_fsm.o + +ifeq ($(MTK_WAPI_SUPPORT), yes) +MGMT_OBJS += $(MGMT_DIR)wapi.o +OS_OBJS += $(OS_DIR)gl_sec.o +endif + +ifeq ($(WLAN_PROC), y) +OS_OBJS += gl_proc.o +endif + +HIF_OBJS := $(HIF_DIR)arm.o \ + $(HIF_DIR)sdio.o + +wlan-objs += $(COMMON_OBJS) +wlan-objs += $(NIC_OBJS) +wlan-objs += $(OS_OBJS) +wlan-objs += $(HIF_OBJS) +wlan-objs += $(MGMT_OBJS) + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/common/dump.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/common/dump.c new file mode 100755 index 000000000000..482cf7aacf3a --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/common/dump.c @@ -0,0 +1,583 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/common/dump.c#1 $ +*/ + +/*! \file "dump.c" + \brief Provide memory dump function for debugging. + + Provide memory dump function for debugging. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: dump.c $ + * + * 11 24 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Adjust code for DBG and CONFIG_XLOG. + * + * 11 10 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Using the new XLOG define for dum Memory. + * + * 11 03 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Add dumpMemory8 at XLOG support. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 19:58:51 GMT mtk01426 +** Init develop +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#if DBG +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to dump a segment of memory in bytes. +* +* \param[in] pucStartAddr Pointer to the starting address of the memory to be dumped. +* \param[in] u4Length Length of the memory to be dumped. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +dumpMemory8 ( + IN PUINT_8 pucStartAddr, + IN UINT_32 u4Length + ) +{ + ASSERT(pucStartAddr); + + LOG_FUNC("DUMP8 ADDRESS: %08lx, Length: %ld\n", (UINT_32)pucStartAddr, u4Length); + + while (u4Length > 0) { + if (u4Length >= 16) { + LOG_FUNC("(%08lx) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x %02x\n", + (UINT_32)pucStartAddr, + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3], + pucStartAddr[ 4], pucStartAddr[ 5], pucStartAddr[ 6], pucStartAddr[ 7], + pucStartAddr[ 8], pucStartAddr[ 9], pucStartAddr[10], pucStartAddr[11], + pucStartAddr[12], pucStartAddr[13], pucStartAddr[14], pucStartAddr[15]); + u4Length -= 16; + pucStartAddr += 16; + } + else { + switch (u4Length) { + case 1: + LOG_FUNC("(%08lx) %02x\n", + (UINT_32)pucStartAddr, + pucStartAddr[ 0]); + break; + case 2: + LOG_FUNC("(%08lx) %02x %02x\n", + (UINT_32)pucStartAddr, + pucStartAddr[ 0], pucStartAddr[ 1]); + break; + case 3: + LOG_FUNC("(%08lx) %02x %02x %02x\n", + (UINT_32)pucStartAddr, + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2]); + break; + case 4: + LOG_FUNC("(%08lx) %02x %02x %02x %02x\n", + (UINT_32)pucStartAddr, + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3]); + break; + case 5: + LOG_FUNC("(%08lx) %02x %02x %02x %02x %02x\n", + (UINT_32)pucStartAddr, + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3], + pucStartAddr[ 4]); + break; + case 6: + LOG_FUNC("(%08lx) %02x %02x %02x %02x %02x %02x\n", + (UINT_32)pucStartAddr, + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3], + pucStartAddr[ 4], pucStartAddr[ 5]); + break; + case 7: + LOG_FUNC("(%08lx) %02x %02x %02x %02x %02x %02x %02x\n", + (UINT_32)pucStartAddr, + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3], + pucStartAddr[ 4], pucStartAddr[ 5], pucStartAddr[ 6]); + break; + case 8: + LOG_FUNC("(%08lx) %02x %02x %02x %02x %02x %02x %02x %02x\n", + (UINT_32)pucStartAddr, + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3], + pucStartAddr[ 4], pucStartAddr[ 5], pucStartAddr[ 6], pucStartAddr[ 7]); + break; + case 9: + LOG_FUNC("(%08lx) %02x %02x %02x %02x %02x %02x %02x %02x - %02x\n", + (UINT_32)pucStartAddr, + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3], + pucStartAddr[ 4], pucStartAddr[ 5], pucStartAddr[ 6], pucStartAddr[ 7], + pucStartAddr[ 8]); + break; + case 10: + LOG_FUNC("(%08lx) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x\n", + (UINT_32)pucStartAddr, + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3], + pucStartAddr[ 4], pucStartAddr[ 5], pucStartAddr[ 6], pucStartAddr[ 7], + pucStartAddr[ 8], pucStartAddr[ 9]); + break; + case 11: + LOG_FUNC("(%08lx) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x\n", + (UINT_32)pucStartAddr, + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3], + pucStartAddr[ 4], pucStartAddr[ 5], pucStartAddr[ 6], pucStartAddr[ 7], + pucStartAddr[ 8], pucStartAddr[ 9], pucStartAddr[10]); + break; + case 12: + LOG_FUNC("(%08lx) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x\n", + (UINT_32)pucStartAddr, + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3], + pucStartAddr[ 4], pucStartAddr[ 5], pucStartAddr[ 6], pucStartAddr[ 7], + pucStartAddr[ 8], pucStartAddr[ 9], pucStartAddr[10], pucStartAddr[11]); + break; + case 13: + LOG_FUNC("(%08lx) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x\n", + (UINT_32)pucStartAddr, + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3], + pucStartAddr[ 4], pucStartAddr[ 5], pucStartAddr[ 6], pucStartAddr[ 7], + pucStartAddr[ 8], pucStartAddr[ 9], pucStartAddr[10], pucStartAddr[11], + pucStartAddr[12]); + break; + case 14: + LOG_FUNC("(%08lx) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x\n", + (UINT_32)pucStartAddr, + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3], + pucStartAddr[ 4], pucStartAddr[ 5], pucStartAddr[ 6], pucStartAddr[ 7], + pucStartAddr[ 8], pucStartAddr[ 9], pucStartAddr[10], pucStartAddr[11], + pucStartAddr[12], pucStartAddr[13]); + break; + case 15: + LOG_FUNC("(%08lx) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x\n", + (UINT_32)pucStartAddr, + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3], + pucStartAddr[ 4], pucStartAddr[ 5], pucStartAddr[ 6], pucStartAddr[ 7], + pucStartAddr[ 8], pucStartAddr[ 9], pucStartAddr[10], pucStartAddr[11], + pucStartAddr[12], pucStartAddr[13], pucStartAddr[14]); + break; + default: + break; + } + u4Length = 0; + } + } + + LOG_FUNC("\n"); + + return; +} /* end of dumpMemory8() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to dump a segment of memory in double words. +* +* \param[in] pucStartAddr Pointer to the starting address of the memory to be dumped. +* \param[in] u4Length Length of the memory to be dumped. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +dumpMemory32 ( + IN PUINT_32 pu4StartAddr, + IN UINT_32 u4Length) +{ + PUINT_8 pucAddr; + + + ASSERT(pu4StartAddr); + + LOG_FUNC("DUMP32 ADDRESS: %08lx, Length: %ld\n", (UINT_32)pu4StartAddr, u4Length); + + if (IS_NOT_ALIGN_4((UINT_32)pu4StartAddr)) { + UINT_32 u4ProtrudeLen = sizeof(UINT_32) - ((UINT_32)pu4StartAddr % 4); + + + u4ProtrudeLen = ((u4Length < u4ProtrudeLen) ? u4Length: u4ProtrudeLen); + LOG_FUNC("pu4StartAddr is not at DW boundary.\n"); + pucAddr = (PUINT_8) &pu4StartAddr[0]; + + switch (u4ProtrudeLen) { + case 1: + LOG_FUNC("(%08lx) %02x------\n", + (UINT_32)pu4StartAddr, + pucAddr[0]); + break; + case 2: + LOG_FUNC("(%08lx) %02x%02x----\n", + (UINT_32)pu4StartAddr, + pucAddr[1], pucAddr[0]); + break; + case 3: + LOG_FUNC("(%08lx) %02x%02x%02x--\n", + (UINT_32)pu4StartAddr, + pucAddr[2], pucAddr[1], pucAddr[0]); + break; + default: + break; + } + + u4Length -= u4ProtrudeLen; + pu4StartAddr = (PUINT_32)((UINT_32)pu4StartAddr + u4ProtrudeLen); + } + + while (u4Length > 0) { + if (u4Length >= 16) { + LOG_FUNC("(%08lx) %08lx %08lx %08lx %08lx\n", + (UINT_32)pu4StartAddr, + pu4StartAddr[0], pu4StartAddr[1], pu4StartAddr[2], pu4StartAddr[3]); + pu4StartAddr += 4; + u4Length -= 16; + } + else { + switch (u4Length) { + case 1: + pucAddr = (PUINT_8) &pu4StartAddr[0]; + LOG_FUNC("(%08lx) ------%02x\n", + (UINT_32)pu4StartAddr, + pucAddr[0]); + break; + case 2: + pucAddr = (PUINT_8) &pu4StartAddr[0]; + LOG_FUNC("(%08lx) ----%02x%02x\n", + (UINT_32)pu4StartAddr, + pucAddr[1], pucAddr[0]); + break; + case 3: + pucAddr = (PUINT_8) &pu4StartAddr[0]; + LOG_FUNC("(%08lx) --%02x%02x%02x\n", + (UINT_32)pu4StartAddr, + pucAddr[2], pucAddr[1], pucAddr[0]); + break; + case 4: + LOG_FUNC("(%08lx) %08lx\n", + (UINT_32)pu4StartAddr, + pu4StartAddr[0]); + break; + case 5: + pucAddr = (PUINT_8) &pu4StartAddr[1]; + LOG_FUNC("(%08lx) %08lx ------%02x\n", + (UINT_32)pu4StartAddr, + pu4StartAddr[0], + pucAddr[0]); + break; + case 6: + pucAddr = (PUINT_8) &pu4StartAddr[1]; + LOG_FUNC("(%08lx) %08lx ----%02x%02x\n", + (UINT_32)pu4StartAddr, + pu4StartAddr[0], + pucAddr[1], pucAddr[0]); + break; + case 7: + pucAddr = (PUINT_8) &pu4StartAddr[1]; + LOG_FUNC("(%08lx) %08lx --%02x%02x%02x\n", + (UINT_32)pu4StartAddr, + pu4StartAddr[0], + pucAddr[2], pucAddr[1], pucAddr[0]); + break; + case 8: + LOG_FUNC("(%08lx) %08lx %08lx\n", + (UINT_32)pu4StartAddr, + pu4StartAddr[0], pu4StartAddr[1]); + break; + case 9: + pucAddr = (PUINT_8) &pu4StartAddr[2]; + LOG_FUNC("(%08lx) %08lx %08lx ------%02x\n", + (UINT_32)pu4StartAddr, + pu4StartAddr[0], pu4StartAddr[1], + pucAddr[0]); + break; + case 10: + pucAddr = (PUINT_8) &pu4StartAddr[2]; + LOG_FUNC("(%08lx) %08lx %08lx ----%02x%02x\n", + (UINT_32)pu4StartAddr, + pu4StartAddr[0], pu4StartAddr[1], + pucAddr[1], pucAddr[0]); + break; + case 11: + pucAddr = (PUINT_8) &pu4StartAddr[2]; + LOG_FUNC("(%08lx) %08lx %08lx --%02x%02x%02x\n", + (UINT_32)pu4StartAddr, + pu4StartAddr[0], pu4StartAddr[1], + pucAddr[2], pucAddr[1], pucAddr[0]); + break; + case 12: + LOG_FUNC("(%08lx) %08lx %08lx %08lx\n", + (UINT_32)pu4StartAddr, + pu4StartAddr[0], pu4StartAddr[1], pu4StartAddr[2]); + break; + case 13: + pucAddr = (PUINT_8) &pu4StartAddr[3]; + LOG_FUNC("(%08lx) %08lx %08lx %08lx ------%02x\n", + (UINT_32)pu4StartAddr, + pu4StartAddr[0], pu4StartAddr[1], pu4StartAddr[2], + pucAddr[0]); + break; + case 14: + pucAddr = (PUINT_8) &pu4StartAddr[3]; + LOG_FUNC("(%08lx) %08lx %08lx %08lx ----%02x%02x\n", + (UINT_32)pu4StartAddr, + pu4StartAddr[0], pu4StartAddr[1], pu4StartAddr[2], + pucAddr[1], pucAddr[0]); + break; + case 15: + pucAddr = (PUINT_8) &pu4StartAddr[3]; + LOG_FUNC("(%08lx) %08lx %08lx %08lx --%02x%02x%02x\n", + (UINT_32)pu4StartAddr, + pu4StartAddr[0], pu4StartAddr[1], pu4StartAddr[2], + pucAddr[2], pucAddr[1], pucAddr[0]); + break; + default: + break; + } + u4Length = 0; + } + } + + return; +} /* end of dumpMemory32() */ +#elif CFG_SUPPORT_XLOG + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to dump a segment of memory in bytes. +* +* \param[in] pucStartAddr Pointer to the starting address of the memory to be dumped. +* \param[in] u4Length Length of the memory to be dumped. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +dumpMemory8 ( + IN UINT_32 log_level, + IN PUINT_8 pucStartAddr, + IN UINT_32 u4Length + ) +{ + ASSERT(pucStartAddr); + + if (log_level == ANDROID_LOG_ERROR) { + xlog_printk(ANDROID_LOG_ERROR, XLOG_TAG, "DUMP8 ADDRESS: %08lx, Length: %ld\n", (UINT_32)pucStartAddr, u4Length); + } + else if (log_level == ANDROID_LOG_WARN) { + xlog_printk(ANDROID_LOG_WARN, XLOG_TAG, "DUMP8 ADDRESS: %08lx, Length: %ld\n", (UINT_32)pucStartAddr, u4Length); + } + else if (log_level == ANDROID_LOG_INFO) { + xlog_printk(ANDROID_LOG_INFO, XLOG_TAG, "DUMP8 ADDRESS: %08lx, Length: %ld\n", (UINT_32)pucStartAddr, u4Length); + } + else if (log_level == ANDROID_LOG_DEBUG) { + xlog_printk(ANDROID_LOG_DEBUG, XLOG_TAG, "DUMP8 ADDRESS: %08lx, Length: %ld\n", (UINT_32)pucStartAddr, u4Length); + } + else if (log_level == ANDROID_LOG_VERBOSE) { + xlog_printk(ANDROID_LOG_VERBOSE, XLOG_TAG, "DUMP8 ADDRESS: %08lx, Length: %ld\n", (UINT_32)pucStartAddr, u4Length); + } + + while (u4Length > 0) { + if (u4Length >= 16) { + XLOG_FUNC(log_level, "%02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x %02x\n", + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3], + pucStartAddr[ 4], pucStartAddr[ 5], pucStartAddr[ 6], pucStartAddr[ 7], + pucStartAddr[ 8], pucStartAddr[ 9], pucStartAddr[10], pucStartAddr[11], + pucStartAddr[12], pucStartAddr[13], pucStartAddr[14], pucStartAddr[15]); + u4Length -= 16; + pucStartAddr += 16; + } + else { + switch (u4Length) { + case 1: + XLOG_FUNC(log_level, "%02x\n", + pucStartAddr[ 0]); + break; + case 2: + XLOG_FUNC(log_level, "%02x %02x\n", + pucStartAddr[ 0], pucStartAddr[ 1]); + break; + case 3: + XLOG_FUNC(log_level, "%02x %02x %02x\n", + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2]); + break; + case 4: + XLOG_FUNC(log_level, "%02x %02x %02x %02x\n", + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3]); + break; + case 5: + XLOG_FUNC(log_level, "%02x %02x %02x %02x %02x\n", + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3], + pucStartAddr[ 4]); + break; + case 6: + XLOG_FUNC(log_level, "%02x %02x %02x %02x %02x %02x\n", + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3], + pucStartAddr[ 4], pucStartAddr[ 5]); + break; + case 7: + XLOG_FUNC(log_level, "%02x %02x %02x %02x %02x %02x %02x\n", + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3], + pucStartAddr[ 4], pucStartAddr[ 5], pucStartAddr[ 6]); + break; + case 8: + XLOG_FUNC(log_level, "%02x %02x %02x %02x %02x %02x %02x %02x\n", + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3], + pucStartAddr[ 4], pucStartAddr[ 5], pucStartAddr[ 6], pucStartAddr[ 7]); + break; + case 9: + XLOG_FUNC(log_level, "%02x %02x %02x %02x %02x %02x %02x %02x - %02x\n", + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3], + pucStartAddr[ 4], pucStartAddr[ 5], pucStartAddr[ 6], pucStartAddr[ 7], + pucStartAddr[ 8]); + break; + case 10: + XLOG_FUNC(log_level, "%02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x\n", + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3], + pucStartAddr[ 4], pucStartAddr[ 5], pucStartAddr[ 6], pucStartAddr[ 7], + pucStartAddr[ 8], pucStartAddr[ 9]); + break; + case 11: + XLOG_FUNC(log_level, "%02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x\n", + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3], + pucStartAddr[ 4], pucStartAddr[ 5], pucStartAddr[ 6], pucStartAddr[ 7], + pucStartAddr[ 8], pucStartAddr[ 9], pucStartAddr[10]); + break; + case 12: + XLOG_FUNC(log_level, "%02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x\n", + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3], + pucStartAddr[ 4], pucStartAddr[ 5], pucStartAddr[ 6], pucStartAddr[ 7], + pucStartAddr[ 8], pucStartAddr[ 9], pucStartAddr[10], pucStartAddr[11]); + break; + case 13: + XLOG_FUNC(log_level, "%02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x\n", + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3], + pucStartAddr[ 4], pucStartAddr[ 5], pucStartAddr[ 6], pucStartAddr[ 7], + pucStartAddr[ 8], pucStartAddr[ 9], pucStartAddr[10], pucStartAddr[11], + pucStartAddr[12]); + break; + case 14: + XLOG_FUNC(log_level, "%02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x\n", + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3], + pucStartAddr[ 4], pucStartAddr[ 5], pucStartAddr[ 6], pucStartAddr[ 7], + pucStartAddr[ 8], pucStartAddr[ 9], pucStartAddr[10], pucStartAddr[11], + pucStartAddr[12], pucStartAddr[13]); + break; + case 15: + XLOG_FUNC(log_level, "%02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x\n", + pucStartAddr[ 0], pucStartAddr[ 1], pucStartAddr[ 2], pucStartAddr[ 3], + pucStartAddr[ 4], pucStartAddr[ 5], pucStartAddr[ 6], pucStartAddr[ 7], + pucStartAddr[ 8], pucStartAddr[ 9], pucStartAddr[10], pucStartAddr[11], + pucStartAddr[12], pucStartAddr[13], pucStartAddr[14]); + break; + default: + break; + } + u4Length = 0; + } + } + + + return; +} /* end of dumpMemory8() */ +#endif /* DBG */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/common/wlan_bow.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/common/wlan_bow.c new file mode 100755 index 000000000000..b9f52a7ad5c0 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/common/wlan_bow.c @@ -0,0 +1,3962 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/common/wlan_bow.c#2 $ +*/ + +/*! \file wlan_bow.c + \brief This file contains the 802.11 PAL commands processing routines for + MediaTek Inc. 802.11 Wireless LAN Adapters. +*/ + +/****************************************************************************** +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************* +*/ + +/****************************************************************************** +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************* +*/ + +/* +** $Log: wlan_bow.c $ + * + * 02 16 2012 chinghwa.yu + * [ALPS00238061] [Need Patch] [Volunteer Patch] Support BOW for 5GHz band, remove debug message. + * + * 02 16 2012 chinghwa.yu + * [ALPS00238061] [Need Patch] [Volunteer Patch] Support BOW for 5GHz band. + * + * 01 20 2012 cp.wu + * [ALPS00096191] [MT6620 Wi-Fi][Driver][Firmware] Porting to ALPS4.0_DEV branch + * sync to up-to-date changes including: + * 1. BOW bugfix + * 2. XLOG + * + * 01 15 2012 yuche.tsai + * NULL + * Fix wrong basic rate issue. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 06 29 2011 terry.wu + * NULL + * Add BoW 11n support. + * + * 06 29 2011 terry.wu + * NULL + * Sync BoW code to Trunk. + * + * 06 23 2011 cp.wu + * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module + * follow-ups for frequency-shifted WAPI AP support + * + * 05 25 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * Add BoW Cancel Scan Request and Turn On deactive network function. + * + * 05 23 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * Add some BoW error handling. + * + * 05 22 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * . + * + * 05 22 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * Only reply probe response to its peer or mached SSID for BoW AP. + * + * 05 22 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * Add BoW SAA retry and disable disconnect event when AAA fail . + * + * 05 21 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * Protect BoW connection establishment. + * + * 05 17 2011 terry.wu + * [WCXRP00000730] [MT6620 Wi-Fi][BoW] Send deauth while disconnecting + * Send deauth while disconnecting BoW link. + * + * 05 17 2011 terry.wu + * [WCXRP00000707] [MT6620 Wi-Fi][Driver] Fix BoW Multiple Physical Link connect/disconnect issue + * Fix wrong StaRec state of BoW . + * + * 05 06 2011 terry.wu + * [WCXRP00000707] [MT6620 Wi-Fi][Driver] Fix BoW Multiple Physical Link connect/disconnect issue + * Fix BoW Multiple Physical Link connect/disconnect issue. + * + * 04 29 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Use kalMemAlloc for allocating BOW event temp buffer. + * + * 04 15 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Fix prAssocRspSwRfb casting. + * + * 04 15 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add BOW short range mode. + * + * 04 12 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add WMM IE for BOW initiator data. + * + * 04 10 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Change Link disconnection event procedure for hotspot and change skb length check to 1514 bytes. + * + * 04 09 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Change Link connection event procedure and change skb length check to 1512 bytes. + * + * 03 28 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Simplify link disconnected routine, remove link disconnected other routine. + * + * 03 27 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add new feature - multiple physical link support. + * + * 02 22 2011 wh.su + * [WCXRP00000486] [MT6620 Wi-Fi][BOW] Fixed the bow send frame but not encrypted issue + * fixed the BOW packet sending without encrypted issue. + * + * 02 21 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Fix BOW link disconnection bug. + * + * 02 16 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add bowNotifyAllLinkDisconnected interface and change channel grant procedure for bow starting. + * + * 02 11 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Update BOW channel granted function. + * + * 02 10 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Fix kernel API change issue. + * Before ALPS 2.2 (2.2 included), kfifo_alloc() is + * struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock); + * After ALPS 2.3, kfifo_alloc() is changed to + * int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask); + * + * 02 09 2011 cp.wu + * [WCXRP00000430] [MT6620 Wi-Fi][Firmware][Driver] Create V1.2 branch for MT6620E1 and MT6620E3 + * create V1.2 driver branch based on label MT6620_WIFI_DRIVER_V1_2_110209_1031 + * with BOW and P2P enabled as default + * + * 02 08 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Replace kfifo_get and kfifo_put with kfifo_out and kfifo_in. + * Update BOW get MAC status, remove returning event for AIS network type. + * + * 01 26 2011 cm.chang + * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument + * . + * + * 01 11 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Update BOW Activity Report structure and bug fix. + * + * 01 10 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Update BOW to support multiple physical link. + * + * 12 08 2010 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Support concurrent networks. + * + * 12 07 2010 cm.chang + * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk + * 1. BSSINFO include RLM parameter + * 2. free all sta records when network is disconnected + * + * 11 11 2010 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Fix BoW timer assert issue. + * + * 10 18 2010 chinghwa.yu + * [WCXRP00000110] [MT6620 Wi-Fi] [Driver] Fix BoW Connected event size + * Fix for event returnning Band. + * + * 10 18 2010 chinghwa.yu + * [WCXRP00000110] [MT6620 Wi-Fi] [Driver] Fix BoW Connected event size + * Fix wrong BoW event size. + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by ENUM_NETWORK_TYPE_INDEX_T only + * remove ENUM_NETWORK_TYPE_T definitions + * + * 09 27 2010 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings + * Update BCM/BoW design and settings. + * + * 09 16 2010 chinghwa.yu + * NULL + * Fix bowResponderScanDone error when prBssDesc is NULL. + * + * 09 14 2010 chinghwa.yu + * NULL + * Add bowRunEventAAAComplete. + * + * 09 14 2010 cp.wu + * NULL + * indicate correct AIS network information for PAL. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 08 24 2010 chinghwa.yu + * NULL + * Initialize nicActivateNetwork(prAdapter as soon as bow is starting.. + * + * 08 24 2010 chinghwa.yu + * NULL + * Update BOW for the 1st time. + * + * 08 23 2010 cp.wu + * NULL + * revise constant definitions to be matched with implementation (original cmd-event definition is deprecated) + * + * 07 30 2010 cp.wu + * NULL + * 1) BoW wrapper: use definitions instead of hard-coded constant for error code + * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead + * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames + * + * 07 15 2010 cp.wu + * + * sync. bluetooth-over-Wi-Fi interface to driver interface document v0.2.6. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 25 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add API in que_mgt to retrieve sta-rec index for security frames. + * + * 06 24 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * 1) add timeout handler mechanism for pending command packets + * 2) add p2p add/removal key + * + * 05 13 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add NULL OID implementation for WOL-related OIDs. + * + * 05 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * 1) all BT physical handles shares the same RSSI/Link Quality. + * 2) simplify BT command composing + * + * 04 28 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * change prefix for data structure used to communicate with 802.11 PAL + * to avoid ambiguous naming with firmware interface + * + * 04 27 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add multiple physical link support + * + * 04 14 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * information buffer for query oid/ioctl is now buffered in prCmdInfo + * instead of glue-layer variable to improve multiple oid/ioctl capability + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * 2) command sequence number is now increased atomically + * * 3) private data could be hold and taken use for other purpose +** +*/ + +/****************************************************************************** +* C O M P I L E R F L A G S +******************************************************************************* +*/ + +/****************************************************************************** +* E X T E R N A L R E F E R E N C E S +******************************************************************************* +*/ +#include "precomp.h" + +#if CFG_ENABLE_BT_OVER_WIFI + +#if CFG_BOW_TEST +extern UINT_32 g_arBowRevPalPacketTime[32]; +#endif + + +/****************************************************************************** +* C O N S T A N T S +******************************************************************************* +*/ + +/****************************************************************************** +* D A T A T Y P E S +******************************************************************************* +*/ + +/****************************************************************************** +* P U B L I C D A T A +******************************************************************************* +*/ + +static UINT_32 g_u4LinkCount = 0; +static UINT_32 g_u4Beaconing = 0; +static BOW_TABLE_T arBowTable[CFG_BOW_PHYSICAL_LINK_NUM]; + +/****************************************************************************** +* P R I V A T E D A T A +******************************************************************************* +*/ + +const BOW_CMD_T arBowCmdTable[] = { + {BOW_CMD_ID_GET_MAC_STATUS, bowCmdGetMacStatus}, + {BOW_CMD_ID_SETUP_CONNECTION, bowCmdSetupConnection}, + {BOW_CMD_ID_DESTROY_CONNECTION, bowCmdDestroyConnection}, + {BOW_CMD_ID_SET_PTK, bowCmdSetPTK}, + {BOW_CMD_ID_READ_RSSI, bowCmdReadRSSI}, + {BOW_CMD_ID_READ_LINK_QUALITY, bowCmdReadLinkQuality}, + {BOW_CMD_ID_SHORT_RANGE_MODE, bowCmdShortRangeMode}, + {BOW_CMD_ID_GET_CHANNEL_LIST, bowCmdGetChannelList}, +}; + +/****************************************************************************** +* M A C R O S +******************************************************************************* +*/ + +/****************************************************************************** +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************* +*/ + +/****************************************************************************** +* F U N C T I O N S +******************************************************************************* +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief command packet generation utility +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] ucCID Command ID +* \param[in] fgSetQuery Set or Query +* \param[in] fgNeedResp Need for response +* \param[in] pfCmdDoneHandler Function pointer when command is done +* \param[in] u4SetQueryInfoLen The length of the set/query buffer +* \param[in] pucInfoBuffer Pointer to set/query buffer +* +* +* \retval WLAN_STATUS_PENDING +* \retval WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSendSetQueryBowCmd ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucCID, + IN BOOLEAN fgSetQuery, + IN BOOLEAN fgNeedResp, + IN PFN_CMD_DONE_HANDLER pfCmdDoneHandler, + IN PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, + IN UINT_32 u4SetQueryInfoLen, + IN PUINT_8 pucInfoBuffer, + IN UINT_8 ucSeqNumber + ) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + UINT_8 ucCmdSeqNum; + + ASSERT(prAdapter); + + prGlueInfo = prAdapter->prGlueInfo; + ASSERT(prGlueInfo); + + DBGLOG(REQ, TRACE, ("Command ID = 0x%08X\n", ucCID)); + + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + u4SetQueryInfoLen)); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, ("Allocate CMD_INFO_T ==> FAILED.\n")); + return WLAN_STATUS_FAILURE; + } + + // increase command sequence number + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + DBGLOG(REQ, TRACE, ("ucCmdSeqNum =%d\n", ucCmdSeqNum)); + + // Setup common CMD Info Packet + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->eNetworkType = NETWORK_TYPE_BOW_INDEX; + prCmdInfo->u2InfoBufLen = (UINT_16)(CMD_HDR_SIZE + u4SetQueryInfoLen); + prCmdInfo->pfCmdDoneHandler = pfCmdDoneHandler; + prCmdInfo->pfCmdTimeoutHandler = pfCmdTimeoutHandler; + prCmdInfo->fgIsOid = FALSE; + prCmdInfo->ucCID = ucCID; + prCmdInfo->fgSetQuery = fgSetQuery; + prCmdInfo->fgNeedResp = fgNeedResp; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = u4SetQueryInfoLen; + prCmdInfo->pvInformationBuffer = NULL; + prCmdInfo->u4InformationBufferLength = 0; + prCmdInfo->u4PrivateData = (UINT_32) ucSeqNumber; + + // Setup WIFI_CMD_T (no payload) + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + if(u4SetQueryInfoLen > 0 && pucInfoBuffer != NULL) { + kalMemCopy(prWifiCmd->aucBuffer, pucInfoBuffer, u4SetQueryInfoLen); + } + + // insert into prCmdQueue + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + + // wakeup txServiceThread later + GLUE_SET_EVENT(prGlueInfo); + return WLAN_STATUS_PENDING; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to dispatch command coming from 802.11 PAL +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmd Pointer to the buffer that holds the command +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanbowHandleCommand( + IN P_ADAPTER_T prAdapter, + IN P_AMPC_COMMAND prCmd + ) +{ + WLAN_STATUS retval = WLAN_STATUS_FAILURE; + UINT_16 i; + + ASSERT(prAdapter); + + for (i = 0; i < sizeof(arBowCmdTable) / sizeof(BOW_CMD_T); i++) { + if ((arBowCmdTable[i].uCmdID == prCmd->rHeader.ucCommandId) && + arBowCmdTable[i].pfCmdHandle) { + retval = arBowCmdTable[i].pfCmdHandle(prAdapter, prCmd); + break; + } + } + + return retval; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is command handler for BOW_CMD_ID_GET_MAC_STATUS +* coming from 802.11 PAL +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmd Pointer to the buffer that holds the command +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +bowCmdGetMacStatus( + IN P_ADAPTER_T prAdapter, + IN P_AMPC_COMMAND prCmd + ) +{ + P_AMPC_EVENT prEvent; + P_BOW_MAC_STATUS prMacStatus; + UINT_8 idx = 0; + UINT_8 ucPrimaryChannel; + ENUM_BAND_T eBand; + ENUM_CHNL_EXT_T eBssSCO; + UINT_8 ucNumOfChannel = 0;//MAX_BOW_NUMBER_OF_CHANNEL; + + RF_CHANNEL_INFO_T aucChannelList[MAX_BOW_NUMBER_OF_CHANNEL]; + + ASSERT(prAdapter); + + //3 <1> If LinkCount != 0 -> OK (optional) + + eBand = BAND_2G4; + eBssSCO = CHNL_EXT_SCN; + + // fill event header + prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_MAC_STATUS)), VIR_MEM_TYPE); + + prEvent->rHeader.ucEventId = BOW_EVENT_ID_MAC_STATUS; + prEvent->rHeader.ucSeqNumber = prCmd->rHeader.ucSeqNumber; + prEvent->rHeader.u2PayloadLength = sizeof(BOW_MAC_STATUS); + + // fill event body + prMacStatus = (P_BOW_MAC_STATUS)(prEvent->aucPayload); + kalMemZero(prMacStatus, sizeof(BOW_MAC_STATUS)); + + //3 <2> Call CNM to decide if BOW available. + if (cnmBowIsPermitted(prAdapter)) + { + prMacStatus->ucAvailability = TRUE; + } + else + { + prMacStatus->ucAvailability = FALSE; + } + + memcpy(prMacStatus->aucMacAddr, prAdapter->rWifiVar.aucDeviceAddress, PARAM_MAC_ADDR_LEN); + + if (cnmPreferredChannel(prAdapter, &eBand, &ucPrimaryChannel, &eBssSCO)) + { +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowCmdGetMacStatus, Get preferred channel.\n")); +#endif + + /*printk("bowCmdGetMacStatus, Get preferred channel % x.\n", ucPrimaryChannel);*/ + + prMacStatus->ucNumOfChannel = 1; + prMacStatus->arChannelList[0].ucChannelBand = eBand; + prMacStatus->arChannelList[0].ucChannelNum = ucPrimaryChannel; + } + else + { +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowCmdGetMacStatus, Get channel list. Current number of channel, %d.\n", ucNumOfChannel)); +#endif + + rlmDomainGetChnlList(prAdapter, BAND_2G4, MAX_BOW_NUMBER_OF_CHANNEL_2G4, &ucNumOfChannel, aucChannelList); + + if (ucNumOfChannel > 0) { + for (idx = 0; idx < ucNumOfChannel/*MAX_BOW_NUMBER_OF_CHANNEL_2G4*/; idx++) + { + prMacStatus->arChannelList[idx].ucChannelBand = aucChannelList[idx].eBand; + prMacStatus->arChannelList[idx].ucChannelNum = aucChannelList[idx].ucChannelNum; + } + + prMacStatus->ucNumOfChannel = ucNumOfChannel; + } + + rlmDomainGetChnlList(prAdapter, BAND_5G, MAX_BOW_NUMBER_OF_CHANNEL_5G, &ucNumOfChannel, aucChannelList); + + if (ucNumOfChannel > 0) { + for (idx = 0; idx < ucNumOfChannel/*MAX_BOW_NUMBER_OF_CHANNEL_5G*/; idx++) + { + prMacStatus->arChannelList[prMacStatus->ucNumOfChannel + idx].ucChannelBand = aucChannelList[idx].eBand; + prMacStatus->arChannelList[prMacStatus->ucNumOfChannel + idx].ucChannelNum = aucChannelList[idx].ucChannelNum; + } + + prMacStatus->ucNumOfChannel = prMacStatus->ucNumOfChannel + ucNumOfChannel; + + } + } + + /*printk("prMacStatus->ucNumOfChannel, eBand, prMacStatus->arChannelList, %x, %x, %x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x.\n", + prMacStatus->ucNumOfChannel, + prMacStatus->arChannelList[0].ucChannelBand, + prMacStatus->arChannelList[0].ucChannelNum, + prMacStatus->arChannelList[1].ucChannelNum, + prMacStatus->arChannelList[2].ucChannelNum, + prMacStatus->arChannelList[3].ucChannelNum, + prMacStatus->arChannelList[4].ucChannelNum, + prMacStatus->arChannelList[5].ucChannelNum, + prMacStatus->arChannelList[6].ucChannelNum, + prMacStatus->arChannelList[7].ucChannelNum, + prMacStatus->arChannelList[8].ucChannelNum, + prMacStatus->arChannelList[9].ucChannelNum, + prMacStatus->arChannelList[10].ucChannelNum, + prMacStatus->arChannelList[11].ucChannelNum, + prMacStatus->arChannelList[12].ucChannelNum, + prMacStatus->arChannelList[13].ucChannelNum, + prMacStatus->arChannelList[14].ucChannelNum, + prMacStatus->arChannelList[15].ucChannelNum, + prMacStatus->arChannelList[16].ucChannelNum, + prMacStatus->arChannelList[17].ucChannelNum);*/ + + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("ucNumOfChannel, eBand, aucChannelList, %x, %x, %x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x.\n", + ucNumOfChannel, + aucChannelList[0].eBand, + aucChannelList[0].ucChannelNum, + aucChannelList[1].ucChannelNum, + aucChannelList[2].ucChannelNum, + aucChannelList[3].ucChannelNum, + aucChannelList[4].ucChannelNum, + aucChannelList[5].ucChannelNum, + aucChannelList[6].ucChannelNum, + aucChannelList[7].ucChannelNum, + aucChannelList[8].ucChannelNum, + aucChannelList[9].ucChannelNum, + aucChannelList[10].ucChannelNum, + aucChannelList[11].ucChannelNum, + aucChannelList[12].ucChannelNum, + aucChannelList[13].ucChannelNum, + aucChannelList[14].ucChannelNum, + aucChannelList[15].ucChannelNum, + aucChannelList[16].ucChannelNum, + aucChannelList[17].ucChannelNum)); + + DBGLOG(BOW, EVENT, ("prMacStatus->ucNumOfChannel, eBand, prMacStatus->arChannelList, %x, %x, %x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x.\n", + prMacStatus->ucNumOfChannel, + prMacStatus->arChannelList[0].ucChannelBand, + prMacStatus->arChannelList[0].ucChannelNum, + prMacStatus->arChannelList[1].ucChannelNum, + prMacStatus->arChannelList[2].ucChannelNum, + prMacStatus->arChannelList[3].ucChannelNum, + prMacStatus->arChannelList[4].ucChannelNum, + prMacStatus->arChannelList[5].ucChannelNum, + prMacStatus->arChannelList[6].ucChannelNum, + prMacStatus->arChannelList[7].ucChannelNum, + prMacStatus->arChannelList[8].ucChannelNum, + prMacStatus->arChannelList[9].ucChannelNum, + prMacStatus->arChannelList[10].ucChannelNum, + prMacStatus->arChannelList[11].ucChannelNum, + prMacStatus->arChannelList[12].ucChannelNum, + prMacStatus->arChannelList[13].ucChannelNum, + prMacStatus->arChannelList[14].ucChannelNum, + prMacStatus->arChannelList[15].ucChannelNum, + prMacStatus->arChannelList[16].ucChannelNum, + prMacStatus->arChannelList[17].ucChannelNum)); + + DBGLOG(BOW, EVENT, ("prMacStatus->ucNumOfChannel, %x.\n", prMacStatus->ucNumOfChannel)); + DBGLOG(BOW, EVENT, ("prMacStatus->arChannelList[0].ucChannelBand, %x.\n", prMacStatus->arChannelList[0].ucChannelBand)); + DBGLOG(BOW, EVENT, ("prMacStatus->arChannelList[0].ucChannelNum, %x.\n", prMacStatus->arChannelList[0].ucChannelNum)); + DBGLOG(BOW, EVENT, ("prMacStatus->ucAvailability, %x.\n", prMacStatus->ucAvailability)); + DBGLOG(BOW, EVENT, ("prMacStatus->aucMacAddr, %x:%x:%x:%x:%x:%x.\n", + prMacStatus->aucMacAddr[0], + prMacStatus->aucMacAddr[1], + prMacStatus->aucMacAddr[2], + prMacStatus->aucMacAddr[3], + prMacStatus->aucMacAddr[4], + prMacStatus->aucMacAddr[5])); +#endif + + kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); + + kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_MAC_STATUS))); + + return WLAN_STATUS_SUCCESS; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is command handler for BOW_CMD_ID_SETUP_CONNECTION +* coming from 802.11 PAL +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmd Pointer to the buffer that holds the command +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +bowCmdSetupConnection( + IN P_ADAPTER_T prAdapter, + IN P_AMPC_COMMAND prCmd + ) +{ + P_BOW_SETUP_CONNECTION prBowSetupConnection; + CMD_BT_OVER_WIFI rCmdBtOverWifi; + P_BOW_FSM_INFO_T prBowFsmInfo; + BOW_TABLE_T rBowTable; + + UINT_8 ucBowTableIdx = 0; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + prBowSetupConnection = (P_BOW_SETUP_CONNECTION) &(prCmd->aucPayload[0]); + + // parameter size check + if(prCmd->rHeader.u2PayloadLength != sizeof(BOW_SETUP_CONNECTION)) + { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_INVALID); + return WLAN_STATUS_INVALID_LENGTH; + } + + //3 <1> If ucLinkCount >= 4 -> Fail. + if (g_u4LinkCount >= CFG_BOW_PHYSICAL_LINK_NUM) + { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); + return WLAN_STATUS_NOT_ACCEPTED; + } + + //3 <2> Call CNM, check if BOW is available. + if (!cnmBowIsPermitted(prAdapter)) + { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); + return WLAN_STATUS_NOT_ACCEPTED; + } + + //3 <3> Lookup BOW Table, if Peer MAC address exist and valid -> Fail. + if (bowCheckBowTableIfVaild(prAdapter, prBowSetupConnection->aucPeerAddress)) + { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); + return WLAN_STATUS_NOT_ACCEPTED; + } + + if(EQUAL_MAC_ADDR(prBowSetupConnection->aucPeerAddress, prAdapter->rWifiVar.aucDeviceAddress)) + { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_INVALID); + return WLAN_STATUS_NOT_ACCEPTED; + } + + + // fill CMD_BT_OVER_WIFI + rCmdBtOverWifi.ucAction = BOW_SETUP_CMD; + rCmdBtOverWifi.ucChannelNum = prBowSetupConnection->ucChannelNum; + COPY_MAC_ADDR(rCmdBtOverWifi.rPeerAddr, prBowSetupConnection->aucPeerAddress); + rCmdBtOverWifi.u2BeaconInterval = prBowSetupConnection->u2BeaconInterval; + rCmdBtOverWifi.ucTimeoutDiscovery = prBowSetupConnection->ucTimeoutDiscovery; + rCmdBtOverWifi.ucTimeoutInactivity = prBowSetupConnection->ucTimeoutInactivity; + rCmdBtOverWifi.ucRole = prBowSetupConnection->ucRole; + rCmdBtOverWifi.PAL_Capabilities = prBowSetupConnection->ucPAL_Capabilities; + rCmdBtOverWifi.cMaxTxPower = prBowSetupConnection->cMaxTxPower; + + if (prBowSetupConnection->ucChannelNum > 14) { + rCmdBtOverWifi.ucChannelBand = BAND_5G; + } + else { + rCmdBtOverWifi.ucChannelBand = BAND_2G4; + } + + COPY_MAC_ADDR(prBowFsmInfo->aucPeerAddress, prBowSetupConnection->aucPeerAddress); + +#if CFG_BOW_PHYSICAL_LINK_NUM > 1 + /*Channel check for supporting multiple physical link*/ + if(g_u4LinkCount > 0) { + if (prBowSetupConnection->ucChannelNum != prBowFsmInfo->ucPrimaryChannel) { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); + return WLAN_STATUS_NOT_ACCEPTED; + } + } +#endif + + prBowFsmInfo->ucPrimaryChannel = prBowSetupConnection->ucChannelNum; + prBowFsmInfo->eBand = rCmdBtOverWifi.ucChannelBand; + prBowFsmInfo->u2BeaconInterval = prBowSetupConnection->u2BeaconInterval; + prBowFsmInfo->ucRole = prBowSetupConnection->ucRole; + + if (prBowSetupConnection->ucPAL_Capabilities > 0) + { + prBowFsmInfo->fgSupportQoS = TRUE; + } + + /*printk("bowCmdSetupConnection.\n"); + printk("rCmdBtOverWifi Channel Band - 0x%x.\n", rCmdBtOverWifi.ucChannelBand); + printk("rCmdBtOverWifi Channel Number - 0x%x.\n", rCmdBtOverWifi.ucChannelNum); + printk("rCmdBtOverWifi Peer address - %x:%x:%x:%x:%x:%x.\n", rCmdBtOverWifi.rPeerAddr[0], + rCmdBtOverWifi.rPeerAddr[1], + rCmdBtOverWifi.rPeerAddr[2], + rCmdBtOverWifi.rPeerAddr[3], + rCmdBtOverWifi.rPeerAddr[4], + rCmdBtOverWifi.rPeerAddr[5]); + printk("rCmdBtOverWifi Beacon interval - 0x%x.\n", rCmdBtOverWifi.u2BeaconInterval); + printk("rCmdBtOverWifi Timeout activity - 0x%x.\n", rCmdBtOverWifi.ucTimeoutDiscovery); + printk("rCmdBtOverWifi Timeout inactivity - 0x%x.\n", rCmdBtOverWifi.ucTimeoutInactivity); + printk("rCmdBtOverWifi Role - 0x%x.\n", rCmdBtOverWifi.ucRole); + printk("rCmdBtOverWifi PAL capability - 0x%x.\n", rCmdBtOverWifi.PAL_Capabilities); + printk("rCmdBtOverWifi Max Tx power - 0x%x.\n", rCmdBtOverWifi.cMaxTxPower);*/ + + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowCmdSetupConnection.\n")); + DBGLOG(BOW, EVENT, ("rCmdBtOverWifi Channel Number - 0x%x.\n", rCmdBtOverWifi.ucChannelNum)); + DBGLOG(BOW, EVENT, ("rCmdBtOverWifi Peer address - %x:%x:%x:%x:%x:%x.\n", rCmdBtOverWifi.rPeerAddr[0], + rCmdBtOverWifi.rPeerAddr[1], + rCmdBtOverWifi.rPeerAddr[2], + rCmdBtOverWifi.rPeerAddr[3], + rCmdBtOverWifi.rPeerAddr[4], + rCmdBtOverWifi.rPeerAddr[5])); + DBGLOG(BOW, EVENT, ("rCmdBtOverWifi Beacon interval - 0x%x.\n", rCmdBtOverWifi.u2BeaconInterval)); + DBGLOG(BOW, EVENT, ("rCmdBtOverWifi Timeout activity - 0x%x.\n", rCmdBtOverWifi.ucTimeoutDiscovery)); + DBGLOG(BOW, EVENT, ("rCmdBtOverWifi Timeout inactivity - 0x%x.\n", rCmdBtOverWifi.ucTimeoutInactivity)); + DBGLOG(BOW, EVENT, ("rCmdBtOverWifi Role - 0x%x.\n", rCmdBtOverWifi.ucRole)); + DBGLOG(BOW, EVENT, ("rCmdBtOverWifi PAL capability - 0x%x.\n", rCmdBtOverWifi.PAL_Capabilities)); + DBGLOG(BOW, EVENT, ("rCmdBtOverWifi Max Tx power - 0x%x.\n", rCmdBtOverWifi.cMaxTxPower)); +#endif + + //3 <4> Get a free BOW entry, mark as Valid, fill in Peer MAC address, LinkCount += 1, state == Starting. + if (!bowGetBowTableFreeEntry(prAdapter, &ucBowTableIdx)) + { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); + return WLAN_STATUS_NOT_ACCEPTED; + } + + prBowFsmInfo->prTargetBssDesc = NULL; + + COPY_MAC_ADDR(rBowTable.aucPeerAddress, prBowSetupConnection->aucPeerAddress); + //owTable.eState = BOW_DEVICE_STATE_ACQUIRING_CHANNEL; + rBowTable.fgIsValid = TRUE; + rBowTable.ucAcquireID = prBowFsmInfo->ucSeqNumOfChReq; + //rBowTable.ucRole = prBowSetupConnection->ucRole; + //rBowTable.ucChannelNum = prBowSetupConnection->ucChannelNum; + bowSetBowTableContent(prAdapter, ucBowTableIdx, &rBowTable); + + kalSetBowRole(prAdapter->prGlueInfo, rCmdBtOverWifi.ucRole, prBowSetupConnection->aucPeerAddress); + + GLUE_INC_REF_CNT(g_u4LinkCount); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowStarting, g_u4LinkCount, %x.\n", g_u4LinkCount)); +#endif + + if (g_u4LinkCount == 1) + { +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowStarting, cnmTimerInitTimer.\n")); + DBGLOG(BOW, EVENT, ("prBowFsmInfo->u2BeaconInterval, %d.\n", prBowFsmInfo->u2BeaconInterval)); +#endif + cnmTimerInitTimer(prAdapter, + &prBowFsmInfo->rStartingBeaconTimer, + (PFN_MGMT_TIMEOUT_FUNC)bowSendBeacon, + (UINT_32)NULL); + + cnmTimerInitTimer(prAdapter, + &prBowFsmInfo->rChGrantedTimer, + (PFN_MGMT_TIMEOUT_FUNC)bowChGrantedTimeout, + (UINT_32)NULL); + + //Reset Global Variable + g_u4Beaconing = 0; + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowCmdSetupConnection, g_u4LinkCount, %x.\n", g_u4LinkCount)); + DBGLOG(BOW, EVENT, ("kalInitBowDevice, bow0\n")); +#endif +#if CFG_BOW_SEPARATE_DATA_PATH + kalInitBowDevice(prAdapter->prGlueInfo, BOWDEVNAME); +#endif + + /*Active BoW Network*/ + SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX); + SET_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX); + nicActivateNetwork(prAdapter, NETWORK_TYPE_BOW_INDEX); + + } + + if(rCmdBtOverWifi.ucRole == BOW_INITIATOR) { + bowSetBowTableState(prAdapter, prBowSetupConnection->aucPeerAddress, BOW_DEVICE_STATE_ACQUIRING_CHANNEL); + bowRequestCh(prAdapter); + } else { + bowSetBowTableState(prAdapter, prBowSetupConnection->aucPeerAddress, BOW_DEVICE_STATE_SCANNING); + bowResponderScan(prAdapter); + } + + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_SUCCESS); + + return WLAN_STATUS_SUCCESS; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is command handler for BOW_CMD_ID_DESTROY_CONNECTION +* coming from 802.11 PAL +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmd Pointer to the buffer that holds the command +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +bowCmdDestroyConnection( + IN P_ADAPTER_T prAdapter, + IN P_AMPC_COMMAND prCmd + ) +{ + P_BOW_DESTROY_CONNECTION prBowDestroyConnection; + CMD_BT_OVER_WIFI rCmdBtOverWifi; + P_BOW_FSM_INFO_T prBowFsmInfo; +#if CFG_BOW_TEST + UINT_8 ucIdx; +#endif + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + + //3 <1> If LinkCount == 0 ->Fail (Optional) + if (g_u4LinkCount == 0) + { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); + return WLAN_STATUS_NOT_ACCEPTED; + } + + // parameter size check + if(prCmd->rHeader.u2PayloadLength != sizeof(BOW_DESTROY_CONNECTION)) + { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); + return WLAN_STATUS_INVALID_LENGTH; + } + + //3 <2> Lookup BOW table, check if is not exist (Valid and Peer MAC address) -> Fail + prBowDestroyConnection = (P_BOW_DESTROY_CONNECTION) &(prCmd->aucPayload[0]); + + if (!bowCheckBowTableIfVaild(prAdapter, prBowDestroyConnection->aucPeerAddress)) + { +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowCmdDestroyConnection, bowCheckIfVaild, not accepted.\n")); +#endif + return WLAN_STATUS_NOT_ACCEPTED; + } + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowCmdDestroyConnection, destroy Peer address - %x:%x:%x:%x:%x:%x.\n", prBowDestroyConnection->aucPeerAddress[0], + prBowDestroyConnection->aucPeerAddress[1], + prBowDestroyConnection->aucPeerAddress[2], + prBowDestroyConnection->aucPeerAddress[3], + prBowDestroyConnection->aucPeerAddress[4], + prBowDestroyConnection->aucPeerAddress[5])); +#endif + + // fill CMD_BT_OVER_WIFI + rCmdBtOverWifi.ucAction = 2; + COPY_MAC_ADDR(rCmdBtOverWifi.rPeerAddr, prBowDestroyConnection->aucPeerAddress); + COPY_MAC_ADDR(prBowFsmInfo->aucPeerAddress, prBowDestroyConnection->aucPeerAddress); +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowCmdDestroyConnection, rCmdBtOverWifi.rPeerAddr - %x:%x:%x:%x:%x:%x.\n", rCmdBtOverWifi.rPeerAddr[0], + rCmdBtOverWifi.rPeerAddr[1], + rCmdBtOverWifi.rPeerAddr[2], + rCmdBtOverWifi.rPeerAddr[3], + rCmdBtOverWifi.rPeerAddr[4], + rCmdBtOverWifi.rPeerAddr[5])); +#endif + +#if CFG_BOW_TEST + for (ucIdx = 0; ucIdx < 11; ucIdx++) + { + DBGLOG(BOW, EVENT, ("BoW receiving PAL packet delta time vs packet number -- %d ms vs %x.\n", ucIdx, g_arBowRevPalPacketTime[ucIdx])); + } +#endif + + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_SUCCESS); + + return wlanoidSendSetQueryBowCmd(prAdapter, + CMD_ID_CMD_BT_OVER_WIFI, + TRUE, + FALSE, + wlanbowCmdEventLinkDisconnected, + wlanbowCmdTimeoutHandler, + sizeof(CMD_BT_OVER_WIFI), + (PUINT_8) &rCmdBtOverWifi, + prCmd->rHeader.ucSeqNumber + ); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is command handler for BOW_CMD_ID_SET_PTK +* coming from 802.11 PAL +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmd Pointer to the buffer that holds the command +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +bowCmdSetPTK( + IN P_ADAPTER_T prAdapter, + IN P_AMPC_COMMAND prCmd + ) +{ + P_BOW_SET_PTK prBowSetPTK; + CMD_802_11_KEY rCmdKey; + + ASSERT(prAdapter); + + // parameter size check + if(prCmd->rHeader.u2PayloadLength != sizeof(BOW_SET_PTK)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + prBowSetPTK = (P_BOW_SET_PTK) &(prCmd->aucPayload[0]); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("prBowSetPTK->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", + prBowSetPTK->aucPeerAddress[0], + prBowSetPTK->aucPeerAddress[1], + prBowSetPTK->aucPeerAddress[2], + prBowSetPTK->aucPeerAddress[3], + prBowSetPTK->aucPeerAddress[4], + prBowSetPTK->aucPeerAddress[5])); + + DBGLOG(BOW, EVENT, ("rCmdKey.ucIsAuthenticator, %x.\n", kalGetBowRole(prAdapter->prGlueInfo, prBowSetPTK->aucPeerAddress))); +#endif + + if (!bowCheckBowTableIfVaild(prAdapter, prBowSetPTK->aucPeerAddress)) + { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); + + return WLAN_STATUS_NOT_ACCEPTED; + } + + if (bowGetBowTableState(prAdapter, prBowSetPTK->aucPeerAddress) != BOW_DEVICE_STATE_CONNECTED) + { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_FAILURE); + + return WLAN_STATUS_NOT_ACCEPTED; + } + + // fill CMD_802_11_KEY + rCmdKey.ucAddRemove = 1; // add + rCmdKey.ucTxKey = 1; + rCmdKey.ucKeyType = 1; + rCmdKey.ucIsAuthenticator = kalGetBowRole(prAdapter->prGlueInfo, prBowSetPTK->aucPeerAddress); + COPY_MAC_ADDR(rCmdKey.aucPeerAddr, prBowSetPTK->aucPeerAddress); + rCmdKey.ucNetType = NETWORK_TYPE_BOW_INDEX; // BT Over Wi-Fi + rCmdKey.ucAlgorithmId = CIPHER_SUITE_CCMP; // AES + rCmdKey.ucKeyId = 0; + rCmdKey.ucKeyLen = 16; // AES = 128bit + kalMemCopy(rCmdKey.aucKeyMaterial, prBowSetPTK->aucTemporalKey, 16); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("prBowSetPTK->aucTemporalKey, %x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x.\n", + prBowSetPTK->aucTemporalKey[0], + prBowSetPTK->aucTemporalKey[1], + prBowSetPTK->aucTemporalKey[2], + prBowSetPTK->aucTemporalKey[3], + prBowSetPTK->aucTemporalKey[4], + prBowSetPTK->aucTemporalKey[5], + prBowSetPTK->aucTemporalKey[6], + prBowSetPTK->aucTemporalKey[7], + prBowSetPTK->aucTemporalKey[8], + prBowSetPTK->aucTemporalKey[9], + prBowSetPTK->aucTemporalKey[10], + prBowSetPTK->aucTemporalKey[11], + prBowSetPTK->aucTemporalKey[12], + prBowSetPTK->aucTemporalKey[13], + prBowSetPTK->aucTemporalKey[14], + prBowSetPTK->aucTemporalKey[15])); + + DBGLOG(BOW, EVENT, ("rCmdKey.aucKeyMaterial, %x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x.\n", + rCmdKey.aucKeyMaterial[0], + rCmdKey.aucKeyMaterial[1], + rCmdKey.aucKeyMaterial[2], + rCmdKey.aucKeyMaterial[3], + rCmdKey.aucKeyMaterial[4], + rCmdKey.aucKeyMaterial[5], + rCmdKey.aucKeyMaterial[6], + rCmdKey.aucKeyMaterial[7], + rCmdKey.aucKeyMaterial[8], + rCmdKey.aucKeyMaterial[9], + rCmdKey.aucKeyMaterial[10], + rCmdKey.aucKeyMaterial[11], + rCmdKey.aucKeyMaterial[12], + rCmdKey.aucKeyMaterial[13], + rCmdKey.aucKeyMaterial[14], + rCmdKey.aucKeyMaterial[15])); +#endif + + return wlanoidSendSetQueryBowCmd(prAdapter, + CMD_ID_ADD_REMOVE_KEY, + TRUE, + FALSE, + wlanbowCmdEventSetCommon, + wlanbowCmdTimeoutHandler, + sizeof(CMD_802_11_KEY), + (PUINT_8) &rCmdKey, + prCmd->rHeader.ucSeqNumber + ); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is command handler for BOW_CMD_ID_READ_RSSI +* coming from 802.11 PAL +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmd Pointer to the buffer that holds the command +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +bowCmdReadRSSI( + IN P_ADAPTER_T prAdapter, + IN P_AMPC_COMMAND prCmd + ) +{ + P_BOW_READ_RSSI prBowReadRSSI; + + ASSERT(prAdapter); + + // parameter size check + if(prCmd->rHeader.u2PayloadLength != sizeof(BOW_READ_RSSI)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + prBowReadRSSI = (P_BOW_READ_RSSI) &(prCmd->aucPayload[0]); + + return wlanoidSendSetQueryBowCmd(prAdapter, + CMD_ID_GET_LINK_QUALITY, + FALSE, + TRUE, + wlanbowCmdEventReadRssi, + wlanbowCmdTimeoutHandler, + 0, + NULL, + prCmd->rHeader.ucSeqNumber + ); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is command handler for BOW_CMD_ID_READ_LINK_QUALITY +* coming from 802.11 PAL +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmd Pointer to the buffer that holds the command +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +bowCmdReadLinkQuality( + IN P_ADAPTER_T prAdapter, + IN P_AMPC_COMMAND prCmd + ) +{ + P_BOW_READ_LINK_QUALITY prBowReadLinkQuality; + + ASSERT(prAdapter); + + // parameter size check + if(prCmd->rHeader.u2PayloadLength != sizeof(P_BOW_READ_LINK_QUALITY)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + prBowReadLinkQuality = (P_BOW_READ_LINK_QUALITY) &(prCmd->aucPayload[0]); + + return wlanoidSendSetQueryBowCmd(prAdapter, + CMD_ID_GET_LINK_QUALITY, + FALSE, + TRUE, + wlanbowCmdEventReadLinkQuality, + wlanbowCmdTimeoutHandler, + 0, + NULL, + prCmd->rHeader.ucSeqNumber + ); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is command handler for BOW_CMD_ID_SHORT_RANGE_MODE +* coming from 802.11 PAL +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmd Pointer to the buffer that holds the command +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +bowCmdShortRangeMode( + IN P_ADAPTER_T prAdapter, + IN P_AMPC_COMMAND prCmd + ) +{ + P_BOW_SHORT_RANGE_MODE prBowShortRangeMode; + CMD_TX_PWR_T rTxPwrParam; + + ASSERT(prAdapter); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowCmdShortRangeMode.\n")); +#endif + + prBowShortRangeMode = (P_BOW_SHORT_RANGE_MODE) &(prCmd->aucPayload[0]); + + // parameter size check + if(prCmd->rHeader.u2PayloadLength != sizeof(BOW_SHORT_RANGE_MODE)) { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); + return WLAN_STATUS_INVALID_LENGTH; + } + + if (!bowCheckBowTableIfVaild(prAdapter, prBowShortRangeMode->aucPeerAddress)) + { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); + return WLAN_STATUS_NOT_ACCEPTED; + } + + if (bowGetBowTableState(prAdapter, prBowShortRangeMode->aucPeerAddress) != BOW_DEVICE_STATE_CONNECTED) + { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_FAILURE); + return WLAN_STATUS_NOT_ACCEPTED; + } + + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("prBowShortRangeMode->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", + prBowShortRangeMode->aucPeerAddress[0], + prBowShortRangeMode->aucPeerAddress[1], + prBowShortRangeMode->aucPeerAddress[2], + prBowShortRangeMode->aucPeerAddress[3], + prBowShortRangeMode->aucPeerAddress[4], + prBowShortRangeMode->aucPeerAddress[5])); +#endif + + rTxPwrParam.cTxPwr2G4Cck = (prBowShortRangeMode->cTxPower << 1); + + rTxPwrParam.cTxPwr2G4OFDM_BPSK = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4OFDM_QPSK = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4OFDM_16QAM = (prBowShortRangeMode->cTxPower << 1); + + rTxPwrParam.cTxPwr2G4OFDM_48Mbps = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4OFDM_54Mbps = (prBowShortRangeMode->cTxPower << 1); + + rTxPwrParam.cTxPwr2G4HT20_BPSK = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4HT20_QPSK = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4HT20_16QAM = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4HT20_MCS5 = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4HT20_MCS6 = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4HT20_MCS7 = (prBowShortRangeMode->cTxPower << 1); + + rTxPwrParam.cTxPwr2G4HT40_BPSK = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4HT40_QPSK = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4HT40_16QAM = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4HT40_MCS5 = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4HT40_MCS6 = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4HT40_MCS7 = (prBowShortRangeMode->cTxPower << 1); + + rTxPwrParam.cTxPwr5GOFDM_BPSK = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GOFDM_QPSK = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GOFDM_16QAM = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GOFDM_48Mbps = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GOFDM_54Mbps = (prBowShortRangeMode->cTxPower << 1); + + rTxPwrParam.cTxPwr5GHT20_BPSK = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GHT20_QPSK = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GHT20_16QAM = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GHT20_MCS5 = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GHT20_MCS6 = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GHT20_MCS7 = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GHT40_BPSK = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GHT40_QPSK = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GHT40_16QAM = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GHT40_MCS5 = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GHT40_MCS6 = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GHT40_MCS7 = (prBowShortRangeMode->cTxPower << 1); + + if (nicUpdateTxPower(prAdapter, &rTxPwrParam) == WLAN_STATUS_SUCCESS) + { +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowCmdShortRangeMode, %x.\n", WLAN_STATUS_SUCCESS)); +#endif + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_SUCCESS); + return WLAN_STATUS_SUCCESS; + } + else + { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_FAILURE); + return WLAN_STATUS_FAILURE; + } + +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is command handler for BOW_CMD_ID_GET_CHANNEL_LIST +* coming from 802.11 PAL +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmd Pointer to the buffer that holds the command +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +bowCmdGetChannelList( + IN P_ADAPTER_T prAdapter, + IN P_AMPC_COMMAND prCmd + ) +{ + ASSERT(prAdapter); + + // not supported yet + return WLAN_STATUS_FAILURE; +} + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is generic command done handler +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmdInfo Pointer to the buffer that holds the command info +* \param[in] pucEventBuf Pointer to the set buffer OR event buffer +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanbowCmdEventSetStatus( + IN P_ADAPTER_T prAdapter, + IN P_AMPC_COMMAND prCmd, + IN UINT_8 ucEventBuf + ) +{ + P_AMPC_EVENT prEvent; + P_BOW_COMMAND_STATUS prBowCmdStatus; + + ASSERT(prAdapter); + + // fill event header + prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS)), VIR_MEM_TYPE); + prEvent->rHeader.ucEventId = BOW_EVENT_ID_COMMAND_STATUS; + prEvent->rHeader.ucSeqNumber = prCmd->rHeader.ucSeqNumber; + prEvent->rHeader.u2PayloadLength = sizeof(BOW_COMMAND_STATUS); + + // fill event body + prBowCmdStatus = (P_BOW_COMMAND_STATUS)(prEvent->aucPayload); + kalMemZero(prBowCmdStatus, sizeof(BOW_COMMAND_STATUS)); + + prBowCmdStatus->ucStatus = ucEventBuf; + + kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); + + kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS))); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is generic command done handler +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmdInfo Pointer to the buffer that holds the command info +* \param[in] pucEventBuf Pointer to the set buffer OR event buffer +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanbowCmdEventSetCommon( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + P_AMPC_EVENT prEvent; + P_BOW_COMMAND_STATUS prBowCmdStatus; + + ASSERT(prAdapter); + + // fill event header + prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS)), VIR_MEM_TYPE); + prEvent->rHeader.ucEventId = BOW_EVENT_ID_COMMAND_STATUS; + prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; + prEvent->rHeader.u2PayloadLength = sizeof(BOW_COMMAND_STATUS); + + // fill event body + prBowCmdStatus = (P_BOW_COMMAND_STATUS)(prEvent->aucPayload); + kalMemZero(prBowCmdStatus, sizeof(BOW_COMMAND_STATUS)); + + prBowCmdStatus->ucStatus = BOWCMD_STATUS_SUCCESS; + + kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); + + kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS))); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief command done handler for CMD_ID_CMD_BT_OVER_WIFI +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmdInfo Pointer to the buffer that holds the command info +* \param[in] pucEventBuf Pointer to the set buffer OR event buffer +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanbowCmdEventLinkConnected( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + P_AMPC_EVENT prEvent; + P_BOW_LINK_CONNECTED prBowLinkConnected; + P_BOW_FSM_INFO_T prBowFsmInfo; + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + + // fill event header + prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_LINK_CONNECTED)), VIR_MEM_TYPE); + prEvent->rHeader.ucEventId = BOW_EVENT_ID_LINK_CONNECTED; + prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; + prEvent->rHeader.u2PayloadLength = sizeof(BOW_LINK_CONNECTED); + + // fill event body + prBowLinkConnected = (P_BOW_LINK_CONNECTED)(prEvent->aucPayload); + kalMemZero(prBowLinkConnected, sizeof(BOW_LINK_CONNECTED)); + prBowLinkConnected->rChannel.ucChannelNum = prBssInfo->ucPrimaryChannel; + prBowLinkConnected->rChannel.ucChannelBand = prBssInfo->eBand; + COPY_MAC_ADDR(prBowLinkConnected->aucPeerAddress, prBowFsmInfo->aucPeerAddress); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("prEvent->rHeader.ucEventId, 0x%x\n", prEvent->rHeader.ucEventId)); + DBGLOG(BOW, EVENT, ("prEvent->rHeader.ucSeqNumber, 0x%x\n", prEvent->rHeader.ucSeqNumber)); + DBGLOG(BOW, EVENT, ("prEvent->rHeader.u2PayloadLength, 0x%x\n", prEvent->rHeader.u2PayloadLength)); + DBGLOG(BOW, EVENT, ("prBowLinkConnected->rChannel.ucChannelNum, 0x%x\n", prBowLinkConnected->rChannel.ucChannelNum)); + DBGLOG(BOW, EVENT, ("prBowLinkConnected->rChannel.ucChannelBand, 0x%x\n", prBowLinkConnected->rChannel.ucChannelBand)); + DBGLOG(BOW, EVENT, ("wlanbowCmdEventLinkConnected, prBowFsmInfo->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", + prBowFsmInfo->aucPeerAddress[0], + prBowFsmInfo->aucPeerAddress[1], + prBowFsmInfo->aucPeerAddress[2], + prBowFsmInfo->aucPeerAddress[3], + prBowFsmInfo->aucPeerAddress[4], + prBowFsmInfo->aucPeerAddress[5])); + DBGLOG(BOW, EVENT, ("wlanbowCmdEventLinkConnected, prBowLinkConnected->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", + prBowLinkConnected->aucPeerAddress[0], + prBowLinkConnected->aucPeerAddress[1], + prBowLinkConnected->aucPeerAddress[2], + prBowLinkConnected->aucPeerAddress[3], + prBowLinkConnected->aucPeerAddress[4], + prBowLinkConnected->aucPeerAddress[5])); + DBGLOG(BOW, EVENT, ("wlanbowCmdEventLinkConnected, g_u4LinkCount, %x.\n", g_u4LinkCount)); +#endif + + /*Indicate Event to PAL*/ + kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); + kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_LINK_CONNECTED))); + + /*Release channel if granted*/ + if(prBowFsmInfo->fgIsChannelGranted) { + cnmTimerStopTimer(prAdapter, &prBowFsmInfo->rChGrantedTimer); + //bowReleaseCh(prAdapter); + /*Requested, not granted yet*/ + } else if(prBowFsmInfo->fgIsChannelRequested) { + prBowFsmInfo->fgIsChannelRequested = FALSE; + } + + /* set to connected status*/ + bowSetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress, BOW_DEVICE_STATE_CONNECTED); + +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief command done handler for CMD_ID_CMD_BT_OVER_WIFI +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmdInfo Pointer to the buffer that holds the command info +* \param[in] pucEventBuf Pointer to the set buffer OR event buffer +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanbowCmdEventLinkDisconnected( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + P_AMPC_EVENT prEvent; + P_BOW_LINK_DISCONNECTED prBowLinkDisconnected; + P_BOW_FSM_INFO_T prBowFsmInfo; + BOW_TABLE_T rBowTable; + UINT_8 ucBowTableIdx; + ENUM_BOW_DEVICE_STATE eFsmState; + BOOL fgSendDeauth = FALSE; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + eFsmState = bowGetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress); + + if(eFsmState == BOW_DEVICE_STATE_DISCONNECTED) { + /*do nothing*/ + return; + } + /*Cancel scan*/ + else if(eFsmState == BOW_DEVICE_STATE_SCANNING && + !(prBowFsmInfo->fgIsChannelRequested)) { + bowResponderCancelScan(prAdapter, FALSE); + bowSetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress, BOW_DEVICE_STATE_DISCONNECTING); + return; + } + + // fill event header + prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_LINK_DISCONNECTED)), VIR_MEM_TYPE); + prEvent->rHeader.ucEventId = BOW_EVENT_ID_LINK_DISCONNECTED; + if ((prCmdInfo->u4PrivateData)) + { + prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; + } + else + { + prEvent->rHeader.ucSeqNumber = 0; + } + + prEvent->rHeader.u2PayloadLength = sizeof(BOW_LINK_DISCONNECTED); + + // fill event body + prBowLinkDisconnected = (P_BOW_LINK_DISCONNECTED)(prEvent->aucPayload); + kalMemZero(prBowLinkDisconnected, sizeof(BOW_LINK_DISCONNECTED)); + prBowLinkDisconnected->ucReason = 0x0; + COPY_MAC_ADDR(prBowLinkDisconnected->aucPeerAddress, prBowFsmInfo->aucPeerAddress); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("prEvent->rHeader.ucEventId, 0x%x\n", prEvent->rHeader.ucEventId)); + DBGLOG(BOW, EVENT, ("prEvent->rHeader.ucSeqNumber, 0x%x\n", prEvent->rHeader.ucSeqNumber)); + DBGLOG(BOW, EVENT, ("prEvent->rHeader.u2PayloadLength, 0x%x\n", prEvent->rHeader.u2PayloadLength)); + + DBGLOG(BOW, EVENT, ("wlanbowCmdEventLinkDisconnected, prBowFsmInfo->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", + prBowFsmInfo->aucPeerAddress[0], + prBowFsmInfo->aucPeerAddress[1], + prBowFsmInfo->aucPeerAddress[2], + prBowFsmInfo->aucPeerAddress[3], + prBowFsmInfo->aucPeerAddress[4], + prBowFsmInfo->aucPeerAddress[5])); + + DBGLOG(BOW, EVENT, ("wlanbowCmdEventLinkDisconnected, prBowLinkDisconnected->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", + prBowLinkDisconnected->aucPeerAddress[0], + prBowLinkDisconnected->aucPeerAddress[1], + prBowLinkDisconnected->aucPeerAddress[2], + prBowLinkDisconnected->aucPeerAddress[3], + prBowLinkDisconnected->aucPeerAddress[4], + prBowLinkDisconnected->aucPeerAddress[5])); + + DBGLOG(BOW, EVENT, ("wlanbowCmdEventLinkDisconnected, g_u4LinkCount, %x.\n", g_u4LinkCount)); +#endif + + /*Indicate BoW event to PAL*/ +#if 0 + kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); + kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_LINK_DISCONNECTED))); +#endif + + // set to disconnected status + prBowFsmInfo->prTargetStaRec = cnmGetStaRecByAddress(prAdapter, NETWORK_TYPE_BOW_INDEX, prBowLinkDisconnected->aucPeerAddress); + + /*Release channel if granted*/ + if(prBowFsmInfo->fgIsChannelGranted) { + cnmTimerStopTimer(prAdapter, &prBowFsmInfo->rChGrantedTimer); + bowReleaseCh(prAdapter); + /*Requested, not granted yet*/ + } else if(prBowFsmInfo->fgIsChannelRequested) { + prBowFsmInfo->fgIsChannelRequested = FALSE; + //bowReleaseCh(prAdapter); + } + +#if 1 + /*Send Deauth to connected peer*/ + if (eFsmState == BOW_DEVICE_STATE_CONNECTED && + (prBowFsmInfo->prTargetStaRec->ucStaState == STA_STATE_3)) + { + fgSendDeauth = TRUE; +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("wlanbowCmdEventLinkDisconnected, bowGetBowTableState, %x.\n", bowGetBowTableState(prAdapter, prBowLinkDisconnected->aucPeerAddress))); +#endif + authSendDeauthFrame(prAdapter, + prBowFsmInfo->prTargetStaRec, + (P_SW_RFB_T)NULL, + REASON_CODE_DEAUTH_LEAVING_BSS, + (PFN_TX_DONE_HANDLER)bowDisconnectLink); + } +#endif + +#if 0 + //3 <3>Stop this link; flush Tx; send deAuthentication -> abort. SAA, AAA. need to check BOW table state == Connected. + if (prAdapter->prGlueInfo->i4TxPendingFrameNum > 0) { + kalFlushPendingTxPackets(prAdapter->prGlueInfo); + } + + /* flush pending security frames */ + if (prAdapter->prGlueInfo->i4TxPendingSecurityFrameNum > 0) { + kalClearSecurityFrames(prAdapter->prGlueInfo); + } +#endif + + /*Update BoW table*/ + bowGetBowTableEntryByPeerAddress(prAdapter, prBowLinkDisconnected->aucPeerAddress, &ucBowTableIdx); + rBowTable.fgIsValid = FALSE; + rBowTable.eState = BOW_DEVICE_STATE_DISCONNECTED; + bowSetBowTableContent(prAdapter, ucBowTableIdx, &rBowTable); + + /*Indicate BoW event to PAL*/ + kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); + kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_LINK_DISCONNECTED))); + + /*Decrease link count*/ + GLUE_DEC_REF_CNT(g_u4LinkCount); + + /*If no need to send deauth, DO disconnect now*/ + /*If need to send deauth, DO disconnect at deauth Tx done*/ + if(!fgSendDeauth){ + bowDisconnectLink(prAdapter, NULL, TX_RESULT_SUCCESS); + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief command done handler for CMD_ID_CMD_BT_OVER_WIFI +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmdInfo Pointer to the buffer that holds the command info +* \param[in] pucEventBuf Pointer to the set buffer OR event buffer +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanbowCmdEventSetSetupConnection ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + P_AMPC_EVENT prEvent; + P_BOW_COMMAND_STATUS prBowCmdStatus; + P_WIFI_CMD_T prWifiCmd; + P_CMD_BT_OVER_WIFI prCmdBtOverWifi; + P_BOW_FSM_INFO_T prBowFsmInfo; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + + // restore original command for rPeerAddr + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prCmdBtOverWifi = (P_CMD_BT_OVER_WIFI)(prWifiCmd->aucBuffer); + + // fill event header + prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS)), VIR_MEM_TYPE); + prEvent->rHeader.ucEventId = BOW_EVENT_ID_COMMAND_STATUS; + prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; + prEvent->rHeader.u2PayloadLength = sizeof(BOW_COMMAND_STATUS); + + // fill event body + prBowCmdStatus = (P_BOW_COMMAND_STATUS)(prEvent->aucPayload); + kalMemZero(prBowCmdStatus, sizeof(BOW_COMMAND_STATUS)); + prBowCmdStatus->ucStatus = BOWCMD_STATUS_SUCCESS; + + /*Indicate BoW event to PAL*/ + kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); + kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS))); + + // set to starting status + kalSetBowState(prAdapter->prGlueInfo, + BOW_DEVICE_STATE_STARTING, + prCmdBtOverWifi->rPeerAddr); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is the command done handler for BOW_CMD_ID_READ_LINK_QUALITY +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmdInfo Pointer to the buffer that holds the command info +* \param[in] pucEventBuf Pointer to the set buffer OR event buffer +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanbowCmdEventReadLinkQuality ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + P_EVENT_LINK_QUALITY prLinkQuality; + P_AMPC_EVENT prEvent; + P_BOW_LINK_QUALITY prBowLinkQuality; + + ASSERT(prAdapter); + + prLinkQuality = (P_EVENT_LINK_QUALITY)pucEventBuf; + + // fill event header + prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_LINK_QUALITY)), VIR_MEM_TYPE); + prEvent->rHeader.ucEventId = BOW_EVENT_ID_LINK_QUALITY; + prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; + prEvent->rHeader.u2PayloadLength = sizeof(BOW_LINK_QUALITY); + + // fill event body + prBowLinkQuality = (P_BOW_LINK_QUALITY)(prEvent->aucPayload); + kalMemZero(prBowLinkQuality, sizeof(BOW_LINK_QUALITY)); + prBowLinkQuality->ucLinkQuality = (UINT_8)prLinkQuality->cLinkQuality; + + kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); + + kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_LINK_QUALITY))); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is the command done handler for BOW_CMD_ID_READ_RSSI +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmdInfo Pointer to the buffer that holds the command info +* \param[in] pucEventBuf Pointer to the set buffer OR event buffer +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanbowCmdEventReadRssi ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + P_EVENT_LINK_QUALITY prLinkQuality; + P_AMPC_EVENT prEvent; + P_BOW_RSSI prBowRssi; + + ASSERT(prAdapter); + + prLinkQuality = (P_EVENT_LINK_QUALITY)pucEventBuf; + + // fill event header + prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_LINK_QUALITY)), VIR_MEM_TYPE); + prEvent->rHeader.ucEventId = BOW_EVENT_ID_RSSI; + prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; + prEvent->rHeader.u2PayloadLength = sizeof(BOW_RSSI); + + // fill event body + prBowRssi = (P_BOW_RSSI)(prEvent->aucPayload); + kalMemZero(prBowRssi, sizeof(BOW_RSSI)); + prBowRssi->cRssi = (INT_8) prLinkQuality->cRssi; + + kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); + + kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_LINK_QUALITY))); + +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is the default command timeout handler +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmdInfo Pointer to the buffer that holds the command info +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanbowCmdTimeoutHandler ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo + ) +{ + P_AMPC_EVENT prEvent; + P_BOW_COMMAND_STATUS prBowCmdStatus; + + ASSERT(prAdapter); + + // fill event header + prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS)), VIR_MEM_TYPE); + prEvent->rHeader.ucEventId = BOW_EVENT_ID_COMMAND_STATUS; + prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; + prEvent->rHeader.u2PayloadLength = sizeof(BOW_COMMAND_STATUS); + + // fill event body + prBowCmdStatus = (P_BOW_COMMAND_STATUS)(prEvent->aucPayload); + kalMemZero(prBowCmdStatus, sizeof(BOW_COMMAND_STATUS)); + + prBowCmdStatus->ucStatus = BOWCMD_STATUS_TIMEOUT; // timeout + + kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); + + kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS))); + + return; +} + + +VOID +bowStopping( + IN P_ADAPTER_T prAdapter + ) +{ + P_BOW_FSM_INFO_T prBowFsmInfo; + P_BSS_INFO_T prBowBssInfo; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + prBowBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowStoping.\n")); + DBGLOG(BOW, EVENT, ("bowStoping, SSID %s.\n", prBowBssInfo->aucSSID)); + DBGLOG(BOW, EVENT, ("bowStoping, prBowBssInfo->aucBSSID, %x:%x:%x:%x:%x:%x.\n", + prBowBssInfo->aucBSSID[0], + prBowBssInfo->aucBSSID[1], + prBowBssInfo->aucBSSID[2], + prBowBssInfo->aucBSSID[3], + prBowBssInfo->aucBSSID[4], + prBowBssInfo->aucBSSID[5])); + DBGLOG(BOW, EVENT, ("bowStoping, prBssInfo->aucOwnMacAddr, %x:%x:%x:%x:%x:%x.\n", + prBowBssInfo->aucOwnMacAddr[0], + prBowBssInfo->aucOwnMacAddr[1], + prBowBssInfo->aucOwnMacAddr[2], + prBowBssInfo->aucOwnMacAddr[3], + prBowBssInfo->aucOwnMacAddr[4], + prBowBssInfo->aucOwnMacAddr[5])); + DBGLOG(BOW, EVENT, ("bowStoping, prAdapter->rWifiVar.aucDeviceAddress, %x:%x:%x:%x:%x:%x.\n", + prAdapter->rWifiVar.aucDeviceAddress[0], + prAdapter->rWifiVar.aucDeviceAddress[1], + prAdapter->rWifiVar.aucDeviceAddress[2], + prAdapter->rWifiVar.aucDeviceAddress[3], + prAdapter->rWifiVar.aucDeviceAddress[4], + prAdapter->rWifiVar.aucDeviceAddress[5])); + DBGLOG(BOW, EVENT, ("bowStopping, g_u4LinkCount, %x.\n", g_u4LinkCount)); + DBGLOG(BOW, EVENT, ("prBowFsmInfo->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", prBowFsmInfo->aucPeerAddress[0], + prBowFsmInfo->aucPeerAddress[1], + prBowFsmInfo->aucPeerAddress[2], + prBowFsmInfo->aucPeerAddress[3], + prBowFsmInfo->aucPeerAddress[4], + prBowFsmInfo->aucPeerAddress[5])); + kalPrint("BoW Stoping,[%d,%d]\n", g_u4LinkCount, g_u4Beaconing); +#endif + + if (g_u4LinkCount == 0) + { + /*Stop beaconing*/ + GLUE_DEC_REF_CNT(g_u4Beaconing); + + /*Deactive BoW network*/ + //prBowBssInfo->fgIsNetActive = FALSE; + //prBowBssInfo->fgIsBeaconActivated = FALSE; + nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_BOW_INDEX); + bowChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); + nicUpdateBss(prAdapter, NETWORK_TYPE_BOW_INDEX); + /*temp solution for FW hal_pwr_mgt.c#3037 ASSERT*/ + nicDeactivateNetwork(prAdapter, NETWORK_TYPE_BOW_INDEX); + SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_BOW_INDEX); + UNSET_NET_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX); + + } + + return; +} + + +VOID +bowStarting( + IN P_ADAPTER_T prAdapter + ) +{ + P_BOW_FSM_INFO_T prBowFsmInfo; + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + + if (g_u4LinkCount == 1) + { +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("BoW Starting.\n")); + DBGLOG(BOW, EVENT, ("BoW channel granted.\n")); +#endif + +#if 0 + /*Active BoW Network*/ + SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX); + SET_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX); + nicActivateNetwork(prAdapter, NETWORK_TYPE_BOW_INDEX); +#endif + + //3 <1> Update BSS_INFO_T per Network Basis + //4 <1.1> Setup Operation Mode + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + prBssInfo->ucNetTypeIndex = NETWORK_TYPE_BOW_INDEX; + prBssInfo->eCurrentOPMode = OP_MODE_BOW; + + //4 <1.2> Setup SSID + COPY_MAC_ADDR(prBssInfo->aucOwnMacAddr, prAdapter->rWifiVar.aucDeviceAddress); + COPY_MAC_ADDR(prBssInfo->aucBSSID, prAdapter->rWifiVar.aucDeviceAddress); + prBssInfo->ucSSIDLen = BOW_SSID_LEN; + bowAssignSsid(prBssInfo->aucSSID, prBssInfo->aucOwnMacAddr); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("SSID %s.\n", prBssInfo->aucSSID)); + DBGLOG(BOW, EVENT, ("prBssInfo->aucBSSID, %x:%x:%x:%x:%x:%x.\n", + prBssInfo->aucBSSID[0], + prBssInfo->aucBSSID[1], + prBssInfo->aucBSSID[2], + prBssInfo->aucBSSID[3], + prBssInfo->aucBSSID[4], + prBssInfo->aucBSSID[5])); + DBGLOG(BOW, EVENT, ("prBssInfo->aucOwnMacAddr, %x:%x:%x:%x:%x:%x.\n", + prBssInfo->aucOwnMacAddr[0], + prBssInfo->aucOwnMacAddr[1], + prBssInfo->aucOwnMacAddr[2], + prBssInfo->aucOwnMacAddr[3], + prBssInfo->aucOwnMacAddr[4], + prBssInfo->aucOwnMacAddr[5])); + DBGLOG(BOW, EVENT, ("prAdapter->rWifiVar.aucDeviceAddress, %x:%x:%x:%x:%x:%x.\n", + prAdapter->rWifiVar.aucDeviceAddress[0], + prAdapter->rWifiVar.aucDeviceAddress[1], + prAdapter->rWifiVar.aucDeviceAddress[2], + prAdapter->rWifiVar.aucDeviceAddress[3], + prAdapter->rWifiVar.aucDeviceAddress[4], + prAdapter->rWifiVar.aucDeviceAddress[5])); +#endif + + //4 <1.3> Clear current AP's STA_RECORD_T and current AID + prBssInfo->prStaRecOfAP = (P_STA_RECORD_T)NULL; + prBssInfo->u2AssocId = 0; + + //4 <1.4> Setup Channel, Band and Phy Attributes + prBssInfo->ucPrimaryChannel = prBowFsmInfo->ucPrimaryChannel; + if (prBowFsmInfo->eBand == BAND_2G4) + { + prBssInfo->eBand = BAND_2G4; + } + else + { + prBssInfo->eBand = BAND_5G; + } + +#if CFG_BOW_SUPPORT_11N + prBssInfo->ucPhyTypeSet = prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11BGN; /* Depend on eBand */ + prBssInfo->ucConfigAdHocAPMode = AP_MODE_MIXED_11BG; /* Depend on eCurrentOPMode and ucPhyTypeSet */ + + prBssInfo->ucNonHTBasicPhyType = (UINT_8) + rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode].ePhyTypeIndex; + prBssInfo->u2BSSBasicRateSet = + rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode].u2BSSBasicRateSet; + + prBssInfo->u2OperationalRateSet = + rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType].u2SupportedRateSet; + + rateGetDataRatesFromRateSet(prBssInfo->u2OperationalRateSet, + prBssInfo->u2BSSBasicRateSet, + prBssInfo->aucAllSupportedRates, + &prBssInfo->ucAllSupportedRatesLen); + +#else + if (prBssInfo->eBand == BAND_2G4) + { + prBssInfo->ucPhyTypeSet = PHY_TYPE_SET_802_11BG; /* Depend on eBand */ + prBssInfo->ucConfigAdHocAPMode = AP_MODE_MIXED_11BG; /* Depend on eCurrentOPMode and ucPhyTypeSet */ + + prBssInfo->u2BSSBasicRateSet = BASIC_RATE_SET_ERP; //RATE_SET_ERP; + prBssInfo->u2OperationalRateSet = RATE_SET_ERP; + prBssInfo->ucNonHTBasicPhyType = PHY_TYPE_ERP_INDEX; + } + else + { + //prBssInfo->ucPhyTypeSet = PHY_TYPE_SET_802_11BG; /* Depend on eBand */ + //prBssInfo->ucConfigAdHocAPMode = AP_MODE_MIXED_11BG; /* Depend on eCurrentOPMode and ucPhyTypeSet */ + prBssInfo->ucPhyTypeSet = PHY_TYPE_SET_802_11A; /* Depend on eBand */ + prBssInfo->ucConfigAdHocAPMode = AP_MODE_11A; /* Depend on eCurrentOPMode and ucPhyTypeSet */ + + //prBssInfo->u2BSSBasicRateSet = BASIC_RATE_SET_ERP; //RATE_SET_ERP; + //prBssInfo->u2OperationalRateSet = RATE_SET_ERP; + + prBssInfo->u2BSSBasicRateSet = BASIC_RATE_SET_OFDM; //RATE_SET_ERP; + prBssInfo->u2OperationalRateSet = RATE_SET_OFDM; + prBssInfo->ucNonHTBasicPhyType = PHY_TYPE_OFDM_INDEX; + } + + +#endif + prBssInfo->fgErpProtectMode = FALSE; + + //4 <1.5> Setup MIB for current BSS + prBssInfo->u2BeaconInterval = prBowFsmInfo->u2BeaconInterval; + prBssInfo->ucDTIMPeriod = DOT11_DTIM_PERIOD_DEFAULT; + prBssInfo->u2ATIMWindow = 0; + prBssInfo->ucBeaconTimeoutCount = 0; + if (prBowFsmInfo->fgSupportQoS) + { + prAdapter->rWifiVar.fgSupportQoS = TRUE; + prBssInfo->fgIsQBSS = TRUE; + } + + + //3 <2> Update BSS_INFO_T common part +#if CFG_SUPPORT_AAA + bssInitForAP(prAdapter, prBssInfo, TRUE); + nicQmUpdateWmmParms(prAdapter, NETWORK_TYPE_BOW_INDEX); +#endif /* CFG_SUPPORT_AAA */ + prBssInfo->fgIsNetActive = TRUE; + prBssInfo->fgIsBeaconActivated = TRUE; + + //3 <3> Set MAC HW + + //4 <2> Initiate BSS_INFO_T - common part + BOW_BSS_INFO_INIT(prAdapter, NETWORK_TYPE_BOW_INDEX); +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("prBowFsmInfo->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", prBowFsmInfo->aucPeerAddress[0], + prBowFsmInfo->aucPeerAddress[1], + prBowFsmInfo->aucPeerAddress[2], + prBowFsmInfo->aucPeerAddress[3], + prBowFsmInfo->aucPeerAddress[4], + prBowFsmInfo->aucPeerAddress[5])); +#endif + + //4 <3.1> use command packets to inform firmware + rlmBssInitForAPandIbss(prAdapter, prBssInfo); + nicUpdateBss(prAdapter, NETWORK_TYPE_BOW_INDEX); + + //4 <3.2> Update AdHoc PM parameter + nicPmIndicateBssCreated(prAdapter, NETWORK_TYPE_BOW_INDEX); + + //4 <3.1> Reset HW TSF Update Mode and Beacon Mode + + //4 <3.2> Setup BSSID + // TODO: rxmSetRxFilterBSSID0 +// rxmSetRxFilterBSSID0(prBssInfo->ucHwBssidId, prBssInfo->aucBSSID); + + //4 <3.3> Setup RX Filter to accept Probe Request + // TODO: f get/set RX filter. + +#if 0 + { + UINT_32 u4RxFilter; + if (halMacRxGetRxFilters(&u4RxFilter)== HAL_STATUS_SUCCESS) { + + u4RxFilter &= ~BIT(RXFILTER_DROP_PROBE_REQ); + + halMacRxSetRxFilters(u4RxFilter); + } + } +#endif + } + + /*Update BoW Table*/ + bowSetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress, BOW_DEVICE_STATE_STARTING); + +#if CFG_BOW_TEST + kalPrint("BoW Starting,[%d,%d]\n", g_u4LinkCount, g_u4Beaconing); + DBGLOG(BOW, EVENT, ("bowStarting, g_u4LinkCount, %x.\n", g_u4LinkCount)); +#endif + + /*Start beaconing*/ + if (g_u4Beaconing < 1) + { + GLUE_INC_REF_CNT(g_u4Beaconing); + bssSendBeaconProbeResponse(prAdapter, NETWORK_TYPE_BOW_INDEX, NULL, 0); + cnmTimerStartTimer(prAdapter, &prBowFsmInfo->rStartingBeaconTimer, prBowFsmInfo->u2BeaconInterval); + } + +#if 0 + /*Responder: Start to scan Initiator*/ + if (prBowFsmInfo->ucRole == BOW_RESPONDER) + { +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowStarting responder, start scan result searching.\n")); +#endif + cnmTimerStopTimer(prAdapter, &prBowFsmInfo->rChGrantedTimer); + bowReleaseCh(prAdapter); + bowResponderScan(prAdapter); + } + /*Initiator: Request channel, wait for responder*/ + else { + //bowRequestCh(prAdapter); + } +#endif + return; +} + +VOID +bowAssignSsid ( + IN PUINT_8 pucSsid, + IN PUINT_8 puOwnMacAddr + ) +{ + UINT_8 i; + UINT_8 aucSSID[]=BOW_WILDCARD_SSID; + + kalMemCopy(pucSsid, aucSSID, BOW_WILDCARD_SSID_LEN); + + for (i = 0; i < 6; i++) + { + pucSsid[(3 * i) + 3] = 0x2D; + if ((*(puOwnMacAddr + i) >> 4) < 0xA) + { + *(pucSsid + (3 * i) + 4) = (*(puOwnMacAddr + i) >> 4) + 0x30; + } + else + { + *(pucSsid + (3 * i) + 4) = (*(puOwnMacAddr + i) >> 4) + 0x57; + } + + if ((*(puOwnMacAddr + i) & 0x0F) < 0xA) + { + pucSsid[(3 * i) + 5] = (*(puOwnMacAddr + i) & 0x0F) + 0x30; + } + else + { + pucSsid[(3 * i) + 5] = (*(puOwnMacAddr + i) & 0x0F) + 0x57; + } + } + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will validate the Rx Probe Request Frame and then return +* result to BSS to indicate if need to send the corresponding Probe Response +* Frame if the specified conditions were matched. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[out] pu4ControlFlags Control flags for replying the Probe Response +* +* @retval TRUE Reply the Probe Response +* @retval FALSE Don't reply the Probe Response +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +bowValidateProbeReq( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT PUINT_32 pu4ControlFlags + ) +{ + P_WLAN_MAC_MGMT_HEADER_T prMgtHdr; + P_BOW_FSM_INFO_T prBowFsmInfo; + P_BSS_INFO_T prBssInfo; + P_IE_SSID_T prIeSsid = (P_IE_SSID_T)NULL; + PUINT_8 pucIE; + UINT_16 u2IELength; + UINT_16 u2Offset = 0; + BOOLEAN fgReplyProbeResp = FALSE; + + ASSERT(prSwRfb); + ASSERT(pu4ControlFlags); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + + +#if 0//CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowValidateProbeReq.\n")); +#endif + + //4 <1> Parse Probe Req IE and Get IE ptr (SSID, Supported Rate IE, ...) + prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T)prSwRfb->pvHeader; + + u2IELength = prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen; + pucIE = (PUINT_8)((UINT_32)prSwRfb->pvHeader + prSwRfb->u2HeaderLen); + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + if (ELEM_ID_SSID == IE_ID(pucIE)) { + if ((!prIeSsid) && + (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) { + prIeSsid = (P_IE_SSID_T)pucIE; + } + break; + } + } /* end of IE_FOR_EACH */ + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + if (ELEM_ID_SSID == IE_ID(pucIE)) { + if ((!prIeSsid) && + (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) { + prIeSsid = (P_IE_SSID_T)pucIE; + } + break; + } + } /* end of IE_FOR_EACH */ + + //4 <2> Check network conditions + /*If BoW AP is beaconing*/ + if (prBssInfo->eCurrentOPMode == OP_MODE_BOW && + g_u4Beaconing > 0) { + + /*Check the probe requset sender is our peer*/ + if(bowCheckBowTableIfVaild(prAdapter, prMgtHdr->aucSrcAddr)) { + fgReplyProbeResp = TRUE; + } + /*Check the probe request target SSID is our SSID*/ + else if ((prIeSsid) && + EQUAL_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, + prIeSsid->aucSSID, prIeSsid->ucLength)) { + fgReplyProbeResp = TRUE; + } + else { + fgReplyProbeResp = FALSE; + } + } + + return fgReplyProbeResp; + +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate an Event of "Media Disconnect" to HOST +* +* @param[in] u4Param Unused timer parameter +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +bowSendBeacon( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Param + ) +{ + P_BOW_FSM_INFO_T prBowFsmInfo; + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + + if ((g_u4Beaconing != 0) && (g_u4LinkCount > 0) && (g_u4LinkCount < CFG_BOW_PHYSICAL_LINK_NUM)) + { + //Send beacon + bssSendBeaconProbeResponse(prAdapter, NETWORK_TYPE_BOW_INDEX, NULL, 0); + cnmTimerStartTimer(prAdapter, &prBowFsmInfo->rStartingBeaconTimer, prBowFsmInfo->u2BeaconInterval); + } +#if CFG_BOW_TEST + else { + kalPrint("BoW Send Beacon,[%d,%d]\n", g_u4LinkCount, g_u4Beaconing); + } +#endif +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate an Event of "Media Disconnect" to HOST +* +* @param[in] u4Param Unused timer parameter +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +bowResponderScan( + IN P_ADAPTER_T prAdapter + ) +{ + P_BOW_FSM_INFO_T prBowFsmInfo; + P_MSG_SCN_SCAN_REQ prScanReqMsg; + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowResponderScan.\n")); + kalPrint("BOW SCAN [REQ:%d]\n", prBowFsmInfo->ucSeqNumOfScanReq+1); +#endif + + prScanReqMsg = (P_MSG_SCN_SCAN_REQ)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_REQ)); + + if (!prScanReqMsg) + { + ASSERT(0); // Can't trigger SCAN FSM + return; + } + + /*Fill scan message*/ + prScanReqMsg->rMsgHdr.eMsgId = MID_BOW_SCN_SCAN_REQ; + prScanReqMsg->ucSeqNum = ++prBowFsmInfo->ucSeqNumOfScanReq; + prScanReqMsg->ucNetTypeIndex = (UINT_8)NETWORK_TYPE_BOW_INDEX; + prScanReqMsg->eScanType = SCAN_TYPE_ACTIVE_SCAN; + prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; + prScanReqMsg->ucSSIDLength = BOW_SSID_LEN; + bowAssignSsid(prScanReqMsg->aucSSID, prBowFsmInfo->aucPeerAddress); + prScanReqMsg->ucChannelListNum = 1; + + if (prBowFsmInfo->eBand == BAND_2G4) + { + prScanReqMsg->eScanChannel = SCAN_CHANNEL_SPECIFIED; + prScanReqMsg->arChnlInfoList[0].eBand = BAND_2G4; + } + else + { + prScanReqMsg->eScanChannel = SCAN_CHANNEL_5G; + prScanReqMsg->arChnlInfoList[0].eBand = BAND_5G; + } + + prScanReqMsg->arChnlInfoList[0].ucChannelNum = prBowFsmInfo->ucPrimaryChannel; + prScanReqMsg->u2IELen = 0; + + /*Send scan message*/ + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanReqMsg, MSG_SEND_METHOD_BUF); + + /*Change state to SCANNING*/ + bowSetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress, BOW_DEVICE_STATE_SCANNING); + + //prBowFsmInfo->fgTryScan = FALSE; /* Will enable background sleep for infrastructure */ + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +bowResponderScanDone( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_MSG_SCN_SCAN_DONE prScanDoneMsg; + P_BOW_FSM_INFO_T prBowFsmInfo; + P_BSS_DESC_T prBssDesc; + UINT_8 ucSeqNumOfCompMsg; + P_CONNECTION_SETTINGS_T prConnSettings; + ENUM_BOW_DEVICE_STATE eFsmState; + ENUM_SCAN_STATUS eScanStatus; + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prScanDoneMsg = (P_MSG_SCN_SCAN_DONE) prMsgHdr; + eFsmState = bowGetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress); + + ASSERT(prScanDoneMsg->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX); + + ucSeqNumOfCompMsg = prScanDoneMsg->ucSeqNum; + eScanStatus = prScanDoneMsg->eScanStatus; + + cnmMemFree(prAdapter, prMsgHdr); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowResponderScanDone.\n")); + kalPrint("BOW SCAN [DONE:%d]\n", ucSeqNumOfCompMsg); +#endif + + if( eScanStatus == SCAN_STATUS_CANCELLED) { +#if CFG_BOW_TEST + kalPrint("BOW SCAN [CANCELLED:%d]\n", ucSeqNumOfCompMsg); +#endif + if(eFsmState == BOW_DEVICE_STATE_DISCONNECTING) { + wlanoidSendSetQueryBowCmd(prAdapter, + CMD_ID_CMD_BT_OVER_WIFI, + TRUE, + FALSE, + wlanbowCmdEventLinkDisconnected, + wlanbowCmdTimeoutHandler, + 0, + NULL, + 0 + ); + } + return; + } + else if(eFsmState == BOW_DEVICE_STATE_DISCONNECTED) { + //bowDisconnectLink(prAdapter, NULL, TX_RESULT_SUCCESS); + return; + } + else if (ucSeqNumOfCompMsg != prBowFsmInfo->ucSeqNumOfScanReq) + { + DBGLOG(BOW, EVENT, ("Sequence no. of BOW Responder scan done is not matched.\n")); + return; + } + else + { + prConnSettings->fgIsScanReqIssued = FALSE; + prBssDesc = scanSearchBssDescByBssid(prAdapter, prBowFsmInfo->aucPeerAddress); +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("End scan result searching.\n")); +#endif + + /*Initiator is FOUND*/ + if (prBssDesc != NULL)// (prBssDesc->aucBSSID != NULL)) + { +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("Search Bow Peer address - %x:%x:%x:%x:%x:%x.\n", prBssDesc->aucBSSID[0], + prBssDesc->aucBSSID[1], + prBssDesc->aucBSSID[2], + prBssDesc->aucBSSID[3], + prBssDesc->aucBSSID[4], + prBssDesc->aucBSSID[5])); + DBGLOG(BOW, EVENT, ("Starting to join initiator.\n")); +#endif + /*Set target BssDesc*/ + prBowFsmInfo->prTargetBssDesc = prBssDesc; + /*Request channel to do JOIN*/ + bowSetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress, BOW_DEVICE_STATE_ACQUIRING_CHANNEL); + bowRequestCh(prAdapter); + } + /*Initiator is NOT FOUND*/ + else + { + /*Scan again, until PAL timeout*/ + bowResponderScan(prAdapter); +#if 0 + wlanoidSendSetQueryBowCmd(prAdapter, + CMD_ID_CMD_BT_OVER_WIFI, + TRUE, + FALSE, + wlanbowCmdEventLinkDisconnected, + wlanbowCmdTimeoutHandler, + 0, + NULL, + 0 + ); +#endif + } + } + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Function for cancelling scan request. There is another option to extend channel privilige +* for another purpose. +* +* @param fgIsChannelExtention - Keep the channel previlege, but can cancel scan timer. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +bowResponderCancelScan ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsChannelExtention + ) +{ + + P_MSG_SCN_SCAN_CANCEL prScanCancel = (P_MSG_SCN_SCAN_CANCEL)NULL; + P_BOW_FSM_INFO_T prBowFsmInfo = (P_BOW_FSM_INFO_T)NULL; + + DEBUGFUNC("bowResponderCancelScan()"); + + do { + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + + if (TRUE) { +#if CFG_BOW_TEST + kalPrint("BOW SCAN [CANCEL:%d]\n", prBowFsmInfo->ucSeqNumOfScanReq); +#endif + /* There is a channel privilege on hand. */ + + DBGLOG(P2P, TRACE, ("BOW Cancel Scan\n")); + + prScanCancel = (P_MSG_SCN_SCAN_CANCEL)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_CANCEL)); + if (!prScanCancel) { + /* Buffer not enough, can not cancel scan request. */ + DBGLOG(P2P, TRACE, ("Buffer not enough, can not cancel scan.\n")); + ASSERT(FALSE); + break; + } + + prScanCancel->rMsgHdr.eMsgId = MID_BOW_SCN_SCAN_CANCEL; + prScanCancel->ucNetTypeIndex = NETWORK_TYPE_BOW_INDEX; + prScanCancel->ucSeqNum = prBowFsmInfo->ucSeqNumOfScanReq; +#if CFG_ENABLE_WIFI_DIRECT + prScanCancel->fgIsChannelExt = fgIsChannelExtention; +#endif + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T)prScanCancel, + MSG_SEND_METHOD_BUF); + + } + + } while (FALSE); + +} /* bowResponderCancelScan */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Initialization of JOIN STATE +* +* @param[in] prBssDesc The pointer of BSS_DESC_T which is the BSS we will try to join with. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +bowResponderJoin( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc + ) +{ + P_BOW_FSM_INFO_T prBowFsmInfo; + P_BSS_INFO_T prBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_STA_RECORD_T prStaRec; + P_MSG_JOIN_REQ_T prJoinReqMsg; + + ASSERT(prBssDesc); + ASSERT(prAdapter); + + DBGLOG(BOW, EVENT, ("Starting bowResponderJoin.\n")); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + //4 <1> We are going to connect to this BSS. + prBssDesc->fgIsConnecting = TRUE; + bowSetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress, BOW_DEVICE_STATE_CONNECTING); + + //4 <2> Setup corresponding STA_RECORD_T + /*Support First JOIN and retry*/ + prStaRec = bssCreateStaRecFromBssDesc( + prAdapter, + STA_TYPE_BOW_AP, + NETWORK_TYPE_BOW_INDEX, + prBssDesc); + + prBowFsmInfo->prTargetStaRec = prStaRec; + + //4 <3> Update ucAvailableAuthTypes which we can choice during SAA + prStaRec->fgIsReAssoc = FALSE; + prBowFsmInfo->ucAvailableAuthTypes = (UINT_8)AUTH_TYPE_OPEN_SYSTEM; + prStaRec->ucTxAuthAssocRetryLimit = TX_AUTH_ASSOCI_RETRY_LIMIT; + + + //4 <4> Use an appropriate Authentication Algorithm Number among the ucAvailableAuthTypes + if (prBowFsmInfo->ucAvailableAuthTypes & + (UINT_8)AUTH_TYPE_OPEN_SYSTEM) { + + DBGLOG(BOW, LOUD, ("JOIN INIT: Try to do Authentication with AuthType == OPEN_SYSTEM.\n")); + prBowFsmInfo->ucAvailableAuthTypes &= + ~(UINT_8)AUTH_TYPE_OPEN_SYSTEM; + + prStaRec->ucAuthAlgNum = (UINT_8)AUTH_ALGORITHM_NUM_OPEN_SYSTEM; + } + else { + ASSERT(0); + } + + //4 <4.1> sync. to firmware domain + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + + //4 <5> Overwrite Connection Setting for eConnectionPolicy + if (prBssDesc->ucSSIDLen) { + COPY_SSID(prConnSettings->aucSSID, + prConnSettings->ucSSIDLen, + prBssDesc->aucSSID, + prBssDesc->ucSSIDLen); +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowResponderJoin, SSID %s.\n", prBssDesc->aucSSID)); + DBGLOG(BOW, EVENT, ("bowResponderJoin, SSID %s.\n", prConnSettings->aucSSID)); +#endif + } + + //4 <6> Send a Msg to trigger SAA to start JOIN process. + prJoinReqMsg = (P_MSG_JOIN_REQ_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_REQ_T)); + if (!prJoinReqMsg) { + + ASSERT(0); // Can't trigger SAA FSM + return; + } + + prJoinReqMsg->rMsgHdr.eMsgId = MID_BOW_SAA_FSM_START; + prJoinReqMsg->ucSeqNum = ++prBowFsmInfo->ucSeqNumOfReqMsg; + prJoinReqMsg->prStaRec = prStaRec; + + prBssInfo->prStaRecOfAP = prStaRec; + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("prStaRec->eStaType, %x.\n", prStaRec->eStaType)); + printk("BoW trigger SAA ["MACSTR"]\n", MAC2STR(prStaRec->aucMacAddr)); +#endif + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prJoinReqMsg, + MSG_SEND_METHOD_BUF); + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle the Join Complete Event from SAA FSM for BOW FSM +* +* @param[in] prMsgHdr Message of Join Complete of SAA FSM. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +bowFsmRunEventJoinComplete( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_MSG_JOIN_COMP_T prJoinCompMsg; + P_BOW_FSM_INFO_T prBowFsmInfo; + P_STA_RECORD_T prStaRec; + P_SW_RFB_T prAssocRspSwRfb; + P_BSS_INFO_T prBssInfo; + P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) NULL; + UINT_16 u2IELength; + PUINT_8 pucIE; + P_BSS_INFO_T prBowBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + prJoinCompMsg = (P_MSG_JOIN_COMP_T)prMsgHdr; + prStaRec = prJoinCompMsg->prStaRec; + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("Start bowfsmRunEventJoinComplete.\n")); + DBGLOG(BOW, EVENT, ("bowfsmRunEventJoinComplete ptr check\n")); + DBGLOG(BOW, EVENT, ("prMsgHdr %x\n", prMsgHdr)); + DBGLOG(BOW, EVENT, ("prAdapter %x\n", prAdapter)); + DBGLOG(BOW, EVENT, ("prBowFsmInfo %x\n", prBowFsmInfo)); + DBGLOG(BOW, EVENT, ("prStaRec %x\n", prStaRec)); +#endif + + ASSERT(prStaRec); + ASSERT(prBowFsmInfo); + + // Check SEQ NUM + if (prJoinCompMsg->ucSeqNum == prBowFsmInfo->ucSeqNumOfReqMsg) { + COPY_MAC_ADDR(prBowFsmInfo->aucPeerAddress, prStaRec->aucMacAddr); + + //4 <1> JOIN was successful + if (prJoinCompMsg->rJoinStatus == WLAN_STATUS_SUCCESS) { + prAssocRspSwRfb = prJoinCompMsg->prSwRfb; + prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) prAssocRspSwRfb->pvHeader; + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + + u2IELength = (UINT_16) ((prAssocRspSwRfb->u2PacketLen - prAssocRspSwRfb->u2HeaderLen) - + (OFFSET_OF(WLAN_ASSOC_RSP_FRAME_T, aucInfoElem[0]) - WLAN_MAC_MGMT_HEADER_LEN)); + pucIE = prAssocRspFrame->aucInfoElem; + + prStaRec->eStaType = STA_TYPE_BOW_AP; + prStaRec->u2DesiredNonHTRateSet &= prBowBssInfo->u2OperationalRateSet; + prStaRec->ucDesiredPhyTypeSet = prStaRec->ucPhyTypeSet & prBowBssInfo->ucPhyTypeSet; +#if CFG_BOW_RATE_LIMITATION + //4 <1.2>Update Rate Set + /*Limit Rate Set to 24M, 48M, 54M */ + prStaRec->u2DesiredNonHTRateSet &= (RATE_SET_BIT_24M | + RATE_SET_BIT_48M | + RATE_SET_BIT_54M); + /*If peer cannot support the above rate set, fix on the avaliable highest rate*/ + if(prStaRec->u2DesiredNonHTRateSet == 0) { + UINT_8 ucHighestRateIndex; + if (rateGetHighestRateIndexFromRateSet(prBowBssInfo->u2OperationalRateSet, &ucHighestRateIndex)) { + prStaRec->u2DesiredNonHTRateSet = BIT(ucHighestRateIndex); + } + } +#endif + + //4 <1.1> Change FW's Media State immediately. + bowChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); + + mqmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); + + //4 <1.2> Update HT information and set channel + /* Record HT related parameters in rStaRec and rBssInfo + * Note: it shall be called before nicUpdateBss() + */ +#if CFG_BOW_SUPPORT_11N + rlmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); +#endif + + //4 <1.3> Update BSS_INFO_T + nicUpdateBss(prAdapter, NETWORK_TYPE_BOW_INDEX); +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("Finish bowUpdateBssInfoForJOIN.\n")); +#endif + //4 <1.4> Activate current AP's STA_RECORD_T in Driver. + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowFsmRunEventJoinComplete, qmActivateStaRec.\n")); +#endif + + //4 <1.7> Set the Next State of BOW FSM + wlanoidSendSetQueryBowCmd(prAdapter, + CMD_ID_CMD_BT_OVER_WIFI, + TRUE, + FALSE, + wlanbowCmdEventLinkConnected, + wlanbowCmdTimeoutHandler, + 0, + NULL, + 0 + ); + } + //4 <2> JOIN was not successful + else + { + /*Retry*/ + bowResponderJoin(prAdapter, prBowFsmInfo->prTargetBssDesc); +#if 0 + wlanoidSendSetQueryBowCmd(prAdapter, + CMD_ID_CMD_BT_OVER_WIFI, + TRUE, + FALSE, + wlanbowCmdEventLinkDisconnected, + wlanbowCmdTimeoutHandler, + 0, + NULL, + 0 + ); +#endif +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("Start bowfsmRunEventJoinComplete -- Join failed.\n")); + printk("BoW trigger SAA REJOIN\n"); +#endif + } + } + + cnmMemFree(prAdapter, prMsgHdr); + +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate the Media State to HOST +* +* @param[in] eConnectionState Current Media State +* @param[in] fgDelayIndication Set TRUE for postponing the Disconnect Indication. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +bowIndicationOfMediaStateToHost ( + IN P_ADAPTER_T prAdapter, + IN ENUM_PARAM_MEDIA_STATE_T eConnectionState, + IN BOOLEAN fgDelayIndication + ) +{ + EVENT_CONNECTION_STATUS rEventConnStatus; + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_INFO_T prBssInfo; + P_BOW_FSM_INFO_T prBowFsmInfo; + + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + + // NOTE(Kevin): Move following line to bowChangeMediaState() macro per CM's request. + //prBowBssInfo->eConnectionState = eConnectionState; + + /* For indicating the Disconnect Event only if current media state is + * disconnected and we didn't do indication yet. + */ + if (prBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { + if (prBssInfo->eConnectionStateIndicated == eConnectionState) { + return; + } + } + + if (!fgDelayIndication) { + //4 <0> Cancel Delay Timer + cnmTimerStopTimer(prAdapter, &prBowFsmInfo->rIndicationOfDisconnectTimer); + + //4 <1> Fill EVENT_CONNECTION_STATUS + rEventConnStatus.ucMediaStatus = (UINT_8)eConnectionState; + + if (eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + rEventConnStatus.ucReasonOfDisconnect = DISCONNECT_REASON_CODE_RESERVED; + + if (prBssInfo->eCurrentOPMode == OP_MODE_BOW) { + rEventConnStatus.ucInfraMode = (UINT_8)NET_TYPE_INFRA; + rEventConnStatus.u2AID = prBssInfo->u2AssocId; + rEventConnStatus.u2ATIMWindow = 0; + } + else if (prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { + rEventConnStatus.ucInfraMode = (UINT_8)NET_TYPE_IBSS; + rEventConnStatus.u2AID = 0; + rEventConnStatus.u2ATIMWindow = prBssInfo->u2ATIMWindow; + } + else { + ASSERT(0); + } + + COPY_SSID(rEventConnStatus.aucSsid, + rEventConnStatus.ucSsidLen, + prConnSettings->aucSSID, + prConnSettings->ucSSIDLen); + + COPY_MAC_ADDR(rEventConnStatus.aucBssid, prBssInfo->aucBSSID); + + rEventConnStatus.u2BeaconPeriod = prBssInfo->u2BeaconInterval; + rEventConnStatus.u4FreqInKHz = nicChannelNum2Freq(prBssInfo->ucPrimaryChannel); + + switch (prBssInfo->ucNonHTBasicPhyType) { + case PHY_TYPE_HR_DSSS_INDEX: + rEventConnStatus.ucNetworkType = (UINT_8)PARAM_NETWORK_TYPE_DS; + break; + + case PHY_TYPE_ERP_INDEX: + rEventConnStatus.ucNetworkType = (UINT_8)PARAM_NETWORK_TYPE_OFDM24; + break; + + case PHY_TYPE_OFDM_INDEX: + rEventConnStatus.ucNetworkType = (UINT_8)PARAM_NETWORK_TYPE_OFDM5; + break; + + default: + ASSERT(0); + rEventConnStatus.ucNetworkType = (UINT_8)PARAM_NETWORK_TYPE_DS; + break; + } + } + else { + #if CFG_PRIVACY_MIGRATION + /* Clear the pmkid cache while media disconnect */ + secClearPmkid(prAdapter); + #endif + + rEventConnStatus.ucReasonOfDisconnect = prBssInfo->ucReasonOfDisconnect; + + } + + //4 <2> Indication + nicMediaStateChange(prAdapter, NETWORK_TYPE_BOW_INDEX, &rEventConnStatus); + prBssInfo->eConnectionStateIndicated = eConnectionState; + } + else { + /* NOTE: Only delay the Indication of Disconnect Event */ + ASSERT(eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED); + + DBGLOG(BOW, INFO, ("Postpone the indication of Disconnect for %d seconds\n", + prConnSettings->ucDelayTimeOfDisconnectEvent)); + + cnmTimerStartTimer(prAdapter, + &prBowFsmInfo->rIndicationOfDisconnectTimer, + SEC_TO_MSEC(prConnSettings->ucDelayTimeOfDisconnectEvent)); + } + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indiate the Event of Tx Fail of AAA Module. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +bowRunEventAAATxFail ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ) +{ + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + ASSERT(prStaRec); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowRunEventAAATxFail , bssRemoveStaRecFromClientList.\n")); + printk("BoW AAA TxFail, target state %d\n", prStaRec->ucStaState+1); +#endif + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + bssRemoveStaRecFromClientList(prAdapter, prBssInfo, prStaRec); + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indiate the Event of Successful Completion of AAA Module. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +bowRunEventAAAComplete ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ) +{ + P_BOW_FSM_INFO_T prBowFsmInfo; + + ASSERT(prStaRec); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowRunEventAAAComplete, cnmStaRecChangeState, STA_STATE_3.\n")); + printk("BoW AAA complete ["MACSTR"]\n", MAC2STR(prStaRec->aucMacAddr)); +#endif + + /*Update BssInfo to connected*/ + bowChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); + nicUpdateBss(prAdapter, NETWORK_TYPE_BOW_INDEX); + + /*Update StaRec to State3*/ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + + /*Connected*/ + wlanoidSendSetQueryBowCmd(prAdapter, + CMD_ID_CMD_BT_OVER_WIFI, + TRUE, + FALSE, + wlanbowCmdEventLinkConnected, + wlanbowCmdTimeoutHandler, + 0, + NULL, + 0 + ); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle RxDeauth +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ + +WLAN_STATUS +bowRunEventRxDeAuth ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prSwRfb + ) +{ + P_BSS_INFO_T prBowBssInfo; + P_BOW_FSM_INFO_T prBowFsmInfo; + ENUM_BOW_DEVICE_STATE eFsmState; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + prBowBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + + if(!IS_STA_IN_BOW(prStaRec)) { + return WLAN_STATUS_NOT_ACCEPTED; + } + + eFsmState = bowGetBowTableState(prAdapter, prStaRec->aucMacAddr); + + if(eFsmState == BOW_DEVICE_STATE_DISCONNECTED) { + /*do nothing*/ + return WLAN_STATUS_NOT_ACCEPTED; + } + + if (prStaRec->ucStaState > STA_STATE_1) { + + if (STA_STATE_3 == prStaRec->ucStaState) { + //P_MSG_AIS_ABORT_T prAisAbortMsg; + + /* NOTE(Kevin): Change state immediately to avoid starvation of + * MSG buffer because of too many deauth frames before changing + * the STA state. + */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + } + + COPY_MAC_ADDR(prBowFsmInfo->aucPeerAddress, prStaRec->aucMacAddr); + + wlanoidSendSetQueryBowCmd(prAdapter, + CMD_ID_CMD_BT_OVER_WIFI, + TRUE, + FALSE, + wlanbowCmdEventLinkDisconnected, + wlanbowCmdTimeoutHandler, + 0, + NULL, + 0 + ); + + return WLAN_STATUS_SUCCESS; + } + + return WLAN_STATUS_NOT_ACCEPTED; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function handle BoW Link disconnect. +* +* \param[in] pMsduInfo Pointer to the Msdu Info +* \param[in] rStatus The Tx done status +* +* \return - +* +* \note after receive deauth frame, callback function call this +*/ +/*----------------------------------------------------------------------------*/ +VOID +bowDisconnectLink ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus + ) +{ + P_BOW_FSM_INFO_T prBowFsmInfo; + P_STA_RECORD_T prStaRec; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + + /*Free target StaRec*/ + if(prMsduInfo) { + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + } + else { + prStaRec = prBowFsmInfo->prTargetStaRec; + } + + if(prStaRec) { + //cnmStaRecFree(prAdapter, prStaRec, TRUE); + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + } + kalPrint("bowDisconnectLink\n"); + /*No one connected*/ + if (g_u4LinkCount == 0 && g_u4Beaconing != 0) + { + cnmTimerStopTimer(prAdapter, &prBowFsmInfo->rStartingBeaconTimer); + bowStopping(prAdapter); + kalPrint("bowStopping\n"); + /*Restore TxPower from Short range mode*/ +#if CFG_SUPPORT_NVRAM && 0 + wlanLoadManufactureData(prAdapter, kalGetConfiguration(prAdapter->prGlueInfo)); +#endif + /*Uninit BoW Interface*/ +#if CFG_BOW_SEPARATE_DATA_PATH + kalUninitBowDevice(prAdapter->prGlueInfo); +#endif + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will validate the Rx Assoc Req Frame and then return +* the status code to AAA to indicate if need to perform following actions +* when the specified conditions were matched. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[out] pu2StatusCode The Status Code of Validation Result +* +* @retval TRUE Reply the Assoc Resp +* @retval FALSE Don't reply the Assoc Resp +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +bowValidateAssocReq ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT PUINT_16 pu2StatusCode + ) +{ + BOOLEAN fgReplyAssocResp = FALSE; + P_BSS_INFO_T prBowBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + P_BOW_FSM_INFO_T prBowFsmInfo; + P_WLAN_ASSOC_REQ_FRAME_T prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T)NULL; + OS_SYSTIME rCurrentTime; + static OS_SYSTIME rLastRejectAssocTime = 0; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T) prSwRfb->pvHeader; + *pu2StatusCode = STATUS_CODE_REQ_DECLINED; + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowValidateAssocReq, prBowFsmInfo->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", + prBowFsmInfo->aucPeerAddress[0], + prBowFsmInfo->aucPeerAddress[1], + prBowFsmInfo->aucPeerAddress[2], + prBowFsmInfo->aucPeerAddress[3], + prBowFsmInfo->aucPeerAddress[4], + prBowFsmInfo->aucPeerAddress[5])); + DBGLOG(BOW, EVENT, ("bowValidateAssocReq, prAssocReqFrame->aucSrcAddr, %x:%x:%x:%x:%x:%x.\n", + prAssocReqFrame->aucSrcAddr[0], + prAssocReqFrame->aucSrcAddr[1], + prAssocReqFrame->aucSrcAddr[2], + prAssocReqFrame->aucSrcAddr[3], + prAssocReqFrame->aucSrcAddr[4], + prAssocReqFrame->aucSrcAddr[5])); +#endif + + /*Assoc Accept*/ + while(EQUAL_MAC_ADDR(prAssocReqFrame->aucSrcAddr, prBowFsmInfo->aucPeerAddress)) { +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowValidateAssocReq, return wlanbowCmdEventLinkConnected.\n")); +#endif + /*Update StaRec*/ + prStaRec = cnmGetStaRecByAddress(prAdapter, + (UINT_8) NETWORK_TYPE_BOW_INDEX, + prAssocReqFrame->aucSrcAddr); + prStaRec->eStaType = STA_TYPE_BOW_CLIENT; + prStaRec->u2DesiredNonHTRateSet &= prBowBssInfo->u2OperationalRateSet; + prStaRec->ucDesiredPhyTypeSet = prStaRec->ucPhyTypeSet & prBowBssInfo->ucPhyTypeSet; + +#if CFG_BOW_RATE_LIMITATION + /*Limit Rate Set to 24M, 48M, 54M */ + prStaRec->u2DesiredNonHTRateSet &= (RATE_SET_BIT_24M | + RATE_SET_BIT_48M | + RATE_SET_BIT_54M); + /*If peer cannot support the above rate set, fix on the avaliable highest rate*/ + if(prStaRec->u2DesiredNonHTRateSet == 0) { + UINT_8 ucHighestRateIndex; + if (rateGetHighestRateIndexFromRateSet(prBowBssInfo->u2OperationalRateSet, &ucHighestRateIndex)) { + prStaRec->u2DesiredNonHTRateSet = BIT(ucHighestRateIndex); + } else { + /*If no avaliable rate is found, DECLINE the association*/ + *pu2StatusCode = STATUS_CODE_ASSOC_DENIED_RATE_NOT_SUPPORTED; + break; + } + } +#endif + prStaRec->ucNetTypeIndex = NETWORK_TYPE_BOW_INDEX; + + /*Undpate BssInfo to FW*/ + bowChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); + nicUpdateBss(prAdapter, NETWORK_TYPE_BOW_INDEX); + + /*reply successful*/ + *pu2StatusCode = STATUS_CODE_SUCCESSFUL; + fgReplyAssocResp = TRUE; + break; + } + + /*Reject Assoc*/ + if(*pu2StatusCode != STATUS_CODE_SUCCESSFUL) { + /*Reply Assoc with reject every 5s*/ + rCurrentTime = kalGetTimeTick(); + if(CHECK_FOR_TIMEOUT(rCurrentTime, rLastRejectAssocTime, MSEC_TO_SYSTIME(5000)) || + rLastRejectAssocTime == 0 + ) { + fgReplyAssocResp = TRUE; + rLastRejectAssocTime = rCurrentTime; + } + } + + return fgReplyAssocResp; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will validate the Rx Auth Frame and then return +* the status code to AAA to indicate if need to perform following actions +* when the specified conditions were matched. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[in] pprStaRec Pointer to pointer of STA_RECORD_T structure. +* @param[out] pu2StatusCode The Status Code of Validation Result +* +* @retval TRUE Reply the Auth +* @retval FALSE Don't reply the Auth +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +bowValidateAuth ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN PP_STA_RECORD_T pprStaRec, + OUT PUINT_16 pu2StatusCode + ) +{ + BOOLEAN fgReplyAuth = FALSE; + P_BSS_INFO_T prBowBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + P_BOW_FSM_INFO_T prBowFsmInfo; + P_WLAN_AUTH_FRAME_T prAuthFrame = (P_WLAN_AUTH_FRAME_T)NULL; + OS_SYSTIME rCurrentTime; + static OS_SYSTIME rLastRejectAuthTime = 0; + + /* TODO(Kevin): Call BoW functions to check .. + 1. Check we are BoW now. + 2. Check we can accept connection from thsi peer + 3. Check Black List here. + */ + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowValidateAuth, prBowFsmInfo->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", + prBowFsmInfo->aucPeerAddress[0], + prBowFsmInfo->aucPeerAddress[1], + prBowFsmInfo->aucPeerAddress[2], + prBowFsmInfo->aucPeerAddress[3], + prBowFsmInfo->aucPeerAddress[4], + prBowFsmInfo->aucPeerAddress[5])); + DBGLOG(BOW, EVENT, ("bowValidateAuth, prAuthFrame->aucSrcAddr, %x:%x:%x:%x:%x:%x.\n", + prAuthFrame->aucSrcAddr[0], + prAuthFrame->aucSrcAddr[1], + prAuthFrame->aucSrcAddr[2], + prAuthFrame->aucSrcAddr[3], + prAuthFrame->aucSrcAddr[4], + prAuthFrame->aucSrcAddr[5])); +#endif + + prStaRec = cnmGetStaRecByAddress(prAdapter, + (UINT_8) NETWORK_TYPE_BOW_INDEX, + prAuthFrame->aucSrcAddr); + if (!prStaRec) { +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowValidateAuth, cnmStaRecAlloc.\n")); +#endif + prStaRec = cnmStaRecAlloc(prAdapter, + (UINT_8) NETWORK_TYPE_BOW_INDEX); + + /* TODO(Kevin): Error handling of allocation of STA_RECORD_T for + * exhausted case and do removal of unused STA_RECORD_T. + */ + ASSERT(prStaRec); + COPY_MAC_ADDR(prStaRec->aucMacAddr, prAuthFrame->aucSrcAddr); + prSwRfb->ucStaRecIdx = prStaRec->ucIndex; + prBowBssInfo->prStaRecOfAP = prStaRec; + + /* NOTE(Kevin): Better to change state here, not at TX Done */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowValidateAuth, cnmStaRecChangeState.\n")); +#endif + } + else + { + prSwRfb->ucStaRecIdx = prStaRec->ucIndex; +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowValidateAuth, prStaRec->ucIndex, %x.\n", prStaRec->ucIndex)); +#endif + bssRemoveStaRecFromClientList(prAdapter, prBowBssInfo, prStaRec); + } + + if (EQUAL_MAC_ADDR(prAuthFrame->aucSrcAddr, prBowFsmInfo->aucPeerAddress)) { + + prStaRec->eStaType = STA_TYPE_BOW_CLIENT; + prStaRec->ucNetTypeIndex = NETWORK_TYPE_BOW_INDEX; +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowValidateAuth, prStaRec->eStaType, %x.\n", prStaRec->eStaType)); + DBGLOG(BOW, EVENT, ("bowValidateAuth, prStaRec->ucNetTypeIndex, %x.\n", prStaRec->ucNetTypeIndex)); +#endif + /* Update Station Record - Status/Reason Code */ + prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; + prStaRec->ucJoinFailureCount = 0; + *pprStaRec = prStaRec; + *pu2StatusCode = STATUS_CODE_SUCCESSFUL; + fgReplyAuth = TRUE; + } + else { + cnmStaRecFree(prAdapter, prStaRec, FALSE); + *pu2StatusCode = STATUS_CODE_REQ_DECLINED; + + /*Reply auth with reject every 5s*/ + rCurrentTime = kalGetTimeTick(); + if(CHECK_FOR_TIMEOUT(rCurrentTime, rLastRejectAuthTime, MSEC_TO_SYSTIME(5000)) || + rLastRejectAuthTime == 0 + ) { + fgReplyAuth = TRUE; + rLastRejectAuthTime = rCurrentTime; + } + } + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowValidateAuth, fgReplyAuth, %x.\n", fgReplyAuth)); +#endif + return fgReplyAuth; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is invoked when CNM granted channel privilege +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +bowRunEventChGrant ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_BSS_INFO_T prBowBssInfo; + P_BOW_FSM_INFO_T prBowFsmInfo; + P_MSG_CH_GRANT_T prMsgChGrant; + UINT_8 ucTokenID; + UINT_32 u4GrantInterval; + ENUM_BOW_DEVICE_STATE eFsmState; + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + + prBowBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + prMsgChGrant = (P_MSG_CH_GRANT_T)prMsgHdr; + ucTokenID = prMsgChGrant->ucTokenID; + u4GrantInterval = prMsgChGrant->u4GrantInterval; + + /* 1. free message */ + cnmMemFree(prAdapter, prMsgHdr); + prBowFsmInfo->fgIsChannelGranted = TRUE; + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("Entering bowRunEventChGrant.\n")); +#endif + + eFsmState = bowGetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress); + + /*Release channel*/ + if((!prBowFsmInfo->fgIsChannelRequested) || + (prBowFsmInfo->ucSeqNumOfChReq != ucTokenID) || + (eFsmState == BOW_DEVICE_STATE_DISCONNECTED) || + (eFsmState == BOW_DEVICE_STATE_DISCONNECTING)){ +#if CFG_BOW_TEST + printk("BoW Channel [GIVE UP:%d]\n", ucTokenID); + printk("[Requested:%d][ucSeqNumOfChReq:%d][eFsmState:%d]\n", + prBowFsmInfo->fgIsChannelRequested, prBowFsmInfo->ucSeqNumOfChReq, eFsmState); +#endif + bowReleaseCh(prAdapter); + return; + } + + /* 2. channel privilege has been approved */ + prBowFsmInfo->u4ChGrantedInterval = u4GrantInterval; + +#if 0 + cnmTimerStartTimer(prAdapter, + &prBowFsmInfo->rChGrantedTimer, + prBowFsmInfo->u4ChGrantedInterval - BOW_JOIN_CH_GRANT_THRESHOLD); +#else + cnmTimerStartTimer(prAdapter, + &prBowFsmInfo->rChGrantedTimer, + BOW_JOIN_CH_REQUEST_INTERVAL - BOW_JOIN_CH_GRANT_THRESHOLD); +#endif + + /* 3.2 set local variable to indicate join timer is ticking */ + prBowFsmInfo->fgIsInfraChannelFinished = FALSE; + +#if CFG_BOW_TEST + printk("BoW Channel [GRANTED:%d].\n", ucTokenID); +#endif + + if(eFsmState == BOW_DEVICE_STATE_ACQUIRING_CHANNEL) { + bowStarting(prAdapter); + bowReleaseCh(prAdapter); + if(prBowFsmInfo->ucRole == BOW_RESPONDER) { + bowResponderJoin(prAdapter, prBowFsmInfo->prTargetBssDesc); + } + } + else { + /*update bssinfo*/ + nicUpdateBss(prAdapter, NETWORK_TYPE_BOW_INDEX); + bowReleaseCh(prAdapter); + } + + return; +} /* end of aisFsmRunEventChGrant() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is to inform CNM for channel privilege requesting +* has been released +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +bowRequestCh ( + IN P_ADAPTER_T prAdapter + ) +{ + P_BOW_FSM_INFO_T prBowFsmInfo; + P_MSG_CH_REQ_T prMsgChReq; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + + if (prBowFsmInfo->fgIsChannelGranted == FALSE) + { + +#if CFG_BOW_TEST + printk("BoW channel [REQUEST:%d], %d, %d.\n", prBowFsmInfo->ucSeqNumOfChReq+1, prBowFsmInfo->ucPrimaryChannel, prBowFsmInfo->eBand); +#endif + prMsgChReq = (P_MSG_CH_REQ_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_REQ_T)); + + if (!prMsgChReq) { + ASSERT(0); // Can't indicate CNM for channel acquiring + return; + } + + prMsgChReq->rMsgHdr.eMsgId = MID_MNY_CNM_CH_REQ; + prMsgChReq->ucNetTypeIndex = NETWORK_TYPE_BOW_INDEX; + prMsgChReq->ucTokenID = ++prBowFsmInfo->ucSeqNumOfChReq; + prMsgChReq->eReqType = CH_REQ_TYPE_JOIN; +#if 0 + prMsgChReq->u4MaxInterval = BOW_JOIN_CH_REQUEST_INTERVAL; +#else + prMsgChReq->u4MaxInterval = 1; +#endif + prMsgChReq->ucPrimaryChannel = prBowFsmInfo->ucPrimaryChannel; //prBowFsmInfo->prTargetBssDesc->ucChannelNum; + prMsgChReq->eRfSco = CHNL_EXT_SCN; //prBowFsmInfo->prTargetBssDesc->eSco; + prMsgChReq->eRfBand = prBowFsmInfo->eBand; //prBowFsmInfo->prTargetBssDesc->eBand; + COPY_MAC_ADDR(prMsgChReq->aucBSSID, prBowFsmInfo->aucPeerAddress); + + + prBowFsmInfo->fgIsChannelRequested = TRUE; + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prMsgChReq, + MSG_SEND_METHOD_BUF); + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is to inform BOW that channel privilege is granted +* has been released +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +bowReleaseCh ( + IN P_ADAPTER_T prAdapter + ) +{ + P_BOW_FSM_INFO_T prBowFsmInfo; + P_MSG_CH_ABORT_T prMsgChAbort; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + + if(prBowFsmInfo->fgIsChannelGranted != FALSE || prBowFsmInfo->fgIsChannelRequested != FALSE) + { +#if CFG_BOW_TEST + printk("BoW channel [RELEASE:%d] %d, %d.\n", prBowFsmInfo->ucSeqNumOfChReq, prBowFsmInfo->ucPrimaryChannel, prBowFsmInfo->eBand); +#endif + + prBowFsmInfo->fgIsChannelRequested = FALSE; + prBowFsmInfo->fgIsChannelGranted = FALSE; + + /* 1. return channel privilege to CNM immediately */ + prMsgChAbort = (P_MSG_CH_ABORT_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_ABORT_T)); + if (!prMsgChAbort) { + ASSERT(0); // Can't release Channel to CNM + return; + } + + prMsgChAbort->rMsgHdr.eMsgId = MID_MNY_CNM_CH_ABORT; + prMsgChAbort->ucNetTypeIndex = NETWORK_TYPE_BOW_INDEX; + prMsgChAbort->ucTokenID = prBowFsmInfo->ucSeqNumOfChReq; + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prMsgChAbort, + MSG_SEND_METHOD_BUF); + } + + return; +} /* end of aisFsmReleaseCh() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate an Event of "Media Disconnect" to HOST +* +* @param[in] u4Param Unused timer parameter +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +bowChGrantedTimeout( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Param + ) +{ + P_BOW_FSM_INFO_T prBowFsmInfo; + ENUM_BOW_DEVICE_STATE eFsmState; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + +#if CFG_BOW_TEST + printk("BoW Channel [TIMEOUT]\n"); +#endif +#if 1 + //bowReleaseCh(prAdapter); + eFsmState = bowGetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress); + + /*If connecting is not completed, request CH again*/ + if((eFsmState == BOW_DEVICE_STATE_CONNECTING) || + (eFsmState == BOW_DEVICE_STATE_STARTING)) + { + bowRequestCh(prAdapter); + } +#endif +} + + +BOOLEAN +bowNotifyAllLinkDisconnected ( + IN P_ADAPTER_T prAdapter + ) +{ + UINT_8 ucBowTableIdx = 0; + CMD_INFO_T rCmdInfo; + + ASSERT(prAdapter); + + kalMemZero(&rCmdInfo, sizeof(CMD_INFO_T)); + + while (ucBowTableIdx < CFG_BOW_PHYSICAL_LINK_NUM) + { + if (arBowTable[ucBowTableIdx].fgIsValid) + { + COPY_MAC_ADDR(prAdapter->rWifiVar.rBowFsmInfo.aucPeerAddress, arBowTable[ucBowTableIdx].aucPeerAddress); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowNotifyAllLinkDisconnected, arBowTable[%x].aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", ucBowTableIdx, + arBowTable[ucBowTableIdx].aucPeerAddress[0], + arBowTable[ucBowTableIdx].aucPeerAddress[1], + arBowTable[ucBowTableIdx].aucPeerAddress[2], + arBowTable[ucBowTableIdx].aucPeerAddress[3], + arBowTable[ucBowTableIdx].aucPeerAddress[4], + arBowTable[ucBowTableIdx].aucPeerAddress[5])); + DBGLOG(BOW, EVENT, ("bowNotifyAllLinkDisconnected, arBowTable[%x].fgIsValid, %x.\n", ucBowTableIdx, arBowTable[ucBowTableIdx].fgIsValid)); +#endif +#if 1 + wlanoidSendSetQueryBowCmd(prAdapter, + CMD_ID_CMD_BT_OVER_WIFI, + TRUE, + FALSE, + wlanbowCmdEventLinkDisconnected, + wlanbowCmdTimeoutHandler, + 0, + NULL, + 0 + ); +#else + wlanbowCmdEventLinkDisconnected(prAdapter, &rCmdInfo, NULL); +#endif + } + + ucBowTableIdx += 1; + } + + return TRUE; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to retrieve Bluetooth-over-Wi-Fi state from glue layer +* +* \param[in] +* prGlueInfo +* rPeerAddr +* \return +* ENUM_BOW_DEVICE_STATE +*/ +/*----------------------------------------------------------------------------*/ + +BOOLEAN +bowCheckBowTableIfVaild( + IN P_ADAPTER_T prAdapter, + IN UINT_8 aucPeerAddress[6] + ) +{ + UINT_8 idx; + + KAL_SPIN_LOCK_DECLARATION(); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + for(idx = 0 ; idx < CFG_BOW_PHYSICAL_LINK_NUM ; idx++) + { + if( arBowTable[idx].fgIsValid && + EQUAL_MAC_ADDR(arBowTable[idx].aucPeerAddress, aucPeerAddress)) + { + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("kalCheckBowifVaild, aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", idx, + aucPeerAddress[0], + aucPeerAddress[1], + aucPeerAddress[2], + aucPeerAddress[3], + aucPeerAddress[4], + aucPeerAddress[5])); + + DBGLOG(BOW, EVENT, ("kalCheckBowifVaild, arBowTable[idx].aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", idx, + arBowTable[idx].aucPeerAddress[0], + arBowTable[idx].aucPeerAddress[1], + arBowTable[idx].aucPeerAddress[2], + arBowTable[idx].aucPeerAddress[3], + arBowTable[idx].aucPeerAddress[4], + arBowTable[idx].aucPeerAddress[5])); + + DBGLOG(BOW, EVENT, ("kalCheckBowifVaild, arBowTable[idx].fgIsValid, %x, %x.\n", idx, arBowTable[idx].fgIsValid)); + +#endif + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + return TRUE; + } + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + return FALSE; +} + +BOOLEAN +bowGetBowTableContent( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucBowTableIdx, + OUT P_BOW_TABLE_T prBowTable + ) +{ + KAL_SPIN_LOCK_DECLARATION(); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + if (arBowTable[ucBowTableIdx].fgIsValid) + { + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowGetBowTableContent, arBowTable[idx].fgIsValid, %x, %x.\n", ucBowTableIdx, arBowTable[ucBowTableIdx].fgIsValid)); + printk("GET State [%d]\n", arBowTable[ucBowTableIdx].eState); +#endif + prBowTable = &(arBowTable[ucBowTableIdx]); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + return TRUE; + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + return FALSE; +} + + +BOOLEAN +bowSetBowTableContent( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucBowTableIdx, + IN P_BOW_TABLE_T prBowTable + ) +{ + KAL_SPIN_LOCK_DECLARATION(); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + COPY_MAC_ADDR(arBowTable[ucBowTableIdx].aucPeerAddress, prBowTable->aucPeerAddress); + arBowTable[ucBowTableIdx].eState = prBowTable->eState; + arBowTable[ucBowTableIdx].fgIsValid = prBowTable->fgIsValid; + arBowTable[ucBowTableIdx].ucAcquireID = prBowTable->ucAcquireID; + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + kalSetBowState(prAdapter->prGlueInfo, prBowTable->eState, prBowTable->aucPeerAddress); + //kalSetBowRole(prAdapter->prGlueInfo, prBowTable->ucRole, prBowTable->aucPeerAddress); + +#if CFG_BOW_TEST + printk("SET State [%d]\n", arBowTable[ucBowTableIdx].eState); + DBGLOG(BOW, EVENT, ("kalCheckBowifVaild, arBowTable[ucBowTableIdx].fgIsValid, %x, %x.\n", ucBowTableIdx, arBowTable[ucBowTableIdx].fgIsValid)); +#endif + + return TRUE; + +} + + +BOOLEAN +bowGetBowTableEntryByPeerAddress( + IN P_ADAPTER_T prAdapter, + IN UINT_8 aucPeerAddress[6], + OUT PUINT_8 pucBowTableIdx + ) +{ + UINT_8 idx; + + KAL_SPIN_LOCK_DECLARATION(); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + for(idx = 0 ; idx < CFG_BOW_PHYSICAL_LINK_NUM ; idx++) + { + if( arBowTable[idx].fgIsValid && + EQUAL_MAC_ADDR(arBowTable[idx].aucPeerAddress, aucPeerAddress)) + { + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("kalCheckBowifVaild, aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", idx, + aucPeerAddress[0], + aucPeerAddress[1], + aucPeerAddress[2], + aucPeerAddress[3], + aucPeerAddress[4], + aucPeerAddress[5])); + DBGLOG(BOW, EVENT, ("kalCheckBowifVaild, arBowTable[idx].aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", idx, + arBowTable[idx].aucPeerAddress[0], + arBowTable[idx].aucPeerAddress[1], + arBowTable[idx].aucPeerAddress[2], + arBowTable[idx].aucPeerAddress[3], + arBowTable[idx].aucPeerAddress[4], + arBowTable[idx].aucPeerAddress[5])); + DBGLOG(BOW, EVENT, ("kalCheckBowifVaild, arBowTable[idx].fgIsValid, %x, %x.\n", idx, arBowTable[idx].fgIsValid)); +#endif + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + *pucBowTableIdx = idx; + + return TRUE; + } + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + return FALSE; +} + + +BOOLEAN +bowGetBowTableFreeEntry( + IN P_ADAPTER_T prAdapter, + OUT PUINT_8 pucBowTableIdx + ) +{ + UINT_8 idx; + + KAL_SPIN_LOCK_DECLARATION(); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + for(idx = 0 ; idx < CFG_BOW_PHYSICAL_LINK_NUM ; idx++) + { + if(!arBowTable[idx].fgIsValid) + { +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowGetBowTableFreeEntry, arBowTable[idx].fgIsValid, %x, %x.\n", idx, arBowTable[idx].fgIsValid)); +#endif + *pucBowTableIdx = idx; + arBowTable[idx].fgIsValid = TRUE; + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + return TRUE; + } + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + return FALSE; +} + + +ENUM_BOW_DEVICE_STATE +bowGetBowTableState( + IN P_ADAPTER_T prAdapter, + IN UINT_8 aucPeerAddress[6] + ) +{ + UINT_8 idx; + + KAL_SPIN_LOCK_DECLARATION(); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + for(idx = 0 ; idx < CFG_BOW_PHYSICAL_LINK_NUM ; idx++) + { + if( arBowTable[idx].fgIsValid && + EQUAL_MAC_ADDR(arBowTable[idx].aucPeerAddress, aucPeerAddress)) + { +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("bowGetState, aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", idx, + aucPeerAddress[0], + aucPeerAddress[1], + aucPeerAddress[2], + aucPeerAddress[3], + aucPeerAddress[4], + aucPeerAddress[5])); + DBGLOG(BOW, EVENT, ("bowGetState, arBowTable[idx].aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", idx, + arBowTable[idx].aucPeerAddress[0], + arBowTable[idx].aucPeerAddress[1], + arBowTable[idx].aucPeerAddress[2], + arBowTable[idx].aucPeerAddress[3], + arBowTable[idx].aucPeerAddress[4], + arBowTable[idx].aucPeerAddress[5])); + DBGLOG(BOW, EVENT, ("bowGetState, arBowTable[idx].fgIsValid, %x, %x.\n", idx, arBowTable[idx].fgIsValid)); + DBGLOG(BOW, EVENT, ("bowGetState, arBowTable[idx].eState;, %x, %x.\n", idx, arBowTable[idx].eState)); + printk("GET State [%d]\n", arBowTable[idx].eState); +#endif + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + return arBowTable[idx].eState; + } + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + return BOW_DEVICE_STATE_DISCONNECTED; +} + + +BOOLEAN +bowSetBowTableState( + IN P_ADAPTER_T prAdapter, + IN UINT_8 aucPeerAddress[6], + IN ENUM_BOW_DEVICE_STATE eState + ) +{ + UINT_8 ucBowTableIdx; + + if(bowGetBowTableEntryByPeerAddress(prAdapter, aucPeerAddress, &ucBowTableIdx)) { + KAL_SPIN_LOCK_DECLARATION(); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + arBowTable[ucBowTableIdx].eState = eState; +#if CFG_BOW_TEST + printk("SET State [%d]\n", eState); +#endif + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + kalSetBowState(prAdapter->prGlueInfo, eState, aucPeerAddress); + return TRUE; + } + return FALSE; +} + + +#endif + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/common/wlan_lib.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/common/wlan_lib.c new file mode 100755 index 000000000000..3d4528f3e715 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/common/wlan_lib.c @@ -0,0 +1,4934 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/common/wlan_lib.c#4 $ +*/ +/*! \file wlan_lib.c + \brief Internal driver stack will export the required procedures here for GLUE Layer. + + This file contains all routines which are exported from MediaTek 802.11 Wireless + LAN driver stack to GLUE Layer. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ +/* +** $Log: wlan_lib.c $ + * + * 01 20 2012 cp.wu + * [ALPS00096191] [MT6620 Wi-Fi][Driver][Firmware] Porting to ALPS4.0_DEV branch + * sync to up-to-date changes including: + * 1. BOW bugfix + * 2. XLOG + * + * 01 16 2012 cp.wu + * [WCXRP00001169] [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band configuration with corresponding network configuration + * correct scan result removing policy. + * + * 01 16 2012 cp.wu + * [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band configuration with corresponding network configuration + * add wlanSetPreferBandByNetwork() for glue layer to invoke for setting preferred band configuration corresponding to network type. + * + * 01 15 2012 yuche.tsai + * NULL + * Fix wrong basic rate issue. + * + * 01 09 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Check in the Add Tx power Cmd to driver. + * + * 11 28 2011 cp.wu + * [WCXRP00001125] [MT6620 Wi-Fi][Firmware] Strengthen Wi-Fi power off sequence to have a clearroom environment when returining to ROM code + * 1. Due to firmware now stops HIF DMA for powering off, do not try to receive any packet from firmware + * 2. Take use of prAdapter->fgIsEnterD3ReqIssued for tracking whether it is powering off or not + * + * 11 14 2011 cm.chang + * [WCXRP00001104] [All Wi-Fi][FW] Show init process by HW mail-box register + * Show FW initial ID when timeout to wait for ready bit + * + * 11 11 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * modify the xlog related code. + * + * 10 25 2011 cp.wu + * [WCXRP00001057] [MT6620 Wi-Fi][Driver][Firmware] Ensure no pending interrupt status bits remained while switching from RAM code to ROM code + * 1. [FW] always clear all pending messages while leaving from RAM code section. + * 2. [DRV] clear interrupt then wait for RDY bit de-assertion + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 08 02 2011 yuche.tsai + * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, TX deauth to a disconnecting device issue. + * Support TX Deauth while tearing down a station connection. + * + * 06 23 2011 cp.wu + * [WCXRP00000812] [MT6620 Wi-Fi][Driver] not show NVRAM when there is no valid MAC address in NVRAM content + * check with firmware for valid MAC address. + * + * 05 31 2011 cp.wu + * [WCXRP00000749] [MT6620 Wi-Fi][Driver] Add band edge tx power control to Wi-Fi NVRAM + * changed to use non-zero checking for valid bit in NVRAM content + * + * 05 27 2011 cp.wu + * [WCXRP00000749] [MT6620 Wi-Fi][Driver] Add band edge tx power control to Wi-Fi NVRAM + * invoke CMD_ID_SET_EDGE_TXPWR_LIMIT when there is valid data exist in NVRAM content. + * + * 05 18 2011 cp.wu + * [WCXRP00000734] [MT6620 Wi-Fi][Driver] Pass PHY_PARAM in NVRAM to firmware domain + * check-in missed file. + * + * 05 11 2011 cp.wu + * [WCXRP00000718] [MT6620 Wi-Fi] modify the behavior of setting tx power + * correct assertion. + * + * 05 11 2011 cp.wu + * [WCXRP00000718] [MT6620 Wi-Fi] modify the behavior of setting tx power + * ACPI APIs migrate to wlan_lib.c for glue layer to invoke. + * + * 05 11 2011 cm.chang + * [WCXRP00000717] [MT5931 Wi-Fi][Driver] Handle wrong NVRAM content about AP bandwidth setting + * . + * + * 04 22 2011 cp.wu + * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for RESET_START and RESET_END events + * skip power-off handshaking when RESET indication is received. + * + * 04 22 2011 george.huang + * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode + * . + * + * 04 15 2011 cp.wu + * [WCXRP00000654] [MT6620 Wi-Fi][Driver] Add loop termination criterion for wlanAdapterStop(). + * add loop termination criteria for wlanAdapterStop(). + * + * 04 12 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix the sta index in processing security frame + * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 + * Add debug message. + * + * 04 12 2011 cp.wu + * [WCXRP00000631] [MT6620 Wi-Fi][Driver] Add an API for QM to retrieve current TC counter value and processing frame dropping cases for TC4 path + * 1. add nicTxGetResource() API for QM to make decisions. + * 2. if management frames is decided by QM for dropping, the call back is invoked to indicate such a case. + * + * 04 06 2011 cp.wu + * [WCXRP00000616] [MT6620 Wi-Fi][Driver] Free memory to pool and kernel in case any unexpected failure happend inside wlanAdapterStart + * invoke nicReleaseAdapterMemory() as failure handling in case wlanAdapterStart() failed unexpectedly + * + * 03 29 2011 wh.su + * [WCXRP00000248] [MT6620 Wi-Fi][FW]Fixed the Klockwork error + * fixed the kclocwork error. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 15 2011 cp.wu + * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous memory consumption + * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK + * 2. Use common coalescing buffer for both TX/RX directions + * + * + * 03 10 2011 cp.wu + * [WCXRP00000532] [MT6620 Wi-Fi][Driver] Migrate NVRAM configuration procedures from MT6620 E2 to MT6620 E3 + * deprecate configuration used by MT6620 E2 + * + * 03 07 2011 terry.wu + * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message + * Toggle non-standard debug messages to comments. + * + * 02 25 2011 cp.wu + * [WCXRP00000496] [MT5931][Driver] Apply host-triggered chip reset before initializing firmware download procedures + * apply host-triggered chip reset mechanism before initializing firmware download procedures. + * + * 02 17 2011 eddie.chen + * [WCXRP00000458] [MT6620 Wi-Fi][Driver] BOW Concurrent - ProbeResp was exist in other channel + * 1) Chnage GetFrameAction decision when BSS is absent. + * 2) Check channel and resource in processing ProbeRequest + * + * 02 16 2011 cm.chang + * [WCXRP00000447] [MT6620 Wi-Fi][FW] Support new NVRAM update mechanism + * . + * + * 02 01 2011 george.huang + * [WCXRP00000333] [MT5931][FW] support SRAM power control drivers + * init variable for CTIA. + * + * 01 27 2011 george.huang + * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability + * Support current measure mode, assigned by registry (XP only). + * + * 01 24 2011 cp.wu + * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving + * 1. add an extra counter for tracking pending forward frames. + * 2. notify TX service thread as well when there is pending forward frame + * 3. correct build errors leaded by introduction of Wi-Fi direct separation module + * + * 01 12 2011 cm.chang + * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting + * User-defined bandwidth is for 2.4G and 5G individually + * + * 01 10 2011 cp.wu + * [WCXRP00000351] [MT6620 Wi-Fi][Driver] remove from scanning result in OID handling layer when the corresponding BSS is disconnected due to beacon timeout + * remove from scanning result when the BSS is disconnected due to beacon timeout. + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease physically continous memory demands + * separate kalMemAlloc() into virtually-continous and physically-continous type to ease slab system pressure + * + * 12 31 2010 cp.wu + * [WCXRP00000327] [MT6620 Wi-Fi][Driver] Improve HEC WHQA 6972 workaround coverage in driver side + * while being unloaded, clear all pending interrupt then set LP-own to firmware + * + * 12 31 2010 cp.wu + * [WCXRP00000335] [MT6620 Wi-Fi][Driver] change to use milliseconds sleep instead of delay to avoid blocking to system scheduling + * change to use msleep() and shorten waiting interval to reduce blocking to other task while Wi-Fi driver is being loaded + * + * 12 28 2010 cp.wu + * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release + * report EEPROM used flag via NIC_CAPABILITY + * + * 12 28 2010 cp.wu + * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release + * integrate with 'EEPROM used' flag for reporting correct capability to Engineer Mode/META and other tools + * + * 12 22 2010 eddie.chen + * [WCXRP00000218] [MT6620 Wi-Fi][Driver] Add auto rate window control in registry + * Remove controling auto rate from initial setting. The initial setting is defined by FW code. + * + * 12 15 2010 cp.wu + * NULL + * sync. with ALPS code by enabling interrupt just before leaving wlanAdapterStart() + * + * 12 08 2010 yuche.tsai + * [WCXRP00000245] [MT6620][Driver] Invitation & Provision Discovery Feature Check-in + * Change Param name for invitation connection. + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 11 03 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * 1) use 8 buffers for MT5931 which is equipped with less memory + * 2) modify MT5931 debug level to TRACE when download is successful + * + * 11 02 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * for MT5931, adapter initialization is done *after* firmware is downloaded. + * + * 11 02 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * correct MT5931 firmware download procedure: + * MT5931 will download firmware first then acquire LP-OWN + * + * 11 02 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * 1) update MT5931 firmware encryption tool. (using 64-bytes unit) + * 2) update MT5931 firmware download procedure + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 11 01 2010 yarco.yang + * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform + * Add code to run WlanIST in SDIO callback. + * + * 10 27 2010 george.huang + * [WCXRP00000127] [MT6620 Wi-Fi][Driver] Add a registry to disable Beacon Timeout function for SQA test by using E1 EVB + * Support registry option for disable beacon lost detection. + * + * 10 26 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command + * 1) update NVRAM content template to ver 1.02 + * 2) add compile option for querying NIC capability (default: off) + * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting + * 4) correct auto-rate compiler error under linux (treat warning as error) + * 5) simplify usage of NVRAM and REG_INFO_T + * 6) add version checking between driver and firmware + * + * 10 26 2010 eddie.chen + * [WCXRP00000134] [MT6620 Wi-Fi][Driver] Add a registry to enable auto rate for SQA test by using E1 EVB + * Add auto rate parameter in registry. + * + * 10 25 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * add option for enable/disable TX PWR gain adjustment (default: off) + * + * 10 18 2010 cp.wu + * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore + * 1. when wlanAdapterStop() failed to send POWER CTRL command to firmware, do not poll for ready bit dis-assertion + * 2. shorten polling count for shorter response time + * 3. if bad I/O operation is detected during TX resource polling, then further operation is aborted as well + * + * 10 18 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android + * complete implementation of Android NVRAM access + * + * 10 15 2010 cp.wu + * [WCXRP00000103] [MT6620 Wi-Fi][Driver] Driver crashed when using WZC to connect to AP#B with connection with AP#A + * bugfix: always reset pointer to IEbuf to zero when keeping scanning result for the connected AP + * + * 10 08 2010 cp.wu + * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test + * adding fixed rate support for distance test. (from registry setting) + * + * 10 07 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * add firmware download for MT5931. + * + * 10 06 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * divide a single function into 2 part to surpress a weird compiler warning from gcc-4.4.0 + * + * 10 06 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * code reorganization to improve isolation between GLUE and CORE layers. + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * load manufacture data when CFG_SUPPORT_NVRAM is set to 1 + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by ENUM_NETWORK_TYPE_INDEX_T only + * remove ENUM_NETWORK_TYPE_T definitions + * + * 09 29 2010 wh.su + * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue + * [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue. + * + * 09 24 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * eliminate unused variables which lead gcc to argue + * + * 09 24 2010 cp.wu + * [WCXRP00000057] [MT6620 Wi-Fi][Driver] Modify online scan to a run-time switchable feature + * Modify online scan as a run-time adjustable option (for Windows, in registry) + * + * 09 23 2010 cp.wu + * [WCXRP00000051] [MT6620 Wi-Fi][Driver] WHQL test fail in MAC address changed item + * use firmware reported mac address right after wlanAdapterStart() as permanent address + * + * 09 23 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * eliminate reference of CFG_RESPONSE_MAX_PKT_SIZE + * + * 09 21 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS associated + * Do a complete reset with STA-REC null checking for RF test re-entry + * + * 09 21 2010 kevin.huang + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * Eliminate Linux Compile Warning + * + * 09 13 2010 cp.wu + * NULL + * acquire & release power control in oid handing wrapper. + * + * 09 09 2010 cp.wu + * NULL + * move IE to buffer head when the IE pointer is not pointed at head. + * + * 09 08 2010 cp.wu + * NULL + * use static memory pool for storing IEs of scanning result. + * + * 09 01 2010 cp.wu + * NULL + * HIFSYS Clock Source Workaround + * + * 09 01 2010 wh.su + * NULL + * adding the wapi support for integration test. + * + * 09 01 2010 cp.wu + * NULL + * move HIF CR initialization from where after sdioSetupCardFeature() to wlanAdapterStart() + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 26 2010 yuche.tsai + * NULL + * Add AT GO test configure mode under WinXP. + * Please enable 1. CFG_ENABLE_WIFI_DIRECT, 2. CFG_TEST_WIFI_DIRECT_GO, 3. CFG_SUPPORT_AAA + * + * 08 25 2010 george.huang + * NULL + * update OID/ registry control path for PM related settings + * + * 08 24 2010 cp.wu + * NULL + * 1) initialize variable for enabling short premable/short time slot. + * 2) add compile option for disabling online scan + * + * 08 13 2010 cp.wu + * NULL + * correction issue: desired phy type not initialized as ABGN mode. + * + * 08 12 2010 cp.wu + * NULL + * [AIS-FSM] honor registry setting for adhoc running mode. (A/B/G) + * + * 08 10 2010 cm.chang + * NULL + * Support EEPROM read/write in RF test mode + * + * 08 03 2010 cp.wu + * NULL + * surpress compilation warning. + * + * 08 03 2010 cp.wu + * NULL + * Centralize mgmt/system service procedures into independent calls. + * + * 07 30 2010 cp.wu + * NULL + * 1) BoW wrapper: use definitions instead of hard-coded constant for error code + * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead + * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames + * + * 07 29 2010 cp.wu + * NULL + * eliminate u4FreqInKHz usage, combined into rConnections.ucAdHoc* + * + * 07 28 2010 cp.wu + * NULL + * 1) eliminate redundant variable eOPMode in prAdapter->rWlanInfo + * 2) change nicMediaStateChange() API prototype + * + * 07 21 2010 cp.wu + * + * 1) change BG_SCAN to ONLINE_SCAN for consistent term + * 2) only clear scanning result when scan is permitted to do + * + * 07 19 2010 cm.chang + * + * Set RLM parameters and enable CNM channel manager + * + * 07 19 2010 jeffrey.chang + * + * Linux port modification + * + * 07 13 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * Reduce unnecessary type casting + * + * 07 13 2010 cp.wu + * + * use multiple queues to keep 1x/MMPDU/CMD's strict order even when there is incoming 1x frames. + * + * 07 13 2010 cp.wu + * + * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets + * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending + * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid descriptor underflow under concurrent network operation + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 05 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) ignore RSN checking when RSN is not turned on. + * 2) set STA-REC deactivation callback as NULL + * 3) add variable initialization API based on PHY configuration + * + * 07 02 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) for event packet, no need to fill RFB. + * 2) when wlanAdapterStart() failed, no need to initialize state machines + * 3) after Beacon/ProbeResp parsing, corresponding BSS_DESC_T should be marked as IE-parsed + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Support sync command of STA_REC + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add scan uninitialization procedure + * + * 06 25 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add API in que_mgt to retrieve sta-rec index for security frames. + * + * 06 24 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path. + * + * 06 23 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Merge g_arStaRec[] into adapter->arStaRec[] + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * initialize mbox & ais_fsm in wlanAdapterStart() + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * change MAC address updating logic. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * simplify timer usage. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 + * 2) when disconnected, indicate nic directly (no event is needed) + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * cnm_timer has been migrated. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 28 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * disable interrupt then send power control command packet. + * + * 05 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) when stopping adapter, wait til RDY bit has been cleaerd. + * 2) set TASK_OFFLOAD as driver-core OIDs + * + * 05 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS + * 2) buffer statistics data for 2 seconds + * 3) use default value for adhoc parameters instead of 0 + * + * 05 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) do not take timeout mechanism for power mode oids + * 2) retrieve network type from connection status + * 3) after disassciation, set radio state to off + * 4) TCP option over IPv6 is supported + * + * 05 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add CFG_STARTUP_DEBUG for debugging starting up issue. + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * 1) add timeout handler mechanism for pending command packets + * 2) add p2p add/removal key + * + * 04 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * surpress compiler warning + * + * 04 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * roll-back to rev.60. + * + * 04 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) remove redundant firmware image unloading + * 2) use compile-time macros to separate logic related to accquiring own + * + * 04 16 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * treat BUS access failure as kind of card removal. + * + * 04 14 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * always set fw-own before driver is unloaded. + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * 2) command sequence number is now increased atomically + * * * 3) private data could be hold and taken use for other purpose + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * finish non-glue layer access to glue variables + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * rWlanInfo should be placed at adapter rather than glue due to most operations + * are done in adapter layer. + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * ePowerCtrl is not necessary as a glue variable. + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * add timeout check in the kalOidComplete + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * improve none-glue code portability + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * improve none-glue code portability + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) for some OID, never do timeout expiration + * 2) add 2 kal API for later integration + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) eliminate unused definitions + * 2) ready bit will be polled for limited iteration + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * kalOidComplete is not necessary in linux + * + * 04 01 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * change to use pass-in prRegInfo instead of accessing prGlueInfo directly + * + * 04 01 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * change to use WIFI_TCM_ALWAYS_ON as firmware image + * + * 04 01 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * . + * + * 03 31 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * modify the wapi related code for new driver's design. + * + * 03 30 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * adding none-glue code portability + * + * 03 30 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * adding non-glue code portability + * + * 03 29 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * improve non-glue code portability + * + * 03 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * firmware download load adress & start address are now configured from config.h + * due to the different configurations on FPGA and ASIC + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * [WPD00003826] Initial import for Linux port + * initial import for Linux port + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port + * + * 03 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * only send CMD_NIC_POWER_CTRL in wlanAdapterStop() when card is not removed and is not in D3 state + * + * 03 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * always send CMD_NIC_POWER_CTRL packet when nic is being halted + * + * 03 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add ACPI D0/D3 state switching support + * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response + * +* 03 12 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add two option for ACK and ENCRYPTION for firmware download + * + * 03 11 2010 cp.wu + * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 + * add RX starvation warning debug message controlled by CFG_HIF_RX_STARVATION_WARNING + * + * 03 08 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add another spin-lock to protect MsduInfoList due to it might be accessed by different thread. + * 2) change own-back acquiring procedure to wait for up to 16.67 seconds + * + * 03 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * when starting adapter, read local adminsitrated address from registry and send to firmware via CMD_BASIC_CONFIG. + * + * 03 02 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) the use of prPendingOid revised, all accessing are now protected by spin lock + * 2) ensure wlanReleasePendingOid will clear all command queues + * + * 03 02 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add mutex to avoid multiple access to qmTxQueue simultaneously. + * + * 03 01 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add command/event definitions for initial states + * + * 02 24 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Added code for QM_TEST_MODE + * + * 02 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct function name .. + * + * 02 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * separate wlanProcesQueuePacket() into 2 APIs upon request + * + * 02 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add new API: wlanProcessQueuedPackets() + * + * 02 11 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct wlanAdapterStart + * + * 02 11 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. add logic for firmware download + * 2. firmware image filename and start/load address are now retrieved from registry + * + * 02 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement host-side firmware download logic + * + * 02 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c] + * 2) firmware image length is now retrieved via NdisFileOpen + * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore + * 4) nicRxWaitResponse() revised + * 5) another set of TQ counter default value is added for fw-download state + * 6) Wi-Fi load address is now retrieved from registry too + * + * 02 09 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address + * 2. follow MSDN defined behavior when associates to another AP + * 3. for firmware download, packet size could be up to 2048 bytes + * + * 02 08 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * prepare for implementing fw download logic + * + * 02 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * wlanoidSetFrequency is now implemented by RF test command. + * + * 02 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * QueryRssi is no longer w/o hardware access, it is now implemented by command/event handling loop + * + * 02 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. clear prPendingCmdInfo properly + * 2. while allocating memory for cmdinfo, no need to add extra 4 bytes. + * + * 01 28 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * allow MCR read/write OIDs in RF test mode + * + * 01 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) implement timeout mechanism when OID is pending for longer than 1 second + * 2) allow OID_802_11_CONFIGURATION to be executed when RF test mode is turned on + * + * 01 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. eliminate improper variable in rHifInfo + * 2. block TX/ordinary OID when RF test mode is engaged + * 3. wait until firmware finish operation when entering into and leaving from RF test mode + * 4. correct some HAL implementation + * + * 01 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Under WinXP with SDIO, use prGlueInfo->rHifInfo.pvInformationBuffer instead of prGlueInfo->pvInformationBuffer +** \main\maintrunk.MT6620WiFiDriver_Prj\36 2009-12-10 16:54:36 GMT mtk02752 +** code clean +** \main\maintrunk.MT6620WiFiDriver_Prj\35 2009-12-09 20:04:59 GMT mtk02752 +** only report as connected when CFG_HIF_EMULATION_TEST is set to 1 +** \main\maintrunk.MT6620WiFiDriver_Prj\34 2009-12-08 17:39:41 GMT mtk02752 +** wlanoidRftestQueryAutoTest could be executed without touching hardware +** \main\maintrunk.MT6620WiFiDriver_Prj\33 2009-12-03 16:10:26 GMT mtk01461 +** Add debug message +** \main\maintrunk.MT6620WiFiDriver_Prj\32 2009-12-02 22:05:33 GMT mtk02752 +** kalOidComplete() will decrease i4OidPendingCount +** \main\maintrunk.MT6620WiFiDriver_Prj\31 2009-12-01 23:02:36 GMT mtk02752 +** remove unnecessary spinlock +** \main\maintrunk.MT6620WiFiDriver_Prj\30 2009-12-01 22:50:38 GMT mtk02752 +** use TC4 for command, maintein i4OidPendingCount +** \main\maintrunk.MT6620WiFiDriver_Prj\29 2009-11-27 12:45:34 GMT mtk02752 +** prCmdInfo should be freed when invoking wlanReleasePendingOid() to clear pending oid +** \main\maintrunk.MT6620WiFiDriver_Prj\28 2009-11-24 19:55:51 GMT mtk02752 +** wlanSendPacket & wlanRetransmitOfPendingFrames is only used in old data path +** \main\maintrunk.MT6620WiFiDriver_Prj\27 2009-11-23 17:59:55 GMT mtk02752 +** clear prPendingOID inside wlanSendCommand() when the OID didn't need to be replied. +** \main\maintrunk.MT6620WiFiDriver_Prj\26 2009-11-23 14:45:29 GMT mtk02752 +** add another version of wlanSendCommand() for command-sending only without blocking for response +** \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-11-17 22:40:44 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-11-11 10:14:56 GMT mtk01084 +** modify place to invoke wlanIst +** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-10-30 18:17:07 GMT mtk01084 +** fix compiler warning +** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-10-29 19:46:15 GMT mtk01084 +** invoke interrupt process routine +** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-10-13 21:58:24 GMT mtk01084 +** modify for new HW architecture +** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-09-09 17:26:01 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-05-20 12:21:27 GMT mtk01461 +** Add SeqNum check when process Event Packet +** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-05-19 10:38:44 GMT mtk01461 +** Add wlanReleasePendingOid() for mpReset() if there is a pending OID and no available TX resource to send it. +** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-04-29 15:41:34 GMT mtk01461 +** Add handle of EVENT of CMD Result in wlanSendCommand() +** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-04-22 09:11:23 GMT mtk01461 +** Fix wlanSendCommand() for Driver Domain CR +** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-04-21 09:33:56 GMT mtk01461 +** Update wlanSendCommand() for Driver Domain Response and handle Event Packet, wlanQuery/SetInformation() for enqueue CMD_INFO_T +** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-04-17 20:00:08 GMT mtk01461 +** Update wlanImageSectionDownload for optimized CMD process +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-04-14 20:50:51 GMT mtk01426 +** Fixed compile error +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-04-13 16:38:40 GMT mtk01084 +** add wifi start function +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-04-13 14:26:44 GMT mtk01084 +** modify a parameter about FW download length +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-04-10 21:53:42 GMT mtk01461 +** Update wlanSendCommand() +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-08 16:51:04 GMT mtk01084 +** Update for the image download part +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-01 10:32:47 GMT mtk01461 +** Add wlanSendLeftClusteredFrames() for SDIO_TX_ENHANCE +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-03-23 21:44:13 GMT mtk01461 +** Refine TC assignment for WmmAssoc flag +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-03-23 16:51:57 GMT mtk01084 +** modify the input argument of caller to RECLAIM_POWER_CONTROL_TO_PM() +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-23 00:27:13 GMT mtk01461 +** Add reference code of FW Image Download +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-19 18:32:37 GMT mtk01084 +** update for basic power management functions +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:09:08 GMT mtk01461 +** Update TX PATH API +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 16:28:45 GMT mtk01426 +** Init develop +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" +#include "mgmt/ais_fsm.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* 6.1.1.2 Interpretation of priority parameter in MAC service primitives */ +/* Static convert the Priority Parameter/TID(User Priority/TS Identifier) to Traffic Class */ +const UINT_8 aucPriorityParam2TC[] = { + TC1_INDEX, + TC0_INDEX, + TC0_INDEX, + TC1_INDEX, + TC2_INDEX, + TC2_INDEX, + TC3_INDEX, + TC3_INDEX +}; + +#if QM_TEST_MODE +extern QUE_MGT_T g_rQM; +#endif +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +BOOLEAN fgIsBusAccessFailed = FALSE; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +// TODO: Check +/* OID set handlers without the need to access HW register */ +PFN_OID_HANDLER_FUNC apfnOidSetHandlerWOHwAccess[] = { + wlanoidSetChannel, + wlanoidSetBeaconInterval, + wlanoidSetAtimWindow, + wlanoidSetFrequency, +}; + +// TODO: Check +/* OID query handlers without the need to access HW register */ +PFN_OID_HANDLER_FUNC apfnOidQueryHandlerWOHwAccess[] = { + wlanoidQueryBssid, + wlanoidQuerySsid, + wlanoidQueryInfrastructureMode, + wlanoidQueryAuthMode, + wlanoidQueryEncryptionStatus, + wlanoidQueryPmkid, + wlanoidQueryNetworkTypeInUse, + wlanoidQueryBssidList, + wlanoidQueryAcpiDevicePowerState, + wlanoidQuerySupportedRates, + wlanoidQueryDesiredRates, + wlanoidQuery802dot11PowerSaveProfile, + wlanoidQueryBeaconInterval, + wlanoidQueryAtimWindow, + wlanoidQueryFrequency, +}; + +/* OID set handlers allowed in RF test mode */ +PFN_OID_HANDLER_FUNC apfnOidSetHandlerAllowedInRFTest[] = { + wlanoidRftestSetTestMode, + wlanoidRftestSetAbortTestMode, + wlanoidRftestSetAutoTest, + wlanoidSetMcrWrite, + wlanoidSetEepromWrite +}; + +/* OID query handlers allowed in RF test mode */ +PFN_OID_HANDLER_FUNC apfnOidQueryHandlerAllowedInRFTest[] = { + wlanoidRftestQueryAutoTest, + wlanoidQueryMcrRead, + wlanoidQueryEepromRead +} +; + +PFN_OID_HANDLER_FUNC apfnOidWOTimeoutCheck[] = { + wlanoidRftestSetTestMode, + wlanoidRftestSetAbortTestMode, + wlanoidSetAcpiDevicePowerState, +}; + + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is a private routine, which is used to check if HW access is needed +* for the OID query/ set handlers. +* +* \param[IN] pfnOidHandler Pointer to the OID handler. +* \param[IN] fgSetInfo It is a Set information handler. +* +* \retval TRUE This function needs HW access +* \retval FALSE This function does not need HW access +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +wlanIsHandlerNeedHwAccess ( + IN PFN_OID_HANDLER_FUNC pfnOidHandler, + IN BOOLEAN fgSetInfo + ) +{ + PFN_OID_HANDLER_FUNC* apfnOidHandlerWOHwAccess; + UINT_32 i; + UINT_32 u4NumOfElem; + + if (fgSetInfo) { + apfnOidHandlerWOHwAccess = apfnOidSetHandlerWOHwAccess; + u4NumOfElem = sizeof(apfnOidSetHandlerWOHwAccess) / sizeof(PFN_OID_HANDLER_FUNC); + } + else { + apfnOidHandlerWOHwAccess = apfnOidQueryHandlerWOHwAccess; + u4NumOfElem = sizeof(apfnOidQueryHandlerWOHwAccess) / sizeof(PFN_OID_HANDLER_FUNC); + } + + for (i = 0; i < u4NumOfElem; i++) { + if (apfnOidHandlerWOHwAccess[i] == pfnOidHandler) { + return FALSE; + } + } + + return TRUE; +} /* wlanIsHandlerNeedHwAccess */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set flag for later handling card +* ejected event. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* +* \return (none) +* +* \note When surprised removal happens, Glue layer should invoke this +* function to notify WPDD not to do any hw access. +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanCardEjected ( + IN P_ADAPTER_T prAdapter + ) +{ + DEBUGFUNC("wlanCardEjected"); + //INITLOG(("\n")); + + ASSERT(prAdapter); + + /* mark that the card is being ejected, NDIS will shut us down soon */ + nicTxRelease(prAdapter); + +} /* wlanCardEjected */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Create adapter object +* +* \param prAdapter This routine is call to allocate the driver software objects. +* If fails, return NULL. +* \retval NULL If it fails, NULL is returned. +* \retval NOT NULL If the adapter was initialized successfully. +*/ +/*----------------------------------------------------------------------------*/ +P_ADAPTER_T +wlanAdapterCreate ( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + P_ADAPTER_T prAdpater = (P_ADAPTER_T)NULL; + + DEBUGFUNC("wlanAdapterCreate"); + + do { + prAdpater = (P_ADAPTER_T) kalMemAlloc(sizeof(ADAPTER_T), VIR_MEM_TYPE); + + if (!prAdpater) { + DBGLOG(INIT, ERROR, ("Allocate ADAPTER memory ==> FAILED\n")); + break; + } + +#if QM_TEST_MODE + g_rQM.prAdapter = prAdpater; +#endif + kalMemZero(prAdpater, sizeof(ADAPTER_T)); + prAdpater->prGlueInfo = prGlueInfo; + + } while(FALSE); + + return prAdpater; +} /* wlanAdapterCreate */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Destroy adapter object +* +* \param prAdapter This routine is call to destroy the driver software objects. +* If fails, return NULL. +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanAdapterDestroy ( + IN P_ADAPTER_T prAdapter + ) +{ + + if (!prAdapter) { + return; + } + + kalMemFree(prAdapter, VIR_MEM_TYPE, sizeof(ADAPTER_T)); + + return; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Initialize the adapter. The sequence is +* 1. Disable interrupt +* 2. Read adapter configuration from EEPROM and registry, verify chip ID. +* 3. Create NIC Tx/Rx resource. +* 4. Initialize the chip +* 5. Initialize the protocol +* 6. Enable Interrupt +* +* \param prAdapter Pointer of Adapter Data Structure +* +* \retval WLAN_STATUS_SUCCESS: Success +* \retval WLAN_STATUS_FAILURE: Failed +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanAdapterStart ( + IN P_ADAPTER_T prAdapter, + IN P_REG_INFO_T prRegInfo, + IN PVOID pvFwImageMapFile, + IN UINT_32 u4FwImageFileLength + ) +{ + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + UINT_32 i, u4Value = 0; + UINT_32 u4WHISR = 0; + UINT_8 aucTxCount[8]; +#if CFG_ENABLE_FW_DOWNLOAD + UINT_32 u4FwLoadAddr, u4ImgSecSize; + #if CFG_ENABLE_FW_DIVIDED_DOWNLOAD + UINT_32 j; + P_FIRMWARE_DIVIDED_DOWNLOAD_T prFwHead; + BOOLEAN fgValidHead; + const UINT_32 u4CRCOffset = offsetof(FIRMWARE_DIVIDED_DOWNLOAD_T, u4NumOfEntries); + #endif +#endif +#if (defined(MT5931) && (!CFG_SUPPORT_BCM_BWCS)) + PARAM_PTA_IPC_T rBwcsPta; + UINT_32 u4SetInfoLen; +#endif + + ASSERT(prAdapter); + + DEBUGFUNC("wlanAdapterStart"); + + //4 <0> Reset variables in ADAPTER_T + prAdapter->fgIsFwOwn = TRUE; + prAdapter->fgIsEnterD3ReqIssued = FALSE; + + QUEUE_INITIALIZE(&(prAdapter->rPendingCmdQueue)); + + /* Initialize rWlanInfo */ + kalMemSet(&(prAdapter->rWlanInfo), 0, sizeof(WLAN_INFO_T)); + + //4 <0.1> reset fgIsBusAccessFailed + fgIsBusAccessFailed = FALSE; + + do { + if ( (u4Status = nicAllocateAdapterMemory(prAdapter)) != WLAN_STATUS_SUCCESS ) { + DBGLOG(INIT, ERROR, ("nicAllocateAdapterMemory Error!\n")); + u4Status = WLAN_STATUS_FAILURE; + break; + } + + prAdapter->u4OsPacketFilter = PARAM_PACKET_FILTER_SUPPORTED; + +#if defined(MT6620) || defined(MT6628) + DBGLOG(INIT, TRACE, ("wlanAdapterStart(): Acquiring LP-OWN\n")); + ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); + #if !CFG_ENABLE_FULL_PM + nicpmSetDriverOwn(prAdapter); + #endif + + if(prAdapter->fgIsFwOwn == TRUE) { + DBGLOG(INIT, ERROR, ("nicpmSetDriverOwn() failed!\n")); + u4Status = WLAN_STATUS_FAILURE; + break; + } + + //4 <1> Initialize the Adapter + if ( (u4Status = nicInitializeAdapter(prAdapter)) != WLAN_STATUS_SUCCESS ) { + DBGLOG(INIT, ERROR, ("nicInitializeAdapter failed!\n")); + u4Status = WLAN_STATUS_FAILURE; + break; + } +#endif + + //4 <2> Initialize System Service (MGMT Memory pool and STA_REC) + nicInitSystemService(prAdapter); + + //4 <3> Initialize Tx + nicTxInitialize(prAdapter); + wlanDefTxPowerCfg(prAdapter); + + //4 <4> Initialize Rx + nicRxInitialize(prAdapter); + +#if CFG_ENABLE_FW_DOWNLOAD + #if defined(MT6620) || defined(MT6628) + if (pvFwImageMapFile) { + /* 1. disable interrupt, download is done by polling mode only */ + nicDisableInterrupt(prAdapter); + + /* 2. Initialize Tx Resource to fw download state */ + nicTxInitResetResource(prAdapter); + + /* 3. FW download here */ + u4FwLoadAddr = prRegInfo->u4LoadAddress; + + #if CFG_ENABLE_FW_DIVIDED_DOWNLOAD + // 3a. parse file header for decision of divided firmware download or not + prFwHead = (P_FIRMWARE_DIVIDED_DOWNLOAD_T)pvFwImageMapFile; + + if(prFwHead->u4Signature == MTK_WIFI_SIGNATURE && + prFwHead->u4CRC == wlanCRC32((PUINT_8)pvFwImageMapFile + u4CRCOffset, u4FwImageFileLength - u4CRCOffset)) { + fgValidHead = TRUE; + } + else { + fgValidHead = FALSE; + } + + /* 3b. engage divided firmware downloading */ + if(fgValidHead == TRUE) { + for(i = 0 ; i < prFwHead->u4NumOfEntries ; i++) { + #if CFG_ENABLE_FW_DOWNLOAD_AGGREGATION + if(wlanImageSectionDownloadAggregated(prAdapter, + prFwHead->arSection[i].u4DestAddr, + prFwHead->arSection[i].u4Length, + (PUINT_8)pvFwImageMapFile + prFwHead->arSection[i].u4Offset) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, ("Firmware scatter download failed!\n")); + u4Status = WLAN_STATUS_FAILURE; + } + #else + for(j = 0 ; j < prFwHead->arSection[i].u4Length ; j += CMD_PKT_SIZE_FOR_IMAGE) { + if(j + CMD_PKT_SIZE_FOR_IMAGE < prFwHead->arSection[i].u4Length) + u4ImgSecSize = CMD_PKT_SIZE_FOR_IMAGE; + else + u4ImgSecSize = prFwHead->arSection[i].u4Length - j; + + if(wlanImageSectionDownload(prAdapter, + prFwHead->arSection[i].u4DestAddr + j, + u4ImgSecSize, + (PUINT_8)pvFwImageMapFile + prFwHead->arSection[i].u4Offset + j) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, ("Firmware scatter download failed!\n")); + u4Status = WLAN_STATUS_FAILURE; + break; + } + } + #endif + + /* escape from loop if any pending error occurs */ + if(u4Status == WLAN_STATUS_FAILURE) { + break; + } + } + } + else + #endif + #if CFG_ENABLE_FW_DOWNLOAD_AGGREGATION + if(wlanImageSectionDownloadAggregated(prAdapter, + u4FwLoadAddr, + u4FwImageFileLength, + (PUINT_8)pvFwImageMapFile) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, ("Firmware scatter download failed!\n")); + u4Status = WLAN_STATUS_FAILURE; + } + #else + for (i = 0; i < u4FwImageFileLength ; i += CMD_PKT_SIZE_FOR_IMAGE) { + if(i + CMD_PKT_SIZE_FOR_IMAGE < u4FwImageFileLength) + u4ImgSecSize = CMD_PKT_SIZE_FOR_IMAGE; + else + u4ImgSecSize = u4FwImageFileLength - i; + + if(wlanImageSectionDownload(prAdapter, + u4FwLoadAddr + i, + u4ImgSecSize, + (PUINT_8)pvFwImageMapFile + i) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, ("Firmware scatter download failed!\n")); + u4Status = WLAN_STATUS_FAILURE; + break; + } + } + #endif + + if(u4Status != WLAN_STATUS_SUCCESS) { + break; + } + + #if !CFG_ENABLE_FW_DOWNLOAD_ACK + // Send INIT_CMD_ID_QUERY_PENDING_ERROR command and wait for response + if(wlanImageQueryStatus(prAdapter) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, ("Firmware download failed!\n")); + u4Status = WLAN_STATUS_FAILURE; + break; + } + #endif + } + else { + DBGLOG(INIT, ERROR, ("No Firmware found!\n")); + u4Status = WLAN_STATUS_FAILURE; + break; + } + + /* 4. send Wi-Fi Start command */ + #if CFG_OVERRIDE_FW_START_ADDRESS + wlanConfigWifiFunc(prAdapter, + TRUE, + prRegInfo->u4StartAddress); + #else + wlanConfigWifiFunc(prAdapter, + FALSE, + 0); + #endif + #elif defined(MT5931) + if (pvFwImageMapFile) { + DBGLOG(INIT, TRACE, ("Download Address: 0x%08X\n", prRegInfo->u4LoadAddress)); + DBGLOG(INIT, TRACE, ("Firmware Length: 0x%08X\n", u4FwImageFileLength)); + + do { +#if CFG_SUPPORT_WHOLE_CHIP_RESET +#define RESET_RDY_INTERVAL (120) + + /* 1.0 whole-chip reset except HIFSYS */ + HAL_MCR_WR(prAdapter, MCR_WMCSR, WMCSR_CHIP_RST); + HAL_MCR_WR(prAdapter, MCR_WMCSR, 0); + + /* 1.0.1 delay for EEIF ready */ + kalMsleep(RESET_RDY_INTERVAL); +#endif + + /* 1.1 wait for INIT_RDY */ + i = 0; + while(1) { + HAL_MCR_RD(prAdapter, MCR_WMCSR, &u4Value); + + if (u4Value & WMCSR_INI_RDY) { + DBGLOG(INIT, TRACE, ("INIT-RDY detected\n")); + break; + } + else if(kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE + || fgIsBusAccessFailed == TRUE) { + u4Status = WLAN_STATUS_FAILURE; + break; + } + else if(i >= CFG_RESPONSE_POLLING_TIMEOUT) { + DBGLOG(INIT, ERROR, ("Waiting for Init Ready bit: Timeout\n")); + u4Status = WLAN_STATUS_FAILURE; + break; + } + else { + i++; + kalMsleep(10); + } + } + + if(u4Status != WLAN_STATUS_SUCCESS) { + break; + } + + /* 1.2 set KSEL/FLEN */ + HAL_MCR_WR(prAdapter, MCR_FWCFG, u4FwImageFileLength >> 6); + + /* 1.3 enable FWDL_EN */ + HAL_MCR_WR(prAdapter, MCR_WMCSR, WMCSR_FWDLEN); + + /* 1.4 wait for PLL_RDY */ + i = 0; + while(1) { + HAL_MCR_RD(prAdapter, MCR_WMCSR, &u4Value); + + if (u4Value & WMCSR_PLLRDY) { + DBGLOG(INIT, TRACE, ("PLL-RDY detected\n")); + break; + } + else if(kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE + || fgIsBusAccessFailed == TRUE) { + u4Status = WLAN_STATUS_FAILURE; + break; + } + else if(i >= CFG_RESPONSE_POLLING_TIMEOUT) { + DBGLOG(INIT, ERROR, ("Waiting for PLL Ready bit: Timeout\n")); + u4Status = WLAN_STATUS_FAILURE; + break; + } + else { + i++; + kalMsleep(10); + } + } + + if(u4Status != WLAN_STATUS_SUCCESS) { + break; + } + + /* 2.1 turn on HIFSYS firmware download mode */ + HAL_MCR_WR(prAdapter, MCR_FWDLSR, FWDLSR_FWDL_MODE); + + /* 2.2 set starting address */ + u4FwLoadAddr = prRegInfo->u4LoadAddress; + HAL_MCR_WR(prAdapter, MCR_FWDLDSAR, u4FwLoadAddr); + + /* 3. upload firmware */ + for (i = 0; i < u4FwImageFileLength ; i += CMD_PKT_SIZE_FOR_IMAGE) { + if(i + CMD_PKT_SIZE_FOR_IMAGE < u4FwImageFileLength) + u4ImgSecSize = CMD_PKT_SIZE_FOR_IMAGE; + else + u4ImgSecSize = u4FwImageFileLength - i; + + if(wlanImageSectionDownload(prAdapter, + u4FwLoadAddr + i, + u4ImgSecSize, + (PUINT_8)pvFwImageMapFile + i) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, ("Firmware scatter download failed!\n")); + u4Status = WLAN_STATUS_FAILURE; + break; + } + } + + if(u4Status != WLAN_STATUS_SUCCESS) { + break; + } + + /* 4.1 poll FWDL_OK & FWDL_FAIL bits */ + i = 0; + while(1) { + HAL_MCR_RD(prAdapter, MCR_WMCSR, &u4Value); + + if (u4Value & WMCSR_DL_OK) { + DBGLOG(INIT, TRACE, ("DL_OK detected\n")); + break; + } + else if(kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE + || fgIsBusAccessFailed == TRUE + || (u4Value & WMCSR_DL_FAIL)) { + DBGLOG(INIT, ERROR, ("DL_FAIL detected: 0x%08X\n", u4Value)); + u4Status = WLAN_STATUS_FAILURE; + break; + } + else if(i >= CFG_RESPONSE_POLLING_TIMEOUT) { + DBGLOG(INIT, ERROR, ("Waiting for DL_OK/DL_FAIL bit: Timeout\n")); + u4Status = WLAN_STATUS_FAILURE; + break; + } + else { + i++; + kalMsleep(10); + } + } + + if(u4Status != WLAN_STATUS_SUCCESS) { + break; + } + + /* 4.2 turn off HIFSYS download mode */ + HAL_MCR_WR(prAdapter, MCR_FWDLSR, 0); + + } while (FALSE); + + if(u4Status != WLAN_STATUS_SUCCESS) { + break; + } + + /* 5. disable interrupt */ + nicDisableInterrupt(prAdapter); + } + else { + DBGLOG(INIT, ERROR, ("No Firmware found!\n")); + u4Status = WLAN_STATUS_FAILURE; + break; + } + #endif +#endif + + DBGLOG(INIT, TRACE, ("wlanAdapterStart(): Waiting for Ready bit..\n")); + //4 <5> check Wi-Fi FW asserts ready bit + i = 0; + while(1) { + HAL_MCR_RD(prAdapter, MCR_WCIR, &u4Value); + + if (u4Value & WCIR_WLAN_READY) { + DBGLOG(INIT, TRACE, ("Ready bit asserted\n")); + break; + } + else if(kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE + || fgIsBusAccessFailed == TRUE) { + u4Status = WLAN_STATUS_FAILURE; + break; + } + else if(i >= CFG_RESPONSE_POLLING_TIMEOUT) { + UINT_32 u4MailBox0; + + nicGetMailbox(prAdapter, 0, &u4MailBox0); + DBGLOG(INIT, ERROR, ("Waiting for Ready bit: Timeout, ID=%d\n", + (u4MailBox0 & 0x0000FFFF))); + u4Status = WLAN_STATUS_FAILURE; + break; + } + else { + i++; + kalMsleep(10); + } + } + +#if defined(MT5931) + // Acquire LP-OWN + DBGLOG(INIT, TRACE, ("wlanAdapterStart(): Acquiring LP-OWN\n")); + ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); + #if !CFG_ENABLE_FULL_PM + nicpmSetDriverOwn(prAdapter); + #endif + + if(prAdapter->fgIsFwOwn == TRUE) { + DBGLOG(INIT, ERROR, ("nicpmSetDriverOwn() failed!\n")); + u4Status = WLAN_STATUS_FAILURE; + break; + } + + //4 <1> Initialize the Adapter + if ( (u4Status = nicInitializeAdapter(prAdapter)) != WLAN_STATUS_SUCCESS ) { + DBGLOG(INIT, ERROR, ("nicInitializeAdapter failed!\n")); + u4Status = WLAN_STATUS_FAILURE; + break; + } + + /* post initialization for MT5931 due to some CR is only accessible after driver own */ + nicRxPostInitialize(prAdapter); +#endif + + if(u4Status == WLAN_STATUS_SUCCESS) { + // 1. reset interrupt status + HAL_READ_INTR_STATUS(prAdapter, 4, (PUINT_8)&u4WHISR); + if(HAL_IS_TX_DONE_INTR(u4WHISR)) { + HAL_READ_TX_RELEASED_COUNT(prAdapter, aucTxCount); + } + + /* 2. reset TX Resource for normal operation */ + nicTxResetResource(prAdapter); + +#if CFG_SUPPORT_OSC_SETTING && defined(MT5931) + wlanSetMcuOscStableTime(prAdapter, 0); +#endif + + /* 3. query for permanent address by polling */ + wlanQueryPermanentAddress(prAdapter); + +#if (CFG_SUPPORT_NIC_CAPABILITY == 1) + /* 4. query for NIC capability */ + wlanQueryNicCapability(prAdapter); +#endif + + /* 5. Override network address */ + wlanUpdateNetworkAddress(prAdapter); + + /* 6. indicate disconnection as default status */ + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_DISCONNECT, + NULL, + 0); + } + + RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); + + if(u4Status != WLAN_STATUS_SUCCESS) { + break; + } + + /* OID timeout timer initialize */ + cnmTimerInitTimer(prAdapter, + &prAdapter->rOidTimeoutTimer, + (PFN_MGMT_TIMEOUT_FUNC)wlanReleasePendingOid, + (UINT_32)NULL); + + /* Power state initialization */ + prAdapter->fgWiFiInSleepyState = FALSE; + prAdapter->rAcpiState = ACPI_STATE_D0; + + /* Online scan option */ + if(prRegInfo->fgDisOnlineScan == 0) { + prAdapter->fgEnOnlineScan = TRUE; + } + else { + prAdapter->fgEnOnlineScan = FALSE; + } + + /* Beacon lost detection option */ + if(prRegInfo->fgDisBcnLostDetection != 0) { + prAdapter->fgDisBcnLostDetection = TRUE; + } + + /* Load compile time constant */ + prAdapter->rWlanInfo.u2BeaconPeriod = CFG_INIT_ADHOC_BEACON_INTERVAL; + prAdapter->rWlanInfo.u2AtimWindow = CFG_INIT_ADHOC_ATIM_WINDOW; + +#if 1// set PM parameters + prAdapter->fgEnArpFilter = prRegInfo->fgEnArpFilter; + prAdapter->u4PsCurrentMeasureEn = prRegInfo->u4PsCurrentMeasureEn; + + prAdapter->u4UapsdAcBmp = prRegInfo->u4UapsdAcBmp; + + prAdapter->u4MaxSpLen = prRegInfo->u4MaxSpLen; + + DBGLOG(INIT, TRACE, ("[1] fgEnArpFilter:0x%x, u4UapsdAcBmp:0x%x, u4MaxSpLen:0x%x", + prAdapter->fgEnArpFilter, + prAdapter->u4UapsdAcBmp, + prAdapter->u4MaxSpLen)); + + prAdapter->fgEnCtiaPowerMode = FALSE; + +#endif + + /* MGMT Initialization */ + nicInitMGMT(prAdapter, prRegInfo); + + /* Enable WZC Disassociation */ + prAdapter->rWifiVar.fgSupportWZCDisassociation = TRUE; + + /* Apply Rate Setting */ + if((ENUM_REGISTRY_FIXED_RATE_T)(prRegInfo->u4FixedRate) < FIXED_RATE_NUM) { + prAdapter->rWifiVar.eRateSetting = (ENUM_REGISTRY_FIXED_RATE_T)(prRegInfo->u4FixedRate); + } + else { + prAdapter->rWifiVar.eRateSetting = FIXED_RATE_NONE; + } + + if(prAdapter->rWifiVar.eRateSetting == FIXED_RATE_NONE) { + /* Enable Auto (Long/Short) Preamble */ + prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_AUTO; + } + else if((prAdapter->rWifiVar.eRateSetting >= FIXED_RATE_MCS0_20M_400NS && + prAdapter->rWifiVar.eRateSetting <= FIXED_RATE_MCS7_20M_400NS) + || (prAdapter->rWifiVar.eRateSetting >= FIXED_RATE_MCS0_40M_400NS && + prAdapter->rWifiVar.eRateSetting <= FIXED_RATE_MCS32_400NS)) { + /* Force Short Preamble */ + prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_SHORT; + } + else { + /* Force Long Preamble */ + prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_LONG; + } + + /* Disable Hidden SSID Join */ + prAdapter->rWifiVar.fgEnableJoinToHiddenSSID = FALSE; + + /* Enable Short Slot Time */ + prAdapter->rWifiVar.fgIsShortSlotTimeOptionEnable = TRUE; + + /* configure available PHY type set */ + nicSetAvailablePhyTypeSet(prAdapter); + +#if 1// set PM parameters + { +#if CFG_SUPPORT_PWR_MGT + prAdapter->u4PowerMode = prRegInfo->u4PowerMode; + prAdapter->rWlanInfo.arPowerSaveMode[NETWORK_TYPE_P2P_INDEX].ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; + prAdapter->rWlanInfo.arPowerSaveMode[NETWORK_TYPE_P2P_INDEX].ucPsProfile = ENUM_PSP_FAST_SWITCH; +#else + prAdapter->u4PowerMode = ENUM_PSP_CONTINUOUS_ACTIVE; +#endif + + nicConfigPowerSaveProfile( + prAdapter, + NETWORK_TYPE_AIS_INDEX, //FIXIT + prAdapter->u4PowerMode, + FALSE); + } + +#endif + +#if CFG_SUPPORT_NVRAM + /* load manufacture data */ + wlanLoadManufactureData(prAdapter, prRegInfo); +#endif + +#if (defined(MT5931) && (!CFG_SUPPORT_BCM_BWCS)) + //Enable DPD calibration. + rBwcsPta.u.aucBTPParams[0] = 0x00; + rBwcsPta.u.aucBTPParams[1] = 0x01; + rBwcsPta.u.aucBTPParams[2] = 0x00; + rBwcsPta.u.aucBTPParams[3] = 0x80; + + wlanoidSetBT(prAdapter, + (PVOID)&rBwcsPta, + sizeof(PARAM_PTA_IPC_T), + &u4SetInfoLen); +#endif + +#if 0 + /* Update Auto rate parameters in FW */ + nicRlmArUpdateParms(prAdapter, + prRegInfo->u4ArSysParam0, + prRegInfo->u4ArSysParam1, + prRegInfo->u4ArSysParam2, + prRegInfo->u4ArSysParam3); +#endif + + +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) + /* clock gating workaround */ + prAdapter->fgIsClockGatingEnabled = FALSE; +#endif + + } while(FALSE); + + if(u4Status == WLAN_STATUS_SUCCESS) { + // restore to hardware default + HAL_SET_INTR_STATUS_READ_CLEAR(prAdapter); + HAL_SET_MAILBOX_READ_CLEAR(prAdapter, FALSE); + + /* Enable interrupt */ + nicEnableInterrupt(prAdapter); + + } + else { + // release allocated memory + nicReleaseAdapterMemory(prAdapter); + } + + return u4Status; +} /* wlanAdapterStart */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Uninitialize the adapter +* +* \param prAdapter Pointer of Adapter Data Structure +* +* \retval WLAN_STATUS_SUCCESS: Success +* \retval WLAN_STATUS_FAILURE: Failed +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanAdapterStop ( + IN P_ADAPTER_T prAdapter + ) +{ + UINT_32 i, u4Value = 0; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) + if(prAdapter->fgIsClockGatingEnabled == TRUE) { + nicDisableClockGating(prAdapter); + } +#endif + + /* MGMT - unitialization */ + nicUninitMGMT(prAdapter); + + if(prAdapter->rAcpiState == ACPI_STATE_D0 && +#if (CFG_CHIP_RESET_SUPPORT == 1) + kalIsResetting() == FALSE && +#endif + kalIsCardRemoved(prAdapter->prGlueInfo) == FALSE) { + + /* 0. Disable interrupt, this can be done without Driver own */ + nicDisableInterrupt(prAdapter); + + ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); + + /* 1. Set CMD to FW to tell WIFI to stop (enter power off state) */ + if(prAdapter->fgIsFwOwn == FALSE && + wlanSendNicPowerCtrlCmd(prAdapter, 1) == WLAN_STATUS_SUCCESS) { + /* 2. Clear pending interrupt */ + i = 0; + while(i < CFG_IST_LOOP_COUNT && nicProcessIST(prAdapter) != WLAN_STATUS_NOT_INDICATING) { + i++; + }; + + /* 3. Wait til RDY bit has been cleaerd */ + i = 0; + while(1) { + HAL_MCR_RD(prAdapter, MCR_WCIR, &u4Value); + + if ((u4Value & WCIR_WLAN_READY) == 0) + break; + else if(kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE + || fgIsBusAccessFailed == TRUE + || i >= CFG_RESPONSE_POLLING_TIMEOUT) { + break; + } + else { + i++; + kalMsleep(10); + } + } + } + + /* 4. Set Onwership to F/W */ + nicpmSetFWOwn(prAdapter, FALSE); + + RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); + } + + nicRxUninitialize(prAdapter); + + nicTxRelease(prAdapter); + + /* System Service Uninitialization */ + nicUninitSystemService(prAdapter); + + nicReleaseAdapterMemory(prAdapter); + +#if defined(_HIF_SPI) + /* Note: restore the SPI Mode Select from 32 bit to default */ + nicRestoreSpiDefMode(prAdapter); +#endif + + return u4Status; +} /* wlanAdapterStop */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called by ISR (interrupt). +* +* \param prAdapter Pointer of Adapter Data Structure +* +* \retval TRUE: NIC's interrupt +* \retval FALSE: Not NIC's interrupt +*/ +/*----------------------------------------------------------------------------*/ +BOOL +wlanISR ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgGlobalIntrCtrl + ) +{ + ASSERT(prAdapter); + + if (fgGlobalIntrCtrl) { + nicDisableInterrupt(prAdapter); + + //wlanIST(prAdapter); + } + + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called by IST (task_let). +* +* \param prAdapter Pointer of Adapter Data Structure +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanIST ( + IN P_ADAPTER_T prAdapter + ) +{ + ASSERT(prAdapter); + + ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); + + nicProcessIST(prAdapter); + + nicEnableInterrupt(prAdapter); + + RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will check command queue to find out if any could be dequeued +* and/or send to HIF to MT6620 +* +* \param prAdapter Pointer of Adapter Data Structure +* \param prCmdQue Pointer of Command Queue (in Glue Layer) +* +* \retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanProcessCommandQueue ( + IN P_ADAPTER_T prAdapter, + IN P_QUE_T prCmdQue + ) +{ + WLAN_STATUS rStatus; + QUE_T rTempCmdQue, rMergeCmdQue, rStandInCmdQue; + P_QUE_T prTempCmdQue, prMergeCmdQue, prStandInCmdQue; + P_QUE_ENTRY_T prQueueEntry; + P_CMD_INFO_T prCmdInfo; + P_MSDU_INFO_T prMsduInfo; + ENUM_FRAME_ACTION_T eFrameAction = FRAME_ACTION_DROP_PKT; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + ASSERT(prCmdQue); + + prTempCmdQue = &rTempCmdQue; + prMergeCmdQue = &rMergeCmdQue; + prStandInCmdQue = &rStandInCmdQue; + + QUEUE_INITIALIZE(prTempCmdQue); + QUEUE_INITIALIZE(prMergeCmdQue); + QUEUE_INITIALIZE(prStandInCmdQue); + + //4 <1> Move whole list of CMD_INFO to temp queue + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_QUE); + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_QUE); + + //4 <2> Dequeue from head and check it is able to be sent + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while(prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + + switch(prCmdInfo->eCmdType) { + case COMMAND_TYPE_GENERAL_IOCTL: + case COMMAND_TYPE_NETWORK_IOCTL: + /* command packet will be always sent */ + eFrameAction = FRAME_ACTION_TX_PKT; + break; + + case COMMAND_TYPE_SECURITY_FRAME: + /* inquire with QM */ + eFrameAction = qmGetFrameAction(prAdapter, + prCmdInfo->eNetworkType, + prCmdInfo->ucStaRecIndex, + NULL, + FRAME_TYPE_802_1X); + break; + + case COMMAND_TYPE_MANAGEMENT_FRAME: + /* inquire with QM */ + prMsduInfo = (P_MSDU_INFO_T)(prCmdInfo->prPacket); + + eFrameAction = qmGetFrameAction(prAdapter, + prMsduInfo->ucNetworkType, + prMsduInfo->ucStaRecIndex, + prMsduInfo, + FRAME_TYPE_MMPDU); + break; + + default: + ASSERT(0); + break; + } + + //4 <3> handling upon dequeue result + if(eFrameAction == FRAME_ACTION_DROP_PKT) { + wlanReleaseCommand(prAdapter, prCmdInfo); + } + else if(eFrameAction == FRAME_ACTION_QUEUE_PKT) { + QUEUE_INSERT_TAIL(prMergeCmdQue, prQueueEntry); + } + else if(eFrameAction == FRAME_ACTION_TX_PKT) { + //4 <4> Send the command + rStatus = wlanSendCommand(prAdapter, prCmdInfo); + + if(rStatus == WLAN_STATUS_RESOURCES) { + // no more TC4 resource for further transmission + QUEUE_INSERT_TAIL(prMergeCmdQue, prQueueEntry); + break; + } + else if(rStatus == WLAN_STATUS_PENDING) { + // command packet which needs further handling upon response + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); + QUEUE_INSERT_TAIL(&(prAdapter->rPendingCmdQueue), prQueueEntry); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); + } + else { + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + + if (rStatus == WLAN_STATUS_SUCCESS) { + if (prCmdInfo->pfCmdDoneHandler) { + prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prCmdInfo->pucInfoBuffer); + } + } + else { + if (prCmdInfo->fgIsOid) { + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, prCmdInfo->u4SetInfoLen, rStatus); + } + } + + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } + } + else { + ASSERT(0); + } + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + + //4 <3> Merge back to original queue + //4 <3.1> Merge prMergeCmdQue & prTempCmdQue + QUEUE_CONCATENATE_QUEUES(prMergeCmdQue, prTempCmdQue); + + //4 <3.2> Move prCmdQue to prStandInQue, due to prCmdQue might differ due to incoming 802.1X frames + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_QUE); + QUEUE_MOVE_ALL(prStandInCmdQue, prCmdQue); + + //4 <3.3> concatenate prStandInQue to prMergeCmdQue + QUEUE_CONCATENATE_QUEUES(prMergeCmdQue, prStandInCmdQue); + + //4 <3.4> then move prMergeCmdQue to prCmdQue + QUEUE_MOVE_ALL(prCmdQue, prMergeCmdQue); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_QUE); + + return WLAN_STATUS_SUCCESS; +} /* end of wlanProcessCommandQueue() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will take CMD_INFO_T which carry some informations of +* incoming OID and notify the NIC_TX to send CMD. +* +* \param prAdapter Pointer of Adapter Data Structure +* \param prCmdInfo Pointer of P_CMD_INFO_T +* +* \retval WLAN_STATUS_SUCCESS : CMD was written to HIF and be freed(CMD Done) immediately. +* \retval WLAN_STATUS_RESOURCE : No resource for current command, need to wait for previous +* frame finishing their transmission. +* \retval WLAN_STATUS_FAILURE : Get failure while access HIF or been rejected. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanSendCommand ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo + ) +{ + P_TX_CTRL_T prTxCtrl; + UINT_8 ucTC; /* "Traffic Class" SW(Driver) resource classification */ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + prTxCtrl = &prAdapter->rTxCtrl; + + //DbgPrint("wlanSendCommand()\n"); + // + // +#if DBG && 0 + LOG_FUNC("wlanSendCommand()\n"); + LOG_FUNC("CmdType %u NetworkType %u StaRecIndex %u Oid %u CID 0x%x SetQuery %u NeedResp %u CmdSeqNum %u\n", + prCmdInfo->eCmdType, + prCmdInfo->eNetworkType, + prCmdInfo->ucStaRecIndex, + prCmdInfo->fgIsOid, + prCmdInfo->ucCID, + prCmdInfo->fgSetQuery, + prCmdInfo->fgNeedResp, + prCmdInfo->ucCmdSeqNum); +#endif + +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) + if(prAdapter->fgIsClockGatingEnabled == TRUE) { + nicDisableClockGating(prAdapter); + } +#endif + + do { + // <0> card removal check + if(kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE + || fgIsBusAccessFailed == TRUE) { + rStatus = WLAN_STATUS_FAILURE; + break; + } + + // <1> Normal case of sending CMD Packet + if (!prCmdInfo->fgDriverDomainMCR) { + // <1.1> Assign Traffic Class(TC) = TC4. + ucTC = TC4_INDEX; + + // <1.2> Check if pending packet or resource was exhausted + if ((rStatus = nicTxAcquireResource(prAdapter, ucTC)) == WLAN_STATUS_RESOURCES) { + DbgPrint("NO Resource:%d\n", ucTC); + break; + } + + // <1.3> Forward CMD_INFO_T to NIC Layer + rStatus = nicTxCmd(prAdapter, prCmdInfo, ucTC); + + // <1.4> Set Pending in response to Query Command/Need Response + if (rStatus == WLAN_STATUS_SUCCESS) { + if ((!prCmdInfo->fgSetQuery) || (prCmdInfo->fgNeedResp)) { + rStatus = WLAN_STATUS_PENDING; + } + } + } + // <2> Special case for access Driver Domain MCR + else { + P_CMD_ACCESS_REG prCmdAccessReg; + prCmdAccessReg = (P_CMD_ACCESS_REG)(prCmdInfo->pucInfoBuffer + CMD_HDR_SIZE); + + if (prCmdInfo->fgSetQuery) { + HAL_MCR_WR(prAdapter, + (prCmdAccessReg->u4Address & BITS(2,31)), //address is in DWORD unit + prCmdAccessReg->u4Data); + } + else { + P_CMD_ACCESS_REG prEventAccessReg; + UINT_32 u4Address; + + u4Address = prCmdAccessReg->u4Address; + prEventAccessReg = (P_CMD_ACCESS_REG)prCmdInfo->pucInfoBuffer; + prEventAccessReg->u4Address = u4Address; + + HAL_MCR_RD(prAdapter, + prEventAccessReg->u4Address & BITS(2,31), //address is in DWORD unit + &prEventAccessReg->u4Data); + } + } + + } + while (FALSE); + +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) + if(prAdapter->fgIsClockGatingEnabled == FALSE) { + nicEnableClockGating(prAdapter); + } +#endif + + return rStatus; +} /* end of wlanSendCommand() */ + + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function will release thd CMD_INFO upon its attribution + * + * \param prAdapter Pointer of Adapter Data Structure + * \param prCmdInfo Pointer of CMD_INFO_T + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +VOID +wlanReleaseCommand ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo + ) +{ + P_TX_CTRL_T prTxCtrl; + P_MSDU_INFO_T prMsduInfo; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prTxCtrl = &prAdapter->rTxCtrl; + + switch(prCmdInfo->eCmdType) { + case COMMAND_TYPE_GENERAL_IOCTL: + case COMMAND_TYPE_NETWORK_IOCTL: + if (prCmdInfo->fgIsOid) { + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, + prCmdInfo->u4SetInfoLen, + WLAN_STATUS_FAILURE); + } + break; + + case COMMAND_TYPE_SECURITY_FRAME: + kalSecurityFrameSendComplete(prAdapter->prGlueInfo, + prCmdInfo->prPacket, + WLAN_STATUS_FAILURE); + break; + + case COMMAND_TYPE_MANAGEMENT_FRAME: + prMsduInfo = (P_MSDU_INFO_T)prCmdInfo->prPacket; + + /* invoke callbacks */ + if(prMsduInfo->pfTxDoneHandler != NULL) { + prMsduInfo->pfTxDoneHandler(prAdapter, prMsduInfo, TX_RESULT_DROPPED_IN_DRIVER); + } + + GLUE_DEC_REF_CNT(prTxCtrl->i4TxMgmtPendingNum); + cnmMgtPktFree(prAdapter, prMsduInfo); + break; + + default: + ASSERT(0); + break; + } + + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + +} /* end of wlanReleaseCommand() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will search the CMD Queue to look for the pending OID and +* compelete it immediately when system request a reset. +* +* \param prAdapter ointer of Adapter Data Structure +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanReleasePendingOid ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Data + ) +{ + P_QUE_T prCmdQue; + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T)NULL; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + do { + // 1: Clear Pending OID in prAdapter->rPendingCmdQueue + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); + + prCmdQue = &prAdapter->rPendingCmdQueue; + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + + if (prCmdInfo->fgIsOid) { + if (prCmdInfo->pfCmdTimeoutHandler) { + prCmdInfo->pfCmdTimeoutHandler(prAdapter, prCmdInfo); + } + else + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, + 0, + WLAN_STATUS_FAILURE); + + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } + else { + QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); + } + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); + + // 2: Clear pending OID in glue layer command queue + kalOidCmdClearance(prAdapter->prGlueInfo); + + // 3: Clear pending OID queued in pvOidEntry with REQ_FLAG_OID set + kalOidClearance(prAdapter->prGlueInfo); + + } while(FALSE); + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will search the CMD Queue to look for the pending CMD/OID for specific +* NETWORK TYPE and compelete it immediately when system request a reset. +* +* \param prAdapter ointer of Adapter Data Structure +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanReleasePendingCMDbyNetwork ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType + ) +{ + P_QUE_T prCmdQue; + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T)NULL; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + do { + // 1: Clear Pending OID in prAdapter->rPendingCmdQueue + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); + + prCmdQue = &prAdapter->rPendingCmdQueue; + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + + DBGLOG(P2P, TRACE, ("Pending CMD for Network Type:%d \n", prCmdInfo->eNetworkType)); + + if (prCmdInfo->eNetworkType == eNetworkType) { + if (prCmdInfo->pfCmdTimeoutHandler) { + prCmdInfo->pfCmdTimeoutHandler(prAdapter, prCmdInfo); + } + else + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, + 0, + WLAN_STATUS_FAILURE); + + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } + else { + QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); + } + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); + + + } while(FALSE); + + return; +} /* wlanReleasePendingCMDbyNetwork */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Return the packet buffer and reallocate one to the RFB +* +* \param prAdapter Pointer of Adapter Data Structure +* \param pvPacket Pointer of returned packet +* +* \retval WLAN_STATUS_SUCCESS: Success +* \retval WLAN_STATUS_FAILURE: Failed +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanReturnPacket ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvPacket + ) +{ + P_RX_CTRL_T prRxCtrl; + P_SW_RFB_T prSwRfb = NULL; + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("wlanReturnPacket"); + + ASSERT(prAdapter); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + if (pvPacket) { + kalPacketFree(prAdapter->prGlueInfo, pvPacket); + RX_ADD_CNT(prRxCtrl, RX_DATA_RETURNED_COUNT, 1); +#if CFG_NATIVE_802_11 + if (GLUE_TEST_FLAG(prAdapter->prGlueInfo, GLUE_FLAG_HALT)) { + } +#endif + } + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_REMOVE_HEAD(&prRxCtrl->rIndicatedRfbList, prSwRfb, P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + if (!prSwRfb){ + ASSERT(0); + return; + } + + if (nicRxSetupRFB(prAdapter, prSwRfb)){ + ASSERT(0); + return; + } + nicRxReturnRFB(prAdapter, prSwRfb); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is a required function that returns information about +* the capabilities and status of the driver and/or its network adapter. +* +* \param[IN] prAdapter Pointer to the Adapter structure. +* \param[IN] pfnOidQryHandler Function pointer for the OID query handler. +* \param[IN] pvInfoBuf Points to a buffer for return the query information. +* \param[IN] u4QueryBufferLen Specifies the number of bytes at pvInfoBuf. +* \param[OUT] pu4QueryInfoLen Points to the number of bytes it written or is needed. +* +* \retval WLAN_STATUS_xxx Different WLAN_STATUS code returned by different handlers. +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanQueryInformation ( + IN P_ADAPTER_T prAdapter, + IN PFN_OID_HANDLER_FUNC pfnOidQryHandler, + IN PVOID pvInfoBuf, + IN UINT_32 u4InfoBufLen, + OUT PUINT_32 pu4QryInfoLen + ) +{ + WLAN_STATUS status = WLAN_STATUS_FAILURE; + + ASSERT(prAdapter); + ASSERT(pu4QryInfoLen); + + // ignore any OID request after connected, under PS current measurement mode + if (prAdapter->u4PsCurrentMeasureEn && + (prAdapter->prGlueInfo->eParamMediaStateIndicated == PARAM_MEDIA_STATE_CONNECTED)) { + return WLAN_STATUS_SUCCESS; // note: return WLAN_STATUS_FAILURE or WLAN_STATUS_SUCCESS for blocking OIDs during current measurement ?? + } + +#if 1 + /* most OID handler will just queue a command packet */ + status = pfnOidQryHandler(prAdapter, + pvInfoBuf, + u4InfoBufLen, + pu4QryInfoLen); +#else + if (wlanIsHandlerNeedHwAccess(pfnOidQryHandler, FALSE)) { + ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); + + /* Reset sleepy state */ + if(prAdapter->fgWiFiInSleepyState == TRUE) { + prAdapter->fgWiFiInSleepyState = FALSE; + } + + status = pfnOidQryHandler(prAdapter, + pvInfoBuf, + u4InfoBufLen, + pu4QryInfoLen); + + RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); + } + else { + status = pfnOidQryHandler(prAdapter, + pvInfoBuf, + u4InfoBufLen, + pu4QryInfoLen); + } +#endif + + return status; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is a required function that allows bound protocol drivers, +* or NDIS, to request changes in the state information that the miniport +* maintains for particular object identifiers, such as changes in multicast +* addresses. +* +* \param[IN] prAdapter Pointer to the Glue info structure. +* \param[IN] pfnOidSetHandler Points to the OID set handlers. +* \param[IN] pvInfoBuf Points to a buffer containing the OID-specific data for the set. +* \param[IN] u4InfoBufLen Specifies the number of bytes at prSetBuffer. +* \param[OUT] pu4SetInfoLen Points to the number of bytes it read or is needed. +* +* \retval WLAN_STATUS_xxx Different WLAN_STATUS code returned by different handlers. +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanSetInformation ( + IN P_ADAPTER_T prAdapter, + IN PFN_OID_HANDLER_FUNC pfnOidSetHandler, + IN PVOID pvInfoBuf, + IN UINT_32 u4InfoBufLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + WLAN_STATUS status = WLAN_STATUS_FAILURE; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + // ignore any OID request after connected, under PS current measurement mode + if (prAdapter->u4PsCurrentMeasureEn && + (prAdapter->prGlueInfo->eParamMediaStateIndicated == PARAM_MEDIA_STATE_CONNECTED)) { + return WLAN_STATUS_SUCCESS; // note: return WLAN_STATUS_FAILURE or WLAN_STATUS_SUCCESS for blocking OIDs during current measurement ?? + } + +#if 1 + /* most OID handler will just queue a command packet + * for power state transition OIDs, handler will acquire power control by itself + */ + status = pfnOidSetHandler(prAdapter, + pvInfoBuf, + u4InfoBufLen, + pu4SetInfoLen); +#else + if (wlanIsHandlerNeedHwAccess(pfnOidSetHandler, TRUE)) { + ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); + + /* Reset sleepy state */ + if(prAdapter->fgWiFiInSleepyState == TRUE) { + prAdapter->fgWiFiInSleepyState = FALSE; + } + + status = pfnOidSetHandler(prAdapter, + pvInfoBuf, + u4InfoBufLen, + pu4SetInfoLen); + + RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); + } + else { + status = pfnOidSetHandler(prAdapter, + pvInfoBuf, + u4InfoBufLen, + pu4SetInfoLen); + } +#endif + + return status; +} + + +#if CFG_SUPPORT_WAPI +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is a used to query driver's config wapi mode or not +* +* \param[IN] prAdapter Pointer to the Glue info structure. +* +* \retval TRUE for use wapi mode +* +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +wlanQueryWapiMode ( + IN P_ADAPTER_T prAdapter + ) +{ + ASSERT(prAdapter); + + return prAdapter->rWifiVar.rConnSettings.fgWapiMode; +} +#endif + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called to set RX filter to Promiscuous Mode. +* +* \param[IN] prAdapter Pointer to the Adapter structure. +* \param[IN] fgEnablePromiscuousMode Enable/ disable RX Promiscuous Mode. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanSetPromiscuousMode ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgEnablePromiscuousMode + ) +{ + ASSERT(prAdapter); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called to set RX filter to allow to receive +* broadcast address packets. +* +* \param[IN] prAdapter Pointer to the Adapter structure. +* \param[IN] fgEnableBroadcast Enable/ disable broadcast packet to be received. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanRxSetBroadcast ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgEnableBroadcast + ) +{ + ASSERT(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called to send out CMD_NIC_POWER_CTRL command packet +* +* \param[IN] prAdapter Pointer to the Adapter structure. +* \param[IN] ucPowerMode refer to CMD/EVENT document +* +* \return WLAN_STATUS_SUCCESS +* \return WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanSendNicPowerCtrlCmd ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucPowerMode + ) +{ + WLAN_STATUS status = WLAN_STATUS_SUCCESS; + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + UINT_8 ucTC, ucCmdSeqNum; + + ASSERT(prAdapter); + + prGlueInfo = prAdapter->prGlueInfo; + + /* 1. Prepare CMD */ + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_NIC_POWER_CTRL))); + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, ("Allocate CMD_INFO_T ==> FAILED.\n")); + return WLAN_STATUS_FAILURE; + } + + /* 2.1 increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + DBGLOG(REQ, TRACE, ("ucCmdSeqNum =%d\n", ucCmdSeqNum)); + + /* 2.2 Setup common CMD Info Packet */ + prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; + prCmdInfo->u2InfoBufLen = (UINT_16)(CMD_HDR_SIZE + sizeof(CMD_NIC_POWER_CTRL)); + prCmdInfo->pfCmdDoneHandler = NULL; + prCmdInfo->pfCmdTimeoutHandler = NULL; + prCmdInfo->fgIsOid = TRUE; + prCmdInfo->ucCID = CMD_ID_NIC_POWER_CTRL; + prCmdInfo->fgSetQuery = TRUE; + prCmdInfo->fgNeedResp = FALSE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = sizeof(CMD_NIC_POWER_CTRL); + + /* 2.3 Setup WIFI_CMD_T */ + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + kalMemZero(prWifiCmd->aucBuffer, sizeof(CMD_NIC_POWER_CTRL)); + ((P_CMD_NIC_POWER_CTRL)(prWifiCmd->aucBuffer))->ucPowerMode = ucPowerMode; + + /* 3. Issue CMD for entering specific power mode */ + ucTC = TC4_INDEX; + + while(1) { + // 3.0 Removal check + if(kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE + || fgIsBusAccessFailed == TRUE) { + status = WLAN_STATUS_FAILURE; + break; + } + + // 3.1 Acquire TX Resource + if (nicTxAcquireResource(prAdapter, ucTC) == WLAN_STATUS_RESOURCES) { + if (nicTxPollingResource(prAdapter, ucTC) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR,("Fail to get TX resource return within timeout\n")); + status = WLAN_STATUS_FAILURE; + break; + } + else { + continue; + } + } + + // 3.2 Send CMD Info Packet + if (nicTxCmd(prAdapter, prCmdInfo, ucTC) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR,("Fail to transmit CMD_NIC_POWER_CTRL command\n")); + status = WLAN_STATUS_FAILURE; + } + + break; + }; + + // 4. Free CMD Info Packet. + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + // 5. Add flag + if(ucPowerMode == 1) { + prAdapter->fgIsEnterD3ReqIssued = TRUE; + } + + return status; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called to check if it is RF test mode and +* the OID is allowed to be called or not +* +* \param[IN] prAdapter Pointer to the Adapter structure. +* \param[IN] fgEnableBroadcast Enable/ disable broadcast packet to be received. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +wlanIsHandlerAllowedInRFTest ( + IN PFN_OID_HANDLER_FUNC pfnOidHandler, + IN BOOLEAN fgSetInfo + ) +{ + PFN_OID_HANDLER_FUNC* apfnOidHandlerAllowedInRFTest; + UINT_32 i; + UINT_32 u4NumOfElem; + + if (fgSetInfo) { + apfnOidHandlerAllowedInRFTest = apfnOidSetHandlerAllowedInRFTest; + u4NumOfElem = sizeof(apfnOidSetHandlerAllowedInRFTest) / sizeof(PFN_OID_HANDLER_FUNC); + } + else { + apfnOidHandlerAllowedInRFTest = apfnOidQueryHandlerAllowedInRFTest; + u4NumOfElem = sizeof(apfnOidQueryHandlerAllowedInRFTest) / sizeof(PFN_OID_HANDLER_FUNC); + } + + for (i = 0; i < u4NumOfElem; i++) { + if (apfnOidHandlerAllowedInRFTest[i] == pfnOidHandler) { + return TRUE; + } + } + + return FALSE; +} + +#if CFG_ENABLE_FW_DOWNLOAD + #if CFG_ENABLE_FW_DOWNLOAD_AGGREGATION +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to download FW image in an aggregated way +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanImageSectionDownloadAggregated ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4DestAddr, + IN UINT_32 u4ImgSecSize, + IN PUINT_8 pucImgSecBuf + ) +{ + #if defined(MT6620) || defined(MT6628) + P_CMD_INFO_T prCmdInfo; + P_INIT_HIF_TX_HEADER_T prInitHifTxHeader; + P_INIT_CMD_DOWNLOAD_BUF prInitCmdDownloadBuf; + UINT_8 ucTC, ucCmdSeqNum; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + PUINT_8 pucOutputBuf = (PUINT_8)NULL; /* Pointer to Transmit Data Structure Frame */ + UINT_32 u4PktCnt, u4Offset, u4Length; + UINT_32 u4TotalLength; + + ASSERT(prAdapter); + ASSERT(pucImgSecBuf); + + pucOutputBuf = prAdapter->rTxCtrl.pucTxCoalescingBufPtr; + + DEBUGFUNC("wlanImageSectionDownloadAggregated"); + + if (u4ImgSecSize == 0) { + return WLAN_STATUS_SUCCESS; + } + + // 1. Allocate CMD Info Packet and Pre-fill Headers + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, + sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF) + CMD_PKT_SIZE_FOR_IMAGE); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, ("Allocate CMD_INFO_T ==> FAILED.\n")); + return WLAN_STATUS_FAILURE; + } + + prCmdInfo->u2InfoBufLen = + sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF) + CMD_PKT_SIZE_FOR_IMAGE; + + // 2. Use TC0's resource to download image. (only TC0 is allowed) + ucTC = TC0_INDEX; + + // 3. Setup common CMD Info Packet + prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T)(prCmdInfo->pucInfoBuffer); + prInitHifTxHeader->ucEtherTypeOffset = 0; + prInitHifTxHeader->ucCSflags = 0; + prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_DOWNLOAD_BUF; + + // 4. Setup CMD_DOWNLOAD_BUF + prInitCmdDownloadBuf = (P_INIT_CMD_DOWNLOAD_BUF)(prInitHifTxHeader->rInitWifiCmd.aucBuffer); + prInitCmdDownloadBuf->u4DataMode = 0 + #if CFG_ENABLE_FW_ENCRYPTION + | DOWNLOAD_BUF_ENCRYPTION_MODE + #endif + ; + + // 5.0 reset loop control variable + u4TotalLength = 0; + u4Offset = u4PktCnt = 0; + + // 5.1 main loop for maximize transmission count per access + while(u4Offset < u4ImgSecSize) { + if(nicTxAcquireResource(prAdapter, ucTC) == WLAN_STATUS_SUCCESS) { + // 5.1.1 calculate u4Length + if(u4Offset + CMD_PKT_SIZE_FOR_IMAGE < u4ImgSecSize) { + u4Length = CMD_PKT_SIZE_FOR_IMAGE; + } + else { + u4Length = u4ImgSecSize - u4Offset; + } + + // 5.1.1 increase command sequence number + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum; + + // 5.1.2 update HIF TX hardware header + prInitHifTxHeader->u2TxByteCount = ALIGN_4(sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF) + (UINT_16)u4Length); + + // 5.1.3 fill command header + prInitCmdDownloadBuf->u4Address = u4DestAddr + u4Offset; + prInitCmdDownloadBuf->u4Length = u4Length; + prInitCmdDownloadBuf->u4CRC32 = wlanCRC32(pucImgSecBuf + u4Offset, u4Length); + + // 5.1.4.1 copy header to coalescing buffer + kalMemCopy(pucOutputBuf + u4TotalLength, + (PVOID)prCmdInfo->pucInfoBuffer, + sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF)); + + // 5.1.4.2 copy payload to coalescing buffer + kalMemCopy(pucOutputBuf + u4TotalLength + sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF), + pucImgSecBuf + u4Offset, + u4Length); + + // 5.1.4.3 update length and other variables + u4TotalLength += ALIGN_4(sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF) + u4Length); + u4Offset += u4Length; + u4PktCnt++; + + if(u4Offset < u4ImgSecSize) { + continue; + } + } + else if(u4PktCnt == 0) { + /* no resource, so get some back */ + if (nicTxPollingResource(prAdapter, ucTC) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR,("Fail to get TX resource return within timeout\n")); + break; + } + } + + if(u4PktCnt != 0) { + // start transmission + HAL_WRITE_TX_PORT(prAdapter, + 0, + u4TotalLength, + (PUINT_8)pucOutputBuf, + prAdapter->u4CoalescingBufCachedSize); + + // reset varaibles + u4PktCnt = 0; + u4TotalLength = 0; + } + } + + // 8. Free CMD Info Packet. + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + return u4Status; + + #else + #error "Only MT6620/MT6628 supports firmware download in an aggregated way" + + return WLAN_STATUS_FAILURE; + + #endif +} + + #endif +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to download FW image. +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanImageSectionDownload ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4DestAddr, + IN UINT_32 u4ImgSecSize, + IN PUINT_8 pucImgSecBuf + ) +{ + #if defined(MT6620) || defined(MT6628) + + P_CMD_INFO_T prCmdInfo; + P_INIT_HIF_TX_HEADER_T prInitHifTxHeader; + P_INIT_CMD_DOWNLOAD_BUF prInitCmdDownloadBuf; + UINT_8 ucTC, ucCmdSeqNum; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + ASSERT(pucImgSecBuf); + ASSERT(u4ImgSecSize <= CMD_PKT_SIZE_FOR_IMAGE); + + DEBUGFUNC("wlanImageSectionDownload"); + + if (u4ImgSecSize == 0) { + return WLAN_STATUS_SUCCESS; + } + + // 1. Allocate CMD Info Packet and its Buffer. + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, + sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF) + u4ImgSecSize); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, ("Allocate CMD_INFO_T ==> FAILED.\n")); + return WLAN_STATUS_FAILURE; + } + + prCmdInfo->u2InfoBufLen = + sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF) + (UINT_16)u4ImgSecSize; + + // 2. Use TC0's resource to download image. (only TC0 is allowed) + ucTC = TC0_INDEX; + + // 3. increase command sequence number + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + // 4. Setup common CMD Info Packet + prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T)(prCmdInfo->pucInfoBuffer); + prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_DOWNLOAD_BUF; + prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum; + + // 5. Setup CMD_DOWNLOAD_BUF + prInitCmdDownloadBuf = (P_INIT_CMD_DOWNLOAD_BUF)(prInitHifTxHeader->rInitWifiCmd.aucBuffer); + prInitCmdDownloadBuf->u4Address = u4DestAddr; + prInitCmdDownloadBuf->u4Length = u4ImgSecSize; + prInitCmdDownloadBuf->u4CRC32 = wlanCRC32(pucImgSecBuf, u4ImgSecSize); + prInitCmdDownloadBuf->u4DataMode = 0 + #if CFG_ENABLE_FW_DOWNLOAD_ACK + | DOWNLOAD_BUF_ACK_OPTION // ACK needed + #endif + #if CFG_ENABLE_FW_ENCRYPTION + | DOWNLOAD_BUF_ENCRYPTION_MODE + #endif + ; + kalMemCopy(prInitCmdDownloadBuf->aucBuffer, pucImgSecBuf, u4ImgSecSize); + + // 6. Send FW_Download command + while(1) { + // 6.1 Acquire TX Resource + if (nicTxAcquireResource(prAdapter, ucTC) == WLAN_STATUS_RESOURCES) { + if (nicTxPollingResource(prAdapter, ucTC) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR,("Fail to get TX resource return within timeout\n")); + break; + } + else { + continue; + } + } + + // 6.2 Send CMD Info Packet + if (nicTxInitCmd(prAdapter, prCmdInfo, ucTC) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR,("Fail to transmit image download command\n")); + } + + break; + }; + + #if CFG_ENABLE_FW_DOWNLOAD_ACK + // 7. Wait for INIT_EVENT_ID_CMD_RESULT + u4Status = wlanImageSectionDownloadStatus(prAdapter, ucCmdSeqNum); + #endif + + // 8. Free CMD Info Packet. + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + return u4Status; + + #elif defined(MT5931) + + UINT_32 i, u4Value; + P_HIF_HW_TX_HEADER_T prHifTxHeader; + + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + ASSERT(pucImgSecBuf); + ASSERT(u4ImgSecSize <= CMD_PKT_SIZE_FOR_IMAGE); + + DEBUGFUNC("wlanImageSectionDownload"); + DBGLOG(INIT, TRACE, ("Destination: 0x%08X / Length: 0x%08X\n", u4DestAddr, u4ImgSecSize)); + + if (u4ImgSecSize == 0) { + return WLAN_STATUS_SUCCESS; + } + + // 1. Use TX coalescing buffer + prHifTxHeader = (P_HIF_HW_TX_HEADER_T) prAdapter->pucCoalescingBufCached; + + // 2. Setup HIF_TX_HEADER + prHifTxHeader->u2TxByteCount = (UINT_16)(ALIGN_4(sizeof(HIF_HW_TX_HEADER_T) + u4ImgSecSize)); + prHifTxHeader->ucEtherTypeOffset = 0; + prHifTxHeader->ucCSflags = 0; + + // 3. Copy payload + kalMemCopy(prHifTxHeader->aucBuffer, pucImgSecBuf, u4ImgSecSize); + + // 3.1 add 4-bytes zero tail + kalMemZero(&(prHifTxHeader->aucBuffer[ALIGN_4(u4ImgSecSize)]), sizeof(HIF_HW_TX_HEADER_T)); + + // 4. Poll til FWDL_RDY = 1 + i = 0; + while(1) { + HAL_MCR_RD(prAdapter, MCR_FWDLSR, &u4Value); + + if (u4Value & FWDLSR_FWDL_RDY) { + DBGLOG(INIT, TRACE, ("FWDL_RDY detected\n")); + break; + } + else if(kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE + || fgIsBusAccessFailed == TRUE) { + u4Status = WLAN_STATUS_FAILURE; + break; + } + else if(i >= CFG_RESPONSE_POLLING_TIMEOUT) { + DBGLOG(INIT, ERROR, ("Waiting for FWDL_RDY: Timeout (0x%08X)\n", u4Value)); + u4Status = WLAN_STATUS_FAILURE; + break; + } + else { + i++; + kalMsleep(10); + } + } + + // 5. Send firmware + HAL_PORT_WR(prAdapter, + MCR_FWDLDR, + prHifTxHeader->u2TxByteCount, + (PUINT_8)prHifTxHeader, + prAdapter->u4CoalescingBufCachedSize); + + return u4Status; + + #endif +} + +#if !CFG_ENABLE_FW_DOWNLOAD_ACK +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to confirm previously firmware download is done without error +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanImageQueryStatus( + IN P_ADAPTER_T prAdapter + ) +{ + P_CMD_INFO_T prCmdInfo; + P_INIT_HIF_TX_HEADER_T prInitHifTxHeader; + UINT_8 aucBuffer[sizeof(INIT_HIF_RX_HEADER_T) + sizeof(INIT_EVENT_PENDING_ERROR)]; + UINT_32 u4RxPktLength; + P_INIT_HIF_RX_HEADER_T prInitHifRxHeader; + P_INIT_EVENT_PENDING_ERROR prEventPendingError; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + UINT_8 ucTC, ucCmdSeqNum; + + ASSERT(prAdapter); + + DEBUGFUNC("wlanImageQueryStatus"); + + // 1. Allocate CMD Info Packet and it Buffer. + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, sizeof(INIT_HIF_TX_HEADER_T)); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, ("Allocate CMD_INFO_T ==> FAILED.\n")); + return WLAN_STATUS_FAILURE; + } + + kalMemZero(prCmdInfo, sizeof(INIT_HIF_TX_HEADER_T)); + prCmdInfo->u2InfoBufLen = sizeof(INIT_HIF_TX_HEADER_T); + + // 2. Use TC0's resource to download image. (only TC0 is allowed) + ucTC = TC0_INDEX; + + // 3. increase command sequence number + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + // 4. Setup common CMD Info Packet + prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T)(prCmdInfo->pucInfoBuffer); + prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_QUERY_PENDING_ERROR; + prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum; + + // 5. Send command + while(1) { + // 5.1 Acquire TX Resource + if (nicTxAcquireResource(prAdapter, ucTC) == WLAN_STATUS_RESOURCES) { + if (nicTxPollingResource(prAdapter, ucTC) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR,("Fail to get TX resource return within timeout\n")); + break; + } + else { + continue; + } + } + + // 5.2 Send CMD Info Packet + if (nicTxInitCmd(prAdapter, prCmdInfo, ucTC) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR,("Fail to transmit image download command\n")); + } + + break; + }; + + // 6. Wait for INIT_EVENT_ID_PENDING_ERROR + do { + if(kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE + || fgIsBusAccessFailed == TRUE) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, ("Bus error(%d)/Card removed(%d)\n", fgIsBusAccessFailed, kalIsCardRemoved(prAdapter->prGlueInfo))); + } + else if(nicRxWaitResponse(prAdapter, + 0, + aucBuffer, + sizeof(INIT_HIF_RX_HEADER_T) + sizeof(INIT_EVENT_PENDING_ERROR), + &u4RxPktLength) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, ("No RX response\n")); + } + else { + prInitHifRxHeader = (P_INIT_HIF_RX_HEADER_T) aucBuffer; + + // EID / SeqNum check + if(prInitHifRxHeader->rInitWifiEvent.ucEID != INIT_EVENT_ID_PENDING_ERROR) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, ("EVENT-ID Mismatch: %d\n", prInitHifRxHeader->rInitWifiEvent.ucEID)); + } + else if(prInitHifRxHeader->rInitWifiEvent.ucSeqNum != ucCmdSeqNum) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, ("SEQ-NUM Mismatch: %d (expected: %d)\n", prInitHifRxHeader->rInitWifiEvent.ucSeqNum, ucCmdSeqNum)); + } + else { + prEventPendingError = (P_INIT_EVENT_PENDING_ERROR) (prInitHifRxHeader->rInitWifiEvent.aucBuffer); + if(prEventPendingError->ucStatus != 0) { // 0 for download success + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, ("ERROR CODE: %d\n", prEventCmdResult->ucStatus)); + } + else { + u4Status = WLAN_STATUS_SUCCESS; + } + } + } + } while (FALSE); + + // 7. Free CMD Info Packet. + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + return u4Status; +} + + +#else +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to confirm the status of +* previously downloaded firmware scatter +* +* @param prAdapter Pointer to the Adapter structure. +* ucCmdSeqNum Sequence number of previous firmware scatter +* +* @return WLAN_STATUS_SUCCESS +* WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanImageSectionDownloadStatus ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucCmdSeqNum + ) +{ + UINT_8 aucBuffer[sizeof(INIT_HIF_RX_HEADER_T) + sizeof(INIT_EVENT_CMD_RESULT)]; + P_INIT_HIF_RX_HEADER_T prInitHifRxHeader; + P_INIT_EVENT_CMD_RESULT prEventCmdResult; + UINT_32 u4RxPktLength; + WLAN_STATUS u4Status; + + ASSERT(prAdapter); + + do { + if(kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE + || fgIsBusAccessFailed == TRUE) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, ("Bus error(%d)/Card removed(%d)\n", fgIsBusAccessFailed, kalIsCardRemoved(prAdapter->prGlueInfo))); + } + else if(nicRxWaitResponse(prAdapter, + 0, + aucBuffer, + sizeof(INIT_HIF_RX_HEADER_T) + sizeof(INIT_EVENT_CMD_RESULT), + &u4RxPktLength) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, ("No RX response\n")); + } + else { + prInitHifRxHeader = (P_INIT_HIF_RX_HEADER_T) aucBuffer; + + // EID / SeqNum check + if(prInitHifRxHeader->rInitWifiEvent.ucEID != INIT_EVENT_ID_CMD_RESULT) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, ("EVENT-ID Mismatch: %d\n", prInitHifRxHeader->rInitWifiEvent.ucEID)); + } + else if(prInitHifRxHeader->rInitWifiEvent.ucSeqNum != ucCmdSeqNum) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, ("SEQ-NUM Mismatch: %d\n", prInitHifRxHeader->rInitWifiEvent.ucSeqNum)); + } + else { + prEventCmdResult = (P_INIT_EVENT_CMD_RESULT) (prInitHifRxHeader->rInitWifiEvent.aucBuffer); + if(prEventCmdResult->ucStatus != 0) { // 0 for download success + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, ("ERROR CODE: %d\n", prEventCmdResult->ucStatus)); + } + else { + u4Status = WLAN_STATUS_SUCCESS; + } + } + } + } while (FALSE); + + return u4Status; +} + + +#endif +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to start FW normal operation. +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanConfigWifiFunc ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgEnable, + IN UINT_32 u4StartAddress + ) +{ + P_CMD_INFO_T prCmdInfo; + P_INIT_HIF_TX_HEADER_T prInitHifTxHeader; + P_INIT_CMD_WIFI_START prInitCmdWifiStart; + UINT_8 ucTC, ucCmdSeqNum; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + + DEBUGFUNC("wlanConfigWifiFunc"); + + // 1. Allocate CMD Info Packet and its Buffer. + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, + sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_WIFI_START)); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, ("Allocate CMD_INFO_T ==> FAILED.\n")); + return WLAN_STATUS_FAILURE; + } + + kalMemZero(prCmdInfo, sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_WIFI_START)); + prCmdInfo->u2InfoBufLen = + sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_WIFI_START); + + // 2. Always use TC0 + ucTC = TC0_INDEX; + + // 3. increase command sequence number + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + // 4. Setup common CMD Info Packet + prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T)(prCmdInfo->pucInfoBuffer); + prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_WIFI_START; + prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum; + + prInitCmdWifiStart = (P_INIT_CMD_WIFI_START)(prInitHifTxHeader->rInitWifiCmd.aucBuffer); + prInitCmdWifiStart->u4Override = (fgEnable == TRUE ? 1 : 0); + prInitCmdWifiStart->u4Address = u4StartAddress; + + // 5. Seend WIFI start command + while(1) { + // 5.1 Acquire TX Resource + if (nicTxAcquireResource(prAdapter, ucTC) == WLAN_STATUS_RESOURCES) { + if (nicTxPollingResource(prAdapter, ucTC) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR,("Fail to get TX resource return within timeout\n")); + break; + } + else { + continue; + } + } + + // 5.2 Send CMD Info Packet + if (nicTxInitCmd(prAdapter, prCmdInfo, ucTC) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR,("Fail to transmit WIFI start command\n")); + } + + break; + }; + + // 6. Free CMD Info Packet. + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + return u4Status; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to generate CRC32 checksum +* +* @param buf Pointer to the data. +* @param len data length +* +* @return crc32 value +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 wlanCRC32( + PUINT_8 buf, + UINT_32 len) +{ + UINT_32 i, crc32 = 0xFFFFFFFF; + const UINT_32 crc32_ccitt_table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d }; + + for (i = 0; i < len; i++) + crc32 = crc32_ccitt_table[(crc32 ^ buf[i]) & 0xff] ^ (crc32 >> 8); + + return ( ~crc32 ); +} +#endif + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to process queued RX packets +* +* @param prAdapter Pointer to the Adapter structure. +* prSwRfbListHead Pointer to head of RX packets link list +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanProcessQueuedSwRfb ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfbListHead + ) +{ + P_SW_RFB_T prSwRfb, prNextSwRfb; + P_TX_CTRL_T prTxCtrl; + P_RX_CTRL_T prRxCtrl; + + ASSERT(prAdapter); + ASSERT(prSwRfbListHead); + + prTxCtrl = &prAdapter->rTxCtrl; + prRxCtrl = &prAdapter->rRxCtrl; + + prSwRfb = prSwRfbListHead; + + do { + // save next first + prNextSwRfb = (P_SW_RFB_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prSwRfb); + + switch(prSwRfb->eDst) { + case RX_PKT_DESTINATION_HOST: + nicRxProcessPktWithoutReorder(prAdapter, prSwRfb); + break; + + case RX_PKT_DESTINATION_FORWARD: + nicRxProcessForwardPkt(prAdapter, prSwRfb); + break; + + case RX_PKT_DESTINATION_HOST_WITH_FORWARD: + nicRxProcessGOBroadcastPkt(prAdapter, prSwRfb); + break; + + case RX_PKT_DESTINATION_NULL: + nicRxReturnRFB(prAdapter, prSwRfb); + break; + + default: + break; + } + +#if CFG_HIF_RX_STARVATION_WARNING + prRxCtrl->u4DequeuedCnt++; +#endif + prSwRfb = prNextSwRfb; + } while(prSwRfb); + + return WLAN_STATUS_SUCCESS; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to purge queued TX packets +* by indicating failure to OS and returned to free list +* +* @param prAdapter Pointer to the Adapter structure. +* prMsduInfoListHead Pointer to head of TX packets link list +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanProcessQueuedMsduInfo ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfoListHead + ) +{ + ASSERT(prAdapter); + ASSERT(prMsduInfoListHead); + + nicTxFreeMsduInfoPacket(prAdapter, prMsduInfoListHead); + nicTxReturnMsduInfo(prAdapter, prMsduInfoListHead); + + return WLAN_STATUS_SUCCESS; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to check if the OID handler needs timeout +* +* @param prAdapter Pointer to the Adapter structure. +* pfnOidHandler Pointer to the OID handler +* +* @return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +wlanoidTimeoutCheck ( + IN P_ADAPTER_T prAdapter, + IN PFN_OID_HANDLER_FUNC pfnOidHandler + ) +{ + PFN_OID_HANDLER_FUNC* apfnOidHandlerWOTimeoutCheck; + UINT_32 i; + UINT_32 u4NumOfElem; + + apfnOidHandlerWOTimeoutCheck = apfnOidWOTimeoutCheck; + u4NumOfElem = sizeof(apfnOidWOTimeoutCheck) / sizeof(PFN_OID_HANDLER_FUNC); + + for (i = 0; i < u4NumOfElem; i++) { + if (apfnOidHandlerWOTimeoutCheck[i] == pfnOidHandler) { + return FALSE; + } + } + + // set timer if need timeout check + cnmTimerStartTimer(prAdapter, + &(prAdapter->rOidTimeoutTimer), + 1000); + + return TRUE; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to clear any pending OID timeout check +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanoidClearTimeoutCheck ( + IN P_ADAPTER_T prAdapter + ) +{ + ASSERT(prAdapter); + + cnmTimerStopTimer(prAdapter, &(prAdapter->rOidTimeoutTimer)); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to set up the MCUSYS's OSC stable time +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ + +#if CFG_SUPPORT_OSC_SETTING && defined(MT5931) +WLAN_STATUS +wlanSetMcuOscStableTime ( + IN P_ADAPTER_T prAdapter, + IN UINT_16 u2OscStableTime + ) +{ + UINT_8 ucCmdSeqNum = 0; + P_CMD_INFO_T prCmdInfo = NULL; + P_WIFI_CMD_T prWifiCmd = NULL; + P_CMD_MCU_LP_PARAM_T prMcuSetOscCmd = NULL; + WLAN_STATUS status = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, + CMD_HDR_SIZE + sizeof(CMD_MCU_LP_PARAM_T)); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, ("Allocate CMD_INFO_T ==> FAILED.\n")); + return WLAN_STATUS_FAILURE; + } + + // increase command sequence number + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + // compose CMD_MCU_LP_PARAM_T cmd pkt + prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_MCU_LP_PARAM_T); + prCmdInfo->pfCmdDoneHandler = NULL; + prCmdInfo->pfCmdTimeoutHandler = NULL; + prCmdInfo->fgIsOid = FALSE; + prCmdInfo->ucCID = CMD_ID_SET_OSC; + prCmdInfo->fgSetQuery = TRUE; + prCmdInfo->fgNeedResp = FALSE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = sizeof(CMD_MCU_LP_PARAM_T); + + // Setup WIFI_CMD_T + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + // configure CMD_MCU_LP_PARAM_T + prMcuSetOscCmd = (P_CMD_MCU_LP_PARAM_T)(prWifiCmd->aucBuffer); + prMcuSetOscCmd->u2OscStableTime = u2OscStableTime; + + status = wlanSendCommand(prAdapter, prCmdInfo); + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + return status; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to update network address in firmware domain +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return WLAN_STATUS_FAILURE The request could not be processed +* WLAN_STATUS_PENDING The request has been queued for later processing +* WLAN_STATUS_SUCCESS The request has been processed +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanUpdateNetworkAddress ( + IN P_ADAPTER_T prAdapter + ) +{ + const UINT_8 aucZeroMacAddr[] = NULL_MAC_ADDR; + PARAM_MAC_ADDRESS rMacAddr; + UINT_8 ucCmdSeqNum; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + P_CMD_BASIC_CONFIG prCmdBasicConfig; + UINT_32 u4SysTime; + + ASSERT(prAdapter); + + if(kalRetrieveNetworkAddress(prAdapter->prGlueInfo, &rMacAddr) == FALSE + || IS_BMCAST_MAC_ADDR(rMacAddr) + || EQUAL_MAC_ADDR(aucZeroMacAddr, rMacAddr)) { + // eFUSE has a valid address, don't do anything + if(prAdapter->fgIsEmbbededMacAddrValid == TRUE) { + return WLAN_STATUS_SUCCESS; + } + else { + // dynamic generate + u4SysTime = (UINT_32) kalGetTimeTick(); + + rMacAddr[0] = 0x00; + rMacAddr[1] = 0x08; + rMacAddr[2] = 0x22; + + kalMemCopy(&rMacAddr[3], &u4SysTime, 3); + } + } + + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, + CMD_HDR_SIZE + sizeof(CMD_BASIC_CONFIG)); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, ("Allocate CMD_INFO_T ==> FAILED.\n")); + return WLAN_STATUS_FAILURE; + } + + // increase command sequence number + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + // compose CMD_BUILD_CONNECTION cmd pkt + prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_BASIC_CONFIG); + prCmdInfo->pfCmdDoneHandler = NULL; + prCmdInfo->pfCmdTimeoutHandler = NULL; + prCmdInfo->fgIsOid = FALSE; + prCmdInfo->ucCID = CMD_ID_BASIC_CONFIG; + prCmdInfo->fgSetQuery = TRUE; + prCmdInfo->fgNeedResp = FALSE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = sizeof(CMD_BASIC_CONFIG); + + // Setup WIFI_CMD_T + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + // configure CMD_BASIC_CONFIG + prCmdBasicConfig = (P_CMD_BASIC_CONFIG)(prWifiCmd->aucBuffer); + kalMemCopy(&(prCmdBasicConfig->rMyMacAddr), &rMacAddr, PARAM_MAC_ADDR_LEN); + prCmdBasicConfig->ucNative80211 = 0; + prCmdBasicConfig->rCsumOffload.u2RxChecksum = 0; + prCmdBasicConfig->rCsumOffload.u2TxChecksum = 0; + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + if(prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_TX_TCP) + prCmdBasicConfig->rCsumOffload.u2TxChecksum |= BIT(2); + + if(prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_TX_UDP) + prCmdBasicConfig->rCsumOffload.u2TxChecksum |= BIT(1); + + if(prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_TX_IP) + prCmdBasicConfig->rCsumOffload.u2TxChecksum |= BIT(0); + + if(prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_RX_TCP) + prCmdBasicConfig->rCsumOffload.u2RxChecksum |= BIT(2); + + if(prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_RX_UDP) + prCmdBasicConfig->rCsumOffload.u2RxChecksum |= BIT(1); + + if(prAdapter->u4CSUMFlags & (CSUM_OFFLOAD_EN_RX_IPv4 | CSUM_OFFLOAD_EN_RX_IPv6)) + prCmdBasicConfig->rCsumOffload.u2RxChecksum |= BIT(0); +#endif + + if(wlanSendCommand(prAdapter, prCmdInfo) == WLAN_STATUS_RESOURCES) { + prCmdInfo->pfCmdDoneHandler = nicCmdEventQueryAddress; + kalEnqueueCommand(prAdapter->prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + + return WLAN_STATUS_PENDING; + } + else { + nicCmdEventQueryAddress(prAdapter, prCmdInfo, (PUINT_8)prCmdBasicConfig); + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + return WLAN_STATUS_SUCCESS; + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to check if the device is in RF test mode +* +* @param pfnOidHandler Pointer to the OID handler +* +* @return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +wlanQueryTestMode( + IN P_ADAPTER_T prAdapter + ) +{ + ASSERT(prAdapter); + + return prAdapter->fgTestMode; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to identify 802.1x and Bluetooth-over-Wi-Fi +* security frames, and queued into command queue for strict ordering +* due to 802.1x frames before add-key OIDs are not to be encrypted +* +* @param prAdapter Pointer of Adapter Data Structure +* @param prPacket Pointer of native packet +* +* @return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +wlanProcessSecurityFrame( + IN P_ADAPTER_T prAdapter, + IN P_NATIVE_PACKET prPacket + ) +{ + UINT_8 ucPriorityParam; + UINT_8 aucEthDestAddr[PARAM_MAC_ADDR_LEN]; + BOOLEAN fgIs1x = FALSE; + BOOLEAN fgIsPAL = FALSE; + UINT_32 u4PacketLen; + ULONG u4SysTime; + UINT_8 ucNetworkType; + P_CMD_INFO_T prCmdInfo; + + ASSERT(prAdapter); + ASSERT(prPacket); + + if (kalQoSFrameClassifierAndPacketInfo(prAdapter->prGlueInfo, + prPacket, + &ucPriorityParam, + &u4PacketLen, + aucEthDestAddr, + &fgIs1x, + &fgIsPAL, + &ucNetworkType) == TRUE) { + if(fgIs1x == FALSE) { + return FALSE; + } + else { + KAL_SPIN_LOCK_DECLARATION(); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); + QUEUE_REMOVE_HEAD(&prAdapter->rFreeCmdList, prCmdInfo, P_CMD_INFO_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); + + DBGLOG(RSN, INFO, ("T1X len=%d\n", u4PacketLen)); + + if (prCmdInfo) { + P_STA_RECORD_T prStaRec; + // fill arrival time + u4SysTime = (OS_SYSTIME)kalGetTimeTick(); + GLUE_SET_PKT_ARRIVAL_TIME(prPacket, u4SysTime); + + kalMemZero(prCmdInfo, sizeof(CMD_INFO_T)); + + prCmdInfo->eCmdType = COMMAND_TYPE_SECURITY_FRAME; + prCmdInfo->u2InfoBufLen = (UINT_16)u4PacketLen; + prCmdInfo->pucInfoBuffer = NULL; + prCmdInfo->prPacket = prPacket; +#if 0 + prCmdInfo->ucStaRecIndex = qmGetStaRecIdx(prAdapter, + aucEthDestAddr, + (ENUM_NETWORK_TYPE_INDEX_T)ucNetworkType); +#endif + prStaRec = cnmGetStaRecByAddress(prAdapter, + (ENUM_NETWORK_TYPE_INDEX_T)ucNetworkType, + aucEthDestAddr); + if(prStaRec) { + prCmdInfo->ucStaRecIndex = prStaRec->ucIndex; + } + else { + prCmdInfo->ucStaRecIndex = STA_REC_INDEX_NOT_FOUND; + } + + prCmdInfo->eNetworkType = (ENUM_NETWORK_TYPE_INDEX_T)ucNetworkType; + prCmdInfo->pfCmdDoneHandler = wlanSecurityFrameTxDone; + prCmdInfo->pfCmdTimeoutHandler = wlanSecurityFrameTxTimeout; + prCmdInfo->fgIsOid = FALSE; + prCmdInfo->fgSetQuery = TRUE; + prCmdInfo->fgNeedResp = FALSE; + + kalEnqueueCommand(prAdapter->prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + + return TRUE; + } + else { + ASSERT(0); + return FALSE; + } + } + } + else { + return FALSE; + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called when 802.1x or Bluetooth-over-Wi-Fi +* security frames has been sent to firmware +* +* @param prAdapter Pointer of Adapter Data Structure +* @param prCmdInfo Pointer of CMD_INFO_T +* @param pucEventBuf meaningless, only for API compatibility +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanSecurityFrameTxDone( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + ASSERT(prAdapter); + ASSERT(prCmdInfo); + if (prCmdInfo->eNetworkType == NETWORK_TYPE_AIS_INDEX && + prAdapter->rWifiVar.rAisSpecificBssInfo.fgCounterMeasure) { + P_STA_RECORD_T prSta = cnmGetStaRecByIndex(prAdapter, prCmdInfo->ucStaRecIndex); + if (prSta) { + kalMsleep(10); + secFsmEventEapolTxDone(prAdapter, prSta, TX_RESULT_SUCCESS); + } + } + + kalSecurityFrameSendComplete(prAdapter->prGlueInfo, + prCmdInfo->prPacket, + WLAN_STATUS_SUCCESS); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called when 802.1x or Bluetooth-over-Wi-Fi +* security frames has failed sending to firmware +* +* @param prAdapter Pointer of Adapter Data Structure +* @param prCmdInfo Pointer of CMD_INFO_T +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanSecurityFrameTxTimeout( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo + ) +{ + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + kalSecurityFrameSendComplete(prAdapter->prGlueInfo, + prCmdInfo->prPacket, + WLAN_STATUS_FAILURE); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called before AIS is starting a new scan +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanClearScanningResult( + IN P_ADAPTER_T prAdapter + ) +{ + BOOLEAN fgKeepCurrOne = FALSE; + UINT_32 i; + + ASSERT(prAdapter); + + // clear scanning result + if(kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { + for(i = 0 ; i < prAdapter->rWlanInfo.u4ScanResultNum ; i++) { + if(EQUAL_MAC_ADDR(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, + prAdapter->rWlanInfo.arScanResult[i].arMacAddress)) { + fgKeepCurrOne = TRUE; + + if(i != 0) { + // copy structure + kalMemCopy(&(prAdapter->rWlanInfo.arScanResult[0]), + &(prAdapter->rWlanInfo.arScanResult[i]), + OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); + } + + if(prAdapter->rWlanInfo.arScanResult[i].u4IELength > 0) { + if(prAdapter->rWlanInfo.apucScanResultIEs[i] != &(prAdapter->rWlanInfo.aucScanIEBuf[0])) { + // move IEs to head + kalMemCopy(prAdapter->rWlanInfo.aucScanIEBuf, + prAdapter->rWlanInfo.apucScanResultIEs[i], + prAdapter->rWlanInfo.arScanResult[i].u4IELength); + } + + // modify IE pointer + prAdapter->rWlanInfo.apucScanResultIEs[0] = &(prAdapter->rWlanInfo.aucScanIEBuf[0]); + } + else { + prAdapter->rWlanInfo.apucScanResultIEs[0] = NULL; + } + + break; + } + } + } + + if(fgKeepCurrOne == TRUE) { + prAdapter->rWlanInfo.u4ScanResultNum = 1; + prAdapter->rWlanInfo.u4ScanIEBufferUsage = + ALIGN_4(prAdapter->rWlanInfo.arScanResult[0].u4IELength); + } + else { + prAdapter->rWlanInfo.u4ScanResultNum = 0; + prAdapter->rWlanInfo.u4ScanIEBufferUsage = 0; + } + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called when AIS received a beacon timeout event +* +* @param prAdapter Pointer of Adapter Data Structure +* @param arBSSID MAC address of the specified BSS +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanClearBssInScanningResult( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 arBSSID + ) +{ + UINT_32 i, j, u4IELength = 0, u4IEMoveLength; + PUINT_8 pucIEPtr; + + ASSERT(prAdapter); + + // clear scanning result + i = 0; + while(1) { + if(i >= prAdapter->rWlanInfo.u4ScanResultNum) { + break; + } + + if(EQUAL_MAC_ADDR(arBSSID, prAdapter->rWlanInfo.arScanResult[i].arMacAddress)) { + // backup current IE length + u4IELength = ALIGN_4(prAdapter->rWlanInfo.arScanResult[i].u4IELength); + pucIEPtr = prAdapter->rWlanInfo.apucScanResultIEs[i]; + + // removed from middle + for(j = i + 1 ; j < prAdapter->rWlanInfo.u4ScanResultNum ; j++) { + kalMemCopy(&(prAdapter->rWlanInfo.arScanResult[j-1]), + &(prAdapter->rWlanInfo.arScanResult[j]), + OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); + + prAdapter->rWlanInfo.apucScanResultIEs[j-1] = + prAdapter->rWlanInfo.apucScanResultIEs[j]; + } + + prAdapter->rWlanInfo.u4ScanResultNum--; + + // remove IE buffer if needed := move rest of IE buffer + if(u4IELength > 0) { + u4IEMoveLength = prAdapter->rWlanInfo.u4ScanIEBufferUsage - + (((UINT_32)pucIEPtr) + u4IELength - ((UINT_32)(&(prAdapter->rWlanInfo.aucScanIEBuf[0])))); + + kalMemCopy(pucIEPtr, + (PUINT_8)(((UINT_32)pucIEPtr) + u4IELength), + u4IEMoveLength); + + prAdapter->rWlanInfo.u4ScanIEBufferUsage -= u4IELength; + + // correction of pointers to IE buffer + for(j = 0 ; j < prAdapter->rWlanInfo.u4ScanResultNum ; j++) { + if(prAdapter->rWlanInfo.apucScanResultIEs[j] > pucIEPtr) { + prAdapter->rWlanInfo.apucScanResultIEs[j] = + (PUINT_8)((UINT_32)(prAdapter->rWlanInfo.apucScanResultIEs[j]) - u4IELength); + } + } + } + } + + i++; + } + + return; +} + + +#if CFG_TEST_WIFI_DIRECT_GO +VOID +wlanEnableP2pFunction ( + IN P_ADAPTER_T prAdapter + ) +{ +#if 0 + P_MSG_P2P_FUNCTION_SWITCH_T prMsgFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T)NULL; + + prMsgFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_FUNCTION_SWITCH_T)); + if (!prMsgFuncSwitch) { + ASSERT(FALSE); + return; + } + + + prMsgFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; + prMsgFuncSwitch->fgIsFuncOn = TRUE; + + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T)prMsgFuncSwitch, + MSG_SEND_METHOD_BUF); +#endif + return; +} + +VOID +wlanEnableATGO ( + IN P_ADAPTER_T prAdapter + ) +{ + + P_MSG_P2P_CONNECTION_REQUEST_T prMsgConnReq = (P_MSG_P2P_CONNECTION_REQUEST_T)NULL; + UINT_8 aucTargetDeviceID[MAC_ADDR_LEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + + prMsgConnReq = (P_MSG_P2P_CONNECTION_REQUEST_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_CONNECTION_REQUEST_T)); + if (!prMsgConnReq) { + ASSERT(FALSE); + return; + } + + prMsgConnReq->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_REQ; + + /*=====Param Modified for test=====*/ + COPY_MAC_ADDR(prMsgConnReq->aucDeviceID, aucTargetDeviceID); + prMsgConnReq->fgIsTobeGO = TRUE; + prMsgConnReq->fgIsPersistentGroup = FALSE; + + /*=====Param Modified for test=====*/ + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T)prMsgConnReq, + MSG_SEND_METHOD_BUF); + + return; +} +#endif + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to retrieve permanent address from firmware +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return WLAN_STATUS_SUCCESS +* WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanQueryPermanentAddress( + IN P_ADAPTER_T prAdapter + ) +{ + UINT_8 ucCmdSeqNum; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + UINT_32 u4RxPktLength; + UINT_8 aucBuffer[sizeof(WIFI_EVENT_T) + sizeof(EVENT_BASIC_CONFIG)]; + P_HIF_RX_HEADER_T prHifRxHdr; + P_WIFI_EVENT_T prEvent; + P_EVENT_BASIC_CONFIG prEventBasicConfig; + + ASSERT(prAdapter); + + DEBUGFUNC("wlanQueryPermanentAddress"); + + // 1. Allocate CMD Info Packet and its Buffer + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, CMD_HDR_SIZE + sizeof(CMD_BASIC_CONFIG)); + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, ("Allocate CMD_INFO_T ==> FAILED.\n")); + return WLAN_STATUS_FAILURE; + } + + // increase command sequence number + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + // compose CMD_BUILD_CONNECTION cmd pkt + prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_BASIC_CONFIG); + prCmdInfo->pfCmdDoneHandler = NULL; + prCmdInfo->fgIsOid = FALSE; + prCmdInfo->ucCID = CMD_ID_BASIC_CONFIG; + prCmdInfo->fgSetQuery = FALSE; + prCmdInfo->fgNeedResp = TRUE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = sizeof(CMD_BASIC_CONFIG); + + // Setup WIFI_CMD_T + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + wlanSendCommand(prAdapter, prCmdInfo); + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + if(nicRxWaitResponse(prAdapter, + 1, + aucBuffer, + sizeof(WIFI_EVENT_T) + sizeof(EVENT_BASIC_CONFIG), + &u4RxPktLength) != WLAN_STATUS_SUCCESS) { + return WLAN_STATUS_FAILURE; + } + + // header checking .. + prHifRxHdr = (P_HIF_RX_HEADER_T)aucBuffer; + if(prHifRxHdr->u2PacketType != HIF_RX_PKT_TYPE_EVENT) { + return WLAN_STATUS_FAILURE; + } + + prEvent = (P_WIFI_EVENT_T)aucBuffer; + if(prEvent->ucEID != EVENT_ID_BASIC_CONFIG) { + return WLAN_STATUS_FAILURE; + } + + prEventBasicConfig = (P_EVENT_BASIC_CONFIG)(prEvent->aucBuffer); + + COPY_MAC_ADDR(prAdapter->rWifiVar.aucPermanentAddress, &(prEventBasicConfig->rMyMacAddr)); + COPY_MAC_ADDR(prAdapter->rWifiVar.aucMacAddress, &(prEventBasicConfig->rMyMacAddr)); + + return WLAN_STATUS_SUCCESS; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to retrieve NIC capability from firmware +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return WLAN_STATUS_SUCCESS +* WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanQueryNicCapability( + IN P_ADAPTER_T prAdapter + ) +{ + UINT_8 ucCmdSeqNum; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + UINT_32 u4RxPktLength; + UINT_8 aucBuffer[sizeof(WIFI_EVENT_T) + sizeof(EVENT_NIC_CAPABILITY)]; + P_HIF_RX_HEADER_T prHifRxHdr; + P_WIFI_EVENT_T prEvent; + P_EVENT_NIC_CAPABILITY prEventNicCapability; + + ASSERT(prAdapter); + + DEBUGFUNC("wlanQueryNicCapability"); + + // 1. Allocate CMD Info Packet and its Buffer + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, CMD_HDR_SIZE + sizeof(EVENT_NIC_CAPABILITY)); + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, ("Allocate CMD_INFO_T ==> FAILED.\n")); + return WLAN_STATUS_FAILURE; + } + + // increase command sequence number + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + // compose CMD_BUILD_CONNECTION cmd pkt + prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(EVENT_NIC_CAPABILITY); + prCmdInfo->pfCmdDoneHandler = NULL; + prCmdInfo->fgIsOid = FALSE; + prCmdInfo->ucCID = CMD_ID_GET_NIC_CAPABILITY; + prCmdInfo->fgSetQuery = FALSE; + prCmdInfo->fgNeedResp = TRUE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = 0; + + // Setup WIFI_CMD_T + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + wlanSendCommand(prAdapter, prCmdInfo); + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + if(nicRxWaitResponse(prAdapter, + 1, + aucBuffer, + sizeof(WIFI_EVENT_T) + sizeof(EVENT_NIC_CAPABILITY), + &u4RxPktLength) != WLAN_STATUS_SUCCESS) { + return WLAN_STATUS_FAILURE; + } + + // header checking .. + prHifRxHdr = (P_HIF_RX_HEADER_T)aucBuffer; + if(prHifRxHdr->u2PacketType != HIF_RX_PKT_TYPE_EVENT) { + return WLAN_STATUS_FAILURE; + } + + prEvent = (P_WIFI_EVENT_T)aucBuffer; + if(prEvent->ucEID != EVENT_ID_NIC_CAPABILITY) { + return WLAN_STATUS_FAILURE; + } + + prEventNicCapability = (P_EVENT_NIC_CAPABILITY)(prEvent->aucBuffer); + + prAdapter->rVerInfo.u2FwProductID = prEventNicCapability->u2ProductID; + prAdapter->rVerInfo.u2FwOwnVersion = prEventNicCapability->u2FwVersion; + prAdapter->rVerInfo.u2FwPeerVersion = prEventNicCapability->u2DriverVersion; + prAdapter->fgIsHw5GBandDisabled = (BOOLEAN)prEventNicCapability->ucHw5GBandDisabled; + prAdapter->fgIsEepromUsed = (BOOLEAN)prEventNicCapability->ucEepromUsed; + prAdapter->fgIsEfuseValid = (BOOLEAN)prEventNicCapability->ucEfuseValid; + prAdapter->fgIsEmbbededMacAddrValid = (BOOLEAN)prEventNicCapability->ucMacAddrValid; + + return WLAN_STATUS_SUCCESS; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to load manufacture data from NVRAM +* if available and valid +* +* @param prAdapter Pointer of Adapter Data Structure +* @param prRegInfo Pointer of REG_INFO_T +* +* @return WLAN_STATUS_SUCCESS +* WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanLoadManufactureData ( + IN P_ADAPTER_T prAdapter, + IN P_REG_INFO_T prRegInfo + ) +{ +#if CFG_SUPPORT_RDD_TEST_MODE + CMD_RDD_CH_T rRddParam; +#endif + + ASSERT(prAdapter); + + /* 1. Version Check */ + kalGetConfigurationVersion(prAdapter->prGlueInfo, + &(prAdapter->rVerInfo.u2Part1CfgOwnVersion), + &(prAdapter->rVerInfo.u2Part1CfgPeerVersion), + &(prAdapter->rVerInfo.u2Part2CfgOwnVersion), + &(prAdapter->rVerInfo.u2Part2CfgPeerVersion)); + +#if (CFG_SW_NVRAM_VERSION_CHECK == 1) + if(CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2Part1CfgPeerVersion + || CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2Part2CfgPeerVersion + || prAdapter->rVerInfo.u2Part1CfgOwnVersion < CFG_DRV_PEER_VERSION + || prAdapter->rVerInfo.u2Part2CfgOwnVersion < CFG_DRV_PEER_VERSION) { + return WLAN_STATUS_FAILURE; + } +#endif + + // MT6620 E1/E2 would be ignored directly + if(prAdapter->rVerInfo.u2Part1CfgOwnVersion == 0x0001) { + prRegInfo->ucTxPwrValid = 1; + } + else { + /* 2. Load TX power gain parameters if valid */ + if(prRegInfo->ucTxPwrValid != 0) { + // send to F/W + nicUpdateTxPower(prAdapter, (P_CMD_TX_PWR_T)(&(prRegInfo->rTxPwr))); + } + } + + /* 3. Check if needs to support 5GHz */ + if(prRegInfo->ucEnable5GBand) { + // check if it is disabled by hardware + if(prAdapter->fgIsHw5GBandDisabled + || prRegInfo->ucSupport5GBand == 0) { + prAdapter->fgEnable5GBand = FALSE; + } + else { + prAdapter->fgEnable5GBand = TRUE; + } + } + else { + prAdapter->fgEnable5GBand = FALSE; + } + + /* 4. Send EFUSE data */ + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_PHY_PARAM, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(CMD_PHY_PARAM_T), + (PUINT_8)(prRegInfo->aucEFUSE), + NULL, + 0); + +#if CFG_SUPPORT_RDD_TEST_MODE + rRddParam.ucRddTestMode = (UINT_8) prRegInfo->u4RddTestMode; + rRddParam.ucRddShutCh = (UINT_8) prRegInfo->u4RddShutFreq; + rRddParam.ucRddStartCh = (UINT_8) nicFreq2ChannelNum(prRegInfo->u4RddStartFreq); + rRddParam.ucRddStopCh = (UINT_8) nicFreq2ChannelNum(prRegInfo->u4RddStopFreq); + rRddParam.ucRddDfs = (UINT_8) prRegInfo->u4RddDfs; + prAdapter->ucRddStatus = 0; + nicUpdateRddTestMode(prAdapter, (P_CMD_RDD_CH_T)(&rRddParam)); +#endif + + /* 5. Get 16-bits Country Code and Bandwidth */ + prAdapter->rWifiVar.rConnSettings.u2CountryCode = + (((UINT_16) prRegInfo->au2CountryCode[0]) << 8) | + (((UINT_16) prRegInfo->au2CountryCode[1]) & BITS(0,7)); + +#if 0 /* Bandwidth control will be controlled by GUI. 20110930 + * So ignore the setting from registry/NVRAM + */ + prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode = + prRegInfo->uc2G4BwFixed20M ? CONFIG_BW_20M : CONFIG_BW_20_40M; + prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode = + prRegInfo->uc5GBwFixed20M ? CONFIG_BW_20M : CONFIG_BW_20_40M; +#endif + + /* 6. Set domain and channel information to chip */ + rlmDomainSendCmd(prAdapter, FALSE); + + /* 7. set band edge tx power if available */ + if(prRegInfo->fg2G4BandEdgePwrUsed) { + CMD_EDGE_TXPWR_LIMIT_T rCmdEdgeTxPwrLimit; + + rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrCCK + = prRegInfo->cBandEdgeMaxPwrCCK; + rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM20 + = prRegInfo->cBandEdgeMaxPwrOFDM20; + rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM40 + = prRegInfo->cBandEdgeMaxPwrOFDM40; + + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_EDGE_TXPWR_LIMIT, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(CMD_EDGE_TXPWR_LIMIT_T), + (PUINT_8)&rCmdEdgeTxPwrLimit, + NULL, + 0); + } + + return WLAN_STATUS_SUCCESS; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to check +* Media Stream Mode is set to non-default value or not, +* and clear to default value if above criteria is met +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return TRUE +* The media stream mode was non-default value and has been reset +* FALSE +* The media stream mode is default value +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +wlanResetMediaStreamMode( + IN P_ADAPTER_T prAdapter + ) +{ + ASSERT(prAdapter); + + if(prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode != 0) { + prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode = 0; + + return TRUE; + } + else { + return FALSE; + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to check if any pending timer has expired +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanTimerTimeoutCheck( + IN P_ADAPTER_T prAdapter + ) +{ + ASSERT(prAdapter); + + cnmTimerDoTimeOutCheck(prAdapter); + + return WLAN_STATUS_SUCCESS; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to check if any pending mailbox message +* to be handled +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanProcessMboxMessage( + IN P_ADAPTER_T prAdapter + ) +{ + UINT_32 i; + + ASSERT(prAdapter); + + for(i = 0 ; i < MBOX_ID_TOTAL_NUM ; i++) { + mboxRcvAllMsg(prAdapter , (ENUM_MBOX_ID_T)i); + } + + return WLAN_STATUS_SUCCESS; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to enqueue a single TX packet into CORE +* +* @param prAdapter Pointer of Adapter Data Structure +* prNativePacket Pointer of Native Packet +* +* @return WLAN_STATUS_SUCCESS +* WLAN_STATUS_RESOURCES +* WLAN_STATUS_INVALID_PACKET +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanEnqueueTxPacket ( + IN P_ADAPTER_T prAdapter, + IN P_NATIVE_PACKET prNativePacket + ) +{ + P_TX_CTRL_T prTxCtrl; + P_MSDU_INFO_T prMsduInfo; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + prTxCtrl = &prAdapter->rTxCtrl; + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + QUEUE_REMOVE_HEAD(&prTxCtrl->rFreeMsduInfoList, prMsduInfo, P_MSDU_INFO_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + + if(prMsduInfo == NULL) { + return WLAN_STATUS_RESOURCES; + } + else { + prMsduInfo->eSrc = TX_PACKET_OS; + + if(nicTxFillMsduInfo(prAdapter, + prMsduInfo, + prNativePacket) == FALSE) { // packet is not extractable + kalSendComplete(prAdapter->prGlueInfo, + prNativePacket, + WLAN_STATUS_INVALID_PACKET); + + nicTxReturnMsduInfo(prAdapter, prMsduInfo); + + return WLAN_STATUS_INVALID_PACKET; + } + else { + // enqueue to QM + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; + } + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to flush pending TX packets in CORE +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanFlushTxPendingPackets( + IN P_ADAPTER_T prAdapter + ) +{ + ASSERT(prAdapter); + + return nicTxFlush(prAdapter); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief this function sends pending MSDU_INFO_T to MT6620 +* +* @param prAdapter Pointer to the Adapter structure. +* @param pfgHwAccess Pointer for tracking LP-OWN status +* +* @retval WLAN_STATUS_SUCCESS Reset is done successfully. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanTxPendingPackets ( + IN P_ADAPTER_T prAdapter, + IN OUT PBOOLEAN pfgHwAccess + ) +{ + P_TX_CTRL_T prTxCtrl; + P_MSDU_INFO_T prMsduInfo; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + + ASSERT(pfgHwAccess); + + // <1> dequeue packet by txDequeuTxPackets() + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); + prMsduInfo = qmDequeueTxPackets(prAdapter, &prTxCtrl->rTc); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); + + if(prMsduInfo != NULL) { + if(kalIsCardRemoved(prAdapter->prGlueInfo) == FALSE) { + /* <2> Acquire LP-OWN if necessary */ + if(*pfgHwAccess == FALSE) { + *pfgHwAccess = TRUE; + + wlanAcquirePowerControl(prAdapter); + } + +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) + if(prAdapter->fgIsClockGatingEnabled == TRUE) { + nicDisableClockGating(prAdapter); + } +#endif + // <3> send packets + nicTxMsduInfoList(prAdapter, prMsduInfo); + + // <4> update TC by txAdjustTcQuotas() + nicTxAdjustTcq(prAdapter); + } + else { + wlanProcessQueuedMsduInfo(prAdapter, prMsduInfo); + } + } + +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) + if(prAdapter->fgIsClockGatingEnabled == FALSE) { + nicEnableClockGating(prAdapter); + } +#endif + + return WLAN_STATUS_SUCCESS; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to acquire power control from firmware +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanAcquirePowerControl( + IN P_ADAPTER_T prAdapter + ) +{ + ASSERT(prAdapter); + + ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); + + /* Reset sleepy state */ + if(prAdapter->fgWiFiInSleepyState == TRUE) { + prAdapter->fgWiFiInSleepyState = FALSE; + } + + return WLAN_STATUS_SUCCESS; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to release power control to firmware +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanReleasePowerControl( + IN P_ADAPTER_T prAdapter + ) +{ + ASSERT(prAdapter); + + RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); + + return WLAN_STATUS_SUCCESS; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to report currently pending TX frames count +* (command packets are not included) +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return number of pending TX frames +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 +wlanGetTxPendingFrameCount ( + IN P_ADAPTER_T prAdapter + ) +{ + P_TX_CTRL_T prTxCtrl; + UINT_32 u4Num; + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + + u4Num = kalGetTxPendingFrameCount(prAdapter->prGlueInfo) + (UINT_32)(prTxCtrl->i4PendingFwdFrameCount); + + return u4Num; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is to report current ACPI state +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return ACPI_STATE_D0 Normal Operation Mode +* ACPI_STATE_D3 Suspend Mode +*/ +/*----------------------------------------------------------------------------*/ +ENUM_ACPI_STATE_T +wlanGetAcpiState ( + IN P_ADAPTER_T prAdapter + ) +{ + ASSERT(prAdapter); + + return prAdapter->rAcpiState; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is to update current ACPI state only +* +* @param prAdapter Pointer of Adapter Data Structure +* @param ePowerState ACPI_STATE_D0 Normal Operation Mode +* ACPI_STATE_D3 Suspend Mode +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanSetAcpiState ( + IN P_ADAPTER_T prAdapter, + IN ENUM_ACPI_STATE_T ePowerState + ) +{ + ASSERT(prAdapter); + ASSERT(ePowerState <= ACPI_STATE_D3); + + prAdapter->rAcpiState = ePowerState; + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is to query ECO version from HIFSYS CR +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return zero Unable to retrieve ECO version information +* non-zero ECO version (1-based) +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 +wlanGetEcoVersion( + IN P_ADAPTER_T prAdapter + ) +{ + ASSERT(prAdapter); + + if(nicVerifyChipID(prAdapter) == TRUE) { + return (prAdapter->ucRevID + 1); + } + else { + return 0; + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is to setting the default Tx Power configuration +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return zero Unable to retrieve ECO version information +* non-zero ECO version (1-based) +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanDefTxPowerCfg ( + IN P_ADAPTER_T prAdapter + ) +{ + UINT_8 i; + P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; + P_SET_TXPWR_CTRL_T prTxpwr; + + ASSERT(prGlueInfo); + + prTxpwr = &prGlueInfo->rTxPwr; + + prTxpwr->c2GLegacyStaPwrOffset = 0; + prTxpwr->c2GHotspotPwrOffset = 0; + prTxpwr->c2GP2pPwrOffset = 0; + prTxpwr->c2GBowPwrOffset = 0; + prTxpwr->c5GLegacyStaPwrOffset = 0; + prTxpwr->c5GHotspotPwrOffset = 0; + prTxpwr->c5GP2pPwrOffset = 0; + prTxpwr->c5GBowPwrOffset = 0; + prTxpwr->ucConcurrencePolicy = 0; + for (i=0; i<3;i++) + prTxpwr->acReserved1[i] = 0; + + for (i=0; i<14;i++) + prTxpwr->acTxPwrLimit2G[i] = 63; + + for (i=0; i<4;i++) + prTxpwr->acTxPwrLimit5G[i] = 63; + + for (i=0; i<2;i++) + prTxpwr->acReserved2[i] = 0; + +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is to +* set preferred band configuration corresponding to network type +* +* @param prAdapter Pointer of Adapter Data Structure +* @param eBand Given band +* @param eNetTypeIndex Given Network Type +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanSetPreferBandByNetwork ( + IN P_ADAPTER_T prAdapter, + IN ENUM_BAND_T eBand, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex + ) +{ + ASSERT(prAdapter); + ASSERT(eBand <= BAND_NUM); + ASSERT(eNetTypeIndex <= NETWORK_TYPE_INDEX_NUM); + + /* 1. set prefer band according to network type */ + prAdapter->aePreferBand[eNetTypeIndex] = eBand; + + /* 2. remove buffered BSS descriptors correspondingly */ + if(eBand == BAND_2G4) { + scanRemoveBssDescByBandAndNetwork(prAdapter, BAND_5G, eNetTypeIndex); + } + else if(eBand == BAND_5G) { + scanRemoveBssDescByBandAndNetwork(prAdapter, BAND_2G4, eNetTypeIndex); + } + + return; +} + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/common/wlan_oid.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/common/wlan_oid.c new file mode 100755 index 000000000000..8d300b6cc355 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/common/wlan_oid.c @@ -0,0 +1,10556 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/common/wlan_oid.c#2 $ +*/ + +/*! \file wlanoid.c + \brief This file contains the WLAN OID processing routines of Windows driver for + MediaTek Inc. 802.11 Wireless LAN Adapters. +*/ + +/****************************************************************************** +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************* +*/ + +/****************************************************************************** +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************* +*/ + +/* +** $Log: wlan_oid.c $ + * + * 01 19 2012 yuche.tsai + * NULL + * Fix RX filter issue for P2P network. + * + * 01 09 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Check in the Add Tx power Cmd to driver. + * + * 12 20 2011 cp.wu + * [WCXRP00001144] [MT6620 Wi-Fi][Driver][Firmware] Add RF_FUNC_ID for exposing device and related version information + * add driver implementations for RF_AT_FUNCID_FW_INFO & RF_AT_FUNCID_DRV_INFO + * to expose version information + * + * 12 06 2011 cp.wu + * [WCXRP00001131] [MT6620 Wi-Fi][Driver][AIS] Implement connect-by-BSSID path + * sync. for connect-by-bssid control path implementations. + * + * 11 22 2011 cp.wu + * [WCXRP00001120] [MT6620 Wi-Fi][Driver] Modify roaming to AIS state transition from synchronous to asynchronous approach to avoid incomplete state termination + * 1. change RDD related compile option brace position. + * 2. when roaming is triggered, ask AIS to transit immediately only when AIS is in Normal TR state without join timeout timer ticking + * 3. otherwise, insert AIS_REQUEST into pending request queue + * + * 11 21 2011 cp.wu + * [WCXRP00001118] [MT6620 Wi-Fi][Driver] Corner case protections to pass Monkey testing + * 1. wlanoidQueryBssIdList might be passed with a non-zero length but a NULL pointer of buffer + * add more checking for such cases + * + * 2. kalSendComplete() might be invoked with a packet belongs to P2P network right after P2P is unregistered. + * add some tweaking to protect such cases because that net device has become invalid. + * + * 11 15 2011 cm.chang + * NULL + * Fix compiling warning + * + * 11 11 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * modify the xlog related code. + * + * 11 10 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters of ar and bb for xlog. + * + * 11 10 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * change the debug module level. + * + * 11 09 2011 george.huang + * [WCXRP00000871] [MT6620 Wi-Fi][FW] Include additional wakeup condition, which is by consequent DTIM unicast indication + * add XLOG for Set PS mode entry + * + * 11 08 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * check if CFG_SUPPORT_SWCR is defined to avoid compiler error. + * + * 11 04 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters and periodically dump counters for Xlog debugging. + * + * 11 03 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * change the DBGLOG for "\n" and "\r\n". LABEL to LOUD for XLOG + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 08 17 2011 tsaiyuan.hsu + * [WCXRP00000938] [MT6620 Wi-Fi][FW] add system config for CTIA + * add system config for CTIA. + * + * 08 15 2011 george.huang + * [MT6620 Wi-Fi][FW] handle TSF drift for connection detection + * . + * + * 07 11 2011 wh.su + * [WCXRP00000849] [MT6620 Wi-Fi][Driver] Remove some of the WAPI define for make sure the value is initialize, for customer not enable WAPI + * For make sure wapi initial value is set. + * + * 06 23 2011 cp.wu + * [WCXRP00000812] [MT6620 Wi-Fi][Driver] not show NVRAM when there is no valid MAC address in NVRAM content + * check with firmware for valid MAC address. + * + * 05 02 2011 eddie.chen + * [WCXRP00000373] [MT6620 Wi-Fi][FW] SW debug control + * Fix compile warning. + * + * 04 29 2011 george.huang + * [WCXRP00000684] [MT6620 Wi-Fi][Driver] Support P2P setting ARP filter + * . + * + * 04 27 2011 george.huang + * [WCXRP00000684] [MT6620 Wi-Fi][Driver] Support P2P setting ARP filter + * add more debug message + * + * 04 26 2011 eddie.chen + * [WCXRP00000373] [MT6620 Wi-Fi][FW] SW debug control + * Add uapsd, online scan in sw control. + * + * 04 12 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix the sta index in processing security frame + * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 + * Add debug message. + * + * 04 08 2011 george.huang + * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode + * separate settings of P2P and AIS + * + * 03 29 2011 cp.wu + * [WCXRP00000604] [MT6620 Wi-Fi][Driver] Surpress Klockwork Warning + * surpress klock warning with code path rewritten + * + * 03 24 2011 wh.su + * [WCXRP00000595] [MT6620 Wi-Fi][Driver] at CTIA indicate disconnect to make the ps profile can apply + * use disconnect event instead of ais abort for CTIA testing. + * + * 03 22 2011 george.huang + * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command + * link with supplicant commands + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 03 17 2011 yarco.yang + * [WCXRP00000569] [MT6620 Wi-Fi][F/W][Driver] Set multicast address support current network usage + * . + * + * 03 15 2011 george.huang + * [WCXRP00000557] [MT6620 Wi-Fi] Support current consumption test mode commands + * Support current consumption measurement mode command + * + * 03 15 2011 eddie.chen + * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter + * Add sw debug counter for QM. + * + * 03 10 2011 cp.wu + * [WCXRP00000532] [MT6620 Wi-Fi][Driver] Migrate NVRAM configuration procedures from MT6620 E2 to MT6620 E3 + * deprecate configuration used by MT6620 E2 + * + * 03 07 2011 terry.wu + * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message + * Toggle non-standard debug messages to comments. + * + * 03 04 2011 cp.wu + * [WCXRP00000515] [MT6620 Wi-Fi][Driver] Surpress compiler warning which is identified by GNU compiler collection + * surpress compile warning occured when compiled by GNU compiler collection. + * + * 03 03 2011 wh.su + * [WCXRP00000510] [MT6620 Wi-Fi] [Driver] Fixed the CTIA enter test mode issue + * fixed the enter ctia test mode issue. + * + * 03 02 2011 george.huang + * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command + * Update sigma CAPI for U-APSD setting + * + * 03 02 2011 george.huang + * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command + * Support UAPSD/OppPS/NoA parameter setting + * + * 03 02 2011 cp.wu + * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right after connection is built. + * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. + * + * 01 27 2011 george.huang + * [WCXRP00000400] [MT6620 Wi-Fi] support CTIA power mode setting + * Support CTIA power mode setting. + * + * 01 26 2011 wh.su + * [WCXRP00000396] [MT6620 Wi-Fi][Driver] Support Sw Ctrl ioctl at linux + * adding the SW cmd ioctl support, use set/get structure ioctl. + * + * 01 25 2011 cp.wu + * [WCXRP00000394] [MT6620 Wi-Fi][Driver] Count space needed for generating error message in scanning list into buffer size checking + * when doing size prechecking, check illegal MAC address as well + * + * 01 20 2011 eddie.chen + * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control + * Add Oid for sw control debug command + * + * 01 15 2011 puff.wen + * NULL + * Add Stress test + * + * 01 12 2011 cp.wu + * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module + * check if allow to switch to IBSS mode via concurrent module before setting to IBSS mode + * + * 01 12 2011 cm.chang + * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting + * User-defined bandwidth is for 2.4G and 5G individually + * + * 01 04 2011 cp.wu + * [WCXRP00000342] [MT6620 Wi-Fi][Driver] show error code in scanning list when MAC address is not correctly configured in NVRAM + * show error code 0x10 when MAC address in NVRAM is not configured correctly. + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease physically continous memory demands + * separate kalMemAlloc() into virtually-continous and physically-continous type to ease slab system pressure + * + * 12 28 2010 george.huang + * [WCXRP00000232] [MT5931 Wi-Fi][FW] Modifications for updated HW power on sequence and related design + * support WMM-PS U-APSD AC assignment. + * + * 12 28 2010 cp.wu + * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release + * report EEPROM used flag via NIC_CAPABILITY + * + * 12 28 2010 cp.wu + * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release + * integrate with 'EEPROM used' flag for reporting correct capability to Engineer Mode/META and other tools + * + * 12 16 2010 cp.wu + * [WCXRP00000268] [MT6620 Wi-Fi][Driver] correction for WHQL failed items + * correction for OID_802_11_NETWORK_TYPES_SUPPORTED handlers + * + * 12 13 2010 cp.wu + * [WCXRP00000256] [MT6620 Wi-Fi][Driver] Eliminate potential issues which is identified by Klockwork + * suppress warning reported by Klockwork. + * + * 12 07 2010 cm.chang + * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk + * 1. BSSINFO include RLM parameter + * 2. free all sta records when network is disconnected + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 11 30 2010 cp.wu + * [WCXRP00000213] [MT6620 Wi-Fi][Driver] Implement scanning with specified SSID for wpa_supplicant with ap_scan=1 + * . + * + * 11 26 2010 cp.wu + * [WCXRP00000209] [MT6620 Wi-Fi][Driver] Modify NVRAM checking mechanism to warning only with necessary data field checking + * 1. NVRAM error is now treated as warning only, thus normal operation is still available but extra scan result used to indicate user is attached + * 2. DPD and TX-PWR are needed fields from now on, if these 2 fields are not availble then warning message is shown + * + * 11 25 2010 cp.wu + * [WCXRP00000208] [MT6620 Wi-Fi][Driver] Add scanning with specified SSID to AIS FSM + * add scanning with specified SSID facility to AIS-FSM + * + * 11 21 2010 wh.su + * [WCXRP00000192] [MT6620 Wi-Fi][Driver] Fixed fail trying to build connection with Security AP while enable WAPI message check + * Not set the wapi mode while the wapi assoc info set non-wapi ie. + * + * 11 05 2010 wh.su + * [WCXRP00000165] [MT6620 Wi-Fi] [Pre-authentication] Assoc req rsn ie use wrong pmkid value + * fixed the.pmkid value mismatch issue + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 10 26 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command + * 1) update NVRAM content template to ver 1.02 + * 2) add compile option for querying NIC capability (default: off) + * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting + * 4) correct auto-rate compiler error under linux (treat warning as error) + * 5) simplify usage of NVRAM and REG_INFO_T + * 6) add version checking between driver and firmware + * + * 10 22 2010 cp.wu + * [WCXRP00000122] [MT6620 Wi-Fi][Driver] Preparation for YuSu source tree integration + * dos2unix conversion. + * + * 10 20 2010 cp.wu + * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore + * use OID_CUSTOM_TEST_MODE as indication for driver reset + * by dropping pending TX packets + * + * 10 18 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android + * complete implementation of Android NVRAM access + * + * 10 06 2010 yuche.tsai + * NULL + * Update SLT 5G Test Channel Set. + * + * 10 06 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * code reorganization to improve isolation between GLUE and CORE layers. + * + * 10 06 2010 yuche.tsai + * NULL + * Update For SLT 5G Test Channel Selection Rule. + * + * 10 05 2010 cp.wu + * [WCXRP00000075] [MT6620 Wi-Fi][Driver] Fill query buffer for OID_802_11_BSSID_LIST in 4-bytes aligned form + * Query buffer size needs to be enlarged due to result is filled in 4-bytes alignment boundary + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * 1) add NVRAM access API + * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) + * 3) add OID implementation for NVRAM read/write service + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by ENUM_NETWORK_TYPE_INDEX_T only + * remove ENUM_NETWORK_TYPE_T definitions + * + * 10 04 2010 cp.wu + * [WCXRP00000075] [MT6620 Wi-Fi][Driver] Fill query buffer for OID_802_11_BSSID_LIST in 4-bytes aligned form + * Extend result length to multiples of 4-bytes + * + * 09 24 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * eliminate unused variables which lead gcc to argue + * + * 09 24 2010 cp.wu + * [WCXRP00000057] [MT6620 Wi-Fi][Driver] Modify online scan to a run-time switchable feature + * Modify online scan as a run-time adjustable option (for Windows, in registry) + * + * 09 23 2010 cp.wu + * [WCXRP00000051] [MT6620 Wi-Fi][Driver] WHQL test fail in MAC address changed item + * use firmware reported mac address right after wlanAdapterStart() as permanent address + * + * 09 23 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * add skeleton for NVRAM integration + * + * 09 08 2010 cp.wu + * NULL + * use static memory pool for storing IEs of scanning result. + * + * 09 07 2010 yuche.tsai + * NULL + * Update SLT due to API change of SCAN module. + * + * 09 06 2010 cp.wu + * NULL + * Androi/Linux: return current operating channel information + * + * 09 06 2010 cp.wu + * NULL + * 1) initialize for correct parameter even for disassociation. + * 2) AIS-FSM should have a limit on trials to build connection + * + * 09 03 2010 yuche.tsai + * NULL + * Refine SLT IO control handler. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 09 01 2010 wh.su + * NULL + * adding the wapi support for integration test. + * + * 08 30 2010 chinglan.wang + * NULL + * Modify the rescan condition. + * + * 08 29 2010 yuche.tsai + * NULL + * Finish SLT TX/RX & Rate Changing Support. + * + * 08 27 2010 chinglan.wang + * NULL + * Update configuration for MT6620_E1_PRE_ALPHA_1832_0827_2010 + * + * 08 25 2010 george.huang + * NULL + * update OID/ registry control path for PM related settings + * + * 08 24 2010 cp.wu + * NULL + * 1) initialize variable for enabling short premable/short time slot. + * 2) add compile option for disabling online scan + * + * 08 16 2010 george.huang + * NULL + * . + * + * 08 16 2010 george.huang + * NULL + * upate params defined in CMD_SET_NETWORK_ADDRESS_LIST + * + * 08 04 2010 cp.wu + * NULL + * fix for check build WHQL testing: + * 1) do not assert query buffer if indicated buffer length is zero + * 2) sdio.c has bugs which cause freeing same pointer twice + * + * 08 04 2010 cp.wu + * NULL + * revert changelist #15371, efuse read/write access will be done by RF test approach + * + * 08 04 2010 cp.wu + * NULL + * add OID definitions for EFUSE read/write access. + * + * 08 04 2010 george.huang + * NULL + * handle change PS mode OID/ CMD + * + * 08 04 2010 cp.wu + * NULL + * add an extra parameter to rftestQueryATInfo 'cause it's necessary to pass u4FuncData for query request. + * + * 08 04 2010 cp.wu + * NULL + * bypass u4FuncData for RF-Test query request as well. + * + * 08 04 2010 yarco.yang + * NULL + * Add TX_AMPDU and ADDBA_REJECT command + * + * 08 03 2010 cp.wu + * NULL + * surpress compilation warning. + * + * 08 02 2010 george.huang + * NULL + * add WMM-PS test related OID/ CMD handlers + * + * 07 29 2010 cp.wu + * NULL + * eliminate u4FreqInKHz usage, combined into rConnections.ucAdHoc* + * + * 07 28 2010 cp.wu + * NULL + * 1) eliminate redundant variable eOPMode in prAdapter->rWlanInfo + * 2) change nicMediaStateChange() API prototype + * + * 07 26 2010 cp.wu + * + * re-commit code logic being overwriten. + * + * 07 24 2010 wh.su + * + * .support the Wi-Fi RSN + * + * 07 21 2010 cp.wu + * + * 1) change BG_SCAN to ONLINE_SCAN for consistent term + * 2) only clear scanning result when scan is permitted to do + * + * 07 20 2010 cp.wu + * + * 1) [AIS] when new scan is issued, clear currently available scanning result except the connected one + * 2) refine disconnection behaviour when issued during BG-SCAN process + * + * 07 19 2010 wh.su + * + * modify the auth and encry status variable. + * + * 07 16 2010 cp.wu + * + * remove work-around in case SCN is not available. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 05 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) change fake BSS_DESC from channel 6 to channel 1 due to channel switching is not done yet. + * 2) after MAC address is queried from firmware, all related variables in driver domain should be updated as well + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * AIS-FSM integration with CNM channel request messages + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implementation of DRV-SCN and related mailbox message handling. + * + * 06 29 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) sync to. CMD/EVENT document v0.03 + * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. + * 3) send command packet to indicate FW-PM after + * a) 1st beacon is received after AIS has connected to an AP + * b) IBSS-ALONE has been created + * c) IBSS-MERGE has occured + * + * 06 25 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add API in que_mgt to retrieve sta-rec index for security frames. + * + * 06 24 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path. + * + * 06 23 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add SCN compilation option. + * 2) when SCN is not turned on, BSSID_SCAN will generate a fake entry for 1st connection + * + * 06 23 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implement SCAN-REQUEST oid as mailbox message dispatching. + * + * 06 23 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * integrate . + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add command warpper for STA-REC/BSS-INFO sync. + * 2) enhance command packet sending procedure for non-oid part + * 3) add command packet definitions for STA-REC/BSS-INFO sync. + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * remove duplicate variable for migration. + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * adding the compiling flag for oid pmkid. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * enable RX management frame handling. + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration the security related function from firmware. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 + * 2) when disconnected, indicate nic directly (no event is needed) + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge wlan_def.h. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge wifi_var.h, precomp.h, cnm_timer.h (data type only) + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 06 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * move timer callback to glue layer. + * + * 05 28 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * simplify cmd packet sending for RF test and MCR access OIDs + * + * 05 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * disable radio even when STA is not associated. + * + * 05 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct 2 OID behaviour to meet WHQL requirement. + * + * 05 26 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * 1) Modify set mac address code + * 2) remove power managment macro + * + * 05 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct BSSID_LIST oid when radio if turned off. + * + * 05 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) when acquiring LP-own, write for clr-own with lower frequency compared to read poll + * 2) correct address list parsing + * + * 05 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * disable wlanoidSetNetworkAddress() temporally. + * + * 05 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * some OIDs should be DRIVER_CORE instead of GLUE_EXTENSION + * + * 05 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) disable NETWORK_LAYER_ADDRESSES handling temporally. + * 2) finish statistics OIDs + * + * 05 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * change OID behavior to meet WHQL requirement. + * + * 05 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS + * 2) buffer statistics data for 2 seconds + * 3) use default value for adhoc parameters instead of 0 + * + * 05 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) do not take timeout mechanism for power mode oids + * 2) retrieve network type from connection status + * 3) after disassciation, set radio state to off + * 4) TCP option over IPv6 is supported + * + * 05 18 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement Wakeup-on-LAN except firmware integration part + * + * 05 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct wlanoidSet802dot11PowerSaveProfile implementation. + * + * 05 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) enable CMD/EVENT ver 0.9 definition. + * 2) abandon use of ENUM_MEDIA_STATE + * + * 05 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct OID_802_11_DISASSOCIATE handling. + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * 1) add timeout handler mechanism for pending command packets + * 2) add p2p add/removal key + * + * 05 14 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Add dissassocation support for wpa supplicant + * + * 05 14 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct return value. + * + * 05 13 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add NULL OID implementation for WOL-related OIDs. + * + * 05 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * for disassociation, still use parameter with current setting. + * + * 05 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * for disassociation, generate a WZC-compatible invalid SSID. + * + * 05 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * associate to illegal SSID when handling OID_802_11_DISASSOCIATE + * + * 04 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * reserve field of privacy filter and RTS threshold setting. + * + * 04 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * surpress compiler warning + * + * 04 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * . + * + * 04 22 2010 cp.wu + * [WPD00003830]add OID_802_11_PRIVACY_FILTER support + * enable RX filter OID + * + * 04 19 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Add ioctl of power management + * + * 04 14 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * information buffer for query oid/ioctl is now buffered in prCmdInfo + * * instead of glue-layer variable to improve multiple oid/ioctl capability + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * 2) command sequence number is now increased atomically + * * * * 3) private data could be hold and taken use for other purpose + * + * 04 12 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct OID_802_11_CONFIGURATION query for infrastructure mode. + * + * 04 09 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * 1) remove unused spin lock declaration + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * finish non-glue layer access to glue variables + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * rWlanInfo should be placed at adapter rather than glue due to most operations + * * are done in adapter layer. + * + * 04 07 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * (1)improve none-glue code portability + * (2) disable set Multicast address during atomic context + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access to prGlueInfo->eParamMediaStateIndicated from non-glue layer + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * ePowerCtrl is not necessary as a glue variable. + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access to prGlueInfo->rWlanInfo.eLinkAttr.ucMediaStreamMode from non-glue layer. + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * improve none-glue code portability + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved + * + * 04 01 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * . + * + * 03 31 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * modify the wapi related code for new driver's design. + * + * 03 30 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * statistics information OIDs are now handled by querying from firmware domain + * + * 03 28 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * improve glue code portability + * + * 03 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * indicate media stream mode after set is done + * + * 03 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add a temporary flag for integration with CMD/EVENT v0.9. + * + * 03 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) correct OID_802_11_CONFIGURATION with frequency setting behavior. + * the frequency is used for adhoc connection only + * 2) update with SD1 v0.9 CMD/EVENT documentation + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * [WPD00003826] Initial import for Linux port + * initial import for Linux port + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port + * + * 03 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * generate information for OID_GEN_RCV_OK & OID_GEN_XMIT_OK + * + * + * 03 22 2010 cp.wu + * [WPD00003824][MT6620 Wi-Fi][New Feature] Add support of large scan list + * Implement feature needed by CR: WPD00003824: refining association command by pasting scanning result + * + * 03 19 2010 wh.su + * [WPD00003820][MT6620 Wi-Fi] Modify the code for meet the WHQL test + * adding the check for pass WHQL test item. + * + * 03 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add ACPI D0/D3 state switching support + * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response + * +* 03 16 2010 wh.su + * [WPD00003820][MT6620 Wi-Fi] Modify the code for meet the WHQL test + * fixed some whql pre-test fail case. + * + * 03 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement custom OID: EEPROM read/write access + * + * 03 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement OID_802_3_MULTICAST_LIST oid handling + * + * 03 02 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) the use of prPendingOid revised, all accessing are now protected by spin lock + * * 2) ensure wlanReleasePendingOid will clear all command queues + * + * 02 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * send CMD_ID_INFRASTRUCTURE when handling OID_802_11_INFRASTRUCTURE_MODE set. + * + * 02 24 2010 wh.su + * [WPD00003820][MT6620 Wi-Fi] Modify the code for meet the WHQL test + * Don't needed to check the auth mode, WHQL testing not specific at auth wpa2. + * + * 02 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * do not check SSID validity anymore. + * + * 02 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add checksum offloading support. + * + * 02 09 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address + * * 2. follow MSDN defined behavior when associates to another AP + * * 3. for firmware download, packet size could be up to 2048 bytes + * + * 02 09 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * move ucCmdSeqNum as instance variable + * + * 02 04 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * when OID_CUSTOM_OID_INTERFACE_VERSION is queried, do modify connection states + * + * 01 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) implement timeout mechanism when OID is pending for longer than 1 second + * * 2) allow OID_802_11_CONFIGURATION to be executed when RF test mode is turned on + * + * 01 27 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * . + * + * 01 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. eliminate improper variable in rHifInfo + * * 2. block TX/ordinary OID when RF test mode is engaged + * * 3. wait until firmware finish operation when entering into and leaving from RF test mode + * * 4. correct some HAL implementation + * + * 01 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement following 802.11 OIDs: + * OID_802_11_RSSI, + * OID_802_11_RSSI_TRIGGER, + * OID_802_11_STATISTICS, + * OID_802_11_DISASSOCIATE, + * OID_802_11_POWER_MODE + * + * 01 21 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement OID_802_11_MEDIA_STREAM_MODE + * + * 01 21 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement OID_802_11_SUPPORTED_RATES / OID_802_11_DESIRED_RATES + * + * 01 21 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * do not fill ucJoinOnly currently + * + * 01 14 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * enable to connect to ad-hoc network + * + * 01 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * .implement Set/Query BeaconInterval/AtimWindow + * + * 01 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * .Set/Get AT Info is not blocked even when driver is not in fg test mode + * + * 12 30 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) According to CMD/EVENT documentation v0.8, + * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, + * and result is retrieved by get ATInfo instead + * 2) add 4 counter for recording aggregation statistics + * + * 12 28 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate redundant variables for connection_state +** \main\maintrunk.MT6620WiFiDriver_Prj\32 2009-12-16 22:13:36 GMT mtk02752 +** change hard-coded MAC address to match with FW (temporally) +** \main\maintrunk.MT6620WiFiDriver_Prj\31 2009-12-10 16:49:50 GMT mtk02752 +** code clean +** \main\maintrunk.MT6620WiFiDriver_Prj\30 2009-12-08 17:38:49 GMT mtk02752 +** + add OID for RF test +** * MCR RD/WR are modified to match with cmd/event definition +** \main\maintrunk.MT6620WiFiDriver_Prj\29 2009-12-08 11:32:20 GMT mtk02752 +** add skeleton for RF test implementation +** \main\maintrunk.MT6620WiFiDriver_Prj\28 2009-12-03 16:43:24 GMT mtk01461 +** Modify query SCAN list oid by adding prEventScanResult +** +** \main\maintrunk.MT6620WiFiDriver_Prj\27 2009-12-03 16:39:27 GMT mtk01461 +** Sync CMD data structure in set ssid oid +** \main\maintrunk.MT6620WiFiDriver_Prj\26 2009-12-03 16:28:22 GMT mtk01461 +** Add invalid check of set SSID oid and fix query scan list oid +** \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-11-30 17:33:08 GMT mtk02752 +** implement wlanoidSetInfrastructureMode/wlanoidQueryInfrastructureMode +** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-11-30 10:53:49 GMT mtk02752 +** 1st DW of WIFI_CMD_T is shared with HIF_TX_HEADER_T +** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-11-30 09:22:48 GMT mtk02752 +** correct wifi cmd length mismatch +** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-25 21:34:33 GMT mtk02752 +** sync EVENT_SCAN_RESULT_T with firmware +** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-25 21:03:27 GMT mtk02752 +** implement wlanoidQueryBssidList() +** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-11-25 18:17:17 GMT mtk02752 +** refine GL_WLAN_INFO_T for buffering scan result +** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-11-23 20:28:51 GMT mtk02752 +** some OID will be set to WLAN_STATUS_PENDING until it is sent via wlanSendCommand() +** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-11-23 17:56:36 GMT mtk02752 +** implement wlanoidSetBssidListScan(), wlanoidSetBssid() and wlanoidSetSsid() +** +** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-11-13 17:20:53 GMT mtk02752 +** add Set BSSID/SSID path but disabled temporally due to FW is not ready yet +** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-11-13 12:28:58 GMT mtk02752 +** add wlanoidSetBssidListScan -> cmd_info path +** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-11-09 22:48:07 GMT mtk01084 +** modify test cases entry +** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-11-04 14:10:58 GMT mtk01084 +** add new test interfaces +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-10-30 18:17:10 GMT mtk01084 +** fix compiler warning +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-10-29 19:46:26 GMT mtk01084 +** add test functions +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-10-23 16:07:56 GMT mtk01084 +** include new file +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-10-13 21:58:29 GMT mtk01084 +** modify for new HW architecture +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-10-02 13:48:49 GMT mtk01725 +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-09-09 17:26:04 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-21 12:09:50 GMT mtk01461 +** Update for MCR Write OID +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-21 09:35:18 GMT mtk01461 +** Update wlanoidQueryMcrRead() for composing CMD_INFO_T +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-17 18:09:51 GMT mtk01426 +** Remove kalIndicateStatusAndComplete() in wlanoidQueryOidInterfaceVersion() +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-04-14 15:51:50 GMT mtk01426 +** Add MCR read/write support +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-19 18:32:40 GMT mtk01084 +** update for basic power management functions +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:06:31 GMT mtk01426 +** Init for develop +** +*/ + +/****************************************************************************** +* C O M P I L E R F L A G S +******************************************************************************* +*/ + +/****************************************************************************** +* E X T E R N A L R E F E R E N C E S +******************************************************************************* +*/ +#include "precomp.h" +#include "mgmt/rsn.h" + +#include + +/****************************************************************************** +* C O N S T A N T S +******************************************************************************* +*/ +#define NVRAM_ERROR_VERSION_MISMATCH BIT(1) +#define NVRAM_ERROR_INVALID_TXPWR BIT(2) +#define NVRAM_ERROR_INVALID_DPD BIT(3) +#define NVRAM_ERROR_INVALID_MAC_ADDR BIT(4) + +/****************************************************************************** +* D A T A T Y P E S +******************************************************************************* +*/ + +/****************************************************************************** +* P U B L I C D A T A +******************************************************************************* +*/ +#if DBG +extern UINT_8 aucDebugModule[DBG_MODULE_NUM]; +extern UINT_32 u4DebugModule; +UINT_32 u4DebugModuleTemp; +#endif /* DBG */ + +/****************************************************************************** +* P R I V A T E D A T A +******************************************************************************* +*/ + +/****************************************************************************** +* M A C R O S +******************************************************************************* +*/ + +/****************************************************************************** +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************* +*/ +extern int sprintf(char * buf, const char * fmt, ...); + +/****************************************************************************** +* F U N C T I O N S +******************************************************************************* +*/ +#if CFG_ENABLE_STATISTICS_BUFFERING +static BOOLEAN +IsBufferedStatisticsUsable( + P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + if(prAdapter->fgIsStatValid == TRUE && + (kalGetTimeTick() - prAdapter->rStatUpdateTime) <= CFG_STATISTICS_VALID_CYCLE) + return TRUE; + else + return FALSE; +} +#endif + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the supported physical layer network +* type that can be used by the driver. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryNetworkTypesSupported ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + UINT_32 u4NumItem = 0; + ENUM_PARAM_NETWORK_TYPE_T eSupportedNetworks[PARAM_NETWORK_TYPE_NUM]; + PPARAM_NETWORK_TYPE_LIST prSupported; + + /* The array of all physical layer network subtypes that the driver supports. */ + + DEBUGFUNC("wlanoidQueryNetworkTypesSupported"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + /* Init. */ + for (u4NumItem = 0; u4NumItem < PARAM_NETWORK_TYPE_NUM ; u4NumItem++) { + eSupportedNetworks[u4NumItem] = 0; + } + + u4NumItem = 0; + + eSupportedNetworks[u4NumItem] = PARAM_NETWORK_TYPE_DS; + u4NumItem ++; + + eSupportedNetworks[u4NumItem] = PARAM_NETWORK_TYPE_OFDM24; + u4NumItem ++; + + *pu4QueryInfoLen = + (UINT_32)OFFSET_OF(PARAM_NETWORK_TYPE_LIST, eNetworkType) + + (u4NumItem * sizeof(ENUM_PARAM_NETWORK_TYPE_T)); + + if (u4QueryBufferLen < *pu4QueryInfoLen) { + return WLAN_STATUS_INVALID_LENGTH; + } + + prSupported = (PPARAM_NETWORK_TYPE_LIST)pvQueryBuffer; + prSupported->NumberOfItems = u4NumItem; + kalMemCopy(prSupported->eNetworkType, + eSupportedNetworks, + u4NumItem * sizeof(ENUM_PARAM_NETWORK_TYPE_T)); + + DBGLOG(REQ, TRACE, ("NDIS supported network type list: %ld\n", + prSupported->NumberOfItems)); + DBGLOG_MEM8(REQ, INFO, prSupported, *pu4QueryInfoLen); + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryNetworkTypesSupported */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the current physical layer network +* type used by the driver. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the +* call failed due to invalid length of the query +* buffer, returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryNetworkTypeInUse ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + // TODO: need to check the OID handler content again!! + + ENUM_PARAM_NETWORK_TYPE_T rCurrentNetworkTypeInUse = PARAM_NETWORK_TYPE_OFDM24; + + DEBUGFUNC("wlanoidQueryNetworkTypeInUse"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + if (u4QueryBufferLen < sizeof(ENUM_PARAM_NETWORK_TYPE_T)) { + *pu4QueryInfoLen = sizeof(ENUM_PARAM_NETWORK_TYPE_T); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { + rCurrentNetworkTypeInUse = + (ENUM_PARAM_NETWORK_TYPE_T)(prAdapter->rWlanInfo.ucNetworkType); + } + else { + rCurrentNetworkTypeInUse = + (ENUM_PARAM_NETWORK_TYPE_T)(prAdapter->rWlanInfo.ucNetworkTypeInUse); + } + + *(P_ENUM_PARAM_NETWORK_TYPE_T)pvQueryBuffer = rCurrentNetworkTypeInUse; + *pu4QueryInfoLen = sizeof(ENUM_PARAM_NETWORK_TYPE_T); + + DBGLOG(REQ, TRACE, ("Network type in use: %d\n", rCurrentNetworkTypeInUse)); + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryNetworkTypeInUse */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set the physical layer network type used +* by the driver. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns the +* amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS The given network type is supported and accepted. +* \retval WLAN_STATUS_INVALID_DATA The given network type is not in the +* supported list. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetNetworkTypeInUse ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + // TODO: need to check the OID handler content again!! + + ENUM_PARAM_NETWORK_TYPE_T eNewNetworkType; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + DEBUGFUNC("wlanoidSetNetworkTypeInUse"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen < sizeof(ENUM_PARAM_NETWORK_TYPE_T)) { + *pu4SetInfoLen = sizeof(ENUM_PARAM_NETWORK_TYPE_T); + return WLAN_STATUS_INVALID_LENGTH; + } + + eNewNetworkType = *(P_ENUM_PARAM_NETWORK_TYPE_T)pvSetBuffer; + *pu4SetInfoLen = sizeof(ENUM_PARAM_NETWORK_TYPE_T); + + DBGLOG(REQ, + INFO, + ("New network type: %d mode\n", eNewNetworkType)); + + switch (eNewNetworkType) { + + case PARAM_NETWORK_TYPE_DS: + prAdapter->rWlanInfo.ucNetworkTypeInUse = (UINT_8) PARAM_NETWORK_TYPE_DS; + break; + + case PARAM_NETWORK_TYPE_OFDM5: + prAdapter->rWlanInfo.ucNetworkTypeInUse = (UINT_8) PARAM_NETWORK_TYPE_OFDM5; + break; + + case PARAM_NETWORK_TYPE_OFDM24: + prAdapter->rWlanInfo.ucNetworkTypeInUse = (UINT_8) PARAM_NETWORK_TYPE_OFDM24; + break; + + case PARAM_NETWORK_TYPE_AUTOMODE: + prAdapter->rWlanInfo.ucNetworkTypeInUse = (UINT_8) PARAM_NETWORK_TYPE_AUTOMODE; + break; + + case PARAM_NETWORK_TYPE_FH: + DBGLOG(REQ, INFO, ("Not support network type: %d\n", eNewNetworkType)); + rStatus = WLAN_STATUS_NOT_SUPPORTED; + break; + + default: + DBGLOG(REQ, INFO, ("Unknown network type: %d\n", eNewNetworkType)); + rStatus = WLAN_STATUS_INVALID_DATA; + break; + } + + /* Verify if we support the new network type. */ + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, ("Unknown network type: %d\n", eNewNetworkType)); + } + + return rStatus; +} /* wlanoidSetNetworkTypeInUse */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the current BSSID. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryBssid ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidQueryBssid"); + + ASSERT(prAdapter); + + if (u4QueryBufferLen < MAC_ADDR_LEN) { + ASSERT(pu4QueryInfoLen); + *pu4QueryInfoLen = MAC_ADDR_LEN; + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + ASSERT(u4QueryBufferLen >= MAC_ADDR_LEN); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + if(kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { + kalMemCopy(pvQueryBuffer, prAdapter->rWlanInfo.rCurrBssId.arMacAddress, MAC_ADDR_LEN); + } + else if(prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_IBSS) { + PARAM_MAC_ADDRESS aucTemp; /*!< BSSID */ + COPY_MAC_ADDR(aucTemp, prAdapter->rWlanInfo.rCurrBssId.arMacAddress); + aucTemp[0] &= ~BIT(0); + aucTemp[1] |= BIT(1); + COPY_MAC_ADDR(pvQueryBuffer, aucTemp); + } + else { + rStatus = WLAN_STATUS_ADAPTER_NOT_READY; + } + + *pu4QueryInfoLen = MAC_ADDR_LEN; + return rStatus; +} /* wlanoidQueryBssid */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the list of all BSSIDs detected by +* the driver. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryBssidList ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ +#if (CFG_NVRAM_EXISTENCE_CHECK == 1) || (CFG_SW_NVRAM_VERSION_CHECK == 1) + const UINT_8 aucZeroMacAddr[] = NULL_MAC_ADDR; + BOOLEAN fgIsConfExist = TRUE; + P_REG_INFO_T prRegInfo; +#endif + + P_GLUE_INFO_T prGlueInfo; + UINT_32 i, u4BssidListExLen; + P_PARAM_BSSID_LIST_EX_T prList; + P_PARAM_BSSID_EX_T prBssidEx; + PUINT_8 cp; + + DEBUGFUNC("wlanoidQueryBssidList"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + + if(!pvQueryBuffer) { + return WLAN_STATUS_INVALID_DATA; + } + } + + prGlueInfo = prAdapter->prGlueInfo; + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in qeury BSSID list! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + u4BssidListExLen = 0; + + if(prAdapter->fgIsRadioOff == FALSE) { + for(i = 0 ; i < prAdapter->rWlanInfo.u4ScanResultNum ; i++) { + u4BssidListExLen += ALIGN_4(prAdapter->rWlanInfo.arScanResult[i].u4Length); + } + } + +#if (CFG_NVRAM_EXISTENCE_CHECK == 1) + if(kalIsConfigurationExist(prAdapter->prGlueInfo) == FALSE) { + fgIsConfExist = FALSE; + u4BssidListExLen += OFFSET_OF(PARAM_BSSID_EX_T, aucIEs); + } +#endif + +#if (CFG_SW_NVRAM_VERSION_CHECK == 1) + prRegInfo = kalGetConfiguration(prGlueInfo); + + if(fgIsConfExist == TRUE && + (CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2Part1CfgPeerVersion + || CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2Part2CfgPeerVersion + || prAdapter->rVerInfo.u2Part1CfgOwnVersion < CFG_DRV_PEER_VERSION + || prAdapter->rVerInfo.u2Part2CfgOwnVersion < CFG_DRV_PEER_VERSION /* NVRAM */ + || CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2FwPeerVersion + || prAdapter->rVerInfo.u2FwOwnVersion < CFG_DRV_PEER_VERSION + || (prAdapter->fgIsEmbbededMacAddrValid == FALSE && + (IS_BMCAST_MAC_ADDR(prRegInfo->aucMacAddr) + || EQUAL_MAC_ADDR(aucZeroMacAddr, prRegInfo->aucMacAddr))) + || prRegInfo->ucTxPwrValid == 0)) { + u4BssidListExLen += OFFSET_OF(PARAM_BSSID_EX_T, aucIEs); + } +#endif + + if(u4BssidListExLen) { + u4BssidListExLen += 4; // u4NumberOfItems. + } + else { + u4BssidListExLen = sizeof(PARAM_BSSID_LIST_EX_T); + } + + *pu4QueryInfoLen = u4BssidListExLen; + + if (u4QueryBufferLen < *pu4QueryInfoLen) { + return WLAN_STATUS_INVALID_LENGTH; + } + + /* Clear the buffer */ + kalMemZero(pvQueryBuffer, u4BssidListExLen); + + prList = (P_PARAM_BSSID_LIST_EX_T) pvQueryBuffer; + cp = (PUINT_8)&prList->arBssid[0]; + + if(prAdapter->fgIsRadioOff == FALSE && prAdapter->rWlanInfo.u4ScanResultNum > 0) { + // fill up for each entry + for(i = 0 ; i < prAdapter->rWlanInfo.u4ScanResultNum ; i++) { + prBssidEx = (P_PARAM_BSSID_EX_T)cp; + + // copy structure + kalMemCopy(prBssidEx, + &(prAdapter->rWlanInfo.arScanResult[i]), + OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); + + /*For WHQL test, Rssi should be in range -10 ~ -200 dBm*/ + if(prBssidEx->rRssi > PARAM_WHQL_RSSI_MAX_DBM) { + prBssidEx->rRssi = PARAM_WHQL_RSSI_MAX_DBM; + } + + if(prAdapter->rWlanInfo.arScanResult[i].u4IELength > 0) { + // copy IEs + kalMemCopy(prBssidEx->aucIEs, + prAdapter->rWlanInfo.apucScanResultIEs[i], + prAdapter->rWlanInfo.arScanResult[i].u4IELength); + } + + // 4-bytes alignement + prBssidEx->u4Length = ALIGN_4(prBssidEx->u4Length); + + cp += prBssidEx->u4Length; + prList->u4NumberOfItems++; + } + } + +#if (CFG_NVRAM_EXISTENCE_CHECK == 1) + #define NVRAM_ERR_MSG "NVRAM WARNING: Err = 0x01" + if(kalIsConfigurationExist(prAdapter->prGlueInfo) == FALSE) { + prBssidEx = (P_PARAM_BSSID_EX_T)cp; + + /* generate fake result as error message */ + i = prAdapter->rWlanInfo.u4ScanResultNum; + + // zero + kalMemZero(prBssidEx, OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); + + // then fill buffer + COPY_MAC_ADDR(prBssidEx->arMacAddress, aucZeroMacAddr); + COPY_SSID(prBssidEx->rSsid.aucSsid, + prBssidEx->rSsid.u4SsidLen, + NVRAM_ERR_MSG, + strlen(NVRAM_ERR_MSG)); + prBssidEx->u4Privacy = 0; + prBssidEx->rRssi = 0; + prBssidEx->eNetworkTypeInUse = PARAM_NETWORK_TYPE_FH; + prBssidEx->rConfiguration.u4Length = sizeof(PARAM_802_11_CONFIG_T); + prBssidEx->rConfiguration.u4BeaconPeriod = 100; + prBssidEx->rConfiguration.u4ATIMWindow = 1; + prBssidEx->rConfiguration.u4DSConfig = 2412000; + prBssidEx->rConfiguration.rFHConfig.u4Length = sizeof(PARAM_802_11_CONFIG_FH_T); + prBssidEx->eOpMode = BSS_TYPE_INFRASTRUCTURE; + prBssidEx->u4IELength = 0; + + /* move to next entry */ + prBssidEx->u4Length = OFFSET_OF(PARAM_BSSID_EX_T, aucIEs); + cp += prBssidEx->u4Length; + prList->u4NumberOfItems++; + } +#endif + +#if (CFG_SW_NVRAM_VERSION_CHECK == 1) + #define VER_ERR_MSG "NVRAM WARNING: Err = 0x%02X" + if(fgIsConfExist == TRUE) { + UINT_32 u4ErrCode = 0; + + if((CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2Part1CfgPeerVersion + || CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2Part2CfgPeerVersion + || prAdapter->rVerInfo.u2Part1CfgOwnVersion < CFG_DRV_PEER_VERSION + || prAdapter->rVerInfo.u2Part2CfgOwnVersion < CFG_DRV_PEER_VERSION /* NVRAM */ + || CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2FwPeerVersion + || prAdapter->rVerInfo.u2FwOwnVersion < CFG_DRV_PEER_VERSION)) { + u4ErrCode |= NVRAM_ERROR_VERSION_MISMATCH; + } + + + if(prRegInfo->ucTxPwrValid == 0) { + u4ErrCode |= NVRAM_ERROR_INVALID_TXPWR; + } + + if(prAdapter->fgIsEmbbededMacAddrValid == FALSE && + (IS_BMCAST_MAC_ADDR(prRegInfo->aucMacAddr) || EQUAL_MAC_ADDR(aucZeroMacAddr, prRegInfo->aucMacAddr))) { + u4ErrCode |= NVRAM_ERROR_INVALID_MAC_ADDR; + } + + if(u4ErrCode != 0) { + UINT_8 aucErrMsg[32]; + prBssidEx = (P_PARAM_BSSID_EX_T)cp; + + // zero + kalMemZero(prBssidEx, OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); + + // then fill buffer + COPY_MAC_ADDR(prBssidEx->arMacAddress, aucZeroMacAddr); + + sprintf(aucErrMsg, VER_ERR_MSG, (unsigned int)u4ErrCode); + COPY_SSID(prBssidEx->rSsid.aucSsid, + prBssidEx->rSsid.u4SsidLen, + aucErrMsg, + strlen(aucErrMsg)); + + prBssidEx->u4Privacy = 0; + prBssidEx->rRssi = 0; + prBssidEx->eNetworkTypeInUse = PARAM_NETWORK_TYPE_FH; + prBssidEx->rConfiguration.u4Length = sizeof(PARAM_802_11_CONFIG_T); + prBssidEx->rConfiguration.u4BeaconPeriod = 100; + prBssidEx->rConfiguration.u4ATIMWindow = 1; + prBssidEx->rConfiguration.u4DSConfig = 2412000; + prBssidEx->rConfiguration.rFHConfig.u4Length = sizeof(PARAM_802_11_CONFIG_FH_T); + prBssidEx->eOpMode = BSS_TYPE_INFRASTRUCTURE; + prBssidEx->u4IELength = 0; + + /* move to next entry */ + prBssidEx->u4Length = OFFSET_OF(PARAM_BSSID_EX_T, aucIEs); + cp += prBssidEx->u4Length; + prList->u4NumberOfItems++; + } + } +#endif + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryBssidList */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to request the driver to perform +* scanning. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetBssidListScan ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_PARAM_SSID_T prSsid; + PARAM_SSID_T rSsid; + + DEBUGFUNC("wlanoidSetBssidListScan()"); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in set BSSID list scan! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + ASSERT(pu4SetInfoLen); + *pu4SetInfoLen = 0; + + if (prAdapter->fgIsRadioOff) { + DBGLOG(REQ, WARN, ("Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + return WLAN_STATUS_SUCCESS; + } + + if(pvSetBuffer != NULL && u4SetBufferLen != 0) { + COPY_SSID(rSsid.aucSsid, + rSsid.u4SsidLen, + pvSetBuffer, + u4SetBufferLen); + prSsid = &rSsid; + } + else { + prSsid = NULL; + } + +#if CFG_SUPPORT_RDD_TEST_MODE + if (prAdapter->prGlueInfo->rRegInfo.u4RddTestMode) { + if((prAdapter->fgEnOnlineScan == TRUE) && (prAdapter->ucRddStatus)){ + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_CONNECTED){ + aisFsmScanRequest(prAdapter, prSsid); + } + } + } + else +#endif + { + if(prAdapter->fgEnOnlineScan == TRUE) { + aisFsmScanRequest(prAdapter, prSsid); + } + else { + if(kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_CONNECTED) { + aisFsmScanRequest(prAdapter, prSsid); + } + } + } + + return WLAN_STATUS_SUCCESS; +} /* wlanoidSetBssidListScan */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine will initiate the join procedure to attempt to associate +* with the specified BSSID. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetBssid ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_GLUE_INFO_T prGlueInfo; + P_UINT_8 pAddr; + UINT_32 i; + INT_32 i4Idx = -1; + P_MSG_AIS_ABORT_T prAisAbortMsg; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = MAC_ADDR_LEN;; + if (u4SetBufferLen != MAC_ADDR_LEN){ + *pu4SetInfoLen = MAC_ADDR_LEN; + return WLAN_STATUS_INVALID_LENGTH; + } + else if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in set ssid! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + prGlueInfo = prAdapter->prGlueInfo; + pAddr = (P_UINT_8)pvSetBuffer; + + // re-association check + if(kalGetMediaStateIndicated(prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { + if(EQUAL_MAC_ADDR(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, pAddr)) { + kalSetMediaStateIndicated(prGlueInfo, PARAM_MEDIA_STATE_TO_BE_INDICATED); + } + else { + kalIndicateStatusAndComplete(prGlueInfo, + WLAN_STATUS_MEDIA_DISCONNECT, + NULL, + 0); + } + } + + // check if any scanned result matchs with the BSSID + for(i = 0 ; i < prAdapter->rWlanInfo.u4ScanResultNum ; i++) { + if(EQUAL_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, pAddr)) { + i4Idx = (INT_32)i; + break; + } + } + + /* prepare message to AIS */ + if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_IBSS + || prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_DEDICATED_IBSS) { + /* IBSS */ /* beacon period */ + prAdapter->rWifiVar.rConnSettings.u2BeaconPeriod = prAdapter->rWlanInfo.u2BeaconPeriod; + prAdapter->rWifiVar.rConnSettings.u2AtimWindow = prAdapter->rWlanInfo.u2AtimWindow; + } + + /* Set Connection Request Issued Flag */ + prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = TRUE; + prAdapter->rWifiVar.rConnSettings.eConnectionPolicy = CONNECT_BY_BSSID; + + /* Send AIS Abort Message */ + prAisAbortMsg = (P_MSG_AIS_ABORT_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); + if (!prAisAbortMsg) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + + prAisAbortMsg->rMsgHdr.eMsgId = MID_OID_AIS_FSM_JOIN_REQ; + prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; + + if (EQUAL_MAC_ADDR(prAdapter->rWifiVar.rConnSettings.aucBSSID, pAddr)) { + prAisAbortMsg->fgDelayIndication = TRUE; + } + else { + /* Update the information to CONNECTION_SETTINGS_T */ + prAdapter->rWifiVar.rConnSettings.ucSSIDLen = 0; + prAdapter->rWifiVar.rConnSettings.aucSSID[0] = '\0'; + + COPY_MAC_ADDR(prAdapter->rWifiVar.rConnSettings.aucBSSID, pAddr); + prAisAbortMsg->fgDelayIndication = FALSE; + } + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prAisAbortMsg, + MSG_SEND_METHOD_BUF); + + return WLAN_STATUS_SUCCESS; +} /* end of wlanoidSetBssid() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine will initiate the join procedure to attempt +* to associate with the new SSID. If the previous scanning +* result is aged, we will scan the channels at first. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetSsid ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_GLUE_INFO_T prGlueInfo; + P_PARAM_SSID_T pParamSsid; + UINT_32 i; + INT_32 i4Idx = -1, i4MaxRSSI = INT_MIN; + P_MSG_AIS_ABORT_T prAisAbortMsg; + BOOLEAN fgIsValidSsid = TRUE; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + /* MSDN: + * Powering on the radio if the radio is powered off through a setting of OID_802_11_DISASSOCIATE + */ + if(prAdapter->fgIsRadioOff == TRUE) { + prAdapter->fgIsRadioOff = FALSE; + } + + if(u4SetBufferLen < sizeof(PARAM_SSID_T) || u4SetBufferLen > sizeof(PARAM_SSID_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + else if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in set ssid! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + pParamSsid = (P_PARAM_SSID_T) pvSetBuffer; + + if (pParamSsid->u4SsidLen > 32) { + return WLAN_STATUS_INVALID_LENGTH; + } + + prGlueInfo = prAdapter->prGlueInfo; + + // prepare for CMD_BUILD_CONNECTION & CMD_GET_CONNECTION_STATUS + // re-association check + if(kalGetMediaStateIndicated(prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { + if(EQUAL_SSID(prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, + prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen, + pParamSsid->aucSsid, + pParamSsid->u4SsidLen)) { + kalSetMediaStateIndicated(prGlueInfo, PARAM_MEDIA_STATE_TO_BE_INDICATED); + } + else { + kalIndicateStatusAndComplete(prGlueInfo, + WLAN_STATUS_MEDIA_DISCONNECT, + NULL, + 0); + } + } + + // check if any scanned result matchs with the SSID + for(i = 0 ; i < prAdapter->rWlanInfo.u4ScanResultNum ; i++) { + PUINT_8 aucSsid = prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid; + UINT_8 ucSsidLength = (UINT_8) prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen; + INT_32 i4RSSI = prAdapter->rWlanInfo.arScanResult[i].rRssi; + + if(EQUAL_SSID(aucSsid, ucSsidLength, pParamSsid->aucSsid, pParamSsid->u4SsidLen) && + i4RSSI >= i4MaxRSSI) { + i4Idx = (INT_32)i; + i4MaxRSSI = i4RSSI; + } + } + + /* prepare message to AIS */ + if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_IBSS + || prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_DEDICATED_IBSS) { + /* IBSS */ /* beacon period */ + prAdapter->rWifiVar.rConnSettings.u2BeaconPeriod = prAdapter->rWlanInfo.u2BeaconPeriod; + prAdapter->rWifiVar.rConnSettings.u2AtimWindow = prAdapter->rWlanInfo.u2AtimWindow; + } + + if (prAdapter->rWifiVar.fgSupportWZCDisassociation) { + if (pParamSsid->u4SsidLen == ELEM_MAX_LEN_SSID) { + fgIsValidSsid = FALSE; + + for (i = 0; i < ELEM_MAX_LEN_SSID; i++) { + if ( !((0 < pParamSsid->aucSsid[i]) && (pParamSsid->aucSsid[i] <= 0x1F)) ) { + fgIsValidSsid = TRUE; + break; + } + } + } + } + + /* Set Connection Request Issued Flag */ + if (fgIsValidSsid) { + prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = TRUE; + + if(pParamSsid->u4SsidLen) { + prAdapter->rWifiVar.rConnSettings.eConnectionPolicy = CONNECT_BY_SSID_BEST_RSSI; + } + else { + // wildcard SSID + prAdapter->rWifiVar.rConnSettings.eConnectionPolicy = CONNECT_BY_SSID_ANY; + } + } + else { + prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = FALSE; + } + + /* Send AIS Abort Message */ + prAisAbortMsg = (P_MSG_AIS_ABORT_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); + if (!prAisAbortMsg) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + + prAisAbortMsg->rMsgHdr.eMsgId = MID_OID_AIS_FSM_JOIN_REQ; + prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; + + if (EQUAL_SSID(prAdapter->rWifiVar.rConnSettings.aucSSID, + prAdapter->rWifiVar.rConnSettings.ucSSIDLen, + pParamSsid->aucSsid, + pParamSsid->u4SsidLen)) { + prAisAbortMsg->fgDelayIndication = TRUE; + } + else { + /* Update the information to CONNECTION_SETTINGS_T */ + COPY_SSID(prAdapter->rWifiVar.rConnSettings.aucSSID, + prAdapter->rWifiVar.rConnSettings.ucSSIDLen, + pParamSsid->aucSsid, + (UINT_8)pParamSsid->u4SsidLen); + + prAisAbortMsg->fgDelayIndication = FALSE; + } + DBGLOG(SCN, INFO, ("SSID %s\n", prAdapter->rWifiVar.rConnSettings.aucSSID)); + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prAisAbortMsg, + MSG_SEND_METHOD_BUF); + + return WLAN_STATUS_SUCCESS; + +} /* end of wlanoidSetSsid() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the currently associated SSID. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQuerySsid ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + P_PARAM_SSID_T prAssociatedSsid; + + DEBUGFUNC("wlanoidQuerySsid"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(PARAM_SSID_T); + + /* Check for query buffer length */ + if (u4QueryBufferLen < *pu4QueryInfoLen) { + DBGLOG(REQ, WARN, ("Invalid length %lu\n", u4QueryBufferLen)); + return WLAN_STATUS_INVALID_LENGTH; + } + + prAssociatedSsid = (P_PARAM_SSID_T)pvQueryBuffer; + + kalMemZero(prAssociatedSsid->aucSsid, sizeof(prAssociatedSsid->aucSsid)); + + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { + prAssociatedSsid->u4SsidLen = prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen; + + if (prAssociatedSsid->u4SsidLen) { + kalMemCopy(prAssociatedSsid->aucSsid, + prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, + prAssociatedSsid->u4SsidLen); + } + } + else { + prAssociatedSsid->u4SsidLen = 0; + + DBGLOG(REQ, TRACE, ("Null SSID\n")); + } + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQuerySsid */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the current 802.11 network type. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryInfrastructureMode ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryInfrastructureMode"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(ENUM_PARAM_OP_MODE_T); + + if (u4QueryBufferLen < sizeof(ENUM_PARAM_OP_MODE_T)) { + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *(P_ENUM_PARAM_OP_MODE_T)pvQueryBuffer = prAdapter->rWifiVar.rConnSettings.eOPMode; + + /* + ** According to OID_802_11_INFRASTRUCTURE_MODE + ** If there is no prior OID_802_11_INFRASTRUCTURE_MODE, + ** NDIS_STATUS_ADAPTER_NOT_READY shall be returned. + */ +#if DBG + switch (*(P_ENUM_PARAM_OP_MODE_T)pvQueryBuffer) { + case NET_TYPE_IBSS: + DBGLOG(REQ, INFO, ("IBSS mode\n")); + break; + case NET_TYPE_INFRA: + DBGLOG(REQ, INFO, ("Infrastructure mode\n")); + break; + default: + DBGLOG(REQ, INFO, ("Automatic mode\n")); + } +#endif + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryInfrastructureMode */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set mode to infrastructure or +* IBSS, or automatic switch between the two. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid +* length of the set buffer, returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetInfrastructureMode ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_GLUE_INFO_T prGlueInfo; + ENUM_PARAM_OP_MODE_T eOpMode; + + DEBUGFUNC("wlanoidSetInfrastructureMode"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + prGlueInfo = prAdapter->prGlueInfo; + + if (u4SetBufferLen < sizeof(ENUM_PARAM_OP_MODE_T)) + return WLAN_STATUS_BUFFER_TOO_SHORT; + + *pu4SetInfoLen = sizeof(ENUM_PARAM_OP_MODE_T); + + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in set infrastructure mode! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + eOpMode = *(P_ENUM_PARAM_OP_MODE_T)pvSetBuffer; + /* Verify the new infrastructure mode. */ + if (eOpMode >= NET_TYPE_NUM) { + DBGLOG(REQ, TRACE, ("Invalid mode value %d\n", eOpMode)); + return WLAN_STATUS_INVALID_DATA; + } + + /* check if possible to switch to AdHoc mode */ + if(eOpMode == NET_TYPE_IBSS || eOpMode == NET_TYPE_DEDICATED_IBSS) { + if(cnmAisIbssIsPermitted(prAdapter) == FALSE) { + DBGLOG(REQ, TRACE, ("Mode value %d unallowed\n", eOpMode)); + return WLAN_STATUS_FAILURE; + } + } + + /* Save the new infrastructure mode setting. */ + prAdapter->rWifiVar.rConnSettings.eOPMode = eOpMode; + + /* Clean up the Tx key flag */ + prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist = FALSE; + + prAdapter->rWifiVar.rConnSettings.fgWapiMode = FALSE; +#if CFG_SUPPORT_WAPI + prAdapter->prGlueInfo->u2WapiAssocInfoIESz = 0; + kalMemZero(&prAdapter->prGlueInfo->aucWapiAssocInfoIEs, 42); +#endif + +#if CFG_SUPPORT_802_11W + prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = FALSE; + prAdapter->rWifiVar.rAisSpecificBssInfo.fgBipKeyInstalled = FALSE; +#endif + +#if CFG_SUPPORT_WPS2 + kalMemZero(&prAdapter->prGlueInfo->aucWSCAssocInfoIE, 200); + prAdapter->prGlueInfo->u2WSCAssocInfoIELen = 0; +#endif + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_INFRASTRUCTURE, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + 0, + NULL, + pvSetBuffer, + u4SetBufferLen + ); + +} /* wlanoidSetInfrastructureMode */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the current 802.11 authentication +* mode. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryAuthMode ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryAuthMode"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(ENUM_PARAM_AUTH_MODE_T); + + if (u4QueryBufferLen < sizeof(ENUM_PARAM_AUTH_MODE_T)) { + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + *(P_ENUM_PARAM_AUTH_MODE_T)pvQueryBuffer = prAdapter->rWifiVar.rConnSettings.eAuthMode; + +#if DBG + switch (*(P_ENUM_PARAM_AUTH_MODE_T)pvQueryBuffer) { + case AUTH_MODE_OPEN: + DBGLOG(REQ, INFO, ("Current auth mode: Open\n")); + break; + + case AUTH_MODE_SHARED: + DBGLOG(REQ, INFO, ("Current auth mode: Shared\n")); + break; + + case AUTH_MODE_AUTO_SWITCH: + DBGLOG(REQ, INFO, ("Current auth mode: Auto-switch\n")); + break; + + case AUTH_MODE_WPA: + DBGLOG(REQ, INFO, ("Current auth mode: WPA\n")); + break; + + case AUTH_MODE_WPA_PSK: + DBGLOG(REQ, INFO, ("Current auth mode: WPA PSK\n")); + break; + + case AUTH_MODE_WPA_NONE: + DBGLOG(REQ, INFO, ("Current auth mode: WPA None\n")); + break; + + case AUTH_MODE_WPA2: + DBGLOG(REQ, INFO, ("Current auth mode: WPA2\n")); + break; + + case AUTH_MODE_WPA2_PSK: + DBGLOG(REQ, INFO, ("Current auth mode: WPA2 PSK\n")); + break; + + default: + DBGLOG(REQ, INFO, ("Current auth mode: %d\n", + *(P_ENUM_PARAM_AUTH_MODE_T)pvQueryBuffer)); + } +#endif + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryAuthMode */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set the IEEE 802.11 authentication mode +* to the driver. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_NOT_ACCEPTED +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetAuthMode ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_GLUE_INFO_T prGlueInfo; + UINT_32 i, u4AkmSuite; + P_DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY prEntry; + + DEBUGFUNC("wlanoidSetAuthMode"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + ASSERT(pvSetBuffer); + + prGlueInfo = prAdapter->prGlueInfo; + + *pu4SetInfoLen = sizeof(ENUM_PARAM_AUTH_MODE_T); + + if (u4SetBufferLen < sizeof(ENUM_PARAM_AUTH_MODE_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + /* RF Test */ + //if (IS_ARB_IN_RFTEST_STATE(prAdapter)) { + // return WLAN_STATUS_SUCCESS; + //} + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in set Authentication mode! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + /* Check if the new authentication mode is valid. */ + if (*(P_ENUM_PARAM_AUTH_MODE_T)pvSetBuffer >= AUTH_MODE_NUM) { + DBGLOG(REQ, TRACE, ("Invalid auth mode %d\n", + *(P_ENUM_PARAM_AUTH_MODE_T)pvSetBuffer)); + return WLAN_STATUS_INVALID_DATA; + } + + switch (*(P_ENUM_PARAM_AUTH_MODE_T)pvSetBuffer) { + case AUTH_MODE_WPA: + case AUTH_MODE_WPA_PSK: + case AUTH_MODE_WPA2: + case AUTH_MODE_WPA2_PSK: + /* infrastructure mode only */ + if (prAdapter->rWifiVar.rConnSettings.eOPMode != NET_TYPE_INFRA) { + return WLAN_STATUS_NOT_ACCEPTED; + } + break; + + case AUTH_MODE_WPA_NONE: + /* ad hoc mode only */ + if (prAdapter->rWifiVar.rConnSettings.eOPMode != NET_TYPE_IBSS) { + return WLAN_STATUS_NOT_ACCEPTED; + } + break; + + default: + ; + } + + /* Save the new authentication mode. */ + prAdapter->rWifiVar.rConnSettings.eAuthMode = *(P_ENUM_PARAM_AUTH_MODE_T)pvSetBuffer; + +#if DBG + switch (prAdapter->rWifiVar.rConnSettings.eAuthMode) { + case AUTH_MODE_OPEN: + DBGLOG(RSN, TRACE, ("New auth mode: open\n")); + break; + + case AUTH_MODE_SHARED: + DBGLOG(RSN, TRACE, ("New auth mode: shared\n")); + break; + + case AUTH_MODE_AUTO_SWITCH: + DBGLOG(RSN, TRACE, ("New auth mode: auto-switch\n")); + break; + + case AUTH_MODE_WPA: + DBGLOG(RSN, TRACE, ("New auth mode: WPA\n")); + break; + + case AUTH_MODE_WPA_PSK: + DBGLOG(RSN, TRACE, ("New auth mode: WPA PSK\n")); + break; + + case AUTH_MODE_WPA_NONE: + DBGLOG(RSN, TRACE, ("New auth mode: WPA None\n")); + break; + + case AUTH_MODE_WPA2: + DBGLOG(RSN, TRACE, ("New auth mode: WPA2\n")); + break; + + case AUTH_MODE_WPA2_PSK: + DBGLOG(RSN, TRACE, ("New auth mode: WPA2 PSK\n")); + break; + + default: + DBGLOG(RSN, TRACE, ("New auth mode: unknown (%d)\n", + prAdapter->rWifiVar.rConnSettings.eAuthMode)); + } +#endif + + if (prAdapter->rWifiVar.rConnSettings.eAuthMode >= AUTH_MODE_WPA) { + switch(prAdapter->rWifiVar.rConnSettings.eAuthMode) { + case AUTH_MODE_WPA: + u4AkmSuite = WPA_AKM_SUITE_802_1X; + break; + + case AUTH_MODE_WPA_PSK: + u4AkmSuite = WPA_AKM_SUITE_PSK; + break; + + case AUTH_MODE_WPA_NONE: + u4AkmSuite = WPA_AKM_SUITE_NONE; + break; + + case AUTH_MODE_WPA2: + u4AkmSuite = RSN_AKM_SUITE_802_1X; + break; + + case AUTH_MODE_WPA2_PSK: + u4AkmSuite = RSN_AKM_SUITE_PSK; + break; + + default: + u4AkmSuite = 0; + } + } + else { + u4AkmSuite = 0; + } + + /* Enable the specific AKM suite only. */ + for (i = 0; i < MAX_NUM_SUPPORTED_AKM_SUITES; i++) { + prEntry = &prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[i]; + + if (prEntry->dot11RSNAConfigAuthenticationSuite == u4AkmSuite) { + prEntry->dot11RSNAConfigAuthenticationSuiteEnabled = TRUE; + } + else { + prEntry->dot11RSNAConfigAuthenticationSuiteEnabled = FALSE; + } +#if CFG_SUPPORT_802_11W + if (kalGetMfpSetting(prAdapter->prGlueInfo) != RSN_AUTH_MFP_DISABLED) { + if ((u4AkmSuite == RSN_AKM_SUITE_PSK) && + prEntry->dot11RSNAConfigAuthenticationSuite == RSN_AKM_SUITE_PSK_SHA256) { + DBGLOG(RSN, TRACE, ("Enable RSN_AKM_SUITE_PSK_SHA256 AKM support\n")); + prEntry->dot11RSNAConfigAuthenticationSuiteEnabled = TRUE; + + } + if ((u4AkmSuite == RSN_AKM_SUITE_802_1X) && + prEntry->dot11RSNAConfigAuthenticationSuite == RSN_AKM_SUITE_802_1X_SHA256) { + DBGLOG(RSN, TRACE, ("Enable RSN_AKM_SUITE_802_1X_SHA256 AKM support\n")); + prEntry->dot11RSNAConfigAuthenticationSuiteEnabled = TRUE; + } + } +#endif + } + + + return WLAN_STATUS_SUCCESS; + +} /* wlanoidSetAuthMode */ + + +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the current 802.11 privacy filter +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryPrivacyFilter ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryPrivacyFilter"); + + ASSERT(prAdapter); + + ASSERT(pvQueryBuffer); + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(ENUM_PARAM_PRIVACY_FILTER_T); + + if (u4QueryBufferLen < sizeof(ENUM_PARAM_PRIVACY_FILTER_T)) { + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + *(P_ENUM_PARAM_PRIVACY_FILTER_T)pvQueryBuffer = prAdapter->rWlanInfo.ePrivacyFilter; + +#if DBG + switch (*(P_ENUM_PARAM_PRIVACY_FILTER_T)pvQueryBuffer) { + case PRIVACY_FILTER_ACCEPT_ALL: + DBGLOG(REQ, INFO, ("Current privacy mode: open mode\n")); + break; + + case PRIVACY_FILTER_8021xWEP: + DBGLOG(REQ, INFO, ("Current privacy mode: filtering mode\n")); + break; + + default: + DBGLOG(REQ, INFO, ("Current auth mode: %d\n", + *(P_ENUM_PARAM_AUTH_MODE_T)pvQueryBuffer)); + } +#endif + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryPrivacyFilter */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set the IEEE 802.11 privacy filter +* to the driver. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_NOT_ACCEPTED +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetPrivacyFilter ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_GLUE_INFO_T prGlueInfo; + + DEBUGFUNC("wlanoidSetPrivacyFilter"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + ASSERT(pvSetBuffer); + + prGlueInfo = prAdapter->prGlueInfo; + + *pu4SetInfoLen = sizeof(ENUM_PARAM_PRIVACY_FILTER_T); + + if (u4SetBufferLen < sizeof(ENUM_PARAM_PRIVACY_FILTER_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in set Authentication mode! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + /* Check if the new authentication mode is valid. */ + if (*(P_ENUM_PARAM_PRIVACY_FILTER_T)pvSetBuffer >= PRIVACY_FILTER_NUM) { + DBGLOG(REQ, TRACE, ("Invalid privacy filter %d\n", + *(P_ENUM_PARAM_PRIVACY_FILTER_T)pvSetBuffer)); + return WLAN_STATUS_INVALID_DATA; + } + + switch (*(P_ENUM_PARAM_PRIVACY_FILTER_T)pvSetBuffer) { + default: + break; + } + + /* Save the new authentication mode. */ + prAdapter->rWlanInfo.ePrivacyFilter = *(ENUM_PARAM_PRIVACY_FILTER_T)pvSetBuffer; + + return WLAN_STATUS_SUCCESS; + +} /* wlanoidSetPrivacyFilter */ +#endif + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to reload the available default settings for +* the specified type field. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_INVALID_DATA +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetReloadDefaults ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + ENUM_PARAM_NETWORK_TYPE_T eNetworkType; + UINT_32 u4Len; + UINT_8 ucCmdSeqNum; + + + DEBUGFUNC("wlanoidSetReloadDefaults"); + + ASSERT(prAdapter); + + ASSERT(pu4SetInfoLen); + *pu4SetInfoLen = sizeof(PARAM_RELOAD_DEFAULTS); + + //if (IS_ARB_IN_RFTEST_STATE(prAdapter)) { + // return WLAN_STATUS_SUCCESS; + //} + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in set Reload default! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + ASSERT(pvSetBuffer); + /* Verify the available reload options and reload the settings. */ + switch (*(P_PARAM_RELOAD_DEFAULTS)pvSetBuffer) { + case ENUM_RELOAD_WEP_KEYS: + /* Reload available default WEP keys from the permanent + storage. */ + prAdapter->rWifiVar.rConnSettings.eAuthMode = AUTH_MODE_OPEN; + prAdapter->rWifiVar.rConnSettings.eEncStatus = ENUM_ENCRYPTION1_KEY_ABSENT;//ENUM_ENCRYPTION_DISABLED; + { + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + P_CMD_802_11_KEY prCmdKey; + UINT_8 aucBCAddr[] = BC_MAC_ADDR; + + prGlueInfo = prAdapter->prGlueInfo; + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_802_11_KEY))); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, ("Allocate CMD_INFO_T ==> FAILED.\n")); + return WLAN_STATUS_FAILURE; + } + // increase command sequence number + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + // compose CMD_802_11_KEY cmd pkt + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->eNetworkType = NETWORK_TYPE_AIS_INDEX; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_802_11_KEY); + prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; + prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; + prCmdInfo->fgIsOid = TRUE; + prCmdInfo->ucCID = CMD_ID_ADD_REMOVE_KEY; + prCmdInfo->fgSetQuery = TRUE; + prCmdInfo->fgNeedResp = FALSE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = sizeof(PARAM_REMOVE_KEY_T); + prCmdInfo->pvInformationBuffer = pvSetBuffer; + prCmdInfo->u4InformationBufferLength = u4SetBufferLen; + + // Setup WIFI_CMD_T + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + prCmdKey = (P_CMD_802_11_KEY)(prWifiCmd->aucBuffer); + + kalMemZero((PUINT_8)prCmdKey, sizeof(CMD_802_11_KEY)); + + prCmdKey->ucAddRemove = 0; /* Remove */ + prCmdKey->ucKeyId = 0;//(UINT_8)(prRemovedKey->u4KeyIndex & 0x000000ff); + kalMemCopy(prCmdKey->aucPeerAddr, aucBCAddr, MAC_ADDR_LEN); + + ASSERT(prCmdKey->ucKeyId < MAX_KEY_NUM); + + prCmdKey->ucKeyType = 0; + + // insert into prCmdQueue + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + + // wakeup txServiceThread later + GLUE_SET_EVENT(prGlueInfo); + + return WLAN_STATUS_PENDING; + } + + break; + + default: + DBGLOG(REQ, TRACE, ("Invalid reload option %d\n", + *(P_PARAM_RELOAD_DEFAULTS)pvSetBuffer)); + rStatus = WLAN_STATUS_INVALID_DATA; + } + + /* OID_802_11_RELOAD_DEFAULTS requiest to reset to auto mode */ + eNetworkType = PARAM_NETWORK_TYPE_AUTOMODE; + wlanoidSetNetworkTypeInUse(prAdapter, &eNetworkType, sizeof(eNetworkType), &u4Len); + + return rStatus; +} /* wlanoidSetReloadDefaults */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set a WEP key to the driver. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +#ifdef LINUX +UINT_8 keyBuffer[sizeof(PARAM_KEY_T) + 16 /* LEGACY_KEY_MAX_LEN*/]; +UINT_8 aucBCAddr[] = BC_MAC_ADDR; +#endif +WLAN_STATUS +wlanoidSetAddWep ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + #ifndef LINUX + UINT_8 keyBuffer[sizeof(PARAM_KEY_T) + 16 /* LEGACY_KEY_MAX_LEN*/]; + UINT_8 aucBCAddr[] = BC_MAC_ADDR; + #endif + P_PARAM_WEP_T prNewWepKey; + P_PARAM_KEY_T prParamKey = (P_PARAM_KEY_T)keyBuffer; + UINT_32 u4KeyId, u4SetLen; + + DEBUGFUNC("wlanoidSetAddWep"); + + ASSERT(prAdapter); + + *pu4SetInfoLen = OFFSET_OF(PARAM_WEP_T, aucKeyMaterial); + + if (u4SetBufferLen < OFFSET_OF(PARAM_WEP_T, aucKeyMaterial)) { + ASSERT(pu4SetInfoLen); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in set add WEP! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + prNewWepKey = (P_PARAM_WEP_T)pvSetBuffer; + + /* Verify the total buffer for minimum length. */ + if (u4SetBufferLen < OFFSET_OF(PARAM_WEP_T, aucKeyMaterial) + prNewWepKey->u4KeyLength) { + DBGLOG(REQ, WARN, ("Invalid total buffer length (%d) than minimum length (%d)\n", + (UINT_8)u4SetBufferLen, + (UINT_8)OFFSET_OF(PARAM_WEP_T, aucKeyMaterial))); + + *pu4SetInfoLen = OFFSET_OF(PARAM_WEP_T, aucKeyMaterial); + return WLAN_STATUS_INVALID_DATA; + } + + /* Verify the key structure length. */ + if (prNewWepKey->u4Length > u4SetBufferLen) { + DBGLOG(REQ, WARN, ("Invalid key structure length (%d) greater than total buffer length (%d)\n", + (UINT_8)prNewWepKey->u4Length, + (UINT_8)u4SetBufferLen)); + + *pu4SetInfoLen = u4SetBufferLen; + return WLAN_STATUS_INVALID_DATA; + } + + /* Verify the key material length for maximum key material length:16 */ + if (prNewWepKey->u4KeyLength > 16 /* LEGACY_KEY_MAX_LEN */) { + DBGLOG(REQ, WARN, ("Invalid key material length (%d) greater than maximum key material length (16)\n", + (UINT_8)prNewWepKey->u4KeyLength)); + + *pu4SetInfoLen = u4SetBufferLen; + return WLAN_STATUS_INVALID_DATA; + } + + *pu4SetInfoLen = u4SetBufferLen; + + u4KeyId = prNewWepKey->u4KeyIndex & BITS(0,29) /* WEP_KEY_ID_FIELD */; + + /* Verify whether key index is valid or not, current version + driver support only 4 global WEP keys setting by this OID */ + if (u4KeyId > MAX_KEY_NUM - 1) { + DBGLOG(REQ, ERROR, ("Error, invalid WEP key ID: %d\n", (UINT_8)u4KeyId)); + return WLAN_STATUS_INVALID_DATA; + } + + prParamKey->u4KeyIndex = u4KeyId; + + /* Transmit key */ + if (prNewWepKey->u4KeyIndex & IS_TRANSMIT_KEY) { + prParamKey->u4KeyIndex |= IS_TRANSMIT_KEY; + } + + /* Per client key */ + if (prNewWepKey->u4KeyIndex & IS_UNICAST_KEY) { + prParamKey->u4KeyIndex |= IS_UNICAST_KEY; + } + + prParamKey->u4KeyLength = prNewWepKey->u4KeyLength; + + kalMemCopy(prParamKey->arBSSID, aucBCAddr, MAC_ADDR_LEN); + + kalMemCopy(prParamKey->aucKeyMaterial, + prNewWepKey->aucKeyMaterial, + prNewWepKey->u4KeyLength); + + prParamKey->u4Length = OFFSET_OF(PARAM_KEY_T, aucKeyMaterial) + prNewWepKey->u4KeyLength; + + wlanoidSetAddKey(prAdapter, + (PVOID)prParamKey, + prParamKey->u4Length, + &u4SetLen); + + return WLAN_STATUS_PENDING; +} /* wlanoidSetAddWep */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to request the driver to remove the WEP key +* at the specified key index. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetRemoveWep ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + UINT_32 u4KeyId, u4SetLen; + PARAM_REMOVE_KEY_T rRemoveKey; + UINT_8 aucBCAddr[] = BC_MAC_ADDR; + + DEBUGFUNC("wlanoidSetRemoveWep"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_KEY_INDEX); + + if (u4SetBufferLen < sizeof(PARAM_KEY_INDEX)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + u4KeyId = *(PUINT_32)pvSetBuffer; + + /* Dump PARAM_WEP content. */ + DBGLOG(REQ, INFO, ("Set: Dump PARAM_KEY_INDEX content\n")); + DBGLOG(REQ, INFO, ("Index : 0x%08lx\n", u4KeyId)); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in set remove WEP! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + if (u4KeyId & IS_TRANSMIT_KEY) { + /* Bit 31 should not be set */ + DBGLOG(REQ, ERROR, ("Invalid WEP key index: 0x%08lx\n", u4KeyId)); + return WLAN_STATUS_INVALID_DATA; + } + + u4KeyId &= BITS(0,7); + + /* Verify whether key index is valid or not. Current version + driver support only 4 global WEP keys. */ + if (u4KeyId > MAX_KEY_NUM - 1) { + DBGLOG(REQ, ERROR, ("invalid WEP key ID %lu\n", u4KeyId)); + return WLAN_STATUS_INVALID_DATA; + } + + rRemoveKey.u4Length = sizeof(PARAM_REMOVE_KEY_T); + rRemoveKey.u4KeyIndex = *(PUINT_32)pvSetBuffer; + + kalMemCopy(rRemoveKey.arBSSID, aucBCAddr, MAC_ADDR_LEN); + + wlanoidSetRemoveKey(prAdapter, + (PVOID)&rRemoveKey, + sizeof(PARAM_REMOVE_KEY_T), + &u4SetLen); + + return WLAN_STATUS_PENDING; +} /* wlanoidSetRemoveWep */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set a key to the driver. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +* +* \note The setting buffer PARAM_KEY_T, which is set by NDIS, is unpacked. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetAddKey ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + P_PARAM_KEY_T prNewKey; + P_CMD_802_11_KEY prCmdKey; + UINT_8 ucCmdSeqNum; + + DEBUGFUNC("wlanoidSetAddKey"); + DBGLOG(REQ, LOUD, ("\n")); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in set add key! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + prNewKey = (P_PARAM_KEY_T) pvSetBuffer; + + /* Verify the key structure length. */ + if (prNewKey->u4Length > u4SetBufferLen) { + DBGLOG(REQ, WARN, ("Invalid key structure length (%d) greater than total buffer length (%d)\n", + (UINT_8)prNewKey->u4Length, + (UINT_8)u4SetBufferLen)); + + *pu4SetInfoLen = u4SetBufferLen; + return WLAN_STATUS_INVALID_LENGTH; + } + + /* Verify the key material length for key material buffer */ + if (prNewKey->u4KeyLength > prNewKey->u4Length - OFFSET_OF(PARAM_KEY_T, aucKeyMaterial)) { + DBGLOG(REQ, WARN, ("Invalid key material length (%d)\n", (UINT_8)prNewKey->u4KeyLength)); + *pu4SetInfoLen = u4SetBufferLen; + return WLAN_STATUS_INVALID_DATA; + } + + /* Exception check */ + if (prNewKey->u4KeyIndex & 0x0fffff00) { + return WLAN_STATUS_INVALID_DATA; + } + + /* Exception check, pairwise key must with transmit bit enabled */ + if ((prNewKey->u4KeyIndex & BITS(30,31)) == IS_UNICAST_KEY) { + return WLAN_STATUS_INVALID_DATA; + } + + if (!(prNewKey->u4KeyLength == WEP_40_LEN || prNewKey->u4KeyLength == WEP_104_LEN || + prNewKey->u4KeyLength == CCMP_KEY_LEN || prNewKey->u4KeyLength == TKIP_KEY_LEN)) + { + return WLAN_STATUS_INVALID_DATA; + } + + /* Exception check, pairwise key must with transmit bit enabled */ + if ((prNewKey->u4KeyIndex & BITS(30,31)) == BITS(30,31)) { + if (((prNewKey->u4KeyIndex & 0xff) != 0) || + ((prNewKey->arBSSID[0] == 0xff) && (prNewKey->arBSSID[1] == 0xff) && (prNewKey->arBSSID[2] == 0xff) && + (prNewKey->arBSSID[3] == 0xff) && (prNewKey->arBSSID[4] == 0xff) && (prNewKey->arBSSID[5] == 0xff))) { + return WLAN_STATUS_INVALID_DATA; + } + } + + *pu4SetInfoLen = u4SetBufferLen; + + /* Dump PARAM_KEY content. */ + DBGLOG(REQ, TRACE, ("Set: Dump PARAM_KEY content\n")); + DBGLOG(REQ, TRACE, ("Length : 0x%08lx\n", prNewKey->u4Length)); + DBGLOG(REQ, TRACE, ("Key Index : 0x%08lx\n", prNewKey->u4KeyIndex)); + DBGLOG(REQ, TRACE, ("Key Length: 0x%08lx\n", prNewKey->u4KeyLength)); + DBGLOG(REQ, TRACE, ("BSSID:\n")); + DBGLOG_MEM8(REQ, TRACE, prNewKey->arBSSID, sizeof(PARAM_MAC_ADDRESS)); + DBGLOG(REQ, TRACE, ("Key RSC:\n")); + DBGLOG_MEM8(REQ, TRACE, &prNewKey->rKeyRSC, sizeof(PARAM_KEY_RSC)); + DBGLOG(REQ, TRACE, ("Key Material:\n")); + DBGLOG_MEM8(REQ, TRACE, prNewKey->aucKeyMaterial, prNewKey->u4KeyLength); + + if (prAdapter->rWifiVar.rConnSettings.eAuthMode < AUTH_MODE_WPA) { + /* Todo:: Store the legacy wep key for OID_802_11_RELOAD_DEFAULTS */ + } + + if (prNewKey->u4KeyIndex & IS_TRANSMIT_KEY) + prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist = TRUE; + + prGlueInfo = prAdapter->prGlueInfo; + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_802_11_KEY))); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, ("Allocate CMD_INFO_T ==> FAILED.\n")); + return WLAN_STATUS_FAILURE; + } + + // increase command sequence number + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + DBGLOG(REQ, INFO, ("ucCmdSeqNum = %d\n", ucCmdSeqNum)); + + // compose CMD_802_11_KEY cmd pkt + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->eNetworkType = NETWORK_TYPE_AIS_INDEX; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_802_11_KEY); + prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; + prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; + prCmdInfo->fgIsOid = TRUE; + prCmdInfo->ucCID = CMD_ID_ADD_REMOVE_KEY; + prCmdInfo->fgSetQuery = TRUE; + prCmdInfo->fgNeedResp = FALSE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = u4SetBufferLen; + prCmdInfo->pvInformationBuffer = pvSetBuffer; + prCmdInfo->u4InformationBufferLength = u4SetBufferLen; + + // Setup WIFI_CMD_T + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + prCmdKey = (P_CMD_802_11_KEY)(prWifiCmd->aucBuffer); + + kalMemZero(prCmdKey, sizeof(CMD_802_11_KEY)); + + prCmdKey->ucAddRemove = 1; /* Add */ + + prCmdKey->ucTxKey = ((prNewKey->u4KeyIndex & IS_TRANSMIT_KEY) == IS_TRANSMIT_KEY) ? 1 : 0; + prCmdKey->ucKeyType = ((prNewKey->u4KeyIndex & IS_UNICAST_KEY) == IS_UNICAST_KEY) ? 1 : 0; + prCmdKey->ucIsAuthenticator = ((prNewKey->u4KeyIndex & IS_AUTHENTICATOR) == IS_AUTHENTICATOR) ? 1 : 0; + + kalMemCopy(prCmdKey->aucPeerAddr, (PUINT_8)prNewKey->arBSSID, MAC_ADDR_LEN); + + prCmdKey->ucNetType = 0; /* AIS */ + + prCmdKey->ucKeyId = (UINT_8)(prNewKey->u4KeyIndex & 0xff); + + /* Note: adjust the key length for WPA-None */ + prCmdKey->ucKeyLen = (UINT_8)prNewKey->u4KeyLength; + + kalMemCopy(prCmdKey->aucKeyMaterial, (PUINT_8)prNewKey->aucKeyMaterial, prCmdKey->ucKeyLen); + + if (prNewKey->u4KeyLength == 5) { + prCmdKey->ucAlgorithmId = CIPHER_SUITE_WEP40; + } + else if (prNewKey->u4KeyLength == 13) { + prCmdKey->ucAlgorithmId = CIPHER_SUITE_WEP104; + } + else if (prNewKey->u4KeyLength == 16) { + if (prAdapter->rWifiVar.rConnSettings.eAuthMode < AUTH_MODE_WPA) + prCmdKey->ucAlgorithmId = CIPHER_SUITE_WEP128; + else { +#if CFG_SUPPORT_802_11W + if (prCmdKey->ucKeyId >= 4) { + prCmdKey->ucAlgorithmId = CIPHER_SUITE_BIP; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + prAisSpecBssInfo->fgBipKeyInstalled = TRUE; + } + else +#endif + prCmdKey->ucAlgorithmId = CIPHER_SUITE_CCMP; + } + } + else if (prNewKey->u4KeyLength == 32) { + if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_NONE) { + if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION2_ENABLED) { + prCmdKey->ucAlgorithmId = CIPHER_SUITE_TKIP; + } + else if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION3_ENABLED) { + prCmdKey->ucAlgorithmId = CIPHER_SUITE_CCMP; + prCmdKey->ucKeyLen = CCMP_KEY_LEN; + } + } + else { + if (rsnCheckPmkidCandicate(prAdapter)) { + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + DBGLOG(RSN, TRACE, ("Add key: Prepare a timer to indicate candidate PMKID Candidate\n")); + cnmTimerStopTimer(prAdapter, &prAisSpecBssInfo->rPreauthenticationTimer); + cnmTimerStartTimer(prAdapter, &prAisSpecBssInfo->rPreauthenticationTimer, + SEC_TO_MSEC(WAIT_TIME_IND_PMKID_CANDICATE_SEC)); + } + prCmdKey->ucAlgorithmId = CIPHER_SUITE_TKIP; + } + } + + // insert into prCmdQueue + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + + // wakeup txServiceThread later + GLUE_SET_EVENT(prGlueInfo); + + return WLAN_STATUS_PENDING; +} /* wlanoidSetAddKey */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to request the driver to remove the key at +* the specified key index. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetRemoveKey ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + P_PARAM_REMOVE_KEY_T prRemovedKey; + P_CMD_802_11_KEY prCmdKey; + UINT_8 ucCmdSeqNum; + + DEBUGFUNC("wlanoidSetRemoveKey"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_REMOVE_KEY_T); + + if (u4SetBufferLen < sizeof(PARAM_REMOVE_KEY_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in set remove key! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + ASSERT(pvSetBuffer); + prRemovedKey = (P_PARAM_REMOVE_KEY_T)pvSetBuffer; + + /* Dump PARAM_REMOVE_KEY content. */ + DBGLOG(REQ, INFO, ("Set: Dump PARAM_REMOVE_KEY content\n")); + DBGLOG(REQ, INFO, ("Length : 0x%08lx\n", prRemovedKey->u4Length)); + DBGLOG(REQ, INFO, ("Key Index : 0x%08lx\n", prRemovedKey->u4KeyIndex)); + DBGLOG(REQ, INFO, ("BSSID:\n")); + DBGLOG_MEM8(REQ, INFO, prRemovedKey->arBSSID, MAC_ADDR_LEN); + + /* Check bit 31: this bit should always 0 */ + if (prRemovedKey->u4KeyIndex & IS_TRANSMIT_KEY) { + /* Bit 31 should not be set */ + DBGLOG(REQ, ERROR, ("invalid key index: 0x%08lx\n", + prRemovedKey->u4KeyIndex)); + return WLAN_STATUS_INVALID_DATA; + } + + /* Check bits 8 ~ 29 should always be 0 */ + if (prRemovedKey->u4KeyIndex & BITS(8, 29)) { + /* Bit 31 should not be set */ + DBGLOG(REQ, ERROR, ("invalid key index: 0x%08lx\n", + prRemovedKey->u4KeyIndex)); + return WLAN_STATUS_INVALID_DATA; + } + + /* Clean up the Tx key flag */ + if (prRemovedKey->u4KeyIndex & IS_UNICAST_KEY) { + prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist = FALSE; + } + + prGlueInfo = prAdapter->prGlueInfo; + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_802_11_KEY))); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, ("Allocate CMD_INFO_T ==> FAILED.\n")); + return WLAN_STATUS_FAILURE; + } + + // increase command sequence number + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + // compose CMD_802_11_KEY cmd pkt + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->eNetworkType = NETWORK_TYPE_AIS_INDEX; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_802_11_KEY); + prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; + prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; + prCmdInfo->fgIsOid = TRUE; + prCmdInfo->ucCID = CMD_ID_ADD_REMOVE_KEY; + prCmdInfo->fgSetQuery = TRUE; + prCmdInfo->fgNeedResp = FALSE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = sizeof(PARAM_REMOVE_KEY_T); + prCmdInfo->pvInformationBuffer = pvSetBuffer; + prCmdInfo->u4InformationBufferLength = u4SetBufferLen; + + // Setup WIFI_CMD_T + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + prCmdKey = (P_CMD_802_11_KEY)(prWifiCmd->aucBuffer); + + kalMemZero((PUINT_8)prCmdKey, sizeof(CMD_802_11_KEY)); + + prCmdKey->ucAddRemove = 0; /* Remove */ + prCmdKey->ucKeyId = (UINT_8)(prRemovedKey->u4KeyIndex & 0x000000ff); + kalMemCopy(prCmdKey->aucPeerAddr, (PUINT_8)prRemovedKey->arBSSID, MAC_ADDR_LEN); + +#if CFG_SUPPORT_802_11W + ASSERT(prCmdKey->ucKeyId < MAX_KEY_NUM + 2); +#else + ASSERT(prCmdKey->ucKeyId < MAX_KEY_NUM); +#endif + + if (prRemovedKey->u4KeyIndex & IS_UNICAST_KEY) { + prCmdKey->ucKeyType = 1; + } + + // insert into prCmdQueue + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + + // wakeup txServiceThread later + GLUE_SET_EVENT(prGlueInfo); + + return WLAN_STATUS_PENDING; +} /* wlanoidSetRemoveKey */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the current encryption status. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryEncryptionStatus ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + BOOLEAN fgTransmitKeyAvailable = TRUE; + ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus = 0; + + DEBUGFUNC("wlanoidQueryEncryptionStatus"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(ENUM_PARAM_ENCRYPTION_STATUS_T); + + fgTransmitKeyAvailable = prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist; + + switch (prAdapter->rWifiVar.rConnSettings.eEncStatus) { + case ENUM_ENCRYPTION3_ENABLED: + if (fgTransmitKeyAvailable) { + eEncStatus = ENUM_ENCRYPTION3_ENABLED; + } + else { + eEncStatus = ENUM_ENCRYPTION3_KEY_ABSENT; + } + break; + + case ENUM_ENCRYPTION2_ENABLED: + if (fgTransmitKeyAvailable) { + eEncStatus = ENUM_ENCRYPTION2_ENABLED; + break; + } + else { + eEncStatus = ENUM_ENCRYPTION2_KEY_ABSENT; + } + break; + + case ENUM_ENCRYPTION1_ENABLED: + if (fgTransmitKeyAvailable) { + eEncStatus = ENUM_ENCRYPTION1_ENABLED; + } + else { + eEncStatus = ENUM_ENCRYPTION1_KEY_ABSENT; + } + break; + + case ENUM_ENCRYPTION_DISABLED: + eEncStatus = ENUM_ENCRYPTION_DISABLED; + break; + + default: + DBGLOG(REQ, ERROR, ("Unknown Encryption Status Setting:%d\n", + prAdapter->rWifiVar.rConnSettings.eEncStatus)); + } + +#if DBG + DBGLOG(REQ, INFO, + ("Encryption status: %d Return:%d\n", + prAdapter->rWifiVar.rConnSettings.eEncStatus, + eEncStatus)); +#endif + + *(P_ENUM_PARAM_ENCRYPTION_STATUS_T)pvQueryBuffer = eEncStatus; + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryEncryptionStatus */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set the encryption status to the driver. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_NOT_SUPPORTED +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetEncryptionStatus ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_GLUE_INFO_T prGlueInfo; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + ENUM_PARAM_ENCRYPTION_STATUS_T eEewEncrypt; + + DEBUGFUNC("wlanoidSetEncryptionStatus"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + prGlueInfo = prAdapter->prGlueInfo; + + *pu4SetInfoLen = sizeof(ENUM_PARAM_ENCRYPTION_STATUS_T); + + //if (IS_ARB_IN_RFTEST_STATE(prAdapter)) { + // return WLAN_STATUS_SUCCESS; + //} + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in set encryption status! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + eEewEncrypt = *(P_ENUM_PARAM_ENCRYPTION_STATUS_T)pvSetBuffer; + DBGLOG(REQ, TRACE, ("ENCRYPTION_STATUS %d\n", eEewEncrypt)); + + switch (eEewEncrypt) { + case ENUM_ENCRYPTION_DISABLED: /* Disable WEP, TKIP, AES */ + DBGLOG(RSN, TRACE, ("Disable Encryption\n")); + secSetCipherSuite(prAdapter, + CIPHER_FLAG_WEP40 | + CIPHER_FLAG_WEP104 | + CIPHER_FLAG_WEP128); + break; + + case ENUM_ENCRYPTION1_ENABLED: /* Enable WEP. Disable TKIP, AES */ + DBGLOG(RSN, TRACE, ("Enable Encryption1\n")); + secSetCipherSuite(prAdapter, + CIPHER_FLAG_WEP40 | + CIPHER_FLAG_WEP104 | + CIPHER_FLAG_WEP128); + break; + + case ENUM_ENCRYPTION2_ENABLED: /* Enable WEP, TKIP. Disable AES */ + secSetCipherSuite(prAdapter, + CIPHER_FLAG_WEP40 | + CIPHER_FLAG_WEP104 | + CIPHER_FLAG_WEP128 | + CIPHER_FLAG_TKIP); + DBGLOG(RSN, TRACE, ("Enable Encryption2\n")); + break; + + case ENUM_ENCRYPTION3_ENABLED: /* Enable WEP, TKIP, AES */ + secSetCipherSuite(prAdapter, + CIPHER_FLAG_WEP40 | + CIPHER_FLAG_WEP104 | + CIPHER_FLAG_WEP128 | + CIPHER_FLAG_TKIP | + CIPHER_FLAG_CCMP); + DBGLOG(RSN, TRACE, ("Enable Encryption3\n")); + break; + + default: + DBGLOG(RSN, WARN, ("Unacceptible encryption status: %d\n", + *(P_ENUM_PARAM_ENCRYPTION_STATUS_T)pvSetBuffer)); + + rStatus = WLAN_STATUS_NOT_SUPPORTED; + } + + if (rStatus == WLAN_STATUS_SUCCESS) { + /* Save the new encryption status. */ + prAdapter->rWifiVar.rConnSettings.eEncStatus = + *(P_ENUM_PARAM_ENCRYPTION_STATUS_T)pvSetBuffer; + } + + return rStatus; +} /* wlanoidSetEncryptionStatus */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to test the driver. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetTest ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_PARAM_802_11_TEST_T prTest; + PVOID pvTestData; + PVOID pvStatusBuffer; + UINT_32 u4StatusBufferSize; + + DEBUGFUNC("wlanoidSetTest"); + + ASSERT(prAdapter); + + ASSERT(pu4SetInfoLen); + ASSERT(pvSetBuffer); + + *pu4SetInfoLen = u4SetBufferLen; + + prTest = (P_PARAM_802_11_TEST_T)pvSetBuffer; + + DBGLOG(REQ, TRACE, ("Test - Type %ld\n", prTest->u4Type)); + + switch (prTest->u4Type) { + case 1: /* Type 1: generate an authentication event */ + pvTestData = (PVOID)&prTest->u.AuthenticationEvent; + pvStatusBuffer = (PVOID)prAdapter->aucIndicationEventBuffer; + u4StatusBufferSize = prTest->u4Length - 8; + break; + + case 2: /* Type 2: generate an RSSI status indication */ + pvTestData = (PVOID)&prTest->u.RssiTrigger; + pvStatusBuffer = (PVOID)&prAdapter->rWlanInfo.rCurrBssId.rRssi; + u4StatusBufferSize = sizeof(PARAM_RSSI); + break; + + default: + return WLAN_STATUS_INVALID_DATA; + } + + ASSERT(u4StatusBufferSize <= 180); + if (u4StatusBufferSize > 180) { + return WLAN_STATUS_INVALID_LENGTH; + } + + /* Get the contents of the StatusBuffer from the test structure. */ + kalMemCopy(pvStatusBuffer, pvTestData, u4StatusBufferSize); + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, + pvStatusBuffer, + u4StatusBufferSize); + + return WLAN_STATUS_SUCCESS; +} /* wlanoidSetTest */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the driver's WPA2 status. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryCapability ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + P_PARAM_CAPABILITY_T prCap; + P_PARAM_AUTH_ENCRYPTION_T prAuthenticationEncryptionSupported; + + DEBUGFUNC("wlanoidQueryCapability"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = 4 * sizeof(UINT_32) + 14 * sizeof(PARAM_AUTH_ENCRYPTION_T); + + if (u4QueryBufferLen < *pu4QueryInfoLen) { + return WLAN_STATUS_INVALID_LENGTH; + } + + prCap = (P_PARAM_CAPABILITY_T)pvQueryBuffer; + + prCap->u4Length = *pu4QueryInfoLen; + prCap->u4Version = 2; /* WPA2 */ + prCap->u4NoOfPMKIDs = CFG_MAX_PMKID_CACHE; + prCap->u4NoOfAuthEncryptPairsSupported = 14; + + prAuthenticationEncryptionSupported = + &prCap->arAuthenticationEncryptionSupported[0]; + + // fill 14 entries of supported settings + prAuthenticationEncryptionSupported[0].eAuthModeSupported = + AUTH_MODE_OPEN; + + prAuthenticationEncryptionSupported[0].eEncryptStatusSupported = + ENUM_ENCRYPTION_DISABLED; + + prAuthenticationEncryptionSupported[1].eAuthModeSupported = + AUTH_MODE_OPEN; + prAuthenticationEncryptionSupported[1].eEncryptStatusSupported = + ENUM_ENCRYPTION1_ENABLED; + + prAuthenticationEncryptionSupported[2].eAuthModeSupported = + AUTH_MODE_SHARED; + prAuthenticationEncryptionSupported[2].eEncryptStatusSupported = + ENUM_ENCRYPTION_DISABLED; + + prAuthenticationEncryptionSupported[3].eAuthModeSupported = + AUTH_MODE_SHARED; + prAuthenticationEncryptionSupported[3].eEncryptStatusSupported = + ENUM_ENCRYPTION1_ENABLED; + + prAuthenticationEncryptionSupported[4].eAuthModeSupported = + AUTH_MODE_WPA; + prAuthenticationEncryptionSupported[4].eEncryptStatusSupported = + ENUM_ENCRYPTION2_ENABLED; + + prAuthenticationEncryptionSupported[5].eAuthModeSupported = + AUTH_MODE_WPA; + prAuthenticationEncryptionSupported[5].eEncryptStatusSupported = + ENUM_ENCRYPTION3_ENABLED; + + prAuthenticationEncryptionSupported[6].eAuthModeSupported = + AUTH_MODE_WPA_PSK; + prAuthenticationEncryptionSupported[6].eEncryptStatusSupported = + ENUM_ENCRYPTION2_ENABLED; + + prAuthenticationEncryptionSupported[7].eAuthModeSupported = + AUTH_MODE_WPA_PSK; + prAuthenticationEncryptionSupported[7].eEncryptStatusSupported = + ENUM_ENCRYPTION3_ENABLED; + + prAuthenticationEncryptionSupported[8].eAuthModeSupported = + AUTH_MODE_WPA_NONE; + prAuthenticationEncryptionSupported[8].eEncryptStatusSupported = + ENUM_ENCRYPTION2_ENABLED; + + prAuthenticationEncryptionSupported[9].eAuthModeSupported = + AUTH_MODE_WPA_NONE; + prAuthenticationEncryptionSupported[9].eEncryptStatusSupported = + ENUM_ENCRYPTION3_ENABLED; + + prAuthenticationEncryptionSupported[10].eAuthModeSupported = + AUTH_MODE_WPA2; + prAuthenticationEncryptionSupported[10].eEncryptStatusSupported = + ENUM_ENCRYPTION2_ENABLED; + + prAuthenticationEncryptionSupported[11].eAuthModeSupported = + AUTH_MODE_WPA2; + prAuthenticationEncryptionSupported[11].eEncryptStatusSupported = + ENUM_ENCRYPTION3_ENABLED; + + prAuthenticationEncryptionSupported[12].eAuthModeSupported = + AUTH_MODE_WPA2_PSK; + prAuthenticationEncryptionSupported[12].eEncryptStatusSupported = + ENUM_ENCRYPTION2_ENABLED; + + prAuthenticationEncryptionSupported[13].eAuthModeSupported = + AUTH_MODE_WPA2_PSK; + prAuthenticationEncryptionSupported[13].eEncryptStatusSupported = + ENUM_ENCRYPTION3_ENABLED; + + return WLAN_STATUS_SUCCESS; + +} /* wlanoidQueryCapability */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the PMKID in the PMK cache. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryPmkid ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + UINT_32 i; + P_PARAM_PMKID_T prPmkid; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + DEBUGFUNC("wlanoidQueryPmkid"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + *pu4QueryInfoLen = OFFSET_OF(PARAM_PMKID_T, arBSSIDInfo) + + prAisSpecBssInfo->u4PmkidCacheCount * sizeof(PARAM_BSSID_INFO_T); + + if (u4QueryBufferLen < *pu4QueryInfoLen) { + return WLAN_STATUS_INVALID_LENGTH; + } + + prPmkid = (P_PARAM_PMKID_T)pvQueryBuffer; + + prPmkid->u4Length = *pu4QueryInfoLen; + prPmkid->u4BSSIDInfoCount = prAisSpecBssInfo->u4PmkidCacheCount; + + for (i = 0; i < prAisSpecBssInfo->u4PmkidCacheCount; i++) { + kalMemCopy(prPmkid->arBSSIDInfo[i].arBSSID, + prAisSpecBssInfo->arPmkidCache[i].rBssidInfo.arBSSID, + sizeof(PARAM_MAC_ADDRESS)); + kalMemCopy(prPmkid->arBSSIDInfo[i].arPMKID, + prAisSpecBssInfo->arPmkidCache[i].rBssidInfo.arPMKID, + sizeof(PARAM_PMKID_VALUE)); + } + + return WLAN_STATUS_SUCCESS; + +} /* wlanoidQueryPmkid */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set the PMKID to the PMK cache in the driver. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +* \retval WLAN_STATUS_INVALID_DATA +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetPmkid ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + UINT_32 i, j; + P_PARAM_PMKID_T prPmkid; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + DEBUGFUNC("wlanoidSetPmkid"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = u4SetBufferLen; + + /* It's possibble BSSIDInfoCount is zero, because OS wishes to clean PMKID */ + if (u4SetBufferLen < OFFSET_OF(PARAM_PMKID_T, arBSSIDInfo)) { + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + ASSERT(pvSetBuffer); + prPmkid = (P_PARAM_PMKID_T)pvSetBuffer; + + if (u4SetBufferLen < + ((prPmkid->u4BSSIDInfoCount * sizeof(PARAM_BSSID_INFO_T)) + + OFFSET_OF(PARAM_PMKID_T, arBSSIDInfo))) { + return WLAN_STATUS_INVALID_DATA; + } + + if (prPmkid->u4BSSIDInfoCount > CFG_MAX_PMKID_CACHE) { + return WLAN_STATUS_INVALID_DATA; + } + + DBGLOG(REQ, INFO, ("Count %lu\n", prPmkid->u4BSSIDInfoCount)); + + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + /* This OID replace everything in the PMKID cache. */ + if (prPmkid->u4BSSIDInfoCount == 0) { + prAisSpecBssInfo->u4PmkidCacheCount = 0; + kalMemZero(prAisSpecBssInfo->arPmkidCache, sizeof(PMKID_ENTRY_T) * CFG_MAX_PMKID_CACHE); + } + if ((prAisSpecBssInfo->u4PmkidCacheCount + prPmkid->u4BSSIDInfoCount > CFG_MAX_PMKID_CACHE)) { + prAisSpecBssInfo->u4PmkidCacheCount = 0; + kalMemZero(prAisSpecBssInfo->arPmkidCache, sizeof(PMKID_ENTRY_T) * CFG_MAX_PMKID_CACHE); + } + + /* + The driver can only clear its PMKID cache whenever it make a media disconnect + indication. Otherwise, it must change the PMKID cache only when set through this OID. + */ +#if CFG_RSN_MIGRATION + for (i = 0; i < prPmkid->u4BSSIDInfoCount; i++) { + /* Search for desired BSSID. If desired BSSID is found, + then set the PMKID */ + if (!rsnSearchPmkidEntry(prAdapter, + (PUINT_8)prPmkid->arBSSIDInfo[i].arBSSID, + &j)) { + /* No entry found for the specified BSSID, so add one entry */ + if (prAisSpecBssInfo->u4PmkidCacheCount < CFG_MAX_PMKID_CACHE - 1) { + j = prAisSpecBssInfo->u4PmkidCacheCount; + kalMemCopy(prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arBSSID, + prPmkid->arBSSIDInfo[i].arBSSID, + sizeof(PARAM_MAC_ADDRESS)); + prAisSpecBssInfo->u4PmkidCacheCount++; + } + else { + j = CFG_MAX_PMKID_CACHE; + } + } + + if (j < CFG_MAX_PMKID_CACHE) { + kalMemCopy(prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arPMKID, + prPmkid->arBSSIDInfo[i].arPMKID, + sizeof(PARAM_PMKID_VALUE)); + DBGLOG(RSN, TRACE, ("Add BSSID "MACSTR" idx=%d PMKID value "MACSTR"\n", + MAC2STR(prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arBSSID),j, MAC2STR(prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arPMKID))); + prAisSpecBssInfo->arPmkidCache[j].fgPmkidExist = TRUE; + } + } +#endif + return WLAN_STATUS_SUCCESS; + +} /* wlanoidSetPmkid */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the set of supported data rates that +* the radio is capable of running +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query +* \param[in] u4QueryBufferLen The length of the query buffer +* \param[out] pu4QueryInfoLen If the call is successful, returns the number +* of bytes written into the query buffer. If the +* call failed due to invalid length of the query +* buffer, returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQuerySupportedRates ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + PARAM_RATES eRate = { + // BSSBasicRateSet for 802.11n Non-HT rates + 0x8C, // 6M + 0x92, // 9M + 0x98, // 12M + 0xA4, // 18M + 0xB0, // 24M + 0xC8, // 36M + 0xE0, // 48M + 0xEC // 54M + }; + + DEBUGFUNC("wlanoidQuerySupportedRates"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(PARAM_RATES_EX); + + if (u4QueryBufferLen < *pu4QueryInfoLen ) { + DBGLOG(REQ, WARN, ("Invalid length %ld\n", u4QueryBufferLen)); + return WLAN_STATUS_INVALID_LENGTH; + } + + kalMemCopy(pvQueryBuffer, + (PVOID)&eRate, + sizeof(PARAM_RATES)); + + return WLAN_STATUS_SUCCESS; +} /* end of wlanoidQuerySupportedRates() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query current desired rates. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryDesiredRates ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryDesiredRates"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(PARAM_RATES_EX); + + if (u4QueryBufferLen < *pu4QueryInfoLen ) { + DBGLOG(REQ, WARN, ("Invalid length %ld\n", u4QueryBufferLen)); + return WLAN_STATUS_INVALID_LENGTH; + } + + kalMemCopy(pvQueryBuffer, + (PVOID)&(prAdapter->rWlanInfo.eDesiredRates), + sizeof(PARAM_RATES)); + + return WLAN_STATUS_SUCCESS; + +} /* end of wlanoidQueryDesiredRates() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to Set the desired rates. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetDesiredRates ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + UINT_32 i; + DEBUGFUNC("wlanoidSetDesiredRates"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen < sizeof(PARAM_RATES)) { + DBGLOG(REQ, WARN, ("Invalid length %ld\n", u4SetBufferLen)); + return WLAN_STATUS_INVALID_LENGTH; + } + + *pu4SetInfoLen = sizeof(PARAM_RATES); + + if (u4SetBufferLen < sizeof(PARAM_RATES)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + kalMemCopy((PVOID)&(prAdapter->rWlanInfo.eDesiredRates), + pvSetBuffer, + sizeof(PARAM_RATES)); + + prAdapter->rWlanInfo.eLinkAttr.ucDesiredRateLen = PARAM_MAX_LEN_RATES; + for (i = 0 ; i < PARAM_MAX_LEN_RATES ; i++) { + prAdapter->rWlanInfo.eLinkAttr.u2DesiredRate[i] = + (UINT_16) (prAdapter->rWlanInfo.eDesiredRates[i]); + } + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_LINK_ATTRIB, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_LINK_ATTRIB), + (PUINT_8)&(prAdapter->rWlanInfo.eLinkAttr), + pvSetBuffer, + u4SetBufferLen + ); + +} /* end of wlanoidSetDesiredRates() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the maximum frame size in bytes, +* not including the header. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the +* call failed due to invalid length of the query +* buffer, returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryMaxFrameSize ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryMaxFrameSize"); + + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + + if (u4QueryBufferLen < sizeof(UINT_32)) { + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_INVALID_LENGTH; + } + + *(PUINT_32)pvQueryBuffer = ETHERNET_MAX_PKT_SZ - ETHERNET_HEADER_SZ; + *pu4QueryInfoLen = sizeof(UINT_32); + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryMaxFrameSize */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the maximum total packet length +* in bytes. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryMaxTotalSize ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryMaxTotalSize"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + if (u4QueryBufferLen < sizeof(UINT_32)) { + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_INVALID_LENGTH; + } + + *(PUINT_32)pvQueryBuffer = ETHERNET_MAX_PKT_SZ; + *pu4QueryInfoLen = sizeof(UINT_32); + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryMaxTotalSize */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the vendor ID of the NIC. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryVendorId ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ +#if DBG + PUINT_8 cp; +#endif + DEBUGFUNC("wlanoidQueryVendorId"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + if (u4QueryBufferLen < sizeof(UINT_32)) { + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_INVALID_LENGTH; + } + + kalMemCopy(pvQueryBuffer, prAdapter->aucMacAddress, 3); + *((PUINT_8)pvQueryBuffer + 3) = 1; + *pu4QueryInfoLen = sizeof(UINT_32); + +#if DBG + cp = (PUINT_8)pvQueryBuffer; + DBGLOG(REQ, LOUD, ("Vendor ID=%02x-%02x-%02x-%02x\n", cp[0], cp[1], cp[2], cp[3])); +#endif + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryVendorId */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the current RSSI value. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call failed due to invalid length of +* the query buffer, returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryRssi ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryRssi"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(PARAM_RSSI); + + /* Check for query buffer length */ + if (u4QueryBufferLen < *pu4QueryInfoLen) { + DBGLOG(REQ, WARN, ("Too short length %ld\n", u4QueryBufferLen)); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_DISCONNECTED) { + return WLAN_STATUS_ADAPTER_NOT_READY; + } + else if (prAdapter->fgIsLinkQualityValid == TRUE && + (kalGetTimeTick() - prAdapter->rLinkQualityUpdateTime) <= CFG_LINK_QUALITY_VALID_PERIOD) { + PARAM_RSSI rRssi; + + rRssi = (PARAM_RSSI)prAdapter->rLinkQuality.cRssi; // ranged from (-128 ~ 30) in unit of dBm + + if(rRssi > PARAM_WHQL_RSSI_MAX_DBM) + rRssi = PARAM_WHQL_RSSI_MAX_DBM; + else if(rRssi < PARAM_WHQL_RSSI_MIN_DBM) + rRssi = PARAM_WHQL_RSSI_MIN_DBM; + + kalMemCopy(pvQueryBuffer, &rRssi, sizeof(PARAM_RSSI)); + return WLAN_STATUS_SUCCESS; + } + + #ifdef LINUX + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_LINK_QUALITY, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryLinkQuality, + nicOidCmdTimeoutCommon, + *pu4QueryInfoLen, + pvQueryBuffer, + pvQueryBuffer, + u4QueryBufferLen + ); + #else + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_LINK_QUALITY, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryLinkQuality, + nicOidCmdTimeoutCommon, + 0, + NULL, + pvQueryBuffer, + u4QueryBufferLen + ); + + #endif +} /* end of wlanoidQueryRssi() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the current RSSI trigger value. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call failed due to invalid length of +* the query buffer, returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryRssiTrigger ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryRssiTrigger"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + + if(prAdapter->rWlanInfo.eRssiTriggerType == ENUM_RSSI_TRIGGER_NONE) + return WLAN_STATUS_ADAPTER_NOT_READY; + + *pu4QueryInfoLen = sizeof(PARAM_RSSI); + + /* Check for query buffer length */ + if (u4QueryBufferLen < *pu4QueryInfoLen) { + DBGLOG(REQ, WARN, ("Too short length %ld\n", u4QueryBufferLen)); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + *(PARAM_RSSI *) pvQueryBuffer = prAdapter->rWlanInfo.rRssiTriggerValue; + DBGLOG(REQ, INFO, ("RSSI trigger: %ld dBm\n", *(PARAM_RSSI *) pvQueryBuffer)); + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryRssiTrigger */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set a trigger value of the RSSI event. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns the +* amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetRssiTrigger ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + PARAM_RSSI rRssiTriggerValue; + DEBUGFUNC("wlanoidSetRssiTrigger"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + + *pu4SetInfoLen = sizeof(PARAM_RSSI); + rRssiTriggerValue = *(PARAM_RSSI *) pvSetBuffer; + + if(rRssiTriggerValue > PARAM_WHQL_RSSI_MAX_DBM + || rRssiTriggerValue < PARAM_WHQL_RSSI_MIN_DBM) + return + + /* Save the RSSI trigger value to the Adapter structure */ + prAdapter->rWlanInfo.rRssiTriggerValue = rRssiTriggerValue; + + /* If the RSSI trigger value is equal to the current RSSI value, the + * indication triggers immediately. We need to indicate the protocol + * that an RSSI status indication event triggers. */ + if (rRssiTriggerValue == (PARAM_RSSI)(prAdapter->rLinkQuality.cRssi)) { + prAdapter->rWlanInfo.eRssiTriggerType = ENUM_RSSI_TRIGGER_TRIGGERED; + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, + (PVOID) &prAdapter->rWlanInfo.rRssiTriggerValue, sizeof(PARAM_RSSI)); + } + else if(rRssiTriggerValue < (PARAM_RSSI)(prAdapter->rLinkQuality.cRssi)) + prAdapter->rWlanInfo.eRssiTriggerType = ENUM_RSSI_TRIGGER_GREATER; + else if(rRssiTriggerValue > (PARAM_RSSI)(prAdapter->rLinkQuality.cRssi)) + prAdapter->rWlanInfo.eRssiTriggerType = ENUM_RSSI_TRIGGER_LESS; + + return WLAN_STATUS_SUCCESS; +} /* wlanoidSetRssiTrigger */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set a suggested value for the number of +* bytes of received packet data that will be indicated to the protocol +* driver. We just accept the set and ignore this value. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetCurrentLookahead ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + DEBUGFUNC("wlanoidSetCurrentLookahead"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen < sizeof(UINT_32)) { + *pu4SetInfoLen = sizeof(UINT_32); + return WLAN_STATUS_INVALID_LENGTH; + } + + *pu4SetInfoLen = sizeof(UINT_32); + return WLAN_STATUS_SUCCESS; +} /* wlanoidSetCurrentLookahead */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the number of frames that the driver +* receives but does not indicate to the protocols due to errors. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryRcvError ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryRcvError"); + DBGLOG(REQ, LOUD, ("\n")); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + else if (u4QueryBufferLen < sizeof(UINT_32) + || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { + *pu4QueryInfoLen = sizeof(UINT_64); + return WLAN_STATUS_INVALID_LENGTH; + } + +#if CFG_ENABLE_STATISTICS_BUFFERING + if(IsBufferedStatisticsUsable(prAdapter) == TRUE) { + // @FIXME, RX_ERROR_DROP_COUNT/RX_FIFO_FULL_DROP_COUNT is not calculated + if(u4QueryBufferLen == sizeof(UINT_32)) { + *pu4QueryInfoLen = sizeof(UINT_32); + *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rStatStruct.rFCSErrorCount.QuadPart; + } + else { + *pu4QueryInfoLen = sizeof(UINT_64); + *(PUINT_64) pvQueryBuffer = (UINT_64) prAdapter->rStatStruct.rFCSErrorCount.QuadPart; + } + + return WLAN_STATUS_SUCCESS; + } + else +#endif + { + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_STATISTICS, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryRecvError, + nicOidCmdTimeoutCommon, + 0, + NULL, + pvQueryBuffer, + u4QueryBufferLen + ); + } +} /* wlanoidQueryRcvError */ + + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to query the number of frames that the NIC +* cannot receive due to lack of NIC receive buffer space. +* +* \param[in] pvAdapter Pointer to the Adapter structure +* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the +* query buffer +* \param[in] u4QueryBufLen The length of the query buffer +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS If success; +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryRcvNoBuffer ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryRcvNoBuffer"); + DBGLOG(REQ, LOUD, ("\n")); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + else if (u4QueryBufferLen < sizeof(UINT_32) + || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { + *pu4QueryInfoLen = sizeof(UINT_64); + return WLAN_STATUS_INVALID_LENGTH; + } + +#if CFG_ENABLE_STATISTICS_BUFFERING + if(IsBufferedStatisticsUsable(prAdapter) == TRUE) { + if(u4QueryBufferLen == sizeof(UINT_32)) { + *pu4QueryInfoLen = sizeof(UINT_32); + *(PUINT_32) pvQueryBuffer = (UINT_32) 0; //@FIXME + } + else { + *pu4QueryInfoLen = sizeof(UINT_64); + *(PUINT_64) pvQueryBuffer = (UINT_64) 0; //@FIXME + } + + return WLAN_STATUS_SUCCESS; + } + else +#endif + { + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_STATISTICS, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryRecvNoBuffer, + nicOidCmdTimeoutCommon, + 0, + NULL, + pvQueryBuffer, + u4QueryBufferLen + ); + } +} /* wlanoidQueryRcvNoBuffer */ + + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to query the number of frames that the NIC +* received and it is CRC error. +* +* \param[in] pvAdapter Pointer to the Adapter structure +* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the +* query buffer +* \param[in] u4QueryBufLen The length of the query buffer +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS If success; +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryRcvCrcError ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryRcvCrcError"); + DBGLOG(REQ, LOUD, ("\n")); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + else if (u4QueryBufferLen < sizeof(UINT_32) + || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { + *pu4QueryInfoLen = sizeof(UINT_64); + return WLAN_STATUS_INVALID_LENGTH; + } +#if CFG_ENABLE_STATISTICS_BUFFERING + if(IsBufferedStatisticsUsable(prAdapter) == TRUE) { + if(u4QueryBufferLen == sizeof(UINT_32)) { + *pu4QueryInfoLen = sizeof(UINT_32); + *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rStatStruct.rFCSErrorCount.QuadPart; + } + else { + *pu4QueryInfoLen = sizeof(UINT_64); + *(PUINT_64) pvQueryBuffer = (UINT_64) prAdapter->rStatStruct.rFCSErrorCount.QuadPart; + } + + return WLAN_STATUS_SUCCESS; + } + else +#endif + { + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_STATISTICS, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryRecvCrcError, + nicOidCmdTimeoutCommon, + 0, + NULL, + pvQueryBuffer, + u4QueryBufferLen + ); + } +} /* wlanoidQueryRcvCrcError */ + + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to query the current 802.11 statistics. +* +* \param[in] pvAdapter Pointer to the Adapter structure +* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the +* query buffer +* \param[in] u4QueryBufLen The length of the query buffer +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryStatistics ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryStatistics"); + DBGLOG(REQ, LOUD, ("\n")); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + else if (u4QueryBufferLen < sizeof(PARAM_802_11_STATISTICS_STRUCT_T)) { + DBGLOG(REQ, WARN, ("Too short length %ld\n", u4QueryBufferLen)); + return WLAN_STATUS_INVALID_LENGTH; + } + +#if CFG_ENABLE_STATISTICS_BUFFERING + if(IsBufferedStatisticsUsable(prAdapter) == TRUE) { + P_PARAM_802_11_STATISTICS_STRUCT_T prStatistics; + + *pu4QueryInfoLen = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); + prStatistics = (P_PARAM_802_11_STATISTICS_STRUCT_T) pvQueryBuffer; + + prStatistics->u4Length = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); + prStatistics->rTransmittedFragmentCount + = prAdapter->rStatStruct.rTransmittedFragmentCount; + prStatistics->rMulticastTransmittedFrameCount + = prAdapter->rStatStruct.rMulticastTransmittedFrameCount; + prStatistics->rFailedCount + = prAdapter->rStatStruct.rFailedCount; + prStatistics->rRetryCount + = prAdapter->rStatStruct.rRetryCount; + prStatistics->rMultipleRetryCount + = prAdapter->rStatStruct.rMultipleRetryCount; + prStatistics->rRTSSuccessCount + = prAdapter->rStatStruct.rRTSSuccessCount; + prStatistics->rRTSFailureCount + = prAdapter->rStatStruct.rRTSFailureCount; + prStatistics->rACKFailureCount + = prAdapter->rStatStruct.rACKFailureCount; + prStatistics->rFrameDuplicateCount + = prAdapter->rStatStruct.rFrameDuplicateCount; + prStatistics->rReceivedFragmentCount + = prAdapter->rStatStruct.rReceivedFragmentCount; + prStatistics->rMulticastReceivedFrameCount + = prAdapter->rStatStruct.rMulticastReceivedFrameCount; + prStatistics->rFCSErrorCount + = prAdapter->rStatStruct.rFCSErrorCount; + prStatistics->rTKIPLocalMICFailures.QuadPart + = 0; + prStatistics->rTKIPICVErrors.QuadPart + = 0; + prStatistics->rTKIPCounterMeasuresInvoked.QuadPart + = 0; + prStatistics->rTKIPReplays.QuadPart + = 0; + prStatistics->rCCMPFormatErrors.QuadPart + = 0; + prStatistics->rCCMPReplays.QuadPart + = 0; + prStatistics->rCCMPDecryptErrors.QuadPart + = 0; + prStatistics->rFourWayHandshakeFailures.QuadPart + = 0; + prStatistics->rWEPUndecryptableCount.QuadPart + = 0; + prStatistics->rWEPICVErrorCount.QuadPart + = 0; + prStatistics->rDecryptSuccessCount.QuadPart + = 0; + prStatistics->rDecryptFailureCount.QuadPart + = 0; + + return WLAN_STATUS_SUCCESS; + } + else +#endif + { + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_STATISTICS, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryStatistics, + nicOidCmdTimeoutCommon, + 0, + NULL, + pvQueryBuffer, + u4QueryBufferLen + ); + } +} /* wlanoidQueryStatistics */ + + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to query current media streaming status. +* +* \param[in] pvAdapter Pointer to the Adapter structure +* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the +* query buffer +* \param[in] u4QueryBufLen The length of the query buffer +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryMediaStreamMode( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryMediaStreamMode"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(ENUM_MEDIA_STREAM_MODE); + + if (u4QueryBufferLen < *pu4QueryInfoLen ) { + DBGLOG(REQ, WARN, ("Invalid length %ld\n", u4QueryBufferLen)); + return WLAN_STATUS_INVALID_LENGTH; + } + + *(P_ENUM_MEDIA_STREAM_MODE)pvQueryBuffer = + prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode == 0 ? + ENUM_MEDIA_STREAM_OFF : ENUM_MEDIA_STREAM_ON; + + return WLAN_STATUS_SUCCESS; + +} /* wlanoidQueryMediaStreamMode */ + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to enter media streaming mode or exit media streaming mode +* +* \param[in] pvAdapter Pointer to the Adapter structure +* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the +* query buffer +* \param[in] u4QueryBufLen The length of the query buffer +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetMediaStreamMode( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + ENUM_MEDIA_STREAM_MODE eStreamMode; + + DEBUGFUNC("wlanoidSetMediaStreamMode"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen < sizeof(ENUM_MEDIA_STREAM_MODE)) { + DBGLOG(REQ, WARN, ("Invalid length %ld\n", u4SetBufferLen)); + return WLAN_STATUS_INVALID_LENGTH; + } + + *pu4SetInfoLen = sizeof(ENUM_MEDIA_STREAM_MODE); + + eStreamMode = *(P_ENUM_MEDIA_STREAM_MODE)pvSetBuffer; + + if(eStreamMode == ENUM_MEDIA_STREAM_OFF) + prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode = 0; + else + prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode = 1; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_LINK_ATTRIB, + TRUE, + FALSE, + TRUE, + nicCmdEventSetMediaStreamMode, + nicOidCmdTimeoutCommon, + sizeof(CMD_LINK_ATTRIB), + (PUINT_8)&(prAdapter->rWlanInfo.eLinkAttr), + pvSetBuffer, + u4SetBufferLen + ); +} /* wlanoidSetMediaStreamMode */ + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to query the permanent MAC address of the NIC. +* +* \param[in] pvAdapter Pointer to the Adapter structure +* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the +* query buffer +* \param[in] u4QueryBufLen The length of the query buffer +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryPermanentAddr ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryPermanentAddr"); + DBGLOG(INIT, LOUD, ("\n")); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + if (u4QueryBufferLen < MAC_ADDR_LEN) { + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + COPY_MAC_ADDR(pvQueryBuffer, prAdapter->rWifiVar.aucPermanentAddress); + *pu4QueryInfoLen = MAC_ADDR_LEN; + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryPermanentAddr */ + + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to query the MAC address the NIC is currently using. +* +* \param[in] pvAdapter Pointer to the Adapter structure +* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the +* query buffer +* \param[in] u4QueryBufLen The length of the query buffer +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryCurrentAddr ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + CMD_BASIC_CONFIG rCmdBasicConfig; + + DEBUGFUNC("wlanoidQueryCurrentAddr"); + DBGLOG(INIT, LOUD, ("\n")); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + if (u4QueryBufferLen < MAC_ADDR_LEN) { + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + kalMemZero(&rCmdBasicConfig, sizeof(CMD_BASIC_CONFIG)); + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_BASIC_CONFIG, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryAddress, + nicOidCmdTimeoutCommon, + sizeof(CMD_BASIC_CONFIG), + (PUINT_8)&rCmdBasicConfig, + pvQueryBuffer, + u4QueryBufferLen + ); + +} /* wlanoidQueryCurrentAddr */ + + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to query NIC link speed. +* +* \param[in] pvAdapter Pointer to the Adapter structure +* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the +* query buffer +* \param[in] u4QueryBufLen The length of the query buffer +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryLinkSpeed( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryLinkSpeed"); + + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(UINT_32); + + if (u4QueryBufferLen < sizeof(UINT_32)) { + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_CONNECTED) { + *(PUINT_32)pvQueryBuffer = 10000; // change to unit of 100bps + return WLAN_STATUS_SUCCESS; + } + else if (prAdapter->fgIsLinkRateValid == TRUE && + (kalGetTimeTick() - prAdapter->rLinkRateUpdateTime) <= CFG_LINK_QUALITY_VALID_PERIOD) { + *(PUINT_32)pvQueryBuffer = prAdapter->rLinkQuality.u2LinkSpeed * 5000; // change to unit of 100bps + return WLAN_STATUS_SUCCESS; + } + else { + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_LINK_QUALITY, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryLinkSpeed, + nicOidCmdTimeoutCommon, + 0, + NULL, + pvQueryBuffer, + u4QueryBufferLen + ); + } +} /* end of wlanoidQueryLinkSpeed() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query MCR value. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryMcrRead ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + P_PARAM_CUSTOM_MCR_RW_STRUC_T prMcrRdInfo; + CMD_ACCESS_REG rCmdAccessReg; + + DEBUGFUNC("wlanoidQueryMcrRead"); + DBGLOG(INIT, LOUD,("\n")); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_MCR_RW_STRUC_T); + + if (u4QueryBufferLen < sizeof(PARAM_CUSTOM_MCR_RW_STRUC_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + prMcrRdInfo = (P_PARAM_CUSTOM_MCR_RW_STRUC_T)pvQueryBuffer; + + /* 0x9000 - 0x9EFF reserved for FW */ +#if CFG_SUPPORT_SWCR + if((prMcrRdInfo->u4McrOffset >>16) == 0x9F00) { + swCrReadWriteCmd(prAdapter, + SWCR_READ, + (UINT_16) (prMcrRdInfo->u4McrOffset & BITS(0,15)), + &prMcrRdInfo->u4McrData); + return WLAN_STATUS_SUCCESS; + } +#endif /* CFG_SUPPORT_SWCR */ + + /* Check if access F/W Domain MCR (due to WiFiSYS is placed from 0x6000-0000*/ + if (prMcrRdInfo->u4McrOffset & 0xFFFF0000){ + // fill command + rCmdAccessReg.u4Address = prMcrRdInfo->u4McrOffset; + rCmdAccessReg.u4Data = 0; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_ACCESS_REG, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryMcrRead, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), + (PUINT_8)&rCmdAccessReg, + pvQueryBuffer, + u4QueryBufferLen + ); + } + else { + HAL_MCR_RD(prAdapter, + prMcrRdInfo->u4McrOffset & BITS(2,31), //address is in DWORD unit + &prMcrRdInfo->u4McrData); + + DBGLOG(INIT, TRACE, ("MCR Read: Offset = %#08lx, Data = %#08lx\n", + prMcrRdInfo->u4McrOffset, prMcrRdInfo->u4McrData)); + return WLAN_STATUS_SUCCESS; + } +} /* end of wlanoidQueryMcrRead() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to write MCR and enable specific function. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetMcrWrite ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_PARAM_CUSTOM_MCR_RW_STRUC_T prMcrWrInfo; + CMD_ACCESS_REG rCmdAccessReg; + +#if CFG_STRESS_TEST_SUPPORT + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prBssInfo = &(prAdapter->rWifiVar.arBssInfo[(NETWORK_TYPE_AIS_INDEX)]); + P_STA_RECORD_T prStaRec = prBssInfo->prStaRecOfAP; + UINT_32 u4McrOffset, u4McrData; +#endif + + DEBUGFUNC("wlanoidSetMcrWrite"); + DBGLOG(INIT, LOUD,("\n")); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_MCR_RW_STRUC_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_MCR_RW_STRUC_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prMcrWrInfo = (P_PARAM_CUSTOM_MCR_RW_STRUC_T)pvSetBuffer; + + /* 0x9000 - 0x9EFF reserved for FW */ + /* 0xFFFE reserved for FW */ + + // -- Puff Stress Test Begin +#if CFG_STRESS_TEST_SUPPORT + + // 0xFFFFFFFE for Control Rate + if (prMcrWrInfo->u4McrOffset == 0xFFFFFFFE){ + if(prMcrWrInfo->u4McrData < FIXED_RATE_NUM && prMcrWrInfo->u4McrData > 0){ + prAdapter->rWifiVar.eRateSetting = (ENUM_REGISTRY_FIXED_RATE_T)(prMcrWrInfo->u4McrData); + } + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + DEBUGFUNC("[Stress Test]Complete Rate is Changed...\n"); + DBGLOG(INIT, TRACE, ("[Stress Test] Rate is Changed to index %d...\n", prAdapter->rWifiVar.eRateSetting)); + } + + // 0xFFFFFFFD for Switch Channel + else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFFD){ + if(prMcrWrInfo->u4McrData <= 11 && prMcrWrInfo->u4McrData >= 1){ + prBssInfo->ucPrimaryChannel = prMcrWrInfo->u4McrData; + } + nicUpdateBss(prAdapter, prBssInfo->ucNetTypeIndex); + DBGLOG(INIT, TRACE, ("[Stress Test] Channel is switched to %d ...\n", prBssInfo->ucPrimaryChannel)); + + return WLAN_STATUS_SUCCESS; + } + + // 0xFFFFFFFFC for Control RF Band and SCO + else if(prMcrWrInfo->u4McrOffset == 0xFFFFFFFC){ + // Band + if(prMcrWrInfo->u4McrData & 0x80000000){ + //prBssInfo->eBand = BAND_5G; + //prBssInfo->ucPrimaryChannel = 52; // Bond to Channel 52 + } else { + prBssInfo->eBand = BAND_2G4; + prBssInfo->ucPrimaryChannel = 8; // Bond to Channel 6 + } + + // Bandwidth + if(prMcrWrInfo->u4McrData & 0x00010000){ + prStaRec->u2HtCapInfo |= HT_CAP_INFO_SUP_CHNL_WIDTH; + prStaRec->ucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + + if(prMcrWrInfo->u4McrData == 0x00010002){ + prBssInfo->eBssSCO = CHNL_EXT_SCB; // U20 + prBssInfo->ucPrimaryChannel += 2; + } else if (prMcrWrInfo->u4McrData == 0x00010001){ + prBssInfo->eBssSCO = CHNL_EXT_SCA; // L20 + prBssInfo->ucPrimaryChannel -= 2; + } else { + prBssInfo->eBssSCO = CHNL_EXT_SCA; // 40 + } + } + + if(prMcrWrInfo->u4McrData & 0x00000000){ + prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_SUP_CHNL_WIDTH; + prBssInfo->eBssSCO = CHNL_EXT_SCN; + } + rlmBssInitForAPandIbss(prAdapter, prBssInfo); + } + + // 0xFFFFFFFB for HT Capability + else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFFB){ + /* Enable HT Capability */ + if(prMcrWrInfo->u4McrData & 0x00000001){ + prStaRec->u2HtCapInfo |= HT_CAP_INFO_HT_GF; + DEBUGFUNC("[Stress Test]Enable HT capability...\n"); + }else{ + prStaRec->u2HtCapInfo &= (~HT_CAP_INFO_HT_GF); + DEBUGFUNC("[Stress Test]Disable HT capability...\n"); + } + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + } + + // 0xFFFFFFFA for Enable Random Rx Reset + else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFFA){ + rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; + rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; + + return wlanSendSetQueryCmd( + prAdapter, + CMD_ID_RANDOM_RX_RESET_EN, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), + (PUINT_8)&rCmdAccessReg, + pvSetBuffer, + u4SetBufferLen + ); + } + + // 0xFFFFFFF9 for Disable Random Rx Reset + else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFF9){ + rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; + rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; + + return wlanSendSetQueryCmd( + prAdapter, + CMD_ID_RANDOM_RX_RESET_DE, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), + (PUINT_8)&rCmdAccessReg, + pvSetBuffer, + u4SetBufferLen + ); + } + + // 0xFFFFFFF8 for Enable SAPP + else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFF8){ + rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; + rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; + + return wlanSendSetQueryCmd( + prAdapter, + CMD_ID_SAPP_EN, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), + (PUINT_8)&rCmdAccessReg, + pvSetBuffer, + u4SetBufferLen + ); + } + + // 0xFFFFFFF7 for Disable SAPP + else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFF7){ + rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; + rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; + + return wlanSendSetQueryCmd( + prAdapter, + CMD_ID_SAPP_DE, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), + (PUINT_8)&rCmdAccessReg, + pvSetBuffer, + u4SetBufferLen + ); + } + + else +#endif + // -- Puff Stress Test End + + + /* Check if access F/W Domain MCR */ + if (prMcrWrInfo->u4McrOffset & 0xFFFF0000){ + + /* 0x9000 - 0x9EFF reserved for FW */ +#if CFG_SUPPORT_SWCR + if((prMcrWrInfo->u4McrOffset >> 16) == 0x9F00) { + swCrReadWriteCmd(prAdapter, + SWCR_WRITE, + (UINT_16) (prMcrWrInfo->u4McrOffset & BITS(0,15)), + &prMcrWrInfo->u4McrData); + return WLAN_STATUS_SUCCESS; + } +#endif /* CFG_SUPPORT_SWCR */ + + + #if 1 + // low power test special command + if (prMcrWrInfo->u4McrOffset == 0x11111110){ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + //DbgPrint("Enter test mode\n"); + prAdapter->fgTestMode = TRUE; + return rStatus; + } + if (prMcrWrInfo->u4McrOffset == 0x11111111){ + //DbgPrint("nicpmSetAcpiPowerD3\n"); + + nicpmSetAcpiPowerD3(prAdapter); + kalDevSetPowerState(prAdapter->prGlueInfo, (UINT_32)ParamDeviceStateD3); + return WLAN_STATUS_SUCCESS; + } + if (prMcrWrInfo->u4McrOffset == 0x11111112){ + + //DbgPrint("LP enter sleep\n"); + + // fill command + rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; + rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_ACCESS_REG, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), + (PUINT_8)&rCmdAccessReg, + pvSetBuffer, + u4SetBufferLen + ); + } +#endif + + #if 1 + // low power test special command + if (prMcrWrInfo->u4McrOffset == 0x11111110){ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + //DbgPrint("Enter test mode\n"); + prAdapter->fgTestMode = TRUE; + return rStatus; + } + if (prMcrWrInfo->u4McrOffset == 0x11111111){ + //DbgPrint("nicpmSetAcpiPowerD3\n"); + + nicpmSetAcpiPowerD3(prAdapter); + kalDevSetPowerState(prAdapter->prGlueInfo, (UINT_32)ParamDeviceStateD3); + return WLAN_STATUS_SUCCESS; + } + if (prMcrWrInfo->u4McrOffset == 0x11111112){ + + //DbgPrint("LP enter sleep\n"); + + // fill command + rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; + rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_ACCESS_REG, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), + (PUINT_8)&rCmdAccessReg, + pvSetBuffer, + u4SetBufferLen + ); + } + +#endif + // fill command + rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; + rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_ACCESS_REG, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), + (PUINT_8)&rCmdAccessReg, + pvSetBuffer, + u4SetBufferLen + ); + } + else { + HAL_MCR_WR(prAdapter, + (prMcrWrInfo->u4McrOffset & BITS(2,31)), //address is in DWORD unit + prMcrWrInfo->u4McrData); + + DBGLOG(INIT, TRACE, ("MCR Write: Offset = %#08lx, Data = %#08lx\n", + prMcrWrInfo->u4McrOffset, prMcrWrInfo->u4McrData)); + + return WLAN_STATUS_SUCCESS; + } +} /* wlanoidSetMcrWrite */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query SW CTRL +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQuerySwCtrlRead ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + P_PARAM_CUSTOM_SW_CTRL_STRUC_T prSwCtrlInfo; + WLAN_STATUS rWlanStatus; + UINT_16 u2Id, u2SubId; + UINT_32 u4Data; + + CMD_SW_DBG_CTRL_T rCmdSwCtrl; + + DEBUGFUNC("wlanoidQuerySwCtrlRead"); + DBGLOG(INIT, LOUD,("\n")); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_SW_CTRL_STRUC_T); + + if (u4QueryBufferLen < sizeof(PARAM_CUSTOM_SW_CTRL_STRUC_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + prSwCtrlInfo = (P_PARAM_CUSTOM_SW_CTRL_STRUC_T)pvQueryBuffer; + + u2Id = (UINT_16)(prSwCtrlInfo->u4Id >> 16); + u2SubId = (UINT_16)(prSwCtrlInfo->u4Id & BITS(0,15)); + u4Data = 0; + rWlanStatus = WLAN_STATUS_SUCCESS; + + switch(u2Id) { + /* 0x9000 - 0x9EFF reserved for FW */ + /* 0xFFFE reserved for FW */ + +#if CFG_SUPPORT_SWCR + case 0x9F00: + swCrReadWriteCmd(prAdapter, + SWCR_READ/* Read */, + (UINT_16) u2SubId , + &u4Data); + break; +#endif /* CFG_SUPPORT_SWCR */ + + case 0xFFFF: + { + u4Data = 0x5AA56620; + } + break; + + case 0x9000: + default: + { + rCmdSwCtrl.u4Id = prSwCtrlInfo->u4Id; + rCmdSwCtrl.u4Data = 0; + rWlanStatus = wlanSendSetQueryCmd(prAdapter, + CMD_ID_SW_DBG_CTRL, + FALSE, + TRUE, + TRUE, + nicCmdEventQuerySwCtrlRead, + nicOidCmdTimeoutCommon, + sizeof(CMD_SW_DBG_CTRL_T), + (PUINT_8)&rCmdSwCtrl, + pvQueryBuffer, + u4QueryBufferLen + ); + } + } /* switch(u2Id)*/ + + prSwCtrlInfo->u4Data = u4Data; + + return rWlanStatus; + +} + /* end of wlanoidQuerySwCtrlRead() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to write SW CTRL +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetSwCtrlWrite ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_PARAM_CUSTOM_SW_CTRL_STRUC_T prSwCtrlInfo; + CMD_SW_DBG_CTRL_T rCmdSwCtrl; + WLAN_STATUS rWlanStatus; + UINT_16 u2Id, u2SubId; + UINT_32 u4Data; + + DEBUGFUNC("wlanoidSetSwCtrlWrite"); + DBGLOG(INIT, LOUD,("\n")); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_SW_CTRL_STRUC_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_SW_CTRL_STRUC_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prSwCtrlInfo = (P_PARAM_CUSTOM_SW_CTRL_STRUC_T)pvSetBuffer; + + u2Id = (UINT_16)(prSwCtrlInfo->u4Id >> 16); + u2SubId = (UINT_16)(prSwCtrlInfo->u4Id & BITS(0,15)); + u4Data = prSwCtrlInfo->u4Data; + rWlanStatus = WLAN_STATUS_SUCCESS; + + switch(u2Id) { + + /* 0x9000 - 0x9EFF reserved for FW */ + /* 0xFFFE reserved for FW */ + +#if CFG_SUPPORT_SWCR + case 0x9F00: + swCrReadWriteCmd(prAdapter, + SWCR_WRITE, + (UINT_16) u2SubId, + &u4Data); + break; +#endif /* CFG_SUPPORT_SWCR */ + + case 0x1000: + if (u2SubId == 0x8000) { + // CTIA power save mode setting (code: 0x10008000) + prAdapter->u4CtiaPowerMode = u4Data; + prAdapter->fgEnCtiaPowerMode = TRUE; + + // + { + PARAM_POWER_MODE ePowerMode; + + if (prAdapter->u4CtiaPowerMode == 0) { + // force to keep in CAM mode + ePowerMode = Param_PowerModeCAM; + } else if (prAdapter->u4CtiaPowerMode == 1) { + ePowerMode = Param_PowerModeMAX_PSP; + } else { + ePowerMode = Param_PowerModeFast_PSP; + } + + nicConfigPowerSaveProfile( + prAdapter, + NETWORK_TYPE_AIS_INDEX, + ePowerMode, + TRUE); + } + } + break; + case 0x1001: + if(u2SubId == 0x0) { + prAdapter->fgEnOnlineScan = (BOOLEAN)u4Data; + } + else if(u2SubId == 0x1) { + prAdapter->fgDisBcnLostDetection = (BOOLEAN)u4Data; + } + else if(u2SubId == 0x2) { + prAdapter->rWifiVar.fgSupportUAPSD = (BOOLEAN)u4Data; + } + else if(u2SubId == 0x3) { + prAdapter->u4UapsdAcBmp = u4Data & BITS(0,15); + prAdapter->rWifiVar.arBssInfo[u4Data>>16].rPmProfSetupInfo.ucBmpDeliveryAC = (UINT_8)prAdapter->u4UapsdAcBmp; + prAdapter->rWifiVar.arBssInfo[u4Data>>16].rPmProfSetupInfo.ucBmpTriggerAC = (UINT_8)prAdapter->u4UapsdAcBmp; + } + break; + +#if CFG_SUPPORT_SWCR + case 0x1002: + if(u2SubId == 0x0) { + if (u4Data) { + u4Data = BIT(HIF_RX_PKT_TYPE_MANAGEMENT); + } + swCrFrameCheckEnable(prAdapter, u4Data); + } + else if(u2SubId == 0x1) { + BOOLEAN fgIsEnable; + UINT_8 ucType; + UINT_32 u4Timeout; + + fgIsEnable = (BOOLEAN)(u4Data & 0xff); + ucType = 0;//((u4Data>>4) & 0xf); + u4Timeout = ((u4Data>>8) & 0xff); + swCrDebugCheckEnable(prAdapter, fgIsEnable, ucType, u4Timeout); + } + break; +#endif + +#if CFG_SUPPORT_802_11W + case 0x2000: + DBGLOG(RSN, TRACE, ("802.11w test 0x%x\n", u2SubId)); + if (u2SubId == 0x0) { + rsnStartSaQuery(prAdapter); + } + if (u2SubId == 0x1) { + rsnStopSaQuery(prAdapter); + } + if (u2SubId == 0x2) { + rsnSaQueryRequest(prAdapter, NULL); + } + if (u2SubId == 0x3) { + P_BSS_INFO_T prBssInfo = &(prAdapter->rWifiVar.arBssInfo[(NETWORK_TYPE_AIS_INDEX)]); + authSendDeauthFrame(prAdapter, prBssInfo->prStaRecOfAP , NULL, 7, NULL); + } + /* wext_set_mode */ + /* + if (u2SubId == 0x3) { + prAdapter->prGlueInfo->rWpaInfo.u4Mfp = RSN_AUTH_MFP_DISABLED; + } + if (u2SubId == 0x4) { + //prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = TRUE; + prAdapter->prGlueInfo->rWpaInfo.u4Mfp = RSN_AUTH_MFP_OPTIONAL; + } + if (u2SubId == 0x5) { + //prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = TRUE; + prAdapter->prGlueInfo->rWpaInfo.u4Mfp = RSN_AUTH_MFP_REQUIRED; + } + */ + break; +#endif + case 0xFFFF: + { + CMD_ACCESS_REG rCmdAccessReg; +#if 1 //CFG_MT6573_SMT_TEST + if (u2SubId == 0x0123) { + + DBGLOG(HAL, INFO, ("set smt fixed rate: %d \n", u4Data)); + + if((ENUM_REGISTRY_FIXED_RATE_T)(u4Data) < FIXED_RATE_NUM) { + prAdapter->rWifiVar.eRateSetting = (ENUM_REGISTRY_FIXED_RATE_T)(u4Data); + } + else { + prAdapter->rWifiVar.eRateSetting = FIXED_RATE_NONE; + } + + if(prAdapter->rWifiVar.eRateSetting == FIXED_RATE_NONE) { + /* Enable Auto (Long/Short) Preamble */ + prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_AUTO; + } + else if((prAdapter->rWifiVar.eRateSetting >= FIXED_RATE_MCS0_20M_400NS && + prAdapter->rWifiVar.eRateSetting <= FIXED_RATE_MCS7_20M_400NS) + || (prAdapter->rWifiVar.eRateSetting >= FIXED_RATE_MCS0_40M_400NS && + prAdapter->rWifiVar.eRateSetting <= FIXED_RATE_MCS32_400NS)) { + /* Force Short Preamble */ + prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_SHORT; + } + else { + /* Force Long Preamble */ + prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_LONG; + } + + /* abort to re-connect */ +#if 1 + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_DISCONNECT, + NULL, + 0); +#else + aisBssBeaconTimeout(prAdapter); +#endif + + return WLAN_STATUS_SUCCESS; + + } + else if (u2SubId == 0x1234) { + // 1. Disable On-Lin Scan + prAdapter->fgEnOnlineScan = FALSE; + + // 3. Disable FIFO FULL no ack + rCmdAccessReg.u4Address = 0x60140028; + rCmdAccessReg.u4Data = 0x904; + wlanSendSetQueryCmd(prAdapter, + CMD_ID_ACCESS_REG, + TRUE, //FALSE, + FALSE, //TRUE, + FALSE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), + (PUINT_8)&rCmdAccessReg, + pvSetBuffer, + 0 + ); + + // 4. Disable Roaming + rCmdSwCtrl.u4Id = 0x90000204; + rCmdSwCtrl.u4Data = 0x0; + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SW_DBG_CTRL, + TRUE, + FALSE, + FALSE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_SW_DBG_CTRL_T), + (PUINT_8)&rCmdSwCtrl, + pvSetBuffer, + u4SetBufferLen + ); + + rCmdSwCtrl.u4Id = 0x90000200; + rCmdSwCtrl.u4Data = 0x820000; + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SW_DBG_CTRL, + TRUE, + FALSE, + FALSE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_SW_DBG_CTRL_T), + (PUINT_8)&rCmdSwCtrl, + pvSetBuffer, + u4SetBufferLen + ); + + // 2. Keep at CAM mode + { + PARAM_POWER_MODE ePowerMode; + + prAdapter->u4CtiaPowerMode = 0; + prAdapter->fgEnCtiaPowerMode = TRUE; + + ePowerMode = Param_PowerModeCAM; + rWlanStatus = nicConfigPowerSaveProfile( + prAdapter, + NETWORK_TYPE_AIS_INDEX, + ePowerMode, + FALSE); + } + + // 5. Disable Beacon Timeout Detection + prAdapter->fgDisBcnLostDetection = TRUE; + } + else if (u2SubId == 0x1235) { + + // 1. Enaable On-Lin Scan + prAdapter->fgEnOnlineScan = TRUE; + + // 3. Enable FIFO FULL no ack + rCmdAccessReg.u4Address = 0x60140028; + rCmdAccessReg.u4Data = 0x905; + wlanSendSetQueryCmd(prAdapter, + CMD_ID_ACCESS_REG, + TRUE, //FALSE, + FALSE, //TRUE, + FALSE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), + (PUINT_8)&rCmdAccessReg, + pvSetBuffer, + 0 + ); + + // 4. Enable Roaming + rCmdSwCtrl.u4Id = 0x90000204; + rCmdSwCtrl.u4Data = 0x1; + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SW_DBG_CTRL, + TRUE, + FALSE, + FALSE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_SW_DBG_CTRL_T), + (PUINT_8)&rCmdSwCtrl, + pvSetBuffer, + u4SetBufferLen + ); + + rCmdSwCtrl.u4Id = 0x90000200; + rCmdSwCtrl.u4Data = 0x820000; + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SW_DBG_CTRL, + TRUE, + FALSE, + FALSE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_SW_DBG_CTRL_T), + (PUINT_8)&rCmdSwCtrl, + pvSetBuffer, + u4SetBufferLen + ); + + // 2. Keep at Fast PS + { + PARAM_POWER_MODE ePowerMode; + + prAdapter->u4CtiaPowerMode = 2; + prAdapter->fgEnCtiaPowerMode = TRUE; + + ePowerMode = Param_PowerModeFast_PSP; + rWlanStatus = nicConfigPowerSaveProfile( + prAdapter, + NETWORK_TYPE_AIS_INDEX, + ePowerMode, + FALSE); + } + + // 5. Enable Beacon Timeout Detection + prAdapter->fgDisBcnLostDetection = FALSE; + } +#endif + } + break; + + case 0x9000: + default: + { + rCmdSwCtrl.u4Id = prSwCtrlInfo->u4Id; + rCmdSwCtrl.u4Data = prSwCtrlInfo->u4Data; + rWlanStatus = wlanSendSetQueryCmd(prAdapter, + CMD_ID_SW_DBG_CTRL, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_SW_DBG_CTRL_T), + (PUINT_8)&rCmdSwCtrl, + pvSetBuffer, + u4SetBufferLen + ); + } + } /* switch(u2Id) */ + + return rWlanStatus; +} + /* wlanoidSetSwCtrlWrite */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query EEPROM value. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryEepromRead ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + P_PARAM_CUSTOM_EEPROM_RW_STRUC_T prEepromRwInfo; + CMD_ACCESS_EEPROM rCmdAccessEeprom; + + DEBUGFUNC("wlanoidQueryEepromRead"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_EEPROM_RW_STRUC_T); + + if (u4QueryBufferLen < sizeof(PARAM_CUSTOM_EEPROM_RW_STRUC_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + prEepromRwInfo = (P_PARAM_CUSTOM_EEPROM_RW_STRUC_T)pvQueryBuffer; + + kalMemZero(&rCmdAccessEeprom, sizeof(CMD_ACCESS_EEPROM)); + rCmdAccessEeprom.u2Offset = prEepromRwInfo->ucEepromIndex; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_ACCESS_EEPROM, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryEepromRead, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_EEPROM), + (PUINT_8)&rCmdAccessEeprom, + pvQueryBuffer, + u4QueryBufferLen + ); + +} /* wlanoidQueryEepromRead */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to write EEPROM value. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetEepromWrite ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_PARAM_CUSTOM_EEPROM_RW_STRUC_T prEepromRwInfo; + CMD_ACCESS_EEPROM rCmdAccessEeprom; + + DEBUGFUNC("wlanoidSetEepromWrite"); + DBGLOG(INIT, LOUD,("\n")); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_EEPROM_RW_STRUC_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_EEPROM_RW_STRUC_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prEepromRwInfo = (P_PARAM_CUSTOM_EEPROM_RW_STRUC_T)pvSetBuffer; + + kalMemZero(&rCmdAccessEeprom, sizeof(CMD_ACCESS_EEPROM)); + rCmdAccessEeprom.u2Offset = prEepromRwInfo->ucEepromIndex; + rCmdAccessEeprom.u2Data = prEepromRwInfo->u2EepromData; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_ACCESS_EEPROM, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_EEPROM), + (PUINT_8)&rCmdAccessEeprom, + pvSetBuffer, + u4SetBufferLen + ); + +} /* wlanoidSetEepromWrite */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the number of the successfully transmitted +* packets. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryXmitOk ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryXmitOk"); + DBGLOG(REQ, LOUD, ("\n")); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + else if (u4QueryBufferLen < sizeof(UINT_32) + || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { + *pu4QueryInfoLen = sizeof(UINT_64); + return WLAN_STATUS_INVALID_LENGTH; + } + +#if CFG_ENABLE_STATISTICS_BUFFERING + if(IsBufferedStatisticsUsable(prAdapter) == TRUE) { + if(u4QueryBufferLen == sizeof(UINT_32)) { + *pu4QueryInfoLen = sizeof(UINT_32); + *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rStatStruct.rTransmittedFragmentCount.QuadPart; + } + else { + *pu4QueryInfoLen = sizeof(UINT_64); + *(PUINT_64) pvQueryBuffer = (UINT_64) prAdapter->rStatStruct.rTransmittedFragmentCount.QuadPart; + } + + return WLAN_STATUS_SUCCESS; + } + else +#endif + { + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_STATISTICS, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryXmitOk, + nicOidCmdTimeoutCommon, + 0, + NULL, + pvQueryBuffer, + u4QueryBufferLen + ); + } +} /* wlanoidQueryXmitOk */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the number of the successfully received +* packets. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryRcvOk ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryRcvOk"); + DBGLOG(REQ, LOUD, ("\n")); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + else if (u4QueryBufferLen < sizeof(UINT_32) + || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { + *pu4QueryInfoLen = sizeof(UINT_64); + return WLAN_STATUS_INVALID_LENGTH; + } + +#if CFG_ENABLE_STATISTICS_BUFFERING + if(IsBufferedStatisticsUsable(prAdapter) == TRUE) { + if(u4QueryBufferLen == sizeof(UINT_32)) { + *pu4QueryInfoLen = sizeof(UINT_32); + *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rStatStruct.rReceivedFragmentCount.QuadPart; + } + else { + *pu4QueryInfoLen = sizeof(UINT_64); + *(PUINT_64) pvQueryBuffer = (UINT_64) prAdapter->rStatStruct.rReceivedFragmentCount.QuadPart; + } + + return WLAN_STATUS_SUCCESS; + } + else +#endif + { + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_STATISTICS, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryRecvOk, + nicOidCmdTimeoutCommon, + 0, + NULL, + pvQueryBuffer, + u4QueryBufferLen + ); + } +} /* wlanoidQueryRcvOk */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the number of frames that the driver +* fails to transmit. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryXmitError ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryXmitError"); + DBGLOG(REQ, LOUD, ("\n")); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + else if (u4QueryBufferLen < sizeof(UINT_32) + || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { + *pu4QueryInfoLen = sizeof(UINT_64); + return WLAN_STATUS_INVALID_LENGTH; + } + +#if CFG_ENABLE_STATISTICS_BUFFERING + if(IsBufferedStatisticsUsable(prAdapter) == TRUE) { + if(u4QueryBufferLen == sizeof(UINT_32)) { + *pu4QueryInfoLen = sizeof(UINT_32); + *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rStatStruct.rFailedCount.QuadPart; + } + else { + *pu4QueryInfoLen = sizeof(UINT_64); + *(PUINT_64) pvQueryBuffer = (UINT_64) prAdapter->rStatStruct.rFailedCount.QuadPart; + } + + return WLAN_STATUS_SUCCESS; + } + else +#endif + { + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_STATISTICS, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryXmitError, + nicOidCmdTimeoutCommon, + 0, + NULL, + pvQueryBuffer, + u4QueryBufferLen + ); + } +} /* wlanoidQueryXmitError */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the number of frames successfully +* transmitted after exactly one collision. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryXmitOneCollision ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryXmitOneCollision"); + DBGLOG(REQ, LOUD, ("\n")); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + else if (u4QueryBufferLen < sizeof(UINT_32) + || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { + *pu4QueryInfoLen = sizeof(UINT_64); + return WLAN_STATUS_INVALID_LENGTH; + } + +#if CFG_ENABLE_STATISTICS_BUFFERING + if(IsBufferedStatisticsUsable(prAdapter) == TRUE) { + if(u4QueryBufferLen == sizeof(UINT_32)) { + *pu4QueryInfoLen = sizeof(UINT_32); + *(PUINT_32) pvQueryBuffer = (UINT_32) + (prAdapter->rStatStruct.rMultipleRetryCount.QuadPart - prAdapter->rStatStruct.rRetryCount.QuadPart); + } + else { + *pu4QueryInfoLen = sizeof(UINT_64); + *(PUINT_64) pvQueryBuffer = (UINT_64) + (prAdapter->rStatStruct.rMultipleRetryCount.QuadPart - prAdapter->rStatStruct.rRetryCount.QuadPart); + } + + return WLAN_STATUS_SUCCESS; + } + else +#endif + { + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_STATISTICS, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryXmitOneCollision, + nicOidCmdTimeoutCommon, + 0, + NULL, + pvQueryBuffer, + u4QueryBufferLen + ); + } +} /* wlanoidQueryXmitOneCollision */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the number of frames successfully +* transmitted after more than one collision. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryXmitMoreCollisions ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryXmitMoreCollisions"); + DBGLOG(REQ, LOUD, ("\n")); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + else if (u4QueryBufferLen < sizeof(UINT_32) + || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { + *pu4QueryInfoLen = sizeof(UINT_64); + return WLAN_STATUS_INVALID_LENGTH; + } + +#if CFG_ENABLE_STATISTICS_BUFFERING + if(IsBufferedStatisticsUsable(prAdapter) == TRUE) { + if(u4QueryBufferLen == sizeof(UINT_32)) { + *pu4QueryInfoLen = sizeof(UINT_32); + *(PUINT_32) pvQueryBuffer = (UINT_32) (prAdapter->rStatStruct.rMultipleRetryCount.QuadPart); + } + else { + *pu4QueryInfoLen = sizeof(UINT_64); + *(PUINT_64) pvQueryBuffer = (UINT_64) (prAdapter->rStatStruct.rMultipleRetryCount.QuadPart); + } + + return WLAN_STATUS_SUCCESS; + } + else +#endif + { + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_STATISTICS, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryXmitMoreCollisions, + nicOidCmdTimeoutCommon, + 0, + NULL, + pvQueryBuffer, + u4QueryBufferLen + ); + } +} /* wlanoidQueryXmitMoreCollisions */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the number of frames +* not transmitted due to excessive collisions. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryXmitMaxCollisions ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryXmitMaxCollisions"); + DBGLOG(REQ, LOUD, ("\n")); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + else if (u4QueryBufferLen < sizeof(UINT_32) + || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { + *pu4QueryInfoLen = sizeof(UINT_64); + return WLAN_STATUS_INVALID_LENGTH; + } + +#if CFG_ENABLE_STATISTICS_BUFFERING + if(IsBufferedStatisticsUsable(prAdapter) == TRUE) { + if(u4QueryBufferLen == sizeof(UINT_32)) { + *pu4QueryInfoLen = sizeof(UINT_32); + *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rStatStruct.rFailedCount.QuadPart; + } + else { + *pu4QueryInfoLen = sizeof(UINT_64); + *(PUINT_64) pvQueryBuffer = (UINT_64) prAdapter->rStatStruct.rFailedCount.QuadPart; + } + + return WLAN_STATUS_SUCCESS; + } + else +#endif + { + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_STATISTICS, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryXmitMaxCollisions, + nicOidCmdTimeoutCommon, + 0, + NULL, + pvQueryBuffer, + u4QueryBufferLen + ); + } +} /* wlanoidQueryXmitMaxCollisions */ + + +#define MTK_CUSTOM_OID_INTERFACE_VERSION 0x00006620 // for WPDWifi DLL +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query current the OID interface version, +* which is the interface between the application and driver. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryOidInterfaceVersion ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryOidInterfaceVersion"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + *(PUINT_32) pvQueryBuffer = MTK_CUSTOM_OID_INTERFACE_VERSION ; + *pu4QueryInfoLen = sizeof(UINT_32); + + DBGLOG(REQ, WARN, ("Custom OID interface version: %#08lX\n", + *(PUINT_32) pvQueryBuffer)); + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryOidInterfaceVersion */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query current Multicast Address List. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryMulticastList( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ +#ifndef LINUX + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_MAC_MCAST_ADDR, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryMcastAddr, + nicOidCmdTimeoutCommon, + 0, + NULL, + pvQueryBuffer, + u4QueryBufferLen + ); +#else + return WLAN_STATUS_SUCCESS; +#endif +} /* end of wlanoidQueryMulticastList() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set Multicast Address List. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_MULTICAST_FULL +*/ +/*----------------------------------------------------------------------------*/ + WLAN_STATUS + wlanoidSetMulticastList( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) + { + UINT_8 ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; /* Caller should provide this information */ + CMD_MAC_MCAST_ADDR rCmdMacMcastAddr; + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + /* The data must be a multiple of the Ethernet address size. */ + if ((u4SetBufferLen % MAC_ADDR_LEN)) { + DBGLOG(REQ, WARN, ("Invalid MC list length %ld\n", u4SetBufferLen)); + + *pu4SetInfoLen = (((u4SetBufferLen + MAC_ADDR_LEN) - 1) / + MAC_ADDR_LEN) * MAC_ADDR_LEN; + + return WLAN_STATUS_INVALID_LENGTH; + } + + *pu4SetInfoLen = u4SetBufferLen; + + /* Verify if we can support so many multicast addresses. */ + if ((u4SetBufferLen / MAC_ADDR_LEN) > MAX_NUM_GROUP_ADDR) { + DBGLOG(REQ, WARN, ("Too many MC addresses\n")); + + return WLAN_STATUS_MULTICAST_FULL; + } + + /* NOTE(Kevin): Windows may set u4SetBufferLen == 0 && + * pvSetBuffer == NULL to clear exist Multicast List. + */ + if (u4SetBufferLen) { + ASSERT(pvSetBuffer); + } + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in set multicast list! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + rCmdMacMcastAddr.u4NumOfGroupAddr = u4SetBufferLen / MAC_ADDR_LEN; + rCmdMacMcastAddr.ucNetTypeIndex = ucNetTypeIndex; + kalMemCopy(rCmdMacMcastAddr.arAddress, pvSetBuffer, u4SetBufferLen); + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_MAC_MCAST_ADDR, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_MAC_MCAST_ADDR), + (PUINT_8)&rCmdMacMcastAddr, + pvSetBuffer, + u4SetBufferLen + ); +} /* end of wlanoidSetMulticastList() */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set Packet Filter. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_NOT_SUPPORTED +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetCurrentPacketFilter ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + UINT_32 u4NewPacketFilter; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidSetCurrentPacketFilter"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen < sizeof(UINT_32)) { + *pu4SetInfoLen = sizeof(UINT_32); + return WLAN_STATUS_INVALID_LENGTH; + } + ASSERT(pvSetBuffer); + + /* Set the new packet filter. */ + u4NewPacketFilter = *(PUINT_32) pvSetBuffer; + + DBGLOG(REQ, INFO, ("New packet filter: %#08lx\n", u4NewPacketFilter)); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in set current packet filter! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + do { + /* Verify the bits of the new packet filter. If any bits are set that + we don't support, leave. */ + if (u4NewPacketFilter & ~(PARAM_PACKET_FILTER_SUPPORTED)) { + rStatus = WLAN_STATUS_NOT_SUPPORTED; + break; + } + +#if DBG + /* Need to enable or disable promiscuous support depending on the new + filter. */ + if (u4NewPacketFilter & PARAM_PACKET_FILTER_PROMISCUOUS) { + DBGLOG(REQ, INFO, ("Enable promiscuous mode\n")); + } + else { + DBGLOG(REQ, INFO, ("Disable promiscuous mode\n")); + } + + if (u4NewPacketFilter & PARAM_PACKET_FILTER_ALL_MULTICAST) { + DBGLOG(REQ, INFO, ("Enable all-multicast mode\n")); + } + else if (u4NewPacketFilter & PARAM_PACKET_FILTER_MULTICAST) { + DBGLOG(REQ, INFO, ("Enable multicast\n")); + } + else { + DBGLOG(REQ, INFO, ("Disable multicast\n")); + } + + if (u4NewPacketFilter & PARAM_PACKET_FILTER_BROADCAST) { + DBGLOG(REQ, INFO, ("Enable Broadcast\n")); + } + else { + DBGLOG(REQ, INFO, ("Disable Broadcast\n")); + } +#endif + } while (FALSE); + + if(rStatus == WLAN_STATUS_SUCCESS) { + // Store the packet filter + + prAdapter->u4OsPacketFilter &= PARAM_PACKET_FILTER_P2P_MASK; + prAdapter->u4OsPacketFilter |= u4NewPacketFilter; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_RX_FILTER, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(UINT_32), + (PUINT_8)&prAdapter->u4OsPacketFilter, + pvSetBuffer, + u4SetBufferLen + ); + } + else { + return rStatus; + } +} /* wlanoidSetCurrentPacketFilter */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query current packet filter. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryCurrentPacketFilter ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryCurrentPacketFilter"); + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(UINT_32); + + if (u4QueryBufferLen >= sizeof(UINT_32)) { + ASSERT(pvQueryBuffer); + *(PUINT_32) pvQueryBuffer = prAdapter->u4OsPacketFilter; + } + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryCurrentPacketFilter */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query ACPI device power state. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryAcpiDevicePowerState ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ +#if DBG + PPARAM_DEVICE_POWER_STATE prPowerState; +#endif + + DEBUGFUNC("wlanoidQueryAcpiDevicePowerState"); + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(PARAM_DEVICE_POWER_STATE); + +#if DBG + prPowerState = (PPARAM_DEVICE_POWER_STATE) pvQueryBuffer; + switch (*prPowerState) { + case ParamDeviceStateD0: + DBGLOG(REQ, INFO, ("Query Power State: D0\n")); + break; + case ParamDeviceStateD1: + DBGLOG(REQ, INFO, ("Query Power State: D1\n")); + break; + case ParamDeviceStateD2: + DBGLOG(REQ, INFO, ("Query Power State: D2\n")); + break; + case ParamDeviceStateD3: + DBGLOG(REQ, INFO, ("Query Power State: D3\n")); + break; + default: + break; + } +#endif + + /* Since we will disconnect the newwork, therefore we do not + need to check queue empty */ + *(PPARAM_DEVICE_POWER_STATE) pvQueryBuffer = ParamDeviceStateD3; + //WARNLOG(("Ready to transition to D3\n")); + return WLAN_STATUS_SUCCESS; + +} /* pwrmgtQueryPower */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set ACPI device power state. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetAcpiDevicePowerState ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + PPARAM_DEVICE_POWER_STATE prPowerState; + BOOLEAN fgRetValue = TRUE; + + DEBUGFUNC("wlanoidSetAcpiDevicePowerState"); + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_DEVICE_POWER_STATE); + + ASSERT(pvSetBuffer); + prPowerState = (PPARAM_DEVICE_POWER_STATE) pvSetBuffer; + switch (*prPowerState) { + case ParamDeviceStateD0: + DBGLOG(REQ, INFO, ("Set Power State: D0\n")); + kalDevSetPowerState(prAdapter->prGlueInfo, (UINT_32)ParamDeviceStateD0); + fgRetValue = nicpmSetAcpiPowerD0(prAdapter); + break; + case ParamDeviceStateD1: + DBGLOG(REQ, INFO, ("Set Power State: D1\n")); + /* no break here */ + case ParamDeviceStateD2: + DBGLOG(REQ, INFO, ("Set Power State: D2\n")); + /* no break here */ + case ParamDeviceStateD3: + DBGLOG(REQ, INFO, ("Set Power State: D3\n")); + fgRetValue = nicpmSetAcpiPowerD3(prAdapter); + kalDevSetPowerState(prAdapter->prGlueInfo, (UINT_32)ParamDeviceStateD3); + break; + default: + break; + } + + if(fgRetValue == TRUE) + return WLAN_STATUS_SUCCESS; + else + return WLAN_STATUS_FAILURE; +} /* end of wlanoidSetAcpiDevicePowerState() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the current fragmentation threshold. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryFragThreshold ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryFragThreshold"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + DBGLOG(REQ, LOUD, ("\n")); + +#if CFG_TX_FRAGMENT + + return WLAN_STATUS_SUCCESS; + +#else + + return WLAN_STATUS_NOT_SUPPORTED; +#endif /* CFG_TX_FRAGMENT */ + +} /* end of wlanoidQueryFragThreshold() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set a new fragmentation threshold to the +* driver. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetFragThreshold ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ +#if CFG_TX_FRAGMENT + + return WLAN_STATUS_SUCCESS; + +#else + + return WLAN_STATUS_NOT_SUPPORTED; +#endif /* CFG_TX_FRAGMENT */ + +} /* end of wlanoidSetFragThreshold() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the current RTS threshold. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryRtsThreshold ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryRtsThreshold"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + DBGLOG(REQ, LOUD, ("\n")); + + if (u4QueryBufferLen < sizeof(PARAM_RTS_THRESHOLD)) { + *pu4QueryInfoLen = sizeof(PARAM_RTS_THRESHOLD); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + *((PARAM_RTS_THRESHOLD *)pvQueryBuffer) = prAdapter->rWlanInfo.eRtsThreshold; + + return WLAN_STATUS_SUCCESS; + +} /* wlanoidQueryRtsThreshold */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set a new RTS threshold to the driver. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetRtsThreshold ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + PARAM_RTS_THRESHOLD *prRtsThreshold; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_RTS_THRESHOLD); + if (u4SetBufferLen < sizeof(PARAM_RTS_THRESHOLD)) { + DBGLOG(REQ, WARN, ("Invalid length %ld\n", u4SetBufferLen)); + return WLAN_STATUS_INVALID_LENGTH; + } + + prRtsThreshold = (PARAM_RTS_THRESHOLD *)pvSetBuffer; + *prRtsThreshold = prAdapter->rWlanInfo.eRtsThreshold; + + return WLAN_STATUS_SUCCESS; + +} /* wlanoidSetRtsThreshold */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to turn radio off. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetDisassociate ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_MSG_AIS_ABORT_T prAisAbortMsg; + + DEBUGFUNC("wlanoidSetDisassociate"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = 0; + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in set disassociate! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + /* prepare message to AIS */ + prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = FALSE; + + /* Send AIS Abort Message */ + prAisAbortMsg = (P_MSG_AIS_ABORT_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); + if (!prAisAbortMsg) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + + prAisAbortMsg->rMsgHdr.eMsgId = MID_OID_AIS_FSM_JOIN_REQ; + prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; + prAisAbortMsg->fgDelayIndication = FALSE; + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prAisAbortMsg, + MSG_SEND_METHOD_BUF); + + /* indicate for disconnection */ + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_DISCONNECT, + NULL, + 0); + } + +#if !defined(LINUX) + prAdapter->fgIsRadioOff = TRUE; +#endif + + return WLAN_STATUS_SUCCESS; +} /* wlanoidSetDisassociate */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to query the power save profile. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \return WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQuery802dot11PowerSaveProfile ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQuery802dot11PowerSaveProfile"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + if (u4QueryBufferLen!=0) { + ASSERT(pvQueryBuffer); + +// *(PPARAM_POWER_MODE) pvQueryBuffer = (PARAM_POWER_MODE)(prAdapter->rWlanInfo.ePowerSaveMode.ucPsProfile); + *(PPARAM_POWER_MODE) pvQueryBuffer = (PARAM_POWER_MODE)(prAdapter->rWlanInfo.arPowerSaveMode[NETWORK_TYPE_AIS_INDEX].ucPsProfile); + *pu4QueryInfoLen = sizeof(PARAM_POWER_MODE); + + // hack for CTIA power mode setting function + if (prAdapter->fgEnCtiaPowerMode) { + // set to non-zero value (to prevent MMI query 0, before it intends to set 0, which will skip its following state machine) + *(PPARAM_POWER_MODE) pvQueryBuffer = (PARAM_POWER_MODE)2; + } + } + + return WLAN_STATUS_SUCCESS; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to set the power save profile. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSet802dot11PowerSaveProfile ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + WLAN_STATUS status; + PARAM_POWER_MODE ePowerMode; + DEBUGFUNC("wlanoidSet802dot11PowerSaveProfile"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_POWER_MODE); + if (u4SetBufferLen < sizeof(PARAM_POWER_MODE)) { + DBGLOG(REQ, WARN, ("Invalid length %ld\n", u4SetBufferLen)); + return WLAN_STATUS_INVALID_LENGTH; + } + else if (*(PPARAM_POWER_MODE) pvSetBuffer >= Param_PowerModeMax) { + //WARNLOG(("Invalid power mode %d\n", + //*(PPARAM_POWER_MODE) pvSetBuffer)); + return WLAN_STATUS_INVALID_DATA; + } + + ePowerMode = *(PPARAM_POWER_MODE) pvSetBuffer; + + if (prAdapter->fgEnCtiaPowerMode) { + if (ePowerMode == Param_PowerModeCAM) { + + } else { + // User setting to PS mode (Param_PowerModeMAX_PSP or Param_PowerModeFast_PSP) + + if (prAdapter->u4CtiaPowerMode == 0) { + // force to keep in CAM mode + ePowerMode = Param_PowerModeCAM; + } else if (prAdapter->u4CtiaPowerMode == 1) { + ePowerMode = Param_PowerModeMAX_PSP; + } else if (prAdapter->u4CtiaPowerMode == 2) { + ePowerMode = Param_PowerModeFast_PSP; + } + } + } + + status = nicConfigPowerSaveProfile( + prAdapter, + NETWORK_TYPE_AIS_INDEX, + ePowerMode, + TRUE); + + switch (ePowerMode) { + case Param_PowerModeCAM: + DBGLOG(INIT, INFO, ("Set Wi-Fi PS mode to CAM (%d)\n", ePowerMode)); + break; + case Param_PowerModeMAX_PSP: + DBGLOG(INIT, INFO, ("Set Wi-Fi PS mode to MAX PS (%d)\n", ePowerMode)); + break; + case Param_PowerModeFast_PSP: + DBGLOG(INIT, INFO, ("Set Wi-Fi PS mode to FAST PS (%d)\n", ePowerMode)); + break; + default: + DBGLOG(INIT, INFO, ("invalid Wi-Fi PS mode setting (%d)\n", ePowerMode)); + break; + } + + return status; + +} /* end of wlanoidSetAcpiDevicePowerStateMode() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query current status of AdHoc Mode. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryAdHocMode ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + return WLAN_STATUS_SUCCESS; +} /* end of wlanoidQueryAdHocMode() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set AdHoc Mode. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetAdHocMode ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + return WLAN_STATUS_SUCCESS; +} /* end of wlanoidSetAdHocMode() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query RF frequency. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryFrequency ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryFrequency"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + if (u4QueryBufferLen < sizeof(UINT_32)) { + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA) { + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { + *(PUINT_32)pvQueryBuffer = + nicChannelNum2Freq(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].ucPrimaryChannel); + } + else { + *(PUINT_32)pvQueryBuffer = 0; + } + } + else { + *(PUINT_32)pvQueryBuffer = + nicChannelNum2Freq(prAdapter->rWifiVar.rConnSettings.ucAdHocChannelNum); + } + + return WLAN_STATUS_SUCCESS; +} /* end of wlanoidQueryFrequency() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set RF frequency by User Settings. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetFrequency ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + PUINT_32 pu4FreqInKHz; + + DEBUGFUNC("wlanoidSetFrequency"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(UINT_32); + + if (u4SetBufferLen < sizeof(UINT_32)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + pu4FreqInKHz = (PUINT_32)pvSetBuffer; + + prAdapter->rWifiVar.rConnSettings.ucAdHocChannelNum + = (UINT_8)nicFreq2ChannelNum(*pu4FreqInKHz); + prAdapter->rWifiVar.rConnSettings.eAdHocBand + = *pu4FreqInKHz < 5000000 ? BAND_2G4 : BAND_5G; + + return WLAN_STATUS_SUCCESS; +} /* end of wlanoidSetFrequency() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set 802.11 channel of the radio frequency. +* This is a proprietary function call to Lunux currently. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetChannel ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + ASSERT(0); //// + + return WLAN_STATUS_SUCCESS; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the Beacon Interval from User Settings. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryBeaconInterval ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryBeaconInterval"); + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(UINT_32); + + if (u4QueryBufferLen < sizeof(UINT_32)) { + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { + if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA) { + *(PUINT_32)pvQueryBuffer = + prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4BeaconPeriod; + } + else { + *(PUINT_32)pvQueryBuffer = + (UINT_32) prAdapter->rWlanInfo.u2BeaconPeriod; + } + } + else { + if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA) { + *(PUINT_32)pvQueryBuffer = 0; + } + else { + *(PUINT_32)pvQueryBuffer = + (UINT_32) prAdapter->rWlanInfo.u2BeaconPeriod; + } + } + + return WLAN_STATUS_SUCCESS; +} /* end of wlanoidQueryBeaconInterval() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set the Beacon Interval to User Settings. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetBeaconInterval ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + PUINT_32 pu4BeaconInterval; + + DEBUGFUNC("wlanoidSetBeaconInterval"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(UINT_32); + if (u4SetBufferLen < sizeof(UINT_32)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + pu4BeaconInterval = (PUINT_32)pvSetBuffer; + + if ((*pu4BeaconInterval < DOT11_BEACON_PERIOD_MIN) || + (*pu4BeaconInterval > DOT11_BEACON_PERIOD_MAX)) { + DBGLOG(REQ, TRACE, ("Invalid Beacon Interval = %ld\n", *pu4BeaconInterval)); + return WLAN_STATUS_INVALID_DATA; + } + + prAdapter->rWlanInfo.u2BeaconPeriod = (UINT_16)*pu4BeaconInterval; + + DBGLOG(REQ, INFO, ("Set beacon interval: %d\n", + prAdapter->rWlanInfo.u2BeaconPeriod)); + + + return WLAN_STATUS_SUCCESS; +} /* end of wlanoidSetBeaconInterval() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the ATIM window from User Settings. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryAtimWindow ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + DEBUGFUNC("wlanoidQueryAtimWindow"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(UINT_32); + + if (u4QueryBufferLen < sizeof(UINT_32)) { + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA) { + *(PUINT_32)pvQueryBuffer = 0; + } + else { + *(PUINT_32)pvQueryBuffer = + (UINT_32) prAdapter->rWlanInfo.u2AtimWindow; + } + + return WLAN_STATUS_SUCCESS; + +} /* end of wlanoidQueryAtimWindow() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set the ATIM window to User Settings. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetAtimWindow ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + PUINT_32 pu4AtimWindow; + + DEBUGFUNC("wlanoidSetAtimWindow"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(UINT_32); + + if (u4SetBufferLen < sizeof(UINT_32)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + pu4AtimWindow = (PUINT_32)pvSetBuffer; + + prAdapter->rWlanInfo.u2AtimWindow = (UINT_16)*pu4AtimWindow; + + return WLAN_STATUS_SUCCESS; +} /* end of wlanoidSetAtimWindow() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to Set the MAC address which is currently used by the NIC. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetCurrentAddr ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + ASSERT(0); //// + + return WLAN_STATUS_SUCCESS; +} /* end of wlanoidSetCurrentAddr() */ + + +#if CFG_TCP_IP_CHKSUM_OFFLOAD +/*----------------------------------------------------------------------------*/ +/*! +* \brief Setting the checksum offload function. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetCSUMOffload ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + UINT_32 i, u4CSUMFlags; + CMD_BASIC_CONFIG rCmdBasicConfig; + + DEBUGFUNC("wlanoidSetCSUMOffload"); + DBGLOG(INIT, LOUD, ("\n")); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(UINT_32); + + if (u4SetBufferLen < sizeof(UINT_32)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + u4CSUMFlags = *(PUINT_32)pvSetBuffer; + + kalMemZero(&rCmdBasicConfig, sizeof(CMD_BASIC_CONFIG)); + + for(i = 0 ; i < 6 ; i++) { // set to broadcast address for not-specified + rCmdBasicConfig.rMyMacAddr[i] = 0xff; + } + + rCmdBasicConfig.ucNative80211 = 0; //@FIXME: for Vista + + if(u4CSUMFlags & CSUM_OFFLOAD_EN_TX_TCP) + rCmdBasicConfig.rCsumOffload.u2TxChecksum |= BIT(2); + + if(u4CSUMFlags & CSUM_OFFLOAD_EN_TX_UDP) + rCmdBasicConfig.rCsumOffload.u2TxChecksum |= BIT(1); + + if(u4CSUMFlags & CSUM_OFFLOAD_EN_TX_IP) + rCmdBasicConfig.rCsumOffload.u2TxChecksum |= BIT(0); + + if(u4CSUMFlags & CSUM_OFFLOAD_EN_RX_TCP) + rCmdBasicConfig.rCsumOffload.u2RxChecksum |= BIT(2); + + if(u4CSUMFlags & CSUM_OFFLOAD_EN_RX_UDP) + rCmdBasicConfig.rCsumOffload.u2RxChecksum |= BIT(1); + + if(u4CSUMFlags & (CSUM_OFFLOAD_EN_RX_IPv4 | CSUM_OFFLOAD_EN_RX_IPv6)) + rCmdBasicConfig.rCsumOffload.u2RxChecksum |= BIT(0); + + prAdapter->u4CSUMFlags = u4CSUMFlags; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_BASIC_CONFIG, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_BASIC_CONFIG), + (PUINT_8)&rCmdBasicConfig, + pvSetBuffer, + u4SetBufferLen + ); +} +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Setting the IP address for pattern search function. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \return WLAN_STATUS_SUCCESS +* \return WLAN_STATUS_ADAPTER_NOT_READY +* \return WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetNetworkAddress( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 i, j; + P_CMD_SET_NETWORK_ADDRESS_LIST prCmdNetworkAddressList; + P_PARAM_NETWORK_ADDRESS_LIST prNetworkAddressList = (P_PARAM_NETWORK_ADDRESS_LIST)pvSetBuffer; + P_PARAM_NETWORK_ADDRESS prNetworkAddress; + P_PARAM_NETWORK_ADDRESS_IP prNetAddrIp; + UINT_32 u4IpAddressCount, u4CmdSize; + PUINT_8 pucBuf = (PUINT_8)pvSetBuffer; + + DEBUGFUNC("wlanoidSetNetworkAddress"); + DBGLOG(INIT, LOUD, ("\n")); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = 4; + + if (u4SetBufferLen < sizeof(PARAM_NETWORK_ADDRESS_LIST)) { + return WLAN_STATUS_INVALID_DATA; + } + + *pu4SetInfoLen = 0; + u4IpAddressCount = 0; + + prNetworkAddress = prNetworkAddressList->arAddress; + for ( i = 0 ; i < prNetworkAddressList->u4AddressCount ; i++) { + if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && + prNetworkAddress->u2AddressLength == sizeof(PARAM_NETWORK_ADDRESS_IP)) { + u4IpAddressCount++; + } + + prNetworkAddress = (P_PARAM_NETWORK_ADDRESS) ((UINT_32) prNetworkAddress + + (UINT_32) (prNetworkAddress->u2AddressLength + OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress))); + } + + // construct payload of command packet + u4CmdSize = OFFSET_OF(CMD_SET_NETWORK_ADDRESS_LIST, arNetAddress) + + sizeof(IPV4_NETWORK_ADDRESS) * u4IpAddressCount; + if (u4IpAddressCount == 0) { + u4CmdSize = sizeof(CMD_SET_NETWORK_ADDRESS_LIST); + } + + prCmdNetworkAddressList = (P_CMD_SET_NETWORK_ADDRESS_LIST) kalMemAlloc(u4CmdSize, VIR_MEM_TYPE); + + if(prCmdNetworkAddressList == NULL) + return WLAN_STATUS_FAILURE; + + // fill P_CMD_SET_NETWORK_ADDRESS_LIST + prCmdNetworkAddressList->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; + + /* only to set IP address to FW once ARP filter is enabled */ + if (prAdapter->fgEnArpFilter) { + prCmdNetworkAddressList->ucAddressCount = (UINT_8)u4IpAddressCount; + prNetworkAddress = prNetworkAddressList->arAddress; + + DBGLOG(REQ, INFO, ("u4IpAddressCount (%d)\n", u4IpAddressCount)); + + for (i = 0, j = 0 ; i < prNetworkAddressList->u4AddressCount ; i++) { + if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && + prNetworkAddress->u2AddressLength == sizeof(PARAM_NETWORK_ADDRESS_IP)) { + prNetAddrIp = (P_PARAM_NETWORK_ADDRESS_IP)prNetworkAddress->aucAddress; + + kalMemCopy(prCmdNetworkAddressList->arNetAddress[j].aucIpAddr, + &(prNetAddrIp->in_addr), + sizeof(UINT_32)); + + j++; + + pucBuf = (PUINT_8)&prNetAddrIp->in_addr; + DBGLOG(REQ, INFO, ("prNetAddrIp->in_addr:%d:%d:%d:%d\n", pucBuf[0], pucBuf[1],pucBuf[2],pucBuf[3])); + } + + prNetworkAddress = (P_PARAM_NETWORK_ADDRESS) ((UINT_32) prNetworkAddress + + (UINT_32) (prNetworkAddress->u2AddressLength + OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress))); + } + + } else { + prCmdNetworkAddressList->ucAddressCount = 0; + } + + rStatus = wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_IP_ADDRESS, + TRUE, + FALSE, + TRUE, + nicCmdEventSetIpAddress, + nicOidCmdTimeoutCommon, + u4CmdSize, + (PUINT_8)prCmdNetworkAddressList, + pvSetBuffer, + u4SetBufferLen + ); + + kalMemFree(prCmdNetworkAddressList, VIR_MEM_TYPE, u4CmdSize); + return rStatus; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Set driver to switch into RF test mode +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set, +* should be NULL +* \param[in] u4SetBufferLen The length of the set buffer, should be 0 +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \return WLAN_STATUS_SUCCESS +* \return WLAN_STATUS_ADAPTER_NOT_READY +* \return WLAN_STATUS_INVALID_DATA +* \return WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidRftestSetTestMode ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + WLAN_STATUS rStatus; + CMD_TEST_CTRL_T rCmdTestCtrl; + + DEBUGFUNC("wlanoidRftestSetTestMode"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = 0; + + if(u4SetBufferLen == 0) { + if(prAdapter->fgTestMode == FALSE) { + // switch to RF Test mode + rCmdTestCtrl.ucAction = 0; // Switch mode + rCmdTestCtrl.u.u4OpMode = 1; // RF test mode + + rStatus = wlanSendSetQueryCmd(prAdapter, + CMD_ID_TEST_MODE, + TRUE, + FALSE, + TRUE, + nicCmdEventEnterRfTest, + nicOidCmdEnterRFTestTimeout, + sizeof(CMD_TEST_CTRL_T), + (PUINT_8)&rCmdTestCtrl, + pvSetBuffer, + u4SetBufferLen); + } + else { + // already in test mode .. + rStatus = WLAN_STATUS_SUCCESS; + } + } + else { + rStatus = WLAN_STATUS_INVALID_DATA; + } + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Set driver to switch into normal operation mode from RF test mode +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* should be NULL +* \param[in] u4SetBufferLen The length of the set buffer, should be 0 +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \return WLAN_STATUS_SUCCESS +* \return WLAN_STATUS_ADAPTER_NOT_READY +* \return WLAN_STATUS_INVALID_DATA +* \return WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidRftestSetAbortTestMode ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + WLAN_STATUS rStatus; + CMD_TEST_CTRL_T rCmdTestCtrl; + + DEBUGFUNC("wlanoidRftestSetTestMode"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = 0; + + if(u4SetBufferLen == 0) { + if(prAdapter->fgTestMode == TRUE) { + // switch to normal mode + rCmdTestCtrl.ucAction = 0; // Switch mode + rCmdTestCtrl.u.u4OpMode = 0; // normal mode + + rStatus = wlanSendSetQueryCmd(prAdapter, + CMD_ID_TEST_MODE, + TRUE, + FALSE, + TRUE, + nicCmdEventLeaveRfTest, + nicOidCmdTimeoutCommon, + sizeof(CMD_TEST_CTRL_T), + (PUINT_8)&rCmdTestCtrl, + pvSetBuffer, + u4SetBufferLen); + } + else { + // already in normal mode .. + rStatus = WLAN_STATUS_SUCCESS; + } + } + else { + rStatus = WLAN_STATUS_INVALID_DATA; + } + + return rStatus; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief query for RF test parameter +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +* \retval WLAN_STATUS_NOT_SUPPORTED +* \retval WLAN_STATUS_NOT_ACCEPTED +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidRftestQueryAutoTest ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + P_PARAM_MTK_WIFI_TEST_STRUC_T prRfATInfo; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidRftestQueryAutoTest"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(PARAM_MTK_WIFI_TEST_STRUC_T); + + if (u4QueryBufferLen != sizeof(PARAM_MTK_WIFI_TEST_STRUC_T)) { + DBGLOG(REQ, ERROR, ("Invalid data. QueryBufferLen: %ld.\n", + u4QueryBufferLen)); + return WLAN_STATUS_INVALID_LENGTH; + } + + prRfATInfo = (P_PARAM_MTK_WIFI_TEST_STRUC_T)pvQueryBuffer; + rStatus = rftestQueryATInfo(prAdapter, + prRfATInfo->u4FuncIndex, + prRfATInfo->u4FuncData, + pvQueryBuffer, + u4QueryBufferLen); + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Set RF test parameter +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \return WLAN_STATUS_SUCCESS +* \return WLAN_STATUS_ADAPTER_NOT_READY +* \return WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidRftestSetAutoTest ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_PARAM_MTK_WIFI_TEST_STRUC_T prRfATInfo; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidRftestSetAutoTest"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_MTK_WIFI_TEST_STRUC_T); + + if (u4SetBufferLen != sizeof(PARAM_MTK_WIFI_TEST_STRUC_T)) { + DBGLOG(REQ, ERROR, ("Invalid data. SetBufferLen: %ld.\n", + u4SetBufferLen)); + return WLAN_STATUS_INVALID_LENGTH; + } + + prRfATInfo = (P_PARAM_MTK_WIFI_TEST_STRUC_T)pvSetBuffer; + rStatus = rftestSetATInfo(prAdapter, prRfATInfo->u4FuncIndex, prRfATInfo->u4FuncData); + + return rStatus; +} + +/* RF test OID set handler */ +WLAN_STATUS +rftestSetATInfo ( + IN P_ADAPTER_T prAdapter, + UINT_32 u4FuncIndex, + UINT_32 u4FuncData + ) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + P_CMD_TEST_CTRL_T pCmdTestCtrl; + UINT_8 ucCmdSeqNum; + + ASSERT(prAdapter); + + prGlueInfo = prAdapter->prGlueInfo; + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_TEST_CTRL_T))); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, ("Allocate CMD_INFO_T ==> FAILED.\n")); + return WLAN_STATUS_FAILURE; + } + + // increase command sequence number + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + // Setup common CMD Info Packet + prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_TEST_CTRL_T); + prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; + prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; + prCmdInfo->fgIsOid = TRUE; + prCmdInfo->ucCID = CMD_ID_TEST_MODE; + prCmdInfo->fgSetQuery = TRUE; + prCmdInfo->fgNeedResp = FALSE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = sizeof(CMD_TEST_CTRL_T); + prCmdInfo->pvInformationBuffer = NULL; + prCmdInfo->u4InformationBufferLength = 0; + + // Setup WIFI_CMD_T (payload = CMD_TEST_CTRL_T) + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + pCmdTestCtrl = (P_CMD_TEST_CTRL_T)(prWifiCmd->aucBuffer); + pCmdTestCtrl->ucAction = 1; // Set ATInfo + pCmdTestCtrl->u.rRfATInfo.u4FuncIndex = u4FuncIndex; + pCmdTestCtrl->u.rRfATInfo.u4FuncData = u4FuncData; + + // insert into prCmdQueue + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + + // wakeup txServiceThread later + GLUE_SET_EVENT(prAdapter->prGlueInfo); + + return WLAN_STATUS_PENDING; +} + +WLAN_STATUS +rftestQueryATInfo( + IN P_ADAPTER_T prAdapter, + UINT_32 u4FuncIndex, + UINT_32 u4FuncData, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen + ) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + P_CMD_TEST_CTRL_T pCmdTestCtrl; + UINT_8 ucCmdSeqNum; + P_EVENT_TEST_STATUS prTestStatus; + + ASSERT(prAdapter); + + prGlueInfo = prAdapter->prGlueInfo; + + if(u4FuncIndex == RF_AT_FUNCID_FW_INFO) { + /* driver implementation */ + prTestStatus = (P_EVENT_TEST_STATUS)pvQueryBuffer; + + prTestStatus->rATInfo.u4FuncData = + (prAdapter->rVerInfo.u2FwProductID << 16) | (prAdapter->rVerInfo.u2FwOwnVersion); + u4QueryBufferLen = sizeof(EVENT_TEST_STATUS); + + return WLAN_STATUS_SUCCESS; + } + else if(u4FuncIndex == RF_AT_FUNCID_DRV_INFO) { + /* driver implementation */ + prTestStatus = (P_EVENT_TEST_STATUS)pvQueryBuffer; + + prTestStatus->rATInfo.u4FuncData = CFG_DRV_OWN_VERSION; + u4QueryBufferLen = sizeof(EVENT_TEST_STATUS); + + return WLAN_STATUS_SUCCESS; + } + else { + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_TEST_CTRL_T))); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, ("Allocate CMD_INFO_T ==> FAILED.\n")); + return WLAN_STATUS_FAILURE; + } + + // increase command sequence number + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + // Setup common CMD Info Packet + prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_TEST_CTRL_T); + prCmdInfo->pfCmdDoneHandler = nicCmdEventQueryRfTestATInfo; + prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; + prCmdInfo->fgIsOid = TRUE; + prCmdInfo->ucCID = CMD_ID_TEST_MODE; + prCmdInfo->fgSetQuery = FALSE; + prCmdInfo->fgNeedResp = TRUE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = sizeof(CMD_TEST_CTRL_T); + prCmdInfo->pvInformationBuffer = pvQueryBuffer; + prCmdInfo->u4InformationBufferLength = u4QueryBufferLen; + + // Setup WIFI_CMD_T (payload = CMD_TEST_CTRL_T) + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + pCmdTestCtrl = (P_CMD_TEST_CTRL_T)(prWifiCmd->aucBuffer); + pCmdTestCtrl->ucAction = 2; // Get ATInfo + pCmdTestCtrl->u.rRfATInfo.u4FuncIndex = u4FuncIndex; + pCmdTestCtrl->u.rRfATInfo.u4FuncData = u4FuncData; + + // insert into prCmdQueue + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + + // wakeup txServiceThread later + GLUE_SET_EVENT(prAdapter->prGlueInfo); + + return WLAN_STATUS_PENDING; + } +} + +WLAN_STATUS +rftestSetFrequency( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4FreqInKHz, + IN PUINT_32 pu4SetInfoLen + ) +{ + CMD_TEST_CTRL_T rCmdTestCtrl; + + ASSERT(prAdapter); + + rCmdTestCtrl.ucAction = 5; // Set Channel Frequency + rCmdTestCtrl.u.u4ChannelFreq = u4FreqInKHz; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_TEST_MODE, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_TEST_CTRL_T), + (PUINT_8)&rCmdTestCtrl, + NULL, + 0); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief command packet generation utility +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] ucCID Command ID +* \param[in] fgSetQuery Set or Query +* \param[in] fgNeedResp Need for response +* \param[in] pfCmdDoneHandler Function pointer when command is done +* \param[in] u4SetQueryInfoLen The length of the set/query buffer +* \param[in] pucInfoBuffer Pointer to set/query buffer +* +* +* \retval WLAN_STATUS_PENDING +* \retval WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanSendSetQueryCmd ( + IN P_ADAPTER_T prAdapter, + UINT_8 ucCID, + BOOLEAN fgSetQuery, + BOOLEAN fgNeedResp, + BOOLEAN fgIsOid, + PFN_CMD_DONE_HANDLER pfCmdDoneHandler, + PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, + UINT_32 u4SetQueryInfoLen, + PUINT_8 pucInfoBuffer, + OUT PVOID pvSetQueryBuffer, + IN UINT_32 u4SetQueryBufferLen + ) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + UINT_8 ucCmdSeqNum; + + prGlueInfo = prAdapter->prGlueInfo; + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + u4SetQueryInfoLen)); + + DEBUGFUNC("wlanSendSetQueryCmd"); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, ("Allocate CMD_INFO_T ==> FAILED.\n")); + return WLAN_STATUS_FAILURE; + } + + // increase command sequence number + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + DBGLOG(REQ, TRACE, ("ucCmdSeqNum =%d\n", ucCmdSeqNum)); + DBGLOG(REQ, TRACE, ("Command ID = 0x%08X\n", ucCID)); + // Setup common CMD Info Packet + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->eNetworkType = NETWORK_TYPE_AIS_INDEX; + prCmdInfo->u2InfoBufLen = (UINT_16)(CMD_HDR_SIZE + u4SetQueryInfoLen); + prCmdInfo->pfCmdDoneHandler = pfCmdDoneHandler; + prCmdInfo->pfCmdTimeoutHandler = pfCmdTimeoutHandler; + prCmdInfo->fgIsOid = fgIsOid; + prCmdInfo->ucCID = ucCID; + prCmdInfo->fgSetQuery = fgSetQuery; + prCmdInfo->fgNeedResp = fgNeedResp; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = u4SetQueryInfoLen; + prCmdInfo->pvInformationBuffer = pvSetQueryBuffer; + prCmdInfo->u4InformationBufferLength = u4SetQueryBufferLen; + + // Setup WIFI_CMD_T (no payload) + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + if(u4SetQueryInfoLen > 0 && pucInfoBuffer != NULL) { + kalMemCopy(prWifiCmd->aucBuffer, pucInfoBuffer, u4SetQueryInfoLen); + } + + // insert into prCmdQueue + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + + // wakeup txServiceThread later + GLUE_SET_EVENT(prGlueInfo); + return WLAN_STATUS_PENDING; +} + + + +#if CFG_SUPPORT_WAPI +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called by WAPI ui to set wapi mode, which is needed to info the the driver +* to operation at WAPI mode while driver initialize. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. +* \retval WLAN_STATUS_INVALID_LENGTH +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetWapiMode ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + DEBUGFUNC("wlanoidSetWapiMode"); + DBGLOG(REQ, LOUD, ("\r\n")); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + ASSERT(pvSetBuffer); + + /* Todo:: For support WAPI and Wi-Fi at same driver, use the set wapi assoc ie at the check point */ + /* The Adapter Connection setting fgUseWapi will cleat whil oid set mode (infra), */ + /* And set fgUseWapi True while set wapi assoc ie */ + /* policay selection, add key all depend on this flag, */ + /* The fgUseWapi may remove later */ + if (*(PUINT_32)pvSetBuffer) { + prAdapter->fgUseWapi = TRUE; + } + else { + prAdapter->fgUseWapi = FALSE; + } + +#if 0 + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + 4)); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, ("Allocate CMD_INFO_T ==> FAILED.\n")); + return WLAN_STATUS_FAILURE; + } + + // increase command sequence number + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + // compose CMD_BUILD_CONNECTION cmd pkt + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->eNetworkType = NETWORK_TYPE_AIS_INDEX; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + 4; + prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; + prCmdInfo->pfCmdTimeoutHandler = NULL; + prCmdInfo->fgIsOid = TRUE; + prCmdInfo->ucCID = CMD_ID_WAPI_MODE; + prCmdInfo->fgSetQuery = TRUE; + prCmdInfo->fgNeedResp = FALSE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = u4SetBufferLen; + prCmdInfo->pvInformationBuffer = pvSetBuffer; + prCmdInfo->u4InformationBufferLength = u4SetBufferLen; + + // Setup WIFI_CMD_T + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + cp = (PUINT_8)(prWifiCmd->aucBuffer); + + kalMemCopy(cp, (PUINT_8)pvSetBuffer, 4); + + // insert into prCmdQueue + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + + // wakeup txServiceThread later + GLUE_SET_EVENT(prGlueInfo); + + return WLAN_STATUS_PENDING; +#else + return WLAN_STATUS_SUCCESS; +#endif +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called by WAPI to set the assoc info, which is needed to add to +* Association request frame while join WAPI AP. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. +* \retval WLAN_STATUS_INVALID_LENGTH +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetWapiAssocInfo ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_WAPI_INFO_ELEM_T prWapiInfo; + PUINT_8 cp; + UINT_16 u2AuthSuiteCount = 0; + UINT_16 u2PairSuiteCount = 0; + UINT_32 u4AuthKeyMgtSuite = 0; + UINT_32 u4PairSuite = 0; + UINT_32 u4GroupSuite = 0; + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + DEBUGFUNC("wlanoidSetWapiAssocInfo"); + DBGLOG(REQ, LOUD, ("\r\n")); + + if (u4SetBufferLen < 20 /* From EID to Group cipher */) { + prAdapter->rWifiVar.rConnSettings.fgWapiMode = FALSE; + return WLAN_STATUS_INVALID_LENGTH; + } + + prAdapter->rWifiVar.rConnSettings.fgWapiMode = TRUE; + + //if (prWapiInfo->ucElemId != ELEM_ID_WAPI) + // DBGLOG(SEC, TRACE, ("Not WAPI IE ?!\n")); + + //if (prWapiInfo->ucLength < 18) + // return WLAN_STATUS_INVALID_LENGTH; + + *pu4SetInfoLen = u4SetBufferLen; + + prWapiInfo = (P_WAPI_INFO_ELEM_T)pvSetBuffer; + + if (prWapiInfo->ucElemId != ELEM_ID_WAPI) { + DBGLOG(SEC, TRACE, ("Not WAPI IE ?! u4SetBufferLen = %d\n", u4SetBufferLen)); + prAdapter->rWifiVar.rConnSettings.fgWapiMode = FALSE; + return WLAN_STATUS_INVALID_LENGTH; + } + + if (prWapiInfo->ucLength < 18) + return WLAN_STATUS_INVALID_LENGTH; + + /* Skip Version check */ + cp = (PUINT_8)&prWapiInfo->u2AuthKeyMgtSuiteCount; + + WLAN_GET_FIELD_16(cp, &u2AuthSuiteCount); + + if (u2AuthSuiteCount>1) + return WLAN_STATUS_INVALID_LENGTH; + + cp += 2; + WLAN_GET_FIELD_32(cp, &u4AuthKeyMgtSuite); + + DBGLOG(SEC, TRACE, ("WAPI: Assoc Info auth mgt suite [%d]: %02x-%02x-%02x-%02x\n", + u2AuthSuiteCount, + (UCHAR) (u4AuthKeyMgtSuite & 0x000000FF), + (UCHAR) ((u4AuthKeyMgtSuite >> 8) & 0x000000FF), + (UCHAR) ((u4AuthKeyMgtSuite >> 16) & 0x000000FF), + (UCHAR) ((u4AuthKeyMgtSuite >> 24) & 0x000000FF))); + + if (u4AuthKeyMgtSuite != WAPI_AKM_SUITE_802_1X && + u4AuthKeyMgtSuite != WAPI_AKM_SUITE_PSK) + ASSERT(FALSE); + + cp += 4; + WLAN_GET_FIELD_16(cp, &u2PairSuiteCount); + if (u2PairSuiteCount>1) + return WLAN_STATUS_INVALID_LENGTH; + + cp += 2; + WLAN_GET_FIELD_32(cp, &u4PairSuite); + DBGLOG(SEC, TRACE, ("WAPI: Assoc Info pairwise cipher suite [%d]: %02x-%02x-%02x-%02x\n", + u2PairSuiteCount, + (UCHAR) (u4PairSuite & 0x000000FF), + (UCHAR) ((u4PairSuite >> 8) & 0x000000FF), + (UCHAR) ((u4PairSuite >> 16) & 0x000000FF), + (UCHAR) ((u4PairSuite >> 24) & 0x000000FF))); + + if (u4PairSuite != WAPI_CIPHER_SUITE_WPI) + ASSERT(FALSE); + + cp += 4; + WLAN_GET_FIELD_32(cp, &u4GroupSuite); + DBGLOG(SEC, TRACE, ("WAPI: Assoc Info group cipher suite : %02x-%02x-%02x-%02x\n", + (UCHAR) (u4GroupSuite & 0x000000FF), + (UCHAR) ((u4GroupSuite >> 8) & 0x000000FF), + (UCHAR) ((u4GroupSuite >> 16) & 0x000000FF), + (UCHAR) ((u4GroupSuite >> 24) & 0x000000FF))); + + if (u4GroupSuite != WAPI_CIPHER_SUITE_WPI) + ASSERT(FALSE); + + prAdapter->rWifiVar.rConnSettings.u4WapiSelectedAKMSuite = u4AuthKeyMgtSuite; + prAdapter->rWifiVar.rConnSettings.u4WapiSelectedPairwiseCipher = u4PairSuite; + prAdapter->rWifiVar.rConnSettings.u4WapiSelectedGroupCipher = u4GroupSuite; + + kalMemCopy(prAdapter->prGlueInfo->aucWapiAssocInfoIEs, pvSetBuffer, u4SetBufferLen); + prAdapter->prGlueInfo->u2WapiAssocInfoIESz = (UINT_16)u4SetBufferLen; + DBGLOG(SEC, TRACE, ("Assoc Info IE sz %ld\n", u4SetBufferLen)); + + return WLAN_STATUS_SUCCESS; + +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set the wpi key to the driver. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +* +* \note The setting buffer P_PARAM_WPI_KEY, which is set by NDIS, is unpacked. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetWapiKey ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + P_PARAM_WPI_KEY_T prNewKey; + P_CMD_802_11_KEY prCmdKey; + PUINT_8 pc; + UINT_8 ucCmdSeqNum; + + DEBUGFUNC("wlanoidSetWapiKey"); + DBGLOG(REQ, LOUD, ("\r\n")); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in set add key! (Adapter not ready). ACPI=D%d, Radio=%d\r\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + prNewKey = (P_PARAM_WPI_KEY_T) pvSetBuffer; + + DBGLOG_MEM8(REQ, TRACE, (PUINT_8)pvSetBuffer, 560); + pc = (PUINT_8)pvSetBuffer; + + *pu4SetInfoLen = u4SetBufferLen; + + /* Exception check */ + if (prNewKey->ucKeyID != 0x1 || + prNewKey->ucKeyID != 0x0) { + prNewKey->ucKeyID = prNewKey->ucKeyID & BIT(0); + //DBGLOG(SEC, INFO, ("Invalid WAPI key ID (%d)\r\n", prNewKey->ucKeyID)); + } + + /* Dump P_PARAM_WPI_KEY_T content. */ + DBGLOG(REQ, TRACE, ("Set: Dump P_PARAM_WPI_KEY_T content\r\n")); + DBGLOG(REQ, TRACE, ("TYPE : %d\r\n", prNewKey->eKeyType)); + DBGLOG(REQ, TRACE, ("Direction : %d\r\n", prNewKey->eDirection)); + DBGLOG(REQ, TRACE, ("KeyID : %d\r\n", prNewKey->ucKeyID)); + DBGLOG(REQ, TRACE, ("AddressIndex:\r\n")); + DBGLOG_MEM8(REQ, TRACE, prNewKey->aucAddrIndex, 12); + prNewKey->u4LenWPIEK = 16; + + DBGLOG_MEM8(REQ, TRACE, (PUINT_8)prNewKey->aucWPIEK, (UINT_8)prNewKey->u4LenWPIEK); + prNewKey->u4LenWPICK = 16; + + DBGLOG(REQ, TRACE, ("CK Key(%d):\r\n", (UINT_8)prNewKey->u4LenWPICK)); + DBGLOG_MEM8(REQ, TRACE, (PUINT_8)prNewKey->aucWPICK, (UINT_8)prNewKey->u4LenWPICK); + DBGLOG(REQ, TRACE, ("PN:\r\n")); + if (prNewKey->eKeyType == 0){ + prNewKey->aucPN[0] = 0x5c; + prNewKey->aucPN[1] = 0x36; + prNewKey->aucPN[2] = 0x5c; + prNewKey->aucPN[3] = 0x36; + prNewKey->aucPN[4] = 0x5c; + prNewKey->aucPN[5] = 0x36; + prNewKey->aucPN[6] = 0x5c; + prNewKey->aucPN[7] = 0x36; + prNewKey->aucPN[8] = 0x5c; + prNewKey->aucPN[9] = 0x36; + prNewKey->aucPN[10] = 0x5c; + prNewKey->aucPN[11] = 0x36; + prNewKey->aucPN[12] = 0x5c; + prNewKey->aucPN[13] = 0x36; + prNewKey->aucPN[14] = 0x5c; + prNewKey->aucPN[15] = 0x36; + } + + DBGLOG_MEM8(REQ, TRACE, (PUINT_8)prNewKey->aucPN, 16); + + prGlueInfo = prAdapter->prGlueInfo; + + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + u4SetBufferLen)); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, ("Allocate CMD_INFO_T ==> FAILED.\n")); + return WLAN_STATUS_FAILURE; + } + + // increase command sequence number + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + // compose CMD_ID_ADD_REMOVE_KEY cmd pkt + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->eNetworkType = NETWORK_TYPE_AIS_INDEX; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_802_11_KEY); + prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; + prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; + prCmdInfo->fgIsOid = TRUE; + prCmdInfo->ucCID = CMD_ID_ADD_REMOVE_KEY; + prCmdInfo->fgSetQuery = TRUE; + prCmdInfo->fgNeedResp = FALSE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = u4SetBufferLen; + prCmdInfo->pvInformationBuffer = pvSetBuffer; + prCmdInfo->u4InformationBufferLength = u4SetBufferLen; + + // Setup WIFI_CMD_T + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + prCmdKey = (P_CMD_802_11_KEY)(prWifiCmd->aucBuffer); + + kalMemZero(prCmdKey, sizeof(CMD_802_11_KEY)); + + prCmdKey->ucAddRemove = 1; /* Add */ + + if (prNewKey->eKeyType == ENUM_WPI_PAIRWISE_KEY) { + prCmdKey->ucTxKey = 1; + prCmdKey->ucKeyType = 1; + } + + kalMemCopy(prCmdKey->aucPeerAddr, (PUINT_8)prNewKey->aucAddrIndex, MAC_ADDR_LEN); + + prCmdKey->ucNetType = 0; /* AIS */ + + prCmdKey->ucKeyId = prNewKey->ucKeyID; + + prCmdKey->ucKeyLen = 32; + + prCmdKey->ucAlgorithmId = CIPHER_SUITE_WPI; + + kalMemCopy(prCmdKey->aucKeyMaterial, (PUINT_8)prNewKey->aucWPIEK, 16); + + kalMemCopy(prCmdKey->aucKeyMaterial+16, (PUINT_8)prNewKey->aucWPICK, 16); + + kalMemCopy(prCmdKey->aucKeyRsc, (PUINT_8)prNewKey->aucPN, 16); + + // insert into prCmdQueue + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + + // wakeup txServiceThread later + GLUE_SET_EVENT(prGlueInfo); + + return WLAN_STATUS_PENDING; +} /* wlanoidSetAddKey */ +#endif + + +#if CFG_SUPPORT_WPS2 +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called by WSC to set the assoc info, which is needed to add to +* Association request frame while join WPS AP. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. +* \retval WLAN_STATUS_INVALID_LENGTH +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetWSCAssocInfo ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + DEBUGFUNC("wlanoidSetWSCAssocInfo"); + DBGLOG(REQ, LOUD, ("\r\n")); + + if(u4SetBufferLen == 0) + return WLAN_STATUS_INVALID_LENGTH; + + *pu4SetInfoLen = u4SetBufferLen; + + kalMemCopy(prAdapter->prGlueInfo->aucWSCAssocInfoIE, pvSetBuffer, u4SetBufferLen); + prAdapter->prGlueInfo->u2WSCAssocInfoIELen = (UINT_16)u4SetBufferLen; + DBGLOG(SEC, TRACE, ("Assoc Info IE sz %ld\n", u4SetBufferLen)); + + return WLAN_STATUS_SUCCESS; + +} +#endif + + +#if CFG_ENABLE_WAKEUP_ON_LAN +WLAN_STATUS +wlanoidSetAddWakeupPattern ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_PARAM_PM_PACKET_PATTERN prPacketPattern; + + DEBUGFUNC("wlanoidSetAddWakeupPattern"); + DBGLOG(REQ, LOUD, ("\r\n")); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_PM_PACKET_PATTERN); + + if (u4SetBufferLen < sizeof(PARAM_PM_PACKET_PATTERN)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prPacketPattern = (P_PARAM_PM_PACKET_PATTERN) pvSetBuffer; + + /* FIXME: + * Send the struct to firmware */ + + return WLAN_STATUS_FAILURE; +} + + +WLAN_STATUS +wlanoidSetRemoveWakeupPattern ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_PARAM_PM_PACKET_PATTERN prPacketPattern; + + DEBUGFUNC("wlanoidSetAddWakeupPattern"); + DBGLOG(REQ, LOUD, ("\r\n")); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_PM_PACKET_PATTERN); + + if (u4SetBufferLen < sizeof(PARAM_PM_PACKET_PATTERN)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prPacketPattern = (P_PARAM_PM_PACKET_PATTERN) pvSetBuffer; + + /* FIXME: + * Send the struct to firmware */ + + return WLAN_STATUS_FAILURE; +} + + +WLAN_STATUS +wlanoidQueryEnableWakeup ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + PUINT_32 pu4WakeupEventEnable; + + DEBUGFUNC("wlanoidQueryEnableWakeup"); + DBGLOG(REQ, LOUD, ("\r\n")); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(UINT_32); + + if (u4QueryBufferLen < sizeof(UINT_32)) { + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + pu4WakeupEventEnable = (PUINT_32)pvQueryBuffer; + + *pu4WakeupEventEnable = prAdapter->u4WakeupEventEnable; + + return WLAN_STATUS_SUCCESS; +} + +WLAN_STATUS +wlanoidSetEnableWakeup ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + PUINT_32 pu4WakeupEventEnable; + + DEBUGFUNC("wlanoidSetEnableWakup"); + DBGLOG(REQ, LOUD, ("\r\n")); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(UINT_32); + + if (u4SetBufferLen < sizeof(UINT_32)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + pu4WakeupEventEnable = (PUINT_32)pvSetBuffer; + prAdapter->u4WakeupEventEnable = *pu4WakeupEventEnable; + + /* FIXME: + * Send Command Event for setting wakeup-pattern / Magic Packet to firmware + * */ + + return WLAN_STATUS_FAILURE; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to configure PS related settings for WMM-PS test. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetWiFiWmmPsTest ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_PARAM_CUSTOM_WMM_PS_TEST_STRUC_T prWmmPsTestInfo; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + CMD_SET_WMM_PS_TEST_STRUC_T rSetWmmPsTestParam; + UINT_16 u2CmdBufLen; + P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo; + P_BSS_INFO_T prBssInfo; + + DEBUGFUNC("wlanoidSetWiFiWmmPsTest"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_WMM_PS_TEST_STRUC_T); + + prWmmPsTestInfo = (P_PARAM_CUSTOM_WMM_PS_TEST_STRUC_T) pvSetBuffer; + + rSetWmmPsTestParam.ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; + rSetWmmPsTestParam.bmfgApsdEnAc = prWmmPsTestInfo->bmfgApsdEnAc; + rSetWmmPsTestParam.ucIsEnterPsAtOnce = prWmmPsTestInfo->ucIsEnterPsAtOnce; + rSetWmmPsTestParam.ucIsDisableUcTrigger = prWmmPsTestInfo->ucIsDisableUcTrigger; + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[rSetWmmPsTestParam.ucNetTypeIndex]); + prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; + prPmProfSetupInfo->ucBmpDeliveryAC = (rSetWmmPsTestParam.bmfgApsdEnAc >> 4) & BITS(0, 3); + prPmProfSetupInfo->ucBmpTriggerAC = rSetWmmPsTestParam.bmfgApsdEnAc & BITS(0, 3); + + u2CmdBufLen = sizeof(CMD_SET_WMM_PS_TEST_STRUC_T); + +#if 0 + /* it will apply the disable trig or not immediately */ + if (prPmInfo->ucWmmPsDisableUcPoll && prPmInfo->ucWmmPsConnWithTrig) { +// NIC_PM_WMM_PS_DISABLE_UC_TRIG(prAdapter, TRUE); + } + else { +// NIC_PM_WMM_PS_DISABLE_UC_TRIG(prAdapter, FALSE); + } +#endif + + rStatus = wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_WMM_PS_TEST_PARMS, + TRUE, + FALSE, + TRUE, + NULL, // TODO? + NULL, + u2CmdBufLen, + (PUINT_8)&rSetWmmPsTestParam, + NULL, + 0); + + + return rStatus; +} /* wlanoidSetWiFiWmmPsTest */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to configure enable/disable TX A-MPDU feature. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetTxAmpdu ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + CMD_TX_AMPDU_T rTxAmpdu; + UINT_16 u2CmdBufLen; + PBOOLEAN pfgEnable; + + DEBUGFUNC("wlanoidSetTxAmpdu"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + + *pu4SetInfoLen = sizeof(BOOLEAN); + + pfgEnable = (PBOOLEAN) pvSetBuffer; + + rTxAmpdu.fgEnable = *pfgEnable; + + u2CmdBufLen = sizeof(CMD_TX_AMPDU_T); + + rStatus = wlanSendSetQueryCmd(prAdapter, + CMD_ID_TX_AMPDU, + TRUE, + FALSE, + TRUE, + NULL, + NULL, + u2CmdBufLen, + (PUINT_8)&rTxAmpdu, + NULL, + 0); + + + return rStatus; +} /* wlanoidSetTxAmpdu */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to configure reject/accept ADDBA Request. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetAddbaReject( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + CMD_ADDBA_REJECT_T rAddbaReject; + UINT_16 u2CmdBufLen; + PBOOLEAN pfgEnable; + + DEBUGFUNC("wlanoidSetAddbaReject"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + + *pu4SetInfoLen = sizeof(BOOLEAN); + + pfgEnable = (PBOOLEAN) pvSetBuffer; + + rAddbaReject.fgEnable = *pfgEnable; + + u2CmdBufLen = sizeof(CMD_ADDBA_REJECT_T); + + rStatus = wlanSendSetQueryCmd(prAdapter, + CMD_ID_ADDBA_REJECT, + TRUE, + FALSE, + TRUE, + NULL, + NULL, + u2CmdBufLen, + (PUINT_8)&rAddbaReject, + NULL, + 0); + + + return rStatus; +} /* wlanoidSetAddbaReject */ + + +#if CFG_SLT_SUPPORT + +WLAN_STATUS +wlanoidQuerySLTStatus ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + P_PARAM_MTK_SLT_TEST_STRUC_T prMtkSltInfo = (P_PARAM_MTK_SLT_TEST_STRUC_T)NULL; + P_SLT_INFO_T prSltInfo = (P_SLT_INFO_T)NULL; + + DEBUGFUNC("wlanoidQuerySLTStatus"); + DBGLOG(REQ, LOUD, ("\r\n")); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(PARAM_MTK_SLT_TEST_STRUC_T); + + if (u4QueryBufferLen < sizeof(PARAM_MTK_SLT_TEST_STRUC_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvQueryBuffer); + + prMtkSltInfo = (P_PARAM_MTK_SLT_TEST_STRUC_T)pvQueryBuffer; + + prSltInfo = &(prAdapter->rWifiVar.rSltInfo); + + switch (prMtkSltInfo->rSltFuncIdx) { + case ENUM_MTK_SLT_FUNC_LP_SET: + { + P_PARAM_MTK_SLT_LP_TEST_STRUC_T prLpSetting = (P_PARAM_MTK_SLT_LP_TEST_STRUC_T)NULL; + + ASSERT(prMtkSltInfo->u4FuncInfoLen == sizeof(PARAM_MTK_SLT_LP_TEST_STRUC_T)); + + prLpSetting = (P_PARAM_MTK_SLT_LP_TEST_STRUC_T)&prMtkSltInfo->unFuncInfoContent; + + prLpSetting->u4BcnRcvNum = prSltInfo->u4BeaconReceiveCnt; + } + break; + default: + // TBD... + break; + } + + return rWlanStatus; +} /* wlanoidQuerySLTStatus */ + +WLAN_STATUS +wlanoidUpdateSLTMode ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + P_PARAM_MTK_SLT_TEST_STRUC_T prMtkSltInfo = (P_PARAM_MTK_SLT_TEST_STRUC_T)NULL; + P_SLT_INFO_T prSltInfo = (P_SLT_INFO_T)NULL; + P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T)NULL; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + P_BSS_INFO_T prBssInfo = (P_BSS_INFO_T)NULL; + + /* 1. Action: Update or Initial Set + * 2. Role. + * 3. Target MAC address. + * 4. RF BW & Rate Settings + */ + + DEBUGFUNC("wlanoidUpdateSLTMode"); + DBGLOG(REQ, LOUD, ("\r\n")); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_MTK_SLT_TEST_STRUC_T); + + if (u4SetBufferLen < sizeof(PARAM_MTK_SLT_TEST_STRUC_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prMtkSltInfo = (P_PARAM_MTK_SLT_TEST_STRUC_T) pvSetBuffer; + + prSltInfo = &(prAdapter->rWifiVar.rSltInfo); + prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; + + switch (prMtkSltInfo->rSltFuncIdx) { + case ENUM_MTK_SLT_FUNC_INITIAL: /* Initialize */ + { + P_PARAM_MTK_SLT_INITIAL_STRUC_T prMtkSltInit = (P_PARAM_MTK_SLT_INITIAL_STRUC_T)NULL; + + ASSERT(prMtkSltInfo->u4FuncInfoLen == sizeof(PARAM_MTK_SLT_INITIAL_STRUC_T)); + + prMtkSltInit = (P_PARAM_MTK_SLT_INITIAL_STRUC_T)&prMtkSltInfo->unFuncInfoContent; + + if (prSltInfo->prPseudoStaRec != NULL) { + /* The driver has been initialized. */ + prSltInfo->prPseudoStaRec = NULL; + } + + + prSltInfo->prPseudoBssDesc = scanSearchExistingBssDesc(prAdapter, + BSS_TYPE_IBSS, + prMtkSltInit->aucTargetMacAddr, + prMtkSltInit->aucTargetMacAddr); + + prSltInfo->u2SiteID = prMtkSltInit->u2SiteID; + + /* Bandwidth 2.4G: Channel 1~14 + * Bandwidth 5G: *36, 40, 44, 48, 52, 56, 60, 64, + * *100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, + * 149, 153, *157, 161, + * 184, 188, 192, 196, 200, 204, 208, 212, *216 + */ + prSltInfo->ucChannel2G4 = 1 + (prSltInfo->u2SiteID % 4) * 5; + + switch (prSltInfo->ucChannel2G4) { + case 1: + prSltInfo->ucChannel5G = 36; + break; + case 6: + prSltInfo->ucChannel5G = 52; + break; + case 11: + prSltInfo->ucChannel5G = 104; + break; + case 16: + prSltInfo->ucChannel2G4 = 14; + prSltInfo->ucChannel5G = 161; + break; + default: + ASSERT(FALSE); + } + + if (prSltInfo->prPseudoBssDesc == NULL) { + do { + prSltInfo->prPseudoBssDesc = scanAllocateBssDesc(prAdapter); + + if (prSltInfo->prPseudoBssDesc == NULL) { + rWlanStatus = WLAN_STATUS_FAILURE; + break; + } + else { + prBssDesc = prSltInfo->prPseudoBssDesc; + } + } while (FALSE); + } + else { + prBssDesc = prSltInfo->prPseudoBssDesc; + } + + if (prBssDesc) { + prBssDesc->eBSSType = BSS_TYPE_IBSS; + + COPY_MAC_ADDR(prBssDesc->aucSrcAddr, prMtkSltInit->aucTargetMacAddr); + COPY_MAC_ADDR(prBssDesc->aucBSSID, prBssInfo->aucOwnMacAddr); + + prBssDesc->u2BeaconInterval = 100; + prBssDesc->u2ATIMWindow = 0; + prBssDesc->ucDTIMPeriod = 1; + + prBssDesc->u2IELength = 0; + + prBssDesc->fgIsERPPresent = TRUE; + prBssDesc->fgIsHTPresent = TRUE; + + prBssDesc->u2OperationalRateSet = BIT(RATE_36M_INDEX); + prBssDesc->u2BSSBasicRateSet = BIT(RATE_36M_INDEX); + prBssDesc->fgIsUnknownBssBasicRate = FALSE; + + prBssDesc->fgIsLargerTSF = TRUE; + + prBssDesc->eBand = BAND_2G4; + + prBssDesc->ucChannelNum = prSltInfo->ucChannel2G4; + + prBssDesc->ucPhyTypeSet = PHY_TYPE_SET_802_11ABGN; + + GET_CURRENT_SYSTIME(&prBssDesc->rUpdateTime); + } + } + break; + case ENUM_MTK_SLT_FUNC_RATE_SET: /* Update RF Settings. */ + if (prSltInfo->prPseudoStaRec == NULL) { + rWlanStatus = WLAN_STATUS_FAILURE; + } + else { + P_PARAM_MTK_SLT_TR_TEST_STRUC_T prTRSetting = (P_PARAM_MTK_SLT_TR_TEST_STRUC_T)NULL; + + ASSERT(prMtkSltInfo->u4FuncInfoLen == sizeof(PARAM_MTK_SLT_TR_TEST_STRUC_T)); + + prStaRec = prSltInfo->prPseudoStaRec; + prTRSetting = (P_PARAM_MTK_SLT_TR_TEST_STRUC_T)&prMtkSltInfo->unFuncInfoContent; + + if (prTRSetting->rNetworkType == PARAM_NETWORK_TYPE_OFDM5) { + prBssInfo->eBand = BAND_5G; + prBssInfo->ucPrimaryChannel = prSltInfo->ucChannel5G; + } + if (prTRSetting->rNetworkType == PARAM_NETWORK_TYPE_OFDM24) { + prBssInfo->eBand = BAND_2G4; + prBssInfo->ucPrimaryChannel = prSltInfo->ucChannel2G4; + } + + if ((prTRSetting->u4FixedRate & FIXED_BW_DL40) != 0) { + /* RF 40 */ + prStaRec->u2HtCapInfo |= HT_CAP_INFO_SUP_CHNL_WIDTH; /* It would controls RFBW capability in WTBL. */ + prStaRec->ucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; /* This controls RF BW, RF BW would be 40 only if + * 1. PHY_TYPE_BIT_HT is TRUE. + * 2. SCO is SCA/SCB. + */ + + /* U20/L20 Control. */ + switch (prTRSetting->u4FixedRate & 0xC000) { + case FIXED_EXT_CHNL_U20: + prBssInfo->eBssSCO = CHNL_EXT_SCB; // +2 + if (prTRSetting->rNetworkType == PARAM_NETWORK_TYPE_OFDM5) { + prBssInfo->ucPrimaryChannel += 2; + } + else { + if (prBssInfo->ucPrimaryChannel <5) { + prBssInfo->ucPrimaryChannel = 8; // For channel 1, testing L20 at channel 8. + } + } + break; + case FIXED_EXT_CHNL_L20: + default: /* 40M */ + prBssInfo->eBssSCO = CHNL_EXT_SCA; // -2 + if (prTRSetting->rNetworkType == PARAM_NETWORK_TYPE_OFDM5) { + prBssInfo->ucPrimaryChannel -= 2; + } + else { + if (prBssInfo->ucPrimaryChannel > 10) { + prBssInfo->ucPrimaryChannel = 3; // For channel 11 / 14. testing U20 at channel 3. + } + } + break; + } + } + else { + /* RF 20 */ + prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_SUP_CHNL_WIDTH; + prBssInfo->eBssSCO = CHNL_EXT_SCN; + } + + prBssInfo->fgErpProtectMode = FALSE; + prBssInfo->eHtProtectMode = HT_PROTECT_MODE_NONE; + prBssInfo->eGfOperationMode = GF_MODE_NORMAL; + + nicUpdateBss(prAdapter, prBssInfo->ucNetTypeIndex); + + prStaRec->u2HtCapInfo &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M); + + switch (prTRSetting->u4FixedRate & 0xFF) { + case RATE_OFDM_54M: + prStaRec->u2DesiredNonHTRateSet = BIT(RATE_54M_INDEX); + break; + case RATE_OFDM_48M: + prStaRec->u2DesiredNonHTRateSet = BIT(RATE_48M_INDEX); + break; + case RATE_OFDM_36M: + prStaRec->u2DesiredNonHTRateSet = BIT(RATE_36M_INDEX); + break; + case RATE_OFDM_24M: + prStaRec->u2DesiredNonHTRateSet = BIT(RATE_24M_INDEX); + break; + case RATE_OFDM_6M: + prStaRec->u2DesiredNonHTRateSet = BIT(RATE_6M_INDEX); + break; + case RATE_CCK_11M_LONG: + prStaRec->u2DesiredNonHTRateSet = BIT(RATE_11M_INDEX); + break; + case RATE_CCK_1M_LONG: + prStaRec->u2DesiredNonHTRateSet = BIT(RATE_1M_INDEX); + break; + case RATE_GF_MCS_0: + prStaRec->u2DesiredNonHTRateSet = BIT(RATE_HT_PHY_INDEX); + prStaRec->u2HtCapInfo |= HT_CAP_INFO_HT_GF; + break; + case RATE_MM_MCS_7: + prStaRec->u2DesiredNonHTRateSet = BIT(RATE_HT_PHY_INDEX); + prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_HT_GF; +#if 0 // Only for Current Measurement Mode. + prStaRec->u2HtCapInfo |= (HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M); +#endif + break; + case RATE_GF_MCS_7: + prStaRec->u2DesiredNonHTRateSet = BIT(RATE_HT_PHY_INDEX); + prStaRec->u2HtCapInfo |= HT_CAP_INFO_HT_GF; + break; + default: + prStaRec->u2DesiredNonHTRateSet = BIT(RATE_36M_INDEX); + break; + } + + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + + } + break; + case ENUM_MTK_SLT_FUNC_LP_SET: /* Reset LP Test Result. */ + { + P_PARAM_MTK_SLT_LP_TEST_STRUC_T prLpSetting = (P_PARAM_MTK_SLT_LP_TEST_STRUC_T)NULL; + + ASSERT(prMtkSltInfo->u4FuncInfoLen == sizeof(PARAM_MTK_SLT_LP_TEST_STRUC_T)); + + prLpSetting = (P_PARAM_MTK_SLT_LP_TEST_STRUC_T)&prMtkSltInfo->unFuncInfoContent; + + if (prSltInfo->prPseudoBssDesc == NULL) { + /* Please initial SLT Mode first. */ + break; + } + else { + prBssDesc = prSltInfo->prPseudoBssDesc; + } + + switch (prLpSetting->rLpTestMode) { + case ENUM_MTK_LP_TEST_NORMAL: + /* In normal mode, we would use target MAC address to be the BSSID. */ + COPY_MAC_ADDR(prBssDesc->aucBSSID, prBssInfo->aucOwnMacAddr); + prSltInfo->fgIsDUT = FALSE; + break; + case ENUM_MTK_LP_TEST_GOLDEN_SAMPLE: + /* 1. Lower AIFS of BCN queue. + * 2. Fixed Random Number tobe 0. + */ + prSltInfo->fgIsDUT = FALSE; + /* In LP test mode, we would use MAC address of Golden Sample to be the BSSID. */ + COPY_MAC_ADDR(prBssDesc->aucBSSID, prBssInfo->aucOwnMacAddr); + break; + case ENUM_MTK_LP_TEST_DUT: + /* 1. Enter Sleep Mode. + * 2. Fix random number a large value & enlarge AIFN of BCN queue. + */ + COPY_MAC_ADDR(prBssDesc->aucBSSID, prBssDesc->aucSrcAddr); + prSltInfo->u4BeaconReceiveCnt = 0; + prSltInfo->fgIsDUT = TRUE; + break; + } + + } + + break; + default: + break; + } + + + + + return WLAN_STATUS_FAILURE; + + + return rWlanStatus; +} /* wlanoidUpdateSLTMode */ +#endif + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query NVRAM value. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryNvramRead ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T prNvramRwInfo; + UINT_16 u2Data; + BOOLEAN fgStatus; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidQueryNvramRead"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T); + + if (u4QueryBufferLen < sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + prNvramRwInfo = (P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T)pvQueryBuffer; + + if(prNvramRwInfo->ucEepromMethod == PARAM_EEPROM_READ_METHOD_READ) { + fgStatus = kalCfgDataRead16(prAdapter->prGlueInfo, + prNvramRwInfo->ucEepromIndex << 1, /* change to byte offset */ + &u2Data); + + if(fgStatus) { + prNvramRwInfo->u2EepromData = u2Data; + DBGLOG(REQ, INFO, ("NVRAM Read: index=%#X, data=%#02X\r\n", + prNvramRwInfo->ucEepromIndex, u2Data)); + } + else{ + DBGLOG(REQ, ERROR, ("NVRAM Read Failed: index=%#x.\r\n", + prNvramRwInfo->ucEepromIndex)); + rStatus = WLAN_STATUS_FAILURE; + } + } + else if (prNvramRwInfo->ucEepromMethod == PARAM_EEPROM_READ_METHOD_GETSIZE) { + prNvramRwInfo->u2EepromData = CFG_FILE_WIFI_REC_SIZE; + DBGLOG(REQ, INFO, ("EEPROM size =%d\r\n", prNvramRwInfo->u2EepromData)); + } + + *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_EEPROM_RW_STRUC_T); + + return rStatus; +} /* wlanoidQueryNvramRead */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to write NVRAM value. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetNvramWrite ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T prNvramRwInfo; + BOOLEAN fgStatus; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + + DEBUGFUNC("wlanoidSetNvramWrite"); + DBGLOG(INIT, LOUD,("\n")); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prNvramRwInfo = (P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T)pvSetBuffer; + + fgStatus = kalCfgDataWrite16(prAdapter->prGlueInfo, + prNvramRwInfo->ucEepromIndex << 1, /* change to byte offset */ + prNvramRwInfo->u2EepromData + ); + + if(fgStatus == FALSE){ + DBGLOG(REQ, ERROR, ("NVRAM Write Failed.\r\n")); + rStatus = WLAN_STATUS_FAILURE; + } + + return rStatus; +} /* wlanoidSetNvramWrite */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to get the config data source type. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryCfgSrcType( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + ASSERT(prAdapter); + + *pu4QueryInfoLen = sizeof(ENUM_CFG_SRC_TYPE_T); + + if(kalIsConfigurationExist(prAdapter->prGlueInfo) == TRUE) { + *(P_ENUM_CFG_SRC_TYPE_T)pvQueryBuffer = CFG_SRC_TYPE_NVRAM; + } + else { + *(P_ENUM_CFG_SRC_TYPE_T)pvQueryBuffer = CFG_SRC_TYPE_EEPROM; + } + + return WLAN_STATUS_SUCCESS; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to get the config data source type. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryEepromType( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + ASSERT(prAdapter); + + *pu4QueryInfoLen = sizeof(P_ENUM_EEPROM_TYPE_T); + +#if CFG_SUPPORT_NIC_CAPABILITY + if(prAdapter->fgIsEepromUsed == TRUE) { + *( P_ENUM_EEPROM_TYPE_T )pvQueryBuffer = EEPROM_TYPE_PRESENT; + } + else { + *( P_ENUM_EEPROM_TYPE_T )pvQueryBuffer = EEPROM_TYPE_NO; + } +#else + *( P_ENUM_EEPROM_TYPE_T )pvQueryBuffer = EEPROM_TYPE_NO; +#endif + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to get the config data source type. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetCountryCode ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + PUINT_8 pucCountry; + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(u4SetBufferLen == 2); + + *pu4SetInfoLen = 2; + + pucCountry = pvSetBuffer; + + prAdapter->rWifiVar.rConnSettings.u2CountryCode = + (((UINT_16) pucCountry[0]) << 8) | ((UINT_16) pucCountry[1]) ; + + prAdapter->prDomainInfo = NULL; /* Force to re-search country code */ + rlmDomainSendCmd(prAdapter, TRUE); + + return WLAN_STATUS_SUCCESS; +} + +#if 0 +WLAN_STATUS +wlanoidSetNoaParam ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_PARAM_CUSTOM_NOA_PARAM_STRUC_T prNoaParam; + CMD_CUSTOM_NOA_PARAM_STRUC_T rCmdNoaParam; + + DEBUGFUNC("wlanoidSetNoaParam"); + DBGLOG(INIT, LOUD,("\n")); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_NOA_PARAM_STRUC_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_NOA_PARAM_STRUC_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prNoaParam = (P_PARAM_CUSTOM_NOA_PARAM_STRUC_T)pvSetBuffer; + + kalMemZero(&rCmdNoaParam, sizeof(CMD_CUSTOM_NOA_PARAM_STRUC_T)); + rCmdNoaParam.u4NoaDurationMs = prNoaParam->u4NoaDurationMs; + rCmdNoaParam.u4NoaIntervalMs = prNoaParam->u4NoaIntervalMs; + rCmdNoaParam.u4NoaCount = prNoaParam->u4NoaCount; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_NOA_PARAM, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_CUSTOM_NOA_PARAM_STRUC_T), + (PUINT_8)&rCmdNoaParam, + pvSetBuffer, + u4SetBufferLen + ); +} + +WLAN_STATUS +wlanoidSetOppPsParam ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_PARAM_CUSTOM_OPPPS_PARAM_STRUC_T prOppPsParam; + CMD_CUSTOM_OPPPS_PARAM_STRUC_T rCmdOppPsParam; + + DEBUGFUNC("wlanoidSetOppPsParam"); + DBGLOG(INIT, LOUD,("\n")); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_OPPPS_PARAM_STRUC_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_OPPPS_PARAM_STRUC_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prOppPsParam = (P_PARAM_CUSTOM_OPPPS_PARAM_STRUC_T)pvSetBuffer; + + kalMemZero(&rCmdOppPsParam, sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUC_T)); + rCmdOppPsParam.u4CTwindowMs = prOppPsParam->u4CTwindowMs; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_OPPPS_PARAM, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUC_T), + (PUINT_8)&rCmdOppPsParam, + pvSetBuffer, + u4SetBufferLen + ); +} + +WLAN_STATUS +wlanoidSetUApsdParam ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + P_PARAM_CUSTOM_UAPSD_PARAM_STRUC_T prUapsdParam; + CMD_CUSTOM_UAPSD_PARAM_STRUC_T rCmdUapsdParam; + P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo; + P_BSS_INFO_T prBssInfo; + + + DEBUGFUNC("wlanoidSetUApsdParam"); + DBGLOG(INIT, LOUD,("\n")); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_UAPSD_PARAM_STRUC_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_UAPSD_PARAM_STRUC_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; + + prUapsdParam = (P_PARAM_CUSTOM_UAPSD_PARAM_STRUC_T)pvSetBuffer; + + kalMemZero(&rCmdUapsdParam, sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUC_T)); + rCmdUapsdParam.fgEnAPSD = prUapsdParam->fgEnAPSD; + prAdapter->rWifiVar.fgSupportUAPSD = prUapsdParam->fgEnAPSD; + + rCmdUapsdParam.fgEnAPSD_AcBe = prUapsdParam->fgEnAPSD_AcBe; + rCmdUapsdParam.fgEnAPSD_AcBk = prUapsdParam->fgEnAPSD_AcBk; + rCmdUapsdParam.fgEnAPSD_AcVo = prUapsdParam->fgEnAPSD_AcVo; + rCmdUapsdParam.fgEnAPSD_AcVi = prUapsdParam->fgEnAPSD_AcVi; + prPmProfSetupInfo->ucBmpDeliveryAC = + ((prUapsdParam->fgEnAPSD_AcBe << 0) | + (prUapsdParam->fgEnAPSD_AcBk << 1) | + (prUapsdParam->fgEnAPSD_AcVi << 2) | + (prUapsdParam->fgEnAPSD_AcVo << 3)); + prPmProfSetupInfo->ucBmpTriggerAC = + ((prUapsdParam->fgEnAPSD_AcBe << 0) | + (prUapsdParam->fgEnAPSD_AcBk << 1) | + (prUapsdParam->fgEnAPSD_AcVi << 2) | + (prUapsdParam->fgEnAPSD_AcVo << 3)); + + rCmdUapsdParam.ucMaxSpLen = prUapsdParam->ucMaxSpLen; + prPmProfSetupInfo->ucUapsdSp = prUapsdParam->ucMaxSpLen; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_UAPSD_PARAM, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUC_T), + (PUINT_8)&rCmdUapsdParam, + pvSetBuffer, + u4SetBufferLen + ); +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set BT profile or BT information and the +* driver will set the built-in PTA configuration into chip. +* +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetBT ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + + P_PTA_IPC_T prPtaIpc; + + DEBUGFUNC("wlanoidSetBT.\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PTA_IPC_T); + if (u4SetBufferLen != sizeof(PTA_IPC_T)) { + WARNLOG(("Invalid length %ld\n", u4SetBufferLen)); + return WLAN_STATUS_INVALID_LENGTH; + } + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail to set BT profile because of ACPI_D3\n")); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + ASSERT(pvSetBuffer); + prPtaIpc = (P_PTA_IPC_T)pvSetBuffer; + +#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS && CFG_SUPPORT_BCM_BWCS_DEBUG + printk(KERN_INFO DRV_NAME "BCM BWCS CMD: BWCS CMD = %02x%02x%02x%02x\n", + prPtaIpc->u.aucBTPParams[0], prPtaIpc->u.aucBTPParams[1], prPtaIpc->u.aucBTPParams[2], prPtaIpc->u.aucBTPParams[3]); + + printk(KERN_INFO DRV_NAME "BCM BWCS CMD: aucBTPParams[0] = %02x, aucBTPParams[1] = %02x, aucBTPParams[2] = %02x, aucBTPParams[3] = %02x.\n", + prPtaIpc->u.aucBTPParams[0], + prPtaIpc->u.aucBTPParams[1], + prPtaIpc->u.aucBTPParams[2], + prPtaIpc->u.aucBTPParams[3]); +#endif + + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_BWCS, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(PTA_IPC_T), + (PUINT_8)prPtaIpc, + NULL, + 0); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query current BT profile and BTCR values +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryBT ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ +// P_PARAM_PTA_IPC_T prPtaIpc; +// UINT_32 u4QueryBuffLen; + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(PTA_IPC_T); + + /* Check for query buffer length */ + if (u4QueryBufferLen != sizeof(PTA_IPC_T)) { + DBGLOG(REQ, WARN, ("Invalid length %lu\n", u4QueryBufferLen)); + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvQueryBuffer); +// prPtaIpc = (P_PTA_IPC_T)pvQueryBuffer; +// prPtaIpc->ucCmd = BT_CMD_PROFILE; +// prPtaIpc->ucLen = sizeof(prPtaIpc->u); +// nicPtaGetProfile(prAdapter, (PUINT_8)&prPtaIpc->u, &u4QueryBuffLen); + + return WLAN_STATUS_SUCCESS; +} + +#if 0 +WLAN_STATUS +wlanoidQueryBtSingleAntenna ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + P_PTA_INFO_T prPtaInfo; + PUINT_32 pu4SingleAntenna; + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(UINT_32); + + /* Check for query buffer length */ + if (u4QueryBufferLen != sizeof(UINT_32)) { + DBGLOG(REQ, WARN, ("Invalid length %lu\n", u4QueryBufferLen)); + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvQueryBuffer); + + prPtaInfo = &prAdapter->rPtaInfo; + pu4SingleAntenna = (PUINT_32)pvQueryBuffer; + + if(prPtaInfo->fgSingleAntenna) { + //printk(KERN_WARNING DRV_NAME"Q Single Ant = 1\r\n"); + *pu4SingleAntenna = 1; + } else { + //printk(KERN_WARNING DRV_NAME"Q Single Ant = 0\r\n"); + *pu4SingleAntenna = 0; + } + + return WLAN_STATUS_SUCCESS; +} + + +WLAN_STATUS +wlanoidSetBtSingleAntenna ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + + PUINT_32 pu4SingleAntenna; + UINT_32 u4SingleAntenna; + P_PTA_INFO_T prPtaInfo; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + prPtaInfo = &prAdapter->rPtaInfo; + + *pu4SetInfoLen = sizeof(UINT_32); + if (u4SetBufferLen != sizeof(UINT_32)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + if (IS_ARB_IN_RFTEST_STATE(prAdapter)) { + return WLAN_STATUS_SUCCESS; + } + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail to set antenna because of ACPI_D3\n")); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + ASSERT(pvSetBuffer); + pu4SingleAntenna = (PUINT_32)pvSetBuffer; + u4SingleAntenna = *pu4SingleAntenna; + + if (u4SingleAntenna == 0) { + //printk(KERN_WARNING DRV_NAME"Set Single Ant = 0\r\n"); + prPtaInfo->fgSingleAntenna = FALSE; + } else { + //printk(KERN_WARNING DRV_NAME"Set Single Ant = 1\r\n"); + prPtaInfo->fgSingleAntenna = TRUE; + } + ptaFsmRunEventSetConfig(prAdapter, &prPtaInfo->rPtaParam); + + return WLAN_STATUS_SUCCESS; +} + + +#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS +WLAN_STATUS +wlanoidQueryPta ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + P_PTA_INFO_T prPtaInfo; + PUINT_32 pu4Pta; + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(UINT_32); + + /* Check for query buffer length */ + if (u4QueryBufferLen != sizeof(UINT_32)) { + DBGLOG(REQ, WARN, ("Invalid length %lu\n", u4QueryBufferLen)); + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvQueryBuffer); + + prPtaInfo = &prAdapter->rPtaInfo; + pu4Pta = (PUINT_32)pvQueryBuffer; + + if(prPtaInfo->fgEnabled) { + //printk(KERN_WARNING DRV_NAME"PTA = 1\r\n"); + *pu4Pta = 1; + } else { + //printk(KERN_WARNING DRV_NAME"PTA = 0\r\n"); + *pu4Pta = 0; + } + + return WLAN_STATUS_SUCCESS; +} + + +WLAN_STATUS +wlanoidSetPta ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + PUINT_32 pu4PtaCtrl; + UINT_32 u4PtaCtrl; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(UINT_32); + if (u4SetBufferLen != sizeof(UINT_32)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + if (IS_ARB_IN_RFTEST_STATE(prAdapter)) { + return WLAN_STATUS_SUCCESS; + } + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail to set BT setting because of ACPI_D3\n")); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + ASSERT(pvSetBuffer); + pu4PtaCtrl = (PUINT_32)pvSetBuffer; + u4PtaCtrl = *pu4PtaCtrl; + + if (u4PtaCtrl == 0) { + //printk(KERN_WARNING DRV_NAME"Set Pta= 0\r\n"); + nicPtaSetFunc(prAdapter, FALSE); + } else { + //printk(KERN_WARNING DRV_NAME"Set Pta= 1\r\n"); + nicPtaSetFunc(prAdapter, TRUE); + } + + return WLAN_STATUS_SUCCESS; +} +#endif + +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set Tx power profile. +* +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetTxPower ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + //P_SET_TXPWR_CTRL_T pTxPwr = (P_SET_TXPWR_CTRL_T)pvSetBuffer; + //UINT_32 i; + WLAN_STATUS rStatus; + + DEBUGFUNC("wlanoidSetTxPower"); + DBGLOG(REQ, LOUD, ("\r\n")); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + +#if 0 + printk("c2GLegacyStaPwrOffset=%d\n", pTxPwr->c2GLegacyStaPwrOffset); + printk("c2GHotspotPwrOffset=%d\n", pTxPwr->c2GHotspotPwrOffset); + printk("c2GP2pPwrOffset=%d\n", pTxPwr->c2GP2pPwrOffset); + printk("c2GBowPwrOffset=%d\n", pTxPwr->c2GBowPwrOffset); + printk("c5GLegacyStaPwrOffset=%d\n", pTxPwr->c5GLegacyStaPwrOffset); + printk("c5GHotspotPwrOffset=%d\n", pTxPwr->c5GHotspotPwrOffset); + printk("c5GP2pPwrOffset=%d\n", pTxPwr->c5GP2pPwrOffset); + printk("c5GBowPwrOffset=%d\n", pTxPwr->c5GBowPwrOffset); + printk("ucConcurrencePolicy=%d\n", pTxPwr->ucConcurrencePolicy); + + for (i=0; i<14;i++) + printk("acTxPwrLimit2G[%d]=%d\n", i, pTxPwr->acTxPwrLimit2G[i]); + + for (i=0; i<4;i++) + printk("acTxPwrLimit5G[%d]=%d\n", i, pTxPwr->acTxPwrLimit5G[i]); +#endif + + rStatus = wlanSendSetQueryCmd ( + prAdapter, /* prAdapter */ + CMD_ID_SET_TXPWR_CTRL, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + TRUE, /* fgIsOid */ + NULL, /* pfCmdDoneHandler*/ + NULL, /* pfCmdTimeoutHandler */ + u4SetBufferLen, /* u4SetQueryInfoLen */ + (PUINT_8) pvSetBuffer, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + ASSERT(rStatus == WLAN_STATUS_PENDING); + + return rStatus; + +} + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/CFG_Wifi_File.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/CFG_Wifi_File.h new file mode 100755 index 000000000000..6b253ef4cf5e --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/CFG_Wifi_File.h @@ -0,0 +1,284 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/CFG_Wifi_File.h#1 $ +*/ + +/*! \file CFG_Wifi_File.h + \brief Collection of NVRAM structure used for YuSu project + + In this file we collect all compiler flags and detail the driver behavior if + enable/disable such switch or adjust numeric parameters. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: CFG_Wifi_File.h $ + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 05 27 2011 cp.wu + * [WCXRP00000749] [MT6620 Wi-Fi][Driver] Add band edge tx power control to Wi-Fi NVRAM + * update NVRAM data structure definition. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 10 2011 cp.wu + * [WCXRP00000532] [MT6620 Wi-Fi][Driver] Migrate NVRAM configuration procedures from MT6620 E2 to MT6620 E3 + * deprecate configuration used by MT6620 E2 + * + * 10 26 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command + * 1) update NVRAM content template to ver 1.02 + * 2) add compile option for querying NIC capability (default: off) + * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting + * 4) correct auto-rate compiler error under linux (treat warning as error) + * 5) simplify usage of NVRAM and REG_INFO_T + * 6) add version checking between driver and firmware + * + * 10 25 2010 cp.wu + * [WCXRP00000133] [MT6620 Wi-Fi] [FW][Driver] Change TX power offset band definition + * follow-up for CMD_5G_PWR_OFFSET_T definition change + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * 1) add NVRAM access API + * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) + * 3) add OID implementation for NVRAM read/write service + * + * 09 23 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * add skeleton for NVRAM integration + * +*/ + +#ifndef _CFG_WIFI_FILE_H +#define _CFG_WIFI_FILE_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "gl_typedef.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +// duplicated from nic_cmd_event.h to avoid header dependency +typedef struct _TX_PWR_PARAM_T { + INT_8 cTxPwr2G4Cck; /* signed, in unit of 0.5dBm */ +#if defined(MT6620) + INT_8 acReserved[3]; +#elif defined(MT5931) || defined(MT6628) + INT_8 cTxPwr2G4Dsss; /* signed, in unit of 0.5dBm */ + INT_8 acReserved[2]; +#else + #error "No valid definition!" +#endif + + INT_8 cTxPwr2G4OFDM_BPSK; + INT_8 cTxPwr2G4OFDM_QPSK; + INT_8 cTxPwr2G4OFDM_16QAM; + INT_8 cTxPwr2G4OFDM_Reserved; + INT_8 cTxPwr2G4OFDM_48Mbps; + INT_8 cTxPwr2G4OFDM_54Mbps; + + INT_8 cTxPwr2G4HT20_BPSK; + INT_8 cTxPwr2G4HT20_QPSK; + INT_8 cTxPwr2G4HT20_16QAM; + INT_8 cTxPwr2G4HT20_MCS5; + INT_8 cTxPwr2G4HT20_MCS6; + INT_8 cTxPwr2G4HT20_MCS7; + + INT_8 cTxPwr2G4HT40_BPSK; + INT_8 cTxPwr2G4HT40_QPSK; + INT_8 cTxPwr2G4HT40_16QAM; + INT_8 cTxPwr2G4HT40_MCS5; + INT_8 cTxPwr2G4HT40_MCS6; + INT_8 cTxPwr2G4HT40_MCS7; + + INT_8 cTxPwr5GOFDM_BPSK; + INT_8 cTxPwr5GOFDM_QPSK; + INT_8 cTxPwr5GOFDM_16QAM; + INT_8 cTxPwr5GOFDM_Reserved; + INT_8 cTxPwr5GOFDM_48Mbps; + INT_8 cTxPwr5GOFDM_54Mbps; + + INT_8 cTxPwr5GHT20_BPSK; + INT_8 cTxPwr5GHT20_QPSK; + INT_8 cTxPwr5GHT20_16QAM; + INT_8 cTxPwr5GHT20_MCS5; + INT_8 cTxPwr5GHT20_MCS6; + INT_8 cTxPwr5GHT20_MCS7; + + INT_8 cTxPwr5GHT40_BPSK; + INT_8 cTxPwr5GHT40_QPSK; + INT_8 cTxPwr5GHT40_16QAM; + INT_8 cTxPwr5GHT40_MCS5; + INT_8 cTxPwr5GHT40_MCS6; + INT_8 cTxPwr5GHT40_MCS7; +} TX_PWR_PARAM_T, *P_TX_PWR_PARAM_T; + +typedef struct _PWR_5G_OFFSET_T { + INT_8 cOffsetBand0; /* 4.915-4.980G */ + INT_8 cOffsetBand1; /* 5.000-5.080G */ + INT_8 cOffsetBand2; /* 5.160-5.180G */ + INT_8 cOffsetBand3; /* 5.200-5.280G */ + INT_8 cOffsetBand4; /* 5.300-5.340G */ + INT_8 cOffsetBand5; /* 5.500-5.580G */ + INT_8 cOffsetBand6; /* 5.600-5.680G */ + INT_8 cOffsetBand7; /* 5.700-5.825G */ +} PWR_5G_OFFSET_T, *P_PWR_5G_OFFSET_T; + +typedef struct _PWR_PARAM_T { + UINT_32 au4Data[28]; + UINT_32 u4RefValue1; + UINT_32 u4RefValue2; +} PWR_PARAM_T, *P_PWR_PARAM_T; + +typedef struct _MT6620_CFG_PARAM_STRUCT { + /* 256 bytes of MP data */ + UINT_16 u2Part1OwnVersion; + UINT_16 u2Part1PeerVersion; + UINT_8 aucMacAddress[6]; + UINT_8 aucCountryCode[2]; + TX_PWR_PARAM_T rTxPwr; + UINT_8 aucEFUSE[144]; + UINT_8 ucTxPwrValid; + UINT_8 ucSupport5GBand; + UINT_8 fg2G4BandEdgePwrUsed; + INT_8 cBandEdgeMaxPwrCCK; + INT_8 cBandEdgeMaxPwrOFDM20; + INT_8 cBandEdgeMaxPwrOFDM40; + + UINT_8 ucRegChannelListMap; + UINT_8 ucRegChannelListIndex; + UINT_8 aucRegSubbandInfo[36]; + + UINT_8 aucReserved2[256-240]; + + /* 256 bytes of function data */ + UINT_16 u2Part2OwnVersion; + UINT_16 u2Part2PeerVersion; + UINT_8 uc2G4BwFixed20M; + UINT_8 uc5GBwFixed20M; + UINT_8 ucEnable5GBand; + UINT_8 aucPreTailReserved; + UINT_8 aucTailReserved[256-8]; +} MT6620_CFG_PARAM_STRUCT, *P_MT6620_CFG_PARAM_STRUCT, + WIFI_CFG_PARAM_STRUCT, *P_WIFI_CFG_PARAM_STRUCT; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifndef DATA_STRUC_INSPECTING_ASSERT +#define DATA_STRUC_INSPECTING_ASSERT(expr) \ + switch (0) {case 0: case (expr): default:;} +#endif + +#define CFG_FILE_WIFI_REC_SIZE sizeof(WIFI_CFG_PARAM_STRUCT) + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#ifndef _lint +/* We don't have to call following function to inspect the data structure. + * It will check automatically while at compile time. + * We'll need this to guarantee the same member order in different structures + * to simply handling effort in some functions. + */ +__KAL_INLINE__ VOID +nvramOffsetCheck ( + VOID + ) +{ + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part2OwnVersion) == 256); + + DATA_STRUC_INSPECTING_ASSERT( + sizeof(WIFI_CFG_PARAM_STRUCT) == 512); + + DATA_STRUC_INSPECTING_ASSERT( + (OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucEFUSE) & 0x0001) == 0); + + DATA_STRUC_INSPECTING_ASSERT( + (OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucRegSubbandInfo) & 0x0001) == 0); +} +#endif + +#endif /* _CFG_WIFI_FILE_H */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/config.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/config.h new file mode 100755 index 000000000000..5bc1eb89991f --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/config.h @@ -0,0 +1,1410 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/config.h#3 $ +*/ + +/*! \file "config.h" + \brief This file includes the various configurable parameters for customers + + This file ncludes the configurable parameters except the paramters indicate the turning-on/off of some features +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: config.h $ + * + * 01 20 2012 cp.wu + * [ALPS00096191] [MT6620 Wi-Fi][Driver][Firmware] Porting to ALPS4.0_DEV branch + * sync to up-to-date changes including: + * 1. BOW bugfix + * 2. XLOG + * + * 01 16 2012 terry.wu + * [WCXRP00001166] [Wi-Fi] [Driver] cfg80211 integration for p2p newtork + * Remove CFG80211_DUMMY_CALLBACK temp config. + * + * 01 09 2012 terry.wu + * [WCXRP00001166] [Wi-Fi] [Driver] cfg80211 integration for p2p newtork + * cfg80211 integration for p2p network. + * + * 11 23 2011 cp.wu + * [WCXRP00001123] [MT6620 Wi-Fi][Driver] Add option to disable beacon content change detection + * add compile option to disable beacon content change detection. + * + * 11 19 2011 yuche.tsai + * NULL + * Add P2P RSSI Link Quality Query Support. (Default Off) + * + * 10 28 2011 cp.wu + * [MT6620 Wi-Fi][Win32 Driver] Enable 5GHz support as default + * enable 5GHz as default for DaVinci trunk and V2.1 driver release . + * + * 10 21 2011 terry.wu + * [WCXRP00001049] [MT6620 Wi-Fi] [Driver/FW] Sync branch 2.1 to ALPS + * Sync branch 2.1 configuration. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 08 12 2011 cp.wu + * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC + * load WIFI_RAM_CODE_E6 for MT6620 E6 ASIC. + * + * 07 05 2011 yuche.tsai + * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue + * Refine compile flag. + * + * 07 05 2011 yuche.tsai + * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue + * Add WiFi Direct Connection Enhancement. + * + * 06 29 2011 terry.wu + * NULL + * Add BoW 11n support. + * + * 06 27 2011 tsaiyuan.hsu + * [WCXRP00000816] [MT6620 Wi-Fi][Driver] add control to enable rx data dump or not + * add control to enable rx data dump by packet type. + * + * 06 01 2011 cm.chang + * [WCXRP00000756] [MT6620 Wi-Fi][Driver] 1. AIS follow channel of BOW 2. Provide legal channel function + * Limit AIS channel same with BOW when BOW is active + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 04 15 2011 cp.wu + * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for RESET_START and RESET_END events[WCXRP00000653] [MT6620 Wi-Fi][Firmware][Wi-Fi Task] Workaround for E3 MCU gating issue by masking HIF_EINT and invoking cos_get_subsystem_enable + * 1. add header dependency + * 2. sync config.h with ALPS release + * + * 04 14 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * Enable RX STBC capability + * + * 04 14 2011 cp.wu + * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for RESET_START and RESET_END events + * sync. whole-chip resetting mechanism to V2.0 branch. + * + * 04 11 2011 george.huang + * [WCXRP00000628] [MT6620 Wi-Fi][FW][Driver] Modify U-APSD setting to default OFF + * . + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 18 2011 wh.su + * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done + * enable the Anti_piracy check at driver . + * + * 03 17 2011 tsaiyuan.hsu + * [WCXRP00000517] [MT6620 Wi-Fi][Driver][FW] Fine Tune Performance of Roaming + * enable roaming feature. + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 03 15 2011 cp.wu + * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous memory consumption + * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK + * 2. Use common coalescing buffer for both TX/RX directions + * + * + * 03 15 2011 eddie.chen + * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter + * Add sw debug counter for QM. + * + * 03 07 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * rename the define to anti_pviracy. + * + * 03 06 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Sync BOW Driver to latest person development branch version.. + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * Add security check code. + * + * 03 01 2011 george.huang + * [WCXRP00000495] [MT6620 Wi-Fi][FW] Support pattern filter for unwanted ARP frames + * Fix compile issue + * + * 02 25 2011 george.huang + * [WCXRP00000497] [MT6620 Wi-Fi][FW] Change default UAPSD AC assignment + * Assign all AC default to be U-APSD enabled. + * + * 02 14 2011 wh.su + * [WCXRP00000432] [MT6620 Wi-Fi][Driver] Add STA privacy check at hotspot mode + * Let the privacy check at hotspot mode default enable. + * + * 02 09 2011 wh.su + * [WCXRP00000432] [MT6620 Wi-Fi][Driver] Add STA privacy check at hotspot mode + * adding the code for check STA privacy bit at AP mode, . + * + * 02 08 2011 cp.wu + * [WCXRP00000427] [MT6620 Wi-Fi][Driver] Modify veresion information to match with release revision number + * change version number to v1.2.0.0 for preparing v1.2 software package release. + * + * 02 01 2011 yarco.yang + * [WCXRP00000417] [MT6620 Driver] Chnage CFG_HANDLE_IST_IN_SDIO_CALLBACK from 1 to 0 for Interoperability + * . + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 01 19 2011 wh.su + * [WCXRP00000370] [MT6620 Wi-Fi][Driver] Disable Rx RDG for workaround pre-N ccmp issue + * Not announce support Rx RDG for wokaround pre-N ccmp construct AAD issue.. + * + * 01 15 2011 puff.wen + * NULL + * Add Stress test + * + * 01 12 2011 cp.wu + * [WCXRP00000356] [MT6620 Wi-Fi][Driver] fill mac header length for security frames 'cause hardware header translation needs such information + * fill mac header length information for 802.1x frames. + * + * 01 11 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Support BOW only for Linux. + * + * 01 10 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Enable BOW and 4 physical links. + * + * 01 08 2011 yuche.tsai + * [WCXRP00000345] [MT6620][Volunteer Patch] P2P may issue a SSID specified scan request, but the SSID length is still invalid. + * Modify CFG_SLT_SUPPORT default value. + * + * 01 08 2011 yuche.tsai + * [WCXRP00000341] [MT6620][SLT] Create Branch for SLT SW. + * Update configure flag. + * + * 12 28 2010 cp.wu + * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release + * report EEPROM used flag via NIC_CAPABILITY + * + * 12 28 2010 cp.wu + * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release + * integrate with 'EEPROM used' flag for reporting correct capability to Engineer Mode/META and other tools + * + * 12 15 2010 yuche.tsai + * NULL + * Update SLT Descriptor number configure in driver. + * + * 12 13 2010 chinglan.wang + * NULL + * Add WPS 1.0 feature flag to enable the WPS 1.0 function. + * + * 11 23 2010 george.huang + * [WCXRP00000127] [MT6620 Wi-Fi][Driver] Add a registry to disable Beacon Timeout function for SQA test by using E1 EVB + * Enable PM function by default + * + * 11 15 2010 wh.su + * [WCXRP00000171] [MT6620 Wi-Fi][Driver] Add message check code same behavior as mt5921 + * use config.mk WAPI config define. + * + * 11 08 2010 wh.su + * [WCXRP00000171] [MT6620 Wi-Fi][Driver] Add message check code same behavior as mt5921 + * use the config.mk define. + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 11 01 2010 yarco.yang + * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform + * Add code to run WlanIST in SDIO callback. + * + * 10 26 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command + * 1) update NVRAM content template to ver 1.02 + * 2) add compile option for querying NIC capability (default: off) + * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting + * 4) correct auto-rate compiler error under linux (treat warning as error) + * 5) simplify usage of NVRAM and REG_INFO_T + * 6) add version checking between driver and firmware + * + * 10 25 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * add option for enable/disable TX PWR gain adjustment (default: off) + * + * 10 20 2010 wh.su + * [WCXRP00000067] [MT6620 Wi-Fi][Driver] Support the android+ WAPI function + * enable the WAPI compiling flag as default + * + * 10 19 2010 cp.wu + * [WCXRP00000122] [MT6620 Wi-Fi][Driver] Preparation for YuSu source tree integration + * remove HIF_SDIO_ONE flags because the settings could be merged for runtime detection instead of compile-time. + * + * 10 18 2010 cp.wu + * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore + * 1. when wlanAdapterStop() failed to send POWER CTRL command to firmware, do not poll for ready bit dis-assertion + * 2. shorten polling count for shorter response time + * 3. if bad I/O operation is detected during TX resource polling, then further operation is aborted as well + * + * 10 18 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android + * complete implementation of Android NVRAM access + * + * 10 14 2010 wh.su + * [WCXRP00000102] [MT6620 Wi-Fi] [FW] Add a compiling flag and code for support Direct GO at Android + * Add a define CFG_TEST_ANDROID_DIRECT_GO compiling flag + * + * 10 08 2010 cm.chang + * NULL + * Remove unused compiling flags (TX_RDG and TX_SGI) + * + * 10 07 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * add firmware download for MT5931. + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * load manufacture data when CFG_SUPPORT_NVRAM is set to 1 + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * 1) add NVRAM access API + * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) + * 3) add OID implementation for NVRAM read/write service + * + * 10 05 2010 yarco.yang + * [WCXRP00000082] [MT6620 Wi-Fi][Driver]High throughput performance tuning + * Change CFG_IST_LOOP_COUNT from 2 to 1 to reduce unnecessary SDIO bus access + * + * 09 24 2010 cp.wu + * [WCXRP00000057] [MT6620 Wi-Fi][Driver] Modify online scan to a run-time switchable feature + * Modify online scan as a run-time adjustable option (for Windows, in registry) + * + * 09 23 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * eliminate reference of CFG_RESPONSE_MAX_PKT_SIZE + * + * 09 20 2010 cm.chang + * NULL + * Disable RX STBC by BB HEC based on MT6620E1_PHY_BUG v05.docx + * + * 09 17 2010 chinglan.wang + * NULL + * Add performance test option + * + * 09 10 2010 chinglan.wang + * NULL + * Modify for Software Migration Phase 2.10 for E2 FPGA + * + * 09 07 2010 yuche.tsai + * NULL + * Add a CFG for max common IE buffer size. + * + * 09 01 2010 cp.wu + * NULL + * restore configuration as before. + * + * 09 01 2010 cp.wu + * NULL + * HIFSYS Clock Source Workaround + * + * 08 31 2010 kevin.huang + * NULL + * Use LINK LIST operation to process SCAN result + * + * 08 30 2010 chinglan.wang + * NULL + * Enable the MT6620_FPGA_BWCS value. + * + * 08 30 2010 chinglan.wang + * NULL + * Disable the FW encryption. + * + * 08 27 2010 chinglan.wang + * NULL + * Update configuration for MT6620_E1_PRE_ALPHA_1832_0827_2010 + * + * 08 26 2010 yuche.tsai + * NULL + * Add AT GO test configure mode under WinXP. + * Please enable 1. CFG_ENABLE_WIFI_DIRECT, 2. CFG_TEST_WIFI_DIRECT_GO, 3. CFG_SUPPORT_AAA + * + * 08 25 2010 cp.wu + * NULL + * add option for enabling AIS 5GHz scan + * + * 08 25 2010 george.huang + * NULL + * update OID/ registry control path for PM related settings + * + * 08 24 2010 cp.wu + * NULL + * 1) initialize variable for enabling short premable/short time slot. + * 2) add compile option for disabling online scan + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 08 23 2010 cp.wu + * NULL + * revise constant definitions to be matched with implementation (original cmd-event definition is deprecated) + * + * 08 23 2010 chinghwa.yu + * NULL + * Disable BOW Test. + * + * 08 23 2010 jeffrey.chang + * NULL + * fix config.h typo + * + * 08 23 2010 chinghwa.yu + * NULL + * Update for BOW. + * + * 08 21 2010 jeffrey.chang + * NULL + * 1) add sdio two setting + * 2) bug fix of sdio glue + * + * 08 09 2010 wh.su + * NULL + * let the firmware download default enabled. + * + * 08 07 2010 wh.su + * NULL + * adding the privacy related code for P2P network + * + * 08 05 2010 yuche.tsai + * NULL + * Add a configure flag for P2P unitest. + * + * 07 23 2010 cp.wu + * + * 1) re-enable AIS-FSM beacon timeout handling. + * 2) scan done API revised + * + * 07 23 2010 cp.wu + * + * 1) enable Ad-Hoc + * 2) disable beacon timeout handling temporally due to unexpected beacon timeout event. + * + * 07 19 2010 wh.su + * + * update for security supporting. + * + * 07 19 2010 yuche.tsai + * + * Add for SLT support. + * + * 07 16 2010 cp.wu + * + * remove work-around in case SCN is not available. + * + * 07 14 2010 yarco.yang + * + * 1. Remove CFG_MQM_MIGRATION + * 2. Add CMD_UPDATE_WMM_PARMS command + * + * 07 13 2010 cp.wu + * + * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets + * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending + * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid descriptor underflow under concurrent network operation + * + * 07 09 2010 yarco.yang + * + * [MT6620 and MT5931] SW Migration: Add ADDBA support + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * take use of RLM module for parsing/generating HT IEs for 11n capability + * + * 07 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * for first connection, if connecting failed do not enter into scan state. + * + * 06 25 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * modify Beacon/ProbeResp to complete parsing, + * because host software has looser memory usage restriction + * + * 06 23 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add SCN compilation option. + * 2) when SCN is not turned on, BSSID_SCAN will generate a fake entry for 1st connection + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add command warpper for STA-REC/BSS-INFO sync. + * 2) enhance command packet sending procedure for non-oid part + * 3) add command packet definitions for STA-REC/BSS-INFO sync. + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * set default compiling flag for security disable. + * + * 06 21 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Support CFG_MQM_MIGRATION flag + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * enable RX management frame handling. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add scan_fsm into building. + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add scan.c. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add management dispatching function table. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * auth.c is migrated. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add bss.c. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 + * 2) when disconnected, indicate nic directly (no event is needed) + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge wlan_def.h. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 31 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add config option for cfg80211. + * + * 05 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * set ATIMwindow default value to zero. + * + * 05 21 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add option for FPGA_BWCS & FPGA_V5 + * + * 05 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS + * 2) buffer statistics data for 2 seconds + * 3) use default value for adhoc parameters instead of 0 + * + * 05 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) enable CMD/EVENT ver 0.9 definition. + * 2) abandon use of ENUM_MEDIA_STATE + * + * 05 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add CFG_STARTUP_DEBUG for debugging starting up issue. + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add basic handling framework for wireless extension ioctls. + * + * 05 11 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * change firmware name to WIFI_RAM_CODE. + * + * 05 07 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * disable bt-over-wifi configuration, turn it on after firmware finished implementation + * + * 04 27 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add multiple physical link support + * + * 04 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * surpress compiler warning + * + * 04 22 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * re-enable power management + * + * 04 22 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * + * 1) modify rx path code for supporting Wi-Fi direct + * 2) modify config.h since Linux dont need to consider retaining packet + * + * 04 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * enable TCP/IP checksum offloading by default. + * + * 04 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * set CFG_ENABLE_FULL_PM to 1 as default to + * 1) acquire own before hardware access + * 2) set own back after hardware access + * + * 04 15 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * change firmware name + * + * 04 07 2010 cp.wu + * [WPD00003827][MT6620 Wi-Fi] Chariot fail and following ping fail, no pkt send from driver + * disable RX-enhanced response temporally, it seems the CQ is not resolved yet. + * + * 04 06 2010 cp.wu + * [WPD00003827][MT6620 Wi-Fi] Chariot fail and following ping fail, no pkt send from driver + * re-enable RX enhanced mode as WPD00003827 is resolved. + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * turn off RX_ENHANCE mode by default. + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) eliminate unused definitions + * * 2) ready bit will be polled for limited iteration + * + * 04 02 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * firmware download: Linux uses different firmware path + * + * 04 01 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * change to use WIFI_TCM_ALWAYS_ON as firmware image + * + * 03 31 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * modify the wapi related code for new driver's design. + * + * 03 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add a temporary flag for integration with CMD/EVENT v0.9. + * + * 03 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * firmware download load adress & start address are now configured from config.h + * * due to the different configurations on FPGA and ASIC + * + * 03 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add options for full PM support. + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * [WPD00003826] Initial import for Linux port + * initial import for Linux port + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * [WPD00003826] Initial import for Linux port + * initial import for Linux port + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port + * + * 03 16 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * turn on FW-DOWNLOAD as default for release. + * + * 03 16 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * build up basic data structure and definitions to support BT-over-WiFi + * + * 03 12 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add two option for ACK and ENCRYPTION for firmware download + * + * 03 11 2010 cp.wu + * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 + * add RX starvation warning debug message controlled by CFG_HIF_RX_STARVATION_WARNING + * + * 03 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code clean: removing unused variables and structure definitions + * + * 03 05 2010 cp.wu + * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 + * change CFG_NUM_OF_QM_RX_PKT_NUM to 120 + * + * 03 04 2010 cp.wu + * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 + * . + * + * 03 04 2010 cp.wu + * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 + * increase RX buffer number to avoid RX buffer starvation. + * + * 02 24 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Changed the number of STA_RECs to 20 + * + * 02 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add checksum offloading support. + * + * 02 11 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. add logic for firmware download + * * 2. firmware image filename and start/load address are now retrieved from registry + * + * 02 08 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * prepare for implementing fw download logic + * + * 12 30 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) According to CMD/EVENT documentation v0.8, + * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, + * * and result is retrieved by get ATInfo instead + * * 2) add 4 counter for recording aggregation statistics +** \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-12-16 22:12:28 GMT mtk02752 +** enable interrupt enhanced response, TX/RX Aggregation as default +** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-12-10 16:38:43 GMT mtk02752 +** eliminate compile options which are obsolete or for emulation purpose +** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-12-09 13:56:26 GMT MTK02468 +** Added RX buffer reordering configurations +** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-12-04 12:09:09 GMT mtk02752 +** once enhanced intr/rx reponse is taken, RX must be access in aggregated basis +** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-23 17:54:50 GMT mtk02752 +** correct a typo +** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-11-17 22:40:47 GMT mtk01084 +** add defines +** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-11-17 17:33:37 GMT mtk02752 +** add coalescing buffer definition for SD1_SD3_DATAPATH_INTEGRATION +** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-11-16 20:32:40 GMT mtk02752 +** add CFG_TX_MAX_PKT_NUM for limiting queued TX packet +** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-11-16 13:34:44 GMT mtk02752 +** add SD1_SD3_DATAPATH_INTEGRATION define for source control +** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-11-13 13:54:11 GMT mtk01084 +** enable INT enhance mode by default +** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-10-30 18:17:14 GMT mtk01084 +** add new define +** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-10-29 19:47:36 GMT mtk01084 +** not use HIF loopback mode +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-10-13 21:58:33 GMT mtk01084 +** update for new macro define +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-09-09 17:26:08 GMT mtk01084 +** add CFG_TEST_WITH_MT5921 +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-05-18 21:02:30 GMT mtk01426 +** Update CFG_RX_COALESCING_BUFFER_SIZE +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-04-21 09:35:51 GMT mtk01461 +** Add CFG_TX_DBG_MGT_BUF to debug MGMT Buffer depth +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-14 15:52:21 GMT mtk01426 +** Add OOB_DATA_PRE_FIXED_LEN define +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-08 16:51:08 GMT mtk01084 +** update for FW download part +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-01 10:33:37 GMT mtk01461 +** Add SW pre test flag CFG_HIF_LOOPBACK_PRETEST +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-03-23 00:29:18 GMT mtk01461 +** Fix CFG_COALESCING_BUFFER_SIZE if enable the CFG_TX_FRAGMENT +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-18 20:58:34 GMT mtk01426 +** Add CFG_HIF_LOOPBACK and CFG_SDIO_RX_ENHANCE +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-17 20:17:36 GMT mtk01426 +** Add CMD/Response related configure +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:08:21 GMT mtk01461 +** Update TX PATH API +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:11:21 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +//2 Flags for OS capability + +#ifdef LINUX + #ifdef CONFIG_X86 + #define MTK_WCN_HIF_SDIO 0 + #else + #define MTK_WCN_HIF_SDIO 1 + #endif +#else + #define MTK_WCN_HIF_SDIO 0 +#endif + + +//2 Flags for Driver Features +#define CFG_TX_FRAGMENT 1 /*!< 1: Enable TX fragmentation + 0: Disable */ +#define CFG_SUPPORT_PERFORMANCE_TEST 0 /*Only for performance Test*/ + +#define CFG_COUNTRY_CODE NULL //"US" + +#ifndef LINUX + #define CFG_FW_FILENAME L"WIFI_RAM_CODE" + #define CFG_FW_FILENAME_E6 L"WIFI_RAM_CODE_E6" +#else + #define CFG_FW_FILENAME "WIFI_RAM_CODE" +#endif + +#define CFG_SUPPORT_802_11D 1 /*!< 1(default): Enable 802.11d + 0: Disable */ + +#define CFG_SUPPORT_SPEC_MGMT 0 /* Spectrum Management (802.11h): TPC and DFS */ +#define CFG_SUPPORT_RRM 0 /* Radio Reasource Measurement (802.11k) */ +#define CFG_SUPPORT_QUIET 0 /* Quiet (802.11h) */ + + +#define CFG_SUPPORT_RX_RDG 0 /* 11n feature. RX RDG capability */ +#define CFG_SUPPORT_MFB 0 /* 802.11n MCS Feedback responder */ +#define CFG_SUPPORT_RX_STBC 1 /* 802.11n RX STBC (1SS) */ +#define CFG_SUPPORT_RX_SGI 1 /* 802.11n RX short GI for both 20M and 40M BW */ +#define CFG_SUPPORT_RX_HT_GF 1 /* 802.11n RX HT green-field capability */ + +/*------------------------------------------------------------------------------ + * SLT Option + *------------------------------------------------------------------------------ + */ +#define CFG_SLT_SUPPORT 0 + + +#ifdef NDIS60_MINIPORT + #define CFG_NATIVE_802_11 1 + + #define CFG_TX_MAX_PKT_SIZE 2304 + #define CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 0 /* !< 1: Enable TCP/IP header checksum offload + 0: Disable */ + #define CFG_TCP_IP_CHKSUM_OFFLOAD 0 + #define CFG_WHQL_DOT11_STATISTICS 1 + #define CFG_WHQL_ADD_REMOVE_KEY 1 + #define CFG_WHQL_CUSTOM_IE 1 + #define CFG_WHQL_SAFE_MODE_ENABLED 1 + +#else + #define CFG_TCP_IP_CHKSUM_OFFLOAD 1 /* !< 1: Enable TCP/IP header checksum offload + 0: Disable */ + #define CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 0 + #define CFG_TX_MAX_PKT_SIZE 1600 + #define CFG_NATIVE_802_11 0 +#endif + + +//2 Flags for Driver Parameters +/*------------------------------------------------------------------------------ + * Flags for EHPI Interface in Colibri Platform + *------------------------------------------------------------------------------ + */ +#define CFG_EHPI_FASTER_BUS_TIMING 0 /*!< 1: Do workaround for faster bus timing + 0(default): Disable */ + +/*------------------------------------------------------------------------------ + * Flags for HIFSYS Interface + *------------------------------------------------------------------------------ + */ +#ifdef _lint + #define _HIF_SDIO 1 +#endif + +#define CFG_SDIO_INTR_ENHANCE 1 /*!< 1(default): Enable SDIO ISR & TX/RX status enhance mode + 0: Disable */ +#define CFG_SDIO_RX_ENHANCE 0 /*!< 1(default): Enable SDIO ISR & TX/RX status enhance mode + 0: Disable */ +#define CFG_SDIO_TX_AGG 1 /*!< 1: Enable SDIO TX enhance mode(Multiple frames in single BLOCK CMD) + 0(default): Disable */ + +#define CFG_SDIO_RX_AGG 1 /*!< 1: Enable SDIO RX enhance mode(Multiple frames in single BLOCK CMD) + 0(default): Disable */ +#if (CFG_SDIO_RX_AGG == 1) && (CFG_SDIO_INTR_ENHANCE == 0) + #error "CFG_SDIO_INTR_ENHANCE should be 1 once CFG_SDIO_RX_AGG equals to 1" +#elif (CFG_SDIO_INTR_ENHANCE == 1 || CFG_SDIO_RX_ENHANCE == 1) && (CFG_SDIO_RX_AGG == 0) + #error "CFG_SDIO_RX_AGG should be 1 once CFG_SDIO_INTR_ENHANCE and/or CFG_SDIO_RX_ENHANCE equals to 1" +#endif + +#define CFG_SDIO_MAX_RX_AGG_NUM 0 /*!< 1: Setting the maximum RX aggregation number + 0(default): no limited */ + +#ifdef WINDOWS_CE + #define CFG_SDIO_PATHRU_MODE 1 /*!< 1: Suport pass through (PATHRU) mode + 0: Disable */ +#else + #define CFG_SDIO_PATHRU_MODE 0 /*!< 0: Always disable if WINDOWS_CE is not defined */ +#endif + +#define CFG_MAX_RX_ENHANCE_LOOP_COUNT 3 + + +/*------------------------------------------------------------------------------ + * Flags and Parameters for Integration + *------------------------------------------------------------------------------ + */ +#if defined(MT6620) + #define MT6620_FPGA_BWCS 0 + #define MT6620_FPGA_V5 0 + + #if (MT6620_FPGA_BWCS == 1) && (MT6620_FPGA_V5 == 1) + #error + #endif + + #if (MTK_WCN_HIF_SDIO == 1) + #define CFG_MULTI_ECOVER_SUPPORT 1 + #elif !defined(LINUX) + #define CFG_MULTI_ECOVER_SUPPORT 1 + #else + #define CFG_MULTI_ECOVER_SUPPORT 0 + #endif + +#elif defined(MT5931) + +#define CFG_MULTI_ECOVER_SUPPORT 0 + +#elif defined(MT6628) + +#define CFG_MULTI_ECOVER_SUPPORT 0 + +#endif + +#if (MTK_WCN_HIF_SDIO == 1) +#define CFG_CHIP_RESET_SUPPORT 1 +#else +#define CFG_CHIP_RESET_SUPPORT 0 +#endif + + +/*------------------------------------------------------------------------------ + * Flags for workaround + *------------------------------------------------------------------------------ + */ +#if defined(MT6620) && (MT6620_FPGA_BWCS == 0) && (MT6620_FPGA_V5 == 0) + #define MT6620_E1_ASIC_HIFSYS_WORKAROUND 0 +#else + #define MT6620_E1_ASIC_HIFSYS_WORKAROUND 0 +#endif + +/*------------------------------------------------------------------------------ + * Flags for driver version + *------------------------------------------------------------------------------ + */ +#define CFG_DRV_OWN_VERSION ((UINT_16)((NIC_DRIVER_MAJOR_VERSION << 8) | (NIC_DRIVER_MINOR_VERSION))) +#define CFG_DRV_PEER_VERSION ((UINT_16)0x0000) + + +/*------------------------------------------------------------------------------ + * Flags for TX path which are OS dependent + *------------------------------------------------------------------------------ + */ +/*! NOTE(Kevin): If the Network buffer is non-scatter-gather like structure(without + * NETIF_F_FRAGLIST in LINUX), then we can set CFG_TX_BUFFER_IS_SCATTER_LIST to "0" + * for zero copy TX packets. + * For scatter-gather like structure, we set "1", driver will do copy frame to + * internal coalescing buffer before write it to FIFO. + */ +#if defined(LINUX) + #define CFG_TX_BUFFER_IS_SCATTER_LIST 1 /*!< 1: Do frame copy before write to TX FIFO. + Used when Network buffer is scatter-gather. + 0(default): Do not copy frame */ +#else /* WINDOWS/WINCE */ + #define CFG_TX_BUFFER_IS_SCATTER_LIST 1 +#endif /* LINUX */ + + +#if CFG_SDIO_TX_AGG || CFG_TX_BUFFER_IS_SCATTER_LIST + #define CFG_COALESCING_BUFFER_SIZE (CFG_TX_MAX_PKT_SIZE * NIC_TX_BUFF_SUM) +#else + #define CFG_COALESCING_BUFFER_SIZE (CFG_TX_MAX_PKT_SIZE) +#endif /* CFG_SDIO_TX_AGG || CFG_TX_BUFFER_IS_SCATTER_LIST */ + +/*------------------------------------------------------------------------------ + * Flags and Parameters for TX path + *------------------------------------------------------------------------------ + */ + +/*! Maximum number of SW TX packet queue */ +#define CFG_TX_MAX_PKT_NUM 256 + +/*! Maximum number of SW TX CMD packet buffer */ +#define CFG_TX_MAX_CMD_PKT_NUM 32 + +/*! Maximum number of associated STAs */ +#define CFG_NUM_OF_STA_RECORD 20 + +/*------------------------------------------------------------------------------ + * Flags and Parameters for RX path + *------------------------------------------------------------------------------ + */ + +/*! Max. descriptor number - sync. with firmware */ +#if CFG_SLT_SUPPORT +#define CFG_NUM_OF_RX0_HIF_DESC 42 +#else +#define CFG_NUM_OF_RX0_HIF_DESC 16 +#endif +#define CFG_NUM_OF_RX1_HIF_DESC 2 + +/*! Max. buffer hold by QM */ +#define CFG_NUM_OF_QM_RX_PKT_NUM 120 + +/*! Maximum number of SW RX packet buffer */ +#define CFG_RX_MAX_PKT_NUM ((CFG_NUM_OF_RX0_HIF_DESC + CFG_NUM_OF_RX1_HIF_DESC) * 3 \ + + CFG_NUM_OF_QM_RX_PKT_NUM) + +#define CFG_RX_REORDER_Q_THRESHOLD 8 + +#ifndef LINUX +#define CFG_RX_RETAINED_PKT_THRESHOLD (CFG_NUM_OF_RX0_HIF_DESC + CFG_NUM_OF_RX1_HIF_DESC + CFG_NUM_OF_QM_RX_PKT_NUM) +#else +#define CFG_RX_RETAINED_PKT_THRESHOLD 0 +#endif + +/*! Maximum RX packet size, if exceed this value, drop incoming packet */ +/* 7.2.3 Maganement frames */ +#define CFG_RX_MAX_PKT_SIZE ( 28 + 2312 + 12 /*HIF_RX_HEADER_T*/ ) //TODO: it should be 4096 under emulation mode + +/*! Minimum RX packet size, if lower than this value, drop incoming packet */ +#define CFG_RX_MIN_PKT_SIZE 10 /*!< 802.11 Control Frame is 10 bytes */ + +#if CFG_SDIO_RX_AGG + /* extra size for CS_STATUS and enhanced response */ + #define CFG_RX_COALESCING_BUFFER_SIZE ((CFG_NUM_OF_RX0_HIF_DESC + 1) \ + * CFG_RX_MAX_PKT_SIZE) +#else + #define CFG_RX_COALESCING_BUFFER_SIZE (CFG_RX_MAX_PKT_SIZE) +#endif + +/*! RX BA capability */ +#define CFG_NUM_OF_RX_BA_AGREEMENTS 8 +#define CFG_RX_BA_MAX_WINSIZE 16 +#define CFG_RX_BA_INC_SIZE 4 +#define CFG_RX_MAX_BA_TID_NUM 8 +#define CFG_RX_REORDERING_ENABLED 1 + +/*------------------------------------------------------------------------------ + * Flags and Parameters for CMD/RESPONSE + *------------------------------------------------------------------------------ + */ +#define CFG_RESPONSE_POLLING_TIMEOUT 512 + + +/*------------------------------------------------------------------------------ + * Flags and Parameters for Protocol Stack + *------------------------------------------------------------------------------ + */ +/*! Maximum number of BSS in the SCAN list */ +#define CFG_MAX_NUM_BSS_LIST 64 + +#define CFG_MAX_COMMON_IE_BUF_LEN (1500 * CFG_MAX_NUM_BSS_LIST) / 3 + +/*! Maximum size of IE buffer of each SCAN record */ +#define CFG_IE_BUFFER_SIZE 512 + +/*! Maximum number of STA records */ +#define CFG_MAX_NUM_STA_RECORD 32 + + + +/*------------------------------------------------------------------------------ + * Flags and Parameters for Power management + *------------------------------------------------------------------------------ + */ +#define CFG_ENABLE_FULL_PM 1 +#define CFG_ENABLE_WAKEUP_ON_LAN 0 + +#define CFG_INIT_POWER_SAVE_PROF ENUM_PSP_FAST_SWITCH + +#define CFG_INIT_ENABLE_PATTERN_FILTER_ARP 0 + +#define CFG_INIT_UAPSD_AC_BMP 0//(BIT(3) | BIT(2) | BIT(1) | BIT(0)) + +//#define CFG_SUPPORT_WAPI 0 +#define CFG_SUPPORT_WPS 1 +#define CFG_SUPPORT_WPS2 1 + +/*------------------------------------------------------------------------------ + * 802.11i RSN Pre-authentication PMKID cahce maximun number + *------------------------------------------------------------------------------ + */ +#define CFG_MAX_PMKID_CACHE 16 /*!< max number of PMKID cache + 16(default) : The Max PMKID cache */ + +/*------------------------------------------------------------------------------ + * Flags and Parameters for Ad-Hoc + *------------------------------------------------------------------------------ + */ +#define CFG_INIT_ADHOC_FREQ (2462000) +#define CFG_INIT_ADHOC_MODE AD_HOC_MODE_MIXED_11BG +#define CFG_INIT_ADHOC_BEACON_INTERVAL (100) +#define CFG_INIT_ADHOC_ATIM_WINDOW (0) + + +/*------------------------------------------------------------------------------ + * Flags and Parameters for Load Setup Default + *------------------------------------------------------------------------------ + */ + +/*------------------------------------------------------------------------------ + * Flags for enable 802.11A Band setting + *------------------------------------------------------------------------------ + */ + +/*------------------------------------------------------------------------------ + * Flags and Parameters for Interrupt Process + *------------------------------------------------------------------------------ + */ +#if defined(_HIF_SDIO) && defined(WINDOWS_CE) + #define CFG_IST_LOOP_COUNT 1 +#else + #define CFG_IST_LOOP_COUNT 1 +#endif /* _HIF_SDIO */ + +#define CFG_INT_WRITE_CLEAR 0 + +#if defined(LINUX) +#define CFG_DBG_GPIO_PINS 0 /* if 1, use MT6516 GPIO pin to log TX behavior */ +#endif + +//2 Flags for Driver Debug Options +/*------------------------------------------------------------------------------ + * Flags of TX Debug Option. NOTE(Kevin): Confirm with SA before modifying following flags. + *------------------------------------------------------------------------------ + */ +#define CFG_DBG_MGT_BUF 1 /*!< 1: Debug statistics usage of MGMT Buffer + 0: Disable */ + +#define CFG_HIF_STATISTICS 0 + +#define CFG_HIF_RX_STARVATION_WARNING 0 + +#define CFG_STARTUP_DEBUG 0 + +#define CFG_RX_PKTS_DUMP 1 + +/*------------------------------------------------------------------------------ + * Flags of Firmware Download Option. + *------------------------------------------------------------------------------ + */ +#define CFG_ENABLE_FW_DOWNLOAD 1 + +#define CFG_ENABLE_FW_DOWNLOAD_ACK 1 +#define CFG_ENABLE_FW_ENCRYPTION 1 + +#if defined(MT6620) || defined(MT6628) + #define CFG_ENABLE_FW_DOWNLOAD_AGGREGATION 0 + #define CFG_ENABLE_FW_DIVIDED_DOWNLOAD 1 +#else + #define CFG_ENABLE_FW_DOWNLOAD_AGGREGATION 0 + #define CFG_ENABLE_FW_DIVIDED_DOWNLOAD 0 +#endif + + + +#if defined(MT6620) + #if MT6620_FPGA_BWCS + #define CFG_FW_LOAD_ADDRESS 0x10014000 + #define CFG_OVERRIDE_FW_START_ADDRESS 0 + #define CFG_FW_START_ADDRESS 0x10014001 + #elif MT6620_FPGA_V5 + #define CFG_FW_LOAD_ADDRESS 0x10008000 + #define CFG_OVERRIDE_FW_START_ADDRESS 0 + #define CFG_FW_START_ADDRESS 0x10008001 + #else + #define CFG_FW_LOAD_ADDRESS 0x10008000 + #define CFG_OVERRIDE_FW_START_ADDRESS 0 + #define CFG_FW_START_ADDRESS 0x10008001 + #endif +#elif defined(MT5931) + #define CFG_FW_LOAD_ADDRESS 0xFF900000 + #define CFG_FW_START_ADDRESS 0x00000000 +#elif defined(MT6628) + #define CFG_FW_LOAD_ADDRESS 0x00060000 + #define CFG_FW_START_ADDRESS 0x00060000 +#endif + + +/*------------------------------------------------------------------------------ + * Flags of Bluetooth-over-WiFi (BT 3.0 + HS) support + *------------------------------------------------------------------------------ + */ + +#ifdef LINUX + #ifdef CONFIG_X86 + #define CFG_ENABLE_BT_OVER_WIFI 0 + #else + #define CFG_ENABLE_BT_OVER_WIFI 1 + #endif +#else + #define CFG_ENABLE_BT_OVER_WIFI 0 +#endif + +#define CFG_BOW_SEPARATE_DATA_PATH 1 + +#define CFG_BOW_PHYSICAL_LINK_NUM 4 + +#define CFG_BOW_TEST 0 + +#define CFG_BOW_LIMIT_AIS_CHNL 1 + +#define CFG_BOW_SUPPORT_11N 0 + +#define CFG_BOW_RATE_LIMITATION 1 + + +/*------------------------------------------------------------------------------ + * Flags of Wi-Fi Direct support + *------------------------------------------------------------------------------ + */ +#ifdef LINUX + #ifdef CONFIG_X86 + #define CFG_ENABLE_WIFI_DIRECT 0 + #define CFG_SUPPORT_802_11W 0 + #else + #define CFG_ENABLE_WIFI_DIRECT 1 + #define CFG_SUPPORT_802_11W 0 /*!< 0(default): Disable 802.11W */ + #endif +#else + #define CFG_ENABLE_WIFI_DIRECT 0 + #define CFG_SUPPORT_802_11W 0 /* Not support at WinXP */ +#endif + +#define CFG_SUPPORT_PERSISTENT_GROUP 0 + +#define CFG_TEST_WIFI_DIRECT_GO 0 + +#define CFG_TEST_ANDROID_DIRECT_GO 0 + +#define CFG_UNITEST_P2P 0 + +/* + * Enable cfg80211 option after Android 2.2(Froyo) is suggested, + * cfg80211 on linux 2.6.29 is not mature yet + */ +#define CFG_ENABLE_WIFI_DIRECT_CFG_80211 1 + +/*------------------------------------------------------------------------------ + * Configuration Flags (Linux Only) + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_EXT_CONFIG 0 + +/*------------------------------------------------------------------------------ + * Statistics Buffering Mechanism + *------------------------------------------------------------------------------ + */ +#if CFG_SUPPORT_PERFORMANCE_TEST +#define CFG_ENABLE_STATISTICS_BUFFERING 1 +#else +#define CFG_ENABLE_STATISTICS_BUFFERING 0 +#endif +#define CFG_STATISTICS_VALID_CYCLE 2000 +#define CFG_LINK_QUALITY_VALID_PERIOD 5000 + +/*------------------------------------------------------------------------------ + * Migration Option + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_ADHOC 1 +#define CFG_SUPPORT_AAA 1 + + +#if (defined(MT5931) && defined(LINUX)) +#define CFG_SUPPORT_BCM 1 +#define CFG_SUPPORT_BCM_BWCS 1 +#define CFG_SUPPORT_BCM_BWCS_DEBUG 1 +#else +#define CFG_SUPPORT_BCM 0 +#define CFG_SUPPORT_BCM_BWCS 0 +#define CFG_SUPPORT_BCM_BWCS_DEBUG 0 +#endif + +#define CFG_SUPPORT_RDD_TEST_MODE 0 + +#define CFG_SUPPORT_PWR_MGT 1 + +#define CFG_RSN_MIGRATION 1 + +#define CFG_PRIVACY_MIGRATION 1 + +#define CFG_ENABLE_HOTSPOT_PRIVACY_CHECK 1 + +#define CFG_MGMT_FRAME_HANDLING 1 + +#define CFG_MGMT_HW_ACCESS_REPLACEMENT 0 + +#if CFG_SUPPORT_PERFORMANCE_TEST + +#else + +#endif + +#define CFG_SUPPORT_AIS_5GHZ 1 +#define CFG_SUPPORT_BEACON_CHANGE_DETECTION 0 + +/*------------------------------------------------------------------------------ + * Option for NVRAM and Version Checking + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_NVRAM 1 +#define CFG_NVRAM_EXISTENCE_CHECK 1 +#define CFG_SW_NVRAM_VERSION_CHECK 0 +#define CFG_SUPPORT_NIC_CAPABILITY 1 + + +/*------------------------------------------------------------------------------ + * CONFIG_TITLE : Stress Test Option + * OWNER : Puff Wen + * Description : For stress test only. DO NOT enable it while normal operation + *------------------------------------------------------------------------------ + */ +#define CFG_STRESS_TEST_SUPPORT 0 + +/*------------------------------------------------------------------------------ + * Flags for LINT + *------------------------------------------------------------------------------ + */ +#define LINT_SAVE_AND_DISABLE /*lint -save -e* */ + +#define LINT_RESTORE /*lint -restore */ + +#define LINT_EXT_HEADER_BEGIN LINT_SAVE_AND_DISABLE + +#define LINT_EXT_HEADER_END LINT_RESTORE + +/*------------------------------------------------------------------------------ + * Flags of Features + *------------------------------------------------------------------------------ + */ + +#define CFG_SUPPORT_QOS 1 /* Enable/disable QoS TX, AMPDU */ +#define CFG_SUPPORT_AMPDU_TX 1 +#define CFG_SUPPORT_AMPDU_RX 1 +#define CFG_SUPPORT_TSPEC 0 /* Enable/disable TS-related Action frames handling */ +#define CFG_SUPPORT_UAPSD 1 +#define CFG_SUPPORT_UL_PSMP 0 + +#define CFG_SUPPORT_ROAMING 1 /* Roaming System */ +#define CFG_SUPPORT_SWCR 1 + +#define CFG_SUPPORT_ANTI_PIRACY 1 + +#define CFG_SUPPORT_OSC_SETTING 1 + +#if defined(MT5931) +#define CFG_SUPPORT_WHOLE_CHIP_RESET 1 /* for e3 chip only */ +#endif + +#define CFG_SUPPORT_P2P_RSSI_QUERY 0 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#endif /* _CONFIG_H */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/debug.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/debug.h new file mode 100755 index 000000000000..9711aff5c528 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/debug.h @@ -0,0 +1,566 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/debug.h#1 $ +*/ + +/*! \file debug.h + \brief Definition of SW debugging level. + + In this file, it describes the definition of various SW debugging levels and + assert functions. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: debug.h $ + * + * 01 20 2012 cp.wu + * [ALPS00096191] [MT6620 Wi-Fi][Driver][Firmware] Porting to ALPS4.0_DEV branch + * sync to up-to-date changes including: + * 1. BOW bugfix + * 2. XLOG + * + * 12 16 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * fixed the compiling error at Windows free build. + * + * 11 24 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Adjust code for DBG and CONFIG_XLOG. + * + * 11 11 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * modify the xlog related code. + * + * 11 10 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Using the new XLOG define for dum Memory. + * + * 11 03 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Add dumpMemory8 at XLOG support. + * + * 11 02 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Add XLOG related code and define. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 01 07 2011 wh.su + * [WCXRP00000326] [MT6620][Wi-Fi][Driver] check in the binary format gl_sec.o.new instead of use change type!!! + * . + * + * 09 23 2010 cp.wu + * NULL + * add BOW index for debugging message and passing compilation + * + * 07 20 2010 wh.su + * + * adding the wapi code. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Support CFG_MQM_MIGRATION flag + * + * 06 17 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Add one more debug moduel for P2P. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add management dispatching function table. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add bss.c. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add debug module index for cnm and ais. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add CFG_STARTUP_DEBUG for debugging starting up issue. + * + * 04 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) surpress compiler warning + * 2) when acqruing LP-own, keep writing WHLPCR whenever OWN is not acquired yet +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-10-29 19:47:50 GMT mtk01084 +** add emu catagory +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-04-17 18:12:04 GMT mtk01426 +** Don't use dynamic memory allocate for debug message +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:11:29 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _DEBUG_H +#define _DEBUG_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +#ifndef BUILD_QA_DBG +#define BUILD_QA_DBG 0 +#endif + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "gl_typedef.h" +#if CFG_SUPPORT_XLOG +#include "linux/xlog.h" +#endif + +extern UINT_8 aucDebugModule[]; +extern UINT_32 u4DebugModule; + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* Define debug category (class): + * (1) ERROR (2) WARN (3) STATE (4) EVENT (5) TRACE (6) INFO (7) LOUD (8) TEMP + */ +#define DBG_CLASS_ERROR BIT(0) +#define DBG_CLASS_WARN BIT(1) +#define DBG_CLASS_STATE BIT(2) +#define DBG_CLASS_EVENT BIT(3) +#define DBG_CLASS_TRACE BIT(4) +#define DBG_CLASS_INFO BIT(5) +#define DBG_CLASS_LOUD BIT(6) +#define DBG_CLASS_TEMP BIT(7) +#define DBG_CLASS_MASK BITS(0,7) + + +#if defined(LINUX) +#define DBG_PRINTF_64BIT_DEC "lld" + +#else //Windows +#define DBG_PRINTF_64BIT_DEC "I64d" + +#endif +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* Define debug module index */ +typedef enum _ENUM_DBG_MODULE_T { + DBG_INIT_IDX = 0, /* For driver initial */ + DBG_HAL_IDX, /* For HAL(HW) Layer */ + DBG_INTR_IDX, /* For Interrupt */ + DBG_REQ_IDX, + DBG_TX_IDX, + DBG_RX_IDX, + DBG_RFTEST_IDX, /* For RF test mode*/ + DBG_EMU_IDX, /* Developer specific */ + + DBG_SW1_IDX, /* Developer specific */ + DBG_SW2_IDX, /* Developer specific */ + DBG_SW3_IDX, /* Developer specific */ + DBG_SW4_IDX, /* Developer specific */ + + DBG_HEM_IDX, /* HEM */ + DBG_AIS_IDX, /* AIS */ + DBG_RLM_IDX, /* RLM */ + DBG_MEM_IDX, /* RLM */ + DBG_CNM_IDX, /* CNM */ + DBG_RSN_IDX, /* RSN */ + DBG_BSS_IDX, /* BSS */ + DBG_SCN_IDX, /* SCN */ + DBG_SAA_IDX, /* SAA */ + DBG_AAA_IDX, /* AAA */ + DBG_P2P_IDX, /* P2P */ + DBG_QM_IDX, /* QUE_MGT */ + DBG_SEC_IDX, /* SEC */ + DBG_BOW_IDX, /* BOW */ + DBG_WAPI_IDX, /* WAPI */ + DBG_ROAMING_IDX, /* ROAMING */ + + DBG_MODULE_NUM /* Notice the XLOG check */ +} ENUM_DBG_MODULE_T; + +//XLOG +//#define XLOG_DBG_MODULE_IDX 28 /* DBG_MODULE_NUM */ +//#if (XLOG_DBG_MODULE_IDX != XLOG_DBG_MODULE_IDX) +//#error "Please modify the DBG_MODULE_NUM and make sure this include at XLOG" +//#endif + +/* Define who owns developer specific index */ +#define DBG_YARCO_IDX DBG_SW1_IDX +#define DBG_KEVIN_IDX DBG_SW2_IDX +#define DBG_CMC_IDX DBG_SW3_IDX +#define DBG_GEORGE_IDX DBG_SW4_IDX + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +/* Debug print format string for the OS system time */ +#define OS_SYSTIME_DBG_FORMAT "0x%08x" + +/* Debug print argument for the OS system time */ +#define OS_SYSTIME_DBG_ARGUMENT(systime) (systime) + +/* Debug print format string for the MAC Address */ +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" + +/* Debug print argument for the MAC Address */ +#define MAC2STR(a) ((PUINT_8)a)[0], ((PUINT_8)a)[1], ((PUINT_8)a)[2], \ + ((PUINT_8)a)[3], ((PUINT_8)a)[4], ((PUINT_8)a)[5] + +/* The pre-defined format to dump the value of a varaible with its name shown. */ +#define DUMPVAR(variable, format) (#variable " = " format "\n", variable) + +/* The pre-defined format to dump the MAC type value with its name shown. */ +#define DUMPMACADDR(addr) (#addr " = " MACSTR "\n", MAC2STR(addr)) + + +/* Basiclly, we just do renaming of KAL functions although they should + * be defined as "Nothing to do" if DBG=0. But in some compiler, the macro + * syntax does not support #define LOG_FUNC(x,...) + * + * A caller shall not invoke these three macros when DBG=0. + */ +#define LOG_FUNC_TIME kalPrint +#define LOG_FUNC kalPrint + +#if DBG + + #define TMP_BUF_LEN 256 + #define TMP_WBUF_LEN (TMP_BUF_LEN * 2) + + extern PINT_16 g_wbuf_p; + extern PINT_8 g_buf_p; + + /* If __FUNCTION__ is already defined by compiler, we just use it. */ + #if defined(__FUNCTION__) + #define DEBUGFUNC(_Func) + #else + #define DEBUGFUNC(_Func) static const char __FUNCTION__[] = _Func; + #endif + + /* The following macros are used for future debug message. */ + /* TODO(Kevin): We should remove INITLOG/ERRORLOG/WARNLOG macro sooner or later */ + #define INITLOG(_Fmt) \ + { \ + if (aucDebugModule[DBG_INIT_IDX] & DBG_CLASS_TRACE) { \ + LOG_FUNC("%s: ", __FUNCTION__); \ + LOG_FUNC _Fmt; \ + } \ + } + + #define ERRORLOG(_Fmt) \ + { \ + if (aucDebugModule[DBG_INIT_IDX] & DBG_CLASS_ERROR) { \ + LOG_FUNC("**Error[%s:%d]-", __FILE__, __LINE__); \ + LOG_FUNC _Fmt; \ + } \ + } + + #define WARNLOG(_Fmt) \ + { \ + if (aucDebugModule[DBG_INIT_IDX] & DBG_CLASS_WARN) { \ + LOG_FUNC("**Warning[%s:%d]-", __FILE__, __LINE__); \ + LOG_FUNC _Fmt; \ + } \ + } + + /*lint -save -e960 Multiple use of '#/##' */ + #define DBGLOG(_Module, _Class, _Fmt) \ + { \ + if (aucDebugModule[DBG_##_Module##_IDX] & DBG_CLASS_##_Class) { \ + if (DBG_CLASS_##_Class == DBG_CLASS_ERROR) { \ + LOG_FUNC_TIME("**Error[%s:%d]-", __FILE__, __LINE__); \ + LOG_FUNC("%s: (" #_Module " " #_Class ") ", __FUNCTION__); \ + } \ + else if (DBG_CLASS_##_Class == DBG_CLASS_WARN) { \ + LOG_FUNC_TIME("**Warning[%s:%d]-", __FILE__, __LINE__); \ + LOG_FUNC("%s: (" #_Module " " #_Class ") ", __FUNCTION__); \ + } \ + else if (DBG_CLASS_##_Class == DBG_CLASS_EVENT) { \ + } \ + else { \ + LOG_FUNC_TIME("%s: (" #_Module " " #_Class ") ", __FUNCTION__); \ + } \ + LOG_FUNC _Fmt; \ + } \ + } + + #define DBGLOG_MEM8(_Module, _Class, _StartAddr, _Length) \ + { \ + if (aucDebugModule[DBG_##_Module##_IDX] & DBG_CLASS_##_Class) { \ + LOG_FUNC("%s: (" #_Module " " #_Class ")\n", __FUNCTION__); \ + dumpMemory8((PUINT_8) (_StartAddr), (UINT_32) (_Length)); \ + } \ + } + + #define DBGLOG_MEM32(_Module, _Class, _StartAddr, _Length) \ + { \ + if (aucDebugModule[DBG_##_Module##_IDX] & DBG_CLASS_##_Class) { \ + LOG_FUNC("%s: (" #_Module " " #_Class ")\n", __FUNCTION__); \ + dumpMemory32((PUINT_32) (_StartAddr), (UINT_32) (_Length)); \ + } \ + } + /*lint -restore */ + + /*lint -save -e961 use of '#undef' is discouraged */ + #undef ASSERT + /*lint -restore */ + + #ifdef _lint + #define ASSERT(_exp) \ + { \ + if (!(_exp)) {do {} while (1);} \ + } + #else + #define ASSERT(_exp) \ + { \ + if (!(_exp) && !fgIsBusAccessFailed) { \ + LOG_FUNC("Assertion failed: %s:%d %s\n", __FILE__, __LINE__, #_exp); \ + kalBreakPoint(); \ + } \ + } + #endif /* _lint */ + + #define ASSERT_REPORT(_exp, _fmt) \ + { \ + if (!(_exp) && !fgIsBusAccessFailed) { \ + LOG_FUNC("Assertion failed: %s:%d %s\n", __FILE__, __LINE__, #_exp); \ + LOG_FUNC _fmt; \ + kalBreakPoint(); \ + } \ + } + + #define DISP_STRING(_str) _str + +#else /* !DBG */ + + #define DEBUGFUNC(_Func) + #define INITLOG(_Fmt) + #define ERRORLOG(_Fmt) + #define WARNLOG(_Fmt) + +#if CFG_SUPPORT_XLOG + #define DBGLOG(_Module, _Class, _Fmt) \ + { \ + _Module##_##_Class##_LOGFUNC _Fmt; \ + } + + #define DBGLOG_MEM8(_Module, _Class, _StartAddr, _Length) \ + { \ + _Module##_##_Class##_LOGFUNC (__FUNCTION__);\ + _Module##_##_Class##_LOGDUMP8(_StartAddr, _Length); \ + } + +#else + #define DBGLOG(_Module, _Class, _Fmt) + #define DBGLOG_MEM8(_Module, _Class, _StartAddr, _Length) +#endif + #define DBGLOG_MEM32(_Module, _Class, _StartAddr, _Length) + + #undef ASSERT + +#if BUILD_QA_DBG + #if defined(LINUX) /* For debugging in Linux w/o GDB */ + #define ASSERT(_exp) \ + { \ + if (!(_exp) && !fgIsBusAccessFailed) { \ + LOG_FUNC("Assertion failed: %s:%d (%s)\n", __FILE__, __LINE__, #_exp); \ + kalBreakPoint(); \ + } \ + } + + #define ASSERT_REPORT(_exp, _fmt) \ + { \ + if (!(_exp) && !fgIsBusAccessFailed) { \ + LOG_FUNC("Assertion failed: %s:%d (%s)\n", __FILE__, __LINE__, #_exp); \ + LOG_FUNC _fmt; \ + kalBreakPoint(); \ + } \ + } + #else + #ifdef WINDOWS_CE + #define UNICODE_TEXT(_msg) TEXT(_msg) + #define ASSERT(_exp) \ + { \ + if (!(_exp) && !fgIsBusAccessFailed) { \ + TCHAR rUbuf[256]; \ + kalBreakPoint(); \ + _stprintf(rUbuf, TEXT("Assertion failed: %s:%d %s\n"), \ + UNICODE_TEXT(__FILE__), \ + __LINE__, \ + UNICODE_TEXT(#_exp)); \ + MessageBox(NULL, rUbuf, TEXT("ASSERT!"), MB_OK); \ + } \ + } + + #define ASSERT_REPORT(_exp, _fmt) \ + { \ + if (!(_exp) && !fgIsBusAccessFailed) { \ + TCHAR rUbuf[256]; \ + kalBreakPoint(); \ + _stprintf(rUbuf, TEXT("Assertion failed: %s:%d %s\n"), \ + UNICODE_TEXT(__FILE__), \ + __LINE__, \ + UNICODE_TEXT(#_exp)); \ + MessageBox(NULL, rUbuf, TEXT("ASSERT!"), MB_OK); \ + } \ + } + #else + #define ASSERT(_exp) \ + { \ + if (!(_exp) && !fgIsBusAccessFailed) { \ + kalBreakPoint(); \ + } \ + } + + #define ASSERT_REPORT(_exp, _fmt) \ + { \ + if (!(_exp) && !fgIsBusAccessFailed) { \ + kalBreakPoint(); \ + } \ + } + #endif /* WINDOWS_CE */ + #endif /* LINUX */ +#else + #define ASSERT(_exp) + #define ASSERT_REPORT(_exp, _fmt) +#endif /* BUILD_QA_DBG */ + + #define DISP_STRING(_str) "" + +#endif /* DBG */ + +#if CFG_STARTUP_DEBUG + #if defined(LINUX) +#define DBGPRINTF kalPrint + #else +#define DBGPRINTF DbgPrint + #endif +#else +#define DBGPRINTF(...) +#endif + + +/* The following macro is used for debugging packed structures. */ +#ifndef DATA_STRUC_INSPECTING_ASSERT +#define DATA_STRUC_INSPECTING_ASSERT(expr) \ + switch (0) {case 0: case (expr): default:;} +#endif + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +#if DBG +VOID +dumpMemory8 ( + IN PUINT_8 pucStartAddr, + IN UINT_32 u4Length + ); + +VOID +dumpMemory32 ( + IN PUINT_32 pu4StartAddr, + IN UINT_32 u4Length + ); +#elif CFG_SUPPORT_XLOG +VOID +dumpMemory8 ( + IN UINT_32 log_level, + IN PUINT_8 pucStartAddr, + IN UINT_32 u4Length + ); +#endif /* DBG */ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#endif /* _DEBUG_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/link.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/link.h new file mode 100755 index 000000000000..f7973a22a387 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/link.h @@ -0,0 +1,458 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/link.h#1 $ +*/ + +/*! \file link.h + \brief Definition for simple doubly linked list operations. + + In this file we define the simple doubly linked list data structure and its + operation MACROs and INLINE functions. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: link.h $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 08 05 2010 yuche.tsai + * NULL + * Modify a MACRO of LINK_FOR_EACH_SAFE for compile error. + * + * 07 19 2010 cm.chang + * + * Set RLM parameters and enable CNM channel manager + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * [WPD00003833] [MT6620 and MT5931] Driver migration + * . + * + * + * + * + * May 4 2009 mtk01084 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * add WIFI to BORA source control +** \main\maintrunk.MT5921\8 2008-10-16 15:57:11 GMT mtk01461 +** Update driver to fix lint warning +** \main\maintrunk.MT5921\7 2008-08-10 18:47:53 GMT mtk01461 +** Update for Driver Review +** \main\maintrunk.MT5921\6 2007-12-11 00:09:00 GMT mtk01461 +** Add macro for checking valid list +** \main\maintrunk.MT5921\5 2007-11-13 14:27:01 GMT mtk01461 +** Add LINK_IS_INVALID macro +** Revision 1.1.1.1 2007/06/22 08:09:05 MTK01461 +** no message +** +*/ + +#ifndef _LINK_H +#define _LINK_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "gl_typedef.h" + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define INVALID_LINK_POISON1 ((VOID *) 0x00100101) // May cause page fault & unalignment issue (data abort) +#define INVALID_LINK_POISON2 ((VOID *) 0x00100201) // Used to verify that nonbody uses non-initialized link entries. + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* Simple Doubly Linked List Structures - Entry Part */ +typedef struct _LINK_ENTRY_T { + struct _LINK_ENTRY_T *prNext, *prPrev; +} LINK_ENTRY_T, *P_LINK_ENTRY_T; + +/* Simple Doubly Linked List Structures - List Part */ +typedef struct _LINK_T { + P_LINK_ENTRY_T prNext; + P_LINK_ENTRY_T prPrev; + UINT_32 u4NumElem; +} LINK_T, *P_LINK_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#if 0 // No one use it, temporarily mark it for [Lint - Info 773] +#define LINK_ADDR(rLink) { (P_LINK_ENTRY_T)(&(rLink)), (P_LINK_ENTRY_T)(&(rLink)), 0 } + +#define LINK_DECLARATION(rLink) \ + struct _LINK_T rLink = LINK_ADDR(rLink) +#endif + +#define LINK_INITIALIZE(prLink) \ + do { \ + ((P_LINK_T)(prLink))->prNext = (P_LINK_ENTRY_T)(prLink); \ + ((P_LINK_T)(prLink))->prPrev = (P_LINK_ENTRY_T)(prLink); \ + ((P_LINK_T)(prLink))->u4NumElem = 0; \ + } while (0) + +#define LINK_ENTRY_INITIALIZE(prEntry) \ + do { \ + ((P_LINK_ENTRY_T)(prEntry))->prNext = (P_LINK_ENTRY_T)NULL; \ + ((P_LINK_ENTRY_T)(prEntry))->prPrev = (P_LINK_ENTRY_T)NULL; \ + } while (0) + +#define LINK_ENTRY_INVALID(prEntry) \ + do { \ + ((P_LINK_ENTRY_T)(prEntry))->prNext = (P_LINK_ENTRY_T)INVALID_LINK_POISON1; \ + ((P_LINK_ENTRY_T)(prEntry))->prPrev = (P_LINK_ENTRY_T)INVALID_LINK_POISON2; \ + } while (0) + +#define LINK_IS_EMPTY(prLink) (((P_LINK_T)(prLink))->prNext == (P_LINK_ENTRY_T)(prLink)) + +/* NOTE: We should do memory zero before any LINK been initiated, so we can check + * if it is valid before parsing the LINK. + */ +#define LINK_IS_INVALID(prLink) (((P_LINK_T)(prLink))->prNext == (P_LINK_ENTRY_T)NULL) + +#define LINK_IS_VALID(prLink) (((P_LINK_T)(prLink))->prNext != (P_LINK_ENTRY_T)NULL) + + +#define LINK_ENTRY(ptr, type, member) ENTRY_OF(ptr, type, member) + +/* Insert an entry into a link list's head */ +#define LINK_INSERT_HEAD(prLink, prEntry) \ + { \ + linkAdd(prEntry, prLink); \ + ((prLink)->u4NumElem)++; \ + } + + +/* Append an entry into a link list's tail */ +#define LINK_INSERT_TAIL(prLink, prEntry) \ + { \ + linkAddTail(prEntry, prLink); \ + ((prLink)->u4NumElem)++; \ + } + +/* Peek head entry, but keep still in link list */ +#define LINK_PEEK_HEAD(prLink, _type, _member) \ + ( \ + LINK_IS_EMPTY(prLink) ? \ + NULL : LINK_ENTRY((prLink)->prNext, _type, _member) \ + ) + +/* Peek tail entry, but keep still in link list */ +#define LINK_PEEK_TAIL(prLink, _type, _member) \ + ( \ + LINK_IS_EMPTY(prLink) ? \ + NULL : LINK_ENTRY((prLink)->prPrev, _type, _member) \ + ) + +/* Get first entry from a link list */ +/* NOTE: We assume the link entry located at the beginning of "prEntry Type", + * so that we can cast the link entry to other data type without doubts. + * And this macro also decrease the total entry count at the same time. + */ +#define LINK_REMOVE_HEAD(prLink, prEntry, _P_TYPE) \ + { \ + ASSERT(prLink); \ + if (LINK_IS_EMPTY(prLink)) { \ + prEntry = (_P_TYPE)NULL; \ + } \ + else { \ + prEntry = (_P_TYPE)(((P_LINK_T)(prLink))->prNext); \ + linkDel((P_LINK_ENTRY_T)prEntry); \ + ((prLink)->u4NumElem)--; \ + } \ + } + +/* Assume the link entry located at the beginning of prEntry Type. + * And also decrease the total entry count. + */ +#define LINK_REMOVE_KNOWN_ENTRY(prLink, prEntry) \ + { \ + ASSERT(prLink); \ + ASSERT(prEntry); \ + linkDel((P_LINK_ENTRY_T)prEntry); \ + ((prLink)->u4NumElem)--; \ + } + +/* Iterate over a link list */ +#define LINK_FOR_EACH(prEntry, prLink) \ + for (prEntry = (prLink)->prNext; \ + prEntry != (P_LINK_ENTRY_T)(prLink); \ + prEntry = (P_LINK_ENTRY_T)prEntry->prNext) + +/* Iterate over a link list backwards */ +#define LINK_FOR_EACH_PREV(prEntry, prLink) \ + for (prEntry = (prLink)->prPrev; \ + prEntry != (P_LINK_ENTRY_T)(prLink); \ + prEntry = (P_LINK_ENTRY_T)prEntry->prPrev) + +/* Iterate over a link list safe against removal of link entry */ +#define LINK_FOR_EACH_SAFE(prEntry, prNextEntry, prLink) \ + for (prEntry = (prLink)->prNext, prNextEntry = prEntry->prNext; \ + prEntry != (P_LINK_ENTRY_T)(prLink); \ + prEntry = prNextEntry, prNextEntry = prEntry->prNext) + +/* Iterate over a link list of given type */ +#define LINK_FOR_EACH_ENTRY(prObj, prLink, rMember, _TYPE) \ + for (prObj = LINK_ENTRY((prLink)->prNext, _TYPE, rMember); \ + &prObj->rMember != (P_LINK_ENTRY_T)(prLink); \ + prObj = LINK_ENTRY(prObj->rMember.prNext, _TYPE, rMember)) + +/* Iterate backwards over a link list of given type */ +#define LINK_FOR_EACH_ENTRY_PREV(prObj, prLink, rMember, _TYPE) \ + for (prObj = LINK_ENTRY((prLink)->prPrev, _TYPE, rMember); \ + &prObj->rMember != (P_LINK_ENTRY_T)(prLink); \ + prObj = LINK_ENTRY(prObj->rMember.prPrev, _TYPE, rMember)) + +/* Iterate over a link list of given type safe against removal of link entry */ +#define LINK_FOR_EACH_ENTRY_SAFE(prObj, prNextObj, prLink, rMember, _TYPE) \ + for (prObj = LINK_ENTRY((prLink)->prNext, _TYPE, rMember), \ + prNextObj = LINK_ENTRY(prObj->rMember.prNext, _TYPE, rMember); \ + &prObj->rMember != (P_LINK_ENTRY_T)(prLink); \ + prObj = prNextObj, \ + prNextObj = LINK_ENTRY(prNextObj->rMember.prNext, _TYPE, rMember)) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is only for internal link list manipulation. +* +* \param[in] prNew Pointer of new link head +* \param[in] prPrev Pointer of previous link head +* \param[in] prNext Pointer of next link head +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +__KAL_INLINE__ VOID +__linkAdd ( + IN P_LINK_ENTRY_T prNew, + IN P_LINK_ENTRY_T prPrev, + IN P_LINK_ENTRY_T prNext + ) +{ + prNext->prPrev = prNew; + prNew->prNext = prNext; + prNew->prPrev = prPrev; + prPrev->prNext = prNew; + + return; +} /* end of __linkAdd() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will add a new entry after the specified link head. +* +* \param[in] prNew New entry to be added +* \param[in] prHead Specified link head to add it after +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +__KAL_INLINE__ VOID +linkAdd ( + IN P_LINK_ENTRY_T prNew, + IN P_LINK_T prLink + ) +{ + __linkAdd(prNew, (P_LINK_ENTRY_T)prLink, prLink->prNext); + + return; +} /* end of linkAdd() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will add a new entry before the specified link head. +* +* \param[in] prNew New entry to be added +* \param[in] prHead Specified link head to add it before +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +__KAL_INLINE__ VOID +linkAddTail ( + IN P_LINK_ENTRY_T prNew, + IN P_LINK_T prLink + ) +{ + __linkAdd(prNew, prLink->prPrev, (P_LINK_ENTRY_T)prLink); + + return; +} /* end of linkAddTail() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is only for internal link list manipulation. +* +* \param[in] prPrev Pointer of previous link head +* \param[in] prNext Pointer of next link head +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +__KAL_INLINE__ VOID +__linkDel ( + IN P_LINK_ENTRY_T prPrev, + IN P_LINK_ENTRY_T prNext + ) +{ + prNext->prPrev = prPrev; + prPrev->prNext = prNext; + + return; +} /* end of __linkDel() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will delete a specified entry from link list. +* NOTE: the entry is in an initial state. +* +* \param prEntry Specified link head(entry) +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +__KAL_INLINE__ VOID +linkDel ( + IN P_LINK_ENTRY_T prEntry + ) +{ + __linkDel(prEntry->prPrev, prEntry->prNext); + + LINK_ENTRY_INITIALIZE(prEntry); + + return; +} /* end of linkDel() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will delete a specified entry from link list and then add it +* after the specified link head. +* +* \param[in] prEntry Specified link head(entry) +* \param[in] prOtherHead Another link head to add it after +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +__KAL_INLINE__ VOID +linkMove ( + IN P_LINK_ENTRY_T prEntry, + IN P_LINK_T prLink + ) +{ + __linkDel(prEntry->prPrev, prEntry->prNext); + linkAdd(prEntry, prLink); + + return; +} /* end of linkMove() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will delete a specified entry from link list and then add it +* before the specified link head. +* +* \param[in] prEntry Specified link head(entry) +* \param[in] prOtherHead Another link head to add it before +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +__KAL_INLINE__ VOID +linkMoveTail ( + IN P_LINK_ENTRY_T prEntry, + IN P_LINK_T prLink + ) +{ + __linkDel(prEntry->prPrev, prEntry->prNext); + linkAddTail(prEntry, prLink); + + return; +} /* end of linkMoveTail() */ + +#endif /* _LINK_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/aa_fsm.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/aa_fsm.h new file mode 100755 index 000000000000..996f5fa3cf63 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/aa_fsm.h @@ -0,0 +1,295 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/mgmt/aa_fsm.h#1 $ +*/ + +/*! \file aa_fsm.h + \brief Declaration of functions and finite state machine for SAA/AAA Module. + + Declaration of functions and finite state machine for SAA/AAA Module. +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: aa_fsm.h $ + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * refine TX-DONE callback. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add buildable & linkable ais_fsm.c + * + * related reference are still waiting to be resolved + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. + * + * 03 10 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * + * Add Channel Manager for arbitration of JOIN and SCAN Req + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * 01 11 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add Deauth and Disassoc Handler + * + * Nov 24 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Revise MGMT Handler with Retain Status + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +*/ + + +#ifndef _AA_FSM_H +#define _AA_FSM_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* Retry interval for retransmiting authentication-request MMPDU. */ +#define TX_AUTHENTICATION_RETRY_TIMEOUT_TU 100 // TU. + +/* Retry interval for retransmiting association-request MMPDU. */ +#define TX_ASSOCIATION_RETRY_TIMEOUT_TU 100 // TU. + +/* Wait for a response to a transmitted authentication-request MMPDU. */ +#define DOT11_AUTHENTICATION_RESPONSE_TIMEOUT_TU 512 // TU. + +/* Wait for a response to a transmitted association-request MMPDU. */ +#define DOT11_ASSOCIATION_RESPONSE_TIMEOUT_TU 512 // TU. + +/* The maximum time to wait for JOIN process complete. */ +#define JOIN_FAILURE_TIMEOUT_BEACON_INTERVAL 20 // Beacon Interval, 20 * 100TU = 2 sec. + +/* Retry interval for next JOIN request. */ +#define JOIN_RETRY_INTERVAL_SEC 10 // Seconds + +/* Maximum Retry Count for accept a JOIN request. */ +#define JOIN_MAX_RETRY_FAILURE_COUNT 2 // Times + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_AA_STATE_T { + AA_STATE_IDLE = 0, + SAA_STATE_SEND_AUTH1, + SAA_STATE_WAIT_AUTH2, + SAA_STATE_SEND_AUTH3, + SAA_STATE_WAIT_AUTH4, + SAA_STATE_SEND_ASSOC1, + SAA_STATE_WAIT_ASSOC2, + AAA_STATE_SEND_AUTH2, + AAA_STATE_SEND_AUTH4, // We may not use, because P2P GO didn't support WEP and 11r + AAA_STATE_SEND_ASSOC2, + AA_STATE_RESOURCE, // A state for debugging the case of out of msg buffer. + AA_STATE_NUM +} ENUM_AA_STATE_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Routines in saa_fsm.c */ +/*----------------------------------------------------------------------------*/ +VOID +saaFsmSteps ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN ENUM_AA_STATE_T eNextState, + IN P_SW_RFB_T prRetainedSwRfb + ); + +WLAN_STATUS +saaFsmSendEventJoinComplete ( + IN P_ADAPTER_T prAdapter, + WLAN_STATUS rJoinStatus, + P_STA_RECORD_T prStaRec, + P_SW_RFB_T prSwRfb + ); + +VOID +saaFsmRunEventStart ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + +WLAN_STATUS +saaFsmRunEventTxDone ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus + ); + +VOID +saaFsmRunEventTxReqTimeOut ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ); + +VOID +saaFsmRunEventRxRespTimeOut ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ); + +VOID +saaFsmRunEventRxAuth ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + +WLAN_STATUS +saaFsmRunEventRxAssoc ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + +WLAN_STATUS +saaFsmRunEventRxDeauth ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + +WLAN_STATUS +saaFsmRunEventRxDisassoc ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + +VOID +saaFsmRunEventAbort ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + +/*----------------------------------------------------------------------------*/ +/* Routines in aaa_fsm.c */ +/*----------------------------------------------------------------------------*/ +VOID +aaaFsmRunEventRxAuth ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + +WLAN_STATUS +aaaFsmRunEventRxAssoc ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + +WLAN_STATUS +aaaFsmRunEventTxDone ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _AA_FSM_H */ + + + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/ais_fsm.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/ais_fsm.h new file mode 100755 index 000000000000..ef4c9d2f2a64 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/ais_fsm.h @@ -0,0 +1,719 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/mgmt/ais_fsm.h#1 $ +*/ + +/*! \file ais_fsm.h + \brief Declaration of functions and finite state machine for AIS Module. + + Declaration of functions and finite state machine for AIS Module. +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: ais_fsm.h $ + * + * 11 22 2011 cp.wu + * [WCXRP00001120] [MT6620 Wi-Fi][Driver] Modify roaming to AIS state transition from synchronous to asynchronous approach to avoid incomplete state termination + * 1. change RDD related compile option brace position. + * 2. when roaming is triggered, ask AIS to transit immediately only when AIS is in Normal TR state without join timeout timer ticking + * 3. otherwise, insert AIS_REQUEST into pending request queue + * + * 04 25 2011 cp.wu + * [WCXRP00000676] [MT6620 Wi-Fi][Driver] AIS to reduce request channel period from 5 seconds to 2 seconds + * channel interval for joining is shortened to 2 seconds to avoid interruption of concurrent operating network. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 02 26 2011 tsaiyuan.hsu + * [WCXRP00000391] [MT6620 Wi-Fi][FW] Add Roaming Support + * not send disassoc or deauth to leaving AP so as to improve performace of roaming. + * + * 02 22 2011 cp.wu + * [WCXRP00000487] [MT6620 Wi-Fi][Driver][AIS] Serve scan and connect request with a queue-based approach to improve response time for scanning request + * handle SCAN and RECONNECT with a FIFO approach. + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 01 14 2011 cp.wu + * [WCXRP00000359] [MT6620 Wi-Fi][Driver] add an extra state to ensure DEAUTH frame is always sent + * Add an extra state to guarantee DEAUTH frame is sent then connect to new BSS. + * This change is due to WAPI AP needs DEAUTH frame as a necessary step in handshaking protocol. + * + * 11 25 2010 cp.wu + * [WCXRP00000208] [MT6620 Wi-Fi][Driver] Add scanning with specified SSID to AIS FSM + * add scanning with specified SSID facility to AIS-FSM + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 09 06 2010 cp.wu + * NULL + * 1) initialize for correct parameter even for disassociation. + * 2) AIS-FSM should have a limit on trials to build connection + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 25 2010 cp.wu + * NULL + * [AIS-FSM] IBSS no longer needs to acquire channel for beaconing, RLM/CNM will handle the channel switching when BSS information is updated + * + * 08 12 2010 kevin.huang + * NULL + * Refine bssProcessProbeRequest() and bssSendBeaconProbeResponse() + * + * 08 12 2010 cp.wu + * NULL + * [AIS-FSM] honor registry setting for adhoc running mode. (A/B/G) + * + * 08 03 2010 cp.wu + * NULL + * surpress compilation warning. + * + * 07 30 2010 cp.wu + * NULL + * 1) BoW wrapper: use definitions instead of hard-coded constant for error code + * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead + * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames + * + * 07 26 2010 cp.wu + * + * AIS-FSM: when scan request is coming in the 1st 5 seconds of channel privilege period, just pend it til 5-sec. period finishes + * + * 07 26 2010 cp.wu + * + * AIS-FSM FIX: return channel privilege even when the privilege is not granted yet + * QM: qmGetFrameAction() won't assert when corresponding STA-REC index is not found + * + * 07 23 2010 cp.wu + * + * add AIS-FSM handling for beacon timeout event. + * + * 07 21 2010 cp.wu + * + * separate AIS-FSM states into different cases of channel request. + * + * 07 21 2010 cp.wu + * + * 1) change BG_SCAN to ONLINE_SCAN for consistent term + * 2) only clear scanning result when scan is permitted to do + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * Add Ad-Hoc support to AIS-FSM + * + * 07 14 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * Refine AIS-FSM by divided into more states + * + * 07 09 2010 cp.wu + * + * 1) separate AIS_FSM state for two kinds of scanning. (OID triggered scan, and scan-for-connection) + * 2) eliminate PRE_BSS_DESC_T, Beacon/PrebResp is now parsed in single pass + * 3) implment DRV-SCN module, currently only accepts single scan request, other request will be directly dropped by returning BUSY + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * AIS-FSM integration with CNM channel request messages + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implementation of DRV-SCN and related mailbox message handling. + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add buildable & linkable ais_fsm.c + * + * related reference are still waiting to be resolved + * + * 06 09 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add definitions for module migration. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 04 23 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * reduce the backgroud ssid idle time min and max value + * + * 04 19 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * Add Beacon Timeout Support + * * and will send Null frame to diagnose connection + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 03 10 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * + * * Add Channel Manager for arbitration of JOIN and SCAN Req + * + * 02 26 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Remove CFG_TEST_VIRTUAL_CMD and add support of Driver STA_RECORD_T activation + * + * 02 23 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Support dynamic channel selection + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * 01 11 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add Deauth and Disassoc Handler + * + * 01 07 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add Media disconnect indication and related postpone functions + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add aisFsmRunEventJoinComplete() + * + * Nov 25 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add Virtual CMD & RESP for testing CMD PATH + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * add aisFsmInitializeConnectionSettings() + * + * Nov 20 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add CFG_TEST_MGMT_FSM for aisFsmTest() + * + * Nov 18 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add function prototype of aisFsmInit() + * + * Nov 16 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +*/ + +#ifndef _AIS_FSM_H +#define _AIS_FSM_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define AIS_BG_SCAN_INTERVAL_MIN_SEC 2 //30 // exponential to 960 +#define AIS_BG_SCAN_INTERVAL_MAX_SEC 2 //960 // 16min + +#define AIS_DELAY_TIME_OF_DISCONNECT_SEC 10 + +#define AIS_IBSS_ALONE_TIMEOUT_SEC 20 // seconds + +#define AIS_BEACON_TIMEOUT_COUNT_ADHOC 30 +#define AIS_BEACON_TIMEOUT_COUNT_INFRA 10 +#define AIS_BEACON_TIMEOUT_GUARD_TIME_SEC 1 /* Second */ + +#define AIS_BEACON_MAX_TIMEOUT_TU 100 +#define AIS_BEACON_MIN_TIMEOUT_TU 5 +#define AIS_BEACON_MAX_TIMEOUT_VALID TRUE +#define AIS_BEACON_MIN_TIMEOUT_VALID TRUE + +#define AIS_BMC_MAX_TIMEOUT_TU 100 +#define AIS_BMC_MIN_TIMEOUT_TU 5 +#define AIS_BMC_MAX_TIMEOUT_VALID TRUE +#define AIS_BMC_MIN_TIMEOUT_VALID TRUE + +#define AIS_JOIN_CH_GRANT_THRESHOLD 10 +#define AIS_JOIN_CH_REQUEST_INTERVAL 2000 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_AIS_STATE_T { + AIS_STATE_IDLE = 0, + AIS_STATE_SEARCH, + AIS_STATE_SCAN, + AIS_STATE_ONLINE_SCAN, + AIS_STATE_LOOKING_FOR, + AIS_STATE_WAIT_FOR_NEXT_SCAN, + AIS_STATE_REQ_CHANNEL_JOIN, + AIS_STATE_JOIN, + AIS_STATE_IBSS_ALONE, + AIS_STATE_IBSS_MERGE, + AIS_STATE_NORMAL_TR, + AIS_STATE_DISCONNECTING, + AIS_STATE_NUM +} ENUM_AIS_STATE_T; + + +typedef struct _MSG_AIS_ABORT_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucReasonOfDisconnect; + BOOLEAN fgDelayIndication; +} MSG_AIS_ABORT_T, *P_MSG_AIS_ABORT_T; + + +typedef struct _MSG_AIS_IBSS_PEER_FOUND_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucNetTypeIndex; + BOOLEAN fgIsMergeIn; /* TRUE: Merge In, FALSE: Merge Out */ + P_STA_RECORD_T prStaRec; +} MSG_AIS_IBSS_PEER_FOUND_T, *P_MSG_AIS_IBSS_PEER_FOUND_T; + +typedef enum _ENUM_AIS_REQUEST_TYPE_T { + AIS_REQUEST_SCAN, + AIS_REQUEST_RECONNECT, + AIS_REQUEST_ROAMING_SEARCH, + AIS_REQUEST_ROAMING_CONNECT, + AIS_REQUEST_NUM +} ENUM_AIS_REQUEST_TYPE_T; + +typedef struct _AIS_REQ_HDR_T { + LINK_ENTRY_T rLinkEntry; + ENUM_AIS_REQUEST_TYPE_T eReqType; +} AIS_REQ_HDR_T, *P_AIS_REQ_HDR_T; + + +typedef struct _AIS_FSM_INFO_T { + ENUM_AIS_STATE_T ePreviousState; + ENUM_AIS_STATE_T eCurrentState; + + BOOLEAN fgTryScan; + + BOOLEAN fgIsInfraChannelFinished; + BOOLEAN fgIsChannelRequested; + BOOLEAN fgIsChannelGranted; + +#if CFG_SUPPORT_ROAMING + BOOLEAN fgIsRoamingScanPending; +#endif /* CFG_SUPPORT_ROAMING */ + + UINT_8 ucAvailableAuthTypes; /* Used for AUTH_MODE_AUTO_SWITCH */ + + P_BSS_DESC_T prTargetBssDesc; /* For destination */ + + P_STA_RECORD_T prTargetStaRec; /* For JOIN Abort */ + + UINT_32 u4SleepInterval; + + TIMER_T rBGScanTimer; + + TIMER_T rIbssAloneTimer; + + TIMER_T rIndicationOfDisconnectTimer; + + TIMER_T rJoinTimeoutTimer; + + UINT_8 ucSeqNumOfReqMsg; + UINT_8 ucSeqNumOfChReq; + UINT_8 ucSeqNumOfScanReq; + + UINT_32 u4ChGrantedInterval; + + UINT_8 ucConnTrialCount; + + UINT_8 ucScanSSIDLen; + UINT_8 aucScanSSID[ELEM_MAX_LEN_SSID]; + + /* Pending Request List */ + LINK_T rPendingReqList; + +} AIS_FSM_INFO_T, *P_AIS_FSM_INFO_T; + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define aisChangeMediaState(_prAdapter, _eNewMediaState) \ + (_prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].eConnectionState = (_eNewMediaState)); + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID +aisInitializeConnectionSettings ( + IN P_ADAPTER_T prAdapter, + IN P_REG_INFO_T prRegInfo + ); + +VOID +aisFsmInit ( + IN P_ADAPTER_T prAdapter + ); + +VOID +aisFsmUninit ( + IN P_ADAPTER_T prAdapter + ); + +VOID +aisFsmStateInit_JOIN ( + IN P_ADAPTER_T prAdapter, + P_BSS_DESC_T prBssDesc + ); + +BOOLEAN +aisFsmStateInit_RetryJOIN ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ); + +VOID +aisFsmStateInit_IBSS_ALONE ( + IN P_ADAPTER_T prAdapter + ); + +VOID +aisFsmStateInit_IBSS_MERGE ( + IN P_ADAPTER_T prAdapter, + P_BSS_DESC_T prBssDesc + ); + +VOID +aisFsmStateAbort ( + IN P_ADAPTER_T prAdapter, + UINT_8 ucReasonOfDisconnect, + BOOLEAN fgDelayIndication + ); + +VOID +aisFsmStateAbort_JOIN ( + IN P_ADAPTER_T prAdapter + ); + +VOID +aisFsmStateAbort_SCAN ( + IN P_ADAPTER_T prAdapter + ); + +VOID +aisFsmStateAbort_NORMAL_TR ( + IN P_ADAPTER_T prAdapter + ); + +VOID +aisFsmStateAbort_IBSS ( + IN P_ADAPTER_T prAdapter + ); + +VOID +aisFsmSteps ( + IN P_ADAPTER_T prAdapter, + ENUM_AIS_STATE_T eNextState + ); + +/*----------------------------------------------------------------------------*/ +/* Mailbox Message Handling */ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmRunEventScanDone ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + +VOID +aisFsmRunEventAbort ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + +VOID +aisFsmRunEventJoinComplete ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + +VOID +aisFsmRunEventFoundIBSSPeer ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + +/*----------------------------------------------------------------------------*/ +/* Handling for Ad-Hoc Network */ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmCreateIBSS ( + IN P_ADAPTER_T prAdapter + ); + +VOID +aisFsmMergeIBSS ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ); + +/*----------------------------------------------------------------------------*/ +/* Handling of Incoming Mailbox Message from CNM */ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmRunEventChGrant ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + + +/*----------------------------------------------------------------------------*/ +/* Generating Outgoing Mailbox Message to CNM */ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmReleaseCh ( + IN P_ADAPTER_T prAdapter + ); + + +/*----------------------------------------------------------------------------*/ +/* Event Indication */ +/*----------------------------------------------------------------------------*/ +VOID +aisIndicationOfMediaStateToHost ( + IN P_ADAPTER_T prAdapter, + ENUM_PARAM_MEDIA_STATE_T eConnectionState, + BOOLEAN fgDelayIndication + ); + +VOID +aisPostponedEventOfDisconnTimeout ( + IN P_ADAPTER_T prAdapter, + UINT_32 u4Param + ); + +VOID +aisUpdateBssInfoForJOIN ( + IN P_ADAPTER_T prAdapter, + P_STA_RECORD_T prStaRec, + P_SW_RFB_T prAssocRspSwRfb + ); + +VOID +aisUpdateBssInfoForCreateIBSS ( + IN P_ADAPTER_T prAdapter + ); + +VOID +aisUpdateBssInfoForMergeIBSS ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ); + +BOOLEAN +aisValidateProbeReq ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT PUINT_32 pu4ControlFlags + ); + +/*----------------------------------------------------------------------------*/ +/* Disconnection Handling */ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmDisconnect ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgDelayIndication + ); + + +/*----------------------------------------------------------------------------*/ +/* Event Handling */ +/*----------------------------------------------------------------------------*/ +VOID +aisBssBeaconTimeout ( + IN P_ADAPTER_T prAdapter + ); + +WLAN_STATUS +aisDeauthXmitComplete ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus + ); + +#if CFG_SUPPORT_ROAMING +VOID +aisFsmRunEventRoamingDiscovery ( + IN P_ADAPTER_T prAdapter, + UINT_32 u4ReqScan + ); + +ENUM_AIS_STATE_T +aisFsmRoamingScanResultsUpdate ( + IN P_ADAPTER_T prAdapter + ); + +VOID +aisFsmRoamingDisconnectPrevAP ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prTargetStaRec + ); + +VOID +aisUpdateBssInfoForRoamingAP ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prAssocRspSwRfb + ); +#endif /*CFG_SUPPORT_ROAMING */ + +/*----------------------------------------------------------------------------*/ +/* Timeout Handling */ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmRunEventBGSleepTimeOut ( + IN P_ADAPTER_T prAdapter, + UINT_32 u4Param + ); + +VOID +aisFsmRunEventIbssAloneTimeOut ( + IN P_ADAPTER_T prAdapter, + UINT_32 u4Param + ); + +VOID +aisFsmRunEventJoinTimeout ( + IN P_ADAPTER_T prAdapter, + UINT_32 u4Param + ); + +/*----------------------------------------------------------------------------*/ +/* OID/IOCTL Handling */ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmScanRequest ( + IN P_ADAPTER_T prAdapter, + IN P_PARAM_SSID_T prSsid + ); + +/*----------------------------------------------------------------------------*/ +/* Internal State Checking */ +/*----------------------------------------------------------------------------*/ +BOOLEAN +aisFsmIsRequestPending ( + IN P_ADAPTER_T prAdapter, + IN ENUM_AIS_REQUEST_TYPE_T eReqType, + IN BOOLEAN bRemove + ); + +P_AIS_REQ_HDR_T +aisFsmGetNextRequest ( + IN P_ADAPTER_T prAdapter + ); + +BOOLEAN +aisFsmInsertRequest ( + IN P_ADAPTER_T prAdapter, + IN ENUM_AIS_REQUEST_TYPE_T eReqType + ); + +VOID +aisFsmFlushRequest ( + IN P_ADAPTER_T prAdapter + ); + + +#if defined(CFG_TEST_MGMT_FSM) && (CFG_TEST_MGMT_FSM != 0) +VOID +aisTest ( + VOID + ); +#endif /* CFG_TEST_MGMT_FSM */ +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _AIS_FSM_H */ + + + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/assoc.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/assoc.h new file mode 100755 index 000000000000..b269c71668d0 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/assoc.h @@ -0,0 +1,191 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/mgmt/assoc.h#1 $ +*/ + +/*! \file assoc.h + \brief This file contains the ASSOC REQ/RESP of + IEEE 802.11 family for MediaTek 802.11 Wireless LAN Adapters. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: assoc.h $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 17 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Add assocCheckTxReAssocRespFrame() proto type for P2P usage. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add buildable & linkable ais_fsm.c + * + * related reference are still waiting to be resolved + * +*/ + +#ifndef _ASSOC_H +#define _ASSOC_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Routines in assoc.c */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +assocSendReAssocReqFrame ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ); + +WLAN_STATUS +assocCheckTxReAssocReqFrame ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + +WLAN_STATUS +assocCheckTxReAssocRespFrame( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + +WLAN_STATUS +assocCheckRxReAssocRspFrameStatus ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT PUINT_16 pu2StatusCode + ); + +WLAN_STATUS +assocSendDisAssocFrame ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN UINT_16 u2ReasonCode + ); + +WLAN_STATUS +assocProcessRxDisassocFrame ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN UINT_8 aucBSSID[], + OUT PUINT_16 pu2ReasonCode + ); + +WLAN_STATUS +assocProcessRxAssocReqFrame ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT PUINT_16 pu2StatusCode + ); + +WLAN_STATUS +assocSendReAssocRespFrame ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _ASSOC_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/auth.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/auth.h new file mode 100755 index 000000000000..827120b73033 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/auth.h @@ -0,0 +1,219 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/mgmt/auth.h#1 $ +*/ + +/*! \file auth.h + \brief This file contains the authentication REQ/RESP of + IEEE 802.11 family for MediaTek 802.11 Wireless LAN Adapters. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: auth.h $ + * + * 04 21 2011 terry.wu + * [WCXRP00000674] [MT6620 Wi-Fi][Driver] Refine AAA authSendAuthFrame + * Add network type parameter to authSendAuthFrame. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add management dispatching function table. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * auth.c is migrated. + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add buildable & linkable ais_fsm.c + * + * related reference are still waiting to be resolved + * +*/ + +#ifndef _AUTH_H +#define _AUTH_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Routines in auth.c */ +/*----------------------------------------------------------------------------*/ +VOID +authAddIEChallengeText ( + IN P_ADAPTER_T prAdapter, + IN OUT P_MSDU_INFO_T prMsduInfo + ); + +#if !CFG_SUPPORT_AAA +WLAN_STATUS +authSendAuthFrame ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN UINT_16 u2TransactionSeqNum + ); +#else +WLAN_STATUS +authSendAuthFrame ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_SW_RFB_T prFalseAuthSwRfb, + IN UINT_16 u2TransactionSeqNum, + IN UINT_16 u2StatusCode + ); +#endif /* CFG_SUPPORT_AAA */ + +WLAN_STATUS +authCheckTxAuthFrame ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN UINT_16 u2TransactionSeqNum + ); + +WLAN_STATUS +authCheckRxAuthFrameTransSeq ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + +WLAN_STATUS +authCheckRxAuthFrameStatus ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN UINT_16 u2TransactionSeqNum, + OUT PUINT_16 pu2StatusCode + ); + +VOID +authHandleIEChallengeText ( + P_ADAPTER_T prAdapter, + P_SW_RFB_T prSwRfb, + P_IE_HDR_T prIEHdr + ); + +WLAN_STATUS +authProcessRxAuth2_Auth4Frame ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + +WLAN_STATUS +authSendDeauthFrame ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prClassErrSwRfb, + IN UINT_16 u2ReasonCode, + IN PFN_TX_DONE_HANDLER pfTxDoneHandler + ); + +WLAN_STATUS +authProcessRxDeauthFrame ( + IN P_SW_RFB_T prSwRfb, + IN UINT_8 aucBSSID[], + OUT PUINT_16 pu2ReasonCode + ); + +WLAN_STATUS +authProcessRxAuth1Frame ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN UINT_8 aucExpectedBSSID[], + IN UINT_16 u2ExpectedAuthAlgNum, + IN UINT_16 u2ExpectedTransSeqNum, + OUT PUINT_16 pu2ReturnStatusCode + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _AUTH_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/bow_fsm.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/bow_fsm.h new file mode 100755 index 000000000000..05cc3edb5099 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/bow_fsm.h @@ -0,0 +1,234 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/mgmt/bow_fsm.h#1 $ +*/ + +/*! \file bow_fsm.h + \brief Declaration of functions and finite state machine for BOW Module. + + Declaration of functions and finite state machine for BOW Module. +*/ + +/******************************************************************************* +* Copyright (c) 2010 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: bow_fsm.h $ + * + * 05 22 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * Submit missing BoW header files. + * + * 03 27 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Support multiple physical link. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 02 16 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add bowNotifyAllLinkDisconnected interface and change channel grant procedure for bow starting.. + * + * 02 15 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add channel previledge into _BOW_FSM_INFO_T. + * + * 09 16 2010 chinghwa.yu + * NULL + * update bowChangeMediaState. + * + * 08 24 2010 chinghwa.yu + * NULL + * Update BOW for the 1st time. + */ + +#ifndef _BOW_FSM_H +#define _BOW_FSM_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define BOW_BG_SCAN_INTERVAL_MIN_SEC 2 //30 // exponential to 960 +#define BOW_BG_SCAN_INTERVAL_MAX_SEC 2 //960 // 16min + +#define BOW_DELAY_TIME_OF_DISCONNECT_SEC 10 + +#define BOW_BEACON_TIMEOUT_COUNT_STARTING 10 +#define BOW_BEACON_TIMEOUT_GUARD_TIME_SEC 1 /* Second */ + +#define BOW_BEACON_MAX_TIMEOUT_TU 100 +#define BOW_BEACON_MIN_TIMEOUT_TU 5 +#define BOW_BEACON_MAX_TIMEOUT_VALID TRUE +#define BOW_BEACON_MIN_TIMEOUT_VALID TRUE + +#define BOW_BMC_MAX_TIMEOUT_TU 100 +#define BOW_BMC_MIN_TIMEOUT_TU 5 +#define BOW_BMC_MAX_TIMEOUT_VALID TRUE +#define BOW_BMC_MIN_TIMEOUT_VALID TRUE + +#define BOW_JOIN_CH_GRANT_THRESHOLD 10 +#define BOW_JOIN_CH_REQUEST_INTERVAL 2000 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef enum _ENUM_BOW_STATE_T { + BOW_STATE_IDLE = 0, + BOW_STATE_SEARCH, + BOW_STATE_SCAN, + BOW_STATE_ONLINE_SCAN, + BOW_STATE_LOOKING_FOR, + BOW_STATE_WAIT_FOR_NEXT_SCAN, + BOW_STATE_REQ_CHANNEL_JOIN, + BOW_STATE_REQ_CHANNEL_ALONE, + BOW_STATE_REQ_CHANNEL_MERGE, + BOW_STATE_JOIN, + BOW_STATE_IBSS_ALONE, + BOW_STATE_IBSS_MERGE, + BOW_STATE_NORMAL_TR, + BOW_STATE_NUM +} ENUM_BOW_STATE_T; + +typedef struct _BOW_FSM_INFO_T { + ENUM_BOW_STATE_T ePreviousState; + ENUM_BOW_STATE_T eCurrentState; + + BOOLEAN fgTryScan; + + /* Channel Privilege */ + + BOOLEAN fgIsInfraChannelFinished; + BOOLEAN fgIsChannelRequested; + BOOLEAN fgIsChannelGranted; + BOOLEAN fgIsScanPending; + UINT_32 u4ChGrantedInterval; + + + UINT_8 ucPrimaryChannel; + ENUM_BAND_T eBand; + UINT_16 u2BeaconInterval; + + ENUM_BOW_STATE_T eReturnState; /* Return state after current activity finished or abort. */ + ENUM_BOW_STATE_T eForwardState; /* Step to next state if ACTION frame is TX successfully. */ + + P_BSS_DESC_T prTargetBss; /* BSS of target P2P Device. For Connection/Service Discovery */ + + P_STA_RECORD_T prTargetStaRec; + P_BSS_DESC_T prTargetBssDesc; /* For destination */ + + UINT_8 aucPeerAddress[6]; + + UINT_8 ucRole; + + BOOLEAN fgSupportQoS; + + BOOLEAN fgIsRsponseProbe; /* Indicate if BOW can response probe request frame. */ + + /* Sequence number of requested message. */ + UINT_8 ucSeqNumOfChReq; + UINT_8 ucSeqNumOfReqMsg; + UINT_8 ucSeqNumOfScnMsg; + UINT_8 ucSeqNumOfScanReq; + + UINT_8 ucSeqNumOfCancelMsg; + + UINT_8 ucDialogToken; + + /* Timer */ + TIMER_T rStartingBeaconTimer; /* For device discovery time of each discovery request from user.*/ + TIMER_T rStartingDiscoveryTimer; + TIMER_T rOperationListenTimer; /* For Find phase under operational state. */ + TIMER_T rFSMTimer; /* A timer used for Action frame timeout usage. */ + TIMER_T rIndicationOfDisconnectTimer; + TIMER_T rChGrantedTimer; + + UINT_8 ucAvailableAuthTypes; /* Used for AUTH_MODE_AUTO_SWITCH */ + +} BOW_FSM_INFO_T, *P_BOW_FSM_INFO_T; + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define bowChangeMediaState(_prAdapter, _eNewMediaState) \ + (_prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX].eConnectionState = (_eNewMediaState)); + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + + + +#endif diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/bss.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/bss.h new file mode 100755 index 000000000000..49e56742f9f8 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/bss.h @@ -0,0 +1,457 @@ +/* +** $Id: @(#) bss.h +*/ + +/*! \file "bss.h" + \brief In this file we define the function prototype used in BSS/IBSS. + + The file contains the function declarations and defines for used in BSS/IBSS. +*/ + +/******************************************************************************* +* Copyright (c) 2010 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: bss.h $ + * + * 01 15 2012 yuche.tsai + * NULL + * Fix wrong basic rate issue. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 03 19 2011 yuche.tsai + * [WCXRP00000581] [Volunteer Patch][MT6620][Driver] P2P IE in Assoc Req Issue + * Append P2P IE in assoc request if P2P is enabled. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 02 2011 wh.su + * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request + * Add code to send beacon and probe response WSC IE at Auto GO. + * + * 02 23 2011 eddie.chen + * [WCXRP00000463] [MT6620 Wi-Fi][FW/Driver][Hotspot] Cannot update WMM PS STA's partital bitmap + * Fix parsing WMM INFO and bmp delivery bitmap definition. + * + * 01 31 2011 george.huang + * [WCXRP00000333] [MT5931][FW] support SRAM power control drivers + * Extend TIM PVB, from 2 to 3 octets. + * + * 11 29 2010 cp.wu + * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC for initial TX rate selection of auto-rate algorithm + * update ucRcpi of STA_RECORD_T for AIS when + * 1) Beacons for IBSS merge is received + * 2) Associate Response for a connecting peer is received + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 12 2010 kevin.huang + * NULL + * Update bssProcessProbeRequest() and bssSendBeaconProbeResponse() declarations + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * when IBSS is being merged-in, send command packet to PM for connected indication + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 25 2010 george.huang + * [WPD00001556]Basic power managemenet function + * Create beacon update path, with expose bssUpdateBeaconContent() + * + * 06 17 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Add CTRL FLAGS for Probe Response. + * + * 06 09 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add necessary changes to driver data paths. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. + * + * 06 04 2010 george.huang + * [BORA00000678][MT6620]WiFi LP integration + * [PM] Support U-APSD for STA mode + * + * 05 28 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add ClientList handling API - bssClearClientList, bssAddStaRecToClientList + * + * 05 14 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Remove unused typedef. + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Fix file merge error + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 04 19 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * Add Beacon Timeout Support + * * * and will send Null frame to diagnose connection + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 02 23 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add DTIM count update while TX Beacon + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup +*/ + +#ifndef _BSS_H +#define _BSS_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +//NOTE(Kevin): change define for george +//#define MAX_LEN_TIM_PARTIAL_BMP (((MAX_ASSOC_ID + 1) + 7) / 8) /* Required bits = (MAX_ASSOC_ID + 1) */ +#define MAX_LEN_TIM_PARTIAL_BMP ((CFG_STA_REC_NUM + 7) / 8) /* reserve length greater than maximum size of STA_REC */ //obsoleted: Assume we only use AID:1~15 + +/* CTRL FLAGS for Probe Response */ +#define BSS_PROBE_RESP_USE_P2P_DEV_ADDR BIT(0) +#define BSS_PROBE_RESP_INCLUDE_P2P_IE BIT(1) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define bssAssignAssocID(_prStaRec) ((_prStaRec)->ucIndex + 1) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Routines for all Operation Modes */ +/*----------------------------------------------------------------------------*/ +P_STA_RECORD_T +bssCreateStaRecFromBssDesc ( + IN P_ADAPTER_T prAdapter, + IN ENUM_STA_TYPE_T eStaType, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_BSS_DESC_T prBssDesc + ); + +VOID +bssComposeNullFrame ( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucBuffer, + IN P_STA_RECORD_T prStaRec + ); + +VOID +bssComposeQoSNullFrame ( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucBuffer, + IN P_STA_RECORD_T prStaRec, + IN UINT_8 ucUP, + IN BOOLEAN fgSetEOSP + ); + +WLAN_STATUS +bssSendNullFrame ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN PFN_TX_DONE_HANDLER pfTxDoneHandler + ); + +WLAN_STATUS +bssSendQoSNullFrame ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN UINT_8 ucUP, + IN PFN_TX_DONE_HANDLER pfTxDoneHandler + ); + + +/*----------------------------------------------------------------------------*/ +/* Routines for both IBSS(AdHoc) and BSS(AP) */ +/*----------------------------------------------------------------------------*/ +VOID +bssGenerateExtSuppRate_IE ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + +VOID +bssBuildBeaconProbeRespFrameCommonIEs ( + IN P_MSDU_INFO_T prMsduInfo, + IN P_BSS_INFO_T prBssInfo, + IN PUINT_8 pucDestAddr + ); + +VOID +bssComposeBeaconProbeRespFrameHeaderAndFF ( + IN PUINT_8 pucBuffer, + IN PUINT_8 pucDestAddr, + IN PUINT_8 pucOwnMACAddress, + IN PUINT_8 pucBSSID, + IN UINT_16 u2BeaconInterval, + IN UINT_16 u2CapInfo + ); + +WLAN_STATUS +bssSendBeaconProbeResponse ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN PUINT_8 pucDestAddr, + IN UINT_32 u4ControlFlags + ); + +WLAN_STATUS +bssProcessProbeRequest ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + +VOID +bssClearClientList ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo + ); + +VOID +bssAddStaRecToClientList ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN P_STA_RECORD_T prStaRec + ); + +VOID +bssRemoveStaRecFromClientList ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN P_STA_RECORD_T prStaRec + ); + + +/*----------------------------------------------------------------------------*/ +/* Routines for IBSS(AdHoc) only */ +/*----------------------------------------------------------------------------*/ +VOID +ibssProcessMatchedBeacon ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN P_BSS_DESC_T prBssDesc, + IN UINT_8 ucRCPI + ); + +WLAN_STATUS +ibssCheckCapabilityForAdHocMode ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc + ); + +VOID +ibssInitForAdHoc ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo + ); + +WLAN_STATUS +bssUpdateBeaconContent ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex + ); + + +/*----------------------------------------------------------------------------*/ +/* Routines for BSS(AP) only */ +/*----------------------------------------------------------------------------*/ +VOID +bssInitForAP ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN BOOLEAN fgIsRateUpdate + ); + +VOID +bssUpdateDTIMCount ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex + ); + +VOID +bssSetTIMBitmap ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN UINT_16 u2AssocId + ); + + +/*link function to p2p module for txBcnIETable*/ +#if CFG_ENABLE_WIFI_DIRECT +UINT_32 +linkToP2pCalculateP2P_IELenForBeacon ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec + ); + +VOID +linkToP2pGenerateP2P_IEForBeacon ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + +UINT_32 +linkToP2pCalculateWSC_IELenForBeacon ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec + ); + +VOID +linkToP2pGenerateP2P_IEForAssocReq ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + +VOID +linkToP2pGenerateP2P_IEForAssocRsp ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + + +UINT_32 +linkToP2pCalculateP2P_IELenForAssocReq ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec + ); + +UINT_32 +linkToP2pCalculateP2P_IELenForAssocRsp ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec + ); + +VOID +linkToP2pGenerateWSC_IEForBeacon( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + +UINT_32 +linkToP2pCalculateWSC_IELenForProbeRsp ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec + ); + +VOID +linkToP2pGenerateWSC_IEForProbeRsp( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); +#endif + +/* WMM-2.2.2 WMM ACI to AC coding */ +typedef enum _ENUM_ACI_T { + ACI_BE = 0, + ACI_BK = 1, + ACI_VI = 2, + ACI_VO = 3, + ACI_NUM +} ENUM_ACI_T, *P_ENUM_ACI_T; + +typedef enum _ENUM_AC_PRIORITY_T { + AC_BK_PRIORITY = 0, + AC_BE_PRIORITY, + AC_VI_PRIORITY, + AC_VO_PRIORITY +} ENUM_AC_PRIORITY_T, *P_ENUM_AC_PRIORITY_T; + + +#endif /* _BSS_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/cnm.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/cnm.h new file mode 100755 index 000000000000..fa8f927c5f10 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/cnm.h @@ -0,0 +1,362 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/mgmt/cnm.h#1 $ +*/ + +/*! \file "cnm.h" + \brief +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: cnm.h $ + * + * 06 23 2011 cp.wu + * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module + * follow-ups for frequency-shifted WAPI AP support + * + * 04 12 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 10 2011 cm.chang + * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module + * Add some functions to let AIS/Tethering or AIS/BOW be the same channel + * + * 01 12 2011 cm.chang + * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module + * Provide function to decide if BSS can be activated or not + * + * 12 07 2010 cm.chang + * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk + * 1. BSSINFO include RLM parameter + * 2. free all sta records when network is disconnected + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 07 19 2010 cm.chang + * + * Set RLM parameters and enable CNM channel manager + * + * 07 13 2010 cm.chang + * + * Rename MSG_CH_RELEASE_T to MSG_CH_ABORT_T + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Rename MID_MNY_CNM_CH_RELEASE to MID_MNY_CNM_CH_ABORT + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Need bandwidth info when requesting channel privilege + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Modify CNM message handler for new flow + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 05 05 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add a new function to send abort message + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 03 10 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * Add Channel Manager for arbitration of JOIN and SCAN Req + * + * 02 08 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support partial part about cmd basic configuration + * + * Nov 18 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add prototype of cnmFsmEventInit() + * + * Nov 2 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +** +*/ + +#ifndef _CNM_H +#define _CNM_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef enum _ENUM_CH_REQ_TYPE_T { + CH_REQ_TYPE_JOIN, + CH_REQ_TYPE_P2P_LISTEN, + + CH_REQ_TYPE_NUM +} ENUM_CH_REQ_TYPE_T, *P_ENUM_CH_REQ_TYPE_T; + +typedef struct _MSG_CH_REQ_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucNetTypeIndex; + UINT_8 ucTokenID; + UINT_8 ucPrimaryChannel; + ENUM_CHNL_EXT_T eRfSco; + ENUM_BAND_T eRfBand; + ENUM_CH_REQ_TYPE_T eReqType; + UINT_32 u4MaxInterval; /* In unit of ms */ + UINT_8 aucBSSID[6]; + UINT_8 aucReserved[2]; +} MSG_CH_REQ_T, *P_MSG_CH_REQ_T; + +typedef struct _MSG_CH_ABORT_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucNetTypeIndex; + UINT_8 ucTokenID; +} MSG_CH_ABORT_T, *P_MSG_CH_ABORT_T; + +typedef struct _MSG_CH_GRANT_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucNetTypeIndex; + UINT_8 ucTokenID; + UINT_8 ucPrimaryChannel; + ENUM_CHNL_EXT_T eRfSco; + ENUM_BAND_T eRfBand; + ENUM_CH_REQ_TYPE_T eReqType; + UINT_32 u4GrantInterval; /* In unit of ms */ +} MSG_CH_GRANT_T, *P_MSG_CH_GRANT_T; + +typedef struct _MSG_CH_REOCVER_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucNetTypeIndex; + UINT_8 ucTokenID; + UINT_8 ucPrimaryChannel; + ENUM_CHNL_EXT_T eRfSco; + ENUM_BAND_T eRfBand; + ENUM_CH_REQ_TYPE_T eReqType; +} MSG_CH_RECOVER_T, *P_MSG_CH_RECOVER_T; + + +typedef struct _CNM_INFO_T { + UINT_32 u4Reserved; +} CNM_INFO_T, *P_CNM_INFO_T; + +#if CFG_ENABLE_WIFI_DIRECT +/* Moved from p2p_fsm.h */ +typedef struct _DEVICE_TYPE_T { + UINT_16 u2CategoryId; /* Category ID */ + UINT_8 aucOui[4]; /* OUI */ + UINT_16 u2SubCategoryId; /* Sub Category ID */ +} __KAL_ATTRIB_PACKED__ DEVICE_TYPE_T, *P_DEVICE_TYPE_T; +#endif + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID +cnmInit ( + P_ADAPTER_T prAdapter + ); + +VOID +cnmUninit ( + P_ADAPTER_T prAdapter + ); + +VOID +cnmChMngrRequestPrivilege ( + P_ADAPTER_T prAdapter, + P_MSG_HDR_T prMsgHdr + ); + +VOID +cnmChMngrAbortPrivilege ( + P_ADAPTER_T prAdapter, + P_MSG_HDR_T prMsgHdr + ); + +VOID +cnmChMngrHandleChEvent ( + P_ADAPTER_T prAdapter, + P_WIFI_EVENT_T prEvent + ); + +BOOLEAN +cnmPreferredChannel ( + P_ADAPTER_T prAdapter, + P_ENUM_BAND_T prBand, + PUINT_8 pucPrimaryChannel, + P_ENUM_CHNL_EXT_T prBssSCO + ); + +BOOLEAN +cnmAisInfraChannelFixed ( + P_ADAPTER_T prAdapter, + P_ENUM_BAND_T prBand, + PUINT_8 pucPrimaryChannel + ); + +VOID +cnmAisInfraConnectNotify ( + P_ADAPTER_T prAdapter + ); + +BOOLEAN +cnmAisIbssIsPermitted ( + P_ADAPTER_T prAdapter + ); + +BOOLEAN +cnmP2PIsPermitted ( + P_ADAPTER_T prAdapter + ); + +BOOLEAN +cnmBowIsPermitted ( + P_ADAPTER_T prAdapter + ); + +BOOLEAN +cnmBss40mBwPermitted ( + P_ADAPTER_T prAdapter, + ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#ifndef _lint +/* We don't have to call following function to inspect the data structure. + * It will check automatically while at compile time. + * We'll need this to guarantee the same member order in different structures + * to simply handling effort in some functions. + */ +__KAL_INLINE__ VOID +cnmMsgDataTypeCheck ( + VOID + ) +{ + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSG_CH_GRANT_T,rMsgHdr) == 0); + + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSG_CH_GRANT_T,rMsgHdr) == + OFFSET_OF(MSG_CH_RECOVER_T,rMsgHdr)); + + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSG_CH_GRANT_T,ucNetTypeIndex) == + OFFSET_OF(MSG_CH_RECOVER_T,ucNetTypeIndex)); + + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSG_CH_GRANT_T,ucTokenID) == + OFFSET_OF(MSG_CH_RECOVER_T,ucTokenID)); + + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSG_CH_GRANT_T,ucPrimaryChannel) == + OFFSET_OF(MSG_CH_RECOVER_T,ucPrimaryChannel)); + + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSG_CH_GRANT_T,eRfSco) == + OFFSET_OF(MSG_CH_RECOVER_T,eRfSco)); + + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSG_CH_GRANT_T,eRfBand) == + OFFSET_OF(MSG_CH_RECOVER_T,eRfBand)); + + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSG_CH_GRANT_T,eReqType) == + OFFSET_OF(MSG_CH_RECOVER_T,eReqType)); + + return; +} +#endif /* _lint */ + +#endif /* _CNM_H */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/cnm_mem.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/cnm_mem.h new file mode 100755 index 000000000000..16554b40ceec --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/cnm_mem.h @@ -0,0 +1,1196 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/mgmt/cnm_mem.h#2 $ +*/ + +/*! \file "cnm_mem.h" + \brief In this file we define the structure of the control unit of + packet buffer and MGT/MSG Memory Buffer. +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: cnm_mem.h $ + * + * 01 17 2012 wh.su + * [WCXRP00001173] [MT6620 Wi-Fi][Driver] Adding the ICS Tethering WPA2-PSK supporting + * Adding the related code which support beacon can reflect the security setting open or WPA2-PSK, WPA-PSK not yet + * Adn support the indicate the assoc request ie at New STA CMD, needed kernel patch. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 17 2011 yuche.tsai + * NULL + * Resize the Secondary Device Type array when WiFi Direct is enabled. + * + * 03 16 2011 wh.su + * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done + * enable the protected while at P2P start GO, and skip some security check . + * + * 01 26 2011 cm.chang + * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument + * . + * + * 01 11 2011 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, + +Add per station flow control when STA is in PS + + + * Add per STA flow control when STA is in PS mode + * + * 12 29 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, +Add per station flow control when STA is in PS + + * 1) PS flow control event + * + * 2) WMM IE in beacon, assoc resp, probe resp + * + * 12 23 2010 george.huang + * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function + * 1. update WMM IE parsing, with ASSOC REQ handling + * 2. extend U-APSD parameter passing from driver to FW + * + * 12 07 2010 cm.chang + * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk + * 1. BSSINFO include RLM parameter + * 2. free all sta records when network is disconnected + * + * 11 29 2010 cm.chang + * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC for initial TX rate selection of auto-rate algorithm + * Sync RCPI of STA_REC to FW as reference of initial TX rate + * + * 10 18 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS associated + * 1. remove redundant variables in STA_REC structure + * 2. add STA-REC uninitialization routine for clearing pending events + * + * 09 21 2010 kevin.huang + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * Eliminate Linux Compile Warning + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 07 12 2010 cp.wu + * + * SAA will take a record for tracking request sequence number. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 07 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Support state of STA record change from 1 to 1 + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Support sync command of STA_REC + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * modify some code for concurrent network. + * + * 06 21 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Fix compile error for P2P related defination. + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 17 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Add P2P related fields. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * saa_fsm.c is migrated. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * restore utility function invoking via hem_mbox to direct calls + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add buildable & linkable ais_fsm.c + * + * related reference are still waiting to be resolved + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * hem_mbox is migrated. + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add hem_mbox.c and cnm_mem.h (but disabled some feature) for further migration + * + * 06 04 2010 george.huang + * [BORA00000678][MT6620]WiFi LP integration + * [BORA00000678] [MT6620]WiFi LP integration + * 1. add u8TimeStamp in MSDU_INFO + * 2. move fgIsRxTSFUpdated/fgIsTxTSFUpdated from static to BSS_INFO + * 3. add new member for supporting PM in STA_RECORD, which is for AP PS mode + * + * 05 31 2010 yarco.yang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add RX TSF Log Feature and ADDBA Rsp with DECLINE handling + * + * 05 28 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support checking of duplicated buffer free + * + * 05 28 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Move define of STA_REC_NUM to config.h and rename to CFG_STA_REC_NUM + * + * 05 21 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Refine txmInitWtblTxRateTable() - set TX initial rate according to AP's operation rate set + * + * 05 19 2010 yarco.yang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Fixed MAC RX Desc be overwritten issue + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 05 10 2010 yarco.yang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support Rx header translation for A-MSDU subframe + * + * 05 07 2010 george.huang + * [BORA00000678][MT6620]WiFi LP integration + * add more sanity check about setting timer + * + * 04 29 2010 george.huang + * [BORA00000678][MT6620]WiFi LP integration + * modify the compiling flag for RAM usage + * + * 04 28 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * Modified some MQM-related data structures (SN counter, TX/RX BA table) + * + * 04 27 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * Added new TX/RX BA tables in STA_REC + * + * 04 19 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * Add Beacon Timeout Support and will send Null frame to diagnose connection + * + * 04 09 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * [BORA00000644] WiFi phase 4 integration + * Added per-TID SN cache in STA_REC + * + * 03 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support power control + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 03 11 2010 yuche.tsai + * [BORA00000343][MT6620] Emulation For TX + * . + * + * 03 05 2010 yarco.yang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Remove Emulation definition + * + * 03 04 2010 cp.wu + * [BORA00000368]Integrate HIF part into BORA + * eliminate HIF_EMULATION in cnm_mem.h + * + * 03 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add cnmStaRecChangeState() declaration. + * + * 03 03 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Remove compiling warning for some emulation flags + * + * 03 03 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * move the AIS specific variable for security to AIS specific structure. + * + * 03 03 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * Fixed the pre-authentication timer not correctly init issue, and modify the security related callback function prototype. + * + * 03 01 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * To store field AMPDU Parameters in STA_REC + * + * 02 26 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Added fgIsWmmSupported in STA_RECORD_T. + * + * 02 26 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Added fgIsUapsdSupported in STA_RECORD_T + * + * 02 13 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Added arTspecTable in STA_REC for TSPEC management + * + * 02 12 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Enable mgmt buffer debug by default + * + * 02 12 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Added BUFFER_SOURCE_BCN + * + * 02 10 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Renamed MSDU_INFO.ucFixedRateIndex as MSDU_INFO.ucFixedRateCode + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * 02 02 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Added SN info in MSDU_INFO_T + * + * 01 27 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * add and fixed some security function. + * + * 01 11 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add Deauth and Disassoc Handler + * + * 01 08 2010 cp.wu + * [BORA00000368]Integrate HIF part into BORA + * 1) separate wifi_var_emu.c/.h from wifi_var.c/.h + * 2) eliminate HIF_EMULATION code sections appeared in wifi_var/cnm_mem + * 3) use cnmMemAlloc() instead to allocate SRAM buffer + * + * 12 31 2009 cp.wu + * [BORA00000368]Integrate HIF part into BORA + * 1) surpress debug message emitted from hal_hif.c + * 2) add two set of field for recording buffer process time + * + * 12 31 2009 cp.wu + * [BORA00000368]Integrate HIF part into BORA + * 1. move wifi task initialization from wifi_task.c(rom) to wifi_init.c (TCM) for integrating F/W download later + * * * * * 2. WIFI_Event_Dispatcher() prototype changed to return to suspend mode from normal operation mode + * * * * * 2. HIF emulation logic revised + * + * 12 29 2009 yuche.tsai + * [BORA00000343][MT6620] Emulation For TX + * .Using global buffer declaring by SD1 instead of using another one. + * + * 12 25 2009 tehuang.liu + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Integrated modifications for 1st connection (mainly on FW modules MQM, TXM, and RXM) + * * MQM: BA handling + * * TXM: Macros updates + * * RXM: Macros/Duplicate Removal updates + * + * 12 24 2009 yarco.yang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * 12 23 2009 cp.wu + * [BORA00000368]Integrate HIF part into BORA + * allocating SRAM for emulation purpose by ruducing MEM_BANK3_BUF_SZ + * + * 12 21 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Remove individual DATA_BUF_BLOCK_NUM definition for emulation compiling flagsu1rwduu`wvpghlqg|fh+fmdkb + * + * 12 21 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support several data buffer banks. + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * .For new FPGA memory size + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * 12 17 2009 george.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Dec 17 2009 MTK02468 + * [BORA00000337] To check in codes for FPGA emulation + * Modified the DATA_BLOCK_SIZE from 1620 to 2048 + * + * Dec 16 2009 mtk01426 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add CFG_TEST_SEC_EMULATION flag + * + * Dec 9 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add HT cap to sta record + * + * Dec 9 2009 mtk02752 + * [BORA00000368] Integrate HIF part into BORA + * add cnmDataPktFree() for emulation loopback purpose + * + * Dec 8 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * add the buffer for key handshake 1x and cmd key order issue + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * move the tx call back function proto type to typedef.h + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add cnmGetStaRecByAddress() and modify variable in STA_RECORD_T + * + * Dec 1 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * rename the port block flag + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add variables to STA_RECORD_T for assoc/auth + * + * Nov 23 2009 mtk02468 + * [BORA00000337] To check in codes for FPGA emulation + * Fixed the value of STA_WAIT_QUEUE_NUM (from 7 to 5) + * + * Nov 20 2009 mtk02468 + * [BORA00000337] To check in codes for FPGA emulation + * Removed u2FrameLength from SW_RFB + * + * Nov 20 2009 mtk02468 + * [BORA00000337] To check in codes for FPGA emulation + * Fixed indenting + * + * Nov 20 2009 mtk02468 + * [BORA00000337] To check in codes for FPGA emulation + * Updated MSDU_INFO and SW_RFB + * + * Nov 19 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * update the variable for security + * + * Nov 18 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * remove the variable to make the compiler ok + * + * Nov 18 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * add the variable for security module + * + * Nov 16 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix typo in define of MSG_BUF_BLOCK_SIZE + * + * Nov 13 2009 mtk02468 + * [BORA00000337] To check in codes for FPGA emulation + * Let typedef STA_REC_T precede typedef MSDU_INFO_T and SW_RFB_T + * + * Nov 13 2009 mtk02468 + * [BORA00000337] To check in codes for FPGA emulation + * Modified MSDU_INFO and STA_REC for TXM and MQM + * + * Nov 12 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Rename STA_REC_T to STA_RECORD_T and add ucIndex member + * + * Nov 9 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Make sure ucBufferSource the same offset in MSDU_INFO and SW_RFB + * + * Nov 6 2009 mtk01426 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * + * Nov 5 2009 mtk01426 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * + * Nov 5 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Update comment + * + * Oct 30 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add draft content of MSDU_INFO_T and SW_RFB_T + * + * Oct 30 2009 mtk01084 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * + * Oct 28 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * + * Oct 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix lint warning + * + * Oct 21 2009 mtk01426 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add CFG_TEST_RX_EMULATION flag + * + * Oct 20 2009 mtk01426 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * + * Oct 9 2009 mtk02468 + * [BORA00000337] To check in codes for FPGA emulation + * Added field ucTC to MSDU_INFO_T and field pucHifRxPacket to SW_RFB_T + * + * Oct 8 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +** +*/ + +#ifndef _CNM_MEM_H +#define _CNM_MEM_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#ifndef POWER_OF_2 +#define POWER_OF_2(n) BIT(n) +#endif + +/* Size of a basic management buffer block in power of 2 */ +#define MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2 7 /* 7 to the power of 2 = 128 */ +#define MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2 5 /* 5 to the power of 2 = 32 */ + +/* Size of a basic management buffer block */ +#define MGT_BUF_BLOCK_SIZE POWER_OF_2(MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2) +#define MSG_BUF_BLOCK_SIZE POWER_OF_2(MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2) + +/* Total size of (n) basic management buffer blocks */ +#define MGT_BUF_BLOCKS_SIZE(n) ((UINT_32)(n) << MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2) +#define MSG_BUF_BLOCKS_SIZE(n) ((UINT_32)(n) << MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2) + +/* Number of management buffer block */ +#define MAX_NUM_OF_BUF_BLOCKS 32 /* Range: 1~32 */ + +/* Size of overall management frame buffer */ +#define MGT_BUFFER_SIZE (MAX_NUM_OF_BUF_BLOCKS * MGT_BUF_BLOCK_SIZE) +#define MSG_BUFFER_SIZE (MAX_NUM_OF_BUF_BLOCKS * MSG_BUF_BLOCK_SIZE) + + +/* STA_REC related definitions */ +#define STA_REC_INDEX_BMCAST 0xFF +#define STA_REC_INDEX_NOT_FOUND 0xFE +#define STA_WAIT_QUEUE_NUM 5 /* Number of SW queues in each STA_REC: AC0~AC4 */ +#define SC_CACHE_INDEX_NUM 5 /* Number of SC caches in each STA_REC: AC0~AC4 */ + + +/* P2P related definitions */ +#ifdef CFG_ENABLE_WIFI_DIRECT +/* Moved from p2p_fsm.h */ +#define WPS_ATTRI_MAX_LEN_DEVICE_NAME 32 /* 0x1011 */ +#define P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT 8 /* NOTE(Kevin): Shall <= 16 */ +#endif + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +#if ((MAX_NUM_OF_BUF_BLOCKS > 32) || (MAX_NUM_OF_BUF_BLOCKS <= 0)) + #error > #define MAX_NUM_OF_MGT_BUF_BLOCKS : Out of boundary ! +#elif MAX_NUM_OF_BUF_BLOCKS > 16 + typedef UINT_32 BUF_BITMAP; +#elif MAX_NUM_OF_BUF_BLOCKS > 8 + typedef UINT_16 BUF_BITMAP; +#else + typedef UINT_8 BUF_BITMAP; +#endif /* MAX_NUM_OF_MGT_BUF_BLOCKS */ + + +/* Control variable of TX management memory pool */ +typedef struct _BUF_INFO_T { + PUINT_8 pucBuf; + +#if CFG_DBG_MGT_BUF + UINT_32 u4AllocCount; + UINT_32 u4FreeCount; + UINT_32 u4AllocNullCount; +#endif /* CFG_DBG_MGT_BUF */ + + BUF_BITMAP rFreeBlocksBitmap; + UINT_8 aucAllocatedBlockNum[MAX_NUM_OF_BUF_BLOCKS]; +} BUF_INFO_T, *P_BUF_INFO_T; + + +/* Wi-Fi divides RAM into three types + * MSG: Mailbox message (Small size) + * BUF: HW DMA buffers (HIF/MAC) + */ +typedef enum _ENUM_RAM_TYPE_T { + RAM_TYPE_MSG = 0, + RAM_TYPE_BUF +} ENUM_RAM_TYPE_T, P_ENUM_RAM_TYPE_T; + +typedef enum _ENUM_BUFFER_SOURCE_T { + BUFFER_SOURCE_HIF_TX0 =0, + BUFFER_SOURCE_HIF_TX1, + BUFFER_SOURCE_MAC_RX, + BUFFER_SOURCE_MNG, + BUFFER_SOURCE_BCN, + BUFFER_SOURCE_NUM +} ENUM_BUFFER_SOURCE_T, *P_ENUM_BUFFER_SOURCE_T; + + +typedef enum _ENUM_SEC_STATE_T { + SEC_STATE_INIT, + SEC_STATE_INITIATOR_PORT_BLOCKED, + SEC_STATE_RESPONDER_PORT_BLOCKED, + SEC_STATE_CHECK_OK, + SEC_STATE_SEND_EAPOL, + SEC_STATE_SEND_DEAUTH, + SEC_STATE_COUNTERMEASURE, + SEC_STATE_NUM +} ENUM_SEC_STATE_T; + +typedef struct _TSPEC_ENTRY_T { + UINT_8 ucStatus; + UINT_8 ucToken; /* Dialog Token in ADDTS_REQ or ADDTS_RSP */ + UINT_16 u2MediumTime; + UINT_32 u4TsInfo; + //PARAM_QOS_TS_INFO rParamTsInfo; + /* Add other retained QoS parameters below */ +} TSPEC_ENTRY_T, *P_TSPEC_ENTRY_T, TSPEC_TABLE_ENTRY_T, *P_TSPEC_TABLE_ENTRY_T; + +typedef struct _SEC_INFO_T { + + ENUM_SEC_STATE_T ePreviousState; + ENUM_SEC_STATE_T eCurrentState; + + BOOL fg2nd1xSend; + BOOL fgKeyStored; + + UINT_8 aucStoredKey[64]; + + BOOL fgAllowOnly1x; +} SEC_INFO_T, *P_SEC_INFO_T; + +#define MAX_NUM_CONCURRENT_FRAGMENTED_MSDUS 3 + +#define UPDATE_BSS_RSSI_INTERVAL_SEC 3 // Seconds + +/* Fragment information structure */ +typedef struct _FRAG_INFO_T { + UINT_16 u2NextFragSeqCtrl; + PUINT_8 pucNextFragStart; + P_SW_RFB_T pr1stFrag; + OS_SYSTIME rReceiveLifetimeLimit; /* The receive time of 1st fragment */ +} FRAG_INFO_T, *P_FRAG_INFO_T; + + +/* Define STA record structure */ +struct _STA_RECORD_T { + LINK_ENTRY_T rLinkEntry; + UINT_8 ucIndex; /* Not modify it except initializing */ + + BOOLEAN fgIsInUse; /* Indicate if this entry is in use or not */ + UINT_8 aucMacAddr[MAC_ADDR_LEN]; /* MAC address */ + + /* SAA/AAA */ + ENUM_AA_STATE_T eAuthAssocState; /* Store STATE Value used in SAA/AAA */ + UINT_8 ucAuthAssocReqSeqNum; + + ENUM_STA_TYPE_T eStaType; /* Indicate the role of this STA in + * the network (for example, P2P GO) + */ + + UINT_8 ucNetTypeIndex; /* ENUM_NETWORK_TYPE_INDEX_T */ + + UINT_8 ucStaState; /* STATE_1,2,3 */ + + UINT_8 ucPhyTypeSet; /* Available PHY Type Set of this peer + * (may deduced from received BSS_DESC_T) + */ + UINT_8 ucDesiredPhyTypeSet; /* The match result by AND operation of peer's + * PhyTypeSet and ours. + */ + BOOLEAN fgHasBasicPhyType; /* A flag to indicate a Basic Phy Type which + * is used to generate some Phy Attribute IE + * (e.g. capability, MIB) during association. + */ + UINT_8 ucNonHTBasicPhyType; /* The Basic Phy Type choosen among the + * ucDesiredPhyTypeSet. + */ + + UINT_16 u2CapInfo; /* For Infra Mode, to store Capability Info. from Association Resp(SAA). + * For AP Mode, to store Capability Info. from Association Req(AAA). + */ + UINT_16 u2AssocId; /* For Infra Mode, to store AID from Association Resp(SAA). + * For AP Mode, to store the Assigned AID(AAA). + */ + + UINT_16 u2ListenInterval; /* Listen Interval from STA(AAA) */ + + UINT_16 u2DesiredNonHTRateSet; /* Our Current Desired Rate Set after + * match with STA's Operational Rate Set + */ + + UINT_16 u2OperationalRateSet; /* Operational Rate Set of peer BSS */ + UINT_16 u2BSSBasicRateSet; /* Basic Rate Set of peer BSS */ + + BOOLEAN fgIsMerging; /* For IBSS Mode, to indicate that Merge is ongoing */ + + BOOLEAN fgDiagnoseConnection; /* For Infra/AP Mode, to diagnose the Connection with + * this peer by sending ProbeReq/Null frame */ + + /*------------------------------------------------------------------------------------------*/ + /* 802.11n HT capabilities when (prStaRec->ucPhyTypeSet & PHY_TYPE_BIT_HT) is true */ + /* They have the same definition with fields of information element */ + /*------------------------------------------------------------------------------------------*/ + UINT_8 ucMcsSet; /* MCS0~7 rate set of peer BSS */ + BOOLEAN fgSupMcs32; /* MCS32 is supported by peer BSS */ + UINT_16 u2HtCapInfo; /* HT cap info field by HT cap IE */ + UINT_8 ucAmpduParam; /* Field A-MPDU Parameters in HT cap IE */ + UINT_16 u2HtExtendedCap; /* HT extended cap field by HT cap IE */ + UINT_32 u4TxBeamformingCap; /* TX beamforming cap field by HT cap IE */ + UINT_8 ucAselCap; /* ASEL cap field by HT cap IE */ + + UINT_8 ucRCPI; /* RCPI of peer */ + + UINT_8 ucDTIMPeriod; /* Target BSS's DTIM Period, we use this + * value for setup Listen Interval + * TODO(Kevin): TBD + */ + UINT_8 ucAuthAlgNum; /* For Infra/AP Mode, the Auth Alogrithm Num used in Authentication(SAA/AAA) */ + BOOLEAN fgIsReAssoc; /* For Infra/AP Mode, to indicate ReAssoc Frame was in used(SAA/AAA) */ + + UINT_8 ucTxAuthAssocRetryCount;/* For Infra Mode, the Retry Count of TX Auth/Assod Frame(SAA) */ + UINT_8 ucTxAuthAssocRetryLimit;/* For Infra Mode, the Retry Limit of TX Auth/Assod Frame(SAA) */ + + UINT_16 u2StatusCode; /* Status of Auth/Assoc Req */ + UINT_16 u2ReasonCode; /* Reason that been Deauth/Disassoc */ + + + P_IE_CHALLENGE_TEXT_T prChallengeText; /* Point to an allocated buffer for storing Challenge Text for Shared Key Authentication */ + + TIMER_T rTxReqDoneOrRxRespTimer;/* For Infra Mode, a timer used to send a timeout event + * while waiting for TX request done or RX response. + */ + + /*------------------------------------------------------------------------------------------*/ + /* Power Management related fields (for STA/ AP/ P2P/ BOW power saving mode) */ + /*------------------------------------------------------------------------------------------*/ + BOOLEAN fgSetPwrMgtBit; /* For Infra Mode, to indicate that outgoing frame need toggle + * the Pwr Mgt Bit in its Frame Control Field. + */ + + BOOLEAN fgIsInPS; /* For AP Mode, to indicate the client PS state(PM). + * TRUE: In PS Mode; FALSE: In Active Mode. */ + + BOOLEAN fgIsInPsPollSP; /* For Infra Mode, to indicate we've sent a PS POLL to AP and start + * the PS_POLL Service Period(LP) + */ + + BOOLEAN fgIsInTriggerSP; /* For Infra Mode, to indicate we've sent a Trigger Frame to AP and start + * the Delivery Service Period(LP) + */ + + UINT_8 ucBmpDeliveryAC; /* 0: AC0, 1: AC1, 2: AC2, 3: AC3 */ + + UINT_8 ucBmpTriggerAC; /* 0: AC0, 1: AC1, 2: AC2, 3: AC3 */ + + UINT_8 ucUapsdSp; /* Max SP length */ + + /*------------------------------------------------------------------------------------------*/ + + BOOLEAN fgIsRtsEnabled; + + OS_SYSTIME rUpdateTime; /* (4) System Timestamp of Successful TX and RX */ + + OS_SYSTIME rLastJoinTime; /* (4) System Timestamp of latest JOIN process */ + + UINT_8 ucJoinFailureCount; /* Retry Count of JOIN process */ + + LINK_T arStaWaitQueue[STA_WAIT_QUEUE_NUM]; /* For TXM to defer pkt forwarding to MAC TX DMA */ + + UINT_16 au2CachedSeqCtrl[TID_NUM + 1]; /* Duplicate removal for HT STA on a per-TID basis ("+1" is for MMPDU and non-QoS) */ + +#if 0 + /* RXM */ + P_RX_BA_ENTRY_T aprRxBaTable[TID_NUM]; + + /* TXM */ + P_TX_BA_ENTRY_T aprTxBaTable[TID_NUM]; +#endif + + FRAG_INFO_T rFragInfo[MAX_NUM_CONCURRENT_FRAGMENTED_MSDUS]; + + SEC_INFO_T rSecInfo; /* The security state machine */ + + BOOLEAN fgPortBlock; /* The 802.1x Port Control flag */ + + BOOLEAN fgTransmitKeyExist; /* Unicast key exist for this STA */ + + UINT_8 ucWTEntry; + + BOOLEAN fgTxAmpduEn; /* Enable TX AMPDU for this Peer */ + BOOLEAN fgRxAmpduEn; /* Enable RX AMPDU for this Peer */ + + PUINT_8 pucAssocReqIe; + UINT_16 u2AssocReqIeLen; + /*------------------------------------------------------------------------------------------*/ + /* WMM/QoS related fields */ + /*------------------------------------------------------------------------------------------*/ + BOOLEAN fgIsQoS; /* If the STA is associated as a QSTA or QAP (for TX/RX) */ + BOOLEAN fgIsWmmSupported; /* If the peer supports WMM, set to TRUE (for association)*/ + BOOLEAN fgIsUapsdSupported; /* Set according to the scan result (for association) */ + + /*------------------------------------------------------------------------------------------*/ + /* P2P related fields */ + /*------------------------------------------------------------------------------------------*/ +#if CFG_ENABLE_WIFI_DIRECT + UINT_8 u2DevNameLen; + UINT_8 aucDevName[WPS_ATTRI_MAX_LEN_DEVICE_NAME]; + + UINT_8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ + + UINT_16 u2ConfigMethods; + + UINT_8 ucDeviceCap; + + UINT_8 ucSecondaryDevTypeCount; + + DEVICE_TYPE_T rPrimaryDevTypeBE; + + DEVICE_TYPE_T arSecondaryDevTypeBE[P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT]; +#endif /* CFG_SUPPORT_P2P */ + + + /*------------------------------------------------------------------------------------------*/ + /* QM related fields */ + /*------------------------------------------------------------------------------------------*/ + + UINT_8 ucFreeQuota; /* Per Sta flow controal. Valid when fgIsInPS is TRUE. Chnage it for per Queue flow control */ + //UINT_8 aucFreeQuotaPerQueue[NUM_OF_PER_STA_TX_QUEUES]; /* used in future */ + UINT_8 ucFreeQuotaForDelivery; + UINT_8 ucFreeQuotaForNonDelivery; + +#if 1 + /*------------------------------------------------------------------------------------------*/ + /* To be removed, this is to make que_mgt compilation success only */ + /*------------------------------------------------------------------------------------------*/ + /* When this STA_REC is in use, set to TRUE. */ + BOOLEAN fgIsValid; + + /* Per-STA Queues: [0] AC0, [1] AC1, [2] AC2, [3] AC3, [4] 802.1x */ + QUE_T arTxQueue[NUM_OF_PER_STA_TX_QUEUES]; + + /* When this STA is in PS Mode, set to TRUE. */ + //BOOLEAN fgIsPS; + + /* When this STA enters Power-Saving, FW will notify the driver with a Session ID */ + UINT_8 ucPsSessionID; + + BOOLEAN fgIsAp; + + /* Reorder Parameter reference table */ + P_RX_BA_ENTRY_T aprRxReorderParamRefTbl[CFG_RX_MAX_BA_TID_NUM]; +#endif +}; + +#if 0 +/* use nic_tx.h instead */ +/* MSDU_INFO and SW_RFB structure */ +typedef struct _MSDU_INFO_T { + + //4 /* ----------------MSDU_INFO and SW_RFB Common Fields------------------ */ + + LINK_ENTRY_T rLinkEntry; + PUINT_8 pucBuffer; /* Pointer to the associated buffer */ + + UINT_8 ucBufferSource; /* HIF TX0, HIF TX1, MAC RX, or MNG Pool */ + UINT_8 ucNetworkTypeIndex; /* Network type index that this TX packet is assocaited with */ + UINT_8 ucTC; /* 0 to 5 (used by HIF TX to increment the corresponding TC counter) */ + UINT_8 ucTID; /* Traffic Identification */ + + BOOLEAN fgIs802_11Frame; /* Set to TRUE for 802.11 frame */ + UINT_8 ucMacHeaderLength; + UINT_16 u2PayloadLength; + PUINT_8 pucMacHeader; /* 802.11 header */ + PUINT_8 pucPayload; /* 802.11 payload */ + + OS_SYSTIME rArrivalTime; /* System Timestamp (4) */ + P_STA_RECORD_T prStaRec; + +#if CFG_PROFILE_BUFFER_TRACING + ENUM_BUFFER_ACTIVITY_TYPE_T eActivity[2]; + UINT_32 rActivityTime[2]; +#endif +#if DBG && CFG_BUFFER_FREE_CHK + BOOLEAN fgBufferInSource; +#endif + + UINT_8 ucControlFlag; /* For specify some Control Flags, e.g. Basic Rate */ + + //4 /* -----------------------Non-Common ------------------------- */ + /* TODO: move flags to ucControlFlag */ + + BOOLEAN fgIs1xFrame; /* Set to TRUE for 802.1x frame */ + + /* TXM: For TX Done handling, callback function & parameter (5) */ + BOOLEAN fgIsTxFailed; /* Set to TRUE if transmission failure */ + + PFN_TX_DONE_HANDLER pfTxDoneHandler; + + UINT_64 u8TimeStamp; /* record the TX timestamp */ + + /* TXM: For PS forwarding control (per-STA flow control) */ + UINT_8 ucPsForwardingType; /* Delivery-enabled, non-delivery-enabled, non-PS */ + UINT_8 ucPsSessionID; /* The Power Save session id for PS forwarding control*/ + + /* TXM: For MAC TX DMA operations */ + UINT_8 ucMacTxQueIdx; /* MAC TX queue: AC0-AC6, BCM, or BCN */ + BOOLEAN fgNoAck; /* Set to true if Ack is not requred for this packet */ + BOOLEAN fgBIP; /* Set to true if BIP is used for this packet */ + UINT_8 ucFragTotalCount; + UINT_8 ucFragFinishedCount; + UINT_16 u2FragThreshold; /* Fragmentation threshold without WLAN Header & FCS */ + BOOLEAN fgFixedRate; /* If a fixed rate is used, set to TRUE. */ + UINT_8 ucFixedRateCode; /* The rate code copied to MAC TX Desc */ + UINT_8 ucFixedRateRetryLimit; /* The retry limit when a fixed rate is used */ + BOOLEAN fgIsBmcQueueEnd; /* Set to true if this packet is the end of BMC */ + + /* TXM: For flushing ACL frames */ + UINT_16 u2PalLLH; /* 802.11 PAL LLH */ + //UINT_16 u2LLH; + UINT_16 u2ACLSeq; /* u2LLH+u2ACLSeq for AM HCI flush ACL frame */ + + /* TXM for retransmitting a flushed packet */ + BOOLEAN fgIsSnAssigned; + UINT_16 u2SequenceNumber; /* To remember the Sequence Control field of this MPDU */ + +} MSDU_INFO_T, *P_MSDU_INFO_T; +#endif + +#if 0 +/* nic_rx.h */ +typedef struct _SW_RFB_T { + + //4 /* ----------------MSDU_INFO and SW_RFB Common Fields------------------ */ + + LINK_ENTRY_T rLinkEntry; + PUINT_8 pucBuffer; /* Pointer to the associated buffer */ + + UINT_8 ucBufferSource; /* HIF TX0, HIF TX1, MAC RX, or MNG Pool */ + UINT_8 ucNetworkTypeIndex; /* Network type index that this TX packet is assocaited with */ + UINT_8 ucTC; /* 0 to 5 (used by HIF TX to increment the corresponding TC counter) */ + UINT_8 ucTID; /* Traffic Identification */ + + BOOLEAN fgIs802_11Frame; /* Set to TRUE for 802.11 frame */ + UINT_8 ucMacHeaderLength; + UINT_16 u2PayloadLength; + PUINT_8 pucMacHeader; /* 802.11 header */ + PUINT_8 pucPayload; /* 802.11 payload */ + + OS_SYSTIME rArrivalTime; /* System Timestamp (4) */ + P_STA_RECORD_T prStaRec; + +#if CFG_PROFILE_BUFFER_TRACING + ENUM_BUFFER_ACTIVITY_TYPE_T eActivity[2]; + UINT_32 rActivityTime[2]; +#endif +#if DBG && CFG_BUFFER_FREE_CHK + BOOLEAN fgBufferInSource; +#endif + + UINT_8 ucControlFlag; /* For specify some Control Flags, e.g. Basic Rate */ + + //4 /* -----------------------Non-Common ------------------------- */ + + /* For composing the HIF RX Header (TODO: move flags to ucControlFlag) */ + PUINT_8 pucHifRxPacket; /* Pointer to the Response packet to HIF RX0 or RX1 */ + UINT_16 u2HifRxPacketLength; + UINT_8 ucHeaderOffset; + UINT_8 ucHifRxPortIndex; + + UINT_16 u2SequenceControl; + BOOLEAN fgIsA4Frame; /* (For MAC RX packet parsing) set to TRUE if 4 addresses are present */ + BOOLEAN fgIsBAR; + BOOLEAN fgIsQoSData; + BOOLEAN fgIsAmsduSubframe; /* Set to TRUE for A-MSDU Subframe */ + + /* For HIF RX DMA Desc */ + BOOLEAN fgTUChecksumCheckRequired; + BOOLEAN fgIPChecksumCheckRequired; + UINT_8 ucEtherTypeOffset; + +} SW_RFB_T, *P_SW_RFB_T; +#endif + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +P_MSDU_INFO_T +cnmMgtPktAlloc ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Length + ); + +VOID +cnmMgtPktFree ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + +VOID +cnmMemInit ( + IN P_ADAPTER_T prAdapter + ); + +PVOID +cnmMemAlloc ( + IN P_ADAPTER_T prAdapter, + IN ENUM_RAM_TYPE_T eRamType, + IN UINT_32 u4Length + ); + +VOID +cnmMemFree ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvMemory + ); + +VOID +cnmStaRecInit ( + IN P_ADAPTER_T prAdapter + ); + +VOID +cnmStaRecUninit ( + IN P_ADAPTER_T prAdapter + ); + +P_STA_RECORD_T +cnmStaRecAlloc ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucNetTypeIndex + ); + +VOID +cnmStaRecFree ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN BOOLEAN fgSyncToChip + ); + +VOID +cnmStaFreeAllStaByNetType ( + P_ADAPTER_T prAdapter, + ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + BOOLEAN fgSyncToChip + ); + +P_STA_RECORD_T +cnmGetStaRecByIndex ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucIndex + ); + +P_STA_RECORD_T +cnmGetStaRecByAddress ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucNetTypeIndex, + IN UINT_8 aucPeerMACAddress[] + ); + +VOID +cnmStaRecResetStatus ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex + ); + +VOID +cnmStaRecChangeState ( + IN P_ADAPTER_T prAdapter, + IN OUT P_STA_RECORD_T prStaRec, + IN UINT_8 ucNewState + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#ifndef _lint +/* Kevin: we don't have to call following function to inspect the data structure. + * It will check automatically while at compile time. + * We'll need this for porting driver to different RTOS. + */ +__KAL_INLINE__ VOID +cnmMemDataTypeCheck ( + VOID + ) +{ +#if 0 + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSDU_INFO_T,rLinkEntry) == 0); + + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSDU_INFO_T,rLinkEntry) == OFFSET_OF(SW_RFB_T,rLinkEntry)); + + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSDU_INFO_T,pucBuffer) == OFFSET_OF(SW_RFB_T,pucBuffer)); + + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSDU_INFO_T,ucBufferSource) == + OFFSET_OF(SW_RFB_T,ucBufferSource)); + + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSDU_INFO_T,pucMacHeader) == + OFFSET_OF(SW_RFB_T,pucMacHeader)); + + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSDU_INFO_T,ucMacHeaderLength) == + OFFSET_OF(SW_RFB_T,ucMacHeaderLength)); + + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSDU_INFO_T,pucPayload) == + OFFSET_OF(SW_RFB_T,pucPayload)); + + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSDU_INFO_T,u2PayloadLength) == + OFFSET_OF(SW_RFB_T,u2PayloadLength)); + + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSDU_INFO_T,prStaRec) == + OFFSET_OF(SW_RFB_T,prStaRec)); + + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSDU_INFO_T,ucNetworkTypeIndex) == + OFFSET_OF(SW_RFB_T,ucNetworkTypeIndex)); + + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSDU_INFO_T,ucTID) == + OFFSET_OF(SW_RFB_T,ucTID)); + + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSDU_INFO_T,fgIs802_11Frame) == + OFFSET_OF(SW_RFB_T,fgIs802_11Frame)); + + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSDU_INFO_T,ucControlFlag) == + OFFSET_OF(SW_RFB_T,ucControlFlag)); + + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSDU_INFO_T,rArrivalTime) == + OFFSET_OF(SW_RFB_T,rArrivalTime)); + + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSDU_INFO_T,ucTC) == + OFFSET_OF(SW_RFB_T,ucTC)); + +#if CFG_PROFILE_BUFFER_TRACING + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSDU_INFO_T,eActivity[0]) == + OFFSET_OF(SW_RFB_T,eActivity[0])); + + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSDU_INFO_T,rActivityTime[0]) == + OFFSET_OF(SW_RFB_T,rActivityTime[0])); +#endif + +#if DBG && CFG_BUFFER_FREE_CHK + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(MSDU_INFO_T,fgBufferInSource) == + OFFSET_OF(SW_RFB_T,fgBufferInSource)); +#endif + + + DATA_STRUC_INSPECTING_ASSERT( + OFFSET_OF(STA_RECORD_T,rLinkEntry) == 0); + + return; +#endif +} +#endif /* _lint */ + +#endif /* _CNM_MEM_H */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/cnm_scan.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/cnm_scan.h new file mode 100755 index 000000000000..a66376cc22bf --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/cnm_scan.h @@ -0,0 +1,250 @@ +/* +** $Id: @(#) +*/ + +/*! \file "cnm_scan.h" + \brief + +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: cnm_scan.h $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 05 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * remove unused definitions. + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implementation of DRV-SCN and related mailbox message handling. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge cnm_scan.h and hem_mbox.h + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 03 30 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support 2.4G OBSS scan + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 03 10 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * + * * * * Add Channel Manager for arbitration of JOIN and SCAN Req + * + * 02 23 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add support scan channel 1~14 and update scan result's frequency infou1rwduu`wvpghlqg|n`slk+mpdkb + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * Nov 18 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add function prototype of cnmScanInit() + * + * Nov 5 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +** +*/ + +#ifndef _CNM_SCAN_H +#define _CNM_SCAN_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define SCN_CHANNEL_DWELL_TIME_MIN_MSEC 12 +#define SCN_CHANNEL_DWELL_TIME_EXT_MSEC 98 + +#define SCN_TOTAL_PROBEREQ_NUM_FOR_FULL 3 +#define SCN_SPECIFIC_PROBEREQ_NUM_FOR_FULL 1 + +#define SCN_TOTAL_PROBEREQ_NUM_FOR_PARTIAL 2 +#define SCN_SPECIFIC_PROBEREQ_NUM_FOR_PARTIAL 1 + + +#define SCN_INTERLACED_CHANNEL_GROUPS_NUM 3 /* Used by partial scan */ + +#define SCN_PARTIAL_SCAN_NUM 3 + +#define SCN_PARTIAL_SCAN_IDLE_MSEC 100 + +#define MAXIMUM_OPERATION_CHANNEL_LIST 32 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* The type of Scan Source */ +typedef enum _ENUM_SCN_REQ_SOURCE_T { + SCN_REQ_SOURCE_HEM = 0, + SCN_REQ_SOURCE_NET_FSM, + SCN_REQ_SOURCE_ROAMING, /* ROAMING Module is independent of AIS FSM */ + SCN_REQ_SOURCE_OBSS, /* 2.4G OBSS scan */ + SCN_REQ_SOURCE_NUM +} ENUM_SCN_REQ_SOURCE_T, *P_ENUM_SCN_REQ_SOURCE_T; + +typedef enum _ENUM_SCAN_PROFILE_T { + SCAN_PROFILE_FULL = 0, + SCAN_PROFILE_PARTIAL, + SCAN_PROFILE_VOIP, + SCAN_PROFILE_FULL_2G4, + SCAN_PROFILE_NUM +} ENUM_SCAN_PROFILE_T, *P_ENUM_SCAN_PROFILE_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#if 0 +VOID +cnmScanInit ( + VOID + ); + +VOID +cnmScanRunEventScanRequest ( + IN P_MSG_HDR_T prMsgHdr + ); + +BOOLEAN +cnmScanRunEventScanAbort ( + IN P_MSG_HDR_T prMsgHdr + ); + +VOID +cnmScanProfileSelection ( + VOID + ); + +VOID +cnmScanProcessStart ( + VOID + ); + +VOID +cnmScanProcessStop ( + VOID + ); + +VOID +cnmScanRunEventReqAISAbsDone ( + IN P_MSG_HDR_T prMsgHdr + ); + +VOID +cnmScanRunEventCancelAISAbsDone ( + IN P_MSG_HDR_T prMsgHdr + ); + +VOID +cnmScanPartialScanTimeout ( + UINT_32 u4Param + ); + +VOID +cnmScanRunEventScnFsmComplete ( + IN P_MSG_HDR_T prMsgHdr + ); +#endif + + + +#endif /* _CNM_SCAN_H */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/cnm_timer.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/cnm_timer.h new file mode 100755 index 000000000000..58a897aaaba6 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/cnm_timer.h @@ -0,0 +1,318 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/mgmt/cnm_timer.h#1 $ +*/ + +/*! \file cnm_timer.h + \brief Declaration of timer obj and related timer macro for setup time out + event. + + In this file we declare the timer object and provide several macro for + Protocol functional blocks to setup their own time out event. +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: cnm_timer.h $ + * + * 12 13 2011 cm.chang + * [WCXRP00001136] [All Wi-Fi][Driver] Add wake lock for pending timer + * Add wake lock if timer timeout value is smaller than 5 seconds + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * cnm_timer has been migrated. + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add hem_mbox.c and cnm_mem.h (but disabled some feature) for further migration + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge cnm_scan.h and hem_mbox.h + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge wifi_var.h, precomp.h, cnm_timer.h (data type only) + * + * 06 04 2010 george.huang + * [BORA00000678][MT6620]WiFi LP integration + * [PM] Support U-APSD for STA mode + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Return timer token back to COS when entering wait off state + * + * 01 08 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support longer timeout interval to 45 days from 65secu1rwduu`wvpghlqg|fh+fmdkb + * + * 01 06 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Fix system time is 32KHz instead of 1ms + * + * Nov 23 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * add the copy time function + * + * Nov 5 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix LINT warnning + * + * Oct 28 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +** +*/ + +#ifndef _CNM_TIMER_H +#define _CNM_TIMER_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#undef MSEC_PER_SEC +#define MSEC_PER_SEC 1000 +#undef USEC_PER_MSEC +#define USEC_PER_MSEC 1000 +#define USEC_PER_TU 1024 /* microsecond */ + +#define MSEC_PER_MIN (60 * MSEC_PER_SEC) + + +#define MGMT_MAX_TIMEOUT_INTERVAL ((UINT_32)0x7fffffff) + +#define WAKE_LOCK_MAX_TIME 5 /* Unit: sec */ + +/* If WAKE_LOCK_MAX_TIME is too large, the whole system may always keep awake + * because of periodic timer of OBSS scanning + */ +#if (WAKE_LOCK_MAX_TIME >= OBSS_SCAN_MIN_INTERVAL) + #error WAKE_LOCK_MAX_TIME is too large +#endif + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef VOID (*PFN_MGMT_TIMEOUT_FUNC)(P_ADAPTER_T, UINT_32); + +typedef struct _TIMER_T { + LINK_ENTRY_T rLinkEntry; + OS_SYSTIME rExpiredSysTime; + UINT_16 u2Minutes; + UINT_16 u2Reserved; + UINT_32 u4Data; + PFN_MGMT_TIMEOUT_FUNC pfMgmtTimeOutFunc; +} TIMER_T, *P_TIMER_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +/* Check if time "a" is before time "b" */ +/* In 32-bit variable, 0x00000001~0x7fffffff -> positive number, + * 0x80000000~0xffffffff -> negative number + */ +#define TIME_BEFORE_64bit(a,b) (a < b) + +#define TIME_BEFORE(a,b) ((UINT_32)((UINT_32)(a) - (UINT_32)(b)) > 0x7fffffff) + +/* #define TIME_BEFORE(a,b) ((INT_32)((INT_32)(b) - (INT_32)(a)) > 0) + * may cause UNexpect result between Free build and Check build for WinCE + */ + +#define TIME_AFTER(a,b) TIME_BEFORE(b,a) + +#define SYSTIME_TO_SEC(_systime) ((_systime) / KAL_HZ) +#define SEC_TO_SYSTIME(_sec) ((_sec) * KAL_HZ) + + +/* The macros to convert second & millisecond */ +#define MSEC_TO_SEC(_msec) ((_msec) / MSEC_PER_SEC) +#define SEC_TO_MSEC(_sec) ((UINT_32)(_sec) * MSEC_PER_SEC) + + +/* The macros to convert millisecond & microsecond */ +#define USEC_TO_MSEC(_usec) ((_usec) / USEC_PER_MSEC) +#define MSEC_TO_USEC(_msec) ((UINT_32)(_msec) * USEC_PER_MSEC) + + +/* The macros to convert TU & microsecond, TU & millisecond */ +#define TU_TO_USEC(_tu) ((_tu) * USEC_PER_TU) +#define TU_TO_MSEC(_tu) USEC_TO_MSEC( TU_TO_USEC(_tu) ) + + +/* The macros to convert TU & & OS system time, round up by 0.5 */ +#define TU_TO_SYSTIME(_tu) MSEC_TO_SYSTIME( TU_TO_MSEC(_tu) ) +#define SYSTIME_TO_TU(_systime) \ + ((SYSTIME_TO_USEC(_systime) + ((USEC_PER_TU / 2) - 1)) / USEC_PER_TU) + + +/* The macros to convert OS system time & microsecond */ +#define SYSTIME_TO_USEC(_systime) (SYSTIME_TO_MSEC(_systime) * USEC_PER_MSEC) + + +/* The macro to get the current OS system time */ +#define GET_CURRENT_SYSTIME(_systime_p) {*(_systime_p) = kalGetTimeTick();} + +/* The macro to copy the system time */ +#define COPY_SYSTIME(_destTime, _srcTime) (_destTime) = (_srcTime) + +/* The macro to get the system time difference between t1 and t2 (t1 - t2) */ +/* #define GET_SYSTIME_DIFFERENCE(_time1, _time2, _diffTime) \ + (_diffTime) = (_time1) - (_time2) */ + +/* The macro to check for the expiration, if TRUE means _currentTime >= _expirationTime */ +#define CHECK_FOR_EXPIRATION(_currentTime, _expirationTime) \ + ( ((UINT_32)(_currentTime) - (UINT_32)(_expirationTime)) <= 0x7fffffffUL) + +/* The macro to check for the timeout */ +#define CHECK_FOR_TIMEOUT(_currentTime, _timeoutStartingTime, _timeout) \ + CHECK_FOR_EXPIRATION((_currentTime), ((_timeoutStartingTime) + (_timeout))) + +/* The macro to set the expiration time with a specified timeout *//* Watch out for round up.*/ +#define SET_EXPIRATION_TIME(_expirationTime, _timeout) \ + { \ + GET_CURRENT_SYSTIME(&(_expirationTime)); \ + (_expirationTime) += (OS_SYSTIME)(_timeout); \ + } + +#define timerRenewTimer(adapter,tmr,interval) \ + timerStartTimer(adapter,tmr,interval,(tmr)->function,(tmr)->data) + +#define MGMT_INIT_TIMER(_adapter_p, _timer, _callbackFunc) \ + timerInitTimer(_adapter_p, &(_timer), (UINT_32)(_callbackFunc)) + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID +cnmTimerInitialize ( + IN P_ADAPTER_T prAdapter + ); + +VOID +cnmTimerDestroy ( + IN P_ADAPTER_T prAdapter + ); + +VOID +cnmTimerInitTimer ( + IN P_ADAPTER_T prAdapter, + IN P_TIMER_T prTimer, + IN PFN_MGMT_TIMEOUT_FUNC pfFunc, + IN UINT_32 u4Data + ); + +VOID +cnmTimerStopTimer ( + IN P_ADAPTER_T prAdapter, + IN P_TIMER_T prTimer + ); + +VOID +cnmTimerStartTimer ( + IN P_ADAPTER_T prAdapter, + IN P_TIMER_T prTimer, + IN UINT_32 u4TimeoutMs + ); + +VOID +cnmTimerDoTimeOutCheck ( + IN P_ADAPTER_T prAdapter + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +__KAL_INLINE__ +INT_32 +timerPendingTimer ( + IN P_TIMER_T prTimer + ) +{ + ASSERT(prTimer); + + return prTimer->rLinkEntry.prNext != NULL; +} + +#endif /* _CNM_TIMER_H */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/hem_mbox.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/hem_mbox.h new file mode 100755 index 000000000000..c9636363385b --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/hem_mbox.h @@ -0,0 +1,486 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/mgmt/hem_mbox.h#3 $ +*/ + +/*! \file hem_mbox.h + \brief + +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: hem_mbox.h $ + * + * 01 17 2012 yuche.tsai + * NULL + * Update mgmt frame filter setting. + * Please also update FW 2.1 + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Hot Spot Tethering for ICS ALPHA testing version. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 08 10 2011 yuche.tsai + * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. + * Add infitation support. + * + * 06 23 2011 cp.wu + * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module + * follow-ups for frequency-shifted WAPI AP support + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 01 26 2011 cm.chang + * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument + * Allocate system RAM if fixed message or mgmt buffer is not available + * + * 11 08 2010 cm.chang + * [WCXRP00000169] [MT6620 Wi-Fi][Driver][FW] Remove unused CNM recover message ID + * Remove CNM channel reover message ID + * + * 09 16 2010 cm.chang + * NULL + * Remove unused message ID + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 25 2010 george.huang + * NULL + * update OID/ registry control path for PM related settings + * + * 08 23 2010 chinghwa.yu + * NULL + * Update for BOW. + * + * 08 16 2010 cp.wu + * NULL + * add interface for RLM to trigger OBSS-SCAN. + * + * 08 11 2010 yuche.tsai + * NULL + * Add some message ID for P2P FSM under provisioning phase. + * + * 08 11 2010 yuche.tsai + * NULL + * Add Message Event ID for P2P Module. + * + * 08 05 2010 yuche.tsai + * NULL + * Check-in P2P Device Discovery Feature. + * + * 08 04 2010 cp.wu + * NULL + * remove unused mailbox message definitions. + * + * 08 02 2010 yuche.tsai + * NULL + * P2P Group Negotiation Code Check in. + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * message table should not be commented out by compilation option without modifying header file + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Rename MID_MNY_CNM_CH_RELEASE to MID_MNY_CNM_CH_ABORT + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * AIS-FSM integration with CNM channel request messages + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implementation of DRV-SCN and related mailbox message handling. + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Modify CNM message handler for new flow + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * restore utility function invoking via hem_mbox to direct calls + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * auth.c is migrated. + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add buildable & linkable ais_fsm.c + * + * related reference are still waiting to be resolved + * + * 06 09 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add definitions for module migration. + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * hem_mbox is migrated. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge cnm_scan.h and hem_mbox.h + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 04 29 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * Removed MID_RXM_MQM_QOS_ACTION_FRAME + * + * 04 29 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * Removed MID_RXM_MQM_BA_ACTION_FRAME + * + * 03 30 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support 2.4G OBSS scan + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 03 10 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * + * * * * * Add Channel Manager for arbitration of JOIN and SCAN Req + * + * 03 05 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Develop partial DPD code + * + * 02 11 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Added MID_RXM_MQM_QOS_ACTION_FRAME for RXM to indicate QoS Action frames to MQM + * + * 01 11 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add Deauth and Disassoc Handler + * + * Dec 7 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Rename the parameter of mboxDummy() + * + * Dec 2 2009 MTK02468 + * [BORA00000337] To check in codes for FPGA emulation + * Added MID_RXM_MQM_BA_ACTION_FRAME + * + * Nov 24 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Remove Dummy MSG ID + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add JOIN REQ related MSG ID + * + * Nov 16 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add AIS ABORT MSG ID + * + * Nov 5 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add SCN MSG IDs + * + * Oct 28 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +*/ + +#ifndef _HEM_MBOX_H +#define _HEM_MBOX_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* Message IDs */ +typedef enum _ENUM_MSG_ID_T { + MID_MNY_CNM_CH_REQ, /* MANY notify CNM to obtain channel privilege */ + MID_MNY_CNM_CH_ABORT, /* MANY notify CNM to abort/release channel privilege */ + + MID_CNM_AIS_CH_GRANT, /* CNM notify AIS for indicating channel granted */ + MID_CNM_P2P_CH_GRANT, /* CNM notify P2P for indicating channel granted */ + MID_CNM_BOW_CH_GRANT, /* CNM notify BOW for indicating channel granted */ + + /*--------------------------------------------------*/ + /* SCN Module Mailbox Messages */ + /*--------------------------------------------------*/ + MID_AIS_SCN_SCAN_REQ, /* AIS notify SCN for starting scan */ + MID_AIS_SCN_SCAN_REQ_V2, /* AIS notify SCN for starting scan with multiple SSID support */ + MID_AIS_SCN_SCAN_CANCEL, /* AIS notify SCN for cancelling scan */ + MID_P2P_SCN_SCAN_REQ, /* P2P notify SCN for starting scan */ + MID_P2P_SCN_SCAN_REQ_V2, /* P2P notify SCN for starting scan with multiple SSID support */ + MID_P2P_SCN_SCAN_CANCEL, /* P2P notify SCN for cancelling scan */ + MID_BOW_SCN_SCAN_REQ, /* BOW notify SCN for starting scan */ + MID_BOW_SCN_SCAN_REQ_V2, /* BOW notify SCN for starting scan with multiple SSID support */ + MID_BOW_SCN_SCAN_CANCEL, /* BOW notify SCN for cancelling scan */ + MID_RLM_SCN_SCAN_REQ, /* RLM notify SCN for starting scan (OBSS-SCAN) */ + MID_RLM_SCN_SCAN_REQ_V2, /* RLM notify SCN for starting scan (OBSS-SCAN) with multiple SSID support */ + MID_RLM_SCN_SCAN_CANCEL, /* RLM notify SCN for cancelling scan (OBSS-SCAN)*/ + MID_SCN_AIS_SCAN_DONE, /* SCN notify AIS for scan completion */ + MID_SCN_P2P_SCAN_DONE, /* SCN notify P2P for scan completion */ + MID_SCN_BOW_SCAN_DONE, /* SCN notify BOW for scan completion */ + MID_SCN_RLM_SCAN_DONE, /* SCN notify RLM for scan completion (OBSS-SCAN) */ + + /*--------------------------------------------------*/ + /* AIS Module Mailbox Messages */ + /*--------------------------------------------------*/ + MID_OID_AIS_FSM_JOIN_REQ, /* OID/IOCTL notify AIS for join */ + MID_OID_AIS_FSM_ABORT, /* OID/IOCTL notify AIS for abort */ + MID_AIS_SAA_FSM_START, /* AIS notify SAA for Starting authentication/association fsm */ + MID_AIS_SAA_FSM_ABORT, /* AIS notify SAA for Aborting authentication/association fsm */ + MID_SAA_AIS_JOIN_COMPLETE, /* SAA notify AIS for indicating join complete */ + +#if CFG_ENABLE_BT_OVER_WIFI + /*--------------------------------------------------*/ + /* BOW Module Mailbox Messages */ + /*--------------------------------------------------*/ + MID_BOW_SAA_FSM_START, /* BOW notify SAA for Starting authentication/association fsm */ + MID_BOW_SAA_FSM_ABORT, /* BOW notify SAA for Aborting authentication/association fsm */ + MID_SAA_BOW_JOIN_COMPLETE, /* SAA notify BOW for indicating join complete */ +#endif + +#if CFG_ENABLE_WIFI_DIRECT + /*--------------------------------------------------*/ + /* P2P Module Mailbox Messages */ + /*--------------------------------------------------*/ + MID_P2P_SAA_FSM_START, /* P2P notify SAA for Starting authentication/association fsm */ + MID_P2P_SAA_FSM_ABORT, /* P2P notify SAA for Aborting authentication/association fsm */ + MID_SAA_P2P_JOIN_COMPLETE, /* SAA notify P2P for indicating join complete */ + + MID_MNY_P2P_FUN_SWITCH, /* Enable P2P FSM. */ + MID_MNY_P2P_DEVICE_DISCOVERY, /* Start device discovery. */ + MID_MNY_P2P_DISCOVERY_ABORT, /* Start device discovery abort. */ + MID_MNY_P2P_CONNECTION_REQ, /* Connection request. */ + MID_MNY_P2P_CONNECTION_ABORT, /* Abort connection request, P2P FSM return to IDLE. */ + MID_MNY_P2P_CONNECTION_TRIGGER, /* Only if connection request is valid. Trigger P2P FSM to connection target AP. */ + MID_MNY_P2P_CONNECTION_PAUSE, /* Disconnect from target AP, connection is not complete yet. */ + MID_MNY_P2P_PROVISION_COMPLETE, /* Provisioning complete. */ + MID_MNY_P2P_INVITATION_REQ, + MID_MNY_P2P_INVITATION_ABORT, + MID_MNY_P2P_BEACON_UPDATE, + MID_MNY_P2P_BEACON_DEL, + MID_MNY_P2P_CHNL_REQ, + MID_MNY_P2P_CHNL_ABORT, + MID_MNY_P2P_MGMT_TX, + MID_MNY_P2P_GROUP_DISSOLVE, + MID_MNY_P2P_MGMT_FRAME_REGISTER, +#endif + +#if CFG_SUPPORT_ADHOC + MID_SCN_AIS_FOUND_IBSS, /* SCN notify AIS that an IBSS Peer has been found and can merge into */ +#endif /* CFG_SUPPORT_ADHOC */ + + MID_SAA_AIS_FSM_ABORT, /* SAA notify AIS for indicating deauthentication/disassociation */ + + MID_TOTAL_NUM +} ENUM_MSG_ID_T, *P_ENUM_MSG_ID_T; + +/* Message header of inter-components */ +struct _MSG_HDR_T { + LINK_ENTRY_T rLinkEntry; + ENUM_MSG_ID_T eMsgId; +}; + +typedef VOID (*PFN_MSG_HNDL_FUNC)(P_ADAPTER_T, P_MSG_HDR_T); + +typedef struct _MSG_HNDL_ENTRY { + ENUM_MSG_ID_T eMsgId; + PFN_MSG_HNDL_FUNC pfMsgHndl; +} MSG_HNDL_ENTRY_T, *P_MSG_HNDL_ENTRY_T; + +typedef enum _EUNM_MSG_SEND_METHOD_T { + MSG_SEND_METHOD_BUF = 0, /* Message is put in the queue and will be + executed when mailbox is checked. */ + MSG_SEND_METHOD_UNBUF /* The handler function is called immediately + in the same context of the sender */ +} EUNM_MSG_SEND_METHOD_T, *P_EUNM_MSG_SEND_METHOD_T; + + +typedef enum _ENUM_MBOX_ID_T { + MBOX_ID_0 = 0, + MBOX_ID_TOTAL_NUM +} ENUM_MBOX_ID_T, *P_ENUM_MBOX_ID_T; + +/* Define Mailbox structure */ +typedef struct _MBOX_T { + LINK_T rLinkHead; +} MBOX_T, *P_MBOX_T; + +typedef struct _MSG_SAA_FSM_START_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucSeqNum; + P_STA_RECORD_T prStaRec; +} MSG_SAA_FSM_START_T, *P_MSG_SAA_FSM_START_T; + +typedef struct _MSG_SAA_FSM_COMP_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucSeqNum; + WLAN_STATUS rJoinStatus; + P_STA_RECORD_T prStaRec; + P_SW_RFB_T prSwRfb; +} MSG_SAA_FSM_COMP_T, *P_MSG_SAA_FSM_COMP_T; + +typedef struct _MSG_SAA_FSM_ABORT_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucSeqNum; + P_STA_RECORD_T prStaRec; +} MSG_SAA_FSM_ABORT_T, *P_MSG_SAA_FSM_ABORT_T; + +typedef struct _MSG_CONNECTION_ABORT_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucNetTypeIndex; +} MSG_CONNECTION_ABORT_T, *P_MSG_CONNECTION_ABORT_T; + + + +/* specific message data types */ +typedef MSG_SAA_FSM_START_T MSG_JOIN_REQ_T, *P_MSG_JOIN_REQ_T; +typedef MSG_SAA_FSM_COMP_T MSG_JOIN_COMP_T, *P_MSG_JOIN_COMP_T; +typedef MSG_SAA_FSM_ABORT_T MSG_JOIN_ABORT_T, *P_MSG_JOIN_ABORT_T; + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID +mboxSetup ( + IN P_ADAPTER_T prAdapter, + IN ENUM_MBOX_ID_T eMboxId + ); + + +VOID +mboxSendMsg ( + IN P_ADAPTER_T prAdapter, + IN ENUM_MBOX_ID_T eMboxId, + IN P_MSG_HDR_T prMsg, + IN EUNM_MSG_SEND_METHOD_T eMethod + ); + +VOID +mboxRcvAllMsg ( + IN P_ADAPTER_T prAdapter, + IN ENUM_MBOX_ID_T eMboxId + ); + +VOID +mboxInitialize ( + IN P_ADAPTER_T prAdapter + ); + +VOID +mboxDestroy ( + IN P_ADAPTER_T prAdapter + ); + +VOID +mboxDummy ( + IN P_ADAPTER_T prAdapter, + P_MSG_HDR_T prMsgHdr + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _HEM_MBOX_H */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/mib.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/mib.h new file mode 100755 index 000000000000..a669eb548f8b --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/mib.h @@ -0,0 +1,201 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/mgmt/mib.h#1 $ +*/ + +/*! \file mib.h + \brief This file contains the IEEE 802.11 family related MIB definition + for MediaTek 802.11 Wireless LAN Adapters. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: mib.h $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 11 08 2010 wh.su + * [WCXRP00000171] [MT6620 Wi-Fi][Driver] Add message check code same behavior as mt5921 + * add the message check code from mt5921. + * + * 07 24 2010 wh.su + * + * .support the Wi-Fi RSN + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +*/ + +#ifndef _MIB_H +#define _MIB_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* Entry in SMT AuthenticationAlgorithms Table: dot11AuthenticationAlgorithmsEntry */ +typedef struct _DOT11_AUTHENTICATION_ALGORITHMS_ENTRY { + BOOLEAN dot11AuthenticationAlgorithmsEnable; /* dot11AuthenticationAlgorithmsEntry 3 */ +} DOT11_AUTHENTICATION_ALGORITHMS_ENTRY, *P_DOT11_AUTHENTICATION_ALGORITHMS_ENTRY; + +/* Entry in SMT dot11RSNAConfigPairwiseCiphersTalbe Table: dot11RSNAConfigPairwiseCiphersEntry */ +typedef struct _DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY +{ + UINT_32 dot11RSNAConfigPairwiseCipher; /* dot11RSNAConfigPairwiseCiphersEntry 2 */ + BOOLEAN dot11RSNAConfigPairwiseCipherEnabled; /* dot11RSNAConfigPairwiseCiphersEntry 3 */ +} DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY, *P_DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY; + +/* Entry in SMT dot11RSNAConfigAuthenticationSuitesTalbe Table: dot11RSNAConfigAuthenticationSuitesEntry */ +typedef struct _DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY +{ + UINT_32 dot11RSNAConfigAuthenticationSuite; /* dot11RSNAConfigAuthenticationSuitesEntry 2 */ + BOOLEAN dot11RSNAConfigAuthenticationSuiteEnabled; /* dot11RSNAConfigAuthenticationSuitesEntry 3 */ +} DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY, *P_DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY; + +/* ----- IEEE 802.11 MIB Major sections ----- */ +typedef struct _IEEE_802_11_MIB_T { + /* dot11PrivacyTable (dot11smt 5) */ + UINT_8 dot11WEPDefaultKeyID; /* dot11PrivacyEntry 2 */ + BOOLEAN dot11TranmitKeyAvailable; + UINT_32 dot11WEPICVErrorCount; /* dot11PrivacyEntry 5 */ + UINT_32 dot11WEPExcludedCount; /* dot11PrivacyEntry 6 */ + + /* dot11RSNAConfigTable (dot11smt 8) */ + UINT_32 dot11RSNAConfigGroupCipher; /* dot11RSNAConfigEntry 4 */ + + /* dot11RSNAConfigPairwiseCiphersTable (dot11smt 9) */ + DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY dot11RSNAConfigPairwiseCiphersTable[MAX_NUM_SUPPORTED_CIPHER_SUITES]; + + /* dot11RSNAConfigAuthenticationSuitesTable (dot11smt 10) */ + DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY dot11RSNAConfigAuthenticationSuitesTable[MAX_NUM_SUPPORTED_AKM_SUITES]; + +#if 0 //SUPPORT_WAPI + BOOLEAN fgWapiKeyInstalled; + PARAM_WPI_KEY_T rWapiPairwiseKey[2]; + BOOLEAN fgPairwiseKeyUsed[2]; + UINT_8 ucWpiActivedPWKey; /* Must be 0 or 1, by wapi spec */ + PARAM_WPI_KEY_T rWapiGroupKey[2]; + BOOLEAN fgGroupKeyUsed[2]; +#endif +} IEEE_802_11_MIB_T, *P_IEEE_802_11_MIB_T; + +/* ------------------ IEEE 802.11 non HT PHY characteristics ---------------- */ +typedef const struct _NON_HT_PHY_ATTRIBUTE_T { + UINT_16 u2SupportedRateSet; + + BOOLEAN fgIsShortPreambleOptionImplemented; + + BOOLEAN fgIsShortSlotTimeOptionImplemented; + +} NON_HT_PHY_ATTRIBUTE_T, *P_NON_HT_PHY_ATTRIBUTE_T; + +typedef const struct _NON_HT_ADHOC_MODE_ATTRIBUTE_T { + + ENUM_PHY_TYPE_INDEX_T ePhyTypeIndex; + + UINT_16 u2BSSBasicRateSet; + +} NON_HT_ADHOC_MODE_ATTRIBUTE_T, *P_NON_HT_ADHOC_MODE_ATTRIBUTE_T; + +typedef NON_HT_ADHOC_MODE_ATTRIBUTE_T NON_HT_AP_MODE_ATTRIBUTE_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +extern NON_HT_PHY_ATTRIBUTE_T rNonHTPhyAttributes[]; +extern NON_HT_ADHOC_MODE_ATTRIBUTE_T rNonHTAdHocModeAttributes[]; +extern NON_HT_AP_MODE_ATTRIBUTE_T rNonHTApModeAttributes[]; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _MIB_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/privacy.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/privacy.h new file mode 100755 index 000000000000..f8dce21b67ea --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/privacy.h @@ -0,0 +1,332 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/mgmt/privacy.h#1 $ +*/ + +/*! \file privacy.h + \brief This file contains the function declaration for privacy.c. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: privacy.h $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 07 24 2010 wh.su + * + * .support the Wi-Fi RSN + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * modify some code for concurrent network. + * + * 06 19 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * consdier the concurrent network setting. + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration the security related function from firmware. + * + * 03 01 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * Refine the variable and parameter for security. + * + * 02 25 2010 wh.su + * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing + * For support the WHQL test, do the remove key code refine. + * + * Dec 10 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * change the cmd return type + * + * Dec 8 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the function declaration for auth mode and encryption status setting from build connection command + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the function declaration for wapi + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the tx done callback handle function + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the function declaration for mac header privacy bit setting + * + * Dec 4 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the structure for parsing the EAPoL frame + * + * Dec 3 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adjust the class error function parameter + * + * Dec 1 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding some security function declaration + * + * Nov 19 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the ap selection structure + * + * Nov 18 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * +** +*/ + +#ifndef _PRIVACY_H +#define _PRIVACY_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define MAX_KEY_NUM 4 +#define WEP_40_LEN 5 +#define WEP_104_LEN 13 +#define LEGACY_KEY_MAX_LEN 16 +#define CCMP_KEY_LEN 16 +#define TKIP_KEY_LEN 32 +#define MAX_KEY_LEN 32 +#define MIC_RX_KEY_OFFSET 16 +#define MIC_TX_KEY_OFFSET 24 +#define MIC_KEY_LEN 8 + +#define WEP_KEY_ID_FIELD BITS(0,29) +#define KEY_ID_FIELD BITS(0,7) + +#define IS_TRANSMIT_KEY BIT(31) +#define IS_UNICAST_KEY BIT(30) +#define IS_AUTHENTICATOR BIT(28) + +#define CIPHER_SUITE_NONE 0 +#define CIPHER_SUITE_WEP40 1 +#define CIPHER_SUITE_TKIP 2 +#define CIPHER_SUITE_TKIP_WO_MIC 3 +#define CIPHER_SUITE_CCMP 4 +#define CIPHER_SUITE_WEP104 5 +#define CIPHER_SUITE_BIP 6 +#define CIPHER_SUITE_WEP128 7 +#define CIPHER_SUITE_WPI 8 + +#define WPA_KEY_INFO_KEY_TYPE BIT(3) /* 1 = Pairwise, 0 = Group key */ +#define WPA_KEY_INFO_MIC BIT(8) +#define WPA_KEY_INFO_SECURE BIT(9) + +#define MASK_2ND_EAPOL (WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC) + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef struct _IEEE_802_1X_HDR { + UINT_8 ucVersion; + UINT_8 ucType; + UINT_16 u2Length; + /* followed by length octets of data */ +} IEEE_802_1X_HDR, *P_IEEE_802_1X_HDR; + +typedef struct _EAPOL_KEY { + UINT_8 ucType; + /* Note: key_info, key_length, and key_data_length are unaligned */ + UINT_8 aucKeyInfo[2]; /* big endian */ + UINT_8 aucKeyLength[2]; /* big endian */ + UINT_8 aucReplayCounter[8]; + UINT_8 aucKeyNonce[16]; + UINT_8 aucKeyIv[16]; + UINT_8 aucKeyRsc[8]; + UINT_8 aucKeyId[8]; /* Reserved in IEEE 802.11i/RSN */ + UINT_8 aucKeyMic[16]; + UINT_8 aucKeyDataLength[2]; /* big endian */ + /* followed by key_data_length bytes of key_data */ +} EAPOL_KEY, *P_EAPOL_KEY; + +/* WPA2 PMKID candicate structure */ +typedef struct _PMKID_CANDICATE_T { + UINT_8 aucBssid[MAC_ADDR_LEN]; + UINT_32 u4PreAuthFlags; +} PMKID_CANDICATE_T, *P_PMKID_CANDICATE_T; + +#if 0 +/* WPA2 PMKID cache structure */ +typedef struct _PMKID_ENTRY_T { + PARAM_BSSID_INFO_T rBssidInfo; + BOOLEAN fgPmkidExist; +} PMKID_ENTRY_T, *P_PMKID_ENTRY_T; +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +VOID +secInit( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucNetTypeIdx + ); + +VOID +secSetPortBlocked( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta, + IN BOOLEAN fgPort + ); + +BOOL +secCheckClassError( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN P_STA_RECORD_T prStaRec + ); + +BOOL +secTxPortControlCheck( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN P_STA_RECORD_T prStaRec + ); + +BOOLEAN +secRxPortControlCheck( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSWRfb + ); + +VOID +secSetCipherSuite( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4CipherSuitesFlags + ); + +BOOL +secProcessEAPOL( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN P_STA_RECORD_T prStaRec, + IN PUINT_8 pucPayload, + IN UINT_16 u2PayloadLen + ); + +VOID +secHandleTxDoneCallback( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T pMsduInfo, + IN P_STA_RECORD_T prStaRec, + IN WLAN_STATUS rStatus + ); + +BOOLEAN +secIsProtectedFrame ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsdu, + IN P_STA_RECORD_T prStaRec + ); + +VOID +secClearPmkid( + IN P_ADAPTER_T prAdapter + ); + +BOOLEAN +secRsnKeyHandshakeEnabled( + IN P_ADAPTER_T prAdapter + ); + +BOOLEAN +secTransmitKeyExist( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ); + +BOOLEAN +secEnabledInAis( + IN P_ADAPTER_T prAdapter + ); + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _PRIVACY_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/rate.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/rate.h new file mode 100755 index 000000000000..652491b9408c --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/rate.h @@ -0,0 +1,155 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/mgmt/rate.h#1 $ +*/ + +/*! \file rate.h + \brief This file contains the rate utility function of + IEEE 802.11 family for MediaTek 802.11 Wireless LAN Adapters. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: rate.h $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add buildable & linkable ais_fsm.c + * + * related reference are still waiting to be resolved + * +*/ + +#ifndef _RATE_H +#define _RATE_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Routines in rate.c */ +/*----------------------------------------------------------------------------*/ +VOID +rateGetRateSetFromIEs ( + IN P_IE_SUPPORTED_RATE_T prIeSupportedRate, + IN P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate, + OUT PUINT_16 pu2OperationalRateSet, + OUT PUINT_16 pu2BSSBasicRateSet, + OUT PBOOLEAN pfgIsUnknownBSSBasicRate + ); + +VOID +rateGetDataRatesFromRateSet ( + IN UINT_16 u2OperationalRateSet, + IN UINT_16 u2BSSBasicRateSet, + OUT PUINT_8 pucDataRates, + OUT PUINT_8 pucDataRatesLen + ); + +BOOLEAN +rateGetHighestRateIndexFromRateSet ( + IN UINT_16 u2RateSet, + OUT PUINT_8 pucHighestRateIndex + ); + +BOOLEAN +rateGetLowestRateIndexFromRateSet ( + IN UINT_16 u2RateSet, + OUT PUINT_8 pucLowestRateIndex + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _RATE_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/rlm.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/rlm.h new file mode 100755 index 000000000000..0a7952f40dc6 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/rlm.h @@ -0,0 +1,498 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/mgmt/rlm.h#1 $ +*/ + +/*! \file "rlm.h" + \brief +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: rlm.h $ + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 04 12 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 01 13 2011 cm.chang + * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module + * Refine function when rcv a 20/40M public action frame + * + * 01 13 2011 cm.chang + * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting + * Use SCO of BSS_INFO to replace user-defined setting variables + * + * 01 12 2011 cm.chang + * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting + * User-defined bandwidth is for 2.4G and 5G individually + * + * 12 07 2010 cm.chang + * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk + * 1. BSSINFO include RLM parameter + * 2. free all sta records when network is disconnected + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 10 18 2010 cm.chang + * [WCXRP00000114] [MT6620 Wi-Fi] [Driver] Fix compiling warning in Linux about RLM network index checking + * Enum member cannot be used as compiling option decision in Linux + * + * 09 10 2010 cm.chang + * NULL + * Always update Beacon content if FW sync OBSS info + * + * 08 31 2010 kevin.huang + * NULL + * Use LINK LIST operation to process SCAN result + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 08 23 2010 chinghwa.yu + * NULL + * Update for BOW. + * + * 08 20 2010 cm.chang + * NULL + * Migrate RLM code to host from FW + * + * 08 16 2010 cp.wu + * NULL + * Replace CFG_SUPPORT_BOW by CFG_ENABLE_BT_OVER_WIFI. + * There is no CFG_SUPPORT_BOW in driver domain source. + * + * 08 02 2010 yuche.tsai + * NULL + * P2P Group Negotiation Code Check in. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Check draft RLM code for HT cap + * + * 06 28 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * 1st draft code for RLM module + * + * 06 02 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add RX HT GF compiling option + * + * 06 02 2010 chinghwa.yu + * [BORA00000563]Add WiFi CoEx BCM module + * Roll back to remove CFG_SUPPORT_BCM_TEST. + * + * 06 01 2010 chinghwa.yu + * [BORA00000563]Add WiFi CoEx BCM module + * Update BCM Test and RW configuration. + * + * 05 31 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add some compiling options to control 11n functions + * + * 05 18 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Ad-hoc Beacon should not carry HT OP and OBSS IEs + * + * 05 17 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * MT6620 does not support L-SIG TXOP + * + * 05 05 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * First draft support for 20/40M bandwidth for AP mode + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW + * + * 04 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * First draft code to support protection in AP mode + * + * 04 07 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Different invoking order for WTBL entry of associated AP + * + * 03 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Not carry HT cap when being associated with b/g only AP + * + * 03 03 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Move default value of HT capability to rlm.h + * + * 02 12 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Use bss info array for concurrent handle + * + * 01 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support protection and bandwidth switch + * + * 01 08 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * + * Modify the prototype of rlmRecAssocRspHtInfo() + * + * Dec 9 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add several function prototypes for HT operation + * + * Nov 18 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * +** +*/ + +#ifndef _RLM_H +#define _RLM_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define ELEM_EXT_CAP_DEFAULT_VAL \ + (ELEM_EXT_CAP_20_40_COEXIST_SUPPORT /*| ELEM_EXT_CAP_PSMP_CAP*/) + + +#if CFG_SUPPORT_RX_STBC + #define FIELD_HT_CAP_INFO_RX_STBC HT_CAP_INFO_RX_STBC_1_SS +#else + #define FIELD_HT_CAP_INFO_RX_STBC HT_CAP_INFO_RX_STBC_NO_SUPPORTED +#endif + +#if CFG_SUPPORT_RX_SGI + #define FIELD_HT_CAP_INFO_SGI_20M HT_CAP_INFO_SHORT_GI_20M + #define FIELD_HT_CAP_INFO_SGI_40M HT_CAP_INFO_SHORT_GI_40M +#else + #define FIELD_HT_CAP_INFO_SGI_20M 0 + #define FIELD_HT_CAP_INFO_SGI_40M 0 +#endif + +#if CFG_SUPPORT_RX_HT_GF + #define FIELD_HT_CAP_INFO_HT_GF HT_CAP_INFO_HT_GF +#else + #define FIELD_HT_CAP_INFO_HT_GF 0 +#endif + +#define HT_CAP_INFO_DEFAULT_VAL \ + (HT_CAP_INFO_SUP_CHNL_WIDTH | FIELD_HT_CAP_INFO_HT_GF | \ + FIELD_HT_CAP_INFO_SGI_20M | FIELD_HT_CAP_INFO_SGI_40M | \ + FIELD_HT_CAP_INFO_RX_STBC | HT_CAP_INFO_DSSS_CCK_IN_40M) + + + +#define AMPDU_PARAM_DEFAULT_VAL \ + (AMPDU_PARAM_MAX_AMPDU_LEN_64K | AMPDU_PARAM_MSS_NO_RESTRICIT) + + +#define SUP_MCS_TX_DEFAULT_VAL \ + SUP_MCS_TX_SET_DEFINED /* TX defined and TX/RX equal (TBD) */ + +#if CFG_SUPPORT_MFB + #define FIELD_HT_EXT_CAP_MFB HT_EXT_CAP_MCS_FEEDBACK_BOTH +#else + #define FIELD_HT_EXT_CAP_MFB HT_EXT_CAP_MCS_FEEDBACK_NO_FB +#endif + +#if CFG_SUPPORT_RX_RDG + #define FIELD_HT_EXT_CAP_RDR HT_EXT_CAP_RD_RESPONDER +#else + #define FIELD_HT_EXT_CAP_RDR 0 +#endif + +#if CFG_SUPPORT_MFB || CFG_SUPPORT_RX_RDG + #define FIELD_HT_EXT_CAP_HTC HT_EXT_CAP_HTC_SUPPORT +#else + #define FIELD_HT_EXT_CAP_HTC 0 +#endif + +#define HT_EXT_CAP_DEFAULT_VAL \ + (HT_EXT_CAP_PCO | HT_EXT_CAP_PCO_TRANS_TIME_NONE | \ + FIELD_HT_EXT_CAP_MFB | FIELD_HT_EXT_CAP_HTC | \ + FIELD_HT_EXT_CAP_RDR) + +#define TX_BEAMFORMING_CAP_DEFAULT_VAL 0 +#define ASEL_CAP_DEFAULT_VAL 0 + + +/* Define bandwidth from user setting */ +#define CONFIG_BW_20_40M 0 +#define CONFIG_BW_20M 1 /* 20MHz only */ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/* It is used for RLM module to judge if specific network is valid + * Note: Ad-hoc mode of AIS is not included now. (TBD) + */ +#define RLM_NET_PARAM_VALID(_prBssInfo) \ + (IS_BSS_ACTIVE(_prBssInfo) && \ + ((_prBssInfo)->eConnectionState == PARAM_MEDIA_STATE_CONNECTED || \ + (_prBssInfo)->eCurrentOPMode == OP_MODE_ACCESS_POINT || \ + (_prBssInfo)->eCurrentOPMode == OP_MODE_IBSS || \ + RLM_NET_IS_BOW(_prBssInfo)) \ + ) + +#define RLM_NET_IS_11N(_prBssInfo) \ + ((_prBssInfo)->ucPhyTypeSet & PHY_TYPE_SET_802_11N) +#define RLM_NET_IS_11GN(_prBssInfo) \ + ((_prBssInfo)->ucPhyTypeSet & PHY_TYPE_SET_802_11GN) + + +/* This macro is used to sweep all 3 networks */ +#define RLM_NET_FOR_EACH(_ucNetIdx) \ + for ((_ucNetIdx) = 0; \ + (_ucNetIdx) < NETWORK_TYPE_INDEX_NUM; \ + (_ucNetIdx)++) + +/* This macro is used to sweep all networks excluding BOW */ +#if CFG_ENABLE_BT_OVER_WIFI + /* Note: value of enum NETWORK_TYPE_BOW_INDEX is validated in + * rlmStuctureCheck(). + */ + #define RLM_NET_FOR_EACH_NO_BOW(_ucNetIdx) \ + for ((_ucNetIdx) = 0; \ + (_ucNetIdx) < NETWORK_TYPE_BOW_INDEX; \ + (_ucNetIdx)++) + + #define RLM_NET_IS_BOW(_prBssInfo) \ + ((_prBssInfo)->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) + +#else + #define RLM_NET_FOR_EACH_NO_BOW(_ucNetIdx) RLM_NET_FOR_EACH(_ucNetIdx) + #define RLM_NET_IS_BOW(_prBssInfo) (FALSE) + +#endif /* end of CFG_ENABLE_BT_OVER_WIFI */ + + +/* The bandwidth modes are not used anymore. They represent if AP + * can use 20/40 bandwidth, not all modes. (20110411) + */ +#define RLM_AP_IS_BW_40_ALLOWED(_prAdapter, _prBssInfo) \ + (((_prBssInfo)->eBand == BAND_2G4 && \ + (_prAdapter)->rWifiVar.rConnSettings.uc2G4BandwidthMode \ + == CONFIG_BW_20_40M) || \ + ((_prBssInfo)->eBand == BAND_5G && \ + (_prAdapter)->rWifiVar.rConnSettings.uc5GBandwidthMode \ + == CONFIG_BW_20_40M)) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID +rlmFsmEventInit ( + P_ADAPTER_T prAdapter + ); + +VOID +rlmFsmEventUninit ( + P_ADAPTER_T prAdapter + ); + +VOID +rlmReqGenerateHtCapIE ( + P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo + ); + +VOID +rlmReqGenerateExtCapIE ( + P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo + ); + +VOID +rlmRspGenerateHtCapIE ( + P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo + ); + +VOID +rlmRspGenerateExtCapIE ( + P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo + ); + +VOID +rlmRspGenerateHtOpIE ( + P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo + ); + +VOID +rlmRspGenerateErpIE ( + P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo + ); + +VOID +rlmProcessBcn ( + P_ADAPTER_T prAdapter, + P_SW_RFB_T prSwRfb, + PUINT_8 pucIE, + UINT_16 u2IELength + ); + +VOID +rlmProcessAssocRsp ( + P_ADAPTER_T prAdapter, + P_SW_RFB_T prSwRfb, + PUINT_8 pucIE, + UINT_16 u2IELength + ); + +VOID +rlmFillSyncCmdParam ( + P_CMD_SET_BSS_RLM_PARAM_T prCmdBody, + P_BSS_INFO_T prBssInfo + ); + +VOID +rlmSyncOperationParams ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo + ); + +VOID +rlmBssInitForAPandIbss ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo + ); + +VOID +rlmProcessAssocReq ( + P_ADAPTER_T prAdapter, + P_SW_RFB_T prSwRfb, + PUINT_8 pucIE, + UINT_16 u2IELength + ); + +VOID +rlmBssAborted ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo + ); + +VOID +linkToRlmRspGenerateObssScanIE ( + P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo + ); + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#ifndef _lint +__KAL_INLINE__ VOID +rlmDataTypeCheck ( + VOID + ) +{ +#if CFG_ENABLE_BT_OVER_WIFI + DATA_STRUC_INSPECTING_ASSERT( + NETWORK_TYPE_AIS_INDEX < NETWORK_TYPE_BOW_INDEX); + + #if CFG_ENABLE_WIFI_DIRECT + DATA_STRUC_INSPECTING_ASSERT( + NETWORK_TYPE_P2P_INDEX < NETWORK_TYPE_BOW_INDEX); + #endif +#endif + + return; +} +#endif /* _lint */ + +#endif /* _RLM_H */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/rlm_domain.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/rlm_domain.h new file mode 100755 index 000000000000..7e27be230959 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/rlm_domain.h @@ -0,0 +1,395 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/mgmt/rlm_domain.h#1 $ +*/ + +/*! \file "rlm_domain.h" + \brief +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: rlm_domain.h $ + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 06 01 2011 cm.chang + * [WCXRP00000756] [MT6620 Wi-Fi][Driver] 1. AIS follow channel of BOW 2. Provide legal channel function + * Provide function to check if specified channel is legal based on domain + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 28 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * 1st draft code for RLM module + * + * 02 23 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add support scan channel 1~14 and update scan result's frequency infou1rwduu`wvpghlqg|n`slk+mpdkb + * + * 01 13 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Provide query function about full channle list. + * + * Dec 1 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Declare public rDomainInfo + * +** +*/ + +#ifndef _RLM_DOMAIN_H +#define _RLM_DOMAIN_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define MAX_SUBBAND_NUM 6 + + +#define COUNTRY_CODE_NULL ((UINT_16)0x0) + +/* ISO/IEC 3166-1 two-character country codes */ +#define COUNTRY_CODE_AG (((UINT_16) 'A' << 8) | (UINT_16) 'G') /* Antigua/Barbuda */ +#define COUNTRY_CODE_AI (((UINT_16) 'A' << 8) | (UINT_16) 'I') /* Anguilla */ +#define COUNTRY_CODE_AR (((UINT_16) 'A' << 8) | (UINT_16) 'T') /* Argentina */ +#define COUNTRY_CODE_AT (((UINT_16) 'A' << 8) | (UINT_16) 'T') /* Austria */ +#define COUNTRY_CODE_AU (((UINT_16) 'A' << 8) | (UINT_16) 'U') /* Australia */ +#define COUNTRY_CODE_AW (((UINT_16) 'A' << 8) | (UINT_16) 'W') /* Aruba */ +#define COUNTRY_CODE_BB (((UINT_16) 'B' << 8) | (UINT_16) 'B') /* Barbados */ +#define COUNTRY_CODE_BE (((UINT_16) 'B' << 8) | (UINT_16) 'E') /* Belgium */ +#define COUNTRY_CODE_BM (((UINT_16) 'B' << 8) | (UINT_16) 'M') /* Bermuda */ +#define COUNTRY_CODE_BO (((UINT_16) 'B' << 8) | (UINT_16) 'O') /* Bolivia */ +#define COUNTRY_CODE_BR (((UINT_16) 'B' << 8) | (UINT_16) 'R') /* Brazil */ +#define COUNTRY_CODE_BS (((UINT_16) 'B' << 8) | (UINT_16) 'S') /* Bahamas */ +#define COUNTRY_CODE_BY (((UINT_16) 'B' << 8) | (UINT_16) 'Y') /* Belarus */ +#define COUNTRY_CODE_CA (((UINT_16) 'C' << 8) | (UINT_16) 'A') /* Canada */ +#define COUNTRY_CODE_CH (((UINT_16) 'C' << 8) | (UINT_16) 'H') /* Switzerland */ +#define COUNTRY_CODE_CL (((UINT_16) 'C' << 8) | (UINT_16) 'L') /* Chile */ +#define COUNTRY_CODE_CN (((UINT_16) 'C' << 8) | (UINT_16) 'N') /* China */ +#define COUNTRY_CODE_CO (((UINT_16) 'C' << 8) | (UINT_16) 'O') /* Colombia */ +#define COUNTRY_CODE_CR (((UINT_16) 'C' << 8) | (UINT_16) 'R') /* Costa Rica */ +#define COUNTRY_CODE_CU (((UINT_16) 'C' << 8) | (UINT_16) 'U') /* Cuba */ +#define COUNTRY_CODE_DE (((UINT_16) 'D' << 8) | (UINT_16) 'E') /* Germany */ +#define COUNTRY_CODE_DK (((UINT_16) 'D' << 8) | (UINT_16) 'K') /* Denmark */ +#define COUNTRY_CODE_DM (((UINT_16) 'D' << 8) | (UINT_16) 'M') /* Dominica */ +#define COUNTRY_CODE_DO (((UINT_16) 'D' << 8) | (UINT_16) 'O') /* Dominican Republic */ +#define COUNTRY_CODE_EC (((UINT_16) 'E' << 8) | (UINT_16) 'C') /* Ecuador */ +#define COUNTRY_CODE_EG (((UINT_16) 'E' << 8) | (UINT_16) 'G') /* Egypt */ +#define COUNTRY_CODE_ES (((UINT_16) 'E' << 8) | (UINT_16) 'S') /* Spain */ +#define COUNTRY_CODE_EU (((UINT_16) 'E' << 8) | (UINT_16) 'U') /* ETSI (Europe) */ +#define COUNTRY_CODE_FI (((UINT_16) 'F' << 8) | (UINT_16) 'I') /* Finland */ +#define COUNTRY_CODE_FR (((UINT_16) 'F' << 8) | (UINT_16) 'R') /* France */ +#define COUNTRY_CODE_GB (((UINT_16) 'G' << 8) | (UINT_16) 'B') /* United Kingdom */ +#define COUNTRY_CODE_GD (((UINT_16) 'G' << 8) | (UINT_16) 'D') /* Grenada */ +#define COUNTRY_CODE_GR (((UINT_16) 'G' << 8) | (UINT_16) 'R') /* Greece */ +#define COUNTRY_CODE_GY (((UINT_16) 'G' << 8) | (UINT_16) 'Y') /* Guyana */ +#define COUNTRY_CODE_HK (((UINT_16) 'H' << 8) | (UINT_16) 'K') /* Hong Kong */ +#define COUNTRY_CODE_HT (((UINT_16) 'H' << 8) | (UINT_16) 'T') /* Haiti */ +#define COUNTRY_CODE_HN (((UINT_16) 'H' << 8) | (UINT_16) 'N') /* Honduras */ +#define COUNTRY_CODE_ID (((UINT_16) 'I' << 8) | (UINT_16) 'D') /* Indonesia */ +#define COUNTRY_CODE_IE (((UINT_16) 'I' << 8) | (UINT_16) 'E') /* Ireland */ +#define COUNTRY_CODE_IL (((UINT_16) 'I' << 8) | (UINT_16) 'L') /* Israel */ +#define COUNTRY_CODE_IN (((UINT_16) 'I' << 8) | (UINT_16) 'N') /* India */ +#define COUNTRY_CODE_IR (((UINT_16) 'I' << 8) | (UINT_16) 'R') /* Iran */ +#define COUNTRY_CODE_IS (((UINT_16) 'I' << 8) | (UINT_16) 'S') /* Iceland */ +#define COUNTRY_CODE_IT (((UINT_16) 'I' << 8) | (UINT_16) 'T') /* Italy */ +#define COUNTRY_CODE_JM (((UINT_16) 'J' << 8) | (UINT_16) 'M') /* Jamaica */ +#define COUNTRY_CODE_JO (((UINT_16) 'J' << 8) | (UINT_16) 'O') /* Jordan */ +#define COUNTRY_CODE_JP (((UINT_16) 'J' << 8) | (UINT_16) 'P') /* Japan */ +#define COUNTRY_CODE_KN (((UINT_16) 'K' << 8) | (UINT_16) 'N') /* Saint Kitts and Nevis */ +#define COUNTRY_CODE_KR (((UINT_16) 'K' << 8) | (UINT_16) 'R') /* South Korea */ +#define COUNTRY_CODE_KW (((UINT_16) 'K' << 8) | (UINT_16) 'W') /* Kuwait */ +#define COUNTRY_CODE_LC (((UINT_16) 'L' << 8) | (UINT_16) 'C') /* Saint Lucia */ +#define COUNTRY_CODE_LI (((UINT_16) 'L' << 8) | (UINT_16) 'I') /* Liechtenstein */ +#define COUNTRY_CODE_LK (((UINT_16) 'L' << 8) | (UINT_16) 'K') /* Sri Lanka */ +#define COUNTRY_CODE_LU (((UINT_16) 'L' << 8) | (UINT_16) 'U') /* Luxembourg */ +#define COUNTRY_CODE_MA (((UINT_16) 'M' << 8) | (UINT_16) 'A') /* Morocco */ +#define COUNTRY_CODE_MD (((UINT_16) 'M' << 8) | (UINT_16) 'D') /* Moldova */ +#define COUNTRY_CODE_MX (((UINT_16) 'M' << 8) | (UINT_16) 'X') /* Mexico */ +#define COUNTRY_CODE_MY (((UINT_16) 'M' << 8) | (UINT_16) 'Y') /* Malaysia */ +#define COUNTRY_CODE_NI (((UINT_16) 'N' << 8) | (UINT_16) 'I') /* Nicaragua */ +#define COUNTRY_CODE_NL (((UINT_16) 'N' << 8) | (UINT_16) 'L') /* Netherlands */ +#define COUNTRY_CODE_NO (((UINT_16) 'N' << 8) | (UINT_16) 'O') /* Norway */ +#define COUNTRY_CODE_NZ (((UINT_16) 'N' << 8) | (UINT_16) 'Z') /* New Zealand */ +#define COUNTRY_CODE_OM (((UINT_16) 'O' << 8) | (UINT_16) 'M') /* Oman */ +#define COUNTRY_CODE_PE (((UINT_16) 'P' << 8) | (UINT_16) 'E') /* Peru */ +#define COUNTRY_CODE_PG (((UINT_16) 'P' << 8) | (UINT_16) 'G') /* Papua New Guinea */ +#define COUNTRY_CODE_PH (((UINT_16) 'P' << 8) | (UINT_16) 'H') /* Philippines */ +#define COUNTRY_CODE_PK (((UINT_16) 'P' << 8) | (UINT_16) 'K') /* Pakistan */ +#define COUNTRY_CODE_PR (((UINT_16) 'P' << 8) | (UINT_16) 'R') /* Puerto Rico */ +#define COUNTRY_CODE_PT (((UINT_16) 'P' << 8) | (UINT_16) 'T') /* Portugal */ +#define COUNTRY_CODE_PY (((UINT_16) 'P' << 8) | (UINT_16) 'Y') /* Paraguay */ +#define COUNTRY_CODE_PZ (((UINT_16) 'P' << 8) | (UINT_16) 'Z') /* Panama */ +#define COUNTRY_CODE_RU (((UINT_16) 'R' << 8) | (UINT_16) 'U') /* Russian */ +#define COUNTRY_CODE_SA (((UINT_16) 'S' << 8) | (UINT_16) 'A') /* Saudi Arabia */ +#define COUNTRY_CODE_SE (((UINT_16) 'S' << 8) | (UINT_16) 'E') /* Sweden */ +#define COUNTRY_CODE_SG (((UINT_16) 'S' << 8) | (UINT_16) 'G') /* Singapore */ +#define COUNTRY_CODE_SR (((UINT_16) 'S' << 8) | (UINT_16) 'R') /* Suriname */ +#define COUNTRY_CODE_TW (((UINT_16) 'T' << 8) | (UINT_16) 'W') /* Taiwan */ +#define COUNTRY_CODE_TH (((UINT_16) 'T' << 8) | (UINT_16) 'H') /* Thailand */ +#define COUNTRY_CODE_TR (((UINT_16) 'T' << 8) | (UINT_16) 'R') /* Turkey */ +#define COUNTRY_CODE_TT (((UINT_16) 'T' << 8) | (UINT_16) 'T') /* Trinidad */ +#define COUNTRY_CODE_UA (((UINT_16) 'U' << 8) | (UINT_16) 'A') /* Ukraine */ +#define COUNTRY_CODE_US (((UINT_16) 'U' << 8) | (UINT_16) 'S') /* United States */ +#define COUNTRY_CODE_UY (((UINT_16) 'U' << 8) | (UINT_16) 'Y') /* Uruguay */ +#define COUNTRY_CODE_VC (((UINT_16) 'V' << 8) | (UINT_16) 'C') /* Saint Vincent */ +#define COUNTRY_CODE_VE (((UINT_16) 'V' << 8) | (UINT_16) 'E') /* Venezuela */ +#define COUNTRY_CODE_VN (((UINT_16) 'V' << 8) | (UINT_16) 'N') /* Vietnam */ + +/* dot11RegDomainsSupportValue */ +#define MIB_REG_DOMAIN_FCC 0x10 /* FCC (US) */ +#define MIB_REG_DOMAIN_IC 0x20 /* IC or DOC (Canada) */ +#define MIB_REG_DOMAIN_ETSI 0x30 /* ETSI (Europe) */ +#define MIB_REG_DOMAIN_SPAIN 0x31 /* Spain */ +#define MIB_REG_DOMAIN_FRANCE 0x32 /* France */ +#define MIB_REG_DOMAIN_JAPAN 0x40 /* MPHPT (Japan) */ +#define MIB_REG_DOMAIN_OTHER 0x00 /* other */ + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/* Define channel offset in unit of 5MHz bandwidth */ +typedef enum _ENUM_CHNL_SPAN_T { + CHNL_SPAN_5 = 1, + CHNL_SPAN_10 = 2, + CHNL_SPAN_20 = 4, + CHNL_SPAN_40 = 8 +} ENUM_CHNL_SPAN_T, *P_ENUM_CHNL_SPAN_T; + +/* Define BSS operating bandwidth */ +typedef enum _ENUM_CHNL_BW_T { + CHNL_BW_20, + CHNL_BW_20_40, + CHNL_BW_10, + CHNL_BW_5 +} ENUM_CHNL_BW_T, *P_ENUM_CHNL_BW_T; + +#if 0 +/* If channel width is CHNL_BW_20_40, the first channel will be SCA and + * the second channel is SCB, then iteratively. + * Note the final channel will not be SCA. + */ +typedef struct _DOMAIN_SUBBAND_INFO { + UINT_8 ucRegClass; + ENUM_BAND_T eBand; + ENUM_CHNL_SPAN_T eChannelSpan; + UINT_8 ucFirstChannelNum; + UINT_8 ucNumChannels; + ENUM_CHNL_BW_T eChannelBw; + BOOLEAN fgDfsNeeded; + BOOLEAN fgIbssProhibited; +} DOMAIN_SUBBAND_INFO, *P_DOMAIN_SUBBAND_INFO; + +/* Use it as all available channel list for STA */ +typedef struct _DOMAIN_INFO_ENTRY { + UINT_16 u2CountryCode; + UINT_16 u2MibRegDomainValue; + + /* If different attributes, put them into different rSubBands. + * For example, DFS shall be used or not. + */ + DOMAIN_SUBBAND_INFO rSubBand[MAX_SUBBAND_NUM]; +} DOMAIN_INFO_ENTRY, *P_DOMAIN_INFO_ENTRY; + +#else /* New definition 20110830 */ + +/* In all bands, the first channel will be SCA and the second channel is SCB, + * then iteratively. + * Note the final channel will not be SCA. + */ +typedef struct _DOMAIN_SUBBAND_INFO { + /* Note1: regulation class depends on operation bandwidth and RF band. + * For example: 2.4GHz, 1~13, 20MHz ==> regulation class = 81 + * 2.4GHz, 1~13, SCA ==> regulation class = 83 + * 2.4GHz, 1~13, SCB ==> regulation class = 84 + * Note2: TX power limit is not specified here because path loss is unknown + */ + UINT_8 ucRegClass; /* Regulation class for 20MHz */ + UINT_8 ucBand; /* Type: ENUM_BAND_T */ + UINT_8 ucChannelSpan; /* Type: ENUM_CHNL_SPAN_T */ + UINT_8 ucFirstChannelNum; + UINT_8 ucNumChannels; + UINT_8 ucReserved; /* Type: BOOLEAN (fgDfsNeeded) */ +} DOMAIN_SUBBAND_INFO, *P_DOMAIN_SUBBAND_INFO; + +/* Use it as all available channel list for STA */ +typedef struct _DOMAIN_INFO_ENTRY { + PUINT_16 pu2CountryGroup; + UINT_32 u4CountryNum; + + /* If different attributes, put them into different rSubBands. + * For example, DFS shall be used or not. + */ + DOMAIN_SUBBAND_INFO rSubBand[MAX_SUBBAND_NUM]; +} DOMAIN_INFO_ENTRY, *P_DOMAIN_INFO_ENTRY; +#endif + +/* The following definitions are not used yet */ +typedef enum _ENUM_CH_SET_2G4_T { + CH_SET_2G4_NA, + CH_SET_2G4_1_11, + CH_SET_2G4_1_13, + CH_SET_2G4_1_14, + CH_SET_2G4_NUM +} ENUM_CH_SET_2G4_T, *P_ENUM_CH_SET_2G4_T; + +typedef enum _ENUM_CH_SET_UNII_LOW_T { + CH_SET_UNII_LOW_NA, + CH_SET_UNII_LOW_36_48, + CH_SET_UNII_LOW_NUM +} ENUM_CH_SET_UNII_LOW_T, *P_ENUM_CH_SET_UNII_LOW_T; + +typedef enum _ENUM_CH_SET_UNII_MID_T { + CH_SET_UNII_MID_NA, + CH_SET_UNII_MID_52_64, + CH_SET_UNII_MID_NUM +} ENUM_CH_SET_UNII_MID_T, *P_ENUM_CH_SET_UNII_MID_T; + +typedef enum _ENUM_CH_SET_UNII_WW_T { + CH_SET_UNII_WW_NA, + CH_SET_UNII_WW_100_128, + CH_SET_UNII_WW_100_140, + CH_SET_UNII_WW_100_116_132_140, + CH_SET_UNII_WW_NUM +} ENUM_CH_SET_UNII_WW_T, *P_ENUM_CH_SET_UNII_WW_T; + +typedef enum _ENUM_CH_SET_UNII_UPPER_T { + CH_SET_UNII_UPPER_NA, + CH_SET_UNII_UPPER_149_161, + CH_SET_UNII_UPPER_149_165, + CH_SET_UNII_UPPER_149_173, + CH_SET_UNII_UPPER_NUM +} ENUM_CH_SET_UNII_UPPER_T, *P_ENUM_CH_SET_UNII_UPPER_T; + +typedef struct _COUNTRY_CH_SET_T { + ENUM_CH_SET_2G4_T e2G4; + ENUM_CH_SET_UNII_LOW_T eUniiLow; + ENUM_CH_SET_UNII_MID_T eUniiMid; + ENUM_CH_SET_UNII_WW_T eUniiWw; + ENUM_CH_SET_UNII_UPPER_T eUniiUpper; +} COUNTRY_CH_SET_T, *P_COUNTRY_CH_SET_T; + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +P_DOMAIN_INFO_ENTRY +rlmDomainGetDomainInfo ( + P_ADAPTER_T prAdapter + ); + +VOID +rlmDomainGetChnlList ( + P_ADAPTER_T prAdapter, + ENUM_BAND_T eSpecificBand, + UINT_8 ucMaxChannelNum, + PUINT_8 pucNumOfChannel, + P_RF_CHANNEL_INFO_T paucChannelList + ); + +VOID +rlmDomainSendCmd ( + P_ADAPTER_T prAdapter, + BOOLEAN fgIsOid + ); + +BOOLEAN +rlmDomainIsLegalChannel ( + P_ADAPTER_T prAdapter, + ENUM_BAND_T eBand, + UINT_8 ucChannel + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _RLM_DOMAIN_H */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/rlm_obss.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/rlm_obss.h new file mode 100755 index 000000000000..b0ca5f16a59c --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/rlm_obss.h @@ -0,0 +1,208 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/mgmt/rlm_obss.h#1 $ +*/ + +/*! \file "rlm_obss.h" + \brief +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: rlm_obss.h $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 01 24 2011 cm.chang + * [WCXRP00000384] [MT6620 Wi-Fi][Driver][FW] Handle 20/40 action frame in AP mode and stop ampdu timer when sta_rec is freed + * Process received 20/40 coexistence action frame for AP mode + * + * 01 13 2011 cm.chang + * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module + * Refine function when rcv a 20/40M public action frame + * + * 01 12 2011 cm.chang + * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting + * User-defined bandwidth is for 2.4G and 5G individually + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 28 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * 1st draft code for RLM module + * + * 05 07 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Process 20/40 coexistence public action frame in AP mode + * + * 05 05 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * First draft support for 20/40M bandwidth for AP mode + * + * 04 07 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add virtual test for OBSS scan + * + * 03 30 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support 2.4G OBSS scan + * + * 02 13 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support PCO in STA mode + * + * 02 12 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Use bss info array for concurrent handle + * + * 01 25 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support protection and bandwidth switch +*/ + +#ifndef _RLM_OBSS_H +#define _RLM_OBSS_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define CHNL_LIST_SZ_2G 14 +#define CHNL_LIST_SZ_5G 14 + + +#define CHNL_LEVEL0 0 +#define CHNL_LEVEL1 1 +#define CHNL_LEVEL2 2 + +#define AFFECTED_CHNL_OFFSET 5 + +#define OBSS_SCAN_MIN_INTERVAL 10 /* In unit of sec */ + +#define PUBLIC_ACTION_MAX_LEN 200 /* In unit of byte */ + +/* P2P GO only */ +/* Define default OBSS Scan parameters (from MIB in spec.) */ +#define dot11OBSSScanPassiveDwell 20 +#define dot11OBSSScanActiveDwell 10 +#define dot11OBSSScanPassiveTotalPerChannel 200 +#define dot11OBSSScanActiveTotalPerChannel 20 +#define dot11BSSWidthTriggerScanInterval 300 /* Unit: sec */ +#define dot11BSSWidthChannelTransitionDelayFactor 5 +#define dot11OBSSScanActivityThreshold 25 + +#define OBSS_20_40M_TIMEOUT (dot11BSSWidthTriggerScanInterval + 10) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/* Control MAC PCO function */ +typedef enum _ENUM_SYS_PCO_PHASE_T { + SYS_PCO_PHASE_DISABLED = 0, + SYS_PCO_PHASE_20M, + SYS_PCO_PHASE_40M +} ENUM_SYS_PCO_PHASE_T, *P_ENUM_SYS_PCO_PHASE_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID +rlmObssInit ( + P_ADAPTER_T prAdapter + ); + +VOID +rlmObssScanDone ( + P_ADAPTER_T prAdapter, + P_MSG_HDR_T prMsgHdr + ); + +VOID +rlmObssTriggerScan ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _RLM_OBSS_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/rlm_protection.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/rlm_protection.h new file mode 100755 index 000000000000..0b12ff7981cd --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/rlm_protection.h @@ -0,0 +1,170 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/mgmt/rlm_protection.h#1 $ +*/ + +/*! \file "rlm_protection.h" + \brief +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: rlm_protection.h $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 08 20 2010 cm.chang + * NULL + * Migrate RLM code to host from FW + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 28 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * 1st draft code for RLM module + * + * 04 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * First draft code to support protection in AP mode + * + * 02 13 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support PCO in STA mode + * + * 02 12 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Use bss info array for concurrent handle + * + * 01 25 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support protection and bandwidth switch +*/ + +#ifndef _RLM_PROTECTION_H +#define _RLM_PROTECTION_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_SYS_PROTECT_MODE_T { + SYS_PROTECT_MODE_NONE = 0, /* Mode 0 */ + SYS_PROTECT_MODE_ERP, /* Mode 1 */ + SYS_PROTECT_MODE_NON_HT, /* Mode 2 */ + SYS_PROTECT_MODE_20M, /* Mode 3 */ + + SYS_PROTECT_MODE_NUM +} ENUM_SYS_PROTECT_MODE_T, *P_ENUM_SYS_PROTECT_MODE_T; + +/* This definition follows HT Protection field of HT Operation IE */ +typedef enum _ENUM_HT_PROTECT_MODE_T { + HT_PROTECT_MODE_NONE = 0, + HT_PROTECT_MODE_NON_MEMBER, + HT_PROTECT_MODE_20M, + HT_PROTECT_MODE_NON_HT, + + HT_PROTECT_MODE_NUM +} ENUM_HT_PROTECT_MODE_T, *P_ENUM_HT_PROTECT_MODE_T; + + +typedef enum _ENUM_GF_MODE_T { + GF_MODE_NORMAL = 0, + GF_MODE_PROTECT, + GF_MODE_DISALLOWED, + + GF_MODE_NUM +} ENUM_GF_MODE_T, *P_ENUM_GF_MODE_T; + +typedef enum _ENUM_RIFS_MODE_T { + RIFS_MODE_NORMAL = 0, + RIFS_MODE_DISALLOWED, + + RIFS_MODE_NUM +} ENUM_RIFS_MODE_T, *P_ENUM_RIFS_MODE_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _RLM_PROTECTION_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/roaming_fsm.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/roaming_fsm.h new file mode 100755 index 000000000000..71c54db250cc --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/roaming_fsm.h @@ -0,0 +1,245 @@ +/* +** $Id: +*/ + +/*! \file "roaming_fsm.h" + \brief This file defines the FSM for Roaming MODULE. + + This file defines the FSM for Roaming MODULE. +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: roaming_fsm.h $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 16 2011 tsaiyuan.hsu + * [WCXRP00000517] [MT6620 Wi-Fi][Driver][FW] Fine Tune Performance of Roaming + * remove obsolete definition and unused variables. + * + * 02 26 2011 tsaiyuan.hsu + * [WCXRP00000391] [MT6620 Wi-Fi][FW] Add Roaming Support + * not send disassoc or deauth to leaving AP so as to improve performace of roaming. + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * +*/ + +#ifndef _ROAMING_FSM_H +#define _ROAMING_FSM_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* Roaming Discovery interval, SCAN result need to be updated */ +#define ROAMING_DISCOVERY_TIMEOUT_SEC 5 // Seconds. + +//#define ROAMING_NO_SWING_RCPI_STEP 5 //rcpi +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_ROAMING_FAIL_REASON_T { + ROAMING_FAIL_REASON_CONNLIMIT = 0, + ROAMING_FAIL_REASON_NOCANDIDATE, + ROAMING_FAIL_REASON_NUM +} ENUM_ROAMING_FAIL_REASON_T; + +/* events of roaming between driver and firmware */ +typedef enum _ENUM_ROAMING_EVENT_T { + ROAMING_EVENT_START = 0, + ROAMING_EVENT_DISCOVERY, + ROAMING_EVENT_ROAM, + ROAMING_EVENT_FAIL, + ROAMING_EVENT_ABORT, + ROAMING_EVENT_NUM +} ENUM_ROAMING_EVENT_T; + +typedef struct _ROAMING_PARAM_T { + UINT_16 u2Event; + UINT_16 u2Data; +} ROAMING_PARAM_T, *P_ROAMING_PARAM_T; + +/**/ +typedef enum _ENUM_ROAMING_STATE_T { + ROAMING_STATE_IDLE = 0, + ROAMING_STATE_DECISION, + ROAMING_STATE_DISCOVERY, + ROAMING_STATE_ROAM, + ROAMING_STATE_NUM +} ENUM_ROAMING_STATE_T; + +typedef struct _ROAMING_INFO_T { + BOOLEAN fgIsEnableRoaming; + + ENUM_ROAMING_STATE_T eCurrentState; + + OS_SYSTIME rRoamingDiscoveryUpdateTime; + +} ROAMING_INFO_T, *P_ROAMING_INFO_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#if CFG_SUPPORT_ROAMING +#define IS_ROAMING_ACTIVE(prAdapter) \ + (prAdapter->rWifiVar.rRoamingInfo.eCurrentState == ROAMING_STATE_ROAM) +#else +#define IS_ROAMING_ACTIVE(prAdapter) FALSE +#endif /* CFG_SUPPORT_ROAMING */ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID +roamingFsmInit ( + IN P_ADAPTER_T prAdapter + ); + +VOID +roamingFsmUninit ( + IN P_ADAPTER_T prAdapter + ); + +VOID +roamingFsmSendCmd ( + IN P_ADAPTER_T prAdapter, + IN P_ROAMING_PARAM_T prParam + ); + +VOID +roamingFsmScanResultsUpdate ( + IN P_ADAPTER_T prAdapter + ); + +VOID +roamingFsmSteps ( + IN P_ADAPTER_T prAdapter, + IN ENUM_ROAMING_STATE_T eNextState + ); + +VOID +roamingFsmRunEventStart ( + IN P_ADAPTER_T prAdapter + ); + +VOID +roamingFsmRunEventDiscovery ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Param + ); + +VOID +roamingFsmRunEventRoam ( + IN P_ADAPTER_T prAdapter + ); + +VOID +roamingFsmRunEventFail ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Reason + ); + +VOID +roamingFsmRunEventAbort ( + IN P_ADAPTER_T prAdapter + ); + +WLAN_STATUS +roamingFsmProcessEvent ( + IN P_ADAPTER_T prAdapter, + IN P_ROAMING_PARAM_T prParam + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _ROAMING_FSM_H */ + + + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/rsn.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/rsn.h new file mode 100755 index 000000000000..5753efab4f12 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/rsn.h @@ -0,0 +1,424 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/mgmt/rsn.h#1 $ +*/ + +/*! \file rsn.h + \brief The wpa/rsn related define, macro and structure are described here. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: rsn.h $ + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 06 22 2011 wh.su + * [WCXRP00000806] [MT6620 Wi-Fi][Driver] Move the WPA/RSN IE and WAPI IE structure to mac.h and let the sw structure not align at byte + * Move the WAPI / WPA/ RSN IE structure to mac.h and some SW structure not align at byte. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 02 09 2011 wh.su + * [WCXRP00000432] [MT6620 Wi-Fi][Driver] Add STA privacy check at hotspot mode + * adding the code for check STA privacy bit at AP mode, . + * + * 11 05 2010 wh.su + * [WCXRP00000165] [MT6620 Wi-Fi] [Pre-authentication] Assoc req rsn ie use wrong pmkid value + * fixed the.pmkid value mismatch issue + * + * 10 04 2010 wh.su + * [WCXRP00000081] [MT6620][Driver] Fix the compiling error at WinXP while enable P2P + * add a kal function for set cipher. + * + * 09 01 2010 wh.su + * NULL + * adding the wapi support for integration test. + * + * 08 30 2010 wh.su + * NULL + * remove non-used code. + * + * 08 19 2010 wh.su + * NULL + * adding the tx pkt call back handle for countermeasure. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration from MT6620 firmware. + * + * 03 03 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * Fixed the pre-authentication timer not correctly init issue, and modify the security related callback function prototype. + * + * 01 27 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * add and fixed some security function. + * + * Dec 4 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adjust the function prototype for generate wap/rsn ie + * + * Dec 3 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adjust the function input parameter + * + * Dec 1 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding some event function declaration + * + * Nov 26 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * move the internal data structure for pmkid to rsn.h + * + * Nov 23 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the port control and class error function + * + * Nov 19 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the pmkid candidate + * + * Nov 18 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * +** +*/ + +#ifndef _RSN_H +#define _RSN_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* ----- Definitions for Cipher Suite Selectors ----- */ +#define RSN_CIPHER_SUITE_USE_GROUP_KEY 0x00AC0F00 +#define RSN_CIPHER_SUITE_WEP40 0x01AC0F00 +#define RSN_CIPHER_SUITE_TKIP 0x02AC0F00 +#define RSN_CIPHER_SUITE_CCMP 0x04AC0F00 +#define RSN_CIPHER_SUITE_WEP104 0x05AC0F00 +#if CFG_SUPPORT_802_11W +#define RSN_CIPHER_SUITE_AES_128_CMAC 0x06AC0F00 +#endif + +#define WPA_CIPHER_SUITE_NONE 0x00F25000 +#define WPA_CIPHER_SUITE_WEP40 0x01F25000 +#define WPA_CIPHER_SUITE_TKIP 0x02F25000 +#define WPA_CIPHER_SUITE_CCMP 0x04F25000 +#define WPA_CIPHER_SUITE_WEP104 0x05F25000 + +/* ----- Definitions for Authentication and Key Management Suite Selectors ----- */ +#define RSN_AKM_SUITE_NONE 0x00AC0F00 +#define RSN_AKM_SUITE_802_1X 0x01AC0F00 +#define RSN_AKM_SUITE_PSK 0x02AC0F00 +#if CFG_SUPPORT_802_11W +#define RSN_AKM_SUITE_802_1X_SHA256 0x05AC0F00 +#define RSN_AKM_SUITE_PSK_SHA256 0x06AC0F00 +#endif + +#define WPA_AKM_SUITE_NONE 0x00F25000 +#define WPA_AKM_SUITE_802_1X 0x01F25000 +#define WPA_AKM_SUITE_PSK 0x02F25000 + +#define ELEM_ID_RSN_LEN_FIXED 20 /* The RSN IE len for associate request */ + +#define ELEM_ID_WPA_LEN_FIXED 22 /* The RSN IE len for associate request */ + +#define MASK_RSNIE_CAP_PREAUTH BIT(0) + +#define GET_SELECTOR_TYPE(x) ((UINT_8)(((x) >> 24) & 0x000000FF)) +#define SET_SELECTOR_TYPE(x, y) x = (((x) & 0x00FFFFFF) | (((UINT_32)(y) << 24) & 0xFF000000)) + +#define AUTH_CIPHER_CCMP 0x00000008 + +/* Cihpher suite flags */ +#define CIPHER_FLAG_NONE 0x00000000 +#define CIPHER_FLAG_WEP40 0x00000001 /* BIT 1 */ +#define CIPHER_FLAG_TKIP 0x00000002 /* BIT 2 */ +#define CIPHER_FLAG_CCMP 0x00000008 /* BIT 4 */ +#define CIPHER_FLAG_WEP104 0x00000010 /* BIT 5 */ +#define CIPHER_FLAG_WEP128 0x00000020 /* BIT 6 */ + +#define WAIT_TIME_IND_PMKID_CANDICATE_SEC 6 /* seconds */ +#define TKIP_COUNTERMEASURE_SEC 60 /* seconds */ + +#if CFG_SUPPORT_802_11W +#define RSN_AUTH_MFP_DISABLED 0 /* MFP disabled */ +#define RSN_AUTH_MFP_OPTIONAL 1 /* MFP optional */ +#define RSN_AUTH_MFP_REQUIRED 2 /* MFP required */ +#endif + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/* Flags for PMKID Candidate list structure */ +#define EVENT_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01 + + +#define CONTROL_FLAG_UC_MGMT_NO_ENC BIT(5) + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define RSN_IE(fp) ((P_RSN_INFO_ELEM_T) fp) +#define WPA_IE(fp) ((P_WPA_INFO_ELEM_T) fp) + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +BOOLEAN +rsnParseRsnIE( + IN P_ADAPTER_T prAdapter, + IN P_RSN_INFO_ELEM_T prInfoElem, + OUT P_RSN_INFO_T prRsnInfo + ); + +BOOLEAN +rsnParseWpaIE( + IN P_ADAPTER_T prAdapter, + IN P_WPA_INFO_ELEM_T prInfoElem, + OUT P_RSN_INFO_T prWpaInfo + ); + +BOOLEAN +rsnSearchSupportedCipher( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Cipher, + OUT PUINT_32 pu4Index + ); + +BOOLEAN +rsnSearchAKMSuite( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4AkmSuite, + OUT PUINT_32 pu4Index + ); + +BOOLEAN +rsnPerformPolicySelection( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBss + ); + +VOID +rsnGenerateWpaNoneIE( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + +VOID +rsnGenerateWPAIE( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + +VOID +rsnGenerateRSNIE( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + +BOOLEAN +rsnParseCheckForWFAInfoElem( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucBuf, + OUT PUINT_8 pucOuiType, + OUT PUINT_16 pu2SubTypeVersion + ); + +#if CFG_SUPPORT_AAA +void +rsnParserCheckForRSNCCMPPSK ( + P_ADAPTER_T prAdapter, + P_RSN_INFO_ELEM_T prIe, + PUINT_16 pu2StatusCode + ); +#endif + +VOID +rsnTkipHandleMICFailure( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta, + IN BOOLEAN fgErrorKeyType + ); + +VOID +rsnSelectPmkidCandidateList( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc + ); + +VOID +rsnUpdatePmkidCandidateList( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc + ); + +BOOLEAN +rsnSearchPmkidEntry( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucBssid, + OUT PUINT_32 pu4EntryIndex + ); + +BOOLEAN +rsnCheckPmkidCandicate( + IN P_ADAPTER_T prAdapter + ); + +VOID +rsnCheckPmkidCache( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBss + ); + +VOID +rsnGeneratePmkidIndication( + IN P_ADAPTER_T prAdapter + ); + +VOID +rsnIndicatePmkidCand( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Parm + ); +#if CFG_SUPPORT_WPS2 +VOID +rsnGenerateWSCIE( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); +#endif + +#if CFG_SUPPORT_802_11W +UINT_32 +rsnCheckBipKeyInstalled( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ); + +UINT_8 +rsnCheckSaQueryTimeout( + IN P_ADAPTER_T prAdapter + ); + +void +rsnStartSaQueryTimer( + IN P_ADAPTER_T prAdapter + ); + +void +rsnStartSaQuery( + IN P_ADAPTER_T prAdapter + ); + +void +rsnStopSaQuery( + IN P_ADAPTER_T prAdapter + ); + +void +rsnSaQueryRequest( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + +void +rsnSaQueryAction( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + +BOOLEAN +rsnCheckRxMgmt( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN UINT_8 ucSubtype + ); +#endif +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _RSN_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/scan.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/scan.h new file mode 100755 index 000000000000..1d6e4eb07903 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/scan.h @@ -0,0 +1,896 @@ +/* +** $Id: @(#) +*/ + +/*! \file "scan.h" + \brief + +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: scan.h $ + * + * 01 16 2012 cp.wu + * [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band configuration with corresponding network configuration + * add wlanSetPreferBandByNetwork() for glue layer to invoke for setting preferred band configuration corresponding to network type. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 08 11 2011 cp.wu + * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time + * sparse channel detection: + * driver: collect sparse channel information with scan-done event + + * + * 07 18 2011 cp.wu + * [WCXRP00000858] [MT5931][Driver][Firmware] Add support for scan to search for more than one SSID in a single scanning request + * add framework in driver domain for supporting new SCAN_REQ_V2 for more than 1 SSID support as well as uProbeDelay in NDIS 6.x driver model + * + * 06 27 2011 cp.wu + * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID settings to work around some tricky AP which use space character as hidden SSID + * allow to have a single BSSID with multiple SSID to be presented in scanning result + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 02 09 2011 wh.su + * [WCXRP00000433] [MT6620 Wi-Fi][Driver] Remove WAPI structure define for avoid P2P module with structure miss-align pointer issue + * always pre-allio WAPI related structure for align p2p module. + * + * 01 14 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Fix compile error. + * + * 09 08 2010 cp.wu + * NULL + * use static memory pool for storing IEs of scanning result. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 31 2010 kevin.huang + * NULL + * Use LINK LIST operation to process SCAN result + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 16 2010 cp.wu + * NULL + * add interface for RLM to trigger OBSS-SCAN. + * + * 08 12 2010 yuche.tsai + * NULL + * Add a functio prototype to find p2p descriptor of a bss descriptor directly. + * + * 08 11 2010 yuche.tsai + * NULL + * Add function prototype for return channel. + * modify data structure for scan specific device ID or TYPE. (Move from P2P Connection Settings to Scan Param) + * + * 08 05 2010 yuche.tsai + * NULL + * Check-in P2P Device Discovery Feature. + * + * 08 02 2010 yuche.tsai + * NULL + * P2P Group Negotiation Code Check in. + * + * 07 26 2010 yuche.tsai + * + * Add a option for channel time extention in scan abort command. + * + * 07 21 2010 yuche.tsai + * + * Add for P2P Scan Result Parsing & Saving. + * + * 07 19 2010 yuche.tsai + * + * Scan status "FIND" is used for P2P FSM find state. + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * SCN module is now able to handle multiple concurrent scanning requests + * + * 07 14 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * pass band with channel number information as scan parameter + * + * 07 14 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * remove timer in DRV-SCN. + * + * 07 09 2010 cp.wu + * + * 1) separate AIS_FSM state for two kinds of scanning. (OID triggered scan, and scan-for-connection) + * 2) eliminate PRE_BSS_DESC_T, Beacon/PrebResp is now parsed in single pass + * 3) implment DRV-SCN module, currently only accepts single scan request, other request will be directly dropped by returning BUSY + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add scan uninitialization procedure + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implementation of DRV-SCN and related mailbox message handling. + * + * 06 25 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * modify Beacon/ProbeResp to complete parsing, + * because host software has looser memory usage restriction + * + * 06 17 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Add P2P related field in SCAN_PARAM_T. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * saa_fsm.c is migrated. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add management dispatching function table. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * restore utility function invoking via hem_mbox to direct calls + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * auth.c is migrated. + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add buildable & linkable ais_fsm.c + * + * related reference are still waiting to be resolved + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 04 13 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * + * Add new HW CH macro support + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 03 10 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * + * * * * * * Add Channel Manager for arbitration of JOIN and SCAN Req + * + * 02 26 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Modify scanBuildProbeReqFrameCommonIEs() to support P2P SCAN + * + * 02 23 2010 wh.su + * [BORA00000592][MT6620 Wi-Fi] Adding the security related code for driver + * refine the scan procedure, reduce the WPA and WAPI IE parsing, and move the parsing to the time for join. + * + * 02 23 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add support scan channel 1~14 and update scan result's frequency infou1rwduu`wvpghlqg|n`slk+mpdkb + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * 01 27 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * add and fixed some security function. + * + * 01 07 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * Simplify the process of Beacon during SCAN and remove redundant variable in PRE_BSS_DESC_T + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding variable for wapi ap + * + * Dec 4 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * remove non-used secuirty variavle + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Refine data structure of BSS_DESC_T and PRE_BSS_DESC_T + * + * Nov 24 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add eNetType to rScanParam and revise MGMT Handler with Retain Status + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add ucAvailablePhyTypeSet to BSS_DESC_T + * + * Nov 20 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add aucSrcAddress to SCAN_PARAM_T for P2P's Device Address + * + * Nov 19 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the security related variable + * + * Nov 18 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the security ie filed for scan parsing + * + * Nov 16 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add scanSearchBssDescByPolicy() + * + * Nov 5 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add function declarations of scan_fsm.c + * + * Oct 30 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add scan.h to source control +** +*/ + +#ifndef _SCAN_H +#define _SCAN_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/*! Maximum buffer size of SCAN list */ +#define SCN_MAX_BUFFER_SIZE (CFG_MAX_NUM_BSS_LIST * ALIGN_4(sizeof(BSS_DESC_T))) + +#define SCN_RM_POLICY_EXCLUDE_CONNECTED BIT(0) // Remove SCAN result except the connected one. +#define SCN_RM_POLICY_TIMEOUT BIT(1) // Remove the timeout one +#define SCN_RM_POLICY_OLDEST_HIDDEN BIT(2) // Remove the oldest one with hidden ssid +#define SCN_RM_POLICY_SMART_WEAKEST BIT(3) /* If there are more than half BSS which has the + * same ssid as connection setting, remove the weakest one from them + * Else remove the weakest one. + */ +#define SCN_RM_POLICY_ENTIRE BIT(4) // Remove entire SCAN result + +#define SCN_BSS_DESC_SAME_SSID_THRESHOLD 3 /* This is used by POLICY SMART WEAKEST, + * If exceed this value, remove weakest BSS_DESC_T + * with same SSID first in large network. + */ + +#define SCN_BSS_DESC_REMOVE_TIMEOUT_SEC 5 // Second. + /* This is used by POLICY TIMEOUT, + * If exceed this value, remove timeout BSS_DESC_T. + */ + + + + +#define SCN_PROBE_DELAY_MSEC 0 + +#define SCN_ADHOC_BSS_DESC_TIMEOUT_SEC 5 // Second. + +/*----------------------------------------------------------------------------*/ +/* MSG_SCN_SCAN_REQ */ +/*----------------------------------------------------------------------------*/ +#define SCAN_REQ_SSID_WILDCARD BIT(0) +#define SCAN_REQ_SSID_P2P_WILDCARD BIT(1) +#define SCAN_REQ_SSID_SPECIFIED BIT(2) + + +/*----------------------------------------------------------------------------*/ +/* Support Multiple SSID SCAN */ +/*----------------------------------------------------------------------------*/ +#define SCN_SSID_MAX_NUM 4 + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_SCAN_TYPE_T { + SCAN_TYPE_PASSIVE_SCAN = 0, + SCAN_TYPE_ACTIVE_SCAN, + SCAN_TYPE_NUM +} ENUM_SCAN_TYPE_T, *P_ENUM_SCAN_TYPE_T; + +typedef enum _ENUM_SCAN_STATE_T { + SCAN_STATE_IDLE = 0, + SCAN_STATE_SCANNING, + SCAN_STATE_NUM +} ENUM_SCAN_STATE_T; + +typedef enum _ENUM_SCAN_CHANNEL_T { + SCAN_CHANNEL_FULL = 0, + SCAN_CHANNEL_2G4, + SCAN_CHANNEL_5G, + SCAN_CHANNEL_P2P_SOCIAL, + SCAN_CHANNEL_SPECIFIED, + SCAN_CHANNEL_NUM +} ENUM_SCAN_CHANNEL, *P_ENUM_SCAN_CHANNEL; + +typedef struct _MSG_SCN_FSM_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_32 u4Dummy; +} MSG_SCN_FSM_T, *P_MSG_SCN_FSM_T; + + + +/*----------------------------------------------------------------------------*/ +/* BSS Descriptors */ +/*----------------------------------------------------------------------------*/ +struct _BSS_DESC_T { + LINK_ENTRY_T rLinkEntry; + + UINT_8 aucBSSID[MAC_ADDR_LEN]; + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* For IBSS, the SrcAddr is different from BSSID */ + + BOOLEAN fgIsConnecting; /* If we are going to connect to this BSS + * (JOIN or ROAMING to another BSS), don't + * remove this record from BSS List. + */ + BOOLEAN fgIsConnected; /* If we have connected to this BSS (NORMAL_TR), + * don't removed this record from BSS list. + */ + + BOOLEAN fgIsHiddenSSID; /* When this flag is TRUE, means the SSID + * of this BSS is not known yet. + */ + UINT_8 ucSSIDLen; + UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; + + OS_SYSTIME rUpdateTime; + + ENUM_BSS_TYPE_T eBSSType; + + UINT_16 u2CapInfo; + + UINT_16 u2BeaconInterval; + UINT_16 u2ATIMWindow; + + UINT_16 u2OperationalRateSet; + UINT_16 u2BSSBasicRateSet; + BOOLEAN fgIsUnknownBssBasicRate; + + BOOLEAN fgIsERPPresent; + BOOLEAN fgIsHTPresent; + + UINT_8 ucPhyTypeSet; /* Available PHY Type Set of this BSS */ + + UINT_8 ucChannelNum; + + ENUM_CHNL_EXT_T eSco; /* Record bandwidth for association process + Some AP will send association resp by 40MHz BW */ + ENUM_BAND_T eBand; + + UINT_8 ucDTIMPeriod; + + BOOLEAN fgIsLargerTSF; /* This BSS's TimeStamp is larger than us(TCL == 1 in RX_STATUS_T) */ + + UINT_8 ucRCPI; + + UINT_8 ucWmmFlag; /* A flag to indicate this BSS's WMM capability */ + + /*! \brief The srbiter Search State will matched the scan result, + and saved the selected cipher and akm, and report the score, + for arbiter join state, join module will carry this target BSS + to rsn generate ie function, for gen wpa/rsn ie */ + UINT_32 u4RsnSelectedGroupCipher; + UINT_32 u4RsnSelectedPairwiseCipher; + UINT_32 u4RsnSelectedAKMSuite; + + UINT_16 u2RsnCap; + + RSN_INFO_T rRSNInfo; + RSN_INFO_T rWPAInfo; +#if 1//CFG_SUPPORT_WAPI + WAPI_INFO_T rIEWAPI; + BOOL fgIEWAPI; +#endif + BOOL fgIERSN; + BOOL fgIEWPA; + + /*! \brief RSN parameters selected for connection */ + /*! \brief The Select score for final AP selection, + 0, no sec, 1,2,3 group cipher is WEP, TKIP, CCMP */ + UINT_8 ucEncLevel; + +#if CFG_ENABLE_WIFI_DIRECT + BOOLEAN fgIsP2PPresent; + P_P2P_DEVICE_DESC_T prP2pDesc; + + UINT_8 aucIntendIfAddr[MAC_ADDR_LEN]; /* For IBSS, the SrcAddr is different from BSSID */ +// UINT_8 ucDevCapabilityBitmap; /* Device Capability Attribute. (P2P_DEV_CAPABILITY_XXXX) */ +// UINT_8 ucGroupCapabilityBitmap; /* Group Capability Attribute. (P2P_GROUP_CAPABILITY_XXXX) */ + + LINK_T rP2pDeviceList; + +// P_LINK_T prP2pDeviceList; + + /* For + * 1. P2P Capability. + * 2. P2P Device ID. ( in aucSrcAddr[] ) + * 3. NOA (TODO:) + * 4. Extend Listen Timing. (Probe Rsp) (TODO:) + * 5. P2P Device Info. (Probe Rsp) + * 6. P2P Group Info. (Probe Rsp) + */ +#endif + + BOOLEAN fgIsIEOverflow; /* The received IE length exceed the maximum IE buffer size */ + UINT_16 u2IELength; /* The byte count of aucIEBuf[] */ + + ULARGE_INTEGER u8TimeStamp; /* Place u8TimeStamp before aucIEBuf[1] to force DW align */ + + UINT_8 aucIEBuf[CFG_IE_BUFFER_SIZE]; +}; + + +typedef struct _SCAN_PARAM_T { /* Used by SCAN FSM */ + /* Active or Passive */ + ENUM_SCAN_TYPE_T eScanType; + + /* Network Type */ + ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex; + + /* Specified SSID Type */ + UINT_8 ucSSIDType; + UINT_8 ucSSIDNum; + + /* Length of Specified SSID */ + UINT_8 ucSpecifiedSSIDLen[SCN_SSID_MAX_NUM]; + + /* Specified SSID */ + UINT_8 aucSpecifiedSSID[SCN_SSID_MAX_NUM][ELEM_MAX_LEN_SSID]; + +#if CFG_ENABLE_WIFI_DIRECT + BOOLEAN fgFindSpecificDev; /* P2P: Discovery Protocol */ + UINT_8 aucDiscoverDevAddr[MAC_ADDR_LEN]; + BOOLEAN fgIsDevType; + P2P_DEVICE_TYPE_T rDiscoverDevType; + + UINT_16 u2PassiveListenInterval; + // TODO: Find Specific Device Type. +#endif /* CFG_SUPPORT_P2P */ + + BOOLEAN fgIsObssScan; + BOOLEAN fgIsScanV2; + + /* Run time flags */ + UINT_16 u2ProbeDelayTime; + + /* channel information */ + ENUM_SCAN_CHANNEL eScanChannel; + UINT_8 ucChannelListNum; + RF_CHANNEL_INFO_T arChnlInfoList[MAXIMUM_OPERATION_CHANNEL_LIST]; + + /* Feedback information */ + UINT_8 ucSeqNum; + + /* Information Element */ + UINT_16 u2IELen; + UINT_8 aucIE[MAX_IE_LENGTH]; + +} SCAN_PARAM_T, *P_SCAN_PARAM_T; + +typedef struct _SCAN_INFO_T { + ENUM_SCAN_STATE_T eCurrentState; /* Store the STATE variable of SCAN FSM */ + + OS_SYSTIME rLastScanCompletedTime; + + SCAN_PARAM_T rScanParam; + + UINT_32 u4NumOfBssDesc; + + UINT_8 aucScanBuffer[SCN_MAX_BUFFER_SIZE]; + + LINK_T rBSSDescList; + + LINK_T rFreeBSSDescList; + + LINK_T rPendingMsgList; + + /* Sparse Channel Detection */ + BOOLEAN fgIsSparseChannelValid; + RF_CHANNEL_INFO_T rSparseChannel; + +} SCAN_INFO_T, *P_SCAN_INFO_T; + + +/* Incoming Mailbox Messages */ +typedef struct _MSG_SCN_SCAN_REQ_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucSeqNum; + UINT_8 ucNetTypeIndex; + ENUM_SCAN_TYPE_T eScanType; + UINT_8 ucSSIDType; /* BIT(0) wildcard / BIT(1) P2P-wildcard / BIT(2) specific */ + UINT_8 ucSSIDLength; + UINT_8 aucSSID[PARAM_MAX_LEN_SSID]; +#if CFG_ENABLE_WIFI_DIRECT + UINT_16 u2ChannelDwellTime; /* In TU. 1024us. */ +#endif + ENUM_SCAN_CHANNEL eScanChannel; + UINT_8 ucChannelListNum; + RF_CHANNEL_INFO_T arChnlInfoList[MAXIMUM_OPERATION_CHANNEL_LIST]; + UINT_16 u2IELen; + UINT_8 aucIE[MAX_IE_LENGTH]; +} MSG_SCN_SCAN_REQ, *P_MSG_SCN_SCAN_REQ; + +typedef struct _MSG_SCN_SCAN_REQ_V2_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucSeqNum; + UINT_8 ucNetTypeIndex; + ENUM_SCAN_TYPE_T eScanType; + UINT_8 ucSSIDType; /* BIT(0) wildcard / BIT(1) P2P-wildcard / BIT(2) specific */ + UINT_8 ucSSIDNum; + P_PARAM_SSID_T prSsid; + UINT_16 u2ProbeDelay; + UINT_16 u2ChannelDwellTime; /* In TU. 1024us. */ + ENUM_SCAN_CHANNEL eScanChannel; + UINT_8 ucChannelListNum; + RF_CHANNEL_INFO_T arChnlInfoList[MAXIMUM_OPERATION_CHANNEL_LIST]; + UINT_16 u2IELen; + UINT_8 aucIE[MAX_IE_LENGTH]; +} MSG_SCN_SCAN_REQ_V2, *P_MSG_SCN_SCAN_REQ_V2; + + +typedef struct _MSG_SCN_SCAN_CANCEL_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucSeqNum; + UINT_8 ucNetTypeIndex; +#if CFG_ENABLE_WIFI_DIRECT + BOOLEAN fgIsChannelExt; +#endif +} MSG_SCN_SCAN_CANCEL, *P_MSG_SCN_SCAN_CANCEL; + +/* Outgoing Mailbox Messages */ +typedef enum _ENUM_SCAN_STATUS_T { + SCAN_STATUS_DONE = 0, + SCAN_STATUS_CANCELLED, + SCAN_STATUS_FAIL, + SCAN_STATUS_BUSY, + SCAN_STATUS_NUM +} ENUM_SCAN_STATUS, *P_ENUM_SCAN_STATUS; + +typedef struct _MSG_SCN_SCAN_DONE_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucSeqNum; + UINT_8 ucNetTypeIndex; + ENUM_SCAN_STATUS eScanStatus; +} MSG_SCN_SCAN_DONE, *P_MSG_SCN_SCAN_DONE; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Routines in scan.c */ +/*----------------------------------------------------------------------------*/ +VOID +scnInit ( + IN P_ADAPTER_T prAdapter + ); + +VOID +scnUninit ( + IN P_ADAPTER_T prAdapter + ); + +/* BSS-DESC Search */ +P_BSS_DESC_T +scanSearchBssDescByBssid ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 aucBSSID[] + ); + +P_BSS_DESC_T +scanSearchBssDescByBssidAndSsid ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 aucBSSID[], + IN BOOLEAN fgCheckSsid, + IN P_PARAM_SSID_T prSsid + ); + +P_BSS_DESC_T +scanSearchBssDescByTA ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 aucSrcAddr[] + ); + +P_BSS_DESC_T +scanSearchBssDescByTAAndSsid ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 aucSrcAddr[], + IN BOOLEAN fgCheckSsid, + IN P_PARAM_SSID_T prSsid + ); + + +/* BSS-DESC Search - Alternative */ +P_BSS_DESC_T +scanSearchExistingBssDesc ( + IN P_ADAPTER_T prAdapter, + IN ENUM_BSS_TYPE_T eBSSType, + IN UINT_8 aucBSSID[], + IN UINT_8 aucSrcAddr[] + ); + +P_BSS_DESC_T +scanSearchExistingBssDescWithSsid ( + IN P_ADAPTER_T prAdapter, + IN ENUM_BSS_TYPE_T eBSSType, + IN UINT_8 aucBSSID[], + IN UINT_8 aucSrcAddr[], + IN BOOLEAN fgCheckSsid, + IN P_PARAM_SSID_T prSsid + ); + + +/* BSS-DESC Allocation */ +P_BSS_DESC_T +scanAllocateBssDesc ( + IN P_ADAPTER_T prAdapter + ); + +/* BSS-DESC Removal */ +VOID +scanRemoveBssDescsByPolicy ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4RemovePolicy + ); + +VOID +scanRemoveBssDescByBssid ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 aucBSSID[] + ); + +VOID +scanRemoveBssDescByBandAndNetwork ( + IN P_ADAPTER_T prAdapter, + IN ENUM_BAND_T eBand, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex + ); + +/* BSS-DESC State Change */ +VOID +scanRemoveConnFlagOfBssDescByBssid ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 aucBSSID[] + ); + +#if 0 +/* BSS-DESC Insertion */ +P_BSS_DESC_T +scanAddToInternalScanResult ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSWRfb, + IN P_BSS_DESC_T prBssDesc + ); +#endif + +/* BSS-DESC Insertion - ALTERNATIVE */ +P_BSS_DESC_T +scanAddToBssDesc ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + +WLAN_STATUS +scanProcessBeaconAndProbeResp ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSWRfb + ); + +VOID +scanBuildProbeReqFrameCommonIEs ( + IN P_MSDU_INFO_T prMsduInfo, + IN PUINT_8 pucDesiredSsid, + IN UINT_32 u4DesiredSsidLen, + IN UINT_16 u2SupportedRateSet + ); + +WLAN_STATUS +scanSendProbeReqFrames ( + IN P_ADAPTER_T prAdapter, + IN P_SCAN_PARAM_T prScanParam + ); + +VOID +scanUpdateBssDescForSearch ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc + ); + +P_BSS_DESC_T +scanSearchBssDescByPolicy ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex + ); + +WLAN_STATUS +scanAddScanResult ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc, + IN P_SW_RFB_T prSwRfb + ); + +/*----------------------------------------------------------------------------*/ +/* Routines in scan_fsm.c */ +/*----------------------------------------------------------------------------*/ +VOID +scnFsmSteps ( + IN P_ADAPTER_T prAdapter, + IN ENUM_SCAN_STATE_T eNextState + ); + +/*----------------------------------------------------------------------------*/ +/* Command Routines */ +/*----------------------------------------------------------------------------*/ +VOID +scnSendScanReq ( + IN P_ADAPTER_T prAdapter + ); + +VOID +scnSendScanReqV2 ( + IN P_ADAPTER_T prAdapter + ); + +/*----------------------------------------------------------------------------*/ +/* RX Event Handling */ +/*----------------------------------------------------------------------------*/ +VOID +scnEventScanDone( + IN P_ADAPTER_T prAdapter, + IN P_EVENT_SCAN_DONE prScanDone + ); + +/*----------------------------------------------------------------------------*/ +/* Mailbox Message Handling */ +/*----------------------------------------------------------------------------*/ +VOID +scnFsmMsgStart ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + +VOID +scnFsmMsgAbort ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + +VOID +scnFsmHandleScanMsg ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_SCN_SCAN_REQ prScanReqMsg + ); + +VOID +scnFsmHandleScanMsgV2 ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_SCN_SCAN_REQ_V2 prScanReqMsg + ); + +VOID +scnFsmRemovePendingMsg ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucSeqNum, + IN UINT_8 ucNetTypeIndex + ); + +/*----------------------------------------------------------------------------*/ +/* Mailbox Message Generation */ +/*----------------------------------------------------------------------------*/ +VOID +scnFsmGenerateScanDoneMsg ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucSeqNum, + IN UINT_8 ucNetTypeIndex, + IN ENUM_SCAN_STATUS eScanStatus + ); + +/*----------------------------------------------------------------------------*/ +/* Query for sparse channel */ +/*----------------------------------------------------------------------------*/ +BOOLEAN +scnQuerySparseChannel ( + IN P_ADAPTER_T prAdapter, + P_ENUM_BAND_T prSparseBand, + PUINT_8 pucSparseChannel + ); + + +#endif /* _SCAN_H */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/sec_fsm.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/sec_fsm.h new file mode 100755 index 000000000000..e887cff4115a --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/sec_fsm.h @@ -0,0 +1,328 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/mgmt/sec_fsm.h#1 $ +*/ + +/*! \file sec_fsm.h + \brief Declaration of functions and finite state machine for SECURITY Module. + + Function declaration for privacy.c and SEC_STATE for SECURITY FSM. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: sec_fsm.h $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 09 29 2010 wh.su + * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue + * [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue. + * + * 09 21 2010 kevin.huang + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * Eliminate Linux Compile Warning + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 20 2010 wh.su + * NULL + * adding the eapol callback setting. + * + * 08 19 2010 wh.su + * NULL + * adding the tx pkt call back handle for countermeasure. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * modify some code for concurrent network. + * + * 06 19 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * consdier the concurrent network setting. + * + * 03 04 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * Code refine, and remove non-used code. + * + * 03 03 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * Fixed the pre-authentication timer not correctly init issue, and modify the security related callback function prototype. + * + * 03 01 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * Refine the variable and parameter for security. + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * fixed the deauth Tx done callback parameter + * + * Dec 4 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the reference function declaration + * + * Dec 3 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * delete non-used code + * + * Dec 1 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adjust the function prototype + * + * Nov 23 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adjust the function declaration + * + * Nov 19 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the security variable + * + * Nov 18 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * +** \main\maintrunk.MT5921\14 2009-04-06 15:35:47 GMT mtk01088 +** add the variable to set the disable AP selection for privacy check, for wps open networking. +** \main\maintrunk.MT5921\13 2008-11-19 11:46:01 GMT mtk01088 +** rename some variable with pre-fix to avoid the misunderstanding +** \main\maintrunk.MT5921\12 2008-08-28 20:37:11 GMT mtk01088 +** remove non-used code +** +** \main\maintrunk.MT5921\11 2008-03-18 09:51:52 GMT mtk01088 +** Add function declaration for timer to indicate pmkid candidate +** \main\maintrunk.MT5921\10 2008-02-29 15:12:08 GMT mtk01088 +** add variable for sw port control +** \main\maintrunk.MT5921\9 2008-02-29 12:37:30 GMT mtk01088 +** rename the security related function declaration +** \main\maintrunk.MT5921\8 2007-12-27 13:59:08 GMT mtk01088 +** adjust the wlan table and sec fsm init timing +** \main\maintrunk.MT5921\7 2007-11-20 10:39:49 GMT mtk01088 +** add function timer for wait EAPoL Error timeout +** \main\maintrunk.MT5921\6 2007-11-06 20:39:08 GMT mtk01088 +** rename the counter measure timer +** \main\maintrunk.MT5921\5 2007-11-06 20:14:31 GMT mtk01088 +** add a abort function +** Revision 1.5 2007/07/16 02:33:42 MTK01088 +** change the ENUM declaration structure prefix from r to e +** +** Revision 1.4 2007/07/09 06:23:10 MTK01088 +** update +** +** Revision 1.3 2007/07/04 10:09:04 MTK01088 +** adjust the state for security fsm +** change function name +** +** Revision 1.2 2007/07/03 08:13:22 MTK01088 +** change the sec fsm state +** add the event for sec fsm +** +** Revision 1.1 2007/06/27 06:20:35 MTK01088 +** add the sec fsm header file +** +** +*/ +#ifndef _SEC_FSM_H +#define _SEC_FSM_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/* TKIP CounterMeasure interval for Rejoin to Network. */ +#define COUNTER_MEASURE_TIMEOUT_INTERVAL_SEC 60 + +/* Timeout to wait the EAPoL Error Report frame Send out. */ +#define EAPOL_REPORT_SEND_TIMEOUT_INTERVAL_SEC 1 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef UINT_32 SEC_STATUS, *P_SEC_STATUS; + +#if 0 +/* WPA2 PMKID candicate structure */ +typedef struct _PMKID_CANDICATE_T { + UINT_8 aucBssid[MAC_ADDR_LEN]; /* MAC address */ + UINT_32 u4PreAuthFlags; +} PMKID_CANDICATE_T, *P_PMKID_CANDICATE_T; +#endif + +typedef SEC_STATUS (*PFN_SEC_FSM_STATE_HANDLER)(VOID); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define SEC_STATE_TRANSITION_FLAG fgIsTransition +#define SEC_NEXT_STATE_VAR eNextState + +#define SEC_STATE_TRANSITION(prAdapter, prSta, eFromState, eToState) \ + { secFsmTrans_ ## eFromState ## _to_ ## eToState(prAdapter, prSta); \ + SEC_NEXT_STATE_VAR = SEC_STATE_ ## eToState; \ + SEC_STATE_TRANSITION_FLAG = (BOOLEAN)TRUE; \ + } + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/*--------------------------------------------------------------*/ +/* Routines to handle the sec check */ +/*--------------------------------------------------------------*/ +/***** Routines in sec_fsm.c *****/ +VOID +secFsmInit( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ); + +VOID +secFsmEventInit( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ); + +VOID +secFsmEventStart( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ); + +VOID +secFsmEventAbort( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ); + +BOOLEAN +secFsmEventPTKInstalled( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ); + +VOID +secFsmEvent2ndEapolTx( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ); + +VOID +secFsmEvent4ndEapolTxDone( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ); + +VOID +secFsmEventEapolTxDone ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus + ); + +VOID +secFsmEventEapolTxTimeout ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Parm + ); + +VOID +secFsmEventDeauthTxDone( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus + ); + +VOID +secFsmEventStartCounterMeasure( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ); + +VOID +secFsmEventEndOfCounterMeasure( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Parm + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#endif /* _SEC_FSM_H */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/swcr.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/swcr.h new file mode 100755 index 000000000000..4afb42d358df --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/swcr.h @@ -0,0 +1,220 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/mgmt/swcr.h#1 $ +*/ + +/*! \file "swcr.h" + \brief +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* + * + */ + +#ifndef _SWCR_H +#define _SWCR_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define SWCR_VAR(x) ((VOID *)&x) +#define SWCR_FUNC(x) ((VOID *)x) + +#define SWCR_T_FUNC BIT(7) + +#define SWCR_L_32 3 +#define SWCR_L_16 2 +#define SWCR_L_8 1 + +#define SWCR_READ 0 +#define SWCR_WRITE 1 + +#define SWCR_MAP_NUM(x) (sizeof(x)/sizeof(x[0])) + +#define SWCR_CR_NUM 7 + +#define SWCR_GET_RW_INDEX(action,rw,index) \ + index = action & 0x7F; \ + rw = action >> 7; + + +extern UINT_32 g_au4SwCr[]; /*: 0: command other: data */ + +typedef VOID (*PFN_SWCR_RW_T)(P_ADAPTER_T prAdapter, UINT_8 ucRead, UINT_16 u2Addr, UINT_32 *pu4Data); +typedef VOID (*PFN_CMD_RW_T)(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0,UINT_8 ucOpt1); + +typedef struct _SWCR_MAP_ENTRY_T { + UINT_16 u2Type; + PVOID u4Addr; +} SWCR_MAP_ENTRY_T, *P_SWCR_MAP_ENTRY_T; + + +typedef struct _SWCR_MOD_MAP_ENTRY_T { + UINT_8 ucMapNum; + P_SWCR_MAP_ENTRY_T prSwCrMap; +} SWCR_MOD_MAP_ENTRY_T, *P_SWCR_MOD_MAP_ENTRY_T; + +typedef enum _ENUM_SWCR_DBG_TYPE_T { + SWCR_DBG_TYPE_ALL = 0, + SWCR_DBG_TYPE_TXRX, + SWCR_DBG_TYPE_RX_RATES, + SWCR_DBG_TYPE_PS, + SWCR_DBG_TYPE_NUM +} ENUM_SWCR_DBG_TYPE_T; + +typedef enum _ENUM_SWCR_DBG_ALL_T { + SWCR_DBG_ALL_TX_CNT = 0, + SWCR_DBG_ALL_TX_BCN_CNT, + SWCR_DBG_ALL_TX_FAILED_CNT, + SWCR_DBG_ALL_TX_RETRY_CNT, + SWCR_DBG_ALL_TX_AGING_TIMEOUT_CNT, + SWCR_DBG_ALL_TX_PS_OVERFLOW_CNT, + SWCR_DBG_ALL_TX_MGNT_DROP_CNT, + SWCR_DBG_ALL_TX_ERROR_CNT, + + SWCR_DBG_ALL_RX_CNT, + SWCR_DBG_ALL_RX_DROP_CNT, + SWCR_DBG_ALL_RX_DUP_DROP_CNT, + SWCR_DBG_ALL_RX_TYPE_ERROR_DROP_CNT, + SWCR_DBG_ALL_RX_CLASS_ERROR_DROP_CNT, + SWCR_DBG_ALL_RX_AMPDU_ERROR_DROP_CNT, + + SWCR_DBG_ALL_RX_STATUS_ERROR_DROP_CNT, + SWCR_DBG_ALL_RX_FORMAT_ERROR_DROP_CNT, + SWCR_DBG_ALL_RX_ICV_ERROR_DROP_CNT, + SWCR_DBG_ALL_RX_KEY_ERROR_DROP_CNT, + SWCR_DBG_ALL_RX_TKIP_ERROR_DROP_CNT, + SWCR_DBG_ALL_RX_MIC_ERROR_DROP_CNT, + SWCR_DBG_ALL_RX_BIP_ERROR_DROP_CNT, + + SWCR_DBG_ALL_RX_FCSERR_CNT, + SWCR_DBG_ALL_RX_FIFOFULL_CNT, + SWCR_DBG_ALL_RX_PFDROP_CNT, + + SWCR_DBG_ALL_PWR_PS_POLL_CNT, + SWCR_DBG_ALL_PWR_TRIGGER_NULL_CNT, + SWCR_DBG_ALL_PWR_BCN_IND_CNT, + SWCR_DBG_ALL_PWR_BCN_TIMEOUT_CNT, + SWCR_DBG_ALL_PWR_PM_STATE0, + SWCR_DBG_ALL_PWR_PM_STATE1, + SWCR_DBG_ALL_PWR_CUR_PS_PROF0, + SWCR_DBG_ALL_PWR_CUR_PS_PROF1, + + SWCR_DBG_ALL_AR_STA0_RATE, + SWCR_DBG_ALL_AR_STA0_BWGI, + SWCR_DBG_ALL_AR_STA0_RX_RATE_RCPI, + + SWCR_DBG_ALL_ROAMING_ENABLE, + SWCR_DBG_ALL_ROAMING_ROAM_CNT, + SWCR_DBG_ALL_ROAMING_INT_CNT, + + SWCR_DBG_ALL_BB_RX_MDRDY_CNT, + SWCR_DBG_ALL_BB_RX_FCSERR_CNT, + SWCR_DBG_ALL_BB_CCK_PD_CNT, + SWCR_DBG_ALL_BB_OFDM_PD_CNT, + SWCR_DBG_ALL_BB_CCK_SFDERR_CNT, + SWCR_DBG_ALL_BB_CCK_SIGERR_CNT, + SWCR_DBG_ALL_BB_OFDM_TAGERR_CNT, + SWCR_DBG_ALL_BB_OFDM_SIGERR_CNT, + + SWCR_DBG_ALL_NUM +} ENUM_SWCR_DBG_ALL_T; + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +VOID swCrReadWriteCmd( + P_ADAPTER_T prAdapter, + UINT_8 ucRead, + UINT_16 u2Addr, + UINT_32 *pu4Data + ); + +/* Debug Support */ +VOID swCrFrameCheckEnable(P_ADAPTER_T prAdapter, UINT_32 u4DumpType); +VOID swCrDebugInit(P_ADAPTER_T prAdapter); +VOID swCrDebugCheckEnable(P_ADAPTER_T prAdapter, BOOLEAN fgIsEnable, UINT_8 ucType, UINT_32 u4Timeout); +VOID swCrDebugUninit(P_ADAPTER_T prAdapter); + +#endif diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/wapi.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/wapi.h new file mode 100755 index 000000000000..a587627b2a7e --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/wapi.h @@ -0,0 +1,164 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/mgmt/wapi.h#1 $ +*/ + +/*! \file wapi.h + \brief The wapi related define, macro and structure are described here. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: wapi.h $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 07 20 2010 wh.su + * + * . + * + * 01 27 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * add and fixed some security function. + * + * Dec 8 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * change the wapi function name and adding the generate wapi ie function + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding some wapi structure define + * + * Nov 23 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * +** \main\maintrunk.MT5921\1 2009-10-09 17:06:29 GMT mtk01088 +** +*/ + +#ifndef _WAPI_H +#define _WAPI_H + +#if CFG_SUPPORT_WAPI + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define WAPI_CIPHER_SUITE_WPI 0x01721400 /* WPI_SMS4 */ +#define WAPI_AKM_SUITE_802_1X 0x01721400 /* WAI */ +#define WAPI_AKM_SUITE_PSK 0x02721400 /* WAI_PSK */ + +#define ELEM_ID_WAPI 68 /* WAPI IE */ + +#define WAPI_IE(fp) ((P_WAPI_INFO_ELEM_T) fp) + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +VOID +wapiGenerateWAPIIE( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + +BOOLEAN +wapiParseWapiIE ( + IN P_WAPI_INFO_ELEM_T prInfoElem, + OUT P_WAPI_INFO_T prWapiInfo + ); + +BOOLEAN +wapiPerformPolicySelection( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBss + ); + +//BOOLEAN +//wapiUpdateTxKeyIdx ( +// IN P_STA_RECORD_T prStaRec, +// IN UINT_8 ucWlanIdx +// ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#endif +#endif /* _WAPI_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/wlan_typedef.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/wlan_typedef.h new file mode 100755 index 000000000000..f0fcdd30c9f6 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/mgmt/wlan_typedef.h @@ -0,0 +1,128 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/mgmt/wlan_typedef.h#1 $ +*/ + +/*! \file wlan_typedef.h + \brief Declaration of data type and return values of internal protocol stack. + + In this file we declare the data type and return values which will be exported + to all MGMT Protocol Stack. +*/ + +/******************************************************************************* +* Copyright (c) 2010 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: wlan_typedef.h $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk +*/ + +#ifndef _WLAN_TYPEDEF_H +#define _WLAN_TYPEDEF_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* Type definition for BSS_INFO_T structure, to describe the attributes used in a + * common BSS. + */ +typedef struct _BSS_INFO_T BSS_INFO_T, *P_BSS_INFO_T; + +typedef BSS_INFO_T AIS_BSS_INFO_T, *P_AIS_BSS_INFO_T; +typedef BSS_INFO_T P2P_BSS_INFO_T, *P_P2P_BSS_INFO_T; +typedef BSS_INFO_T BOW_BSS_INFO_T, *P_BOW_BSS_INFO_T; + +typedef struct _AIS_SPECIFIC_BSS_INFO_T AIS_SPECIFIC_BSS_INFO_T, *P_AIS_SPECIFIC_BSS_INFO_T; +typedef struct _P2P_SPECIFIC_BSS_INFO_T P2P_SPECIFIC_BSS_INFO_T, *P_P2P_SPECIFIC_BSS_INFO_T; +typedef struct _BOW_SPECIFIC_BSS_INFO_T BOW_SPECIFIC_BSS_INFO_T, *P_BOW_SPECIFIC_BSS_INFO_T; + + +/* BSS related structures */ +/* Type definition for BSS_DESC_T structure, to describe parameter sets of a particular BSS */ +typedef struct _BSS_DESC_T BSS_DESC_T, *P_BSS_DESC_T, **PP_BSS_DESC_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#endif /* _WLAN_TYPEDEF_H */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/adapter.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/adapter.h new file mode 100755 index 000000000000..40217c119637 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/adapter.h @@ -0,0 +1,1447 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/nic/adapter.h#6 $ +*/ + +/*! \file adapter.h + \brief Definition of internal data structure for driver manipulation. + + In this file we define the internal data structure - ADAPTER_T which stands + for MiniPort ADAPTER(From Windows point of view) or stands for Network ADAPTER. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: adapter.h $ + * + * 02 22 2012 yuche.tsai + * [ALPS00240483] [Wifi P2P]Run Sigma tool of A69. Always run fail on 5.1.2. No get correct connection from Realtek. + * Fix assoc response without P2P IE issue for Sigma test. + * + * 02 14 2012 yuche.tsai + * [ALPS00118350] [ALPS.ICS][WiFi Direct] Dirver update for wifi direct connection + * Replace Beacon/Probe Response IE by driver generating instead of from supplicant. + * + * 01 28 2012 yuche.tsai + * NULL + * Update for Beacon composing code but not active yet. + * + * 01 20 2012 chinglan.wang + * NULL + * Fix the WPA-PSK TKIP and WPA2-PSK AES security mode bug. + * + * 01 16 2012 yuche.tsai + * NULL + * Update Driver for wifi driect gc join IE update issue. + * + * 01 16 2012 cp.wu + * [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band configuration with corresponding network configuration + * add wlanSetPreferBandByNetwork() for glue layer to invoke for setting preferred band configuration corresponding to network type. + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Hot Spot Tethering for ICS ALPHA testing version. + * + * 12 13 2011 cm.chang + * [WCXRP00001136] [All Wi-Fi][Driver] Add wake lock for pending timer + * Add wake lock if timer timeout value is smaller than 5 seconds + * + * 12 02 2011 yuche.tsai + * NULL + * Resolve class 3 error issue under AP mode. + * + * data frame may TX before Assoc Response TX. + * + * 11 19 2011 yuche.tsai + * NULL + * Add P2P RSSI Link Quality Query Support. (Default Off) + * + * 11 11 2011 yuche.tsai + * NULL + * Fix work thread cancel issue. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 06 23 2011 cp.wu + * [WCXRP00000812] [MT6620 Wi-Fi][Driver] not show NVRAM when there is no valid MAC address in NVRAM content + * check with firmware for valid MAC address. + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 04 12 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 04 10 2011 yuche.tsai + * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. + * Add device discoverability support. (Phase I) + * + * 04 08 2011 george.huang + * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode + * separate settings of P2P and AIS + * + * 04 07 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix for sigma. + * + * 03 19 2011 yuche.tsai + * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. + * Add beacon timeout support for WiFi Direct Netwrok. + * + * 03 19 2011 yuche.tsai + * [WCXRP00000581] [Volunteer Patch][MT6620][Driver] P2P IE in Assoc Req Issue + * Append P2P IE in assoc request if P2P is enabled. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 17 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage after system running for a long period + * use pre-allocated buffer for storing enhanced interrupt response as well + * + * 03 15 2011 cp.wu + * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous memory consumption + * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK + * 2. Use common coalescing buffer for both TX/RX directions + * + * + * 03 10 2011 yuche.tsai + * [WCXRP00000533] [Volunteer Patch][MT6620][Driver] Provide a P2P function API for Legacy WiFi to query AP mode. + * Provide an API for Legacy WiFi to query the operation mode.. + * + * 03 05 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * add the code to get the check rsponse and indicate to app. + * + * 03 02 2011 wh.su + * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request + * Add code to send beacon and probe response WSC IE at Auto GO. + * + * 03 02 2011 cp.wu + * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right after connection is built. + * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. + * + * 02 21 2011 terry.wu + * [WCXRP00000476] [MT6620 Wi-Fi][Driver] Clean P2P scan list while removing P2P + * Clean P2P scan list while removing P2P. + * + * 02 17 2011 eddie.chen + * [WCXRP00000458] [MT6620 Wi-Fi][Driver] BOW Concurrent - ProbeResp was exist in other channel + * 1) Chnage GetFrameAction decision when BSS is absent. + * 2) Check channel and resource in processing ProbeRequest + * + * 02 16 2011 cm.chang + * [WCXRP00000447] [MT6620 Wi-Fi][FW] Support new NVRAM update mechanism + * . + * + * 02 10 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Add RX deauthentication & disassociation process under Hot-Spot mode. + * + * 02 09 2011 wh.su + * [WCXRP00000433] [MT6620 Wi-Fi][Driver] Remove WAPI structure define for avoid P2P module with structure miss-align pointer issue + * always pre-allio WAPI related structure for align p2p module. + * + * 02 08 2011 yuche.tsai + * [WCXRP00000419] [Volunteer Patch][MT6620/MT5931][Driver] Provide function of disconnect to target station for AAA module. + * Provide disconnect function for AAA module. + * + * 02 01 2011 cm.chang + * [WCXRP00000415] [MT6620 Wi-Fi][Driver] Check if any memory leakage happens when uninitializing in DGB mode + * . + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 01 27 2011 george.huang + * [WCXRP00000400] [MT6620 Wi-Fi] support CTIA power mode setting + * Support CTIA power mode setting. + * + * 01 27 2011 george.huang + * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability + * Support current measure mode, assigned by registry (XP only). + * + * 01 24 2011 cp.wu + * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving + * 1. add an extra counter for tracking pending forward frames. + * 2. notify TX service thread as well when there is pending forward frame + * 3. correct build errors leaded by introduction of Wi-Fi direct separation module + * + * 01 12 2011 cm.chang + * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting + * User-defined bandwidth is for 2.4G and 5G individually + * + * 12 29 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, + +Add per station flow control when STA is in PS + + + * Add WMM parameter for broadcast. + * + * 12 29 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, + +Add per station flow control when STA is in PS + + + * Add CWMin CWMax for AP to generate IE. + * + * 12 29 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, +Add per station flow control when STA is in PS + + * 1) PS flow control event + * + * 2) WMM IE in beacon, assoc resp, probe resp + * + * 12 28 2010 cp.wu + * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release + * report EEPROM used flag via NIC_CAPABILITY + * + * 12 28 2010 cp.wu + * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release + * integrate with 'EEPROM used' flag for reporting correct capability to Engineer Mode/META and other tools + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 10 27 2010 george.huang + * [WCXRP00000127] [MT6620 Wi-Fi][Driver] Add a registry to disable Beacon Timeout function for SQA test by using E1 EVB + * Support registry option for disable beacon lost detection. + * + * 10 26 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command + * 1) update NVRAM content template to ver 1.02 + * 2) add compile option for querying NIC capability (default: off) + * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting + * 4) correct auto-rate compiler error under linux (treat warning as error) + * 5) simplify usage of NVRAM and REG_INFO_T + * 6) add version checking between driver and firmware + * + * 10 08 2010 cp.wu + * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test + * adding fixed rate support for distance test. (from registry setting) + * + * 10 06 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * code reorganization to improve isolation between GLUE and CORE layers. + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * 1) add NVRAM access API + * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) + * 3) add OID implementation for NVRAM read/write service + * + * 09 27 2010 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings + * Update BCM/BoW design and settings. + * + * 09 24 2010 cp.wu + * [WCXRP00000057] [MT6620 Wi-Fi][Driver] Modify online scan to a run-time switchable feature + * Modify online scan as a run-time adjustable option (for Windows, in registry) + * + * 09 23 2010 cp.wu + * [WCXRP00000051] [MT6620 Wi-Fi][Driver] WHQL test fail in MAC address changed item + * use firmware reported mac address right after wlanAdapterStart() as permanent address + * + * 09 08 2010 cp.wu + * NULL + * use static memory pool for storing IEs of scanning result. + * + * 09 07 2010 yuche.tsai + * NULL + * Add a common IE buffer in P2P INFO structure. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 09 01 2010 cp.wu + * NULL + * restore configuration as before. + * + * 09 01 2010 wh.su + * NULL + * adding the wapi support for integration test. + * + * 08 31 2010 kevin.huang + * NULL + * Use LINK LIST operation to process SCAN result + * + * 08 29 2010 yuche.tsai + * NULL + * Finish SLT TX/RX & Rate Changing Support. + * + * 08 25 2010 george.huang + * NULL + * update OID/ registry control path for PM related settings + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 08 23 2010 chinghwa.yu + * NULL + * Update for BOW. + * + * 08 20 2010 cm.chang + * NULL + * Migrate RLM code to host from FW + * + * 08 16 2010 yuche.tsai + * NULL + * Add an intend mode for BSS info. + * It is used to let P2P BSS Info to know which OP Mode it is going to become. + * + * 08 04 2010 george.huang + * NULL + * handle change PS mode OID/ CMD + * + * 08 02 2010 cp.wu + * NULL + * comment out deprecated members in BSS_INFO, which are only used by firmware rather than driver. + * + * 07 29 2010 cp.wu + * NULL + * eliminate u4FreqInKHz usage, combined into rConnections.ucAdHoc* + * + * 07 28 2010 cp.wu + * NULL + * 1) eliminate redundant variable eOPMode in prAdapter->rWlanInfo + * 2) change nicMediaStateChange() API prototype + * + * 07 24 2010 wh.su + * + * .support the Wi-Fi RSN + * + * 07 21 2010 yuche.tsai + * + * Add for P2P Scan Result Parsing & Saving. + * + * 07 19 2010 wh.su + * + * update for security supporting. + * + * 07 19 2010 cm.chang + * + * Set RLM parameters and enable CNM channel manager + * + * 07 19 2010 yuche.tsai + * + * Remove BSS info which is redonedent in Wifi Var.. + * + * 07 16 2010 yarco.yang + * + * 1. Support BSS Absence/Presence Event + * 2. Support STA change PS mode Event + * 3. Support BMC forwarding for AP mode. + * + * 07 14 2010 yarco.yang + * + * 1. Remove CFG_MQM_MIGRATION + * 2. Add CMD_UPDATE_WMM_PARMS command + * + * 07 09 2010 george.huang + * + * [WPD00001556] Migrate PM variables from FW to driver: for composing QoS Info + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Check draft RLM code for HT cap + * + * 06 29 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * replace g_rQM with Adpater->rQM + * + * 06 28 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * 1st draft code for RLM module + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * remove duplicate variable for migration. + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * modify some code for concurrent network. + * + * 06 21 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Add P2P FSM Info in adapter. + * + * 06 21 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Support CFG_MQM_MIGRATION flag + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration the security related function from firmware. + * + * 06 17 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Add P2P related field, additional include p2p_fsm.h if p2p is enabled. + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add scan.c. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add management dispatching function table. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * auth.c is migrated. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add buildable & linkable ais_fsm.c + * + * related reference are still waiting to be resolved + * + * 06 09 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add definitions for module migration. + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * cnm_timer has been migrated. + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * hem_mbox is migrated. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge wifi_var.h, precomp.h, cnm_timer.h (data type only) + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * change OID behavior to meet WHQL requirement. + * + * 05 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS + * 2) buffer statistics data for 2 seconds + * 3) use default value for adhoc parameters instead of 0 + * + * 05 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) do not take timeout mechanism for power mode oids + * 2) retrieve network type from connection status + * 3) after disassciation, set radio state to off + * 4) TCP option over IPv6 is supported + * + * 05 18 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement Wakeup-on-LAN except firmware integration part + * + * 04 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * reserve field of privacy filter and RTS threshold setting. + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * * * 2) command sequence number is now increased atomically + * * * * * * 3) private data could be hold and taken use for other purpose + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * rWlanInfo should be placed at adapter rather than glue due to most operations + * * * are done in adapter layer. + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved + * + * 03 31 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * modify the wapi related code for new driver's design. + * + * 03 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add ACPI D0/D3 state switching support + * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response + * + * 03 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement OID_802_3_MULTICAST_LIST oid handling + * + * 03 02 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) the use of prPendingOid revised, all accessing are now protected by spin lock + * * * 2) ensure wlanReleasePendingOid will clear all command queues + * + * 02 09 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * move ucCmdSeqNum as instance variable + * + * 01 27 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * . + * + * 01 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. eliminate improper variable in rHifInfo + * * * 2. block TX/ordinary OID when RF test mode is engaged + * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode + * * * 4. correct some HAL implementation + * + * 12 30 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) According to CMD/EVENT documentation v0.8, + * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, + * * * and result is retrieved by get ATInfo instead + * * * 2) add 4 counter for recording aggregation statistics + * + * 12 28 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate redundant variables for connection_state +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-12-16 18:02:03 GMT mtk02752 +** add external reference to avoid compilation error +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-12-10 16:40:26 GMT mtk02752 +** eliminate unused member +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-12-08 17:36:08 GMT mtk02752 +** add RF test data members into P_ADAPTER_T +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-10-13 21:58:45 GMT mtk01084 +** update for new HW architecture design +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-28 10:29:57 GMT mtk01461 +** Add read WTSR for SDIO_STATUS_ENHANCE mode +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-21 09:37:35 GMT mtk01461 +** Add prPendingCmdInfoOfOID for temporarily saving the CMD_INFO_T before en-queue to rCmdQueue +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-17 19:57:51 GMT mtk01461 +** Add MGMT Buffer Info +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-01 10:34:12 GMT mtk01461 +** Add SW pre test CFG_HIF_LOOPBACK_PRETEST +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-23 21:41:48 GMT mtk01461 +** Add fgIsWmmAssoc flag for TC assignment +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-19 18:32:51 GMT mtk01084 +** update for basic power management functions +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-18 20:51:52 GMT mtk01426 +** Add #if CFG_SDIO_RX_ENHANCE related data structure +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:17 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _ADAPTER_H +#define _ADAPTER_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef struct _ENHANCE_MODE_DATA_STRUCT_T SDIO_CTRL_T, *P_SDIO_CTRL_T; + +typedef struct _WLAN_INFO_T { + PARAM_BSSID_EX_T rCurrBssId; + + // Scan Result + PARAM_BSSID_EX_T arScanResult[CFG_MAX_NUM_BSS_LIST]; + PUINT_8 apucScanResultIEs[CFG_MAX_NUM_BSS_LIST]; + UINT_32 u4ScanResultNum; + + // IE pool for Scanning Result + UINT_8 aucScanIEBuf[CFG_MAX_COMMON_IE_BUF_LEN]; + UINT_32 u4ScanIEBufferUsage; + + OS_SYSTIME u4SysTime; + + // connection parameter (for Ad-Hoc) + UINT_16 u2BeaconPeriod; + UINT_16 u2AtimWindow; + + PARAM_RATES eDesiredRates; + CMD_LINK_ATTRIB eLinkAttr; +// CMD_PS_PROFILE_T ePowerSaveMode; + CMD_PS_PROFILE_T arPowerSaveMode[NETWORK_TYPE_INDEX_NUM]; + + // trigger parameter + ENUM_RSSI_TRIGGER_TYPE eRssiTriggerType; + PARAM_RSSI rRssiTriggerValue; + + // Privacy Filter + ENUM_PARAM_PRIVACY_FILTER_T ePrivacyFilter; + + // RTS Threshold + PARAM_RTS_THRESHOLD eRtsThreshold; + + // Network Type + UINT_8 ucNetworkType; + + // Network Type In Use + UINT_8 ucNetworkTypeInUse; + +} WLAN_INFO_T, *P_WLAN_INFO_T; + +/* Session for CONNECTION SETTINGS */ +typedef struct _CONNECTION_SETTINGS_T { + + UINT_8 aucMacAddress[MAC_ADDR_LEN]; + + UINT_8 ucDelayTimeOfDisconnectEvent; + + BOOLEAN fgIsConnByBssidIssued; + UINT_8 aucBSSID[MAC_ADDR_LEN]; + + BOOLEAN fgIsConnReqIssued; + UINT_8 ucSSIDLen; + UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; + + ENUM_PARAM_OP_MODE_T eOPMode; + + ENUM_PARAM_CONNECTION_POLICY_T eConnectionPolicy; + + ENUM_PARAM_AD_HOC_MODE_T eAdHocMode; + + ENUM_PARAM_AUTH_MODE_T eAuthMode; + + ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; + + BOOLEAN fgIsScanReqIssued; + + + /* MIB attributes */ + UINT_16 u2BeaconPeriod; + + UINT_16 u2RTSThreshold; /* User desired setting */ + + UINT_16 u2DesiredNonHTRateSet; /* User desired setting */ + + UINT_8 ucAdHocChannelNum; /* For AdHoc */ + + ENUM_BAND_T eAdHocBand; /* For AdHoc */ + + UINT_32 u4FreqInKHz; /* Center frequency */ + + /* ATIM windows using for IBSS power saving function */ + UINT_16 u2AtimWindow; + + /* Features */ + BOOLEAN fgIsEnableRoaming; + + BOOLEAN fgIsAdHocQoSEnable; + + ENUM_PARAM_PHY_CONFIG_T eDesiredPhyConfig; + + /* Used for AP mode for desired channel and bandwidth */ + UINT_16 u2CountryCode; + UINT_8 uc2G4BandwidthMode; /* 20/40M or 20M only */ + UINT_8 uc5GBandwidthMode; /* 20/40M or 20M only */ + + BOOLEAN fgTxShortGIDisabled; + BOOLEAN fgRxShortGIDisabled; + +#if CFG_SUPPORT_802_11D + BOOLEAN fgMultiDomainCapabilityEnabled; +#endif /* CFG_SUPPORT_802_11D*/ + + +#if 1 //CFG_SUPPORT_WAPI + BOOL fgWapiMode; + UINT_32 u4WapiSelectedGroupCipher; + UINT_32 u4WapiSelectedPairwiseCipher; + UINT_32 u4WapiSelectedAKMSuite; +#endif + + /* CR1486, CR1640 */ + /* for WPS, disable the privacy check for AP selection policy */ + BOOLEAN fgPrivacyCheckDisable; + + /* b0~3: trigger-en AC0~3. b4~7: delivery-en AC0~3 */ + UINT_8 bmfgApsdEnAc; + +} CONNECTION_SETTINGS_T, *P_CONNECTION_SETTINGS_T; + +struct _BSS_INFO_T { + + ENUM_PARAM_MEDIA_STATE_T eConnectionState; /* Connected Flag used in AIS_NORMAL_TR */ + ENUM_PARAM_MEDIA_STATE_T eConnectionStateIndicated; /* The Media State that report to HOST */ + + ENUM_OP_MODE_T eCurrentOPMode; /* Current Operation Mode - Infra/IBSS */ +#if CFG_ENABLE_WIFI_DIRECT + ENUM_OP_MODE_T eIntendOPMode; +#endif + + BOOLEAN fgIsNetActive; /* TRUE if this network has been activated */ + + UINT_8 ucNetTypeIndex; /* ENUM_NETWORK_TYPE_INDEX_T */ + + UINT_8 ucReasonOfDisconnect; /* Used by media state indication */ + + BOOLEAN ucSSIDLen; /* Length of SSID */ + UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; /* SSID used in this BSS */ + + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* The BSSID of the associated BSS */ + + UINT_8 aucOwnMacAddr[MAC_ADDR_LEN];/* Owned MAC Address used in this BSS */ + + P_STA_RECORD_T prStaRecOfAP; /* For Infra Mode, and valid only if + * eConnectionState == MEDIA_STATE_CONNECTED + */ + LINK_T rStaRecOfClientList; /* For IBSS/AP Mode, all known STAs in current BSS */ + + UINT_16 u2CapInfo; /* Change Detection */ + + UINT_16 u2BeaconInterval; /* The Beacon Interval of this BSS */ + + + UINT_16 u2ATIMWindow; /* For IBSS Mode */ + + UINT_16 u2AssocId; /* For Infra Mode, it is the Assoc ID assigned by AP. + */ + + + UINT_8 ucDTIMPeriod; /* For Infra/AP Mode */ + + UINT_8 ucDTIMCount; /* For AP Mode, it is the DTIM value we should carried in + * the Beacon of next TBTT. + */ + + UINT_8 ucPhyTypeSet; /* Available PHY Type Set of this peer + * (This is deduced from received BSS_DESC_T) + */ + + UINT_8 ucNonHTBasicPhyType; /* The Basic PHY Type Index, used to setup Phy Capability */ + + UINT_8 ucConfigAdHocAPMode; /* The configuration of AdHoc/AP Mode. e.g. 11g or 11b */ + + UINT_8 ucBeaconTimeoutCount; /* For Infra/AP Mode, it is a threshold of Beacon Lost Count to + confirm connection was lost */ + + BOOLEAN fgHoldSameBssidForIBSS; /* For IBSS Mode, to keep use same BSSID to extend the life cycle of an IBSS */ + + BOOLEAN fgIsBeaconActivated; /* For AP/IBSS Mode, it is used to indicate that Beacon is sending */ + + P_MSDU_INFO_T prBeacon; /* For AP/IBSS Mode - Beacon Frame */ + + BOOLEAN fgIsIBSSMaster; /* For IBSS Mode - To indicate that we can reply ProbeResp Frame. + In current TBTT interval */ + + BOOLEAN fgIsShortPreambleAllowed; /* From Capability Info. of AssocResp Frame AND of Beacon/ProbeResp Frame */ + BOOLEAN fgUseShortPreamble; /* Short Preamble is enabled in current BSS. */ + BOOLEAN fgUseShortSlotTime; /* Short Slot Time is enabled in current BSS. */ + + UINT_16 u2OperationalRateSet; /* Operational Rate Set of current BSS */ + UINT_16 u2BSSBasicRateSet; /* Basic Rate Set of current BSS */ + + + UINT_8 ucAllSupportedRatesLen; /* Used for composing Beacon Frame in AdHoc or AP Mode */ + UINT_8 aucAllSupportedRates[RATE_NUM]; + + UINT_8 ucAssocClientCnt; /* TODO(Kevin): Number of associated clients */ + + BOOLEAN fgIsProtection; + BOOLEAN fgIsQBSS; /* fgIsWmmBSS; */ /* For Infra/AP/IBSS Mode, it is used to indicate if we support WMM in + * current BSS. */ + BOOLEAN fgIsNetAbsent; /* TRUE: BSS is absent, FALSE: BSS is present */ + + UINT_32 u4RsnSelectedGroupCipher; + UINT_32 u4RsnSelectedPairwiseCipher; + UINT_32 u4RsnSelectedAKMSuite; + UINT_16 u2RsnSelectedCapInfo; + + /*------------------------------------------------------------------------*/ + /* Power Management related information */ + /*------------------------------------------------------------------------*/ + PM_PROFILE_SETUP_INFO_T rPmProfSetupInfo; + + + /*------------------------------------------------------------------------*/ + /* WMM/QoS related information */ + /*------------------------------------------------------------------------*/ + UINT_8 ucWmmParamSetCount; /* Used to detect the change of EDCA parameters. For AP mode, the value is used in WMM IE */ + + AC_QUE_PARMS_T arACQueParms[WMM_AC_INDEX_NUM]; + + UINT_8 aucCWminLog2ForBcast[WMM_AC_INDEX_NUM]; /* For AP mode, broadcast the CWminLog2 */ + UINT_8 aucCWmaxLog2ForBcast[WMM_AC_INDEX_NUM]; /* For AP mode, broadcast the CWmaxLog2 */ + AC_QUE_PARMS_T arACQueParmsForBcast[WMM_AC_INDEX_NUM]; /* For AP mode, broadcast the value */ + + /*------------------------------------------------------------------------*/ + /* 802.11n HT operation IE when (prStaRec->ucPhyTypeSet & PHY_TYPE_BIT_HT)*/ + /* is true. They have the same definition with fields of */ + /* information element (CM) */ + /*------------------------------------------------------------------------*/ + ENUM_BAND_T eBand; + UINT_8 ucPrimaryChannel; + UINT_8 ucHtOpInfo1; + UINT_16 u2HtOpInfo2; + UINT_16 u2HtOpInfo3; + + /*------------------------------------------------------------------------*/ + /* Required protection modes (CM) */ + /*------------------------------------------------------------------------*/ + BOOLEAN fgErpProtectMode; + ENUM_HT_PROTECT_MODE_T eHtProtectMode; + ENUM_GF_MODE_T eGfOperationMode; + ENUM_RIFS_MODE_T eRifsOperationMode; + + BOOLEAN fgObssErpProtectMode; /* GO only */ + ENUM_HT_PROTECT_MODE_T eObssHtProtectMode; /* GO only */ + ENUM_GF_MODE_T eObssGfOperationMode; /* GO only */ + BOOLEAN fgObssRifsOperationMode; /* GO only */ + + /*------------------------------------------------------------------------*/ + /* OBSS to decide if 20/40M bandwidth is permitted. */ + /* The first member indicates the following channel list length. */ + /*------------------------------------------------------------------------*/ + BOOLEAN fgAssoc40mBwAllowed; + BOOLEAN fg40mBwAllowed; + ENUM_CHNL_EXT_T eBssSCO; /* Real setting for HW + * 20/40M AP mode will always set 40M, + * but its OP IE can be changed. + */ + UINT_8 auc2G_20mReqChnlList[CHNL_LIST_SZ_2G + 1]; + UINT_8 auc2G_NonHtChnlList[CHNL_LIST_SZ_2G + 1]; + UINT_8 auc2G_PriChnlList[CHNL_LIST_SZ_2G + 1]; + UINT_8 auc2G_SecChnlList[CHNL_LIST_SZ_2G + 1]; + + UINT_8 auc5G_20mReqChnlList[CHNL_LIST_SZ_5G + 1]; + UINT_8 auc5G_NonHtChnlList[CHNL_LIST_SZ_5G + 1]; + UINT_8 auc5G_PriChnlList[CHNL_LIST_SZ_5G + 1]; + UINT_8 auc5G_SecChnlList[CHNL_LIST_SZ_5G + 1]; + + TIMER_T rObssScanTimer; + UINT_16 u2ObssScanInterval; /* in unit of sec */ + + BOOLEAN fgObssActionForcedTo20M; /* GO only */ + BOOLEAN fgObssBeaconForcedTo20M; /* GO only */ + + /*------------------------------------------------------------------------*/ + /* HW Related Fields (Kevin) */ + /*------------------------------------------------------------------------*/ + UINT_8 ucHwDefaultFixedRateCode; /* The default rate code copied to MAC TX Desc */ + UINT_16 u2HwLPWakeupGuardTimeUsec; + + + UINT_8 ucBssFreeQuota; /* The value is updated from FW */ +}; + + +struct _AIS_SPECIFIC_BSS_INFO_T { + UINT_8 ucRoamingAuthTypes; /* This value indicate the roaming type used in AIS_JOIN */ + + BOOLEAN fgIsIBSSActive; + + /*! \brief Global flag to let arbiter stay at standby and not connect to any network */ + BOOLEAN fgCounterMeasure; + UINT_8 ucWEPDefaultKeyID; + BOOLEAN fgTransmitKeyExist; /* Legacy wep Transmit key exist or not */ + + /* While Do CounterMeasure procedure, check the EAPoL Error report have send out */ + BOOLEAN fgCheckEAPoLTxDone; + + UINT_32 u4RsnaLastMICFailTime; + + /* Stored the current bss wpa rsn cap filed, used for roaming policy */ + //UINT_16 u2RsnCap; + TIMER_T rPreauthenticationTimer; + + /* By the flow chart of 802.11i, + wait 60 sec before associating to same AP + or roaming to a new AP + or sending data in IBSS, + keep a timer for handle the 60 sec counterMeasure */ + TIMER_T rRsnaBlockTrafficTimer; + TIMER_T rRsnaEAPoLReportTimeoutTimer; + + /* For Keep the Tx/Rx Mic key for TKIP SW Calculate Mic */ + /* This is only one for AIS/AP */ + UINT_8 aucTxMicKey[8]; + UINT_8 aucRxMicKey[8]; + + /* Buffer for WPA2 PMKID */ + /* The PMKID cache lifetime is expire by media_disconnect_indication */ + UINT_32 u4PmkidCandicateCount; + PMKID_CANDICATE_T arPmkidCandicate[CFG_MAX_PMKID_CACHE]; + UINT_32 u4PmkidCacheCount; + PMKID_ENTRY_T arPmkidCache[CFG_MAX_PMKID_CACHE]; + BOOLEAN fgIndicatePMKID; +#if CFG_SUPPORT_802_11W + BOOLEAN fgMgmtProtection; + UINT_32 u4SaQueryStart; + UINT_32 u4SaQueryCount; + UINT_8 ucSaQueryTimedOut; + PUINT_8 pucSaQueryTransId; + TIMER_T rSaQueryTimer; + BOOLEAN fgBipKeyInstalled; +#endif +}; + +struct _BOW_SPECIFIC_BSS_INFO_T { + UINT_16 u2Reserved; /* Reserved for Data Type Check */ +}; + +#if CFG_SLT_SUPPORT +typedef struct _SLT_INFO_T { + + P_BSS_DESC_T prPseudoBssDesc; + UINT_16 u2SiteID; + UINT_8 ucChannel2G4; + UINT_8 ucChannel5G; + BOOLEAN fgIsDUT; + UINT_32 u4BeaconReceiveCnt; + /////////Deprecated///////// + P_STA_RECORD_T prPseudoStaRec; +} SLT_INFO_T, *P_SLT_INFO_T; +#endif + + +/* Major member variables for WiFi FW operation. + Variables within this region will be ready for access after WIFI function is enabled. +*/ +typedef struct _WIFI_VAR_T { + BOOLEAN fgIsRadioOff; + + BOOLEAN fgIsEnterD3ReqIssued; + + BOOLEAN fgDebugCmdResp; + + CONNECTION_SETTINGS_T rConnSettings; + + SCAN_INFO_T rScanInfo; + +#if CFG_SUPPORT_ROAMING + ROAMING_INFO_T rRoamingInfo; +#endif /* CFG_SUPPORT_ROAMING */ + + AIS_FSM_INFO_T rAisFsmInfo; + + ENUM_PWR_STATE_T aePwrState[NETWORK_TYPE_INDEX_NUM]; + + BSS_INFO_T arBssInfo[NETWORK_TYPE_INDEX_NUM]; + + AIS_SPECIFIC_BSS_INFO_T rAisSpecificBssInfo; + +#if CFG_ENABLE_WIFI_DIRECT + P_P2P_CONNECTION_SETTINGS_T prP2PConnSettings; + + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo; + + P_P2P_FSM_INFO_T prP2pFsmInfo; +#endif /* CFG_ENABLE_WIFI_DIRECT */ + +#if CFG_ENABLE_BT_OVER_WIFI + BOW_SPECIFIC_BSS_INFO_T rBowSpecificBssInfo; + BOW_FSM_INFO_T rBowFsmInfo; +#endif /* CFG_ENABLE_BT_OVER_WIFI */ + + DEAUTH_INFO_T arDeauthInfo[MAX_DEAUTH_INFO_COUNT]; + + /* Current Wi-Fi Settings and Flags */ + UINT_8 aucPermanentAddress[MAC_ADDR_LEN]; + UINT_8 aucMacAddress[MAC_ADDR_LEN]; + UINT_8 aucDeviceAddress[MAC_ADDR_LEN]; + UINT_8 aucInterfaceAddress[MAC_ADDR_LEN]; + + UINT_8 ucAvailablePhyTypeSet; + + ENUM_PHY_TYPE_INDEX_T eNonHTBasicPhyType2G4; /* Basic Phy Type used by SCN according + * to the set of Available PHY Types + */ + + ENUM_PARAM_PREAMBLE_TYPE_T ePreambleType; + ENUM_REGISTRY_FIXED_RATE_T eRateSetting; + + BOOLEAN fgIsShortSlotTimeOptionEnable; + /* User desired setting, but will honor the capability of AP */ + + BOOLEAN fgEnableJoinToHiddenSSID; + BOOLEAN fgSupportWZCDisassociation; + + BOOLEAN fgSupportQoS; + BOOLEAN fgSupportAmpduTx; + BOOLEAN fgSupportAmpduRx; + BOOLEAN fgSupportTspec; + BOOLEAN fgSupportUAPSD; + BOOLEAN fgSupportULPSMP; + +#if CFG_SLT_SUPPORT + SLT_INFO_T rSltInfo; +#endif + +} WIFI_VAR_T, *P_WIFI_VAR_T;/* end of _WIFI_VAR_T */ + +/* cnm_timer module */ +typedef struct { + LINK_T rLinkHead; + OS_SYSTIME rNextExpiredSysTime; + KAL_WAKE_LOCK_T rWakeLock; + BOOLEAN fgWakeLocked; +} ROOT_TIMER, *P_ROOT_TIMER; + + +/* FW/DRV/NVRAM version information */ +typedef struct { + + /* NVRAM or Registry */ + UINT_16 u2Part1CfgOwnVersion; + UINT_16 u2Part1CfgPeerVersion; + UINT_16 u2Part2CfgOwnVersion; + UINT_16 u2Part2CfgPeerVersion; + + /* Firmware */ + UINT_16 u2FwProductID; + UINT_16 u2FwOwnVersion; + UINT_16 u2FwPeerVersion; + +} WIFI_VER_INFO_T, *P_WIFI_VER_INFO_T; + + +#if CFG_ENABLE_WIFI_DIRECT +/* +* p2p function pointer structure +*/ + +typedef struct _P2P_FUNCTION_LINKER { + P2P_REMOVE prP2pRemove; + KAL_P2P_GET_CIPHER prKalP2pGetCipher; + KAL_P2P_GET_TKIP_CIPHER prKalP2pGetTkipCipher; + KAL_P2P_GET_CCMP_CIPHER prKalP2pGetCcmpCipher; + KAL_P2P_GET_WSC_MODE prKalP2pGetWscMode; + KAL_P2P_GET_DEV_HDLR prKalP2pGetDevHdlr; +// NIC_P2P_MEDIA_STATE_CHANGE prNicP2pMediaStateChange; + KAL_P2P_UPDATE_ASSOC_INFO prKalP2pUpdateAssocInfo; + P2P_VALIDATE_AUTH prP2pValidateAuth; + P2P_VALIDATE_ASSOC_REQ prP2pValidateAssocReq; + P2P_RUN_EVENT_AAA_TX_FAIL prP2pRunEventAAATxFail; + P2P_RUN_EVENT_AAA_COMPLETE prP2pRunEventAAASuccess; + P2P_RUN_EVENT_AAA_COMPLETE prP2pRunEventAAAComplete; + P2P_PARSE_CHECK_FOR_P2P_INFO_ELEM prP2pParseCheckForP2pInfoElem; +// SCAN_UPDATE_P2P_DEVICE_DESC prScanUpdateP2pDeviceDesc; +// P2P_FSM_RUN_EVENT_RX_PROBE_RESPONSE_FRAME prP2pFsmRunEventRxProbeResponseFrame; + P2P_PROCESS_EVENT_UPDATE_NOA_PARAM prP2pProcessEvent_UpdateNOAParam; + SCAN_P2P_PROCESS_BEACON_AND_PROBE_RESP prScanP2pProcessBeaconAndProbeResp; + P2P_RX_PUBLIC_ACTION_FRAME prP2pRxPublicActionFrame; + RLM_RSP_GENERATE_OBSS_SCAN_IE prRlmRspGenerateObssScanIE; + RLM_PROCESS_PUBLIC_ACTION prRlmProcessPublicAction; + RLM_PROCESS_HT_ACTION prRlmProcessHtAction; + RLM_UPDATE_PARAMS_FOR_AP prRlmUpdateParamsForAp; + RLM_HANDLE_OBSS_STATUS_EVENT_PKT prRlmHandleObssStatusEventPkt; + P2P_CALCULATE_P2P_IE_LEN prP2pCalculateP2p_IELenForBeacon; + P2P_GENERATE_P2P_IE prP2pGenerateP2p_IEForBeacon; + P2P_CALCULATE_P2P_IE_LEN prP2pCalculateP2p_IELenForAssocRsp; + P2P_GENERATE_P2P_IE prP2pGenerateP2p_IEForAssocRsp; + P2P_CALCULATE_P2P_IE_LEN prP2pCalculateWSC_IELenForBeacon; + P2P_GENERATE_P2P_IE prP2pGenerateWSC_IEForBeacon; +// P2P_CALCULATE_WSC_IE_LEN_FOR_PROBE_RSP prP2pCalculateWSC_IELenForProbeRsp; +// P2P_GENERATE_WSC_IE_FOR_PROBE_RSP prP2pGenerateWSC_IEForProbeRsp; + P2P_FUNC_VALIDATE_PROBE_REQ prP2pFuncValidateProbeReq; + RLM_BSS_INIT_FOR_AP prRlmBssInitForAP; + P2P_GET_PROB_RSP_IE_TABLE_SIZE prP2pGetTxProbRspIETAbleSize; + P2P_BUILD_REASSOC_REQ_FRAME_COMMON_IES prP2pBuildReassocReqFrameCommIEs; +// SCAN_REMOVE_P2P_BSS_DESC prScanRemoveP2pBssDesc; + P2P_FUNC_DISCONNECT prP2pFuncDisconnect; + P2P_FSM_RUN_EVENT_RX_DEAUTH prP2pFsmRunEventRxDeauthentication; + P2P_FSM_RUN_EVENT_RX_DISASSOC prP2pFsmRunEventRxDisassociation; +// P2P_HANDLE_SEC_CHECK_RSP prP2pHandleSecCheckRsp; + P2P_FUN_IS_AP_MODE prP2pFuncIsApMode; + P2P_FSM_RUN_EVENT_BEACON_TIMEOUT prP2pFsmRunEventBeaconTimeout; + P2P_RX_PUBLIC_ACTION_FRAME prP2pRxActionFrame; + KAL_P2P_SET_MULTICAST_WORK_ITEM prP2pSetMulticastListWorkQueue; + P2P_FUNC_STORE_ASSOC_RSP_IE_BUFFER prP2pFuncStoreAssocRspIeBuffer; + P2P_CALCULATE_P2P_IE_LEN prP2pCalculate_IELenForAssocReq; + P2P_GENERATE_P2P_IE prP2pGenerate_IEForAssocReq; +} P2P_FUNCTION_LINKER, *P_P2P_FUNCTION_LINKER; + + +#endif + +/* + * Major ADAPTER structure + * Major data structure for driver operation + */ +struct _ADAPTER_T { + UINT_8 ucRevID; + + UINT_16 u2NicOpChnlNum; + + BOOLEAN fgIsEnableWMM; + BOOLEAN fgIsWmmAssoc; /* This flag is used to indicate that WMM is enable in current BSS */ + + UINT_32 u4OsPacketFilter; // packet filter used by OS + + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + UINT_32 u4CSUMFlags; +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + + + ENUM_BAND_T aePreferBand[NETWORK_TYPE_INDEX_NUM]; + + /* ADAPTER flags */ + UINT_32 u4Flags; + UINT_32 u4HwFlags; + + BOOLEAN fgIsRadioOff; + + BOOLEAN fgIsEnterD3ReqIssued; + + UINT_8 aucMacAddress[MAC_ADDR_LEN]; + + ENUM_PHY_TYPE_INDEX_T eCurrentPhyType; /* Current selection basing on the set of Available PHY Types */ + +#if CFG_COALESCING_BUFFER_SIZE || CFG_SDIO_RX_AGG + UINT_32 u4CoalescingBufCachedSize; + PUINT_8 pucCoalescingBufCached; +#endif /* CFG_COALESCING_BUFFER_SIZE */ + + /* Buffer for CMD_INFO_T, Mgt packet and mailbox message */ + BUF_INFO_T rMgtBufInfo; + BUF_INFO_T rMsgBufInfo; + PUINT_8 pucMgtBufCached; + UINT_32 u4MgtBufCachedSize; + UINT_8 aucMsgBuf[MSG_BUFFER_SIZE]; +#if CFG_DBG_MGT_BUF + UINT_32 u4MemAllocDynamicCount; /* Debug only */ + UINT_32 u4MemFreeDynamicCount; /* Debug only */ +#endif + + STA_RECORD_T arStaRec[CFG_STA_REC_NUM]; + + /* Element for TX PATH */ + TX_CTRL_T rTxCtrl; + QUE_T rFreeCmdList; + CMD_INFO_T arHifCmdDesc[CFG_TX_MAX_CMD_PKT_NUM]; + + /* Element for RX PATH */ + RX_CTRL_T rRxCtrl; + + P_SDIO_CTRL_T prSDIOCtrl; + +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) + /* Element for MT6620 E1 HIFSYS workaround */ + BOOLEAN fgIsClockGatingEnabled; +#endif + + /* Buffer for Authentication Event */ + /* Move to glue layer and refine the kal function */ + /* Reference to rsnGeneratePmkidIndication function at rsn.c */ + UINT_8 aucIndicationEventBuffer[(CFG_MAX_PMKID_CACHE * 20) + 8 ]; + + UINT_32 u4IntStatus; + + ENUM_ACPI_STATE_T rAcpiState; + + BOOLEAN fgIsIntEnable; + BOOLEAN fgIsIntEnableWithLPOwnSet; + + BOOLEAN fgIsFwOwn; + BOOLEAN fgWiFiInSleepyState; + + UINT_32 u4PwrCtrlBlockCnt; + + QUE_T rPendingCmdQueue; + + P_GLUE_INFO_T prGlueInfo; + + UINT_8 ucCmdSeqNum; + UINT_8 ucTxSeqNum; + +#if 1//CFG_SUPPORT_WAPI + BOOLEAN fgUseWapi; +#endif + + /* RF Test flags */ + BOOLEAN fgTestMode; + + /* WLAN Info for DRIVER_CORE OID query */ + WLAN_INFO_T rWlanInfo; + +#if CFG_ENABLE_WIFI_DIRECT + BOOLEAN fgIsP2PRegistered; + BOOLEAN fgIsWlanLaunched; + P_P2P_INFO_T prP2pInfo; + P2P_FUNCTION_LINKER rP2pFuncLkr; +#if CFG_SUPPORT_P2P_RSSI_QUERY + OS_SYSTIME rP2pLinkQualityUpdateTime; + BOOLEAN fgIsP2pLinkQualityValid; + EVENT_LINK_QUALITY rP2pLinkQuality; +#endif +#endif + + /* Online Scan Option */ + BOOLEAN fgEnOnlineScan; + + /* Online Scan Option */ + BOOLEAN fgDisBcnLostDetection; + + /* MAC address */ + PARAM_MAC_ADDRESS rMyMacAddr; + + /* Wake-up Event for WOL */ + UINT_32 u4WakeupEventEnable; + + /* Event Buffering */ + EVENT_STATISTICS rStatStruct; + OS_SYSTIME rStatUpdateTime; + BOOLEAN fgIsStatValid; + + EVENT_LINK_QUALITY rLinkQuality; + OS_SYSTIME rLinkQualityUpdateTime; + BOOLEAN fgIsLinkQualityValid; + OS_SYSTIME rLinkRateUpdateTime; + BOOLEAN fgIsLinkRateValid; + + /* WIFI_VAR_T */ + WIFI_VAR_T rWifiVar; + + /* MTK WLAN NIC driver IEEE 802.11 MIB */ + IEEE_802_11_MIB_T rMib; + + /* Mailboxs for inter-module communication */ + MBOX_T arMbox[MBOX_ID_TOTAL_NUM]; + + /* Timers for OID Pending Handling */ + TIMER_T rOidTimeoutTimer; + + /* Root Timer for cnm_timer module */ + ROOT_TIMER rRootTimer; + + /* RLM maintenance */ + ENUM_CHNL_EXT_T eRfSco; + ENUM_SYS_PROTECT_MODE_T eSysProtectMode; + ENUM_GF_MODE_T eSysHtGfMode; + ENUM_RIFS_MODE_T eSysTxRifsMode; + ENUM_SYS_PCO_PHASE_T eSysPcoPhase; + + P_DOMAIN_INFO_ENTRY prDomainInfo; + + /* QM */ + QUE_MGT_T rQM; + + CNM_INFO_T rCnmInfo; + + UINT_32 u4PowerMode; + + UINT_32 u4CtiaPowerMode; + BOOLEAN fgEnCtiaPowerMode; + + UINT_32 fgEnArpFilter; + + UINT_32 u4UapsdAcBmp; + + UINT_32 u4MaxSpLen; + + UINT_32 u4PsCurrentMeasureEn; + + /* Version Information */ + WIFI_VER_INFO_T rVerInfo; + + /* 5GHz support (from F/W) */ + BOOLEAN fgIsHw5GBandDisabled; + BOOLEAN fgEnable5GBand; + BOOLEAN fgIsEepromUsed; + BOOLEAN fgIsEfuseValid; + BOOLEAN fgIsEmbbededMacAddrValid; + + /* Packet Forwarding Tracking */ + INT_32 i4PendingFwdFrameCount; + +#if CFG_SUPPORT_RDD_TEST_MODE + UINT_8 ucRddStatus; +#endif + +};/* end of _ADAPTER_T */ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Macros for BSS_INFO_T - Flag of Net Active */ +/*----------------------------------------------------------------------------*/ +#define IS_NET_ACTIVE(_prAdapter, _NetTypeIndex) \ + (_prAdapter->rWifiVar.arBssInfo[(_NetTypeIndex)].fgIsNetActive) +#define IS_BSS_ACTIVE(_prBssInfo) ((_prBssInfo)->fgIsNetActive) + +#define IS_AIS_ACTIVE(_prAdapter) IS_NET_ACTIVE(_prAdapter, NETWORK_TYPE_AIS_INDEX) +#define IS_P2P_ACTIVE(_prAdapter) IS_NET_ACTIVE(_prAdapter, NETWORK_TYPE_P2P_INDEX) +#define IS_BOW_ACTIVE(_prAdapter) IS_NET_ACTIVE(_prAdapter, NETWORK_TYPE_BOW_INDEX) + +#define SET_NET_ACTIVE(_prAdapter, _NetTypeIndex) \ + {_prAdapter->rWifiVar.arBssInfo[(_NetTypeIndex)].fgIsNetActive = TRUE;} + +#define UNSET_NET_ACTIVE(_prAdapter, _NetTypeIndex) \ + {_prAdapter->rWifiVar.arBssInfo[(_NetTypeIndex)].fgIsNetActive = FALSE;} + +#define BSS_INFO_INIT(_prAdapter, _NetTypeIndex) \ + { UINT_8 _aucZeroMacAddr[] = NULL_MAC_ADDR; \ + P_BSS_INFO_T _prBssInfo = &(_prAdapter->rWifiVar.arBssInfo[(_NetTypeIndex)]); \ + \ + _prBssInfo->eConnectionState = PARAM_MEDIA_STATE_DISCONNECTED; \ + _prBssInfo->eConnectionStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED; \ + _prBssInfo->eCurrentOPMode = OP_MODE_INFRASTRUCTURE; \ + _prBssInfo->fgIsNetActive = FALSE; \ + _prBssInfo->ucNetTypeIndex = (_NetTypeIndex); \ + _prBssInfo->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_RESERVED; \ + COPY_MAC_ADDR(_prBssInfo->aucBSSID, _aucZeroMacAddr); \ + LINK_INITIALIZE(&_prBssInfo->rStaRecOfClientList); \ + _prBssInfo->fgIsBeaconActivated = FALSE; \ + _prBssInfo->ucHwDefaultFixedRateCode = RATE_CCK_1M_LONG; \ + _prBssInfo->fgIsNetAbsent = FALSE; \ + } + +#if CFG_ENABLE_BT_OVER_WIFI +#define BOW_BSS_INFO_INIT(_prAdapter, _NetTypeIndex) \ + { \ + P_BSS_INFO_T _prBssInfo = &(_prAdapter->rWifiVar.arBssInfo[(_NetTypeIndex)]); \ + \ + _prBssInfo->eConnectionState = PARAM_MEDIA_STATE_DISCONNECTED; \ + _prBssInfo->eConnectionStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED; \ + _prBssInfo->eCurrentOPMode = OP_MODE_BOW; \ + _prBssInfo->ucNetTypeIndex = (_NetTypeIndex); \ + _prBssInfo->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_RESERVED; \ + LINK_INITIALIZE(&_prBssInfo->rStaRecOfClientList); \ + _prBssInfo->fgIsBeaconActivated = TRUE; \ + _prBssInfo->ucHwDefaultFixedRateCode = RATE_CCK_1M_LONG; \ + _prBssInfo->fgIsNetAbsent = FALSE; \ + } +#endif + +/*----------------------------------------------------------------------------*/ +/* Macros for Power State */ +/*----------------------------------------------------------------------------*/ +#define SET_NET_PWR_STATE_IDLE(_prAdapter, _NetTypeIndex) \ + {_prAdapter->rWifiVar.aePwrState[(_NetTypeIndex)] = PWR_STATE_IDLE;} + +#define SET_NET_PWR_STATE_ACTIVE(_prAdapter, _NetTypeIndex) \ + {_prAdapter->rWifiVar.aePwrState[(_NetTypeIndex)] = PWR_STATE_ACTIVE;} + +#define SET_NET_PWR_STATE_PS(_prAdapter, _NetTypeIndex) \ + {_prAdapter->rWifiVar.aePwrState[(_NetTypeIndex)] = PWR_STATE_PS;} + +#define IS_NET_PWR_STATE_ACTIVE(_prAdapter, _NetTypeIndex) \ + (_prAdapter->rWifiVar.aePwrState[(_NetTypeIndex)] == PWR_STATE_ACTIVE) + +#define IS_NET_PWR_STATE_IDLE(_prAdapter, _NetTypeIndex) \ + (_prAdapter->rWifiVar.aePwrState[(_NetTypeIndex)] == PWR_STATE_IDLE) + +#define IS_SCN_PWR_STATE_ACTIVE(_prAdapter) \ + (_prAdapter->rWifiVar.rScanInfo.eScanPwrState == SCAN_PWR_STATE_ACTIVE) + +#define IS_SCN_PWR_STATE_IDLE(_prAdapter) \ + (_prAdapter->rWifiVar.rScanInfo.eScanPwrState == SCAN_PWR_STATE_IDLE) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _ADAPTER_H */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/bow.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/bow.h new file mode 100755 index 000000000000..c435fdc99236 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/bow.h @@ -0,0 +1,366 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/nic/bow.h#1 $ +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: bow.h $ + * + * 02 16 2012 chinghwa.yu + * [ALPS00238061] [Need Patch] [Volunteer Patch] Support BOW for 5GHz band. + * + * 05 25 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * Add BoW Cancel Scan Request and Turn On deactive network function. + * + * 05 22 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * Submit missing BoW header files. + * + * 03 27 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add new feature - multiple physical link support. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 06 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Sync BOW Driver to latest person development branch version.. + * + * 02 10 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Fix kernel API change issue. + * Before ALPS 2.2 (2.2 included), kfifo_alloc() is + * struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock); + * After ALPS 2.3, kfifo_alloc() is changed to + * int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask); + * + * 02 10 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Update BOW structure. + * + * 02 09 2011 cp.wu + * [WCXRP00000430] [MT6620 Wi-Fi][Firmware][Driver] Create V1.2 branch for MT6620E1 and MT6620E3 + * create V1.2 driver branch based on label MT6620_WIFI_DRIVER_V1_2_110209_1031 + * with BOW and P2P enabled as default + * + * 02 08 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Replace kfifo_get and kfifo_put with kfifo_out and kfifo_in. + * Update BOW get MAC status, remove returning event for AIS network type. + * + * 01 11 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add Activity Report definition. + * + * 10 18 2010 chinghwa.yu + * [WCXRP00000110] [MT6620 Wi-Fi] [Driver] Fix BoW Connected event size + * Fix wrong BoW event size. + * + * 07 15 2010 cp.wu + * + * sync. bluetooth-over-Wi-Fi interface to driver interface document v0.2.6. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * 1) all BT physical handles shares the same RSSI/Link Quality. + * 2) simplify BT command composing + * + * 04 28 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * change prefix for data structure used to communicate with 802.11 PAL + * to avoid ambiguous naming with firmware interface + * + * 04 27 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * basic implementation for EVENT_BT_OVER_WIFI + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * 3) private data could be hold and taken use for other purpose + * + * 04 09 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * sync. with design document for interface change. + * + * 04 02 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * Wi-Fi driver no longer needs to implement 802.11 PAL, thus replaced by wrapping command/event definitions + * + * 03 16 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * correct typo. + * + * 03 16 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * update for all command/event needed to be supported by 802.11 PAL. + * + * 03 16 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * build up basic data structure and definitions to support BT-over-WiFi + * +*/ + +#ifndef _BOW_H_ +#define _BOW_H_ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define BOWDEVNAME "bow0" + +#define MAX_BOW_NUMBER_OF_CHANNEL_2G4 14 +#define MAX_BOW_NUMBER_OF_CHANNEL_5G 4 +#define MAX_BOW_NUMBER_OF_CHANNEL 18 //(MAX_BOW_NUMBER_OF_CHANNEL_2G4 + MAX_BOW_NUMBER_OF_CHANNEL_5G) + +#define MAX_ACTIVITY_REPORT 2 +#define MAX_ACTIVITY_REPROT_TIME 660 + +#define ACTIVITY_REPORT_STATUS_SUCCESS 0 +#define ACTIVITY_REPORT_STATUS_FAILURE 1 +#define ACTIVITY_REPORT_STATUS_TIME_INVALID 2 +#define ACTIVITY_REPORT_STATUS_OTHERS 3 + +#define ACTIVITY_REPORT_SCHEDULE_UNKNOWN 0 //Does not know the schedule of the interference +#define ACTIVITY_REPORT_SCHEDULE_KNOWN 1 + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef struct _BT_OVER_WIFI_COMMAND_HEADER_T { + UINT_8 ucCommandId; + UINT_8 ucSeqNumber; + UINT_16 u2PayloadLength; +} AMPC_COMMAND_HEADER_T, *P_AMPC_COMMAND_HEADER_T; + +typedef struct _BT_OVER_WIFI_COMMAND { + AMPC_COMMAND_HEADER_T rHeader; + UINT_8 aucPayload[0]; +} AMPC_COMMAND, *P_AMPC_COMMAND; + +typedef struct _BT_OVER_WIFI_EVENT_HEADER_T { + UINT_8 ucEventId; + UINT_8 ucSeqNumber; + UINT_16 u2PayloadLength; +} AMPC_EVENT_HEADER_T, *P_AMPC_EVENT_HEADER_T; + +typedef struct _BT_OVER_WIFI_EVENT { + AMPC_EVENT_HEADER_T rHeader; + UINT_8 aucPayload[0]; +} AMPC_EVENT, *P_AMPC_EVENT; + +typedef struct _CHANNEL_DESC_T { + UINT_8 ucChannelBand; + UINT_8 ucChannelNum; +} CHANNEL_DESC, P_CHANNEL_DESC; + +// Command Structures +typedef struct _BOW_SETUP_CONNECTION { +//Fixed to 2.4G + UINT_8 ucChannelNum; + UINT_8 ucReserved1; + UINT_8 aucPeerAddress[6]; + UINT_16 u2BeaconInterval; + UINT_8 ucTimeoutDiscovery; + UINT_8 ucTimeoutInactivity; + UINT_8 ucRole; + UINT_8 ucPAL_Capabilities; + INT_8 cMaxTxPower; + UINT_8 ucReserved2; + +//Pending, for future BOW 5G supporting. +/* UINT_8 aucPeerAddress[6]; + UINT_16 u2BeaconInterval; + UINT_8 ucTimeoutDiscovery; + UINT_8 ucTimeoutInactivity; + UINT_8 ucRole; + UINT_8 ucPAL_Capabilities; + INT_8 cMaxTxPower; + UINT_8 ucChannelListNum; + CHANNEL_DESC arChannelList[1]; +*/ +} BOW_SETUP_CONNECTION, *P_BOW_SETUP_CONNECTION; + +typedef struct _BOW_DESTROY_CONNECTION { + UINT_8 aucPeerAddress[6]; + UINT_8 aucReserved[2]; +} BOW_DESTROY_CONNECTION, *P_BOW_DESTROY_CONNECTION; + +typedef struct _BOW_SET_PTK { + UINT_8 aucPeerAddress[6]; + UINT_8 aucReserved[2]; + UINT_8 aucTemporalKey[16]; +} BOW_SET_PTK, *P_BOW_SET_PTK; + +typedef struct _BOW_READ_RSSI { + UINT_8 aucPeerAddress[6]; + UINT_8 aucReserved[2]; +} BOW_READ_RSSI, *P_BOW_READ_RSSI; + +typedef struct _BOW_READ_LINK_QUALITY { + UINT_8 aucPeerAddress[6]; + UINT_8 aucReserved[2]; +} BOW_READ_LINK_QUALITY, *P_BOW_READ_LINK_QUALITY; + +typedef struct _BOW_SHORT_RANGE_MODE { + UINT_8 aucPeerAddress[6]; + INT_8 cTxPower; + UINT_8 ucReserved; +} BOW_SHORT_RANGE_MODE, *P_BOW_SHORT_RANGE_MODE; + +// Event Structures +typedef struct _BOW_COMMAND_STATUS { + UINT_8 ucStatus; + UINT_8 ucReserved[3]; +} BOW_COMMAND_STATUS, *P_BOW_COMMAND_STATUS; + +typedef struct _BOW_MAC_STATUS { + UINT_8 aucMacAddr[6]; + UINT_8 ucAvailability; + UINT_8 ucNumOfChannel; + CHANNEL_DESC arChannelList[MAX_BOW_NUMBER_OF_CHANNEL]; +} BOW_MAC_STATUS, *P_BOW_MAC_STATUS; + +typedef struct _BOW_LINK_CONNECTED { + CHANNEL_DESC rChannel; + UINT_8 aucReserved; + UINT_8 aucPeerAddress[6]; +} BOW_LINK_CONNECTED, *P_BOW_LINK_CONNECTED; + +typedef struct _BOW_LINK_DISCONNECTED { + UINT_8 ucReason; + UINT_8 aucReserved; + UINT_8 aucPeerAddress[6]; +} BOW_LINK_DISCONNECTED, *P_BOW_LINK_DISCONNECTED; + +typedef struct _BOW_RSSI { + INT_8 cRssi; + UINT_8 aucReserved[3]; +} BOW_RSSI, *P_BOW_RSSI; + +typedef struct _BOW_LINK_QUALITY { + UINT_8 ucLinkQuality; + UINT_8 aucReserved[3]; +} BOW_LINK_QUALITY, *P_BOW_LINK_QUALITY; + +typedef enum _ENUM_BOW_CMD_ID_T { + BOW_CMD_ID_GET_MAC_STATUS = 1, + BOW_CMD_ID_SETUP_CONNECTION, + BOW_CMD_ID_DESTROY_CONNECTION, + BOW_CMD_ID_SET_PTK, + BOW_CMD_ID_READ_RSSI, + BOW_CMD_ID_READ_LINK_QUALITY, + BOW_CMD_ID_SHORT_RANGE_MODE, + BOW_CMD_ID_GET_CHANNEL_LIST, +} ENUM_BOW_CMD_ID_T, *P_ENUM_BOW_CMD_ID_T; + +typedef enum _ENUM_BOW_EVENT_ID_T { + BOW_EVENT_ID_COMMAND_STATUS = 1, + BOW_EVENT_ID_MAC_STATUS, + BOW_EVENT_ID_LINK_CONNECTED, + BOW_EVENT_ID_LINK_DISCONNECTED, + BOW_EVENT_ID_RSSI, + BOW_EVENT_ID_LINK_QUALITY, + BOW_EVENT_ID_CHANNEL_LIST, + BOW_EVENT_ID_CHANNEL_SELECTED, +} ENUM_BOW_EVENT_ID_T, *P_ENUM_BOW_EVENT_ID_T; + +typedef enum _ENUM_BOW_DEVICE_STATE { + BOW_DEVICE_STATE_DISCONNECTED = 0, + BOW_DEVICE_STATE_DISCONNECTING, + BOW_DEVICE_STATE_ACQUIRING_CHANNEL, + BOW_DEVICE_STATE_STARTING, + BOW_DEVICE_STATE_SCANNING, + BOW_DEVICE_STATE_CONNECTING, + BOW_DEVICE_STATE_CONNECTED, + BOW_DEVICE_STATE_NUM +} ENUM_BOW_DEVICE_STATE, *P_ENUM_BOW_DEVICE_STATE; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +#endif /*_BOW_H */ diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/cmd_buf.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/cmd_buf.h new file mode 100755 index 000000000000..1dcae5533bf0 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/cmd_buf.h @@ -0,0 +1,220 @@ +/* +** $Id: +*/ + +/*! \file "cmd_buf.h" + \brief In this file we define the structure for Command Packet. + + In this file we define the structure for Command Packet and the control unit + of MGMT Memory Pool. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: cmd_buf.h $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by ENUM_NETWORK_TYPE_INDEX_T only + * remove ENUM_NETWORK_TYPE_T definitions + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 07 13 2010 cp.wu + * + * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets + * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending + * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid descriptor underflow under concurrent network operation + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Enable change log +*/ + +#ifndef _CMD_BUF_H +#define _CMD_BUF_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef enum _COMMAND_TYPE { + COMMAND_TYPE_GENERAL_IOCTL, + COMMAND_TYPE_NETWORK_IOCTL, + COMMAND_TYPE_SECURITY_FRAME, + COMMAND_TYPE_MANAGEMENT_FRAME, + COMMAND_TYPE_NUM +} COMMAND_TYPE, *P_COMMAND_TYPE; + +typedef VOID (*PFN_CMD_DONE_HANDLER) ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +typedef VOID (*PFN_CMD_TIMEOUT_HANDLER) ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo + ); + +struct _CMD_INFO_T { + QUE_ENTRY_T rQueEntry; + + COMMAND_TYPE eCmdType; + + UINT_16 u2InfoBufLen; /* This is actual CMD buffer length */ + PUINT_8 pucInfoBuffer; /* May pointer to structure in prAdapter */ + P_NATIVE_PACKET prPacket; /* only valid when it's a security frame */ + + ENUM_NETWORK_TYPE_INDEX_T eNetworkType; + UINT_8 ucStaRecIndex; /* only valid when it's a security frame */ + + PFN_CMD_DONE_HANDLER pfCmdDoneHandler; + PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler; + + BOOLEAN fgIsOid; /* Used to check if we need indicate */ + + UINT_8 ucCID; + BOOLEAN fgSetQuery; + BOOLEAN fgNeedResp; + BOOLEAN fgDriverDomainMCR; /* Access Driver Domain MCR, for CMD_ID_ACCESS_REG only */ + UINT_8 ucCmdSeqNum; + UINT_32 u4SetInfoLen; /* Indicate how many byte we read for Set OID */ + + /* information indicating by OID/ioctl */ + PVOID pvInformationBuffer; + UINT_32 u4InformationBufferLength; + + /* private data */ + UINT_32 u4PrivateData; +}; + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID +cmdBufInitialize ( + IN P_ADAPTER_T prAdapter + ); + +P_CMD_INFO_T +cmdBufAllocateCmdInfo ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Length + ); + +VOID +cmdBufFreeCmdInfo ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo + ); + +/*----------------------------------------------------------------------------*/ +/* Routines for CMDs */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanSendSetQueryCmd ( + IN P_ADAPTER_T prAdapter, + UINT_8 ucCID, + BOOLEAN fgSetQuery, + BOOLEAN fgNeedResp, + BOOLEAN fgIsOid, + PFN_CMD_DONE_HANDLER pfCmdDoneHandler, + PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, + UINT_32 u4SetQueryInfoLen, + PUINT_8 pucInfoBuffer, + OUT PVOID pvSetQueryBuffer, + IN UINT_32 u4SetQueryBufferLen + ); + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#endif /* _CMD_BUF_H */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/hal.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/hal.h new file mode 100755 index 000000000000..df4f0fa3b04e --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/hal.h @@ -0,0 +1,654 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/nic/hal.h#1 $ +*/ + +/*! \file "hal.h" + \brief The declaration of hal functions + + N/A +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: hal.h $ + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 04 01 2011 tsaiyuan.hsu + * [WCXRP00000615] [MT 6620 Wi-Fi][Driver] Fix klocwork issues + * fix the klocwork issues, 57500, 57501, 57502 and 57503. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 07 2011 terry.wu + * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message + * Toggle non-standard debug messages to comments. + * + * 11 08 2010 cp.wu + * [WCXRP00000166] [MT6620 Wi-Fi][Driver] use SDIO CMD52 for enabling/disabling interrupt to reduce transaction period + * change to use CMD52 for enabling/disabling interrupt to reduce SDIO transaction time + * + * 09 01 2010 cp.wu + * NULL + * move HIF CR initialization from where after sdioSetupCardFeature() to wlanAdapterStart() + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * change zero-padding for TX port access to HAL. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer + * + * 01 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. eliminate improper variable in rHifInfo + * * * * 2. block TX/ordinary OID when RF test mode is engaged + * * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode + * * * * 4. correct some HAL implementation +** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-12-16 18:02:26 GMT mtk02752 +** include precomp.h +** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-12-10 16:43:16 GMT mtk02752 +** code clean +** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-11-13 13:54:15 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-11-11 10:36:01 GMT mtk01084 +** modify HAL functions +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-11-09 22:56:28 GMT mtk01084 +** modify HW access routines +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-10-29 19:50:09 GMT mtk01084 +** add new macro HAL_TX_PORT_WR +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-10-23 16:08:10 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-10-13 21:58:50 GMT mtk01084 +** update for new HW architecture design +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-05-18 14:28:10 GMT mtk01084 +** fix issue in HAL_DRIVER_OWN_BY_SDIO_CMD52() +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-05-11 17:26:33 GMT mtk01084 +** modify the bit definition to check driver own status +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-28 10:30:22 GMT mtk01461 +** Fix typo +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-01 10:50:34 GMT mtk01461 +** Redefine HAL_PORT_RD/WR macro for SW pre test +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-24 09:46:49 GMT mtk01084 +** fix LINT error +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-23 16:53:38 GMT mtk01084 +** add HAL_DRIVER_OWN_BY_SDIO_CMD52() +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-18 20:53:13 GMT mtk01426 +** Fixed lint warn +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:20 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _HAL_H +#define _HAL_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/* Macros for flag operations for the Adapter structure */ +#define HAL_SET_FLAG(_M, _F) ((_M)->u4HwFlags |= (_F)) +#define HAL_CLEAR_FLAG(_M, _F) ((_M)->u4HwFlags &= ~(_F)) +#define HAL_TEST_FLAG(_M, _F) ((_M)->u4HwFlags & (_F)) +#define HAL_TEST_FLAGS(_M, _F) (((_M)->u4HwFlags & (_F)) == (_F)) + +#if defined(_HIF_SDIO) +#define HAL_MCR_RD(_prAdapter, _u4Offset, _pu4Value) \ + { \ + if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == FALSE) { \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + if (kalDevRegRead(_prAdapter->prGlueInfo, _u4Offset, _pu4Value) == FALSE) {\ + HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ + fgIsBusAccessFailed = TRUE; \ + DBGLOG(HAL, ERROR, ("HAL_MCR_RD access fail! 0x%x: 0x%x \n", _u4Offset, *_pu4Value)); \ + } \ + } else { \ + DBGLOG(HAL, WARN, ("ignore HAL_MCR_RD access! 0x%x\n", _u4Offset)); \ + } \ + } + +#define HAL_MCR_WR(_prAdapter, _u4Offset, _u4Value) \ + { \ + if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == FALSE) { \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + if (kalDevRegWrite(_prAdapter->prGlueInfo, _u4Offset, _u4Value) == FALSE) {\ + HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ + fgIsBusAccessFailed = TRUE; \ + DBGLOG(HAL, ERROR, ("HAL_MCR_WR access fail! 0x%x: 0x%x \n", _u4Offset, _u4Value)); \ + } \ + } else { \ + DBGLOG(HAL, WARN, ("ignore HAL_MCR_WR access! 0x%x: 0x%x \n", _u4Offset, _u4Value)); \ + } \ + } + +#define HAL_PORT_RD(_prAdapter, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ + { \ + /*fgResult = FALSE; */\ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == FALSE) { \ + if (kalDevPortRead(_prAdapter->prGlueInfo, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) == FALSE) {\ + HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ + fgIsBusAccessFailed = TRUE; \ + DBGLOG(HAL, ERROR, ("HAL_PORT_RD access fail! 0x%x\n", _u4Port)); \ + } \ + else { \ + /*fgResult = TRUE;*/ } \ + } else { \ + DBGLOG(HAL, WARN, ("ignore HAL_PORT_RD access! 0x%x\n", _u4Port)); \ + } \ + } + +#define HAL_PORT_WR(_prAdapter, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ + { \ + /*fgResult = FALSE; */\ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == FALSE) { \ + if (kalDevPortWrite(_prAdapter->prGlueInfo, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) == FALSE) {\ + HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ + fgIsBusAccessFailed = TRUE; \ + DBGLOG(HAL, ERROR, ("HAL_PORT_WR access fail! 0x%x\n", _u4Port)); \ + } \ + else { \ + /*fgResult = TRUE;*/ } \ + } else { \ + DBGLOG(HAL, WARN, ("ignore HAL_PORT_WR access! 0x%x\n", _u4Port)); \ + } \ + } + +#define HAL_BYTE_WR(_prAdapter, _u4Port, _ucBuf) \ + { \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == FALSE) { \ + if (kalDevWriteWithSdioCmd52(_prAdapter->prGlueInfo, _u4Port, _ucBuf) == FALSE) {\ + HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ + fgIsBusAccessFailed = TRUE; \ + DBGLOG(HAL, ERROR, ("HAL_BYTE_WR access fail! 0x%x\n", _u4Port)); \ + } \ + else { \ + } \ + } \ + else { \ + DBGLOG(HAL, WARN, ("ignore HAL_BYTE_WR access! 0x%x\n", _u4Port)); \ + } \ + } + + +#define HAL_DRIVER_OWN_BY_SDIO_CMD52(_prAdapter, _pfgDriverIsOwnReady) \ + { \ + UINT_8 ucBuf = BIT(1); \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == FALSE) { \ + if (kalDevReadAfterWriteWithSdioCmd52(_prAdapter->prGlueInfo, MCR_WHLPCR_BYTE1, &ucBuf, 1) == FALSE) {\ + HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ + fgIsBusAccessFailed = TRUE; \ + DBGLOG(HAL, ERROR, ("kalDevReadAfterWriteWithSdioCmd52 access fail!\n")); \ + } \ + else { \ + *_pfgDriverIsOwnReady = (ucBuf & BIT(0)) ? TRUE : FALSE; \ + } \ + } else { \ + DBGLOG(HAL, WARN, ("ignore HAL_DRIVER_OWN_BY_SDIO_CMD52 access!\n")); \ + } \ + } + +#else /* #if defined(_HIF_SDIO) */ +#define HAL_MCR_RD(_prAdapter, _u4Offset, _pu4Value) \ + { \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + kalDevRegRead(_prAdapter->prGlueInfo, _u4Offset, _pu4Value); \ + } + +#define HAL_MCR_WR(_prAdapter, _u4Offset, _u4Value) \ + { \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + kalDevRegWrite(_prAdapter->prGlueInfo, _u4Offset, _u4Value); \ + } + +#define HAL_PORT_RD(_prAdapter, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ + { \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + kalDevPortRead(_prAdapter->prGlueInfo, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize); \ + } + +#define HAL_PORT_WR(_prAdapter, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ + { \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + kalDevPortWrite(_prAdapter->prGlueInfo, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize); \ + } + +#define HAL_BYTE_WR(_prAdapter, _u4Port, _ucBuf) \ + { \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + kalDevWriteWithSdioCmd52(_prAdapter->prGlueInfo, _u4Port, _ucBuf); \ + } + +#endif /* #if defined(_HIF_SDIO) */ + + +#define HAL_READ_RX_PORT(prAdapter, u4PortId, u4Len, pvBuf, _u4ValidBufSize) \ + { \ + ASSERT(u4PortId < 2); \ + HAL_PORT_RD(prAdapter, \ + ((u4PortId == 0) ? MCR_WRDR0 : MCR_WRDR1), \ + u4Len, \ + pvBuf, \ + _u4ValidBufSize/*temp!!*//*4Kbyte*/) \ + } + +#define HAL_WRITE_TX_PORT(_prAdapter, _ucTxPortIdx, _u4Len, _pucBuf, _u4ValidBufSize) \ + { \ + ASSERT(_ucTxPortIdx < 2); \ + if((_u4ValidBufSize - _u4Len) >= sizeof(UINT_32)) { \ + /* fill with single dword of zero as TX-aggregation termination */ \ + *(PUINT_32) (&((_pucBuf)[ALIGN_4(_u4Len)])) = 0; \ + } \ + HAL_PORT_WR(_prAdapter, \ + (_ucTxPortIdx == 0) ? MCR_WTDR0 : MCR_WTDR1, \ + _u4Len, \ + _pucBuf, \ + _u4ValidBufSize/*temp!!*//*4KByte*/) \ + } + +/* The macro to read the given MCR several times to check if the wait + condition come true. */ +#define HAL_MCR_RD_AND_WAIT(_pAdapter, _offset, _pReadValue, _waitCondition, _waitDelay, _waitCount, _status) \ + { \ + UINT_32 count; \ + (_status) = FALSE; \ + for (count = 0; count < (_waitCount); count++) { \ + HAL_MCR_RD((_pAdapter), (_offset), (_pReadValue)); \ + if ((_waitCondition)) { \ + (_status) = TRUE; \ + break; \ + } \ + kalUdelay((_waitDelay)); \ + } \ + } + + +/* The macro to write 1 to a R/S bit and read it several times to check if the + command is done */ +#define HAL_MCR_WR_AND_WAIT(_pAdapter, _offset, _writeValue, _busyMask, _waitDelay, _waitCount, _status) \ + { \ + UINT_32 u4Temp; \ + UINT_32 u4Count = _waitCount; \ + (_status) = FALSE; \ + HAL_MCR_WR((_pAdapter), (_offset), (_writeValue)); \ + do { \ + kalUdelay((_waitDelay)); \ + HAL_MCR_RD((_pAdapter), (_offset), &u4Temp); \ + if (!(u4Temp & (_busyMask))) { \ + (_status) = TRUE; \ + break; \ + } \ + u4Count--; \ + } while (u4Count); \ + } + +#define HAL_GET_CHIP_ID_VER(_prAdapter, pu2ChipId, pu2Version) \ + { \ + UINT_32 u4Value; \ + HAL_MCR_RD(_prAdapter, \ + MCR_WCIR, \ + &u4Value); \ + *pu2ChipId = (UINT_16)(u4Value & WCIR_CHIP_ID); \ + *pu2Version = (UINT_16)(u4Value & WCIR_REVISION_ID) >> 16; \ + } + +#define HAL_WAIT_WIFI_FUNC_READY(_prAdapter) \ + { \ + UINT_32 u4Value; \ + UINT_32 i; \ + for (i = 0; i < 100; i++) { \ + HAL_MCR_RD(_prAdapter, \ + MCR_WCIR, \ + &u4Value); \ + if (u4Value & WCIR_WLAN_READY) { \ + break; \ + } \ + NdisMSleep(10); \ + } \ + } + +#define HAL_INTR_DISABLE(_prAdapter) \ + HAL_MCR_WR(_prAdapter, \ + MCR_WHLPCR, \ + WHLPCR_INT_EN_CLR) + +#define HAL_INTR_ENABLE(_prAdapter) \ + HAL_MCR_WR(_prAdapter, \ + MCR_WHLPCR, \ + WHLPCR_INT_EN_SET) + +#define HAL_INTR_ENABLE_AND_LP_OWN_SET(_prAdapter) \ + HAL_MCR_WR(_prAdapter, \ + MCR_WHLPCR, \ + (WHLPCR_INT_EN_SET | WHLPCR_FW_OWN_REQ_SET)) + +#define HAL_LP_OWN_SET(_prAdapter) \ + HAL_MCR_WR(_prAdapter, \ + MCR_WHLPCR, \ + WHLPCR_FW_OWN_REQ_SET) + +#define HAL_LP_OWN_CLR_OK(_prAdapter, _pfgResult) \ + { \ + UINT_32 i; \ + UINT_32 u4RegValue; \ + UINT_32 u4LoopCnt = 2048 / 8; \ + *_pfgResult = TRUE; \ + /* Software get LP ownership */ \ + HAL_MCR_WR(_prAdapter, \ + MCR_WHLPCR, \ + WHLPCR_FW_OWN_REQ_CLR) \ + for (i = 0; i < u4LoopCnt; i++) { \ + HAL_MCR_RD(_prAdapter, MCR_WHLPCR, &u4RegValue); \ + if (u4RegValue & WHLPCR_IS_DRIVER_OWN) { \ + break; \ + } \ + else { \ + kalUdelay(8); \ + } \ + } \ + if (i == u4LoopCnt) { \ + *_pfgResult = FALSE; \ + /*ERRORLOG(("LP cannot be own back (%ld)", u4LoopCnt));*/ \ + /* check the time of LP instructions need to perform from Sleep to On */ \ + /*ASSERT(0); */ \ + } \ + } + +#define HAL_GET_ABNORMAL_INTERRUPT_REASON_CODE(_prAdapter, pu4AbnormalReason) \ + { \ + HAL_MCR_RD(_prAdapter, \ + MCR_WASR, \ + pu4AbnormalReason); \ + } + + +#define HAL_DISABLE_RX_ENHANCE_MODE(_prAdapter) \ + { \ + UINT_32 u4Value; \ + HAL_MCR_RD(_prAdapter, \ + MCR_WHCR, \ + &u4Value); \ + HAL_MCR_WR(_prAdapter, \ + MCR_WHCR, \ + u4Value & ~WHCR_RX_ENHANCE_MODE_EN); \ + } + +#define HAL_ENABLE_RX_ENHANCE_MODE(_prAdapter) \ + { \ + UINT_32 u4Value; \ + HAL_MCR_RD(_prAdapter, \ + MCR_WHCR, \ + &u4Value); \ + HAL_MCR_WR(_prAdapter, \ + MCR_WHCR, \ + u4Value | WHCR_RX_ENHANCE_MODE_EN); \ + } + +#define HAL_CFG_MAX_HIF_RX_LEN_NUM(_prAdapter, _ucNumOfRxLen) \ + { \ + UINT_32 u4Value, ucNum; \ + ucNum = ((_ucNumOfRxLen >= 16) ? 0 : _ucNumOfRxLen); \ + u4Value = 0; \ + HAL_MCR_RD(_prAdapter, \ + MCR_WHCR, \ + &u4Value); \ + u4Value &= ~WHCR_MAX_HIF_RX_LEN_NUM; \ + u4Value |= ((((UINT_32)ucNum) << 4) & WHCR_MAX_HIF_RX_LEN_NUM); \ + HAL_MCR_WR(_prAdapter, \ + MCR_WHCR, \ + u4Value); \ + } + +#define HAL_SET_INTR_STATUS_READ_CLEAR(prAdapter) \ + { \ + UINT_32 u4Value; \ + HAL_MCR_RD(prAdapter, \ + MCR_WHCR, \ + &u4Value); \ + HAL_MCR_WR(prAdapter, \ + MCR_WHCR, \ + u4Value & ~WHCR_W_INT_CLR_CTRL); \ + prAdapter->prGlueInfo->rHifInfo.fgIntReadClear = TRUE;\ + } + +#define HAL_SET_INTR_STATUS_WRITE_1_CLEAR(prAdapter) \ + { \ + UINT_32 u4Value; \ + HAL_MCR_RD(prAdapter, \ + MCR_WHCR, \ + &u4Value); \ + HAL_MCR_WR(prAdapter, \ + MCR_WHCR, \ + u4Value | WHCR_W_INT_CLR_CTRL); \ + prAdapter->prGlueInfo->rHifInfo.fgIntReadClear = FALSE;\ + } + +/* Note: enhance mode structure may also carried inside the buffer, + if the length of the buffer is long enough */ +#define HAL_READ_INTR_STATUS(prAdapter, length, pvBuf) \ + HAL_PORT_RD(prAdapter, \ + MCR_WHISR, \ + length, \ + pvBuf, \ + length) + +#define HAL_READ_TX_RELEASED_COUNT(_prAdapter, aucTxReleaseCount) \ + { \ + PUINT_32 pu4Value = (PUINT_32)aucTxReleaseCount; \ + HAL_MCR_RD(_prAdapter, \ + MCR_WTSR0, \ + &pu4Value[0]); \ + HAL_MCR_RD(_prAdapter, \ + MCR_WTSR1, \ + &pu4Value[1]); \ + } + +#define HAL_READ_RX_LENGTH(prAdapter, pu2Rx0Len, pu2Rx1Len) \ + { \ + UINT_32 u4Value; \ + u4Value = 0; \ + HAL_MCR_RD(prAdapter, \ + MCR_WRPLR, \ + &u4Value); \ + *pu2Rx0Len = (UINT_16)u4Value; \ + *pu2Rx1Len = (UINT_16)(u4Value >> 16); \ + } + +#define HAL_GET_INTR_STATUS_FROM_ENHANCE_MODE_STRUCT(pvBuf, u2Len, pu4Status) \ + { \ + PUINT_32 pu4Buf = (PUINT_32)pvBuf; \ + *pu4Status = pu4Buf[0]; \ + } + +#define HAL_GET_TX_STATUS_FROM_ENHANCE_MODE_STRUCT(pvInBuf, pu4BufOut, u4LenBufOut) \ + { \ + PUINT_32 pu4Buf = (PUINT_32)pvInBuf; \ + ASSERT(u4LenBufOut >= 8); \ + pu4BufOut[0] = pu4Buf[1]; \ + pu4BufOut[1] = pu4Buf[2]; \ + } + +#define HAL_GET_RX_LENGTH_FROM_ENHANCE_MODE_STRUCT(pvInBuf, pu2Rx0Num, au2Rx0Len, pu2Rx1Num, au2Rx1Len) \ + { \ + PUINT_32 pu4Buf = (PUINT_32)pvInBuf; \ + ASSERT((sizeof(au2Rx0Len) / sizeof(UINT_16)) >= 16); \ + ASSERT((sizeof(au2Rx1Len) / sizeof(UINT_16)) >= 16); \ + *pu2Rx0Num = (UINT_16)pu4Buf[3]; \ + *pu2Rx1Num = (UINT_16)(pu4Buf[3] >> 16); \ + kalMemCopy(au2Rx0Len, &pu4Buf[4], 8); \ + kalMemCopy(au2Rx1Len, &pu4Buf[12], 8); \ + } + +#define HAL_GET_MAILBOX_FROM_ENHANCE_MODE_STRUCT(pvInBuf, pu4Mailbox0, pu4Mailbox1) \ + { \ + PUINT_32 pu4Buf = (PUINT_32)pvInBuf; \ + *pu4Mailbox0 = (UINT_16)pu4Buf[21]; \ + *pu4Mailbox1 = (UINT_16)pu4Buf[22]; \ + } + +#define HAL_IS_TX_DONE_INTR(u4IntrStatus) \ + ((u4IntrStatus & WHISR_TX_DONE_INT) ? TRUE : FALSE) + +#define HAL_IS_RX_DONE_INTR(u4IntrStatus) \ + ((u4IntrStatus & (WHISR_RX0_DONE_INT | WHISR_RX1_DONE_INT)) ? TRUE : FALSE) + +#define HAL_IS_ABNORMAL_INTR(u4IntrStatus) \ + ((u4IntrStatus & WHISR_ABNORMAL_INT) ? TRUE : FALSE) + +#define HAL_IS_FW_OWNBACK_INTR(u4IntrStatus) \ + ((u4IntrStatus & WHISR_FW_OWN_BACK_INT) ? TRUE : FALSE) + +#define HAL_PUT_MAILBOX(prAdapter, u4MboxId, u4Data) \ + { \ + ASSERT(u4MboxId < 2); \ + HAL_MCR_WR(prAdapter, \ + ((u4MboxId == 0) ? MCR_H2DSM0R : MCR_H2DSM1R), \ + u4Data); \ + } + +#define HAL_GET_MAILBOX(prAdapter, u4MboxId, pu4Data) \ + { \ + ASSERT(u4MboxId < 2); \ + HAL_MCR_RD(prAdapter, \ + ((u4MboxId == 0) ? MCR_D2HRM0R : MCR_D2HRM1R), \ + pu4Data); \ + } + +#define HAL_SET_MAILBOX_READ_CLEAR(prAdapter, fgEnableReadClear) \ + { \ + UINT_32 u4Value; \ + HAL_MCR_RD(prAdapter, MCR_WHCR, &u4Value);\ + HAL_MCR_WR(prAdapter, MCR_WHCR, \ + (fgEnableReadClear) ? \ + (u4Value | WHCR_W_MAILBOX_RD_CLR_EN) : \ + (u4Value & ~WHCR_W_MAILBOX_RD_CLR_EN)); \ + prAdapter->prGlueInfo->rHifInfo.fgMbxReadClear = fgEnableReadClear;\ + } + +#define HAL_GET_MAILBOX_READ_CLEAR(prAdapter) (prAdapter->prGlueInfo->rHifInfo.fgMbxReadClear) + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _HAL_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/hif_emu.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/hif_emu.h new file mode 100755 index 000000000000..7a74a00ab4ba --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/hif_emu.h @@ -0,0 +1,308 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/nic/hif_emu.h#1 $ +*/ +/*! \file hif.h" + \brief Sdio specific structure for GLUE layer on WinXP + + Sdio specific structure for GLUE layer on WinXP +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: hif_emu.h $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-11-04 14:11:18 GMT mtk01084 +** add new test func +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-10-30 18:17:42 GMT mtk01084 +** modify return value +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-10-29 19:50:45 GMT mtk01084 +** add emu test cases +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-10-23 16:08:54 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-10-23 16:08:16 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-10-13 21:27:05 GMT mtk01084 +** +*/ + +#ifndef _HIF_EMU_H +#define _HIF_EMU_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum +{ + HIF_TC_MBOX_LB = 0x100, + HIF_TC_SW_INT, + HIF_TC_COUNT_INCREASE, + HIF_TC_COUNT_RESET, + HIF_TC_TX_SINGLE_PACKET, + HIF_TC_TX_AGG_PACKET, + HIF_TC_TX_CLEAR_TC_COUNT, + HIF_TC_TX_CHK_STATE, + HIF_TC_RX_SINGLE_PACKET = 0x200, + HIF_TC_RX_PACKET_LEN, + HIF_TC_RX_PACKET_LEN_OVERFLOW, + HIF_TC_RX_AGG_PACKET, + HIF_TC_RX_CHK_STATE, + HIF_TC_RX_SW_PKT_FORMAT, + HIF_TC_RX_READ_HALF, + HIF_TC_MIX_TX_RX_STRESS, + HIF_TC_INTR_ENHANCE, + HIF_TC_RX_ENHANCE_MODE, + HIF_TC_TX_BURST, + HIF_TC_RX_BURST, +} HIF_TEST_CASE; + +#define HIF_TEST_CASE_START BIT(16) + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID +emuInit ( + IN P_ADAPTER_T prAdapter + ); + +BOOLEAN +emuStart ( + IN P_ADAPTER_T prAdapter + ); + + +BOOLEAN +emuInitChkCis ( + IN P_ADAPTER_T prAdapter + ); + +BOOLEAN +emuMailboxLoopback ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgReadClearChk + ); + +BOOLEAN +emuSoftwareInterruptLoopback ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIntrReadClear + ); + +BOOLEAN +emuCheckTxCount ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgReadByIntrEnhanMode + ); + +BOOLEAN +emuSendPacket1 ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4PortId, + IN BOOLEAN fgUseEnhanceModeRead + ); + +BOOLEAN +emuSendPacketAggN ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4PortId, + IN UINT_32 u4AggNum, + IN UINT_32 u4LenStart, + IN UINT_32 u4LenEnd, + IN BOOLEAN fgUseIntrEnhanceModeRead + ); + +BOOLEAN +emuReadHalfRxPacket ( + IN P_ADAPTER_T prAdapter + ); + +BOOLEAN +emuLPown_ownback_stress ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4LoopCount + ); + +BOOLEAN +emuLPown_illegal_access ( + IN P_ADAPTER_T prAdapter + ); + +BOOLEAN +emuIntrEnhanceChk ( + IN P_ADAPTER_T prAdapter + ); + +BOOLEAN +emuResetTxCount ( + IN P_ADAPTER_T prAdapter + ); + +BOOLEAN +emuChkTxState ( + IN P_ADAPTER_T prAdapter + ); + +BOOLEAN +emuChkRxState ( + IN P_ADAPTER_T prAdapter + ); + +BOOLEAN +emuRxPacket1 ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4PortId, + IN UINT_32 u4RxLen, + IN BOOLEAN fgEnIntrEnhanceMode, + IN BOOLEAN fgEnRxEnhanceMode, + IN BOOLEAN fgMBoxReadClearByRxEnhance + ); + +BOOLEAN +emuRxPacketLenChk ( + IN P_ADAPTER_T prAdapter + ); + +BOOLEAN +emuRxPacketAggN ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4PortId, + IN BOOLEAN fgEnRxEnhanceMode, + IN UINT_32 u4RxLen, + IN UINT_32 u4AggNum, + IN UINT_32 u4MaxReadAggNum//0: unlimited + ); + +BOOLEAN +emuRxPacketSwHdrFormat ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4PortId, + IN UINT_32 u4RxLen, + IN UINT_32 u4Num + ); + +BOOLEAN +emuRxPacketLenOverflow ( + IN P_ADAPTER_T prAdapter + ); + +BOOLEAN +emuTxPacketBurstInSwHdrFormat ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgEnable + ); + +BOOLEAN +emuRxPacketBurstInSwHdrFormat ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgEnable + ); + +BOOLEAN +emuSendPacketAggNSwHdrFormat ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4PortId, + IN UINT_32 u4LenStart + ); + +#define RUN_TEST_CASE(_Fmt) \ + { \ + if (status == FALSE) { \ + break; \ + } \ + if (_Fmt == FALSE) { \ + status = FALSE; \ + break; \ + } \ + } +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _HIF_EMU_H */ + + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/hif_rx.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/hif_rx.h new file mode 100755 index 000000000000..5f9303969ecb --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/hif_rx.h @@ -0,0 +1,271 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/nic/hif_rx.h#1 $ +*/ + +/*! \file "hif_rx.h" + \brief Provide HIF RX Header Information between F/W and Driver + + N/A +*/ +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: hif_rx.h $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 09 01 2010 kevin.huang + * NULL + * Use LINK LIST operation to process SCAN result + * + * 07 16 2010 yarco.yang + * + * 1. Support BSS Absence/Presence Event + * 2. Support STA change PS mode Event + * 3. Support BMC forwarding for AP mode. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * follow-ups for HIF_RX_HEADER_T update: + * 1) add TCL + * 2) add RCPI + * 3) add ChannelNumber + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 09 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add necessary changes to driver data paths. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-12-10 16:44:00 GMT mtk02752 +** code clean +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-12-09 13:59:20 GMT MTK02468 +** Added HIF_RX_HDR parsing macros +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-11-24 19:54:54 GMT mtk02752 +** adopt HIF_RX_HEADER_T in new data path +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-10-29 19:51:19 GMT mtk01084 +** modify FW/ driver interface +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-28 10:33:58 GMT mtk01461 +** Add define of HW_APPENED_LEN +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-01 10:51:02 GMT mtk01461 +** Rename ENUM_HIF_RX_PKT_TYPE_T +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-19 12:05:03 GMT mtk01426 +** Remove __KAL_ATTRIB_PACKED__ and add hifDataTypeCheck() +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-17 20:18:52 GMT mtk01426 +** Add comment to HIF_RX_HEADER_T +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:23 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _HIF_RX_H +#define _HIF_RX_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/*! HIF_RX_HEADER_T */ +// DW 0, Byte 1 +#define HIF_RX_HDR_PACKET_TYPE_MASK BITS(0,1) + +// DW 1, Byte 0 +#define HIF_RX_HDR_HEADER_LEN BITS(2,7) +#define HIF_RX_HDR_HEADER_LEN_OFFSET 2 +#define HIF_RX_HDR_HEADER_OFFSET_MASK BITS(0,1) + +// DW 1, Byte 1 +#define HIF_RX_HDR_80211_HEADER_FORMAT BIT(0) +#define HIF_RX_HDR_DO_REORDER BIT(1) +#define HIF_RX_HDR_PAL BIT(2) +#define HIF_RX_HDR_TCL BIT(3) +#define HIF_RX_HDR_NETWORK_IDX_MASK BITS(4,7) +#define HIF_RX_HDR_NETWORK_IDX_OFFSET 4 + +// DW 1, Byte 2, 3 +#define HIF_RX_HDR_SEQ_NO_MASK BITS(0,11) +#define HIF_RX_HDR_TID_MASK BITS(12,14) +#define HIF_RX_HDR_TID_OFFSET 12 +#define HIF_RX_HDR_BAR_FRAME BIT(15) + + + +#define HIF_RX_HDR_FLAG_AMP_WDS BIT(0) +#define HIF_RX_HDR_FLAG_802_11_FORMAT BIT(1) +#define HIF_RX_HDR_FLAG_BAR_FRAME BIT(2) +#define HIF_RX_HDR_FLAG_DO_REORDERING BIT(3) +#define HIF_RX_HDR_FLAG_CTRL_WARPPER_FRAME BIT(4) + +#define HIF_RX_HW_APPENDED_LEN 4 + +// For DW 2, Byte 3 - ucHwChannelNum +#define HW_CHNL_NUM_MAX_2G4 14 +#define HW_CHNL_NUM_MAX_4G_5G (255 - HW_CHNL_NUM_MAX_2G4) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef struct _HIF_RX_HEADER_T { + UINT_16 u2PacketLen; + UINT_16 u2PacketType; + UINT_8 ucHerderLenOffset; + UINT_8 uc80211_Reorder_PAL_TCL; + UINT_16 u2SeqNoTid; + UINT_8 ucStaRecIdx; + UINT_8 ucRcpi; + UINT_8 ucHwChannelNum; + UINT_8 ucReserved; +} HIF_RX_HEADER_T, *P_HIF_RX_HEADER_T; + +typedef enum _ENUM_HIF_RX_PKT_TYPE_T { + HIF_RX_PKT_TYPE_DATA = 0, + HIF_RX_PKT_TYPE_EVENT, + HIF_RX_PKT_TYPE_TX_LOOPBACK, + HIF_RX_PKT_TYPE_MANAGEMENT, + HIF_RX_PKT_TYPE_NUM +} ENUM_HIF_RX_PKT_TYPE_T, *P_ENUM_HIF_RX_PKT_TYPE_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define HIF_RX_HDR_SIZE sizeof(HIF_RX_HEADER_T) + +#define HIF_RX_HDR_GET_80211_FLAG(_prHifRxHdr) \ + (((((_prHifRxHdr)->uc80211_Reorder_PAL_TCL) & HIF_RX_HDR_80211_HEADER_FORMAT) ? TRUE : FALSE)) +#define HIF_RX_HDR_GET_REORDER_FLAG(_prHifRxHdr) \ + (((((_prHifRxHdr)->uc80211_Reorder_PAL_TCL) & HIF_RX_HDR_DO_REORDER) ? TRUE : FALSE)) +#define HIF_RX_HDR_GET_PAL_FLAG(_prHifRxHdr) \ + (((((_prHifRxHdr)->uc80211_Reorder_PAL_TCL) & HIF_RX_HDR_PAL) ? TRUE : FALSE)) +#define HIF_RX_HDR_GET_TCL_FLAG(_prHifRxHdr) \ + (((((_prHifRxHdr)->uc80211_Reorder_PAL_TCL) & HIF_RX_HDR_TCL) ? TRUE : FALSE)) +#define HIF_RX_HDR_GET_NETWORK_IDX(_prHifRxHdr) \ + ((((_prHifRxHdr)->uc80211_Reorder_PAL_TCL) & HIF_RX_HDR_NETWORK_IDX_MASK)\ + >> HIF_RX_HDR_NETWORK_IDX_OFFSET) + + +#define HIF_RX_HDR_GET_TID(_prHifRxHdr) \ + ((((_prHifRxHdr)->u2SeqNoTid) & HIF_RX_HDR_TID_MASK)\ + >> HIF_RX_HDR_TID_OFFSET) +#define HIF_RX_HDR_GET_SN(_prHifRxHdr) \ + (((_prHifRxHdr)->u2SeqNoTid) & HIF_RX_HDR_SEQ_NO_MASK) +#define HIF_RX_HDR_GET_BAR_FLAG(_prHifRxHdr) \ + (((((_prHifRxHdr)->u2SeqNoTid) & HIF_RX_HDR_BAR_FRAME)? TRUE: FALSE)) + + +#define HIF_RX_HDR_GET_CHNL_NUM(_prHifRxHdr) \ + ( ( ((_prHifRxHdr)->ucHwChannelNum) > HW_CHNL_NUM_MAX_4G_5G ) ? \ + ( ((_prHifRxHdr)->ucHwChannelNum) - HW_CHNL_NUM_MAX_4G_5G ) : \ + ((_prHifRxHdr)->ucHwChannelNum) ) + +/* To do: support more bands other than 2.4G and 5G */ +#define HIF_RX_HDR_GET_RF_BAND(_prHifRxHdr) \ + ( ( ((_prHifRxHdr)->ucHwChannelNum) <= HW_CHNL_NUM_MAX_2G4 ) ? \ + BAND_2G4 : BAND_5G) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +__KAL_INLINE__ VOID +hifDataTypeCheck ( + VOID + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/* Kevin: we don't have to call following function to inspect the data structure. + * It will check automatically while at compile time. + * We'll need this for porting driver to different RTOS. + */ +__KAL_INLINE__ VOID +hifDataTypeCheck ( + VOID + ) +{ + DATA_STRUC_INSPECTING_ASSERT(sizeof(HIF_RX_HEADER_T) == 12); + + return; +} + +#endif diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/hif_tx.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/hif_tx.h new file mode 100755 index 000000000000..bf1c823451b9 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/hif_tx.h @@ -0,0 +1,269 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/nic/hif_tx.h#1 $ +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: hif_tx.h $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 10 07 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * add firmware download for MT5931. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * fill extra information for revised HIF_TX_HEADER. + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add flag on MSDU_INFO_T for indicating BIP frame and forceBasicRate + * 2) add packet type for indicating management frames + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 03 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code clean: removing unused variables and structure definitions + * + * 02 09 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address + * * * 2. follow MSDN defined behavior when associates to another AP + * * * 3. for firmware download, packet size could be up to 2048 bytes + * + * 01 13 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Enabled the Burst_End Indication mechanism + * + * 01 13 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * TX: fill ucWlanHeaderLength/ucPktFormtId_Flags according to info provided by prMsduInfo +** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-12-10 16:43:40 GMT mtk02752 +** code clean +** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-11-24 19:55:11 GMT mtk02752 +** adopt HIF_TX_HEADER_T in new data path +** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-11-23 17:54:13 GMT mtk02752 +** CMD_HDR_SIZE = (sizeof(WIFI_CMD_T)) to follow up CM's CMD/EVENT documentation +** +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-11-17 22:41:10 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-11-17 17:34:07 GMT mtk02752 +** remove HIF_TX_BUFF_COUNT_TC0 (move to nic_tx.h) +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-11-17 12:14:12 GMT mtk02752 +** add initial value for HIF_TX_BUFF_COUNT_TC5 +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-11-13 13:54:18 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-11-04 14:11:14 GMT mtk01084 +** modify SW TX data format +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-10-29 19:51:53 GMT mtk01084 +** modify FW/ driver interface +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-05-20 12:22:46 GMT mtk01461 +** Add SeqNum field to CMD Header +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-17 19:40:52 GMT mtk01461 +** Update the Log Sign +*/ + +#ifndef _HIF_TX_H +#define _HIF_TX_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* Maximum buffer size for individual HIF TCQ Buffer */ +#define HIF_TX_BUFF_MAX_SIZE 1552 /* Reserved field was not included */ + +/* Maximum buffer count for individual HIF TCQ */ +#define HIF_TX_BUFF_COUNT_TC0 3 +#define HIF_TX_BUFF_COUNT_TC1 3 +#define HIF_TX_BUFF_COUNT_TC2 3 +#define HIF_TX_BUFF_COUNT_TC3 3 +#define HIF_TX_BUFF_COUNT_TC4 2 + +#define TX_HDR_SIZE sizeof(HIF_TX_HEADER_T) + +#define CMD_HDR_SIZE sizeof(WIFI_CMD_T) + +#define CMD_PKT_SIZE_FOR_IMAGE 2048 /* !< 2048 Bytes CMD payload buffer */ + + +/*! NIC_HIF_TX_HEADER_T */ +// DW 0, Byte 0,1 +#define HIF_TX_HDR_TX_BYTE_COUNT_MASK BITS(0,11) +#define HIF_TX_HDR_USER_PRIORITY_OFFSET 12 + +// DW 0, Byte 2 +#define HIF_TX_HDR_ETHER_TYPE_OFFSET_MASK BITS(0,7) + +// DW 0, Byte 3 +#define HIF_TX_HDR_IP_CSUM BIT(0) +#define HIF_TX_HDR_TCP_CSUM BIT(1) +#define HIF_TX_HDR_RESOURCE_MASK BITS(2,5) +#define HIF_TX_HDR_RESOURCE_OFFSET 2 +#define HIF_TX_HDR_PACKET_TYPE_MASK BITS(6,7) +#define HIF_TX_HDR_PACKET_TYPE_OFFSET 6 + +// DW 1, Byte 0 +#define HIF_TX_HDR_WLAN_HEADER_LEN_MASK BITS(0,5) + +// DW 1, Byte 1 +#define HIF_TX_HDR_FORMAT_ID_MASK BITS(0,2) +#define HIF_TX_HDR_NETWORK_TYPE_MASK BITS(4,5) +#define HIF_TX_HDR_NETWORK_TYPE_OFFSET 4 +#define HIF_TX_HDR_FLAG_1X_FRAME_MASK BIT(6) +#define HIF_TX_HDR_FLAG_1X_FRAME_OFFSET 6 +#define HIF_TX_HDR_FLAG_802_11_FORMAT_MASK BIT(7) +#define HIF_TX_HDR_FLAG_802_11_FORMAT_OFFSET 7 + + +// DW2, Byte 3 +#define HIF_TX_HDR_PS_FORWARDING_TYPE_MASK BITS(0,1) +#define HIF_TX_HDR_PS_SESSION_ID_MASK BITS(2,4) +#define HIF_TX_HDR_PS_SESSION_ID_OFFSET 2 +#define HIF_TX_HDR_BURST_END_MASK BIT(5) +#define HIF_TX_HDR_BURST_END_OFFSET 5 + +// DW3, Byte 1 +#define HIF_TX_HDR_NEED_ACK BIT(0) +#define HIF_TX_HDR_BIP BIT(1) +#define HIF_TX_HDR_BASIC_RATE BIT(2) + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef struct _HIF_HW_TX_HEADER_T { + UINT_16 u2TxByteCount; + UINT_8 ucEtherTypeOffset; + UINT_8 ucCSflags; + UINT_8 aucBuffer[0]; +} HIF_HW_TX_HEADER_T, *P_HIF_HW_TX_HEADER_T; + +typedef struct _HIF_TX_HEADER_T { + UINT_16 u2TxByteCount_UserPriority; + UINT_8 ucEtherTypeOffset; + UINT_8 ucResource_PktType_CSflags; + UINT_8 ucWlanHeaderLength; + UINT_8 ucPktFormtId_Flags; + UINT_16 u2LLH; /* for BOW */ + UINT_16 u2SeqNo; /* for BOW */ + UINT_8 ucStaRecIdx; + UINT_8 ucForwardingType_SessionID_Reserved; + UINT_8 ucPacketSeqNo; + UINT_8 ucAck_BIP_BasicRate; + UINT_8 aucReserved[2]; +} HIF_TX_HEADER_T, *P_HIF_TX_HEADER_T; + +typedef enum _ENUM_HIF_TX_PKT_TYPE_T { + HIF_TX_PKT_TYPE_DATA = 0, + HIF_TX_PKT_TYPE_CMD, + HIF_TX_PKT_TYPE_HIF_LOOPBACK, + HIF_TX_PKT_TYPE_MANAGEMENT, + HIF_TX_PKT_TYPE_NUM +} ENUM_HIF_TX_PKT_TYPE_T, *P_ENUM_HIF_TX_PKT_TYPE_T; + +typedef enum _ENUM_HIF_OOB_CTRL_PKT_TYPE_T { + HIF_OOB_CTRL_PKT_TYPE_LOOPBACK = 1, + HIF_OOB_CTRL_PKT_TYP_NUM +} ENUM_HIF_OOB_CTRL_PKT_TYPE_T, *P_ENUM_HIF_OOB_CTRL_PKT_TYPE_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define TFCB_FRAME_PAD_TO_DW(u2Length) ALIGN_4(u2Length) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/* Kevin: we don't have to call following function to inspect the data structure. + * It will check automatically while at compile time. + */ +__KAL_INLINE__ VOID +hif_txDataTypeCheck ( + VOID + ); + +__KAL_INLINE__ VOID +hif_txDataTypeCheck ( + VOID + ) +{ + DATA_STRUC_INSPECTING_ASSERT(sizeof(HIF_TX_HEADER_T) == 16); + + return; +} + +#endif /*_HIF_TX_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/mac.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/mac.h new file mode 100755 index 000000000000..2253263bdc6f --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/mac.h @@ -0,0 +1,2178 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/nic/mac.h#2 $ +*/ + +/*! \file "mac.h" + \brief Brief description. + + Detail description. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: mac.h $ + * + * 01 16 2012 yuche.tsai + * NULL + * Update Driver for wifi driect gc join IE update issue. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 06 22 2011 wh.su + * [WCXRP00000806] [MT6620 Wi-Fi][Driver] Move the WPA/RSN IE and WAPI IE structure to mac.h and let the sw structure not align at byte + * Move the WAPI / WPA/ RSN IE structure to mac.h and some SW structure not align at byte. + * + * 05 06 2011 wh.su + * [WCXRP00000699] [MT6620 Wi-Fi][Driver] Add the ie pointer check for avoid TP-LINK AP send the wrong beacon make driver got incorrect support rate set + * Add the length check before access the ie length filed. + * + * 05 06 2011 wh.su + * [WCXRP00000699] [MT6620 Wi-Fi][Driver] Add the ie pointer check for avoid TP-LINK AP send the wrong beacon make driver got incorrect support rate set + * adding the length check before processing next ie.. + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 04 12 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 04 10 2011 yuche.tsai + * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. + * Add device discoverability support. (Phase I) + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Some action frame define is not belong to P2P. + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Add some service discovery MAC define, phase I. + * + * 12 13 2010 cp.wu + * [WCXRP00000260] [MT6620 Wi-Fi][Driver][Firmware] Create V1.1 branch for both firmware and driver + * create branch for Wi-Fi driver v1.1 + * + * 12 13 2010 cp.wu + * [WCXRP00000256] [MT6620 Wi-Fi][Driver] Eliminate potential issues which is identified by Klockwork + * suppress warning reported by Klockwork. + * + * 11 01 2010 cp.wu + * [WCXRP00000122] [MT6620 Wi-Fi][Driver] Preparation for YuSu source tree integration + * revert to previous revision. (this file is not necessary to be changed) + * + * 08 20 2010 cm.chang + * NULL + * Migrate RLM code to host from FW + * + * 08 02 2010 yuche.tsai + * NULL + * 1. Add P2P MAC define. + * 2. Add scan device found event + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Add WFA specific OUI. + * + * 06 17 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Add P2P IE ID & Vendor OUI TYPE for P2P. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge MAC.h. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 01 13 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Added OFFSET_BAR_SSC_SN +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-12-09 14:00:24 GMT MTK02468 +** Added offsets and masks for the BA Parameter Set filed +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:26 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _MAC_H +#define _MAC_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +//3 /* --------------- Constants for Ethernet/802.11 MAC --------------- */ +/* MAC Address */ +#define MAC_ADDR_LEN 6 + +#define MAC_ADDR_LOCAL_ADMIN BIT(1) + +#define ETH_P_IPV4 0x0800 +#define ETH_P_IPX 0x8137 // Novell IPX +#define ETH_P_AARP 0x80F3 // AppleTalk Address Resolution Protocol (AARP) +#define ETH_P_IPV6 0x86DD + +#define IP_VERSION_4 4 +#define IP_VERSION_6 6 + +#define IP_PROTOCOL_TCP 6 +#define IP_PROTOCOL_UDP 17 + +#define IPV4_HDR_IP_PROTOCOL_OFFSET 9 +#define IPV4_HDR_IP_CSUM_OFFSET 10 + +#define IPV6_HDR_IP_PROTOCOL_OFFSET 6 + +#define TCP_HDR_TCP_CSUM_OFFSET 16 +#define UDP_HDR_UDP_CSUM_OFFSET 6 + +#define LLC_LEN 8 // LLC(3) + SNAP(3) + EtherType(2) + +#define NULL_MAC_ADDR {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} +#define BC_MAC_ADDR {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} + +/* Ethernet Frame Field Size, in byte */ +#define ETHER_HEADER_LEN 14 +#define ETHER_TYPE_LEN 2 +#define ETHER_MIN_PKT_SZ 60 +#define ETHER_MAX_PKT_SZ 1514 + +/* IEEE 802.11 WLAN Frame Field Size, in byte */ +#define WLAN_MAC_HEADER_LEN 24 /* Address 4 excluded */ +#define WLAN_MAC_HEADER_A4_LEN 30 /* Address 4 included */ +#define WLAN_MAC_HEADER_QOS_LEN 26 /* QoS Control included */ +#define WLAN_MAC_HEADER_QOS_HTC_LEN 30 /* QoS Control and HTC included */ +#define WLAN_MAC_HEADER_A4_QOS_LEN 32 /* Address 4 and QoS Control included */ +#define WLAN_MAC_HEADER_A4_QOS_HTC_LEN 36 /* Address 4, QoS Control and HTC included */ +#define WLAN_MAC_MGMT_HEADER_LEN 24 /* Address 4 excluded */ +#define WLAN_MAC_MGMT_HEADER_HTC_LEN 28 /* HTC included */ + +#define QOS_CTRL_LEN 2 +#define HT_CTRL_LEN 4 + +#define WLAN_MAC_CTS_ACK_LEN WLAN_MAC_CTS_ACK_FRAME_HEADER_LEN + FCS_LEN + +/* 6.2.1.1.2 Semantics of the service primitive */ +#define MSDU_MAX_LENGTH 2304 + +/* 7.1.3.3.3 Broadcast BSSID */ +#define BC_BSSID BC_MAC_ADDR + +/* 7.1.3.7 FCS field */ +#define FCS_LEN 4 + +/* 7.3.1.6 Listen Interval field */ +#define DEFAULT_LISTEN_INTERVAL_BY_DTIM_PERIOD 2 // In unit of AP's DTIM interval, +#define DEFAULT_LISTEN_INTERVAL 10 + +/* 7.3.2.1 Broadcast(Wildcard) SSID */ +#define BC_SSID "" +#define BC_SSID_LEN 0 + +/* 7.3.2.2 Data Rate Value */ +#define RATE_1M 2 /* 1M in unit of 500kb/s */ +#define RATE_2M 4 /* 2M */ +#define RATE_5_5M 11 /* 5.5M */ +#define RATE_11M 22 /* 11M */ +#define RATE_22M 44 /* 22M */ +#define RATE_33M 66 /* 33M */ +#define RATE_6M 12 /* 6M */ +#define RATE_9M 18 /* 9M */ +#define RATE_12M 24 /* 12M */ +#define RATE_18M 36 /* 18M */ +#define RATE_24M 48 /* 24M */ +#define RATE_36M 72 /* 36M */ +#define RATE_48M 96 /* 48M */ +#define RATE_54M 108 /* 54M */ +/* 7.3.2.14 BSS membership selector */ +#define RATE_HT_PHY 127 /* BSS Selector - Clause 20. HT PHY */ +#define RATE_MASK BITS(0,6) /* mask bits for the rate */ +#define RATE_BASIC_BIT BIT(7) /* mask bit for the rate belonging to the BSSBasicRateSet */ + +/* 8.3.2.2 TKIP MPDU formats */ +#define TKIP_MIC_LEN 8 + +/* 9.2.10 DIFS */ +#define DIFS 2 /* 2 x aSlotTime */ + +/* 11.3 STA Authentication and Association */ +#define STA_STATE_1 0 /* Accept Class 1 frames */ +#define STA_STATE_2 1 /* Accept Class 1 & 2 frames */ +#define STA_STATE_3 2 /* Accept Class 1,2 & 3 frames */ + +/* 15.4.8.5 802.11k RCPI-dBm mapping*/ +#define NDBM_LOW_BOUND_FOR_RCPI 110 +#define RCPI_LOW_BOUND 0 +#define RCPI_HIGH_BOUND 220 +#define RCPI_MEASUREMENT_NOT_AVAILABLE 255 + + +/* PHY characteristics */ +/* 17.4.4/18.3.3/19.8.4 Slot Time (aSlotTime) */ +#define SLOT_TIME_LONG 20 /* Long Slot Time */ +#define SLOT_TIME_SHORT 9 /* Short Slot Time */ + +#define SLOT_TIME_HR_DSSS SLOT_TIME_LONG /* 802.11b aSlotTime */ +#define SLOT_TIME_OFDM SLOT_TIME_SHORT /* 802.11a aSlotTime(20M Spacing) */ +#define SLOT_TIME_OFDM_10M_SPACING 13 /* 802.11a aSlotTime(10M Spacing) */ +#define SLOT_TIME_ERP_LONG SLOT_TIME_LONG /* 802.11g aSlotTime(Long) */ +#define SLOT_TIME_ERP_SHORT SLOT_TIME_SHORT /* 802.11g aSlotTime(Short) */ + +/* 17.4.4/18.3.3/19.8.4 Contention Window (aCWmin & aCWmax) */ +#define CWMIN_OFDM 15 /* 802.11a aCWmin */ +#define CWMAX_OFDM 1023 /* 802.11a aCWmax */ + +#define CWMIN_HR_DSSS 31 /* 802.11b aCWmin */ +#define CWMAX_HR_DSSS 1023 /* 802.11b aCWmax */ + +#define CWMIN_ERP_0 31 /* 802.11g aCWmin(0) - for only have 1/2/5/11Mbps Rates */ +#define CWMIN_ERP_1 15 /* 802.11g aCWmin(1) */ +#define CWMAX_ERP 1023 /* 802.11g aCWmax */ + +/* Short Inter-Frame Space (aSIFSTime) */ +/* 15.3.3 802.11b aSIFSTime */ +#define SIFS_TIME_HR_DSSS 10 +/* 17.4.4 802.11a aSIFSTime */ +#define SIFS_TIME_OFDM 16 +/* 19.8.4 802.11g aSIFSTime */ +#define SIFS_TIME_ERP 10 + +/* 15.4.6.2 Number of operating channels */ +#define CH_1 0x1 +#define CH_2 0x2 +#define CH_3 0x3 +#define CH_4 0x4 +#define CH_5 0x5 +#define CH_6 0x6 +#define CH_7 0x7 +#define CH_8 0x8 +#define CH_9 0x9 +#define CH_10 0xa +#define CH_11 0xb +#define CH_12 0xc +#define CH_13 0xd +#define CH_14 0xe + +#define MAXIMUM_OPERATION_CHANNEL_LIST 32 + + +//3 /* --------------- IEEE 802.11 PICS --------------- */ +/* Annex D - dot11OperationEntry 2 */ +#define DOT11_RTS_THRESHOLD_MIN 0 +#define DOT11_RTS_THRESHOLD_MAX 2347 // from Windows DDK +//#define DOT11_RTS_THRESHOLD_MAX 3000 // from Annex D + +#define DOT11_RTS_THRESHOLD_DEFAULT \ + DOT11_RTS_THRESHOLD_MAX + +/* Annex D - dot11OperationEntry 5 */ +#define DOT11_FRAGMENTATION_THRESHOLD_MIN 256 +#define DOT11_FRAGMENTATION_THRESHOLD_MAX 2346 // from Windows DDK +//#define DOT11_FRAGMENTATION_THRESHOLD_MAX 3000 // from Annex D + +#define DOT11_FRAGMENTATION_THRESHOLD_DEFAULT \ + DOT11_FRAGMENTATION_THRESHOLD_MAX + +/* Annex D - dot11OperationEntry 6 */ +#define DOT11_TRANSMIT_MSDU_LIFETIME_TU_MIN 1 +#define DOT11_TRANSMIT_MSDU_LIFETIME_TU_MAX 0xFFFFffff +#define DOT11_TRANSMIT_MSDU_LIFETIME_TU_DEFAULT 4095 // 802.11 define 512 + // MT5921 only aceept N <= 4095 + +/* Annex D - dot11OperationEntry 7 */ +#define DOT11_RECEIVE_LIFETIME_TU_MIN 1 +#define DOT11_RECEIVE_LIFETIME_TU_MAX 0xFFFFffff +#define DOT11_RECEIVE_LIFETIME_TU_DEFAULT 4096 // 802.11 define 512 + +/* Annex D - dot11StationConfigEntry 12 */ +#define DOT11_BEACON_PERIOD_MIN 1 // TU. +#define DOT11_BEACON_PERIOD_MAX 0xffff // TU. +#define DOT11_BEACON_PERIOD_DEFAULT 100 // TU. + +/* Annex D - dot11StationConfigEntry 13 */ +#define DOT11_DTIM_PERIOD_MIN 1 // TU. +#define DOT11_DTIM_PERIOD_MAX 255 // TU. +#define DOT11_DTIM_PERIOD_DEFAULT 1 // TU. + +/* Annex D - dot11RegDomainsSupportValue */ +#define REGULATION_DOMAIN_FCC 0x10 /* FCC (US) */ +#define REGULATION_DOMAIN_IC 0x20 /* IC or DOC (Canada) */ +#define REGULATION_DOMAIN_ETSI 0x30 /* ETSI (Europe) */ +#define REGULATION_DOMAIN_SPAIN 0x31 /* Spain */ +#define REGULATION_DOMAIN_FRANCE 0x32 /* France */ +#define REGULATION_DOMAIN_JAPAN 0x40 /* MKK (Japan) */ +#define REGULATION_DOMAIN_CHINA 0x50 /* China */ +#define REGULATION_DOMAIN_OTHER 0x00 /* Other */ + + + +//3 /* --------------- IEEE 802.11 MAC header fields --------------- */ +/* 7.1.3.1 Masks for the subfields in the Frame Control field */ +#define MASK_FC_PROTOCOL_VER BITS(0,1) +#define MASK_FC_TYPE BITS(2,3) +#define MASK_FC_SUBTYPE BITS(4,7) +#define MASK_FC_SUBTYPE_QOS_DATA BIT(7) +#define MASK_FC_TO_DS BIT(8) +#define MASK_FC_FROM_DS BIT(9) +#define MASK_FC_MORE_FRAG BIT(10) +#define MASK_FC_RETRY BIT(11) +#define MASK_FC_PWR_MGT BIT(12) +#define MASK_FC_MORE_DATA BIT(13) +#define MASK_FC_PROTECTED_FRAME BIT(14) +#define MASK_FC_ORDER BIT(15) + +#define MASK_FRAME_TYPE (MASK_FC_TYPE | MASK_FC_SUBTYPE) +#define MASK_TO_DS_FROM_DS (MASK_FC_TO_DS | MASK_FC_FROM_DS) + +#define MAX_NUM_OF_FC_SUBTYPES 16 +#define OFFSET_OF_FC_SUBTYPE 4 + + +/* 7.1.3.1.2 MAC frame types and subtypes */ +#define MAC_FRAME_TYPE_MGT 0 +#define MAC_FRAME_TYPE_CTRL BIT(2) +#define MAC_FRAME_TYPE_DATA BIT(3) +#define MAC_FRAME_TYPE_QOS_DATA (MAC_FRAME_TYPE_DATA | MASK_FC_SUBTYPE_QOS_DATA) + +#define MAC_FRAME_ASSOC_REQ (MAC_FRAME_TYPE_MGT | 0x0000) +#define MAC_FRAME_ASSOC_RSP (MAC_FRAME_TYPE_MGT | 0x0010) +#define MAC_FRAME_REASSOC_REQ (MAC_FRAME_TYPE_MGT | 0x0020) +#define MAC_FRAME_REASSOC_RSP (MAC_FRAME_TYPE_MGT | 0x0030) +#define MAC_FRAME_PROBE_REQ (MAC_FRAME_TYPE_MGT | 0x0040) +#define MAC_FRAME_PROBE_RSP (MAC_FRAME_TYPE_MGT | 0x0050) +#define MAC_FRAME_BEACON (MAC_FRAME_TYPE_MGT | 0x0080) +#define MAC_FRAME_ATIM (MAC_FRAME_TYPE_MGT | 0x0090) +#define MAC_FRAME_DISASSOC (MAC_FRAME_TYPE_MGT | 0x00A0) +#define MAC_FRAME_AUTH (MAC_FRAME_TYPE_MGT | 0x00B0) +#define MAC_FRAME_DEAUTH (MAC_FRAME_TYPE_MGT | 0x00C0) +#define MAC_FRAME_ACTION (MAC_FRAME_TYPE_MGT | 0x00D0) +#define MAC_FRAME_ACTION_NO_ACK (MAC_FRAME_TYPE_MGT | 0x00E0) + + +#define MAC_FRAME_CONTRL_WRAPPER (MAC_FRAME_TYPE_CTRL | 0x0070) +#define MAC_FRAME_BLOCK_ACK_REQ (MAC_FRAME_TYPE_CTRL | 0x0080) +#define MAC_FRAME_BLOCK_ACK (MAC_FRAME_TYPE_CTRL | 0x0090) +#define MAC_FRAME_PS_POLL (MAC_FRAME_TYPE_CTRL | 0x00A0) +#define MAC_FRAME_RTS (MAC_FRAME_TYPE_CTRL | 0x00B0) +#define MAC_FRAME_CTS (MAC_FRAME_TYPE_CTRL | 0x00C0) +#define MAC_FRAME_ACK (MAC_FRAME_TYPE_CTRL | 0x00D0) +#define MAC_FRAME_CF_END (MAC_FRAME_TYPE_CTRL | 0x00E0) +#define MAC_FRAME_CF_END_CF_ACK (MAC_FRAME_TYPE_CTRL | 0x00F0) + +#define MAC_FRAME_DATA (MAC_FRAME_TYPE_DATA | 0x0000) +#define MAC_FRAME_DATA_CF_ACK (MAC_FRAME_TYPE_DATA | 0x0010) +#define MAC_FRAME_DATA_CF_POLL (MAC_FRAME_TYPE_DATA | 0x0020) +#define MAC_FRAME_DATA_CF_ACK_CF_POLL (MAC_FRAME_TYPE_DATA | 0x0030) +#define MAC_FRAME_NULL (MAC_FRAME_TYPE_DATA | 0x0040) +#define MAC_FRAME_CF_ACK (MAC_FRAME_TYPE_DATA | 0x0050) +#define MAC_FRAME_CF_POLL (MAC_FRAME_TYPE_DATA | 0x0060) +#define MAC_FRAME_CF_ACK_CF_POLL (MAC_FRAME_TYPE_DATA | 0x0070) +#define MAC_FRAME_QOS_DATA (MAC_FRAME_TYPE_DATA | 0x0080) +#define MAC_FRAME_QOS_DATA_CF_ACK (MAC_FRAME_TYPE_DATA | 0x0090) +#define MAC_FRAME_QOS_DATA_CF_POLL (MAC_FRAME_TYPE_DATA | 0x00A0) +#define MAC_FRAME_QOS_DATA_CF_ACK_CF_POLL (MAC_FRAME_TYPE_DATA | 0x00B0) +#define MAC_FRAME_QOS_NULL (MAC_FRAME_TYPE_DATA | 0x00C0) +#define MAC_FRAME_QOS_CF_POLL (MAC_FRAME_TYPE_DATA | 0x00E0) +#define MAC_FRAME_QOS_CF_ACK_CF_POLL (MAC_FRAME_TYPE_DATA | 0x00F0) + +/* 7.1.3.2 Mask for the AID value in the Duration/ID field */ +#define MASK_DI_DURATION BITS(0,14) +#define MASK_DI_AID BITS(0,13) +#define MASK_DI_AID_MSB BITS(14,15) +#define MASK_DI_CFP_FIXED_VALUE BIT(15) + +/* 7.1.3.4 Masks for the subfields in the Sequence Control field */ +#define MASK_SC_SEQ_NUM BITS(4,15) +#define MASK_SC_SEQ_NUM_OFFSET 4 +#define MASK_SC_FRAG_NUM BITS(0,3) +#define INVALID_SEQ_CTRL_NUM 0x000F /* According to 6.2.1.1.2 + * FRAG_NUM won't equal to 15 + */ + +/* 7.1.3.5 QoS Control field */ +#define TID_NUM 16 +#define TID_MASK BITS(0,3) +#define EOSP BIT(4) +#define ACK_POLICY BITS(5,6) +#define A_MSDU_PRESENT BIT(7) + +#define MASK_QC_TID BITS(0,3) +#define MASK_QC_EOSP BIT(4) +#define MASK_QC_EOSP_OFFSET 4 +#define MASK_QC_ACK_POLICY BITS(5, 6) +#define MASK_QC_ACK_POLICY_OFFSET 5 +#define MASK_QC_A_MSDU_PRESENT BIT(7) + +/* 7.1.3.5a HT Control field */ +#define HT_CTRL_LINK_ADAPTATION_CTRL BITS(0,15) +#define HT_CTRL_CALIBRATION_POSITION BITS(16,17) +#define HT_CTRL_CALIBRATION_SEQUENCE BITS(18,19) +#define HT_CTRL_CSI_STEERING BITS(22,23) +#define HT_CTRL_NDP_ANNOUNCEMENT BIT(24) +#define HT_CTRL_AC_CONSTRAINT BIT(30) +#define HT_CTRL_RDG_MORE_PPDU BIT(31) + +#define LINK_ADAPTATION_CTRL_TRQ BIT(1) +#define LINK_ADAPTATION_CTRL_MAI_MRQ BIT(2) +#define LINK_ADAPTATION_CTRL_MAI_MSI BITS(3,5) +#define LINK_ADAPTATION_CTRL_MFSI BITS(6,8) +#define LINK_ADAPTATION_CTRL_MFB_ASELC_CMD BITS(9,11) +#define LINK_ADAPTATION_CTRL_MFB_ASELC_DATA BITS(12,15) + +/* 7.1.3.5.3 Ack Policy subfield*/ +#define ACK_POLICY_NORMAL_ACK_IMPLICIT_BA_REQ 0 +#define ACK_POLICY_NO_ACK 1 +#define ACK_POLICY_NO_EXPLICIT_ACK_PSMP_ACK 2 +#define ACK_POLICY_BA 3 + +/* 7.1.3.7 FCS field */ +#define FCS_LEN 4 + +/* 7.2.1.4 WLAN Control Frame - PS-POLL Frame */ +#define PSPOLL_FRAME_LEN 16 /* w/o FCS */ + +/* 7.2.7.1 BAR */ +#define OFFSET_BAR_SSC_SN 4 + +/* 8.3.2.2 TKIP MPDU formats */ +#define TKIP_MIC_LEN 8 + +/* 2009.11.30 mtk02468: Moved these definitions to the right place */ +#if 0 +/* Block Ack Parameter Set field */ +#define BA_PARM_BA_POLICY BIT(1) +#define BA_PARM_TID BITS(2,5) +#define BA_PARM_BUFFER_SIZE BITS(6,15) +#endif + +#define BA_POLICY_IMMEDIATE BIT(1) + +/* Block Ack Starting Sequence Control field */ +#define BA_START_SEQ_CTL_FRAG_NUM BITS(0,3) +#define BA_START_SEQ_CTL_SSN BITS(4,15) + +/* BAR Control field */ +#define BAR_CONTROL_NO_ACK_POLICY BIT(0) +#define BAR_CONTROL_MULTI_TID BIT(1) +#define BAR_CONTROL_COMPRESSED_BA BIT(2) +#define BAR_CONTROL_TID_INFO BITS(12,15) +#define BAR_CONTROL_TID_INFO_OFFSET 12 + +/* TID Value */ +#define BAR_INFO_TID_VALUE BITS(12,15) + +#define BAR_COMPRESSED_VARIANT_FRAME_LEN (16 + 4) + +//3 /* --------------- IEEE 802.11 frame body fields --------------- */ +//3 Management frame body components (I): Fixed Fields. +/* 7.3.1.1 Authentication Algorithm Number field */ +#define AUTH_ALGORITHM_NUM_FIELD_LEN 2 + +#define AUTH_ALGORITHM_NUM_OPEN_SYSTEM 0 /* Open System */ +#define AUTH_ALGORITHM_NUM_SHARED_KEY 1 /* Shared Key */ +#define AUTH_ALGORITHM_NUM_FAST_BSS_TRANSITION 2 /* Fast BSS Transition */ + +/* 7.3.1.2 Authentication Transaction Sequence Number field */ +#define AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN 2 +#define AUTH_TRANSACTION_SEQ_1 1 +#define AUTH_TRANSACTION_SEQ_2 2 +#define AUTH_TRANSACTION_SEQ_3 3 +#define AUTH_TRANSACTION_SEQ_4 4 + +/* 7.3.1.3 Beacon Interval field */ +#define BEACON_INTERVAL_FIELD_LEN 2 + +/* 7.3.1.4 Capability Information field */ +#define CAP_INFO_FIELD_LEN 2 +#define CAP_INFO_ESS BIT(0) +#define CAP_INFO_IBSS BIT(1) +#define CAP_INFO_BSS_TYPE (CAP_INFO_ESS | CAP_INFO_IBSS) +#define CAP_INFO_CF_POLLABLE BIT(2) +#define CAP_INFO_CF_POLL_REQ BIT(3) +#define CAP_INFO_CF (CAP_INFO_CF_POLLABLE | CAP_INFO_CF_POLL_REQ) +#define CAP_INFO_PRIVACY BIT(4) +#define CAP_INFO_SHORT_PREAMBLE BIT(5) +#define CAP_INFO_PBCC BIT(6) +#define CAP_INFO_CH_AGILITY BIT(7) +#define CAP_INFO_SPEC_MGT BIT(8) +#define CAP_INFO_QOS BIT(9) +#define CAP_INFO_SHORT_SLOT_TIME BIT(10) +#define CAP_INFO_APSD BIT(11) +#define CAP_INFO_RESERVED BIT(12) +#define CAP_INFO_DSSS_OFDM BIT(13) +#define CAP_INFO_DELAYED_BLOCK_ACK BIT(14) +#define CAP_INFO_IMM_BLOCK_ACK BIT(15) +/* STA usage of CF-Pollable and CF-Poll Request subfields */ +/* STA: not CF-Pollable */ +#define CAP_CF_STA_NOT_POLLABLE 0x0000 +/* STA: CF-Pollable, not requesting on the CF-Polling list */ +#define CAP_CF_STA_NOT_ON_LIST CAP_INFO_CF_POLL_REQ +/* STA: CF-Pollable, requesting on the CF-Polling list */ +#define CAP_CF_STA_ON_LIST CAP_INFO_CF_POLLABLE +/* STA: CF-Pollable, requesting never to be polled */ +#define CAP_CF_STA_NEVER_POLLED (CAP_INFO_CF_POLLABLE | CAP_INFO_CF_POLL_REQ) + +/* AP usage of CF-Pollable and CF-Poll Request subfields */ +/* AP: No point coordinator (PC) */ +#define CAP_CF_AP_NO_PC 0x0000 +/* AP: PC at AP for delivery only (no polling) */ +#define CAP_CF_AP_DELIVERY_ONLY CAP_INFO_CF_POLL_REQ +/* AP: PC at AP for delivery and polling */ +#define CAP_CF_AP_DELIVERY_POLLING CAP_INFO_CF_POLLABLE + +/* 7.3.1.5 Current AP Address field */ +#define CURR_AP_ADDR_FIELD_LEN MAC_ADDR_LEN + +/* 7.3.1.6 Listen Interval field */ +#define LISTEN_INTERVAL_FIELD_LEN 2 + +/* 7.3.1.7 Reason Code field */ +#define REASON_CODE_FIELD_LEN 2 + +#define REASON_CODE_RESERVED 0 /* Reseved */ +#define REASON_CODE_UNSPECIFIED 1 /* Unspecified reason */ +#define REASON_CODE_PREV_AUTH_INVALID 2 /* Previous auth no longer valid */ +#define REASON_CODE_DEAUTH_LEAVING_BSS 3 /* Deauth because sending STA is leaving BSS */ +#define REASON_CODE_DISASSOC_INACTIVITY 4 /* Disassoc due to inactivity */ +#define REASON_CODE_DISASSOC_AP_OVERLOAD 5 /* Disassoc because AP is unable to handle all assoc STAs */ +#define REASON_CODE_CLASS_2_ERR 6 /* Class 2 frame rx from nonauth STA */ +#define REASON_CODE_CLASS_3_ERR 7 /* Class 3 frame rx from nonassoc STA */ +#define REASON_CODE_DISASSOC_LEAVING_BSS 8 /* Disassoc because sending STA is leaving BSS */ +#define REASON_CODE_ASSOC_BEFORE_AUTH 9 /* STA requesting (re)assoc is not auth with responding STA */ +#define REASON_CODE_DISASSOC_PWR_CAP_UNACCEPTABLE 10 /* Disassoc because the info in Power Capability is unacceptable */ +#define REASON_CODE_DISASSOC_SUP_CHS_UNACCEPTABLE 11 /* Disassoc because the info in Supported Channels is unacceptable */ +#define REASON_CODE_INVALID_INFO_ELEM 13 /* Invalid information element */ +#define REASON_CODE_MIC_FAILURE 14 /* MIC failure */ +#define REASON_CODE_4_WAY_HANDSHAKE_TIMEOUT 15 /* 4-way handshake timeout */ +#define REASON_CODE_GROUP_KEY_UPDATE_TIMEOUT 16 /* Group key update timeout */ +#define REASON_CODE_DIFFERENT_INFO_ELEM 17 /* Info element in 4-way handshake different from (Re-)associate request/Probe response/Beacon */ +#define REASON_CODE_MULTICAST_CIPHER_NOT_VALID 18 /* Multicast Cipher is not valid */ +#define REASON_CODE_UNICAST_CIPHER_NOT_VALID 19 /* Unicast Cipher is not valid */ +#define REASON_CODE_AKMP_NOT_VALID 20 /* AKMP is not valid */ +#define REASON_CODE_UNSUPPORTED_RSNE_VERSION 21 /* Unsupported RSNE version */ +#define REASON_CODE_INVALID_RSNE_CAPABILITIES 22 /* Invalid RSNE Capabilities */ +#define REASON_CODE_IEEE_802_1X_AUTH_FAILED 23 /* IEEE 802.1X Authentication failed */ +#define REASON_CODE_CIPHER_REJECT_SEC_POLICY 24 /* Cipher suite rejected because of the security policy */ +#define REASON_CODE_DISASSOC_UNSPECIFIED_QOS 32 /* Disassoc for unspecified, QoS-related reason */ +#define REASON_CODE_DISASSOC_LACK_OF_BANDWIDTH 33 /* Disassoc because QAP lacks sufficient bandwidth for this QSTA */ +#define REASON_CODE_DISASSOC_ACK_LOST_POOR_CHANNEL 34 /* Disassoc because of too many ACKs lost for AP transmissions and/or poor channel conditions */ +#define REASON_CODE_DISASSOC_TX_OUTSIDE_TXOP_LIMIT 35 /* Disassoc because QSTA is transmitting outside the limits of its TXOPs */ +#define REASON_CODE_PEER_WHILE_LEAVING 36 /* QSTA is leaving the QBSS or resetting */ +#define REASON_CODE_PEER_REFUSE_DLP 37 /* Peer does not want to use this mechanism */ +#define REASON_CODE_PEER_SETUP_REQUIRED 38 /* Frames received but a setup is reqired */ +#define REASON_CODE_PEER_TIME_OUT 39 /* Time out */ +#define REASON_CODE_PEER_CIPHER_UNSUPPORTED 45 /* Peer does not support the requested cipher suite */ + +/* 7.3.1.8 AID field */ +#define AID_FIELD_LEN 2 +#define AID_MASK BITS(0,13) +#define AID_MSB BITS(14,15) +#define AID_MIN_VALUE 1 +#define AID_MAX_VALUE 2007 + +/* 7.3.1.9 Status Code field */ +#define STATUS_CODE_FIELD_LEN 2 + +#define STATUS_CODE_RESERVED 0 /* Reserved - Used by TX Auth */ +#define STATUS_CODE_SUCCESSFUL 0 /* Successful */ +#define STATUS_CODE_UNSPECIFIED_FAILURE 1 /* Unspecified failure */ +#define STATUS_CODE_CAP_NOT_SUPPORTED 10 /* Cannot support all requested cap in the Cap Info field */ +#define STATUS_CODE_REASSOC_DENIED_WITHOUT_ASSOC 11 /* Reassoc denied due to inability to confirm that assoc exists */ +#define STATUS_CODE_ASSOC_DENIED_OUTSIDE_STANDARD 12 /* Assoc denied due to reason outside the scope of this std. */ +#define STATUS_CODE_AUTH_ALGORITHM_NOT_SUPPORTED 13 /* Responding STA does not support the specified auth algorithm */ +#define STATUS_CODE_AUTH_OUT_OF_SEQ 14 /* Rx an auth frame with auth transaction seq num out of expected seq */ +#define STATUS_CODE_AUTH_REJECTED_CHAL_FAIL 15 /* Auth rejected because of challenge failure */ +#define STATUS_CODE_AUTH_REJECTED_TIMEOUT 16 /* Auth rejected due to timeout waiting for next frame in sequence */ +#define STATUS_CODE_ASSOC_DENIED_AP_OVERLOAD 17 /* Assoc denied because AP is unable to handle additional assoc STAs */ +#define STATUS_CODE_ASSOC_DENIED_RATE_NOT_SUPPORTED 18 /* Assoc denied due to requesting STA not supporting all of basic rates */ +#define STATUS_CODE_ASSOC_DENIED_NO_SHORT_PREAMBLE 19 /* Assoc denied due to requesting STA not supporting short preamble */ +#define STATUS_CODE_ASSOC_DENIED_NO_PBCC 20 /* Assoc denied due to requesting STA not supporting PBCC */ +#define STATUS_CODE_ASSOC_DENIED_NO_CH_AGILITY 21 /* Assoc denied due to requesting STA not supporting channel agility */ +#define STATUS_CODE_ASSOC_REJECTED_NO_SPEC_MGT 22 /* Assoc rejected because Spectrum Mgt capability is required */ +#define STATUS_CODE_ASSOC_REJECTED_PWR_CAP 23 /* Assoc rejected because the info in Power Capability is unacceptable */ +#define STATUS_CODE_ASSOC_REJECTED_SUP_CHS 24 /* Assoc rejected because the info in Supported Channels is unacceptable */ +#define STATUS_CODE_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25 /* Assoc denied due to requesting STA not supporting short slot time */ +#define STATUS_CODE_ASSOC_DENIED_NO_DSSS_OFDM 26 /* Assoc denied due to requesting STA not supporting DSSS-OFDM */ +#if CFG_SUPPORT_802_11W +#define STATUS_CODE_ASSOC_REJECTED_TEMPORARILY 30 /* IEEE 802.11w, Assoc denied due to the SA query */ +#define STATUS_CODE_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31 /* IEEE 802.11w, Assoc denied due to the MFP select policy */ +#endif +#define STATUS_CODE_UNSPECIFIED_QOS_FAILURE 32 /* Unspecified, QoS-related failure */ +#define STATUS_CODE_ASSOC_DENIED_BANDWIDTH 33 /* Assoc denied due to insufficient bandwidth to handle another QSTA */ +#define STATUS_CODE_ASSOC_DENIED_POOR_CHANNEL 34 /* Assoc denied due to excessive frame loss rates and/or poor channel conditions */ +#define STATUS_CODE_ASSOC_DENIED_NO_QOS_FACILITY 35 /* Assoc denied due to requesting STA not supporting QoS facility */ +#define STATUS_CODE_REQ_DECLINED 37 /* Request has been declined */ +#define STATUS_CODE_REQ_INVALID_PARAMETER_VALUE 38 /* Request has not been successful as one or more parameters have invalid values */ +#define STATUS_CODE_REQ_NOT_HONORED_TSPEC 39 /* TS not created because request cannot be honored. Suggested TSPEC provided. */ +#define STATUS_CODE_INVALID_INFO_ELEMENT 40 /* Invalid information element */ +#define STATUS_CODE_INVALID_GROUP_CIPHER 41 /* Invalid group cipher */ +#define STATUS_CODE_INVALID_PAIRWISE_CIPHER 42 /* Invalid pairwise cipher */ +#define STATUS_CODE_INVALID_AKMP 43 /* Invalid AKMP */ +#define STATUS_CODE_UNSUPPORTED_RSN_IE_VERSION 44 /* Unsupported RSN information element version */ +#define STATUS_CODE_INVALID_RSN_IE_CAP 45 /* Invalid RSN information element capabilities */ +#define STATUS_CODE_CIPHER_SUITE_REJECTED 46 /* Cipher suite rejected because of security policy */ +#define STATUS_CODE_REQ_NOT_HONORED_TS_DELAY 47 /* TS not created becasue request cannot be honored. Attempt to create a TS later. */ +#define STATUS_CODE_DIRECT_LINK_NOT_ALLOWED 48 /* Direct Link is not allowed in the BSS by policy */ +#define STATUS_CODE_DESTINATION_STA_NOT_PRESENT 49 /* Destination STA is not present within this QBSS */ +#define STATUS_CODE_DESTINATION_STA_NOT_QSTA 50 /* Destination STA is not a QSTA */ +#define STATUS_CODE_ASSOC_DENIED_LARGE_LIS_INTERVAL 51 /* Association denied because the ListenInterval is too large */ + +/* proprietary definition of reserved field of Status Code */ +#define STATUS_CODE_JOIN_FAILURE 0xFFF0 /* Join failure */ +#define STATUS_CODE_JOIN_TIMEOUT 0xFFF1 /* Join timeout */ +#define STATUS_CODE_AUTH_TIMEOUT 0xFFF2 /* Authentication timeout */ +#define STATUS_CODE_ASSOC_TIMEOUT 0xFFF3 /* (Re)Association timeout */ +#define STATUS_CODE_CCX_CCKM_REASSOC_FAILURE 0xFFF4 /* CCX CCKM reassociation failure */ + + +/* 7.3.1.10 Timestamp field */ +#define TIMESTAMP_FIELD_LEN 8 + +/* 7.3.1.11 Category of Action field */ +#define CATEGORY_SPEC_MGT 0 +#define CATEGORY_QOS_ACTION 1 /* QoS action */ +#define CATEGORY_DLS_ACTION 2 /* Direct Link Protocol (DLP) action */ +#define CATEGORY_BLOCK_ACK_ACTION 3 /* Block ack action */ +#define CATEGORY_PUBLIC_ACTION 4 /* Public action */ +#define CATEGORY_RM_ACTION 5 /* Radio measurement action */ +#define CATEGORY_HT_ACTION 7 +#if CFG_SUPPORT_802_11W +#define CATEGORY_SA_QUERT_ACTION 8 +#endif +#define CATEGORY_WME_MGT_NOTIFICATION 17 /* WME management notification */ +#define CATEGORY_VENDOR_SPECIFIC_ACTION 127 + + +/* 7.3.1.14 Block Ack Parameter Set field */ +#define BA_PARAM_SET_ACK_POLICY_MASK BIT(1) +#define BA_PARAM_SET_ACK_POLICY_MASK_OFFSET 1 +#define BA_PARAM_SET_TID_MASK BITS(2,5) +#define BA_PARAM_SET_TID_MASK_OFFSET 2 +#define BA_PARAM_SET_BUFFER_SIZE_MASK BITS(6,15) +#define BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET 6 + +#define BA_PARAM_SET_ACK_POLICY_IMMEDIATE_BA 1 +#define BA_PARAM_SET_ACK_POLICY_DELAYED_BA 0 + + +//3 Management frame body components (II): Information Elements. +/* 7.3.2 Element IDs of information elements */ +#define ELEM_HDR_LEN 2 + +#define ELEM_ID_SSID 0 /* SSID */ +#define ELEM_ID_SUP_RATES 1 /* Supported rates */ +#define ELEM_ID_FH_PARAM_SET 2 /* FH parameter set */ +#define ELEM_ID_DS_PARAM_SET 3 /* DS parameter set */ +#define ELEM_ID_CF_PARAM_SET 4 /* CF parameter set */ +#define ELEM_ID_TIM 5 /* TIM */ +#define ELEM_ID_IBSS_PARAM_SET 6 /* IBSS parameter set */ +#define ELEM_ID_COUNTRY_INFO 7 /* Country information */ +#define ELEM_ID_HOPPING_PATTERN_PARAM 8 /* Hopping pattern parameters */ +#define ELEM_ID_HOPPING_PATTERN_TABLE 9 /* Hopping pattern table */ +#define ELEM_ID_REQUEST 10 /* Request */ +#define ELEM_ID_BSS_LOAD 11 /* BSS load */ +#define ELEM_ID_EDCA_PARAM_SET 12 /* EDCA parameter set */ +#define ELEM_ID_TSPEC 13 /* Traffic specification (TSPEC) */ +#define ELEM_ID_TCLAS 14 /* Traffic classification (TCLAS) */ +#define ELEM_ID_SCHEDULE 15 /* Schedule */ +#define ELEM_ID_CHALLENGE_TEXT 16 /* Challenge text */ + +#define ELEM_ID_PWR_CONSTRAINT 32 /* Power constraint */ +#define ELEM_ID_PWR_CAP 33 /* Power capability */ +#define ELEM_ID_TPC_REQ 34 /* TPC request */ +#define ELEM_ID_TPC_REPORT 35 /* TPC report */ +#define ELEM_ID_SUP_CHS 36 /* Supported channels */ +#define ELEM_ID_CH_SW_ANNOUNCEMENT 37 /* Channel switch announcement */ +#define ELEM_ID_MEASUREMENT_REQ 38 /* Measurement request */ +#define ELEM_ID_MEASUREMENT_REPORT 39 /* Measurement report */ +#define ELEM_ID_QUIET 40 /* Quiet */ +#define ELEM_ID_IBSS_DFS 41 /* IBSS DFS */ +#define ELEM_ID_ERP_INFO 42 /* ERP information */ +#define ELEM_ID_TS_DELAY 43 /* TS delay */ +#define ELEM_ID_TCLAS_PROCESSING 44 /* TCLAS processing */ +#define ELEM_ID_HT_CAP 45 /* HT Capabilities subelement */ +#define ELEM_ID_QOS_CAP 46 /* QoS capability */ +#define ELEM_ID_RSN 48 /* RSN IE */ +#define ELEM_ID_EXTENDED_SUP_RATES 50 /* Extended supported rates */ +#if CFG_SUPPORT_802_11W +#define ELEM_ID_TIMEOUT_INTERVAL 56 /* 802.11w SA Timeout interval */ +#endif +#define ELEM_ID_HT_OP 61 /* HT Operation */ +#define ELEM_ID_SCO 62 /* Secondary Channel Offset */ +#define ELEM_ID_RRM_ENABLED_CAP 70 /* Radio Resource Management Enabled Capabilities */ +#define ELEM_ID_20_40_BSS_COEXISTENCE 72 /* 20/40 BSS Coexistence */ +#define ELEM_ID_20_40_INTOLERANT_CHNL_REPORT 73 /* 20/40 BSS Intolerant Channel Report */ +#define ELEM_ID_OBSS_SCAN_PARAMS 74 /* Overlapping BSS Scan Parameters */ +#define ELEM_ID_EXTENDED_CAP 127 /* Extended capabilities */ + +#define ELEM_ID_VENDOR 221 /* Vendor specific IE */ +#define ELEM_ID_WPA ELEM_ID_VENDOR /* WPA IE */ +#define ELEM_ID_WMM ELEM_ID_VENDOR /* WMM IE */ +#define ELEM_ID_P2P ELEM_ID_VENDOR /* WiFi Direct */ +#define ELEM_ID_WSC ELEM_ID_VENDOR /* WSC IE */ + +#define ELEM_ID_RESERVED 255 /* Reserved */ + + +/* 7.3.2.1 SSID element */ +#define ELEM_MAX_LEN_SSID 32 + +/* 7.3.2.2 Supported Rates */ +#define ELEM_MAX_LEN_SUP_RATES 8 + +/* 7.3.2.4 DS Parameter Set */ +#define ELEM_MAX_LEN_DS_PARAMETER_SET 1 + +/* 7.3.2.5 CF Parameter Set */ +#define ELEM_CF_PARM_LEN 8 + +/* 7.3.2.6 TIM */ +#define ELEM_MIX_LEN_TIM 4 +#define ELEM_MAX_LEN_TIM 254 + +/* 7.3.2.7 IBSS Parameter Set element */ +#define ELEM_MAX_LEN_IBSS_PARAMETER_SET 2 + +/* 7.3.2.8 Challenge Text element */ +#define ELEM_MIN_LEN_CHALLENGE_TEXT 1 +#define ELEM_MAX_LEN_CHALLENGE_TEXT 253 + +/* 7.3.2.9 Country Information element */ +/* Country IE should contain at least 3-bytes country code string and one subband triplet. */ +#define ELEM_MIN_LEN_COUNTRY_INFO 6 + +#define ELEM_ID_COUNTRY_INFO_TRIPLET_LEN_FIXED 3 +#define ELEM_ID_COUNTRY_INFO_SUBBAND_TRIPLET_LEN_FIXED 3 +#define ELEM_ID_COUNTRY_INFO_REGULATORY_TRIPLET_LEN_FIXED 3 + + +/* 7.3.2.13 ERP Information element */ +#define ELEM_MAX_LEN_ERP 1 +/* -- bits in the ERP Information element */ +#define ERP_INFO_NON_ERP_PRESENT BIT(0) /* NonERP_Present bit */ +#define ERP_INFO_USE_PROTECTION BIT(1) /* Use_Protection bit */ +#define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2) /* Barker_Preamble_Mode bit */ + + +/* 7.3.2.14 Extended Supported Rates */ +#define ELEM_MAX_LEN_EXTENDED_SUP_RATES 255 + +/* 7.3.2.21 Measurement Request element */ +#define ELEM_RM_TYPE_BASIC_REQ 0 +#define ELEM_RM_TYPE_CCA_REQ 1 +#define ELEM_RM_TYPE_RPI_HISTOGRAM_REQ 2 +#define ELEM_RM_TYPE_CHNL_LOAD_REQ 3 +#define ELEM_RM_TYPE_NOISE_HISTOGRAM_REQ 4 +#define ELEM_RM_TYPE_BEACON_REQ 5 +#define ELEM_RM_TYPE_FRAME_REQ 6 +#define ELEM_RM_TYPE_STA_STATISTICS_REQ 7 +#define ELEM_RM_TYPE_LCI_REQ 8 +#define ELEM_RM_TYPE_TS_REQ 9 +#define ELEM_RM_TYPE_MEASURE_PAUSE_REQ 255 + +/* 7.3.2.22 Measurement Report element */ +#define ELEM_RM_TYPE_BASIC_REPORT 0 +#define ELEM_RM_TYPE_CCA_REPORT 1 +#define ELEM_RM_TYPE_RPI_HISTOGRAM_REPORT 2 +#define ELEM_RM_TYPE_CHNL_LOAD_REPORT 3 +#define ELEM_RM_TYPE_NOISE_HISTOGRAM_REPORT 4 +#define ELEM_RM_TYPE_BEACON_REPORT 5 +#define ELEM_RM_TYPE_FRAME_REPORT 6 +#define ELEM_RM_TYPE_STA_STATISTICS_REPORT 7 +#define ELEM_RM_TYPE_LCI_REPORT 8 +#define ELEM_RM_TYPE_TS_REPORT 9 + + +/* 7.3.2.25 RSN information element */ +#define ELEM_MAX_LEN_WPA 24 /* one pairwise, one AKM suite, one PMKID */ +#define ELEM_MAX_LEN_RSN 38 /* one pairwise, one AKM suite, one PMKID */ +#define ELEM_MAX_LEN_WAPI 38 /* one pairwise, one AKM suite, one BKID */ +#define ELEM_MAX_LEN_WSC 200/* one pairwise, one AKM suite, one BKID */ + +#if CFG_SUPPORT_802_11W +#define ELEM_WPA_CAP_MFPR BIT(6) +#define ELEM_WPA_CAP_MFPC BIT(7) +#endif + +/* 7.3.2.27 Extended Capabilities information element */ +#define ELEM_EXT_CAP_20_40_COEXIST_SUPPORT BIT(0) +#define ELEM_EXT_CAP_PSMP_CAP BIT(4) +#define ELEM_EXT_CAP_SERVICE_INTERVAL_GRANULARITY BIT(5) +#define ELEM_EXT_CAP_SCHEDULE_PSMP BIT(6) + +#define ELEM_MAX_LEN_EXT_CAP (3 - ELEM_HDR_LEN) + +/* 7.3.2.30 TSPEC element */ +#define TS_INFO_TRAFFIC_TYPE_MASK BIT(0) //WMM: 0 (Asynchronous TS of low-duty cycles) +#define TS_INFO_TID_OFFSET 1 +#define TS_INFO_TID_MASK BITS(1,4) +#define TS_INFO_DIRECTION_OFFSET 5 +#define TS_INFO_DIRECTION_MASK BITS(5,6) +#define TS_INFO_ACCESS_POLICY_OFFSET 7 +#define TS_INFO_ACCESS_POLICY_MASK BITS(7,8) //WMM: Bit(7,8) = (1,0) = EDCA +#define TS_INFO_AGGREGATION_MASK BIT(9) //WMM: 0 +#define TS_INFO_APSD_MASK BIT(10) +#define TS_INFO_UP_OFFSET 11 +#define TS_INFO_UP_MASK BITS(11,13) +#define TS_INFO_ACK_POLICY_OFFSET 14 +#define TS_INFO_ACK_POLICY_MASK BITS(14,15) +#define TS_INFO_SCHEDULE_MASK 16 + +/* 7.3.2.56 HT capabilities element */ +#define ELEM_MAX_LEN_HT_CAP (28 - ELEM_HDR_LEN) /* sizeof(IE_HT_CAP_T)-2 */ + +/* 7.3.2.56.2 HT capabilities Info field */ +#define HT_CAP_INFO_LDPC_CAP BIT(0) +#define HT_CAP_INFO_SUP_CHNL_WIDTH BIT(1) +#define HT_CAP_INFO_SM_POWER_SAVE BITS(2,3) +#define HT_CAP_INFO_HT_GF BIT(4) +#define HT_CAP_INFO_SHORT_GI_20M BIT(5) +#define HT_CAP_INFO_SHORT_GI_40M BIT(6) +#define HT_CAP_INFO_TX_STBC BIT(7) +#define HT_CAP_INFO_RX_STBC BITS(8,9) +#define HT_CAP_INFO_HT_DELAYED_BA BIT(10) +#define HT_CAP_INFO_MAX_AMSDU_LEN BIT(11) +#define HT_CAP_INFO_DSSS_CCK_IN_40M BIT(12) +#define HT_CAP_INFO_40M_INTOLERANT BIT(14) +#define HT_CAP_INFO_LSIG_TXOP_SUPPORT BIT(15) + +#define HT_CAP_INFO_RX_STBC_NO_SUPPORTED 0 +#define HT_CAP_INFO_RX_STBC_1_SS BIT(8) +#define HT_CAP_INFO_RX_STBC_2_SS BIT(9) +#define HT_CAP_INFO_RX_STBC_3_SS HT_CAP_INFO_RX_STBC + +/* 7.3.2.56.3 A-MPDU Parameters field */ +#define AMPDU_PARAM_MAX_AMPDU_LEN_EXP BITS(0,1) +#define AMPDU_PARAM_MIN_START_SPACING BITS(2,4) + +#define AMPDU_PARAM_MAX_AMPDU_LEN_8K 0 +#define AMPDU_PARAM_MAX_AMPDU_LEN_16K BIT(0) +#define AMPDU_PARAM_MAX_AMPDU_LEN_32K BIT(1) +#define AMPDU_PARAM_MAX_AMPDU_LEN_64K BITS(0,1) + +#define AMPDU_PARAM_MSS_NO_RESTRICIT 0 +#define AMPDU_PARAM_MSS_1_4_US BIT(2) +#define AMPDU_PARAM_MSS_1_2_US BIT(3) +#define AMPDU_PARAM_MSS_1_US BITS(2,3) +#define AMPDU_PARAM_MSS_2_US BIT(4) +#define AMPDU_PARAM_MSS_4_US (BIT(4) | BIT(2)) +#define AMPDU_PARAM_MSS_8_US (BIT(4) | BIT(3)) +#define AMPDU_PARAM_MSS_16_US BITS(2,4) + +/* 7.3.2.56.4 Supported MCS Set field (TX rate: octects 12~15) */ +#define SUP_MCS_TX_SET_DEFINED BIT(0) +#define SUP_MCS_TX_RX_SET_NOT_EQUAL BIT(1) +#define SUP_MCS_TX_MAX_NUM_SS BITS(2,3) +#define SUP_MCS_TX_UNEQUAL_MODULATION BIT(4) + +#define SUP_MCS_TX_MAX_NUM_1_SS 0 +#define SUP_MCS_TX_MAX_NUM_2_SS BIT(2) +#define SUP_MCS_TX_MAX_NUM_3_SS BIT(3) +#define SUP_MCS_TX_MAX_NUM_4_SS BITS(2,3) + +#define SUP_MCS_RX_BITMASK_OCTET_NUM 10 +#define SUP_MCS_RX_DEFAULT_HIGHEST_RATE 0 /* Not specify */ + +/* 7.3.2.56.5 HT Extended Capabilities field */ +#define HT_EXT_CAP_PCO BIT(0) +#define HT_EXT_CAP_PCO_TRANSITION_TIME BITS(1,2) +#define HT_EXT_CAP_MCS_FEEDBACK BITS(8,9) +#define HT_EXT_CAP_HTC_SUPPORT BIT(10) +#define HT_EXT_CAP_RD_RESPONDER BIT(11) + +#define HT_EXT_CAP_PCO_TRANS_TIME_NONE 0 +#define HT_EXT_CAP_PCO_TRANS_TIME_400US BIT(1) +#define HT_EXT_CAP_PCO_TRANS_TIME_1_5MS BIT(2) +#define HT_EXT_CAP_PCO_TRANS_TIME_5MS BITS(1,2) + +#define HT_EXT_CAP_MCS_FEEDBACK_NO_FB 0 +#define HT_EXT_CAP_MCS_FEEDBACK_UNSOLICITED BIT(9) +#define HT_EXT_CAP_MCS_FEEDBACK_BOTH BITS(8,9) + +/* 7.3.2.56.6 Transmit Beamforming Capabilities field */ + +/* 7.3.2.56.7 Antenna Selection Capability field */ +#define ASEL_CAP_CAPABLE BIT(0) +#define ASEL_CAP_CSI_FB_BY_TX_ASEL_CAPABLE BIT(1) +#define ASEL_CAP_ANT_INDICES_FB_BY_TX_ASEL_CAPABLE BIT(2) +#define ASEL_CAP_EXPLICIT_CSI_FB_CAPABLE BIT(3) +#define ASEL_CAP_ANT_INDICES_CAPABLE BIT(4) +#define ASEL_CAP_RX_ASEL_CAPABLE BIT(5) +#define ASEL_CAP_TX_SOUNDING_CAPABLE BIT(6) + +/* 7.3.2.57 HT Operation element */ +#define ELEM_MAX_LEN_HT_OP (24 - ELEM_HDR_LEN) /* sizeof(IE_HT_OP_T)-2 */ + +#define HT_OP_INFO1_SCO BITS(0,1) +#define HT_OP_INFO1_STA_CHNL_WIDTH BIT(2) +#define HT_OP_INFO1_RIFS_MODE BIT(3) + +#define HT_OP_INFO2_HT_PROTECTION BITS(0,1) +#define HT_OP_INFO2_NON_GF_HT_STA_PRESENT BIT(2) +#define HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT BIT(4) + +#define HT_OP_INFO3_DUAL_BEACON BIT(6) +#define HT_OP_INFO3_DUAL_CTS_PROTECTION BIT(7) +#define HT_OP_INFO3_STBC_BEACON BIT(8) +#define HT_OP_INFO3_LSIG_TXOP_FULL_SUPPORT BIT(9) +#define HT_OP_INFO3_PCO_ACTIVE BIT(10) +#define HT_OP_INFO3_PCO_PHASE BIT(11) + +/* 7.3.2.59 OBSS Scan Parameter element */ +#define ELEM_MAX_LEN_OBSS_SCAN (16 - ELEM_HDR_LEN) + +/* 7.3.2.60 20/40 BSS Coexistence element */ +#define ELEM_MAX_LEN_20_40_BSS_COEXIST (3 - ELEM_HDR_LEN) + +#define BSS_COEXIST_INFO_REQ BIT(0) +#define BSS_COEXIST_40M_INTOLERANT BIT(1) +#define BSS_COEXIST_20M_REQ BIT(2) +#define BSS_COEXIST_OBSS_SCAN_EXEMPTION_REQ BIT(3) +#define BSS_COEXIST_OBSS_SCAN_EXEMPTION_GRANT BIT(4) + + +//3 Management frame body components (III): 7.4 Action frame format details. +/* 7.4.1 Spectrum Measurement Action frame details */ +#define ACTION_MEASUREMENT_REQ 0 /* Spectrum measurement request */ +#define ACTION_MEASUREMENT_REPORT 1 /* Spectrum measurement report */ +#define ACTION_TPC_REQ 2 /* TPC request */ +#define ACTION_TPC_REPORT 3 /* TPC report */ +#define ACTION_CHNL_SWITCH 4 /* Channel Switch Announcement */ + +/* 7.4.2 QoS Action frame details */ +#define ACTION_ADDTS_REQ 0 /* ADDTS request */ +#define ACTION_ADDTS_RSP 1 /* ADDTS response */ +#define ACTION_DELTS 2 /* DELTS */ +#define ACTION_SCHEDULE 3 /* Schedule */ + +#define ACTION_ADDTS_REQ_FRAME_LEN (24+3+63) /* WMM TSPEC IE: 63 */ +#define ACTION_ADDTS_RSP_FRAME_LEN (24+4+63) /* WMM Status Code: 1; WMM TSPEC IE: 63*/ + +/* 7.4.3 DLS Action frame details */ +#define ACTION_DLS_REQ 0 /* DLS request */ +#define ACTION_DLS_RSP 1 /* DLS response */ +#define ACTION_DLS_TEARDOWN 2 /* DLS teardown */ + +/* 7.4.4 Block ack Action frame details */ +#define ACTION_ADDBA_REQ 0 /* ADDBA request */ +#define ACTION_ADDBA_RSP 1 /* ADDBA response */ +#define ACTION_DELBA 2 /* DELBA */ + +#define ACTION_ADDBA_REQ_FRAME_LEN (24+9) +#define ACTION_ADDBA_RSP_FRAME_LEN (24+9) + +#define ACTION_DELBA_INITIATOR_MASK BIT(11) +#define ACTION_DELBA_TID_MASK BITS(12,15) +#define ACTION_DELBA_TID_OFFSET 12 +#define ACTION_DELBA_FRAME_LEN (24+6) + +/* 7.4.6 Radio Measurement Action frame details */ +#define ACTION_RM_REQ 0 /* Radio measurement request */ +#define ACTION_RM_REPORT 1 /* Radio measurement report */ +#define ACTION_LM_REQ 2 /* Link measurement request */ +#define ACTION_LM_REPORT 3 /* Link measurement report */ +#define ACTION_NEIGHBOR_REPORT_REQ 4 /* Neighbor report request */ +#define ACTION_NEIGHBOR_REPORT_RSP 5 /* Neighbor report response */ + +/* 7.4.7 Public Action frame details */ +#define ACTION_PUBLIC_20_40_COEXIST 0 /* 20/40 BSS coexistence */ + +#if CFG_SUPPORT_802_11W +/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */ +#define ACTION_SA_QUERY_REQUEST 0 +#define ACTION_SA_QUERY_RESPONSE 1 + +#define ACTION_SA_QUERY_TR_ID_LEN 2 + +/* Timeout Interval Type */ +#define ACTION_SA_TIMEOUT_REASSOC_DEADLINE 1 +#define ACTION_SA_TIMEOUT_KEY_LIFETIME 2 +#define ACTION_SA_TIMEOUT_ASSOC_COMEBACK 3 +#endif + +/* 7.4.10.1 HT action frame details */ +#define ACTION_HT_NOTIFY_CHANNEL_WIDTH 0 /* Notify Channel Width */ +#define ACTION_HT_SM_POWER_SAVE 1 /* SM Power Save */ +#define ACTION_HT_PSMP 2 /* PSMP */ +#define ACTION_HT_SET_PCO_PHASE 3 /* Set PCO Phase */ +#define ACTION_HT_CSI 4 /* CSI */ +#define ACTION_HT_NON_COMPRESSED_BEAMFORM 5 /* Non-compressed Beamforming */ +#define ACTION_HT_COMPRESSED_BEAMFORM 6 /* Compressed Beamforming */ +#define ACTION_HT_ANT_SEL_INDICES_FB 7 /* Antenna Selection Indices Feedback */ + +//3 /* --------------- WFA frame body fields --------------- */ +#define VENDOR_OUI_WFA { 0x00, 0x50, 0xF2 } +#define VENDOR_OUI_WFA_SPECIFIC { 0x50, 0x6F, 0x9A } +#define VENDOR_OUI_TYPE_WPA 1 +#define VENDOR_OUI_TYPE_WMM 2 +#define VENDOR_OUI_TYPE_WPS 4 +#define VENDOR_OUI_TYPE_P2P 9 + +#define VENDOR_OUI_TYPE_LEN 4 /* Length of OUI and Type */ + +/* VERSION(2 octets for WPA) / SUBTYPE(1 octet)-VERSION(1 octet) fields for WMM in WFA IE */ +#define VERSION_WPA 0x0001 /* Little Endian Format */ +#define VENDOR_OUI_SUBTYPE_VERSION_WMM_INFO 0x0100 +#define VENDOR_OUI_SUBTYPE_VERSION_WMM_PARAM 0x0101 + +/* SUBTYPE(1 octet) for WMM */ +#define VENDOR_OUI_SUBTYPE_WMM_INFO 0x00 /* WMM Spec version 1.1 */ +#define VENDOR_OUI_SUBTYPE_WMM_PARAM 0x01 +#define VENDOR_OUI_SUBTYPE_WMM_TSPEC 0x02 + +/* VERSION(1 octet) for WMM */ +#define VERSION_WMM 0x01 /* WMM Spec version 1.1 */ + +/* WMM-2.1.6 QoS Control Field */ +#define WMM_QC_UP_MASK BITS(0,2) +#define WMM_QC_EOSP BIT(4) +#define WMM_QC_ACK_POLICY_MASK BITS(5, 6) +#define WMM_QC_ACK_POLICY_OFFSET 5 +#define WMM_QC_ACK_POLICY_ACKNOWLEDGE 0 +#define WMM_QC_ACK_POLICY_NOT_ACKNOWLEDGE (1 << WMM_QC_ACK_POLICY_OFFSET) + + +/* WMM-2.2.1 WMM Information Element */ +#define ELEM_MIN_LEN_WFA_OUI_TYPE_SUBTYPE 6 + + +//3 Control frame body +/* 7.2.1.7 BlockAckReq */ +#define CTRL_BAR_BAR_CONTROL_OFFSET 16 +#define CTRL_BAR_BAR_INFORMATION_OFFSET 18 + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +#if defined(WINDOWS_DDK) || defined(WINDOWS_CE) +#pragma pack(1) +#endif + +typedef struct _LLC_SNAP_HEADER_T { + UINT_8 ucDSAP; + UINT_8 ucSSAP; + UINT_8 ucControl; + UINT_8 aucCode[3]; + UINT_16 u2Type; +} __KAL_ATTRIB_PACKED__ LLC_SNAP_HEADER_T, *P_LLC_SNAP_HEADER_T; + +//3 MAC Header. +/* Ethernet Frame Header */ +typedef struct _ETH_FRAME_HEADER_T { + UINT_8 aucDestAddr[MAC_ADDR_LEN]; + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; + UINT_16 u2TypeLen; +} __KAL_ATTRIB_PACKED__ ETH_FRAME_HEADER_T, *P_ETH_FRAME_HEADER_T; + +/* Ethernet Frame Structure */ +typedef struct _ETH_FRAME_T { + UINT_8 aucDestAddr[MAC_ADDR_LEN]; + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; + UINT_16 u2TypeLen; + UINT_8 aucData[1]; +} __KAL_ATTRIB_PACKED__ ETH_FRAME_T, *P_ETH_FRAME_T; + + +/* IEEE 802.11 WLAN Frame Structure */ +/* WLAN MAC Header (without Address 4 and QoS Control fields) */ +typedef struct _WLAN_MAC_HEADER_T { + UINT_16 u2FrameCtrl; + UINT_16 u2DurationID; + UINT_8 aucAddr1[MAC_ADDR_LEN]; + UINT_8 aucAddr2[MAC_ADDR_LEN]; + UINT_8 aucAddr3[MAC_ADDR_LEN]; + UINT_16 u2SeqCtrl; +} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_T, *P_WLAN_MAC_HEADER_T; + + +/* WLAN MAC Header (QoS Control fields included) */ +typedef struct _WLAN_MAC_HEADER_QOS_T { + UINT_16 u2FrameCtrl; + UINT_16 u2DurationID; + UINT_8 aucAddr1[MAC_ADDR_LEN]; + UINT_8 aucAddr2[MAC_ADDR_LEN]; + UINT_8 aucAddr3[MAC_ADDR_LEN]; + UINT_16 u2SeqCtrl; + UINT_16 u2QosCtrl; +} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_QOS_T, *P_WLAN_MAC_HEADER_QOS_T; + + +/* WLAN MAC Header (HT Control fields included) */ +typedef struct _WLAN_MAC_HEADER_HT_T { + UINT_16 u2FrameCtrl; + UINT_16 u2DurationID; + UINT_8 aucAddr1[MAC_ADDR_LEN]; + UINT_8 aucAddr2[MAC_ADDR_LEN]; + UINT_8 aucAddr3[MAC_ADDR_LEN]; + UINT_16 u2SeqCtrl; + UINT_16 u2QosCtrl; + UINT_32 u4HtCtrl; +} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_HT_T, *P_WLAN_MAC_HEADER_HT_T; + + +/* WLAN MAC Header (Address 4 included) */ +typedef struct _WLAN_MAC_HEADER_A4_T { + UINT_16 u2FrameCtrl; + UINT_16 u2DurationID; + UINT_8 aucAddr1[MAC_ADDR_LEN]; + UINT_8 aucAddr2[MAC_ADDR_LEN]; + UINT_8 aucAddr3[MAC_ADDR_LEN]; + UINT_16 u2SeqCtrl; + UINT_8 aucAddr4[MAC_ADDR_LEN]; +} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_A4_T, *P_WLAN_MAC_HEADER_A4_T; + + +/* WLAN MAC Header (Address 4 and QoS Control fields included) */ +typedef struct _WLAN_MAC_HEADER_A4_QOS_T { + UINT_16 u2FrameCtrl; + UINT_16 u2DurationID; + UINT_8 aucAddr1[MAC_ADDR_LEN]; + UINT_8 aucAddr2[MAC_ADDR_LEN]; + UINT_8 aucAddr3[MAC_ADDR_LEN]; + UINT_16 u2SeqCtrl; + UINT_8 aucAddr4[MAC_ADDR_LEN]; + UINT_16 u2QosCtrl; +} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_A4_QOS_T, *P_WLAN_MAC_HEADER_A4_QOS_T; + + +typedef struct _WLAN_MAC_HEADER_A4_HT_T { + UINT_16 u2FrameCtrl; + UINT_16 u2DurationID; + UINT_8 aucAddr1[MAC_ADDR_LEN]; + UINT_8 aucAddr2[MAC_ADDR_LEN]; + UINT_8 aucAddr3[MAC_ADDR_LEN]; + UINT_16 u2SeqCtrl; + UINT_8 aucAddr4[MAC_ADDR_LEN]; + UINT_16 u2QosCtrl; + UINT_32 u4HtCtrl; +} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_A4_HT_T, *P_WLAN_MAC_HEADER_A4_HT_T; + + +/* 7.2.3 WLAN MAC Header for Management Frame - MMPDU */ +typedef struct _WLAN_MAC_MGMT_HEADER_T { + UINT_16 u2FrameCtrl; + UINT_16 u2Duration; + UINT_8 aucDestAddr[MAC_ADDR_LEN]; + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; + UINT_8 aucBSSID[MAC_ADDR_LEN]; + UINT_16 u2SeqCtrl; +} __KAL_ATTRIB_PACKED__ WLAN_MAC_MGMT_HEADER_T, *P_WLAN_MAC_MGMT_HEADER_T; + + +/* WLAN MAC Header for Management Frame (HT Control fields included) */ +typedef struct _WLAN_MAC_MGMT_HEADER_HT_T { + UINT_16 u2FrameCtrl; + UINT_16 u2DurationID; + UINT_8 aucAddr1[MAC_ADDR_LEN]; + UINT_8 aucAddr2[MAC_ADDR_LEN]; + UINT_8 aucAddr3[MAC_ADDR_LEN]; + UINT_16 u2SeqCtrl; + UINT_32 u4HtCtrl; +} __KAL_ATTRIB_PACKED__ WLAN_MAC_MGMT_HEADER_HT_T, *P_WLAN_MAC_MGMT_HEADER_HT_T; + +//3 WLAN CONTROL Frame +/* 7.2.1.4 WLAN Control Frame - PS-POLL Frame */ +typedef struct _CTRL_PSPOLL_FRAME_T { + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2AID; /* AID */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_8 aucTA[MAC_ADDR_LEN]; /* TA */ +} __KAL_ATTRIB_PACKED__ CTRL_PSPOLL_FRAME_T, *P_CTRL_PSPOLL_FRAME_T; + + +/* BAR */ +typedef struct _CTRL_BAR_FRAME_T { + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* RA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* TA */ + UINT_16 u2BarControl; + UINT_8 aucBarInfo[2]; /* Variable size */ +} __KAL_ATTRIB_PACKED__ CTRL_BAR_FRAME_T, *P_CTRL_BAR_FRAME_T; + +//3 WLAN Management Frame. +/* 7.2.3.1 WLAN Management Frame - Beacon Frame */ +typedef struct _WLAN_BEACON_FRAME_T { + /* Beacon header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Beacon frame body */ + UINT_32 au4Timestamp[2]; /* Timestamp */ + UINT_16 u2BeaconInterval; /* Beacon Interval */ + UINT_16 u2CapInfo; /* Capability */ + UINT_8 aucInfoElem[1]; /* Various IEs, start from SSID */ +} __KAL_ATTRIB_PACKED__ WLAN_BEACON_FRAME_T, *P_WLAN_BEACON_FRAME_T; + +typedef struct _WLAN_BEACON_FRAME_BODY_T { + /* Beacon frame body */ + UINT_32 au4Timestamp[2]; /* Timestamp */ + UINT_16 u2BeaconInterval; /* Beacon Interval */ + UINT_16 u2CapInfo; /* Capability */ + UINT_8 aucInfoElem[1]; /* Various IEs, start from SSID */ +} __KAL_ATTRIB_PACKED__ WLAN_BEACON_FRAME_BODY_T, *P_WLAN_BEACON_FRAME_BODY_T; + + +/* 7.2.3.3 WLAN Management Frame - Disassociation Frame */ +typedef struct _WLAN_DISASSOC_FRAME_T { + /* Authentication MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Disassociation frame body */ + UINT_16 u2ReasonCode; /* Reason code */ + UINT_8 aucInfoElem[1]; /* Various IEs, possible no. */ +} __KAL_ATTRIB_PACKED__ WLAN_DISASSOC_FRAME_T, *P_WLAN_DISASSOC_FRAME_T; + + +/* 7.2.3.4 WLAN Management Frame - Association Request frame */ +typedef struct _WLAN_ASSOC_REQ_FRAME_T { + /* Association Request MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Association Request frame body */ + UINT_16 u2CapInfo; /* Capability information */ + UINT_16 u2ListenInterval; /* Listen interval */ + UINT_8 aucInfoElem[1]; /* Information elements, include WPA IE */ +} __KAL_ATTRIB_PACKED__ WLAN_ASSOC_REQ_FRAME_T, *P_WLAN_ASSOC_REQ_FRAME_T; + + +/* 7.2.3.5 WLAN Management Frame - Association Response frame */ +typedef struct _WLAN_ASSOC_RSP_FRAME_T { + /* Association Response MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Association Response frame body */ + UINT_16 u2CapInfo; /* Capability information */ + UINT_16 u2StatusCode; /* Status code */ + UINT_16 u2AssocId; /* Association ID */ + UINT_8 aucInfoElem[1]; /* Information elements, such as + supported rates, and etc. */ +} __KAL_ATTRIB_PACKED__ WLAN_ASSOC_RSP_FRAME_T, *P_WLAN_ASSOC_RSP_FRAME_T; + + +/* 7.2.3.6 WLAN Management Frame - Reassociation Request frame */ +typedef struct _WLAN_REASSOC_REQ_FRAME_T { + /* Reassociation Request MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Reassociation Request frame body */ + UINT_16 u2CapInfo; /* Capability information */ + UINT_16 u2ListenInterval; /* Listen interval */ + UINT_8 aucCurrentAPAddr[MAC_ADDR_LEN]; /* Current AP address */ + UINT_8 aucInfoElem[1]; /* Information elements, include WPA IE */ +} __KAL_ATTRIB_PACKED__ WLAN_REASSOC_REQ_FRAME_T, *P_WLAN_REASSOC_REQ_FRAME_T; + + +/* 7.2.3.7 WLAN Management Frame - Reassociation Response frame + (the same as Association Response frame) */ +typedef WLAN_ASSOC_RSP_FRAME_T WLAN_REASSOC_RSP_FRAME_T, *P_WLAN_REASSOC_RSP_FRAME_T; + +/* 7.2.3.9 WLAN Management Frame - Probe Response Frame */ +typedef WLAN_BEACON_FRAME_T WLAN_PROBE_RSP_FRAME_T, *P_WLAN_PROBE_RSP_FRAME_T; + +/* 7.2.3.10 WLAN Management Frame - Authentication Frame */ +typedef struct _WLAN_AUTH_FRAME_T { + /* Authentication MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Authentication frame body */ + UINT_16 u2AuthAlgNum; /* Authentication algorithm number */ + UINT_16 u2AuthTransSeqNo; /* Authentication transaction sequence number */ + UINT_16 u2StatusCode; /* Status code */ + UINT_8 aucInfoElem[1]; /* Various IEs for Fast BSS Transition */ +} __KAL_ATTRIB_PACKED__ WLAN_AUTH_FRAME_T, *P_WLAN_AUTH_FRAME_T; + + +/* 7.2.3.11 WLAN Management Frame - Deauthentication Frame */ +typedef struct _WLAN_DEAUTH_FRAME_T { + /* Authentication MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Deauthentication frame body */ + UINT_16 u2ReasonCode; /* Reason code */ + UINT_8 aucInfoElem[1]; /* Various IEs, possible no. */ +} __KAL_ATTRIB_PACKED__ WLAN_DEAUTH_FRAME_T, *P_WLAN_DEAUTH_FRAME_T; + + + +//3 Information Elements. +/* 7.3.2 Generic element format */ +typedef struct _IE_HDR_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 aucInfo[1]; +} __KAL_ATTRIB_PACKED__ IE_HDR_T, *P_IE_HDR_T; + +/* 7.3.2.1 SSID element */ +typedef struct _IE_SSID_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; +} __KAL_ATTRIB_PACKED__ IE_SSID_T, *P_IE_SSID_T; + +/* 7.3.2.2 Supported Rates element */ +typedef struct _IE_SUPPORTED_RATE_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 aucSupportedRates[ELEM_MAX_LEN_SUP_RATES]; +} __KAL_ATTRIB_PACKED__ IE_SUPPORTED_RATE_T, *P_IE_SUPPORTED_RATE_T; + +/* 7.3.2.4 DS Parameter Set element */ +typedef struct _IE_DS_PARAM_SET_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucCurrChnl; +} __KAL_ATTRIB_PACKED__ IE_DS_PARAM_SET_T, *P_IE_DS_PARAM_SET_T; + + +/* 7.3.2.5 CF Parameter Set element */ +typedef struct _IE_CF_PARAM_SET_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucCFPCount; + UINT_8 ucCFPPeriod; + UINT_16 u2CFPMaxDur; + UINT_16 u2DurRemaining; +} __KAL_ATTRIB_PACKED__ IE_CF_PARAM_SET_T, *P_IE_CF_PARAM_SET_T; + + +/* 7.3.2.6 TIM */ +typedef struct _IE_TIM_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucDTIMCount; + UINT_8 ucDTIMPeriod; + UINT_8 ucBitmapControl; + UINT_8 aucPartialVirtualMap[1]; +} __KAL_ATTRIB_PACKED__ IE_TIM_T, *P_IE_TIM_T; + +/* 7.3.2.7 IBSS Parameter Set element */ +typedef struct _IE_IBSS_PARAM_SET_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_16 u2ATIMWindow; +} __KAL_ATTRIB_PACKED__ IE_IBSS_PARAM_SET_T, *P_IE_IBSS_PARAM_SET_T; + +/* 7.3.2.8 Challenge Text element */ +typedef struct _IE_CHALLENGE_TEXT_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 aucChallengeText[ELEM_MAX_LEN_CHALLENGE_TEXT]; +} __KAL_ATTRIB_PACKED__ IE_CHALLENGE_TEXT_T, *P_IE_CHALLENGE_TEXT_T; + +/* 7.3.2.9 Country information element */ +#if CFG_SUPPORT_802_11D +/*! \brief COUNTRY_INFO_TRIPLET is defined for the COUNTRY_INFO_ELEM structure. */ +typedef struct _COUNTRY_INFO_TRIPLET_T { + UINT_8 ucParam1; /*!< If param1 >= 201, this triplet is referred to as + Regulatory Triplet in 802_11J. */ + UINT_8 ucParam2; + UINT_8 ucParam3; +} __KAL_ATTRIB_PACKED__ COUNTRY_INFO_TRIPLET_T, *P_COUNTRY_INFO_TRIPLET_T; + +typedef struct _COUNTRY_INFO_SUBBAND_TRIPLET_T { + UINT_8 ucFirstChnlNum; /*!< First Channel Number */ + UINT_8 ucNumOfChnl; /*!< Number of Channels */ + INT_8 cMaxTxPwrLv; /*!< Maximum Transmit Power Level */ +} __KAL_ATTRIB_PACKED__ COUNTRY_INFO_SUBBAND_TRIPLET_T, *P_COUNTRY_INFO_SUBBAND_TRIPLET_T; + +typedef struct _COUNTRY_INFO_REGULATORY_TRIPLET_T { + UINT_8 ucRegExtId; /*!< Regulatory Extension Identifier, should + be greater than or equal to 201 */ + UINT_8 ucRegClass; /*!< Regulatory Class */ + UINT_8 ucCoverageClass; /*!< Coverage Class, unsigned 1-octet value 0~31 + , 32~255 reserved */ +} __KAL_ATTRIB_PACKED__ COUNTRY_INFO_REGULATORY_TRIPLET_T, *P_COUNTRY_INFO_REGULATORY_TRIPLET_T; + +typedef struct _IE_COUNTRY_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 aucCountryStr[3]; + COUNTRY_INFO_SUBBAND_TRIPLET_T arCountryStr[1]; +} __KAL_ATTRIB_PACKED__ IE_COUNTRY_T, *P_IE_COUNTRY_T; +#endif /* CFG_SUPPORT_802_11D */ + +/* 7.3.2.13 ERP element */ +typedef struct _IE_ERP_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucERP; +} __KAL_ATTRIB_PACKED__ IE_ERP_T, *P_IE_ERP_T; + +/* 7.3.2.14 Extended Supported Rates element */ +typedef struct _IE_EXT_SUPPORTED_RATE_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 aucExtSupportedRates[ELEM_MAX_LEN_EXTENDED_SUP_RATES]; +} __KAL_ATTRIB_PACKED__ IE_EXT_SUPPORTED_RATE_T, *P_IE_EXT_SUPPORTED_RATE_T; + +/* 7.3.2.15 Power Constraint element */ +typedef struct _IE_POWER_CONSTRAINT_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucLocalPowerConstraint; /* Unit: dBm */ +} __KAL_ATTRIB_PACKED__ IE_POWER_CONSTRAINT_T, *P_IE_POWER_CONSTRAINT_T; + +/* 7.3.2.16 Power Capability element */ +typedef struct _IE_POWER_CAP_T { + UINT_8 ucId; + UINT_8 ucLength; + INT_8 cMinTxPowerCap; /* Unit: dBm */ + INT_8 cMaxTxPowerCap; /* Unit: dBm */ +} __KAL_ATTRIB_PACKED__ IE_POWER_CAP_T, *P_IE_POWER_CAP_T; + +/* 7.3.2.17 TPC request element */ +typedef struct _IE_TPC_REQ_T { + UINT_8 ucId; + UINT_8 ucLength; +} __KAL_ATTRIB_PACKED__ IE_TPC_REQ_T, *P_IE_TPC_REQ_T; + +/* 7.3.2.18 TPC report element */ +typedef struct _IE_TPC_REPORT_T { + UINT_8 ucId; + UINT_8 ucLength; + INT_8 cTxPower; /* Unit: dBm */ + INT_8 cLinkMargin; /* Unit: dB */ +} __KAL_ATTRIB_PACKED__ IE_TPC_REPORT_T, *P_IE_TPC_REPORT_T; + +/* 7.3.2.20 Channel Switch Announcement element */ +typedef struct _IE_CHNL_SWITCH_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucSwitchMode; + UINT_8 ucNewChannel; + UINT_8 ucSwitchCount; +} __KAL_ATTRIB_PACKED__ IE_CHNL_SWITCH_T, *P_IE_CHNL_SWITCH_T; + +/* 7.3.2.21 Measurement Request element */ +typedef struct _IE_MEASUREMENT_REQ_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucToken; + UINT_8 ucRequestMode; + UINT_8 ucMeasurementType; + UINT_8 aucRequestFields[1]; +} __KAL_ATTRIB_PACKED__ IE_MEASUREMENT_REQ_T, *P_IE_MEASUREMENT_REQ_T; + +typedef struct _SM_BASIC_REQ_T { + UINT_8 ucChannel; + UINT_32 au4StartTime[2]; + UINT_16 u2Duration; +} __KAL_ATTRIB_PACKED__ SM_BASIC_REQ_T, *P_SM_BASIC_REQ_T; + +/* SM_COMMON_REQ_T is not specified in Spec. Use it as common structure of SM */ +typedef SM_BASIC_REQ_T SM_REQ_COMMON_T, *P_SM_REQ_COMMON_T; +typedef SM_BASIC_REQ_T SM_CCA_REQ_T, *P_SM_CCA_REQ_T; +typedef SM_BASIC_REQ_T SM_RPI_HISTOGRAM_REQ_T, *P_SM_RPI_HISTOGRAM_REQ_T; + +typedef struct _RM_CHNL_LOAD_REQ_T { + UINT_8 ucRegulatoryClass; + UINT_8 ucChannel; + UINT_16 u2RandomInterval; + UINT_16 u2Duration; + UINT_8 aucSubElements[1]; +} __KAL_ATTRIB_PACKED__ RM_CHNL_LOAD_REQ_T, *P_RM_CHNL_LOAD_REQ_T; + +typedef RM_CHNL_LOAD_REQ_T \ + RM_NOISE_HISTOGRAM_REQ_T, *P_RM_NOISE_HISTOGRAM_REQ_T; + +typedef struct _RM_BCN_REQ_T { + UINT_8 ucRegulatoryClass; + UINT_8 ucChannel; + UINT_16 u2RandomInterval; + UINT_16 u2Duration; + UINT_8 ucMeasurementMode; + UINT_8 aucBssid[6]; + UINT_8 aucSubElements[1]; +} __KAL_ATTRIB_PACKED__ RM_BCN_REQ_T, *P_RM_BCN_REQ_T; + +typedef struct _RM_FRAME_REQ_T { + UINT_8 ucRegulatoryClass; + UINT_8 ucChannel; + UINT_16 u2RandomInterval; + UINT_16 u2Duration; + UINT_8 ucFrameReqType; + UINT_8 aucMacAddr[6]; + UINT_8 aucSubElements[1]; +} __KAL_ATTRIB_PACKED__ RM_FRAME_REQ_T, *P_RM_FRAME_REQ_T; + +typedef struct _RM_STA_STATS_REQ_T { + UINT_8 aucPeerMacAddr[6]; + UINT_16 u2RandomInterval; + UINT_16 u2Duration; + UINT_8 ucGroupID; + UINT_8 aucSubElements[1]; +} __KAL_ATTRIB_PACKED__ RM_STA_STATS_REQ_T, *P_RM_STA_STATS_REQ_T; + +typedef struct _RM_LCI_REQ_T { + UINT_8 ucLocationSubject; + UINT_8 ucLatitudeResolution; + UINT_8 ucLongitudeResolution; + UINT_8 ucAltitudeResolution; + UINT_8 aucSubElements[1]; +} __KAL_ATTRIB_PACKED__ RM_LCI_REQ_T, *P_RM_LCI_REQ_T; + +typedef struct _RM_TS_MEASURE_REQ_T { + UINT_16 u2RandomInterval; + UINT_16 u2Duration; + UINT_8 aucPeerStaAddr[6]; + UINT_8 ucTrafficID; + UINT_8 ucBin0Range; + UINT_8 aucSubElements[1]; +} __KAL_ATTRIB_PACKED__ RM_TS_MEASURE_REQ_T, *P_RM_TS_MEASURE_REQ_T; + +typedef struct _RM_MEASURE_PAUSE_REQ_T { + UINT_16 u2PauseTime; + UINT_8 aucSubElements[1]; +} __KAL_ATTRIB_PACKED__ RM_MEASURE_PAUSE_REQ_T, *P_RM_MEASURE_PAUSE_REQ_T; + +/* 7.3.2.22 Measurement Report element */ +typedef struct _IE_MEASUREMENT_REPORT_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucToken; + UINT_8 ucReportMode; + UINT_8 ucMeasurementType; + UINT_8 aucReportFields[1]; +} __KAL_ATTRIB_PACKED__ IE_MEASUREMENT_REPORT_T, *P_IE_MEASUREMENT_REPORT_T; + +typedef struct _SM_BASIC_REPORT_T { + UINT_8 ucChannel; + UINT_32 u4StartTime[2]; + UINT_16 u2Duration; + UINT_8 ucMap; +} __KAL_ATTRIB_PACKED__ SM_BASIC_REPORT_T, *P_SM_BASIC_REPORT_T; + +typedef struct _SM_CCA_REPORT_T { + UINT_8 ucChannel; + UINT_32 u4StartTime[2]; + UINT_16 u2Duration; + UINT_8 ucCcaBusyFraction; +} __KAL_ATTRIB_PACKED__ SM_CCA_REPORT_T, *P_SM_CCA_REPORT_T; + +typedef struct _SM_RPI_REPORT_T { + UINT_8 ucChannel; + UINT_32 u4StartTime[2]; + UINT_16 u2Duration; + UINT_8 aucRPI[8]; +} __KAL_ATTRIB_PACKED__ SM_RPI_REPORT_T, *P_SM_RPI_REPORT_T; + +typedef struct _RM_CHNL_LOAD_REPORT_T { + UINT_8 ucRegulatoryClass; + UINT_8 ucChannel; + UINT_32 u4StartTime[2]; + UINT_16 u2Duration; + UINT_8 ucChnlLoad; +} __KAL_ATTRIB_PACKED__ RM_CHNL_LOAD_REPORT_T, *P_RM_CHNL_LOAD_REPORT_T; + +typedef struct _RM_IPI_REPORT_T { + UINT_8 ucRegulatoryClass; + UINT_8 ucChannel; + UINT_32 u4StartTime[2]; + UINT_16 u2Duration; + UINT_8 ucAntennaId; + INT_8 cANPI; + UINT_8 aucIPI[11]; +} __KAL_ATTRIB_PACKED__ RM_IPI_REPORT_T, *P_RM_IPI_REPORT_T; + +/* 7.3.2.23 Quiet element */ +typedef struct _IE_QUIET_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucCount; + UINT_8 ucPeriod; + UINT_16 u2Duration; + UINT_16 u2Offset; +} __KAL_ATTRIB_PACKED__ IE_QUIET_T, *P_IE_QUIET_T; + +/* 7.3.2.27 Extended Capabilities element */ +typedef struct _IE_EXT_CAP_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 aucCapabilities[1]; +} __KAL_ATTRIB_PACKED__ IE_EXT_CAP_T, *P_EXT_CAP_T; + +/* 7.3.2.27 Extended Capabilities element */ +typedef struct _IE_RRM_ENABLED_CAP_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 aucCap[5]; +} __KAL_ATTRIB_PACKED__ IE_RRM_ENABLED_CAP_T, *P_IE_RRM_ENABLED_CAP_T; + +/* 7.3.2.56 HT Capabilities element */ +typedef struct _SUP_MCS_SET_FIELD { + UINT_8 aucRxMcsBitmask[SUP_MCS_RX_BITMASK_OCTET_NUM]; + UINT_16 u2RxHighestSupportedRate; + UINT_32 u4TxRateInfo; +} __KAL_ATTRIB_PACKED__ SUP_MCS_SET_FIELD, *P_SUP_MCS_SET_FIELD; + +typedef struct _IE_HT_CAP_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_16 u2HtCapInfo; + UINT_8 ucAmpduParam; + SUP_MCS_SET_FIELD rSupMcsSet; + UINT_16 u2HtExtendedCap; + UINT_32 u4TxBeamformingCap; + UINT_8 ucAselCap; +} __KAL_ATTRIB_PACKED__ IE_HT_CAP_T, *P_IE_HT_CAP_T; + +/* 7.3.2.57 HT Operation element */ +typedef struct _IE_HT_OP_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucPrimaryChannel; + UINT_8 ucInfo1; + UINT_16 u2Info2; + UINT_16 u2Info3; + UINT_8 aucBasicMcsSet[16]; +} __KAL_ATTRIB_PACKED__ IE_HT_OP_T, *P_IE_HT_OP_T; + +/* 7.3.2.25 RSN Information element format */ +typedef struct _RSN_INFO_ELEM_T { + UCHAR ucElemId; + UCHAR ucLength; + UINT_16 u2Version; + UINT_32 u4GroupKeyCipherSuite; + UINT_16 u2PairwiseKeyCipherSuiteCount; + UCHAR aucPairwiseKeyCipherSuite1[4]; +} __KAL_ATTRIB_PACKED__ RSN_INFO_ELEM_T, *P_RSN_INFO_ELEM_T; + +/* 7.3.2.26 WPA Information element format */ +typedef struct _WPA_INFO_ELEM_T { + UCHAR ucElemId; + UCHAR ucLength; + UCHAR aucOui[3]; + UCHAR ucOuiType; + UINT_16 u2Version; + UINT_32 u4GroupKeyCipherSuite; + UINT_16 u2PairwiseKeyCipherSuiteCount; + UCHAR aucPairwiseKeyCipherSuite1[4]; +} __KAL_ATTRIB_PACKED__ WPA_INFO_ELEM_T, *P_WPA_INFO_ELEM_T; + +/* 7.3.2.58 20/40 BSS Intolerant Channel Report element */ +typedef struct _IE_INTOLERANT_CHNL_REPORT_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucRegulatoryClass; + UINT_8 aucChannelList[1]; +} __KAL_ATTRIB_PACKED__ IE_INTOLERANT_CHNL_REPORT_T, *P_IE_INTOLERANT_CHNL_REPORT_T; + +/* 7.3.2.59 OBSS Scan Parameters element */ +typedef struct _IE_OBSS_SCAN_PARAM_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_16 u2ScanPassiveDwell; + UINT_16 u2ScanActiveDwell; + UINT_16 u2TriggerScanInterval; + UINT_16 u2ScanPassiveTotalPerChnl; + UINT_16 u2ScanActiveTotalPerChnl; + UINT_16 u2WidthTransDelayFactor; + UINT_16 u2ScanActivityThres; +} __KAL_ATTRIB_PACKED__ IE_OBSS_SCAN_PARAM_T, *P_IE_OBSS_SCAN_PARAM_T; + +/* 7.3.2.60 20/40 BSS Coexistence element */ +typedef struct _IE_20_40_COEXIST_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucData; +} __KAL_ATTRIB_PACKED__ IE_20_40_COEXIST_T, *P_IE_20_40_COEXIST_T; + + +//3 7.4 Action Frame. +/* 7.4 Action frame format */ +typedef struct _WLAN_ACTION_FRAME { + /* Action MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Action frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_8 ucActionDetails[1]; /* Action details */ +} __KAL_ATTRIB_PACKED__ WLAN_ACTION_FRAME, *P_WLAN_ACTION_FRAME; + +/* 7.4.1.1 Spectrum Measurement Request frame format */ +typedef struct _ACTION_SM_REQ_FRAME { + /* ADDTS Request MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* ADDTS Request frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_8 ucDialogToken; /* Dialog Token */ + UINT_8 aucInfoElem[1]; /* Information elements */ +} __KAL_ATTRIB_PACKED__ ACTION_SM_REQ_FRAME, *P_ACTION_SM_REQ_FRAME; + +/* 7.4.1.2 Spectrum Measurement Report frame format */ +typedef ACTION_SM_REQ_FRAME ACTION_SM_REPORT_FRAME, *P_ACTION_SM_REPORT_FRAME; + +/* 7.4.2.1 ADDTS Request frame format */ +typedef struct _ACTION_ADDTS_REQ_FRAME { + /* ADDTS Request MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* ADDTS Request frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_8 ucDialogToken; /* Dialog Token */ + UINT_8 aucInfoElem[1]; /* Information elements, such as + TS Delay, and etc. */ +} __KAL_ATTRIB_PACKED__ ACTION_ADDTS_REQ_FRAME, *P_ACTION_ADDTS_REQ_FRAME; + + +/* 7.4.2.2 ADDTS Response frame format */ +typedef struct _ACTION_ADDTS_RSP_FRAME { + /* ADDTS Response MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* ADDTS Response frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_8 ucDialogToken; /* Dialog Token */ + UINT_8 ucStatusCode; /* WMM Status Code is of one byte */ + UINT_8 aucInfoElem[1]; /* Information elements, such as + TS Delay, and etc. */ +} __KAL_ATTRIB_PACKED__ ACTION_ADDTS_RSP_FRAME, *P_ACTION_ADDTS_RSP_FRAME; + + +/* 7.4.2.3 DELTS frame format */ +typedef struct _ACTION_DELTS_FRAME { + /* DELTS MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* DELTS frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_8 aucTsInfo[3]; /* TS Info */ +} __KAL_ATTRIB_PACKED__ ACTION_DELTS_FRAME, *P_ACTION_DELTS_FRAME; + + +/* 7.4.4.1 ADDBA Request frame format */ +typedef struct _ACTION_ADDBA_REQ_FRAME_T { + /* Action MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Action frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_8 ucDialogToken; /* Dialog Token chosen by the sender */ + UINT_8 aucBAParameterSet[2]; /* BA policy, TID, buffer size */ + UINT_8 aucBATimeoutValue[2]; + UINT_8 aucBAStartSeqCtrl[2]; /* SSN */ +} __KAL_ATTRIB_PACKED__ ACTION_ADDBA_REQ_FRAME_T, *P_ACTION_ADDBA_REQ_FRAME_T; + +typedef struct _ACTION_ADDBA_REQ_BODY_T{ + UINT_16 u2BAParameterSet; /* BA policy, TID, buffer size */ + UINT_16 u2BATimeoutValue; + UINT_16 u2BAStartSeqCtrl; /* SSN */ +} __KAL_ATTRIB_PACKED__ ACTION_ADDBA_REQ_BODY_T, *P_ACTION_ADDBA_REQ_BODY_T; + +/* 7.4.4.2 ADDBA Response frame format */ +typedef struct _ACTION_ADDBA_RSP_FRAME_T { + /* Action MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Action frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_8 ucDialogToken; /* Dialog Token chosen by the sender */ + UINT_8 aucStatusCode[2]; + UINT_8 aucBAParameterSet[2]; /* BA policy, TID, buffer size */ + UINT_8 aucBATimeoutValue[2]; +} __KAL_ATTRIB_PACKED__ ACTION_ADDBA_RSP_FRAME_T, *P_ACTION_ADDBA_RSP_FRAME_T; + +typedef struct _ACTION_ADDBA_RSP_BODY_T { + UINT_16 u2StatusCode; + UINT_16 u2BAParameterSet; /* BA policy, TID, buffer size */ + UINT_16 u2BATimeoutValue; +} __KAL_ATTRIB_PACKED__ ACTION_ADDBA_RSP_BODY_T, *P_ACTION_ADDBA_RSP_BODY_T; + +/* 7.4.4.3 DELBA frame format */ +typedef struct _ACTION_DELBA_FRAME_T { + /* Action MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Action frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_16 u2DelBaParameterSet; /* Bit 11 Initiator, Bits 12-15 TID */ + UINT_16 u2ReasonCode; /* 7.3.1.7 */ +} __KAL_ATTRIB_PACKED__ ACTION_DELBA_FRAME_T, *P_ACTION_DELBA_FRAME_T; + +/* 7.4.6.1 Radio Measurement Request frame format */ +typedef struct _ACTION_RM_REQ_FRAME { + /* MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Radio Measurement Request frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_8 ucDialogToken; /* Dialog Token */ + UINT_16 u2Repetitions; /* Number of repetitions */ + UINT_8 aucInfoElem[1]; /* Measurement Request elements, such as + channel load request, and etc. */ +} __KAL_ATTRIB_PACKED__ ACTION_RM_REQ_FRAME, *P_ACTION_RM_REQ_FRAME; + +/* 7.4.6.2 Radio Measurement Report frame format */ +typedef struct _ACTION_RM_REPORT_FRAME { + /* MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Radio Measurement Report frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_8 ucDialogToken; /* Dialog Token */ + UINT_8 aucInfoElem[1]; /* Measurement Report elements, such as + channel load report, and etc. */ +} __KAL_ATTRIB_PACKED__ ACTION_RM_REPORT_FRAME, *P_ACTION_RM_REPORT_FRAME; + +/* 7.4.7.1a 20/40 BSS Coexistence Management frame format */ +typedef struct _ACTION_20_40_COEXIST_FRAME { + /* MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* BSS Coexistence Management frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + + IE_20_40_COEXIST_T rBssCoexist;/* 20/40 BSS coexistence element */ + IE_INTOLERANT_CHNL_REPORT_T rChnlReport;/* Intolerant channel report */ + +} __KAL_ATTRIB_PACKED__ ACTION_20_40_COEXIST_FRAME, *P_ACTION_20_40_COEXIST_FRAME; + + +#if CFG_SUPPORT_802_11W +/* 7.4.9 SA Query Management frame format */ +typedef struct _ACTION_SA_QUERY_FRAME { + /* MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* BSS Coexistence Management frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + + UINT_8 ucTransId[ACTION_SA_QUERY_TR_ID_LEN]; /* Transaction id */ + +} __KAL_ATTRIB_PACKED__ ACTION_SA_QUERY_FRAME, *P_ACTION_SA_QUERY_FRAME; +#endif + +/* 7.4.10 Notify Channel Width Management frame format */ +typedef struct _ACTION_NOTIFY_CHNL_WIDTH_FRAME { + /* MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* BSS Coexistence Management frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_8 ucChannelWidth; /* Channel Width */ +} __KAL_ATTRIB_PACKED__ ACTION_NOTIFY_CHNL_WIDTH_FRAME, *P_ACTION_NOTIFY_CHNL_WIDTH_FRAME; + +//3 Information Elements from WFA. +typedef struct _IE_WFA_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 aucOui[3]; + UINT_8 ucOuiType; + UINT_8 aucOuiSubTypeVersion[2]; + /*!< Please be noted. WPA defines a 16 bit field version + instead of one subtype field and one version field*/ +} __KAL_ATTRIB_PACKED__ IE_WFA_T, *P_IE_WFA_T; + +/* WAPI Information element format */ +typedef struct _WAPI_INFO_ELEM_T { + UCHAR ucElemId; + UCHAR ucLength; + UINT_16 u2Version; + UINT_16 u2AuthKeyMgtSuiteCount; + UCHAR aucAuthKeyMgtSuite1[4]; +} __KAL_ATTRIB_PACKED__ WAPI_INFO_ELEM_T, *P_WAPI_INFO_ELEM_T; + +#if defined(WINDOWS_DDK) || defined(WINDOWS_CE) +#pragma pack() +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +/* Convert the ECWmin(max) to CWmin(max) */ +#define ECW_TO_CW(_ECW) ((1 << (_ECW)) - 1) + +/* Convert the RCPI to dBm */ +#define RCPI_TO_dBm(_rcpi) \ + ((PARAM_RSSI)(((_rcpi) > RCPI_HIGH_BOUND ? RCPI_HIGH_BOUND : (_rcpi)) >> 1) - NDBM_LOW_BOUND_FOR_RCPI) + +/* Convert the dBm to RCPI */ +#define dBm_TO_RCPI(_dbm) \ + (RCPI)( ( (((PARAM_RSSI)(_dbm) + NDBM_LOW_BOUND_FOR_RCPI) << 1) > RCPI_HIGH_BOUND) ? RCPI_HIGH_BOUND : \ + ( (((PARAM_RSSI)(_dbm) + NDBM_LOW_BOUND_FOR_RCPI) << 1) < RCPI_LOW_BOUND ? RCPI_LOW_BOUND : \ + (((PARAM_RSSI)(_dbm) + NDBM_LOW_BOUND_FOR_RCPI) << 1) ) ) + +/* Convert an unsigned char pointer to an information element pointer */ +#define IE_ID(fp) (((P_IE_HDR_T) fp)->ucId) +#define IE_LEN(fp) (((P_IE_HDR_T) fp)->ucLength) +#define IE_SIZE(fp) (ELEM_HDR_LEN + IE_LEN(fp)) + +#define SSID_IE(fp) ((P_IE_SSID_T) fp) + +#define SUP_RATES_IE(fp) ((P_IE_SUPPORTED_RATE_T) fp) + +#define DS_PARAM_IE(fp) ((P_IE_DS_PARAM_SET_T) fp) + +#define TIM_IE(fp) ((P_IE_TIM_T) fp) + +#define IBSS_PARAM_IE(fp) ((P_IE_IBSS_PARAM_SET_T) fp) + +#define ERP_INFO_IE(fp) ((P_IE_ERP_T) fp) + +#define EXT_SUP_RATES_IE(fp) ((P_IE_EXT_SUPPORTED_RATE_T) fp) + +#define WFA_IE(fp) ((P_IE_WFA_T) fp) + +#if CFG_SUPPORT_802_11D +#define COUNTRY_IE(fp) ((P_IE_COUNTRY_T) fp) +#endif + +#define EXT_CAP_IE(fp) ((P_EXT_CAP_T) fp) + +#define HT_CAP_IE(fp) ((P_IE_HT_CAP_T) fp) + +#define HT_OP_IE(fp) ((P_IE_HT_OP_T) fp) + +#define OBSS_SCAN_PARAM_IE(fp) ((P_IE_OBSS_SCAN_PARAM_T) fp) + +#define BSS_20_40_COEXIST_IE(fp) ((P_IE_20_40_COEXIST_T) fp) + +#define QUIET_IE(fp) ((P_IE_QUIET_T) fp) + + + +/* The macro to check if the MAC address is B/MCAST Address */ +#define IS_BMCAST_MAC_ADDR(_pucDestAddr) \ + ((BOOLEAN) ( ((PUINT_8)(_pucDestAddr))[0] & BIT(0) )) + +/* The macro to check if the MAC address is UCAST Address */ +#define IS_UCAST_MAC_ADDR(_pucDestAddr) \ + ((BOOLEAN) !( ((PUINT_8)(_pucDestAddr))[0] & BIT(0) )) + +/* The macro to copy the MAC address */ +#define COPY_MAC_ADDR(_pucDestAddr, _pucSrcAddr) \ + kalMemCopy(_pucDestAddr, _pucSrcAddr, MAC_ADDR_LEN) + +/* The macro to check if two MAC addresses are equal */ +#define EQUAL_MAC_ADDR(_pucDestAddr, _pucSrcAddr) \ + (!kalMemCmp(_pucDestAddr, _pucSrcAddr, MAC_ADDR_LEN)) + +/* The macro to check if two MAC addresses are not equal */ +#define UNEQUAL_MAC_ADDR(_pucDestAddr, _pucSrcAddr) \ + (kalMemCmp(_pucDestAddr, _pucSrcAddr, MAC_ADDR_LEN)) + + +/* The macro to check whether two SSIDs are equal */ +#define EQUAL_SSID(pucSsid1, ucSsidLen1, pucSsid2, ucSsidLen2) \ + ((ucSsidLen1 <= ELEM_MAX_LEN_SSID) && \ + (ucSsidLen2 <= ELEM_MAX_LEN_SSID) && \ + ((ucSsidLen1) == (ucSsidLen2)) && \ + !kalMemCmp(pucSsid1, pucSsid2, ucSsidLen1)) + +/* The macro to check whether two SSIDs are equal */ +#define UNEQUAL_SSID(pucSsid1, ucSsidLen1, pucSsid2, ucSsidLen2) \ + ((ucSsidLen1 > ELEM_MAX_LEN_SSID) || \ + (ucSsidLen2 > ELEM_MAX_LEN_SSID) || \ + ((ucSsidLen1) != (ucSsidLen2)) || \ + kalMemCmp(pucSsid1, pucSsid2, ucSsidLen1)) + +/* The macro to copy the SSID, the length of pucDestSsid should have at least 32 bytes */ +#define COPY_SSID(pucDestSsid, ucDestSsidLen, pucSrcSsid, ucSrcSsidLen) \ + do { \ + ucDestSsidLen = ucSrcSsidLen; \ + if (ucSrcSsidLen) { \ + ASSERT(ucSrcSsidLen <= ELEM_MAX_LEN_SSID); \ + kalMemCopy(pucDestSsid, pucSrcSsid, ((ucSrcSsidLen > ELEM_MAX_LEN_SSID) ? ELEM_MAX_LEN_SSID : ucSrcSsidLen)); \ + } \ + } while (FALSE) + +/* The macro to copy the IE */ +#define COPY_IE(pucDestIE, pucSrcIE) \ + do { \ + kalMemCopy((PUINT_8)pucDestIE, \ + (PUINT_8)pucSrcIE,\ + IE_SIZE(pucSrcIE)); \ + } while (FALSE) + +#define IE_FOR_EACH(_pucIEsBuf, _u2IEsBufLen, _u2Offset) \ + for ((_u2Offset) = 0; ((((_u2Offset) + 2) <= (_u2IEsBufLen)) && (((_u2Offset) + IE_SIZE(_pucIEsBuf)) <= (_u2IEsBufLen))) ; \ + (_u2Offset) += IE_SIZE(_pucIEsBuf), (_pucIEsBuf) += IE_SIZE(_pucIEsBuf)) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _MAC_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/mt5931_reg.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/mt5931_reg.h new file mode 100755 index 000000000000..1c75d2d03a27 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/mt5931_reg.h @@ -0,0 +1,340 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/nic/mt5931_reg.h#1 $ +*/ + +/*! \file "mt5931_reg.h" + \brief The common register definition of mt5931 + + N/A +*/ + +/******************************************************************************* +* Copyright (c) 2010 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: mt5931_reg.h $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 02 25 2011 cp.wu + * [WCXRP00000496] [MT5931][Driver] Apply host-triggered chip reset before initializing firmware download procedures + * apply host-triggered chip reset mechanism before initializing firmware download procedures. + * + * 02 18 2011 terry.wu + * [WCXRP00000412] [MT6620 Wi-Fi][FW/Driver] Dump firmware assert info at android kernel log + * Add WHISR_D2H_SW_ASSERT_INFO_INT to MT5931_reg. + * + * 10 07 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * add firmware download for MT5931. + * +*/ + +#ifndef _MT5931_REG_H +#define _MT5931_REG_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +//1 MT5931 MCR Definition + +//2 Host Interface + +//4 CHIP ID Register +#define MCR_WCIR 0x0000 + +//4 HIF Low Power Control Register +#define MCR_WHLPCR 0x0004 + +//4 Control Status Register +#define MCR_WSDIOCSR 0x0008 +#define MCR_WSPICSR 0x0008 + +//4 HIF Control Register +#define MCR_WHCR 0x000C + +//4 HIF Interrupt Status Register +#define MCR_WHISR 0x0010 + +//4 HIF Interrupt Enable Register +#define MCR_WHIER 0x0014 + +//4 Abnormal Status Register +#define MCR_WASR 0x0018 + +//4 WLAN Software Interrupt Control Register +#define MCR_WSICR 0x001C + +//4 WLAN TX Status Register +#define MCR_WTSR0 0x0020 + +//4 WLAN TX Status Register +#define MCR_WTSR1 0x0024 + +//4 WLAN TX Data Register 0 +#define MCR_WTDR0 0x0028 + +//4 WLAN TX Data Register 1 +#define MCR_WTDR1 0x002C + +//4 WLAN RX Data Register 0 +#define MCR_WRDR0 0x0030 + +//4 WLAN RX Data Register 1 +#define MCR_WRDR1 0x0034 + +//4 Host to Device Send Mailbox 0 Register +#define MCR_H2DSM0R 0x0038 + +//4 Host to Device Send Mailbox 1 Register +#define MCR_H2DSM1R 0x003c + +//4 Device to Host Receive Mailbox 0 Register +#define MCR_D2HRM0R 0x0040 + +//4 Device to Host Receive Mailbox 1 Register +#define MCR_D2HRM1R 0x0044 + +//4 Device to Host Receive Mailbox 2 Register +#define MCR_D2HRM2R 0x0048 + +//4 WLAN RX Packet Length Register +#define MCR_WRPLR 0x0050 + +//4 EHPI Transaction Count Register +#define MCR_EHTCR 0x0054 + +//4 Firmware Download Data Register +#define MCR_FWDLDR 0x0080 + +//4 Firmware Download Destination Starting Address Register +#define MCR_FWDLDSAR 0x0084 + +//4 Firmware Download Status Register +#define MCR_FWDLSR 0x0088 + +//4 WLAN MCU Control & Status Register +#define MCR_WMCSR 0x008c + +//4 WLAN Firmware Download Configuration +#define MCR_FWCFG 0x0090 + + +//#if CFG_SDIO_INTR_ENHANCE +typedef struct _ENHANCE_MODE_DATA_STRUCT_T { + UINT_32 u4WHISR; + union { + struct { + UINT_8 ucTQ0Cnt; + UINT_8 ucTQ1Cnt; + UINT_8 ucTQ2Cnt; + UINT_8 ucTQ3Cnt; + UINT_8 ucTQ4Cnt; + UINT_8 ucTQ5Cnt; + UINT_16 u2Rsrv; + } u; + UINT_32 au4WTSR[2]; + } rTxInfo; + union { + struct { + UINT_16 u2NumValidRx0Len; + UINT_16 u2NumValidRx1Len; + UINT_16 au2Rx0Len[16]; + UINT_16 au2Rx1Len[16]; + } u; + UINT_32 au4RxStatusRaw[17]; + } rRxInfo; + UINT_32 u4RcvMailbox0; + UINT_32 u4RcvMailbox1; +} ENHANCE_MODE_DATA_STRUCT_T, *P_ENHANCE_MODE_DATA_STRUCT_T; +// #endif /* ENHANCE_MODE_DATA_STRUCT_T */ + + +//2 Definition in each register +//3 WCIR 0x0000 +#define WCIR_WLAN_READY BIT(21) +#define WCIR_POR_INDICATOR BIT(20) +#define WCIR_REVISION_ID BITS(16,19) +#define WCIR_CHIP_ID BITS(0,15) + +#define MTK_CHIP_REV 0x00005931 +#define MTK_CHIP_MP_REVERSION_ID 0x0 + +//3 WHLPCR 0x0004 +#define WHLPCR_FW_OWN_REQ_CLR BIT(9) +#define WHLPCR_FW_OWN_REQ_SET BIT(8) +#define WHLPCR_IS_DRIVER_OWN BIT(8) +#define WHLPCR_INT_EN_CLR BIT(1) +#define WHLPCR_INT_EN_SET BIT(0) + +//3 WSDIOCSR 0x0008 +#define WSDIOCSR_SDIO_RE_INIT_EN BIT(0) + +//3 WSPICSR 0x0008 +#define WCSR_SPI_MODE_SEL BITS(3,4) +#define WCSR_SPI_ENDIAN_BIG BIT(2) +#define WCSR_SPI_INT_OUT_MODE BIT(1) +#define WCSR_SPI_DATA_OUT_MODE BIT(0) + +//3 WHCR 0x000C +#define WHCR_RX_ENHANCE_MODE_EN BIT(16) +#define WHCR_MAX_HIF_RX_LEN_NUM BITS(4,7) +#define WHCR_W_MAILBOX_RD_CLR_EN BIT(2) +#define WHCR_W_INT_CLR_CTRL BIT(1) +#define WHCR_MCU_DBG_EN BIT(0) +#define WHCR_OFFSET_MAX_HIF_RX_LEN_NUM 4 + +//3 WHISR 0x0010 +#define WHISR_D2H_SW_INT BITS(8,31) +#define WHISR_D2H_SW_ASSERT_INFO_INT BIT(31) +#define WHISR_FW_OWN_BACK_INT BIT(4) +#define WHISR_ABNORMAL_INT BIT(3) +#define WHISR_RX1_DONE_INT BIT(2) +#define WHISR_RX0_DONE_INT BIT(1) +#define WHISR_TX_DONE_INT BIT(0) + + +//3 WHIER 0x0014 +#define WHIER_D2H_SW_INT BITS(8,31) +#define WHIER_FW_OWN_BACK_INT_EN BIT(4) +#define WHIER_ABNORMAL_INT_EN BIT(3) +#define WHIER_RX1_DONE_INT_EN BIT(2) +#define WHIER_RX0_DONE_INT_EN BIT(1) +#define WHIER_TX_DONE_INT_EN BIT(0) +#define WHIER_DEFAULT (WHIER_RX0_DONE_INT_EN | \ + WHIER_RX1_DONE_INT_EN | \ + WHIER_TX_DONE_INT_EN | \ + WHIER_ABNORMAL_INT_EN | \ + WHIER_D2H_SW_INT \ + ) + + +//3 WASR 0x0018 +#define WASR_FW_OWN_INVALID_ACCESS BIT(4) +#define WASR_RX1_UNDER_FLOW BIT(3) +#define WASR_RX0_UNDER_FLOW BIT(2) +#define WASR_TX1_OVER_FLOW BIT(1) +#define WASR_TX0_OVER_FLOW BIT(0) + + +//3 WSICR 0x001C +#define WSICR_H2D_SW_INT_SET BITS(16,31) + + +//3 WRPLR 0x0050 +#define WRPLR_RX1_PACKET_LENGTH BITS(16,31) +#define WRPLR_RX0_PACKET_LENGTH BITS(0,15) + + +//3 FWDLSR 0x0088 +#define FWDLSR_FWDL_RDY BIT(8) +#define FWDLSR_FWDL_MODE BIT(0) + + +//3 WMCSR 0x008c +#define WMCSR_CHIP_RST BIT(15) /* write */ +#define WMCSR_DL_OK BIT(15) /* read */ +#define WMCSR_DL_FAIL BIT(14) +#define WMCSR_PLLRDY BIT(13) +#define WMCSR_WF_ON BIT(12) +#define WMCSR_INI_RDY BIT(11) +#define WMCSR_WF_EN BIT(6) +#define WMCSR_SW_EN BIT(5) +#define WMCSR_SPLLEN BIT(4) +#define WMCSR_SPWREN BIT(3) +#define WMCSR_HSTOPIL BIT(2) +#define WMCSR_FWDLRST BIT(1) +#define WMCSR_FWDLEN BIT(0) + + +//3 FWCFG 0x0090 +#define FWCFG_KSEL BITS(14,15) +#define FWCFG_FLEN BITS(0,13) + + +#endif /* _MT5931_REG_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/mt6620_reg.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/mt6620_reg.h new file mode 100755 index 000000000000..44c3fa0b19d3 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/mt6620_reg.h @@ -0,0 +1,330 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/nic/mt6620_reg.h#1 $ +*/ + +/*! \file "mt6620_reg.h" + \brief The common register definition of mt6620 + + N/A +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: mt6620_reg.h $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 01 31 2011 terry.wu + * [WCXRP00000412] [MT6620 Wi-Fi][FW/Driver] Dump firmware assert info at android kernel log + * Print firmware ASSERT info at Android kernel log, driver side + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 03 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add ACPI D0/D3 state switching support + * * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response +** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-12-10 16:44:18 GMT mtk02752 +** remove 5921 definitions +** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-11-09 22:56:32 GMT mtk01084 +** modify HW register definitions +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-11-04 14:11:04 GMT mtk01084 +** modify default IER bits +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-10-29 19:52:32 GMT mtk01084 +** modify data struture +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-10-23 16:08:20 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-10-13 21:58:53 GMT mtk01084 +** update for new HW architecture design +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-09-09 17:26:11 GMT mtk01084 +** add CFG_TEST_WITH_MT5921 +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-05-18 20:59:57 GMT mtk01426 +** Update WHIER_DEFAULT value +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-05-07 16:57:36 GMT mtk01426 +** Update CHIP ID to 0x6620, and WHLPCR bit definition +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-28 10:34:57 GMT mtk01461 +** Add read WTSR and fix RX STATUS is DW align for SDIO_STATUS_ENHANCE mode +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-24 09:46:52 GMT mtk01084 +** fix LINT error +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-23 00:32:24 GMT mtk01461 +** Define constants for TX PATH +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-18 20:54:10 GMT mtk01426 +** Add WHCR_MAX_HIF_RX_AGG_LEN_OFFSET definition +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:29 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _MT6620_REG_H +#define _MT6620_REG_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +//1 MT6620 MCR Definition + +//2 Host Interface + +//4 CHIP ID Register +#define MCR_WCIR 0x0000 + +//4 HIF Low Power Control Register +#define MCR_WHLPCR 0x0004 +//#define MCR_WHLPCR_BYTE1 0x0005 + + +//4 Control Status Register +#define MCR_WSDIOCSR 0x0008 +#define MCR_WSPICSR 0x0008 + +//4 HIF Control Register +#define MCR_WHCR 0x000C + +//4 HIF Interrupt Status Register +#define MCR_WHISR 0x0010 + +//4 HIF Interrupt Enable Register +#define MCR_WHIER 0x0014 + +//4 Abnormal Status Register +#define MCR_WASR 0x0018 + +//4 WLAN Software Interrupt Control Register +#define MCR_WSICR 0x001C + +//4 WLAN TX Status Register +#define MCR_WTSR0 0x0020 + +//4 WLAN TX Status Register +#define MCR_WTSR1 0x0024 + +//4 WLAN TX Data Register 0 +#define MCR_WTDR0 0x0028 + +//4 WLAN TX Data Register 1 +#define MCR_WTDR1 0x002C + +//4 WLAN RX Data Register 0 +#define MCR_WRDR0 0x0030 + +//4 WLAN RX Data Register 1 +#define MCR_WRDR1 0x0034 + +//4 Host to Device Send Mailbox 0 Register +#define MCR_H2DSM0R 0x0038 + +//4 Host to Device Send Mailbox 1 Register +#define MCR_H2DSM1R 0x003c + +//4 Device to Host Receive Mailbox 0 Register +#define MCR_D2HRM0R 0x0040 + +//4 Device to Host Receive Mailbox 1 Register +#define MCR_D2HRM1R 0x0044 + +//4 WLAN RX Packet Length Register +#define MCR_WRPLR 0x0048 + + + + +//temp //#if CFG_SDIO_INTR_ENHANCE +typedef struct _ENHANCE_MODE_DATA_STRUCT_T { + UINT_32 u4WHISR; + union { + struct { + UINT_8 ucTQ0Cnt; + UINT_8 ucTQ1Cnt; + UINT_8 ucTQ2Cnt; + UINT_8 ucTQ3Cnt; + UINT_8 ucTQ4Cnt; + UINT_8 ucTQ5Cnt; + UINT_16 u2Rsrv; + } u; + UINT_32 au4WTSR[2]; + } rTxInfo; + union { + struct { + UINT_16 u2NumValidRx0Len; + UINT_16 u2NumValidRx1Len; + UINT_16 au2Rx0Len[16]; + UINT_16 au2Rx1Len[16]; + } u; + UINT_32 au4RxStatusRaw[17]; + } rRxInfo; + UINT_32 u4RcvMailbox0; + UINT_32 u4RcvMailbox1; +} ENHANCE_MODE_DATA_STRUCT_T, *P_ENHANCE_MODE_DATA_STRUCT_T; +// #endif /* ENHANCE_MODE_DATA_STRUCT_T */ + + +//2 Definition in each register +//3 WCIR 0x0000 +#define WCIR_WLAN_READY BIT(21) +#define WCIR_POR_INDICATOR BIT(20) +#define WCIR_REVISION_ID BITS(16,19) +#define WCIR_CHIP_ID BITS(0,15) + +#define MTK_CHIP_REV 0x00006620 +#define MTK_CHIP_MP_REVERSION_ID 0x0 + +//3 WHLPCR 0x0004 +#define WHLPCR_FW_OWN_REQ_CLR BIT(9) +#define WHLPCR_FW_OWN_REQ_SET BIT(8) +#define WHLPCR_IS_DRIVER_OWN BIT(8) +#define WHLPCR_INT_EN_CLR BIT(1) +#define WHLPCR_INT_EN_SET BIT(0) + +//3 WSDIOCSR 0x0008 +#define WSDIOCSR_SDIO_RE_INIT_EN BIT(0) + +//3 WSPICSR 0x0008 +#define WCSR_SPI_MODE_SEL BITS(3,4) +#define WCSR_SPI_ENDIAN_BIG BIT(2) +#define WCSR_SPI_INT_OUT_MODE BIT(1) +#define WCSR_SPI_DATA_OUT_MODE BIT(0) + +//3 WHCR 0x000C +#define WHCR_RX_ENHANCE_MODE_EN BIT(16) +#define WHCR_MAX_HIF_RX_LEN_NUM BITS(4,7) +#define WHCR_W_MAILBOX_RD_CLR_EN BIT(2) +#define WHCR_W_INT_CLR_CTRL BIT(1) +#define WHCR_MCU_DBG_EN BIT(0) +#define WHCR_OFFSET_MAX_HIF_RX_LEN_NUM 4 + +//3 WHISR 0x0010 +#define WHISR_D2H_SW_INT BITS(8,31) +#define WHISR_D2H_SW_ASSERT_INFO_INT BIT(31) +#define WHISR_FW_INT_INDICATOR BIT(7) +#define WHISR_FW_OWN_BACK_INT BIT(4) +#define WHISR_ABNORMAL_INT BIT(3) +#define WHISR_RX1_DONE_INT BIT(2) +#define WHISR_RX0_DONE_INT BIT(1) +#define WHISR_TX_DONE_INT BIT(0) + + +//3 WHIER 0x0014 +#define WHIER_D2H_SW_INT BITS(8,31) +#define WHIER_FW_INT_INDICATOR_EN BIT(7) +#define WHIER_FW_OWN_BACK_INT_EN BIT(4) +#define WHIER_ABNORMAL_INT_EN BIT(3) +#define WHIER_RX1_DONE_INT_EN BIT(2) +#define WHIER_RX0_DONE_INT_EN BIT(1) +#define WHIER_TX_DONE_INT_EN BIT(0) +#define WHIER_DEFAULT (WHIER_RX0_DONE_INT_EN | \ + WHIER_RX1_DONE_INT_EN | \ + WHIER_TX_DONE_INT_EN | \ + WHIER_ABNORMAL_INT_EN | \ + WHIER_D2H_SW_INT \ + ) + + +//3 WASR 0x0018 +#define WASR_FW_OWN_INVALID_ACCESS BIT(4) +#define WASR_RX1_UNDER_FLOW BIT(3) +#define WASR_RX0_UNDER_FLOW BIT(2) +#define WASR_TX1_OVER_FLOW BIT(1) +#define WASR_TX0_OVER_FLOW BIT(0) + + +//3 WSICR 0x001C +#define WSICR_H2D_SW_INT_SET BITS(16,31) + + +//3 WTSR0 0x0044 +#define WRPLR_RX1_PACKET_LENGTH BITS(16,31) +#define WRPLR_RX0_PACKET_LENGTH BITS(0,15) + +#endif /* _MT6620_REG_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/nic.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/nic.h new file mode 100755 index 000000000000..5b1e51cf14ad --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/nic.h @@ -0,0 +1,764 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/nic/nic.h#1 $ +*/ + +/*! \file "nic.h" + \brief The declaration of nic functions + + Detail description. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: nic.h $ + * + * 11 01 2011 chinglan.wang + * NULL + * Modify the Wi-Fi method of the flush TX queue when disconnect the AP. + * If disconnect the AP and flush all the data frame in the TX queue, WPS cannot do the 4-way handshake to connect to the AP.. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 05 11 2011 cp.wu + * [WCXRP00000718] [MT6620 Wi-Fi] modify the behavior of setting tx power + * ACPI APIs migrate to wlan_lib.c for glue layer to invoke. + * + * 04 11 2011 yuche.tsai + * [WCXRP00000627] [Volunteer Patch][MT6620][Driver] Pending MMPUD of P2P Network may crash system issue. + * Fix kernel panic issue when MMPDU of P2P is pending in driver after WLAN module removed. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 02 2011 cp.wu + * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right after connection is built. + * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. + * + * 02 01 2011 cm.chang + * [WCXRP00000415] [MT6620 Wi-Fi][Driver] Check if any memory leakage happens when uninitializing in DGB mode + * . + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 10 26 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command + * 1) update NVRAM content template to ver 1.02 + * 2) add compile option for querying NIC capability (default: off) + * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting + * 4) correct auto-rate compiler error under linux (treat warning as error) + * 5) simplify usage of NVRAM and REG_INFO_T + * 6) add version checking between driver and firmware + * + * 10 26 2010 eddie.chen + * [WCXRP00000134] [MT6620 Wi-Fi][Driver] Add a registry to enable auto rate for SQA test by using E1 EVB + * Add auto rate parameter in registry. + * + * 10 12 2010 cp.wu + * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test + * add HT (802.11n) fixed rate support. + * + * 10 08 2010 cp.wu + * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test + * adding fixed rate support for distance test. (from registry setting) + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * 1) add NVRAM access API + * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) + * 3) add OID implementation for NVRAM read/write service + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by ENUM_NETWORK_TYPE_INDEX_T only + * remove ENUM_NETWORK_TYPE_T definitions + * + * 09 21 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS associated + * Do a complete reset with STA-REC null checking for RF test re-entry + * + * 09 08 2010 cp.wu + * NULL + * use static memory pool for storing IEs of scanning result. + * + * 09 01 2010 cp.wu + * NULL + * HIFSYS Clock Source Workaround + * + * 08 25 2010 george.huang + * NULL + * update OID/ registry control path for PM related settings + * + * 08 12 2010 cp.wu + * NULL + * [AIS-FSM] honor registry setting for adhoc running mode. (A/B/G) + * + * 08 03 2010 cp.wu + * NULL + * Centralize mgmt/system service procedures into independent calls. + * + * 07 28 2010 cp.wu + * NULL + * 1) eliminate redundant variable eOPMode in prAdapter->rWlanInfo + * 2) change nicMediaStateChange() API prototype + * + * 07 14 2010 yarco.yang + * + * 1. Remove CFG_MQM_MIGRATION + * 2. Add CMD_UPDATE_WMM_PARMS command + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 06 2010 george.huang + * [WPD00001556]Basic power managemenet function + * Update arguments for nicUpdateBeaconIETemplate() + * + * 07 06 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * STA-REC is maintained by CNM only. + * + * 07 05 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) ignore RSN checking when RSN is not turned on. + * 2) set STA-REC deactivation callback as NULL + * 3) add variable initialization API based on PHY configuration + * + * 06 30 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * sync. with CMD/EVENT document ver0.07. + * + * 06 29 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) sync to. CMD/EVENT document v0.03 + * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. + * 3) send command packet to indicate FW-PM after + * a) 1st beacon is received after AIS has connected to an AP + * b) IBSS-ALONE has been created + * c) IBSS-MERGE has occured + * + * 06 25 2010 george.huang + * [WPD00001556]Basic power managemenet function + * Create beacon update path, with expose bssUpdateBeaconContent() + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add command warpper for STA-REC/BSS-INFO sync. + * 2) enhance command packet sending procedure for non-oid part + * 3) add command packet definitions for STA-REC/BSS-INFO sync. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implement TX_DONE callback path. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 + * 2) when disconnected, indicate nic directly (no event is needed) + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 04 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) surpress compiler warning + * 2) when acqruing LP-own, keep writing WHLPCR whenever OWN is not acquired yet + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * * * 3) private data could be hold and taken use for other purpose + * + * 04 12 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add channel frequency <-> number conversion + * + * 03 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add ACPI D0/D3 state switching support + * * * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response + * + * 03 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * always process TX interrupt first then RX interrupt. + * + * 02 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct behavior to prevent duplicated RX handling for RX0_DONE and RX1_DONE + * + * 02 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add checksum offloading support. +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-10-13 21:58:58 GMT mtk01084 +** update for new HW architecture design +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-04-24 21:12:55 GMT mtk01104 +** Add function prototype nicRestoreSpiDefMode() +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-19 18:32:54 GMT mtk01084 +** update for basic power management functions +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:32 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _NIC_H +#define _NIC_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + + +struct _REG_ENTRY_T { + UINT_32 u4Offset; + UINT_32 u4Value; +}; + +struct _TABLE_ENTRY_T { + P_REG_ENTRY_T pu4TablePtr; + UINT_16 u2Size; +}; + +/*! INT status to event map */ +typedef struct _INT_EVENT_MAP_T { + UINT_32 u4Int; + UINT_32 u4Event; +} INT_EVENT_MAP_T, *P_INT_EVENT_MAP_T; + + +enum ENUM_INT_EVENT_T { + INT_EVENT_ABNORMAL, + INT_EVENT_SW_INT, + INT_EVENT_TX, + INT_EVENT_RX, + INT_EVENT_NUM +}; + +typedef enum _ENUM_IE_UPD_METHOD_T { + IE_UPD_METHOD_UPDATE_RANDOM, + IE_UPD_METHOD_UPDATE_ALL, + IE_UPD_METHOD_DELETE_ALL, +} ENUM_IE_UPD_METHOD_T, *P_ENUM_IE_UPD_METHOD_T; + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Routines in nic.c */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicAllocateAdapterMemory ( + IN P_ADAPTER_T prAdapter + ); + +VOID +nicReleaseAdapterMemory ( + IN P_ADAPTER_T prAdapter + ); + +VOID +nicDisableInterrupt ( + IN P_ADAPTER_T prAdapter + ); + +VOID +nicEnableInterrupt ( + IN P_ADAPTER_T prAdapter + ); + +WLAN_STATUS +nicProcessIST ( + IN P_ADAPTER_T prAdapter + ); + +WLAN_STATUS +nicProcessIST_impl ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4IntStatus + ); + +WLAN_STATUS +nicInitializeAdapter ( + IN P_ADAPTER_T prAdapter + ); + +VOID +nicMCRInit ( + IN P_ADAPTER_T prAdapter + ); + +BOOL +nicVerifyChipID ( + IN P_ADAPTER_T prAdapter + ); + + +#if CFG_SDIO_INTR_ENHANCE +VOID +nicSDIOInit ( + IN P_ADAPTER_T prAdapter + ); + +VOID +nicSDIOReadIntStatus ( + IN P_ADAPTER_T prAdapter, + OUT PUINT_32 pu4IntStatus + ); +#endif + +BOOLEAN +nicpmSetDriverOwn ( + IN P_ADAPTER_T prAdapter + ); + +VOID +nicpmSetFWOwn ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgEnableGlobalInt + ); + +BOOLEAN +nicpmSetAcpiPowerD0 ( + IN P_ADAPTER_T prAdapter + ); + +BOOLEAN +nicpmSetAcpiPowerD3 ( + IN P_ADAPTER_T prAdapter + ); + +#if defined(_HIF_SPI) +void +nicRestoreSpiDefMode( + IN P_ADAPTER_T prAdapter + ); +#endif + +VOID +nicProcessSoftwareInterrupt( + IN P_ADAPTER_T prAdapter + ); + +VOID +nicProcessAbnormalInterrupt ( + IN P_ADAPTER_T prAdapter + ); + +VOID +nicPutMailbox ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4MailboxNum, + IN UINT_32 u4Data); + +VOID +nicGetMailbox ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4MailboxNum, + OUT PUINT_32 pu4Data); + +VOID +nicSetSwIntr ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4SwIntrBitmap + ); + +P_CMD_INFO_T +nicGetPendingCmdInfo ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucSeqNum + ); + +P_MSDU_INFO_T +nicGetPendingTxMsduInfo ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucSeqNum + ); + +P_MSDU_INFO_T +nicGetPendingStaMMPDU( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucStaRecIdx + ); + +VOID +nicFreePendingTxMsduInfoByNetwork ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType + ); + +UINT_8 +nicIncreaseCmdSeqNum ( + IN P_ADAPTER_T prAdapter + ); + +UINT_8 +nicIncreaseTxSeqNum ( + IN P_ADAPTER_T prAdapter + ); + +/* Media State Change */ +WLAN_STATUS +nicMediaStateChange ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType, + IN P_EVENT_CONNECTION_STATUS prConnectionStatus + ); + +/* Utility function for channel number conversion */ +UINT_32 +nicChannelNum2Freq ( + IN UINT_32 u4ChannelNum + ); + +UINT_32 +nicFreq2ChannelNum ( + IN UINT_32 u4FreqInKHz + ); + +/* firmware command wrapper */ + /* NETWORK (WIFISYS) */ +WLAN_STATUS +nicActivateNetwork( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx + ); + +WLAN_STATUS +nicDeactivateNetwork( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx + ); + + + /* BSS-INFO */ +WLAN_STATUS +nicUpdateBss( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx + ); + + /* BSS-INFO Indication (PM) */ +WLAN_STATUS +nicPmIndicateBssCreated( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx + ); + +WLAN_STATUS +nicPmIndicateBssConnected( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx + ); + +WLAN_STATUS +nicPmIndicateBssAbort( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx + ); + + /* Beacon Template Update */ +WLAN_STATUS +nicUpdateBeaconIETemplate ( + IN P_ADAPTER_T prAdapter, + IN ENUM_IE_UPD_METHOD_T eIeUpdMethod, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN UINT_16 u2Capability, + IN PUINT_8 aucIe, + IN UINT_16 u2IELen + ); + +WLAN_STATUS +nicQmUpdateWmmParms( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx + ); + + +/*----------------------------------------------------------------------------*/ +/* Calibration Control */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicUpdateTxPower( + IN P_ADAPTER_T prAdapter, + IN P_CMD_TX_PWR_T prTxPwrParam + ); + +WLAN_STATUS +nicUpdate5GOffset( + IN P_ADAPTER_T prAdapter, + IN P_CMD_5G_PWR_OFFSET_T pr5GPwrOffset + ); + +WLAN_STATUS +nicUpdateDPD( + IN P_ADAPTER_T prAdapter, + IN P_CMD_PWR_PARAM_T prDpdCalResult + ); + + +/*----------------------------------------------------------------------------*/ +/* PHY configuration */ +/*----------------------------------------------------------------------------*/ +VOID +nicSetAvailablePhyTypeSet ( + IN P_ADAPTER_T prAdapter + ); + +/*----------------------------------------------------------------------------*/ +/* MGMT and System Service Control */ +/*----------------------------------------------------------------------------*/ +VOID +nicInitSystemService ( + IN P_ADAPTER_T prAdapter + ); + +VOID +nicResetSystemService ( + IN P_ADAPTER_T prAdapter + ); + +VOID +nicUninitSystemService ( + IN P_ADAPTER_T prAdapter + ); + +VOID +nicInitMGMT ( + IN P_ADAPTER_T prAdapter, + IN P_REG_INFO_T prRegInfo + ); + +VOID +nicUninitMGMT ( + IN P_ADAPTER_T prAdapter + ); + +WLAN_STATUS +nicConfigPowerSaveProfile ( + IN P_ADAPTER_T prAdapter, + ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + PARAM_POWER_MODE ePwrMode, + BOOLEAN fgEnCmdEvent + ); + +/*----------------------------------------------------------------------------*/ +/* Scan Result Processing */ +/*----------------------------------------------------------------------------*/ +VOID +nicAddScanResult ( + IN P_ADAPTER_T prAdapter, + IN PARAM_MAC_ADDRESS rMacAddr, + IN P_PARAM_SSID_T prSsid, + IN UINT_32 u4Privacy, + IN PARAM_RSSI rRssi, + IN ENUM_PARAM_NETWORK_TYPE_T eNetworkType, + IN P_PARAM_802_11_CONFIG_T prConfiguration, + IN ENUM_PARAM_OP_MODE_T eOpMode, + IN PARAM_RATES_EX rSupportedRates, + IN UINT_16 u2IELength, + IN PUINT_8 pucIEBuf + ); + +VOID +nicFreeScanResultIE ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Idx + ); + +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) +/*----------------------------------------------------------------------------*/ +/* Workaround Control */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicEnableClockGating ( + IN P_ADAPTER_T prAdapter + ); + +WLAN_STATUS +nicDisableClockGating ( + IN P_ADAPTER_T prAdapter + ); +#endif + + +/*----------------------------------------------------------------------------*/ +/* Fixed Rate Hacking */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicUpdateRateParams ( + IN P_ADAPTER_T prAdapter, + IN ENUM_REGISTRY_FIXED_RATE_T eRateSetting, + IN PUINT_8 pucDesiredPhyTypeSet, + IN PUINT_16 pu2DesiredNonHTRateSet, + IN PUINT_16 pu2BSSBasicRateSet, + IN PUINT_8 pucMcsSet, + IN PUINT_8 pucSupMcs32, + IN PUINT_16 u2HtCapInfo + ); + +/*----------------------------------------------------------------------------*/ +/* Write registers */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicWriteMcr ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Address, + IN UINT_32 u4Value + ); + +/*----------------------------------------------------------------------------*/ +/* Update auto rate */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicRlmArUpdateParms( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4ArSysParam0, + IN UINT_32 u4ArSysParam1, + IN UINT_32 u4ArSysParam2, + IN UINT_32 u4ArSysParam3 + ); + +/*----------------------------------------------------------------------------*/ +/* Enable/Disable Roaming */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicRoamingUpdateParams( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4EnableRoaming + ); + + +VOID +nicPrintFirmwareAssertInfo( + IN P_ADAPTER_T prAdapter + ); + +/*----------------------------------------------------------------------------*/ +/* Link Quality Updating */ +/*----------------------------------------------------------------------------*/ +VOID +nicUpdateLinkQuality( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx, + IN P_EVENT_LINK_QUALITY prEventLinkQuality + ); + +VOID +nicUpdateRSSI( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx, + IN INT_8 cRssi, + IN INT_8 cLinkQuality + ); + +VOID +nicUpdateLinkSpeed( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx, + IN UINT_16 u2LinkSpeed + ); + +#if CFG_SUPPORT_RDD_TEST_MODE +WLAN_STATUS +nicUpdateRddTestMode( + IN P_ADAPTER_T prAdapter, + IN P_CMD_RDD_CH_T prRddChParam + ); +#endif + +#endif /* _NIC_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/nic_rx.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/nic_rx.h new file mode 100755 index 000000000000..c872e8f3b35f --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/nic_rx.h @@ -0,0 +1,577 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/nic/nic_rx.h#1 $ +*/ + +/*! \file "nic_rx.h" + \brief The declaration of the nic rx functions + +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: nic_rx.h $ + * + * 11 04 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters and periodically dump counters for Xlog debugging. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 06 27 2011 tsaiyuan.hsu + * [WCXRP00000816] [MT6620 Wi-Fi][Driver] add control to enable rx data dump or not + * add control to enable rx data dump by packet type. + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 01 24 2011 cm.chang + * [WCXRP00000384] [MT6620 Wi-Fi][Driver][FW] Handle 20/40 action frame in AP mode and stop ampdu timer when sta_rec is freed + * Process received 20/40 coexistence action frame for AP mode + * + * 09 08 2010 cp.wu + * NULL + * use static memory pool for storing IEs of scanning result. + * + * 09 07 2010 yuche.tsai + * NULL + * Change prototype of API of adding P2P device to scan result. + * Additional IE buffer is saved. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 05 2010 yuche.tsai + * NULL + * Modify data structure for P2P Scan result. + * + * 08 03 2010 cp.wu + * NULL + * newly added P2P API should be declared in header file. + * + * 07 30 2010 cp.wu + * NULL + * 1) BoW wrapper: use definitions instead of hard-coded constant for error code + * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead + * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * saa_fsm.c is migrated. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add management dispatching function table. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 03 30 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * remove driver-land statistics. + * + * 03 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * generate information for OID_GEN_RCV_OK & OID_GEN_XMIT_OK + * * + * + * 03 11 2010 cp.wu + * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 + * add RX starvation warning debug message controlled by CFG_HIF_RX_STARVATION_WARNING + * + * 03 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code clean: removing unused variables and structure definitions + * + * 02 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct behavior to prevent duplicated RX handling for RX0_DONE and RX1_DONE + * + * 02 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement host-side firmware download logic + * + * 02 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c] + * * 2) firmware image length is now retrieved via NdisFileOpen + * * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore + * * 4) nicRxWaitResponse() revised + * * 5) another set of TQ counter default value is added for fw-download state + * * 6) Wi-Fi load address is now retrieved from registry too + * + * 12 30 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) According to CMD/EVENT documentation v0.8, + * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, + * * * * and result is retrieved by get ATInfo instead + * * * * 2) add 4 counter for recording aggregation statistics +** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-12-10 16:49:09 GMT mtk02752 +** code clean +** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-12-09 14:02:37 GMT MTK02468 +** Added ucStaRecIdx in SW_RFB_T and HALF_SEQ_NO_COUNT definition (to replace HALF_SEQ_NO_CNOUT) +** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-27 11:07:54 GMT mtk02752 +** add flush for reset +** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-25 18:18:09 GMT mtk02752 +** modify nicRxAddScanResult() +** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-11-24 22:42:22 GMT mtk02752 +** add nicRxAddScanResult() to prepare to handle SCAN_RESULT event +** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-11-24 19:57:06 GMT mtk02752 +** adopt P_HIF_RX_HEADER_T +** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-11-16 21:43:04 GMT mtk02752 +** correct ENUM_RX_PKT_DESTINATION_T definitions +** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-11-16 15:28:25 GMT mtk02752 +** add ucQueuedPacketNum for indicating how many packet are queued by RX reordering buffer/forwarding path +** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-11-16 15:05:01 GMT mtk02752 +** add eTC for SW_RFB_T and structure RX_MAILBOX +** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-11-13 21:16:57 GMT mtk02752 +** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-11-13 16:59:30 GMT mtk02752 +** add handler for event packet +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-11-13 13:45:50 GMT mtk02752 +** add port param for nicRxEnhanceReadBuffer() +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-11-11 10:12:31 GMT mtk02752 +** nicSDIOReadIntStatus() always read sizeof(ENHANCE_MODE_DATA_STRUCT_T) for int response, thus the number should be set to 0(:=16) instead of 10 +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-10-29 19:53:32 GMT mtk01084 +** modify structure naming +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-10-23 16:08:23 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-10-13 21:59:01 GMT mtk01084 +** update for new HW architecture design +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-05-20 12:23:33 GMT mtk01461 +** Add u4MaxEventBufferLen parameter to nicRxWaitResponse() +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-05-18 21:00:48 GMT mtk01426 +** Update SDIO_MAXIMUM_RX_STATUS value +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-28 10:36:15 GMT mtk01461 +** Remove unused define - SDIO_MAXIMUM_TX_STATUS +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-01 10:53:17 GMT mtk01461 +** Add function for HIF_LOOPBACK_PRE_TEST +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-18 20:56:19 GMT mtk01426 +** Add to support CFG_HIF_LOOPBACK and CFG_SDIO_RX_ENHANCE +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-17 20:19:56 GMT mtk01426 +** Add nicRxWaitResponse function proto type +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:35 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _NIC_RX_H +#define _NIC_RX_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define MAX_SEQ_NO 4095 +#define MAX_SEQ_NO_COUNT 4096 +#define HALF_SEQ_NO_CNOUT 2048 + +#define HALF_SEQ_NO_COUNT 2048 + +#define MT6620_FIXED_WIN_SIZE 64 +#define CFG_RX_MAX_BA_ENTRY 4 +#define CFG_RX_MAX_BA_TID_NUM 8 + +#define RX_STATUS_FLAG_MORE_PACKET BIT(30) +#define RX_STATUS_CHKSUM_MASK BITS(0,10) + +#define RX_RFB_LEN_FIELD_LEN 4 +#define RX_HEADER_OFFSET 2 + + +#if defined(_HIF_SDIO) && defined (WINDOWS_DDK) +/*! On XP, maximum Tx+Rx Statue <= 64-4(HISR)*/ + #define SDIO_MAXIMUM_RX_LEN_NUM 0 /*!< 0~15 (0: un-limited) */ +#else + #define SDIO_MAXIMUM_RX_LEN_NUM 0 /*!< 0~15 (0: un-limited) */ +#endif + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_RX_STATISTIC_COUNTER_T { + RX_MPDU_TOTAL_COUNT = 0, + RX_SIZE_ERR_DROP_COUNT, + + RX_DATA_INDICATION_COUNT, + RX_DATA_RETURNED_COUNT, + RX_DATA_RETAINED_COUNT, + + RX_DROP_TOTAL_COUNT, + RX_TYPE_ERR_DROP_COUNT, + RX_CLASS_ERR_DROP_COUNT, + RX_DST_NULL_DROP_COUNT, + +#if CFG_TCP_IP_CHKSUM_OFFLOAD || CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 + RX_CSUM_TCP_FAILED_COUNT, + RX_CSUM_UDP_FAILED_COUNT, + RX_CSUM_IP_FAILED_COUNT, + RX_CSUM_TCP_SUCCESS_COUNT, + RX_CSUM_UDP_SUCCESS_COUNT, + RX_CSUM_IP_SUCCESS_COUNT, + RX_CSUM_UNKNOWN_L4_PKT_COUNT, + RX_CSUM_UNKNOWN_L3_PKT_COUNT, + RX_IP_V6_PKT_CCOUNT, +#endif + RX_STATISTIC_COUNTER_NUM +} ENUM_RX_STATISTIC_COUNTER_T; + +typedef enum _ENUM_RX_PKT_DESTINATION_T { + RX_PKT_DESTINATION_HOST, /* to OS */ + RX_PKT_DESTINATION_FORWARD, /* to TX queue for forward, AP mode */ + RX_PKT_DESTINATION_HOST_WITH_FORWARD, /* to both TX and OS, AP mode broadcast packet */ + RX_PKT_DESTINATION_NULL, /* packet to be freed */ + RX_PKT_DESTINATION_NUM +} ENUM_RX_PKT_DESTINATION_T; + +struct _SW_RFB_T { + QUE_ENTRY_T rQueEntry; + PVOID pvPacket; /*!< ptr to rx Packet Descriptor */ + PUINT_8 pucRecvBuff; /*!< ptr to receive data buffer */ + P_HIF_RX_HEADER_T prHifRxHdr; + UINT_32 u4HifRxHdrFlag; + PVOID pvHeader; + UINT_16 u2PacketLen; + UINT_16 u2HeaderLen; + UINT_16 u2SSN; + UINT_8 ucTid; + UINT_8 ucWlanIdx; + UINT_8 ucPacketType; + UINT_8 ucStaRecIdx; + + ENUM_CSUM_RESULT_T aeCSUM[CSUM_TYPE_NUM]; + ENUM_RX_PKT_DESTINATION_T eDst; + ENUM_TRAFFIC_CLASS_INDEX_T eTC; /* only valid when eDst == FORWARD */ +}; + +/*! RX configuration type structure */ +typedef struct _RX_CTRL_T { + UINT_32 u4RxCachedSize; + PUINT_8 pucRxCached; + QUE_T rFreeSwRfbList; + QUE_T rReceivedRfbList; + QUE_T rIndicatedRfbList; + +#if CFG_SDIO_RX_AGG + PUINT_8 pucRxCoalescingBufPtr; +#endif + + PVOID apvIndPacket[CFG_RX_MAX_PKT_NUM]; + PVOID apvRetainedPacket[CFG_RX_MAX_PKT_NUM]; + + UINT_8 ucNumIndPacket; + UINT_8 ucNumRetainedPacket; + UINT_64 au8Statistics[RX_STATISTIC_COUNTER_NUM]; /*!< RX Counters */ + +#if CFG_HIF_STATISTICS + UINT_32 u4TotalRxAccessNum; + UINT_32 u4TotalRxPacketNum; +#endif + +#if CFG_HIF_RX_STARVATION_WARNING + UINT_32 u4QueuedCnt; + UINT_32 u4DequeuedCnt; +#endif + +#if CFG_RX_PKTS_DUMP + UINT_32 u4RxPktsDumpTypeMask; +#endif + +} RX_CTRL_T, *P_RX_CTRL_T; + +typedef struct _RX_MAILBOX_T { + UINT_32 u4RxMailbox[2]; /* for Device-to-Host Mailbox */ +} RX_MAILBOX_T, *P_RX_MAILBOX_T; + +typedef WLAN_STATUS (*PROCESS_RX_MGT_FUNCTION)(P_ADAPTER_T, P_SW_RFB_T); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define RX_INC_CNT(prRxCtrl, eCounter) \ + {((P_RX_CTRL_T)prRxCtrl)->au8Statistics[eCounter]++;} + +#define RX_ADD_CNT(prRxCtrl, eCounter, u8Amount) \ + {((P_RX_CTRL_T)prRxCtrl)->au8Statistics[eCounter] += (UINT_64)u8Amount;} + +#define RX_GET_CNT(prRxCtrl, eCounter) \ + (((P_RX_CTRL_T)prRxCtrl)->au8Statistics[eCounter]) + +#define RX_RESET_ALL_CNTS(prRxCtrl) \ + {kalMemZero(&prRxCtrl->au8Statistics[0], sizeof(prRxCtrl->au8Statistics));} + +#define RX_STATUS_TEST_MORE_FLAG(flag) \ + ((BOOL)((flag & RX_STATUS_FLAG_MORE_PACKET) ? TRUE : FALSE)) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID +nicRxInitialize ( + IN P_ADAPTER_T prAdapter + ); + +#if defined(MT5931) +VOID +nicRxPostInitialize ( + IN P_ADAPTER_T prAdapter + ); +#endif + +VOID +nicRxUninitialize ( + IN P_ADAPTER_T prAdapter + ); + +VOID +nicRxProcessRFBs ( + IN P_ADAPTER_T prAdapter + ); + +#if !CFG_SDIO_INTR_ENHANCE +VOID +nicRxReceiveRFBs ( + IN P_ADAPTER_T prAdapter + ); + +WLAN_STATUS +nicRxReadBuffer ( + IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb + ); + +#else +VOID +nicRxSDIOReceiveRFBs ( + IN P_ADAPTER_T prAdapter + ); + +WLAN_STATUS +nicRxEnhanceReadBuffer ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4DataPort, + IN UINT_16 u2RxLength, + IN OUT P_SW_RFB_T prSwRfb + ); +#endif /* CFG_SDIO_INTR_ENHANCE */ + + +#if CFG_SDIO_RX_AGG +VOID +nicRxSDIOAggReceiveRFBs ( + IN P_ADAPTER_T prAdapter + ); +#endif + +WLAN_STATUS +nicRxSetupRFB ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prRfb + ); + +VOID +nicRxReturnRFB ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prRfb + ); + +VOID +nicProcessRxInterrupt ( + IN P_ADAPTER_T prAdapter + ); + +VOID +nicRxProcessPktWithoutReorder ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + +VOID +nicRxProcessForwardPkt ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + +VOID +nicRxProcessGOBroadcastPkt ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + + +VOID +nicRxFillRFB ( + IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb + ); + +VOID +nicRxProcessDataPacket ( + IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb + ); + +VOID +nicRxProcessEventPacket ( + IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb + ); + +VOID +nicRxProcessMgmtPacket ( + IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb + ); + +#if CFG_TCP_IP_CHKSUM_OFFLOAD +VOID +nicRxFillChksumStatus( + IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb, + IN UINT_32 u4TcpUdpIpCksStatus + ); + +VOID +nicRxUpdateCSUMStatistics ( + IN P_ADAPTER_T prAdapter, + IN const ENUM_CSUM_RESULT_T aeCSUM[] + ); +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + + +VOID +nicRxQueryStatus ( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucBuffer, + OUT PUINT_32 pu4Count + ); + +VOID +nicRxClearStatistics ( + IN P_ADAPTER_T prAdapter + ); + +VOID +nicRxQueryStatistics ( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucBuffer, + OUT PUINT_32 pu4Count + ); + +WLAN_STATUS +nicRxWaitResponse ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucPortIdx, + OUT PUINT_8 pucRspBuffer, + IN UINT_32 u4MaxRespBufferLen, + OUT PUINT_32 pu4Length + ); + +VOID +nicRxEnablePromiscuousMode ( + IN P_ADAPTER_T prAdapter + ); + + +VOID +nicRxDisablePromiscuousMode ( + IN P_ADAPTER_T prAdapter + ); + + +WLAN_STATUS +nicRxFlush ( + IN P_ADAPTER_T prAdapter + ); + +WLAN_STATUS +nicRxProcessActionFrame ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + +#endif /* _NIC_RX_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/nic_tx.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/nic_tx.h new file mode 100755 index 000000000000..590fb18494e4 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/nic_tx.h @@ -0,0 +1,679 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/nic/nic_tx.h#1 $ +*/ + +/*! \file nic_tx.h + \brief Functions that provide TX operation in NIC's point of view. + + This file provides TX functions which are responsible for both Hardware and + Software Resource Management and keep their Synchronization. + +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: nic_tx.h $ + * + * 11 19 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Add xlog for tx + * + * 11 10 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Add TX_DONE status detail information. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 04 12 2011 cp.wu + * [WCXRP00000631] [MT6620 Wi-Fi][Driver] Add an API for QM to retrieve current TC counter value and processing frame dropping cases for TC4 path + * 1. add nicTxGetResource() API for QM to make decisions. + * 2. if management frames is decided by QM for dropping, the call back is invoked to indicate such a case. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 02 16 2011 cp.wu + * [WCXRP00000449] [MT6620 Wi-Fi][Driver] Refine CMD queue handling by adding an extra API for checking availble count and modify behavior + * 1. add new API: nicTxGetFreeCmdCount() + * 2. when there is insufficient command descriptor, nicTxEnqueueMsdu() will drop command packets directly + * + * 01 24 2011 cp.wu + * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving + * 1. add an extra counter for tracking pending forward frames. + * 2. notify TX service thread as well when there is pending forward frame + * 3. correct build errors leaded by introduction of Wi-Fi direct separation module + * + * 12 15 2010 yuche.tsai + * NULL + * Update SLT Descriptor number configure in driver. + * + * 11 16 2010 yarco.yang + * [WCXRP00000177] [MT5931 F/W] Performance tuning for 1st connection + * Update TX buffer count + * + * 11 03 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * 1) use 8 buffers for MT5931 which is equipped with less memory + * 2) modify MT5931 debug level to TRACE when download is successful + * + * 10 18 2010 cp.wu + * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore + * 1. when wlanAdapterStop() failed to send POWER CTRL command to firmware, do not poll for ready bit dis-assertion + * 2. shorten polling count for shorter response time + * 3. if bad I/O operation is detected during TX resource polling, then further operation is aborted as well + * + * 10 06 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * code reorganization to improve isolation between GLUE and CORE layers. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 30 2010 cp.wu + * NULL + * API added: nicTxPendingPackets(), for simplifying porting layer + * + * 07 26 2010 cp.wu + * + * change TC4 initial value from 2 to 4. + * + * 07 13 2010 cp.wu + * + * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets + * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending + * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid descriptor underflow under concurrent network operation + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 06 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Add MGMT Packet type for HIF_TX_HEADER + * + * 06 23 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * integrate . + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * refine TX-DONE callback. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * TX descriptors are now allocated once for reducing allocation overhead + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * specify correct value for management frames. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add flag on MSDU_INFO_T for indicating BIP frame and forceBasicRate + * 2) add packet type for indicating management frames + * + * 06 09 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add necessary changes to driver data paths. + * + * 06 09 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add TX_PACKET_MGMT to indicate the frame is coming from management modules + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge wlan_def.h. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 03 30 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * remove driver-land statistics. + * + * 03 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * generate information for OID_GEN_RCV_OK & OID_GEN_XMIT_OK + * * * + * + * 03 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code clean: removing unused variables and structure definitions + * + * 03 02 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Redistributed the initial TC resources for normal operation + * + * 03 02 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add mutex to avoid multiple access to qmTxQueue simultaneously. + * + * 02 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add new API: wlanProcessQueuedPackets() + * + * 02 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c] + * * * 2) firmware image length is now retrieved via NdisFileOpen + * * * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore + * * * 4) nicRxWaitResponse() revised + * * * 5) another set of TQ counter default value is added for fw-download state + * * * 6) Wi-Fi load address is now retrieved from registry too + * + * 02 09 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address + * * * * 2. follow MSDN defined behavior when associates to another AP + * * * * 3. for firmware download, packet size could be up to 2048 bytes + * + * 01 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. eliminate improper variable in rHifInfo + * * * * * 2. block TX/ordinary OID when RF test mode is engaged + * * * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode + * * * * * 4. correct some HAL implementation + * + * 01 13 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Enabled the Burst_End Indication mechanism + * + * 12 30 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) According to CMD/EVENT documentation v0.8, + * * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, + * * * * * and result is retrieved by get ATInfo instead + * * * * * 2) add 4 counter for recording aggregation statistics +** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-12-10 16:53:28 GMT mtk02752 +** remove unused API +** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-11-27 11:08:00 GMT mtk02752 +** add flush for reset +** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-24 19:56:49 GMT mtk02752 +** remove redundant eTC +** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-23 22:01:08 GMT mtk02468 +** Added MSDU_INFO fields for composing HIF TX header +** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-11-17 22:40:51 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-11-17 17:35:05 GMT mtk02752 +** + nicTxMsduInfoList() for sending MsduInfoList +** + NIC_TX_BUFF_COUNT_TC[0~5] +** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-11-17 11:07:00 GMT mtk02752 +** add nicTxAdjustTcq() API +** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-11-16 22:28:30 GMT mtk02752 +** move aucFreeBufferCount/aucMaxNumOfBuffer into another structure +** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-11-16 21:44:50 GMT mtk02752 +** + nicTxReturnMsduInfo() +** + nicTxFillMsduInfo() +** + rFreeMsduInfoList field in TX_CTRL +** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-11-16 18:00:43 GMT mtk02752 +** use P_PACKET_INFO_T for prPacket to avoid inventing another new structure for packet +** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-11-16 15:28:49 GMT mtk02752 +** add ucQueuedPacketNum for indicating how many packets are queued by per STA/AC queue +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-11-16 10:52:01 GMT mtk02752 +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-11-14 23:39:24 GMT mtk02752 +** interface structure redefine +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-11-13 21:17:03 GMT mtk02752 +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-10-29 19:53:10 GMT mtk01084 +** remove strange code by Frog +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-10-13 21:59:04 GMT mtk01084 +** update for new HW architecture design +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-10-02 13:53:03 GMT mtk01725 +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-28 10:36:50 GMT mtk01461 +** Add declaration of nicTxReleaseResource() +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-17 19:58:39 GMT mtk01461 +** Move CMD_INFO_T related define and function to cmd_buf.h +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-01 10:53:53 GMT mtk01461 +** Add function for SDIO_TX_ENHANCE +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-23 00:33:27 GMT mtk01461 +** Define constants for TX PATH and add nicTxPollingResource +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:09:32 GMT mtk01461 +** Update TX PATH API +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:38 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _NIC_TX_H +#define _NIC_TX_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define NIC_TX_RESOURCE_POLLING_TIMEOUT 256 +#define NIC_TX_RESOURCE_POLLING_DELAY_MSEC 50 + +/* Maximum buffer count for individual HIF TCQ */ + +#if defined(MT6620) +#if CFG_SLT_SUPPORT + /* 20101215 mtk01725 Redistributed the initial TC resources for SLT operation */ + #define NIC_TX_BUFF_COUNT_TC0 0 // First connection: 0 + #define NIC_TX_BUFF_COUNT_TC1 16 // First connection: 32 + #define NIC_TX_BUFF_COUNT_TC2 0 // First connection: 0 + #define NIC_TX_BUFF_COUNT_TC3 0 // First connection: 0 + #define NIC_TX_BUFF_COUNT_TC4 4 // First connection: 2 + #define NIC_TX_BUFF_COUNT_TC5 0 // First connection: 0 +#else + /* 20100302 mtk02468 Redistributed the initial TC resources for normal operation */ + #define NIC_TX_BUFF_COUNT_TC0 6 // First connection: 0 + #define NIC_TX_BUFF_COUNT_TC1 8 // First connection: 32 + #define NIC_TX_BUFF_COUNT_TC2 8 // First connection: 0 + #define NIC_TX_BUFF_COUNT_TC3 8 // First connection: 0 + #define NIC_TX_BUFF_COUNT_TC4 4 // First connection: 2 + #define NIC_TX_BUFF_COUNT_TC5 2 // First connection: 0 +#endif +#elif defined(MT5931) || defined(MT6628) + #define NIC_TX_BUFF_COUNT_TC0 1 // First connection: 0 + #define NIC_TX_BUFF_COUNT_TC1 14 // First connection: 32 + #define NIC_TX_BUFF_COUNT_TC2 1 // First connection: 0 + #define NIC_TX_BUFF_COUNT_TC3 1 // First connection: 0 + #define NIC_TX_BUFF_COUNT_TC4 4 // First connection: 2 + #define NIC_TX_BUFF_COUNT_TC5 1 // First connection: 0 +#endif + +#define NIC_TX_BUFF_SUM (NIC_TX_BUFF_COUNT_TC0 + \ + NIC_TX_BUFF_COUNT_TC1 + \ + NIC_TX_BUFF_COUNT_TC2 + \ + NIC_TX_BUFF_COUNT_TC3 + \ + NIC_TX_BUFF_COUNT_TC4 + \ + NIC_TX_BUFF_COUNT_TC5) +#if CFG_ENABLE_FW_DOWNLOAD + + #define NIC_TX_INIT_BUFF_COUNT_TC0 8 + #define NIC_TX_INIT_BUFF_COUNT_TC1 0 + #define NIC_TX_INIT_BUFF_COUNT_TC2 0 + #define NIC_TX_INIT_BUFF_COUNT_TC3 0 + #define NIC_TX_INIT_BUFF_COUNT_TC4 0 + #define NIC_TX_INIT_BUFF_COUNT_TC5 0 + + #define NIC_TX_INIT_BUFF_SUM (NIC_TX_INIT_BUFF_COUNT_TC0 + \ + NIC_TX_INIT_BUFF_COUNT_TC1 + \ + NIC_TX_INIT_BUFF_COUNT_TC2 + \ + NIC_TX_INIT_BUFF_COUNT_TC3 + \ + NIC_TX_INIT_BUFF_COUNT_TC4 + \ + NIC_TX_INIT_BUFF_COUNT_TC5) + +#endif + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +//3 /* Session for TX QUEUES */ +/* The definition in this ENUM is used to categorize packet's Traffic Class according + * to the their TID(User Priority). + * In order to achieve QoS goal, a particular TC should not block the process of + * another packet with different TC. + * In current design we will have 5 categories(TCs) of SW resource. + */ +typedef enum _ENUM_TRAFFIC_CLASS_INDEX_T { + TC0_INDEX = 0, /* HIF TX0: AC0 packets */ + TC1_INDEX, /* HIF TX0: AC1 packets & non-QoS packets */ + TC2_INDEX, /* HIF TX0: AC2 packets */ + TC3_INDEX, /* HIF TX0: AC3 packets */ + TC4_INDEX, /* HIF TX1: Command packets or 802.1x packets */ + TC5_INDEX, /* HIF TX0: BMCAST packets */ + TC_NUM /* Maximum number of Traffic Classes. */ +} ENUM_TRAFFIC_CLASS_INDEX_T; + +typedef enum _ENUM_TX_STATISTIC_COUNTER_T { + TX_MPDU_TOTAL_COUNT = 0, + TX_INACTIVE_BSS_DROP, + TX_INACTIVE_STA_DROP, + TX_FORWARD_OVERFLOW_DROP, + TX_AP_BORADCAST_DROP, + TX_STATISTIC_COUNTER_NUM +} ENUM_TX_STATISTIC_COUNTER_T; + + +typedef struct _TX_TCQ_STATUS_T { + UINT_8 aucFreeBufferCount[TC_NUM]; + UINT_8 aucMaxNumOfBuffer[TC_NUM]; +} TX_TCQ_STATUS_T, *P_TX_TCQ_STATUS_T; + +typedef struct _TX_TCQ_ADJUST_T { + INT_8 acVariation[TC_NUM]; +} TX_TCQ_ADJUST_T, *P_TX_TCQ_ADJUST_T; + +typedef struct _TX_CTRL_T { + UINT_32 u4TxCachedSize; + PUINT_8 pucTxCached; + +/* Elements below is classified according to TC (Traffic Class) value. */ + + TX_TCQ_STATUS_T rTc; + + PUINT_8 pucTxCoalescingBufPtr; + + QUE_T rFreeMsduInfoList; + + /* Management Frame Tracking */ + /* number of management frames to be sent */ + INT_32 i4TxMgmtPendingNum; + + /* to tracking management frames need TX done callback */ + QUE_T rTxMgmtTxingQueue; + +#if CFG_HIF_STATISTICS + UINT_32 u4TotalTxAccessNum; + UINT_32 u4TotalTxPacketNum; +#endif + UINT_32 au4Statistics[TX_STATISTIC_COUNTER_NUM]; + + /* Number to track forwarding frames */ + INT_32 i4PendingFwdFrameCount; + +} TX_CTRL_T, *P_TX_CTRL_T; + +typedef enum _ENUM_TX_PACKET_SRC_T { + TX_PACKET_OS, + TX_PACKET_OS_OID, + TX_PACKET_FORWARDING, + TX_PACKET_MGMT, + TX_PACKET_NUM +} ENUM_TX_PACKET_SRC_T; + +typedef enum _ENUM_HIF_TX_PACKET_TYPE_T { + HIF_TX_PACKET_TYPE_DATA = 0, + HIF_TX_PACKET_TYPE_COMMAND, + HIF_TX_PACKET_TYPE_HIF_LB, + HIF_TX_PACKET_TYPE_MGMT +} ENUM_HIF_TX_PACKET_TYPE_T, *P_ENUM_HIF_TX_PACKET_TYPE_T; + +typedef enum _ENUM_TX_RESULT_CODE_T { + TX_RESULT_SUCCESS = 0, + TX_RESULT_LIFE_TIMEOUT, + TX_RESULT_RTS_ERROR, + TX_RESULT_MPDU_ERROR, + TX_RESULT_AGING_TIMEOUT, + TX_RESULT_FLUSHED, + TX_RESULT_DROPPED_IN_DRIVER = 32, + TX_RESULT_NUM +} ENUM_TX_RESULT_CODE_T, *P_ENUM_TX_RESULT_CODE_T; + +/* TX Call Back Function */ +typedef WLAN_STATUS (*PFN_TX_DONE_HANDLER) ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus + ); + +/* TX transactions could be divided into 4 kinds: + * + * 1) 802.1X / Bluetooth-over-Wi-Fi Security Frames + * [CMD_INFO_T] - [prPacket] - in skb or NDIS_PACKET form + * + * 2) MMPDU + * [CMD_INFO_T] - [prPacket] - [MSDU_INFO_T] - [prPacket] - direct buffer for frame body + * + * 3) Command Packets + * [CMD_INFO_T] - [pucInfoBuffer] - direct buffer for content of command packet + * + * 4) Normal data frame + * [MSDU_INFO_T] - [prPacket] - in skb or NDIS_PACKET form + */ + + +/* PS_FORWARDING_TYPE_NON_PS means that the receiving STA is in Active Mode +* from the perspective of host driver (maybe not synchronized with FW --> SN is needed) +*/ + +struct _MSDU_INFO_T { + QUE_ENTRY_T rQueEntry; + P_NATIVE_PACKET prPacket; + + ENUM_TX_PACKET_SRC_T eSrc; /* specify OS/FORWARD packet */ + UINT_8 ucUserPriority; + + /* For composing HIF TX header */ + UINT_8 ucTC; /* Traffic Class: 0~4 (HIF TX0), 5 (HIF TX1) */ + UINT_8 ucPacketType; /* 0: Data, 1: Command, 2: HIF Loopback 3: Management Frame */ + UINT_8 ucStaRecIndex; + UINT_8 ucNetworkType; /* See ENUM_NETWORK_TYPE_T */ + UINT_8 ucFormatID; /* 0: MAUI, Linux, Windows NDIS 5.1 */ + BOOLEAN fgIs802_1x; /* TRUE: 802.1x frame */ + BOOLEAN fgIs802_11; /* TRUE: 802.11 header is present */ + UINT_16 u2PalLLH; /* PAL Logical Link Header (for BOW network) */ + UINT_16 u2AclSN; /* ACL Sequence Number (for BOW network) */ + UINT_8 ucPsForwardingType; /* See ENUM_PS_FORWARDING_TYPE_T */ + UINT_8 ucPsSessionID; /* PS Session ID specified by the FW for the STA */ + BOOLEAN fgIsBurstEnd; /* TRUE means this is the last packet of the burst for (STA, TID) */ + BOOLEAN fgIsBIP; /* Management Frame Protection */ + BOOLEAN fgIsBasicRate; /* Force Basic Rate Transmission */ + + /* flattened from PACKET_INFO_T */ + UINT_8 ucMacHeaderLength; + UINT_8 ucLlcLength; /* w/o EtherType */ + UINT_16 u2FrameLength; + UINT_8 aucEthDestAddr[MAC_ADDR_LEN]; /* Ethernet Destination Address */ + + /* for TX done tracking */ + UINT_8 ucTxSeqNum; + PFN_TX_DONE_HANDLER pfTxDoneHandler; +}; + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define TX_INC_CNT(prTxCtrl, eCounter) \ + {((P_TX_CTRL_T)prTxCtrl)->au4Statistics[eCounter]++;} + +#define TX_ADD_CNT(prTxCtrl, eCounter, u8Amount) \ + {((P_TX_CTRL_T)prTxCtrl)->au4Statistics[eCounter] += (UINT_32)u8Amount;} + +#define TX_GET_CNT(prTxCtrl, eCounter) \ + (((P_TX_CTRL_T)prTxCtrl)->au4Statistics[eCounter]) + +#define TX_RESET_ALL_CNTS(prTxCtrl) \ + {kalMemZero(&prTxCtrl->au4Statistics[0], sizeof(prTxCtrl->au4Statistics));} + + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID +nicTxInitialize ( + IN P_ADAPTER_T prAdapter + ); + +WLAN_STATUS +nicTxAcquireResource ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucTC + ); + +WLAN_STATUS +nicTxPollingResource ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucTC + ); + +BOOLEAN +nicTxReleaseResource ( + IN P_ADAPTER_T prAdapter, + IN UINT_8* aucTxRlsCnt + ); + +WLAN_STATUS +nicTxResetResource ( + IN P_ADAPTER_T prAdapter + ); + +UINT_8 +nicTxGetResource ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucTC + ); + +WLAN_STATUS +nicTxMsduInfoList ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfoListHead + ); + +WLAN_STATUS +nicTxMsduQueue ( + IN P_ADAPTER_T prAdapter, + UINT_8 ucPortIdx, + P_QUE_T prQue + ); + +WLAN_STATUS +nicTxCmd ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN UINT_8 ucTC + ); + +VOID +nicTxRelease ( + IN P_ADAPTER_T prAdapter + ); + +VOID +nicProcessTxInterrupt ( + IN P_ADAPTER_T prAdapter + ); + +VOID +nicTxFreeMsduInfoPacket ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfoListHead + ); + +VOID +nicTxReturnMsduInfo ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfoListHead + ); + +BOOLEAN +nicTxFillMsduInfo ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN P_NATIVE_PACKET prNdisPacket + ); + +WLAN_STATUS +nicTxAdjustTcq ( + IN P_ADAPTER_T prAdapter + ); + +WLAN_STATUS +nicTxFlush ( + IN P_ADAPTER_T prAdapter + ); + +#if CFG_ENABLE_FW_DOWNLOAD +WLAN_STATUS +nicTxInitCmd ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN UINT_8 ucTC + ); + +WLAN_STATUS +nicTxInitResetResource ( + IN P_ADAPTER_T prAdapter + ); +#endif + +WLAN_STATUS +nicTxEnqueueMsdu ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + +UINT_32 +nicTxGetFreeCmdCount ( + IN P_ADAPTER_T prAdapter + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _NIC_TX_H */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/que_mgt.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/que_mgt.h new file mode 100755 index 000000000000..68931e663cb2 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/que_mgt.h @@ -0,0 +1,1185 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/nic/que_mgt.h#1 $ +*/ + +/*! \file "que_mgt.h" + \brief TX/RX queues management header file + + The main tasks of queue management include TC-based HIF TX flow control, + adaptive TC quota adjustment, HIF TX grant scheduling, Power-Save + forwarding control, RX packet reordering, and RX BA agreement management. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: que_mgt.h $ + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 06 14 2011 eddie.chen + * [WCXRP00000753] [MT5931 Wi-Fi][DRV] Adjust QM for MT5931 + * Change the parameter for WMM pass. + * + * 05 31 2011 eddie.chen + * [WCXRP00000753] [MT5931 Wi-Fi][DRV] Adjust QM for MT5931 + * Fix the QM quota in MT5931. + * + * 05 09 2011 eddie.chen + * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet + * Check free number before copying broadcast packet. + * + * 04 14 2011 eddie.chen + * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning + * Check the SW RFB free. Fix the compile warning.. + * + * 04 07 2011 eddie.chen + * [WCXRP00000527] [MT6620 Wi-Fi][FW/Driver] Clean buffered packet when BSS is inactive or disconnected + * Add functino to remove broadcast and unknown packets. + * + * 04 07 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix for sigma. + * + * 03 28 2011 eddie.chen + * [WCXRP00000602] [MT6620 Wi-Fi][DRV] Fix wmm parameters in beacon for BOW + * Fix wmm parameters in beacon for BOW. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 15 2011 eddie.chen + * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter + * Add sw debug counter for QM. + * + * 02 17 2011 eddie.chen + * [WCXRP00000458] [MT6620 Wi-Fi][Driver] BOW Concurrent - ProbeResp was exist in other channel + * 1) Chnage GetFrameAction decision when BSS is absent. + * 2) Check channel and resource in processing ProbeRequest + * + * 01 12 2011 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, + +Add per station flow control when STA is in PS + + + * 1) Check Bss if support QoS before adding WMMIE + * 2) Check if support prAdapter->rWifiVar QoS and uapsd in flow control + * + * 12 29 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, + +Add per station flow control when STA is in PS + + + * 1) PS flow control event + * + * 2) WMM IE in beacon, assoc resp, probe resp + * + * 12 23 2010 george.huang + * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function + * 1. update WMM IE parsing, with ASSOC REQ handling + * 2. extend U-APSD parameter passing from driver to FW + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by ENUM_NETWORK_TYPE_INDEX_T only + * remove ENUM_NETWORK_TYPE_T definitions + * + * 09 21 2010 kevin.huang + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * Eliminate Linux Compile Warning + * + * 08 04 2010 yarco.yang + * NULL + * Add TX_AMPDU and ADDBA_REJECT command + * + * 07 22 2010 george.huang + * + * Update fgIsQoS information in BSS INFO by CMD + * + * 07 16 2010 yarco.yang + * + * 1. Support BSS Absence/Presence Event + * 2. Support STA change PS mode Event + * 3. Support BMC forwarding for AP mode. + * + * 07 14 2010 yarco.yang + * + * 1. Remove CFG_MQM_MIGRATION + * 2. Add CMD_UPDATE_WMM_PARMS command + * + * 07 13 2010 yarco.yang + * + * [WPD00003849] + * [MT6620 and MT5931] SW Migration, add qmGetFrameAction() API for CMD Queue Processing + * + * 07 09 2010 yarco.yang + * + * [MT6620 and MT5931] SW Migration: Add ADDBA support + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 29 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * replace g_rQM with Adpater->rQM + * + * 06 25 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add API in que_mgt to retrieve sta-rec index for security frames. + * + * 06 23 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Merge g_arStaRec[] into adapter->arStaRec[] + * + * 06 21 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Support CFG_MQM_MIGRATION flag + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add hem_mbox.c and cnm_mem.h (but disabled some feature) for further migration + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 03 30 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Enabled adaptive TC resource control + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port + * + * 03 19 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * By default enabling dynamic STA_REC activation and decactivation + * + * 03 17 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Changed STA_REC index determination rules (DA=BMCAST always --> STA_REC_INDEX_BMCAST) + * + * 03 11 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Fixed buffer leak when processing BAR frames + * + * 02 25 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Enabled multi-STA TX path with fairness + * + * 02 24 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Enabled dynamically activating and deactivating STA_RECs + * + * 02 24 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Added code for dynamic activating and deactivating STA_RECs. + * + * 01 13 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Enabled the Burst_End Indication mechanism +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-12-09 14:04:53 GMT MTK02468 +** Added RX buffer reordering function prototypes +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-12-02 22:08:44 GMT MTK02468 +** Added macro QM_INIT_STA_REC for initialize a STA_REC +** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-11-23 21:58:43 GMT mtk02468 +** Initial version +** +*/ + +#ifndef _QUE_MGT_H +#define _QUE_MGT_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/* Queue Manager Features */ +#define QM_BURST_END_INFO_ENABLED 1 /* 1: Indicate the last TX packet to the FW for each burst */ +#define QM_FORWARDING_FAIRNESS 1 /* 1: To fairly share TX resource among active STAs */ +#define QM_ADAPTIVE_TC_RESOURCE_CTRL 1 /* 1: To adaptively adjust resource for each TC */ +#define QM_PRINT_TC_RESOURCE_CTRL 0 /* 1: To print TC resource adjustment results */ +#define QM_RX_WIN_SSN_AUTO_ADVANCING 1 /* 1: If pkt with SSN is missing, auto advance the RX reordering window */ +#define QM_RX_INIT_FALL_BEHIND_PASS 1 /* 1: Indicate the packets falling behind to OS before the frame with SSN is received */ +/* Parameters */ +#define QM_INIT_TIME_TO_UPDATE_QUE_LEN 60 /* p: Update queue lengths when p TX packets are enqueued */ +#define QM_INIT_TIME_TO_ADJUST_TC_RSC 3 /* s: Adjust the TC resource every s updates of queue lengths */ +#define QM_QUE_LEN_MOVING_AVE_FACTOR 3 /* Factor for Que Len averaging */ + +#define QM_MIN_RESERVED_TC0_RESOURCE 1 +#define QM_MIN_RESERVED_TC1_RESOURCE 1 +#define QM_MIN_RESERVED_TC2_RESOURCE 1 +#define QM_MIN_RESERVED_TC3_RESOURCE 1 +#define QM_MIN_RESERVED_TC4_RESOURCE 2 /* Resource for TC4 is not adjustable */ +#define QM_MIN_RESERVED_TC5_RESOURCE 1 + +#if defined(MT6620) + +#define QM_GUARANTEED_TC0_RESOURCE 4 +#define QM_GUARANTEED_TC1_RESOURCE 4 +#define QM_GUARANTEED_TC2_RESOURCE 9 +#define QM_GUARANTEED_TC3_RESOURCE 11 +#define QM_GUARANTEED_TC4_RESOURCE 2 /* Resource for TC4 is not adjustable */ +#define QM_GUARANTEED_TC5_RESOURCE 4 + +#elif defined(MT5931) || defined(MT6628) + +#define QM_GUARANTEED_TC0_RESOURCE 4 +#define QM_GUARANTEED_TC1_RESOURCE 4 +#define QM_GUARANTEED_TC2_RESOURCE 4 +#define QM_GUARANTEED_TC3_RESOURCE 4 +#define QM_GUARANTEED_TC4_RESOURCE 2 /* Resource for TC4 is not adjustable */ +#define QM_GUARANTEED_TC5_RESOURCE 2 + +#else +#error +#endif + + + +#define QM_EXTRA_RESERVED_RESOURCE_WHEN_BUSY 0 + +#define QM_TOTAL_TC_RESOURCE (\ + NIC_TX_BUFF_COUNT_TC0 + NIC_TX_BUFF_COUNT_TC1 +\ + NIC_TX_BUFF_COUNT_TC2 + NIC_TX_BUFF_COUNT_TC3 +\ + NIC_TX_BUFF_COUNT_TC5) +#define QM_AVERAGE_TC_RESOURCE 6 + +/* Note: QM_INITIAL_RESIDUAL_TC_RESOURCE shall not be less than 0 */ +#define QM_INITIAL_RESIDUAL_TC_RESOURCE (QM_TOTAL_TC_RESOURCE - \ + (QM_GUARANTEED_TC0_RESOURCE +\ + QM_GUARANTEED_TC1_RESOURCE +\ + QM_GUARANTEED_TC2_RESOURCE +\ + QM_GUARANTEED_TC3_RESOURCE +\ + QM_GUARANTEED_TC5_RESOURCE \ + )) + +/* Hard-coded network type for Phase 3: NETWORK_TYPE_AIS/P2P/BOW */ +#define QM_OPERATING_NETWORK_TYPE NETWORK_TYPE_AIS + +#define QM_TEST_MODE 0 +#define QM_TEST_TRIGGER_TX_COUNT 50 +#define QM_TEST_STA_REC_DETERMINATION 0 +#define QM_TEST_STA_REC_DEACTIVATION 0 +#define QM_TEST_FAIR_FORWARDING 0 + +#define QM_DEBUG_COUNTER 0 + +/* Per-STA Queues: [0] AC0, [1] AC1, [2] AC2, [3] AC3, [4] 802.1x */ +/* Per-Type Queues: [0] BMCAST */ +#define NUM_OF_PER_STA_TX_QUEUES 5 +#define NUM_OF_PER_TYPE_TX_QUEUES 1 + +/* These two constants are also used for FW to verify the STA_REC index */ +#define STA_REC_INDEX_BMCAST 0xFF +#define STA_REC_INDEX_NOT_FOUND 0xFE + +/* TX Queue Index */ +#define TX_QUEUE_INDEX_BMCAST 0 +#define TX_QUEUE_INDEX_NO_STA_REC 0 +#define TX_QUEUE_INDEX_AC0 0 +#define TX_QUEUE_INDEX_AC1 1 +#define TX_QUEUE_INDEX_AC2 2 +#define TX_QUEUE_INDEX_AC3 3 +#define TX_QUEUE_INDEX_802_1X 4 +#define TX_QUEUE_INDEX_NON_QOS 1 + + +//1 WMM-related +/* WMM FLAGS */ +#define WMM_FLAG_SUPPORT_WMM BIT(0) +#define WMM_FLAG_SUPPORT_WMMSA BIT(1) +#define WMM_FLAG_AC_PARAM_PRESENT BIT(2) +#define WMM_FLAG_SUPPORT_UAPSD BIT(3) + +/* WMM Admission Control Mandatory FLAGS */ +#define ACM_FLAG_ADM_NOT_REQUIRED 0 +#define ACM_FLAG_ADM_GRANTED BIT(0) +#define ACM_FLAG_ADM_REQUIRED BIT(1) + +/* WMM Power Saving FLAGS */ +#define AC_FLAG_TRIGGER_ENABLED BIT(1) +#define AC_FLAG_DELIVERY_ENABLED BIT(2) + +/* WMM-2.2.1 WMM Information Element */ +#define ELEM_MAX_LEN_WMM_INFO 7 + +/* WMM-2.2.2 WMM Parameter Element */ +#define ELEM_MAX_LEN_WMM_PARAM 24 + +/* WMM-2.2.1 WMM QoS Info field */ +#define WMM_QOS_INFO_PARAM_SET_CNT BITS(0,3) /* Sent by AP */ +#define WMM_QOS_INFO_UAPSD BIT(7) + +#define WMM_QOS_INFO_VO_UAPSD BIT(0) /* Sent by non-AP STA */ +#define WMM_QOS_INFO_VI_UAPSD BIT(1) +#define WMM_QOS_INFO_BK_UAPSD BIT(2) +#define WMM_QOS_INFO_BE_UAPSD BIT(3) +#define WMM_QOS_INFO_MAX_SP_LEN_MASK BITS(5,6) +#define WMM_QOS_INFO_MAX_SP_ALL 0 +#define WMM_QOS_INFO_MAX_SP_2 BIT(5) +#define WMM_QOS_INFO_MAX_SP_4 BIT(6) +#define WMM_QOS_INFO_MAX_SP_6 BITS(5,6) + +/* -- definitions for Max SP length field */ +#define WMM_MAX_SP_LENGTH_ALL 0 +#define WMM_MAX_SP_LENGTH_2 2 +#define WMM_MAX_SP_LENGTH_4 4 +#define WMM_MAX_SP_LENGTH_6 6 + + +/* WMM-2.2.2 WMM ACI/AIFSN field */ +/* -- subfields in the ACI/AIFSN field */ +#define WMM_ACIAIFSN_AIFSN BITS(0,3) +#define WMM_ACIAIFSN_ACM BIT(4) +#define WMM_ACIAIFSN_ACI BITS(5,6) +#define WMM_ACIAIFSN_ACI_OFFSET 5 + +/* -- definitions for ACI field */ +#define WMM_ACI_AC_BE 0 +#define WMM_ACI_AC_BK BIT(5) +#define WMM_ACI_AC_VI BIT(6) +#define WMM_ACI_AC_VO BITS(5,6) + +#define WMM_ACI(_AC) (_AC << WMM_ACIAIFSN_ACI_OFFSET) + +/* -- definitions for ECWmin/ECWmax field */ +#define WMM_ECW_WMIN_MASK BITS(0,3) +#define WMM_ECW_WMAX_MASK BITS(4,7) +#define WMM_ECW_WMAX_OFFSET 4 + +#define TXM_DEFAULT_FLUSH_QUEUE_GUARD_TIME 0 /* Unit: 64 us */ + + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +enum { + QM_DBG_CNT_00=0, + QM_DBG_CNT_01, + QM_DBG_CNT_02, + QM_DBG_CNT_03, + QM_DBG_CNT_04, + QM_DBG_CNT_05, + QM_DBG_CNT_06, + QM_DBG_CNT_07, + QM_DBG_CNT_08, + QM_DBG_CNT_09, + QM_DBG_CNT_10, + QM_DBG_CNT_11, + QM_DBG_CNT_12, + QM_DBG_CNT_13, + QM_DBG_CNT_14, + QM_DBG_CNT_15, + QM_DBG_CNT_16, + QM_DBG_CNT_17, + QM_DBG_CNT_18, + QM_DBG_CNT_19, + QM_DBG_CNT_20, + QM_DBG_CNT_21, + QM_DBG_CNT_22, + QM_DBG_CNT_23, + QM_DBG_CNT_24, + QM_DBG_CNT_25, + QM_DBG_CNT_26, + QM_DBG_CNT_27, + QM_DBG_CNT_28, + QM_DBG_CNT_29, + QM_DBG_CNT_30, + QM_DBG_CNT_31, + QM_DBG_CNT_NUM +}; + + + + +/* Used for MAC TX */ +typedef enum _ENUM_MAC_TX_QUEUE_INDEX_T { + MAC_TX_QUEUE_AC0_INDEX = 0, + MAC_TX_QUEUE_AC1_INDEX, + MAC_TX_QUEUE_AC2_INDEX, + MAC_TX_QUEUE_AC3_INDEX, + MAC_TX_QUEUE_AC4_INDEX, + MAC_TX_QUEUE_AC5_INDEX, + MAC_TX_QUEUE_AC6_INDEX, + MAC_TX_QUEUE_BCN_INDEX, + MAC_TX_QUEUE_BMC_INDEX, + MAC_TX_QUEUE_NUM +} ENUM_MAC_TX_QUEUE_INDEX_T; + +typedef struct _RX_BA_ENTRY_T { + BOOLEAN fgIsValid; + QUE_T rReOrderQue; + UINT_16 u2WinStart; + UINT_16 u2WinEnd; + UINT_16 u2WinSize; + + /* For identifying the RX BA agreement */ + UINT_8 ucStaRecIdx; + UINT_8 ucTid; + + BOOLEAN fgIsWaitingForPktWithSsn; + + //UINT_8 ucTxBufferSize; + //BOOL fgIsAcConstrain; + //BOOL fgIsBaEnabled; +} RX_BA_ENTRY_T, *P_RX_BA_ENTRY_T; + +/* The mailbox message (could be used for Host-To-Device or Device-To-Host Mailbox) */ +typedef struct _MAILBOX_MSG_T{ + UINT_32 u4Msg[2]; /* [0]: D2HRM0R or H2DRM0R, [1]: D2HRM1R or H2DRM1R */ +} MAILBOX_MSG_T, *P_MAILBOX_MSG_T; + + +/* Used for adaptively adjusting TC resources */ +typedef struct _TC_RESOURCE_CTRL_T { + /* TC0, TC1, TC2, TC3, TC5 */ + UINT_32 au4AverageQueLen[TC_NUM - 1]; +} TC_RESOURCE_CTRL_T, *P_TC_RESOURCE_CTRL_T; + +typedef struct _QUE_MGT_T{ /* Queue Management Control Info */ + + /* Per-Type Queues: [0] BMCAST or UNKNOWN-STA packets */ + QUE_T arTxQueue[NUM_OF_PER_TYPE_TX_QUEUES]; + +#if 0 + /* For TX Scheduling */ + UINT_8 arRemainingTxOppt[NUM_OF_PER_STA_TX_QUEUES]; + UINT_8 arCurrentTxStaIndex[NUM_OF_PER_STA_TX_QUEUES]; + +#endif + + /* Reordering Queue Parameters */ + RX_BA_ENTRY_T arRxBaTable[CFG_NUM_OF_RX_BA_AGREEMENTS]; + + /* Current number of activated RX BA agreements <= CFG_NUM_OF_RX_BA_AGREEMENTS */ + UINT_8 ucRxBaCount; + +#if QM_TEST_MODE + UINT_32 u4PktCount; + P_ADAPTER_T prAdapter; + +#if QM_TEST_FAIR_FORWARDING + UINT_32 u4CurrentStaRecIndexToEnqueue; +#endif + +#endif + + +#if QM_FORWARDING_FAIRNESS + /* The current TX count for a STA with respect to a TC index */ + UINT_32 au4ForwardCount[NUM_OF_PER_STA_TX_QUEUES]; + + /* The current serving STA with respect to a TC index */ + UINT_32 au4HeadStaRecIndex [NUM_OF_PER_STA_TX_QUEUES]; +#endif + +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + UINT_32 au4AverageQueLen[TC_NUM]; + UINT_32 au4CurrentTcResource[TC_NUM]; + UINT_32 au4MinReservedTcResource[TC_NUM]; /* The minimum amount of resource no matter busy or idle */ + UINT_32 au4GuaranteedTcResource[TC_NUM]; /* The minimum amount of resource when extremely busy */ + + UINT_32 u4TimeToAdjustTcResource; + UINT_32 u4TimeToUpdateQueLen; + + /* Set to TRUE if the last TC adjustment has not been completely applied (i.e., waiting more TX-Done events + to align the TC quotas to the TC resource assignment) */ + BOOLEAN fgTcResourcePostAnnealing; + +#endif + +#if QM_DEBUG_COUNTER + UINT_32 au4QmDebugCounters[QM_DBG_CNT_NUM]; +#endif + + + + +} QUE_MGT_T, *P_QUE_MGT_T; + + + +typedef struct _EVENT_RX_ADDBA_T { + /* Event header */ + UINT_16 u2Length; + UINT_16 u2Reserved1; /* Must be filled with 0x0001 (EVENT Packet) */ + UINT_8 ucEID; + UINT_8 ucSeqNum; + UINT_8 aucReserved2[2]; + + /* Fields not present in the received ADDBA_REQ */ + UINT_8 ucStaRecIdx; + + /* Fields that are present in the received ADDBA_REQ */ + UINT_8 ucDialogToken; /* Dialog Token chosen by the sender */ + UINT_16 u2BAParameterSet; /* BA policy, TID, buffer size */ + UINT_16 u2BATimeoutValue; + UINT_16 u2BAStartSeqCtrl; /* SSN */ + +} EVENT_RX_ADDBA_T, *P_EVENT_RX_ADDBA_T; + +typedef struct _EVENT_RX_DELBA_T { + /* Event header */ + UINT_16 u2Length; + UINT_16 u2Reserved1; /* Must be filled with 0x0001 (EVENT Packet) */ + UINT_8 ucEID; + UINT_8 ucSeqNum; + UINT_8 aucReserved2[2]; + + /* Fields not present in the received ADDBA_REQ */ + UINT_8 ucStaRecIdx; + UINT_8 ucTid; +} EVENT_RX_DELBA_T, *P_EVENT_RX_DELBA_T; + + +typedef struct _EVENT_BSS_ABSENCE_PRESENCE_T { + /* Event header */ + UINT_16 u2Length; + UINT_16 u2Reserved1; /* Must be filled with 0x0001 (EVENT Packet) */ + UINT_8 ucEID; + UINT_8 ucSeqNum; + UINT_8 aucReserved2[2]; + + /* Event Body */ + UINT_8 ucNetTypeIdx; + BOOLEAN fgIsAbsent; + UINT_8 ucBssFreeQuota; + UINT_8 aucReserved[1]; +} EVENT_BSS_ABSENCE_PRESENCE_T, *P_EVENT_BSS_ABSENCE_PRESENCE_T; + + +typedef struct _EVENT_STA_CHANGE_PS_MODE_T { + /* Event header */ + UINT_16 u2Length; + UINT_16 u2Reserved1; /* Must be filled with 0x0001 (EVENT Packet) */ + UINT_8 ucEID; + UINT_8 ucSeqNum; + UINT_8 aucReserved2[2]; + + /* Event Body */ + UINT_8 ucStaRecIdx; + BOOLEAN fgIsInPs; + UINT_8 ucUpdateMode; + UINT_8 ucFreeQuota; +} EVENT_STA_CHANGE_PS_MODE_T, *P_EVENT_STA_CHANGE_PS_MODE_T; + +/* The free quota is used by PS only now */ +/* The event may be used by per STA flow conttrol in general */ +typedef struct _EVENT_STA_UPDATE_FREE_QUOTA_T { + /* Event header */ + UINT_16 u2Length; + UINT_16 u2Reserved1; /* Must be filled with 0x0001 (EVENT Packet) */ + UINT_8 ucEID; + UINT_8 ucSeqNum; + UINT_8 aucReserved2[2]; + + /* Event Body */ + UINT_8 ucStaRecIdx; + UINT_8 ucUpdateMode; + UINT_8 ucFreeQuota; + UINT_8 aucReserved[1]; +} EVENT_STA_UPDATE_FREE_QUOTA_T, *P_EVENT_STA_UPDATE_FREE_QUOTA_T; + + + + +/* WMM-2.2.1 WMM Information Element */ +typedef struct _IE_WMM_INFO_T { + UINT_8 ucId; /* Element ID */ + UINT_8 ucLength; /* Length */ + UINT_8 aucOui[3]; /* OUI */ + UINT_8 ucOuiType; /* OUI Type */ + UINT_8 ucOuiSubtype; /* OUI Subtype */ + UINT_8 ucVersion; /* Version */ + UINT_8 ucQosInfo; /* QoS Info field */ + UINT_8 ucDummy[3]; /* Dummy for pack */ +} IE_WMM_INFO_T, *P_IE_WMM_INFO_T; + +/* WMM-2.2.2 WMM Parameter Element */ +typedef struct _IE_WMM_PARAM_T { + UINT_8 ucId; /* Element ID */ + UINT_8 ucLength; /* Length */ + + /* IE Body */ + UINT_8 aucOui[3]; /* OUI */ + UINT_8 ucOuiType; /* OUI Type */ + UINT_8 ucOuiSubtype; /* OUI Subtype */ + UINT_8 ucVersion; /* Version */ + + /* WMM IE Body */ + UINT_8 ucQosInfo; /* QoS Info field */ + UINT_8 ucReserved; + + /* AC Parameters */ + UINT_8 ucAciAifsn_BE; + UINT_8 ucEcw_BE; + UINT_8 aucTxopLimit_BE[2]; + + UINT_8 ucAciAifsn_BG; + UINT_8 ucEcw_BG; + UINT_8 aucTxopLimit_BG[2]; + + UINT_8 ucAciAifsn_VI; + UINT_8 ucEcw_VI; + UINT_8 aucTxopLimit_VI[2]; + + UINT_8 ucAciAifsn_VO; + UINT_8 ucEcw_VO; + UINT_8 aucTxopLimit_VO[2]; + +} IE_WMM_PARAM_T, *P_IE_WMM_PARAM_T; + +typedef struct _IE_WMM_TSPEC_T { + UINT_8 ucId; /* Element ID */ + UINT_8 ucLength; /* Length */ + UINT_8 aucOui[3]; /* OUI */ + UINT_8 ucOuiType; /* OUI Type */ + UINT_8 ucOuiSubtype; /* OUI Subtype */ + UINT_8 ucVersion; /* Version */ + /* WMM TSPEC body */ + UINT_8 aucTsInfo[3]; /* TS Info */ + UINT_8 aucTspecBodyPart[1]; /* Note: Utilize PARAM_QOS_TSPEC to fill (memory copy) */ +} IE_WMM_TSPEC_T, *P_IE_WMM_TSPEC_T; + +typedef struct _IE_WMM_HDR_T { + UINT_8 ucId; /* Element ID */ + UINT_8 ucLength; /* Length */ + UINT_8 aucOui[3]; /* OUI */ + UINT_8 ucOuiType; /* OUI Type */ + UINT_8 ucOuiSubtype; /* OUI Subtype */ + UINT_8 ucVersion; /* Version */ + UINT_8 aucBody[1]; /* IE body */ +} IE_WMM_HDR_T, *P_IE_WMM_HDR_T; + + +typedef struct _AC_QUE_PARMS_T{ + UINT_16 u2CWmin; /*!< CWmin */ + UINT_16 u2CWmax; /*!< CWmax */ + UINT_16 u2TxopLimit; /*!< TXOP limit */ + UINT_16 u2Aifsn; /*!< AIFSN */ + UINT_8 ucGuradTime; /*!< GuardTime for STOP/FLUSH. */ + BOOLEAN fgIsACMSet; +} AC_QUE_PARMS_T, *P_AC_QUE_PARMS_T; + +/* WMM ACI (AC index) */ +typedef enum _ENUM_WMM_ACI_T { + WMM_AC_BE_INDEX = 0, + WMM_AC_BK_INDEX, + WMM_AC_VI_INDEX, + WMM_AC_VO_INDEX, + WMM_AC_INDEX_NUM +} ENUM_WMM_ACI_T, *P_ENUM_WMM_ACI_T; + + +/* Used for CMD Queue Operation */ +typedef enum _ENUM_FRAME_ACTION_T { + FRAME_ACTION_DROP_PKT = 0, + FRAME_ACTION_QUEUE_PKT, + FRAME_ACTION_TX_PKT, + FRAME_ACTION_NUM +} ENUM_FRAME_ACTION_T; + + +typedef enum _ENUM_FRAME_TYPE_IN_CMD_Q_T { + FRAME_TYPE_802_1X = 0, + FRAME_TYPE_MMPDU, + FRAME_TYEP_NUM +} ENUM_FRAME_TYPE_IN_CMD_Q_T; + +typedef enum _ENUM_FREE_QUOTA_MODET_T { + FREE_QUOTA_UPDATE_MODE_INIT = 0, + FREE_QUOTA_UPDATE_MODE_OVERWRITE, + FREE_QUOTA_UPDATE_MODE_INCREASE, + FREE_QUOTA_UPDATE_MODE_DECREASE +} ENUM_FREE_QUOTA_MODET_T, *P_ENUM_FREE_QUOTA_MODET_T; + + + +typedef struct _CMD_UPDATE_WMM_PARMS_T { + AC_QUE_PARMS_T arACQueParms[AC_NUM]; + UINT_8 ucNetTypeIndex; + UINT_8 fgIsQBSS; + UINT_8 aucReserved[2]; +} CMD_UPDATE_WMM_PARMS_T, *P_CMD_UPDATE_WMM_PARMS_T; + + +typedef struct _CMD_TX_AMPDU_T { + BOOLEAN fgEnable; + UINT_8 aucReserved[3]; +} CMD_TX_AMPDU_T, *P_CMD_TX_AMPDU_T; + + +typedef struct _CMD_ADDBA_REJECT { + BOOLEAN fgEnable; + UINT_8 aucReserved[3]; +} CMD_ADDBA_REJECT_T, *P_CMD_ADDBA_REJECT_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define QM_TX_SET_NEXT_MSDU_INFO(_prMsduInfoPreceding, _prMsduInfoNext) \ + ((((_prMsduInfoPreceding)->rQueEntry).prNext) = (P_QUE_ENTRY_T)(_prMsduInfoNext)) + +#define QM_TX_SET_NEXT_SW_RFB(_prSwRfbPreceding, _prSwRfbNext) \ + ((((_prSwRfbPreceding)->rQueEntry).prNext) = (P_QUE_ENTRY_T)(_prSwRfbNext)) + + +#define QM_TX_GET_NEXT_MSDU_INFO(_prMsduInfo) \ + ((P_MSDU_INFO_T)(((_prMsduInfo)->rQueEntry).prNext)) + +#define QM_RX_SET_NEXT_SW_RFB(_prSwRfbPreceding, _prSwRfbNext) \ + ((((_prSwRfbPreceding)->rQueEntry).prNext) = (P_QUE_ENTRY_T)(_prSwRfbNext)) + +#define QM_RX_GET_NEXT_SW_RFB(_prSwRfb) \ + ((P_SW_RFB_T)(((_prSwRfb)->rQueEntry).prNext)) + +#if 0 +#define QM_GET_STA_REC_PTR_FROM_INDEX(_prAdapter, _ucIndex) \ + ((((_ucIndex) != STA_REC_INDEX_BMCAST) && ((_ucIndex)!= STA_REC_INDEX_NOT_FOUND)) ?\ + &(_prAdapter->arStaRec[_ucIndex]): NULL) +#endif + +#define QM_GET_STA_REC_PTR_FROM_INDEX(_prAdapter, _ucIndex) \ + cnmGetStaRecByIndex(_prAdapter,_ucIndex) + + +#define QM_TX_SET_MSDU_INFO_FOR_DATA_PACKET(\ + _prMsduInfo,\ + _ucTC,\ + _ucPacketType,\ + _ucFormatID,\ + _fgIs802_1x,\ + _fgIs802_11,\ + _u2PalLLH,\ + _u2AclSN,\ + _ucPsForwardingType,\ + _ucPsSessionID\ + ) \ +{\ + ASSERT(_prMsduInfo);\ + (_prMsduInfo)->ucTC = (_ucTC);\ + (_prMsduInfo)->ucPacketType = (_ucPacketType);\ + (_prMsduInfo)->ucFormatID = (_ucFormatID);\ + (_prMsduInfo)->fgIs802_1x = (_fgIs802_1x);\ + (_prMsduInfo)->fgIs802_11 = (_fgIs802_11);\ + (_prMsduInfo)->u2PalLLH = (_u2PalLLH);\ + (_prMsduInfo)->u2AclSN = (_u2AclSN);\ + (_prMsduInfo)->ucPsForwardingType = (_ucPsForwardingType);\ + (_prMsduInfo)->ucPsSessionID = (_ucPsSessionID);\ + (_prMsduInfo)->fgIsBurstEnd = (FALSE);\ +} + +#define QM_INIT_STA_REC(\ + _prStaRec,\ + _fgIsValid,\ + _fgIsQoS,\ + _pucMacAddr\ + )\ +{\ + ASSERT(_prStaRec);\ + (_prStaRec)->fgIsValid = (_fgIsValid);\ + (_prStaRec)->fgIsQoS = (_fgIsQoS);\ + (_prStaRec)->fgIsInPS = FALSE; \ + (_prStaRec)->ucPsSessionID = 0xFF;\ + COPY_MAC_ADDR((_prStaRec)->aucMacAddr,(_pucMacAddr));\ +} + +#if QM_ADAPTIVE_TC_RESOURCE_CTRL +#define QM_GET_TX_QUEUE_LEN(_prAdapter, _u4QueIdx) ((_prAdapter->rQM.au4AverageQueLen[(_u4QueIdx)] >> QM_QUE_LEN_MOVING_AVE_FACTOR)) +#endif + + +#define WMM_IE_OUI_TYPE(fp) (((P_IE_WMM_HDR_T)(fp))->ucOuiType) +#define WMM_IE_OUI_SUBTYPE(fp) (((P_IE_WMM_HDR_T)(fp))->ucOuiSubtype) +#define WMM_IE_OUI(fp) (((P_IE_WMM_HDR_T)(fp))->aucOui) + +#if QM_DEBUG_COUNTER +#define QM_DBG_CNT_INC(_prQM, _index) { (_prQM)->au4QmDebugCounters[(_index)]++; } +#else +#define QM_DBG_CNT_INC(_prQM, _index) {} +#endif + + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Queue Management and STA_REC Initialization */ +/*----------------------------------------------------------------------------*/ + +VOID +qmInit( + IN P_ADAPTER_T prAdapter + ); + +#if QM_TEST_MODE +VOID +qmTestCases( + IN P_ADAPTER_T prAdapter + ); +#endif + +VOID +qmActivateStaRec( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ); + +VOID +qmDeactivateStaRec( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4StaRecIdx + ); + + +/*----------------------------------------------------------------------------*/ +/* TX-Related Queue Management */ +/*----------------------------------------------------------------------------*/ + +P_MSDU_INFO_T +qmFlushTxQueues( + IN P_ADAPTER_T prAdapter + ); + +P_MSDU_INFO_T +qmFlushStaTxQueues( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4StaRecIdx + ); + +P_MSDU_INFO_T +qmEnqueueTxPackets( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfoListHead + ); + +P_MSDU_INFO_T +qmDequeueTxPackets( + IN P_ADAPTER_T prAdapter, + IN P_TX_TCQ_STATUS_T prTcqStatus + ); + +VOID +qmAdjustTcQuotas ( + IN P_ADAPTER_T prAdapter, + OUT P_TX_TCQ_ADJUST_T prTcqAdjust, + IN P_TX_TCQ_STATUS_T prTcqStatus + ); + + +#if QM_ADAPTIVE_TC_RESOURCE_CTRL +VOID +qmReassignTcResource( + IN P_ADAPTER_T prAdapter + ); + +VOID +qmUpdateAverageTxQueLen( + IN P_ADAPTER_T prAdapter + ); +#endif + + +/*----------------------------------------------------------------------------*/ +/* RX-Related Queue Management */ +/*----------------------------------------------------------------------------*/ + +VOID +qmInitRxQueues( + IN P_ADAPTER_T prAdapter + ); + +P_SW_RFB_T +qmFlushRxQueues( + IN P_ADAPTER_T prAdapter + ); + +P_SW_RFB_T +qmHandleRxPackets( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfbListHead + ); + +VOID +qmProcessPktWithReordering( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT P_QUE_T prReturnedQue + ); + +VOID +qmProcessBarFrame( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT P_QUE_T prReturnedQue + ); + +VOID +qmInsertFallWithinReorderPkt( + IN P_SW_RFB_T prSwRfb, + IN P_RX_BA_ENTRY_T prReorderQueParm, + OUT P_QUE_T prReturnedQue + ); + +VOID +qmInsertFallAheadReorderPkt( + IN P_SW_RFB_T prSwRfb, + IN P_RX_BA_ENTRY_T prReorderQueParm, + OUT P_QUE_T prReturnedQue + ); + +VOID +qmPopOutDueToFallWithin( + IN P_RX_BA_ENTRY_T prReorderQueParm, + OUT P_QUE_T prReturnedQue + ); + +VOID +qmPopOutDueToFallAhead( + IN P_RX_BA_ENTRY_T prReorderQueParm, + OUT P_QUE_T prReturnedQue + ); + + +VOID +qmHandleMailboxRxMessage( + IN MAILBOX_MSG_T prMailboxRxMsg + ); + +BOOLEAN +qmCompareSnIsLessThan( + IN UINT_32 u4SnLess, + IN UINT_32 u4SnGreater + ); + +VOID +qmHandleEventRxAddBa( + IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent + ); + +VOID +qmHandleEventRxDelBa( + IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent + ); + +P_RX_BA_ENTRY_T +qmLookupRxBaEntry( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucStaRecIdx, + IN UINT_8 ucTid + ); + +BOOL +qmAddRxBaEntry( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucStaRecIdx, + IN UINT_8 ucTid, + IN UINT_16 u2WinStart, + IN UINT_16 u2WinSize + ); + + +VOID +qmDelRxBaEntry( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucStaRecIdx, + IN UINT_8 ucTid, + IN BOOLEAN fgFlushToHost + ); + + +VOID +mqmProcessAssocRsp ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN PUINT_8 pucIE, + IN UINT_16 u2IELength + ); + +VOID +mqmParseEdcaParameters ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN PUINT_8 pucIE, + IN UINT_16 u2IELength, + IN BOOLEAN fgForceOverride + ); + +VOID +mqmFillAcQueParam( + IN P_IE_WMM_PARAM_T prIeWmmParam, + IN UINT_32 u4AcOffset, + OUT P_AC_QUE_PARMS_T prAcQueParams + ); + +VOID +mqmProcessScanResult( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prScanResult, + OUT P_STA_RECORD_T prStaRec + ); + + +/* Utility function: for deciding STA-REC index */ +UINT_8 +qmGetStaRecIdx( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucEthDestAddr, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType + ); + +VOID +mqmGenerateWmmInfoIE ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + +VOID +mqmGenerateWmmParamIE ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + + +ENUM_FRAME_ACTION_T +qmGetFrameAction( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType, + IN UINT_8 ucStaRecIdx, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_FRAME_TYPE_IN_CMD_Q_T eFrameType +); + +VOID +qmHandleEventBssAbsencePresence( + IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent + ); + +VOID +qmHandleEventStaChangePsMode( + IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent + ); + +VOID +mqmProcessAssocReq ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN PUINT_8 pucIE, + IN UINT_16 u2IELength + ); + +VOID +qmHandleEventStaUpdateFreeQuota( + IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent + ); + + +VOID +qmUpdateFreeQuota( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN UINT_8 ucUpdateMode, + IN UINT_8 ucFreeQuota + ); + +VOID +qmFreeAllByNetType( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx + ); + +UINT_32 +qmGetRxReorderQueuedBufferCount( + IN P_ADAPTER_T prAdapter + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _QUE_MGT_H */ diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/wlan_def.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/wlan_def.h new file mode 100755 index 000000000000..9ddf0e94b187 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic/wlan_def.h @@ -0,0 +1,1056 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/nic/wlan_def.h#1 $ +*/ + +/*! \file "wlan_def.h" + \brief This file includes the basic definition of WLAN + +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: wlan_def.h $ + * + * 12 06 2011 cp.wu + * [WCXRP00001131] [MT6620 Wi-Fi][Driver][AIS] Implement connect-by-BSSID path + * sync. for connect-by-bssid control path implementations. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 06 22 2011 wh.su + * [WCXRP00000806] [MT6620 Wi-Fi][Driver] Move the WPA/RSN IE and WAPI IE structure to mac.h and let the sw structure not align at byte + * Move the WAPI / WPA/ RSN IE structure to mac.h and some SW structure not align at byte. + * + * 04 07 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix for sigma. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 17 2011 yuche.tsai + * NULL + * Resize the Secondary Device Type array when WiFi Direct is enabled. + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Add new station type MACRO. + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 10 11 2010 kevin.huang + * [WCXRP00000068] [MT6620 Wi-Fi][Driver][FW] Fix STA RECORD sync issue and remove unused code + * Update ENUM_STA_ROLE_INDEX_T by using a fixed base value + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by ENUM_NETWORK_TYPE_INDEX_T only + * remove ENUM_NETWORK_TYPE_T definitions + * + * 09 14 2010 chinghwa.yu + * NULL + * Update OP_MODE_BOW and include bow_fsm.h. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 31 2010 kevin.huang + * NULL + * Use LINK LIST operation to process SCAN result + * + * 08 29 2010 yuche.tsai + * NULL + * Change P2P Descriptor List to a pointer and allocate it dynamically to avoid structure corrupt by BssDescriptor free. + * + * 08 16 2010 kevin.huang + * NULL + * Refine AAA functions + * + * 08 12 2010 kevin.huang + * NULL + * Refine bssProcessProbeRequest() and bssSendBeaconProbeResponse() + * + * 08 12 2010 yuche.tsai + * NULL + * Add a pointer in BSS Descriptor for P2P Descriptor. + * + * 08 11 2010 yuche.tsai + * NULL + * Add an Interface in BSS Descriptor. + * + * 08 05 2010 yuche.tsai + * NULL + * Modify data structure for P2P Scan result. + * + * 07 26 2010 yuche.tsai + * + * Add an operation mode for P2P device. + * + * 07 23 2010 cp.wu + * + * P2P/RSN/WAPI IEs need to be declared with compact structure. + * + * 07 21 2010 yuche.tsai + * + * Add for P2P Scan Result Parsing & Saving. + * + * 07 20 2010 wh.su + * + * adding the wapi code. + * + * 07 09 2010 cp.wu + * + * 1) separate AIS_FSM state for two kinds of scanning. (OID triggered scan, and scan-for-connection) + * 2) eliminate PRE_BSS_DESC_T, Beacon/PrebResp is now parsed in single pass + * 3) implment DRV-SCN module, currently only accepts single scan request, other request will be directly dropped by returning BUSY + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 28 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * 1st draft code for RLM module + * + * 06 25 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * modify Beacon/ProbeResp to complete parsing, + * because host software has looser memory usage restriction + * + * 06 21 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Add P2P present boolean flag in BSS & Pre-BSS descriptor. + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration the security related function from firmware. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * auth.c is migrated. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add buildable & linkable ais_fsm.c + * + * related reference are still waiting to be resolved + * + * 06 09 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add definitions for module migration. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * move bss related data types to wlan_def.h to avoid recursive dependency. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge wlan_def.h. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge cnm_scan.h and hem_mbox.h + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge wifi_var.h, precomp.h, cnm_timer.h (data type only) + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:40 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _WLAN_DEF_H +#define _WLAN_DEF_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* disconnect reason */ +#define DISCONNECT_REASON_CODE_RESERVED 0 +#define DISCONNECT_REASON_CODE_RADIO_LOST 1 +#define DISCONNECT_REASON_CODE_DEAUTHENTICATED 2 +#define DISCONNECT_REASON_CODE_DISASSOCIATED 3 +#define DISCONNECT_REASON_CODE_NEW_CONNECTION 4 + +/* The rate definitions */ +#define TX_MODE_CCK 0x00 +#define TX_MODE_OFDM 0x40 +#define TX_MODE_HT_MM 0x80 +#define TX_MODE_HT_GF 0xC0 + +#define RATE_CCK_SHORT_PREAMBLE 0x10 +#define RATE_OFDM 0x20 + +#define PHY_RATE_1M 0x0 +#define PHY_RATE_2M 0x1 +#define PHY_RATE_5_5M 0x2 +#define PHY_RATE_11M 0x3 +#define PHY_RATE_6M 0xB +#define PHY_RATE_9M 0xF +#define PHY_RATE_12M 0xA +#define PHY_RATE_18M 0xE +#define PHY_RATE_24M 0x9 +#define PHY_RATE_36M 0xD +#define PHY_RATE_48M 0x8 +#define PHY_RATE_54M 0xC +#define PHY_RATE_MCS0 0x0 +#define PHY_RATE_MCS1 0x1 +#define PHY_RATE_MCS2 0x2 +#define PHY_RATE_MCS3 0x3 +#define PHY_RATE_MCS4 0x4 +#define PHY_RATE_MCS5 0x5 +#define PHY_RATE_MCS6 0x6 +#define PHY_RATE_MCS7 0x7 +#define PHY_RATE_MCS32 0x20 + +#define RATE_CCK_1M_LONG (TX_MODE_CCK | PHY_RATE_1M) +#define RATE_CCK_2M_LONG (TX_MODE_CCK | PHY_RATE_2M) +#define RATE_CCK_5_5M_LONG (TX_MODE_CCK | PHY_RATE_5_5M) +#define RATE_CCK_11M_LONG (TX_MODE_CCK | PHY_RATE_11M) +#define RATE_CCK_2M_SHORT (TX_MODE_CCK | PHY_RATE_2M | RATE_CCK_SHORT_PREAMBLE) +#define RATE_CCK_5_5M_SHORT (TX_MODE_CCK | PHY_RATE_5_5M | RATE_CCK_SHORT_PREAMBLE) +#define RATE_CCK_11M_SHORT (TX_MODE_CCK | PHY_RATE_11M | RATE_CCK_SHORT_PREAMBLE) +#define RATE_OFDM_6M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_6M) +#define RATE_OFDM_9M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_9M) +#define RATE_OFDM_12M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_12M) +#define RATE_OFDM_18M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_18M) +#define RATE_OFDM_24M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_24M) +#define RATE_OFDM_36M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_36M) +#define RATE_OFDM_48M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_48M) +#define RATE_OFDM_54M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_54M) + +#define RATE_MM_MCS_0 (TX_MODE_HT_MM | PHY_RATE_MCS0) +#define RATE_MM_MCS_1 (TX_MODE_HT_MM | PHY_RATE_MCS1) +#define RATE_MM_MCS_2 (TX_MODE_HT_MM | PHY_RATE_MCS2) +#define RATE_MM_MCS_3 (TX_MODE_HT_MM | PHY_RATE_MCS3) +#define RATE_MM_MCS_4 (TX_MODE_HT_MM | PHY_RATE_MCS4) +#define RATE_MM_MCS_5 (TX_MODE_HT_MM | PHY_RATE_MCS5) +#define RATE_MM_MCS_6 (TX_MODE_HT_MM | PHY_RATE_MCS6) +#define RATE_MM_MCS_7 (TX_MODE_HT_MM | PHY_RATE_MCS7) +#define RATE_MM_MCS_32 (TX_MODE_HT_MM | PHY_RATE_MCS32) + +#define RATE_GF_MCS_0 (TX_MODE_HT_GF | PHY_RATE_MCS0) +#define RATE_GF_MCS_1 (TX_MODE_HT_GF | PHY_RATE_MCS1) +#define RATE_GF_MCS_2 (TX_MODE_HT_GF | PHY_RATE_MCS2) +#define RATE_GF_MCS_3 (TX_MODE_HT_GF | PHY_RATE_MCS3) +#define RATE_GF_MCS_4 (TX_MODE_HT_GF | PHY_RATE_MCS4) +#define RATE_GF_MCS_5 (TX_MODE_HT_GF | PHY_RATE_MCS5) +#define RATE_GF_MCS_6 (TX_MODE_HT_GF | PHY_RATE_MCS6) +#define RATE_GF_MCS_7 (TX_MODE_HT_GF | PHY_RATE_MCS7) +#define RATE_GF_MCS_32 (TX_MODE_HT_GF | PHY_RATE_MCS32) + +#define RATE_TX_MODE_MASK BITS(6,7) +#define RATE_TX_MODE_OFFSET 6 +#define RATE_CODE_GET_TX_MODE(_ucRateCode) ((_ucRateCode & RATE_TX_MODE_MASK) >> RATE_TX_MODE_OFFSET) +#define RATE_PHY_RATE_MASK BITS(0,5) +#define RATE_PHY_RATE_OFFSET 0 +#define RATE_CODE_GET_PHY_RATE(_ucRateCode) ((_ucRateCode & RATE_PHY_RATE_MASK) >> RATE_PHY_RATE_OFFSET) +#define RATE_PHY_RATE_SHORT_PREAMBLE BIT(4) +#define RATE_CODE_IS_SHORT_PREAMBLE(_ucRateCode) ((_ucRateCode & RATE_PHY_RATE_SHORT_PREAMBLE)?TRUE:FALSE) + + +#define CHNL_LIST_SZ_2G 14 +#define CHNL_LIST_SZ_5G 14 + +/*! CNM(STA_RECORD_T) related definition */ +#define CFG_STA_REC_NUM 20 + +/* PHY TYPE bit definitions */ +#define PHY_TYPE_BIT_HR_DSSS BIT(PHY_TYPE_HR_DSSS_INDEX) /* HR/DSSS PHY (clause 18) */ +#define PHY_TYPE_BIT_ERP BIT(PHY_TYPE_ERP_INDEX) /* ERP PHY (clause 19) */ +#define PHY_TYPE_BIT_OFDM BIT(PHY_TYPE_OFDM_INDEX) /* OFDM 5 GHz PHY (clause 17) */ +#define PHY_TYPE_BIT_HT BIT(PHY_TYPE_HT_INDEX) /* HT PHY (clause 20) */ + + +/* PHY TYPE set definitions */ +#define PHY_TYPE_SET_802_11ABGN (PHY_TYPE_BIT_OFDM | \ + PHY_TYPE_BIT_HR_DSSS | \ + PHY_TYPE_BIT_ERP | \ + PHY_TYPE_BIT_HT) + +#define PHY_TYPE_SET_802_11BGN (PHY_TYPE_BIT_HR_DSSS | \ + PHY_TYPE_BIT_ERP | \ + PHY_TYPE_BIT_HT) + +#define PHY_TYPE_SET_802_11GN (PHY_TYPE_BIT_ERP | \ + PHY_TYPE_BIT_HT) + +#define PHY_TYPE_SET_802_11AN (PHY_TYPE_BIT_OFDM | \ + PHY_TYPE_BIT_HT) + +#define PHY_TYPE_SET_802_11ABG (PHY_TYPE_BIT_OFDM | \ + PHY_TYPE_BIT_HR_DSSS | \ + PHY_TYPE_BIT_ERP) + +#define PHY_TYPE_SET_802_11BG (PHY_TYPE_BIT_HR_DSSS | \ + PHY_TYPE_BIT_ERP) + +#define PHY_TYPE_SET_802_11A (PHY_TYPE_BIT_OFDM) + +#define PHY_TYPE_SET_802_11G (PHY_TYPE_BIT_ERP) + +#define PHY_TYPE_SET_802_11B (PHY_TYPE_BIT_HR_DSSS) + +#define PHY_TYPE_SET_802_11N (PHY_TYPE_BIT_HT) + + +/* Rate set bit definitions */ +#define RATE_SET_BIT_1M BIT(RATE_1M_INDEX) /* Bit 0: 1M */ +#define RATE_SET_BIT_2M BIT(RATE_2M_INDEX) /* Bit 1: 2M */ +#define RATE_SET_BIT_5_5M BIT(RATE_5_5M_INDEX) /* Bit 2: 5.5M */ +#define RATE_SET_BIT_11M BIT(RATE_11M_INDEX) /* Bit 3: 11M */ +#define RATE_SET_BIT_22M BIT(RATE_22M_INDEX) /* Bit 4: 22M */ +#define RATE_SET_BIT_33M BIT(RATE_33M_INDEX) /* Bit 5: 33M */ +#define RATE_SET_BIT_6M BIT(RATE_6M_INDEX) /* Bit 6: 6M */ +#define RATE_SET_BIT_9M BIT(RATE_9M_INDEX) /* Bit 7: 9M */ +#define RATE_SET_BIT_12M BIT(RATE_12M_INDEX) /* Bit 8: 12M */ +#define RATE_SET_BIT_18M BIT(RATE_18M_INDEX) /* Bit 9: 18M */ +#define RATE_SET_BIT_24M BIT(RATE_24M_INDEX) /* Bit 10: 24M */ +#define RATE_SET_BIT_36M BIT(RATE_36M_INDEX) /* Bit 11: 36M */ +#define RATE_SET_BIT_48M BIT(RATE_48M_INDEX) /* Bit 12: 48M */ +#define RATE_SET_BIT_54M BIT(RATE_54M_INDEX) /* Bit 13: 54M */ +#define RATE_SET_BIT_HT_PHY BIT(RATE_HT_PHY_INDEX) /* Bit 14: BSS Selector */ + + +/* Rate set definitions */ +#define RATE_SET_HR_DSSS (RATE_SET_BIT_1M | \ + RATE_SET_BIT_2M | \ + RATE_SET_BIT_5_5M | \ + RATE_SET_BIT_11M) + +#define RATE_SET_ERP (RATE_SET_BIT_1M | \ + RATE_SET_BIT_2M | \ + RATE_SET_BIT_5_5M | \ + RATE_SET_BIT_11M | \ + RATE_SET_BIT_6M | \ + RATE_SET_BIT_9M | \ + RATE_SET_BIT_12M | \ + RATE_SET_BIT_18M | \ + RATE_SET_BIT_24M | \ + RATE_SET_BIT_36M | \ + RATE_SET_BIT_48M | \ + RATE_SET_BIT_54M) + +#define RATE_SET_ERP_P2P (RATE_SET_BIT_6M | \ + RATE_SET_BIT_9M | \ + RATE_SET_BIT_12M | \ + RATE_SET_BIT_18M | \ + RATE_SET_BIT_24M | \ + RATE_SET_BIT_36M | \ + RATE_SET_BIT_48M | \ + RATE_SET_BIT_54M) + +#define RATE_SET_OFDM (RATE_SET_BIT_6M | \ + RATE_SET_BIT_9M | \ + RATE_SET_BIT_12M | \ + RATE_SET_BIT_18M | \ + RATE_SET_BIT_24M | \ + RATE_SET_BIT_36M | \ + RATE_SET_BIT_48M | \ + RATE_SET_BIT_54M) + +#define RATE_SET_HT (RATE_SET_ERP) +//#define RATE_SET_HT (RATE_SET_ERP | RATE_SET_BIT_HT_PHY) /* NOTE(Kevin): TBD */ + + +#define RATE_SET_ALL_ABG RATE_SET_ERP + +#define BASIC_RATE_SET_HR_DSSS (RATE_SET_BIT_1M | \ + RATE_SET_BIT_2M) + +#define BASIC_RATE_SET_HR_DSSS_ERP (RATE_SET_BIT_1M | \ + RATE_SET_BIT_2M | \ + RATE_SET_BIT_5_5M | \ + RATE_SET_BIT_11M) + +#define BASIC_RATE_SET_ERP (RATE_SET_BIT_1M | \ + RATE_SET_BIT_2M | \ + RATE_SET_BIT_5_5M | \ + RATE_SET_BIT_11M | \ + RATE_SET_BIT_6M | \ + RATE_SET_BIT_12M | \ + RATE_SET_BIT_24M) + +#define BASIC_RATE_SET_OFDM (RATE_SET_BIT_6M | \ + RATE_SET_BIT_12M | \ + RATE_SET_BIT_24M) + +#define BASIC_RATE_SET_ERP_P2P (RATE_SET_BIT_6M | \ + RATE_SET_BIT_12M | \ + RATE_SET_BIT_24M) + +#define INITIAL_RATE_SET_RCPI_100 RATE_SET_ALL_ABG + +#define INITIAL_RATE_SET_RCPI_80 (RATE_SET_BIT_1M | \ + RATE_SET_BIT_2M | \ + RATE_SET_BIT_5_5M | \ + RATE_SET_BIT_11M | \ + RATE_SET_BIT_6M | \ + RATE_SET_BIT_9M | \ + RATE_SET_BIT_12M | \ + RATE_SET_BIT_24M) + +#define INITIAL_RATE_SET_RCPI_60 (RATE_SET_BIT_1M | \ + RATE_SET_BIT_2M | \ + RATE_SET_BIT_5_5M | \ + RATE_SET_BIT_11M | \ + RATE_SET_BIT_6M) + +#define INITIAL_RATE_SET(_rcpi) (INITIAL_RATE_SET_ ## _rcpi) + +#define RCPI_100 100 /* -60 dBm */ +#define RCPI_80 80 /* -70 dBm */ +#define RCPI_60 60 /* -80 dBm */ + + +/* The number of RCPI records used to calculate their average value */ +#define MAX_NUM_RCPI_RECORDS 10 + +/* The number of RCPI records used to calculate their average value */ +#define NO_RCPI_RECORDS -128 +#define MAX_RCPI_DBM 0 +#define MIN_RCPI_DBM -100 + + +#define MAC_TX_RESERVED_FIELD 0 /* NOTE(Kevin): Should defined in tx.h */ + +#define MAX_ASSOC_ID (CFG_STA_REC_NUM) /* Available AID: 1 ~ 20(STA_REC_NUM) */ + + +#define MAX_DEAUTH_INFO_COUNT 4 /* NOTE(Kevin): Used in auth.c */ +#define MIN_DEAUTH_INTERVAL_MSEC 500 /* The minimum interval if continuously send Deauth Frame */ + +/* Authentication Type */ +#define AUTH_TYPE_OPEN_SYSTEM BIT(AUTH_ALGORITHM_NUM_OPEN_SYSTEM) +#define AUTH_TYPE_SHARED_KEY BIT(AUTH_ALGORITHM_NUM_SHARED_KEY) +#define AUTH_TYPE_FAST_BSS_TRANSITION BIT(AUTH_ALGORITHM_NUM_FAST_BSS_TRANSITION) + +/* Authentication Retry Limit */ +#define TX_AUTH_ASSOCI_RETRY_LIMIT 2 +#define TX_AUTH_ASSOCI_RETRY_LIMIT_FOR_ROAMING 1 + +/* WMM-2.2.1 WMM Information Element */ +#define ELEM_MAX_LEN_WMM_INFO 7 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef UINT_16 PHY_TYPE, *P_PHY_TYPE; +typedef UINT_8 RCPI, *P_RCPI; +typedef UINT_8 ALC_VAL, *P_ALC_VAL; + +typedef enum _ENUM_HW_BSSID_T { + BSSID_0 = 0, + BSSID_1, + BSSID_NUM +} ENUM_HW_BSSID_T; + +typedef enum _ENUM_HW_MAC_ADDR_T { + MAC_ADDR_0 = 0, + MAC_ADDR_1, + MAC_ADDR_NUM +} ENUM_HW_MAC_ADDR_T; + +typedef enum _ENUM_HW_OP_MODE_T { + HW_OP_MODE_STA = 0, + HW_OP_MODE_AP, + HW_OP_MODE_ADHOC, + HW_OP_MODE_NUM +} ENUM_HW_OP_MODE_T; + +typedef enum _ENUM_TSF_T { + ENUM_LOCAL_TSF_0, + ENUM_LOCAL_TSF_1, + ENUM_LOCAL_TSF_NUM +} ENUM_LOCAL_TSF_T, *P_ENUM_LOCAL_TSF_T; + +typedef enum _HAL_TS_HW_UPDATE_MODE { + HAL_TSF_HW_UPDATE_BY_TICK_AND_RECEIVED_FRAME, + HAL_TSF_HW_UPDATE_BY_TICK_ONLY, + HAL_TSF_HW_UPDATE_BY_RECEIVED_FRAME_ONLY, + HAL_TSF_HW_UPDATE_BY_TICK_AND_RECEIVED_FRAME_AD_HOC +} HAL_TSF_HW_UPDATE_MODE; + + +typedef enum _ENUM_AC_T { + AC0 = 0, + AC1, + AC2, + AC3, + AC_NUM +} ENUM_AC_T, *P_ENUM_AC_T; + + +/* The Type of Network been activated */ +typedef enum _ENUM_NETWORK_TYPE_INDEX_T { + NETWORK_TYPE_AIS_INDEX = 0, + NETWORK_TYPE_P2P_INDEX, + NETWORK_TYPE_BOW_INDEX, + NETWORK_TYPE_INDEX_NUM +} ENUM_NETWORK_TYPE_INDEX_T; + + +/* The Type of STA Type. */ +typedef enum _ENUM_STA_TYPE_INDEX_T { + STA_TYPE_LEGACY_INDEX = 0, + STA_TYPE_P2P_INDEX, + STA_TYPE_BOW_INDEX, + STA_TYPE_INDEX_NUM +} +ENUM_STA_TYPE_INDEX_T; + +#define STA_ROLE_BASE_INDEX 4 + +typedef enum _ENUM_STA_ROLE_INDEX_T { + STA_ROLE_ADHOC_INDEX = STA_ROLE_BASE_INDEX, //4 + STA_ROLE_CLIENT_INDEX, + STA_ROLE_AP_INDEX, + STA_ROLE_DLS_INDEX +} ENUM_STA_ROLE_INDEX_T; + +/* The Power State of a specific Network */ +typedef enum _ENUM_PWR_STATE_T { + PWR_STATE_IDLE = 0, + PWR_STATE_ACTIVE, + PWR_STATE_PS, + PWR_STATE_NUM +} ENUM_PWR_STATE_T; + +typedef enum _ENUM_PHY_TYPE_INDEX_T { + //PHY_TYPE_DSSS_INDEX, /* DSSS PHY (clause 15) -- Not used anymore */ + PHY_TYPE_HR_DSSS_INDEX = 0, /* HR/DSSS PHY (clause 18) */ + PHY_TYPE_ERP_INDEX, /* ERP PHY (clause 19) */ + PHY_TYPE_ERP_P2P_INDEX, /* ERP PHY (clause 19) w/o HR/DSSS */ + PHY_TYPE_OFDM_INDEX, /* OFDM 5 GHz PHY (clause 17) */ + PHY_TYPE_HT_INDEX, /* HT PHY (clause 20) */ + PHY_TYPE_INDEX_NUM // 5 +} ENUM_PHY_TYPE_INDEX_T, *P_ENUM_PHY_TYPE_INDEX_T; + +typedef enum _ENUM_ACPI_STATE_T { + ACPI_STATE_D0 = 0, + ACPI_STATE_D1, + ACPI_STATE_D2, + ACPI_STATE_D3 +} ENUM_ACPI_STATE_T; + +/* The operation mode of a specific Network */ +typedef enum _ENUM_OP_MODE_T { + OP_MODE_INFRASTRUCTURE = 0, /* Infrastructure/GC */ + OP_MODE_IBSS, /* AdHoc */ + OP_MODE_ACCESS_POINT, /* For GO */ + OP_MODE_P2P_DEVICE, /* P2P Device */ + OP_MODE_BOW, + OP_MODE_NUM +} ENUM_OP_MODE_T, *P_ENUM_OP_MODE_T; + +typedef enum _ENUM_CHNL_EXT_T { + CHNL_EXT_SCN = 0, + CHNL_EXT_SCA = 1, + CHNL_EXT_RES = 2, + CHNL_EXT_SCB = 3 +} ENUM_CHNL_EXT_T, *P_ENUM_CHNL_EXT_T; + +/* This starting freq of the band is unit of kHz */ +typedef enum _ENUM_BAND_T { + BAND_NULL, + BAND_2G4, + BAND_5G, + BAND_NUM +} ENUM_BAND_T, *P_ENUM_BAND_T; + +/* Provide supported channel list to other components in array format */ +typedef struct _RF_CHANNEL_INFO_T { + ENUM_BAND_T eBand; + UINT_8 ucChannelNum; +} RF_CHANNEL_INFO_T, *P_RF_CHANNEL_INFO_T; + +typedef enum _ENUM_RATE_INDEX_T { + RATE_1M_INDEX = 0, /* 1M */ + RATE_2M_INDEX, /* 2M */ + RATE_5_5M_INDEX, /* 5.5M */ + RATE_11M_INDEX, /* 11M */ + RATE_22M_INDEX, /* 22M */ + RATE_33M_INDEX, /* 33M */ + RATE_6M_INDEX, /* 6M */ + RATE_9M_INDEX, /* 9M */ + RATE_12M_INDEX, /* 12M */ + RATE_18M_INDEX, /* 18M */ + RATE_24M_INDEX, /* 24M */ + RATE_36M_INDEX, /* 36M */ + RATE_48M_INDEX, /* 48M */ + RATE_54M_INDEX, /* 54M */ + RATE_HT_PHY_INDEX, /* BSS Selector - HT PHY */ + RATE_NUM // 15 +} ENUM_RATE_INDEX_T, *P_ENUM_RATE_INDEX_T; + +typedef enum _ENUM_HT_RATE_INDEX_T { + HT_RATE_MCS0_INDEX = 0, + HT_RATE_MCS1_INDEX, + HT_RATE_MCS2_INDEX, + HT_RATE_MCS3_INDEX, + HT_RATE_MCS4_INDEX, + HT_RATE_MCS5_INDEX, + HT_RATE_MCS6_INDEX, + HT_RATE_MCS7_INDEX, + HT_RATE_MCS32_INDEX, + HT_RATE_NUM // 9 +} ENUM_HT_RATE_INDEX_T, *P_ENUM_HT_RATE_INDEX_T; + +typedef enum _ENUM_PREMABLE_OPTION_T { + PREAMBLE_DEFAULT_LONG_NONE = 0, /* LONG for PHY_TYPE_HR_DSSS, NONE for PHY_TYPE_OFDM */ + PREAMBLE_OPTION_SHORT, /* SHORT mandatory for PHY_TYPE_ERP, SHORT option for PHY_TYPE_HR_DSSS */ + PREAMBLE_HT_MIXED_MODE, + PREAMBLE_HT_GREEN_FIELD, + PREAMBLE_OPTION_NUM +} ENUM_PREMABLE_OPTION_T, *P_ENUM_PREMABLE_OPTION_T; + +typedef enum _ENUM_MODULATION_SYSTEM_T { + MODULATION_SYSTEM_CCK = 0, + MODULATION_SYSTEM_OFDM, + MODULATION_SYSTEM_HT20, + MODULATION_SYSTEM_HT40, + MODULATION_SYSTEM_NUM +} ENUM_MODULATION_SYSTEM_T, *P_ENUM_MODULATION_SYSTEM_T; + +typedef enum _ENUM_MODULATION_TYPE_T { + MODULATION_TYPE_CCK_BPSK = 0, + MODULATION_TYPE_QPSK, + MODULATION_TYPE_16QAM, + MODULATION_TYPE_64QAM, + MODULATION_TYPE_NUM +} ENUM_MODULATION_TYPE_T, *P_ENUM_MODULATION_TYPE_T; + +typedef enum _ENUM_PS_FORWARDING_TYPE_T { + PS_FORWARDING_TYPE_NON_PS = 0, + PS_FORWARDING_TYPE_DELIVERY_ENABLED, + PS_FORWARDING_TYPE_NON_DELIVERY_ENABLED, + PS_FORWARDING_MORE_DATA_ENABLED, + PS_FORWARDING_TYPE_NUM +} ENUM_PS_FORWARDING_TYPE_T, *P_ENUM_PS_FORWARDING_TYPE_T; + +typedef struct _DEAUTH_INFO_T { + UINT_8 aucRxAddr[MAC_ADDR_LEN]; + OS_SYSTIME rLastSendTime; +} DEAUTH_INFO_T, *P_DEAUTH_INFO_T; + +/*----------------------------------------------------------------------------*/ +/* Information Element (IE) handlers */ +/*----------------------------------------------------------------------------*/ +typedef VOID (*PFN_APPEND_IE_FUNC)(P_ADAPTER_T, P_MSDU_INFO_T); +typedef VOID (*PFN_HANDLE_IE_FUNC)(P_ADAPTER_T, P_SW_RFB_T, P_IE_HDR_T); +typedef VOID (*PFN_VERIFY_IE_FUNC)(P_ADAPTER_T, P_SW_RFB_T, P_IE_HDR_T, PUINT_16); +typedef UINT_32 (*PFN_CALCULATE_VAR_IE_LEN_FUNC)(P_ADAPTER_T, ENUM_NETWORK_TYPE_INDEX_T, P_STA_RECORD_T); + +typedef struct _APPEND_IE_ENTRY_T { + UINT_16 u2EstimatedIELen; + PFN_APPEND_IE_FUNC pfnAppendIE; +} APPEND_IE_ENTRY_T, *P_APPEND_IE_ENTRY_T; + +typedef struct _APPEND_VAR_IE_ENTRY_T { + UINT_16 u2EstimatedFixedIELen; /* For Fixed Length */ + PFN_CALCULATE_VAR_IE_LEN_FUNC pfnCalculateVariableIELen; + PFN_APPEND_IE_FUNC pfnAppendIE; +} APPEND_VAR_IE_ENTRY_T, *P_APPEND_VAR_IE_ENTRY_T; + +typedef struct _HANDLE_IE_ENTRY_T { + UINT_8 ucElemID; + PFN_HANDLE_IE_FUNC pfnHandleIE; +} HANDLE_IE_ENTRY_T, *P_HANDLE_IE_ENTRY_T; + +typedef struct _VERIFY_IE_ENTRY_T { + UINT_8 ucElemID; + PFN_VERIFY_IE_FUNC pfnVarifyIE; +} VERIFY_IE_ENTRY_T, *P_VERIFY_IE_ENTRY_T; + +/*----------------------------------------------------------------------------*/ +/* Parameters of User Configuration */ +/*----------------------------------------------------------------------------*/ +typedef enum _ENUM_PARAM_CONNECTION_POLICY_T { + CONNECT_BY_SSID_BEST_RSSI = 0, + CONNECT_BY_SSID_GOOD_RSSI_MIN_CH_LOAD, + CONNECT_BY_SSID_ANY, /* NOTE(Kevin): Needed by WHQL */ + CONNECT_BY_BSSID, + CONNECT_BY_CUSTOMIZED_RULE /* NOTE(Kevin): TBD */ +} ENUM_PARAM_CONNECTION_POLICY_T, *P_ENUM_PARAM_CONNECTION_POLICY_T; + +typedef enum _ENUM_PARAM_PREAMBLE_TYPE_T { + PREAMBLE_TYPE_LONG = 0, + PREAMBLE_TYPE_SHORT, + PREAMBLE_TYPE_AUTO /*!< Try preamble short first, if fail tray preamble long. */ +} ENUM_PARAM_PREAMBLE_TYPE_T, *P_ENUM_PARAM_PREAMBLE_TYPE_T; + +/* This is enum defined for user to select a phy config listed in combo box */ +typedef enum _ENUM_PARAM_PHY_CONFIG_T { + PHY_CONFIG_802_11ABG = 0, /*!< Can associated with 802.11abg AP but without n capability, Scan dual band. */ + PHY_CONFIG_802_11BG, /*!< Can associated with 802_11bg AP, Scan single band and not report 5G BSSs. */ + PHY_CONFIG_802_11G, /*!< Can associated with 802_11g only AP, Scan single band and not report 5G BSSs. */ + PHY_CONFIG_802_11A, /*!< Can associated with 802_11a only AP, Scan single band and not report 2.4G BSSs. */ + PHY_CONFIG_802_11B, /*!< Can associated with 802_11b only AP, Scan single band and not report 5G BSSs. */ + PHY_CONFIG_802_11ABGN, /*!< Can associated with 802.11abgn AP, Scan dual band. */ + PHY_CONFIG_802_11BGN, /*!< Can associated with 802_11bgn AP, Scan single band and not report 5G BSSs. */ + PHY_CONFIG_802_11AN, /*!< Can associated with 802_11an AP, Scan single band and not report 2.4G BSSs. */ + PHY_CONFIG_802_11GN, /*!< Can associated with 802_11gn AP, Scan single band and not report 5G BSSs. */ + PHY_CONFIG_NUM // 9 +} ENUM_PARAM_PHY_CONFIG_T, *P_ENUM_PARAM_PHY_CONFIG_T; + +/* This is enum defined for user to select an AP Mode */ +typedef enum _ENUM_PARAM_AP_MODE_T { + AP_MODE_11B = 0, /*!< Create 11b BSS if we support 802.11abg/802.11bg. */ + AP_MODE_MIXED_11BG, /*!< Create 11bg mixed BSS if we support 802.11abg/802.11bg/802.11g. */ + AP_MODE_11G, /*!< Create 11g only BSS if we support 802.11abg/802.11bg/802.11g. */ + AP_MODE_11G_P2P, /*!< Create 11g only BSS for P2P if we support 802.11abg/802.11bg/802.11g. */ + AP_MODE_11A, /*!< Create 11a only BSS if we support 802.11abg. */ + AP_MODE_NUM // 4 +} ENUM_PARAM_AP_MODE_T, *P_ENUM_PARAM_AP_MODE_T; + + +/* Masks for determining the Network Type or the Station Role, given the ENUM_STA_TYPE_T */ +#define NETWORK_TYPE_AIS_MASK BIT(NETWORK_TYPE_AIS_INDEX) +#define NETWORK_TYPE_P2P_MASK BIT(NETWORK_TYPE_P2P_INDEX) +#define NETWORK_TYPE_BOW_MASK BIT(NETWORK_TYPE_BOW_INDEX) +#define STA_TYPE_LEGACY_MASK BIT(STA_TYPE_LEGACY_INDEX) +#define STA_TYPE_P2P_MASK BIT(STA_TYPE_P2P_INDEX) +#define STA_TYPE_BOW_MASK BIT(STA_TYPE_BOW_INDEX) +#define STA_TYPE_ADHOC_MASK BIT(STA_ROLE_ADHOC_INDEX) +#define STA_TYPE_CLIENT_MASK BIT(STA_ROLE_CLIENT_INDEX) +#define STA_TYPE_AP_MASK BIT(STA_ROLE_AP_INDEX) +#define STA_TYPE_DLS_MASK BIT(STA_ROLE_DLS_INDEX) + +/* Macros for obtaining the Network Type or the Station Role, given the ENUM_STA_TYPE_T */ +#define IS_STA_IN_AIS(_prStaRec) ((_prStaRec)->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) +#define IS_STA_IN_P2P(_prStaRec) ((_prStaRec)->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) +#define IS_STA_IN_BOW(_prStaRec) ((_prStaRec)->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) +#define IS_STA_LEGACY_TYPE(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_LEGACY_MASK) +#define IS_STA_P2P_TYPE(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_P2P_MASK) +#define IS_STA_BOW_TYPE(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_BOW_MASK) +#define IS_ADHOC_STA(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_ADHOC_MASK) +#define IS_CLIENT_STA(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_CLIENT_MASK) +#define IS_AP_STA(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_AP_MASK) +#define IS_DLS_STA(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_DLS_MASK) + +/* The ENUM_STA_TYPE_T accounts for ENUM_NETWORK_TYPE_T and ENUM_STA_ROLE_INDEX_T. + * * It is a merged version of Network Type and STA Role. + * */ +typedef enum _ENUM_STA_TYPE_T { + STA_TYPE_LEGACY_AP = (STA_TYPE_LEGACY_MASK | STA_TYPE_AP_MASK), + STA_TYPE_LEGACY_CLIENT = (STA_TYPE_LEGACY_MASK | STA_TYPE_CLIENT_MASK), + STA_TYPE_ADHOC_PEER = (STA_TYPE_LEGACY_MASK | STA_TYPE_ADHOC_MASK), +#if CFG_ENABLE_WIFI_DIRECT + STA_TYPE_P2P_GO = (STA_TYPE_P2P_MASK | STA_TYPE_AP_MASK), + STA_TYPE_P2P_GC = (STA_TYPE_P2P_MASK | STA_TYPE_CLIENT_MASK), +#endif +#if CFG_ENABLE_BT_OVER_WIFI + STA_TYPE_BOW_AP = (STA_TYPE_BOW_MASK | STA_TYPE_AP_MASK), + STA_TYPE_BOW_CLIENT = (STA_TYPE_BOW_MASK | STA_TYPE_CLIENT_MASK), +#endif + STA_TYPE_DLS_PEER = (STA_TYPE_LEGACY_MASK | STA_TYPE_DLS_MASK) +} ENUM_STA_TYPE_T, *P_ENUM_STA_TYPE_T; + +/* The type of BSS we discovered */ +typedef enum _ENUM_BSS_TYPE_T { + BSS_TYPE_INFRASTRUCTURE = 1, + BSS_TYPE_IBSS, + BSS_TYPE_P2P_DEVICE, + BSS_TYPE_BOW_DEVICE, + BSS_TYPE_NUM +} ENUM_BSS_TYPE_T, *P_ENUM_BSS_TYPE_T; + +/*----------------------------------------------------------------------------*/ +/* RSN structures */ +/*----------------------------------------------------------------------------*/ +//#if defined(WINDOWS_DDK) || defined(WINDOWS_CE) +//#pragma pack(1) +//#endif + +#define MAX_NUM_SUPPORTED_CIPHER_SUITES 8 /* max number of supported cipher suites */ +#if CFG_SUPPORT_802_11W +#define MAX_NUM_SUPPORTED_AKM_SUITES 8 /* max number of supported AKM suites */ +#else +#define MAX_NUM_SUPPORTED_AKM_SUITES 6 /* max number of supported AKM suites */ +#endif + +/* Structure of RSN Information */ +typedef struct _RSN_INFO_T { + UINT_8 ucElemId; + UINT_16 u2Version; + UINT_32 u4GroupKeyCipherSuite; + UINT_32 u4PairwiseKeyCipherSuiteCount; + UINT_32 au4PairwiseKeyCipherSuite[MAX_NUM_SUPPORTED_CIPHER_SUITES]; + UINT_32 u4AuthKeyMgtSuiteCount; + UINT_32 au4AuthKeyMgtSuite[MAX_NUM_SUPPORTED_AKM_SUITES]; + UINT_16 u2RsnCap; + BOOLEAN fgRsnCapPresent; +} /*__KAL_ATTRIB_PACKED__*/ RSN_INFO_T, *P_RSN_INFO_T; + +#define MAX_NUM_SUPPORTED_WAPI_AKM_SUITES 1 /* max number of supported AKM suites */ +#define MAX_NUM_SUPPORTED_WAPI_CIPHER_SUITES 1 /* max number of supported cipher suites */ + +/* Structure of WAPI Information */ +typedef struct _WAPI_INFO_T { + UINT_8 ucElemId; + UCHAR ucLength; + UINT_16 u2Version; + UINT_32 u4AuthKeyMgtSuiteCount; + UINT_32 au4AuthKeyMgtSuite[MAX_NUM_SUPPORTED_WAPI_AKM_SUITES]; + UINT_32 u4PairwiseKeyCipherSuiteCount; + UINT_32 au4PairwiseKeyCipherSuite[MAX_NUM_SUPPORTED_WAPI_CIPHER_SUITES]; + UINT_32 u4GroupKeyCipherSuite; + UINT_16 u2WapiCap; + UINT_16 u2Bkid; + UINT_8 aucBkid[1][16]; +} /* __KAL_ATTRIB_PACKED__*/ WAPI_INFO_T, *P_WAPI_INFO_T; + +//#if defined(WINDOWS_DDK) || defined(WINDOWS_CE) +//#pragma pack() +//#endif + + +#if CFG_ENABLE_WIFI_DIRECT + +typedef struct _P2P_DEVICE_TYPE_T { + UINT_16 u2CategoryID; + UINT_16 u2SubCategoryID; +} P2P_DEVICE_TYPE_T, *P_P2P_DEVICE_TYPE_T; + +typedef struct _P2P_DEVICE_DESC_T { + LINK_ENTRY_T rLinkEntry; + BOOLEAN fgDevInfoValid; + UINT_8 aucDeviceAddr[MAC_ADDR_LEN]; /* Device Address. */ + UINT_8 aucInterfaceAddr[MAC_ADDR_LEN]; /* Interface Address. */ + UINT_8 ucDeviceCapabilityBitmap; + UINT_8 ucGroupCapabilityBitmap; + UINT_16 u2ConfigMethod; /* Configure Method support. */ + P2P_DEVICE_TYPE_T rPriDevType; + UINT_8 ucSecDevTypeNum; + P2P_DEVICE_TYPE_T arSecDevType[8]; // Reference to P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT + UINT_16 u2NameLength; + UINT_8 aucName[32]; // Reference to WPS_ATTRI_MAX_LEN_DEVICE_NAME + // TODO: Service Information or PasswordID valid? +} P2P_DEVICE_DESC_T, *P_P2P_DEVICE_DESC_T; + +#endif + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +static const UINT_8 aucRateIndex2RateCode[PREAMBLE_OPTION_NUM][RATE_NUM] = { + { /* Long Preamble */ + RATE_CCK_1M_LONG, /* RATE_1M_INDEX = 0 */ + RATE_CCK_2M_LONG, /* RATE_2M_INDEX */ + RATE_CCK_5_5M_LONG, /* RATE_5_5M_INDEX */ + RATE_CCK_11M_LONG, /* RATE_11M_INDEX */ + RATE_CCK_1M_LONG, /* RATE_22M_INDEX - Not supported */ + RATE_CCK_1M_LONG, /* RATE_33M_INDEX - Not supported */ + RATE_OFDM_6M, /* RATE_6M_INDEX */ + RATE_OFDM_9M, /* RATE_9M_INDEX */ + RATE_OFDM_12M, /* RATE_12M_INDEX */ + RATE_OFDM_18M, /* RATE_18M_INDEX */ + RATE_OFDM_24M, /* RATE_24M_INDEX */ + RATE_OFDM_36M, /* RATE_36M_INDEX */ + RATE_OFDM_48M, /* RATE_48M_INDEX */ + RATE_OFDM_54M, /* RATE_54M_INDEX */ + }, + { /* Short Preamble */ + RATE_CCK_1M_LONG, /* RATE_1M_INDEX = 0 */ + RATE_CCK_2M_SHORT, /* RATE_2M_INDEX */ + RATE_CCK_5_5M_SHORT, /* RATE_5_5M_INDEX */ + RATE_CCK_11M_SHORT, /* RATE_11M_INDEX */ + RATE_CCK_1M_LONG, /* RATE_22M_INDEX - Not supported */ + RATE_CCK_1M_LONG, /* RATE_33M_INDEX - Not supported */ + RATE_OFDM_6M, /* RATE_6M_INDEX */ + RATE_OFDM_9M, /* RATE_9M_INDEX */ + RATE_OFDM_12M, /* RATE_12M_INDEX */ + RATE_OFDM_18M, /* RATE_18M_INDEX */ + RATE_OFDM_24M, /* RATE_24M_INDEX */ + RATE_OFDM_36M, /* RATE_36M_INDEX */ + RATE_OFDM_48M, /* RATE_48M_INDEX */ + RATE_OFDM_54M, /* RATE_54M_INDEX */ + }, + { /* Mixed Mode(Option) */ + RATE_MM_MCS_0, /* RATE_MCS0_INDEX, */ + RATE_MM_MCS_1, /* RATE_MCS1_INDEX, */ + RATE_MM_MCS_2, /* RATE_MCS2_INDEX, */ + RATE_MM_MCS_3, /* RATE_MCS3_INDEX, */ + RATE_MM_MCS_4, /* RATE_MCS4_INDEX, */ + RATE_MM_MCS_5, /* RATE_MCS5_INDEX, */ + RATE_MM_MCS_6, /* RATE_MCS6_INDEX, */ + RATE_MM_MCS_7, /* RATE_MCS7_INDEX, */ + RATE_MM_MCS_32 /* RATE_MCS32_INDEX, */ + }, + { /* Green Field(Option) */ + RATE_GF_MCS_0, /* RATE_MCS0_INDEX, */ + RATE_GF_MCS_1, /* RATE_MCS1_INDEX, */ + RATE_GF_MCS_2, /* RATE_MCS2_INDEX, */ + RATE_GF_MCS_3, /* RATE_MCS3_INDEX, */ + RATE_GF_MCS_4, /* RATE_MCS4_INDEX, */ + RATE_GF_MCS_5, /* RATE_MCS5_INDEX, */ + RATE_GF_MCS_6, /* RATE_MCS6_INDEX, */ + RATE_GF_MCS_7, /* RATE_MCS7_INDEX, */ + RATE_GF_MCS_32 /* RATE_MCS32_INDEX, */ + } +}; + +static const UINT_8 aucRateTableSize[PREAMBLE_OPTION_NUM] = { + RATE_HT_PHY_INDEX, + RATE_HT_PHY_INDEX, + HT_RATE_NUM, + HT_RATE_NUM +}; + + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +/* Macros to get and set the wireless LAN frame fields those are 16/32 bits in + length. */ +#define WLAN_GET_FIELD_16(_memAddr_p, _value_p) \ + { \ + PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ + *(PUINT_16)(_value_p) = ((UINT_16) __cp[0]) | ((UINT_16) __cp[1] << 8); \ + } + +#define WLAN_GET_FIELD_BE16(_memAddr_p, _value_p) \ + { \ + PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ + *(PUINT_16)(_value_p) = ((UINT_16) __cp[0] << 8) | ((UINT_16) __cp[1]); \ + } + +#define WLAN_GET_FIELD_32(_memAddr_p, _value_p) \ + { \ + PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ + *(PUINT_32)(_value_p) = ((UINT_32) __cp[0]) | ((UINT_32) __cp[1] << 8) | \ + ((UINT_32) __cp[2] << 16) | ((UINT_32) __cp[3] << 24); \ + } + +#define WLAN_GET_FIELD_64(_memAddr_p, _value_p) \ + { \ + PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ + *(PUINT_64)(_value_p) = \ + ((UINT_64) __cp[0]) | ((UINT_64) __cp[1] << 8) | \ + ((UINT_64) __cp[2] << 16) | ((UINT_64) __cp[3] << 24) | \ + ((UINT_64) __cp[4] << 32) | ((UINT_64) __cp[5] << 40) | \ + ((UINT_64) __cp[6] << 48) | ((UINT_64) __cp[7] << 56); \ + } + +#define WLAN_SET_FIELD_16(_memAddr_p, _value) \ + { \ + PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ + __cp[0] = (UINT_8) (_value); \ + __cp[1] = (UINT_8) ((_value) >> 8); \ + } + +#define WLAN_SET_FIELD_BE16(_memAddr_p, _value) \ + { \ + PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ + __cp[0] = (UINT_8) ((_value) >> 8); \ + __cp[1] = (UINT_8) (_value); \ + } + +#define WLAN_SET_FIELD_32(_memAddr_p, _value) \ + { \ + PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ + __cp[0] = (UINT_8) (_value); \ + __cp[1] = (UINT_8) ((_value) >> 8); \ + __cp[2] = (UINT_8) ((_value) >> 16); \ + __cp[3] = (UINT_8) ((_value) >> 24); \ + } + + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _WLAN_DEF_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic_cmd_event.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic_cmd_event.h new file mode 100755 index 000000000000..27332fd039c3 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic_cmd_event.h @@ -0,0 +1,1824 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/nic_cmd_event.h#1 $ +*/ + +/*! \file "nic_cmd_event.h" + \brief This file contains the declairation file of the WLAN OID processing routines + of Windows driver for MediaTek Inc. 802.11 Wireless LAN Adapters. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: nic_cmd_event.h $ + * + * 01 09 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Check in the Add Tx power Cmd to driver. + * + * 11 19 2011 yuche.tsai + * NULL + * Add P2P RSSI Link Quality Query Support. (Default Off) + * + * 11 10 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Add TX_DONE status detail information. + * + * 11 08 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * check if CFG_SUPPORT_SWCR is defined to avoid compiler error. + * + * 11 04 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters and periodically dump counters for Xlog debugging. + * + * 10 26 2011 cp.wu + * [WCXRP00001065] [MT6620 Wi-Fi][MT5931][FW][DRV] Adding parameter for controlling minimum channel dwell time for scanning + * add interface for control minimum channel dwell time for scanning. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 08 11 2011 cp.wu + * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time + * sparse channel detection: + * driver: collect sparse channel information with scan-done event + * + * 08 09 2011 cp.wu + * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC[WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC + * add CCK-DSSS TX-PWR control field in NVRAM and CMD definition for MT5931-MP + * + * 08 03 2011 terry.wu + * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode + * Reply Probe Rsp in FW for Hotspot Mode. + * + * + * + * 08 03 2011 terry.wu + * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode + * Reply Probe Rsp in FW for Hotspot Mode. + * + * + * 08 03 2011 terry.wu + * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode + * Reply Probe Rsp in FW for Hotspot Mode. + * + * 08 03 2011 terry.wu + * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode + * Reply Probe Rsp in FW for Hotspot Mode. + * + * 06 23 2011 cp.wu + * [WCXRP00000812] [MT6620 Wi-Fi][Driver] not show NVRAM when there is no valid MAC address in NVRAM content + * check with firmware for valid MAC address. + * + * 06 23 2011 cp.wu + * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module + * follow-ups for frequency-shifted WAPI AP support + * + * 06 09 2011 tsaiyuan.hsu + * [WCXRP00000760] [MT5931 Wi-Fi][FW] Refine rxmHandleMacRxDone to reduce code size + * move send_auth at rxmHandleMacRxDone in firmware to driver to reduce code size. + * + * 05 27 2011 cp.wu + * [WCXRP00000749] [MT6620 Wi-Fi][Driver] Add band edge tx power control to Wi-Fi NVRAM + * invoke CMD_ID_SET_EDGE_TXPWR_LIMIT when there is valid data exist in NVRAM content. + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 03 31 2011 chinglan.wang + * [WCXRP00000613] [MT6620 Wi-Fi] [FW] [Driver] BssInfo can get the security mode which is WPA/WPA2/WAPI or not. + * . + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 18 2011 cm.chang + * [WCXRP00000576] [MT6620 Wi-Fi][Driver][FW] Remove P2P compile option in scan req/cancel command + * As CR title + * + * 03 17 2011 yarco.yang + * [WCXRP00000569] [MT6620 Wi-Fi][F/W][Driver] Set multicast address support current network usage + * . + * + * 03 07 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * rename the define to anti_pviracy. + * + * 03 05 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * add the code to get the check rsponse and indicate to app. + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * Add Security check related code. + * + * 03 02 2011 george.huang + * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command + * Support UAPSD/OppPS/NoA parameter setting + * + * 02 16 2011 cm.chang + * [WCXRP00000447] [MT6620 Wi-Fi][FW] Support new NVRAM update mechanism + * . + * + * 02 10 2011 cp.wu + * [WCXRP00000434] [MT6620 Wi-Fi][Driver] Obsolete unused event packet handlers + * EVENT_ID_CONNECTION_STATUS has been obsoleted and no need to handle. + * + * 02 08 2011 eddie.chen + * [WCXRP00000426] [MT6620 Wi-Fi][FW/Driver] Add STA aging timeout and defualtHwRatein AP mode + * Add event STA agint timeout + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 01 25 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Update cmd format of BSS INFO, always sync OwnMac to FW no matter P2P is enabled or not.. + * + * 01 20 2011 eddie.chen + * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control + * Add Oid for sw control debug command + * + * 01 15 2011 puff.wen + * NULL + * Add Stress test + * + * 01 12 2011 cm.chang + * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting + * Sync HT operation element information from host to FW + * + * 01 12 2011 cm.chang + * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting + * User-defined bandwidth is for 2.4G and 5G individually + * + * 12 29 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, + +Add per station flow control when STA is in PS + + + * 1) PS flow control event + * + * 2) WMM IE in beacon, assoc resp, probe resp + * + * 12 28 2010 cp.wu + * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release + * report EEPROM used flag via NIC_CAPABILITY + * + * 12 28 2010 cp.wu + * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release + * integrate with 'EEPROM used' flag for reporting correct capability to Engineer Mode/META and other tools + * + * 12 23 2010 george.huang + * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function + * 1. update WMM IE parsing, with ASSOC REQ handling + * 2. extend U-APSD parameter passing from driver to FW + * + * 12 07 2010 cm.chang + * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk + * 1. BSSINFO include RLM parameter + * 2. free all sta records when network is disconnected + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 11 29 2010 cm.chang + * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC for initial TX rate selection of auto-rate algorithm + * Sync RCPI of STA_REC to FW as reference of initial TX rate + * + * 11 08 2010 cm.chang + * [WCXRP00000169] [MT6620 Wi-Fi][Driver][FW] Remove unused CNM recover message ID + * Remove CNM channel reover message ID + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 10 26 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command + * 1) update NVRAM content template to ver 1.02 + * 2) add compile option for querying NIC capability (default: off) + * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting + * 4) correct auto-rate compiler error under linux (treat warning as error) + * 5) simplify usage of NVRAM and REG_INFO_T + * 6) add version checking between driver and firmware + * + * 10 25 2010 cp.wu + * [WCXRP00000133] [MT6620 Wi-Fi] [FW][Driver] Change TX power offset band definition + * follow-up for CMD_5G_PWR_OFFSET_T definition change + * + * 10 20 2010 cp.wu + * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore + * use OID_CUSTOM_TEST_MODE as indication for driver reset + * by dropping pending TX packets + * + * 10 20 2010 wh.su + * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group + * Add the code to support disconnect p2p group + * + * 09 15 2010 cm.chang + * NULL + * Add new CMD for TX power, 5G power offset and power parameters + * + * 09 07 2010 yuche.tsai + * NULL + * Add a pointer in P2P SCAN RESULT structure. This pointer + * is pointed to a IE buffer for this P2p device. + * + * 09 07 2010 wh.su + * NULL + * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 23 2010 chinghwa.yu + * NULL + * Update for BOW. + * + * 08 20 2010 cm.chang + * NULL + * Migrate RLM code to host from FW + * + * 08 16 2010 george.huang + * NULL + * add new CMD ID definition + * + * 08 16 2010 yuche.tsai + * NULL + * Add a field in BSS INFO cmd to change interface address for P2P. (switching between Device Addr & Interface Addr) + * + * 08 12 2010 yuche.tsai + * NULL + * Add interface address indication when indicate connection status. + * It is requested by supplicant to do 4 way handshake. + * + * 08 07 2010 wh.su + * NULL + * adding the privacy related code for P2P network + * + * 08 05 2010 yuche.tsai + * NULL + * Change data structure for P2P Device scan result, all channel time for scan command. + * + * 08 04 2010 george.huang + * NULL + * handle change PS mode OID/ CMD + * + * 08 04 2010 yarco.yang + * NULL + * Add TX_AMPDU and ADDBA_REJECT command + * + * 08 03 2010 george.huang + * NULL + * handle event for updating NOA parameters indicated from FW + * + * 08 02 2010 george.huang + * NULL + * add WMM-PS test related OID/ CMD handlers + * + * 07 28 2010 cp.wu + * NULL + * sync. CMD_BSS_INFO structure change to CMD-EVENT v0.15. + * + * 07 26 2010 yuche.tsai + * + * Add P2P Device Found Event. + * Channel extention option in scan abort command. + * + * 07 23 2010 cp.wu + * + * add AIS-FSM handling for beacon timeout event. + * + * 07 21 2010 yuche.tsai + * + * Add for P2P Scan Result Parsing & Saving. + * + * 07 20 2010 george.huang + * + * DWORD align for the CMD data structure + * + * 07 20 2010 cp.wu + * + * pass band information for scan in an efficient way by mapping ENUM_BAND_T into UINT_8.. + * + * 07 19 2010 wh.su + * + * update for security supporting. + * + * 07 19 2010 cm.chang + * + * Set RLM parameters and enable CNM channel manager + * + * 07 16 2010 yarco.yang + * + * 1. Support BSS Absence/Presence Event + * 2. Support STA change PS mode Event + * 3. Support BMC forwarding for AP mode. + * + * 07 14 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * pass band with channel number information as scan parameter + * + * 07 14 2010 yarco.yang + * + * 1. Remove CFG_MQM_MIGRATION + * 2. Add CMD_UPDATE_WMM_PARMS command + * + * 07 09 2010 cp.wu + * + * reorder members of CMD_SET_BSS_INFO. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * update prStaRecOfAP with BSS-INFO. + * + * 07 07 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Support state of STA record change from 1 to 1 + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Support sync command of STA_REC + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implementation of DRV-SCN and related mailbox message handling. + * + * 06 30 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * sync. with CMD/EVENT document ver0.07. + * + * 06 29 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * correct variable naming for 8-bit variable used in CMD_BEACON_TEMPLATE_UPDATE. + * + * 06 29 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) sync to. CMD/EVENT document v0.03 + * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. + * 3) send command packet to indicate FW-PM after + * a) 1st beacon is received after AIS has connected to an AP + * b) IBSS-ALONE has been created + * c) IBSS-MERGE has occured + * + * 06 28 2010 george.huang + * [WPD00001556]Basic power managemenet function + * Create beacon update path, with expose bssUpdateBeaconContent() + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add command warpper for STA-REC/BSS-INFO sync. + * 2) enhance command packet sending procedure for non-oid part + * 3) add command packet definitions for STA-REC/BSS-INFO sync. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add BSS/STA_REC commands for integration. + * + * 06 21 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Add TX Done Event handle entry + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 + * 2) when disconnected, indicate nic directly (no event is needed) + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS + * 2) buffer statistics data for 2 seconds + * 3) use default value for adhoc parameters instead of 0 + * + * 05 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) do not take timeout mechanism for power mode oids + * 2) retrieve network type from connection status + * 3) after disassciation, set radio state to off + * 4) TCP option over IPv6 is supported + * + * 05 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct OID_802_11_DISASSOCIATE handling. + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * 1) add timeout handler mechanism for pending command packets + * 2) add p2p add/removal key + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * * * * 3) private data could be hold and taken use for other purpose + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * sync statistics data structure definition with firmware implementation + * + * 03 30 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * statistics information OIDs are now handled by querying from firmware domain + * + * 03 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * indicate media stream mode after set is done + * + * 03 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add a temporary flag for integration with CMD/EVENT v0.9. + * + * 03 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) correct OID_802_11_CONFIGURATION with frequency setting behavior. + * * the frequency is used for adhoc connection only + * * 2) update with SD1 v0.9 CMD/EVENT documentation + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port + * + * 03 22 2010 cp.wu + * [WPD00003824][MT6620 Wi-Fi][New Feature] Add support of large scan list + * Implement feature needed by CR: WPD00003824: refining association command by pasting scanning result + * + * 03 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add ACPI D0/D3 state switching support + * * * * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response + * + * 03 15 2010 kevin.huang + * [WPD00003820][MT6620 Wi-Fi] Modify the code for meet the WHQL test + * Add event for activate STA_RECORD_T + * + * 03 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement custom OID: EEPROM read/write access + * + * 03 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement OID_802_3_MULTICAST_LIST oid handling + * + * 02 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * move EVENT_ID_ASSOC_INFO from nic_rx.c to gl_kal_ndis_51.c + * 'cause it involves OS dependent data structure handling + * + * 02 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * send CMD_ID_INFRASTRUCTURE when handling OID_802_11_INFRASTRUCTURE_MODE set. + * + * 02 09 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address + * * * * * 2. follow MSDN defined behavior when associates to another AP + * * * * * 3. for firmware download, packet size could be up to 2048 bytes + * + * 01 27 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * . + * + * 01 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. eliminate improper variable in rHifInfo + * * * * * * 2. block TX/ordinary OID when RF test mode is engaged + * * * * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode + * * * * * * 4. correct some HAL implementation + * + * 01 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement following 802.11 OIDs: + * * * OID_802_11_RSSI, + * * * OID_802_11_RSSI_TRIGGER, + * * * OID_802_11_STATISTICS, + * * * OID_802_11_DISASSOCIATE, + * * * OID_802_11_POWER_MODE + * + * 01 21 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement OID_802_11_MEDIA_STREAM_MODE + * + * 01 21 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement OID_802_11_SUPPORTED_RATES / OID_802_11_DESIRED_RATES + * + * 12 30 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) According to CMD/EVENT documentation v0.8, + * * * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, + * * * * * * and result is retrieved by get ATInfo instead + * * * * * * 2) add 4 counter for recording aggregation statistics +** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-12-11 18:35:07 GMT mtk02752 +** add CMD added in CMD/EVEN document v0.8 +** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-12-10 16:39:37 GMT mtk02752 +** eliminate unused definitions +** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-12-10 09:55:11 GMT mtk02752 +** command ID/event ID revised +** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-12-09 13:57:37 GMT MTK02468 +** Added event ids (EVENT_ID_RX_ADDBA and EVENT_ID_RX_DELBA) +** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-12-08 17:35:39 GMT mtk02752 +** + add event ID for EVENT_ID_TEST_STATUS (rf test) +** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-12-07 23:01:09 GMT mtk02752 +** add data structure for RF_TEST +** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-12-03 16:22:56 GMT mtk01461 +** Modify the element - i4RSSI in EVENT of SCAN RESULT +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-11-30 10:54:44 GMT mtk02752 +** 1st DW of WIFI_CMD_T is shared with HIF_TX_HEADER_T, while 1st DW of WIFI_EVENT_T is shared with HIF_RX_HEADER_T +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-11-26 10:16:58 GMT mtk02752 +** resync EVENT_CONNECTION_STATUS +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-11-25 21:34:01 GMT mtk02752 +** sync. EVENT_SCAN_RESULT_T with firmware +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-11-25 21:03:48 GMT mtk02752 +** refine MGMT_FRAME +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-11-25 18:17:47 GMT mtk02752 +** refine GL_WLAN_INFO_T for buffering scan result and presume max. ie length = 600 bytes +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-11-24 22:41:20 GMT mtk02752 +** add EVENT_SCAN_RESULT_T definition +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-11-23 20:29:16 GMT mtk02752 +** fix typo +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-11-23 14:46:01 GMT mtk02752 +** add new command/event structure upon CM@SD1's documentation +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-11-13 15:13:40 GMT mtk02752 +** add command definition for CMD_BUILD_CONNECTION and EVENT_CONNECTION_STATUS +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-05-20 12:22:22 GMT mtk01461 +** Add SeqNum field to Event Header +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-04-29 15:42:11 GMT mtk01461 +** Update structure of HIF_EVENT_HEADER_T and EVENT_HDR_SIZE +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-04-21 12:10:36 GMT mtk01461 +** Add Common Set CMD Callback for MCR Write and other Set OID +** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-04-21 01:40:17 GMT mtk01461 +** Command Done Handler +*/ +#ifndef _NIC_CMD_EVENT_H +#define _NIC_CMD_EVENT_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define CMD_STATUS_SUCCESS 0 +#define CMD_STATUS_REJECTED 1 +#define CMD_STATUS_UNKNOWN 2 + +#define EVENT_HDR_SIZE OFFSET_OF(WIFI_EVENT_T, aucBuffer[0]) + +#define MAX_IE_LENGTH (600) +#define MAX_WSC_IE_LENGTH (400) + +/* Action field in structure CMD_CH_PRIVILEGE_T */ +#define CMD_CH_ACTION_REQ 0 +#define CMD_CH_ACTION_ABORT 1 + +/* Status field in structure EVENT_CH_PRIVILEGE_T */ +#define EVENT_CH_STATUS_GRANT 0 + + +typedef enum _ENUM_CMD_ID_T { + CMD_ID_TEST_MODE = 1, /* 0x01 (Set) */ + CMD_ID_RESET_REQUEST, /* 0x02 (Set) */ + CMD_ID_BUILD_CONNECTION, /* 0x03 (Set) */ + CMD_ID_SCAN_REQ_V2, /* 0x04 (Set) */ + CMD_ID_NIC_POWER_CTRL, /* 0x05 (Set) */ + CMD_ID_POWER_SAVE_MODE, /* 0x06 (Set) */ + CMD_ID_LINK_ATTRIB, /* 0x07 (Set) */ + CMD_ID_ADD_REMOVE_KEY, /* 0x08 (Set) */ + CMD_ID_DEFAULT_KEY_ID, /* 0x09 (Set) */ + CMD_ID_INFRASTRUCTURE, /* 0x0a (Set) */ + CMD_ID_SET_RX_FILTER, /* 0x0b (Set) */ + CMD_ID_DOWNLOAD_BUF, /* 0x0c (Set) */ + CMD_ID_WIFI_START, /* 0x0d (Set) */ + CMD_ID_CMD_BT_OVER_WIFI, /* 0x0e (Set) */ + CMD_ID_SET_MEDIA_CHANGE_DELAY_TIME, /* 0x0f (Set) */ + CMD_ID_SEND_ADDBA_RSP, /* 0x10 (Set) */ + CMD_ID_WAPI_MODE, /* 0x11 (Set) (obsolete) */ + CMD_ID_WAPI_ASSOC_INFO, /* 0x12 (Set) (obsolete) */ + CMD_ID_SET_DOMAIN_INFO, /* 0x13 (Set) */ + CMD_ID_SET_IP_ADDRESS, /* 0x14 (Set) */ + CMD_ID_BSS_ACTIVATE_CTRL, /* 0x15 (Set) */ + CMD_ID_SET_BSS_INFO, /* 0x16 (Set) */ + CMD_ID_UPDATE_STA_RECORD, /* 0x17 (Set) */ + CMD_ID_REMOVE_STA_RECORD, /* 0x18 (Set) */ + CMD_ID_INDICATE_PM_BSS_CREATED, /* 0x19 (Set) */ + CMD_ID_INDICATE_PM_BSS_CONNECTED, /* 0x1a (Set) */ + CMD_ID_INDICATE_PM_BSS_ABORT, /* 0x1b (Set) */ + CMD_ID_UPDATE_BEACON_CONTENT, /* 0x1c (Set) */ + CMD_ID_SET_BSS_RLM_PARAM, /* 0x1d (Set) */ + CMD_ID_SCAN_REQ, /* 0x1e (Set) */ + CMD_ID_SCAN_CANCEL, /* 0x1f (Set) */ + CMD_ID_CH_PRIVILEGE, /* 0x20 (Set) */ + CMD_ID_UPDATE_WMM_PARMS, /* 0x21 (Set) */ + CMD_ID_SET_WMM_PS_TEST_PARMS, /* 0x22 (Set) */ + CMD_ID_TX_AMPDU, /* 0x23 (Set) */ + CMD_ID_ADDBA_REJECT, /* 0x24 (Set) */ + CMD_ID_SET_PS_PROFILE_ADV, /* 0x25 (Set) */ + CMD_ID_SET_RAW_PATTERN, /* 0x26 (Set) */ + CMD_ID_CONFIG_PATTERN_FUNC, /* 0x27 (Set) */ + CMD_ID_SET_TX_PWR, /* 0x28 (Set) */ + CMD_ID_SET_5G_PWR_OFFSET, /* 0x29 (Set) */ + CMD_ID_SET_PWR_PARAM, /* 0x2A (Set) */ + CMD_ID_P2P_ABORT, /* 0x2B (Set) */ +#if CFG_STRESS_TEST_SUPPORT + CMD_ID_RANDOM_RX_RESET_EN = 0x2C, /* 0x2C (Set ) */ + CMD_ID_RANDOM_RX_RESET_DE = 0x2D, /* 0x2D (Set ) */ + CMD_ID_SAPP_EN = 0x2E, /* 0x2E (Set ) */ + CMD_ID_SAPP_DE = 0x2F, /* 0x2F (Set ) */ +#endif + CMD_ID_ROAMING_TRANSIT = 0x30, /* 0x30 (Set) */ + CMD_ID_SET_PHY_PARAM, /* 0x31 (Set) */ + CMD_ID_SET_NOA_PARAM, /* 0x32 (Set) */ + CMD_ID_SET_OPPPS_PARAM, /* 0x33 (Set) */ + CMD_ID_SET_UAPSD_PARAM, /* 0x34 (Set) */ + CMD_ID_SET_SIGMA_STA_SLEEP, /* 0x35 (Set) */ + CMD_ID_SET_EDGE_TXPWR_LIMIT, /* 0x36 (Set) */ + CMD_ID_SET_DEVICE_MODE, /* 0x37 (Set) */ + CMD_ID_SET_TXPWR_CTRL, /* 0x38 (Set) */ + + CMD_ID_GET_NIC_CAPABILITY = 0x80, /* 0x80 (Query) */ + CMD_ID_GET_LINK_QUALITY, /* 0x81 (Query) */ + CMD_ID_GET_STATISTICS, /* 0x82 (Query) */ + CMD_ID_GET_CONNECTION_STATUS, /* 0x83 (Query) */ + CMD_ID_GET_ASSOC_INFO, /* 0x84 (Query) (obsolete) */ + + CMD_ID_BASIC_CONFIG = 0xc1, /* 0xc1 (Set / Query) */ + CMD_ID_ACCESS_REG, /* 0xc2 (Set / Query) */ + CMD_ID_MAC_MCAST_ADDR, /* 0xc3 (Set / Query) */ + CMD_ID_802_11_PMKID, /* 0xc4 (Set / Query) */ + CMD_ID_ACCESS_EEPROM, /* 0xc5 (Set / Query) */ + CMD_ID_SW_DBG_CTRL, /* 0xc6 (Set / Query) */ +#if 1/* CFG_SUPPORT_ANTI_PIRACY */ + CMD_ID_SEC_CHECK, /* 0xc7 (Set / Query) */ +#endif + +#if CFG_SUPPORT_RDD_TEST_MODE + CMD_ID_SET_RDD_CH = 0xE1, +#endif + + CMD_ID_SET_BWCS = 0xF1, +#if CFG_SUPPORT_OSC_SETTING && defined(MT5931) + CMD_ID_SET_OSC = 0xf2, +#endif +} ENUM_CMD_ID_T, *P_ENUM_CMD_ID_T; + +typedef enum _ENUM_EVENT_ID_T { + EVENT_ID_CMD_RESULT = 1, /* 0x01 (Query) */ + EVENT_ID_NIC_CAPABILITY, /* 0x02 (Query) */ + EVENT_ID_CONNECTION_STATUS, /* 0x03 (Query / Unsolicited) (obsolete) */ + EVENT_ID_SCAN_RESULT, /* 0x04 (Query / Unsolicited) (obselete) */ + EVENT_ID_LINK_QUALITY, /* 0x05 (Query / Unsolicited) */ + EVENT_ID_STATISTICS, /* 0x06 (Query) */ + EVENT_ID_MIC_ERR_INFO, /* 0x07 (Unsolicited) */ + EVENT_ID_ASSOC_INFO, /* 0x08 (Query - CMD_ID_GET_ASSOC_INFO) */ + EVENT_ID_BASIC_CONFIG, /* 0x09 (Query - CMD_ID_BASIC_CONFIG) */ + EVENT_ID_ACCESS_REG, /* 0x0a (Query - CMD_ID_ACCESS_REG) */ + EVENT_ID_MAC_MCAST_ADDR, /* 0x0b (Query - CMD_ID_MAC_MCAST_ADDR) */ + EVENT_ID_802_11_PMKID, /* 0x0c (Query - CMD_ID_802_11_PMKID) */ + EVENT_ID_ACCESS_EEPROM, /* 0x0d (Query - CMD_ID_ACCESS_EEPROM) */ + EVENT_ID_SLEEPY_NOTIFY, /* 0x0e (Query) */ + EVENT_ID_BT_OVER_WIFI, /* 0x0f (Unsolicited) */ + EVENT_ID_TEST_STATUS, /* 0x10 (Query - CMD_ID_TEST_MODE) */ + EVENT_ID_RX_ADDBA, /* 0x11 (Unsolicited) (obsolete) */ + EVENT_ID_RX_DELBA, /* 0x12 (Unsolicited) (obsolete) */ + EVENT_ID_ACTIVATE_STA_REC_T, /* 0x13 (Unsolicited) */ + EVENT_ID_DEACTIVATE_STA_REC_T, /* 0x14 (Unsolicited) */ + EVENT_ID_SCAN_DONE, /* 0x15 (Unsoiicited) */ + EVENT_ID_RX_FLUSH, /* 0x16 (Unsolicited) */ + EVENT_ID_TX_DONE, /* 0x17 (Unsolicited) */ + EVENT_ID_CH_PRIVILEGE, /* 0x18 (Unsolicited) */ + EVENT_ID_BSS_ABSENCE_PRESENCE = 0x19, /* 0x19 (Unsolicited) */ + EVENT_ID_STA_CHANGE_PS_MODE, /* 0x1A (Unsolicited) */ + EVENT_ID_BSS_BEACON_TIMEOUT, /* 0x1B (Unsolicited) */ + EVENT_ID_UPDATE_NOA_PARAMS, /* 0x1C (Unsolicited) */ + EVENT_ID_AP_OBSS_STATUS, /* 0x1D (Unsolicited) */ + EVENT_ID_STA_UPDATE_FREE_QUOTA, /* 0x1E (Unsolicited) */ + EVENT_ID_SW_DBG_CTRL, /* 0x1F (Query - CMD_ID_SW_DBG_CTRL) */ + EVENT_ID_ROAMING_STATUS, /* 0x20 (Unsolicited) */ + EVENT_ID_STA_AGING_TIMEOUT, /* 0x21 (Unsolicited) */ +#if 1 /* CFG_SUPPORT_ANTI_PIRACY */ + EVENT_ID_SEC_CHECK_RSP, /* 0x22 (Unsolicited) */ +#endif + EVENT_ID_SEND_DEAUTH, /* 0x23 (Unsolicited) */ + +#if CFG_SUPPORT_RDD_TEST_MODE + EVENT_ID_UPDATE_RDD_STATUS, /* 0x24 (Unsolicited) */ +#endif + +#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS + EVENT_ID_UPDATE_BWCS_STATUS = 0x25, /* 0x25 (Unsolicited) */ + EVENT_ID_UPDATE_BCM_DEBUG /* 0x26 (Unsolicited) */ +#endif +} ENUM_EVENT_ID_T, *P_ENUM_EVENT_ID_T; + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +#ifndef LINUX +typedef UINT_8 CMD_STATUS; +#endif +/* for Event Packet (via HIF-RX) */ + /* following CM's documentation v0.7 */ +typedef struct _WIFI_CMD_T { + UINT_16 u2TxByteCount_UserPriority; + UINT_8 ucEtherTypeOffset; + UINT_8 ucResource_PktType_CSflags; + UINT_8 ucCID; + UINT_8 ucSetQuery; + UINT_8 ucSeqNum; + UINT_8 aucReserved2; + + UINT_8 aucBuffer[0]; +} WIFI_CMD_T, *P_WIFI_CMD_T; + +/* for Command Packet (via HIF-TX) */ + /* following CM's documentation v0.7 */ +typedef struct _WIFI_EVENT_T { + UINT_16 u2PacketLen; + UINT_16 u2PacketType; + UINT_8 ucEID; + UINT_8 ucSeqNum; + UINT_8 aucReserved2[2]; + + UINT_8 aucBuffer[0]; +} WIFI_EVENT_T, *P_WIFI_EVENT_T; + +// CMD_ID_TEST_MODE +typedef struct _CMD_TEST_CTRL_T { + UINT_8 ucAction; + UINT_8 aucReserved[3]; + union { + UINT_32 u4OpMode; + UINT_32 u4ChannelFreq; + PARAM_MTK_WIFI_TEST_STRUC_T rRfATInfo; + } u; +} CMD_TEST_CTRL_T, *P_CMD_TEST_CTRL_T; + +// EVENT_TEST_STATUS +typedef struct _PARAM_CUSTOM_RFTEST_TX_STATUS_STRUC_T { + UINT_32 u4PktSentStatus; + UINT_32 u4PktSentCount; + UINT_16 u2AvgAlc; + UINT_8 ucCckGainControl; + UINT_8 ucOfdmGainControl; +} PARAM_CUSTOM_RFTEST_TX_STATUS_STRUC_T, *P_PARAM_CUSTOM_RFTEST_TX_STATUS_STRUC_T; + +typedef struct _PARAM_CUSTOM_RFTEST_RX_STATUS_STRUC_T { + UINT_32 u4IntRxOk; /*!< number of packets that Rx ok from interrupt */ + UINT_32 u4IntCrcErr; /*!< number of packets that CRC error from interrupt */ + UINT_32 u4IntShort; /*!< number of packets that is short preamble from interrupt */ + UINT_32 u4IntLong; /*!< number of packets that is long preamble from interrupt */ + UINT_32 u4PauRxPktCount; /*!< number of packets that Rx ok from PAU */ + UINT_32 u4PauCrcErrCount; /*!< number of packets that CRC error from PAU */ + UINT_32 u4PauRxFifoFullCount; /*!< number of packets that is short preamble from PAU */ + UINT_32 u4PauCCACount; /*!< CCA rising edge count */ +} PARAM_CUSTOM_RFTEST_RX_STATUS_STRUC_T, *P_PARAM_CUSTOM_RFTEST_RX_STATUS_STRUC_T; + +typedef union _EVENT_TEST_STATUS { + PARAM_MTK_WIFI_TEST_STRUC_T rATInfo; +// PARAM_CUSTOM_RFTEST_TX_STATUS_STRUC_T rTxStatus; +// PARAM_CUSTOM_RFTEST_RX_STATUS_STRUC_T rRxStatus; +} EVENT_TEST_STATUS, *P_EVENT_TEST_STATUS; + +// CMD_BUILD_CONNECTION +typedef struct _CMD_BUILD_CONNECTION { + UINT_8 ucInfraMode; + UINT_8 ucAuthMode; + UINT_8 ucEncryptStatus; + UINT_8 ucSsidLen; + UINT_8 aucSsid[PARAM_MAX_LEN_SSID]; + UINT_8 aucBssid[PARAM_MAC_ADDR_LEN]; + + /* Ad-hoc mode */ + UINT_16 u2BeaconPeriod; + UINT_16 u2ATIMWindow; + UINT_8 ucJoinOnly; + UINT_8 ucReserved; + UINT_32 u4FreqInKHz; + + /* for faster connection */ + UINT_8 aucScanResult[0]; +} CMD_BUILD_CONNECTION, *P_CMD_BUILD_CONNECTION; + +//CMD_ADD_REMOVE_KEY +typedef struct _CMD_802_11_KEY { + UINT_8 ucAddRemove; + UINT_8 ucTxKey; + UINT_8 ucKeyType; + UINT_8 ucIsAuthenticator; + UINT_8 aucPeerAddr[6]; + UINT_8 ucNetType; + UINT_8 ucAlgorithmId; + UINT_8 ucKeyId; + UINT_8 ucKeyLen; + UINT_8 aucReverved[2]; + UINT_8 aucKeyMaterial[32]; + UINT_8 aucKeyRsc[16]; +} CMD_802_11_KEY, *P_CMD_802_11_KEY; + +/* WPA2 PMKID cache structure */ +typedef struct _PMKID_ENTRY_T { + PARAM_BSSID_INFO_T rBssidInfo; + BOOLEAN fgPmkidExist; +} PMKID_ENTRY_T, *P_PMKID_ENTRY_T; + +typedef struct _CMD_802_11_PMKID +{ + ULONG u4BSSIDInfoCount; + P_PMKID_ENTRY_T arPMKIDInfo[1]; +} CMD_802_11_PMKID, *P_CMD_802_11_PMKID; + +// CMD_BASIC_CONFIG +typedef struct _CMD_CSUM_OFFLOAD { + UINT_16 u2RxChecksum; // bit0: IP, bit1: UDP, bit2: TCP + UINT_16 u2TxChecksum; // bit0: IP, bit1: UDP, bit2: TCP +} CMD_CSUM_OFFLOAD, *P_CMD_CSUM_OFFLOAD; + +typedef struct _CMD_BASIC_CONFIG { + PARAM_MAC_ADDRESS rMyMacAddr; + UINT_8 ucNative80211; + UINT_8 aucReserved[1]; + + CMD_CSUM_OFFLOAD rCsumOffload; +} CMD_BASIC_CONFIG, *P_CMD_BASIC_CONFIG, EVENT_BASIC_CONFIG, *P_EVENT_BASIC_CONFIG; + +// CMD_MAC_MCAST_ADDR +typedef struct _CMD_MAC_MCAST_ADDR { + UINT_32 u4NumOfGroupAddr; + UINT_8 ucNetTypeIndex; + UINT_8 aucReserved[3]; + PARAM_MAC_ADDRESS arAddress[MAX_NUM_GROUP_ADDR]; +} CMD_MAC_MCAST_ADDR, *P_CMD_MAC_MCAST_ADDR, EVENT_MAC_MCAST_ADDR, *P_EVENT_MAC_MCAST_ADDR; + +// CMD_ACCESS_EEPROM +typedef struct _CMD_ACCESS_EEPROM { + UINT_16 u2Offset; + UINT_16 u2Data; +} CMD_ACCESS_EEPROM, *P_CMD_ACCESS_EEPROM, EVENT_ACCESS_EEPROM, *P_EVENT_ACCESS_EEPROM; + +typedef struct _CMD_CUSTOM_NOA_PARAM_STRUC_T { + UINT_32 u4NoaDurationMs; + UINT_32 u4NoaIntervalMs; + UINT_32 u4NoaCount; +} CMD_CUSTOM_NOA_PARAM_STRUC_T, *P_CMD_CUSTOM_NOA_PARAM_STRUC_T; + +typedef struct _CMD_CUSTOM_OPPPS_PARAM_STRUC_T { + UINT_32 u4CTwindowMs; +} CMD_CUSTOM_OPPPS_PARAM_STRUC_T, *P_CMD_CUSTOM_OPPPS_PARAM_STRUC_T; + +typedef struct _CMD_CUSTOM_UAPSD_PARAM_STRUC_T { + UINT_8 fgEnAPSD; + UINT_8 fgEnAPSD_AcBe; + UINT_8 fgEnAPSD_AcBk; + UINT_8 fgEnAPSD_AcVo; + UINT_8 fgEnAPSD_AcVi; + UINT_8 ucMaxSpLen; + UINT_8 aucResv[2]; +} CMD_CUSTOM_UAPSD_PARAM_STRUC_T, *P_CMD_CUSTOM_UAPSD_PARAM_STRUC_T; + +// EVENT_CONNECTION_STATUS +typedef struct _EVENT_CONNECTION_STATUS { + UINT_8 ucMediaStatus; + UINT_8 ucReasonOfDisconnect; + + UINT_8 ucInfraMode; + UINT_8 ucSsidLen; + UINT_8 aucSsid[PARAM_MAX_LEN_SSID]; + UINT_8 aucBssid[PARAM_MAC_ADDR_LEN]; + UINT_8 ucAuthenMode; + UINT_8 ucEncryptStatus; + UINT_16 u2BeaconPeriod; + UINT_16 u2AID; + UINT_16 u2ATIMWindow; + UINT_8 ucNetworkType; + UINT_8 aucReserved[1]; + UINT_32 u4FreqInKHz; + +#if CFG_ENABLE_WIFI_DIRECT + UINT_8 aucInterfaceAddr[PARAM_MAC_ADDR_LEN]; +#endif + +} EVENT_CONNECTION_STATUS, *P_EVENT_CONNECTION_STATUS; + +// EVENT_NIC_CAPABILITY +typedef struct _EVENT_NIC_CAPABILITY { + UINT_16 u2ProductID; + UINT_16 u2FwVersion; + UINT_16 u2DriverVersion; + UINT_8 ucHw5GBandDisabled; + UINT_8 ucEepromUsed; + UINT_8 ucEfuseValid; + UINT_8 ucMacAddrValid; + UINT_8 aucReserved[2]; +} EVENT_NIC_CAPABILITY, *P_EVENT_NIC_CAPABILITY; + +// modified version of WLAN_BEACON_FRAME_BODY_T for simplier buffering +typedef struct _WLAN_BEACON_FRAME_BODY_T_LOCAL { + /* Beacon frame body */ + UINT_32 au4Timestamp[2]; /* Timestamp */ + UINT_16 u2BeaconInterval; /* Beacon Interval */ + UINT_16 u2CapInfo; /* Capability */ + UINT_8 aucInfoElem[MAX_IE_LENGTH]; /* Various IEs, start from SSID */ + UINT_16 u2IELength; /* This field is *NOT* carried by F/W but caculated by nic_rx */ +} WLAN_BEACON_FRAME_BODY_T_LOCAL, *P_WLAN_BEACON_FRAME_BODY_T_LOCAL; + +// EVENT_SCAN_RESULT +typedef struct _EVENT_SCAN_RESULT_T { + INT_32 i4RSSI; + UINT_32 u4LinkQuality; + UINT_32 u4DSConfig; /* Center frequency */ + UINT_32 u4DomainInfo; /* Require CM opinion */ + UINT_32 u4Reserved; + UINT_8 ucNetworkType; + UINT_8 ucOpMode; + UINT_8 aucBssid[MAC_ADDR_LEN]; + UINT_8 aucRatesEx[PARAM_MAX_LEN_RATES_EX]; + WLAN_BEACON_FRAME_BODY_T_LOCAL rBeaconFrameBody; +} EVENT_SCAN_RESULT_T, *P_EVENT_SCAN_RESULT_T; + +/* event of tkip mic error */ +typedef struct _EVENT_MIC_ERR_INFO +{ + UINT_32 u4Flags; +} EVENT_MIC_ERR_INFO, *P_EVENT_MIC_ERR_INFO; + +typedef struct _EVENT_PMKID_CANDIDATE_LIST_T +{ + UINT_32 u4Version; /*!< Version */ + UINT_32 u4NumCandidates; /*!< How many candidates follow */ + PARAM_PMKID_CANDIDATE_T arCandidateList[1]; +} EVENT_PMKID_CANDIDATE_LIST_T, *P_EVENT_PMKID_CANDIDATE_LIST_T; + + +typedef struct _EVENT_CMD_RESULT { + UINT_8 ucCmdID; + UINT_8 ucStatus; + UINT_8 aucReserved[2]; +} EVENT_CMD_RESULT, *P_EVENT_CMD_RESULT; + +#if CFG_SUPPORT_OSC_SETTING && defined(MT5931) +typedef struct _CMD_MCU_LP_PARAM_T { + UINT_16 u2OscStableTime; + UINT_8 ucReserved[6]; +} CMD_MCU_LP_PARAM_T, *P_CMD_MCU_LP_PARAM_T; +#endif + + +// CMD_ID_ACCESS_REG & EVENT_ID_ACCESS_REG +typedef struct _CMD_ACCESS_REG { + UINT_32 u4Address; + UINT_32 u4Data; +} CMD_ACCESS_REG, *P_CMD_ACCESS_REG; + +typedef struct _CMD_SW_DBG_CTRL_T { + UINT_32 u4Id; + UINT_32 u4Data; + /* Debug Support */ + UINT_32 u4DebugCnt[64]; +} CMD_SW_DBG_CTRL_T, *P_CMD_SW_DBG_CTRL_T; + + +// CMD_ID_LINK_ATTRIB +typedef struct _CMD_LINK_ATTRIB { + INT_8 cRssiTrigger; + UINT_8 ucDesiredRateLen; + UINT_16 u2DesiredRate[32]; + UINT_8 ucMediaStreamMode; + UINT_8 aucReserved[1]; +} CMD_LINK_ATTRIB, *P_CMD_LINK_ATTRIB; + +// CMD_ID_NIC_POWER_CTRL +typedef struct _CMD_NIC_POWER_CTRL { + UINT_8 ucPowerMode; + UINT_8 aucReserved[3]; +} CMD_NIC_POWER_CTRL, *P_CMD_NIC_POWER_CTRL; + +// CMD_ID_POWER_SAVE_MODE +typedef struct _CMD_PS_PROFILE_T { + UINT_8 ucNetTypeIndex; + UINT_8 ucPsProfile; + UINT_8 aucReserved[2]; +} CMD_PS_PROFILE_T, *P_CMD_PS_PROFILE_T; + + +// EVENT_LINK_QUALITY +typedef struct _EVENT_LINK_QUALITY { + INT_8 cRssi; + INT_8 cLinkQuality; + UINT_16 u2LinkSpeed; + UINT_8 ucMediumBusyPercentage; +} EVENT_LINK_QUALITY, *P_EVENT_LINK_QUALITY; + +#if CFG_SUPPORT_P2P_RSSI_QUERY +// EVENT_LINK_QUALITY +typedef struct _EVENT_LINK_QUALITY_EX { + INT_8 cRssi; + INT_8 cLinkQuality; + UINT_16 u2LinkSpeed; + UINT_8 ucMediumBusyPercentage; + UINT_8 ucIsLQ0Rdy; + INT_8 cRssiP2P; /* For P2P Network. */ + INT_8 cLinkQualityP2P; + UINT_16 u2LinkSpeedP2P; + UINT_8 ucMediumBusyPercentageP2P; + UINT_8 ucIsLQ1Rdy; +} EVENT_LINK_QUALITY_EX, *P_EVENT_LINK_QUALITY_EX; +#endif + +// EVENT_ID_STATISTICS +typedef struct _EVENT_STATISTICS { + LARGE_INTEGER rTransmittedFragmentCount; + LARGE_INTEGER rMulticastTransmittedFrameCount; + LARGE_INTEGER rFailedCount; + LARGE_INTEGER rRetryCount; + LARGE_INTEGER rMultipleRetryCount; + LARGE_INTEGER rRTSSuccessCount; + LARGE_INTEGER rRTSFailureCount; + LARGE_INTEGER rACKFailureCount; + LARGE_INTEGER rFrameDuplicateCount; + LARGE_INTEGER rReceivedFragmentCount; + LARGE_INTEGER rMulticastReceivedFrameCount; + LARGE_INTEGER rFCSErrorCount; +} EVENT_STATISTICS, *P_EVENT_STATISTICS; + +// EVENT_ID_FW_SLEEPY_NOTIFY +typedef struct _EVENT_SLEEPY_NOTIFY { + UINT_8 ucSleepyState; + UINT_8 aucReserved[3]; +} EVENT_SLEEPY_NOTIFY, *P_EVENT_SLEEPY_NOTIFY; + +typedef struct _EVENT_ACTIVATE_STA_REC_T { + UINT_8 aucMacAddr[6]; + UINT_8 ucStaRecIdx; + UINT_8 ucNetworkTypeIndex; + BOOLEAN fgIsQoS; + BOOLEAN fgIsAP; + UINT_8 aucReserved[2]; +} EVENT_ACTIVATE_STA_REC_T, *P_EVENT_ACTIVATE_STA_REC_T; + +typedef struct _EVENT_DEACTIVATE_STA_REC_T { + UINT_8 ucStaRecIdx; + UINT_8 aucReserved[3]; +} EVENT_DEACTIVATE_STA_REC_T, *P_EVENT_DEACTIVATE_STA_REC_T; + +// CMD_BT_OVER_WIFI +typedef struct _CMD_BT_OVER_WIFI { + UINT_8 ucAction; /* 0: query, 1: setup, 2: destroy */ + UINT_8 ucChannelNum; + PARAM_MAC_ADDRESS rPeerAddr; + UINT_16 u2BeaconInterval; + UINT_8 ucTimeoutDiscovery; + UINT_8 ucTimeoutInactivity; + UINT_8 ucRole; + UINT_8 PAL_Capabilities; + UINT_8 cMaxTxPower; + UINT_8 ucChannelBand; + UINT_8 ucReserved[1]; +} CMD_BT_OVER_WIFI, *P_CMD_BT_OVER_WIFI; + +// EVENT_BT_OVER_WIFI +typedef struct _EVENT_BT_OVER_WIFI { + UINT_8 ucLinkStatus; + UINT_8 ucSelectedChannel; + INT_8 cRSSI; + UINT_8 ucReserved[1]; +} EVENT_BT_OVER_WIFI, *P_EVENT_BT_OVER_WIFI; + +// Same with DOMAIN_SUBBAND_INFO +typedef struct _CMD_SUBBAND_INFO { + UINT_8 ucRegClass; + UINT_8 ucBand; + UINT_8 ucChannelSpan; + UINT_8 ucFirstChannelNum; + UINT_8 ucNumChannels; + UINT_8 aucReserved[3]; +} CMD_SUBBAND_INFO, *P_CMD_SUBBAND_INFO; + +// CMD_SET_DOMAIN_INFO +typedef struct _CMD_SET_DOMAIN_INFO_T { + UINT_16 u2CountryCode; + UINT_16 u2Reserved; + CMD_SUBBAND_INFO rSubBand[6]; + + UINT_8 uc2G4Bandwidth; /* CONFIG_BW_20_40M or CONFIG_BW_20M */ + UINT_8 uc5GBandwidth; /* CONFIG_BW_20_40M or CONFIG_BW_20M */ + UINT_8 aucReserved[2]; +} CMD_SET_DOMAIN_INFO_T, *P_CMD_SET_DOMAIN_INFO_T; + +// CMD_SET_IP_ADDRESS +typedef struct _IPV4_NETWORK_ADDRESS { + UINT_8 aucIpAddr[4]; +} IPV4_NETWORK_ADDRESS, *P_IPV4_NETWORK_ADDRESS; + +typedef struct _CMD_SET_NETWORK_ADDRESS_LIST { + UINT_8 ucNetTypeIndex; + UINT_8 ucAddressCount; + UINT_8 ucReserved[2]; + IPV4_NETWORK_ADDRESS arNetAddress[1]; +} CMD_SET_NETWORK_ADDRESS_LIST, *P_CMD_SET_NETWORK_ADDRESS_LIST; + +typedef struct _PATTERN_DESCRIPTION { + UINT_8 fgCheckBcA1; + UINT_8 fgCheckMcA1; + UINT_8 ePatternHeader; + UINT_8 fgAndOp; + UINT_8 fgNotOp; + UINT_8 ucPatternMask; + UINT_16 ucPatternOffset; + UINT_8 aucPattern[8]; +} PATTERN_DESCRIPTION, *P_PATTERN_DESCRIPTION; + +typedef struct _CMD_RAW_PATTERN_CONFIGURATION_T { + PATTERN_DESCRIPTION arPatternDesc[4]; +} CMD_RAW_PATTERN_CONFIGURATION_T, *P_CMD_RAW_PATTERN_CONFIGURATION_T; + +typedef struct _CMD_PATTERN_FUNC_CONFIG { + BOOLEAN fgBcA1En; + BOOLEAN fgMcA1En; + BOOLEAN fgBcA1MatchDrop; + BOOLEAN fgMcA1MatchDrop; +} CMD_PATTERN_FUNC_CONFIG, *P_CMD_PATTERN_FUNC_CONFIG; + + +typedef struct _EVENT_TX_DONE_T { + UINT_8 ucPacketSeq; + UINT_8 ucStatus; + UINT_16 u2SequenceNumber; + UINT_32 au4Reserved1; + UINT_32 au4Reserved2; + UINT_32 au4Reserved3; +} EVENT_TX_DONE_T, *P_EVENT_TX_DONE_T; + +typedef struct _CMD_BSS_ACTIVATE_CTRL { + UINT_8 ucNetTypeIndex; + UINT_8 ucActive; + UINT_8 aucReserved[2]; +} CMD_BSS_ACTIVATE_CTRL, *P_CMD_BSS_ACTIVATE_CTRL; + +typedef struct _CMD_SET_BSS_RLM_PARAM_T { + UINT_8 ucNetTypeIndex; + UINT_8 ucRfBand; + UINT_8 ucPrimaryChannel; + UINT_8 ucRfSco; + UINT_8 ucErpProtectMode; + UINT_8 ucHtProtectMode; + UINT_8 ucGfOperationMode; + UINT_8 ucTxRifsMode; + UINT_16 u2HtOpInfo3; + UINT_16 u2HtOpInfo2; + UINT_8 ucHtOpInfo1; + UINT_8 ucUseShortPreamble; + UINT_8 ucUseShortSlotTime; + UINT_8 ucCheckId; /* Fixed value: 0x72 */ +} CMD_SET_BSS_RLM_PARAM_T, *P_CMD_SET_BSS_RLM_PARAM_T; + +typedef struct _CMD_SET_BSS_INFO { + UINT_8 ucNetTypeIndex; + UINT_8 ucConnectionState; + UINT_8 ucCurrentOPMode; + UINT_8 ucSSIDLen; + UINT_8 aucSSID[32]; + UINT_8 aucBSSID[6]; + UINT_8 ucIsQBSS; + UINT_8 ucReserved1; + UINT_16 u2OperationalRateSet; + UINT_16 u2BSSBasicRateSet; + UINT_8 ucStaRecIdxOfAP; + UINT_8 ucReserved2; + UINT_8 ucReserved3; + UINT_8 ucNonHTBasicPhyType; /* For Slot Time and CWmin */ + UINT_8 ucAuthMode; + UINT_8 ucEncStatus; + UINT_8 ucPhyTypeSet; + UINT_8 aucOwnMac[6]; + UINT_8 fgWapiMode; + UINT_8 fgIsApMode; + UINT_8 aucRsv[1]; + CMD_SET_BSS_RLM_PARAM_T rBssRlmParam; +} CMD_SET_BSS_INFO, *P_CMD_SET_BSS_INFO; + +typedef struct _CMD_UPDATE_STA_RECORD_T { + UINT_8 ucIndex; + UINT_8 ucStaType; + UINT_8 aucMacAddr[MAC_ADDR_LEN]; + UINT_16 u2AssocId; + UINT_16 u2ListenInterval; + UINT_8 ucNetTypeIndex; + UINT_8 ucDesiredPhyTypeSet; + UINT_16 u2DesiredNonHTRateSet; + UINT_16 u2BSSBasicRateSet; + UINT_8 ucIsQoS; + UINT_8 ucIsUapsdSupported; + UINT_8 ucStaState; + UINT_8 ucMcsSet; + UINT_8 ucSupMcs32; + UINT_8 ucAmpduParam; + UINT_16 u2HtCapInfo; + UINT_16 u2HtExtendedCap; + UINT_32 u4TxBeamformingCap; + UINT_8 ucAselCap; + UINT_8 ucRCPI; + UINT_8 ucNeedResp; + UINT_8 ucUapsdAc; /* b0~3: Trigger enabled, b4~7: Delivery enabled */ + UINT_8 ucUapsdSp; /* 0: all, 1: max 2, 2: max 4, 3: max 6 */ + UINT_8 aucReserved[3]; + /* TBD */ +} CMD_UPDATE_STA_RECORD_T, *P_CMD_UPDATE_STA_RECORD_T; + +typedef struct _CMD_REMOVE_STA_RECORD_T { + UINT_8 ucIndex; + UINT_8 ucReserved; + UINT_8 aucMacAddr[MAC_ADDR_LEN]; +} CMD_REMOVE_STA_RECORD_T, *P_CMD_REMOVE_STA_RECORD_T; + +typedef struct _CMD_INDICATE_PM_BSS_CREATED_T { + UINT_8 ucNetTypeIndex; + UINT_8 ucDtimPeriod; + UINT_16 u2BeaconInterval; + UINT_16 u2AtimWindow; + UINT_8 aucReserved[2]; +} CMD_INDICATE_PM_BSS_CREATED, *P_CMD_INDICATE_PM_BSS_CREATED; + +typedef struct _CMD_INDICATE_PM_BSS_CONNECTED_T { + UINT_8 ucNetTypeIndex; + UINT_8 ucDtimPeriod; + UINT_16 u2AssocId; + UINT_16 u2BeaconInterval; + UINT_16 u2AtimWindow; + UINT_8 fgIsUapsdConnection; + UINT_8 ucBmpDeliveryAC; + UINT_8 ucBmpTriggerAC; + UINT_8 aucReserved[1]; +} CMD_INDICATE_PM_BSS_CONNECTED, *P_CMD_INDICATE_PM_BSS_CONNECTED; + +typedef struct _CMD_INDICATE_PM_BSS_ABORT { + UINT_8 ucNetTypeIndex; + UINT_8 aucReserved[3]; +} CMD_INDICATE_PM_BSS_ABORT, *P_CMD_INDICATE_PM_BSS_ABORT; + +typedef struct _CMD_BEACON_TEMPLATE_UPDATE { + UINT_8 ucUpdateMethod; // 0: update randomly, 1: update all, 2: delete all (1 and 2 will update directly without search) + UINT_8 ucNetTypeIndex; + UINT_8 aucReserved[2]; + UINT_16 u2Capability; + UINT_16 u2IELen; + UINT_8 aucIE[MAX_IE_LENGTH]; +} CMD_BEACON_TEMPLATE_UPDATE, *P_CMD_BEACON_TEMPLATE_UPDATE; + +typedef struct _CMD_SET_WMM_PS_TEST_STRUC_T { + UINT_8 ucNetTypeIndex; + UINT_8 bmfgApsdEnAc; /* b0~3: trigger-en AC0~3. b4~7: delivery-en AC0~3 */ + UINT_8 ucIsEnterPsAtOnce; /* enter PS immediately without 5 second guard after connected */ + UINT_8 ucIsDisableUcTrigger; /* not to trigger UC on beacon TIM is matched (under U-APSD) */ +} CMD_SET_WMM_PS_TEST_STRUC_T, *P_CMD_SET_WMM_PS_TEST_STRUC_T; + + +/* Definition for CHANNEL_INFO.ucBand: + * 0: Reserved + * 1: BAND_2G4 + * 2: BAND_5G + * Others: Reserved + */ +typedef struct _CHANNEL_INFO_T { + UINT_8 ucBand; + UINT_8 ucChannelNum; +} CHANNEL_INFO_T, *P_CHANNEL_INFO_T; + +typedef struct _CMD_SCAN_REQ_T { + UINT_8 ucSeqNum; + UINT_8 ucNetworkType; + UINT_8 ucScanType; + UINT_8 ucSSIDType; /* BIT(0) wildcard / BIT(1) P2P-wildcard / BIT(2) specific */ + UINT_8 ucSSIDLength; + UINT_8 aucReserved[1]; + UINT_16 u2ChannelMinDwellTime; + UINT_8 aucSSID[32]; + UINT_16 u2ChannelDwellTime; /* For P2P */ + UINT_8 ucChannelType; + UINT_8 ucChannelListNum; + CHANNEL_INFO_T arChannelList[32]; + UINT_16 u2IELen; + UINT_8 aucIE[MAX_IE_LENGTH]; +} CMD_SCAN_REQ, *P_CMD_SCAN_REQ; + +typedef struct _CMD_SCAN_REQ_V2_T { + UINT_8 ucSeqNum; + UINT_8 ucNetworkType; + UINT_8 ucScanType; + UINT_8 ucSSIDType; + PARAM_SSID_T arSSID[4]; + UINT_16 u2ProbeDelayTime; + UINT_16 u2ChannelDwellTime; /* For P2P */ + UINT_8 ucChannelType; + UINT_8 ucChannelListNum; + CHANNEL_INFO_T arChannelList[32]; + UINT_16 u2IELen; + UINT_8 aucIE[MAX_IE_LENGTH]; +} CMD_SCAN_REQ_V2, *P_CMD_SCAN_REQ_V2; + +typedef struct _CMD_SCAN_CANCEL_T { + UINT_8 ucSeqNum; + UINT_8 ucIsExtChannel; /* For P2P channel extention. */ + UINT_8 aucReserved[2]; +} CMD_SCAN_CANCEL, *P_CMD_SCAN_CANCEL; + +typedef struct _EVENT_SCAN_DONE_T { + UINT_8 ucSeqNum; + UINT_8 ucSparseChannelValid; + CHANNEL_INFO_T rSparseChannel; +} EVENT_SCAN_DONE, *P_EVENT_SCAN_DONE; + +typedef struct _CMD_CH_PRIVILEGE_T { + UINT_8 ucNetTypeIndex; + UINT_8 ucTokenID; + UINT_8 ucAction; + UINT_8 ucPrimaryChannel; + UINT_8 ucRfSco; + UINT_8 ucRfBand; + UINT_8 ucReqType; + UINT_8 ucReserved; + UINT_32 u4MaxInterval; /* In unit of ms */ + UINT_8 aucBSSID[6]; + UINT_8 aucReserved[2]; +} CMD_CH_PRIVILEGE_T, *P_CMD_CH_PRIVILEGE_T; + +typedef struct _CMD_TX_PWR_T { + INT_8 cTxPwr2G4Cck; /* signed, in unit of 0.5dBm */ +#if defined(MT6620) + INT_8 acReserved[3]; +#elif defined(MT5931) || defined(MT6628) + INT_8 cTxPwr2G4Dsss; /* signed, in unit of 0.5dBm */ + INT_8 acReserved[2]; +#else + #error "No valid definition!" +#endif + + INT_8 cTxPwr2G4OFDM_BPSK; + INT_8 cTxPwr2G4OFDM_QPSK; + INT_8 cTxPwr2G4OFDM_16QAM; + INT_8 cTxPwr2G4OFDM_Reserved; + INT_8 cTxPwr2G4OFDM_48Mbps; + INT_8 cTxPwr2G4OFDM_54Mbps; + + INT_8 cTxPwr2G4HT20_BPSK; + INT_8 cTxPwr2G4HT20_QPSK; + INT_8 cTxPwr2G4HT20_16QAM; + INT_8 cTxPwr2G4HT20_MCS5; + INT_8 cTxPwr2G4HT20_MCS6; + INT_8 cTxPwr2G4HT20_MCS7; + + INT_8 cTxPwr2G4HT40_BPSK; + INT_8 cTxPwr2G4HT40_QPSK; + INT_8 cTxPwr2G4HT40_16QAM; + INT_8 cTxPwr2G4HT40_MCS5; + INT_8 cTxPwr2G4HT40_MCS6; + INT_8 cTxPwr2G4HT40_MCS7; + + INT_8 cTxPwr5GOFDM_BPSK; + INT_8 cTxPwr5GOFDM_QPSK; + INT_8 cTxPwr5GOFDM_16QAM; + INT_8 cTxPwr5GOFDM_Reserved; + INT_8 cTxPwr5GOFDM_48Mbps; + INT_8 cTxPwr5GOFDM_54Mbps; + + INT_8 cTxPwr5GHT20_BPSK; + INT_8 cTxPwr5GHT20_QPSK; + INT_8 cTxPwr5GHT20_16QAM; + INT_8 cTxPwr5GHT20_MCS5; + INT_8 cTxPwr5GHT20_MCS6; + INT_8 cTxPwr5GHT20_MCS7; + + INT_8 cTxPwr5GHT40_BPSK; + INT_8 cTxPwr5GHT40_QPSK; + INT_8 cTxPwr5GHT40_16QAM; + INT_8 cTxPwr5GHT40_MCS5; + INT_8 cTxPwr5GHT40_MCS6; + INT_8 cTxPwr5GHT40_MCS7; +} CMD_TX_PWR_T, *P_CMD_TX_PWR_T; + +typedef struct _CMD_5G_PWR_OFFSET_T { + INT_8 cOffsetBand0; /* 4.915-4.980G */ + INT_8 cOffsetBand1; /* 5.000-5.080G */ + INT_8 cOffsetBand2; /* 5.160-5.180G */ + INT_8 cOffsetBand3; /* 5.200-5.280G */ + INT_8 cOffsetBand4; /* 5.300-5.340G */ + INT_8 cOffsetBand5; /* 5.500-5.580G */ + INT_8 cOffsetBand6; /* 5.600-5.680G */ + INT_8 cOffsetBand7; /* 5.700-5.825G */ +} CMD_5G_PWR_OFFSET_T, *P_CMD_5G_PWR_OFFSET_T; + +typedef struct _CMD_PWR_PARAM_T { + UINT_32 au4Data[28]; + UINT_32 u4RefValue1; + UINT_32 u4RefValue2; +} CMD_PWR_PARAM_T, *P_CMD_PWR_PARAM_T; + +typedef struct _CMD_PHY_PARAM_T { + UINT_8 aucData[144]; /* eFuse content */ +} CMD_PHY_PARAM_T, *P_CMD_PHY_PARAM_T; + + + +typedef struct _EVENT_CH_PRIVILEGE_T { + UINT_8 ucNetTypeIndex; + UINT_8 ucTokenID; + UINT_8 ucStatus; + UINT_8 ucPrimaryChannel; + UINT_8 ucRfSco; + UINT_8 ucRfBand; + UINT_8 ucReqType; + UINT_8 ucReserved; + UINT_32 u4GrantInterval; /* In unit of ms */ +} EVENT_CH_PRIVILEGE_T, *P_EVENT_CH_PRIVILEGE_T; + +typedef struct _EVENT_BSS_BEACON_TIMEOUT_T { + UINT_8 ucNetTypeIndex; + UINT_8 aucReserved[3]; +} EVENT_BSS_BEACON_TIMEOUT_T, *P_EVENT_BSS_BEACON_TIMEOUT_T; + +typedef struct _EVENT_STA_AGING_TIMEOUT_T { + UINT_8 ucStaRecIdx; + UINT_8 aucReserved[3]; +} EVENT_STA_AGING_TIMEOUT_T, *P_EVENT_STA_AGING_TIMEOUT_T; + +typedef struct _EVENT_NOA_TIMING_T { + UINT_8 fgIsInUse; /* Indicate if this entry is in use or not */ + UINT_8 ucCount; /* Count */ + UINT_8 aucReserved[2]; + + UINT_32 u4Duration; /* Duration */ + UINT_32 u4Interval; /* Interval */ + UINT_32 u4StartTime; /* Start Time */ +} EVENT_NOA_TIMING_T, *P_EVENT_NOA_TIMING_T; + +typedef struct _EVENT_UPDATE_NOA_PARAMS_T { + UINT_8 ucNetTypeIndex; + UINT_8 aucReserved[2]; + UINT_8 fgEnableOppPS; + UINT_16 u2CTWindow; + + UINT_8 ucNoAIndex; + UINT_8 ucNoATimingCount; /* Number of NoA Timing */ + EVENT_NOA_TIMING_T arEventNoaTiming[8/*P2P_MAXIMUM_NOA_COUNT*/]; +} EVENT_UPDATE_NOA_PARAMS_T, *P_EVENT_UPDATE_NOA_PARAMS_T; + +typedef struct _EVENT_AP_OBSS_STATUS_T { + UINT_8 ucNetTypeIndex; + UINT_8 ucObssErpProtectMode; + UINT_8 ucObssHtProtectMode; + UINT_8 ucObssGfOperationMode; + UINT_8 ucObssRifsOperationMode; + UINT_8 ucObssBeaconForcedTo20M; + UINT_8 aucReserved[2]; +} EVENT_AP_OBSS_STATUS_T, *P_EVENT_AP_OBSS_STATUS_T; + +typedef struct _CMD_EDGE_TXPWR_LIMIT_T { + INT_8 cBandEdgeMaxPwrCCK; + INT_8 cBandEdgeMaxPwrOFDM20; + INT_8 cBandEdgeMaxPwrOFDM40; + INT_8 cReserved; +} CMD_EDGE_TXPWR_LIMIT_T, *P_CMD_EDGE_TXPWR_LIMIT_T; + +typedef struct _CMD_SET_DEVICE_MODE_T { + UINT_16 u2ChipID; + UINT_16 u2Mode; +} CMD_SET_DEVICE_MODE_T, *P_CMD_SET_DEVICE_MODE_T; + + +#if CFG_SUPPORT_RDD_TEST_MODE +typedef struct _CMD_RDD_CH_T { + UINT_8 ucRddTestMode; + UINT_8 ucRddShutCh; + UINT_8 ucRddStartCh; + UINT_8 ucRddStopCh; + UINT_8 ucRddDfs; + UINT_8 ucReserved; + UINT_8 ucReserved1; + UINT_8 ucReserved2; +} CMD_RDD_CH_T, *P_CMD_RDD_CH_T; + +typedef struct _EVENT_RDD_STATUS_T { + UINT_8 ucRddStatus; + UINT_8 aucReserved[3]; +} EVENT_RDD_STATUS_T, *P_EVENT_RDD_STATUS_T; +#endif + +typedef struct _CMD_SET_TXPWR_CTRL_T{ + INT_8 c2GLegacyStaPwrOffset; /* Unit: 0.5dBm, default: 0*/ + INT_8 c2GHotspotPwrOffset; + INT_8 c2GP2pPwrOffset; + INT_8 c2GBowPwrOffset; + INT_8 c5GLegacyStaPwrOffset; /* Unit: 0.5dBm, default: 0*/ + INT_8 c5GHotspotPwrOffset; + INT_8 c5GP2pPwrOffset; + INT_8 c5GBowPwrOffset; + UINT_8 ucConcurrencePolicy; /* TX power policy when concurrence + in the same channel + 0: Highest power has priority + 1: Lowest power has priority */ + INT_8 acReserved1[3]; /* Must be zero */ + + /* Power limit by channel for all data rates */ + INT_8 acTxPwrLimit2G[14]; /* Channel 1~14, Unit: 0.5dBm*/ + INT_8 acTxPwrLimit5G[4]; /* UNII 1~4 */ + INT_8 acReserved2[2]; /* Must be zero */ +} CMD_SET_TXPWR_CTRL_T, *P_CMD_SET_TXPWR_CTRL_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID +nicCmdEventQueryMcrRead ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +nicCmdEventQuerySwCtrlRead ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + + + +VOID +nicCmdEventQueryRfTestATInfo( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +nicCmdEventSetCommon ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +nicCmdEventSetDisassociate ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +nicCmdEventSetIpAddress ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +nicCmdEventQueryLinkQuality( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +nicCmdEventQueryLinkSpeed( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +nicCmdEventQueryStatistics( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +nicCmdEventEnterRfTest( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +nicCmdEventLeaveRfTest( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +nicCmdEventQueryAddress( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +nicCmdEventQueryMcastAddr( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +nicCmdEventQueryEepromRead( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +nicCmdEventSetMediaStreamMode( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +/* Statistics responder */ +VOID +nicCmdEventQueryXmitOk( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +nicCmdEventQueryRecvOk( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +nicCmdEventQueryXmitError( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +nicCmdEventQueryRecvError( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +nicCmdEventQueryRecvNoBuffer( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +nicCmdEventQueryRecvCrcError( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +nicCmdEventQueryRecvErrorAlignment( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +nicCmdEventQueryXmitOneCollision( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +nicCmdEventQueryXmitMoreCollisions( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +nicCmdEventQueryXmitMaxCollisions( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +/* for timeout check */ +VOID +nicOidCmdTimeoutCommon ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo + ); + +VOID +nicCmdTimeoutCommon ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo + ); + +VOID +nicOidCmdEnterRFTestTimeout ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _NIC_CMD_EVENT_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic_init_cmd_event.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic_init_cmd_event.h new file mode 100755 index 000000000000..84ed48cf14fc --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/nic_init_cmd_event.h @@ -0,0 +1,225 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/nic_init_cmd_event.h#1 $ +*/ + +/*! \file "nic_init_cmd_event.h" + \brief This file contains the declairation file of the WLAN initialization routines + for MediaTek Inc. 802.11 Wireless LAN Adapters. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: nic_init_cmd_event.h $ + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 03 12 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add two option for ACK and ENCRYPTION for firmware download + * + * 03 01 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add command/event definitions for initial states + * + * 02 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement host-side firmware download logic + * + * 02 08 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * prepare for implementing fw download logic + * +*/ +#ifndef _NIC_INIT_CMD_EVENT_H +#define _NIC_INIT_CMD_EVENT_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "gl_typedef.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define INIT_CMD_STATUS_SUCCESS 0 +#define INIT_CMD_STATUS_REJECTED_INVALID_PARAMS 1 +#define INIT_CMD_STATUS_REJECTED_CRC_ERROR 2 +#define INIT_CMD_STATUS_REJECTED_DECRYPT_FAIL 3 +#define INIT_CMD_STATUS_UNKNOWN 4 + +#define EVENT_HDR_SIZE OFFSET_OF(WIFI_EVENT_T, aucBuffer[0]) + +typedef enum _ENUM_INIT_CMD_ID { + INIT_CMD_ID_DOWNLOAD_BUF = 1, + INIT_CMD_ID_WIFI_START, + INIT_CMD_ID_ACCESS_REG, + INIT_CMD_ID_QUERY_PENDING_ERROR +} ENUM_INIT_CMD_ID, *P_ENUM_INIT_CMD_ID; + +typedef enum _ENUM_INIT_EVENT_ID { + INIT_EVENT_ID_CMD_RESULT = 1, + INIT_EVENT_ID_ACCESS_REG, + INIT_EVENT_ID_PENDING_ERROR +} ENUM_INIT_EVENT_ID, *P_ENUM_INIT_EVENT_ID; + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef UINT_8 CMD_STATUS; + +// commands +typedef struct _INIT_WIFI_CMD_T { + UINT_8 ucCID; + UINT_8 ucSeqNum; + UINT_16 u2Reserved; + UINT_8 aucBuffer[0]; +} INIT_WIFI_CMD_T, *P_INIT_WIFI_CMD_T; + +typedef struct _INIT_HIF_TX_HEADER_T { + UINT_16 u2TxByteCount; + UINT_8 ucEtherTypeOffset; + UINT_8 ucCSflags; + INIT_WIFI_CMD_T rInitWifiCmd; +} INIT_HIF_TX_HEADER_T, *P_INIT_HIF_TX_HEADER_T; + +#define DOWNLOAD_BUF_ENCRYPTION_MODE BIT(0) +#define DOWNLOAD_BUF_NO_CRC_CHECKING BIT(30) +#define DOWNLOAD_BUF_ACK_OPTION BIT(31) +typedef struct _INIT_CMD_DOWNLOAD_BUF { + UINT_32 u4Address; + UINT_32 u4Length; + UINT_32 u4CRC32; + UINT_32 u4DataMode; + UINT_8 aucBuffer[0]; +} INIT_CMD_DOWNLOAD_BUF, *P_INIT_CMD_DOWNLOAD_BUF; + +typedef struct _INIT_CMD_WIFI_START { + UINT_32 u4Override; + UINT_32 u4Address; +} INIT_CMD_WIFI_START, *P_INIT_CMD_WIFI_START; + +typedef struct _INIT_CMD_ACCESS_REG { + UINT_8 ucSetQuery; + UINT_8 aucReserved[3]; + UINT_32 u4Address; + UINT_32 u4Data; +} INIT_CMD_ACCESS_REG, *P_INIT_CMD_ACCESS_REG; + +// Events +typedef struct _INIT_WIFI_EVENT_T { + UINT_16 u2RxByteCount; + UINT_8 ucEID; + UINT_8 ucSeqNum; + UINT_8 aucBuffer[0]; +} INIT_WIFI_EVENT_T, *P_INIT_WIFI_EVENT_T; + +typedef struct _INIT_HIF_RX_HEADER_T { + INIT_WIFI_EVENT_T rInitWifiEvent; +} INIT_HIF_RX_HEADER_T, *P_INIT_HIF_RX_HEADER_T; + +typedef struct _INIT_EVENT_CMD_RESULT { + UINT_8 ucStatus; // 0: success + // 1: rejected by invalid param + // 2: rejected by incorrect CRC + // 3: rejected by decryption failure + // 4: unknown CMD + UINT_8 aucReserved[3]; +} INIT_EVENT_CMD_RESULT, *P_INIT_EVENT_CMD_RESULT, INIT_EVENT_PENDING_ERROR, *P_INIT_EVENT_PENDING_ERROR; + +typedef struct _INIT_EVENT_ACCESS_REG { + UINT_32 u4Address; + UINT_32 u4Data; +} INIT_EVENT_ACCESS_REG, *P_INIT_EVENT_ACCESS_REG; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _NIC_INIT_CMD_EVENT_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/p2p_typedef.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/p2p_typedef.h new file mode 100755 index 000000000000..ad798890b8cf --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/p2p_typedef.h @@ -0,0 +1,310 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/p2p_typedef.h#4 $ +*/ + +/*! \file p2p_typedef.h + \brief Declaration of data type and return values of internal protocol stack. + + In this file we declare the data type and return values which will be exported + to all MGMT Protocol Stack. +*/ + +/******************************************************************************* +* Copyright (c) 2010 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + + +#ifndef _P2P_TYPEDEF_H +#define _P2P_TYPEDEF_H + +#if CFG_ENABLE_WIFI_DIRECT + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/* +* type definition of pointer to p2p structure +*/ +//typedef struct _GL_P2P_INFO_T GL_P2P_INFO_T, *P_GL_P2P_INFO_T; +typedef struct _P2P_INFO_T P2P_INFO_T, *P_P2P_INFO_T; + +typedef struct _P2P_FSM_INFO_T P2P_FSM_INFO_T, *P_P2P_FSM_INFO_T; + +typedef struct _P2P_CONNECTION_SETTINGS_T P2P_CONNECTION_SETTINGS_T, *P_P2P_CONNECTION_SETTINGS_T; + + +/* Type definition for function pointer to p2p function*/ +typedef BOOLEAN (*P2P_LAUNCH)( + P_GLUE_INFO_T prGlueInfo + ); + +typedef BOOLEAN (*P2P_REMOVE)( + P_GLUE_INFO_T prGlueInfo, + BOOLEAN fgIsWlanLaunched + ); + +typedef BOOLEAN (*KAL_P2P_GET_CIPHER)( + IN P_GLUE_INFO_T prGlueInfo + ); + +typedef BOOLEAN (*KAL_P2P_GET_TKIP_CIPHER)( + IN P_GLUE_INFO_T prGlueInfo + ); + +typedef BOOLEAN (*KAL_P2P_GET_CCMP_CIPHER)( + IN P_GLUE_INFO_T prGlueInfo + ); + +typedef BOOLEAN (*KAL_P2P_GET_WSC_MODE)( + IN P_GLUE_INFO_T prGlueInfo + ); + +typedef struct net_device* (*KAL_P2P_GET_DEV_HDLR)( + P_GLUE_INFO_T prGlueInfo + ); + +typedef VOID (*KAL_P2P_SET_MULTICAST_WORK_ITEM) ( + P_GLUE_INFO_T prGlueInfo + ); + +typedef VOID (*KAL_P2P_UPDATE_ASSOC_INFO)( + IN P_GLUE_INFO_T prGlueInfo, + IN PUINT_8 pucFrameBody, + IN UINT_32 u4FrameBodyLen, + IN BOOLEAN fgReassocRequest + ); + +typedef BOOLEAN (*P2P_VALIDATE_AUTH) ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN PP_STA_RECORD_T pprStaRec, + OUT PUINT_16 pu2StatusCode + ); + +typedef BOOLEAN (*P2P_VALIDATE_ASSOC_REQ) ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT PUINT_16 pu4ControlFlags + ); + +typedef VOID (*P2P_RUN_EVENT_AAA_TX_FAIL) ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ); + +typedef BOOLEAN (*P2P_PARSE_CHECK_FOR_P2P_INFO_ELEM)( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucBuf, + OUT PUINT_8 pucOuiType + ); + + +typedef WLAN_STATUS (*P2P_RUN_EVENT_AAA_COMPLETE) ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ); + +typedef VOID (*P2P_PROCESS_EVENT_UPDATE_NOA_PARAM) ( + IN P_ADAPTER_T prAdapter, + UINT_8 ucNetTypeIndex, + P_EVENT_UPDATE_NOA_PARAMS_T prEventUpdateNoaParam + ); + +typedef VOID (*SCAN_P2P_PROCESS_BEACON_AND_PROBE_RESP) ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN P_WLAN_STATUS prStatus, + IN P_BSS_DESC_T prBssDesc, + IN P_WLAN_BEACON_FRAME_T prWlanBeaconFrame + ); + +typedef VOID (*P2P_RX_PUBLIC_ACTION_FRAME) ( + P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + +typedef VOID (*RLM_RSP_GENERATE_OBSS_SCAN_IE) ( + P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo + ); + +typedef VOID (*RLM_UPDATE_BW_BY_CH_LIST_FOR_AP)( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo + ); + +typedef VOID (*RLM_PROCESS_PUBLIC_ACTION)( + P_ADAPTER_T prAdapter, + P_SW_RFB_T prSwRfb + ); + +typedef VOID (*RLM_PROCESS_HT_ACTION)( + P_ADAPTER_T prAdapter, + P_SW_RFB_T prSwRfb + ); + +typedef VOID (*RLM_UPDATE_PARAMS_FOR_AP)( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + BOOLEAN fgUpdateBeacon + ); + +typedef VOID (*RLM_HANDLE_OBSS_STATUS_EVENT_PKT) ( + P_ADAPTER_T prAdapter, + P_EVENT_AP_OBSS_STATUS_T prObssStatus + ); + + +typedef BOOLEAN (*P2P_FUNC_VALIDATE_PROBE_REQ) ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT PUINT_32 pu4ControlFlags + ); + +typedef VOID (*RLM_BSS_INIT_FOR_AP)( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo + ); + +typedef UINT_32 (*P2P_GET_PROB_RSP_IE_TABLE_SIZE)( + VOID + ); + +typedef PUINT_8 (*P2P_BUILD_REASSOC_REQ_FRAME_COMMON_IES) ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN PUINT_8 pucBuffer + ); + + +typedef VOID (*P2P_FUNC_DISCONNECT) ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN BOOLEAN fgSendDeauth, + IN UINT_16 u2ReasonCode + ); + +typedef VOID (*P2P_FSM_RUN_EVENT_RX_DEAUTH) ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prSwRfb + ); + +typedef VOID (*P2P_FSM_RUN_EVENT_RX_DISASSOC) ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prSwRfb + ); + +typedef BOOLEAN (*P2P_FUN_IS_AP_MODE) ( + IN P_P2P_FSM_INFO_T prP2pFsmInfo + ); + +typedef VOID (*P2P_FSM_RUN_EVENT_BEACON_TIMEOUT) ( + IN P_ADAPTER_T prAdapter + ); + + +typedef VOID (*P2P_FUNC_STORE_ASSOC_RSP_IE_BUFFER) ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ); + + +typedef VOID (*P2P_GENERATE_P2P_IE) ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + +typedef UINT_32 (*P2P_CALCULATE_P2P_IE_LEN) ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec + ); + + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#endif /*CFG_ENABLE_WIFI_DIRECT*/ + +#endif /* _P2P_TYPEDEF_H */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/precomp.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/precomp.h new file mode 100755 index 000000000000..9c2534b4f281 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/precomp.h @@ -0,0 +1,385 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/precomp.h#1 $ +*/ + +/*! \file precomp.h + \brief Collection of most compiler flags are described here. + + In this file we collect all compiler flags and detail the driver behavior if + enable/disable such switch or adjust numeric parameters. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: precomp.h $ + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 15 2011 eddie.chen + * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter + * Add sw debug counter for QM. + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 12 13 2010 cp.wu + * [WCXRP00000260] [MT6620 Wi-Fi][Driver][Firmware] Create V1.1 branch for both firmware and driver + * create branch for Wi-Fi driver v1.1 + * + * 10 07 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * add firmware download for MT5931. + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * 1) add NVRAM access API + * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) + * 3) add OID implementation for NVRAM read/write service + * + * 09 21 2010 kevin.huang + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * Isolate P2P related function for Hardware Software Bundle + * + * 09 14 2010 chinghwa.yu + * NULL + * Fix BOW_FSM_INFO_T dependence. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 07 20 2010 wh.su + * + * adding the wapi code. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Check draft RLM code for HT cap + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Modify CNM message handler for new flow + * + * 06 28 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * 1st draft code for RLM module + * + * 06 19 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * consdier the concurrent network setting. + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration the security related function from firmware. + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration from MT6620 firmware. + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add hem_mbox.c and cnm_mem.h (but disabled some feature) for further migration + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge cnm_scan.h and hem_mbox.h + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge wifi_var.h, precomp.h, cnm_timer.h (data type only) + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * 1) add timeout handler mechanism for pending command packets + * 2) add p2p add/removal key + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * * * * * 3) private data could be hold and taken use for other purpose + * + * 03 16 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * build up basic data structure and definitions to support BT-over-WiFi + * + * 02 08 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * prepare for implementing fw download logic + * + * 01 27 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * . +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-12-08 11:30:58 GMT mtk02752 +** add rftest.h for implementing RF test mode in driver land +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-11-23 22:02:00 GMT mtk02468 +** Added que_mgt.h +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-10-13 21:58:36 GMT mtk01084 +** update for new macro define +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-21 09:40:11 GMT mtk01461 +** Add nic_cmd_event.h +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-17 20:00:26 GMT mtk01461 +** Add cmd_buf.h +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-19 18:32:44 GMT mtk01084 +** update for basic power management functions +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:08:25 GMT mtk01461 +** Update TX PATH API +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:11:38 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _PRECOMP_H +#define _PRECOMP_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "gl_os.h" // Include "config.h" + +#include "debug.h" + +#include "link.h" +#include "queue.h" + + +/*------------------------------------------------------------------------------ + * .\include\mgmt + *------------------------------------------------------------------------------ + */ +#include "wlan_typedef.h" + +#include "mac.h" + +/* Dependency: mac.h (MAC_ADDR_LEN) */ +#include "wlan_def.h" + +#if CFG_SUPPORT_SWCR +#include "swcr.h" +#endif + +/*------------------------------------------------------------------------------ + * .\include\nic + *------------------------------------------------------------------------------ + */ +/* Dependency: wlan_def.h (ENUM_NETWORK_TYPE_T) */ +#include "cmd_buf.h" + +/* Dependency: mac.h (MAC_ADDR_LEN) */ +#include "nic_cmd_event.h" + +/* Dependency: nic_cmd_event.h (P_EVENT_CONNECTION_STATUS) */ +#include "nic.h" + +#include "nic_init_cmd_event.h" + +#include "hif_rx.h" +#include "hif_tx.h" + +#include "nic_tx.h" + +/* Dependency: hif_rx.h (P_HIF_RX_HEADER_T) */ +#include "nic_rx.h" + +#include "que_mgt.h" + +#if CFG_ENABLE_WIFI_DIRECT +#include "p2p_typedef.h" +#endif + + +/*------------------------------------------------------------------------------ + * .\include\mgmt + *------------------------------------------------------------------------------ + */ + +#include "hem_mbox.h" + +#include "scan.h" +#include "bss.h" + +#include "wlan_lib.h" +#include "wlan_oid.h" +#include "wlan_bow.h" + +#include "hal.h" + +#if defined(MT6620) + #include "mt6620_reg.h" +#elif defined(MT5931) + #include "mt5931_reg.h" +#elif defined(MT6628) + #include "mt6628_reg.h" +#endif + +#include "rlm.h" +#include "rlm_domain.h" +#include "rlm_protection.h" +#include "rlm_obss.h" +#include "rate.h" + + +#include "aa_fsm.h" + +#include "cnm_timer.h" + +#if CFG_ENABLE_BT_OVER_WIFI +#include "bow.h" +#include "bow_fsm.h" +#endif + +#include "pwr_mgt.h" + + +#include "cnm.h" +/* Dependency: aa_fsm.h (ENUM_AA_STATE_T), p2p_fsm.h (WPS_ATTRI_MAX_LEN_DEVICE_NAME) */ +#include "cnm_mem.h" +#include "cnm_scan.h" + + +#include "privacy.h" + +#include "mib.h" + +#include "auth.h" +#include "assoc.h" + +#if CFG_SUPPORT_ROAMING +#include "roaming_fsm.h" +#endif /* CFG_SUPPORT_ROAMING */ + +#include "ais_fsm.h" + + +#include "adapter.h" + + +#include "que_mgt.h" +#include "rftest.h" + + +#if CFG_RSN_MIGRATION +#include "rsn.h" +#include "sec_fsm.h" +#endif + +#if CFG_SUPPORT_WAPI +#include "wapi.h" +#endif + +/*------------------------------------------------------------------------------ + * NVRAM structure + *------------------------------------------------------------------------------ + */ +#include "CFG_Wifi_File.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _PRECOMP_H */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/pwr_mgt.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/pwr_mgt.h new file mode 100755 index 000000000000..288589b2f40f --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/pwr_mgt.h @@ -0,0 +1,191 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/pwr_mgt.h#1 $ +*/ + +/*! \file "pwr_mgt.h" + \brief In this file we define the STATE and EVENT for Power Management FSM. + + The SCAN FSM is responsible for performing SCAN behavior when the Arbiter enter + ARB_STATE_SCAN. The STATE and EVENT for SCAN FSM are defined here with detail + description. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: pwr_mgt.h $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 07 09 2010 george.huang + * + * [WPD00001556] Migrate PM variables from FW to driver: for composing QoS Info + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 04 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * don't need SPIN_LOCK_PWR_CTRL anymore, it will raise IRQL + * and cause SdBusSubmitRequest running at DISPATCH_LEVEL as well. + + * + * 03 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * firmware download load adress & start address are now configured from config.h + * * * due to the different configurations on FPGA and ASIC +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-12-10 16:39:10 GMT mtk02752 +** disable PM macros temporally +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-10-29 19:48:37 GMT mtk01084 +** temp remove power management macro +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-08 16:51:11 GMT mtk01084 +** update for power management control macro +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-04-03 14:59:58 GMT mtk01426 +** Add #if CFG_HIF_LOOPBACK_PRETEST +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-23 16:53:10 GMT mtk01084 +** modify ACQUIRE_POWER_CONTROL_FROM_PM() and RECLAIM_POWER_CONTROL_TO_PM() macro +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-19 18:32:47 GMT mtk01084 +** update for basic power management functions +** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-03-19 15:05:20 GMT mtk01084 +** Initial version +** +*/ + +#ifndef _PWR_MGT_H +#define _PWR_MGT_H +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define PM_UAPSD_AC0 (BIT(0)) +#define PM_UAPSD_AC1 (BIT(1)) +#define PM_UAPSD_AC2 (BIT(2)) +#define PM_UAPSD_AC3 (BIT(3)) + +#define PM_UAPSD_ALL (PM_UAPSD_AC0 | PM_UAPSD_AC1 | PM_UAPSD_AC2 | PM_UAPSD_AC3) +#define PM_UAPSD_NONE 0 + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef struct _PM_PROFILE_SETUP_INFO_T { + /* Profile setup */ + UINT_8 ucBmpDeliveryAC; /* 0: AC_BE, 1: AC_BK, 2: AC_VI, 3: AC_VO */ + UINT_8 ucBmpTriggerAC; /* 0: AC_BE, 1: AC_BK, 2: AC_VI, 3: AC_VO */ + + UINT_8 ucUapsdSp; /* Number of triggered packets in UAPSD */ + +} PM_PROFILE_SETUP_INFO_T, *P_PM_PROFILE_SETUP_INFO_T; + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#if !CFG_ENABLE_FULL_PM + #define ACQUIRE_POWER_CONTROL_FROM_PM(_prAdapter) + #define RECLAIM_POWER_CONTROL_TO_PM(_prAdapter, _fgEnableGINT_in_IST) +#else + #define ACQUIRE_POWER_CONTROL_FROM_PM(_prAdapter) \ + { \ + if (_prAdapter->fgIsFwOwn) { \ + nicpmSetDriverOwn(_prAdapter); \ + } \ + /* Increase Block to Enter Low Power Semaphore count */ \ + GLUE_INC_REF_CNT(_prAdapter->u4PwrCtrlBlockCnt); \ + } + + #define RECLAIM_POWER_CONTROL_TO_PM(_prAdapter, _fgEnableGINT_in_IST) \ + { \ + ASSERT(_prAdapter->u4PwrCtrlBlockCnt != 0); \ + /* Decrease Block to Enter Low Power Semaphore count */ \ + GLUE_DEC_REF_CNT(_prAdapter->u4PwrCtrlBlockCnt); \ + if (_prAdapter->fgWiFiInSleepyState && (_prAdapter->u4PwrCtrlBlockCnt == 0)) { \ + nicpmSetFWOwn(_prAdapter, _fgEnableGINT_in_IST); \ + } \ + } +#endif + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _PWR_MGT_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/queue.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/queue.h new file mode 100755 index 000000000000..aee2ccd34757 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/queue.h @@ -0,0 +1,233 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/queue.h#1 $ +*/ + +/*! \file queue.h + \brief Definition for singly queue operations. + + In this file we define the singly queue data structure and its + queue operation MACROs. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: queue.h $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 07 16 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * bugfix for SCN migration + * 1) modify QUEUE_CONCATENATE_QUEUES() so it could be used to concatence with an empty queue + * 2) before AIS issues scan request, network(BSS) needs to be activated first + * 3) only invoke COPY_SSID when using specified SSID for scan + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 04 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * . +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:11:46 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _QUEUE_H +#define _QUEUE_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "gl_typedef.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* Singly Queue Structures - Entry Part */ +typedef struct _QUE_ENTRY_T { + struct _QUE_ENTRY_T *prNext; + struct _QUE_ENTRY_T *prPrev; /* For Rx buffer reordering used only */ +} QUE_ENTRY_T, *P_QUE_ENTRY_T; + +/* Singly Queue Structures - Queue Part */ +typedef struct _QUE_T { + P_QUE_ENTRY_T prHead; + P_QUE_ENTRY_T prTail; + UINT_32 u4NumElem; +} QUE_T, *P_QUE_T; + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define QUEUE_INITIALIZE(prQueue) \ + { \ + (prQueue)->prHead = (P_QUE_ENTRY_T)NULL; \ + (prQueue)->prTail = (P_QUE_ENTRY_T)NULL; \ + (prQueue)->u4NumElem = 0; \ + } + +#define QUEUE_IS_EMPTY(prQueue) (((P_QUE_T)(prQueue))->prHead == (P_QUE_ENTRY_T)NULL) + +#define QUEUE_IS_NOT_EMPTY(prQueue) ((prQueue)->u4NumElem > 0) + +#define QUEUE_GET_HEAD(prQueue) ((prQueue)->prHead) + +#define QUEUE_GET_TAIL(prQueue) ((prQueue)->prTail) + +#define QUEUE_GET_NEXT_ENTRY(prQueueEntry) ((prQueueEntry)->prNext) + +#define QUEUE_INSERT_HEAD(prQueue, prQueueEntry) \ + { \ + ASSERT(prQueue); \ + ASSERT(prQueueEntry); \ + (prQueueEntry)->prNext = (prQueue)->prHead; \ + (prQueue)->prHead = (prQueueEntry); \ + if ((prQueue)->prTail == (P_QUE_ENTRY_T)NULL) { \ + (prQueue)->prTail = (prQueueEntry); \ + } \ + ((prQueue)->u4NumElem)++; \ + } + +#define QUEUE_INSERT_TAIL(prQueue, prQueueEntry) \ + { \ + ASSERT(prQueue); \ + ASSERT(prQueueEntry); \ + (prQueueEntry)->prNext = (P_QUE_ENTRY_T)NULL; \ + if ((prQueue)->prTail) { \ + ((prQueue)->prTail)->prNext = (prQueueEntry); \ + } else { \ + (prQueue)->prHead = (prQueueEntry); \ + } \ + (prQueue)->prTail = (prQueueEntry); \ + ((prQueue)->u4NumElem)++; \ + } + +/* NOTE: We assume the queue entry located at the beginning of "prQueueEntry Type", + * so that we can cast the queue entry to other data type without doubts. + * And this macro also decrease the total entry count at the same time. + */ +#define QUEUE_REMOVE_HEAD(prQueue, prQueueEntry, _P_TYPE) \ + { \ + ASSERT(prQueue); \ + prQueueEntry = (_P_TYPE)((prQueue)->prHead); \ + if (prQueueEntry) { \ + (prQueue)->prHead = ((P_QUE_ENTRY_T)(prQueueEntry))->prNext; \ + if ((prQueue)->prHead == (P_QUE_ENTRY_T)NULL){ \ + (prQueue)->prTail = (P_QUE_ENTRY_T)NULL; \ + } \ + ((P_QUE_ENTRY_T)(prQueueEntry))->prNext = (P_QUE_ENTRY_T)NULL; \ + ((prQueue)->u4NumElem)--; \ + } \ + } + +#define QUEUE_MOVE_ALL(prDestQueue, prSrcQueue) \ + { \ + ASSERT(prDestQueue); \ + ASSERT(prSrcQueue); \ + *(P_QUE_T)prDestQueue = *(P_QUE_T)prSrcQueue; \ + QUEUE_INITIALIZE(prSrcQueue); \ + } + +#define QUEUE_CONCATENATE_QUEUES(prDestQueue, prSrcQueue) \ + { \ + ASSERT(prDestQueue); \ + ASSERT(prSrcQueue); \ + if (prSrcQueue->u4NumElem > 0) { \ + if ((prDestQueue)->prTail) { \ + ((prDestQueue)->prTail)->prNext = (prSrcQueue)->prHead; \ + } else { \ + (prDestQueue)->prHead = (prSrcQueue)->prHead; \ + } \ + (prDestQueue)->prTail = (prSrcQueue)->prTail; \ + ((prDestQueue)->u4NumElem) += ((prSrcQueue)->u4NumElem); \ + QUEUE_INITIALIZE(prSrcQueue); \ + } \ + } + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _QUEUE_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/rftest.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/rftest.h new file mode 100755 index 000000000000..5cb7c3201445 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/rftest.h @@ -0,0 +1,361 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/rftest.h#1 $ +*/ + +/*! \file "rftest.h" + \brief definitions for RF Productino test + +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: rftest.h $ + * + * 12 20 2011 cp.wu + * [WCXRP00001144] [MT6620 Wi-Fi][Driver][Firmware] Add RF_FUNC_ID for exposing device and related version information + * add driver implementations for RF_AT_FUNCID_FW_INFO & RF_AT_FUNCID_DRV_INFO + * to expose version information + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 08 04 2010 cp.wu + * NULL + * add an extra parameter to rftestQueryATInfo 'cause it's necessary to pass u4FuncData for query request. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 04 14 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * information buffer for query oid/ioctl is now buffered in prCmdInfo + * * * * instead of glue-layer variable to improve multiple oid/ioctl capability + * + * 12 30 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) According to CMD/EVENT documentation v0.8, + * * * * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, + * * * * * * * and result is retrieved by get ATInfo instead + * * * * * * * 2) add 4 counter for recording aggregation statistics +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-12-08 17:35:11 GMT mtk02752 +** * comment out RF test which is not supported on MT6620 +** + API decalre for rftest +** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-12-08 11:29:07 GMT mtk02752 +** definitions for RF test mode +** +*/ +#ifndef _RFTEST_H +#define _RFTEST_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +// Table Version +#define RF_AUTO_TEST_FUNCTION_TABLE_VERSION 0x01000001 + +// Power +#define RF_AT_PARAM_POWER_MASK BITS(0,7) +#define RF_AT_PARAM_POWER_MAX RF_AT_PARAM_POWER_MASK + +// Rate +#define RF_AT_PARAM_RATE_MCS_MASK BIT(31) +#define RF_AT_PARAM_RATE_MASK BITS(0,7) +#define RF_AT_PARAM_RATE_CCK_MAX 3 +#define RF_AT_PARAM_RATE_1M 0 +#define RF_AT_PARAM_RATE_2M 1 +#define RF_AT_PARAM_RATE_5_5M 2 +#define RF_AT_PARAM_RATE_11M 3 +#define RF_AT_PARAM_RATE_6M 4 +#define RF_AT_PARAM_RATE_9M 5 +#define RF_AT_PARAM_RATE_12M 6 +#define RF_AT_PARAM_RATE_18M 7 +#define RF_AT_PARAM_RATE_24M 8 +#define RF_AT_PARAM_RATE_36M 9 +#define RF_AT_PARAM_RATE_48M 10 +#define RF_AT_PARAM_RATE_54M 11 + +// Antenna +#define RF_AT_PARAM_ANTENNA_ID_MASK BITS(0,7) +#define RF_AT_PARAM_ANTENNA_ID_MAX 1 + +// Packet Length +#define RF_AT_PARAM_TX_80211HDR_BYTE_MAX (32) +#define RF_AT_PARAM_TX_80211PAYLOAD_BYTE_MAX (2048) + +#define RF_AT_PARAM_TX_PKTLEN_BYTE_DEFAULT 1024 +#define RF_AT_PARAM_TX_PKTLEN_BYTE_MAX \ + ((UINT_16)(RF_AT_PARAM_TX_80211HDR_BYTE_MAX + RF_AT_PARAM_TX_80211PAYLOAD_BYTE_MAX )) + +// Packet Count +#define RF_AT_PARAM_TX_PKTCNT_DEFAULT 1000 +#define RF_AT_PARAM_TX_PKTCNT_UNLIMITED 0 + +// Packet Interval +#define RF_AT_PARAM_TX_PKT_INTERVAL_US_DEFAULT 50 + +// ALC +#define RF_AT_PARAM_ALC_DISABLE 0 +#define RF_AT_PARAM_ALC_ENABLE 1 + +// TXOP +#define RF_AT_PARAM_TXOP_DEFAULT 0 +#define RF_AT_PARAM_TXOPQUE_QMASK BITS(16,31) +#define RF_AT_PARAM_TXOPQUE_TMASK BITS(0,15) +#define RF_AT_PARAM_TXOPQUE_AC0 (0<<16) +#define RF_AT_PARAM_TXOPQUE_AC1 (1<<16) +#define RF_AT_PARAM_TXOPQUE_AC2 (2<<16) +#define RF_AT_PARAM_TXOPQUE_AC3 (3<<16) +#define RF_AT_PARAM_TXOPQUE_AC4 (4<<16) +#define RF_AT_PARAM_TXOPQUE_QOFFSET 16 + +// Retry Limit +#define RF_AT_PARAM_TX_RETRY_DEFAULT 0 +#define RF_AT_PARAM_TX_RETRY_MAX 6 + +// QoS Queue +#define RF_AT_PARAM_QOSQUE_AC0 0 +#define RF_AT_PARAM_QOSQUE_AC1 1 +#define RF_AT_PARAM_QOSQUE_AC2 2 +#define RF_AT_PARAM_QOSQUE_AC3 3 +#define RF_AT_PARAM_QOSQUE_AC4 4 +#define RF_AT_PARAM_QOSQUE_DEFAULT RF_AT_PARAM_QOSQUE_AC0 + +// Bandwidth +#define RF_AT_PARAM_BANDWIDTH_20MHZ 0 +#define RF_AT_PARAM_BANDWIDTH_40MHZ 1 +#define RF_AT_PARAM_BANDWIDTH_U20_IN_40MHZ 2 +#define RF_AT_PARAM_BANDWIDTH_D20_IN_40MHZ 3 +#define RF_AT_PARAM_BANDWIDTH_DEFAULT RF_AT_PARAM_BANDWIDTH_20MHZ + +// GI (Guard Interval) +#define RF_AT_PARAM_GI_800NS 0 +#define RF_AT_PARAM_GI_400NS 1 +#define RF_AT_PARAM_GI_DEFAULT RF_AT_PARAM_GI_800NS + +// STBC +#define RF_AT_PARAM_STBC_DISABLE 0 +#define RF_AT_PARAM_STBC_ENABLE 1 + +// RIFS +#define RF_AT_PARAM_RIFS_DISABLE 0 +#define RF_AT_PARAM_RIFS_ENABLE 1 + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +// Function ID List +typedef enum _ENUM_RF_AT_FUNCID_T { + RF_AT_FUNCID_VERSION = 0, + RF_AT_FUNCID_COMMAND, + RF_AT_FUNCID_POWER, + RF_AT_FUNCID_RATE, + RF_AT_FUNCID_PREAMBLE, + RF_AT_FUNCID_ANTENNA, + RF_AT_FUNCID_PKTLEN, + RF_AT_FUNCID_PKTCNT, + RF_AT_FUNCID_PKTINTERVAL, + RF_AT_FUNCID_TEMP_COMPEN, + RF_AT_FUNCID_TXOPLIMIT, + RF_AT_FUNCID_ACKPOLICY, + RF_AT_FUNCID_PKTCONTENT, + RF_AT_FUNCID_RETRYLIMIT, + RF_AT_FUNCID_QUEUE, + RF_AT_FUNCID_BANDWIDTH, + RF_AT_FUNCID_GI, + RF_AT_FUNCID_STBC, + RF_AT_FUNCID_CHNL_FREQ, + RF_AT_FUNCID_RIFS, + RF_AT_FUNCID_TRSW_TYPE, + RF_AT_FUNCID_RF_SX_SHUTDOWN, + RF_AT_FUNCID_PLL_SHUTDOWN, + RF_AT_FUNCID_SLOW_CLK_MODE, + RF_AT_FUNCID_ADC_CLK_MODE, + RF_AT_FUNCID_MEASURE_MODE, + RF_AT_FUNCID_VOLT_COMPEN, + RF_AT_FUNCID_DPD_TX_GAIN, + RF_AT_FUNCID_DPD_MODE, + RF_AT_FUNCID_TSSI_MODE, + RF_AT_FUNCID_TX_GAIN_CODE, + RF_AT_FUNCID_TX_PWR_MODE, + + /* Query command */ + RF_AT_FUNCID_TXED_COUNT = 32, + RF_AT_FUNCID_TXOK_COUNT, + RF_AT_FUNCID_RXOK_COUNT, + RF_AT_FUNCID_RXERROR_COUNT, + RF_AT_FUNCID_RESULT_INFO, + RF_AT_FUNCID_TRX_IQ_RESULT, + RF_AT_FUNCID_TSSI_RESULT, + RF_AT_FUNCID_DPD_RESULT, + RF_AT_FUNCID_RXV_DUMP, + RF_AT_FUNCID_RX_PHY_STATIS, + RF_AT_FUNCID_MEASURE_RESULT, + RF_AT_FUNCID_TEMP_SENSOR, + RF_AT_FUNCID_VOLT_SENSOR, + RF_AT_FUNCID_READ_EFUSE, + RF_AT_FUNCID_RX_RSSI, + RF_AT_FUNCID_FW_INFO, + RF_AT_FUNCID_DRV_INFO, + + /* Set command */ + RF_AT_FUNCID_SET_DPD_RESULT = 64, + RF_AT_FUNCID_SET_CW_MODE, + RF_AT_FUNCID_SET_JAPAN_CH14_FILTER, + RF_AT_FUNCID_WRITE_EFUSE, + RF_AT_FUNCID_SET_MAC_ADDRESS + +} ENUM_RF_AT_FUNCID_T; + +// Command +typedef enum _ENUM_RF_AT_COMMAND_T { + RF_AT_COMMAND_STOPTEST = 0, + RF_AT_COMMAND_STARTTX, + RF_AT_COMMAND_STARTRX, + RF_AT_COMMAND_RESET, + RF_AT_COMMAND_OUTPUT_POWER, /* Payload */ + RF_AT_COMMAND_LO_LEAKAGE, /* Local freq is renamed to Local leakage */ + RF_AT_COMMAND_CARRIER_SUPPR, /* OFDM (LTF/STF), CCK (PI,PI/2) */ + RF_AT_COMMAND_TRX_IQ_CAL, + RF_AT_COMMAND_TSSI_CAL, + RF_AT_COMMAND_DPD_CAL, + RF_AT_COMMAND_CW, + RF_AT_COMMAND_NUM +} ENUM_RF_AT_COMMAND_T; + +// Preamble +typedef enum _ENUM_RF_AT_PREAMBLE_T { + RF_AT_PREAMBLE_NORMAL = 0, + RF_AT_PREAMBLE_CCK_SHORT, + RF_AT_PREAMBLE_11N_MM, + RF_AT_PREAMBLE_11N_GF, + RF_AT_PREAMBLE_NUM +} ENUM_RF_AT_PREAMBLE_T; + +// Ack Policy +typedef enum _ENUM_RF_AT_ACK_POLICY_T { + RF_AT_ACK_POLICY_NORMAL = 0, + RF_AT_ACK_POLICY_NOACK, + RF_AT_ACK_POLICY_NOEXPLICTACK, + RF_AT_ACK_POLICY_BLOCKACK, + RF_AT_ACK_POLICY_NUM +} ENUM_RF_AT_ACK_POLICY_T; + +typedef enum _ENUM_RF_AUTOTEST_STATE_T { + RF_AUTOTEST_STATE_STANDBY = 0, + RF_AUTOTEST_STATE_TX, + RF_AUTOTEST_STATE_RX, + RF_AUTOTEST_STATE_RESET, + RF_AUTOTEST_STATE_OUTPUT_POWER, + RF_AUTOTEST_STATE_LOCA_FREQUENCY, + RF_AUTOTEST_STATE_CARRIER_SUPRRESION, + RF_AUTOTEST_STATE_NUM +} ENUM_RF_AUTOTEST_STATE_T; + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +WLAN_STATUS +rftestSetATInfo( + IN P_ADAPTER_T prAdapter, + UINT_32 u4FuncIndex, + UINT_32 u4FuncData + ); + +WLAN_STATUS +rftestQueryATInfo( + IN P_ADAPTER_T prAdapter, + UINT_32 u4FuncIndex, + UINT_32 u4FuncData, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen + ); + +WLAN_STATUS +rftestSetFrequency( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4FreqInKHz, + IN PUINT_32 pu4SetInfoLen + ); + +#endif /* _RFTEST_H */ + + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/typedef.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/typedef.h new file mode 100755 index 000000000000..6d9ed672bffb --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/typedef.h @@ -0,0 +1,281 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/typedef.h#1 $ +*/ + +/*! \file typedef.h + \brief Declaration of data type and return values of internal protocol stack. + + In this file we declare the data type and return values which will be exported + to the GLUE Layer. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: typedef.h $ + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 12 30 2010 cp.wu + * [WCXRP00000327] [MT6620 Wi-Fi][Driver] Improve HEC WHQA 6972 workaround coverage in driver side + * host driver not to set FW-own when there is still pending interrupts + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 16 2010 kevin.huang + * NULL + * Refine AAA functions + * + * 07 19 2010 jeffrey.chang + * + * Linux port modification + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 23 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * integrate . + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 09 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add necessary changes to driver data paths. + * + * 06 09 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add definitions for module migration. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 06 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * move timer callback to glue layer. + * + * 05 31 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add cfg80211 interface, which is to replace WE, for further extension + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port + * + * 02 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add Ethernet destination address information in packet info for TX + * + * 02 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add new API: wlanProcessQueuedPackets() +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-03-23 21:41:37 GMT mtk01461 +** Update PACKET_INFO_INIT for TX Path +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-23 00:30:17 GMT mtk01461 +** Add parameter in PACKET_INFO_T for HIF Loopback +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-18 20:25:22 GMT mtk01461 +** Fix LINT warning +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:08:28 GMT mtk01461 +** Update TX PATH API +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:11:54 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _TYPEDEF_H +#define _TYPEDEF_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/* ieee80211.h of linux has duplicated definitions */ +#if defined(WLAN_STATUS_SUCCESS) +#undef WLAN_STATUS_SUCCESS +#endif + +#define WLAN_STATUS_SUCCESS ((WLAN_STATUS) 0x00000000L) +#define WLAN_STATUS_PENDING ((WLAN_STATUS) 0x00000103L) +#define WLAN_STATUS_NOT_ACCEPTED ((WLAN_STATUS) 0x00010003L) + +#define WLAN_STATUS_MEDIA_CONNECT ((WLAN_STATUS) 0x4001000BL) +#define WLAN_STATUS_MEDIA_DISCONNECT ((WLAN_STATUS) 0x4001000CL) +#define WLAN_STATUS_MEDIA_SPECIFIC_INDICATION ((WLAN_STATUS) 0x40010012L) + +#define WLAN_STATUS_SCAN_COMPLETE ((WLAN_STATUS) 0x60010001L) +#define WLAN_STATUS_MSDU_OK ((WLAN_STATUS) 0x60010002L) + +/* TODO(Kevin): double check if 0x60010001 & 0x60010002 is proprietary */ +#define WLAN_STATUS_ROAM_OUT_FIND_BEST ((WLAN_STATUS) 0x60010101L) +#define WLAN_STATUS_ROAM_DISCOVERY ((WLAN_STATUS) 0x60010102L) + +#define WLAN_STATUS_FAILURE ((WLAN_STATUS) 0xC0000001L) +#define WLAN_STATUS_RESOURCES ((WLAN_STATUS) 0xC000009AL) +#define WLAN_STATUS_NOT_SUPPORTED ((WLAN_STATUS) 0xC00000BBL) + +#define WLAN_STATUS_MULTICAST_FULL ((WLAN_STATUS) 0xC0010009L) +#define WLAN_STATUS_INVALID_PACKET ((WLAN_STATUS) 0xC001000FL) +#define WLAN_STATUS_ADAPTER_NOT_READY ((WLAN_STATUS) 0xC0010011L) +#define WLAN_STATUS_NOT_INDICATING ((WLAN_STATUS) 0xC0010013L) +#define WLAN_STATUS_INVALID_LENGTH ((WLAN_STATUS) 0xC0010014L) +#define WLAN_STATUS_INVALID_DATA ((WLAN_STATUS) 0xC0010015L) +#define WLAN_STATUS_BUFFER_TOO_SHORT ((WLAN_STATUS) 0xC0010016L) + +#define WLAN_STATUS_BWCS_UPDATE ((WLAN_STATUS) 0xC0010017L) + +/* NIC status flags */ +#define ADAPTER_FLAG_HW_ERR 0x00400000 + +/* Type Length */ +#define TL_IPV4 0x0008 +#define TL_IPV6 0xDD86 + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* Type definition for GLUE_INFO structure */ +typedef struct _GLUE_INFO_T GLUE_INFO_T, *P_GLUE_INFO_T; + +/* Type definition for WLAN STATUS */ +typedef UINT_32 WLAN_STATUS, *P_WLAN_STATUS; + +/* Type definition for ADAPTER structure */ +typedef struct _ADAPTER_T ADAPTER_T, *P_ADAPTER_T; + +/* Type definition for MESSAGE HEADER structure */ +typedef struct _MSG_HDR_T MSG_HDR_T, *P_MSG_HDR_T; + +/* Type definition for Pointer to OS Native Packet */ +typedef void *P_NATIVE_PACKET; + +/* Type definition for STA_RECORD_T structure to handle the connectivity and packet reception + * for a particular STA. + */ +typedef struct _STA_RECORD_T STA_RECORD_T, *P_STA_RECORD_T, **PP_STA_RECORD_T; + +/* CMD_INFO_T is used by Glue Layer to send a cluster of Command(OID) information to + * the TX Path to reduce the parameters of a function call. + */ +typedef struct _CMD_INFO_T CMD_INFO_T, *P_CMD_INFO_T; + +/* Following typedef should be removed later, because Glue Layer should not + * be aware of following data type. + */ +typedef struct _SW_RFB_T SW_RFB_T, *P_SW_RFB_T, **PP_SW_RFB_T; + +typedef struct _MSDU_INFO_T MSDU_INFO_T, *P_MSDU_INFO_T; + +typedef struct _REG_ENTRY_T REG_ENTRY_T, *P_REG_ENTRY_T; + +/* IST handler definition */ +typedef VOID (*IST_EVENT_FUNCTION)(P_ADAPTER_T); + +/* Type definition for function pointer of timer handler */ +typedef VOID (*PFN_TIMER_CALLBACK)(IN P_GLUE_INFO_T); + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#endif /* _TYPEDEF_H */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/wlan_bow.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/wlan_bow.h new file mode 100755 index 000000000000..93fe2c83bb1a --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/wlan_bow.h @@ -0,0 +1,591 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/wlan_bow.h#1 $ +*/ + +/*! \file "wlan_bow.h" + \brief This file contains the declairations of 802.11 PAL + command processing routines for + MediaTek Inc. 802.11 Wireless LAN Adapters. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: wlan_bow.h $ + * + * 05 25 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * Add BoW Cancel Scan Request and Turn On deactive network function. + * + * 05 23 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * Add some BoW error handling. + * + * 05 21 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * Protect BoW connection establishment. + * + * 05 17 2011 terry.wu + * [WCXRP00000730] [MT6620 Wi-Fi][BoW] Send deauth while disconnecting + * Send deauth while disconnecting BoW link. + * + * 05 06 2011 terry.wu + * [WCXRP00000707] [MT6620 Wi-Fi][Driver] Fix BoW Multiple Physical Link connect/disconnect issue + * Fix BoW Multiple Physical Link connect/disconnect issue. + * + * 04 15 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add BOW short range mode. + * + * 03 27 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Support multiple physical link. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 10 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add BOW table. + * + * 02 16 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add bowNotifyAllLinkDisconnected interface and change channel grant procedure for bow starting.. + * + * 02 15 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Update bowString and channel grant. + * + * 01 11 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Update BOW Activity Report structure and bug fix. + * + * 09 27 2010 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings + * Update BCM/BoW design and settings. + * + * 09 14 2010 chinghwa.yu + * NULL + * Add bowRunEventAAAComplete. + * + * 08 24 2010 chinghwa.yu + * NULL + * Update BOW for the 1st time. + * + * 07 30 2010 cp.wu + * NULL + * 1) BoW wrapper: use definitions instead of hard-coded constant for error code + * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead + * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames + * + * 07 15 2010 cp.wu + * + * sync. bluetooth-over-Wi-Fi interface to driver interface document v0.2.6. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * 1) add timeout handler mechanism for pending command packets + * 2) add p2p add/removal key + * + * 05 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * 1) all BT physical handles shares the same RSSI/Link Quality. + * 2) simplify BT command composing + * + * 04 28 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * change prefix for data structure used to communicate with 802.11 PAL + * to avoid ambiguous naming with firmware interface + * + * 04 27 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add multiple physical link support + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * * * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose +** +*/ + +#ifndef _WLAN_BOW_H +#define _WLAN_BOW_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "nic/bow.h" +#include "nic/cmd_buf.h" + +#if CFG_ENABLE_BT_OVER_WIFI +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define BOWCMD_STATUS_SUCCESS 0 +#define BOWCMD_STATUS_FAILURE 1 +#define BOWCMD_STATUS_UNACCEPTED 2 +#define BOWCMD_STATUS_INVALID 3 +#define BOWCMD_STATUS_TIMEOUT 4 + +#define BOW_WILDCARD_SSID "AMP" +#define BOW_WILDCARD_SSID_LEN 3 +#define BOW_SSID_LEN 21 + + /* 0: query, 1: setup, 2: destroy */ +#define BOW_QUERY_CMD 0 +#define BOW_SETUP_CMD 1 +#define BOW_DESTROY_CMD 2 + +#define BOW_INITIATOR 0 +#define BOW_RESPONDER 1 + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +typedef struct _BOW_TABLE_T { + UINT_8 ucAcquireID; + BOOLEAN fgIsValid; + ENUM_BOW_DEVICE_STATE eState; + UINT_8 aucPeerAddress[6]; + //UINT_8 ucRole; + //UINT_8 ucChannelNum; + UINT_16 u2Reserved; +} BOW_TABLE_T, *P_BOW_TABLE_T; + +typedef WLAN_STATUS (*PFN_BOW_CMD_HANDLE)(P_ADAPTER_T, P_AMPC_COMMAND); + +typedef struct _BOW_CMD_T { + UINT_8 uCmdID; + PFN_BOW_CMD_HANDLE pfCmdHandle; +} BOW_CMD_T, *P_BOW_CMD_T; + +typedef struct _BOW_EVENT_ACTIVITY_REPORT_T { + UINT_8 ucReason; + UINT_8 aucReserved; + UINT_8 aucPeerAddress[6]; +} BOW_EVENT_ACTIVITY_REPORT_T, *P_BOW_EVENT_ACTIVITY_REPORT_T; + +/* +ucReason: 0: success + 1: general failure + 2: too much time (> 2/3 second totally) requested for scheduling. + Others: reserved. +*/ + +typedef struct _BOW_EVENT_SYNC_TSF_T { + UINT_64 u4TsfTime; + UINT_32 u4TsfSysTime; + UINT_32 u4ScoTime; + UINT_32 u4ScoSysTime; + } BOW_EVENT_SYNC_TSF_T, *P_BOW_EVENT_SYNC_TSF_T; + +typedef struct _BOW_ACTIVITY_REPORT_BODY_T { + UINT_32 u4StartTime; + UINT_32 u4Duration; + UINT_32 u4Periodicity; + } BOW_ACTIVITY_REPORT_BODY_T, *P_BOW_ACTIVITY_REPORT_BODY_T; + +typedef struct _BOW_ACTIVITY_REPORT_T { + UINT_8 aucPeerAddress[6]; + UINT_8 ucScheduleKnown; + UINT_8 ucNumReports; + BOW_ACTIVITY_REPORT_BODY_T arBowActivityReportBody[MAX_ACTIVITY_REPORT]; + } BOW_ACTIVITY_REPORT_T, *P_BOW_ACTIVITY_REPORT_T; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*--------------------------------------------------------------*/ +/* Firmware Command Packer */ +/*--------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSendSetQueryBowCmd ( + IN P_ADAPTER_T prAdapter, + UINT_8 ucCID, + BOOLEAN fgSetQuery, + BOOLEAN fgNeedResp, + PFN_CMD_DONE_HANDLER pfCmdDoneHandler, + PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, + UINT_32 u4SetQueryInfoLen, + PUINT_8 pucInfoBuffer, + IN UINT_8 ucSeqNumber + ); + + +/*--------------------------------------------------------------*/ +/* Command Dispatcher */ +/*--------------------------------------------------------------*/ +WLAN_STATUS +wlanbowHandleCommand( + IN P_ADAPTER_T prAdapter, + IN P_AMPC_COMMAND prCmd + ); + + +/*--------------------------------------------------------------*/ +/* Routines to handle command */ +/*--------------------------------------------------------------*/ +WLAN_STATUS +bowCmdGetMacStatus( + IN P_ADAPTER_T prAdapter, + IN P_AMPC_COMMAND prCmd + ); + +WLAN_STATUS +bowCmdSetupConnection( + IN P_ADAPTER_T prAdapter, + IN P_AMPC_COMMAND prCmd + ); + +WLAN_STATUS +bowCmdDestroyConnection( + IN P_ADAPTER_T prAdapter, + IN P_AMPC_COMMAND prCmd + ); + +WLAN_STATUS +bowCmdSetPTK( + IN P_ADAPTER_T prAdapter, + IN P_AMPC_COMMAND prCmd + ); + +WLAN_STATUS +bowCmdReadRSSI( + IN P_ADAPTER_T prAdapter, + IN P_AMPC_COMMAND prCmd + ); + +WLAN_STATUS +bowCmdReadLinkQuality( + IN P_ADAPTER_T prAdapter, + IN P_AMPC_COMMAND prCmd + ); + +WLAN_STATUS +bowCmdShortRangeMode( + IN P_ADAPTER_T prAdapter, + IN P_AMPC_COMMAND prCmd + ); + +WLAN_STATUS +bowCmdGetChannelList( + IN P_ADAPTER_T prAdapter, + IN P_AMPC_COMMAND prCmd + ); + +VOID +wlanbowCmdEventSetStatus( + IN P_ADAPTER_T prAdapter, + IN P_AMPC_COMMAND prCmd, + IN UINT_8 ucEventBuf + ); + +/*--------------------------------------------------------------*/ +/* Callbacks for event indication */ +/*--------------------------------------------------------------*/ +VOID +wlanbowCmdEventSetCommon ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +wlanbowCmdEventLinkConnected ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +wlanbowCmdEventLinkDisconnected ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +wlanbowCmdEventSetSetupConnection ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +wlanbowCmdEventReadLinkQuality ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +wlanbowCmdEventReadRssi ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +wlanbowCmdTimeoutHandler ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo + ); + +VOID +bowStopping( + IN P_ADAPTER_T prAdapter); + +VOID +bowStarting ( + IN P_ADAPTER_T prAdapter + ); + +VOID +bowAssignSsid ( + IN PUINT_8 pucSsid, + IN PUINT_8 pucSsidLen + ); + +BOOLEAN +bowValidateProbeReq ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT PUINT_32 pu4ControlFlags + ); + +VOID +bowSendBeacon( + IN P_ADAPTER_T prAdapter, + UINT_32 u4Param + ); + +VOID +bowResponderScan( + IN P_ADAPTER_T prAdapter + ); + +VOID +bowResponderScanDone( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + +VOID +bowResponderCancelScan ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsChannelExtention + ); + +VOID +bowResponderJoin( + IN P_ADAPTER_T prAdapter, + P_BSS_DESC_T prBssDesc + ); + +VOID +bowFsmRunEventJoinComplete( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + +VOID +bowIndicationOfMediaStateToHost( + IN P_ADAPTER_T prAdapter, + ENUM_PARAM_MEDIA_STATE_T eConnectionState, + BOOLEAN fgDelayIndication + ); + +VOID +bowRunEventAAATxFail( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ); + +WLAN_STATUS +bowRunEventAAAComplete( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ); + +WLAN_STATUS +bowRunEventRxDeAuth ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prSwRfb + ); + +VOID +bowDisconnectLink ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus + ); + +BOOLEAN +bowValidateAssocReq( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT PUINT_16 pu2StatusCode + ); + +BOOLEAN +bowValidateAuth( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN PP_STA_RECORD_T pprStaRec, + OUT PUINT_16 pu2StatusCode + ); + +VOID +bowRunEventChGrant ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ); + +VOID +bowRequestCh ( + IN P_ADAPTER_T prAdapter + ); + +VOID +bowReleaseCh ( + IN P_ADAPTER_T prAdapter + ); + +VOID +bowChGrantedTimeout( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Param + ); + +BOOLEAN +bowNotifyAllLinkDisconnected ( + IN P_ADAPTER_T prAdapter + ); + +BOOLEAN +bowCheckBowTableIfVaild( + IN P_ADAPTER_T prAdapter, + IN UINT_8 aucPeerAddress[6] + ); + +BOOLEAN +bowGetBowTableContent( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucBowTableIdx, + OUT P_BOW_TABLE_T prBowTable + ); + +BOOLEAN +bowGetBowTableEntryByPeerAddress( + IN P_ADAPTER_T prAdapter, + IN UINT_8 aucPeerAddress[6], + OUT PUINT_8 pucBowTableIdx + ); + +BOOLEAN +bowGetBowTableFreeEntry( + IN P_ADAPTER_T prAdapter, + OUT PUINT_8 pucBowTableIdx + ); + +ENUM_BOW_DEVICE_STATE +bowGetBowTableState( + IN P_ADAPTER_T prAdapter, + IN UINT_8 aucPeerAddress[6] + ); + +BOOLEAN +bowSetBowTableState( + IN P_ADAPTER_T prAdapter, + IN UINT_8 aucPeerAddress[6], + IN ENUM_BOW_DEVICE_STATE eState + ); + + +BOOLEAN +bowSetBowTableContent( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucBowTableIdx, + IN P_BOW_TABLE_T prBowTable + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif +#endif /* _WLAN_BOW_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/wlan_lib.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/wlan_lib.h new file mode 100755 index 000000000000..40da9ddb3014 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/wlan_lib.h @@ -0,0 +1,987 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/wlan_lib.h#2 $ +*/ + +/*! \file "wlan_lib.h" + \brief The declaration of the functions of the wlanAdpater objects + + Detail description. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: wlan_lib.h $ + * + * 01 16 2012 cp.wu + * [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band configuration with corresponding network configuration + * add wlanSetPreferBandByNetwork() for glue layer to invoke for setting preferred band configuration corresponding to network type. + * + * 01 09 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Check in the Add Tx power Cmd to driver. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 08 02 2011 yuche.tsai + * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, TX deauth to a disconnecting device issue. + * Support TX Deauth while tearing down a station connection. + * + * 05 27 2011 cp.wu + * [WCXRP00000749] [MT6620 Wi-Fi][Driver] Add band edge tx power control to Wi-Fi NVRAM + * invoke CMD_ID_SET_EDGE_TXPWR_LIMIT when there is valid data exist in NVRAM content. + * + * 05 11 2011 cp.wu + * [WCXRP00000718] [MT6620 Wi-Fi] modify the behavior of setting tx power + * ACPI APIs migrate to wlan_lib.c for glue layer to invoke. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 10 2011 cp.wu + * [WCXRP00000532] [MT6620 Wi-Fi][Driver] Migrate NVRAM configuration procedures from MT6620 E2 to MT6620 E3 + * deprecate configuration used by MT6620 E2 + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 01 27 2011 george.huang + * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability + * Support current measure mode, assigned by registry (XP only). + * + * 01 24 2011 cp.wu + * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving + * 1. add an extra counter for tracking pending forward frames. + * 2. notify TX service thread as well when there is pending forward frame + * 3. correct build errors leaded by introduction of Wi-Fi direct separation module + * + * 01 10 2011 cp.wu + * [WCXRP00000351] [MT6620 Wi-Fi][Driver] remove from scanning result in OID handling layer when the corresponding BSS is disconnected due to beacon timeout + * remove from scanning result when the BSS is disconnected due to beacon timeout. + * + * 10 27 2010 george.huang + * [WCXRP00000127] [MT6620 Wi-Fi][Driver] Add a registry to disable Beacon Timeout function for SQA test by using E1 EVB + * Support registry option for disable beacon lost detection. + * + * 10 26 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command + * 1) update NVRAM content template to ver 1.02 + * 2) add compile option for querying NIC capability (default: off) + * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting + * 4) correct auto-rate compiler error under linux (treat warning as error) + * 5) simplify usage of NVRAM and REG_INFO_T + * 6) add version checking between driver and firmware + * + * 10 26 2010 eddie.chen + * [WCXRP00000134] [MT6620 Wi-Fi][Driver] Add a registry to enable auto rate for SQA test by using E1 EVB + * Add auto rate parameter in registry. + * + * 10 18 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android + * complete implementation of Android NVRAM access + * + * 10 08 2010 cp.wu + * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test + * adding fixed rate support for distance test. (from registry setting) + * + * 10 06 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * divide a single function into 2 part to surpress a weird compiler warning from gcc-4.4.0 + * + * 10 06 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * code reorganization to improve isolation between GLUE and CORE layers. + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * load manufacture data when CFG_SUPPORT_NVRAM is set to 1 + * + * 09 24 2010 cp.wu + * [WCXRP00000057] [MT6620 Wi-Fi][Driver] Modify online scan to a run-time switchable feature + * Modify online scan as a run-time adjustable option (for Windows, in registry) + * + * 09 23 2010 cp.wu + * [WCXRP00000051] [MT6620 Wi-Fi][Driver] WHQL test fail in MAC address changed item + * use firmware reported mac address right after wlanAdapterStart() as permanent address + * + * 09 23 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * add skeleton for NVRAM integration + * + * 08 26 2010 yuche.tsai + * NULL + * Add AT GO test configure mode under WinXP. + * Please enable 1. CFG_ENABLE_WIFI_DIRECT, 2. CFG_TEST_WIFI_DIRECT_GO, 3. CFG_SUPPORT_AAA + * + * 08 25 2010 george.huang + * NULL + * . + * + * 07 21 2010 cp.wu + * + * 1) change BG_SCAN to ONLINE_SCAN for consistent term + * 2) only clear scanning result when scan is permitted to do + * + * 07 13 2010 cp.wu + * + * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets + * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending + * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid descriptor underflow under concurrent network operation + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 24 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * change MAC address updating logic. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * simplify timer usage. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * cnm_timer has been migrated. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS + * 2) buffer statistics data for 2 seconds + * 3) use default value for adhoc parameters instead of 0 + * + * 05 12 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add extra 64 adjustable parameters for CoEX scenario. + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) for some OID, never do timeout expiration + * * 2) add 2 kal API for later integration + * + * 04 01 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * change to use WIFI_TCM_ALWAYS_ON as firmware image + * + * 03 31 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * modify the wapi related code for new driver's design. + * + * 03 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * always send CMD_NIC_POWER_CTRL packet when nic is being halted + * + * 03 12 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add two option for ACK and ENCRYPTION for firmware download + * + * 02 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * separate wlanProcesQueuePacket() into 2 APIs upon request + * + * 02 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add new API: wlanProcessQueuedPackets() + * + * 02 11 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. add logic for firmware download + * * * 2. firmware image filename and start/load address are now retrieved from registry + * + * 02 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c] + * * * * 2) firmware image length is now retrieved via NdisFileOpen + * * * * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore + * * * * 4) nicRxWaitResponse() revised + * * * * 5) another set of TQ counter default value is added for fw-download state + * * * * 6) Wi-Fi load address is now retrieved from registry too + * + * 02 08 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * prepare for implementing fw download logic + * + * 01 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. eliminate improper variable in rHifInfo + * * * * * * * 2. block TX/ordinary OID when RF test mode is engaged + * * * * * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode + * * * * * * * 4. correct some HAL implementation +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-12-10 16:39:55 GMT mtk02752 +** eliminate unused API +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-10-13 21:58:41 GMT mtk01084 +** update for new macro define +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-05-19 10:43:06 GMT mtk01461 +** Add wlanReleasePendingOid() +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-13 16:38:44 GMT mtk01084 +** add WIFI start function +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-08 16:51:14 GMT mtk01084 +** Update for the image download part +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-01 10:57:38 GMT mtk01461 +** Add wlanSendLeftClusteredFrames() for SDIO_TX_ENHANCE +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-23 00:31:02 GMT mtk01461 +** Add declaration of FW Image download reference code +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:08:31 GMT mtk01461 +** Update TX PATH API +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:12:04 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _WLAN_LIB_H +#define _WLAN_LIB_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "CFG_Wifi_File.h" +#include "rlm_domain.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define MAX_NUM_GROUP_ADDR 32 /* max number of group addresses */ + + + +#define TX_CS_TCP_UDP_GEN BIT(1) +#define TX_CS_IP_GEN BIT(0) + + +#define CSUM_OFFLOAD_EN_TX_TCP BIT(0) +#define CSUM_OFFLOAD_EN_TX_UDP BIT(1) +#define CSUM_OFFLOAD_EN_TX_IP BIT(2) +#define CSUM_OFFLOAD_EN_RX_TCP BIT(3) +#define CSUM_OFFLOAD_EN_RX_UDP BIT(4) +#define CSUM_OFFLOAD_EN_RX_IPv4 BIT(5) +#define CSUM_OFFLOAD_EN_RX_IPv6 BIT(6) +#define CSUM_OFFLOAD_EN_TX_MASK BITS(0,2) +#define CSUM_OFFLOAD_EN_ALL BITS(0,6) + +/* TCP, UDP, IP Checksum */ +#define RX_CS_TYPE_UDP BIT(7) +#define RX_CS_TYPE_TCP BIT(6) +#define RX_CS_TYPE_IPv6 BIT(5) +#define RX_CS_TYPE_IPv4 BIT(4) + +#define RX_CS_STATUS_UDP BIT(3) +#define RX_CS_STATUS_TCP BIT(2) +#define RX_CS_STATUS_IP BIT(0) + +#define CSUM_NOT_SUPPORTED 0x0 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef WLAN_STATUS (*PFN_OID_HANDLER_FUNC) ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvBuf, + IN UINT_32 u4BufLen, + OUT PUINT_32 pu4OutInfoLen + ); + +typedef enum _ENUM_CSUM_TYPE_T { + CSUM_TYPE_IPV4, + CSUM_TYPE_IPV6, + CSUM_TYPE_TCP, + CSUM_TYPE_UDP, + CSUM_TYPE_NUM +} ENUM_CSUM_TYPE_T, *P_ENUM_CSUM_TYPE_T; + +typedef enum _ENUM_CSUM_RESULT_T { + CSUM_RES_NONE, + CSUM_RES_SUCCESS, + CSUM_RES_FAILED, + CSUM_RES_NUM +} ENUM_CSUM_RESULT_T, *P_ENUM_CSUM_RESULT_T; + +typedef enum _ENUM_PHY_MODE_T { + ENUM_PHY_2G4_CCK, + ENUM_PHY_2G4_OFDM_BPSK, + ENUM_PHY_2G4_OFDM_QPSK, + ENUM_PHY_2G4_OFDM_16QAM, + ENUM_PHY_2G4_OFDM_48M, + ENUM_PHY_2G4_OFDM_54M, + ENUM_PHY_2G4_HT20_BPSK, + ENUM_PHY_2G4_HT20_QPSK, + ENUM_PHY_2G4_HT20_16QAM, + ENUM_PHY_2G4_HT20_MCS5, + ENUM_PHY_2G4_HT20_MCS6, + ENUM_PHY_2G4_HT20_MCS7, + ENUM_PHY_2G4_HT40_BPSK, + ENUM_PHY_2G4_HT40_QPSK, + ENUM_PHY_2G4_HT40_16QAM, + ENUM_PHY_2G4_HT40_MCS5, + ENUM_PHY_2G4_HT40_MCS6, + ENUM_PHY_2G4_HT40_MCS7, + ENUM_PHY_5G_OFDM_BPSK, + ENUM_PHY_5G_OFDM_QPSK, + ENUM_PHY_5G_OFDM_16QAM, + ENUM_PHY_5G_OFDM_48M, + ENUM_PHY_5G_OFDM_54M, + ENUM_PHY_5G_HT20_BPSK, + ENUM_PHY_5G_HT20_QPSK, + ENUM_PHY_5G_HT20_16QAM, + ENUM_PHY_5G_HT20_MCS5, + ENUM_PHY_5G_HT20_MCS6, + ENUM_PHY_5G_HT20_MCS7, + ENUM_PHY_5G_HT40_BPSK, + ENUM_PHY_5G_HT40_QPSK, + ENUM_PHY_5G_HT40_16QAM, + ENUM_PHY_5G_HT40_MCS5, + ENUM_PHY_5G_HT40_MCS6, + ENUM_PHY_5G_HT40_MCS7, + ENUM_PHY_MODE_NUM +} ENUM_PHY_MODE_T, *P_ENUM_PHY_MODE_T; + +typedef enum _ENUM_POWER_SAVE_POLL_MODE_T { + ENUM_POWER_SAVE_POLL_DISABLE, + ENUM_POWER_SAVE_POLL_LEGACY_NULL, + ENUM_POWER_SAVE_POLL_QOS_NULL, + ENUM_POWER_SAVE_POLL_NUM +} ENUM_POWER_SAVE_POLL_MODE_T, *P_ENUM_POWER_SAVE_POLL_MODE_T; + +typedef enum _ENUM_AC_TYPE_T { + ENUM_AC_TYPE_AC0, + ENUM_AC_TYPE_AC1, + ENUM_AC_TYPE_AC2, + ENUM_AC_TYPE_AC3, + ENUM_AC_TYPE_AC4, + ENUM_AC_TYPE_AC5, + ENUM_AC_TYPE_AC6, + ENUM_AC_TYPE_BMC, + ENUM_AC_TYPE_NUM +} ENUM_AC_TYPE_T, *P_ENUM_AC_TYPE_T; + +typedef enum _ENUM_ADV_AC_TYPE_T { + ENUM_ADV_AC_TYPE_RX_NSW, + ENUM_ADV_AC_TYPE_RX_PTA, + ENUM_ADV_AC_TYPE_RX_SP, + ENUM_ADV_AC_TYPE_TX_PTA, + ENUM_ADV_AC_TYPE_TX_RSP, + ENUM_ADV_AC_TYPE_NUM +} ENUM_ADV_AC_TYPE_T, *P_ENUM_ADV_AC_TYPE_T; + +typedef enum _ENUM_REG_CH_MAP_T { + REG_CH_MAP_COUNTRY_CODE, + REG_CH_MAP_TBL_IDX, + REG_CH_MAP_CUSTOMIZED, + REG_CH_MAP_NUM +} ENUM_REG_CH_MAP_T, *P_ENUM_REG_CH_MAP_T; + +typedef struct _SET_TXPWR_CTRL_T{ + INT_8 c2GLegacyStaPwrOffset; /* Unit: 0.5dBm, default: 0*/ + INT_8 c2GHotspotPwrOffset; + INT_8 c2GP2pPwrOffset; + INT_8 c2GBowPwrOffset; + INT_8 c5GLegacyStaPwrOffset; /* Unit: 0.5dBm, default: 0*/ + INT_8 c5GHotspotPwrOffset; + INT_8 c5GP2pPwrOffset; + INT_8 c5GBowPwrOffset; + UINT_8 ucConcurrencePolicy; /* TX power policy when concurrence + in the same channel + 0: Highest power has priority + 1: Lowest power has priority */ + INT_8 acReserved1[3]; /* Must be zero */ + + /* Power limit by channel for all data rates */ + INT_8 acTxPwrLimit2G[14]; /* Channel 1~14, Unit: 0.5dBm*/ + INT_8 acTxPwrLimit5G[4]; /* UNII 1~4 */ + INT_8 acReserved2[2]; /* Must be zero */ +} SET_TXPWR_CTRL_T, *P_SET_TXPWR_CTRL_T; + +/* For storing driver initialization value from glue layer */ +typedef struct _REG_INFO_T { + UINT_32 u4SdBlockSize; /* SDIO block size */ + UINT_32 u4SdBusWidth; /* SDIO bus width. 1 or 4 */ + UINT_32 u4SdClockRate; /* SDIO clock rate. (in unit of HZ) */ + UINT_32 u4StartAddress; /* Starting address of Wi-Fi Firmware */ + UINT_32 u4LoadAddress; /* Load address of Wi-Fi Firmware */ + UINT_16 aucFwImgFilename[65]; /* Firmware filename */ + UINT_16 aucFwImgFilenameE6[65]; /* Firmware filename for E6 */ + UINT_32 u4StartFreq; /* Start Frequency for Ad-Hoc network : in unit of KHz */ + UINT_32 u4AdhocMode; /* Default mode for Ad-Hoc network : ENUM_PARAM_AD_HOC_MODE_T */ + UINT_32 u4RddStartFreq; + UINT_32 u4RddStopFreq; + UINT_32 u4RddTestMode; + UINT_32 u4RddShutFreq; + UINT_32 u4RddDfs; + INT_32 i4HighRssiThreshold; + INT_32 i4MediumRssiThreshold; + INT_32 i4LowRssiThreshold; + INT_32 au4TxPriorityTag[ENUM_AC_TYPE_NUM]; + INT_32 au4RxPriorityTag[ENUM_AC_TYPE_NUM]; + INT_32 au4AdvPriorityTag[ENUM_ADV_AC_TYPE_NUM]; + UINT_32 u4FastPSPoll; + UINT_32 u4PTA; /* 0: disable, 1: enable */ + UINT_32 u4TXLimit; /* 0: disable, 1: enable */ + UINT_32 u4SilenceWindow; /* range: 100 - 625, unit: us */ + UINT_32 u4TXLimitThreshold; /* range: 250 - 1250, unit: us */ + UINT_32 u4PowerMode; + UINT_32 fgEnArpFilter; + UINT_32 u4PsCurrentMeasureEn; + UINT_32 u4UapsdAcBmp; + UINT_32 u4MaxSpLen; + UINT_32 fgDisOnlineScan; /* 0: enable online scan, non-zero: disable online scan*/ + UINT_32 fgDisBcnLostDetection; /* 0: enable online scan, non-zero: disable online scan*/ + UINT_32 u4FixedRate; /* 0: automatic, non-zero: fixed rate */ + UINT_32 u4ArSysParam0; + UINT_32 u4ArSysParam1; + UINT_32 u4ArSysParam2; + UINT_32 u4ArSysParam3; + UINT_32 fgDisRoaming; /* 0:enable roaming 1:disable */ + + // NVRAM - MP Data -START- + UINT_8 aucMacAddr[6]; + UINT_16 au2CountryCode[4]; /* Country code (in ISO 3166-1 expression, ex: "US", "TW") */ + TX_PWR_PARAM_T rTxPwr; + UINT_8 aucEFUSE[144]; + UINT_8 ucTxPwrValid; + UINT_8 ucSupport5GBand; + UINT_8 fg2G4BandEdgePwrUsed; + INT_8 cBandEdgeMaxPwrCCK; + INT_8 cBandEdgeMaxPwrOFDM20; + INT_8 cBandEdgeMaxPwrOFDM40; + ENUM_REG_CH_MAP_T eRegChannelListMap; + UINT_8 ucRegChannelListIndex; + DOMAIN_INFO_ENTRY rDomainInfo; + // NVRAM - MP Data -END- + + // NVRAM - Functional Data -START- + UINT_8 uc2G4BwFixed20M; + UINT_8 uc5GBwFixed20M; + UINT_8 ucEnable5GBand; + // NVRAM - Functional Data -END- + +} REG_INFO_T, *P_REG_INFO_T; + +/* for divided firmware loading */ +typedef struct _FWDL_SECTION_INFO_T +{ + UINT_32 u4Offset; + UINT_32 u4Reserved; + UINT_32 u4Length; + UINT_32 u4DestAddr; +} FWDL_SECTION_INFO_T, *P_FWDL_SECTION_INFO_T; + +typedef struct _FIRMWARE_DIVIDED_DOWNLOAD_T +{ + UINT_32 u4Signature; + UINT_32 u4CRC; /* CRC calculated without first 8 bytes included */ + UINT_32 u4NumOfEntries; + UINT_32 u4Reserved; + FWDL_SECTION_INFO_T arSection[]; +} FIRMWARE_DIVIDED_DOWNLOAD_T, *P_FIRMWARE_DIVIDED_DOWNLOAD_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define BUILD_SIGN(ch0, ch1, ch2, ch3) \ + ((UINT_32)(UINT_8)(ch0) | ((UINT_32)(UINT_8)(ch1) << 8) | \ + ((UINT_32)(UINT_8)(ch2) << 16) | ((UINT_32)(UINT_8)(ch3) << 24 )) + +#define MTK_WIFI_SIGNATURE BUILD_SIGN('M', 'T', 'K', 'W') + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +P_ADAPTER_T +wlanAdapterCreate ( + IN P_GLUE_INFO_T prGlueInfo + ); + +VOID +wlanAdapterDestroy ( + IN P_ADAPTER_T prAdapter + ); + +VOID +wlanCardEjected( + IN P_ADAPTER_T prAdapter + ); + +VOID +wlanIST ( + IN P_ADAPTER_T prAdapter + ); + +BOOL +wlanISR ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgGlobalIntrCtrl + ); + +WLAN_STATUS +wlanProcessCommandQueue ( + IN P_ADAPTER_T prAdapter, + IN P_QUE_T prCmdQue + ); + +WLAN_STATUS +wlanSendCommand ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo + ); + +VOID +wlanReleaseCommand ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo + ); + +VOID +wlanReleasePendingOid ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Data + ); + +VOID +wlanReleasePendingCMDbyNetwork( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType + ); + +VOID +wlanReturnPacket ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvPacket + ); + +WLAN_STATUS +wlanQueryInformation ( + IN P_ADAPTER_T prAdapter, + IN PFN_OID_HANDLER_FUNC pfOidQryHandler, + IN PVOID pvInfoBuf, + IN UINT_32 u4InfoBufLen, + OUT PUINT_32 pu4QryInfoLen + ); + +WLAN_STATUS +wlanSetInformation ( + IN P_ADAPTER_T prAdapter, + IN PFN_OID_HANDLER_FUNC pfOidSetHandler, + IN PVOID pvInfoBuf, + IN UINT_32 u4InfoBufLen, + OUT PUINT_32 pu4SetInfoLen + ); + + +WLAN_STATUS +wlanAdapterStart ( + IN P_ADAPTER_T prAdapter, + IN P_REG_INFO_T prRegInfo, + IN PVOID pvFwImageMapFile, + IN UINT_32 u4FwImageFileLength + ); + +WLAN_STATUS +wlanAdapterStop ( + IN P_ADAPTER_T prAdapter + ); + +#if CFG_SUPPORT_WAPI +BOOLEAN +wlanQueryWapiMode( + IN P_ADAPTER_T prAdapter + ); +#endif + +VOID +wlanReturnRxPacket ( + IN PVOID pvAdapter, + IN PVOID pvPacket + ); + +VOID +wlanRxSetBroadcast ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgEnableBroadcast + ); + +BOOLEAN +wlanIsHandlerNeedHwAccess ( + IN PFN_OID_HANDLER_FUNC pfnOidHandler, + IN BOOLEAN fgSetInfo + ); + +VOID +wlanSetPromiscuousMode ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgEnablePromiscuousMode + ); + +#if CFG_ENABLE_FW_DOWNLOAD + #if CFG_ENABLE_FW_DOWNLOAD_AGGREGATION +WLAN_STATUS +wlanImageSectionDownloadAggregated ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4DestAddr, + IN UINT_32 u4ImgSecSize, + IN PUINT_8 pucImgSecBuf + ); + #endif + +WLAN_STATUS +wlanImageSectionDownload ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4DestAddr, + IN UINT_32 u4ImgSecSize, + IN PUINT_8 pucImgSecBuf + ); + +#if !CFG_ENABLE_FW_DOWNLOAD_ACK +WLAN_STATUS +wlanImageQueryStatus( + IN P_ADAPTER_T prAdapter + ); +#else +WLAN_STATUS +wlanImageSectionDownloadStatus ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucCmdSeqNum + ); +#endif + +WLAN_STATUS +wlanConfigWifiFunc ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgEnable, + IN UINT_32 u4StartAddress + ); + +UINT_32 wlanCRC32( + PUINT_8 buf, + UINT_32 len + ); + +#endif + +WLAN_STATUS +wlanSendNicPowerCtrlCmd ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucPowerMode + ); + +BOOLEAN +wlanIsHandlerAllowedInRFTest ( + IN PFN_OID_HANDLER_FUNC pfnOidHandler, + IN BOOLEAN fgSetInfo + ); + +WLAN_STATUS +wlanProcessQueuedSwRfb ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfbListHead + ); + +WLAN_STATUS +wlanProcessQueuedMsduInfo ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfoListHead + ); + +BOOLEAN +wlanoidTimeoutCheck ( + IN P_ADAPTER_T prAdapter, + IN PFN_OID_HANDLER_FUNC pfnOidHandler + ); + +VOID +wlanoidClearTimeoutCheck ( + IN P_ADAPTER_T prAdapter + ); + +WLAN_STATUS +wlanUpdateNetworkAddress ( + IN P_ADAPTER_T prAdapter + ); + +BOOLEAN +wlanQueryTestMode( + IN P_ADAPTER_T prAdapter + ); + +/* Security Frame Handling */ +BOOLEAN +wlanProcessSecurityFrame( + IN P_ADAPTER_T prAdapter, + IN P_NATIVE_PACKET prPacket + ); + +VOID +wlanSecurityFrameTxDone( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); + +VOID +wlanSecurityFrameTxTimeout( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo + ); + +/*----------------------------------------------------------------------------*/ +/* OID/IOCTL Handling */ +/*----------------------------------------------------------------------------*/ +VOID +wlanClearScanningResult( + IN P_ADAPTER_T prAdapter + ); + +VOID +wlanClearBssInScanningResult( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 arBSSID + ); + +#if CFG_TEST_WIFI_DIRECT_GO +VOID +wlanEnableP2pFunction( + IN P_ADAPTER_T prAdapter + ); + +VOID +wlanEnableATGO( + IN P_ADAPTER_T prAdapter + ); +#endif + + +/*----------------------------------------------------------------------------*/ +/* Address Retreive by Polling */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanQueryPermanentAddress( + IN P_ADAPTER_T prAdapter + ); + + +/*----------------------------------------------------------------------------*/ +/* NIC Capability Retrieve by Polling */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanQueryNicCapability( + IN P_ADAPTER_T prAdapter + ); + + +/*----------------------------------------------------------------------------*/ +/* Loading Manufacture Data */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanLoadManufactureData ( + IN P_ADAPTER_T prAdapter, + IN P_REG_INFO_T prRegInfo + ); + + +/*----------------------------------------------------------------------------*/ +/* Media Stream Mode */ +/*----------------------------------------------------------------------------*/ +BOOLEAN +wlanResetMediaStreamMode( + IN P_ADAPTER_T prAdapter + ); + + +/*----------------------------------------------------------------------------*/ +/* Timer Timeout Check (for Glue Layer) */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanTimerTimeoutCheck( + IN P_ADAPTER_T prAdapter + ); + + +/*----------------------------------------------------------------------------*/ +/* Mailbox Message Check (for Glue Layer) */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanProcessMboxMessage( + IN P_ADAPTER_T prAdapter + ); + + +/*----------------------------------------------------------------------------*/ +/* TX Pending Packets Handling (for Glue Layer) */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanEnqueueTxPacket ( + IN P_ADAPTER_T prAdapter, + IN P_NATIVE_PACKET prNativePacket + ); + +WLAN_STATUS +wlanFlushTxPendingPackets( + IN P_ADAPTER_T prAdapter + ); + +WLAN_STATUS +wlanTxPendingPackets ( + IN P_ADAPTER_T prAdapter, + IN OUT PBOOLEAN pfgHwAccess + ); + + +/*----------------------------------------------------------------------------*/ +/* Low Power Acquire/Release (for Glue Layer) */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanAcquirePowerControl( + IN P_ADAPTER_T prAdapter + ); + +WLAN_STATUS +wlanReleasePowerControl( + IN P_ADAPTER_T prAdapter + ); + + +/*----------------------------------------------------------------------------*/ +/* Pending Packets Number Reporting (for Glue Layer) */ +/*----------------------------------------------------------------------------*/ +UINT_32 +wlanGetTxPendingFrameCount ( + IN P_ADAPTER_T prAdapter + ); + + +/*----------------------------------------------------------------------------*/ +/* ACPI state inquiry (for Glue Layer) */ +/*----------------------------------------------------------------------------*/ +ENUM_ACPI_STATE_T +wlanGetAcpiState ( + IN P_ADAPTER_T prAdapter + ); + +VOID +wlanSetAcpiState ( + IN P_ADAPTER_T prAdapter, + IN ENUM_ACPI_STATE_T ePowerState + ); + +#if CFG_SUPPORT_OSC_SETTING && defined(MT5931) +WLAN_STATUS +wlanSetMcuOscStableTime ( + IN P_ADAPTER_T prAdapter, + IN UINT_16 u2OscStableTime + ); +#endif + +VOID +wlanDefTxPowerCfg ( + IN P_ADAPTER_T prAdapter + ); + +/*----------------------------------------------------------------------------*/ +/* get ECO version from Revision ID register (for Win32) */ +/*----------------------------------------------------------------------------*/ +UINT_8 +wlanGetEcoVersion( + IN P_ADAPTER_T prAdapter + ); + +/*----------------------------------------------------------------------------*/ +/* set preferred band configuration corresponding to network type */ +/*----------------------------------------------------------------------------*/ +VOID +wlanSetPreferBandByNetwork ( + IN P_ADAPTER_T prAdapter, + IN ENUM_BAND_T eBand, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex + ); + +#endif /* _WLAN_LIB_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/include/wlan_oid.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/wlan_oid.h new file mode 100755 index 000000000000..88cc92d27f8b --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/include/wlan_oid.h @@ -0,0 +1,2058 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/include/wlan_oid.h#4 $ +*/ + +/*! \file "wlan_oid.h" + \brief This file contains the declairation file of the WLAN OID processing routines + of Windows driver for MediaTek Inc. 802.11 Wireless LAN Adapters. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: wlan_oid.h $ + * + * 01 19 2012 yuche.tsai + * NULL + * Fix RX filter issue for P2P network. + * + * 01 17 2012 yuche.tsai + * NULL + * Update mgmt frame filter setting. + * Please also update FW 2.1 + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Hot Spot Tethering for ICS ALPHA testing version. + * + * 01 09 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Check in the Add Tx power Cmd to driver. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 03 22 2011 george.huang + * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command + * link with supplicant commands + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 03 02 2011 george.huang + * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command + * Support UAPSD/OppPS/NoA parameter setting + * + * 01 20 2011 eddie.chen + * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control + * Add Oid for sw control debug command + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 10 18 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android + * complete implementation of Android NVRAM access + * + * 10 08 2010 cp.wu + * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test + * adding fixed rate support for distance test. (from registry setting) + * + * 09 23 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * add skeleton for NVRAM integration + * + * 09 08 2010 cp.wu + * NULL + * use static memory pool for storing IEs of scanning result. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 29 2010 yuche.tsai + * NULL + * Finish SLT TX/RX & Rate Changing Support. + * + * 08 04 2010 cp.wu + * NULL + * revert changelist #15371, efuse read/write access will be done by RF test approach + * + * 08 04 2010 cp.wu + * NULL + * add OID definitions for EFUSE read/write access. + * + * 08 04 2010 yarco.yang + * NULL + * Add TX_AMPDU and ADDBA_REJECT command + * + * 08 02 2010 george.huang + * NULL + * add WMM-PS test related OID/ CMD handlers + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add command warpper for STA-REC/BSS-INFO sync. + * 2) enhance command packet sending procedure for non-oid part + * 3) add command packet definitions for STA-REC/BSS-INFO sync. + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration from MT6620 firmware. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge wlan_def.h. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge wifi_var.h, precomp.h, cnm_timer.h (data type only) + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 06 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * move timer callback to glue layer. + * + * 05 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS + * 2) buffer statistics data for 2 seconds + * 3) use default value for adhoc parameters instead of 0 + * + * 05 18 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement Wakeup-on-LAN except firmware integration part + * + * 05 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * MT6620 is not supporting NDIS_PACKET_TYPE_PROMISCUOUS. + * + + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * 1) add timeout handler mechanism for pending command packets + * 2) add p2p add/removal key + * + * 05 13 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add NULL OID implementation for WOL-related OIDs. + * + * 04 22 2010 cp.wu + * [WPD00003830]add OID_802_11_PRIVACY_FILTER support + * enable RX filter OID + * + * 04 14 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * information buffer for query oid/ioctl is now buffered in prCmdInfo + * * * * * instead of glue-layer variable to improve multiple oid/ioctl capability + * + * 03 31 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * modify the wapi related code for new driver's design. + * + * 03 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * indicate media stream mode after set is done + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port + * + * 03 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement custom OID: EEPROM read/write access + * + * 02 09 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address + * * * * * * 2. follow MSDN defined behavior when associates to another AP + * * * * * * 3. for firmware download, packet size could be up to 2048 bytes + * + * 01 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) implement timeout mechanism when OID is pending for longer than 1 second + * * * 2) allow OID_802_11_CONFIGURATION to be executed when RF test mode is turned on + * + * 01 27 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * . + * + * 01 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement following 802.11 OIDs: + * * * * OID_802_11_RSSI, + * * * * OID_802_11_RSSI_TRIGGER, + * * * * OID_802_11_STATISTICS, + * * * * OID_802_11_DISASSOCIATE, + * * * * OID_802_11_POWER_MODE + * + * 01 21 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement OID_802_11_MEDIA_STREAM_MODE + * + * 01 21 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement OID_802_11_SUPPORTED_RATES / OID_802_11_DESIRED_RATES +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-12-08 11:38:11 GMT mtk02752 +** add declares for RF test related APIs +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-11-24 22:41:53 GMT mtk02752 +** remove u4SysTime, MSDN 10-second will be implemented in FW side +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-11-23 20:30:13 GMT mtk02752 +** add u4SysTime field in PARAM_BSSID_EX_T +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-11-12 19:48:35 GMT mtk02752 +** allow upper layer to set a packet filter with PROMISCUOUS mode +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:12:12 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _WLAN_OID_H +#define _WLAN_OID_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define PARAM_MAX_LEN_SSID 32 + +#define PARAM_MAC_ADDR_LEN 6 + +#define ETHERNET_HEADER_SZ 14 +#define ETHERNET_MIN_PKT_SZ 60 +#define ETHERNET_MAX_PKT_SZ 1514 + +#define PARAM_MAX_LEN_RATES 8 +#define PARAM_MAX_LEN_RATES_EX 16 + +#define PARAM_AUTH_REQUEST_REAUTH 0x01 +#define PARAM_AUTH_REQUEST_KEYUPDATE 0x02 +#define PARAM_AUTH_REQUEST_PAIRWISE_ERROR 0x06 +#define PARAM_AUTH_REQUEST_GROUP_ERROR 0x0E + +#define PARAM_EEPROM_READ_METHOD_READ 1 +#define PARAM_EEPROM_READ_METHOD_GETSIZE 0 + +#define PARAM_WHQL_RSSI_MAX_DBM (-10) +#define PARAM_WHQL_RSSI_MIN_DBM (-200) + +#define PARAM_DEVICE_WAKE_UP_ENABLE 0x00000001 +#define PARAM_DEVICE_WAKE_ON_PATTERN_MATCH_ENABLE 0x00000002 +#define PARAM_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE 0x00000004 + +#define PARAM_WAKE_UP_MAGIC_PACKET 0x00000001 +#define PARAM_WAKE_UP_PATTERN_MATCH 0x00000002 +#define PARAM_WAKE_UP_LINK_CHANGE 0x00000004 + + +/* Packet filter bit definitioin (UINT_32 bit-wise definition) */ +#define PARAM_PACKET_FILTER_DIRECTED 0x00000001 +#define PARAM_PACKET_FILTER_MULTICAST 0x00000002 +#define PARAM_PACKET_FILTER_ALL_MULTICAST 0x00000004 +#define PARAM_PACKET_FILTER_BROADCAST 0x00000008 +#define PARAM_PACKET_FILTER_PROMISCUOUS 0x00000020 +#define PARAM_PACKET_FILTER_ALL_LOCAL 0x00000080 +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 +#define PARAM_PACKET_FILTER_P2P_MASK 0xC0000000 +#define PARAM_PACKET_FILTER_PROBE_REQ 0x80000000 +#define PARAM_PACKET_FILTER_ACTION_FRAME 0x40000000 +#endif + +#if CFG_SLT_SUPPORT +#define PARAM_PACKET_FILTER_SUPPORTED (PARAM_PACKET_FILTER_DIRECTED | \ + PARAM_PACKET_FILTER_MULTICAST | \ + PARAM_PACKET_FILTER_BROADCAST | \ + PARAM_PACKET_FILTER_ALL_MULTICAST) +#else +#define PARAM_PACKET_FILTER_SUPPORTED (PARAM_PACKET_FILTER_DIRECTED | \ + PARAM_PACKET_FILTER_MULTICAST | \ + PARAM_PACKET_FILTER_BROADCAST) +#endif + + +#define BT_PROFILE_PARAM_LEN 8 +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Parameters of User Configuration which match to NDIS5.1 */ +/*----------------------------------------------------------------------------*/ +/* NDIS_802_11_AUTHENTICATION_MODE */ +typedef enum _ENUM_PARAM_AUTH_MODE_T +{ + AUTH_MODE_OPEN, /*!< Open system */ + AUTH_MODE_SHARED, /*!< Shared key */ + AUTH_MODE_AUTO_SWITCH, /*!< Either open system or shared key */ + AUTH_MODE_WPA, + AUTH_MODE_WPA_PSK, + AUTH_MODE_WPA_NONE, /*!< For Ad hoc */ + AUTH_MODE_WPA2, + AUTH_MODE_WPA2_PSK, + AUTH_MODE_NUM /*!< Upper bound, not real case */ +} ENUM_PARAM_AUTH_MODE_T, *P_ENUM_PARAM_AUTH_MODE_T; + +/* NDIS_802_11_ENCRYPTION_STATUS *//* Encryption types */ +typedef enum _ENUM_WEP_STATUS_T +{ + ENUM_WEP_ENABLED, + ENUM_ENCRYPTION1_ENABLED = ENUM_WEP_ENABLED, + ENUM_WEP_DISABLED, + ENUM_ENCRYPTION_DISABLED = ENUM_WEP_DISABLED, + ENUM_WEP_KEY_ABSENT, + ENUM_ENCRYPTION1_KEY_ABSENT = ENUM_WEP_KEY_ABSENT, + ENUM_WEP_NOT_SUPPORTED, + ENUM_ENCRYPTION_NOT_SUPPORTED = ENUM_WEP_NOT_SUPPORTED, + ENUM_ENCRYPTION2_ENABLED, + ENUM_ENCRYPTION2_KEY_ABSENT, + ENUM_ENCRYPTION3_ENABLED, + ENUM_ENCRYPTION3_KEY_ABSENT +} ENUM_PARAM_ENCRYPTION_STATUS_T, *P_ENUM_PARAM_ENCRYPTION_STATUS_T; + + + +typedef UINT_8 PARAM_MAC_ADDRESS[PARAM_MAC_ADDR_LEN]; + +typedef UINT_32 PARAM_KEY_INDEX; +typedef UINT_64 PARAM_KEY_RSC; +typedef INT_32 PARAM_RSSI; + +typedef UINT_32 PARAM_FRAGMENTATION_THRESHOLD; +typedef UINT_32 PARAM_RTS_THRESHOLD; + +typedef UINT_8 PARAM_RATES[PARAM_MAX_LEN_RATES]; +typedef UINT_8 PARAM_RATES_EX[PARAM_MAX_LEN_RATES_EX]; + +typedef enum _ENUM_PARAM_PHY_TYPE_T { + PHY_TYPE_802_11ABG = 0, /*!< Can associated with 802.11abg AP, Scan dual band. */ + PHY_TYPE_802_11BG, /*!< Can associated with 802_11bg AP, Scan single band and not report 802_11a BSSs. */ + PHY_TYPE_802_11G, /*!< Can associated with 802_11g only AP, Scan single band and not report 802_11ab BSSs. */ + PHY_TYPE_802_11A, /*!< Can associated with 802_11a only AP, Scan single band and not report 802_11bg BSSs. */ + PHY_TYPE_802_11B, /*!< Can associated with 802_11b only AP, Scan single band and not report 802_11ag BSSs. */ + PHY_TYPE_NUM // 5 +} ENUM_PARAM_PHY_TYPE_T, *P_ENUM_PARAM_PHY_TYPE_T; + +typedef enum _ENUM_PARAM_OP_MODE_T { + NET_TYPE_IBSS = 0, /*!< Try to merge/establish an AdHoc, do periodic SCAN for merging. */ + NET_TYPE_INFRA, /*!< Try to join an Infrastructure, do periodic SCAN for joining. */ + NET_TYPE_AUTO_SWITCH, /*!< Try to join an Infrastructure, if fail then try to merge or + establish an AdHoc, do periodic SCAN for joining or merging. */ + NET_TYPE_DEDICATED_IBSS, /*!< Try to merge an AdHoc first, if fail then establish AdHoc permanently, no more SCAN. */ + NET_TYPE_NUM // 4 +} ENUM_PARAM_OP_MODE_T, *P_ENUM_PARAM_OP_MODE_T; + +typedef struct _PARAM_SSID_T { + UINT_32 u4SsidLen; /*!< SSID length in bytes. Zero length is broadcast(any) SSID */ + UINT_8 aucSsid[PARAM_MAX_LEN_SSID]; +} PARAM_SSID_T, *P_PARAM_SSID_T; + +/* This is enum defined for user to select an AdHoc Mode */ +typedef enum _ENUM_PARAM_AD_HOC_MODE_T { + AD_HOC_MODE_11B = 0, /*!< Create 11b IBSS if we support 802.11abg/802.11bg. */ + AD_HOC_MODE_MIXED_11BG, /*!< Create 11bg mixed IBSS if we support 802.11abg/802.11bg/802.11g. */ + AD_HOC_MODE_11G, /*!< Create 11g only IBSS if we support 802.11abg/802.11bg/802.11g. */ + AD_HOC_MODE_11A, /*!< Create 11a only IBSS if we support 802.11abg. */ + AD_HOC_MODE_NUM // 4 +} ENUM_PARAM_AD_HOC_MODE_T, *P_ENUM_PARAM_AD_HOC_MODE_T; + + +typedef enum _ENUM_PARAM_MEDIA_STATE_T { + PARAM_MEDIA_STATE_CONNECTED, + PARAM_MEDIA_STATE_DISCONNECTED, + PARAM_MEDIA_STATE_TO_BE_INDICATED // for following MSDN re-association behavior +} ENUM_PARAM_MEDIA_STATE_T, *P_ENUM_PARAM_MEDIA_STATE_T; + + +typedef enum _ENUM_PARAM_NETWORK_TYPE_T { + PARAM_NETWORK_TYPE_FH, + PARAM_NETWORK_TYPE_DS, + PARAM_NETWORK_TYPE_OFDM5, + PARAM_NETWORK_TYPE_OFDM24, + PARAM_NETWORK_TYPE_AUTOMODE, + PARAM_NETWORK_TYPE_NUM /*!< Upper bound, not real case */ +} ENUM_PARAM_NETWORK_TYPE_T, *P_ENUM_PARAM_NETWORK_TYPE_T; + + +typedef struct _PARAM_NETWORK_TYPE_LIST { + UINT_32 NumberOfItems; /*!< At least 1 */ + ENUM_PARAM_NETWORK_TYPE_T eNetworkType [1]; +} PARAM_NETWORK_TYPE_LIST, *PPARAM_NETWORK_TYPE_LIST; + +typedef enum _ENUM_PARAM_PRIVACY_FILTER_T +{ + PRIVACY_FILTER_ACCEPT_ALL, + PRIVACY_FILTER_8021xWEP, + PRIVACY_FILTER_NUM +} ENUM_PARAM_PRIVACY_FILTER_T, *P_ENUM_PARAM_PRIVACY_FILTER_T; + +typedef enum _ENUM_RELOAD_DEFAULTS +{ + ENUM_RELOAD_WEP_KEYS +} PARAM_RELOAD_DEFAULTS, *P_PARAM_RELOAD_DEFAULTS; + +typedef struct _PARAM_PM_PACKET_PATTERN +{ + UINT_32 Priority; // Importance of the given pattern. + UINT_32 Reserved; // Context information for transports. + UINT_32 MaskSize; // Size in bytes of the pattern mask. + UINT_32 PatternOffset; // Offset from beginning of this + // structure to the pattern bytes. + UINT_32 PatternSize; // Size in bytes of the pattern. + UINT_32 PatternFlags; // Flags (TBD). +} PARAM_PM_PACKET_PATTERN, *P_PARAM_PM_PACKET_PATTERN; + +/*--------------------------------------------------------------*/ +/*! \brief Struct definition to indicate specific event. */ +/*--------------------------------------------------------------*/ +typedef enum _ENUM_STATUS_TYPE_T +{ + ENUM_STATUS_TYPE_AUTHENTICATION, + ENUM_STATUS_TYPE_MEDIA_STREAM_MODE, + ENUM_STATUS_TYPE_CANDIDATE_LIST, + ENUM_STATUS_TYPE_NUM /*!< Upper bound, not real case */ +} ENUM_STATUS_TYPE_T, *P_ENUM_STATUS_TYPE_T; + + +typedef struct _PARAM_802_11_CONFIG_FH_T { + UINT_32 u4Length; /*!< Length of structure */ + UINT_32 u4HopPattern; /*!< Defined as 802.11 */ + UINT_32 u4HopSet; /*!< to one if non-802.11 */ + UINT_32 u4DwellTime; /*!< In unit of Kusec */ +} PARAM_802_11_CONFIG_FH_T, *P_PARAM_802_11_CONFIG_FH_T; + +typedef struct _PARAM_802_11_CONFIG_T { + UINT_32 u4Length; /*!< Length of structure */ + UINT_32 u4BeaconPeriod; /*!< In unit of Kusec */ + UINT_32 u4ATIMWindow; /*!< In unit of Kusec */ + UINT_32 u4DSConfig; /*!< Channel frequency in unit of kHz */ + PARAM_802_11_CONFIG_FH_T rFHConfig; +} PARAM_802_11_CONFIG_T, *P_PARAM_802_11_CONFIG_T; + +typedef struct _PARAM_STATUS_INDICATION_T +{ + ENUM_STATUS_TYPE_T eStatusType; +} PARAM_STATUS_INDICATION_T, *P_PARAM_STATUS_INDICATION_T; + +typedef struct _PARAM_AUTH_REQUEST_T +{ + UINT_32 u4Length; /*!< Length of this struct */ + PARAM_MAC_ADDRESS arBssid; + UINT_32 u4Flags; /*!< Definitions are as follows */ +} PARAM_AUTH_REQUEST_T, *P_PARAM_AUTH_REQUEST_T; + +typedef struct _PARAM_AUTH_EVENT_T +{ + PARAM_STATUS_INDICATION_T rStatus; + PARAM_AUTH_REQUEST_T arRequest[1]; +} PARAM_AUTH_EVENT_T, *P_PARAM_AUTH_EVENT_T; + +/*! \brief Capabilities, privacy, rssi and IEs of each BSSID */ +typedef struct _PARAM_BSSID_EX_T { + UINT_32 u4Length; /*!< Length of structure */ + PARAM_MAC_ADDRESS arMacAddress; /*!< BSSID */ + UINT_8 Reserved[2]; + PARAM_SSID_T rSsid; /*!< SSID */ + UINT_32 u4Privacy; /*!< Need WEP encryption */ + PARAM_RSSI rRssi; /*!< in dBm */ + ENUM_PARAM_NETWORK_TYPE_T eNetworkTypeInUse; + PARAM_802_11_CONFIG_T rConfiguration; + ENUM_PARAM_OP_MODE_T eOpMode; + PARAM_RATES_EX rSupportedRates; + UINT_32 u4IELength; + UINT_8 aucIEs[1]; +} PARAM_BSSID_EX_T, *P_PARAM_BSSID_EX_T; + +typedef struct _PARAM_BSSID_LIST_EX { + UINT_32 u4NumberOfItems; /*!< at least 1 */ + PARAM_BSSID_EX_T arBssid[1]; +} PARAM_BSSID_LIST_EX_T, *P_PARAM_BSSID_LIST_EX_T; + + +typedef struct _PARAM_WEP_T +{ + UINT_32 u4Length; /*!< Length of structure */ + UINT_32 u4KeyIndex; /*!< 0: pairwise key, others group keys */ + UINT_32 u4KeyLength; /*!< Key length in bytes */ + UINT_8 aucKeyMaterial[1]; /*!< Key content by above setting */ +} PARAM_WEP_T, *P_PARAM_WEP_T; + +/*! \brief Key mapping of BSSID */ +typedef struct _PARAM_KEY_T +{ + UINT_32 u4Length; /*!< Length of structure */ + UINT_32 u4KeyIndex; /*!< KeyID */ + UINT_32 u4KeyLength; /*!< Key length in bytes */ + PARAM_MAC_ADDRESS arBSSID; /*!< MAC address */ + PARAM_KEY_RSC rKeyRSC; + UINT_8 aucKeyMaterial[1]; /*!< Key content by above setting */ +} PARAM_KEY_T, *P_PARAM_KEY_T; + +typedef struct _PARAM_REMOVE_KEY_T +{ + UINT_32 u4Length; /*!< Length of structure */ + UINT_32 u4KeyIndex; /*!< KeyID */ + PARAM_MAC_ADDRESS arBSSID; /*!< MAC address */ +} PARAM_REMOVE_KEY_T, *P_PARAM_REMOVE_KEY_T; + +#if CFG_SUPPORT_WAPI +typedef enum _ENUM_KEY_TYPE { + ENUM_WPI_PAIRWISE_KEY = 0, + ENUM_WPI_GROUP_KEY +} ENUM_KEY_TYPE; + +typedef enum _ENUM_WPI_PROTECT_TYPE +{ + ENUM_WPI_NONE, + ENUM_WPI_RX, + ENUM_WPI_TX, + ENUM_WPI_RX_TX +} ENUM_WPI_PROTECT_TYPE; + +typedef struct _PARAM_WPI_KEY_T { + ENUM_KEY_TYPE eKeyType; + ENUM_WPI_PROTECT_TYPE eDirection; + UINT_8 ucKeyID; + UINT_8 aucRsv[3]; + UINT_8 aucAddrIndex[12]; + UINT_32 u4LenWPIEK; + UINT_8 aucWPIEK[256]; + UINT_32 u4LenWPICK; + UINT_8 aucWPICK[256]; + UINT_8 aucPN[16]; +} PARAM_WPI_KEY_T, *P_PARAM_WPI_KEY_T; +#endif + + +typedef enum _PARAM_POWER_MODE +{ + Param_PowerModeCAM, + Param_PowerModeMAX_PSP, + Param_PowerModeFast_PSP, + Param_PowerModeMax /* Upper bound, not real case */ +} PARAM_POWER_MODE, *PPARAM_POWER_MODE; + +typedef enum _PARAM_DEVICE_POWER_STATE +{ + ParamDeviceStateUnspecified = 0, + ParamDeviceStateD0, + ParamDeviceStateD1, + ParamDeviceStateD2, + ParamDeviceStateD3, + ParamDeviceStateMaximum +} PARAM_DEVICE_POWER_STATE, *PPARAM_DEVICE_POWER_STATE; + +#if CFG_SUPPORT_802_11D + +/*! \brief The enumeration definitions for OID_IPN_MULTI_DOMAIN_CAPABILITY */ +typedef enum _PARAM_MULTI_DOMAIN_CAPABILITY { + ParamMultiDomainCapDisabled, + ParamMultiDomainCapEnabled +} PARAM_MULTI_DOMAIN_CAPABILITY, *P_PARAM_MULTI_DOMAIN_CAPABILITY; +#endif + +typedef struct _COUNTRY_STRING_ENTRY { + UINT_8 aucCountryCode[2]; + UINT_8 aucEnvironmentCode[2]; +} COUNTRY_STRING_ENTRY, *P_COUNTRY_STRING_ENTRY; + +/* Power management related definition and enumerations */ +#define UAPSD_NONE 0 +#define UAPSD_AC0 (BIT(0) | BIT(4)) +#define UAPSD_AC1 (BIT(1) | BIT(5)) +#define UAPSD_AC2 (BIT(2) | BIT(6)) +#define UAPSD_AC3 (BIT(3) | BIT(7)) +#define UAPSD_ALL (UAPSD_AC0 | UAPSD_AC1 | UAPSD_AC2 | UAPSD_AC3) + +typedef enum _ENUM_POWER_SAVE_PROFILE_T +{ + ENUM_PSP_CONTINUOUS_ACTIVE = 0, + ENUM_PSP_CONTINUOUS_POWER_SAVE, + ENUM_PSP_FAST_SWITCH, + ENUM_PSP_NUM +} ENUM_POWER_SAVE_PROFILE_T, *PENUM_POWER_SAVE_PROFILE_T; + + +/*--------------------------------------------------------------*/ +/*! \brief Set/Query testing type. */ +/*--------------------------------------------------------------*/ +typedef struct _PARAM_802_11_TEST_T +{ + UINT_32 u4Length; + UINT_32 u4Type; + union + { + PARAM_AUTH_EVENT_T AuthenticationEvent; + PARAM_RSSI RssiTrigger; + } u; +} PARAM_802_11_TEST_T, *P_PARAM_802_11_TEST_T; + + + +/*--------------------------------------------------------------*/ +/*! \brief Set/Query authentication and encryption capability. */ +/*--------------------------------------------------------------*/ +typedef struct _PARAM_AUTH_ENCRYPTION_T +{ + ENUM_PARAM_AUTH_MODE_T eAuthModeSupported; + ENUM_PARAM_ENCRYPTION_STATUS_T eEncryptStatusSupported; +} PARAM_AUTH_ENCRYPTION_T, *P_PARAM_AUTH_ENCRYPTION_T; + +typedef struct _PARAM_CAPABILITY_T +{ + UINT_32 u4Length; + UINT_32 u4Version; + UINT_32 u4NoOfPMKIDs; + UINT_32 u4NoOfAuthEncryptPairsSupported; + PARAM_AUTH_ENCRYPTION_T arAuthenticationEncryptionSupported[1]; +} PARAM_CAPABILITY_T, *P_PARAM_CAPABILITY_T; + +typedef UINT_8 PARAM_PMKID_VALUE[16]; + +typedef struct _PARAM_BSSID_INFO_T +{ + PARAM_MAC_ADDRESS arBSSID; + PARAM_PMKID_VALUE arPMKID; +} PARAM_BSSID_INFO_T, *P_PARAM_BSSID_INFO_T; + +typedef struct _PARAM_PMKID_T +{ + UINT_32 u4Length; + UINT_32 u4BSSIDInfoCount; + PARAM_BSSID_INFO_T arBSSIDInfo[1]; +} PARAM_PMKID_T, *P_PARAM_PMKID_T; + +/*! \brief PMKID candidate lists. */ +typedef struct _PARAM_PMKID_CANDIDATE_T { + PARAM_MAC_ADDRESS arBSSID; + UINT_32 u4Flags; +} PARAM_PMKID_CANDIDATE_T, *P_PARAM_PMKID_CANDIDATE_T; + +//#ifdef LINUX +typedef struct _PARAM_PMKID_CANDIDATE_LIST_T +{ + UINT_32 u4Version; /*!< Version */ + UINT_32 u4NumCandidates; /*!< How many candidates follow */ + PARAM_PMKID_CANDIDATE_T arCandidateList[1]; +} PARAM_PMKID_CANDIDATE_LIST_T, *P_PARAM_PMKID_CANDIDATE_LIST_T; +//#endif + +typedef struct _PARAM_CUSTOM_MCR_RW_STRUC_T { + UINT_32 u4McrOffset; + UINT_32 u4McrData; +} PARAM_CUSTOM_MCR_RW_STRUC_T, *P_PARAM_CUSTOM_MCR_RW_STRUC_T; + + +typedef struct _PARAM_CUSTOM_SW_CTRL_STRUC_T { + UINT_32 u4Id; + UINT_32 u4Data; +} PARAM_CUSTOM_SW_CTRL_STRUC_T, *P_PARAM_CUSTOM_SW_CTRL_STRUC_T; + + +typedef struct _PARAM_CUSTOM_EEPROM_RW_STRUC_T { + UINT_8 ucEepromMethod; /* For read only read: 1, query size: 0*/ + UINT_8 ucEepromIndex; + UINT_8 reserved; + UINT_16 u2EepromData; +} PARAM_CUSTOM_EEPROM_RW_STRUC_T, *P_PARAM_CUSTOM_EEPROM_RW_STRUC_T, + PARAM_CUSTOM_NVRAM_RW_STRUCT_T, *P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T; + +typedef struct _PARAM_CUSTOM_WMM_PS_TEST_STRUC_T { + UINT_8 bmfgApsdEnAc; /* b0~3: trigger-en AC0~3. b4~7: delivery-en AC0~3 */ + UINT_8 ucIsEnterPsAtOnce; /* enter PS immediately without 5 second guard after connected */ + UINT_8 ucIsDisableUcTrigger; /* not to trigger UC on beacon TIM is matched (under U-APSD) */ + UINT_8 reserved; +} PARAM_CUSTOM_WMM_PS_TEST_STRUC_T, *P_PARAM_CUSTOM_WMM_PS_TEST_STRUC_T; + +typedef struct _PARAM_CUSTOM_NOA_PARAM_STRUC_T { + UINT_32 u4NoaDurationMs; + UINT_32 u4NoaIntervalMs; + UINT_32 u4NoaCount; +} PARAM_CUSTOM_NOA_PARAM_STRUC_T, *P_PARAM_CUSTOM_NOA_PARAM_STRUC_T; + +typedef struct _PARAM_CUSTOM_OPPPS_PARAM_STRUC_T { + UINT_32 u4CTwindowMs; +} PARAM_CUSTOM_OPPPS_PARAM_STRUC_T, *P_PARAM_CUSTOM_OPPPS_PARAM_STRUC_T; + +typedef struct _PARAM_CUSTOM_UAPSD_PARAM_STRUC_T { + UINT_8 fgEnAPSD; + UINT_8 fgEnAPSD_AcBe; + UINT_8 fgEnAPSD_AcBk; + UINT_8 fgEnAPSD_AcVo; + UINT_8 fgEnAPSD_AcVi; + UINT_8 ucMaxSpLen; + UINT_8 aucResv[2]; +} PARAM_CUSTOM_UAPSD_PARAM_STRUC_T, *P_PARAM_CUSTOM_UAPSD_PARAM_STRUC_T; + +typedef enum _ENUM_CFG_SRC_TYPE_T { + CFG_SRC_TYPE_EEPROM, + CFG_SRC_TYPE_NVRAM, + CFG_SRC_TYPE_UNKNOWN, + CFG_SRC_TYPE_NUM +} ENUM_CFG_SRC_TYPE_T, *P_ENUM_CFG_SRC_TYPE_T; + +typedef enum _ENUM_EEPROM_TYPE_T { + EEPROM_TYPE_NO, + EEPROM_TYPE_PRESENT, + EEPROM_TYPE_NUM +} ENUM_EEPROM_TYPE_T, *P_ENUM_EEPROM_TYPE_T; + +typedef struct _PARAM_QOS_TSINFO { + UINT_8 ucTrafficType; /* Traffic Type: 1 for isochronous 0 for asynchronous */ + UINT_8 ucTid; /* TSID: must be between 8 ~ 15 */ + UINT_8 ucDirection; /* direction */ + UINT_8 ucAccessPolicy; /* access policy */ + UINT_8 ucAggregation; /* aggregation */ + UINT_8 ucApsd; /* APSD */ + UINT_8 ucuserPriority; /* user priority */ + UINT_8 ucTsInfoAckPolicy; /* TSINFO ACK policy */ + UINT_8 ucSchedule; /* Schedule */ +} PARAM_QOS_TSINFO, *P_PARAM_QOS_TSINFO; + +typedef struct _PARAM_QOS_TSPEC { + PARAM_QOS_TSINFO rTsInfo; /* TS info field */ + UINT_16 u2NominalMSDUSize; /* nominal MSDU size */ + UINT_16 u2MaxMSDUsize; /* maximum MSDU size */ + UINT_32 u4MinSvcIntv; /* minimum service interval */ + UINT_32 u4MaxSvcIntv; /* maximum service interval */ + UINT_32 u4InactIntv; /* inactivity interval */ + UINT_32 u4SpsIntv; /* suspension interval */ + UINT_32 u4SvcStartTime; /* service start time */ + UINT_32 u4MinDataRate; /* minimum Data rate */ + UINT_32 u4MeanDataRate; /* mean data rate */ + UINT_32 u4PeakDataRate; /* peak data rate */ + UINT_32 u4MaxBurstSize; /* maximum burst size */ + UINT_32 u4DelayBound; /* delay bound */ + UINT_32 u4MinPHYRate; /* minimum PHY rate */ + UINT_16 u2Sba; /* surplus bandwidth allowance */ + UINT_16 u2MediumTime; /* medium time */ +} PARAM_QOS_TSPEC, *P_PARAM_QOS_TSPEC; + +typedef struct _PARAM_QOS_ADDTS_REQ_INFO { + PARAM_QOS_TSPEC rTspec; +} PARAM_QOS_ADDTS_REQ_INFO, *P_PARAM_QOS_ADDTS_REQ_INFO; + +typedef struct _PARAM_VOIP_CONFIG { + UINT_32 u4VoipTrafficInterval; /* 0: disable VOIP configuration */ +} PARAM_VOIP_CONFIG, *P_PARAM_VOIP_CONFIG; + +/*802.11 Statistics Struct*/ +typedef struct _PARAM_802_11_STATISTICS_STRUCT_T { + UINT_32 u4Length; // Length of structure + LARGE_INTEGER rTransmittedFragmentCount; + LARGE_INTEGER rMulticastTransmittedFrameCount; + LARGE_INTEGER rFailedCount; + LARGE_INTEGER rRetryCount; + LARGE_INTEGER rMultipleRetryCount; + LARGE_INTEGER rRTSSuccessCount; + LARGE_INTEGER rRTSFailureCount; + LARGE_INTEGER rACKFailureCount; + LARGE_INTEGER rFrameDuplicateCount; + LARGE_INTEGER rReceivedFragmentCount; + LARGE_INTEGER rMulticastReceivedFrameCount; + LARGE_INTEGER rFCSErrorCount; + LARGE_INTEGER rTKIPLocalMICFailures; + LARGE_INTEGER rTKIPICVErrors; + LARGE_INTEGER rTKIPCounterMeasuresInvoked; + LARGE_INTEGER rTKIPReplays; + LARGE_INTEGER rCCMPFormatErrors; + LARGE_INTEGER rCCMPReplays; + LARGE_INTEGER rCCMPDecryptErrors; + LARGE_INTEGER rFourWayHandshakeFailures; + LARGE_INTEGER rWEPUndecryptableCount; + LARGE_INTEGER rWEPICVErrorCount; + LARGE_INTEGER rDecryptSuccessCount; + LARGE_INTEGER rDecryptFailureCount; +} PARAM_802_11_STATISTICS_STRUCT_T, *P_PARAM_802_11_STATISTICS_STRUCT_T; + +/* Linux Network Device Statistics Struct */ +typedef struct _PARAM_LINUX_NETDEV_STATISTICS_T { + UINT_32 u4RxPackets; + UINT_32 u4TxPackets; + UINT_32 u4RxBytes; + UINT_32 u4TxBytes; + UINT_32 u4RxErrors; + UINT_32 u4TxErrors; + UINT_32 u4Multicast; +} PARAM_LINUX_NETDEV_STATISTICS_T, *P_PARAM_LINUX_NETDEV_STATISTICS_T; + + +typedef struct _PARAM_MTK_WIFI_TEST_STRUC_T { + UINT_32 u4FuncIndex; + UINT_32 u4FuncData; +} PARAM_MTK_WIFI_TEST_STRUC_T, *P_PARAM_MTK_WIFI_TEST_STRUC_T; + + +/* 802.11 Media stream constraints */ +typedef enum _ENUM_MEDIA_STREAM_MODE { + ENUM_MEDIA_STREAM_OFF, + ENUM_MEDIA_STREAM_ON +} ENUM_MEDIA_STREAM_MODE, *P_ENUM_MEDIA_STREAM_MODE; + +/* for NDIS 5.1 Media Streaming Change */ +typedef struct _PARAM_MEDIA_STREAMING_INDICATION { + PARAM_STATUS_INDICATION_T rStatus; + ENUM_MEDIA_STREAM_MODE eMediaStreamMode; +} PARAM_MEDIA_STREAMING_INDICATION, *P_PARAM_MEDIA_STREAMING_INDICATION; + + +#define PARAM_PROTOCOL_ID_DEFAULT 0x00 +#define PARAM_PROTOCOL_ID_TCP_IP 0x02 +#define PARAM_PROTOCOL_ID_IPX 0x06 +#define PARAM_PROTOCOL_ID_NBF 0x07 +#define PARAM_PROTOCOL_ID_MAX 0x0F +#define PARAM_PROTOCOL_ID_MASK 0x0F + +/* for NDIS OID_GEN_NETWORK_LAYER_ADDRESSES */ +typedef struct _PARAM_NETWORK_ADDRESS_IP +{ + UINT_16 sin_port; + UINT_32 in_addr; + UINT_8 sin_zero[8]; +} PARAM_NETWORK_ADDRESS_IP, *P_PARAM_NETWORK_ADDRESS_IP; + +typedef struct _PARAM_NETWORK_ADDRESS { + UINT_16 u2AddressLength; // length in bytes of Address[] in this + UINT_16 u2AddressType; // type of this address (PARAM_PROTOCOL_ID_XXX above) + UINT_8 aucAddress[1]; // actually AddressLength bytes long +} PARAM_NETWORK_ADDRESS, *P_PARAM_NETWORK_ADDRESS; + +// The following is used with OID_GEN_NETWORK_LAYER_ADDRESSES to set network layer addresses on an interface + +typedef struct _PARAM_NETWORK_ADDRESS_LIST +{ + UINT_32 u4AddressCount; // number of addresses following + UINT_16 u2AddressType; // type of this address (NDIS_PROTOCOL_ID_XXX above) + PARAM_NETWORK_ADDRESS arAddress[1]; // actually AddressCount elements long +} PARAM_NETWORK_ADDRESS_LIST, *P_PARAM_NETWORK_ADDRESS_LIST; + +#if CFG_SLT_SUPPORT + +#define FIXED_BW_LG20 0x0000 +#define FIXED_BW_UL20 0x2000 +#define FIXED_BW_DL40 0x3000 + +#define FIXED_EXT_CHNL_U20 0x4000 // For AGG register. +#define FIXED_EXT_CHNL_L20 0xC000 // For AGG regsiter. + +typedef enum _ENUM_MTK_LP_TEST_MODE_T { + ENUM_MTK_LP_TEST_NORMAL, + ENUM_MTK_LP_TEST_GOLDEN_SAMPLE, + ENUM_MTK_LP_TEST_DUT, + ENUM_MTK_LP_TEST_MODE_NUM +} ENUM_MTK_LP_TEST_MODE_T, *P_ENUM_MTK_LP_TEST_MODE_T; + +typedef enum _ENUM_MTK_SLT_FUNC_IDX_T { + ENUM_MTK_SLT_FUNC_DO_NOTHING, + ENUM_MTK_SLT_FUNC_INITIAL, + ENUM_MTK_SLT_FUNC_RATE_SET, + ENUM_MTK_SLT_FUNC_LP_SET, + ENUM_MTK_SLT_FUNC_NUM +} ENUM_MTK_SLT_FUNC_IDX_T, *P_ENUM_MTK_SLT_FUNC_IDX_T; + +typedef struct _PARAM_MTK_SLT_LP_TEST_STRUC_T { + ENUM_MTK_LP_TEST_MODE_T rLpTestMode; + UINT_32 u4BcnRcvNum; +} PARAM_MTK_SLT_LP_TEST_STRUC_T, *P_PARAM_MTK_SLT_LP_TEST_STRUC_T; + +typedef struct _PARAM_MTK_SLT_TR_TEST_STRUC_T { + ENUM_PARAM_NETWORK_TYPE_T rNetworkType; // Network Type OFDM5G or OFDM2.4G + UINT_32 u4FixedRate; // Fixed Rate including BW +} PARAM_MTK_SLT_TR_TEST_STRUC_T, *P_PARAM_MTK_SLT_TR_TEST_STRUC_T; + +typedef struct _PARAM_MTK_SLT_INITIAL_STRUC_T { + UINT_8 aucTargetMacAddr[PARAM_MAC_ADDR_LEN]; + UINT_16 u2SiteID; +} PARAM_MTK_SLT_INITIAL_STRUC_T, *P_PARAM_MTK_SLT_INITIAL_STRUC_T; + +typedef struct _PARAM_MTK_SLT_TEST_STRUC_T { + ENUM_MTK_SLT_FUNC_IDX_T rSltFuncIdx; + UINT_32 u4Length; /* Length of structure, + including myself */ + UINT_32 u4FuncInfoLen; /* Include following content + field and myself */ + union { + PARAM_MTK_SLT_INITIAL_STRUC_T rMtkInitTest; + PARAM_MTK_SLT_LP_TEST_STRUC_T rMtkLpTest; + PARAM_MTK_SLT_TR_TEST_STRUC_T rMtkTRTest; + } unFuncInfoContent; + +} PARAM_MTK_SLT_TEST_STRUC_T, *P_PARAM_MTK_SLT_TEST_STRUC_T; + +#endif + +/*--------------------------------------------------------------*/ +/*! \brief For Fixed Rate Configuration (Registry) */ +/*--------------------------------------------------------------*/ +typedef enum _ENUM_REGISTRY_FIXED_RATE_T { + FIXED_RATE_NONE, + FIXED_RATE_1M, + FIXED_RATE_2M, + FIXED_RATE_5_5M, + FIXED_RATE_11M, + FIXED_RATE_6M, + FIXED_RATE_9M, + FIXED_RATE_12M, + FIXED_RATE_18M, + FIXED_RATE_24M, + FIXED_RATE_36M, + FIXED_RATE_48M, + FIXED_RATE_54M, + FIXED_RATE_MCS0_20M_800NS, + FIXED_RATE_MCS1_20M_800NS, + FIXED_RATE_MCS2_20M_800NS, + FIXED_RATE_MCS3_20M_800NS, + FIXED_RATE_MCS4_20M_800NS, + FIXED_RATE_MCS5_20M_800NS, + FIXED_RATE_MCS6_20M_800NS, + FIXED_RATE_MCS7_20M_800NS, + FIXED_RATE_MCS0_20M_400NS, + FIXED_RATE_MCS1_20M_400NS, + FIXED_RATE_MCS2_20M_400NS, + FIXED_RATE_MCS3_20M_400NS, + FIXED_RATE_MCS4_20M_400NS, + FIXED_RATE_MCS5_20M_400NS, + FIXED_RATE_MCS6_20M_400NS, + FIXED_RATE_MCS7_20M_400NS, + FIXED_RATE_MCS0_40M_800NS, + FIXED_RATE_MCS1_40M_800NS, + FIXED_RATE_MCS2_40M_800NS, + FIXED_RATE_MCS3_40M_800NS, + FIXED_RATE_MCS4_40M_800NS, + FIXED_RATE_MCS5_40M_800NS, + FIXED_RATE_MCS6_40M_800NS, + FIXED_RATE_MCS7_40M_800NS, + FIXED_RATE_MCS32_800NS, + FIXED_RATE_MCS0_40M_400NS, + FIXED_RATE_MCS1_40M_400NS, + FIXED_RATE_MCS2_40M_400NS, + FIXED_RATE_MCS3_40M_400NS, + FIXED_RATE_MCS4_40M_400NS, + FIXED_RATE_MCS5_40M_400NS, + FIXED_RATE_MCS6_40M_400NS, + FIXED_RATE_MCS7_40M_400NS, + FIXED_RATE_MCS32_400NS, + FIXED_RATE_NUM +} ENUM_REGISTRY_FIXED_RATE_T, *P_ENUM_REGISTRY_FIXED_RATE_T; + +typedef enum _ENUM_BT_CMD_T { + BT_CMD_PROFILE = 0, + BT_CMD_UPDATE, + BT_CMD_NUM +} ENUM_BT_CMD_T; + +typedef enum _ENUM_BT_PROFILE_T { + BT_PROFILE_CUSTOM = 0, + BT_PROFILE_SCO, + BT_PROFILE_ACL, + BT_PROFILE_MIXED, + BT_PROFILE_NO_CONNECTION, + BT_PROFILE_NUM +} ENUM_BT_PROFILE_T; + +typedef struct _PTA_PROFILE_T { + ENUM_BT_PROFILE_T eBtProfile; + union { + UINT_8 aucBTPParams[BT_PROFILE_PARAM_LEN]; + /* 0: sco reserved slot time, + 1: sco idle slot time, + 2: acl throughput, + 3: bt tx power, + 4: bt rssi + 5: VoIP interval + 6: BIT(0) Use this field, BIT(1) 0 apply single/ 1 dual PTA setting. + */ + UINT_32 au4Btcr[4]; + } u; +} PTA_PROFILE_T, *P_PTA_PROFILE_T; + +typedef struct _PTA_IPC_T { + UINT_8 ucCmd; + UINT_8 ucLen; + union { + PTA_PROFILE_T rProfile; + UINT_8 aucBTPParams[BT_PROFILE_PARAM_LEN]; + } u; +} PARAM_PTA_IPC_T, *P_PARAM_PTA_IPC_T, PTA_IPC_T, *P_PTA_IPC_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*--------------------------------------------------------------*/ +/* Routines to set parameters or query information. */ +/*--------------------------------------------------------------*/ +/***** Routines in wlan_oid.c *****/ +WLAN_STATUS +wlanoidQueryNetworkTypesSupported( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidQueryNetworkTypeInUse( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetNetworkTypeInUse ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryBssid( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetBssidListScan( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryBssidList( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetBssid( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidSetSsid( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQuerySsid( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidQueryInfrastructureMode( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetInfrastructureMode( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryAuthMode( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetAuthMode( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +#if 0 +WLAN_STATUS +wlanoidQueryPrivacyFilter ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + + +WLAN_STATUS +wlanoidSetPrivacyFilter ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); +#endif + +WLAN_STATUS +wlanoidSetEncryptionStatus( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryEncryptionStatus( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetAddWep( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidSetRemoveWep( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidSetAddKey( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidSetRemoveKey( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidSetReloadDefaults( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidSetTest( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryCapability( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidQueryFrequency ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetFrequency ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + + +WLAN_STATUS +wlanoidQueryAtimWindow ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetAtimWindow ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + + +WLAN_STATUS +wlanoidSetChannel ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryRssi( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidQueryRssiTrigger( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetRssiTrigger( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryRtsThreshold ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetRtsThreshold ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQuery802dot11PowerSaveProfile ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSet802dot11PowerSaveProfile ( + IN P_ADAPTER_T prAdapter, + IN PVOID prSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryPmkid( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetPmkid( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQuerySupportedRates( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidQueryDesiredRates ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetDesiredRates ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryPermanentAddr ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuf, + IN UINT_32 u4QueryBufLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidQueryCurrentAddr ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuf, + IN UINT_32 u4QueryBufLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidQueryPermanentAddr ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuf, + IN UINT_32 u4QueryBufLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidQueryLinkSpeed( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidQueryMcrRead ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetMcrWrite ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + + +WLAN_STATUS +wlanoidQuerySwCtrlRead ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetSwCtrlWrite ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + + +WLAN_STATUS +wlanoidQueryEepromRead ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetEepromWrite ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryRfTestRxStatus ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidQueryRfTestTxStatus ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidQueryOidInterfaceVersion ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidQueryVendorId( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidQueryMulticastList( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetMulticastList( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryRcvError ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidQueryRcvNoBuffer ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidQueryRcvCrcError ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidQueryStatistics ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +#ifdef LINUX + +WLAN_STATUS +wlanoidQueryStatisticsForLinux ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +#endif + +WLAN_STATUS +wlanoidQueryMediaStreamMode( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetMediaStreamMode( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryRcvOk( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidQueryXmitOk( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidQueryXmitError ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidQueryXmitOneCollision ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidQueryXmitMoreCollisions ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidQueryXmitMaxCollisions ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + + +WLAN_STATUS +wlanoidSetCurrentPacketFilter( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryCurrentPacketFilter ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + + +WLAN_STATUS +wlanoidSetAcpiDevicePowerState ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryAcpiDevicePowerState ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + + +WLAN_STATUS +wlanoidSetDisassociate ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryFragThreshold ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetFragThreshold ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + + +WLAN_STATUS +wlanoidQueryAdHocMode ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetAdHocMode ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryBeaconInterval ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetBeaconInterval ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidSetCurrentAddr ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +#if CFG_TCP_IP_CHKSUM_OFFLOAD +WLAN_STATUS +wlanoidSetCSUMOffload ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen +); +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + +WLAN_STATUS +wlanoidSetNetworkAddress ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryMaxFrameSize ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidQueryMaxTotalSize ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetCurrentLookahead ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +/* RF Test related APIs */ +WLAN_STATUS +wlanoidRftestSetTestMode ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidRftestSetAbortTestMode ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidRftestQueryAutoTest ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidRftestSetAutoTest ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +#if CFG_SUPPORT_WAPI +WLAN_STATUS +wlanoidSetWapiMode ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidSetWapiAssocInfo ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidSetWapiKey( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); +#endif + +#if CFG_SUPPORT_WPS2 +WLAN_STATUS +wlanoidSetWSCAssocInfo ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); +#endif + +#if CFG_ENABLE_WAKEUP_ON_LAN +WLAN_STATUS +wlanoidSetAddWakeupPattern ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidSetRemoveWakeupPattern ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryEnableWakeup ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 u4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetEnableWakeup ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); +#endif + +WLAN_STATUS +wlanoidSetWiFiWmmPsTest ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidSetTxAmpdu ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidSetAddbaReject( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryNvramRead ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetNvramWrite ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryCfgSrcType( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidQueryEepromType( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetCountryCode ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + + +#if CFG_SLT_SUPPORT + +WLAN_STATUS +wlanoidQuerySLTStatus( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidUpdateSLTMode( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +#endif + +#if 0 +WLAN_STATUS +wlanoidSetNoaParam ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidSetOppPsParam ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidSetUApsdParam ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); +#endif + +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetBT ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryBT ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetTxPower ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +/* +WLAN_STATUS +wlanoidQueryBtSingleAntenna ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetBtSingleAntenna ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidSetPta ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryPta ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); +*/ +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _WLAN_OID_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/aaa_fsm.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/aaa_fsm.c new file mode 100755 index 000000000000..2fde7696f74f --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/aaa_fsm.c @@ -0,0 +1,1552 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/mgmt/aaa_fsm.c#1 $ +*/ + +/*! \file "aaa_fsm.c" + \brief This file defines the FSM for AAA MODULE. + + This file defines the FSM for AAA MODULE. +*/ + +/******************************************************************************* +* Copyright (c) 2010 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: aaa_fsm.c $ + * + * 02 22 2012 yuche.tsai + * [ALPS00240483] [Wifi P2P]Run Sigma tool of A69. Always run fail on 5.1.2. No get correct connection from Realtek. + * Fix assoc response without P2P IE issue for Sigma test. + * + * 12 02 2011 yuche.tsai + * NULL + * Resolve class 3 error issue under AP mode. + * + * data frame may TX before Assoc Response TX. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 06 29 2011 terry.wu + * NULL + * Add BoW 11n support. + * + * 06 16 2011 cp.wu + * [WCXRP00000782] [MT6620 Wi-Fi][AIS] Treat connection at higher priority over scanning to avoid WZC connection timeout + * When RECONNECT request is identified as disconnected, it is necessary to check for pending scan request. + * + * 06 02 2011 eddie.chen + * [WCXRP00000759] [MT6620 Wi-Fi][DRV] Update RCPI in AAA + * Update RCPI when receiving Assoc request. + * + * 04 21 2011 terry.wu + * [WCXRP00000674] [MT6620 Wi-Fi][Driver] Refine AAA authSendAuthFrame + * Add network type parameter to authSendAuthFrame. + * + * 04 15 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add BOW short range mode. + * + * 04 09 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Change Link connection event procedure and change skb length check to 1512 bytes. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 09 2011 wh.su + * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done + * Skip to call p2pRunEventAAAComplete to avoid indicate STA connect twice. + * + * 03 04 2011 terry.wu + * [WCXRP00000515] [MT6620 Wi-Fi][Driver] Surpress compiler warning which is identified by GNU compiler collection + * Remove unused variable. + * + * 02 16 2011 yuche.tsai + * [WCXRP00000429] [Volunteer Patch][MT6620][Driver] Hot Spot Client Limit Issue + * Add more check after RX assoc frame under Hot-Spot mode. + * + * 02 09 2011 yuche.tsai + * [WCXRP00000429] [Volunteer Patch][MT6620][Driver] Hot Spot Client Limit Issue + * Fix Client Limit Issue. + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. + * + * 01 15 2011 puff.wen + * NULL + * [On behalf of Frog] Add CFG_ENABLE_WIFI_DIRECT to p2pRunEventAAAComplete + * + * 01 14 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Modify AAA flow according to CM's comment. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 29 2010 yuche.tsai + * NULL + * Fix Compile warning, type cast from UINT_32 to UINT_16. + * + * 08 26 2010 yuche.tsai + * NULL + * In P2P AT GO test mode under WinXP, we would not indicate connected event to host. + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 08 23 2010 chinghwa.yu + * NULL + * Update for BOW. + * + * 08 20 2010 kevin.huang + * NULL + * Modify AAA Module for changing STA STATE 3 at p2p/bowRunEventAAAComplete() + * + * 08 17 2010 yuche.tsai + * NULL + * Fix bug while enabling P2P GO. + * + * 08 16 2010 kevin.huang + * NULL + * Refine AAA functions + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * refine TX-DONE callback. + * + * 06 21 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * modify due to P2P functino call prototype change. + * + * 06 17 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * First draft for migration P2P FSM from FW to Driver. + * + * 04 02 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Modify CFG flags + * + * 02 26 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * add support of Driver STA_RECORD_T activation + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will send Event to AIS/BOW/P2P +* +* @param[in] rJoinStatus To indicate JOIN success or failure. +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] prSwRfb Pointer to the SW_RFB_T + +* @return none +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +aaaFsmSendEventJoinComplete ( + WLAN_STATUS rJoinStatus, + P_STA_RECORD_T prStaRec, + P_SW_RFB_T prSwRfb + ) +{ + P_MSG_SAA_JOIN_COMP_T prJoinCompMsg; + + + ASSERT(prStaRec); + + prJoinCompMsg = cnmMemAlloc(RAM_TYPE_TCM, sizeof(MSG_SAA_JOIN_COMP_T)); + if (!prJoinCompMsg) { + return WLAN_STATUS_RESOURCES; + } + + if (IS_STA_IN_AIS(prStaRec)) { + prJoinCompMsg->rMsgHdr.eMsgId = MID_SAA_AIS_JOIN_COMPLETE; + } + else if (IS_STA_IN_P2P(prStaRec)) { + prJoinCompMsg->rMsgHdr.eMsgId = MID_SAA_P2P_JOIN_COMPLETE; + } + else if (IS_STA_IN_BOW(prStaRec)) { + prJoinCompMsg->rMsgHdr.eMsgId = MID_SAA_BOW_JOIN_COMPLETE; + } + else { + ASSERT(0); + } + + prJoinCompMsg->rJoinStatus = rJoinStatus; + prJoinCompMsg->prStaRec = prStaRec; + prJoinCompMsg->prSwRfb = prSwRfb; + + mboxSendMsg(MBOX_ID_0, + (P_MSG_HDR_T)prJoinCompMsg, + MSG_SEND_METHOD_BUF); + + return WLAN_STATUS_SUCCESS; + +} /* end of saaFsmSendEventJoinComplete() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle the Start Event to AAA FSM. +* +* @param[in] prMsgHdr Message of Join Request for a particular STA. +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +aaaFsmRunEventStart ( + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_MSG_SAA_JOIN_REQ_T prJoinReqMsg; + P_STA_RECORD_T prStaRec; + P_AIS_BSS_INFO_T prAisBssInfo; + + + ASSERT(prMsgHdr); + + prJoinReqMsg = (P_MSG_SAA_JOIN_REQ_T)prMsgHdr; + prStaRec = prJoinReqMsg->prStaRec; + + ASSERT(prStaRec); + + DBGLOG(SAA, LOUD, ("EVENT-START: Trigger SAA FSM\n")); + + cnmMemFree(prMsgHdr); + + //4 <1> Validation of SAA Start Event + if (!IS_AP_STA(prStaRec->eStaType)) { + + DBGLOG(SAA, ERROR, ("EVENT-START: STA Type - %d was not supported.\n", prStaRec->eStaType)); + + /* Ignore the return value because don't care the prSwRfb */ + saaFsmSendEventJoinComplete(WLAN_STATUS_FAILURE, prStaRec, NULL); + + return; + } + + //4 <2> The previous JOIN process is not completed ? + if (prStaRec->eAuthAssocState != AA_STATE_IDLE) { + DBGLOG(SAA, ERROR, ("EVENT-START: Reentry of SAA Module.\n")); + prStaRec->eAuthAssocState = AA_STATE_IDLE; + } + + //4 <3> Reset Status Code and Time + /* Update Station Record - Status/Reason Code */ + prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; + + /* Update the record join time. */ + GET_CURRENT_SYSTIME(&prStaRec->rLastJoinTime); + + prStaRec->ucTxAuthAssocRetryCount = 0; + + if (prStaRec->prChallengeText) { + cnmMemFree(prStaRec->prChallengeText); + prStaRec->prChallengeText = (P_IE_CHALLENGE_TEXT_T)NULL; + } + + cnmTimerStopTimer(&prStaRec->rTxReqDoneOrRxRespTimer); + + prStaRec->ucStaState = STA_STATE_1; + + /* Trigger SAA MODULE */ + saaFsmSteps(prStaRec, SAA_STATE_SEND_AUTH1, (P_SW_RFB_T)NULL); + + return; +} /* end of saaFsmRunEventStart() */ +#endif + + +#if CFG_SUPPORT_AAA +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will process the Rx Auth Request Frame and then +* trigger AAA FSM. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to the SW_RFB_T structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aaaFsmRunEventRxAuth ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + UINT_16 u2StatusCode; + BOOLEAN fgReplyAuth = FALSE; + ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex; + + + ASSERT(prAdapter); + + do { + + + //4 <1> Check P2P network conditions +#if CFG_ENABLE_WIFI_DIRECT + if(prAdapter->fgIsP2PRegistered){ + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + if (prBssInfo->fgIsNetActive) { + + //4 <1.1> Validate Auth Frame by Auth Algorithm/Transation Seq + if (WLAN_STATUS_SUCCESS == + authProcessRxAuth1Frame(prAdapter, + prSwRfb, + prBssInfo->aucBSSID, + AUTH_ALGORITHM_NUM_OPEN_SYSTEM, + AUTH_TRANSACTION_SEQ_1, + &u2StatusCode)) { + + if (STATUS_CODE_SUCCESSFUL == u2StatusCode) { + + if(prAdapter->rP2pFuncLkr.prP2pValidateAuth) { + //4 <1.2> Validate Auth Frame for Network Specific Conditions + fgReplyAuth = + prAdapter->rP2pFuncLkr.prP2pValidateAuth( + prAdapter, + prSwRfb, + &prStaRec, + &u2StatusCode); + } + else { + ASSERT(0); + } + } + else { + + fgReplyAuth = TRUE; + } + eNetTypeIndex = NETWORK_TYPE_P2P_INDEX; + break; + } + } + } +#endif /* CFG_ENABLE_WIFI_DIRECT */ + + //4 <2> Check BOW network conditions +#if CFG_ENABLE_BT_OVER_WIFI + { + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + + if ((prBssInfo->fgIsNetActive) && + (OP_MODE_BOW == prBssInfo->eCurrentOPMode)) { + + //4 <2.1> Validate Auth Frame by Auth Algorithm/Transation Seq + /* Check if for this BSSID */ + if (WLAN_STATUS_SUCCESS == + authProcessRxAuth1Frame(prAdapter, + prSwRfb, + prBssInfo->aucBSSID, + AUTH_ALGORITHM_NUM_OPEN_SYSTEM, + AUTH_TRANSACTION_SEQ_1, + &u2StatusCode)) { + + if (STATUS_CODE_SUCCESSFUL == u2StatusCode) { + + //4 <2.2> Validate Auth Frame for Network Specific Conditions + fgReplyAuth = bowValidateAuth(prAdapter, prSwRfb, &prStaRec, &u2StatusCode); + + } + else { + + fgReplyAuth = TRUE; + } + eNetTypeIndex = NETWORK_TYPE_BOW_INDEX; + /* TODO(Kevin): Allocate a STA_RECORD_T for new client */ + break; + } + } + } +#endif /* CFG_ENABLE_BT_OVER_WIFI */ + + return; + } while (FALSE); + + if(prStaRec) { + /* update RCPI */ + prStaRec->ucRCPI = prSwRfb->prHifRxHdr->ucRcpi; + } + + //4 <3> Update STA_RECORD_T and reply Auth_2(Response to Auth_1) Frame + if (fgReplyAuth) { + + if (prStaRec) { + + if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { + if (prStaRec->eAuthAssocState != AA_STATE_IDLE) { + DBGLOG(AAA, WARN, ("Previous AuthAssocState (%d) != IDLE.\n", + prStaRec->eAuthAssocState)); + } + + prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; + } + else { + prStaRec->eAuthAssocState = AA_STATE_IDLE; + + /* NOTE(Kevin): Change to STATE_1 */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + } + + /* Update the record join time. */ + GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); + + /* Update Station Record - Status/Reason Code */ + prStaRec->u2StatusCode = u2StatusCode; + + prStaRec->ucAuthAlgNum = AUTH_ALGORITHM_NUM_OPEN_SYSTEM; + } + else { + /* NOTE(Kevin): We should have STA_RECORD_T if the status code was successful */ + ASSERT(!(u2StatusCode == STATUS_CODE_SUCCESSFUL)); + } + + /* NOTE: Ignore the return status for AAA */ + //4 <4> Reply Auth + authSendAuthFrame(prAdapter, + prStaRec, + eNetTypeIndex, + prSwRfb, + AUTH_TRANSACTION_SEQ_2, + u2StatusCode); + + } + + return; +} /* end of aaaFsmRunEventRxAuth() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will process the Rx (Re)Association Request Frame and then +* trigger AAA FSM. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to the SW_RFB_T structure. +* +* @retval WLAN_STATUS_SUCCESS Always return success +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +aaaFsmRunEventRxAssoc ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + UINT_16 u2StatusCode = STATUS_CODE_RESERVED; + BOOLEAN fgReplyAssocResp = FALSE; + + + ASSERT(prAdapter); + + do { + + //4 <1> Check if we have the STA_RECORD_T for incoming Assoc Req + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + /* We should have the corresponding Sta Record. */ + if ((!prStaRec) || (!prStaRec->fgIsInUse)) { + ASSERT(0); // Only for debug phase + break; + } + + if (!IS_CLIENT_STA(prStaRec)) { + break; + } + + if (prStaRec->ucStaState == STA_STATE_3) { + /* Do Reassocation */ + } + else if ((prStaRec->ucStaState == STA_STATE_2) && + (prStaRec->eAuthAssocState == AAA_STATE_SEND_AUTH2)) { + /* Normal case */ + } + else { + DBGLOG(AAA, WARN, ("Previous AuthAssocState (%d) != SEND_AUTH2.\n", + prStaRec->eAuthAssocState)); + break; + } + + /* update RCPI */ + prStaRec->ucRCPI = prSwRfb->prHifRxHdr->ucRcpi; + + //4 <2> Check P2P network conditions +#if CFG_ENABLE_WIFI_DIRECT + if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) { + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + if (prBssInfo->fgIsNetActive) { + + //4 <2.1> Validate Assoc Req Frame and get Status Code + /* Check if for this BSSID */ + if (WLAN_STATUS_SUCCESS == + assocProcessRxAssocReqFrame(prAdapter, + prSwRfb, + &u2StatusCode)) { + + if (STATUS_CODE_SUCCESSFUL == u2StatusCode) { + if(prAdapter->rP2pFuncLkr.prP2pValidateAssocReq) { + //4 <2.2> Validate Assoc Req Frame for Network Specific Conditions + fgReplyAssocResp = prAdapter->rP2pFuncLkr.prP2pValidateAssocReq( + prAdapter, + prSwRfb, + (PUINT_16)&u2StatusCode); + } + else { + ASSERT(0); + } + } + else { + fgReplyAssocResp = TRUE; + } + + break; + } + } + } +#endif /* CFG_ENABLE_WIFI_DIRECT */ + + //4 <3> Check BOW network conditions +#if CFG_ENABLE_BT_OVER_WIFI + if (IS_STA_IN_BOW(prStaRec)) { + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + + if ((prBssInfo->fgIsNetActive) && + (OP_MODE_BOW == prBssInfo->eCurrentOPMode)){ + + //4 <3.1> Validate Auth Frame by Auth Algorithm/Transation Seq + /* Check if for this BSSID */ + if (WLAN_STATUS_SUCCESS == + assocProcessRxAssocReqFrame(prAdapter, + prSwRfb, + &u2StatusCode)) { + + if (STATUS_CODE_SUCCESSFUL == u2StatusCode) { + + //4 <3.2> Validate Auth Frame for Network Specific Conditions + fgReplyAssocResp = bowValidateAssocReq(prAdapter, prSwRfb, &u2StatusCode); + + } + else { + + fgReplyAssocResp = TRUE; + } + + /* TODO(Kevin): Allocate a STA_RECORD_T for new client */ + break; + } + } + } +#endif /* CFG_ENABLE_BT_OVER_WIFI */ + + return WLAN_STATUS_SUCCESS; // To release the SW_RFB_T + } while (FALSE); + + + //4 <4> Update STA_RECORD_T and reply Assoc Resp Frame + if (fgReplyAssocResp) { + UINT_16 u2IELength; + PUINT_8 pucIE; + + if ((((P_WLAN_ASSOC_REQ_FRAME_T)(prSwRfb->pvHeader))->u2FrameCtrl & MASK_FRAME_TYPE) == + MAC_FRAME_REASSOC_RSP) { + + u2IELength = prSwRfb->u2PacketLen - + (UINT_16)OFFSET_OF(WLAN_REASSOC_REQ_FRAME_T, aucInfoElem[0]); + + pucIE = ((P_WLAN_REASSOC_REQ_FRAME_T)(prSwRfb->pvHeader))->aucInfoElem; + } + else { + u2IELength = prSwRfb->u2PacketLen - + (UINT_16)OFFSET_OF(WLAN_ASSOC_REQ_FRAME_T, aucInfoElem[0]); + + pucIE = ((P_WLAN_ASSOC_REQ_FRAME_T)(prSwRfb->pvHeader))->aucInfoElem; + } + + rlmProcessAssocReq(prAdapter, prSwRfb, pucIE, u2IELength); + + //4 <4.1> Assign Association ID + if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { + +#if CFG_ENABLE_WIFI_DIRECT + if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) { + ASSERT(prAdapter->rP2pFuncLkr.prP2pRunEventAAAComplete); + if (prAdapter->rP2pFuncLkr.prP2pRunEventAAAComplete(prAdapter, prStaRec) == WLAN_STATUS_SUCCESS) { + prStaRec->u2AssocId = bssAssignAssocID(prStaRec); + //prStaRec->eAuthAssocState = AA_STATE_IDLE; + prStaRec->eAuthAssocState = AAA_STATE_SEND_ASSOC2; // NOTE(Kevin): for TX done + + /* NOTE(Kevin): Method A: Change to STATE_3 before handle TX Done */ + //cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + } + else { + /* Client List FULL. */ + u2StatusCode = STATUS_CODE_REQ_DECLINED; + + prStaRec->u2AssocId = 0; /* Invalid Assocation ID */ + + /* If (Re)association fail, the peer can try Assocation w/o Auth immediately */ + prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; + + /* NOTE(Kevin): Better to change state here, not at TX Done */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); + } + } +#endif + +#if CFG_ENABLE_BT_OVER_WIFI + if ((IS_STA_IN_BOW(prStaRec))) { + +// if (bowRunEventAAAComplete(prAdapter, prStaRec) == WLAN_STATUS_SUCCESS) { + prStaRec->u2AssocId = bssAssignAssocID(prStaRec); + prStaRec->eAuthAssocState = AAA_STATE_SEND_ASSOC2; // NOTE(Kevin): for TX done + + /* NOTE(Kevin): Method A: Change to STATE_3 before handle TX Done */ + //cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + } +#if 0 + else { + /* Client List FULL. */ + u2StatusCode = STATUS_CODE_REQ_DECLINED; + + prStaRec->u2AssocId = 0; /* Invalid Assocation ID */ + + /* If (Re)association fail, the peer can try Assocation w/o Auth immediately */ + prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; + + /* NOTE(Kevin): Better to change state here, not at TX Done */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); + } + } +#endif +#endif + } + else { + prStaRec->u2AssocId = 0; /* Invalid Assocation ID */ + + /* If (Re)association fail, the peer can try Assocation w/o Auth immediately */ + prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; + + /* NOTE(Kevin): Better to change state here, not at TX Done */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); + } + + /* Update the record join time. */ + GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); + + /* Update Station Record - Status/Reason Code */ + prStaRec->u2StatusCode = u2StatusCode; + + /* NOTE: Ignore the return status for AAA */ + //4 <4.2> Reply Assoc Resp + assocSendReAssocRespFrame(prAdapter, prStaRec); + + } + + return WLAN_STATUS_SUCCESS; + +} /* end of aaaFsmRunEventRxAssoc() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle TxDone(Auth2/AssocReq) Event of AAA FSM. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prMsduInfo Pointer to the MSDU_INFO_T. +* @param[in] rTxDoneStatus Return TX status of the Auth1/Auth3/AssocReq frame. +* +* @retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +aaaFsmRunEventTxDone ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus + ) +{ + P_STA_RECORD_T prStaRec; + P_BSS_INFO_T prBssInfo; + + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + DBGLOG(AAA, LOUD, ("EVENT-TX DONE: Current Time = %ld\n", kalGetTimeTick())); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if ((!prStaRec) || (!prStaRec->fgIsInUse)) { + return WLAN_STATUS_SUCCESS; /* For the case of replying ERROR STATUS CODE */ + } + + ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + switch (prStaRec->eAuthAssocState) { + case AAA_STATE_SEND_AUTH2: + { + /* Strictly check the outgoing frame is matched with current AA STATE */ + if (authCheckTxAuthFrame(prAdapter, + prMsduInfo, + AUTH_TRANSACTION_SEQ_2) != WLAN_STATUS_SUCCESS) { + break; + } + + if (STATUS_CODE_SUCCESSFUL == prStaRec->u2StatusCode) { + if (TX_RESULT_SUCCESS == rTxDoneStatus) { + + /* NOTE(Kevin): Change to STATE_2 at TX Done */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); + } + else { + + prStaRec->eAuthAssocState = AA_STATE_IDLE; + + /* NOTE(Kevin): Change to STATE_1 */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + +#if CFG_ENABLE_WIFI_DIRECT + if ((prAdapter->fgIsP2PRegistered) && + (IS_STA_IN_P2P(prStaRec))) { + if(prAdapter->rP2pFuncLkr.prP2pRunEventAAATxFail) { + prAdapter->rP2pFuncLkr.prP2pRunEventAAATxFail(prAdapter, prStaRec); + } else { + ASSERT(0); + } + } +#endif /* CFG_ENABLE_WIFI_DIRECT */ + +#if CFG_ENABLE_BT_OVER_WIFI + if (IS_STA_IN_BOW(prStaRec)) { + bowRunEventAAATxFail(prAdapter, prStaRec); + } +#endif /* CFG_ENABLE_BT_OVER_WIFI */ + } + + } + /* NOTE(Kevin): Ignore the TX Done Event of Auth Frame with Error Status Code */ + + } + break; + + case AAA_STATE_SEND_ASSOC2: + { + /* Strictly check the outgoing frame is matched with current SAA STATE */ + if (assocCheckTxReAssocRespFrame(prAdapter, prMsduInfo) != WLAN_STATUS_SUCCESS) { + break; + } + + if (STATUS_CODE_SUCCESSFUL == prStaRec->u2StatusCode) { + if (TX_RESULT_SUCCESS == rTxDoneStatus) { + + prStaRec->eAuthAssocState = AA_STATE_IDLE; + + /* NOTE(Kevin): Change to STATE_3 at TX Done */ +#if CFG_ENABLE_WIFI_DIRECT + if ((prAdapter->fgIsP2PRegistered) && + (IS_STA_IN_P2P(prStaRec))) { + if(prAdapter->rP2pFuncLkr.prP2pRunEventAAASuccess) { + prAdapter->rP2pFuncLkr.prP2pRunEventAAASuccess(prAdapter, prStaRec); + } else { + ASSERT(0); + } + } +#endif /* CFG_ENABLE_WIFI_DIRECT */ + +#if CFG_ENABLE_BT_OVER_WIFI + + if (IS_STA_IN_BOW(prStaRec)) + { + bowRunEventAAAComplete(prAdapter, prStaRec); + } +#endif /* CFG_ENABLE_BT_OVER_WIFI */ + + } + else { + + prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; + + /* NOTE(Kevin): Change to STATE_2 */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); + +#if CFG_ENABLE_WIFI_DIRECT + if ((prAdapter->fgIsP2PRegistered) && + (IS_STA_IN_P2P(prStaRec))) { + if(prAdapter->rP2pFuncLkr.prP2pRunEventAAATxFail) { + prAdapter->rP2pFuncLkr.prP2pRunEventAAATxFail(prAdapter, prStaRec); + } else { + ASSERT(0); + } + } +#endif /* CFG_ENABLE_WIFI_DIRECT */ + +#if CFG_ENABLE_BT_OVER_WIFI + if (IS_STA_IN_BOW(prStaRec)) { + bowRunEventAAATxFail(prAdapter, prStaRec); + } +#endif /* CFG_ENABLE_BT_OVER_WIFI */ + + } + } + /* NOTE(Kevin): Ignore the TX Done Event of Auth Frame with Error Status Code */ + } + break; + + default: + break; /* Ignore other cases */ + } + + + return WLAN_STATUS_SUCCESS; + +} /* end of aaaFsmRunEventTxDone() */ +#endif /* CFG_SUPPORT_AAA */ + + +#if 0 /* TODO(Kevin): for abort event, just reset the STA_RECORD_T. */ +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will send ABORT Event to JOIN FSM. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +saaFsmRunEventAbort ( + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_JOIN_INFO_T prJoinInfo; + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("joinFsmRunEventAbort"); + + + ASSERT(prAdapter); + prJoinInfo = &prAdapter->rJoinInfo; + + DBGLOG(JOIN, EVENT, ("JOIN EVENT: ABORT\n")); + + + /* NOTE(Kevin): when reach here, the ARB_STATE should be in ARB_STATE_JOIN. */ + ASSERT(prJoinInfo->prBssDesc); + + //4 <1> Update Flags and Elements of JOIN Module. + /* Reset Send Auth/(Re)Assoc Frame Count */ + prJoinInfo->ucTxAuthAssocRetryCount = 0; + + /* Cancel all JOIN relative Timer */ + ARB_CANCEL_TIMER(prAdapter, + prJoinInfo->rTxRequestTimer); + + ARB_CANCEL_TIMER(prAdapter, + prJoinInfo->rRxResponseTimer); + + ARB_CANCEL_TIMER(prAdapter, + prJoinInfo->rJoinTimer); + + //4 <2> Update the associated STA_RECORD_T during JOIN. + /* Get a Station Record if possible, TA == BSSID for AP */ + prStaRec = staRecGetStaRecordByAddr(prAdapter, + prJoinInfo->prBssDesc->aucBSSID); + if (prStaRec) { + + /* Update Station Record - Class 1 Flag */ + prStaRec->ucStaState = STA_STATE_1; + } +#if DBG + else { + ASSERT(0); /* Shouldn't happened, because we already add this STA_RECORD_T at JOIN_STATE_INIT */ + } +#endif /* DBG */ + + //4 <3> Pull back to IDLE. + joinFsmSteps(prAdapter, JOIN_STATE_IDLE); + + //4 <4> If we are in Roaming, recover the settings of previous BSS. + /* NOTE: JOIN FAIL - + * Restore original setting from current BSS_INFO_T. + */ + if (prAdapter->eConnectionState == MEDIA_STATE_CONNECTED) { + joinAdoptParametersFromCurrentBss(prAdapter); + } + + return; +} /* end of joinFsmRunEventAbort() */ +#endif + + +/* TODO(Kevin): following code will be modified and move to AIS FSM */ +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will send Join Timeout Event to JOIN FSM. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* +* \retval WLAN_STATUS_FAILURE Fail because of Join Timeout +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +joinFsmRunEventJoinTimeOut ( + IN P_ADAPTER_T prAdapter + ) +{ + P_JOIN_INFO_T prJoinInfo; + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("joinFsmRunEventJoinTimeOut"); + + + ASSERT(prAdapter); + prJoinInfo = &prAdapter->rJoinInfo; + + DBGLOG(JOIN, EVENT, ("JOIN EVENT: JOIN TIMEOUT\n")); + + /* Get a Station Record if possible, TA == BSSID for AP */ + prStaRec = staRecGetStaRecordByAddr(prAdapter, + prJoinInfo->prBssDesc->aucBSSID); + + /* We have renew this Sta Record when in JOIN_STATE_INIT */ + ASSERT(prStaRec); + + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = STATUS_CODE_JOIN_TIMEOUT; + + /* Increase Failure Count */ + prStaRec->ucJoinFailureCount++; + + /* Reset Send Auth/(Re)Assoc Frame Count */ + prJoinInfo->ucTxAuthAssocRetryCount = 0; + + /* Cancel other JOIN relative Timer */ + ARB_CANCEL_TIMER(prAdapter, + prJoinInfo->rTxRequestTimer); + + ARB_CANCEL_TIMER(prAdapter, + prJoinInfo->rRxResponseTimer); + + /* Restore original setting from current BSS_INFO_T */ + if (prAdapter->eConnectionState == MEDIA_STATE_CONNECTED) { + joinAdoptParametersFromCurrentBss(prAdapter); + } + + /* Pull back to IDLE */ + joinFsmSteps(prAdapter, JOIN_STATE_IDLE); + + return WLAN_STATUS_FAILURE; + +} /* end of joinFsmRunEventJoinTimeOut() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will adopt the parameters from Peer BSS. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +joinAdoptParametersFromPeerBss ( + IN P_ADAPTER_T prAdapter + ) +{ + P_JOIN_INFO_T prJoinInfo; + P_BSS_DESC_T prBssDesc; + + DEBUGFUNC("joinAdoptParametersFromPeerBss"); + + + ASSERT(prAdapter); + prJoinInfo = &prAdapter->rJoinInfo; + prBssDesc = prJoinInfo->prBssDesc; + + //4 <1> Adopt Peer BSS' PHY TYPE + prAdapter->eCurrentPhyType = prBssDesc->ePhyType; + + DBGLOG(JOIN, INFO, ("Target BSS[%s]'s PhyType = %s\n", + prBssDesc->aucSSID, (prBssDesc->ePhyType == PHY_TYPE_ERP_INDEX) ? "ERP" : "HR_DSSS")); + + + //4 <2> Adopt Peer BSS' Frequency(Band/Channel) + DBGLOG(JOIN, INFO, ("Target BSS's Channel = %d, Band = %d\n", + prBssDesc->ucChannelNum, prBssDesc->eBand)); + + nicSwitchChannel(prAdapter, + prBssDesc->eBand, + prBssDesc->ucChannelNum, + 10); + + prJoinInfo->fgIsParameterAdopted = TRUE; + + return; +} /* end of joinAdoptParametersFromPeerBss() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will adopt the parameters from current associated BSS. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +joinAdoptParametersFromCurrentBss ( + IN P_ADAPTER_T prAdapter + ) +{ + //P_JOIN_INFO_T prJoinInfo = &prAdapter->rJoinInfo; + P_BSS_INFO_T prBssInfo; + + + ASSERT(prAdapter); + prBssInfo = &prAdapter->rBssInfo; + + //4 <1> Adopt current BSS' PHY TYPE + prAdapter->eCurrentPhyType = prBssInfo->ePhyType; + + //4 <2> Adopt current BSS' Frequency(Band/Channel) + DBGLOG(JOIN, INFO, ("Current BSS's Channel = %d, Band = %d\n", + prBssInfo->ucChnl, prBssInfo->eBand)); + + nicSwitchChannel(prAdapter, + prBssInfo->eBand, + prBssInfo->ucChnl, + 10); + return; +} /* end of joinAdoptParametersFromCurrentBss() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will update all the SW variables and HW MCR registers after +* the association with target BSS. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +joinComplete ( + IN P_ADAPTER_T prAdapter + ) +{ + P_JOIN_INFO_T prJoinInfo; + P_BSS_DESC_T prBssDesc; + P_PEER_BSS_INFO_T prPeerBssInfo; + P_BSS_INFO_T prBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_STA_RECORD_T prStaRec; + P_TX_CTRL_T prTxCtrl; +#if CFG_SUPPORT_802_11D + P_IE_COUNTRY_T prIECountry; +#endif + + DEBUGFUNC("joinComplete"); + + + ASSERT(prAdapter); + prJoinInfo = &prAdapter->rJoinInfo; + prBssDesc = prJoinInfo->prBssDesc; + prPeerBssInfo = &prAdapter->rPeerBssInfo; + prBssInfo = &prAdapter->rBssInfo; + prConnSettings = &prAdapter->rConnSettings; + prTxCtrl = &prAdapter->rTxCtrl; + +//4 <1> Update Connecting & Connected Flag of BSS_DESC_T. + /* Remove previous AP's Connection Flags if have */ + scanRemoveConnectionFlagOfBssDescByBssid(prAdapter, prBssInfo->aucBSSID); + + prBssDesc->fgIsConnected = TRUE; /* Mask as Connected */ + + if (prBssDesc->fgIsHiddenSSID) { + /* NOTE(Kevin): This is for the case of Passive Scan and the target BSS didn't + * broadcast SSID on its Beacon Frame. + */ + COPY_SSID(prBssDesc->aucSSID, + prBssDesc->ucSSIDLen, + prAdapter->rConnSettings.aucSSID, + prAdapter->rConnSettings.ucSSIDLen); + + if (prBssDesc->ucSSIDLen) { + prBssDesc->fgIsHiddenSSID = FALSE; + } +#if DBG + else { + ASSERT(0); + } +#endif /* DBG */ + + DBGLOG(JOIN, INFO, ("Hidden SSID! - Update SSID : %s\n", prBssDesc->aucSSID)); + } + + +//4 <2> Update BSS_INFO_T from BSS_DESC_T + //4 <2.A> PHY Type + prBssInfo->ePhyType = prBssDesc->ePhyType; + + //4 <2.B> BSS Type + prBssInfo->eBSSType = BSS_TYPE_INFRASTRUCTURE; + + //4 <2.C> BSSID + COPY_MAC_ADDR(prBssInfo->aucBSSID, prBssDesc->aucBSSID); + + DBGLOG(JOIN, INFO, ("JOIN to BSSID: ["MACSTR"]\n", MAC2STR(prBssDesc->aucBSSID))); + + + //4 <2.D> SSID + COPY_SSID(prBssInfo->aucSSID, + prBssInfo->ucSSIDLen, + prBssDesc->aucSSID, + prBssDesc->ucSSIDLen); + + //4 <2.E> Channel / Band information. + prBssInfo->eBand = prBssDesc->eBand; + prBssInfo->ucChnl = prBssDesc->ucChannelNum; + + //4 <2.F> RSN/WPA information. + secFsmRunEventStart(prAdapter); + prBssInfo->u4RsnSelectedPairwiseCipher = prBssDesc->u4RsnSelectedPairwiseCipher; + prBssInfo->u4RsnSelectedGroupCipher = prBssDesc->u4RsnSelectedGroupCipher; + prBssInfo->u4RsnSelectedAKMSuite = prBssDesc->u4RsnSelectedAKMSuite; + + if (secRsnKeyHandshakeEnabled()) { + prBssInfo->fgIsWPAorWPA2Enabled = TRUE; + } + else { + prBssInfo->fgIsWPAorWPA2Enabled = FALSE; + } + + //4 <2.G> Beacon interval. + prBssInfo->u2BeaconInterval = prBssDesc->u2BeaconInterval; + + //4 <2.H> DTIM period. + prBssInfo->ucDtimPeriod = prBssDesc->ucDTIMPeriod; + + //4 <2.I> ERP Information + if ((prBssInfo->ePhyType == PHY_TYPE_ERP_INDEX) && // Our BSS's PHY_TYPE is ERP now. + (prBssDesc->fgIsERPPresent)) { + + prBssInfo->fgIsERPPresent = TRUE; + prBssInfo->ucERP = prBssDesc->ucERP; /* Save the ERP for later check */ + } + else { /* Some AP, may send ProbeResp without ERP IE. Thus prBssDesc->fgIsERPPresent is FALSE. */ + prBssInfo->fgIsERPPresent = FALSE; + prBssInfo->ucERP = 0; + } + +#if CFG_SUPPORT_802_11D + //4 <2.J> Country inforamtion of the associated AP + if (prConnSettings->fgMultiDomainCapabilityEnabled) { + DOMAIN_INFO_ENTRY rDomainInfo; + if (domainGetDomainInfoByScanResult(prAdapter, &rDomainInfo)) { + if (prBssDesc->prIECountry) { + prIECountry = prBssDesc->prIECountry; + + domainParseCountryInfoElem(prIECountry, &prBssInfo->rDomainInfo); + + /* use the domain get from the BSS info */ + prBssInfo->fgIsCountryInfoPresent = TRUE; + nicSetupOpChnlList(prAdapter, prBssInfo->rDomainInfo.u2CountryCode, FALSE); + } else { + /* use the domain get from the scan result */ + prBssInfo->fgIsCountryInfoPresent = TRUE; + nicSetupOpChnlList(prAdapter, rDomainInfo.u2CountryCode, FALSE); + } + } + } +#endif + + //4 <2.K> Signal Power of the associated AP + prBssInfo->rRcpi = prBssDesc->rRcpi; + prBssInfo->rRssi = RCPI_TO_dBm(prBssInfo->rRcpi); + GET_CURRENT_SYSTIME(&prBssInfo->rRssiLastUpdateTime); + + //4 <2.L> Capability Field of the associated AP + prBssInfo->u2CapInfo = prBssDesc->u2CapInfo; + + DBGLOG(JOIN, INFO, ("prBssInfo-> fgIsERPPresent = %d, ucERP = %02x, rRcpi = %d, rRssi = %ld\n", + prBssInfo->fgIsERPPresent, prBssInfo->ucERP, prBssInfo->rRcpi, prBssInfo->rRssi)); + + +//4 <3> Update BSS_INFO_T from PEER_BSS_INFO_T & NIC RATE FUNC + //4 <3.A> Association ID + prBssInfo->u2AssocId = prPeerBssInfo->u2AssocId; + + //4 <3.B> WMM Infomation + if (prAdapter->fgIsEnableWMM && + (prPeerBssInfo->rWmmInfo.ucWmmFlag & WMM_FLAG_SUPPORT_WMM)) { + + prBssInfo->fgIsWmmAssoc = TRUE; + prTxCtrl->rTxQForVoipAccess = TXQ_AC3; + + qosWmmInfoInit(&prBssInfo->rWmmInfo, (prBssInfo->ePhyType == PHY_TYPE_HR_DSSS_INDEX) ? TRUE : FALSE); + + if (prPeerBssInfo->rWmmInfo.ucWmmFlag & WMM_FLAG_AC_PARAM_PRESENT) { + kalMemCopy(&prBssInfo->rWmmInfo, + &prPeerBssInfo->rWmmInfo, + sizeof(WMM_INFO_T)); + } + else { + kalMemCopy(&prBssInfo->rWmmInfo, + &prPeerBssInfo->rWmmInfo, + sizeof(WMM_INFO_T) - sizeof(prPeerBssInfo->rWmmInfo.arWmmAcParams)); + } + } + else { + prBssInfo->fgIsWmmAssoc = FALSE; + prTxCtrl->rTxQForVoipAccess = TXQ_AC1; + + kalMemZero(&prBssInfo->rWmmInfo, sizeof(WMM_INFO_T)); + } + + + //4 <3.C> Operational Rate Set & BSS Basic Rate Set + prBssInfo->u2OperationalRateSet = prPeerBssInfo->u2OperationalRateSet; + prBssInfo->u2BSSBasicRateSet = prPeerBssInfo->u2BSSBasicRateSet; + + + //4 <3.D> Short Preamble + if (prBssInfo->fgIsERPPresent) { + + /* NOTE(Kevin 2007/12/24): Truth Table. + * Short Preamble Bit in + * Final Driver Setting(Short) + * TRUE FALSE FALSE FALSE(shouldn't have such case, use the AssocResp) + * TRUE FALSE TRUE FALSE + * FALSE FALSE FALSE FALSE(shouldn't have such case, use the AssocResp) + * FALSE FALSE TRUE FALSE + * TRUE TRUE FALSE TRUE(follow ERP) + * TRUE TRUE TRUE FALSE(follow ERP) + * FALSE TRUE FALSE FALSE(shouldn't have such case, and we should set to FALSE) + * FALSE TRUE TRUE FALSE(we should set to FALSE) + */ + if ((prPeerBssInfo->fgIsShortPreambleAllowed) && + ((prConnSettings->ePreambleType == PREAMBLE_TYPE_SHORT) || /* Short Preamble Option Enable is TRUE */ + ((prConnSettings->ePreambleType == PREAMBLE_TYPE_AUTO) && + (prBssDesc->u2CapInfo & CAP_INFO_SHORT_PREAMBLE)))) { + + prBssInfo->fgIsShortPreambleAllowed = TRUE; + + if (prBssInfo->ucERP & ERP_INFO_BARKER_PREAMBLE_MODE) { + prBssInfo->fgUseShortPreamble = FALSE; + } + else { + prBssInfo->fgUseShortPreamble = TRUE; + } + } + else { + prBssInfo->fgIsShortPreambleAllowed = FALSE; + prBssInfo->fgUseShortPreamble = FALSE; + } + } + else { + /* NOTE(Kevin 2007/12/24): Truth Table. + * Short Preamble Bit in + * Final Driver Setting(Short) + * TRUE FALSE FALSE + * FALSE FALSE FALSE + * TRUE TRUE TRUE + * FALSE TRUE(status success) TRUE + * --> Honor the result of prPeerBssInfo. + */ + + prBssInfo->fgIsShortPreambleAllowed = prBssInfo->fgUseShortPreamble = + prPeerBssInfo->fgIsShortPreambleAllowed; + } + + DBGLOG(JOIN, INFO, ("prBssInfo->fgIsShortPreambleAllowed = %d, prBssInfo->fgUseShortPreamble = %d\n", + prBssInfo->fgIsShortPreambleAllowed, prBssInfo->fgUseShortPreamble)); + + + //4 <3.E> Short Slot Time + prBssInfo->fgUseShortSlotTime = + prPeerBssInfo->fgUseShortSlotTime; /* AP support Short Slot Time */ + + DBGLOG(JOIN, INFO, ("prBssInfo->fgUseShortSlotTime = %d\n", + prBssInfo->fgUseShortSlotTime)); + + nicSetSlotTime(prAdapter, + prBssInfo->ePhyType, + ((prConnSettings->fgIsShortSlotTimeOptionEnable && + prBssInfo->fgUseShortSlotTime) ? TRUE : FALSE)); + + + //4 <3.F> Update Tx Rate for Control Frame + bssUpdateTxRateForControlFrame(prAdapter); + + + //4 <3.G> Save the available Auth Types during Roaming (Design for Fast BSS Transition). + //if (prAdapter->fgIsEnableRoaming) /* NOTE(Kevin): Always prepare info for roaming */ + { + + if (prJoinInfo->ucCurrAuthAlgNum == AUTH_ALGORITHM_NUM_OPEN_SYSTEM) { + prJoinInfo->ucRoamingAuthTypes |= AUTH_TYPE_OPEN_SYSTEM; + } + else if (prJoinInfo->ucCurrAuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY) { + prJoinInfo->ucRoamingAuthTypes |= AUTH_TYPE_SHARED_KEY; + } + + prBssInfo->ucRoamingAuthTypes = prJoinInfo->ucRoamingAuthTypes; + + + /* Set the stable time of the associated BSS. We won't do roaming decision + * during the stable time. + */ + SET_EXPIRATION_TIME(prBssInfo->rRoamingStableExpirationTime, + SEC_TO_SYSTIME(ROAMING_STABLE_TIMEOUT_SEC)); + } + + + //4 <3.H> Update Parameter for TX Fragmentation Threshold +#if CFG_TX_FRAGMENT + txFragInfoUpdate(prAdapter); +#endif /* CFG_TX_FRAGMENT */ + + +//4 <4> Update STA_RECORD_T + /* Get a Station Record if possible */ + prStaRec = staRecGetStaRecordByAddr(prAdapter, + prBssDesc->aucBSSID); + + if (prStaRec) { + UINT_16 u2OperationalRateSet, u2DesiredRateSet; + + //4 <4.A> Desired Rate Set + u2OperationalRateSet = (rPhyAttributes[prBssInfo->ePhyType].u2SupportedRateSet & + prBssInfo->u2OperationalRateSet); + + u2DesiredRateSet = (u2OperationalRateSet & prConnSettings->u2DesiredRateSet); + if (u2DesiredRateSet) { + prStaRec->u2DesiredRateSet = u2DesiredRateSet; + } + else { + /* For Error Handling - The Desired Rate Set is not covered in Operational Rate Set. */ + prStaRec->u2DesiredRateSet = u2OperationalRateSet; + } + + /* Try to set the best initial rate for this entry */ + if (!rateGetBestInitialRateIndex(prStaRec->u2DesiredRateSet, + prStaRec->rRcpi, + &prStaRec->ucCurrRate1Index)) { + + if (!rateGetLowestRateIndexFromRateSet(prStaRec->u2DesiredRateSet, + &prStaRec->ucCurrRate1Index)) { + ASSERT(0); + } + } + + DBGLOG(JOIN, INFO, ("prStaRec->ucCurrRate1Index = %d\n", + prStaRec->ucCurrRate1Index)); + + //4 <4.B> Preamble Mode + prStaRec->fgIsShortPreambleOptionEnable = + prBssInfo->fgUseShortPreamble; + + //4 <4.C> QoS Flag + prStaRec->fgIsQoS = prBssInfo->fgIsWmmAssoc; + } +#if DBG + else { + ASSERT(0); + } +#endif /* DBG */ + + +//4 <5> Update NIC + //4 <5.A> Update BSSID & Operation Mode + nicSetupBSS(prAdapter, prBssInfo); + + //4 <5.B> Update WLAN Table. + if (nicSetHwBySta(prAdapter, prStaRec) == FALSE) { + ASSERT(FALSE); + } + + //4 <5.C> Update Desired Rate Set for BT. +#if CFG_TX_FRAGMENT + if (prConnSettings->fgIsEnableTxAutoFragmentForBT) { + txRateSetInitForBT(prAdapter, prStaRec); + } +#endif /* CFG_TX_FRAGMENT */ + + //4 <5.D> TX AC Parameter and TX/RX Queue Control + if (prBssInfo->fgIsWmmAssoc) { + +#if CFG_TX_AGGREGATE_HW_FIFO + nicTxAggregateTXQ(prAdapter, FALSE); +#endif /* CFG_TX_AGGREGATE_HW_FIFO */ + + qosUpdateWMMParametersAndAssignAllowedACI(prAdapter, &prBssInfo->rWmmInfo); + } + else { + +#if CFG_TX_AGGREGATE_HW_FIFO + nicTxAggregateTXQ(prAdapter, TRUE); +#endif /* CFG_TX_AGGREGATE_HW_FIFO */ + + nicTxNonQoSAssignDefaultAdmittedTXQ(prAdapter); + + nicTxNonQoSUpdateTXQParameters(prAdapter, + prBssInfo->ePhyType); + } + +#if CFG_TX_STOP_WRITE_TX_FIFO_UNTIL_JOIN + { + prTxCtrl->fgBlockTxDuringJoin = FALSE; + + #if !CFG_TX_AGGREGATE_HW_FIFO /* TX FIFO AGGREGATE already do flush once */ + nicTxFlushStopQueues(prAdapter, (UINT_8)TXQ_DATA_MASK, (UINT_8)NULL); + #endif /* CFG_TX_AGGREGATE_HW_FIFO */ + + nicTxRetransmitOfSendWaitQue(prAdapter); + + if (prTxCtrl->fgIsPacketInOsSendQueue) { + nicTxRetransmitOfOsSendQue(prAdapter); + } + + #if CFG_SDIO_TX_ENHANCE + halTxLeftClusteredMpdu(prAdapter); + #endif /* CFG_SDIO_TX_ENHANCE */ + + } +#endif /* CFG_TX_STOP_WRITE_TX_FIFO_UNTIL_JOIN */ + + +//4 <6> Setup CONNECTION flag. + prAdapter->eConnectionState = MEDIA_STATE_CONNECTED; + prAdapter->eConnectionStateIndicated = MEDIA_STATE_CONNECTED; + + if (prJoinInfo->fgIsReAssoc) { + prAdapter->fgBypassPortCtrlForRoaming = TRUE; + } + else { + prAdapter->fgBypassPortCtrlForRoaming = FALSE; + } + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_CONNECT, + (PVOID)NULL, + 0); + + return; +} /* end of joinComplete() */ +#endif + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/ais_fsm.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/ais_fsm.c new file mode 100755 index 000000000000..503d9fe072f0 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/ais_fsm.c @@ -0,0 +1,4582 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/mgmt/ais_fsm.c#2 $ +*/ + +/*! \file "aa_fsm.c" + \brief This file defines the FSM for SAA and AAA MODULE. + + This file defines the FSM for SAA and AAA MODULE. +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: ais_fsm.c $ + * + * 01 20 2012 cp.wu + * [ALPS00096191] [MT6620 Wi-Fi][Driver][Firmware] Porting to ALPS4.0_DEV branch + * sync to up-to-date changes including: + * 1. BOW bugfix + * 2. XLOG + * + * 01 16 2012 cp.wu + * [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band configuration with corresponding network configuration + * add wlanSetPreferBandByNetwork() for glue layer to invoke for setting preferred band configuration corresponding to network type. + * + * 11 24 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Adjust code for DBG and CONFIG_XLOG. + * + * 11 22 2011 cp.wu + * [WCXRP00001120] [MT6620 Wi-Fi][Driver] Modify roaming to AIS state transition from synchronous to asynchronous approach to avoid incomplete state termination + * 1. change RDD related compile option brace position. + * 2. when roaming is triggered, ask AIS to transit immediately only when AIS is in Normal TR state without join timeout timer ticking + * 3. otherwise, insert AIS_REQUEST into pending request queue + * + * 11 11 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * modify the xlog related code. + * + * 11 04 2011 cp.wu + * [WCXRP00001086] [MT6620 Wi-Fi][Driver] On Android, indicate an extra DISCONNECT for REASSOCIATED cases as an explicit trigger for Android framework + * correct reference to BSSID field in Association-Response frame. + * + * 11 04 2011 cp.wu + * [WCXRP00001086] [MT6620 Wi-Fi][Driver] On Android, indicate an extra DISCONNECT for REASSOCIATED cases as an explicit trigger for Android framework + * 1. for DEAUTH/DISASSOC cases, indicate for DISCONNECTION immediately. + * 2. (Android only) when reassociation-and-non-roaming cases happened, indicate an extra DISCONNECT indication to Android Wi-Fi framework + * + * 11 02 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Add XLOG related code and define. + * + * 10 26 2011 tsaiyuan.hsu + * [WCXRP00001064] [MT6620 Wi-Fi][DRV]] add code with roaming awareness when disconnecting AIS network + * be aware of roaming when disconnecting AIS network. + * + * 10 25 2011 cm.chang + * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode + * . + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 08 16 2011 tsaiyuan.hsu + * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver + * EnableRoaming in registry is deprecated . + * + * 08 16 2011 tsaiyuan.hsu + * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver + * use registry to enable or disable roaming. + * + * 07 07 2011 cp.wu + * [WCXRP00000840] [MT6620 Wi-Fi][Driver][AIS] Stop timer for joining when channel is released due to join failure count exceeding limit + * stop timer when joining operation is failed due to try count exceeds limitation + * + * 06 28 2011 cp.wu + * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID settings to work around some tricky AP which use space character as hidden SSID + * do not handle SCAN request immediately after connected to increase the probability of receiving 1st beacon frame. + * + * 06 23 2011 cp.wu + * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module + * follow-ups for frequency-shifted WAPI AP support + * + * 06 16 2011 cp.wu + * [WCXRP00000782] [MT6620 Wi-Fi][AIS] Treat connection at higher priority over scanning to avoid WZC connection timeout + * ensure DEAUTH is always sent before establish a new connection + * + * 06 16 2011 cp.wu + * [WCXRP00000782] [MT6620 Wi-Fi][AIS] Treat connection at higher priority over scanning to avoid WZC connection timeout + * typo fix: a right brace is missed. + * + * 06 16 2011 cp.wu + * [WCXRP00000782] [MT6620 Wi-Fi][AIS] Treat connection at higher priority over scanning to avoid WZC connection timeout + * When RECONNECT request is identified as disconnected, it is necessary to check for pending scan request. + * + * 06 16 2011 cp.wu + * [WCXRP00000757] [MT6620 Wi-Fi][Driver][SCN] take use of RLM API to filter out BSS in disallowed channels + * mark fgIsTransition as TRUE for state rolling. + * + * 06 16 2011 cp.wu + * [WCXRP00000782] [MT6620 Wi-Fi][AIS] Treat connection at higher priority over scanning to avoid WZC connection timeout + * always check for pending scan after switched into NORMAL_TR state. + * + * 06 14 2011 cp.wu + * [WCXRP00000782] [MT6620 Wi-Fi][AIS] Treat connection at higher priority over scanning to avoid WZC connection timeout + * always treat connection request at higher priority over scanning request + * + * 06 09 2011 tsaiyuan.hsu + * [WCXRP00000760] [MT5931 Wi-Fi][FW] Refine rxmHandleMacRxDone to reduce code size + * move send_auth at rxmHandleMacRxDone in firmware to driver to reduce code size. + * + * 05 18 2011 cp.wu + * [WCXRP00000732] [MT6620 Wi-Fi][AIS] No need to switch back to IDLE state when DEAUTH frame is dropped due to bss disconnection + * change SCAN handling behavior when followed by a CONNECT/DISCONNECT requests by pending instead of dropping. + * + * 05 17 2011 cp.wu + * [WCXRP00000732] [MT6620 Wi-Fi][AIS] No need to switch back to IDLE state when DEAUTH frame is dropped due to bss disconnection + * when TX DONE status is TX_RESULT_DROPPED_IN_DRIVER, no need to switch back to IDLE state. + * + * 04 14 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 04 13 2011 george.huang + * [WCXRP00000628] [MT6620 Wi-Fi][FW][Driver] Modify U-APSD setting to default OFF + * remove assert + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 18 2011 cp.wu + * [WCXRP00000575] [MT6620 Wi-Fi][Driver][AIS] reduce memory usage when generating mailbox message for scan request + * when there is no IE needed for probe request, then request a smaller memory for mailbox message + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 03 16 2011 tsaiyuan.hsu + * [WCXRP00000517] [MT6620 Wi-Fi][Driver][FW] Fine Tune Performance of Roaming + * remove obsolete definition and unused variables. + * + * 03 11 2011 cp.wu + * [WCXRP00000535] [MT6620 Wi-Fi][Driver] Fixed channel operation when AIS and Tethering are operating concurrently + * When fixed channel operation is necessary, AIS-FSM would scan and only connect for BSS on the specific channel + * + * 03 09 2011 tsaiyuan.hsu + * [WCXRP00000517] [MT6620 Wi-Fi][Driver][FW] Fine Tune Performance of Roaming + * avoid clearing fgIsScanReqIssued so as to add scan results. + * + * 03 07 2011 terry.wu + * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message + * Toggle non-standard debug messages to comments. + * + * 03 04 2011 tsaiyuan.hsu + * [WCXRP00000517] [MT6620 Wi-Fi][Driver][FW] Fine Tune Performance of Roaming + * reset retry conter of attemp to connect to ap after completion of join. + * + * 03 04 2011 cp.wu + * [WCXRP00000515] [MT6620 Wi-Fi][Driver] Surpress compiler warning which is identified by GNU compiler collection + * surpress compile warning occured when compiled by GNU compiler collection. + * + * 03 02 2011 cp.wu + * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right after connection is built. + * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. + * + * 02 26 2011 tsaiyuan.hsu + * [WCXRP00000391] [MT6620 Wi-Fi][FW] Add Roaming Support + * not send disassoc or deauth to leaving AP so as to improve performace of roaming. + * + * 02 23 2011 cp.wu + * [WCXRP00000487] [MT6620 Wi-Fi][Driver][AIS] Serve scan and connect request with a queue-based approach to improve response time for scanning request + * when handling reconnect request, set fgTryScan as TRUE + * + * 02 22 2011 cp.wu + * [WCXRP00000487] [MT6620 Wi-Fi][Driver][AIS] Serve scan and connect request with a queue-based approach to improve response time for scanning request + * handle SCAN and RECONNECT with a FIFO approach. + * + * 02 09 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * Check if prRegInfo is null or not before initializing roaming parameters. + * + * 02 01 2011 cp.wu + * [WCXRP00000416] [MT6620 Wi-Fi][Driver] treat "unable to find BSS" as connection trial to prevent infinite reconnection trials + * treat "unable to find BSS" as connection trial to prevent infinite reconnection trials. + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 01 26 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * . + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Fix Compile Error when DBG is disabled. + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. + * + * 01 14 2011 cp.wu + * [WCXRP00000359] [MT6620 Wi-Fi][Driver] add an extra state to ensure DEAUTH frame is always sent + * Add an extra state to guarantee DEAUTH frame is sent then connect to new BSS. + * This change is due to WAPI AP needs DEAUTH frame as a necessary step in handshaking protocol. + * + * 01 11 2011 cp.wu + * [WCXRP00000307] [MT6620 Wi-Fi][SQA]WHQL test .2c_wlan_adhoc case fail. + * [IBSS] when merged in, the bss state should be updated to firmware to pass WHQL adhoc failed item + * + * 01 10 2011 cp.wu + * [WCXRP00000351] [MT6620 Wi-Fi][Driver] remove from scanning result in OID handling layer when the corresponding BSS is disconnected due to beacon timeout + * remove from scanning result when the BSS is disconnected due to beacon timeout. + * + * 01 03 2011 cp.wu + * [WCXRP00000337] [MT6620 Wi-FI][Driver] AIS-FSM not to invoke cnmStaRecResetStatus directly 'cause it frees all belonging STA-RECs + * do not invoke cnmStaRecResetStatus() directly, nicUpdateBss will do the things after bss is disconnected + * + * 12 30 2010 cp.wu + * [WCXRP00000270] [MT6620 Wi-Fi][Driver] Clear issues after concurrent networking support has been merged + * do not need to manipulate prStaRec after indicating BSS disconnection to firmware, 'cause all STA-RECs belongs to BSS has been freed already + * + * 12 27 2010 cp.wu + * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release + * add DEBUGFUNC() macro invoking for more detailed debugging information + * + * 12 23 2010 george.huang + * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function + * 1. update WMM IE parsing, with ASSOC REQ handling + * 2. extend U-APSD parameter passing from driver to FW + * + * 12 17 2010 cp.wu + * [WCXRP00000270] [MT6620 Wi-Fi][Driver] Clear issues after concurrent networking support has been merged + * before BSS disconnection is indicated to firmware, all correlated peer should be cleared and freed + * + * 12 07 2010 cm.chang + * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk + * 1. BSSINFO include RLM parameter + * 2. free all sta records when network is disconnected + * + * 11 25 2010 yuche.tsai + * NULL + * Update SLT Function for QoS Support and not be affected by fixed rate function. + * + * 11 25 2010 cp.wu + * [WCXRP00000208] [MT6620 Wi-Fi][Driver] Add scanning with specified SSID to AIS FSM + * add scanning with specified SSID facility to AIS-FSM + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 10 26 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command + * 1) update NVRAM content template to ver 1.02 + * 2) add compile option for querying NIC capability (default: off) + * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting + * 4) correct auto-rate compiler error under linux (treat warning as error) + * 5) simplify usage of NVRAM and REG_INFO_T + * 6) add version checking between driver and firmware + * + * 10 14 2010 wh.su + * [WCXRP00000097] [MT6620 Wi-Fi] [Driver] Fixed the P2P not setting the fgIsChannelExt value make scan not abort + * initial the fgIsChannelExt value. + * + * 10 08 2010 cp.wu + * [WCXRP00000087] [MT6620 Wi-Fi][Driver] Cannot connect to 5GHz AP, driver will cause FW assert. + * correct erroneous logic: specifying eBand with incompatible eSco + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by ENUM_NETWORK_TYPE_INDEX_T only + * remove ENUM_NETWORK_TYPE_T definitions + * + * 09 27 2010 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings + * Update BCM/BoW design and settings. + * + * 09 23 2010 cp.wu + * [WCXRP00000049] [MT6620 Wi-Fi][Driver] Adhoc cannot be created successfully. + * keep IBSS-ALONE state retrying until further instruction is received + * + * 09 21 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS associated + * Do a complete reset with STA-REC null checking for RF test re-entry + * + * 09 09 2010 yuche.tsai + * NULL + * Fix NULL IE Beacon issue. Sync Beacon Content to FW before enable beacon. + * Both in IBSS Create & IBSS Merge + * + * 09 09 2010 cp.wu + * NULL + * frequency is in unit of KHz thus no need to divide 1000 once more. + * + * 09 06 2010 cp.wu + * NULL + * 1) initialize for correct parameter even for disassociation. + * 2) AIS-FSM should have a limit on trials to build connection + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 29 2010 yuche.tsai + * NULL + * Finish SLT TX/RX & Rate Changing Support. + * + * 08 25 2010 cp.wu + * NULL + * add option for enabling AIS 5GHz scan + * + * 08 25 2010 cp.wu + * NULL + * [AIS-FSM] IBSS no longer needs to acquire channel for beaconing, RLM/CNM will handle the channel switching when BSS information is updated + * + * 08 25 2010 george.huang + * NULL + * update OID/ registry control path for PM related settings + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 08 20 2010 cm.chang + * NULL + * Migrate RLM code to host from FW + * + * 08 12 2010 cp.wu + * NULL + * check-in missed files. + * + * 08 12 2010 kevin.huang + * NULL + * Refine bssProcessProbeRequest() and bssSendBeaconProbeResponse() + * + * 08 09 2010 cp.wu + * NULL + * reset fgIsScanReqIssued when abort request is received right after join completion. + * + * 08 03 2010 cp.wu + * NULL + * surpress compilation warning. + * + * 08 02 2010 cp.wu + * NULL + * comment out deprecated members in BSS_INFO, which are only used by firmware rather than driver. + * + * 07 30 2010 cp.wu + * NULL + * 1) BoW wrapper: use definitions instead of hard-coded constant for error code + * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead + * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames + * + * 07 29 2010 cp.wu + * NULL + * eliminate u4FreqInKHz usage, combined into rConnections.ucAdHoc* + * + * 07 29 2010 cp.wu + * NULL + * allocate on MGMT packet for IBSS beaconing. + * + * 07 29 2010 cp.wu + * NULL + * [AIS-FSM] fix: when join failed, release channel privilege as well + * + * 07 28 2010 cp.wu + * NULL + * reuse join-abort sub-procedure to reduce code size. + * + * 07 28 2010 cp.wu + * NULL + * 1) eliminate redundant variable eOPMode in prAdapter->rWlanInfo + * 2) change nicMediaStateChange() API prototype + * + * 07 26 2010 cp.wu + * + * AIS-FSM: when scan request is coming in the 1st 5 seconds of channel privilege period, just pend it til 5-sec. period finishes + * + * 07 26 2010 cp.wu + * + * AIS-FSM FIX: return channel privilege even when the privilege is not granted yet + * QM: qmGetFrameAction() won't assert when corresponding STA-REC index is not found + * + * 07 26 2010 cp.wu + * + * re-commit code logic being overwriten. + * + * 07 24 2010 wh.su + * + * .support the Wi-Fi RSN + * + * 07 23 2010 cp.wu + * + * 1) re-enable AIS-FSM beacon timeout handling. + * 2) scan done API revised + * + * 07 23 2010 cp.wu + * + * 1) enable Ad-Hoc + * 2) disable beacon timeout handling temporally due to unexpected beacon timeout event. + * + * 07 23 2010 cp.wu + * + * indicate scan done for linux wireless extension + * + * 07 23 2010 cp.wu + * + * add AIS-FSM handling for beacon timeout event. + * + * 07 22 2010 cp.wu + * + * 1) refine AIS-FSM indent. + * 2) when entering RF Test mode, flush 802.1X frames as well + * 3) when entering D3 state, flush 802.1X frames as well + * + * 07 21 2010 cp.wu + * + * separate AIS-FSM states into different cases of channel request. + * + * 07 21 2010 cp.wu + * + * 1) change BG_SCAN to ONLINE_SCAN for consistent term + * 2) only clear scanning result when scan is permitted to do + * + * 07 20 2010 cp.wu + * + * 1) [AIS] when new scan is issued, clear currently available scanning result except the connected one + * 2) refine disconnection behaviour when issued during BG-SCAN process + * + * 07 20 2010 cp.wu + * + * 1) bugfix: do not stop timer for join after switched into normal_tr state, for providing chance for DHCP handshasking + * 2) modify rsnPerformPolicySelection() invoking + * + * 07 19 2010 cp.wu + * + * 1) init AIS_BSS_INFO as channel number = 1 with band = 2.4GHz + * 2) correct typo + * + * 07 19 2010 wh.su + * + * update for security supporting. + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * when IBSS is being merged-in, send command packet to PM for connected indication + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * Add Ad-Hoc support to AIS-FSM + * + * 07 19 2010 jeffrey.chang + * + * Linux port modification + * + * 07 16 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * bugfix for SCN migration + * 1) modify QUEUE_CONCATENATE_QUEUES() so it could be used to concatence with an empty queue + * 2) before AIS issues scan request, network(BSS) needs to be activated first + * 3) only invoke COPY_SSID when using specified SSID for scan + * + * 07 15 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * for AIS scanning, driver specifies no extra IE for probe request + * + * 07 15 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * driver no longer generates probe request frames + * + * 07 14 2010 yarco.yang + * + * Remove CFG_MQM_MIGRATION + * + * 07 14 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * Refine AIS-FSM by divided into more states + * + * 07 13 2010 cm.chang + * + * Rename MSG_CH_RELEASE_T to MSG_CH_ABORT_T + * + * 07 09 2010 cp.wu + * + * 1) separate AIS_FSM state for two kinds of scanning. (OID triggered scan, and scan-for-connection) + * 2) eliminate PRE_BSS_DESC_T, Beacon/PrebResp is now parsed in single pass + * 3) implment DRV-SCN module, currently only accepts single scan request, other request will be directly dropped by returning BUSY + * + * 07 09 2010 george.huang + * + * [WPD00001556] Migrate PM variables from FW to driver: for composing QoS Info + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * take use of RLM module for parsing/generating HT IEs for 11n capability + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Rename MID_MNY_CNM_CH_RELEASE to MID_MNY_CNM_CH_ABORT + * + * 07 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * for first connection, if connecting failed do not enter into scan state. + * + * 07 06 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * once STA-REC is allocated and updated, invoke cnmStaRecChangeState() to sync. with firmware. + * + * 07 06 2010 george.huang + * [WPD00001556]Basic power managemenet function + * Update arguments for nicUpdateBeaconIETemplate() + * + * 07 06 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * STA-REC is maintained by CNM only. + * + * 07 05 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * remove unused definitions. + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * AIS-FSM integration with CNM channel request messages + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implementation of DRV-SCN and related mailbox message handling. + * + * 06 30 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * sync. with CMD/EVENT document ver0.07. + * + * 06 29 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) sync to. CMD/EVENT document v0.03 + * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. + * 3) send command packet to indicate FW-PM after + * a) 1st beacon is received after AIS has connected to an AP + * b) IBSS-ALONE has been created + * c) IBSS-MERGE has occured + * + * 06 25 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * modify Beacon/ProbeResp to complete parsing, + * because host software has looser memory usage restriction + * + * 06 23 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * integrate . + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * comment out RLM APIs by CFG_RLM_MIGRATION. + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add command warpper for STA-REC/BSS-INFO sync. + * 2) enhance command packet sending procedure for non-oid part + * 3) add command packet definitions for STA-REC/BSS-INFO sync. + * + * 06 21 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Support CFG_MQM_MIGRATION flag + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add scan_fsm into building. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * RSN/PRIVACY compilation flag awareness correction + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration from MT6620 firmware. + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add scan.c. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * restore utility function invoking via hem_mbox to direct calls + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * auth.c is migrated. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add bss.c. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * change to enqueue TX frame infinitely. + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 + * 2) when disconnected, indicate nic directly (no event is needed) + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add buildable & linkable ais_fsm.c + * + * related reference are still waiting to be resolved + * + * 06 01 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add conditionial compiling flag to choose default available bandwidth + * + * 05 28 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add ClientList handling API - bssClearClientList, bssAddStaRecToClientList + * + * 05 24 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Refine authSendAuthFrame() for NULL STA_RECORD_T case and minimum deauth interval. + * + * 05 21 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Fix compile error if CFG_CMD_EVENT_VER_009 == 0 for prEventConnStatus->ucNetworkType. + * + * 05 21 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Refine txmInitWtblTxRateTable() - set TX initial rate according to AP's operation rate set + * + * 05 17 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Call pmAbort() and add ucNetworkType field in EVENT_CONNECTION_STATUS + * + * 05 14 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Fix compile warning - define of MQM_WMM_PARSING was removed + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 04 28 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * Removed the use of compiling flag MQM_WMM_PARSING + * + * 04 27 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * + * Fix typo + * + * 04 27 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add Set Slot Time and Beacon Timeout Support for AdHoc Mode + * + * 04 19 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * Add Send Deauth for Class 3 Error and Leave Network Support + * + * 04 15 2010 wh.su + * [BORA00000680][MT6620] Support the statistic for Microsoft os query + * fixed the protected bit at cap info for ad-hoc. + * + * 04 13 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add new HW CH macro support + * + * 04 07 2010 chinghwa.yu + * [BORA00000563]Add WiFi CoEx BCM module + * Add TX Power Control RCPI function. + * + * 03 29 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * move the wlan table alloc / free to change state function. + * + * 03 25 2010 wh.su + * [BORA00000676][MT6620] Support the frequency setting and query at build connection / connection event + * modify the build connection and status event structure bu CMD_EVENT doc 0.09 draft, default is disable. + * + * 03 24 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * fixed some WHQL testing error. + * + * 03 24 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * Add Set / Unset POWER STATE in AIS Network + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 03 10 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * Add Channel Manager for arbitration of JOIN and SCAN Req + * + * 03 03 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add PHY_CONFIG to change Phy Type + * + * 03 03 2010 chinghwa.yu + * [BORA00000563]Add WiFi CoEx BCM module + * Use bcmWiFiNotify to replace wifi_send_msg to pass infomation to BCM module. + * + * 03 03 2010 chinghwa.yu + * [BORA00000563]Add WiFi CoEx BCM module + * Remove wmt_task definition and add PTA function. + * + * 03 02 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Init TXM and MQM testing procedures in aisFsmRunEventJoinComplete() + * + * 03 01 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Modified aisUpdateBssInfo() to call TXM's functions for setting WTBL TX parameters + * + * 03 01 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * clear the pmkid cache while indicate media disconnect. + * + * 02 26 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * . + * + * 02 26 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Enabled MQM parsing WMM IEs for non-AP mode + * + * 02 26 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Remove CFG_TEST_VIRTUAL_CMD and add support of Driver STA_RECORD_T activation + * + * 02 25 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * use the Rx0 dor event indicate. + * + * 02 23 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Support dynamic channel selection + * + * 02 23 2010 wh.su + * [BORA00000621][MT6620 Wi-Fi] Add the RSSI indicate to avoid XP stalled for query rssi value + * Adding the RSSI event support, using the HAL function to get the rcpi value and tranlsate to RSSI and indicate to driver + * + * 02 12 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Use bss info array for concurrent handle + * + * 02 05 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Revise data structure to share the same BSS_INFO_T for avoiding coding error + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * 01 27 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Set max AMDPU size supported by the peer to 64 KB, removed mqmInit() and mqmTxSendAddBaReq() function calls in aisUpdateBssInfo() + * + * 01 27 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * add and fixed some security function. + * + * 01 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support protection and bandwidth switch + * + * 01 20 2010 kevin.huang + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Add PHASE_2_INTEGRATION_WORK_AROUND and CFG_SUPPORT_BCM flags + * + * 01 15 2010 tehuang.liu + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Configured the AMPDU factor to 3 for the APu1rwduu`wvpghlqg|q`mpdkb+ilp + * + * 01 14 2010 chinghwa.yu + * [BORA00000563]Add WiFi CoEx BCM module + * Add WiFi BCM module for the 1st time. + * + * 01 11 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add Deauth and Disassoc Handler + * + * 01 07 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * Refine JOIN Complete and seperate the function of Media State indication + * + * 01 04 2010 tehuang.liu + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * For working out the first connection Chariot-verified version + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Dec 10 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the sample code to update the wlan table rate, + * + * Dec 10 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Different function prototype of wifi_send_msg() + * + * Dec 9 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Call rlm related function to process HT info when join complete + * + * Dec 9 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * default the acquired wlan table entry code off + * + * Dec 9 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the code to acquired the wlan table entry, and a sample code to update the BA bit at table + * + * Dec 7 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix the problem of prSwRfb overwrited by event packet in aisFsmRunEventJoinComplete() + * + * Dec 4 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the code to integrate the security related code + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Remove redundant declaration + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add code for JOIN init and JOIN complete + * + * Nov 30 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Rename u4RSSI to i4RSSI + * + * Nov 30 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Revise ENUM_MEDIA_STATE to ENUM_PARAM_MEDIA_STATE + * + * Nov 30 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add fgIsScanReqIssued to CONNECTION_SETTINGS_T + * + * Nov 26 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Revise Virtual CMD handler due to structure changed + * + * Nov 25 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add Virtual CMD & RESP for testing CMD PATH + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add aisFsmInitializeConnectionSettings() + * + * Nov 20 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add CFG_TEST_MGMT_FSM flag for aisFsmTest() + * + * Nov 16 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define AIS_ROAMING_CONNECTION_TRIAL_LIMIT 2 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +#if DBG +/*lint -save -e64 Type mismatch */ +static PUINT_8 apucDebugAisState[AIS_STATE_NUM] = { + (PUINT_8)DISP_STRING("AIS_STATE_IDLE"), + (PUINT_8)DISP_STRING("AIS_STATE_SEARCH"), + (PUINT_8)DISP_STRING("AIS_STATE_SCAN"), + (PUINT_8)DISP_STRING("AIS_STATE_ONLINE_SCAN"), + (PUINT_8)DISP_STRING("AIS_STATE_LOOKING_FOR"), + (PUINT_8)DISP_STRING("AIS_STATE_WAIT_FOR_NEXT_SCAN"), + (PUINT_8)DISP_STRING("AIS_STATE_REQ_CHANNEL_JOIN"), + (PUINT_8)DISP_STRING("AIS_STATE_JOIN"), + (PUINT_8)DISP_STRING("AIS_STATE_IBSS_ALONE"), + (PUINT_8)DISP_STRING("AIS_STATE_IBSS_MERGE"), + (PUINT_8)DISP_STRING("AIS_STATE_NORMAL_TR"), + (PUINT_8)DISP_STRING("AIS_STATE_DISCONNECTING") +}; +/*lint -restore */ +#endif /* DBG */ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief the function is used to initialize the value of the connection settings for +* AIS network +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisInitializeConnectionSettings ( + IN P_ADAPTER_T prAdapter, + IN P_REG_INFO_T prRegInfo + ) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + UINT_8 aucAnyBSSID[] = BC_BSSID; + UINT_8 aucZeroMacAddr[] = NULL_MAC_ADDR; + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + /* Setup default values for operation */ + COPY_MAC_ADDR(prConnSettings->aucMacAddress, aucZeroMacAddr); + + prConnSettings->ucDelayTimeOfDisconnectEvent = AIS_DELAY_TIME_OF_DISCONNECT_SEC; + + COPY_MAC_ADDR(prConnSettings->aucBSSID, aucAnyBSSID); + prConnSettings->fgIsConnByBssidIssued = FALSE; + + prConnSettings->fgIsConnReqIssued = FALSE; + + prConnSettings->ucSSIDLen = 0; + + prConnSettings->eOPMode = NET_TYPE_INFRA; + + prConnSettings->eConnectionPolicy = CONNECT_BY_SSID_BEST_RSSI; + + if(prRegInfo) { + prConnSettings->ucAdHocChannelNum = (UINT_8) nicFreq2ChannelNum(prRegInfo->u4StartFreq); + prConnSettings->eAdHocBand = prRegInfo->u4StartFreq < 5000000 ? BAND_2G4 : BAND_5G; + prConnSettings->eAdHocMode = (ENUM_PARAM_AD_HOC_MODE_T) (prRegInfo->u4AdhocMode); + } + + prConnSettings->eAuthMode = AUTH_MODE_OPEN; + + prConnSettings->eEncStatus = ENUM_ENCRYPTION_DISABLED; + + prConnSettings->fgIsScanReqIssued = FALSE; + + /* MIB attributes */ + prConnSettings->u2BeaconPeriod = DOT11_BEACON_PERIOD_DEFAULT; + + prConnSettings->u2RTSThreshold = DOT11_RTS_THRESHOLD_DEFAULT; + + prConnSettings->u2DesiredNonHTRateSet = RATE_SET_ALL_ABG; + + //prConnSettings->u4FreqInKHz; /* Center frequency */ + + + /* Set U-APSD AC */ + prConnSettings->bmfgApsdEnAc = PM_UAPSD_NONE; + + secInit(prAdapter, NETWORK_TYPE_AIS_INDEX); + + /* Features */ + prConnSettings->fgIsEnableRoaming = FALSE; +#if CFG_SUPPORT_ROAMING + if(prRegInfo) { + prConnSettings->fgIsEnableRoaming = ((prRegInfo->fgDisRoaming > 0)?(FALSE):(TRUE)); + } +#endif /* CFG_SUPPORT_ROAMING */ + + prConnSettings->fgIsAdHocQoSEnable = FALSE; + + prConnSettings->eDesiredPhyConfig = PHY_CONFIG_802_11ABGN; + + /* Set default bandwidth modes */ + prConnSettings->uc2G4BandwidthMode = CONFIG_BW_20M; + prConnSettings->uc5GBandwidthMode = CONFIG_BW_20_40M; + + return; +} /* end of aisFsmInitializeConnectionSettings() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief the function is used to initialize the value in AIS_FSM_INFO_T for +* AIS FSM operation +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmInit ( + IN P_ADAPTER_T prAdapter + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecificBssInfo; + + DEBUGFUNC("aisFsmInit()"); + DBGLOG(SW1, INFO, ("->aisFsmInit()\n")); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prAisSpecificBssInfo = &(prAdapter->rWifiVar.rAisSpecificBssInfo); + + //4 <1> Initiate FSM + prAisFsmInfo->ePreviousState = AIS_STATE_IDLE; + prAisFsmInfo->eCurrentState = AIS_STATE_IDLE; + + prAisFsmInfo->ucAvailableAuthTypes = 0; + + prAisFsmInfo->prTargetBssDesc = (P_BSS_DESC_T)NULL; + + prAisFsmInfo->ucSeqNumOfReqMsg = 0; + prAisFsmInfo->ucSeqNumOfChReq = 0; + prAisFsmInfo->ucSeqNumOfScanReq = 0; + + prAisFsmInfo->fgIsInfraChannelFinished = TRUE; +#if CFG_SUPPORT_ROAMING + prAisFsmInfo->fgIsRoamingScanPending = FALSE; +#endif /* CFG_SUPPORT_ROAMING */ + prAisFsmInfo->fgIsChannelRequested = FALSE; + prAisFsmInfo->fgIsChannelGranted = FALSE; + + //4 <1.1> Initiate FSM - Timer INIT + cnmTimerInitTimer(prAdapter, + &prAisFsmInfo->rBGScanTimer, + (PFN_MGMT_TIMEOUT_FUNC)aisFsmRunEventBGSleepTimeOut, + (UINT_32)NULL); + + cnmTimerInitTimer(prAdapter, + &prAisFsmInfo->rIbssAloneTimer, + (PFN_MGMT_TIMEOUT_FUNC)aisFsmRunEventIbssAloneTimeOut, + (UINT_32)NULL); + + cnmTimerInitTimer(prAdapter, + &prAisFsmInfo->rIndicationOfDisconnectTimer, + (PFN_MGMT_TIMEOUT_FUNC)aisPostponedEventOfDisconnTimeout, + (UINT_32)NULL); + + cnmTimerInitTimer(prAdapter, + &prAisFsmInfo->rJoinTimeoutTimer, + (PFN_MGMT_TIMEOUT_FUNC)aisFsmRunEventJoinTimeout, + (UINT_32)NULL); + + //4 <1.2> Initiate PWR STATE + SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_AIS_INDEX); + + + //4 <2> Initiate BSS_INFO_T - common part + BSS_INFO_INIT(prAdapter, NETWORK_TYPE_AIS_INDEX); + COPY_MAC_ADDR(prAisBssInfo->aucOwnMacAddr, prAdapter->rWifiVar.aucMacAddress); + + //4 <3> Initiate BSS_INFO_T - private part + /* TODO */ + prAisBssInfo->eBand = BAND_2G4; + prAisBssInfo->ucPrimaryChannel = 1; + prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T)NULL; + + //4 <4> Allocate MSDU_INFO_T for Beacon + prAisBssInfo->prBeacon = cnmMgtPktAlloc(prAdapter, + OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem[0]) + MAX_IE_LENGTH); + + if (prAisBssInfo->prBeacon) { + prAisBssInfo->prBeacon->eSrc = TX_PACKET_MGMT; + prAisBssInfo->prBeacon->ucStaRecIndex = 0xFF; /* NULL STA_REC */ + } + else { + ASSERT(0); + } + +#if 0 + prAisBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC = PM_UAPSD_ALL; + prAisBssInfo->rPmProfSetupInfo.ucBmpTriggerAC = PM_UAPSD_ALL; + prAisBssInfo->rPmProfSetupInfo.ucUapsdSp = WMM_MAX_SP_LENGTH_2; +#else + if (prAdapter->u4UapsdAcBmp == 0) { + prAdapter->u4UapsdAcBmp = CFG_INIT_UAPSD_AC_BMP; + //ASSERT(prAdapter->u4UapsdAcBmp); + } + prAisBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC = (UINT_8)prAdapter->u4UapsdAcBmp; + prAisBssInfo->rPmProfSetupInfo.ucBmpTriggerAC =(UINT_8) prAdapter->u4UapsdAcBmp; + prAisBssInfo->rPmProfSetupInfo.ucUapsdSp = (UINT_8)prAdapter->u4MaxSpLen; +#endif + + /* request list initialization */ + LINK_INITIALIZE(&prAisFsmInfo->rPendingReqList); + + //DBGPRINTF("[2] ucBmpDeliveryAC:0x%x, ucBmpTriggerAC:0x%x, ucUapsdSp:0x%x", + //prAisBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC, + //prAisBssInfo->rPmProfSetupInfo.ucBmpTriggerAC, + //prAisBssInfo->rPmProfSetupInfo.ucUapsdSp); + + return; +} /* end of aisFsmInit() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief the function is used to uninitialize the value in AIS_FSM_INFO_T for +* AIS FSM operation +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmUninit ( + IN P_ADAPTER_T prAdapter + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecificBssInfo; + + DEBUGFUNC("aisFsmUninit()"); + DBGLOG(SW1, INFO, ("->aisFsmUninit()\n")); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prAisSpecificBssInfo = &(prAdapter->rWifiVar.rAisSpecificBssInfo); + + //4 <1> Stop all timers + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rBGScanTimer); + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rIbssAloneTimer); + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rIndicationOfDisconnectTimer); + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rJoinTimeoutTimer); + + //4 <2> flush pending request + aisFsmFlushRequest(prAdapter); + + //4 <3> Reset driver-domain BSS-INFO + if(prAisBssInfo->prBeacon) { + cnmMgtPktFree(prAdapter, prAisBssInfo->prBeacon); + prAisBssInfo->prBeacon = NULL; + } + +#if CFG_SUPPORT_802_11W + rsnStopSaQuery(prAdapter); +#endif + + return; +} /* end of aisFsmUninit() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Initialization of JOIN STATE +* +* @param[in] prBssDesc The pointer of BSS_DESC_T which is the BSS we will try to join with. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmStateInit_JOIN ( + IN P_ADAPTER_T prAdapter, + P_BSS_DESC_T prBssDesc + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecificBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_STA_RECORD_T prStaRec; + P_MSG_JOIN_REQ_T prJoinReqMsg; + + DEBUGFUNC("aisFsmStateInit_JOIN()"); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prAisSpecificBssInfo = &(prAdapter->rWifiVar.rAisSpecificBssInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + ASSERT(prBssDesc); + + //4 <1> We are going to connect to this BSS. + prBssDesc->fgIsConnecting = TRUE; + + + //4 <2> Setup corresponding STA_RECORD_T + prStaRec = bssCreateStaRecFromBssDesc(prAdapter, + STA_TYPE_LEGACY_AP, + NETWORK_TYPE_AIS_INDEX, + prBssDesc); + + prAisFsmInfo->prTargetStaRec = prStaRec; + + //4 <2.1> sync. to firmware domain + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + + //4 <3> Update ucAvailableAuthTypes which we can choice during SAA + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { + + prStaRec->fgIsReAssoc = FALSE; + + switch (prConnSettings->eAuthMode) { + case AUTH_MODE_OPEN: /* Note: Omit break here. */ + case AUTH_MODE_WPA: + case AUTH_MODE_WPA_PSK: + case AUTH_MODE_WPA2: + case AUTH_MODE_WPA2_PSK: + prAisFsmInfo->ucAvailableAuthTypes = (UINT_8)AUTH_TYPE_OPEN_SYSTEM; + break; + + + case AUTH_MODE_SHARED: + prAisFsmInfo->ucAvailableAuthTypes = (UINT_8)AUTH_TYPE_SHARED_KEY; + break; + + + case AUTH_MODE_AUTO_SWITCH: + DBGLOG(AIS, LOUD, ("JOIN INIT: eAuthMode == AUTH_MODE_AUTO_SWITCH\n")); + prAisFsmInfo->ucAvailableAuthTypes = (UINT_8)(AUTH_TYPE_OPEN_SYSTEM | + AUTH_TYPE_SHARED_KEY); + break; + + default: + ASSERT(!(prConnSettings->eAuthMode == AUTH_MODE_WPA_NONE)); + DBGLOG(AIS, ERROR, ("JOIN INIT: Auth Algorithm : %d was not supported by JOIN\n", + prConnSettings->eAuthMode)); + /* TODO(Kevin): error handling ? */ + return; + } + + /* TODO(tyhsu): Assume that Roaming Auth Type is equal to ConnSettings eAuthMode */ + prAisSpecificBssInfo->ucRoamingAuthTypes = prAisFsmInfo->ucAvailableAuthTypes; + + prStaRec->ucTxAuthAssocRetryLimit = TX_AUTH_ASSOCI_RETRY_LIMIT; + + } + else { + ASSERT(prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE); + ASSERT(!prBssDesc->fgIsConnected); + + DBGLOG(AIS, LOUD, ("JOIN INIT: AUTH TYPE = %d for Roaming\n", + prAisSpecificBssInfo->ucRoamingAuthTypes)); + + + prStaRec->fgIsReAssoc = TRUE; /* We do roaming while the medium is connected */ + + /* TODO(Kevin): We may call a sub function to acquire the Roaming Auth Type */ + prAisFsmInfo->ucAvailableAuthTypes = prAisSpecificBssInfo->ucRoamingAuthTypes; + + prStaRec->ucTxAuthAssocRetryLimit = TX_AUTH_ASSOCI_RETRY_LIMIT_FOR_ROAMING; + } + + + //4 <4> Use an appropriate Authentication Algorithm Number among the ucAvailableAuthTypes + if (prAisFsmInfo->ucAvailableAuthTypes & + (UINT_8)AUTH_TYPE_OPEN_SYSTEM) { + + DBGLOG(AIS, LOUD, ("JOIN INIT: Try to do Authentication with AuthType == OPEN_SYSTEM.\n")); + prAisFsmInfo->ucAvailableAuthTypes &= + ~(UINT_8)AUTH_TYPE_OPEN_SYSTEM; + + prStaRec->ucAuthAlgNum = (UINT_8)AUTH_ALGORITHM_NUM_OPEN_SYSTEM; + } + else if (prAisFsmInfo->ucAvailableAuthTypes & + (UINT_8)AUTH_TYPE_SHARED_KEY) { + + DBGLOG(AIS, LOUD, ("JOIN INIT: Try to do Authentication with AuthType == SHARED_KEY.\n")); + + prAisFsmInfo->ucAvailableAuthTypes &= + ~(UINT_8)AUTH_TYPE_SHARED_KEY; + + prStaRec->ucAuthAlgNum = (UINT_8)AUTH_ALGORITHM_NUM_SHARED_KEY; + } + else if (prAisFsmInfo->ucAvailableAuthTypes & + (UINT_8)AUTH_TYPE_FAST_BSS_TRANSITION) { + + DBGLOG(AIS, LOUD, ("JOIN INIT: Try to do Authentication with AuthType == FAST_BSS_TRANSITION.\n")); + + prAisFsmInfo->ucAvailableAuthTypes &= + ~(UINT_8)AUTH_TYPE_FAST_BSS_TRANSITION; + + prStaRec->ucAuthAlgNum = (UINT_8)AUTH_ALGORITHM_NUM_FAST_BSS_TRANSITION; + } + else { + ASSERT(0); + } + + //4 <5> Overwrite Connection Setting for eConnectionPolicy == ANY (Used by Assoc Req) + if (prConnSettings->eConnectionPolicy == CONNECT_BY_SSID_ANY) { + + if (prBssDesc->ucSSIDLen) { + COPY_SSID(prConnSettings->aucSSID, + prConnSettings->ucSSIDLen, + prBssDesc->aucSSID, + prBssDesc->ucSSIDLen); + } + } + + //4 <6> Send a Msg to trigger SAA to start JOIN process. + prJoinReqMsg = (P_MSG_JOIN_REQ_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_REQ_T)); + if (!prJoinReqMsg) { + + ASSERT(0); // Can't trigger SAA FSM + return; + } + + prJoinReqMsg->rMsgHdr.eMsgId = MID_AIS_SAA_FSM_START; + prJoinReqMsg->ucSeqNum = ++prAisFsmInfo->ucSeqNumOfReqMsg; + prJoinReqMsg->prStaRec = prStaRec; + + if (1) { + int j; + P_FRAG_INFO_T prFragInfo; + for (j = 0; j < MAX_NUM_CONCURRENT_FRAGMENTED_MSDUS; j++) { + prFragInfo = &prStaRec->rFragInfo[j]; + + if (prFragInfo->pr1stFrag) { + //nicRxReturnRFB(prAdapter, prFragInfo->pr1stFrag); + prFragInfo->pr1stFrag = (P_SW_RFB_T)NULL; + } + } + } + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prJoinReqMsg, + MSG_SEND_METHOD_BUF); + + return; +} /* end of aisFsmInit_JOIN() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Retry JOIN for AUTH_MODE_AUTO_SWITCH +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @retval TRUE We will retry JOIN +* @retval FALSE We will not retry JOIN +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +aisFsmStateInit_RetryJOIN ( + IN P_ADAPTER_T prAdapter, + P_STA_RECORD_T prStaRec + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_MSG_JOIN_REQ_T prJoinReqMsg; + + DEBUGFUNC("aisFsmStateInit_RetryJOIN()"); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + /* Retry other AuthType if possible */ + if (!prAisFsmInfo->ucAvailableAuthTypes) { + return FALSE; + } + + if (prAisFsmInfo->ucAvailableAuthTypes & + (UINT_8)AUTH_TYPE_SHARED_KEY) { + + DBGLOG(AIS, INFO, ("RETRY JOIN INIT: Retry Authentication with AuthType == SHARED_KEY.\n")); + + prAisFsmInfo->ucAvailableAuthTypes &= + ~(UINT_8)AUTH_TYPE_SHARED_KEY; + + prStaRec->ucAuthAlgNum = (UINT_8)AUTH_ALGORITHM_NUM_SHARED_KEY; + } + else { + DBGLOG(AIS, ERROR, ("RETRY JOIN INIT: Retry Authentication with Unexpected AuthType.\n")); + ASSERT(0); + } + + prAisFsmInfo->ucAvailableAuthTypes = 0; /* No more available Auth Types */ + + /* Trigger SAA to start JOIN process. */ + prJoinReqMsg = (P_MSG_JOIN_REQ_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_REQ_T)); + if (!prJoinReqMsg) { + + ASSERT(0); // Can't trigger SAA FSM + return FALSE; + } + + prJoinReqMsg->rMsgHdr.eMsgId = MID_AIS_SAA_FSM_START; + prJoinReqMsg->ucSeqNum = ++prAisFsmInfo->ucSeqNumOfReqMsg; + prJoinReqMsg->prStaRec = prStaRec; + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prJoinReqMsg, + MSG_SEND_METHOD_BUF); + + return TRUE; + +}/* end of aisFsmRetryJOIN() */ + + +#if CFG_SUPPORT_ADHOC +/*----------------------------------------------------------------------------*/ +/*! +* @brief State Initialization of AIS_STATE_IBSS_ALONE +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmStateInit_IBSS_ALONE ( + IN P_ADAPTER_T prAdapter + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_INFO_T prAisBssInfo; + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + //4 <1> Check if IBSS was created before ? + if (prAisBssInfo->fgIsBeaconActivated) { + + //4 <2> Start IBSS Alone Timer for periodic SCAN and then SEARCH +#if !CFG_SLT_SUPPORT + cnmTimerStartTimer(prAdapter, + &prAisFsmInfo->rIbssAloneTimer, + SEC_TO_MSEC(AIS_IBSS_ALONE_TIMEOUT_SEC)); +#endif + } + + aisFsmCreateIBSS(prAdapter); + + return; +} /* end of aisFsmStateInit_IBSS_ALONE() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief State Initialization of AIS_STATE_IBSS_MERGE +* +* @param[in] prBssDesc The pointer of BSS_DESC_T which is the IBSS we will try to merge with. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmStateInit_IBSS_MERGE ( + IN P_ADAPTER_T prAdapter, + P_BSS_DESC_T prBssDesc + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_INFO_T prAisBssInfo; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + + + ASSERT(prBssDesc); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + //4 <1> We will merge with to this BSS immediately. + prBssDesc->fgIsConnecting = FALSE; + prBssDesc->fgIsConnected = TRUE; + + //4 <2> Setup corresponding STA_RECORD_T + prStaRec = bssCreateStaRecFromBssDesc(prAdapter, + STA_TYPE_ADHOC_PEER, + NETWORK_TYPE_AIS_INDEX, + prBssDesc); + + prStaRec->fgIsMerging = TRUE; + + prAisFsmInfo->prTargetStaRec = prStaRec; + + //4 <2.1> sync. to firmware domain + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + + //4 <3> IBSS-Merge + aisFsmMergeIBSS(prAdapter, prStaRec); + + return; +} /* end of aisFsmStateInit_IBSS_MERGE() */ + +#endif /* CFG_SUPPORT_ADHOC */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process of JOIN Abort +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmStateAbort_JOIN ( + IN P_ADAPTER_T prAdapter + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_MSG_JOIN_ABORT_T prJoinAbortMsg; + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + /* 1. Abort JOIN process */ + prJoinAbortMsg = (P_MSG_JOIN_ABORT_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_ABORT_T)); + if (!prJoinAbortMsg) { + + ASSERT(0); // Can't abort SAA FSM + return; + } + + prJoinAbortMsg->rMsgHdr.eMsgId = MID_AIS_SAA_FSM_ABORT; + prJoinAbortMsg->ucSeqNum = prAisFsmInfo->ucSeqNumOfReqMsg; + prJoinAbortMsg->prStaRec = prAisFsmInfo->prTargetStaRec; + + scanRemoveConnFlagOfBssDescByBssid(prAdapter, prAisFsmInfo->prTargetStaRec->aucMacAddr); + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prJoinAbortMsg, + MSG_SEND_METHOD_BUF); + + /* 2. Return channel privilege */ + aisFsmReleaseCh(prAdapter); + + /* 3.1 stop join timeout timer */ + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rJoinTimeoutTimer); + + /* 3.2 reset local variable */ + prAisFsmInfo->fgIsInfraChannelFinished = TRUE; + + return; +} /* end of aisFsmAbortJOIN() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process of SCAN Abort +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmStateAbort_SCAN ( + IN P_ADAPTER_T prAdapter + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_MSG_SCN_SCAN_CANCEL prScanCancelMsg; + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + /* Abort JOIN process. */ + prScanCancelMsg = (P_MSG_SCN_SCAN_CANCEL)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_CANCEL)); + if (!prScanCancelMsg) { + + ASSERT(0); // Can't abort SCN FSM + return; + } + + prScanCancelMsg->rMsgHdr.eMsgId = MID_AIS_SCN_SCAN_CANCEL; + prScanCancelMsg->ucSeqNum = prAisFsmInfo->ucSeqNumOfScanReq; + prScanCancelMsg->ucNetTypeIndex = (UINT_8)NETWORK_TYPE_AIS_INDEX; +#if CFG_ENABLE_WIFI_DIRECT + if(prAdapter->fgIsP2PRegistered) { + prScanCancelMsg->fgIsChannelExt = FALSE; + } +#endif + + /* unbuffered message to guarantee scan is cancelled in sequence */ + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prScanCancelMsg, + MSG_SEND_METHOD_UNBUF); + + return; +} /* end of aisFsmAbortSCAN() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process of NORMAL_TR Abort +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmStateAbort_NORMAL_TR ( + IN P_ADAPTER_T prAdapter + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + + ASSERT(prAdapter); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + /* TODO(Kevin): Do abort other MGMT func */ + + /* 1. Release channel to CNM */ + aisFsmReleaseCh(prAdapter); + + /* 2.1 stop join timeout timer */ + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rJoinTimeoutTimer); + + /* 2.2 reset local variable */ + prAisFsmInfo->fgIsInfraChannelFinished = TRUE; + + return; +} /* end of aisFsmAbortNORMAL_TR() */ + + +#if CFG_SUPPORT_ADHOC +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process of NORMAL_TR Abort +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmStateAbort_IBSS ( + IN P_ADAPTER_T prAdapter + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_DESC_T prBssDesc; + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + // reset BSS-DESC + if (prAisFsmInfo->prTargetStaRec) { + prBssDesc = scanSearchBssDescByTA(prAdapter, + prAisFsmInfo->prTargetStaRec->aucMacAddr); + + if (prBssDesc) { + prBssDesc->fgIsConnected = FALSE; + prBssDesc->fgIsConnecting = FALSE; + } + } + + // release channel privilege + aisFsmReleaseCh(prAdapter); + + return; +} +#endif /* CFG_SUPPORT_ADHOC */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief The Core FSM engine of AIS(Ad-hoc, Infra STA) +* +* @param[in] eNextState Enum value of next AIS STATE +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmSteps ( + IN P_ADAPTER_T prAdapter, + ENUM_AIS_STATE_T eNextState + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_DESC_T prBssDesc; + P_MSG_CH_REQ_T prMsgChReq; + P_MSG_SCN_SCAN_REQ prScanReqMsg; + P_AIS_REQ_HDR_T prAisReq; + ENUM_BAND_T eBand; + UINT_8 ucChannel; + UINT_16 u2ScanIELen; + + BOOLEAN fgIsTransition = (BOOLEAN)FALSE; + + DEBUGFUNC("aisFsmSteps()"); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + do { + + /* Do entering Next State */ + prAisFsmInfo->ePreviousState = prAisFsmInfo->eCurrentState; + +#if CFG_SUPPORT_XLOG + DBGLOG(AIS, STATE, ("[%d] TRANSITION: [%d] -> [%d]\n", + DBG_AIS_IDX, + prAisFsmInfo->eCurrentState, + eNextState)); +#else + DBGLOG(AIS, STATE, ("TRANSITION: [%s] -> [%s]\n", + apucDebugAisState[prAisFsmInfo->eCurrentState], + apucDebugAisState[eNextState])); +#endif + /* NOTE(Kevin): This is the only place to change the eCurrentState(except initial) */ + prAisFsmInfo->eCurrentState = eNextState; + + fgIsTransition = (BOOLEAN)FALSE; + + /* Do tasks of the State that we just entered */ + switch (prAisFsmInfo->eCurrentState) { + /* NOTE(Kevin): we don't have to rearrange the sequence of following + * switch case. Instead I would like to use a common lookup table of array + * of function pointer to speed up state search. + */ + case AIS_STATE_IDLE: + + prAisReq = aisFsmGetNextRequest(prAdapter); + + if(prAisReq == NULL || prAisReq->eReqType == AIS_REQUEST_RECONNECT) { + if (prConnSettings->fgIsConnReqIssued) { + + prAisFsmInfo->fgTryScan = TRUE; + + SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX); + SET_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX); + + // sync with firmware + nicActivateNetwork(prAdapter, NETWORK_TYPE_AIS_INDEX); + + // reset trial count + prAisFsmInfo->ucConnTrialCount = 0; + + eNextState = AIS_STATE_SEARCH; + fgIsTransition = TRUE; + } + else { + UNSET_NET_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX); + SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_AIS_INDEX); + + // sync with firmware + nicDeactivateNetwork(prAdapter, NETWORK_TYPE_AIS_INDEX); + + // check for other pending request + if(prAisReq) { + if(aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, TRUE) == TRUE) { + wlanClearScanningResult(prAdapter); + eNextState = AIS_STATE_SCAN; + + fgIsTransition = TRUE; + } + } + } + + if(prAisReq) { + /* free the message */ + cnmMemFree(prAdapter, prAisReq); + } + } + else if(prAisReq->eReqType == AIS_REQUEST_SCAN) { +#if CFG_SUPPORT_ROAMING + prAisFsmInfo->fgIsRoamingScanPending = FALSE; +#endif /* CFG_SUPPORT_ROAMING */ + wlanClearScanningResult(prAdapter); + + eNextState = AIS_STATE_SCAN; + fgIsTransition = TRUE; + + /* free the message */ + cnmMemFree(prAdapter, prAisReq); + } + else if(prAisReq->eReqType == AIS_REQUEST_ROAMING_CONNECT || prAisReq->eReqType == AIS_REQUEST_ROAMING_SEARCH) { + /* ignore */ + /* free the message */ + cnmMemFree(prAdapter, prAisReq); + } + + prAisFsmInfo->u4SleepInterval = AIS_BG_SCAN_INTERVAL_MIN_SEC; + + break; + + case AIS_STATE_SEARCH: + //4 <1> Search for a matched candidate and save it to prTargetBssDesc. +#if CFG_SLT_SUPPORT + prBssDesc = prAdapter->rWifiVar.rSltInfo.prPseudoBssDesc; +#else + prBssDesc = scanSearchBssDescByPolicy(prAdapter, NETWORK_TYPE_AIS_INDEX); +#endif + + // we are under Roaming Condition. + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + if(prAisFsmInfo->ucConnTrialCount > AIS_ROAMING_CONNECTION_TRIAL_LIMIT) { +#if CFG_SUPPORT_ROAMING + roamingFsmRunEventFail(prAdapter, ROAMING_FAIL_REASON_CONNLIMIT); +#endif /* CFG_SUPPORT_ROAMING */ + // reset retry count + prAisFsmInfo->ucConnTrialCount = 0; + + // abort connection trial + prConnSettings->fgIsConnReqIssued = FALSE; + + eNextState = AIS_STATE_NORMAL_TR; + fgIsTransition = TRUE; + + break; + } + } + + //4 <2> We are not under Roaming Condition. + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { + + //4 <2.a> If we have the matched one + if (prBssDesc) { + + //4 Stored the Selected BSS security cipher. For later asoc req compose IE + prAisBssInfo->u4RsnSelectedGroupCipher = + prBssDesc->u4RsnSelectedGroupCipher; + prAisBssInfo->u4RsnSelectedPairwiseCipher = + prBssDesc->u4RsnSelectedPairwiseCipher; + prAisBssInfo->u4RsnSelectedAKMSuite = + prBssDesc->u4RsnSelectedAKMSuite; + + //4 Do STATE transition and update current Operation Mode. + if (prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE) { + + prAisBssInfo->eCurrentOPMode = OP_MODE_INFRASTRUCTURE; + + /* Record the target BSS_DESC_T for next STATE. */ + prAisFsmInfo->prTargetBssDesc = prBssDesc; + + /* Transit to channel acquire */ + eNextState = AIS_STATE_REQ_CHANNEL_JOIN; + fgIsTransition = TRUE; + + // increase connection trial count + prAisFsmInfo->ucConnTrialCount++; + } +#if CFG_SUPPORT_ADHOC + else if (prBssDesc->eBSSType == BSS_TYPE_IBSS) { + + prAisBssInfo->eCurrentOPMode = OP_MODE_IBSS; + + /* Record the target BSS_DESC_T for next STATE. */ + prAisFsmInfo->prTargetBssDesc = prBssDesc; + + eNextState = AIS_STATE_IBSS_MERGE; + fgIsTransition = TRUE; + } +#endif /* CFG_SUPPORT_ADHOC */ + else { + ASSERT(0); + eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; + fgIsTransition = TRUE; + } + } + //4 <2.b> If we don't have the matched one + else { + + // increase connection trial count for infrastructure connection + if (prConnSettings->eOPMode == NET_TYPE_INFRA) { + prAisFsmInfo->ucConnTrialCount++; + } + + //4 Try to SCAN + if (prAisFsmInfo->fgTryScan) { + eNextState = AIS_STATE_LOOKING_FOR; + + fgIsTransition = TRUE; + } + //4 We've do SCAN already, now wait in some STATE. + else { + if (prConnSettings->eOPMode == NET_TYPE_INFRA) { + + /* issue reconnect request, and retreat to idle state for scheduling */ + aisFsmInsertRequest(prAdapter, AIS_REQUEST_RECONNECT); + + eNextState = AIS_STATE_IDLE; + fgIsTransition = TRUE; + } +#if CFG_SUPPORT_ADHOC + else if ((prConnSettings->eOPMode == NET_TYPE_IBSS) + || (prConnSettings->eOPMode == NET_TYPE_AUTO_SWITCH) + || (prConnSettings->eOPMode == NET_TYPE_DEDICATED_IBSS)) { + + prAisBssInfo->eCurrentOPMode = OP_MODE_IBSS; + prAisFsmInfo->prTargetBssDesc = NULL; + + eNextState = AIS_STATE_IBSS_ALONE; + fgIsTransition = TRUE; + } +#endif /* CFG_SUPPORT_ADHOC */ + else { + ASSERT(0); + eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; + fgIsTransition = TRUE; + } + } + } + } + //4 <3> We are under Roaming Condition. + else { // prAdapter->eConnectionState == MEDIA_STATE_CONNECTED. + + //4 <3.a> This BSS_DESC_T is our AP. + /* NOTE(Kevin 2008/05/16): Following cases will go back to NORMAL_TR. + * CASE I: During Roaming, APP(WZC/NDISTEST) change the connection + * settings. That make we can NOT match the original AP, so the + * prBssDesc is NULL. + * CASE II: The same reason as CASE I. Because APP change the + * eOPMode to other network type in connection setting + * (e.g. NET_TYPE_IBSS), so the BssDesc become the IBSS node. + * (For CASE I/II, before WZC/NDISTEST set the OID_SSID, it will change + * other parameters in connection setting first. So if we do roaming + * at the same time, it will hit these cases.) + * + * CASE III: Normal case, we can't find other candidate to roam + * out, so only the current AP will be matched. + */ + if ((!prBssDesc) || /* CASE I */ + (prBssDesc->eBSSType != BSS_TYPE_INFRASTRUCTURE) || /* CASE II */ + (prBssDesc->fgIsConnected) /* CASE III */) { +#if DBG + if ((prBssDesc) && + (prBssDesc->fgIsConnected)) { + ASSERT(EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAisBssInfo->aucBSSID)); + } +#endif /* DBG */ + /* We already associated with it, go back to NORMAL_TR */ + /* TODO(Kevin): Roaming Fail */ +#if CFG_SUPPORT_ROAMING + roamingFsmRunEventFail(prAdapter, ROAMING_FAIL_REASON_NOCANDIDATE); +#endif /* CFG_SUPPORT_ROAMING */ + + /* Retreat to NORMAL_TR state */ + eNextState = AIS_STATE_NORMAL_TR; + fgIsTransition = TRUE; + } + //4 <3.b> Try to roam out for JOIN this BSS_DESC_T. + else { +#if DBG + ASSERT(UNEQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAisBssInfo->aucBSSID)); +#endif /* DBG */ + + //4 Record the target BSS_DESC_T for next STATE. + prAisFsmInfo->prTargetBssDesc = prBssDesc; + + // tyhsu: increase connection trial count + prAisFsmInfo->ucConnTrialCount++; + + /* Transit to channel acquire */ + eNextState = AIS_STATE_REQ_CHANNEL_JOIN; + fgIsTransition = TRUE; + } + } + + break; + + case AIS_STATE_WAIT_FOR_NEXT_SCAN: + + DBGLOG(AIS, LOUD, ("SCAN: Idle Begin - Current Time = %ld\n", kalGetTimeTick())); + + cnmTimerStartTimer(prAdapter, + &prAisFsmInfo->rBGScanTimer, + SEC_TO_MSEC(prAisFsmInfo->u4SleepInterval)); + + SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_AIS_INDEX); + + if (prAisFsmInfo->u4SleepInterval < AIS_BG_SCAN_INTERVAL_MAX_SEC) { + prAisFsmInfo->u4SleepInterval <<= 1; + } + break; + + case AIS_STATE_SCAN: + case AIS_STATE_ONLINE_SCAN: + case AIS_STATE_LOOKING_FOR: + + if(!IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX)) { + SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX); + + // sync with firmware + nicActivateNetwork(prAdapter, NETWORK_TYPE_AIS_INDEX); + } + + /* IE length decision */ +#if CFG_SUPPORT_WPS2 + u2ScanIELen = prAdapter->prGlueInfo->u2WSCIELen; +#else + u2ScanIELen = 0; +#endif + + prScanReqMsg = (P_MSG_SCN_SCAN_REQ)cnmMemAlloc(prAdapter, + RAM_TYPE_MSG, + OFFSET_OF(MSG_SCN_SCAN_REQ, aucIE) + u2ScanIELen); + if (!prScanReqMsg) { + ASSERT(0); // Can't trigger SCAN FSM + return; + } + + prScanReqMsg->rMsgHdr.eMsgId = MID_AIS_SCN_SCAN_REQ; + prScanReqMsg->ucSeqNum = ++prAisFsmInfo->ucSeqNumOfScanReq; + prScanReqMsg->ucNetTypeIndex = (UINT_8)NETWORK_TYPE_AIS_INDEX; + +#if CFG_SUPPORT_RDD_TEST_MODE + prScanReqMsg->eScanType = SCAN_TYPE_PASSIVE_SCAN; +#else + prScanReqMsg->eScanType = SCAN_TYPE_ACTIVE_SCAN; +#endif + + if(prAisFsmInfo->eCurrentState == AIS_STATE_SCAN + || prAisFsmInfo->eCurrentState == AIS_STATE_ONLINE_SCAN) { + if(prAisFsmInfo->ucScanSSIDLen == 0) { + /* Scan for all available SSID */ + prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_WILDCARD; + } + else { + prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; + COPY_SSID(prScanReqMsg->aucSSID, + prScanReqMsg->ucSSIDLength, + prAisFsmInfo->aucScanSSID, + prAisFsmInfo->ucScanSSIDLen); + } + } + else { + /* Scan for determined SSID */ + prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; + COPY_SSID(prScanReqMsg->aucSSID, + prScanReqMsg->ucSSIDLength, + prConnSettings->aucSSID, + prConnSettings->ucSSIDLen); + } + + /* check if tethering is running and need to fix on specific channel */ + if(cnmAisInfraChannelFixed(prAdapter, &eBand, &ucChannel) == TRUE) { + prScanReqMsg->eScanChannel = SCAN_CHANNEL_SPECIFIED; + prScanReqMsg->ucChannelListNum = 1; + prScanReqMsg->arChnlInfoList[0].eBand + = eBand;; + prScanReqMsg->arChnlInfoList[0].ucChannelNum + = ucChannel; + } + else if(prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] == BAND_NULL) { + if(prAdapter->fgEnable5GBand == TRUE) { + prScanReqMsg->eScanChannel = SCAN_CHANNEL_FULL; + } + else { + prScanReqMsg->eScanChannel = SCAN_CHANNEL_2G4; + } + } + else if(prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] == BAND_2G4) { + prScanReqMsg->eScanChannel = SCAN_CHANNEL_2G4; + } + else if(prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] == BAND_5G) { + prScanReqMsg->eScanChannel = SCAN_CHANNEL_5G; + } + else { + prScanReqMsg->eScanChannel = SCAN_CHANNEL_FULL; + ASSERT(0); + } + +#if CFG_SUPPORT_WPS2 + if(prAdapter->prGlueInfo->u2WSCIELen > 0) { + kalMemCopy(prScanReqMsg->aucIE, &prAdapter->prGlueInfo->aucWSCIE, prAdapter->prGlueInfo->u2WSCIELen); + } +#endif + + prScanReqMsg->u2IELen = u2ScanIELen; + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prScanReqMsg, + MSG_SEND_METHOD_BUF); + + prAisFsmInfo->fgTryScan = FALSE; /* Will enable background sleep for infrastructure */ + + break; + + case AIS_STATE_REQ_CHANNEL_JOIN: + /* send message to CNM for acquiring channel */ + prMsgChReq = (P_MSG_CH_REQ_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_REQ_T)); + if (!prMsgChReq) { + ASSERT(0); // Can't indicate CNM for channel acquiring + return; + } + + prMsgChReq->rMsgHdr.eMsgId = MID_MNY_CNM_CH_REQ; + prMsgChReq->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; + prMsgChReq->ucTokenID = ++prAisFsmInfo->ucSeqNumOfChReq; + prMsgChReq->eReqType = CH_REQ_TYPE_JOIN; + prMsgChReq->u4MaxInterval = AIS_JOIN_CH_REQUEST_INTERVAL; + prMsgChReq->ucPrimaryChannel = prAisFsmInfo->prTargetBssDesc->ucChannelNum; + prMsgChReq->eRfSco = prAisFsmInfo->prTargetBssDesc->eSco; + prMsgChReq->eRfBand = prAisFsmInfo->prTargetBssDesc->eBand; + COPY_MAC_ADDR(prMsgChReq->aucBSSID, prAisFsmInfo->prTargetBssDesc->aucBSSID); + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prMsgChReq, + MSG_SEND_METHOD_BUF); + + prAisFsmInfo->fgIsChannelRequested = TRUE; + break; + + case AIS_STATE_JOIN: + aisFsmStateInit_JOIN(prAdapter, prAisFsmInfo->prTargetBssDesc); + break; + +#if CFG_SUPPORT_ADHOC + case AIS_STATE_IBSS_ALONE: + aisFsmStateInit_IBSS_ALONE(prAdapter); + break; + + case AIS_STATE_IBSS_MERGE: + aisFsmStateInit_IBSS_MERGE(prAdapter, prAisFsmInfo->prTargetBssDesc); + break; +#endif /* CFG_SUPPORT_ADHOC */ + + case AIS_STATE_NORMAL_TR: + if(prAisFsmInfo->fgIsInfraChannelFinished == FALSE) { + /* Don't do anything when rJoinTimeoutTimer is still ticking */ + } + else { + /* 1. Process for pending scan */ + if(aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, TRUE) == TRUE) { + wlanClearScanningResult(prAdapter); + eNextState = AIS_STATE_ONLINE_SCAN; + fgIsTransition = TRUE; + } + /* 2. Process for pending roaming scan */ + else if(aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_SEARCH, TRUE) == TRUE) { + eNextState = AIS_STATE_LOOKING_FOR; + fgIsTransition = TRUE; + } + /* 3. Process for pending roaming scan */ + else if(aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_CONNECT, TRUE) == TRUE) { + eNextState = AIS_STATE_SEARCH; + fgIsTransition = TRUE; + } + } + + break; + + case AIS_STATE_DISCONNECTING: + /* send for deauth frame for disconnection */ + authSendDeauthFrame(prAdapter, + prAisBssInfo->prStaRecOfAP, + (P_SW_RFB_T)NULL, + REASON_CODE_DEAUTH_LEAVING_BSS, + aisDeauthXmitComplete); + break; + + default: + ASSERT(0); /* Make sure we have handle all STATEs */ + break; + + } + } + while (fgIsTransition); + + return; + +} /* end of aisFsmSteps() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmRunEventScanDone ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_MSG_SCN_SCAN_DONE prScanDoneMsg; + P_AIS_FSM_INFO_T prAisFsmInfo; + ENUM_AIS_STATE_T eNextState; + UINT_8 ucSeqNumOfCompMsg; + P_CONNECTION_SETTINGS_T prConnSettings; + + DEBUGFUNC("aisFsmRunEventScanDone()"); + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + + DBGLOG(AIS, LOUD, ("EVENT-SCAN DONE: Current Time = %ld\n", kalGetTimeTick())); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + prScanDoneMsg = (P_MSG_SCN_SCAN_DONE)prMsgHdr; + ASSERT(prScanDoneMsg->ucNetTypeIndex == (UINT_8)NETWORK_TYPE_AIS_INDEX); + + ucSeqNumOfCompMsg = prScanDoneMsg->ucSeqNum; + cnmMemFree(prAdapter, prMsgHdr); + + eNextState = prAisFsmInfo->eCurrentState; + + if (ucSeqNumOfCompMsg != prAisFsmInfo->ucSeqNumOfScanReq) { + DBGLOG(AIS, WARN, ("SEQ NO of AIS SCN DONE MSG is not matched.\n")); + } + else { + switch (prAisFsmInfo->eCurrentState) { + case AIS_STATE_SCAN: + prConnSettings->fgIsScanReqIssued = FALSE; + + kalScanDone(prAdapter->prGlueInfo, KAL_NETWORK_TYPE_AIS_INDEX, WLAN_STATUS_SUCCESS); + eNextState = AIS_STATE_IDLE; + break; + + case AIS_STATE_ONLINE_SCAN: + prConnSettings->fgIsScanReqIssued = FALSE; + + kalScanDone(prAdapter->prGlueInfo, KAL_NETWORK_TYPE_AIS_INDEX, WLAN_STATUS_SUCCESS); +#if CFG_SUPPORT_ROAMING + eNextState = aisFsmRoamingScanResultsUpdate(prAdapter); +#else + eNextState = AIS_STATE_NORMAL_TR; +#endif /* CFG_SUPPORT_ROAMING */ + break; + + case AIS_STATE_LOOKING_FOR: +#if CFG_SUPPORT_ROAMING + eNextState = aisFsmRoamingScanResultsUpdate(prAdapter); +#else + eNextState = AIS_STATE_SEARCH; +#endif /* CFG_SUPPORT_ROAMING */ + break; + + default: + break; + + } + } + + if (eNextState != prAisFsmInfo->eCurrentState) { + aisFsmSteps(prAdapter, eNextState); + } + + return; +} /* end of aisFsmRunEventScanDone() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmRunEventAbort ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_MSG_AIS_ABORT_T prAisAbortMsg; + P_AIS_FSM_INFO_T prAisFsmInfo; + UINT_8 ucReasonOfDisconnect; + BOOLEAN fgDelayIndication; + + DEBUGFUNC("aisFsmRunEventAbort()"); + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + //4 <1> Extract information of Abort Message and then free memory. + prAisAbortMsg = (P_MSG_AIS_ABORT_T)prMsgHdr; + ucReasonOfDisconnect = prAisAbortMsg->ucReasonOfDisconnect; + fgDelayIndication = prAisAbortMsg->fgDelayIndication; + + cnmMemFree(prAdapter, prMsgHdr); + +#if CFG_SUPPORT_XLOG + DBGLOG(AIS, LOUD, ("[%d] EVENT-ABORT: Current State [%d]\n", + DBG_AIS_IDX, + prAisFsmInfo->eCurrentState)); +#else + DBGLOG(AIS, LOUD, ("EVENT-ABORT: Current State %s\n", + apucDebugAisState[prAisFsmInfo->eCurrentState])); +#endif + + //4 <2> clear previous pending connection request and insert new one + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_RECONNECT, TRUE); + aisFsmInsertRequest(prAdapter, AIS_REQUEST_RECONNECT); + + if(prAisFsmInfo->eCurrentState != AIS_STATE_DISCONNECTING) { + //4 <3> invoke abort handler + aisFsmStateAbort(prAdapter, ucReasonOfDisconnect, fgDelayIndication); + } + + return; +} /* end of aisFsmRunEventAbort() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function handles AIS-FSM abort event/command +* +* \param[in] prAdapter Pointer of ADAPTER_T +* ucReasonOfDisconnect Reason for disonnection +* fgDelayIndication Option to delay disconnection indication +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmStateAbort ( + IN P_ADAPTER_T prAdapter, + UINT_8 ucReasonOfDisconnect, + BOOLEAN fgDelayIndication + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + BOOLEAN fgIsCheckConnected; + + ASSERT(prAdapter); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + fgIsCheckConnected = FALSE; + + //4 <1> Save information of Abort Message and then free memory. + prAisBssInfo->ucReasonOfDisconnect = ucReasonOfDisconnect; + + //4 <2> Abort current job. + switch (prAisFsmInfo->eCurrentState) { + case AIS_STATE_IDLE: + case AIS_STATE_SEARCH: + break; + + case AIS_STATE_WAIT_FOR_NEXT_SCAN: + /* Do cancel timer */ + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rBGScanTimer); + + /* in case roaming is triggered */ + fgIsCheckConnected = TRUE; + break; + + case AIS_STATE_SCAN: + /* Do abort SCAN */ + aisFsmStateAbort_SCAN(prAdapter); + + /* queue for later handling */ + if(aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, FALSE) == FALSE) { + aisFsmInsertRequest(prAdapter, AIS_REQUEST_SCAN); + } + + break; + + case AIS_STATE_LOOKING_FOR: + /* Do abort SCAN */ + aisFsmStateAbort_SCAN(prAdapter); + + /* in case roaming is triggered */ + fgIsCheckConnected = TRUE; + break; + + case AIS_STATE_REQ_CHANNEL_JOIN: + /* Release channel to CNM */ + aisFsmReleaseCh(prAdapter); + + /* in case roaming is triggered */ + fgIsCheckConnected = TRUE; + break; + + case AIS_STATE_JOIN: + /* Do abort JOIN */ + aisFsmStateAbort_JOIN(prAdapter); + + /* in case roaming is triggered */ + fgIsCheckConnected = TRUE; + break; + +#if CFG_SUPPORT_ADHOC + case AIS_STATE_IBSS_ALONE: + case AIS_STATE_IBSS_MERGE: + aisFsmStateAbort_IBSS(prAdapter); + break; +#endif /* CFG_SUPPORT_ADHOC */ + + case AIS_STATE_ONLINE_SCAN: + /* Do abort SCAN */ + aisFsmStateAbort_SCAN(prAdapter); + + /* queue for later handling */ + if(aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, FALSE) == FALSE) { + aisFsmInsertRequest(prAdapter, AIS_REQUEST_SCAN); + } + + fgIsCheckConnected = TRUE; + break; + + case AIS_STATE_NORMAL_TR: + fgIsCheckConnected = TRUE; + break; + + case AIS_STATE_DISCONNECTING: + /* Do abort NORMAL_TR */ + aisFsmStateAbort_NORMAL_TR(prAdapter); + + break; + + default: + break; + } + + if (fgIsCheckConnected && + (PARAM_MEDIA_STATE_CONNECTED == prAisBssInfo->eConnectionState)) { + + /* switch into DISCONNECTING state for sending DEAUTH if necessary */ + if (prAisBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE && + prAisBssInfo->ucReasonOfDisconnect == DISCONNECT_REASON_CODE_NEW_CONNECTION && + prAisBssInfo->prStaRecOfAP && + prAisBssInfo->prStaRecOfAP->fgIsInUse) { + aisFsmSteps(prAdapter, AIS_STATE_DISCONNECTING); + + return; + } + else { + /* Do abort NORMAL_TR */ + aisFsmStateAbort_NORMAL_TR(prAdapter); + } + } + + aisFsmDisconnect(prAdapter, fgDelayIndication); + + return; + +} /* end of aisFsmStateAbort() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle the Join Complete Event from SAA FSM for AIS FSM +* +* @param[in] prMsgHdr Message of Join Complete of SAA FSM. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmRunEventJoinComplete ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_MSG_JOIN_COMP_T prJoinCompMsg; + P_AIS_FSM_INFO_T prAisFsmInfo; + ENUM_AIS_STATE_T eNextState; + P_STA_RECORD_T prStaRec; + P_SW_RFB_T prAssocRspSwRfb; + BOOLEAN fgReassociated = FALSE; + + DEBUGFUNC("aisFsmRunEventJoinComplete()"); + + ASSERT(prMsgHdr); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prJoinCompMsg = (P_MSG_JOIN_COMP_T)prMsgHdr; + prStaRec = prJoinCompMsg->prStaRec; + prAssocRspSwRfb = prJoinCompMsg->prSwRfb; + + eNextState = prAisFsmInfo->eCurrentState; + + // Check State and SEQ NUM + if (prAisFsmInfo->eCurrentState == AIS_STATE_JOIN) { + P_BSS_INFO_T prAisBssInfo; + + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + // Check SEQ NUM + if (prJoinCompMsg->ucSeqNum == prAisFsmInfo->ucSeqNumOfReqMsg) { + + + //4 <1> JOIN was successful + if (prJoinCompMsg->rJoinStatus == WLAN_STATUS_SUCCESS) { + + //1. Reset retry count + prAisFsmInfo->ucConnTrialCount = 0; + + // Completion of roaming + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + +#if CFG_SUPPORT_ROAMING + //2. Deactivate previous BSS + aisFsmRoamingDisconnectPrevAP(prAdapter, prStaRec); + + //3. Update bss based on roaming staRec + aisUpdateBssInfoForRoamingAP(prAdapter, prStaRec, prAssocRspSwRfb); +#endif /* CFG_SUPPORT_ROAMING */ + } + else { + //4 <1.1> Change FW's Media State immediately. + aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); + + //4 <1.2> Deactivate previous AP's STA_RECORD_T in Driver if have. + if ((prAisBssInfo->prStaRecOfAP) && + (prAisBssInfo->prStaRecOfAP != prStaRec) && + (prAisBssInfo->prStaRecOfAP->fgIsInUse)) { + + cnmStaRecChangeState(prAdapter, prAisBssInfo->prStaRecOfAP, STA_STATE_1); + } + + //4 <1.2.1> check for non-roaming/reassociated + if(EQUAL_MAC_ADDR(prAisBssInfo->aucBSSID, ((P_WLAN_ASSOC_RSP_FRAME_T)prAssocRspSwRfb->pvHeader)->aucBSSID) && + prAisBssInfo->eConnectionStateIndicated == PARAM_MEDIA_STATE_CONNECTED) { + fgReassociated = TRUE; + } + + //4 <1.3> Update BSS_INFO_T + aisUpdateBssInfoForJOIN(prAdapter, prStaRec, prAssocRspSwRfb); + + //4 <1.4> Activate current AP's STA_RECORD_T in Driver. + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + + //4 <1.5> Update RSSI if necessary + nicUpdateRSSI(prAdapter, NETWORK_TYPE_AIS_INDEX, (INT_8)(RCPI_TO_dBm(prStaRec->ucRCPI)), 0); + +#if defined(LINUX) + //4 Android Framework needs DISCONNECT indication for non-roaming/reassociated cases + if(fgReassociated) { + aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED, FALSE); + } +#endif + //4 <1.6> Indicate Connected Event to Host immediately. + /* Require BSSID, Association ID, Beacon Interval.. from AIS_BSS_INFO_T */ + aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_CONNECTED, FALSE); + } + +#if CFG_SUPPORT_ROAMING + roamingFsmRunEventStart(prAdapter); +#endif /* CFG_SUPPORT_ROAMING */ + + //4 <1.7> Set the Next State of AIS FSM + eNextState = AIS_STATE_NORMAL_TR; + } + //4 <2> JOIN was not successful + else { + //4 <2.1> Redo JOIN process with other Auth Type if possible + if (aisFsmStateInit_RetryJOIN(prAdapter, prStaRec) == FALSE) { + P_BSS_DESC_T prBssDesc; + + /* 1. Increase Failure Count */ + prStaRec->ucJoinFailureCount++; + + /* 2. release channel */ + aisFsmReleaseCh(prAdapter); + + /* 3.1 stop join timeout timer */ + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rJoinTimeoutTimer); + + /* 3.2 reset local variable */ + prAisFsmInfo->fgIsInfraChannelFinished = TRUE; + + prBssDesc = scanSearchBssDescByBssid(prAdapter, prStaRec->aucMacAddr); + + ASSERT(prBssDesc); + ASSERT(prBssDesc->fgIsConnecting); + + if(prBssDesc) { + prBssDesc->fgIsConnecting = FALSE; + } + + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { +#if CFG_SUPPORT_ROAMING + eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; +#endif /* CFG_SUPPORT_ROAMING */ + } + else { + /* 4. send reconnect request */ + aisFsmInsertRequest(prAdapter, AIS_REQUEST_RECONNECT); + + eNextState = AIS_STATE_IDLE; + } + } + } + } +#if DBG + else { + DBGLOG(AIS, WARN, ("SEQ NO of AIS JOIN COMP MSG is not matched.\n")); + } +#endif /* DBG */ + + } + + if (eNextState != prAisFsmInfo->eCurrentState) { + aisFsmSteps(prAdapter, eNextState); + } + + if (prAssocRspSwRfb) { + nicRxReturnRFB(prAdapter, prAssocRspSwRfb); + } + + cnmMemFree(prAdapter, prMsgHdr); + + return; +} /* end of aisFsmRunEventJoinComplete() */ + + +#if CFG_SUPPORT_ADHOC +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle the Grant Msg of IBSS Create which was sent by +* CNM to indicate that channel was changed for creating IBSS. +* +* @param[in] prAdapter Pointer of ADAPTER_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmCreateIBSS ( + IN P_ADAPTER_T prAdapter + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + + ASSERT(prAdapter); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + do { + // Check State + if (prAisFsmInfo->eCurrentState == AIS_STATE_IBSS_ALONE) { + aisUpdateBssInfoForCreateIBSS(prAdapter); + } + } + while (FALSE); + + return; +} /* end of aisFsmCreateIBSS() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle the Grant Msg of IBSS Merge which was sent by +* CNM to indicate that channel was changed for merging IBSS. +* +* @param[in] prAdapter Pointer of ADAPTER_T +* @param[in] prStaRec Pointer of STA_RECORD_T for merge +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmMergeIBSS ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + ENUM_AIS_STATE_T eNextState; + P_BSS_INFO_T prAisBssInfo; + + ASSERT(prAdapter); + ASSERT(prStaRec); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + do { + + eNextState = prAisFsmInfo->eCurrentState; + + switch (prAisFsmInfo->eCurrentState) { + case AIS_STATE_IBSS_MERGE: + { + P_BSS_DESC_T prBssDesc; + + //4 <1.1> Change FW's Media State immediately. + aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); + + //4 <1.2> Deactivate previous Peers' STA_RECORD_T in Driver if have. + bssClearClientList(prAdapter, prAisBssInfo); + + //4 <1.3> Unmark connection flag of previous BSS_DESC_T. + if ((prBssDesc = scanSearchBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID)) != NULL) { + prBssDesc->fgIsConnecting = FALSE; + prBssDesc->fgIsConnected = FALSE; + } + + //4 <1.4> Update BSS_INFO_T + aisUpdateBssInfoForMergeIBSS(prAdapter, prStaRec); + + //4 <1.5> Add Peers' STA_RECORD_T to Client List + bssAddStaRecToClientList(prAdapter, prAisBssInfo, prStaRec); + + //4 <1.6> Activate current Peer's STA_RECORD_T in Driver. + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + prStaRec->fgIsMerging = FALSE; + + //4 <1.7> Enable other features + + //4 <1.8> Indicate Connected Event to Host immediately. + aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_CONNECTED, FALSE); + + //4 <1.9> Set the Next State of AIS FSM + eNextState = AIS_STATE_NORMAL_TR; + + //4 <1.10> Release channel privilege + aisFsmReleaseCh(prAdapter); + +#if CFG_SLT_SUPPORT + prAdapter->rWifiVar.rSltInfo.prPseudoStaRec = prStaRec; +#endif + } + break; + + default: + break; + } + + if (eNextState != prAisFsmInfo->eCurrentState) { + aisFsmSteps(prAdapter, eNextState); + } + + } + while (FALSE); + + return; +} /* end of aisFsmMergeIBSS() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle the Notification of existing IBSS was found +* from SCN. +* +* @param[in] prMsgHdr Message of Notification of an IBSS was present. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmRunEventFoundIBSSPeer ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_MSG_AIS_IBSS_PEER_FOUND_T prAisIbssPeerFoundMsg; + P_AIS_FSM_INFO_T prAisFsmInfo; + ENUM_AIS_STATE_T eNextState; + P_STA_RECORD_T prStaRec; + P_BSS_INFO_T prAisBssInfo; + P_BSS_DESC_T prBssDesc; + BOOLEAN fgIsMergeIn; + + + ASSERT(prMsgHdr); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + prAisIbssPeerFoundMsg = (P_MSG_AIS_IBSS_PEER_FOUND_T)prMsgHdr; + + ASSERT(prAisIbssPeerFoundMsg->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX); + + prStaRec = prAisIbssPeerFoundMsg->prStaRec; + ASSERT(prStaRec); + + fgIsMergeIn = prAisIbssPeerFoundMsg->fgIsMergeIn; + + cnmMemFree(prAdapter, prMsgHdr); + + + eNextState = prAisFsmInfo->eCurrentState; + switch (prAisFsmInfo->eCurrentState) { + case AIS_STATE_IBSS_ALONE: + { + //4 <1> An IBSS Peer 'merged in'. + if (fgIsMergeIn) { + + //4 <1.1> Change FW's Media State immediately. + aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); + + //4 <1.2> Add Peers' STA_RECORD_T to Client List + bssAddStaRecToClientList(prAdapter, prAisBssInfo, prStaRec); + +#if CFG_SLT_SUPPORT + //4 <1.3> Mark connection flag of BSS_DESC_T. + if ((prBssDesc = scanSearchBssDescByTA(prAdapter, prStaRec->aucMacAddr)) != NULL) { + prBssDesc->fgIsConnecting = FALSE; + prBssDesc->fgIsConnected = TRUE; + } + else { + ASSERT(0); // Should be able to find a BSS_DESC_T here. + } + + //4 <1.4> Activate current Peer's STA_RECORD_T in Driver. + prStaRec->fgIsQoS = TRUE; /* TODO(Kevin): TBD */ +#else + //4 <1.3> Mark connection flag of BSS_DESC_T. + if ((prBssDesc = scanSearchBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID)) != NULL) { + prBssDesc->fgIsConnecting = FALSE; + prBssDesc->fgIsConnected = TRUE; + } + else { + ASSERT(0); // Should be able to find a BSS_DESC_T here. + } + + + //4 <1.4> Activate current Peer's STA_RECORD_T in Driver. + prStaRec->fgIsQoS = FALSE; /* TODO(Kevin): TBD */ + +#endif + + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + prStaRec->fgIsMerging = FALSE; + + //4 <1.6> sync. to firmware + nicUpdateBss(prAdapter, NETWORK_TYPE_AIS_INDEX); + + //4 <1.7> Indicate Connected Event to Host immediately. + aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_CONNECTED, FALSE); + + //4 <1.8> indicate PM for connected + nicPmIndicateBssConnected(prAdapter, NETWORK_TYPE_AIS_INDEX); + + //4 <1.9> Set the Next State of AIS FSM + eNextState = AIS_STATE_NORMAL_TR; + + //4 <1.10> Release channel privilege + aisFsmReleaseCh(prAdapter); + } + //4 <2> We need 'merge out' to this IBSS + else { + + //4 <2.1> Get corresponding BSS_DESC_T + prBssDesc = scanSearchBssDescByTA(prAdapter, prStaRec->aucMacAddr); + + prAisFsmInfo->prTargetBssDesc = prBssDesc; + + //4 <2.2> Set the Next State of AIS FSM + eNextState = AIS_STATE_IBSS_MERGE; + } + } + break; + + case AIS_STATE_NORMAL_TR: + { + + //4 <3> An IBSS Peer 'merged in'. + if (fgIsMergeIn) { + + //4 <3.1> Add Peers' STA_RECORD_T to Client List + bssAddStaRecToClientList(prAdapter, prAisBssInfo, prStaRec); + +#if CFG_SLT_SUPPORT + //4 <3.2> Activate current Peer's STA_RECORD_T in Driver. + prStaRec->fgIsQoS = TRUE; /* TODO(Kevin): TBD */ +#else + //4 <3.2> Activate current Peer's STA_RECORD_T in Driver. + prStaRec->fgIsQoS = FALSE; /* TODO(Kevin): TBD */ +#endif + + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + prStaRec->fgIsMerging = FALSE; + + } + //4 <4> We need 'merge out' to this IBSS + else { + + //4 <4.1> Get corresponding BSS_DESC_T + prBssDesc = scanSearchBssDescByTA(prAdapter, prStaRec->aucMacAddr); + + prAisFsmInfo->prTargetBssDesc = prBssDesc; + + //4 <4.2> Set the Next State of AIS FSM + eNextState = AIS_STATE_IBSS_MERGE; + + } + } + break; + + default: + break; + } + + if (eNextState != prAisFsmInfo->eCurrentState) { + aisFsmSteps(prAdapter, eNextState); + } + + return; +} /* end of aisFsmRunEventFoundIBSSPeer() */ +#endif /* CFG_SUPPORT_ADHOC */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate the Media State to HOST +* +* @param[in] eConnectionState Current Media State +* @param[in] fgDelayIndication Set TRUE for postponing the Disconnect Indication. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisIndicationOfMediaStateToHost ( + IN P_ADAPTER_T prAdapter, + ENUM_PARAM_MEDIA_STATE_T eConnectionState, + BOOLEAN fgDelayIndication + ) +{ + EVENT_CONNECTION_STATUS rEventConnStatus; + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_INFO_T prAisBssInfo; + P_AIS_FSM_INFO_T prAisFsmInfo; + + DEBUGFUNC("aisIndicationOfMediaStateToHost()"); + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + // NOTE(Kevin): Move following line to aisChangeMediaState() macro per CM's request. + //prAisBssInfo->eConnectionState = eConnectionState; + + /* For indicating the Disconnect Event only if current media state is + * disconnected and we didn't do indication yet. + */ + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { + if (prAisBssInfo->eConnectionStateIndicated == eConnectionState) { + return; + } + } + + if (!fgDelayIndication) { + //4 <0> Cancel Delay Timer + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rIndicationOfDisconnectTimer); + + //4 <1> Fill EVENT_CONNECTION_STATUS + rEventConnStatus.ucMediaStatus = (UINT_8)eConnectionState; + + if (eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + rEventConnStatus.ucReasonOfDisconnect = DISCONNECT_REASON_CODE_RESERVED; + + if (prAisBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { + rEventConnStatus.ucInfraMode = (UINT_8)NET_TYPE_INFRA; + rEventConnStatus.u2AID = prAisBssInfo->u2AssocId; + rEventConnStatus.u2ATIMWindow = 0; + } + else if (prAisBssInfo->eCurrentOPMode == OP_MODE_IBSS) { + rEventConnStatus.ucInfraMode = (UINT_8)NET_TYPE_IBSS; + rEventConnStatus.u2AID = 0; + rEventConnStatus.u2ATIMWindow = prAisBssInfo->u2ATIMWindow; + } + else { + ASSERT(0); + } + + COPY_SSID(rEventConnStatus.aucSsid, + rEventConnStatus.ucSsidLen, + prConnSettings->aucSSID, + prConnSettings->ucSSIDLen); + + COPY_MAC_ADDR(rEventConnStatus.aucBssid, prAisBssInfo->aucBSSID); + + rEventConnStatus.u2BeaconPeriod = prAisBssInfo->u2BeaconInterval; + rEventConnStatus.u4FreqInKHz = nicChannelNum2Freq(prAisBssInfo->ucPrimaryChannel); + + switch (prAisBssInfo->ucNonHTBasicPhyType) { + case PHY_TYPE_HR_DSSS_INDEX: + rEventConnStatus.ucNetworkType = (UINT_8)PARAM_NETWORK_TYPE_DS; + break; + + case PHY_TYPE_ERP_INDEX: + rEventConnStatus.ucNetworkType = (UINT_8)PARAM_NETWORK_TYPE_OFDM24; + break; + + case PHY_TYPE_OFDM_INDEX: + rEventConnStatus.ucNetworkType = (UINT_8)PARAM_NETWORK_TYPE_OFDM5; + break; + + default: + ASSERT(0); + rEventConnStatus.ucNetworkType = (UINT_8)PARAM_NETWORK_TYPE_DS; + break; + } + } + else { + /* Deactivate previous Peers' STA_RECORD_T in Driver if have. */ + bssClearClientList(prAdapter, prAisBssInfo); + + #if CFG_PRIVACY_MIGRATION + /* Clear the pmkid cache while media disconnect */ + secClearPmkid(prAdapter); + #endif + + rEventConnStatus.ucReasonOfDisconnect = prAisBssInfo->ucReasonOfDisconnect; + } + + //4 <2> Indication + nicMediaStateChange(prAdapter, NETWORK_TYPE_AIS_INDEX, &rEventConnStatus); + prAisBssInfo->eConnectionStateIndicated = eConnectionState; + } + else { + /* NOTE: Only delay the Indication of Disconnect Event */ + ASSERT(eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED); + + DBGLOG(AIS, INFO, ("Postpone the indication of Disconnect for %d seconds\n", + prConnSettings->ucDelayTimeOfDisconnectEvent)); + + cnmTimerStartTimer(prAdapter, + &prAisFsmInfo->rIndicationOfDisconnectTimer, + SEC_TO_MSEC(prConnSettings->ucDelayTimeOfDisconnectEvent)); + } + + return; +} /* end of aisIndicationOfMediaStateToHost() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate an Event of "Media Disconnect" to HOST +* +* @param[in] u4Param Unused timer parameter +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisPostponedEventOfDisconnTimeout ( + IN P_ADAPTER_T prAdapter, + UINT_32 u4Param + ) +{ + P_BSS_INFO_T prAisBssInfo; + + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + //4 <1> Deactivate previous AP's STA_RECORD_T in Driver if have. + if (prAisBssInfo->prStaRecOfAP) { + //cnmStaRecChangeState(prAdapter, prAisBssInfo->prStaRecOfAP, STA_STATE_1); + + prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T)NULL; + } + + //4 <2> Remove pending connection request + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_RECONNECT, TRUE); + + //4 <3> Indicate Disconnected Event to Host immediately. + aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED, FALSE); + + return; +} /* end of aisPostponedEventOfDisconnTimeout() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will update the contain of BSS_INFO_T for AIS network once +* the association was completed. +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] prAssocRspSwRfb Pointer to SW RFB of ASSOC RESP FRAME. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisUpdateBssInfoForJOIN ( + IN P_ADAPTER_T prAdapter, + P_STA_RECORD_T prStaRec, + P_SW_RFB_T prAssocRspSwRfb + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame; + P_BSS_DESC_T prBssDesc; + UINT_16 u2IELength; + PUINT_8 pucIE; + + DEBUGFUNC("aisUpdateBssInfoForJOIN()"); + + ASSERT(prStaRec); + ASSERT(prAssocRspSwRfb); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) prAssocRspSwRfb->pvHeader; + + + DBGLOG(AIS, INFO, ("Update AIS_BSS_INFO_T and apply settings to MAC\n")); + + + //3 <1> Update BSS_INFO_T from AIS_FSM_INFO_T or User Settings + //4 <1.1> Setup Operation Mode + prAisBssInfo->eCurrentOPMode = OP_MODE_INFRASTRUCTURE; + + //4 <1.2> Setup SSID + COPY_SSID(prAisBssInfo->aucSSID, + prAisBssInfo->ucSSIDLen, + prConnSettings->aucSSID, + prConnSettings->ucSSIDLen); + + //4 <1.3> Setup Channel, Band + prAisBssInfo->ucPrimaryChannel = prAisFsmInfo->prTargetBssDesc->ucChannelNum; + prAisBssInfo->eBand = prAisFsmInfo->prTargetBssDesc->eBand; + + + //3 <2> Update BSS_INFO_T from STA_RECORD_T + //4 <2.1> Save current AP's STA_RECORD_T and current AID + prAisBssInfo->prStaRecOfAP = prStaRec; + prAisBssInfo->u2AssocId = prStaRec->u2AssocId; + + //4 <2.2> Setup Capability + prAisBssInfo->u2CapInfo = prStaRec->u2CapInfo; /* Use AP's Cap Info as BSS Cap Info */ + + if (prAisBssInfo->u2CapInfo & CAP_INFO_SHORT_PREAMBLE) { + prAisBssInfo->fgIsShortPreambleAllowed = TRUE; + } + else { + prAisBssInfo->fgIsShortPreambleAllowed = FALSE; + } + + //4 <2.3> Setup PHY Attributes and Basic Rate Set/Operational Rate Set + prAisBssInfo->ucPhyTypeSet = prStaRec->ucDesiredPhyTypeSet; + + prAisBssInfo->ucNonHTBasicPhyType = prStaRec->ucNonHTBasicPhyType; + + prAisBssInfo->u2OperationalRateSet = prStaRec->u2OperationalRateSet; + prAisBssInfo->u2BSSBasicRateSet = prStaRec->u2BSSBasicRateSet; + + + //3 <3> Update BSS_INFO_T from SW_RFB_T (Association Resp Frame) + //4 <3.1> Setup BSSID + COPY_MAC_ADDR(prAisBssInfo->aucBSSID, prAssocRspFrame->aucBSSID); + + + u2IELength = (UINT_16) ((prAssocRspSwRfb->u2PacketLen - prAssocRspSwRfb->u2HeaderLen) - + (OFFSET_OF(WLAN_ASSOC_RSP_FRAME_T, aucInfoElem[0]) - WLAN_MAC_MGMT_HEADER_LEN)); + pucIE = prAssocRspFrame->aucInfoElem; + + + //4 <3.2> Parse WMM and setup QBSS flag + /* Parse WMM related IEs and configure HW CRs accordingly */ + mqmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); + + prAisBssInfo->fgIsQBSS = prStaRec->fgIsQoS; + + //3 <4> Update BSS_INFO_T from BSS_DESC_T + prBssDesc = scanSearchBssDescByBssid(prAdapter, prAssocRspFrame->aucBSSID); + if(prBssDesc) { + prBssDesc->fgIsConnecting = FALSE; + prBssDesc->fgIsConnected = TRUE; + + //4 <4.1> Setup MIB for current BSS + prAisBssInfo->u2BeaconInterval = prBssDesc->u2BeaconInterval; + } + else { + // should never happen + ASSERT(0); + } + + /* NOTE: Defer ucDTIMPeriod updating to when beacon is received after connection */ + prAisBssInfo->ucDTIMPeriod = 0; + prAisBssInfo->u2ATIMWindow = 0; + + prAisBssInfo->ucBeaconTimeoutCount = AIS_BEACON_TIMEOUT_COUNT_INFRA; + + //4 <4.2> Update HT information and set channel + /* Record HT related parameters in rStaRec and rBssInfo + * Note: it shall be called before nicUpdateBss() + */ + rlmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); + + //4 <4.3> Sync with firmware for BSS-INFO + nicUpdateBss(prAdapter, NETWORK_TYPE_AIS_INDEX); + + //4 <4.4> *DEFER OPERATION* nicPmIndicateBssConnected() will be invoked + //inside scanProcessBeaconAndProbeResp() after 1st beacon is received + + return; +} /* end of aisUpdateBssInfoForJOIN() */ + + +#if CFG_SUPPORT_ADHOC +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will create an Ad-Hoc network and start sending Beacon Frames. +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisUpdateBssInfoForCreateIBSS ( + IN P_ADAPTER_T prAdapter + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + if (prAisBssInfo->fgIsBeaconActivated) { + return; + } + + //3 <1> Update BSS_INFO_T per Network Basis + //4 <1.1> Setup Operation Mode + prAisBssInfo->eCurrentOPMode = OP_MODE_IBSS; + + //4 <1.2> Setup SSID + COPY_SSID(prAisBssInfo->aucSSID, + prAisBssInfo->ucSSIDLen, + prConnSettings->aucSSID, + prConnSettings->ucSSIDLen); + + //4 <1.3> Clear current AP's STA_RECORD_T and current AID + prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T)NULL; + prAisBssInfo->u2AssocId = 0; + + //4 <1.4> Setup Channel, Band and Phy Attributes + prAisBssInfo->ucPrimaryChannel = prConnSettings->ucAdHocChannelNum; + prAisBssInfo->eBand = prConnSettings->eAdHocBand; + + if (prAisBssInfo->eBand == BAND_2G4) { + + prAisBssInfo->ucPhyTypeSet = + prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11BGN; /* Depend on eBand */ + + prAisBssInfo->ucConfigAdHocAPMode = AD_HOC_MODE_MIXED_11BG; /* Depend on eCurrentOPMode and ucPhyTypeSet */ + } + else { + + prAisBssInfo->ucPhyTypeSet = + prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11AN; /* Depend on eBand */ + + prAisBssInfo->ucConfigAdHocAPMode = AD_HOC_MODE_11A; /* Depend on eCurrentOPMode and ucPhyTypeSet */ + } + + //4 <1.5> Setup MIB for current BSS + prAisBssInfo->u2BeaconInterval = prConnSettings->u2BeaconPeriod; + prAisBssInfo->ucDTIMPeriod = 0; + prAisBssInfo->u2ATIMWindow = prConnSettings->u2AtimWindow; + + prAisBssInfo->ucBeaconTimeoutCount = AIS_BEACON_TIMEOUT_COUNT_ADHOC; + +#if CFG_PRIVACY_MIGRATION + if (prConnSettings->eEncStatus == ENUM_ENCRYPTION1_ENABLED || + prConnSettings->eEncStatus == ENUM_ENCRYPTION2_ENABLED || + prConnSettings->eEncStatus == ENUM_ENCRYPTION3_ENABLED) { + prAisBssInfo->fgIsProtection = TRUE; + } + else { + prAisBssInfo->fgIsProtection = FALSE; + } +#else + prAisBssInfo->fgIsProtection = FALSE; +#endif + + //3 <2> Update BSS_INFO_T common part + ibssInitForAdHoc(prAdapter, prAisBssInfo); + + + + //3 <3> Set MAC HW + //4 <3.1> Setup channel and bandwidth + rlmBssInitForAPandIbss(prAdapter, prAisBssInfo); + + //4 <3.2> use command packets to inform firmware + nicUpdateBss(prAdapter, NETWORK_TYPE_AIS_INDEX); + + //4 <3.3> enable beaconing + bssUpdateBeaconContent(prAdapter, NETWORK_TYPE_AIS_INDEX); + + //4 <3.4> Update AdHoc PM parameter + nicPmIndicateBssCreated(prAdapter, NETWORK_TYPE_AIS_INDEX); + + //3 <4> Set ACTIVE flag. + prAisBssInfo->fgIsBeaconActivated = TRUE; + prAisBssInfo->fgHoldSameBssidForIBSS = TRUE; + + //3 <5> Start IBSS Alone Timer + cnmTimerStartTimer(prAdapter, + &prAisFsmInfo->rIbssAloneTimer, + SEC_TO_MSEC(AIS_IBSS_ALONE_TIMEOUT_SEC)); + + return; + +} /* end of aisCreateIBSS() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will update the contain of BSS_INFO_T for AIS network once +* the existing IBSS was found. +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisUpdateBssInfoForMergeIBSS ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_DESC_T prBssDesc; + //UINT_16 u2IELength; + //PUINT_8 pucIE; + + + ASSERT(prStaRec); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rIbssAloneTimer); + + if (!prAisBssInfo->fgIsBeaconActivated) { + + //3 <1> Update BSS_INFO_T per Network Basis + //4 <1.1> Setup Operation Mode + prAisBssInfo->eCurrentOPMode = OP_MODE_IBSS; + + //4 <1.2> Setup SSID + COPY_SSID(prAisBssInfo->aucSSID, + prAisBssInfo->ucSSIDLen, + prConnSettings->aucSSID, + prConnSettings->ucSSIDLen); + + //4 <1.3> Clear current AP's STA_RECORD_T and current AID + prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T)NULL; + prAisBssInfo->u2AssocId = 0; + } + + //3 <2> Update BSS_INFO_T from STA_RECORD_T + //4 <2.1> Setup Capability + prAisBssInfo->u2CapInfo = prStaRec->u2CapInfo; /* Use Peer's Cap Info as IBSS Cap Info */ + + if (prAisBssInfo->u2CapInfo & CAP_INFO_SHORT_PREAMBLE) { + prAisBssInfo->fgIsShortPreambleAllowed = TRUE; + prAisBssInfo->fgUseShortPreamble = TRUE; + } + else { + prAisBssInfo->fgIsShortPreambleAllowed = FALSE; + prAisBssInfo->fgUseShortPreamble = FALSE; + } + + // 7.3.1.4 For IBSS, the Short Slot Time subfield shall be set to 0. + prAisBssInfo->fgUseShortSlotTime = FALSE; /* Set to FALSE for AdHoc */ + prAisBssInfo->u2CapInfo &= ~CAP_INFO_SHORT_SLOT_TIME; + + if (prAisBssInfo->u2CapInfo & CAP_INFO_PRIVACY) { + prAisBssInfo->fgIsProtection= TRUE; + } + else { + prAisBssInfo->fgIsProtection = FALSE; + } + + //4 <2.2> Setup PHY Attributes and Basic Rate Set/Operational Rate Set + prAisBssInfo->ucPhyTypeSet = prStaRec->ucDesiredPhyTypeSet; + + prAisBssInfo->ucNonHTBasicPhyType = prStaRec->ucNonHTBasicPhyType; + + prAisBssInfo->u2OperationalRateSet = prStaRec->u2OperationalRateSet; + prAisBssInfo->u2BSSBasicRateSet = prStaRec->u2BSSBasicRateSet; + + rateGetDataRatesFromRateSet(prAisBssInfo->u2OperationalRateSet, + prAisBssInfo->u2BSSBasicRateSet, + prAisBssInfo->aucAllSupportedRates, + &prAisBssInfo->ucAllSupportedRatesLen); + + //3 <3> X Update BSS_INFO_T from SW_RFB_T (Association Resp Frame) + + + //3 <4> Update BSS_INFO_T from BSS_DESC_T + prBssDesc = scanSearchBssDescByTA(prAdapter, prStaRec->aucMacAddr); + if(prBssDesc) { + prBssDesc->fgIsConnecting = FALSE; + prBssDesc->fgIsConnected = TRUE; + + //4 <4.1> Setup BSSID + COPY_MAC_ADDR(prAisBssInfo->aucBSSID, prBssDesc->aucBSSID); + + //4 <4.2> Setup Channel, Band + prAisBssInfo->ucPrimaryChannel = prBssDesc->ucChannelNum; + prAisBssInfo->eBand = prBssDesc->eBand; + + //4 <4.3> Setup MIB for current BSS + prAisBssInfo->u2BeaconInterval = prBssDesc->u2BeaconInterval; + prAisBssInfo->ucDTIMPeriod = 0; + prAisBssInfo->u2ATIMWindow = 0; /* TBD(Kevin) */ + + prAisBssInfo->ucBeaconTimeoutCount = AIS_BEACON_TIMEOUT_COUNT_ADHOC; + } + else { + // should never happen + ASSERT(0); + } + + + //3 <5> Set MAC HW + //4 <5.1> Find Lowest Basic Rate Index for default TX Rate of MMPDU + { + UINT_8 ucLowestBasicRateIndex; + + if (!rateGetLowestRateIndexFromRateSet(prAisBssInfo->u2BSSBasicRateSet, + &ucLowestBasicRateIndex)) { + + if (prAisBssInfo->ucPhyTypeSet & PHY_TYPE_BIT_OFDM) { + ucLowestBasicRateIndex = RATE_6M_INDEX; + } + else { + ucLowestBasicRateIndex = RATE_1M_INDEX; + } + } + + prAisBssInfo->ucHwDefaultFixedRateCode = + aucRateIndex2RateCode[prAisBssInfo->fgUseShortPreamble][ucLowestBasicRateIndex]; + } + + //4 <5.2> Setup channel and bandwidth + rlmBssInitForAPandIbss(prAdapter, prAisBssInfo); + + //4 <5.3> use command packets to inform firmware + nicUpdateBss(prAdapter, NETWORK_TYPE_AIS_INDEX); + + //4 <5.4> enable beaconing + bssUpdateBeaconContent(prAdapter, NETWORK_TYPE_AIS_INDEX); + + //4 <5.5> Update AdHoc PM parameter + nicPmIndicateBssConnected(prAdapter, NETWORK_TYPE_AIS_INDEX); + + //3 <6> Set ACTIVE flag. + prAisBssInfo->fgIsBeaconActivated = TRUE; + prAisBssInfo->fgHoldSameBssidForIBSS = TRUE; + + return; +} /* end of aisUpdateBssInfoForMergeIBSS() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will validate the Rx Probe Request Frame and then return +* result to BSS to indicate if need to send the corresponding Probe Response +* Frame if the specified conditions were matched. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[out] pu4ControlFlags Control flags for replying the Probe Response +* +* @retval TRUE Reply the Probe Response +* @retval FALSE Don't reply the Probe Response +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +aisValidateProbeReq ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT PUINT_32 pu4ControlFlags + ) +{ + P_WLAN_MAC_MGMT_HEADER_T prMgtHdr; + P_BSS_INFO_T prBssInfo; + P_IE_SSID_T prIeSsid = (P_IE_SSID_T)NULL; + PUINT_8 pucIE; + UINT_16 u2IELength; + UINT_16 u2Offset = 0; + BOOLEAN fgReplyProbeResp = FALSE; + + + ASSERT(prSwRfb); + ASSERT(pu4ControlFlags); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + //4 <1> Parse Probe Req IE and Get IE ptr (SSID, Supported Rate IE, ...) + prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T)prSwRfb->pvHeader; + + u2IELength = prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen; + pucIE = (PUINT_8)((UINT_32)prSwRfb->pvHeader + prSwRfb->u2HeaderLen); + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + if (ELEM_ID_SSID == IE_ID(pucIE)) { + if ((!prIeSsid) && + (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) { + prIeSsid = (P_IE_SSID_T)pucIE; + } + break; + } + } /* end of IE_FOR_EACH */ + + //4 <2> Check network conditions + + if (prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { + + if ((prIeSsid) && + ((prIeSsid->ucLength == BC_SSID_LEN) || /* WILDCARD SSID */ + EQUAL_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, /* CURRENT SSID */ + prIeSsid->aucSSID, prIeSsid->ucLength)) ) { + fgReplyProbeResp = TRUE; + } + } + + return fgReplyProbeResp; + +} /* end of aisValidateProbeReq() */ + +#endif /* CFG_SUPPORT_ADHOC */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will modify and update necessary information to firmware +* for disconnection handling +* +* @param[in] prAdapter Pointer to the Adapter structure. +* +* @retval None +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmDisconnect ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgDelayIndication + ) +{ + P_BSS_INFO_T prAisBssInfo; + + ASSERT(prAdapter); + + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_AIS_INDEX); + +#if CFG_SUPPORT_ADHOC + if (prAisBssInfo->fgIsBeaconActivated) { + nicUpdateBeaconIETemplate(prAdapter, + IE_UPD_METHOD_DELETE_ALL, + NETWORK_TYPE_AIS_INDEX, + 0, + NULL, + 0); + + prAisBssInfo->fgIsBeaconActivated = FALSE; + } +#endif + + rlmBssAborted(prAdapter, prAisBssInfo); + + //4 <3> Unset the fgIsConnected flag of BSS_DESC_T and send Deauth if needed. + if (PARAM_MEDIA_STATE_CONNECTED == prAisBssInfo->eConnectionState) { + + if (prAisBssInfo->ucReasonOfDisconnect == DISCONNECT_REASON_CODE_RADIO_LOST) { + scanRemoveBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); + + /* remove from scanning results as well */ + wlanClearBssInScanningResult(prAdapter, prAisBssInfo->aucBSSID); + + /* trials for re-association */ + if (fgDelayIndication) { + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_RECONNECT, TRUE); + aisFsmInsertRequest(prAdapter, AIS_REQUEST_RECONNECT); + } + } + else { + scanRemoveConnFlagOfBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); + } + + if (fgDelayIndication) { + if (OP_MODE_IBSS != prAisBssInfo->eCurrentOPMode) { + prAisBssInfo->fgHoldSameBssidForIBSS = FALSE; + } + } + else { + prAisBssInfo->fgHoldSameBssidForIBSS = FALSE; + } + } + else { + prAisBssInfo->fgHoldSameBssidForIBSS = FALSE; + } + + + //4 <4> Change Media State immediately. + aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); + + //4 <4.1> sync. with firmware + nicUpdateBss(prAdapter, NETWORK_TYPE_AIS_INDEX); + + if (!fgDelayIndication) { + //4 <5> Deactivate previous AP's STA_RECORD_T or all Clients in Driver if have. + if (prAisBssInfo->prStaRecOfAP) { + //cnmStaRecChangeState(prAdapter, prAisBssInfo->prStaRecOfAP, STA_STATE_1); + + prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T)NULL; + } + } + +#if CFG_SUPPORT_ROAMING + roamingFsmRunEventAbort(prAdapter); + + /* clear pending roaming connection request */ + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_SEARCH, TRUE); + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_CONNECT, TRUE); +#endif /* CFG_SUPPORT_ROAMING */ + + //4 <6> Indicate Disconnected Event to Host + aisIndicationOfMediaStateToHost(prAdapter, + PARAM_MEDIA_STATE_DISCONNECTED, + fgDelayIndication); + + + //4 <7> Trigger AIS FSM + aisFsmSteps(prAdapter, AIS_STATE_IDLE); + + return; +} /* end of aisFsmDisconnect() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate an Event of "Background Scan Time-Out" to AIS FSM. +* +* @param[in] u4Param Unused timer parameter +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmRunEventBGSleepTimeOut ( + IN P_ADAPTER_T prAdapter, + UINT_32 u4Param + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + ENUM_AIS_STATE_T eNextState; + + DEBUGFUNC("aisFsmRunEventBGSleepTimeOut()"); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + eNextState = prAisFsmInfo->eCurrentState; + + switch (prAisFsmInfo->eCurrentState) { + case AIS_STATE_WAIT_FOR_NEXT_SCAN: + DBGLOG(AIS, LOUD, ("EVENT - SCAN TIMER: Idle End - Current Time = %ld\n", kalGetTimeTick())); + + eNextState = AIS_STATE_LOOKING_FOR; + + SET_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX); + + break; + + default: + break; + } + + /* Call aisFsmSteps() when we are going to change AIS STATE */ + if (eNextState != prAisFsmInfo->eCurrentState) { + aisFsmSteps(prAdapter, eNextState); + } + + return; +} /* end of aisFsmBGSleepTimeout() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate an Event of "IBSS ALONE Time-Out" to AIS FSM. +* +* @param[in] u4Param Unused timer parameter +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmRunEventIbssAloneTimeOut ( + IN P_ADAPTER_T prAdapter, + UINT_32 u4Param + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + ENUM_AIS_STATE_T eNextState; + + DEBUGFUNC("aisFsmRunEventIbssAloneTimeOut()"); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + eNextState = prAisFsmInfo->eCurrentState; + + switch(prAisFsmInfo->eCurrentState) { + case AIS_STATE_IBSS_ALONE: + + /* There is no one participate in our AdHoc during this TIMEOUT Interval + * so go back to search for a valid IBSS again. + */ + + DBGLOG(AIS, LOUD, ("EVENT-IBSS ALONE TIMER: Start pairing\n")); + + prAisFsmInfo->fgTryScan = TRUE; + + /* abort timer */ + aisFsmReleaseCh(prAdapter); + + /* Pull back to SEARCH to find candidate again */ + eNextState = AIS_STATE_SEARCH; + + break; + + default: + break; + } + + + /* Call aisFsmSteps() when we are going to change AIS STATE */ + if (eNextState != prAisFsmInfo->eCurrentState) { + aisFsmSteps(prAdapter, eNextState); + } + + return; +} /* end of aisIbssAloneTimeOut() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate an Event of "Join Time-Out" to AIS FSM. +* +* @param[in] u4Param Unused timer parameter +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmRunEventJoinTimeout ( + IN P_ADAPTER_T prAdapter, + UINT_32 u4Param + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + ENUM_AIS_STATE_T eNextState; + + DEBUGFUNC("aisFsmRunEventJoinTimeout()"); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + eNextState = prAisFsmInfo->eCurrentState; + + switch(prAisFsmInfo->eCurrentState) { + case AIS_STATE_JOIN: + DBGLOG(AIS, LOUD, ("EVENT- JOIN TIMEOUT\n")); + + /* 1. Do abort JOIN */ + aisFsmStateAbort_JOIN(prAdapter); + + /* 2. Increase Join Failure Count */ + prAisFsmInfo->prTargetStaRec->ucJoinFailureCount++; + + if(prAisFsmInfo->prTargetStaRec->ucJoinFailureCount < JOIN_MAX_RETRY_FAILURE_COUNT) { + /* 3.1 Retreat to AIS_STATE_SEARCH state for next try */ + eNextState = AIS_STATE_SEARCH; + } + else { + /* 3.2 Retreat to AIS_STATE_WAIT_FOR_NEXT_SCAN state for next try */ + eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; + } + break; + + case AIS_STATE_NORMAL_TR: + /* 1. release channel */ + aisFsmReleaseCh(prAdapter); + prAisFsmInfo->fgIsInfraChannelFinished = TRUE; + + /* 2. process if there is pending scan */ + if(aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, TRUE) == TRUE) { + wlanClearScanningResult(prAdapter); + eNextState = AIS_STATE_ONLINE_SCAN; + } + + break; + + default: + /* release channel */ + aisFsmReleaseCh(prAdapter); + break; + + } + + + /* Call aisFsmSteps() when we are going to change AIS STATE */ + if (eNextState != prAisFsmInfo->eCurrentState) { + aisFsmSteps(prAdapter, eNextState); + } + + return; +} /* end of aisFsmRunEventJoinTimeout() */ + + +#if defined(CFG_TEST_MGMT_FSM) && (CFG_TEST_MGMT_FSM != 0) +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisTest ( + VOID + ) +{ + P_MSG_AIS_ABORT_T prAisAbortMsg; + P_CONNECTION_SETTINGS_T prConnSettings; + UINT_8 aucSSID[]="pci-11n"; + UINT_8 ucSSIDLen=7; + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + /* Set Connection Request Issued Flag */ + prConnSettings->fgIsConnReqIssued = TRUE; + prConnSettings->ucSSIDLen = ucSSIDLen; + kalMemCopy(prConnSettings->aucSSID, aucSSID, ucSSIDLen); + + prAisAbortMsg = (P_MSG_AIS_ABORT_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); + if (!prAisAbortMsg) { + + ASSERT(0); // Can't trigger SCAN FSM + return; + } + + prAisAbortMsg->rMsgHdr.eMsgId = MID_HEM_AIS_FSM_ABORT; + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prAisAbortMsg, + MSG_SEND_METHOD_BUF); + + wifi_send_msg(INDX_WIFI, MSG_ID_WIFI_IST, 0); + + return; +} +#endif /* CFG_TEST_MGMT_FSM */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is used to handle OID_802_11_BSSID_LIST_SCAN +* +* \param[in] prAdapter Pointer of ADAPTER_T +* \param[in] prAdapter Pointer of SSID_T if specified +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmScanRequest ( + IN P_ADAPTER_T prAdapter, + IN P_PARAM_SSID_T prSsid + ) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_INFO_T prAisBssInfo; + P_AIS_FSM_INFO_T prAisFsmInfo; + + DEBUGFUNC("aisFsmScanRequest()"); + + ASSERT(prAdapter); + + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + if (!prConnSettings->fgIsScanReqIssued) { + prConnSettings->fgIsScanReqIssued = TRUE; + + if(prSsid == NULL) { + prAisFsmInfo->ucScanSSIDLen = 0; + } + else { + COPY_SSID(prAisFsmInfo->aucScanSSID, + prAisFsmInfo->ucScanSSIDLen, + prSsid->aucSsid, + (UINT_8)prSsid->u4SsidLen); + } + + if(prAisFsmInfo->eCurrentState == AIS_STATE_NORMAL_TR) { + if(prAisBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE + && prAisFsmInfo->fgIsInfraChannelFinished == FALSE) { + // 802.1x might not finished yet, pend it for later handling .. + aisFsmInsertRequest(prAdapter, AIS_REQUEST_SCAN); + } + else { + if(prAisFsmInfo->fgIsChannelGranted == TRUE) { + DBGLOG(AIS, WARN, ("Scan Request with channel granted for join operation: %d, %d", + prAisFsmInfo->fgIsChannelGranted, + prAisFsmInfo->fgIsChannelRequested)); + } + + /* start online scan */ + wlanClearScanningResult(prAdapter); + aisFsmSteps(prAdapter, AIS_STATE_ONLINE_SCAN); + } + } + else if(prAisFsmInfo->eCurrentState == AIS_STATE_IDLE) { + wlanClearScanningResult(prAdapter); + aisFsmSteps(prAdapter, AIS_STATE_SCAN); + } + else { + aisFsmInsertRequest(prAdapter, AIS_REQUEST_SCAN); + } + } + else { + DBGLOG(AIS, WARN, ("Scan Request dropped. (state: %d)\n", prAisFsmInfo->eCurrentState)); + } + + return; +} /* end of aisFsmScanRequest() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is invoked when CNM granted channel privilege +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmRunEventChGrant ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_BSS_INFO_T prAisBssInfo; + P_AIS_FSM_INFO_T prAisFsmInfo; + P_MSG_CH_GRANT_T prMsgChGrant; + UINT_8 ucTokenID; + UINT_32 u4GrantInterval; + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prMsgChGrant = (P_MSG_CH_GRANT_T)prMsgHdr; + + ucTokenID = prMsgChGrant->ucTokenID; + u4GrantInterval = prMsgChGrant->u4GrantInterval; + + /* 1. free message */ + cnmMemFree(prAdapter, prMsgHdr); + + if(prAisFsmInfo->eCurrentState == AIS_STATE_REQ_CHANNEL_JOIN && + prAisFsmInfo->ucSeqNumOfChReq == ucTokenID) { + /* 2. channel privilege has been approved */ + prAisFsmInfo->u4ChGrantedInterval = u4GrantInterval; + + /* 3. state transition to join/ibss-alone/ibss-merge */ + /* 3.1 set timeout timer in cases join could not be completed */ + cnmTimerStartTimer(prAdapter, + &prAisFsmInfo->rJoinTimeoutTimer, + prAisFsmInfo->u4ChGrantedInterval - AIS_JOIN_CH_GRANT_THRESHOLD); + /* 3.2 set local variable to indicate join timer is ticking */ + prAisFsmInfo->fgIsInfraChannelFinished = FALSE; + + /* 3.3 switch to join state */ + aisFsmSteps(prAdapter, AIS_STATE_JOIN); + + prAisFsmInfo->fgIsChannelGranted = TRUE; + } + else { /* mismatched grant */ + /* 2. return channel privilege to CNM immediately */ + aisFsmReleaseCh(prAdapter); + } + + return; +} /* end of aisFsmRunEventChGrant() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is to inform CNM that channel privilege +* has been released +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmReleaseCh ( + IN P_ADAPTER_T prAdapter + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_MSG_CH_ABORT_T prMsgChAbort; + + ASSERT(prAdapter); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + if(prAisFsmInfo->fgIsChannelGranted == TRUE + || prAisFsmInfo->fgIsChannelRequested == TRUE) { + + prAisFsmInfo->fgIsChannelRequested = FALSE; + prAisFsmInfo->fgIsChannelGranted = FALSE; + + /* 1. return channel privilege to CNM immediately */ + prMsgChAbort = (P_MSG_CH_ABORT_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_ABORT_T)); + if (!prMsgChAbort) { + ASSERT(0); // Can't release Channel to CNM + return; + } + + prMsgChAbort->rMsgHdr.eMsgId = MID_MNY_CNM_CH_ABORT; + prMsgChAbort->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; + prMsgChAbort->ucTokenID = prAisFsmInfo->ucSeqNumOfChReq; + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prMsgChAbort, + MSG_SEND_METHOD_BUF); + } + + return; +} /* end of aisFsmReleaseCh() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is to inform AIS that corresponding beacon has not +* been received for a while and probing is not successful +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisBssBeaconTimeout ( + IN P_ADAPTER_T prAdapter + ) +{ + P_BSS_INFO_T prAisBssInfo; + BOOLEAN fgDoAbortIndication = FALSE; + + ASSERT(prAdapter); + + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + //4 <1> Diagnose Connection for Beacon Timeout Event + if (PARAM_MEDIA_STATE_CONNECTED == prAisBssInfo->eConnectionState) { + if (OP_MODE_INFRASTRUCTURE == prAisBssInfo->eCurrentOPMode) { + P_STA_RECORD_T prStaRec = prAisBssInfo->prStaRecOfAP; + + if (prStaRec) { + fgDoAbortIndication = TRUE; + } + } + else if (OP_MODE_IBSS == prAisBssInfo->eCurrentOPMode) { + fgDoAbortIndication = TRUE; + } + } + + //4 <2> invoke abort handler + if (fgDoAbortIndication) { + aisFsmStateAbort(prAdapter, DISCONNECT_REASON_CODE_RADIO_LOST, TRUE); + } + + return; +} /* end of aisBssBeaconTimeout() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is to inform AIS that DEAUTH frame has been +* sent and thus state machine could go ahead +* +* \param[in] prAdapter Pointer of ADAPTER_T +* \param[in] prMsduInfo Pointer of MSDU_INFO_T for DEAUTH frame +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +aisDeauthXmitComplete ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + + ASSERT(prAdapter); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + if(prAisFsmInfo->eCurrentState == AIS_STATE_DISCONNECTING) { + if(rTxDoneStatus != TX_RESULT_DROPPED_IN_DRIVER) { + aisFsmStateAbort(prAdapter, DISCONNECT_REASON_CODE_NEW_CONNECTION, FALSE); + } + } + else { + DBGLOG(AIS, WARN, ("DEAUTH frame transmitted without further handling")); + } + + return WLAN_STATUS_SUCCESS; + +} /* end of aisDeauthXmitComplete() */ + +#if CFG_SUPPORT_ROAMING +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate an Event of "Looking for a candidate due to weak signal" to AIS FSM. +* +* @param[in] u4ReqScan Requesting Scan or not +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmRunEventRoamingDiscovery ( + IN P_ADAPTER_T prAdapter, + UINT_32 u4ReqScan + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + ENUM_AIS_REQUEST_TYPE_T eAisRequest; + + DBGLOG(AIS, LOUD, ("aisFsmRunEventRoamingDiscovery()\n")); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + /* search candidates by best rssi */ + prConnSettings->eConnectionPolicy = CONNECT_BY_SSID_BEST_RSSI; + + /* results are still new */ + if (!u4ReqScan) { + roamingFsmRunEventRoam(prAdapter); + eAisRequest = AIS_REQUEST_ROAMING_CONNECT; + } + else { + if(prAisFsmInfo->eCurrentState == AIS_STATE_ONLINE_SCAN + || prAisFsmInfo->eCurrentState == AIS_STATE_LOOKING_FOR) { + eAisRequest = AIS_REQUEST_ROAMING_CONNECT; + } + else { + eAisRequest = AIS_REQUEST_ROAMING_SEARCH; + } + } + + if(prAisFsmInfo->eCurrentState == AIS_STATE_NORMAL_TR && prAisFsmInfo->fgIsInfraChannelFinished == TRUE) { + if(eAisRequest == AIS_REQUEST_ROAMING_SEARCH) { + aisFsmSteps(prAdapter, AIS_STATE_LOOKING_FOR); + } + else { + aisFsmSteps(prAdapter, AIS_STATE_SEARCH); + } + } + else { + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_SEARCH, TRUE); + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_CONNECT, TRUE); + + aisFsmInsertRequest(prAdapter, eAisRequest); + } + + return; +} /* end of aisFsmRunEventRoamingDiscovery() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Update the time of ScanDone for roaming and transit to Roam state. +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +ENUM_AIS_STATE_T +aisFsmRoamingScanResultsUpdate ( + IN P_ADAPTER_T prAdapter + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_ROAMING_INFO_T prRoamingFsmInfo; + ENUM_AIS_STATE_T eNextState; + + DBGLOG(AIS, LOUD, ("->aisFsmRoamingScanResultsUpdate()\n")); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prRoamingFsmInfo = (P_ROAMING_INFO_T)&(prAdapter->rWifiVar.rRoamingInfo); + + roamingFsmScanResultsUpdate(prAdapter); + + eNextState = prAisFsmInfo->eCurrentState; + if (prRoamingFsmInfo->eCurrentState == ROAMING_STATE_DISCOVERY) { + roamingFsmRunEventRoam(prAdapter); + eNextState = AIS_STATE_SEARCH; + } + else if (prAisFsmInfo->eCurrentState == AIS_STATE_LOOKING_FOR) { + eNextState = AIS_STATE_SEARCH; + } + else if (prAisFsmInfo->eCurrentState == AIS_STATE_ONLINE_SCAN) { + eNextState = AIS_STATE_NORMAL_TR; + } + + return eNextState; +} /* end of aisFsmRoamingScanResultsUpdate() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will modify and update necessary information to firmware +* for disconnection of last AP before switching to roaming bss. +* +* @param IN prAdapter Pointer to the Adapter structure. +* prTargetStaRec Target of StaRec of roaming +* +* @retval None +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmRoamingDisconnectPrevAP ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prTargetStaRec + ) +{ + P_BSS_INFO_T prAisBssInfo; + + DBGLOG(AIS, LOUD, ("aisFsmRoamingDisconnectPrevAP()")); + + ASSERT(prAdapter); + + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_AIS_INDEX); + + /* Not invoke rlmBssAborted() here to avoid prAisBssInfo->fg40mBwAllowed + * to be reset. RLM related parameters will be reset again when handling + * association response in rlmProcessAssocRsp(). 20110413 + */ + //rlmBssAborted(prAdapter, prAisBssInfo); + + //4 <3> Unset the fgIsConnected flag of BSS_DESC_T and send Deauth if needed. + if (PARAM_MEDIA_STATE_CONNECTED == prAisBssInfo->eConnectionState) { + scanRemoveConnFlagOfBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); + } + + //4 <4> Change Media State immediately. + aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); + + //4 <4.1> sync. with firmware + prTargetStaRec->ucNetTypeIndex = 0xff; /* Virtial NetType */ + nicUpdateBss(prAdapter, NETWORK_TYPE_AIS_INDEX); + prTargetStaRec->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; /* Virtial NetType */ + + return; +} /* end of aisFsmRoamingDisconnectPrevAP() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will update the contain of BSS_INFO_T for AIS network once +* the roaming was completed. +* +* @param IN prAdapter Pointer to the Adapter structure. +* prStaRec StaRec of roaming AP +* prAssocRspSwRfb +* +* @retval None +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisUpdateBssInfoForRoamingAP ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prAssocRspSwRfb + ) +{ + P_BSS_INFO_T prAisBssInfo; + + DBGLOG(AIS, LOUD, ("aisUpdateBssInfoForRoamingAP()")); + + ASSERT(prAdapter); + + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + //4 <1.1> Change FW's Media State immediately. + aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); + + //4 <1.2> Deactivate previous AP's STA_RECORD_T in Driver if have. + if ((prAisBssInfo->prStaRecOfAP) && + (prAisBssInfo->prStaRecOfAP != prStaRec) && + (prAisBssInfo->prStaRecOfAP->fgIsInUse)) { + cnmStaRecChangeState(prAdapter, prAisBssInfo->prStaRecOfAP, STA_STATE_1); + } + + //4 <1.3> Update BSS_INFO_T + aisUpdateBssInfoForJOIN(prAdapter, prStaRec, prAssocRspSwRfb); + + //4 <1.4> Activate current AP's STA_RECORD_T in Driver. + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + + //4 <1.6> Indicate Connected Event to Host immediately. + /* Require BSSID, Association ID, Beacon Interval.. from AIS_BSS_INFO_T */ + aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_CONNECTED, FALSE); + + return; +} /* end of aisFsmRoamingUpdateBss() */ + +#endif /* CFG_SUPPORT_ROAMING */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Check if there is any pending request and remove it (optional) +* +* @param prAdapter +* eReqType +* bRemove +* +* @return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +aisFsmIsRequestPending ( + IN P_ADAPTER_T prAdapter, + IN ENUM_AIS_REQUEST_TYPE_T eReqType, + IN BOOLEAN bRemove + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_AIS_REQ_HDR_T prPendingReqHdr, prPendingReqHdrNext; + + ASSERT(prAdapter); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + /* traverse through pending request list */ + LINK_FOR_EACH_ENTRY_SAFE(prPendingReqHdr, + prPendingReqHdrNext, + &(prAisFsmInfo->rPendingReqList), + rLinkEntry, + AIS_REQ_HDR_T) { + /* check for specified type */ + if(prPendingReqHdr->eReqType == eReqType) { + /* check if need to remove */ + if(bRemove == TRUE) { + LINK_REMOVE_KNOWN_ENTRY(&(prAisFsmInfo->rPendingReqList), &(prPendingReqHdr->rLinkEntry)); + + cnmMemFree(prAdapter, prPendingReqHdr); + } + + return TRUE; + } + } + + return FALSE; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Get next pending request +* +* @param prAdapter +* +* @return P_AIS_REQ_HDR_T +*/ +/*----------------------------------------------------------------------------*/ +P_AIS_REQ_HDR_T +aisFsmGetNextRequest ( + IN P_ADAPTER_T prAdapter + ) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_AIS_REQ_HDR_T prPendingReqHdr; + + ASSERT(prAdapter); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + LINK_REMOVE_HEAD(&(prAisFsmInfo->rPendingReqList), prPendingReqHdr, P_AIS_REQ_HDR_T); + + return prPendingReqHdr; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Insert a new request +* +* @param prAdapter +* eReqType +* +* @return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +aisFsmInsertRequest ( + IN P_ADAPTER_T prAdapter, + IN ENUM_AIS_REQUEST_TYPE_T eReqType + ) +{ + P_AIS_REQ_HDR_T prAisReq; + P_AIS_FSM_INFO_T prAisFsmInfo; + + ASSERT(prAdapter); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + prAisReq = (P_AIS_REQ_HDR_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(AIS_REQ_HDR_T)); + + if(!prAisReq) { + ASSERT(0); // Can't generate new message + return FALSE; + } + + prAisReq->eReqType = eReqType; + + /* attach request into pending request list */ + LINK_INSERT_TAIL(&prAisFsmInfo->rPendingReqList, &prAisReq->rLinkEntry); + + return TRUE; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Flush all pending requests +* +* @param prAdapter +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisFsmFlushRequest ( + IN P_ADAPTER_T prAdapter + ) +{ + P_AIS_REQ_HDR_T prAisReq; + + ASSERT(prAdapter); + + while((prAisReq = aisFsmGetNextRequest(prAdapter)) != NULL) { + cnmMemFree(prAdapter, prAisReq); + } + + return; +} + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/assoc.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/assoc.c new file mode 100755 index 000000000000..35c39f1a2ecb --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/assoc.c @@ -0,0 +1,2087 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/mgmt/assoc.c#3 $ +*/ + +/*! \file "assoc.c" + \brief This file includes the association-related functions. + + This file includes the association-related functions. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: assoc.c $ + * + * 02 22 2012 yuche.tsai + * [ALPS00240483] [Wifi P2P]Run Sigma tool of A69. Always run fail on 5.1.2. No get correct connection from Realtek. + * Fix assoc response without P2P IE issue for Sigma test. + * + * 01 17 2012 wh.su + * [WCXRP00001173] [MT6620 Wi-Fi][Driver] Adding the ICS Tethering WPA2-PSK supporting + * Adding the related code which support beacon can reflect the security setting open or WPA2-PSK, WPA-PSK not yet + * Adn support the indicate the assoc request ie at New STA CMD, needed kernel patch. + * + * 01 16 2012 yuche.tsai + * NULL + * Update Driver for wifi driect gc join IE update issue. + * + * 11 10 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * change the debug module level. + * + * 10 25 2011 cm.chang + * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode + * . + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 07 15 2011 terry.wu + * [WCXRP00000855] [MT6620 Wi-Fi] [Driver] Workaround for Kingnet 710 AP wrong AID assignment + * Update workaround for Kingnet AP. + * + * 07 15 2011 terry.wu + * [WCXRP00000855] [MT6620 Wi-Fi] [Driver] Workaround for Kingnet 710 AP wrong AID assignment + * Workaround for Kingnet 710 AP wrong AID assignment. + * + * 05 02 2011 eddie.chen + * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning[WCXRP00000672] [MT6620 Wi-Fi][FW] Fix the PS event allocation + * Check STA when rx assoc. + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 03 19 2011 yuche.tsai + * [WCXRP00000581] [Volunteer Patch][MT6620][Driver] P2P IE in Assoc Req Issue + * Append P2P IE in assoc request if P2P is enabled. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 03 16 2011 wh.su + * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done + * enable the protected while at P2P start GO, and skip some security check . + * + * 03 14 2011 wh.su + * [WCXRP00000545] [MT6620 Wi-Fi] [Driver] Fixed the p2p not enable, received a assoc rsp cause the rx assoc execute a null function + * Modify file for avoid assert at BOW recieve a assoc response frame but no p2p fucntion. + * + * 03 08 2011 terry.wu + * [WCXRP00000524] [MT6620 Wi-Fi][Driver] Fix p2p assoc request containing wrong IE format + * Fix p2p assoc request containing wrong IE format. + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * add code to let the beacon and probe response for Auto GO WSC . + * + * 02 15 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Fix RX disassoc issue under Hot-spot mode. + * + * 02 09 2011 wh.su + * [WCXRP00000432] [MT6620 Wi-Fi][Driver] Add STA privacy check at hotspot mode + * adding the code for check STA privacy bit at AP mode, . + * + * 02 08 2011 eddie.chen + * [WCXRP00000426] [MT6620 Wi-Fi][FW/Driver] Add STA aging timeout and defualtHwRatein AP mode + * Add event STA agint timeout + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. + * + * 01 12 2011 yuche.tsai + * [WCXRP00000353] [Volunteer Patch][MT6620][Driver] Desired Non-HT Rate Set update when STA record is created under AP Mode. + * Update Phy Type Set. When legacy client is connected, it can use 11b rate, + * but if the P2P device is connected, 11b rate is not allowed. + * + * 01 11 2011 yuche.tsai + * [WCXRP00000353] [Volunteer Patch][MT6620][Driver] Desired Non-HT Rate Set update when STA record is created under AP Mode. + * Update Desired Non-HT Rate Set. + * + * 12 30 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, + +Add per station flow control when STA is in PS + + + * Recover the code that was coverwritted.. + * + * 12 29 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, +Add per station flow control when STA is in PS + + * 1) PS flow control event + * + * 2) WMM IE in beacon, assoc resp, probe resp + * + * 11 04 2010 wh.su + * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID + * adding the p2p random ssid support. + * + * 10 18 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * use definition macro to replace hard-coded constant + * + * 09 28 2010 wh.su + * NULL + * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. + * + * 09 27 2010 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings + * Update BCM/BoW design and settings. + * + * 09 16 2010 cm.chang + * NULL + * Change conditional compiling options for BOW + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 09 01 2010 wh.su + * NULL + * adding the wapi support for integration test. + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 16 2010 yuche.tsai + * NULL + * Add SSID IE in assoc req frame which is sent by P2P GC. + * + * 08 16 2010 kevin.huang + * NULL + * Refine AAA functions + * + * 08 03 2010 cp.wu + * NULL + * surpress compilation warning. + * + * 07 20 2010 wh.su + * + * adding the wapi code. + * + * 07 09 2010 yarco.yang + * + * [MT6620 and MT5931] SW Migration: Add ADDBA support + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * take use of RLM module for parsing/generating HT IEs for 11n capability + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * comment out RSN IE generation by CFG_RSN_MIGRATION compilation flag. + * + * 06 28 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * send MMPDU in basic rate. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add scan_fsm into building. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * specify correct value for management frames. + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration from MT6620 firmware. + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * revised. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add management dispatching function table. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * auth.c is migrated. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 05 24 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Update assocProcessRxAssocReqFrame() to avoid redundant SSID IE {0,0} for IOT. + * + * 05 14 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Fix compile warning - macro > 10 line, initial value of an array + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW + * + * 04 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * First draft code to support protection in AP mode + * + * 04 19 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * Add Beacon Timeout Support + * * * * * * * * and will send Null frame to diagnose connection + * + * 04 16 2010 wh.su + * [BORA00000680][MT6620] Support the statistic for Microsoft os query + * adding the wpa-none for ibss beacon. + * + * 03 25 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Remove compiling warning + * + * 03 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Not carry HT cap when being associated with b/g only AP + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * 01 28 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * fixed the compiling warning.u1rwduu`wvpghlqg|rm+vp + * + * 01 27 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * add and fixed some security function. + * + * 01 11 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add Deauth and Disassoc Handler + * + * 01 07 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Update Assoc ID for PS + * + * 01 04 2010 tehuang.liu + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * For working out the first connection Chariot-verified version + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Dec 12 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Use new constant definition ELEM_MAX_LEN_EXT_CAP + * + * Dec 9 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Modify assoc req IE talbe for HT cap IE + * + * Dec 7 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * update the assocComposeReAssocReqFrameHeader() and fix the u2EstimatedFrameLen in assocSendReAssocReqFrame() + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * remove some space line + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the sending disassoc frame function + * + * Dec 4 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the txassocReq IE table, adding for WPA/RSN + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix eNetType not init in send AssocReq function + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Integrate the send Assoc with TXM + * + * Dec 1 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the code to indicate the assoc request and assoc response (now disable) + * + * Nov 24 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Remove unused variables + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +APPEND_VAR_IE_ENTRY_T txAssocReqIETable[] = { + { (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, rlmReqGenerateHtCapIE },/* 45 */ +#if CFG_SUPPORT_WPS2 + { (ELEM_HDR_LEN + ELEM_MAX_LEN_WSC), NULL, rsnGenerateWSCIE }, /* 221 */ +#endif +#if CFG_SUPPORT_WAPI + { (ELEM_HDR_LEN + ELEM_MAX_LEN_WAPI), NULL, wapiGenerateWAPIIE }, /* 68 */ +#endif +#if CFG_RSN_MIGRATION + { (ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWPAIE }, /* 72 */ +#endif + { (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, rlmReqGenerateExtCapIE }, /* 127 */ + { (ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_INFO), NULL, mqmGenerateWmmInfoIE }, /* 221 */ +#if CFG_RSN_MIGRATION + { (ELEM_HDR_LEN + ELEM_MAX_LEN_RSN), NULL, rsnGenerateRSNIE }, /* 221 */ +#endif +#if CFG_ENABLE_WIFI_DIRECT + { (0), linkToP2pCalculateP2P_IELenForAssocReq, linkToP2pGenerateP2P_IEForAssocReq }, /* 221 */ +#endif +}; + +#if CFG_SUPPORT_AAA +VERIFY_IE_ENTRY_T rxAssocReqIETable[] = { + { ELEM_ID_RESERVED, NULL } /* 255 */ +}; + + +#if 1 +APPEND_VAR_IE_ENTRY_T txAssocRespIETable[] = { + + { (ELEM_HDR_LEN + ELEM_MAX_LEN_ERP), NULL, rlmRspGenerateErpIE }, /* 42 */ + { (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, rlmRspGenerateHtCapIE }, /* 45 */ + { (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP), NULL, rlmRspGenerateHtOpIE }, /* 61 */ +#if CFG_ENABLE_WIFI_DIRECT + { (ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN), NULL, linkToRlmRspGenerateObssScanIE }, /* 74 */ + { (0), linkToP2pCalculateP2P_IELenForAssocRsp, linkToP2pGenerateP2P_IEForAssocRsp }, /* 221 */ +#endif + { (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, rlmRspGenerateExtCapIE }, /* 127 */ + { (ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_PARAM), NULL, mqmGenerateWmmParamIE } /* 221 */ +}; +#else +APPEND_IE_ENTRY_T txAssocRespIETable[] = { + { (ELEM_HDR_LEN + ELEM_MAX_LEN_ERP), rlmRspGenerateErpIE }, /* 42 */ + { (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), rlmRspGenerateHtCapIE }, /* 45 */ + { (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP), rlmRspGenerateHtOpIE }, /* 61 */ +#if CFG_ENABLE_WIFI_DIRECT + { (ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN), linkToRlmRspGenerateObssScanIE }, /* 74 */ + { (ELEM_HDR_LEN + 4), linkToP2pGenerateP2P_IEForAssocRsp }, /* 221 */ +#endif + { (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), rlmRspGenerateExtCapIE }, /* 127 */ + { (ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_PARAM), mqmGenerateWmmParamIE } /* 221 */ +}; +#endif +#endif + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to compose the Capability Info Field. +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @retval Capability Info Field +*/ +/*----------------------------------------------------------------------------*/ +__KAL_INLINE__ UINT_16 +assocBuildCapabilityInfo ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ) +{ + UINT_32 u4NonHTPhyType; + UINT_16 u2CapInfo; + + + ASSERT(prStaRec); + + + /* Set up our requested capabilities. */ + u2CapInfo = CAP_INFO_ESS; + u2CapInfo |= CAP_CF_STA_NOT_POLLABLE; + + if (prStaRec->u2CapInfo & CAP_INFO_PRIVACY) { + u2CapInfo |= CAP_INFO_PRIVACY; + } + + + /* 7.3.1.4 */ + if (prStaRec->fgHasBasicPhyType) { + u4NonHTPhyType = prStaRec->ucNonHTBasicPhyType; + + if ( (rNonHTPhyAttributes[u4NonHTPhyType].fgIsShortPreambleOptionImplemented) && + ( (prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_SHORT) || /* Short Preamble Option Enable is TRUE */ + ((prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_AUTO) && + (prStaRec->u2CapInfo & CAP_INFO_SHORT_PREAMBLE)) ) ) { + + /* Case I: Implemented == TRUE and Short Preamble Option Enable == TRUE. + * Case II: Implemented == TRUE and Short Preamble == AUTO (depends on + * BSS_DESC_T's capability) + */ + u2CapInfo |= CAP_INFO_SHORT_PREAMBLE; + } + + if (rNonHTPhyAttributes[u4NonHTPhyType].fgIsShortSlotTimeOptionImplemented && + prAdapter->rWifiVar.fgIsShortSlotTimeOptionEnable) { + u2CapInfo |= CAP_INFO_SHORT_SLOT_TIME; + } + } + + DBGLOG(SAA, LOUD, ("ASSOC REQ: Compose Capability = 0x%04x for Target BSS ["MACSTR"].\n", + u2CapInfo, MAC2STR(prStaRec->aucMacAddr))); + + + return u2CapInfo; + +} /* end of assocBuildCapabilityInfo() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to compose Common Information Elements for Association +* Request Frame. +* +* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +__KAL_INLINE__ VOID +assocBuildReAssocReqFrameCommonIEs ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + P_STA_RECORD_T prStaRec; + PUINT_8 pucBuffer; + UINT_16 u2SupportedRateSet; + UINT_8 aucAllSupportedRates[RATE_NUM] = {0}; + UINT_8 ucAllSupportedRatesLen; + UINT_8 ucSupRatesLen; + UINT_8 ucExtSupRatesLen; + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + ASSERT(prMsduInfo); + ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + ASSERT(prStaRec); + + if(!prStaRec) { + return; + } + + pucBuffer = (PUINT_8)((UINT_32)prMsduInfo->prPacket + + (UINT_32)prMsduInfo->u2FrameLength); + ASSERT(pucBuffer); + + if (IS_STA_IN_AIS(prStaRec)) { + + /* Fill the SSID element. */ + SSID_IE(pucBuffer)->ucId = ELEM_ID_SSID; + + /* NOTE(Kevin): We copy the SSID from CONNECTION_SETTINGS for the case of + * Passive Scan and the target BSS didn't broadcast SSID on its Beacon Frame. + */ + + COPY_SSID(SSID_IE(pucBuffer)->aucSSID, + SSID_IE(pucBuffer)->ucLength, + prConnSettings->aucSSID, + prConnSettings->ucSSIDLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + + } +#if CFG_ENABLE_WIFI_DIRECT + else if((prAdapter->fgIsP2PRegistered) && + (IS_STA_IN_P2P(prStaRec))) { + ASSERT(prAdapter->rP2pFuncLkr.prP2pBuildReassocReqFrameCommIEs); + pucBuffer = prAdapter->rP2pFuncLkr.prP2pBuildReassocReqFrameCommIEs(prAdapter, prMsduInfo, pucBuffer); + } +#endif +#if CFG_ENABLE_BT_OVER_WIFI + else if (IS_STA_IN_BOW(prStaRec)) { + + SSID_IE(pucBuffer)->ucId = ELEM_ID_SSID; + + /* NOTE(Kevin): We copy the SSID from CONNECTION_SETTINGS for the case of + * Passive Scan and the target BSS didn't broadcast SSID on its Beacon Frame. + */ + + COPY_SSID(SSID_IE(pucBuffer)->aucSSID, + SSID_IE(pucBuffer)->ucLength, + prConnSettings->aucSSID, + prConnSettings->ucSSIDLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + } +#endif + + else { + /* TODO(Kevin): For other network */ + } + + /* NOTE(Kevin 2008/12/19): 16.3.6.3 MLME-ASSOCIATE.indication - + * SupportedRates - The set of data rates that are supported by the STA + * that is requesting association. + * Original(Portable Driver): Only send the Rates that we'll support. + * New: Send the Phy Rates if the result of following & operation == NULL. + */ + //rateGetDataRatesFromRateSet((prBssDesc->u2OperationalRateSet & + // rPhyAttributes[prBssDesc->ePhyType].u2SupportedRateSet), + + if (prStaRec->fgHasBasicPhyType) { + UINT_32 u4NonHTPhyType; + + + u4NonHTPhyType = prStaRec->ucNonHTBasicPhyType; + + u2SupportedRateSet = (prStaRec->u2OperationalRateSet & + rNonHTPhyAttributes[u4NonHTPhyType].u2SupportedRateSet); + + ASSERT(u2SupportedRateSet); + + if (!u2SupportedRateSet) { + u2SupportedRateSet = rNonHTPhyAttributes[u4NonHTPhyType].u2SupportedRateSet; + } + + /* TODO(Kevin): For P2P, we shouldn't send support rate set which contains 11b rate */ + + rateGetDataRatesFromRateSet(u2SupportedRateSet, + 0, + aucAllSupportedRates, + &ucAllSupportedRatesLen); + + ucSupRatesLen = ((ucAllSupportedRatesLen > ELEM_MAX_LEN_SUP_RATES) ? + ELEM_MAX_LEN_SUP_RATES : ucAllSupportedRatesLen); + + ucExtSupRatesLen = ucAllSupportedRatesLen - ucSupRatesLen; + + + /* Fill the Supported Rates element. */ + if (ucSupRatesLen) { + SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_SUP_RATES; + SUP_RATES_IE(pucBuffer)->ucLength = ucSupRatesLen; + kalMemCopy(SUP_RATES_IE(pucBuffer)->aucSupportedRates, + aucAllSupportedRates, + ucSupRatesLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + } + + + /* Fill the Extended Supported Rates element. */ + if (ucExtSupRatesLen) { + + EXT_SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_EXTENDED_SUP_RATES; + EXT_SUP_RATES_IE(pucBuffer)->ucLength = ucExtSupRatesLen; + + kalMemCopy(EXT_SUP_RATES_IE(pucBuffer)->aucExtSupportedRates, + &aucAllSupportedRates[ucSupRatesLen], + ucExtSupRatesLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + } + } + + return; +} /* end of assocBuildReAssocReqFrameCommonIEs() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will compose the (Re)Association Request frame header and +* its fixed fields +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] pucBuffer Pointer to the frame buffer. +* @param[in] aucMACAddress Given Our MAC Address. +* @param[in out] pu2PayloadLen Return the length of the composed fixed fields +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +__KAL_INLINE__ VOID +assocComposeReAssocReqFrameHeaderAndFF ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN PUINT_8 pucBuffer, + IN UINT_8 aucMACAddress[], + IN OUT PUINT_16 pu2PayloadLen + ) +{ + P_WLAN_ASSOC_REQ_FRAME_T prAssocFrame; + BOOLEAN fgIsReAssoc; + + UINT_16 u2FrameCtrl; + UINT_16 u2CapInfo; + UINT_16 u2ListenInterval; + + + ASSERT(prStaRec); + ASSERT(pucBuffer); + ASSERT(aucMACAddress); + ASSERT(pu2PayloadLen); + + prAssocFrame = (P_WLAN_ASSOC_REQ_FRAME_T)pucBuffer; + fgIsReAssoc = prStaRec->fgIsReAssoc; + + //4 <1> Compose the frame header of the (Re)Association Request frame. + /* Fill the Frame Control field. */ + if (fgIsReAssoc) { + u2FrameCtrl = MAC_FRAME_REASSOC_REQ; + } + else { + u2FrameCtrl = MAC_FRAME_ASSOC_REQ; + } + WLAN_SET_FIELD_16(&prAssocFrame->u2FrameCtrl, u2FrameCtrl); + + /* Fill the DA field with Target BSSID. */ + COPY_MAC_ADDR(prAssocFrame->aucDestAddr, prStaRec->aucMacAddr); + + /* Fill the SA field with our MAC Address. */ + COPY_MAC_ADDR(prAssocFrame->aucSrcAddr, aucMACAddress); + + /* Fill the BSSID field with Target BSSID. */ + COPY_MAC_ADDR(prAssocFrame->aucBSSID, prStaRec->aucMacAddr); + + /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ + prAssocFrame->u2SeqCtrl = 0; + + + //4 <2> Compose the frame body's common fixed field part of the (Re)Association Request frame. + u2CapInfo = assocBuildCapabilityInfo(prAdapter, prStaRec); + + /* Fill the Capability Information field. */ + WLAN_SET_FIELD_16(&prAssocFrame->u2CapInfo, u2CapInfo); + + + /* Calculate the listen interval for the maximum power mode. Currently, we + set it to the value 2 times DTIM period. */ + if (prStaRec->ucDTIMPeriod) { + u2ListenInterval = prStaRec->ucDTIMPeriod * DEFAULT_LISTEN_INTERVAL_BY_DTIM_PERIOD; + } + else { + DBGLOG(SAA, TRACE, ("Use default listen interval\n")); + u2ListenInterval = DEFAULT_LISTEN_INTERVAL; + } + prStaRec->u2ListenInterval = u2ListenInterval; + + /* Fill the Listen Interval field. */ + WLAN_SET_FIELD_16(&prAssocFrame->u2ListenInterval, u2ListenInterval); + + + //4 <3> Compose the Current AP Address field for ReAssociation Request frame. + /* Fill the Current AP Address field. */ + if (prStaRec->fgIsReAssoc) { + if (IS_STA_IN_AIS(prStaRec)) { + + P_AIS_BSS_INFO_T prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + P_WLAN_REASSOC_REQ_FRAME_T prReAssocFrame = + (P_WLAN_REASSOC_REQ_FRAME_T)prAssocFrame; + + COPY_MAC_ADDR(prReAssocFrame->aucCurrentAPAddr, prAisBssInfo->aucBSSID); + } + else { + ASSERT(0); /* We don't support ReAssociation for other network */ + } + + *pu2PayloadLen = (CAP_INFO_FIELD_LEN + + LISTEN_INTERVAL_FIELD_LEN + + CURR_AP_ADDR_FIELD_LEN); + } + else { + *pu2PayloadLen = (CAP_INFO_FIELD_LEN + + LISTEN_INTERVAL_FIELD_LEN); + } + + return; +} /* end of assocComposeReAssocReqFrame() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will send the (Re)Association Request frame +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @retval WLAN_STATUS_RESOURCES No available resource for frame composing. +* @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +assocSendReAssocReqFrame ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ) +{ + P_MSDU_INFO_T prMsduInfo; + P_BSS_INFO_T prBssInfo; + + UINT_16 u2PayloadLen; + UINT_16 u2EstimatedFrameLen; + UINT_16 u2EstimatedExtraIELen; + BOOLEAN fgIsReAssoc; + UINT_32 i; + + + ASSERT(prStaRec); + + //4 <1> Allocate a PKT_INFO_T for Authentication Frame + fgIsReAssoc = prStaRec->fgIsReAssoc; + + /* Init with MGMT Header Length + Length of Fixed Fields + Common IE Length */ + if (fgIsReAssoc) { + u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + \ + WLAN_MAC_MGMT_HEADER_LEN + \ + CAP_INFO_FIELD_LEN + \ + LISTEN_INTERVAL_FIELD_LEN + \ + CURR_AP_ADDR_FIELD_LEN + \ + (ELEM_HDR_LEN + ELEM_MAX_LEN_SSID) + \ + (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + \ + (ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)); + } + else { + u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + \ + WLAN_MAC_MGMT_HEADER_LEN + \ + CAP_INFO_FIELD_LEN + \ + LISTEN_INTERVAL_FIELD_LEN + \ + (ELEM_HDR_LEN + ELEM_MAX_LEN_SSID) + \ + (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + \ + (ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)); + } + + /* + Extra IE Length */ + u2EstimatedExtraIELen = 0; + +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { + if ((prAdapter->fgIsP2PRegistered) && (prAdapter->rP2pFuncLkr.prP2pCalculate_IELenForAssocReq)) { + u2EstimatedExtraIELen = prAdapter->rP2pFuncLkr.prP2pCalculate_IELenForAssocReq(prAdapter, + prStaRec->ucNetTypeIndex, + prStaRec); + } + else { + DBGLOG(P2P, TRACE, ("Function Linker Lost.\n")); + ASSERT(FALSE); + } + + } + else { + for (i = 0; i < sizeof(txAssocReqIETable)/sizeof(APPEND_VAR_IE_ENTRY_T); i++) { + if (txAssocReqIETable[i].u2EstimatedFixedIELen != 0) { + u2EstimatedExtraIELen += txAssocReqIETable[i].u2EstimatedFixedIELen; + } + else { + u2EstimatedExtraIELen += (UINT_16)txAssocReqIETable[i].pfnCalculateVariableIELen(prAdapter, + prStaRec->ucNetTypeIndex, + prStaRec); + } + } + } + +#else + for (i = 0; i < sizeof(txAssocReqIETable)/sizeof(APPEND_VAR_IE_ENTRY_T); i++) { + if (txAssocReqIETable[i].u2EstimatedFixedIELen != 0) { + u2EstimatedExtraIELen += txAssocReqIETable[i].u2EstimatedFixedIELen; + } + else { + u2EstimatedExtraIELen += (UINT_16)txAssocReqIETable[i].pfnCalculateVariableIELen(prAdapter, + prStaRec->ucNetTypeIndex, + prStaRec); + } + } +#endif + + u2EstimatedFrameLen += u2EstimatedExtraIELen; + + /* Allocate a MSDU_INFO_T */ + if ( (prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen)) == NULL) { + DBGLOG(SAA, WARN, ("No PKT_INFO_T for sending (Re)Assoc Request.\n")); + return WLAN_STATUS_RESOURCES; + } + + //4 <2> Compose (Re)Association Request frame header and fixed fields in MSDU_INfO_T. + ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + + /* Compose Header and Fixed Field */ + assocComposeReAssocReqFrameHeaderAndFF(prAdapter, + prStaRec, + (PUINT_8)((UINT_32)(prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + prBssInfo->aucOwnMacAddr, + &u2PayloadLen); + + //4 <3> Update information of MSDU_INFO_T + prMsduInfo->eSrc = TX_PACKET_MGMT; + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; + prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; + prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = saaFsmRunEventTxDone; + prMsduInfo->fgIsBasicRate = TRUE; + + //4 <4> Compose the frame body's IEs of the (Re)Association Request frame. + assocBuildReAssocReqFrameCommonIEs(prAdapter, prMsduInfo); + + + //4 <5> Compose IEs in MSDU_INFO_T +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { + if ((prAdapter->fgIsP2PRegistered) && (prAdapter->rP2pFuncLkr.prP2pGenerate_IEForAssocReq)) { + prAdapter->rP2pFuncLkr.prP2pGenerate_IEForAssocReq(prAdapter, prMsduInfo); + } + else { + + DBGLOG(P2P, TRACE, ("Function Linker Lost.\n")); + ASSERT(FALSE); + } + } + else { + /* Append IE */ + for (i = 0; i < sizeof(txAssocReqIETable)/sizeof(APPEND_VAR_IE_ENTRY_T); i++) { + if (txAssocReqIETable[i].pfnAppendIE) { + txAssocReqIETable[i].pfnAppendIE(prAdapter, prMsduInfo); + } + } + } + +#else + /* Append IE */ + for (i = 0; i < sizeof(txAssocReqIETable)/sizeof(APPEND_VAR_IE_ENTRY_T); i++) { + if (txAssocReqIETable[i].pfnAppendIE) { + txAssocReqIETable[i].pfnAppendIE(prAdapter, prMsduInfo); + } + } +#endif + + //4 <6> Update the (Re)association request information + if (IS_STA_IN_AIS(prStaRec)) { + P_WLAN_ASSOC_REQ_FRAME_T prAssocFrame; + + prAssocFrame = (P_WLAN_ASSOC_REQ_FRAME_T)((UINT_32)(prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); + +#if CFG_RSN_MIGRATION + kalUpdateReAssocReqInfo(prAdapter->prGlueInfo, + (PUINT_8)&prAssocFrame->u2CapInfo, + prMsduInfo->u2FrameLength, + fgIsReAssoc); +#endif + } + +#if CFG_ENABLE_WIFI_DIRECT + if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) { + P_WLAN_ASSOC_REQ_FRAME_T prAssocFrame; + + prAssocFrame = (P_WLAN_ASSOC_REQ_FRAME_T)((UINT_32)(prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); + + if(prAdapter->rP2pFuncLkr.prKalP2pUpdateAssocInfo) { + prAdapter->rP2pFuncLkr.prKalP2pUpdateAssocInfo( + prAdapter->prGlueInfo, + (PUINT_8)&prAssocFrame->u2CapInfo, + prMsduInfo->u2FrameLength, + fgIsReAssoc); + } else { + ASSERT(0); + } + } +#endif + + /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ + + //4 <6> Enqueue the frame to send this (Re)Association request frame. + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; +} /* end of assocSendReAssocReqFrame() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will strictly check the TX (Re)Association Request frame for +* SAA event handling. +* +* @param[in] prMsduInfo Pointer of MSDU_INFO_T +* +* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. +* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +assocCheckTxReAssocReqFrame ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ) +{ + P_WLAN_ASSOC_REQ_FRAME_T prAssocReqFrame; + P_STA_RECORD_T prStaRec; + UINT_16 u2TxFrameCtrl; + + + ASSERT(prMsduInfo); + ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); + + prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T)(prMsduInfo->prPacket); + ASSERT(prAssocReqFrame); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + ASSERT(prStaRec); + + if(!prStaRec) { + return WLAN_STATUS_INVALID_PACKET; + } + + //WLAN_GET_FIELD_16(&prAssocReqFrame->u2FrameCtrl, &u2TxFrameCtrl) + u2TxFrameCtrl = prAssocReqFrame->u2FrameCtrl; // NOTE(Kevin): Optimized for ARM + u2TxFrameCtrl &= MASK_FRAME_TYPE; + if (prStaRec->fgIsReAssoc) { + if (u2TxFrameCtrl != MAC_FRAME_REASSOC_REQ) { + return WLAN_STATUS_FAILURE; + } + } + else { + if (u2TxFrameCtrl != MAC_FRAME_ASSOC_REQ) { + return WLAN_STATUS_FAILURE; + } + } + + return WLAN_STATUS_SUCCESS; + +} /* end of assocCheckTxReAssocReqFrame() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will strictly check the TX (Re)Association Response frame for +* AAA event handling. +* +* @param[in] prMsduInfo Pointer of MSDU_INFO_T +* +* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. +* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +assocCheckTxReAssocRespFrame ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ) +{ + P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame; + P_STA_RECORD_T prStaRec; + UINT_16 u2TxFrameCtrl; + + + ASSERT(prMsduInfo); + ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); + + prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T)(prMsduInfo->prPacket); + ASSERT(prAssocRspFrame); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + ASSERT(prStaRec); + + if(!prStaRec) { + return WLAN_STATUS_INVALID_PACKET; + } + + //WLAN_GET_FIELD_16(&prAssocFrame->u2FrameCtrl, &u2TxFrameCtrl) + u2TxFrameCtrl = prAssocRspFrame->u2FrameCtrl; // NOTE(Kevin): Optimized for ARM + u2TxFrameCtrl &= MASK_FRAME_TYPE; + if (prStaRec->fgIsReAssoc) { + if (u2TxFrameCtrl != MAC_FRAME_REASSOC_RSP) { + return WLAN_STATUS_FAILURE; + } + } + else { + if (u2TxFrameCtrl != MAC_FRAME_ASSOC_RSP) { + return WLAN_STATUS_FAILURE; + } + } + + return WLAN_STATUS_SUCCESS; + +} /* end of assocCheckTxReAssocRespFrame() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will validate the incoming (Re)Association Frame and take out +* the status code. +* +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[out] pu2StatusCode Pointer to store the Status Code from Authentication. +* +* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. +* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +assocCheckRxReAssocRspFrameStatus ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT PUINT_16 pu2StatusCode + ) +{ + P_STA_RECORD_T prStaRec; + P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame; + UINT_16 u2RxFrameCtrl; + UINT_16 u2RxCapInfo; + UINT_16 u2RxStatusCode; + UINT_16 u2RxAssocId; + + + ASSERT(prSwRfb); + ASSERT(pu2StatusCode); + + if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < (CAP_INFO_FIELD_LEN + + STATUS_CODE_FIELD_LEN + + AID_FIELD_LEN)) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + + DBGLOG(SAA, LOUD, ("prSwRfb->u2PayloadLength = %d\n", prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen)); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + ASSERT(prStaRec); + + if(!prStaRec) { + return WLAN_STATUS_INVALID_PACKET; + } + + //4 <1> locate the (Re)Assocation Resp Frame. + prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) prSwRfb->pvHeader; + + //4 <2> Parse the Header of (Re)Assocation Resp Frame. + //WLAN_GET_FIELD_16(&prAssocRspFrame->u2FrameCtrl, &u2RxFrameCtrl); + u2RxFrameCtrl = prAssocRspFrame->u2FrameCtrl; // NOTE(Kevin): Optimized for ARM + u2RxFrameCtrl &= MASK_FRAME_TYPE; + if (prStaRec->fgIsReAssoc) { + if (u2RxFrameCtrl != MAC_FRAME_REASSOC_RSP) { + return WLAN_STATUS_FAILURE; + } + } + else { + if (u2RxFrameCtrl != MAC_FRAME_ASSOC_RSP) { + return WLAN_STATUS_FAILURE; + } + } + + //4 <3> Parse the Fixed Fields of (Re)Assocation Resp Frame Body. + //WLAN_GET_FIELD_16(&prAssocRspFrame->u2CapInfo, &u2RxCapInfo); + u2RxCapInfo = prAssocRspFrame->u2CapInfo; // NOTE(Kevin): Optimized for ARM + + //WLAN_GET_FIELD_16(&prAssocRspFrame->u2StatusCode, &u2RxStatusCode); + u2RxStatusCode = prAssocRspFrame->u2StatusCode; // NOTE(Kevin): Optimized for ARM + + //4 <4> Check CAP_INFO + /* NOTE(Kevin): CM suggest to add MGMT workaround for those APs didn't check + * the CAP Privacy Bit to overcome a corner case that the Privacy Bit + * of our SCAN result didn't consist with AP's Association Resp. + */ + if (u2RxStatusCode == STATUS_CODE_SUCCESSFUL) { +#if CFG_SUPPORT_WAPI + if (prAdapter->rWifiVar.rConnSettings.fgWapiMode) { + /* WAPI AP allow the customer use WZC to join mode, the privacy bit is 0 */ + /* even at WAI & WAPI_PSK mode, but the assoc respose set the privacy bit set 1 */ + DBGLOG(SEC, TRACE, ("Workaround the WAPI AP allow the customer to use WZC to join\n")); + } + else +#endif +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered && 1) { + /* Todo:: Fixed this */ + } + else +#endif + if ((prStaRec->u2CapInfo & CAP_INFO_PRIVACY) ^ (u2RxCapInfo & CAP_INFO_PRIVACY)) { + u2RxStatusCode = STATUS_CODE_CAP_NOT_SUPPORTED; + } + } + + if (u2RxStatusCode == STATUS_CODE_SUCCESSFUL) { +#if CFG_RSN_MIGRATION + /* Update the information in the structure used to query and set + OID_802_11_ASSOCIATION_INFORMATION. */ + kalUpdateReAssocRspInfo(prAdapter->prGlueInfo, + (PUINT_8)&prAssocRspFrame->u2CapInfo, + (UINT_32)(prSwRfb->u2PacketLen)); +#endif + } + + //4 <5> Update CAP_INFO and ASSOC_ID + if (u2RxStatusCode == STATUS_CODE_SUCCESSFUL) { + prStaRec->u2CapInfo = u2RxCapInfo; + + //WLAN_GET_FIELD_16(&prAssocRspFrame->u2AssocId, &u2RxAssocId); + u2RxAssocId = prAssocRspFrame->u2AssocId; // NOTE(Kevin): Optimized for ARM + + /* 20110715 Workaround for Kingnet 710 AP (Realtek 8186) + * This AP raises the bit 6&7 not bit 14&15 in AID field. + * It cause wrong AID assignment. + * For AID = 2 + * Normal case: 0xC002(1100 0000 0000 0010) => 2 + * Kingnet 710: 0x00C2(0000 0000 1100 0010) => 194 + * workaround: mask bit 6&7 for this AP + */ + if((u2RxAssocId & BIT(6)) && + (u2RxAssocId & BIT(7)) && + !(u2RxAssocId & BITS(8, 15))) { + prStaRec->u2AssocId = u2RxAssocId & ~BITS(6,7); + } else { + prStaRec->u2AssocId = u2RxAssocId & ~AID_MSB; +#if CFG_SUPPORT_802_11W + if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { + P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; + + prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + ASSERT(prBssSpecInfo); + + prBssSpecInfo->ucSaQueryTimedOut = 0; + } +#endif + } + } + +#if CFG_SUPPORT_802_11W + if (u2RxStatusCode == STATUS_CODE_AUTH_ALGORITHM_NOT_SUPPORTED){ + DBGLOG(SAA, INFO, ("AP rejected due the authentication algorithm not support\n")); + } + else if (u2RxStatusCode == STATUS_CODE_ASSOC_REJECTED_TEMPORARILY) { + PUINT_8 pucIE, pucTime; + UINT_16 u2IELength; + UINT_16 u2Offset = 0; + + u2IELength = prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen; + pucIE = (PUINT_8)((UINT_32)prSwRfb->pvHeader + prSwRfb->u2HeaderLen); + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + if (ELEM_ID_TIMEOUT_INTERVAL == IE_ID(pucIE) && IE_LEN(pucIE) == 5) { + pucTime = ((P_IE_HDR_T)pucIE)->aucInfo; + if (pucTime[0] == ACTION_SA_TIMEOUT_ASSOC_COMEBACK) { + UINT_32 tu; + WLAN_GET_FIELD_32(pucTime + 1, &tu); + DBGLOG(SAA, INFO, ("AP rejected association temporarily; comeback duration %u TU " + "(%u ms)\n", tu, TU_TO_MSEC(tu))); + if (tu > TX_ASSOCIATION_RETRY_TIMEOUT_TU) { + DBGLOG(SAA, INFO, ("Update timer based on comeback duration\n")); + //ieee80211_reschedule_timer(wpa_s, ms); + } + } + break; + } + } /* end of IE_FOR_EACH */ + } +#endif + *pu2StatusCode = u2RxStatusCode; + + return WLAN_STATUS_SUCCESS; + +} /* end of assocCheckRxReAssocRspFrameStatus() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will compose the Disassociation frame +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] pucBuffer Pointer to the frame buffer. +* @param[in] aucMACAddress Given Our MAC Address. +* @param[in] u2ReasonCode The reason code of disassociation +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +__KAL_INLINE__ VOID +assocComposeDisassocFrame ( + IN P_STA_RECORD_T prStaRec, + IN PUINT_8 pucBuffer, + IN UINT_8 aucMACAddress[], + IN UINT_16 u2ReasonCode + ) +{ + P_WLAN_DISASSOC_FRAME_T prDisAssocFrame; + UINT_16 u2FrameCtrl; + + ASSERT(pucBuffer); + ASSERT(pucBuffer); + ASSERT(aucMACAddress); + + prDisAssocFrame = (P_WLAN_DISASSOC_FRAME_T)pucBuffer; + + //4 <1> Compose the frame header of the DisAssociation frame. + /* Fill the Frame Control field. */ + u2FrameCtrl = MAC_FRAME_DISASSOC; + + WLAN_SET_FIELD_16(&prDisAssocFrame->u2FrameCtrl, u2FrameCtrl); + + /* Fill the DA field with Target BSSID. */ + COPY_MAC_ADDR(prDisAssocFrame->aucDestAddr, prStaRec->aucMacAddr); + + /* Fill the SA field with our MAC Address. */ + COPY_MAC_ADDR(prDisAssocFrame->aucSrcAddr, aucMACAddress); + + /* Fill the BSSID field with Target BSSID. */ + COPY_MAC_ADDR(prDisAssocFrame->aucBSSID, prStaRec->aucMacAddr); + + /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ + prDisAssocFrame->u2SeqCtrl = 0; + + //4 <2> Compose the frame body's fixed field part of the Disassociation frame. + /* Fill the Reason Code field. */ + WLAN_SET_FIELD_16(&prDisAssocFrame->u2ReasonCode, u2ReasonCode); + + return; +} /* end of assocComposeDisassocFrame() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will send the Disassociation frame +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] u2ReasonCode The reason code of disassociation +* +* @retval WLAN_STATUS_RESOURCES No available resource for frame composing. +* @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +assocSendDisAssocFrame ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN UINT_16 u2ReasonCode + ) +{ + PUINT_8 pucMacAddress; + P_MSDU_INFO_T prMsduInfo; + UINT_16 u2PayloadLen; + UINT_16 u2EstimatedFrameLen; + //UINT_32 u4Status = WLAN_STATUS_SUCCESS; + + + ASSERT(prStaRec); + + //4 <1> Allocate a PKT_INFO_T for Disassociation Frame + /* Init with MGMT Header Length + Length of Fixed Fields + IE Length */ + u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + \ + WLAN_MAC_MGMT_HEADER_LEN + \ + REASON_CODE_FIELD_LEN; + + /* Allocate a MSDU_INFO_T */ + if ( (prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen)) == NULL) { + DBGLOG(SAA, WARN, ("No PKT_INFO_T for sending DisAssoc.\n")); + return WLAN_STATUS_RESOURCES; + } + + //4 <2> Compose Disassociation frame header and fixed fields in MSDU_INfO_T. + ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + pucMacAddress = prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex].aucOwnMacAddr; + + /* Compose Header and Fixed Field */ + assocComposeDisassocFrame(prStaRec, + (PUINT_8)((UINT_32)(prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + pucMacAddress, + u2ReasonCode); + +#if CFG_SUPPORT_802_11W + if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) { + P_WLAN_DISASSOC_FRAME_T prDisassocFrame; + + prDisassocFrame = (P_WLAN_DEAUTH_FRAME_T)(PUINT_8)((UINT_32)(prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); + + prDisassocFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; + DBGLOG(TX, WARN, ("assocSendDisAssocFrame with protection\n")); + } +#endif + + u2PayloadLen = REASON_CODE_FIELD_LEN; + + //4 <3> Update information of MSDU_INFO_T + ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + prMsduInfo->eSrc = TX_PACKET_MGMT; + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; + prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; + prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = NULL; + prMsduInfo->fgIsBasicRate = TRUE; + + //4 <4> Enqueue the frame to send this (Re)Association request frame. + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; +} /* end of assocSendDisAssocFrame() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will parse and process the incoming Disassociation frame +* if the given BSSID is matched. +* +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[in] aucBSSID Given BSSID +* @param[out] pu2ReasonCode Pointer to store the Reason Code from Deauthentication. +* +* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. +* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +assocProcessRxDisassocFrame ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN UINT_8 aucBSSID[], + OUT PUINT_16 pu2ReasonCode + ) +{ + P_WLAN_DISASSOC_FRAME_T prDisassocFrame; + UINT_16 u2RxReasonCode; + + + ASSERT(prSwRfb); + ASSERT(aucBSSID); + ASSERT(pu2ReasonCode); + + //4 <1> locate the Disassociation Frame. + prDisassocFrame = (P_WLAN_DISASSOC_FRAME_T) prSwRfb->pvHeader; + + //4 <2> Parse the Header of Disassociation Frame. + if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < REASON_CODE_FIELD_LEN) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + + /* Check if this Disassoc Frame is coming from Target BSSID */ + if (UNEQUAL_MAC_ADDR(prDisassocFrame->aucBSSID, aucBSSID)) { + DBGLOG(SAA, LOUD, ("Ignore Disassoc Frame from other BSS ["MACSTR"]\n", + MAC2STR(prDisassocFrame->aucSrcAddr))); + return WLAN_STATUS_FAILURE; + } + + //4 <3> Parse the Fixed Fields of Deauthentication Frame Body. + WLAN_GET_FIELD_16(&prDisassocFrame->u2ReasonCode, &u2RxReasonCode); + *pu2ReasonCode = u2RxReasonCode; + + return WLAN_STATUS_SUCCESS; + +} /* end of assocProcessRxDisassocFrame() */ + + +#if CFG_SUPPORT_AAA +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will parse and process the incoming Association Req frame +* and return a Status Code. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[out] pu2StatusCode Pointer to store the Status Code for carried in Association Response. +* +* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. +* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +assocProcessRxAssocReqFrame ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT PUINT_16 pu2StatusCode + ) +{ + P_WLAN_ASSOC_REQ_FRAME_T prAssocReqFrame; + P_STA_RECORD_T prStaRec; + P_BSS_INFO_T prBssInfo; + P_IE_SSID_T prIeSsid = (P_IE_SSID_T)NULL; + P_RSN_INFO_ELEM_T prIeRsn = (P_RSN_INFO_ELEM_T)NULL; + P_IE_SUPPORTED_RATE_T prIeSupportedRate = (P_IE_SUPPORTED_RATE_T)NULL; + P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate = (P_IE_EXT_SUPPORTED_RATE_T)NULL; + PUINT_8 pucIE, pucIEStart; + UINT_16 u2IELength; + UINT_16 u2Offset = 0; + UINT_16 u2StatusCode = STATUS_CODE_SUCCESSFUL; + UINT_16 u2RxFrameCtrl; + UINT_16 u2BSSBasicRateSet; + BOOLEAN fgIsUnknownBssBasicRate; + UINT_32 i; + + + ASSERT(prAdapter); + ASSERT(prSwRfb); + ASSERT(pu2StatusCode); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + if (prStaRec == NULL) { + return WLAN_STATUS_FAILURE; + } + + //4 <1> locate the Association Req Frame. + prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T) prSwRfb->pvHeader; + + //4 <2> Parse the Header of Association Req Frame. + if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < + (CAP_INFO_FIELD_LEN + LISTEN_INTERVAL_FIELD_LEN)) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + /* Check if this Disassoc Frame is coming from Target BSSID */ + if (UNEQUAL_MAC_ADDR(prAssocReqFrame->aucBSSID, prBssInfo->aucBSSID)) { + return WLAN_STATUS_FAILURE; /* Just Ignore this MMPDU */ + } + + //WLAN_GET_FIELD_16(&prAssocReqFrame->u2FrameCtrl, &u2RxFrameCtrl); + u2RxFrameCtrl = prAssocReqFrame->u2FrameCtrl; // NOTE(Kevin): Optimized for ARM + u2RxFrameCtrl &= MASK_FRAME_TYPE; + if (MAC_FRAME_REASSOC_REQ == u2RxFrameCtrl) { + prStaRec->fgIsReAssoc = TRUE; + + u2IELength = (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - + (UINT_16)(OFFSET_OF(WLAN_REASSOC_REQ_FRAME_T, aucInfoElem[0]) - WLAN_MAC_MGMT_HEADER_LEN); + + pucIEStart = pucIE = ((P_WLAN_REASSOC_REQ_FRAME_T)(prSwRfb->pvHeader))->aucInfoElem; + } + else { + prStaRec->fgIsReAssoc = FALSE; + + u2IELength = (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - + (UINT_16)(OFFSET_OF(WLAN_ASSOC_REQ_FRAME_T, aucInfoElem[0]) - WLAN_MAC_MGMT_HEADER_LEN); + + pucIEStart = pucIE = prAssocReqFrame->aucInfoElem; + } + + + //4 <3> Parse the Fixed Fields of Assoc Req Frame Body. + prStaRec->u2CapInfo = prAssocReqFrame->u2CapInfo; + +#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_HOTSPOT_PRIVACY_CHECK + if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { + if (((prStaRec->u2CapInfo & CAP_INFO_PRIVACY) && + prAdapter->rP2pFuncLkr.prKalP2pGetCipher && + !prAdapter->rP2pFuncLkr.prKalP2pGetCipher(prAdapter->prGlueInfo))/* || + (((prStaRec->u2CapInfo & CAP_INFO_PRIVACY) == 0) && + prAdapter->rP2pFuncLkr.prKalP2pGetCipher && + prAdapter->rP2pFuncLkr.prKalP2pGetCipher(prAdapter->prGlueInfo))*/) { + u2StatusCode = STATUS_CODE_CAP_NOT_SUPPORTED; + DBGLOG(RSN, TRACE, ("STA Assoc req privacy bit check fail\n")); + return WLAN_STATUS_SUCCESS; + } + } +#endif + + prStaRec->u2ListenInterval = prAssocReqFrame->u2ListenInterval; + prStaRec->ucPhyTypeSet = 0; + + /* Might be legacy client or p2p gc. */ + prStaRec->eStaType = STA_TYPE_LEGACY_CLIENT; + + //4 <4> Parse the IE of Assoc Req Frame Body. + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_SSID: + if ((!prIeSsid) && /* NOTE(Kevin): Get SSID once */ + (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) { + prIeSsid = (P_IE_SSID_T)pucIE; + } + break; + + case ELEM_ID_SUP_RATES: + if ((!prIeSupportedRate) && (IE_LEN(pucIE) <= RATE_NUM)) { + prIeSupportedRate = SUP_RATES_IE(pucIE); + } + break; + + case ELEM_ID_EXTENDED_SUP_RATES: + if (!prIeExtSupportedRate) + prIeExtSupportedRate = EXT_SUP_RATES_IE(pucIE); + break; + case ELEM_ID_HT_CAP: + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_HT; + break; + case ELEM_ID_RSN: + #if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_HOTSPOT_PRIVACY_CHECK + if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { + prIeRsn = RSN_IE(pucIE); + rsnParserCheckForRSNCCMPPSK(prAdapter, prIeRsn, &u2StatusCode); + if (u2StatusCode != STATUS_CODE_SUCCESSFUL) { + *pu2StatusCode = u2StatusCode; + return WLAN_STATUS_SUCCESS; + } + } + #endif + break; + case ELEM_ID_VENDOR: + #if CFG_ENABLE_WIFI_DIRECT + { + + if ((prAdapter->fgIsP2PRegistered) && (prAdapter->rP2pFuncLkr.prP2pParseCheckForP2pInfoElem)) { + UINT_8 ucOuiType = 0; + + prAdapter->rP2pFuncLkr.prP2pParseCheckForP2pInfoElem(prAdapter, pucIE, &ucOuiType); + + if (ucOuiType == VENDOR_OUI_TYPE_P2P) { + DBGLOG(P2P, TRACE, ("Target Client is a P2P group client\n")); + prStaRec->eStaType = STA_TYPE_P2P_GC; + } + + } + + } + #endif + break; + default: + for (i = 0; i < (sizeof(rxAssocReqIETable) / sizeof(VERIFY_IE_ENTRY_T)); i++) { + + if ((IE_ID(pucIE)) == rxAssocReqIETable[i].ucElemID) { + rxAssocReqIETable[i].pfnVarifyIE(prAdapter, prSwRfb, (P_IE_HDR_T)pucIE, &u2StatusCode); + + if (u2StatusCode != STATUS_CODE_SUCCESSFUL) { + *pu2StatusCode = u2StatusCode; + return WLAN_STATUS_SUCCESS; + } + } + } + + break; + } + } /* end of IE_FOR_EACH */ + + // parsing for WMM related information (2010/12/21) + mqmProcessAssocReq( + prAdapter, + prSwRfb, + pucIEStart, + u2IELength); + + do { + if (prIeSsid) { + if (UNEQUAL_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, + prIeSsid->aucSSID, prIeSsid->ucLength)) { + + u2StatusCode = STATUS_CODE_UNSPECIFIED_FAILURE; + break; + } + } + else { + u2StatusCode = STATUS_CODE_UNSPECIFIED_FAILURE; + break; + } + + prStaRec->u2OperationalRateSet = 0; + prStaRec->u2BSSBasicRateSet = 0; + + if (prIeSupportedRate || prIeExtSupportedRate) { + rateGetRateSetFromIEs(prIeSupportedRate, + prIeExtSupportedRate, + &prStaRec->u2OperationalRateSet, + &u2BSSBasicRateSet, /* Ignore any Basic Bit */ + &fgIsUnknownBssBasicRate); + + if ((prBssInfo->u2BSSBasicRateSet & prStaRec->u2OperationalRateSet) != + prBssInfo->u2BSSBasicRateSet) { + + u2StatusCode = STATUS_CODE_ASSOC_DENIED_RATE_NOT_SUPPORTED; + break; + } + + /* Accpet the Sta, update BSSBasicRateSet from Bss */ + + prStaRec->u2BSSBasicRateSet = prBssInfo->u2BSSBasicRateSet; + + prStaRec->u2DesiredNonHTRateSet = (prStaRec->u2OperationalRateSet & RATE_SET_ALL_ABG); + + if (BAND_2G4 == HIF_RX_HDR_GET_RF_BAND(prSwRfb->prHifRxHdr)) { + #if 0 /* Marked by CMC 20111024 */ + /* check if support 11n */ + if (!(u2BSSBasicRateSet & RATE_SET_BIT_HT_PHY)) { + + if (prStaRec->u2OperationalRateSet & RATE_SET_OFDM) { + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_ERP; + } + + + if (!(u2BSSBasicRateSet & RATE_SET_OFDM)) { + if (prStaRec->u2OperationalRateSet & RATE_SET_HR_DSSS) { + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_HR_DSSS; + } + + } + + } + #else + if (prStaRec->u2OperationalRateSet & RATE_SET_OFDM) { + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_ERP; + } + if (prStaRec->u2OperationalRateSet & RATE_SET_HR_DSSS) { + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_HR_DSSS; + } + #endif + } + else { /* (BAND_5G == prBssDesc->eBande) */ + #if 0 /* Marked by CMC 20111024 */ + if (!(u2BSSBasicRateSet & RATE_SET_BIT_HT_PHY)) { + + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_OFDM; + } + ASSERT((prStaRec->u2OperationalRateSet & RATE_SET_HR_DSSS) == 0); + #else + if (prStaRec->u2OperationalRateSet & RATE_SET_OFDM) { + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_OFDM; + } + #endif + } + + } + else { + ASSERT(0); + u2StatusCode = STATUS_CODE_ASSOC_DENIED_RATE_NOT_SUPPORTED; + break; + } + +#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_HOTSPOT_PRIVACY_CHECK + if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { + if (prIeRsn) { + if (prAdapter->rP2pFuncLkr.prKalP2pGetCipher && + !prAdapter->rP2pFuncLkr.prKalP2pGetCipher(prAdapter->prGlueInfo)) { + u2StatusCode = STATUS_CODE_CIPHER_SUITE_REJECTED; + break; + } + } + else { + prStaRec->rSecInfo.fgAllowOnly1x = FALSE; + if (prAdapter->rP2pFuncLkr.prKalP2pGetCipher && + prAdapter->rP2pFuncLkr.prKalP2pGetCipher(prAdapter->prGlueInfo)) { + //Only Allow 1x + prStaRec->rSecInfo.fgAllowOnly1x = TRUE; + break; + } + } + } +#endif + + } while (FALSE); + +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { + #if 1 /* ICS */ + { + PUINT_8 cp = (PUINT_8)&prAssocReqFrame->u2CapInfo; + if (prStaRec->fgIsReAssoc) + cp += 10; + else + cp += 4; + if (prStaRec->pucAssocReqIe) { + kalMemFree(prStaRec->pucAssocReqIe, VIR_MEM_TYPE, prStaRec->u2AssocReqIeLen); + prStaRec->pucAssocReqIe = NULL; + } + prStaRec->u2AssocReqIeLen = u2IELength; + if (u2IELength) { + prStaRec->pucAssocReqIe = kalMemAlloc(u2IELength, VIR_MEM_TYPE); + kalMemCopy(prStaRec->pucAssocReqIe, cp, u2IELength); + } + } + #endif + if(prAdapter->rP2pFuncLkr.prKalP2pUpdateAssocInfo) { + prAdapter->rP2pFuncLkr.prKalP2pUpdateAssocInfo(prAdapter->prGlueInfo, (PUINT_8)&prAssocReqFrame->u2CapInfo, u2IELength + (prStaRec->fgIsReAssoc ? 10 : 4), prStaRec->fgIsReAssoc); + } else { + ASSERT(0); + } + } +#endif + + *pu2StatusCode = u2StatusCode; + + return WLAN_STATUS_SUCCESS; + +} /* end of assocProcessRxAssocReqFrame() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to compose Common Information Elements for Association +* Response Frame. +* +* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. +* @param[in] prBssInfo Pointer to the BSS_INFO_T. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +__KAL_INLINE__ VOID +assocBuildReAssocRespFrameCommonIEs ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN P_BSS_INFO_T prBssInfo + ) +{ + PUINT_8 pucBuffer; + P_STA_RECORD_T prStaRec; + UINT_8 ucSupRatesLen; + UINT_8 ucExtSupRatesLen; + + + ASSERT(prMsduInfo); + ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + ASSERT(prStaRec); + + + pucBuffer = (PUINT_8)((UINT_32)prMsduInfo->prPacket + + (UINT_32)prMsduInfo->u2FrameLength); + ASSERT(pucBuffer); + + if (prBssInfo->ucAllSupportedRatesLen > ELEM_MAX_LEN_SUP_RATES) { + + ucSupRatesLen = ELEM_MAX_LEN_SUP_RATES; + ucExtSupRatesLen = prBssInfo->ucAllSupportedRatesLen - ELEM_MAX_LEN_SUP_RATES; + } + else { + ucSupRatesLen = prBssInfo->ucAllSupportedRatesLen; + ucExtSupRatesLen = 0; + } + + /* Fill the Supported Rates element. */ + if (ucSupRatesLen) { + SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_SUP_RATES; + SUP_RATES_IE(pucBuffer)->ucLength = ucSupRatesLen; + kalMemCopy(SUP_RATES_IE(pucBuffer)->aucSupportedRates, + prBssInfo->aucAllSupportedRates, + ucSupRatesLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + } + + + /* Fill the Extended Supported Rates element. */ + if (ucExtSupRatesLen) { + + EXT_SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_EXTENDED_SUP_RATES; + EXT_SUP_RATES_IE(pucBuffer)->ucLength = ucExtSupRatesLen; + + kalMemCopy(EXT_SUP_RATES_IE(pucBuffer)->aucExtSupportedRates, + &prBssInfo->aucAllSupportedRates[ucSupRatesLen], + ucExtSupRatesLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + } + + return; +} /* end of assocBuildReAssocRespFrameCommonIEs() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will compose the (Re)Association Response frame +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] pucBuffer Pointer to the frame buffer. +* @param[in] aucBssid Given BSSID. +* @param[in] u2CapInfo Capability Field of current BSS. +* @param[in out] pu2PayloadLen Return the length of the composed fixed fields +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +__KAL_INLINE__ VOID +assocComposeReAssocRespFrameHeaderAndFF ( + IN P_STA_RECORD_T prStaRec, + IN PUINT_8 pucBuffer, + IN UINT_8 aucBSSID[], + IN UINT_16 u2CapInfo, + IN OUT PUINT_16 pu2PayloadLen + ) +{ + P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame; + BOOLEAN fgIsReAssoc; + + UINT_16 u2FrameCtrl; + + + ASSERT(prStaRec); + ASSERT(pucBuffer); + ASSERT(aucBSSID); + ASSERT(pu2PayloadLen); + + prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T)pucBuffer; + fgIsReAssoc = prStaRec->fgIsReAssoc; + + //4 <1> Compose the frame header of the (Re)Association Request frame. + /* Fill the Frame Control field. */ + if (fgIsReAssoc) { + u2FrameCtrl = MAC_FRAME_REASSOC_RSP; + } + else { + u2FrameCtrl = MAC_FRAME_ASSOC_RSP; + } + //WLAN_SET_FIELD_16(&prAssocFrame->u2FrameCtrl, u2FrameCtrl); + prAssocRspFrame->u2FrameCtrl = u2FrameCtrl; // NOTE(Kevin): Optimized for ARM + + /* Fill the DA field with Target MAC Address. */ + COPY_MAC_ADDR(prAssocRspFrame->aucDestAddr, prStaRec->aucMacAddr); + + /* Fill the SA field with current BSSID. */ + COPY_MAC_ADDR(prAssocRspFrame->aucSrcAddr, aucBSSID); + + /* Fill the BSSID field with current BSSID. */ + COPY_MAC_ADDR(prAssocRspFrame->aucBSSID, aucBSSID); + + /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ + prAssocRspFrame->u2SeqCtrl = 0; + + + //4 <2> Compose the frame body's common fixed field part of the (Re)Association Request frame. + /* Fill the Capability Information field. */ + //WLAN_SET_FIELD_16(&prAssocFrame->u2CapInfo, u2CapInfo); + prAssocRspFrame->u2CapInfo = u2CapInfo; // NOTE(Kevin): Optimized for ARM + + //WLAN_SET_FIELD_16(&prAssocFrame->u2StatusCode, prStaRec->u2StatusCode); + prAssocRspFrame->u2StatusCode = prStaRec->u2StatusCode; // NOTE(Kevin): Optimized for ARM + + //WLAN_SET_FIELD_16(&prAssocFrame->u2AssocId, ((prStaRec->u2AssocId & AID_MASK) | AID_MSB)); + prAssocRspFrame->u2AssocId = + ((prStaRec->u2AssocId & AID_MASK) | AID_MSB); // NOTE(Kevin): Optimized for ARM + + *pu2PayloadLen = (CAP_INFO_FIELD_LEN + + STATUS_CODE_FIELD_LEN + + AID_FIELD_LEN); + + return; +} /* end of assocComposeReAssocRespFrameHeaderAndFF() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will send the (Re)Association Resp frame +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @retval WLAN_STATUS_RESOURCES No available resource for frame composing. +* @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +assocSendReAssocRespFrame ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ) +{ + P_BSS_INFO_T prBssInfo; + P_MSDU_INFO_T prMsduInfo; + + UINT_16 u2PayloadLen; + UINT_16 u2EstimatedFrameLen; + UINT_16 u2EstimatedExtraIELen; + BOOLEAN fgIsReAssoc; + UINT_32 i; + + + ASSERT(prStaRec); + + + //4 <1> Allocate a PKT_INFO_T for Authentication Frame + fgIsReAssoc = prStaRec->fgIsReAssoc; + + /* Init with MGMT Header Length + Length of Fixed Fields + Common IE Length */ + u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + \ + WLAN_MAC_MGMT_HEADER_LEN + \ + CAP_INFO_FIELD_LEN + \ + STATUS_CODE_FIELD_LEN + \ + AID_FIELD_LEN + \ + (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + \ + (ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)); + + /* + Extra IE Length */ + u2EstimatedExtraIELen = 0; + + for (i = 0; i < sizeof(txAssocRespIETable)/sizeof(APPEND_VAR_IE_ENTRY_T); i++) { + if (txAssocRespIETable[i].u2EstimatedFixedIELen != 0) { + u2EstimatedExtraIELen += txAssocRespIETable[i].u2EstimatedFixedIELen; + } + else if (txAssocRespIETable[i].pfnCalculateVariableIELen != NULL) { + u2EstimatedExtraIELen += (UINT_16)txAssocRespIETable[i].pfnCalculateVariableIELen(prAdapter, + prStaRec->ucNetTypeIndex, + prStaRec); + } + + } + + u2EstimatedFrameLen += u2EstimatedExtraIELen; + + /* Allocate a MSDU_INFO_T */ + if ( (prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen)) == NULL) { + DBGLOG(AAA, WARN, ("No PKT_INFO_T for sending (Re)Assoc Response.\n")); + return WLAN_STATUS_RESOURCES; + } + + //4 <2> Compose (Re)Association Request frame header and fixed fields in MSDU_INfO_T. + ASSERT(prStaRec->ucNetTypeIndex != NETWORK_TYPE_AIS_INDEX); + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + /* Compose Header and Fixed Field */ + assocComposeReAssocRespFrameHeaderAndFF(prStaRec, + (PUINT_8)((UINT_32)(prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + prBssInfo->aucBSSID, + prBssInfo->u2CapInfo, + &u2PayloadLen); + + //4 <3> Update information of MSDU_INFO_T + ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + prMsduInfo->eSrc = TX_PACKET_MGMT; + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; + prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; + prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = aaaFsmRunEventTxDone; + prMsduInfo->fgIsBasicRate = TRUE; + + //4 <4> Compose the frame body's IEs of the (Re)Association Request frame. + assocBuildReAssocRespFrameCommonIEs(prAdapter, prMsduInfo, prBssInfo); + + + //4 <5> Compose IEs in MSDU_INFO_T + + /* Append IE */ + for (i = 0; i < sizeof(txAssocRespIETable)/sizeof(APPEND_VAR_IE_ENTRY_T); i++) { + if (txAssocRespIETable[i].pfnAppendIE) { + txAssocRespIETable[i].pfnAppendIE(prAdapter, prMsduInfo); + } + } + + /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ + + //4 <6> Enqueue the frame to send this (Re)Association request frame. + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; + +} /* end of assocSendReAssocRespFrame() */ +#endif /* CFG_SUPPORT_AAA */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/auth.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/auth.c new file mode 100755 index 000000000000..e9388592ba45 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/auth.c @@ -0,0 +1,1398 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/mgmt/auth.c#1 $ +*/ + +/*! \file "auth.c" + \brief This file includes the authentication-related functions. + + This file includes the authentication-related functions. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: auth.c $ + * + * 11 09 2011 yuche.tsai + * NULL + * Fix Network Index & Station Record Index when TX deauth issue. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 06 22 2011 yuche.tsai + * NULL + * Fix coding error. + * + * 06 20 2011 yuche.tsai + * [WCXRP00000796] [Volunteer Patch][MT6620][Driver] Add BC deauth frame TX feature. + * Add feature to send BC deauth frame when under AP/GO mode. + * + * 04 21 2011 terry.wu + * [WCXRP00000674] [MT6620 Wi-Fi][Driver] Refine AAA authSendAuthFrame + * Add network type parameter to authSendAuthFrame. + * + * 04 15 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add BOW short range mode. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 02 08 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. + +2. Provision Discovery Request/Response + + * 1. Fix Service Disocvery Logical issue. + * 2. Fix a NULL pointer access violation issue when sending deauthentication packet to a class error station. + * + * 01 24 2011 cp.wu + * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving + * 1. add an extra counter for tracking pending forward frames. + * 2. notify TX service thread as well when there is pending forward frame + * 3. correct build errors leaded by introduction of Wi-Fi direct separation module + * + * 01 21 2011 terry.wu + * [WCXRP00000381] [MT6620 Wi-Fi][Driver] Kernel panic when replying unaccept Auth in AP mode + * In AP mode, use STA_REC_INDEX_NOT_FOUND(0xFE) instead of StaRec index when replying an unaccept Auth frame. + * + * 10 18 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * use definition macro to replace hard-coded constant + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 16 2010 cp.wu + * NULL + * Replace CFG_SUPPORT_BOW by CFG_ENABLE_BT_OVER_WIFI. + * There is no CFG_SUPPORT_BOW in driver domain source. + * + * 08 16 2010 kevin.huang + * NULL + * Refine AAA functions + * + * 08 03 2010 cp.wu + * NULL + * surpress compilation warning. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 28 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * send MMPDU in basic rate. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * specify correct value for management frames. + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add management dispatching function table. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * auth.c is migrated. + * + * 05 28 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Update authSendDeauthFrame() for correct the value of eNetTypeIndex in MSDU_INFO_T + * + * 05 24 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Check Net is active before sending Deauth frame. + * + * 05 24 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Refine authSendAuthFrame() for NULL STA_RECORD_T case and minimum deauth interval. + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW + * + * 04 19 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * Add Send Deauth for Class 3 Error and Leave Network Support + * + * 02 23 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Fix compile warning + * + * 02 05 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add debug message for abnormal authentication frame from AP + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * 01 11 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add Deauth and Disassoc Handler + * + * 01 07 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * Fix the Debug Label + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Dec 7 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Update the authComposeAuthFrameHeader() + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the send deauth frame function + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Integrate send Auth with TXM + * + * Nov 24 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Revise MGMT Handler with Retain Status + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +APPEND_IE_ENTRY_T txAuthIETable[] = { + { (ELEM_HDR_LEN + ELEM_MAX_LEN_CHALLENGE_TEXT), authAddIEChallengeText } +}; + +HANDLE_IE_ENTRY_T rxAuthIETable[] = { + { ELEM_ID_CHALLENGE_TEXT, authHandleIEChallengeText } +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will compose the Authentication frame header and fixed fields. +* +* @param[in] pucBuffer Pointer to the frame buffer. +* @param[in] aucPeerMACAddress Given Peer MAC Address. +* @param[in] aucMACAddress Given Our MAC Address. +* @param[in] u2AuthAlgNum Authentication Algorithm Number +* @param[in] u2TransactionSeqNum Transaction Sequence Number +* @param[in] u2StatusCode Status Code +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +__KAL_INLINE__ VOID +authComposeAuthFrameHeaderAndFF ( + IN PUINT_8 pucBuffer, + IN UINT_8 aucPeerMACAddress[], + IN UINT_8 aucMACAddress[], + IN UINT_16 u2AuthAlgNum, + IN UINT_16 u2TransactionSeqNum, + IN UINT_16 u2StatusCode + ) +{ + P_WLAN_AUTH_FRAME_T prAuthFrame; + UINT_16 u2FrameCtrl; + + + ASSERT(pucBuffer); + ASSERT(aucPeerMACAddress); + ASSERT(aucMACAddress); + + prAuthFrame = (P_WLAN_AUTH_FRAME_T)pucBuffer; + + //4 <1> Compose the frame header of the Authentication frame. + /* Fill the Frame Control field. */ + u2FrameCtrl = MAC_FRAME_AUTH; + + /* If this frame is the third frame in the shared key authentication + * sequence, it shall be encrypted. + */ + if ((u2AuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY) && + (u2TransactionSeqNum == AUTH_TRANSACTION_SEQ_3)) { + + u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; /* HW will also detect this bit for applying encryption */ + } + + //WLAN_SET_FIELD_16(&prAuthFrame->u2FrameCtrl, u2FrameCtrl); + prAuthFrame->u2FrameCtrl = u2FrameCtrl; // NOTE(Kevin): Optimized for ARM + + /* Fill the DA field with Target BSSID. */ + COPY_MAC_ADDR(prAuthFrame->aucDestAddr, aucPeerMACAddress); + + /* Fill the SA field with our MAC Address. */ + COPY_MAC_ADDR(prAuthFrame->aucSrcAddr, aucMACAddress); + + switch (u2TransactionSeqNum) { + case AUTH_TRANSACTION_SEQ_1: + case AUTH_TRANSACTION_SEQ_3: + + /* Fill the BSSID field with Target BSSID. */ + COPY_MAC_ADDR(prAuthFrame->aucBSSID, aucPeerMACAddress); + break; + + case AUTH_TRANSACTION_SEQ_2: + case AUTH_TRANSACTION_SEQ_4: + + /* Fill the BSSID field with Current BSSID. */ + COPY_MAC_ADDR(prAuthFrame->aucBSSID, aucMACAddress); + break; + + default: + ASSERT(0); + } + + /* Clear the SEQ/FRAG_NO field. */ + prAuthFrame->u2SeqCtrl = 0; + + + //4 <2> Compose the frame body's fixed field part of the Authentication frame. + /* Fill the Authentication Algorithm Number field. */ + //WLAN_SET_FIELD_16(&prAuthFrame->u2AuthAlgNum, u2AuthAlgNum); + prAuthFrame->u2AuthAlgNum = u2AuthAlgNum; // NOTE(Kevin): Optimized for ARM + + /* Fill the Authentication Transaction Sequence Number field. */ + //WLAN_SET_FIELD_16(&prAuthFrame->u2AuthTransSeqNo, u2TransactionSeqNum); + prAuthFrame->u2AuthTransSeqNo = u2TransactionSeqNum; // NOTE(Kevin): Optimized for ARM + + /* Fill the Status Code field. */ + //WLAN_SET_FIELD_16(&prAuthFrame->u2StatusCode, u2StatusCode); + prAuthFrame->u2StatusCode = u2StatusCode; // NOTE(Kevin): Optimized for ARM + + return; +} /* end of authComposeAuthFrameHeaderAndFF() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will append Challenge Text IE to the Authentication frame +* +* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +authAddIEChallengeText ( + IN P_ADAPTER_T prAdapter, + IN OUT P_MSDU_INFO_T prMsduInfo + ) +{ + P_WLAN_AUTH_FRAME_T prAuthFrame; + P_STA_RECORD_T prStaRec; + UINT_16 u2TransactionSeqNum; + + + ASSERT(prMsduInfo); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if(!prStaRec) { + return; + } + + ASSERT(prStaRec); + + /* For Management, frame header and payload are in a continuous buffer */ + prAuthFrame = (P_WLAN_AUTH_FRAME_T)prMsduInfo->prPacket; + + WLAN_GET_FIELD_16(&prAuthFrame->u2AuthTransSeqNo, &u2TransactionSeqNum) + + /* Only consider SEQ_3 for Challenge Text */ + if ((u2TransactionSeqNum == AUTH_TRANSACTION_SEQ_3) && + (prStaRec->ucAuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY) && + (prStaRec->prChallengeText != NULL)) { + + COPY_IE(((UINT_32)(prMsduInfo->prPacket) + prMsduInfo->u2FrameLength), + (prStaRec->prChallengeText)); + + prMsduInfo->u2FrameLength += IE_SIZE(prStaRec->prChallengeText); + } + + return; + +} /* end of authAddIEChallengeText() */ + + +#if !CFG_SUPPORT_AAA +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will send the Authenticiation frame +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] u2TransactionSeqNum Transaction Sequence Number +* +* @retval WLAN_STATUS_RESOURCES No available resource for frame composing. +* @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +authSendAuthFrame ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN UINT_16 u2TransactionSeqNum + ) +{ + P_MSDU_INFO_T prMsduInfo; + P_BSS_INFO_T prBssInfo; + UINT_16 u2EstimatedFrameLen; + UINT_16 u2EstimatedExtraIELen; + UINT_16 u2PayloadLen; + UINT_32 i; + + + DBGLOG(SAA, LOUD, ("Send Auth Frame\n")); + + ASSERT(prStaRec); + + //4 <1> Allocate a PKT_INFO_T for Authentication Frame + /* Init with MGMT Header Length + Length of Fixed Fields */ + u2EstimatedFrameLen = (MAC_TX_RESERVED_FIELD + + WLAN_MAC_MGMT_HEADER_LEN + + AUTH_ALGORITHM_NUM_FIELD_LEN + + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + + STATUS_CODE_FIELD_LEN); + + /* + Extra IE Length */ + u2EstimatedExtraIELen = 0; + + for (i = 0; i < sizeof(txAuthIETable)/sizeof(APPEND_IE_ENTRY_T); i++) { + u2EstimatedExtraIELen += txAuthIETable[i].u2EstimatedIELen; + } + + u2EstimatedFrameLen += u2EstimatedExtraIELen; + + /* Allocate a MSDU_INFO_T */ + if ( (prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen)) == NULL) { + DBGLOG(SAA, WARN, ("No PKT_INFO_T for sending Auth Frame.\n")); + return WLAN_STATUS_RESOURCES; + } + + //4 <2> Compose Authentication Request frame header and fixed fields in MSDU_INfO_T. + ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + /* Compose Header and some Fixed Fields */ + authComposeAuthFrameHeaderAndFF( + (PUINT_8)((UINT_32)(prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + prStaRec->aucMacAddr, + prBssInfo->aucOwnMacAddr, + prStaRec->ucAuthAlgNum, + u2TransactionSeqNum, + STATUS_CODE_RESERVED); + + u2PayloadLen = (AUTH_ALGORITHM_NUM_FIELD_LEN + + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + + STATUS_CODE_FIELD_LEN); + + //4 <3> Update information of MSDU_INFO_T + prMsduInfo->eSrc = TX_PACKET_MGMT; + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; + prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; + prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = saaFsmRunEventTxDone; + prMsduInfo->fgIsBasicRate = TRUE; + + //4 <4> Compose IEs in MSDU_INFO_T + for (i = 0; i < sizeof(txAuthIETable)/sizeof(APPEND_IE_ENTRY_T); i++) { + if (txAuthIETable[i].pfnAppendIE) { + txAuthIETable[i].pfnAppendIE(prAdapter, prMsduInfo); + } + } + + /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ + + //4 <6> Inform TXM to send this Authentication frame. + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; +} /* end of authSendAuthFrame() */ + +#else + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will send the Authenticiation frame +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] u2TransactionSeqNum Transaction Sequence Number +* +* @retval WLAN_STATUS_RESOURCES No available resource for frame composing. +* @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +authSendAuthFrame ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_SW_RFB_T prFalseAuthSwRfb, + IN UINT_16 u2TransactionSeqNum, + IN UINT_16 u2StatusCode + ) +{ + PUINT_8 pucReceiveAddr; + PUINT_8 pucTransmitAddr; + P_MSDU_INFO_T prMsduInfo; + P_BSS_INFO_T prBssInfo; + /*get from input parameter*/ + //ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex = NETWORK_TYPE_AIS_INDEX; + PFN_TX_DONE_HANDLER pfTxDoneHandler = (PFN_TX_DONE_HANDLER)NULL; + UINT_16 u2EstimatedFrameLen; + UINT_16 u2EstimatedExtraIELen; + UINT_16 u2PayloadLen; + UINT_16 ucAuthAlgNum; + UINT_32 i; + + + DBGLOG(SAA, LOUD, ("Send Auth Frame %d, Status Code = %d\n", + u2TransactionSeqNum, u2StatusCode)); + + //4 <1> Allocate a PKT_INFO_T for Authentication Frame + /* Init with MGMT Header Length + Length of Fixed Fields */ + u2EstimatedFrameLen = (MAC_TX_RESERVED_FIELD + + WLAN_MAC_MGMT_HEADER_LEN + + AUTH_ALGORITHM_NUM_FIELD_LEN + + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + + STATUS_CODE_FIELD_LEN); + + /* + Extra IE Length */ + u2EstimatedExtraIELen = 0; + + for (i = 0; i < sizeof(txAuthIETable)/sizeof(APPEND_IE_ENTRY_T); i++) { + u2EstimatedExtraIELen += txAuthIETable[i].u2EstimatedIELen; + } + + u2EstimatedFrameLen += u2EstimatedExtraIELen; + + /* Allocate a MSDU_INFO_T */ + if ( (prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen)) == NULL) { + DBGLOG(SAA, WARN, ("No PKT_INFO_T for sending Auth Frame.\n")); + return WLAN_STATUS_RESOURCES; + } + + //4 <2> Compose Authentication Request frame header and fixed fields in MSDU_INfO_T. + if (prStaRec) { + ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + pucTransmitAddr = prBssInfo->aucOwnMacAddr; + + pucReceiveAddr = prStaRec->aucMacAddr; + + ucAuthAlgNum = prStaRec->ucAuthAlgNum; + + switch (u2TransactionSeqNum) { + case AUTH_TRANSACTION_SEQ_1: + case AUTH_TRANSACTION_SEQ_3: + pfTxDoneHandler = saaFsmRunEventTxDone; + break; + + case AUTH_TRANSACTION_SEQ_2: + case AUTH_TRANSACTION_SEQ_4: + pfTxDoneHandler = aaaFsmRunEventTxDone; + break; + } + + } + else { /* For Error Status Code */ + P_WLAN_AUTH_FRAME_T prFalseAuthFrame; + + + ASSERT(prFalseAuthSwRfb); + prFalseAuthFrame = (P_WLAN_AUTH_FRAME_T)prFalseAuthSwRfb->pvHeader; + + ASSERT(u2StatusCode != STATUS_CODE_SUCCESSFUL); + + pucTransmitAddr = prFalseAuthFrame->aucDestAddr; + + pucReceiveAddr = prFalseAuthFrame->aucSrcAddr; + + ucAuthAlgNum = prFalseAuthFrame->u2AuthAlgNum; + + u2TransactionSeqNum = (prFalseAuthFrame->u2AuthTransSeqNo + 1); + } + + /* Compose Header and some Fixed Fields */ + authComposeAuthFrameHeaderAndFF((PUINT_8)((UINT_32)(prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + pucReceiveAddr, + pucTransmitAddr, + ucAuthAlgNum, + u2TransactionSeqNum, + u2StatusCode); + + u2PayloadLen = (AUTH_ALGORITHM_NUM_FIELD_LEN + + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + + STATUS_CODE_FIELD_LEN); + + //4 <3> Update information of MSDU_INFO_T + prMsduInfo->eSrc = TX_PACKET_MGMT; + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; + if(prStaRec) { + prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; + } + else { + prMsduInfo->ucStaRecIndex = STA_REC_INDEX_NOT_FOUND; //false Auth frame + } + prMsduInfo->ucNetworkType = (UINT_8)eNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = pfTxDoneHandler; + prMsduInfo->fgIsBasicRate = TRUE; + + //4 <4> Compose IEs in MSDU_INFO_T + for (i = 0; i < sizeof(txAuthIETable)/sizeof(APPEND_IE_ENTRY_T); i++) { + if (txAuthIETable[i].pfnAppendIE) { + txAuthIETable[i].pfnAppendIE(prAdapter, prMsduInfo); + } + } + + /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ + + //4 <6> Inform TXM to send this Authentication frame. + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; +} /* end of authSendAuthFrame() */ + +#endif /* CFG_SUPPORT_AAA */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will strictly check the TX Authentication frame for SAA/AAA event +* handling. +* +* @param[in] prMsduInfo Pointer of MSDU_INFO_T +* @param[in] u2TransactionSeqNum Transaction Sequence Number +* +* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. +* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +authCheckTxAuthFrame ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN UINT_16 u2TransactionSeqNum + ) +{ + P_WLAN_AUTH_FRAME_T prAuthFrame; + P_STA_RECORD_T prStaRec; + UINT_16 u2TxFrameCtrl; + UINT_16 u2TxAuthAlgNum; + UINT_16 u2TxTransactionSeqNum; + + + ASSERT(prMsduInfo); + + prAuthFrame = (P_WLAN_AUTH_FRAME_T)(prMsduInfo->prPacket); + ASSERT(prAuthFrame); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + ASSERT(prStaRec); + + if(!prStaRec) { + return WLAN_STATUS_INVALID_PACKET; + } + + //WLAN_GET_FIELD_16(&prAuthFrame->u2FrameCtrl, &u2TxFrameCtrl) + u2TxFrameCtrl = prAuthFrame->u2FrameCtrl; // NOTE(Kevin): Optimized for ARM + u2TxFrameCtrl &= MASK_FRAME_TYPE; + if (u2TxFrameCtrl != MAC_FRAME_AUTH) { + return WLAN_STATUS_FAILURE; + } + + //WLAN_GET_FIELD_16(&prAuthFrame->u2AuthAlgNum, &u2TxAuthAlgNum) + u2TxAuthAlgNum = prAuthFrame->u2AuthAlgNum; // NOTE(Kevin): Optimized for ARM + if (u2TxAuthAlgNum != (UINT_16)(prStaRec->ucAuthAlgNum)) { + return WLAN_STATUS_FAILURE; + } + + //WLAN_GET_FIELD_16(&prAuthFrame->u2AuthTransSeqNo, &u2TxTransactionSeqNum) + u2TxTransactionSeqNum = prAuthFrame->u2AuthTransSeqNo; // NOTE(Kevin): Optimized for ARM + if (u2TxTransactionSeqNum != u2TransactionSeqNum) { + return WLAN_STATUS_FAILURE; + } + + return WLAN_STATUS_SUCCESS; + +} /* end of authCheckTxAuthFrame() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will check the incoming Auth Frame's Transaction Sequence +* Number before delivering it to the corresponding SAA or AAA Module. +* +* @param[in] prSwRfb Pointer to the SW_RFB_T structure. +* +* @retval WLAN_STATUS_SUCCESS Always not retain authentication frames +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +authCheckRxAuthFrameTransSeq ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ) +{ + P_WLAN_AUTH_FRAME_T prAuthFrame; + UINT_16 u2RxTransactionSeqNum; + + + ASSERT(prSwRfb); + + //4 <1> locate the Authentication Frame. + prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; + + //4 <2> Parse the Header of Authentication Frame. + if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < (AUTH_ALGORITHM_NUM_FIELD_LEN + + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + + STATUS_CODE_FIELD_LEN)) { + ASSERT(0); + return WLAN_STATUS_SUCCESS; + } + + //4 <3> Parse the Fixed Fields of Authentication Frame Body. + //WLAN_GET_FIELD_16(&prAuthFrame->u2AuthTransSeqNo, &u2RxTransactionSeqNum); + u2RxTransactionSeqNum = prAuthFrame->u2AuthTransSeqNo; // NOTE(Kevin): Optimized for ARM + + switch (u2RxTransactionSeqNum) { + case AUTH_TRANSACTION_SEQ_2: + case AUTH_TRANSACTION_SEQ_4: + saaFsmRunEventRxAuth(prAdapter, prSwRfb); + break; + + case AUTH_TRANSACTION_SEQ_1: + case AUTH_TRANSACTION_SEQ_3: +#if CFG_SUPPORT_AAA + aaaFsmRunEventRxAuth(prAdapter, prSwRfb); +#endif /* CFG_SUPPORT_AAA */ + break; + + default: + if (prAuthFrame->u2StatusCode != STATUS_CODE_SUCCESSFUL) { + DBGLOG(SAA, WARN, ("Strange Authentication Packet: Auth Trans Seq No = %d, Error Status Code = %d\n", + u2RxTransactionSeqNum, prAuthFrame->u2StatusCode)); + } + else { + ASSERT(0); + } + /* TODO(Kevin): Free SW_RFB_T */ + break; + } + + return WLAN_STATUS_SUCCESS; + +} /* end of authCheckRxAuthFrameTransSeq() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will validate the incoming Authentication Frame and take +* the status code out. +* +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[in] u2TransactionSeqNum Transaction Sequence Number +* @param[out] pu2StatusCode Pointer to store the Status Code from Authentication. +* +* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. +* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +authCheckRxAuthFrameStatus ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN UINT_16 u2TransactionSeqNum, + OUT PUINT_16 pu2StatusCode + ) +{ + P_STA_RECORD_T prStaRec; + P_WLAN_AUTH_FRAME_T prAuthFrame; + UINT_16 u2RxAuthAlgNum; + UINT_16 u2RxTransactionSeqNum; + //UINT_16 u2RxStatusCode; // NOTE(Kevin): Optimized for ARM + + + ASSERT(prSwRfb); + ASSERT(pu2StatusCode); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + ASSERT(prStaRec); + + if(!prStaRec) { + return WLAN_STATUS_INVALID_PACKET; + } + + //4 <1> locate the Authentication Frame. + prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; + + //4 <2> Parse the Fixed Fields of Authentication Frame Body. + //WLAN_GET_FIELD_16(&prAuthFrame->u2AuthAlgNum, &u2RxAuthAlgNum); + u2RxAuthAlgNum = prAuthFrame->u2AuthAlgNum; // NOTE(Kevin): Optimized for ARM + if (u2RxAuthAlgNum != (UINT_16)prStaRec->ucAuthAlgNum) { + DBGLOG(SAA, LOUD, ("Discard Auth frame with auth type = %d, current = %d\n", + u2RxAuthAlgNum, prStaRec->ucAuthAlgNum)); + return WLAN_STATUS_FAILURE; + } + + //WLAN_GET_FIELD_16(&prAuthFrame->u2AuthTransSeqNo, &u2RxTransactionSeqNum); + u2RxTransactionSeqNum = prAuthFrame->u2AuthTransSeqNo; // NOTE(Kevin): Optimized for ARM + if (u2RxTransactionSeqNum != u2TransactionSeqNum) { + DBGLOG(SAA, LOUD, ("Discard Auth frame with Transaction Seq No = %d\n", + u2RxTransactionSeqNum)); + return WLAN_STATUS_FAILURE; + } + + //4 <3> Get the Status code + //WLAN_GET_FIELD_16(&prAuthFrame->u2StatusCode, &u2RxStatusCode); + //*pu2StatusCode = u2RxStatusCode; + *pu2StatusCode = prAuthFrame->u2StatusCode; // NOTE(Kevin): Optimized for ARM + + return WLAN_STATUS_SUCCESS; + +} /* end of authCheckRxAuthFrameStatus() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle the Challenge Text IE from the Authentication frame +* +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[in] prIEHdr Pointer to start address of IE +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +authHandleIEChallengeText ( + P_ADAPTER_T prAdapter, + P_SW_RFB_T prSwRfb, + P_IE_HDR_T prIEHdr + ) +{ + P_WLAN_AUTH_FRAME_T prAuthFrame; + P_STA_RECORD_T prStaRec; + UINT_16 u2TransactionSeqNum; + + + ASSERT(prSwRfb); + ASSERT(prIEHdr); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + ASSERT(prStaRec); + + if(!prStaRec) { + return; + } + + /* For Management, frame header and payload are in a continuous buffer */ + prAuthFrame = (P_WLAN_AUTH_FRAME_T)prSwRfb->pvHeader; + + //WLAN_GET_FIELD_16(&prAuthFrame->u2AuthTransSeqNo, &u2TransactionSeqNum) + u2TransactionSeqNum = prAuthFrame->u2AuthTransSeqNo; // NOTE(Kevin): Optimized for ARM + + /* Only consider SEQ_2 for Challenge Text */ + if ((u2TransactionSeqNum == AUTH_TRANSACTION_SEQ_2) && + (prStaRec->ucAuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY)) { + + /* Free previous allocated TCM memory */ + if (prStaRec->prChallengeText) { + ASSERT(0); + cnmMemFree(prAdapter, prStaRec->prChallengeText); + prStaRec->prChallengeText = (P_IE_CHALLENGE_TEXT_T)NULL; + } + + if ( ( prStaRec->prChallengeText = cnmMemAlloc(prAdapter, RAM_TYPE_MSG, IE_SIZE(prIEHdr)) ) == NULL) { + return; + } + + /* Save the Challenge Text from Auth Seq 2 Frame, before sending Auth Seq 3 Frame */ + COPY_IE(prStaRec->prChallengeText, prIEHdr); + } + + return; + +} /* end of authAddIEChallengeText() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will parse and process the incoming Authentication frame. +* +* @param[in] prSwRfb Pointer to SW RFB data structure. +* +* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +authProcessRxAuth2_Auth4Frame ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ) +{ + P_WLAN_AUTH_FRAME_T prAuthFrame; + PUINT_8 pucIEsBuffer; + UINT_16 u2IEsLen; + UINT_16 u2Offset; + UINT_8 ucIEID; + UINT_32 i; + + + ASSERT(prSwRfb); + + prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; + + pucIEsBuffer = &prAuthFrame->aucInfoElem[0]; + u2IEsLen = (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - + (AUTH_ALGORITHM_NUM_FIELD_LEN + + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + + STATUS_CODE_FIELD_LEN); + + IE_FOR_EACH(pucIEsBuffer, u2IEsLen, u2Offset) { + ucIEID = IE_ID(pucIEsBuffer); + + for (i = 0; i < (sizeof(rxAuthIETable) / sizeof(HANDLE_IE_ENTRY_T)); i++) { + + if (ucIEID == rxAuthIETable[i].ucElemID) { + rxAuthIETable[i].pfnHandleIE(prAdapter, prSwRfb, (P_IE_HDR_T)pucIEsBuffer); + } + } + } + + return WLAN_STATUS_SUCCESS; + +} /* end of authProcessRxAuth2_Auth4Frame() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will compose the Deauthentication frame +* +* @param[in] pucBuffer Pointer to the frame buffer. +* @param[in] aucPeerMACAddress Given Peer MAC Address. +* @param[in] aucMACAddress Given Our MAC Address. +* @param[in] u2StatusCode Status Code +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +__KAL_INLINE__ VOID +authComposeDeauthFrameHeaderAndFF ( + IN PUINT_8 pucBuffer, + IN UINT_8 aucPeerMACAddress[], + IN UINT_8 aucMACAddress[], + IN UINT_8 aucBssid[], + IN UINT_16 u2ReasonCode + ) +{ + P_WLAN_DEAUTH_FRAME_T prDeauthFrame; + UINT_16 u2FrameCtrl; + + ASSERT(pucBuffer); + ASSERT(aucPeerMACAddress); + ASSERT(aucMACAddress); + ASSERT(aucBssid); + + prDeauthFrame = (P_WLAN_DEAUTH_FRAME_T)pucBuffer; + + //4 <1> Compose the frame header of the Deauthentication frame. + /* Fill the Frame Control field. */ + u2FrameCtrl = MAC_FRAME_DEAUTH; + + //WLAN_SET_FIELD_16(&prDeauthFrame->u2FrameCtrl, u2FrameCtrl); + prDeauthFrame->u2FrameCtrl = u2FrameCtrl; // NOTE(Kevin): Optimized for ARM + + /* Fill the DA field with Target BSSID. */ + COPY_MAC_ADDR(prDeauthFrame->aucDestAddr, aucPeerMACAddress); + + /* Fill the SA field with our MAC Address. */ + COPY_MAC_ADDR(prDeauthFrame->aucSrcAddr, aucMACAddress); + + /* Fill the BSSID field with Target BSSID. */ + COPY_MAC_ADDR(prDeauthFrame->aucBSSID, aucBssid); + + /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ + prDeauthFrame->u2SeqCtrl = 0; + + //4 <2> Compose the frame body's fixed field part of the Authentication frame. + /* Fill the Status Code field. */ + //WLAN_SET_FIELD_16(&prDeauthFrame->u2ReasonCode, u2ReasonCode); + prDeauthFrame->u2ReasonCode = u2ReasonCode; // NOTE(Kevin): Optimized for ARM + + return; +} /* end of authComposeDeauthFrameHeaderAndFF() */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will send the Deauthenticiation frame +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] prClassErrSwRfb Pointer to the SW_RFB_T which is Class Error. +* @param[in] u2ReasonCode A reason code to indicate why to leave BSS. +* @param[in] pfTxDoneHandler TX Done call back function +* +* @retval WLAN_STATUS_RESOURCES No available resource for frame composing. +* @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module +* @retval WLAN_STATUS_FAILURE Didn't send Deauth frame for various reasons. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +authSendDeauthFrame ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prClassErrSwRfb, + IN UINT_16 u2ReasonCode, + IN PFN_TX_DONE_HANDLER pfTxDoneHandler + ) +{ + P_WLAN_MAC_HEADER_A4_T prWlanMacHeader = NULL; + PUINT_8 pucReceiveAddr; + PUINT_8 pucTransmitAddr; + PUINT_8 pucBssid = NULL; + + ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex = NETWORK_TYPE_AIS_INDEX; + P_MSDU_INFO_T prMsduInfo; + UINT_16 u2EstimatedFrameLen; + UINT_16 u2RxFrameCtrl; + P_BSS_INFO_T prBssInfo; + + P_DEAUTH_INFO_T prDeauthInfo; + OS_SYSTIME rCurrentTime; + INT_32 i4NewEntryIndex, i; + UINT_8 ucStaRecIdx = STA_REC_INDEX_NOT_FOUND; + +#if CFG_ENABLE_WIFI_DIRECT + UINT_8 aucBMC[] = BC_MAC_ADDR; +#endif + + /* NOTE(Kevin): The best way to reply the Deauth is according to the incoming data + * frame + */ + //4 <1> Find the Receiver Address first. + if (prClassErrSwRfb) { + BOOLEAN fgIsAbleToSendDeauth = FALSE; + + prWlanMacHeader = (P_WLAN_MAC_HEADER_A4_T) prClassErrSwRfb->pvHeader; + + //WLAN_GET_FIELD_16(&prWlanMacHeader->u2FrameCtrl, &u2RxFrameCtrl); + u2RxFrameCtrl = prWlanMacHeader->u2FrameCtrl; // NOTE(Kevin): Optimized for ARM + + /* TODO(Kevin): Currently we won't send Deauth for IBSS node. How about DLS ? */ + if ((prWlanMacHeader->u2FrameCtrl & MASK_TO_DS_FROM_DS) == 0) { + return WLAN_STATUS_FAILURE; + } + + /* Check if corresponding BSS is able to send Deauth */ + for (i = NETWORK_TYPE_AIS_INDEX; i < NETWORK_TYPE_INDEX_NUM; i++) { + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[i]); + + if (IS_NET_ACTIVE(prAdapter, i) && + (EQUAL_MAC_ADDR(prWlanMacHeader->aucAddr1, prBssInfo->aucOwnMacAddr))) { + { + fgIsAbleToSendDeauth = TRUE; + eNetTypeIndex = (ENUM_NETWORK_TYPE_INDEX_T)i; + break; + } + } + } + + if (!fgIsAbleToSendDeauth) { + return WLAN_STATUS_FAILURE; + } + + pucReceiveAddr = prWlanMacHeader->aucAddr2; + + } + else if (prStaRec) { + + pucReceiveAddr = prStaRec->aucMacAddr; + } + else { +#if CFG_ENABLE_WIFI_DIRECT + pucReceiveAddr = aucBMC; +#else + return WLAN_STATUS_FAILURE; +#endif + } + + //4 <2> Check if already send a Deauth frame in MIN_DEAUTH_INTERVAL_MSEC + GET_CURRENT_SYSTIME(&rCurrentTime); + + i4NewEntryIndex = -1; + for (i = 0; i < MAX_DEAUTH_INFO_COUNT; i++) { + prDeauthInfo = &(prAdapter->rWifiVar.arDeauthInfo[i]); + + + /* For continuously sending Deauth frame, the minimum interval is + * MIN_DEAUTH_INTERVAL_MSEC. + */ + if (CHECK_FOR_TIMEOUT(rCurrentTime, + prDeauthInfo->rLastSendTime, + MSEC_TO_SYSTIME(MIN_DEAUTH_INTERVAL_MSEC))) { + + i4NewEntryIndex = i; + } + else if (EQUAL_MAC_ADDR(pucReceiveAddr, prDeauthInfo->aucRxAddr) && + (!pfTxDoneHandler)) { + + return WLAN_STATUS_FAILURE; + } + } + + //4 <3> Update information. + if (i4NewEntryIndex > 0) { + + prDeauthInfo = &(prAdapter->rWifiVar.arDeauthInfo[i4NewEntryIndex]); + + COPY_MAC_ADDR(prDeauthInfo->aucRxAddr, pucReceiveAddr); + prDeauthInfo->rLastSendTime = rCurrentTime; + } + else { + /* NOTE(Kevin): for the case of AP mode, we may encounter this case + * if deauth all the associated clients. + */ + DBGLOG(SAA, WARN, ("No unused DEAUTH_INFO_T !\n")); + } + + //4 <4> Allocate a PKT_INFO_T for Deauthentication Frame + /* Init with MGMT Header Length + Length of Fixed Fields + IE Length */ + u2EstimatedFrameLen = (MAC_TX_RESERVED_FIELD + + WLAN_MAC_MGMT_HEADER_LEN + + REASON_CODE_FIELD_LEN); + + /* Allocate a MSDU_INFO_T */ + if ( (prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen)) == NULL) { + DBGLOG(SAA, WARN, ("No PKT_INFO_T for sending Deauth Request.\n")); + return WLAN_STATUS_RESOURCES; + } + + //4 <5> Find the Transmitter Address and BSSID. + if (prClassErrSwRfb) { + + /* The TA of Deauth is the A1 of RX frame */ + pucTransmitAddr = prWlanMacHeader->aucAddr1; + + switch (prWlanMacHeader->u2FrameCtrl & MASK_TO_DS_FROM_DS) { + + case MASK_FC_FROM_DS: + /* The BSSID of Deauth is the A2 of RX frame */ + pucBssid = prWlanMacHeader->aucAddr2; + break; + + case MASK_FC_TO_DS: + /* The BSSID of Deauth is the A1 of RX frame */ + pucBssid = prWlanMacHeader->aucAddr1; + break; + + case MASK_TO_DS_FROM_DS: + /* TODO(Kevin): Consider BOW, now we set the BSSID of Deauth + * to the A2 of RX frame for temporary solution. + */ + pucBssid = prWlanMacHeader->aucAddr2; + break; + + /* No Default */ + } + + } + else if (prStaRec) { + eNetTypeIndex = prStaRec->ucNetTypeIndex; + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); + + pucTransmitAddr = prBssInfo->aucOwnMacAddr; + + pucBssid = prBssInfo->aucBSSID; + } +#if CFG_ENABLE_WIFI_DIRECT + else { + if (prAdapter->fgIsP2PRegistered) { + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + ucStaRecIdx = STA_REC_INDEX_BMCAST; + + pucTransmitAddr = prBssInfo->aucOwnMacAddr; + + pucBssid = prBssInfo->aucBSSID; + + eNetTypeIndex = NETWORK_TYPE_P2P_INDEX; + } + else { + return WLAN_STATUS_FAILURE; + } + } + +#endif + + + //4 <6> compose Deauthentication frame header and some fixed fields */ + authComposeDeauthFrameHeaderAndFF( + (PUINT_8)((UINT_32)(prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + pucReceiveAddr, + pucTransmitAddr, + pucBssid, + u2ReasonCode); + +#if CFG_SUPPORT_802_11W + if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) { + P_WLAN_DEAUTH_FRAME_T prDeauthFrame; + + prDeauthFrame = (P_WLAN_DEAUTH_FRAME_T)(PUINT_8)((UINT_32)(prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); + + prDeauthFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; + DBGLOG(TX, WARN, ("authSendDeauthFrame with protection\n")); + } +#endif + + //4 <7> Update information of MSDU_INFO_T + prMsduInfo->eSrc = TX_PACKET_MGMT; + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; + prMsduInfo->ucStaRecIndex = ((prStaRec == NULL)?ucStaRecIdx:prStaRec->ucIndex); + prMsduInfo->ucNetworkType = (UINT_8)eNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + REASON_CODE_FIELD_LEN; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = pfTxDoneHandler; + prMsduInfo->fgIsBasicRate = TRUE; + + //4 <8> Inform TXM to send this Deauthentication frame. + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; +} /* end of authSendDeauthFrame() */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will parse and process the incoming Deauthentication frame +* if the given BSSID is matched. +* +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[in] aucBSSID Given BSSID +* @param[out] pu2ReasonCode Pointer to store the Reason Code from Deauthentication. +* +* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. +* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +authProcessRxDeauthFrame ( + IN P_SW_RFB_T prSwRfb, + IN UINT_8 aucBSSID[], + OUT PUINT_16 pu2ReasonCode + ) +{ + P_WLAN_DEAUTH_FRAME_T prDeauthFrame; + UINT_16 u2RxReasonCode; + + + ASSERT(prSwRfb); + ASSERT(aucBSSID); + ASSERT(pu2ReasonCode); + + //4 <1> locate the Deauthentication Frame. + prDeauthFrame = (P_WLAN_DEAUTH_FRAME_T) prSwRfb->pvHeader; + + //4 <2> Parse the Header of Deauthentication Frame. +#if 0 // Kevin: Seems redundant + WLAN_GET_FIELD_16(&prDeauthFrame->u2FrameCtrl, &u2RxFrameCtrl) + u2RxFrameCtrl &= MASK_FRAME_TYPE; + if (u2RxFrameCtrl != MAC_FRAME_DEAUTH) { + return WLAN_STATUS_FAILURE; + } +#endif + + if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < REASON_CODE_FIELD_LEN) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + + /* Check if this Deauth Frame is coming from Target BSSID */ + if (UNEQUAL_MAC_ADDR(prDeauthFrame->aucBSSID, aucBSSID)) { + DBGLOG(SAA, LOUD, ("Ignore Deauth Frame from other BSS ["MACSTR"]\n", + MAC2STR(prDeauthFrame->aucSrcAddr))); + return WLAN_STATUS_FAILURE; + } + + //4 <3> Parse the Fixed Fields of Deauthentication Frame Body. + WLAN_GET_FIELD_16(&prDeauthFrame->u2ReasonCode, &u2RxReasonCode); + *pu2ReasonCode = u2RxReasonCode; + + return WLAN_STATUS_SUCCESS; + +} /* end of authProcessRxDeauthFrame() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will parse and process the incoming Authentication frame. +* +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[in] aucExpectedBSSID Given Expected BSSID. +* @param[in] u2ExpectedAuthAlgNum Given Expected Authentication Algorithm Number +* @param[in] u2ExpectedTransSeqNum Given Expected Transaction Sequence Number. +* @param[out] pu2ReturnStatusCode Return Status Code. +* +* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. +* @retval WLAN_STATUS_FAILURE The frame we will ignore. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +authProcessRxAuth1Frame ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN UINT_8 aucExpectedBSSID[], + IN UINT_16 u2ExpectedAuthAlgNum, + IN UINT_16 u2ExpectedTransSeqNum, + OUT PUINT_16 pu2ReturnStatusCode + ) +{ + P_WLAN_AUTH_FRAME_T prAuthFrame; + UINT_16 u2ReturnStatusCode = STATUS_CODE_SUCCESSFUL; + + + ASSERT(prSwRfb); + ASSERT(aucExpectedBSSID); + ASSERT(pu2ReturnStatusCode); + + //4 <1> locate the Authentication Frame. + prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; + + //4 <2> Check the BSSID + if (UNEQUAL_MAC_ADDR(prAuthFrame->aucBSSID, aucExpectedBSSID)) { + return WLAN_STATUS_FAILURE; /* Just Ignore this MMPDU */ + } + + //4 <3> Parse the Fixed Fields of Authentication Frame Body. + if (prAuthFrame->u2AuthAlgNum != u2ExpectedAuthAlgNum) { + u2ReturnStatusCode = STATUS_CODE_AUTH_ALGORITHM_NOT_SUPPORTED; + } + + if (prAuthFrame->u2AuthTransSeqNo != u2ExpectedTransSeqNum) { + u2ReturnStatusCode = STATUS_CODE_AUTH_OUT_OF_SEQ; + } + + *pu2ReturnStatusCode = u2ReturnStatusCode; + + return WLAN_STATUS_SUCCESS; + +} /* end of authProcessRxAuth1Frame() */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/bss.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/bss.c new file mode 100755 index 000000000000..aa5c89bcbd53 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/bss.c @@ -0,0 +1,3103 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/mgmt/bss.c#7 $ +*/ + +/*! \file "bss.c" + \brief This file contains the functions for creating BSS(AP)/IBSS(AdHoc). + + This file contains the functions for BSS(AP)/IBSS(AdHoc). We may create a BSS/IBSS + network, or merge with exist IBSS network and sending Beacon Frame or reply + the Probe Response Frame for received Probe Request Frame. +*/ + +/******************************************************************************* +* Copyright (c) 2010 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: bss.c $ + * + * 02 23 2012 yuche.tsai + * [ALPS00240485] [Wifi P2P]Run Sigma tool of A69. Always run fail on 6.1.2 and 6.1.3. sniffer check no framename,proberesp,P2P_IE,0 + * 1. Recompose probe response frame in driver, in order to sync the IEs between supplicant & driver. + * 2. Under GO mode, indicate probe request to supplicant due to WSC IE sync issue. + * Davinci Label: 20120223_ALPS_WIFI_FW_V2_1. + * + * 02 22 2012 yuche.tsai + * [ALPS00240483] [Wifi P2P]Run Sigma tool of A69. Always run fail on 5.1.2. No get correct connection from Realtek. + * Fix assoc response without P2P IE issue for Sigma test. + * + * 02 14 2012 yuche.tsai + * [ALPS00118350] [ALPS.ICS][WiFi Direct] Dirver update for wifi direct connection + * Replace Beacon/Probe Response IE by driver generating instead of from supplicant. + * + * 01 28 2012 yuche.tsai + * NULL + * Update for Beacon composing code but not active yet. + * + * 01 20 2012 chinglan.wang + * NULL + * Fix the WPA-PSK TKIP and WPA2-PSK AES security mode bug. + * + * 01 19 2012 chinglan.wang + * NULL + * Support the WPA-PSK TKIP security mode for the tethering.. + * + * 01 15 2012 yuche.tsai + * NULL + * Fix wrong basic rate issue. + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Hot Spot Tethering for ICS ALPHA testing version. + * + * 11 03 2011 cm.chang + * [WCXRP00000997] [MT6620 Wi-Fi][Driver][FW] Handle change of BSS preamble type and slot time + * Fix preamble type of STA mode + * + * 11 03 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * change the DBGLOG for "\n" and "\r\n". LABEL to LOUD for XLOG + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 04 12 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix the sta index in processing security frame + * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 + * Add debug message. + * + * 04 07 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix for sigma. + * + * 03 29 2011 eddie.chen + * [WCXRP00000608] [MT6620 Wi-Fi][DRV] Change wmm parameters in beacon + * Change wmm parameters in beacon. + * + * 03 29 2011 yuche.tsai + * [WCXRP00000607] [Volunteer Patch][MT6620][Driver] Coding Style Fix for klocwork scan. + * Fix klocwork issue. + * + * 03 19 2011 yuche.tsai + * [WCXRP00000581] [Volunteer Patch][MT6620][Driver] P2P IE in Assoc Req Issue + * Append P2P IE in assoc request if P2P is enabled. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 11 2011 chinglan.wang + * [WCXRP00000537] [MT6620 Wi-Fi][Driver] Can not connect to 802.11b/g/n mixed AP with WEP security. + * . + * + * 03 03 2011 george.huang + * [WCXRP00000508] [MT6620 Wi-Fi][Driver] aware of beacon MSDU will be free, after BSS deactivated + * . + * + * 03 03 2011 george.huang + * [WCXRP00000508] [MT6620 Wi-Fi][Driver] aware of beacon MSDU will be free, after BSS deactivated + * modify to handle if beacon MSDU been released when BSS deactivated + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * add code to let the beacon and probe response for Auto GO WSC . + * + * 03 02 2011 wh.su + * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request + * Add code to send beacon and probe response WSC IE at Auto GO. + * + * 02 17 2011 eddie.chen + * [WCXRP00000458] [MT6620 Wi-Fi][Driver] BOW Concurrent - ProbeResp was exist in other channel + * 1) Chnage GetFrameAction decision when BSS is absent. + * 2) Check channel and resource in processing ProbeRequest + * + * 02 12 2011 yuche.tsai + * [WCXRP00000441] [Volunteer Patch][MT6620][Driver] BoW can not create desired station type when Hot Spot is enabled. + * bss should create station record type according to callers input. + * + * 02 11 2011 terry.wu + * [WCXRP00000383] [MT6620 Wi-Fi][Driver] Separate WiFi and P2P driver into two modules + * In p2p link function, check networktype before calling p2p function. + * + * 02 11 2011 terry.wu + * [WCXRP00000383] [MT6620 Wi-Fi][Driver] Separate WiFi and P2P driver into two modules + * Modify p2p link function to avoid assert. + * + * 01 26 2011 cm.chang + * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument + * . + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. + * + * 01 25 2011 eddie.chen + * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets + * Fix the compile error in windows. + * + * 01 24 2011 eddie.chen + * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets + * Add destination decision in AP mode. + * + * 01 24 2011 terry.wu + * [WCXRP00000383] [MT6620 Wi-Fi][Driver] Separate WiFi and P2P driver into two modules + * .Fix typo and missing entry + * + * 12 30 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, + +Add per station flow control when STA is in PS + + + * Fix prBssInfo->aucCWminLog to prBssInfo->aucCWminLogForBcast + * + * 12 29 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, + +Add per station flow control when STA is in PS + + + * Add WMM parameter for broadcast. + * + * 12 29 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, +Add per station flow control when STA is in PS + + * 1) PS flow control event + * + * 2) WMM IE in beacon, assoc resp, probe resp + * + * 11 29 2010 cp.wu + * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC for initial TX rate selection of auto-rate algorithm + * update ucRcpi of STA_RECORD_T for AIS when + * 1) Beacons for IBSS merge is received + * 2) Associate Response for a connecting peer is received + * + * 10 18 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * use definition macro to replace hard-coded constant + * + * 10 08 2010 wh.su + * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine + * update the frog's new p2p state machine. + * + * 09 28 2010 wh.su + * NULL + * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. + * + * 09 27 2010 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings + * Update BCM/BoW design and settings. + * + * 09 16 2010 cm.chang + * NULL + * Change conditional compiling options for BOW + * + * 09 10 2010 cm.chang + * NULL + * Always update Beacon content if FW sync OBSS info + * + * 09 07 2010 wh.su + * NULL + * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 31 2010 kevin.huang + * NULL + * Use LINK LIST operation to process SCAN result + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 29 2010 yuche.tsai + * NULL + * Finish SLT TX/RX & Rate Changing Support. + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 08 16 2010 yuche.tsai + * NULL + * Before composing Beacon IE, assign network type index for msdu info, + * this information is needed by RLM module while composing some RLM related IE field. + * + * 08 16 2010 cp.wu + * NULL + * Replace CFG_SUPPORT_BOW by CFG_ENABLE_BT_OVER_WIFI. + * There is no CFG_SUPPORT_BOW in driver domain source. + * + * 08 16 2010 kevin.huang + * NULL + * Refine AAA functions + * + * 08 12 2010 kevin.huang + * NULL + * Fix undefined pucDestAddr in bssUpdateBeaconContent() + * + * 08 12 2010 kevin.huang + * NULL + * Refine bssProcessProbeRequest() and bssSendBeaconProbeResponse() + * + * 08 11 2010 cp.wu + * NULL + * 1) do not use in-stack variable for beacon updating. (for MAUI porting) + * 2) extending scanning result to 64 instead of 48 + * + * 08 02 2010 yuche.tsai + * NULL + * P2P Group Negotiation Code Check in. + * + * 08 02 2010 george.huang + * NULL + * add WMM-PS test related OID/ CMD handlers + * + * 07 26 2010 yuche.tsai + * + * Add support to RX probe response for P2P. + * + * 07 20 2010 cp.wu + * + * 1) bugfix: do not stop timer for join after switched into normal_tr state, for providing chance for DHCP handshasking + * 2) modify rsnPerformPolicySelection() invoking + * + * 07 19 2010 wh.su + * + * update for security supporting. + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * when IBSS is being merged-in, send command packet to PM for connected indication + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * Add Ad-Hoc support to AIS-FSM + * + * 07 14 2010 yarco.yang + * + * 1. Remove CFG_MQM_MIGRATION + * 2. Add CMD_UPDATE_WMM_PARMS command + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 06 2010 george.huang + * [WPD00001556]Basic power managemenet function + * Update arguments for nicUpdateBeaconIETemplate() + * + * 06 29 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) sync to. CMD/EVENT document v0.03 + * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. + * 3) send command packet to indicate FW-PM after + * a) 1st beacon is received after AIS has connected to an AP + * b) IBSS-ALONE has been created + * c) IBSS-MERGE has occured + * + * 06 28 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * send MMPDU in basic rate. + * + * 06 25 2010 george.huang + * [WPD00001556]Basic power managemenet function + * Create beacon update path, with expose bssUpdateBeaconContent() + * + * 06 21 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Fix compile error while enable WIFI_DIRECT support. + * + * 06 21 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Support CFG_MQM_MIGRATION flag + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * enable RX management frame handling. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * specify correct value for management frames. + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * correct when ADHOC support is turned on. + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add scan.c. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add management dispatching function table. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * auth.c is migrated. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * fix compilation error when WIFI_DIRECT is turned on + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add bss.c. + * + * 06 04 2010 george.huang + * [BORA00000678][MT6620]WiFi LP integration + * [PM] Support U-APSD for STA mode + * + * 05 28 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add ClientList handling API - bssClearClientList, bssAddStaRecToClientList + * + * 05 24 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Update bssProcessProbeRequest() to avoid redundant SSID IE {0,0} for IOT. + * + * 05 21 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Refine txmInitWtblTxRateTable() - set TX initial rate according to AP's operation rate set + * + * 05 18 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Ad-hoc Beacon should not carry HT OP and OBSS IEs + * + * 05 14 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Use TX MGMT Frame API for sending PS NULL frame to avoid the TX Burst Mechanism in TX FW Frame API + * + * 05 14 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Seperate Beacon and ProbeResp IE array + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 04 28 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * Removed the use of compiling flag MQM_WMM_PARSING + * + * 04 27 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add Set Slot Time and Beacon Timeout Support for AdHoc Mode + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW + * + * 04 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * First draft code to support protection in AP mode + * + * 04 20 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * Fix restart Beacon Timeout Func after connection diagnosis + * + * 04 19 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * Add Beacon Timeout Support and will send Null frame to diagnose connection + * + * 04 16 2010 wh.su + * [BORA00000680][MT6620] Support the statistic for Microsoft os query + * adding the wpa-none for ibss beacon. + * + * 04 15 2010 wh.su + * [BORA00000680][MT6620] Support the statistic for Microsoft os query + * fixed the protected bit at cap info for ad-hoc. + * + * 03 18 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Rename the CFG flags + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 02 26 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Update outgoing beacon's TX data rate + * + * 02 23 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add DTIM count update while TX Beacon + * + * 02 05 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Modify code due to define - BAND_24G and specific BSS_INFO_T was changed + * + * 02 05 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Revise data structure to share the same BSS_INFO_T for avoiding coding error + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +#if (CFG_SUPPORT_ADHOC) || (CFG_SUPPORT_AAA) +APPEND_VAR_IE_ENTRY_T txBcnIETable[] = { + { (ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)), NULL, bssGenerateExtSuppRate_IE } /* 50 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_ERP), NULL, rlmRspGenerateErpIE } /* 42 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, rlmRspGenerateHtCapIE } /* 45 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP), NULL, rlmRspGenerateHtOpIE } /* 61 */ +#if CFG_ENABLE_WIFI_DIRECT + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN), NULL, linkToRlmRspGenerateObssScanIE } /* 74 */ +#endif + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, rlmRspGenerateExtCapIE } /* 127 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWpaNoneIE } /* 221 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_PARAM), NULL, mqmGenerateWmmParamIE } /* 221 */ +#if CFG_ENABLE_WIFI_DIRECT + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWPAIE } /* 221 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_RSN), NULL, rsnGenerateRSNIE } /* 48 */ + ,{ 0, linkToP2pCalculateP2P_IELenForBeacon, linkToP2pGenerateP2P_IEForBeacon } /* 221 */ + ,{ 0, linkToP2pCalculateWSC_IELenForBeacon, linkToP2pGenerateWSC_IEForBeacon } /* 221 */ +#endif /* CFG_ENABLE_WIFI_DIRECT */ +}; + + +APPEND_VAR_IE_ENTRY_T txProbRspIETable[] = { + { (ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)), NULL, bssGenerateExtSuppRate_IE } /* 50 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_ERP), NULL, rlmRspGenerateErpIE } /* 42 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, rlmRspGenerateHtCapIE } /* 45 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP), NULL, rlmRspGenerateHtOpIE } /* 61 */ +#if CFG_ENABLE_WIFI_DIRECT + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_RSN), NULL, rsnGenerateRSNIE } /* 48 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN), NULL, linkToRlmRspGenerateObssScanIE } /* 74 */ +#endif + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, rlmRspGenerateExtCapIE } /* 127 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWpaNoneIE } /* 221 */ + ,{ (ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_PARAM), NULL, mqmGenerateWmmParamIE } /* 221 */ +#if 0 + ,{ 0, linkToP2pCalculateWSC_IELenForProbeRsp, linkToP2pGenerateWSC_IEForProbeRsp } /* 221 */ +#endif /* CFG_ENABLE_WIFI_DIRECT */ + +}; + +#if CFG_ENABLE_WIFI_DIRECT +P_APPEND_VAR_IE_ENTRY_T prTxProbRspIETableWIP2P = NULL; +#endif + +#endif /* CFG_SUPPORT_ADHOC || CFG_SUPPORT_AAA */ + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Routines for all Operation Modes */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will create or reset a STA_RECORD_T by given BSS_DESC_T for +* Infrastructure or AdHoc Mode. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] eStaType Assign STA Type for this STA_RECORD_T +* @param[in] eNetTypeIndex Assign Net Type Index for this STA_RECORD_T +* @param[in] prBssDesc Received Beacon/ProbeResp from this STA +* +* @retval Pointer to STA_RECORD_T +*/ +/*----------------------------------------------------------------------------*/ +P_STA_RECORD_T +bssCreateStaRecFromBssDesc ( + IN P_ADAPTER_T prAdapter, + IN ENUM_STA_TYPE_T eStaType, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_BSS_DESC_T prBssDesc + ) +{ + P_STA_RECORD_T prStaRec; + UINT_8 ucNonHTPhyTypeSet; + + + ASSERT(prBssDesc); + + //4 <1> Get a valid STA_RECORD_T + prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) eNetTypeIndex, + prBssDesc->aucSrcAddr); + if (!prStaRec) { + + prStaRec = cnmStaRecAlloc(prAdapter, (UINT_8) eNetTypeIndex); + + /* TODO(Kevin): Error handling of allocation of STA_RECORD_T for + * exhausted case and do removal of unused STA_RECORD_T. + */ + + if(!prStaRec) { + ASSERT(FALSE); + return NULL; + } + + ASSERT(prStaRec); + + prStaRec->ucJoinFailureCount = 0; + /* TODO(Kevin): If this is an old entry, we may also reset the ucJoinFailureCount to 0. + */ + + COPY_MAC_ADDR(prStaRec->aucMacAddr, prBssDesc->aucSrcAddr); + } + + + //4 <2> Setup STA TYPE and NETWORK + prStaRec->eStaType = eStaType; + + prStaRec->ucNetTypeIndex = eNetTypeIndex; + + + //4 <3> Update information from BSS_DESC_T to current P_STA_RECORD_T + prStaRec->u2CapInfo = prBssDesc->u2CapInfo; + + prStaRec->u2OperationalRateSet = prBssDesc->u2OperationalRateSet; + prStaRec->u2BSSBasicRateSet = prBssDesc->u2BSSBasicRateSet; + + prStaRec->ucPhyTypeSet = prBssDesc->ucPhyTypeSet; + + if (!((prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION3_ENABLED) || + (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION3_KEY_ABSENT) || + (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION_DISABLED))) { + DBGLOG(BSS, INFO, ("Ignore the HT Bit for TKIP as pairwise cipher configed!\n")); + prStaRec->ucPhyTypeSet &= ~PHY_TYPE_BIT_HT; + } + + prStaRec->ucDesiredPhyTypeSet = prStaRec->ucPhyTypeSet & prAdapter->rWifiVar.ucAvailablePhyTypeSet; + + ucNonHTPhyTypeSet = prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_SET_802_11ABG; + + /* Check for Target BSS's non HT Phy Types */ + if (ucNonHTPhyTypeSet) { + + if (ucNonHTPhyTypeSet & PHY_TYPE_BIT_ERP) { + prStaRec->ucNonHTBasicPhyType = PHY_TYPE_ERP_INDEX; + } + else if (ucNonHTPhyTypeSet & PHY_TYPE_BIT_OFDM) { + prStaRec->ucNonHTBasicPhyType = PHY_TYPE_OFDM_INDEX; + } + else /* if (ucNonHTPhyTypeSet & PHY_TYPE_HR_DSSS_INDEX) */ { + prStaRec->ucNonHTBasicPhyType = PHY_TYPE_HR_DSSS_INDEX; + } + + prStaRec->fgHasBasicPhyType = TRUE; + } + else { + /* Use mandatory for 11N only BSS */ + ASSERT(prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N); + + { + /* TODO(Kevin): which value should we set for 11n ? ERP ? */ + prStaRec->ucNonHTBasicPhyType = PHY_TYPE_HR_DSSS_INDEX; + } + + prStaRec->fgHasBasicPhyType = FALSE; + } + + /* Update non HT Desired Rate Set */ + { + P_CONNECTION_SETTINGS_T prConnSettings; + + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + prStaRec->u2DesiredNonHTRateSet = + (prStaRec->u2OperationalRateSet & prConnSettings->u2DesiredNonHTRateSet); + } + + //4 <4> Update information from BSS_DESC_T to current P_STA_RECORD_T + if (IS_AP_STA(prStaRec)) { + /* do not need to parse IE for DTIM, + * which have been parsed before inserting into BSS_DESC_T + */ + if (prBssDesc->ucDTIMPeriod) { + prStaRec->ucDTIMPeriod = prBssDesc->ucDTIMPeriod; + } + else { + prStaRec->ucDTIMPeriod = 0; // Means that TIM was not parsed. + } + } + + + //4 <5> Update default value + prStaRec->fgDiagnoseConnection = FALSE; + + + //4 <6> Update default value for other Modules + /* Determine fgIsWmmSupported and fgIsUapsdSupported in STA_REC */ + mqmProcessScanResult(prAdapter, prBssDesc, prStaRec); + + return prStaRec; + +} /* end of bssCreateStaRecFromBssDesc() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will compose the Null Data frame. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] pucBuffer Pointer to the frame buffer. +* @param[in] prStaRec Pointer to the STA_RECORD_T. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +bssComposeNullFrame ( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucBuffer, + IN P_STA_RECORD_T prStaRec + ) +{ + P_WLAN_MAC_HEADER_T prNullFrame; + P_BSS_INFO_T prBssInfo; + UINT_16 u2FrameCtrl; + + + ASSERT(pucBuffer); + ASSERT(prStaRec); + ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + ASSERT(prBssInfo); + + prNullFrame = (P_WLAN_MAC_HEADER_T)pucBuffer; + + //4 <1> Decide the Frame Control Field + u2FrameCtrl = MAC_FRAME_NULL; + + if (IS_AP_STA(prStaRec)) { + u2FrameCtrl |= MASK_FC_TO_DS; + + if (prStaRec->fgSetPwrMgtBit) { + u2FrameCtrl |= MASK_FC_PWR_MGT; + } + } + else if (IS_CLIENT_STA(prStaRec)) { + u2FrameCtrl |= MASK_FC_FROM_DS; + } + else if (IS_DLS_STA(prStaRec)) { + /* TODO(Kevin) */ + } + else { + /* NOTE(Kevin): We won't send Null frame for IBSS */ + ASSERT(0); + return; + } + + //4 <2> Compose the Null frame + /* Fill the Frame Control field. */ + //WLAN_SET_FIELD_16(&prNullFrame->u2FrameCtrl, u2FrameCtrl); + prNullFrame->u2FrameCtrl = u2FrameCtrl; // NOTE(Kevin): Optimized for ARM + + /* Fill the Address 1 field with Target Peer Address. */ + COPY_MAC_ADDR(prNullFrame->aucAddr1, prStaRec->aucMacAddr); + + /* Fill the Address 2 field with our MAC Address. */ + COPY_MAC_ADDR(prNullFrame->aucAddr2, prBssInfo->aucOwnMacAddr); + + /* Fill the Address 3 field with Target BSSID. */ + COPY_MAC_ADDR(prNullFrame->aucAddr3, prBssInfo->aucBSSID); + + /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ + prNullFrame->u2SeqCtrl = 0; + + return; + +} /* end of bssComposeNullFrameHeader() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will compose the QoS Null Data frame. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] pucBuffer Pointer to the frame buffer. +* @param[in] prStaRec Pointer to the STA_RECORD_T. +* @param[in] ucUP User Priority. +* @param[in] fgSetEOSP Set the EOSP bit. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +bssComposeQoSNullFrame ( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucBuffer, + IN P_STA_RECORD_T prStaRec, + IN UINT_8 ucUP, + IN BOOLEAN fgSetEOSP + ) +{ + P_WLAN_MAC_HEADER_QOS_T prQoSNullFrame; + P_BSS_INFO_T prBssInfo; + UINT_16 u2FrameCtrl; + UINT_16 u2QosControl; + + + ASSERT(pucBuffer); + ASSERT(prStaRec); + ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + ASSERT(prBssInfo); + + prQoSNullFrame = (P_WLAN_MAC_HEADER_QOS_T)pucBuffer; + + //4 <1> Decide the Frame Control Field + u2FrameCtrl = MAC_FRAME_QOS_NULL; + + if (IS_AP_STA(prStaRec)) { + u2FrameCtrl |= MASK_FC_TO_DS; + + if (prStaRec->fgSetPwrMgtBit) { + u2FrameCtrl |= MASK_FC_PWR_MGT; + } + } + else if (IS_CLIENT_STA(prStaRec)) { + u2FrameCtrl |= MASK_FC_FROM_DS; + } + else if (IS_DLS_STA(prStaRec)) { + /* TODO(Kevin) */ + } + else { + /* NOTE(Kevin): We won't send QoS Null frame for IBSS */ + ASSERT(0); + return; + } + + //4 <2> Compose the QoS Null frame + /* Fill the Frame Control field. */ + //WLAN_SET_FIELD_16(&prQoSNullFrame->u2FrameCtrl, u2FrameCtrl); + prQoSNullFrame->u2FrameCtrl = u2FrameCtrl; // NOTE(Kevin): Optimized for ARM + + /* Fill the Address 1 field with Target Peer Address. */ + COPY_MAC_ADDR(prQoSNullFrame->aucAddr1, prStaRec->aucMacAddr); + + /* Fill the Address 2 field with our MAC Address. */ + COPY_MAC_ADDR(prQoSNullFrame->aucAddr2, prBssInfo->aucOwnMacAddr); + + /* Fill the Address 3 field with Target BSSID. */ + COPY_MAC_ADDR(prQoSNullFrame->aucAddr3, prBssInfo->aucBSSID); + + /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ + prQoSNullFrame->u2SeqCtrl = 0; + + u2QosControl = (UINT_16)(ucUP & WMM_QC_UP_MASK); + + if (fgSetEOSP) { + u2QosControl |= WMM_QC_EOSP; + } + + //WLAN_SET_FIELD_16(&prQoSNullFrame->u2QosCtrl, u2QosControl); + prQoSNullFrame->u2QosCtrl = u2QosControl; // NOTE(Kevin): Optimized for ARM + + return; + +} /* end of bssComposeQoSNullFrameHeader() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Send the Null Frame +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] pfTxDoneHandler TX Done call back function +* +* @retval WLAN_STATUS_RESOURCE No available resources to send frame. +* @retval WLAN_STATUS_SUCCESS Succe]ss. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +bssSendNullFrame ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN PFN_TX_DONE_HANDLER pfTxDoneHandler + ) +{ + P_MSDU_INFO_T prMsduInfo; + UINT_16 u2EstimatedFrameLen; + + + //4 <1> Allocate a PKT_INFO_T for Null Frame + /* Init with MGMT Header Length */ + u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + \ + WLAN_MAC_HEADER_LEN; + + /* Allocate a MSDU_INFO_T */ + if ( (prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen)) == NULL) { + DBGLOG(BSS, WARN, ("No PKT_INFO_T for sending Null Frame.\n")); + return WLAN_STATUS_RESOURCES; + } + + //4 <2> Compose Null frame in MSDU_INfO_T. + bssComposeNullFrame(prAdapter, + (PUINT_8)((UINT_32)prMsduInfo->prPacket + MAC_TX_RESERVED_FIELD), + prStaRec); +#if 0 + //4 <3> Update information of MSDU_INFO_T + TXM_SET_DATA_PACKET( \ + /* STA_REC ptr */ prStaRec, \ + /* MSDU_INFO ptr */ prMsduInfo, \ + /* MAC HDR ptr */ (prMsduInfo->pucBuffer + MAC_TX_RESERVED_FIELD), \ + /* MAC HDR length */ WLAN_MAC_HEADER_LEN, \ + /* PAYLOAD ptr */ (prMsduInfo->pucBuffer + MAC_TX_RESERVED_FIELD + WLAN_MAC_HEADER_LEN), \ + /* PAYLOAD length */ 0, \ + /* Network Type Index */(UINT_8)prStaRec->ucNetTypeIndex, \ + /* TID */ 0 /* BE: AC1 */, \ + /* Flag 802.11 */ TRUE,\ + /* Pkt arrival time */ 0 /* TODO: Obtain the system time */, \ + /* Resource TC */ 0 /* Irrelevant */, \ + /* Flag 802.1x */ FALSE,\ + /* TX-done callback */ pfTxDoneHandler, \ + /* PS forwarding type*/ PS_FORWARDING_TYPE_NON_PS, \ + /* PS Session ID */ 0 /* Irrelevant */, \ + /* Flag fixed rate */ TRUE, \ + /* Fixed tx rate */ g_aprBssInfo[prStaRec->ucNetTypeIndex]->ucHwDefaultFixedRateCode, \ + /* Fixed-rate retry */ BSS_DEFAULT_CONN_TEST_NULL_FRAME_RETRY_LIMIT, \ + /* PAL LLH */ 0 /* Irrelevant */,\ + /* ACL SN */ 0 /* Irrelevant */,\ + /* Flag No Ack */ FALSE \ + ); + + /* Terminate with a NULL pointer */ + NIC_HIF_TX_SET_NEXT_MSDU_INFO(prMsduInfo,NULL); + + /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ + + /* Indicate the packet to TXM */ + //4 <4> Inform TXM to send this Null frame. + txmSendFwDataPackets(prMsduInfo); +#endif + + prMsduInfo->eSrc = TX_PACKET_MGMT; + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_DATA; + prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; + prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_HEADER_LEN; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = pfTxDoneHandler; + prMsduInfo->fgIsBasicRate = FALSE; + + //4 <4> Inform TXM to send this Null frame. + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; + +} /* end of bssSendNullFrame() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Send the QoS Null Frame +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] pfTxDoneHandler TX Done call back function +* +* @retval WLAN_STATUS_RESOURCE No available resources to send frame. +* @retval WLAN_STATUS_SUCCESS Success. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +bssSendQoSNullFrame ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN UINT_8 ucUP, + IN PFN_TX_DONE_HANDLER pfTxDoneHandler + ) +{ + P_MSDU_INFO_T prMsduInfo; + UINT_16 u2EstimatedFrameLen; + + + //4 <1> Allocate a PKT_INFO_T for Null Frame + /* Init with MGMT Header Length */ + u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + \ + WLAN_MAC_HEADER_QOS_LEN; + + /* Allocate a MSDU_INFO_T */ + if ( (prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen)) == NULL) { + DBGLOG(BSS, WARN, ("No PKT_INFO_T for sending Null Frame.\n")); + return WLAN_STATUS_RESOURCES; + } + + //4 <2> Compose Null frame in MSDU_INfO_T. + bssComposeQoSNullFrame(prAdapter, + (PUINT_8)((UINT_32)(prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + prStaRec, + ucUP, + FALSE); +#if 0 + //4 <3> Update information of MSDU_INFO_T + TXM_SET_DATA_PACKET( \ + /* STA_REC ptr */ prStaRec, \ + /* MSDU_INFO ptr */ prMsduInfo, \ + /* MAC HDR ptr */ (prMsduInfo->pucBuffer + MAC_TX_RESERVED_FIELD), \ + /* MAC HDR length */ WLAN_MAC_HEADER_QOS_LEN, \ + /* PAYLOAD ptr */ (prMsduInfo->pucBuffer + MAC_TX_RESERVED_FIELD + WLAN_MAC_HEADER_QOS_LEN), \ + /* PAYLOAD length */ 0, \ + /* Network Type Index */(UINT_8)prStaRec->ucNetTypeIndex, \ + /* TID */ 0 /* BE: AC1 */, \ + /* Flag 802.11 */ TRUE,\ + /* Pkt arrival time */ 0 /* TODO: Obtain the system time */, \ + /* Resource TC */ 0 /* Irrelevant */, \ + /* Flag 802.1x */ FALSE,\ + /* TX-done callback */ pfTxDoneHandler, \ + /* PS forwarding type*/ PS_FORWARDING_TYPE_NON_PS, \ + /* PS Session ID */ 0 /* Irrelevant */, \ + /* Flag fixed rate */ TRUE, \ + /* Fixed tx rate */ g_aprBssInfo[prStaRec->ucNetTypeIndex]->ucHwDefaultFixedRateCode, \ + /* Fixed-rate retry */ TXM_DEFAULT_DATA_FRAME_RETRY_LIMIT, \ + /* PAL LLH */ 0 /* Irrelevant */,\ + /* ACL SN */ 0 /* Irrelevant */,\ + /* Flag No Ack */ FALSE \ + ); + + /* Terminate with a NULL pointer */ + NIC_HIF_TX_SET_NEXT_MSDU_INFO(prMsduInfo,NULL); + + /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ + + /* Indicate the packet to TXM */ + //4 <4> Inform TXM to send this Null frame. + txmSendFwDataPackets(prMsduInfo); +#endif + + prMsduInfo->eSrc = TX_PACKET_MGMT; + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; + prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; + prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_HEADER_QOS_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_HEADER_QOS_LEN; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = pfTxDoneHandler; + prMsduInfo->fgIsBasicRate = TRUE; + + //4 <4> Inform TXM to send this Null frame. + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; + +} /* end of bssSendQoSNullFrame() */ + + +#if (CFG_SUPPORT_ADHOC) || (CFG_SUPPORT_AAA) +/*----------------------------------------------------------------------------*/ +/* Routines for both IBSS(AdHoc) and BSS(AP) */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to generate Information Elements of Extended +* Support Rate +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +bssGenerateExtSuppRate_IE ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ) +{ + P_BSS_INFO_T prBssInfo; + PUINT_8 pucBuffer; + UINT_8 ucExtSupRatesLen; + + + ASSERT(prMsduInfo); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]); + ASSERT(prBssInfo); + + pucBuffer = (PUINT_8)((UINT_32)prMsduInfo->prPacket + + (UINT_32)prMsduInfo->u2FrameLength); + ASSERT(pucBuffer); + + if (prBssInfo->ucAllSupportedRatesLen > ELEM_MAX_LEN_SUP_RATES) { + + ucExtSupRatesLen = prBssInfo->ucAllSupportedRatesLen - ELEM_MAX_LEN_SUP_RATES; + } + else { + ucExtSupRatesLen = 0; + } + + /* Fill the Extended Supported Rates element. */ + if (ucExtSupRatesLen) { + + EXT_SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_EXTENDED_SUP_RATES; + EXT_SUP_RATES_IE(pucBuffer)->ucLength = ucExtSupRatesLen; + + kalMemCopy(EXT_SUP_RATES_IE(pucBuffer)->aucExtSupportedRates, + &prBssInfo->aucAllSupportedRates[ELEM_MAX_LEN_SUP_RATES], + ucExtSupRatesLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + } + + return; +} /* end of bssGenerateExtSuppRate_IE() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to compose Common Information Elements for Beacon +* or Probe Response Frame. +* +* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. +* @param[in] prBssInfo Pointer to the BSS_INFO_T. +* @param[in] pucDestAddr Pointer to the Destination Address, if NULL, means Beacon. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +bssBuildBeaconProbeRespFrameCommonIEs ( + IN P_MSDU_INFO_T prMsduInfo, + IN P_BSS_INFO_T prBssInfo, + IN PUINT_8 pucDestAddr + ) +{ + PUINT_8 pucBuffer; + UINT_8 ucSupRatesLen; + + + ASSERT(prMsduInfo); + ASSERT(prBssInfo); + + pucBuffer = (PUINT_8)((UINT_32)prMsduInfo->prPacket + + (UINT_32)prMsduInfo->u2FrameLength); + ASSERT(pucBuffer); + + /* Compose the frame body of the Probe Response frame. */ + //4 <1> Fill the SSID element. + SSID_IE(pucBuffer)->ucId = ELEM_ID_SSID; + SSID_IE(pucBuffer)->ucLength = prBssInfo->ucSSIDLen; + if (prBssInfo->ucSSIDLen) { + kalMemCopy(SSID_IE(pucBuffer)->aucSSID, prBssInfo->aucSSID, prBssInfo->ucSSIDLen); + } + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + + + //4 <2> Fill the Supported Rates element. + if (prBssInfo->ucAllSupportedRatesLen > ELEM_MAX_LEN_SUP_RATES) { + + ucSupRatesLen = ELEM_MAX_LEN_SUP_RATES; + } + else { + ucSupRatesLen = prBssInfo->ucAllSupportedRatesLen; + } + + if (ucSupRatesLen) { + SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_SUP_RATES; + SUP_RATES_IE(pucBuffer)->ucLength = ucSupRatesLen; + kalMemCopy(SUP_RATES_IE(pucBuffer)->aucSupportedRates, + prBssInfo->aucAllSupportedRates, + ucSupRatesLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + } + + + //4 <3> Fill the DS Parameter Set element. + if (prBssInfo->eBand == BAND_2G4) { + DS_PARAM_IE(pucBuffer)->ucId = ELEM_ID_DS_PARAM_SET; + DS_PARAM_IE(pucBuffer)->ucLength = ELEM_MAX_LEN_DS_PARAMETER_SET; + DS_PARAM_IE(pucBuffer)->ucCurrChnl = prBssInfo->ucPrimaryChannel; + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + } + + + //4 <4> IBSS Parameter Set element, ID: 6 + if (prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { + IBSS_PARAM_IE(pucBuffer)->ucId = ELEM_ID_IBSS_PARAM_SET; + IBSS_PARAM_IE(pucBuffer)->ucLength = ELEM_MAX_LEN_IBSS_PARAMETER_SET; + WLAN_SET_FIELD_16(&(IBSS_PARAM_IE(pucBuffer)->u2ATIMWindow), prBssInfo->u2ATIMWindow); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + } + + + //4 <5> TIM element, ID: 5 + if ((!pucDestAddr) && // For Beacon only. + (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT)) { + +#if CFG_ENABLE_WIFI_DIRECT + /*no fgIsP2PRegistered protect*/ + if (prBssInfo->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { +#if 0 + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo; + UINT_8 ucBitmapControl = 0; + UINT_32 u4N1, u4N2; + + + prP2pSpecificBssInfo = &(prAdapter->rWifiVar.rP2pSpecificBssInfo); + + // Clear existing value. + prP2pSpecificBssInfo->ucBitmapCtrl = 0; + kalMemZero(prP2pSpecificBssInfo->aucPartialVirtualBitmap, + sizeof(prP2pSpecificBssInfo->aucPartialVirtualBitmap)); + + + // IEEE 802.11 2007 - 7.3.2.6 + TIM_IE(pucBuffer)->ucId = ELEM_ID_TIM; + TIM_IE(pucBuffer)->ucDTIMCount = prBssInfo->ucDTIMCount; + TIM_IE(pucBuffer)->ucDTIMPeriod = prBssInfo->ucDTIMPeriod; + + // Setup DTIM Count for next TBTT. + if (prBssInfo->ucDTIMCount == 0) { + //3 *** pmQueryBufferedBCAST(); + } + + //3 *** pmQueryBufferedPSNode(); + /* TODO(Kevin): Call PM Module here to loop all STA_RECORD_Ts and it + * will call bssSetTIMBitmap to toggle the Bitmap. + */ + + // Set Virtual Bitmap for UCAST + u4N1 = (prP2pSpecificBssInfo->u2SmallestAID >> 4) << 1; // Find the largest even number. + u4N2 = prP2pSpecificBssInfo->u2LargestAID >> 3; // Find the smallest number. + + ASSERT(u4N2 >= u4N1); + + kalMemCopy(TIM_IE(pucBuffer)->aucPartialVirtualMap, + &prP2pSpecificBssInfo->aucPartialVirtualBitmap[u4N1], + ((u4N2 - u4N1) + 1)); + + // Set Virtual Bitmap for BMCAST + // BMC bit only indicated when DTIM count == 0. + if (prBssInfo->ucDTIMCount == 0) { + ucBitmapControl = prP2pSpecificBssInfo->ucBitmapCtrl; + } + TIM_IE(pucBuffer)->ucBitmapControl = ucBitmapControl | (UINT_8)u4N1; + + TIM_IE(pucBuffer)->ucLength = ((u4N2 - u4N1) + 4); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); +#else + + // IEEE 802.11 2007 - 7.3.2.6 + TIM_IE(pucBuffer)->ucId = ELEM_ID_TIM; + TIM_IE(pucBuffer)->ucLength = (3 + MAX_LEN_TIM_PARTIAL_BMP)/*((u4N2 - u4N1) + 4)*/; // NOTE: fixed PVB length (AID is allocated from 8 ~ 15 only) + TIM_IE(pucBuffer)->ucDTIMCount = 0/*prBssInfo->ucDTIMCount*/; // will be overwrite by FW + TIM_IE(pucBuffer)->ucDTIMPeriod = prBssInfo->ucDTIMPeriod; + TIM_IE(pucBuffer)->ucBitmapControl = 0/*ucBitmapControl | (UINT_8)u4N1*/; // will be overwrite by FW + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + +#endif + + } + else +#endif /* CFG_ENABLE_WIFI_DIRECT */ + { + /* NOTE(Kevin): 1. AIS - Didn't Support AP Mode. + * 2. BOW - Didn't Support BCAST and PS. + */ + } + + + + } + + return; +} /* end of bssBuildBeaconProbeRespFrameCommonIEs() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will compose the Beacon/Probe Response frame header and +* its fixed fields. +* +* @param[in] pucBuffer Pointer to the frame buffer. +* @param[in] pucDestAddr Pointer to the Destination Address, if NULL, means Beacon. +* @param[in] pucOwnMACAddress Given Our MAC Address. +* @param[in] pucBSSID Given BSSID of the BSS. +* @param[in] u2BeaconInterval Given Beacon Interval. +* @param[in] u2CapInfo Given Capability Info. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +bssComposeBeaconProbeRespFrameHeaderAndFF ( + IN PUINT_8 pucBuffer, + IN PUINT_8 pucDestAddr, + IN PUINT_8 pucOwnMACAddress, + IN PUINT_8 pucBSSID, + IN UINT_16 u2BeaconInterval, + IN UINT_16 u2CapInfo + ) +{ + P_WLAN_BEACON_FRAME_T prBcnProbRspFrame; + UINT_8 aucBCAddr[] = BC_MAC_ADDR; + UINT_16 u2FrameCtrl; + + DEBUGFUNC("bssComposeBeaconProbeRespFrameHeaderAndFF"); + //DBGLOG(INIT, LOUD, ("\n")); + + + ASSERT(pucBuffer); + ASSERT(pucOwnMACAddress); + ASSERT(pucBSSID); + + prBcnProbRspFrame = (P_WLAN_BEACON_FRAME_T)pucBuffer; + + //4 <1> Compose the frame header of the Beacon /ProbeResp frame. + /* Fill the Frame Control field. */ + if (pucDestAddr) { + u2FrameCtrl = MAC_FRAME_PROBE_RSP; + } + else { + u2FrameCtrl = MAC_FRAME_BEACON; + pucDestAddr = aucBCAddr; + } + //WLAN_SET_FIELD_16(&prBcnProbRspFrame->u2FrameCtrl, u2FrameCtrl); + prBcnProbRspFrame->u2FrameCtrl = u2FrameCtrl; // NOTE(Kevin): Optimized for ARM + + /* Fill the DA field with BCAST MAC ADDR or TA of ProbeReq. */ + COPY_MAC_ADDR(prBcnProbRspFrame->aucDestAddr, pucDestAddr); + + /* Fill the SA field with our MAC Address. */ + COPY_MAC_ADDR(prBcnProbRspFrame->aucSrcAddr, pucOwnMACAddress); + + /* Fill the BSSID field with current BSSID. */ + COPY_MAC_ADDR(prBcnProbRspFrame->aucBSSID, pucBSSID); + + /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ + prBcnProbRspFrame->u2SeqCtrl = 0; + + + //4 <2> Compose the frame body's common fixed field part of the Beacon /ProbeResp frame. + /* MAC will update TimeStamp field */ + + /* Fill the Beacon Interval field. */ + //WLAN_SET_FIELD_16(&prBcnProbRspFrame->u2BeaconInterval, u2BeaconInterval); + prBcnProbRspFrame->u2BeaconInterval = u2BeaconInterval; // NOTE(Kevin): Optimized for ARM + + /* Fill the Capability Information field. */ + //WLAN_SET_FIELD_16(&prBcnProbRspFrame->u2CapInfo, u2CapInfo); + prBcnProbRspFrame->u2CapInfo = u2CapInfo; // NOTE(Kevin): Optimized for ARM + + return; +} /* end of bssComposeBeaconProbeRespFrameHeaderAndFF() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Update the Beacon Frame Template to FW for AIS AdHoc and P2P GO. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] eNetTypeIndex Specify which network reply the Probe Response. +* +* @retval WLAN_STATUS_SUCCESS Success. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +bssUpdateBeaconContent ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex + ) +{ + P_BSS_INFO_T prBssInfo; + P_MSDU_INFO_T prMsduInfo; + P_WLAN_BEACON_FRAME_T prBcnFrame; + UINT_32 i; + + DEBUGFUNC("bssUpdateBeaconContent"); + DBGLOG(INIT, LOUD, ("bssUpdateBeaconContent\n")); + + ASSERT(eNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); + + //4 <1> Allocate a PKT_INFO_T for Beacon Frame + /* Allocate a MSDU_INFO_T */ + // For Beacon + prMsduInfo = prBssInfo->prBeacon; + + // beacon prMsduInfo will be NULLify once BSS deactivated, so skip if it is + if (prMsduInfo == NULL) { + return WLAN_STATUS_SUCCESS; + } + + //4 <2> Compose header + bssComposeBeaconProbeRespFrameHeaderAndFF( + (PUINT_8)((UINT_32)(prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + NULL, + prBssInfo->aucOwnMacAddr, + prBssInfo->aucBSSID, + prBssInfo->u2BeaconInterval, + prBssInfo->u2CapInfo); + + + prMsduInfo->u2FrameLength = (WLAN_MAC_MGMT_HEADER_LEN + + (TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN)); + + prMsduInfo->ucNetworkType = eNetTypeIndex; + + //4 <3> Compose the frame body's Common IEs of the Beacon frame. + bssBuildBeaconProbeRespFrameCommonIEs(prMsduInfo, prBssInfo, NULL); + + + //4 <4> Compose IEs in MSDU_INFO_T + + /* Append IE for Beacon */ + for (i = 0; i < sizeof(txBcnIETable)/sizeof(APPEND_VAR_IE_ENTRY_T); i++) { + if (txBcnIETable[i].pfnAppendIE) { + txBcnIETable[i].pfnAppendIE(prAdapter, prMsduInfo); + } + } + + prBcnFrame = (P_WLAN_BEACON_FRAME_T)prMsduInfo->prPacket; + + return nicUpdateBeaconIETemplate(prAdapter, + IE_UPD_METHOD_UPDATE_ALL, + eNetTypeIndex, + prBssInfo->u2CapInfo, + (PUINT_8)prBcnFrame->aucInfoElem, + prMsduInfo->u2FrameLength - OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem)); + + +} /* end of bssUpdateBeaconContent() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Send the Beacon Frame(for BOW) or Probe Response Frame according to the given +* Destination Address. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] eNetTypeIndex Specify which network reply the Probe Response. +* @param[in] pucDestAddr Pointer to the Destination Address to reply +* @param[in] u4ControlFlags Control flags for information on Probe Response. +* +* @retval WLAN_STATUS_RESOURCE No available resources to send frame. +* @retval WLAN_STATUS_SUCCESS Success. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +bssSendBeaconProbeResponse ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN PUINT_8 pucDestAddr, + IN UINT_32 u4ControlFlags + ) +{ + P_BSS_INFO_T prBssInfo; + P_MSDU_INFO_T prMsduInfo; + UINT_16 u2EstimatedFrameLen; + UINT_16 u2EstimatedFixedIELen; + UINT_16 u2EstimatedExtraIELen; + P_APPEND_VAR_IE_ENTRY_T prIeArray = NULL; + UINT_32 u4IeArraySize = 0; + UINT_32 i; + + + ASSERT(eNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); + + + if (!pucDestAddr) { // For Beacon + prIeArray = &txBcnIETable[0]; + u4IeArraySize = sizeof(txBcnIETable)/sizeof(APPEND_VAR_IE_ENTRY_T); + } + else { +#if CFG_ENABLE_WIFI_DIRECT + + if (u4ControlFlags & BSS_PROBE_RESP_INCLUDE_P2P_IE) { + if(prAdapter->fgIsP2PRegistered && prTxProbRspIETableWIP2P) { + ASSERT(prAdapter->rP2pFuncLkr.prP2pGetTxProbRspIETAbleSize); + prIeArray = prTxProbRspIETableWIP2P; + u4IeArraySize = + prAdapter->rP2pFuncLkr.prP2pGetTxProbRspIETAbleSize(); + } else { + DBGLOG(BSS, WARN, ( "prTxProbRspIETableWIP2P is NULL\n")); + ASSERT(0); + } + } + else +#endif /* CFG_ENABLE_WIFI_DIRECT */ + { + prIeArray = &txProbRspIETable[0]; + u4IeArraySize = sizeof(txProbRspIETable)/sizeof(APPEND_VAR_IE_ENTRY_T); + } + } + + + //4 <1> Allocate a PKT_INFO_T for Beacon /Probe Response Frame + /* Allocate a MSDU_INFO_T */ + + /* Init with MGMT Header Length + Length of Fixed Fields + Common IE Fields */ + u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + \ + WLAN_MAC_MGMT_HEADER_LEN + \ + TIMESTAMP_FIELD_LEN + \ + BEACON_INTERVAL_FIELD_LEN + \ + CAP_INFO_FIELD_LEN + \ + (ELEM_HDR_LEN + ELEM_MAX_LEN_SSID) + \ + (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + \ + (ELEM_HDR_LEN + ELEM_MAX_LEN_DS_PARAMETER_SET) + \ + (ELEM_HDR_LEN + ELEM_MAX_LEN_IBSS_PARAMETER_SET) + \ + (ELEM_HDR_LEN + (3 + MAX_LEN_TIM_PARTIAL_BMP)); + + /* + Extra IE Length */ + u2EstimatedExtraIELen = 0; + + for (i = 0; i < u4IeArraySize; i++) { + u2EstimatedFixedIELen = prIeArray[i].u2EstimatedFixedIELen; + + if (u2EstimatedFixedIELen) { + u2EstimatedExtraIELen += u2EstimatedFixedIELen; + } + else { + ASSERT(prIeArray[i].pfnCalculateVariableIELen); + + u2EstimatedExtraIELen += (UINT_16) + prIeArray[i].pfnCalculateVariableIELen(prAdapter, eNetTypeIndex, NULL); + } + } + + u2EstimatedFrameLen += u2EstimatedExtraIELen; + + if ( (prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen)) == NULL) { + DBGLOG(BSS, WARN, ("No PKT_INFO_T for sending %s.\n", + ((!pucDestAddr)?"Beacon":"Probe Response"))); + return WLAN_STATUS_RESOURCES; + } + + + //4 <2> Compose Beacon/Probe Response frame header and fixed fields in MSDU_INfO_T. + /* Compose Header and Fixed Field */ +#if CFG_ENABLE_WIFI_DIRECT + if (u4ControlFlags & BSS_PROBE_RESP_USE_P2P_DEV_ADDR) { + if(prAdapter->fgIsP2PRegistered) { + bssComposeBeaconProbeRespFrameHeaderAndFF( + (PUINT_8)((UINT_32)(prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + pucDestAddr, + prAdapter->rWifiVar.aucDeviceAddress, + prAdapter->rWifiVar.aucDeviceAddress, + DOT11_BEACON_PERIOD_DEFAULT, + (prBssInfo->u2CapInfo & ~(CAP_INFO_ESS | CAP_INFO_IBSS))); + } + } + else +#endif /* CFG_ENABLE_WIFI_DIRECT */ + { + bssComposeBeaconProbeRespFrameHeaderAndFF( + (PUINT_8)((UINT_32)(prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + pucDestAddr, + prBssInfo->aucOwnMacAddr, + prBssInfo->aucBSSID, + prBssInfo->u2BeaconInterval, + prBssInfo->u2CapInfo); + } + + + //4 <3> Update information of MSDU_INFO_T + prMsduInfo->eSrc = TX_PACKET_MGMT; + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; + prMsduInfo->ucStaRecIndex = 0xFF; + prMsduInfo->ucNetworkType = (UINT_8)eNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = (WLAN_MAC_MGMT_HEADER_LEN + + TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN); + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = NULL; + prMsduInfo->fgIsBasicRate = TRUE; + + + //4 <4> Compose the frame body's Common IEs of the Beacon/ProbeResp frame. + bssBuildBeaconProbeRespFrameCommonIEs(prMsduInfo, prBssInfo, pucDestAddr); + + + //4 <5> Compose IEs in MSDU_INFO_T + + /* Append IE */ + for (i = 0; i < u4IeArraySize; i++) { + if (prIeArray[i].pfnAppendIE) { + prIeArray[i].pfnAppendIE(prAdapter, prMsduInfo); + } + } + + /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ + + //4 <6> Inform TXM to send this Beacon /Probe Response frame. + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; + +} /* end of bssSendBeaconProbeResponse() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will process the Rx Probe Request Frame and then send +* back the corresponding Probe Response Frame if the specified conditions +* were matched. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to SW RFB data structure. +* +* @retval WLAN_STATUS_SUCCESS Always return success +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +bssProcessProbeRequest ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ) +{ + P_WLAN_MAC_MGMT_HEADER_T prMgtHdr; + P_BSS_INFO_T prBssInfo; + ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex; + UINT_8 aucBCBSSID[] = BC_BSSID; + BOOLEAN fgIsBcBssid; + BOOLEAN fgReplyProbeResp; + UINT_32 u4CtrlFlagsForProbeResp = 0; + ENUM_BAND_T eBand; + UINT_8 ucHwChannelNum; + + + ASSERT(prSwRfb); + + //4 <1> Parse Probe Req and Get BSSID + prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T)prSwRfb->pvHeader; + + if (EQUAL_MAC_ADDR(aucBCBSSID, prMgtHdr->aucBSSID)) { + fgIsBcBssid = TRUE; + } + else { + fgIsBcBssid = FALSE; + } + + + //4 <2> Check network conditions before reply Probe Response Frame (Consider Concurrent) + for (eNetTypeIndex = NETWORK_TYPE_AIS_INDEX; eNetTypeIndex < NETWORK_TYPE_INDEX_NUM; eNetTypeIndex++) { + + if (!IS_NET_ACTIVE(prAdapter, eNetTypeIndex)) { + continue; + } + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); + + if ((!fgIsBcBssid) && + UNEQUAL_MAC_ADDR(prBssInfo->aucBSSID, prMgtHdr->aucBSSID)) { + continue; + } + + eBand = HIF_RX_HDR_GET_RF_BAND(prSwRfb->prHifRxHdr); + ucHwChannelNum = HIF_RX_HDR_GET_CHNL_NUM(prSwRfb->prHifRxHdr); + + if(prBssInfo->eBand != eBand) { + continue; + } + + if(prBssInfo->ucPrimaryChannel != ucHwChannelNum) { + continue; + } + + fgReplyProbeResp = FALSE; + + if (NETWORK_TYPE_AIS_INDEX == eNetTypeIndex) { + +#if CFG_SUPPORT_ADHOC + fgReplyProbeResp = aisValidateProbeReq(prAdapter, prSwRfb, &u4CtrlFlagsForProbeResp); +#endif + } +#if CFG_ENABLE_WIFI_DIRECT + else if ((prAdapter->fgIsP2PRegistered) && + (NETWORK_TYPE_P2P_INDEX == eNetTypeIndex)) { + + fgReplyProbeResp = prAdapter->rP2pFuncLkr.prP2pFuncValidateProbeReq(prAdapter, prSwRfb, &u4CtrlFlagsForProbeResp); + } +#endif +#if CFG_ENABLE_BT_OVER_WIFI + else if (NETWORK_TYPE_BOW_INDEX == eNetTypeIndex) { + + fgReplyProbeResp = bowValidateProbeReq(prAdapter, prSwRfb, &u4CtrlFlagsForProbeResp); + } +#endif + + if (fgReplyProbeResp) { + if(nicTxGetFreeCmdCount(prAdapter) > (CFG_TX_MAX_CMD_PKT_NUM/2) ){ + /* Resource margin is enough */ + bssSendBeaconProbeResponse(prAdapter, eNetTypeIndex, prMgtHdr->aucSrcAddr, u4CtrlFlagsForProbeResp); + } + } + } + + return WLAN_STATUS_SUCCESS; + +} /* end of bssProcessProbeRequest() */ + + +#if 0 // NOTE(Kevin): condition check should move to P2P_FSM.c +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will process the Rx Probe Request Frame and then send +* back the corresponding Probe Response Frame if the specified conditions +* were matched. +* +* @param[in] prSwRfb Pointer to SW RFB data structure. +* +* @retval WLAN_STATUS_SUCCESS Always return success +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +bssProcessProbeRequest ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ) +{ + P_WLAN_MAC_MGMT_HEADER_T prMgtHdr; + P_BSS_INFO_T prBssInfo; + P_IE_SSID_T prIeSsid = (P_IE_SSID_T)NULL; + P_IE_SUPPORTED_RATE_T prIeSupportedRate = (P_IE_SUPPORTED_RATE_T)NULL; + P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate = (P_IE_EXT_SUPPORTED_RATE_T)NULL; + PUINT_8 pucIE; + UINT_16 u2IELength; + UINT_16 u2Offset = 0; + UINT_8 aucBCBSSID[] = BC_BSSID; + ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex; + BOOLEAN fgReplyProbeResp; +#if CFG_ENABLE_WIFI_DIRECT + BOOLEAN fgP2PTargetDeviceFound; + UINT_8 aucP2PWildcardSSID[] = P2P_WILDCARD_SSID; +#endif + + ASSERT(prSwRfb); + + //4 <1> Parse Probe Req and Get SSID IE ptr + prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T)prSwRfb->pvHeader; + + u2IELength = prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen; + pucIE = (PUINT_8)((UINT_32)prSwRfb->pvHeader + prSwRfb->u2HeaderLen); + + prIeSsid = (P_IE_SSID_T)NULL; + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_SSID: + if ((!prIeSsid) && + (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) { + prIeSsid = (P_IE_SSID_T)pucIE; + } + break; + + case ELEM_ID_SUP_RATES: + /* NOTE(Kevin): Buffalo WHR-G54S's supported rate set IE exceed 8. + * IE_LEN(pucIE) == 12, "1(B), 2(B), 5.5(B), 6(B), 9(B), 11(B), + * 12(B), 18(B), 24(B), 36(B), 48(B), 54(B)" + */ + // if (IE_LEN(pucIE) <= ELEM_MAX_LEN_SUP_RATES) { + if (IE_LEN(pucIE) <= RATE_NUM) { + prIeSupportedRate = SUP_RATES_IE(pucIE); + } + break; + + case ELEM_ID_EXTENDED_SUP_RATES: + prIeExtSupportedRate = EXT_SUP_RATES_IE(pucIE); + break; + +#if CFG_ENABLE_WIFI_DIRECT + // TODO: P2P IE & WCS IE parsing for P2P. + case ELEM_ID_P2P: + + break; +#endif + + /* no default */ + } + } /* end of IE_FOR_EACH */ + + //4 <2> Check network conditions before reply Probe Response Frame (Consider Concurrent) + for (eNetTypeIndex = NETWORK_TYPE_AIS_INDEX; eNetTypeIndex < NETWORK_TYPE_INDEX_NUM; eNetTypeIndex++) { + + if (!IS_NET_ACTIVE(prAdapter, eNetTypeIndex)) { + continue; + } + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); + + if (UNEQUAL_MAC_ADDR(aucBCBSSID, prMgtHdr->aucBSSID) && + UNEQUAL_MAC_ADDR(prBssInfo->aucBSSID, prMgtHdr->aucBSSID)) { + /* BSSID not Wildcard BSSID. */ + continue; + } + + fgReplyProbeResp = FALSE; + + if (NETWORK_TYPE_AIS_INDEX == eNetTypeIndex) { + + if (prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { + + /* TODO(Kevin): Check if we are IBSS Master. */ + if (TRUE) { + + if (prIeSsid) { + if ((prIeSsid->ucLength == BC_SSID_LEN) || /* WILDCARD SSID */ + EQUAL_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, + prIeSsid->aucSSID, prIeSsid->ucLength)) { + fgReplyProbeResp = TRUE; + } + } + } + } + } +#if CFG_ENABLE_WIFI_DIRECT + else if (NETWORK_TYPE_P2P_INDEX == eNetTypeIndex) { + + // TODO(Kevin): Move following lines to p2p_fsm.c + + if ((prIeSsid) && + ((prIeSsid->ucLength == BC_SSID_LEN) || + (EQUAL_SSID(aucP2PWildcardSSID, + P2P_WILDCARD_SSID_LEN, + prIeSsid->aucSSID, + prIeSsid->ucLength)))) { +// if (p2pFsmRunEventRxProbeRequestFrame(prAdapter, prMgtHdr->aucSrcAddr, pucIE, u2IELength)) { + if (p2pFsmRunEventRxProbeRequestFrame(prAdapter, prSwRfb)) { + /* Extand channel request time & cancel scan request. */ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; + + // TODO: RX probe request may not caused by LISTEN state. + // TODO: It can be GO. + /* Generally speaking, cancel a non-exist scan request is fine. + * We can check P2P FSM here for only LISTEN state. + */ + + P_MSG_SCN_SCAN_CANCEL prScanCancelMsg; + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + /* Abort JOIN process. */ + prScanCancelMsg = (P_MSG_SCN_SCAN_CANCEL)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_CANCEL)); + if (!prScanCancelMsg) { + ASSERT(0); // Can't abort SCN FSM + continue; + } + + prScanCancelMsg->rMsgHdr.eMsgId = MID_P2P_SCN_SCAN_CANCEL; + prScanCancelMsg->ucSeqNum = prP2pFsmInfo->ucSeqNumOfScnMsg; + prScanCancelMsg->ucNetTypeIndex = (UINT_8)NETWORK_TYPE_P2P_INDEX; + prScanCancelMsg->fgIsChannelExt = TRUE; + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prScanCancelMsg, + MSG_SEND_METHOD_BUF); + } + } + else { + /* 1. Probe Request without SSID. + * 2. Probe Request with SSID not Wildcard SSID & not P2P Wildcard SSID. + */ + continue; + } + +#if 0 // Frog + if (prAdapter->rWifiVar.prP2pFsmInfo->eCurrentState == P2P_STATE_LISTEN) { + // P2P 2.4.1 - P2P Devices shall not respond to Probe Request frames which only contain 11b rates only. + if (prIeSupportedRate || prIeExtSupportedRate) { + UINT_16 u2OperationalRateSet, u2BSSBasicRateSet; + BOOLEAN fgIsUnknownBssBasicRate; + + rateGetRateSetFromIEs(prIeSupportedRate, + prIeExtSupportedRate, + &u2OperationalRateSet, + &u2BSSBasicRateSet, /* Ignore any Basic Bit */ + &fgIsUnknownBssBasicRate); + + if (u2OperationalRateSet & ~RATE_SET_HR_DSSS) { + continue; + } + } + } + + // TODO: Check channel time before first check point to: + /* If Target device is selected: + * 1. Send XXXX request frame. + * else + * 1. Send Probe Response frame. + */ + + if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + /* TODO(Kevin): During PROVISION state, can we reply Probe Response ? */ + + /* TODO(Kevin): + * If we are GO, accept legacy client --> accept Wildcard SSID + * If we are in Listen State, accept only P2P Device --> check P2P IE and WPS IE + */ + if (TRUE /* We are GO */) { + if (prIeSsid) { + UINT_8 aucSSID[]=P2P_WILDCARD_SSID; + + if ((prIeSsid->ucLength == BC_SSID_LEN) || /* WILDCARD SSID */ + EQUAL_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, + prIeSsid->aucSSID, prIeSsid->ucLength) || + EQUAL_SSID(aucSSID, P2P_WILDCARD_SSID_LEN, + prIeSsid->aucSSID, prIeSsid->ucLength)) { + fgReplyProbeResp = TRUE; + } + } + } +// else if (FALSE /* We are in Listen State */) { +// } + + /* TODO(Kevin): Check P2P IE and WPS IE */ + } +#endif + } +#endif +#if CFG_ENABLE_BT_OVER_WIFI + else if (NETWORK_TYPE_BOW_INDEX == eNetTypeIndex) { + + if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + /* TODO(Kevin): TBD */ + } + } +#endif + else { + ASSERT(eNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + } + + if (fgReplyProbeResp) { + bssSendBeaconProbeResponse(prAdapter, eNetTypeIndex, prMgtHdr->aucSrcAddr); + } + + } + + return WLAN_STATUS_SUCCESS; + +} /* end of bssProcessProbeRequest() */ +#endif + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to clear the client list for AdHoc or AP Mode +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prBssInfo Given related BSS_INFO_T. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +bssClearClientList ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo + ) +{ + P_LINK_T prStaRecOfClientList; + + + ASSERT(prBssInfo); + + prStaRecOfClientList = &prBssInfo->rStaRecOfClientList; + + if (!LINK_IS_EMPTY(prStaRecOfClientList)) { + P_STA_RECORD_T prPeerStaRec; + + LINK_FOR_EACH_ENTRY(prPeerStaRec, prStaRecOfClientList, rLinkEntry, STA_RECORD_T) { + cnmStaRecChangeState(prAdapter, prPeerStaRec, STA_STATE_1); + } + + LINK_INITIALIZE(prStaRecOfClientList); + } + + return; +} /* end of bssClearClientList() */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to Add a STA_RECORD_T to the client list for AdHoc or AP Mode +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prBssInfo Given related BSS_INFO_T. +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +bssAddStaRecToClientList ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN P_STA_RECORD_T prStaRec + ) +{ + P_LINK_T prStaRecOfClientList; + + + ASSERT(prBssInfo); + + prStaRecOfClientList = &prBssInfo->rStaRecOfClientList; + + if (!LINK_IS_EMPTY(prStaRecOfClientList)) { + P_STA_RECORD_T prCurrStaRec; + + LINK_FOR_EACH_ENTRY(prCurrStaRec, prStaRecOfClientList, rLinkEntry, STA_RECORD_T) { + + if (prCurrStaRec == prStaRec) { + DBGLOG(BSS, WARN, ("Current Client List already contains that STA_RECORD_T["MACSTR"]\n", + MAC2STR(prStaRec->aucMacAddr))); + return; + } + } + } + + LINK_INSERT_TAIL(prStaRecOfClientList, &prStaRec->rLinkEntry); + + return; +} /* end of bssAddStaRecToClientList() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to Remove a STA_RECORD_T from the client list for AdHoc or AP Mode +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +bssRemoveStaRecFromClientList ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN P_STA_RECORD_T prStaRec + ) +{ + P_LINK_T prStaRecOfClientList; + + + ASSERT(prBssInfo); + + prStaRecOfClientList = &prBssInfo->rStaRecOfClientList; + + if (!LINK_IS_EMPTY(prStaRecOfClientList)) { + P_STA_RECORD_T prCurrStaRec; + + LINK_FOR_EACH_ENTRY(prCurrStaRec, prStaRecOfClientList, rLinkEntry, STA_RECORD_T) { + + if (prCurrStaRec == prStaRec) { + + LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, &prStaRec->rLinkEntry); + + return; + } + } + } + + DBGLOG(BSS, INFO, ("Current Client List didn't contain that STA_RECORD_T["MACSTR"] before removing.\n", + MAC2STR(prStaRec->aucMacAddr))); + + return; +} /* end of bssRemoveStaRecFromClientList() */ +#endif /* CFG_SUPPORT_ADHOC || CFG_SUPPORT_AAA */ + + +#if CFG_SUPPORT_ADHOC +/*----------------------------------------------------------------------------*/ +/* Routines for IBSS(AdHoc) only */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to process Beacons from current Ad-Hoc network peers. +* We also process Beacons from other Ad-Hoc network during SCAN. If it has +* the same SSID and we'll decide to merge into it if it has a larger TSF. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prBssInfo Pointer to the BSS_INFO_T. +* @param[in] prBSSDesc Pointer to the BSS Descriptor. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +ibssProcessMatchedBeacon ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN P_BSS_DESC_T prBssDesc, + IN UINT_8 ucRCPI + ) +{ + P_STA_RECORD_T prStaRec = NULL; + + BOOLEAN fgIsCheckCapability = FALSE; + BOOLEAN fgIsCheckTSF = FALSE; + BOOLEAN fgIsGoingMerging = FALSE; + BOOLEAN fgIsSameBSSID; + + + ASSERT(prBssInfo); + ASSERT(prBssDesc); + + //4 <1> Process IBSS Beacon only after we create or merge with other IBSS. + if (!prBssInfo->fgIsBeaconActivated) { + return; + } + + //4 <2> Get the STA_RECORD_T of TA. + prStaRec = cnmGetStaRecByAddress(prAdapter, + (UINT_8) NETWORK_TYPE_AIS_INDEX, + prBssDesc->aucSrcAddr); + + fgIsSameBSSID = UNEQUAL_MAC_ADDR(prBssInfo->aucBSSID, prBssDesc->aucBSSID) ? FALSE : TRUE; + + + //4 <3> IBSS Merge Decision Flow for Processing Beacon. + if (fgIsSameBSSID) { + + /* Same BSSID: + * Case I. This is a new TA and it has decide to merged with us. + * a) If fgIsMerging == FALSE - we will send msg to notify AIS. + * b) If fgIsMerging == TRUE - already notify AIS. + * Case II. This is an old TA and we've already merged together. + */ + if (!prStaRec) { + + /* For Case I - Check this IBSS's capability first before adding this Sta Record. */ + fgIsCheckCapability = TRUE; + + /* If check is passed, then we perform merging with this new IBSS */ + fgIsGoingMerging = TRUE; + + } + else { + + ASSERT((prStaRec->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) && + IS_ADHOC_STA(prStaRec)); + + if (prStaRec->ucStaState != STA_STATE_3) { + + if (!prStaRec->fgIsMerging) { + + /* For Case I - Check this IBSS's capability first before adding this Sta Record. */ + fgIsCheckCapability = TRUE; + + /* If check is passed, then we perform merging with this new IBSS */ + fgIsGoingMerging = TRUE; + } + else { + /* For Case II - Update rExpirationTime of Sta Record */ + GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); + } + } + else { + /* For Case II - Update rExpirationTime of Sta Record */ + GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); + } + + } + } + else { + + /* Unequal BSSID: + * Case III. This is a new TA and we need to compare the TSF and get the winner. + * Case IV. This is an old TA and it merge into a new IBSS before we do the same thing. + * We need to compare the TSF to get the winner. + * Case V. This is an old TA and it restart a new IBSS. We also need to + * compare the TSF to get the winner. + */ + + /* For Case III, IV & V - We'll always check this new IBSS's capability first + * before merging into new IBSS. + */ + fgIsCheckCapability = TRUE; + + /* If check is passed, we need to perform TSF check to decide the major BSSID */ + fgIsCheckTSF = TRUE; + + /* For Case IV & V - We won't update rExpirationTime of Sta Record */ + } + + + //4 <7> Check this BSS_DESC_T's capability. + if (fgIsCheckCapability) { + BOOLEAN fgIsCapabilityMatched = FALSE; + + do { + if (!(prBssDesc->ucPhyTypeSet & (prAdapter->rWifiVar.ucAvailablePhyTypeSet))) { + DBGLOG(BSS, LOUD, + ("IBSS MERGE: Ignore Peer MAC: "MACSTR" - Unsupported Phy.\n", + MAC2STR(prBssDesc->aucSrcAddr))); + + break; + } + + if (prBssDesc->fgIsUnknownBssBasicRate) { + DBGLOG(BSS, LOUD, + ("IBSS MERGE: Ignore Peer MAC: "MACSTR" - Unknown Basic Rate.\n", + MAC2STR(prBssDesc->aucSrcAddr))); + + break; + } + + if (ibssCheckCapabilityForAdHocMode(prAdapter, prBssDesc) == WLAN_STATUS_FAILURE) { + DBGLOG(BSS, LOUD, + ("IBSS MERGE: Ignore Peer MAC: "MACSTR" - Capability is not matched.\n", + MAC2STR(prBssDesc->aucSrcAddr))); + + break; + } + + fgIsCapabilityMatched = TRUE; + } + while (FALSE); + + if (!fgIsCapabilityMatched) { + + if (prStaRec) { + /* For Case II - We merge this STA_RECORD in RX Path. + * Case IV & V - They change their BSSID after we merge with them. + */ + + DBGLOG(BSS, LOUD, + ("IBSS MERGE: Ignore Peer MAC: "MACSTR" - Capability is not matched.\n", + MAC2STR(prBssDesc->aucSrcAddr))); + } + + return; + } + + DBGLOG(BSS, LOUD, + ("IBSS MERGE: Peer MAC: "MACSTR" - Check capability was passed.\n", + MAC2STR(prBssDesc->aucSrcAddr))); + } + + + if (fgIsCheckTSF) { +#if CFG_SLT_SUPPORT + fgIsGoingMerging = TRUE; +#else + if (prBssDesc->fgIsLargerTSF) { + fgIsGoingMerging = TRUE; + } + else { + return; + } +#endif + } + + + if (fgIsGoingMerging) { + P_MSG_AIS_IBSS_PEER_FOUND_T prAisIbssPeerFoundMsg; + + + //4 <1> We will merge with to this BSS immediately. + prBssDesc->fgIsConnecting = TRUE; + prBssDesc->fgIsConnected = FALSE; + + //4 <2> Setup corresponding STA_RECORD_T + prStaRec = bssCreateStaRecFromBssDesc(prAdapter, + STA_TYPE_ADHOC_PEER, + NETWORK_TYPE_AIS_INDEX, + prBssDesc); + + if(!prStaRec) { + // no memory ? + return; + } + + prStaRec->fgIsMerging = TRUE; + + /* update RCPI */ + prStaRec->ucRCPI = ucRCPI; + + //4 <3> Send Merge Msg to CNM to obtain the channel privilege. + prAisIbssPeerFoundMsg = (P_MSG_AIS_IBSS_PEER_FOUND_T) + cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_IBSS_PEER_FOUND_T)); + + if (!prAisIbssPeerFoundMsg) { + + ASSERT(0); // Can't send Merge Msg + return; + } + + prAisIbssPeerFoundMsg->rMsgHdr.eMsgId = MID_SCN_AIS_FOUND_IBSS; + prAisIbssPeerFoundMsg->ucNetTypeIndex = (UINT_8)NETWORK_TYPE_AIS_INDEX; + prAisIbssPeerFoundMsg->prStaRec = prStaRec; + + /* Inform AIS to do STATE TRANSITION + * For Case I - If AIS in IBSS_ALONE, let it jump to NORMAL_TR after we know the new member. + * For Case III, IV - Now this new BSSID wins the TSF, follow it. + */ + if (fgIsSameBSSID) { + prAisIbssPeerFoundMsg->fgIsMergeIn = TRUE; + } + else { +#if CFG_SLT_SUPPORT + prAisIbssPeerFoundMsg->fgIsMergeIn = TRUE; +#else + prAisIbssPeerFoundMsg->fgIsMergeIn = (prBssDesc->fgIsLargerTSF) ? FALSE: TRUE; +#endif + } + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prAisIbssPeerFoundMsg, + MSG_SEND_METHOD_BUF); + + } + + return; +} /* end of ibssProcessMatchedBeacon() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will check the Capability for Ad-Hoc to decide if we are +* able to merge with(same capability). +* +* @param[in] prBSSDesc Pointer to the BSS Descriptor. +* +* @retval WLAN_STATUS_FAILURE Can't pass the check of Capability. +* @retval WLAN_STATUS_SUCCESS Pass the check of Capability. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +ibssCheckCapabilityForAdHocMode ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc + ) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + + + ASSERT(prBssDesc); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + do { + //4 <1> Check the BSS Basic Rate Set for current AdHoc Mode + if ((prConnSettings->eAdHocMode == AD_HOC_MODE_11B) && + (prBssDesc->u2BSSBasicRateSet & ~RATE_SET_HR_DSSS)) { + break; + } + else if ((prConnSettings->eAdHocMode == AD_HOC_MODE_11A) && + (prBssDesc->u2BSSBasicRateSet & ~RATE_SET_OFDM)) { + break; + } + + //4 <2> Check the Short Slot Time. +#if 0 // Do not check ShortSlotTime until Wi-Fi define such policy + if (prConnSettings->eAdHocMode == AD_HOC_MODE_11G) { + if (((prConnSettings->fgIsShortSlotTimeOptionEnable) && + !(prBssDesc->u2CapInfo & CAP_INFO_SHORT_SLOT_TIME)) || + (!(prConnSettings->fgIsShortSlotTimeOptionEnable) && + (prBssDesc->u2CapInfo & CAP_INFO_SHORT_SLOT_TIME))) { + break; + } + } +#endif + + //4 <3> Check the ATIM window setting. + if (prBssDesc->u2ATIMWindow) { + DBGLOG(BSS, INFO, ("AdHoc PS was not supported(ATIM Window: %d)\n", + prBssDesc->u2ATIMWindow)); + break; + } + +#if CFG_RSN_MIGRATION + //4 <4> Check the Security setting. + if (!rsnPerformPolicySelection(prAdapter, prBssDesc)) { + break; + } +#endif + + rStatus = WLAN_STATUS_SUCCESS; + } + while (FALSE); + + return rStatus; + +} /* end of ibssCheckCapabilityForAdHocMode() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will initial the BSS_INFO_T for IBSS Mode. +* +* @param[in] prBssInfo Pointer to the BSS_INFO_T. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +ibssInitForAdHoc ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo + ) +{ + UINT_8 ucLowestBasicRateIndex; + UINT_8 aucBSSID[MAC_ADDR_LEN]; + PUINT_16 pu2BSSID = (PUINT_16)&aucBSSID[0]; + UINT_32 i; + + + ASSERT(prBssInfo); + ASSERT(prBssInfo->eCurrentOPMode == OP_MODE_IBSS); + + + //4 <1> Setup PHY Attributes and Basic Rate Set/Operational Rate Set + prBssInfo->ucNonHTBasicPhyType = (UINT_8) + rNonHTAdHocModeAttributes[prBssInfo->ucConfigAdHocAPMode].ePhyTypeIndex; + prBssInfo->u2BSSBasicRateSet = + rNonHTAdHocModeAttributes[prBssInfo->ucConfigAdHocAPMode].u2BSSBasicRateSet; + + + prBssInfo->u2OperationalRateSet = + rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType].u2SupportedRateSet; + + rateGetDataRatesFromRateSet(prBssInfo->u2OperationalRateSet, + prBssInfo->u2BSSBasicRateSet, + prBssInfo->aucAllSupportedRates, + &prBssInfo->ucAllSupportedRatesLen); + + //4 <2> Setup BSSID + if (!prBssInfo->fgHoldSameBssidForIBSS) { + + for (i = 0; i < sizeof(aucBSSID)/sizeof(UINT_16); i++) { + pu2BSSID[i] = (UINT_16)(kalRandomNumber() & 0xFFFF); + } + + aucBSSID[0] &= ~0x01; // 7.1.3.3.3 - The individual/group bit of the address is set to 0. + aucBSSID[0] |= 0x02; // 7.1.3.3.3 - The universal/local bit of the address is set to 1. + + COPY_MAC_ADDR(prBssInfo->aucBSSID, aucBSSID); + } + + + //4 <3> Setup Capability - Short Preamble + if (rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType].fgIsShortPreambleOptionImplemented && + ((prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_SHORT) || /* Short Preamble Option Enable is TRUE */ + (prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_AUTO)) ) { + + prBssInfo->fgIsShortPreambleAllowed = TRUE; + prBssInfo->fgUseShortPreamble = TRUE; + } + else { + prBssInfo->fgIsShortPreambleAllowed = FALSE; + prBssInfo->fgUseShortPreamble = FALSE; + } + + + //4 <4> Setup Capability - Short Slot Time + // 7.3.1.4 For IBSS, the Short Slot Time subfield shall be set to 0. + prBssInfo->fgUseShortSlotTime = FALSE; /* Set to FALSE for AdHoc */ + + + //4 <5> Compoase Capability + prBssInfo->u2CapInfo = CAP_INFO_IBSS; + + if (prBssInfo->fgIsProtection) { + prBssInfo->u2CapInfo |= CAP_INFO_PRIVACY; + } + + if (prBssInfo->fgIsShortPreambleAllowed) { + prBssInfo->u2CapInfo |= CAP_INFO_SHORT_PREAMBLE; + } + + if (prBssInfo->fgUseShortSlotTime) { + prBssInfo->u2CapInfo |= CAP_INFO_SHORT_SLOT_TIME; + } + + + //4 <6> Find Lowest Basic Rate Index for default TX Rate of MMPDU + rateGetLowestRateIndexFromRateSet(prBssInfo->u2BSSBasicRateSet, &ucLowestBasicRateIndex); + + prBssInfo->ucHwDefaultFixedRateCode = + aucRateIndex2RateCode[PREAMBLE_DEFAULT_LONG_NONE][ucLowestBasicRateIndex]; + + return; +} /* end of ibssInitForAdHoc() */ + +#endif /* CFG_SUPPORT_ADHOC */ + + +#if CFG_SUPPORT_AAA + +/*----------------------------------------------------------------------------*/ +/* Routines for BSS(AP) only */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will initial the BSS_INFO_T for AP Mode. +* +* @param[in] prBssInfo Given related BSS_INFO_T. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +bssInitForAP ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN BOOLEAN fgIsRateUpdate + ) +{ + UINT_8 ucLowestBasicRateIndex; + + P_AC_QUE_PARMS_T prACQueParms; + + ENUM_WMM_ACI_T eAci; + + UINT_8 auCWminLog2ForBcast[WMM_AC_INDEX_NUM] = { 4/*BE*/, 4 /*BK*/, 3/*VO*/, 2/*VI*/}; + UINT_8 auCWmaxLog2ForBcast[WMM_AC_INDEX_NUM] = { 10, 10, 4, 3}; + UINT_8 auAifsForBcast[WMM_AC_INDEX_NUM] = { 3, 7, 2, 2 }; + UINT_8 auTxopForBcast[WMM_AC_INDEX_NUM] = { 0, 0, 94, 47 }; /* If the AP is OFDM */ + + UINT_8 auCWminLog2[WMM_AC_INDEX_NUM] = { 4 /*BE*/, 4 /*BK*/, 3 /*VO*/, 2 /*VI*/}; + UINT_8 auCWmaxLog2[WMM_AC_INDEX_NUM] = { 7, 10, 4, 3}; + UINT_8 auAifs[WMM_AC_INDEX_NUM] = { 3, 7, 1, 1 }; + UINT_8 auTxop[WMM_AC_INDEX_NUM] = { 0, 0, 94, 47 }; /* If the AP is OFDM */ + + DEBUGFUNC("bssInitForAP"); + DBGLOG(BSS, LOUD,("\n")); + + ASSERT(prBssInfo); + ASSERT((prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) || (prBssInfo->eCurrentOPMode == OP_MODE_BOW)); + +#if 0 + prAdapter->rWifiVar.rConnSettings.fgRxShortGIDisabled = TRUE; + prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode = CONFIG_BW_20M; + prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode = CONFIG_BW_20M; +#endif + + + //4 <1> Setup PHY Attributes and Basic Rate Set/Operational Rate Set + prBssInfo->ucNonHTBasicPhyType = (UINT_8) + rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode].ePhyTypeIndex; + prBssInfo->u2BSSBasicRateSet = + rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode].u2BSSBasicRateSet; + + + prBssInfo->u2OperationalRateSet = + rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType].u2SupportedRateSet; + + if (fgIsRateUpdate) { + rateGetDataRatesFromRateSet(prBssInfo->u2OperationalRateSet, + prBssInfo->u2BSSBasicRateSet, + prBssInfo->aucAllSupportedRates, + &prBssInfo->ucAllSupportedRatesLen); + } + + //4 <2> Setup BSSID + COPY_MAC_ADDR(prBssInfo->aucBSSID, prBssInfo->aucOwnMacAddr); + + + //4 <3> Setup Capability - Short Preamble + if (rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType].fgIsShortPreambleOptionImplemented && + ((prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_SHORT) || /* Short Preamble Option Enable is TRUE */ + (prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_AUTO)) ) { + + prBssInfo->fgIsShortPreambleAllowed = TRUE; + prBssInfo->fgUseShortPreamble = TRUE; + } + else { + prBssInfo->fgIsShortPreambleAllowed = FALSE; + prBssInfo->fgUseShortPreamble = FALSE; + } + + + //4 <4> Setup Capability - Short Slot Time + prBssInfo->fgUseShortSlotTime = TRUE; + + //4 <5> Compoase Capability + prBssInfo->u2CapInfo = CAP_INFO_ESS; + + if (prBssInfo->fgIsProtection) { + prBssInfo->u2CapInfo |= CAP_INFO_PRIVACY; + } + + if (prBssInfo->fgIsShortPreambleAllowed) { + prBssInfo->u2CapInfo |= CAP_INFO_SHORT_PREAMBLE; + } + + if (prBssInfo->fgUseShortSlotTime) { + prBssInfo->u2CapInfo |= CAP_INFO_SHORT_SLOT_TIME; + } + + + //4 <6> Find Lowest Basic Rate Index for default TX Rate of MMPDU + rateGetLowestRateIndexFromRateSet(prBssInfo->u2BSSBasicRateSet, &ucLowestBasicRateIndex); + + prBssInfo->ucHwDefaultFixedRateCode = + aucRateIndex2RateCode[PREAMBLE_DEFAULT_LONG_NONE][ucLowestBasicRateIndex]; + + + //4 <7> Fill the EDCA + + prACQueParms = prBssInfo->arACQueParmsForBcast; + + for(eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++){ + + prACQueParms[eAci].fgIsACMSet = FALSE; + prACQueParms[eAci].u2Aifsn = auAifsForBcast[eAci]; + prACQueParms[eAci].u2CWmin = BIT(auCWminLog2ForBcast[eAci])-1; + prACQueParms[eAci].u2CWmax = BIT(auCWmaxLog2ForBcast[eAci])-1; + prACQueParms[eAci].u2TxopLimit = auTxopForBcast[eAci]; + + prBssInfo->aucCWminLog2ForBcast[eAci] = auCWminLog2ForBcast[eAci] ; /* used to send WMM IE */ + prBssInfo->aucCWmaxLog2ForBcast[eAci] = auCWmaxLog2ForBcast[eAci] ; + + DBGLOG(BSS, INFO, ("Bcast: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", + eAci,prACQueParms[eAci].fgIsACMSet , + prACQueParms[eAci].u2Aifsn, + prACQueParms[eAci].u2CWmin, + prACQueParms[eAci].u2CWmax, + prACQueParms[eAci].u2TxopLimit)); + + } + + prACQueParms = prBssInfo->arACQueParms; + + for(eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++){ + + prACQueParms[eAci].fgIsACMSet = FALSE; + prACQueParms[eAci].u2Aifsn = auAifs[eAci]; + prACQueParms[eAci].u2CWmin = BIT(auCWminLog2[eAci])-1; + prACQueParms[eAci].u2CWmax = BIT(auCWmaxLog2[eAci])-1; + prACQueParms[eAci].u2TxopLimit = auTxop[eAci]; + + DBGLOG(BSS, INFO, ("eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", + eAci,prACQueParms[eAci].fgIsACMSet , + prACQueParms[eAci].u2Aifsn, + prACQueParms[eAci].u2CWmin, + prACQueParms[eAci].u2CWmax, + prACQueParms[eAci].u2TxopLimit)); + } + + /* Note: Caller should update the EDCA setting to HW by nicQmUpdateWmmParms() it there is no AIS network */ + /* Note: In E2, only 4 HW queues. The the Edca parameters should be folow by AIS network */ + /* Note: In E3, 8 HW queues. the Wmm parameters should be updated to right queues according to BSS */ + + + return; +} /* end of bssInitForAP() */ + +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* @brief Update DTIM Count +* +* @param[in] eNetTypeIndex Specify which network to update +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +bssUpdateDTIMCount ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex + ) +{ + P_BSS_INFO_T prBssInfo; + + + ASSERT(eNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); + + if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + + // Setup DTIM Count for next TBTT. + if (prBssInfo->ucDTIMCount > 0) { + prBssInfo->ucDTIMCount--; + } + else { + + ASSERT(prBssInfo->ucDTIMPeriod > 0); + + prBssInfo->ucDTIMCount = prBssInfo->ucDTIMPeriod - 1; + } + } + + return; +} /* end of bssUpdateDTIMIE() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to set the Virtual Bitmap in TIM Information Elements +* +* @param[in] prBssInfo Pointer to the BSS_INFO_T. +* @param[in] u2AssocId The association id to set in Virtual Bitmap. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +bssSetTIMBitmap ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN UINT_16 u2AssocId + ) +{ + + ASSERT(prBssInfo); + + if (prBssInfo->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo; + + + prP2pSpecificBssInfo = &(prAdapter->rWifiVar.rP2pSpecificBssInfo); + + /* Use Association ID == 0 for BMCAST indication */ + if (u2AssocId == 0) { + + prP2pSpecificBssInfo->ucBitmapCtrl |= (UINT_8)BIT(0); + } + else { + PUINT_8 pucPartialVirtualBitmap; + UINT_8 ucBitmapToSet; + + + pucPartialVirtualBitmap = &prP2pSpecificBssInfo->aucPartialVirtualBitmap[(u2AssocId >> 3)]; // (u2AssocId / 8) + ucBitmapToSet = (UINT_8) BIT((u2AssocId % 8)); + + if (*pucPartialVirtualBitmap & ucBitmapToSet) { + /* The virtual bitmap has been set */ + return; + } + + *pucPartialVirtualBitmap |= ucBitmapToSet; + + // Update u2SmallestAID and u2LargestAID + if ((u2AssocId < prP2pSpecificBssInfo->u2SmallestAID) || + (prP2pSpecificBssInfo->u2SmallestAID == 0)) { + prP2pSpecificBssInfo->u2SmallestAID = u2AssocId; + } + + if ((u2AssocId > prP2pSpecificBssInfo->u2LargestAID) || + (prP2pSpecificBssInfo->u2LargestAID == 0)) { + prP2pSpecificBssInfo->u2LargestAID = u2AssocId; + } + } + } + + return; +} /* end of bssSetTIMBitmap() */ +#endif + +#endif /* CFG_SUPPORT_AAA */ + + +VOID +bssCreateStaRecFromAuth ( + IN P_ADAPTER_T prAdapter + ) +{ + +} + + +VOID +bssUpdateStaRecFromAssocReq ( + IN P_ADAPTER_T prAdapter + ) +{ + +} + +#if CFG_ENABLE_WIFI_DIRECT + +/*link function to p2p module for txBcnIETable*/ +UINT_32 +linkToP2pCalculateP2P_IELenForBeacon ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec + ) +{ + if (eNetTypeIndex != NETWORK_TYPE_P2P_INDEX || + prAdapter->fgIsP2PRegistered == FALSE) { + return 0; + } + +#if 1 + + if (prAdapter->rP2pFuncLkr.prP2pFuncIsApMode) { + if (prAdapter->rP2pFuncLkr.prP2pFuncIsApMode(prAdapter->rWifiVar.prP2pFsmInfo)) { + return 0; + } + + } + + + if (prAdapter->rP2pFuncLkr.prP2pCalculateP2p_IELenForBeacon) { + return prAdapter->rP2pFuncLkr.prP2pCalculateP2p_IELenForBeacon( + prAdapter, + eNetTypeIndex, + prStaRec + ); + } else { + ASSERT(0); + } +#endif + return 0; +} + +VOID +linkToP2pGenerateP2P_IEForBeacon ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ) +{ + if (prMsduInfo->ucNetworkType != NETWORK_TYPE_P2P_INDEX || + prAdapter->fgIsP2PRegistered == FALSE) { + return; + } +#if 1 + + if (prAdapter->rP2pFuncLkr.prP2pFuncIsApMode) { + if (prAdapter->rP2pFuncLkr.prP2pFuncIsApMode(prAdapter->rWifiVar.prP2pFsmInfo)) { + return; + } + + } + + + if(prAdapter->rP2pFuncLkr.prP2pGenerateP2p_IEForBeacon) { + prAdapter->rP2pFuncLkr.prP2pGenerateP2p_IEForBeacon( + prAdapter, + prMsduInfo + ); + } else { + ASSERT(0); + } +#endif + return; +} + +/*link function to p2p module for txAssocReqIETable*/ +UINT_32 +linkToP2pCalculateP2P_IELenForAssocReq ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec + ) +{ + if (eNetTypeIndex != NETWORK_TYPE_P2P_INDEX || + prAdapter->fgIsP2PRegistered == FALSE) { + return 0; + } +#if 0 + if(prAdapter->rP2pFuncLkr.prP2pCalculateP2p_IELenForAssocReq) { + return prAdapter->rP2pFuncLkr.prP2pCalculateP2p_IELenForAssocReq( + prAdapter, + eNetTypeIndex, + prStaRec + ); + } else { + ASSERT(0); + } +#endif + return 0; +} /* linkToP2pCalculateP2P_IELenForAssocReq */ + +/*link function to p2p module for txAssocReqIETable*/ +UINT_32 +linkToP2pCalculateP2P_IELenForAssocRsp ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec + ) +{ + if (eNetTypeIndex != NETWORK_TYPE_P2P_INDEX || + prAdapter->fgIsP2PRegistered == FALSE) { + return 0; + } +#if 1 + if(prAdapter->rP2pFuncLkr.prP2pCalculateP2p_IELenForAssocRsp) { + return prAdapter->rP2pFuncLkr.prP2pCalculateP2p_IELenForAssocRsp( + prAdapter, + eNetTypeIndex, + prStaRec + ); + } else { + ASSERT(0); + } +#endif + return 0; +} /* linkToP2pCalculateP2P_IELenForAssocRsp */ + + +VOID +linkToP2pGenerateP2P_IEForAssocReq ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ) +{ + if (prMsduInfo->ucNetworkType != NETWORK_TYPE_P2P_INDEX || + prAdapter->fgIsP2PRegistered == FALSE) { + return; + } +#if 0 + if(prAdapter->rP2pFuncLkr.prP2pGenerateP2p_IEForAssocReq) { + prAdapter->rP2pFuncLkr.prP2pGenerateP2p_IEForAssocReq( + prAdapter, + prMsduInfo + ); + } else { + ASSERT(0); + } +#endif + return; +} /* linkToP2pGenerateP2P_IEForAssocReq */ + + +VOID +linkToP2pGenerateP2P_IEForAssocRsp ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ) +{ + if (prMsduInfo->ucNetworkType != NETWORK_TYPE_P2P_INDEX || + prAdapter->fgIsP2PRegistered == FALSE) { + return; + } +#if 1 + if(prAdapter->rP2pFuncLkr.prP2pGenerateP2p_IEForAssocRsp) { + prAdapter->rP2pFuncLkr.prP2pGenerateP2p_IEForAssocRsp( + prAdapter, + prMsduInfo + ); + } else { + ASSERT(0); + } +#endif + return; +} /* linkToP2pGenerateP2P_IEForAssocRsp */ + + +UINT_32 +linkToP2pCalculateWSC_IELenForBeacon ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec + ) +{ + if (eNetTypeIndex != NETWORK_TYPE_P2P_INDEX || + prAdapter->fgIsP2PRegistered == FALSE) { + return 0; + } +#if 1 + if (prAdapter->rP2pFuncLkr.prP2pCalculateWSC_IELenForBeacon) { + return prAdapter->rP2pFuncLkr.prP2pCalculateWSC_IELenForBeacon( + prAdapter, + eNetTypeIndex, + prStaRec + ); + } + else { + ASSERT(0); + } +#endif + return 0; +} + +VOID +linkToP2pGenerateWSC_IEForBeacon( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ) +{ + if (prMsduInfo->ucNetworkType != NETWORK_TYPE_P2P_INDEX || + prAdapter->fgIsP2PRegistered == FALSE) { + return; + } +#if 1 + if (prAdapter->rP2pFuncLkr.prP2pGenerateWSC_IEForBeacon) { + prAdapter->rP2pFuncLkr.prP2pGenerateWSC_IEForBeacon( + prAdapter, + prMsduInfo + ); + } + else { + ASSERT(0); + } +#endif + return; +} + +UINT_32 +linkToP2pCalculateWSC_IELenForProbeRsp ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec + ) +{ + if (eNetTypeIndex != NETWORK_TYPE_P2P_INDEX || + prAdapter->fgIsP2PRegistered == FALSE) { + return 0; + } + +#if 0 + if(prAdapter->rP2pFuncLkr.prP2pCalculateWSC_IELenForProbeRsp) { + return prAdapter->rP2pFuncLkr.prP2pCalculateWSC_IELenForProbeRsp( + prAdapter, + eNetTypeIndex, + prStaRec + ); + } else { + ASSERT(0); + } +#endif + return 0; +} + +VOID +linkToP2pGenerateWSC_IEForProbeRsp( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ) +{ + if (prMsduInfo->ucNetworkType != NETWORK_TYPE_P2P_INDEX || + prAdapter->fgIsP2PRegistered == FALSE) { + return; + } + + +#if 0 + if(prAdapter->rP2pFuncLkr.prP2pGenerateWSC_IEForProbeRsp) { + prAdapter->rP2pFuncLkr.prP2pGenerateWSC_IEForProbeRsp( + prAdapter, + prMsduInfo + ); + } else { + ASSERT(0); + } +#endif + + return; +} + + +EXPORT_SYMBOL(prTxProbRspIETableWIP2P); + +#endif + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/cnm.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/cnm.c new file mode 100755 index 000000000000..e6e6354846ce --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/cnm.c @@ -0,0 +1,814 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/mgmt/cnm.c#1 $ +*/ + +/*! \file "cnm.c" + \brief Module of Concurrent Network Management + + Module of Concurrent Network Management +*/ + +/******************************************************************************* +* Copyright (c) 2010 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: cnm.c $ + * + * 11 15 2011 cm.chang + * NULL + * Fix possible wrong message when P2P is unregistered + * + * 11 14 2011 yuche.tsai + * [WCXRP00001107] [Volunteer Patch][Driver] Large Network Type index assert in FW issue. + * Large Network Type index assert. + * Fix NULL prDev issue. + * + * 11 10 2011 cm.chang + * NULL + * Modify debug message for XLOG + * + * 11 08 2011 cm.chang + * NULL + * Add RLM and CNM debug message for XLOG + * + * 11 01 2011 cm.chang + * [WCXRP00001077] [All Wi-Fi][Driver] Fix wrong preferred channel for AP and BOW + * Only check AIS channel for P2P and BOW + * + * 10 25 2011 cm.chang + * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode + * . + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 08 17 2011 cm.chang + * [WCXRP00000937] [MT6620 Wi-Fi][Driver][FW] cnm.c line #848 assert when doing monkey test + * Print out net type index for ch request/abourt message + * + * 06 23 2011 cp.wu + * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module + * follow-ups for frequency-shifted WAPI AP support + * + * 06 01 2011 cm.chang + * [WCXRP00000756] [MT6620 Wi-Fi][Driver] 1. AIS follow channel of BOW 2. Provide legal channel function + * Limit AIS channel same with BOW when BOW is active + * + * 04 12 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 10 2011 cm.chang + * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module + * Check if P2P network index is Tethering AP + * + * 03 10 2011 cm.chang + * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module + * Add some functions to let AIS/Tethering or AIS/BOW be the same channel + * + * 02 17 2011 cm.chang + * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module + * When P2P registried, invoke BOW deactivate function + * + * 01 12 2011 cm.chang + * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module + * Provide function to decide if BSS can be activated or not + * + * 12 07 2010 cm.chang + * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk + * 1. BSSINFO include RLM parameter + * 2. free all sta records when network is disconnected + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 11 08 2010 cm.chang + * [WCXRP00000169] [MT6620 Wi-Fi][Driver][FW] Remove unused CNM recover message ID + * Remove CNM channel reover message ID + * + * 10 13 2010 cm.chang + * [WCXRP00000094] [MT6620 Wi-Fi][Driver] Connect to 2.4GHz AP, Driver crash. + * Add exception handle when cmd buffer is not available + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 07 19 2010 wh.su + * + * update for security supporting. + * + * 07 19 2010 cm.chang + * + * Set RLM parameters and enable CNM channel manager + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Rename MID_MNY_CNM_CH_RELEASE to MID_MNY_CNM_CH_ABORT + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Fix wrong message ID for channel grant to requester + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Modify CNM message handler for new flow + * + * 06 07 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Set 20/40M bandwidth of AP HT OP before association process + * + * 05 31 2010 yarco.yang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add RX TSF Log Feature and ADDBA Rsp with DECLINE handling + * + * 05 21 2010 yarco.yang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support TCP/UDP/IP Checksum offload feature + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 05 05 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add a new function to send abort message + * + * 04 27 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * BMC mac address shall be ignored in basic config command + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW + * + * 04 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support change of MAC address by host command + * + * 04 16 2010 wh.su + * [BORA00000680][MT6620] Support the statistic for Microsoft os query + * adding the wpa-none for ibss beacon. + * + * 04 07 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Fix bug for OBSS scan + * + * 03 30 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support 2.4G OBSS scan + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 03 10 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * + * * * * * * * * * * Add Channel Manager for arbitration of JOIN and SCAN Req + * + * 02 25 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * use the Rx0 dor event indicate. + * + * 02 08 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support partial part about cmd basic configuration + * + * Dec 10 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Remove conditional compiling FPGA_V5 + * + * Nov 18 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add function cnmFsmEventInit() + * + * Nov 2 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to initialize variables in CNM_INFO_T. +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +cnmInit ( + P_ADAPTER_T prAdapter + ) +{ + return; +} /* end of cnmInit() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to initialize variables in CNM_INFO_T. +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +cnmUninit ( + P_ADAPTER_T prAdapter + ) +{ + return; +} /* end of cnmUninit() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Before handle the message from other module, it need to obtain +* the Channel privilege from Channel Manager +* +* @param[in] prMsgHdr The message need to be handled. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +cnmChMngrRequestPrivilege ( + P_ADAPTER_T prAdapter, + P_MSG_HDR_T prMsgHdr + ) +{ + P_MSG_CH_REQ_T prMsgChReq; + P_CMD_CH_PRIVILEGE_T prCmdBody; + WLAN_STATUS rStatus; + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + + prMsgChReq = (P_MSG_CH_REQ_T) prMsgHdr; + + prCmdBody = (P_CMD_CH_PRIVILEGE_T) + cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_CH_PRIVILEGE_T)); + ASSERT(prCmdBody); + + /* To do: exception handle */ + if (!prCmdBody) { + DBGLOG(CNM, ERROR, ("ChReq: fail to get buf (net=%d, token=%d)\n", + prMsgChReq->ucNetTypeIndex, prMsgChReq->ucTokenID)); + + cnmMemFree(prAdapter, prMsgHdr); + return; + } + + DBGLOG(CNM, INFO, ("ChReq net=%d token=%d b=%d c=%d s=%d\n", + prMsgChReq->ucNetTypeIndex, prMsgChReq->ucTokenID, + prMsgChReq->eRfBand, prMsgChReq->ucPrimaryChannel, + prMsgChReq->eRfSco)); + + prCmdBody->ucNetTypeIndex = prMsgChReq->ucNetTypeIndex; + prCmdBody->ucTokenID = prMsgChReq->ucTokenID; + prCmdBody->ucAction = CMD_CH_ACTION_REQ; /* Request */ + prCmdBody->ucPrimaryChannel = prMsgChReq->ucPrimaryChannel; + prCmdBody->ucRfSco = (UINT_8) prMsgChReq->eRfSco; + prCmdBody->ucRfBand = (UINT_8) prMsgChReq->eRfBand; + prCmdBody->ucReqType = (UINT_8) prMsgChReq->eReqType; + prCmdBody->ucReserved = 0; + prCmdBody->u4MaxInterval= prMsgChReq->u4MaxInterval; + COPY_MAC_ADDR(prCmdBody->aucBSSID, prMsgChReq->aucBSSID); + + ASSERT(prCmdBody->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + /* For monkey testing 20110901 */ + if (prCmdBody->ucNetTypeIndex >= NETWORK_TYPE_INDEX_NUM) { + DBGLOG(CNM, ERROR, ("CNM: ChReq with wrong netIdx=%d\n\n", + prCmdBody->ucNetTypeIndex)); + } + + rStatus = wlanSendSetQueryCmd ( + prAdapter, /* prAdapter */ + CMD_ID_CH_PRIVILEGE, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_CH_PRIVILEGE_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdBody, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + ASSERT(rStatus == WLAN_STATUS_PENDING); + + cnmMemFree(prAdapter, prCmdBody); + cnmMemFree(prAdapter, prMsgHdr); + + return; +} /* end of cnmChMngrRequestPrivilege() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Before deliver the message to other module, it need to release +* the Channel privilege to Channel Manager. +* +* @param[in] prMsgHdr The message need to be delivered +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +cnmChMngrAbortPrivilege ( + P_ADAPTER_T prAdapter, + P_MSG_HDR_T prMsgHdr + ) +{ + P_MSG_CH_ABORT_T prMsgChAbort; + P_CMD_CH_PRIVILEGE_T prCmdBody; + WLAN_STATUS rStatus; + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + + prMsgChAbort = (P_MSG_CH_ABORT_T) prMsgHdr; + + prCmdBody = (P_CMD_CH_PRIVILEGE_T) + cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_CH_PRIVILEGE_T)); + ASSERT(prCmdBody); + + /* To do: exception handle */ + if (!prCmdBody) { + DBGLOG(CNM, ERROR, ("ChAbort: fail to get buf (net=%d, token=%d)\n", + prMsgChAbort->ucNetTypeIndex, prMsgChAbort->ucTokenID)); + + cnmMemFree(prAdapter, prMsgHdr); + return; + } + + DBGLOG(CNM, INFO, ("ChAbort net=%d token=%d\n", + prMsgChAbort->ucNetTypeIndex, prMsgChAbort->ucTokenID)); + + prCmdBody->ucNetTypeIndex = prMsgChAbort->ucNetTypeIndex; + prCmdBody->ucTokenID = prMsgChAbort->ucTokenID; + prCmdBody->ucAction = CMD_CH_ACTION_ABORT; /* Abort */ + + ASSERT(prCmdBody->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + /* For monkey testing 20110901 */ + if (prCmdBody->ucNetTypeIndex >= NETWORK_TYPE_INDEX_NUM) { + DBGLOG(CNM, ERROR, ("CNM: ChAbort with wrong netIdx=%d\n\n", + prCmdBody->ucNetTypeIndex)); + } + + rStatus = wlanSendSetQueryCmd ( + prAdapter, /* prAdapter */ + CMD_ID_CH_PRIVILEGE, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_CH_PRIVILEGE_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdBody, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + ASSERT(rStatus == WLAN_STATUS_PENDING); + + cnmMemFree(prAdapter, prCmdBody); + cnmMemFree(prAdapter, prMsgHdr); + + return; +} /* end of cnmChMngrAbortPrivilege() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +cnmChMngrHandleChEvent ( + P_ADAPTER_T prAdapter, + P_WIFI_EVENT_T prEvent + ) +{ + P_EVENT_CH_PRIVILEGE_T prEventBody; + P_MSG_CH_GRANT_T prChResp; + + ASSERT(prAdapter); + ASSERT(prEvent); + + prEventBody = (P_EVENT_CH_PRIVILEGE_T) (prEvent->aucBuffer); + prChResp = (P_MSG_CH_GRANT_T) + cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_GRANT_T)); + ASSERT(prChResp); + + /* To do: exception handle */ + if (!prChResp) { + DBGLOG(CNM, ERROR, ("ChGrant: fail to get buf (net=%d, token=%d)\n", + prEventBody->ucNetTypeIndex, prEventBody->ucTokenID)); + + return; + } + + DBGLOG(CNM, INFO, ("ChGrant net=%d token=%d ch=%d sco=%d\n", + prEventBody->ucNetTypeIndex, prEventBody->ucTokenID, + prEventBody->ucPrimaryChannel, prEventBody->ucRfSco)); + + ASSERT(prEventBody->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + ASSERT(prEventBody->ucStatus == EVENT_CH_STATUS_GRANT); + + /* Decide message ID based on network and response status */ + if (prEventBody->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { + prChResp->rMsgHdr.eMsgId = MID_CNM_AIS_CH_GRANT; + } +#if CFG_ENABLE_WIFI_DIRECT + else if ((prAdapter->fgIsP2PRegistered) && + (prEventBody->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX)) { + prChResp->rMsgHdr.eMsgId = MID_CNM_P2P_CH_GRANT; + } +#endif +#if CFG_ENABLE_BT_OVER_WIFI + else if (prEventBody->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) { + prChResp->rMsgHdr.eMsgId = MID_CNM_BOW_CH_GRANT; + } +#endif + else { + cnmMemFree(prAdapter, prChResp); + return; + } + + prChResp->ucNetTypeIndex = prEventBody->ucNetTypeIndex; + prChResp->ucTokenID = prEventBody->ucTokenID; + prChResp->ucPrimaryChannel = prEventBody->ucPrimaryChannel; + prChResp->eRfSco = (ENUM_CHNL_EXT_T) prEventBody->ucRfSco; + prChResp->eRfBand = (ENUM_BAND_T) prEventBody->ucRfBand; + prChResp->eReqType = (ENUM_CH_REQ_TYPE_T) prEventBody->ucReqType; + prChResp->u4GrantInterval = prEventBody->u4GrantInterval; + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prChResp, + MSG_SEND_METHOD_BUF); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is invoked for P2P or BOW networks +* +* @param (none) +* +* @return TRUE: suggest to adopt the returned preferred channel +* FALSE: No suggestion. Caller should adopt its preference +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +cnmPreferredChannel ( + P_ADAPTER_T prAdapter, + P_ENUM_BAND_T prBand, + PUINT_8 pucPrimaryChannel, + P_ENUM_CHNL_EXT_T prBssSCO + ) +{ + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + ASSERT(prBand); + ASSERT(pucPrimaryChannel); + ASSERT(prBssSCO); + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; + + if (RLM_NET_PARAM_VALID(prBssInfo)) { + *prBand = prBssInfo->eBand; + *pucPrimaryChannel = prBssInfo->ucPrimaryChannel; + *prBssSCO = prBssInfo->eBssSCO; + + return TRUE; + } + + return FALSE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param (none) +* +* @return TRUE: available channel is limited to return value +* FALSE: no limited +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +cnmAisInfraChannelFixed ( + P_ADAPTER_T prAdapter, + P_ENUM_BAND_T prBand, + PUINT_8 pucPrimaryChannel + ) +{ +#if CFG_ENABLE_WIFI_DIRECT ||(CFG_ENABLE_BT_OVER_WIFI && CFG_BOW_LIMIT_AIS_CHNL) + P_BSS_INFO_T prBssInfo; +#endif + +#if CFG_ENABLE_WIFI_DIRECT + if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX) && + prAdapter->rP2pFuncLkr.prP2pFuncIsApMode && + prAdapter->rP2pFuncLkr.prP2pFuncIsApMode( + prAdapter->rWifiVar.prP2pFsmInfo)) { + + ASSERT(prAdapter->fgIsP2PRegistered); + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; + + *prBand = prBssInfo->eBand; + *pucPrimaryChannel = prBssInfo->ucPrimaryChannel; + + return TRUE; + } +#endif + +#if CFG_ENABLE_BT_OVER_WIFI && CFG_BOW_LIMIT_AIS_CHNL + if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX)) { + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]; + + *prBand = prBssInfo->eBand; + *pucPrimaryChannel = prBssInfo->ucPrimaryChannel; + + return TRUE; + } +#endif + + return FALSE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +cnmAisInfraConnectNotify ( + P_ADAPTER_T prAdapter + ) +{ +#if CFG_ENABLE_BT_OVER_WIFI + P_BSS_INFO_T prAisBssInfo, prBowBssInfo; + + prAisBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; + prBowBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]; + + if (RLM_NET_PARAM_VALID(prAisBssInfo) && RLM_NET_PARAM_VALID(prBowBssInfo)){ + if (prAisBssInfo->eBand != prBowBssInfo->eBand || + prAisBssInfo->ucPrimaryChannel != prBowBssInfo->ucPrimaryChannel) { + + /* Notify BOW to do deactivation */ + bowNotifyAllLinkDisconnected(prAdapter); + } + } +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param (none) +* +* @return TRUE: permitted +* FALSE: Not permitted +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +cnmAisIbssIsPermitted ( + P_ADAPTER_T prAdapter + ) +{ +#if CFG_ENABLE_WIFI_DIRECT + if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX)) { + return FALSE; + } +#endif + +#if CFG_ENABLE_BT_OVER_WIFI + if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX)) { + return FALSE; + } +#endif + + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param (none) +* +* @return TRUE: permitted +* FALSE: Not permitted +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +cnmP2PIsPermitted ( + P_ADAPTER_T prAdapter + ) +{ + P_BSS_INFO_T prBssInfo; + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; + + if (IS_BSS_ACTIVE(prBssInfo) && + prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { + return FALSE; + } + +#if CFG_ENABLE_BT_OVER_WIFI + if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX)) { + /* Notify BOW to do deactivation */ + bowNotifyAllLinkDisconnected(prAdapter); + } +#endif + + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param (none) +* +* @return TRUE: permitted +* FALSE: Not permitted +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +cnmBowIsPermitted ( + P_ADAPTER_T prAdapter + ) +{ + P_BSS_INFO_T prBssInfo; + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; + + if (IS_BSS_ACTIVE(prBssInfo) && + prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { + return FALSE; + } + +#if CFG_ENABLE_WIFI_DIRECT + if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX)) { + return FALSE; + } +#endif + + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param (none) +* +* @return TRUE: permitted +* FALSE: Not permitted +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +cnmBss40mBwPermitted ( + P_ADAPTER_T prAdapter, + ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx + ) +{ + P_BSS_INFO_T prBssInfo; + UINT_8 i; + + /* Note: To support real-time decision instead of current activated-time, + * the STA roaming case shall be considered about synchronization + * problem. Another variable fgAssoc40mBwAllowed is added to + * represent HT capability when association + */ + for (i = 0; i < NETWORK_TYPE_INDEX_NUM; i++) { + if (i != (UINT_8) eNetTypeIdx) { + prBssInfo = &prAdapter->rWifiVar.arBssInfo[i]; + + if (IS_BSS_ACTIVE(prBssInfo) && (prBssInfo->fg40mBwAllowed || + prBssInfo->fgAssoc40mBwAllowed)) { + return FALSE; + } + } + } + + return TRUE; +} + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/cnm_mem.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/cnm_mem.c new file mode 100755 index 000000000000..67e1652c5584 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/cnm_mem.c @@ -0,0 +1,1339 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/mgmt/cnm_mem.c#2 $ +*/ + +/*! \file "cnm_mem.c" + \brief This file contain the management function of packet buffers and + generic memory alloc/free functioin for mailbox message. + + A data packet has a fixed size of buffer, but a management + packet can be equipped with a variable size of buffer. +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: cnm_mem.c $ + * + * 01 17 2012 wh.su + * [WCXRP00001173] [MT6620 Wi-Fi][Driver] Adding the ICS Tethering WPA2-PSK supporting + * Adding the related code which support beacon can reflect the security setting open or WPA2-PSK, WPA-PSK not yet + * Adn support the indicate the assoc request ie at New STA CMD, needed kernel patch. + * + * 11 17 2011 tsaiyuan.hsu + * [WCXRP00001115] [MT6620 Wi-Fi][DRV] avoid deactivating staRec when changing state 3 to 3. + * initialize fgNeedResp. + * + * 11 17 2011 tsaiyuan.hsu + * [WCXRP00001115] [MT6620 Wi-Fi][DRV] avoid deactivating staRec when changing state 3 to 3. + * avoid deactivating staRec when changing state from 3 to 3. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 02 01 2011 cm.chang + * [WCXRP00000415] [MT6620 Wi-Fi][Driver] Check if any memory leakage happens when uninitializing in DGB mode + * . + * + * 01 26 2011 cm.chang + * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument + * Allocate system RAM if fixed message or mgmt buffer is not available + * + * 01 26 2011 cm.chang + * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument + * . + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. + * + * 12 13 2010 cp.wu + * [WCXRP00000260] [MT6620 Wi-Fi][Driver][Firmware] Create V1.1 branch for both firmware and driver + * create branch for Wi-Fi driver v1.1 + * + * 12 07 2010 cm.chang + * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk + * 1. BSSINFO include RLM parameter + * 2. free all sta records when network is disconnected + * + * 11 29 2010 cm.chang + * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC for initial TX rate selection of auto-rate algorithm + * Sync RCPI of STA_REC to FW as reference of initial TX rate + * + * 11 25 2010 yuche.tsai + * NULL + * Update SLT Function for QoS Support and not be affected by fixed rate function. + * + * 10 18 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS associated + * 1. remove redundant variables in STA_REC structure + * 2. add STA-REC uninitialization routine for clearing pending events + * + * 10 13 2010 cm.chang + * [WCXRP00000094] [MT6620 Wi-Fi][Driver] Connect to 2.4GHz AP, Driver crash. + * Add exception handle when cmd buffer is not available + * + * 10 12 2010 cp.wu + * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test + * add HT (802.11n) fixed rate support. + * + * 10 08 2010 cp.wu + * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test + * adding fixed rate support for distance test. (from registry setting) + * + * 09 24 2010 wh.su + * NULL + * [WCXRP00005002][MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning. + * + * 09 21 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS associated + * Do a complete reset with STA-REC null checking for RF test re-entry + * + * 09 16 2010 cm.chang + * NULL + * Change conditional compiling options for BOW + * + * 09 10 2010 cm.chang + * NULL + * Always update Beacon content if FW sync OBSS info + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 08 23 2010 chinghwa.yu + * NULL + * Update for BOW. + * + * 08 20 2010 cm.chang + * NULL + * Migrate RLM code to host from FW + * + * 08 19 2010 wh.su + * NULL + * adding the tx pkt call back handle for countermeasure. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Check draft RLM code for HT cap + * + * 07 07 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Support state of STA record change from 1 to 1 + * + * 07 05 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Fix correct structure size in cnmStaSendDeactivateCmd() + * + * 07 05 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) ignore RSN checking when RSN is not turned on. + * 2) set STA-REC deactivation callback as NULL + * 3) add variable initialization API based on PHY configuration + * + * 07 02 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * spin lock target revised + * + * 07 02 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * change inner loop index from i to k. + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Support sync command of STA_REC + * + * 06 23 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Merge g_arStaRec[] into adapter->arStaRec[] + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 05 31 2010 yarco.yang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add RX TSF Log Feature and ADDBA Rsp with DECLINE handling + * + * 05 28 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support checking of duplicated buffer free + * + * 05 28 2010 wh.su + * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing + * fixed the ad-hoc wpa-none send non-encrypted frame issue. + * + * 05 28 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Move define of STA_REC_NUM to config.h and rename to CFG_STA_REC_NUM + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 04 28 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * Modified some MQM-related data structures (SN counter, TX/RX BA table) + * + * 04 27 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * Added new TX/RX BA tables in STA_REC + * + * 04 27 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * Notify MQM, TXM, and RXM upon disconnection . + * + * 04 26 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * Call mqm, txm, rxm functions upon disconnection + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW + * + * 04 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * First draft code to support protection in AP mode + * + * 04 19 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * Add Beacon Timeout Support + * * * * * * * * * * and will send Null frame to diagnose connection + * + * 04 09 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * [BORA00000644] WiFi phase 4 integration + * * Added per-TID SN cache in STA_REC + * + * 04 07 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Different invoking order for WTBL entry of associated AP + * + * 03 29 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * move the wlan table alloc / free to change state function. + * + * 03 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support power control + * + * 03 03 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Initialize StaRec->arStaWaitQueue + * + * 03 03 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add debug message when no available pkt buffer + * + * 03 01 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Fixed STA_REC initialization bug: prStaRec->au2CachedSeqCtrl[k] + * + * 02 26 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Added fgIsWmmSupported in STA_RECORD_T. + * + * 02 26 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Added fgIsUapsdSupported in STA_RECORD_T + * + * 02 26 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * add support of Driver STA_RECORD_T activation + * + * 02 13 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Added arTspecTable in STA_REC for TSPEC management + * + * 02 12 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Enable mgmt buffer debug by default + * + * 02 12 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Added BUFFER_SOURCE_BCN + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * 01 11 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add Deauth and Disassoc Handler + * + * 01 08 2010 cp.wu + * [BORA00000368]Integrate HIF part into BORA + * 1) separate wifi_var_emu.c/.h from wifi_var.c/.h + * * * * * * * * * 2) eliminate HIF_EMULATION code sections appeared in wifi_var/cnm_mem + * * * * * * * * * 3) use cnmMemAlloc() instead to allocate SRAM buffer + * + * 12 25 2009 tehuang.liu + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Integrated modifications for 1st connection (mainly on FW modules MQM, TXM, and RXM) + * * * * * * * MQM: BA handling + * * * * * * * TXM: Macros updates + * * * * * * * RXM: Macros/Duplicate Removal updates + * + * 12 24 2009 yarco.yang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * 12 21 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support several data buffer banks. + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * .For new FPGA memory size + * + * Dec 9 2009 MTK02468 + * [BORA00000337] To check in codes for FPGA emulation + * Removed DBGPRINT + * + * Dec 9 2009 mtk02752 + * [BORA00000368] Integrate HIF part into BORA + * add cnmDataPktFree() for emulation loopback purpose + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix warning of null pointer + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add cnmGetStaRecByAddress() and add fgIsInUse flag in STA_RECORD_T + * + * Nov 23 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Assign ucBufferSource in function cnmMgtPktAlloc() + * + * Nov 23 2009 mtk02468 + * [BORA00000337] To check in codes for FPGA emulation + * Added packet redispatch function calls + * + * Nov 13 2009 mtk01084 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * enable packet re-usable in current emulation driver + * + * Nov 12 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * 1. Add new function cnmGetStaRecByIndex() + * 2. Rename STA_REC_T to STA_RECORD_T + * + * Nov 9 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Call cnmDataPktDispatch() in cnmPktFree() + * + * Nov 2 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Remove definition of pragma section code + * + * Oct 28 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * + * Oct 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix lint warning + * + * Oct 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix typo + * + * Oct 12 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * + * Oct 8 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static VOID +cnmStaRecHandleEventPkt ( + P_ADAPTER_T prAdapter, + P_CMD_INFO_T prCmdInfo, + PUINT_8 pucEventBuf + ); + +static VOID +cnmStaSendUpdateCmd ( + P_ADAPTER_T prAdapter, + P_STA_RECORD_T prStaRec, + BOOLEAN fgNeedResp + ); + +static VOID +cnmStaSendRemoveCmd ( + P_ADAPTER_T prAdapter, + P_STA_RECORD_T prStaRec + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +P_MSDU_INFO_T +cnmMgtPktAlloc ( + P_ADAPTER_T prAdapter, + UINT_32 u4Length + ) +{ + P_MSDU_INFO_T prMsduInfo; + P_QUE_T prQueList; + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + prQueList = &prAdapter->rTxCtrl.rFreeMsduInfoList; + + /* Get a free MSDU_INFO_T */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + QUEUE_REMOVE_HEAD(prQueList, prMsduInfo, P_MSDU_INFO_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + + if (prMsduInfo) { + prMsduInfo->prPacket = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, u4Length); + prMsduInfo->eSrc = TX_PACKET_MGMT; + + if (prMsduInfo->prPacket == NULL) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + QUEUE_INSERT_TAIL(prQueList, &prMsduInfo->rQueEntry); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + prMsduInfo = NULL; + } + } + +#if DBG + if (prMsduInfo == NULL) { + DBGLOG(MEM, WARN, ("\n")); + DBGLOG(MEM, WARN, ("MgtDesc#=%ld\n", prQueList->u4NumElem)); + +#if CFG_DBG_MGT_BUF + DBGLOG(MEM, WARN, ("rMgtBufInfo: alloc#=%ld, free#=%ld, null#=%ld\n", + prAdapter->rMgtBufInfo.u4AllocCount, + prAdapter->rMgtBufInfo.u4FreeCount, + prAdapter->rMgtBufInfo.u4AllocNullCount)); +#endif + + DBGLOG(MEM, WARN, ("\n")); + } +#endif + + return prMsduInfo; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +cnmMgtPktFree ( + P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo + ) +{ + P_QUE_T prQueList; + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prQueList = &prAdapter->rTxCtrl.rFreeMsduInfoList; + + ASSERT(prMsduInfo->prPacket); + if (prMsduInfo->prPacket) { + cnmMemFree(prAdapter, prMsduInfo->prPacket); + prMsduInfo->prPacket = NULL; + } + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + QUEUE_INSERT_TAIL(prQueList, &prMsduInfo->rQueEntry) + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is used to initial the MGMT/MSG memory pool. +* +* \param (none) +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +cnmMemInit ( + P_ADAPTER_T prAdapter + ) +{ + P_BUF_INFO_T prBufInfo; + + /* Initialize Management buffer pool */ + prBufInfo = &prAdapter->rMgtBufInfo; + kalMemZero(prBufInfo, sizeof(prAdapter->rMgtBufInfo)); + prBufInfo->pucBuf = prAdapter->pucMgtBufCached; + + /* Setup available memory blocks. 1 indicates FREE */ + prBufInfo->rFreeBlocksBitmap = + (BUF_BITMAP) BITS(0, MAX_NUM_OF_BUF_BLOCKS - 1); + + + /* Initialize Message buffer pool */ + prBufInfo = &prAdapter->rMsgBufInfo; + kalMemZero(prBufInfo, sizeof(prAdapter->rMsgBufInfo)); + prBufInfo->pucBuf = &prAdapter->aucMsgBuf[0]; + + /* Setup available memory blocks. 1 indicates FREE */ + prBufInfo->rFreeBlocksBitmap = + (BUF_BITMAP) BITS(0, MAX_NUM_OF_BUF_BLOCKS - 1); + + return; + +} /* end of cnmMemInit() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Allocate MGMT/MSG memory pool. +* +* \param[in] eRamType Target RAM type. +* TCM blk_sz= 16bytes, BUF blk_sz= 256bytes +* \param[in] u4Length Length of the buffer to allocate. +* +* \retval !NULL Pointer to the start address of allocated memory. +* \retval NULL Fail to allocat memory +*/ +/*----------------------------------------------------------------------------*/ +PVOID +cnmMemAlloc ( + IN P_ADAPTER_T prAdapter, + IN ENUM_RAM_TYPE_T eRamType, + IN UINT_32 u4Length + ) +{ + P_BUF_INFO_T prBufInfo; + BUF_BITMAP rRequiredBitmap; + UINT_32 u4BlockNum; + UINT_32 i, u4BlkSzInPower; + PVOID pvMemory; + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + ASSERT(u4Length); + + if (eRamType == RAM_TYPE_MSG && u4Length <= 256) { + prBufInfo = &prAdapter->rMsgBufInfo; + u4BlkSzInPower = MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2; + + u4Length += (MSG_BUF_BLOCK_SIZE - 1); + u4BlockNum = u4Length >> MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2; + + ASSERT(u4BlockNum <= MAX_NUM_OF_BUF_BLOCKS); + } + else { + eRamType = RAM_TYPE_BUF; + + prBufInfo = &prAdapter->rMgtBufInfo; + u4BlkSzInPower = MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2; + + u4Length += (MGT_BUF_BLOCK_SIZE - 1); + u4BlockNum = u4Length >> MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2; + + ASSERT(u4BlockNum <= MAX_NUM_OF_BUF_BLOCKS); + } + +#if CFG_DBG_MGT_BUF + prBufInfo->u4AllocCount++; +#endif + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, + eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); + + if ((u4BlockNum > 0) && (u4BlockNum <= MAX_NUM_OF_BUF_BLOCKS)) { + + /* Convert number of block into bit cluster */ + rRequiredBitmap = BITS(0, u4BlockNum-1); + + for (i = 0; i <= (MAX_NUM_OF_BUF_BLOCKS - u4BlockNum); i++) { + + /* Have available memory blocks */ + if ((prBufInfo->rFreeBlocksBitmap & rRequiredBitmap) + == rRequiredBitmap) { + + /* Clear corresponding bits of allocated memory blocks */ + prBufInfo->rFreeBlocksBitmap &= ~rRequiredBitmap; + + /* Store how many blocks be allocated */ + prBufInfo->aucAllocatedBlockNum[i] = (UINT_8) u4BlockNum; + + KAL_RELEASE_SPIN_LOCK(prAdapter, + eRamType == RAM_TYPE_MSG ? + SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); + + /* Return the start address of allocated memory */ + return (PVOID)(prBufInfo->pucBuf + (i << u4BlkSzInPower)); + + } + + rRequiredBitmap <<= 1; + } + } + +#ifdef LINUX + pvMemory = (PVOID)kalMemAlloc(u4Length, VIR_MEM_TYPE); +#else + pvMemory = (PVOID)NULL; +#endif + +#if CFG_DBG_MGT_BUF + prBufInfo->u4AllocNullCount++; + + if (pvMemory) { + prAdapter->u4MemAllocDynamicCount++; + } +#endif + + KAL_RELEASE_SPIN_LOCK(prAdapter, + eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); + + return pvMemory; + +} /* end of cnmMemAlloc() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Release memory to MGT/MSG memory pool. +* +* \param pucMemory Start address of previous allocated memory +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +cnmMemFree ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvMemory + ) +{ + P_BUF_INFO_T prBufInfo; + UINT_32 u4BlockIndex; + BUF_BITMAP rAllocatedBlocksBitmap; + ENUM_RAM_TYPE_T eRamType; + KAL_SPIN_LOCK_DECLARATION(); + + + ASSERT(prAdapter); + ASSERT(pvMemory); + if (!pvMemory) { + return; + } + + /* Judge it belongs to which RAM type */ + if ( ((UINT_32)pvMemory >= (UINT_32)&prAdapter->aucMsgBuf[0]) && + ((UINT_32)pvMemory <= (UINT_32)&prAdapter->aucMsgBuf[MSG_BUFFER_SIZE-1])) { + + prBufInfo = &prAdapter->rMsgBufInfo; + u4BlockIndex = ((UINT_32)pvMemory - (UINT_32)prBufInfo->pucBuf) + >> MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2; + ASSERT(u4BlockIndex < MAX_NUM_OF_BUF_BLOCKS); + eRamType = RAM_TYPE_MSG; + } + else if ( ((UINT_32)pvMemory >= (UINT_32)prAdapter->pucMgtBufCached) && + ((UINT_32)pvMemory <= ((UINT_32)prAdapter->pucMgtBufCached + MGT_BUFFER_SIZE -1))) { + prBufInfo = &prAdapter->rMgtBufInfo; + u4BlockIndex = ((UINT_32)pvMemory - (UINT_32)prBufInfo->pucBuf) + >> MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2; + ASSERT(u4BlockIndex < MAX_NUM_OF_BUF_BLOCKS); + eRamType = RAM_TYPE_BUF; + } + else { + #ifdef LINUX + /* For Linux, it is supported because size is not needed */ + kalMemFree(pvMemory, VIR_MEM_TYPE, 0); + #else + /* For Windows, it is not supported because of no size argument */ + ASSERT(0); + #endif + + #if CFG_DBG_MGT_BUF + prAdapter->u4MemFreeDynamicCount++; + #endif + return; + } + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, + eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); + +#if CFG_DBG_MGT_BUF + prBufInfo->u4FreeCount++; +#endif + + /* Convert number of block into bit cluster */ + ASSERT(prBufInfo->aucAllocatedBlockNum[u4BlockIndex] > 0); + + rAllocatedBlocksBitmap = + BITS(0, prBufInfo->aucAllocatedBlockNum[u4BlockIndex] - 1); + rAllocatedBlocksBitmap <<= u4BlockIndex; + + /* Clear saved block count for this memory segment */ + prBufInfo->aucAllocatedBlockNum[u4BlockIndex] = 0; + + /* Set corresponding bit of released memory block */ + prBufInfo->rFreeBlocksBitmap |= rAllocatedBlocksBitmap; + + KAL_RELEASE_SPIN_LOCK(prAdapter, + eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); + + return; + +} /* end of cnmMemFree() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +cnmStaRecInit ( + P_ADAPTER_T prAdapter + ) +{ + P_STA_RECORD_T prStaRec; + UINT_16 i; + + for (i = 0; i < CFG_STA_REC_NUM; i++) { + prStaRec = &prAdapter->arStaRec[i]; + + prStaRec->ucIndex = (UINT_8) i; + prStaRec->fgIsInUse = FALSE; + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +cnmStaRecUninit ( + IN P_ADAPTER_T prAdapter + ) +{ + P_STA_RECORD_T prStaRec; + UINT_16 i; + + for (i = 0; i < CFG_STA_REC_NUM; i++) { + prStaRec = &prAdapter->arStaRec[i]; + + if (prStaRec->fgIsInUse) { + cnmStaRecFree(prAdapter, prStaRec, FALSE); + } + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +P_STA_RECORD_T +cnmStaRecAlloc ( + P_ADAPTER_T prAdapter, + UINT_8 ucNetTypeIndex + ) +{ + P_STA_RECORD_T prStaRec; + UINT_16 i, k; + + ASSERT(prAdapter); + + for (i = 0; i < CFG_STA_REC_NUM; i++) { + prStaRec = &prAdapter->arStaRec[i]; + + if (!prStaRec->fgIsInUse) { + /*---- Initialize STA_REC_T here ----*/ + kalMemZero(prStaRec, sizeof(STA_RECORD_T)); + prStaRec->ucIndex = (UINT_8) i; + prStaRec->ucNetTypeIndex = ucNetTypeIndex; + prStaRec->fgIsInUse = TRUE; + + if (prStaRec->pucAssocReqIe) { + kalMemFree(prStaRec->pucAssocReqIe, VIR_MEM_TYPE, prStaRec->u2AssocReqIeLen); + prStaRec->pucAssocReqIe = NULL; + prStaRec->u2AssocReqIeLen = 0; + } + + /* Initialize the SN caches for duplicate detection */ + for (k = 0; k < TID_NUM + 1; k++) { + prStaRec->au2CachedSeqCtrl[k] = 0xFFFF; + } + + /* Initialize SW TX queues in STA_REC */ + for (k = 0; k < STA_WAIT_QUEUE_NUM; k++) { + LINK_INITIALIZE(&prStaRec->arStaWaitQueue[k]); + } + + /* Default enable TX/RX AMPDU */ + prStaRec->fgTxAmpduEn = TRUE; + prStaRec->fgRxAmpduEn = TRUE; + + for (k = 0; k < NUM_OF_PER_STA_TX_QUEUES; k++) { + QUEUE_INITIALIZE(&prStaRec->arTxQueue[k]); + } + + break; + } + } + + return (i < CFG_STA_REC_NUM) ? prStaRec : NULL; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +cnmStaRecFree ( + P_ADAPTER_T prAdapter, + P_STA_RECORD_T prStaRec, + BOOLEAN fgSyncToChip + ) +{ + ASSERT(prAdapter); + ASSERT(prStaRec); + + /* To do: free related resources, e.g. timers, buffers, etc */ + cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); + prStaRec->fgTransmitKeyExist = FALSE; + prStaRec->fgSetPwrMgtBit = FALSE; + + if (prStaRec->pucAssocReqIe) { + kalMemFree(prStaRec->pucAssocReqIe, VIR_MEM_TYPE, prStaRec->u2AssocReqIeLen); + prStaRec->pucAssocReqIe = NULL; + prStaRec->u2AssocReqIeLen = 0; + } + + qmDeactivateStaRec(prAdapter, prStaRec->ucIndex); + + if (fgSyncToChip) { + cnmStaSendRemoveCmd(prAdapter, prStaRec); + } + + prStaRec->fgIsInUse = FALSE; + + return; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +cnmStaFreeAllStaByNetType ( + P_ADAPTER_T prAdapter, + ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + BOOLEAN fgSyncToChip + ) +{ + P_STA_RECORD_T prStaRec; + UINT_16 i; + + for (i = 0; i < CFG_STA_REC_NUM; i++) { + prStaRec = (P_STA_RECORD_T) &prAdapter->arStaRec[i]; + + if (prStaRec->fgIsInUse && + prStaRec->ucNetTypeIndex == (UINT_8) eNetTypeIndex) { + + cnmStaRecFree(prAdapter, prStaRec, fgSyncToChip); + } + } /* end of for loop */ +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +P_STA_RECORD_T +cnmGetStaRecByIndex ( + P_ADAPTER_T prAdapter, + UINT_8 ucIndex + ) +{ + P_STA_RECORD_T prStaRec; + + ASSERT(prAdapter); + + prStaRec = (ucIndex < CFG_STA_REC_NUM) ? + &prAdapter->arStaRec[ucIndex] : NULL; + + if (prStaRec && prStaRec->fgIsInUse == FALSE) { + prStaRec = NULL; + } + + return prStaRec; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Get STA_RECORD_T by Peer MAC Address(Usually TA). +* +* @param[in] pucPeerMacAddr Given Peer MAC Address. +* +* @retval Pointer to STA_RECORD_T, if found. NULL, if not found +*/ +/*----------------------------------------------------------------------------*/ +P_STA_RECORD_T +cnmGetStaRecByAddress ( + P_ADAPTER_T prAdapter, + UINT_8 ucNetTypeIndex, + PUINT_8 pucPeerMacAddr + ) +{ + P_STA_RECORD_T prStaRec; + UINT_16 i; + + ASSERT(prAdapter); + ASSERT(pucPeerMacAddr); + + for (i = 0; i < CFG_STA_REC_NUM; i++) { + prStaRec = &prAdapter->arStaRec[i]; + + if (prStaRec->fgIsInUse && + prStaRec->ucNetTypeIndex == ucNetTypeIndex && + EQUAL_MAC_ADDR(prStaRec->aucMacAddr, pucPeerMacAddr)) { + break; + } + } + + return (i < CFG_STA_REC_NUM) ? prStaRec : NULL; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Reset the Status and Reason Code Field to 0 of all Station Records for +* the specified Network Type +* +* @param[in] eNetType Specify Network Type +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +cnmStaRecResetStatus ( + P_ADAPTER_T prAdapter, + ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex + ) +{ + cnmStaFreeAllStaByNetType(prAdapter, eNetTypeIndex, FALSE); + +#if 0 + P_STA_RECORD_T prStaRec; + UINT_16 i; + + ASSERT(prAdapter); + + for (i = 0; i < CFG_STA_REC_NUM; i++) { + prStaRec = &prAdapter->arStaRec[i]; + + if (prStaRec->fgIsInUse) { + if ((NETWORK_TYPE_AIS_INDEX == eNetTypeIndex) && + IS_STA_IN_AIS(prStaRec->eStaType)) { + + prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; + prStaRec->u2ReasonCode = REASON_CODE_RESERVED; + prStaRec->ucJoinFailureCount = 0; + prStaRec->fgTransmitKeyExist = FALSE; + + prStaRec->fgSetPwrMgtBit = FALSE; + } + + /* TODO(Kevin): For P2P and BOW */ + } + } + + return; +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will change the ucStaState of STA_RECORD_T and also do +* event indication to HOST to sync the STA_RECORD_T in driver. +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] u4NewState New STATE to change. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +cnmStaRecChangeState ( + P_ADAPTER_T prAdapter, + P_STA_RECORD_T prStaRec, + UINT_8 ucNewState + ) +{ + BOOLEAN fgNeedResp; + + ASSERT(prAdapter); + ASSERT(prStaRec); + ASSERT(prStaRec->fgIsInUse); + + /* Do nothing when following state transitions happen, + * other 6 conditions should be sync to FW, including 1-->1, 3-->3 + */ + if ((ucNewState == STA_STATE_2 && prStaRec->ucStaState != STA_STATE_3) || + (ucNewState == STA_STATE_1 && prStaRec->ucStaState == STA_STATE_2)) { + prStaRec->ucStaState = ucNewState; + return; + } + + fgNeedResp = FALSE; + if (ucNewState == STA_STATE_3) { + secFsmEventStart(prAdapter, prStaRec); + if (ucNewState != prStaRec->ucStaState) { + fgNeedResp = TRUE; + } + } + else { + if (ucNewState != prStaRec->ucStaState && + prStaRec->ucStaState == STA_STATE_3) { + qmDeactivateStaRec(prAdapter, prStaRec->ucIndex); + } + fgNeedResp = FALSE; + } + prStaRec->ucStaState = ucNewState; + + cnmStaSendUpdateCmd(prAdapter, prStaRec, fgNeedResp); + +#if CFG_ENABLE_WIFI_DIRECT + /* To do: Confirm if it is invoked here or other location, but it should + * be invoked after state sync of STA_REC + * Update system operation parameters for AP mode + */ + if (prAdapter->fgIsP2PRegistered && (IS_STA_IN_P2P(prStaRec))) { + P_BSS_INFO_T prBssInfo; + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; + + if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + if(prAdapter->rP2pFuncLkr.prRlmUpdateParamsForAp) { + prAdapter->rP2pFuncLkr.prRlmUpdateParamsForAp(prAdapter, prBssInfo, FALSE); + } else { + ASSERT(0); + } + } + } +#endif + return; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param[in] +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +static VOID +cnmStaRecHandleEventPkt ( + P_ADAPTER_T prAdapter, + P_CMD_INFO_T prCmdInfo, + PUINT_8 pucEventBuf + ) +{ + P_EVENT_ACTIVATE_STA_REC_T prEventContent; + P_STA_RECORD_T prStaRec; + + prEventContent = (P_EVENT_ACTIVATE_STA_REC_T) pucEventBuf; + prStaRec = cnmGetStaRecByIndex(prAdapter, prEventContent->ucStaRecIdx); + + if (prStaRec && prStaRec->ucStaState == STA_STATE_3 && + !kalMemCmp(&prStaRec->aucMacAddr[0], &prEventContent->aucMacAddr[0], + MAC_ADDR_LEN)) { + + qmActivateStaRec(prAdapter, prStaRec); + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param[in] +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +static VOID +cnmStaSendUpdateCmd ( + P_ADAPTER_T prAdapter, + P_STA_RECORD_T prStaRec, + BOOLEAN fgNeedResp + ) +{ + P_CMD_UPDATE_STA_RECORD_T prCmdContent; + WLAN_STATUS rStatus; + + ASSERT(prAdapter); + ASSERT(prStaRec); + ASSERT(prStaRec->fgIsInUse); + + /* To do: come out a mechanism to limit one STA_REC sync once for AP mode + * to avoid buffer empty case when many STAs are associated + * simultaneously. + */ + + /* To do: how to avoid 2 times of allocated memory. Use Stack? + * One is here, the other is in wlanSendQueryCmd() + */ + prCmdContent = cnmMemAlloc(prAdapter, + RAM_TYPE_BUF, sizeof(CMD_UPDATE_STA_RECORD_T)); + ASSERT(prCmdContent); + + /* To do: exception handle */ + if (!prCmdContent) { + return; + } + + prCmdContent->ucIndex = prStaRec->ucIndex; + prCmdContent->ucStaType = (UINT_8) prStaRec->eStaType; + kalMemCopy(&prCmdContent->aucMacAddr[0], &prStaRec->aucMacAddr[0], + MAC_ADDR_LEN); + prCmdContent->u2AssocId = prStaRec->u2AssocId; + prCmdContent->u2ListenInterval = prStaRec->u2ListenInterval; + prCmdContent->ucNetTypeIndex = prStaRec->ucNetTypeIndex; + + prCmdContent->ucDesiredPhyTypeSet = prStaRec->ucDesiredPhyTypeSet; + prCmdContent->u2DesiredNonHTRateSet = prStaRec->u2DesiredNonHTRateSet; + prCmdContent->u2BSSBasicRateSet = prStaRec->u2BSSBasicRateSet; + prCmdContent->ucMcsSet = prStaRec->ucMcsSet; + prCmdContent->ucSupMcs32 = (UINT_8) prStaRec->fgSupMcs32; + prCmdContent->u2HtCapInfo = prStaRec->u2HtCapInfo; + prCmdContent->ucNeedResp = (UINT_8) fgNeedResp; + +#if !CFG_SLT_SUPPORT + if(prAdapter->rWifiVar.eRateSetting != FIXED_RATE_NONE) { + /* override rate configuration */ + nicUpdateRateParams(prAdapter, + prAdapter->rWifiVar.eRateSetting, + &(prCmdContent->ucDesiredPhyTypeSet), + &(prCmdContent->u2DesiredNonHTRateSet), + &(prCmdContent->u2BSSBasicRateSet), + &(prCmdContent->ucMcsSet), + &(prCmdContent->ucSupMcs32), + &(prCmdContent->u2HtCapInfo)); + } +#endif + + prCmdContent->ucIsQoS = prStaRec->fgIsQoS; + prCmdContent->ucIsUapsdSupported = prStaRec->fgIsUapsdSupported; + prCmdContent->ucStaState = prStaRec->ucStaState; + + prCmdContent->ucAmpduParam = prStaRec->ucAmpduParam; + prCmdContent->u2HtExtendedCap = prStaRec->u2HtExtendedCap; + prCmdContent->u4TxBeamformingCap = prStaRec->u4TxBeamformingCap; + prCmdContent->ucAselCap = prStaRec->ucAselCap; + prCmdContent->ucRCPI = prStaRec->ucRCPI; + + prCmdContent->ucUapsdAc = prStaRec->ucBmpTriggerAC | (prStaRec->ucBmpDeliveryAC << 4); + prCmdContent->ucUapsdSp = prStaRec->ucUapsdSp; + + DBGLOG(REQ, TRACE, ("STA "MACSTR" type=%d state = %d\n", MAC2STR(prStaRec->aucMacAddr), prStaRec->eStaType, prStaRec->ucStaState)); + + rStatus = wlanSendSetQueryCmd ( + prAdapter, /* prAdapter */ + CMD_ID_UPDATE_STA_RECORD, /* ucCID */ + TRUE, /* fgSetQuery */ + fgNeedResp, /* fgNeedResp */ + FALSE, /* fgIsOid */ + fgNeedResp? cnmStaRecHandleEventPkt : NULL, + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_UPDATE_STA_RECORD_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdContent, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + ASSERT(rStatus == WLAN_STATUS_PENDING); + + cnmMemFree(prAdapter, prCmdContent); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param[in] +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +static VOID +cnmStaSendRemoveCmd ( + P_ADAPTER_T prAdapter, + P_STA_RECORD_T prStaRec + ) +{ + CMD_REMOVE_STA_RECORD_T rCmdContent; + WLAN_STATUS rStatus; + + ASSERT(prAdapter); + ASSERT(prStaRec); + + rCmdContent.ucIndex = prStaRec->ucIndex; + kalMemCopy(&rCmdContent.aucMacAddr[0], &prStaRec->aucMacAddr[0], + MAC_ADDR_LEN); + + rStatus = wlanSendSetQueryCmd ( + prAdapter, /* prAdapter */ + CMD_ID_REMOVE_STA_RECORD, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_REMOVE_STA_RECORD_T), /* u4SetQueryInfoLen */ + (PUINT_8) &rCmdContent, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + ASSERT(rStatus == WLAN_STATUS_PENDING); +} + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/cnm_timer.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/cnm_timer.c new file mode 100755 index 000000000000..021ff7ae8025 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/cnm_timer.c @@ -0,0 +1,575 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/mgmt/cnm_timer.c#1 $ +*/ + +/*! \file "cnm_timer.c" + \brief + +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: cnm_timer.c $ + * + * 12 13 2011 cm.chang + * [WCXRP00001136] [All Wi-Fi][Driver] Add wake lock for pending timer + * Add wake lock if timer timeout value is smaller than 5 seconds + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 02 24 2011 cp.wu + * [WCXRP00000490] [MT6620 Wi-Fi][Driver][Win32] modify kalMsleep() implementation because NdisMSleep() won't sleep long enough for specified interval such as 500ms + * modify cnm_timer and hem_mbox APIs to be thread safe to ease invoking restrictions + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * cnm_timer has been migrated. + * + * 05 28 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support sleep notification to host + * + * 05 19 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add some checking assertions + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Return timer token back to COS when entering wait off state + * + * 01 11 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Remove compiling warning + * + * 01 08 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support longer timeout interval to 45 days from 65secu1rwduu`wvpghlqg|fh+fmdkb + * + * 01 06 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Fix system time is 32KHz instead of 1ms + * + * 01 04 2010 tehuang.liu + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * For working out the first connection Chariot-verified version + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Place rRootTimer.rNextExpiredSysTime = rExpiredSysTime; before set timer + * + * Oct 30 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * In cnmTimerInitialize(), just stop timer if it was already created. + * + * Oct 30 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Move the external reference for Lint to precomp.h + * + * Oct 30 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix lint warning + * + * Oct 28 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set the time to do the time out check. +* +* \param[in] rTimeout Time out interval from current time. +* +* \retval TRUE Success. +* +*/ +/*----------------------------------------------------------------------------*/ +static BOOLEAN +cnmTimerSetTimer ( + IN P_ADAPTER_T prAdapter, + IN OS_SYSTIME rTimeout + ) +{ + P_ROOT_TIMER prRootTimer; + BOOLEAN fgNeedWakeLock; + + ASSERT(prAdapter); + + prRootTimer = &prAdapter->rRootTimer; + + kalSetTimer(prAdapter->prGlueInfo, rTimeout); + + if (rTimeout <= SEC_TO_SYSTIME(WAKE_LOCK_MAX_TIME)) { + fgNeedWakeLock = TRUE; + + if (!prRootTimer->fgWakeLocked) { + KAL_WAKE_LOCK(prAdapter, &prRootTimer->rWakeLock); + prRootTimer->fgWakeLocked = TRUE; + } + } + else { + fgNeedWakeLock = FALSE; + } + + return fgNeedWakeLock; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routines is called to initialize a root timer. +* +* \param[in] prAdapter +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +cnmTimerInitialize ( + IN P_ADAPTER_T prAdapter + ) +{ + P_ROOT_TIMER prRootTimer; + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + prRootTimer = &prAdapter->rRootTimer; + + /* Note: glue layer have configured timer */ + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + LINK_INITIALIZE(&prRootTimer->rLinkHead); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + + KAL_WAKE_LOCK_INIT(prAdapter, &prRootTimer->rWakeLock, "WLAN Timer"); + prRootTimer->fgWakeLocked = FALSE; + return; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routines is called to destroy a root timer. +* When WIFI is off, the token shall be returned back to system. +* +* \param[in] +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +cnmTimerDestroy ( + IN P_ADAPTER_T prAdapter + ) +{ + P_ROOT_TIMER prRootTimer; + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + prRootTimer = &prAdapter->rRootTimer; + + if (prRootTimer->fgWakeLocked) { + KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock); + prRootTimer->fgWakeLocked = FALSE; + } + KAL_WAKE_LOCK_DESTROY(prAdapter, &prRootTimer->rWakeLock); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + LINK_INITIALIZE(&prRootTimer->rLinkHead); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + + /* Note: glue layer will be responsible for timer destruction */ + + return; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routines is called to initialize a timer. +* +* \param[in] prTimer Pointer to a timer structure. +* \param[in] pfnFunc Pointer to the call back function. +* \param[in] u4Data Parameter for call back function. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +cnmTimerInitTimer ( + IN P_ADAPTER_T prAdapter, + IN P_TIMER_T prTimer, + IN PFN_MGMT_TIMEOUT_FUNC pfFunc, + IN UINT_32 u4Data + ) +{ + ASSERT(prAdapter); + + ASSERT(prTimer); + +#if DBG + /* Note: NULL function pointer is permitted for HEM POWER */ + if (pfFunc == NULL) { + DBGLOG(CNM, WARN, ("Init timer with NULL callback function!\n")); + } +#endif + +#if DBG + ASSERT(prAdapter->rRootTimer.rLinkHead.prNext); + { + P_LINK_T prTimerList; + P_LINK_ENTRY_T prLinkEntry; + P_TIMER_T prPendingTimer; + + prTimerList = &(prAdapter->rRootTimer.rLinkHead); + + LINK_FOR_EACH(prLinkEntry, prTimerList) { + prPendingTimer = LINK_ENTRY(prLinkEntry, TIMER_T, rLinkEntry); + ASSERT(prPendingTimer); + ASSERT(prPendingTimer != prTimer); + } + } +#endif + + LINK_ENTRY_INITIALIZE(&prTimer->rLinkEntry); + + prTimer->pfMgmtTimeOutFunc = pfFunc; + prTimer->u4Data = u4Data; + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routines is called to stop a timer. +* +* \param[in] prTimer Pointer to a timer structure. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static VOID +cnmTimerStopTimer_impl ( + IN P_ADAPTER_T prAdapter, + IN P_TIMER_T prTimer, + IN BOOLEAN fgAcquireSpinlock + ) +{ + P_ROOT_TIMER prRootTimer; + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + ASSERT(prTimer); + + prRootTimer = &prAdapter->rRootTimer; + + if (fgAcquireSpinlock) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + } + + if (timerPendingTimer(prTimer)) { + LINK_REMOVE_KNOWN_ENTRY(&prRootTimer->rLinkHead, + &prTimer->rLinkEntry); + + /* Reduce dummy timeout for power saving, especially HIF activity. + * If two or more timers exist and being removed timer is smallest, + * this dummy timeout will still happen, but it is OK. + */ + if (LINK_IS_EMPTY(&prRootTimer->rLinkHead)) { + kalCancelTimer(prAdapter->prGlueInfo); + + if (fgAcquireSpinlock && prRootTimer->fgWakeLocked) { + KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock); + prRootTimer->fgWakeLocked = FALSE; + } + } + } + + if (fgAcquireSpinlock) { + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routines is called to stop a timer. +* +* \param[in] prTimer Pointer to a timer structure. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +cnmTimerStopTimer ( + IN P_ADAPTER_T prAdapter, + IN P_TIMER_T prTimer + ) +{ + ASSERT(prAdapter); + ASSERT(prTimer); + + cnmTimerStopTimer_impl(prAdapter, prTimer, TRUE); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routines is called to start a timer with wake_lock. +* +* \param[in] prTimer Pointer to a timer structure. +* \param[in] u4TimeoutMs Timeout to issue the timer and call back function +* (unit: ms). +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +cnmTimerStartTimer ( + IN P_ADAPTER_T prAdapter, + IN P_TIMER_T prTimer, + IN UINT_32 u4TimeoutMs + ) +{ + P_ROOT_TIMER prRootTimer; + P_LINK_T prTimerList; + OS_SYSTIME rExpiredSysTime, rTimeoutSystime; + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + ASSERT(prTimer); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + + prRootTimer = &prAdapter->rRootTimer; + prTimerList= &prRootTimer->rLinkHead; + + /* If timeout interval is larger than 1 minute, the mod value is set + * to the timeout value first, then per minutue. + */ + if (u4TimeoutMs > MSEC_PER_MIN) { + ASSERT(u4TimeoutMs <= ((UINT_32)0xFFFF * MSEC_PER_MIN)); + + prTimer->u2Minutes = (UINT_16)(u4TimeoutMs / MSEC_PER_MIN); + u4TimeoutMs -= (prTimer->u2Minutes * MSEC_PER_MIN); + if (u4TimeoutMs == 0) { + u4TimeoutMs = MSEC_PER_MIN; + prTimer->u2Minutes--; + } + } + else { + prTimer->u2Minutes = 0; + } + + /* The assertion check if MSEC_TO_SYSTIME() may be overflow. */ + ASSERT(u4TimeoutMs < (((UINT_32)0x80000000 - MSEC_PER_SEC) / KAL_HZ)); + rTimeoutSystime = MSEC_TO_SYSTIME(u4TimeoutMs); + rExpiredSysTime = kalGetTimeTick() + rTimeoutSystime; + + /* If no timer pending or the fast time interval is used. */ + if (LINK_IS_EMPTY(prTimerList) || + TIME_BEFORE(rExpiredSysTime, prRootTimer->rNextExpiredSysTime)) { + + prRootTimer->rNextExpiredSysTime = rExpiredSysTime; + cnmTimerSetTimer(prAdapter, rTimeoutSystime); + } + + /* Add this timer to checking list */ + prTimer->rExpiredSysTime = rExpiredSysTime; + + if (!timerPendingTimer(prTimer)) { + LINK_INSERT_TAIL(prTimerList, &prTimer->rLinkEntry); + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + + return; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routines is called to check the timer list. +* +* \param[in] +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +cnmTimerDoTimeOutCheck ( + IN P_ADAPTER_T prAdapter + ) +{ + P_ROOT_TIMER prRootTimer; + P_LINK_T prTimerList; + P_LINK_ENTRY_T prLinkEntry; + P_TIMER_T prTimer; + OS_SYSTIME rCurSysTime; + PFN_MGMT_TIMEOUT_FUNC pfMgmtTimeOutFunc; + UINT_32 u4TimeoutData; + BOOLEAN fgNeedWakeLock; + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + /* acquire spin lock */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + + prRootTimer = &prAdapter->rRootTimer; + prTimerList= &prRootTimer->rLinkHead; + + rCurSysTime = kalGetTimeTick(); + + /* Set the permitted max timeout value for new one */ + prRootTimer->rNextExpiredSysTime = rCurSysTime + MGMT_MAX_TIMEOUT_INTERVAL; + + LINK_FOR_EACH(prLinkEntry, prTimerList) { + prTimer = LINK_ENTRY(prLinkEntry, TIMER_T, rLinkEntry); + ASSERT(prTimer); + + /* Check if this entry is timeout. */ + if (!TIME_BEFORE(rCurSysTime, prTimer->rExpiredSysTime)) { + cnmTimerStopTimer_impl(prAdapter, prTimer, FALSE); + + pfMgmtTimeOutFunc = prTimer->pfMgmtTimeOutFunc; + u4TimeoutData = prTimer->u4Data; + + if (prTimer->u2Minutes > 0) { + prTimer->u2Minutes--; + prTimer->rExpiredSysTime = + rCurSysTime + MSEC_TO_SYSTIME(MSEC_PER_MIN); + LINK_INSERT_TAIL(prTimerList, &prTimer->rLinkEntry); + } + else if (pfMgmtTimeOutFunc) { + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + (pfMgmtTimeOutFunc)(prAdapter, u4TimeoutData); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + } + + /* Search entire list again because of nest del and add timers + * and current MGMT_TIMER could be volatile after stopped + */ + prLinkEntry = (P_LINK_ENTRY_T)prTimerList; + + prRootTimer->rNextExpiredSysTime = + rCurSysTime + MGMT_MAX_TIMEOUT_INTERVAL; + } + else if (TIME_BEFORE(prTimer->rExpiredSysTime, + prRootTimer->rNextExpiredSysTime)) { + prRootTimer->rNextExpiredSysTime = prTimer->rExpiredSysTime; + } + } /* end of for loop */ + + /* Setup the prNext timeout event. It is possible the timer was already + * set in the above timeout callback function. + */ + fgNeedWakeLock = FALSE; + if (!LINK_IS_EMPTY(prTimerList)) { + ASSERT(TIME_AFTER(prRootTimer->rNextExpiredSysTime, rCurSysTime)); + + fgNeedWakeLock = cnmTimerSetTimer(prAdapter, (OS_SYSTIME) + ((INT_32)prRootTimer->rNextExpiredSysTime - (INT_32)rCurSysTime)); + } + + if (prRootTimer->fgWakeLocked && !fgNeedWakeLock) { + KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock); + prRootTimer->fgWakeLocked = FALSE; + } + + /* release spin lock */ + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); +} + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/hem_mbox.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/hem_mbox.c new file mode 100755 index 000000000000..0558c97fbc9c --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/hem_mbox.c @@ -0,0 +1,844 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/mgmt/hem_mbox.c#3 $ +*/ + +/*! \file "hem_mbox.c" + \brief + +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: hem_mbox.c $ + * + * 01 20 2012 cp.wu + * [ALPS00096191] [MT6620 Wi-Fi][Driver][Firmware] Porting to ALPS4.0_DEV branch + * sync to up-to-date changes including: + * 1. BOW bugfix + * 2. XLOG + * + * 01 17 2012 yuche.tsai + * NULL + * Update mgmt frame filter setting. + * Please also update FW 2.1 + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Hot Spot Tethering for ICS ALPHA testing version. + * + * 11 24 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Adjust code for DBG and CONFIG_XLOG. + * + * 11 15 2011 cm.chang + * NULL + * Add exception handle for NULL function pointer of mailbox message + * + * 11 11 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * modify the xlog related code. + * + * 11 02 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Add XLOG related code and define. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 08 11 2011 yuche.tsai + * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. + * Add mailbox ID. + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 03 29 2011 cm.chang + * [WCXRP00000606] [MT6620 Wi-Fi][Driver][FW] Fix klocwork warning + * As CR titile + * + * 03 29 2011 cm.chang + * [WCXRP00000606] [MT6620 Wi-Fi][Driver][FW] Fix klocwork warning + * As CR title + * + * 02 24 2011 cp.wu + * [WCXRP00000490] [MT6620 Wi-Fi][Driver][Win32] modify kalMsleep() implementation because NdisMSleep() won't sleep long enough for specified interval such as 500ms + * modify cnm_timer and hem_mbox APIs to be thread safe to ease invoking restrictions + * + * 02 15 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Update bowString and channel grant. + * + * 01 26 2011 cm.chang + * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument + * Allocate system RAM if fixed message or mgmt buffer is not available + * + * 01 26 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * . + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Fix Compile Error when DBG is disabled. + * + * 01 24 2011 cp.wu + * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving + * 1. add an extra counter for tracking pending forward frames. + * 2. notify TX service thread as well when there is pending forward frame + * 3. correct build errors leaded by introduction of Wi-Fi direct separation module + * + * 12 08 2010 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Support concurrent networks. + * + * 11 08 2010 cm.chang + * [WCXRP00000169] [MT6620 Wi-Fi][Driver][FW] Remove unused CNM recover message ID + * Remove CNM channel reover message ID + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 10 08 2010 wh.su + * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine + * update the frog's new p2p state machine. + * + * 09 28 2010 wh.su + * NULL + * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. + * + * 09 16 2010 cm.chang + * NULL + * Remove unused message ID + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 26 2010 yuche.tsai + * NULL + * Add P2P Connection Abort Event Message handler. + * + * 08 25 2010 george.huang + * NULL + * update OID/ registry control path for PM related settings + * + * 08 24 2010 yarco.yang + * NULL + * Fixed Driver ASSERT at mboxInitMsgMap() + * + * 08 24 2010 chinghwa.yu + * NULL + * Update for MID_SCN_BOW_SCAN_DONE mboxDummy. + * Update saa_fsm for BOW. + * + * 08 23 2010 chinghwa.yu + * NULL + * Add CFG_ENABLE_BT_OVER_WIFI. + * + * 08 23 2010 chinghwa.yu + * NULL + * Update for BOW. + * + * 08 16 2010 cp.wu + * NULL + * add interface for RLM to trigger OBSS-SCAN. + * + * 08 16 2010 yuche.tsai + * NULL + * Add debug message for newly add P2P message. + * + * 08 11 2010 yuche.tsai + * NULL + * Add some function entry for P2P FSM under provisioning phase.. + * + * 08 11 2010 yuche.tsai + * NULL + * Add some events to P2P Module. + * + * 08 05 2010 yuche.tsai + * NULL + * Add message box event for P2P device switch on & device discovery. + * + * 08 04 2010 cp.wu + * NULL + * remove unused mailbox message definitions. + * + * 08 02 2010 yuche.tsai + * NULL + * P2P Group Negotiation Code Check in. + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * message table should not be commented out by compilation option without modifying header file + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * Add Ad-Hoc support to AIS-FSM + * + * 07 19 2010 yuche.tsai + * + * Add wifi direct scan done callback. + * + * 07 09 2010 cp.wu + * + * change handler of MID_MNY_CNM_CONNECTION_ABORT from NULL to mboxDummy. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Rename MID_MNY_CNM_CH_RELEASE to MID_MNY_CNM_CH_ABORT + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * AIS-FSM integration with CNM channel request messages + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implementation of DRV-SCN and related mailbox message handling. + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Modify CNM message handler for new flow + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * enable currently migrated message call-backs. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * restore utility function invoking via hem_mbox to direct calls + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add buildable & linkable ais_fsm.c + * + * related reference are still waiting to be resolved + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * hem_mbox is migrated. + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add hem_mbox.c and cnm_mem.h (but disabled some feature) for further migration + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Fix file merge error + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 04 29 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * Removed MID_RXM_MQM_QOS_ACTION_FRAME + * + * 04 29 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * Removed MID_RXM_MQM_BA_ACTION_FRAME + * + * 04 27 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * MID_RXM_MQM_BA_ACTION_FRAME + * + * 03 30 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support 2.4G OBSS scan + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 03 10 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * + * * * * * * * * * * * * * * Add Channel Manager for arbitration of JOIN and SCAN Req + * + * 03 05 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Develop partial DPD code + * + * 02 11 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Updated arMsgMapTable for MID_RXM_MQM_QOS_ACTION_FRAME + * + * 01 11 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add Deauth and Disassoc Handler + * + * Dec 9 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add hemRunEventScanDone() to arMsgMapTable[] + * + * Dec 4 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix mboxDummy() didn't free prMsgHdr + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add saaAisJoinComplete event handler + * + * Dec 2 2009 MTK02468 + * [BORA00000337] To check in codes for FPGA emulation + * Fixed the handler function name in arMsgMapTable for MID_RXM_MQM_BA_ACTION_FRAME + * + * Dec 2 2009 MTK02468 + * [BORA00000337] To check in codes for FPGA emulation + * Added MID_RXM_MQM_BA_ACTION_FRAME to MsgMapTable + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Revise MSG Handler (remove dummy and add for SAA) + * + * Nov 16 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add aisFsmRunEventAbort() event handler + * + * Nov 11 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix typo + * + * Nov 10 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add more MSG_HNDL_ENTRY_T to avoid ASSERT() in mboxInitMsgMap() + * + * Nov 5 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add SCN message and function entry to arMsgMapTable[] + * + * Nov 2 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix sorting algorithm in mboxInitMsgMap() + * + * Oct 28 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +#if DBG +/*lint -save -e64 Type mismatch */ +static PUINT_8 apucDebugMsg[] = { + (PUINT_8)DISP_STRING("MID_MNY_CNM_CH_REQ"), + (PUINT_8)DISP_STRING("MID_MNY_CNM_CH_ABORT"), + (PUINT_8)DISP_STRING("MID_CNM_AIS_CH_GRANT"), + (PUINT_8)DISP_STRING("MID_CNM_P2P_CH_GRANT"), + (PUINT_8)DISP_STRING("MID_CNM_BOW_CH_GRANT"), + + (PUINT_8)DISP_STRING("MID_AIS_SCN_SCAN_REQ"), + (PUINT_8)DISP_STRING("MID_AIS_SCN_SCAN_CANCEL"), + (PUINT_8)DISP_STRING("MID_P2P_SCN_SCAN_REQ"), + (PUINT_8)DISP_STRING("MID_P2P_SCN_SCAN_CANCEL"), + (PUINT_8)DISP_STRING("MID_BOW_SCN_SCAN_REQ"), + (PUINT_8)DISP_STRING("MID_BOW_SCN_SCAN_CANCEL"), + (PUINT_8)DISP_STRING("MID_RLM_SCN_SCAN_REQ"), + (PUINT_8)DISP_STRING("MID_RLM_SCN_SCAN_CANCEL"), + (PUINT_8)DISP_STRING("MID_SCN_AIS_SCAN_DONE"), + (PUINT_8)DISP_STRING("MID_SCN_P2P_SCAN_DONE"), + (PUINT_8)DISP_STRING("MID_SCN_BOW_SCAN_DONE"), + (PUINT_8)DISP_STRING("MID_SCN_RLM_SCAN_DONE"), + + (PUINT_8)DISP_STRING("MID_OID_AIS_FSM_JOIN_REQ"), + (PUINT_8)DISP_STRING("MID_OID_AIS_FSM_ABORT"), + (PUINT_8)DISP_STRING("MID_AIS_SAA_FSM_START"), + (PUINT_8)DISP_STRING("MID_AIS_SAA_FSM_ABORT"), + (PUINT_8)DISP_STRING("MID_SAA_AIS_JOIN_COMPLETE"), + +#if CFG_ENABLE_BT_OVER_WIFI + (PUINT_8)DISP_STRING("MID_BOW_SAA_FSM_START"), + (PUINT_8)DISP_STRING("MID_BOW_SAA_FSM_ABORT"), + (PUINT_8)DISP_STRING("MID_SAA_BOW_JOIN_COMPLETE"), +#endif + +#if CFG_ENABLE_WIFI_DIRECT + (PUINT_8)DISP_STRING("MID_P2P_SAA_FSM_START"), + (PUINT_8)DISP_STRING("MID_P2P_SAA_FSM_ABORT"), + (PUINT_8)DISP_STRING("MID_SAA_P2P_JOIN_COMPLETE"), + + (PUINT_8)DISP_STRING("MID_MNY_P2P_FUN_SWITCH"), + (PUINT_8)DISP_STRING("MID_MNY_P2P_DEVICE_DISCOVERY"), + (PUINT_8)DISP_STRING("MID_MNY_P2P_DISCOVERY_ABORT"), + (PUINT_8)DISP_STRING("MID_MNY_P2P_CONNECTION_REQ"), + (PUINT_8)DISP_STRING("MID_MNY_P2P_CONNECTION_ABORT"), + (PUINT_8)DISP_STRING("MID_MNY_P2P_CONNECTION_TRIGGER"), + (PUINT_8)DISP_STRING("MID_MNY_P2P_CONNECTION_PAUSE"), + (PUINT_8)DISP_STRING("MID_MNY_P2P_PROVISION_COMPLETE"), + #endif + +#if CFG_SUPPORT_ADHOC + //(PUINT_8)DISP_STRING("MID_AIS_CNM_CREATE_IBSS_REQ"), + //(PUINT_8)DISP_STRING("MID_CNM_AIS_CREATE_IBSS_GRANT"), + //(PUINT_8)DISP_STRING("MID_AIS_CNM_MERGE_IBSS_REQ"), + //(PUINT_8)DISP_STRING("MID_CNM_AIS_MERGE_IBSS_GRANT"), + (PUINT_8)DISP_STRING("MID_SCN_AIS_FOUND_IBSS"), +#endif /* CFG_SUPPORT_ADHOC */ + + (PUINT_8)DISP_STRING("MID_SAA_AIS_FSM_ABORT") +}; +/*lint -restore */ +#endif /* DBG */ + +/* This message entry will be re-ordered based on the message ID order + * by invoking mboxInitMsgMap() + */ +static MSG_HNDL_ENTRY_T arMsgMapTable[] = { + { MID_MNY_CNM_CH_REQ, cnmChMngrRequestPrivilege }, + { MID_MNY_CNM_CH_ABORT, cnmChMngrAbortPrivilege }, + { MID_CNM_AIS_CH_GRANT, aisFsmRunEventChGrant }, + { MID_CNM_P2P_CH_GRANT, mboxDummy }, /*set in gl_p2p_init.c*/ + +#if CFG_ENABLE_BT_OVER_WIFI + { MID_CNM_BOW_CH_GRANT, bowRunEventChGrant }, +#else + { MID_CNM_BOW_CH_GRANT, mboxDummy }, +#endif + + /*--------------------------------------------------*/ + /* SCN Module Mailbox Messages */ + /*--------------------------------------------------*/ + { MID_AIS_SCN_SCAN_REQ, scnFsmMsgStart }, + { MID_AIS_SCN_SCAN_REQ_V2, scnFsmMsgStart }, + { MID_AIS_SCN_SCAN_CANCEL, scnFsmMsgAbort }, + { MID_P2P_SCN_SCAN_REQ, scnFsmMsgStart }, + { MID_P2P_SCN_SCAN_REQ_V2, scnFsmMsgStart }, + { MID_P2P_SCN_SCAN_CANCEL, scnFsmMsgAbort }, + { MID_BOW_SCN_SCAN_REQ, scnFsmMsgStart }, + { MID_BOW_SCN_SCAN_REQ_V2, scnFsmMsgStart }, + { MID_BOW_SCN_SCAN_CANCEL, scnFsmMsgAbort }, + { MID_RLM_SCN_SCAN_REQ, scnFsmMsgStart }, + { MID_RLM_SCN_SCAN_REQ_V2, scnFsmMsgStart }, + { MID_RLM_SCN_SCAN_CANCEL, scnFsmMsgAbort }, + { MID_SCN_AIS_SCAN_DONE, aisFsmRunEventScanDone }, + { MID_SCN_P2P_SCAN_DONE, mboxDummy }, /*set in gl_p2p_init.c*/ + +#if CFG_ENABLE_BT_OVER_WIFI + { MID_SCN_BOW_SCAN_DONE, bowResponderScanDone }, +#else + { MID_SCN_BOW_SCAN_DONE, mboxDummy }, +#endif + { MID_SCN_RLM_SCAN_DONE, rlmObssScanDone }, + + /*--------------------------------------------------*/ + /* AIS Module Mailbox Messages */ + /*--------------------------------------------------*/ + { MID_OID_AIS_FSM_JOIN_REQ, aisFsmRunEventAbort }, + { MID_OID_AIS_FSM_ABORT, aisFsmRunEventAbort }, + { MID_AIS_SAA_FSM_START, saaFsmRunEventStart }, + { MID_AIS_SAA_FSM_ABORT, saaFsmRunEventAbort }, + { MID_SAA_AIS_JOIN_COMPLETE, aisFsmRunEventJoinComplete }, + +#if CFG_ENABLE_BT_OVER_WIFI + /*--------------------------------------------------*/ + /* BOW Module Mailbox Messages */ + /*--------------------------------------------------*/ + { MID_BOW_SAA_FSM_START, saaFsmRunEventStart }, + { MID_BOW_SAA_FSM_ABORT, saaFsmRunEventAbort }, + { MID_SAA_BOW_JOIN_COMPLETE, bowFsmRunEventJoinComplete }, +#endif + +#if CFG_ENABLE_WIFI_DIRECT /*set in gl_p2p_init.c*/ + { MID_P2P_SAA_FSM_START, mboxDummy }, + { MID_P2P_SAA_FSM_ABORT, mboxDummy }, + { MID_SAA_P2P_JOIN_COMPLETE, mboxDummy },// TODO: p2pFsmRunEventJoinComplete + + { MID_MNY_P2P_FUN_SWITCH, mboxDummy }, + { MID_MNY_P2P_DEVICE_DISCOVERY, mboxDummy }, + { MID_MNY_P2P_DISCOVERY_ABORT, mboxDummy }, + { MID_MNY_P2P_CONNECTION_REQ, mboxDummy }, + { MID_MNY_P2P_CONNECTION_ABORT, mboxDummy }, + { MID_MNY_P2P_CONNECTION_TRIGGER,mboxDummy }, + { MID_MNY_P2P_CONNECTION_PAUSE, mboxDummy }, + { MID_MNY_P2P_PROVISION_COMPLETE,mboxDummy }, + { MID_MNY_P2P_INVITATION_REQ,mboxDummy }, + { MID_MNY_P2P_INVITATION_ABORT,mboxDummy }, + { MID_MNY_P2P_BEACON_UPDATE,mboxDummy }, + { MID_MNY_P2P_BEACON_DEL,mboxDummy }, + { MID_MNY_P2P_CHNL_REQ,mboxDummy }, + { MID_MNY_P2P_CHNL_ABORT,mboxDummy }, + { MID_MNY_P2P_MGMT_TX,mboxDummy }, + { MID_MNY_P2P_GROUP_DISSOLVE,mboxDummy }, + { MID_MNY_P2P_MGMT_FRAME_REGISTER, mboxDummy }, +#endif + +#if CFG_SUPPORT_ADHOC + { MID_SCN_AIS_FOUND_IBSS, aisFsmRunEventFoundIBSSPeer }, +#endif /* CFG_SUPPORT_ADHOC */ + + { MID_SAA_AIS_FSM_ABORT, aisFsmRunEventAbort } +}; + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#if CFG_SUPPORT_XLOG +#define MBOX_HNDL_MSG(prAdapter, prMsg) do { \ + ASSERT(arMsgMapTable[prMsg->eMsgId].pfMsgHndl); \ + if (arMsgMapTable[prMsg->eMsgId].pfMsgHndl) { \ + DBGLOG(CNM, LOUD, ("DO MSG [%d]\n", prMsg->eMsgId)); \ + arMsgMapTable[prMsg->eMsgId].pfMsgHndl(prAdapter, prMsg); \ + } \ + else { \ + DBGLOG(CNM, ERROR, ("NULL fptr for MSG [%d]\n", prMsg->eMsgId)); \ + cnmMemFree(prAdapter, prMsg); \ + } \ +} while (0) +#else +#define MBOX_HNDL_MSG(prAdapter, prMsg) do { \ + ASSERT(arMsgMapTable[prMsg->eMsgId].pfMsgHndl); \ + if (arMsgMapTable[prMsg->eMsgId].pfMsgHndl) { \ + DBGLOG(CNM, LOUD, ("DO MSG [%d: %s]\n", prMsg->eMsgId, apucDebugMsg[prMsg->eMsgId])); \ + arMsgMapTable[prMsg->eMsgId].pfMsgHndl(prAdapter, prMsg); \ + } \ + else { \ + DBGLOG(CNM, ERROR, ("NULL fptr for MSG [%d]\n", prMsg->eMsgId)); \ + cnmMemFree(prAdapter, prMsg); \ + } \ +} while (0) +#endif +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +mboxInitMsgMap ( + VOID + ) +{ + UINT_32 i, idx; + MSG_HNDL_ENTRY_T rTempEntry; + + ASSERT((sizeof(arMsgMapTable) / sizeof(MSG_HNDL_ENTRY_T)) == MID_TOTAL_NUM); + + for (i = 0; i < MID_TOTAL_NUM; i++) { + if (arMsgMapTable[i].eMsgId == (ENUM_MSG_ID_T) i) { + continue; + } + for (idx = i + 1; idx < MID_TOTAL_NUM; idx++) { + if (arMsgMapTable[idx].eMsgId == (ENUM_MSG_ID_T) i) { + break; + } + } + ASSERT(idx < MID_TOTAL_NUM); + if (idx >= MID_TOTAL_NUM) { + continue; + } + + /* Swap target entry and current entry */ + rTempEntry.eMsgId = arMsgMapTable[idx].eMsgId; + rTempEntry.pfMsgHndl= arMsgMapTable[idx].pfMsgHndl; + + arMsgMapTable[idx].eMsgId = arMsgMapTable[i].eMsgId; + arMsgMapTable[idx].pfMsgHndl = arMsgMapTable[i].pfMsgHndl; + + arMsgMapTable[i].eMsgId = rTempEntry.eMsgId; + arMsgMapTable[i].pfMsgHndl = rTempEntry.pfMsgHndl; + } + + /* Verify the correctness of final message map */ + for (i = 0; i < MID_TOTAL_NUM; i++) { + ASSERT(arMsgMapTable[i].eMsgId == (ENUM_MSG_ID_T) i); + while (arMsgMapTable[i].eMsgId != (ENUM_MSG_ID_T) i); + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +mboxSetup ( + IN P_ADAPTER_T prAdapter, + IN ENUM_MBOX_ID_T eMboxId + ) +{ + P_MBOX_T prMbox; + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(eMboxId < MBOX_ID_TOTAL_NUM); + ASSERT(prAdapter); + + prMbox = &(prAdapter->arMbox[eMboxId]); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); + LINK_INITIALIZE(&prMbox->rLinkHead); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +mboxSendMsg ( + IN P_ADAPTER_T prAdapter, + IN ENUM_MBOX_ID_T eMboxId, + IN P_MSG_HDR_T prMsg, + IN EUNM_MSG_SEND_METHOD_T eMethod + ) +{ + P_MBOX_T prMbox; + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(eMboxId < MBOX_ID_TOTAL_NUM); + ASSERT(prMsg); + ASSERT(prAdapter); + + prMbox = &(prAdapter->arMbox[eMboxId]); + + switch (eMethod) { + case MSG_SEND_METHOD_BUF: + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); + LINK_INSERT_TAIL(&prMbox->rLinkHead, &prMsg->rLinkEntry); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); + + // to wake up main service thread + GLUE_SET_EVENT(prAdapter->prGlueInfo); + + break; + + case MSG_SEND_METHOD_UNBUF: + MBOX_HNDL_MSG(prAdapter, prMsg); + break; + + default: + ASSERT(0); + break; + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +mboxRcvAllMsg ( + IN P_ADAPTER_T prAdapter, + ENUM_MBOX_ID_T eMboxId + ) +{ + P_MBOX_T prMbox; + P_MSG_HDR_T prMsg; + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(eMboxId < MBOX_ID_TOTAL_NUM); + ASSERT(prAdapter); + + prMbox = &(prAdapter->arMbox[eMboxId]); + + while (!LINK_IS_EMPTY(&prMbox->rLinkHead) ) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); + LINK_REMOVE_HEAD(&prMbox->rLinkHead, prMsg, P_MSG_HDR_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); + + ASSERT(prMsg); + MBOX_HNDL_MSG(prAdapter, prMsg); + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +mboxInitialize ( + IN P_ADAPTER_T prAdapter + ) +{ + UINT_32 i; + + ASSERT(prAdapter); + + /* Initialize Mailbox */ + mboxInitMsgMap(); + + /* Setup/initialize each mailbox */ + for (i = 0; i < MBOX_ID_TOTAL_NUM; i++) { + mboxSetup(prAdapter, i); + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +mboxDestroy ( + IN P_ADAPTER_T prAdapter + ) +{ + P_MBOX_T prMbox; + P_MSG_HDR_T prMsg; + UINT_8 i; + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + for (i = 0; i < MBOX_ID_TOTAL_NUM; i++) { + prMbox = &(prAdapter->arMbox[i]); + + while (!LINK_IS_EMPTY(&prMbox->rLinkHead) ) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); + LINK_REMOVE_HEAD(&prMbox->rLinkHead, prMsg, P_MSG_HDR_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); + + ASSERT(prMsg); + cnmMemFree(prAdapter, prMsg); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is dummy function to prevent empty arMsgMapTable[] for compiling. +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +mboxDummy ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + ASSERT(prAdapter); + + cnmMemFree(prAdapter, prMsgHdr); + + return; +} + + +#if CFG_ENABLE_WIFI_DIRECT +EXPORT_SYMBOL(arMsgMapTable); +#endif + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/mib.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/mib.c new file mode 100755 index 000000000000..e1cc658d9dd7 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/mib.c @@ -0,0 +1,146 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/mgmt/mib.c#1 $ +*/ + +/*! \file "mib.c" + \brief This file includes the mib default vale and functions. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: mib.c $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add mib.c. + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +NON_HT_PHY_ATTRIBUTE_T rNonHTPhyAttributes[] = { + {RATE_SET_HR_DSSS, TRUE, FALSE }, /* For PHY_TYPE_HR_DSSS_INDEX(0) */ + {RATE_SET_ERP, TRUE, TRUE }, /* For PHY_TYPE_ERP_INDEX(1) */ + {RATE_SET_ERP_P2P, TRUE, TRUE }, /* For PHY_TYPE_ERP_P2P_INDEX(2) */ + {RATE_SET_OFDM, FALSE, FALSE }, /* For PHY_TYPE_OFDM_INDEX(3) */ +}; + +NON_HT_ADHOC_MODE_ATTRIBUTE_T rNonHTAdHocModeAttributes[AD_HOC_MODE_NUM] = { + {PHY_TYPE_HR_DSSS_INDEX, BASIC_RATE_SET_HR_DSSS}, /* For AD_HOC_MODE_11B(0) */ + {PHY_TYPE_ERP_INDEX, BASIC_RATE_SET_HR_DSSS_ERP}, /* For AD_HOC_MODE_MIXED_11BG(1) */ + {PHY_TYPE_ERP_INDEX, BASIC_RATE_SET_ERP}, /* For AD_HOC_MODE_11G(2) */ + {PHY_TYPE_OFDM_INDEX, BASIC_RATE_SET_OFDM}, /* For AD_HOC_MODE_11A(3) */ +}; + +NON_HT_AP_MODE_ATTRIBUTE_T rNonHTApModeAttributes[AP_MODE_NUM] = { + {PHY_TYPE_HR_DSSS_INDEX, BASIC_RATE_SET_HR_DSSS}, /* For AP_MODE_11B(0) */ + {PHY_TYPE_ERP_INDEX, BASIC_RATE_SET_HR_DSSS_ERP}, /* For AP_MODE_MIXED_11BG(1) */ + {PHY_TYPE_ERP_INDEX, BASIC_RATE_SET_ERP}, /* For AP_MODE_11G(2) */ + {PHY_TYPE_ERP_P2P_INDEX, BASIC_RATE_SET_ERP_P2P}, /* For AP_MODE_11G_P2P(3) */ + {PHY_TYPE_OFDM_INDEX, BASIC_RATE_SET_OFDM}, /* For AP_MODE_11A(4) */ +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/privacy.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/privacy.c new file mode 100755 index 000000000000..36d2c9bbba2c --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/privacy.c @@ -0,0 +1,1069 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/mgmt/privacy.c#1 $ +*/ + +/*! \file "privacy.c" + \brief This file including the protocol layer privacy function. + + This file provided the macros and functions library support for the + protocol layer security setting from rsn.c and nic_privacy.c + +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: privacy.c $ + * + * 11 10 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * change the debug module level. + * + * 10 20 2011 terry.wu + * NULL + * Fix Hotspot deauth send failed. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 06 28 2011 tsaiyuan.hsu + * [WCXRP00000819] [MT6620 Wi-Fi][Driver] check if staRec is NULL or not in secCheckClassError + * check if staRec is NULL or not in secCheckClassError. + * + * 06 09 2011 tsaiyuan.hsu + * [WCXRP00000760] [MT5931 Wi-Fi][FW] Refine rxmHandleMacRxDone to reduce code size + * move send_auth at rxmHandleMacRxDone in firmware to driver to reduce code size. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. + * + * 11 04 2010 wh.su + * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID + * adding the p2p random ssid support. + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by ENUM_NETWORK_TYPE_INDEX_T only + * remove ENUM_NETWORK_TYPE_T definitions + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 09 01 2010 wh.su + * NULL + * adding the wapi support for integration test. + * + * 07 24 2010 wh.su + * + * .support the Wi-Fi RSN + * + * 07 20 2010 wh.su + * + * adding the wapi code. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * modify some code for concurrent network. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * [WPD00003833][MT6620 and MT5931] Driver migration + * enable RX management frame handling. + * + * 06 19 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * adding the compiling flag for migration. + * + * 06 19 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * consdier the concurrent network setting. + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration the security related function from firmware. + * + * 05 28 2010 wh.su + * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing + * fixed the ad-hoc wpa-none send non-encrypted frame issue. + * + * 05 24 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Refine authSendAuthFrame() for NULL STA_RECORD_T case and minimum deauth interval. + * + * 04 29 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * adjsut the pre-authentication code. + * + * 04 22 2010 wh.su + * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing + * fixed the wpi same key id rx issue and fixed the remove wep key issue. + * + * 04 19 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * Add Send Deauth for Class 3 Error and Leave Network Support + * + * 04 15 2010 wh.su + * [BORA00000680][MT6620] Support the statistic for Microsoft os query + * remove the assert code for allow ad-hoc pkt. + * + * 04 13 2010 wh.su + * [BORA00000680][MT6620] Support the statistic for Microsoft os query + * fixed the Klocwork error and refine the class error message. + * + * 03 04 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * Code refine, and remove non-used code. + * + * 03 03 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * move the AIS specific variable for security to AIS specific structure. + * + * 03 03 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * Fixed the pre-authentication timer not correctly init issue, and modify the security related callback function prototype. + * + * 03 01 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * Refine the variable and parameter for security. + * + * 02 26 2010 wh.su + * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing + * change the waning message shown level, and clear the global transmit flag for CMD INFRASTRUCTURE. + * + * 02 25 2010 wh.su + * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing + * For support the WHQL test, do the remove key code refine. + * + * 01 27 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * add and fixed some security function. + * + * 12 25 2009 tehuang.liu + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Integrated modifications for 1st connection (mainly on FW modules MQM, TXM, and RXM) + * * * * * * * * * MQM: BA handling + * * * * * * * * * TXM: Macros updates + * * * * * * * * * RXM: Macros/Duplicate Removal updates + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Dec 11 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * modify the cmd with result return + * + * Dec 11 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * fixed the value not initialize issue + * + * Dec 10 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * change the cmd return type + * + * Dec 8 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the function to update the auth mode and encryption status for cmd build connection + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding some code for wapi mode + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the call to check the 4th and eapol error report frame + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * rename the function name + * + * Dec 4 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the code for parsing the EAPoL frame, and do some code refine + * + * Dec 3 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the class error check + * + * Dec 3 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the cmd_802_11_pmkid code + * + * Dec 1 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * doing some function rename, and adding the code for cmd CMD_ADD_REMOVE_KEY + * + * Nov 23 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the clear pmkid function + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix eStaType check for AIS + * + * Nov 19 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the ap selection related code + * + * Nov 18 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +#if CFG_PRIVACY_MIGRATION + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to initialize the privacy-related +* parameters. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] ucNetTypeIdx Pointer to netowrk type index +* +* \retval NONE +*/ +/*----------------------------------------------------------------------------*/ +VOID +secInit ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucNetTypeIdx + ) +{ + UINT_8 i; + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_INFO_T prBssInfo; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + DEBUGFUNC("secInit"); + + ASSERT(prAdapter); + + prConnSettings = &prAdapter->rWifiVar.rConnSettings; + prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + prBssInfo->u4RsnSelectedGroupCipher = 0; + prBssInfo->u4RsnSelectedPairwiseCipher = 0; + prBssInfo->u4RsnSelectedAKMSuite = 0; + +#if CFG_ENABLE_WIFI_DIRECT + prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; + + prBssInfo->u4RsnSelectedGroupCipher = RSN_CIPHER_SUITE_CCMP; + prBssInfo->u4RsnSelectedPairwiseCipher = RSN_CIPHER_SUITE_CCMP; + prBssInfo->u4RsnSelectedAKMSuite = RSN_AKM_SUITE_PSK; +#endif + +#if CFG_ENABLE_BT_OVER_WIFI + prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]; + + prBssInfo->u4RsnSelectedGroupCipher = RSN_CIPHER_SUITE_CCMP; + prBssInfo->u4RsnSelectedPairwiseCipher = RSN_CIPHER_SUITE_CCMP; + prBssInfo->u4RsnSelectedAKMSuite = RSN_AKM_SUITE_PSK; +#endif + + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[0].dot11RSNAConfigPairwiseCipher = + WPA_CIPHER_SUITE_WEP40; + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[1].dot11RSNAConfigPairwiseCipher = + WPA_CIPHER_SUITE_TKIP; + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[2].dot11RSNAConfigPairwiseCipher = + WPA_CIPHER_SUITE_CCMP; + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[3].dot11RSNAConfigPairwiseCipher = + WPA_CIPHER_SUITE_WEP104; + + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[4].dot11RSNAConfigPairwiseCipher = + RSN_CIPHER_SUITE_WEP40; + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[5].dot11RSNAConfigPairwiseCipher = + RSN_CIPHER_SUITE_TKIP; + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[6].dot11RSNAConfigPairwiseCipher = + RSN_CIPHER_SUITE_CCMP; + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[7].dot11RSNAConfigPairwiseCipher = + RSN_CIPHER_SUITE_WEP104; + + for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i ++) { + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[i].dot11RSNAConfigPairwiseCipherEnabled = + FALSE; + } + + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[0].dot11RSNAConfigAuthenticationSuite = + WPA_AKM_SUITE_NONE; + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[1].dot11RSNAConfigAuthenticationSuite = + WPA_AKM_SUITE_802_1X; + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[2].dot11RSNAConfigAuthenticationSuite = + WPA_AKM_SUITE_PSK; + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[3].dot11RSNAConfigAuthenticationSuite = + RSN_AKM_SUITE_NONE; + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[4].dot11RSNAConfigAuthenticationSuite = + RSN_AKM_SUITE_802_1X; + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[5].dot11RSNAConfigAuthenticationSuite = + RSN_AKM_SUITE_PSK; + +#if CFG_SUPPORT_802_11W + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[6].dot11RSNAConfigAuthenticationSuite = + RSN_AKM_SUITE_802_1X_SHA256; + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[7].dot11RSNAConfigAuthenticationSuite = + RSN_AKM_SUITE_PSK_SHA256; +#endif + + for (i = 0; i < MAX_NUM_SUPPORTED_AKM_SUITES; i ++) { + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[i].dot11RSNAConfigAuthenticationSuiteEnabled = + FALSE; + } + + secClearPmkid(prAdapter); + + cnmTimerInitTimer(prAdapter, + &prAisSpecBssInfo->rPreauthenticationTimer, + (PFN_MGMT_TIMEOUT_FUNC)rsnIndicatePmkidCand, + (UINT_32)NULL); + +#if CFG_SUPPORT_802_11W + cnmTimerInitTimer(prAdapter, + &prAisSpecBssInfo->rSaQueryTimer, + (PFN_MGMT_TIMEOUT_FUNC)rsnStartSaQueryTimer, + (UINT_32)NULL); +#endif + + prAisSpecBssInfo->fgCounterMeasure = FALSE; + prAisSpecBssInfo->ucWEPDefaultKeyID = 0; + + + #if 0 + for (i=0;iarWtbl[i].fgUsed = FALSE; + g_prWifiVar->arWtbl[i].prSta = NULL; + g_prWifiVar->arWtbl[i].ucNetTypeIdx = NETWORK_TYPE_INDEX_NUM; + + } + nicPrivacyInitialize((UINT_8)NETWORK_TYPE_INDEX_NUM); + #endif +} /* secInit */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will indicate an Event of "Rx Class Error" to SEC_FSM for +* JOIN Module. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] prSwRfb Pointer to the SW RFB. +* +* \return FALSE Class Error +*/ +/*----------------------------------------------------------------------------*/ +BOOL +secCheckClassError ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN P_STA_RECORD_T prStaRec + ) +{ + ASSERT(prAdapter); + ASSERT(prSwRfb); + //ASSERT(prStaRec); + + //prStaRec = &(g_arStaRec[prSwRfb->ucStaRecIdx]); + + if ((prStaRec) && 1 /* RXM_IS_DATA_FRAME(prSwRfb) */) { + ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex = prStaRec->ucNetTypeIndex; + + if (IS_NET_ACTIVE(prAdapter, eNetTypeIndex)) { + P_BSS_INFO_T prBssInfo; + prBssInfo = &prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]; + + if ((STA_STATE_3 != prStaRec->ucStaState) && + IS_BSS_ACTIVE(prBssInfo) && + prBssInfo->fgIsNetAbsent == FALSE) { + /*(IS_AP_STA(prStaRec) || IS_CLIENT_STA(prStaRec))) {*/ + + if (WLAN_STATUS_SUCCESS == authSendDeauthFrame(prAdapter, + prStaRec, + NULL, + REASON_CODE_CLASS_3_ERR, + (PFN_TX_DONE_HANDLER)NULL)) { + + DBGLOG(RSN, INFO, ("Send Deauth to MAC:["MACSTR"] for Rx Class 3 Error.\n", + MAC2STR(prStaRec->aucMacAddr))); + } + + return FALSE; + } + + return secRxPortControlCheck(prAdapter, prSwRfb); + } + } + + return FALSE; +} /* end of secCheckClassError() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to setting the sta port status. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] prSta Pointer to the sta +* \param[in] fgPortBlock The port status +* +* \retval none +* +*/ +/*----------------------------------------------------------------------------*/ +VOID +secSetPortBlocked ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta, + IN BOOLEAN fgPortBlock + ) +{ + if (prSta == NULL) + return ; + + prSta->fgPortBlock = fgPortBlock; + + DBGLOG(RSN, TRACE, ("The STA "MACSTR" port %s\n", MAC2STR(prSta->aucMacAddr), fgPortBlock == TRUE ? "BLOCK" :" OPEN")); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to report the sta port status. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] prSta Pointer to the sta +* \param[out] fgPortBlock The port status +* +* \return TRUE sta exist, FALSE sta not exist +* +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +secGetPortStatus ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta, + OUT PBOOLEAN pfgPortStatus + ) +{ + if (prSta == NULL) + return FALSE; + + *pfgPortStatus = prSta->fgPortBlock; + + return TRUE; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to handle Peer device Tx Security process MSDU. +* +* \param[in] prMsduInfo pointer to the packet info pointer +* +* \retval TRUE Accept the packet +* \retval FALSE Refuse the MSDU packet due port blocked +* +*/ +/*----------------------------------------------------------------------------*/ +BOOL /* ENUM_PORT_CONTROL_RESULT */ +secTxPortControlCheck( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN P_STA_RECORD_T prStaRec + ) +{ + ASSERT(prAdapter); + ASSERT(prMsduInfo); + ASSERT(prStaRec); + + if (prStaRec) { + + /* Todo:: */ + if (prMsduInfo->fgIs802_1x) + return TRUE; + + if (prStaRec->fgPortBlock == TRUE) { + DBGLOG(INIT, TRACE, ("Drop Tx packet due Port Control!\n")); + return FALSE; + } + +#if CFG_SUPPORT_WAPI + if (prAdapter->rWifiVar.rConnSettings.fgWapiMode) { + return TRUE; + } +#endif + if (IS_STA_IN_AIS(prStaRec)) { + if (!prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist && + (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION1_ENABLED)){ + DBGLOG(INIT, TRACE, ("Drop Tx packet due the key is removed!!!\n")); + return FALSE; + } + } + } + + return TRUE; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to handle The Rx Security process MSDU. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] prSWRfb SW rfb pinter +* +* \retval TRUE Accept the packet +* \retval FALSE Refuse the MSDU packet due port control +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +secRxPortControlCheck ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSWRfb + ) +{ + ASSERT(prSWRfb); + +#if 0 + /* whsu:Todo: Process MGMT and DATA */ + if (prSWRfb->prStaRec) { + if (prSWRfb->prStaRec->fgPortBlock == TRUE) { + if (1 /* prSWRfb->fgIsDataFrame and not 1x*/ && + (g_prWifiVar->rConnSettings.eAuthMode >= AUTH_MODE_WPA)){ + //DBGLOG(SEC, WARN, ("Drop Rx data due port control !\r\n")); + return TRUE; /* Todo: whsu FALSE; */ + } + //if (!RX_STATUS_IS_PROTECT(prSWRfb->prRxStatus)) { + // DBGLOG(RSN, WARN, ("Drop rcv non-encrypted data frame!\n")); + // return FALSE; + //} + } + } + else { + } +#endif + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine will enable/disable the cipher suite +* +* \param[in] prAdapter Pointer to the adapter object data area. +* \param[in] u4CipherSuitesFlags flag for cipher suite +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +secSetCipherSuite ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4CipherSuitesFlags + ) +{ + UINT_32 i; + P_DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY prEntry; + P_IEEE_802_11_MIB_T prMib; + + ASSERT(prAdapter); + + prMib = &prAdapter->rMib; + + ASSERT(prMib); + + if (u4CipherSuitesFlags == CIPHER_FLAG_NONE) { + /* Disable all the pairwise cipher suites. */ + for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i++) { + prMib->dot11RSNAConfigPairwiseCiphersTable[i].dot11RSNAConfigPairwiseCipherEnabled = + FALSE; + } + + /* Update the group cipher suite. */ + prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_NONE; + + return; + } + + for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i++) { + prEntry = &prMib->dot11RSNAConfigPairwiseCiphersTable[i]; + + switch (prEntry->dot11RSNAConfigPairwiseCipher) { + case WPA_CIPHER_SUITE_WEP40: + case RSN_CIPHER_SUITE_WEP40: + if (u4CipherSuitesFlags & CIPHER_FLAG_WEP40) { + prEntry->dot11RSNAConfigPairwiseCipherEnabled = TRUE; + } + else { + prEntry->dot11RSNAConfigPairwiseCipherEnabled = FALSE; + } + break; + + case WPA_CIPHER_SUITE_TKIP: + case RSN_CIPHER_SUITE_TKIP: + if (u4CipherSuitesFlags & CIPHER_FLAG_TKIP) { + prEntry->dot11RSNAConfigPairwiseCipherEnabled = TRUE; + } + else { + prEntry->dot11RSNAConfigPairwiseCipherEnabled = FALSE; + } + break; + + case WPA_CIPHER_SUITE_CCMP: + case RSN_CIPHER_SUITE_CCMP: + if (u4CipherSuitesFlags & CIPHER_FLAG_CCMP) { + prEntry->dot11RSNAConfigPairwiseCipherEnabled = TRUE; + } + else { + prEntry->dot11RSNAConfigPairwiseCipherEnabled = FALSE; + } + break; + + case WPA_CIPHER_SUITE_WEP104: + case RSN_CIPHER_SUITE_WEP104: + if (u4CipherSuitesFlags & CIPHER_FLAG_WEP104) { + prEntry->dot11RSNAConfigPairwiseCipherEnabled = TRUE; + } + else { + prEntry->dot11RSNAConfigPairwiseCipherEnabled = FALSE; + } + break; + default: + break; + } + } + + /* Update the group cipher suite. */ + if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_CCMP, &i)) { + prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_CCMP; + } + else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_TKIP, &i)) { + prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_TKIP; + } + else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_WEP104, &i)) { + prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_WEP104; + } + else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_WEP40, &i)) { + prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_WEP40; + } + else { + prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_NONE; + } + +} /* secSetCipherSuite */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to handle The 2nd Tx EAPoL Frame. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] prMsduInfo pointer to the packet info pointer +* \param[in] pucPayload pointer to the 1x hdr +* \param[in] u2PayloadLen the 1x payload length +* +* \retval TRUE Accept the packet +* \retval FALSE Refuse the MSDU packet due port control +* +*/ +/*----------------------------------------------------------------------------*/ +BOOL +secProcessEAPOL ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN P_STA_RECORD_T prStaRec, + IN PUINT_8 pucPayload, + IN UINT_16 u2PayloadLen +) +{ + P_EAPOL_KEY prEapol = (P_EAPOL_KEY)NULL; + P_IEEE_802_1X_HDR pr1xHdr; + UINT_16 u2KeyInfo; + + ASSERT(prMsduInfo); + ASSERT(prStaRec); + + //prStaRec = &(g_arStaRec[prMsduInfo->ucStaRecIndex]); + ASSERT(prStaRec); + + if (prStaRec && IS_AP_STA(prStaRec)) { + pr1xHdr = (P_IEEE_802_1X_HDR)pucPayload; + if ((pr1xHdr->ucType == 3) /* EAPoL key */ && ((u2PayloadLen - 4) > sizeof(EAPOL_KEY))) { + prEapol = (P_EAPOL_KEY)((PUINT_32)(pucPayload + 4)); + WLAN_GET_FIELD_BE16(prEapol->aucKeyInfo, &u2KeyInfo); + if ((prEapol->ucType == 254) && (u2KeyInfo & MASK_2ND_EAPOL)) { + if (u2KeyInfo & WPA_KEY_INFO_SECURE) { + /* 4th EAPoL check at secHandleTxDoneCallback() */ + //DBGLOG(RSN, TRACE, ("Tx 4th EAPoL frame\r\n")); + } + else if (u2PayloadLen == 123 /* Not include LLC */) { + DBGLOG(RSN, INFO, ("Tx 2nd EAPoL frame\r\n")); + secFsmEvent2ndEapolTx(prAdapter, prStaRec); + } + } + } + } + + return TRUE; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will handle the 4th EAPoL Tx done and mic Error Report frame. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pMsduInfo Pointer to the Msdu Info +* \param[in] rStatus The Tx done status +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +VOID +secHandleTxDoneCallback( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN P_STA_RECORD_T prStaRec, + IN WLAN_STATUS rStatus + ) +{ + PUINT_8 pucPayload; + P_IEEE_802_1X_HDR pr1xHdr = (P_IEEE_802_1X_HDR)NULL; + P_EAPOL_KEY prEapol = (P_EAPOL_KEY)NULL; + UINT_16 u2KeyInfo; + UINT_16 u2PayloadLen; + + DEBUGFUNC("secHandleTxDoneCallback"); + + ASSERT(prMsduInfo); + //Todo:: Notice if using the TX free immediate after send to firmware, the payload may not correcttly!!!! + + ASSERT(prStaRec); + + //Todo:: This call back may not need because the order of set key and send 4th 1x can be make sure + //Todo:: Notice the LLC offset + #if 1 + pucPayload = (PUINT_8)prMsduInfo->prPacket; + ASSERT(pucPayload); + + u2PayloadLen = prMsduInfo->u2FrameLength; + + if (0 /* prMsduInfo->fgIs1xFrame */) { + + if (prStaRec && IS_AP_STA(prStaRec)) { + pr1xHdr = (P_IEEE_802_1X_HDR)(PUINT_32)(pucPayload + 8); + if ((pr1xHdr->ucType == 3) /* EAPoL key */ && ((u2PayloadLen - 4) > sizeof(EAPOL_KEY))) { + prEapol = (P_EAPOL_KEY)(PUINT_32)(pucPayload + 12); + WLAN_GET_FIELD_BE16(prEapol->aucKeyInfo, &u2KeyInfo); + if ((prEapol->ucType == 254) && (u2KeyInfo & MASK_2ND_EAPOL)) { + if (prStaRec->rSecInfo.fg2nd1xSend == TRUE && u2PayloadLen == 107 /* include LLC *//* u2KeyInfo & WPA_KEY_INFO_SECURE */) { + DBGLOG(RSN, INFO, ("Tx 4th EAPoL frame\r\n")); + secFsmEvent4ndEapolTxDone(prAdapter, prStaRec); + } + else if (prAdapter->rWifiVar.rAisSpecificBssInfo.fgCheckEAPoLTxDone){ + DBGLOG(RSN, INFO, ("Tx EAPoL Error report frame\r\n")); + //secFsmEventEapolTxDone(prAdapter, (UINT_32)prMsduInfo->prStaRec); + } + } + } + } + + } + #endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to initialize the pmkid parameters. +* +* \param[in] prAdapter Pointer to the Adapter structure +* +* \retval NONE +*/ +/*----------------------------------------------------------------------------*/ +VOID +secClearPmkid ( + IN P_ADAPTER_T prAdapter + ) +{ + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + DEBUGFUNC("secClearPmkid"); + + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + DBGLOG(RSN, TRACE, ("secClearPmkid\n")); + prAisSpecBssInfo->u4PmkidCandicateCount = 0; + prAisSpecBssInfo->u4PmkidCacheCount = 0; + kalMemZero((PVOID)prAisSpecBssInfo->arPmkidCandicate, sizeof(PMKID_CANDICATE_T) * CFG_MAX_PMKID_CACHE); + kalMemZero((PVOID)prAisSpecBssInfo->arPmkidCache, sizeof(PMKID_ENTRY_T) * CFG_MAX_PMKID_CACHE); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Whether WPA, or WPA2 but not WPA-None is enabled. +* +* \param[in] prAdapter Pointer to the Adapter structure +* +* \retval BOOLEAN +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +secRsnKeyHandshakeEnabled ( + IN P_ADAPTER_T prAdapter + ) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + + ASSERT(prAdapter); + + prConnSettings = &prAdapter->rWifiVar.rConnSettings; + + ASSERT(prConnSettings); + + ASSERT(prConnSettings->eEncStatus < ENUM_ENCRYPTION3_KEY_ABSENT); + + if (prConnSettings->eEncStatus == ENUM_ENCRYPTION_DISABLED) { + return FALSE; + } + + ASSERT(prConnSettings->eAuthMode < AUTH_MODE_NUM); + if ((prConnSettings->eAuthMode >= AUTH_MODE_WPA) && + (prConnSettings->eAuthMode != AUTH_MODE_WPA_NONE)) { + return TRUE; + } + + return FALSE; +} /* secRsnKeyHandshakeEnabled */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Return whether the transmit key alread installed. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] prSta Pointer the sta record +* +* \retval TRUE Default key or Transmit key installed +* FALSE Default key or Transmit key not installed +* +* \note: +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +secTransmitKeyExist ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ) +{ + ASSERT(prSta); + + if (prSta->fgTransmitKeyExist){ + return TRUE; + } + else { + return FALSE; + } +} /* secTransmitKeyExist */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Whether 802.11 privacy is enabled. +* +* \param[in] prAdapter Pointer to the Adapter structure +* +* \retval BOOLEAN +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +secEnabledInAis ( + IN P_ADAPTER_T prAdapter + ) +{ + DEBUGFUNC("secEnabled"); + + ASSERT(prAdapter->rWifiVar.rConnSettings.eEncStatus < ENUM_ENCRYPTION3_KEY_ABSENT); + + switch (prAdapter->rWifiVar.rConnSettings.eEncStatus) { + case ENUM_ENCRYPTION_DISABLED: + return FALSE; + case ENUM_ENCRYPTION1_ENABLED: + case ENUM_ENCRYPTION2_ENABLED: + case ENUM_ENCRYPTION3_ENABLED: + return TRUE; + default: + DBGLOG(RSN, TRACE, ("Unknown encryption setting %d\n", + prAdapter->rWifiVar.rConnSettings.eEncStatus)); + break; + } + return FALSE; +} /* secEnabled */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set the privacy bit at mac header for TxM +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] prMsdu the msdu for known the sta record +* +* \return TRUE the privacy need to set +* FALSE the privacy no need to set +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +secIsProtectedFrame ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsdu, + IN P_STA_RECORD_T prStaRec + ) +{ + ASSERT(prAdapter); + + ASSERT(prMsdu); + + ASSERT(prStaRec); + //prStaRec = &(g_arStaRec[prMsdu->ucStaRecIndex]); + + if (prStaRec == NULL) { + if (prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist) + return TRUE; + return FALSE; /* No privacy bit */ + } + + /* Todo:: */ + if (0 /* prMsdu->fgIs1xFrame */){ + if (IS_STA_IN_AIS(prStaRec) && + prAdapter->rWifiVar.rConnSettings.eAuthMode < AUTH_MODE_WPA) { + DBGLOG(RSN, LOUD, ("For AIS Legacy 1x, always not encryped\n")); + return FALSE; + } + else if (!prStaRec->fgTransmitKeyExist) { + DBGLOG(RSN, LOUD, ("1x Not Protected.\n")); + return FALSE; + } + else if (prStaRec->rSecInfo.fgKeyStored) { + DBGLOG(RSN, LOUD, ("1x not Protected due key stored!\n")); + return FALSE; + } + else { + DBGLOG(RSN, LOUD, ("1x Protected.\n")); + return TRUE; + } + } + else { + if (!prStaRec->fgTransmitKeyExist) { + /* whsu , check for AIS only */ + if (prAdapter->rWifiVar.rConnSettings.eAuthMode < AUTH_MODE_WPA && + prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist){ + DBGLOG(RSN, LOUD, ("Protected\n")); + return TRUE; + } + } + else { + DBGLOG(RSN, LOUD, ("Protected.\n")); + return TRUE; + } + } + + /* No sec or key is removed!!! */ + return FALSE; +} +#endif diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/rate.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/rate.c new file mode 100755 index 000000000000..9faea9d1f1d9 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/rate.c @@ -0,0 +1,591 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/mgmt/rate.c#1 $ +*/ + +/*! \file "rate.c" + \brief This file contains the transmission rate handling routines. + + This file contains the transmission rate handling routines for setting up + ACK/CTS Rate, Highest Tx Rate, Lowest Tx Rate, Initial Tx Rate and do + conversion between Rate Set and Data Rates. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: rate.c $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add rate.c. + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Update comments + * + * Nov 16 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix DBGLOG + * + * Nov 5 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +** \main\maintrunk.MT5921\12 2008-12-19 17:19:32 GMT mtk01461 +** Fix the problem that do not ASSERT the length of Supported Rate IE == 8 +** \main\maintrunk.MT5921\11 2008-12-01 18:17:42 GMT mtk01088 +** fixed the lint "possible using null pointer" warning +** \main\maintrunk.MT5921\10 2008-08-20 00:16:36 GMT mtk01461 +** Update for Driver Review +** \main\maintrunk.MT5921\9 2008-04-13 21:17:13 GMT mtk01461 +** Revise GEN Link Speed OID +** \main\maintrunk.MT5921\8 2008-03-28 10:40:13 GMT mtk01461 +** Add rateGetRateSetFromDataRates() for set desired rate OID +** \main\maintrunk.MT5921\7 2008-03-26 09:16:20 GMT mtk01461 +** Add adopt operational rate as ACK rate if BasicRateSet was not found +** Add comments +** \main\maintrunk.MT5921\6 2008-02-21 15:01:39 GMT mtk01461 +** Add initial rate according rx signal quality support +** \main\maintrunk.MT5921\5 2008-01-07 15:06:44 GMT mtk01461 +** Fix typo of rate adaptation of CtrlResp Frame +** \main\maintrunk.MT5921\4 2007-10-25 18:05:12 GMT mtk01461 +** Add VOIP SCAN Support & Refine Roaming +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* The list of valid data rates. */ +const UINT_8 aucDataRate[] = { + RATE_1M, /* RATE_1M_INDEX = 0 */ + RATE_2M, /* RATE_2M_INDEX */ + RATE_5_5M, /* RATE_5_5M_INDEX */ + RATE_11M, /* RATE_11M_INDEX */ + RATE_22M, /* RATE_22M_INDEX */ + RATE_33M, /* RATE_33M_INDEX */ + RATE_6M, /* RATE_6M_INDEX */ + RATE_9M, /* RATE_9M_INDEX */ + RATE_12M, /* RATE_12M_INDEX */ + RATE_18M, /* RATE_18M_INDEX */ + RATE_24M, /* RATE_24M_INDEX */ + RATE_36M, /* RATE_36M_INDEX */ + RATE_48M, /* RATE_48M_INDEX */ + RATE_54M, /* RATE_54M_INDEX */ + RATE_HT_PHY /* RATE_HT_PHY_INDEX */ +}; + +static const UINT_8 aucDefaultAckCtsRateIndex[RATE_NUM] = { + RATE_1M_INDEX, /* RATE_1M_INDEX = 0 */ + RATE_2M_INDEX, /* RATE_2M_INDEX */ + RATE_5_5M_INDEX, /* RATE_5_5M_INDEX */ + RATE_11M_INDEX, /* RATE_11M_INDEX */ + RATE_1M_INDEX, /* RATE_22M_INDEX - Not supported */ + RATE_1M_INDEX, /* RATE_33M_INDEX - Not supported */ + RATE_6M_INDEX, /* RATE_6M_INDEX */ + RATE_6M_INDEX, /* RATE_9M_INDEX */ + RATE_12M_INDEX, /* RATE_12M_INDEX */ + RATE_12M_INDEX, /* RATE_18M_INDEX */ + RATE_24M_INDEX, /* RATE_24M_INDEX */ + RATE_24M_INDEX, /* RATE_36M_INDEX */ + RATE_24M_INDEX, /* RATE_48M_INDEX */ + RATE_24M_INDEX /* RATE_54M_INDEX */ +}; + +const BOOLEAN afgIsOFDMRate[RATE_NUM] = { + FALSE, /* RATE_1M_INDEX = 0 */ + FALSE, /* RATE_2M_INDEX */ + FALSE, /* RATE_5_5M_INDEX */ + FALSE, /* RATE_11M_INDEX */ + FALSE, /* RATE_22M_INDEX - Not supported */ + FALSE, /* RATE_33M_INDEX - Not supported */ + TRUE, /* RATE_6M_INDEX */ + TRUE, /* RATE_9M_INDEX */ + TRUE, /* RATE_12M_INDEX */ + TRUE, /* RATE_18M_INDEX */ + TRUE, /* RATE_24M_INDEX */ + TRUE, /* RATE_36M_INDEX */ + TRUE, /* RATE_48M_INDEX */ + TRUE /* RATE_54M_INDEX */ +}; + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief Convert the given Supported Rate & Extended Supported Rate IE to the +* Operational Rate Set and Basic Rate Set, and also check if any Basic +* Rate Code is unknown by driver. +* +* @param[in] prIeSupportedRate Pointer to the Supported Rate IE +* @param[in] prIeExtSupportedRate Pointer to the Ext Supported Rate IE +* @param[out] pu2OperationalRateSet Pointer to the Operational Rate Set +* @param[out] pu2BSSBasicRateSet Pointer to the Basic Rate Set +* @param[out] pfgIsUnknownBSSBasicRate Pointer to a Flag to indicate that Basic +* Rate Set has unknown Rate Code +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +rateGetRateSetFromIEs ( + IN P_IE_SUPPORTED_RATE_T prIeSupportedRate, + IN P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate, + OUT PUINT_16 pu2OperationalRateSet, + OUT PUINT_16 pu2BSSBasicRateSet, + OUT PBOOLEAN pfgIsUnknownBSSBasicRate + ) +{ + UINT_16 u2OperationalRateSet = 0; + UINT_16 u2BSSBasicRateSet = 0; + BOOLEAN fgIsUnknownBSSBasicRate = FALSE; + UINT_8 ucRate; + UINT_32 i, j; + + + ASSERT(pu2OperationalRateSet); + ASSERT(pu2BSSBasicRateSet); + ASSERT(pfgIsUnknownBSSBasicRate); + + if (prIeSupportedRate) { + /* NOTE(Kevin): Buffalo WHR-G54S's supported rate set IE exceed 8. + * IE_LEN(pucIE) == 12, "1(B), 2(B), 5.5(B), 6(B), 9(B), 11(B), + * 12(B), 18(B), 24(B), 36(B), 48(B), 54(B)" + */ + //ASSERT(prIeSupportedRate->ucLength <= ELEM_MAX_LEN_SUP_RATES); + ASSERT(prIeSupportedRate->ucLength <= RATE_NUM); + + for (i = 0; i < prIeSupportedRate->ucLength; i++) { + ucRate = prIeSupportedRate->aucSupportedRates[i] & RATE_MASK; + + /* Search all valid data rates */ + for (j = 0; j < sizeof(aucDataRate)/sizeof(UINT_8); j++) { + if (ucRate == aucDataRate[j]) { + u2OperationalRateSet |= BIT(j); + + if (prIeSupportedRate->aucSupportedRates[i] & RATE_BASIC_BIT) { + u2BSSBasicRateSet |= BIT(j); + } + + break; + } + } + + if ((j == sizeof(aucDataRate)/sizeof(UINT_8)) && + (prIeSupportedRate->aucSupportedRates[i] & RATE_BASIC_BIT)) { + fgIsUnknownBSSBasicRate = TRUE; /* A data rate not list in the aucDataRate[] */ + } + } + } + + + if (prIeExtSupportedRate) { + //ASSERT(prIeExtSupportedRate->ucLength <= ELEM_MAX_LEN_EXTENDED_SUP_RATES); + + for (i = 0; i < prIeExtSupportedRate->ucLength; i++) { + ucRate = prIeExtSupportedRate->aucExtSupportedRates[i] & RATE_MASK; + + /* Search all valid data rates */ + for (j = 0; j < sizeof(aucDataRate)/sizeof(UINT_8); j++) { + if (ucRate == aucDataRate[j]) { + u2OperationalRateSet |= BIT(j); + + if (prIeExtSupportedRate->aucExtSupportedRates[i] & RATE_BASIC_BIT) { + u2BSSBasicRateSet |= BIT(j); + } + + break; + } + } + + if ((j == sizeof(aucDataRate)/sizeof(UINT_8)) && + (prIeExtSupportedRate->aucExtSupportedRates[i] & RATE_BASIC_BIT)) { + fgIsUnknownBSSBasicRate = TRUE; /* A data rate not list in the aucDataRate[] */ + } + } + } + + *pu2OperationalRateSet = u2OperationalRateSet; + *pu2BSSBasicRateSet = u2BSSBasicRateSet; + *pfgIsUnknownBSSBasicRate = fgIsUnknownBSSBasicRate; + + return; + +} /* end of rateGetRateSetFromIEs() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Convert the given Operational Rate Set & Basic Rate Set to the Rate Code +* Format for used in (Ext)Supportec Rate IE. +* +* @param[in] u2OperationalRateSet Operational Rate Set +* @param[in] u2BSSBasicRateSet Basic Rate Set +* @param[out] pucDataRates Pointer to the Data Rate Buffer +* @param[out] pucDataRatesLen Pointer to the Data Rate Buffer Length +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +rateGetDataRatesFromRateSet ( + IN UINT_16 u2OperationalRateSet, + IN UINT_16 u2BSSBasicRateSet, + OUT PUINT_8 pucDataRates, + OUT PUINT_8 pucDataRatesLen + ) +{ + UINT_32 i, j; + + + ASSERT(pucDataRates); + ASSERT(pucDataRatesLen); + + ASSERT(u2BSSBasicRateSet == (u2OperationalRateSet & u2BSSBasicRateSet)); + + for (i = RATE_1M_INDEX, j = 0; i < RATE_NUM; i++) { + if (u2OperationalRateSet & BIT(i)) { + + *(pucDataRates + j) = aucDataRate[i]; + + if (u2BSSBasicRateSet & BIT(i)) { + *(pucDataRates + j) |= RATE_BASIC_BIT; + } + + j++; + } + } + + *pucDataRatesLen = (UINT_8)j; + + return; + +} /* end of rateGetDataRatesFromRateSet() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Get the highest rate from given Rate Set. +* +* \param[in] u2RateSet Rate Set +* \param[out] pucHighestRateIndex Pointer to buffer of the Highest Rate Index +* +* \retval TRUE Highest Rate Index was found +* \retval FALSE Highest Rate Index was not found +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +rateGetHighestRateIndexFromRateSet ( + IN UINT_16 u2RateSet, + OUT PUINT_8 pucHighestRateIndex + ) +{ + INT_32 i; + + + ASSERT(pucHighestRateIndex); + + for (i = RATE_54M_INDEX; i >= RATE_1M_INDEX; i--) { + if (u2RateSet & BIT(i)) { + *pucHighestRateIndex = (UINT_8)i; + return TRUE; + } + } + + return FALSE; + +} /* end of rateGetHighestRateIndexFromRateSet() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Get the lowest rate from given Rate Set. +* +* \param[in] u2RateSet Rate Set +* \param[out] pucLowestRateIndex Pointer to buffer of the Lowest Rate Index +* +* \retval TRUE Lowest Rate Index was found +* \retval FALSE Lowest Rate Index was not found +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +rateGetLowestRateIndexFromRateSet ( + IN UINT_16 u2RateSet, + OUT PUINT_8 pucLowestRateIndex + ) +{ + UINT_32 i; + + ASSERT(pucLowestRateIndex); + + for (i = RATE_1M_INDEX; i <= RATE_54M_INDEX; i++) { + if (u2RateSet & BIT(i)) { + *pucLowestRateIndex = (UINT_8)i; + return TRUE; + } + } + + return FALSE; + +} /* end of rateGetLowestRateIndexFromRateSet() */ + + +#if 0 // NOTE(Kevin): For reference +/*----------------------------------------------------------------------------*/ +/*! +* \brief Convert the given Data Rates to the Rate Set. +* +* \param[in] pucDataRates Pointer to the Data Rates +* \param[in] ucDataRatesLen Length of given Data Rates +* \param[out] pu2RateSet Pointer to the Rate Set +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +rateGetRateSetFromDataRates ( + IN PUINT_8 pucDataRates, + IN UINT_8 ucDataRatesLen, + OUT PUINT_16 pu2RateSet + ) +{ + UINT_16 u2RateSet = 0; + UINT_8 ucRate; + UINT_32 i, j; + + + ASSERT(pucDataRates); + ASSERT(pu2RateSet); + + if (pucDataRates) { + for (i = 0; i < ucDataRatesLen; i++) { + ucRate = pucDataRates[i] & RATE_MASK; + + /* Search all valid data rates */ + for (j = 0; j < sizeof(aucDataRate)/sizeof(UINT_8); j++) { + if (ucRate == aucDataRate[j]) { + u2RateSet |= BIT(j); + break; + } + } + } + } + + *pu2RateSet = u2RateSet; + + return; + +} /* end of rateGetRateSetFromDataRates() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Parse the Operational Rate Set and Basic Rate Set to get the corresponding +* ACK/CTS(Respnose) TX Rates. +* +* \param[in] u2OperationalRateSet Operational Rate Set +* \param[in] u2BSSBasicRateSet Basic Rate Set +* \param[out] aucAckCtsRateIndex Pointer to the Ack/Cts Data Rate Buffer +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +rateSetAckCtsDataRatesFromRateSet ( + IN UINT_16 u2OperationalRateSet, + IN UINT_16 u2BSSBasicRateSet, + IN OUT UINT_8 aucAckCtsRateIndex[] + ) +{ + INT_32 i,j; + + + ASSERT(aucAckCtsRateIndex); + ASSERT(u2BSSBasicRateSet == (u2OperationalRateSet & u2BSSBasicRateSet)); + + /* Setup default ACK/CTS response rate */ + kalMemCopy(aucAckCtsRateIndex, (PVOID)aucDefaultAckCtsRateIndex, sizeof(aucDefaultAckCtsRateIndex)); + + + for (i = RATE_54M_INDEX; i >= RATE_1M_INDEX; i--) { + if (u2OperationalRateSet & BIT(i)) { + for (j = i; j >= RATE_1M_INDEX; j--) { + if (u2BSSBasicRateSet & BIT(j)) { + if ((afgIsOFDMRate[i] && afgIsOFDMRate[j]) || (!afgIsOFDMRate[i] && !afgIsOFDMRate[j])) // Reply ACK Frame at the same Modulation Scheme. + aucAckCtsRateIndex[i] = (UINT_8)j; + break; + } + } + + /* NOTE(Kevin 2008/03/25): Following code is used for those AP which has + * NULL BasicRateSet. + * e.g. If input Operational Rate Set = [18M 12M 9M], Basic Rate Set = NULL. + * Originally we'll get Ack Rate for [18M 12M 9M] is [12M 12M "6M"]. + * Now we'll get Ack Rate for [18M 12M 9M] is [12M 12M 9M], + * The Ack Rate for Tx Rates which are not list in Operational Rate Set is still + * use highest mandatory rate as default. + */ + if (j < RATE_1M_INDEX) { /* The ACK/CTS rate was not found in BasicRateSet */ + if (!(BIT(aucAckCtsRateIndex[i]) & u2OperationalRateSet)) { + aucAckCtsRateIndex[i] = (UINT_8)i; + } + } + } + } + + return; + +} /* end of rateSetAckCtsDataRatesFromRateSet() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Get the proper initial rate from Rate Set according to given RCPI value +* +* \param[in] u2RateSet Rate Set +* \param[in] rRcpi RCPI value from AP or Peer STA +* \param[out] pucInitialRateIndex Pointer to buffer of the initial Rate Index +* +* \retval TRUE Initial Rate Index was found +* \retval FALSE Initial Rate Index was not found +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +rateGetBestInitialRateIndex ( + IN UINT_16 u2RateSet, + IN RCPI rRcpi, + OUT PUINT_8 pucInitialRateIndex + ) +{ + UINT_16 u2InitRateSet; + INT_32 i; + + + ASSERT(pucInitialRateIndex); + + DBGLOG(MGT, TRACE, ("rRcpi = %d\n", rRcpi)); + + if (rRcpi >= RCPI_100) { /* Best Signal */ + u2InitRateSet = INITIAL_RATE_SET(RCPI_100); + } + else if (rRcpi >= RCPI_80) { /* Better Signal */ + u2InitRateSet = INITIAL_RATE_SET(RCPI_80); + } + else if (rRcpi >= RCPI_60) { /* Good Signal */ + u2InitRateSet = INITIAL_RATE_SET(RCPI_60); + } + else { /* Worse Signal */ + /* NOTE(Kevin): If return FALSE, we should assign the BSS Basic Rate Index + * (prBssInfo->ucBasicRateIndex) to the initial rate. It was determined in + * function - bssUpdateTxRateForControlFrame(). + */ + return FALSE; + } + + u2RateSet &= u2InitRateSet; + + for (i = RATE_54M_INDEX; i >= RATE_1M_INDEX; i--) { + if (u2RateSet & BIT(i)) { + *pucInitialRateIndex = (UINT_8)i; + return TRUE; + } + } + + return FALSE; + +} /* end of rateGetBestInitialRateIndex() */ +#endif + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/rlm.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/rlm.c new file mode 100755 index 000000000000..0ff9a32e3c76 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/rlm.c @@ -0,0 +1,1788 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/mgmt/rlm.c#1 $ +*/ + +/*! \file "rlm.c" + \brief + +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: rlm.c $ + * + * 11 15 2011 cm.chang + * NULL + * Check length HT cap IE about RX associate request frame + * + * 11 10 2011 cm.chang + * NULL + * Modify debug message for XLOG + * + * 11 08 2011 cm.chang + * NULL + * Add RLM and CNM debug message for XLOG + * + * 11 03 2011 cm.chang + * [WCXRP00000997] [MT6620 Wi-Fi][Driver][FW] Handle change of BSS preamble type and slot time + * Fix preamble type of STA mode + * + * 10 25 2011 cm.chang + * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode + * . + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 06 10 2011 cm.chang + * [WCXRP00000773] [MT6620 Wi-Fi][Driver] Workaround some AP fill primary channel field with its secondary channel + * If DS IE exists, ignore the primary channel field in HT OP IE + * + * 05 02 2011 cm.chang + * [WCXRP00000691] [MT6620 Wi-Fi][Driver] Workaround about AP's wrong HT capability IE to have wrong channel number + * Fix compiling error + * + * 05 02 2011 cm.chang + * [WCXRP00000691] [MT6620 Wi-Fi][Driver] Workaround about AP's wrong HT capability IE to have wrong channel number + * Refine channel number validation method + * + * 05 02 2011 cm.chang + * [WCXRP00000691] [MT6620 Wi-Fi][Driver] Workaround about AP's wrong HT capability IE to have wrong channel number + * Check if IE channel is valid before recording BSS channel number + * + * 04 14 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 04 12 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 03 29 2011 cm.chang + * [WCXRP00000606] [MT6620 Wi-Fi][Driver][FW] Fix klocwork warning + * As CR titile + * + * 03 29 2011 cm.chang + * [WCXRP00000606] [MT6620 Wi-Fi][Driver][FW] Fix klocwork warning + * As CR title + * + * 01 24 2011 cm.chang + * [WCXRP00000384] [MT6620 Wi-Fi][Driver][FW] Handle 20/40 action frame in AP mode and stop ampdu timer when sta_rec is freed + * Process received 20/40 coexistence action frame for AP mode + * + * 12 13 2010 cp.wu + * [WCXRP00000260] [MT6620 Wi-Fi][Driver][Firmware] Create V1.1 branch for both firmware and driver + * create branch for Wi-Fi driver v1.1 + * + * 12 07 2010 cm.chang + * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk + * 1. BSSINFO include RLM parameter + * 2. free all sta records when network is disconnected + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 10 15 2010 cm.chang + * [WCXRP00000094] [MT6620 Wi-Fi][Driver] Connect to 2.4GHz AP, Driver crash. + * Add exception handle when no mgmt buffer in free build + * + * 10 08 2010 cm.chang + * NULL + * When 20M only setting, ignore OBSS IE + * + * 09 16 2010 cm.chang + * NULL + * Change conditional compiling options for BOW + * + * 09 10 2010 cm.chang + * NULL + * Always update Beacon content if FW sync OBSS info + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 08 23 2010 cp.wu + * NULL + * revise constant definitions to be matched with implementation (original cmd-event definition is deprecated) + * + * 08 23 2010 chinghwa.yu + * NULL + * Temporary add rlmUpdateParamByStaForBow() and rlmBssInitForBow(). + * + * 08 23 2010 chinghwa.yu + * NULL + * Add CFG_ENABLE_BT_OVER_WIFI. + * + * 08 23 2010 chinghwa.yu + * NULL + * Update for BOW. + * + * 08 20 2010 cm.chang + * NULL + * Migrate RLM code to host from FW + * + * 08 02 2010 yuche.tsai + * NULL + * P2P Group Negotiation Code Check in. + * + * 07 26 2010 yuche.tsai + * + * Fix compile error while enabling WiFi Direct function. + * + * 07 21 2010 yuche.tsai + * + * Add P2P Scan & Scan Result Parsing & Saving. + * + * 07 19 2010 cm.chang + * + * Set RLM parameters and enable CNM channel manager + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * take use of RLM module for parsing/generating HT IEs for 11n capability + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Check draft RLM code for HT cap + * + * 06 05 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Fix channel ID definition in RFB status to primary channel instead of center channel + * + * 06 02 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add TX short GI compiling option + * + * 06 02 2010 chinghwa.yu + * [BORA00000563]Add WiFi CoEx BCM module + * Roll back to remove CFG_SUPPORT_BCM_TEST. + * + * 06 01 2010 chinghwa.yu + * [BORA00000563]Add WiFi CoEx BCM module + * Update BCM Test and RW configuration. + * + * 05 31 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add some compiling options to control 11n functions + * + * 05 28 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Set RTS threshold of 2K bytes initially + * + * 05 18 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Ad-hoc Beacon should not carry HT OP and OBSS IEs + * + * 05 07 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Process 20/40 coexistence public action frame in AP mode + * + * 05 05 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * First draft support for 20/40M bandwidth for AP mode + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW + * + * 04 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * First draft code to support protection in AP mode + * + * 04 13 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Utilize status of swRfb to know channel number and band + * + * 04 07 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Different invoking order for WTBL entry of associated AP + * + * 04 07 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add virtual test for OBSS scan + * + * 04 02 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Process Beacon only ready for infra STA now + * + * 03 30 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support 2.4G OBSS scan + * + * 03 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Not carry HT cap when being associated with b/g only AP + * + * 03 24 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * fixed some WHQL testing error. + * + * 03 15 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Provide draft measurement and quiet functions + * + * 03 09 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * If bss is not 11n network, zero WTBL HT parameters + * + * 03 03 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * To support CFG_SUPPORT_BCM_STP + * + * 03 02 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Generate HT IE only depending on own phyTypeSet + * + * 03 02 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Not fill HT related IE if BssInfo does not include 11n phySet + * + * 03 01 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * To store field AMPDU Parameters in STA_REC + * + * 02 26 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Enable RDG RX, but disable RDG TX for IOT and LongNAV + * + * 02 12 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Use bss info array for concurrent handle + * + * 02 05 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * 01 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support protection and bandwidth switch + * + * 01 07 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Modify the parameter of rlmRecAssocRspHtInfo function + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Dec 12 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix prBssInfo->ucPrimaryChannel handle for assoc resp + * + * Dec 9 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add some function to process HT operation + * + * Nov 28 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Call rlmStatisticsInit() to handle MIB counters + * + * Nov 18 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static VOID +rlmFillHtCapIE ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_MSDU_INFO_T prMsduInfo + ); + +static VOID +rlmFillExtCapIE ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_MSDU_INFO_T prMsduInfo + ); + +static VOID +rlmFillHtOpIE ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_MSDU_INFO_T prMsduInfo + ); + +static UINT_8 +rlmRecIeInfoForClient ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + PUINT_8 pucIE, + UINT_16 u2IELength + ); + +static BOOLEAN +rlmRecBcnFromNeighborForClient ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_SW_RFB_T prSwRfb, + PUINT_8 pucIE, + UINT_16 u2IELength + ); + +static BOOLEAN +rlmRecBcnInfoForClient ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_SW_RFB_T prSwRfb, + PUINT_8 pucIE, + UINT_16 u2IELength + ); + +static VOID +rlmBssReset ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmFsmEventInit ( + P_ADAPTER_T prAdapter + ) +{ + ASSERT(prAdapter); + + /* Note: assume TIMER_T structures are reset to zero or stopped + * before invoking this function. + */ + + /* Initialize OBSS FSM */ + rlmObssInit(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmFsmEventUninit ( + P_ADAPTER_T prAdapter + ) +{ + P_BSS_INFO_T prBssInfo; + UINT_8 ucNetIdx; + + ASSERT(prAdapter); + + RLM_NET_FOR_EACH(ucNetIdx) { + prBssInfo = &prAdapter->rWifiVar.arBssInfo[ucNetIdx]; + ASSERT(prBssInfo); + + /* Note: all RLM timers will also be stopped. + * Now only one OBSS scan timer. + */ + rlmBssReset(prAdapter, prBssInfo); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief For probe request, association request +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmReqGenerateHtCapIE ( + P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo + ) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; + ASSERT(prBssInfo); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11N) && + (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N))) { + + rlmFillHtCapIE(prAdapter, prBssInfo, prMsduInfo); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief For probe request, association request +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmReqGenerateExtCapIE ( + P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo + ) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; + ASSERT(prBssInfo); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11N) && + (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N))) { + + rlmFillExtCapIE(prAdapter, prBssInfo, prMsduInfo); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief For probe response (GO, IBSS) and association response +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmRspGenerateHtCapIE ( + P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo + ) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + ASSERT(IS_NET_ACTIVE(prAdapter, prMsduInfo->ucNetworkType)); + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; + ASSERT(prBssInfo); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if (RLM_NET_IS_11N(prBssInfo) && + (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N))) { + + rlmFillHtCapIE(prAdapter, prBssInfo, prMsduInfo); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief For probe response (GO, IBSS) and association response +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmRspGenerateExtCapIE ( + P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo + ) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + ASSERT(IS_NET_ACTIVE(prAdapter, prMsduInfo->ucNetworkType)); + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; + ASSERT(prBssInfo); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if (RLM_NET_IS_11N(prBssInfo) && + (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N))) { + + rlmFillExtCapIE(prAdapter, prBssInfo, prMsduInfo); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief For probe response (GO, IBSS) and association response +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmRspGenerateHtOpIE ( + P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo + ) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + ASSERT(IS_NET_ACTIVE(prAdapter, prMsduInfo->ucNetworkType)); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; + ASSERT(prBssInfo); + + if (RLM_NET_IS_11N(prBssInfo) && + (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N))) { + + rlmFillHtOpIE(prAdapter, prBssInfo, prMsduInfo); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief For probe response (GO, IBSS) and association response +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmRspGenerateErpIE ( + P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo + ) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + P_IE_ERP_T prErpIe; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + ASSERT(IS_NET_ACTIVE(prAdapter, prMsduInfo->ucNetworkType)); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; + ASSERT(prBssInfo); + + if (RLM_NET_IS_11GN(prBssInfo) && prBssInfo->eBand == BAND_2G4 && + (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11GN))) { + prErpIe = (P_IE_ERP_T) + (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); + + /* Add ERP IE */ + prErpIe->ucId = ELEM_ID_ERP_INFO; + prErpIe->ucLength = 1; + + prErpIe->ucERP = prBssInfo->fgObssErpProtectMode ? + ERP_INFO_USE_PROTECTION : 0; + + if (prBssInfo->fgErpProtectMode) { + prErpIe->ucERP |= + (ERP_INFO_NON_ERP_PRESENT | ERP_INFO_USE_PROTECTION); + } + + /* Handle barker preamble */ + if (!prBssInfo->fgUseShortPreamble) { + prErpIe->ucERP |= ERP_INFO_BARKER_PREAMBLE_MODE; + } + + ASSERT(IE_SIZE(prErpIe) <= (ELEM_HDR_LEN+ ELEM_MAX_LEN_ERP)); + + prMsduInfo->u2FrameLength += IE_SIZE(prErpIe); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +static VOID +rlmFillHtCapIE ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_MSDU_INFO_T prMsduInfo + ) +{ + P_IE_HT_CAP_T prHtCap; + P_SUP_MCS_SET_FIELD prSupMcsSet; + BOOLEAN fg40mAllowed; + + ASSERT(prAdapter); + ASSERT(prBssInfo); + ASSERT(prMsduInfo); + + fg40mAllowed = prBssInfo->fgAssoc40mBwAllowed; + + prHtCap = (P_IE_HT_CAP_T) + (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); + + /* Add HT capabilities IE */ + prHtCap->ucId = ELEM_ID_HT_CAP; + prHtCap->ucLength = sizeof(IE_HT_CAP_T) - ELEM_HDR_LEN; + + prHtCap->u2HtCapInfo = HT_CAP_INFO_DEFAULT_VAL; + if (!fg40mAllowed) { + prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_DSSS_CCK_IN_40M); + } + if (prAdapter->rWifiVar.rConnSettings.fgRxShortGIDisabled) { + prHtCap->u2HtCapInfo &= + ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M); + } + + prHtCap->ucAmpduParam = AMPDU_PARAM_DEFAULT_VAL; + + prSupMcsSet = &prHtCap->rSupMcsSet; + kalMemZero((PVOID)&prSupMcsSet->aucRxMcsBitmask[0], + SUP_MCS_RX_BITMASK_OCTET_NUM); + + prSupMcsSet->aucRxMcsBitmask[0] = BITS(0, 7); + + if (fg40mAllowed) { + prSupMcsSet->aucRxMcsBitmask[32/8] = BIT(0); /* MCS32 */ + } + prSupMcsSet->u2RxHighestSupportedRate = SUP_MCS_RX_DEFAULT_HIGHEST_RATE; + prSupMcsSet->u4TxRateInfo = SUP_MCS_TX_DEFAULT_VAL; + + prHtCap->u2HtExtendedCap = HT_EXT_CAP_DEFAULT_VAL; + if (!fg40mAllowed || prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) { + prHtCap->u2HtExtendedCap &= + ~(HT_EXT_CAP_PCO | HT_EXT_CAP_PCO_TRANS_TIME_NONE); + } + + prHtCap->u4TxBeamformingCap = TX_BEAMFORMING_CAP_DEFAULT_VAL; + + prHtCap->ucAselCap = ASEL_CAP_DEFAULT_VAL; + + + ASSERT(IE_SIZE(prHtCap) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP)); + + prMsduInfo->u2FrameLength += IE_SIZE(prHtCap); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +static VOID +rlmFillExtCapIE ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_MSDU_INFO_T prMsduInfo + ) +{ + P_EXT_CAP_T prExtCap; + BOOLEAN fg40mAllowed; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + fg40mAllowed = prBssInfo->fgAssoc40mBwAllowed; + + /* Add Extended Capabilities IE */ + prExtCap = (P_EXT_CAP_T) + (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); + + prExtCap->ucId = ELEM_ID_EXTENDED_CAP; + prExtCap->ucLength = 1; + prExtCap->aucCapabilities[0] = ELEM_EXT_CAP_DEFAULT_VAL; + + if (!fg40mAllowed) { + prExtCap->aucCapabilities[0] &= ~ELEM_EXT_CAP_20_40_COEXIST_SUPPORT; + } + + if (prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) { + prExtCap->aucCapabilities[0] &= ~ELEM_EXT_CAP_PSMP_CAP; + } + + ASSERT(IE_SIZE(prExtCap) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP)); + + prMsduInfo->u2FrameLength += IE_SIZE(prExtCap); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +static VOID +rlmFillHtOpIE ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_MSDU_INFO_T prMsduInfo + ) +{ + P_IE_HT_OP_T prHtOp; + UINT_16 i; + + ASSERT(prAdapter); + ASSERT(prBssInfo); + ASSERT(prMsduInfo); + + prHtOp = (P_IE_HT_OP_T) + (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); + + /* Add HT operation IE */ + prHtOp->ucId = ELEM_ID_HT_OP; + prHtOp->ucLength = sizeof(IE_HT_OP_T) - ELEM_HDR_LEN; + + /* RIFS and 20/40 bandwidth operations are included */ + prHtOp->ucPrimaryChannel = prBssInfo->ucPrimaryChannel; + prHtOp->ucInfo1 = prBssInfo->ucHtOpInfo1; + + /* Decide HT protection mode field */ + if (prBssInfo->eHtProtectMode == HT_PROTECT_MODE_NON_HT) { + prHtOp->u2Info2 = (UINT_8) HT_PROTECT_MODE_NON_HT; + } + else if (prBssInfo->eObssHtProtectMode == HT_PROTECT_MODE_NON_MEMBER) { + prHtOp->u2Info2 = (UINT_8) HT_PROTECT_MODE_NON_MEMBER; + } + else { + /* It may be SYS_PROTECT_MODE_NONE or SYS_PROTECT_MODE_20M */ + prHtOp->u2Info2 = (UINT_8) prBssInfo->eHtProtectMode; + } + + if (prBssInfo->eGfOperationMode != GF_MODE_NORMAL) { + /* It may be GF_MODE_PROTECT or GF_MODE_DISALLOWED + * Note: it will also be set in ad-hoc network + */ + prHtOp->u2Info2 |= HT_OP_INFO2_NON_GF_HT_STA_PRESENT; + } + + if (0 /* Regulatory class 16 */ && + prBssInfo->eObssHtProtectMode == HT_PROTECT_MODE_NON_MEMBER) { + /* (TBD) It is HT_PROTECT_MODE_NON_MEMBER, so require protection + * although it is possible to have no protection by spec. + */ + prHtOp->u2Info2 |= HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT; + } + + prHtOp->u2Info3 = prBssInfo->u2HtOpInfo3; /* To do: handle L-SIG TXOP */ + + /* No basic MCSx are needed temporarily */ + for (i = 0; i < 16; i++) { + prHtOp->aucBasicMcsSet[i] = 0; + } + + ASSERT(IE_SIZE(prHtOp) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP)); + + prMsduInfo->u2FrameLength += IE_SIZE(prHtOp); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function should be invoked to update parameters of associated AP. +* (Association response and Beacon) +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +static UINT_8 +rlmRecIeInfoForClient ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + PUINT_8 pucIE, + UINT_16 u2IELength + ) +{ + UINT_16 u2Offset; + P_STA_RECORD_T prStaRec; + P_IE_HT_CAP_T prHtCap; + P_IE_HT_OP_T prHtOp; + P_IE_OBSS_SCAN_PARAM_T prObssScnParam; + UINT_8 ucERP, ucPrimaryChannel; +#if CFG_SUPPORT_QUIET && 0 + BOOLEAN fgHasQuietIE = FALSE; +#endif + + ASSERT(prAdapter); + ASSERT(prBssInfo); + ASSERT(pucIE); + + prStaRec = prBssInfo->prStaRecOfAP; + ASSERT(prStaRec); + if (!prStaRec) { + return 0; + } + + prBssInfo->fgUseShortPreamble = prBssInfo->fgIsShortPreambleAllowed; + ucPrimaryChannel = 0; + prObssScnParam = NULL; + + /* Note: HT-related members in staRec may not be zero before, so + * if following IE does not exist, they are still not zero. + * These HT-related parameters are vaild only when the corresponding + * BssInfo supports 802.11n, i.e., RLM_NET_IS_11N() + */ + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_HT_CAP: + if (!RLM_NET_IS_11N(prBssInfo) || + IE_LEN(pucIE) != (sizeof(IE_HT_CAP_T) - 2)) { + break; + } + prHtCap = (P_IE_HT_CAP_T) pucIE; + prStaRec->ucMcsSet = prHtCap->rSupMcsSet.aucRxMcsBitmask[0]; + prStaRec->fgSupMcs32 = + (prHtCap->rSupMcsSet.aucRxMcsBitmask[32/8] & BIT(0)) ? + TRUE : FALSE; + + prStaRec->u2HtCapInfo = prHtCap->u2HtCapInfo; + prStaRec->ucAmpduParam = prHtCap->ucAmpduParam; + prStaRec->u2HtExtendedCap = prHtCap->u2HtExtendedCap; + prStaRec->u4TxBeamformingCap = prHtCap->u4TxBeamformingCap; + prStaRec->ucAselCap = prHtCap->ucAselCap; + break; + + case ELEM_ID_HT_OP: + if (!RLM_NET_IS_11N(prBssInfo) || + IE_LEN(pucIE) != (sizeof(IE_HT_OP_T) - 2)) { + break; + } + prHtOp = (P_IE_HT_OP_T) pucIE; + /* Workaround that some APs fill primary channel field by its + * secondary channel, but its DS IE is correct 20110610 + */ + if (ucPrimaryChannel == 0) { + ucPrimaryChannel = prHtOp->ucPrimaryChannel; + } + prBssInfo->ucHtOpInfo1 = prHtOp->ucInfo1; + prBssInfo->u2HtOpInfo2 = prHtOp->u2Info2; + prBssInfo->u2HtOpInfo3 = prHtOp->u2Info3; + + if (!prBssInfo->fg40mBwAllowed) { + prBssInfo->ucHtOpInfo1 &= + ~(HT_OP_INFO1_SCO | HT_OP_INFO1_STA_CHNL_WIDTH); + } + + if ((prBssInfo->ucHtOpInfo1 & HT_OP_INFO1_SCO) != CHNL_EXT_RES) { + prBssInfo->eBssSCO = (ENUM_CHNL_EXT_T) + (prBssInfo->ucHtOpInfo1 & HT_OP_INFO1_SCO); + } + + prBssInfo->eHtProtectMode = (ENUM_HT_PROTECT_MODE_T) + (prBssInfo->u2HtOpInfo2 & HT_OP_INFO2_HT_PROTECTION); + + /* To do: process regulatory class 16 */ + if ((prBssInfo->u2HtOpInfo2 & HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT) + && 0 /* && regulatory class is 16 */) { + prBssInfo->eGfOperationMode = GF_MODE_DISALLOWED; + } + else if (prBssInfo->u2HtOpInfo2&HT_OP_INFO2_NON_GF_HT_STA_PRESENT) { + prBssInfo->eGfOperationMode = GF_MODE_PROTECT; + } + else { + prBssInfo->eGfOperationMode = GF_MODE_NORMAL; + } + + prBssInfo->eRifsOperationMode = + (prBssInfo->ucHtOpInfo1 & HT_OP_INFO1_RIFS_MODE) ? + RIFS_MODE_NORMAL : RIFS_MODE_DISALLOWED; + + break; + + case ELEM_ID_20_40_BSS_COEXISTENCE: + if (!RLM_NET_IS_11N(prBssInfo)) { + break; + } + /* To do: store if scanning exemption grant to BssInfo */ + break; + + case ELEM_ID_OBSS_SCAN_PARAMS: + if (!RLM_NET_IS_11N(prBssInfo) || + IE_LEN(pucIE) != (sizeof(IE_OBSS_SCAN_PARAM_T) - 2)) { + break; + } + /* Store OBSS parameters to BssInfo */ + prObssScnParam = (P_IE_OBSS_SCAN_PARAM_T) pucIE; + break; + + case ELEM_ID_EXTENDED_CAP: + if (!RLM_NET_IS_11N(prBssInfo)) { + break; + } + /* To do: store extended capability (PSMP, coexist) to BssInfo */ + break; + + case ELEM_ID_ERP_INFO: + if (IE_LEN(pucIE) != (sizeof(IE_ERP_T) - 2) || + prBssInfo->eBand != BAND_2G4) { + break; + } + ucERP = ERP_INFO_IE(pucIE)->ucERP; + prBssInfo->fgErpProtectMode = + (ucERP & ERP_INFO_USE_PROTECTION) ? TRUE : FALSE; + + if (ucERP & ERP_INFO_BARKER_PREAMBLE_MODE) { + prBssInfo->fgUseShortPreamble = FALSE; + } + break; + + case ELEM_ID_DS_PARAM_SET: + if (IE_LEN(pucIE) == ELEM_MAX_LEN_DS_PARAMETER_SET) { + ucPrimaryChannel = DS_PARAM_IE(pucIE)->ucCurrChnl; + } + break; + + #if CFG_SUPPORT_QUIET && 0 + /* Note: RRM code should be moved to independent RRM function by + * component design rule. But we attach it to RLM temporarily + */ + case ELEM_ID_QUIET: + rrmQuietHandleQuietIE(prBssInfo, (P_IE_QUIET_T) pucIE); + fgHasQuietIE = TRUE; + break; + #endif + default: + break; + } /* end of switch */ + } /* end of IE_FOR_EACH */ + + /* Some AP will have wrong channel number (255) when running time. + * Check if correct channel number information. 20110501 + */ + if ((prBssInfo->eBand == BAND_2G4 && ucPrimaryChannel > 14) || + (prBssInfo->eBand != BAND_2G4 && (ucPrimaryChannel >= 200 || + ucPrimaryChannel <= 14))) { + ucPrimaryChannel = 0; + } + +#if CFG_SUPPORT_QUIET && 0 + if (!fgHasQuietIE) { + rrmQuietIeNotExist(prAdapter, prBssInfo); + } +#endif + + /* Check if OBSS scan process will launch */ + if (!prAdapter->fgEnOnlineScan || !prObssScnParam || + !(prStaRec->u2HtCapInfo & HT_CAP_INFO_SUP_CHNL_WIDTH) || + prBssInfo->eBand != BAND_2G4 || !prBssInfo->fg40mBwAllowed) { + + /* Note: it is ok not to stop rObssScanTimer() here */ + prBssInfo->u2ObssScanInterval = 0; + } + else { + if (prObssScnParam->u2TriggerScanInterval < OBSS_SCAN_MIN_INTERVAL) { + prObssScnParam->u2TriggerScanInterval = OBSS_SCAN_MIN_INTERVAL; + } + if (prBssInfo->u2ObssScanInterval != + prObssScnParam->u2TriggerScanInterval) { + + prBssInfo->u2ObssScanInterval = + prObssScnParam->u2TriggerScanInterval; + + /* Start timer to trigger OBSS scanning */ + cnmTimerStartTimer(prAdapter, &prBssInfo->rObssScanTimer, + prBssInfo->u2ObssScanInterval * MSEC_PER_SEC); + } + } + + return ucPrimaryChannel; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief AIS or P2P GC. +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +static BOOLEAN +rlmRecBcnFromNeighborForClient ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_SW_RFB_T prSwRfb, + PUINT_8 pucIE, + UINT_16 u2IELength + ) +{ + UINT_16 u2Offset, i; + UINT_8 ucPriChannel, ucSecChannel; + ENUM_CHNL_EXT_T eSCO; + BOOLEAN fgHtBss, fg20mReq; + + ASSERT(prAdapter); + ASSERT(prBssInfo && prSwRfb); + ASSERT(pucIE); + + /* Record it to channel list to change 20/40 bandwidth */ + ucPriChannel = 0; + eSCO = CHNL_EXT_SCN; + + fgHtBss = FALSE; + fg20mReq = FALSE; + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_HT_CAP: + { + P_IE_HT_CAP_T prHtCap; + + if (IE_LEN(pucIE) != (sizeof(IE_HT_CAP_T) - 2)) { + break; + } + + prHtCap = (P_IE_HT_CAP_T) pucIE; + if (prHtCap->u2HtCapInfo & HT_CAP_INFO_40M_INTOLERANT) { + fg20mReq = TRUE; + } + fgHtBss = TRUE; + break; + } + case ELEM_ID_HT_OP: + { + P_IE_HT_OP_T prHtOp; + + if (IE_LEN(pucIE) != (sizeof(IE_HT_OP_T) - 2)) { + break; + } + + prHtOp = (P_IE_HT_OP_T) pucIE; + /* Workaround that some APs fill primary channel field by its + * secondary channel, but its DS IE is correct 20110610 + */ + if (ucPriChannel == 0) { + ucPriChannel = prHtOp->ucPrimaryChannel; + } + + if ((prHtOp->ucInfo1 & HT_OP_INFO1_SCO) != CHNL_EXT_RES) { + eSCO = (ENUM_CHNL_EXT_T) (prHtOp->ucInfo1 & HT_OP_INFO1_SCO); + } + break; + } + case ELEM_ID_20_40_BSS_COEXISTENCE: + { + P_IE_20_40_COEXIST_T prCoexist; + + if (IE_LEN(pucIE) != (sizeof(IE_20_40_COEXIST_T) - 2)) { + break; + } + + prCoexist = (P_IE_20_40_COEXIST_T) pucIE; + if (prCoexist->ucData & BSS_COEXIST_40M_INTOLERANT) { + fg20mReq = TRUE; + } + break; + } + case ELEM_ID_DS_PARAM_SET: + if (IE_LEN(pucIE) != (sizeof(IE_DS_PARAM_SET_T) - 2)) { + break; + } + ucPriChannel = DS_PARAM_IE(pucIE)->ucCurrChnl; + break; + + default: + break; + } + } + + + /* To do: Update channel list and 5G band. All channel lists have the same + * update procedure. We should give it the entry pointer of desired + * channel list. + */ + if (HIF_RX_HDR_GET_RF_BAND(prSwRfb->prHifRxHdr) != BAND_2G4) { + return FALSE; + } + + if (ucPriChannel == 0 || ucPriChannel > 14) { + ucPriChannel = HIF_RX_HDR_GET_CHNL_NUM(prSwRfb->prHifRxHdr); + } + + if (fgHtBss) { + ASSERT(prBssInfo->auc2G_PriChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_PriChnlList[0] && + i <= CHNL_LIST_SZ_2G; i++) { + if (prBssInfo->auc2G_PriChnlList[i] == ucPriChannel) { + break; + } + } + if ((i > prBssInfo->auc2G_PriChnlList[0]) && (i <= CHNL_LIST_SZ_2G)) { + prBssInfo->auc2G_PriChnlList[i] = ucPriChannel; + prBssInfo->auc2G_PriChnlList[0]++; + } + + /* Update secondary channel */ + if (eSCO != CHNL_EXT_SCN) { + ucSecChannel = (eSCO == CHNL_EXT_SCA) ? + (ucPriChannel + 4) : (ucPriChannel - 4); + + ASSERT(prBssInfo->auc2G_SecChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_SecChnlList[0] && + i <= CHNL_LIST_SZ_2G; i++) { + if (prBssInfo->auc2G_SecChnlList[i] == ucSecChannel) { + break; + } + } + if ((i > prBssInfo->auc2G_SecChnlList[0])&& (i <= CHNL_LIST_SZ_2G)){ + prBssInfo->auc2G_SecChnlList[i] = ucSecChannel; + prBssInfo->auc2G_SecChnlList[0]++; + } + } + + /* Update 20M bandwidth request channels */ + if (fg20mReq) { + ASSERT(prBssInfo->auc2G_20mReqChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_20mReqChnlList[0] && + i <= CHNL_LIST_SZ_2G; i++) { + if (prBssInfo->auc2G_20mReqChnlList[i] == ucPriChannel) { + break; + } + } + if ((i > prBssInfo->auc2G_20mReqChnlList[0]) && + (i <= CHNL_LIST_SZ_2G)){ + prBssInfo->auc2G_20mReqChnlList[i] = ucPriChannel; + prBssInfo->auc2G_20mReqChnlList[0]++; + } + } + } + else { + /* Update non-HT channel list */ + ASSERT(prBssInfo->auc2G_NonHtChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_NonHtChnlList[0] && + i <= CHNL_LIST_SZ_2G; i++) { + if (prBssInfo->auc2G_NonHtChnlList[i] == ucPriChannel) { + break; + } + } + if ((i > prBssInfo->auc2G_NonHtChnlList[0]) && (i <= CHNL_LIST_SZ_2G)) { + prBssInfo->auc2G_NonHtChnlList[i] = ucPriChannel; + prBssInfo->auc2G_NonHtChnlList[0]++; + } + + } + + return FALSE; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief AIS or P2P GC. +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +static BOOLEAN +rlmRecBcnInfoForClient ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_SW_RFB_T prSwRfb, + PUINT_8 pucIE, + UINT_16 u2IELength + ) +{ + ASSERT(prAdapter); + ASSERT(prBssInfo && prSwRfb); + ASSERT(pucIE); + +#if 0 /* SW migration 2010/8/20 */ + /* Note: we shall not update parameters when scanning, otherwise + * channel and bandwidth will not be correct or asserted failure + * during scanning. + * Note: remove channel checking. All received Beacons should be processed + * if measurement or other actions are executed in adjacent channels + * and Beacon content checking mechanism is not disabled. + */ + if (IS_SCAN_ACTIVE() + /* || prBssInfo->ucPrimaryChannel != CHNL_NUM_BY_SWRFB(prSwRfb) */) { + return FALSE; + } +#endif + + /* Handle change of slot time */ + prBssInfo->u2CapInfo = + ((P_WLAN_BEACON_FRAME_T)(prSwRfb->pvHeader))->u2CapInfo; + prBssInfo->fgUseShortSlotTime = + (prBssInfo->u2CapInfo & CAP_INFO_SHORT_SLOT_TIME) ? TRUE : FALSE; + + rlmRecIeInfoForClient(prAdapter, prBssInfo, pucIE, u2IELength); + + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmProcessBcn ( + P_ADAPTER_T prAdapter, + P_SW_RFB_T prSwRfb, + PUINT_8 pucIE, + UINT_16 u2IELength + ) +{ + P_BSS_INFO_T prBssInfo; + BOOLEAN fgNewParameter; + UINT_8 ucNetIdx; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + ASSERT(pucIE); + + fgNewParameter = FALSE; + + /* When concurrent networks exist, GO shall have the same handle as + * the other BSS, so the Beacon shall be procesed for bandwidth and + * protection mechanism. + * Note1: we do not have 2 AP (GO) cases simultaneously now. + * Note2: If we are GO, concurrent AIS AP should detect it and reflect + * action in its Beacon, so AIS STA just follows Beacon from AP. + */ + RLM_NET_FOR_EACH_NO_BOW(ucNetIdx) { + prBssInfo = &prAdapter->rWifiVar.arBssInfo[ucNetIdx]; + ASSERT(prBssInfo); + + if (IS_BSS_ACTIVE(prBssInfo)) { + if (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE && + prBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + /* P2P client or AIS infra STA */ + if (EQUAL_MAC_ADDR(prBssInfo->aucBSSID, + ((P_WLAN_MAC_MGMT_HEADER_T) + (prSwRfb->pvHeader))->aucBSSID)) { + + fgNewParameter = rlmRecBcnInfoForClient(prAdapter, + prBssInfo, prSwRfb, pucIE, u2IELength); + } + else { + fgNewParameter = rlmRecBcnFromNeighborForClient(prAdapter, + prBssInfo, prSwRfb, pucIE, u2IELength); + } + } + #if CFG_ENABLE_WIFI_DIRECT + else if (prAdapter->fgIsP2PRegistered && + (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT || + prBssInfo->eCurrentOPMode == OP_MODE_P2P_DEVICE)) { + /* AP scan to check if 20/40M bandwidth is permitted */ + rlmRecBcnFromNeighborForClient(prAdapter, + prBssInfo, prSwRfb, pucIE, u2IELength); + } + #endif + else if (prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { + /* To do: Ad-hoc */ + } + + /* Appy new parameters if necessary */ + if (fgNewParameter) { + rlmSyncOperationParams(prAdapter, prBssInfo); + fgNewParameter = FALSE; + } + } /* end of IS_BSS_ACTIVE() */ + } /* end of RLM_NET_FOR_EACH_NO_BOW */ +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function should be invoked after judging successful association. +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmProcessAssocRsp ( + P_ADAPTER_T prAdapter, + P_SW_RFB_T prSwRfb, + PUINT_8 pucIE, + UINT_16 u2IELength + ) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + UINT_8 ucPriChannel; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + ASSERT(pucIE); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + ASSERT(prStaRec); + if (!prStaRec) { + return; + } + ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; + ASSERT(prStaRec == prBssInfo->prStaRecOfAP); + + /* To do: the invoked function is used to clear all members. It may be + * done by center mechanism in invoker. + */ + rlmBssReset(prAdapter, prBssInfo); + + prBssInfo->fgUseShortSlotTime = + (prBssInfo->u2CapInfo & CAP_INFO_SHORT_SLOT_TIME) ? TRUE : FALSE; + + if ((ucPriChannel = + rlmRecIeInfoForClient(prAdapter, prBssInfo, pucIE, u2IELength)) > 0) { + prBssInfo->ucPrimaryChannel = ucPriChannel; + } + + if (!RLM_NET_IS_11N(prBssInfo) || + !(prStaRec->u2HtCapInfo & HT_CAP_INFO_SUP_CHNL_WIDTH)) { + prBssInfo->fg40mBwAllowed = FALSE; + } + + /* Note: Update its capabilities to WTBL by cnmStaRecChangeState(), which + * shall be invoked afterwards. + * Update channel, bandwidth and protection mode by nicUpdateBss() + */ +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function should be invoked after judging successful association. +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmFillSyncCmdParam ( + P_CMD_SET_BSS_RLM_PARAM_T prCmdBody, + P_BSS_INFO_T prBssInfo + ) +{ + ASSERT(prCmdBody && prBssInfo); + if (!prCmdBody || !prBssInfo) { + return; + } + + prCmdBody->ucNetTypeIndex = prBssInfo->ucNetTypeIndex; + prCmdBody->ucRfBand = (UINT_8) prBssInfo->eBand; + prCmdBody->ucPrimaryChannel = prBssInfo->ucPrimaryChannel; + prCmdBody->ucRfSco = (UINT_8) prBssInfo->eBssSCO; + prCmdBody->ucErpProtectMode = (UINT_8) prBssInfo->fgErpProtectMode; + prCmdBody->ucHtProtectMode = (UINT_8) prBssInfo->eHtProtectMode; + prCmdBody->ucGfOperationMode = (UINT_8) prBssInfo->eGfOperationMode; + prCmdBody->ucTxRifsMode = (UINT_8) prBssInfo->eRifsOperationMode; + prCmdBody->u2HtOpInfo3 = prBssInfo->u2HtOpInfo3; + prCmdBody->u2HtOpInfo2 = prBssInfo->u2HtOpInfo2; + prCmdBody->ucHtOpInfo1 = prBssInfo->ucHtOpInfo1; + prCmdBody->ucUseShortPreamble = prBssInfo->fgUseShortPreamble; + prCmdBody->ucUseShortSlotTime = prBssInfo->fgUseShortSlotTime; + prCmdBody->ucCheckId = 0x72; + + if (RLM_NET_PARAM_VALID(prBssInfo)) { + DBGLOG(RLM, INFO, ("N=%d b=%d c=%d s=%d e=%d h=%d I=0x%02x l=%d p=%d\n", + prCmdBody->ucNetTypeIndex, prCmdBody->ucRfBand, + prCmdBody->ucPrimaryChannel, prCmdBody->ucRfSco, + prCmdBody->ucErpProtectMode, prCmdBody->ucHtProtectMode, + prCmdBody->ucHtOpInfo1, prCmdBody->ucUseShortSlotTime, + prCmdBody->ucUseShortPreamble)); + } + else { + DBGLOG(RLM, INFO, ("N=%d closed\n", prCmdBody->ucNetTypeIndex)); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will operation parameters based on situations of +* concurrent networks. Channel, bandwidth, protection mode, supported +* rate will be modified. +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmSyncOperationParams ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo + ) +{ + P_CMD_SET_BSS_RLM_PARAM_T prCmdBody; + WLAN_STATUS rStatus; + + ASSERT(prAdapter); + ASSERT(prBssInfo); + + prCmdBody = (P_CMD_SET_BSS_RLM_PARAM_T) + cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_SET_BSS_RLM_PARAM_T)); + ASSERT(prCmdBody); + + /* To do: exception handle */ + if (!prCmdBody) { + DBGLOG(RLM, WARN, ("No buf for sync RLM params (Net=%d)\n", + prBssInfo->ucNetTypeIndex)); + return; + } + + rlmFillSyncCmdParam(prCmdBody, prBssInfo); + + rStatus = wlanSendSetQueryCmd ( + prAdapter, /* prAdapter */ + CMD_ID_SET_BSS_RLM_PARAM, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_SET_BSS_RLM_PARAM_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdBody, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + ASSERT(rStatus == WLAN_STATUS_PENDING); + + cnmMemFree(prAdapter, prCmdBody); +} + +#if CFG_SUPPORT_AAA +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function should be invoked after judging successful association. +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmProcessAssocReq ( + P_ADAPTER_T prAdapter, + P_SW_RFB_T prSwRfb, + PUINT_8 pucIE, + UINT_16 u2IELength + ) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + UINT_16 u2Offset; + P_IE_HT_CAP_T prHtCap; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + ASSERT(pucIE); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + ASSERT(prStaRec); + if (!prStaRec) { + return; + } + ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_HT_CAP: + if (!RLM_NET_IS_11N(prBssInfo) || + IE_LEN(pucIE) != (sizeof(IE_HT_CAP_T) - 2)) { + break; + } + prHtCap = (P_IE_HT_CAP_T) pucIE; + prStaRec->ucMcsSet = prHtCap->rSupMcsSet.aucRxMcsBitmask[0]; + prStaRec->fgSupMcs32 = + (prHtCap->rSupMcsSet.aucRxMcsBitmask[32/8] & BIT(0)) ? + TRUE : FALSE; + + prStaRec->u2HtCapInfo = prHtCap->u2HtCapInfo; + prStaRec->ucAmpduParam = prHtCap->ucAmpduParam; + prStaRec->u2HtExtendedCap = prHtCap->u2HtExtendedCap; + prStaRec->u4TxBeamformingCap = prHtCap->u4TxBeamformingCap; + prStaRec->ucAselCap = prHtCap->ucAselCap; + break; + + default: + break; + } /* end of switch */ + } /* end of IE_FOR_EACH */ +} +#endif /* CFG_SUPPORT_AAA */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief It is for both STA and AP modes +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmBssInitForAPandIbss ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo + ) +{ + ASSERT(prAdapter); + ASSERT(prBssInfo); + +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered && + prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + + ASSERT(prAdapter->rP2pFuncLkr.prRlmBssInitForAP); + prAdapter->rP2pFuncLkr.prRlmBssInitForAP(prAdapter, prBssInfo); + } +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief It is for both STA and AP modes +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmBssAborted ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo + ) +{ + ASSERT(prAdapter); + ASSERT(prBssInfo); + + rlmBssReset(prAdapter, prBssInfo); + + prBssInfo->fg40mBwAllowed = FALSE; + prBssInfo->fgAssoc40mBwAllowed = FALSE; + + /* Assume FW state is updated by CMD_ID_SET_BSS_INFO, so + * the sync CMD is not needed here. + */ +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief All RLM timers will also be stopped. +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +static VOID +rlmBssReset ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo + ) +{ + ASSERT(prAdapter); + ASSERT(prBssInfo); + + /* HT related parameters */ + prBssInfo->ucHtOpInfo1 = 0; /* RIFS disabled. 20MHz */ + prBssInfo->u2HtOpInfo2 = 0; + prBssInfo->u2HtOpInfo3 = 0; + + prBssInfo->eBssSCO = 0; + prBssInfo->fgErpProtectMode = 0; + prBssInfo->eHtProtectMode = 0; + prBssInfo->eGfOperationMode = 0; + prBssInfo->eRifsOperationMode = 0; + + /* OBSS related parameters */ + prBssInfo->auc2G_20mReqChnlList[0] = 0; + prBssInfo->auc2G_NonHtChnlList[0] = 0; + prBssInfo->auc2G_PriChnlList[0] = 0; + prBssInfo->auc2G_SecChnlList[0] = 0; + prBssInfo->auc5G_20mReqChnlList[0] = 0; + prBssInfo->auc5G_NonHtChnlList[0] = 0; + prBssInfo->auc5G_PriChnlList[0] = 0; + prBssInfo->auc5G_SecChnlList[0] = 0; + + /* All RLM timers will also be stopped */ + cnmTimerStopTimer(prAdapter, &prBssInfo->rObssScanTimer); + prBssInfo->u2ObssScanInterval = 0; + + prBssInfo->fgObssErpProtectMode = 0; /* GO only */ + prBssInfo->eObssHtProtectMode = 0; /* GO only */ + prBssInfo->eObssGfOperationMode = 0; /* GO only */ + prBssInfo->fgObssRifsOperationMode = 0; /* GO only */ + prBssInfo->fgObssActionForcedTo20M = 0; /* GO only */ + prBssInfo->fgObssBeaconForcedTo20M = 0; /* GO only */ +} + + +#if CFG_ENABLE_WIFI_DIRECT +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +linkToRlmRspGenerateObssScanIE ( + P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo + ) +{ + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + if (prAdapter->fgIsP2PRegistered) { + ASSERT(prAdapter->rP2pFuncLkr.prRlmRspGenerateObssScanIE); + + if (prAdapter->rP2pFuncLkr.prRlmRspGenerateObssScanIE) { + prAdapter->rP2pFuncLkr.prRlmRspGenerateObssScanIE( + prAdapter, prMsduInfo); + } + } + return; +} +#endif + +EXPORT_SYMBOL(rlmSyncOperationParams); + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/rlm_domain.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/rlm_domain.c new file mode 100755 index 000000000000..f6965640f186 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/rlm_domain.c @@ -0,0 +1,713 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/mgmt/rlm_domain.c#1 $ +*/ + +/*! \file "rlm_domain.c" + \brief + +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: rlm_domain.c $ + * + * 11 10 2011 cm.chang + * NULL + * Modify debug message for XLOG + * + * 11 02 2011 cm.chang + * NULL + * Format alignment + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 06 01 2011 cm.chang + * [WCXRP00000756] [MT6620 Wi-Fi][Driver] 1. AIS follow channel of BOW 2. Provide legal channel function + * Provide function to check if specified channel is legal based on domain + * + * 03 19 2011 yuche.tsai + * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. + * Add beacon timeout support for WiFi Direct Netwrok. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 02 2011 terry.wu + * [WCXRP00000505] [MT6620 Wi-Fi][Driver/FW] WiFi Direct Integration + * Export rlmDomainGetDomainInfo for p2p driver. + * + * 01 12 2011 cm.chang + * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting + * User-defined bandwidth is for 2.4G and 5G individually + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Check draft RLM code for HT cap + * + * 03 25 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Filter out not supported RF freq when reporting available chnl list + * + * 01 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support protection and bandwidth switch + * + * 01 13 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Provide query function about full channle list. + * + * Dec 1 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/* The following country or domain shall be set from host driver. + * And host driver should pass specified DOMAIN_INFO_ENTRY to MT6620 as + * the channel list of being a STA to do scanning/searching AP or being an + * AP to choose an adequate channel if auto-channel is set. + */ + +/* Define mapping tables between country code and its channel set + */ +static const UINT_16 g_u2CountryGroup0[] = +{ + COUNTRY_CODE_US, COUNTRY_CODE_BS, COUNTRY_CODE_BB, COUNTRY_CODE_BO, COUNTRY_CODE_DM, + COUNTRY_CODE_DO, COUNTRY_CODE_HT, COUNTRY_CODE_PR, COUNTRY_CODE_TH, COUNTRY_CODE_TW, + COUNTRY_CODE_AI, COUNTRY_CODE_AG, COUNTRY_CODE_AW, COUNTRY_CODE_BM, COUNTRY_CODE_CU, + COUNTRY_CODE_GD, COUNTRY_CODE_GY, COUNTRY_CODE_JM, COUNTRY_CODE_KN, COUNTRY_CODE_LC, + COUNTRY_CODE_VC, COUNTRY_CODE_TT, COUNTRY_CODE_SR +}; +static const UINT_16 g_u2CountryGroup1[] = +{ + COUNTRY_CODE_BR, COUNTRY_CODE_EC, COUNTRY_CODE_HK, COUNTRY_CODE_MX, COUNTRY_CODE_PE, + COUNTRY_CODE_CR, COUNTRY_CODE_MD, COUNTRY_CODE_NI, COUNTRY_CODE_PZ +}; +static const UINT_16 g_u2CountryGroup2[] = {COUNTRY_CODE_CO, COUNTRY_CODE_PY}; +static const UINT_16 g_u2CountryGroup3[] = {COUNTRY_CODE_JP}; +static const UINT_16 g_u2CountryGroup4[] = +{ + COUNTRY_CODE_CN, COUNTRY_CODE_UY, COUNTRY_CODE_MA +}; +static const UINT_16 g_u2CountryGroup5[] = {COUNTRY_CODE_AR}; +static const UINT_16 g_u2CountryGroup6[] = {COUNTRY_CODE_AU, COUNTRY_CODE_NZ}; +static const UINT_16 g_u2CountryGroup7[] = {COUNTRY_CODE_RU}; +static const UINT_16 g_u2CountryGroup8[] = +{ + COUNTRY_CODE_ID, COUNTRY_CODE_HN, COUNTRY_CODE_PG, COUNTRY_CODE_PK +}; +static const UINT_16 g_u2CountryGroup9[] = {COUNTRY_CODE_CA}; +static const UINT_16 g_u2CountryGroup10[] = +{ + COUNTRY_CODE_CL, COUNTRY_CODE_IN, COUNTRY_CODE_SA, COUNTRY_CODE_SG, COUNTRY_CODE_VE, + COUNTRY_CODE_MY, COUNTRY_CODE_VN, COUNTRY_CODE_EG +}; +static const UINT_16 g_u2CountryGroup11[] = {COUNTRY_CODE_IL, COUNTRY_CODE_UA}; +static const UINT_16 g_u2CountryGroup12[] = {COUNTRY_CODE_JO, COUNTRY_CODE_KW}; +static const UINT_16 g_u2CountryGroup13[] = {COUNTRY_CODE_KR, COUNTRY_CODE_OM}; +static const UINT_16 g_u2CountryGroup14[] = +{ + COUNTRY_CODE_EU + /* When country code is not found, this domain info will be used. + * So mark all country codes to reduce search time. 20110908 + */ + /*, COUNTRY_CODE_PH, COUNTRY_CODE_TR, COUNTRY_CODE_IR, COUNTRY_CODE_BY, + COUNTRY_CODE_LK */ +}; + + +DOMAIN_INFO_ENTRY arSupportedRegDomains[] = { + { + (PUINT_16) g_u2CountryGroup0, sizeof(g_u2CountryGroup0) / 2, + { + { 81, BAND_2G4, CHNL_SPAN_5, 1, 11, FALSE }, /* CH_SET_2G4_1_11 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE }, /* CH_SET_UNII_LOW_36_48 */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, FALSE }, /* CH_SET_UNII_MID_52_64 */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 11, FALSE }, /* CH_SET_UNII_WW_100_140 */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE }, /* CH_SET_UNII_UPPER_149_165 */ + { 0, BAND_NULL, 0, 0, 0, FALSE } + } + }, + { + (PUINT_16) g_u2CountryGroup1, sizeof(g_u2CountryGroup1) / 2, + { + { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE }, /* CH_SET_UNII_LOW_36_48 */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, FALSE }, /* CH_SET_UNII_MID_52_64 */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 11, FALSE }, /* CH_SET_UNII_WW_100_140 */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE }, /* CH_SET_UNII_UPPER_149_165 */ + { 0, BAND_NULL, 0, 0, 0, FALSE } + } + }, + { + (PUINT_16) g_u2CountryGroup2, sizeof(g_u2CountryGroup2) / 2, + { + { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE }, /* CH_SET_UNII_LOW_36_48 */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, FALSE }, /* CH_SET_UNII_MID_52_64 */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 11, FALSE }, /* CH_SET_UNII_WW_100_140 */ + { 125, BAND_NULL, 0, 0, 0, FALSE }, /* CH_SET_UNII_UPPER_NA */ + { 0, BAND_NULL, 0, 0, 0, FALSE } + } + }, + { + (PUINT_16) g_u2CountryGroup3, sizeof(g_u2CountryGroup3) / 2, + { + { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE }, /* CH_SET_2G4_1_14 */ + { 82, BAND_2G4, CHNL_SPAN_5, 14, 1, FALSE }, + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE }, /* CH_SET_UNII_LOW_36_48 */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, FALSE }, /* CH_SET_UNII_MID_52_64 */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 11, FALSE }, /* CH_SET_UNII_WW_100_140 */ + { 125, BAND_NULL, 0, 0, 0, FALSE } /* CH_SET_UNII_UPPER_NA */ + } + }, + { + (PUINT_16) g_u2CountryGroup4, sizeof(g_u2CountryGroup4) / 2, + { + { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_NULL, 0, 0, 0, FALSE }, /* CH_SET_UNII_LOW_NA */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, FALSE }, /* CH_SET_UNII_MID_52_64 */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 11, FALSE }, /* CH_SET_UNII_WW_100_140 */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE }, /* CH_SET_UNII_UPPER_149_165 */ + { 0, BAND_NULL, 0, 0, 0, FALSE } + } + }, + { + (PUINT_16) g_u2CountryGroup5, sizeof(g_u2CountryGroup5) / 2, + { + { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_NULL, 0, 0, 0, FALSE }, /* CH_SET_UNII_LOW_NA */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, FALSE }, /* CH_SET_UNII_MID_52_64 */ + { 121, BAND_NULL, 0, 0, 0, FALSE }, /* CH_SET_UNII_WW_NA */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE }, /* CH_SET_UNII_UPPER_149_165 */ + { 0, BAND_NULL, 0, 0, 0, FALSE } + } + }, + { + (PUINT_16) g_u2CountryGroup6, sizeof(g_u2CountryGroup6) / 2, + { + { 81, BAND_2G4, CHNL_SPAN_5, 1, 11, FALSE }, /* CH_SET_2G4_1_11 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE }, /* CH_SET_UNII_LOW_36_48 */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, FALSE }, /* CH_SET_UNII_MID_52_64 */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 11, FALSE }, /* CH_SET_UNII_WW_100_140 */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 4, FALSE }, /* CH_SET_UNII_UPPER_149_161 */ + { 0, BAND_NULL, 0, 0, 0, FALSE } + } + }, + { + (PUINT_16) g_u2CountryGroup7, sizeof(g_u2CountryGroup7) / 2, + { + { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE }, /* CH_SET_UNII_LOW_36_48 */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, FALSE }, /* CH_SET_UNII_MID_52_64 */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 11, FALSE }, /* CH_SET_UNII_WW_100_140 */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 4, FALSE }, /* CH_SET_UNII_UPPER_149_161 */ + { 0, BAND_NULL, 0, 0, 0, FALSE } + } + }, + { + (PUINT_16) g_u2CountryGroup8, sizeof(g_u2CountryGroup8) / 2, + { + { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_NULL, 0, 0, 0, FALSE }, /* CH_SET_UNII_LOW_NA */ + { 118, BAND_NULL, 0, 0, 0, FALSE }, /* CH_SET_UNII_MID_NA */ + { 121, BAND_NULL, 0, 0, 0, FALSE }, /* CH_SET_UNII_WW_NA */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 4, FALSE }, /* CH_SET_UNII_UPPER_149_161 */ + { 0, BAND_NULL, 0, 0, 0, FALSE } + } + }, + { + (PUINT_16) g_u2CountryGroup9, sizeof(g_u2CountryGroup9) / 2, + { + { 81, BAND_2G4, CHNL_SPAN_5, 1, 11, FALSE }, /* CH_SET_2G4_1_11 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE }, /* CH_SET_UNII_LOW_36_48 */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, FALSE }, /* CH_SET_UNII_MID_52_64 */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 5, FALSE }, /* CH_SET_UNII_WW_100_116_132_140 */ + { 121, BAND_5G, CHNL_SPAN_20, 132, 5, FALSE }, + { 125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE }, /* CH_SET_UNII_UPPER_149_165 */ + } + }, + { + (PUINT_16) g_u2CountryGroup10, sizeof(g_u2CountryGroup10) / 2, + { + { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE }, /* CH_SET_UNII_LOW_36_48 */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, FALSE }, /* CH_SET_UNII_MID_52_64 */ + { 121, BAND_NULL, 0, 0, 0, FALSE }, /* CH_SET_UNII_WW_NA */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE }, /* CH_SET_UNII_UPPER_149_165 */ + { 0, BAND_NULL, 0, 0, 0, FALSE } + } + }, + { + (PUINT_16) g_u2CountryGroup11, sizeof(g_u2CountryGroup11) / 2, + { + { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE }, /* CH_SET_UNII_LOW_36_48 */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, FALSE }, /* CH_SET_UNII_MID_52_64 */ + { 121, BAND_NULL, 0, 0, 0, FALSE }, /* CH_SET_UNII_WW_NA */ + { 125, BAND_NULL, 0, 0, 0, FALSE }, /* CH_SET_UNII_UPPER_NA */ + { 0, BAND_NULL, 0, 0, 0, FALSE } + } + }, + { + (PUINT_16) g_u2CountryGroup12, sizeof(g_u2CountryGroup12) / 2, + { + { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE }, /* CH_SET_UNII_LOW_36_48 */ + { 118, BAND_NULL, 0, 0, 0, FALSE }, /* CH_SET_UNII_MID_NA */ + { 121, BAND_NULL, 0, 0, 0, FALSE }, /* CH_SET_UNII_WW_NA */ + { 125, BAND_NULL, 0, 0, 0, FALSE }, /* CH_SET_UNII_UPPER_NA */ + { 0, BAND_NULL, 0, 0, 0, FALSE } + } + }, + { + (PUINT_16) g_u2CountryGroup13, sizeof(g_u2CountryGroup13) / 2, + { + { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE }, /* CH_SET_UNII_LOW_36_48 */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, FALSE }, /* CH_SET_UNII_MID_52_64 */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 8, FALSE }, /* CH_SET_UNII_WW_100_128 */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE }, /* CH_SET_UNII_UPPER_149_165 */ + { 0, BAND_NULL, 0, 0, 0, FALSE } + } + }, + { + /* Note: The final one is for Europe union now. */ + (PUINT_16) g_u2CountryGroup14, sizeof(g_u2CountryGroup14) / 2, + { + { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE }, /* CH_SET_UNII_LOW_36_48 */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, FALSE }, /* CH_SET_UNII_MID_52_64 */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 11, FALSE }, /* CH_SET_UNII_WW_100_140 */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 7, FALSE }, /* CH_SET_UNII_UPPER_149_173 */ + { 0, BAND_NULL, 0, 0, 0, FALSE } + } + } +}; + +#if 0 +COUNTRY_CH_SET_T arCountryChSets[] = { + /* idx=0: US, Bahamas, Barbados, Bolivia(Voluntary), Dominica (the Commonwealth of Dominica), + The Dominican Republic, Haiti */ + {CH_SET_2G4_1_11, CH_SET_UNII_LOW_36_48, CH_SET_UNII_MID_52_64, + CH_SET_UNII_WW_100_140, CH_SET_UNII_UPPER_149_165}, + /* idx=1: Brazil, Ecuador, Hong Kong, Mexico, Peru */ + {CH_SET_2G4_1_13, CH_SET_UNII_LOW_36_48, CH_SET_UNII_MID_52_64, + CH_SET_UNII_WW_100_140, CH_SET_UNII_UPPER_149_165}, + /* idx=2: JP1, Colombia(Voluntary), Paraguay */ + {CH_SET_2G4_1_13, CH_SET_UNII_LOW_36_48, CH_SET_UNII_MID_52_64, + CH_SET_UNII_WW_100_140, CH_SET_UNII_UPPER_NA}, + /* idx=3: JP2 */ + {CH_SET_2G4_1_14, CH_SET_UNII_LOW_36_48, CH_SET_UNII_MID_52_64, + CH_SET_UNII_WW_100_140, CH_SET_UNII_UPPER_NA}, + /* idx=4: CN, Uruguay, Morocco */ + {CH_SET_2G4_1_13, CH_SET_UNII_LOW_NA, CH_SET_UNII_MID_NA, + CH_SET_UNII_WW_NA, CH_SET_UNII_UPPER_149_165}, + /* idx=5: Argentina */ + {CH_SET_2G4_1_13, CH_SET_UNII_LOW_NA, CH_SET_UNII_MID_52_64, + CH_SET_UNII_WW_NA, CH_SET_UNII_UPPER_149_165}, + /* idx=6: Australia, New Zealand */ + {CH_SET_2G4_1_11, CH_SET_UNII_LOW_36_48, CH_SET_UNII_MID_52_64, + CH_SET_UNII_WW_100_140, CH_SET_UNII_UPPER_149_161}, + /* idx=7: Russia */ + {CH_SET_2G4_1_13, CH_SET_UNII_LOW_36_48, CH_SET_UNII_MID_52_64, + CH_SET_UNII_WW_100_140, CH_SET_UNII_UPPER_149_161}, + /* idx=8: Indonesia */ + {CH_SET_2G4_1_13, CH_SET_UNII_LOW_NA, CH_SET_UNII_MID_NA, + CH_SET_UNII_WW_NA, CH_SET_UNII_UPPER_149_161}, + /* idx=9: Canada */ + {CH_SET_2G4_1_11, CH_SET_UNII_LOW_36_48, CH_SET_UNII_MID_52_64, + CH_SET_UNII_WW_100_116_132_140, CH_SET_UNII_UPPER_149_165}, + /* idx=10: Chile, India, Saudi Arabia, Singapore */ + {CH_SET_2G4_1_13, CH_SET_UNII_LOW_36_48, CH_SET_UNII_MID_52_64, + CH_SET_UNII_WW_NA, CH_SET_UNII_UPPER_149_165}, + /* idx=11: Israel, Ukraine */ + {CH_SET_2G4_1_13, CH_SET_UNII_LOW_36_48, CH_SET_UNII_MID_52_64, + CH_SET_UNII_WW_NA, CH_SET_UNII_UPPER_NA}, + /* idx=12: Jordan, Kuwait */ + {CH_SET_2G4_1_13, CH_SET_UNII_LOW_36_48, CH_SET_UNII_MID_NA, + CH_SET_UNII_WW_NA, CH_SET_UNII_UPPER_NA}, + /* idx=13: South Korea */ + {CH_SET_2G4_1_13, CH_SET_UNII_LOW_36_48, CH_SET_UNII_MID_52_64, + CH_SET_UNII_WW_100_128, CH_SET_UNII_UPPER_149_165}, + /* idx=14: Taiwan */ + {CH_SET_2G4_1_11, CH_SET_UNII_LOW_NA, CH_SET_UNII_MID_52_64, + CH_SET_UNII_WW_100_140, CH_SET_UNII_UPPER_149_165}, + /* idx=15: EU all countries */ + {CH_SET_2G4_1_13, CH_SET_UNII_LOW_36_48, CH_SET_UNII_MID_52_64, + CH_SET_UNII_WW_100_140, CH_SET_UNII_UPPER_149_173} +}; +#endif + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in/out] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +P_DOMAIN_INFO_ENTRY +rlmDomainGetDomainInfo ( + P_ADAPTER_T prAdapter + ) +{ +#define REG_DOMAIN_DEF_IDX 14 /* EU (Europe Union) */ +#define REG_DOMAIN_GROUP_NUM \ + (sizeof(arSupportedRegDomains) / sizeof(DOMAIN_INFO_ENTRY)) + + UINT_16 i, j; + P_DOMAIN_INFO_ENTRY prDomainInfo; + P_REG_INFO_T prRegInfo; + UINT_16 u2TargetCountryCode; + + ASSERT(prAdapter); + + if (prAdapter->prDomainInfo) { + return prAdapter->prDomainInfo; + } + + prRegInfo = &prAdapter->prGlueInfo->rRegInfo; + + DBGLOG(RLM, INFO, ("Domain: map=%d, idx=%d, code=0x%04x\n", + prRegInfo->eRegChannelListMap, prRegInfo->ucRegChannelListIndex, + prAdapter->rWifiVar.rConnSettings.u2CountryCode)); + + if (prRegInfo->eRegChannelListMap == REG_CH_MAP_TBL_IDX && + prRegInfo->ucRegChannelListIndex < REG_DOMAIN_GROUP_NUM) { + prDomainInfo = &arSupportedRegDomains[prRegInfo->ucRegChannelListIndex]; + goto L_set_domain_info; + } + else if (prRegInfo->eRegChannelListMap == REG_CH_MAP_CUSTOMIZED) { + prDomainInfo = &prRegInfo->rDomainInfo; + goto L_set_domain_info; + } + + u2TargetCountryCode = prAdapter->rWifiVar.rConnSettings.u2CountryCode; + + /* If no matched country code, the final one will be used + * The final one is for Europe union now. + */ + for (i = 0; i < REG_DOMAIN_GROUP_NUM; i++) { + prDomainInfo = &arSupportedRegDomains[i]; + + ASSERT((prDomainInfo->u4CountryNum && prDomainInfo->pu2CountryGroup) || + prDomainInfo->u4CountryNum == 0); + + for (j = 0; j < prDomainInfo->u4CountryNum; j++) { + if (prDomainInfo->pu2CountryGroup[j] == u2TargetCountryCode) { + break; + } + } + if (j < prDomainInfo->u4CountryNum) { + break; /* Found */ + } + } + + DATA_STRUC_INSPECTING_ASSERT(REG_DOMAIN_DEF_IDX < REG_DOMAIN_GROUP_NUM); + + if (i >= REG_DOMAIN_GROUP_NUM) { + prDomainInfo = &arSupportedRegDomains[REG_DOMAIN_DEF_IDX]; + } + +L_set_domain_info: + + prAdapter->prDomainInfo = prDomainInfo; + return prDomainInfo; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in/out] The input variable pointed by pucNumOfChannel is the max +* arrary size. The return value indciates meaning list size. +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmDomainGetChnlList ( + P_ADAPTER_T prAdapter, + ENUM_BAND_T eSpecificBand, + UINT_8 ucMaxChannelNum, + PUINT_8 pucNumOfChannel, + P_RF_CHANNEL_INFO_T paucChannelList + ) +{ + UINT_8 i, j, ucNum; + P_DOMAIN_SUBBAND_INFO prSubband; + P_DOMAIN_INFO_ENTRY prDomainInfo; + + ASSERT(prAdapter); + ASSERT(paucChannelList); + ASSERT(pucNumOfChannel); + + /* If no matched country code, the final one will be used */ + prDomainInfo = rlmDomainGetDomainInfo(prAdapter); + ASSERT(prDomainInfo); + + ucNum = 0; + for (i = 0; i < MAX_SUBBAND_NUM; i++) { + prSubband = &prDomainInfo->rSubBand[i]; + + if (prSubband->ucBand == BAND_NULL || prSubband->ucBand >= BAND_NUM || + (prSubband->ucBand == BAND_5G && !prAdapter->fgEnable5GBand)) { + continue; + } + + if (eSpecificBand == BAND_NULL || prSubband->ucBand == eSpecificBand) { + for (j = 0; j < prSubband->ucNumChannels; j++) { + if (ucNum >= ucMaxChannelNum) { + break; + } + paucChannelList[ucNum].eBand = prSubband->ucBand; + paucChannelList[ucNum].ucChannelNum = + prSubband->ucFirstChannelNum + j * prSubband->ucChannelSpan; + ucNum++; + } + } + } + + *pucNumOfChannel = ucNum; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param[in] +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmDomainSendCmd ( + P_ADAPTER_T prAdapter, + BOOLEAN fgIsOid + ) +{ + P_DOMAIN_INFO_ENTRY prDomainInfo; + P_CMD_SET_DOMAIN_INFO_T prCmd; + WLAN_STATUS rStatus; + UINT_8 i; + P_DOMAIN_SUBBAND_INFO prSubBand; + + prDomainInfo = rlmDomainGetDomainInfo(prAdapter); + ASSERT(prDomainInfo); + + prCmd = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_SET_DOMAIN_INFO_T)); + ASSERT(prCmd); + + /* To do: exception handle */ + if (!prCmd) { + DBGLOG(RLM, ERROR, ("Domain: no buf to send cmd\n")); + return; + } + kalMemZero(prCmd, sizeof(CMD_SET_DOMAIN_INFO_T)); + + prCmd->u2CountryCode = prAdapter->rWifiVar.rConnSettings.u2CountryCode; + prCmd->u2Reserved = 0; + prCmd->uc2G4Bandwidth = + prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode; + prCmd->uc5GBandwidth = + prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode; + + for (i = 0; i < 6; i++) { + prSubBand = &prDomainInfo->rSubBand[i]; + + prCmd->rSubBand[i].ucRegClass = prSubBand->ucRegClass; + prCmd->rSubBand[i].ucBand = prSubBand->ucBand; + + if (prSubBand->ucBand != BAND_NULL && prSubBand->ucBand < BAND_NUM) { + prCmd->rSubBand[i].ucChannelSpan = prSubBand->ucChannelSpan; + prCmd->rSubBand[i].ucFirstChannelNum = prSubBand->ucFirstChannelNum; + prCmd->rSubBand[i].ucNumChannels = prSubBand->ucNumChannels; + } + } + + /* Update domain info to chip */ + rStatus = wlanSendSetQueryCmd ( + prAdapter, /* prAdapter */ + CMD_ID_SET_DOMAIN_INFO, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + fgIsOid, /* fgIsOid */ + NULL, /* pfCmdDoneHandler*/ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_SET_DOMAIN_INFO_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmd, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + ASSERT(rStatus == WLAN_STATUS_PENDING); + + cnmMemFree(prAdapter, prCmd); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in/out] +* +* \return TRUE Legal channel +* FALSE Illegal channel for current regulatory domain +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +rlmDomainIsLegalChannel ( + P_ADAPTER_T prAdapter, + ENUM_BAND_T eBand, + UINT_8 ucChannel + ) +{ + UINT_8 i, j; + P_DOMAIN_SUBBAND_INFO prSubband; + P_DOMAIN_INFO_ENTRY prDomainInfo; + + prDomainInfo = rlmDomainGetDomainInfo(prAdapter); + ASSERT(prDomainInfo); + + for (i = 0; i < MAX_SUBBAND_NUM; i++) { + prSubband = &prDomainInfo->rSubBand[i]; + + if (prSubband->ucBand == BAND_5G && !prAdapter->fgEnable5GBand) { + continue; + } + + if (prSubband->ucBand == eBand) { + for (j = 0; j < prSubband->ucNumChannels; j++) { + if ((prSubband->ucFirstChannelNum + j*prSubband->ucChannelSpan) + == ucChannel) { + return TRUE; + } + } + } + } + + return FALSE; +} + +EXPORT_SYMBOL(rlmDomainGetDomainInfo); + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/rlm_obss.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/rlm_obss.c new file mode 100755 index 000000000000..ef573727d6b0 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/rlm_obss.c @@ -0,0 +1,502 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/mgmt/rlm_obss.c#1 $ +*/ + +/*! \file "rlm_obss.c" + \brief + +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: rlm_obss.c $ + * + * 11 15 2011 cm.chang + * NULL + * Avoid possible OBSS scan when BSS is switched + * + * 11 08 2011 cm.chang + * NULL + * Add RLM and CNM debug message for XLOG + * + * 10 25 2011 cm.chang + * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode + * . + * + * 04 12 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 03 29 2011 cm.chang + * [WCXRP00000606] [MT6620 Wi-Fi][Driver][FW] Fix klocwork warning + * As CR titile + * + * 03 29 2011 cm.chang + * [WCXRP00000606] [MT6620 Wi-Fi][Driver][FW] Fix klocwork warning + * As CR title + * + * 01 24 2011 cm.chang + * [WCXRP00000384] [MT6620 Wi-Fi][Driver][FW] Handle 20/40 action frame in AP mode and stop ampdu timer when sta_rec is freed + * Process received 20/40 coexistence action frame for AP mode + * + * 01 13 2011 cm.chang + * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module + * Refine function when rcv a 20/40M public action frame + * + * 01 13 2011 cm.chang + * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting + * Use SCO of BSS_INFO to replace user-defined setting variables + * + * 01 12 2011 cm.chang + * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting + * User-defined bandwidth is for 2.4G and 5G individually + * + * 10 18 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * use definition macro to replace hard-coded constant + * + * 09 16 2010 cm.chang + * NULL + * Change conditional compiling options for BOW + * + * 09 10 2010 cm.chang + * NULL + * Always update Beacon content if FW sync OBSS info + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 08 20 2010 cm.chang + * NULL + * Migrate RLM code to host from FW + * + * 07 26 2010 yuche.tsai + * + * Fix compile error while enabling WiFi Direct function. + * + * 07 21 2010 yuche.tsai + * + * Add P2P Scan & Scan Result Parsing & Saving. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Check draft RLM code for HT cap + * + * 05 07 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Process 20/40 coexistence public action frame in AP mode + * + * 05 05 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * First draft support for 20/40M bandwidth for AP mode + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW + * + * 04 13 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add more ASSERT to check exception + * + * 04 07 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add virtual test for OBSS scan + * + * 03 30 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support 2.4G OBSS scan + * + * 03 03 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * To support CFG_SUPPORT_BCM_STP + * + * 02 13 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support PCO in STA mode + * + * 02 12 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Use bss info array for concurrent handle + * + * 02 05 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * 01 25 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support protection and bandwidth switch +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static VOID +rlmObssScanTimeout ( + P_ADAPTER_T prAdapter, + UINT_32 u4Data + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmObssInit ( + P_ADAPTER_T prAdapter + ) +{ + P_BSS_INFO_T prBssInfo; + UINT_8 ucNetIdx; + + RLM_NET_FOR_EACH(ucNetIdx) { + prBssInfo = &prAdapter->rWifiVar.arBssInfo[ucNetIdx]; + ASSERT(prBssInfo); + + cnmTimerInitTimer(prAdapter, &prBssInfo->rObssScanTimer, + rlmObssScanTimeout, (UINT_32) prBssInfo); + } /* end of RLM_NET_FOR_EACH */ +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +rlmObssUpdateChnlLists ( + P_ADAPTER_T prAdapter, + P_SW_RFB_T prSwRfb + ) +{ + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmObssScanDone ( + P_ADAPTER_T prAdapter, + P_MSG_HDR_T prMsgHdr + ) +{ + P_MSG_SCN_SCAN_DONE prScanDoneMsg; + P_BSS_INFO_T prBssInfo; + P_MSDU_INFO_T prMsduInfo; + P_ACTION_20_40_COEXIST_FRAME prTxFrame; + UINT_16 i, u2PayloadLen; + + ASSERT(prMsgHdr); + + prScanDoneMsg = (P_MSG_SCN_SCAN_DONE) prMsgHdr; + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prScanDoneMsg->ucNetTypeIndex]; + ASSERT(prBssInfo); + + DBGLOG(RLM, INFO, ("OBSS Scan Done (NetIdx=%d, Mode=%d)\n", + prScanDoneMsg->ucNetTypeIndex, prBssInfo->eCurrentOPMode)); + + cnmMemFree(prAdapter, prMsgHdr); + +#if CFG_ENABLE_WIFI_DIRECT + /* AP mode */ + if ((prAdapter->fgIsP2PRegistered) && + (IS_NET_ACTIVE(prAdapter, prBssInfo->ucNetTypeIndex)) && + (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT)) { + return; + } +#endif + + /* STA mode */ + if (prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE || + !RLM_NET_PARAM_VALID(prBssInfo) || prBssInfo->u2ObssScanInterval == 0) { + DBGLOG(RLM, WARN, ("OBSS Scan Done (NetIdx=%d) -- Aborted!!\n", + prBssInfo->ucNetTypeIndex)); + return; + } + + /* To do: check 2.4G channel list to decide if obss mgmt should be + * sent to associated AP. Note: how to handle concurrent network? + * To do: invoke rlmObssChnlLevel() to decide if 20/40 BSS coexistence + * management frame is needed. + */ + if ((prBssInfo->auc2G_20mReqChnlList[0] > 0 || + prBssInfo->auc2G_NonHtChnlList[0] > 0) && + (prMsduInfo = (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, + MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN)) != NULL) { + + DBGLOG(RLM, INFO, ("Send 20/40 coexistence mgmt(20mReq=%d, NonHt=%d)\n", + prBssInfo->auc2G_20mReqChnlList[0], + prBssInfo->auc2G_NonHtChnlList[0])); + + prTxFrame = (P_ACTION_20_40_COEXIST_FRAME) + ((UINT_32)(prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); + + prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; + COPY_MAC_ADDR(prTxFrame->aucDestAddr, prBssInfo->aucBSSID); + COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); + COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); + + prTxFrame->ucCategory = CATEGORY_PUBLIC_ACTION; + prTxFrame->ucAction = ACTION_PUBLIC_20_40_COEXIST; + + /* To do: find correct algorithm */ + prTxFrame->rBssCoexist.ucId = ELEM_ID_20_40_BSS_COEXISTENCE; + prTxFrame->rBssCoexist.ucLength = 1; + prTxFrame->rBssCoexist.ucData = + (prBssInfo->auc2G_20mReqChnlList[0] > 0) ? BSS_COEXIST_20M_REQ : 0; + + u2PayloadLen = 2 + 3; + + if (prBssInfo->auc2G_NonHtChnlList[0] > 0) { + ASSERT(prBssInfo->auc2G_NonHtChnlList[0] <= CHNL_LIST_SZ_2G); + + prTxFrame->rChnlReport.ucId = ELEM_ID_20_40_INTOLERANT_CHNL_REPORT; + prTxFrame->rChnlReport.ucLength = + prBssInfo->auc2G_NonHtChnlList[0] + 1; + prTxFrame->rChnlReport.ucRegulatoryClass = 81; /* 2.4GHz, ch1~13 */ + for (i = 0; i < prBssInfo->auc2G_NonHtChnlList[0] && + i < CHNL_LIST_SZ_2G; i++) { + prTxFrame->rChnlReport.aucChannelList[i] = + prBssInfo->auc2G_NonHtChnlList[i+1]; + } + + u2PayloadLen += IE_SIZE(&prTxFrame->rChnlReport); + } + ASSERT((WLAN_MAC_HEADER_LEN + u2PayloadLen) <= PUBLIC_ACTION_MAX_LEN); + + /* Clear up channel lists in 2.4G band */ + prBssInfo->auc2G_20mReqChnlList[0] = 0; + prBssInfo->auc2G_NonHtChnlList[0] = 0; + + + //4 Update information of MSDU_INFO_T + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; /* Management frame */ + prMsduInfo->ucStaRecIndex = prBssInfo->prStaRecOfAP->ucIndex; + prMsduInfo->ucNetworkType = prBssInfo->ucNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = NULL; + prMsduInfo->fgIsBasicRate = FALSE; + + //4 Enqueue the frame to send this action frame. + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + } /* end of prMsduInfo != NULL */ + + if (prBssInfo->u2ObssScanInterval > 0) { + DBGLOG(RLM, INFO, ("Set OBSS timer (NetIdx=%d, %d sec)\n", + prBssInfo->ucNetTypeIndex, prBssInfo->u2ObssScanInterval)); + + cnmTimerStartTimer(prAdapter, &prBssInfo->rObssScanTimer, + prBssInfo->u2ObssScanInterval * MSEC_PER_SEC); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +static VOID +rlmObssScanTimeout ( + P_ADAPTER_T prAdapter, + UINT_32 u4Data + ) +{ + P_BSS_INFO_T prBssInfo; + + prBssInfo = (P_BSS_INFO_T) u4Data; + ASSERT(prBssInfo); + +#if CFG_ENABLE_WIFI_DIRECT + /* AP mode */ + if (prAdapter->fgIsP2PRegistered && + (IS_NET_ACTIVE(prAdapter, prBssInfo->ucNetTypeIndex)) && + (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT)) { + + prBssInfo->fgObssActionForcedTo20M = FALSE; + + /* Check if Beacon content need to be updated */ + ASSERT(prAdapter->rP2pFuncLkr.prRlmUpdateParamsForAp); + prAdapter->rP2pFuncLkr.prRlmUpdateParamsForAp( + prAdapter, prBssInfo, FALSE); + return; + } +#endif /* end of CFG_ENABLE_WIFI_DIRECT */ + + + /* STA mode */ + if (prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE || + !RLM_NET_PARAM_VALID(prBssInfo) || prBssInfo->u2ObssScanInterval == 0) { + DBGLOG(RLM, WARN, ("OBSS Scan timeout (NetIdx=%d) -- Aborted!!\n", + prBssInfo->ucNetTypeIndex)); + return; + } + + rlmObssTriggerScan(prAdapter, prBssInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmObssTriggerScan ( + P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo + ) +{ + P_MSG_SCN_SCAN_REQ prScanReqMsg; + + ASSERT(prBssInfo); + + prScanReqMsg = (P_MSG_SCN_SCAN_REQ) + cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_REQ)); + ASSERT(prScanReqMsg); + + if (!prScanReqMsg) { + DBGLOG(RLM, WARN, ("No buf for OBSS scan (NetIdx=%d)!!\n", + prBssInfo->ucNetTypeIndex)); + + cnmTimerStartTimer(prAdapter, &prBssInfo->rObssScanTimer, + prBssInfo->u2ObssScanInterval * MSEC_PER_SEC); + return; + } + + /* It is ok that ucSeqNum is set to fixed value because the same network + * OBSS scan interval is limited to OBSS_SCAN_MIN_INTERVAL (min 10 sec) + * and scan module don't care seqNum of OBSS scanning + */ + prScanReqMsg->rMsgHdr.eMsgId = MID_RLM_SCN_SCAN_REQ; + prScanReqMsg->ucSeqNum = 0x33; + prScanReqMsg->ucNetTypeIndex = prBssInfo->ucNetTypeIndex; + prScanReqMsg->eScanType = SCAN_TYPE_ACTIVE_SCAN; + prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_WILDCARD; + prScanReqMsg->ucSSIDLength = 0; + prScanReqMsg->eScanChannel = SCAN_CHANNEL_2G4; + prScanReqMsg->u2IELen = 0; + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prScanReqMsg, + MSG_SEND_METHOD_BUF); + + DBGLOG(RLM, INFO, ("Timeout to trigger OBSS scan (NetIdx=%d)!!\n", + prBssInfo->ucNetTypeIndex)); +} + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/rlm_protection.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/rlm_protection.c new file mode 100755 index 000000000000..16941cb1b9e1 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/rlm_protection.c @@ -0,0 +1,152 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/mgmt/rlm_protection.c#1 $ +*/ + +/*! \file "rlm_protection.c" + \brief + +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: rlm_protection.c $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 08 20 2010 cm.chang + * NULL + * Migrate RLM code to host from FW + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Check draft RLM code for HT cap + * + * 05 28 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Set RTS threshold of 2K bytes initially + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW + * + * 04 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * First draft code to support protection in AP mode + * + * 03 31 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Enable RTS threshold temporarily for AMPDU + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 03 03 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * To support CFG_SUPPORT_BCM_STP + * + * 02 13 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support PCO in STA mode + * + * 02 12 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Use bss info array for concurrent handle + * + * 01 25 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support protection and bandwidth switch +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/roaming_fsm.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/roaming_fsm.c new file mode 100755 index 000000000000..45b5d2326841 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/roaming_fsm.c @@ -0,0 +1,625 @@ +/* +** $Id: +*/ + +/*! \file "roaming_fsm.c" + \brief This file defines the FSM for Roaming MODULE. + + This file defines the FSM for Roaming MODULE. +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: roaming_fsm.c $ + * + * 01 20 2012 cp.wu + * [ALPS00096191] [MT6620 Wi-Fi][Driver][Firmware] Porting to ALPS4.0_DEV branch + * sync to up-to-date changes including: + * 1. BOW bugfix + * 2. XLOG + * + * 11 24 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Adjust code for DBG and CONFIG_XLOG. + * + * 11 11 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * modify the xlog related code. + * + * 11 02 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Add XLOG related code and define. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 16 2011 tsaiyuan.hsu + * [WCXRP00000517] [MT6620 Wi-Fi][Driver][FW] Fine Tune Performance of Roaming + * remove obsolete definition and unused variables. + * + * 02 26 2011 tsaiyuan.hsu + * [WCXRP00000391] [MT6620 Wi-Fi][FW] Add Roaming Support + * not send disassoc or deauth to leaving AP so as to improve performace of roaming. + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +#if CFG_SUPPORT_ROAMING +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +#if DBG +/*lint -save -e64 Type mismatch */ +static PUINT_8 apucDebugRoamingState[ROAMING_STATE_NUM] = { + (PUINT_8)DISP_STRING("ROAMING_STATE_IDLE"), + (PUINT_8)DISP_STRING("ROAMING_STATE_DECISION"), + (PUINT_8)DISP_STRING("ROAMING_STATE_DISCOVERY"), + (PUINT_8)DISP_STRING("ROAMING_STATE_ROAM") +}; +/*lint -restore */ +#endif /* DBG */ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define ROAMING_ENABLE_CHECK(_roam) \ + { \ + if (!(_roam->fgIsEnableRoaming)) {return;} \ + } + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Initialize the value in ROAMING_FSM_INFO_T for ROAMING FSM operation +* +* @param [IN P_ADAPTER_T] prAdapter +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +roamingFsmInit ( + IN P_ADAPTER_T prAdapter + ) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + + DBGLOG(ROAMING, LOUD, ("->roamingFsmInit(): Current Time = %ld\n", kalGetTimeTick())); + + prRoamingFsmInfo = (P_ROAMING_INFO_T)&(prAdapter->rWifiVar.rRoamingInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + //4 <1> Initiate FSM + prRoamingFsmInfo->fgIsEnableRoaming = prConnSettings->fgIsEnableRoaming; + prRoamingFsmInfo->eCurrentState = ROAMING_STATE_IDLE; + prRoamingFsmInfo->rRoamingDiscoveryUpdateTime = 0; + + return; +} /* end of roamingFsmInit() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Uninitialize the value in AIS_FSM_INFO_T for AIS FSM operation +* +* @param [IN P_ADAPTER_T] prAdapter +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +roamingFsmUninit ( + IN P_ADAPTER_T prAdapter + ) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + + DBGLOG(ROAMING, LOUD, ("->roamingFsmUninit(): Current Time = %ld\n", kalGetTimeTick())); + + prRoamingFsmInfo = (P_ROAMING_INFO_T)&(prAdapter->rWifiVar.rRoamingInfo); + + prRoamingFsmInfo->eCurrentState = ROAMING_STATE_IDLE; + + return; +} /* end of roamingFsmUninit() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Send commands to firmware +* +* @param [IN P_ADAPTER_T] prAdapter +* [IN P_ROAMING_PARAM_T] prParam +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +roamingFsmSendCmd ( + IN P_ADAPTER_T prAdapter, + IN P_ROAMING_PARAM_T prParam + ) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + WLAN_STATUS rStatus; + + DBGLOG(ROAMING, LOUD, ("->roamingFsmSendCmd(): Current Time = %ld\n", kalGetTimeTick())); + + prRoamingFsmInfo = (P_ROAMING_INFO_T)&(prAdapter->rWifiVar.rRoamingInfo); + + rStatus = wlanSendSetQueryCmd ( + prAdapter, /* prAdapter */ + CMD_ID_ROAMING_TRANSIT, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + sizeof(ROAMING_PARAM_T), /* u4SetQueryInfoLen */ + (PUINT_8) prParam, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + ASSERT(rStatus == WLAN_STATUS_PENDING); + + return; +} /* end of roamingFsmSendCmd() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Update the recent time when ScanDone occurred +* +* @param [IN P_ADAPTER_T] prAdapter +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +roamingFsmScanResultsUpdate ( + IN P_ADAPTER_T prAdapter + ) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + + prRoamingFsmInfo = (P_ROAMING_INFO_T)&(prAdapter->rWifiVar.rRoamingInfo); + + /* Check Roaming Conditions */ + ROAMING_ENABLE_CHECK(prRoamingFsmInfo); + + DBGLOG(ROAMING, LOUD, ("->roamingFsmScanResultsUpdate(): Current Time = %ld\n", kalGetTimeTick())); + + GET_CURRENT_SYSTIME(&prRoamingFsmInfo->rRoamingDiscoveryUpdateTime); + + return; +} /* end of roamingFsmScanResultsUpdate() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief The Core FSM engine of ROAMING for AIS Infra. +* +* @param [IN P_ADAPTER_T] prAdapter +* [IN ENUM_ROAMING_STATE_T] eNextState Enum value of next AIS STATE +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +roamingFsmSteps ( + IN P_ADAPTER_T prAdapter, + IN ENUM_ROAMING_STATE_T eNextState + ) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + ENUM_ROAMING_STATE_T ePreviousState; + BOOLEAN fgIsTransition = (BOOLEAN)FALSE; + + prRoamingFsmInfo = (P_ROAMING_INFO_T)&(prAdapter->rWifiVar.rRoamingInfo); + + do { + + /* Do entering Next State */ +#if CFG_SUPPORT_XLOG + DBGLOG(ROAMING, STATE, ("[%d] TRANSITION: [%d] -> [%d]\n", + DBG_ROAMING_IDX, + prRoamingFsmInfo->eCurrentState, + eNextState)); +#else + DBGLOG(ROAMING, STATE, ("TRANSITION: [%s] -> [%s]\n", + apucDebugRoamingState[prRoamingFsmInfo->eCurrentState], + apucDebugRoamingState[eNextState])); +#endif + /* NOTE(Kevin): This is the only place to change the eCurrentState(except initial) */ + ePreviousState = prRoamingFsmInfo->eCurrentState; + prRoamingFsmInfo->eCurrentState = eNextState; + + fgIsTransition = (BOOLEAN)FALSE; + + /* Do tasks of the State that we just entered */ + switch (prRoamingFsmInfo->eCurrentState) { + /* NOTE(Kevin): we don't have to rearrange the sequence of following + * switch case. Instead I would like to use a common lookup table of array + * of function pointer to speed up state search. + */ + case ROAMING_STATE_IDLE: + case ROAMING_STATE_DECISION: + break; + + case ROAMING_STATE_DISCOVERY: + { + OS_SYSTIME rCurrentTime; + + GET_CURRENT_SYSTIME(&rCurrentTime); + if (CHECK_FOR_TIMEOUT(rCurrentTime, prRoamingFsmInfo->rRoamingDiscoveryUpdateTime, + SEC_TO_SYSTIME(ROAMING_DISCOVERY_TIMEOUT_SEC))) { + DBGLOG(ROAMING, LOUD, ("roamingFsmSteps: DiscoveryUpdateTime Timeout")); + aisFsmRunEventRoamingDiscovery(prAdapter, TRUE); + } + else { + DBGLOG(ROAMING, LOUD, ("roamingFsmSteps: DiscoveryUpdateTime Updated")); + aisFsmRunEventRoamingDiscovery(prAdapter, FALSE); + } + } + break; + + case ROAMING_STATE_ROAM: + break; + + default: + ASSERT(0); /* Make sure we have handle all STATEs */ + } + } + while (fgIsTransition); + + return; + +} /* end of roamingFsmSteps() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Transit to Decision state after join completion +* +* @param [IN P_ADAPTER_T] prAdapter +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +roamingFsmRunEventStart ( + IN P_ADAPTER_T prAdapter + ) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + ENUM_ROAMING_STATE_T eNextState; + P_BSS_INFO_T prAisBssInfo; + ROAMING_PARAM_T rParam; + + prRoamingFsmInfo = (P_ROAMING_INFO_T)&(prAdapter->rWifiVar.rRoamingInfo); + + /* Check Roaming Conditions */ + ROAMING_ENABLE_CHECK(prRoamingFsmInfo); + + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + if (prAisBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) { + return; + } + + DBGLOG(ROAMING, EVENT, ("EVENT-ROAMING START: Current Time = %ld\n", kalGetTimeTick())); + + /* IDLE, ROAM -> DECISION */ + /* Errors as DECISION, DISCOVERY -> DECISION */ + if (!(prRoamingFsmInfo->eCurrentState == ROAMING_STATE_IDLE + || prRoamingFsmInfo->eCurrentState == ROAMING_STATE_ROAM)) { + return; + } + + eNextState = ROAMING_STATE_DECISION; + if (eNextState != prRoamingFsmInfo->eCurrentState) { + rParam.u2Event = ROAMING_EVENT_START; + roamingFsmSendCmd(prAdapter, (P_ROAMING_PARAM_T) &rParam); + + /* Step to next state */ + roamingFsmSteps(prAdapter, eNextState); + } + + return; +} /* end of roamingFsmRunEventStart() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Transit to Discovery state when deciding to find a candidate +* +* @param [IN P_ADAPTER_T] prAdapter +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +roamingFsmRunEventDiscovery ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Param + ) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + ENUM_ROAMING_STATE_T eNextState; + + prRoamingFsmInfo = (P_ROAMING_INFO_T)&(prAdapter->rWifiVar.rRoamingInfo); + + /* Check Roaming Conditions */ + ROAMING_ENABLE_CHECK(prRoamingFsmInfo); + + DBGLOG(ROAMING, EVENT, ("EVENT-ROAMING DISCOVERY: Current Time = %ld\n", kalGetTimeTick())); + + /* DECISION -> DISCOVERY */ + /* Errors as IDLE, DISCOVERY, ROAM -> DISCOVERY */ + if (prRoamingFsmInfo->eCurrentState != ROAMING_STATE_DECISION) { + return; + } + + eNextState = ROAMING_STATE_DISCOVERY; + /* DECISION -> DISCOVERY */ + if (eNextState != prRoamingFsmInfo->eCurrentState) { + P_BSS_INFO_T prAisBssInfo; + P_BSS_DESC_T prBssDesc; + + // sync. rcpi with firmware + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prBssDesc = scanSearchBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); + if (prBssDesc) { + prBssDesc->ucRCPI = (UINT_8)(u4Param&0xff); + } + + roamingFsmSteps(prAdapter, eNextState); + } + + return; +} /* end of roamingFsmRunEventDiscovery() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Transit to Roam state after Scan Done +* +* @param [IN P_ADAPTER_T] prAdapter +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +roamingFsmRunEventRoam ( + IN P_ADAPTER_T prAdapter + ) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + ENUM_ROAMING_STATE_T eNextState; + ROAMING_PARAM_T rParam; + + prRoamingFsmInfo = (P_ROAMING_INFO_T)&(prAdapter->rWifiVar.rRoamingInfo); + + /* Check Roaming Conditions */ + ROAMING_ENABLE_CHECK(prRoamingFsmInfo); + + DBGLOG(ROAMING, EVENT, ("EVENT-ROAMING ROAM: Current Time = %ld\n", kalGetTimeTick())); + + /* IDLE, ROAM -> DECISION */ + /* Errors as IDLE, DECISION, ROAM -> ROAM */ + if (prRoamingFsmInfo->eCurrentState != ROAMING_STATE_DISCOVERY) { + return; + } + + eNextState = ROAMING_STATE_ROAM; + /* DISCOVERY -> ROAM */ + if (eNextState != prRoamingFsmInfo->eCurrentState) { + rParam.u2Event = ROAMING_EVENT_ROAM; + roamingFsmSendCmd(prAdapter, (P_ROAMING_PARAM_T) &rParam); + + /* Step to next state */ + roamingFsmSteps(prAdapter, eNextState); + } + + return; +} /* end of roamingFsmRunEventRoam() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Transit to Decision state as being failed to find out any candidate +* +* @param [IN P_ADAPTER_T] prAdapter +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +roamingFsmRunEventFail ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Param + ) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + ENUM_ROAMING_STATE_T eNextState; + ROAMING_PARAM_T rParam; + + prRoamingFsmInfo = (P_ROAMING_INFO_T)&(prAdapter->rWifiVar.rRoamingInfo); + + /* Check Roaming Conditions */ + ROAMING_ENABLE_CHECK(prRoamingFsmInfo); + + DBGLOG(ROAMING, EVENT, ("EVENT-ROAMING FAIL: reason %x Current Time = %ld\n", u4Param, kalGetTimeTick())); + + /* IDLE, ROAM -> DECISION */ + /* Errors as IDLE, DECISION, DISCOVERY -> DECISION */ + if (prRoamingFsmInfo->eCurrentState != ROAMING_STATE_ROAM) { + return; + } + + eNextState = ROAMING_STATE_DECISION; + /* ROAM -> DECISION */ + if (eNextState != prRoamingFsmInfo->eCurrentState) { + rParam.u2Event = ROAMING_EVENT_FAIL; + rParam.u2Data = (UINT_16)(u4Param&0xffff); + roamingFsmSendCmd(prAdapter, (P_ROAMING_PARAM_T) &rParam); + + /* Step to next state */ + roamingFsmSteps(prAdapter, eNextState); + } + + return; +} /* end of roamingFsmRunEventFail() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Transit to Idle state as beging aborted by other moduels, AIS +* +* @param [IN P_ADAPTER_T] prAdapter +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +roamingFsmRunEventAbort ( + IN P_ADAPTER_T prAdapter + ) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + ENUM_ROAMING_STATE_T eNextState; + ROAMING_PARAM_T rParam; + + prRoamingFsmInfo = (P_ROAMING_INFO_T)&(prAdapter->rWifiVar.rRoamingInfo); + + ROAMING_ENABLE_CHECK(prRoamingFsmInfo); + + DBGLOG(ROAMING, EVENT, ("EVENT-ROAMING ABORT: Current Time = %ld\n", kalGetTimeTick())); + + eNextState = ROAMING_STATE_IDLE; + /* IDLE, DECISION, DISCOVERY, ROAM -> IDLE */ + if (eNextState != prRoamingFsmInfo->eCurrentState) { + rParam.u2Event = ROAMING_EVENT_ABORT; + roamingFsmSendCmd(prAdapter, (P_ROAMING_PARAM_T) &rParam); + + /* Step to next state */ + roamingFsmSteps(prAdapter, eNextState); + } + + return; +} /* end of roamingFsmRunEventAbort() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process events from firmware +* +* @param [IN P_ADAPTER_T] prAdapter +* [IN P_ROAMING_PARAM_T] prParam +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +roamingFsmProcessEvent ( + IN P_ADAPTER_T prAdapter, + IN P_ROAMING_PARAM_T prParam + ) +{ + DBGLOG(ROAMING, LOUD, ("ROAMING Process Events: Current Time = %ld\n", kalGetTimeTick())); + + if (ROAMING_EVENT_DISCOVERY == prParam->u2Event) { + roamingFsmRunEventDiscovery(prAdapter, prParam->u2Data); + } + + return WLAN_STATUS_SUCCESS; +} + +#endif diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/rsn.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/rsn.c new file mode 100755 index 000000000000..84aa4d677ca5 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/rsn.c @@ -0,0 +1,2653 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/mgmt/rsn.c#2 $ +*/ + +/*! \file "rsn.c" + \brief This file including the 802.11i, wpa and wpa2(rsn) related function. + + This file provided the macros and functions library support the wpa/rsn ie parsing, + cipher and AKM check to help the AP seleced deciding, tkip mic error handler and rsn PMKID support. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: rsn.c $ + * + * 02 14 2012 yuche.tsai + * [ALPS00118350] [ALPS.ICS][WiFi Direct] Dirver update for wifi direct connection + * Replace Beacon/Probe Response IE by driver generating instead of from supplicant. + * + * 01 30 2012 chinglan.wang + * [ALPS00118489] [Need Patch] [Volunteer Patch] [ICS] [Wi-Fi Direct] Update wpa_supplicant_8 (p2p supplicant) for ICS Wi-Fi direct mode. + * . + * + * 01 27 2012 yuche.tsai + * [ALPS00118350] [ALPS.ICS][WiFi Direct] Dirver update for wifi direct connection + * Fix compile warning & update latest driver 2.2. + * Davinci Label: 20120127_ALPS_WIFI_P2P_DRIVER_V2_1 + * + * 01 19 2012 chinglan.wang + * NULL + * Support the WPA-PSK TKIP security mode for the tethering.. + * + * 11 11 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * modify the xlog related code. + * + * 11 10 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * change the debug module level. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 02 09 2011 wh.su + * [WCXRP00000432] [MT6620 Wi-Fi][Driver] Add STA privacy check at hotspot mode + * adding the code for check STA privacy bit at AP mode, . + * + * 12 24 2010 chinglan.wang + * NULL + * [MT6620][Wi-Fi] Modify the key management in the driver for WPS function. + * + * 12 13 2010 cp.wu + * [WCXRP00000260] [MT6620 Wi-Fi][Driver][Firmware] Create V1.1 branch for both firmware and driver + * create branch for Wi-Fi driver v1.1 + * + * 11 05 2010 wh.su + * [WCXRP00000165] [MT6620 Wi-Fi] [Pre-authentication] Assoc req rsn ie use wrong pmkid value + * fixed the.pmkid value mismatch issue + * + * 11 03 2010 wh.su + * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group + * Refine the HT rate disallow TKIP pairwise cipher . + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by ENUM_NETWORK_TYPE_INDEX_T only + * remove ENUM_NETWORK_TYPE_T definitions + * + * 09 29 2010 yuche.tsai + * NULL + * Fix compile error, remove unused pointer in rsnGenerateRSNIE(). + * + * 09 28 2010 wh.su + * NULL + * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. + * + * 09 24 2010 wh.su + * NULL + * [WCXRP00005002][MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning. + * + * 09 06 2010 wh.su + * NULL + * let the p2p can set the privacy bit at beacon and rsn ie at assoc req at key handshake state. + * + * 08 30 2010 wh.su + * NULL + * remove non-used code. + * + * 08 19 2010 wh.su + * NULL + * adding the tx pkt call back handle for countermeasure. + * + * 07 24 2010 wh.su + * + * .support the Wi-Fi RSN + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * modify some code for concurrent network. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * [WPD00003833][MT6620 and MT5931] Driver migration + * enable RX management frame handling. + * + * 06 19 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * consdier the concurrent network setting. + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * [WPD00003840] [MT6620 5931] Security migration + * migration from firmware. + * + * 05 27 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * not indiate pmkid candidate while no new one scaned. + * + * 04 29 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * adjsut the pre-authentication code. + * + * 03 03 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * move the AIS specific variable for security to AIS specific structure. + * + * 03 03 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * Fixed the pre-authentication timer not correctly init issue, and modify the security related callback function prototype. + * + * 01 27 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * add and fixed some security function. + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Dec 8 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * change the name + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * using the Rx0 port to indicate event + * + * Dec 4 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * refine the code for generate the WPA/RSN IE for assoc req + * + * Dec 3 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adjust code for pmkid event + * + * Dec 1 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the code for event (mic error and pmkid indicate) and do some function rename + * + * Nov 23 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding some security function + * + * Nov 19 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding some security feature, including pmkid + * + * Nov 18 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +#if CFG_RSN_MIGRATION + +//extern PHY_ATTRIBUTE_T rPhyAttributes[]; + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to parse RSN IE. +* +* \param[in] prInfoElem Pointer to the RSN IE +* \param[out] prRsnInfo Pointer to the BSSDescription structure to store the +** RSN information from the given RSN IE +* +* \retval TRUE - Succeeded +* \retval FALSE - Failed +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +rsnParseRsnIE ( + IN P_ADAPTER_T prAdapter, + IN P_RSN_INFO_ELEM_T prInfoElem, + OUT P_RSN_INFO_T prRsnInfo + ) +{ + UINT_32 i; + INT_32 u4RemainRsnIeLen; + UINT_16 u2Version; + UINT_16 u2Cap = 0; + UINT_32 u4GroupSuite = RSN_CIPHER_SUITE_CCMP; + UINT_16 u2PairSuiteCount = 0; + UINT_16 u2AuthSuiteCount = 0; + PUINT_8 pucPairSuite = NULL; + PUINT_8 pucAuthSuite = NULL; + PUINT_8 cp; + + DEBUGFUNC("rsnParseRsnIE"); + + ASSERT(prInfoElem); + ASSERT(prRsnInfo); + + /* Verify the length of the RSN IE. */ + if (prInfoElem->ucLength < 2) { + DBGLOG(RSN, TRACE, ("RSN IE length too short (length=%d)\n", prInfoElem->ucLength)); + return FALSE; + } + + /* Check RSN version: currently, we only support version 1. */ + WLAN_GET_FIELD_16(&prInfoElem->u2Version, &u2Version); + if (u2Version != 1) { + DBGLOG(RSN, TRACE,("Unsupported RSN IE version: %d\n", u2Version)); + return FALSE; + } + + cp = (PUCHAR) &prInfoElem->u4GroupKeyCipherSuite; + u4RemainRsnIeLen = (INT_32) prInfoElem->ucLength - 2; + + do { + if (u4RemainRsnIeLen == 0) { + break; + } + + /* Parse the Group Key Cipher Suite field. */ + if (u4RemainRsnIeLen < 4) { + DBGLOG(RSN, TRACE, ("Fail to parse RSN IE in group cipher suite (IE len: %d)\n", + prInfoElem->ucLength)); + return FALSE; + } + + WLAN_GET_FIELD_32(cp, &u4GroupSuite); + cp += 4; + u4RemainRsnIeLen -= 4; + + if (u4RemainRsnIeLen == 0) { + break; + } + + /* Parse the Pairwise Key Cipher Suite Count field. */ + if (u4RemainRsnIeLen < 2) { + DBGLOG(RSN, TRACE,("Fail to parse RSN IE in pairwise cipher suite count (IE len: %d)\n", + prInfoElem->ucLength)); + return FALSE; + } + + WLAN_GET_FIELD_16(cp, &u2PairSuiteCount); + cp += 2; + u4RemainRsnIeLen -= 2; + + /* Parse the Pairwise Key Cipher Suite List field. */ + i = (UINT_32) u2PairSuiteCount * 4; + if (u4RemainRsnIeLen < (INT_32) i) { + DBGLOG(RSN, TRACE,("Fail to parse RSN IE in pairwise cipher suite list (IE len: %d)\n", + prInfoElem->ucLength)); + return FALSE; + } + + pucPairSuite = cp; + + cp += i; + u4RemainRsnIeLen -= (INT_32) i; + + if (u4RemainRsnIeLen == 0) { + break; + } + + /* Parse the Authentication and Key Management Cipher Suite Count field. */ + if (u4RemainRsnIeLen < 2) { + DBGLOG(RSN, TRACE,("Fail to parse RSN IE in auth & key mgt suite count (IE len: %d)\n", + prInfoElem->ucLength)); + return FALSE; + } + + WLAN_GET_FIELD_16(cp, &u2AuthSuiteCount); + cp += 2; + u4RemainRsnIeLen -= 2; + + /* Parse the Authentication and Key Management Cipher Suite List + field. */ + i = (UINT_32) u2AuthSuiteCount * 4; + if (u4RemainRsnIeLen < (INT_32) i) { + DBGLOG(RSN, TRACE, ("Fail to parse RSN IE in auth & key mgt suite list (IE len: %d)\n", + prInfoElem->ucLength)); + return FALSE; + } + + pucAuthSuite = cp; + + cp += i; + u4RemainRsnIeLen -= (INT_32) i; + + if (u4RemainRsnIeLen == 0) { + break; + } + + /* Parse the RSN u2Capabilities field. */ + if (u4RemainRsnIeLen < 2) { + DBGLOG(RSN, TRACE, ("Fail to parse RSN IE in RSN capabilities (IE len: %d)\n", + prInfoElem->ucLength)); + return FALSE; + } + + WLAN_GET_FIELD_16(cp, &u2Cap); + } while (FALSE); + + /* Save the RSN information for the BSS. */ + prRsnInfo->ucElemId = ELEM_ID_RSN; + + prRsnInfo->u2Version = u2Version; + + prRsnInfo->u4GroupKeyCipherSuite = u4GroupSuite; + + DBGLOG(RSN, LOUD, ("RSN: version %d, group key cipher suite %02x-%02x-%02x-%02x\n", + u2Version, (UCHAR) (u4GroupSuite & 0x000000FF), + (UCHAR) ((u4GroupSuite >> 8) & 0x000000FF), + (UCHAR) ((u4GroupSuite >> 16) & 0x000000FF), + (UCHAR) ((u4GroupSuite >> 24) & 0x000000FF))); + + if (pucPairSuite) { + /* The information about the pairwise key cipher suites is present. */ + if (u2PairSuiteCount > MAX_NUM_SUPPORTED_CIPHER_SUITES) { + u2PairSuiteCount = MAX_NUM_SUPPORTED_CIPHER_SUITES; + } + + prRsnInfo->u4PairwiseKeyCipherSuiteCount = (UINT_32) u2PairSuiteCount; + + for (i = 0; i < (UINT_32) u2PairSuiteCount; i++) { + WLAN_GET_FIELD_32(pucPairSuite, + &prRsnInfo->au4PairwiseKeyCipherSuite[i]); + pucPairSuite += 4; + + DBGLOG(RSN, LOUD, ("RSN: pairwise key cipher suite [%d]: %02x-%02x-%02x-%02x\n", + (UINT_8)i, (UCHAR) (prRsnInfo->au4PairwiseKeyCipherSuite[i] & 0x000000FF), + (UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[i] >> 8) & 0x000000FF), + (UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[i] >> 16) & 0x000000FF), + (UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[i] >> 24) & 0x000000FF))); + } + } + else { + /* The information about the pairwise key cipher suites is not present. + Use the default chipher suite for RSN: CCMP. */ + prRsnInfo->u4PairwiseKeyCipherSuiteCount = 1; + prRsnInfo->au4PairwiseKeyCipherSuite[0] = RSN_CIPHER_SUITE_CCMP; + + DBGLOG(RSN, LOUD, ("RSN: pairwise key cipher suite: %02x-%02x-%02x-%02x (default)\n", + (UCHAR) (prRsnInfo->au4PairwiseKeyCipherSuite[0] & 0x000000FF), + (UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[0] >> 8) & 0x000000FF), + (UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[0] >> 16) & 0x000000FF), + (UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[0] >> 24) & 0x000000FF))); + } + + if (pucAuthSuite) { + /* The information about the authentication and key management suites + is present. */ + if (u2AuthSuiteCount > MAX_NUM_SUPPORTED_AKM_SUITES) { + u2AuthSuiteCount = MAX_NUM_SUPPORTED_AKM_SUITES; + } + + prRsnInfo->u4AuthKeyMgtSuiteCount = (UINT_32) u2AuthSuiteCount; + + for (i = 0; i < (UINT_32) u2AuthSuiteCount; i++) { + WLAN_GET_FIELD_32(pucAuthSuite, &prRsnInfo->au4AuthKeyMgtSuite[i]); + pucAuthSuite += 4; + + DBGLOG(RSN, LOUD, ("RSN: AKM suite [%d]: %02x-%02x-%02x-%02x\n", + (UINT_8)i, (UCHAR) (prRsnInfo->au4AuthKeyMgtSuite[i] & 0x000000FF), + (UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[i] >> 8) & 0x000000FF), + (UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[i] >> 16) & 0x000000FF), + (UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[i] >> 24) & 0x000000FF))); + } + } + else { + /* The information about the authentication and key management suites + is not present. Use the default AKM suite for RSN. */ + prRsnInfo->u4AuthKeyMgtSuiteCount = 1; + prRsnInfo->au4AuthKeyMgtSuite[0] = RSN_AKM_SUITE_802_1X; + + DBGLOG(RSN, LOUD, ("RSN: AKM suite: %02x-%02x-%02x-%02x (default)\n", + (UCHAR) (prRsnInfo->au4AuthKeyMgtSuite[0] & 0x000000FF), + (UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[0] >> 8) & 0x000000FF), + (UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[0] >> 16) & 0x000000FF), + (UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[0] >> 24) & 0x000000FF))); + } + + prRsnInfo->u2RsnCap = u2Cap; +#if CFG_SUPPORT_802_11W + prRsnInfo->fgRsnCapPresent = TRUE; +#endif + DBGLOG(RSN, LOUD, ("RSN cap: 0x%04x\n", prRsnInfo->u2RsnCap)); + + return TRUE; +} /* rsnParseRsnIE */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to parse WPA IE. +* +* \param[in] prInfoElem Pointer to the WPA IE. +* \param[out] prWpaInfo Pointer to the BSSDescription structure to store the +* WPA information from the given WPA IE. +* +* \retval TRUE Succeeded. +* \retval FALSE Failed. +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +rsnParseWpaIE ( + IN P_ADAPTER_T prAdapter, + IN P_WPA_INFO_ELEM_T prInfoElem, + OUT P_RSN_INFO_T prWpaInfo + ) +{ + UINT_32 i; + INT_32 u4RemainWpaIeLen; + UINT_16 u2Version; + UINT_16 u2Cap = 0; + UINT_32 u4GroupSuite = WPA_CIPHER_SUITE_TKIP; + UINT_16 u2PairSuiteCount = 0; + UINT_16 u2AuthSuiteCount = 0; + PUCHAR pucPairSuite = NULL; + PUCHAR pucAuthSuite = NULL; + PUCHAR cp; + BOOLEAN fgCapPresent = FALSE; + + DEBUGFUNC("rsnParseWpaIE"); + + ASSERT(prInfoElem); + ASSERT(prWpaInfo); + + /* Verify the length of the WPA IE. */ + if (prInfoElem->ucLength < 6) { + DBGLOG(RSN, TRACE,("WPA IE length too short (length=%d)\n", prInfoElem->ucLength)); + return FALSE; + } + + /* Check WPA version: currently, we only support version 1. */ + WLAN_GET_FIELD_16(&prInfoElem->u2Version, &u2Version); + if (u2Version != 1) { + DBGLOG(RSN, TRACE, ("Unsupported WPA IE version: %d\n", u2Version)); + return FALSE; + } + + cp = (PUCHAR) &prInfoElem->u4GroupKeyCipherSuite; + u4RemainWpaIeLen = (INT_32) prInfoElem->ucLength - 6; + + do { + if (u4RemainWpaIeLen == 0) { + break; + } + + /* WPA_OUI : 4 + Version : 2 + GroupSuite : 4 + PairwiseCount: 2 + PairwiseSuite: 4 * pairSuiteCount + AuthCount : 2 + AuthSuite : 4 * authSuiteCount + Cap : 2 */ + + /* Parse the Group Key Cipher Suite field. */ + if (u4RemainWpaIeLen < 4) { + DBGLOG(RSN, TRACE,("Fail to parse WPA IE in group cipher suite (IE len: %d)\n", + prInfoElem->ucLength)); + return FALSE; + } + + WLAN_GET_FIELD_32(cp, &u4GroupSuite); + cp += 4; + u4RemainWpaIeLen -= 4; + + if (u4RemainWpaIeLen == 0) { + break; + } + + /* Parse the Pairwise Key Cipher Suite Count field. */ + if (u4RemainWpaIeLen < 2) { + DBGLOG(RSN, TRACE,("Fail to parse WPA IE in pairwise cipher suite count (IE len: %d)\n", + prInfoElem->ucLength)); + return FALSE; + } + + WLAN_GET_FIELD_16(cp, &u2PairSuiteCount); + cp += 2; + u4RemainWpaIeLen -= 2; + + /* Parse the Pairwise Key Cipher Suite List field. */ + i = (UINT_32) u2PairSuiteCount * 4; + if (u4RemainWpaIeLen < (INT_32) i) { + DBGLOG(RSN, TRACE,("Fail to parse WPA IE in pairwise cipher suite list (IE len: %d)\n", + prInfoElem->ucLength)); + return FALSE; + } + + pucPairSuite = cp; + + cp += i; + u4RemainWpaIeLen -= (INT_32) i; + + if (u4RemainWpaIeLen == 0) { + break; + } + + /* Parse the Authentication and Key Management Cipher Suite Count + field. */ + if (u4RemainWpaIeLen < 2) { + DBGLOG(RSN, TRACE,("Fail to parse WPA IE in auth & key mgt suite count (IE len: %d)\n", + prInfoElem->ucLength)); + return FALSE; + } + + WLAN_GET_FIELD_16(cp, &u2AuthSuiteCount); + cp += 2; + u4RemainWpaIeLen -= 2; + + /* Parse the Authentication and Key Management Cipher Suite List + field. */ + i = (UINT_32) u2AuthSuiteCount * 4; + if (u4RemainWpaIeLen < (INT_32) i) { + DBGLOG(RSN, TRACE, ("Fail to parse WPA IE in auth & key mgt suite list (IE len: %d)\n", + prInfoElem->ucLength)); + return FALSE; + } + + pucAuthSuite = cp; + + cp += i; + u4RemainWpaIeLen -= (INT_32) i; + + if (u4RemainWpaIeLen == 0) { + break; + } + + /* Parse the WPA u2Capabilities field. */ + if (u4RemainWpaIeLen < 2) { + DBGLOG(RSN, TRACE, ("Fail to parse WPA IE in WPA capabilities (IE len: %d)\n", + prInfoElem->ucLength)); + return FALSE; + } + + fgCapPresent = TRUE; + WLAN_GET_FIELD_16(cp, &u2Cap); + u4RemainWpaIeLen -= 2; + } while (FALSE); + + /* Save the WPA information for the BSS. */ + + prWpaInfo->ucElemId = ELEM_ID_WPA; + + prWpaInfo->u2Version = u2Version; + + prWpaInfo->u4GroupKeyCipherSuite = u4GroupSuite; + + DBGLOG(RSN, LOUD, ("WPA: version %d, group key cipher suite %02x-%02x-%02x-%02x\n", + u2Version, (UCHAR) (u4GroupSuite & 0x000000FF), + (UCHAR) ((u4GroupSuite >> 8) & 0x000000FF), + (UCHAR) ((u4GroupSuite >> 16) & 0x000000FF), + (UCHAR) ((u4GroupSuite >> 24) & 0x000000FF))); + + if (pucPairSuite) { + /* The information about the pairwise key cipher suites is present. */ + if (u2PairSuiteCount > MAX_NUM_SUPPORTED_CIPHER_SUITES) { + u2PairSuiteCount = MAX_NUM_SUPPORTED_CIPHER_SUITES; + } + + prWpaInfo->u4PairwiseKeyCipherSuiteCount = (UINT_32) u2PairSuiteCount; + + for (i = 0; i < (UINT_32) u2PairSuiteCount; i++) { + WLAN_GET_FIELD_32(pucPairSuite, + &prWpaInfo->au4PairwiseKeyCipherSuite[i]); + pucPairSuite += 4; + + DBGLOG(RSN, LOUD, ("WPA: pairwise key cipher suite [%d]: %02x-%02x-%02x-%02x\n", + (UINT_8)i, (UCHAR) (prWpaInfo->au4PairwiseKeyCipherSuite[i] & 0x000000FF), + (UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[i] >> 8) & 0x000000FF), + (UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[i] >> 16) & 0x000000FF), + (UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[i] >> 24) & 0x000000FF))); + } + } + else { + /* The information about the pairwise key cipher suites is not present. + Use the default chipher suite for WPA: TKIP. */ + prWpaInfo->u4PairwiseKeyCipherSuiteCount = 1; + prWpaInfo->au4PairwiseKeyCipherSuite[0] = WPA_CIPHER_SUITE_TKIP; + + DBGLOG(RSN, LOUD, ("WPA: pairwise key cipher suite: %02x-%02x-%02x-%02x (default)\n", + (UCHAR) (prWpaInfo->au4PairwiseKeyCipherSuite[0] & 0x000000FF), + (UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[0] >> 8) & 0x000000FF), + (UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[0] >> 16) & 0x000000FF), + (UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[0] >> 24) & 0x000000FF))); + } + + if (pucAuthSuite) { + /* The information about the authentication and key management suites + is present. */ + if (u2AuthSuiteCount > MAX_NUM_SUPPORTED_AKM_SUITES) { + u2AuthSuiteCount = MAX_NUM_SUPPORTED_AKM_SUITES; + } + + prWpaInfo->u4AuthKeyMgtSuiteCount = (UINT_32) u2AuthSuiteCount; + + for (i = 0; i < (UINT_32) u2AuthSuiteCount; i++) { + WLAN_GET_FIELD_32(pucAuthSuite, &prWpaInfo->au4AuthKeyMgtSuite[i]); + pucAuthSuite += 4; + + DBGLOG(RSN, LOUD, ("WPA: AKM suite [%d]: %02x-%02x-%02x-%02x\n", + (UINT_8)i, (UCHAR) (prWpaInfo->au4AuthKeyMgtSuite[i] & 0x000000FF), + (UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[i] >> 8) & 0x000000FF), + (UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[i] >> 16) & 0x000000FF), + (UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[i] >> 24) & 0x000000FF))); + } + } + else { + /* The information about the authentication and key management suites + is not present. Use the default AKM suite for WPA. */ + prWpaInfo->u4AuthKeyMgtSuiteCount = 1; + prWpaInfo->au4AuthKeyMgtSuite[0] = WPA_AKM_SUITE_802_1X; + + DBGLOG(RSN, LOUD, ("WPA: AKM suite: %02x-%02x-%02x-%02x (default)\n", + (UCHAR) (prWpaInfo->au4AuthKeyMgtSuite[0] & 0x000000FF), + (UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[0] >> 8) & 0x000000FF), + (UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[0] >> 16) & 0x000000FF), + (UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[0] >> 24) & 0x000000FF))); + } + + if (fgCapPresent) { + prWpaInfo->fgRsnCapPresent = TRUE; + prWpaInfo->u2RsnCap = u2Cap; + DBGLOG(RSN, LOUD, ("WPA: RSN cap: 0x%04x\n", prWpaInfo->u2RsnCap)); + } + else { + prWpaInfo->fgRsnCapPresent = FALSE; + prWpaInfo->u2RsnCap = 0; + } + + return TRUE; +} /* rsnParseWpaIE */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to search the desired pairwise +* cipher suite from the MIB Pairwise Cipher Suite +* configuration table. +* +* \param[in] u4Cipher The desired pairwise cipher suite to be searched +* \param[out] pu4Index Pointer to the index of the desired pairwise cipher in +* the table +* +* \retval TRUE - The desired pairwise cipher suite is found in the table. +* \retval FALSE - The desired pairwise cipher suite is not found in the +* table. +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +rsnSearchSupportedCipher ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Cipher, + OUT PUINT_32 pu4Index + ) +{ + UINT_8 i; + P_DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY prEntry; + + DEBUGFUNC("rsnSearchSupportedCipher"); + + ASSERT(pu4Index); + + for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i++) { + prEntry = &prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[i]; + if (prEntry->dot11RSNAConfigPairwiseCipher == u4Cipher && + prEntry->dot11RSNAConfigPairwiseCipherEnabled) { + *pu4Index = i; + return TRUE; + } + } + return FALSE; +} /* rsnSearchSupportedCipher */ + + +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to search the desired +* authentication and key management (AKM) suite from the +* MIB Authentication and Key Management Suites table. +* +* \param[in] u4AkmSuite The desired AKM suite to be searched +* \param[out] pu4Index Pointer to the index of the desired AKM suite in the +* table +* +* \retval TRUE The desired AKM suite is found in the table. +* \retval FALSE The desired AKM suite is not found in the table. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +rsnSearchAKMSuite ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4AkmSuite, + OUT PUINT_32 pu4Index + ) +{ + UINT_8 i; + P_DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY prEntry; + + DEBUGFUNC("rsnSearchAKMSuite"); + + ASSERT(pu4Index); + + for (i = 0; i < MAX_NUM_SUPPORTED_AKM_SUITES; i++) { + prEntry = &prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[i]; + if (prEntry->dot11RSNAConfigAuthenticationSuite == u4AkmSuite && + prEntry->dot11RSNAConfigAuthenticationSuiteEnabled) { + *pu4Index = i; + return TRUE; + } + } + return FALSE; +} /* rsnSearchAKMSuite */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to perform RSNA or TSN policy +* selection for a given BSS. +* +* \param[in] prBss Pointer to the BSS description +* +* \retval TRUE - The RSNA/TSN policy selection for the given BSS is +* successful. The selected pairwise and group cipher suites +* are returned in the BSS description. +* \retval FALSE - The RSNA/TSN policy selection for the given BSS is failed. +* The driver shall not attempt to join the given BSS. +* +* \note The Encrypt status matched score will save to bss for final ap select. +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +rsnPerformPolicySelection ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBss + ) +{ +#if CFG_SUPPORT_802_11W + INT_32 i; + UINT_32 j; +#else + UINT_32 i, j; +#endif + BOOLEAN fgSuiteSupported; + UINT_32 u4PairwiseCipher = 0; + UINT_32 u4GroupCipher = 0; + UINT_32 u4AkmSuite = 0; + P_RSN_INFO_T prBssRsnInfo; + ENUM_NETWORK_TYPE_INDEX_T eNetwotkType; + BOOLEAN fgIsWpsActive = (BOOLEAN)FALSE; + + DEBUGFUNC("rsnPerformPolicySelection"); + + ASSERT(prBss); + + DBGLOG(RSN, TRACE, ("rsnPerformPolicySelection\n")); + //Todo:: + eNetwotkType = NETWORK_TYPE_AIS_INDEX; + + prBss->u4RsnSelectedPairwiseCipher = 0; + prBss->u4RsnSelectedGroupCipher = 0; + prBss->u4RsnSelectedAKMSuite = 0; + prBss->ucEncLevel = 0; + +#if CFG_SUPPORT_WPS + fgIsWpsActive = kalWSCGetActiveState(prAdapter->prGlueInfo); + + /* CR1640, disable the AP select privacy check */ + if ( fgIsWpsActive && + (prAdapter->rWifiVar.rConnSettings.eAuthMode < AUTH_MODE_WPA) && + (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA)) { + DBGLOG(RSN, TRACE,("-- Skip the Protected BSS check\n")); + return TRUE; + } +#endif + + /* Protection is not required in this BSS. */ + if ((prBss->u2CapInfo & CAP_INFO_PRIVACY) == 0 ) { + + if (secEnabledInAis(prAdapter) == FALSE) { + DBGLOG(RSN, TRACE,("-- No Protected BSS\n")); + return TRUE; + } + else { + DBGLOG(RSN, TRACE,("-- Protected BSS\n")); + return FALSE; + } + } + + /* Protection is required in this BSS. */ + if ((prBss->u2CapInfo & CAP_INFO_PRIVACY) != 0) { + if (secEnabledInAis(prAdapter) == FALSE) { + DBGLOG(RSN, TRACE,("-- Protected BSS\n")); + return FALSE; + } + } + + if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA || + prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_PSK || + prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_NONE) { + + if (prBss->fgIEWPA) { + prBssRsnInfo = &prBss->rWPAInfo; + } + else { + DBGLOG(RSN, TRACE, ("WPA Information Element does not exist.\n")); + return FALSE; + } + } + else if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2 || + prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2_PSK) { + + if (prBss->fgIERSN) { + prBssRsnInfo = &prBss->rRSNInfo; + } + else { + DBGLOG(RSN, TRACE, ("RSN Information Element does not exist.\n")); + return FALSE; + } + } + else if (prAdapter->rWifiVar.rConnSettings.eEncStatus != ENUM_ENCRYPTION1_ENABLED) { + /* If the driver is configured to use WEP only, ignore this BSS. */ + DBGLOG(RSN, TRACE, ("-- Not WEP-only legacy BSS\n")); + return FALSE; + } + else if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION1_ENABLED) { + /* If the driver is configured to use WEP only, use this BSS. */ + DBGLOG(RSN, TRACE, ("-- WEP-only legacy BSS\n")); + return TRUE; + } + + if (prBssRsnInfo->u4PairwiseKeyCipherSuiteCount == 1 && + GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[0]) == + CIPHER_SUITE_NONE) { + /* Since the pairwise cipher use the same cipher suite as the group + cipher in the BSS, we check the group cipher suite against the + current encryption status. */ + fgSuiteSupported = FALSE; + + switch (prBssRsnInfo->u4GroupKeyCipherSuite) { + case WPA_CIPHER_SUITE_CCMP: + case RSN_CIPHER_SUITE_CCMP: + if (prAdapter->rWifiVar.rConnSettings.eEncStatus == + ENUM_ENCRYPTION3_ENABLED) { + fgSuiteSupported = TRUE; + } + break; + + case WPA_CIPHER_SUITE_TKIP: + case RSN_CIPHER_SUITE_TKIP: + if (prAdapter->rWifiVar.rConnSettings.eEncStatus == + ENUM_ENCRYPTION2_ENABLED) { + fgSuiteSupported = TRUE; + } + break; + + case WPA_CIPHER_SUITE_WEP40: + case WPA_CIPHER_SUITE_WEP104: + if (prAdapter->rWifiVar.rConnSettings.eEncStatus == + ENUM_ENCRYPTION1_ENABLED) { + fgSuiteSupported = TRUE; + } + break; + } + + if (fgSuiteSupported) { + u4PairwiseCipher = WPA_CIPHER_SUITE_NONE; + u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite; + } +#if DBG + else { + DBGLOG(RSN, TRACE, ("Inproper encryption status %d for group-key-only BSS\n", + prAdapter->rWifiVar.rConnSettings.eEncStatus)); + } +#endif + } + else { + fgSuiteSupported = FALSE; + + DBGLOG(RSN, TRACE, ("eEncStatus %d %d 0x%x\n", prAdapter->rWifiVar.rConnSettings.eEncStatus, + prBssRsnInfo->u4PairwiseKeyCipherSuiteCount, + prBssRsnInfo->au4PairwiseKeyCipherSuite[0])); + /* Select pairwise/group ciphers */ + switch (prAdapter->rWifiVar.rConnSettings.eEncStatus) + { + case ENUM_ENCRYPTION3_ENABLED: + for (i = 0; i < prBssRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) { + if (GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[i]) + == CIPHER_SUITE_CCMP) { + u4PairwiseCipher = prBssRsnInfo->au4PairwiseKeyCipherSuite[i]; + } + } + u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite; + break; + + case ENUM_ENCRYPTION2_ENABLED: + for (i = 0; i < prBssRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) { + if (GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[i]) + == CIPHER_SUITE_TKIP) { + u4PairwiseCipher = prBssRsnInfo->au4PairwiseKeyCipherSuite[i]; + } + } + if (GET_SELECTOR_TYPE(prBssRsnInfo->u4GroupKeyCipherSuite) == + CIPHER_SUITE_CCMP) { + DBGLOG(RSN, TRACE, ("Cannot join CCMP BSS\n")); + } + else { + u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite; + } + break; + + case ENUM_ENCRYPTION1_ENABLED: + for (i = 0; i < prBssRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) { + if (GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[i]) + == CIPHER_SUITE_WEP40 || + GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[i]) + == CIPHER_SUITE_WEP104) { + u4PairwiseCipher = prBssRsnInfo->au4PairwiseKeyCipherSuite[i]; + } + } + if (GET_SELECTOR_TYPE(prBssRsnInfo->u4GroupKeyCipherSuite) == + CIPHER_SUITE_CCMP || + GET_SELECTOR_TYPE(prBssRsnInfo->u4GroupKeyCipherSuite) == + CIPHER_SUITE_TKIP) { + DBGLOG(RSN, TRACE, ("Cannot join CCMP/TKIP BSS\n")); + } + else { + u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite; + } + break; + + default: + break; + } + } + + /* Exception handler */ + /* If we cannot find proper pairwise and group cipher suites to join the + BSS, do not check the supported AKM suites. */ + if (u4PairwiseCipher == 0 || u4GroupCipher == 0) { + DBGLOG(RSN, TRACE, ("Failed to select pairwise/group cipher (0x%08lx/0x%08lx)\n", + u4PairwiseCipher, u4GroupCipher)); + return FALSE; + } + +#if CFG_ENABLE_WIFI_DIRECT + if ((prAdapter->fgIsP2PRegistered) && + (eNetwotkType == NETWORK_TYPE_P2P_INDEX)) { + if (u4PairwiseCipher != RSN_CIPHER_SUITE_CCMP || + u4GroupCipher != RSN_CIPHER_SUITE_CCMP || + u4AkmSuite != RSN_AKM_SUITE_PSK) { + DBGLOG(RSN, TRACE, ("Failed to select pairwise/group cipher for P2P network (0x%08lx/0x%08lx)\n", + u4PairwiseCipher, u4GroupCipher)); + return FALSE; + } + } +#endif + +#if CFG_ENABLE_BT_OVER_WIFI + if (eNetwotkType == NETWORK_TYPE_BOW_INDEX) { + if (u4PairwiseCipher != RSN_CIPHER_SUITE_CCMP || + u4GroupCipher != RSN_CIPHER_SUITE_CCMP || + u4AkmSuite != RSN_AKM_SUITE_PSK) { + } + DBGLOG(RSN, TRACE, ("Failed to select pairwise/group cipher for BT over Wi-Fi network (0x%08lx/0x%08lx)\n", + u4PairwiseCipher, u4GroupCipher)); + return FALSE; + } +#endif + + + /* Verify if selected pairwisse cipher is supported */ + fgSuiteSupported = rsnSearchSupportedCipher(prAdapter, u4PairwiseCipher, &i); + + /* Verify if selected group cipher is supported */ + if (fgSuiteSupported) { + fgSuiteSupported = rsnSearchSupportedCipher(prAdapter, u4GroupCipher, &i); + } + + if (!fgSuiteSupported) { + DBGLOG(RSN, TRACE, ("Failed to support selected pairwise/group cipher (0x%08lx/0x%08lx)\n", + u4PairwiseCipher, u4GroupCipher)); + return FALSE; + } + + /* Select AKM */ + /* If the driver cannot support any authentication suites advertised in + the given BSS, we fail to perform RSNA policy selection. */ + /* Attempt to find any overlapping supported AKM suite. */ +#if CFG_SUPPORT_802_11W + if (i != 0) + for (i = (prBssRsnInfo->u4AuthKeyMgtSuiteCount - 1); i >= 0; i--) +#else + for (i = 0; i < prBssRsnInfo->u4AuthKeyMgtSuiteCount; i++) +#endif + { + if (rsnSearchAKMSuite(prAdapter, + prBssRsnInfo->au4AuthKeyMgtSuite[i], + &j)) { + u4AkmSuite = prBssRsnInfo->au4AuthKeyMgtSuite[i]; + break; + } + } + + if (u4AkmSuite == 0) { + DBGLOG(RSN, TRACE, ("Cannot support any AKM suites\n")); + return FALSE; + } + + DBGLOG(RSN, TRACE, ("Selected pairwise/group cipher: %02x-%02x-%02x-%02x/%02x-%02x-%02x-%02x\n", + (UINT_8) (u4PairwiseCipher & 0x000000FF), + (UINT_8) ((u4PairwiseCipher >> 8) & 0x000000FF), + (UINT_8) ((u4PairwiseCipher >> 16) & 0x000000FF), + (UINT_8) ((u4PairwiseCipher >> 24) & 0x000000FF), + (UINT_8) (u4GroupCipher & 0x000000FF), + (UINT_8) ((u4GroupCipher >> 8) & 0x000000FF), + (UINT_8) ((u4GroupCipher >> 16) & 0x000000FF), + (UINT_8) ((u4GroupCipher >> 24) & 0x000000FF))); + + DBGLOG(RSN, TRACE, ("Selected AKM suite: %02x-%02x-%02x-%02x\n", + (UINT_8) (u4AkmSuite & 0x000000FF), + (UINT_8) ((u4AkmSuite >> 8) & 0x000000FF), + (UINT_8) ((u4AkmSuite >> 16) & 0x000000FF), + (UINT_8) ((u4AkmSuite >> 24) & 0x000000FF))); + +#if CFG_SUPPORT_802_11W + DBGLOG(RSN, TRACE, ("MFP setting = %d\n ", kalGetMfpSetting(prAdapter->prGlueInfo))); + + if (kalGetMfpSetting(prAdapter->prGlueInfo) == RSN_AUTH_MFP_REQUIRED) { + if (!prBssRsnInfo->fgRsnCapPresent) { + DBGLOG(RSN, TRACE, ("Skip RSN IE, No MFP Required Capability.\n")); + return FALSE; + } + else if (!(prBssRsnInfo->u2RsnCap & ELEM_WPA_CAP_MFPC)) { + DBGLOG(RSN, TRACE, ("Skip RSN IE, No MFP Required\n")); + return FALSE; + } + prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = TRUE; + } + else if (kalGetMfpSetting(prAdapter->prGlueInfo) == RSN_AUTH_MFP_OPTIONAL) { + if (prBssRsnInfo->u2RsnCap && ((prBssRsnInfo->u2RsnCap & ELEM_WPA_CAP_MFPR) || + (prBssRsnInfo->u2RsnCap & ELEM_WPA_CAP_MFPC))) { + prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = TRUE; + } + else { + prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = FALSE; + } + } + else { + if (prBssRsnInfo->fgRsnCapPresent && (prBssRsnInfo->u2RsnCap & ELEM_WPA_CAP_MFPR)) { + DBGLOG(RSN, TRACE, ("Skip RSN IE, No MFP Required Capability\n")); + return FALSE; + } + prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = FALSE; + } + DBGLOG(RSN, TRACE, ("fgMgmtProtection = %d\n ", prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection)); +#endif + + if (GET_SELECTOR_TYPE(u4GroupCipher) == CIPHER_SUITE_CCMP){ + prBss->ucEncLevel = 3; + } + else if (GET_SELECTOR_TYPE(u4GroupCipher) == CIPHER_SUITE_TKIP){ + prBss->ucEncLevel = 2; + } + else if (GET_SELECTOR_TYPE(u4GroupCipher) == CIPHER_SUITE_WEP40 || + GET_SELECTOR_TYPE(u4GroupCipher) == CIPHER_SUITE_WEP104) { + prBss->ucEncLevel = 1; + } + else { + ASSERT(FALSE); + } + prBss->u4RsnSelectedPairwiseCipher = u4PairwiseCipher; + prBss->u4RsnSelectedGroupCipher = u4GroupCipher; + prBss->u4RsnSelectedAKMSuite = u4AkmSuite; + + return TRUE; + +} /* rsnPerformPolicySelection */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to generate WPA IE for beacon frame. +* +* \param[in] pucIeStartAddr Pointer to put the generated WPA IE. +* +* \return The append WPA-None IE length +* \note +* Called by: JOIN module, compose beacon IE +*/ +/*----------------------------------------------------------------------------*/ +VOID +rsnGenerateWpaNoneIE ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ) +{ + UINT_32 i; + P_WPA_INFO_ELEM_T prWpaIE; + UINT_32 u4Suite; + UINT_16 u2SuiteCount; + PUINT_8 cp, cp2; + UINT_8 ucExpendedLen = 0; + PUINT_8 pucBuffer; + ENUM_NETWORK_TYPE_INDEX_T eNetworkId; + + DEBUGFUNC("rsnGenerateWpaNoneIE"); + + ASSERT(prMsduInfo); + + if (prAdapter->rWifiVar.rConnSettings.eAuthMode != AUTH_MODE_WPA_NONE) { + return; + } + + eNetworkId = (ENUM_NETWORK_TYPE_INDEX_T)prMsduInfo->ucNetworkType; + + if (eNetworkId != NETWORK_TYPE_AIS_INDEX) + return; + + pucBuffer = (PUINT_8)((UINT_32)prMsduInfo->prPacket + + (UINT_32)prMsduInfo->u2FrameLength); + + ASSERT(pucBuffer); + + prWpaIE = (P_WPA_INFO_ELEM_T)(pucBuffer); + + /* Start to construct a WPA IE. */ + /* Fill the Element ID field. */ + prWpaIE->ucElemId = ELEM_ID_WPA; + + /* Fill the OUI and OUI Type fields. */ + prWpaIE->aucOui[0] = 0x00; + prWpaIE->aucOui[1] = 0x50; + prWpaIE->aucOui[2] = 0xF2; + prWpaIE->ucOuiType = VENDOR_OUI_TYPE_WPA; + + /* Fill the Version field. */ + WLAN_SET_FIELD_16(&prWpaIE->u2Version, 1); /* version 1 */ + ucExpendedLen = 6; + + /* Fill the Pairwise Key Cipher Suite List field. */ + u2SuiteCount = 0; + cp = (PUINT_8)&prWpaIE->aucPairwiseKeyCipherSuite1[0]; + + if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_CCMP, &i)) { + u4Suite = WPA_CIPHER_SUITE_CCMP; + } + else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_TKIP, &i)) { + u4Suite = WPA_CIPHER_SUITE_TKIP; + } + else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_WEP104, &i)) { + u4Suite = WPA_CIPHER_SUITE_WEP104; + } + else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_WEP40, &i)) { + u4Suite = WPA_CIPHER_SUITE_WEP40; + } + else { + u4Suite = WPA_CIPHER_SUITE_TKIP; + } + + WLAN_SET_FIELD_32(cp, u4Suite); + u2SuiteCount++; + ucExpendedLen += 4; + cp += 4; + + /* Fill the Group Key Cipher Suite field as the same in pair-wise key. */ + WLAN_SET_FIELD_32(&prWpaIE->u4GroupKeyCipherSuite, u4Suite); + ucExpendedLen += 4; + + /* Fill the Pairwise Key Cipher Suite Count field. */ + WLAN_SET_FIELD_16(&prWpaIE->u2PairwiseKeyCipherSuiteCount, u2SuiteCount); + ucExpendedLen += 2; + + cp2 = cp; + + /* Fill the Authentication and Key Management Suite List field. */ + u2SuiteCount = 0; + cp += 2; + + if (rsnSearchAKMSuite(prAdapter, WPA_AKM_SUITE_802_1X, &i)) { + u4Suite = WPA_AKM_SUITE_802_1X; + } + else if (rsnSearchAKMSuite(prAdapter, WPA_AKM_SUITE_PSK, &i)) { + u4Suite = WPA_AKM_SUITE_PSK; + } + else { + u4Suite = WPA_AKM_SUITE_NONE; + } + + /* This shall be the only avaiable value for current implementation */ + ASSERT(u4Suite == WPA_AKM_SUITE_NONE); + + WLAN_SET_FIELD_32(cp, u4Suite); + u2SuiteCount++; + ucExpendedLen += 4; + cp += 4; + + /* Fill the Authentication and Key Management Suite Count field. */ + WLAN_SET_FIELD_16(cp2, u2SuiteCount); + ucExpendedLen += 2; + + /* Fill the Length field. */ + prWpaIE->ucLength = (UINT_8)ucExpendedLen; + + /* Increment the total IE length for the Element ID and Length fields. */ + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + +} /* rsnGenerateWpaNoneIE */ + + +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to generate WPA IE for +* associate request frame. +* +* \param[in] prCurrentBss The Selected BSS description +* +* \retval The append WPA IE length +* +* \note +* Called by: AIS module, Associate request +*/ +/*----------------------------------------------------------------------------*/ +VOID +rsnGenerateWPAIE ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ) +{ + PUCHAR cp; + PUINT_8 pucBuffer; + ENUM_NETWORK_TYPE_INDEX_T eNetworkId; + + DEBUGFUNC("rsnGenerateWPAIE"); + + ASSERT(prMsduInfo); + + pucBuffer = (PUINT_8)((UINT_32)prMsduInfo->prPacket + + (UINT_32)prMsduInfo->u2FrameLength); + + ASSERT(pucBuffer); + + eNetworkId = (ENUM_NETWORK_TYPE_INDEX_T)prMsduInfo->ucNetworkType; + + //if (eNetworkId != NETWORK_TYPE_AIS_INDEX) + // return; + + if ((1 /* prCurrentBss->fgIEWPA */ && +#if CFG_ENABLE_WIFI_DIRECT + ((prAdapter->fgIsP2PRegistered) && + (eNetworkId == NETWORK_TYPE_P2P_INDEX) && + (prAdapter->rP2pFuncLkr.prKalP2pGetTkipCipher(prAdapter->prGlueInfo)))) || +#endif + ((prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA) || + (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_PSK))) + { + /* Construct a WPA IE for association request frame. */ + WPA_IE(pucBuffer)->ucElemId = ELEM_ID_WPA; + WPA_IE(pucBuffer)->ucLength = ELEM_ID_WPA_LEN_FIXED; + WPA_IE(pucBuffer)->aucOui[0] = 0x00; + WPA_IE(pucBuffer)->aucOui[1] = 0x50; + WPA_IE(pucBuffer)->aucOui[2] = 0xF2; + WPA_IE(pucBuffer)->ucOuiType = VENDOR_OUI_TYPE_WPA; + WLAN_SET_FIELD_16(&WPA_IE(pucBuffer)->u2Version, 1); + +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered && eNetworkId == NETWORK_TYPE_P2P_INDEX) + { + WLAN_SET_FIELD_32(&WPA_IE(pucBuffer)->u4GroupKeyCipherSuite, WPA_CIPHER_SUITE_TKIP); + } + else +#endif + WLAN_SET_FIELD_32(&WPA_IE(pucBuffer)->u4GroupKeyCipherSuite, + prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].u4RsnSelectedGroupCipher); + + cp = (PUCHAR) &WPA_IE(pucBuffer)->aucPairwiseKeyCipherSuite1[0]; + + WLAN_SET_FIELD_16(&WPA_IE(pucBuffer)->u2PairwiseKeyCipherSuiteCount, 1); +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered && eNetworkId == NETWORK_TYPE_P2P_INDEX) + { + WLAN_SET_FIELD_32(cp, WPA_CIPHER_SUITE_TKIP); + } + else +#endif + WLAN_SET_FIELD_32(cp, prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].u4RsnSelectedPairwiseCipher); + cp += 4; + + WLAN_SET_FIELD_16(cp, 1); + cp += 2; +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered && eNetworkId == NETWORK_TYPE_P2P_INDEX) + { + WLAN_SET_FIELD_32(cp, WPA_AKM_SUITE_PSK); + } + else +#endif + WLAN_SET_FIELD_32(cp, prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].u4RsnSelectedAKMSuite); + cp += 4; + + WPA_IE(pucBuffer)->ucLength = ELEM_ID_WPA_LEN_FIXED; + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + } + +} /* rsnGenerateWPAIE */ + + +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to generate RSN IE for +* associate request frame. +* +* \param[in] prMsduInfo The Selected BSS description +* +* \retval The append RSN IE length +* +* \note +* Called by: AIS module, P2P module, BOW module Associate request +*/ +/*----------------------------------------------------------------------------*/ +VOID +rsnGenerateRSNIE ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ) +{ + UINT_32 u4Entry; + PUCHAR cp; + //UINT_8 ucExpendedLen = 0; + PUINT_8 pucBuffer; + ENUM_NETWORK_TYPE_INDEX_T eNetworkId; + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("rsnGenerateRSNIE"); + + ASSERT(prMsduInfo); + + pucBuffer = (PUINT_8)((UINT_32)prMsduInfo->prPacket + + (UINT_32)prMsduInfo->u2FrameLength); + + ASSERT(pucBuffer); + + /* Todo:: network id */ + eNetworkId = (ENUM_NETWORK_TYPE_INDEX_T)prMsduInfo->ucNetworkType; + + if ( +#if CFG_ENABLE_WIFI_DIRECT + ((prAdapter->fgIsP2PRegistered) && + (eNetworkId == NETWORK_TYPE_P2P_INDEX) && + (prAdapter->rP2pFuncLkr.prKalP2pGetCcmpCipher(prAdapter->prGlueInfo))) || +#endif +#if CFG_ENABLE_BT_OVER_WIFI + (eNetworkId == NETWORK_TYPE_BOW_INDEX) || +#endif + (eNetworkId == NETWORK_TYPE_AIS_INDEX /* prCurrentBss->fgIERSN */ && + ((prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2) || + (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2_PSK)))) + { + /* Construct a RSN IE for association request frame. */ + RSN_IE(pucBuffer)->ucElemId = ELEM_ID_RSN; + RSN_IE(pucBuffer)->ucLength = ELEM_ID_RSN_LEN_FIXED; + WLAN_SET_FIELD_16(&RSN_IE(pucBuffer)->u2Version, 1); // Version + WLAN_SET_FIELD_32(&RSN_IE(pucBuffer)->u4GroupKeyCipherSuite, + prAdapter->rWifiVar.arBssInfo[eNetworkId].u4RsnSelectedGroupCipher); // Group key suite + cp = (PUCHAR) &RSN_IE(pucBuffer)->aucPairwiseKeyCipherSuite1[0]; + WLAN_SET_FIELD_16(&RSN_IE(pucBuffer)->u2PairwiseKeyCipherSuiteCount, 1); + WLAN_SET_FIELD_32(cp, prAdapter->rWifiVar.arBssInfo[eNetworkId].u4RsnSelectedPairwiseCipher); + cp += 4; + WLAN_SET_FIELD_16(cp, 1); // AKM suite count + cp += 2; + WLAN_SET_FIELD_32(cp, prAdapter->rWifiVar.arBssInfo[eNetworkId].u4RsnSelectedAKMSuite); // AKM suite + cp += 4; + WLAN_SET_FIELD_16(cp, prAdapter->rWifiVar.arBssInfo[eNetworkId].u2RsnSelectedCapInfo); // Capabilities +#if CFG_SUPPORT_802_11W + if (eNetworkId == NETWORK_TYPE_AIS_INDEX && prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection) { + if (kalGetMfpSetting(prAdapter->prGlueInfo) == RSN_AUTH_MFP_REQUIRED) { + WLAN_SET_FIELD_16(cp, ELEM_WPA_CAP_MFPC | ELEM_WPA_CAP_MFPR); // Capabilities + } + else if (kalGetMfpSetting(prAdapter->prGlueInfo) == RSN_AUTH_MFP_OPTIONAL) { + WLAN_SET_FIELD_16(cp, ELEM_WPA_CAP_MFPC); // Capabilities + } + } +#endif + cp += 2; + + if (eNetworkId == NETWORK_TYPE_AIS_INDEX) + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if (eNetworkId == NETWORK_TYPE_AIS_INDEX && + rsnSearchPmkidEntry(prAdapter, prStaRec->aucMacAddr, &u4Entry)) { + //DBGLOG(RSN, TRACE, ("Add Pmk at assoc req\n")); + //DBGLOG(RSN, TRACE, ("addr " MACSTR" PMKID "MACSTR"\n", + // MAC2STR(prAdapter->rWifiVar.rAisSpecificBssInfo.arPmkidCache[u4Entry].rBssidInfo.arBSSID), MAC2STR(prAdapter->rWifiVar.rAisSpecificBssInfo.arPmkidCache[u4Entry].rBssidInfo.arPMKID))); + if (prAdapter->rWifiVar.rAisSpecificBssInfo.arPmkidCache[u4Entry].fgPmkidExist) { + RSN_IE(pucBuffer)->ucLength = 38; + WLAN_SET_FIELD_16(cp, 1); // PMKID count + cp += 2; + DBGLOG(RSN, TRACE, ("BSSID "MACSTR" ind=%d\n", MAC2STR(prStaRec->aucMacAddr), u4Entry)); + DBGLOG(RSN, TRACE, ("use PMKID "MACSTR"\n", MAC2STR(prAdapter->rWifiVar.rAisSpecificBssInfo.arPmkidCache[u4Entry].rBssidInfo.arPMKID))); + kalMemCopy(cp, (PVOID)prAdapter->rWifiVar.rAisSpecificBssInfo.arPmkidCache[u4Entry].rBssidInfo.arPMKID, + sizeof(PARAM_PMKID_VALUE)); + //ucExpendedLen = 40; + } + else { + WLAN_SET_FIELD_16(cp, 0); // PMKID count + //ucExpendedLen = ELEM_ID_RSN_LEN_FIXED + 2; +#if CFG_SUPPORT_802_11W + cp += 2; + RSN_IE(pucBuffer)->ucLength += 2; +#endif + } + } + else { + WLAN_SET_FIELD_16(cp, 0); // PMKID count + //ucExpendedLen = ELEM_ID_RSN_LEN_FIXED + 2; +#if CFG_SUPPORT_802_11W + cp += 2; + RSN_IE(pucBuffer)->ucLength += 2; +#endif + } + +#if CFG_SUPPORT_802_11W + if ((eNetworkId == NETWORK_TYPE_AIS_INDEX) && (kalGetMfpSetting(prAdapter->prGlueInfo) != RSN_AUTH_MFP_DISABLED) /* (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) */ ) { + WLAN_SET_FIELD_32(cp, RSN_CIPHER_SUITE_AES_128_CMAC); + cp += 4; + RSN_IE(pucBuffer)->ucLength += 4; + } +#endif + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + } + +} /* rsnGenerateRSNIE */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Parse the given IE buffer and check if it is WFA IE and return Type and +* SubType for further process. +* +* \param[in] pucBuf Pointer to the buffer of WFA Information Element. +* \param[out] pucOuiType Pointer to the storage of OUI Type. +* \param[out] pu2SubTypeVersion Pointer to the storage of OUI SubType and Version. + +* \retval TRUE Parse IE ok +* \retval FALSE Parse IE fail +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +rsnParseCheckForWFAInfoElem ( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucBuf, + OUT PUINT_8 pucOuiType, + OUT PUINT_16 pu2SubTypeVersion + ) +{ + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; + P_IE_WFA_T prWfaIE; + + ASSERT(pucBuf); + ASSERT(pucOuiType); + ASSERT(pu2SubTypeVersion); + prWfaIE = (P_IE_WFA_T)pucBuf; + + do { + if (IE_LEN(pucBuf) <= ELEM_MIN_LEN_WFA_OUI_TYPE_SUBTYPE) { + break; + } + else if (prWfaIE->aucOui[0] != aucWfaOui[0] || + prWfaIE->aucOui[1] != aucWfaOui[1] || + prWfaIE->aucOui[2] != aucWfaOui[2]) { + break; + } + + *pucOuiType = prWfaIE->ucOuiType; + WLAN_GET_FIELD_16(&prWfaIE->aucOuiSubTypeVersion[0], pu2SubTypeVersion); + + return TRUE; + } + while (FALSE); + + return FALSE; + +} /* end of rsnParseCheckForWFAInfoElem() */ + +#if CFG_SUPPORT_AAA +/*----------------------------------------------------------------------------*/ +/*! +* \brief Parse the given IE buffer and check if it is RSN IE with CCMP PSK +* +* \param[in] prAdapter Pointer to Adapter +* \param[in] prSwRfb Pointer to the rx buffer +* \param[in] pIE Pointer rthe buffer of Information Element. +* \param[out] prStatusCode Pointer to the return status code. + +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +void +rsnParserCheckForRSNCCMPPSK( + P_ADAPTER_T prAdapter, + P_RSN_INFO_ELEM_T prIe, + PUINT_16 pu2StatusCode + ) +{ + + RSN_INFO_T rRsnIe; + + ASSERT(prAdapter); + ASSERT(prIe); + ASSERT(pu2StatusCode); + + *pu2StatusCode = STATUS_CODE_INVALID_INFO_ELEMENT; + + if (rsnParseRsnIE(prAdapter, prIe, &rRsnIe)) { + if ((rRsnIe.u4PairwiseKeyCipherSuiteCount != 1) || (rRsnIe.au4PairwiseKeyCipherSuite[0] != RSN_CIPHER_SUITE_CCMP)) { + *pu2StatusCode = STATUS_CODE_INVALID_PAIRWISE_CIPHER; + return; + } + if ((rRsnIe.u4GroupKeyCipherSuite != RSN_CIPHER_SUITE_CCMP)) { + *pu2StatusCode = STATUS_CODE_INVALID_GROUP_CIPHER; + return; + } + if ((rRsnIe.u4AuthKeyMgtSuiteCount != 1) || (rRsnIe.au4AuthKeyMgtSuite[0] != RSN_AKM_SUITE_PSK)) { + *pu2StatusCode = STATUS_CODE_INVALID_AKMP; + return; + } + + DBGLOG(RSN, TRACE, ("RSN with CCMP-PSK\n" )); + *pu2StatusCode = WLAN_STATUS_SUCCESS; + } + +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to generate an authentication event to NDIS. +* +* \param[in] u4Flags Authentication event: \n +* PARAM_AUTH_REQUEST_REAUTH 0x01 \n +* PARAM_AUTH_REQUEST_KEYUPDATE 0x02 \n +* PARAM_AUTH_REQUEST_PAIRWISE_ERROR 0x06 \n +* PARAM_AUTH_REQUEST_GROUP_ERROR 0x0E \n +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +rsnGenMicErrorEvent ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgFlags + ) +{ + P_PARAM_AUTH_EVENT_T prAuthEvent; + + DEBUGFUNC("rsnGenMicErrorEvent"); + + prAuthEvent = (P_PARAM_AUTH_EVENT_T)prAdapter->aucIndicationEventBuffer; + + /* Status type: Authentication Event */ + prAuthEvent->rStatus.eStatusType = ENUM_STATUS_TYPE_AUTHENTICATION; + + /* Authentication request */ + prAuthEvent->arRequest[0].u4Length = sizeof(PARAM_AUTH_REQUEST_T); + kalMemCopy((PVOID)prAuthEvent->arRequest[0].arBssid, (PVOID)prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].aucBSSID, MAC_ADDR_LEN); + + if (fgFlags == TRUE) + prAuthEvent->arRequest[0].u4Flags = PARAM_AUTH_REQUEST_GROUP_ERROR; + else + prAuthEvent->arRequest[0].u4Flags = PARAM_AUTH_REQUEST_PAIRWISE_ERROR; + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, + (PVOID)prAuthEvent, + sizeof(PARAM_STATUS_INDICATION_T) + sizeof(PARAM_AUTH_REQUEST_T)); + +} /* rsnGenMicErrorEvent */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to handle TKIP MIC failures. +* +* \param[in] adapter_p Pointer to the adapter object data area. +* \param[in] prSta Pointer to the STA which occur MIC Error +* \param[in] fgErrorKeyType type of error key +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rsnTkipHandleMICFailure ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta, + IN BOOLEAN fgErrorKeyType + ) +{ + UINT_32 u4RsnaCurrentMICFailTime; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + + DEBUGFUNC("rsnTkipHandleMICFailure"); + + ASSERT(prAdapter); + + ASSERT(prSta); + + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + /* Record the MIC error occur time. */ + GET_CURRENT_SYSTIME(&u4RsnaCurrentMICFailTime); + + /* Generate authentication request event. */ + DBGLOG(RSN, INFO, ("Generate TKIP MIC error event (type: 0%d)\n", + fgErrorKeyType)); + + /* If less than 60 seconds have passed since a previous TKIP MIC failure, + disassociate from the AP and wait for 60 seconds before (re)associating + with the same AP. */ + if (prAisSpecBssInfo->u4RsnaLastMICFailTime != 0 && + !CHECK_FOR_TIMEOUT(u4RsnaCurrentMICFailTime, + prAisSpecBssInfo->u4RsnaLastMICFailTime, + SEC_TO_SYSTIME(TKIP_COUNTERMEASURE_SEC))) { + /* If less than 60 seconds expired since last MIC error, we have to + block traffic. */ + + DBGLOG(RSN, INFO, ("Start blocking traffic!\n")); + rsnGenMicErrorEvent( prAdapter,/* prSta,*/ fgErrorKeyType); + + secFsmEventStartCounterMeasure(prAdapter, prSta); + } + else { + rsnGenMicErrorEvent( prAdapter,/* prSta,*/ fgErrorKeyType); + DBGLOG(RSN, INFO, ("First TKIP MIC error!\n")); + } + + COPY_SYSTIME(prAisSpecBssInfo->u4RsnaLastMICFailTime, u4RsnaCurrentMICFailTime); +} /* rsnTkipHandleMICFailure */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called to select a list of BSSID from +* the scan results for PMKID candidate list. +* +* \param[in] prBssDesc the BSS Desc at scan result list +* \param[out] pu4CandidateCount Pointer to the number of selected candidates. +* It is set to zero if no BSSID matches our requirement. +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rsnSelectPmkidCandidateList ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc + ) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + P_AIS_BSS_INFO_T prAisBssInfo; + + DEBUGFUNC("rsnSelectPmkidCandidateList"); + + ASSERT(prBssDesc); + + prConnSettings = &prAdapter->rWifiVar.rConnSettings; + prAisBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; + + /* Search a BSS with the same SSID from the given BSS description set. */ + //DBGLOG(RSN, TRACE, ("Check scan result ["MACSTR"]\n", + // MAC2STR(prBssDesc->aucBSSID))); + + if (UNEQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, + prConnSettings->aucSSID, prConnSettings->ucSSIDLen)) { + DBGLOG(RSN, TRACE, ("-- SSID not matched\n")); + return; + } + +#if 0 + if ((prBssDesc->u2BSSBasicRateSet & + ~(rPhyAttributes[prAisBssInfo->ePhyType].u2SupportedRateSet)) || + prBssDesc->fgIsUnknownBssBasicRate) { + DBGLOG(RSN, TRACE, ("-- Rate set not matched\n")); + return; + } + + if (/* prBssDesc->u4RsnSelectedPairwiseCipher != prAisBssInfo->u4RsnSelectedPairwiseCipher ||*/ + prBssDesc->u4RsnSelectedGroupCipher != prAisBssInfo->u4RsnSelectedGroupCipher /*|| + prBssDesc->u4RsnSelectedAKMSuite != prAisBssInfo->u4RsnSelectedAKMSuite */) { + DBGLOG(RSN, TRACE, ("-- Encrypt status not matched for PMKID \n")); + return; + } +#endif + + rsnUpdatePmkidCandidateList(prAdapter, prBssDesc); + +} /* rsnSelectPmkidCandidateList */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called to select a list of BSSID from +* the scan results for PMKID candidate list. +* +* \param[in] prBssDesc the BSS DESC at scan result list +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rsnUpdatePmkidCandidateList ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc + ) +{ + UINT_32 i; + P_CONNECTION_SETTINGS_T prConnSettings; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + DEBUGFUNC("rsnUpdatePmkidCandidateList"); + + ASSERT(prBssDesc); + + prConnSettings = &prAdapter->rWifiVar.rConnSettings; + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + if (UNEQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, + prConnSettings->aucSSID, prConnSettings->ucSSIDLen)) { + DBGLOG(RSN, TRACE, ("-- SSID not matched\n")); + return; + } + + for (i = 0; i < CFG_MAX_PMKID_CACHE; i++) { + if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAisSpecBssInfo->arPmkidCandicate[i].aucBssid)) + return; + } + + /* If the number of selected BSSID exceed MAX_NUM_PMKID_CACHE(16), + then we only store MAX_NUM_PMKID_CACHE(16) in PMKID cache */ + if ((prAisSpecBssInfo->u4PmkidCandicateCount + 1) > CFG_MAX_PMKID_CACHE) { + prAisSpecBssInfo->u4PmkidCandicateCount --; + } + + i = prAisSpecBssInfo->u4PmkidCandicateCount; + + COPY_MAC_ADDR((PVOID)prAisSpecBssInfo->arPmkidCandicate[i].aucBssid, + (PVOID)prBssDesc->aucBSSID); + + if (prBssDesc->u2RsnCap & MASK_RSNIE_CAP_PREAUTH) { + prAisSpecBssInfo->arPmkidCandicate[i].u4PreAuthFlags = 1; + DBGLOG(RSN, TRACE, ("Add " MACSTR " with pre-auth to candidate list\n", + MAC2STR(prAisSpecBssInfo->arPmkidCandicate[i].aucBssid))); + } + else { + prAisSpecBssInfo->arPmkidCandicate[i].u4PreAuthFlags = 0; + DBGLOG(RSN, TRACE, ("Add " MACSTR " without pre-auth to candidate list\n", + MAC2STR(prAisSpecBssInfo->arPmkidCandicate[i].aucBssid))); + } + + prAisSpecBssInfo->u4PmkidCandicateCount ++; + +} /* rsnUpdatePmkidCandidateList */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to search the desired entry in +* PMKID cache according to the BSSID +* +* \param[in] pucBssid Pointer to the BSSID +* \param[out] pu4EntryIndex Pointer to place the found entry index +* +* \retval TRUE, if found one entry for specified BSSID +* \retval FALSE, if not found +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +rsnSearchPmkidEntry ( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucBssid, + OUT PUINT_32 pu4EntryIndex + ) +{ + UINT_32 i; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + DEBUGFUNC("rsnSearchPmkidEntry"); + + ASSERT(pucBssid); + ASSERT(pu4EntryIndex); + + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + if (prAisSpecBssInfo->u4PmkidCacheCount > CFG_MAX_PMKID_CACHE) { + return FALSE; + } + + ASSERT(prAisSpecBssInfo->u4PmkidCacheCount <= CFG_MAX_PMKID_CACHE); + + /* Search for desired BSSID */ + for (i = 0; i < prAisSpecBssInfo->u4PmkidCacheCount; i++) { + if (!kalMemCmp(prAisSpecBssInfo->arPmkidCache[i].rBssidInfo.arBSSID, pucBssid, + MAC_ADDR_LEN)) { + break; + } + } + + /* If desired BSSID is found, then set the PMKID */ + if (i < prAisSpecBssInfo->u4PmkidCacheCount) { + *pu4EntryIndex = i; + + return TRUE; + } + + return FALSE; +} /* rsnSearchPmkidEntry */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to check if there is difference +* between PMKID candicate list and PMKID cache. If there +* is new candicate that no cache entry is available, then +* add a new entry for the new candicate in the PMKID cache +* and set the PMKID indication flag to TRUE. +* +* \retval TRUE, if new member in the PMKID candicate list +* \retval FALSe, if no new member in the PMKID candicate list +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +rsnCheckPmkidCandicate ( + IN P_ADAPTER_T prAdapter + ) +{ + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + UINT_32 i; // Index for PMKID candicate + UINT_32 j; // Indix for PMKID cache + BOOLEAN status = FALSE; + + DEBUGFUNC("rsnCheckPmkidCandicate"); + + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + /* Check for each candicate */ + for (i = 0; i < prAisSpecBssInfo->u4PmkidCandicateCount; i++) { + for (j = 0; j < prAisSpecBssInfo->u4PmkidCacheCount; j++) { + if (!kalMemCmp(prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arBSSID, + prAisSpecBssInfo->arPmkidCandicate[i].aucBssid, + MAC_ADDR_LEN)) { + //DBGLOG(RSN, TRACE, (MACSTR" at PMKID cache!!\n", MAC2STR(prAisSpecBssInfo->arPmkidCandicate[i].aucBssid))); + break; + } + } + + /* No entry found in PMKID cache for the candicate, add new one */ + if (j == prAisSpecBssInfo->u4PmkidCacheCount && prAisSpecBssInfo->u4PmkidCacheCount < CFG_MAX_PMKID_CACHE) { + DBGLOG(RSN, TRACE, ("Add "MACSTR" to PMKID cache!!\n", MAC2STR(prAisSpecBssInfo->arPmkidCandicate[i].aucBssid))); + kalMemCopy((PVOID)prAisSpecBssInfo->arPmkidCache[prAisSpecBssInfo->u4PmkidCacheCount].rBssidInfo.arBSSID, + (PVOID)prAisSpecBssInfo->arPmkidCandicate[i].aucBssid, + MAC_ADDR_LEN); + prAisSpecBssInfo->arPmkidCache[prAisSpecBssInfo->u4PmkidCacheCount].fgPmkidExist = FALSE; + prAisSpecBssInfo->u4PmkidCacheCount++; + + status = TRUE; + } + } + + return status; +} /* rsnCheckPmkidCandicate */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called to wait a duration to indicate the pre-auth AP candicate +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +rsnIndicatePmkidCand ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Parm + ) +{ + DBGLOG(RSN, EVENT, ("Security - Time to indicate the PMKID cand.\n")); + + /* If the authentication mode is WPA2 and indication PMKID flag + is available, then we indicate the PMKID candidate list to NDIS and + clear the flag, indicatePMKID */ + + if (prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].eConnectionState == PARAM_MEDIA_STATE_CONNECTED && + prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2) { + rsnGeneratePmkidIndication(prAdapter); + } + + return; +} /* end of rsnIndicatePmkidCand() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to check the BSS Desc at scan result +* with pre-auth cap at wpa2 mode. If there +* is candicate that no cache entry is available, then +* add a new entry for the new candicate in the PMKID cache +* and set the PMKID indication flag to TRUE. +* +* \param[in] prBss The BSS Desc at scan result +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rsnCheckPmkidCache ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBss + ) +{ + P_AIS_BSS_INFO_T prAisBssInfo; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + + DEBUGFUNC("rsnCheckPmkidCandicate"); + + ASSERT(prBss); + + prConnSettings = &prAdapter->rWifiVar.rConnSettings; + prAisBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + if ((prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) && + (prConnSettings->eAuthMode == AUTH_MODE_WPA2)) { + rsnSelectPmkidCandidateList(prAdapter, prBss); + + /* Set indication flag of PMKID to TRUE, and then connHandleNetworkConnection() + will indicate this later */ + if (rsnCheckPmkidCandicate(prAdapter)) { + DBGLOG(RSN, TRACE, ("Prepare a timer to indicate candidate PMKID Candidate\n")); + cnmTimerStopTimer(prAdapter, &prAisSpecBssInfo->rPreauthenticationTimer); + cnmTimerStartTimer(prAdapter, &prAisSpecBssInfo->rPreauthenticationTimer, + SEC_TO_MSEC(WAIT_TIME_IND_PMKID_CANDICATE_SEC)); + } + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to generate an PMKID candidate list +* indication to NDIS. +* +* \param[in] prAdapter Pointer to the adapter object data area. +* \param[in] u4Flags PMKID candidate list event: +* PARAM_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01 +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rsnGeneratePmkidIndication ( + IN P_ADAPTER_T prAdapter + ) +{ + P_PARAM_STATUS_INDICATION_T prStatusEvent; + P_PARAM_PMKID_CANDIDATE_LIST_T prPmkidEvent; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecificBssInfo; + UINT_8 i, j = 0, count = 0; + UINT_32 u4LenOfUsedBuffer; + + DEBUGFUNC("rsnGeneratePmkidIndication"); + + ASSERT(prAdapter); + + prStatusEvent = + (P_PARAM_STATUS_INDICATION_T)prAdapter->aucIndicationEventBuffer; + + /* Status type: PMKID Candidatelist Event */ + prStatusEvent->eStatusType = ENUM_STATUS_TYPE_CANDIDATE_LIST; + ASSERT(prStatusEvent); + + prPmkidEvent = (P_PARAM_PMKID_CANDIDATE_LIST_T)(&prStatusEvent->eStatusType + 1); + ASSERT(prPmkidEvent); + + prAisSpecificBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + ASSERT(prAisSpecificBssInfo); + + for (i = 0; i < prAisSpecificBssInfo->u4PmkidCandicateCount; i++) { + for (j = 0; j < prAisSpecificBssInfo->u4PmkidCacheCount; j++) { + if (EQUAL_MAC_ADDR( prAisSpecificBssInfo->arPmkidCache[j].rBssidInfo.arBSSID, + prAisSpecificBssInfo->arPmkidCandicate[i].aucBssid) && + (prAisSpecificBssInfo->arPmkidCache[j].fgPmkidExist == TRUE)){ + break; + } + } + if (count >= CFG_MAX_PMKID_CACHE) { + break; + } + + if (j == prAisSpecificBssInfo->u4PmkidCacheCount) { + kalMemCopy((PVOID)prPmkidEvent->arCandidateList[count].arBSSID, + (PVOID)prAisSpecificBssInfo->arPmkidCandicate[i].aucBssid, + PARAM_MAC_ADDR_LEN); + prPmkidEvent->arCandidateList[count].u4Flags = + prAisSpecificBssInfo->arPmkidCandicate[i].u4PreAuthFlags; + DBGLOG(RSN, TRACE, (MACSTR" %d\n", MAC2STR(prPmkidEvent->arCandidateList[count].arBSSID), + prPmkidEvent->arCandidateList[count].u4Flags)); + count++; + } + } + + /* PMKID Candidate List */ + prPmkidEvent->u4Version = 1; + prPmkidEvent->u4NumCandidates = count; + DBGLOG(RSN, TRACE, ("rsnGeneratePmkidIndication #%d\n", prPmkidEvent->u4NumCandidates)); + u4LenOfUsedBuffer = sizeof(ENUM_STATUS_TYPE_T) + (2 * sizeof(UINT_32)) + + (count * sizeof(PARAM_PMKID_CANDIDATE_T)); + //dumpMemory8((PUINT_8)prAdapter->aucIndicationEventBuffer, u4LenOfUsedBuffer); + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, + (PVOID) prAdapter->aucIndicationEventBuffer, + u4LenOfUsedBuffer); + +} /* rsnGeneratePmkidIndication */ +#endif + +#if CFG_SUPPORT_WPS2 +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to generate WSC IE for +* associate request frame. +* +* \param[in] prCurrentBss The Selected BSS description +* +* \retval The append WSC IE length +* +* \note +* Called by: AIS module, Associate request +*/ +/*----------------------------------------------------------------------------*/ +VOID +rsnGenerateWSCIE ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ) +{ + PUINT_8 pucBuffer; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + if (prMsduInfo->ucNetworkType != NETWORK_TYPE_AIS_INDEX) + return; + + pucBuffer = (PUINT_8)((UINT_32)prMsduInfo->prPacket + + (UINT_32)prMsduInfo->u2FrameLength); + + /* ASSOC INFO IE ID: 221 :0xDD */ + if (prAdapter->prGlueInfo->u2WSCAssocInfoIELen) { + kalMemCopy(pucBuffer, &prAdapter->prGlueInfo->aucWSCAssocInfoIE, prAdapter->prGlueInfo->u2WSCAssocInfoIELen); + prMsduInfo->u2FrameLength += prAdapter->prGlueInfo->u2WSCAssocInfoIELen; + } + +} +#endif + + +#if CFG_SUPPORT_802_11W + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to check if the Bip Key installed or not +* +* \param[in] +* prAdapter +* +* \return +* TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 +rsnCheckBipKeyInstalled ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ) +{ + if (prStaRec && prStaRec->ucNetTypeIndex == (UINT_8)NETWORK_TYPE_AIS_INDEX) + return prAdapter->rWifiVar.rAisSpecificBssInfo.fgBipKeyInstalled; + else + return FALSE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to check the Sa query timeout. +* +* +* \note +* Called by: AIS module, Handle by Sa Quert timeout +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 +rsnCheckSaQueryTimeout ( + IN P_ADAPTER_T prAdapter + ) +{ + P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; + UINT_32 now; + + prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + ASSERT(prBssSpecInfo); + + GET_CURRENT_SYSTIME(&now); + + if (CHECK_FOR_TIMEOUT(now, + prBssSpecInfo->u4SaQueryStart, + TU_TO_MSEC(1000))) { + LOG_FUNC("association SA Query timed out\n"); + + prBssSpecInfo->ucSaQueryTimedOut = 1; + kalMemFree(prBssSpecInfo->pucSaQueryTransId, VIR_MEM_TYPE, prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN); + prBssSpecInfo->pucSaQueryTransId = NULL; + prBssSpecInfo->u4SaQueryCount = 0; + cnmTimerStopTimer(prAdapter, &prBssSpecInfo->rSaQueryTimer); + /* Re-connect */ + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_DISCONNECT, + NULL, + 0); + + return 1; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to start the 802.11w sa query timer. +* +* +* \note +* Called by: AIS module, Handle Rx mgmt request +*/ +/*----------------------------------------------------------------------------*/ +void rsnStartSaQueryTimer ( + IN P_ADAPTER_T prAdapter + ) +{ + P_BSS_INFO_T prBssInfo; + P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; + P_MSDU_INFO_T prMsduInfo; + P_ACTION_SA_QUERY_FRAME prTxFrame; + UINT_16 u2PayloadLen; + PUINT_8 pucTmp = NULL; + UINT_8 ucTransId[ACTION_SA_QUERY_TR_ID_LEN]; + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; + ASSERT(prBssInfo); + + prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + ASSERT(prBssSpecInfo); + + LOG_FUNC("MFP: Start Sa Query\n"); + + if (prBssSpecInfo->u4SaQueryCount > 0 && + rsnCheckSaQueryTimeout(prAdapter)) { + LOG_FUNC("MFP: u4SaQueryCount count =%d\n", prBssSpecInfo->u4SaQueryCount); + return; + } + + prMsduInfo = (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, + MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN); + + if (!prMsduInfo) + return; + + prTxFrame = (P_ACTION_SA_QUERY_FRAME) + ((UINT_32)(prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); + + prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; + prTxFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; + + COPY_MAC_ADDR(prTxFrame->aucDestAddr, prBssInfo->aucBSSID); + COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); + COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); + + prTxFrame->ucCategory = CATEGORY_SA_QUERT_ACTION; + prTxFrame->ucAction = ACTION_SA_QUERY_REQUEST; + + if (prBssSpecInfo->u4SaQueryCount == 0) { + GET_CURRENT_SYSTIME(&prBssSpecInfo->u4SaQueryStart); + } + + if (prBssSpecInfo->u4SaQueryCount) { + pucTmp = kalMemAlloc(prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN, VIR_MEM_TYPE); + if (!pucTmp) { + DBGLOG(RSN, INFO, ("MFP: Fail to alloc tmp buffer for backup sa query id\n")); + return; + } + kalMemCopy(pucTmp, prBssSpecInfo->pucSaQueryTransId, prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN); + } + + kalMemFree(prBssSpecInfo->pucSaQueryTransId, VIR_MEM_TYPE, prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN); + + ucTransId[0] = (UINT_8)(kalRandomNumber() & 0xFF); + ucTransId[1] = (UINT_8)(kalRandomNumber() & 0xFF); + + kalMemCopy(prTxFrame->ucTransId, ucTransId, ACTION_SA_QUERY_TR_ID_LEN); + + prBssSpecInfo->u4SaQueryCount++; + + prBssSpecInfo->pucSaQueryTransId = kalMemAlloc(prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN, VIR_MEM_TYPE); + if (!prBssSpecInfo->pucSaQueryTransId) { + DBGLOG(RSN, INFO, ("MFP: Fail to alloc buffer for sa query id list\n")); + return; + } + + if (pucTmp) { + kalMemCopy(prBssSpecInfo->pucSaQueryTransId, pucTmp, (prBssSpecInfo->u4SaQueryCount - 1) * ACTION_SA_QUERY_TR_ID_LEN); + kalMemCopy(&prBssSpecInfo->pucSaQueryTransId[(prBssSpecInfo->u4SaQueryCount - 1) * ACTION_SA_QUERY_TR_ID_LEN], + ucTransId, ACTION_SA_QUERY_TR_ID_LEN); + kalMemFree(pucTmp, VIR_MEM_TYPE, (prBssSpecInfo->u4SaQueryCount - 1) * ACTION_SA_QUERY_TR_ID_LEN); + } + else { + kalMemCopy(prBssSpecInfo->pucSaQueryTransId, ucTransId, ACTION_SA_QUERY_TR_ID_LEN); + } + + u2PayloadLen = 2 + ACTION_SA_QUERY_TR_ID_LEN; + + //4 Update information of MSDU_INFO_T + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; /* Management frame */ + prMsduInfo->ucStaRecIndex = prBssInfo->prStaRecOfAP->ucIndex; + prMsduInfo->ucNetworkType = prBssInfo->ucNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = NULL; + prMsduInfo->fgIsBasicRate = FALSE; + + //4 Enqueue the frame to send this action frame. + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + DBGLOG(RSN, TRACE, ("Set SA Query timer %d (%d sec)\n", prBssSpecInfo->u4SaQueryCount, prBssInfo->u2ObssScanInterval)); + + cnmTimerStartTimer(prAdapter, &prBssSpecInfo->rSaQueryTimer, + TU_TO_MSEC(201)); + +} + + +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to start the 802.11w sa query. +* +* +* \note +* Called by: AIS module, Handle Rx mgmt request +*/ +/*----------------------------------------------------------------------------*/ +void rsnStartSaQuery ( + IN P_ADAPTER_T prAdapter + ) +{ + rsnStartSaQueryTimer(prAdapter); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to stop the 802.11w sa query. +* +* +* \note +* Called by: AIS module, Handle Rx mgmt request +*/ +/*----------------------------------------------------------------------------*/ +void rsnStopSaQuery ( + IN P_ADAPTER_T prAdapter + ) +{ + P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; + + prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + ASSERT(prBssSpecInfo); + + cnmTimerStopTimer(prAdapter, &prBssSpecInfo->rSaQueryTimer); + kalMemFree(prBssSpecInfo->pucSaQueryTransId, VIR_MEM_TYPE, prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN); + prBssSpecInfo->pucSaQueryTransId = NULL; + prBssSpecInfo->u4SaQueryCount = 0; +} + +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to process the 802.11w sa query action frame. +* +* +* \note +* Called by: AIS module, Handle Rx mgmt request +*/ +/*----------------------------------------------------------------------------*/ +void +rsnSaQueryRequest ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ) +{ + P_BSS_INFO_T prBssInfo; + P_MSDU_INFO_T prMsduInfo; + P_ACTION_SA_QUERY_FRAME prRxFrame = NULL; + UINT_16 u2PayloadLen; + P_STA_RECORD_T prStaRec; + P_ACTION_SA_QUERY_FRAME prTxFrame; + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; + ASSERT(prBssInfo); + + prRxFrame = (P_ACTION_SA_QUERY_FRAME)prSwRfb->pvHeader; + if (!prRxFrame) + return; + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + DBGLOG(RSN, TRACE, ("IEEE 802.11: Received SA Query Request from " + MACSTR"\n", MAC2STR(prStaRec->aucMacAddr))); + + DBGLOG_MEM8(RSN, TRACE, prRxFrame->ucTransId, + ACTION_SA_QUERY_TR_ID_LEN); + + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_DISCONNECTED) { + DBGLOG(RSN, TRACE, ("IEEE 802.11: Ignore SA Query Request " + "from unassociated STA " MACSTR"\n", MAC2STR(prStaRec->aucMacAddr))); + return; + } + DBGLOG(RSN, TRACE, ("IEEE 802.11: Sending SA Query Response to " + MACSTR"\n", MAC2STR(prStaRec->aucMacAddr))); + + prMsduInfo = (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, + MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN); + + if (!prMsduInfo) + return; + + prTxFrame = (P_ACTION_SA_QUERY_FRAME) + ((UINT_32)(prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); + + prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; + /* SA Query always with protected */ + prTxFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; + + COPY_MAC_ADDR(prTxFrame->aucDestAddr, prBssInfo->aucBSSID); + COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); + COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); + + prTxFrame->ucCategory = CATEGORY_SA_QUERT_ACTION; + prTxFrame->ucAction = ACTION_SA_QUERY_RESPONSE; + + kalMemCopy(prTxFrame->ucTransId, + prRxFrame->ucTransId, + ACTION_SA_QUERY_TR_ID_LEN); + + u2PayloadLen = 2 + ACTION_SA_QUERY_TR_ID_LEN; + + //4 Update information of MSDU_INFO_T + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; /* Management frame */ + prMsduInfo->ucStaRecIndex = prBssInfo->prStaRecOfAP->ucIndex; + prMsduInfo->ucNetworkType = prBssInfo->ucNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = NULL; + prMsduInfo->fgIsBasicRate = FALSE; + + //4 Enqueue the frame to send this action frame. + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + +} + + +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to process the 802.11w sa query action frame. +* +* +* \note +* Called by: AIS module, Handle Rx mgmt request +*/ +/*----------------------------------------------------------------------------*/ +void +rsnSaQueryAction ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ) +{ + P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; + P_ACTION_SA_QUERY_FRAME prRxFrame; + P_STA_RECORD_T prStaRec; + UINT_32 i; + + prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + ASSERT(prBssSpecInfo); + + prRxFrame = (P_ACTION_SA_QUERY_FRAME) prSwRfb->pvHeader; + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + if (prSwRfb->u2PacketLen < ACTION_SA_QUERY_TR_ID_LEN) { + DBGLOG(RSN, TRACE, ("IEEE 802.11: Too short SA Query Action " + "frame (len=%lu)\n", (unsigned long) prSwRfb->u2PacketLen)); + return; + } + + if (prRxFrame->ucAction == ACTION_SA_QUERY_REQUEST) { + rsnSaQueryRequest(prAdapter, prSwRfb); + return; + } + + if (prRxFrame->ucAction != ACTION_SA_QUERY_RESPONSE) { + DBGLOG(RSN, TRACE, ("IEEE 802.11: Unexpected SA Query " + "Action %d\n", prRxFrame->ucAction)); + return; + } + + DBGLOG(RSN, TRACE, ("IEEE 802.11: Received SA Query Response from " + MACSTR"\n", MAC2STR(prStaRec->aucMacAddr))); + + DBGLOG_MEM8(RSN, TRACE, prRxFrame->ucTransId, + ACTION_SA_QUERY_TR_ID_LEN); + + /* MLME-SAQuery.confirm */ + + for (i = 0; i < prBssSpecInfo->u4SaQueryCount; i++) { + if (kalMemCmp(prBssSpecInfo->pucSaQueryTransId + + i * ACTION_SA_QUERY_TR_ID_LEN, + prRxFrame->ucTransId, + ACTION_SA_QUERY_TR_ID_LEN) == 0) + break; + } + + if (i >= prBssSpecInfo->u4SaQueryCount) { + DBGLOG(RSN, TRACE, ("IEEE 802.11: No matching SA Query " + "transaction identifier found\n")); + return; + } + + DBGLOG(RSN, TRACE, ("Reply to pending SA Query received\n")); + + rsnStopSaQuery(prAdapter); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to process the 802.11w mgmt frame. +* +* +* \note +* Called by: AIS module, Handle Rx mgmt request +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +rsnCheckRxMgmt ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN UINT_8 ucSubtype + ) +{ + P_HIF_RX_HEADER_T prHifRxHdr; + BOOLEAN fgUnicast = TRUE; + BOOLEAN fgRobustAction = FALSE; + + prHifRxHdr = prSwRfb->prHifRxHdr; + + if ((HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr) == NETWORK_TYPE_AIS_INDEX) && + prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection /* Use MFP */) { + + P_WLAN_ASSOC_REQ_FRAME_T prAssocReqFrame; + prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T) prSwRfb->pvHeader; + + if (prAssocReqFrame->aucDestAddr[0] & BIT(0)) + fgUnicast = FALSE; + + LOG_FUNC("QM RX MGT: rsnCheckRxMgmt = %d 0x%x %d ucSubtype=%x\n", fgUnicast, prHifRxHdr->ucReserved, (prHifRxHdr->ucReserved & CONTROL_FLAG_UC_MGMT_NO_ENC), ucSubtype); + + if (prHifRxHdr->ucReserved & CONTROL_FLAG_UC_MGMT_NO_ENC) { + /* "Dropped unprotected Robust Action frame from an MFP STA" */ + /* exclude Public Action */ + if (ucSubtype == 13 /* 0x1011: MAC_FRAME_ACTION */) + { + UINT_8 ucAction = *prSwRfb->pucRecvBuff; + if (ucAction != CATEGORY_PUBLIC_ACTION && ucAction != CATEGORY_HT_ACTION) { +#if DBG && CFG_RX_PKTS_DUMP + LOG_FUNC("QM RX MGT: UnProtected Robust Action frame = %d\n", ucAction); +#endif + fgRobustAction = TRUE; + return TRUE; + } + } + if (fgUnicast && ((ucSubtype == 10 /* 0x1010: MAC_FRAME_DISASSOC */) || (ucSubtype == 12 /* 0x1100: MAC_FRAME_DEAUTH */))) { + LOG_FUNC("QM RX MGT: rsnStartSaQuery\n"); + /* MFP test plan 5.3.3.5 */ + rsnStartSaQuery(prAdapter); + return TRUE; + } + } +#if 0 + else { + if (fgUnicast && ((ucSubtype == MAC_FRAME_DISASSOC) || (ucSubtype == MAC_FRAME_DEAUTH))) { + /* This done by function handler */ + //kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + // WLAN_STATUS_MEDIA_DISCONNECT, + // NULL, + // 0); + } + } +#endif + } + return FALSE; +} +#endif + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/saa_fsm.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/saa_fsm.c new file mode 100755 index 000000000000..d87862206d64 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/saa_fsm.c @@ -0,0 +1,2056 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/mgmt/saa_fsm.c#1 $ +*/ + +/*! \file "saa_fsm.c" + \brief This file defines the FSM for SAA MODULE. + + This file defines the FSM for SAA MODULE. +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: saa_fsm.c $ + * + * 01 20 2012 cp.wu + * [ALPS00096191] [MT6620 Wi-Fi][Driver][Firmware] Porting to ALPS4.0_DEV branch + * sync to up-to-date changes including: + * 1. BOW bugfix + * 2. XLOG + * + * 11 24 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Adjust code for DBG and CONFIG_XLOG. + * + * 11 11 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * modify the xlog related code. + * + * 11 04 2011 cp.wu + * [WCXRP00001086] [MT6620 Wi-Fi][Driver] On Android, indicate an extra DISCONNECT for REASSOCIATED cases as an explicit trigger for Android framework + * 1. for DEAUTH/DISASSOC cases, indicate for DISCONNECTION immediately. + * 2. (Android only) when reassociation-and-non-roaming cases happened, indicate an extra DISCONNECT indication to Android Wi-Fi framework + * + * 11 02 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Add XLOG related code and define. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 05 12 2011 cp.wu + * [WCXRP00000720] [MT6620 Wi-Fi][Driver] Do not do any further operation in case STA-REC has been invalidated before SAA-FSM starts to roll + * check for valid STA-REC before SAA-FSM starts to roll. + * + * 04 21 2011 terry.wu + * [WCXRP00000674] [MT6620 Wi-Fi][Driver] Refine AAA authSendAuthFrame + * Add network type parameter to authSendAuthFrame. + * + * 04 15 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add BOW short range mode. + * + * 04 14 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 02 10 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Add RX deauthentication & disassociation process under Hot-Spot mode. + * + * 01 26 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * . + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Fix compile error of after Station Type Macro modification. + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. + * + * 11 29 2010 cp.wu + * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC for initial TX rate selection of auto-rate algorithm + * update ucRcpi of STA_RECORD_T for AIS when + * 1) Beacons for IBSS merge is received + * 2) Associate Response for a connecting peer is received + * + * 10 18 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS associated + * 1. remove redundant variables in STA_REC structure + * 2. add STA-REC uninitialization routine for clearing pending events + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 24 2010 chinghwa.yu + * NULL + * Update for MID_SCN_BOW_SCAN_DONE mboxDummy. + * Update saa_fsm for BOW. + * + * 08 16 2010 cp.wu + * NULL + * Replace CFG_SUPPORT_BOW by CFG_ENABLE_BT_OVER_WIFI. + * There is no CFG_SUPPORT_BOW in driver domain source. + * + * 08 02 2010 yuche.tsai + * NULL + * Add support for P2P join event start. + * + * 07 12 2010 cp.wu + * + * SAA will take a record for tracking request sequence number. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * AIS-FSM integration with CNM channel request messages + * + * 06 23 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * sync. with main branch for reseting to state 1 when associating with another AP + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * refine TX-DONE callback. + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * remove duplicate variable for migration. + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration the security related function from firmware. + * + * 06 17 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Fix compile error when enable WiFi Direct function. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * saa_fsm.c is migrated. + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW + * + * 04 19 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * + * * * Add Connection Policy - Any and Rx Burst Deauth Support for WHQL + * + * 03 10 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * Add Channel Manager for arbitration of JOIN and SCAN Req + * + * 02 26 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add support of Driver STA_RECORD_T activation + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * 01 27 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * add and fixed some security function. + * + * 01 12 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Fix compile warning due to declared but not used + * + * 01 11 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add Deauth and Disassoc Handler + * + * 01 08 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Refine Debug Label + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Update comment + * + * Dec 1 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * rename the function + * + * Nov 24 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Revise MGMT Handler with Retain Status + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +#if DBG +/*lint -save -e64 Type mismatch */ +static PUINT_8 apucDebugAAState[AA_STATE_NUM] = { + (PUINT_8)DISP_STRING("AA_STATE_IDLE"), + (PUINT_8)DISP_STRING("SAA_STATE_SEND_AUTH1"), + (PUINT_8)DISP_STRING("SAA_STATE_WAIT_AUTH2"), + (PUINT_8)DISP_STRING("SAA_STATE_SEND_AUTH3"), + (PUINT_8)DISP_STRING("SAA_STATE_WAIT_AUTH4"), + (PUINT_8)DISP_STRING("SAA_STATE_SEND_ASSOC1"), + (PUINT_8)DISP_STRING("SAA_STATE_WAIT_ASSOC2"), + (PUINT_8)DISP_STRING("AAA_STATE_SEND_AUTH2"), + (PUINT_8)DISP_STRING("AAA_STATE_SEND_AUTH4"), + (PUINT_8)DISP_STRING("AAA_STATE_SEND_ASSOC2"), + (PUINT_8)DISP_STRING("AA_STATE_RESOURCE") +}; +/*lint -restore */ +#endif /* DBG */ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief The Core FSM engine of SAA Module. +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] eNextState The value of Next State +* @param[in] prRetainedSwRfb Pointer to the retained SW_RFB_T for JOIN Success +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +saaFsmSteps ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN ENUM_AA_STATE_T eNextState, + IN P_SW_RFB_T prRetainedSwRfb + ) +{ + ENUM_AA_STATE_T ePreviousState; + BOOLEAN fgIsTransition; + + + ASSERT(prStaRec); + if(!prStaRec) { + return; + } + + do { + +#if CFG_SUPPORT_XLOG + DBGLOG(SAA, STATE, ("[%d] TRANSITION: [%d] -> [%d]\n", + DBG_SAA_IDX, + prStaRec->eAuthAssocState, + eNextState)); +#else + DBGLOG(SAA, STATE, ("TRANSITION: [%s] -> [%s]\n", + apucDebugAAState[prStaRec->eAuthAssocState], + apucDebugAAState[eNextState])); +#endif + ePreviousState = prStaRec->eAuthAssocState; + + /* NOTE(Kevin): This is the only place to change the eAuthAssocState(except initial) */ + prStaRec->eAuthAssocState = eNextState; + + + fgIsTransition = (BOOLEAN)FALSE; + switch (prStaRec->eAuthAssocState) { + case AA_STATE_IDLE: + { + if (ePreviousState != prStaRec->eAuthAssocState) { /* Only trigger this event once */ + + if (prRetainedSwRfb) { + + if (saaFsmSendEventJoinComplete(prAdapter, + WLAN_STATUS_SUCCESS, + prStaRec, + prRetainedSwRfb) == WLAN_STATUS_SUCCESS) { + } + else { + eNextState = AA_STATE_RESOURCE; + fgIsTransition = TRUE; + } + } + else { + if (saaFsmSendEventJoinComplete(prAdapter, + WLAN_STATUS_FAILURE, + prStaRec, + NULL) == WLAN_STATUS_RESOURCES) { + eNextState = AA_STATE_RESOURCE; + fgIsTransition = TRUE; + } + } + + } + + /* Free allocated TCM memory */ + if (prStaRec->prChallengeText) { + cnmMemFree(prAdapter, prStaRec->prChallengeText); + prStaRec->prChallengeText = (P_IE_CHALLENGE_TEXT_T)NULL; + } + } + break; + + case SAA_STATE_SEND_AUTH1: + { + /* Do tasks in INIT STATE */ + if (prStaRec->ucTxAuthAssocRetryCount >= + prStaRec->ucTxAuthAssocRetryLimit) { + + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = STATUS_CODE_AUTH_TIMEOUT; + + eNextState = AA_STATE_IDLE; + fgIsTransition = TRUE; + } + else { + prStaRec->ucTxAuthAssocRetryCount++; + + /* Update Station Record - Class 1 Flag */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + +#if !CFG_SUPPORT_AAA + if (authSendAuthFrame(prAdapter, + prStaRec, + AUTH_TRANSACTION_SEQ_1) != WLAN_STATUS_SUCCESS) +#else + if (authSendAuthFrame( + prAdapter, + prStaRec, + prStaRec->ucNetTypeIndex, + NULL, + AUTH_TRANSACTION_SEQ_1, + STATUS_CODE_RESERVED) != WLAN_STATUS_SUCCESS) +#endif /* CFG_SUPPORT_AAA */ + { + + cnmTimerInitTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer, + (PFN_MGMT_TIMEOUT_FUNC)saaFsmRunEventTxReqTimeOut, + (UINT_32)prStaRec); + + cnmTimerStartTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer, + TU_TO_MSEC(TX_AUTHENTICATION_RETRY_TIMEOUT_TU)); + } + } + } + break; + + case SAA_STATE_WAIT_AUTH2: + break; + + case SAA_STATE_SEND_AUTH3: + { + /* Do tasks in INIT STATE */ + if (prStaRec->ucTxAuthAssocRetryCount >= + prStaRec->ucTxAuthAssocRetryLimit) { + + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = STATUS_CODE_AUTH_TIMEOUT; + + eNextState = AA_STATE_IDLE; + fgIsTransition = TRUE; + } + else { + prStaRec->ucTxAuthAssocRetryCount++; + +#if !CFG_SUPPORT_AAA + if (authSendAuthFrame(prAdapter, + prStaRec, + AUTH_TRANSACTION_SEQ_3) != WLAN_STATUS_SUCCESS) +#else + if (authSendAuthFrame(prAdapter, + prStaRec, + prStaRec->ucNetTypeIndex, + NULL, + AUTH_TRANSACTION_SEQ_3, + STATUS_CODE_RESERVED) != WLAN_STATUS_SUCCESS) +#endif /* CFG_SUPPORT_AAA */ + { + + cnmTimerInitTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer, + (PFN_MGMT_TIMEOUT_FUNC)saaFsmRunEventTxReqTimeOut, + (UINT_32)prStaRec); + + cnmTimerStartTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer, + TU_TO_MSEC(TX_AUTHENTICATION_RETRY_TIMEOUT_TU)); + } + } + } + break; + + case SAA_STATE_WAIT_AUTH4: + break; + + case SAA_STATE_SEND_ASSOC1: + /* Do tasks in INIT STATE */ + if (prStaRec->ucTxAuthAssocRetryCount >= + prStaRec->ucTxAuthAssocRetryLimit) { + + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = STATUS_CODE_ASSOC_TIMEOUT; + + eNextState = AA_STATE_IDLE; + fgIsTransition = TRUE; + } + else { + prStaRec->ucTxAuthAssocRetryCount++; + + if (assocSendReAssocReqFrame(prAdapter, prStaRec) != WLAN_STATUS_SUCCESS) { + + cnmTimerInitTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer, + (PFN_MGMT_TIMEOUT_FUNC)saaFsmRunEventTxReqTimeOut, + (UINT_32)prStaRec); + + cnmTimerStartTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer, + TU_TO_MSEC(TX_ASSOCIATION_RETRY_TIMEOUT_TU)); + } + } + + break; + + case SAA_STATE_WAIT_ASSOC2: + break; + + case AA_STATE_RESOURCE: + /* TODO(Kevin) Can setup a timer and send message later */ + break; + + default: + DBGLOG(SAA, ERROR, ("Unknown AA STATE\n")); + ASSERT(0); + break; + } + + } + while (fgIsTransition); + + return; + +} /* end of saaFsmSteps() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will send Event to AIS/BOW/P2P +* +* @param[in] rJoinStatus To indicate JOIN success or failure. +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] prSwRfb Pointer to the SW_RFB_T + +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +saaFsmSendEventJoinComplete ( + IN P_ADAPTER_T prAdapter, + IN WLAN_STATUS rJoinStatus, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prSwRfb + ) +{ + P_BSS_INFO_T prBssInfo; + + ASSERT(prStaRec); + if(!prStaRec) { + return WLAN_STATUS_INVALID_PACKET; + } + + /* Store limitation about 40Mhz bandwidth capability during association */ + if (prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM) { + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; + + if (rJoinStatus == WLAN_STATUS_SUCCESS) { + prBssInfo->fg40mBwAllowed = prBssInfo->fgAssoc40mBwAllowed; + } + prBssInfo->fgAssoc40mBwAllowed = FALSE; + } + + if(prStaRec->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { + P_MSG_SAA_FSM_COMP_T prSaaFsmCompMsg; + + prSaaFsmCompMsg = cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SAA_FSM_COMP_T)); + if (!prSaaFsmCompMsg) { + return WLAN_STATUS_RESOURCES; + } + + prSaaFsmCompMsg->rMsgHdr.eMsgId = MID_SAA_AIS_JOIN_COMPLETE; + prSaaFsmCompMsg->ucSeqNum = prStaRec->ucAuthAssocReqSeqNum; + prSaaFsmCompMsg->rJoinStatus = rJoinStatus; + prSaaFsmCompMsg->prStaRec = prStaRec; + prSaaFsmCompMsg->prSwRfb = prSwRfb; + + /* NOTE(Kevin): Set to UNBUF for immediately JOIN complete */ + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T)prSaaFsmCompMsg, + MSG_SEND_METHOD_UNBUF); + + return WLAN_STATUS_SUCCESS; + } +#if CFG_ENABLE_WIFI_DIRECT + else if ((prAdapter->fgIsP2PRegistered) && + (IS_STA_IN_P2P(prStaRec))) { + P_MSG_SAA_FSM_COMP_T prSaaFsmCompMsg; + + prSaaFsmCompMsg = cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SAA_FSM_COMP_T)); + if (!prSaaFsmCompMsg) { + return WLAN_STATUS_RESOURCES; + } + + prSaaFsmCompMsg->rMsgHdr.eMsgId = MID_SAA_P2P_JOIN_COMPLETE; + prSaaFsmCompMsg->ucSeqNum = prStaRec->ucAuthAssocReqSeqNum; + prSaaFsmCompMsg->rJoinStatus = rJoinStatus; + prSaaFsmCompMsg->prStaRec = prStaRec; + prSaaFsmCompMsg->prSwRfb = prSwRfb; + + /* NOTE(Kevin): Set to UNBUF for immediately JOIN complete */ + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T)prSaaFsmCompMsg, + MSG_SEND_METHOD_UNBUF); + + return WLAN_STATUS_SUCCESS; + } +#endif +#if CFG_ENABLE_BT_OVER_WIFI + else if(prStaRec->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) { + //@TODO: BOW handler + + P_MSG_SAA_FSM_COMP_T prSaaFsmCompMsg; + + prSaaFsmCompMsg = cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SAA_FSM_COMP_T)); + if (!prSaaFsmCompMsg) { + return WLAN_STATUS_RESOURCES; + } + + prSaaFsmCompMsg->rMsgHdr.eMsgId = MID_SAA_BOW_JOIN_COMPLETE; + prSaaFsmCompMsg->ucSeqNum = prStaRec->ucAuthAssocReqSeqNum; + prSaaFsmCompMsg->rJoinStatus = rJoinStatus; + prSaaFsmCompMsg->prStaRec = prStaRec; + prSaaFsmCompMsg->prSwRfb = prSwRfb; + + /* NOTE(Kevin): Set to UNBUF for immediately JOIN complete */ + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T)prSaaFsmCompMsg, + MSG_SEND_METHOD_UNBUF); + + return WLAN_STATUS_SUCCESS; + } +#endif + else { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + +} /* end of saaFsmSendEventJoinComplete() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle the Start Event to SAA FSM. +* +* @param[in] prMsgHdr Message of Join Request for a particular STA. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +saaFsmRunEventStart ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_MSG_SAA_FSM_START_T prSaaFsmStartMsg; + P_STA_RECORD_T prStaRec; + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + + prSaaFsmStartMsg = (P_MSG_SAA_FSM_START_T)prMsgHdr; + prStaRec = prSaaFsmStartMsg->prStaRec; + + if((!prStaRec) || (prStaRec->fgIsInUse == FALSE)) { + cnmMemFree(prAdapter, prMsgHdr); + return; + } + + ASSERT(prStaRec); + + DBGLOG(SAA, LOUD, ("EVENT-START: Trigger SAA FSM.\n")); + + /* record sequence number of request message */ + prStaRec->ucAuthAssocReqSeqNum = prSaaFsmStartMsg->ucSeqNum; + + cnmMemFree(prAdapter, prMsgHdr); + + //4 <1> Validation of SAA Start Event + if (!IS_AP_STA(prStaRec)) { + + DBGLOG(SAA, ERROR, ("EVENT-START: STA Type - %d was not supported.\n", prStaRec->eStaType)); + + /* Ignore the return value because don't care the prSwRfb */ + saaFsmSendEventJoinComplete(prAdapter, WLAN_STATUS_FAILURE, prStaRec, NULL); + + return; + } + + //4 <2> The previous JOIN process is not completed ? + if (prStaRec->eAuthAssocState != AA_STATE_IDLE) { + DBGLOG(SAA, ERROR, ("EVENT-START: Reentry of SAA Module.\n")); + prStaRec->eAuthAssocState = AA_STATE_IDLE; + } + + //4 <3> Reset Status Code and Time + /* Update Station Record - Status/Reason Code */ + prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; + + /* Update the record join time. */ + GET_CURRENT_SYSTIME(&prStaRec->rLastJoinTime); + + prStaRec->ucTxAuthAssocRetryCount = 0; + + if (prStaRec->prChallengeText) { + cnmMemFree(prAdapter, prStaRec->prChallengeText); + prStaRec->prChallengeText = (P_IE_CHALLENGE_TEXT_T)NULL; + } + + cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); + +#if CFG_PRIVACY_MIGRATION + //4 <4> Init the sec fsm + secFsmInit(prAdapter, prStaRec); +#endif + + //4 <5> Reset the STA STATE + /* Update Station Record - Class 1 Flag */ + /* NOTE(Kevin): Moved to AIS FSM for Reconnect issue - + * We won't deactivate the same STA_RECORD_T and then activate it again for the + * case of reconnection. + */ + //cnmStaRecChangeState(prStaRec, STA_STATE_1); + + //4 <6> Decide if this BSS 20/40M bandwidth is allowed + if (prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM) { + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; + + if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11N) + && (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N)) { + prBssInfo->fgAssoc40mBwAllowed = + cnmBss40mBwPermitted(prAdapter, prBssInfo->ucNetTypeIndex); + } + else { + prBssInfo->fgAssoc40mBwAllowed = FALSE; + } + DBGLOG(RLM, INFO, ("STA 40mAllowed=%d\n", prBssInfo->fgAssoc40mBwAllowed)); + } + + //4 <7> Trigger SAA FSM + saaFsmSteps(prAdapter, prStaRec, SAA_STATE_SEND_AUTH1, (P_SW_RFB_T)NULL); + + return; +} /* end of saaFsmRunEventStart() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle TxDone(Auth1/Auth3/AssocReq) Event of SAA FSM. +* +* @param[in] prMsduInfo Pointer to the MSDU_INFO_T. +* @param[in] rTxDoneStatus Return TX status of the Auth1/Auth3/AssocReq frame. +* +* @retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +saaFsmRunEventTxDone ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus + ) +{ + + P_STA_RECORD_T prStaRec; + ENUM_AA_STATE_T eNextState; + + + ASSERT(prMsduInfo); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if(!prStaRec) { + return WLAN_STATUS_INVALID_PACKET; + } + + ASSERT(prStaRec); + + DBGLOG(SAA, LOUD, ("EVENT-TX DONE: Current Time = %ld\n", kalGetTimeTick())); + + eNextState = prStaRec->eAuthAssocState; + + switch (prStaRec->eAuthAssocState) { + case SAA_STATE_SEND_AUTH1: + { + /* Strictly check the outgoing frame is matched with current AA STATE */ + if (authCheckTxAuthFrame(prAdapter, + prMsduInfo, + AUTH_TRANSACTION_SEQ_1) != WLAN_STATUS_SUCCESS) { + break; + } + + if (rTxDoneStatus == TX_RESULT_SUCCESS) { + eNextState = SAA_STATE_WAIT_AUTH2; + + cnmTimerStopTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer); + + cnmTimerInitTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer, + (PFN_MGMT_TIMEOUT_FUNC)saaFsmRunEventRxRespTimeOut, + (UINT_32)prStaRec); + + cnmTimerStartTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer, + TU_TO_MSEC(DOT11_AUTHENTICATION_RESPONSE_TIMEOUT_TU)); + } + + /* if TX was successful, change to next state. + * if TX was failed, do retry if possible. + */ + saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T)NULL); + } + break; + + case SAA_STATE_SEND_AUTH3: + { + /* Strictly check the outgoing frame is matched with current JOIN STATE */ + if (authCheckTxAuthFrame(prAdapter, + prMsduInfo, + AUTH_TRANSACTION_SEQ_3) != WLAN_STATUS_SUCCESS) { + break; + } + + if (rTxDoneStatus == TX_RESULT_SUCCESS) { + eNextState = SAA_STATE_WAIT_AUTH4; + + cnmTimerStopTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer); + + cnmTimerInitTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer, + (PFN_MGMT_TIMEOUT_FUNC)saaFsmRunEventRxRespTimeOut, + (UINT_32)prStaRec); + + cnmTimerStartTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer, + TU_TO_MSEC(DOT11_AUTHENTICATION_RESPONSE_TIMEOUT_TU)); + } + + /* if TX was successful, change to next state. + * if TX was failed, do retry if possible. + */ + saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T)NULL); + } + break; + + case SAA_STATE_SEND_ASSOC1: + { + /* Strictly check the outgoing frame is matched with current SAA STATE */ + if (assocCheckTxReAssocReqFrame(prAdapter, prMsduInfo) != WLAN_STATUS_SUCCESS) { + break; + } + + if (rTxDoneStatus == TX_RESULT_SUCCESS) { + eNextState = SAA_STATE_WAIT_ASSOC2; + + cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); + + cnmTimerInitTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer, + (PFN_MGMT_TIMEOUT_FUNC)saaFsmRunEventRxRespTimeOut, + (UINT_32)prStaRec); + + cnmTimerStartTimer(prAdapter, + &(prStaRec->rTxReqDoneOrRxRespTimer), + TU_TO_MSEC(DOT11_ASSOCIATION_RESPONSE_TIMEOUT_TU)); + } + + /* if TX was successful, change to next state. + * if TX was failed, do retry if possible. + */ + saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T)NULL); + } + break; + + default: + break; /* Ignore other cases */ + } + + + return WLAN_STATUS_SUCCESS; + +} /* end of saaFsmRunEventTxDone() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will send Tx Request Timeout Event to SAA FSM. +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +saaFsmRunEventTxReqTimeOut ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ) +{ + ASSERT(prStaRec); + if(!prStaRec) { + return; + } + + DBGLOG(SAA, LOUD, ("EVENT-TIMER: TX REQ TIMEOUT, Current Time = %ld\n", kalGetTimeTick())); + + switch (prStaRec->eAuthAssocState) { + case SAA_STATE_SEND_AUTH1: + case SAA_STATE_SEND_AUTH3: + case SAA_STATE_SEND_ASSOC1: + saaFsmSteps(prAdapter, prStaRec, prStaRec->eAuthAssocState, (P_SW_RFB_T)NULL); + break; + + default: + return; + } + + return; +} /* end of saaFsmRunEventTxReqTimeOut() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will send Rx Response Timeout Event to SAA FSM. +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +saaFsmRunEventRxRespTimeOut ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ) +{ + ENUM_AA_STATE_T eNextState; + + + DBGLOG(SAA, LOUD, ("EVENT-TIMER: RX RESP TIMEOUT, Current Time = %ld\n", kalGetTimeTick())); + + ASSERT(prStaRec); + if(!prStaRec) { + return; + } + + eNextState = prStaRec->eAuthAssocState; + + switch (prStaRec->eAuthAssocState) { + case SAA_STATE_WAIT_AUTH2: + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = STATUS_CODE_AUTH_TIMEOUT; + + /* Pull back to earlier state to do retry */ + eNextState = SAA_STATE_SEND_AUTH1; + break; + + case SAA_STATE_WAIT_AUTH4: + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = STATUS_CODE_AUTH_TIMEOUT; + + /* Pull back to earlier state to do retry */ + eNextState = SAA_STATE_SEND_AUTH3; + break; + + case SAA_STATE_WAIT_ASSOC2: + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = STATUS_CODE_ASSOC_TIMEOUT; + + /* Pull back to earlier state to do retry */ + eNextState = SAA_STATE_SEND_ASSOC1; + break; + + default: + break; /* Ignore other cases */ + } + + + if (eNextState != prStaRec->eAuthAssocState) { + saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T)NULL); + } + + return; +} /* end of saaFsmRunEventRxRespTimeOut() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will process the Rx Auth Response Frame and then +* trigger SAA FSM. +* +* @param[in] prSwRfb Pointer to the SW_RFB_T structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +saaFsmRunEventRxAuth ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ) +{ + P_STA_RECORD_T prStaRec; + UINT_16 u2StatusCode; + ENUM_AA_STATE_T eNextState; + + + ASSERT(prSwRfb); + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + /* We should have the corresponding Sta Record. */ + if (!prStaRec) { + ASSERT(0); + return; + } + + if (!IS_AP_STA(prStaRec)) { + return; + } + + switch(prStaRec->eAuthAssocState) { + case SAA_STATE_SEND_AUTH1: + case SAA_STATE_WAIT_AUTH2: + /* Check if the incoming frame is what we are waiting for */ + if (authCheckRxAuthFrameStatus(prAdapter, + prSwRfb, + AUTH_TRANSACTION_SEQ_2, + &u2StatusCode) == WLAN_STATUS_SUCCESS) { + + cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); + + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = u2StatusCode; + + if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { + + authProcessRxAuth2_Auth4Frame(prAdapter, prSwRfb); + + if (prStaRec->ucAuthAlgNum == + (UINT_8)AUTH_ALGORITHM_NUM_SHARED_KEY) { + + eNextState = SAA_STATE_SEND_AUTH3; + } + else { + /* Update Station Record - Class 2 Flag */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); + + eNextState = SAA_STATE_SEND_ASSOC1; + } + } + else { + DBGLOG(SAA, INFO, ("Auth Req was rejected by ["MACSTR"], Status Code = %d\n", + MAC2STR(prStaRec->aucMacAddr), u2StatusCode)); + + eNextState = AA_STATE_IDLE; + } + + /* Reset Send Auth/(Re)Assoc Frame Count */ + prStaRec->ucTxAuthAssocRetryCount = 0; + + saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T)NULL); + } + break; + + case SAA_STATE_SEND_AUTH3: + case SAA_STATE_WAIT_AUTH4: + /* Check if the incoming frame is what we are waiting for */ + if (authCheckRxAuthFrameStatus(prAdapter, + prSwRfb, + AUTH_TRANSACTION_SEQ_4, + &u2StatusCode) == WLAN_STATUS_SUCCESS) { + + cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); + + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = u2StatusCode; + + if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { + + authProcessRxAuth2_Auth4Frame(prAdapter, prSwRfb); /* Add for 802.11r handling */ + + /* Update Station Record - Class 2 Flag */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); + + eNextState = SAA_STATE_SEND_ASSOC1; + } + else { + DBGLOG(SAA, INFO, ("Auth Req was rejected by ["MACSTR"], Status Code = %d\n", + MAC2STR(prStaRec->aucMacAddr), u2StatusCode)); + + eNextState = AA_STATE_IDLE; + } + + /* Reset Send Auth/(Re)Assoc Frame Count */ + prStaRec->ucTxAuthAssocRetryCount = 0; + + saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T)NULL); + } + break; + + default: + break; /* Ignore other cases */ + } + + return; +} /* end of saaFsmRunEventRxAuth() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will process the Rx (Re)Association Response Frame and then +* trigger SAA FSM. +* +* @param[in] prSwRfb Pointer to the SW_RFB_T structure. +* +* @retval WLAN_STATUS_SUCCESS if the status code was not success +* @retval WLAN_STATUS_BUFFER_RETAINED if the status code was success +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +saaFsmRunEventRxAssoc ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ) +{ + P_STA_RECORD_T prStaRec; + UINT_16 u2StatusCode; + ENUM_AA_STATE_T eNextState; + P_SW_RFB_T prRetainedSwRfb = (P_SW_RFB_T)NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + + ASSERT(prSwRfb); + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + /* We should have the corresponding Sta Record. */ + if (!prStaRec) { + ASSERT(0); + return rStatus; + } + + if (!IS_AP_STA(prStaRec)) { + return rStatus; + } + + switch (prStaRec->eAuthAssocState) { + case SAA_STATE_SEND_ASSOC1: + case SAA_STATE_WAIT_ASSOC2: + /* TRUE if the incoming frame is what we are waiting for */ + if (assocCheckRxReAssocRspFrameStatus(prAdapter, + prSwRfb, + &u2StatusCode) == WLAN_STATUS_SUCCESS) { + + cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); + + + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = u2StatusCode; + + if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { + + /* Update Station Record - Class 3 Flag */ + /* NOTE(Kevin): Moved to AIS FSM for roaming issue - + * We should deactivate the STA_RECORD_T of previous AP before + * activate new one in Driver. + */ + //cnmStaRecChangeState(prStaRec, STA_STATE_3); + + prStaRec->ucJoinFailureCount = 0; // Clear history. + + prRetainedSwRfb = prSwRfb; + rStatus = WLAN_STATUS_PENDING; + } + else { + DBGLOG(SAA, INFO, ("Assoc Req was rejected by ["MACSTR"], Status Code = %d\n", + MAC2STR(prStaRec->aucMacAddr), u2StatusCode)); + } + + /* Reset Send Auth/(Re)Assoc Frame Count */ + prStaRec->ucTxAuthAssocRetryCount = 0; + + /* update RCPI */ + prStaRec->ucRCPI = prSwRfb->prHifRxHdr->ucRcpi; + + eNextState = AA_STATE_IDLE; + + saaFsmSteps(prAdapter, prStaRec, eNextState, prRetainedSwRfb); + } + break; + + default: + break; /* Ignore other cases */ + } + + return rStatus; + +} /* end of saaFsmRunEventRxAssoc() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will check the incoming Deauth Frame. +* +* @param[in] prSwRfb Pointer to the SW_RFB_T structure. +* +* @retval WLAN_STATUS_SUCCESS Always not retain deauthentication frames +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +saaFsmRunEventRxDeauth ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ) +{ + P_STA_RECORD_T prStaRec; +#if DBG + P_WLAN_DEAUTH_FRAME_T prDeauthFrame; +#endif /* DBG */ + + + ASSERT(prSwRfb); + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + +#if DBG + prDeauthFrame = (P_WLAN_DEAUTH_FRAME_T) prSwRfb->pvHeader; + + DBGLOG(SAA, INFO, ("Rx Deauth frame from BSSID=["MACSTR"].\n", + MAC2STR(prDeauthFrame->aucBSSID))); +#endif /* DBG */ + + do { + + /* We should have the corresponding Sta Record. */ + if (!prStaRec) { + break; + } + + if (IS_STA_IN_AIS(prStaRec)) { + P_AIS_BSS_INFO_T prAisBssInfo; + + + if (!IS_AP_STA(prStaRec)) { + break; + } + + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + if (prStaRec->ucStaState > STA_STATE_1) { + + /* Check if this is the AP we are associated or associating with */ + if (authProcessRxDeauthFrame(prSwRfb, + prStaRec->aucMacAddr, + &prStaRec->u2ReasonCode) == WLAN_STATUS_SUCCESS) { + + if (STA_STATE_3 == prStaRec->ucStaState) { + P_MSG_AIS_ABORT_T prAisAbortMsg; + + /* NOTE(Kevin): Change state immediately to avoid starvation of + * MSG buffer because of too many deauth frames before changing + * the STA state. + */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + + prAisAbortMsg = (P_MSG_AIS_ABORT_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); + if (!prAisAbortMsg) { + break; + } + + prAisAbortMsg->rMsgHdr.eMsgId = MID_SAA_AIS_FSM_ABORT; + prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_DEAUTHENTICATED; + prAisAbortMsg->fgDelayIndication = FALSE; + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prAisAbortMsg, + MSG_SEND_METHOD_BUF); + } + else { + + /* TODO(Kevin): Joining Abort */ + } + + } + + } + + } +#if CFG_ENABLE_WIFI_DIRECT + else if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { + /* TODO(Kevin) */ + prAdapter->rP2pFuncLkr.prP2pFsmRunEventRxDeauthentication(prAdapter, prStaRec, prSwRfb); + } +#endif +#if CFG_ENABLE_BT_OVER_WIFI + else if (IS_STA_IN_BOW(prStaRec)) { + bowRunEventRxDeAuth(prAdapter, prStaRec, prSwRfb); + } +#endif + else { + ASSERT(0); + } + + } while (FALSE); + + return WLAN_STATUS_SUCCESS; + +} /* end of saaFsmRunEventRxDeauth() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will check the incoming Disassociation Frame. +* +* @param[in] prSwRfb Pointer to the SW_RFB_T structure. +* +* @retval WLAN_STATUS_SUCCESS Always not retain disassociation frames +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +saaFsmRunEventRxDisassoc ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ) +{ + P_STA_RECORD_T prStaRec; +#if DBG + P_WLAN_DISASSOC_FRAME_T prDisassocFrame; +#endif /* DBG */ + + + ASSERT(prSwRfb); + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + +#if DBG + prDisassocFrame = (P_WLAN_DISASSOC_FRAME_T) prSwRfb->pvHeader; + + DBGLOG(SAA, INFO, ("Rx Disassoc frame from BSSID=["MACSTR"].\n", + MAC2STR(prDisassocFrame->aucBSSID))); +#endif /* DBG */ + + do { + + /* We should have the corresponding Sta Record. */ + if (!prStaRec) { + break; + } + + if (IS_STA_IN_AIS(prStaRec)) { + P_AIS_BSS_INFO_T prAisBssInfo; + + + if (!IS_AP_STA(prStaRec)) { + break; + } + + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + if (prStaRec->ucStaState > STA_STATE_1) { + + /* Check if this is the AP we are associated or associating with */ + if (assocProcessRxDisassocFrame(prAdapter, + prSwRfb, + prStaRec->aucMacAddr, + &prStaRec->u2ReasonCode) == WLAN_STATUS_SUCCESS) { + + if (STA_STATE_3 == prStaRec->ucStaState) { + P_MSG_AIS_ABORT_T prAisAbortMsg; + + prAisAbortMsg = (P_MSG_AIS_ABORT_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); + if (!prAisAbortMsg) { + break; + } + + prAisAbortMsg->rMsgHdr.eMsgId = MID_SAA_AIS_FSM_ABORT; + prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_DISASSOCIATED; + prAisAbortMsg->fgDelayIndication = FALSE; + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prAisAbortMsg, + MSG_SEND_METHOD_BUF); + } + else { + + /* TODO(Kevin): Joining Abort */ + } + + } + + } + + } +#if CFG_ENABLE_WIFI_DIRECT + else if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { + /* TODO(Kevin) */ + prAdapter->rP2pFuncLkr.prP2pFsmRunEventRxDisassociation(prAdapter, prStaRec, prSwRfb); + } +#endif +#if CFG_ENABLE_BT_OVER_WIFI + else if (IS_STA_IN_BOW(prStaRec)) { + /* TODO(Kevin) */ + } +#endif + else { + ASSERT(0); + } + + } while (FALSE); + + return WLAN_STATUS_SUCCESS; + +} /* end of saaFsmRunEventRxDisassoc() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle the Abort Event to SAA FSM. +* +* @param[in] prMsgHdr Message of Abort Request for a particular STA. +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +saaFsmRunEventAbort ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_MSG_SAA_FSM_ABORT_T prSaaFsmAbortMsg; + P_STA_RECORD_T prStaRec; + + + ASSERT(prMsgHdr); + + prSaaFsmAbortMsg = (P_MSG_SAA_FSM_ABORT_T)prMsgHdr; + prStaRec = prSaaFsmAbortMsg->prStaRec; + + ASSERT(prStaRec); + if(!prStaRec) { + cnmMemFree(prAdapter, prMsgHdr); + return; + } + + DBGLOG(SAA, LOUD, ("EVENT-ABORT: Stop SAA FSM.\n")); + + cnmMemFree(prAdapter, prMsgHdr); + + + /* Reset Send Auth/(Re)Assoc Frame Count */ + prStaRec->ucTxAuthAssocRetryCount = 0; + + /* Cancel JOIN relative Timer */ + cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); + + if (prStaRec->eAuthAssocState != AA_STATE_IDLE) { +#if DBG + DBGLOG(SAA, LOUD, ("EVENT-ABORT: Previous Auth/Assoc State == %s.\n", + apucDebugAAState[prStaRec->eAuthAssocState])); +#else + DBGLOG(SAA, LOUD, ("EVENT-ABORT: Previous Auth/Assoc State == %d.\n", + prStaRec->eAuthAssocState)); +#endif + } + + /* For the Auth/Assoc State to IDLE */ + prStaRec->eAuthAssocState = AA_STATE_IDLE; + + return; +} /* end of saaFsmRunEventAbort() */ + + +/* TODO(Kevin): following code will be modified and move to AIS FSM */ +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will send Join Timeout Event to JOIN FSM. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* +* \retval WLAN_STATUS_FAILURE Fail because of Join Timeout +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +joinFsmRunEventJoinTimeOut ( + IN P_ADAPTER_T prAdapter + ) +{ + P_JOIN_INFO_T prJoinInfo; + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("joinFsmRunEventJoinTimeOut"); + + + ASSERT(prAdapter); + prJoinInfo = &prAdapter->rJoinInfo; + + DBGLOG(JOIN, EVENT, ("JOIN EVENT: JOIN TIMEOUT\n")); + + /* Get a Station Record if possible, TA == BSSID for AP */ + prStaRec = staRecGetStaRecordByAddr(prAdapter, + prJoinInfo->prBssDesc->aucBSSID); + + /* We have renew this Sta Record when in JOIN_STATE_INIT */ + ASSERT(prStaRec); + + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = STATUS_CODE_JOIN_TIMEOUT; + + /* Increase Failure Count */ + prStaRec->ucJoinFailureCount++; + + /* Reset Send Auth/(Re)Assoc Frame Count */ + prJoinInfo->ucTxAuthAssocRetryCount = 0; + + /* Cancel other JOIN relative Timer */ + ARB_CANCEL_TIMER(prAdapter, + prJoinInfo->rTxRequestTimer); + + ARB_CANCEL_TIMER(prAdapter, + prJoinInfo->rRxResponseTimer); + + /* Restore original setting from current BSS_INFO_T */ + if (prAdapter->eConnectionState == MEDIA_STATE_CONNECTED) { + joinAdoptParametersFromCurrentBss(prAdapter); + } + + /* Pull back to IDLE */ + joinFsmSteps(prAdapter, JOIN_STATE_IDLE); + + return WLAN_STATUS_FAILURE; + +} /* end of joinFsmRunEventJoinTimeOut() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will adopt the parameters from Peer BSS. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +joinAdoptParametersFromPeerBss ( + IN P_ADAPTER_T prAdapter + ) +{ + P_JOIN_INFO_T prJoinInfo; + P_BSS_DESC_T prBssDesc; + + DEBUGFUNC("joinAdoptParametersFromPeerBss"); + + + ASSERT(prAdapter); + prJoinInfo = &prAdapter->rJoinInfo; + prBssDesc = prJoinInfo->prBssDesc; + + //4 <1> Adopt Peer BSS' PHY TYPE + prAdapter->eCurrentPhyType = prBssDesc->ePhyType; + + DBGLOG(JOIN, INFO, ("Target BSS[%s]'s PhyType = %s\n", + prBssDesc->aucSSID, (prBssDesc->ePhyType == PHY_TYPE_ERP_INDEX) ? "ERP" : "HR_DSSS")); + + + //4 <2> Adopt Peer BSS' Frequency(Band/Channel) + DBGLOG(JOIN, INFO, ("Target BSS's Channel = %d, Band = %d\n", + prBssDesc->ucChannelNum, prBssDesc->eBand)); + + nicSwitchChannel(prAdapter, + prBssDesc->eBand, + prBssDesc->ucChannelNum, + 10); + + prJoinInfo->fgIsParameterAdopted = TRUE; + + return; +} /* end of joinAdoptParametersFromPeerBss() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will adopt the parameters from current associated BSS. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +joinAdoptParametersFromCurrentBss ( + IN P_ADAPTER_T prAdapter + ) +{ + //P_JOIN_INFO_T prJoinInfo = &prAdapter->rJoinInfo; + P_BSS_INFO_T prBssInfo; + + + ASSERT(prAdapter); + prBssInfo = &prAdapter->rBssInfo; + + //4 <1> Adopt current BSS' PHY TYPE + prAdapter->eCurrentPhyType = prBssInfo->ePhyType; + + //4 <2> Adopt current BSS' Frequency(Band/Channel) + DBGLOG(JOIN, INFO, ("Current BSS's Channel = %d, Band = %d\n", + prBssInfo->ucChnl, prBssInfo->eBand)); + + nicSwitchChannel(prAdapter, + prBssInfo->eBand, + prBssInfo->ucChnl, + 10); + return; +} /* end of joinAdoptParametersFromCurrentBss() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will update all the SW variables and HW MCR registers after +* the association with target BSS. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +joinComplete ( + IN P_ADAPTER_T prAdapter + ) +{ + P_JOIN_INFO_T prJoinInfo; + P_BSS_DESC_T prBssDesc; + P_PEER_BSS_INFO_T prPeerBssInfo; + P_BSS_INFO_T prBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_STA_RECORD_T prStaRec; + P_TX_CTRL_T prTxCtrl; +#if CFG_SUPPORT_802_11D + P_IE_COUNTRY_T prIECountry; +#endif + + DEBUGFUNC("joinComplete"); + + + ASSERT(prAdapter); + prJoinInfo = &prAdapter->rJoinInfo; + prBssDesc = prJoinInfo->prBssDesc; + prPeerBssInfo = &prAdapter->rPeerBssInfo; + prBssInfo = &prAdapter->rBssInfo; + prConnSettings = &prAdapter->rConnSettings; + prTxCtrl = &prAdapter->rTxCtrl; + +//4 <1> Update Connecting & Connected Flag of BSS_DESC_T. + /* Remove previous AP's Connection Flags if have */ + scanRemoveConnectionFlagOfBssDescByBssid(prAdapter, prBssInfo->aucBSSID); + + prBssDesc->fgIsConnected = TRUE; /* Mask as Connected */ + + if (prBssDesc->fgIsHiddenSSID) { + /* NOTE(Kevin): This is for the case of Passive Scan and the target BSS didn't + * broadcast SSID on its Beacon Frame. + */ + COPY_SSID(prBssDesc->aucSSID, + prBssDesc->ucSSIDLen, + prAdapter->rConnSettings.aucSSID, + prAdapter->rConnSettings.ucSSIDLen); + + if (prBssDesc->ucSSIDLen) { + prBssDesc->fgIsHiddenSSID = FALSE; + } +#if DBG + else { + ASSERT(0); + } +#endif /* DBG */ + + DBGLOG(JOIN, INFO, ("Hidden SSID! - Update SSID : %s\n", prBssDesc->aucSSID)); + } + + +//4 <2> Update BSS_INFO_T from BSS_DESC_T + //4 <2.A> PHY Type + prBssInfo->ePhyType = prBssDesc->ePhyType; + + //4 <2.B> BSS Type + prBssInfo->eBSSType = BSS_TYPE_INFRASTRUCTURE; + + //4 <2.C> BSSID + COPY_MAC_ADDR(prBssInfo->aucBSSID, prBssDesc->aucBSSID); + + DBGLOG(JOIN, INFO, ("JOIN to BSSID: ["MACSTR"]\n", MAC2STR(prBssDesc->aucBSSID))); + + + //4 <2.D> SSID + COPY_SSID(prBssInfo->aucSSID, + prBssInfo->ucSSIDLen, + prBssDesc->aucSSID, + prBssDesc->ucSSIDLen); + + //4 <2.E> Channel / Band information. + prBssInfo->eBand = prBssDesc->eBand; + prBssInfo->ucChnl = prBssDesc->ucChannelNum; + + //4 <2.F> RSN/WPA information. + secFsmRunEventStart(prAdapter); + prBssInfo->u4RsnSelectedPairwiseCipher = prBssDesc->u4RsnSelectedPairwiseCipher; + prBssInfo->u4RsnSelectedGroupCipher = prBssDesc->u4RsnSelectedGroupCipher; + prBssInfo->u4RsnSelectedAKMSuite = prBssDesc->u4RsnSelectedAKMSuite; + + if (secRsnKeyHandshakeEnabled()) { + prBssInfo->fgIsWPAorWPA2Enabled = TRUE; + } + else { + prBssInfo->fgIsWPAorWPA2Enabled = FALSE; + } + + //4 <2.G> Beacon interval. + prBssInfo->u2BeaconInterval = prBssDesc->u2BeaconInterval; + + //4 <2.H> DTIM period. + prBssInfo->ucDtimPeriod = prBssDesc->ucDTIMPeriod; + + //4 <2.I> ERP Information + if ((prBssInfo->ePhyType == PHY_TYPE_ERP_INDEX) && // Our BSS's PHY_TYPE is ERP now. + (prBssDesc->fgIsERPPresent)) { + + prBssInfo->fgIsERPPresent = TRUE; + prBssInfo->ucERP = prBssDesc->ucERP; /* Save the ERP for later check */ + } + else { /* Some AP, may send ProbeResp without ERP IE. Thus prBssDesc->fgIsERPPresent is FALSE. */ + prBssInfo->fgIsERPPresent = FALSE; + prBssInfo->ucERP = 0; + } + +#if CFG_SUPPORT_802_11D + //4 <2.J> Country inforamtion of the associated AP + if (prConnSettings->fgMultiDomainCapabilityEnabled) { + DOMAIN_INFO_ENTRY rDomainInfo; + if (domainGetDomainInfoByScanResult(prAdapter, &rDomainInfo)) { + if (prBssDesc->prIECountry) { + prIECountry = prBssDesc->prIECountry; + + domainParseCountryInfoElem(prIECountry, &prBssInfo->rDomainInfo); + + /* use the domain get from the BSS info */ + prBssInfo->fgIsCountryInfoPresent = TRUE; + nicSetupOpChnlList(prAdapter, prBssInfo->rDomainInfo.u2CountryCode, FALSE); + } else { + /* use the domain get from the scan result */ + prBssInfo->fgIsCountryInfoPresent = TRUE; + nicSetupOpChnlList(prAdapter, rDomainInfo.u2CountryCode, FALSE); + } + } + } +#endif + + //4 <2.K> Signal Power of the associated AP + prBssInfo->rRcpi = prBssDesc->rRcpi; + prBssInfo->rRssi = RCPI_TO_dBm(prBssInfo->rRcpi); + GET_CURRENT_SYSTIME(&prBssInfo->rRssiLastUpdateTime); + + //4 <2.L> Capability Field of the associated AP + prBssInfo->u2CapInfo = prBssDesc->u2CapInfo; + + DBGLOG(JOIN, INFO, ("prBssInfo-> fgIsERPPresent = %d, ucERP = %02x, rRcpi = %d, rRssi = %ld\n", + prBssInfo->fgIsERPPresent, prBssInfo->ucERP, prBssInfo->rRcpi, prBssInfo->rRssi)); + + +//4 <3> Update BSS_INFO_T from PEER_BSS_INFO_T & NIC RATE FUNC + //4 <3.A> Association ID + prBssInfo->u2AssocId = prPeerBssInfo->u2AssocId; + + //4 <3.B> WMM Infomation + if (prAdapter->fgIsEnableWMM && + (prPeerBssInfo->rWmmInfo.ucWmmFlag & WMM_FLAG_SUPPORT_WMM)) { + + prBssInfo->fgIsWmmAssoc = TRUE; + prTxCtrl->rTxQForVoipAccess = TXQ_AC3; + + qosWmmInfoInit(&prBssInfo->rWmmInfo, (prBssInfo->ePhyType == PHY_TYPE_HR_DSSS_INDEX) ? TRUE : FALSE); + + if (prPeerBssInfo->rWmmInfo.ucWmmFlag & WMM_FLAG_AC_PARAM_PRESENT) { + kalMemCopy(&prBssInfo->rWmmInfo, + &prPeerBssInfo->rWmmInfo, + sizeof(WMM_INFO_T)); + } + else { + kalMemCopy(&prBssInfo->rWmmInfo, + &prPeerBssInfo->rWmmInfo, + sizeof(WMM_INFO_T) - sizeof(prPeerBssInfo->rWmmInfo.arWmmAcParams)); + } + } + else { + prBssInfo->fgIsWmmAssoc = FALSE; + prTxCtrl->rTxQForVoipAccess = TXQ_AC1; + + kalMemZero(&prBssInfo->rWmmInfo, sizeof(WMM_INFO_T)); + } + + + //4 <3.C> Operational Rate Set & BSS Basic Rate Set + prBssInfo->u2OperationalRateSet = prPeerBssInfo->u2OperationalRateSet; + prBssInfo->u2BSSBasicRateSet = prPeerBssInfo->u2BSSBasicRateSet; + + + //4 <3.D> Short Preamble + if (prBssInfo->fgIsERPPresent) { + + /* NOTE(Kevin 2007/12/24): Truth Table. + * Short Preamble Bit in + * Final Driver Setting(Short) + * TRUE FALSE FALSE FALSE(shouldn't have such case, use the AssocResp) + * TRUE FALSE TRUE FALSE + * FALSE FALSE FALSE FALSE(shouldn't have such case, use the AssocResp) + * FALSE FALSE TRUE FALSE + * TRUE TRUE FALSE TRUE(follow ERP) + * TRUE TRUE TRUE FALSE(follow ERP) + * FALSE TRUE FALSE FALSE(shouldn't have such case, and we should set to FALSE) + * FALSE TRUE TRUE FALSE(we should set to FALSE) + */ + if ((prPeerBssInfo->fgIsShortPreambleAllowed) && + ((prConnSettings->ePreambleType == PREAMBLE_TYPE_SHORT) || /* Short Preamble Option Enable is TRUE */ + ((prConnSettings->ePreambleType == PREAMBLE_TYPE_AUTO) && + (prBssDesc->u2CapInfo & CAP_INFO_SHORT_PREAMBLE)))) { + + prBssInfo->fgIsShortPreambleAllowed = TRUE; + + if (prBssInfo->ucERP & ERP_INFO_BARKER_PREAMBLE_MODE) { + prBssInfo->fgUseShortPreamble = FALSE; + } + else { + prBssInfo->fgUseShortPreamble = TRUE; + } + } + else { + prBssInfo->fgIsShortPreambleAllowed = FALSE; + prBssInfo->fgUseShortPreamble = FALSE; + } + } + else { + /* NOTE(Kevin 2007/12/24): Truth Table. + * Short Preamble Bit in + * Final Driver Setting(Short) + * TRUE FALSE FALSE + * FALSE FALSE FALSE + * TRUE TRUE TRUE + * FALSE TRUE(status success) TRUE + * --> Honor the result of prPeerBssInfo. + */ + + prBssInfo->fgIsShortPreambleAllowed = prBssInfo->fgUseShortPreamble = + prPeerBssInfo->fgIsShortPreambleAllowed; + } + + DBGLOG(JOIN, INFO, ("prBssInfo->fgIsShortPreambleAllowed = %d, prBssInfo->fgUseShortPreamble = %d\n", + prBssInfo->fgIsShortPreambleAllowed, prBssInfo->fgUseShortPreamble)); + + + //4 <3.E> Short Slot Time + prBssInfo->fgUseShortSlotTime = + prPeerBssInfo->fgUseShortSlotTime; /* AP support Short Slot Time */ + + DBGLOG(JOIN, INFO, ("prBssInfo->fgUseShortSlotTime = %d\n", + prBssInfo->fgUseShortSlotTime)); + + nicSetSlotTime(prAdapter, + prBssInfo->ePhyType, + ((prConnSettings->fgIsShortSlotTimeOptionEnable && + prBssInfo->fgUseShortSlotTime) ? TRUE : FALSE)); + + + //4 <3.F> Update Tx Rate for Control Frame + bssUpdateTxRateForControlFrame(prAdapter); + + + //4 <3.G> Save the available Auth Types during Roaming (Design for Fast BSS Transition). + //if (prAdapter->fgIsEnableRoaming) /* NOTE(Kevin): Always prepare info for roaming */ + { + + if (prJoinInfo->ucCurrAuthAlgNum == AUTH_ALGORITHM_NUM_OPEN_SYSTEM) { + prJoinInfo->ucRoamingAuthTypes |= AUTH_TYPE_OPEN_SYSTEM; + } + else if (prJoinInfo->ucCurrAuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY) { + prJoinInfo->ucRoamingAuthTypes |= AUTH_TYPE_SHARED_KEY; + } + + prBssInfo->ucRoamingAuthTypes = prJoinInfo->ucRoamingAuthTypes; + + + /* Set the stable time of the associated BSS. We won't do roaming decision + * during the stable time. + */ + SET_EXPIRATION_TIME(prBssInfo->rRoamingStableExpirationTime, + SEC_TO_SYSTIME(ROAMING_STABLE_TIMEOUT_SEC)); + } + + + //4 <3.H> Update Parameter for TX Fragmentation Threshold +#if CFG_TX_FRAGMENT + txFragInfoUpdate(prAdapter); +#endif /* CFG_TX_FRAGMENT */ + + +//4 <4> Update STA_RECORD_T + /* Get a Station Record if possible */ + prStaRec = staRecGetStaRecordByAddr(prAdapter, + prBssDesc->aucBSSID); + + if (prStaRec) { + UINT_16 u2OperationalRateSet, u2DesiredRateSet; + + //4 <4.A> Desired Rate Set + u2OperationalRateSet = (rPhyAttributes[prBssInfo->ePhyType].u2SupportedRateSet & + prBssInfo->u2OperationalRateSet); + + u2DesiredRateSet = (u2OperationalRateSet & prConnSettings->u2DesiredRateSet); + if (u2DesiredRateSet) { + prStaRec->u2DesiredRateSet = u2DesiredRateSet; + } + else { + /* For Error Handling - The Desired Rate Set is not covered in Operational Rate Set. */ + prStaRec->u2DesiredRateSet = u2OperationalRateSet; + } + + /* Try to set the best initial rate for this entry */ + if (!rateGetBestInitialRateIndex(prStaRec->u2DesiredRateSet, + prStaRec->rRcpi, + &prStaRec->ucCurrRate1Index)) { + + if (!rateGetLowestRateIndexFromRateSet(prStaRec->u2DesiredRateSet, + &prStaRec->ucCurrRate1Index)) { + ASSERT(0); + } + } + + DBGLOG(JOIN, INFO, ("prStaRec->ucCurrRate1Index = %d\n", + prStaRec->ucCurrRate1Index)); + + //4 <4.B> Preamble Mode + prStaRec->fgIsShortPreambleOptionEnable = + prBssInfo->fgUseShortPreamble; + + //4 <4.C> QoS Flag + prStaRec->fgIsQoS = prBssInfo->fgIsWmmAssoc; + } +#if DBG + else { + ASSERT(0); + } +#endif /* DBG */ + + +//4 <5> Update NIC + //4 <5.A> Update BSSID & Operation Mode + nicSetupBSS(prAdapter, prBssInfo); + + //4 <5.B> Update WLAN Table. + if (nicSetHwBySta(prAdapter, prStaRec) == FALSE) { + ASSERT(FALSE); + } + + //4 <5.C> Update Desired Rate Set for BT. +#if CFG_TX_FRAGMENT + if (prConnSettings->fgIsEnableTxAutoFragmentForBT) { + txRateSetInitForBT(prAdapter, prStaRec); + } +#endif /* CFG_TX_FRAGMENT */ + + //4 <5.D> TX AC Parameter and TX/RX Queue Control + if (prBssInfo->fgIsWmmAssoc) { + +#if CFG_TX_AGGREGATE_HW_FIFO + nicTxAggregateTXQ(prAdapter, FALSE); +#endif /* CFG_TX_AGGREGATE_HW_FIFO */ + + qosUpdateWMMParametersAndAssignAllowedACI(prAdapter, &prBssInfo->rWmmInfo); + } + else { + +#if CFG_TX_AGGREGATE_HW_FIFO + nicTxAggregateTXQ(prAdapter, TRUE); +#endif /* CFG_TX_AGGREGATE_HW_FIFO */ + + nicTxNonQoSAssignDefaultAdmittedTXQ(prAdapter); + + nicTxNonQoSUpdateTXQParameters(prAdapter, + prBssInfo->ePhyType); + } + +#if CFG_TX_STOP_WRITE_TX_FIFO_UNTIL_JOIN + { + prTxCtrl->fgBlockTxDuringJoin = FALSE; + + #if !CFG_TX_AGGREGATE_HW_FIFO /* TX FIFO AGGREGATE already do flush once */ + nicTxFlushStopQueues(prAdapter, (UINT_8)TXQ_DATA_MASK, (UINT_8)NULL); + #endif /* CFG_TX_AGGREGATE_HW_FIFO */ + + nicTxRetransmitOfSendWaitQue(prAdapter); + + if (prTxCtrl->fgIsPacketInOsSendQueue) { + nicTxRetransmitOfOsSendQue(prAdapter); + } + + #if CFG_SDIO_TX_ENHANCE + halTxLeftClusteredMpdu(prAdapter); + #endif /* CFG_SDIO_TX_ENHANCE */ + + } +#endif /* CFG_TX_STOP_WRITE_TX_FIFO_UNTIL_JOIN */ + + +//4 <6> Setup CONNECTION flag. + prAdapter->eConnectionState = MEDIA_STATE_CONNECTED; + prAdapter->eConnectionStateIndicated = MEDIA_STATE_CONNECTED; + + if (prJoinInfo->fgIsReAssoc) { + prAdapter->fgBypassPortCtrlForRoaming = TRUE; + } + else { + prAdapter->fgBypassPortCtrlForRoaming = FALSE; + } + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_CONNECT, + (PVOID)NULL, + 0); + + return; +} /* end of joinComplete() */ +#endif + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/scan.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/scan.c new file mode 100755 index 000000000000..94e3aab8353f --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/scan.c @@ -0,0 +1,3002 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/mgmt/scan.c#5 $ +*/ + +/*! \file "scan.c" + \brief This file defines the scan profile and the processing function of + scan result for SCAN Module. + + The SCAN Profile selection is part of SCAN MODULE and responsible for defining + SCAN Parameters - e.g. MIN_CHANNEL_TIME, number of scan channels. + In this file we also define the process of SCAN Result including adding, searching + and removing SCAN record from the list. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: scan.c $ + * + * 02 06 2012 yuche.tsai + * [ALPS00118350] [ALPS.ICS][WiFi Direct] Dirver update for wifi direct connection + * Small bug fix for CNM memory usage, scan SSID search issue, P2P network deactivate issue. + * + * 01 20 2012 cp.wu + * [ALPS00096191] [MT6620 Wi-Fi][Driver][Firmware] Porting to ALPS4.0_DEV branch + * sync to up-to-date changes including: + * 1. BOW bugfix + * 2. XLOG + * + * 01 16 2012 yuche.tsai + * NULL + * Fix compile error. + * + * 01 16 2012 cp.wu + * [WCXRP00001169] [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band configuration with corresponding network configuration + * correct typo. + * + * 01 16 2012 cp.wu + * [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band configuration with corresponding network configuration + * add wlanSetPreferBandByNetwork() for glue layer to invoke for setting preferred band configuration corresponding to network type. + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Hot Spot Tethering for ICS ALPHA testing version. + * + * 12 06 2011 cp.wu + * [WCXRP00001131] [MT6620 Wi-Fi][Driver][AIS] Implement connect-by-BSSID path + * sync. for connect-by-bssid control path implementations. + * + * 11 23 2011 cp.wu + * [WCXRP00001123] [MT6620 Wi-Fi][Driver] Add option to disable beacon content change detection + * add compile option to disable beacon content change detection. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 08 11 2011 cp.wu + * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time + * sparse channel detection: + * driver: collect sparse channel information with scan-done event + * + * 08 10 2011 cp.wu + * [WCXRP00000922] [MT6620 Wi-Fi][Driver] traverse whole BSS-DESC list for removing + * traverse whole BSS-DESC list because BSSID is not unique anymore. + * + * 07 26 2011 yuche.tsai + * [WCXRP00000875] [Volunteer Patch][WiFi Direct][Driver] MT6620 IOT issue with realtek test bed solution. + * P2P Scan would not check SSID field, because this field may change. + * + * 07 12 2011 cp.wu + * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID settings to work around some tricky AP which use space character as hidden SSID + * for multiple BSS descriptior detecting issue: + * 1) check BSSID for infrastructure network + * 2) check SSID for AdHoc network + * + * 07 12 2011 cp.wu + * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID settings to work around some tricky AP which use space character as hidden SSID + * check for BSSID for beacons used to update DTIM + * + * 07 12 2011 cp.wu + * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID settings to work around some tricky AP which use space character as hidden SSID + * do not check BSS descriptor for connected flag due to linksys's hidden SSID will use another BSS descriptor and never connected + * + * 07 11 2011 cp.wu + * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID settings to work around some tricky AP which use space character as hidden SSID + * just pass beacons with the same BSSID. + * + * 07 11 2011 wh.su + * [WCXRP00000849] [MT6620 Wi-Fi][Driver] Remove some of the WAPI define for make sure the value is initialize, for customer not enable WAPI + * For make sure wapi initial value is set. + * + * 06 28 2011 cp.wu + * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID settings to work around some tricky AP which use space character as hidden SSID + * Do not check for SSID as beacon content change due to the existence of single BSSID with multiple SSID AP configuration + * + * 06 27 2011 cp.wu + * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID settings to work around some tricky AP which use space character as hidden SSID + * 1. correct logic + * 2. replace only BSS-DESC which doesn't have a valid SSID. + * + * 06 27 2011 cp.wu + * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID settings to work around some tricky AP which use space character as hidden SSID + * remove unused temporal variable reference. + * + * 06 27 2011 cp.wu + * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID settings to work around some tricky AP which use space character as hidden SSID + * allow to have a single BSSID with multiple SSID to be presented in scanning result + * + * 06 02 2011 cp.wu + * [WCXRP00000757] [MT6620 Wi-Fi][Driver][SCN] take use of RLM API to filter out BSS in disallowed channels + * filter out BSS in disallowed channel by + * 1. do not add to scan result array if BSS is at disallowed channel + * 2. do not allow to search for BSS-DESC in disallowed channels + * + * 05 02 2011 cm.chang + * [WCXRP00000691] [MT6620 Wi-Fi][Driver] Workaround about AP's wrong HT capability IE to have wrong channel number + * Refine channel number validation method + * + * 05 02 2011 cp.wu + * [MT6620 Wi-Fi][Driver] Take parsed result for channel information instead of hardware channel number passed from firmware domain + * take parsed result for generating scanning result with channel information. + * + * 05 02 2011 cm.chang + * [WCXRP00000691] [MT6620 Wi-Fi][Driver] Workaround about AP's wrong HT capability IE to have wrong channel number + * Check if IE channel is valid before recording BSS channel number + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 04 14 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 04 12 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix the sta index in processing security frame + * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 + * Add debug message. + * + * 04 11 2011 yuche.tsai + * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. + * Alway keep the latest Bss type when RX Beacon. + * + * 03 23 2011 yuche.tsai + * NULL + * Fix concurrent issue when AIS scan result would over write P2P scan result. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 14 2011 cp.wu + * [WCXRP00000535] [MT6620 Wi-Fi][Driver] Fixed channel operation when AIS and Tethering are operating concurrently + * filtering out other BSS coming from adjacent channels + * + * 03 11 2011 chinglan.wang + * [WCXRP00000537] [MT6620 Wi-Fi][Driver] Can not connect to 802.11b/g/n mixed AP with WEP security. + * . + * + * 03 11 2011 cp.wu + * [WCXRP00000535] [MT6620 Wi-Fi][Driver] Fixed channel operation when AIS and Tethering are operating concurrently + * When fixed channel operation is necessary, AIS-FSM would scan and only connect for BSS on the specific channel + * + * 02 24 2011 cp.wu + * [WCXRP00000490] [MT6620 Wi-Fi][Driver][Win32] modify kalMsleep() implementation because NdisMSleep() won't sleep long enough for specified interval such as 500ms + * implement beacon change detection by checking SSID and supported rate. + * + * 02 22 2011 yuche.tsai + * [WCXRP00000480] [Volunteer Patch][MT6620][Driver] WCS IE format issue + * Fix WSC big endian issue. + * + * 02 21 2011 terry.wu + * [WCXRP00000476] [MT6620 Wi-Fi][Driver] Clean P2P scan list while removing P2P + * Clean P2P scan list while removing P2P. + * + * 01 27 2011 yuche.tsai + * [WCXRP00000399] [Volunteer Patch][MT6620/MT5931][Driver] Fix scan side effect after P2P module separate. + * Fix scan channel extension issue when p2p module is not registered. + * + * 01 26 2011 cm.chang + * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument + * . + * + * 01 21 2011 cp.wu + * [WCXRP00000380] [MT6620 Wi-Fi][Driver] SSID information should come from buffered BSS_DESC_T rather than using beacon-carried information + * SSID should come from buffered prBssDesc rather than beacon-carried information + * + * 01 14 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Fix compile error. + * + * 01 14 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Memfree for P2P Descriptor & P2P Descriptor List. + * + * 01 14 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Free P2P Descriptor List & Descriptor under BSS Descriptor. + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease physically continous memory demands + * 1) correct typo in scan.c + * 2) TX descriptors, RX descriptos and management buffer should use virtually continous buffer instead of physically contineous one + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease physically continous memory demands + * separate kalMemAlloc() into virtually-continous and physically-continous type to ease slab system pressure + * + * 12 31 2010 cp.wu + * [WCXRP00000327] [MT6620 Wi-Fi][Driver] Improve HEC WHQA 6972 workaround coverage in driver side + * while being unloaded, clear all pending interrupt then set LP-own to firmware + * + * 12 21 2010 cp.wu + * [WCXRP00000280] [MT6620 Wi-Fi][Driver] Enable BSS selection with best RCPI policy in SCN module + * SCN: enable BEST RSSI selection policy support + * + * 11 29 2010 cp.wu + * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC for initial TX rate selection of auto-rate algorithm + * update ucRcpi of STA_RECORD_T for AIS when + * 1) Beacons for IBSS merge is received + * 2) Associate Response for a connecting peer is received + * + * 11 03 2010 wh.su + * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group + * Refine the HT rate disallow TKIP pairwise cipher . + * + * 10 12 2010 cp.wu + * [WCXRP00000091] [MT6620 Wi-Fi][Driver] Add scanning logic to filter out beacons which is received on the folding frequency + * trust HT IE if available for 5GHz band + * + * 10 11 2010 cp.wu + * [WCXRP00000091] [MT6620 Wi-Fi][Driver] Add scanning logic to filter out beacons which is received on the folding frequency + * add timing and strenght constraint for filtering out beacons with same SSID/TA but received on different channels + * + * 10 08 2010 wh.su + * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine + * update the frog's new p2p state machine. + * + * 10 01 2010 yuche.tsai + * NULL + * [MT6620 P2P] Fix Big Endian Issue when parse P2P device name TLV. + * + * 09 24 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * eliminate unused variables which lead gcc to argue + * + * 09 08 2010 cp.wu + * NULL + * use static memory pool for storing IEs of scanning result. + * + * 09 07 2010 yuche.tsai + * NULL + * When indicate scan result, append IE buffer information in the scan result. + * + * 09 03 2010 yuche.tsai + * NULL + * 1. Update Beacon RX count when running SLT. + * 2. Ignore Beacon when running SLT, would not update information from Beacon. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 31 2010 kevin.huang + * NULL + * Use LINK LIST operation to process SCAN result + * + * 08 29 2010 yuche.tsai + * NULL + * 1. Fix P2P Descriptor List to be a link list, to avoid link corrupt after Bss Descriptor Free. + * 2.. Fix P2P Device Name Length BE issue. + * + * 08 23 2010 yuche.tsai + * NULL + * Add P2P Device Found Indication to supplicant + * + * 08 20 2010 cp.wu + * NULL + * reset BSS_DESC_T variables before parsing IE due to peer might have been reconfigured. + * + * 08 20 2010 yuche.tsai + * NULL + * Workaround for P2P Descriptor Infinite loop issue. + * + * 08 16 2010 cp.wu + * NULL + * Replace CFG_SUPPORT_BOW by CFG_ENABLE_BT_OVER_WIFI. + * There is no CFG_SUPPORT_BOW in driver domain source. + * + * 08 16 2010 yuche.tsai + * NULL + * Modify code of processing Probe Resonse frame for P2P. + * + * 08 12 2010 yuche.tsai + * NULL + * Add function to get P2P descriptor of BSS descriptor directly. + * + * 08 11 2010 yuche.tsai + * NULL + * Modify Scan result processing for P2P module. + * + * 08 05 2010 yuche.tsai + * NULL + * Update P2P Device Discovery result add function. + * + * 08 03 2010 cp.wu + * NULL + * surpress compilation warning. + * + * 07 26 2010 yuche.tsai + * + * Add support for Probe Request & Response parsing. + * + * 07 21 2010 cp.wu + * + * 1) change BG_SCAN to ONLINE_SCAN for consistent term + * 2) only clear scanning result when scan is permitted to do + * + * 07 21 2010 yuche.tsai + * + * Fix compile error for SCAN module while disabling P2P feature. + * + * 07 21 2010 yuche.tsai + * + * Add P2P Scan & Scan Result Parsing & Saving. + * + * 07 19 2010 wh.su + * + * update for security supporting. + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * Add Ad-Hoc support to AIS-FSM + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * SCN module is now able to handle multiple concurrent scanning requests + * + * 07 15 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * driver no longer generates probe request frames + * + * 07 14 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * remove timer in DRV-SCN. + * + * 07 09 2010 cp.wu + * + * 1) separate AIS_FSM state for two kinds of scanning. (OID triggered scan, and scan-for-connection) + * 2) eliminate PRE_BSS_DESC_T, Beacon/PrebResp is now parsed in single pass + * 3) implment DRV-SCN module, currently only accepts single scan request, other request will be directly dropped by returning BUSY + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * take use of RLM module for parsing/generating HT IEs for 11n capability + * + * 07 05 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) ignore RSN checking when RSN is not turned on. + * 2) set STA-REC deactivation callback as NULL + * 3) add variable initialization API based on PHY configuration + * + * 07 05 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * correct BSS_DESC_T initialization after allocated. + * + * 07 02 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) for event packet, no need to fill RFB. + * 2) when wlanAdapterStart() failed, no need to initialize state machines + * 3) after Beacon/ProbeResp parsing, corresponding BSS_DESC_T should be marked as IE-parsed + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add scan uninitialization procedure + * + * 06 30 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * if beacon/probe-resp is received in 2.4GHz bands and there is ELEM_ID_DS_PARAM_SET IE available, + * trust IE instead of RMAC information + * + * 06 29 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) sync to. CMD/EVENT document v0.03 + * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. + * 3) send command packet to indicate FW-PM after + * a) 1st beacon is received after AIS has connected to an AP + * b) IBSS-ALONE has been created + * c) IBSS-MERGE has occured + * + * 06 28 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * send MMPDU in basic rate. + * + * 06 25 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * modify Beacon/ProbeResp to complete parsing, + * because host software has looser memory usage restriction + * + * 06 23 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * integrate . + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * comment out RLM APIs by CFG_RLM_MIGRATION. + * + * 06 21 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Update P2P Function call. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * RSN/PRIVACY compilation flag awareness correction + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * specify correct value for management frames. + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration from MT6620 firmware. + * + * 06 17 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Fix compile error when enable P2P function. + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * correct when ADHOC support is turned on. + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add scan.c. + * + * 06 04 2010 george.huang + * [BORA00000678][MT6620]WiFi LP integration + * [PM] Support U-APSD for STA mode + * + * 05 28 2010 wh.su + * [BORA00000680][MT6620] Support the statistic for Microsoft os query + * adding the TKIP disallow join a HT AP code. + * + * 05 14 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add more chance of JOIN retry for BG_SCAN + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 04 29 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * adjsut the pre-authentication code. + * + * 04 27 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add Set Slot Time and Beacon Timeout Support for AdHoc Mode + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW + * + * 04 19 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * Add Beacon Timeout Support and will send Null frame to diagnose connection + * + * 04 13 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add new HW CH macro support + * + * 04 06 2010 wh.su + * [BORA00000680][MT6620] Support the statistic for Microsoft os query + * fixed the firmware return the broadcast frame at wrong tc. + * + * 03 29 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * let the rsn wapi IE always parsing. + * + * 03 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Not carry HT cap when being associated with b/g only AP + * + * 03 18 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Solve the compile warning for 'return non-void' function + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 03 10 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * + * * * * * * * * * * * * * * * * Add Channel Manager for arbitration of JOIN and SCAN Req + * + * 03 03 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * move the AIS specific variable for security to AIS specific structure. + * + * 03 01 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * Refine the variable and parameter for security. + * + * 02 26 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Fix No PKT_INFO_T issue + * + * 02 26 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Update outgoing ProbeRequest Frame's TX data rate + * + * 02 23 2010 wh.su + * [BORA00000592][MT6620 Wi-Fi] Adding the security related code for driver + * refine the scan procedure, reduce the WPA and WAPI IE parsing, and move the parsing to the time for join. + * + * 02 23 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add support scan channel 1~14 and update scan result's frequency infou1rwduu`wvpghlqg|n`slk+mpdkb + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * 01 27 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * add and fixed some security function. + * + * 01 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support protection and bandwidth switch + * + * 01 20 2010 kevin.huang + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Add PHASE_2_INTEGRATION_WORK_AROUND and CFG_SUPPORT_BCM flags + * + * 01 11 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add Deauth and Disassoc Handler + * + * 01 08 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * + * Refine Beacon processing, add read RF channel from RX Status + * + * 01 04 2010 tehuang.liu + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * For working out the first connection Chariot-verified version + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Dec 12 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Modify u2EstimatedExtraIELen for probe request + * + * Dec 9 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add HT cap IE to probe request + * + * Dec 7 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix lint warning + * + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Update the process of SCAN Result by adding more Phy Attributes + * + * Dec 1 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adjust the function and code for meet the new define + * + * Nov 30 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Rename u4RSSI to i4RSSI + * + * Nov 30 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Report event of scan result to host + * + * Nov 26 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix SCAN Record update + * + * Nov 24 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Revise MGMT Handler with Retain Status and Integrate with TXM + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add (Ext)Support Rate Set IE to ProbeReq + * + * Nov 20 2009 mtk02468 + * [BORA00000337] To check in codes for FPGA emulation + * Removed the use of SW_RFB->u2FrameLength + * + * Nov 20 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix uninitial aucMacAddress[] for ProbeReq + * + * Nov 16 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add scanSearchBssDescByPolicy() + * + * Nov 5 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add Send Probe Request Frame + * + * Oct 30 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define REPLICATED_BEACON_TIME_THRESHOLD (3000) +#define REPLICATED_BEACON_FRESH_PERIOD (10000) +#define REPLICATED_BEACON_STRENGTH_THRESHOLD (32) + +#define ROAMING_NO_SWING_RCPI_STEP (10) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used by SCN to initialize its variables +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +scnInit ( + IN P_ADAPTER_T prAdapter + ) +{ + P_SCAN_INFO_T prScanInfo; + P_BSS_DESC_T prBSSDesc; + PUINT_8 pucBSSBuff; + UINT_32 i; + + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + pucBSSBuff = &prScanInfo->aucScanBuffer[0]; + + + DBGLOG(SCN, INFO, ("->scnInit()\n")); + + //4 <1> Reset STATE and Message List + prScanInfo->eCurrentState = SCAN_STATE_IDLE; + + prScanInfo->rLastScanCompletedTime = (OS_SYSTIME)0; + + LINK_INITIALIZE(&prScanInfo->rPendingMsgList); + + + //4 <2> Reset link list of BSS_DESC_T + kalMemZero((PVOID) pucBSSBuff, SCN_MAX_BUFFER_SIZE); + + LINK_INITIALIZE(&prScanInfo->rFreeBSSDescList); + LINK_INITIALIZE(&prScanInfo->rBSSDescList); + + for (i = 0; i < CFG_MAX_NUM_BSS_LIST; i++) { + + prBSSDesc = (P_BSS_DESC_T)pucBSSBuff; + + LINK_INSERT_TAIL(&prScanInfo->rFreeBSSDescList, &prBSSDesc->rLinkEntry); + + pucBSSBuff += ALIGN_4(sizeof(BSS_DESC_T)); + } + /* Check if the memory allocation consist with this initialization function */ + ASSERT(((UINT_32)pucBSSBuff - (UINT_32)&prScanInfo->aucScanBuffer[0]) == SCN_MAX_BUFFER_SIZE); + + /* reset freest channel information */ + prScanInfo->fgIsSparseChannelValid = FALSE; + + return; +} /* end of scnInit() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used by SCN to uninitialize its variables +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +scnUninit ( + IN P_ADAPTER_T prAdapter + ) +{ + P_SCAN_INFO_T prScanInfo; + + + ASSERT(prAdapter); + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + DBGLOG(SCN, INFO, ("->scnUninit()\n")); + + //4 <1> Reset STATE and Message List + prScanInfo->eCurrentState = SCAN_STATE_IDLE; + + prScanInfo->rLastScanCompletedTime = (OS_SYSTIME)0; + + /* NOTE(Kevin): Check rPendingMsgList ? */ + + //4 <2> Reset link list of BSS_DESC_T + LINK_INITIALIZE(&prScanInfo->rFreeBSSDescList); + LINK_INITIALIZE(&prScanInfo->rBSSDescList); + + return; +} /* end of scnUninit() */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Find the corresponding BSS Descriptor according to given BSSID +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] aucBSSID Given BSSID. +* +* @return Pointer to BSS Descriptor, if found. NULL, if not found +*/ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T +scanSearchBssDescByBssid ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 aucBSSID[] + ) +{ + return scanSearchBssDescByBssidAndSsid(prAdapter, + aucBSSID, + FALSE, + NULL); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Find the corresponding BSS Descriptor according to given BSSID +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] aucBSSID Given BSSID. +* @param[in] fgCheckSsid Need to check SSID or not. (for multiple SSID with single BSSID cases) +* @param[in] prSsid Specified SSID +* +* @return Pointer to BSS Descriptor, if found. NULL, if not found +*/ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T +scanSearchBssDescByBssidAndSsid ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 aucBSSID[], + IN BOOLEAN fgCheckSsid, + IN P_PARAM_SSID_T prSsid + ) +{ + P_SCAN_INFO_T prScanInfo; + P_LINK_T prBSSDescList; + P_BSS_DESC_T prBssDesc; + P_BSS_DESC_T prDstBssDesc = (P_BSS_DESC_T)NULL; + + + ASSERT(prAdapter); + ASSERT(aucBSSID); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + prBSSDescList = &prScanInfo->rBSSDescList; + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { + + if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, aucBSSID)) { + if(fgCheckSsid == FALSE || prSsid == NULL) { + return prBssDesc; + } + else { + if(EQUAL_SSID(prBssDesc->aucSSID, + prBssDesc->ucSSIDLen, + prSsid->aucSsid, + prSsid->u4SsidLen)) { + return prBssDesc; + } + else if(prDstBssDesc == NULL && prBssDesc->fgIsHiddenSSID == TRUE) { + prDstBssDesc = prBssDesc; + } + else { + /* 20120206 frog: Equal BSSID but not SSID, SSID not hidden, SSID must be updated. */ + COPY_SSID(prBssDesc->aucSSID, + prBssDesc->ucSSIDLen, + prSsid->aucSsid, + prSsid->u4SsidLen); + return prBssDesc; + } + + } + } + } + + return prDstBssDesc; + +} /* end of scanSearchBssDescByBssid() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Find the corresponding BSS Descriptor according to given Transmitter Address. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] aucSrcAddr Given Source Address(TA). +* +* @return Pointer to BSS Descriptor, if found. NULL, if not found +*/ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T +scanSearchBssDescByTA ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 aucSrcAddr[] + ) +{ + return scanSearchBssDescByTAAndSsid(prAdapter, + aucSrcAddr, + FALSE, + NULL); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Find the corresponding BSS Descriptor according to given Transmitter Address. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] aucSrcAddr Given Source Address(TA). +* @param[in] fgCheckSsid Need to check SSID or not. (for multiple SSID with single BSSID cases) +* @param[in] prSsid Specified SSID +* +* @return Pointer to BSS Descriptor, if found. NULL, if not found +*/ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T +scanSearchBssDescByTAAndSsid ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 aucSrcAddr[], + IN BOOLEAN fgCheckSsid, + IN P_PARAM_SSID_T prSsid + ) +{ + P_SCAN_INFO_T prScanInfo; + P_LINK_T prBSSDescList; + P_BSS_DESC_T prBssDesc; + P_BSS_DESC_T prDstBssDesc = (P_BSS_DESC_T)NULL; + + + ASSERT(prAdapter); + ASSERT(aucSrcAddr); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + prBSSDescList = &prScanInfo->rBSSDescList; + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { + + if (EQUAL_MAC_ADDR(prBssDesc->aucSrcAddr, aucSrcAddr)) { + if(fgCheckSsid == FALSE || prSsid == NULL) { + return prBssDesc; + } + else { + if(EQUAL_SSID(prBssDesc->aucSSID, + prBssDesc->ucSSIDLen, + prSsid->aucSsid, + prSsid->u4SsidLen)) { + return prBssDesc; + } + else if(prDstBssDesc == NULL && prBssDesc->fgIsHiddenSSID == TRUE) { + prDstBssDesc = prBssDesc; + } + } + } + } + + return prDstBssDesc; + +} /* end of scanSearchBssDescByTA() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Find the corresponding BSS Descriptor according to +* given eBSSType, BSSID and Transmitter Address +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] eBSSType BSS Type of incoming Beacon/ProbeResp frame. +* @param[in] aucBSSID Given BSSID of Beacon/ProbeResp frame. +* @param[in] aucSrcAddr Given source address (TA) of Beacon/ProbeResp frame. +* +* @return Pointer to BSS Descriptor, if found. NULL, if not found +*/ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T +scanSearchExistingBssDesc ( + IN P_ADAPTER_T prAdapter, + IN ENUM_BSS_TYPE_T eBSSType, + IN UINT_8 aucBSSID[], + IN UINT_8 aucSrcAddr[] + ) +{ + return scanSearchExistingBssDescWithSsid(prAdapter, + eBSSType, + aucBSSID, + aucSrcAddr, + FALSE, + NULL); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Find the corresponding BSS Descriptor according to +* given eBSSType, BSSID and Transmitter Address +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] eBSSType BSS Type of incoming Beacon/ProbeResp frame. +* @param[in] aucBSSID Given BSSID of Beacon/ProbeResp frame. +* @param[in] aucSrcAddr Given source address (TA) of Beacon/ProbeResp frame. +* @param[in] fgCheckSsid Need to check SSID or not. (for multiple SSID with single BSSID cases) +* @param[in] prSsid Specified SSID +* +* @return Pointer to BSS Descriptor, if found. NULL, if not found +*/ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T +scanSearchExistingBssDescWithSsid ( + IN P_ADAPTER_T prAdapter, + IN ENUM_BSS_TYPE_T eBSSType, + IN UINT_8 aucBSSID[], + IN UINT_8 aucSrcAddr[], + IN BOOLEAN fgCheckSsid, + IN P_PARAM_SSID_T prSsid + ) +{ + P_SCAN_INFO_T prScanInfo; + P_BSS_DESC_T prBssDesc, prIBSSBssDesc; + + ASSERT(prAdapter); + ASSERT(aucSrcAddr); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + + switch (eBSSType) { + case BSS_TYPE_P2P_DEVICE: + fgCheckSsid = FALSE; + case BSS_TYPE_INFRASTRUCTURE: + case BSS_TYPE_BOW_DEVICE: + { + prBssDesc = scanSearchBssDescByBssidAndSsid(prAdapter, aucBSSID, fgCheckSsid, prSsid); + + /* if (eBSSType == prBssDesc->eBSSType) */ + + return prBssDesc; + } + + case BSS_TYPE_IBSS: + { + prIBSSBssDesc = scanSearchBssDescByBssidAndSsid(prAdapter, aucBSSID, fgCheckSsid, prSsid); + prBssDesc = scanSearchBssDescByTAAndSsid(prAdapter, aucSrcAddr, fgCheckSsid, prSsid); + + /* NOTE(Kevin): + * Rules to maintain the SCAN Result: + * For AdHoc - + * CASE I We have TA1(BSSID1), but it change its BSSID to BSSID2 + * -> Update TA1 entry's BSSID. + * CASE II We have TA1(BSSID1), and get TA1(BSSID1) again + * -> Update TA1 entry's contain. + * CASE III We have a SCAN result TA1(BSSID1), and TA2(BSSID2). Sooner or + * later, TA2 merge into TA1, we get TA2(BSSID1) + * -> Remove TA2 first and then replace TA1 entry's TA with TA2, Still have only one entry of BSSID. + * CASE IV We have a SCAN result TA1(BSSID1), and another TA2 also merge into BSSID1. + * -> Replace TA1 entry's TA with TA2, Still have only one entry. + * CASE V New IBSS + * -> Add this one to SCAN result. + */ + if (prBssDesc) { + if ((!prIBSSBssDesc) || // CASE I + (prBssDesc == prIBSSBssDesc)) { // CASE II + + return prBssDesc; + } + else { // CASE III + P_LINK_T prBSSDescList; + P_LINK_T prFreeBSSDescList; + + + prBSSDescList = &prScanInfo->rBSSDescList; + prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; + + /* Remove this BSS Desc from the BSS Desc list */ + LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); + + /* Return this BSS Desc to the free BSS Desc list. */ + LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); + + return prIBSSBssDesc; + } + } + + if (prIBSSBssDesc) { // CASE IV + + return prIBSSBssDesc; + } + + // CASE V + break; // Return NULL; + } + + default: + break; + } + + + return (P_BSS_DESC_T)NULL; + +} /* end of scanSearchExistingBssDesc() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Delete BSS Descriptors from current list according to given Remove Policy. +* +* @param[in] u4RemovePolicy Remove Policy. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +scanRemoveBssDescsByPolicy ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4RemovePolicy + ) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + P_SCAN_INFO_T prScanInfo; + P_LINK_T prBSSDescList; + P_LINK_T prFreeBSSDescList; + P_BSS_DESC_T prBssDesc; + + + ASSERT(prAdapter); + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prBSSDescList = &prScanInfo->rBSSDescList; + prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; + + //DBGLOG(SCN, TRACE, ("Before Remove - Number Of SCAN Result = %ld\n", + //prBSSDescList->u4NumElem)); + + if (u4RemovePolicy & SCN_RM_POLICY_TIMEOUT) { + P_BSS_DESC_T prBSSDescNext; + OS_SYSTIME rCurrentTime; + + + GET_CURRENT_SYSTIME(&rCurrentTime); + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, rLinkEntry, BSS_DESC_T) { + + if ((u4RemovePolicy & SCN_RM_POLICY_EXCLUDE_CONNECTED) && + (prBssDesc->fgIsConnected || prBssDesc->fgIsConnecting)) { + /* Don't remove the one currently we are connected. */ + continue; + } + + if (CHECK_FOR_TIMEOUT(rCurrentTime, prBssDesc->rUpdateTime, + SEC_TO_SYSTIME(SCN_BSS_DESC_REMOVE_TIMEOUT_SEC)) ) { + + //DBGLOG(SCN, TRACE, ("Remove TIMEOUT BSS DESC(%#x): MAC: "MACSTR", Current Time = %08lx, Update Time = %08lx\n", + //prBssDesc, MAC2STR(prBssDesc->aucBSSID), rCurrentTime, prBssDesc->rUpdateTime)); + + /* Remove this BSS Desc from the BSS Desc list */ + LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); +#if 0 //CFG_ENABLE_WIFI_DIRECT + if(prAdapter->fgIsP2PRegistered) { + ASSERT(prAdapter->rP2pFuncLkr.prScanRemoveP2pBssDesc); + prAdapter->rP2pFuncLkr.prScanRemoveP2pBssDesc(prAdapter, prBssDesc); + } +#endif + /* Return this BSS Desc to the free BSS Desc list. */ + LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); + } + } + } + else if (u4RemovePolicy & SCN_RM_POLICY_OLDEST_HIDDEN) { + P_BSS_DESC_T prBssDescOldest = (P_BSS_DESC_T)NULL; + + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { + + if ((u4RemovePolicy & SCN_RM_POLICY_EXCLUDE_CONNECTED) && + (prBssDesc->fgIsConnected || prBssDesc->fgIsConnecting)) { + /* Don't remove the one currently we are connected. */ + continue; + } + + if (!prBssDesc->fgIsHiddenSSID) { + continue; + } + + if (!prBssDescOldest) { /* 1st element */ + prBssDescOldest = prBssDesc; + continue; + } + + if (TIME_BEFORE(prBssDesc->rUpdateTime, prBssDescOldest->rUpdateTime)) { + prBssDescOldest = prBssDesc; + } + } + + if (prBssDescOldest) { + + //DBGLOG(SCN, TRACE, ("Remove OLDEST HIDDEN BSS DESC(%#x): MAC: "MACSTR", Update Time = %08lx\n", + //prBssDescOldest, MAC2STR(prBssDescOldest->aucBSSID), prBssDescOldest->rUpdateTime)); + + /* Remove this BSS Desc from the BSS Desc list */ + LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDescOldest); +#if 0 //CFG_ENABLE_WIFI_DIRECT + if(prAdapter->fgIsP2PRegistered) { + ASSERT(prAdapter->rP2pFuncLkr.prScanRemoveP2pBssDesc); + prAdapter->rP2pFuncLkr.prScanRemoveP2pBssDesc(prAdapter, prBssDescOldest); + } +#endif + /* Return this BSS Desc to the free BSS Desc list. */ + LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDescOldest->rLinkEntry); + } + } + else if (u4RemovePolicy & SCN_RM_POLICY_SMART_WEAKEST) { + P_BSS_DESC_T prBssDescWeakest = (P_BSS_DESC_T)NULL; + P_BSS_DESC_T prBssDescWeakestSameSSID = (P_BSS_DESC_T)NULL; + UINT_32 u4SameSSIDCount = 0; + + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { + + if ((u4RemovePolicy & SCN_RM_POLICY_EXCLUDE_CONNECTED) && + (prBssDesc->fgIsConnected || prBssDesc->fgIsConnecting)) { + /* Don't remove the one currently we are connected. */ + continue; + } + + if ((!prBssDesc->fgIsHiddenSSID) && + (EQUAL_SSID(prBssDesc->aucSSID, + prBssDesc->ucSSIDLen, + prConnSettings->aucSSID, + prConnSettings->ucSSIDLen))) { + + u4SameSSIDCount++; + + if (!prBssDescWeakestSameSSID) { + prBssDescWeakestSameSSID = prBssDesc; + } + else if (prBssDesc->ucRCPI < prBssDescWeakestSameSSID->ucRCPI) { + prBssDescWeakestSameSSID = prBssDesc; + } + } + + if (!prBssDescWeakest) { /* 1st element */ + prBssDescWeakest = prBssDesc; + continue; + } + + if (prBssDesc->ucRCPI < prBssDescWeakest->ucRCPI) { + prBssDescWeakest = prBssDesc; + } + + } + + if ((u4SameSSIDCount >= SCN_BSS_DESC_SAME_SSID_THRESHOLD) && + (prBssDescWeakestSameSSID)) { + prBssDescWeakest = prBssDescWeakestSameSSID; + } + + if (prBssDescWeakest) { + + //DBGLOG(SCN, TRACE, ("Remove WEAKEST BSS DESC(%#x): MAC: "MACSTR", Update Time = %08lx\n", + //prBssDescOldest, MAC2STR(prBssDescOldest->aucBSSID), prBssDescOldest->rUpdateTime)); + + /* Remove this BSS Desc from the BSS Desc list */ + LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDescWeakest); +#if 0 //CFG_ENABLE_WIFI_DIRECT + if(prAdapter->fgIsP2PRegistered) { + ASSERT(prAdapter->rP2pFuncLkr.prScanRemoveP2pBssDesc); + prAdapter->rP2pFuncLkr.prScanRemoveP2pBssDesc(prAdapter, prBssDescWeakest); + } + +#endif + /* Return this BSS Desc to the free BSS Desc list. */ + LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDescWeakest->rLinkEntry); + } + } + else if (u4RemovePolicy & SCN_RM_POLICY_ENTIRE) { + P_BSS_DESC_T prBSSDescNext; + + LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, rLinkEntry, BSS_DESC_T) { + + if ((u4RemovePolicy & SCN_RM_POLICY_EXCLUDE_CONNECTED) && + (prBssDesc->fgIsConnected || prBssDesc->fgIsConnecting)) { + /* Don't remove the one currently we are connected. */ + continue; + } + + /* Remove this BSS Desc from the BSS Desc list */ + LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); +#if 0 //CFG_ENABLE_WIFI_DIRECT + if(prAdapter->fgIsP2PRegistered) { + ASSERT(prAdapter->rP2pFuncLkr.prScanRemoveP2pBssDesc); + prAdapter->rP2pFuncLkr.prScanRemoveP2pBssDesc(prAdapter, prBssDesc); + } +#endif + /* Return this BSS Desc to the free BSS Desc list. */ + LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); + } + + } + + return; + +} /* end of scanRemoveBssDescsByPolicy() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Delete BSS Descriptors from current list according to given BSSID. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] aucBSSID Given BSSID. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +scanRemoveBssDescByBssid ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 aucBSSID[] + ) +{ + P_SCAN_INFO_T prScanInfo; + P_LINK_T prBSSDescList; + P_LINK_T prFreeBSSDescList; + P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T)NULL; + P_BSS_DESC_T prBSSDescNext; + + + ASSERT(prAdapter); + ASSERT(aucBSSID); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prBSSDescList = &prScanInfo->rBSSDescList; + prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; + + /* Check if such BSS Descriptor exists in a valid list */ + LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, rLinkEntry, BSS_DESC_T) { + + if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, aucBSSID)) { + + /* Remove this BSS Desc from the BSS Desc list */ + LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); +#if 0 //CFG_ENABLE_WIFI_DIRECT + if(prAdapter->fgIsP2PRegistered) { + ASSERT(prAdapter->rP2pFuncLkr.prScanRemoveP2pBssDesc); + prAdapter->rP2pFuncLkr.prScanRemoveP2pBssDesc(prAdapter, prBssDesc); + } +#endif + + /* Return this BSS Desc to the free BSS Desc list. */ + LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); + + /* BSSID is not unique, so need to traverse whols link-list */ + } + } + + return; +} /* end of scanRemoveBssDescByBssid() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Delete BSS Descriptors from current list according to given band configuration +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] eBand Given band +* @param[in] eNetTypeIndex AIS - Remove IBSS/Infrastructure BSS +* BOW - Remove BOW BSS +* P2P - Remove P2P BSS +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +scanRemoveBssDescByBandAndNetwork ( + IN P_ADAPTER_T prAdapter, + IN ENUM_BAND_T eBand, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex + ) +{ + P_SCAN_INFO_T prScanInfo; + P_LINK_T prBSSDescList; + P_LINK_T prFreeBSSDescList; + P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T)NULL; + P_BSS_DESC_T prBSSDescNext; + BOOLEAN fgToRemove; + + ASSERT(prAdapter); + ASSERT(eBand <= BAND_NUM); + ASSERT(eNetTypeIndex <= NETWORK_TYPE_INDEX_NUM); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prBSSDescList = &prScanInfo->rBSSDescList; + prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; + + + if(eBand == BAND_NULL) { + return; /* no need to do anything, keep all scan result */ + } + + /* Check if such BSS Descriptor exists in a valid list */ + LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, rLinkEntry, BSS_DESC_T) { + fgToRemove = FALSE; + + if(prBssDesc->eBand == eBand) { + switch (eNetTypeIndex) { + case NETWORK_TYPE_AIS_INDEX: + if((prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE) + || (prBssDesc->eBSSType == BSS_TYPE_IBSS)) { + fgToRemove = TRUE; + } + break; + + case NETWORK_TYPE_P2P_INDEX: + if(prBssDesc->eBSSType == BSS_TYPE_P2P_DEVICE) { + fgToRemove = TRUE; + } + break; + + case NETWORK_TYPE_BOW_INDEX: + if(prBssDesc->eBSSType == BSS_TYPE_BOW_DEVICE) { + fgToRemove = TRUE; + } + break; + + default: + ASSERT(0); + break; + } + } + + if(fgToRemove == TRUE) { + /* Remove this BSS Desc from the BSS Desc list */ + LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); +#if 0 //CFG_ENABLE_WIFI_DIRECT + if(prAdapter->fgIsP2PRegistered) { + ASSERT(prAdapter->rP2pFuncLkr.prScanRemoveP2pBssDesc); + prAdapter->rP2pFuncLkr.prScanRemoveP2pBssDesc(prAdapter, prBssDesc); + } +#endif + + /* Return this BSS Desc to the free BSS Desc list. */ + LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); + } + } + + return; +} /* end of scanRemoveBssDescByBand() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Clear the CONNECTION FLAG of a specified BSS Descriptor. +* +* @param[in] aucBSSID Given BSSID. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +scanRemoveConnFlagOfBssDescByBssid ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 aucBSSID[] + ) +{ + P_SCAN_INFO_T prScanInfo; + P_LINK_T prBSSDescList; + P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T)NULL; + + + ASSERT(prAdapter); + ASSERT(aucBSSID); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prBSSDescList = &prScanInfo->rBSSDescList; + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { + + if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, aucBSSID)) { + prBssDesc->fgIsConnected = FALSE; + prBssDesc->fgIsConnecting = FALSE; + + /* BSSID is not unique, so need to traverse whols link-list */ + } + } + + return; + +} /* end of scanRemoveConnectionFlagOfBssDescByBssid() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Allocate new BSS_DESC_T +* +* @param[in] prAdapter Pointer to the Adapter structure. +* +* @return Pointer to BSS Descriptor, if has free space. NULL, if has no space. +*/ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T +scanAllocateBssDesc ( + IN P_ADAPTER_T prAdapter + ) +{ + P_SCAN_INFO_T prScanInfo; + P_LINK_T prFreeBSSDescList; + P_BSS_DESC_T prBssDesc; + + + ASSERT(prAdapter); + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; + + LINK_REMOVE_HEAD(prFreeBSSDescList, prBssDesc, P_BSS_DESC_T); + + if (prBssDesc) { + P_LINK_T prBSSDescList; + + kalMemZero(prBssDesc, sizeof(BSS_DESC_T)); + +#if CFG_ENABLE_WIFI_DIRECT + LINK_INITIALIZE(&(prBssDesc->rP2pDeviceList)); + prBssDesc->fgIsP2PPresent = FALSE; +#endif /* CFG_ENABLE_WIFI_DIRECT */ + + prBSSDescList = &prScanInfo->rBSSDescList; + + /* NOTE(Kevin): In current design, this new empty BSS_DESC_T will be + * inserted to BSSDescList immediately. + */ + LINK_INSERT_TAIL(prBSSDescList, &prBssDesc->rLinkEntry); + } + + return prBssDesc; + +} /* end of scanAllocateBssDesc() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This API parses Beacon/ProbeResp frame and insert extracted BSS_DESC_T +* with IEs into prAdapter->rWifiVar.rScanInfo.aucScanBuffer +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to the receiving frame buffer. +* +* @return Pointer to BSS Descriptor +* NULL if the Beacon/ProbeResp frame is invalid +*/ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T +scanAddToBssDesc ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ) +{ + P_BSS_DESC_T prBssDesc = NULL; + UINT_16 u2CapInfo; + ENUM_BSS_TYPE_T eBSSType = BSS_TYPE_INFRASTRUCTURE; + + PUINT_8 pucIE; + UINT_16 u2IELength; + UINT_16 u2Offset = 0; + + P_WLAN_BEACON_FRAME_T prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T)NULL; + P_IE_SSID_T prIeSsid = (P_IE_SSID_T)NULL; + P_IE_SUPPORTED_RATE_T prIeSupportedRate = (P_IE_SUPPORTED_RATE_T)NULL; + P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate = (P_IE_EXT_SUPPORTED_RATE_T)NULL; + P_HIF_RX_HEADER_T prHifRxHdr; + UINT_8 ucHwChannelNum = 0; + UINT_8 ucIeDsChannelNum = 0; + UINT_8 ucIeHtChannelNum = 0; + BOOLEAN fgIsValidSsid = FALSE, fgEscape = FALSE; + PARAM_SSID_T rSsid; + UINT_64 u8Timestamp; + + UINT_32 i; + UINT_8 ucSSIDChar; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T)prSwRfb->pvHeader; + + WLAN_GET_FIELD_16(&prWlanBeaconFrame->u2CapInfo, &u2CapInfo); + WLAN_GET_FIELD_64(&prWlanBeaconFrame->au4Timestamp[0], &u8Timestamp); + + // decide BSS type + switch (u2CapInfo & CAP_INFO_BSS_TYPE) { + case CAP_INFO_ESS: + /* It can also be Group Owner of P2P Group. */ + eBSSType = BSS_TYPE_INFRASTRUCTURE; + break; + + case CAP_INFO_IBSS: + eBSSType = BSS_TYPE_IBSS; + break; + case 0: + /* The P2P Device shall set the ESS bit of the Capabilities field in the Probe Response fame to 0 and IBSS bit to 0. (3.1.2.1.1) */ + eBSSType = BSS_TYPE_P2P_DEVICE; + break; + +#if CFG_ENABLE_BT_OVER_WIFI + // @TODO: add rule to identify BOW beacons +#endif + + default: + return NULL; + } + + //4 <1.1> Pre-parse SSID IE + pucIE = prWlanBeaconFrame->aucInfoElem; + u2IELength = (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - + (UINT_16)OFFSET_OF(WLAN_BEACON_FRAME_BODY_T, aucInfoElem[0]); + + if (u2IELength > CFG_IE_BUFFER_SIZE) { + u2IELength = CFG_IE_BUFFER_SIZE; + } + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_SSID: + if (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID) { + ucSSIDChar = '\0'; + + /* D-Link DWL-900AP+ */ + if (IE_LEN(pucIE) == 0) { + fgIsValidSsid = FALSE; + } + /* Cisco AP1230A - (IE_LEN(pucIE) == 1) && (SSID_IE(pucIE)->aucSSID[0] == '\0') */ + /* Linksys WRK54G/ASUS WL520g - (IE_LEN(pucIE) == n) && (SSID_IE(pucIE)->aucSSID[0~(n-1)] == '\0') */ + else { + for (i = 0; i < IE_LEN(pucIE); i++) { + ucSSIDChar |= SSID_IE(pucIE)->aucSSID[i]; + } + + if (ucSSIDChar) { + fgIsValidSsid = TRUE; + } + } + + /* Update SSID to BSS Descriptor only if SSID is not hidden. */ + if (fgIsValidSsid == TRUE) { + COPY_SSID(rSsid.aucSsid, + rSsid.u4SsidLen, + SSID_IE(pucIE)->aucSSID, + SSID_IE(pucIE)->ucLength); + } + } + fgEscape = TRUE; + break; + default: + break; + } + + if(fgEscape == TRUE) { + break; + } + } + + + //4 <1.2> Replace existing BSS_DESC_T or allocate a new one + prBssDesc = scanSearchExistingBssDescWithSsid(prAdapter, + eBSSType, + (PUINT_8)prWlanBeaconFrame->aucBSSID, + (PUINT_8)prWlanBeaconFrame->aucSrcAddr, + fgIsValidSsid, + fgIsValidSsid == TRUE ? &rSsid : NULL); + + if (prBssDesc == (P_BSS_DESC_T)NULL) { + do { + //4 <1.2.1> First trial of allocation + prBssDesc = scanAllocateBssDesc(prAdapter); + if (prBssDesc) { + break; + } + + //4 <1.2.2> Hidden is useless, remove the oldest hidden ssid. (for passive scan) + scanRemoveBssDescsByPolicy(prAdapter, + (SCN_RM_POLICY_EXCLUDE_CONNECTED | SCN_RM_POLICY_OLDEST_HIDDEN)); + + //4 <1.2.3> Second tail of allocation + prBssDesc = scanAllocateBssDesc(prAdapter); + if (prBssDesc) { + break; + } + + //4 <1.2.4> Remove the weakest one + /* If there are more than half of BSS which has the same ssid as connection + * setting, remove the weakest one from them. + * Else remove the weakest one. + */ + scanRemoveBssDescsByPolicy(prAdapter, + (SCN_RM_POLICY_EXCLUDE_CONNECTED | SCN_RM_POLICY_SMART_WEAKEST)); + + //4 <1.2.5> reallocation + prBssDesc = scanAllocateBssDesc(prAdapter); + if (prBssDesc) { + break; + } + + //4 <1.2.6> no space, should not happen + //ASSERT(0); // still no space available ? + DBGLOG(SCN, WARN, ("BSS_DESC allocation failure\n")); + + return NULL; + + } + while(FALSE); + + } + else { + OS_SYSTIME rCurrentTime; + + // WCXRP00000091 + // if the received strength is much weaker than the original one, + // ignore it due to it might be received on the folding frequency + + GET_CURRENT_SYSTIME(&rCurrentTime); + + prBssDesc->eBSSType = eBSSType; + + if(HIF_RX_HDR_GET_CHNL_NUM(prSwRfb->prHifRxHdr) != prBssDesc->ucChannelNum && + prBssDesc->ucRCPI > prSwRfb->prHifRxHdr->ucRcpi) { + + // for signal strength is too much weaker and previous beacon is not stale + if((prBssDesc->ucRCPI - prSwRfb->prHifRxHdr->ucRcpi) >= REPLICATED_BEACON_STRENGTH_THRESHOLD && + rCurrentTime - prBssDesc->rUpdateTime <= REPLICATED_BEACON_FRESH_PERIOD) { + return prBssDesc; + } + // for received beacons too close in time domain + else if(rCurrentTime - prBssDesc->rUpdateTime <= REPLICATED_BEACON_TIME_THRESHOLD) { + return prBssDesc; + } + } + + /* if Timestamp has been reset, re-generate BSS DESC 'cause AP should have reset itself */ + if(prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE && u8Timestamp < prBssDesc->u8TimeStamp.QuadPart) { + scanRemoveBssDescByBssid(prAdapter, prBssDesc->aucBSSID); + + prBssDesc = scanAllocateBssDesc(prAdapter); + if (!prBssDesc) { + return NULL; + } + } + } + + /* NOTE: Keep consistency of Scan Record during JOIN process */ + if (prBssDesc->fgIsConnecting) { + return prBssDesc; + } + + //4 <2> Get information from Fixed Fields + prBssDesc->eBSSType = eBSSType; /* Update the latest BSS type information. */ + + COPY_MAC_ADDR(prBssDesc->aucSrcAddr, prWlanBeaconFrame->aucSrcAddr); + + COPY_MAC_ADDR(prBssDesc->aucBSSID, prWlanBeaconFrame->aucBSSID); + + prBssDesc->u8TimeStamp.QuadPart = u8Timestamp; + + WLAN_GET_FIELD_16(&prWlanBeaconFrame->u2BeaconInterval, &prBssDesc->u2BeaconInterval); + + prBssDesc->u2CapInfo = u2CapInfo; + + + //4 <2.1> Retrieve IEs for later parsing + u2IELength = (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - + (UINT_16)OFFSET_OF(WLAN_BEACON_FRAME_BODY_T, aucInfoElem[0]); + + if (u2IELength > CFG_IE_BUFFER_SIZE) { + u2IELength = CFG_IE_BUFFER_SIZE; + prBssDesc->fgIsIEOverflow = TRUE; + } + else { + prBssDesc->fgIsIEOverflow = FALSE; + } + prBssDesc->u2IELength = u2IELength; + + kalMemCopy(prBssDesc->aucIEBuf, prWlanBeaconFrame->aucInfoElem, u2IELength); + + //4 <2.2> reset prBssDesc variables in case that AP has been reconfigured + prBssDesc->fgIsERPPresent = FALSE; + prBssDesc->fgIsHTPresent = FALSE; + prBssDesc->eSco = CHNL_EXT_SCN; + prBssDesc->fgIEWAPI = FALSE; +#if CFG_RSN_MIGRATION + prBssDesc->fgIERSN = FALSE; +#endif +#if CFG_PRIVACY_MIGRATION + prBssDesc->fgIEWPA = FALSE; +#endif + + + //4 <3.1> Full IE parsing on SW_RFB_T + pucIE = prWlanBeaconFrame->aucInfoElem; + + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + + switch (IE_ID(pucIE)) { + case ELEM_ID_SSID: + if ((!prIeSsid) && /* NOTE(Kevin): for Atheros IOT #1 */ + (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) { + BOOLEAN fgIsHiddenSSID = FALSE; + ucSSIDChar = '\0'; + + + prIeSsid = (P_IE_SSID_T)pucIE; + + /* D-Link DWL-900AP+ */ + if (IE_LEN(pucIE) == 0) { + fgIsHiddenSSID = TRUE; + } + /* Cisco AP1230A - (IE_LEN(pucIE) == 1) && (SSID_IE(pucIE)->aucSSID[0] == '\0') */ + /* Linksys WRK54G/ASUS WL520g - (IE_LEN(pucIE) == n) && (SSID_IE(pucIE)->aucSSID[0~(n-1)] == '\0') */ + else { + for (i = 0; i < IE_LEN(pucIE); i++) { + ucSSIDChar |= SSID_IE(pucIE)->aucSSID[i]; + } + + if (!ucSSIDChar) { + fgIsHiddenSSID = TRUE; + } + } + + /* Update SSID to BSS Descriptor only if SSID is not hidden. */ + if (!fgIsHiddenSSID) { + COPY_SSID(prBssDesc->aucSSID, + prBssDesc->ucSSIDLen, + SSID_IE(pucIE)->aucSSID, + SSID_IE(pucIE)->ucLength); + } + + } + break; + + case ELEM_ID_SUP_RATES: + /* NOTE(Kevin): Buffalo WHR-G54S's supported rate set IE exceed 8. + * IE_LEN(pucIE) == 12, "1(B), 2(B), 5.5(B), 6(B), 9(B), 11(B), + * 12(B), 18(B), 24(B), 36(B), 48(B), 54(B)" + */ + /* TP-LINK will set extra and incorrect ie with ELEM_ID_SUP_RATES */ + if ((!prIeSupportedRate) && (IE_LEN(pucIE) <= RATE_NUM)) { + prIeSupportedRate = SUP_RATES_IE(pucIE); + } + break; + + case ELEM_ID_DS_PARAM_SET: + if (IE_LEN(pucIE) == ELEM_MAX_LEN_DS_PARAMETER_SET) { + ucIeDsChannelNum = DS_PARAM_IE(pucIE)->ucCurrChnl; + } + break; + + case ELEM_ID_TIM: + if (IE_LEN(pucIE) <= ELEM_MAX_LEN_TIM) { + prBssDesc->ucDTIMPeriod = TIM_IE(pucIE)->ucDTIMPeriod; + } + break; + + case ELEM_ID_IBSS_PARAM_SET: + if (IE_LEN(pucIE) == ELEM_MAX_LEN_IBSS_PARAMETER_SET){ + prBssDesc->u2ATIMWindow = IBSS_PARAM_IE(pucIE)->u2ATIMWindow; + } + break; + +#if 0 //CFG_SUPPORT_802_11D + case ELEM_ID_COUNTRY_INFO: + prBssDesc->prIECountry = (P_IE_COUNTRY_T)pucIE; + break; +#endif + + case ELEM_ID_ERP_INFO: + if (IE_LEN(pucIE) == ELEM_MAX_LEN_ERP) { + prBssDesc->fgIsERPPresent = TRUE; + } + break; + + case ELEM_ID_EXTENDED_SUP_RATES: + if (!prIeExtSupportedRate) { + prIeExtSupportedRate = EXT_SUP_RATES_IE(pucIE); + } + break; + +#if CFG_RSN_MIGRATION + case ELEM_ID_RSN: + if (rsnParseRsnIE(prAdapter, RSN_IE(pucIE), &prBssDesc->rRSNInfo)) { + prBssDesc->fgIERSN = TRUE; + prBssDesc->u2RsnCap = prBssDesc->rRSNInfo.u2RsnCap; + if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2) { + rsnCheckPmkidCache(prAdapter, prBssDesc); + } + } + break; +#endif + + case ELEM_ID_HT_CAP: + prBssDesc->fgIsHTPresent = TRUE; + break; + + case ELEM_ID_HT_OP: + if (IE_LEN(pucIE) != (sizeof(IE_HT_OP_T) - 2)) { + break; + } + + if ((((P_IE_HT_OP_T) pucIE)->ucInfo1 & HT_OP_INFO1_SCO) != CHNL_EXT_RES) { + prBssDesc->eSco = (ENUM_CHNL_EXT_T) + (((P_IE_HT_OP_T) pucIE)->ucInfo1 & HT_OP_INFO1_SCO); + } + ucIeHtChannelNum = ((P_IE_HT_OP_T) pucIE)->ucPrimaryChannel; + + break; + +#if CFG_SUPPORT_WAPI + case ELEM_ID_WAPI: + if (wapiParseWapiIE(WAPI_IE(pucIE), &prBssDesc->rIEWAPI)) { + prBssDesc->fgIEWAPI = TRUE; + } + break; +#endif + + case ELEM_ID_VENDOR: // ELEM_ID_P2P, ELEM_ID_WMM + { + UINT_8 ucOuiType; + UINT_16 u2SubTypeVersion; +#if CFG_PRIVACY_MIGRATION + if (rsnParseCheckForWFAInfoElem(prAdapter, pucIE, &ucOuiType, &u2SubTypeVersion)) { + if ((ucOuiType == VENDOR_OUI_TYPE_WPA) && + (u2SubTypeVersion == VERSION_WPA)) { + + if (rsnParseWpaIE(prAdapter, WPA_IE(pucIE), &prBssDesc->rWPAInfo)) { + prBssDesc->fgIEWPA = TRUE; + } + } + } +#endif + +#if CFG_ENABLE_WIFI_DIRECT + if(prAdapter->fgIsP2PRegistered) { + ASSERT(prAdapter->rP2pFuncLkr.prP2pParseCheckForP2pInfoElem); + if (prAdapter->rP2pFuncLkr.prP2pParseCheckForP2pInfoElem(prAdapter, pucIE, &ucOuiType)) { + if (ucOuiType == VENDOR_OUI_TYPE_P2P) { + prBssDesc->fgIsP2PPresent = TRUE; + } + } + } +#endif /* CFG_ENABLE_WIFI_DIRECT */ + } + break; + + /* no default */ + } + } + + + //4 <3.2> Save information from IEs - SSID + /* Update Flag of Hidden SSID for used in SEARCH STATE. */ + + /* NOTE(Kevin): in current driver, the ucSSIDLen == 0 represent + * all cases of hidden SSID. + * If the fgIsHiddenSSID == TRUE, it means we didn't get the ProbeResp with + * valid SSID. + */ + if (prBssDesc->ucSSIDLen == 0) { + prBssDesc->fgIsHiddenSSID = TRUE; + } + else { + prBssDesc->fgIsHiddenSSID = FALSE; + } + + + //4 <3.3> Check rate information in related IEs. + if (prIeSupportedRate || prIeExtSupportedRate) { + rateGetRateSetFromIEs(prIeSupportedRate, + prIeExtSupportedRate, + &prBssDesc->u2OperationalRateSet, + &prBssDesc->u2BSSBasicRateSet, + &prBssDesc->fgIsUnknownBssBasicRate); + } + + + //4 <4> Update information from HIF RX Header + { + prHifRxHdr = prSwRfb->prHifRxHdr; + + ASSERT(prHifRxHdr); + + //4 <4.1> Get TSF comparison result + prBssDesc->fgIsLargerTSF = HIF_RX_HDR_GET_TCL_FLAG(prHifRxHdr); + + //4 <4.2> Get Band information + prBssDesc->eBand = HIF_RX_HDR_GET_RF_BAND(prHifRxHdr); + + //4 <4.2> Get channel and RCPI information + ucHwChannelNum = HIF_RX_HDR_GET_CHNL_NUM(prHifRxHdr); + + if (BAND_2G4 == prBssDesc->eBand) { + + /* Update RCPI if in right channel */ + if (ucIeDsChannelNum >= 1 && ucIeDsChannelNum <= 14) { + + // Receive Beacon/ProbeResp frame from adjacent channel. + if ((ucIeDsChannelNum == ucHwChannelNum) || + (prHifRxHdr->ucRcpi > prBssDesc->ucRCPI)) { + prBssDesc->ucRCPI = prHifRxHdr->ucRcpi; + } + + // trust channel information brought by IE + prBssDesc->ucChannelNum = ucIeDsChannelNum; + } + else if(ucIeHtChannelNum >= 1 && ucIeHtChannelNum <= 14) { + // Receive Beacon/ProbeResp frame from adjacent channel. + if ((ucIeHtChannelNum == ucHwChannelNum) || + (prHifRxHdr->ucRcpi > prBssDesc->ucRCPI)) { + prBssDesc->ucRCPI = prHifRxHdr->ucRcpi; + } + + // trust channel information brought by IE + prBssDesc->ucChannelNum = ucIeHtChannelNum; + } + else { + prBssDesc->ucRCPI = prHifRxHdr->ucRcpi; + + prBssDesc->ucChannelNum = ucHwChannelNum; + } + } + // 5G Band + else { + if(ucIeHtChannelNum >= 1 && ucIeHtChannelNum < 200) { + // Receive Beacon/ProbeResp frame from adjacent channel. + if ((ucIeHtChannelNum == ucHwChannelNum) || + (prHifRxHdr->ucRcpi > prBssDesc->ucRCPI)) { + prBssDesc->ucRCPI = prHifRxHdr->ucRcpi; + } + + // trust channel information brought by IE + prBssDesc->ucChannelNum = ucIeHtChannelNum; + } + else { + /* Always update RCPI */ + prBssDesc->ucRCPI = prHifRxHdr->ucRcpi; + + prBssDesc->ucChannelNum = ucHwChannelNum; + } + } + } + + + //4 <5> PHY type setting + prBssDesc->ucPhyTypeSet = 0; + + if (BAND_2G4 == prBssDesc->eBand) { + /* check if support 11n */ + if (prBssDesc->fgIsHTPresent) { + prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_HT; + } + + /* if not 11n only */ + if (!(prBssDesc->u2BSSBasicRateSet & RATE_SET_BIT_HT_PHY)) { + /* check if support 11g */ + if ((prBssDesc->u2OperationalRateSet & RATE_SET_OFDM) || + prBssDesc->fgIsERPPresent) { + prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_ERP; + } + + /* if not 11g only */ + if (!(prBssDesc->u2BSSBasicRateSet & RATE_SET_OFDM)) { + /* check if support 11b */ + if ((prBssDesc->u2OperationalRateSet & RATE_SET_HR_DSSS)) { + prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_HR_DSSS; + } + } + } + } + else { /* (BAND_5G == prBssDesc->eBande) */ + /* check if support 11n */ + if (prBssDesc->fgIsHTPresent) { + prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_HT; + } + + /* if not 11n only */ + if (!(prBssDesc->u2BSSBasicRateSet & RATE_SET_BIT_HT_PHY)) { + /* Support 11a definitely */ + prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_OFDM; + + ASSERT(!(prBssDesc->u2OperationalRateSet & RATE_SET_HR_DSSS)); + } + } + + + //4 <6> Update BSS_DESC_T's Last Update TimeStamp. + GET_CURRENT_SYSTIME(&prBssDesc->rUpdateTime); + + return prBssDesc; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Convert the Beacon or ProbeResp Frame in SW_RFB_T to scan result for query +* +* @param[in] prSwRfb Pointer to the receiving SW_RFB_T structure. +* +* @retval WLAN_STATUS_SUCCESS It is a valid Scan Result and been sent to the host. +* @retval WLAN_STATUS_FAILURE It is not a valid Scan Result. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +scanAddScanResult ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc, + IN P_SW_RFB_T prSwRfb + ) +{ + P_SCAN_INFO_T prScanInfo; + UINT_8 aucRatesEx[PARAM_MAX_LEN_RATES_EX]; + P_WLAN_BEACON_FRAME_T prWlanBeaconFrame; + PARAM_MAC_ADDRESS rMacAddr; + PARAM_SSID_T rSsid; + ENUM_PARAM_NETWORK_TYPE_T eNetworkType; + PARAM_802_11_CONFIG_T rConfiguration; + ENUM_PARAM_OP_MODE_T eOpMode; + UINT_8 ucRateLen = 0; + UINT_32 i; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + if (prBssDesc->eBand == BAND_2G4) { + if ((prBssDesc->u2OperationalRateSet & RATE_SET_OFDM) + || prBssDesc->fgIsERPPresent) { + eNetworkType = PARAM_NETWORK_TYPE_OFDM24; + } + else { + eNetworkType = PARAM_NETWORK_TYPE_DS; + } + } + else { + ASSERT(prBssDesc->eBand == BAND_5G); + eNetworkType = PARAM_NETWORK_TYPE_OFDM5; + } + + if(prBssDesc->eBSSType == BSS_TYPE_P2P_DEVICE) { + /* NOTE(Kevin): Not supported by WZC(TBD) */ + return WLAN_STATUS_FAILURE; + } + + prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T)prSwRfb->pvHeader; + COPY_MAC_ADDR(rMacAddr, prWlanBeaconFrame->aucBSSID); + COPY_SSID(rSsid.aucSsid, + rSsid.u4SsidLen, + prBssDesc->aucSSID, + prBssDesc->ucSSIDLen); + + rConfiguration.u4Length = sizeof(PARAM_802_11_CONFIG_T); + rConfiguration.u4BeaconPeriod = (UINT_32) prWlanBeaconFrame->u2BeaconInterval; + rConfiguration.u4ATIMWindow = prBssDesc->u2ATIMWindow; + rConfiguration.u4DSConfig = nicChannelNum2Freq(prBssDesc->ucChannelNum); + rConfiguration.rFHConfig.u4Length = sizeof(PARAM_802_11_CONFIG_FH_T); + + rateGetDataRatesFromRateSet(prBssDesc->u2OperationalRateSet, + 0, + aucRatesEx, + &ucRateLen); + + /* NOTE(Kevin): Set unused entries, if any, at the end of the array to 0. + * from OID_802_11_BSSID_LIST + */ + for (i = ucRateLen; i < sizeof(aucRatesEx) / sizeof(aucRatesEx[0]) ; i++) { + aucRatesEx[i] = 0; + } + + switch(prBssDesc->eBSSType) { + case BSS_TYPE_IBSS: + eOpMode = NET_TYPE_IBSS; + break; + + case BSS_TYPE_INFRASTRUCTURE: + case BSS_TYPE_P2P_DEVICE: + case BSS_TYPE_BOW_DEVICE: + default: + eOpMode = NET_TYPE_INFRA; + break; + } + + nicAddScanResult(prAdapter, + rMacAddr, + &rSsid, + prWlanBeaconFrame->u2CapInfo & CAP_INFO_PRIVACY ? 1 : 0, + RCPI_TO_dBm(prBssDesc->ucRCPI), + eNetworkType, + &rConfiguration, + eOpMode, + aucRatesEx, + prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen, + (PUINT_8)((UINT_32)(prSwRfb->pvHeader) + WLAN_MAC_MGMT_HEADER_LEN)); + + return WLAN_STATUS_SUCCESS; + +} /* end of scanAddScanResult() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Parse the content of given Beacon or ProbeResp Frame. +* +* @param[in] prSwRfb Pointer to the receiving SW_RFB_T structure. +* +* @retval WLAN_STATUS_SUCCESS if not report this SW_RFB_T to host +* @retval WLAN_STATUS_PENDING if report this SW_RFB_T to host as scan result +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +scanProcessBeaconAndProbeResp ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T)NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_BSS_INFO_T prAisBssInfo; + P_WLAN_BEACON_FRAME_T prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T)NULL; +#if CFG_SLT_SUPPORT + P_SLT_INFO_T prSltInfo = (P_SLT_INFO_T)NULL; +#endif + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + //4 <0> Ignore invalid Beacon Frame + if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < + (TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN)) { +#ifndef _lint + ASSERT(0); +#endif /* _lint */ + return rStatus; + } + +#if CFG_SLT_SUPPORT + prSltInfo = &prAdapter->rWifiVar.rSltInfo; + + if (prSltInfo->fgIsDUT) { + DBGLOG(P2P, INFO, ("\n\rBCN: RX\n")); + prSltInfo->u4BeaconReceiveCnt++; + return WLAN_STATUS_SUCCESS; + } + else { + return WLAN_STATUS_SUCCESS; + } +#endif + + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T)prSwRfb->pvHeader; + + //4 <1> Parse and add into BSS_DESC_T + prBssDesc = scanAddToBssDesc(prAdapter, prSwRfb); + + if (prBssDesc) { + + //4 <1.1> Beacon Change Detection for Connected BSS + if(prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED && + ((prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE && prConnSettings->eOPMode != NET_TYPE_IBSS) + || (prBssDesc->eBSSType == BSS_TYPE_IBSS && prConnSettings->eOPMode != NET_TYPE_INFRA)) && + EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAisBssInfo->aucBSSID) && + EQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, prAisBssInfo->aucSSID, prAisBssInfo->ucSSIDLen)) { + BOOLEAN fgNeedDisconnect = FALSE; + +#if CFG_SUPPORT_BEACON_CHANGE_DETECTION + // <1.1.2> check if supported rate differs + if(prAisBssInfo->u2OperationalRateSet != prBssDesc->u2OperationalRateSet) { + fgNeedDisconnect = TRUE; + } +#endif + + // <1.1.3> beacon content change detected, disconnect immediately + if(fgNeedDisconnect == TRUE) { + aisBssBeaconTimeout(prAdapter); + } + } + + //4 <1.1> Update AIS_BSS_INFO + if(((prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE && prConnSettings->eOPMode != NET_TYPE_IBSS) + || (prBssDesc->eBSSType == BSS_TYPE_IBSS && prConnSettings->eOPMode != NET_TYPE_INFRA))) { + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + + /* *not* checking prBssDesc->fgIsConnected anymore, + * due to Linksys AP uses " " as hidden SSID, and would have different BSS descriptor */ + if ((!prAisBssInfo->ucDTIMPeriod) && + EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAisBssInfo->aucBSSID) && + (prAisBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) && + ((prWlanBeaconFrame->u2FrameCtrl & MASK_FRAME_TYPE) == MAC_FRAME_BEACON)) { + + prAisBssInfo->ucDTIMPeriod = prBssDesc->ucDTIMPeriod; + + /* sync with firmware for beacon information */ + nicPmIndicateBssConnected(prAdapter, NETWORK_TYPE_AIS_INDEX); + } + } + +#if CFG_SUPPORT_ADHOC + if (EQUAL_SSID(prBssDesc->aucSSID, + prBssDesc->ucSSIDLen, + prConnSettings->aucSSID, + prConnSettings->ucSSIDLen) && + (prBssDesc->eBSSType == BSS_TYPE_IBSS) && + (prAisBssInfo->eCurrentOPMode == OP_MODE_IBSS)) { + + ibssProcessMatchedBeacon(prAdapter, prAisBssInfo, prBssDesc, prSwRfb->prHifRxHdr->ucRcpi); + } +#endif /* CFG_SUPPORT_ADHOC */ + } + + rlmProcessBcn(prAdapter, + prSwRfb, + ((P_WLAN_BEACON_FRAME_T)(prSwRfb->pvHeader))->aucInfoElem, + (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - + (UINT_16)(OFFSET_OF(WLAN_BEACON_FRAME_BODY_T, aucInfoElem[0]))); + + //4 <3> Send SW_RFB_T to HIF when we perform SCAN for HOST + if(prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE + || prBssDesc->eBSSType == BSS_TYPE_IBSS) { + /* for AIS, send to host */ + if (prConnSettings->fgIsScanReqIssued && + rlmDomainIsLegalChannel(prAdapter, prBssDesc->eBand, prBssDesc->ucChannelNum) == TRUE) { + ENUM_BAND_T eBand; + UINT_8 ucChannel; + BOOLEAN fgAddToScanResult; + + /* check ucChannelNum/eBand for adjacement channel filtering */ + if(cnmAisInfraChannelFixed(prAdapter, &eBand, &ucChannel) == TRUE && + (eBand != prBssDesc->eBand || ucChannel != prBssDesc->ucChannelNum)) { + DBGLOG(SCN, WARN, ("BSS Droppeed ["MACSTR"] on ch:#%d\n", MAC2STR(prBssDesc->aucBSSID), prBssDesc->ucChannelNum)); + fgAddToScanResult = FALSE; + } + else { + fgAddToScanResult = TRUE; + } + + if(fgAddToScanResult == TRUE) { + rStatus = scanAddScanResult(prAdapter, prBssDesc, prSwRfb); + } + } + } + +#if CFG_ENABLE_WIFI_DIRECT + if(prAdapter->fgIsP2PRegistered) { + ASSERT(prAdapter->rP2pFuncLkr.prScanP2pProcessBeaconAndProbeResp); + prAdapter->rP2pFuncLkr.prScanP2pProcessBeaconAndProbeResp( + prAdapter, + prSwRfb, + &rStatus, + prBssDesc, + prWlanBeaconFrame); + } +#endif + } + + return rStatus; + +} /* end of scanProcessBeaconAndProbeResp() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Search the Candidate of BSS Descriptor for JOIN(Infrastructure) or +* MERGE(AdHoc) according to current Connection Policy. +* +* \return Pointer to BSS Descriptor, if found. NULL, if not found +*/ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T +scanSearchBssDescByPolicy ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex + ) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_INFO_T prBssInfo; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + P_SCAN_INFO_T prScanInfo; + + P_LINK_T prBSSDescList; + + P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T)NULL; + P_BSS_DESC_T prPrimaryBssDesc = (P_BSS_DESC_T)NULL; + P_BSS_DESC_T prCandidateBssDesc = (P_BSS_DESC_T)NULL; + + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + P_STA_RECORD_T prPrimaryStaRec; + P_STA_RECORD_T prCandidateStaRec = (P_STA_RECORD_T)NULL; + + /* The first one reach the check point will be our candidate */ + BOOLEAN fgIsFindFirst = (BOOLEAN)FALSE; + + BOOLEAN fgIsFindBestRSSI = (BOOLEAN)FALSE; + BOOLEAN fgIsFindBestEncryptionLevel = (BOOLEAN)FALSE; + //BOOLEAN fgIsFindMinChannelLoad = (BOOLEAN)FALSE; + + /* TODO(Kevin): Support Min Channel Load */ + //UINT_8 aucChannelLoad[CHANNEL_NUM] = {0}; + + BOOLEAN fgIsFixedChannel; + ENUM_BAND_T eBand; + UINT_8 ucChannel; + + ASSERT(prAdapter); + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); + + prAisSpecBssInfo = &(prAdapter->rWifiVar.rAisSpecificBssInfo); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prBSSDescList = &prScanInfo->rBSSDescList; + + /* check for fixed channel operation */ + if(eNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { + fgIsFixedChannel = cnmAisInfraChannelFixed(prAdapter, &eBand, &ucChannel); + } + else { + fgIsFixedChannel = FALSE; + } + +#if DBG + if (prConnSettings->ucSSIDLen < ELEM_MAX_LEN_SSID) { + prConnSettings->aucSSID[prConnSettings->ucSSIDLen] = '\0'; + } +#endif + + DBGLOG(SCN, INFO, ("SEARCH: Num Of BSS_DESC_T = %d, Look for SSID: %s\n", + prBSSDescList->u4NumElem, prConnSettings->aucSSID)); + + + //4 <1> The outer loop to search for a candidate. + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { + + /* TODO(Kevin): Update Minimum Channel Load Information here */ + + DBGLOG(SCN, INFO, ("SEARCH: ["MACSTR"], SSID:%s\n", + MAC2STR(prBssDesc->aucBSSID), prBssDesc->aucSSID)); + + + //4 <2> Check PHY Type and attributes + //4 <2.1> Check Unsupported BSS PHY Type + if (!(prBssDesc->ucPhyTypeSet & (prAdapter->rWifiVar.ucAvailablePhyTypeSet))) { + + DBGLOG(SCN, INFO, ("SEARCH: Ignore unsupported ucPhyTypeSet = %x\n", + prBssDesc->ucPhyTypeSet)); + continue; + } + + //4 <2.2> Check if has unknown NonHT BSS Basic Rate Set. + if (prBssDesc->fgIsUnknownBssBasicRate) { + + continue; + } + + //4 <2.3> Check if fixed operation cases should be aware + if (fgIsFixedChannel == TRUE && + (prBssDesc->eBand != eBand || prBssDesc->ucChannelNum != ucChannel)) { + continue; + } + + //4 <2.4> Check if the channel is legal under regulatory domain + if(rlmDomainIsLegalChannel(prAdapter, prBssDesc->eBand, prBssDesc->ucChannelNum) == FALSE) { + continue; + } + + //4 <3> Check if reach the excessive join retry limit + /* NOTE(Kevin): STA_RECORD_T is recorded by TA. */ + prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) eNetTypeIndex, + prBssDesc->aucSrcAddr); + + if (prStaRec) { + /* NOTE(Kevin): + * The Status Code is the result of a Previous Connection Request, we use this as SCORE for choosing a proper + * candidate (Also used for compare see <6>) + * The Reason Code is an indication of the reason why AP reject us, we use this Code for "Reject" + * a SCAN result to become our candidate(Like a blacklist). + */ +#if 0 /* TODO(Kevin): */ + if (prStaRec->u2ReasonCode != REASON_CODE_RESERVED) { + DBGLOG(SCN, INFO, ("SEARCH: Ignore BSS with previous Reason Code = %d\n", + prStaRec->u2ReasonCode)); + continue; + } + else +#endif + if (prStaRec->u2StatusCode != STATUS_CODE_SUCCESSFUL) { + OS_SYSTIME rCurrentTime; + + + GET_CURRENT_SYSTIME(&rCurrentTime); + + /* NOTE(Kevin): greedy association - after timeout, we'll still + * try to associate to the AP whose STATUS of conection attempt + * was not success. + * We may also use (ucJoinFailureCount x JOIN_RETRY_INTERVAL_SEC) for + * time bound. + */ + if ((prStaRec->ucJoinFailureCount < JOIN_MAX_RETRY_FAILURE_COUNT) || + (CHECK_FOR_TIMEOUT(rCurrentTime, + prStaRec->rLastJoinTime, + SEC_TO_SYSTIME(JOIN_RETRY_INTERVAL_SEC)))) { + + /* NOTE(Kevin): Every JOIN_RETRY_INTERVAL_SEC interval, we can retry + * JOIN_MAX_RETRY_FAILURE_COUNT times. + */ + if (prStaRec->ucJoinFailureCount >= JOIN_MAX_RETRY_FAILURE_COUNT) { + prStaRec->ucJoinFailureCount = 0; + } + DBGLOG(SCN, INFO, ("SEARCH: Try to join BSS again which has Status Code = %d (Curr = %ld/Last Join = %ld)\n", + prStaRec->u2StatusCode, rCurrentTime, prStaRec->rLastJoinTime)); + } + else { + DBGLOG(SCN, INFO, ("SEARCH: Ignore BSS which reach maximum Join Retry Count = %d \n", + JOIN_MAX_RETRY_FAILURE_COUNT)); + continue; + } + + } + } + + + //4 <4> Check for various NETWORK conditions + if (eNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { + + //4 <4.1> Check BSS Type for the corresponding Operation Mode in Connection Setting + /* NOTE(Kevin): For NET_TYPE_AUTO_SWITCH, we will always pass following check. */ + if (((prConnSettings->eOPMode == NET_TYPE_INFRA) && + (prBssDesc->eBSSType != BSS_TYPE_INFRASTRUCTURE)) || + ((prConnSettings->eOPMode == NET_TYPE_IBSS || prConnSettings->eOPMode == NET_TYPE_DEDICATED_IBSS) && + (prBssDesc->eBSSType != BSS_TYPE_IBSS))) { + + DBGLOG(SCN, INFO, ("SEARCH: Ignore eBSSType = %s\n", + ((prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE) ? + "INFRASTRUCTURE" : "IBSS"))); + continue; + } + + //4 <4.2> Check AP's BSSID if OID_802_11_BSSID has been set. + if ((prConnSettings->fgIsConnByBssidIssued) && + (prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE)) { + + if (UNEQUAL_MAC_ADDR(prConnSettings->aucBSSID, prBssDesc->aucBSSID)) { + + DBGLOG(SCN, INFO, ("SEARCH: Ignore due to BSSID was not matched!\n")); + continue; + } + } + +#if CFG_SUPPORT_ADHOC + //4 <4.3> Check for AdHoc Mode + if (prBssDesc->eBSSType == BSS_TYPE_IBSS) { + OS_SYSTIME rCurrentTime; + + //4 <4.3.1> Check if this SCAN record has been updated recently for IBSS. + /* NOTE(Kevin): Because some STA may change its BSSID frequently after it + * create the IBSS - e.g. IPN2220, so we need to make sure we get the new one. + * For BSS, if the old record was matched, however it won't be able to pass + * the Join Process later. + */ + GET_CURRENT_SYSTIME(&rCurrentTime); + if (CHECK_FOR_TIMEOUT(rCurrentTime, prBssDesc->rUpdateTime, + SEC_TO_SYSTIME(SCN_ADHOC_BSS_DESC_TIMEOUT_SEC))) { + DBGLOG(SCN, LOUD, ("SEARCH: Skip old record of BSS Descriptor - BSSID:["MACSTR"]\n\n", + MAC2STR(prBssDesc->aucBSSID))); + continue; + } + + //4 <4.3.2> Check Peer's capability + if (ibssCheckCapabilityForAdHocMode(prAdapter, prBssDesc) == WLAN_STATUS_FAILURE) { + + DBGLOG(SCN, INFO, + ("SEARCH: Ignore BSS DESC MAC: "MACSTR", Capability is not supported for current AdHoc Mode.\n", + MAC2STR(prPrimaryBssDesc->aucBSSID))); + + continue; + } + + + //4 <4.3.3> Compare TSF + if (prBssInfo->fgIsBeaconActivated && + UNEQUAL_MAC_ADDR(prBssInfo->aucBSSID, prBssDesc->aucBSSID)) { + + DBGLOG(SCN, LOUD, + ("SEARCH: prBssDesc->fgIsLargerTSF = %d\n", + prBssDesc->fgIsLargerTSF)); + + if (!prBssDesc->fgIsLargerTSF) { + DBGLOG(SCN, INFO, + ("SEARCH: Ignore BSS DESC MAC: ["MACSTR"], Smaller TSF\n", MAC2STR(prBssDesc->aucBSSID))); + continue; + } + } + } +#endif /* CFG_SUPPORT_ADHOC */ + + } + + + + +#if 0 /* TODO(Kevin): For IBSS */ + //4 <2.c> Check if this SCAN record has been updated recently for IBSS. + /* NOTE(Kevin): Because some STA may change its BSSID frequently after it + * create the IBSS, so we need to make sure we get the new one. + * For BSS, if the old record was matched, however it won't be able to pass + * the Join Process later. + */ + if (prBssDesc->eBSSType == BSS_TYPE_IBSS) { + OS_SYSTIME rCurrentTime; + + GET_CURRENT_SYSTIME(&rCurrentTime); + if (CHECK_FOR_TIMEOUT(rCurrentTime, prBssDesc->rUpdateTime, + SEC_TO_SYSTIME(BSS_DESC_TIMEOUT_SEC))) { + DBGLOG(SCAN, TRACE, ("Skip old record of BSS Descriptor - BSSID:["MACSTR"]\n\n", + MAC2STR(prBssDesc->aucBSSID))); + continue; + } + } + + if ((prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE) && + (prAdapter->eConnectionState == MEDIA_STATE_CONNECTED)) { + OS_SYSTIME rCurrentTime; + + GET_CURRENT_SYSTIME(&rCurrentTime); + if (CHECK_FOR_TIMEOUT(rCurrentTime, prBssDesc->rUpdateTime, + SEC_TO_SYSTIME(BSS_DESC_TIMEOUT_SEC))) { + DBGLOG(SCAN, TRACE, ("Skip old record of BSS Descriptor - BSSID:["MACSTR"]\n\n", + MAC2STR(prBssDesc->aucBSSID))); + continue; + } + } + + + //4 <4B> Check for IBSS AdHoc Mode. + /* Skip if one or more BSS Basic Rate are not supported by current AdHocMode */ + if (prPrimaryBssDesc->eBSSType == BSS_TYPE_IBSS) { + //4 <4B.1> Check if match the Capability of current IBSS AdHoc Mode. + if (ibssCheckCapabilityForAdHocMode(prAdapter, prPrimaryBssDesc) == WLAN_STATUS_FAILURE) { + + DBGLOG(SCAN, TRACE, + ("Ignore BSS DESC MAC: "MACSTR", Capability is not supported for current AdHoc Mode.\n", + MAC2STR(prPrimaryBssDesc->aucBSSID))); + + continue; + } + + + //4 <4B.2> IBSS Merge Decision Flow for SEARCH STATE. + if (prAdapter->fgIsIBSSActive && + UNEQUAL_MAC_ADDR(prBssInfo->aucBSSID, prPrimaryBssDesc->aucBSSID)) { + + if (!fgIsLocalTSFRead) { + NIC_GET_CURRENT_TSF(prAdapter, &rCurrentTsf); + + DBGLOG(SCAN, TRACE, + ("\n\nCurrent TSF : %08lx-%08lx\n\n", + rCurrentTsf.u.HighPart, rCurrentTsf.u.LowPart)); + } + + if (rCurrentTsf.QuadPart > prPrimaryBssDesc->u8TimeStamp.QuadPart) { + DBGLOG(SCAN, TRACE, + ("Ignore BSS DESC MAC: ["MACSTR"], Current BSSID: ["MACSTR"].\n", + MAC2STR(prPrimaryBssDesc->aucBSSID), MAC2STR(prBssInfo->aucBSSID))); + + DBGLOG(SCAN, TRACE, + ("\n\nBSS's TSF : %08lx-%08lx\n\n", + prPrimaryBssDesc->u8TimeStamp.u.HighPart, prPrimaryBssDesc->u8TimeStamp.u.LowPart)); + + prPrimaryBssDesc->fgIsLargerTSF = FALSE; + continue; + } + else { + prPrimaryBssDesc->fgIsLargerTSF = TRUE; + } + + } + } + + //4 <5> Check the Encryption Status. + if (rsnPerformPolicySelection(prPrimaryBssDesc)) { + + if (prPrimaryBssDesc->ucEncLevel > 0) { + fgIsFindBestEncryptionLevel = TRUE; + + fgIsFindFirst = FALSE; + } + } + else { + /* Can't pass the Encryption Status Check, get next one */ + continue; + } + + /* For RSN Pre-authentication, update the PMKID canidate list for + same SSID and encrypt status */ + /* Update PMKID candicate list. */ + if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2) { + rsnUpdatePmkidCandidateList(prPrimaryBssDesc); + if (prAdapter->rWifiVar.rAisBssInfo.u4PmkidCandicateCount) { + prAdapter->rWifiVar.rAisBssInfo.fgIndicatePMKID = rsnCheckPmkidCandicate(); + } + } + +#endif + + + prPrimaryBssDesc = (P_BSS_DESC_T)NULL; + + //4 <6> Check current Connection Policy. + switch (prConnSettings->eConnectionPolicy) { + case CONNECT_BY_SSID_BEST_RSSI: + /* Choose Hidden SSID to join only if the `fgIsEnableJoin...` is TRUE */ + if (prAdapter->rWifiVar.fgEnableJoinToHiddenSSID && prBssDesc->fgIsHiddenSSID) { + /* NOTE(Kevin): following if () statement means that + * If Target is hidden, then we won't connect when user specify SSID_ANY policy. + */ + if (prConnSettings->ucSSIDLen) { + prPrimaryBssDesc = prBssDesc; + + fgIsFindBestRSSI = TRUE; + } + + } + else if (EQUAL_SSID(prBssDesc->aucSSID, + prBssDesc->ucSSIDLen, + prConnSettings->aucSSID, + prConnSettings->ucSSIDLen)) { + prPrimaryBssDesc = prBssDesc; + + fgIsFindBestRSSI = TRUE; + } + break; + + case CONNECT_BY_SSID_ANY: + /* NOTE(Kevin): In this policy, we don't know the desired + * SSID from user, so we should exclude the Hidden SSID from scan list. + * And because we refuse to connect to Hidden SSID node at the beginning, so + * when the JOIN Module deal with a BSS_DESC_T which has fgIsHiddenSSID == TRUE, + * then the Connection Settings must be valid without doubt. + */ + if (!prBssDesc->fgIsHiddenSSID) { + prPrimaryBssDesc = prBssDesc; + + fgIsFindFirst = TRUE; + } + break; + + case CONNECT_BY_BSSID: + if(EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prConnSettings->aucBSSID)) { + prPrimaryBssDesc = prBssDesc; + } + break; + + default: + break; + } + + + /* Primary Candidate was not found */ + if (prPrimaryBssDesc == NULL) { + continue; + } + + //4 <7> Check the Encryption Status. + if (prPrimaryBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE) { +#if CFG_SUPPORT_WAPI + if (prAdapter->rWifiVar.rConnSettings.fgWapiMode) { + if (wapiPerformPolicySelection(prAdapter, prPrimaryBssDesc)) { + fgIsFindFirst = TRUE; + } + else { + /* Can't pass the Encryption Status Check, get next one */ + continue; + } + } + else +#endif +#if CFG_RSN_MIGRATION + if (rsnPerformPolicySelection(prAdapter, prPrimaryBssDesc)) { + if (prAisSpecBssInfo->fgCounterMeasure) { + DBGLOG(RSN, INFO, ("Skip while at counter measure period!!!\n")); + continue; + } + + if (prPrimaryBssDesc->ucEncLevel > 0) { + fgIsFindBestEncryptionLevel = TRUE; + + fgIsFindFirst = FALSE; + } + +#if 0 + /* Update PMKID candicate list. */ + if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2) { + rsnUpdatePmkidCandidateList(prPrimaryBssDesc); + if (prAisSpecBssInfo->u4PmkidCandicateCount) { + if (rsnCheckPmkidCandicate()) { + DBGLOG(RSN, WARN, ("Prepare a timer to indicate candidate "MACSTR"\n", + MAC2STR(prAisSpecBssInfo->arPmkidCache[prAisSpecBssInfo->u4PmkidCacheCount].rBssidInfo.aucBssid))); + cnmTimerStopTimer(&prAisSpecBssInfo->rPreauthenticationTimer); + cnmTimerStartTimer(&prAisSpecBssInfo->rPreauthenticationTimer, + SEC_TO_MSEC(WAIT_TIME_IND_PMKID_CANDICATE_SEC)); + } + } + } +#endif + } + else { + /* Can't pass the Encryption Status Check, get next one */ + continue; + } +#endif + } + else { + /* Todo:: P2P and BOW Policy Selection */ + } + + prPrimaryStaRec = prStaRec; + + //4 <8> Compare the Candidate and the Primary Scan Record. + if (!prCandidateBssDesc) { + prCandidateBssDesc = prPrimaryBssDesc; + prCandidateStaRec = prPrimaryStaRec; + + //4 <8.1> Condition - Get the first matched one. + if (fgIsFindFirst) { + break; + } + } + else { +#if 0 /* TODO(Kevin): For security(TBD) */ + //4 <6B> Condition - Choose the one with best Encryption Score. + if (fgIsFindBestEncryptionLevel) { + if (prCandidateBssDesc->ucEncLevel < + prPrimaryBssDesc->ucEncLevel) { + + prCandidateBssDesc = prPrimaryBssDesc; + prCandidateStaRec = prPrimaryStaRec; + continue; + } + } + + /* If reach here, that means they have the same Encryption Score. + */ + + //4 <6C> Condition - Give opportunity to the one we didn't connect before. + // For roaming, only compare the candidates other than current associated BSSID. + if (!prCandidateBssDesc->fgIsConnected && !prPrimaryBssDesc->fgIsConnected) { + if ((prCandidateStaRec != (P_STA_RECORD_T)NULL) && + (prCandidateStaRec->u2StatusCode != STATUS_CODE_SUCCESSFUL)) { + + DBGLOG(SCAN, TRACE, ("So far -BSS DESC MAC: "MACSTR" has nonzero Status Code = %d\n", + MAC2STR(prCandidateBssDesc->aucBSSID), prCandidateStaRec->u2StatusCode)); + + if (prPrimaryStaRec != (P_STA_RECORD_T)NULL) { + if (prPrimaryStaRec->u2StatusCode != STATUS_CODE_SUCCESSFUL) { + + /* Give opportunity to the one with smaller rLastJoinTime */ + if (TIME_BEFORE(prCandidateStaRec->rLastJoinTime, + prPrimaryStaRec->rLastJoinTime)) { + continue; + } + /* We've connect to CANDIDATE recently, let us try PRIMARY now */ + else { + prCandidateBssDesc = prPrimaryBssDesc; + prCandidateStaRec = prPrimaryStaRec; + continue; + } + } + /* PRIMARY's u2StatusCode = 0 */ + else { + prCandidateBssDesc = prPrimaryBssDesc; + prCandidateStaRec = prPrimaryStaRec; + continue; + } + } + /* PRIMARY has no StaRec - We didn't connet to PRIMARY before */ + else { + prCandidateBssDesc = prPrimaryBssDesc; + prCandidateStaRec = prPrimaryStaRec; + continue; + } + } + else { + if ((prPrimaryStaRec != (P_STA_RECORD_T)NULL) && + (prPrimaryStaRec->u2StatusCode != STATUS_CODE_SUCCESSFUL)) { + continue; + } + } + } +#endif + + + //4 <6D> Condition - Visible SSID win Hidden SSID. + if (prCandidateBssDesc->fgIsHiddenSSID) { + if (!prPrimaryBssDesc->fgIsHiddenSSID) { + prCandidateBssDesc = prPrimaryBssDesc; /* The non Hidden SSID win. */ + prCandidateStaRec = prPrimaryStaRec; + continue; + } + } + else { + if (prPrimaryBssDesc->fgIsHiddenSSID) { + continue; + } + } + + + //4 <6E> Condition - Choose the one with better RCPI(RSSI). + if (fgIsFindBestRSSI) { + /* TODO(Kevin): We shouldn't compare the actual value, we should + * allow some acceptable tolerance of some RSSI percentage here. + */ + DBGLOG(SCN, TRACE, ("Candidate ["MACSTR"]: RCPI = %d, Primary ["MACSTR"]: RCPI = %d\n", + MAC2STR(prCandidateBssDesc->aucBSSID), prCandidateBssDesc->ucRCPI, + MAC2STR(prPrimaryBssDesc->aucBSSID), prPrimaryBssDesc->ucRCPI)); + + ASSERT(!(prCandidateBssDesc->fgIsConnected && + prPrimaryBssDesc->fgIsConnected)); + + /* NOTE: To prevent SWING, we do roaming only if target AP has at least 5dBm larger than us. */ + if (prCandidateBssDesc->fgIsConnected) { + if (prCandidateBssDesc->ucRCPI + ROAMING_NO_SWING_RCPI_STEP <= prPrimaryBssDesc->ucRCPI) { + + prCandidateBssDesc = prPrimaryBssDesc; + prCandidateStaRec = prPrimaryStaRec; + continue; + } + } + else if (prPrimaryBssDesc->fgIsConnected) { + if (prCandidateBssDesc->ucRCPI < prPrimaryBssDesc->ucRCPI + ROAMING_NO_SWING_RCPI_STEP) { + + prCandidateBssDesc = prPrimaryBssDesc; + prCandidateStaRec = prPrimaryStaRec; + continue; + } + } + else if (prCandidateBssDesc->ucRCPI < prPrimaryBssDesc->ucRCPI) { + prCandidateBssDesc = prPrimaryBssDesc; + prCandidateStaRec = prPrimaryStaRec; + continue; + } + } + +#if 0 + /* If reach here, that means they have the same Encryption Score, and + * both RSSI value are close too. + */ + //4 <6F> Seek the minimum Channel Load for less interference. + if (fgIsFindMinChannelLoad) { + + /* TODO(Kevin): Check which one has minimum channel load in its channel */ + } +#endif + } + } + + return prCandidateBssDesc; + +} /* end of scanSearchBssDescByPolicy() */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/scan_fsm.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/scan_fsm.c new file mode 100755 index 000000000000..998cb9b9c8a7 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/scan_fsm.c @@ -0,0 +1,1159 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/mgmt/scan_fsm.c#1 $ +*/ + +/*! \file "scan_fsm.c" + \brief This file defines the state transition function for SCAN FSM. + + The SCAN FSM is part of SCAN MODULE and responsible for performing basic SCAN + behavior as metioned in IEEE 802.11 2007 11.1.3.1 & 11.1.3.2 . +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: scan_fsm.c $ + * + * 01 20 2012 cp.wu + * [ALPS00096191] [MT6620 Wi-Fi][Driver][Firmware] Porting to ALPS4.0_DEV branch + * sync to up-to-date changes including: + * 1. BOW bugfix + * 2. XLOG + * + * 11 24 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Adjust code for DBG and CONFIG_XLOG. + * + * 11 14 2011 yuche.tsai + * [WCXRP00001107] [Volunteer Patch][Driver] Large Network Type index assert in FW issue. + * Avoid possible FW assert when unload P2P module. + * + * 11 11 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * modify the xlog related code. + * + * 11 02 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Add XLOG related code and define. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 08 11 2011 cp.wu + * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time + * sparse channel detection: + * driver: collect sparse channel information with scan-done event + + * + * 07 18 2011 cp.wu + * [WCXRP00000858] [MT5931][Driver][Firmware] Add support for scan to search for more than one SSID in a single scanning request + * free mailbox message afte parsing is completed. + * + * 07 18 2011 cp.wu + * [WCXRP00000858] [MT5931][Driver][Firmware] Add support for scan to search for more than one SSID in a single scanning request + * add framework in driver domain for supporting new SCAN_REQ_V2 for more than 1 SSID support as well as uProbeDelay in NDIS 6.x driver model + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 03 29 2011 cp.wu + * [WCXRP00000604] [MT6620 Wi-Fi][Driver] Surpress Klockwork Warning + * surpress klock warning with code path rewritten + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 18 2011 cm.chang + * [WCXRP00000576] [MT6620 Wi-Fi][Driver][FW] Remove P2P compile option in scan req/cancel command + * As CR title + * + * 02 18 2011 yuche.tsai + * [WCXRP00000478] [Volunteer Patch][MT6620][Driver] Probe request frame during search phase do not contain P2P wildcard SSID. + * Take P2P wildcard SSID into consideration. + * + * 01 27 2011 yuche.tsai + * [WCXRP00000399] [Volunteer Patch][MT6620/MT5931][Driver] Fix scan side effect after P2P module separate. + * Fix scan channel extension issue when p2p module is not registered. + * + * 01 26 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * . + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Fix Compile Error when DBG is disabled. + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 16 2010 cp.wu + * NULL + * add interface for RLM to trigger OBSS-SCAN. + * + * 08 16 2010 yuche.tsai + * NULL + * Fix bug for processing queued scan request. + * + * 08 11 2010 yuche.tsai + * NULL + * Add a function for returning channel. + * + * 08 05 2010 yuche.tsai + * NULL + * Update SCAN FSM for support P2P Device discovery scan. + * + * 08 03 2010 cp.wu + * NULL + * surpress compilation warning. + * + * 07 26 2010 yuche.tsai + * + * Add option of channel extension while cancelling scan request. + * + * 07 21 2010 yuche.tsai + * + * Add P2P Scan & Scan Result Parsing & Saving. + * + * 07 20 2010 cp.wu + * + * pass band information for scan in an efficient way by mapping ENUM_BAND_T into UINT_8.. + * + * 07 19 2010 cp.wu + * + * due to FW/DRV won't be sync. precisely, some strict assertions should be eased. + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * SCN module is now able to handle multiple concurrent scanning requests + * + * 07 16 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * bugfix for SCN migration + * 1) modify QUEUE_CONCATENATE_QUEUES() so it could be used to concatence with an empty queue + * 2) before AIS issues scan request, network(BSS) needs to be activated first + * 3) only invoke COPY_SSID when using specified SSID for scan + * + * 07 15 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * driver no longer generates probe request frames + * + * 07 14 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * pass band with channel number information as scan parameter + * + * 07 14 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * remove timer in DRV-SCN. + * + * 07 09 2010 cp.wu + * + * 1) separate AIS_FSM state for two kinds of scanning. (OID triggered scan, and scan-for-connection) + * 2) eliminate PRE_BSS_DESC_T, Beacon/PrebResp is now parsed in single pass + * 3) implment DRV-SCN module, currently only accepts single scan request, other request will be directly dropped by returning BUSY + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * take use of RLM module for parsing/generating HT IEs for 11n capability + * + * 07 02 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * when returning to SCAN_IDLE state, send a correct message to source FSM. + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implementation of DRV-SCN and related mailbox message handling. + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * comment out RLM APIs by CFG_RLM_MIGRATION. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add scan_fsm into building. + * + * 05 14 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Refine the order of Stop TX Queue and Switch Channel + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Update pause/resume/flush API to new Bitmap API + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 03 18 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Ignore the PROBE_DELAY state if the value of Probe Delay == 0 + * + * 03 10 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * Add Channel Manager for arbitration of JOIN and SCAN Req + * + * 02 23 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add support scan channel 1~14 and update scan result's frequency infou1rwduu`wvpghlqg|n`slk+mpdkb + * + * 01 08 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add set RX Filter to receive BCN from different BSSID during SCAN + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Nov 25 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Remove flag of CFG_TEST_MGMT_FSM + * + * Nov 20 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Change parameter of scanSendProbeReqFrames() + * + * Nov 16 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Update scnFsmSteps() + * + * Nov 5 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix typo + * + * Nov 5 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +#if DBG +/*lint -save -e64 Type mismatch */ +static PUINT_8 apucDebugScanState[SCAN_STATE_NUM] = { + (PUINT_8)DISP_STRING("SCAN_STATE_IDLE"), + (PUINT_8)DISP_STRING("SCAN_STATE_SCANNING"), +}; +/*lint -restore */ +#endif /* DBG */ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +scnFsmSteps ( + IN P_ADAPTER_T prAdapter, + IN ENUM_SCAN_STATE_T eNextState + ) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + P_MSG_HDR_T prMsgHdr; + + BOOLEAN fgIsTransition = (BOOLEAN)FALSE; + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + do { + +#if CFG_SUPPORT_XLOG + DBGLOG(SCN, STATE, ("[%d] TRANSITION: [%d] -> [%d]\n", + DBG_SCN_IDX, + prScanInfo->eCurrentState, + eNextState)); +#else + DBGLOG(SCN, STATE, ("TRANSITION: [%s] -> [%s]\n", + apucDebugScanState[prScanInfo->eCurrentState], + apucDebugScanState[eNextState])); +#endif + + /* NOTE(Kevin): This is the only place to change the eCurrentState(except initial) */ + prScanInfo->eCurrentState = eNextState; + + fgIsTransition = (BOOLEAN)FALSE; + + switch (prScanInfo->eCurrentState) { + case SCAN_STATE_IDLE: + /* check for pending scanning requests */ + if(!LINK_IS_EMPTY(&(prScanInfo->rPendingMsgList))) { + // load next message from pending list as scan parameters + LINK_REMOVE_HEAD(&(prScanInfo->rPendingMsgList), prMsgHdr, P_MSG_HDR_T); + + if(prMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ + || prMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ + || prMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ + || prMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ) { + scnFsmHandleScanMsg(prAdapter, (P_MSG_SCN_SCAN_REQ)prMsgHdr); + } + else { + scnFsmHandleScanMsgV2(prAdapter, (P_MSG_SCN_SCAN_REQ_V2)prMsgHdr); + } + + /* switch to next state */ + eNextState = SCAN_STATE_SCANNING; + fgIsTransition = TRUE; + + cnmMemFree(prAdapter, prMsgHdr); + } + break; + + case SCAN_STATE_SCANNING: + if(prScanParam->fgIsScanV2 == FALSE) { + scnSendScanReq(prAdapter); + } + else { + scnSendScanReqV2(prAdapter); + } + break; + + default: + ASSERT(0); + break; + + } + } + while (fgIsTransition); + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Generate CMD_ID_SCAN_REQ command +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +scnSendScanReq ( + IN P_ADAPTER_T prAdapter + ) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + CMD_SCAN_REQ rCmdScanReq; + UINT_32 i; + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + // send command packet for scan + kalMemZero(&rCmdScanReq, sizeof(CMD_SCAN_REQ)); + + rCmdScanReq.ucSeqNum = prScanParam->ucSeqNum; + rCmdScanReq.ucNetworkType = (UINT_8)prScanParam->eNetTypeIndex; + rCmdScanReq.ucScanType = (UINT_8)prScanParam->eScanType; + rCmdScanReq.ucSSIDType = prScanParam->ucSSIDType; + + if(prScanParam->ucSSIDNum == 1) { + COPY_SSID(rCmdScanReq.aucSSID, + rCmdScanReq.ucSSIDLength, + prScanParam->aucSpecifiedSSID[0], + prScanParam->ucSpecifiedSSIDLen[0]); + } + + rCmdScanReq.ucChannelType = (UINT_8)prScanParam->eScanChannel; + + if (prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { + /* P2P would use: + * 1. Specified Listen Channel of passive scan for LISTEN state. + * 2. Specified Listen Channel of Target Device of active scan for SEARCH state. (Target != NULL) + */ + rCmdScanReq.ucChannelListNum = prScanParam->ucChannelListNum; + + for(i = 0 ; i < rCmdScanReq.ucChannelListNum ; i++) { + rCmdScanReq.arChannelList[i].ucBand = + (UINT_8) prScanParam->arChnlInfoList[i].eBand; + + rCmdScanReq.arChannelList[i].ucChannelNum = + (UINT_8)prScanParam->arChnlInfoList[i].ucChannelNum; + } + } + +#if CFG_ENABLE_WIFI_DIRECT + if(prAdapter->fgIsP2PRegistered) { + rCmdScanReq.u2ChannelDwellTime = prScanParam->u2PassiveListenInterval; + } +#endif + + if(prScanParam->u2IELen <= MAX_IE_LENGTH) { + rCmdScanReq.u2IELen = prScanParam->u2IELen; + } + else { + rCmdScanReq.u2IELen = MAX_IE_LENGTH; + } + + if (prScanParam->u2IELen) { + kalMemCopy(rCmdScanReq.aucIE, + prScanParam->aucIE, + sizeof(UINT_8) * rCmdScanReq.u2IELen); + } + + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SCAN_REQ, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + OFFSET_OF(CMD_SCAN_REQ, aucIE) + rCmdScanReq.u2IELen, + (PUINT_8)&rCmdScanReq, + NULL, + 0); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Generate CMD_ID_SCAN_REQ_V2 command +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +scnSendScanReqV2 ( + IN P_ADAPTER_T prAdapter + ) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + CMD_SCAN_REQ_V2 rCmdScanReq; + UINT_32 i; + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + // send command packet for scan + kalMemZero(&rCmdScanReq, sizeof(CMD_SCAN_REQ_V2)); + + rCmdScanReq.ucSeqNum = prScanParam->ucSeqNum; + rCmdScanReq.ucNetworkType = (UINT_8)prScanParam->eNetTypeIndex; + rCmdScanReq.ucScanType = (UINT_8)prScanParam->eScanType; + rCmdScanReq.ucSSIDType = prScanParam->ucSSIDType; + + for (i = 0 ; i < prScanParam->ucSSIDNum; i++) { + COPY_SSID(rCmdScanReq.arSSID[i].aucSsid, + rCmdScanReq.arSSID[i].u4SsidLen, + prScanParam->aucSpecifiedSSID[i], + prScanParam->ucSpecifiedSSIDLen[i]); + } + + rCmdScanReq.u2ProbeDelayTime = (UINT_8)prScanParam->u2ProbeDelayTime; + rCmdScanReq.ucChannelType = (UINT_8)prScanParam->eScanChannel; + + if (prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { + /* P2P would use: + * 1. Specified Listen Channel of passive scan for LISTEN state. + * 2. Specified Listen Channel of Target Device of active scan for SEARCH state. (Target != NULL) + */ + rCmdScanReq.ucChannelListNum = prScanParam->ucChannelListNum; + + for(i = 0 ; i < rCmdScanReq.ucChannelListNum ; i++) { + rCmdScanReq.arChannelList[i].ucBand = + (UINT_8) prScanParam->arChnlInfoList[i].eBand; + + rCmdScanReq.arChannelList[i].ucChannelNum = + (UINT_8)prScanParam->arChnlInfoList[i].ucChannelNum; + } + } + +#if CFG_ENABLE_WIFI_DIRECT + if(prAdapter->fgIsP2PRegistered) { + rCmdScanReq.u2ChannelDwellTime = prScanParam->u2PassiveListenInterval; + } +#endif + + if(prScanParam->u2IELen <= MAX_IE_LENGTH) { + rCmdScanReq.u2IELen = prScanParam->u2IELen; + } + else { + rCmdScanReq.u2IELen = MAX_IE_LENGTH; + } + + if (prScanParam->u2IELen) { + kalMemCopy(rCmdScanReq.aucIE, + prScanParam->aucIE, + sizeof(UINT_8) * rCmdScanReq.u2IELen); + } + + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SCAN_REQ_V2, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + OFFSET_OF(CMD_SCAN_REQ_V2, aucIE) + rCmdScanReq.u2IELen, + (PUINT_8)&rCmdScanReq, + NULL, + 0); + +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +scnFsmMsgStart ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + + ASSERT(prMsgHdr); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + + if (prScanInfo->eCurrentState == SCAN_STATE_IDLE) { + if(prMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ + || prMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ + || prMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ + || prMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ) { + scnFsmHandleScanMsg(prAdapter, (P_MSG_SCN_SCAN_REQ)prMsgHdr); + } + else if(prMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ_V2 + || prMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ_V2 + || prMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ_V2 + || prMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ_V2) { + scnFsmHandleScanMsgV2(prAdapter, (P_MSG_SCN_SCAN_REQ_V2)prMsgHdr); + } + else { + // should not deliver to this function + ASSERT(0); + } + + cnmMemFree(prAdapter, prMsgHdr); + scnFsmSteps(prAdapter, SCAN_STATE_SCANNING); + } + else { + LINK_INSERT_TAIL(&prScanInfo->rPendingMsgList, &prMsgHdr->rLinkEntry); + } + + return; +} + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +scnFsmMsgAbort ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr + ) +{ + P_MSG_SCN_SCAN_CANCEL prScanCancel; + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + CMD_SCAN_CANCEL rCmdScanCancel; + + ASSERT(prMsgHdr); + + prScanCancel = (P_MSG_SCN_SCAN_CANCEL)prMsgHdr; + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + if (prScanInfo->eCurrentState != SCAN_STATE_IDLE) { + if(prScanCancel->ucSeqNum == prScanParam->ucSeqNum && + prScanCancel->ucNetTypeIndex == (UINT_8)prScanParam->eNetTypeIndex) { + /* send cancel message to firmware domain */ + rCmdScanCancel.ucSeqNum = prScanParam->ucSeqNum; + +#if CFG_ENABLE_WIFI_DIRECT + if(prAdapter->fgIsP2PRegistered) { + rCmdScanCancel.ucIsExtChannel = (UINT_8) prScanCancel->fgIsChannelExt; + } + else { + rCmdScanCancel.ucIsExtChannel = (UINT_8) FALSE; + } +#endif + + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SCAN_CANCEL, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(CMD_SCAN_CANCEL), + (PUINT_8)&rCmdScanCancel, + NULL, + 0); + + /* generate scan-done event for caller */ + scnFsmGenerateScanDoneMsg(prAdapter, + prScanParam->ucSeqNum, + (UINT_8)prScanParam->eNetTypeIndex, + SCAN_STATUS_CANCELLED); + + /* switch to next pending scan */ + scnFsmSteps(prAdapter, SCAN_STATE_IDLE); + } + else { + scnFsmRemovePendingMsg(prAdapter, prScanCancel->ucSeqNum, prScanCancel->ucNetTypeIndex); + } + } + + cnmMemFree(prAdapter, prMsgHdr); + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Scan Message Parsing (Legacy) +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +scnFsmHandleScanMsg ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_SCN_SCAN_REQ prScanReqMsg + ) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + UINT_32 i; + + ASSERT(prAdapter); + ASSERT(prScanReqMsg); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + prScanParam->eScanType = prScanReqMsg->eScanType; + prScanParam->eNetTypeIndex = (ENUM_NETWORK_TYPE_INDEX_T)prScanReqMsg->ucNetTypeIndex; + prScanParam->ucSSIDType = prScanReqMsg->ucSSIDType; + if (prScanParam->ucSSIDType & (SCAN_REQ_SSID_SPECIFIED | SCAN_REQ_SSID_P2P_WILDCARD)) { + prScanParam->ucSSIDNum = 1; + + COPY_SSID(prScanParam->aucSpecifiedSSID[0], + prScanParam->ucSpecifiedSSIDLen[0], + prScanReqMsg->aucSSID, + prScanReqMsg->ucSSIDLength); + + // reset SSID length to zero for rest array entries + for(i = 1 ; i < SCN_SSID_MAX_NUM ; i++) { + prScanParam->ucSpecifiedSSIDLen[i] = 0; + } + } + else { + prScanParam->ucSSIDNum = 0; + + for(i = 0 ; i < SCN_SSID_MAX_NUM ; i++) { + prScanParam->ucSpecifiedSSIDLen[i] = 0; + } + } + + prScanParam->u2ProbeDelayTime = 0; + prScanParam->eScanChannel = prScanReqMsg->eScanChannel; + if(prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { + if(prScanReqMsg->ucChannelListNum <= MAXIMUM_OPERATION_CHANNEL_LIST) { + prScanParam->ucChannelListNum = prScanReqMsg->ucChannelListNum; + } + else { + prScanParam->ucChannelListNum = MAXIMUM_OPERATION_CHANNEL_LIST; + } + + kalMemCopy(prScanParam->arChnlInfoList, + prScanReqMsg->arChnlInfoList, + sizeof(RF_CHANNEL_INFO_T) * prScanParam->ucChannelListNum); + } + + if(prScanReqMsg->u2IELen <= MAX_IE_LENGTH) { + prScanParam->u2IELen = prScanReqMsg->u2IELen; + } + else { + prScanParam->u2IELen = MAX_IE_LENGTH; + } + + if(prScanParam->u2IELen) { + kalMemCopy(prScanParam->aucIE, prScanReqMsg->aucIE, prScanParam->u2IELen); + } + +#if CFG_ENABLE_WIFI_DIRECT + if(prAdapter->fgIsP2PRegistered) { + prScanParam->u2PassiveListenInterval = prScanReqMsg->u2ChannelDwellTime; + } +#endif + prScanParam->ucSeqNum = prScanReqMsg->ucSeqNum; + + if(prScanReqMsg->rMsgHdr.eMsgId == MID_RLM_SCN_SCAN_REQ) { + prScanParam->fgIsObssScan = TRUE; + } + else { + prScanParam->fgIsObssScan = FALSE; + } + + prScanParam->fgIsScanV2 = FALSE; + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Scan Message Parsing - V2 with multiple SSID support +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +scnFsmHandleScanMsgV2 ( + IN P_ADAPTER_T prAdapter, + IN P_MSG_SCN_SCAN_REQ_V2 prScanReqMsg + ) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + UINT_32 i; + + ASSERT(prAdapter); + ASSERT(prScanReqMsg); + ASSERT(prScanReqMsg->ucSSIDNum <= SCN_SSID_MAX_NUM); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + prScanParam->eScanType = prScanReqMsg->eScanType; + prScanParam->eNetTypeIndex = (ENUM_NETWORK_TYPE_INDEX_T)prScanReqMsg->ucNetTypeIndex; + prScanParam->ucSSIDType = prScanReqMsg->ucSSIDType; + prScanParam->ucSSIDNum = prScanReqMsg->ucSSIDNum; + + for(i = 0 ; i < prScanReqMsg->ucSSIDNum ; i++) { + COPY_SSID(prScanParam->aucSpecifiedSSID[i], + prScanParam->ucSpecifiedSSIDLen[i], + prScanReqMsg->prSsid[i].aucSsid, + (UINT_8)prScanReqMsg->prSsid[i].u4SsidLen); + } + + prScanParam->u2ProbeDelayTime = prScanReqMsg->u2ProbeDelay; + prScanParam->eScanChannel = prScanReqMsg->eScanChannel; + if(prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { + if(prScanReqMsg->ucChannelListNum <= MAXIMUM_OPERATION_CHANNEL_LIST) { + prScanParam->ucChannelListNum = prScanReqMsg->ucChannelListNum; + } + else { + prScanParam->ucChannelListNum = MAXIMUM_OPERATION_CHANNEL_LIST; + } + + kalMemCopy(prScanParam->arChnlInfoList, + prScanReqMsg->arChnlInfoList, + sizeof(RF_CHANNEL_INFO_T) * prScanParam->ucChannelListNum); + } + + if(prScanReqMsg->u2IELen <= MAX_IE_LENGTH) { + prScanParam->u2IELen = prScanReqMsg->u2IELen; + } + else { + prScanParam->u2IELen = MAX_IE_LENGTH; + } + + if(prScanParam->u2IELen) { + kalMemCopy(prScanParam->aucIE, prScanReqMsg->aucIE, prScanParam->u2IELen); + } + +#if CFG_ENABLE_WIFI_DIRECT + if(prAdapter->fgIsP2PRegistered) { + prScanParam->u2PassiveListenInterval = prScanReqMsg->u2ChannelDwellTime; + } +#endif + prScanParam->ucSeqNum = prScanReqMsg->ucSeqNum; + + if(prScanReqMsg->rMsgHdr.eMsgId == MID_RLM_SCN_SCAN_REQ) { + prScanParam->fgIsObssScan = TRUE; + } + else { + prScanParam->fgIsObssScan = FALSE; + } + + prScanParam->fgIsScanV2 = TRUE; + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Remove pending scan request +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +scnFsmRemovePendingMsg ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucSeqNum, + IN UINT_8 ucNetTypeIndex + ) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + P_MSG_HDR_T prPendingMsgHdr, prPendingMsgHdrNext, prRemoveMsgHdr = NULL; + P_LINK_ENTRY_T prRemoveLinkEntry = NULL; + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + /* traverse through rPendingMsgList for removal */ + LINK_FOR_EACH_ENTRY_SAFE(prPendingMsgHdr, + prPendingMsgHdrNext, + &(prScanInfo->rPendingMsgList), + rLinkEntry, + MSG_HDR_T) { + if(prPendingMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ + || prPendingMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ + || prPendingMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ + || prPendingMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ) { + P_MSG_SCN_SCAN_REQ prScanReqMsg = (P_MSG_SCN_SCAN_REQ)prPendingMsgHdr; + + if(ucSeqNum == prScanReqMsg->ucSeqNum && + ucNetTypeIndex == prScanReqMsg->ucNetTypeIndex) { + prRemoveLinkEntry = &(prScanReqMsg->rMsgHdr.rLinkEntry); + prRemoveMsgHdr = prPendingMsgHdr; + } + } + else if(prPendingMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ_V2 + || prPendingMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ_V2 + || prPendingMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ_V2 + || prPendingMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ_V2) { + P_MSG_SCN_SCAN_REQ_V2 prScanReqMsgV2 = (P_MSG_SCN_SCAN_REQ_V2)prPendingMsgHdr; + + if(ucSeqNum == prScanReqMsgV2->ucSeqNum && + ucNetTypeIndex == prScanReqMsgV2->ucNetTypeIndex) { + prRemoveLinkEntry = &(prScanReqMsgV2->rMsgHdr.rLinkEntry); + prRemoveMsgHdr = prPendingMsgHdr; + } + } + + if(prRemoveLinkEntry) { + /* generate scan-done event for caller */ + scnFsmGenerateScanDoneMsg(prAdapter, + ucSeqNum, + ucNetTypeIndex, + SCAN_STATUS_CANCELLED); + + /* remove from pending list */ + LINK_REMOVE_KNOWN_ENTRY(&(prScanInfo->rPendingMsgList), prRemoveLinkEntry); + cnmMemFree(prAdapter, prRemoveMsgHdr); + + break; + } + } + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +scnEventScanDone ( + IN P_ADAPTER_T prAdapter, + IN P_EVENT_SCAN_DONE prScanDone + ) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + // buffer empty channel information + if(prScanParam->eScanChannel == SCAN_CHANNEL_FULL + || prScanParam->eScanChannel == SCAN_CHANNEL_2G4) { + if(prScanDone->ucSparseChannelValid) { + prScanInfo->fgIsSparseChannelValid = TRUE; + prScanInfo->rSparseChannel.eBand = (ENUM_BAND_T)prScanDone->rSparseChannel.ucBand; + prScanInfo->rSparseChannel.ucChannelNum = prScanDone->rSparseChannel.ucChannelNum; + } + else { + prScanInfo->fgIsSparseChannelValid = FALSE; + } + } + + if(prScanInfo->eCurrentState == SCAN_STATE_SCANNING && + prScanDone->ucSeqNum == prScanParam->ucSeqNum) { + /* generate scan-done event for caller */ + scnFsmGenerateScanDoneMsg(prAdapter, + prScanParam->ucSeqNum, + (UINT_8)prScanParam->eNetTypeIndex, + SCAN_STATUS_DONE); + + /* switch to next pending scan */ + scnFsmSteps(prAdapter, SCAN_STATE_IDLE); + } + else { + DBGLOG(SCN, LOUD, ("Unexpected SCAN-DONE event: SeqNum = %d, Current State = %d\n", + prScanDone->ucSeqNum, + prScanInfo->eCurrentState)); + } + + return; +} /* end of scnEventScanDone */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +scnFsmGenerateScanDoneMsg ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucSeqNum, + IN UINT_8 ucNetTypeIndex, + IN ENUM_SCAN_STATUS eScanStatus + ) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + P_MSG_SCN_SCAN_DONE prScanDoneMsg; + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + prScanDoneMsg = (P_MSG_SCN_SCAN_DONE)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_DONE)); + if (!prScanDoneMsg) { + ASSERT(0); // Can't indicate SCAN FSM Complete + return; + } + + if(prScanParam->fgIsObssScan == TRUE) { + prScanDoneMsg->rMsgHdr.eMsgId = MID_SCN_RLM_SCAN_DONE; + } + else { + switch((ENUM_NETWORK_TYPE_INDEX_T)ucNetTypeIndex) { + case NETWORK_TYPE_AIS_INDEX: + prScanDoneMsg->rMsgHdr.eMsgId = MID_SCN_AIS_SCAN_DONE; + break; + +#if CFG_ENABLE_WIFI_DIRECT + case NETWORK_TYPE_P2P_INDEX: + prScanDoneMsg->rMsgHdr.eMsgId = MID_SCN_P2P_SCAN_DONE; + break; +#endif + +#if CFG_ENABLE_BT_OVER_WIFI + case NETWORK_TYPE_BOW_INDEX: + prScanDoneMsg->rMsgHdr.eMsgId = MID_SCN_BOW_SCAN_DONE; + break; +#endif + + default: + DBGLOG(SCN, LOUD, ("Unexpected Network Type: %d\n", ucNetTypeIndex)); + ASSERT(0); + break; + } + } + + prScanDoneMsg->ucSeqNum = ucSeqNum; + prScanDoneMsg->ucNetTypeIndex = ucNetTypeIndex; + prScanDoneMsg->eScanStatus = eScanStatus; + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prScanDoneMsg, + MSG_SEND_METHOD_BUF); + +} /* end of scnFsmGenerateScanDoneMsg() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Query for most sparse channel +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +scnQuerySparseChannel ( + IN P_ADAPTER_T prAdapter, + P_ENUM_BAND_T prSparseBand, + PUINT_8 pucSparseChannel + ) +{ + P_SCAN_INFO_T prScanInfo; + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + if(prScanInfo->fgIsSparseChannelValid == TRUE) { + if(prSparseBand) { + *prSparseBand = prScanInfo->rSparseChannel.eBand; + } + + if(pucSparseChannel) { + *pucSparseChannel = prScanInfo->rSparseChannel.ucChannelNum; + } + + return TRUE; + } + else { + return FALSE; + } +} + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/sec_fsm.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/sec_fsm.c new file mode 100755 index 000000000000..37d66653b473 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/sec_fsm.c @@ -0,0 +1,1306 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/mgmt/sec_fsm.c#1 $ +*/ + +/*! \file "sec_fsm.c" + \brief This is the file implement security check state machine. + + In security module, do the port control check after success join to an AP, + and the path to NORMAL TR, the state machine handle these state transition. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: sec_fsm.c $ + * + * 01 20 2012 cp.wu + * [ALPS00096191] [MT6620 Wi-Fi][Driver][Firmware] Porting to ALPS4.0_DEV branch + * sync to up-to-date changes including: + * 1. BOW bugfix + * 2. XLOG + * + * 11 24 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Adjust code for DBG and CONFIG_XLOG. + * + * 11 11 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * modify the xlog related code. + * + * 11 10 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * change the debug module level. + * + * 11 02 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Add XLOG related code and define. + * + * 03 29 2011 wh.su + * [WCXRP00000248] [MT6620 Wi-Fi][FW]Fixed the Klockwork error + * fixed the kclocwork error. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 01 26 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * . + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Fix Compile Error when DBG is disabled. + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. + * + * 09 29 2010 wh.su + * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue + * [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue. + * + * 09 24 2010 wh.su + * NULL + * [WCXRP00005002][MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 20 2010 wh.su + * NULL + * adding the eapol callback setting. + * + * 08 19 2010 wh.su + * NULL + * adding the tx pkt call back handle for countermeasure. + * + * 07 19 2010 wh.su + * + * fixed the compilng error at debug mode. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * modify some code for concurrent network. + * + * 06 19 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * consdier the concurrent network setting. + * + * 05 28 2010 wh.su + * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing + * fixed the ad-hoc wpa-none send non-encrypted frame issue. + * + * 05 24 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Refine authSendAuthFrame() for NULL STA_RECORD_T case and minimum deauth interval. + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW + * + * 04 13 2010 wh.su + * [BORA00000680][MT6620] Support the statistic for Microsoft os query + * fixed the Klocwork error and refine the class error message. + * + * 03 03 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * move the AIS specific variable for security to AIS specific structure. + * + * 03 03 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * Fixed the pre-authentication timer not correctly init issue, and modify the security related callback function prototype. + * + * 03 01 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * Refine the variable and parameter for security. + * + * 01 27 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * add and fixed some security function. + * + * 01 13 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * fixed the compiling warning + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * refine some code + * + * Dec 4 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * refine the code + * + * Dec 1 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * code refine + * + * Nov 23 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adjust the function name + * + * Nov 19 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adjust the state machine, to meet the firmware security design v1.1 + * + * Nov 18 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +#if CFG_RSN_MIGRATION + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +#if DBG +/*lint -save -e64 Type mismatch */ +static PUINT_8 apucDebugSecState[SEC_STATE_NUM] = { + (PUINT_8)DISP_STRING("SEC_STATE_INIT"), + (PUINT_8)DISP_STRING("SEC_STATE_INITIATOR_PORT_BLOCKED"), + (PUINT_8)DISP_STRING("SEC_STATE_RESPONDER_PORT_BLOCKED"), + (PUINT_8)DISP_STRING("SEC_STATE_CHECK_OK"), + (PUINT_8)DISP_STRING("SEC_STATE_SEND_EAPOL"), + (PUINT_8)DISP_STRING("SEC_STATE_SEND_DEAUTH"), + (PUINT_8)DISP_STRING("SEC_STATE_COUNTERMEASURE"), +}; +/*lint -restore */ +#endif /* DBG */ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do initialization of Security FSM and all variables in +* SEC_INFO_T. +* +* \param[in] prSta Pointer to the STA record +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +secFsmInit ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ) +{ + P_SEC_INFO_T prSecInfo; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + ASSERT(prSta); + + prSecInfo = &prSta->rSecInfo; + + #if 1 /* MT6620 */ + //At MT5921, is ok, but at MT6620, firmware base ASIC, the firmware + //will lost these data, thus, driver have to keep the wep material and + //setting to firmware while awake from D3. + #endif + + prSecInfo->eCurrentState = SEC_STATE_INIT; + + prSecInfo->fg2nd1xSend = FALSE; + prSecInfo->fgKeyStored = FALSE; + + if (IS_STA_IN_AIS(prSta)) { + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + prAisSpecBssInfo->u4RsnaLastMICFailTime = 0; + prAisSpecBssInfo->fgCheckEAPoLTxDone = FALSE; + + cnmTimerInitTimer(prAdapter, + &prAdapter->rWifiVar.rAisSpecificBssInfo.rRsnaEAPoLReportTimeoutTimer, + (PFN_MGMT_TIMEOUT_FUNC)secFsmEventEapolTxTimeout, + (UINT_32)prSta); + + cnmTimerInitTimer(prAdapter, + &prAdapter->rWifiVar.rAisSpecificBssInfo.rRsnaBlockTrafficTimer, + (PFN_MGMT_TIMEOUT_FUNC)secFsmEventEndOfCounterMeasure, + (UINT_32)prSta); + + } + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do uninitialization of Security FSM and all variables in +* SEC_INFO_T. +* +* \param[in] prSta Pointer to the STA record +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID /* whsu:Todo: */ +secFsmUnInit ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ) +{ + P_SEC_INFO_T prSecInfo; + + ASSERT(prSta); + + prSecInfo = &prSta->rSecInfo; + + prSecInfo->fg2nd1xSend = FALSE; + prSecInfo->fgKeyStored = FALSE; + + //nicPrivacyRemoveWlanTable(prSta->ucWTEntry); + + if (IS_STA_IN_AIS(prSta)) { + cnmTimerStopTimer(prAdapter, + &prAdapter->rWifiVar.rAisSpecificBssInfo.rRsnaEAPoLReportTimeoutTimer); + cnmTimerStopTimer(prAdapter, + &prAdapter->rWifiVar.rAisSpecificBssInfo.rRsnaBlockTrafficTimer); + } + +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do action part while in STATE transition of +* STANDBY to CHECK_OK. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - none +*/ +/*----------------------------------------------------------------------------*/ +__KAL_INLINE__ VOID +secFsmTrans_INIT_to_CHECK_OK ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ) +{ + secSetPortBlocked(prAdapter, prSta, FALSE); + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do action part while in STATE transition of +* INIT to INITIATOR_PORT_BLOCKED. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - none +*/ +/*----------------------------------------------------------------------------*/ +__KAL_INLINE__ VOID +secFsmTrans_INIT_to_INITIATOR_PORT_BLOCKED ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ) +{ + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do action part while in STATE transition of +* INIT to RESPONDER_PORT_BLOCKED. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - none +*/ +/*----------------------------------------------------------------------------*/ +__KAL_INLINE__ VOID +secFsmTrans_INIT_to_RESPONDER_PORT_BLOCKED ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ) +{ + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do action part while in STATE transition of +* INITIATOR_PORT_BLOCKED to CHECK_OK. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - none +*/ +/*----------------------------------------------------------------------------*/ +__KAL_INLINE__ VOID +secFsmTrans_INITIATOR_PORT_BLOCKED_to_CHECK_OK ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ) +{ + secSetPortBlocked(prAdapter, prSta, FALSE); + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do action part while in STATE transition of +* RESPONDER_PORT_BLOCKED to CHECK_OK. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - none +*/ +/*----------------------------------------------------------------------------*/ +__KAL_INLINE__ VOID +secFsmTrans_RESPONDER_PORT_BLOCKED_to_CHECK_OK ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ) +{ + secSetPortBlocked(prAdapter, prSta, FALSE); + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do action part while in STATE transition of +* CHECK_OK to SEND_EAPOL +* +* \param[in] prSta Pointer to the Sta record +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +__KAL_INLINE__ VOID +secFsmTrans_CHECK_OK_to_SEND_EAPOL ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ) +{ + + P_AIS_SPECIFIC_BSS_INFO_T prAisBssInfo; + + ASSERT(prAdapter); + + ASSERT(prSta); + + prAisBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + ASSERT(prAisBssInfo); + + if (!IS_STA_IN_AIS(prSta)) { + DBGLOG(RSN, INFO, ("Counter Measure should occur at AIS network!!\n")); + //ASSERT(0); + return; + } + + prAisBssInfo->fgCheckEAPoLTxDone = TRUE; + + //cnmTimerStartTimer(prAdapter, + // &prAisBssInfo->rRsnaEAPoLReportTimeoutTimer, + // SEC_TO_MSEC(EAPOL_REPORT_SEND_TIMEOUT_INTERVAL_SEC)); + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do action part while in STATE transition of +* SEND_EAPOL to SEND_DEAUTH. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - none +*/ +/*----------------------------------------------------------------------------*/ +__KAL_INLINE__ VOID +secFsmTrans_SEND_EAPOL_to_SEND_DEAUTH ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ) +{ + + if (!IS_STA_IN_AIS(prSta)) { + DBGLOG(RSN, INFO, ("Counter Measure should occur at AIS network!!\n")); + //ASSERT(0); + return; + } + + /* Compose deauth frame to AP, a call back function for tx done */ + if (authSendDeauthFrame(prAdapter, + prSta, + (P_SW_RFB_T)NULL, + REASON_CODE_MIC_FAILURE, + (PFN_TX_DONE_HANDLER)secFsmEventDeauthTxDone) != WLAN_STATUS_SUCCESS) { + ASSERT(FALSE); + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do action part while in STATE transition of +* SEND_DEAUTH to COUNTERMEASURE. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +__KAL_INLINE__ VOID +secFsmTrans_SEND_DEAUTH_to_COUNTERMEASURE ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ) +{ + ASSERT(prAdapter); + ASSERT(prSta); + + if (!IS_STA_IN_AIS(prSta)) { + DBGLOG(RSN, INFO, ("Counter Measure should occur at AIS network!!\n")); + //ASSERT(0); + return; + } + + //Start the 60 sec timer + cnmTimerStartTimer(prAdapter, + &prAdapter->rWifiVar.rAisSpecificBssInfo.rRsnaBlockTrafficTimer, + SEC_TO_MSEC(COUNTER_MEASURE_TIMEOUT_INTERVAL_SEC)); + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do action part while in STATE transition of +* SEND_DEAUTH to COUNTERMEASURE. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +__KAL_INLINE__ VOID +secFsmTrans_COUNTERMEASURE_to_INIT ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ) +{ + + //Clear the counter measure flag + return; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief The Core FSM engine of security module. +* +* \param[in] prSta Pointer to the Sta record +* \param[in] eNextState Enum value of next sec STATE +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +VOID +secFsmSteps ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta, + IN ENUM_SEC_STATE_T eNextState + ) +{ + P_SEC_INFO_T prSecInfo; + BOOLEAN fgIsTransition = (BOOLEAN)FALSE; + + ASSERT(prSta); + + prSecInfo = &prSta->rSecInfo; + ASSERT(prSecInfo); + + DEBUGFUNC("secFsmSteps"); + do { + /* Do entering Next State */ + prSecInfo->ePreviousState = prSecInfo->eCurrentState; + + /* Do entering Next State */ +#if CFG_SUPPORT_XLOG + DBGLOG(RSN, STATE, ("\n"MACSTR" [%d] TRANSITION: [%d] -> [%d]\n\n", + MAC2STR(prSta->aucMacAddr), + DBG_RSN_IDX, + prSecInfo->eCurrentState, + eNextState)); +#else + /* Do entering Next State */ + DBGLOG(RSN, STATE, ("\n"MACSTR" TRANSITION: [%s] -> [%s]\n\n", + MAC2STR(prSta->aucMacAddr), + apucDebugSecState[prSecInfo->eCurrentState], + apucDebugSecState[eNextState])); +#endif + prSecInfo->eCurrentState = eNextState; + + fgIsTransition = (BOOLEAN)FALSE; +#if 0 + /* Do tasks of the State that we just entered */ + switch (prSecInfo->eCurrentState) { + case SEC_STATE_INIT: + break; + case SEC_STATE_INITIATOR_PORT_BLOCKED: + break; + case SEC_STATE_RESPONDER_PORT_BLOCKED: + break; + case SEC_STATE_CHECK_OK: + break; + case SEC_STATE_SEND_EAPOL: + break; + case SEC_STATE_SEND_DEAUTH: + break; + case SEC_STATE_COUNTERMEASURE: + break; + default: + ASSERT(0); /* Make sure we have handle all STATEs */ + break; + } +#endif + } + while (fgIsTransition); + + return; + +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do initialization of Security FSM and all variables in +* SEC_INFO_T. +* +* \param[in] prSta Pointer to the Sta record +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +secFsmEventStart ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ) +{ + P_SEC_INFO_T prSecInfo; + BOOLEAN fgIsTransition = (BOOLEAN)FALSE; + ENUM_SEC_STATE_T eNextState; + + DBGLOG(RSN, TRACE, ("secFsmRunEventStart\n")); + + ASSERT(prSta); + + if (!prSta) + return; + + if (!IS_STA_IN_AIS(prSta)) + return; + + DBGLOG(RSN, TRACE, ("secFsmRunEventStart for sta "MACSTR" network %d\n", + MAC2STR(prSta->aucMacAddr), prSta->ucNetTypeIndex)); + + prSecInfo = (P_SEC_INFO_T)&prSta->rSecInfo; + + eNextState = prSecInfo->eCurrentState; + + secSetPortBlocked(prAdapter, prSta, TRUE); + + //prSta->fgTransmitKeyExist = FALSE; + //whsu:: nicPrivacySetStaDefaultWTIdx(prSta); + +#if 1 /* Since the 1x and key can set to firmware in order, always enter the check ok state */ + SEC_STATE_TRANSITION(prAdapter, prSta, INIT, CHECK_OK); +#else + if (IS_STA_IN_AIS(prSta->eStaType)) { + if (secRsnKeyHandshakeEnabled(prAdapter) == TRUE +#if CFG_SUPPORT_WAPI + || (prAdapter->rWifiVar.rConnSettings.fgWapiMode) +#endif + ) { + prSta->fgTransmitKeyExist = FALSE; + //nicPrivacyInitialize(prSta->ucNetTypeIndex); + SEC_STATE_TRANSITION(prAdapter, prSta, INIT, INITIATOR_PORT_BLOCKED); + } + else { + SEC_STATE_TRANSITION(prAdapter, prSta, INIT, CHECK_OK); + } + } +#if CFG_ENABLE_WIFI_DIRECT || CFG_ENABLE_BT_OVER_WIFI + #if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_BT_OVER_WIFI + else if ((prSta->eStaType == STA_TYPE_BOW_CLIENT) || + (prSta->eStaType == STA_TYPE_P2P_GC)) + #elif CFG_ENABLE_WIFI_DIRECT + else if (prSta->eStaType == STA_TYPE_P2P_GC) + #elif CFG_ENABLE_BT_OVER_WIFI + else if (prSta->eStaType == STA_TYPE_BOW_CLIENT) + #endif + { + SEC_STATE_TRANSITION(prAdapter, prSta, INIT, RESPONDER_PORT_BLOCKED); + } +#endif + else { + SEC_STATE_TRANSITION(prAdapter, prSta, INIT, INITIATOR_PORT_BLOCKED); + } +#endif + if (prSecInfo->eCurrentState != eNextState) { + secFsmSteps(prAdapter, prSta, eNextState); + } + + return; +} /* secFsmRunEventStart */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function called by reset procedure to force the sec fsm enter +* idle state +* +* \param[in] ucNetTypeIdx The Specific Network type index +* \param[in] prSta Pointer to the Sta record +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +secFsmEventAbort ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ) +{ + P_SEC_INFO_T prSecInfo; + + DBGLOG(RSN, TRACE, ("secFsmEventAbort for sta "MACSTR" network %d\n", + MAC2STR(prSta->aucMacAddr), prSta->ucNetTypeIndex)); + + ASSERT(prSta); + + if (!prSta) + return; + + if (!IS_STA_IN_AIS(prSta)) + return; + + prSecInfo = (P_SEC_INFO_T)&prSta->rSecInfo; + + prSta->fgTransmitKeyExist = FALSE; + + secSetPortBlocked(prAdapter, prSta, TRUE); + + if (prSecInfo == NULL) + return; + + if (IS_STA_IN_AIS(prSta)) { + + prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist = FALSE; + + if (prSecInfo->eCurrentState == SEC_STATE_SEND_EAPOL) { + if (prAdapter->rWifiVar.rAisSpecificBssInfo.fgCheckEAPoLTxDone == FALSE) { + DBGLOG(RSN, TRACE, ("EAPOL STATE not match the flag\n")); + //cnmTimerStopTimer(prAdapter, &prAdapter->rWifiVar.rAisSpecificBssInfo.rRsnaEAPoLReportTimeoutTimer); + } + } + } + prSecInfo->eCurrentState = SEC_STATE_INIT; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will indicate an Event of "2nd EAPoL Tx is sending" to Sec FSM. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +VOID +secFsmEvent2ndEapolTx ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ) +{ + P_SEC_INFO_T prSecInfo; + ENUM_SEC_STATE_T eNextState; + //BOOLEAN fgIsTransition = (BOOLEAN)FALSE; + + DEBUGFUNC("secFsmRunEvent2ndEapolTx"); + + ASSERT(prSta); + + prSecInfo = &prSta->rSecInfo; + eNextState = prSecInfo->eCurrentState; + +#if CFG_SUPPORT_XLOG + DBGLOG(RSN, TRACE, (MACSTR" Sec state [%d]\n", MAC2STR(prSta->aucMacAddr), prSecInfo->eCurrentState)); +#else + DBGLOG(RSN, TRACE, (MACSTR" Sec state %s\n", MAC2STR(prSta->aucMacAddr), + apucDebugSecState[prSecInfo->eCurrentState])); +#endif + + switch(prSecInfo->eCurrentState) { + case SEC_STATE_INITIATOR_PORT_BLOCKED : + case SEC_STATE_CHECK_OK : + prSecInfo->fg2nd1xSend = TRUE; + break; + default: +#if CFG_SUPPORT_XLOG + DBGLOG(RSN, WARN, ("Rcv 2nd EAPoL at [%d]\n", prSecInfo->eCurrentState)); +#else + DBGLOG(RSN, WARN, ("Rcv 2nd EAPoL at %s\n", apucDebugSecState[prSecInfo->eCurrentState])); +#endif + break; + } + + if (prSecInfo->eCurrentState != eNextState) { + secFsmSteps(prAdapter, prSta, eNextState); + } + + return; + +}/* secFsmRunEvent2ndEapolTx */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will indicate an Event of "4th EAPoL Tx is Tx done" to Sec FSM. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +VOID +secFsmEvent4ndEapolTxDone ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ) +{ + P_SEC_INFO_T prSecInfo; + ENUM_SEC_STATE_T eNextState; + BOOLEAN fgIsTransition = (BOOLEAN)FALSE; + P_CMD_802_11_KEY prStoredKey; + + DEBUGFUNC("secFsmRunEvent4ndEapolTx"); + + ASSERT(prSta); + + prSecInfo = &prSta->rSecInfo; + eNextState = prSecInfo->eCurrentState; + +#if CFG_SUPPORT_XLOG + DBGLOG(RSN, TRACE, (MACSTR " Sec state [%d]\n", MAC2STR(prSta->aucMacAddr), prSecInfo->eCurrentState)); +#else + DBGLOG(RSN, TRACE, (MACSTR " Sec state %s\n", MAC2STR(prSta->aucMacAddr), + apucDebugSecState[prSecInfo->eCurrentState])); +#endif + + switch(prSecInfo->eCurrentState) { + case SEC_STATE_INITIATOR_PORT_BLOCKED : + case SEC_STATE_CHECK_OK : + prSecInfo->fg2nd1xSend = FALSE; + if (prSecInfo->fgKeyStored) { + prStoredKey = (P_CMD_802_11_KEY)prSecInfo->aucStoredKey; + + //prSta = rxmLookupStaRecIndexFromTA(prStoredKey->aucPeerAddr); + //if (nicPrivacySetKeyEntry(prStoredKey, prSta->ucWTEntry) == FALSE) + // DBGLOG(RSN, WARN, ("nicPrivacySetKeyEntry() fail,..\n")); + + //key update + prSecInfo->fgKeyStored = FALSE; + prSta->fgTransmitKeyExist = TRUE; + } + if (prSecInfo->eCurrentState == SEC_STATE_INITIATOR_PORT_BLOCKED) { + SEC_STATE_TRANSITION(prAdapter, prSta, INITIATOR_PORT_BLOCKED, CHECK_OK); + } + break; + default: + +#if CFG_SUPPORT_XLOG + DBGLOG(RSN, WARN, ("Rcv thh EAPoL Tx done at [%d]\n", prSecInfo->eCurrentState)); +#else + DBGLOG(RSN, WARN, ("Rcv thh EAPoL Tx done at %s\n", apucDebugSecState[prSecInfo->eCurrentState])); +#endif + break; + } + + if (prSecInfo->eCurrentState != eNextState) { + secFsmSteps(prAdapter, prSta, eNextState); + } + + return; + +}/* secFsmRunEvent4ndEapolTx */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will indicate an Event of "Pairwise key installed" to SEC FSM. +* +* \param[in] prSta Pointer to the Sta record +* +* \retval TRUE The key can be installed to HW +* \retval FALSE The kay conflict with the current key, abort it +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +secFsmEventPTKInstalled ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ) +{ + P_SEC_INFO_T prSecInfo; + ENUM_SEC_STATE_T eNextState; + BOOLEAN fgStatus = TRUE; + BOOLEAN fgIsTransition = (BOOLEAN)FALSE; + + ASSERT(prSta); + + prSecInfo = &prSta->rSecInfo; + if (prSecInfo == NULL) + return TRUE; /* Not PTK */ + +#if CFG_SUPPORT_XLOG + DBGLOG(RSN, TRACE, (MACSTR " Sec state [%d]\n", MAC2STR(prSta->aucMacAddr), prSecInfo->eCurrentState)); +#else + DBGLOG(RSN, TRACE, (MACSTR " Sec state %s\n", MAC2STR(prSta->aucMacAddr), + apucDebugSecState[prSecInfo->eCurrentState])); +#endif + + eNextState = prSecInfo->eCurrentState; + + switch(prSecInfo->eCurrentState) { + case SEC_STATE_INIT: + /* Legacy wep, wpa-none */ + break; + + case SEC_STATE_INITIATOR_PORT_BLOCKED: + if (prSecInfo->fg2nd1xSend) { + } + else { + SEC_STATE_TRANSITION(prAdapter, prSta, INITIATOR_PORT_BLOCKED, CHECK_OK); + } + break; + + case SEC_STATE_RESPONDER_PORT_BLOCKED: + SEC_STATE_TRANSITION(prAdapter, prSta, RESPONDER_PORT_BLOCKED, CHECK_OK); + break; + + + case SEC_STATE_CHECK_OK: + break; + + default: + fgStatus = FALSE; + break; + } + + if (prSecInfo->eCurrentState != eNextState) { + secFsmSteps(prAdapter, prSta, eNextState); + } + + return fgStatus; + +} /* end of secFsmRunEventPTKInstalled() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will indicate an Event of "Counter Measure" to SEC FSM. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +VOID +secFsmEventStartCounterMeasure ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta + ) +{ + P_SEC_INFO_T prSecInfo; + ENUM_SEC_STATE_T eNextState; + BOOLEAN fgIsTransition = (BOOLEAN)FALSE; + + DEBUGFUNC("secFsmRunEventStartCounterMeasure"); + + ASSERT(prSta); + + if (!IS_STA_IN_AIS(prSta)) { + DBGLOG(RSN, INFO, ("Counter Measure should occur at AIS network!!\n")); + //ASSERT(0); + return; + } + + prSecInfo = &prSta->rSecInfo; + + eNextState = prSecInfo->eCurrentState; + +#if CFG_SUPPORT_XLOG + DBGLOG(RSN, TRACE, (MACSTR " Sec state [%d]\n", MAC2STR(prSta->aucMacAddr), prSecInfo->eCurrentState)); +#else + DBGLOG(RSN, TRACE, (MACSTR " Sec state %s\n", MAC2STR(prSta->aucMacAddr), + apucDebugSecState[prSecInfo->eCurrentState])); +#endif + + prAdapter->rWifiVar.rAisSpecificBssInfo.u4RsnaLastMICFailTime = 0; + + switch(prSecInfo->eCurrentState) { + case SEC_STATE_CHECK_OK: + { + prAdapter->rWifiVar.rAisSpecificBssInfo.fgCounterMeasure = TRUE; + + // dls port control + SEC_STATE_TRANSITION(prAdapter, prSta, CHECK_OK, SEND_EAPOL); + } + break; + + default: + break; + } + + /* Call arbFsmSteps() when we are going to change ARB STATE */ + if (prSecInfo->eCurrentState != eNextState) { + secFsmSteps(prAdapter, prSta, eNextState); + } + + return; + +} /* secFsmRunEventStartCounterMeasure */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will indicate an Event of "802.1x EAPoL Tx Done" to Sec FSM. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +VOID +secFsmEventEapolTxDone ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus + ) +{ + P_SEC_INFO_T prSecInfo; + ENUM_SEC_STATE_T eNextState; + BOOLEAN fgIsTransition = (BOOLEAN)FALSE; + P_AIS_SPECIFIC_BSS_INFO_T prAisBssInfo; + + DEBUGFUNC("secFsmRunEventEapolTxDone"); + + ASSERT(prStaRec); + + if (rTxDoneStatus != TX_RESULT_SUCCESS) { + DBGLOG(RSN, INFO, ("Error EAPoL fram fail to send!!\n")); + //ASSERT(0); + return; + } + + if (!IS_STA_IN_AIS(prStaRec)) { + DBGLOG(RSN, INFO, ("Counter Measure should occur at AIS network!!\n")); + //ASSERT(0); + return; + } + + prAisBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + ASSERT(prAisBssInfo); + + prSecInfo = &prStaRec->rSecInfo; + eNextState = prSecInfo->eCurrentState; + +#if CFG_SUPPORT_XLOG + DBGLOG(RSN, TRACE, (MACSTR " Sec state [%d]\n", MAC2STR(prStaRec->aucMacAddr), prSecInfo->eCurrentState)); +#else + DBGLOG(RSN, TRACE, (MACSTR " Sec state %s\n", MAC2STR(prStaRec->aucMacAddr), + apucDebugSecState[prSecInfo->eCurrentState])); +#endif + + switch(prSecInfo->eCurrentState) { + case SEC_STATE_SEND_EAPOL: + if (prAisBssInfo->fgCheckEAPoLTxDone == FALSE) { + ASSERT(0); + } + + prAisBssInfo->fgCheckEAPoLTxDone = FALSE; + //cnmTimerStopTimer(prAdapter, &prAisBssInfo->rRsnaEAPoLReportTimeoutTimer); + + SEC_STATE_TRANSITION(prAdapter, prStaRec, SEND_EAPOL, SEND_DEAUTH); + break; + default: + break; + } + + if (prSecInfo->eCurrentState != eNextState) { + secFsmSteps(prAdapter, prStaRec, eNextState); + } + + return; + +}/* secFsmRunEventEapolTxDone */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will indicate an Event of "Deauth frame Tx Done" to Sec FSM. +* +* \param[in] pMsduInfo Pointer to the Msdu Info +* \param[in] rStatus The Tx done status +* +* \return - +* +* \note after receive deauth frame, callback function call this +*/ +/*----------------------------------------------------------------------------*/ +VOID +secFsmEventDeauthTxDone ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus + ) +{ + P_STA_RECORD_T prStaRec; + P_SEC_INFO_T prSecInfo; + ENUM_SEC_STATE_T eNextState; + BOOLEAN fgIsTransition = (BOOLEAN)FALSE; + + DEBUGFUNC("secFsmRunEventDeauthTxDone"); + + ASSERT(prMsduInfo); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + ASSERT(prStaRec); + + if (!prStaRec) + return; + + if (!IS_STA_IN_AIS(prStaRec)) { + DBGLOG(RSN, INFO, ("Counter Measure should occur at AIS network!!\n")); + //ASSERT(0); + return; + } + + prSecInfo = (P_SEC_INFO_T)&prStaRec->rSecInfo; + +#if CFG_SUPPORT_XLOG + DBGLOG(RSN, TRACE, (MACSTR " Sec state [%d]\n", MAC2STR(prStaRec->aucMacAddr), prSecInfo->eCurrentState)); +#else + DBGLOG(RSN, TRACE, (MACSTR " Sec state %s\n", MAC2STR(prStaRec->aucMacAddr), + apucDebugSecState[prSecInfo->eCurrentState])); +#endif + + switch(prSecInfo->eCurrentState) { + case SEC_STATE_SEND_DEAUTH: + + DBGLOG(RSN, TRACE, ("Set timer %d\n", COUNTER_MEASURE_TIMEOUT_INTERVAL_SEC)); + + SEC_STATE_TRANSITION(prAdapter, prStaRec, SEND_DEAUTH, COUNTERMEASURE); + + break; + + default: + ASSERT(0); + break; + } + + return; +}/* secFsmRunEventDeauthTxDone */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will check the eapol error frame fail to send issue. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +VOID +secFsmEventEapolTxTimeout ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Parm + ) +{ + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("secFsmRunEventEapolTxTimeout"); + + prStaRec = (P_STA_RECORD_T)u4Parm; + + ASSERT(prStaRec); + + /* Todo:: How to handle the Eapol Error fail to send case? */ + ASSERT(0); + + return; + +}/* secFsmEventEapolTxTimeout */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will stop the counterMeasure duration. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +VOID +secFsmEventEndOfCounterMeasure ( + IN P_ADAPTER_T prAdapter, + UINT_32 u4Parm + ) +{ + P_STA_RECORD_T prSta; + P_SEC_INFO_T prSecInfo; + ENUM_SEC_STATE_T eNextState; + BOOLEAN fgIsTransition = (BOOLEAN)FALSE; + + DEBUGFUNC("secFsmRunEventEndOfCounterMeasure"); + + prSta = (P_STA_RECORD_T)u4Parm; + + ASSERT(prSta); + + if (!IS_STA_IN_AIS(prSta)) { + DBGLOG(RSN, INFO, ("Counter Measure should occur at AIS network!!\n")); + //ASSERT(0); + return; + } + + prSecInfo = &prSta->rSecInfo; + eNextState = prSecInfo->eCurrentState; + +#if CFG_SUPPORT_XLOG + DBGLOG(RSN, TRACE, (MACSTR " Sec state [%d]\n", MAC2STR(prSta->aucMacAddr), prSecInfo->eCurrentState)); +#else + DBGLOG(RSN, TRACE, (MACSTR " Sec state %s\n", MAC2STR(prSta->aucMacAddr), + apucDebugSecState[prSecInfo->eCurrentState])); +#endif + + switch(prSecInfo->eCurrentState) { + case SEC_STATE_SEND_DEAUTH: + { + prAdapter->rWifiVar.rAisSpecificBssInfo.fgCounterMeasure = FALSE; + + SEC_STATE_TRANSITION(prAdapter, prSta, COUNTERMEASURE, INIT); + } + break; + + default: + ASSERT(0); + } + + /* Call arbFsmSteps() when we are going to change ARB STATE */ + if (prSecInfo->eCurrentState != eNextState) { + secFsmSteps(prAdapter, prSta, eNextState); + } + + return; +}/* end of secFsmRunEventEndOfCounterMeasure */ +#endif diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/swcr.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/swcr.c new file mode 100755 index 000000000000..41e4e7548c2e --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/swcr.c @@ -0,0 +1,1213 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/mgmt/swcr.c#2 $ +*/ + +/*! \file "swcr.c" + \brief + +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: swcr.c $ + * + * 01 15 2012 yuche.tsai + * NULL + * Fix wrong basic rate issue. + * + * 11 22 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * keep debug counter setting after wake up. + * + * 11 19 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Fix initialize the prTxCtrol + * + * 11 19 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Add xlog for tx + * + * 11 18 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Fix xlog format to hex format + * + * 11 15 2011 cm.chang + * NULL + * Fix compiling warning + * + * 11 11 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * fix debug counters of rx in driver. + * + * 11 11 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * reform debug formt. + * + * 11 11 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add txbcn count into xlog. + * + * 11 10 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters of ar and bb for xlog. + * + * 11 10 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Modify the QM xlog level and remove LOG_FUNC. + * + * 11 08 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add Xlog for PS. + * + * 11 04 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters and periodically dump counters for Xlog debugging. + * + * 11 03 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * change the DBGLOG for "\n" and "\r\n". LABEL to LOUD for XLOG + * + * 06 27 2011 tsaiyuan.hsu + * [WCXRP00000816] [MT6620 Wi-Fi][Driver] add control to enable rx data dump or not + * add control to enable rx data dump by packet type. + * + * 05 11 2011 eddie.chen + * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet + * Fix dest type when GO packet copying. + * + * 05 09 2011 eddie.chen + * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet + * Check free number before copying broadcast packet. + * + * 04 14 2011 eddie.chen + * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning + * Check the SW RFB free. Fix the compile warning.. + * + * 04 12 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix the sta index in processing security frame + * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 + * Add debug message. + * + * 03 28 2011 eddie.chen + * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning + * Fix Klocwork warning. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 15 2011 eddie.chen + * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter + * Add sw debug counter for QM. + * + * 01 11 2011 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, +Add per station flow control when STA is in PS + + * Add swcr for test. + * +* +*/ + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +#if CFG_SUPPORT_SWCR + +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wformat" +#endif +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +#if 0 +extern SWCR_MAP_ENTRY_T g_arRlmArSwCrMap[]; +SWCR_MOD_MAP_ENTRY_T g_arSwCrAllMaps[] = { + { SWCR_MAP_NUM(g_arRlmArSwCrMap), g_arRlmArSwCrMap}, /* 0x00nn */ + {0,NULL} +}; +#endif + +VOID swCtrlCmdCategory0(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0,UINT_8 ucOpt1); +VOID swCtrlCmdCategory1(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0,UINT_8 ucOpt1); +VOID testPsCmdCategory0(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0,UINT_8 ucOpt1); +VOID testPsCmdCategory1(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0,UINT_8 ucOpt1); +VOID swCtrlSwCr(P_ADAPTER_T prAdapter, UINT_8 ucRead, UINT_16 u2Addr, UINT_32 *pu4Data); + +/* Support Debug */ +VOID swCrDebugCheck(P_ADAPTER_T prAdapter, P_CMD_SW_DBG_CTRL_T prCmdSwCtrl); +VOID swCrDebugCheckTimeout( + IN P_ADAPTER_T prAdapter, + UINT_32 u4Param); +VOID swCrDebugQuery( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ); +VOID swCrDebugQueryTimeout( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo); + +UINT_32 g_au4SwCr[SWCR_CR_NUM]; /*: 0: command other: data */ + +static TIMER_T g_rSwcrDebugTimer; +static BOOLEAN g_fgSwcrDebugTimer = FALSE; +static UINT_32 g_u4SwcrDebugCheckTimeout = 0; +static ENUM_SWCR_DBG_TYPE_T g_ucSwcrDebugCheckType = 0; +static UINT_32 g_u4SwcrDebugFrameDumpType = 0; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +#define TEST_PS 1 + +const static PFN_CMD_RW_T g_arSwCtrlCmd[] ={ + swCtrlCmdCategory0, + swCtrlCmdCategory1 +#if TEST_PS + , testPsCmdCategory0 + , testPsCmdCategory1 +#endif + +}; + + +const PFN_SWCR_RW_T g_arSwCrModHandle[] = { + swCtrlSwCr, + NULL +}; + + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +enum { + SWCTRL_MAGIC, + SWCTRL_DEBUG, + SWCTRL_WIFI_VAR, + SWCTRL_ENABLE_INT, + SWCTRL_DISABLE_INT, + SWCTRL_TXM_INFO, + SWCTRL_RXM_INFO, + SWCTRL_DUMP_BSS, + SWCTRL_QM_INFO, + SWCTRL_DUMP_ALL_QUEUE_LEN, + SWCTRL_DUMP_MEM, + SWCTRL_TX_CTRL_INFO, + SWCTRL_DUMP_QUEUE, + SWCTRL_DUMP_QM_DBG_CNT, + SWCTRL_QM_DBG_CNT, + SWCTRL_RX_PKTS_DUMP, + SWCTRL_CATA0_INDEX_NUM +}; + +enum { + SWCTRL_STA_INFO, + SWCTRL_DUMP_STA, + SWCTRL_STA_QUE_INFO, + SWCTRL_CATA1_INDEX_NUM +}; + + + +#if TEST_PS +enum { + TEST_PS_MAGIC, + TEST_PS_SETUP_BSS, + TEST_PS_ENABLE_BEACON, + TEST_PS_TRIGGER_BMC, + TEST_PS_SEND_NULL, + TEST_PS_BUFFER_BMC, + TEST_PS_UPDATE_BEACON, + TEST_PS_CATA0_INDEX_NUM +}; + +enum { + TEST_PS_STA_PS, + TEST_PS_STA_ENTER_PS, + TEST_PS_STA_EXIT_PS, + TEST_PS_STA_TRIGGER_PSPOLL, + TEST_PS_STA_TRIGGER_FRAME, + TEST_PS_CATA1_INDEX_NUM +}; +#endif + + + + + +#define _SWCTRL_MAGIC 0x66201642 + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +void dumpQueue(P_ADAPTER_T prAdapter) +{ + + P_TX_CTRL_T prTxCtrl; + P_QUE_MGT_T prQM; + P_GLUE_INFO_T prGlueInfo; + UINT_32 i; + UINT_32 j; + + + DEBUGFUNC("dumpQueue"); + + prTxCtrl = &prAdapter->rTxCtrl; + prQM = &prAdapter->rQM; + prGlueInfo = prAdapter->prGlueInfo; + + for(i = TC0_INDEX; i<=TC5_INDEX; i++) { + DBGLOG(SW4, INFO,( "TC %u\n",i)); + DBGLOG(SW4, INFO,( "Max %u Free %u\n", + prTxCtrl->rTc.aucMaxNumOfBuffer[i], prTxCtrl->rTc.aucFreeBufferCount[i])); + + DBGLOG(SW4, INFO,("Average %u minReserved %u CurrentTcResource %u GuaranteedTcResource %u\n", + QM_GET_TX_QUEUE_LEN(prAdapter, i), + prQM->au4MinReservedTcResource[i], + prQM->au4CurrentTcResource[i], + prQM->au4GuaranteedTcResource[i])); + + } + + + for(i = 0; iau4HeadStaRecIndex[i],prQM->au4ForwardCount[i])); + } + + DBGLOG(SW4, INFO,( "BMC or unknown TxQueue Len %u\n",prQM->arTxQueue[0].u4NumElem)); + DBGLOG(SW4, INFO,( "Pending %d\n",prGlueInfo->i4TxPendingFrameNum)); + DBGLOG(SW4, INFO,( "Pending Security %d\n",prGlueInfo->i4TxPendingSecurityFrameNum)); +#if defined(LINUX) + for(i=0;i<4;i++){ + for(j=0;jai4TxPendingFrameNumPerQueue[i][j])); + } + } +#endif + + DBGLOG(SW4, INFO,( " rFreeSwRfbList %u\n", prAdapter->rRxCtrl.rFreeSwRfbList.u4NumElem)); + DBGLOG(SW4, INFO,( " rReceivedRfbList %u\n", prAdapter->rRxCtrl.rReceivedRfbList.u4NumElem)); + DBGLOG(SW4, INFO,( " rIndicatedRfbList %u\n", prAdapter->rRxCtrl.rIndicatedRfbList.u4NumElem)); + DBGLOG(SW4, INFO,( " ucNumIndPacket %u\n", prAdapter->rRxCtrl.ucNumIndPacket)); + DBGLOG(SW4, INFO,( " ucNumRetainedPacket %u\n", prAdapter->rRxCtrl.ucNumRetainedPacket)); + + +} + + +void dumpSTA(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec) +{ + UINT_8 ucWTEntry; + UINT_32 i; + P_BSS_INFO_T prBssInfo; + + DEBUGFUNC("dumpSTA"); + + ASSERT(prStaRec); + ucWTEntry = prStaRec->ucWTEntry; + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; + ASSERT(prBssInfo); + + DBGLOG(SW4, INFO,("Mac address: " MACSTR " Rcpi %u" "\n", MAC2STR(prStaRec->aucMacAddr),prStaRec->ucRCPI)); + + DBGLOG(SW4, INFO,("Idx %u Wtbl %u Used %u State %u Bss Phy 0x%x Sta DesiredPhy 0x%x\n", + prStaRec->ucIndex, ucWTEntry, + prStaRec->fgIsInUse,prStaRec->ucStaState, + prBssInfo->ucPhyTypeSet, + prStaRec->ucDesiredPhyTypeSet)); + + DBGLOG(SW4, INFO,("Sta Operation 0x%x DesiredNontHtRateSet 0x%x Mcs 0x%x u2HtCapInfo 0x%x\n", + prStaRec->u2OperationalRateSet,prStaRec->u2DesiredNonHTRateSet,prStaRec->ucMcsSet, prStaRec->u2HtCapInfo)); + + + for(i = 0; iarTxQueue[i].u4NumElem)); + } + + DBGLOG(SW4, INFO, ("BmpDeliveryAC %x\n",prStaRec->ucBmpDeliveryAC)); + DBGLOG(SW4, INFO, ("BmpTriggerAC %x\n",prStaRec->ucBmpTriggerAC)); + DBGLOG(SW4, INFO, ("UapsdSpSupproted %u\n",prStaRec->fgIsUapsdSupported)); + DBGLOG(SW4, INFO, ("IsQoS %u\n",prStaRec->fgIsQoS)); + DBGLOG(SW4, INFO, ("AssocId %u\n",prStaRec->u2AssocId)); + + DBGLOG(SW4, INFO, ("fgIsInPS %u\n",prStaRec->fgIsInPS)); + DBGLOG(SW4, INFO, ("ucFreeQuota %u\n",prStaRec->ucFreeQuota)); + DBGLOG(SW4, INFO, ("ucFreeQuotaForDelivery %u\n",prStaRec->ucFreeQuotaForDelivery)); + DBGLOG(SW4, INFO, ("ucFreeQuotaForNonDelivery %u\n",prStaRec->ucFreeQuotaForNonDelivery)); + + +#if 0 + DBGLOG(SW4, INFO, ("IsQmmSup %u\n",prStaRec->fgIsWmmSupported)); + DBGLOG(SW4, INFO, ("IsUapsdSup %u\n",prStaRec->fgIsUapsdSupported)); + DBGLOG(SW4, INFO, ("AvailabaleDeliverPkts %u\n",prStaRec->ucAvailableDeliverPkts)); + DBGLOG(SW4, INFO, ("BmpDeliverPktsAC %u\n",prStaRec->u4BmpDeliverPktsAC)); + DBGLOG(SW4, INFO, ("BmpBufferAC %u\n",prStaRec->u4BmpBufferAC)); + DBGLOG(SW4, INFO, ("BmpNonDeliverPktsAC %u\n",prStaRec->u4BmpNonDeliverPktsAC)); +#endif + + for(i=0;iaprRxReorderParamRefTbl[i]){ + DBGLOG(SW4, INFO,("RxReorder fgIsValid: %u\n",prStaRec->aprRxReorderParamRefTbl[i]->fgIsValid)); + DBGLOG(SW4, INFO,("RxReorder Tid: %u\n",prStaRec->aprRxReorderParamRefTbl[i]->ucTid)); + DBGLOG(SW4, INFO,("RxReorder rReOrderQue Len: %u\n", prStaRec->aprRxReorderParamRefTbl[i]->rReOrderQue.u4NumElem)); + DBGLOG(SW4, INFO,("RxReorder WinStart: %u\n", prStaRec->aprRxReorderParamRefTbl[i]->u2WinStart)); + DBGLOG(SW4, INFO,("RxReorder WinEnd: %u\n", prStaRec->aprRxReorderParamRefTbl[i]->u2WinEnd)); + DBGLOG(SW4, INFO,("RxReorder WinSize: %u\n", prStaRec->aprRxReorderParamRefTbl[i]->u2WinSize)); + } + } + +} + + +VOID dumpBss(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) +{ + + DBGLOG(SW4, INFO, ("SSID %s\n",prBssInfo->aucSSID)); + DBGLOG(SW4, INFO, ("OWN " MACSTR"\n",MAC2STR(prBssInfo->aucOwnMacAddr))); + DBGLOG(SW4, INFO, ("BSSID " MACSTR"\n",MAC2STR(prBssInfo->aucBSSID))); + DBGLOG(SW4, INFO, ("ucNetTypeIndex %u\n",prBssInfo->ucNetTypeIndex)); + DBGLOG(SW4, INFO, ("eConnectionState %u\n",prBssInfo->eConnectionState)); + DBGLOG(SW4, INFO, ("eCurrentOPMode %u\n",prBssInfo->eCurrentOPMode)); + DBGLOG(SW4, INFO, ("fgIsQBSS %u\n",prBssInfo->fgIsQBSS)); + DBGLOG(SW4, INFO, ("fgIsShortPreambleAllowed %u\n",prBssInfo->fgIsShortPreambleAllowed)); + DBGLOG(SW4, INFO, ("fgUseShortPreamble %u\n",prBssInfo->fgUseShortPreamble)); + DBGLOG(SW4, INFO, ("fgUseShortSlotTime %u\n",prBssInfo->fgUseShortSlotTime)); + DBGLOG(SW4, INFO, ("ucNonHTBasicPhyType %x\n",prBssInfo->ucNonHTBasicPhyType)); + DBGLOG(SW4, INFO, ("u2OperationalRateSet %x\n",prBssInfo->u2OperationalRateSet)); + DBGLOG(SW4, INFO, ("u2BSSBasicRateSet %x\n",prBssInfo->u2BSSBasicRateSet)); + DBGLOG(SW4, INFO, ("ucPhyTypeSet %x\n",prBssInfo->ucPhyTypeSet)); + DBGLOG(SW4, INFO, ("rStaRecOfClientList %d\n",prBssInfo->rStaRecOfClientList.u4NumElem)); + DBGLOG(SW4, INFO, ("u2CapInfo %x\n",prBssInfo->u2CapInfo)); + DBGLOG(SW4, INFO, ("u2ATIMWindow %x\n",prBssInfo->u2ATIMWindow)); + DBGLOG(SW4, INFO, ("u2AssocId %x\n",prBssInfo->u2AssocId)); + DBGLOG(SW4, INFO, ("ucDTIMPeriod %x\n",prBssInfo->ucDTIMPeriod)); + DBGLOG(SW4, INFO, ("ucDTIMCount %x\n",prBssInfo->ucDTIMCount)); + DBGLOG(SW4, INFO, ("fgIsNetAbsent %x\n", prBssInfo->fgIsNetAbsent)); + DBGLOG(SW4, INFO, ("eBand %d\n", prBssInfo->eBand)); + DBGLOG(SW4, INFO, ("ucPrimaryChannel %d\n", prBssInfo->ucPrimaryChannel)); + DBGLOG(SW4, INFO, ("ucHtOpInfo1 %d\n", prBssInfo->ucHtOpInfo1)); + DBGLOG(SW4, INFO, ("ucHtOpInfo2 %d\n", prBssInfo->u2HtOpInfo2)); + DBGLOG(SW4, INFO, ("ucHtOpInfo3 %d\n", prBssInfo->u2HtOpInfo3)); + DBGLOG(SW4, INFO, ("fgErpProtectMode %d\n", prBssInfo->fgErpProtectMode)); + DBGLOG(SW4, INFO, ("eHtProtectMode %d\n", prBssInfo->eHtProtectMode)); + DBGLOG(SW4, INFO, ("eGfOperationMode %d\n", prBssInfo->eGfOperationMode)); + DBGLOG(SW4, INFO, ("eRifsOperationMode %d\n", prBssInfo->eRifsOperationMode)); + DBGLOG(SW4, INFO, ("fgObssErpProtectMode %d\n", prBssInfo->fgObssErpProtectMode)); + DBGLOG(SW4, INFO, ("eObssHtProtectMode %d\n", prBssInfo->eObssHtProtectMode)); + DBGLOG(SW4, INFO, ("eObssGfProtectMode %d\n", prBssInfo->eObssGfOperationMode)); + DBGLOG(SW4, INFO, ("fgObssRifsOperationMode %d\n", prBssInfo->fgObssRifsOperationMode)); + DBGLOG(SW4, INFO, ("fgAssoc40mBwAllowed %d\n", prBssInfo->fgAssoc40mBwAllowed)); + DBGLOG(SW4, INFO, ("fg40mBwAllowed %d\n", prBssInfo->fg40mBwAllowed)); + DBGLOG(SW4, INFO, ("eBssSCO %d\n", prBssInfo->eBssSCO)); + + +} + + + +VOID swCtrlCmdCategory0(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0,UINT_8 ucOpt1) +{ + UINT_8 ucIndex,ucRead; + UINT_32 i; + + DEBUGFUNC("swCtrlCmdCategory0"); + + SWCR_GET_RW_INDEX(ucAction,ucRead,ucIndex); + + i=0; + + if(ucIndex>=SWCTRL_CATA0_INDEX_NUM) return; + + if(ucRead == SWCR_WRITE) { + switch(ucIndex) { + case SWCTRL_DEBUG: +#if DBG + aucDebugModule[ucOpt0] = (UINT_8)g_au4SwCr[1]; +#endif + break; + case SWCTRL_WIFI_VAR: + break; + +#if QM_DEBUG_COUNTER + case SWCTRL_DUMP_QM_DBG_CNT: + for(i=0;irQM.au4QmDebugCounters[i] = 0; + } + break; + case SWCTRL_QM_DBG_CNT: + prAdapter->rQM.au4QmDebugCounters[ucOpt0] = g_au4SwCr[1]; + + break; +#endif +#if CFG_RX_PKTS_DUMP + case SWCTRL_RX_PKTS_DUMP: + //DBGLOG(SW4, INFO,("SWCTRL_RX_PKTS_DUMP: mask %x\n", g_au4SwCr[1])); + prAdapter->rRxCtrl.u4RxPktsDumpTypeMask = g_au4SwCr[1]; + break; +#endif + default: + break; + } + } + else { + switch(ucIndex) { + case SWCTRL_DEBUG: +#if DBG + g_au4SwCr[1] = aucDebugModule[ucOpt0] ; +#endif + break; + case SWCTRL_MAGIC: + g_au4SwCr[1] = _SWCTRL_MAGIC ; + DBGLOG(SW4, INFO,("BUILD TIME: %s %s\n", __DATE__, __TIME__)); + break; + case SWCTRL_QM_INFO: + { + P_QUE_MGT_T prQM = &prAdapter->rQM; + switch(ucOpt0) { + case 0: + g_au4SwCr[1] = (QM_GET_TX_QUEUE_LEN(prAdapter, ucOpt1)) ; + g_au4SwCr[2] = prQM->au4MinReservedTcResource[ucOpt1] ; + g_au4SwCr[3] = prQM->au4CurrentTcResource[ucOpt1]; + g_au4SwCr[4] = prQM->au4GuaranteedTcResource[ucOpt1]; + break; + + case 1: + g_au4SwCr[1] = prQM->au4ForwardCount[ucOpt1]; + g_au4SwCr[2] = prQM->au4HeadStaRecIndex[ucOpt1]; + break; + + case 2: + g_au4SwCr[1] = prQM->arTxQueue[ucOpt1].u4NumElem; /* only one */ + + + break; + } + + } + case SWCTRL_TX_CTRL_INFO: + { + P_TX_CTRL_T prTxCtrl; + prTxCtrl = &prAdapter->rTxCtrl; + switch(ucOpt0) { + case 0: + g_au4SwCr[1] = prAdapter->rTxCtrl.rTc.aucFreeBufferCount[ucOpt1]; + g_au4SwCr[2] = prAdapter->rTxCtrl.rTc.aucMaxNumOfBuffer[ucOpt1]; + break; + } + + } + break; + case SWCTRL_DUMP_QUEUE: + dumpQueue(prAdapter); + + break; +#if QM_DEBUG_COUNTER + case SWCTRL_DUMP_QM_DBG_CNT: + for(i=0;irQM.au4QmDebugCounters[i])); + } + break; + + case SWCTRL_QM_DBG_CNT: + g_au4SwCr[1] = prAdapter->rQM.au4QmDebugCounters[ucOpt0]; + break; +#endif + case SWCTRL_DUMP_BSS: + { + dumpBss(prAdapter, &(prAdapter->rWifiVar.arBssInfo[ucOpt0])) ; + } + break; + + default: + break; + } + + } +} + + +VOID swCtrlCmdCategory1(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0,UINT_8 ucOpt1) +{ + UINT_8 ucIndex,ucRead; + UINT_8 ucWTEntry; + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("swCtrlCmdCategory1"); + + SWCR_GET_RW_INDEX(ucAction,ucRead,ucIndex); + + if(ucOpt0>=CFG_STA_REC_NUM) return; + + //prStaRec = cnmGetStaRecByIndex (prAdapter, ucOpt0); + prStaRec = &prAdapter->arStaRec[ucOpt0]; + ucWTEntry = prStaRec->ucWTEntry; + if(ucRead == SWCR_WRITE) { + } + else { + /* Read */ + switch(ucIndex) { + case SWCTRL_STA_QUE_INFO: + { + g_au4SwCr[1] = prStaRec->arTxQueue[ucOpt1].u4NumElem; + } + break; + case SWCTRL_STA_INFO: + switch(ucOpt1) { + case 0: + g_au4SwCr[1] = prStaRec->fgIsInPS; + break; + } + + break; + + case SWCTRL_DUMP_STA: + { + dumpSTA(prAdapter, prStaRec); + } + break; + + default: + + break; + } + } + + +} + +#if TEST_PS + +VOID +testPsSendQoSNullFrame ( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN UINT_8 ucUP, + IN UINT_8 ucNetTypeIndex, + IN BOOLEAN fgBMC, + IN BOOLEAN fgIsBurstEnd, + IN BOOLEAN ucPacketType, + IN BOOLEAN ucPsSessionID, + IN BOOLEAN fgSetEOSP + ) +{ + P_MSDU_INFO_T prMsduInfo; + UINT_16 u2EstimatedFrameLen; + P_WLAN_MAC_HEADER_QOS_T prQoSNullFrame; + + + DEBUGFUNC("testPsSendQoSNullFrame"); + DBGLOG(SW4, LOUD, ("\n")); + + //4 <1> Allocate a PKT_INFO_T for Null Frame + /* Init with MGMT Header Length */ + u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + \ + WLAN_MAC_HEADER_QOS_LEN; + + /* Allocate a MSDU_INFO_T */ + if ( (prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen)) == NULL) { + DBGLOG(SW4, WARN, ("No PKT_INFO_T for sending Null Frame.\n")); + return ; + } + + //4 <2> Compose Null frame in MSDU_INfO_T. + bssComposeQoSNullFrame(prAdapter, + (PUINT_8)((UINT_32)(prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + prStaRec, + ucUP, + fgSetEOSP); + + + prMsduInfo->eSrc = TX_PACKET_MGMT; + //prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_DATA; + prMsduInfo->ucPacketType = ucPacketType; + prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; + prMsduInfo->ucNetworkType = ucNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_HEADER_QOS_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_HEADER_QOS_LEN; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = NULL; + prMsduInfo->fgIsBasicRate = TRUE; + prMsduInfo->fgIsBurstEnd = fgIsBurstEnd; + prMsduInfo->ucUserPriority = ucUP; + prMsduInfo->ucPsSessionID = ucPsSessionID /* 0~7 Test 7 means NOACK*/; + + prQoSNullFrame = (P_WLAN_MAC_HEADER_QOS_T)( (PUINT_8)((UINT_32)(prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD) ); + + if(fgBMC) { + prQoSNullFrame->aucAddr1[0] = 0xfd; + } + else { + prQoSNullFrame->aucAddr1[5] = 0xdd; + } + + //4 <4> Inform TXM to send this Null frame. + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + +} + + + +VOID +testPsSetupBss( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucNetworkTypeIndex + ) +{ + P_BSS_INFO_T prBssInfo; + UINT_8 _aucZeroMacAddr[] = NULL_MAC_ADDR; + + DEBUGFUNC("testPsSetupBss()"); + DBGLOG(SW4, INFO, ("index %d\n", ucNetworkTypeIndex)); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[ucNetworkTypeIndex]); + + //4 <1.2> Initiate PWR STATE + //SET_NET_PWR_STATE_IDLE(prAdapter, ucNetworkTypeIndex); + + + //4 <2> Initiate BSS_INFO_T - common part + BSS_INFO_INIT(prAdapter, ucNetworkTypeIndex); + + prBssInfo->eConnectionState = PARAM_MEDIA_STATE_DISCONNECTED; + prBssInfo->eConnectionStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED; + prBssInfo->eCurrentOPMode = OP_MODE_ACCESS_POINT; + prBssInfo->fgIsNetActive = TRUE; + prBssInfo->ucNetTypeIndex = (ucNetworkTypeIndex); + prBssInfo->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_RESERVED; + + prBssInfo->ucPhyTypeSet = PHY_TYPE_SET_802_11BG; /* Depend on eBand */ + prBssInfo->ucConfigAdHocAPMode = AP_MODE_MIXED_11BG; /* Depend on eCurrentOPMode and ucPhyTypeSet */ + prBssInfo->u2BSSBasicRateSet = RATE_SET_ERP; + prBssInfo->u2OperationalRateSet = RATE_SET_OFDM; + prBssInfo->fgErpProtectMode = FALSE; + prBssInfo->fgIsQBSS = TRUE; + + //4 <1.5> Setup MIB for current BSS + prBssInfo->u2BeaconInterval = 100; + prBssInfo->ucDTIMPeriod = DOT11_DTIM_PERIOD_DEFAULT; + prBssInfo->u2ATIMWindow = 0; + + prBssInfo->ucBeaconTimeoutCount = 0; + + + bssInitForAP (prAdapter,prBssInfo, TRUE); + + COPY_MAC_ADDR(prBssInfo->aucBSSID, _aucZeroMacAddr); + LINK_INITIALIZE(&prBssInfo->rStaRecOfClientList); + prBssInfo->fgIsBeaconActivated = TRUE; + prBssInfo->ucHwDefaultFixedRateCode = RATE_CCK_1M_LONG; + + + COPY_MAC_ADDR(prBssInfo->aucOwnMacAddr, prAdapter->rWifiVar.aucMacAddress); + + //4 <3> Initiate BSS_INFO_T - private part + /* TODO */ + prBssInfo->eBand = BAND_2G4; + prBssInfo->ucPrimaryChannel = 1; + prBssInfo->prStaRecOfAP = (P_STA_RECORD_T)NULL; + + + //prBssInfo->fgErpProtectMode = eErpProectMode; + //prBssInfo->eHtProtectMode = eHtProtectMode; + //prBssInfo->eGfOperationMode = eGfOperationMode; + + + //4 <4> Allocate MSDU_INFO_T for Beacon + prBssInfo->prBeacon = cnmMgtPktAlloc(prAdapter, + OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem[0]) + MAX_IE_LENGTH); + + if (prBssInfo->prBeacon) { + prBssInfo->prBeacon->eSrc = TX_PACKET_MGMT; + prBssInfo->prBeacon->ucNetworkType = ucNetworkTypeIndex; + } + else { + DBGLOG(SW4, INFO, ("prBeacon allocation fail\n")); + } + +#if 0 + prBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC = PM_UAPSD_ALL; + prBssInfo->rPmProfSetupInfo.ucBmpTriggerAC = PM_UAPSD_ALL; + prBssInfo->rPmProfSetupInfo.ucUapsdSp = WMM_MAX_SP_LENGTH_2; +#else + prBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC = (UINT_8)prAdapter->u4UapsdAcBmp; + prBssInfo->rPmProfSetupInfo.ucBmpTriggerAC =(UINT_8) prAdapter->u4UapsdAcBmp; + prBssInfo->rPmProfSetupInfo.ucUapsdSp = (UINT_8)prAdapter->u4MaxSpLen; +#endif + +#if 0 + for(eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++){ + + prBssInfo->arACQueParms[eAci].fgIsACMSet = FALSE; + prBssInfo->arACQueParms[eAci].u2Aifsn = (UINT_16) eAci; + prBssInfo->arACQueParms[eAci].u2CWmin = 7; + prBssInfo->arACQueParms[eAci].u2CWmax = 31; + prBssInfo->arACQueParms[eAci].u2TxopLimit = eAci+1; + DBGLOG(SW4, INFO, ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", + eAci,prBssInfo->arACQueParms[eAci].fgIsACMSet , + prBssInfo->arACQueParms[eAci].u2Aifsn, + prBssInfo->arACQueParms[eAci].u2CWmin, + prBssInfo->arACQueParms[eAci].u2CWmax, + prBssInfo->arACQueParms[eAci].u2TxopLimit)); + + } +#endif + + + DBGLOG(SW4, INFO, ("[2] ucBmpDeliveryAC:0x%x, ucBmpTriggerAC:0x%x, ucUapsdSp:0x%x", + prBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC, + prBssInfo->rPmProfSetupInfo.ucBmpTriggerAC, + prBssInfo->rPmProfSetupInfo.ucUapsdSp)); + + return; +} + + + + +VOID testPsCmdCategory0(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0,UINT_8 ucOpt1) +{ + UINT_8 ucIndex,ucRead; + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("testPsCmdCategory0"); + SWCR_GET_RW_INDEX(ucAction,ucRead,ucIndex); + + DBGLOG(SW4, LOUD, ("Read %u Index %u\n",ucRead,ucIndex)); + + prStaRec = cnmGetStaRecByIndex (prAdapter, 0); + + if(ucIndex>=TEST_PS_CATA0_INDEX_NUM) return; + + if(ucRead == SWCR_WRITE) { + switch(ucIndex) { + case TEST_PS_SETUP_BSS: + testPsSetupBss(prAdapter, ucOpt0) ; + break; + + case TEST_PS_ENABLE_BEACON: + break; + + case TEST_PS_TRIGGER_BMC: + //txmForwardQueuedBmcPkts (ucOpt0); + break; + case TEST_PS_SEND_NULL: + { + + testPsSendQoSNullFrame (prAdapter,prStaRec, + (UINT_8)(g_au4SwCr[1] & 0xFF), /* UP */ + ucOpt0, + (BOOLEAN)((g_au4SwCr[1] >>8)& 0xFF), /* BMC*/ + (BOOLEAN)((g_au4SwCr[1] >>16)& 0xFF), /* BurstEnd*/ + (BOOLEAN)((g_au4SwCr[1] >>24)& 0xFF), /* Packet type*/ + (UINT_8)((g_au4SwCr[2] )& 0xFF), /* PS sesson ID 7: NOACK */ + FALSE /* EOSP */ + ); + } + break; + case TEST_PS_BUFFER_BMC: + //g_aprBssInfo[ucOpt0]->fgApToBufferBMC = (g_au4SwCr[1] & 0xFF); + break; + case TEST_PS_UPDATE_BEACON: + bssUpdateBeaconContent(prAdapter, ucOpt0 /*networktype*/ ); + break; + + default: + break; + } + } + else { + switch(ucIndex) { + + case TEST_PS_MAGIC: + g_au4SwCr[1] = 0x88660011 ; + break; + + } + } +} + +#endif //TEST_PS + +#if TEST_PS + +VOID testPsCmdCategory1(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0,UINT_8 ucOpt1) +{ + UINT_8 ucIndex,ucRead; + UINT_8 ucWTEntry; + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("testPsCmdCategory1"); + + SWCR_GET_RW_INDEX(ucAction,ucRead,ucIndex); + + if(ucOpt0>=CFG_STA_REC_NUM) return; + + prStaRec = cnmGetStaRecByIndex (prAdapter, ucOpt0); + ucWTEntry = prStaRec->ucWTEntry; + if(ucRead == SWCR_WRITE) { + + switch(ucIndex) { + case TEST_PS_STA_PS: + prStaRec->fgIsInPS = (BOOLEAN) (g_au4SwCr[1] & 0x1); + prStaRec->fgIsQoS = (BOOLEAN) (g_au4SwCr[1] >>8 & 0xFF); + prStaRec->fgIsUapsdSupported = (BOOLEAN) (g_au4SwCr[1] >>16 & 0xFF); + prStaRec->ucBmpDeliveryAC = (BOOLEAN) (g_au4SwCr[1] >>24 & 0xFF); + break; + + } + + } + else { + /* Read */ + switch(ucIndex) { + default: + break; + } + } + + +} + +#endif //TEST_PS + + + +VOID swCtrlSwCr(P_ADAPTER_T prAdapter, UINT_8 ucRead, UINT_16 u2Addr, UINT_32 *pu4Data) +{ + /* According other register STAIDX */ + UINT_8 ucOffset; + ucOffset = (u2Addr>>2) & 0x3F; + + if(ucOffset>= SWCR_CR_NUM) return; + + if(ucRead==SWCR_WRITE) { + g_au4SwCr[ucOffset] = *pu4Data; + if(ucOffset==0x0) { + /* Commmand [31:24]: Category */ + /* Commmand [23:23]: 1(W) 0(R) */ + /* Commmand [22:16]: Index */ + /* Commmand [15:08]: Option0 */ + /* Commmand [07:00]: Option1 */ + UINT_8 ucCate; + UINT_32 u4Cmd; + u4Cmd = g_au4SwCr[0]; + ucCate = (UINT_8)(u4Cmd >> 24) ; + if(ucCate < sizeof(g_arSwCtrlCmd)/sizeof(g_arSwCtrlCmd[0])) { + if(g_arSwCtrlCmd[ucCate]!=NULL) { + g_arSwCtrlCmd[ucCate](prAdapter, ucCate, (UINT_8)(u4Cmd>>16 & 0xFF),(UINT_8)((u4Cmd>>8) & 0xFF), (UINT_8)(u4Cmd&0xFF)); + } + } + } + } + else { + *pu4Data = g_au4SwCr[ucOffset]; + } +} + +VOID swCrReadWriteCmd(P_ADAPTER_T prAdapter, UINT_8 ucRead, UINT_16 u2Addr, UINT_32 *pu4Data) +{ + UINT_8 ucMod; + + ucMod = u2Addr >>8; + /* Address [15:8] MOD ID */ + /* Address [7:0] OFFSET */ + + DEBUGFUNC("swCrReadWriteCmd"); + DBGLOG(SW4, INFO, ("%u addr 0x%x data 0x%x\n",ucRead,u2Addr,*pu4Data)); + + if(ucMod < (sizeof(g_arSwCrModHandle)/sizeof(g_arSwCrModHandle[0])) ) { + + if(g_arSwCrModHandle[ucMod]!=NULL) { + g_arSwCrModHandle[ucMod](prAdapter, ucRead, u2Addr, pu4Data); + } + } /* ucMod */ +} + +/* Debug Support */ +VOID swCrFrameCheckEnable(P_ADAPTER_T prAdapter, UINT_32 u4DumpType) +{ + g_u4SwcrDebugFrameDumpType = u4DumpType; + prAdapter->rRxCtrl.u4RxPktsDumpTypeMask = u4DumpType; +} + +VOID swCrDebugInit(P_ADAPTER_T prAdapter) +{ + // frame dump + if (g_u4SwcrDebugFrameDumpType) { + swCrFrameCheckEnable(prAdapter, g_u4SwcrDebugFrameDumpType); + } + + // debug counter + g_fgSwcrDebugTimer = FALSE; + + cnmTimerInitTimer(prAdapter, + &g_rSwcrDebugTimer, + (PFN_MGMT_TIMEOUT_FUNC)swCrDebugCheckTimeout, + (UINT_32) NULL); + + if (g_u4SwcrDebugCheckTimeout) { + swCrDebugCheckEnable(prAdapter, TRUE, g_ucSwcrDebugCheckType, g_u4SwcrDebugCheckTimeout); + } +} + +VOID swCrDebugUninit(P_ADAPTER_T prAdapter) +{ + cnmTimerStopTimer(prAdapter, &g_rSwcrDebugTimer); + + g_fgSwcrDebugTimer = FALSE; +} + +VOID swCrDebugCheckEnable(P_ADAPTER_T prAdapter, BOOLEAN fgIsEnable, UINT_8 ucType, UINT_32 u4Timeout) +{ + if (fgIsEnable) { + g_ucSwcrDebugCheckType = ucType; + g_u4SwcrDebugCheckTimeout = u4Timeout; + if (g_fgSwcrDebugTimer == FALSE) { + swCrDebugCheckTimeout(prAdapter, 0); + } + } + else { + cnmTimerStopTimer(prAdapter, &g_rSwcrDebugTimer); + g_u4SwcrDebugCheckTimeout = 0; + } + + g_fgSwcrDebugTimer = fgIsEnable; +} + +VOID swCrDebugCheck(P_ADAPTER_T prAdapter, P_CMD_SW_DBG_CTRL_T prCmdSwCtrl) +{ + P_RX_CTRL_T prRxCtrl; + P_TX_CTRL_T prTxCtrl; + + ASSERT(prAdapter); + + prTxCtrl = &prAdapter->rTxCtrl; + prRxCtrl = &prAdapter->rRxCtrl; + + // dump counters + if (prCmdSwCtrl) { + if (prCmdSwCtrl->u4Data == SWCR_DBG_TYPE_ALL) { + + // TX Counter from fw + DBGLOG(SW4, INFO, ("TX0\n" \ + "%08x %08x %08x %08x\n" \ + "%08x %08x %08x %08x\n", + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_BCN_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_FAILED_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_RETRY_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_AGING_TIMEOUT_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_PS_OVERFLOW_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_MGNT_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_ERROR_CNT])); +#if 1 + // TX Counter from drv + DBGLOG(SW4, INFO, ("TX1\n" \ + "%08x %08x %08x %08x\n", + (UINT_32)TX_GET_CNT(prTxCtrl, TX_INACTIVE_BSS_DROP), + (UINT_32)TX_GET_CNT(prTxCtrl, TX_INACTIVE_STA_DROP), + (UINT_32)TX_GET_CNT(prTxCtrl, TX_FORWARD_OVERFLOW_DROP), + (UINT_32)TX_GET_CNT(prTxCtrl, TX_AP_BORADCAST_DROP))); +#endif + + // RX Counter + DBGLOG(SW4, INFO, ("RX0\n" \ + "%08x %08x %08x %08x\n" \ + "%08x %08x %08x %08x\n" \ + "%08x %08x %08x %08x\n" \ + "%08x %08x %08x %08x\n", + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_DUP_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_TYPE_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_CLASS_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_AMPDU_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_STATUS_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_FORMAT_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_ICV_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_KEY_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_TKIP_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_MIC_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_BIP_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_FCSERR_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_FIFOFULL_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_PFDROP_CNT])); + + DBGLOG(SW4, INFO, ("RX1\n" \ + "%08x %08x %08x %08x\n" \ + "%08x %08x %08x %08x\n", + (UINT_32)RX_GET_CNT(prRxCtrl, RX_MPDU_TOTAL_COUNT), + (UINT_32)RX_GET_CNT(prRxCtrl, RX_DATA_INDICATION_COUNT), + (UINT_32)RX_GET_CNT(prRxCtrl, RX_DATA_RETURNED_COUNT), + (UINT_32)RX_GET_CNT(prRxCtrl, RX_DATA_RETAINED_COUNT), + (UINT_32)RX_GET_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT), + (UINT_32)RX_GET_CNT(prRxCtrl, RX_TYPE_ERR_DROP_COUNT), + (UINT_32)RX_GET_CNT(prRxCtrl, RX_CLASS_ERR_DROP_COUNT), + (UINT_32)RX_GET_CNT(prRxCtrl, RX_DST_NULL_DROP_COUNT))); + + DBGLOG(SW4, INFO, ("PWR\n" \ + "%08x %08x %08x %08x\n" \ + "%08x %08x %08x %08x\n", + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_PS_POLL_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_TRIGGER_NULL_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_BCN_IND_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_BCN_TIMEOUT_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_PM_STATE0], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_PM_STATE1], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_CUR_PS_PROF0], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_CUR_PS_PROF1])); + + DBGLOG(SW4, INFO, ("ARM\n" \ + "%08x %08x %08x %08x\n" \ + "%08x %08x\n", + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_AR_STA0_RATE], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_AR_STA0_BWGI], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_AR_STA0_RX_RATE_RCPI], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_ROAMING_ENABLE], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_ROAMING_ROAM_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_ROAMING_INT_CNT])); + + DBGLOG(SW4, INFO, ("BB\n" \ + "%08x %08x %08x %08x\n" \ + "%08x %08x %08x %08x\n", + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_RX_MDRDY_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_RX_FCSERR_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_CCK_PD_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_OFDM_PD_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_CCK_SFDERR_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_CCK_SIGERR_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_OFDM_TAGERR_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_OFDM_SIGERR_CNT])); + + } + } + + // start the next check + if (g_u4SwcrDebugCheckTimeout) { + cnmTimerStartTimer(prAdapter, &g_rSwcrDebugTimer, g_u4SwcrDebugCheckTimeout * MSEC_PER_SEC); + } +} + +VOID swCrDebugCheckTimeout( + IN P_ADAPTER_T prAdapter, + UINT_32 u4Param) +{ + CMD_SW_DBG_CTRL_T rCmdSwCtrl; + WLAN_STATUS rStatus; + + rCmdSwCtrl.u4Id = (0xb000<<16) + g_ucSwcrDebugCheckType; + rCmdSwCtrl.u4Data = 0; + rStatus = wlanSendSetQueryCmd ( + prAdapter, /* prAdapter */ + CMD_ID_SW_DBG_CTRL, /* ucCID */ + FALSE, /* fgSetQuery */ + TRUE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + swCrDebugQuery, /* pfCmdDoneHandler */ + swCrDebugQueryTimeout, /* pfCmdTimeoutHandler */ + sizeof(CMD_SW_DBG_CTRL_T), /* u4SetQueryInfoLen */ + (PUINT_8)&rCmdSwCtrl, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + ASSERT(rStatus == WLAN_STATUS_PENDING); + + return; +} + +VOID swCrDebugQuery( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + ASSERT(prAdapter); + + swCrDebugCheck(prAdapter, (P_CMD_SW_DBG_CTRL_T)(pucEventBuf)); +} + +VOID swCrDebugQueryTimeout( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo) +{ + ASSERT(prAdapter); + + swCrDebugCheck(prAdapter, NULL); +} + +#endif /* CFG_SUPPORT_SWCR */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/wapi.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/wapi.c new file mode 100755 index 000000000000..db2bf3456e1e --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/mgmt/wapi.c @@ -0,0 +1,568 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/mgmt/wapi.c#1 $ +*/ + +/*! \file "wapi.c" + \brief This file including the WAPI related function. + + This file provided the macros and functions library support the wapi ie parsing, + cipher and AKM check to help the AP seleced deciding. +*/ + +/******************************************************************************* +* Copyright (c) 2009 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER + +* Copyright (c) 2008 MediaTek Inc. ALL RIGHTS RESERVED. + +* BY OPENING OR USING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES +* AND AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS (¨MEDIATEK +* SOFTWARE〃)RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN ¨AS IS〃 BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, WHETHER EXPRESS OR IMPLIED, INCLUDING +* BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE, OR NON-INFRINGEMENT. NOR DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTIES +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE. +* BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTIES FOR ANY AND ALL +* WARRANTY CLAIMS RELATING THERETO. MEDIATEK SHALL NOT BE RESPONSIBLE FOR +* ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYERˇS SPECIFICATION OR CONFORMING +* TO A PARTICULAR STANDARD OR OPEN FORUM. + +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER SHALL BE, +* AT MEDIATEK'S SOLE OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE +* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGES PAID BY BUYER TO +* MEDIATEK FOR SUCH MEDIATEK SOFTWARE. + +* THE MEDIATEK SOFTWARE IS PROVIDED FOR AND ONLY FOR USE WITH MEDIATEK CHIPS +* OR PRODUCTS. EXCEPT AS EXPRESSLY PROVIDED, NO LICENSE IS GRANTED BY +* IMPLICATION OR OTHERWISE UNDER ANY INTELLECTUAL PROPERTY RIGHTS, INCLUDING +* PATENT OR COPYRIGHTS, OF MEDIATEK. UNAUTHORIZED USE, REPRODUCTION, OR +* DISCLOSURE OF THE MEDIATEK SOFTWARE IN WHOLE OR IN PART IS STRICTLY PROHIBITED. + +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE WITH +* THE LAWS OF THE REPUBLIC OF SINGAPORE, EXCLUDING ITS CONFLICT OF LAWS +* PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS RELATING HERETO OR ARISING +* HEREFROM SHALL BE EXCLUSIVELY SETTLED VIA ARBITRATION IN SINGAPORE UNDER THE +* THEN CURRENT ARBITRAL RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE. +* THE LANGUAGE OF ARBITRATION SHALL BE ENGLISH. THE AWARDS OF THE ARBITRATION +* SHALL BE FINAL AND BINDING UPON BOTH PARTIES AND SHALL BE ENTERED AND +* ENFORCEABLE IN ANY COURT OF COMPETENT JURISDICTION. +******************************************************************************** +*/ + +/* +** $Log: wapi.c $ + * + * 11 10 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * change the debug module level. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 10 20 2010 wh.su + * [WCXRP00000067] [MT6620 Wi-Fi][Driver] Support the android+ WAPI function + * fixed the network type + * + * 09 01 2010 wh.su + * NULL + * adding the wapi support for integration test. + * + * 07 20 2010 wh.su + * + * . + * + * 04 06 2010 wh.su + * [BORA00000680][MT6620] Support the statistic for Microsoft os query + * fixed the firmware return the broadcast frame at wrong tc. + * + * 03 03 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * move the AIS specific variable for security to AIS specific structure. + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Dec 8 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the function to check and update the default wapi tx + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the generate wapi ie function, and replace the tabe by space + * + * Nov 23 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "precomp.h" +#if CFG_SUPPORT_WAPI + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to generate WPA IE for +* associate request frame. +* +* \param[in] prCurrentBss The Selected BSS description +* +* \retval The append WPA IE length +* +* \note +* Called by: AIS module, Associate request +*/ +/*----------------------------------------------------------------------------*/ +VOID +wapiGenerateWAPIIE ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ) +{ + PUINT_8 pucBuffer; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + if (prMsduInfo->ucNetworkType != NETWORK_TYPE_AIS_INDEX) + return; + + pucBuffer = (PUINT_8)((UINT_32)prMsduInfo->prPacket + + (UINT_32)prMsduInfo->u2FrameLength); + + /* ASSOC INFO IE ID: 68 :0x44 */ + if (/* prWlanInfo->fgWapiMode && */ prAdapter->prGlueInfo->u2WapiAssocInfoIESz) { + kalMemCopy(pucBuffer, &prAdapter->prGlueInfo->aucWapiAssocInfoIEs, prAdapter->prGlueInfo->u2WapiAssocInfoIESz); + prMsduInfo->u2FrameLength += prAdapter->prGlueInfo->u2WapiAssocInfoIESz; + } + +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to parse WAPI IE. +* +* \param[in] prInfoElem Pointer to the RSN IE +* \param[out] prRsnInfo Pointer to the BSSDescription structure to store the +** WAPI information from the given WAPI IE +* +* \retval TRUE - Succeeded +* \retval FALSE - Failed +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +wapiParseWapiIE ( + IN P_WAPI_INFO_ELEM_T prInfoElem, + OUT P_WAPI_INFO_T prWapiInfo + ) +{ + UINT_32 i; + INT_32 u4RemainWapiIeLen; + UINT_16 u2Version; + UINT_16 u2Cap = 0; + UINT_32 u4GroupSuite = WAPI_CIPHER_SUITE_WPI; + UINT_16 u2PairSuiteCount = 0; + UINT_16 u2AuthSuiteCount = 0; + PUCHAR pucPairSuite = NULL; + PUCHAR pucAuthSuite = NULL; + PUCHAR cp; + + DEBUGFUNC("wapiParseWapiIE"); + + ASSERT(prInfoElem); + ASSERT(prWapiInfo); + + /* Verify the length of the WAPI IE. */ + if (prInfoElem->ucLength < 6) { + DBGLOG(SEC, TRACE, ("WAPI IE length too short (length=%d)\n", prInfoElem->ucLength)); + return FALSE; + } + + /* Check WAPI version: currently, we only support version 1. */ + WLAN_GET_FIELD_16(&prInfoElem->u2Version, &u2Version); + if (u2Version != 1) { + DBGLOG(SEC, TRACE, ("Unsupported WAPI IE version: %d\n", u2Version)); + return FALSE; + } + + cp = (PUCHAR) &prInfoElem->u2AuthKeyMgtSuiteCount; + u4RemainWapiIeLen = (INT_32) prInfoElem->ucLength - 2; + + do { + if (u4RemainWapiIeLen == 0) { + break; + } + + /* + AuthCount : 2 + AuthSuite : 4 * authSuiteCount + PairwiseCount: 2 + PairwiseSuite: 4 * pairSuiteCount + GroupSuite : 4 + Cap : 2 */ + + /* Parse the Authentication and Key Management Cipher Suite Count + field. */ + if (u4RemainWapiIeLen < 2) { + DBGLOG(SEC, TRACE, ("Fail to parse WAPI IE in auth & key mgt suite count (IE len: %d)\n", + prInfoElem->ucLength)); + return FALSE; + } + + WLAN_GET_FIELD_16(cp, &u2AuthSuiteCount); + cp += 2; + u4RemainWapiIeLen -= 2; + + /* Parse the Authentication and Key Management Cipher Suite List + field. */ + i = (UINT_32) u2AuthSuiteCount * 4; + if (u4RemainWapiIeLen < (INT_32) i) { + DBGLOG(SEC, TRACE, ("Fail to parse WAPI IE in auth & key mgt suite list (IE len: %d)\n", + prInfoElem->ucLength)); + return FALSE; + } + + pucAuthSuite = cp; + + cp += i; + u4RemainWapiIeLen -= (INT_32) i; + + if (u4RemainWapiIeLen == 0) { + break; + } + + /* Parse the Pairwise Key Cipher Suite Count field. */ + if (u4RemainWapiIeLen < 2) { + DBGLOG(SEC, TRACE, ("Fail to parse WAPI IE in pairwise cipher suite count (IE len: %d)\n", + prInfoElem->ucLength)); + return FALSE; + } + + WLAN_GET_FIELD_16(cp, &u2PairSuiteCount); + cp += 2; + u4RemainWapiIeLen -= 2; + + /* Parse the Pairwise Key Cipher Suite List field. */ + i = (UINT_32) u2PairSuiteCount * 4; + if (u4RemainWapiIeLen < (INT_32) i) { + DBGLOG(SEC, TRACE, ("Fail to parse WAPI IE in pairwise cipher suite list (IE len: %d)\n", + prInfoElem->ucLength)); + return FALSE; + } + + pucPairSuite = cp; + + cp += i; + u4RemainWapiIeLen -= (INT_32) i; + + /* Parse the Group Key Cipher Suite field. */ + if (u4RemainWapiIeLen < 4) { + DBGLOG(SEC, TRACE, ("Fail to parse WAPI IE in group cipher suite (IE len: %d)\n", + prInfoElem->ucLength)); + return FALSE; + } + + WLAN_GET_FIELD_32(cp, &u4GroupSuite); + cp += 4; + u4RemainWapiIeLen -= 4; + + /* Parse the WAPI u2Capabilities field. */ + if (u4RemainWapiIeLen < 2) { + DBGLOG(SEC, TRACE, ("Fail to parse WAPI IE in WAPI capabilities (IE len: %d)\n", + prInfoElem->ucLength)); + return FALSE; + } + + WLAN_GET_FIELD_16(cp, &u2Cap); + u4RemainWapiIeLen -= 2; + + /* Todo:: BKID support */ + } while (FALSE); + + /* Save the WAPI information for the BSS. */ + + prWapiInfo->ucElemId = ELEM_ID_WAPI; + + prWapiInfo->u2Version = u2Version; + + prWapiInfo->u4GroupKeyCipherSuite = u4GroupSuite; + + DBGLOG(SEC, LOUD, ("WAPI: version %d, group key cipher suite %02x-%02x-%02x-%02x\n", + u2Version, (UCHAR) (u4GroupSuite & 0x000000FF), + (UCHAR) ((u4GroupSuite >> 8) & 0x000000FF), + (UCHAR) ((u4GroupSuite >> 16) & 0x000000FF), + (UCHAR) ((u4GroupSuite >> 24) & 0x000000FF))); + + if (pucPairSuite) { + /* The information about the pairwise key cipher suites is present. */ + if (u2PairSuiteCount > MAX_NUM_SUPPORTED_CIPHER_SUITES) { + u2PairSuiteCount = MAX_NUM_SUPPORTED_CIPHER_SUITES; + } + + prWapiInfo->u4PairwiseKeyCipherSuiteCount = (UINT_32) u2PairSuiteCount; + + for (i = 0; i < (UINT_32) u2PairSuiteCount; i++) { + WLAN_GET_FIELD_32(pucPairSuite, + &prWapiInfo->au4PairwiseKeyCipherSuite[i]); + pucPairSuite += 4; + + DBGLOG(SEC, LOUD,("WAPI: pairwise key cipher suite [%d]: %02x-%02x-%02x-%02x\n", + (UINT_8)i, (UCHAR) (prWapiInfo->au4PairwiseKeyCipherSuite[i] & 0x000000FF), + (UCHAR) ((prWapiInfo->au4PairwiseKeyCipherSuite[i] >> 8) & 0x000000FF), + (UCHAR) ((prWapiInfo->au4PairwiseKeyCipherSuite[i] >> 16) & 0x000000FF), + (UCHAR) ((prWapiInfo->au4PairwiseKeyCipherSuite[i] >> 24) & 0x000000FF))); + } + } + else { + /* The information about the pairwise key cipher suites is not present. + Use the default chipher suite for WAPI: WPI. */ + prWapiInfo->u4PairwiseKeyCipherSuiteCount = 1; + prWapiInfo->au4PairwiseKeyCipherSuite[0] = WAPI_CIPHER_SUITE_WPI; + + DBGLOG(SEC, LOUD, ("WAPI: pairwise key cipher suite: %02x-%02x-%02x-%02x (default)\n", + (UCHAR) (prWapiInfo->au4PairwiseKeyCipherSuite[0] & 0x000000FF), + (UCHAR) ((prWapiInfo->au4PairwiseKeyCipherSuite[0] >> 8) & 0x000000FF), + (UCHAR) ((prWapiInfo->au4PairwiseKeyCipherSuite[0] >> 16) & 0x000000FF), + (UCHAR) ((prWapiInfo->au4PairwiseKeyCipherSuite[0] >> 24) & 0x000000FF))); + } + + if (pucAuthSuite) { + /* The information about the authentication and key management suites + is present. */ + if (u2AuthSuiteCount > MAX_NUM_SUPPORTED_AKM_SUITES) { + u2AuthSuiteCount = MAX_NUM_SUPPORTED_AKM_SUITES; + } + + prWapiInfo->u4AuthKeyMgtSuiteCount = (UINT_32) u2AuthSuiteCount; + + for (i = 0; i < (UINT_32) u2AuthSuiteCount; i++) { + WLAN_GET_FIELD_32(pucAuthSuite, &prWapiInfo->au4AuthKeyMgtSuite[i]); + pucAuthSuite += 4; + + DBGLOG(SEC, LOUD, ("WAPI: AKM suite [%d]: %02x-%02x-%02x-%02x\n", + (UINT_8)i, (UCHAR) (prWapiInfo->au4AuthKeyMgtSuite[i] & 0x000000FF), + (UCHAR) ((prWapiInfo->au4AuthKeyMgtSuite[i] >> 8) & 0x000000FF), + (UCHAR) ((prWapiInfo->au4AuthKeyMgtSuite[i] >> 16) & 0x000000FF), + (UCHAR) ((prWapiInfo->au4AuthKeyMgtSuite[i] >> 24) & 0x000000FF))); + } + } + else { + /* The information about the authentication and key management suites + is not present. Use the default AKM suite for WAPI. */ + prWapiInfo->u4AuthKeyMgtSuiteCount = 1; + prWapiInfo->au4AuthKeyMgtSuite[0] = WAPI_AKM_SUITE_802_1X; + + DBGLOG(SEC, LOUD, ("WAPI: AKM suite: %02x-%02x-%02x-%02x (default)\n", + (UCHAR) (prWapiInfo->au4AuthKeyMgtSuite[0] & 0x000000FF), + (UCHAR) ((prWapiInfo->au4AuthKeyMgtSuite[0] >> 8) & 0x000000FF), + (UCHAR) ((prWapiInfo->au4AuthKeyMgtSuite[0] >> 16) & 0x000000FF), + (UCHAR) ((prWapiInfo->au4AuthKeyMgtSuite[0] >> 24) & 0x000000FF))); + } + + prWapiInfo->u2WapiCap = u2Cap; + DBGLOG(SEC, LOUD, ("WAPI: cap: 0x%04x\n", prWapiInfo->u2WapiCap)); + + return TRUE; +} /* wapiParseWapiIE */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to perform WAPI policy selection for a given BSS. +* +* \param[in] prAdapter Pointer to the adapter object data area. +* \param[in] prBss Pointer to the BSS description +* +* \retval TRUE - The WAPI policy selection for the given BSS is +* successful. The selected pairwise and group cipher suites +* are returned in the BSS description. +* \retval FALSE - The WAPI policy selection for the given BSS is failed. +* The driver shall not attempt to join the given BSS. +* +* \note The Encrypt status matched score will save to bss for final ap select. +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +wapiPerformPolicySelection ( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBss + ) +{ + UINT_32 i; + UINT_32 u4PairwiseCipher = 0; + UINT_32 u4GroupCipher = 0; + UINT_32 u4AkmSuite = 0; + P_WAPI_INFO_T prBssWapiInfo; + P_WLAN_INFO_T prWlanInfo; + + DEBUGFUNC("wapiPerformPolicySelection"); + + ASSERT(prBss); + + /* Notice!!!! WAPI AP not set the privacy bit for WAI and WAI-PSK at WZC configuration mode */ + prWlanInfo = &prAdapter->rWlanInfo; + + if (prBss->fgIEWAPI) { + prBssWapiInfo = &prBss->rIEWAPI; + } + else { + if (prAdapter->rWifiVar.rConnSettings.fgWapiMode == FALSE) { + DBGLOG(SEC, TRACE,("-- No Protected BSS\n")); + return TRUE; + } + else { + DBGLOG(SEC, TRACE, ("WAPI Information Element does not exist.\n")); + return FALSE; + } + } + + /* Select pairwise/group ciphers */ + for (i = 0; i < prBssWapiInfo->u4PairwiseKeyCipherSuiteCount; i++) { + if (prBssWapiInfo->au4PairwiseKeyCipherSuite[i] == + prAdapter->rWifiVar.rConnSettings.u4WapiSelectedPairwiseCipher) { + u4PairwiseCipher = prBssWapiInfo->au4PairwiseKeyCipherSuite[i]; + } + } + if (prBssWapiInfo->u4GroupKeyCipherSuite == + prAdapter->rWifiVar.rConnSettings.u4WapiSelectedGroupCipher) + u4GroupCipher = prBssWapiInfo->u4GroupKeyCipherSuite; + + /* Exception handler */ + /* If we cannot find proper pairwise and group cipher suites to join the + BSS, do not check the supported AKM suites. */ + if (u4PairwiseCipher == 0 || u4GroupCipher == 0) { + DBGLOG(SEC, TRACE, ("Failed to select pairwise/group cipher (0x%08lx/0x%08lx)\n", + u4PairwiseCipher, u4GroupCipher)); + return FALSE; + } + + /* Select AKM */ + /* If the driver cannot support any authentication suites advertised in + the given BSS, we fail to perform RSNA policy selection. */ + /* Attempt to find any overlapping supported AKM suite. */ + for (i = 0; i < prBssWapiInfo->u4AuthKeyMgtSuiteCount; i++) { + if (prBssWapiInfo->au4AuthKeyMgtSuite[i] == prAdapter->rWifiVar.rConnSettings.u4WapiSelectedAKMSuite) { + u4AkmSuite = prBssWapiInfo->au4AuthKeyMgtSuite[i]; + break; + } + } + + if (u4AkmSuite == 0) { + DBGLOG(SEC, TRACE, ("Cannot support any AKM suites\n")); + return FALSE; + } + + DBGLOG(SEC, TRACE, ("Selected pairwise/group cipher: %02x-%02x-%02x-%02x/%02x-%02x-%02x-%02x\n", + (UINT_8) (u4PairwiseCipher & 0x000000FF), + (UINT_8) ((u4PairwiseCipher >> 8) & 0x000000FF), + (UINT_8) ((u4PairwiseCipher >> 16) & 0x000000FF), + (UINT_8) ((u4PairwiseCipher >> 24) & 0x000000FF), + (UINT_8) (u4GroupCipher & 0x000000FF), + (UINT_8) ((u4GroupCipher >> 8) & 0x000000FF), + (UINT_8) ((u4GroupCipher >> 16) & 0x000000FF), + (UINT_8) ((u4GroupCipher >> 24) & 0x000000FF))); + + DBGLOG(SEC, TRACE, ("Selected AKM suite: %02x-%02x-%02x-%02x\n", + (UINT_8) (u4AkmSuite & 0x000000FF), + (UINT_8) ((u4AkmSuite >> 8) & 0x000000FF), + (UINT_8) ((u4AkmSuite >> 16) & 0x000000FF), + (UINT_8) ((u4AkmSuite >> 24) & 0x000000FF))); + + return TRUE; +} /* wapiPerformPolicySelection */ + +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is use for wapi mode, to update the current wpi tx idx ? 0 :1 . +* +* \param[in] prStaRec Pointer to the Sta record +* \param[out] ucWlanIdx The Rx status->wlanidx field +* +* \retval TRUE - Succeeded +* \retval FALSE - Failed +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +wapiUpdateTxKeyIdx ( + IN P_STA_RECORD_T prStaRec, + IN UINT_8 ucWlanIdx + ) +{ + UINT_8 ucKeyId; + + if ((ucWlanIdx & BITS(0, 3)) == CIPHER_SUITE_WPI) { + + ucKeyId = ((ucWlanIdx & BITS(4, 5)) >> 4); + + if (ucKeyId != g_prWifiVar->rAisSpecificBssInfo.ucWpiActivedPWKey) { + DBGLOG(RSN, STATE, ("Change wapi key index from %d->%d\n", g_prWifiVar->rAisSpecificBssInfo.ucWpiActivedPWKey, ucKeyId)); + g_prWifiVar->rAisSpecificBssInfo.ucWpiActivedPWKey = ucKeyId; + + prStaRec->ucWTEntry = + (ucKeyId == WTBL_AIS_BSSID_WAPI_IDX_0) ? WTBL_AIS_BSSID_WAPI_IDX_0 : WTBL_AIS_BSSID_WAPI_IDX_1; + } + } +} +#endif +#endif + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/nic/cmd_buf.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/nic/cmd_buf.c new file mode 100755 index 000000000000..c5d7cacace2f --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/nic/cmd_buf.c @@ -0,0 +1,262 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/nic/cmd_buf.c#1 $ +*/ + +/*! \file "cmd_buf.c" + \brief This file contain the management function of internal Command Buffer + for CMD_INFO_T. + + We'll convert the OID into Command Packet and then send to FW. Thus we need + to copy the OID information to Command Buffer for following reasons. + 1. The data structure of OID information may not equal to the data structure of + Command, we cannot use the OID buffer directly. + 2. If the Command was not generated by driver we also need a place to store the + information. + 3. Because the CMD is NOT FIFO when doing memory allocation (CMD will be generated + from OID or interrupt handler), thus we'll use the Block style of Memory Allocation + here. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: cmd_buf.c $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 02 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. clear prPendingCmdInfo properly + * * 2. while allocating memory for cmdinfo, no need to add extra 4 bytes. +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-10-13 21:59:08 GMT mtk01084 +** remove un-neceasary spaces +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-05-20 12:24:26 GMT mtk01461 +** Increase CMD Buffer - HIF_RX_HW_APPENDED_LEN when doing CMD_INFO_T allocation +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-04-21 09:41:08 GMT mtk01461 +** Add init of Driver Domain MCR flag and fix lint MTK WARN +** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-04-17 19:51:45 GMT mtk01461 +** allocation function of CMD_INFO_T +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to initial the MGMT memory pool for CMD Packet. +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +cmdBufInitialize ( + IN P_ADAPTER_T prAdapter + ) +{ + P_CMD_INFO_T prCmdInfo; + UINT_32 i; + + ASSERT(prAdapter); + + QUEUE_INITIALIZE(&prAdapter->rFreeCmdList); + + for (i = 0; i < CFG_TX_MAX_CMD_PKT_NUM; i++) { + prCmdInfo = &prAdapter->arHifCmdDesc[i]; + QUEUE_INSERT_TAIL(&prAdapter->rFreeCmdList, &prCmdInfo->rQueEntry); + } + +} /* end of cmdBufInitialize() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Allocate CMD_INFO_T from a free list and MGMT memory pool. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] u4Length Length of the frame buffer to allocate. +* +* @retval NULL Pointer to the valid CMD Packet handler +* @retval !NULL Fail to allocat CMD Packet +*/ +/*----------------------------------------------------------------------------*/ +P_CMD_INFO_T +cmdBufAllocateCmdInfo ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Length + ) +{ + P_CMD_INFO_T prCmdInfo; + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("cmdBufAllocateCmdInfo"); + + + ASSERT(prAdapter); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); + QUEUE_REMOVE_HEAD(&prAdapter->rFreeCmdList, prCmdInfo, P_CMD_INFO_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); + + if (prCmdInfo) { + /* Setup initial value in CMD_INFO_T */ + /* Start address of allocated memory */ + prCmdInfo->pucInfoBuffer = + cnmMemAlloc(prAdapter, RAM_TYPE_BUF, u4Length); + + if (prCmdInfo->pucInfoBuffer == NULL) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); + QUEUE_INSERT_TAIL(&prAdapter->rFreeCmdList, &prCmdInfo->rQueEntry); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); + + prCmdInfo = NULL; + } + else { + prCmdInfo->u2InfoBufLen = 0; + prCmdInfo->fgIsOid = FALSE; + prCmdInfo->fgDriverDomainMCR = FALSE; + } + } + + return prCmdInfo; + +} /* end of cmdBufAllocateCmdInfo() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to free the CMD Packet to the MGMT memory pool. +* +* @param prAdapter Pointer to the Adapter structure. +* @param prCmdInfo CMD Packet handler +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +cmdBufFreeCmdInfo ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo + ) +{ + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("cmdBufFreeCmdInfo"); + + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + if (prCmdInfo) { + if (prCmdInfo->pucInfoBuffer) { + cnmMemFree(prAdapter, prCmdInfo->pucInfoBuffer); + prCmdInfo->pucInfoBuffer = NULL; + } + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); + QUEUE_INSERT_TAIL(&prAdapter->rFreeCmdList, &prCmdInfo->rQueEntry); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); + } + + return; + +} /* end of cmdBufFreeCmdPacket() */ + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/nic/nic.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/nic/nic.c new file mode 100755 index 000000000000..10ab7c7009b0 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/nic/nic.c @@ -0,0 +1,4370 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/nic/nic.c#3 $ +*/ + +/*! \file nic.c + \brief Functions that provide operation in NIC's (Network Interface Card) point of view. + + This file includes functions which unite multiple hal(Hardware) operations + and also take the responsibility of Software Resource Management in order + to keep the synchronization with Hardware Manipulation. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: nic.c $ + * + * 02 14 2012 yuche.tsai + * [ALPS00118350] [ALPS.ICS][WiFi Direct] Dirver update for wifi direct connection + * Replace Beacon/Probe Response IE by driver generating instead of from supplicant. + * + * 01 13 2012 yuche.tsai + * NULL + * Update driver/p2p driver for ICS tethering mode. + * Fix FW reply probe request issue. + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Hot Spot Tethering for ICS ALPHA testing version. + * + * 11 28 2011 cp.wu + * [WCXRP00001125] [MT6620 Wi-Fi][Firmware] Strengthen Wi-Fi power off sequence to have a clearroom environment when returining to ROM code + * 1. Due to firmware now stops HIF DMA for powering off, do not try to receive any packet from firmware + * 2. Take use of prAdapter->fgIsEnterD3ReqIssued for tracking whether it is powering off or not + * + * 11 22 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * keep debug counter setting after wake up. + * + * 11 19 2011 yuche.tsai + * NULL + * Add P2P RSSI Link Quality Query Support. (Default Off) + * + * 11 04 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters and periodically dump counters for Xlog debugging. + * + * 11 04 2011 cp.wu + * [WCXRP00001079] [MT5931][Driver] Release pending MMPDU only when BSS is being deactivated + * pre-check for NULL before calling MMPDU freeing function + * + * 11 03 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * change the DBGLOG for "\n" and "\r\n". LABEL to LOUD for XLOG + * + * 11 01 2011 chinglan.wang + * NULL + * Modify the Wi-Fi method of the flush TX queue when disconnect the AP. + * If disconnect the AP and flush all the data frame in the TX queue, WPS cannot do the 4-way handshake to connect to the AP.. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 08 03 2011 terry.wu + * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode + * Reply Probe Rsp in FW for Hotspot Mode. + * + * + * + * 08 03 2011 terry.wu + * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode + * Reply Probe Rsp in FW for Hotspot Mode. + * + * + * 08 03 2011 terry.wu + * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode + * Reply Probe Rsp in FW for Hotspot Mode. + * + * 08 03 2011 terry.wu + * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode + * Reply Probe Rsp in FW for Hotspot Mode. + * + * 08 02 2011 yuche.tsai + * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, TX deauth to a disconnecting device issue. + * Support TX Deauth while tearing down a station connection. + * + * 07 11 2011 wh.su + * [WCXRP00000849] [MT6620 Wi-Fi][Driver] Remove some of the WAPI define for make sure the value is initialize, for customer not enable WAPI + * For make sure wapi initial value is set. + * + * 06 27 2011 cp.wu + * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID settings to work around some tricky AP which use space character as hidden SSID + * 1. correct logic + * 2. replace only BSS-DESC which doesn't have a valid SSID. + * + * 06 27 2011 cp.wu + * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID settings to work around some tricky AP which use space character as hidden SSID + * allow to have a single BSSID with multiple SSID to be presented in scanning result + * + * 05 11 2011 eddie.chen + * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet + * Fix dest type when GO packet copying. + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 04 15 2011 cp.wu + * [WCXRP00000651] [MT6620 Wi-Fi][Driver] Refine RSSI buffering mechanism + * ROLLBACK due to the special design is to workaround incorrect initial RCPI value coming from firmware domain. + * + * 04 14 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 04 14 2011 cp.wu + * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for RESET_START and RESET_END events + * sync. whole-chip resetting mechanism to V2.0 branch. + * + * 04 12 2011 cp.wu + * [WCXRP00000635] [MT6620 Wi-Fi][Driver] Clear pending security frames when QM clear pending data frames for dedicated network type + * clear pending security frames for dedicated network type when BSS is being deactivated/disconnected + * + * 04 12 2011 wh.su + * NULL + * enable the p2p check the cipher to set the bssInfo auth mode. + * + * 04 12 2011 wh.su + * NULL + * prepare the code for sync the auth mode and encryption status for P2P and BOW. + * + * 04 11 2011 yuche.tsai + * [WCXRP00000627] [Volunteer Patch][MT6620][Driver] Pending MMPUD of P2P Network may crash system issue. + * Fix kernel panic issue when MMPDU of P2P is pending in driver after WLAN module removed. + * + * 04 10 2011 george.huang + * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode + * Fix compiler issue. + * + * 04 08 2011 george.huang + * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode + * separate settings of P2P and AIS + * + * 04 07 2011 eddie.chen + * [WCXRP00000527] [MT6620 Wi-Fi][FW/Driver] Clean buffered packet when BSS is inactive or disconnected[WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Remove packet when BSS is inactive + * + * 04 07 2011 cp.wu + * [WCXRP00000616] [MT6620 Wi-Fi][Driver] Free memory to pool and kernel in case any unexpected failure happend inside wlanAdapterStart + * . + * + * 04 07 2011 cp.wu + * [WCXRP00000616] [MT6620 Wi-Fi][Driver] Free memory to pool and kernel in case any unexpected failure happend inside wlanAdapterStart + * implementation of internal error handling of nicAllocateAdapterMemory. + * + * 03 31 2011 chinglan.wang + * [WCXRP00000613] [MT6620 Wi-Fi] [FW] [Driver] BssInfo can get the security mode which is WPA/WPA2/WAPI or not. + * . + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 17 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage after system running for a long period + * use pre-allocated buffer for storing enhanced interrupt response as well + * + * 03 16 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage after system running for a long period + * 1. pre-allocate physical continuous buffer while module is being loaded + * 2. use pre-allocated physical continuous buffer for TX/RX DMA transfer + * + * The windows part remained the same as before, but added similiar APIs to hide the difference. + * + * 03 15 2011 cp.wu + * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous memory consumption + * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK + * 2. Use common coalescing buffer for both TX/RX directions + * + * + * 03 10 2011 cm.chang + * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module + * Add some functions to let AIS/Tethering or AIS/BOW be the same channel + * + * 03 07 2011 terry.wu + * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message + * Toggle non-standard debug messages to comments. + * + * 03 02 2011 cp.wu + * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right after connection is built. + * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. + * + * 02 08 2011 terry.wu + * [WCXRP00000412] [MT6620 Wi-Fi][FW/Driver] Dump firmware assert info at android kernel log + * Use kalPrint to print firmware assert info. + * + * 02 01 2011 terry.wu + * [WCXRP00000412] [MT6620 Wi-Fi][FW/Driver] Dump firmware assert info at android kernel log + * . + * + * 02 01 2011 cm.chang + * [WCXRP00000415] [MT6620 Wi-Fi][Driver] Check if any memory leakage happens when uninitializing in DGB mode + * . + * + * 01 31 2011 terry.wu + * [WCXRP00000412] [MT6620 Wi-Fi][FW/Driver] Dump firmware assert info at android kernel log + * Print firmware ASSERT info at Android kernel log, driver side + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 01 26 2011 cm.chang + * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument + * Allocate system RAM if fixed message or mgmt buffer is not available + * + * 01 24 2011 cp.wu + * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving + * 1. add an extra counter for tracking pending forward frames. + * 2. notify TX service thread as well when there is pending forward frame + * 3. correct build errors leaded by introduction of Wi-Fi direct separation module + * + * 01 19 2011 cp.wu + * [WCXRP00000372] [MT6620 Wi-Fi][Driver] Check bus access failure inside nicProcessIST() + * check bus error and/or card removal when retrieving interrupt status from HAL + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease physically continous memory demands + * 1) correct typo in scan.c + * 2) TX descriptors, RX descriptos and management buffer should use virtually continous buffer instead of physically contineous one + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease physically continous memory demands + * separate kalMemAlloc() into virtually-continous and physically-continous type to ease slab system pressure + * + * 12 30 2010 cp.wu + * [WCXRP00000327] [MT6620 Wi-Fi][Driver] Improve HEC WHQA 6972 workaround coverage in driver side + * host driver not to set FW-own when there is still pending interrupts + * + * 12 17 2010 cp.wu + * [WCXRP00000270] [MT6620 Wi-Fi][Driver] Clear issues after concurrent networking support has been merged + * before BSS disconnection is indicated to firmware, all correlated peer should be cleared and freed + * + * 12 07 2010 cm.chang + * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk + * 1. BSSINFO include RLM parameter + * 2. free all sta records when network is disconnected + * + * 12 02 2010 eddie.chen + * [WCXRP00000218] [MT6620 Wi-Fi][Driver] Add auto rate window control in registry + * Add more control value but dont use it now. + * + * 11 30 2010 eddie.chen + * [WCXRP00000218] [MT6620 Wi-Fi][Driver] Add auto rate window control in registry + * Add auto rate check window in registry + * + * 11 10 2010 eddie.chen + * [WCXRP00000156] [MT6620][FW] Change Auto rate window to 64 and add throughput swcr + * Use autorate parameter 1 as phy rate mask. + * + * 11 08 2010 cp.wu + * [WCXRP00000166] [MT6620 Wi-Fi][Driver] use SDIO CMD52 for enabling/disabling interrupt to reduce transaction period + * change to use CMD52 for enabling/disabling interrupt to reduce SDIO transaction time + * + * 10 26 2010 eddie.chen + * [WCXRP00000134] [MT6620 Wi-Fi][Driver] Add a registry to enable auto rate for SQA test by using E1 EVB + * Add auto rate parameter in registry. + * + * 10 18 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS associated + * 1. remove redundant variables in STA_REC structure + * 2. add STA-REC uninitialization routine for clearing pending events + * + * 10 18 2010 cp.wu + * [WCXRP00000103] [MT6620 Wi-Fi][Driver] Driver crashed when using WZC to connect to AP#B with connection with AP#A + * reset ptrs when IEs are going to be dropped + * + * 10 12 2010 cp.wu + * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test + * add HT (802.11n) fixed rate support. + * + * 10 08 2010 cp.wu + * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test + * adding fixed rate support for distance test. (from registry setting) + * + * 10 07 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * add firmware download for MT5931. + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * load manufacture data when CFG_SUPPORT_NVRAM is set to 1 + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by ENUM_NETWORK_TYPE_INDEX_T only + * remove ENUM_NETWORK_TYPE_T definitions + * + * 09 21 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS associated + * Do a complete reset with STA-REC null checking for RF test re-entry + * + * 09 08 2010 cp.wu + * NULL + * use static memory pool for storing IEs of scanning result. + * + * 09 06 2010 cp.wu + * NULL + * Androi/Linux: return current operating channel information + * + * 09 01 2010 cp.wu + * NULL + * HIFSYS Clock Source Workaround + * + * 08 26 2010 yuche.tsai + * NULL + * Fix someones coding error while enable WIFI_DIRECT. + * + * 08 25 2010 george.huang + * NULL + * update OID/ registry control path for PM related settings + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 08 24 2010 chinghwa.yu + * NULL + * Update BOW for the 1st time. + * + * 08 23 2010 chinghwa.yu + * NULL + * Update for BOW. + * + * 08 20 2010 yuche.tsai + * NULL + * Add state change indication. + * + * 08 16 2010 yuche.tsai + * NULL + * Add support for P2P BSS update info. + * + * 08 12 2010 cp.wu + * NULL + * [removing debugging] not to dump beacon content. + * + * 08 12 2010 cp.wu + * NULL + * [AIS-FSM] honor registry setting for adhoc running mode. (A/B/G) + * + * 08 11 2010 cp.wu + * NULL + * 1) do not use in-stack variable for beacon updating. (for MAUI porting) + * 2) extending scanning result to 64 instead of 48 + * + * 08 04 2010 yarco.yang + * NULL + * Add TX_AMPDU and ADDBA_REJECT command + * + * 08 03 2010 cp.wu + * NULL + * surpress compilation warning. + * + * 08 03 2010 cp.wu + * NULL + * Centralize mgmt/system service procedures into independent calls. + * + * 07 28 2010 cp.wu + * NULL + * 1) eliminate redundant variable eOPMode in prAdapter->rWlanInfo + * 2) change nicMediaStateChange() API prototype + * + * 07 28 2010 cp.wu + * NULL + * sync. CMD_BSS_INFO structure change to CMD-EVENT v0.15. + * + * 07 24 2010 wh.su + * + * .support the Wi-Fi RSN + * + * 07 23 2010 cp.wu + * + * FIX: structure of CMD_SET_BSS_INFO has been changed but no follow-ups are done. + * + * 07 22 2010 george.huang + * + * . + * + * 07 22 2010 george.huang + * + * Update fgIsQoS information in BSS INFO by CMD + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * Add Ad-Hoc support to AIS-FSM + * + * 07 14 2010 yarco.yang + * + * 1. Remove CFG_MQM_MIGRATION + * 2. Add CMD_UPDATE_WMM_PARMS command + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * update prStaRecOfAP with BSS-INFO. + * + * 07 06 2010 george.huang + * [WPD00001556]Basic power managemenet function + * Update arguments for nicUpdateBeaconIETemplate() + * + * 07 06 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * STA-REC is maintained by CNM only. + * + * 07 05 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) ignore RSN checking when RSN is not turned on. + * 2) set STA-REC deactivation callback as NULL + * 3) add variable initialization API based on PHY configuration + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Support sync command of STA_REC + * + * 06 30 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * sync. with CMD/EVENT document ver0.07. + * + * 06 29 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * correct variable naming for 8-bit variable used in CMD_BEACON_TEMPLATE_UPDATE. + * + * 06 29 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) sync to. CMD/EVENT document v0.03 + * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. + * 3) send command packet to indicate FW-PM after + * a) 1st beacon is received after AIS has connected to an AP + * b) IBSS-ALONE has been created + * c) IBSS-MERGE has occured + * + * 06 25 2010 george.huang + * [WPD00001556]Basic power managemenet function + * Create beacon update path, with expose bssUpdateBeaconContent() + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * fill fgIsUapsdConnection when indicating BSS-CREATE with AIS-STA mode. + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add command warpper for STA-REC/BSS-INFO sync. + * 2) enhance command packet sending procedure for non-oid part + * 3) add command packet definitions for STA-REC/BSS-INFO sync. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implement TX_DONE callback path. + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * remove duplicate variable for migration. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * TX descriptors are now allocated once for reducing allocation overhead + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 + * 2) when disconnected, indicate nic directly (no event is needed) + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 04 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) surpress compiler warning + * 2) when acqruing LP-own, keep writing WHLPCR whenever OWN is not acquired yet + * + * 04 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * surpress compiler warning + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * * * * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose + * + * 04 12 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add channel frequency <-> number conversion + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer + * + * 04 06 2010 cp.wu + * [WPD00003827][MT6620 Wi-Fi] Chariot fail and following ping fail, no pkt send from driver + * correct nicProcessIST_impl() for interrupt status brought up by RX enhanced response + * + * 03 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add ACPI D0/D3 state switching support + * * * * * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response + * + * 03 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * always process TX interrupt first then RX interrupt. + * + * 02 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct behavior to prevent duplicated RX handling for RX0_DONE and RX1_DONE + * + * 02 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add checksum offloading support. +** \main\maintrunk.MT6620WiFiDriver_Prj\27 2009-12-16 18:03:43 GMT mtk02752 +** handling enhanced response which fields are fetched at different moments +** \main\maintrunk.MT6620WiFiDriver_Prj\26 2009-12-15 17:00:29 GMT mtk02752 +** if RX enhanced response is used, D2H interrupt status should be coming from buffered result as well +** \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-12-15 12:01:55 GMT mtk02752 +** if TX_DONE bit is not set but WTSR0/WTSR1 is non-zero, then set TX_DONE bit due to time latency of interrupt status enhanced response +** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-12-10 16:52:52 GMT mtk02752 +** code clean +** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-11-24 20:51:01 GMT mtk02752 +** integrate with SD1 by invoking qmHandleMailboxRxMessage() +** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-16 17:32:33 GMT mtk02752 +** prepare code for invoking rxHandleMailboxRxMessage() +** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-11 10:36:08 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-11-09 22:56:41 GMT mtk01084 +** modify HW access routines +** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-10-30 18:17:20 GMT mtk01084 +** prevent warning +** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-10-29 19:54:57 GMT mtk01084 +** init HIF +** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-10-23 16:08:30 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-10-13 21:59:12 GMT mtk01084 +** update for new HW design +** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-09-09 17:26:15 GMT mtk01084 +** modify for CFG_TEST_WITH_MT5921 +** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-05-19 10:55:22 GMT mtk01461 +** Unmask the unused HISR +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-05-18 15:59:13 GMT mtk01084 +** remove debug purpose code +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-05-18 14:05:02 GMT mtk01084 +** update for WIFI ownback part on initial +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-05-04 21:32:57 GMT mtk01084 +** add temporarily code to set driver own on adapter initialization +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-04-28 10:35:41 GMT mtk01461 +** Add init of TX aggregation and fix RX STATUS is DW align for SDIO_STATUS_ENHANCE mode +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-24 21:12:10 GMT mtk01104 +** Add function nicRestoreSpiDefMode() +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-21 09:43:31 GMT mtk01461 +** Revise for MTK coding style - nicInitializeAdapter() +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-17 19:52:47 GMT mtk01461 +** Update allocate Adapter Memory for MGMT Memory pool +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-01 10:57:08 GMT mtk01461 +** Refine the order of release memory from pucRxCoalescingBufCached +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-19 18:32:57 GMT mtk01084 +** update for basic power management functions +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-18 21:00:14 GMT mtk01426 +** Add CFG_SDIO_RX_ENHANCE support +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:10:27 GMT mtk01461 +** Update TX PATH API +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:25:59 GMT mtk01426 +** Init for develop +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +const UINT_8 aucPhyCfg2PhyTypeSet[PHY_CONFIG_NUM] = +{ + PHY_TYPE_SET_802_11ABG, /* PHY_CONFIG_802_11ABG */ + PHY_TYPE_SET_802_11BG, /* PHY_CONFIG_802_11BG */ + PHY_TYPE_SET_802_11G, /* PHY_CONFIG_802_11G */ + PHY_TYPE_SET_802_11A, /* PHY_CONFIG_802_11A */ + PHY_TYPE_SET_802_11B, /* PHY_CONFIG_802_11B */ + PHY_TYPE_SET_802_11ABGN, /* PHY_CONFIG_802_11ABGN */ + PHY_TYPE_SET_802_11BGN, /* PHY_CONFIG_802_11BGN */ + PHY_TYPE_SET_802_11AN, /* PHY_CONFIG_802_11AN */ + PHY_TYPE_SET_802_11GN /* PHY_CONFIG_802_11GN */ +}; + +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) + #define REQ_GATING_ENABLE_H2D_INT BIT(31) + #define REQ_GATING_DISABLE_H2D_INT BIT(30) + #define ACK_GATING_ENABLE_D2H_INT BIT(31) + #define ACK_GATING_DISABLE_D2H_INT BIT(30) + + #define GATING_CONTROL_POLL_LIMIT 64 +#endif + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +static INT_EVENT_MAP_T arIntEventMapTable[] = { + {WHISR_ABNORMAL_INT, INT_EVENT_ABNORMAL}, + {WHISR_D2H_SW_INT, INT_EVENT_SW_INT}, + {WHISR_TX_DONE_INT, INT_EVENT_TX}, + {(WHISR_RX0_DONE_INT | WHISR_RX1_DONE_INT), INT_EVENT_RX} +}; + +static const UINT_8 ucIntEventMapSize = (sizeof(arIntEventMapTable) / sizeof(INT_EVENT_MAP_T)); + +static IST_EVENT_FUNCTION apfnEventFuncTable[] = { + nicProcessAbnormalInterrupt, /*!< INT_EVENT_ABNORMAL */ + nicProcessSoftwareInterrupt, /*!< INT_EVENT_SW_INT */ + nicProcessTxInterrupt, /*!< INT_EVENT_TX */ + nicProcessRxInterrupt, /*!< INT_EVENT_RX */ +}; +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +/*! This macro is used to reduce coding errors inside nicAllocateAdapterMemory() + * and also enhance the readability. + */ +#define LOCAL_NIC_ALLOCATE_MEMORY(pucMem, u4Size, eMemType, pucComment) \ + { \ + DBGLOG(INIT, INFO, ("Allocating %ld bytes for %s.\n", u4Size, pucComment)); \ + if ((pucMem = (PUINT_8)kalMemAlloc(u4Size, eMemType)) == (PUINT_8)NULL) { \ + DBGLOG(INIT, ERROR, ("Could not allocate %ld bytes for %s.\n", u4Size, pucComment)); \ + break; \ + } \ + ASSERT(((UINT_32)pucMem % 4) == 0); \ + DBGLOG(INIT, INFO, ("Virtual Address = %08lx for %s.\n", (UINT_32)pucMem, pucComment)); \ + } + + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This routine is responsible for the allocation of the data structures +* inside the Adapter structure, include: +* 1. SW_RFB_Ts +* 2. Common coalescing buffer for TX PATH. +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @retval WLAN_STATUS_SUCCESS - Has enough memory. +* @retval WLAN_STATUS_RESOURCES - Memory is not enough. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicAllocateAdapterMemory ( + IN P_ADAPTER_T prAdapter + ) +{ + WLAN_STATUS status = WLAN_STATUS_RESOURCES; + P_RX_CTRL_T prRxCtrl; + P_TX_CTRL_T prTxCtrl; + + DEBUGFUNC("nicAllocateAdapterMemory"); + + ASSERT(prAdapter); + prRxCtrl = &prAdapter->rRxCtrl; + prTxCtrl = &prAdapter->rTxCtrl; + + do { + //4 <0> Reset all Memory Handler + #if CFG_DBG_MGT_BUF + prAdapter->u4MemFreeDynamicCount = 0; + prAdapter->u4MemAllocDynamicCount = 0; + #endif + prAdapter->pucMgtBufCached = (PUINT_8)NULL; + prRxCtrl->pucRxCached = (PUINT_8)NULL; + prAdapter->prSDIOCtrl = (P_SDIO_CTRL_T)NULL; + + + //4 <1> Memory for Management Memory Pool and CMD_INFO_T + /* Allocate memory for the CMD_INFO_T and its MGMT memory pool. */ + prAdapter->u4MgtBufCachedSize = MGT_BUFFER_SIZE; + + LOCAL_NIC_ALLOCATE_MEMORY(prAdapter->pucMgtBufCached, + prAdapter->u4MgtBufCachedSize, + VIR_MEM_TYPE, + "COMMON MGMT MEMORY POOL"); + + //4 <2> Memory for RX Descriptor + /* Initialize the number of rx buffers we will have in our queue. */ + /* We may setup ucRxPacketDescriptors by GLUE Layer, and using + * this variable directly. + */ + /* Allocate memory for the SW receive structures. */ + prRxCtrl->u4RxCachedSize = CFG_RX_MAX_PKT_NUM * \ + ALIGN_4(sizeof(SW_RFB_T)); + + LOCAL_NIC_ALLOCATE_MEMORY(prRxCtrl->pucRxCached, + prRxCtrl->u4RxCachedSize, + VIR_MEM_TYPE, + "SW_RFB_T"); + + //4 <3> Memory for TX DEscriptor + prTxCtrl->u4TxCachedSize = CFG_TX_MAX_PKT_NUM * \ + ALIGN_4(sizeof(MSDU_INFO_T)); + + LOCAL_NIC_ALLOCATE_MEMORY(prTxCtrl->pucTxCached, + prTxCtrl->u4TxCachedSize, + VIR_MEM_TYPE, + "MSDU_INFO_T"); + + //4 <4> Memory for Common Coalescing Buffer +#if CFG_COALESCING_BUFFER_SIZE || CFG_SDIO_RX_AGG + prAdapter->pucCoalescingBufCached = (PUINT_8)NULL; + + /* Allocate memory for the common coalescing buffer. */ + prAdapter->u4CoalescingBufCachedSize = CFG_COALESCING_BUFFER_SIZE > CFG_RX_COALESCING_BUFFER_SIZE ? + CFG_COALESCING_BUFFER_SIZE : CFG_RX_COALESCING_BUFFER_SIZE; + + prAdapter->pucCoalescingBufCached = + kalAllocateIOBuffer(prAdapter->u4CoalescingBufCachedSize); + + if(prAdapter->pucCoalescingBufCached == NULL) { + DBGLOG(INIT, ERROR, ("Could not allocate %ld bytes for coalescing buffer.\n", prAdapter->u4CoalescingBufCachedSize)); + break; + } +#endif /* CFG_COALESCING_BUFFER_SIZE */ + + //4 <5> Memory for enhanced interrupt response + prAdapter->prSDIOCtrl = (P_SDIO_CTRL_T) + kalAllocateIOBuffer(sizeof(ENHANCE_MODE_DATA_STRUCT_T)); + + if(prAdapter->prSDIOCtrl == NULL) { + DBGLOG(INIT, ERROR, ("Could not allocate %ld bytes for interrupt response.\n", sizeof(ENHANCE_MODE_DATA_STRUCT_T))); + break; + } + + status = WLAN_STATUS_SUCCESS; + + } + while(FALSE); + + if(status != WLAN_STATUS_SUCCESS) { + nicReleaseAdapterMemory(prAdapter); + } + + return status; + +} /* end of nicAllocateAdapterMemory() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This routine is responsible for releasing the allocated memory by +* nicAllocatedAdapterMemory(). +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicReleaseAdapterMemory ( + IN P_ADAPTER_T prAdapter + ) +{ + P_TX_CTRL_T prTxCtrl; + P_RX_CTRL_T prRxCtrl; + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + prRxCtrl = &prAdapter->rRxCtrl; + + //4 <5> Memory for enhanced interrupt response + if (prAdapter->prSDIOCtrl) { + kalReleaseIOBuffer((PVOID)prAdapter->prSDIOCtrl, sizeof(ENHANCE_MODE_DATA_STRUCT_T)); + prAdapter->prSDIOCtrl = (P_SDIO_CTRL_T)NULL; + } + + //4 <4> Memory for Common Coalescing Buffer +#if CFG_COALESCING_BUFFER_SIZE || CFG_SDIO_RX_AGG + if (prAdapter->pucCoalescingBufCached) { + kalReleaseIOBuffer((PVOID)prAdapter->pucCoalescingBufCached, prAdapter->u4CoalescingBufCachedSize); + prAdapter->pucCoalescingBufCached = (PUINT_8)NULL; + } +#endif /* CFG_COALESCING_BUFFER_SIZE */ + + //4 <3> Memory for TX Descriptor + if (prTxCtrl->pucTxCached) { + kalMemFree((PVOID)prTxCtrl->pucTxCached, + VIR_MEM_TYPE, + prTxCtrl->u4TxCachedSize); + prTxCtrl->pucTxCached = (PUINT_8)NULL; + } + + //4 <2> Memory for RX Descriptor + if (prRxCtrl->pucRxCached) { + kalMemFree((PVOID)prRxCtrl->pucRxCached, + VIR_MEM_TYPE, + prRxCtrl->u4RxCachedSize); + prRxCtrl->pucRxCached = (PUINT_8)NULL; + } + + //4 <1> Memory for Management Memory Pool + if (prAdapter->pucMgtBufCached) { + kalMemFree((PVOID)prAdapter->pucMgtBufCached, + VIR_MEM_TYPE, + prAdapter->u4MgtBufCachedSize); + prAdapter->pucMgtBufCached = (PUINT_8)NULL; + } + +#if CFG_DBG_MGT_BUF + /* Check if all allocated memories are free */ + ASSERT(prAdapter->u4MemFreeDynamicCount == + prAdapter->u4MemAllocDynamicCount); +#endif + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief disable global interrupt +* +* @param prAdapter pointer to the Adapter handler +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicDisableInterrupt ( + IN P_ADAPTER_T prAdapter + ) +{ + ASSERT(prAdapter); + + HAL_BYTE_WR(prAdapter, MCR_WHLPCR, WHLPCR_INT_EN_CLR); + + prAdapter->fgIsIntEnable = FALSE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief enable global interrupt +* +* @param prAdapter pointer to the Adapter handler +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicEnableInterrupt ( + IN P_ADAPTER_T prAdapter + ) +{ + BOOLEAN fgIsIntEnableCache; + + + ASSERT(prAdapter); + fgIsIntEnableCache = prAdapter->fgIsIntEnable; + + prAdapter->fgIsIntEnable = TRUE; // NOTE(Kevin): It must be placed before MCR GINT write. + + /* If need enable INT and also set LPOwn at the same time. */ + if (prAdapter->fgIsIntEnableWithLPOwnSet) { + prAdapter->fgIsIntEnableWithLPOwnSet = FALSE; /* NOTE(Kevin): It's better to place it + * before MCR GINT write. + */ + /* If INT was enabled, only set LPOwn */ + if (fgIsIntEnableCache) { + HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_SET); + prAdapter->fgIsFwOwn = TRUE; + } + /* If INT was not enabled, enable it and also set LPOwn now */ + else { + HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_SET | + WHLPCR_INT_EN_SET); + prAdapter->fgIsFwOwn = TRUE; + } + } + /* If INT was not enabled, enable it now */ + else if (!fgIsIntEnableCache) { + HAL_BYTE_WR(prAdapter, MCR_WHLPCR, WHLPCR_INT_EN_SET); + } + + return; +} /* end of nicEnableInterrupt() */ + + +#if CFG_SDIO_INTR_ENHANCE +/*----------------------------------------------------------------------------*/ +/*! +* @brief For SDIO enhance mode, set the max rx len and tx status +* +* @param prAdapter a pointer to adapter private data structure. +* +* @return - none +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicSDIOInit ( + IN P_ADAPTER_T prAdapter + ) +{ + UINT_32 u4Value = 0; + + ASSERT(prAdapter); + + //4 <1> Check STATUS Buffer is DW alignment. + ASSERT( IS_ALIGN_4( (UINT_32)&prAdapter->prSDIOCtrl->u4WHISR ) ); + + //4 <2> Setup STATUS count. + { + HAL_MCR_RD(prAdapter, MCR_WHCR, &u4Value); + + //4 <2.1> Setup the number of maximum RX length to be report + u4Value &= ~(WHCR_MAX_HIF_RX_LEN_NUM); + u4Value |= ((SDIO_MAXIMUM_RX_LEN_NUM << WHCR_OFFSET_MAX_HIF_RX_LEN_NUM)); + + //4 <2.2> Setup RX enhancement mode +#if CFG_SDIO_RX_ENHANCE + u4Value |= WHCR_RX_ENHANCE_MODE_EN; +#else + u4Value &= ~WHCR_RX_ENHANCE_MODE_EN; +#endif /* CFG_SDIO_RX_AGG */ + + HAL_MCR_WR(prAdapter, MCR_WHCR, u4Value); + } + + return; + +} /* end of nicSDIOInit() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Read interrupt status from hardware +* +* @param prAdapter pointer to the Adapter handler +* @param the interrupts +* +* @return N/A +* +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicSDIOReadIntStatus ( + IN P_ADAPTER_T prAdapter, + OUT PUINT_32 pu4IntStatus + ) +{ + P_SDIO_CTRL_T prSDIOCtrl; + + DEBUGFUNC("nicSDIOReadIntStatus"); + + ASSERT(prAdapter); + ASSERT(pu4IntStatus); + + prSDIOCtrl = prAdapter->prSDIOCtrl; + ASSERT(prSDIOCtrl); + + HAL_PORT_RD(prAdapter, + MCR_WHISR, + sizeof(ENHANCE_MODE_DATA_STRUCT_T), + (PUINT_8)prSDIOCtrl, + sizeof(ENHANCE_MODE_DATA_STRUCT_T)); + + if(kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE + || fgIsBusAccessFailed == TRUE) { + *pu4IntStatus = 0; + return; + } + + /* workaround */ + if((prSDIOCtrl->u4WHISR & WHISR_TX_DONE_INT) == 0 && + (prSDIOCtrl->rTxInfo.au4WTSR[0] | prSDIOCtrl->rTxInfo.au4WTSR[1])) { + prSDIOCtrl->u4WHISR |= WHISR_TX_DONE_INT; + } + + if((prSDIOCtrl->u4WHISR & BIT(31)) == 0 && + HAL_GET_MAILBOX_READ_CLEAR(prAdapter) == TRUE && + (prSDIOCtrl->u4RcvMailbox0 != 0 || prSDIOCtrl->u4RcvMailbox1 != 0)) { + prSDIOCtrl->u4WHISR |= BIT(31); + } + + *pu4IntStatus = prSDIOCtrl->u4WHISR; + + return; +} /* end of nicSDIOReadIntStatus() */ +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* @brief The function used to read interrupt status and then invoking +* dispatching procedure for the appropriate functions +* corresponding to specific interrupt bits +* +* @param prAdapter pointer to the Adapter handler +* +* @retval WLAN_STATUS_SUCCESS +* @retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicProcessIST ( + IN P_ADAPTER_T prAdapter + ) +{ + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + UINT_32 u4IntStatus = 0; + UINT_32 i; + + DEBUGFUNC("nicProcessIST"); + //DBGLOG(INIT, LOUD, ("\n")); + + ASSERT(prAdapter); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, ("Fail in set nicProcessIST! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff)); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) + if(prAdapter->fgIsClockGatingEnabled == TRUE) { + nicDisableClockGating(prAdapter); + } +#endif + + for (i = 0; i < CFG_IST_LOOP_COUNT; i++) { + +#if CFG_SDIO_INTR_ENHANCE + nicSDIOReadIntStatus(prAdapter, &u4IntStatus); +#else + HAL_MCR_RD(prAdapter, MCR_WHISR, &u4IntStatus); +#endif /* CFG_SDIO_INTR_ENHANCE */ + + //DBGLOG(INIT, TRACE, ("u4IntStatus: 0x%x\n", u4IntStatus)); + + if (u4IntStatus & ~(WHIER_DEFAULT | WHIER_FW_OWN_BACK_INT_EN)) { + DBGLOG(INTR, WARN, ("Un-handled HISR %#x, HISR = %#x (HIER:0x%x)\n", + (u4IntStatus & ~WHIER_DEFAULT), u4IntStatus, WHIER_DEFAULT)); + u4IntStatus &= WHIER_DEFAULT; + } + + nicProcessIST_impl(prAdapter, u4IntStatus); + + if(u4IntStatus == 0) { + if(i == 0) { + u4Status = WLAN_STATUS_NOT_INDICATING; + } + break; + } + } + +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) + if(prAdapter->fgIsClockGatingEnabled == FALSE) { + nicEnableClockGating(prAdapter); + } +#endif + + return u4Status; +} /* end of nicProcessIST() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief The function used to dispatch the appropriate functions for specific +* interrupt bits +* +* @param prAdapter pointer to the Adapter handler +* u4IntStatus interrupt status bits +* +* @retval WLAN_STATUS_SUCCESS +* @retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicProcessIST_impl ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4IntStatus + ) +{ + UINT_32 u4IntCount = 0; + P_INT_EVENT_MAP_T prIntEventMap = NULL; + + ASSERT(prAdapter); + + prAdapter->u4IntStatus = u4IntStatus; + + /* Process each of the interrupt status consequently */ + prIntEventMap = &arIntEventMapTable[0]; + for (u4IntCount = 0; u4IntCount < ucIntEventMapSize; prIntEventMap++, u4IntCount++) { + if (prIntEventMap->u4Int & prAdapter->u4IntStatus) { + if(prIntEventMap->u4Event == INT_EVENT_RX && + prAdapter->fgIsEnterD3ReqIssued == TRUE) { + // ignore + } + else if (apfnEventFuncTable[prIntEventMap->u4Event] != NULL) { + apfnEventFuncTable[prIntEventMap->u4Event](prAdapter); + } + else { + DBGLOG(INTR , WARN, + ("Empty INTR handler! ISAR bit#: %ld, event:%d, func: 0x%x\n", + prIntEventMap->u4Int, prIntEventMap->u4Event, apfnEventFuncTable[prIntEventMap->u4Event])); + + ASSERT(0); // to trap any NULL interrupt handler + } + prAdapter->u4IntStatus &= ~prIntEventMap->u4Int; + } + } + + return WLAN_STATUS_SUCCESS; +} /* end of nicProcessIST_impl() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Verify the CHIP ID +* +* @param prAdapter a pointer to adapter private data structure. +* +* +* @retval TRUE CHIP ID is the same as the setting compiled +* @retval FALSE CHIP ID is different from the setting compiled +*/ +/*----------------------------------------------------------------------------*/ +BOOL +nicVerifyChipID ( + IN P_ADAPTER_T prAdapter + ) +{ + UINT_32 u4CIR = 0; + + ASSERT(prAdapter); + + HAL_MCR_RD(prAdapter, MCR_WCIR, &u4CIR ); + + DBGLOG(INIT, TRACE,("Chip ID: 0x%x\n", u4CIR & WCIR_CHIP_ID)); + DBGLOG(INIT, TRACE,("Revision ID: 0x%x\n", ((u4CIR & WCIR_REVISION_ID) >> 16))); + + if ((u4CIR & WCIR_CHIP_ID) != MTK_CHIP_REV) { + return FALSE; + } + + prAdapter->ucRevID = (UINT_8)(((u4CIR & WCIR_REVISION_ID) >> 16) & 0xF) ; + + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Initialize the MCR to the appropriate init value, and verify the init +* value +* +* @param prAdapter a pointer to adapter private data structure. +* +* @return - +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicMCRInit ( + IN P_ADAPTER_T prAdapter + ) +{ + + ASSERT(prAdapter); + + //4 <0> Initial value +} + +VOID +nicHifInit ( + IN P_ADAPTER_T prAdapter + ) +{ + + ASSERT(prAdapter); +#if 0 + /* reset event */ + nicPutMailbox(prAdapter, 0, 0x52455345); // RESE + nicPutMailbox(prAdapter, 1, 0x545F5746); // T_WF + nicSetSwIntr(prAdapter, BIT(16)); +#endif +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Initialize the Adapter soft variable +* +* @param prAdapter pointer to the Adapter handler +* +* @return (none) +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicInitializeAdapter ( + IN P_ADAPTER_T prAdapter + ) +{ + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + + prAdapter->fgIsIntEnableWithLPOwnSet = FALSE; + + do { + if (!nicVerifyChipID(prAdapter)) { + u4Status = WLAN_STATUS_FAILURE; + break; + } + + //4 <1> MCR init + nicMCRInit(prAdapter); + + #if CFG_SDIO_INTR_ENHANCE + nicSDIOInit(prAdapter); + #endif /* CFG_SDIO_INTR_ENHANCE */ + + HAL_MCR_WR(prAdapter, MCR_WHIER, WHIER_DEFAULT); + + + //4 <2> init FW HIF + nicHifInit(prAdapter); + } + while (FALSE); + + + return u4Status; +} + + +#if defined(_HIF_SPI) +/*----------------------------------------------------------------------------*/ +/*! +* \brief Restore the SPI Mode Select to default mode, +* this is important while driver is unload, and this must be last mcr +* since the operation will let the hif use 8bit mode access +* +* \param[in] prAdapter a pointer to adapter private data structure. +* \param[in] eGPIO2_Mode GPIO2 operation mode +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +void +nicRestoreSpiDefMode ( + IN P_ADAPTER_T prAdapter + ) +{ + ASSERT(prAdapter); + + HAL_MCR_WR(prAdapter, MCR_WCSR, SPICSR_8BIT_MODE_DATA); + +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process rx interrupt. When the rx +* Interrupt is asserted, it means there are frames in queue. +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicProcessAbnormalInterrupt ( + IN P_ADAPTER_T prAdapter + ) +{ + UINT_32 u4Value; + + HAL_MCR_RD(prAdapter, MCR_WASR, &u4Value); + DBGLOG(REQ, WARN, ("MCR_WASR: 0x%x \n", u4Value)); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief . +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicProcessFwOwnBackInterrupt( + IN P_ADAPTER_T prAdapter + ) +{ + + return; +} /* end of nicProcessFwOwnBackInterrupt() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief . +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicProcessSoftwareInterrupt( + IN P_ADAPTER_T prAdapter + ) +{ + UINT_32 u4IntrBits; + + ASSERT(prAdapter); + + u4IntrBits = prAdapter->u4IntStatus & BITS(8, 31); + + if((u4IntrBits & WHISR_D2H_SW_ASSERT_INFO_INT) != 0) { + nicPrintFirmwareAssertInfo(prAdapter); +#if CFG_CHIP_RESET_SUPPORT + glSendResetRequest(); +#endif + } + +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) + ASSERT((u4IntrBits & (ACK_GATING_ENABLE_D2H_INT | ACK_GATING_DISABLE_D2H_INT)) + != (ACK_GATING_ENABLE_D2H_INT | ACK_GATING_DISABLE_D2H_INT)); + + if(u4IntrBits & ACK_GATING_ENABLE_D2H_INT) { + prAdapter->fgIsClockGatingEnabled = TRUE; + } + + if(u4IntrBits & ACK_GATING_DISABLE_D2H_INT) { + prAdapter->fgIsClockGatingEnabled = FALSE; + + // Indicate Service Thread for TX + if(kalGetTxPendingCmdCount(prAdapter->prGlueInfo) > 0 + || wlanGetTxPendingFrameCount(prAdapter) > 0) { + kalSetEvent(prAdapter->prGlueInfo); + } + } +#endif + + DBGLOG(REQ, WARN, ("u4IntrBits: 0x%x \n", u4IntrBits)); + + return; +} /* end of nicProcessSoftwareInterrupt() */ + +VOID +nicPutMailbox ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4MailboxNum, + IN UINT_32 u4Data + ) +{ + if (u4MailboxNum == 0) { + HAL_MCR_WR(prAdapter, MCR_H2DSM0R, u4Data); + } else if (u4MailboxNum == 1) { + HAL_MCR_WR(prAdapter, MCR_H2DSM1R, u4Data); + } else { + ASSERT(0); + } +} + +VOID +nicGetMailbox ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4MailboxNum, + OUT PUINT_32 pu4Data + ) +{ + if (u4MailboxNum == 0) { + HAL_MCR_RD(prAdapter, MCR_D2HRM0R, pu4Data); + } else if (u4MailboxNum == 1) { + HAL_MCR_RD(prAdapter, MCR_D2HRM1R, pu4Data); + } else { + ASSERT(0); + } +} + +VOID +nicSetSwIntr ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4SwIntrBitmap + ) +{ + /* NOTE: + * SW interrup in HW bit 16 is mapping to SW bit 0 (shift 16bit in HW transparancy) + * SW interrupt valid from b0~b15 + */ + ASSERT((u4SwIntrBitmap & BITS(0, 15)) == 0); +// DBGLOG(INIT, TRACE, ("u4SwIntrBitmap: 0x%08x\n", u4SwIntrBitmap)); + + HAL_MCR_WR(prAdapter, MCR_WSICR, u4SwIntrBitmap); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This procedure is used to dequeue from prAdapter->rPendingCmdQueue +* with specified sequential number +* +* @param prAdapter Pointer of ADAPTER_T +* ucSeqNum Sequential Number +* +* @retval - P_CMD_INFO_T +*/ +/*----------------------------------------------------------------------------*/ +P_CMD_INFO_T +nicGetPendingCmdInfo ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucSeqNum + ) +{ + P_QUE_T prCmdQue; + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T)NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); + + prCmdQue = &prAdapter->rPendingCmdQueue; + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + + if(prCmdInfo->ucCmdSeqNum == ucSeqNum) + break; + else { + QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); + + prCmdInfo = NULL; + } + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); + + return prCmdInfo; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This procedure is used to dequeue from prAdapter->rTxCtrl.rTxMgmtTxingQueue +* with specified sequential number +* +* @param prAdapter Pointer of ADAPTER_T +* ucSeqNum Sequential Number +* +* @retval - P_MSDU_INFO_T +*/ +/*----------------------------------------------------------------------------*/ +P_MSDU_INFO_T +nicGetPendingTxMsduInfo ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucSeqNum + ) +{ + P_QUE_T prTxingQue; + QUE_T rTempQue; + P_QUE_T prTempQue = &rTempQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + P_MSDU_INFO_T prMsduInfo = (P_MSDU_INFO_T)NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + + prTxingQue = &(prAdapter->rTxCtrl.rTxMgmtTxingQueue); + QUEUE_MOVE_ALL(prTempQue, prTxingQue); + + QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prMsduInfo = (P_MSDU_INFO_T)prQueueEntry; + + if(prMsduInfo->ucTxSeqNum == ucSeqNum) + break; + else { + QUEUE_INSERT_TAIL(prTxingQue, prQueueEntry); + + prMsduInfo = NULL; + } + + QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); + } + QUEUE_CONCATENATE_QUEUES(prTxingQue, prTempQue); + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + + return prMsduInfo; +} + +P_MSDU_INFO_T +nicGetPendingStaMMPDU ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucStaRecIdx + ) +{ + P_MSDU_INFO_T prMsduInfoListHead = (P_MSDU_INFO_T)NULL; + P_QUE_T prTxingQue = (P_QUE_T)NULL; + QUE_T rTempQue; + P_QUE_T prTempQue = &rTempQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + P_MSDU_INFO_T prMsduInfo = (P_MSDU_INFO_T)NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + do { + if (prAdapter == NULL) { + + ASSERT(FALSE); + break; + } + + prTxingQue = &(prAdapter->rTxCtrl.rTxMgmtTxingQueue); + QUEUE_MOVE_ALL(prTempQue, prTxingQue); + + QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prMsduInfo = (P_MSDU_INFO_T)prQueueEntry; + + if ((prMsduInfo->ucStaRecIndex == ucStaRecIdx) && (prMsduInfo->pfTxDoneHandler != NULL)) { + QM_TX_SET_NEXT_MSDU_INFO(prMsduInfo, + prMsduInfoListHead); + prMsduInfoListHead = prMsduInfo; + } + else { + QUEUE_INSERT_TAIL(prTxingQue, prQueueEntry); + + prMsduInfo = NULL; + } + + + QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); + } + + } while (FALSE); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + + + return prMsduInfoListHead; +} /* nicGetPendingStaMMPDU */ + + +VOID +nicFreePendingTxMsduInfoByNetwork ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType + ) +{ + P_QUE_T prTxingQue; + QUE_T rTempQue; + P_QUE_T prTempQue = &rTempQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + P_MSDU_INFO_T prMsduInfoListHead = (P_MSDU_INFO_T)NULL; + P_MSDU_INFO_T prMsduInfoListTail = (P_MSDU_INFO_T)NULL; + P_MSDU_INFO_T prMsduInfo = (P_MSDU_INFO_T)NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + + prTxingQue = &(prAdapter->rTxCtrl.rTxMgmtTxingQueue); + QUEUE_MOVE_ALL(prTempQue, prTxingQue); + + QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prMsduInfo = (P_MSDU_INFO_T)prQueueEntry; + + if((ENUM_NETWORK_TYPE_INDEX_T)(prMsduInfo->ucNetworkType) == eNetworkType) { + if(prMsduInfoListHead == NULL) { + prMsduInfoListHead = prMsduInfoListTail = prMsduInfo; + } + else { + QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, prMsduInfo); + prMsduInfoListTail = prMsduInfo; + } + } + else { + QUEUE_INSERT_TAIL(prTxingQue, prQueueEntry); + + prMsduInfo = NULL; + } + + QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); + } + QUEUE_CONCATENATE_QUEUES(prTxingQue, prTempQue); + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + + /* free */ + if(prMsduInfoListHead) { + nicTxFreeMsduInfoPacket(prAdapter, prMsduInfoListHead); + } + + return; + +} /* end of nicFreePendingTxMsduInfoByNetwork() */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This procedure is used to retrieve a CMD sequence number atomically +* +* @param prAdapter Pointer of ADAPTER_T +* +* @retval - UINT_8 +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 +nicIncreaseCmdSeqNum ( + IN P_ADAPTER_T prAdapter + ) +{ + UINT_8 ucRetval; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_SEQ_NUM); + + prAdapter->ucCmdSeqNum++; + ucRetval = prAdapter->ucCmdSeqNum; + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_SEQ_NUM); + + return ucRetval; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This procedure is used to retrieve a TX sequence number atomically +* +* @param prAdapter Pointer of ADAPTER_T +* +* @retval - UINT_8 +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 +nicIncreaseTxSeqNum ( + IN P_ADAPTER_T prAdapter + ) +{ + UINT_8 ucRetval; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_SEQ_NUM); + + prAdapter->ucTxSeqNum++; + ucRetval = prAdapter->ucTxSeqNum; + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_SEQ_NUM); + + return ucRetval; +} + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to handle +* media state change event +* +* @param +* +* @retval +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicMediaStateChange ( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType, + IN P_EVENT_CONNECTION_STATUS prConnectionStatus + ) +{ + P_GLUE_INFO_T prGlueInfo; + + ASSERT(prAdapter); + prGlueInfo = prAdapter->prGlueInfo; + + switch(eNetworkType) { + case NETWORK_TYPE_AIS_INDEX: + if (prConnectionStatus->ucMediaStatus == PARAM_MEDIA_STATE_DISCONNECTED) { // disconnected + if(kalGetMediaStateIndicated(prGlueInfo) != PARAM_MEDIA_STATE_DISCONNECTED) { + + kalIndicateStatusAndComplete(prGlueInfo, + WLAN_STATUS_MEDIA_DISCONNECT, + NULL, + 0); + + prAdapter->rWlanInfo.u4SysTime = kalGetTimeTick(); + } + + /* reset buffered link quality information */ + prAdapter->fgIsLinkQualityValid = FALSE; + prAdapter->fgIsLinkRateValid = FALSE; + } + else if(prConnectionStatus->ucMediaStatus == PARAM_MEDIA_STATE_CONNECTED) { // connected + prAdapter->rWlanInfo.u4SysTime = kalGetTimeTick(); + + // fill information for association result + prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen + = prConnectionStatus->ucSsidLen; + kalMemCopy(prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, + prConnectionStatus->aucSsid, + prConnectionStatus->ucSsidLen); + kalMemCopy(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, + prConnectionStatus->aucBssid, + MAC_ADDR_LEN); + prAdapter->rWlanInfo.rCurrBssId.u4Privacy + = prConnectionStatus->ucEncryptStatus; // @FIXME + prAdapter->rWlanInfo.rCurrBssId.rRssi + = 0; //@FIXME + prAdapter->rWlanInfo.rCurrBssId.eNetworkTypeInUse + = PARAM_NETWORK_TYPE_AUTOMODE; //@FIXME + prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4BeaconPeriod + = prConnectionStatus->u2BeaconPeriod; + prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4ATIMWindow + = prConnectionStatus->u2ATIMWindow; + prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4DSConfig + = prConnectionStatus->u4FreqInKHz; + prAdapter->rWlanInfo.ucNetworkType + = prConnectionStatus->ucNetworkType; + prAdapter->rWlanInfo.rCurrBssId.eOpMode + = (ENUM_PARAM_OP_MODE_T) prConnectionStatus->ucInfraMode; + + // always indicate to OS according to MSDN (re-association/roaming) + kalIndicateStatusAndComplete(prGlueInfo, + WLAN_STATUS_MEDIA_CONNECT, + NULL, + 0); + } + break; + +#if CFG_ENABLE_BT_OVER_WIFI + case NETWORK_TYPE_BOW_INDEX: + break; +#endif + +#if CFG_ENABLE_WIFI_DIRECT + case NETWORK_TYPE_P2P_INDEX: + break; +#endif + default: + ASSERT(0); + } + + return WLAN_STATUS_SUCCESS; +} /* nicMediaStateChange */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to convert between +* frequency and channel number +* +* @param u4ChannelNum +* +* @retval - Frequency in unit of KHz, 0 for invalid channel number +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 +nicChannelNum2Freq ( + UINT_32 u4ChannelNum + ) +{ + UINT_32 u4ChannelInMHz; + + if(u4ChannelNum >= 1 && u4ChannelNum <= 13) { + u4ChannelInMHz = 2412 + (u4ChannelNum - 1) * 5; + } + else if(u4ChannelNum == 14) { + u4ChannelInMHz = 2484; + } + else if(u4ChannelNum == 133) { + u4ChannelInMHz = 3665; // 802.11y + } + else if(u4ChannelNum == 137) { + u4ChannelInMHz = 3685; // 802.11y + } + else if(u4ChannelNum >= 34 && u4ChannelNum <= 165) { + u4ChannelInMHz = 5000 + u4ChannelNum * 5; + } + else if(u4ChannelNum >= 183 && u4ChannelNum <= 196) { + u4ChannelInMHz = 4000 + u4ChannelNum * 5; + } + else { + u4ChannelInMHz = 0; + } + + return 1000 * u4ChannelInMHz; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to convert between +* frequency and channel number +* +* @param u4FreqInKHz +* +* @retval - Frequency Number, 0 for invalid freqency +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 +nicFreq2ChannelNum ( + UINT_32 u4FreqInKHz + ) +{ + switch(u4FreqInKHz) { + case 2412000: + return 1; + case 2417000: + return 2; + case 2422000: + return 3; + case 2427000: + return 4; + case 2432000: + return 5; + case 2437000: + return 6; + case 2442000: + return 7; + case 2447000: + return 8; + case 2452000: + return 9; + case 2457000: + return 10; + case 2462000: + return 11; + case 2467000: + return 12; + case 2472000: + return 13; + case 2484000: + return 14; + case 3665000: + return 133; // 802.11y + case 3685000: + return 137; // 802.11y + case 4915000: + return 183; + case 4920000: + return 184; + case 4925000: + return 185; + case 4930000: + return 186; + case 4935000: + return 187; + case 4940000: + return 188; + case 4945000: + return 189; + case 4960000: + return 192; + case 4980000: + return 196; + case 5170000: + return 34; + case 5180000: + return 36; + case 5190000: + return 38; + case 5200000: + return 40; + case 5210000: + return 42; + case 5220000: + return 44; + case 5230000: + return 46; + case 5240000: + return 48; + case 5250000: + return 50; + case 5260000: + return 52; + case 5270000: + return 54; + case 5280000: + return 56; + case 5290000: + return 58; + case 5300000: + return 60; + case 5320000: + return 64; + case 5500000: + return 100; + case 5520000: + return 104; + case 5540000: + return 108; + case 5560000: + return 112; + case 5580000: + return 116; + case 5600000: + return 120; + case 5620000: + return 124; + case 5640000: + return 128; + case 5660000: + return 132; + case 5680000: + return 136; + case 5700000: + return 140; + case 5745000: + return 149; + case 5765000: + return 153; + case 5785000: + return 157; + case 5805000: + return 161; + case 5825000: + return 165; + default: + return 0; + } +} + + +/* firmware command wrapper */ +/* NETWORK (WIFISYS) */ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to activate WIFISYS for specified network +* +* @param prAdapter Pointer of ADAPTER_T +* eNetworkTypeIdx Index of network type +* +* @retval - +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicActivateNetwork( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx + ) +{ + CMD_BSS_ACTIVATE_CTRL rCmdActivateCtrl; + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); + + rCmdActivateCtrl.ucNetTypeIndex = (UINT_8)eNetworkTypeIdx; + rCmdActivateCtrl.ucActive = 1; + + if (((UINT_8) eNetworkTypeIdx) < NETWORK_TYPE_INDEX_NUM) { + prBssInfo = &prAdapter->rWifiVar.arBssInfo[eNetworkTypeIdx]; + prBssInfo->fg40mBwAllowed = FALSE; + prBssInfo->fgAssoc40mBwAllowed = FALSE; + } + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_BSS_ACTIVATE_CTRL, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(CMD_BSS_ACTIVATE_CTRL), + (PUINT_8)&rCmdActivateCtrl, + NULL, + 0); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to deactivate WIFISYS for specified network +* +* @param prAdapter Pointer of ADAPTER_T +* eNetworkTypeIdx Index of network type +* +* @retval - +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicDeactivateNetwork( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx + ) +{ + WLAN_STATUS u4Status; + CMD_BSS_ACTIVATE_CTRL rCmdActivateCtrl; + + ASSERT(prAdapter); + ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); + + rCmdActivateCtrl.ucNetTypeIndex = (UINT_8)eNetworkTypeIdx; + rCmdActivateCtrl.ucActive = 0; + + u4Status = wlanSendSetQueryCmd(prAdapter, + CMD_ID_BSS_ACTIVATE_CTRL, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(CMD_BSS_ACTIVATE_CTRL), + (PUINT_8)&rCmdActivateCtrl, + NULL, + 0); + + /* free all correlated station records */ + cnmStaFreeAllStaByNetType(prAdapter, eNetworkTypeIdx, FALSE); + qmFreeAllByNetType(prAdapter, eNetworkTypeIdx); + nicFreePendingTxMsduInfoByNetwork(prAdapter, eNetworkTypeIdx); + kalClearSecurityFramesByNetType(prAdapter->prGlueInfo, eNetworkTypeIdx); + + return u4Status; +} + + +/* BSS-INFO */ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to sync bss info with firmware +* when a new BSS has been connected or disconnected +* +* @param prAdapter Pointer of ADAPTER_T +* eNetworkTypeIdx Index of BSS-INFO type +* +* @retval - +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicUpdateBss( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx + ) +{ + WLAN_STATUS u4Status; + P_BSS_INFO_T prBssInfo; + CMD_SET_BSS_INFO rCmdSetBssInfo; + + ASSERT(prAdapter); + ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); + DBGLOG(INIT, LOUD, ("nicUpdateBss\n")); + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetworkTypeIdx]); + + kalMemZero(&rCmdSetBssInfo, sizeof(CMD_SET_BSS_INFO)); + + rCmdSetBssInfo.ucNetTypeIndex = (UINT_8)eNetworkTypeIdx; + rCmdSetBssInfo.ucConnectionState = (UINT_8)prBssInfo->eConnectionState; + rCmdSetBssInfo.ucCurrentOPMode = (UINT_8)prBssInfo->eCurrentOPMode; + rCmdSetBssInfo.ucSSIDLen = (UINT_8)prBssInfo->ucSSIDLen; + kalMemCopy(rCmdSetBssInfo.aucSSID, prBssInfo->aucSSID, prBssInfo->ucSSIDLen); + COPY_MAC_ADDR(rCmdSetBssInfo.aucBSSID, prBssInfo->aucBSSID); + rCmdSetBssInfo.ucIsQBSS = (UINT_8)prBssInfo->fgIsQBSS; + rCmdSetBssInfo.ucNonHTBasicPhyType = prBssInfo->ucNonHTBasicPhyType; + rCmdSetBssInfo.u2OperationalRateSet = prBssInfo->u2OperationalRateSet; + rCmdSetBssInfo.u2BSSBasicRateSet = prBssInfo->u2BSSBasicRateSet; + rCmdSetBssInfo.ucPhyTypeSet = prBssInfo->ucPhyTypeSet; +#if CFG_ENABLE_WIFI_DIRECT + if(prAdapter->fgIsP2PRegistered) { + COPY_MAC_ADDR(rCmdSetBssInfo.aucOwnMac, prBssInfo->aucOwnMacAddr); + } +#endif + + rlmFillSyncCmdParam(&rCmdSetBssInfo.rBssRlmParam, prBssInfo); + + rCmdSetBssInfo.fgWapiMode = (UINT_8)FALSE; + + if(rCmdSetBssInfo.ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { + P_CONNECTION_SETTINGS_T prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + rCmdSetBssInfo.ucAuthMode = (UINT_8)prConnSettings->eAuthMode; + rCmdSetBssInfo.ucEncStatus = (UINT_8)prConnSettings->eEncStatus; + rCmdSetBssInfo.fgWapiMode = (UINT_8)prConnSettings->fgWapiMode; + } +#if CFG_ENABLE_BT_OVER_WIFI + else if(rCmdSetBssInfo.ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) { + //P_CONNECTION_SETTINGS_T prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + rCmdSetBssInfo.ucAuthMode = (UINT_8)AUTH_MODE_WPA2_PSK; + rCmdSetBssInfo.ucEncStatus = (UINT_8)ENUM_ENCRYPTION3_KEY_ABSENT; + } +#endif + else { +#if CFG_ENABLE_WIFI_DIRECT + if(prAdapter->fgIsP2PRegistered) { + if (prAdapter->rP2pFuncLkr.prKalP2pGetCipher && + prAdapter->rP2pFuncLkr.prKalP2pGetCipher(prAdapter->prGlueInfo)) { + rCmdSetBssInfo.ucAuthMode = (UINT_8)AUTH_MODE_WPA2_PSK; + rCmdSetBssInfo.ucEncStatus = (UINT_8)ENUM_ENCRYPTION3_KEY_ABSENT; + } + else { + rCmdSetBssInfo.ucAuthMode = (UINT_8)AUTH_MODE_OPEN; + rCmdSetBssInfo.ucEncStatus = (UINT_8)ENUM_ENCRYPTION_DISABLED; + } + rCmdSetBssInfo.fgIsApMode = prAdapter->rP2pFuncLkr.prP2pFuncIsApMode(prAdapter->rWifiVar.prP2pFsmInfo); + } +#else + rCmdSetBssInfo.ucAuthMode = (UINT_8)AUTH_MODE_WPA2_PSK; + rCmdSetBssInfo.ucEncStatus = (UINT_8)ENUM_ENCRYPTION3_KEY_ABSENT; +#endif + } + + if(eNetworkTypeIdx == NETWORK_TYPE_AIS_INDEX && + prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE && + prBssInfo->prStaRecOfAP != NULL) { + rCmdSetBssInfo.ucStaRecIdxOfAP = prBssInfo->prStaRecOfAP->ucIndex; + + cnmAisInfraConnectNotify(prAdapter); + } +#if CFG_ENABLE_WIFI_DIRECT + else if ((prAdapter->fgIsP2PRegistered) && + (eNetworkTypeIdx == NETWORK_TYPE_P2P_INDEX) && + (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) && + (prBssInfo->prStaRecOfAP != NULL)) { + rCmdSetBssInfo.ucStaRecIdxOfAP = prBssInfo->prStaRecOfAP->ucIndex; + } +#endif + +#if CFG_ENABLE_BT_OVER_WIFI + else if (eNetworkTypeIdx == NETWORK_TYPE_BOW_INDEX && + prBssInfo->eCurrentOPMode == OP_MODE_BOW && + prBssInfo->prStaRecOfAP != NULL) { + rCmdSetBssInfo.ucStaRecIdxOfAP = prBssInfo->prStaRecOfAP->ucIndex; + } +#endif + else { + rCmdSetBssInfo.ucStaRecIdxOfAP = 0; + } + + DBGLOG(REQ, TRACE, ("SET_BSS_INFO auth=%d, enc=%d\n", rCmdSetBssInfo.ucAuthMode, rCmdSetBssInfo.ucEncStatus)); + + + u4Status = wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_BSS_INFO, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(CMD_SET_BSS_INFO), + (PUINT_8)&rCmdSetBssInfo, + NULL, + 0); + + /* if BSS-INFO is going to be disconnected state, free all correlated station records */ + if(prBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { + /* clear client list */ + bssClearClientList(prAdapter, prBssInfo); + + /* free all correlated station records */ + cnmStaFreeAllStaByNetType(prAdapter, eNetworkTypeIdx, FALSE); + qmFreeAllByNetType(prAdapter, eNetworkTypeIdx); + kalClearSecurityFramesByNetType(prAdapter->prGlueInfo, eNetworkTypeIdx); + DBGLOG(INIT, LOUD, ("free all correlated station records\n")); + } + + return u4Status; +} + + +/* BSS-INFO Indication (PM) */ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to indicate PM that +* a BSS has been created. (for AdHoc / P2P-GO) +* +* @param prAdapter Pointer of ADAPTER_T +* eNetworkTypeIdx Index of BSS-INFO +* +* @retval - +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicPmIndicateBssCreated( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx + ) +{ + P_BSS_INFO_T prBssInfo; + CMD_INDICATE_PM_BSS_CREATED rCmdIndicatePmBssCreated; + + ASSERT(prAdapter); + ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetworkTypeIdx]); + + rCmdIndicatePmBssCreated.ucNetTypeIndex = (UINT_8)eNetworkTypeIdx; + rCmdIndicatePmBssCreated.ucDtimPeriod = prBssInfo->ucDTIMPeriod; + rCmdIndicatePmBssCreated.u2BeaconInterval = prBssInfo->u2BeaconInterval; + rCmdIndicatePmBssCreated.u2AtimWindow = prBssInfo->u2ATIMWindow; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_INDICATE_PM_BSS_CREATED, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(CMD_INDICATE_PM_BSS_CREATED), + (PUINT_8)&rCmdIndicatePmBssCreated, + NULL, + 0); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to indicate PM that +* a BSS has been connected +* +* @param prAdapter Pointer of ADAPTER_T +* eNetworkTypeIdx Index of BSS-INFO +* +* @retval - +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicPmIndicateBssConnected( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx + ) +{ + P_BSS_INFO_T prBssInfo; + CMD_INDICATE_PM_BSS_CONNECTED rCmdIndicatePmBssConnected; + + ASSERT(prAdapter); + ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetworkTypeIdx]); + + rCmdIndicatePmBssConnected.ucNetTypeIndex = (UINT_8)eNetworkTypeIdx; + rCmdIndicatePmBssConnected.ucDtimPeriod = prBssInfo->ucDTIMPeriod; + rCmdIndicatePmBssConnected.u2AssocId = prBssInfo->u2AssocId; + rCmdIndicatePmBssConnected.u2BeaconInterval = prBssInfo->u2BeaconInterval; + rCmdIndicatePmBssConnected.u2AtimWindow = prBssInfo->u2ATIMWindow; + + rCmdIndicatePmBssConnected.ucBmpDeliveryAC = prBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC; + rCmdIndicatePmBssConnected.ucBmpTriggerAC = prBssInfo->rPmProfSetupInfo.ucBmpTriggerAC; + + //DBGPRINTF("nicPmIndicateBssConnected: ucBmpDeliveryAC:0x%x, ucBmpTriggerAC:0x%x", + //rCmdIndicatePmBssConnected.ucBmpDeliveryAC, + //rCmdIndicatePmBssConnected.ucBmpTriggerAC); + + if ((eNetworkTypeIdx == NETWORK_TYPE_AIS_INDEX) +#if CFG_ENABLE_WIFI_DIRECT + || ((eNetworkTypeIdx == NETWORK_TYPE_P2P_INDEX) && (prAdapter->fgIsP2PRegistered)) +#endif + ) { + if(prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { + rCmdIndicatePmBssConnected.fgIsUapsdConnection = (UINT_8)prBssInfo->prStaRecOfAP->fgIsUapsdSupported; + } + else { + rCmdIndicatePmBssConnected.fgIsUapsdConnection = 0; //@FIXME + } + } + else { + rCmdIndicatePmBssConnected.fgIsUapsdConnection = 0; + } + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_INDICATE_PM_BSS_CONNECTED, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(CMD_INDICATE_PM_BSS_CONNECTED), + (PUINT_8)&rCmdIndicatePmBssConnected, + NULL, + 0); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to indicate PM that +* a BSS has been disconnected +* +* @param prAdapter Pointer of ADAPTER_T +* eNetworkTypeIdx Index of BSS-INFO +* +* @retval - +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicPmIndicateBssAbort( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx + ) +{ + CMD_INDICATE_PM_BSS_ABORT rCmdIndicatePmBssAbort; + + ASSERT(prAdapter); + ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); + + rCmdIndicatePmBssAbort.ucNetTypeIndex = (UINT_8)eNetworkTypeIdx; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_INDICATE_PM_BSS_ABORT, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(CMD_INDICATE_PM_BSS_ABORT), + (PUINT_8)&rCmdIndicatePmBssAbort, + NULL, + 0); +} + +WLAN_STATUS +nicConfigPowerSaveProfile ( + IN P_ADAPTER_T prAdapter, + ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + PARAM_POWER_MODE ePwrMode, + BOOLEAN fgEnCmdEvent + ) +{ + DEBUGFUNC("nicConfigPowerSaveProfile"); + DBGLOG(INIT, TRACE, ("eNetTypeIndex:%d, ePwrMode:%d, fgEnCmdEvent:%d\n", + eNetTypeIndex, ePwrMode, fgEnCmdEvent)); + + ASSERT(prAdapter); + + if (eNetTypeIndex >= NETWORK_TYPE_INDEX_NUM) { + ASSERT(0); + return WLAN_STATUS_NOT_SUPPORTED; + } + +// prAdapter->rWlanInfo.ePowerSaveMode.ucNetTypeIndex = eNetTypeIndex; +// prAdapter->rWlanInfo.ePowerSaveMode.ucPsProfile = (UINT_8)ePwrMode; + prAdapter->rWlanInfo.arPowerSaveMode[eNetTypeIndex].ucNetTypeIndex = eNetTypeIndex; + prAdapter->rWlanInfo.arPowerSaveMode[eNetTypeIndex].ucPsProfile = (UINT_8)ePwrMode; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_POWER_SAVE_MODE, + TRUE, + FALSE, + TRUE, + (fgEnCmdEvent ? nicCmdEventSetCommon : NULL), + (fgEnCmdEvent ? nicOidCmdTimeoutCommon : NULL), + sizeof(CMD_PS_PROFILE_T), + (PUINT_8)&(prAdapter->rWlanInfo.arPowerSaveMode[eNetTypeIndex]), + NULL, + sizeof(PARAM_POWER_MODE) + ); + +} /* end of wlanoidSetAcpiDevicePowerStateMode() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to indicate firmware domain +* for beacon generation parameters +* +* @param prAdapter Pointer of ADAPTER_T +* eIeUpdMethod, Update Method +* eNetTypeIndex Index of Network +* u2Capability Capability +* aucIe Pointer to buffer of IEs +* u2IELen Length of IEs +* +* @retval - WLAN_STATUS_SUCCESS +* WLAN_STATUS_FAILURE +* WLAN_STATUS_PENDING +* WLAN_STATUS_INVALID_DATA +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicUpdateBeaconIETemplate ( + IN P_ADAPTER_T prAdapter, + IN ENUM_IE_UPD_METHOD_T eIeUpdMethod, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN UINT_16 u2Capability, + IN PUINT_8 aucIe, + IN UINT_16 u2IELen + ) +{ + P_CMD_BEACON_TEMPLATE_UPDATE prCmdBcnUpdate; + UINT_16 u2CmdBufLen = 0; + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + UINT_8 ucCmdSeqNum; + + DEBUGFUNC("wlanUpdateBeaconIETemplate"); + DBGLOG(INIT, LOUD, ("\n")); + + ASSERT(prAdapter); + prGlueInfo = prAdapter->prGlueInfo; + + if (u2IELen > MAX_IE_LENGTH) { + return WLAN_STATUS_INVALID_DATA; + } + + if (eIeUpdMethod == IE_UPD_METHOD_UPDATE_RANDOM + || eIeUpdMethod == IE_UPD_METHOD_UPDATE_ALL) { + u2CmdBufLen = OFFSET_OF(CMD_BEACON_TEMPLATE_UPDATE, aucIE) + u2IELen; + } + else if (eIeUpdMethod == IE_UPD_METHOD_DELETE_ALL) { + u2CmdBufLen = OFFSET_OF(CMD_BEACON_TEMPLATE_UPDATE, u2IELen); + } + else { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + + // prepare command info + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + u2CmdBufLen)); + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, ("Allocate CMD_INFO_T ==> FAILED.\n")); + return WLAN_STATUS_FAILURE; + } + + // increase command sequence number + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + DBGLOG(REQ, TRACE, ("ucCmdSeqNum =%d\n", ucCmdSeqNum)); + + // Setup common CMD Info Packet + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->eNetworkType = eNetTypeIndex; + prCmdInfo->u2InfoBufLen = (UINT_16)(CMD_HDR_SIZE + u2CmdBufLen); + prCmdInfo->pfCmdDoneHandler = NULL; //@FIXME + prCmdInfo->pfCmdTimeoutHandler = NULL; //@FIXME + prCmdInfo->fgIsOid = FALSE; + prCmdInfo->ucCID = CMD_ID_UPDATE_BEACON_CONTENT; + prCmdInfo->fgSetQuery = TRUE; + prCmdInfo->fgNeedResp = FALSE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = u2CmdBufLen; + prCmdInfo->pvInformationBuffer = NULL; + prCmdInfo->u4InformationBufferLength = 0; + + // Setup WIFI_CMD_T (no payload) + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + prCmdBcnUpdate = (P_CMD_BEACON_TEMPLATE_UPDATE)(prWifiCmd->aucBuffer); + + // fill beacon updating command + prCmdBcnUpdate->ucUpdateMethod = (UINT_8) eIeUpdMethod; + prCmdBcnUpdate->ucNetTypeIndex = (UINT_8) eNetTypeIndex; + prCmdBcnUpdate->u2Capability = u2Capability; + prCmdBcnUpdate->u2IELen = u2IELen; + if(u2IELen > 0 ) { + kalMemCopy(prCmdBcnUpdate->aucIE, aucIe, u2IELen); + } + + // insert into prCmdQueue + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + + // wakeup txServiceThread later + GLUE_SET_EVENT(prGlueInfo); + DBGLOG(INIT, LOUD, ("Command ID = 0x%08X\n", prCmdInfo->ucCID)); + return WLAN_STATUS_PENDING; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to initialization PHY related +* varaibles +* +* @param prAdapter Pointer of ADAPTER_T +* +* @retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicSetAvailablePhyTypeSet ( + IN P_ADAPTER_T prAdapter + ) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + + ASSERT(prAdapter); + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + if (prConnSettings->eDesiredPhyConfig >= PHY_CONFIG_NUM) { + ASSERT(0); + return; + } + + prAdapter->rWifiVar.ucAvailablePhyTypeSet = + aucPhyCfg2PhyTypeSet[prConnSettings->eDesiredPhyConfig]; + + if (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_BIT_ERP) { + prAdapter->rWifiVar.eNonHTBasicPhyType2G4 = PHY_TYPE_ERP_INDEX; + } + /* NOTE(Kevin): Because we don't have N only mode, TBD */ + else /* if (ucNonHTPhyTypeSet & PHY_TYPE_HR_DSSS_INDEX) */ { + prAdapter->rWifiVar.eNonHTBasicPhyType2G4 = PHY_TYPE_HR_DSSS_INDEX; + } + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to update WMM Parms +* +* @param prAdapter Pointer of ADAPTER_T +* eNetworkTypeIdx Index of BSS-INFO +* +* @retval - +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicQmUpdateWmmParms( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx + ) +{ + P_BSS_INFO_T prBssInfo; + CMD_UPDATE_WMM_PARMS_T rCmdUpdateWmmParms; + + ASSERT(prAdapter); + ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); + + DBGLOG(QM, EVENT, ("sizeof(AC_QUE_PARMS_T): %d \n", sizeof(AC_QUE_PARMS_T))); + DBGLOG(QM, EVENT, ("sizeof(CMD_UPDATE_WMM_PARMS): %d \n", sizeof(CMD_UPDATE_WMM_PARMS_T))); + DBGLOG(QM, EVENT, ("sizeof(WIFI_CMD_T): %d \n", sizeof(WIFI_CMD_T))); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetworkTypeIdx]); + rCmdUpdateWmmParms.ucNetTypeIndex = (UINT_8)eNetworkTypeIdx; + kalMemCopy(&rCmdUpdateWmmParms.arACQueParms[0], &prBssInfo->arACQueParms[0], + (sizeof(AC_QUE_PARMS_T)*AC_NUM)); + + rCmdUpdateWmmParms.fgIsQBSS = prBssInfo->fgIsQBSS; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_UPDATE_WMM_PARMS, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(CMD_UPDATE_WMM_PARMS_T), + (PUINT_8)&rCmdUpdateWmmParms, + NULL, + 0); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to update TX power gain corresponding to +* each band/modulation combination +* +* @param prAdapter Pointer of ADAPTER_T +* prTxPwrParam Pointer of TX power parameters +* +* @retval WLAN_STATUS_PENDING +* WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicUpdateTxPower( + IN P_ADAPTER_T prAdapter, + IN P_CMD_TX_PWR_T prTxPwrParam + ) +{ + DEBUGFUNC("nicUpdateTxPower"); + + ASSERT(prAdapter); + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_TX_PWR, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(CMD_TX_PWR_T), + (PUINT_8)prTxPwrParam, + NULL, + 0); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to update power offset around 5GHz band +* +* @param prAdapter Pointer of ADAPTER_T +* pr5GPwrOffset Pointer of 5GHz power offset parameter +* +* @retval WLAN_STATUS_PENDING +* WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicUpdate5GOffset( + IN P_ADAPTER_T prAdapter, + IN P_CMD_5G_PWR_OFFSET_T pr5GPwrOffset + ) +{ + DEBUGFUNC("nicUpdate5GOffset"); + + ASSERT(prAdapter); + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_5G_PWR_OFFSET, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(CMD_5G_PWR_OFFSET_T), + (PUINT_8)pr5GPwrOffset, + NULL, + 0); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to update DPD calibration result +* +* @param prAdapter Pointer of ADAPTER_T +* pr5GPwrOffset Pointer of parameter for DPD calibration result +* +* @retval WLAN_STATUS_PENDING +* WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicUpdateDPD( + IN P_ADAPTER_T prAdapter, + IN P_CMD_PWR_PARAM_T prDpdCalResult + ) +{ + DEBUGFUNC("nicUpdateDPD"); + + ASSERT(prAdapter); + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_PWR_PARAM, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(CMD_PWR_PARAM_T), + (PUINT_8)prDpdCalResult, + NULL, + 0); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function starts system service such as timer and +* memory pools +* +* @param prAdapter Pointer of ADAPTER_T +* +* @retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicInitSystemService ( + IN P_ADAPTER_T prAdapter + ) +{ + ASSERT(prAdapter); + + // <1> Initialize MGMT Memory pool and STA_REC + cnmMemInit(prAdapter); + cnmStaRecInit(prAdapter); + cmdBufInitialize(prAdapter); + + // <2> Mailbox Initialization + mboxInitialize(prAdapter); + + // <3> Timer Initialization + cnmTimerInitialize(prAdapter); + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function reset some specific system service, +* such as STA-REC +* +* @param prAdapter Pointer of ADAPTER_T +* +* @retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicResetSystemService ( + IN P_ADAPTER_T prAdapter + ) +{ + ASSERT(prAdapter); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to update WMM Parms +* +* @param prAdapter Pointer of ADAPTER_T +* +* @retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicUninitSystemService ( + IN P_ADAPTER_T prAdapter + ) +{ + ASSERT(prAdapter); + + /* Timer Destruction */ + cnmTimerDestroy(prAdapter); + + /* Mailbox Destruction */ + mboxDestroy(prAdapter); + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to update WMM Parms +* +* @param prAdapter Pointer of ADAPTER_T +* +* @retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicInitMGMT ( + IN P_ADAPTER_T prAdapter, + IN P_REG_INFO_T prRegInfo + ) +{ + ASSERT(prAdapter); + + /* CNM Module - initialization */ + cnmInit(prAdapter); + + /* RLM Module - initialization */ + rlmFsmEventInit(prAdapter); + + /* SCN Module - initialization */ + scnInit(prAdapter); + + /* AIS Module - intiailization */ + aisInitializeConnectionSettings(prAdapter, prRegInfo); + aisFsmInit(prAdapter); + +#if CFG_SUPPORT_ROAMING + /* Roaming Module - intiailization */ + roamingFsmInit(prAdapter); +#endif /* CFG_SUPPORT_ROAMING */ + +#if CFG_SUPPORT_SWCR + swCrDebugInit(prAdapter); +#endif /* CFG_SUPPORT_SWCR */ + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to update WMM Parms +* +* @param prAdapter Pointer of ADAPTER_T +* +* @retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicUninitMGMT ( + IN P_ADAPTER_T prAdapter + ) +{ + ASSERT(prAdapter); + +#if CFG_SUPPORT_SWCR + swCrDebugUninit(prAdapter); +#endif /* CFG_SUPPORT_SWCR */ + +#if CFG_SUPPORT_ROAMING + /* Roaming Module - unintiailization */ + roamingFsmUninit(prAdapter); +#endif /* CFG_SUPPORT_ROAMING */ + + /* AIS Module - unintiailization */ + aisFsmUninit(prAdapter); + + /* SCN Module - unintiailization */ + scnUninit(prAdapter); + + /* RLM Module - uninitialization */ + rlmFsmEventUninit(prAdapter); + + /* CNM Module - uninitialization */ + cnmUninit(prAdapter); + + return; +} + + +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is to inform firmware to enable MCU clock gating +* +* @param prAdapter Pointer of ADAPTER_T +* +* @retval none +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicEnableClockGating ( + IN P_ADAPTER_T prAdapter + ) +{ + UINT_32 i, u4WHISR = 0; + + ASSERT(prAdapter); + + if(prAdapter->fgIsClockGatingEnabled == TRUE) { + return WLAN_STATUS_SUCCESS; + } + else { + nicSetSwIntr(prAdapter, REQ_GATING_ENABLE_H2D_INT); + + i = 0; + while(i < GATING_CONTROL_POLL_LIMIT) { + if(kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE + || fgIsBusAccessFailed == TRUE) { + return WLAN_STATUS_FAILURE; + } + + HAL_READ_INTR_STATUS(prAdapter, sizeof(UINT_32), (PUINT_8)&u4WHISR); + + if(u4WHISR & ACK_GATING_ENABLE_D2H_INT) { + prAdapter->fgIsClockGatingEnabled = TRUE; + return WLAN_STATUS_SUCCESS; + } + } + + ASSERT(0); + return WLAN_STATUS_PENDING; + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is to inform firmware to disable MCU clock gating +* +* @param prAdapter Pointer of ADAPTER_T +* +* @retval none +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicDisableClockGating ( + IN P_ADAPTER_T prAdapter + ) +{ + UINT_32 i, u4WHISR = 0; + + ASSERT(prAdapter); + + if(prAdapter->fgIsClockGatingEnabled == FALSE) { + return WLAN_STATUS_SUCCESS; + } + else { + nicSetSwIntr(prAdapter, REQ_GATING_DISABLE_H2D_INT); + + i = 0; + while(i < GATING_CONTROL_POLL_LIMIT) { + if(kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE + || fgIsBusAccessFailed == TRUE) { + return WLAN_STATUS_FAILURE; + } + + HAL_READ_INTR_STATUS(prAdapter, sizeof(UINT_32), (PUINT_8)&u4WHISR); + + if(u4WHISR & ACK_GATING_DISABLE_D2H_INT) { + prAdapter->fgIsClockGatingEnabled = FALSE; + return WLAN_STATUS_SUCCESS; + } + } + + ASSERT(0); + return WLAN_STATUS_PENDING; + } +} +#endif + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is invoked to buffer scan result +* +* @param prAdapter Pointer to the Adapter structure. +* @param rMacAddr BSSID +* @param prSsid Pointer to SSID +* @param u4Privacy Privacy settings (0: Open / 1: WEP/WPA/WPA2 enabled) +* @param rRssi Received Strength (-10 ~ -200 dBm) +* @param eNetworkType Network Type (a/b/g) +* @param prConfiguration Network Parameter +* @param eOpMode Infra/Ad-Hoc +* @param rSupportedRates Supported basic rates +* @param u2IELength IE Length +* @param pucIEBuf Pointer to Information Elements(IEs) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicAddScanResult ( + IN P_ADAPTER_T prAdapter, + IN PARAM_MAC_ADDRESS rMacAddr, + IN P_PARAM_SSID_T prSsid, + IN UINT_32 u4Privacy, + IN PARAM_RSSI rRssi, + IN ENUM_PARAM_NETWORK_TYPE_T eNetworkType, + IN P_PARAM_802_11_CONFIG_T prConfiguration, + IN ENUM_PARAM_OP_MODE_T eOpMode, + IN PARAM_RATES_EX rSupportedRates, + IN UINT_16 u2IELength, + IN PUINT_8 pucIEBuf + ) +{ + BOOLEAN bReplace; + UINT_32 i; + UINT_32 u4IdxWeakest = 0; + PARAM_RSSI rWeakestRssi; + UINT_32 u4BufferSize; + + ASSERT(prAdapter); + + rWeakestRssi = (PARAM_RSSI)INT_MAX; + u4BufferSize = sizeof(prAdapter->rWlanInfo.aucScanIEBuf) / sizeof(prAdapter->rWlanInfo.aucScanIEBuf[0]); + + bReplace = FALSE; + + // decide to replace or add + for(i = 0 ; i < prAdapter->rWlanInfo.u4ScanResultNum ; i++) { + // find weakest entry && not connected one + if(UNEQUAL_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, prAdapter->rWlanInfo.rCurrBssId.arMacAddress) + && prAdapter->rWlanInfo.arScanResult[i].rRssi < rWeakestRssi) { + u4IdxWeakest = i; + rWeakestRssi = prAdapter->rWlanInfo.arScanResult[i].rRssi; + } + + if(prAdapter->rWlanInfo.arScanResult[i].eOpMode == eOpMode && + EQUAL_MAC_ADDR(&(prAdapter->rWlanInfo.arScanResult[i].arMacAddress), rMacAddr) && + (EQUAL_SSID(prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid, + prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen, + prSsid->aucSsid, + prSsid->u4SsidLen) + || prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen == 0)) { + // replace entry + bReplace = TRUE; + + // free IE buffer then zero + nicFreeScanResultIE(prAdapter, i); + kalMemZero(&(prAdapter->rWlanInfo.arScanResult[i]), OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); + + // then fill buffer + prAdapter->rWlanInfo.arScanResult[i].u4Length = + OFFSET_OF(PARAM_BSSID_EX_T, aucIEs) + u2IELength; + COPY_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, rMacAddr); + COPY_SSID(prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid, + prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen, + prSsid->aucSsid, + prSsid->u4SsidLen); + prAdapter->rWlanInfo.arScanResult[i].u4Privacy = u4Privacy; + prAdapter->rWlanInfo.arScanResult[i].rRssi = rRssi; + prAdapter->rWlanInfo.arScanResult[i].eNetworkTypeInUse = eNetworkType; + kalMemCopy(&(prAdapter->rWlanInfo.arScanResult[i].rConfiguration), + prConfiguration, + sizeof(PARAM_802_11_CONFIG_T)); + prAdapter->rWlanInfo.arScanResult[i].eOpMode = eOpMode; + kalMemCopy((prAdapter->rWlanInfo.arScanResult[i].rSupportedRates), + rSupportedRates, + sizeof(PARAM_RATES_EX)); + prAdapter->rWlanInfo.arScanResult[i].u4IELength = (UINT_32)u2IELength; + + // IE - allocate buffer and update pointer + if(u2IELength > 0) { + if(ALIGN_4(u2IELength) + prAdapter->rWlanInfo.u4ScanIEBufferUsage <= u4BufferSize) { + kalMemCopy(&(prAdapter->rWlanInfo.aucScanIEBuf[prAdapter->rWlanInfo.u4ScanIEBufferUsage]), + pucIEBuf, + u2IELength); + + prAdapter->rWlanInfo.apucScanResultIEs[i] = + &(prAdapter->rWlanInfo.aucScanIEBuf[prAdapter->rWlanInfo.u4ScanIEBufferUsage]); + + prAdapter->rWlanInfo.u4ScanIEBufferUsage += ALIGN_4(u2IELength); + } + else { + // buffer is not enough + prAdapter->rWlanInfo.arScanResult[i].u4Length -= u2IELength; + prAdapter->rWlanInfo.arScanResult[i].u4IELength = 0; + prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; + } + } + else { + prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; + } + + break; + } + } + + if (bReplace == FALSE) { + if (prAdapter->rWlanInfo.u4ScanResultNum < (CFG_MAX_NUM_BSS_LIST - 1)) { + i = prAdapter->rWlanInfo.u4ScanResultNum; + + // zero + kalMemZero(&(prAdapter->rWlanInfo.arScanResult[i]), + OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); + + // then fill buffer + prAdapter->rWlanInfo.arScanResult[i].u4Length = + OFFSET_OF(PARAM_BSSID_EX_T, aucIEs) + u2IELength; + COPY_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, rMacAddr); + COPY_SSID(prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid, + prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen, + prSsid->aucSsid, + prSsid->u4SsidLen); + prAdapter->rWlanInfo.arScanResult[i].u4Privacy = u4Privacy; + prAdapter->rWlanInfo.arScanResult[i].rRssi = rRssi; + prAdapter->rWlanInfo.arScanResult[i].eNetworkTypeInUse = eNetworkType; + kalMemCopy(&(prAdapter->rWlanInfo.arScanResult[i].rConfiguration), + prConfiguration, + sizeof(PARAM_802_11_CONFIG_T)); + prAdapter->rWlanInfo.arScanResult[i].eOpMode = eOpMode; + kalMemCopy((prAdapter->rWlanInfo.arScanResult[i].rSupportedRates), + rSupportedRates, + sizeof(PARAM_RATES_EX)); + prAdapter->rWlanInfo.arScanResult[i].u4IELength = (UINT_32)u2IELength; + + // IE - allocate buffer and update pointer + if(u2IELength > 0) { + if(ALIGN_4(u2IELength) + prAdapter->rWlanInfo.u4ScanIEBufferUsage <= u4BufferSize) { + kalMemCopy(&(prAdapter->rWlanInfo.aucScanIEBuf[prAdapter->rWlanInfo.u4ScanIEBufferUsage]), + pucIEBuf, + u2IELength); + + prAdapter->rWlanInfo.apucScanResultIEs[i] = + &(prAdapter->rWlanInfo.aucScanIEBuf[prAdapter->rWlanInfo.u4ScanIEBufferUsage]); + + prAdapter->rWlanInfo.u4ScanIEBufferUsage += ALIGN_4(u2IELength); + } + else { + // buffer is not enough + prAdapter->rWlanInfo.arScanResult[i].u4Length -= u2IELength; + prAdapter->rWlanInfo.arScanResult[i].u4IELength = 0; + prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; + } + } + else { + prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; + } + + prAdapter->rWlanInfo.u4ScanResultNum++; + } + else if(rWeakestRssi != (PARAM_RSSI)INT_MAX) { + // replace weakest one + i = u4IdxWeakest; + + // free IE buffer then zero + nicFreeScanResultIE(prAdapter, i); + kalMemZero(&(prAdapter->rWlanInfo.arScanResult[i]), + OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); + + // then fill buffer + prAdapter->rWlanInfo.arScanResult[i].u4Length = + OFFSET_OF(PARAM_BSSID_EX_T, aucIEs) + u2IELength; + COPY_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, rMacAddr); + COPY_SSID(prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid, + prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen, + prSsid->aucSsid, + prSsid->u4SsidLen); + prAdapter->rWlanInfo.arScanResult[i].u4Privacy = u4Privacy; + prAdapter->rWlanInfo.arScanResult[i].rRssi = rRssi; + prAdapter->rWlanInfo.arScanResult[i].eNetworkTypeInUse = eNetworkType; + kalMemCopy(&(prAdapter->rWlanInfo.arScanResult[i].rConfiguration), + prConfiguration, + sizeof(PARAM_802_11_CONFIG_T)); + prAdapter->rWlanInfo.arScanResult[i].eOpMode = eOpMode; + kalMemCopy((prAdapter->rWlanInfo.arScanResult[i].rSupportedRates), + rSupportedRates, + sizeof(PARAM_RATES_EX)); + prAdapter->rWlanInfo.arScanResult[i].u4IELength = (UINT_32)u2IELength; + + if(u2IELength > 0) { + // IE - allocate buffer and update pointer + if(ALIGN_4(u2IELength) + prAdapter->rWlanInfo.u4ScanIEBufferUsage <= u4BufferSize) { + kalMemCopy(&(prAdapter->rWlanInfo.aucScanIEBuf[prAdapter->rWlanInfo.u4ScanIEBufferUsage]), + pucIEBuf, + u2IELength); + + prAdapter->rWlanInfo.apucScanResultIEs[i] = + &(prAdapter->rWlanInfo.aucScanIEBuf[prAdapter->rWlanInfo.u4ScanIEBufferUsage]); + + prAdapter->rWlanInfo.u4ScanIEBufferUsage += ALIGN_4(u2IELength); + } + else { + // buffer is not enough + prAdapter->rWlanInfo.arScanResult[i].u4Length -= u2IELength; + prAdapter->rWlanInfo.arScanResult[i].u4IELength = 0; + prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; + } + } + else { + prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; + } + } + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is invoked to free IE buffer for dedicated scan result +* +* @param prAdapter Pointer to the Adapter structure. +* @param u4Idx Index of Scan Result +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicFreeScanResultIE ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Idx + ) +{ + UINT_32 i; + PUINT_8 pucPivot, pucMovePivot; + UINT_32 u4MoveSize, u4FreeSize, u4ReserveSize; + + ASSERT(prAdapter); + ASSERT(u4Idx < CFG_MAX_NUM_BSS_LIST); + + if(prAdapter->rWlanInfo.arScanResult[u4Idx].u4IELength == 0 + || prAdapter->rWlanInfo.apucScanResultIEs[u4Idx] == NULL) { + return; + } + + u4FreeSize = ALIGN_4(prAdapter->rWlanInfo.arScanResult[u4Idx].u4IELength); + + pucPivot = prAdapter->rWlanInfo.apucScanResultIEs[u4Idx]; + pucMovePivot = (PUINT_8)((UINT_32)(prAdapter->rWlanInfo.apucScanResultIEs[u4Idx]) + u4FreeSize); + + u4ReserveSize = ((UINT_32)pucPivot) - (UINT_32)(&(prAdapter->rWlanInfo.aucScanIEBuf[0])); + u4MoveSize = prAdapter->rWlanInfo.u4ScanIEBufferUsage - u4ReserveSize - u4FreeSize; + + // 1. rest of buffer to move forward + kalMemCopy(pucPivot, pucMovePivot, u4MoveSize); + + // 1.1 modify pointers + for(i = 0 ; i < prAdapter->rWlanInfo.u4ScanResultNum ; i++) { + if(i != u4Idx) { + if(prAdapter->rWlanInfo.apucScanResultIEs[i] >= pucMovePivot) { + prAdapter->rWlanInfo.apucScanResultIEs[i] = + (PUINT_8)((UINT_32)(prAdapter->rWlanInfo.apucScanResultIEs[i]) - u4FreeSize); + } + } + } + + // 1.2 reset the freed one + prAdapter->rWlanInfo.arScanResult[u4Idx].u4IELength = 0; + prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; + + // 2. reduce IE buffer usage + prAdapter->rWlanInfo.u4ScanIEBufferUsage -= u4FreeSize; + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is to hack parameters for WLAN TABLE for +* fixed rate settings +* +* @param prAdapter Pointer to the Adapter structure. +* @param eRateSetting +* @param pu2DesiredNonHTRateSet, +* @param pu2BSSBasicRateSet, +* @param pucMcsSet +* @param pucSupMcs32 +* @param pu2HtCapInfo +* +* @return WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicUpdateRateParams ( + IN P_ADAPTER_T prAdapter, + IN ENUM_REGISTRY_FIXED_RATE_T eRateSetting, + IN PUINT_8 pucDesiredPhyTypeSet, + IN PUINT_16 pu2DesiredNonHTRateSet, + IN PUINT_16 pu2BSSBasicRateSet, + IN PUINT_8 pucMcsSet, + IN PUINT_8 pucSupMcs32, + IN PUINT_16 pu2HtCapInfo + ) +{ + ASSERT(prAdapter); + ASSERT(eRateSetting > FIXED_RATE_NONE && eRateSetting < FIXED_RATE_NUM); + + switch(prAdapter->rWifiVar.eRateSetting) { + case FIXED_RATE_1M: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HR_DSSS; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_1M; + *pu2BSSBasicRateSet = RATE_SET_BIT_1M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_2M: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HR_DSSS; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_2M; + *pu2BSSBasicRateSet = RATE_SET_BIT_2M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_5_5M: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HR_DSSS; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_5_5M; + *pu2BSSBasicRateSet = RATE_SET_BIT_5_5M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_11M: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HR_DSSS; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_11M; + *pu2BSSBasicRateSet = RATE_SET_BIT_11M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_6M: + if((*pucDesiredPhyTypeSet) | PHY_TYPE_BIT_ERP) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; + } + else if((*pucDesiredPhyTypeSet) | PHY_TYPE_BIT_OFDM) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; + } + + *pu2DesiredNonHTRateSet = RATE_SET_BIT_6M; + *pu2BSSBasicRateSet = RATE_SET_BIT_6M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_9M: + if((*pucDesiredPhyTypeSet) | PHY_TYPE_BIT_ERP) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; + } + else if((*pucDesiredPhyTypeSet) | PHY_TYPE_BIT_OFDM) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; + } + + *pu2DesiredNonHTRateSet = RATE_SET_BIT_9M; + *pu2BSSBasicRateSet = RATE_SET_BIT_9M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_12M: + if((*pucDesiredPhyTypeSet) | PHY_TYPE_BIT_ERP) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; + } + else if((*pucDesiredPhyTypeSet) | PHY_TYPE_BIT_OFDM) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; + } + + *pu2DesiredNonHTRateSet = RATE_SET_BIT_12M; + *pu2BSSBasicRateSet = RATE_SET_BIT_12M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_18M: + if((*pucDesiredPhyTypeSet) | PHY_TYPE_BIT_ERP) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; + } + else if((*pucDesiredPhyTypeSet) | PHY_TYPE_BIT_OFDM) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; + } + + *pu2DesiredNonHTRateSet = RATE_SET_BIT_18M; + *pu2BSSBasicRateSet = RATE_SET_BIT_18M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_24M: + if((*pucDesiredPhyTypeSet) | PHY_TYPE_BIT_ERP) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; + } + else if((*pucDesiredPhyTypeSet) | PHY_TYPE_BIT_OFDM) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; + } + + *pu2DesiredNonHTRateSet = RATE_SET_BIT_24M; + *pu2BSSBasicRateSet = RATE_SET_BIT_24M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_36M: + if((*pucDesiredPhyTypeSet) | PHY_TYPE_BIT_ERP) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; + } + else if((*pucDesiredPhyTypeSet) | PHY_TYPE_BIT_OFDM) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; + } + + *pu2DesiredNonHTRateSet = RATE_SET_BIT_36M; + *pu2BSSBasicRateSet = RATE_SET_BIT_36M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_48M: + if((*pucDesiredPhyTypeSet) | PHY_TYPE_BIT_ERP) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; + } + else if((*pucDesiredPhyTypeSet) | PHY_TYPE_BIT_OFDM) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; + } + + *pu2DesiredNonHTRateSet = RATE_SET_BIT_48M; + *pu2BSSBasicRateSet = RATE_SET_BIT_48M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_54M: + if((*pucDesiredPhyTypeSet) | PHY_TYPE_BIT_ERP) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; + } + else if((*pucDesiredPhyTypeSet) | PHY_TYPE_BIT_OFDM) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; + } + + *pu2DesiredNonHTRateSet = RATE_SET_BIT_54M; + *pu2BSSBasicRateSet = RATE_SET_BIT_54M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_MCS0_20M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS0_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + break; + + case FIXED_RATE_MCS1_20M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS1_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + break; + + case FIXED_RATE_MCS2_20M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS2_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + break; + + case FIXED_RATE_MCS3_20M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS3_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + break; + + case FIXED_RATE_MCS4_20M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS4_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + break; + + case FIXED_RATE_MCS5_20M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS5_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + break; + + case FIXED_RATE_MCS6_20M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS6_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + break; + + case FIXED_RATE_MCS7_20M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS7_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + break; + + case FIXED_RATE_MCS0_20M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS0_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; + break; + + case FIXED_RATE_MCS1_20M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS1_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; + break; + + case FIXED_RATE_MCS2_20M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS2_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; + break; + + case FIXED_RATE_MCS3_20M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS3_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; + break; + + case FIXED_RATE_MCS4_20M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS4_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; + break; + + case FIXED_RATE_MCS5_20M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS5_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; + break; + + case FIXED_RATE_MCS6_20M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS6_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; + break; + + case FIXED_RATE_MCS7_20M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS7_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; + break; + + case FIXED_RATE_MCS0_40M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS0_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS1_40M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS1_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS2_40M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS2_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS3_40M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS3_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS4_40M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS4_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS5_40M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS5_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS6_40M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS6_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS7_40M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS7_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS32_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS32_INDEX; + *pucSupMcs32 = 1; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_SHORT_GI_40M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS0_40M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS0_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_40M); + break; + + case FIXED_RATE_MCS1_40M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS1_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_40M); + break; + + case FIXED_RATE_MCS2_40M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS2_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_40M); + break; + + case FIXED_RATE_MCS3_40M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS3_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_40M); + break; + + case FIXED_RATE_MCS4_40M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS4_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_40M); + break; + + case FIXED_RATE_MCS5_40M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS5_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_40M); + break; + + case FIXED_RATE_MCS6_40M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS6_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_40M); + break; + + case FIXED_RATE_MCS7_40M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS7_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_40M); + break; + + case FIXED_RATE_MCS32_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS32_INDEX; + *pucSupMcs32 = 1; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M + | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_40M); + break; + + default: + ASSERT(0); + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to write the register +* +* @param u4Address Register address +* u4Value the value to be written +* +* @retval WLAN_STATUS_SUCCESS +* WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ + +WLAN_STATUS +nicWriteMcr ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4Address, + IN UINT_32 u4Value + ) +{ + CMD_ACCESS_REG rCmdAccessReg; + + rCmdAccessReg.u4Address = u4Address; + rCmdAccessReg.u4Data = u4Value; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_ACCESS_REG, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(CMD_ACCESS_REG), + (PUINT_8)&rCmdAccessReg, + NULL, + 0 + ); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to modify the auto rate parameters +* +* @param u4ArSysParam0 see description below +* u4ArSysParam1 +* u4ArSysParam2 +* u4ArSysParam3 +* +* +* @retval WLAN_STATUS_SUCCESS +* WLAN_STATUS_FAILURE +* +* @note +* ArSysParam0[0:3] -> auto rate version (0:disable 1:version1 2:version2) +* ArSysParam0[4:5]-> auto bw version (0:disable 1:version1 2:version2) +* ArSysParam0[6:7]-> auto gi version (0:disable 1:version1 2:version2) +* ArSysParam0[8:15]-> HT rate clear mask +* ArSysParam0[16:31]-> Legacy rate clear mask +* ArSysParam1[0:7]-> Auto Rate check weighting window +* ArSysParam1[8:15]-> Auto Rate v1 Force Rate down +* ArSysParam1[16:23]-> Auto Rate v1 PerH +* ArSysParam1[24:31]-> Auto Rate v1 PerL +* +* Examples +* ArSysParam0 = 1, +* Enable auto rate version 1 +* +* ArSysParam0 = 983041, +* Enable auto rate version 1 +* Remove CCK 1M, 2M, 5.5M, 11M +* +* ArSysParam0 = 786433 +* Enable auto rate version 1 +* Remove CCK 5.5M 11M +*/ +/*----------------------------------------------------------------------------*/ + + +WLAN_STATUS +nicRlmArUpdateParms( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4ArSysParam0, + IN UINT_32 u4ArSysParam1, + IN UINT_32 u4ArSysParam2, + IN UINT_32 u4ArSysParam3 + ) +{ + UINT_8 ucArVer,ucAbwVer,ucAgiVer; + UINT_16 u2HtClrMask; + UINT_16 u2LegacyClrMask; + UINT_8 ucArCheckWindow; + UINT_8 ucArPerL; + UINT_8 ucArPerH; + UINT_8 ucArPerForceRateDownPer; + + ucArVer = (UINT_8)(u4ArSysParam0 & BITS(0,3)); + ucAbwVer = (UINT_8)((u4ArSysParam0 & BITS(4,5)) >>4); + ucAgiVer = (UINT_8)((u4ArSysParam0 & BITS(6,7)) >>6); + u2HtClrMask = (UINT_16) ((u4ArSysParam0 & BITS(8,15)) >> 8); + u2LegacyClrMask = (UINT_16) ((u4ArSysParam0 & BITS(16,31)) >> 16); + +#if 0 + ucArCheckWindow = (UINT_8) (u4ArSysParam1 & BITS(0,7)); + ucArPerForceRateDownPer = (UINT_8) ((u4ArSysParam1 & BITS(8,15)>>8)); + ucArPerH = (UINT_8) ((u4ArSysParam1 & BITS(16,23)) >>16); + ucArPerL = (UINT_8) ((u4ArSysParam1 & BITS(24,31)) >>24); +#endif + + ucArCheckWindow = (UINT_8) (u4ArSysParam1 & BITS(0,7)); + ucArPerForceRateDownPer = (UINT_8) (((u4ArSysParam1>>8) & BITS(0,7))); + ucArPerH = (UINT_8) (((u4ArSysParam1>>16) & BITS(0,7))); + ucArPerL = (UINT_8) (((u4ArSysParam1>>24) & BITS(0,7))); + + + DBGLOG(INIT, INFO, ("ArParam %u %u %u %u\n", u4ArSysParam0, u4ArSysParam1, u4ArSysParam2, u4ArSysParam3)); + DBGLOG(INIT, INFO, ("ArVer %u AbwVer %u AgiVer %u\n", ucArVer, ucAbwVer, ucAgiVer)); + DBGLOG(INIT, INFO, ("HtMask %x LegacyMask %x\n", u2HtClrMask, u2LegacyClrMask)); + DBGLOG(INIT, INFO, ("CheckWin %u RateDownPer %u PerH %u PerL %u\n", ucArCheckWindow, ucArPerForceRateDownPer, ucArPerH, ucArPerL)); + +#define SWCR_DATA_ADDR(MOD,ADDR) (0x90000000+(MOD<<8)+(ADDR)) +#define SWCR_DATA_CMD(CATE,WRITE,INDEX,OPT0,OPT1) ( (CATE<<24) | (WRITE<<23) | (INDEX<<16) | (OPT0 <<8) | OPT1 ) +#define SWCR_DATA0 0x0 +#define SWCR_DATA1 0x4 +#define SWCR_DATA2 0x8 +#define SWCR_DATA3 0xC +#define SWCR_DATA4 0x10 +#define SWCR_WRITE 1 +#define SWCR_READ 0 + + if(ucArVer > 0) { + /* dummy = WiFi.WriteMCR(&h90000104, &h00000001) */ + /* dummy = WiFi.WriteMCR(&h90000100, &h00850000)*/ + + nicWriteMcr (prAdapter, SWCR_DATA_ADDR(1/*MOD*/,SWCR_DATA1),1); + nicWriteMcr (prAdapter, SWCR_DATA_ADDR(1/*MOD*/,SWCR_DATA0),SWCR_DATA_CMD(0,SWCR_WRITE,5,0,0)); + } + else { + nicWriteMcr (prAdapter, SWCR_DATA_ADDR(1/*MOD*/,SWCR_DATA1),0); + nicWriteMcr (prAdapter, SWCR_DATA_ADDR(1/*MOD*/,SWCR_DATA0),SWCR_DATA_CMD(0,SWCR_WRITE,5,0,0)) ; + } + + /* ucArVer 0: none 1:PER 2:Rcpi */ + nicWriteMcr (prAdapter, SWCR_DATA_ADDR(1/*MOD*/,SWCR_DATA1),ucArVer); + nicWriteMcr (prAdapter, SWCR_DATA_ADDR(1/*MOD*/,SWCR_DATA0),SWCR_DATA_CMD(0,SWCR_WRITE,7,0,0)); + + /* Candidate rate Ht mask */ + nicWriteMcr (prAdapter, SWCR_DATA_ADDR(1/*MOD*/,SWCR_DATA1),u2HtClrMask); + nicWriteMcr (prAdapter, SWCR_DATA_ADDR(1/*MOD*/,SWCR_DATA0),SWCR_DATA_CMD(0,SWCR_WRITE,0x1c,0,0)); + + /* Candidate rate legacy mask */ + nicWriteMcr (prAdapter, SWCR_DATA_ADDR(1/*MOD*/,SWCR_DATA1),u2LegacyClrMask); + nicWriteMcr (prAdapter, SWCR_DATA_ADDR(1/*MOD*/,SWCR_DATA0),SWCR_DATA_CMD(0,SWCR_WRITE,0x1d,0,0)); + +#if 0 + if(ucArCheckWindow!=0) { + /* TX DONE MCS INDEX CHECK STA RATE DOWN TH */ + nicWriteMcr (prAdapter, SWCR_DATA_ADDR(1/*MOD*/,SWCR_DATA1),ucArCheckWindow); + nicWriteMcr (prAdapter, SWCR_DATA_ADDR(1/*MOD*/,SWCR_DATA0),SWCR_DATA_CMD(0,SWCR_WRITE,0x14,0,0)); + nicWriteMcr (prAdapter, SWCR_DATA_ADDR(1/*MOD*/,SWCR_DATA1),ucArCheckWindow); + nicWriteMcr (prAdapter, SWCR_DATA_ADDR(1/*MOD*/,SWCR_DATA0),SWCR_DATA_CMD(0,SWCR_WRITE,0xc,0,0)); + } + + if(ucArPerForceRateDownPer !=0) { + nicWriteMcr (prAdapter, SWCR_DATA_ADDR(1/*MOD*/,SWCR_DATA1),ucArPerForceRateDownPer); + nicWriteMcr (prAdapter, SWCR_DATA_ADDR(1/*MOD*/,SWCR_DATA0),SWCR_DATA_CMD(0,SWCR_WRITE,0x18,0,0)); + } + if(ucArPerH !=0) { + nicWriteMcr (prAdapter, SWCR_DATA_ADDR(1/*MOD*/,SWCR_DATA1),ucArPerH); + nicWriteMcr (prAdapter, SWCR_DATA_ADDR(1/*MOD*/,SWCR_DATA0),SWCR_DATA_CMD(0,SWCR_WRITE,0x1,0,0)); + } + if(ucArPerL !=0) { + nicWriteMcr (prAdapter, SWCR_DATA_ADDR(1/*MOD*/,SWCR_DATA1),ucArPerL); + nicWriteMcr (prAdapter, SWCR_DATA_ADDR(1/*MOD*/,SWCR_DATA0),SWCR_DATA_CMD(0,SWCR_WRITE,0x2,0,0)); + } +#endif + + + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to enable roaming +* +* @param u4EnableRoaming +* +* +* @retval WLAN_STATUS_SUCCESS +* WLAN_STATUS_FAILURE +* +* @note +* u4EnableRoaming -> Enable Romaing +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicRoamingUpdateParams( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4EnableRoaming + ) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prConnSettings->fgIsEnableRoaming = ((u4EnableRoaming>0)?(TRUE):(FALSE)); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief dump firmware Assert message +* +* \param[in] +* prAdapter +* +* \return +* TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicPrintFirmwareAssertInfo( + IN P_ADAPTER_T prAdapter + ) +{ + UINT_32 u4MailBox0, u4MailBox1; + UINT_32 line = 0; + UINT_8 aucAssertFile[7]; + UINT_32 u4ChipId; + +#if CFG_SDIO_INTR_ENHANCE + u4MailBox0 = prAdapter->prSDIOCtrl->u4RcvMailbox0; + u4MailBox1 = prAdapter->prSDIOCtrl->u4RcvMailbox1; +#else + nicGetMailbox(prAdapter, 0, &u4MailBox0); + nicGetMailbox(prAdapter, 1, &u4MailBox1); +#endif + + line = u4MailBox0 & 0x0000FFFF; + + u4MailBox0 = ((u4MailBox0 >> 16) & 0x0000FFFF); + + kalMemCopy(&aucAssertFile[0], &u4MailBox0, 2); + kalMemCopy(&aucAssertFile[2], &u4MailBox1, 4); + + aucAssertFile[6] = '\0'; + +#if defined(MT6620) + u4ChipId = 6620; +#elif defined(MT5931) + u4ChipId = 5931; +#elif defined(MT6628) + u4ChipId = 6628; +#endif + + kalPrint("\n[MT%ld][wifi][Firmware] Assert at \"%s\" #%ld\n\n", + u4ChipId, + aucAssertFile, + line); + +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to update Link Quality information +* +* @param prAdapter Pointer of Adapter Data Structure +* eNetTypeIdx +* prEventLinkQuality +* cRssi +* cLinkQuality +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicUpdateLinkQuality( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx, + IN P_EVENT_LINK_QUALITY prEventLinkQuality + ) +{ + ASSERT(prAdapter); + ASSERT(eNetTypeIdx < NETWORK_TYPE_INDEX_NUM); + ASSERT(prEventLinkQuality); + + switch(eNetTypeIdx) { + case NETWORK_TYPE_AIS_INDEX: + /* check is to prevent RSSI to be updated by incorrect initial RSSI from hardware */ + /* buffer statistics for further query */ + if(prAdapter->fgIsLinkQualityValid == FALSE + || (kalGetTimeTick() - prAdapter->rLinkQualityUpdateTime) > CFG_LINK_QUALITY_VALID_PERIOD) { + nicUpdateRSSI(prAdapter, eNetTypeIdx, prEventLinkQuality->cRssi, prEventLinkQuality->cLinkQuality); + } + + if(prAdapter->fgIsLinkRateValid == FALSE + || (kalGetTimeTick() - prAdapter->rLinkRateUpdateTime) > CFG_LINK_QUALITY_VALID_PERIOD) { + nicUpdateLinkSpeed(prAdapter, eNetTypeIdx, prEventLinkQuality->u2LinkSpeed); + } + break; +#if CFG_ENABLE_WIFI_DIRECT +#if CFG_SUPPORT_P2P_RSSI_QUERY + case NETWORK_TYPE_P2P_INDEX: + if (prAdapter->fgIsP2pLinkQualityValid == FALSE + || (kalGetTimeTick() - prAdapter->rP2pLinkQualityUpdateTime) > CFG_LINK_QUALITY_VALID_PERIOD) { + P_EVENT_LINK_QUALITY_EX prEventLQEx = (P_EVENT_LINK_QUALITY_EX)prEventLinkQuality; + + nicUpdateRSSI(prAdapter, NETWORK_TYPE_P2P_INDEX, prEventLQEx->cRssiP2P, prEventLQEx->cLinkQualityP2P); + } + break; +#endif +#endif + default: + break; + + } + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to update RSSI and Link Quality information +* +* @param prAdapter Pointer of Adapter Data Structure +* eNetTypeIdx +* cRssi +* cLinkQuality +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicUpdateRSSI( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx, + IN INT_8 cRssi, + IN INT_8 cLinkQuality + ) +{ + ASSERT(prAdapter); + ASSERT(eNetTypeIdx < NETWORK_TYPE_INDEX_NUM); + + switch(eNetTypeIdx) { + case NETWORK_TYPE_AIS_INDEX: + prAdapter->fgIsLinkQualityValid = TRUE; + prAdapter->rLinkQualityUpdateTime = kalGetTimeTick(); + + prAdapter->rLinkQuality.cRssi = cRssi; + prAdapter->rLinkQuality.cLinkQuality = cLinkQuality; + + /* indicate to glue layer */ + kalUpdateRSSI(prAdapter->prGlueInfo, + KAL_NETWORK_TYPE_AIS_INDEX, + prAdapter->rLinkQuality.cRssi, + prAdapter->rLinkQuality.cLinkQuality); + + break; +#if CFG_ENABLE_WIFI_DIRECT +#if CFG_SUPPORT_P2P_RSSI_QUERY + case NETWORK_TYPE_P2P_INDEX: + prAdapter->fgIsP2pLinkQualityValid = TRUE; + prAdapter->rP2pLinkQualityUpdateTime = kalGetTimeTick(); + + prAdapter->rP2pLinkQuality.cRssi= cRssi; + prAdapter->rP2pLinkQuality.cLinkQuality= cLinkQuality; + + kalUpdateRSSI(prAdapter->prGlueInfo, + KAL_NETWORK_TYPE_P2P_INDEX, + cRssi, + cLinkQuality); + break; +#endif +#endif + default: + break; + + } + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to update Link Quality information +* +* @param prAdapter Pointer of Adapter Data Structure +* eNetTypeIdx +* prEventLinkQuality +* cRssi +* cLinkQuality +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicUpdateLinkSpeed( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx, + IN UINT_16 u2LinkSpeed + ) +{ + ASSERT(prAdapter); + ASSERT(eNetTypeIdx < NETWORK_TYPE_INDEX_NUM); + + switch(eNetTypeIdx) { + case NETWORK_TYPE_AIS_INDEX: + /* buffer statistics for further query */ + prAdapter->fgIsLinkRateValid = TRUE; + prAdapter->rLinkRateUpdateTime = kalGetTimeTick(); + + prAdapter->rLinkQuality.u2LinkSpeed = u2LinkSpeed; + + break; + + default: + break; + + } + + return; +} + +#if CFG_SUPPORT_RDD_TEST_MODE +WLAN_STATUS +nicUpdateRddTestMode( + IN P_ADAPTER_T prAdapter, + IN P_CMD_RDD_CH_T prRddChParam + ) +{ + DEBUGFUNC("nicUpdateRddTestMode.\n"); + + ASSERT(prAdapter); + +// aisFsmScanRequest(prAdapter, NULL); + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_RDD_CH, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(CMD_RDD_CH_T), + (PUINT_8)prRddChParam, + NULL, + 0); +} +#endif + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/nic/nic_cmd_event.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/nic/nic_cmd_event.c new file mode 100755 index 000000000000..ffeeac036736 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/nic/nic_cmd_event.c @@ -0,0 +1,1588 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/nic/nic_cmd_event.c#1 $ +*/ + +/*! \file nic_cmd_event.c + \brief Callback functions for Command packets. + + Various Event packet handlers which will be setup in the callback function of + a command packet. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: nic_cmd_event.c $ + * + * 01 27 2012 yuche.tsai + * [ALPS00118350] [ALPS.ICS][WiFi Direct] Dirver update for wifi direct connection + * Fix compile warning & update latest driver 2.2. + * Davinci Label: 20120127_ALPS_WIFI_P2P_DRIVER_V2_1 + * + * 06 15 2011 cm.chang + * [WCXRP00000785] [MT6620 Wi-Fi][Driver][FW] P2P/BOW MAC address is XOR with AIS MAC address + * P2P/BOW mac address XOR with local bit instead of OR + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 05 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * add the code to get the check rsponse and indicate to app. + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * Add security check code. + * + * 02 24 2011 cp.wu + * [WCXRP00000493] [MT6620 Wi-Fi][Driver] Do not indicate redundant disconnection to host when entering into RF test mode + * only indicate DISCONNECTION to host when entering RF test if necessary (connected -> disconnected cases) + * + * 01 20 2011 eddie.chen + * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control + * Add Oid for sw control debug command + * + * 12 31 2010 cp.wu + * [WCXRP00000335] [MT6620 Wi-Fi][Driver] change to use milliseconds sleep instead of delay to avoid blocking to system scheduling + * change to use msleep() and shorten waiting interval to reduce blocking to other task while Wi-Fi driver is being loaded + * + * 12 01 2010 cp.wu + * [WCXRP00000223] MT6620 Wi-Fi][Driver][FW] Adopt NVRAM parameters when enter/exit RF test mode + * reload NVRAM settings before entering RF test mode and leaving from RF test mode. + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 10 20 2010 cp.wu + * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore + * use OID_CUSTOM_TEST_MODE as indication for driver reset + * by dropping pending TX packets + * + * 10 18 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android + * complete implementation of Android NVRAM access + * + * 09 21 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS associated + * Do a complete reset with STA-REC null checking for RF test re-entry + * + * 09 15 2010 yuche.tsai + * NULL + * Start to test AT GO only when P2P state is not IDLE. + * + * 09 09 2010 yuche.tsai + * NULL + * Add AT GO Test mode after MAC address available. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 16 2010 cp.wu + * NULL + * Replace CFG_SUPPORT_BOW by CFG_ENABLE_BT_OVER_WIFI. + * There is no CFG_SUPPORT_BOW in driver domain source. + * + * 08 12 2010 cp.wu + * NULL + * [AIS-FSM] honor registry setting for adhoc running mode. (A/B/G) + * + * 08 11 2010 yuche.tsai + * NULL + * Add support for P2P Device Address query from FW. + * + * 08 03 2010 cp.wu + * NULL + * Centralize mgmt/system service procedures into independent calls. + * + * 08 02 2010 cp.wu + * NULL + * reset FSMs before entering RF test mode. + * + * 07 22 2010 cp.wu + * + * 1) refine AIS-FSM indent. + * 2) when entering RF Test mode, flush 802.1X frames as well + * 3) when entering D3 state, flush 802.1X frames as well + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 05 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) change fake BSS_DESC from channel 6 to channel 1 due to channel switching is not done yet. + * 2) after MAC address is queried from firmware, all related variables in driver domain should be updated as well + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * remove duplicate variable for migration. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 29 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * change upon request: indicate as disconnected in driver domain when leaving from RF test mode + * + * 05 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * do not clear scanning list array after disassociation + * + * 05 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) disable NETWORK_LAYER_ADDRESSES handling temporally. + * 2) finish statistics OIDs + * + * 05 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * change OID behavior to meet WHQL requirement. + * + * 05 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS + * 2) buffer statistics data for 2 seconds + * 3) use default value for adhoc parameters instead of 0 + * + * 05 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) do not take timeout mechanism for power mode oids + * 2) retrieve network type from connection status + * 3) after disassciation, set radio state to off + * 4) TCP option over IPv6 is supported + * + * 05 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct OID_802_11_DISASSOCIATE handling. + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * 1) add timeout handler mechanism for pending command packets + * 2) add p2p add/removal key + * + * 04 16 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * treat BUS access failure as kind of card removal. + * + * 04 14 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * information buffer for query oid/ioctl is now buffered in prCmdInfo + * * * * * * instead of glue-layer variable to improve multiple oid/ioctl capability + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * * * * * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * accessing to firmware load/start address, and access to OID handling information + * are now handled in glue layer + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * rWlanInfo should be placed at adapter rather than glue due to most operations + * * * * are done in adapter layer. + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add KAL API: kalFlushPendingTxPackets(), and take use of the API + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access to prGlueInfo->rWlanInfo.eLinkAttr.ucMediaStreamMode from non-glue layer. + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * improve none-glude code portability + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * sync statistics data structure definition with firmware implementation + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer + * + * 03 30 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * statistics information OIDs are now handled by querying from firmware domain + * + * 03 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * indicate media stream mode after set is done + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port + * + * 03 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement custom OID: EEPROM read/write access + * + * 03 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement OID_802_3_MULTICAST_LIST oid handling + * + * 02 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * limit RSSI return value to microsoft defined range. + * + * 02 09 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address + * * * * * * * 2. follow MSDN defined behavior when associates to another AP + * * * * * * * 3. for firmware download, packet size could be up to 2048 bytes + * + * 01 29 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * block until firmware finished RF test enter/leave then indicate completion to upper layer + * + * 01 29 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * when entering RF test mode and leaving from RF test mode, wait for W_FUNC_RDY bit to be asserted forever until it is set or card is removed. + * + * 01 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. eliminate improper variable in rHifInfo + * * * * * * * * 2. block TX/ordinary OID when RF test mode is engaged + * * * * * * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode + * * * * * * * * 4. correct some HAL implementation + * + * 01 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Under WinXP with SDIO, use prGlueInfo->rHifInfo.pvInformationBuffer instead of prGlueInfo->pvInformationBuffer + * + * 01 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement following 802.11 OIDs: + * * * * * OID_802_11_RSSI, + * * * * * OID_802_11_RSSI_TRIGGER, + * * * * * OID_802_11_STATISTICS, + * * * * * OID_802_11_DISASSOCIATE, + * * * * * OID_802_11_POWER_MODE + * + * 01 21 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement OID_802_11_MEDIA_STREAM_MODE + * + * 12 30 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) According to CMD/EVENT documentation v0.8, + * * * * * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, + * * * * * * * * and result is retrieved by get ATInfo instead + * * * * * * * * 2) add 4 counter for recording aggregation statistics +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-12-10 16:47:47 GMT mtk02752 +** only handle MCR read when accessing FW domain register +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-12-08 17:37:28 GMT mtk02752 +** * refine nicCmdEventQueryMcrRead +** + add TxStatus/RxStatus for RF test QueryInformation OIDs +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-12-02 22:05:45 GMT mtk02752 +** kalOidComplete() will decrease i4OidPendingCount +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-12-01 23:02:57 GMT mtk02752 +** remove unnecessary spin locks +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-12-01 22:51:18 GMT mtk02752 +** maintein i4OidPendingCount +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-11-30 10:55:03 GMT mtk02752 +** modify for compatibility +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-11-23 14:46:32 GMT mtk02752 +** add another version of command-done handler upon new event structure +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-04-29 15:42:33 GMT mtk01461 +** Add comment +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-04-21 19:32:42 GMT mtk01461 +** Add nicCmdEventSetCommon() for general set OID +** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-04-21 01:40:35 GMT mtk01461 +** Command Done Handler +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +VOID +nicCmdEventQueryMcrRead ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + UINT_32 u4QueryInfoLen; + P_PARAM_CUSTOM_MCR_RW_STRUC_T prMcrRdInfo; + P_GLUE_INFO_T prGlueInfo; + P_CMD_ACCESS_REG prCmdAccessReg; + + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + //4 <2> Update information of OID + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + prCmdAccessReg = (P_CMD_ACCESS_REG)(pucEventBuf); + + u4QueryInfoLen = sizeof(PARAM_CUSTOM_MCR_RW_STRUC_T); + + prMcrRdInfo = (P_PARAM_CUSTOM_MCR_RW_STRUC_T) prCmdInfo->pvInformationBuffer; + prMcrRdInfo->u4McrOffset = prCmdAccessReg->u4Address; + prMcrRdInfo->u4McrData = prCmdAccessReg->u4Data; + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } + + return; + +} + + +VOID +nicCmdEventQuerySwCtrlRead ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + UINT_32 u4QueryInfoLen; + P_PARAM_CUSTOM_SW_CTRL_STRUC_T prSwCtrlInfo; + P_GLUE_INFO_T prGlueInfo; + P_CMD_SW_DBG_CTRL_T prCmdSwCtrl; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + //4 <2> Update information of OID + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + prCmdSwCtrl = (P_CMD_SW_DBG_CTRL_T)(pucEventBuf); + + u4QueryInfoLen = sizeof(PARAM_CUSTOM_SW_CTRL_STRUC_T); + + prSwCtrlInfo = (P_PARAM_CUSTOM_SW_CTRL_STRUC_T) prCmdInfo->pvInformationBuffer; + prSwCtrlInfo->u4Id = prCmdSwCtrl->u4Id; + prSwCtrlInfo->u4Data = prCmdSwCtrl->u4Data; + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } + + return; + +} + + + +VOID +nicCmdEventSetCommon ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + if (prCmdInfo->fgIsOid) { + /* Update Set Infomation Length */ + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, + prCmdInfo->u4InformationBufferLength, + WLAN_STATUS_SUCCESS); + } + + return; +} + +VOID +nicCmdEventSetDisassociate ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + if (prCmdInfo->fgIsOid) { + /* Update Set Infomation Length */ + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, + 0, + WLAN_STATUS_SUCCESS); + } + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_DISCONNECT, + NULL, + 0); + +#if !defined(LINUX) + prAdapter->fgIsRadioOff = TRUE; +#endif + + return; +} + +VOID +nicCmdEventSetIpAddress ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + UINT_32 u4Count; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + u4Count = (prCmdInfo->u4SetInfoLen - OFFSET_OF(CMD_SET_NETWORK_ADDRESS_LIST, arNetAddress)) + / sizeof(IPV4_NETWORK_ADDRESS) ; + + if (prCmdInfo->fgIsOid) { + /* Update Set Infomation Length */ + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, + OFFSET_OF(PARAM_NETWORK_ADDRESS_LIST, arAddress) + u4Count * + (OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(PARAM_NETWORK_ADDRESS_IP)), + WLAN_STATUS_SUCCESS); + } + + return; +} + +VOID +nicCmdEventQueryRfTestATInfo( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + P_EVENT_TEST_STATUS prTestStatus, prQueryBuffer; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prTestStatus = (P_EVENT_TEST_STATUS)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + prQueryBuffer = (P_EVENT_TEST_STATUS) prCmdInfo->pvInformationBuffer; + + kalMemCopy(prQueryBuffer, prTestStatus, sizeof(EVENT_TEST_STATUS)); + + u4QueryInfoLen = sizeof(EVENT_TEST_STATUS); + + /* Update Query Infomation Length */ + kalOidComplete(prGlueInfo, + prCmdInfo->fgSetQuery, + u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } + + return; +} + +VOID +nicCmdEventQueryLinkQuality( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + PARAM_RSSI rRssi, *prRssi; + P_EVENT_LINK_QUALITY prLinkQuality; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prLinkQuality = (P_EVENT_LINK_QUALITY)pucEventBuf; + + rRssi = (PARAM_RSSI)prLinkQuality->cRssi; // ranged from (-128 ~ 30) in unit of dBm + + if(rRssi > PARAM_WHQL_RSSI_MAX_DBM) + rRssi = PARAM_WHQL_RSSI_MAX_DBM; + else if(rRssi < PARAM_WHQL_RSSI_MIN_DBM) + rRssi = PARAM_WHQL_RSSI_MIN_DBM; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + prRssi = (PARAM_RSSI *) prCmdInfo->pvInformationBuffer; + + kalMemCopy(prRssi, &rRssi, sizeof(PARAM_RSSI)); + u4QueryInfoLen = sizeof(PARAM_RSSI); + + kalOidComplete(prGlueInfo, + prCmdInfo->fgSetQuery, + u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This routine is in response of OID_GEN_LINK_SPEED query request +* +* @param prAdapter Pointer to the Adapter structure. +* @param prCmdInfo Pointer to the pending command info +* @param pucEventBuf +* +* @retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicCmdEventQueryLinkSpeed( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + P_EVENT_LINK_QUALITY prLinkQuality; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + PUINT_32 pu4LinkSpeed; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prLinkQuality = (P_EVENT_LINK_QUALITY)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + pu4LinkSpeed = (PUINT_32)(prCmdInfo->pvInformationBuffer); + + if(prLinkQuality->u2LinkSpeed == 0) { + *pu4LinkSpeed = 10000; /* 10K * 100bps = 1Mbps */ + } + else { + *pu4LinkSpeed = prLinkQuality->u2LinkSpeed * 5000; + } + + u4QueryInfoLen = sizeof(UINT_32); + + kalOidComplete(prGlueInfo, + prCmdInfo->fgSetQuery, + u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + + +VOID +nicCmdEventQueryStatistics( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + P_PARAM_802_11_STATISTICS_STRUCT_T prStatistics; + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prEventStatistics = (P_EVENT_STATISTICS)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + u4QueryInfoLen = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); + prStatistics = (P_PARAM_802_11_STATISTICS_STRUCT_T) prCmdInfo->pvInformationBuffer; + + prStatistics->u4Length = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); + prStatistics->rTransmittedFragmentCount + = prEventStatistics->rTransmittedFragmentCount; + prStatistics->rMulticastTransmittedFrameCount + = prEventStatistics->rMulticastTransmittedFrameCount; + prStatistics->rFailedCount + = prEventStatistics->rFailedCount; + prStatistics->rRetryCount + = prEventStatistics->rRetryCount; + prStatistics->rMultipleRetryCount + = prEventStatistics->rMultipleRetryCount; + prStatistics->rRTSSuccessCount + = prEventStatistics->rRTSSuccessCount; + prStatistics->rRTSFailureCount + = prEventStatistics->rRTSFailureCount; + prStatistics->rACKFailureCount + = prEventStatistics->rACKFailureCount; + prStatistics->rFrameDuplicateCount + = prEventStatistics->rFrameDuplicateCount; + prStatistics->rReceivedFragmentCount + = prEventStatistics->rReceivedFragmentCount; + prStatistics->rMulticastReceivedFrameCount + = prEventStatistics->rMulticastReceivedFrameCount; + prStatistics->rFCSErrorCount + = prEventStatistics->rFCSErrorCount; + prStatistics->rTKIPLocalMICFailures.QuadPart + = 0; + prStatistics->rTKIPICVErrors.QuadPart + = 0; + prStatistics->rTKIPCounterMeasuresInvoked.QuadPart + = 0; + prStatistics->rTKIPReplays.QuadPart + = 0; + prStatistics->rCCMPFormatErrors.QuadPart + = 0; + prStatistics->rCCMPReplays.QuadPart + = 0; + prStatistics->rCCMPDecryptErrors.QuadPart + = 0; + prStatistics->rFourWayHandshakeFailures.QuadPart + = 0; + prStatistics->rWEPUndecryptableCount.QuadPart + = 0; + prStatistics->rWEPICVErrorCount.QuadPart + = 0; + prStatistics->rDecryptSuccessCount.QuadPart + = 0; + prStatistics->rDecryptFailureCount.QuadPart + = 0; + + kalOidComplete(prGlueInfo, + prCmdInfo->fgSetQuery, + u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + +VOID +nicCmdEventEnterRfTest( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + UINT_32 u4WHISR = 0, u4Value = 0; + UINT_8 aucTxCount[8]; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + // [driver-land] + prAdapter->fgTestMode = TRUE; + + // 0. always indicate disconnection + if(kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_DISCONNECTED) { + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_DISCONNECT, + NULL, + 0); + } + + // 1. Remove pending TX + nicTxRelease(prAdapter); + + // 1.1 clear pending Security / Management Frames + kalClearSecurityFrames(prAdapter->prGlueInfo); + kalClearMgmtFrames(prAdapter->prGlueInfo); + + // 1.2 clear pending TX packet queued in glue layer + kalFlushPendingTxPackets(prAdapter->prGlueInfo); + + // 2. Reset driver-domain FSMs + nicUninitMGMT(prAdapter); + + nicResetSystemService(prAdapter); + nicInitMGMT(prAdapter, NULL); + + // 3. Disable Interrupt + HAL_INTR_DISABLE(prAdapter); + + // 4. Block til firmware completed entering into RF test mode + kalMsleep(500); + while(1) { + HAL_MCR_RD(prAdapter, MCR_WCIR, &u4Value); + + if (u4Value & WCIR_WLAN_READY) { + break; + } + else if(kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE + || fgIsBusAccessFailed == TRUE) { + if (prCmdInfo->fgIsOid) { + /* Update Set Infomation Length */ + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, + prCmdInfo->u4SetInfoLen, + WLAN_STATUS_NOT_SUPPORTED); + + } + return; + } + else + kalMsleep(10); + } + + // 5. Clear Interrupt Status + HAL_READ_INTR_STATUS(prAdapter, 4, (PUINT_8)&u4WHISR); + if(HAL_IS_TX_DONE_INTR(u4WHISR)) { + HAL_READ_TX_RELEASED_COUNT(prAdapter, aucTxCount); + } + + // 6. Reset TX Counter + nicTxResetResource(prAdapter); + + // 7. Re-enable Interrupt + HAL_INTR_ENABLE(prAdapter); + + // 8. completion indication + if (prCmdInfo->fgIsOid) { + /* Update Set Infomation Length */ + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, + prCmdInfo->u4SetInfoLen, + WLAN_STATUS_SUCCESS); + } + +#if CFG_SUPPORT_NVRAM + // 9. load manufacture data + wlanLoadManufactureData(prAdapter, kalGetConfiguration(prAdapter->prGlueInfo)); +#endif + + return; +} + +VOID +nicCmdEventLeaveRfTest( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + UINT_32 u4WHISR = 0, u4Value = 0; + UINT_8 aucTxCount[8]; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + // 1. Disable Interrupt + HAL_INTR_DISABLE(prAdapter); + + // 2. Block til firmware completed leaving from RF test mode + kalMsleep(500); + while(1) { + HAL_MCR_RD(prAdapter, MCR_WCIR, &u4Value); + + if (u4Value & WCIR_WLAN_READY) { + break; + } + else if(kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE + || fgIsBusAccessFailed == TRUE) { + if (prCmdInfo->fgIsOid) { + /* Update Set Infomation Length */ + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, + prCmdInfo->u4SetInfoLen, + WLAN_STATUS_NOT_SUPPORTED); + + } + return; + } + else { + kalMsleep(10); + } + } + + // 3. Clear Interrupt Status + HAL_READ_INTR_STATUS(prAdapter, 4, (PUINT_8)&u4WHISR); + if(HAL_IS_TX_DONE_INTR(u4WHISR)) { + HAL_READ_TX_RELEASED_COUNT(prAdapter, aucTxCount); + } + + // 4. Reset TX Counter + nicTxResetResource(prAdapter); + + // 5. Re-enable Interrupt + HAL_INTR_ENABLE(prAdapter); + + // 6. set driver-land variable + prAdapter->fgTestMode = FALSE; + + // 7. completion indication + if (prCmdInfo->fgIsOid) { + /* Update Set Infomation Length */ + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, + prCmdInfo->u4SetInfoLen, + WLAN_STATUS_SUCCESS); + } + + /* 8. Indicate as disconnected */ + if(kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_DISCONNECTED) { + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_DISCONNECT, + NULL, + 0); + + prAdapter->rWlanInfo.u4SysTime = kalGetTimeTick(); + } + +#if CFG_SUPPORT_NVRAM + /* 9. load manufacture data */ + wlanLoadManufactureData(prAdapter, kalGetConfiguration(prAdapter->prGlueInfo)); +#endif + + /* 10. Override network address */ + wlanUpdateNetworkAddress(prAdapter); + + return; +} + +VOID +nicCmdEventQueryAddress( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + UINT_32 u4QueryInfoLen; + P_GLUE_INFO_T prGlueInfo; + P_EVENT_BASIC_CONFIG prEventBasicConfig; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + prEventBasicConfig = (P_EVENT_BASIC_CONFIG)(pucEventBuf); + + // copy to adapter + kalMemCopy(&(prAdapter->rMyMacAddr), &(prEventBasicConfig->rMyMacAddr), MAC_ADDR_LEN); + + //4 <2> Update information of OID + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + kalMemCopy(prCmdInfo->pvInformationBuffer, &(prEventBasicConfig->rMyMacAddr), MAC_ADDR_LEN); + u4QueryInfoLen = MAC_ADDR_LEN; + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } + + //4 <3> Update new MAC address and all 3 networks + COPY_MAC_ADDR(prAdapter->rWifiVar.aucMacAddress, prAdapter->rMyMacAddr); + COPY_MAC_ADDR(prAdapter->rWifiVar.aucDeviceAddress, prAdapter->rMyMacAddr); + prAdapter->rWifiVar.aucDeviceAddress[0] ^= MAC_ADDR_LOCAL_ADMIN; + + COPY_MAC_ADDR(prAdapter->rWifiVar.aucInterfaceAddress, prAdapter->rMyMacAddr); + prAdapter->rWifiVar.aucInterfaceAddress[0] ^= MAC_ADDR_LOCAL_ADMIN; + + COPY_MAC_ADDR(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].aucOwnMacAddr, + prAdapter->rMyMacAddr); + +#if CFG_ENABLE_WIFI_DIRECT + if(prAdapter->fgIsP2PRegistered) { + COPY_MAC_ADDR(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].aucOwnMacAddr, + prAdapter->rWifiVar.aucDeviceAddress); + } +#endif + +#if CFG_ENABLE_BT_OVER_WIFI + COPY_MAC_ADDR(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX].aucOwnMacAddr, + prAdapter->rWifiVar.aucDeviceAddress); +#endif + +#if CFG_TEST_WIFI_DIRECT_GO + if (prAdapter->rWifiVar.prP2pFsmInfo->eCurrentState == P2P_STATE_IDLE) { + wlanEnableP2pFunction(prAdapter); + + wlanEnableATGO(prAdapter); + } +#endif + + kalUpdateMACAddress(prAdapter->prGlueInfo, prAdapter->rWifiVar.aucMacAddress); + + return; +} + +VOID +nicCmdEventQueryMcastAddr( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + UINT_32 u4QueryInfoLen; + P_GLUE_INFO_T prGlueInfo; + P_EVENT_MAC_MCAST_ADDR prEventMacMcastAddr; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + //4 <2> Update information of OID + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + prEventMacMcastAddr = (P_EVENT_MAC_MCAST_ADDR)(pucEventBuf); + + u4QueryInfoLen = prEventMacMcastAddr->u4NumOfGroupAddr * MAC_ADDR_LEN; + + // buffer length check + if (prCmdInfo->u4InformationBufferLength < u4QueryInfoLen) { + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_BUFFER_TOO_SHORT); + } + else { + kalMemCopy(prCmdInfo->pvInformationBuffer, + prEventMacMcastAddr->arAddress, + prEventMacMcastAddr->u4NumOfGroupAddr * MAC_ADDR_LEN); + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } + } +} + +VOID +nicCmdEventQueryEepromRead( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + UINT_32 u4QueryInfoLen; + P_PARAM_CUSTOM_EEPROM_RW_STRUC_T prEepromRdInfo; + P_GLUE_INFO_T prGlueInfo; + P_EVENT_ACCESS_EEPROM prEventAccessEeprom; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + //4 <2> Update information of OID + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + prEventAccessEeprom = (P_EVENT_ACCESS_EEPROM)(pucEventBuf); + + u4QueryInfoLen = sizeof(PARAM_CUSTOM_EEPROM_RW_STRUC_T); + + prEepromRdInfo = (P_PARAM_CUSTOM_EEPROM_RW_STRUC_T) prCmdInfo->pvInformationBuffer; + prEepromRdInfo->ucEepromIndex = (UINT_8)(prEventAccessEeprom->u2Offset); + prEepromRdInfo->u2EepromData = prEventAccessEeprom->u2Data; + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } + + return; + +} + + +VOID +nicCmdEventSetMediaStreamMode( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + PARAM_MEDIA_STREAMING_INDICATION rParamMediaStreamIndication; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + if (prCmdInfo->fgIsOid) { + /* Update Set Infomation Length */ + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, + prCmdInfo->u4SetInfoLen, + WLAN_STATUS_SUCCESS); + } + + rParamMediaStreamIndication.rStatus.eStatusType = + ENUM_STATUS_TYPE_MEDIA_STREAM_MODE; + rParamMediaStreamIndication.eMediaStreamMode = + prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode == 0 ? + ENUM_MEDIA_STREAM_OFF : ENUM_MEDIA_STREAM_ON; + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, + (PVOID)&rParamMediaStreamIndication, + sizeof(PARAM_MEDIA_STREAMING_INDICATION)); +} + + +/* Statistics responder */ +VOID +nicCmdEventQueryXmitOk( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + PUINT_32 pu4Data; + PUINT_64 pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prEventStatistics = (P_EVENT_STATISTICS)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if(prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { + u4QueryInfoLen = sizeof(UINT_32); + + pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; + *pu4Data = (UINT_32) prEventStatistics->rTransmittedFragmentCount.QuadPart; + } + else { + u4QueryInfoLen = sizeof(UINT_64); + + pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; + *pu8Data = prEventStatistics->rTransmittedFragmentCount.QuadPart; + } + + kalOidComplete(prGlueInfo, + prCmdInfo->fgSetQuery, + u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + + +VOID +nicCmdEventQueryRecvOk( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + PUINT_32 pu4Data; + PUINT_64 pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prEventStatistics = (P_EVENT_STATISTICS)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if(prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { + u4QueryInfoLen = sizeof(UINT_32); + + pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; + *pu4Data = (UINT_32) prEventStatistics->rReceivedFragmentCount.QuadPart; + } + else { + u4QueryInfoLen = sizeof(UINT_64); + + pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; + *pu8Data = prEventStatistics->rReceivedFragmentCount.QuadPart; + } + + kalOidComplete(prGlueInfo, + prCmdInfo->fgSetQuery, + u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + +VOID +nicCmdEventQueryXmitError( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + PUINT_32 pu4Data; + PUINT_64 pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prEventStatistics = (P_EVENT_STATISTICS)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if(prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { + u4QueryInfoLen = sizeof(UINT_32); + + pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; + *pu4Data = (UINT_32) prEventStatistics->rFailedCount.QuadPart; + } + else { + u4QueryInfoLen = sizeof(UINT_64); + + pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; + *pu8Data = (UINT_64) prEventStatistics->rFailedCount.QuadPart; + } + + kalOidComplete(prGlueInfo, + prCmdInfo->fgSetQuery, + u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + + +VOID +nicCmdEventQueryRecvError( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + PUINT_32 pu4Data; + PUINT_64 pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prEventStatistics = (P_EVENT_STATISTICS)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if(prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { + u4QueryInfoLen = sizeof(UINT_32); + + pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; + *pu4Data = (UINT_32) prEventStatistics->rFCSErrorCount.QuadPart; + // @FIXME, RX_ERROR_DROP_COUNT/RX_FIFO_FULL_DROP_COUNT is not calculated + } + else { + u4QueryInfoLen = sizeof(UINT_64); + + pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; + *pu8Data = prEventStatistics->rFCSErrorCount.QuadPart; + // @FIXME, RX_ERROR_DROP_COUNT/RX_FIFO_FULL_DROP_COUNT is not calculated + } + + kalOidComplete(prGlueInfo, + prCmdInfo->fgSetQuery, + u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + + +VOID +nicCmdEventQueryRecvNoBuffer( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + PUINT_32 pu4Data; + PUINT_64 pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prEventStatistics = (P_EVENT_STATISTICS)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if(prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { + u4QueryInfoLen = sizeof(UINT_32); + + pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; + *pu4Data = 0; // @FIXME? + } + else { + u4QueryInfoLen = sizeof(UINT_64); + + pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; + *pu8Data = 0; //@FIXME? + } + + kalOidComplete(prGlueInfo, + prCmdInfo->fgSetQuery, + u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + + +VOID +nicCmdEventQueryRecvCrcError( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + PUINT_32 pu4Data; + PUINT_64 pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prEventStatistics = (P_EVENT_STATISTICS)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if(prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { + u4QueryInfoLen = sizeof(UINT_32); + + pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; + *pu4Data = (UINT_32) prEventStatistics->rFCSErrorCount.QuadPart; + } + else { + u4QueryInfoLen = sizeof(UINT_64); + + pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; + *pu8Data = prEventStatistics->rFCSErrorCount.QuadPart; + } + + kalOidComplete(prGlueInfo, + prCmdInfo->fgSetQuery, + u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + + +VOID +nicCmdEventQueryRecvErrorAlignment( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + PUINT_32 pu4Data; + PUINT_64 pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prEventStatistics = (P_EVENT_STATISTICS)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if(prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { + u4QueryInfoLen = sizeof(UINT_32); + + pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; + *pu4Data = (UINT_32) 0; //@FIXME + } + else { + u4QueryInfoLen = sizeof(UINT_64); + + pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; + *pu8Data = 0; //@FIXME + } + + kalOidComplete(prGlueInfo, + prCmdInfo->fgSetQuery, + u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + + +VOID +nicCmdEventQueryXmitOneCollision( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + PUINT_32 pu4Data; + PUINT_64 pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prEventStatistics = (P_EVENT_STATISTICS)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if(prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { + u4QueryInfoLen = sizeof(UINT_32); + + pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; + *pu4Data = (UINT_32) (prEventStatistics->rMultipleRetryCount.QuadPart - prEventStatistics->rRetryCount.QuadPart); + } + else { + u4QueryInfoLen = sizeof(UINT_64); + + pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; + *pu8Data = (UINT_64) (prEventStatistics->rMultipleRetryCount.QuadPart - prEventStatistics->rRetryCount.QuadPart); + } + + kalOidComplete(prGlueInfo, + prCmdInfo->fgSetQuery, + u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + + +VOID +nicCmdEventQueryXmitMoreCollisions( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + PUINT_32 pu4Data; + PUINT_64 pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prEventStatistics = (P_EVENT_STATISTICS)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if(prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { + u4QueryInfoLen = sizeof(UINT_32); + + pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; + *pu4Data = (UINT_32) prEventStatistics->rMultipleRetryCount.QuadPart; + } + else { + u4QueryInfoLen = sizeof(UINT_64); + + pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; + *pu8Data = (UINT_64) prEventStatistics->rMultipleRetryCount.QuadPart; + } + + kalOidComplete(prGlueInfo, + prCmdInfo->fgSetQuery, + u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + + +VOID +nicCmdEventQueryXmitMaxCollisions( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN PUINT_8 pucEventBuf + ) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + PUINT_32 pu4Data; + PUINT_64 pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prEventStatistics = (P_EVENT_STATISTICS)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if(prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { + u4QueryInfoLen = sizeof(UINT_32); + + pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; + *pu4Data = (UINT_32) prEventStatistics->rFailedCount.QuadPart; + } + else { + u4QueryInfoLen = sizeof(UINT_64); + + pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; + *pu8Data = (UINT_64) prEventStatistics->rFailedCount.QuadPart; + } + + kalOidComplete(prGlueInfo, + prCmdInfo->fgSetQuery, + u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called when command by OID/ioctl has been timeout +* +* @param prAdapter Pointer to the Adapter structure. +* @param prCmdInfo Pointer to the command information +* +* @return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicOidCmdTimeoutCommon ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo + ) +{ + ASSERT(prAdapter); + + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, + 0, + WLAN_STATUS_FAILURE); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is a generic command timeout handler +* +* @param pfnOidHandler Pointer to the OID handler +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicCmdTimeoutCommon ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo + ) +{ + ASSERT(prAdapter); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called when command for entering RF test has +* failed sending due to timeout (highly possibly by firmware crash) +* +* @param prAdapter Pointer to the Adapter structure. +* @param prCmdInfo Pointer to the command information +* +* @return none +* +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicOidCmdEnterRFTestTimeout ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo + ) +{ + ASSERT(prAdapter); + + // 1. Remove pending TX frames + nicTxRelease(prAdapter); + + // 1.1 clear pending Security / Management Frames + kalClearSecurityFrames(prAdapter->prGlueInfo); + kalClearMgmtFrames(prAdapter->prGlueInfo); + + // 1.2 clear pending TX packet queued in glue layer + kalFlushPendingTxPackets(prAdapter->prGlueInfo); + + // 2. indiate for OID failure + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, + 0, + WLAN_STATUS_FAILURE); +} + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/nic/nic_pwr_mgt.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/nic/nic_pwr_mgt.c new file mode 100755 index 000000000000..24f3b60a7d8f --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/nic/nic_pwr_mgt.c @@ -0,0 +1,825 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/nic/nic_pwr_mgt.c#1 $ +*/ + +/*! \file "nic_pwr_mgt.c" + \brief In this file we define the STATE and EVENT for Power Management FSM. + + The SCAN FSM is responsible for performing SCAN behavior when the Arbiter enter + ARB_STATE_SCAN. The STATE and EVENT for SCAN FSM are defined here with detail + description. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: nic_pwr_mgt.c $ + * + * 11 28 2011 cp.wu + * [WCXRP00001125] [MT6620 Wi-Fi][Firmware] Strengthen Wi-Fi power off sequence to have a clearroom environment when returining to ROM code + * 1. Due to firmware now stops HIF DMA for powering off, do not try to receive any packet from firmware + * 2. Take use of prAdapter->fgIsEnterD3ReqIssued for tracking whether it is powering off or not + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 05 11 2011 cp.wu + * [WCXRP00000718] [MT6620 Wi-Fi] modify the behavior of setting tx power + * ACPI APIs migrate to wlan_lib.c for glue layer to invoke. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 15 2011 cp.wu + * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous memory consumption + * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK + * 2. Use common coalescing buffer for both TX/RX directions + * + * + * 03 07 2011 terry.wu + * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message + * Toggle non-standard debug messages to comments. + * + * 12 31 2010 cp.wu + * [WCXRP00000335] [MT6620 Wi-Fi][Driver] change to use milliseconds sleep instead of delay to avoid blocking to system scheduling + * change to use msleep() and shorten waiting interval to reduce blocking to other task while Wi-Fi driver is being loaded + * + * 12 31 2010 cp.wu + * [WCXRP00000327] [MT6620 Wi-Fi][Driver] Improve HEC WHQA 6972 workaround coverage in driver side + * check success or failure for setting fw-own + * + * 12 30 2010 cp.wu + * [WCXRP00000327] [MT6620 Wi-Fi][Driver] Improve HEC WHQA 6972 workaround coverage in driver side + * host driver not to set FW-own when there is still pending interrupts + * + * 10 07 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * add firmware download for MT5931. + * + * 09 21 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS associated + * Do a complete reset with STA-REC null checking for RF test re-entry + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 30 2010 cp.wu + * NULL + * reset ACPI power state before waking up MT6620 Wi-Fi firmware. + * + * 08 12 2010 cp.wu + * NULL + * [AIS-FSM] honor registry setting for adhoc running mode. (A/B/G) + * + * 08 03 2010 cp.wu + * NULL + * Centralize mgmt/system service procedures into independent calls. + * + * 07 22 2010 cp.wu + * + * 1) refine AIS-FSM indent. + * 2) when entering RF Test mode, flush 802.1X frames as well + * 3) when entering D3 state, flush 802.1X frames as well + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * change MAC address updating logic. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) when acquiring LP-own, write for clr-own with lower frequency compared to read poll + * 2) correct address list parsing + * + * 05 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * sleepy notify is only used for sleepy state, + * while wake-up state is automatically set when host needs to access device + * + * 05 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct hibernation problem. + * + * 04 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) surpress compiler warning + * 2) when acqruing LP-own, keep writing WHLPCR whenever OWN is not acquired yet + * + * 04 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * surpress compiler warning + * + * 04 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * when acquiring driver-own, wait for up to 8 seconds. + * + * 04 21 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * add for private ioctl support + * + * 04 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) remove redundant firmware image unloading + * * 2) use compile-time macros to separate logic related to accquiring own + * + * 04 16 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * treat BUS access failure as kind of card removal. + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * accessing to firmware load/start address, and access to OID handling information + * * are now handled in glue layer + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * ePowerCtrl is not necessary as a glue variable. + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add KAL API: kalFlushPendingTxPackets(), and take use of the API + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port + * + * 03 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * always send CMD_NIC_POWER_CTRL packet when nic is being halted + * + * 03 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct typo. + * + * 03 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add ACPI D0/D3 state switching support + * * * * * * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response + * + * 03 08 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add another spin-lock to protect MsduInfoList due to it might be accessed by different thread. + * * 2) change own-back acquiring procedure to wait for up to 16.67 seconds +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-10-13 21:59:15 GMT mtk01084 +** update for new HW design +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-09-09 17:26:36 GMT mtk01084 +** remove CMD52 access +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-05-18 14:50:29 GMT mtk01084 +** modify lines in nicpmSetDriverOwn() +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-23 16:55:37 GMT mtk01084 +** modify nicpmSetDriverOwn() +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-19 18:33:00 GMT mtk01084 +** update for basic power management functions +** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-03-19 15:05:32 GMT mtk01084 +** Initial version +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to process the POWER ON procedure. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicpmSetFWOwn ( + IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgEnableGlobalInt + ) +{ + UINT_32 u4RegValue; + + ASSERT(prAdapter); + + if(prAdapter->fgIsFwOwn == TRUE) { + return; + } + else { + if(nicProcessIST(prAdapter) != WLAN_STATUS_NOT_INDICATING) { + // pending interrupts + return; + } + } + + if (fgEnableGlobalInt) { + prAdapter->fgIsIntEnableWithLPOwnSet = TRUE; + } + else { + HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_SET); + + HAL_MCR_RD(prAdapter, MCR_WHLPCR, &u4RegValue); + if(u4RegValue & WHLPCR_FW_OWN_REQ_SET) { + // if set firmware own not successful (possibly pending interrupts), + // indicate an own clear event + HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_CLR); + + return; + } + + prAdapter->fgIsFwOwn = TRUE; + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to process the POWER OFF procedure. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +nicpmSetDriverOwn ( + IN P_ADAPTER_T prAdapter + ) +{ +#define LP_OWN_BACK_TOTAL_DELAY_MS 8192 //exponential of 2 +#define LP_OWN_BACK_LOOP_DELAY_MS 1 //exponential of 2 +#define LP_OWN_BACK_CLR_OWN_ITERATION 256 //exponential of 2 + + BOOLEAN fgStatus = TRUE; + UINT_32 i, u4CurrTick, u4RegValue = 0; + + ASSERT(prAdapter); + + if(prAdapter->fgIsFwOwn == FALSE) + return fgStatus; + + u4CurrTick = kalGetTimeTick(); + i = 0; + while(1) { + HAL_MCR_RD(prAdapter, MCR_WHLPCR, &u4RegValue); + + if (u4RegValue & WHLPCR_FW_OWN_REQ_SET) { + prAdapter->fgIsFwOwn = FALSE; + break; + } + else if(kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE + || fgIsBusAccessFailed == TRUE + || (kalGetTimeTick() - u4CurrTick) > LP_OWN_BACK_TOTAL_DELAY_MS) { + //ERRORLOG(("LP cannot be own back (for %ld ms)", kalGetTimeTick() - u4CurrTick)); + fgStatus = FALSE; + break; + } + else { + if((i & (LP_OWN_BACK_CLR_OWN_ITERATION - 1)) == 0) { + /* Software get LP ownership - per 256 iterations */ + HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_CLR); + } + + /* Delay for LP engine to complete its operation. */ + kalMsleep(LP_OWN_BACK_LOOP_DELAY_MS); + i++; + } + } + + return fgStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to set ACPI power mode to D0. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +nicpmSetAcpiPowerD0 ( + IN P_ADAPTER_T prAdapter + ) +{ + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + UINT_32 u4Value = 0, u4WHISR = 0; + UINT_8 aucTxCount[8]; + UINT_32 i; +#if CFG_ENABLE_FW_DOWNLOAD + UINT_32 u4FwImgLength, u4FwLoadAddr, u4ImgSecSize; + PVOID prFwMappingHandle; + PVOID pvFwImageMapFile = NULL; + #if CFG_ENABLE_FW_DIVIDED_DOWNLOAD + UINT_32 j; + P_FIRMWARE_DIVIDED_DOWNLOAD_T prFwHead; + BOOLEAN fgValidHead; + const UINT_32 u4CRCOffset = offsetof(FIRMWARE_DIVIDED_DOWNLOAD_T, u4NumOfEntries); + #endif +#endif + + DEBUGFUNC("nicpmSetAcpiPowerD0"); + + ASSERT(prAdapter); + + do { + /* 0. Reset variables in ADAPTER_T */ + prAdapter->fgIsFwOwn = TRUE; + prAdapter->fgWiFiInSleepyState = FALSE; + prAdapter->rAcpiState = ACPI_STATE_D0; + prAdapter->fgIsEnterD3ReqIssued = FALSE; + +#if defined(MT6620) || defined(MT6628) + /* 1. Request Ownership to enter F/W download state */ + ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); + #if !CFG_ENABLE_FULL_PM + nicpmSetDriverOwn(prAdapter); + #endif + + /* 2. Initialize the Adapter */ + if ( (u4Status = nicInitializeAdapter(prAdapter)) != WLAN_STATUS_SUCCESS ) { + DBGLOG(INIT, ERROR, ("nicInitializeAdapter failed!\n")); + u4Status = WLAN_STATUS_FAILURE; + break; + } +#endif + + #if CFG_ENABLE_FW_DOWNLOAD + prFwMappingHandle = kalFirmwareImageMapping(prAdapter->prGlueInfo, &pvFwImageMapFile, &u4FwImgLength); + if(!prFwMappingHandle) { + DBGLOG(INIT, ERROR,("Fail to load FW image from file!\n")); + pvFwImageMapFile = NULL; + } + + #if defined(MT6620) || defined(MT6628) + if (pvFwImageMapFile) { + /* 3.1 disable interrupt, download is done by polling mode only */ + nicDisableInterrupt(prAdapter); + + /* 3.2 Initialize Tx Resource to fw download state */ + nicTxInitResetResource(prAdapter); + + /* 3.3 FW download here */ + u4FwLoadAddr = kalGetFwLoadAddress(prAdapter->prGlueInfo); + + #if CFG_ENABLE_FW_DIVIDED_DOWNLOAD + // 3a. parse file header for decision of divided firmware download or not + prFwHead = (P_FIRMWARE_DIVIDED_DOWNLOAD_T)pvFwImageMapFile; + + if(prFwHead->u4Signature == MTK_WIFI_SIGNATURE && + prFwHead->u4CRC == wlanCRC32((PUINT_8)pvFwImageMapFile + u4CRCOffset, u4FwImgLength - u4CRCOffset)) { + fgValidHead = TRUE; + } + else { + fgValidHead = FALSE; + } + + /* 3b. engage divided firmware downloading */ + if(fgValidHead == TRUE) { + for(i = 0 ; i < prFwHead->u4NumOfEntries ; i++) { + #if CFG_ENABLE_FW_DOWNLOAD_AGGREGATION + if(wlanImageSectionDownloadAggregated(prAdapter, + prFwHead->arSection[i].u4DestAddr, + prFwHead->arSection[i].u4Length, + (PUINT_8)pvFwImageMapFile + prFwHead->arSection[i].u4Offset) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, ("Firmware scatter download failed!\n")); + u4Status = WLAN_STATUS_FAILURE; + } + #else + for(j = 0 ; j < prFwHead->arSection[i].u4Length ; j += CMD_PKT_SIZE_FOR_IMAGE) { + if(j + CMD_PKT_SIZE_FOR_IMAGE < prFwHead->arSection[i].u4Length) + u4ImgSecSize = CMD_PKT_SIZE_FOR_IMAGE; + else + u4ImgSecSize = prFwHead->arSection[i].u4Length - j; + + if(wlanImageSectionDownload(prAdapter, + prFwHead->arSection[i].u4DestAddr + j, + u4ImgSecSize, + (PUINT_8)pvFwImageMapFile + prFwHead->arSection[i].u4Offset + j) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, ("Firmware scatter download failed!\n")); + u4Status = WLAN_STATUS_FAILURE; + break; + } + } + #endif + /* escape from loop if any pending error occurs */ + if(u4Status == WLAN_STATUS_FAILURE) { + break; + } + } + } + else + #endif + #if CFG_ENABLE_FW_DOWNLOAD_AGGREGATION + if(wlanImageSectionDownloadAggregated(prAdapter, + u4FwLoadAddr, + u4FwImgLength, + (PUINT_8)pvFwImageMapFile) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, ("Firmware scatter download failed!\n")); + u4Status = WLAN_STATUS_FAILURE; + } + #else + for (i = 0; i < u4FwImgLength ; i += CMD_PKT_SIZE_FOR_IMAGE) { + if(i + CMD_PKT_SIZE_FOR_IMAGE < u4FwImgLength) + u4ImgSecSize = CMD_PKT_SIZE_FOR_IMAGE; + else + u4ImgSecSize = u4FwImgLength - i; + + if(wlanImageSectionDownload(prAdapter, + u4FwLoadAddr + i, + u4ImgSecSize, + (PUINT_8)pvFwImageMapFile + i) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, ("wlanImageSectionDownload failed!\n")); + u4Status = WLAN_STATUS_FAILURE; + break; + } + } + #endif + + if(u4Status != WLAN_STATUS_SUCCESS) { + kalFirmwareImageUnmapping(prAdapter->prGlueInfo, prFwMappingHandle, pvFwImageMapFile); + break; + } + + #if !CFG_ENABLE_FW_DOWNLOAD_ACK + // Send INIT_CMD_ID_QUERY_PENDING_ERROR command and wait for response + if(wlanImageQueryStatus(prAdapter) != WLAN_STATUS_SUCCESS) { + kalFirmwareImageUnmapping(prAdapter->prGlueInfo, prFwMappingHandle, pvFwImageMapFile); + u4Status = WLAN_STATUS_FAILURE; + break; + } + #endif + + kalFirmwareImageUnmapping(prAdapter->prGlueInfo, prFwMappingHandle, pvFwImageMapFile); + } + else { + u4Status = WLAN_STATUS_FAILURE; + break; + } + + /* 4. send Wi-Fi Start command */ + #if CFG_OVERRIDE_FW_START_ADDRESS + wlanConfigWifiFunc(prAdapter, + TRUE, + kalGetFwStartAddress(prAdapter->prGlueInfo)); + #else + wlanConfigWifiFunc(prAdapter, + FALSE, + 0); + #endif + + #elif defined(MT5931) + if (pvFwImageMapFile) { + DBGLOG(INIT, TRACE, ("Download Address: 0x%08X\n", kalGetFwLoadAddress(prAdapter->prGlueInfo))); + DBGLOG(INIT, TRACE, ("Firmware Length: 0x%08X\n", u4FwImgLength)); + + do { + /* 1.0 whole-chip reset except HIFSYS */ + HAL_MCR_WR(prAdapter, MCR_WMCSR, WMCSR_CHIP_RST); + HAL_MCR_WR(prAdapter, MCR_WMCSR, 0); + + /* 1.1 wait for INIT_RDY */ + i = 0; + while(1) { + HAL_MCR_RD(prAdapter, MCR_WMCSR, &u4Value); + + if (u4Value & WMCSR_INI_RDY) { + DBGLOG(INIT, TRACE, ("INIT-RDY detected\n")); + break; + } + else if(kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE + || fgIsBusAccessFailed == TRUE) { + u4Status = WLAN_STATUS_FAILURE; + break; + } + else if(i >= CFG_RESPONSE_POLLING_TIMEOUT) { + DBGLOG(INIT, ERROR, ("Waiting for Init Ready bit: Timeout\n")); + u4Status = WLAN_STATUS_FAILURE; + break; + } + else { + i++; + kalMsleep(10); + } + } + + /* 1.2 set KSEL/FLEN */ + HAL_MCR_WR(prAdapter, MCR_FWCFG, u4FwImgLength >> 6); + + /* 1.3 enable FWDL_EN */ + HAL_MCR_WR(prAdapter, MCR_WMCSR, WMCSR_FWDLEN); + + /* 1.4 wait for PLL_RDY */ + i = 0; + while(1) { + HAL_MCR_RD(prAdapter, MCR_WMCSR, &u4Value); + + if (u4Value & WMCSR_PLLRDY) { + DBGLOG(INIT, TRACE, ("PLL-RDY detected\n")); + break; + } + else if(kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE + || fgIsBusAccessFailed == TRUE) { + u4Status = WLAN_STATUS_FAILURE; + break; + } + else if(i >= CFG_RESPONSE_POLLING_TIMEOUT) { + DBGLOG(INIT, ERROR, ("Waiting for PLL Ready bit: Timeout\n")); + u4Status = WLAN_STATUS_FAILURE; + break; + } + else { + i++; + kalMsleep(10); + } + } + + /* 2.1 turn on HIFSYS firmware download mode */ + HAL_MCR_WR(prAdapter, MCR_FWDLSR, FWDLSR_FWDL_MODE); + + /* 2.2 set starting address */ + u4FwLoadAddr = kalGetFwLoadAddress(prAdapter->prGlueInfo); + HAL_MCR_WR(prAdapter, MCR_FWDLDSAR, u4FwLoadAddr); + + /* 3. upload firmware */ + for (i = 0; i < u4FwImgLength ; i += CMD_PKT_SIZE_FOR_IMAGE) { + if(i + CMD_PKT_SIZE_FOR_IMAGE < u4FwImgLength) + u4ImgSecSize = CMD_PKT_SIZE_FOR_IMAGE; + else + u4ImgSecSize = u4FwImgLength - i; + + if(wlanImageSectionDownload(prAdapter, + u4FwLoadAddr + i, + u4ImgSecSize, + (PUINT_8)pvFwImageMapFile + i) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, ("Firmware scatter download failed!\n")); + u4Status = WLAN_STATUS_FAILURE; + break; + } + } + + /* 4.1 poll FWDL_OK & FWDL_FAIL bits */ + i = 0; + while(1) { + HAL_MCR_RD(prAdapter, MCR_WMCSR, &u4Value); + + if (u4Value & WMCSR_DL_OK) { + DBGLOG(INIT, TRACE, ("DL_OK detected\n")); + break; + } + else if(kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE + || fgIsBusAccessFailed == TRUE + || (u4Value & WMCSR_DL_FAIL)) { + DBGLOG(INIT, ERROR, ("DL_FAIL detected: 0x%08X\n", u4Value)); + u4Status = WLAN_STATUS_FAILURE; + break; + } + else if(i >= CFG_RESPONSE_POLLING_TIMEOUT) { + DBGLOG(INIT, ERROR, ("Waiting for DL_OK/DL_FAIL bit: Timeout\n")); + u4Status = WLAN_STATUS_FAILURE; + break; + } + else { + i++; + kalMsleep(10); + } + } + + /* 4.2 turn off HIFSYS download mode */ + HAL_MCR_WR(prAdapter, MCR_FWDLSR, 0); + + } while (FALSE); + } + else { + DBGLOG(INIT, ERROR, ("No Firmware found!\n")); + u4Status = WLAN_STATUS_FAILURE; + break; + } + + #endif + #endif + + /* 5. check Wi-Fi FW asserts ready bit */ + DBGLOG(INIT, TRACE, ("wlanAdapterStart(): Waiting for Ready bit..\n")); + i = 0; + while(1) { + HAL_MCR_RD(prAdapter, MCR_WCIR, &u4Value); + + if (u4Value & WCIR_WLAN_READY) { + DBGLOG(INIT, TRACE, ("Ready bit asserted\n")); + break; + } + else if(kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE + || fgIsBusAccessFailed == TRUE) { + u4Status = WLAN_STATUS_FAILURE; + break; + } + else if(i >= CFG_RESPONSE_POLLING_TIMEOUT) { + DBGLOG(INIT, ERROR, ("Waiting for Ready bit: Timeout\n")); + u4Status = WLAN_STATUS_FAILURE; + break; + } + else { + i++; + kalMsleep(10); + } + } + +#if defined(MT5931) + // Acquire LP-OWN + ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); + #if !CFG_ENABLE_FULL_PM + nicpmSetDriverOwn(prAdapter); + #endif + + /* 2. Initialize the Adapter */ + if ( (u4Status = nicInitializeAdapter(prAdapter)) != WLAN_STATUS_SUCCESS ) { + DBGLOG(INIT, ERROR, ("nicInitializeAdapter failed!\n")); + u4Status = WLAN_STATUS_FAILURE; + break; + } +#endif + + if(u4Status == WLAN_STATUS_SUCCESS) { + // 6.1 reset interrupt status + HAL_READ_INTR_STATUS(prAdapter, 4, (PUINT_8)&u4WHISR); + if(HAL_IS_TX_DONE_INTR(u4WHISR)) { + HAL_READ_TX_RELEASED_COUNT(prAdapter, aucTxCount); + } + + /* 6.2 reset TX Resource for normal operation */ + nicTxResetResource(prAdapter); + + /* 6.3 Enable interrupt */ + nicEnableInterrupt(prAdapter); + + /* 6.4 Override network address */ + wlanUpdateNetworkAddress(prAdapter); + + /* 6.5 indicate disconnection as default status */ + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_DISCONNECT, + NULL, + 0); + } + + RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); + + /* MGMT Initialization */ + nicInitMGMT(prAdapter, NULL); + + } while(FALSE); + + if(u4Status != WLAN_STATUS_SUCCESS) { + return FALSE; + } + else { + return TRUE; + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This routine is used to set ACPI power mode to D3. +* +* @param prAdapter pointer to the Adapter handler +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +nicpmSetAcpiPowerD3 ( + IN P_ADAPTER_T prAdapter + ) +{ + UINT_32 i; + + ASSERT(prAdapter); + + /* 1. MGMT - unitialization */ + nicUninitMGMT(prAdapter); + + /* 2. Disable Interrupt */ + nicDisableInterrupt(prAdapter); + + /* 3. emit CMD_NIC_POWER_CTRL command packet */ + wlanSendNicPowerCtrlCmd(prAdapter, 1); + + /* 4. Clear Interrupt Status */ + i = 0; + while(i < CFG_IST_LOOP_COUNT && nicProcessIST(prAdapter) != WLAN_STATUS_NOT_INDICATING) { + i++; + }; + + /* 5. Remove pending TX */ + nicTxRelease(prAdapter); + + // 5.1 clear pending Security / Management Frames + kalClearSecurityFrames(prAdapter->prGlueInfo); + kalClearMgmtFrames(prAdapter->prGlueInfo); + + // 5.2 clear pending TX packet queued in glue layer + kalFlushPendingTxPackets(prAdapter->prGlueInfo); + + /* 6. Set Onwership to F/W */ + nicpmSetFWOwn(prAdapter, FALSE); + + /* 7. Set variables */ + prAdapter->rAcpiState = ACPI_STATE_D3; + + return TRUE; +} + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/nic/nic_rx.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/nic/nic_rx.c new file mode 100755 index 000000000000..10fdceff1673 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/nic/nic_rx.c @@ -0,0 +1,3568 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/nic/nic_rx.c#3 $ +*/ + +/*! \file nic_rx.c + \brief Functions that provide many rx-related functions + + This file includes the functions used to process RFB and dispatch RFBs to + the appropriate related rx functions for protocols. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: nic_rx.c $ + * + * 01 17 2012 yuche.tsai + * NULL + * Update mgmt frame filter setting. + * Please also update FW 2.1 + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Hot Spot Tethering for ICS ALPHA testing version. + * + * 11 19 2011 yuche.tsai + * NULL + * Add P2P RSSI Link Quality Query Support. (Default Off) + * + * 11 17 2011 tsaiyuan.hsu + * [WCXRP00001115] [MT6620 Wi-Fi][DRV] avoid deactivating staRec when changing state 3 to 3. + * avoid deactivating staRec when changing state from 3 to 3. + * + * 11 11 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * modify the xlog related code. + * + * 11 10 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Modify the QM xlog level and remove LOG_FUNC. + * + * 11 09 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Add xlog for beacon timeout and sta aging timeout. + * + * 11 08 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Add xlog function. + * + * 11 04 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters and periodically dump counters for Xlog debugging. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 08 26 2011 cp.wu + * [WCXRP00000958] [MT6620 Wi-Fi][Driver] Extend polling timeout from 25ms to 1sec due to RF calibration might took up to 600ms + * extend polling RX response timeout period from 25ms to 1000ms. + * + * 08 11 2011 cp.wu + * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time + * sparse channel detection: + * driver: collect sparse channel information with scan-done event + * + * 07 28 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings + * Add BWCS cmd and event. + * + * 06 27 2011 tsaiyuan.hsu + * [WCXRP00000816] [MT6620 Wi-Fi][Driver] add control to enable rx data dump or not + * add control to enable rx data dump by packet type. + * + * 06 09 2011 tsaiyuan.hsu + * [WCXRP00000760] [MT5931 Wi-Fi][FW] Refine rxmHandleMacRxDone to reduce code size + * move send_auth at rxmHandleMacRxDone in firmware to driver to reduce code size. + * + * 05 16 2011 eddie.chen + * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet + * Sync from ALPS. + * + * 05 09 2011 eddie.chen + * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet + * Check free number before copying broadcast packet. + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 04 12 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 04 10 2011 yuche.tsai + * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. + * Add device discoverability support. (Phase I) + * + * 04 01 2011 tsaiyuan.hsu + * [WCXRP00000615] [MT 6620 Wi-Fi][Driver] Fix klocwork issues + * fix the klocwork issues, 57500, 57501, 57502 and 57503. + * + * 03 19 2011 yuche.tsai + * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. + * Add beacon timeout support for WiFi Direct Netwrok. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 18 2011 wh.su + * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done + * enable the Anti_piracy check at driver . + * + * 03 17 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage after system running for a long period + * use pre-allocated buffer for storing enhanced interrupt response as well + * + * 03 15 2011 cp.wu + * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous memory consumption + * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK + * 2. Use common coalescing buffer for both TX/RX directions + * + * + * 03 07 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * rename the define to anti_pviracy. + * + * 03 05 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * add the code to get the check rsponse and indicate to app. + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * Add security check code. + * + * 03 02 2011 cp.wu + * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right after connection is built. + * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. + * + * 02 10 2011 yuche.tsai + * [WCXRP00000419] [Volunteer Patch][MT6620/MT5931][Driver] Provide function of disconnect to target station for AAA module. + * Remove Station Record after Aging timeout. + * + * 02 10 2011 cp.wu + * [WCXRP00000434] [MT6620 Wi-Fi][Driver] Obsolete unused event packet handlers + * EVENT_ID_CONNECTION_STATUS has been obsoleted and no need to handle. + * + * 02 09 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Add MLME deauthentication support for Hot-Spot mode. + * + * 02 09 2011 eddie.chen + * [WCXRP00000426] [MT6620 Wi-Fi][FW/Driver] Add STA aging timeout and defualtHwRatein AP mode + * Adjust variable order. + * + * 02 08 2011 eddie.chen + * [WCXRP00000426] [MT6620 Wi-Fi][FW/Driver] Add STA aging timeout and defualtHwRatein AP mode + * Add event STA agint timeout + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 01 26 2011 cm.chang + * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument + * . + * + * 01 24 2011 eddie.chen + * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets + * Remove comments. + * + * 01 24 2011 eddie.chen + * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets + * Add destination decision in AP mode. + * + * 01 24 2011 cm.chang + * [WCXRP00000384] [MT6620 Wi-Fi][Driver][FW] Handle 20/40 action frame in AP mode and stop ampdu timer when sta_rec is freed + * Process received 20/40 coexistence action frame for AP mode + * + * 01 24 2011 cp.wu + * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving + * 1. add an extra counter for tracking pending forward frames. + * 2. notify TX service thread as well when there is pending forward frame + * 3. correct build errors leaded by introduction of Wi-Fi direct separation module + * + * 01 12 2011 cp.wu + * [WCXRP00000357] [MT6620 Wi-Fi][Driver][Bluetooth over Wi-Fi] add another net device interface for BT AMP + * implementation of separate BT_OVER_WIFI data path. + * + * 12 29 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, +Add per station flow control when STA is in PS + + * 1) PS flow control event + * + * 2) WMM IE in beacon, assoc resp, probe resp + * + * 12 15 2010 george.huang + * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function + * update beacon for NoA + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 10 27 2010 george.huang + * [WCXRP00000127] [MT6620 Wi-Fi][Driver] Add a registry to disable Beacon Timeout function for SQA test by using E1 EVB + * Support registry option for disable beacon lost detection. + * + * 10 20 2010 wh.su + * NULL + * add a cmd to reset the p2p key + * + * 10 20 2010 wh.su + * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group + * Add the code to support disconnect p2p group + * + * 09 29 2010 wh.su + * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue + * fixed compilier error. + * + * 09 29 2010 wh.su + * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue + * [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue. + * + * 09 23 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * eliminate reference of CFG_RESPONSE_MAX_PKT_SIZE + * + * 09 21 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS associated + * release RX packet to packet pool when in RF test mode + * + * 09 21 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS associated + * Do a complete reset with STA-REC null checking for RF test re-entry + * + * 09 08 2010 cp.wu + * NULL + * use static memory pool for storing IEs of scanning result. + * + * 09 07 2010 yuche.tsai + * NULL + * Add a common buffer, store the IE of a P2P device in this common buffer. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 31 2010 kevin.huang + * NULL + * Use LINK LIST operation to process SCAN result + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 20 2010 cm.chang + * NULL + * Migrate RLM code to host from FW + * + * 08 20 2010 yuche.tsai + * NULL + * When enable WiFi Direct function, check each packet to tell which interface to indicate. + * + * 08 05 2010 yuche.tsai + * NULL + * Add P2P Device Discovery Function. + * + * 08 03 2010 cp.wu + * NULL + * surpress compilation warning. + * + * 08 03 2010 george.huang + * NULL + * handle event for updating NOA parameters indicated from FW + * + * 08 02 2010 yuche.tsai + * NULL + * Add support API for RX public action frame. + * + * 08 02 2010 jeffrey.chang + * NULL + * 1) modify tx service thread to avoid busy looping + * 2) add spin lock declartion for linux build + * + * 07 30 2010 cp.wu + * NULL + * 1) BoW wrapper: use definitions instead of hard-coded constant for error code + * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead + * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames + * + * 07 26 2010 yuche.tsai + * + * Update Device Capability Bitmap & Group Capability Bitmap from 16 bits to 8 bits. + * + * 07 24 2010 wh.su + * + * .support the Wi-Fi RSN + * + * 07 23 2010 cp.wu + * + * add AIS-FSM handling for beacon timeout event. + * + * 07 21 2010 yuche.tsai + * + * Add P2P Scan & Scan Result Parsing & Saving. + * + * 07 19 2010 cm.chang + * + * Set RLM parameters and enable CNM channel manager + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * Add Ad-Hoc support to AIS-FSM + * + * 07 19 2010 jeffrey.chang + * + * Linux port modification + * + * 07 16 2010 yarco.yang + * + * 1. Support BSS Absence/Presence Event + * 2. Support STA change PS mode Event + * 3. Support BMC forwarding for AP mode. + * + * 07 15 2010 cp.wu + * + * sync. bluetooth-over-Wi-Fi interface to driver interface document v0.2.6. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * fill ucStaRecIdx into SW_RFB_T. + * + * 07 02 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) for event packet, no need to fill RFB. + * 2) when wlanAdapterStart() failed, no need to initialize state machines + * 3) after Beacon/ProbeResp parsing, corresponding BSS_DESC_T should be marked as IE-parsed + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implementation of DRV-SCN and related mailbox message handling. + * + * 06 29 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * replace g_rQM with Adpater->rQM + * + * 06 23 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Merge g_arStaRec[] into adapter->arStaRec[] + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add command warpper for STA-REC/BSS-INFO sync. + * 2) enhance command packet sending procedure for non-oid part + * 3) add command packet definitions for STA-REC/BSS-INFO sync. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * refine TX-DONE callback. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implement TX_DONE callback path. + * + * 06 21 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Add TX Done Event handle entry + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * remove duplicate variable for migration. + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * . + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * . + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * saa_fsm.c is migrated. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add management dispatching function table. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 + * 2) when disconnected, indicate nic directly (no event is needed) + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * cnm_timer has been migrated. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge wlan_def.h. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * sync with MT6620 driver for scan result replacement policy + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS + * 2) buffer statistics data for 2 seconds + * 3) use default value for adhoc parameters instead of 0 + * + * 05 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) do not take timeout mechanism for power mode oids + * 2) retrieve network type from connection status + * 3) after disassciation, set radio state to off + * 4) TCP option over IPv6 is supported + * + * 04 29 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * fixing the PMKID candicate indicate code. + * + * 04 28 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * change prefix for data structure used to communicate with 802.11 PAL + * to avoid ambiguous naming with firmware interface + * + * 04 27 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * basic implementation for EVENT_BT_OVER_WIFI + * + * 04 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * surpress compiler warning + * + * 04 22 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * + * 1) modify rx path code for supporting Wi-Fi direct + * 2) modify config.h since Linux dont need to consider retaining packet + * + * 04 16 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * treat BUS access failure as kind of card removal. + * + * 04 14 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * nicRxProcessEvent packet doesn't access spin-lock directly from now on. + * + * 04 14 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * do not need to release the spin lock due to it is done inside nicGetPendingCmdInfo() + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * * * * * * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose + * + * 04 12 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add channel frequency <-> number conversion + * + * 04 09 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * 1) add spinlock + * 2) add KAPI for handling association info + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * rWlanInfo should be placed at adapter rather than glue due to most operations + * * * * * are done in adapter layer. + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access to prGlueInfo->eParamMediaStateIndicated from non-glue layer + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer + * + * 04 01 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * improve Linux supplicant compliance + * + * 03 31 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * fix ioctl which may cause cmdinfo memory leak + * + * 03 30 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * remove driver-land statistics. + * + * 03 29 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * improve none-glue code portability + * + * 03 28 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * rWlanInfo is modified before data is indicated to OS + * + * 03 28 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * rWlanInfo is modified before data is indicated to OS + * + * 03 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add a temporary flag for integration with CMD/EVENT v0.9. + * + * 03 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) correct OID_802_11_CONFIGURATION with frequency setting behavior. + * * * the frequency is used for adhoc connection only + * * * 2) update with SD1 v0.9 CMD/EVENT documentation + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port + * + * 03 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * . + * + * 03 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * generate information for OID_GEN_RCV_OK & OID_GEN_XMIT_OK + * * * * + * + * 03 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add ACPI D0/D3 state switching support + * * * * * * * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response + * + * 03 15 2010 kevin.huang + * [WPD00003820][MT6620 Wi-Fi] Modify the code for meet the WHQL test + * Add event for activate STA_RECORD_T + * + * 03 12 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct fgSetQuery/fgNeedResp check + * + * 03 11 2010 cp.wu + * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 + * add RX starvation warning debug message controlled by CFG_HIF_RX_STARVATION_WARNING + * + * 03 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code clean: removing unused variables and structure definitions + * + * 03 08 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add another spin-lock to protect MsduInfoList due to it might be accessed by different thread. + * * * 2) change own-back acquiring procedure to wait for up to 16.67 seconds + * + * 03 02 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) the use of prPendingOid revised, all accessing are now protected by spin lock + * * * * 2) ensure wlanReleasePendingOid will clear all command queues + * + * 03 02 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add mutex to avoid multiple access to qmTxQueue simultaneously. + * + * 02 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * move EVENT_ID_ASSOC_INFO from nic_rx.c to gl_kal_ndis_51.c + * * 'cause it involves OS dependent data structure handling + * + * 02 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct behavior to prevent duplicated RX handling for RX0_DONE and RX1_DONE + * + * 02 24 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Updated API interfaces for qmHandleEventRxAddBa() and qmHandleEventRxDelBa() + * + * 02 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement host-side firmware download logic + * + * 02 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c] + * * * * * 2) firmware image length is now retrieved via NdisFileOpen + * * * * * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore + * * * * * 4) nicRxWaitResponse() revised + * * * * * 5) another set of TQ counter default value is added for fw-download state + * * * * * 6) Wi-Fi load address is now retrieved from registry too + * + * 02 09 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address + * * * * * * * * 2. follow MSDN defined behavior when associates to another AP + * * * * * * * * 3. for firmware download, packet size could be up to 2048 bytes + * + * 01 27 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * . + * + * 01 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement following 802.11 OIDs: + * * * * * * OID_802_11_RSSI, + * * * * * * OID_802_11_RSSI_TRIGGER, + * * * * * * OID_802_11_STATISTICS, + * * * * * * OID_802_11_DISASSOCIATE, + * * * * * * OID_802_11_POWER_MODE + * + * 12 30 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) According to CMD/EVENT documentation v0.8, + * * * * * * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, + * * * * * * * * * and result is retrieved by get ATInfo instead + * * * * * * * * * 2) add 4 counter for recording aggregation statistics + * + * 12 23 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add a precheck: if free sw rfb is not enough, do not invoke read transactionu1rwduu`wvpghlqg|fu+rp + * + * 12 22 2009 cp.wu + * [WPD00003809][Bug] Host driver will crash when processing reordered MSDUs + * The root cause is pointer accessing by mistake. After dequeued from reordering-buffer, handling logic should access returned pointer instead of pointer which has been passed in before. +** \main\maintrunk.MT6620WiFiDriver_Prj\58 2009-12-17 13:40:33 GMT mtk02752 +** always update prAdapter->rSDIOCtrl when enhanced response is read by RX +** \main\maintrunk.MT6620WiFiDriver_Prj\57 2009-12-16 18:01:38 GMT mtk02752 +** if interrupt enhanced response is fetched by RX enhanced response, RX needs to invoke interrupt handlers too +** \main\maintrunk.MT6620WiFiDriver_Prj\56 2009-12-16 14:16:52 GMT mtk02752 +** \main\maintrunk.MT6620WiFiDriver_Prj\55 2009-12-15 20:03:12 GMT mtk02752 +** ASSERT when RX FreeSwRfb is not enough +** \main\maintrunk.MT6620WiFiDriver_Prj\54 2009-12-15 17:01:29 GMT mtk02752 +** when CFG_SDIO_RX_ENHANCE is enabled, after enhanced response is read, rx procedure should process 1) TX_DONE_INT 2) D2H INT as well +** \main\maintrunk.MT6620WiFiDriver_Prj\53 2009-12-14 20:45:28 GMT mtk02752 +** when CFG_SDIO_RX_ENHANCE is set, TC counter must be updated each time RX enhance response is read +** +** \main\maintrunk.MT6620WiFiDriver_Prj\52 2009-12-14 11:34:16 GMT mtk02752 +** correct a trivial logic issue +** \main\maintrunk.MT6620WiFiDriver_Prj\51 2009-12-14 10:28:25 GMT mtk02752 +** add a protection to avoid out-of-boundary access +** \main\maintrunk.MT6620WiFiDriver_Prj\50 2009-12-10 16:55:18 GMT mtk02752 +** code clean +** \main\maintrunk.MT6620WiFiDriver_Prj\49 2009-12-09 14:06:47 GMT MTK02468 +** Added parsing event packets with EVENT_ID_RX_ADDBA or EVENT_ID_RX_DELBA +** \main\maintrunk.MT6620WiFiDriver_Prj\48 2009-12-08 17:37:51 GMT mtk02752 +** handle EVENT_ID_TEST_STATUS as well +** \main\maintrunk.MT6620WiFiDriver_Prj\47 2009-12-04 17:59:11 GMT mtk02752 +** to pass free-build compilation check +** \main\maintrunk.MT6620WiFiDriver_Prj\46 2009-12-04 12:09:52 GMT mtk02752 +** correct trivial mistake +** \main\maintrunk.MT6620WiFiDriver_Prj\45 2009-12-04 11:53:37 GMT mtk02752 +** all API should be compilable under SD1_SD3_DATAPATH_INTEGRATION == 0 +** \main\maintrunk.MT6620WiFiDriver_Prj\44 2009-12-03 16:19:48 GMT mtk01461 +** Fix the Connected Event +** \main\maintrunk.MT6620WiFiDriver_Prj\43 2009-11-30 10:56:18 GMT mtk02752 +** 1st DW of WIFI_EVENT_T is shared with HIF_RX_HEADER_T +** \main\maintrunk.MT6620WiFiDriver_Prj\42 2009-11-30 10:11:27 GMT mtk02752 +** implement replacement for bss scan result +** \main\maintrunk.MT6620WiFiDriver_Prj\41 2009-11-27 11:08:05 GMT mtk02752 +** add flush for reset +** \main\maintrunk.MT6620WiFiDriver_Prj\40 2009-11-26 09:38:59 GMT mtk02752 +** \main\maintrunk.MT6620WiFiDriver_Prj\39 2009-11-26 09:29:40 GMT mtk02752 +** enable packet forwarding path (for AP mode) +** \main\maintrunk.MT6620WiFiDriver_Prj\38 2009-11-25 21:37:00 GMT mtk02752 +** sync. with EVENT_SCAN_RESULT_T change, and add an assert for checking event size +** \main\maintrunk.MT6620WiFiDriver_Prj\37 2009-11-25 20:17:41 GMT mtk02752 +** fill HIF_TX_HEADER_T.u2SeqNo +** \main\maintrunk.MT6620WiFiDriver_Prj\36 2009-11-25 18:18:57 GMT mtk02752 +** buffer scan result to prGlueInfo->rWlanInfo.arScanResult directly. +** \main\maintrunk.MT6620WiFiDriver_Prj\35 2009-11-24 22:42:45 GMT mtk02752 +** add nicRxAddScanResult() to prepare to handle SCAN_RESULT event (not implemented yet) +** \main\maintrunk.MT6620WiFiDriver_Prj\34 2009-11-24 20:51:41 GMT mtk02752 +** integrate with SD1's data path API +** \main\maintrunk.MT6620WiFiDriver_Prj\33 2009-11-24 19:56:17 GMT mtk02752 +** adopt P_HIF_RX_HEADER_T in new path +** \main\maintrunk.MT6620WiFiDriver_Prj\32 2009-11-23 20:31:21 GMT mtk02752 +** payload to send into pfCmdDoneHandler() will not include WIFI_EVENT_T +** \main\maintrunk.MT6620WiFiDriver_Prj\31 2009-11-23 17:51:34 GMT mtk02752 +** when event packet corresponding to some pendingOID is received, pendingOID should be cleared +** \main\maintrunk.MT6620WiFiDriver_Prj\30 2009-11-23 14:46:54 GMT mtk02752 +** implement nicRxProcessEventPacket() +** \main\maintrunk.MT6620WiFiDriver_Prj\29 2009-11-17 22:40:54 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\28 2009-11-16 21:48:22 GMT mtk02752 +** add SD1_SD3_DATAPATH_INTEGRATION data path handling +** \main\maintrunk.MT6620WiFiDriver_Prj\27 2009-11-16 15:41:18 GMT mtk01084 +** modify the length to be read in emu mode +** \main\maintrunk.MT6620WiFiDriver_Prj\26 2009-11-13 17:00:12 GMT mtk02752 +** add blank function for event packet +** \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-11-13 13:54:24 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-11-11 14:41:51 GMT mtk02752 +** fix typo +** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-11-11 14:33:46 GMT mtk02752 +** add protection when there is no packet avilable +** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-11 12:33:36 GMT mtk02752 +** add RX1 read path for aggregated/enhanced/normal packet read procedures +** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-11 10:36:18 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-11-04 14:11:08 GMT mtk01084 +** modify lines in RX aggregation +** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-10-30 18:17:23 GMT mtk01084 +** modify RX aggregation handling +** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-10-29 19:56:12 GMT mtk01084 +** modify HAL part +** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-10-23 16:08:34 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-10-13 21:59:20 GMT mtk01084 +** update for new HW design +** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-10-02 13:59:08 GMT mtk01725 +** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-05-21 23:39:05 GMT mtk01461 +** Fix the paste error of RX STATUS in OOB of HIF Loopback CTRL +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-05-20 12:25:32 GMT mtk01461 +** Fix process of Read Done, and add u4MaxEventBufferLen to nicRxWaitResponse() +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-05-18 21:13:18 GMT mtk01426 +** Fixed compiler error +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-05-18 21:05:29 GMT mtk01426 +** Fixed nicRxSDIOAggReceiveRFBs() ASSERT issue +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-04-28 10:38:43 GMT mtk01461 +** Fix RX STATUS is DW align for SDIO_STATUS_ENHANCE mode and refine nicRxSDIOAggeceiveRFBs() for RX Aggregation +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-22 09:12:17 GMT mtk01461 +** Fix nicRxProcessHIFLoopbackPacket(), the size of HIF CTRL LENTH field is 1 byte +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-14 15:51:26 GMT mtk01426 +** Update RX OOB Setting +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-03 14:58:58 GMT mtk01426 +** Fixed logical error +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-01 10:58:31 GMT mtk01461 +** Rename the HIF_PKT_TYPE_DATA +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-23 21:51:18 GMT mtk01461 +** Fix u4HeaderOffset in nicRxProcessHIFLoopbackPacket() +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-18 21:02:58 GMT mtk01426 +** Add CFG_SDIO_RX_ENHANCE and CFG_HIF_LOOPBACK support +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-17 20:20:59 GMT mtk01426 +** Add nicRxWaitResponse function +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:26:01 GMT mtk01426 +** Init for develop +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +#ifndef LINUX +#include +#else +#include +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define RX_RESPONSE_TIMEOUT (1000) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +#if CFG_MGMT_FRAME_HANDLING +static PROCESS_RX_MGT_FUNCTION apfnProcessRxMgtFrame[MAX_NUM_OF_FC_SUBTYPES] = { + #if CFG_SUPPORT_AAA + aaaFsmRunEventRxAssoc, /* subtype 0000: Association request */ + #else + NULL, /* subtype 0000: Association request */ + #endif /* CFG_SUPPORT_AAA */ + saaFsmRunEventRxAssoc, /* subtype 0001: Association response */ + #if CFG_SUPPORT_AAA + aaaFsmRunEventRxAssoc, /* subtype 0010: Reassociation request */ + #else + NULL, /* subtype 0010: Reassociation request */ + #endif /* CFG_SUPPORT_AAA */ + saaFsmRunEventRxAssoc, /* subtype 0011: Reassociation response */ + #if CFG_SUPPORT_ADHOC + bssProcessProbeRequest, /* subtype 0100: Probe request */ + #else + NULL, /* subtype 0100: Probe request */ + #endif /* CFG_SUPPORT_ADHOC */ + scanProcessBeaconAndProbeResp, /* subtype 0101: Probe response */ + NULL, /* subtype 0110: reserved */ + NULL, /* subtype 0111: reserved */ + scanProcessBeaconAndProbeResp, /* subtype 1000: Beacon */ + NULL, /* subtype 1001: ATIM */ + saaFsmRunEventRxDisassoc, /* subtype 1010: Disassociation */ + authCheckRxAuthFrameTransSeq, /* subtype 1011: Authentication */ + saaFsmRunEventRxDeauth, /* subtype 1100: Deauthentication */ + nicRxProcessActionFrame, /* subtype 1101: Action */ + NULL, /* subtype 1110: reserved */ + NULL /* subtype 1111: reserved */ +}; +#endif + + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief Initialize the RFBs +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicRxInitialize ( + IN P_ADAPTER_T prAdapter + ) +{ + P_RX_CTRL_T prRxCtrl; + PUINT_8 pucMemHandle; + P_SW_RFB_T prSwRfb = (P_SW_RFB_T)NULL; + UINT_32 i; + + DEBUGFUNC("nicRxInitialize"); + + ASSERT(prAdapter); + prRxCtrl = &prAdapter->rRxCtrl; + + //4 <0> Clear allocated memory. + kalMemZero((PVOID) prRxCtrl->pucRxCached, prRxCtrl->u4RxCachedSize); + + //4 <1> Initialize the RFB lists + QUEUE_INITIALIZE(&prRxCtrl->rFreeSwRfbList); + QUEUE_INITIALIZE(&prRxCtrl->rReceivedRfbList); + QUEUE_INITIALIZE(&prRxCtrl->rIndicatedRfbList); + + pucMemHandle = prRxCtrl->pucRxCached; + for (i = CFG_RX_MAX_PKT_NUM; i != 0; i--) { + prSwRfb = (P_SW_RFB_T)pucMemHandle; + + nicRxSetupRFB(prAdapter, prSwRfb); + nicRxReturnRFB(prAdapter, prSwRfb); + + pucMemHandle += ALIGN_4(sizeof(SW_RFB_T)); + } + + ASSERT(prRxCtrl->rFreeSwRfbList.u4NumElem == CFG_RX_MAX_PKT_NUM); + /* Check if the memory allocation consist with this initialization function */ + ASSERT((UINT_32)(pucMemHandle - prRxCtrl->pucRxCached) == prRxCtrl->u4RxCachedSize); + + //4 <2> Clear all RX counters + RX_RESET_ALL_CNTS(prRxCtrl); + +#if CFG_SDIO_RX_AGG + prRxCtrl->pucRxCoalescingBufPtr = prAdapter->pucCoalescingBufCached; + #if !defined(MT5931) + HAL_CFG_MAX_HIF_RX_LEN_NUM(prAdapter, CFG_SDIO_MAX_RX_AGG_NUM); + #endif +#else + #if !defined(MT5931) + HAL_CFG_MAX_HIF_RX_LEN_NUM(prAdapter, 1); + #endif +#endif + +#if CFG_HIF_STATISTICS + prRxCtrl->u4TotalRxAccessNum = 0; + prRxCtrl->u4TotalRxPacketNum = 0; +#endif + +#if CFG_HIF_RX_STARVATION_WARNING + prRxCtrl->u4QueuedCnt = 0; + prRxCtrl->u4DequeuedCnt = 0; +#endif + + return; +} /* end of nicRxInitialize() */ + + +#if defined(MT5931) +/*----------------------------------------------------------------------------*/ +/*! +* @brief Initialize HIF RX control registers explicitly +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicRxPostInitialize ( + IN P_ADAPTER_T prAdapter + ) +{ + P_RX_CTRL_T prRxCtrl; + DEBUGFUNC("nicRxPostInitialize"); + + ASSERT(prAdapter); + prRxCtrl = &prAdapter->rRxCtrl; + +#if CFG_SDIO_RX_AGG + HAL_CFG_MAX_HIF_RX_LEN_NUM(prAdapter, CFG_SDIO_MAX_RX_AGG_NUM); +#else + HAL_CFG_MAX_HIF_RX_LEN_NUM(prAdapter, 1); +#endif + +} /* end of nicRxPostInitialize() */ +#endif + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Uninitialize the RFBs +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicRxUninitialize ( + IN P_ADAPTER_T prAdapter + ) +{ + P_RX_CTRL_T prRxCtrl; + P_SW_RFB_T prSwRfb = (P_SW_RFB_T)NULL; + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + nicRxFlush(prAdapter); + + do { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_REMOVE_HEAD(&prRxCtrl->rReceivedRfbList, prSwRfb, P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + if (prSwRfb){ + if (prSwRfb->pvPacket) { + kalPacketFree(prAdapter->prGlueInfo, prSwRfb->pvPacket); + } + prSwRfb->pvPacket = NULL; + } + else { + break; + } + }while (TRUE); + + do { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfb, P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + if (prSwRfb){ + if (prSwRfb->pvPacket) { + kalPacketFree(prAdapter->prGlueInfo, prSwRfb->pvPacket); + } + prSwRfb->pvPacket = NULL; + } + else { + break; + } + }while (TRUE); + + return; +} /* end of nicRxUninitialize() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Fill RFB +* +* @param prAdapter pointer to the Adapter handler +* @param prSWRfb specify the RFB to receive rx data +* +* @return (none) +* +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicRxFillRFB ( + IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb + ) +{ + P_HIF_RX_HEADER_T prHifRxHdr; + + UINT_32 u4PktLen = 0; + UINT_32 u4MacHeaderLen; + UINT_32 u4HeaderOffset; + + DEBUGFUNC("nicRxFillRFB"); + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prHifRxHdr = prSwRfb->prHifRxHdr; + ASSERT(prHifRxHdr); + + u4PktLen= prHifRxHdr->u2PacketLen; + + u4HeaderOffset = (UINT_32)(prHifRxHdr->ucHerderLenOffset & HIF_RX_HDR_HEADER_OFFSET_MASK); + u4MacHeaderLen = (UINT_32)(prHifRxHdr->ucHerderLenOffset & HIF_RX_HDR_HEADER_LEN) + >> HIF_RX_HDR_HEADER_LEN_OFFSET; + + //DBGLOG(RX, TRACE, ("u4HeaderOffset = %d, u4MacHeaderLen = %d\n", + // u4HeaderOffset, u4MacHeaderLen)); + + prSwRfb->u2HeaderLen = (UINT_16)u4MacHeaderLen; + prSwRfb->pvHeader = (PUINT_8)prHifRxHdr + HIF_RX_HDR_SIZE + u4HeaderOffset; + prSwRfb->u2PacketLen = (UINT_16)(u4PktLen - (HIF_RX_HDR_SIZE + u4HeaderOffset)); + + //DBGLOG(RX, TRACE, ("Dump Rx packet, u2PacketLen = %d\n", prSwRfb->u2PacketLen)); + //DBGLOG_MEM8(RX, TRACE, prSwRfb->pvHeader, prSwRfb->u2PacketLen); + +#if 0 + if (prHifRxHdr->ucReorder & HIF_RX_HDR_80211_HEADER_FORMAT){ + prSwRfb->u4HifRxHdrFlag |= HIF_RX_HDR_FLAG_802_11_FORMAT; + DBGLOG(RX, TRACE, ("HIF_RX_HDR_FLAG_802_11_FORMAT\n")); + } + + if (prHifRxHdr->ucReorder & HIF_RX_HDR_DO_REORDER){ + prSwRfb->u4HifRxHdrFlag |= HIF_RX_HDR_FLAG_DO_REORDERING; + DBGLOG(RX, TRACE, ("HIF_RX_HDR_FLAG_DO_REORDERING\n")); + + /* Get Seq. No and TID, Wlan Index info */ + if (prHifRxHdr->u2SeqNoTid & HIF_RX_HDR_BAR_FRAME){ + prSwRfb->u4HifRxHdrFlag |= HIF_RX_HDR_FLAG_BAR_FRAME; + DBGLOG(RX, TRACE, ("HIF_RX_HDR_FLAG_BAR_FRAME\n")); + } + + prSwRfb->u2SSN = prHifRxHdr->u2SeqNoTid & HIF_RX_HDR_SEQ_NO_MASK; + prSwRfb->ucTid = (UINT_8)((prHifRxHdr->u2SeqNoTid & HIF_RX_HDR_TID_MASK) + >> HIF_RX_HDR_TID_OFFSET); + DBGLOG(RX, TRACE, ("u2SSN = %d, ucTid = %d\n", + prSwRfb->u2SSN, prSwRfb->ucTid)); + } + + if (prHifRxHdr->ucReorder & HIF_RX_HDR_WDS){ + prSwRfb->u4HifRxHdrFlag |= HIF_RX_HDR_FLAG_AMP_WDS; + DBGLOG(RX, TRACE, ("HIF_RX_HDR_FLAG_AMP_WDS\n")); + } +#endif +} + + +#if CFG_TCP_IP_CHKSUM_OFFLOAD || CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 +/*----------------------------------------------------------------------------*/ +/*! +* @brief Fill checksum status in RFB +* +* @param prAdapter pointer to the Adapter handler +* @param prSWRfb the RFB to receive rx data +* @param u4TcpUdpIpCksStatus specify the Checksum status +* +* @return (none) +* +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicRxFillChksumStatus( + IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb, + IN UINT_32 u4TcpUdpIpCksStatus +) +{ + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + if (prAdapter->u4CSUMFlags != CSUM_NOT_SUPPORTED){ + if (u4TcpUdpIpCksStatus & RX_CS_TYPE_IPv4) { // IPv4 packet + prSwRfb->aeCSUM[CSUM_TYPE_IPV6] = CSUM_RES_NONE; + if(u4TcpUdpIpCksStatus & RX_CS_STATUS_IP) { //IP packet csum failed + prSwRfb->aeCSUM[CSUM_TYPE_IPV4] = CSUM_RES_FAILED; + } else { + prSwRfb->aeCSUM[CSUM_TYPE_IPV4] = CSUM_RES_SUCCESS; + } + + if (u4TcpUdpIpCksStatus & RX_CS_TYPE_TCP) { //TCP packet + prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_NONE; + if(u4TcpUdpIpCksStatus & RX_CS_STATUS_TCP) { //TCP packet csum failed + prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_FAILED; + } else { + prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_SUCCESS; + } + } + else if (u4TcpUdpIpCksStatus & RX_CS_TYPE_UDP) { //UDP packet + prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_NONE; + if(u4TcpUdpIpCksStatus & RX_CS_STATUS_UDP) { //UDP packet csum failed + prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_FAILED; + } else { + prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_SUCCESS; + } + } + else { + prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_NONE; + prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_NONE; + } + } + else if (u4TcpUdpIpCksStatus & RX_CS_TYPE_IPv6) {//IPv6 packet + prSwRfb->aeCSUM[CSUM_TYPE_IPV4] = CSUM_RES_NONE; + prSwRfb->aeCSUM[CSUM_TYPE_IPV6] = CSUM_RES_SUCCESS; + + if (u4TcpUdpIpCksStatus & RX_CS_TYPE_TCP) { //TCP packet + prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_NONE; + if(u4TcpUdpIpCksStatus & RX_CS_STATUS_TCP) { //TCP packet csum failed + prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_FAILED; + } else { + prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_SUCCESS; + } + } + else if (u4TcpUdpIpCksStatus & RX_CS_TYPE_UDP) { //UDP packet + prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_NONE; + if(u4TcpUdpIpCksStatus & RX_CS_STATUS_UDP) { //UDP packet csum failed + prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_FAILED; + } else { + prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_SUCCESS; + } + } + else { + prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_NONE; + prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_NONE; + } + } + else { + prSwRfb->aeCSUM[CSUM_TYPE_IPV4] = CSUM_RES_NONE; + prSwRfb->aeCSUM[CSUM_TYPE_IPV6] = CSUM_RES_NONE; + } + } + +} +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process packet doesn't need to do buffer reordering +* +* @param prAdapter pointer to the Adapter handler +* @param prSWRfb the RFB to receive rx data +* +* @return (none) +* +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicRxProcessPktWithoutReorder ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ) +{ + P_RX_CTRL_T prRxCtrl; + P_TX_CTRL_T prTxCtrl; + BOOL fgIsRetained = FALSE; + UINT_32 u4CurrentRxBufferCount; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + + DEBUGFUNC("nicRxProcessPktWithoutReorder"); + //DBGLOG(RX, TRACE, ("\n")); + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + prTxCtrl = &prAdapter->rTxCtrl; + ASSERT(prTxCtrl); + + u4CurrentRxBufferCount = prRxCtrl->rFreeSwRfbList.u4NumElem; + /* QM USED = $A, AVAILABLE COUNT = $B, INDICATED TO OS = $C + * TOTAL = $A + $B + $C + * + * Case #1 (Retain) + * ------------------------------------------------------- + * $A + $B < THRESHOLD := $A + $B + $C < THRESHOLD + $C := $TOTAL - THRESHOLD < $C + * => $C used too much, retain + * + * Case #2 (Non-Retain) + * ------------------------------------------------------- + * $A + $B > THRESHOLD := $A + $B + $C > THRESHOLD + $C := $TOTAL - THRESHOLD > $C + * => still availble for $C to use + * + */ + fgIsRetained = (((u4CurrentRxBufferCount + + qmGetRxReorderQueuedBufferCount(prAdapter) + + prTxCtrl->i4PendingFwdFrameCount) < CFG_RX_RETAINED_PKT_THRESHOLD) ? + TRUE : FALSE); + + //DBGLOG(RX, INFO, ("fgIsRetained = %d\n", fgIsRetained)); + + if (kalProcessRxPacket(prAdapter->prGlueInfo, + prSwRfb->pvPacket, + prSwRfb->pvHeader, + (UINT_32)prSwRfb->u2PacketLen, + fgIsRetained, + prSwRfb->aeCSUM) != WLAN_STATUS_SUCCESS) { + DBGLOG(RX, ERROR, ("kalProcessRxPacket return value != WLAN_STATUS_SUCCESS\n")); + ASSERT(0); + + nicRxReturnRFB(prAdapter, prSwRfb); + return; + } + else { + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + if (prStaRec) { +#if CFG_ENABLE_WIFI_DIRECT + if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX && + prAdapter->fgIsP2PRegistered == TRUE) { + GLUE_SET_PKT_FLAG_P2P(prSwRfb->pvPacket); + } +#endif +#if CFG_ENABLE_BT_OVER_WIFI + if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) { + GLUE_SET_PKT_FLAG_PAL(prSwRfb->pvPacket); + } +#endif + } + prRxCtrl->apvIndPacket[prRxCtrl->ucNumIndPacket] = prSwRfb->pvPacket; + prRxCtrl->ucNumIndPacket++; + } + + if (fgIsRetained) { + prRxCtrl->apvRetainedPacket[prRxCtrl->ucNumRetainedPacket] = prSwRfb->pvPacket; + prRxCtrl->ucNumRetainedPacket++; + /* TODO : error handling of nicRxSetupRFB */ + nicRxSetupRFB(prAdapter, prSwRfb); + nicRxReturnRFB(prAdapter, prSwRfb); + } + else{ + prSwRfb->pvPacket = NULL; + nicRxReturnRFB(prAdapter, prSwRfb); + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process forwarding data packet +* +* @param prAdapter pointer to the Adapter handler +* @param prSWRfb the RFB to receive rx data +* +* @return (none) +* +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicRxProcessForwardPkt ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ) +{ + P_MSDU_INFO_T prMsduInfo, prRetMsduInfoList; + P_TX_CTRL_T prTxCtrl; + P_RX_CTRL_T prRxCtrl; + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("nicRxProcessForwardPkt"); + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prTxCtrl = &prAdapter->rTxCtrl; + prRxCtrl = &prAdapter->rRxCtrl; + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + QUEUE_REMOVE_HEAD(&prTxCtrl->rFreeMsduInfoList, prMsduInfo, P_MSDU_INFO_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + + if(prMsduInfo && kalProcessRxPacket(prAdapter->prGlueInfo, + prSwRfb->pvPacket, + prSwRfb->pvHeader, + (UINT_32)prSwRfb->u2PacketLen, + prRxCtrl->rFreeSwRfbList.u4NumElem < CFG_RX_RETAINED_PKT_THRESHOLD ? TRUE : FALSE, + prSwRfb->aeCSUM) == WLAN_STATUS_SUCCESS) { + + prMsduInfo->eSrc = TX_PACKET_FORWARDING; + // pack into MSDU_INFO_T + nicTxFillMsduInfo(prAdapter, prMsduInfo, (P_NATIVE_PACKET)(prSwRfb->pvPacket)); + // Overwrite the ucNetworkType + prMsduInfo->ucNetworkType = HIF_RX_HDR_GET_NETWORK_IDX(prSwRfb->prHifRxHdr); + + // release RX buffer (to rIndicatedRfbList) + prSwRfb->pvPacket = NULL; + nicRxReturnRFB(prAdapter, prSwRfb); + + // increase forward frame counter + GLUE_INC_REF_CNT(prTxCtrl->i4PendingFwdFrameCount); + + // send into TX queue + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); + prRetMsduInfoList = qmEnqueueTxPackets(prAdapter, prMsduInfo); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); + + if(prRetMsduInfoList != NULL) { // TX queue refuses queuing the packet + nicTxFreeMsduInfoPacket(prAdapter, prRetMsduInfoList); + nicTxReturnMsduInfo(prAdapter, prRetMsduInfoList); + } + /* indicate service thread for sending */ + if(prTxCtrl->i4PendingFwdFrameCount > 0) { + kalSetEvent(prAdapter->prGlueInfo); + } + } + else { // no TX resource + nicRxReturnRFB(prAdapter, prSwRfb); + } + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process broadcast data packet for both host and forwarding +* +* @param prAdapter pointer to the Adapter handler +* @param prSWRfb the RFB to receive rx data +* +* @return (none) +* +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicRxProcessGOBroadcastPkt ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ) +{ + P_SW_RFB_T prSwRfbDuplicated; + P_TX_CTRL_T prTxCtrl; + P_RX_CTRL_T prRxCtrl; + P_HIF_RX_HEADER_T prHifRxHdr; + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("nicRxProcessGOBroadcastPkt"); + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prTxCtrl = &prAdapter->rTxCtrl; + prRxCtrl = &prAdapter->rRxCtrl; + + prHifRxHdr = prSwRfb->prHifRxHdr; + ASSERT(prHifRxHdr); + + ASSERT(CFG_NUM_OF_QM_RX_PKT_NUM >= 16); + + if( prRxCtrl->rFreeSwRfbList.u4NumElem + >= (CFG_RX_MAX_PKT_NUM - (CFG_NUM_OF_QM_RX_PKT_NUM - 16 /* Reserved for others */) ) ) { + + /* 1. Duplicate SW_RFB_T */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfbDuplicated, P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + + if(prSwRfbDuplicated){ + kalMemCopy(prSwRfbDuplicated->pucRecvBuff, + prSwRfb->pucRecvBuff, + ALIGN_4(prHifRxHdr->u2PacketLen + HIF_RX_HW_APPENDED_LEN)); + + prSwRfbDuplicated->ucPacketType = HIF_RX_PKT_TYPE_DATA; + prSwRfbDuplicated->ucStaRecIdx = (UINT_8)(prHifRxHdr->ucStaRecIdx); + nicRxFillRFB(prAdapter, prSwRfbDuplicated); + + /* 2. Modify eDst */ + prSwRfbDuplicated->eDst = RX_PKT_DESTINATION_FORWARD; + + /* 4. Forward */ + nicRxProcessForwardPkt(prAdapter, prSwRfbDuplicated); + } + } + else { + DBGLOG(RX, WARN, ("Stop to forward BMC packet due to less free Sw Rfb %u\n", prRxCtrl->rFreeSwRfbList.u4NumElem)); + } + + /* 3. Indicate to host */ + prSwRfb->eDst = RX_PKT_DESTINATION_HOST; + nicRxProcessPktWithoutReorder(prAdapter, prSwRfb); + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process HIF data packet +* +* @param prAdapter pointer to the Adapter handler +* @param prSWRfb the RFB to receive rx data +* +* @return (none) +* +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicRxProcessDataPacket ( + IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb + ) +{ + P_RX_CTRL_T prRxCtrl; + P_SW_RFB_T prRetSwRfb, prNextSwRfb; + P_HIF_RX_HEADER_T prHifRxHdr; + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("nicRxProcessDataPacket"); + //DBGLOG(INIT, TRACE, ("\n")); + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prHifRxHdr = prSwRfb->prHifRxHdr; + prRxCtrl = &prAdapter->rRxCtrl; + + nicRxFillRFB(prAdapter, prSwRfb); + +#if 1 /* Check 1x Pkt */ + if (prSwRfb->u2PacketLen > 14) { + PUINT_8 pc = (PUINT_8)prSwRfb->pvHeader; + UINT_16 u2Etype = 0; + + u2Etype = (pc[ETH_TYPE_LEN_OFFSET] << 8) | (pc[ETH_TYPE_LEN_OFFSET + 1]); + +#if CFG_SUPPORT_WAPI + if (u2Etype == ETH_P_1X || u2Etype == ETH_WPI_1X) { + DBGLOG(RSN, INFO, ("R1X len=%d\n", prSwRfb->u2PacketLen)); + } +#else + if (u2Etype == ETH_P_1X) { + DBGLOG(RSN, INFO, ("R1X len=%d\n", prSwRfb->u2PacketLen)); + } +#endif + else if (u2Etype == ETH_P_PRE_1X) { + DBGLOG(RSN, INFO, ("Pre R1X len=%d\n", prSwRfb->u2PacketLen)); + } + } +#endif + +#if CFG_TCP_IP_CHKSUM_OFFLOAD || CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 + { + UINT_32 u4TcpUdpIpCksStatus; + + u4TcpUdpIpCksStatus = *((PUINT_32)((UINT_32)prHifRxHdr + + (UINT_32)(ALIGN_4(prHifRxHdr->u2PacketLen)))); + nicRxFillChksumStatus(prAdapter, prSwRfb, u4TcpUdpIpCksStatus); + + } +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + + prStaRec = cnmGetStaRecByIndex(prAdapter, prHifRxHdr->ucStaRecIdx); + if(secCheckClassError(prAdapter, prSwRfb, prStaRec) == TRUE && + prAdapter->fgTestMode == FALSE) { +#if CFG_HIF_RX_STARVATION_WARNING + prRxCtrl->u4QueuedCnt++; +#endif + + if((prRetSwRfb = qmHandleRxPackets(prAdapter, prSwRfb)) != NULL) { + do { + // save next first + prNextSwRfb = (P_SW_RFB_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prRetSwRfb); + + switch(prRetSwRfb->eDst) { + case RX_PKT_DESTINATION_HOST: + nicRxProcessPktWithoutReorder(prAdapter, prRetSwRfb); + break; + + case RX_PKT_DESTINATION_FORWARD: + nicRxProcessForwardPkt(prAdapter, prRetSwRfb); + break; + + case RX_PKT_DESTINATION_HOST_WITH_FORWARD: + nicRxProcessGOBroadcastPkt(prAdapter, prRetSwRfb); + break; + + case RX_PKT_DESTINATION_NULL: + nicRxReturnRFB(prAdapter, prRetSwRfb); + RX_INC_CNT(prRxCtrl, RX_DST_NULL_DROP_COUNT); + RX_INC_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT); + break; + + default: + break; + } +#if CFG_HIF_RX_STARVATION_WARNING + prRxCtrl->u4DequeuedCnt++; +#endif + prRetSwRfb = prNextSwRfb; + } while(prRetSwRfb); + } + } + else { + nicRxReturnRFB(prAdapter, prSwRfb); + RX_INC_CNT(prRxCtrl, RX_CLASS_ERR_DROP_COUNT); + RX_INC_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT); + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process HIF event packet +* +* @param prAdapter pointer to the Adapter handler +* @param prSWRfb the RFB to receive rx data +* +* @return (none) +* +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicRxProcessEventPacket ( + IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb + ) +{ + P_CMD_INFO_T prCmdInfo; + P_MSDU_INFO_T prMsduInfo; + P_WIFI_EVENT_T prEvent; + P_GLUE_INFO_T prGlueInfo; + + DEBUGFUNC("nicRxProcessEventPacket"); + //DBGLOG(INIT, TRACE, ("\n")); + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prEvent = (P_WIFI_EVENT_T) prSwRfb->pucRecvBuff; + prGlueInfo = prAdapter->prGlueInfo; + + // Event Handling + switch(prEvent->ucEID) { + case EVENT_ID_CMD_RESULT: + prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); + + if(prCmdInfo != NULL) { + P_EVENT_CMD_RESULT prCmdResult; + prCmdResult = (P_EVENT_CMD_RESULT) ((PUINT_8)prEvent + EVENT_HDR_SIZE); + + /* CMD_RESULT should be only in response to Set commands */ + ASSERT(prCmdInfo->fgSetQuery == FALSE || prCmdInfo->fgNeedResp == TRUE); + + if(prCmdResult->ucStatus == 0) { // success + if(prCmdInfo->pfCmdDoneHandler) { + prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prEvent->aucBuffer); + } + else if(prCmdInfo->fgIsOid == TRUE) { + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_SUCCESS); + } + } + else if(prCmdResult->ucStatus == 1) { // reject + if(prCmdInfo->fgIsOid == TRUE) + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_FAILURE); + } + else if(prCmdResult->ucStatus == 2) { // unknown CMD + if(prCmdInfo->fgIsOid == TRUE) + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_NOT_SUPPORTED); + } + + // return prCmdInfo + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } + + break; + +#if 0 + case EVENT_ID_CONNECTION_STATUS: + /* OBSELETE */ + { + P_EVENT_CONNECTION_STATUS prConnectionStatus; + prConnectionStatus = (P_EVENT_CONNECTION_STATUS) (prEvent->aucBuffer); + + DbgPrint("RX EVENT: EVENT_ID_CONNECTION_STATUS = %d\n", prConnectionStatus->ucMediaStatus); + if (prConnectionStatus->ucMediaStatus == PARAM_MEDIA_STATE_DISCONNECTED) { // disconnected + if(kalGetMediaStateIndicated(prGlueInfo) != PARAM_MEDIA_STATE_DISCONNECTED) { + + kalIndicateStatusAndComplete(prGlueInfo, + WLAN_STATUS_MEDIA_DISCONNECT, + NULL, + 0); + + prAdapter->rWlanInfo.u4SysTime = kalGetTimeTick(); + } + } + else if(prConnectionStatus->ucMediaStatus == PARAM_MEDIA_STATE_CONNECTED) { // connected + prAdapter->rWlanInfo.u4SysTime = kalGetTimeTick(); + + // fill information for association result + prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen + = prConnectionStatus->ucSsidLen; + kalMemCopy(prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, + prConnectionStatus->aucSsid, + prConnectionStatus->ucSsidLen); + + kalMemCopy(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, + prConnectionStatus->aucBssid, + MAC_ADDR_LEN); + + prAdapter->rWlanInfo.rCurrBssId.u4Privacy + = prConnectionStatus->ucEncryptStatus; // @FIXME + prAdapter->rWlanInfo.rCurrBssId.rRssi + = 0; //@FIXME + prAdapter->rWlanInfo.rCurrBssId.eNetworkTypeInUse + = PARAM_NETWORK_TYPE_AUTOMODE; //@FIXME + prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4BeaconPeriod + = prConnectionStatus->u2BeaconPeriod; + prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4ATIMWindow + = prConnectionStatus->u2ATIMWindow; + prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4DSConfig + = prConnectionStatus->u4FreqInKHz; + prAdapter->rWlanInfo.ucNetworkType + = prConnectionStatus->ucNetworkType; + + switch(prConnectionStatus->ucInfraMode) { + case 0: + prAdapter->rWlanInfo.rCurrBssId.eOpMode = NET_TYPE_IBSS; + break; + case 1: + prAdapter->rWlanInfo.rCurrBssId.eOpMode = NET_TYPE_INFRA; + break; + case 2: + default: + prAdapter->rWlanInfo.rCurrBssId.eOpMode = NET_TYPE_AUTO_SWITCH; + break; + } + // always indicate to OS according to MSDN (re-association/roaming) + kalIndicateStatusAndComplete(prGlueInfo, + WLAN_STATUS_MEDIA_CONNECT, + NULL, + 0); + } + } + break; + + case EVENT_ID_SCAN_RESULT: + /* OBSELETE */ + break; +#endif + + case EVENT_ID_RX_ADDBA: + /* The FW indicates that an RX BA agreement will be established */ + qmHandleEventRxAddBa(prAdapter, prEvent); + break; + + case EVENT_ID_RX_DELBA: + /* The FW indicates that an RX BA agreement has been deleted */ + qmHandleEventRxDelBa(prAdapter, prEvent); + break; + + case EVENT_ID_LINK_QUALITY: +#if CFG_ENABLE_WIFI_DIRECT && CFG_SUPPORT_P2P_RSSI_QUERY + if (prEvent->u2PacketLen == EVENT_HDR_SIZE + sizeof(EVENT_LINK_QUALITY_EX)) { + P_EVENT_LINK_QUALITY_EX prLqEx = (P_EVENT_LINK_QUALITY_EX)(prEvent->aucBuffer); + + if (prLqEx->ucIsLQ0Rdy) { + nicUpdateLinkQuality(prAdapter, NETWORK_TYPE_AIS_INDEX, (P_EVENT_LINK_QUALITY)prLqEx); + } + + + if (prLqEx->ucIsLQ1Rdy) { + nicUpdateLinkQuality(prAdapter, NETWORK_TYPE_P2P_INDEX, (P_EVENT_LINK_QUALITY)prLqEx); + } + } + else { + /* For old FW, P2P may invoke link quality query, and make driver flag becone TRUE. */ + DBGLOG(P2P, WARN, ("Old FW version, not support P2P RSSI query.\n")); + + /* Must not use NETWORK_TYPE_P2P_INDEX, cause the structure is mismatch. */ + nicUpdateLinkQuality(prAdapter, NETWORK_TYPE_AIS_INDEX, (P_EVENT_LINK_QUALITY)(prEvent->aucBuffer)); + } + +#else + nicUpdateLinkQuality(prAdapter, NETWORK_TYPE_AIS_INDEX, (P_EVENT_LINK_QUALITY)(prEvent->aucBuffer)); +#endif + + /* command response handling */ + prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); + + if(prCmdInfo != NULL) { + if (prCmdInfo->pfCmdDoneHandler) { + prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prEvent->aucBuffer); + } + else if(prCmdInfo->fgIsOid) { + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_SUCCESS); + } + + // return prCmdInfo + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } + + #ifndef LINUX + if(prAdapter->rWlanInfo.eRssiTriggerType == ENUM_RSSI_TRIGGER_GREATER && + prAdapter->rWlanInfo.rRssiTriggerValue >= (PARAM_RSSI)(prAdapter->rLinkQuality.cRssi)) { + prAdapter->rWlanInfo.eRssiTriggerType = ENUM_RSSI_TRIGGER_TRIGGERED; + + kalIndicateStatusAndComplete(prGlueInfo, + WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, + (PVOID) &(prAdapter->rWlanInfo.rRssiTriggerValue), sizeof(PARAM_RSSI)); + } + else if(prAdapter->rWlanInfo.eRssiTriggerType == ENUM_RSSI_TRIGGER_LESS && + prAdapter->rWlanInfo.rRssiTriggerValue <= (PARAM_RSSI)(prAdapter->rLinkQuality.cRssi)) { + prAdapter->rWlanInfo.eRssiTriggerType = ENUM_RSSI_TRIGGER_TRIGGERED; + + kalIndicateStatusAndComplete(prGlueInfo, + WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, + (PVOID) &(prAdapter->rWlanInfo.rRssiTriggerValue), sizeof(PARAM_RSSI)); + } + #endif + + break; + + case EVENT_ID_MIC_ERR_INFO: + { + P_EVENT_MIC_ERR_INFO prMicError; + //P_PARAM_AUTH_EVENT_T prAuthEvent; + P_STA_RECORD_T prStaRec; + + DBGLOG(RSN, EVENT, ("EVENT_ID_MIC_ERR_INFO\n")); + + prMicError = (P_EVENT_MIC_ERR_INFO)(prEvent->aucBuffer); + prStaRec = cnmGetStaRecByAddress(prAdapter, + (UINT_8) NETWORK_TYPE_AIS_INDEX, + prAdapter->rWlanInfo.rCurrBssId.arMacAddress); + ASSERT(prStaRec); + + if (prStaRec) { + rsnTkipHandleMICFailure(prAdapter, prStaRec, (BOOLEAN)prMicError->u4Flags); + } + else { + DBGLOG(RSN, INFO, ("No STA rec!!\n")); + } +#if 0 + prAuthEvent = (P_PARAM_AUTH_EVENT_T)prAdapter->aucIndicationEventBuffer; + + /* Status type: Authentication Event */ + prAuthEvent->rStatus.eStatusType = ENUM_STATUS_TYPE_AUTHENTICATION; + + /* Authentication request */ + prAuthEvent->arRequest[0].u4Length = sizeof(PARAM_AUTH_REQUEST_T); + kalMemCopy((PVOID)prAuthEvent->arRequest[0].arBssid, + (PVOID)prAdapter->rWlanInfo.rCurrBssId.arMacAddress, /* whsu:Todo? */ + PARAM_MAC_ADDR_LEN); + + if (prMicError->u4Flags != 0) { + prAuthEvent->arRequest[0].u4Flags = PARAM_AUTH_REQUEST_GROUP_ERROR; + } + else { + prAuthEvent->arRequest[0].u4Flags = PARAM_AUTH_REQUEST_PAIRWISE_ERROR; + } + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, + (PVOID)prAuthEvent, + sizeof(PARAM_STATUS_INDICATION_T) + sizeof(PARAM_AUTH_REQUEST_T)); +#endif + } + break; + + case EVENT_ID_ASSOC_INFO: + { + P_EVENT_ASSOC_INFO prAssocInfo; + prAssocInfo = (P_EVENT_ASSOC_INFO)(prEvent->aucBuffer); + + kalHandleAssocInfo(prAdapter->prGlueInfo, prAssocInfo); + } + break; + + case EVENT_ID_802_11_PMKID: + { + P_PARAM_AUTH_EVENT_T prAuthEvent; + PUINT_8 cp; + UINT_32 u4LenOfUsedBuffer; + + prAuthEvent = (P_PARAM_AUTH_EVENT_T)prAdapter->aucIndicationEventBuffer; + + prAuthEvent->rStatus.eStatusType = ENUM_STATUS_TYPE_CANDIDATE_LIST; + + u4LenOfUsedBuffer = (UINT_32)(prEvent->u2PacketLen - 8); + + prAuthEvent->arRequest[0].u4Length = u4LenOfUsedBuffer; + + cp = (PUINT_8)&prAuthEvent->arRequest[0]; + + /* Status type: PMKID Candidatelist Event */ + kalMemCopy(cp, (P_EVENT_PMKID_CANDIDATE_LIST_T)(prEvent->aucBuffer), prEvent->u2PacketLen - 8); + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, + (PVOID)prAuthEvent, + sizeof(PARAM_STATUS_INDICATION_T) + u4LenOfUsedBuffer); + } + break; + +#if 0 + case EVENT_ID_ACTIVATE_STA_REC_T: + { + P_EVENT_ACTIVATE_STA_REC_T prActivateStaRec; + prActivateStaRec = (P_EVENT_ACTIVATE_STA_REC_T)(prEvent->aucBuffer); + + DbgPrint("RX EVENT: EVENT_ID_ACTIVATE_STA_REC_T Index:%d, MAC:["MACSTR"]\n", + prActivateStaRec->ucStaRecIdx, + MAC2STR(prActivateStaRec->aucMacAddr)); + + qmActivateStaRec(prAdapter, + (UINT_32)prActivateStaRec->ucStaRecIdx, + ((prActivateStaRec->fgIsQoS) ? TRUE: FALSE), + prActivateStaRec->ucNetworkTypeIndex, + ((prActivateStaRec->fgIsAP) ? TRUE: FALSE), + prActivateStaRec->aucMacAddr); + + } + break; + + case EVENT_ID_DEACTIVATE_STA_REC_T: + { + P_EVENT_DEACTIVATE_STA_REC_T prDeactivateStaRec; + prDeactivateStaRec = (P_EVENT_DEACTIVATE_STA_REC_T)(prEvent->aucBuffer); + + DbgPrint("RX EVENT: EVENT_ID_DEACTIVATE_STA_REC_T Index:%d, MAC:["MACSTR"]\n", + prDeactivateStaRec->ucStaRecIdx); + + qmDeactivateStaRec(prAdapter, + prDeactivateStaRec->ucStaRecIdx); + } + break; +#endif + + case EVENT_ID_SCAN_DONE: + scnEventScanDone(prAdapter, (P_EVENT_SCAN_DONE)(prEvent->aucBuffer)); + break; + + case EVENT_ID_TX_DONE: + { + P_EVENT_TX_DONE_T prTxDone; + prTxDone = (P_EVENT_TX_DONE_T)(prEvent->aucBuffer); + + DBGLOG(INIT, TRACE,("EVENT_ID_TX_DONE PacketSeq:%u ucStatus: %u SN: %u\n", + prTxDone->ucPacketSeq, prTxDone->ucStatus, prTxDone->u2SequenceNumber)); + + /* call related TX Done Handler */ + prMsduInfo = nicGetPendingTxMsduInfo(prAdapter, prTxDone->ucPacketSeq); + + if(prMsduInfo) { + prMsduInfo->pfTxDoneHandler(prAdapter, prMsduInfo, (ENUM_TX_RESULT_CODE_T)(prTxDone->ucStatus)); + + cnmMgtPktFree(prAdapter, prMsduInfo); + } + } + break; + + case EVENT_ID_SLEEPY_NOTIFY: + { + P_EVENT_SLEEPY_NOTIFY prEventSleepyNotify; + prEventSleepyNotify = (P_EVENT_SLEEPY_NOTIFY)(prEvent->aucBuffer); + + //DBGLOG(RX, INFO, ("ucSleepyState = %d\n", prEventSleepyNotify->ucSleepyState)); + + prAdapter->fgWiFiInSleepyState = (BOOLEAN)(prEventSleepyNotify->ucSleepyState); + } + break; + case EVENT_ID_BT_OVER_WIFI: +#if CFG_ENABLE_BT_OVER_WIFI + { + UINT_8 aucTmp[sizeof(AMPC_EVENT) + sizeof(BOW_LINK_DISCONNECTED)]; + P_EVENT_BT_OVER_WIFI prEventBtOverWifi; + P_AMPC_EVENT prBowEvent; + P_BOW_LINK_CONNECTED prBowLinkConnected; + P_BOW_LINK_DISCONNECTED prBowLinkDisconnected; + + prEventBtOverWifi = (P_EVENT_BT_OVER_WIFI)(prEvent->aucBuffer); + + // construct event header + prBowEvent = (P_AMPC_EVENT)aucTmp; + + if(prEventBtOverWifi->ucLinkStatus == 0) { + // Connection + prBowEvent->rHeader.ucEventId = BOW_EVENT_ID_LINK_CONNECTED; + prBowEvent->rHeader.ucSeqNumber = 0; + prBowEvent->rHeader.u2PayloadLength = sizeof(BOW_LINK_CONNECTED); + + // fill event body + prBowLinkConnected = (P_BOW_LINK_CONNECTED)(prBowEvent->aucPayload); + prBowLinkConnected->rChannel.ucChannelNum = prEventBtOverWifi->ucSelectedChannel; + kalMemZero(prBowLinkConnected->aucPeerAddress, MAC_ADDR_LEN); //@FIXME + + kalIndicateBOWEvent(prAdapter->prGlueInfo, prBowEvent); + } + else { + // Disconnection + prBowEvent->rHeader.ucEventId = BOW_EVENT_ID_LINK_DISCONNECTED; + prBowEvent->rHeader.ucSeqNumber = 0; + prBowEvent->rHeader.u2PayloadLength = sizeof(BOW_LINK_DISCONNECTED); + + // fill event body + prBowLinkDisconnected = (P_BOW_LINK_DISCONNECTED)(prBowEvent->aucPayload); + prBowLinkDisconnected->ucReason = 0; //@FIXME + kalMemZero(prBowLinkDisconnected->aucPeerAddress, MAC_ADDR_LEN); //@FIXME + + kalIndicateBOWEvent(prAdapter->prGlueInfo, prBowEvent); + } + } + break; +#endif + case EVENT_ID_STATISTICS: + /* buffer statistics for further query */ + prAdapter->fgIsStatValid = TRUE; + prAdapter->rStatUpdateTime = kalGetTimeTick(); + kalMemCopy(&prAdapter->rStatStruct, prEvent->aucBuffer, sizeof(EVENT_STATISTICS)); + + /* command response handling */ + prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); + + if(prCmdInfo != NULL) { + if (prCmdInfo->pfCmdDoneHandler) { + prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prEvent->aucBuffer); + } + else if(prCmdInfo->fgIsOid) { + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_SUCCESS); + } + + // return prCmdInfo + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } + + break; + + case EVENT_ID_CH_PRIVILEGE: + cnmChMngrHandleChEvent(prAdapter, prEvent); + break; + + case EVENT_ID_BSS_ABSENCE_PRESENCE: + qmHandleEventBssAbsencePresence(prAdapter, prEvent); + break; + + case EVENT_ID_STA_CHANGE_PS_MODE: + qmHandleEventStaChangePsMode(prAdapter, prEvent); + break; +#if CFG_ENABLE_WIFI_DIRECT + case EVENT_ID_STA_UPDATE_FREE_QUOTA: + qmHandleEventStaUpdateFreeQuota(prAdapter, prEvent); + break; +#endif + case EVENT_ID_BSS_BEACON_TIMEOUT: + DBGLOG(INIT, INFO,("EVENT_ID_BSS_BEACON_TIMEOUT\n")); + + if (prAdapter->fgDisBcnLostDetection == FALSE) { + P_EVENT_BSS_BEACON_TIMEOUT_T prEventBssBeaconTimeout; + prEventBssBeaconTimeout = (P_EVENT_BSS_BEACON_TIMEOUT_T)(prEvent->aucBuffer); + + if(prEventBssBeaconTimeout->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { + aisBssBeaconTimeout(prAdapter); + } +#if CFG_ENABLE_WIFI_DIRECT + else if((prAdapter->fgIsP2PRegistered) && + (prEventBssBeaconTimeout->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX)) { + + prAdapter->rP2pFuncLkr.prP2pFsmRunEventBeaconTimeout(prAdapter); + } +#endif +#if CFG_ENABLE_BT_OVER_WIFI + else if(prEventBssBeaconTimeout->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) { + } +#endif + else { + DBGLOG(RX, ERROR, ("EVENT_ID_BSS_BEACON_TIMEOUT: (ucNetTypeIdx = %d)\n", + prEventBssBeaconTimeout->ucNetTypeIndex)); + } + } + + break; + case EVENT_ID_UPDATE_NOA_PARAMS: +#if CFG_ENABLE_WIFI_DIRECT + if(prAdapter->fgIsP2PRegistered){ + P_EVENT_UPDATE_NOA_PARAMS_T prEventUpdateNoaParam; + prEventUpdateNoaParam = (P_EVENT_UPDATE_NOA_PARAMS_T)(prEvent->aucBuffer); + + if (prEventUpdateNoaParam->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { + prAdapter->rP2pFuncLkr.prP2pProcessEvent_UpdateNOAParam(prAdapter, + prEventUpdateNoaParam->ucNetTypeIndex, + prEventUpdateNoaParam); + } else { + ASSERT(0); + } + } +#else + ASSERT(0); +#endif + break; + + case EVENT_ID_STA_AGING_TIMEOUT: +#if CFG_ENABLE_WIFI_DIRECT + { + P_EVENT_STA_AGING_TIMEOUT_T prEventStaAgingTimeout; + P_STA_RECORD_T prStaRec; + P_BSS_INFO_T prBssInfo = (P_BSS_INFO_T)NULL; + + prEventStaAgingTimeout = (P_EVENT_STA_AGING_TIMEOUT_T)(prEvent->aucBuffer); + prStaRec = cnmGetStaRecByIndex(prAdapter, prEventStaAgingTimeout->ucStaRecIdx); + if (prStaRec == NULL) { + break; + } + + + DBGLOG(INIT, INFO,("EVENT_ID_STA_AGING_TIMEOUT %u " MACSTR "\n", + prEventStaAgingTimeout->ucStaRecIdx, MAC2STR(prStaRec->aucMacAddr))); + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + /* Call False Auth */ + if(prAdapter->fgIsP2PRegistered){ + if(prAdapter->rP2pFuncLkr.prP2pFuncDisconnect) { + prAdapter->rP2pFuncLkr.prP2pFuncDisconnect(prAdapter, prStaRec, TRUE, REASON_CODE_DISASSOC_INACTIVITY); + } + } + + bssRemoveStaRecFromClientList(prAdapter, prBssInfo, prStaRec); + } +#endif + break; + + case EVENT_ID_AP_OBSS_STATUS: +#if CFG_ENABLE_WIFI_DIRECT + if(prAdapter->fgIsP2PRegistered){ + ASSERT(prAdapter->rP2pFuncLkr.prRlmHandleObssStatusEventPkt); + prAdapter->rP2pFuncLkr.prRlmHandleObssStatusEventPkt( + prAdapter, + (P_EVENT_AP_OBSS_STATUS_T) prEvent->aucBuffer); + } +#endif + break; + + case EVENT_ID_ROAMING_STATUS: +#if CFG_SUPPORT_ROAMING + { + P_ROAMING_PARAM_T prParam; + + prParam = (P_ROAMING_PARAM_T)(prEvent->aucBuffer); + roamingFsmProcessEvent(prAdapter, prParam); + } +#endif /* CFG_SUPPORT_ROAMING */ + break; +#if 0 // CFG_ENABLE_WIFI_DIRECT && CFG_SUPPORT_ANTI_PIRACY + case EVENT_ID_SEC_CHECK_RSP: + if(prAdapter->fgIsP2PRegistered){ + ASSERT(prAdapter->rP2pFuncLkr.prP2pHandleSecCheckRsp); + + prAdapter->rP2pFuncLkr.prP2pHandleSecCheckRsp( + prAdapter, + (PUINT_8) prEvent->aucBuffer, + prEvent->u2PacketLen - EVENT_HDR_SIZE); + + /* command response handling */ + prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); + + if(prCmdInfo != NULL) { + if (prCmdInfo->pfCmdDoneHandler) { + prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prEvent->aucBuffer); + } + else if(prCmdInfo->fgIsOid) { + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_SUCCESS); + } + + // return prCmdInfo + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } + } + break; +#endif + case EVENT_ID_SEND_DEAUTH: +#if DBG + { + P_WLAN_MAC_HEADER_T prWlanMacHeader; + + prWlanMacHeader = (P_WLAN_MAC_HEADER_T)&prEvent->aucBuffer[0]; + DBGLOG(RX, INFO, ("nicRx: aucAddr1: "MACSTR"\n", MAC2STR(prWlanMacHeader->aucAddr1))); + DBGLOG(RX, INFO, ("nicRx: aucAddr2: "MACSTR"\n", MAC2STR(prWlanMacHeader->aucAddr2))); + } +#endif + /* receive packets without StaRec */ + prSwRfb->pvHeader = (P_WLAN_MAC_HEADER_T)&prEvent->aucBuffer[0]; + if (WLAN_STATUS_SUCCESS == authSendDeauthFrame(prAdapter, + NULL, + prSwRfb, + REASON_CODE_CLASS_3_ERR, + (PFN_TX_DONE_HANDLER)NULL)) { + DBGLOG(RX, INFO, ("Send Deauth Error\n")); + } + break; + +#if CFG_SUPPORT_RDD_TEST_MODE + case EVENT_ID_UPDATE_RDD_STATUS: + { + P_EVENT_RDD_STATUS_T prEventRddStatus; + + prEventRddStatus = (P_EVENT_RDD_STATUS_T) (prEvent->aucBuffer); + + prAdapter->ucRddStatus = prEventRddStatus->ucRddStatus; + } + + break; +#endif + +#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS + case EVENT_ID_UPDATE_BWCS_STATUS: + { + P_PTA_IPC_T prEventBwcsStatus; + + prEventBwcsStatus = (P_PTA_IPC_T) (prEvent->aucBuffer); + +#if CFG_SUPPORT_BCM_BWCS_DEBUG + printk(KERN_INFO DRV_NAME "BCM BWCS Event: %02x%02x%02x%02x\n", prEventBwcsStatus->u.aucBTPParams[0], + prEventBwcsStatus->u.aucBTPParams[1], + prEventBwcsStatus->u.aucBTPParams[2], + prEventBwcsStatus->u.aucBTPParams[3]); + + printk(KERN_INFO DRV_NAME "BCM BWCS Event: aucBTPParams[0] = %02x, aucBTPParams[1] = %02x, aucBTPParams[2] = %02x, aucBTPParams[3] = %02x\n", + prEventBwcsStatus->u.aucBTPParams[0], + prEventBwcsStatus->u.aucBTPParams[1], + prEventBwcsStatus->u.aucBTPParams[2], + prEventBwcsStatus->u.aucBTPParams[3]); +#endif + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_BWCS_UPDATE, + (PVOID) prEventBwcsStatus, + sizeof(PTA_IPC_T)); + } + + break; + + case EVENT_ID_UPDATE_BCM_DEBUG: + { + P_PTA_IPC_T prEventBwcsStatus; + + prEventBwcsStatus = (P_PTA_IPC_T) (prEvent->aucBuffer); + +#if CFG_SUPPORT_BCM_BWCS_DEBUG + printk(KERN_INFO DRV_NAME "BCM FW status: %02x%02x%02x%02x\n", prEventBwcsStatus->u.aucBTPParams[0], + prEventBwcsStatus->u.aucBTPParams[1], + prEventBwcsStatus->u.aucBTPParams[2], + prEventBwcsStatus->u.aucBTPParams[3]); + + printk(KERN_INFO DRV_NAME "BCM FW status: aucBTPParams[0] = %02x, aucBTPParams[1] = %02x, aucBTPParams[2] = %02x, aucBTPParams[3] = %02x\n", + prEventBwcsStatus->u.aucBTPParams[0], + prEventBwcsStatus->u.aucBTPParams[1], + prEventBwcsStatus->u.aucBTPParams[2], + prEventBwcsStatus->u.aucBTPParams[3]); +#endif + } + + break; +#endif + + case EVENT_ID_ACCESS_REG: + case EVENT_ID_NIC_CAPABILITY: + case EVENT_ID_BASIC_CONFIG: + case EVENT_ID_MAC_MCAST_ADDR: + case EVENT_ID_ACCESS_EEPROM: + case EVENT_ID_TEST_STATUS: + default: + prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); + + if(prCmdInfo != NULL) { + if (prCmdInfo->pfCmdDoneHandler) { + prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prEvent->aucBuffer); + } + else if(prCmdInfo->fgIsOid) { + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_SUCCESS); + } + + // return prCmdInfo + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } + + break; + } + + nicRxReturnRFB(prAdapter, prSwRfb); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief nicRxProcessMgmtPacket is used to dispatch management frames +* to corresponding modules +* +* @param prAdapter Pointer to the Adapter structure. +* @param prSWRfb the RFB to receive rx data +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicRxProcessMgmtPacket ( + IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb + ) +{ + UINT_8 ucSubtype; +#if CFG_SUPPORT_802_11W + BOOL fgMfgDrop = FALSE; +#endif + ASSERT(prAdapter); + ASSERT(prSwRfb); + + nicRxFillRFB(prAdapter, prSwRfb); + + ucSubtype = (*(PUINT_8)(prSwRfb->pvHeader) & MASK_FC_SUBTYPE )>> OFFSET_OF_FC_SUBTYPE; + +#if CFG_RX_PKTS_DUMP + { + P_HIF_RX_HEADER_T prHifRxHdr; + UINT_16 u2TxFrameCtrl; + + prHifRxHdr = prSwRfb->prHifRxHdr; + u2TxFrameCtrl = (*(PUINT_8)(prSwRfb->pvHeader) & MASK_FRAME_TYPE); + if (prAdapter->rRxCtrl.u4RxPktsDumpTypeMask & BIT(HIF_RX_PKT_TYPE_MANAGEMENT)) { + if (u2TxFrameCtrl == MAC_FRAME_BEACON || + u2TxFrameCtrl == MAC_FRAME_PROBE_RSP) { + + DBGLOG(SW4, INFO, ("QM RX MGT: net %u sta idx %u wlan idx %u ssn %u ptype %u subtype %u 11 %u\n", + HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr), + prHifRxHdr->ucStaRecIdx, + prSwRfb->ucWlanIdx, + HIF_RX_HDR_GET_SN(prHifRxHdr), /* The new SN of the frame */ + prSwRfb->ucPacketType, + ucSubtype, + HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr))); + + DBGLOG_MEM8(SW4, TRACE, (PUINT_8)prSwRfb->pvHeader, prSwRfb->u2PacketLen); + } + } + } +#endif + + if(prAdapter->fgTestMode == FALSE) { +#if CFG_MGMT_FRAME_HANDLING +#if CFG_SUPPORT_802_11W + fgMfgDrop = rsnCheckRxMgmt(prAdapter, prSwRfb, ucSubtype); + if (fgMfgDrop) { + #if DBG + LOG_FUNC("QM RX MGT: Drop Unprotected Mgmt frame!!!\n"); + #endif + nicRxReturnRFB(prAdapter, prSwRfb); + RX_INC_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT); + return; + } + else +#endif + if(apfnProcessRxMgtFrame[ucSubtype]) { + switch(apfnProcessRxMgtFrame[ucSubtype](prAdapter, prSwRfb)){ + case WLAN_STATUS_PENDING: + return; + case WLAN_STATUS_SUCCESS: + case WLAN_STATUS_FAILURE: + break; + + default: + ASSERT(0); + break; + } + } +#endif + } + + nicRxReturnRFB(prAdapter, prSwRfb); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief nicProcessRFBs is used to process RFBs in the rReceivedRFBList queue. +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicRxProcessRFBs ( + IN P_ADAPTER_T prAdapter + ) +{ + P_RX_CTRL_T prRxCtrl; + P_SW_RFB_T prSwRfb = (P_SW_RFB_T)NULL; + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("nicRxProcessRFBs"); + + ASSERT(prAdapter); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + prRxCtrl->ucNumIndPacket = 0; + prRxCtrl->ucNumRetainedPacket = 0; + + do { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_REMOVE_HEAD(&prRxCtrl->rReceivedRfbList, prSwRfb, P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + + if (prSwRfb){ + switch(prSwRfb->ucPacketType){ + case HIF_RX_PKT_TYPE_DATA: + nicRxProcessDataPacket(prAdapter, prSwRfb); + break; + + case HIF_RX_PKT_TYPE_EVENT: + nicRxProcessEventPacket(prAdapter, prSwRfb); + break; + + case HIF_RX_PKT_TYPE_TX_LOOPBACK: + DBGLOG(RX, ERROR, ("ucPacketType = %d\n", prSwRfb->ucPacketType)); + break; + + case HIF_RX_PKT_TYPE_MANAGEMENT: + nicRxProcessMgmtPacket(prAdapter, prSwRfb); + break; + + default: + RX_INC_CNT(prRxCtrl, RX_TYPE_ERR_DROP_COUNT); + RX_INC_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT); + DBGLOG(RX, ERROR, ("ucPacketType = %d\n", prSwRfb->ucPacketType)); + break; + } + } + else { + break; + } + }while(TRUE); + + if (prRxCtrl->ucNumIndPacket > 0) { + RX_ADD_CNT(prRxCtrl, RX_DATA_INDICATION_COUNT, prRxCtrl->ucNumIndPacket); + RX_ADD_CNT(prRxCtrl, RX_DATA_RETAINED_COUNT, prRxCtrl->ucNumRetainedPacket); + + //DBGLOG(RX, INFO, ("%d packets indicated, Retained cnt = %d\n", + // prRxCtrl->ucNumIndPacket, prRxCtrl->ucNumRetainedPacket)); + #if CFG_NATIVE_802_11 + kalRxIndicatePkts(prAdapter->prGlueInfo, (UINT_32)prRxCtrl->ucNumIndPacket, (UINT_32)prRxCtrl->ucNumRetainedPacket); + #else + kalRxIndicatePkts(prAdapter->prGlueInfo, prRxCtrl->apvIndPacket, (UINT_32)prRxCtrl->ucNumIndPacket); + #endif + } + +} /* end of nicRxProcessRFBs() */ + + +#if !CFG_SDIO_INTR_ENHANCE +/*----------------------------------------------------------------------------*/ +/*! +* @brief Read the rx data from data port and setup RFB +* +* @param prAdapter pointer to the Adapter handler +* @param prSWRfb the RFB to receive rx data +* +* @retval WLAN_STATUS_SUCCESS: SUCCESS +* @retval WLAN_STATUS_FAILURE: FAILURE +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicRxReadBuffer ( + IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb + ) +{ + P_RX_CTRL_T prRxCtrl; + PUINT_8 pucBuf; + P_HIF_RX_HEADER_T prHifRxHdr; + UINT_32 u4PktLen = 0, u4ReadBytes; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + BOOL fgResult = TRUE; + UINT_32 u4RegValue; + UINT_32 rxNum; + + DEBUGFUNC("nicRxReadBuffer"); + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + pucBuf = prSwRfb->pucRecvBuff; + prHifRxHdr = prSwRfb->prHifRxHdr; + ASSERT(pucBuf); + DBGLOG(RX, TRACE, ("pucBuf= 0x%x, prHifRxHdr= 0x%x\n", pucBuf, prHifRxHdr)); + + do { + /* Read the RFB DW length and packet length */ + HAL_MCR_RD(prAdapter, MCR_WRPLR, &u4RegValue); + if (!fgResult) { + DBGLOG(RX, ERROR, ("Read RX Packet Lentgh Error\n")); + return WLAN_STATUS_FAILURE; + } + + //20091021 move the line to get the HIF RX header (for RX0/1) + if(u4RegValue == 0) { + DBGLOG(RX, ERROR, ("No RX packet\n")); + return WLAN_STATUS_FAILURE; + } + + u4PktLen = u4RegValue & BITS(0, 15); + if(u4PktLen != 0) { + rxNum = 0; + } + else { + rxNum = 1; + u4PktLen = (u4RegValue & BITS(16, 31)) >> 16; + } + + DBGLOG(RX, TRACE, ("RX%d: u4PktLen = %d\n", rxNum, u4PktLen)); + + //4 <4> Read Entire RFB and packet, include HW appended DW (Checksum Status) + u4ReadBytes = ALIGN_4(u4PktLen) + 4; + HAL_READ_RX_PORT(prAdapter, rxNum, u4ReadBytes, pucBuf, CFG_RX_MAX_PKT_SIZE); + + //20091021 move the line to get the HIF RX header + //u4PktLen = (UINT_32)prHifRxHdr->u2PacketLen; + if (u4PktLen != (UINT_32)prHifRxHdr->u2PacketLen) { + DBGLOG(RX, ERROR, ("Read u4PktLen = %d, prHifRxHdr->u2PacketLen: %d\n", + u4PktLen, prHifRxHdr->u2PacketLen)); + #if DBG + dumpMemory8((PUINT_8)prHifRxHdr, (prHifRxHdr->u2PacketLen > 4096) ? 4096 : prHifRxHdr->u2PacketLen); + #endif + ASSERT(0); + } + /* u4PktLen is byte unit, not inlude HW appended DW */ + + prSwRfb->ucPacketType = (UINT_8)(prHifRxHdr->u2PacketType & HIF_RX_HDR_PACKET_TYPE_MASK); + DBGLOG(RX, TRACE, ("ucPacketType = %d\n", prSwRfb->ucPacketType)); + + prSwRfb->ucStaRecIdx = (UINT_8)(prHifRxHdr->ucStaRecIdx); + + /* fgResult will be updated in MACRO */ + if (!fgResult) { + return WLAN_STATUS_FAILURE; + } + + DBGLOG(RX, TRACE, ("Dump RX buffer, length = 0x%x\n", u4ReadBytes)); + DBGLOG_MEM8(RX, TRACE, pucBuf, u4ReadBytes); + }while(FALSE); + + return u4Status; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Read frames from the data port, fill RFB +* and put each frame into the rReceivedRFBList queue. +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicRxReceiveRFBs ( + IN P_ADAPTER_T prAdapter + ) +{ + P_RX_CTRL_T prRxCtrl; + P_SW_RFB_T prSwRfb = (P_SW_RFB_T)NULL; + P_HIF_RX_HEADER_T prHifRxHdr; + + UINT_32 u4HwAppendDW; + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("nicRxReceiveRFBs"); + + ASSERT(prAdapter); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + do { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfb, P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + + if (!prSwRfb) { + DBGLOG(RX, TRACE, ("No More RFB\n")); + break; + } + + // need to consider + if (nicRxReadBuffer(prAdapter, prSwRfb) == WLAN_STATUS_FAILURE) { + DBGLOG(RX, TRACE, ("halRxFillRFB failed\n")); + nicRxReturnRFB(prAdapter, prSwRfb); + break; + } + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_INSERT_TAIL(&prRxCtrl->rReceivedRfbList, &prSwRfb->rQueEntry); + RX_INC_CNT(prRxCtrl, RX_MPDU_TOTAL_COUNT); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + + prHifRxHdr = prSwRfb->prHifRxHdr; + u4HwAppendDW = *((PUINT_32)((UINT_32)prHifRxHdr + + (UINT_32)(ALIGN_4(prHifRxHdr->u2PacketLen)))); + DBGLOG(RX, TRACE, ("u4HwAppendDW = 0x%x\n", u4HwAppendDW)); + DBGLOG(RX, TRACE, ("u2PacketLen = 0x%x\n", prHifRxHdr->u2PacketLen)); + } +// while (RX_STATUS_TEST_MORE_FLAG(u4HwAppendDW)); + while (FALSE); + + return; + +} /* end of nicReceiveRFBs() */ + +#else +/*----------------------------------------------------------------------------*/ +/*! +* @brief Read frames from the data port, fill RFB +* and put each frame into the rReceivedRFBList queue. +* +* @param prAdapter Pointer to the Adapter structure. +* @param u4DataPort Specify which port to read +* @param u2RxLength Specify to the the rx packet length in Byte. +* @param prSwRfb the RFB to receive rx data. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ + +WLAN_STATUS +nicRxEnhanceReadBuffer ( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4DataPort, + IN UINT_16 u2RxLength, + IN OUT P_SW_RFB_T prSwRfb + ) +{ + P_RX_CTRL_T prRxCtrl; + PUINT_8 pucBuf; + P_HIF_RX_HEADER_T prHifRxHdr; + UINT_32 u4PktLen = 0; + WLAN_STATUS u4Status = WLAN_STATUS_FAILURE; + BOOL fgResult = TRUE; + + DEBUGFUNC("nicRxEnhanceReadBuffer"); + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + pucBuf = prSwRfb->pucRecvBuff; + ASSERT(pucBuf); + + prHifRxHdr = prSwRfb->prHifRxHdr; + ASSERT(prHifRxHdr); + + //DBGLOG(RX, TRACE, ("u2RxLength = %d\n", u2RxLength)); + + do { + //4 <1> Read RFB frame from MCR_WRDR0, include HW appended DW + HAL_READ_RX_PORT(prAdapter, + u4DataPort, + ALIGN_4(u2RxLength + HIF_RX_HW_APPENDED_LEN), + pucBuf, + CFG_RX_MAX_PKT_SIZE); + + if (!fgResult) { + DBGLOG(RX, ERROR, ("Read RX Packet Lentgh Error\n")); + break; + } + + u4PktLen = (UINT_32)(prHifRxHdr->u2PacketLen); + //DBGLOG(RX, TRACE, ("u4PktLen = %d\n", u4PktLen)); + + prSwRfb->ucPacketType = (UINT_8)(prHifRxHdr->u2PacketType & HIF_RX_HDR_PACKET_TYPE_MASK); + //DBGLOG(RX, TRACE, ("ucPacketType = %d\n", prSwRfb->ucPacketType)); + + prSwRfb->ucStaRecIdx = (UINT_8)(prHifRxHdr->ucStaRecIdx); + + //4 <2> if the RFB dw size or packet size is zero + if (u4PktLen == 0) { + DBGLOG(RX, ERROR, ("Packet Length = %d\n", u4PktLen)); + ASSERT(0); + break; + } + + //4 <3> if the packet is too large or too small + if (u4PktLen > CFG_RX_MAX_PKT_SIZE) { + DBGLOG(RX, TRACE, ("Read RX Packet Lentgh Error (%d)\n", u4PktLen)); + ASSERT(0); + break; + } + + u4Status = WLAN_STATUS_SUCCESS; + } + while (FALSE); + + DBGLOG_MEM8(RX, TRACE, pucBuf, ALIGN_4(u2RxLength + HIF_RX_HW_APPENDED_LEN)); + return u4Status; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Read frames from the data port for SDIO +* I/F, fill RFB and put each frame into the rReceivedRFBList queue. +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicRxSDIOReceiveRFBs ( + IN P_ADAPTER_T prAdapter + ) +{ + P_SDIO_CTRL_T prSDIOCtrl; + P_RX_CTRL_T prRxCtrl; + P_SW_RFB_T prSwRfb = (P_SW_RFB_T)NULL; + UINT_32 i, rxNum; + UINT_16 u2RxPktNum, u2RxLength = 0, u2Tmp = 0; + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("nicRxSDIOReceiveRFBs"); + + ASSERT(prAdapter); + + prSDIOCtrl = prAdapter->prSDIOCtrl; + ASSERT(prSDIOCtrl); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + for (rxNum = 0 ; rxNum < 2 ; rxNum++) { + u2RxPktNum = (rxNum == 0 ? prSDIOCtrl->rRxInfo.u.u2NumValidRx0Len : prSDIOCtrl->rRxInfo.u.u2NumValidRx1Len); + + if(u2RxPktNum == 0) { + continue; + } + + for (i = 0; i < u2RxPktNum; i++) { + if(rxNum == 0) { + HAL_READ_RX_LENGTH(prAdapter, &u2RxLength, &u2Tmp); + } + else if(rxNum == 1) { + HAL_READ_RX_LENGTH(prAdapter, &u2Tmp, &u2RxLength); + } + + if (!u2RxLength) { + break; + } + + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfb, P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + + if (!prSwRfb) { + DBGLOG(RX, TRACE, ("No More RFB\n")); + break; + } + ASSERT(prSwRfb); + + if (nicRxEnhanceReadBuffer(prAdapter, rxNum, u2RxLength, prSwRfb) == WLAN_STATUS_FAILURE) { + DBGLOG(RX, TRACE, ("nicRxEnhanceRxReadBuffer failed\n")); + nicRxReturnRFB(prAdapter, prSwRfb); + break; + } + + //prSDIOCtrl->au4RxLength[i] = 0; + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_INSERT_TAIL(&prRxCtrl->rReceivedRfbList, &prSwRfb->rQueEntry); + RX_INC_CNT(prRxCtrl, RX_MPDU_TOTAL_COUNT); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + } + } + + prSDIOCtrl->rRxInfo.u.u2NumValidRx0Len = 0; + prSDIOCtrl->rRxInfo.u.u2NumValidRx1Len = 0; + + return; +}/* end of nicRxSDIOReceiveRFBs() */ + +#endif /* CFG_SDIO_INTR_ENHANCE */ + + + +#if CFG_SDIO_RX_AGG +/*----------------------------------------------------------------------------*/ +/*! +* @brief Read frames from the data port for SDIO with Rx aggregation enabled +* I/F, fill RFB and put each frame into the rReceivedRFBList queue. +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicRxSDIOAggReceiveRFBs ( + IN P_ADAPTER_T prAdapter + ) +{ + P_ENHANCE_MODE_DATA_STRUCT_T prEnhDataStr; + P_RX_CTRL_T prRxCtrl; + P_SDIO_CTRL_T prSDIOCtrl; + P_SW_RFB_T prSwRfb = (P_SW_RFB_T)NULL; + UINT_32 u4RxLength; + UINT_32 i, rxNum; + UINT_32 u4RxAggCount = 0, u4RxAggLength = 0; + UINT_32 u4RxAvailAggLen, u4CurrAvailFreeRfbCnt; + PUINT_8 pucSrcAddr; + P_HIF_RX_HEADER_T prHifRxHdr; + BOOL fgResult = TRUE; + BOOLEAN fgIsRxEnhanceMode; + UINT_16 u2RxPktNum; +#if CFG_SDIO_RX_ENHANCE + UINT_32 u4MaxLoopCount = CFG_MAX_RX_ENHANCE_LOOP_COUNT; +#endif + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("nicRxSDIOAggReceiveRFBs"); + + ASSERT(prAdapter); + prEnhDataStr = prAdapter->prSDIOCtrl; + prRxCtrl = &prAdapter->rRxCtrl; + prSDIOCtrl = prAdapter->prSDIOCtrl; + +#if CFG_SDIO_RX_ENHANCE + fgIsRxEnhanceMode = TRUE; +#else + fgIsRxEnhanceMode = FALSE; +#endif + + do { +#if CFG_SDIO_RX_ENHANCE + /* to limit maximum loop for RX */ + u4MaxLoopCount--; + if (u4MaxLoopCount == 0) { + break; + } +#endif + + if(prEnhDataStr->rRxInfo.u.u2NumValidRx0Len == 0 && + prEnhDataStr->rRxInfo.u.u2NumValidRx1Len == 0) { + break; + } + + for(rxNum = 0 ; rxNum < 2 ; rxNum++) { + u2RxPktNum = (rxNum == 0 ? prEnhDataStr->rRxInfo.u.u2NumValidRx0Len : prEnhDataStr->rRxInfo.u.u2NumValidRx1Len); + + // if this assertion happened, it is most likely a F/W bug + ASSERT(u2RxPktNum <= 16); + + if (u2RxPktNum > 16) + continue; + + if(u2RxPktNum == 0) + continue; + + #if CFG_HIF_STATISTICS + prRxCtrl->u4TotalRxAccessNum++; + prRxCtrl->u4TotalRxPacketNum += u2RxPktNum; + #endif + + u4CurrAvailFreeRfbCnt = prRxCtrl->rFreeSwRfbList.u4NumElem; + + // if SwRfb is not enough, abort reading this time + if(u4CurrAvailFreeRfbCnt < u2RxPktNum) { + #if CFG_HIF_RX_STARVATION_WARNING + DbgPrint("FreeRfb is not enough: %d available, need %d\n", u4CurrAvailFreeRfbCnt, u2RxPktNum); + DbgPrint("Queued Count: %d / Dequeud Count: %d\n", prRxCtrl->u4QueuedCnt, prRxCtrl->u4DequeuedCnt); + #endif + continue; + } + +#if CFG_SDIO_RX_ENHANCE + u4RxAvailAggLen = CFG_RX_COALESCING_BUFFER_SIZE - (sizeof(ENHANCE_MODE_DATA_STRUCT_T) + 4/* extra HW padding */); +#else + u4RxAvailAggLen = CFG_RX_COALESCING_BUFFER_SIZE; +#endif + u4RxAggCount = 0; + + for (i = 0; i < u2RxPktNum ; i++) { + u4RxLength = (rxNum == 0 ? + (UINT_32)prEnhDataStr->rRxInfo.u.au2Rx0Len[i] : + (UINT_32)prEnhDataStr->rRxInfo.u.au2Rx1Len[i]); + + if (!u4RxLength) { + ASSERT(0); + break; + } + + if (ALIGN_4(u4RxLength + HIF_RX_HW_APPENDED_LEN) < u4RxAvailAggLen) { + if (u4RxAggCount < u4CurrAvailFreeRfbCnt) { + u4RxAvailAggLen -= ALIGN_4(u4RxLength + HIF_RX_HW_APPENDED_LEN); + u4RxAggCount++; + } + else { + // no FreeSwRfb for rx packet + ASSERT(0); + break; + } + } + else { + // CFG_RX_COALESCING_BUFFER_SIZE is not large enough + ASSERT(0); + break; + } + } + + u4RxAggLength = (CFG_RX_COALESCING_BUFFER_SIZE - u4RxAvailAggLen); + //DBGLOG(RX, INFO, ("u4RxAggCount = %d, u4RxAggLength = %d\n", + // u4RxAggCount, u4RxAggLength)); + + HAL_READ_RX_PORT(prAdapter, + rxNum, + u4RxAggLength, + prRxCtrl->pucRxCoalescingBufPtr, + CFG_RX_COALESCING_BUFFER_SIZE); + if (!fgResult) { + DBGLOG(RX, ERROR, ("Read RX Agg Packet Error\n")); + continue; + } + + pucSrcAddr = prRxCtrl->pucRxCoalescingBufPtr; + for (i = 0; i < u4RxAggCount; i++) { + UINT_16 u2PktLength; + + u2PktLength = (rxNum == 0 ? + prEnhDataStr->rRxInfo.u.au2Rx0Len[i] : + prEnhDataStr->rRxInfo.u.au2Rx1Len[i]); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfb, P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + + ASSERT(prSwRfb); + kalMemCopy(prSwRfb->pucRecvBuff, pucSrcAddr, + ALIGN_4(u2PktLength + HIF_RX_HW_APPENDED_LEN)); + + prHifRxHdr = prSwRfb->prHifRxHdr; + ASSERT(prHifRxHdr); + + prSwRfb->ucPacketType = (UINT_8)(prHifRxHdr->u2PacketType & HIF_RX_HDR_PACKET_TYPE_MASK); + //DBGLOG(RX, TRACE, ("ucPacketType = %d\n", prSwRfb->ucPacketType)); + + prSwRfb->ucStaRecIdx = (UINT_8)(prHifRxHdr->ucStaRecIdx); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_INSERT_TAIL(&prRxCtrl->rReceivedRfbList, &prSwRfb->rQueEntry); + RX_INC_CNT(prRxCtrl, RX_MPDU_TOTAL_COUNT); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + + pucSrcAddr += ALIGN_4(u2PktLength + HIF_RX_HW_APPENDED_LEN); + //prEnhDataStr->au4RxLength[i] = 0; + } + +#if CFG_SDIO_RX_ENHANCE + kalMemCopy(prAdapter->prSDIOCtrl, (pucSrcAddr + 4), sizeof(ENHANCE_MODE_DATA_STRUCT_T)); + + /* do the same thing what nicSDIOReadIntStatus() does */ + if((prSDIOCtrl->u4WHISR & WHISR_TX_DONE_INT) == 0 && + (prSDIOCtrl->rTxInfo.au4WTSR[0] | prSDIOCtrl->rTxInfo.au4WTSR[1])) { + prSDIOCtrl->u4WHISR |= WHISR_TX_DONE_INT; + } + + if((prSDIOCtrl->u4WHISR & BIT(31)) == 0 && + HAL_GET_MAILBOX_READ_CLEAR(prAdapter) == TRUE && + (prSDIOCtrl->u4RcvMailbox0 != 0 || prSDIOCtrl->u4RcvMailbox1 != 0)) { + prSDIOCtrl->u4WHISR |= BIT(31); + } + + /* dispatch to interrupt handler with RX bits masked */ + nicProcessIST_impl(prAdapter, prSDIOCtrl->u4WHISR & (~(WHISR_RX0_DONE_INT | WHISR_RX1_DONE_INT))); +#endif + } + +#if !CFG_SDIO_RX_ENHANCE + prEnhDataStr->rRxInfo.u.u2NumValidRx0Len = 0; + prEnhDataStr->rRxInfo.u.u2NumValidRx1Len = 0; +#endif + } + while ((prEnhDataStr->rRxInfo.u.u2NumValidRx0Len + || prEnhDataStr->rRxInfo.u.u2NumValidRx1Len) + && fgIsRxEnhanceMode); + + return; +} +#endif /* CFG_SDIO_RX_AGG */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Setup a RFB and allocate the os packet to the RFB +* +* @param prAdapter Pointer to the Adapter structure. +* @param prSwRfb Pointer to the RFB +* +* @retval WLAN_STATUS_SUCCESS +* @retval WLAN_STATUS_RESOURCES +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicRxSetupRFB ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ) +{ + PVOID pvPacket; + PUINT_8 pucRecvBuff; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + if (!prSwRfb->pvPacket) { + kalMemZero(prSwRfb, sizeof(SW_RFB_T)); + pvPacket = kalPacketAlloc(prAdapter->prGlueInfo, CFG_RX_MAX_PKT_SIZE, + &pucRecvBuff); + if (pvPacket == NULL) { + return WLAN_STATUS_RESOURCES; + } + + prSwRfb->pvPacket = pvPacket; + prSwRfb->pucRecvBuff= (PVOID)pucRecvBuff; + } + else { + kalMemZero(((PUINT_8)prSwRfb + OFFSET_OF(SW_RFB_T, prHifRxHdr)), + (sizeof(SW_RFB_T)-OFFSET_OF(SW_RFB_T, prHifRxHdr))); + } + + prSwRfb->prHifRxHdr = (P_HIF_RX_HEADER_T)(prSwRfb->pucRecvBuff); + + return WLAN_STATUS_SUCCESS; + +} /* end of nicRxSetupRFB() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This routine is called to put a RFB back onto the "RFB with Buffer" list +* or "RFB without buffer" list according to pvPacket. +* +* @param prAdapter Pointer to the Adapter structure. +* @param prSwRfb Pointer to the RFB +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicRxReturnRFB ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ) +{ + P_RX_CTRL_T prRxCtrl; + P_QUE_ENTRY_T prQueEntry; + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + ASSERT(prSwRfb); + prRxCtrl = &prAdapter->rRxCtrl; + prQueEntry = &prSwRfb->rQueEntry; + + ASSERT(prQueEntry); + + /* The processing on this RFB is done, so put it back on the tail of + our list */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + + if (prSwRfb->pvPacket) { + QUEUE_INSERT_TAIL(&prRxCtrl->rFreeSwRfbList, prQueEntry); + } + else { + QUEUE_INSERT_TAIL(&prRxCtrl->rIndicatedRfbList, prQueEntry); + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + return; +} /* end of nicRxReturnRFB() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process rx interrupt. When the rx +* Interrupt is asserted, it means there are frames in queue. +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicProcessRxInterrupt ( + IN P_ADAPTER_T prAdapter + ) +{ + ASSERT(prAdapter); + +#if CFG_SDIO_INTR_ENHANCE + #if CFG_SDIO_RX_AGG + nicRxSDIOAggReceiveRFBs(prAdapter); + #else + nicRxSDIOReceiveRFBs(prAdapter); + #endif +#else + nicRxReceiveRFBs(prAdapter); +#endif /* CFG_SDIO_INTR_ENHANCE */ + + nicRxProcessRFBs(prAdapter); + + return; + +} /* end of nicProcessRxInterrupt() */ + + +#if CFG_TCP_IP_CHKSUM_OFFLOAD +/*----------------------------------------------------------------------------*/ +/*! +* @brief Used to update IP/TCP/UDP checksum statistics of RX Module. +* +* @param prAdapter Pointer to the Adapter structure. +* @param aeCSUM The array of checksum result. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicRxUpdateCSUMStatistics ( + IN P_ADAPTER_T prAdapter, + IN const ENUM_CSUM_RESULT_T aeCSUM[] + ) +{ + P_RX_CTRL_T prRxCtrl; + + ASSERT(prAdapter); + ASSERT(aeCSUM); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + if ((aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_SUCCESS) || + (aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_SUCCESS)) { + + RX_INC_CNT(prRxCtrl, RX_CSUM_IP_SUCCESS_COUNT); + } + else if ((aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_FAILED) || + (aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_FAILED)) { + + RX_INC_CNT(prRxCtrl, RX_CSUM_IP_FAILED_COUNT); + } + else if ((aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_NONE) && + (aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_NONE)) { + + RX_INC_CNT(prRxCtrl, RX_CSUM_UNKNOWN_L3_PKT_COUNT); + } + else { + ASSERT(0); + } + + if (aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_SUCCESS) { + RX_INC_CNT(prRxCtrl, RX_CSUM_TCP_SUCCESS_COUNT); + } + else if (aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_FAILED) { + RX_INC_CNT(prRxCtrl, RX_CSUM_TCP_FAILED_COUNT); + } + else if (aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_SUCCESS) { + RX_INC_CNT(prRxCtrl, RX_CSUM_UDP_SUCCESS_COUNT); + } + else if (aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_FAILED) { + RX_INC_CNT(prRxCtrl, RX_CSUM_UDP_FAILED_COUNT); + } + else if ((aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_NONE) && + (aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_NONE)) { + + RX_INC_CNT(prRxCtrl, RX_CSUM_UNKNOWN_L4_PKT_COUNT); + } + else { + ASSERT(0); + } + + return; +} /* end of nicRxUpdateCSUMStatistics() */ +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to query current status of RX Module. +* +* @param prAdapter Pointer to the Adapter structure. +* @param pucBuffer Pointer to the message buffer. +* @param pu4Count Pointer to the buffer of message length count. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicRxQueryStatus ( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucBuffer, + OUT PUINT_32 pu4Count + ) +{ + P_RX_CTRL_T prRxCtrl; + PUINT_8 pucCurrBuf = pucBuffer; + + + ASSERT(prAdapter); + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + //if (pucBuffer) {} /* For Windows, we'll print directly instead of sprintf() */ + ASSERT(pu4Count); + + SPRINTF(pucCurrBuf, ("\n\nRX CTRL STATUS:")); + SPRINTF(pucCurrBuf, ("\n===============")); + SPRINTF(pucCurrBuf, ("\nFREE RFB w/i BUF LIST :%9ld", prRxCtrl->rFreeSwRfbList.u4NumElem)); + SPRINTF(pucCurrBuf, ("\nFREE RFB w/o BUF LIST :%9ld", prRxCtrl->rIndicatedRfbList.u4NumElem)); + SPRINTF(pucCurrBuf, ("\nRECEIVED RFB LIST :%9ld", prRxCtrl->rReceivedRfbList.u4NumElem)); + + SPRINTF(pucCurrBuf, ("\n\n")); + + //*pu4Count = (UINT_32)((UINT_32)pucCurrBuf - (UINT_32)pucBuffer); + + return; +} /* end of nicRxQueryStatus() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Clear RX related counters +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return - (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicRxClearStatistics ( + IN P_ADAPTER_T prAdapter + ) +{ + P_RX_CTRL_T prRxCtrl; + + ASSERT(prAdapter); + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + RX_RESET_ALL_CNTS(prRxCtrl); + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to query current statistics of RX Module. +* +* @param prAdapter Pointer to the Adapter structure. +* @param pucBuffer Pointer to the message buffer. +* @param pu4Count Pointer to the buffer of message length count. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicRxQueryStatistics ( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucBuffer, + OUT PUINT_32 pu4Count + ) +{ + P_RX_CTRL_T prRxCtrl; + PUINT_8 pucCurrBuf = pucBuffer; + + ASSERT(prAdapter); + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + //if (pucBuffer) {} /* For Windows, we'll print directly instead of sprintf() */ + ASSERT(pu4Count); + +#define SPRINTF_RX_COUNTER(eCounter) \ + SPRINTF(pucCurrBuf, ("%-30s : %ld\n", #eCounter, (UINT_32)prRxCtrl->au8Statistics[eCounter])) + + SPRINTF_RX_COUNTER(RX_MPDU_TOTAL_COUNT); + SPRINTF_RX_COUNTER(RX_SIZE_ERR_DROP_COUNT); + SPRINTF_RX_COUNTER(RX_DATA_INDICATION_COUNT); + SPRINTF_RX_COUNTER(RX_DATA_RETURNED_COUNT); + SPRINTF_RX_COUNTER(RX_DATA_RETAINED_COUNT); + +#if CFG_TCP_IP_CHKSUM_OFFLOAD || CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 + SPRINTF_RX_COUNTER(RX_CSUM_TCP_FAILED_COUNT); + SPRINTF_RX_COUNTER(RX_CSUM_UDP_FAILED_COUNT); + SPRINTF_RX_COUNTER(RX_CSUM_IP_FAILED_COUNT); + SPRINTF_RX_COUNTER(RX_CSUM_TCP_SUCCESS_COUNT); + SPRINTF_RX_COUNTER(RX_CSUM_UDP_SUCCESS_COUNT); + SPRINTF_RX_COUNTER(RX_CSUM_IP_SUCCESS_COUNT); + SPRINTF_RX_COUNTER(RX_CSUM_UNKNOWN_L4_PKT_COUNT); + SPRINTF_RX_COUNTER(RX_CSUM_UNKNOWN_L3_PKT_COUNT); + SPRINTF_RX_COUNTER(RX_IP_V6_PKT_CCOUNT); +#endif + + //*pu4Count = (UINT_32)(pucCurrBuf - pucBuffer); + + nicRxClearStatistics(prAdapter); + + return; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Read the Response data from data port +* +* @param prAdapter pointer to the Adapter handler +* @param pucRspBuffer pointer to the Response buffer +* +* @retval WLAN_STATUS_SUCCESS: Response packet has been read +* @retval WLAN_STATUS_FAILURE: Read Response packet timeout or error occurred +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicRxWaitResponse ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucPortIdx, + OUT PUINT_8 pucRspBuffer, + IN UINT_32 u4MaxRespBufferLen, + OUT PUINT_32 pu4Length + ) +{ + UINT_32 u4Value = 0, u4PktLen = 0, i = 0; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + BOOL fgResult = TRUE; + UINT_32 u4Time, u4Current; + + DEBUGFUNC("nicRxWaitResponse"); + + ASSERT(prAdapter); + ASSERT(pucRspBuffer); + ASSERT(ucPortIdx < 2); + + u4Time = (UINT_32)kalGetTimeTick(); + + do { + /* Read the packet length */ + HAL_MCR_RD(prAdapter, MCR_WRPLR, &u4Value); + + if (!fgResult) { + DBGLOG(RX, ERROR, ("Read Response Packet Error\n")); + return WLAN_STATUS_FAILURE; + } + + if(ucPortIdx == 0) { + u4PktLen = u4Value & 0xFFFF; + } + else { + u4PktLen = (u4Value >> 16) & 0xFFFF; + } + + DBGLOG(RX, TRACE, ("i = %d, u4PktLen = %d\n", i, u4PktLen)); + + if (u4PktLen == 0) { + /* timeout exceeding check */ + u4Current = (UINT_32)kalGetTimeTick(); + + if((u4Current > u4Time) && ((u4Current - u4Time) > RX_RESPONSE_TIMEOUT)) { + return WLAN_STATUS_FAILURE; + } + else if(u4Current < u4Time && ((u4Current + (0xFFFFFFFF - u4Time)) > RX_RESPONSE_TIMEOUT)) { + return WLAN_STATUS_FAILURE; + } + + /* Response packet is not ready */ + kalUdelay(50); + + i++; + } + else if (u4PktLen > u4MaxRespBufferLen) { + DBGLOG(RX, WARN, ("Not enough Event Buffer: required length = 0x%x, available buffer length = %d\n", + u4PktLen, u4MaxRespBufferLen)); + + return WLAN_STATUS_FAILURE; + } + else { + HAL_PORT_RD(prAdapter, + ucPortIdx == 0 ? MCR_WRDR0 : MCR_WRDR1, + u4PktLen, + pucRspBuffer, + u4MaxRespBufferLen); + + /* fgResult will be updated in MACRO */ + if (!fgResult) { + DBGLOG(RX, ERROR, ("Read Response Packet Error\n")); + return WLAN_STATUS_FAILURE; + } + + DBGLOG(RX, TRACE, ("Dump Response buffer, length = 0x%x\n", + u4PktLen)); + DBGLOG_MEM8(RX, TRACE, pucRspBuffer, u4PktLen); + + *pu4Length = u4PktLen; + break; + } + } while(TRUE); + + return u4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Set filter to enable Promiscuous Mode +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicRxEnablePromiscuousMode ( + IN P_ADAPTER_T prAdapter + ) +{ + ASSERT(prAdapter); + + return; +} /* end of nicRxEnablePromiscuousMode() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Set filter to disable Promiscuous Mode +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicRxDisablePromiscuousMode ( + IN P_ADAPTER_T prAdapter + ) +{ + ASSERT(prAdapter); + + return; +} /* end of nicRxDisablePromiscuousMode() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief this function flushes all packets queued in reordering module +* +* @param prAdapter Pointer to the Adapter structure. +* +* @retval WLAN_STATUS_SUCCESS Flushed successfully +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicRxFlush ( + IN P_ADAPTER_T prAdapter + ) +{ + P_SW_RFB_T prSwRfb; + + ASSERT(prAdapter); + + if((prSwRfb = qmFlushRxQueues(prAdapter)) != NULL) { + do { + P_SW_RFB_T prNextSwRfb; + + // save next first + prNextSwRfb = (P_SW_RFB_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prSwRfb); + + // free + nicRxReturnRFB(prAdapter, prSwRfb); + + prSwRfb = prNextSwRfb; + } while(prSwRfb); + } + + return WLAN_STATUS_SUCCESS; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param +* +* @retval +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicRxProcessActionFrame ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb + ) +{ + P_WLAN_ACTION_FRAME prActFrame; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + if (prSwRfb->u2PacketLen < sizeof(WLAN_ACTION_FRAME) - 1) { + return WLAN_STATUS_INVALID_PACKET; + } + prActFrame = (P_WLAN_ACTION_FRAME) prSwRfb->pvHeader; + + switch (prActFrame->ucCategory) { + case CATEGORY_PUBLIC_ACTION: + + #if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered) { + ASSERT(prAdapter->rP2pFuncLkr.prRlmProcessPublicAction); + if (prAdapter->rP2pFuncLkr.prRlmProcessPublicAction) { + prAdapter->rP2pFuncLkr.prRlmProcessPublicAction( + prAdapter, prSwRfb); + } + + ASSERT(prAdapter->rP2pFuncLkr.prP2pRxPublicActionFrame); + if (prAdapter->rP2pFuncLkr.prP2pRxPublicActionFrame) { + prAdapter->rP2pFuncLkr.prP2pRxPublicActionFrame( + prAdapter, prSwRfb); + } + } + #endif + break; + + case CATEGORY_HT_ACTION: + #if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered) { + ASSERT(prAdapter->rP2pFuncLkr.prRlmProcessHtAction); + if (prAdapter->rP2pFuncLkr.prRlmProcessHtAction) { + prAdapter->rP2pFuncLkr.prRlmProcessHtAction( + prAdapter, prSwRfb); + } + } + #endif + break; + case CATEGORY_VENDOR_SPECIFIC_ACTION: + #if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered) { + ASSERT(prAdapter->rP2pFuncLkr.prP2pRxActionFrame); + if (prAdapter->rP2pFuncLkr.prP2pRxActionFrame) { + + prAdapter->rP2pFuncLkr.prP2pRxActionFrame(prAdapter, prSwRfb); + } + } + + #endif + break; +#if CFG_SUPPORT_802_11W + case CATEGORY_SA_QUERT_ACTION: + { + P_HIF_RX_HEADER_T prHifRxHdr; + + prHifRxHdr = prSwRfb->prHifRxHdr; + + if ((HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr) == NETWORK_TYPE_AIS_INDEX) && + prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection /* Use MFP */ + ) { + if (!(prHifRxHdr->ucReserved & CONTROL_FLAG_UC_MGMT_NO_ENC)) { + /* MFP test plan 5.3.3.4 */ + rsnSaQueryAction(prAdapter, prSwRfb); + } + else { + DBGLOG(RSN, TRACE, ("Un-Protected SA Query, do nothing\n")); + } + } + } + break; +#endif + default: + break; + } /* end of switch case */ + + return WLAN_STATUS_SUCCESS; +} + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/nic/nic_tx.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/nic/nic_tx.c new file mode 100755 index 000000000000..06fcde225e3d --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/nic/nic_tx.c @@ -0,0 +1,2020 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/nic/nic_tx.c#1 $ +*/ + +/*! \file nic_tx.c + \brief Functions that provide TX operation in NIC Layer. + + This file provides TX functions which are responsible for both Hardware and + Software Resource Management and keep their Synchronization. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: nic_tx.c $ + * + * 03 26 2012 yuche.tsai + * [ALPS00255551] [WiFi direct][Google Issue]GC can't send picture to GO sometimes,GO and GC can't ping each other + * Avoid ran out of driver resource when starting GO. + * + * 11 19 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Add xlog for tx + * + * 11 09 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Add xlog for beacon timeout and sta aging timeout. + * + * 11 08 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Add xlog function. + * + * 05 17 2011 cp.wu + * [WCXRP00000732] [MT6620 Wi-Fi][AIS] No need to switch back to IDLE state when DEAUTH frame is dropped due to bss disconnection + * when TX DONE status is TX_RESULT_DROPPED_IN_DRIVER, no need to switch back to IDLE state. + * + * 04 12 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix the sta index in processing security frame + * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 + * Add debug message. + * + * 04 12 2011 cp.wu + * [WCXRP00000631] [MT6620 Wi-Fi][Driver] Add an API for QM to retrieve current TC counter value and processing frame dropping cases for TC4 path + * remove unused variables. + * + * 04 12 2011 cp.wu + * [WCXRP00000631] [MT6620 Wi-Fi][Driver] Add an API for QM to retrieve current TC counter value and processing frame dropping cases for TC4 path + * 1. add nicTxGetResource() API for QM to make decisions. + * 2. if management frames is decided by QM for dropping, the call back is invoked to indicate such a case. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 17 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage after system running for a long period + * use pre-allocated buffer for storing enhanced interrupt response as well + * + * 03 15 2011 cp.wu + * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous memory consumption + * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK + * 2. Use common coalescing buffer for both TX/RX directions + * + * + * 02 16 2011 cp.wu + * [WCXRP00000449] [MT6620 Wi-Fi][Driver] Refine CMD queue handling by adding an extra API for checking availble count and modify behavior + * 1. add new API: nicTxGetFreeCmdCount() + * 2. when there is insufficient command descriptor, nicTxEnqueueMsdu() will drop command packets directly + * + * 01 24 2011 cp.wu + * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving + * 1. add an extra counter for tracking pending forward frames. + * 2. notify TX service thread as well when there is pending forward frame + * 3. correct build errors leaded by introduction of Wi-Fi direct separation module + * + * 01 12 2011 cp.wu + * [WCXRP00000356] [MT6620 Wi-Fi][Driver] fill mac header length for security frames 'cause hardware header translation needs such information + * fill mac header length information for 802.1x frames. + * + * 12 31 2010 cp.wu + * [WCXRP00000335] [MT6620 Wi-Fi][Driver] change to use milliseconds sleep instead of delay to avoid blocking to system scheduling + * change to use msleep() and shorten waiting interval to reduce blocking to other task while Wi-Fi driver is being loaded + * + * 11 01 2010 yarco.yang + * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform + * Add GPIO debug function + * + * 10 18 2010 cp.wu + * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore + * 1. when wlanAdapterStop() failed to send POWER CTRL command to firmware, do not poll for ready bit dis-assertion + * 2. shorten polling count for shorter response time + * 3. if bad I/O operation is detected during TX resource polling, then further operation is aborted as well + * + * 10 06 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * code reorganization to improve isolation between GLUE and CORE layers. + * + * 09 29 2010 wh.su + * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue + * [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue. + * + * 09 27 2010 wh.su + * NULL + * since the u2TxByteCount_UserPriority will or another setting, keep the overall buffer for avoid error + * + * 09 24 2010 wh.su + * NULL + * [WCXRP000000058][MT6620 Wi-Fi][Driver] Fail to handshake with WAPI AP due the 802.1x frame send to fw with extra bytes padding. + * + * 09 01 2010 cp.wu + * NULL + * HIFSYS Clock Source Workaround + * + * 08 30 2010 cp.wu + * NULL + * API added: nicTxPendingPackets(), for simplifying porting layer + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 20 2010 wh.su + * NULL + * adding the eapol callback setting. + * + * 08 18 2010 yarco.yang + * NULL + * 1. Fixed HW checksum offload function not work under Linux issue. + * 2. Add debug message. + * + * 08 05 2010 yuche.tsai + * NULL + * . + * + * 08 03 2010 cp.wu + * NULL + * surpress compilation warning. + * + * 08 02 2010 jeffrey.chang + * NULL + * 1) modify tx service thread to avoid busy looping + * 2) add spin lock declartion for linux build + * + * 07 29 2010 cp.wu + * NULL + * simplify post-handling after TX_DONE interrupt is handled. + * + * 07 19 2010 jeffrey.chang + * + * Linux port modification + * + * 07 13 2010 cp.wu + * + * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets + * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending + * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid descriptor underflow under concurrent network operation + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 29 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * replace g_rQM with Adpater->rQM + * + * 06 25 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add API in que_mgt to retrieve sta-rec index for security frames. + * + * 06 24 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path. + * + * 06 23 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Merge g_arStaRec[] into adapter->arStaRec[] + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add command warpper for STA-REC/BSS-INFO sync. + * 2) enhance command packet sending procedure for non-oid part + * 3) add command packet definitions for STA-REC/BSS-INFO sync. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add checking for TX descriptor poll. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * TX descriptors are now allocated once for reducing allocation overhead + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * change zero-padding for TX port access to HAL. + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * . + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * . + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * fill extra information for revised HIF_TX_HEADER. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * change to enqueue TX frame infinitely. + * + * 06 09 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add TX_PACKET_MGMT to indicate the frame is coming from management modules + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 10 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * fill network type field while doing frame identification. + * + * 04 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * surpress compiler warning + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Tag the packet for QoS on Tx path + * + * 03 30 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * remove driver-land statistics. + * + * 03 29 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * improve none-glue code portability + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port + * + * 03 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * generate information for OID_GEN_RCV_OK & OID_GEN_XMIT_OK + * * * * * + * +* 03 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code clean: removing unused variables and structure definitions + * + * 03 08 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add another spin-lock to protect MsduInfoList due to it might be accessed by different thread. + * * * * 2) change own-back acquiring procedure to wait for up to 16.67 seconds + * + * 03 02 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add mutex to avoid multiple access to qmTxQueue simultaneously. + * + * 02 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * avoid refering to NDIS-specific data structure directly from non-glue layer. + * + * 02 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add Ethernet destination address information in packet info for TX + * + * 02 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c] + * * * * * * 2) firmware image length is now retrieved via NdisFileOpen + * * * * * * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore + * * * * * * 4) nicRxWaitResponse() revised + * * * * * * 5) another set of TQ counter default value is added for fw-download state + * * * * * * 6) Wi-Fi load address is now retrieved from registry too + * + * 02 09 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address + * * * * * * * * * 2. follow MSDN defined behavior when associates to another AP + * * * * * * * * * 3. for firmware download, packet size could be up to 2048 bytes + * + * 02 08 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * prepare for implementing fw download logic + * + * 01 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. eliminate improper variable in rHifInfo + * * * * * * * * * 2. block TX/ordinary OID when RF test mode is engaged + * * * * * * * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode + * * * * * * * * * 4. correct some HAL implementation + * + * 01 13 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Enabled the Burst_End Indication mechanism + * + * 01 13 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * TX: fill ucWlanHeaderLength/ucPktFormtId_Flags according to info provided by prMsduInfo + * + * 12 30 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) According to CMD/EVENT documentation v0.8, + * * * * * * * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, + * * * * * * * * * * and result is retrieved by get ATInfo instead + * * * * * * * * * * 2) add 4 counter for recording aggregation statistics +** \main\maintrunk.MT6620WiFiDriver_Prj\44 2009-12-10 16:52:15 GMT mtk02752 +** remove unused API +** \main\maintrunk.MT6620WiFiDriver_Prj\43 2009-12-07 22:44:24 GMT mtk02752 +** correct assertion criterion +** \main\maintrunk.MT6620WiFiDriver_Prj\42 2009-12-07 21:15:52 GMT mtk02752 +** correct trivial mistake +** \main\maintrunk.MT6620WiFiDriver_Prj\41 2009-12-04 15:47:21 GMT mtk02752 +** + always append a dword of zero on TX path to avoid TX aggregation to triggered on uninitialized data +** + add more assertion for packet size check +** \main\maintrunk.MT6620WiFiDriver_Prj\40 2009-12-04 14:51:55 GMT mtk02752 +** nicTxMsduInfo(): save ptr for next entry before attaching to qDataPort +** \main\maintrunk.MT6620WiFiDriver_Prj\39 2009-12-04 11:54:54 GMT mtk02752 +** add 2 assertion for size check +** \main\maintrunk.MT6620WiFiDriver_Prj\38 2009-12-03 16:20:35 GMT mtk01461 +** Add debug message +** \main\maintrunk.MT6620WiFiDriver_Prj\37 2009-11-30 10:57:10 GMT mtk02752 +** 1st DW of WIFI_CMD_T is shared with HIF_TX_HEADER_T +** \main\maintrunk.MT6620WiFiDriver_Prj\36 2009-11-30 09:20:43 GMT mtk02752 +** use TC4 instead of TC5 for command packet +** \main\maintrunk.MT6620WiFiDriver_Prj\35 2009-11-27 11:08:11 GMT mtk02752 +** add flush for reset +** \main\maintrunk.MT6620WiFiDriver_Prj\34 2009-11-26 20:31:22 GMT mtk02752 +** fill prMsduInfo->ucUserPriority +** \main\maintrunk.MT6620WiFiDriver_Prj\33 2009-11-25 21:04:33 GMT mtk02752 +** fill u2SeqNo +** \main\maintrunk.MT6620WiFiDriver_Prj\32 2009-11-24 20:52:12 GMT mtk02752 +** integration with SD1's data path API +** \main\maintrunk.MT6620WiFiDriver_Prj\31 2009-11-24 19:54:25 GMT mtk02752 +** nicTxRetransmitOfOsSendQue & nicTxData but changed to use nicTxMsduInfoList +** \main\maintrunk.MT6620WiFiDriver_Prj\30 2009-11-23 17:53:18 GMT mtk02752 +** add nicTxCmd() for SD1_SD3_DATAPATH_INTEGRATION, which will append only HIF_TX_HEADER. seqNum, WIFI_CMD_T will be created inside oid handler +** \main\maintrunk.MT6620WiFiDriver_Prj\29 2009-11-20 15:10:24 GMT mtk02752 +** use TxAccquireResource instead of accessing TCQ directly. +** \main\maintrunk.MT6620WiFiDriver_Prj\28 2009-11-17 22:40:57 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\27 2009-11-17 17:35:40 GMT mtk02752 +** add nicTxMsduInfoList () implementation +** \main\maintrunk.MT6620WiFiDriver_Prj\26 2009-11-17 11:07:10 GMT mtk02752 +** add nicTxAdjustTcq() implementation +** \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-11-16 22:28:38 GMT mtk02752 +** move aucFreeBufferCount/aucMaxNumOfBuffer into another structure +** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-11-16 21:45:32 GMT mtk02752 +** add SD1_SD3_DATAPATH_INTEGRATION data path handling +** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-11-13 13:29:56 GMT mtk01084 +** modify TX hdr format, fix tx retransmission issue +** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-11 10:36:21 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-04 14:11:11 GMT mtk01084 +** modify TX SW data structure +** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-10-29 19:56:17 GMT mtk01084 +** modify HAL part +** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-10-13 21:59:23 GMT mtk01084 +** update for new HW design +** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-10-02 14:00:18 GMT mtk01725 +** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-05-20 12:26:06 GMT mtk01461 +** Assign SeqNum to CMD Packet +** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-05-19 10:54:04 GMT mtk01461 +** Add debug message +** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-05-12 09:41:55 GMT mtk01461 +** Fix Query Command need resp issue +** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-04-29 15:44:38 GMT mtk01461 +** Move OS dependent code to kalQueryTxOOBData() +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-04-28 10:40:03 GMT mtk01461 +** Add nicTxReleaseResource() for SDIO_STATUS_ENHANCE, and also fix the TX aggregation issue for 1x packet to TX1 port +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-04-21 09:50:47 GMT mtk01461 +** Update nicTxCmd() for moving wait RESP function call to wlanSendCommand() +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-04-17 19:56:32 GMT mtk01461 +** Move the CMD_INFO_T related function to cmd_buf.c +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-04-17 18:14:40 GMT mtk01426 +** Update OOB query for TX packet +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-14 15:51:32 GMT mtk01426 +** Support PKGUIO +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-02 17:26:40 GMT mtk01461 +** Add virtual OOB for HIF LOOPBACK SW PRETEST +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-01 10:54:43 GMT mtk01461 +** Add function for SDIO_TX_ENHANCE +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-03-23 21:53:47 GMT mtk01461 +** Add code for retransmit of rOsSendQueue, mpSendPacket(), and add code for TX Checksum offload, Loopback Test. +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-23 00:33:51 GMT mtk01461 +** Add code for TX Data & Cmd Packet +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-18 20:25:40 GMT mtk01461 +** Fix LINT warning +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:10:30 GMT mtk01461 +** Update TX PATH API +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:26:04 GMT mtk01426 +** Init for develop +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will initial all variables in regard to SW TX Queues and +* all free lists of MSDU_INFO_T and SW_TFCB_T. +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicTxInitialize ( + IN P_ADAPTER_T prAdapter + ) +{ + P_TX_CTRL_T prTxCtrl; + PUINT_8 pucMemHandle; + P_MSDU_INFO_T prMsduInfo; + UINT_32 i; + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("nicTxInitialize"); + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + + //4 <1> Initialization of Traffic Class Queue Parameters + nicTxResetResource(prAdapter); + +#if CFG_SDIO_TX_AGG + prTxCtrl->pucTxCoalescingBufPtr = prAdapter->pucCoalescingBufCached; +#endif /* CFG_SDIO_TX_AGG */ + + // allocate MSDU_INFO_T and link it into rFreeMsduInfoList + QUEUE_INITIALIZE(&prTxCtrl->rFreeMsduInfoList); + + pucMemHandle = prTxCtrl->pucTxCached; + for (i = 0 ; i < CFG_TX_MAX_PKT_NUM ; i++) { + prMsduInfo = (P_MSDU_INFO_T)pucMemHandle; + kalMemZero(prMsduInfo, sizeof(MSDU_INFO_T)); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + QUEUE_INSERT_TAIL(&prTxCtrl->rFreeMsduInfoList, (P_QUE_ENTRY_T)prMsduInfo); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + + pucMemHandle += ALIGN_4(sizeof(MSDU_INFO_T)); + } + + ASSERT(prTxCtrl->rFreeMsduInfoList.u4NumElem == CFG_TX_MAX_PKT_NUM); + /* Check if the memory allocation consist with this initialization function */ + ASSERT((UINT_32)(pucMemHandle - prTxCtrl->pucTxCached) == prTxCtrl->u4TxCachedSize); + + QUEUE_INITIALIZE(&prTxCtrl->rTxMgmtTxingQueue); + prTxCtrl->i4TxMgmtPendingNum = 0; + +#if CFG_HIF_STATISTICS + prTxCtrl->u4TotalTxAccessNum = 0; + prTxCtrl->u4TotalTxPacketNum = 0; +#endif + + prTxCtrl->i4PendingFwdFrameCount = 0; + + qmInit(prAdapter); + + TX_RESET_ALL_CNTS(prTxCtrl); + + return; +} /* end of nicTxInitialize() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Driver maintain a variable that is synchronous with the usage of individual +* TC Buffer Count. This function will check if has enough TC Buffer for incoming +* packet and then update the value after promise to provide the resources. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] ucTC Specify the resource of TC +* +* \retval WLAN_STATUS_SUCCESS Resource is available and been assigned. +* \retval WLAN_STATUS_RESOURCES Resource is not available. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicTxAcquireResource ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucTC + ) +{ + P_TX_CTRL_T prTxCtrl; + WLAN_STATUS u4Status = WLAN_STATUS_RESOURCES; + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + +// DbgPrint("nicTxAcquireResource prTxCtrl->rTc.aucFreeBufferCount[%d]=%d\n", ucTC, prTxCtrl->rTc.aucFreeBufferCount[ucTC]); + + if (prTxCtrl->rTc.aucFreeBufferCount[ucTC]) { + + prTxCtrl->rTc.aucFreeBufferCount[ucTC]--; + + DBGLOG(TX, EVENT, ("Acquire: TC = %d aucFreeBufferCount = %d\n", + ucTC, prTxCtrl->rTc.aucFreeBufferCount[ucTC])); + + u4Status = WLAN_STATUS_SUCCESS; + } + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + + return u4Status; + +}/* end of nicTxAcquireResourceAndTFCBs() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Driver maintain a variable that is synchronous with the usage of individual +* TC Buffer Count. This function will do polling if FW has return the resource. +* Used when driver start up before enable interrupt. +* +* @param prAdapter Pointer to the Adapter structure. +* @param ucTC Specify the resource of TC +* +* @retval WLAN_STATUS_SUCCESS Resource is available. +* @retval WLAN_STATUS_FAILURE Resource is not available. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicTxPollingResource ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucTC + ) +{ + P_TX_CTRL_T prTxCtrl; + WLAN_STATUS u4Status = WLAN_STATUS_FAILURE; + INT_32 i = NIC_TX_RESOURCE_POLLING_TIMEOUT; + UINT_32 au4WTSR[2]; + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + + if (ucTC >= TC_NUM) { + return WLAN_STATUS_FAILURE; + } + + if (prTxCtrl->rTc.aucFreeBufferCount[ucTC] > 0) { + return WLAN_STATUS_SUCCESS; + } + + while (i-- > 0) { + HAL_READ_TX_RELEASED_COUNT(prAdapter, au4WTSR); + + if(kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE + || fgIsBusAccessFailed == TRUE) { + u4Status = WLAN_STATUS_FAILURE; + break; + } + else if (nicTxReleaseResource(prAdapter, (PUINT_8)au4WTSR)) { + if (prTxCtrl->rTc.aucFreeBufferCount[ucTC] > 0) { + u4Status = WLAN_STATUS_SUCCESS; + break; + } + else { + kalMsleep(NIC_TX_RESOURCE_POLLING_DELAY_MSEC); + } + } + else { + kalMsleep(NIC_TX_RESOURCE_POLLING_DELAY_MSEC); + } + } + +#if DBG + { + INT_32 i4Times = NIC_TX_RESOURCE_POLLING_TIMEOUT - (i+1); + + if (i4Times) { + DBGLOG(TX, TRACE, ("Polling MCR_WTSR delay %d times, %d msec\n", + i4Times, (i4Times * NIC_TX_RESOURCE_POLLING_DELAY_MSEC))); + } + } +#endif /* DBG */ + + return u4Status; + +} /* end of nicTxPollingResource() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Driver maintain a variable that is synchronous with the usage of individual +* TC Buffer Count. This function will release TC Buffer count according to +* the given TX_STATUS COUNTER after TX Done. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] u4TxStatusCnt Value of TX STATUS +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +nicTxReleaseResource ( + IN P_ADAPTER_T prAdapter, + IN UINT_8* aucTxRlsCnt + ) +{ + PUINT_32 pu4Tmp = (PUINT_32)aucTxRlsCnt; + P_TX_CTRL_T prTxCtrl; + BOOLEAN bStatus = FALSE; + UINT_32 i; + + KAL_SPIN_LOCK_DECLARATION(); + + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + + if (pu4Tmp[0] | pu4Tmp[1]) { + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + for (i = 0; i < TC_NUM; i++) { + prTxCtrl->rTc.aucFreeBufferCount[i] += aucTxRlsCnt[i]; + + if ((i==1) || (i==5)){ + DBGLOG(TX, EVENT, ("Release: i = %d aucFreeBufferCount = %d\n", + i, prTxCtrl->rTc.aucFreeBufferCount[i])); + } + } + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); +#if 0 + for (i = 0; i < TC_NUM; i++) { + DBGLOG(INIT, TRACE, ("aucFreeBufferCount[%d]: %d, aucMaxNumOfBuffer[%d]: %d\n", + i, prTxCtrl->rTc.aucFreeBufferCount[i], i, prTxCtrl->rTc.aucMaxNumOfBuffer[i])); + } + DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[0]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[0]); + DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[1]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[1]); + DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[2]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[2]); + DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[3]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[3]); + DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[4]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[4]); + DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[5]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[5]); +#endif + ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC0_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC0_INDEX]); + ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC1_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC1_INDEX]); + ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC2_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC2_INDEX]); + ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC3_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC3_INDEX]); + ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC4_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC4_INDEX]); + ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC5_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC5_INDEX]); + bStatus = TRUE; + } + + return bStatus; +} /* end of nicTxReleaseResource() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Reset TC Buffer Count to initialized value +* +* \param[in] prAdapter Pointer to the Adapter structure. +* +* @return WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicTxResetResource ( + IN P_ADAPTER_T prAdapter + ) +{ + P_TX_CTRL_T prTxCtrl; + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("nicTxResetResource"); + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + + prTxCtrl->rTc.aucMaxNumOfBuffer[TC0_INDEX] = NIC_TX_BUFF_COUNT_TC0; + prTxCtrl->rTc.aucFreeBufferCount[TC0_INDEX] = NIC_TX_BUFF_COUNT_TC0; + + prTxCtrl->rTc.aucMaxNumOfBuffer[TC1_INDEX] = NIC_TX_BUFF_COUNT_TC1; + prTxCtrl->rTc.aucFreeBufferCount[TC1_INDEX] = NIC_TX_BUFF_COUNT_TC1; + + prTxCtrl->rTc.aucMaxNumOfBuffer[TC2_INDEX] = NIC_TX_BUFF_COUNT_TC2; + prTxCtrl->rTc.aucFreeBufferCount[TC2_INDEX] = NIC_TX_BUFF_COUNT_TC2; + + prTxCtrl->rTc.aucMaxNumOfBuffer[TC3_INDEX] = NIC_TX_BUFF_COUNT_TC3; + prTxCtrl->rTc.aucFreeBufferCount[TC3_INDEX] = NIC_TX_BUFF_COUNT_TC3; + + prTxCtrl->rTc.aucMaxNumOfBuffer[TC4_INDEX] = NIC_TX_BUFF_COUNT_TC4; + prTxCtrl->rTc.aucFreeBufferCount[TC4_INDEX] = NIC_TX_BUFF_COUNT_TC4; + + prTxCtrl->rTc.aucMaxNumOfBuffer[TC5_INDEX] = NIC_TX_BUFF_COUNT_TC5; + prTxCtrl->rTc.aucFreeBufferCount[TC5_INDEX] = NIC_TX_BUFF_COUNT_TC5; + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + + return WLAN_STATUS_SUCCESS; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Driver maintain a variable that is synchronous with the usage of individual +* TC Buffer Count. This function will return the value for other component +* which needs this information for making decisions +* +* @param prAdapter Pointer to the Adapter structure. +* @param ucTC Specify the resource of TC +* +* @retval UINT_8 The number of corresponding TC number +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 +nicTxGetResource ( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucTC + ) +{ + P_TX_CTRL_T prTxCtrl; + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + + ASSERT(prTxCtrl); + + if (ucTC >= TC_NUM) { + return 0; + } + else { + return prTxCtrl->rTc.aucFreeBufferCount[ucTC]; + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief In this function, we'll aggregate frame(PACKET_INFO_T) +* corresponding to HIF TX port +* +* @param prAdapter Pointer to the Adapter structure. +* @param prMsduInfoListHead a link list of P_MSDU_INFO_T +* +* @retval WLAN_STATUS_SUCCESS Bus access ok. +* @retval WLAN_STATUS_FAILURE Bus access fail. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicTxMsduInfoList ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfoListHead + ) +{ + P_MSDU_INFO_T prMsduInfo, prNextMsduInfo; + QUE_T qDataPort0, qDataPort1; + WLAN_STATUS status; + + ASSERT(prAdapter); + ASSERT(prMsduInfoListHead); + + prMsduInfo = prMsduInfoListHead; + + QUEUE_INITIALIZE(&qDataPort0); + QUEUE_INITIALIZE(&qDataPort1); + + // Separate MSDU_INFO_T lists into 2 categories: for Port#0 & Port#1 + while(prMsduInfo) { + prNextMsduInfo = (P_MSDU_INFO_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prMsduInfo); +#if DBG && 0 + LOG_FUNC("nicTxMsduInfoList Acquire TC %d net %u mac len %u len %u Type %u 1x %u 11 %u\n", + prMsduInfo->ucTC, + prMsduInfo->ucNetworkType, + prMsduInfo->ucMacHeaderLength, + prMsduInfo->u2FrameLength, + prMsduInfo->ucPacketType, + prMsduInfo->fgIs802_1x, + prMsduInfo->fgIs802_11 ); + + LOG_FUNC("Dest Mac: " MACSTR "\n", + MAC2STR(prMsduInfo->aucEthDestAddr)); +#endif + + switch(prMsduInfo->ucTC) { + case TC0_INDEX: + case TC1_INDEX: + case TC2_INDEX: + case TC3_INDEX: + case TC5_INDEX: // Broadcast/multicast data packets + QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prMsduInfo) = NULL; + QUEUE_INSERT_TAIL(&qDataPort0, (P_QUE_ENTRY_T)prMsduInfo); + status = nicTxAcquireResource(prAdapter, prMsduInfo->ucTC); + ASSERT(status == WLAN_STATUS_SUCCESS) + + break; + + case TC4_INDEX: // Command or 802.1x packets + QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prMsduInfo) = NULL; + QUEUE_INSERT_TAIL(&qDataPort1, (P_QUE_ENTRY_T)prMsduInfo); + + status = nicTxAcquireResource(prAdapter, prMsduInfo->ucTC); + ASSERT(status == WLAN_STATUS_SUCCESS) + + break; + + default: + ASSERT(0); + break; + } + + prMsduInfo = prNextMsduInfo; + } + + if(qDataPort0.u4NumElem > 0) { + nicTxMsduQueue(prAdapter, 0, &qDataPort0); + } + + if(qDataPort1.u4NumElem > 0) { + nicTxMsduQueue(prAdapter, 1, &qDataPort1); + } + + return WLAN_STATUS_SUCCESS; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief In this function, we'll write frame(PACKET_INFO_T) into HIF. +* +* @param prAdapter Pointer to the Adapter structure. +* @param ucPortIdx Port Number +* @param prQue a link list of P_MSDU_INFO_T +* +* @retval WLAN_STATUS_SUCCESS Bus access ok. +* @retval WLAN_STATUS_FAILURE Bus access fail. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicTxMsduQueue ( + IN P_ADAPTER_T prAdapter, + UINT_8 ucPortIdx, + P_QUE_T prQue + ) +{ + P_MSDU_INFO_T prMsduInfo, prNextMsduInfo; + HIF_TX_HEADER_T rHwTxHeader; + P_NATIVE_PACKET prNativePacket; + UINT_16 u2OverallBufferLength; + UINT_8 ucEtherTypeOffsetInWord; + PUINT_8 pucOutputBuf = (PUINT_8)NULL; /* Pointer to Transmit Data Structure Frame */ + UINT_32 u4TxHdrSize; + UINT_32 u4ValidBufSize; + UINT_32 u4TotalLength; + P_TX_CTRL_T prTxCtrl; + QUE_T rFreeQueue; +#if CFG_TCP_IP_CHKSUM_OFFLOAD + UINT_8 ucChksumFlag; +#endif + + ASSERT(prAdapter); + ASSERT(ucPortIdx < 2); + ASSERT(prQue); + + prTxCtrl = &prAdapter->rTxCtrl; + u4ValidBufSize = prAdapter->u4CoalescingBufCachedSize; + +#if CFG_HIF_STATISTICS + prTxCtrl->u4TotalTxAccessNum++; + prTxCtrl->u4TotalTxPacketNum += prQue->u4NumElem; +#endif + + QUEUE_INITIALIZE(&rFreeQueue); + + if(prQue->u4NumElem > 0) { + prMsduInfo = (P_MSDU_INFO_T)QUEUE_GET_HEAD(prQue); + pucOutputBuf = prTxCtrl->pucTxCoalescingBufPtr; + u4TotalLength = 0; + + while(prMsduInfo) { + + kalMemZero(&rHwTxHeader, sizeof(rHwTxHeader)); + + prNativePacket = prMsduInfo->prPacket; + + ASSERT(prNativePacket); + + u4TxHdrSize = TX_HDR_SIZE; + + u2OverallBufferLength = ((prMsduInfo->u2FrameLength + TX_HDR_SIZE) & + (UINT_16)HIF_TX_HDR_TX_BYTE_COUNT_MASK); + + rHwTxHeader.u2TxByteCount_UserPriority = u2OverallBufferLength; + rHwTxHeader.u2TxByteCount_UserPriority |= + ((UINT_16)prMsduInfo->ucUserPriority << HIF_TX_HDR_USER_PRIORITY_OFFSET); + + if (prMsduInfo->fgIs802_11) { + ucEtherTypeOffsetInWord = + (TX_HDR_SIZE + prMsduInfo->ucMacHeaderLength + prMsduInfo->ucLlcLength) >> 1; + } + else { + ucEtherTypeOffsetInWord = + ((ETHER_HEADER_LEN - ETHER_TYPE_LEN) + TX_HDR_SIZE) >> 1; + } + + rHwTxHeader.ucEtherTypeOffset = + ucEtherTypeOffsetInWord & HIF_TX_HDR_ETHER_TYPE_OFFSET_MASK; + + rHwTxHeader.ucResource_PktType_CSflags = (prMsduInfo->ucTC) << HIF_TX_HDR_RESOURCE_OFFSET; + rHwTxHeader.ucResource_PktType_CSflags |= + (UINT_8)(((prMsduInfo->ucPacketType) << HIF_TX_HDR_PACKET_TYPE_OFFSET) & + (HIF_TX_HDR_PACKET_TYPE_MASK)); + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + if (prMsduInfo->eSrc == TX_PACKET_OS + || prMsduInfo->eSrc == TX_PACKET_FORWARDING) { + if (prAdapter->u4CSUMFlags & + (CSUM_OFFLOAD_EN_TX_TCP | + CSUM_OFFLOAD_EN_TX_UDP | + CSUM_OFFLOAD_EN_TX_IP)) { + kalQueryTxChksumOffloadParam(prNativePacket, &ucChksumFlag); + + if (ucChksumFlag & TX_CS_IP_GEN) { + rHwTxHeader.ucResource_PktType_CSflags |= (UINT_8)HIF_TX_HDR_IP_CSUM; + } + + if (ucChksumFlag & TX_CS_TCP_UDP_GEN) { + rHwTxHeader.ucResource_PktType_CSflags |= (UINT_8)HIF_TX_HDR_TCP_CSUM; + } + } + } +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + + rHwTxHeader.u2LLH = prMsduInfo->u2PalLLH; + rHwTxHeader.ucStaRecIdx = prMsduInfo->ucStaRecIndex; + rHwTxHeader.ucForwardingType_SessionID_Reserved = + (prMsduInfo->ucPsForwardingType) | ((prMsduInfo->ucPsSessionID) << HIF_TX_HDR_PS_SESSION_ID_OFFSET) + | ((prMsduInfo->fgIsBurstEnd)? HIF_TX_HDR_BURST_END_MASK : 0); + + rHwTxHeader.ucWlanHeaderLength = (prMsduInfo->ucMacHeaderLength & HIF_TX_HDR_WLAN_HEADER_LEN_MASK); + rHwTxHeader.ucPktFormtId_Flags = + (prMsduInfo->ucFormatID & HIF_TX_HDR_FORMAT_ID_MASK) + | ((prMsduInfo->ucNetworkType << HIF_TX_HDR_NETWORK_TYPE_OFFSET) & HIF_TX_HDR_NETWORK_TYPE_MASK) + | ((prMsduInfo->fgIs802_1x << HIF_TX_HDR_FLAG_1X_FRAME_OFFSET) & HIF_TX_HDR_FLAG_1X_FRAME_MASK) + | ((prMsduInfo->fgIs802_11 << HIF_TX_HDR_FLAG_802_11_FORMAT_OFFSET) & HIF_TX_HDR_FLAG_802_11_FORMAT_MASK); + + rHwTxHeader.u2SeqNo = prMsduInfo->u2AclSN; + + if(prMsduInfo->pfTxDoneHandler) { + rHwTxHeader.ucPacketSeqNo = prMsduInfo->ucTxSeqNum; + rHwTxHeader.ucAck_BIP_BasicRate = HIF_TX_HDR_NEED_ACK; + } + else { + rHwTxHeader.ucPacketSeqNo = 0; + rHwTxHeader.ucAck_BIP_BasicRate = 0; + } + + if(prMsduInfo->fgIsBIP) { + rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_BIP; + } + + if(prMsduInfo->fgIsBasicRate) { + rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_BASIC_RATE; + } + +#if CFG_SDIO_TX_AGG + // attach to coalescing buffer + kalMemCopy(pucOutputBuf + u4TotalLength, &rHwTxHeader, u4TxHdrSize); + u4TotalLength += u4TxHdrSize; + + if (prMsduInfo->eSrc == TX_PACKET_OS + || prMsduInfo->eSrc == TX_PACKET_FORWARDING) { + kalCopyFrame(prAdapter->prGlueInfo, + prNativePacket, + pucOutputBuf + u4TotalLength); + } + else if(prMsduInfo->eSrc == TX_PACKET_MGMT) { + kalMemCopy(pucOutputBuf + u4TotalLength, + prNativePacket, + prMsduInfo->u2FrameLength); + } + else { + ASSERT(0); + } + + u4TotalLength += ALIGN_4(prMsduInfo->u2FrameLength); + +#else + kalMemCopy(pucOutputBuf, &rHwTxHeader, u4TxHdrSize); + + /* Copy Frame Body */ + if (prMsduInfo->eSrc == TX_PACKET_OS + || prMsduInfo->eSrc == TX_PACKET_FORWARDING) { + kalCopyFrame(prAdapter->prGlueInfo, + prNativePacket, + pucOutputBuf + u4TxHdrSize); + } + else if(prMsduInfo->eSrc == TX_PACKET_MGMT) { + kalMemCopy(pucOutputBuf + u4TxHdrSize, + prNativePacket, + prMsduInfo->u2FrameLength); + } + else { + ASSERT(0); + } + + ASSERT(u2OverallBufferLength <= u4ValidBufSize); + + HAL_WRITE_TX_PORT(prAdapter, + ucPortIdx, + (UINT_32)u2OverallBufferLength, + (PUINT_8)pucOutputBuf, + u4ValidBufSize); + + // send immediately +#endif + prNextMsduInfo = (P_MSDU_INFO_T) + QUEUE_GET_NEXT_ENTRY(&prMsduInfo->rQueEntry); + + if (prMsduInfo->eSrc == TX_PACKET_MGMT) { + GLUE_DEC_REF_CNT(prTxCtrl->i4TxMgmtPendingNum); + + if (prMsduInfo->pfTxDoneHandler == NULL) { + cnmMgtPktFree(prAdapter, prMsduInfo); + } + else { + KAL_SPIN_LOCK_DECLARATION(); + DBGLOG(INIT, TRACE,("Wait TxSeqNum:%d\n", prMsduInfo->ucTxSeqNum)); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + QUEUE_INSERT_TAIL(&(prTxCtrl->rTxMgmtTxingQueue), (P_QUE_ENTRY_T)prMsduInfo); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + } + } + else { + /* only free MSDU when it is not a MGMT frame */ + QUEUE_INSERT_TAIL(&rFreeQueue, (P_QUE_ENTRY_T)prMsduInfo); + + if (prMsduInfo->eSrc == TX_PACKET_OS) { + kalSendComplete(prAdapter->prGlueInfo, + prNativePacket, + WLAN_STATUS_SUCCESS); + } + else if(prMsduInfo->eSrc == TX_PACKET_FORWARDING) { + GLUE_DEC_REF_CNT(prTxCtrl->i4PendingFwdFrameCount); + } + } + + prMsduInfo = prNextMsduInfo; + } + +#if CFG_SDIO_TX_AGG + ASSERT(u4TotalLength <= u4ValidBufSize); + + #if CFG_DBG_GPIO_PINS + { + /* Start port write */ + mtk_wcn_stp_debug_gpio_assert(IDX_TX_PORT_WRITE, DBG_TIE_LOW); + kalUdelay(1); + mtk_wcn_stp_debug_gpio_assert(IDX_TX_PORT_WRITE, DBG_TIE_HIGH); + } + #endif + + // send coalescing buffer + HAL_WRITE_TX_PORT(prAdapter, + ucPortIdx, + u4TotalLength, + (PUINT_8)pucOutputBuf, + u4ValidBufSize); +#endif + + // return + nicTxReturnMsduInfo(prAdapter, (P_MSDU_INFO_T)QUEUE_GET_HEAD(&rFreeQueue)); + } + + return WLAN_STATUS_SUCCESS; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief In this function, we'll write Command(CMD_INFO_T) into HIF. +* +* @param prAdapter Pointer to the Adapter structure. +* @param prPacketInfo Pointer of CMD_INFO_T +* @param ucTC Specify the resource of TC +* +* @retval WLAN_STATUS_SUCCESS Bus access ok. +* @retval WLAN_STATUS_FAILURE Bus access fail. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicTxCmd ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN UINT_8 ucTC + ) +{ + P_WIFI_CMD_T prWifiCmd; + UINT_16 u2OverallBufferLength; + PUINT_8 pucOutputBuf = (PUINT_8)NULL; /* Pointer to Transmit Data Structure Frame */ + UINT_8 ucPortIdx; + HIF_TX_HEADER_T rHwTxHeader; + P_NATIVE_PACKET prNativePacket; + UINT_8 ucEtherTypeOffsetInWord; + P_MSDU_INFO_T prMsduInfo; + P_TX_CTRL_T prTxCtrl; + + KAL_SPIN_LOCK_DECLARATION(); + + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prTxCtrl = &prAdapter->rTxCtrl; + pucOutputBuf = prTxCtrl->pucTxCoalescingBufPtr; + + // <1> Assign Data Port + if (ucTC != TC4_INDEX) { + ucPortIdx = 0; + } + else { + // Broadcast/multicast data frames, 1x frames, command packets, MMPDU + ucPortIdx = 1; + } + + if(prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME) { + // <2> Compose HIF_TX_HEADER + kalMemZero(&rHwTxHeader, sizeof(rHwTxHeader)); + + prNativePacket = prCmdInfo->prPacket; + + ASSERT(prNativePacket); + + u2OverallBufferLength = TFCB_FRAME_PAD_TO_DW((prCmdInfo->u2InfoBufLen + TX_HDR_SIZE) + & (UINT_16)HIF_TX_HDR_TX_BYTE_COUNT_MASK); + + rHwTxHeader.u2TxByteCount_UserPriority = ((prCmdInfo->u2InfoBufLen + TX_HDR_SIZE) + & (UINT_16)HIF_TX_HDR_TX_BYTE_COUNT_MASK); + ucEtherTypeOffsetInWord = ((ETHER_HEADER_LEN - ETHER_TYPE_LEN) + TX_HDR_SIZE) >> 1; + + rHwTxHeader.ucEtherTypeOffset = + ucEtherTypeOffsetInWord & HIF_TX_HDR_ETHER_TYPE_OFFSET_MASK; + + rHwTxHeader.ucResource_PktType_CSflags = (ucTC << HIF_TX_HDR_RESOURCE_OFFSET); + + rHwTxHeader.ucStaRecIdx = prCmdInfo->ucStaRecIndex; + rHwTxHeader.ucForwardingType_SessionID_Reserved = HIF_TX_HDR_BURST_END_MASK; + + rHwTxHeader.ucWlanHeaderLength = (ETH_HLEN & HIF_TX_HDR_WLAN_HEADER_LEN_MASK); + rHwTxHeader.ucPktFormtId_Flags = + (((UINT_8)(prCmdInfo->eNetworkType) << HIF_TX_HDR_NETWORK_TYPE_OFFSET) & HIF_TX_HDR_NETWORK_TYPE_MASK) + | ((1 << HIF_TX_HDR_FLAG_1X_FRAME_OFFSET) & HIF_TX_HDR_FLAG_1X_FRAME_MASK); + + rHwTxHeader.u2SeqNo = 0; + rHwTxHeader.ucPacketSeqNo = 0; + rHwTxHeader.ucAck_BIP_BasicRate = 0; + + // <2.3> Copy HIF TX HEADER + kalMemCopy((PVOID)&pucOutputBuf[0], (PVOID)&rHwTxHeader, TX_HDR_SIZE); + + // <3> Copy Frame Body Copy + kalCopyFrame(prAdapter->prGlueInfo, + prNativePacket, + pucOutputBuf + TX_HDR_SIZE); + } + else if(prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME) { + prMsduInfo = (P_MSDU_INFO_T)prCmdInfo->prPacket; + + ASSERT(prMsduInfo->fgIs802_11 == TRUE); + ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); + + // <2> Compose HIF_TX_HEADER + kalMemZero(&rHwTxHeader, sizeof(rHwTxHeader)); + + u2OverallBufferLength = ((prMsduInfo->u2FrameLength + TX_HDR_SIZE) & + (UINT_16)HIF_TX_HDR_TX_BYTE_COUNT_MASK); + + rHwTxHeader.u2TxByteCount_UserPriority = u2OverallBufferLength; + rHwTxHeader.u2TxByteCount_UserPriority |= + ((UINT_16)prMsduInfo->ucUserPriority << HIF_TX_HDR_USER_PRIORITY_OFFSET); + + ucEtherTypeOffsetInWord = + (TX_HDR_SIZE + prMsduInfo->ucMacHeaderLength + prMsduInfo->ucLlcLength) >> 1; + + rHwTxHeader.ucEtherTypeOffset = + ucEtherTypeOffsetInWord & HIF_TX_HDR_ETHER_TYPE_OFFSET_MASK; + + rHwTxHeader.ucResource_PktType_CSflags = (prMsduInfo->ucTC) << HIF_TX_HDR_RESOURCE_OFFSET; + rHwTxHeader.ucResource_PktType_CSflags |= + (UINT_8)(((prMsduInfo->ucPacketType) << HIF_TX_HDR_PACKET_TYPE_OFFSET) & + (HIF_TX_HDR_PACKET_TYPE_MASK)); + + rHwTxHeader.u2LLH = prMsduInfo->u2PalLLH; + rHwTxHeader.ucStaRecIdx = prMsduInfo->ucStaRecIndex; + rHwTxHeader.ucForwardingType_SessionID_Reserved = + (prMsduInfo->ucPsForwardingType) | ((prMsduInfo->ucPsSessionID) << HIF_TX_HDR_PS_SESSION_ID_OFFSET) + | ((prMsduInfo->fgIsBurstEnd)? HIF_TX_HDR_BURST_END_MASK : 0); + + rHwTxHeader.ucWlanHeaderLength = (prMsduInfo->ucMacHeaderLength & HIF_TX_HDR_WLAN_HEADER_LEN_MASK); + rHwTxHeader.ucPktFormtId_Flags = + (prMsduInfo->ucFormatID & HIF_TX_HDR_FORMAT_ID_MASK) + | ((prMsduInfo->ucNetworkType << HIF_TX_HDR_NETWORK_TYPE_OFFSET) & HIF_TX_HDR_NETWORK_TYPE_MASK) + | ((prMsduInfo->fgIs802_1x << HIF_TX_HDR_FLAG_1X_FRAME_OFFSET) & HIF_TX_HDR_FLAG_1X_FRAME_MASK) + | ((prMsduInfo->fgIs802_11 << HIF_TX_HDR_FLAG_802_11_FORMAT_OFFSET) & HIF_TX_HDR_FLAG_802_11_FORMAT_MASK); + + rHwTxHeader.u2SeqNo = prMsduInfo->u2AclSN; + + if(prMsduInfo->pfTxDoneHandler) { + rHwTxHeader.ucPacketSeqNo = prMsduInfo->ucTxSeqNum; + rHwTxHeader.ucAck_BIP_BasicRate = HIF_TX_HDR_NEED_ACK; + } + else { + rHwTxHeader.ucPacketSeqNo = 0; + rHwTxHeader.ucAck_BIP_BasicRate = 0; + } + + if(prMsduInfo->fgIsBIP) { + rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_BIP; + } + + if(prMsduInfo->fgIsBasicRate) { + rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_BASIC_RATE; + } + + // <2.3> Copy HIF TX HEADER + kalMemCopy((PVOID)&pucOutputBuf[0], (PVOID)&rHwTxHeader, TX_HDR_SIZE); + + // <3> Copy Frame Body + kalMemCopy(pucOutputBuf + TX_HDR_SIZE, + prMsduInfo->prPacket, + prMsduInfo->u2FrameLength); + + // <4> Management Frame Post-Processing + GLUE_DEC_REF_CNT(prTxCtrl->i4TxMgmtPendingNum); + + if (prMsduInfo->pfTxDoneHandler == NULL) { + cnmMgtPktFree(prAdapter, prMsduInfo); + } + else { + + DBGLOG(INIT, TRACE,("Wait Cmd TxSeqNum:%d\n", prMsduInfo->ucTxSeqNum)); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + QUEUE_INSERT_TAIL(&(prTxCtrl->rTxMgmtTxingQueue), (P_QUE_ENTRY_T)prMsduInfo); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + } + } + else { + prWifiCmd = (P_WIFI_CMD_T)prCmdInfo->pucInfoBuffer; + + // <2> Compose the Header of Transmit Data Structure for CMD Packet + u2OverallBufferLength = TFCB_FRAME_PAD_TO_DW( + (prCmdInfo->u2InfoBufLen) & (UINT_16)HIF_TX_HDR_TX_BYTE_COUNT_MASK); + + prWifiCmd->u2TxByteCount_UserPriority = u2OverallBufferLength; + prWifiCmd->ucEtherTypeOffset = 0; + prWifiCmd->ucResource_PktType_CSflags = (ucTC << HIF_TX_HDR_RESOURCE_OFFSET) + | (UINT_8)((HIF_TX_PKT_TYPE_CMD << HIF_TX_HDR_PACKET_TYPE_OFFSET) & (HIF_TX_HDR_PACKET_TYPE_MASK)); + + + // <3> Copy CMD Header to command buffer (by using pucCoalescingBufCached) + kalMemCopy((PVOID)&pucOutputBuf[0], + (PVOID)prCmdInfo->pucInfoBuffer, + prCmdInfo->u2InfoBufLen); + + ASSERT(u2OverallBufferLength <= prAdapter->u4CoalescingBufCachedSize); + } + + // <4> Write frame to data port + HAL_WRITE_TX_PORT(prAdapter, + ucPortIdx, + (UINT_32)u2OverallBufferLength, + (PUINT_8)pucOutputBuf, + (UINT_32)prAdapter->u4CoalescingBufCachedSize); + + return WLAN_STATUS_SUCCESS; +} /* end of nicTxCmd() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will clean up all the pending frames in internal SW Queues +* by return the pending TX packet to the system. +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicTxRelease ( + IN P_ADAPTER_T prAdapter + ) +{ + P_TX_CTRL_T prTxCtrl; + P_MSDU_INFO_T prMsduInfo; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + prTxCtrl = &prAdapter->rTxCtrl; + + nicTxFlush(prAdapter); + + // free MSDU_INFO_T from rTxMgmtMsduInfoList + do { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + QUEUE_REMOVE_HEAD(&prTxCtrl->rTxMgmtTxingQueue, prMsduInfo, P_MSDU_INFO_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + + if(prMsduInfo) { + // the packet must be mgmt frame with tx done callback + ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); + ASSERT(prMsduInfo->pfTxDoneHandler != NULL); + + // invoke done handler + prMsduInfo->pfTxDoneHandler(prAdapter, prMsduInfo, TX_RESULT_LIFE_TIMEOUT); + + cnmMgtPktFree(prAdapter, prMsduInfo); + } + else { + break; + } + } while(TRUE); + + return; +} /* end of nicTxRelease() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process the TX Done interrupt and pull in more pending frames in SW +* Queues for transmission. +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicProcessTxInterrupt( + IN P_ADAPTER_T prAdapter + ) +{ + P_TX_CTRL_T prTxCtrl; +#if CFG_SDIO_INTR_ENHANCE + P_SDIO_CTRL_T prSDIOCtrl; +#else + UINT_32 au4TxCount[2]; +#endif /* CFG_SDIO_INTR_ENHANCE */ + + ASSERT(prAdapter); + + prTxCtrl = &prAdapter->rTxCtrl; + ASSERT(prTxCtrl); + + /* Get the TX STATUS */ +#if CFG_SDIO_INTR_ENHANCE + + prSDIOCtrl = prAdapter->prSDIOCtrl; + #if DBG + //dumpMemory8((PUINT_8)prSDIOCtrl, sizeof(SDIO_CTRL_T)); + #endif + + nicTxReleaseResource(prAdapter, (PUINT_8)&prSDIOCtrl->rTxInfo); + kalMemZero(&prSDIOCtrl->rTxInfo, sizeof(prSDIOCtrl->rTxInfo)); + +#else + + HAL_MCR_RD(prAdapter, MCR_WTSR0, &au4TxCount[0]); + HAL_MCR_RD(prAdapter, MCR_WTSR1, &au4TxCount[1]); + DBGLOG(EMU, TRACE, ("MCR_WTSR0: 0x%x, MCR_WTSR1: 0x%x\n", au4TxCount[0], au4TxCount[1])); + + nicTxReleaseResource(prAdapter, (PUINT_8)au4TxCount); + +#endif /* CFG_SDIO_INTR_ENHANCE */ + + nicTxAdjustTcq(prAdapter); + + // Indicate Service Thread + if(kalGetTxPendingCmdCount(prAdapter->prGlueInfo) > 0 + || wlanGetTxPendingFrameCount(prAdapter) > 0) { + kalSetEvent(prAdapter->prGlueInfo); + } + + return; +} /* end of nicProcessTxInterrupt() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief this function frees packet of P_MSDU_INFO_T linked-list +* +* @param prAdapter Pointer to the Adapter structure. +* @param prMsduInfoList a link list of P_MSDU_INFO_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicTxFreeMsduInfoPacket ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfoListHead + ) +{ + P_NATIVE_PACKET prNativePacket; + P_MSDU_INFO_T prMsduInfo = prMsduInfoListHead; + P_TX_CTRL_T prTxCtrl; + + + ASSERT(prAdapter); + ASSERT(prMsduInfoListHead); + + prTxCtrl = &prAdapter->rTxCtrl; + + while(prMsduInfo) { + prNativePacket = prMsduInfo->prPacket; + + if(prMsduInfo->eSrc == TX_PACKET_OS) { + kalSendComplete(prAdapter->prGlueInfo, + prNativePacket, + WLAN_STATUS_FAILURE); + } + else if(prMsduInfo->eSrc == TX_PACKET_MGMT) { + if (prMsduInfo->pfTxDoneHandler) { + prMsduInfo->pfTxDoneHandler(prAdapter, prMsduInfo, TX_RESULT_DROPPED_IN_DRIVER); + } + cnmMemFree(prAdapter, prNativePacket); + } + else if(prMsduInfo->eSrc == TX_PACKET_FORWARDING) { + GLUE_DEC_REF_CNT(prTxCtrl->i4PendingFwdFrameCount); + } + + prMsduInfo = (P_MSDU_INFO_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prMsduInfo); + } + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief this function returns P_MSDU_INFO_T of MsduInfoList to TxCtrl->rfreeMsduInfoList +* +* @param prAdapter Pointer to the Adapter structure. +* @param prMsduInfoList a link list of P_MSDU_INFO_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicTxReturnMsduInfo ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfoListHead + ) +{ + P_TX_CTRL_T prTxCtrl; + P_MSDU_INFO_T prMsduInfo = prMsduInfoListHead, prNextMsduInfo; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + prTxCtrl = &prAdapter->rTxCtrl; + ASSERT(prTxCtrl); + + while(prMsduInfo) { + prNextMsduInfo = (P_MSDU_INFO_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prMsduInfo); + + switch(prMsduInfo->eSrc) { + case TX_PACKET_FORWARDING: + wlanReturnPacket(prAdapter, prMsduInfo->prPacket); + break; + case TX_PACKET_OS: + case TX_PACKET_OS_OID: + case TX_PACKET_MGMT: + default: + break; + } + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + QUEUE_INSERT_TAIL(&prTxCtrl->rFreeMsduInfoList, (P_QUE_ENTRY_T)prMsduInfo); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + prMsduInfo = prNextMsduInfo; + }; + + return; +} + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief this function fills packet information to P_MSDU_INFO_T +* +* @param prAdapter Pointer to the Adapter structure. +* @param prMsduInfo P_MSDU_INFO_T +* @param prPacket P_NATIVE_PACKET +* +* @retval TRUE Success to extract information +* @retval FALSE Fail to extract correct information +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +nicTxFillMsduInfo ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN P_NATIVE_PACKET prPacket + ) +{ + P_GLUE_INFO_T prGlueInfo; + UINT_8 ucPriorityParam; + UINT_8 ucMacHeaderLen; + UINT_8 aucEthDestAddr[PARAM_MAC_ADDR_LEN]; + BOOLEAN fgIs1x = FALSE; + BOOLEAN fgIsPAL = FALSE; + UINT_32 u4PacketLen; + ULONG u4SysTime; + UINT_8 ucNetworkType; + + + ASSERT(prAdapter); + + prGlueInfo = prAdapter->prGlueInfo; + ASSERT(prGlueInfo); + + if (kalQoSFrameClassifierAndPacketInfo(prGlueInfo, + prPacket, + &ucPriorityParam, + &u4PacketLen, + aucEthDestAddr, + &fgIs1x, + &fgIsPAL, + &ucNetworkType) == FALSE) { + return FALSE; + } + + /* Save the value of Priority Parameter */ + GLUE_SET_PKT_TID(prPacket, ucPriorityParam); + + if (fgIs1x) { + GLUE_SET_PKT_FLAG_1X(prPacket); + } + + if (fgIsPAL) { + GLUE_SET_PKT_FLAG_PAL(prPacket); + } + + ucMacHeaderLen = ETH_HLEN; + + /* Save the value of Header Length */ + GLUE_SET_PKT_HEADER_LEN(prPacket, ucMacHeaderLen); + + /* Save the value of Frame Length */ + GLUE_SET_PKT_FRAME_LEN(prPacket, (UINT_16)u4PacketLen); + + /* Save the value of Arrival Time*/ + u4SysTime = (OS_SYSTIME)kalGetTimeTick(); + GLUE_SET_PKT_ARRIVAL_TIME(prPacket, u4SysTime); + + prMsduInfo->prPacket = prPacket; + prMsduInfo->fgIs802_1x = fgIs1x; + prMsduInfo->fgIs802_11 = FALSE; + prMsduInfo->ucNetworkType = ucNetworkType; + prMsduInfo->ucUserPriority = ucPriorityParam; + prMsduInfo->ucMacHeaderLength = ucMacHeaderLen; + prMsduInfo->u2FrameLength = (UINT_16)u4PacketLen; + COPY_MAC_ADDR(prMsduInfo->aucEthDestAddr, aucEthDestAddr); + + return TRUE; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief this function update TCQ values by passing current status to txAdjustTcQuotas +* +* @param prAdapter Pointer to the Adapter structure. +* +* @retval WLAN_STATUS_SUCCESS Updated successfully +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicTxAdjustTcq ( + IN P_ADAPTER_T prAdapter + ) +{ + UINT_32 u4Num; + TX_TCQ_ADJUST_T rTcqAdjust; + P_TX_CTRL_T prTxCtrl; + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + prTxCtrl = &prAdapter->rTxCtrl; + ASSERT(prTxCtrl); + + qmAdjustTcQuotas(prAdapter, &rTcqAdjust, &prTxCtrl->rTc); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + + for (u4Num = 0 ; u4Num < TC_NUM ; u4Num++) { + prTxCtrl->rTc.aucFreeBufferCount[u4Num] += rTcqAdjust.acVariation[u4Num]; + prTxCtrl->rTc.aucMaxNumOfBuffer[u4Num] += rTcqAdjust.acVariation[u4Num]; + + ASSERT(prTxCtrl->rTc.aucFreeBufferCount[u4Num] >= 0); + ASSERT(prTxCtrl->rTc.aucMaxNumOfBuffer[u4Num] >= 0); + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + + return WLAN_STATUS_SUCCESS; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief this function flushes all packets queued in STA/AC queue +* +* @param prAdapter Pointer to the Adapter structure. +* +* @retval WLAN_STATUS_SUCCESS Flushed successfully +*/ +/*----------------------------------------------------------------------------*/ + +WLAN_STATUS +nicTxFlush ( + IN P_ADAPTER_T prAdapter + ) +{ + P_MSDU_INFO_T prMsduInfo; + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + // ask Per STA/AC queue to be fllushed and return all queued packets + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); + prMsduInfo = qmFlushTxQueues(prAdapter); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); + + if(prMsduInfo != NULL) { + nicTxFreeMsduInfoPacket(prAdapter, prMsduInfo); + nicTxReturnMsduInfo(prAdapter, prMsduInfo); + } + + return WLAN_STATUS_SUCCESS; +} + + +#if CFG_ENABLE_FW_DOWNLOAD +/*----------------------------------------------------------------------------*/ +/*! +* \brief In this function, we'll write Command(CMD_INFO_T) into HIF. +* However this function is used for INIT_CMD. +* +* In order to avoid further maintainance issues, these 2 functions are separated +* +* @param prAdapter Pointer to the Adapter structure. +* @param prPacketInfo Pointer of CMD_INFO_T +* @param ucTC Specify the resource of TC +* +* @retval WLAN_STATUS_SUCCESS Bus access ok. +* @retval WLAN_STATUS_FAILURE Bus access fail. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicTxInitCmd ( + IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN UINT_8 ucTC + ) +{ + P_INIT_HIF_TX_HEADER_T prInitTxHeader; + UINT_16 u2OverallBufferLength; + PUINT_8 pucOutputBuf = (PUINT_8)NULL; /* Pointer to Transmit Data Structure Frame */ + UINT_32 ucPortIdx; + P_TX_CTRL_T prTxCtrl; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(ucTC == TC0_INDEX); + + prTxCtrl = &prAdapter->rTxCtrl; + pucOutputBuf = prTxCtrl->pucTxCoalescingBufPtr; + prInitTxHeader = (P_INIT_HIF_TX_HEADER_T)prCmdInfo->pucInfoBuffer; + + // <1> Compose the Header of Transmit Data Structure for CMD Packet + u2OverallBufferLength = TFCB_FRAME_PAD_TO_DW( + (prCmdInfo->u2InfoBufLen) & (UINT_16)HIF_TX_HDR_TX_BYTE_COUNT_MASK); + + prInitTxHeader->u2TxByteCount = u2OverallBufferLength; + prInitTxHeader->ucEtherTypeOffset = 0; + prInitTxHeader->ucCSflags = 0; + + // <2> Assign Data Port + if (ucTC != TC4_INDEX) { + ucPortIdx = 0; + } + else { // Broadcast/multicast data packets + ucPortIdx = 1; + } + + // <3> Copy CMD Header to command buffer (by using pucCoalescingBufCached) + kalMemCopy((PVOID)&pucOutputBuf[0], + (PVOID)prCmdInfo->pucInfoBuffer, + prCmdInfo->u2InfoBufLen); + + ASSERT(u2OverallBufferLength <= prAdapter->u4CoalescingBufCachedSize); + + // <4> Write frame to data port + HAL_WRITE_TX_PORT(prAdapter, + ucPortIdx, + (UINT_32)u2OverallBufferLength, + (PUINT_8)pucOutputBuf, + (UINT_32)prAdapter->u4CoalescingBufCachedSize); + + return WLAN_STATUS_SUCCESS; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief In this function, we'll reset TX resource counter to initial value used +* in F/W download state +* +* @param prAdapter Pointer to the Adapter structure. +* +* @retval WLAN_STATUS_SUCCESS Reset is done successfully. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicTxInitResetResource ( + IN P_ADAPTER_T prAdapter + ) +{ + P_TX_CTRL_T prTxCtrl; + + DEBUGFUNC("nicTxInitResetResource"); + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + + prTxCtrl->rTc.aucMaxNumOfBuffer[TC0_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC0; + prTxCtrl->rTc.aucFreeBufferCount[TC0_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC0; + + prTxCtrl->rTc.aucMaxNumOfBuffer[TC1_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC1; + prTxCtrl->rTc.aucFreeBufferCount[TC1_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC1; + + prTxCtrl->rTc.aucMaxNumOfBuffer[TC2_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC2; + prTxCtrl->rTc.aucFreeBufferCount[TC2_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC2; + + prTxCtrl->rTc.aucMaxNumOfBuffer[TC3_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC3; + prTxCtrl->rTc.aucFreeBufferCount[TC3_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC3; + + prTxCtrl->rTc.aucMaxNumOfBuffer[TC4_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC4; + prTxCtrl->rTc.aucFreeBufferCount[TC4_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC4; + + prTxCtrl->rTc.aucMaxNumOfBuffer[TC5_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC5; + prTxCtrl->rTc.aucFreeBufferCount[TC5_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC5; + + return WLAN_STATUS_SUCCESS; + +} + +#endif + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief this function enqueues MSDU_INFO_T into queue management, +* or command queue +* +* @param prAdapter Pointer to the Adapter structure. +* prMsduInfo Pointer to MSDU +* +* @retval WLAN_STATUS_SUCCESS Reset is done successfully. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicTxEnqueueMsdu ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ) +{ + P_TX_CTRL_T prTxCtrl; + P_MSDU_INFO_T prNextMsduInfo, prRetMsduInfo, prMsduInfoHead; + QUE_T qDataPort0, qDataPort1; + P_CMD_INFO_T prCmdInfo; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prTxCtrl = &prAdapter->rTxCtrl; + ASSERT(prTxCtrl); + + QUEUE_INITIALIZE(&qDataPort0); + QUEUE_INITIALIZE(&qDataPort1); + + /* check how many management frame are being queued */ + while(prMsduInfo) { + prNextMsduInfo = (P_MSDU_INFO_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prMsduInfo); + + QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prMsduInfo) = NULL; + + if(prMsduInfo->eSrc == TX_PACKET_MGMT) { + // MMPDU: force stick to TC4 + prMsduInfo->ucTC = TC4_INDEX; + + QUEUE_INSERT_TAIL(&qDataPort1, (P_QUE_ENTRY_T)prMsduInfo); + } + else { + QUEUE_INSERT_TAIL(&qDataPort0, (P_QUE_ENTRY_T)prMsduInfo); + } + + prMsduInfo = prNextMsduInfo; + } + + if(qDataPort0.u4NumElem) { + /* send to QM */ + KAL_SPIN_LOCK_DECLARATION(); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); + prRetMsduInfo = qmEnqueueTxPackets(prAdapter, (P_MSDU_INFO_T)QUEUE_GET_HEAD(&qDataPort0)); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); + + /* post-process for dropped packets */ + if(prRetMsduInfo != NULL) { // unable to enqueue + nicTxFreeMsduInfoPacket(prAdapter, prRetMsduInfo); + nicTxReturnMsduInfo(prAdapter, prRetMsduInfo); + } + } + + if(qDataPort1.u4NumElem) { + prMsduInfoHead = (P_MSDU_INFO_T)QUEUE_GET_HEAD(&qDataPort1); + + if(qDataPort1.u4NumElem > nicTxGetFreeCmdCount(prAdapter)) { + // not enough descriptors for sending + u4Status = WLAN_STATUS_FAILURE; + + // free all MSDUs + while(prMsduInfoHead) { + prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY(&prMsduInfoHead->rQueEntry); + + if (prMsduInfoHead->pfTxDoneHandler != NULL) { + prMsduInfoHead->pfTxDoneHandler(prAdapter, prMsduInfoHead, TX_RESULT_DROPPED_IN_DRIVER); + } + + + cnmMgtPktFree(prAdapter, prMsduInfoHead); + + prMsduInfoHead = prNextMsduInfo; + } + } + else { + /* send to command queue */ + while(prMsduInfoHead) { + prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY(&prMsduInfoHead->rQueEntry); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); + QUEUE_REMOVE_HEAD(&prAdapter->rFreeCmdList, prCmdInfo, P_CMD_INFO_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); + + if (prCmdInfo) { + GLUE_INC_REF_CNT(prTxCtrl->i4TxMgmtPendingNum); + + kalMemZero(prCmdInfo, sizeof(CMD_INFO_T)); + + prCmdInfo->eCmdType = COMMAND_TYPE_MANAGEMENT_FRAME; + prCmdInfo->u2InfoBufLen = prMsduInfoHead->u2FrameLength; + prCmdInfo->pucInfoBuffer = NULL; + prCmdInfo->prPacket = (P_NATIVE_PACKET)prMsduInfoHead; + prCmdInfo->ucStaRecIndex = prMsduInfoHead->ucStaRecIndex; + prCmdInfo->eNetworkType = prMsduInfoHead->ucNetworkType; + prCmdInfo->pfCmdDoneHandler = NULL; + prCmdInfo->pfCmdTimeoutHandler = NULL; + prCmdInfo->fgIsOid = FALSE; + prCmdInfo->fgSetQuery = TRUE; + prCmdInfo->fgNeedResp = FALSE; + + kalEnqueueCommand(prAdapter->prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + } + else { + /* Cmd free count is larger than expected, but allocation fail. */ + ASSERT(0); + + u4Status = WLAN_STATUS_FAILURE; + cnmMgtPktFree(prAdapter, prMsduInfoHead); + } + + prMsduInfoHead = prNextMsduInfo; + } + } + } + + /* indicate service thread for sending */ + if(prTxCtrl->i4TxMgmtPendingNum > 0 + || kalGetTxPendingFrameCount(prAdapter->prGlueInfo) > 0) { + kalSetEvent(prAdapter->prGlueInfo); + } + + return u4Status; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief this function returns available count in command queue +* +* @param prAdapter Pointer to the Adapter structure. +* +* @retval +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 +nicTxGetFreeCmdCount ( + IN P_ADAPTER_T prAdapter + ) +{ + ASSERT(prAdapter); + + return prAdapter->rFreeCmdList.u4NumElem; +} + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/nic/que_mgt.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/nic/que_mgt.c new file mode 100755 index 000000000000..ae10d8f186a8 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/nic/que_mgt.c @@ -0,0 +1,4786 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/nic/que_mgt.c#1 $ +*/ + +/*! \file "que_mgt.c" + \brief TX/RX queues management + + The main tasks of queue management include TC-based HIF TX flow control, + adaptive TC quota adjustment, HIF TX grant scheduling, Power-Save + forwarding control, RX packet reordering, and RX BA agreement management. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: que_mgt.c $ + * + * 02 20 2012 yuche.tsai + * [ALPS00239286] [Need Patch] [Volunteer Patch] + * Ignore BSS operating mode check while composing beacon frame.. + * + * 11 19 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Add xlog for tx + * + * 11 18 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Fix xlog format to hex format + * + * 11 17 2011 tsaiyuan.hsu + * [WCXRP00001115] [MT6620 Wi-Fi][DRV] avoid deactivating staRec when changing state 3 to 3. + * avoid deactivating staRec when changing state from 3 to 3. + * + * 11 11 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug msg for xlog. + * + * 11 10 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters of ar and bb for xlog. + * + * 11 10 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Use short name for xlog. + * + * 11 10 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Modify the QM xlog level and remove LOG_FUNC. + * + * 11 10 2011 chinglan.wang + * NULL + * [WiFi WPS]Can't switch to new AP via WPS PBC when there existing a connection to another AP. + * + * 11 09 2011 chinglan.wang + * NULL + * [WiFi direct]Can't make P2P connect via PBC. + * + * 11 08 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Add xlog function. + * + * 11 04 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters and periodically dump counters for Xlog debugging. + * + * 11 01 2011 chinglan.wang + * NULL + * Modify the Wi-Fi method of the flush TX queue when disconnect the AP. + * If disconnect the AP and flush all the data frame in the TX queue, WPS cannot do the 4-way handshake to connect to the AP.. + * + * 10 25 2011 wh.su + * [WCXRP00001059] [MT6620 Wi-Fi][Driver][P2P] Fixed sometimes data (1x) will not indicate to upper layer due ba check un-expect + * let the Rx BA accept even the sta not valid. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 08 02 2011 yuche.tsai + * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, TX deauth to a disconnecting device issue. + * Support TX Deauth while tearing down a station connection. + * + * 07 07 2011 eddie.chen + * [WCXRP00000834] [MT6620 Wi-Fi][DRV] Send 1x packet when peer STA is in PS. + * Add setEvent when free quota is updated. + * + * 07 05 2011 eddie.chen + * [WCXRP00000834] [MT6620 Wi-Fi][DRV] Send 1x packet when peer STA is in PS. + * Send 1x when peer STA is in PS. + * + * 06 27 2011 tsaiyuan.hsu + * [WCXRP00000816] [MT6620 Wi-Fi][Driver] add control to enable rx data dump or not + * add control to enable rx data dump by packet type. + * + * 05 31 2011 eddie.chen + * [WCXRP00000753] [MT5931 Wi-Fi][DRV] Adjust QM for MT5931 + * Fix the QM quota in MT5931. + * + * 05 11 2011 eddie.chen + * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet + * Fix dest type when GO packet copying. + * + * 05 09 2011 yuche.tsai + * [WCXRP00000712] [Volunteer Patch][MT6620][Driver] Sending deauth issue when Hot spot is disabled. (GO is dissolved) + * Deauth frame is not bound to network active status. + * + * 05 09 2011 eddie.chen + * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet + * Check free number before copying broadcast packet. + * + * 05 09 2011 eddie.chen + * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet + * Check free number before copying broadcast packet. + * + * 04 14 2011 eddie.chen + * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning + * Check the SW RFB free. Fix the compile warning.. + * + * 04 12 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix the sta index in processing security frame + * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 + * Add debug message. + * + * 04 11 2011 yuche.tsai + * [WCXRP00000627] [Volunteer Patch][MT6620][Driver] Pending MMPUD of P2P Network may crash system issue. + * Fix kernel panic issue when MMPDU of P2P is pending in driver after WLAN module removed. + * + * 04 07 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Add debug. + * + * 04 07 2011 eddie.chen + * [WCXRP00000527] [MT6620 Wi-Fi][FW/Driver] Clean buffered packet when BSS is inactive or disconnected[WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Remove packet when BSS is inactive + * + * 04 07 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix for sigma. + * + * 03 28 2011 eddie.chen + * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning + * Fix Klocwork warning. + * + * 03 28 2011 eddie.chen + * [WCXRP00000602] [MT6620 Wi-Fi][DRV] Fix wmm parameters in beacon for BOW + * Fix wmm parameters in beacon for BOW. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 15 2011 eddie.chen + * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter + * Add sw debug counter for QM. + * + * 02 23 2011 eddie.chen + * [WCXRP00000463] [MT6620 Wi-Fi][FW/Driver][Hotspot] Cannot update WMM PS STA's partital bitmap + * Fix parsing WMM INFO and bmp delivery bitmap definition. + * + * 02 17 2011 eddie.chen + * [WCXRP00000458] [MT6620 Wi-Fi][Driver] BOW Concurrent - ProbeResp was exist in other channel + * 1) Chnage GetFrameAction decision when BSS is absent. + * 2) Check channel and resource in processing ProbeRequest + * + * 02 08 2011 eddie.chen + * [WCXRP00000426] [MT6620 Wi-Fi][FW/Driver] Add STA aging timeout and defualtHwRatein AP mode + * Add event STA agint timeout + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. + * + * 01 24 2011 eddie.chen + * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets + * Remove comments. + * + * 01 24 2011 eddie.chen + * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets + * Add destination decision in AP mode. + * + * 01 14 2011 wh.su + * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out[WCXRP00000326] [MT6620][Wi-Fi][Driver] check in the binary format gl_sec.o.new instead of use change type!!! + * Allow 802.1x can be send even the net is not active due the drver / fw sync issue. + * + * 01 13 2011 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, +Add per station flow control when STA is in PS + * Fix typo and compile error. + * + * 01 12 2011 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, +Add per station flow control when STA is in PS + * Fix WMM parameter condition for STA + * + * 01 12 2011 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, +Add per station flow control when STA is in PS + * 1) Check Bss if support QoS before adding WMMIE + * 2) Check if support prAdapter->rWifiVar QoS and uapsd in flow control + * + * 01 12 2011 george.huang + * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability + * Update MQM for WMM IE generation method + * + * 01 11 2011 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, +Add per station flow control when STA is in PS + + * Add per STA flow control when STA is in PS mode + * + * 01 03 2011 george.huang + * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function + * update prStaRec->fgIsUapsdSupported flag. + * + * 12 29 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, +Add per station flow control when STA is in PS + + * Add WMM parameter for broadcast. + * + * 12 29 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, +Add per station flow control when STA is in PS + + * 1) PS flow control event + * + * 2) WMM IE in beacon, assoc resp, probe resp + * + * 12 23 2010 george.huang + * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function + * 1. update WMM IE parsing, with ASSOC REQ handling + * 2. extend U-APSD parameter passing from driver to FW + * + * 10 14 2010 wh.su + * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out + * use the #14 and modify the add code for check MMPDU. + * + * 10 14 2010 wh.su + * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out + * only MMPDU not check the netActive flag. + * + * 10 14 2010 wh.su + * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out + * not check the netActive flag for mgmt . + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by ENUM_NETWORK_TYPE_INDEX_T only + * remove ENUM_NETWORK_TYPE_T definitions + * + * 09 21 2010 kevin.huang + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * Eliminate Linux Compile Warning + * + * 08 30 2010 yarco.yang + * NULL + * Fixed klockwork error message + * + * 08 18 2010 yarco.yang + * NULL + * 1. Fixed HW checksum offload function not work under Linux issue. + * 2. Add debug message. + * + * 08 10 2010 yarco.yang + * NULL + * Code refine + * + * 08 06 2010 yarco.yang + * NULL + * Update qmGetFrameAction() to allow P2P MGMT frame w/o STA_Record still can perform TX action + * + * 07 26 2010 cp.wu + * + * AIS-FSM FIX: return channel privilege even when the privilege is not granted yet + * QM: qmGetFrameAction() won't assert when corresponding STA-REC index is not found + * + * 07 20 2010 yarco.yang + * + * Add to SetEvent when BSS is from Absent to Present or STA from PS to Awake + * + * 07 16 2010 yarco.yang + * + * 1. Support BSS Absence/Presence Event + * 2. Support STA change PS mode Event + * 3. Support BMC forwarding for AP mode. + * + * 07 14 2010 yarco.yang + * + * 1. Remove CFG_MQM_MIGRATION + * 2. Add CMD_UPDATE_WMM_PARMS command + * + * 07 13 2010 yarco.yang + * + * [WPD00003849] + * [MT6620 and MT5931] SW Migration, add qmGetFrameAction() API for CMD Queue Processing + * + * 07 09 2010 yarco.yang + * + * [MT6620 and MT5931] SW Migration: Add ADDBA support + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * . + * + * 07 06 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Use fgInUse instead of fgIsValid for De-queue judgement + * + * 07 06 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * For MMPDU, STA_REC will be decided by caller module + * + * 07 06 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Add MGMT Packet type for HIF_TX_HEADER + * + * 06 29 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * replace g_rQM with Adpater->rQM + * + * 06 25 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add API in que_mgt to retrieve sta-rec index for security frames. + * + * 06 23 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Merge g_arStaRec[] into adapter->arStaRec[] + * + * 06 21 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Support CFG_MQM_MIGRATION flag + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 03 31 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Refined the debug msg + * + * 03 30 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * comment out one assertion which refer to undefined data member. + * + * 03 30 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Enabled adaptive TC resource control + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port + * +* 03 17 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Changed STA_REC index determination rules (DA=BMCAST always --> STA_REC_INDEX_BMCAST) + * + * 03 11 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Fixed buffer leak when processing BAR frames + * + * 03 02 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * For TX packets with STA_REC index = STA_REC_INDEX_NOT_FOUND, use TC5 + * + * 03 01 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Fixed STA_REC index determination bug (fgIsValid shall be checked) + * + * 02 25 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Refined function qmDetermineStaRecIndex() for BMCAST packets + * + * 02 25 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Enabled multi-STA TX path with fairness + * + * 02 24 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Enabled dynamically activating and deactivating STA_RECs + * + * 02 24 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Added code for dynamic activating and deactivating STA_RECs. + * + * 01 13 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Enabled the 802.1x path + * + * 01 13 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Enabled the Burst_End Indication mechanism +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-12-14 15:01:37 GMT MTK02468 +** Fixed casting for qmAddRxBaEntry() +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-12-10 16:51:03 GMT mtk02752 +** remove SD1_SD3.. flag +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-12-09 14:07:25 GMT MTK02468 +** Added RX buffer reordering functions +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-12-04 13:34:16 GMT MTK02468 +** Modified Flush Queue function to let queues be reinitialized +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-12-04 13:18:25 GMT MTK02468 +** Added flushing per-Type queues code +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-12-02 23:39:49 GMT MTK02468 +** Added Debug msgs and fixed incorrect assert +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-11-26 23:50:27 GMT MTK02468 +** Bug fixing (qmDequeueTxPackets local variable initialization) +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-11-26 09:39:25 GMT mtk02752 +** correct and surpress PREfast warning +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-11-23 22:10:55 GMT mtk02468 +** Used SD1_SD3_DATAPATH_INTEGRATION +** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-11-23 22:02:30 GMT mtk02468 +** Initial version +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +__KAL_INLINE__ VOID +qmDetermineStaRecIndex( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ); + +__KAL_INLINE__ VOID +qmDequeueTxPacketsFromPerStaQueues( + IN P_ADAPTER_T prAdapter, + OUT P_QUE_T prQue, + IN UINT_8 ucTC, + IN UINT_8 ucCurrentAvailableQuota, + IN UINT_8 ucTotalQuota + ); + +__KAL_INLINE__ VOID +qmDequeueTxPacketsFromPerTypeQueues( + IN P_ADAPTER_T prAdapter, + OUT P_QUE_T prQue, + IN UINT_8 ucTC, + IN UINT_8 ucMaxNum + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Init Queue Managment for TX +* +* \param[in] (none) +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +qmInit( + IN P_ADAPTER_T prAdapter + ) +{ + UINT_32 u4QueArrayIdx; + UINT_32 i; + + P_QUE_MGT_T prQM = &prAdapter->rQM; + + //DbgPrint("QM: Enter qmInit()\n"); +#if CFG_SUPPORT_QOS + prAdapter->rWifiVar.fgSupportQoS = TRUE; +#else + prAdapter->rWifiVar.fgSupportQoS = FALSE; +#endif + +#if CFG_SUPPORT_AMPDU_RX + prAdapter->rWifiVar.fgSupportAmpduRx = TRUE; +#else + prAdapter->rWifiVar.fgSupportAmpduRx = FALSE; +#endif + +#if CFG_SUPPORT_AMPDU_TX + prAdapter->rWifiVar.fgSupportAmpduTx = TRUE; +#else + prAdapter->rWifiVar.fgSupportAmpduTx = FALSE; +#endif + +#if CFG_SUPPORT_TSPEC + prAdapter->rWifiVar.fgSupportTspec = TRUE; +#else + prAdapter->rWifiVar.fgSupportTspec = FALSE; +#endif + +#if CFG_SUPPORT_UAPSD + prAdapter->rWifiVar.fgSupportUAPSD= TRUE; +#else + prAdapter->rWifiVar.fgSupportUAPSD = FALSE; +#endif + +#if CFG_SUPPORT_UL_PSMP + prAdapter->rWifiVar.fgSupportULPSMP = TRUE; +#else + prAdapter->rWifiVar.fgSupportULPSMP = FALSE; +#endif + + //4 <2> Initialize other TX queues (queues not in STA_RECs) + for(u4QueArrayIdx = 0; u4QueArrayIdx < NUM_OF_PER_TYPE_TX_QUEUES; u4QueArrayIdx++){ + QUEUE_INITIALIZE(&(prQM->arTxQueue[u4QueArrayIdx])); + } + + //4 <3> Initialize the RX BA table and RX queues + /* Initialize the RX Reordering Parameters and Queues */ + for(u4QueArrayIdx = 0; u4QueArrayIdx < CFG_NUM_OF_RX_BA_AGREEMENTS; u4QueArrayIdx++){ + prQM->arRxBaTable[u4QueArrayIdx].fgIsValid = FALSE; + QUEUE_INITIALIZE(&(prQM->arRxBaTable[u4QueArrayIdx].rReOrderQue)); + prQM->arRxBaTable[u4QueArrayIdx].u2WinStart = 0xFFFF; + prQM->arRxBaTable[u4QueArrayIdx].u2WinEnd = 0xFFFF; + + prQM->arRxBaTable[u4QueArrayIdx].fgIsWaitingForPktWithSsn = FALSE; + + } + prQM->ucRxBaCount = 0; + +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + //4 <4> Initialize TC resource control variables + for(i = 0; i < TC_NUM; i++){ + prQM->au4AverageQueLen[i] = 0; + } + prQM->u4TimeToAdjustTcResource = QM_INIT_TIME_TO_ADJUST_TC_RSC; + prQM->u4TimeToUpdateQueLen = QM_INIT_TIME_TO_UPDATE_QUE_LEN; + +// ASSERT(prQM->u4TimeToAdjust && prQM->u4TimeToUpdateQueLen); + + prQM->au4CurrentTcResource[TC0_INDEX] = NIC_TX_BUFF_COUNT_TC0; + prQM->au4CurrentTcResource[TC1_INDEX] = NIC_TX_BUFF_COUNT_TC1; + prQM->au4CurrentTcResource[TC2_INDEX] = NIC_TX_BUFF_COUNT_TC2; + prQM->au4CurrentTcResource[TC3_INDEX] = NIC_TX_BUFF_COUNT_TC3; + prQM->au4CurrentTcResource[TC4_INDEX] = NIC_TX_BUFF_COUNT_TC4; /* Not adjustable (TX port 1)*/ + prQM->au4CurrentTcResource[TC5_INDEX] = NIC_TX_BUFF_COUNT_TC5; + + prQM->au4MinReservedTcResource[TC0_INDEX] = QM_MIN_RESERVED_TC0_RESOURCE; + prQM->au4MinReservedTcResource[TC1_INDEX] = QM_MIN_RESERVED_TC1_RESOURCE; + prQM->au4MinReservedTcResource[TC2_INDEX] = QM_MIN_RESERVED_TC2_RESOURCE; + prQM->au4MinReservedTcResource[TC3_INDEX] = QM_MIN_RESERVED_TC3_RESOURCE; + prQM->au4MinReservedTcResource[TC4_INDEX] = QM_MIN_RESERVED_TC4_RESOURCE; /* Not adjustable (TX port 1)*/ + prQM->au4MinReservedTcResource[TC5_INDEX] = QM_MIN_RESERVED_TC5_RESOURCE; + + + prQM->au4GuaranteedTcResource[TC0_INDEX] = QM_GUARANTEED_TC0_RESOURCE; + prQM->au4GuaranteedTcResource[TC1_INDEX] = QM_GUARANTEED_TC1_RESOURCE; + prQM->au4GuaranteedTcResource[TC2_INDEX] = QM_GUARANTEED_TC2_RESOURCE; + prQM->au4GuaranteedTcResource[TC3_INDEX] = QM_GUARANTEED_TC3_RESOURCE; + prQM->au4GuaranteedTcResource[TC4_INDEX] = QM_GUARANTEED_TC4_RESOURCE; + prQM->au4GuaranteedTcResource[TC5_INDEX] = QM_GUARANTEED_TC5_RESOURCE; + + prQM->fgTcResourcePostAnnealing = FALSE; + + ASSERT(QM_INITIAL_RESIDUAL_TC_RESOURCE < 64); +#endif + +#if QM_TEST_MODE + prQM->u4PktCount = 0; + +#if QM_TEST_FAIR_FORWARDING + + prQM->u4CurrentStaRecIndexToEnqueue = 0; + { + UINT_8 aucMacAddr[MAC_ADDR_LEN]; + P_STA_RECORD_T prStaRec; + + /* Irrelevant in case this STA is an AIS AP (see qmDetermineStaRecIndex()) */ + aucMacAddr[0] = 0x11; + aucMacAddr[1] = 0x22; + aucMacAddr[2] = 0xAA; + aucMacAddr[3] = 0xBB; + aucMacAddr[4] = 0xCC; + aucMacAddr[5] = 0xDD; + + prStaRec = &prAdapter->arStaRec[1]; + ASSERT(prStaRec); + + prStaRec->fgIsValid = TRUE; + prStaRec->fgIsQoS = TRUE; + prStaRec->fgIsInPS = FALSE; + prStaRec->ucPsSessionID = 0xFF; + prStaRec->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; + prStaRec->fgIsAp = TRUE; + COPY_MAC_ADDR((prStaRec)->aucMacAddr,aucMacAddr); + + } + +#endif + +#endif + +#if QM_FORWARDING_FAIRNESS +{ + UINT_32 i; + for (i=0; i < NUM_OF_PER_STA_TX_QUEUES; i++){ + prQM->au4ForwardCount[i] = 0; + prQM->au4HeadStaRecIndex[i] = 0; + } +} +#endif + +} + +#if QM_TEST_MODE +VOID +qmTestCases( + IN P_ADAPTER_T prAdapter + ) +{ + P_QUE_MGT_T prQM = &prAdapter->rQM; + + DbgPrint("QM: ** TEST MODE **\n"); + + if(QM_TEST_STA_REC_DETERMINATION){ + if(prAdapter->arStaRec[0].fgIsValid){ + prAdapter->arStaRec[0].fgIsValid = FALSE; + DbgPrint("QM: (Test) Deactivate STA_REC[0]\n"); + } + else{ + prAdapter->arStaRec[0].fgIsValid = TRUE; + DbgPrint("QM: (Test) Activate STA_REC[0]\n"); + } + } + + if(QM_TEST_STA_REC_DEACTIVATION){ + /* Note that QM_STA_REC_HARD_CODING shall be set to 1 for this test */ + + if(prAdapter->arStaRec[0].fgIsValid){ + + DbgPrint("QM: (Test) Deactivate STA_REC[0]\n"); + qmDeactivateStaRec(prAdapter,0); + } + else{ + + UINT_8 aucMacAddr[MAC_ADDR_LEN]; + + /* Irrelevant in case this STA is an AIS AP (see qmDetermineStaRecIndex()) */ + aucMacAddr[0] = 0x11; + aucMacAddr[1] = 0x22; + aucMacAddr[2] = 0xAA; + aucMacAddr[3] = 0xBB; + aucMacAddr[4] = 0xCC; + aucMacAddr[5] = 0xDD; + + DbgPrint("QM: (Test) Activate STA_REC[0]\n"); + qmActivateStaRec( + prAdapter, /* Adapter pointer */ + 0, /* STA_REC index from FW */ + TRUE, /* fgIsQoS */ + NETWORK_TYPE_AIS_INDEX, /* Network type */ + TRUE, /* fgIsAp */ + aucMacAddr /* MAC address */ + ); + } + } + + if(QM_TEST_FAIR_FORWARDING){ + if(prAdapter->arStaRec[1].fgIsValid){ + prQM->u4CurrentStaRecIndexToEnqueue ++; + prQM->u4CurrentStaRecIndexToEnqueue %= 2; + DbgPrint("QM: (Test) Switch to STA_REC[%ld]\n", prQM->u4CurrentStaRecIndexToEnqueue); + } + } + +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Activate a STA_REC +* +* \param[in] prAdapter Pointer to the Adapter instance +* \param[in] u4StaRecIdx The index of the STA_REC +* \param[in] fgIsQoS Set to TRUE if this is a QoS STA +* \param[in] pucMacAddr The MAC address of the STA +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +qmActivateStaRec( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec + ) +{ + + //4 <1> Deactivate first + ASSERT(prStaRec); + + if(prStaRec->fgIsValid){ /* The STA_REC has been activated */ + DBGLOG(QM, WARN, ("QM: (WARNING) Activating a STA_REC which has been activated \n")); + DBGLOG(QM, WARN, ("QM: (WARNING) Deactivating a STA_REC before re-activating \n")); + qmDeactivateStaRec(prAdapter, prStaRec->ucIndex); // To flush TX/RX queues and del RX BA agreements + } + + //4 <2> Activate the STA_REC + /* Init the STA_REC */ + prStaRec->fgIsValid = TRUE; + prStaRec->fgIsInPS = FALSE; + prStaRec->ucPsSessionID = 0xFF; + prStaRec->fgIsAp = (IS_AP_STA(prStaRec)) ? TRUE : FALSE;; + + /* Done in qmInit() or qmDeactivateStaRec() */ +#if 0 + /* At the beginning, no RX BA agreements have been established */ + for(i =0; iaprRxReorderParamRefTbl)[i] = NULL; + } +#endif + + DBGLOG(QM, INFO, ("QM: +STA[%ld]\n", prStaRec->ucIndex)); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Deactivate a STA_REC +* +* \param[in] prAdapter Pointer to the Adapter instance +* \param[in] u4StaRecIdx The index of the STA_REC +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +qmDeactivateStaRec( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4StaRecIdx + ) +{ + P_STA_RECORD_T prStaRec; + UINT_32 i; + P_MSDU_INFO_T prFlushedTxPacketList = NULL; + + ASSERT(u4StaRecIdx < CFG_NUM_OF_STA_RECORD); + + prStaRec = &prAdapter->arStaRec[u4StaRecIdx]; + ASSERT(prStaRec); + + //4<1> Flush TX queues + prFlushedTxPacketList = qmFlushStaTxQueues(prAdapter, u4StaRecIdx); + + if(prFlushedTxPacketList){ + wlanProcessQueuedMsduInfo(prAdapter, prFlushedTxPacketList); + } + + //4 <2> Flush RX queues and delete RX BA agreements + for(i =0; i < CFG_RX_MAX_BA_TID_NUM; i++){ + /* Delete the RX BA entry with TID = i */ + qmDelRxBaEntry(prAdapter, (UINT_8)u4StaRecIdx, (UINT_8)i, FALSE); + } + + //4 <3> Deactivate the STA_REC + prStaRec->fgIsValid = FALSE; + prStaRec->fgIsInPS = FALSE; + + DBGLOG(QM, INFO, ("QM: -STA[%ld]\n", u4StaRecIdx)); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Deactivate a STA_REC +* +* \param[in] prAdapter Pointer to the Adapter instance +* \param[in] u4StaRecIdx The index of the network +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ + +VOID +qmFreeAllByNetType( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx + ) +{ + + P_QUE_MGT_T prQM; + P_QUE_T prQue; + QUE_T rNeedToFreeQue; + QUE_T rTempQue; + P_QUE_T prNeedToFreeQue; + P_QUE_T prTempQue; + P_MSDU_INFO_T prMsduInfo; + + + prQM = &prAdapter->rQM; + prQue = &prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST]; + + QUEUE_INITIALIZE(&rNeedToFreeQue); + QUEUE_INITIALIZE(&rTempQue); + + prNeedToFreeQue = &rNeedToFreeQue; + prTempQue = &rTempQue; + + QUEUE_MOVE_ALL(prTempQue, prQue); + + QUEUE_REMOVE_HEAD(prTempQue, prMsduInfo, P_MSDU_INFO_T); + while (prMsduInfo) { + + if(prMsduInfo->ucNetworkType == eNetworkTypeIdx) { + QUEUE_INSERT_TAIL(prNeedToFreeQue, (P_QUE_ENTRY_T)prMsduInfo); + } + else { + QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T)prMsduInfo); + } + + QUEUE_REMOVE_HEAD(prTempQue, prMsduInfo, P_MSDU_INFO_T); + } + if(QUEUE_IS_NOT_EMPTY(prNeedToFreeQue)) { + wlanProcessQueuedMsduInfo(prAdapter, (P_MSDU_INFO_T)QUEUE_GET_HEAD(prNeedToFreeQue)); + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Flush all TX queues +* +* \param[in] (none) +* +* \return The flushed packets (in a list of MSDU_INFOs) +*/ +/*----------------------------------------------------------------------------*/ +P_MSDU_INFO_T +qmFlushTxQueues( + IN P_ADAPTER_T prAdapter + ) +{ + UINT_8 ucStaArrayIdx; + UINT_8 ucQueArrayIdx; + + P_MSDU_INFO_T prMsduInfoListHead; + P_MSDU_INFO_T prMsduInfoListTail; + + P_QUE_MGT_T prQM = &prAdapter->rQM; + + DBGLOG(QM, TRACE, ("QM: Enter qmFlushTxQueues()\n")); + + prMsduInfoListHead = NULL; + prMsduInfoListTail = NULL; + + /* Concatenate all MSDU_INFOs in per-STA queues */ + for(ucStaArrayIdx = 0; ucStaArrayIdx < CFG_NUM_OF_STA_RECORD; ucStaArrayIdx++){ + + /* Always check each STA_REC when flushing packets no matter it is inactive or active */ + #if 0 + if(!prAdapter->arStaRec[ucStaArrayIdx].fgIsValid){ + continue; /* Continue to check the next STA_REC */ + } + #endif + + for(ucQueArrayIdx = 0; ucQueArrayIdx < NUM_OF_PER_STA_TX_QUEUES; ucQueArrayIdx++){ + if(QUEUE_IS_EMPTY(&(prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]))){ + continue; /* Continue to check the next TX queue of the same STA */ + } + + if(!prMsduInfoListHead){ + + /* The first MSDU_INFO is found */ + prMsduInfoListHead =(P_MSDU_INFO_T) + QUEUE_GET_HEAD(&prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]); + prMsduInfoListTail =(P_MSDU_INFO_T) + QUEUE_GET_TAIL(&prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]); + } + else{ + /* Concatenate the MSDU_INFO list with the existing list */ + QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, + QUEUE_GET_HEAD(&prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx])); + + prMsduInfoListTail = (P_MSDU_INFO_T) + QUEUE_GET_TAIL(&prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]); + } + + QUEUE_INITIALIZE(&prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]); + } + } + + /* Flush per-Type queues */ + for(ucQueArrayIdx = 0; ucQueArrayIdx < NUM_OF_PER_TYPE_TX_QUEUES; ucQueArrayIdx++){ + + if(QUEUE_IS_EMPTY(&(prQM->arTxQueue[ucQueArrayIdx]))){ + continue; /* Continue to check the next TX queue of the same STA */ + } + + if(!prMsduInfoListHead){ + + /* The first MSDU_INFO is found */ + prMsduInfoListHead =(P_MSDU_INFO_T) + QUEUE_GET_HEAD(&prQM->arTxQueue[ucQueArrayIdx]); + prMsduInfoListTail =(P_MSDU_INFO_T) + QUEUE_GET_TAIL(&prQM->arTxQueue[ucQueArrayIdx]); + } + else{ + /* Concatenate the MSDU_INFO list with the existing list */ + QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, + QUEUE_GET_HEAD(&prQM->arTxQueue[ucQueArrayIdx])); + + prMsduInfoListTail = (P_MSDU_INFO_T) + QUEUE_GET_TAIL(&prQM->arTxQueue[ucQueArrayIdx]); + } + + QUEUE_INITIALIZE(&prQM->arTxQueue[ucQueArrayIdx]); + + } + + if(prMsduInfoListTail){ + /* Terminate the MSDU_INFO list with a NULL pointer */ + QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, NULL); + } + + return prMsduInfoListHead; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Flush TX packets for a particular STA +* +* \param[in] u4StaRecIdx STA_REC index +* +* \return The flushed packets (in a list of MSDU_INFOs) +*/ +/*----------------------------------------------------------------------------*/ +P_MSDU_INFO_T +qmFlushStaTxQueues( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4StaRecIdx + ) +{ + UINT_8 ucQueArrayIdx; + P_MSDU_INFO_T prMsduInfoListHead; + P_MSDU_INFO_T prMsduInfoListTail; + P_STA_RECORD_T prStaRec; + + DBGLOG(QM, TRACE, ("QM: Enter qmFlushStaTxQueues(%ld)\n", u4StaRecIdx)); + + ASSERT(u4StaRecIdx < CFG_NUM_OF_STA_RECORD); + + prMsduInfoListHead = NULL; + prMsduInfoListTail = NULL; + + prStaRec = &prAdapter->arStaRec[u4StaRecIdx]; + ASSERT(prStaRec); + + /* No matter whether this is an activated STA_REC, do flush */ +#if 0 + if(!prStaRec->fgIsValid){ + return NULL; + } +#endif + + /* Concatenate all MSDU_INFOs in TX queues of this STA_REC */ + for(ucQueArrayIdx = 0; ucQueArrayIdx < NUM_OF_PER_STA_TX_QUEUES; ucQueArrayIdx++){ + if(QUEUE_IS_EMPTY(&(prStaRec->arTxQueue[ucQueArrayIdx]))){ + continue; + } + + if(!prMsduInfoListHead){ + /* The first MSDU_INFO is found */ + prMsduInfoListHead =(P_MSDU_INFO_T) + QUEUE_GET_HEAD(&prStaRec->arTxQueue[ucQueArrayIdx]); + prMsduInfoListTail =(P_MSDU_INFO_T) + QUEUE_GET_TAIL(&prStaRec->arTxQueue[ucQueArrayIdx]); } + else{ + /* Concatenate the MSDU_INFO list with the existing list */ + QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, + QUEUE_GET_HEAD(&prStaRec->arTxQueue[ucQueArrayIdx])); + + prMsduInfoListTail = + (P_MSDU_INFO_T)QUEUE_GET_TAIL(&prStaRec->arTxQueue[ucQueArrayIdx]); + } + + QUEUE_INITIALIZE(&prStaRec->arTxQueue[ucQueArrayIdx]); + + } + +#if 0 + if(prMsduInfoListTail){ + /* Terminate the MSDU_INFO list with a NULL pointer */ + QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, nicGetPendingStaMMPDU(prAdapter, (UINT_8)u4StaRecIdx)); + } + else { + prMsduInfoListHead = nicGetPendingStaMMPDU(prAdapter, (UINT_8)u4StaRecIdx); + } +#endif + + return prMsduInfoListHead; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Flush RX packets +* +* \param[in] (none) +* +* \return The flushed packets (in a list of SW_RFBs) +*/ +/*----------------------------------------------------------------------------*/ +P_SW_RFB_T +qmFlushRxQueues( + IN P_ADAPTER_T prAdapter + ) +{ + UINT_32 i; + P_SW_RFB_T prSwRfbListHead; + P_SW_RFB_T prSwRfbListTail; + P_QUE_MGT_T prQM = &prAdapter->rQM; + + prSwRfbListHead = prSwRfbListTail = NULL; + + DBGLOG(QM, TRACE, ("QM: Enter qmFlushRxQueues()\n")); + + for(i =0; iarRxBaTable[i].rReOrderQue))){ + if(!prSwRfbListHead){ + + /* The first MSDU_INFO is found */ + prSwRfbListHead =(P_SW_RFB_T) + QUEUE_GET_HEAD(&(prQM->arRxBaTable[i].rReOrderQue)); + prSwRfbListTail =(P_SW_RFB_T) + QUEUE_GET_TAIL(&(prQM->arRxBaTable[i].rReOrderQue)); + } + else{ + /* Concatenate the MSDU_INFO list with the existing list */ + QM_TX_SET_NEXT_MSDU_INFO(prSwRfbListTail, + QUEUE_GET_HEAD(&(prQM->arRxBaTable[i].rReOrderQue))); + + prSwRfbListTail = (P_SW_RFB_T) + QUEUE_GET_TAIL(&(prQM->arRxBaTable[i].rReOrderQue)); + } + + QUEUE_INITIALIZE(&(prQM->arRxBaTable[i].rReOrderQue)); + + } + else{ + continue; + } + } + + if(prSwRfbListTail){ + /* Terminate the MSDU_INFO list with a NULL pointer */ + QM_TX_SET_NEXT_SW_RFB(prSwRfbListTail, NULL); + } + return prSwRfbListHead; + +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Flush RX packets with respect to a particular STA +* +* \param[in] u4StaRecIdx STA_REC index +* \param[in] u4Tid TID +* +* \return The flushed packets (in a list of SW_RFBs) +*/ +/*----------------------------------------------------------------------------*/ +P_SW_RFB_T +qmFlushStaRxQueue( + IN P_ADAPTER_T prAdapter, + IN UINT_32 u4StaRecIdx, + IN UINT_32 u4Tid + ) +{ + //UINT_32 i; + P_SW_RFB_T prSwRfbListHead; + P_SW_RFB_T prSwRfbListTail; + P_RX_BA_ENTRY_T prReorderQueParm; + P_STA_RECORD_T prStaRec; + + DBGLOG(QM, TRACE, ("QM: Enter qmFlushStaRxQueues(%ld)\n", u4StaRecIdx)); + + prSwRfbListHead = prSwRfbListTail = NULL; + + prStaRec = &prAdapter->arStaRec[u4StaRecIdx]; + ASSERT(prStaRec); + + /* No matter whether this is an activated STA_REC, do flush */ +#if 0 + if(!prStaRec->fgIsValid){ + return NULL; + } +#endif + + /* Obtain the RX BA Entry pointer */ + prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[u4Tid]); + + /* Note: For each queued packet, prCurrSwRfb->eDst equals RX_PKT_DESTINATION_HOST */ + if(prReorderQueParm){ + + if(QUEUE_IS_NOT_EMPTY(&(prReorderQueParm->rReOrderQue))){ + + prSwRfbListHead =(P_SW_RFB_T) + QUEUE_GET_HEAD(&(prReorderQueParm->rReOrderQue)); + prSwRfbListTail =(P_SW_RFB_T) + QUEUE_GET_TAIL(&(prReorderQueParm->rReOrderQue)); + + + QUEUE_INITIALIZE(&(prReorderQueParm->rReOrderQue)); + + } + } + + if(prSwRfbListTail){ + /* Terminate the MSDU_INFO list with a NULL pointer */ + QM_TX_SET_NEXT_SW_RFB(prSwRfbListTail, NULL); + } + return prSwRfbListHead; + + +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Enqueue TX packets +* +* \param[in] prMsduInfoListHead Pointer to the list of TX packets +* +* \return The freed packets, which are not enqueued +*/ +/*----------------------------------------------------------------------------*/ +P_MSDU_INFO_T +qmEnqueueTxPackets( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfoListHead + ) +{ + P_MSDU_INFO_T prMsduInfoReleaseList; + P_MSDU_INFO_T prCurrentMsduInfo; + P_MSDU_INFO_T prNextMsduInfo; + + P_STA_RECORD_T prStaRec; + P_QUE_T prTxQue; + QUE_T rNotEnqueuedQue; + + + UINT_8 ucPacketType; + UINT_8 ucTC; + P_QUE_MGT_T prQM = &prAdapter->rQM; + UINT_8 aucNextUP[WMM_AC_INDEX_NUM] = { 1 /* BEtoBK*/, 1 /*na*/, 0/*VItoBE*/ , 4 /*VOtoVI*/}; + + DBGLOG(QM, LOUD, ("Enter qmEnqueueTxPackets\n")); + + ASSERT(prMsduInfoListHead); + +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + { + //UINT_32 i; + //4 <0> Update TC resource control related variables + /* Keep track of the queue length */ + if (--prQM->u4TimeToUpdateQueLen == 0){ + prQM->u4TimeToUpdateQueLen = QM_INIT_TIME_TO_UPDATE_QUE_LEN; + qmUpdateAverageTxQueLen(prAdapter); + } + } +#endif + + /* Push TX packets into STA_REC (for UNICAST) or prAdapter->rQM (for BMCAST) */ + prStaRec = NULL; + prMsduInfoReleaseList = NULL; + prCurrentMsduInfo = NULL; + QUEUE_INITIALIZE(&rNotEnqueuedQue); + prNextMsduInfo = prMsduInfoListHead; + + do{ + P_BSS_INFO_T prBssInfo; + BOOLEAN fgCheckACMAgain; + ENUM_WMM_ACI_T eAci = WMM_AC_BE_INDEX; + prCurrentMsduInfo = prNextMsduInfo; + prNextMsduInfo = QM_TX_GET_NEXT_MSDU_INFO(prCurrentMsduInfo); + ucTC = TC1_INDEX; + + //4 <1> Lookup the STA_REC index + /* The ucStaRecIndex will be set in this function */ + qmDetermineStaRecIndex(prAdapter, prCurrentMsduInfo); + ucPacketType = HIF_TX_PACKET_TYPE_DATA; + + DBGLOG(QM, LOUD , ("***** ucStaRecIndex = %d *****\n", + prCurrentMsduInfo->ucStaRecIndex)); + + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prCurrentMsduInfo->ucNetworkType]); + + if(IS_NET_ACTIVE(prAdapter, prCurrentMsduInfo->ucNetworkType)) { + + switch (prCurrentMsduInfo->ucStaRecIndex){ + case STA_REC_INDEX_BMCAST: + prTxQue = &prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST]; + ucTC = TC5_INDEX; +#if 0 + if(prCurrentMsduInfo->ucNetworkType == NETWORK_TYPE_P2P_INDEX + && prCurrentMsduInfo->eSrc != TX_PACKET_MGMT + ) { + if(LINK_IS_EMPTY(&prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].rStaRecOfClientList)) { + prTxQue = &rNotEnqueuedQue; + TX_INC_CNT(&prAdapter->rTxCtrl,TX_AP_BORADCAST_DROP); + } + } +#endif + + QM_DBG_CNT_INC(prQM, QM_DBG_CNT_23); + break; + + case STA_REC_INDEX_NOT_FOUND: + ucTC = TC5_INDEX; + + if(prCurrentMsduInfo->eSrc == TX_PACKET_FORWARDING) { + + /* if the packet is the forward type. the packet should be freed */ + DBGLOG(QM, TRACE, ("Forwarding packet but Sta is STA_REC_INDEX_NOT_FOUND\n")); + //prTxQue = &rNotEnqueuedQue; + } + prTxQue = &prQM->arTxQueue[TX_QUEUE_INDEX_NO_STA_REC]; + QM_DBG_CNT_INC(prQM, QM_DBG_CNT_24); + + break; + + default: + prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prCurrentMsduInfo->ucStaRecIndex); + + ASSERT(prStaRec); + ASSERT(prStaRec->fgIsValid); + + if(prCurrentMsduInfo->ucUserPriority < 8) { + QM_DBG_CNT_INC(prQM, prCurrentMsduInfo->ucUserPriority + 15); + /* QM_DBG_CNT_15 */ /* QM_DBG_CNT_16 */ /* QM_DBG_CNT_17 */ /* QM_DBG_CNT_18 */ + /* QM_DBG_CNT_19 */ /* QM_DBG_CNT_20 */ /* QM_DBG_CNT_21 */ /* QM_DBG_CNT_22 */ + } + + eAci = WMM_AC_BE_INDEX; + do { + fgCheckACMAgain = FALSE; + if (prStaRec->fgIsQoS){ + switch(prCurrentMsduInfo->ucUserPriority){ + case 1: + case 2: + prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC0]; + ucTC = TC0_INDEX; + eAci = WMM_AC_BK_INDEX; + break; + case 0: + case 3: + prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC1]; + ucTC = TC1_INDEX; + eAci = WMM_AC_BE_INDEX; + break; + case 4: + case 5: + prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC2]; + ucTC = TC2_INDEX; + eAci = WMM_AC_VI_INDEX; + break; + case 6: + case 7: + prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC3]; + ucTC = TC3_INDEX; + eAci = WMM_AC_VO_INDEX; + break; + default: + prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC1]; + ucTC = TC1_INDEX; + eAci = WMM_AC_BE_INDEX; + ASSERT(0); + break; + } + if(prBssInfo->arACQueParms[eAci].fgIsACMSet && eAci != WMM_AC_BK_INDEX) { + prCurrentMsduInfo->ucUserPriority = aucNextUP[eAci]; + fgCheckACMAgain = TRUE; + } + } + else{ + prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC1]; + ucTC = TC1_INDEX; + } + } + while(fgCheckACMAgain); + + //LOG_FUNC ("QoS %u UP %u TC %u",prStaRec->fgIsQoS,prCurrentMsduInfo->ucUserPriority, ucTC); + + break; /*default */ + } /* switch (prCurrentMsduInfo->ucStaRecIndex) */ + + if(prCurrentMsduInfo->eSrc == TX_PACKET_FORWARDING) { + if(prTxQue->u4NumElem > 32) { + DBGLOG(QM, INFO, ("Drop the Packet for full Tx queue (forwarding) Bss %u\n", prCurrentMsduInfo->ucNetworkType)); + prTxQue = &rNotEnqueuedQue; + TX_INC_CNT(&prAdapter->rTxCtrl,TX_FORWARD_OVERFLOW_DROP); + } + } + + } + else { + + DBGLOG(QM, INFO, ("Drop the Packet for inactive Bss %u\n", prCurrentMsduInfo->ucNetworkType)); + QM_DBG_CNT_INC(prQM, QM_DBG_CNT_31); + prTxQue = &rNotEnqueuedQue; + TX_INC_CNT(&prAdapter->rTxCtrl,TX_INACTIVE_BSS_DROP); + } + + //4 <3> Fill the MSDU_INFO for constructing HIF TX header + + /* TODO: Fill MSDU_INFO according to the network type, + * EtherType, and STA status (for PS forwarding control). + */ + + /* Note that the Network Type Index and STA_REC index are determined in + * qmDetermineStaRecIndex(prCurrentMsduInfo). + */ + QM_TX_SET_MSDU_INFO_FOR_DATA_PACKET( + prCurrentMsduInfo, /* MSDU_INFO ptr */ + ucTC, /* TC tag */ + ucPacketType, /* Packet Type */ + 0, /* Format ID */ + prCurrentMsduInfo->fgIs802_1x, /* Flag 802.1x */ + prCurrentMsduInfo->fgIs802_11, /* Flag 802.11 */ + 0, /* PAL LLH */ + 0, /* ACL SN */ + PS_FORWARDING_TYPE_NON_PS, /* PS Forwarding Type */ + 0 /* PS Session ID */ + ); + + //4 <4> Enqueue the packet + QUEUE_INSERT_TAIL(prTxQue, (P_QUE_ENTRY_T)prCurrentMsduInfo); + + +#if QM_TEST_MODE + if (++prQM->u4PktCount == QM_TEST_TRIGGER_TX_COUNT){ + prQM->u4PktCount = 0; + qmTestCases(prAdapter); + } + +#endif + + DBGLOG(QM, LOUD, ("Current queue length = %u\n", prTxQue->u4NumElem)); + }while(prNextMsduInfo); + + if( QUEUE_IS_NOT_EMPTY(&rNotEnqueuedQue) ) { + QM_TX_SET_NEXT_MSDU_INFO((P_MSDU_INFO_T)QUEUE_GET_TAIL(&rNotEnqueuedQue), NULL); + prMsduInfoReleaseList = (P_MSDU_INFO_T)QUEUE_GET_HEAD(&rNotEnqueuedQue); + } + + + return prMsduInfoReleaseList; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Determine the STA_REC index for a packet +* +* \param[in] prMsduInfo Pointer to the packet +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static VOID +qmDetermineStaRecIndex( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ) +{ + UINT_32 i; + + P_STA_RECORD_T prTempStaRec; + //P_QUE_MGT_T prQM = &prAdapter->rQM; + + prTempStaRec = NULL; + + ASSERT(prMsduInfo); + + //4 <1> DA = BMCAST + if (IS_BMCAST_MAC_ADDR(prMsduInfo->aucEthDestAddr)){ + /* For intrastructure mode and P2P (playing as a GC), BMCAST frames shall be sent to the AP. + * FW shall take care of this. The host driver is not able to distinguish these cases. */ + prMsduInfo->ucStaRecIndex = STA_REC_INDEX_BMCAST; + DBGLOG(QM, LOUD, ("TX with DA = BMCAST\n")); + return; + } + + + //4 <2> Check if an AP STA is present + for (i = 0; i < CFG_NUM_OF_STA_RECORD; i++){ + prTempStaRec = &(prAdapter->arStaRec[i]); + + if((prTempStaRec->ucNetTypeIndex == prMsduInfo->ucNetworkType) + && (prTempStaRec->fgIsAp) + && (prTempStaRec->fgIsValid)){ + prMsduInfo->ucStaRecIndex = prTempStaRec->ucIndex; + return; + } + } + + + + + //4 <3> Not BMCAST, No AP --> Compare DA (i.e., to see whether this is a unicast frame to a client) + for (i = 0; i < CFG_NUM_OF_STA_RECORD; i++){ + prTempStaRec = &(prAdapter->arStaRec[i]); + if (prTempStaRec->fgIsValid){ + if (EQUAL_MAC_ADDR(prTempStaRec->aucMacAddr, prMsduInfo->aucEthDestAddr)){ + prMsduInfo->ucStaRecIndex = prTempStaRec->ucIndex; + return; + } + } + } + + + //4 <4> No STA found, Not BMCAST --> Indicate NOT_FOUND to FW + prMsduInfo->ucStaRecIndex = STA_REC_INDEX_NOT_FOUND; + DBGLOG(QM, LOUD, ("QM: TX with STA_REC_INDEX_NOT_FOUND\n")); + + +#if (QM_TEST_MODE && QM_TEST_FAIR_FORWARDING) + prMsduInfo->ucStaRecIndex = (UINT_8)prQM->u4CurrentStaRecIndexToEnqueue; +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Dequeue TX packets from a STA_REC for a particular TC +* +* \param[out] prQue The queue to put the dequeued packets +* \param[in] ucTC The TC index (TC0_INDEX to TC5_INDEX) +* \param[in] ucMaxNum The maximum amount of dequeued packets +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static VOID +qmDequeueTxPacketsFromPerStaQueues( + IN P_ADAPTER_T prAdapter, + OUT P_QUE_T prQue, + IN UINT_8 ucTC, + IN UINT_8 ucCurrentQuota, + IN UINT_8 ucTotalQuota + ) +{ + +#if QM_FORWARDING_FAIRNESS + UINT_32 i; /* Loop for */ + + PUINT_32 pu4HeadStaRecIndex; /* The Head STA index */ + PUINT_32 pu4HeadStaRecForwardCount; /* The total forwarded packets for the head STA */ + + P_STA_RECORD_T prStaRec; /* The current focused STA */ + P_BSS_INFO_T prBssInfo; /* The Bss for current focused STA */ + P_QUE_T prCurrQueue; /* The current TX queue to dequeue */ + P_MSDU_INFO_T prDequeuedPkt; /* The dequeued packet */ + + UINT_32 u4ForwardCount; /* To remember the total forwarded packets for a STA */ + UINT_32 u4MaxForwardCount; /* The maximum number of packets a STA can forward */ + UINT_32 u4Resource; /* The TX resource amount */ + + BOOLEAN fgChangeHeadSta; /* Whether a new head STA shall be determined at the end of the function */ + P_QUE_MGT_T prQM = &prAdapter->rQM; + + PUINT_8 pucFreeQuota; + + DBGLOG(QM, LOUD, ("Enter qmDequeueTxPacketsFromPerStaQueues (TC = %u)\n", ucTC)); + + ASSERT(ucTC == TC0_INDEX || ucTC == TC1_INDEX || + ucTC == TC2_INDEX || ucTC == TC3_INDEX || + ucTC == TC4_INDEX + ); + + if(!ucCurrentQuota){ + DBGLOG(TX, LOUD, ("@@@@@ TC = %u ucCurrentQuota = %u @@@@@\n", + ucTC, ucCurrentQuota)); + return; + } + + u4Resource = ucCurrentQuota; + + //4 <1> Determine the head STA + /* The head STA shall be an active STA */ + + pu4HeadStaRecIndex = &(prQM->au4HeadStaRecIndex[ucTC]); + pu4HeadStaRecForwardCount = &(prQM->au4ForwardCount[ucTC]); + + DBGLOG(QM, LOUD, ("(Fairness) TID = %u Init Head STA = %u Resource = %u\n", + ucTC, *pu4HeadStaRecIndex, u4Resource)); + + + /* From STA[x] to STA[x+1] to STA[x+2] to ... to STA[x] */ + for (i=0; i < CFG_NUM_OF_STA_RECORD + 1; i++){ + prStaRec = &prAdapter->arStaRec[(*pu4HeadStaRecIndex)]; + ASSERT(prStaRec); + + /* Only Data frame (1x was not included) will be queued in */ + if (prStaRec->fgIsValid){ + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + ASSERT(prBssInfo->ucNetTypeIndex == prStaRec->ucNetTypeIndex); + + /* Determine how many packets the head STA is allowed to send in a round */ + + QM_DBG_CNT_INC(prQM, QM_DBG_CNT_25); + u4MaxForwardCount = ucTotalQuota; +#if CFG_ENABLE_WIFI_DIRECT + + pucFreeQuota = NULL; + if(prStaRec->fgIsInPS && (ucTC!=TC4_INDEX)) { + // TODO: Change the threshold in coorperation with the PS forwarding mechanism + // u4MaxForwardCount = ucTotalQuota; + /* Per STA flow control when STA in PS mode */ + /* The PHASE 1: only update from ucFreeQuota (now) */ + /* XXX The PHASE 2: Decide by ucFreeQuota and ucBmpDeliveryAC (per queue ) aucFreeQuotaPerQueue[] */ + /* NOTE: other method to set u4Resource */ + + if(prStaRec->fgIsQoS && prStaRec->fgIsUapsdSupported + /* && prAdapter->rWifiVar.fgSupportQoS + && prAdapter->rWifiVar.fgSupportUAPSD*/) { + + if( prStaRec->ucBmpTriggerAC & BIT(ucTC)) { + u4MaxForwardCount = prStaRec->ucFreeQuotaForDelivery; + pucFreeQuota = &prStaRec->ucFreeQuotaForDelivery; + } + else { + u4MaxForwardCount = prStaRec->ucFreeQuotaForNonDelivery; + pucFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery; + } + + } + else { + ASSERT(prStaRec->ucFreeQuotaForDelivery == 0); + u4MaxForwardCount = prStaRec->ucFreeQuotaForNonDelivery; + pucFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery; + } + + } /* fgIsInPS */ +#endif /* CFG_ENABLE_WIFI_DIRECT */ + +#if CFG_ENABLE_WIFI_DIRECT + if(prBssInfo->fgIsNetAbsent && (ucTC!=TC4_INDEX)) { + if(u4MaxForwardCount > prBssInfo->ucBssFreeQuota) { + u4MaxForwardCount = prBssInfo->ucBssFreeQuota; + } + } + +#endif /* CFG_ENABLE_WIFI_DIRECT */ + + /* Determine whether the head STA can continue to forward packets in this round */ + if((*pu4HeadStaRecForwardCount) < u4MaxForwardCount){ + break; + } + + } /* prStaRec->fgIsValid */ + else{ + /* The current Head STA has been deactivated, so search for a new head STA */ + prStaRec = NULL; + prBssInfo = NULL; + (*pu4HeadStaRecIndex) ++; + (*pu4HeadStaRecIndex) %= CFG_NUM_OF_STA_RECORD; + + /* Reset the forwarding count before searching (since this is for a new selected STA) */ + (*pu4HeadStaRecForwardCount) = 0; + } + } /* i < CFG_NUM_OF_STA_RECORD + 1 */ + + /* All STA_RECs are inactive, so exit */ + if (!prStaRec){ + /* Under concurrent, it is possible that there is no candidcated STA.*/ + //DBGLOG(TX, EVENT, ("All STA_RECs are inactive\n")); + return; + } + + DBGLOG(QM, LOUD, ("(Fairness) TID = %u Round Head STA = %lu\n", + ucTC, *pu4HeadStaRecIndex)); + + //4 <2> Dequeue packets from the head STA + + prCurrQueue = &prStaRec->arTxQueue[ucTC]; + prDequeuedPkt = NULL; + fgChangeHeadSta = FALSE; + + while(prCurrQueue){ + + +#if QM_DEBUG_COUNTER + + if(ucTC <= TC4_INDEX) { + if(QUEUE_IS_EMPTY(prCurrQueue)) { + QM_DBG_CNT_INC(prQM, ucTC); + /* QM_DBG_CNT_00 */ /* QM_DBG_CNT_01 */ /* QM_DBG_CNT_02 */ /* QM_DBG_CNT_03 */ /* QM_DBG_CNT_04 */ + } + if(u4Resource == 0) { + QM_DBG_CNT_INC(prQM, ucTC + 5); + /* QM_DBG_CNT_05 */ /* QM_DBG_CNT_06 */ /* QM_DBG_CNT_07 */ /* QM_DBG_CNT_08 */ /* QM_DBG_CNT_09 */ + } + if(((*pu4HeadStaRecForwardCount) >= u4MaxForwardCount)) { + QM_DBG_CNT_INC(prQM, ucTC + 10); + /* QM_DBG_CNT_10 */ /* QM_DBG_CNT_11 */ /* QM_DBG_CNT_12 */ /* QM_DBG_CNT_13 */ /* QM_DBG_CNT_14 */ + } + } +#endif + + + /* Three cases to break: (1) No resource (2) No packets (3) Fairness */ + if (QUEUE_IS_EMPTY(prCurrQueue) || ((*pu4HeadStaRecForwardCount) >= u4MaxForwardCount)){ + fgChangeHeadSta = TRUE; + break; + } + else if (u4Resource == 0){ + break; + } + else{ + + QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T); +#if DBG && 0 + LOG_FUNC("Deq0 TC %d queued %u net %u mac len %u len %u Type %u 1x %u 11 %u\n", + prDequeuedPkt->ucTC, + prCurrQueue->u4NumElem, + prDequeuedPkt->ucNetworkType, + prDequeuedPkt->ucMacHeaderLength, + prDequeuedPkt->u2FrameLength, + prDequeuedPkt->ucPacketType, + prDequeuedPkt->fgIs802_1x, + prDequeuedPkt->fgIs802_11 ); + + LOG_FUNC("Dest Mac: " MACSTR "\n", + MAC2STR(prDequeuedPkt->aucEthDestAddr)); + +#if LINUX + { + struct sk_buff *prSkb = (struct sk_buff *) prDequeuedPkt->prPacket; + dumpMemory8((PUINT_8)prSkb->data,prSkb->len); + } +#endif + +#endif + + ASSERT(prDequeuedPkt->ucTC == ucTC); + + if(!QUEUE_IS_EMPTY(prCurrQueue)) { + /* XXX: check all queues for STA */ + prDequeuedPkt->ucPsForwardingType = PS_FORWARDING_MORE_DATA_ENABLED; + } + + QUEUE_INSERT_TAIL(prQue,(P_QUE_ENTRY_T)prDequeuedPkt); + u4Resource--; + (*pu4HeadStaRecForwardCount) ++; + + +#if CFG_ENABLE_WIFI_DIRECT + /* XXX The PHASE 2: decrease from aucFreeQuotaPerQueue[] */ + if(prStaRec->fgIsInPS && (ucTC!=TC4_INDEX)) { + ASSERT(pucFreeQuota); + ASSERT(*pucFreeQuota>0); + if(*pucFreeQuota>0) { + *pucFreeQuota = *pucFreeQuota - 1; + } + } +#endif /* CFG_ENABLE_WIFI_DIRECT */ + +#if CFG_ENABLE_WIFI_DIRECT + if(prBssInfo->fgIsNetAbsent && (ucTC!=TC4_INDEX)) { + if(prBssInfo->ucBssFreeQuota>0) { + prBssInfo->ucBssFreeQuota--; + } + } +#endif /* CFG_ENABLE_WIFI_DIRECT */ + + } + } + + if (*pu4HeadStaRecForwardCount){ + DBGLOG(QM, LOUD, ("TC = %u Round Head STA = %lu, u4HeadStaRecForwardCount = %lu\n", ucTC, *pu4HeadStaRecIndex, (*pu4HeadStaRecForwardCount))); + } + +#if QM_BURST_END_INFO_ENABLED + /* Let FW know which packet is the last one dequeued from the STA */ + if (prDequeuedPkt){ + prDequeuedPkt->fgIsBurstEnd = TRUE; + } +#endif + + + //4 <3> Dequeue from the other STAs if there is residual TX resource + + /* Check all of the STAs to continue forwarding packets (including the head STA) */ + for (i= 0; i< CFG_NUM_OF_STA_RECORD; i++){ + /* Break in case no reasource is available */ + if (u4Resource == 0){ + break; + } + + /* The current head STA will be examined when i = CFG_NUM_OF_STA_RECORD-1 */ + prStaRec = &prAdapter->arStaRec[((*pu4HeadStaRecIndex) + i + 1) % CFG_NUM_OF_STA_RECORD]; + ASSERT(prStaRec); + + if (prStaRec->fgIsValid) { + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + ASSERT(prBssInfo->ucNetTypeIndex == prStaRec->ucNetTypeIndex); + + DBGLOG(QM, LOUD, ("(Fairness) TID = %u Sharing STA = %u Resource = %lu\n", + ucTC, prStaRec->ucIndex, u4Resource)); + + prCurrQueue = &prStaRec->arTxQueue[ucTC]; + u4ForwardCount = 0; + u4MaxForwardCount = ucTotalQuota; + +#if CFG_ENABLE_WIFI_DIRECT + pucFreeQuota = NULL; + if(prStaRec->fgIsInPS && (ucTC!=TC4_INDEX)) { + // TODO: Change the threshold in coorperation with the PS forwarding mechanism + // u4MaxForwardCount = ucTotalQuota; + /* Per STA flow control when STA in PS mode */ + /* The PHASE 1: only update from ucFreeQuota (now) */ + /* XXX The PHASE 2: Decide by ucFreeQuota and ucBmpDeliveryAC (per queue ) aucFreeQuotaPerQueue[] */ + /* NOTE: other method to set u4Resource */ + if(prStaRec->fgIsQoS && prStaRec->fgIsUapsdSupported + /* && prAdapter->rWifiVar.fgSupportQoS + && prAdapter->rWifiVar.fgSupportUAPSD*/) { + + if( prStaRec->ucBmpTriggerAC & BIT(ucTC)) { + u4MaxForwardCount = prStaRec->ucFreeQuotaForDelivery; + pucFreeQuota = &prStaRec->ucFreeQuotaForDelivery; + } + else { + u4MaxForwardCount = prStaRec->ucFreeQuotaForNonDelivery; + pucFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery; + } + + } + else { + ASSERT(prStaRec->ucFreeQuotaForDelivery == 0); + u4MaxForwardCount = prStaRec->ucFreeQuotaForNonDelivery; + pucFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery; + } + + } +#endif /* CFG_ENABLE_WIFI_DIRECT */ +#if CFG_ENABLE_WIFI_DIRECT + if(prBssInfo->fgIsNetAbsent && (ucTC!=TC4_INDEX)) { + if(u4MaxForwardCount > prBssInfo->ucBssFreeQuota) { + u4MaxForwardCount = prBssInfo->ucBssFreeQuota; + } + } + +#endif /* CFG_ENABLE_WIFI_DIRECT */ + } /* prStaRec->fgIsValid */ + else{ + prBssInfo = NULL; + /* Invalid STA, so check the next STA */ + continue; + } + + while(prCurrQueue){ + /* Three cases to break: (1) No resource (2) No packets (3) Fairness */ + if ((u4Resource == 0) || QUEUE_IS_EMPTY(prCurrQueue) || (u4ForwardCount >= u4MaxForwardCount)){ + break; + } + else{ + + QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T); + +#if DBG && 0 + DBGLOG(QM, LOUD, ("Deq0 TC %d queued %u net %u mac len %u len %u Type %u 1x %u 11 %u\n", + prDequeuedPkt->ucTC, + prCurrQueue->u4NumElem, + prDequeuedPkt->ucNetworkType, + prDequeuedPkt->ucMacHeaderLength, + prDequeuedPkt->u2FrameLength, + prDequeuedPkt->ucPacketType, + prDequeuedPkt->fgIs802_1x, + prDequeuedPkt->fgIs802_11 )); + + DBGLOG(QM, LOUD,("Dest Mac: " MACSTR "\n", + MAC2STR(prDequeuedPkt->aucEthDestAddr))); + +#if LINUX + { + struct sk_buff *prSkb = (struct sk_buff *) prDequeuedPkt->prPacket; + dumpMemory8((PUINT_8)prSkb->data,prSkb->len); + } +#endif + +#endif + + + ASSERT(prDequeuedPkt->ucTC == ucTC); + + if(!QUEUE_IS_EMPTY(prCurrQueue)) { + prDequeuedPkt->ucPsForwardingType = PS_FORWARDING_MORE_DATA_ENABLED; + } + + QUEUE_INSERT_TAIL(prQue,(P_QUE_ENTRY_T)prDequeuedPkt); + u4Resource--; + u4ForwardCount ++; + +#if CFG_ENABLE_WIFI_DIRECT + /* XXX The PHASE 2: decrease from aucFreeQuotaPerQueue[] */ + if(prStaRec->fgIsInPS && (ucTC!=TC4_INDEX)) { + ASSERT(pucFreeQuota); + ASSERT(*pucFreeQuota>0); + if(*pucFreeQuota>0) { + *pucFreeQuota = *pucFreeQuota - 1; + } + } +#endif /* CFG_ENABLE_WIFI_DIRECT */ + + +#if CFG_ENABLE_WIFI_DIRECT + ASSERT(prBssInfo->ucNetTypeIndex == prStaRec->ucNetTypeIndex); + if(prBssInfo->fgIsNetAbsent && (ucTC!=TC4_INDEX)) { + if(prBssInfo->ucBssFreeQuota>0) { + prBssInfo->ucBssFreeQuota--; + } + } +#endif /* CFG_ENABLE_WIFI_DIRECT */ + + } + } + +#if QM_BURST_END_INFO_ENABLED + /* Let FW know which packet is the last one dequeued from the STA */ + if (u4ForwardCount){ + prDequeuedPkt->fgIsBurstEnd = TRUE; + } +#endif + } + + + if (fgChangeHeadSta){ + (*pu4HeadStaRecIndex) ++; + (*pu4HeadStaRecIndex) %= CFG_NUM_OF_STA_RECORD; + (*pu4HeadStaRecForwardCount) = 0; + DBGLOG(QM, LOUD, ("(Fairness) TID = %u Scheduled Head STA = %lu Left Resource = %lu\n", + ucTC, (*pu4HeadStaRecIndex), u4Resource)); + } + + +/***************************************************************************************/ +#else + UINT_8 ucStaRecIndex; + P_STA_RECORD_T prStaRec; + P_QUE_T prCurrQueue; + UINT_8 ucPktCount; + P_MSDU_INFO_T prDequeuedPkt; + + DBGLOG(QM, LOUD, ("Enter qmDequeueTxPacketsFromPerStaQueues (TC = %u)\n", ucTC)); + + if (ucCurrentQuota == 0){ + return; + } + + //4 <1> Determine the queue index and the head STA + + /* The head STA */ + ucStaRecIndex = 0; /* TODO: Get the current head STA */ + prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, ucStaRecIndex); + ASSERT(prStaRec); + + if(prStaRec == NULL) { + return; + } + + /* The queue to pull out packets */ + ASSERT(ucTC == TC0_INDEX || ucTC == TC1_INDEX || + ucTC == TC2_INDEX || ucTC == TC3_INDEX || + ucTC == TC4_INDEX + ); + prCurrQueue = &prStaRec->arTxQueue[ucTC]; + + ucPktCount = ucCurrentQuota; + prDequeuedPkt = NULL; + + //4 <2> Dequeue packets for the head STA + while(TRUE){ + if (!(prStaRec->fgIsValid) || ucPktCount ==0 || QUEUE_IS_EMPTY(prCurrQueue)){ + break; + + } + else{ + + QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T); + //DbgPrint("QM: Remove Queue Head, TC= %d\n", prDequeuedPkt->ucTC); + ASSERT(prDequeuedPkt->ucTC == ucTC); + + QUEUE_INSERT_TAIL(prQue,(P_QUE_ENTRY_T)prDequeuedPkt); + ucPktCount--; + } + } + + //DbgPrint("QM: Remaining number of queued packets = %d\n", prCurrQueue->u4NumElem); + +#if QM_BURST_END_INFO_ENABLED + if (prDequeuedPkt){ + prDequeuedPkt->fgIsBurstEnd = TRUE; + } + +#endif + + //4 <3> Update scheduling info + /* TODO */ + + //4 <4> Utilize the remainaing TX opportunities for non-head STAs + /* TODO */ +#endif +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Dequeue TX packets from a per-Type-based Queue for a particular TC +* +* \param[out] prQue The queue to put the dequeued packets +* \param[in] ucTC The TC index (Shall always be TC5_INDEX) +* \param[in] ucMaxNum The maximum amount of dequeued packets +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static VOID +qmDequeueTxPacketsFromPerTypeQueues( + IN P_ADAPTER_T prAdapter, + OUT P_QUE_T prQue, + IN UINT_8 ucTC, + IN UINT_8 ucMaxNum + ) +{ + //UINT_8 ucQueIndex; + //UINT_8 ucStaRecIndex; + P_BSS_INFO_T prBssInfo; + P_BSS_INFO_T parBssInfo; + P_QUE_T prCurrQueue; + UINT_8 ucPktCount; + P_MSDU_INFO_T prDequeuedPkt; + P_MSDU_INFO_T prBurstEndPkt; + QUE_T rMergeQue; + P_QUE_T prMergeQue; + P_QUE_MGT_T prQM; + + DBGLOG(QM, LOUD, ("Enter qmDequeueTxPacketsFromPerTypeQueues (TC = %d, Max = %d)\n", ucTC, ucMaxNum)); + + /* TC5: Broadcast/Multicast data packets */ + ASSERT(ucTC == TC5_INDEX); + + if (ucMaxNum == 0){ + return; + } + + prQM = &prAdapter->rQM; + //4 <1> Determine the queue + + prCurrQueue = &prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST]; + ucPktCount = ucMaxNum; + prDequeuedPkt = NULL; + prBurstEndPkt = NULL; + + parBssInfo = prAdapter->rWifiVar.arBssInfo; + + QUEUE_INITIALIZE(&rMergeQue); + prMergeQue = &rMergeQue; + + //4 <2> Dequeue packets + while(TRUE){ + if(ucPktCount ==0 || QUEUE_IS_EMPTY(prCurrQueue)){ + break; + } + else{ + QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T); + ASSERT(prDequeuedPkt->ucTC == ucTC); + + ASSERT(prDequeuedPkt->ucNetworkType < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &parBssInfo[prDequeuedPkt->ucNetworkType]; + + if(IS_BSS_ACTIVE(prBssInfo)) { + if( !prBssInfo->fgIsNetAbsent){ + QUEUE_INSERT_TAIL(prQue,(P_QUE_ENTRY_T)prDequeuedPkt); + prBurstEndPkt = prDequeuedPkt; + ucPktCount--; + QM_DBG_CNT_INC(prQM, QM_DBG_CNT_26); +#if DBG && 0 + LOG_FUNC("DeqType TC %d queued %u net %u mac len %u len %u Type %u 1x %u 11 %u\n", + prDequeuedPkt->ucTC, + prCurrQueue->u4NumElem, + prDequeuedPkt->ucNetworkType, + prDequeuedPkt->ucMacHeaderLength, + prDequeuedPkt->u2FrameLength, + prDequeuedPkt->ucPacketType, + prDequeuedPkt->fgIs802_1x, + prDequeuedPkt->fgIs802_11 ); + + LOG_FUNC("Dest Mac: " MACSTR "\n", + MAC2STR(prDequeuedPkt->aucEthDestAddr)); + +#if LINUX + { + struct sk_buff *prSkb = (struct sk_buff *) prDequeuedPkt->prPacket; + dumpMemory8((PUINT_8)prSkb->data,prSkb->len); + } +#endif + +#endif + } + else { + QUEUE_INSERT_TAIL(prMergeQue,(P_QUE_ENTRY_T)prDequeuedPkt); + } + } + else { + QM_TX_SET_NEXT_MSDU_INFO(prDequeuedPkt, NULL); + wlanProcessQueuedMsduInfo(prAdapter,prDequeuedPkt); + } + } + } + + if(QUEUE_IS_NOT_EMPTY(prMergeQue)) { + QUEUE_CONCATENATE_QUEUES(prMergeQue, prCurrQueue); + QUEUE_MOVE_ALL(prCurrQueue, prMergeQue); + QM_TX_SET_NEXT_MSDU_INFO((P_MSDU_INFO_T)QUEUE_GET_TAIL(prCurrQueue), NULL); + } + +#if QM_BURST_END_INFO_ENABLED + if (prBurstEndPkt){ + prBurstEndPkt->fgIsBurstEnd = TRUE; + } +#endif +} /* qmDequeueTxPacketsFromPerTypeQueues */ + + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Dequeue TX packets to send to HIF TX +* +* \param[in] prTcqStatus Info about the maximum amount of dequeued packets +* +* \return The list of dequeued TX packets +*/ +/*----------------------------------------------------------------------------*/ +P_MSDU_INFO_T +qmDequeueTxPackets( + IN P_ADAPTER_T prAdapter, + IN P_TX_TCQ_STATUS_T prTcqStatus + ) +{ + + INT_32 i; + P_MSDU_INFO_T prReturnedPacketListHead; + QUE_T rReturnedQue; + + DBGLOG(QM, LOUD, ("Enter qmDequeueTxPackets\n")); + + QUEUE_INITIALIZE(&rReturnedQue); + + prReturnedPacketListHead = NULL; + + /* TC0 to TC4: AC0~AC3, 802.1x (commands packets are not handled by QM) */ + for(i = TC4_INDEX; i >= TC0_INDEX; i--){ + DBGLOG(QM, LOUD, ("Dequeue packets from Per-STA queue[%u]\n", i)); + + qmDequeueTxPacketsFromPerStaQueues( + prAdapter, + &rReturnedQue, + (UINT_8)i, + prTcqStatus->aucFreeBufferCount[i], + prTcqStatus->aucMaxNumOfBuffer[i] + ); + + /* The aggregate number of dequeued packets */ + DBGLOG(QM, LOUD, ("DQA)[%u](%lu)\n", i, rReturnedQue.u4NumElem)); + } + + + /* TC5 (BMCAST or STA-NOT-FOUND packets) */ + qmDequeueTxPacketsFromPerTypeQueues( + prAdapter, + &rReturnedQue, + TC5_INDEX, + prTcqStatus->aucFreeBufferCount[TC5_INDEX] + ); + + DBGLOG(QM, LOUD, ("Current total number of dequeued packets = %u\n", rReturnedQue.u4NumElem)); + + if (QUEUE_IS_NOT_EMPTY(&rReturnedQue)){ + prReturnedPacketListHead = (P_MSDU_INFO_T)QUEUE_GET_HEAD(&rReturnedQue); + QM_TX_SET_NEXT_MSDU_INFO((P_MSDU_INFO_T)QUEUE_GET_TAIL(&rReturnedQue), NULL); + } + + return prReturnedPacketListHead; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Adjust the TC quotas according to traffic demands +* +* \param[out] prTcqAdjust The resulting adjustment +* \param[in] prTcqStatus Info about the current TC quotas and counters +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +qmAdjustTcQuotas ( + IN P_ADAPTER_T prAdapter, + OUT P_TX_TCQ_ADJUST_T prTcqAdjust, + IN P_TX_TCQ_STATUS_T prTcqStatus + ) +{ +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + UINT_32 i; + P_QUE_MGT_T prQM = &prAdapter->rQM; + + /* Must initialize */ + for (i = 0; i < TC_NUM; i++){ + prTcqAdjust->acVariation[i]= 0; + } + + //4 <1> If TC resource is not just adjusted, exit directly + if (!prQM->fgTcResourcePostAnnealing){ + return; + } + + //4 <2> Adjust TcqStatus according to the updated prQM->au4CurrentTcResource + else{ + INT_32 i4TotalExtraQuota = 0; + INT_32 ai4ExtraQuota[TC_NUM]; + BOOLEAN fgResourceRedistributed = TRUE; + + /* Obtain the free-to-distribute resource */ + for (i = 0; i < TC_NUM; i++){ + ai4ExtraQuota[i] = (INT_32)prTcqStatus->aucMaxNumOfBuffer[i] - (INT_32)prQM->au4CurrentTcResource[i]; + + if (ai4ExtraQuota[i] > 0){ /* The resource shall be reallocated to other TCs */ + if (ai4ExtraQuota[i] > prTcqStatus->aucFreeBufferCount[i]){ + ai4ExtraQuota[i] = prTcqStatus->aucFreeBufferCount[i]; + fgResourceRedistributed = FALSE; + } + + i4TotalExtraQuota += ai4ExtraQuota[i]; + prTcqAdjust->acVariation[i] = (INT_8)(-ai4ExtraQuota[i]); + } + } + + /* Distribute quotas to TCs which need extra resource according to prQM->au4CurrentTcResource */ + for (i = 0; i < TC_NUM; i++){ + if (ai4ExtraQuota[i] < 0){ + if ((-ai4ExtraQuota[i]) > i4TotalExtraQuota){ + ai4ExtraQuota[i] = (-i4TotalExtraQuota); + fgResourceRedistributed = FALSE; + } + + i4TotalExtraQuota += ai4ExtraQuota[i]; + prTcqAdjust->acVariation[i] = (INT_8)(-ai4ExtraQuota[i]); + } + } + + /* In case some TC is waiting for TX Done, continue to adjust TC quotas upon TX Done */ + prQM->fgTcResourcePostAnnealing = (!fgResourceRedistributed); + +#if QM_PRINT_TC_RESOURCE_CTRL + DBGLOG(QM, LOUD, ("QM: Curr Quota [0]=%u [1]=%u [2]=%u [3]=%u [4]=%u [5]=%u\n", + prTcqStatus->aucFreeBufferCount[0], + prTcqStatus->aucFreeBufferCount[1], + prTcqStatus->aucFreeBufferCount[2], + prTcqStatus->aucFreeBufferCount[3], + prTcqStatus->aucFreeBufferCount[4], + prTcqStatus->aucFreeBufferCount[5] + )); +#endif + } + +#else + UINT_32 i; + for (i = 0; i < TC_NUM; i++){ + prTcqAdjust->acVariation[i]= 0; + } + +#endif +} + +#if QM_ADAPTIVE_TC_RESOURCE_CTRL +/*----------------------------------------------------------------------------*/ +/*! +* \brief Update the average TX queue length for the TC resource control mechanism +* +* \param (none) +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +qmUpdateAverageTxQueLen( + IN P_ADAPTER_T prAdapter + ) +{ + INT_32 u4CurrQueLen, i, k; + P_STA_RECORD_T prStaRec; + P_QUE_MGT_T prQM = &prAdapter->rQM; + + //4 <1> Update the queue lengths for TC0 to TC3 (skip TC4) and TC5 */ + for (i = 0; i < NUM_OF_PER_STA_TX_QUEUES - 1; i++){ + u4CurrQueLen = 0; + + for (k = 0; k < CFG_NUM_OF_STA_RECORD; k++){ + prStaRec = &prAdapter->arStaRec[k]; + ASSERT(prStaRec); + + /* If the STA is activated, get the queue length */ + if (prStaRec->fgIsValid && + (!prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex].fgIsNetAbsent) + ) + { + + u4CurrQueLen += (prStaRec->arTxQueue[i].u4NumElem); + } + } + + if (prQM->au4AverageQueLen[i] == 0){ + prQM->au4AverageQueLen[i] = (u4CurrQueLen << QM_QUE_LEN_MOVING_AVE_FACTOR); + } + else{ + prQM->au4AverageQueLen[i] -= (prQM->au4AverageQueLen[i] >> QM_QUE_LEN_MOVING_AVE_FACTOR); + prQM->au4AverageQueLen[i] += (u4CurrQueLen); + } + + } + + /* Update the queue length for TC5 (BMCAST) */ + u4CurrQueLen = prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST].u4NumElem; + + if (prQM->au4AverageQueLen[TC_NUM-1] == 0){ + prQM->au4AverageQueLen[TC_NUM-1] = (u4CurrQueLen << QM_QUE_LEN_MOVING_AVE_FACTOR); + } + else{ + prQM->au4AverageQueLen[TC_NUM-1] -= (prQM->au4AverageQueLen[TC_NUM-1] >> QM_QUE_LEN_MOVING_AVE_FACTOR); + prQM->au4AverageQueLen[TC_NUM-1] += (u4CurrQueLen); + } + + + //4 <2> Adjust TC resource assignment + /* Check whether it is time to adjust the TC resource assignment */ + if (--prQM->u4TimeToAdjustTcResource == 0){ + /* The last assignment has not been completely applied */ + if (prQM->fgTcResourcePostAnnealing){ + /* Upon the next qmUpdateAverageTxQueLen function call, do this check again */ + prQM->u4TimeToAdjustTcResource = 1; + } + + /* The last assignment has been applied */ + else{ + prQM->u4TimeToAdjustTcResource = QM_INIT_TIME_TO_ADJUST_TC_RSC; + qmReassignTcResource(prAdapter); + } + } + + /* Debug */ +#if QM_PRINT_TC_RESOURCE_CTRL + for (i=0; i= 100){ + DBGLOG(QM, LOUD, ("QM: QueLen [%ld %ld %ld %ld %ld %ld]\n", + QM_GET_TX_QUEUE_LEN(prAdapter, 0), + QM_GET_TX_QUEUE_LEN(prAdapter, 1), + QM_GET_TX_QUEUE_LEN(prAdapter, 2), + QM_GET_TX_QUEUE_LEN(prAdapter, 3), + QM_GET_TX_QUEUE_LEN(prAdapter, 4), + QM_GET_TX_QUEUE_LEN(prAdapter, 5) + )); + break; + } + } +#endif + +} + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Assign TX resource for each TC according to TX queue length and current assignment +* +* \param (none) +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +qmReassignTcResource( + IN P_ADAPTER_T prAdapter + ) +{ + INT_32 i4TotalResourceDemand = 0; + UINT_32 u4ResidualResource = 0; + UINT_32 i; + INT_32 ai4PerTcResourceDemand[TC_NUM]; + UINT_32 u4ShareCount = 0; + UINT_32 u4Share = 0 ; + P_QUE_MGT_T prQM = &prAdapter->rQM; + + /* Note: After the new assignment is obtained, set prQM->fgTcResourcePostAnnealing to TRUE to + * start the TC-quota adjusting procedure, which will be invoked upon every TX Done + */ + + //4 <1> Determine the demands + /* Determine the amount of extra resource to fulfill all of the demands */ + for (i=0; iau4MinReservedTcResource[i] - prQM->au4CurrentTcResource[i]); + + /* If there are queued packets, allocate extra resource for the TC (for TCP consideration) */ + if (QM_GET_TX_QUEUE_LEN(prAdapter, i)){ + ai4PerTcResourceDemand[i] += QM_EXTRA_RESERVED_RESOURCE_WHEN_BUSY; + } + + i4TotalResourceDemand += ai4PerTcResourceDemand[i]; + } + + //4 <2> Case 1: Demand <= Total Resource + if (i4TotalResourceDemand <= 0){ + //4 <2.1> Satisfy every TC + for (i = 0; i < TC_NUM; i++){ + /* Skip TC4 (not adjustable) */ + if (i == TC4_INDEX) { + continue; + } + + prQM->au4CurrentTcResource[i] += ai4PerTcResourceDemand[i]; + } + + //4 <2.2> Share the residual resource evenly + u4ShareCount= (TC_NUM - 1); /* excluding TC4 */ + u4ResidualResource = (UINT_32)(-i4TotalResourceDemand); + u4Share = (u4ResidualResource/u4ShareCount); + + for (i=0; iau4CurrentTcResource[i] += u4Share; + + /* Every TC is fully satisfied */ + ai4PerTcResourceDemand[i] = 0; + + /* The left resource will be allocated to TC3 */ + u4ResidualResource -= u4Share; + } + + //4 <2.3> Allocate the left resource to TC3 (VO) + prQM->au4CurrentTcResource[TC3_INDEX] += (u4ResidualResource); + + } + + //4 <3> Case 2: Demand > Total Resource --> Guarantee a minimum amount of resource for each TC + else{ + u4ResidualResource = QM_INITIAL_RESIDUAL_TC_RESOURCE; + + //4 <3.1> Allocated resouce amount = minimum of (guaranteed, total demand) + for (i=0; iau4CurrentTcResource[i] + ai4PerTcResourceDemand[i] < prQM->au4GuaranteedTcResource[i]){ + prQM->au4CurrentTcResource[i] += ai4PerTcResourceDemand[i]; + u4ResidualResource += (prQM->au4GuaranteedTcResource[i] - prQM->au4CurrentTcResource[i]); + ai4PerTcResourceDemand[i] = 0; + } + + /* The demand can not be fulfilled with the guaranteed resource amount */ + else{ + ai4PerTcResourceDemand[i] -= (prQM->au4GuaranteedTcResource[i] - prQM->au4CurrentTcResource[i]); + prQM->au4CurrentTcResource[i] = prQM->au4GuaranteedTcResource[i]; + u4ShareCount++; + } + } + + //4 <3.2> Allocate the residual resource + do{ + /* If there is no resource left, exit directly */ + if (u4ResidualResource == 0){ + break; + } + + /* This shall not happen */ + if (u4ShareCount == 0){ + prQM->au4CurrentTcResource[TC1_INDEX] += u4ResidualResource; + DBGLOG(QM, ERROR, ("QM: (Error) u4ShareCount = 0\n")); + break; + } + + /* Share the residual resource evenly */ + u4Share = (u4ResidualResource / u4ShareCount); + if(u4Share){ + for (i=0; iau4CurrentTcResource[i] += u4Share; + u4ResidualResource -= u4Share; + ai4PerTcResourceDemand[i] -= u4Share; + } + else{ + prQM->au4CurrentTcResource[i] += ai4PerTcResourceDemand[i]; + u4ResidualResource -= ai4PerTcResourceDemand[i]; + ai4PerTcResourceDemand[i] = 0; + } + } + } + } + + /* By priority, allocate the left resource that is not divisible by u4Share */ + if (u4ResidualResource == 0){ + break; + } + + if (ai4PerTcResourceDemand[TC3_INDEX]){ /* VO */ + prQM->au4CurrentTcResource[TC3_INDEX]++; + if (--u4ResidualResource == 0) { + break; + } + } + + if (ai4PerTcResourceDemand[TC2_INDEX]){ /* VI */ + prQM->au4CurrentTcResource[TC2_INDEX]++; + if (--u4ResidualResource == 0) { + break; + } + } + + if (ai4PerTcResourceDemand[TC5_INDEX]){ /* BMCAST */ + prQM->au4CurrentTcResource[TC5_INDEX]++; + if (--u4ResidualResource == 0) { + break; + } + } + + if (ai4PerTcResourceDemand[TC1_INDEX]){ /* BE */ + prQM->au4CurrentTcResource[TC1_INDEX]++; + if (--u4ResidualResource == 0) { + break; + } + } + + if (ai4PerTcResourceDemand[TC0_INDEX]){ /* BK */ + prQM->au4CurrentTcResource[TC0_INDEX]++; + if (--u4ResidualResource == 0) { + break; + } + } + + /* Allocate the left resource */ + prQM->au4CurrentTcResource[TC3_INDEX] += u4ResidualResource; + + }while(FALSE); + } + + prQM->fgTcResourcePostAnnealing = TRUE; + +#if QM_PRINT_TC_RESOURCE_CTRL + /* Debug print */ + DBGLOG(QM, LOUD, ("QM: TC Rsc %ld %ld %ld %ld %ld %ld\n", + prQM->au4CurrentTcResource[0], + prQM->au4CurrentTcResource[1], + prQM->au4CurrentTcResource[2], + prQM->au4CurrentTcResource[3], + prQM->au4CurrentTcResource[4], + prQM->au4CurrentTcResource[5] + )); +#endif + +} + +#endif + + +/*----------------------------------------------------------------------------*/ +/* RX-Related Queue Management */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/*! +* \brief Init Queue Managment for RX +* +* \param[in] (none) +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +qmInitRxQueues( + IN P_ADAPTER_T prAdapter + ) +{ + //DbgPrint("QM: Enter qmInitRxQueues()\n"); + /* TODO */ +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Handle RX packets (buffer reordering) +* +* \param[in] prSwRfbListHead The list of RX packets +* +* \return The list of packets which are not buffered for reordering +*/ +/*----------------------------------------------------------------------------*/ +P_SW_RFB_T +qmHandleRxPackets( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfbListHead + ) +{ + +#if CFG_RX_REORDERING_ENABLED + //UINT_32 i; + P_SW_RFB_T prCurrSwRfb; + P_SW_RFB_T prNextSwRfb; + P_HIF_RX_HEADER_T prHifRxHdr; + QUE_T rReturnedQue; + PUINT_8 pucEthDestAddr; + + //DbgPrint("QM: Enter qmHandleRxPackets()\n"); + + DEBUGFUNC("qmHandleRxPackets"); + + ASSERT(prSwRfbListHead); + + QUEUE_INITIALIZE(&rReturnedQue); + prNextSwRfb = prSwRfbListHead; + + do{ + prCurrSwRfb = prNextSwRfb; + prNextSwRfb = QM_RX_GET_NEXT_SW_RFB(prCurrSwRfb); + + prHifRxHdr = prCurrSwRfb->prHifRxHdr; // TODO: (Tehuang) Use macro to obtain the pointer + + /* TODO: (Tehuang) Check if relaying */ + prCurrSwRfb->eDst = RX_PKT_DESTINATION_HOST; + + /* Decide the Destination */ +#if CFG_RX_PKTS_DUMP + if (prAdapter->rRxCtrl.u4RxPktsDumpTypeMask & BIT(HIF_RX_PKT_TYPE_DATA)) { + DBGLOG(SW4, INFO, ("QM RX DATA: net %u sta idx %u wlan idx %u ssn %u tid %u ptype %u 11 %u\n", + HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr), + prHifRxHdr->ucStaRecIdx, + prCurrSwRfb->ucWlanIdx, + HIF_RX_HDR_GET_SN(prHifRxHdr), /* The new SN of the frame */ + HIF_RX_HDR_GET_TID(prHifRxHdr), + prCurrSwRfb->ucPacketType, + HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr))); + + DBGLOG_MEM8(SW4, TRACE, (PUINT_8)prCurrSwRfb->pvHeader, prCurrSwRfb->u2PacketLen); + } +#endif + + if (!HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr)){ + + UINT_8 ucNetTypeIdx; + P_BSS_INFO_T prBssInfo; + + pucEthDestAddr = prCurrSwRfb->pvHeader; + ucNetTypeIdx = HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[ucNetTypeIdx]); + //DBGLOG_MEM8(QM, TRACE,prCurrSwRfb->pvHeader, 16); + // + + if( prAdapter->rRxCtrl.rFreeSwRfbList.u4NumElem + > (CFG_RX_MAX_PKT_NUM - CFG_NUM_OF_QM_RX_PKT_NUM) ) { + + if(IS_BSS_ACTIVE(prBssInfo)) { + if(OP_MODE_ACCESS_POINT == prBssInfo->eCurrentOPMode) { + if (IS_BMCAST_MAC_ADDR(pucEthDestAddr)){ + prCurrSwRfb->eDst = RX_PKT_DESTINATION_HOST_WITH_FORWARD; + } + else if(UNEQUAL_MAC_ADDR(prBssInfo->aucOwnMacAddr,pucEthDestAddr)) { + prCurrSwRfb->eDst = RX_PKT_DESTINATION_FORWARD; + /* TODO : need to check the dst mac is valid */ + /* If src mac is invalid, the packet will be freed in fw */ + } + } /* OP_MODE_ACCESS_POINT */ + } + else { + DBGLOG(QM, TRACE, ("Mark NULL the Packet for inactive Bss %u\n",ucNetTypeIdx)); + prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(&rReturnedQue, (P_QUE_ENTRY_T)prCurrSwRfb); + continue; + } + + } + else { + /* Dont not occupy other SW RFB */ + DBGLOG(QM, TRACE, ("Mark NULL the Packet for less Free Sw Rfb\n")); + prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(&rReturnedQue, (P_QUE_ENTRY_T)prCurrSwRfb); + continue; + } + + } + + /* BAR frame */ + if(HIF_RX_HDR_GET_BAR_FLAG(prHifRxHdr)){ + prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; + qmProcessBarFrame(prAdapter, prCurrSwRfb, &rReturnedQue); + } + /* Reordering is not required for this packet, return it without buffering */ + else if(!HIF_RX_HDR_GET_REORDER_FLAG(prHifRxHdr)){ +#if 0 + if (!HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr)){ + UINT_8 ucNetTypeIdx; + P_BSS_INFO_T prBssInfo; + + pucEthDestAddr = prCurrSwRfb->pvHeader; + ucNetTypeIdx = HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[ucNetTypeIdx]); + + if (IS_BMCAST_MAC_ADDR(pucEthDestAddr) && (OP_MODE_ACCESS_POINT == prBssInfo->eCurrentOPMode)){ + prCurrSwRfb->eDst = RX_PKT_DESTINATION_HOST_WITH_FORWARD; + } + } +#endif + QUEUE_INSERT_TAIL(&rReturnedQue, (P_QUE_ENTRY_T)prCurrSwRfb); + } + /* Reordering is required for this packet */ + else{ + /* If this packet should dropped or indicated to the host immediately, + * it should be enqueued into the rReturnedQue with specific flags. If + * this packet should be buffered for reordering, it should be enqueued + * into the reordering queue in the STA_REC rather than into the + * rReturnedQue. + */ + qmProcessPktWithReordering(prAdapter, prCurrSwRfb, &rReturnedQue); + + } + }while(prNextSwRfb); + + + /* The returned list of SW_RFBs must end with a NULL pointer */ + if(QUEUE_IS_NOT_EMPTY(&rReturnedQue)){ + QM_TX_SET_NEXT_MSDU_INFO((P_SW_RFB_T)QUEUE_GET_TAIL(&rReturnedQue), NULL); + } + + return (P_SW_RFB_T)QUEUE_GET_HEAD(&rReturnedQue); + +#else + + //DbgPrint("QM: Enter qmHandleRxPackets()\n"); + return prSwRfbListHead; + +#endif + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Reorder the received packet +* +* \param[in] prSwRfb The RX packet to process +* \param[out] prReturnedQue The queue for indicating packets +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +qmProcessPktWithReordering( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT P_QUE_T prReturnedQue + ) +{ + + + P_STA_RECORD_T prStaRec; + P_HIF_RX_HEADER_T prHifRxHdr; + P_RX_BA_ENTRY_T prReorderQueParm; + + UINT_32 u4SeqNo; + UINT_32 u4WinStart; + UINT_32 u4WinEnd; + P_QUE_T prReorderQue; + //P_SW_RFB_T prReorderedSwRfb; + + DEBUGFUNC("qmProcessPktWithReordering"); + + ASSERT(prSwRfb); + ASSERT(prReturnedQue); + ASSERT(prSwRfb->prHifRxHdr); + + prHifRxHdr = prSwRfb->prHifRxHdr; + prSwRfb->ucStaRecIdx = prHifRxHdr->ucStaRecIdx; + prSwRfb->u2SSN = HIF_RX_HDR_GET_SN(prHifRxHdr); /* The new SN of the frame */ + prSwRfb->ucTid = (UINT_8)(HIF_RX_HDR_GET_TID(prHifRxHdr)); + //prSwRfb->eDst = RX_PKT_DESTINATION_HOST; + + /* Incorrect STA_REC index */ + if(prSwRfb->ucStaRecIdx >= CFG_NUM_OF_STA_RECORD){ + prSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prSwRfb); + DBGLOG(QM, WARN,("Reordering for a NULL STA_REC, ucStaRecIdx = %d\n", + prSwRfb->ucStaRecIdx)); + //ASSERT(0); + return; + } + + /* Check whether the STA_REC is activated */ + prStaRec = &(prAdapter->arStaRec[prSwRfb->ucStaRecIdx]); + ASSERT(prStaRec); + +#if 0 + if(!(prStaRec->fgIsValid)){ + /* TODO: (Tehuang) Handle the Host-FW sync issue. */ + prSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prSwRfb); + DBGLOG(QM, WARN, ("Reordering for an invalid STA_REC \n")); + //ASSERT(0); + return; + } +#endif + + /* Check whether the BA agreement exists */ + prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[prSwRfb->ucTid]); + if(!prReorderQueParm){ + /* TODO: (Tehuang) Handle the Host-FW sync issue.*/ + prSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prSwRfb); + DBGLOG(QM, WARN,("Reordering for a NULL ReorderQueParm \n")); + //ASSERT(0); + return; + } + + + + /* Start to reorder packets */ + u4SeqNo = (UINT_32)(prSwRfb->u2SSN); + prReorderQue = &(prReorderQueParm->rReOrderQue); + u4WinStart = (UINT_32)(prReorderQueParm->u2WinStart); + u4WinEnd = (UINT_32)(prReorderQueParm->u2WinEnd); + + /* Debug */ + //DbgPrint("QM:(R)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); + + /* Case 1: Fall within */ + if /* 0 - start - sn - end - 4095 */ + (((u4WinStart <= u4SeqNo) && (u4SeqNo <= u4WinEnd)) + /* 0 - end - start - sn - 4095 */ + || ((u4WinEnd < u4WinStart) && (u4WinStart <= u4SeqNo)) + /* 0 - sn - end - start - 4095 */ + || ((u4SeqNo <= u4WinEnd) && (u4WinEnd < u4WinStart))){ + + qmInsertFallWithinReorderPkt(prSwRfb, prReorderQueParm, prReturnedQue); + +#if QM_RX_WIN_SSN_AUTO_ADVANCING + if(prReorderQueParm->fgIsWaitingForPktWithSsn){ + /* Let the first received packet pass the reorder check */ + DBGLOG(QM, LOUD, ("QM:(A)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd)); + + prReorderQueParm->u2WinStart = (UINT_16)u4SeqNo; + prReorderQueParm->u2WinEnd = + ((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) - 1) % MAX_SEQ_NO_COUNT; + prReorderQueParm->fgIsWaitingForPktWithSsn = FALSE; + } +#endif + + + qmPopOutDueToFallWithin(prReorderQueParm, prReturnedQue); + } + /* Case 2: Fall ahead */ + else if + /* 0 - start - end - sn - (start+2048) - 4095 */ + (((u4WinStart < u4WinEnd) + && (u4WinEnd < u4SeqNo) + && (u4SeqNo < (u4WinStart + HALF_SEQ_NO_COUNT))) + /* 0 - sn - (start+2048) - start - end - 4095 */ + || ((u4SeqNo < u4WinStart) + && (u4WinStart < u4WinEnd) + && ((u4SeqNo + MAX_SEQ_NO_COUNT) < (u4WinStart + HALF_SEQ_NO_COUNT))) + /* 0 - end - sn - (start+2048) - start - 4095 */ + || ((u4WinEnd < u4SeqNo) + && (u4SeqNo < u4WinStart) + && ((u4SeqNo + MAX_SEQ_NO_COUNT) < (u4WinStart + HALF_SEQ_NO_COUNT)))){ + + +#if QM_RX_WIN_SSN_AUTO_ADVANCING + if(prReorderQueParm->fgIsWaitingForPktWithSsn){ + prReorderQueParm->fgIsWaitingForPktWithSsn = FALSE; + } +#endif + + qmInsertFallAheadReorderPkt(prSwRfb, prReorderQueParm, prReturnedQue); + + /* Advance the window after inserting a new tail */ + prReorderQueParm->u2WinEnd = (UINT_16)u4SeqNo; + prReorderQueParm->u2WinStart = + (((prReorderQueParm->u2WinEnd) - (prReorderQueParm->u2WinSize) + MAX_SEQ_NO_COUNT + 1) + % MAX_SEQ_NO_COUNT); + + qmPopOutDueToFallAhead(prReorderQueParm, prReturnedQue); + + } + /* Case 3: Fall behind */ + else{ + +#if QM_RX_WIN_SSN_AUTO_ADVANCING + #if QM_RX_INIT_FALL_BEHIND_PASS + if(prReorderQueParm->fgIsWaitingForPktWithSsn){ + //?? prSwRfb->eDst = RX_PKT_DESTINATION_HOST; + QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prSwRfb); + //DbgPrint("QM:(P)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); + return; + } + #endif +#endif + + /* An erroneous packet */ + prSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prSwRfb); + //DbgPrint("QM:(D)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); + return; + } + + return; + +} + + +VOID +qmProcessBarFrame( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT P_QUE_T prReturnedQue + ) +{ + + P_STA_RECORD_T prStaRec; + P_HIF_RX_HEADER_T prHifRxHdr; + P_RX_BA_ENTRY_T prReorderQueParm; + + UINT_32 u4SSN; + UINT_32 u4WinStart; + UINT_32 u4WinEnd; + P_QUE_T prReorderQue; + //P_SW_RFB_T prReorderedSwRfb; + + ASSERT(prSwRfb); + ASSERT(prReturnedQue); + ASSERT(prSwRfb->prHifRxHdr); + + prHifRxHdr = prSwRfb->prHifRxHdr; + prSwRfb->ucStaRecIdx = prHifRxHdr->ucStaRecIdx; + prSwRfb->u2SSN = HIF_RX_HDR_GET_SN(prHifRxHdr); /* The new SSN */ + prSwRfb->ucTid = (UINT_8)(HIF_RX_HDR_GET_TID(prHifRxHdr)); + + prSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prSwRfb); + + /* Incorrect STA_REC index */ + if(prSwRfb->ucStaRecIdx >= CFG_NUM_OF_STA_RECORD){ + DBGLOG(QM, WARN, ("QM: (Warning) BAR for a NULL STA_REC, ucStaRecIdx = %d\n", + prSwRfb->ucStaRecIdx)); + //ASSERT(0); + return; + } + + /* Check whether the STA_REC is activated */ + prStaRec = &(prAdapter->arStaRec[prSwRfb->ucStaRecIdx]); + ASSERT(prStaRec); + +#if 0 + if(!(prStaRec->fgIsValid)){ + /* TODO: (Tehuang) Handle the Host-FW sync issue. */ + DbgPrint("QM: (Warning) BAR for an invalid STA_REC \n"); + //ASSERT(0); + return; + } +#endif + + /* Check whether the BA agreement exists */ + prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[prSwRfb->ucTid]); + if(!prReorderQueParm){ + /* TODO: (Tehuang) Handle the Host-FW sync issue.*/ + DBGLOG(QM, WARN, ("QM: (Warning) BAR for a NULL ReorderQueParm \n")); + //ASSERT(0); + return; + } + + + u4SSN = (UINT_32)(prSwRfb->u2SSN); + prReorderQue = &(prReorderQueParm->rReOrderQue); + u4WinStart = (UINT_32)(prReorderQueParm->u2WinStart); + u4WinEnd = (UINT_32)(prReorderQueParm->u2WinEnd); + + if(qmCompareSnIsLessThan(u4WinStart,u4SSN)){ + prReorderQueParm->u2WinStart = (UINT_16)u4SSN; + prReorderQueParm->u2WinEnd = + ((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) - 1) % MAX_SEQ_NO_COUNT; + DBGLOG(QM, TRACE, ("QM:(BAR)[%d](%ld){%d,%d}\n", prSwRfb->ucTid, u4SSN, prReorderQueParm->u2WinStart, prReorderQueParm->u2WinEnd)); + qmPopOutDueToFallAhead(prReorderQueParm, prReturnedQue); + } + else{ + DBGLOG(QM, TRACE, ("QM:(BAR)(%d)(%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SSN, u4WinStart, u4WinEnd)); + } +} + + + +VOID +qmInsertFallWithinReorderPkt( + IN P_SW_RFB_T prSwRfb, + IN P_RX_BA_ENTRY_T prReorderQueParm, + OUT P_QUE_T prReturnedQue + ) +{ + P_SW_RFB_T prExaminedQueuedSwRfb; + P_QUE_T prReorderQue; + ASSERT(prSwRfb); + ASSERT(prReorderQueParm); + ASSERT(prReturnedQue); + + prReorderQue = &(prReorderQueParm->rReOrderQue); + prExaminedQueuedSwRfb = (P_SW_RFB_T)QUEUE_GET_HEAD(prReorderQue); + + /* There are no packets queued in the Reorder Queue */ + if(prExaminedQueuedSwRfb == NULL){ + ((P_QUE_ENTRY_T)prSwRfb)->prPrev = NULL; + ((P_QUE_ENTRY_T)prSwRfb)->prNext = NULL; + prReorderQue->prHead = (P_QUE_ENTRY_T)prSwRfb; + prReorderQue->prTail = (P_QUE_ENTRY_T)prSwRfb; + prReorderQue->u4NumElem ++; + } + + /* Determine the insert position */ + else{ + do{ + /* Case 1: Terminate. A duplicate packet */ + if(((prExaminedQueuedSwRfb->u2SSN) == (prSwRfb->u2SSN))){ + prSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prSwRfb); + return; + } + + /* Case 2: Terminate. The insert point is found */ + else if(qmCompareSnIsLessThan( + (prSwRfb->u2SSN),(prExaminedQueuedSwRfb->u2SSN))){ + break; + } + + /* Case 3: Insert point not found. Check the next SW_RFB in the Reorder Queue */ + else{ + prExaminedQueuedSwRfb = + (P_SW_RFB_T)(((P_QUE_ENTRY_T)prExaminedQueuedSwRfb)->prNext); + } + }while(prExaminedQueuedSwRfb); + + /* Update the Reorder Queue Parameters according to the found insert position */ + if(prExaminedQueuedSwRfb == NULL){ + /* The received packet shall be placed at the tail */ + ((P_QUE_ENTRY_T)prSwRfb)->prPrev = prReorderQue->prTail; + ((P_QUE_ENTRY_T)prSwRfb)->prNext = NULL; + (prReorderQue->prTail)->prNext = (P_QUE_ENTRY_T)(prSwRfb); + prReorderQue->prTail = (P_QUE_ENTRY_T)(prSwRfb); + } + else{ + ((P_QUE_ENTRY_T)prSwRfb)->prPrev = ((P_QUE_ENTRY_T)prExaminedQueuedSwRfb)->prPrev; + ((P_QUE_ENTRY_T)prSwRfb)->prNext = (P_QUE_ENTRY_T)prExaminedQueuedSwRfb; + if(((P_QUE_ENTRY_T)prExaminedQueuedSwRfb) == (prReorderQue->prHead)){ + /* The received packet will become the head */ + prReorderQue->prHead = (P_QUE_ENTRY_T)prSwRfb; + } + else{ + (((P_QUE_ENTRY_T)prExaminedQueuedSwRfb)->prPrev)->prNext = (P_QUE_ENTRY_T)prSwRfb; + } + ((P_QUE_ENTRY_T)prExaminedQueuedSwRfb)->prPrev = (P_QUE_ENTRY_T)prSwRfb; + } + + prReorderQue->u4NumElem ++; + + } + +} + + +VOID +qmInsertFallAheadReorderPkt( + IN P_SW_RFB_T prSwRfb, + IN P_RX_BA_ENTRY_T prReorderQueParm, + OUT P_QUE_T prReturnedQue + ) +{ + P_QUE_T prReorderQue; + ASSERT(prSwRfb); + ASSERT(prReorderQueParm); + ASSERT(prReturnedQue); + + prReorderQue = &(prReorderQueParm->rReOrderQue); + + /* There are no packets queued in the Reorder Queue */ + if(QUEUE_IS_EMPTY(prReorderQue)){ + ((P_QUE_ENTRY_T)prSwRfb)->prPrev = NULL; + ((P_QUE_ENTRY_T)prSwRfb)->prNext = NULL; + prReorderQue->prHead = (P_QUE_ENTRY_T)prSwRfb; + } + else{ + ((P_QUE_ENTRY_T)prSwRfb)->prPrev = prReorderQue->prTail; + ((P_QUE_ENTRY_T)prSwRfb)->prNext = NULL; + (prReorderQue->prTail)->prNext = (P_QUE_ENTRY_T)(prSwRfb); + } + prReorderQue->prTail = (P_QUE_ENTRY_T)prSwRfb; + prReorderQue->u4NumElem ++; + +} + + +VOID +qmPopOutDueToFallWithin( + IN P_RX_BA_ENTRY_T prReorderQueParm, + OUT P_QUE_T prReturnedQue + ) +{ + P_SW_RFB_T prReorderedSwRfb; + P_QUE_T prReorderQue; + BOOLEAN fgDequeuHead; + + prReorderQue = &(prReorderQueParm->rReOrderQue); + + /* Check whether any packet can be indicated to the higher layer */ + while(TRUE){ + if(QUEUE_IS_EMPTY(prReorderQue)){ + break; + } + + /* Always examine the head packet */ + prReorderedSwRfb = (P_SW_RFB_T)QUEUE_GET_HEAD(prReorderQue); + fgDequeuHead = FALSE; + + /* SN == WinStart, so the head packet shall be indicated (advance the window) */ + if((prReorderedSwRfb->u2SSN) == (prReorderQueParm->u2WinStart)){ + + fgDequeuHead = TRUE; + prReorderQueParm->u2WinStart = + (((prReorderedSwRfb->u2SSN) + 1)% MAX_SEQ_NO_COUNT); + } + /* SN > WinStart, break to update WinEnd */ + else{ + break; + } + + + /* Dequeue the head packet */ + if(fgDequeuHead){ + + if(((P_QUE_ENTRY_T)prReorderedSwRfb)->prNext == NULL){ + prReorderQue->prHead = NULL; + prReorderQue->prTail = NULL; + } + else{ + prReorderQue->prHead = ((P_QUE_ENTRY_T)prReorderedSwRfb)->prNext; + (((P_QUE_ENTRY_T)prReorderedSwRfb)->prNext)->prPrev = NULL; + } + prReorderQue->u4NumElem --; + //DbgPrint("QM: [%d] %d (%d)\n", prReorderQueParm->ucTid, prReorderedSwRfb->u2PacketLen, prReorderedSwRfb->u2SSN); + QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prReorderedSwRfb); + } + } + + /* After WinStart has been determined, update the WinEnd */ + prReorderQueParm->u2WinEnd = + (((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) -1 )% MAX_SEQ_NO_COUNT); + +} + +VOID +qmPopOutDueToFallAhead( + IN P_RX_BA_ENTRY_T prReorderQueParm, + OUT P_QUE_T prReturnedQue + ) +{ + P_SW_RFB_T prReorderedSwRfb; + P_QUE_T prReorderQue; + BOOLEAN fgDequeuHead; + + prReorderQue = &(prReorderQueParm->rReOrderQue); + + /* Check whether any packet can be indicated to the higher layer */ + while(TRUE){ + if(QUEUE_IS_EMPTY(prReorderQue)){ + break; + } + + /* Always examine the head packet */ + prReorderedSwRfb = (P_SW_RFB_T)QUEUE_GET_HEAD(prReorderQue); + fgDequeuHead = FALSE; + + /* SN == WinStart, so the head packet shall be indicated (advance the window) */ + if((prReorderedSwRfb->u2SSN) == (prReorderQueParm->u2WinStart)){ + + fgDequeuHead = TRUE; + prReorderQueParm->u2WinStart = + (((prReorderedSwRfb->u2SSN) + 1)% MAX_SEQ_NO_COUNT); + } + + /* SN < WinStart, so the head packet shall be indicated (do not advance the window) */ + else if(qmCompareSnIsLessThan( + (UINT_32)(prReorderedSwRfb->u2SSN), + (UINT_32)(prReorderQueParm->u2WinStart))){ + + fgDequeuHead = TRUE; + + } + + /* SN > WinStart, break to update WinEnd */ + else{ + break; + } + + + /* Dequeue the head packet */ + if(fgDequeuHead){ + + if(((P_QUE_ENTRY_T)prReorderedSwRfb)->prNext == NULL){ + prReorderQue->prHead = NULL; + prReorderQue->prTail = NULL; + } + else{ + prReorderQue->prHead = ((P_QUE_ENTRY_T)prReorderedSwRfb)->prNext; + (((P_QUE_ENTRY_T)prReorderedSwRfb)->prNext)->prPrev = NULL; + } + prReorderQue->u4NumElem --; + //DbgPrint("QM: [%d] %d (%d)\n", prReorderQueParm->ucTid, prReorderedSwRfb->u2PacketLen, prReorderedSwRfb->u2SSN); + QUEUE_INSERT_TAIL(prReturnedQue,(P_QUE_ENTRY_T)prReorderedSwRfb); + } + } + + /* After WinStart has been determined, update the WinEnd */ + prReorderQueParm->u2WinEnd = + (((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) -1)% MAX_SEQ_NO_COUNT); + +} + +BOOLEAN +qmCompareSnIsLessThan( + IN UINT_32 u4SnLess, + IN UINT_32 u4SnGreater + ) +{ + /* 0 <---> SnLess <--(gap>2048)--> SnGreater : SnLess > SnGreater */ + if((u4SnLess + HALF_SEQ_NO_COUNT) <= u4SnGreater){ /* Shall be <= */ + return FALSE; + } + + /* 0 <---> SnGreater <--(gap>2048)--> SnLess : SnLess < SnGreater */ + else if((u4SnGreater + HALF_SEQ_NO_COUNT) < u4SnLess){ + return TRUE; + } + + /* 0 <---> SnGreater <--(gap<2048)--> SnLess : SnLess > SnGreater */ + /* 0 <---> SnLess <--(gap<2048)--> SnGreater : SnLess < SnGreater */ + else{ + return (u4SnLess < u4SnGreater); + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Handle Mailbox RX messages +* +* \param[in] prMailboxRxMsg The received Mailbox message from the FW +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +qmHandleMailboxRxMessage( + IN MAILBOX_MSG_T prMailboxRxMsg + ) +{ + //DbgPrint("QM: Enter qmHandleMailboxRxMessage()\n"); + /* TODO */ +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Handle ADD RX BA Event from the FW +* +* \param[in] prAdapter Adapter pointer +* \param[in] prEvent The event packet from the FW +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +qmHandleEventRxAddBa( + IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent + ) +{ + P_EVENT_RX_ADDBA_T prEventRxAddBa; + P_STA_RECORD_T prStaRec; + UINT_32 u4Tid; + UINT_32 u4WinSize; + + DBGLOG(QM, INFO, ("QM:Event +RxBa\n")); + + prEventRxAddBa = (P_EVENT_RX_ADDBA_T)prEvent; + prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventRxAddBa->ucStaRecIdx); + + if(!prStaRec){ + /* Invalid STA_REC index, discard the event packet */ + //ASSERT(0); + DBGLOG(QM, INFO, ("QM: (Warning) RX ADDBA Event for a NULL STA_REC\n")); + return; + } + +#if 0 + if(!(prStaRec->fgIsValid)){ + /* TODO: (Tehuang) Handle the Host-FW synchronization issue */ + DBGLOG(QM, WARN, ("QM: (Warning) RX ADDBA Event for an invalid STA_REC\n")); + //ASSERT(0); + //return; + } +#endif + + u4Tid = (((prEventRxAddBa->u2BAParameterSet)& BA_PARAM_SET_TID_MASK) + >> BA_PARAM_SET_TID_MASK_OFFSET); + + u4WinSize = (((prEventRxAddBa->u2BAParameterSet)& BA_PARAM_SET_BUFFER_SIZE_MASK) + >> BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET); + + if(!qmAddRxBaEntry( + prAdapter, + prStaRec->ucIndex, + (UINT_8)u4Tid, + (prEventRxAddBa->u2BAStartSeqCtrl >> OFFSET_BAR_SSC_SN), + (UINT_16)u4WinSize)){ + + /* FW shall ensure the availabiilty of the free-to-use BA entry */ + DBGLOG(QM, ERROR, ("QM: (Error) qmAddRxBaEntry() failure\n")); + ASSERT(0); + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Handle DEL RX BA Event from the FW +* +* \param[in] prAdapter Adapter pointer +* \param[in] prEvent The event packet from the FW +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +qmHandleEventRxDelBa( + IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent + ) +{ + P_EVENT_RX_DELBA_T prEventRxDelBa; + P_STA_RECORD_T prStaRec; + + //DbgPrint("QM:Event -RxBa\n"); + + prEventRxDelBa = (P_EVENT_RX_DELBA_T)prEvent; + prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventRxDelBa->ucStaRecIdx); + + if(!prStaRec){ + /* Invalid STA_REC index, discard the event packet */ + //ASSERT(0); + return; + } + +#if 0 + if(!(prStaRec->fgIsValid)){ + /* TODO: (Tehuang) Handle the Host-FW synchronization issue */ + //ASSERT(0); + return; + } +#endif + + qmDelRxBaEntry(prAdapter, prStaRec->ucIndex, prEventRxDelBa->ucTid, TRUE); + +} + +P_RX_BA_ENTRY_T +qmLookupRxBaEntry( + IN P_ADAPTER_T prAdapter, + UINT_8 ucStaRecIdx, + UINT_8 ucTid + ) +{ + int i; + P_QUE_MGT_T prQM = &prAdapter->rQM; + + //DbgPrint("QM: Enter qmLookupRxBaEntry()\n"); + + for(i=0; iarRxBaTable[i].fgIsValid){ + if((prQM->arRxBaTable[i].ucStaRecIdx == ucStaRecIdx) && + (prQM->arRxBaTable[i].ucTid == ucTid)){ + return &prQM->arRxBaTable[i]; + } + } + } + return NULL; +} + +BOOL +qmAddRxBaEntry( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucStaRecIdx, + IN UINT_8 ucTid, + IN UINT_16 u2WinStart, + IN UINT_16 u2WinSize + ) +{ + int i; + P_RX_BA_ENTRY_T prRxBaEntry = NULL; + P_STA_RECORD_T prStaRec; + P_QUE_MGT_T prQM = &prAdapter->rQM; + + ASSERT(ucStaRecIdx < CFG_NUM_OF_STA_RECORD); + + if(ucStaRecIdx >= CFG_NUM_OF_STA_RECORD){ + /* Invalid STA_REC index, discard the event packet */ + DBGLOG(QM, WARN, ("QM: (WARNING) RX ADDBA Event for a invalid ucStaRecIdx = %d\n", ucStaRecIdx)); + return FALSE; + } + + prStaRec = &prAdapter->arStaRec[ucStaRecIdx]; + ASSERT(prStaRec); + + //if(!(prStaRec->fgIsValid)){ + // DbgPrint("QM: (WARNING) Invalid STA when adding an RX BA \n"); + // return FALSE; + //} + + //4 <1> Delete before adding + /* Remove the BA entry for the same (STA, TID) tuple if it exists */ + if(qmLookupRxBaEntry(prAdapter, ucStaRecIdx,ucTid)){ + qmDelRxBaEntry(prAdapter, ucStaRecIdx, ucTid, TRUE); /* prQM->ucRxBaCount-- */ + } + + //4 <2> Add a new BA entry + /* No available entry to store the BA agreement info. Retrun FALSE. */ + if(prQM->ucRxBaCount >= CFG_NUM_OF_RX_BA_AGREEMENTS){ + DBGLOG(QM, ERROR, ("QM: **failure** (limited resource, ucRxBaCount=%d)\n", prQM->ucRxBaCount)); + return FALSE; + } + else{ + /* Find the free-to-use BA entry */ + for(i=0; iarRxBaTable[i].fgIsValid){ + prRxBaEntry = &(prQM->arRxBaTable[i]); + prQM->ucRxBaCount++; + DBGLOG(QM, LOUD, ("QM: ucRxBaCount=%d\n", prQM->ucRxBaCount)); + break; + } + } + + /* If a free-to-use entry is found, configure it and associate it with the STA_REC */ + u2WinSize += CFG_RX_BA_INC_SIZE; + if(prRxBaEntry){ + prRxBaEntry->ucStaRecIdx = ucStaRecIdx; + prRxBaEntry->ucTid = ucTid; + prRxBaEntry->u2WinStart = u2WinStart; + prRxBaEntry->u2WinSize= u2WinSize; + prRxBaEntry->u2WinEnd = ((u2WinStart + u2WinSize - 1) % MAX_SEQ_NO_COUNT); + prRxBaEntry->fgIsValid = TRUE; + prRxBaEntry->fgIsWaitingForPktWithSsn = TRUE; + + DBGLOG(QM, INFO, ("QM: +RxBA(STA=%d TID=%d WinStart=%d WinEnd=%d WinSize=%d)\n", + ucStaRecIdx, ucTid, + prRxBaEntry->u2WinStart, prRxBaEntry->u2WinEnd, prRxBaEntry->u2WinSize)); + + /* Update the BA entry reference table for per-packet lookup */ + prStaRec->aprRxReorderParamRefTbl[ucTid] = prRxBaEntry; + } + else{ + /* This shall not happen because FW should keep track of the usage of RX BA entries */ + DBGLOG(QM, ERROR, ("QM: **AddBA Error** (ucRxBaCount=%d)\n", prQM->ucRxBaCount)); + return FALSE; + } + } + + return TRUE; +} +VOID +qmDelRxBaEntry( + IN P_ADAPTER_T prAdapter, + IN UINT_8 ucStaRecIdx, + IN UINT_8 ucTid, + IN BOOLEAN fgFlushToHost + ) +{ + P_RX_BA_ENTRY_T prRxBaEntry; + P_STA_RECORD_T prStaRec; + P_SW_RFB_T prFlushedPacketList = NULL; + P_QUE_MGT_T prQM = &prAdapter->rQM; + + ASSERT(ucStaRecIdx < CFG_NUM_OF_STA_RECORD); + + prStaRec = &prAdapter->arStaRec[ucStaRecIdx]; + ASSERT(prStaRec); + +#if 0 + if(!(prStaRec->fgIsValid)){ + DbgPrint("QM: (WARNING) Invalid STA when deleting an RX BA \n"); + return; + } +#endif + + /* Remove the BA entry for the same (STA, TID) tuple if it exists */ + prRxBaEntry = prStaRec->aprRxReorderParamRefTbl[ucTid]; + + if(prRxBaEntry){ + + prFlushedPacketList = qmFlushStaRxQueue(prAdapter, ucStaRecIdx, ucTid); + + if(prFlushedPacketList){ + + if(fgFlushToHost) { + wlanProcessQueuedSwRfb(prAdapter, prFlushedPacketList); + } + else { + + P_SW_RFB_T prSwRfb; + P_SW_RFB_T prNextSwRfb; + prSwRfb = prFlushedPacketList; + + do { + prNextSwRfb = (P_SW_RFB_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prSwRfb); + nicRxReturnRFB(prAdapter, prSwRfb); + prSwRfb = prNextSwRfb; + } while(prSwRfb); + + } + + + } +#if ((QM_TEST_MODE == 0) && (QM_TEST_STA_REC_DEACTIVATION == 0)) + /* Update RX BA entry state. Note that RX queue flush is not done here */ + prRxBaEntry->fgIsValid = FALSE; + prQM->ucRxBaCount--; + + /* Debug */ + #if 0 + DbgPrint("QM: ucRxBaCount=%d\n", prQM->ucRxBaCount); + #endif + + /* Update STA RX BA table */ + prStaRec->aprRxReorderParamRefTbl[ucTid] = NULL; +#endif + + DBGLOG(QM, INFO, ("QM: -RxBA(STA=%d,TID=%d)\n", ucStaRecIdx, ucTid)); + + } + + + /* Debug */ + #if CFG_HIF_RX_STARVATION_WARNING + { + P_RX_CTRL_T prRxCtrl; + prRxCtrl = &prAdapter->rRxCtrl; + DBGLOG(QM, TRACE, ("QM: (RX DEBUG) Enqueued: %d / Dequeued: %d\n", prRxCtrl->u4QueuedCnt, prRxCtrl->u4DequeuedCnt)); + } + #endif +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To process WMM related IEs in ASSOC_RSP +* +* \param[in] prAdapter Adapter pointer +* \param[in] prSwRfb The received frame +* \param[in] pucIE The pointer to the first IE in the frame +* \param[in] u2IELength The total length of IEs in the frame +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +mqmProcessAssocReq ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN PUINT_8 pucIE, + IN UINT_16 u2IELength + ) +{ + P_STA_RECORD_T prStaRec; + UINT_16 u2Offset; + PUINT_8 pucIEStart; + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; + P_IE_WMM_INFO_T prIeWmmInfo; + + DEBUGFUNC("mqmProcessAssocReq"); + + ASSERT(prSwRfb); + ASSERT(pucIE); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + ASSERT(prStaRec); + + if(prStaRec == NULL) { + return; + } + + prStaRec->fgIsQoS = FALSE; + prStaRec->fgIsWmmSupported = prStaRec->fgIsUapsdSupported = FALSE; + + pucIEStart = pucIE; + + /* If the device does not support QoS or if WMM is not supported by the peer, exit.*/ + if (!prAdapter->rWifiVar.fgSupportQoS) { + return; + } + + + /* Determine whether QoS is enabled with the association */ + else{ + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_WMM: + + if((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) && + (!kalMemCmp(WMM_IE_OUI(pucIE),aucWfaOui,3))){ + + switch(WMM_IE_OUI_SUBTYPE(pucIE)){ + case VENDOR_OUI_SUBTYPE_WMM_INFO: + { + + UINT_8 ucQosInfo; + UINT_8 ucQosInfoAC; + UINT_8 ucBmpAC; + if(IE_LEN(pucIE) != 7){ + break; /* WMM Info IE with a wrong length */ + } + prStaRec->fgIsQoS = TRUE; + prStaRec->fgIsWmmSupported = TRUE; + + prIeWmmInfo = (P_IE_WMM_INFO_T)pucIE; + ucQosInfo = prIeWmmInfo->ucQosInfo; + ucQosInfoAC = ucQosInfo & BITS(0, 3); + + prStaRec->fgIsUapsdSupported = ((ucQosInfoAC)? TRUE: FALSE) & + prAdapter->rWifiVar.fgSupportUAPSD; + + ucBmpAC = 0; + + if( ucQosInfoAC & WMM_QOS_INFO_VO_UAPSD) { + ucBmpAC |= BIT(ACI_VO); + } + if( ucQosInfoAC & WMM_QOS_INFO_VI_UAPSD) { + ucBmpAC |= BIT(ACI_VI); + } + if( ucQosInfoAC & WMM_QOS_INFO_BE_UAPSD) { + ucBmpAC |= BIT(ACI_BE); + } + if( ucQosInfoAC & WMM_QOS_INFO_BK_UAPSD) { + ucBmpAC |= BIT(ACI_BK); + } + + prStaRec->ucBmpTriggerAC = prStaRec->ucBmpDeliveryAC = ucBmpAC; + + prStaRec->ucUapsdSp = (ucQosInfo & WMM_QOS_INFO_MAX_SP_LEN_MASK) >> 5; + + } + break; + + default: + /* Other WMM QoS IEs. Ignore any */ + break; + } + } + /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS */ + + break; + default: + break; + } + } + + DBGLOG(QM, TRACE, ("MQM: Assoc_Req Parsing (QoS Enabled=%d)\n", prStaRec->fgIsQoS)); + + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To process WMM related IEs in ASSOC_RSP +* +* \param[in] prAdapter Adapter pointer +* \param[in] prSwRfb The received frame +* \param[in] pucIE The pointer to the first IE in the frame +* \param[in] u2IELength The total length of IEs in the frame +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +mqmProcessAssocRsp ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN PUINT_8 pucIE, + IN UINT_16 u2IELength + ) +{ + P_STA_RECORD_T prStaRec; + UINT_16 u2Offset; + PUINT_8 pucIEStart; + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; + + DEBUGFUNC("mqmProcessAssocRsp"); + + ASSERT(prSwRfb); + ASSERT(pucIE); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + ASSERT(prStaRec); + + if(prStaRec == NULL) { + return; + } + + prStaRec->fgIsQoS = FALSE; + + pucIEStart = pucIE; + + DBGLOG(QM, TRACE, ("QM: (fgIsWmmSupported=%d, fgSupportQoS=%d)\n", + prStaRec->fgIsWmmSupported, prAdapter->rWifiVar.fgSupportQoS)); + + /* If the device does not support QoS or if WMM is not supported by the peer, exit.*/ + if((!prAdapter->rWifiVar.fgSupportQoS) || (!prStaRec->fgIsWmmSupported)){ + return; + } + + /* Determine whether QoS is enabled with the association */ + else{ + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_WMM: + + if((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) && + (!kalMemCmp(WMM_IE_OUI(pucIE),aucWfaOui,3))){ + + switch(WMM_IE_OUI_SUBTYPE(pucIE)){ + case VENDOR_OUI_SUBTYPE_WMM_PARAM: + if(IE_LEN(pucIE) != 24){ + break; /* WMM Info IE with a wrong length */ + } + prStaRec->fgIsQoS = TRUE; + break; + + case VENDOR_OUI_SUBTYPE_WMM_INFO: + if(IE_LEN(pucIE) != 7){ + break; /* WMM Info IE with a wrong length */ + } + prStaRec->fgIsQoS = TRUE; + break; + + default: + /* Other WMM QoS IEs. Ignore any */ + break; + } + } + /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS */ + + break; + default: + break; + } + } + + /* Parse AC parameters and write to HW CRs */ + if((prStaRec->fgIsQoS) && (prStaRec->eStaType == STA_TYPE_LEGACY_AP)){ + mqmParseEdcaParameters(prAdapter, prSwRfb, pucIEStart, u2IELength, TRUE); + } + + DBGLOG(QM, TRACE, ("MQM: Assoc_Rsp Parsing (QoS Enabled=%d)\n", prStaRec->fgIsQoS)); + nicQmUpdateWmmParms(prAdapter, prStaRec->ucNetTypeIndex); + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To parse WMM Parameter IE (in BCN or Assoc_Rsp) +* +* \param[in] prAdapter Adapter pointer +* \param[in] prSwRfb The received frame +* \param[in] pucIE The pointer to the first IE in the frame +* \param[in] u2IELength The total length of IEs in the frame +* \param[in] fgForceOverride TRUE: If EDCA parameters are found, always set to HW CRs. +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +mqmParseEdcaParameters ( + IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN PUINT_8 pucIE, + IN UINT_16 u2IELength, + IN BOOLEAN fgForceOverride + ) +{ + P_STA_RECORD_T prStaRec; + UINT_16 u2Offset; + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; + P_BSS_INFO_T prBssInfo; + + DEBUGFUNC("mqmParseEdcaParameters"); + + ASSERT(prSwRfb); + ASSERT(pucIE); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + ASSERT(prStaRec); + + if(prStaRec == NULL) { + return; + } + + DBGLOG(QM, TRACE, ("QM: (fgIsWmmSupported=%d, fgIsQoS=%d)\n", + prStaRec->fgIsWmmSupported, prStaRec->fgIsQoS)); + + if((!prAdapter->rWifiVar.fgSupportQoS) || (!prStaRec->fgIsWmmSupported) || (!prStaRec->fgIsQoS)){ + return; + } + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + /* Goal: Obtain the EDCA parameters */ + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_WMM: + + if((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) && + (!kalMemCmp(WMM_IE_OUI(pucIE),aucWfaOui,3))){ + + switch(WMM_IE_OUI_SUBTYPE(pucIE)){ + case VENDOR_OUI_SUBTYPE_WMM_PARAM: + if(IE_LEN(pucIE) != 24){ + break; /* WMM Param IE with a wrong length */ + } + else{ + P_AC_QUE_PARMS_T prAcQueParams; + P_IE_WMM_PARAM_T prIeWmmParam; + ENUM_WMM_ACI_T eAci; + PUINT_8 pucWmmParamSetCount; + //int i; + + pucWmmParamSetCount = &(prBssInfo->ucWmmParamSetCount); + + prIeWmmParam = (P_IE_WMM_PARAM_T)pucIE; + + /* Check the Parameter Set Count to determine whether EDCA parameters have been changed */ + if(!fgForceOverride){ + if(*pucWmmParamSetCount == (prIeWmmParam->ucQosInfo & WMM_QOS_INFO_PARAM_SET_CNT)){ + break; /* Ignore the IE without updating HW CRs */ + } + } + + /* Update Parameter Set Count */ + *pucWmmParamSetCount = (prIeWmmParam->ucQosInfo & WMM_QOS_INFO_PARAM_SET_CNT); + + /* Update EDCA parameters */ + for(eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++){ + + prAcQueParams = &prBssInfo->arACQueParms[eAci]; + mqmFillAcQueParam(prIeWmmParam, eAci, prAcQueParams); + + prAcQueParams->fgIsACMSet = + (prAcQueParams->u2Aifsn & WMM_ACIAIFSN_ACM) ? TRUE : FALSE; + prAcQueParams->u2Aifsn &= WMM_ACIAIFSN_AIFSN; + + DBGLOG(QM, LOUD, ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", + eAci, prAcQueParams->fgIsACMSet, + prAcQueParams->u2Aifsn, prAcQueParams->u2CWmin, + prAcQueParams->u2CWmax, prAcQueParams->u2TxopLimit)); + } + } + break; + + default: + /* Other WMM QoS IEs. Ignore */ + break; + } + + } + /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... (not cared) */ + break; + default: + break; + } + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is used for parsing EDCA parameters specified in the WMM Parameter IE +* +* \param[in] prAdapter Adapter pointer +* \param[in] prIeWmmParam The pointer to the WMM Parameter IE +* \param[in] u4AcOffset The offset specifying the AC queue for parsing +* \param[in] prHwAcParams The parameter structure used to configure the HW CRs +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +mqmFillAcQueParam( + IN P_IE_WMM_PARAM_T prIeWmmParam, + IN UINT_32 u4AcOffset, + OUT P_AC_QUE_PARMS_T prAcQueParams + ) +{ + prAcQueParams->u2Aifsn = *((PUINT_8)(&(prIeWmmParam->ucAciAifsn_BE)) + (u4AcOffset * 4)); + + prAcQueParams->u2CWmax = + BIT(((*((PUINT_8)(&(prIeWmmParam->ucEcw_BE)) + (u4AcOffset * 4))) & WMM_ECW_WMAX_MASK) + >> WMM_ECW_WMAX_OFFSET)-1; + + prAcQueParams->u2CWmin = + BIT((*((PUINT_8)(&(prIeWmmParam->ucEcw_BE)) + (u4AcOffset * 4))) & WMM_ECW_WMIN_MASK)-1; + + WLAN_GET_FIELD_16(((PUINT_8)(&(prIeWmmParam->aucTxopLimit_BE)) + (u4AcOffset * 4)),&(prAcQueParams->u2TxopLimit)); + + prAcQueParams->ucGuradTime = TXM_DEFAULT_FLUSH_QUEUE_GUARD_TIME; + + +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To parse WMM/11n related IEs in scan results (only for AP peers) +* +* \param[in] prAdapter Adapter pointer +* \param[in] prScanResult The scan result which shall be parsed to obtain needed info +* \param[out] prStaRec The obtained info is stored in the STA_REC +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +mqmProcessScanResult( + IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prScanResult, + OUT P_STA_RECORD_T prStaRec + ) +{ + PUINT_8 pucIE; + UINT_16 u2IELength; + UINT_16 u2Offset; + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; + + DEBUGFUNC("mqmProcessScanResult"); + + ASSERT(prScanResult); + ASSERT(prStaRec); + + /* Reset the flag before parsing */ + prStaRec->fgIsWmmSupported = prStaRec->fgIsUapsdSupported = FALSE; + + if (!prAdapter->rWifiVar.fgSupportQoS){ + return; + } + + u2IELength = prScanResult->u2IELength; + pucIE = prScanResult->aucIEBuf; + + /* Goal: Determine whether the peer supports WMM/QoS and UAPSDU */ + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_WMM: + if((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) && + (!kalMemCmp(WMM_IE_OUI(pucIE),aucWfaOui,3))){ + + switch(WMM_IE_OUI_SUBTYPE(pucIE)){ + case VENDOR_OUI_SUBTYPE_WMM_PARAM: + if(IE_LEN(pucIE) != 24){ + break; /* WMM Param IE with a wrong length */ + } + else{ + prStaRec->fgIsWmmSupported = TRUE; + prStaRec->fgIsUapsdSupported = (((((P_IE_WMM_PARAM_T)pucIE)->ucQosInfo) & WMM_QOS_INFO_UAPSD)? TRUE: FALSE); + } + break; + + case VENDOR_OUI_SUBTYPE_WMM_INFO: + if(IE_LEN(pucIE) != 7){ + break; /* WMM Info IE with a wrong length */ + } + else{ + prStaRec->fgIsWmmSupported = TRUE; + prStaRec->fgIsUapsdSupported = (((((P_IE_WMM_INFO_T)pucIE)->ucQosInfo) & WMM_QOS_INFO_UAPSD)? TRUE: FALSE); + } + break; + + default: + /* A WMM QoS IE that doesn't matter. Ignore it. */ + break; + } + } + /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... (not cared) */ + + break; + + default: + /* A WMM IE that doesn't matter. Ignore it. */ + break; + } + } + DBGLOG(QM, LOUD, ("MQM: Scan Result Parsing (WMM=%d, UAPSD=%d)\n", + prStaRec->fgIsWmmSupported, prStaRec->fgIsUapsdSupported)); + +} + +UINT_8 +qmGetStaRecIdx( + IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucEthDestAddr, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType + ) +{ + UINT_32 i; + P_STA_RECORD_T prTempStaRec; + + prTempStaRec = NULL; + + ASSERT(prAdapter); + + //4 <1> DA = BMCAST + if(IS_BMCAST_MAC_ADDR(pucEthDestAddr)){ + return STA_REC_INDEX_BMCAST; + } + + + //4 <2> Check if an AP STA is present + for(i = 0; i < CFG_NUM_OF_STA_RECORD; i++){ + prTempStaRec = &(prAdapter->arStaRec[i]); + if((prTempStaRec->ucNetTypeIndex == eNetworkType) + && (prTempStaRec->fgIsAp) + && (prTempStaRec->fgIsValid)){ + return prTempStaRec->ucIndex; + } + } + + //4 <3> Not BMCAST, No AP --> Compare DA (i.e., to see whether this is a unicast frame to a client) + for(i = 0; i < CFG_NUM_OF_STA_RECORD; i++){ + prTempStaRec = &(prAdapter->arStaRec[i]); + if(prTempStaRec->fgIsValid){ + if(EQUAL_MAC_ADDR(prTempStaRec->aucMacAddr, pucEthDestAddr)){ + return prTempStaRec->ucIndex; + } + } + } + + + //4 <4> No STA found, Not BMCAST --> Indicate NOT_FOUND to FW + return STA_REC_INDEX_NOT_FOUND; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Generate the WMM Info IE +* +* \param[in] prAdapter Adapter pointer +* @param prMsduInfo The TX MMPDU +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +mqmGenerateWmmInfoIE ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ) +{ + P_IE_WMM_INFO_T prIeWmmInfo; + UINT_32 ucUapsd[] = { + WMM_QOS_INFO_BE_UAPSD, + WMM_QOS_INFO_BK_UAPSD, + WMM_QOS_INFO_VI_UAPSD, + WMM_QOS_INFO_VO_UAPSD + }; + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; + + P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo; + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("mqmGenerateWmmInfoIE"); + + ASSERT(prMsduInfo); + + /* In case QoS is not turned off, exit directly */ + if(!prAdapter->rWifiVar.fgSupportQoS){ + return; + } + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + ASSERT(prStaRec); + + if(prStaRec == NULL) { + return; + } + + if(!prStaRec->fgIsWmmSupported) { + return; + } + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; + + prIeWmmInfo = (P_IE_WMM_INFO_T) + ((PUINT_8) prMsduInfo->prPacket + prMsduInfo->u2FrameLength); + + prIeWmmInfo->ucId = ELEM_ID_WMM; + prIeWmmInfo->ucLength = ELEM_MAX_LEN_WMM_INFO; + + /* WMM-2.2.1 WMM Information Element Field Values */ + prIeWmmInfo->aucOui[0] = aucWfaOui[0]; + prIeWmmInfo->aucOui[1] = aucWfaOui[1]; + prIeWmmInfo->aucOui[2] = aucWfaOui[2]; + prIeWmmInfo->ucOuiType = VENDOR_OUI_TYPE_WMM; + prIeWmmInfo->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_INFO; + + prIeWmmInfo->ucVersion = VERSION_WMM; + prIeWmmInfo->ucQosInfo = 0; + + /* UAPSD intial queue configurations (delivery and trigger enabled)*/ +// if(prAdapter->rWifiVar.fgSupportUAPSD){ + if(prAdapter->rWifiVar.fgSupportUAPSD && prStaRec->fgIsUapsdSupported){ + + UINT_8 ucQosInfo = 0; + UINT_8 i; + + + /* Static U-APSD setting */ + for(i = ACI_BE; i <= ACI_VO; i++){ + if (prPmProfSetupInfo->ucBmpDeliveryAC & prPmProfSetupInfo->ucBmpTriggerAC & BIT(i)){ + ucQosInfo |= (UINT_8)ucUapsd[i]; + } + } + + + if (prPmProfSetupInfo->ucBmpDeliveryAC & prPmProfSetupInfo->ucBmpTriggerAC) { + switch (prPmProfSetupInfo->ucUapsdSp) { + case WMM_MAX_SP_LENGTH_ALL: + ucQosInfo |= WMM_QOS_INFO_MAX_SP_ALL; + break; + + case WMM_MAX_SP_LENGTH_2: + ucQosInfo |= WMM_QOS_INFO_MAX_SP_2; + break; + + case WMM_MAX_SP_LENGTH_4: + ucQosInfo |= WMM_QOS_INFO_MAX_SP_4; + break; + + case WMM_MAX_SP_LENGTH_6: + ucQosInfo |= WMM_QOS_INFO_MAX_SP_6; + break; + + default: + DBGLOG(QM, INFO, ("MQM: Incorrect SP length \n")); + ucQosInfo |= WMM_QOS_INFO_MAX_SP_2; + break; + } + } + prIeWmmInfo->ucQosInfo = ucQosInfo; + + } + + /* Increment the total IE length for the Element ID and Length fields. */ + prMsduInfo->u2FrameLength += IE_SIZE(prIeWmmInfo); + +} + + +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* @brief log2 calculation for CW +* +* @param[in] val value +* +* @return log2(val) +*/ +/*----------------------------------------------------------------------------*/ + +UINT_32 cwlog2(UINT_32 val) { + + UINT_32 n; + n=0; + + while (val >= 512) { n+= 9; val = val >> 9; } + while (val >= 16) { n+= 4; val >>= 4; } + while (val >= 2) { n+= 1; val >>= 1; } + return n; +} +#endif + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Generate the WMM Param IE +* +* \param[in] prAdapter Adapter pointer +* @param prMsduInfo The TX MMPDU +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +mqmGenerateWmmParamIE ( + IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo + ) +{ + P_IE_WMM_PARAM_T prIeWmmParam; + + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; + + UINT_8 aucACI[] = { + WMM_ACI_AC_BE, + WMM_ACI_AC_BK, + WMM_ACI_AC_VI, + WMM_ACI_AC_VO + }; + + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + ENUM_WMM_ACI_T eAci; + + DEBUGFUNC("mqmGenerateWmmParamIE"); + DBGLOG(QM, LOUD,("\n")); + + ASSERT(prMsduInfo); + + /* In case QoS is not turned off, exit directly */ + if(!prAdapter->rWifiVar.fgSupportQoS){ + return; + } + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if(prStaRec) { + if(!prStaRec->fgIsQoS) { + return; + } + } + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]); + + if(!prBssInfo->fgIsQBSS) { return; } + +#if 0 // 20120220 frog: update beacon content & change OP mode is a separate event for P2P network. + if( prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT && + prBssInfo->eCurrentOPMode != OP_MODE_BOW) + { + return; + } +#endif + + prIeWmmParam = (P_IE_WMM_PARAM_T) + ((PUINT_8) prMsduInfo->prPacket + prMsduInfo->u2FrameLength); + + prIeWmmParam->ucId = ELEM_ID_WMM; + prIeWmmParam->ucLength = ELEM_MAX_LEN_WMM_PARAM; + + /* WMM-2.2.1 WMM Information Element Field Values */ + prIeWmmParam->aucOui[0] = aucWfaOui[0]; + prIeWmmParam->aucOui[1] = aucWfaOui[1]; + prIeWmmParam->aucOui[2] = aucWfaOui[2]; + prIeWmmParam->ucOuiType = VENDOR_OUI_TYPE_WMM; + prIeWmmParam->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_PARAM; + + prIeWmmParam->ucVersion = VERSION_WMM; + prIeWmmParam->ucQosInfo = (prBssInfo->ucWmmParamSetCount & WMM_QOS_INFO_PARAM_SET_CNT); + + /* UAPSD intial queue configurations (delivery and trigger enabled)*/ + if(prAdapter->rWifiVar.fgSupportUAPSD){ + + prIeWmmParam->ucQosInfo |= WMM_QOS_INFO_UAPSD; + + } + + /* EDCA parameter */ + + for(eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++){ + + //DBGLOG(QM, LOUD, ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", + // eAci,prBssInfo->arACQueParmsForBcast[eAci].fgIsACMSet , + // prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn, + // prBssInfo->arACQueParmsForBcast[eAci].u2CWmin, + // prBssInfo->arACQueParmsForBcast[eAci].u2CWmax, + // prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit)); + + *( ((PUINT_8)(&prIeWmmParam->ucAciAifsn_BE)) + (eAci <<2) ) = (UINT_8) (aucACI[eAci] + | (prBssInfo->arACQueParmsForBcast[eAci].fgIsACMSet ? WMM_ACIAIFSN_ACM:0 ) + | (prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn & (WMM_ACIAIFSN_AIFSN))); +#if 1 + *( ((PUINT_8)(&prIeWmmParam->ucEcw_BE)) + (eAci <<2) ) = (UINT_8) (0 + | (((prBssInfo->aucCWminLog2ForBcast[eAci] )) & WMM_ECW_WMIN_MASK) + | ((((prBssInfo->aucCWmaxLog2ForBcast[eAci] )) << WMM_ECW_WMAX_OFFSET ) & WMM_ECW_WMAX_MASK) + ); +#else + *( ((PUINT_8)(&prIeWmmParam->ucEcw_BE)) + (eAci <<2) ) = (UINT_8) (0 + | (cwlog2((prBssInfo->arACQueParmsForBcast[eAci].u2CWmin + 1)) & WMM_ECW_WMIN_MASK) + | ((cwlog2((prBssInfo->arACQueParmsForBcast[eAci].u2CWmax + 1)) << WMM_ECW_WMAX_OFFSET ) & WMM_ECW_WMAX_MASK) + ); +#endif + + WLAN_SET_FIELD_16( ((PUINT_8)(prIeWmmParam->aucTxopLimit_BE)) + (eAci<<2) + , prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit); + + } + + /* Increment the total IE length for the Element ID and Length fields. */ + prMsduInfo->u2FrameLength += IE_SIZE(prIeWmmParam); + +} + + + + +ENUM_FRAME_ACTION_T +qmGetFrameAction( + IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType, + IN UINT_8 ucStaRecIdx, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_FRAME_TYPE_IN_CMD_Q_T eFrameType +) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + P_WLAN_MAC_HEADER_T prWlanFrame; + UINT_16 u2TxFrameCtrl; + + DEBUGFUNC("qmGetFrameAction"); + +#if (NIC_TX_BUFF_COUNT_TC4 > 2) +#define QM_MGMT_QUUEUD_THRESHOLD 2 +#else +#define QM_MGMT_QUUEUD_THRESHOLD 1 +#endif + + DATA_STRUC_INSPECTING_ASSERT(QM_MGMT_QUUEUD_THRESHOLD <= (NIC_TX_BUFF_COUNT_TC4)); + DATA_STRUC_INSPECTING_ASSERT(QM_MGMT_QUUEUD_THRESHOLD > 0); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetworkType]); + prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, ucStaRecIdx); + + /* XXX Check BOW P2P AIS time ot set active */ + if (!IS_BSS_ACTIVE(prBssInfo)) { + if (eFrameType == FRAME_TYPE_MMPDU) { + prWlanFrame = (P_WLAN_MAC_HEADER_T) prMsduInfo->prPacket; + u2TxFrameCtrl = (prWlanFrame->u2FrameCtrl) & MASK_FRAME_TYPE; // Optimized for ARM + if ((u2TxFrameCtrl == MAC_FRAME_DEAUTH) && (prMsduInfo->pfTxDoneHandler == NULL)) { + return FRAME_ACTION_TX_PKT; + } + + } + + DBGLOG(QM, INFO, ("Drop packets Action (Inactive %u).\n",prBssInfo->ucNetTypeIndex)); + TX_INC_CNT(&prAdapter->rTxCtrl, TX_INACTIVE_BSS_DROP); + return FRAME_ACTION_DROP_PKT; + } + + /* TODO Handle disconnect issue */ + + /* P2P probe Request frame */ + do { + if(eFrameType == FRAME_TYPE_MMPDU) { + ASSERT(prMsduInfo!=NULL); + prWlanFrame = (P_WLAN_MAC_HEADER_T) prMsduInfo->prPacket; + u2TxFrameCtrl = (prWlanFrame->u2FrameCtrl) & MASK_FRAME_TYPE; // Optimized for ARM + + if (u2TxFrameCtrl == MAC_FRAME_BEACON ) { + if( prBssInfo->fgIsNetAbsent) { + return FRAME_ACTION_DROP_PKT; + } + } + else if (u2TxFrameCtrl == MAC_FRAME_PROBE_RSP) { + if( prBssInfo->fgIsNetAbsent) { + break; + } + } + else if (u2TxFrameCtrl == MAC_FRAME_DEAUTH) { + if( prBssInfo->fgIsNetAbsent) { + break; + } + DBGLOG(P2P, LOUD, ("Sending DEAUTH Frame\n")); + return FRAME_ACTION_TX_PKT; + } + /* MMPDU with prStaRec && fgIsInUse not check fgIsNetActive */ + else if(u2TxFrameCtrl == MAC_FRAME_ASSOC_REQ + || u2TxFrameCtrl == MAC_FRAME_AUTH + || u2TxFrameCtrl == MAC_FRAME_REASSOC_REQ + || u2TxFrameCtrl == MAC_FRAME_PROBE_REQ + || u2TxFrameCtrl == MAC_FRAME_ACTION) { + + if(prStaRec){ + if(prStaRec->fgIsInPS) { + if( nicTxGetResource (prAdapter, TC4_INDEX)>= QM_MGMT_QUUEUD_THRESHOLD) { + return FRAME_ACTION_TX_PKT; + } + else { + return FRAME_ACTION_QUEUE_PKT; + } + } + } + return FRAME_ACTION_TX_PKT; + } + + if (!prStaRec){ + return FRAME_ACTION_TX_PKT; + } + else { + if (!prStaRec->fgIsInUse) { + return FRAME_ACTION_DROP_PKT; + } + } + + } /* FRAME_TYPE_MMPDU */ + else if ((eFrameType == FRAME_TYPE_802_1X)){ + + if (!prStaRec){ + return FRAME_ACTION_TX_PKT; + } + else { + if (!prStaRec->fgIsInUse) { + return FRAME_ACTION_DROP_PKT; + } + if(prStaRec->fgIsInPS) { + if( nicTxGetResource (prAdapter, TC4_INDEX)>= QM_MGMT_QUUEUD_THRESHOLD) { + return FRAME_ACTION_TX_PKT; + } + else { + return FRAME_ACTION_QUEUE_PKT; + } + } + } + + } /* FRAME_TYPE_802_1X */ + else if ((!IS_BSS_ACTIVE(prBssInfo)) + || (!prStaRec) + || (!prStaRec->fgIsInUse)){ + return FRAME_ACTION_DROP_PKT; + } + }while(0); + + if (prBssInfo->fgIsNetAbsent){ + DBGLOG(QM, LOUD, ("Queue packets (Absent %u).\n",prBssInfo->ucNetTypeIndex)); + return FRAME_ACTION_QUEUE_PKT; + } + + if (prStaRec && prStaRec->fgIsInPS){ + DBGLOG(QM, LOUD, ("Queue packets (PS %u).\n",prStaRec->fgIsInPS)); + return FRAME_ACTION_QUEUE_PKT; + } + else { + switch (eFrameType){ + case FRAME_TYPE_802_1X: + if (!prStaRec->fgIsValid){ + return FRAME_ACTION_QUEUE_PKT; + } + break; + + case FRAME_TYPE_MMPDU: + break; + + default: + ASSERT(0); + } + } + + return FRAME_ACTION_TX_PKT; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Handle BSS change operation Event from the FW +* +* \param[in] prAdapter Adapter pointer +* \param[in] prEvent The event packet from the FW +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +qmHandleEventBssAbsencePresence( + IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent + ) +{ + P_EVENT_BSS_ABSENCE_PRESENCE_T prEventBssStatus; + P_BSS_INFO_T prBssInfo; + BOOLEAN fgIsNetAbsentOld; + + prEventBssStatus = (P_EVENT_BSS_ABSENCE_PRESENCE_T)prEvent; + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prEventBssStatus->ucNetTypeIdx]); + fgIsNetAbsentOld = prBssInfo->fgIsNetAbsent; + prBssInfo->fgIsNetAbsent = prEventBssStatus->fgIsAbsent; + prBssInfo->ucBssFreeQuota = prEventBssStatus->ucBssFreeQuota; + + //DBGLOG(QM, TRACE, ("qmHandleEventBssAbsencePresence (ucNetTypeIdx=%d, fgIsAbsent=%d, FreeQuota=%d)\n", + // prEventBssStatus->ucNetTypeIdx, prBssInfo->fgIsNetAbsent, prBssInfo->ucBssFreeQuota)); + + DBGLOG(QM, TRACE, ("NAF=%d,%d,%d\n", + prEventBssStatus->ucNetTypeIdx, prBssInfo->fgIsNetAbsent, prBssInfo->ucBssFreeQuota)); + + if(!prBssInfo->fgIsNetAbsent) { + QM_DBG_CNT_INC(&(prAdapter->rQM),QM_DBG_CNT_27); + } + else { + QM_DBG_CNT_INC(&(prAdapter->rQM),QM_DBG_CNT_28); + } + /* From Absent to Present */ + if ((fgIsNetAbsentOld) && (!prBssInfo->fgIsNetAbsent)){ + kalSetEvent(prAdapter->prGlueInfo); + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Handle STA change PS mode Event from the FW +* +* \param[in] prAdapter Adapter pointer +* \param[in] prEvent The event packet from the FW +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +qmHandleEventStaChangePsMode( + IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent + ) +{ + P_EVENT_STA_CHANGE_PS_MODE_T prEventStaChangePsMode; + P_STA_RECORD_T prStaRec; + BOOLEAN fgIsInPSOld; + + //DbgPrint("QM:Event -RxBa\n"); + + prEventStaChangePsMode = (P_EVENT_STA_CHANGE_PS_MODE_T)prEvent; + prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventStaChangePsMode->ucStaRecIdx); + ASSERT(prStaRec); + + if(prStaRec) { + + fgIsInPSOld = prStaRec->fgIsInPS; + prStaRec->fgIsInPS = prEventStaChangePsMode->fgIsInPs; + + qmUpdateFreeQuota( + prAdapter, + prStaRec, + prEventStaChangePsMode->ucUpdateMode, + prEventStaChangePsMode->ucFreeQuota); + + //DBGLOG(QM, TRACE, ("qmHandleEventStaChangePsMode (ucStaRecIdx=%d, fgIsInPs=%d)\n", + // prEventStaChangePsMode->ucStaRecIdx, prStaRec->fgIsInPS)); + + + DBGLOG(QM, TRACE, ("PS=%d,%d\n", + prEventStaChangePsMode->ucStaRecIdx, prStaRec->fgIsInPS)); + + /* From PS to Awake */ + if ((fgIsInPSOld) && (!prStaRec->fgIsInPS)){ + kalSetEvent(prAdapter->prGlueInfo); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Update STA free quota Event from FW +* +* \param[in] prAdapter Adapter pointer +* \param[in] prEvent The event packet from the FW +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +qmHandleEventStaUpdateFreeQuota( + IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent + ) +{ + P_EVENT_STA_UPDATE_FREE_QUOTA_T prEventStaUpdateFreeQuota; + P_STA_RECORD_T prStaRec; + + + prEventStaUpdateFreeQuota = (P_EVENT_STA_UPDATE_FREE_QUOTA_T)prEvent; + prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventStaUpdateFreeQuota->ucStaRecIdx); + ASSERT(prStaRec); + + if(prStaRec) { + if(prStaRec->fgIsInPS) { + qmUpdateFreeQuota( + prAdapter, + prStaRec, + prEventStaUpdateFreeQuota->ucUpdateMode, + prEventStaUpdateFreeQuota->ucFreeQuota); + + kalSetEvent(prAdapter->prGlueInfo); + } +#if 0 + DBGLOG(QM, TRACE, ("qmHandleEventStaUpdateFreeQuota (ucStaRecIdx=%d, ucUpdateMode=%d, ucFreeQuota=%d)\n", + prEventStaUpdateFreeQuota->ucStaRecIdx, + prEventStaUpdateFreeQuota->ucUpdateMode, + prEventStaUpdateFreeQuota->ucFreeQuota)); +#endif + + DBGLOG(QM, TRACE, ("UFQ=%d,%d,%d\n", + prEventStaUpdateFreeQuota->ucStaRecIdx, + prEventStaUpdateFreeQuota->ucUpdateMode, + prEventStaUpdateFreeQuota->ucFreeQuota)); + + + } + +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Update STA free quota +* +* \param[in] prStaRec the STA +* \param[in] ucUpdateMode the method to update free quota +* \param[in] ucFreeQuota the value for update +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +qmUpdateFreeQuota( + IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN UINT_8 ucUpdateMode, + IN UINT_8 ucFreeQuota + ) +{ + + UINT_8 ucFreeQuotaForNonDelivery; + UINT_8 ucFreeQuotaForDelivery; + + ASSERT(prStaRec); + DBGLOG(QM, LOUD, ("qmUpdateFreeQuota orig ucFreeQuota=%d Mode %u New %u\n", + prStaRec->ucFreeQuota, ucUpdateMode, ucFreeQuota )); + + if(!prStaRec->fgIsInPS)return; + + switch (ucUpdateMode) { + case FREE_QUOTA_UPDATE_MODE_INIT: + case FREE_QUOTA_UPDATE_MODE_OVERWRITE: + prStaRec->ucFreeQuota = ucFreeQuota; + break; + case FREE_QUOTA_UPDATE_MODE_INCREASE: + prStaRec->ucFreeQuota += ucFreeQuota; + break; + case FREE_QUOTA_UPDATE_MODE_DECREASE: + prStaRec->ucFreeQuota -= ucFreeQuota; + break; + default: + ASSERT(0); + } + + DBGLOG(QM, LOUD, ("qmUpdateFreeQuota new ucFreeQuota=%d)\n", + prStaRec->ucFreeQuota )); + + ucFreeQuota = prStaRec->ucFreeQuota; + + ucFreeQuotaForNonDelivery = 0; + ucFreeQuotaForDelivery = 0; + + if(ucFreeQuota > 0) { + if( prStaRec->fgIsQoS && prStaRec->fgIsUapsdSupported + /* && prAdapter->rWifiVar.fgSupportQoS + && prAdapter->rWifiVar.fgSupportUAPSD*/) { + /* XXX We should assign quota to aucFreeQuotaPerQueue[NUM_OF_PER_STA_TX_QUEUES] */ + + if(prStaRec->ucFreeQuotaForNonDelivery > 0 && prStaRec->ucFreeQuotaForDelivery > 0) { + ucFreeQuotaForNonDelivery = ucFreeQuota>>1; + ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery; + } + else if(prStaRec->ucFreeQuotaForNonDelivery == 0 && prStaRec->ucFreeQuotaForDelivery == 0) { + ucFreeQuotaForNonDelivery = ucFreeQuota>>1; + ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery; + } + else if(prStaRec->ucFreeQuotaForNonDelivery > 0) { + /* NonDelivery is not busy */ + if(ucFreeQuota >= 3 ) { + ucFreeQuotaForNonDelivery = 2; + ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery ; + } + else { + ucFreeQuotaForDelivery = ucFreeQuota; + ucFreeQuotaForNonDelivery = 0; + } + } + else if(prStaRec->ucFreeQuotaForDelivery > 0) { + /* Delivery is not busy */ + if(ucFreeQuota >= 3 ) { + ucFreeQuotaForDelivery = 2; + ucFreeQuotaForNonDelivery = ucFreeQuota - ucFreeQuotaForDelivery; + } + else { + ucFreeQuotaForNonDelivery = ucFreeQuota; + ucFreeQuotaForDelivery = 0; + } + } + + } + else { + /* !prStaRec->fgIsUapsdSupported */ + ucFreeQuotaForNonDelivery = ucFreeQuota; + ucFreeQuotaForDelivery = 0; + } + } /* ucFreeQuota > 0 */ + + prStaRec->ucFreeQuotaForDelivery = ucFreeQuotaForDelivery; + prStaRec->ucFreeQuotaForNonDelivery = ucFreeQuotaForNonDelivery; + + DBGLOG(QM, LOUD, ("new QuotaForDelivery = %d QuotaForNonDelivery = %d\n", + prStaRec->ucFreeQuotaForDelivery, prStaRec->ucFreeQuotaForNonDelivery )); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Return the reorder queued RX packets +* +* \param[in] (none) +* +* \return The number of queued RX packets +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 +qmGetRxReorderQueuedBufferCount( + IN P_ADAPTER_T prAdapter + ) +{ + UINT_32 i, u4Total; + P_QUE_MGT_T prQM = &prAdapter->rQM; + u4Total = 0; + /* XXX The summation may impact the performance */ + for(i =0; iarRxBaTable[i].rReOrderQue.u4NumElem; +#if DBG && 0 + if(QUEUE_IS_EMPTY(&(prQM->arRxBaTable[i].rReOrderQue))){ + ASSERT(prQM->arRxBaTable[i].rReOrderQue == 0); + } +#endif + } + ASSERT(u4Total <=( CFG_NUM_OF_QM_RX_PKT_NUM*2)); + return u4Total; +} + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_bow.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_bow.c new file mode 100755 index 000000000000..5fc877f9abe4 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_bow.c @@ -0,0 +1,1459 @@ +/* +** $Id: @(#) gl_bow.c@@ +*/ + +/*! \file gl_bow.c + \brief Main routines of Linux driver interface for 802.11 PAL (BT 3.0 + HS) + + This file contains the main routines of Linux driver for MediaTek Inc. 802.11 + Wireless LAN Adapters. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: gl_bow.c $ + * + * 02 16 2012 chinghwa.yu + * [ALPS00235223] [20110216 Chinghwa] + + +[Root Cause] + +PAL operates BOW char dev poll after BOW char dev is registered. + + +[Solution] + +Rejects PAL char device operation after BOW is unregistered or when wlan GLUE_FLAG_HALT is set. + + +This is a workaround for BOW driver robustness, happens only in ICS. + + +Root cause should be fixed by CR [ALPS00231570] + + +orig Feature_Name : Others + + +[Customer Priority]: 1.High + +[Customer Issue Type(Classification)]: CNN + +[Original owner]: mtk54109 Xi Huang (#67198) + + +[Submitter Information]:VEND_YONGXU CEN + +TEL: 028-66189617?823 + +EMAIL: cenyongxu@mgsei.com + +[Finder Information]: Yongxu Cen + +TEL: 028-66767232?だ审?823 + +EMAIL: cenyongxu@mgsei.com + + +The device reboot automatically and then the "KE" pops up after you turn on the "Airplane mode".(once) + + +Happened time10:47 + + +SW Version:ALPS.ICS.FDD.p25 + + +Reference phoneThis issue doesn't exist in Nexus S. + + +Contactmtk@mgsei.com 028-66767232?だ审?823. + + + * [ALPS00235223] [Rose][ICS][Cross Feature][AEE-IPANIC]The device reboot automatically and then the "KE" pops up after you turn on the "Airplane mode".(once) + * + * [Root Cause] + * PAL operates BOW char dev poll after BOW char dev is registered. + * + * [Solution] + * Rejects PAL char device operation after BOW is unregistered or when wlan GLUE_FLAG_HALT is set. + * + * This is a workaround for BOW driver robustness, happens only in ICS. + * + * Root cause should be fixed by CR [ALPS00231570] + * + * 02 03 2012 chinghwa.yu + * [ALPS00118114] [Rose][ICS][Free Test][Bluetooth]The "KE" pops up after you turn on the airplane mode.(5/5) + * + * Rejects PAL char device operation after BOW is unregistered. + * + * 01 20 2012 cp.wu + * [ALPS00096191] [MT6620 Wi-Fi][Driver][Firmware] Porting to ALPS4.0_DEV branch + * sync to up-to-date changes including: + * 1. BOW bugfix + * 2. XLOG + * + * 11 10 2011 cp.wu + * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer + * 1. eliminaite direct calls to printk in porting layer. + * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. + * + * 10 25 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Modify ampc0 char device for major number 151 for all MT6575 projects. + * + * 07 28 2011 cp.wu + * [WCXRP00000884] [MT6620 Wi-Fi][Driver] Deprecate ioctl interface by unlocked ioctl + * unlocked_ioctl returns as long instead of int. + * + * 07 28 2011 cp.wu + * [WCXRP00000884] [MT6620 Wi-Fi][Driver] Deprecate ioctl interface by unlocked ioctl + * migrate to unlocked ioctl interface + * + * 04 12 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add WMM IE for BOW initiator data. + * + * 04 10 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Change Link disconnection event procedure for hotspot and change skb length check to 1514 bytes. + * + * 04 09 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Change Link connection event procedure and change skb length check to 1512 bytes. + * + * 03 27 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add new feature - multiple physical link support. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 06 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Sync BOW Driver to latest person development branch version.. + * + * 03 03 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * support concurrent network + * + * 03 03 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * replace alloc_netdev to alloc_netdev_mq for BoW + * + * 03 03 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * modify net device relative functions to support multiple H/W queues + * + * 02 15 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Update net register and BOW for concurrent features. + * + * 02 10 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Fix kernel API change issue. + * Before ALPS 2.2 (2.2 included), kfifo_alloc() is + * struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock); + * After ALPS 2.3, kfifo_alloc() is changed to + * int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask); + * + * 02 09 2011 cp.wu + * [WCXRP00000430] [MT6620 Wi-Fi][Firmware][Driver] Create V1.2 branch for MT6620E1 and MT6620E3 + * create V1.2 driver branch based on label MT6620_WIFI_DRIVER_V1_2_110209_1031 + * with BOW and P2P enabled as default + * + * 02 08 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Replace kfifo_get and kfifo_put with kfifo_out and kfifo_in. + * Update BOW get MAC status, remove returning event for AIS network type. + * + * 01 12 2011 cp.wu + * [WCXRP00000357] [MT6620 Wi-Fi][Driver][Bluetooth over Wi-Fi] add another net device interface for BT AMP + * implementation of separate BT_OVER_WIFI data path. + * + * 01 12 2011 cp.wu + * [WCXRP00000356] [MT6620 Wi-Fi][Driver] fill mac header length for security frames 'cause hardware header translation needs such information + * fill mac header length information for 802.1x frames. + * + * 11 11 2010 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Fix BoW timer assert issue. + * + * 09 14 2010 chinghwa.yu + * NULL + * Add bowRunEventAAAComplete. + * + * 09 14 2010 cp.wu + * NULL + * correct typo: POLLOUT instead of POLL_OUT + * + * 09 13 2010 cp.wu + * NULL + * add waitq for poll() and read(). + * + * 08 24 2010 chinghwa.yu + * NULL + * Update BOW for the 1st time. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 05 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * change variable names for multiple physical link to match with coding convention + * + * 05 05 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * multiple BoW interfaces need to compare with peer address + * + * 04 28 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * change prefix for data structure used to communicate with 802.11 PAL + * to avoid ambiguous naming with firmware interface + * + * 04 28 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * fix kalIndicateBOWEvent. + * + * 04 27 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add multiple physical link support + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * * * * * * * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "gl_os.h" +#include "debug.h" +#include "wlan_lib.h" +#include "gl_wext.h" +#include "precomp.h" +#include +#include "bss.h" + +#if CFG_ENABLE_BT_OVER_WIFI + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* @FIXME if there is command/event with payload length > 28 */ +#define MAX_BUFFER_SIZE (64) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +#if CFG_BOW_TEST + UINT_32 g_u4PrevSysTime = 0; + UINT_32 g_u4CurrentSysTime = 0; + UINT_32 g_arBowRevPalPacketTime[11]; +#endif + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +// forward declarations +static ssize_t +mt6620_ampc_read( + IN struct file *filp, + IN char __user *buf, + IN size_t size, + IN OUT loff_t *ppos); + +static ssize_t +mt6620_ampc_write( + IN struct file *filp, + OUT const char __user *buf, + IN size_t size, + IN OUT loff_t *ppos); + +static long +mt6620_ampc_ioctl( + IN struct file *filp, + IN unsigned int cmd, + IN OUT unsigned long arg); + +static unsigned int +mt6620_ampc_poll( + IN struct file *filp, + IN poll_table *wait); + +static int +mt6620_ampc_open( + IN struct inode *inodep, + IN struct file *filp); + +static int +mt6620_ampc_release( + IN struct inode *inodep, + IN struct file *filp); + + +// character file operations +static const struct file_operations mt6620_ampc_fops = { + .owner = THIS_MODULE, + .read = mt6620_ampc_read, + .write = mt6620_ampc_write, + .unlocked_ioctl = mt6620_ampc_ioctl, + .poll = mt6620_ampc_poll, + .open = mt6620_ampc_open, + .release = mt6620_ampc_release, +}; + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Register for character device to communicate with 802.11 PAL +* +* \param[in] prGlueInfo Pointer to glue info +* +* \return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +glRegisterAmpc ( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + ASSERT(prGlueInfo); + + if(prGlueInfo->rBowInfo.fgIsRegistered == TRUE) { + return FALSE; + } + else { +#if 0 + // 1. allocate major number dynamically + + if(alloc_chrdev_region(&(prGlueInfo->rBowInfo.u4DeviceNumber), + 0, // first minor number + 1, // number + GLUE_BOW_DEVICE_NAME) !=0) + + return FALSE; +#endif + +#if 1 + +#if defined (CONFIG_AMPC_CDEV_NUM) + prGlueInfo->rBowInfo.u4DeviceNumber = MKDEV(CONFIG_AMPC_CDEV_NUM, 0); +#else + prGlueInfo->rBowInfo.u4DeviceNumber = MKDEV(226, 0); +#endif + + if(register_chrdev_region(prGlueInfo->rBowInfo.u4DeviceNumber, + 1, // number + GLUE_BOW_DEVICE_NAME) !=0) + + return FALSE; +#endif + + // 2. spin-lock initialization + // spin_lock_init(&(prGlueInfo->rBowInfo.rSpinLock)); + + // 3. initialize kfifo +/* prGlueInfo->rBowInfo.prKfifo = kfifo_alloc(GLUE_BOW_KFIFO_DEPTH, + GFP_KERNEL, + &(prGlueInfo->rBowInfo.rSpinLock));*/ + if ((kfifo_alloc((struct kfifo *) &(prGlueInfo->rBowInfo.rKfifo), GLUE_BOW_KFIFO_DEPTH, GFP_KERNEL))) + goto fail_kfifo_alloc; + +// if(prGlueInfo->rBowInfo.prKfifo == NULL) + if(&(prGlueInfo->rBowInfo.rKfifo) == NULL) + goto fail_kfifo_alloc; + + // 4. initialize cdev + cdev_init(&(prGlueInfo->rBowInfo.cdev), &mt6620_ampc_fops); + prGlueInfo->rBowInfo.cdev.owner = THIS_MODULE; + prGlueInfo->rBowInfo.cdev.ops = &mt6620_ampc_fops; + + // 5. add character device + if(cdev_add(&(prGlueInfo->rBowInfo.cdev), + prGlueInfo->rBowInfo.u4DeviceNumber, + 1)) + goto fail_cdev_add; + + + // 6. in queue initialization + init_waitqueue_head(&(prGlueInfo->rBowInfo.outq)); + + // 7. finish + prGlueInfo->rBowInfo.fgIsRegistered = TRUE; + return TRUE; + +fail_cdev_add: + kfifo_free(&(prGlueInfo->rBowInfo.rKfifo)); +// kfifo_free(prGlueInfo->rBowInfo.prKfifo); +fail_kfifo_alloc: + unregister_chrdev_region(prGlueInfo->rBowInfo.u4DeviceNumber, 1); + return FALSE; + } +} /* end of glRegisterAmpc */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Unregister character device for communicating with 802.11 PAL +* +* \param[in] prGlueInfo Pointer to glue info +* +* \return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +glUnregisterAmpc ( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + ASSERT(prGlueInfo); + + if(prGlueInfo->rBowInfo.fgIsRegistered == FALSE) { + return FALSE; + } + else { + prGlueInfo->rBowInfo.fgIsRegistered = FALSE; + + // 1. free netdev if necessary +#if CFG_BOW_SEPARATE_DATA_PATH + kalUninitBowDevice(prGlueInfo); +#endif + + // 2. removal of character device + cdev_del(&(prGlueInfo->rBowInfo.cdev)); + + // 3. free kfifo +// kfifo_free(prGlueInfo->rBowInfo.prKfifo); + kfifo_free(&(prGlueInfo->rBowInfo.rKfifo)); +// prGlueInfo->rBowInfo.prKfifo = NULL; +// prGlueInfo->rBowInfo.rKfifo = NULL; + + // 4. free device number + unregister_chrdev_region(prGlueInfo->rBowInfo.u4DeviceNumber, 1); + + return TRUE; + } +} /* end of glUnregisterAmpc */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief read handler for character device to communicate with 802.11 PAL +* +* \param[in] +* \return +* Follows Linux Character Device Interface +* +*/ +/*----------------------------------------------------------------------------*/ +static ssize_t +mt6620_ampc_read( + IN struct file *filp, + IN char __user *buf, + IN size_t size, + IN OUT loff_t *ppos) +{ + UINT_8 aucBuffer[MAX_BUFFER_SIZE]; + ssize_t retval; + + P_GLUE_INFO_T prGlueInfo; + prGlueInfo = (P_GLUE_INFO_T)(filp->private_data); + + ASSERT(prGlueInfo); + + if ((prGlueInfo->rBowInfo.fgIsRegistered == FALSE) || (prGlueInfo->u4Flag & GLUE_FLAG_HALT)) { + return -EFAULT; + } + + // size check +// if(kfifo_len(prGlueInfo->rBowInfo.prKfifo) >= size) + if(kfifo_len(&(prGlueInfo->rBowInfo.rKfifo)) >= size) + retval = size; + else + retval = kfifo_len(&(prGlueInfo->rBowInfo.rKfifo)); +// retval = kfifo_len(prGlueInfo->rBowInfo.prKfifo); + +// kfifo_get(prGlueInfo->rBowInfo.prKfifo, aucBuffer, retval); +// kfifo_out(prGlueInfo->rBowInfo.prKfifo, aucBuffer, retval); + if (!(kfifo_out(&(prGlueInfo->rBowInfo.rKfifo), aucBuffer, retval))) + retval = -EIO; + + if(copy_to_user(buf, aucBuffer, retval)) + retval = -EIO; + + return retval; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief write handler for character device to communicate with 802.11 PAL +* +* \param[in] +* \return +* Follows Linux Character Device Interface +* +*/ +/*----------------------------------------------------------------------------*/ +static ssize_t +mt6620_ampc_write( + IN struct file *filp, + OUT const char __user *buf, + IN size_t size, + IN OUT loff_t *ppos) +{ +#if CFG_BOW_TEST + UINT_8 i; +#endif + + UINT_8 aucBuffer[MAX_BUFFER_SIZE]; + P_AMPC_COMMAND prCmd; + P_GLUE_INFO_T prGlueInfo; + + prGlueInfo = (P_GLUE_INFO_T)(filp->private_data); + ASSERT(prGlueInfo); + + if ((prGlueInfo->rBowInfo.fgIsRegistered == FALSE) || (prGlueInfo->u4Flag & GLUE_FLAG_HALT)) { + return -EFAULT; + } + + if(size > MAX_BUFFER_SIZE) + return -EINVAL; + else if(copy_from_user(aucBuffer, buf, size)) + return -EIO; + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("AMP driver CMD buffer size : %d.\n", size)); + + for(i = 0; i < MAX_BUFFER_SIZE; i++) + { + DBGLOG(BOW, EVENT, ("AMP write content : 0x%x.\n", aucBuffer[i])); + } + + DBGLOG(BOW, EVENT, ("BoW CMD write.\n")); +#endif + + prCmd = (P_AMPC_COMMAND) aucBuffer; + + #if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("AMP write content payload length : %d.\n", prCmd->rHeader.u2PayloadLength)); + + DBGLOG(BOW, EVENT, ("AMP write content header length : %d.\n", sizeof(AMPC_COMMAND_HEADER_T))); + #endif + + // size check + if(prCmd->rHeader.u2PayloadLength + sizeof(AMPC_COMMAND_HEADER_T) != size) + { + #if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("Wrong CMD total length.\n")); + #endif + + return -EINVAL; + } + + if(wlanbowHandleCommand(prGlueInfo->prAdapter, prCmd) == WLAN_STATUS_SUCCESS) + return size; + else + return -EINVAL; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief ioctl handler for character device to communicate with 802.11 PAL +* +* \param[in] +* \return +* Follows Linux Character Device Interface +* +*/ +/*----------------------------------------------------------------------------*/ +static long +mt6620_ampc_ioctl( + IN struct file *filp, + IN unsigned int cmd, + IN OUT unsigned long arg) +{ + int err = 0; + P_GLUE_INFO_T prGlueInfo; + prGlueInfo = (P_GLUE_INFO_T)(filp->private_data); + + ASSERT(prGlueInfo); + + if ((prGlueInfo->rBowInfo.fgIsRegistered == FALSE) || (prGlueInfo->u4Flag & GLUE_FLAG_HALT)) { + return -EFAULT; + } + + // permission check + if(_IOC_DIR(cmd) & _IOC_READ) + err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); + else if (_IOC_DIR(cmd) & _IOC_WRITE) + err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); + if (err) + return -EFAULT; + + // no ioctl is implemented yet + return 0; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief ioctl handler for character device to communicate with 802.11 PAL +* +* \param[in] +* \return +* Follows Linux Character Device Interface +* +*/ +/*----------------------------------------------------------------------------*/ +static unsigned int +mt6620_ampc_poll( + IN struct file *filp, + IN poll_table *wait) +{ + unsigned int retval; + P_GLUE_INFO_T prGlueInfo; + prGlueInfo = (P_GLUE_INFO_T)(filp->private_data); + + ASSERT(prGlueInfo); + + if ((prGlueInfo->rBowInfo.fgIsRegistered == FALSE) || (prGlueInfo->u4Flag & GLUE_FLAG_HALT)) { + return -EFAULT; + } + + poll_wait(filp, &prGlueInfo->rBowInfo.outq, wait); + + retval = (POLLOUT | POLLWRNORM); // always accepts incoming command packets + +// DBGLOG(BOW, EVENT, ("mt6620_ampc_pol, POLLOUT | POLLWRNORM, %x\n", retval)); + +// if(kfifo_len(prGlueInfo->rBowInfo.prKfifo) > 0) + if(kfifo_len(&(prGlueInfo->rBowInfo.rKfifo)) > 0) + { + retval |= (POLLIN | POLLRDNORM); + +// DBGLOG(BOW, EVENT, ("mt6620_ampc_pol, POLLIN | POLLRDNORM, %x\n", retval)); + + } + + return retval; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief open handler for character device to communicate with 802.11 PAL +* +* \param[in] +* \return +* Follows Linux Character Device Interface +* +*/ +/*----------------------------------------------------------------------------*/ +static int +mt6620_ampc_open( + IN struct inode *inodep, + IN struct file *filp) +{ + P_GLUE_INFO_T prGlueInfo; + P_GL_BOW_INFO prBowInfo; + + prBowInfo = container_of(inodep->i_cdev, GL_BOW_INFO, cdev); + ASSERT(prBowInfo); + + prGlueInfo = container_of(prBowInfo, GLUE_INFO_T, rBowInfo); + ASSERT(prGlueInfo); + + // set-up private data + filp->private_data = prGlueInfo; + + return 0; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief close handler for character device to communicate with 802.11 PAL +* +* \param[in] +* \return +* Follows Linux Character Device Interface +* +*/ +/*----------------------------------------------------------------------------*/ +static int +mt6620_ampc_release( + IN struct inode *inodep, + IN struct file *filp) +{ + P_GLUE_INFO_T prGlueInfo; + prGlueInfo = (P_GLUE_INFO_T)(filp->private_data); + + ASSERT(prGlueInfo); + + return 0; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to indicate event for Bluetooth over Wi-Fi +* +* \param[in] +* prGlueInfo +* prEvent +* \return +* none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalIndicateBOWEvent( + IN P_GLUE_INFO_T prGlueInfo, + IN P_AMPC_EVENT prEvent + ) +{ + size_t u4AvailSize, u4EventSize; + + ASSERT(prGlueInfo); + ASSERT(prEvent); + + // check device + if ((prGlueInfo->rBowInfo.fgIsRegistered == FALSE) || (prGlueInfo->u4Flag & GLUE_FLAG_HALT)) { + return; + } + +/* u4AvailSize = + GLUE_BOW_KFIFO_DEPTH - kfifo_len(prGlueInfo->rBowInfo.prKfifo);*/ + + u4AvailSize = + GLUE_BOW_KFIFO_DEPTH - kfifo_len(&(prGlueInfo->rBowInfo.rKfifo)); + + + u4EventSize = + prEvent->rHeader.u2PayloadLength + sizeof(AMPC_EVENT_HEADER_T); + + // check kfifo availability + if(u4AvailSize < u4EventSize) { + DBGLOG(BOW, EVENT, ("[bow] no space for event: %d/%d\n", + u4EventSize, + u4AvailSize)); + return; + } + + // queue into kfifo +// kfifo_put(prGlueInfo->rBowInfo.prKfifo, (PUINT_8)prEvent, u4EventSize); +// kfifo_in(prGlueInfo->rBowInfo.prKfifo, (PUINT_8)prEvent, u4EventSize); + kfifo_in(&(prGlueInfo->rBowInfo.rKfifo), (PUINT_8)prEvent, u4EventSize); + wake_up_interruptible(&(prGlueInfo->rBowInfo.outq)); + + return; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to retrieve Bluetooth-over-Wi-Fi state from glue layer +* +* \param[in] +* prGlueInfo +* rPeerAddr +* \return +* ENUM_BOW_DEVICE_STATE +*/ +/*----------------------------------------------------------------------------*/ +ENUM_BOW_DEVICE_STATE +kalGetBowState ( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_8 aucPeerAddress[6] + ) +{ + UINT_8 i; + + ASSERT(prGlueInfo); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("kalGetBowState.\n")); +#endif + + for(i = 0 ; i < CFG_BOW_PHYSICAL_LINK_NUM ; i++) + { + if(EQUAL_MAC_ADDR(prGlueInfo->rBowInfo.arPeerAddr, aucPeerAddress) == 0) + { + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("kalGetBowState, aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", i, + aucPeerAddress[0], + aucPeerAddress[1], + aucPeerAddress[2], + aucPeerAddress[3], + aucPeerAddress[4], + aucPeerAddress[5])); + + DBGLOG(BOW, EVENT, ("kalGetBowState, prGlueInfo->rBowInfo.aeState %x, %x.\n", i, prGlueInfo->rBowInfo.aeState[i])); + +#endif + + return prGlueInfo->rBowInfo.aeState[i]; + } + } + + return BOW_DEVICE_STATE_DISCONNECTED; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to set Bluetooth-over-Wi-Fi state in glue layer +* +* \param[in] +* prGlueInfo +* eBowState +* rPeerAddr +* \return +* none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +kalSetBowState ( + IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_BOW_DEVICE_STATE eBowState, + IN UINT_8 aucPeerAddress[6] + ) +{ + UINT_8 i; + + ASSERT(prGlueInfo); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("kalSetBowState.\n")); + + DBGLOG(BOW, EVENT, ("kalSetBowState, prGlueInfo->rBowInfo.arPeerAddr, %x:%x:%x:%x:%x:%x.\n", + prGlueInfo->rBowInfo.arPeerAddr[0], + prGlueInfo->rBowInfo.arPeerAddr[1], + prGlueInfo->rBowInfo.arPeerAddr[2], + prGlueInfo->rBowInfo.arPeerAddr[3], + prGlueInfo->rBowInfo.arPeerAddr[4], + prGlueInfo->rBowInfo.arPeerAddr[5])); + + DBGLOG(BOW, EVENT, ("kalSetBowState, aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", + aucPeerAddress[0], + aucPeerAddress[1], + aucPeerAddress[2], + aucPeerAddress[3], + aucPeerAddress[4], + aucPeerAddress[5])); +#endif + + for(i = 0 ; i < CFG_BOW_PHYSICAL_LINK_NUM ; i++) + { + if(EQUAL_MAC_ADDR(prGlueInfo->rBowInfo.arPeerAddr, aucPeerAddress) == 0) + { + prGlueInfo->rBowInfo.aeState[i] = eBowState; + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("kalSetBowState, aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", i, + aucPeerAddress[0], + aucPeerAddress[1], + aucPeerAddress[2], + aucPeerAddress[3], + aucPeerAddress[4], + aucPeerAddress[5])); + + DBGLOG(BOW, EVENT, ("kalSetBowState, prGlueInfo->rBowInfo.aeState %x, %x.\n", i, prGlueInfo->rBowInfo.aeState[i])); +#endif + + return TRUE; + } + } + + return FALSE; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to retrieve Bluetooth-over-Wi-Fi global state +* +* \param[in] +* prGlueInfo +* +* \return +* BOW_DEVICE_STATE_DISCONNECTED +* in case there is no BoW connection or +* BoW connection under initialization +* +* BOW_DEVICE_STATE_STARTING +* in case there is no BoW connection but +* some BoW connection under initialization +* +* BOW_DEVICE_STATE_CONNECTED +* in case there is any BoW connection available +*/ +/*----------------------------------------------------------------------------*/ +ENUM_BOW_DEVICE_STATE +kalGetBowGlobalState ( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + UINT_32 i; + + ASSERT(prGlueInfo); + + +//Henry, can reduce this logic to indentify state change + + for(i = 0 ; i < CFG_BOW_PHYSICAL_LINK_NUM ; i++) { + if(prGlueInfo->rBowInfo.aeState[i] == BOW_DEVICE_STATE_CONNECTED) { + return BOW_DEVICE_STATE_CONNECTED; + } + } + + for(i = 0 ; i < CFG_BOW_PHYSICAL_LINK_NUM ; i++) { + if(prGlueInfo->rBowInfo.aeState[i] == BOW_DEVICE_STATE_STARTING) { + return BOW_DEVICE_STATE_STARTING; + } + } + + return BOW_DEVICE_STATE_DISCONNECTED; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to retrieve Bluetooth-over-Wi-Fi operating frequency +* +* \param[in] +* prGlueInfo +* +* \return +* in unit of KHz +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 +kalGetBowFreqInKHz( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + ASSERT(prGlueInfo); + + return prGlueInfo->rBowInfo.u4FreqInKHz; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to retrieve Bluetooth-over-Wi-Fi role +* +* \param[in] +* prGlueInfo +* +* \return +* 0: Responder +* 1: Initiator +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 +kalGetBowRole( + IN P_GLUE_INFO_T prGlueInfo, + IN PARAM_MAC_ADDRESS rPeerAddr + ) +{ + UINT_32 i; + + ASSERT(prGlueInfo); + + for(i = 0 ; i < CFG_BOW_PHYSICAL_LINK_NUM ; i++) { + if(EQUAL_MAC_ADDR(prGlueInfo->rBowInfo.arPeerAddr[i], rPeerAddr) == 0) { + return prGlueInfo->rBowInfo.aucRole[i]; + } + } + + return 0; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to set Bluetooth-over-Wi-Fi role +* +* \param[in] +* prGlueInfo +* ucRole +* 0: Responder +* 1: Initiator +* \return +* none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalSetBowRole( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_8 ucRole, + IN PARAM_MAC_ADDRESS rPeerAddr + ) +{ + UINT_32 i; + + ASSERT(prGlueInfo); + ASSERT(ucRole <= 1); + + for(i = 0 ; i < CFG_BOW_PHYSICAL_LINK_NUM ; i++) { + if(EQUAL_MAC_ADDR(prGlueInfo->rBowInfo.arPeerAddr[i], rPeerAddr) == 0) { + prGlueInfo->rBowInfo.aucRole[i] = ucRole; //Henry, 0 : Responder, 1 : Initiator + } + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to get available Bluetooth-over-Wi-Fi physical link number +* +* \param[in] +* prGlueInfo +* \return +* UINT_32 +* how many physical links are aviailable +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 +kalGetBowAvailablePhysicalLinkCount( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + UINT_8 i; + UINT_8 ucLinkCount = 0; + + ASSERT(prGlueInfo); + + for(i = 0 ; i < CFG_BOW_PHYSICAL_LINK_NUM ; i++) { + if(prGlueInfo->rBowInfo.aeState[i] == BOW_DEVICE_STATE_DISCONNECTED) { + ucLinkCount++; + } + } + +#if 0//CFG_BOW_TEST + DBGLOG(BOW, EVENT, ("kalGetBowAvailablePhysicalLinkCount, ucLinkCount, %c.\n", ucLinkCount)); +#endif + + return ucLinkCount; +} + +#if CFG_BOW_SEPARATE_DATA_PATH + +/* Net Device Hooks */ +/*----------------------------------------------------------------------------*/ +/*! + * \brief A function for net_device open (ifup) + * + * \param[in] prDev Pointer to struct net_device. + * + * \retval 0 The execution succeeds. + * \retval < 0 The execution failed. + */ +/*----------------------------------------------------------------------------*/ +static int +bowOpen( + IN struct net_device *prDev + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + /* 2. carrier on & start TX queue */ + netif_carrier_on(prDev); + netif_tx_start_all_queues(prDev); + + return 0; /* success */ +} + + +/*----------------------------------------------------------------------------*/ +/*! + * \brief A function for net_device stop (ifdown) + * + * \param[in] prDev Pointer to struct net_device. + * + * \retval 0 The execution succeeds. + * \retval < 0 The execution failed. + */ +/*----------------------------------------------------------------------------*/ +static int +bowStop( + IN struct net_device *prDev + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + /* 1. stop TX queue */ + netif_tx_stop_all_queues(prDev); + + /* 2. turn of carrier */ + if(netif_carrier_ok(prDev)) { + netif_carrier_off(prDev); + } + + return 0; +}; + + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is TX entry point of NET DEVICE. + * + * \param[in] prSkb Pointer of the sk_buff to be sent + * \param[in] prDev Pointer to struct net_device + * + * \retval NETDEV_TX_OK - on success. + * \retval NETDEV_TX_BUSY - on failure, packet will be discarded by upper layer. + */ +/*----------------------------------------------------------------------------*/ +static int +bowHardStartXmit( + IN struct sk_buff *prSkb, + IN struct net_device *prDev + ) +{ + P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + + P_QUE_ENTRY_T prQueueEntry = NULL; + P_QUE_T prTxQueue = NULL; + UINT_16 u2QueueIdx = 0; + UINT_8 ucDSAP, ucSSAP, ucControl; + UINT_8 aucOUI[3]; + PUINT_8 aucLookAheadBuf = NULL; + +#if CFG_BOW_TEST + UINT_32 i; +#endif + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prSkb); + ASSERT(prDev); + ASSERT(prGlueInfo); + + aucLookAheadBuf = prSkb->data; + + ucDSAP = *(PUINT_8) &aucLookAheadBuf[ETH_LLC_OFFSET]; + ucSSAP = *(PUINT_8) &aucLookAheadBuf[ETH_LLC_OFFSET + 1]; + ucControl = *(PUINT_8) &aucLookAheadBuf[ETH_LLC_OFFSET + 2]; + aucOUI[0] = *(PUINT_8) &aucLookAheadBuf[ETH_SNAP_OFFSET]; + aucOUI[1] = *(PUINT_8) &aucLookAheadBuf[ETH_SNAP_OFFSET + 1]; + aucOUI[2] = *(PUINT_8) &aucLookAheadBuf[ETH_SNAP_OFFSET + 2]; + + if (!(ucDSAP == ETH_LLC_DSAP_SNAP && + ucSSAP == ETH_LLC_SSAP_SNAP && + ucControl == ETH_LLC_CONTROL_UNNUMBERED_INFORMATION && + aucOUI[0] == ETH_SNAP_BT_SIG_OUI_0 && + aucOUI[1] == ETH_SNAP_BT_SIG_OUI_1 && + aucOUI[2] == ETH_SNAP_BT_SIG_OUI_2) || (prSkb->len > 1514)) + { + +#if CFG_BOW_TEST + DBGLOG(BOW, TRACE, ("Invalid BOW packet, skip tx\n")); +#endif + + dev_kfree_skb(prSkb); + return NETDEV_TX_OK; + } + + if (prGlueInfo->u4Flag & GLUE_FLAG_HALT) { + DBGLOG(BOW, TRACE, ("GLUE_FLAG_HALT skip tx\n")); + dev_kfree_skb(prSkb); + return NETDEV_TX_OK; + } + + prQueueEntry = (P_QUE_ENTRY_T) GLUE_GET_PKT_QUEUE_ENTRY(prSkb); + prTxQueue = &prGlueInfo->rTxQueue; + +#if CFG_BOW_TEST + DBGLOG(BOW, TRACE, ("Tx sk_buff->len: %d\n", prSkb->len)); + DBGLOG(BOW, TRACE, ("Tx sk_buff->data_len: %d\n", prSkb->data_len)); + DBGLOG(BOW, TRACE, ("Tx sk_buff->data:\n")); + + for(i = 0; i < prSkb->len; i++) + { + DBGLOG(BOW, TRACE, ("%4x", prSkb->data[i])); + + if((i+1)%16 ==0) + { + DBGLOG(BOW, TRACE, ("\n")); + } + } + + DBGLOG(BOW, TRACE, ("\n"); +#endif + +#if CFG_BOW_TEST +// g_u4CurrentSysTime = (OS_SYSTIME)kalGetTimeTick(); + + g_u4CurrentSysTime = (OS_SYSTIME) jiffies_to_usecs(jiffies); + + i = g_u4CurrentSysTime - g_u4PrevSysTime; + + if ( (i >> 10) > 0) + { + i = 10; + } + else + { + i = i >> 7; + } + + g_arBowRevPalPacketTime[i]++; + + g_u4PrevSysTime = g_u4CurrentSysTime; + +#endif + + if (wlanProcessSecurityFrame(prGlueInfo->prAdapter, (P_NATIVE_PACKET) prSkb) == FALSE) { + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + QUEUE_INSERT_TAIL(prTxQueue, prQueueEntry); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + + + GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingFrameNum); + GLUE_INC_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_BOW_INDEX][u2QueueIdx]); + + if (prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_BOW_INDEX][u2QueueIdx] >= CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD) { + netif_stop_subqueue(prDev, u2QueueIdx); + } + } + else { + GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingSecurityFrameNum); + } + + kalSetEvent(prGlueInfo); + + /* For Linux, we'll always return OK FLAG, because we'll free this skb by ourself */ + return NETDEV_TX_OK; +} + + +// callbacks for netdevice +static const struct net_device_ops bow_netdev_ops = { + .ndo_open = bowOpen, + .ndo_stop = bowStop, + .ndo_start_xmit = bowHardStartXmit, +}; + +/*----------------------------------------------------------------------------*/ +/*! +* \brief initialize net device for Bluetooth-over-Wi-Fi +* +* \param[in] +* prGlueInfo +* prDevName +* +* \return +* TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +kalInitBowDevice( + IN P_GLUE_INFO_T prGlueInfo, + IN const char *prDevName + ) +{ + P_ADAPTER_T prAdapter; + P_GL_HIF_INFO_T prHif; + PARAM_MAC_ADDRESS rMacAddr; + + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->rBowInfo.fgIsRegistered == TRUE); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + prHif = &prGlueInfo->rHifInfo; + ASSERT(prHif); + + if(prGlueInfo->rBowInfo.fgIsNetRegistered == FALSE) { + prGlueInfo->rBowInfo.prDevHandler = alloc_netdev_mq(sizeof(P_GLUE_INFO_T), prDevName, ether_setup, CFG_MAX_TXQ_NUM); + + if (!prGlueInfo->rBowInfo.prDevHandler) { + return FALSE; + } + else { + /* 1. setup netdev */ + /* 1.1 Point to shared glue structure */ + *((P_GLUE_INFO_T *) netdev_priv(prGlueInfo->rBowInfo.prDevHandler)) = prGlueInfo; + + /* 1.2 fill hardware address */ + COPY_MAC_ADDR(rMacAddr, prAdapter->rMyMacAddr); + rMacAddr[0] |= 0x2; // change to local administrated address + memcpy(prGlueInfo->rBowInfo.prDevHandler->dev_addr, rMacAddr, ETH_ALEN); + memcpy(prGlueInfo->rBowInfo.prDevHandler->perm_addr, prGlueInfo->rBowInfo.prDevHandler->dev_addr, ETH_ALEN); + + /* 1.3 register callback functions */ + prGlueInfo->rBowInfo.prDevHandler->netdev_ops = &bow_netdev_ops; + +#if (MTK_WCN_HIF_SDIO == 0) + SET_NETDEV_DEV(prGlueInfo->rBowInfo.prDevHandler, &(prHif->func->dev)); +#endif + + register_netdev(prGlueInfo->rBowInfo.prDevHandler); + + /* 2. net device initialize */ + netif_carrier_off(prGlueInfo->rBowInfo.prDevHandler); + netif_tx_stop_all_queues(prGlueInfo->rBowInfo.prDevHandler); + + /* 3. finish */ + prGlueInfo->rBowInfo.fgIsNetRegistered = TRUE; + } + } + + return TRUE; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief uninitialize net device for Bluetooth-over-Wi-Fi +* +* \param[in] +* prGlueInfo +* +* \return +* TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +kalUninitBowDevice( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + ASSERT(prGlueInfo); + //ASSERT(prGlueInfo->rBowInfo.fgIsRegistered == TRUE); + + if(prGlueInfo->rBowInfo.fgIsNetRegistered == TRUE) { + + prGlueInfo->rBowInfo.fgIsNetRegistered = FALSE; + + if(netif_carrier_ok(prGlueInfo->rBowInfo.prDevHandler)) { + netif_carrier_off(prGlueInfo->rBowInfo.prDevHandler); + } + + netif_tx_stop_all_queues(prGlueInfo->rBowInfo.prDevHandler); + + /* netdevice unregistration & free */ + unregister_netdev(prGlueInfo->rBowInfo.prDevHandler); + free_netdev(prGlueInfo->rBowInfo.prDevHandler); + prGlueInfo->rBowInfo.prDevHandler = NULL; + + return TRUE; + + } + else { + return FALSE; + } +} + +#endif // CFG_BOW_SEPARATE_DATA_PATH +#endif // CFG_ENABLE_BT_OVER_WIFI + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_init.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_init.c new file mode 100755 index 000000000000..77642622fa66 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_init.c @@ -0,0 +1,2810 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/os/linux/gl_init.c#5 $ +*/ + +/*! \file gl_init.c + \brief Main routines of Linux driver + + This file contains the main routines of Linux driver for MediaTek Inc. 802.11 + Wireless LAN Adapters. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: gl_init.c $ + * + * 02 23 2012 yuche.tsai + * [ALPS00240485] [Wifi P2P]Run Sigma tool of A69. Always run fail on 6.1.2 and 6.1.3. sniffer check no framename,proberesp,P2P_IE,0 + * 1. Recompose probe response frame in driver, in order to sync the IEs between supplicant & driver. + * 2. Under GO mode, indicate probe request to supplicant due to WSC IE sync issue. + * Davinci Label: 20120223_ALPS_WIFI_FW_V2_1. + * + * 02 14 2012 yuche.tsai + * [ALPS00118350] [ALPS.ICS][WiFi Direct] Dirver update for wifi direct connection + * Replace Beacon/Probe Response IE by driver generating instead of from supplicant. + * + * 02 06 2012 yuche.tsai + * [ALPS00118350] [ALPS.ICS][WiFi Direct] Dirver update for wifi direct connection + * Small bug fix for CNM memory usage, scan SSID search issue, P2P network deactivate issue. + * + * 01 20 2012 cp.wu + * [ALPS00096191] [MT6620 Wi-Fi][Driver][Firmware] Porting to ALPS4.0_DEV branch + * sync to up-to-date changes including: + * 1. BOW bugfix + * 2. XLOG + * + * 01 17 2012 wh.su + * [WCXRP00001173] [MT6620 Wi-Fi][Driver] Adding the ICS Tethering WPA2-PSK supporting + * Adding the related code which support beacon can reflect the security setting open or WPA2-PSK, WPA-PSK not yet + * Adn support the indicate the assoc request ie at New STA CMD, needed kernel patch. + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Hot Spot Tethering for ICS ALPHA testing version. + * + * 01 11 2012 terry.wu + * [WCXRP00001166] [Wi-Fi] [Driver] cfg80211 integration for p2p newtork + * Notify tx_thread to do p2p init for cfg80211 rfkill workaround. + * + * 12 22 2011 george.huang + * [WCXRP00000768] [MT6620 Wi-Fi][FW] Modification for code size shrink + * using global variable instead of stack for setting wlanoidSetNetworkAddress(), due to buffer may be released before TX thread handling + * + * 11 19 2011 yuche.tsai + * NULL + * Add P2P RSSI Link Quality Query Support. (Default Off) + * + * 11 14 2011 yuche.tsai + * [WCXRP00001107] [Volunteer Patch][Driver] Large Network Type index assert in FW issue. + * Large Network Type index assert. + * Fix NULL prDev issue. + * + * 11 14 2011 cm.chang + * NULL + * Fix compiling warning + * + * 11 11 2011 yuche.tsai + * NULL + * Fix work thread cancel issue. + * + * 11 10 2011 cp.wu + * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer + * 1. eliminaite direct calls to printk in porting layer. + * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 08 11 2011 cp.wu + * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time + * expose scnQuerySparseChannel() for P2P-FSM. + * + * 08 11 2011 cp.wu + * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time + * sparse channel detection: + * 1) firmware: collect MDRDY counter to decide which is the most sparse channel + * 2) driver: collect sparse channel information with scan-done event + * + * 08 02 2011 yuche.tsai + * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, TX deauth to a disconnecting device issue. + * Support TX Deauth while tearing down a station connection. + * + * 07 07 2011 wh.su + * [WCXRP00000839] [MT6620 Wi-Fi][Driver] Add the dumpMemory8 and dumpMemory32 EXPORT_SYMBOL + * Add the dumpMemory8 symbol export for debug mode. + * + * 07 05 2011 yuche.tsai + * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue + * Export one function for enhancement. + * + * 06 13 2011 eddie.chen + * [WCXRP00000779] [MT6620 Wi-Fi][DRV] Add tx rx statistics in linux and use netif_rx_ni + * Add tx rx statistics and netif_rx_ni. + * + * 05 27 2011 cp.wu + * [WCXRP00000749] [MT6620 Wi-Fi][Driver] Add band edge tx power control to Wi-Fi NVRAM + * invoke CMD_ID_SET_EDGE_TXPWR_LIMIT when there is valid data exist in NVRAM content. + * + * 05 18 2011 cp.wu + * [WCXRP00000734] [MT6620 Wi-Fi][Driver] Pass PHY_PARAM in NVRAM to firmware domain + * pass PHY_PARAM in NVRAM from driver to firmware. + * + * 05 09 2011 jeffrey.chang + * [WCXRP00000710] [MT6620 Wi-Fi] Support pattern filter update function on IP address change + * support ARP filter through kernel notifier + * + * 05 03 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Use kalMemAlloc to allocate event buffer for kalIndicateBOWEvent. + * + * 04 27 2011 george.huang + * [WCXRP00000684] [MT6620 Wi-Fi][Driver] Support P2P setting ARP filter + * Support P2P ARP filter setting on early suspend/ late resume + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 04 15 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add BOW short range mode. + * + * 04 14 2011 cp.wu + * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for RESET_START and RESET_END events + * sync. whole-chip resetting mechanism to V2.0 branch. + * + * 04 14 2011 yuche.tsai + * [WCXRP00000646] [Volunteer Patch][MT6620][FW/Driver] Sigma Test Modification for some test case. + * Refine P2P connection flow for Sigma Test. + * + * 04 12 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 04 11 2011 yuche.tsai + * [WCXRP00000627] [Volunteer Patch][MT6620][Driver] Pending MMPUD of P2P Network may crash system issue. + * Fix multiple export symbol issue. + * + * 04 11 2011 george.huang + * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode + * export wlan functions to p2p + * + * 04 11 2011 yuche.tsai + * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. + * Alway keep the latest Bss type when RX Beacon. + * + * 04 10 2011 yuche.tsai + * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. + * Add device discoverability support. (Phase I) + * + * 04 07 2011 eddie.chen + * [WCXRP00000527] [MT6620 Wi-Fi][FW/Driver] Clean buffered packet when BSS is inactive or disconnected[WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Remove packet when BSS is inactive + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 18 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * remove early suspend functions + * + * 03 17 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage after system running for a long period + * reverse order to prevent probing racing. + * + * 03 16 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage after system running for a long period + * 1. pre-allocate physical continuous buffer while module is being loaded + * 2. use pre-allocated physical continuous buffer for TX/RX DMA transfer + * + * The windows part remained the same as before, but added similiar APIs to hide the difference. + * + * 03 15 2011 jeffrey.chang + * [WCXRP00000558] [MT6620 Wi-Fi][MT6620 Wi-Fi][Driver] refine the queue selection algorithm for WMM + * refine the queue_select function + * + * 03 10 2011 cp.wu + * [WCXRP00000532] [MT6620 Wi-Fi][Driver] Migrate NVRAM configuration procedures from MT6620 E2 to MT6620 E3 + * deprecate configuration used by MT6620 E2 + * + * 03 10 2011 terry.wu + * [WCXRP00000505] [MT6620 Wi-Fi][Driver/FW] WiFi Direct Integration + * Remove unnecessary assert and message. + * + * 03 08 2011 terry.wu + * [WCXRP00000505] [MT6620 Wi-Fi][Driver/FW] WiFi Direct Integration + * Export nicQmUpdateWmmParms. + * + * 03 03 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * support concurrent network + * + * 03 03 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * modify net device relative functions to support multiple H/W queues + * + * 02 24 2011 george.huang + * [WCXRP00000495] [MT6620 Wi-Fi][FW] Support pattern filter for unwanted ARP frames + * Support ARP filter during suspended + * + * 02 21 2011 cp.wu + * [WCXRP00000482] [MT6620 Wi-Fi][Driver] Simplify logic for checking NVRAM existence in driver domain + * simplify logic for checking NVRAM existence only once. + * + * 02 17 2011 terry.wu + * [WCXRP00000459] [MT6620 Wi-Fi][Driver] Fix deference null pointer problem in wlanRemove + * Fix deference a null pointer problem in wlanRemove. + * + * 02 16 2011 jeffrey.chang + * NULL + * fix compilig error + * + * 02 16 2011 jeffrey.chang + * NULL + * Add query ipv4 and ipv6 address during early suspend and late resume + * + * 02 15 2011 jeffrey.chang + * NULL + * to support early suspend in android + * + * 02 11 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Add one more export symbol. + * + * 02 10 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Add RX deauthentication & disassociation process under Hot-Spot mode. + * + * 02 09 2011 terry.wu + * [WCXRP00000383] [MT6620 Wi-Fi][Driver] Separate WiFi and P2P driver into two modules + * Halt p2p module init and exit until TxThread finished p2p register and unregister. + * + * 02 08 2011 george.huang + * [WCXRP00000422] [MT6620 Wi-Fi][Driver] support query power mode OID handler + * Support querying power mode OID. + * + * 02 08 2011 yuche.tsai + * [WCXRP00000421] [Volunteer Patch][MT6620][Driver] Fix incorrect SSID length Issue + * Export Deactivation Network. + * + * 02 01 2011 jeffrey.chang + * [WCXRP00000414] KAL Timer is not unregistered when driver not loaded + * Unregister the KAL timer during driver unloading + * + * 01 26 2011 cm.chang + * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument + * Allocate system RAM if fixed message or mgmt buffer is not available + * + * 01 19 2011 cp.wu + * [WCXRP00000371] [MT6620 Wi-Fi][Driver] make linux glue layer portable for Android 2.3.1 with Linux 2.6.35.7 + * add compile option to check linux version 2.6.35 for different usage of system API to improve portability + * + * 01 12 2011 cp.wu + * [WCXRP00000357] [MT6620 Wi-Fi][Driver][Bluetooth over Wi-Fi] add another net device interface for BT AMP + * implementation of separate BT_OVER_WIFI data path. + * + * 01 10 2011 cp.wu + * [WCXRP00000349] [MT6620 Wi-Fi][Driver] make kalIoctl() of linux port as a thread safe API to avoid potential issues due to multiple access + * use mutex to protect kalIoctl() for thread safe. + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease physically continous memory demands + * separate kalMemAlloc() into virtually-continous and physically-continous type to ease slab system pressure + * + * 12 15 2010 cp.wu + * [WCXRP00000265] [MT6620 Wi-Fi][Driver] Remove set_mac_address routine from legacy Wi-Fi Android driver + * remove set MAC address. MAC address is always loaded from NVRAM instead. + * + * 12 10 2010 kevin.huang + * [WCXRP00000128] [MT6620 Wi-Fi][Driver] Add proc support to Android Driver for debug and driver status check + * Add Linux Proc Support + * + * 11 01 2010 yarco.yang + * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform + * Add GPIO debug function + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 10 26 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command + * 1) update NVRAM content template to ver 1.02 + * 2) add compile option for querying NIC capability (default: off) + * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting + * 4) correct auto-rate compiler error under linux (treat warning as error) + * 5) simplify usage of NVRAM and REG_INFO_T + * 6) add version checking between driver and firmware + * + * 10 21 2010 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * . + * + * 10 19 2010 jeffrey.chang + * [WCXRP00000120] [MT6620 Wi-Fi][Driver] Refine linux kernel module to the license of MTK propietary and enable MTK HIF by default + * Refine linux kernel module to the license of MTK and enable MTK HIF + * + * 10 18 2010 jeffrey.chang + * [WCXRP00000106] [MT6620 Wi-Fi][Driver] Enable setting multicast callback in Android + * . + * + * 10 18 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android + * complete implementation of Android NVRAM access + * + * 09 27 2010 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings + * Update BCM/BoW design and settings. + * + * 09 23 2010 cp.wu + * [WCXRP00000051] [MT6620 Wi-Fi][Driver] WHQL test fail in MAC address changed item + * use firmware reported mac address right after wlanAdapterStart() as permanent address + * + * 09 21 2010 kevin.huang + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * Eliminate Linux Compile Warning + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 09 01 2010 wh.su + * NULL + * adding the wapi support for integration test. + * + * 08 18 2010 yarco.yang + * NULL + * 1. Fixed HW checksum offload function not work under Linux issue. + * 2. Add debug message. + * + * 08 16 2010 yarco.yang + * NULL + * Support Linux x86 + * + * 08 02 2010 jeffrey.chang + * NULL + * 1) modify tx service thread to avoid busy looping + * 2) add spin lock declartion for linux build + * + * 07 29 2010 jeffrey.chang + * NULL + * fix memory leak for module unloading + * + * 07 28 2010 jeffrey.chang + * NULL + * 1) remove unused spinlocks + * 2) enable encyption ioctls + * 3) fix scan ioctl which may cause supplicant to hang + * + * 07 23 2010 jeffrey.chang + * + * bug fix: allocate regInfo when disabling firmware download + * + * 07 23 2010 jeffrey.chang + * + * use glue layer api to decrease or increase counter atomically + * + * 07 22 2010 jeffrey.chang + * + * add new spinlock + * + * 07 19 2010 jeffrey.chang + * + * modify cmd/data path for new design + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 26 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * 1) Modify set mac address code + * 2) remove power managment macro + * + * 05 10 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * implement basic wi-fi direct framework + * + * 05 07 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * prevent supplicant accessing driver during resume + * + * 05 07 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add basic framework for implementating P2P driver hook. + * + * 04 27 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * 1) fix firmware download bug + * 2) remove query statistics for acelerating firmware download + * + * 04 27 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * follow Linux's firmware framework, and remove unused kal API + * + * 04 21 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * add for private ioctl support + * + * 04 19 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Query statistics from firmware + * + * 04 19 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * modify tcp/ip checksum offload flags + * + * 04 16 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * fix tcp/ip checksum offload bug + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * * * * * * * * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose + * + * 04 09 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * fix spinlock usage + * + * 04 07 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Set MAC address from firmware + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * rWlanInfo should be placed at adapter rather than glue due to most operations + * * * * * * are done in adapter layer. + * + * 04 07 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * (1)improve none-glue code portability + * * (2) disable set Multicast address during atomic context + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * adding debug module + * + * 03 31 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * modify the wapi related code for new driver's design. + * + * 03 30 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * emulate NDIS Pending OID facility + * + * 03 26 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * fix f/w download start and load address by using config.h + * + * 03 26 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * [WPD00003826] Initial import for Linux port + * adding firmware download support + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port +** \main\maintrunk.MT5921\52 2009-10-27 22:49:59 GMT mtk01090 +** Fix compile error for Linux EHPI driver +** \main\maintrunk.MT5921\51 2009-10-20 17:38:22 GMT mtk01090 +** Refine driver unloading and clean up procedure. Block requests, stop main thread and clean up queued requests, and then stop hw. +** \main\maintrunk.MT5921\50 2009-10-08 10:33:11 GMT mtk01090 +** Avoid accessing private data of net_device directly. Replace with netdev_priv(). Add more checking for input parameters and pointers. +** \main\maintrunk.MT5921\49 2009-09-28 20:19:05 GMT mtk01090 +** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. +** \main\maintrunk.MT5921\48 2009-09-03 13:58:46 GMT mtk01088 +** remove non-used code +** \main\maintrunk.MT5921\47 2009-09-03 11:40:25 GMT mtk01088 +** adding the module parameter for wapi +** \main\maintrunk.MT5921\46 2009-08-18 22:56:41 GMT mtk01090 +** Add Linux SDIO (with mmc core) support. +** Add Linux 2.6.21, 2.6.25, 2.6.26. +** Fix compile warning in Linux. +** \main\maintrunk.MT5921\45 2009-07-06 20:53:00 GMT mtk01088 +** adding the code to check the wapi 1x frame +** \main\maintrunk.MT5921\44 2009-06-23 23:18:55 GMT mtk01090 +** Add build option BUILD_USE_EEPROM and compile option CFG_SUPPORT_EXT_CONFIG for NVRAM support +** \main\maintrunk.MT5921\43 2009-02-16 23:46:51 GMT mtk01461 +** Revise the order of increasing u4TxPendingFrameNum because of CFG_TX_RET_TX_CTRL_EARLY +** \main\maintrunk.MT5921\42 2009-01-22 13:11:59 GMT mtk01088 +** set the tid and 1x value at same packet reserved field +** \main\maintrunk.MT5921\41 2008-10-20 22:43:53 GMT mtk01104 +** Fix wrong variable name "prDev" in wlanStop() +** \main\maintrunk.MT5921\40 2008-10-16 15:37:10 GMT mtk01461 +** add handle WLAN_STATUS_SUCCESS in wlanHardStartXmit() for CFG_TX_RET_TX_CTRL_EARLY +** \main\maintrunk.MT5921\39 2008-09-25 15:56:21 GMT mtk01461 +** Update driver for Code review +** \main\maintrunk.MT5921\38 2008-09-05 17:25:07 GMT mtk01461 +** Update Driver for Code Review +** \main\maintrunk.MT5921\37 2008-09-02 10:57:06 GMT mtk01461 +** Update driver for code review +** \main\maintrunk.MT5921\36 2008-08-05 01:53:28 GMT mtk01461 +** Add support for linux statistics +** \main\maintrunk.MT5921\35 2008-08-04 16:52:58 GMT mtk01461 +** Fix ASSERT if removing module in BG_SSID_SCAN state +** \main\maintrunk.MT5921\34 2008-06-13 22:52:24 GMT mtk01461 +** Revise status code handling in wlanHardStartXmit() for WLAN_STATUS_SUCCESS +** \main\maintrunk.MT5921\33 2008-05-30 18:56:53 GMT mtk01461 +** Not use wlanoidSetCurrentAddrForLinux() +** \main\maintrunk.MT5921\32 2008-05-30 14:39:40 GMT mtk01461 +** Remove WMM Assoc Flag +** \main\maintrunk.MT5921\31 2008-05-23 10:26:40 GMT mtk01084 +** modify wlanISR interface +** \main\maintrunk.MT5921\30 2008-05-03 18:52:36 GMT mtk01461 +** Fix Unset Broadcast filter when setMulticast +** \main\maintrunk.MT5921\29 2008-05-03 15:17:26 GMT mtk01461 +** Move Query Media Status to GLUE +** \main\maintrunk.MT5921\28 2008-04-24 22:48:21 GMT mtk01461 +** Revise set multicast function by using windows oid style for LP own back +** \main\maintrunk.MT5921\27 2008-04-24 12:00:08 GMT mtk01461 +** Fix multicast setting in Linux and add comment +** \main\maintrunk.MT5921\26 2008-03-28 10:40:22 GMT mtk01461 +** Fix set mac address func in Linux +** \main\maintrunk.MT5921\25 2008-03-26 15:37:26 GMT mtk01461 +** Add set MAC Address +** \main\maintrunk.MT5921\24 2008-03-26 14:24:53 GMT mtk01461 +** For Linux, set net_device has feature with checksum offload by default +** \main\maintrunk.MT5921\23 2008-03-11 14:50:52 GMT mtk01461 +** Fix typo +** \main\maintrunk.MT5921\22 2008-02-29 15:35:20 GMT mtk01088 +** add 1x decide code for sw port control +** \main\maintrunk.MT5921\21 2008-02-21 15:01:54 GMT mtk01461 +** Rearrange the set off place of GLUE spin lock in HardStartXmit +** \main\maintrunk.MT5921\20 2008-02-12 23:26:50 GMT mtk01461 +** Add debug option - Packet Order for Linux and add debug level - Event +** \main\maintrunk.MT5921\19 2007-12-11 00:11:12 GMT mtk01461 +** Fix SPIN_LOCK protection +** \main\maintrunk.MT5921\18 2007-11-30 17:02:25 GMT mtk01425 +** 1. Set Rx multicast packets mode before setting the address list +** \main\maintrunk.MT5921\17 2007-11-26 19:44:24 GMT mtk01461 +** Add OS_TIMESTAMP to packet +** \main\maintrunk.MT5921\16 2007-11-21 15:47:20 GMT mtk01088 +** fixed the unload module issue +** \main\maintrunk.MT5921\15 2007-11-07 18:37:38 GMT mtk01461 +** Fix compile warnning +** \main\maintrunk.MT5921\14 2007-11-02 01:03:19 GMT mtk01461 +** Unify TX Path for Normal and IBSS Power Save + IBSS neighbor learning +** \main\maintrunk.MT5921\13 2007-10-30 10:42:33 GMT mtk01425 +** 1. Refine for multicast list +** \main\maintrunk.MT5921\12 2007-10-25 18:08:13 GMT mtk01461 +** Add VOIP SCAN Support & Refine Roaming +** Revision 1.4 2007/07/05 07:25:33 MTK01461 +** Add Linux initial code, modify doc, add 11BB, RF init code +** +** Revision 1.3 2007/06/27 02:18:50 MTK01461 +** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API +** +** Revision 1.2 2007/06/25 06:16:24 MTK01461 +** Update illustrations, gl_init.c, gl_kal.c, gl_kal.h, gl_os.h and RX API +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "gl_os.h" +#include "debug.h" +#include "wlan_lib.h" +#include "gl_wext.h" +#include "precomp.h" + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +//#define MAX_IOREQ_NUM 10 + +BOOLEAN fgIsUnderEarlierSuspend = false; + +struct semaphore g_halt_sem; +int g_u4HaltFlag = 0; + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* Tasklet mechanism is like buttom-half in Linux. We just want to + * send a signal to OS for interrupt defer processing. All resources + * are NOT allowed reentry, so txPacket, ISR-DPC and ioctl must avoid preempty. + */ +typedef struct _WLANDEV_INFO_T { + struct net_device *prDev; +} WLANDEV_INFO_T, *P_WLANDEV_INFO_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +MODULE_AUTHOR(NIC_AUTHOR); +MODULE_DESCRIPTION(NIC_DESC); +MODULE_SUPPORTED_DEVICE(NIC_NAME); + +#if MTK_WCN_HIF_SDIO + MODULE_LICENSE("MTK Propietary"); +#else + MODULE_LICENSE("GPL"); +#endif + +//#ifdef MODULE_LICENSE +// MODULE_LICENSE("GPL"); +//#endif /* MODULE_LICENSE */ + +#define NIC_INF_NAME "wlan%d" /* interface name */ + +#if DBG + UINT_8 aucDebugModule[DBG_MODULE_NUM]; + UINT_32 u4DebugModule = 0; +#endif /* DBG */ + +//4 2007/06/26, mikewu, now we don't use this, we just fix the number of wlan device to 1 +static WLANDEV_INFO_T arWlanDevInfo[CFG_MAX_WLAN_DEVICES] = {{0}}; +static UINT_32 u4WlanDevNum = 0; /* How many NICs coexist now */ + +//static UINT_32 u4PacketFilter = 0; +//static UINT_8 aucMCAddrList[MAX_NUM_GROUP_ADDR][ETH_ALEN]; + + +#if 0 //CFG_SUPPORT_WAPI + #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) + static int UseWapi = 1; + MODULE_PARM (UseWapi, "i"); + #else + static int UseWapi = 0; + module_param(UseWapi, int, S_IRUGO | S_IWUSR); + MODULE_PARM_DESC(UseWapi, "Use Wapi mode"); + #endif +#endif + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +#if CFG_ENABLE_WIFI_DIRECT +static SUB_MODULE_HANDLER rSubModHandler[SUB_MODULE_NUM] = {{NULL}}; +#endif + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +extern int glRegisterEarlySuspend( + struct early_suspend *prDesc, + early_suspend_callback wlanSuspend, + late_resume_callback wlanResume); + +extern int glUnregisterEarlySuspend(struct early_suspend *prDesc); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) +/*----------------------------------------------------------------------------*/ +/*! +* \brief Override the implementation of select queue +* +* \param[in] dev Pointer to struct net_device +* \param[in] skb Pointer to struct skb_buff +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +unsigned int _cfg80211_classify8021d(struct sk_buff *skb) +{ + unsigned int dscp = 0; + + /* skb->priority values from 256->263 are magic values + * directly indicate a specific 802.1d priority. This is + * to allow 802.1d priority to be passed directly in from + * tags + */ + + if (skb->priority >= 256 && skb->priority <= 263) { + return skb->priority - 256; + } + switch (skb->protocol) { + case htons(ETH_P_IP): + dscp = ip_hdr(skb)->tos & 0xfc; + break; + } + return dscp >> 5; +} + + +static const UINT_16 au16Wlan1dToQueueIdx[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; + +static UINT_16 +wlanSelectQueue( + struct net_device *dev, + struct sk_buff *skb) +{ + skb->priority = _cfg80211_classify8021d(skb); + + return au16Wlan1dToQueueIdx[skb->priority]; +} +#endif + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Load NVRAM data and translate it into REG_INFO_T +* +* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T +* \param[out] prRegInfo Pointer to struct REG_INFO_T +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static void +glLoadNvram ( + IN P_GLUE_INFO_T prGlueInfo, + OUT P_REG_INFO_T prRegInfo + ) +{ + UINT_32 i, j; + UINT_8 aucTmp[2]; + PUINT_8 pucDest; + + ASSERT(prGlueInfo); + ASSERT(prRegInfo); + + if((!prGlueInfo) || (!prRegInfo)) { + return; + } + + if(kalCfgDataRead16(prGlueInfo, + sizeof(WIFI_CFG_PARAM_STRUCT) - sizeof(UINT_16), + (PUINT_16)aucTmp) == TRUE) { + prGlueInfo->fgNvramAvailable = TRUE; + + // load MAC Address + for (i = 0 ; i < PARAM_MAC_ADDR_LEN; i += sizeof(UINT_16)) { + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucMacAddress) + i, + (PUINT_16) (((PUINT_8)prRegInfo->aucMacAddr) + i)); + } + + // load country code + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucCountryCode[0]), + (PUINT_16)aucTmp); + + // cast to wide characters + prRegInfo->au2CountryCode[0] = (UINT_16) aucTmp[0]; + prRegInfo->au2CountryCode[1] = (UINT_16) aucTmp[1]; + + // load default normal TX power + for (i = 0 ; i < sizeof(TX_PWR_PARAM_T) ; i += sizeof(UINT_16)) { + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, rTxPwr) + i, + (PUINT_16) (((PUINT_8)&(prRegInfo->rTxPwr)) + i)); + } + + // load feature flags + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, ucTxPwrValid), + (PUINT_16)aucTmp); + prRegInfo->ucTxPwrValid = aucTmp[0]; + prRegInfo->ucSupport5GBand = aucTmp[1]; + + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, uc2G4BwFixed20M), + (PUINT_16)aucTmp); + prRegInfo->uc2G4BwFixed20M = aucTmp[0]; + prRegInfo->uc5GBwFixed20M = aucTmp[1]; + + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, ucEnable5GBand), + (PUINT_16)aucTmp); + prRegInfo->ucEnable5GBand = aucTmp[0]; + + /* load EFUSE overriding part */ + for (i = 0 ; i < sizeof(prRegInfo->aucEFUSE) ; i += sizeof(UINT_16)) { + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucEFUSE) + i, + (PUINT_16) (((PUINT_8)&(prRegInfo->aucEFUSE)) + i)); + } + + /* load band edge tx power control */ + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, fg2G4BandEdgePwrUsed), + (PUINT_16)aucTmp); + prRegInfo->fg2G4BandEdgePwrUsed = (BOOLEAN)aucTmp[0]; + if (aucTmp[0]) { + prRegInfo->cBandEdgeMaxPwrCCK = (INT_8)aucTmp[1]; + + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, cBandEdgeMaxPwrOFDM20), + (PUINT_16)aucTmp); + prRegInfo->cBandEdgeMaxPwrOFDM20 = (INT_8)aucTmp[0]; + prRegInfo->cBandEdgeMaxPwrOFDM40 = (INT_8)aucTmp[1]; + } + + /* load regulation subbands */ + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, ucRegChannelListMap), + (PUINT_16)aucTmp); + prRegInfo->eRegChannelListMap = (ENUM_REG_CH_MAP_T) aucTmp[0]; + prRegInfo->ucRegChannelListIndex = aucTmp[1]; + + if (prRegInfo->eRegChannelListMap == REG_CH_MAP_CUSTOMIZED) { + for (i = 0 ; i < MAX_SUBBAND_NUM; i++) { + pucDest = (PUINT_8) &prRegInfo->rDomainInfo.rSubBand[i]; + for (j = 0; j < 6; j += sizeof(UINT_16)) { + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucRegSubbandInfo) + + (i * 6 + j), + (PUINT_16)aucTmp); + + *pucDest++ = aucTmp[0]; + *pucDest++ = aucTmp[1]; + } + } + } + } + else { + prGlueInfo->fgNvramAvailable = FALSE; + } + + return; +} + + +#if CFG_ENABLE_WIFI_DIRECT +/*----------------------------------------------------------------------------*/ +/*! +* \brief called by txthread, run sub module init function +* +* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanSubModRunInit( + P_GLUE_INFO_T prGlueInfo + ) +{ + /*now, we only have p2p module*/ + if(rSubModHandler[P2P_MODULE].fgIsInited == FALSE) { + rSubModHandler[P2P_MODULE].subModInit(prGlueInfo); + rSubModHandler[P2P_MODULE].fgIsInited = TRUE; + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief called by txthread, run sub module exit function +* +* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanSubModRunExit( + P_GLUE_INFO_T prGlueInfo + ) +{ + /*now, we only have p2p module*/ + if(rSubModHandler[P2P_MODULE].fgIsInited == TRUE) { + rSubModHandler[P2P_MODULE].subModExit(prGlueInfo); + rSubModHandler[P2P_MODULE].fgIsInited = FALSE; + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief set sub module init flag, force TxThread to run sub modle init +* +* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +wlanSubModInit( + P_GLUE_INFO_T prGlueInfo + ) +{ + //4 Mark HALT, notify main thread to finish current job + prGlueInfo->u4Flag |= GLUE_FLAG_SUB_MOD_INIT; + /* wake up main thread */ + wake_up_interruptible(&prGlueInfo->waitq); + /* wait main thread finish sub module INIT*/ + wait_for_completion_interruptible(&prGlueInfo->rSubModComp); + + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief set sub module exit flag, force TxThread to run sub modle exit +* +* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +wlanSubModExit( + P_GLUE_INFO_T prGlueInfo + ) +{ + //4 Mark HALT, notify main thread to finish current job + prGlueInfo->u4Flag |= GLUE_FLAG_SUB_MOD_EXIT; + /* wake up main thread */ + wake_up_interruptible(&prGlueInfo->waitq); + /* wait main thread finish sub module EXIT */ + wait_for_completion_interruptible(&prGlueInfo->rSubModComp); + + return TRUE; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief set by sub module, indicate sub module is already inserted +* +* \param[in] rSubModInit, function pointer point to sub module init function +* \param[in] rSubModExit, function pointer point to sub module exit function +* \param[in] eSubModIdx, sub module index +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanSubModRegisterInitExit( + SUB_MODULE_INIT rSubModInit, + SUB_MODULE_EXIT rSubModExit, + ENUM_SUB_MODULE_IDX_T eSubModIdx + ) +{ + rSubModHandler[eSubModIdx].subModInit = rSubModInit; + rSubModHandler[eSubModIdx].subModExit = rSubModExit; + rSubModHandler[eSubModIdx].fgIsInited = FALSE; +} + +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* \brief check wlan is launched or not +* +* \param[in] (none) +* +* \return TRUE, wlan is already started +* FALSE, wlan is not started yet +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +wlanIsLaunched( + VOID + ) +{ + struct net_device *prDev = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + + //4 <0> Sanity check + ASSERT(u4WlanDevNum <= CFG_MAX_WLAN_DEVICES); + if (0 == u4WlanDevNum) { + return FALSE; + } + + prDev = arWlanDevInfo[u4WlanDevNum-1].prDev; + + ASSERT(prDev); + if (NULL == prDev) { + return FALSE; + } + + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prDev); + ASSERT(prGlueInfo); + if (NULL == prGlueInfo) { + return FALSE; + } + + return prGlueInfo->prAdapter->fgIsWlanLaunched; +} + +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Export wlan GLUE_INFO_T pointer to p2p module +* +* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T +* +* \return TRUE: get GlueInfo pointer successfully +* FALSE: wlan is not started yet +*/ +/*---------------------------------------------------------------------------*/ +BOOLEAN +wlanExportGlueInfo( + P_GLUE_INFO_T *prGlueInfoExpAddr + ) +{ + struct net_device *prDev = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + + if (0 == u4WlanDevNum) { + return FALSE; + } + + prDev = arWlanDevInfo[u4WlanDevNum-1].prDev; + if (NULL == prDev) { + return FALSE; + } + + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prDev); + if (NULL == prGlueInfo) { + return FALSE; + } + + if(FALSE == prGlueInfo->prAdapter->fgIsWlanLaunched) { + return FALSE; + } + + *prGlueInfoExpAddr = prGlueInfo; + return TRUE; +} + +#endif + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Release prDev from wlandev_array and free tasklet object related to it. +* +* \param[in] prDev Pointer to struct net_device +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static void +wlanClearDevIdx ( + struct net_device *prDev + ) +{ + int i; + + ASSERT(prDev); + + for (i = 0; i < CFG_MAX_WLAN_DEVICES; i++) { + if (arWlanDevInfo[i].prDev == prDev) { + arWlanDevInfo[i].prDev = NULL; + u4WlanDevNum--; + } + } + + return; +} /* end of wlanClearDevIdx() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Allocate an unique interface index, net_device::ifindex member for this +* wlan device. Store the net_device in wlandev_array, and initialize +* tasklet object related to it. +* +* \param[in] prDev Pointer to struct net_device +* +* \retval >= 0 The device number. +* \retval -1 Fail to get index. +*/ +/*----------------------------------------------------------------------------*/ +static int +wlanGetDevIdx ( + struct net_device *prDev + ) +{ + int i; + + ASSERT(prDev); + + for (i = 0; i < CFG_MAX_WLAN_DEVICES; i++) { + if (arWlanDevInfo[i].prDev == (struct net_device *) NULL) { + /* Reserve 2 bytes space to store one digit of + * device number and NULL terminator. + */ + arWlanDevInfo[i].prDev = prDev; + u4WlanDevNum++; + return i; + } + } + + return -1; +} /* end of wlanGetDevIdx() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief A method of struct net_device, a primary SOCKET interface to configure +* the interface lively. Handle an ioctl call on one of our devices. +* Everything Linux ioctl specific is done here. Then we pass the contents +* of the ifr->data to the request message handler. +* +* \param[in] prDev Linux kernel netdevice +* +* \param[in] prIFReq Our private ioctl request structure, typed for the generic +* struct ifreq so we can use ptr to function +* +* \param[in] cmd Command ID +* +* \retval WLAN_STATUS_SUCCESS The IOCTL command is executed successfully. +* \retval OTHER The execution of IOCTL command is failed. +*/ +/*----------------------------------------------------------------------------*/ +int +wlanDoIOCTL( + struct net_device *prDev, + struct ifreq *prIFReq, + int i4Cmd + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + int ret = 0; + + /* Verify input parameters for the following functions */ + ASSERT(prDev && prIFReq); + if (!prDev || !prIFReq) { + DBGLOG(INIT, WARN, ("%s Invalid input data\n", __FUNCTION__)); + return -EINVAL; + } + + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prDev); + ASSERT(prGlueInfo); + if (!prGlueInfo) { + DBGLOG(INIT, WARN, ("%s No glue info\n", __FUNCTION__)); + return -EFAULT; + } + + if (prGlueInfo->u4ReadyFlag == 0) { + return -EINVAL; + } + + //printk ("ioctl %x\n", i4Cmd); + + if (i4Cmd == SIOCGIWPRIV) { + /* 0x8B0D, get private ioctl table */ + ret = wext_get_priv(prDev, prIFReq); + } + else if ((i4Cmd >= SIOCIWFIRST) && (i4Cmd < SIOCIWFIRSTPRIV)) { + /* 0x8B00 ~ 0x8BDF, wireless extension region */ + ret = wext_support_ioctl(prDev, prIFReq, i4Cmd); + } + else if ((i4Cmd >= SIOCIWFIRSTPRIV) && (i4Cmd < SIOCIWLASTPRIV)) { + /* 0x8BE0 ~ 0x8BFF, private ioctl region */ + ret = priv_support_ioctl(prDev, prIFReq, i4Cmd); + } + else { + DBGLOG(INIT, WARN, ("Unexpected ioctl command: 0x%04x\n", i4Cmd)); + /* return 0 for safe? */ + } + + return ret; +} /* end of wlanDoIOCTL() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is to set multicast list and set rx mode. +* +* \param[in] prDev Pointer to struct net_device +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ + +static struct work_struct workq; +static struct net_device *gPrDev; + +static void +wlanSetMulticastList (struct net_device *prDev) +{ + gPrDev = prDev; + schedule_work(&workq); +} + +/* FIXME: Since we cannot sleep in the wlanSetMulticastList, we arrange + * another workqueue for sleeping. We don't want to block + * tx_thread, so we can't let tx_thread to do this */ + +static void +wlanSetMulticastListWorkQueue (struct work_struct *work) { + + P_GLUE_INFO_T prGlueInfo = NULL; + UINT_32 u4PacketFilter = 0; + UINT_32 u4SetInfoLen; + struct net_device *prDev = gPrDev; + + down(&g_halt_sem); + if (g_u4HaltFlag) { + up(&g_halt_sem); + return; + } + + prGlueInfo = (NULL != prDev) ? (P_GLUE_INFO_T) netdev_priv(prDev) : NULL; + ASSERT(prDev); + ASSERT(prGlueInfo); + if (!prDev || !prGlueInfo) { + DBGLOG(INIT, WARN, ("abnormal dev or skb: prDev(0x%p), prGlueInfo(0x%p)\n", + prDev, prGlueInfo)); + up(&g_halt_sem); + return; + } + + if (prDev->flags & IFF_PROMISC) { + u4PacketFilter |= PARAM_PACKET_FILTER_PROMISCUOUS; + } + + if (prDev->flags & IFF_BROADCAST) { + u4PacketFilter |= PARAM_PACKET_FILTER_BROADCAST; + } + + if (prDev->flags & IFF_MULTICAST) { + if ((prDev->flags & IFF_ALLMULTI) || +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) + (netdev_mc_count(prDev) > MAX_NUM_GROUP_ADDR)) { +#else + (prDev->mc_count > MAX_NUM_GROUP_ADDR)) { +#endif + + u4PacketFilter |= PARAM_PACKET_FILTER_ALL_MULTICAST; + } + else { + u4PacketFilter |= PARAM_PACKET_FILTER_MULTICAST; + } + } + + up(&g_halt_sem); + + if (kalIoctl(prGlueInfo, + wlanoidSetCurrentPacketFilter, + &u4PacketFilter, + sizeof(u4PacketFilter), + FALSE, + FALSE, + TRUE, + FALSE, + &u4SetInfoLen) != WLAN_STATUS_SUCCESS) { + return; + } + + + if (u4PacketFilter & PARAM_PACKET_FILTER_MULTICAST) { + /* Prepare multicast address list */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) + struct netdev_hw_addr *ha; +#else + struct dev_mc_list *prMcList; +#endif + PUINT_8 prMCAddrList = NULL; + UINT_32 i = 0; + + down(&g_halt_sem); + if (g_u4HaltFlag) { + up(&g_halt_sem); + return; + } + + prMCAddrList = kalMemAlloc(MAX_NUM_GROUP_ADDR * ETH_ALEN, VIR_MEM_TYPE); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) + netdev_for_each_mc_addr(ha, prDev) { + if(i < MAX_NUM_GROUP_ADDR) { + memcpy((prMCAddrList + i * ETH_ALEN), ha->addr, ETH_ALEN); + i++; + } + } +#else + for (i = 0, prMcList = prDev->mc_list; + (prMcList) && (i < prDev->mc_count) && (i < MAX_NUM_GROUP_ADDR); + i++, prMcList = prMcList->next) { + memcpy((prMCAddrList + i * ETH_ALEN), prMcList->dmi_addr, ETH_ALEN); + } +#endif + + up(&g_halt_sem); + + kalIoctl(prGlueInfo, + wlanoidSetMulticastList, + prMCAddrList, + (i * ETH_ALEN), + FALSE, + FALSE, + TRUE, + FALSE, + &u4SetInfoLen); + + kalMemFree(prMCAddrList, VIR_MEM_TYPE, MAX_NUM_GROUP_ADDR * ETH_ALEN); + } + + return; +} /* end of wlanSetMulticastList() */ + + +/* FIXME: Since we cannot sleep in the wlanSetMulticastList, we arrange + * another workqueue for sleeping. We don't want to block + * tx_thread, so we can't let tx_thread to do this */ + +void +p2pSetMulticastListWorkQueueWrapper (P_GLUE_INFO_T prGlueInfo) { + + ASSERT(prGlueInfo); + + if (!prGlueInfo) { + DBGLOG(INIT, WARN, ("abnormal dev or skb: prGlueInfo(0x%p)\n", + prGlueInfo)); + return; + } + +#if CFG_ENABLE_WIFI_DIRECT + if(prGlueInfo->prAdapter->fgIsP2PRegistered) { + P_P2P_FUNCTION_LINKER prFuncLkr = &(prGlueInfo->prAdapter->rP2pFuncLkr); + prFuncLkr->prP2pSetMulticastListWorkQueue(prGlueInfo); + } +#endif + + return; +} /* end of p2pSetMulticastListWorkQueueWrapper() */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is TX entry point of NET DEVICE. +* +* \param[in] prSkb Pointer of the sk_buff to be sent +* \param[in] prDev Pointer to struct net_device +* +* \retval NETDEV_TX_OK - on success. +* \retval NETDEV_TX_BUSY - on failure, packet will be discarded by upper layer. +*/ +/*----------------------------------------------------------------------------*/ +int +wlanHardStartXmit( + struct sk_buff *prSkb, + struct net_device *prDev + ) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prDev); + + P_QUE_ENTRY_T prQueueEntry = NULL; + P_QUE_T prTxQueue = NULL; + UINT_16 u2QueueIdx = 0; + +#if CFG_BOW_TEST + UINT_32 i; +#endif + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prSkb); + ASSERT(prDev); + ASSERT(prGlueInfo); + + if (prGlueInfo->u4Flag & GLUE_FLAG_HALT) { + DBGLOG(INIT, INFO, ("GLUE_FLAG_HALT skip tx\n")); + dev_kfree_skb(prSkb); + return NETDEV_TX_OK; + } + + prQueueEntry = (P_QUE_ENTRY_T) GLUE_GET_PKT_QUEUE_ENTRY(prSkb); + prTxQueue = &prGlueInfo->rTxQueue; + +#if CFG_BOW_TEST + DBGLOG(BOW, TRACE, ("sk_buff->len: %d\n", prSkb->len)); + DBGLOG(BOW, TRACE, ("sk_buff->data_len: %d\n", prSkb->data_len)); + DBGLOG(BOW, TRACE, ("sk_buff->data:\n")); + + for(i = 0; i < prSkb->len; i++) + { + DBGLOG(BOW, TRACE, ("%4x", prSkb->data[i])); + + if((i+1)%16 ==0) + { + DBGLOG(BOW, TRACE, ("\n")); + } + } + + DBGLOG(BOW, TRACE, ("\n")); +#endif + + if (wlanProcessSecurityFrame(prGlueInfo->prAdapter, (P_NATIVE_PACKET) prSkb) == FALSE) { + + #if CFG_DBG_GPIO_PINS + { + /* TX request from OS */ + mtk_wcn_stp_debug_gpio_assert(IDX_TX_REQ, DBG_TIE_LOW); + kalUdelay(1); + mtk_wcn_stp_debug_gpio_assert(IDX_TX_REQ, DBG_TIE_HIGH); + } + #endif + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 26) + u2QueueIdx = skb_get_queue_mapping(prSkb); + ASSERT(u2QueueIdx < CFG_MAX_TXQ_NUM); +#endif + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + QUEUE_INSERT_TAIL(prTxQueue, prQueueEntry); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + + GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingFrameNum); + GLUE_INC_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_AIS_INDEX][u2QueueIdx]); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 26) + if (prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_AIS_INDEX][u2QueueIdx] >= CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD) { + netif_stop_subqueue(prDev, u2QueueIdx); + } +#else + if (prGlueInfo->i4TxPendingFrameNum >= CFG_TX_STOP_NETIF_QUEUE_THRESHOLD) { + netif_stop_queue(prDev); + } +#endif + } else { + //printk("is security frame\n"); + + GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingSecurityFrameNum); + } + + DBGLOG(TX, EVENT, ("\n+++++ pending frame %d len = %d +++++\n", prGlueInfo->i4TxPendingFrameNum, prSkb->len)); + prGlueInfo->rNetDevStats.tx_bytes += prSkb->len; + prGlueInfo->rNetDevStats.tx_packets++; + + //pr->u4Flag |= GLUE_FLAG_TXREQ; + //wake_up_interruptible(&prGlueInfo->waitq); + kalSetEvent(prGlueInfo); + + + /* For Linux, we'll always return OK FLAG, because we'll free this skb by ourself */ + return NETDEV_TX_OK; +} /* end of wlanHardStartXmit() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief A method of struct net_device, to get the network interface statistical +* information. +* +* Whenever an application needs to get statistics for the interface, this method +* is called. This happens, for example, when ifconfig or netstat -i is run. +* +* \param[in] prDev Pointer to struct net_device. +* +* \return net_device_stats buffer pointer. +*/ +/*----------------------------------------------------------------------------*/ +struct net_device_stats * +wlanGetStats ( + IN struct net_device *prDev + ) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prDev); + + #if 0 + WLAN_STATUS rStatus; + UINT_32 u4XmitError = 0; + UINT_32 u4XmitOk = 0; + UINT_32 u4RecvError = 0; + UINT_32 u4RecvOk = 0; + UINT_32 u4BufLen; + + ASSERT(prDev); + + /* @FIX ME: need a more clear way to do this */ + + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryXmitError, + &u4XmitError, + sizeof(UINT_32), + TRUE, + TRUE, + TRUE, + &u4BufLen); + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryXmitOk, + &u4XmitOk, + sizeof(UINT_32), + TRUE, + TRUE, + TRUE, + &u4BufLen); + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryRcvOk, + &u4RecvOk, + sizeof(UINT_32), + TRUE, + TRUE, + TRUE, + &u4BufLen); + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryRcvError, + &u4RecvError, + sizeof(UINT_32), + TRUE, + TRUE, + TRUE, + &u4BufLen); + prGlueInfo->rNetDevStats.rx_packets = u4RecvOk; + prGlueInfo->rNetDevStats.tx_packets = u4XmitOk; + prGlueInfo->rNetDevStats.tx_errors = u4XmitError; + prGlueInfo->rNetDevStats.rx_errors = u4RecvError; + //prGlueInfo->rNetDevStats.rx_bytes = rCustomNetDevStats.u4RxBytes; + //prGlueInfo->rNetDevStats.tx_bytes = rCustomNetDevStats.u4TxBytes; + //prGlueInfo->rNetDevStats.rx_errors = rCustomNetDevStats.u4RxErrors; + //prGlueInfo->rNetDevStats.multicast = rCustomNetDevStats.u4Multicast; + #endif + //prGlueInfo->rNetDevStats.rx_packets = 0; + //prGlueInfo->rNetDevStats.tx_packets = 0; + prGlueInfo->rNetDevStats.tx_errors = 0; + prGlueInfo->rNetDevStats.rx_errors = 0; + //prGlueInfo->rNetDevStats.rx_bytes = 0; + //prGlueInfo->rNetDevStats.tx_bytes = 0; + prGlueInfo->rNetDevStats.rx_errors = 0; + prGlueInfo->rNetDevStats.multicast = 0; + + return &prGlueInfo->rNetDevStats; + +} /* end of wlanGetStats() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief A function for prDev->init +* +* \param[in] prDev Pointer to struct net_device. +* +* \retval 0 The execution of wlanInit succeeds. +* \retval -ENXIO No such device. +*/ +/*----------------------------------------------------------------------------*/ +static int +wlanInit( + struct net_device *prDev + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + + + + if (!prDev) { + return -ENXIO; + } + + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prDev); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 12) + INIT_WORK(&workq, wlanSetMulticastListWorkQueue); +#else + INIT_WORK(&workq, wlanSetMulticastListWorkQueue, NULL); +#endif + + + return 0; /* success */ +} /* end of wlanInit() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief A function for prDev->uninit +* +* \param[in] prDev Pointer to struct net_device. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static void +wlanUninit( + struct net_device *prDev + ) +{ + return; +} /* end of wlanUninit() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief A function for prDev->open +* +* \param[in] prDev Pointer to struct net_device. +* +* \retval 0 The execution of wlanOpen succeeds. +* \retval < 0 The execution of wlanOpen failed. +*/ +/*----------------------------------------------------------------------------*/ +static int +wlanOpen( + struct net_device *prDev + ) +{ + ASSERT(prDev); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 26) + netif_tx_start_all_queues(prDev); +#else + netif_start_queue(prDev); +#endif + + return 0; /* success */ +} /* end of wlanOpen() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief A function for prDev->stop +* +* \param[in] prDev Pointer to struct net_device. +* +* \retval 0 The execution of wlanStop succeeds. +* \retval < 0 The execution of wlanStop failed. +*/ +/*----------------------------------------------------------------------------*/ +static int +wlanStop( + struct net_device *prDev + ) +{ + ASSERT(prDev); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 26) + netif_tx_stop_all_queues(prDev); +#else + netif_stop_queue(prDev); +#endif + + return 0; /* success */ +} /* end of wlanStop() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Register the device to the kernel and return the index. +* +* \param[in] prDev Pointer to struct net_device. +* +* \retval 0 The execution of wlanNetRegister succeeds. +* \retval < 0 The execution of wlanNetRegister failed. +*/ +/*----------------------------------------------------------------------------*/ +static INT_32 +wlanNetRegister( + struct net_device *prDev + ) +{ + INT_32 i4DevIdx = -1; + + ASSERT(prDev); + + + /* GeorgeKuo: register_netdev() helps translate wlan%d to wlan0; it + * calls rtnl_lock() and rtnl_unlock() to do protection for + * register_netdevice(). Avoid using register_netdevice() directly. + */ + //rtnl_lock(); + + do { + if (!prDev) { + break; + } + + if ((i4DevIdx = wlanGetDevIdx(prDev)) < 0) { + DBGLOG(INIT, ERROR, ("wlanNetRegister: net_device number exceeds.\n")); + break; + } + + if (register_netdev(prDev) < 0) { + DBGLOG(INIT, ERROR, ("wlanNetRegister: net_device context is not registered.\n")); + wlanClearDevIdx(prDev); + i4DevIdx = -1; + } + } + while(FALSE); + + //rtnl_unlock(); + + return i4DevIdx; /* success */ +} /* end of wlanNetRegister() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Unregister the device from the kernel +* +* \param[in] prDev Pointer to struct net_device. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static VOID +wlanNetUnregister( + struct net_device *prDev + ) +{ + /* Waiting for executing tasklet completion. + * Note: before tasklet completion, all resources should be kept. + */ + + /* GeorgeKuo: unregister_netdev() uses rtnl_lock() to protect + * unregister_netdevice(). Avoid using unregister_netdevice() directly. + */ + + //rtnl_lock(); + + if (!prDev) { + //rtnl_unlock(); + DBGLOG(INIT, ERROR, ("wlanNetUnregister: The device context is NULL\n")); + //ASSERT(prDev); + return; + } + + wlanClearDevIdx(prDev); + + DBGLOG(INIT, INFO, ("unregistering netdev (0x%p)\n", prDev)); + unregister_netdev(prDev); + DBGLOG(INIT, INFO, ("unregistration completed\n")); + + return; +} /* end of wlanNetUnregister() */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) +static const struct net_device_ops wlan_netdev_ops = { + .ndo_open = wlanOpen, + .ndo_stop = wlanStop, + .ndo_set_multicast_list = wlanSetMulticastList, + .ndo_get_stats = wlanGetStats, + .ndo_do_ioctl = wlanDoIOCTL, + .ndo_start_xmit = wlanHardStartXmit, + .ndo_init = wlanInit, + .ndo_uninit = wlanUninit, + .ndo_select_queue = wlanSelectQueue, +}; +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief A method for creating Linux NET4 struct net_device object and the +* private data(prGlueInfo and prAdapter). Setup the IO address to the HIF. +* Assign the function pointer to the net_device object +* +* \param[in] pvData Memory address for the device +* +* \retval Not null The net_device object. +* \retval NULL Fail to create net_device object +*/ +/*----------------------------------------------------------------------------*/ +static struct net_device * +wlanNetCreate( + PVOID pvData + ) +{ + struct net_device *prDev = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + UINT_32 i; + + //4 <1> Create netdev +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 26) + prDev = alloc_netdev_mq(sizeof(GLUE_INFO_T), NIC_INF_NAME, ether_setup, CFG_MAX_TXQ_NUM); +#else + prDev = alloc_netdev(sizeof(GLUE_INFO_T), NIC_INF_NAME, ether_setup); +#endif + + DBGLOG(INIT, INFO, ("net_device prDev(0x%p) allocated\n", prDev)); + + if (!prDev) { + DBGLOG(INIT, ERROR, ("Allocating memory to net_device context failed\n")); + return NULL; + } + + //4 <2> Create Glue structure + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prDev); + + if (!prGlueInfo) { + DBGLOG(INIT, ERROR, ("Allocating memory to glue layer failed\n")); + goto netcreate_err; + } + + //4 <3> Initial Glue structure + prGlueInfo->prDevHandler = prDev; + prGlueInfo->eParamMediaStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED; + prGlueInfo->ePowerState = ParamDeviceStateD0; + prGlueInfo->fgIsMacAddrOverride = FALSE; + + init_completion(&prGlueInfo->rScanComp); + init_completion(&prGlueInfo->rHaltComp); + init_completion(&prGlueInfo->rPendComp); +#if CFG_ENABLE_WIFI_DIRECT + init_completion(&prGlueInfo->rSubModComp); +#endif + + /* initialize timer for OID timeout checker */ + kalOsTimerInitialize(prGlueInfo, kalTimeoutHandler); + + for (i = 0; i < SPIN_LOCK_NUM; i++) { + spin_lock_init(&prGlueInfo->rSpinLock[i]); + } + + /* initialize semaphore for ioctl */ + sema_init(&prGlueInfo->ioctl_sem, 1); + + /* initialize semaphore for ioctl */ + sema_init(&g_halt_sem, 1); + g_u4HaltFlag = 0; + + + //4 <4> Create Adapter structure + prAdapter = (P_ADAPTER_T) wlanAdapterCreate(prGlueInfo); + + if (!prAdapter) { + DBGLOG(INIT, ERROR, ("Allocating memory to adapter failed\n")); + goto netcreate_err; + } + + prGlueInfo->prAdapter = prAdapter; + + //4 <6> Register Callback function +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) + prDev->netdev_ops = &wlan_netdev_ops; +#else + prDev->open = wlanOpen; + prDev->stop = wlanStop; + /*prDev->change_mtu = wlanChangeMTU;*/ + prDev->get_stats = wlanGetStats; + prDev->set_multicast_list = wlanSetMulticastList; + prDev->hard_start_xmit = wlanHardStartXmit; + + /* GeorgeKuo: wait to be removed? */ + prDev->do_ioctl = wlanDoIOCTL; + prDev->init = wlanInit; + prDev->uninit = wlanUninit; +#endif + + //4 <7> Use wireless extension to replace IOCTL + prDev->wireless_handlers = &wext_handler_def; + +#if CFG_TCP_IP_CHKSUM_OFFLOAD +#if 0 //CFG_SUPPORT_WAPI + if (!UseWapi) { + prDev->features = NETIF_F_IP_CSUM; + } + else { + wlanSetWapiMode(prAdapter, UseWapi); + } +#else + + //prDev->features = NETIF_F_IP_CSUM; + prDev->features = NETIF_F_HW_CSUM; +#endif +#else +#if 0//CFG_SUPPORT_WAPI + if (UseWapi) { + wlanSetWapiMode(prAdapter, UseWapi); + } +#endif +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + + netif_carrier_off(prDev); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 26) + netif_tx_stop_all_queues(prDev); +#else + netif_stop_queue(prDev); +#endif + + goto netcreate_done; + +netcreate_err: + if (NULL != prAdapter) { + wlanAdapterDestroy(prAdapter); + prAdapter = NULL; + } + + if (NULL != prDev) { + /* Free net_device and private data, which are allocated by + * alloc_netdev(). + */ + free_netdev(prDev); + prDev = NULL; + } + +netcreate_done: + + return prDev; +} /* end of wlanNetCreate() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Destroying the struct net_device object and the private data. +* +* \param[in] prDev Pointer to struct net_device. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static VOID +wlanNetDestroy( + struct net_device *prDev + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + if (!prDev) { + DBGLOG(INIT, ERROR, ("wlanNetDestroy: The device context is NULL\n")); + return; + } + + /* prGlueInfo is allocated with net_device */ + prGlueInfo = netdev_priv(prDev); + ASSERT(prGlueInfo); + + /* destroy kal OS timer */ + kalCancelTimer(prGlueInfo); + + glClearHifInfo(prGlueInfo); + + wlanAdapterDestroy(prGlueInfo->prAdapter); + prGlueInfo->prAdapter = NULL; + + /* Free net_device and private data, which are allocated by alloc_netdev(). + */ + free_netdev(prDev); + + return; +} /* end of wlanNetDestroy() */ + +#ifndef CONFIG_X86 +UINT_8 g_aucBufIpAddr[32] = {0}; + +static void wlanEarlySuspend(void) +{ + struct net_device *prDev = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + UINT_8 ip[4] = { 0 }; + UINT_32 u4NumIPv4 = 0; +#ifdef CONFIG_IPV6 + UINT_8 ip6[16] = { 0 }; // FIX ME: avoid to allocate large memory in stack + UINT_32 u4NumIPv6 = 0; +#endif + UINT_32 i; + P_PARAM_NETWORK_ADDRESS_IP prParamIpAddr; + + DBGLOG(INIT, INFO, ("*********wlanEarlySuspend************\n")); + + // <1> Sanity check and acquire the net_device + ASSERT(u4WlanDevNum <= CFG_MAX_WLAN_DEVICES); + prDev = arWlanDevInfo[u4WlanDevNum-1].prDev; + ASSERT(prDev); + + // <2> acquire the prGlueInfo + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prDev); + ASSERT(prGlueInfo); + +fgIsUnderEarlierSuspend = true; + + // <3> get the IPv4 address + if(!prDev || !(prDev->ip_ptr)||\ + !((struct in_device *)(prDev->ip_ptr))->ifa_list||\ + !(&(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local))){ + DBGLOG(INIT, INFO, ("ip is not avaliable.\n")); + return; + } + + // <4> copy the IPv4 address + kalMemCopy(ip, &(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local), sizeof(ip)); + DBGLOG(INIT, INFO, ("ip is %d.%d.%d.%d\n", + ip[0],ip[1],ip[2],ip[3])); + + // todo: traverse between list to find whole sets of IPv4 addresses + if (!((ip[0] == 0) && + (ip[1] == 0) && + (ip[2] == 0) && + (ip[3] == 0))) { + u4NumIPv4++; + } + +#ifdef CONFIG_IPV6 + // <5> get the IPv6 address + if(!prDev || !(prDev->ip6_ptr)||\ + !((struct in_device *)(prDev->ip6_ptr))->ifa_list||\ + !(&(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local))){ + DBGLOG(INIT, INFO, ("ipv6 is not avaliable.\n")); + return; + } + // <6> copy the IPv6 address + kalMemCopy(ip6, &(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local), sizeof(ip6)); + DBGLOG(INIT, INFO, ("ipv6 is %d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d\n", + ip6[0],ip6[1],ip6[2],ip6[3], + ip6[4],ip6[5],ip6[6],ip6[7], + ip6[8],ip6[9],ip6[10],ip6[11], + ip6[12],ip6[13],ip6[14],ip6[15] + )); + + // todo: traverse between list to find whole sets of IPv6 addresses + if (!((ip6[0] == 0) && + (ip6[1] == 0) && + (ip6[2] == 0) && + (ip6[3] == 0) && + (ip6[4] == 0) && + (ip6[5] == 0))) { + //u4NumIPv6++; + } + +#endif + + // <7> set up the ARP filter + { + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + UINT_32 u4SetInfoLen = 0; +// UINT_8 aucBuf[32] = {0}; + UINT_32 u4Len = OFFSET_OF(PARAM_NETWORK_ADDRESS_LIST, arAddress); + P_PARAM_NETWORK_ADDRESS_LIST prParamNetAddrList = (P_PARAM_NETWORK_ADDRESS_LIST)g_aucBufIpAddr;//aucBuf; + P_PARAM_NETWORK_ADDRESS prParamNetAddr = prParamNetAddrList->arAddress; + + kalMemZero(g_aucBufIpAddr, sizeof(g_aucBufIpAddr)); + + prParamNetAddrList->u4AddressCount = u4NumIPv4 + u4NumIPv6; + prParamNetAddrList->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; + for (i = 0; i < u4NumIPv4; i++) { + prParamNetAddr->u2AddressLength = sizeof(PARAM_NETWORK_ADDRESS_IP);//4;; + prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP;; +#if 0 + kalMemCopy(prParamNetAddr->aucAddress, ip, sizeof(ip)); + prParamNetAddr = (P_PARAM_NETWORK_ADDRESS)((UINT_32)prParamNetAddr + sizeof(ip)); + u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(ip); +#else + prParamIpAddr = (P_PARAM_NETWORK_ADDRESS_IP)prParamNetAddr->aucAddress; + kalMemCopy(&prParamIpAddr->in_addr, ip, sizeof(ip)); + prParamNetAddr = (P_PARAM_NETWORK_ADDRESS)((UINT_32)prParamNetAddr + sizeof(PARAM_NETWORK_ADDRESS)); + u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(PARAM_NETWORK_ADDRESS); +#endif + } +#ifdef CONFIG_IPV6 + for (i = 0; i < u4NumIPv6; i++) { + prParamNetAddr->u2AddressLength = 6;; + prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP;; + kalMemCopy(prParamNetAddr->aucAddress, ip6, sizeof(ip6)); + prParamNetAddr = (P_PARAM_NETWORK_ADDRESS)((UINT_32)prParamNetAddr + sizeof(ip6)); + u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(ip6); + } +#endif + ASSERT(u4Len <= sizeof(g_aucBufIpAddr/*aucBuf*/)); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetNetworkAddress, + (PVOID)prParamNetAddrList, + u4Len, + FALSE, + FALSE, + TRUE, + FALSE, + &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, ("set HW pattern filter fail 0x%lx\n", rStatus)); + } + } +} + +static void wlanLateResume(void) +{ + struct net_device *prDev = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + UINT_8 ip[4] = { 0 }; +#ifdef CONFIG_IPV6 + UINT_8 ip6[16] = { 0 }; // FIX ME: avoid to allocate large memory in stack +#endif + + DBGLOG(INIT, INFO, ("*********wlanLateResume************\n")); + + // <1> Sanity check and acquire the net_device + ASSERT(u4WlanDevNum <= CFG_MAX_WLAN_DEVICES); + prDev = arWlanDevInfo[u4WlanDevNum-1].prDev; + ASSERT(prDev); + + // <2> acquire the prGlueInfo + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prDev); + ASSERT(prGlueInfo); + +fgIsUnderEarlierSuspend = false; + + // <3> get the IPv4 address + if(!prDev || !(prDev->ip_ptr)||\ + !((struct in_device *)(prDev->ip_ptr))->ifa_list||\ + !(&(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local))){ + DBGLOG(INIT, INFO, ("ip is not avaliable.\n")); + return; + } + + // <4> copy the IPv4 address + kalMemCopy(ip, &(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local), sizeof(ip)); + DBGLOG(INIT, INFO, ("ip is %d.%d.%d.%d\n", + ip[0],ip[1],ip[2],ip[3])); + +#ifdef CONFIG_IPV6 + // <5> get the IPv6 address + if(!prDev || !(prDev->ip6_ptr)||\ + !((struct in_device *)(prDev->ip6_ptr))->ifa_list||\ + !(&(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local))){ + DBGLOG(INIT, INFO, ("ipv6 is not avaliable.\n")); + return; + } + // <6> copy the IPv6 address + kalMemCopy(ip6, &(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local), sizeof(ip6)); + DBGLOG(INIT, INFO, ("ipv6 is %d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d\n", + ip6[0],ip6[1],ip6[2],ip6[3], + ip6[4],ip6[5],ip6[6],ip6[7], + ip6[8],ip6[9],ip6[10],ip6[11], + ip6[12],ip6[13],ip6[14],ip6[15] + )); +#endif + // <7> clear the ARP filter + { + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + UINT_32 u4SetInfoLen = 0; +// UINT_8 aucBuf[32] = {0}; + UINT_32 u4Len = sizeof(PARAM_NETWORK_ADDRESS_LIST); + P_PARAM_NETWORK_ADDRESS_LIST prParamNetAddrList = (P_PARAM_NETWORK_ADDRESS_LIST)g_aucBufIpAddr;//aucBuf; + + kalMemZero(g_aucBufIpAddr, sizeof(g_aucBufIpAddr)); + + prParamNetAddrList->u4AddressCount = 0; + prParamNetAddrList->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; + + ASSERT(u4Len <= sizeof(g_aucBufIpAddr/*aucBuf*/)); + rStatus = kalIoctl(prGlueInfo, + wlanoidSetNetworkAddress, + (PVOID)prParamNetAddrList, + u4Len, + FALSE, + FALSE, + TRUE, + FALSE, + &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, ("set HW pattern filter fail 0x%lx\n", rStatus)); + } + } +} + +static struct early_suspend mt6620_early_suspend_desc = { + .level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN, +}; + +#if defined(CONFIG_HAS_EARLYSUSPEND) +static void wlan_early_suspend(struct early_suspend *h) +{ + DBGLOG(INIT, INFO, ("*********wlan_early_suspend************\n")); + wlanEarlySuspend(); +} + +static void wlan_late_resume(struct early_suspend *h) +{ + DBGLOG(INIT, INFO, ("*********wlan_late_resume************\n")); + wlanLateResume(); +} +#endif //defined(CONFIG_HAS_EARLYSUSPEND) +#endif //! CONFIG_X86 + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Wlan probe function. This function probes and initializes the device. +* +* \param[in] pvData data passed by bus driver init function +* _HIF_EHPI: NULL +* _HIF_SDIO: sdio bus driver handle +* +* \retval 0 Success +* \retval negative value Failed +*/ +/*----------------------------------------------------------------------------*/ +static INT_32 +wlanProbe( + PVOID pvData + ) +{ + struct net_device *prDev = NULL; + P_WLANDEV_INFO_T prWlandevInfo = NULL; + INT_32 i4DevIdx = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + INT_32 i4Status = 0; + BOOL bRet = FALSE; + + + do { +#if DBG + int i; + /* Initialize DEBUG CLASS of each module */ + for (i = 0; i < DBG_MODULE_NUM; i++) { + aucDebugModule[i] = DBG_CLASS_ERROR | \ + DBG_CLASS_WARN | \ + DBG_CLASS_STATE | \ + DBG_CLASS_TRACE | \ + DBG_CLASS_EVENT; + //aucDebugModule[i] = 0; + } +#if 0 + aucDebugModule[DBG_INIT_IDX] |= DBG_CLASS_TRACE | DBG_CLASS_INFO; + aucDebugModule[DBG_ARB_IDX] |= DBG_CLASS_TRACE | DBG_CLASS_INFO; + aucDebugModule[DBG_JOIN_IDX] |= DBG_CLASS_TRACE | DBG_CLASS_INFO; + //aucDebugModule[DBG_RX_IDX] |= DBG_CLASS_TRACE | DBG_CLASS_INFO; + aucDebugModule[DBG_TX_IDX] |= DBG_CLASS_TRACE | DBG_CLASS_INFO; + aucDebugModule[DBG_NIC_IDX] |= DBG_CLASS_TRACE | DBG_CLASS_INFO; + aucDebugModule[DBG_HAL_IDX] |= DBG_CLASS_TRACE | DBG_CLASS_INFO; + aucDebugModule[DBG_KEVIN_IDX] |= DBG_CLASS_TRACE | DBG_CLASS_INFO | DBG_CLASS_TEMP; + aucDebugModule[DBG_SCAN_IDX] |= DBG_CLASS_TRACE | DBG_CLASS_INFO; + aucDebugModule[DBG_REQ_IDX] |= DBG_CLASS_TRACE | DBG_CLASS_INFO; + //aucDebugModule[DBG_MGT_IDX] |= DBG_CLASS_TRACE | DBG_CLASS_INFO; + aucDebugModule[DBG_RSN_IDX] |= DBG_CLASS_TRACE; + aucDebugModule[DBG_ROAMING_IDX] |= DBG_CLASS_TRACE | DBG_CLASS_INFO; +#endif +#endif /* DBG */ + + //4 <1> Initialize the IO port of the interface + /* GeorgeKuo: pData has different meaning for _HIF_XXX: + * _HIF_EHPI: pointer to memory base variable, which will be + * initialized by glBusInit(). + * _HIF_SDIO: bus driver handle + */ + + bRet = glBusInit(pvData); + + /* Cannot get IO address from interface */ + if (FALSE == bRet) { + DBGLOG(INIT, ERROR, (KERN_ALERT "wlanProbe: glBusInit() fail\n")); + i4Status = -EIO; + break; + } + + //4 <2> Create network device, Adapter, KalInfo, prDevHandler(netdev) + if ((prDev = wlanNetCreate(pvData)) == NULL) { + DBGLOG(INIT, ERROR, ("wlanProbe: No memory for dev and its private\n")); + i4Status = -ENOMEM; + break; + } + + //4 <2.5> Set the ioaddr to HIF Info + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prDev); + gPrDev = prDev; + glSetHifInfo(prGlueInfo, (UINT_32) pvData); + + + /* main thread is created in this function */ + init_waitqueue_head(&prGlueInfo->waitq); + // + + QUEUE_INITIALIZE(&prGlueInfo->rCmdQueue); + QUEUE_INITIALIZE(&prGlueInfo->rTxQueue); + + + + //prGlueInfo->main_thread = kthread_run(tx_thread, prGlueInfo->prDevHandler, "tx_thread"); + + //4 <4> Setup IRQ + prWlandevInfo = &arWlanDevInfo[i4DevIdx]; + + //i4Status = glBusSetIrq(prDev, NULL, netdev_priv(prDev)); + + if (i4Status != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, ("wlanProbe: Set IRQ error\n")); + break; + } + + prGlueInfo->i4DevIdx = i4DevIdx; + + prAdapter = prGlueInfo->prAdapter; + + prGlueInfo->u4ReadyFlag = 0; + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + prAdapter->u4CSUMFlags = (CSUM_OFFLOAD_EN_TX_TCP | CSUM_OFFLOAD_EN_TX_UDP | CSUM_OFFLOAD_EN_TX_IP); +#endif + + + //4 <5> Start Device + // +#if CFG_ENABLE_FW_DOWNLOAD + /* before start adapter, we need to open and load firmware */ + { + UINT_32 u4FwSize = 0; + PVOID prFwBuffer = NULL; + P_REG_INFO_T prRegInfo = &prGlueInfo->rRegInfo; + + //P_REG_INFO_T prRegInfo = (P_REG_INFO_T) kmalloc(sizeof(REG_INFO_T), GFP_KERNEL); + kalMemSet(prRegInfo, 0, sizeof(REG_INFO_T)); + prRegInfo->u4StartAddress = CFG_FW_START_ADDRESS; + prRegInfo->u4LoadAddress = CFG_FW_LOAD_ADDRESS; + + // Load NVRAM content to REG_INFO_T + glLoadNvram(prGlueInfo, prRegInfo); + + //kalMemCopy(&prGlueInfo->rRegInfo, prRegInfo, sizeof(REG_INFO_T)); + + prRegInfo->u4PowerMode = CFG_INIT_POWER_SAVE_PROF; + prRegInfo->fgEnArpFilter = TRUE; + + if (kalFirmwareImageMapping(prGlueInfo, &prFwBuffer, &u4FwSize) == NULL) { + i4Status = -EIO; + goto bailout; + } else { + if (wlanAdapterStart(prAdapter, prRegInfo, prFwBuffer, u4FwSize) != WLAN_STATUS_SUCCESS) { + i4Status = -EIO; + } + } + + kalFirmwareImageUnmapping(prGlueInfo, NULL, prFwBuffer); + +bailout: + //kfree(prRegInfo); + + if (i4Status < 0) { + break; + } + } +#else + //P_REG_INFO_T prRegInfo = (P_REG_INFO_T) kmalloc(sizeof(REG_INFO_T), GFP_KERNEL); + kalMemSet(&prGlueInfo->rRegInfo, 0, sizeof(REG_INFO_T)); + P_REG_INFO_T prRegInfo = &prGlueInfo->rRegInfo; + + // Load NVRAM content to REG_INFO_T + glLoadNvram(prGlueInfo, prRegInfo); + + prRegInfo->u4PowerMode = CFG_INIT_POWER_SAVE_PROF; + + if (wlanAdapterStart(prAdapter, prRegInfo, NULL, 0) != WLAN_STATUS_SUCCESS) { + i4Status = -EIO; + break; + } +#endif + prGlueInfo->main_thread = kthread_run(tx_thread, prGlueInfo->prDevHandler, "tx_thread"); + + /* set MAC address */ + { + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + struct sockaddr MacAddr; + UINT_32 u4SetInfoLen = 0; + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryCurrentAddr, + &MacAddr.sa_data, + PARAM_MAC_ADDR_LEN, + TRUE, + TRUE, + TRUE, + FALSE, + &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, WARN, ("set MAC addr fail 0x%lx\n", rStatus)); + prGlueInfo->u4ReadyFlag = 0; + } else { + memcpy(prGlueInfo->prDevHandler->dev_addr, &MacAddr.sa_data, ETH_ALEN); + memcpy(prGlueInfo->prDevHandler->perm_addr, prGlueInfo->prDevHandler->dev_addr, ETH_ALEN); + + /* card is ready */ + prGlueInfo->u4ReadyFlag = 1; + } + } + + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + /* set HW checksum offload */ + { + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + UINT_32 u4CSUMFlags = CSUM_OFFLOAD_EN_ALL; + UINT_32 u4SetInfoLen = 0; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetCSUMOffload, + (PVOID)&u4CSUMFlags, + sizeof(UINT_32), + FALSE, + FALSE, + TRUE, + FALSE, + &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, WARN, ("set HW checksum offload fail 0x%lx\n", rStatus)); + } + } +#endif + + //4 <3> Register the card + if ((i4DevIdx = wlanNetRegister(prDev)) < 0){ + i4Status = -ENXIO; + DBGLOG(INIT, ERROR, ("wlanProbe: Cannot register the net_device context to the kernel\n")); + break; + } + + //4 <6> Initialize /proc filesystem +#ifdef WLAN_INCLUDE_PROC + if ( (i4Status = procInitProcfs(prDev, NIC_DEVICE_ID_LOW)) < 0) { + DBGLOG(INIT, ERROR, ("wlanProbe: init procfs failed\n")); + break; + } +#endif /* WLAN_INCLUDE_PROC */ + +#if CFG_ENABLE_BT_OVER_WIFI + prGlueInfo->rBowInfo.fgIsNetRegistered = FALSE; + prGlueInfo->rBowInfo.fgIsRegistered = FALSE; + glRegisterAmpc(prGlueInfo); +#endif + +#if CFG_ENABLE_WIFI_DIRECT + /*wlan is launched*/ + prGlueInfo->prAdapter->fgIsWlanLaunched = TRUE; + /*if p2p module is inserted, notify tx_thread to init p2p network*/ + if(rSubModHandler[P2P_MODULE].subModInit) { + //4 Mark SUB_MOB_INIT, notify main thread to finish current job + prGlueInfo->u4Flag |= GLUE_FLAG_SUB_MOD_INIT; + } +#endif + } + while (FALSE); + + return i4Status; +} /* end of wlanProbe() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief A method to stop driver operation and release all resources. Following +* this call, no frame should go up or down through this interface. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static VOID +wlanRemove( + VOID + ) +{ + struct net_device *prDev = NULL; + P_WLANDEV_INFO_T prWlandevInfo = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + + DBGLOG(INIT, INFO, ("Remove wlan!\n")); + + + //4 <0> Sanity check + ASSERT(u4WlanDevNum <= CFG_MAX_WLAN_DEVICES); + if (0 == u4WlanDevNum) { + DBGLOG(INIT, INFO, ("0 == u4WlanDevNum\n")); + return; + } + + prDev = arWlanDevInfo[u4WlanDevNum-1].prDev; + prWlandevInfo = &arWlanDevInfo[u4WlanDevNum-1]; + + ASSERT(prDev); + if (NULL == prDev) { + DBGLOG(INIT, INFO, ("NULL == prDev\n")); + return; + } + + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prDev); + ASSERT(prGlueInfo); + if (NULL == prGlueInfo) { + DBGLOG(INIT, INFO, ("NULL == prGlueInfo\n")); + free_netdev(prDev); + return; + } + + +#if CFG_ENABLE_WIFI_DIRECT + prGlueInfo->prAdapter->fgIsWlanLaunched = FALSE; + if(prGlueInfo->prAdapter->fgIsP2PRegistered) { + wlanSubModExit(prGlueInfo); + } + +#endif + +#if CFG_ENABLE_BT_OVER_WIFI + if(prGlueInfo->rBowInfo.fgIsNetRegistered) { + bowNotifyAllLinkDisconnected(prGlueInfo->prAdapter); + /*wait 300ms for BoW module to send deauth*/ + kalMsleep(300); + } +#endif + + //4 <1> Stopping handling interrupt and free IRQ + glBusFreeIrq(prDev, netdev_priv(prDev)); + + kalMemSet(&(prGlueInfo->prAdapter->rWlanInfo), 0, sizeof(WLAN_INFO_T)); + + flush_scheduled_work(); + + down(&g_halt_sem); + g_u4HaltFlag = 1; + + //4 <2> Mark HALT, notify main thread to stop, and clean up queued requests + prGlueInfo->u4Flag |= GLUE_FLAG_HALT; + /* wake up main thread */ + wake_up_interruptible(&prGlueInfo->waitq); + /* wait main thread stops */ + wait_for_completion_interruptible(&prGlueInfo->rHaltComp); + + DBGLOG(INIT, INFO, ("mtk_sdiod stopped\n")); + + //prGlueInfo->rHifInfo.main_thread = NULL; + prGlueInfo->main_thread = NULL; + +#if CFG_ENABLE_BT_OVER_WIFI + if(prGlueInfo->rBowInfo.fgIsRegistered) { + glUnregisterAmpc(prGlueInfo); + } +#endif + + + //4 <3> Remove /proc filesystem. +#ifdef WLAN_INCLUDE_PROC + procRemoveProcfs(prDev, NIC_DEVICE_ID_LOW); +#endif /* WLAN_INCLUDE_PROC */ + + //4 <4> wlanAdapterStop + prAdapter = prGlueInfo->prAdapter; + + wlanAdapterStop(prAdapter); + DBGLOG(INIT, INFO, ("Number of Stalled Packets = %ld\n", prGlueInfo->i4TxPendingFrameNum)); + + //4 <5> Release the Bus + glBusRelease(prDev); + + up(&g_halt_sem); + flush_scheduled_work(); + + //4 <6> Unregister the card + wlanNetUnregister(prDev); + + //4 <7> Destroy the device + wlanNetDestroy(prDev); + prDev = NULL; + + return; +} /* end of wlanRemove() */ +extern void wlanRegisterNotifier(void); +extern void wlanUnregisterNotifier(void); + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Driver entry point when the driver is configured as a Linux Module, and +* is called once at module load time, by the user-level modutils +* application: insmod or modprobe. +* +* \retval 0 Success +*/ +/*----------------------------------------------------------------------------*/ +//1 Module Entry Point +static int __init initWlan(void) +{ + int ret = 0; + + DBGLOG(INIT, INFO, ("initWlan\n")); + + /* memory pre-allocation */ + kalInitIOBuffer(); + + //return ((glRegisterBus(wlanProbe, wlanRemove) == WLAN_STATUS_SUCCESS) ? 0: -EIO); + ret = ((glRegisterBus(wlanProbe, wlanRemove) == WLAN_STATUS_SUCCESS) ? 0: -EIO); + + if (ret == -EIO) { + kalUninitIOBuffer(); + return ret; + } + + glRegisterEarlySuspend(&mt6620_early_suspend_desc, wlan_early_suspend, wlan_late_resume); + wlanRegisterNotifier(); + +#if (CFG_CHIP_RESET_SUPPORT) + glResetInit(); +#endif + + return ret; +} /* end of initWlan() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Driver exit point when the driver as a Linux Module is removed. Called +* at module unload time, by the user level modutils application: rmmod. +* This is our last chance to clean up after ourselves. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +//1 Module Leave Point +static VOID __exit exitWlan(void) +{ + //printk("remove %p\n", wlanRemove); + glUnregisterEarlySuspend(&mt6620_early_suspend_desc); + wlanUnregisterNotifier(); + +#if CFG_CHIP_RESET_SUPPORT + glResetUninit(); +#endif + + glUnregisterBus(wlanRemove); + + /* free pre-allocated memory */ + kalUninitIOBuffer(); + + DBGLOG(INIT, INFO, ("exitWlan\n")); + + return; +} /* end of exitWlan() */ + +module_init(initWlan); +module_exit(exitWlan); + +/* export necessary symbol for p2p driver using */ +#if CFG_ENABLE_WIFI_DIRECT +EXPORT_SYMBOL(wlanSubModRegisterInitExit); +EXPORT_SYMBOL(wlanSubModExit); +EXPORT_SYMBOL(wlanSubModInit); + +EXPORT_SYMBOL(nicPmIndicateBssCreated); +EXPORT_SYMBOL(rlmProcessAssocRsp); +EXPORT_SYMBOL(kalSetEvent); +EXPORT_SYMBOL(rlmBssInitForAPandIbss); +EXPORT_SYMBOL(kalEnqueueCommand); +EXPORT_SYMBOL(nicIncreaseTxSeqNum); +EXPORT_SYMBOL(nicCmdEventQueryAddress); +EXPORT_SYMBOL(bssCreateStaRecFromBssDesc); +EXPORT_SYMBOL(rlmBssAborted); +EXPORT_SYMBOL(cnmStaRecResetStatus); +EXPORT_SYMBOL(mqmProcessAssocRsp); +EXPORT_SYMBOL(nicTxReturnMsduInfo); +EXPORT_SYMBOL(nicTxEnqueueMsdu); +EXPORT_SYMBOL(wlanProcessSecurityFrame); +EXPORT_SYMBOL(nicChannelNum2Freq); +EXPORT_SYMBOL(nicUpdateBss); +EXPORT_SYMBOL(wlanSendSetQueryCmd); +EXPORT_SYMBOL(cnmStaRecAlloc); +EXPORT_SYMBOL(cnmTimerInitTimer); +EXPORT_SYMBOL(rateGetRateSetFromIEs); +EXPORT_SYMBOL(nicOidCmdTimeoutCommon); +EXPORT_SYMBOL(cnmStaRecChangeState); +EXPORT_SYMBOL(rateGetDataRatesFromRateSet); +EXPORT_SYMBOL(cnmMgtPktAlloc); +EXPORT_SYMBOL(cnmMgtPktFree); +EXPORT_SYMBOL(wextSrchDesiredWPAIE); +EXPORT_SYMBOL(nicRxReturnRFB); +EXPORT_SYMBOL(cnmTimerStartTimer); +EXPORT_SYMBOL(cmdBufAllocateCmdInfo); +EXPORT_SYMBOL(cnmGetStaRecByAddress); +EXPORT_SYMBOL(nicMediaStateChange); +EXPORT_SYMBOL(bssUpdateBeaconContent); +EXPORT_SYMBOL(kalIoctl); +EXPORT_SYMBOL(nicActivateNetwork); +EXPORT_SYMBOL(nicDeactivateNetwork); +EXPORT_SYMBOL(kalRandomNumber); +EXPORT_SYMBOL(nicCmdEventSetCommon); +EXPORT_SYMBOL(cnmTimerStopTimer); +EXPORT_SYMBOL(nicIncreaseCmdSeqNum); +EXPORT_SYMBOL(authSendDeauthFrame); +EXPORT_SYMBOL(cnmMemAlloc); +EXPORT_SYMBOL(nicPmIndicateBssAbort); +EXPORT_SYMBOL(nicCmdEventSetIpAddress); +EXPORT_SYMBOL(mboxSendMsg); +EXPORT_SYMBOL(scanSearchBssDescByBssid); +EXPORT_SYMBOL(bssRemoveStaRecFromClientList); +EXPORT_SYMBOL(assocProcessRxDisassocFrame); +EXPORT_SYMBOL(authProcessRxDeauthFrame); +EXPORT_SYMBOL(cnmStaRecFree); +EXPORT_SYMBOL(rNonHTPhyAttributes); +EXPORT_SYMBOL(rNonHTApModeAttributes); +EXPORT_SYMBOL(cnmMemFree); +EXPORT_SYMBOL(wlanExportGlueInfo); +EXPORT_SYMBOL(bssInitForAP); +EXPORT_SYMBOL(nicPmIndicateBssConnected); +EXPORT_SYMBOL(rlmRspGenerateHtOpIE); +EXPORT_SYMBOL(bssGenerateExtSuppRate_IE); +EXPORT_SYMBOL(rlmRspGenerateErpIE); +EXPORT_SYMBOL(rlmRspGenerateHtCapIE); +EXPORT_SYMBOL(cnmGetStaRecByIndex); +EXPORT_SYMBOL(rsnGenerateWpaNoneIE); +EXPORT_SYMBOL(rlmRspGenerateExtCapIE); +EXPORT_SYMBOL(rsnGenerateRSNIE); +EXPORT_SYMBOL(rsnParseRsnIE); +#if CFG_SUPPORT_WPS +EXPORT_SYMBOL(wextSrchDesiredWPSIE); +#endif +EXPORT_SYMBOL(mboxDummy); +EXPORT_SYMBOL(saaFsmRunEventStart); +EXPORT_SYMBOL(saaFsmRunEventAbort); +EXPORT_SYMBOL(cnmP2PIsPermitted); +EXPORT_SYMBOL(cnmBss40mBwPermitted); +EXPORT_SYMBOL(mqmGenerateWmmParamIE); +EXPORT_SYMBOL(cnmPreferredChannel); +EXPORT_SYMBOL(bssAddStaRecToClientList); +EXPORT_SYMBOL(nicQmUpdateWmmParms); +EXPORT_SYMBOL(qmFreeAllByNetType); +EXPORT_SYMBOL(wlanQueryInformation); +EXPORT_SYMBOL(nicConfigPowerSaveProfile); +EXPORT_SYMBOL(scanSearchExistingBssDesc); +EXPORT_SYMBOL(scanAllocateBssDesc); +EXPORT_SYMBOL(wlanProcessCommandQueue); +EXPORT_SYMBOL(wlanAcquirePowerControl); +EXPORT_SYMBOL(wlanReleasePowerControl); +EXPORT_SYMBOL(wlanReleasePendingCMDbyNetwork); +#if DBG +EXPORT_SYMBOL(aucDebugModule); +EXPORT_SYMBOL(fgIsBusAccessFailed); +EXPORT_SYMBOL(allocatedMemSize); +EXPORT_SYMBOL(dumpMemory8); +EXPORT_SYMBOL(dumpMemory32); +#endif +EXPORT_SYMBOL(rlmDomainIsLegalChannel); +EXPORT_SYMBOL(scnQuerySparseChannel); +EXPORT_SYMBOL(rlmDomainGetChnlList); +EXPORT_SYMBOL(p2pSetMulticastListWorkQueueWrapper); +EXPORT_SYMBOL(nicUpdateRSSI); +EXPORT_SYMBOL(nicCmdEventQueryLinkQuality); +EXPORT_SYMBOL(kalGetMediaStateIndicated); +EXPORT_SYMBOL(nicFreq2ChannelNum); +EXPORT_SYMBOL(assocSendDisAssocFrame); +EXPORT_SYMBOL(nicUpdateBeaconIETemplate); +EXPORT_SYMBOL(rsnParseCheckForWFAInfoElem); +EXPORT_SYMBOL(kalClearMgmtFramesByNetType); +EXPORT_SYMBOL(kalClearSecurityFramesByNetType); +EXPORT_SYMBOL(nicFreePendingTxMsduInfoByNetwork); +EXPORT_SYMBOL(bssComposeBeaconProbeRespFrameHeaderAndFF); +EXPORT_SYMBOL(bssBuildBeaconProbeRespFrameCommonIEs); +#endif + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_kal.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_kal.c new file mode 100755 index 000000000000..5ed39f2afad7 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_kal.c @@ -0,0 +1,3660 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/os/linux/gl_kal.c#2 $ +*/ + +/*! \file gl_kal.c + \brief GLUE Layer will export the required procedures here for internal driver stack. + + This file contains all routines which are exported from GLUE Layer to internal + driver stack. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: gl_kal.c $ + * + * 03 26 2012 cp.wu + * [ALPS00255324] wifi ???ぃwps?ぃ??ご + * invoke put_cred() after get_current_cred() calls to release a reference + * + * 03 26 2012 yuche.tsai + * [ALPS00255551] [WiFi direct][Google Issue]GC can't send picture to GO sometimes,GO and GC can't ping each other + * Avoid ran out of driver resource when starting GO. + * + * 02 20 2012 cp.wu + * [ALPS00239244] [MT6620 Wi-Fi][Driver] Improve error handling while firmware image doesn't exist + * no need to free buffer if firmware image doesn't exis. + * + * 02 06 2012 wh.su + * [ALPS00109161] [Need Patch] [Volunteer Patch] [Wi-Fi] Support the set tx power driver cmd + * Adding the AP mode channel query filter. + * + * 02 06 2012 yuche.tsai + * [ALPS00118350] [ALPS.ICS][WiFi Direct] Dirver update for wifi direct connection + * Small bug fix for CNM memory usage, scan SSID search issue, P2P network deactivate issue. + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Hot Spot Tethering for ICS ALPHA testing version. + * + * 01 02 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Adding the proto type function for set_int set_tx_power and get int get_ch_list. + * + * 11 21 2011 cp.wu + * [WCXRP00001118] [MT6620 Wi-Fi][Driver] Corner case protections to pass Monkey testing + * 1. wlanoidQueryBssIdList might be passed with a non-zero length but a NULL pointer of buffer + * add more checking for such cases + * + * 2. kalSendComplete() might be invoked with a packet belongs to P2P network right after P2P is unregistered. + * add some tweaking to protect such cases because that net device has become invalid. + * + * 11 19 2011 yuche.tsai + * NULL + * Add P2P RSSI Link Quality Query Support. (Default Off) + * + * 11 16 2011 yuche.tsai + * NULL + * Avoid using work thread. + * + * 11 10 2011 cp.wu + * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer + * 1. eliminaite direct calls to printk in porting layer. + * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 08 12 2011 cp.wu + * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC + * load WIFI_RAM_CODE_E6 for MT6620 E6 ASIC. + * + * 06 13 2011 eddie.chen + * [WCXRP00000779] [MT6620 Wi-Fi][DRV] Add tx rx statistics in linux and use netif_rx_ni + * Add tx rx statistics and netif_rx_ni. + * + * 04 15 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add BOW short range mode. + * + * 04 12 2011 cp.wu + * [WCXRP00000635] [MT6620 Wi-Fi][Driver] Clear pending security frames when QM clear pending data frames for dedicated network type + * clear pending security frames for dedicated network type when BSS is being deactivated/disconnected + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 18 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage after system running for a long period + * refix ... + * + * 03 18 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage after system running for a long period + * correct compiling warning/error. + * + * 03 18 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage after system running for a long period + * add more robust fault tolerance design when pre-allocation failed. (rarely happen) + * + * 03 17 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage after system running for a long period + * use pre-allocated buffer for storing enhanced interrupt response as well + * + * 03 16 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage after system running for a long period + * 1. pre-allocate physical continuous buffer while module is being loaded + * 2. use pre-allocated physical continuous buffer for TX/RX DMA transfer + * + * The windows part remained the same as before, but added similiar APIs to hide the difference. + * + * 03 15 2011 cp.wu + * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous memory consumption + * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK + * 2. Use common coalescing buffer for both TX/RX directions + * + * + * 03 14 2011 jeffrey.chang + * [WCXRP00000546] [MT6620 Wi-Fi][MT6620 Wi-Fi][Driver] fix kernel build warning message + * fix kernel build warning message + * + * 03 07 2011 terry.wu + * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message + * Toggle non-standard debug messages to comments. + * + * 03 06 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Sync BOW Driver to latest person development branch version.. + * + * 03 03 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * support concurrent network + * + * 03 03 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * modify net device relative functions to support multiple H/W queues + * + * 03 02 2011 cp.wu + * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right after connection is built. + * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. + * + * 02 21 2011 cp.wu + * [WCXRP00000482] [MT6620 Wi-Fi][Driver] Simplify logic for checking NVRAM existence in driver domain + * simplify logic for checking NVRAM existence only once. + * + * 01 24 2011 cp.wu + * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving + * 1. add an extra counter for tracking pending forward frames. + * 2. notify TX service thread as well when there is pending forward frame + * 3. correct build errors leaded by introduction of Wi-Fi direct separation module + * + * 01 19 2011 cp.wu + * [WCXRP00000371] [MT6620 Wi-Fi][Driver] make linux glue layer portable for Android 2.3.1 with Linux 2.6.35.7 + * add compile option to check linux version 2.6.35 for different usage of system API to improve portability + * + * 01 12 2011 cp.wu + * [WCXRP00000357] [MT6620 Wi-Fi][Driver][Bluetooth over Wi-Fi] add another net device interface for BT AMP + * implementation of separate BT_OVER_WIFI data path. + * + * 01 10 2011 cp.wu + * [WCXRP00000349] [MT6620 Wi-Fi][Driver] make kalIoctl() of linux port as a thread safe API to avoid potential issues due to multiple access + * use mutex to protect kalIoctl() for thread safe. + * + * 11 26 2010 cp.wu + * [WCXRP00000209] [MT6620 Wi-Fi][Driver] Modify NVRAM checking mechanism to warning only with necessary data field checking + * 1. NVRAM error is now treated as warning only, thus normal operation is still available but extra scan result used to indicate user is attached + * 2. DPD and TX-PWR are needed fields from now on, if these 2 fields are not availble then warning message is shown + * + * 11 04 2010 wh.su + * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID + * adding the p2p random ssid support. + * + * 11 02 2010 jeffrey.chang + * [WCXRP00000145] [MT6620 Wi-Fi][Driver] fix issue of byte endian in packet classifier which discards BoW packets + * . + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 11 01 2010 yarco.yang + * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform + * Add code to run WlanIST in SDIO callback. + * + * 10 26 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command + * 1) update NVRAM content template to ver 1.02 + * 2) add compile option for querying NIC capability (default: off) + * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting + * 4) correct auto-rate compiler error under linux (treat warning as error) + * 5) simplify usage of NVRAM and REG_INFO_T + * 6) add version checking between driver and firmware + * + * 10 25 2010 jeffrey.chang + * [WCXRP00000129] [MT6620] [Driver] Kernel panic when rmmod module on Andriod platform + * Remove redundant code which cause mismatch of power control release + * + * 10 25 2010 jeffrey.chang + * [WCXRP00000129] [MT6620] [Driver] Kernel panic when rmmod module on Andriod platform + * Remove redundant GLUE_HALT condfition to avoid unmatched release of power control + * + * 10 18 2010 jeffrey.chang + * [WCXRP00000116] [MT6620 Wi-Fi][Driver] Refine the set_scan ioctl to resolve the Android UI hanging issue + * refine the scan ioctl to prevent hanging of Android UI + * + * 10 18 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android + * complete implementation of Android NVRAM access + * + * 10 06 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * if there is NVRAM, then use MAC address on NVRAM as default MAC address. + * + * 10 06 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * code reorganization to improve isolation between GLUE and CORE layers. + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * 1) add NVRAM access API + * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) + * 3) add OID implementation for NVRAM read/write service + * + * 09 21 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS associated + * Do a complete reset with STA-REC null checking for RF test re-entry + * + * 09 21 2010 kevin.huang + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * Eliminate Linux Compile Warning + * + * 09 07 2010 wh.su + * NULL + * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 30 2010 cp.wu + * NULL + * API added: nicTxPendingPackets(), for simplifying porting layer + * + * 08 20 2010 yuche.tsai + * NULL + * Support second interface indicate when enabling P2P. + * + * 08 18 2010 yarco.yang + * NULL + * 1. Fixed HW checksum offload function not work under Linux issue. + * 2. Add debug message. + * + * 08 16 2010 jeffrey.chang + * NULL + * remove redundant code which cause kernel panic + * + * 08 16 2010 cp.wu + * NULL + * P2P packets are now marked when being queued into driver, and identified later without checking MAC address + * + * 08 02 2010 jeffrey.chang + * NULL + * 1) modify tx service thread to avoid busy looping + * 2) add spin lock declartion for linux build + * + * 07 29 2010 cp.wu + * NULL + * simplify post-handling after TX_DONE interrupt is handled. + * + * 07 28 2010 jeffrey.chang + * NULL + * 1) remove unused spinlocks + * 2) enable encyption ioctls + * 3) fix scan ioctl which may cause supplicant to hang + * + * 07 23 2010 cp.wu + * + * 1) re-enable AIS-FSM beacon timeout handling. + * 2) scan done API revised + * + * 07 23 2010 jeffrey.chang + * + * add new KAL api + * + * 07 23 2010 jeffrey.chang + * + * bug fix: allocate regInfo when disabling firmware download + * + * 07 23 2010 jeffrey.chang + * + * use glue layer api to decrease or increase counter atomically + * + * 07 22 2010 jeffrey.chang + * + * modify tx thread and remove some spinlock + * + * 07 22 2010 jeffrey.chang + * + * use different spin lock for security frame + * + * 07 22 2010 jeffrey.chang + * + * add new spinlock + * + * 07 19 2010 jeffrey.chang + * + * add spinlock for pending security frame count + * + * 07 19 2010 jeffrey.chang + * + * adjust the timer unit to microsecond + * + * 07 19 2010 jeffrey.chang + * + * timer should return value greater than zero + * + * 07 19 2010 jeffrey.chang + * + * add kal api for scanning done + * + * 07 19 2010 jeffrey.chang + * + * modify cmd/data path for new design + * + * 07 19 2010 jeffrey.chang + * + * add new kal api + * + * 07 19 2010 jeffrey.chang + * + * for linux driver migration + * + * 07 19 2010 jeffrey.chang + * + * Linux port modification + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 23 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Merge g_arStaRec[] into adapter->arStaRec[] + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * change MAC address updating logic. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 06 01 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * remove unused files. + * + * 05 29 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * fix private ioctl for rftest + * + * 05 29 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * workaround for fixing request_firmware() failure on android 2.1 + * + * 05 28 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * fix kernel panic when debug mode enabled + * + * 05 26 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * 1) Modify set mac address code + * 2) remove power managment macro + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * 1) add timeout handler mechanism for pending command packets + * 2) add p2p add/removal key + * + * 05 14 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Disable network interface after disassociation + * + * 05 10 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * fill network type field while doing frame identification. + * + * 05 07 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * prevent supplicant accessing driver during resume + * + * 04 27 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * identify BT Over Wi-Fi Security frame and mark it as 802.1X frame + * + * 04 27 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * 1) fix firmware download bug + * 2) remove query statistics for acelerating firmware download + * + * 04 27 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * follow Linux's firmware framework, and remove unused kal API + * + * 04 22 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * + * 1) modify rx path code for supporting Wi-Fi direct + * 2) modify config.h since Linux dont need to consider retaining packet + * + * 04 21 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * add for private ioctl support + * + * 04 15 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * change firmware name + * + * 04 14 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * flush pending TX packets while unloading driver + * + * 04 14 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Set driver own before handling cmd queue + * + * 04 14 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * 1) prGlueInfo->pvInformationBuffer and prGlueInfo->u4InformationBufferLength are no longer used + * 2) fix ioctl + * + * 04 14 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * information buffer for query oid/ioctl is now buffered in prCmdInfo + * * * * * * * instead of glue-layer variable to improve multiple oid/ioctl capability + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * * * * * * * * * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose + * + * 04 09 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * fix spinlock usage + * + * 04 09 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * add spinlock for i4TxPendingFrameNum access + * + * 04 09 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * 1) add spinlock + * * 2) add KAPI for handling association info + * + * 04 09 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * fix spinlock usage + * + * 04 09 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * adding firmware download KAPI + * + * 04 07 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Set MAC address from firmware + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. free cmdinfo after command is emiited. + * 2. for BoW frames, user priority is extracted from sk_buff directly. + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * finish non-glue layer access to glue variables + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * accessing to firmware load/start address, and access to OID handling information + * * * are now handled in glue layer + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * rWlanInfo should be placed at adapter rather than glue due to most operations + * * * * * * * are done in adapter layer. + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access to prGlueInfo->eParamMediaStateIndicated from non-glue layer + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * (1)deliver the kalOidComplete status to upper layer + * (2) fix spin lock + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add KAL API: kalFlushPendingTxPackets(), and take use of the API + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access to prGlueInfo->rWlanInfo.eLinkAttr.ucMediaStreamMode from non-glue layer. + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * add timeout check in the kalOidComplete + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * improve none-glue code portability + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) for some OID, never do timeout expiration + * * * 2) add 2 kal API for later integration + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * raising the priority of processing interrupt + * + * 04 01 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Bug fix: the tx thread will cause starvation of MMC thread, and the interrupt will never come in + * + * 03 30 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * emulate NDIS Pending OID facility + * + * 03 28 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * adding secondary command queue for improving non-glue code portability + * + * 03 26 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * [WPD00003826] Initial import for Linux port + * adding firmware download kal api + * + * 03 25 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add Bluetooth-over-Wifi frame header check + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port +** \main\maintrunk.MT5921\50 2009-09-28 20:19:08 GMT mtk01090 +** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. +** \main\maintrunk.MT5921\49 2009-08-18 22:56:44 GMT mtk01090 +** Add Linux SDIO (with mmc core) support. +** Add Linux 2.6.21, 2.6.25, 2.6.26. +** Fix compile warning in Linux. +** \main\maintrunk.MT5921\48 2009-06-23 23:18:58 GMT mtk01090 +** Add build option BUILD_USE_EEPROM and compile option CFG_SUPPORT_EXT_CONFIG for NVRAM support +** \main\maintrunk.MT5921\47 2008-11-19 11:55:43 GMT mtk01088 +** fixed some lint warning, and rename some variable with pre-fix to avoid the misunderstanding +** \main\maintrunk.MT5921\46 2008-09-02 21:07:42 GMT mtk01461 +** Remove ASSERT(pvBuf) in kalIndicateStatusAndComplete(), this parameter can be NULL +** \main\maintrunk.MT5921\45 2008-08-29 16:03:21 GMT mtk01088 +** remove non-used code for code review, add assert check +** \main\maintrunk.MT5921\44 2008-08-21 00:32:49 GMT mtk01461 +** \main\maintrunk.MT5921\43 2008-05-30 20:27:02 GMT mtk01461 +** Rename KAL function +** \main\maintrunk.MT5921\42 2008-05-30 15:47:29 GMT mtk01461 +** \main\maintrunk.MT5921\41 2008-05-30 15:13:04 GMT mtk01084 +** rename wlanoid +** \main\maintrunk.MT5921\40 2008-05-29 14:15:14 GMT mtk01084 +** remove un-used KAL function +** \main\maintrunk.MT5921\39 2008-05-03 15:17:30 GMT mtk01461 +** Move Query Media Status to GLUE +** \main\maintrunk.MT5921\38 2008-04-24 11:59:44 GMT mtk01461 +** change awake queue threshold and remove code which mark #if 0 +** \main\maintrunk.MT5921\37 2008-04-17 23:06:35 GMT mtk01461 +** Add iwpriv support for AdHocMode setting +** \main\maintrunk.MT5921\36 2008-04-08 15:38:56 GMT mtk01084 +** add KAL function to setting pattern search function enable/ disable +** \main\maintrunk.MT5921\35 2008-04-01 23:53:13 GMT mtk01461 +** Add comment +** \main\maintrunk.MT5921\34 2008-03-26 15:36:48 GMT mtk01461 +** Add update MAC Address for Linux +** \main\maintrunk.MT5921\33 2008-03-18 11:49:34 GMT mtk01084 +** update function for initial value access +** \main\maintrunk.MT5921\32 2008-03-18 10:25:22 GMT mtk01088 +** use kal update associate request at linux +** \main\maintrunk.MT5921\31 2008-03-06 23:43:08 GMT mtk01385 +** 1. add Query Registry Mac address function. +** \main\maintrunk.MT5921\30 2008-02-26 09:47:57 GMT mtk01084 +** modify KAL set network address/ checksum offload part +** \main\maintrunk.MT5921\29 2008-02-12 23:26:53 GMT mtk01461 +** Add debug option - Packet Order for Linux +** \main\maintrunk.MT5921\28 2008-01-09 17:54:43 GMT mtk01084 +** modify the argument of kalQueryPacketInfo() +** \main\maintrunk.MT5921\27 2007-12-24 16:02:03 GMT mtk01425 +** 1. Revise csum offload +** \main\maintrunk.MT5921\26 2007-11-30 17:03:36 GMT mtk01425 +** 1. Fix bugs +** +** \main\maintrunk.MT5921\25 2007-11-29 01:57:17 GMT mtk01461 +** Fix Windows RX multiple packet retain problem +** \main\maintrunk.MT5921\24 2007-11-20 11:24:07 GMT mtk01088 +** CR90, not doing the netif_carrier_off to let supplicant 1x pkt can be rcv at hardstattXmit +** \main\maintrunk.MT5921\23 2007-11-09 16:36:44 GMT mtk01425 +** 1. Modify for CSUM offloading with Tx Fragment +** \main\maintrunk.MT5921\22 2007-11-07 18:37:39 GMT mtk01461 +** Add Tx Fragmentation Support +** \main\maintrunk.MT5921\21 2007-11-06 19:34:06 GMT mtk01088 +** add the WPS code, indicate the mgmt frame to upper layer +** \main\maintrunk.MT5921\20 2007-11-02 01:03:21 GMT mtk01461 +** Unify TX Path for Normal and IBSS Power Save + IBSS neighbor learning +** \main\maintrunk.MT5921\19 2007-10-30 11:59:38 GMT MTK01425 +** 1. Update wlanQueryInformation +** \main\maintrunk.MT5921\18 2007-10-30 10:44:57 GMT mtk01425 +** 1. Refine multicast list code +** 2. Refine TCP/IP csum offload code +** +** Revision 1.5 2007/07/17 13:01:18 MTK01088 +** add associate req and rsp function +** +** Revision 1.4 2007/07/13 05:19:19 MTK01084 +** provide timer set functions +** +** Revision 1.3 2007/06/27 02:18:51 MTK01461 +** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API +** +** Revision 1.2 2007/06/25 06:16:24 MTK01461 +** Update illustrations, gl_init.c, gl_kal.c, gl_kal.h, gl_os.h and RX API +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "gl_os.h" +#include "gl_wext.h" +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +#if DBG +int allocatedMemSize = 0; +#endif + +extern struct semaphore g_halt_sem; +extern int g_u4HaltFlag; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +static PVOID pvIoBuffer = NULL; +static UINT_32 pvIoBufferSize = 0; +static UINT_32 pvIoBufferUsage = 0; + + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +#if defined(MT6620) && CFG_MULTI_ECOVER_SUPPORT +typedef enum _ENUM_WMTHWVER_TYPE_T{ + WMTHWVER_MT6620_E1 = 0x0, + WMTHWVER_MT6620_E2 = 0x1, + WMTHWVER_MT6620_E3 = 0x2, + WMTHWVER_MT6620_E4 = 0x3, + WMTHWVER_MT6620_E5 = 0x4, + WMTHWVER_MT6620_E6 = 0x5, + WMTHWVER_MT6620_MAX, + WMTHWVER_INVALID = 0xff +} ENUM_WMTHWVER_TYPE_T, *P_ENUM_WMTHWVER_TYPE_T; + +extern ENUM_WMTHWVER_TYPE_T +mtk_wcn_wmt_hwver_get( + VOID + ); +#elif defined(MT5931) && CFG_MULTI_ECOVER_SUPPORT +typedef enum _ENUM_HWVER_TYPE_T{ + HWVER_MT5931_E1 = 0x1, + HWVER_MT5931_E2 = 0x2, + HWVER_MT5931_E3 = 0x3, + HWVER_MT5931_MAX, + HWVER_INVALID = 0xff +} ENUM_HWVER_TYPE_T, *P_ENUM_HWVER_TYPE_T; +#endif + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#if CFG_ENABLE_FW_DOWNLOAD + +static struct file *filp = NULL; +static uid_t orgfsuid; +static gid_t orgfsgid; +static mm_segment_t orgfs; + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is provided by GLUE Layer for internal driver stack to +* open firmware image in kernel space +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* +* \retval WLAN_STATUS_SUCCESS. +* \retval WLAN_STATUS_FAILURE. +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +kalFirmwareOpen ( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + /* FIX ME: since we don't have hotplug script in the filesystem + * , so the request_firmware() KAPI can not work properly + */ + + /* save uid and gid used for filesystem access. + * set user and group to 0(root) */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)) + orgfsuid = current->fsuid; + orgfsgid = current->fsgid; + current->fsuid = current->fsgid = 0; +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) + struct cred *cred = (struct cred *) get_current_cred(); + orgfsuid = cred->fsuid; + orgfsgid = cred->fsgid; + cred->fsuid = cred->fsgid = 0; +#else + struct cred *cred = get_task_cred(current); + orgfsuid = cred->fsuid; + orgfsgid = cred->fsgid; + cred->fsuid = cred->fsgid = 0; +#endif + + ASSERT(prGlueInfo); + + + orgfs = get_fs(); + set_fs(get_ds()); + + + /* open the fw file */ +#if defined(MT6620) & CFG_MULTI_ECOVER_SUPPORT + switch(mtk_wcn_wmt_hwver_get()) { + case WMTHWVER_MT6620_E1: + case WMTHWVER_MT6620_E2: + case WMTHWVER_MT6620_E3: + case WMTHWVER_MT6620_E4: + case WMTHWVER_MT6620_E5: + filp = filp_open("/etc/firmware/"CFG_FW_FILENAME, O_RDONLY, 0); + break; + + case WMTHWVER_MT6620_E6: + default: + filp = filp_open("/etc/firmware/"CFG_FW_FILENAME"_E6", O_RDONLY, 0); + break; + } +#elif defined(MT5931) && CFG_MULTI_ECOVER_SUPPORT + switch (wlanGetEcoVersion(prGlueInfo->prAdapter)) { + case HWVER_MT5931_E1: + case HWVER_MT5931_E2: + filp = filp_open("/etc/firmware/"CFG_FW_FILENAME"_E2", O_RDONLY, 0); + break; + case HWVER_MT5931_E3: + default: + filp = filp_open("/etc/firmware/"CFG_FW_FILENAME, O_RDONLY, 0); + break; + } +#else + filp = filp_open("/etc/firmware/"CFG_FW_FILENAME, O_RDONLY, 0); +#endif + if (IS_ERR(filp)) { + DBGLOG(INIT, INFO, ("Open FW image: %s failed\n", CFG_FW_FILENAME)); + goto error_open; + } + DBGLOG(INIT, INFO, ("Open FW image: %s done\n", CFG_FW_FILENAME)); + return WLAN_STATUS_SUCCESS; + +error_open: + /* restore */ + set_fs(orgfs); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)) + current->fsuid = orgfsuid; + current->fsgid = orgfsgid; +#else + cred->fsuid = orgfsuid; + cred->fsgid = orgfsgid; + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) + put_cred(cred); + #endif +#endif + return WLAN_STATUS_FAILURE; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is provided by GLUE Layer for internal driver stack to +* release firmware image in kernel space +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* +* \retval WLAN_STATUS_SUCCESS. +* \retval WLAN_STATUS_FAILURE. +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +kalFirmwareClose ( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + ASSERT(prGlueInfo); + + if ((filp != NULL) && !IS_ERR(filp)) { + /* close firmware file */ + filp_close(filp, NULL); + + /* restore */ + set_fs(orgfs); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)) + current->fsuid = orgfsuid; + current->fsgid = orgfsgid; +#else + { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) + struct cred *cred = (struct cred *) get_current_cred(); +#else + struct cred *cred = get_task_cred(current); +#endif + cred->fsuid = orgfsuid; + cred->fsgid = orgfsgid; + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) + put_cred(cred); + #endif + } +#endif + filp = NULL; + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is provided by GLUE Layer for internal driver stack to +* load firmware image in kernel space +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* +* \retval WLAN_STATUS_SUCCESS. +* \retval WLAN_STATUS_FAILURE. +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +kalFirmwareLoad ( + IN P_GLUE_INFO_T prGlueInfo, + OUT PVOID prBuf, + IN UINT_32 u4Offset, + OUT PUINT_32 pu4Size + ) +{ + ASSERT(prGlueInfo); + ASSERT(pu4Size); + ASSERT(prBuf); + + //l = filp->f_path.dentry->d_inode->i_size; + + /* the object must have a read method */ + if ((filp == NULL) || IS_ERR(filp) || (filp->f_op == NULL) || (filp->f_op->read == NULL)) { + goto error_read; + } else { + filp->f_pos = u4Offset; + *pu4Size = filp->f_op->read(filp, prBuf, *pu4Size, &filp->f_pos); + } + + return WLAN_STATUS_SUCCESS; + +error_read: + return WLAN_STATUS_FAILURE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is provided by GLUE Layer for internal driver stack to +* query firmware image size in kernel space +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* +* \retval WLAN_STATUS_SUCCESS. +* \retval WLAN_STATUS_FAILURE. +* +*/ +/*----------------------------------------------------------------------------*/ + +WLAN_STATUS +kalFirmwareSize ( + IN P_GLUE_INFO_T prGlueInfo, + OUT PUINT_32 pu4Size + ) +{ + ASSERT(prGlueInfo); + ASSERT(pu4Size); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 12) + *pu4Size = filp->f_path.dentry->d_inode->i_size; +#else + *pu4Size = filp->f_dentry->d_inode->i_size; +#endif + + return WLAN_STATUS_SUCCESS; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to load firmware image +* +* \param pvGlueInfo Pointer of GLUE Data Structure +* \param ppvMapFileBuf Pointer of pointer to memory-mapped firmware image +* \param pu4FileLength File length and memory mapped length as well + +* \retval Map File Handle, used for unammping +*/ +/*----------------------------------------------------------------------------*/ + +PVOID +kalFirmwareImageMapping ( + IN P_GLUE_INFO_T prGlueInfo, + OUT PPVOID ppvMapFileBuf, + OUT PUINT_32 pu4FileLength + ) +{ + DEBUGFUNC("kalFirmwareImageMapping"); + + ASSERT(prGlueInfo); + ASSERT(ppvMapFileBuf); + ASSERT(pu4FileLength); + + do { + /* <1> Open firmware */ + if (kalFirmwareOpen(prGlueInfo) != WLAN_STATUS_SUCCESS) { + break; + } else { + UINT_32 u4FwSize = 0; + PVOID prFwBuffer = NULL; + /* <2> Query firmare size */ + kalFirmwareSize(prGlueInfo, &u4FwSize); + /* <3> Use vmalloc for allocating large memory trunk */ + prFwBuffer = vmalloc(ALIGN_4(u4FwSize)); + /* <4> Load image binary into buffer */ + if (kalFirmwareLoad(prGlueInfo, prFwBuffer, 0, &u4FwSize) != WLAN_STATUS_SUCCESS) { + vfree(prFwBuffer); + kalFirmwareClose(prGlueInfo); + break; + } + /* <5> write back info */ + *pu4FileLength = u4FwSize; + *ppvMapFileBuf = prFwBuffer; + + return prFwBuffer; + } + + } while (FALSE); + + return NULL; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to unload firmware image mapped memory +* +* \param pvGlueInfo Pointer of GLUE Data Structure +* \param pvFwHandle Pointer to mapping handle +* \param pvMapFileBuf Pointer to memory-mapped firmware image +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ + +VOID +kalFirmwareImageUnmapping ( + IN P_GLUE_INFO_T prGlueInfo, + IN PVOID prFwHandle, + IN PVOID pvMapFileBuf + ) +{ + DEBUGFUNC("kalFirmwareImageUnmapping"); + + ASSERT(prGlueInfo); + + /* pvMapFileBuf might be NULL when file doesn't exist */ + if(pvMapFileBuf) { + vfree(pvMapFileBuf); + } + + kalFirmwareClose(prGlueInfo); +} + +#endif + +#if 0 + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to load firmware image +* +* \param pvGlueInfo Pointer of GLUE Data Structure +* \param ppvMapFileBuf Pointer of pointer to memory-mapped firmware image +* \param pu4FileLength File length and memory mapped length as well + +* \retval Map File Handle, used for unammping +*/ +/*----------------------------------------------------------------------------*/ + +PVOID +kalFirmwareImageMapping ( + IN P_GLUE_INFO_T prGlueInfo, + OUT PPVOID ppvMapFileBuf, + OUT PUINT_32 pu4FileLength + ) +{ + INT_32 i4Ret = 0; + + DEBUGFUNC("kalFirmwareImageMapping"); + + ASSERT(prGlueInfo); + ASSERT(ppvMapFileBuf); + ASSERT(pu4FileLength); + + do { + GL_HIF_INFO_T *prHifInfo = &prGlueInfo->rHifInfo; + prGlueInfo->prFw = NULL; + + /* <1> Open firmware */ + i4Ret = request_firmware(&prGlueInfo->prFw, CFG_FW_FILENAME, &prHifInfo->func->dev); + + if (i4Ret) { + printk (KERN_INFO DRV_NAME"fw %s:request failed %d\n", CFG_FW_FILENAME, i4Ret); + break; + } else { + *pu4FileLength = prGlueInfo->prFw->size; + *ppvMapFileBuf = prGlueInfo->prFw->data; + return prGlueInfo->prFw->data; + } + + } while (FALSE); + + return NULL; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to unload firmware image mapped memory +* +* \param pvGlueInfo Pointer of GLUE Data Structure +* \param pvFwHandle Pointer to mapping handle +* \param pvMapFileBuf Pointer to memory-mapped firmware image +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ + +VOID +kalFirmwareImageUnmapping ( + IN P_GLUE_INFO_T prGlueInfo, + IN PVOID prFwHandle, + IN PVOID pvMapFileBuf + ) +{ + DEBUGFUNC("kalFirmwareImageUnmapping"); + + ASSERT(prGlueInfo); + ASSERT(pvMapFileBuf); + + release_firmware(prGlueInfo->prFw); + +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is provided by GLUE Layer for internal driver stack to acquire +* OS SPIN_LOCK. +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* \param[in] rLockCategory Specify which SPIN_LOCK +* \param[out] pu4Flags Pointer of a variable for saving IRQ flags +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalAcquireSpinLock ( + IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_SPIN_LOCK_CATEGORY_E rLockCategory, + OUT PUINT_32 pu4Flags + ) +{ + UINT_32 u4Flags = 0; + + ASSERT(prGlueInfo); + ASSERT(pu4Flags); + + if (rLockCategory < SPIN_LOCK_NUM) { + +#if CFG_USE_SPIN_LOCK_BOTTOM_HALF + spin_lock_bh(&prGlueInfo->rSpinLock[rLockCategory]); +#else /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ + spin_lock_irqsave(&prGlueInfo->rSpinLock[rLockCategory], u4Flags); +#endif /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ + + *pu4Flags = u4Flags; + } + + return; +} /* end of kalAcquireSpinLock() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is provided by GLUE Layer for internal driver stack to release +* OS SPIN_LOCK. +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* \param[in] rLockCategory Specify which SPIN_LOCK +* \param[in] u4Flags Saved IRQ flags +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalReleaseSpinLock ( + IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_SPIN_LOCK_CATEGORY_E rLockCategory, + IN UINT_32 u4Flags + ) +{ + ASSERT(prGlueInfo); + + if (rLockCategory < SPIN_LOCK_NUM) { + +#if CFG_USE_SPIN_LOCK_BOTTOM_HALF + spin_unlock_bh(&prGlueInfo->rSpinLock[rLockCategory]); +#else /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ + spin_unlock_irqrestore(&prGlueInfo->rSpinLock[rLockCategory], u4Flags); +#endif /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ + + } + + return; +} /* end of kalReleaseSpinLock() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is provided by GLUE Layer for internal driver stack to update +* current MAC address. +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* \param[in] pucMacAddr Pointer of current MAC address +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalUpdateMACAddress ( + IN P_GLUE_INFO_T prGlueInfo, + IN PUINT_8 pucMacAddr + ) +{ + ASSERT(prGlueInfo); + ASSERT(pucMacAddr); + + if(UNEQUAL_MAC_ADDR(prGlueInfo->prDevHandler->dev_addr, pucMacAddr)) { + memcpy(prGlueInfo->prDevHandler->dev_addr, pucMacAddr, PARAM_MAC_ADDR_LEN); + } + + return; +} + + +#if CFG_TCP_IP_CHKSUM_OFFLOAD +/*----------------------------------------------------------------------------*/ +/*! +* \brief To query the packet information for offload related parameters. +* +* \param[in] pvPacket Pointer to the packet descriptor. +* \param[in] pucFlag Points to the offload related parameter. +* +* \return (none) +* +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalQueryTxChksumOffloadParam ( + IN PVOID pvPacket, + OUT PUINT_8 pucFlag + ) +{ + struct sk_buff *skb = (struct sk_buff *) pvPacket; + UINT_8 ucFlag = 0; + + ASSERT(pvPacket); + ASSERT(pucFlag); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) + if (skb->ip_summed == CHECKSUM_HW) +#else + if (skb->ip_summed == CHECKSUM_PARTIAL) +#endif + { + +#if DBG + /* Kevin: do double check, we can remove this part in Normal Driver. + * Because we register NIC feature with NETIF_F_IP_CSUM for MT5912B MAC, so + * we'll process IP packet only. + */ + if (skb->protocol != __constant_htons(ETH_P_IP)) { + //printk("Wrong skb->protocol( = %08x) for TX Checksum Offload.\n", skb->protocol); + } + else +#endif + ucFlag |= (TX_CS_IP_GEN | TX_CS_TCP_UDP_GEN); + } + + *pucFlag = ucFlag; + + return; +} /* kalQueryChksumOffloadParam */ + + +//4 2007/10/8, mikewu, this is rewritten by Mike +/*----------------------------------------------------------------------------*/ +/*! +* \brief To update the checksum offload status to the packet to be indicated to OS. +* +* \param[in] pvPacket Pointer to the packet descriptor. +* \param[in] pucFlag Points to the offload related parameter. +* +* \return (none) +* +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalUpdateRxCSUMOffloadParam ( + IN PVOID pvPacket, + IN ENUM_CSUM_RESULT_T aeCSUM[] + ) +{ + struct sk_buff *skb = (struct sk_buff *)pvPacket; + + ASSERT(pvPacket); + + if ( (aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_SUCCESS || aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_SUCCESS)&& + ( (aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_SUCCESS) || (aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_SUCCESS)) ) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + } + else { + skb->ip_summed = CHECKSUM_NONE; +#if DBG + if (aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_NONE && aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_NONE) { + DBGLOG(RX, TRACE, ("RX: \"non-IPv4/IPv6\" Packet\n")); + } + else if (aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_FAILED) { + DBGLOG(RX, TRACE, ("RX: \"bad IP Checksum\" Packet\n")); + } + else if (aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_FAILED) { + DBGLOG(RX, TRACE, ("RX: \"bad TCP Checksum\" Packet\n")); + } + else if (aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_FAILED) { + DBGLOG(RX, TRACE, ("RX: \"bad UDP Checksum\" Packet\n")); + } + else { + + } +#endif + } + +} /* kalUpdateRxCSUMOffloadParam */ +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called to free packet allocated from kalPacketAlloc. +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* \param[in] pvPacket Pointer of the packet descriptor +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalPacketFree( + IN P_GLUE_INFO_T prGlueInfo, + IN PVOID pvPacket + ) +{ + dev_kfree_skb((struct sk_buff *) pvPacket); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Only handles driver own creating packet (coalescing buffer). +* +* \param prGlueInfo Pointer of GLUE Data Structure +* \param u4Size Pointer of Packet Handle +* \param ppucData Status Code for OS upper layer +* +* \return NULL: Failed to allocate skb, Not NULL get skb +*/ +/*----------------------------------------------------------------------------*/ +PVOID +kalPacketAlloc ( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_32 u4Size, + OUT PUINT_8 *ppucData + ) +{ + struct sk_buff *prSkb = dev_alloc_skb(u4Size); + + if (prSkb) { + *ppucData = (PUINT_8) (prSkb->data); + } +#if DBG +{ + PUINT_32 pu4Head = (PUINT_32)&prSkb->cb[0]; + *pu4Head = (UINT_32)prSkb->head; + DBGLOG(RX, TRACE, ("prSkb->head = %#lx, prSkb->cb = %#lx\n", (UINT_32)prSkb->head, *pu4Head)); +} +#endif + return (PVOID) prSkb; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Process the received packet for indicating to OS. +* +* \param[in] prGlueInfo Pointer to the Adapter structure. +* \param[in] pvPacket Pointer of the packet descriptor +* \param[in] pucPacketStart The starting address of the buffer of Rx packet. +* \param[in] u4PacketLen The packet length. +* \param[in] pfgIsRetain Is the packet to be retained. +* \param[in] aerCSUM The result of TCP/ IP checksum offload. +* +* \retval WLAN_STATUS_SUCCESS. +* \retval WLAN_STATUS_FAILURE. +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +kalProcessRxPacket ( + IN P_GLUE_INFO_T prGlueInfo, + IN PVOID pvPacket, + IN PUINT_8 pucPacketStart, + IN UINT_32 u4PacketLen, + //IN PBOOLEAN pfgIsRetain, + IN BOOLEAN fgIsRetain, + IN ENUM_CSUM_RESULT_T aerCSUM[] + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + struct sk_buff *skb = (struct sk_buff *)pvPacket; + + + skb->data = (unsigned char *)pucPacketStart; + skb->tail = (unsigned char *) ((UINT_32) (pucPacketStart + u4PacketLen)); + skb->len = (unsigned int)u4PacketLen; + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + kalUpdateRxCSUMOffloadParam(skb, aerCSUM); +#endif + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To indicate an array of received packets is available for higher +* level protocol uses. +* +* \param[in] prGlueInfo Pointer to the Adapter structure. +* \param[in] apvPkts The packet array to be indicated +* \param[in] ucPktNum The number of packets to be indicated +* +* \retval TRUE Success. +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +kalRxIndicatePkts ( + IN P_GLUE_INFO_T prGlueInfo, + IN PVOID apvPkts[], + IN UINT_8 ucPktNum + ) +{ + UINT_8 ucIdx = 0; + struct net_device *prNetDev = prGlueInfo->prDevHandler; + struct sk_buff *prSkb = NULL; + + ASSERT(prGlueInfo); + ASSERT(apvPkts); + +#if CFG_BOW_TEST + UINT_32 i; +#endif + + for(ucIdx = 0; ucIdx < ucPktNum; ucIdx++) { + prSkb = apvPkts[ucIdx]; +#if DBG + do { + PUINT_8 pu4Head = (PUINT_8)&prSkb->cb[0]; + UINT_32 u4HeadValue = 0; + kalMemCopy(&u4HeadValue, pu4Head, sizeof(u4HeadValue)); + DBGLOG(RX, TRACE, ("prSkb->head = 0x%p, prSkb->cb = 0x%lx\n", pu4Head, u4HeadValue)); + } while (0); +#endif + + if (GLUE_GET_PKT_IS_P2P(prSkb)) { + /* P2P */ +#if CFG_ENABLE_WIFI_DIRECT + if(prGlueInfo->prAdapter->fgIsP2PRegistered) { + prNetDev = prGlueInfo->prAdapter->rP2pFuncLkr.prKalP2pGetDevHdlr(prGlueInfo); + } +#else + prNetDev = prGlueInfo->prDevHandler; +#endif + } + else if (GLUE_GET_PKT_IS_PAL(prSkb)) { + /* BOW */ +#if CFG_ENABLE_BT_OVER_WIFI && CFG_BOW_SEPARATE_DATA_PATH + if (prGlueInfo->rBowInfo.fgIsNetRegistered) { + prNetDev = prGlueInfo->rBowInfo.prDevHandler; + } +#else + prNetDev = prGlueInfo->prDevHandler; +#endif + } + else { + /* AIS */ + prNetDev = prGlueInfo->prDevHandler; + prGlueInfo->rNetDevStats.rx_bytes += prSkb->len; + prGlueInfo->rNetDevStats.rx_packets++; + + } + + prNetDev->last_rx = jiffies; + prSkb->protocol = eth_type_trans(prSkb, prNetDev); + prSkb->dev = prNetDev; + //DBGLOG_MEM32(RX, TRACE, (PUINT_32)prSkb->data, prSkb->len); + DBGLOG(RX, EVENT, ("kalRxIndicatePkts len = %d\n", prSkb->len)); + +#if CFG_BOW_TEST + DBGLOG(BOW, TRACE, ("Rx sk_buff->len: %d\n", prSkb->len)); + DBGLOG(BOW, TRACE, ("Rx sk_buff->data_len: %d\n", prSkb->data_len)); + DBGLOG(BOW, TRACE, ("Rx sk_buff->data:\n")); + + for(i = 0; i < prSkb->len; i++) + { + DBGLOG(BOW, TRACE, ("%4x", prSkb->data[i])); + + if((i+1)%16 ==0) + { + DBGLOG(BOW, TRACE, ("\n")); + } + } + + DBGLOG(BOW, TRACE, ("\n")); +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) + if(!in_interrupt()){ + netif_rx_ni(prSkb); /* only in non-interrupt context */ + } + else { + netif_rx(prSkb); + } +#else + netif_rx(prSkb); +#endif + + wlanReturnPacket(prGlueInfo->prAdapter, NULL); + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Called by driver to indicate event to upper layer, for example, the wpa +* supplicant or wireless tools. +* +* \param[in] pvAdapter Pointer to the adapter descriptor. +* \param[in] eStatus Indicated status. +* \param[in] pvBuf Indicated message buffer. +* \param[in] u4BufLen Indicated message buffer size. +* +* \return (none) +* +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalIndicateStatusAndComplete ( + IN P_GLUE_INFO_T prGlueInfo, + IN WLAN_STATUS eStatus, + IN PVOID pvBuf, + IN UINT_32 u4BufLen + ) +{ + UINT_32 bufLen; + P_PARAM_STATUS_INDICATION_T pStatus = (P_PARAM_STATUS_INDICATION_T) pvBuf; + P_PARAM_AUTH_EVENT_T pAuth = (P_PARAM_AUTH_EVENT_T) pStatus; + P_PARAM_PMKID_CANDIDATE_LIST_T pPmkid = + (P_PARAM_PMKID_CANDIDATE_LIST_T) (pStatus + 1); + PARAM_MAC_ADDRESS arBssid; + + kalMemZero(arBssid, MAC_ADDR_LEN); + + ASSERT(prGlueInfo); + + + switch (eStatus) { + case WLAN_STATUS_MEDIA_CONNECT: + + prGlueInfo->eParamMediaStateIndicated = PARAM_MEDIA_STATE_CONNECTED; + + /* indicate assoc event */ + wlanQueryInformation(prGlueInfo->prAdapter, + wlanoidQueryBssid, + &arBssid[0], + sizeof(arBssid), + &bufLen); + wext_indicate_wext_event(prGlueInfo, SIOCGIWAP, arBssid, bufLen); + + /* switch netif on */ + netif_carrier_on(prGlueInfo->prDevHandler); + + do { + /* print message on console */ + PARAM_SSID_T ssid; + + wlanQueryInformation(prGlueInfo->prAdapter, + wlanoidQuerySsid, + &ssid, + sizeof(ssid), + &bufLen); + + ssid.aucSsid[(ssid.u4SsidLen >= PARAM_MAX_LEN_SSID) ? + (PARAM_MAX_LEN_SSID - 1) : ssid.u4SsidLen ] = '\0'; + DBGLOG(INIT, INFO, ("[wifi] %s netif_carrier_on [ssid:%s " MACSTR "]\n", + prGlueInfo->prDevHandler->name, + ssid.aucSsid, + MAC2STR(arBssid))); + } while(0); + break; + + case WLAN_STATUS_MEDIA_DISCONNECT: + /* indicate disassoc event */ + wext_indicate_wext_event(prGlueInfo, SIOCGIWAP, NULL, 0); + /* For CR 90 and CR99, While supplicant do reassociate, driver will do netif_carrier_off first, + after associated success, at joinComplete(), do netif_carier_on, + but for unknown reason, the supplicant 1x pkt will not called the driver + hardStartXmit, for template workaround these bugs, add this compiling flag + */ + /* switch netif off */ + +#if 1 /* CONSOLE_MESSAGE */ + DBGLOG(INIT, INFO, ("[wifi] %s netif_carrier_off\n", prGlueInfo->prDevHandler->name)); +#endif + + netif_carrier_off(prGlueInfo->prDevHandler); + + prGlueInfo->eParamMediaStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED; + + break; + + case WLAN_STATUS_SCAN_COMPLETE: + /* indicate scan complete event */ + wext_indicate_wext_event(prGlueInfo, SIOCGIWSCAN, NULL, 0); + break; + + #if 0 + case WLAN_STATUS_MSDU_OK: + if (netif_running(prGlueInfo->prDevHandler)) { + netif_wake_queue(prGlueInfo->prDevHandler); + } + break; + #endif + + case WLAN_STATUS_MEDIA_SPECIFIC_INDICATION: + if (pStatus) { + switch (pStatus->eStatusType) { + case ENUM_STATUS_TYPE_AUTHENTICATION: + /* + printk(KERN_NOTICE "ENUM_STATUS_TYPE_AUTHENTICATION: L(%ld) [" MACSTR "] F:%lx\n", + pAuth->Request[0].Length, + MAC2STR(pAuth->Request[0].Bssid), + pAuth->Request[0].Flags); + */ + /* indicate (UC/GC) MIC ERROR event only */ + if ((pAuth->arRequest[0].u4Flags == + PARAM_AUTH_REQUEST_PAIRWISE_ERROR) || + (pAuth->arRequest[0].u4Flags == + PARAM_AUTH_REQUEST_GROUP_ERROR)) { + wext_indicate_wext_event(prGlueInfo, + IWEVMICHAELMICFAILURE, + (unsigned char *)&pAuth->arRequest[0], + pAuth->arRequest[0].u4Length); + } + break; + + case ENUM_STATUS_TYPE_CANDIDATE_LIST: + /* + printk(KERN_NOTICE "Param_StatusType_PMKID_CandidateList: Ver(%ld) Num(%ld)\n", + pPmkid->u2Version, + pPmkid->u4NumCandidates); + if (pPmkid->u4NumCandidates > 0) { + printk(KERN_NOTICE "candidate[" MACSTR "] preAuth Flag:%lx\n", + MAC2STR(pPmkid->arCandidateList[0].rBSSID), + pPmkid->arCandidateList[0].fgFlags); + } + */ + { + UINT_32 i = 0; + + P_PARAM_PMKID_CANDIDATE_T prPmkidCand = (P_PARAM_PMKID_CANDIDATE_T)&pPmkid->arCandidateList[0]; + + for (i=0; iu4NumCandidates; i++) { + wext_indicate_wext_event(prGlueInfo, + IWEVPMKIDCAND, + (unsigned char *)&pPmkid->arCandidateList[i], + pPmkid->u4NumCandidates); + prPmkidCand += sizeof(PARAM_PMKID_CANDIDATE_T); + } + } + break; + + default: + /* case ENUM_STATUS_TYPE_MEDIA_STREAM_MODE */ + /* + printk(KERN_NOTICE "unknown media specific indication type:%x\n", + pStatus->StatusType); + */ + break; + } + } + else { + /* + printk(KERN_WARNING "media specific indication buffer NULL\n"); + */ + } + break; + +#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS + case WLAN_STATUS_BWCS_UPDATE: + { + wext_indicate_wext_event(prGlueInfo, IWEVCUSTOM, pvBuf, sizeof(PTA_IPC_T)); + } + + break; + +#endif + + default: + /* + printk(KERN_WARNING "unknown indication:%lx\n", eStatus); + */ + break; + } +} /* kalIndicateStatusAndComplete */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to update the (re)association request +* information to the structure used to query and set +* OID_802_11_ASSOCIATION_INFORMATION. +* +* \param[in] prGlueInfo Pointer to the Glue structure. +* \param[in] pucFrameBody Pointer to the frame body of the last (Re)Association +* Request frame from the AP. +* \param[in] u4FrameBodyLen The length of the frame body of the last +* (Re)Association Request frame. +* \param[in] fgReassocRequest TRUE, if it is a Reassociation Request frame. +* +* \return (none) +* +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalUpdateReAssocReqInfo ( + IN P_GLUE_INFO_T prGlueInfo, + IN PUINT_8 pucFrameBody, + IN UINT_32 u4FrameBodyLen, + IN BOOLEAN fgReassocRequest + ) +{ + PUINT_8 cp; + + if (fgReassocRequest) { + if (u4FrameBodyLen < 15) { + /* + printk(KERN_WARNING "frameBodyLen too short:%ld\n", frameBodyLen); + */ + return; + } + } + else { + if (u4FrameBodyLen < 9) { + /* + printk(KERN_WARNING "frameBodyLen too short:%ld\n", frameBodyLen); + */ + return; + } + } + + cp = pucFrameBody; + + if (fgReassocRequest) { + /* Capability information field 2 */ + /* Listen interval field 2*/ + /* Current AP address 6 */ + cp += 10; + u4FrameBodyLen -= 10; + } + else { + /* Capability information field 2 */ + /* Listen interval field 2*/ + cp += 4; + u4FrameBodyLen -= 4; + } + + wext_indicate_wext_event(prGlueInfo, IWEVASSOCREQIE, cp, u4FrameBodyLen); + return; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Notify OS with SendComplete event of the specific packet. Linux should +* free packets here. +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* \param[in] pvPacket Pointer of Packet Handle +* \param[in] status Status Code for OS upper layer +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalSendCompleteAndAwakeQueue ( + IN P_GLUE_INFO_T prGlueInfo, + IN PVOID pvPacket + ) +{ + + struct net_device *prDev = NULL; + struct sk_buff *prSkb = NULL; + UINT_16 u2QueueIdx = 0; + UINT_8 ucNetworkType = 0; + BOOLEAN fgIsValidDevice = TRUE; + + + ASSERT(pvPacket); + ASSERT(prGlueInfo->i4TxPendingFrameNum); + + prSkb = (struct sk_buff *) pvPacket; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 26) + u2QueueIdx = skb_get_queue_mapping(prSkb); +#endif + ASSERT(u2QueueIdx < CFG_MAX_TXQ_NUM); + + if (GLUE_GET_PKT_IS_PAL(prSkb)) { + ucNetworkType = NETWORK_TYPE_BOW_INDEX; + } else if (GLUE_GET_PKT_IS_P2P(prSkb)) { + ucNetworkType = NETWORK_TYPE_P2P_INDEX; + +#if CFG_ENABLE_WIFI_DIRECT + /* in case packet was sent after P2P device is unregistered */ + if(prGlueInfo->prAdapter->fgIsP2PRegistered == FALSE) { + fgIsValidDevice = FALSE; + } +#endif + } else { + ucNetworkType = NETWORK_TYPE_AIS_INDEX; + } + + GLUE_DEC_REF_CNT(prGlueInfo->i4TxPendingFrameNum); + GLUE_DEC_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[ucNetworkType][u2QueueIdx]); + prDev = prSkb->dev; + + ASSERT(prDev); + + if(fgIsValidDevice == TRUE) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 26) + if (netif_subqueue_stopped(prDev, prSkb) && + prGlueInfo->ai4TxPendingFrameNumPerQueue[ucNetworkType][u2QueueIdx] <= CFG_TX_START_NETIF_PER_QUEUE_THRESHOLD) { + netif_wake_subqueue(prDev, u2QueueIdx); + } +#else + if (prGlueInfo->i4TxPendingFrameNum < CFG_TX_STOP_NETIF_QUEUE_THRESHOLD) { + netif_wake_queue(prGlueInfo->prDevHandler); + } +#endif + } + + + dev_kfree_skb((struct sk_buff *) pvPacket); + + DBGLOG(TX, EVENT, ("----- pending frame %d -----\n", prGlueInfo->i4TxPendingFrameNum)); + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Copy Mac Address setting from registry. It's All Zeros in Linux. +* +* \param[in] prAdapter Pointer to the Adapter structure +* +* \param[out] paucMacAddr Pointer to the Mac Address buffer +* +* \retval WLAN_STATUS_SUCCESS +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalQueryRegistryMacAddr ( + IN P_GLUE_INFO_T prGlueInfo, + OUT PUINT_8 paucMacAddr + ) +{ + UINT_8 aucZeroMac[MAC_ADDR_LEN] = {0,0,0,0,0,0} + DEBUGFUNC("kalQueryRegistryMacAddr"); + + ASSERT(prGlueInfo); + ASSERT(paucMacAddr); + + kalMemCopy((PVOID) paucMacAddr, (PVOID)aucZeroMac, MAC_ADDR_LEN); + + return; +} /* end of kalQueryRegistryMacAddr() */ + +#if CFG_SUPPORT_EXT_CONFIG +/*----------------------------------------------------------------------------*/ +/*! +* \brief Read external configuration, ex. NVRAM or file +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 +kalReadExtCfg ( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + ASSERT(prGlueInfo); + + /* External data is given from user space by ioctl or /proc, not read by + driver. + */ + if (0 != prGlueInfo->u4ExtCfgLength) { + DBGLOG(INIT, TRACE, ("Read external configuration data -- OK\n")); + } + else { + DBGLOG(INIT, TRACE, ("Read external configuration data -- fail\n")); + } + + return prGlueInfo->u4ExtCfgLength; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This inline function is to extract some packet information, including +* user priority, packet length, destination address, 802.1x and BT over Wi-Fi +* or not. +* +* @param prGlueInfo Pointer to the glue structure +* @param prNdisPacket Packet descriptor +* @param pucPriorityParam User priority +* @param pu4PacketLen Packet length +* @param pucEthDestAddr Destination address +* @param pfgIs1X 802.1x packet or not +* @param pfgIsPAL BT over Wi-Fi packet or not +* +* @retval TRUE Success to extract information +* @retval FALSE Fail to extract correct information +*/ +/*----------------------------------------------------------------------------*/ + +BOOL +kalQoSFrameClassifierAndPacketInfo ( + IN P_GLUE_INFO_T prGlueInfo, + IN P_NATIVE_PACKET prPacket, + OUT PUINT_8 pucPriorityParam, + OUT PUINT_32 pu4PacketLen, + OUT PUINT_8 pucEthDestAddr, + OUT PBOOLEAN pfgIs1X, + OUT PBOOLEAN pfgIsPAL, + OUT PUINT_8 pucNetworkType + ) +{ + + UINT_32 u4PacketLen; + + + UINT_8 ucUserPriority = USER_PRIORITY_DEFAULT; /* Default */ + UINT_16 u2EtherTypeLen; + struct sk_buff *prSkb = (struct sk_buff *) prPacket; + PUINT_8 aucLookAheadBuf = NULL; + + DEBUGFUNC("kalQoSFrameClassifierAndPacketInfo"); + + u4PacketLen = prSkb->len; + + if (u4PacketLen < ETH_HLEN) { + DBGLOG(INIT, WARN, ("Invalid Ether packet length: %d\n", u4PacketLen)); + return FALSE; + } + + aucLookAheadBuf = prSkb->data; + + *pfgIs1X = FALSE; + *pfgIsPAL = FALSE; + //4 <3> Obtain the User Priority for WMM + u2EtherTypeLen = (aucLookAheadBuf[ETH_TYPE_LEN_OFFSET] << 8) | (aucLookAheadBuf[ETH_TYPE_LEN_OFFSET + 1]); + + if ((u2EtherTypeLen == ETH_P_IP) && + (u4PacketLen >= LOOK_AHEAD_LEN)) { + PUINT_8 pucIpHdr = &aucLookAheadBuf[ETH_HLEN]; + UINT_8 ucIpVersion; + + ucIpVersion = (pucIpHdr[0] & IPVH_VERSION_MASK) >> IPVH_VERSION_OFFSET; + //printk ("ip version %x\n", ucIpVersion); + if (ucIpVersion == IPVERSION) { + UINT_8 ucIpTos; + /* Get the DSCP value from the header of IP packet. */ + ucIpTos = pucIpHdr[1]; + ucUserPriority = ((ucIpTos & IPTOS_PREC_MASK) >> IPTOS_PREC_OFFSET); + } + + /* TODO(Kevin): Add TSPEC classifier here */ + } + else if (u2EtherTypeLen == ETH_P_1X) { /* For Port Control */ + //DBGLOG(REQ, TRACE, ("Tx 1x\n")); + *pfgIs1X = TRUE; + } + else if (u2EtherTypeLen == ETH_P_PRE_1X) { /* For Pre 1x pkt */ + //DBGLOG(REQ, TRACE, ("Tx Pre-1x\n")); + *pfgIs1X = TRUE; + } +#if CFG_SUPPORT_WAPI + else if (u2EtherTypeLen == ETH_WPI_1X) { + *pfgIs1X = TRUE; + } +#endif + else if (u2EtherTypeLen <= 1500) { /* 802.3 Frame */ + UINT_8 ucDSAP, ucSSAP, ucControl; + UINT_8 aucOUI[3]; + + ucDSAP = *(PUINT_8) &aucLookAheadBuf[ETH_LLC_OFFSET]; + ucSSAP = *(PUINT_8) &aucLookAheadBuf[ETH_LLC_OFFSET + 1]; + ucControl = *(PUINT_8) &aucLookAheadBuf[ETH_LLC_OFFSET + 2]; + + aucOUI[0] = *(PUINT_8) &aucLookAheadBuf[ETH_SNAP_OFFSET]; + aucOUI[1] = *(PUINT_8) &aucLookAheadBuf[ETH_SNAP_OFFSET + 1]; + aucOUI[2] = *(PUINT_8) &aucLookAheadBuf[ETH_SNAP_OFFSET + 2]; + + if(ucDSAP == ETH_LLC_DSAP_SNAP && + ucSSAP == ETH_LLC_SSAP_SNAP && + ucControl == ETH_LLC_CONTROL_UNNUMBERED_INFORMATION && + aucOUI[0] == ETH_SNAP_BT_SIG_OUI_0 && + aucOUI[1] == ETH_SNAP_BT_SIG_OUI_1 && + aucOUI[2] == ETH_SNAP_BT_SIG_OUI_2) { + + UINT_16 tmp = ((aucLookAheadBuf[ETH_SNAP_OFFSET + 3] << 8) | aucLookAheadBuf[ETH_SNAP_OFFSET + 4]); + + *pfgIsPAL = TRUE; + ucUserPriority = (UINT_8)prSkb->priority; + + if (tmp == BOW_PROTOCOL_ID_SECURITY_FRAME) { + *pfgIs1X = TRUE; + } + } + } + + //4 <4> Return the value of Priority Parameter. + *pucPriorityParam = ucUserPriority; + + //4 <5> Retrieve Packet Information - DA + /* Packet Length/ Destination Address */ + *pu4PacketLen = u4PacketLen; + + kalMemCopy(pucEthDestAddr, aucLookAheadBuf, PARAM_MAC_ADDR_LEN); + + + //<6> Network type +#if CFG_ENABLE_BT_OVER_WIFI + if(*pfgIsPAL == TRUE) { + *pucNetworkType = NETWORK_TYPE_BOW_INDEX; + } + else +#endif + { +#if CFG_ENABLE_WIFI_DIRECT + if(prGlueInfo->prAdapter->fgIsP2PRegistered && GLUE_GET_PKT_IS_P2P(prPacket)) { + *pucNetworkType = NETWORK_TYPE_P2P_INDEX; + } + else +#endif + { + *pucNetworkType = NETWORK_TYPE_AIS_INDEX; + } + } + return TRUE; +} /* end of kalQoSFrameClassifier() */ + +VOID +kalOidComplete ( + IN P_GLUE_INFO_T prGlueInfo, + IN BOOLEAN fgSetQuery, + IN UINT_32 u4SetQueryInfoLen, + IN WLAN_STATUS rOidStatus + ) +{ + + /* remove timeout check timer */ + wlanoidClearTimeoutCheck(prGlueInfo->prAdapter); + + ASSERT(prGlueInfo); + //if (prGlueInfo->u4TimeoutFlag != 1) { + prGlueInfo->rPendStatus = rOidStatus; + complete(&prGlueInfo->rPendComp); + //} + /* else let it timeout on kalIoctl entry */ +} + +VOID +kalOidClearance( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + //if (prGlueInfo->u4TimeoutFlag != 1) { + clear_bit(GLUE_FLAG_OID_BIT, &prGlueInfo->u4Flag); + complete(&prGlueInfo->rPendComp); + //} +} + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to transfer linux ioctl to OID, and we +* need to specify the behavior of the OID by ourself +* +* @param prGlueInfo Pointer to the glue structure +* @param pvInfoBuf Data buffer +* @param u4InfoBufLen Data buffer length +* @param fgRead Is this a read OID +* @param fgWaitResp does this OID need to wait for values +* @param fgCmd does this OID compose command packet +* @param pu4QryInfoLen The data length of the return values +* +* @retval TRUE Success to extract information +* @retval FALSE Fail to extract correct information +*/ +/*----------------------------------------------------------------------------*/ + +// todo: enqueue the i/o requests for multiple processes access +// +// currently, return -1 +// + +//static GL_IO_REQ_T OidEntry; + +WLAN_STATUS +kalIoctl (IN P_GLUE_INFO_T prGlueInfo, + IN PFN_OID_HANDLER_FUNC pfnOidHandler, + IN PVOID pvInfoBuf, + IN UINT_32 u4InfoBufLen, + IN BOOL fgRead, + IN BOOL fgWaitResp, + IN BOOL fgCmd, + IN BOOL fgIsP2pOid, + OUT PUINT_32 pu4QryInfoLen + ) +{ + P_GL_IO_REQ_T prIoReq = NULL; + WLAN_STATUS ret = WLAN_STATUS_SUCCESS; + + //GLUE_SPIN_LOCK_DECLARATION(); + ASSERT(prGlueInfo); + + /* <1> Check if driver is halt */ + + //if (prGlueInfo->u4Flag & GLUE_FLAG_HALT) { + // return WLAN_STATUS_ADAPTER_NOT_READY; + //} + + if (down_interruptible(&g_halt_sem)) { + return WLAN_STATUS_FAILURE; + } + + + if (g_u4HaltFlag) { + up(&g_halt_sem); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + if(down_interruptible(&prGlueInfo->ioctl_sem)) { + up(&g_halt_sem); + return WLAN_STATUS_FAILURE; + } + + /* <2> TODO: thread-safe */ + + /* <3> point to the OidEntry of Glue layer */ + + prIoReq = &(prGlueInfo->OidEntry); + + ASSERT(prIoReq); + + /* <4> Compose the I/O request */ + prIoReq->prAdapter = prGlueInfo->prAdapter; + prIoReq->pfnOidHandler = pfnOidHandler; + prIoReq->pvInfoBuf = pvInfoBuf; + prIoReq->u4InfoBufLen = u4InfoBufLen; + prIoReq->pu4QryInfoLen = pu4QryInfoLen; + prIoReq->fgRead = fgRead; + prIoReq->fgWaitResp= fgWaitResp; + prIoReq->rStatus = WLAN_STATUS_FAILURE; +#if CFG_ENABLE_WIFI_DIRECT + prIoReq->fgIsP2pOid = fgIsP2pOid; +#endif + + /* <5> Reset the status of pending OID */ + prGlueInfo->rPendStatus = WLAN_STATUS_FAILURE; + //prGlueInfo->u4TimeoutFlag = 0; + + /* <6> Check if we use the command queue */ + prIoReq->u4Flag = fgCmd; + + /* <7> schedule the OID bit */ + set_bit(GLUE_FLAG_OID_BIT, &prGlueInfo->u4Flag); + + /* <8> Wake up tx thread to handle kick start the I/O request */ + wake_up_interruptible(&prGlueInfo->waitq); + + /* <9> Block and wait for event or timeout, current the timeout is 5 secs */ + //if (wait_for_completion_interruptible_timeout(&prGlueInfo->rPendComp, 5 * KAL_HZ)) { + //if (!wait_for_completion_interruptible(&prGlueInfo->rPendComp)) { + wait_for_completion(&prGlueInfo->rPendComp); { + /* Case 1: No timeout. */ + /* if return WLAN_STATUS_PENDING, the status of cmd is stored in prGlueInfo */ + if (prIoReq->rStatus == WLAN_STATUS_PENDING) { + ret = prGlueInfo->rPendStatus; + } else { + ret = prIoReq->rStatus; + } + } + #if 0 + else { + /* Case 2: timeout */ + /* clear pending OID's cmd in CMD queue */ + if (fgCmd) { + prGlueInfo->u4TimeoutFlag = 1; + wlanReleasePendingOid(prGlueInfo->prAdapter, 0); + } + ret = WLAN_STATUS_FAILURE; + } + #endif + + up(&prGlueInfo->ioctl_sem); + up(&g_halt_sem); + + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to clear all pending security frames +* +* \param prGlueInfo Pointer of GLUE Data Structure +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalClearSecurityFrames( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + P_QUE_T prCmdQue; + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T)NULL; + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prGlueInfo); + + // Clear pending security frames in prGlueInfo->rCmdQueue + prCmdQue = &prGlueInfo->rCmdQueue; + + + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + + if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME) { + prCmdInfo->pfCmdTimeoutHandler(prGlueInfo->prAdapter, prCmdInfo); + cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); + } + else { + QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); + } + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + + QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to clear pending security frames +* belongs to dedicated network type +* +* \param prGlueInfo Pointer of GLUE Data Structure +* \param eNetworkTypeIdx Network Type Index +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalClearSecurityFramesByNetType( + IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx + ) +{ + P_QUE_T prCmdQue; + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T)NULL; + GLUE_SPIN_LOCK_DECLARATION(); + + + ASSERT(prGlueInfo); + + // Clear pending security frames in prGlueInfo->rCmdQueue + prCmdQue = &prGlueInfo->rCmdQueue; + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + + if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME && + prCmdInfo->eNetworkType == eNetworkTypeIdx) { + prCmdInfo->pfCmdTimeoutHandler(prGlueInfo->prAdapter, prCmdInfo); + cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); + } + else { + QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); + } + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + + QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to clear all pending management frames +* +* \param prGlueInfo Pointer of GLUE Data Structure +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalClearMgmtFrames( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + P_QUE_T prCmdQue; + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T)NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prGlueInfo); + + // Clear pending management frames in prGlueInfo->rCmdQueue + prCmdQue = &prGlueInfo->rCmdQueue; + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + + if (prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME) { + wlanReleaseCommand(prGlueInfo->prAdapter, prCmdInfo); + cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); + } + else { + QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); + } + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + + QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to clear all pending management frames +* belongs to dedicated network type +* \param prGlueInfo Pointer of GLUE Data Structure +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalClearMgmtFramesByNetType( + IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx + ) +{ + P_QUE_T prCmdQue; + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T)NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prGlueInfo); + + // Clear pending management frames in prGlueInfo->rCmdQueue + prCmdQue = &prGlueInfo->rCmdQueue; + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + + if (prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME && + prCmdInfo->eNetworkType == eNetworkTypeIdx) { + wlanReleaseCommand(prGlueInfo->prAdapter, prCmdInfo); + cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); + } + else { + QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); + } + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + + QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); +} + + + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is a kernel thread function for handling command packets +* Tx requests and interrupt events +* +* @param data data pointer to private data of tx_thread +* +* @retval If the function succeeds, the return value is 0. +* Otherwise, an error code is returned. +* +*/ +/*----------------------------------------------------------------------------*/ + +int tx_thread(void *data) +{ + struct net_device *dev = data; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) netdev_priv(dev); + + P_QUE_ENTRY_T prQueueEntry = NULL; + P_GL_IO_REQ_T prIoReq = NULL; + P_QUE_T prTxQueue = NULL; + P_QUE_T prCmdQue = NULL; + + int ret = 0; + + BOOLEAN fgNeedHwAccess = FALSE; + + struct sk_buff *prSkb = NULL; + + /* for spin lock acquire and release */ + GLUE_SPIN_LOCK_DECLARATION(); + + prTxQueue = &prGlueInfo->rTxQueue; + prCmdQue = &prGlueInfo->rCmdQueue; + + current->flags |= PF_NOFREEZE; + + DBGLOG(INIT, INFO, ("tx_thread starts running... \n")); + + while (TRUE) { + +#if CFG_ENABLE_WIFI_DIRECT + /*run sub mod init*/ + if (test_and_clear_bit(GLUE_FLAG_SUB_MOD_INIT_BIT, &prGlueInfo->u4Flag)) { + wlanSubModRunInit(prGlueInfo); + complete(&prGlueInfo->rSubModComp); + } + /*run sub mod exit*/ + if (test_and_clear_bit(GLUE_FLAG_SUB_MOD_EXIT_BIT, &prGlueInfo->u4Flag)) { + wlanSubModRunExit(prGlueInfo); + complete(&prGlueInfo->rSubModComp); + } + + /*run p2p multicast list work. */ + if (test_and_clear_bit(GLUE_FLAG_SUB_MOD_MULTICAST_BIT, &prGlueInfo->u4Flag)) { + p2pSetMulticastListWorkQueueWrapper(prGlueInfo); + } + + +#endif + + if (prGlueInfo->u4Flag & GLUE_FLAG_HALT) { + DBGLOG(INIT, INFO, ("tx_thread should stop now...\n")); + break; + } + + /* + * sleep on waitqueue if no events occurred. Event contain (1) GLUE_FLAG_INT + * (2) GLUE_FLAG_OID (3) GLUE_FLAG_TXREQ (4) GLUE_FLAG_HALT + * + */ + + ret = wait_event_interruptible(prGlueInfo->waitq, + (prGlueInfo->u4Flag != 0)); + +#if CFG_DBG_GPIO_PINS + /* TX thread Wake up */ + mtk_wcn_stp_debug_gpio_assert(IDX_TX_THREAD, DBG_TIE_LOW); +#endif +#if CFG_ENABLE_WIFI_DIRECT + /*run sub mod init*/ + if (test_and_clear_bit(GLUE_FLAG_SUB_MOD_INIT_BIT, &prGlueInfo->u4Flag)) { + wlanSubModRunInit(prGlueInfo); + complete(&prGlueInfo->rSubModComp); + } + /*run sub mod exit*/ + if (test_and_clear_bit(GLUE_FLAG_SUB_MOD_EXIT_BIT, &prGlueInfo->u4Flag)) { + wlanSubModRunExit(prGlueInfo); + complete(&prGlueInfo->rSubModComp); + } +#endif + if (prGlueInfo->u4Flag & GLUE_FLAG_HALT) { + DBGLOG(INIT, INFO, ("<1>tx_thread should stop now...\n")); + break; + } + + fgNeedHwAccess = FALSE; + + /* Handle Interrupt */ + if (test_and_clear_bit(GLUE_FLAG_INT_BIT, &prGlueInfo->u4Flag)) { + + if (fgNeedHwAccess == FALSE) { + fgNeedHwAccess = TRUE; + + wlanAcquirePowerControl(prGlueInfo->prAdapter); + } + + /* the Wi-Fi interrupt is already disabled in mmc thread, + so we set the flag only to enable the interrupt later */ + prGlueInfo->prAdapter->fgIsIntEnable = FALSE; + //wlanISR(prGlueInfo->prAdapter, TRUE); + + if (prGlueInfo->u4Flag & GLUE_FLAG_HALT) { + /* Should stop now... skip pending interrupt */ + DBGLOG(INIT, INFO, ("ignore pending interrupt\n")); + } + else { + + wlanIST(prGlueInfo->prAdapter); + } + } + + /* transfer ioctl to OID request */ + #if 0 + if (prGlueInfo->u4Flag & GLUE_FLAG_HALT) { + printk(KERN_INFO DRV_NAME"<2>tx_thread should stop now...\n"); + break; + } + #endif + + do { + if (test_and_clear_bit(GLUE_FLAG_OID_BIT, &prGlueInfo->u4Flag)) { + /* get current prIoReq */ + prIoReq = &(prGlueInfo->OidEntry); +#if CFG_ENABLE_WIFI_DIRECT + if(prGlueInfo->prAdapter->fgIsP2PRegistered == FALSE + && prIoReq->fgIsP2pOid == TRUE) { + /* if this Oid belongs to p2p and p2p module is removed + * do nothing, + */ + } + else +#endif + { + if (FALSE == prIoReq->fgRead) { + prIoReq->rStatus = wlanSetInformation( + prIoReq->prAdapter, + prIoReq->pfnOidHandler, + prIoReq->pvInfoBuf, + prIoReq->u4InfoBufLen, + prIoReq->pu4QryInfoLen); + } else { + prIoReq->rStatus = wlanQueryInformation( + prIoReq->prAdapter, + prIoReq->pfnOidHandler, + prIoReq->pvInfoBuf, + prIoReq->u4InfoBufLen, + prIoReq->pu4QryInfoLen); + } + + if (prIoReq->rStatus != WLAN_STATUS_PENDING) { + complete(&prGlueInfo->rPendComp); + } else { + wlanoidTimeoutCheck(prGlueInfo->prAdapter, prIoReq->pfnOidHandler); + } + } + } + + } while (FALSE); + + + /* + * + * if TX request, clear the TXREQ flag. TXREQ set by kalSetEvent/GlueSetEvent + * indicates the following requests occur + * + */ + #if 0 + if (prGlueInfo->u4Flag & GLUE_FLAG_HALT) { + printk(KERN_INFO DRV_NAME"<3>tx_thread should stop now...\n"); + break; + } + #endif + + if (test_and_clear_bit(GLUE_FLAG_TXREQ_BIT, &prGlueInfo->u4Flag)) + { + + /* Process Mailbox Messages */ + wlanProcessMboxMessage(prGlueInfo->prAdapter); + + /* Process CMD request */ + do { + if (prCmdQue->u4NumElem > 0) { + if (fgNeedHwAccess == FALSE) { + fgNeedHwAccess = TRUE; + + wlanAcquirePowerControl(prGlueInfo->prAdapter); + } + wlanProcessCommandQueue(prGlueInfo->prAdapter, prCmdQue); + } + } while (FALSE); + + /* Handle Packet Tx */ + { + while (QUEUE_IS_NOT_EMPTY(prTxQueue)) { + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + QUEUE_REMOVE_HEAD(prTxQueue, prQueueEntry, P_QUE_ENTRY_T); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + + ASSERT(prQueueEntry); + if (NULL == prQueueEntry) { + break; + } + + prSkb = (struct sk_buff *) GLUE_GET_PKT_DESCRIPTOR(prQueueEntry); + ASSERT(prSkb); + if (NULL == prSkb) { + DBGLOG(INIT, WARN, ("prSkb == NULL in tx\n")); + continue; + } + + if(wlanEnqueueTxPacket(prGlueInfo->prAdapter, + (P_NATIVE_PACKET)prSkb) == WLAN_STATUS_RESOURCES) { + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + QUEUE_INSERT_HEAD(prTxQueue, prQueueEntry); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + + break; + } + } + + if (wlanGetTxPendingFrameCount(prGlueInfo->prAdapter) > 0) { + wlanTxPendingPackets(prGlueInfo->prAdapter, &fgNeedHwAccess); + } + } + + } + + /* Process RX, In linux, we don't need to free sk_buff by ourself */ + + /* In linux, we don't need to free sk_buff by ourself */ + + /* In linux, we don't do reset */ + if (fgNeedHwAccess == TRUE) { + wlanReleasePowerControl(prGlueInfo->prAdapter); + } + + /* handle cnmTimer time out */ + if (test_and_clear_bit(GLUE_FLAG_TIMEOUT_BIT, &prGlueInfo->u4Flag)) { + wlanTimerTimeoutCheck(prGlueInfo->prAdapter); + } + + #if CFG_DBG_GPIO_PINS + /* TX thread go to sleep */ + if (!prGlueInfo->u4Flag){ + mtk_wcn_stp_debug_gpio_assert(IDX_TX_THREAD, DBG_TIE_HIGH); + } + #endif + } + + #if 0 + if (fgNeedHwAccess == TRUE) { + wlanReleasePowerControl(prGlueInfo->prAdapter); + } + #endif + + /* flush the pending TX packets */ + if (prGlueInfo->i4TxPendingFrameNum > 0) { + kalFlushPendingTxPackets(prGlueInfo); + } + + /* flush pending security frames */ + if (prGlueInfo->i4TxPendingSecurityFrameNum > 0) { + kalClearSecurityFrames(prGlueInfo); + } + + /* remove pending oid */ + wlanReleasePendingOid(prGlueInfo->prAdapter, 0); + + + /* In linux, we don't need to free sk_buff by ourself */ + + DBGLOG(INIT, INFO, ("mtk_sdiod stops\n")); + complete(&prGlueInfo->rHaltComp); + + return 0; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to check if card is removed +* +* \param pvGlueInfo Pointer of GLUE Data Structure +* +* \retval TRUE: card is removed +* FALSE: card is still attached +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +kalIsCardRemoved( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + ASSERT(prGlueInfo); + + return FALSE; + // Linux MMC doesn't have removal notification yet +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to send command to firmware for overriding netweork address + * + * \param pvGlueInfo Pointer of GLUE Data Structure + + * \retval TRUE + * FALSE + */ +/*----------------------------------------------------------------------------*/ +BOOLEAN +kalRetrieveNetworkAddress( + IN P_GLUE_INFO_T prGlueInfo, + IN OUT PARAM_MAC_ADDRESS * prMacAddr + ) +{ + ASSERT(prGlueInfo); + + if(prGlueInfo->fgIsMacAddrOverride == FALSE) { + #if !defined(CONFIG_X86) + UINT_32 i; + BOOLEAN fgIsReadError = FALSE; + + for(i = 0 ; i < MAC_ADDR_LEN ; i+=2) { + if(kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucMacAddress) + i, + (PUINT_16) (((PUINT_8)prMacAddr) + i)) == FALSE) { + fgIsReadError = TRUE; + break; + } + } + + if(fgIsReadError == TRUE) { + return FALSE; + } + else { + return TRUE; + } + #else + /* x86 Linux doesn't need to override network address so far */ + return FALSE; + #endif + } + else { + COPY_MAC_ADDR(prMacAddr, prGlueInfo->rMacAddrOverride); + + return TRUE; + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to flush pending TX packets in glue layer +* +* \param pvGlueInfo Pointer of GLUE Data Structure +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalFlushPendingTxPackets( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + P_QUE_T prTxQue; + P_QUE_ENTRY_T prQueueEntry; + PVOID prPacket; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prGlueInfo); + + prTxQue = &(prGlueInfo->rTxQueue); + + if (prGlueInfo->i4TxPendingFrameNum) { + while (TRUE) { + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + QUEUE_REMOVE_HEAD(prTxQue, prQueueEntry, P_QUE_ENTRY_T); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + + if (prQueueEntry == NULL) { + break; + } + + prPacket = GLUE_GET_PKT_DESCRIPTOR(prQueueEntry); + + kalSendComplete(prGlueInfo, + prPacket, + WLAN_STATUS_NOT_ACCEPTED); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is get indicated media state +* +* \param pvGlueInfo Pointer of GLUE Data Structure +* +* \retval +*/ +/*----------------------------------------------------------------------------*/ +ENUM_PARAM_MEDIA_STATE_T +kalGetMediaStateIndicated( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + ASSERT(prGlueInfo); + + return prGlueInfo->eParamMediaStateIndicated; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to set indicated media state +* +* \param pvGlueInfo Pointer of GLUE Data Structure +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalSetMediaStateIndicated( + IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_PARAM_MEDIA_STATE_T eParamMediaStateIndicate + ) +{ + ASSERT(prGlueInfo); + + prGlueInfo->eParamMediaStateIndicated = eParamMediaStateIndicate; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to clear pending OID staying in command queue +* +* \param prGlueInfo Pointer of GLUE Data Structure +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalOidCmdClearance( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + P_QUE_T prCmdQue; + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T)NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prGlueInfo); + + prCmdQue = &prGlueInfo->rCmdQueue; + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + + if (((P_CMD_INFO_T)prQueueEntry)->fgIsOid) { + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + break; + } + else { + QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); + } + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + + QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + + if (prCmdInfo) { + if (prCmdInfo->pfCmdTimeoutHandler) { + prCmdInfo->pfCmdTimeoutHandler(prGlueInfo->prAdapter, prCmdInfo); + } + else { + kalOidComplete(prGlueInfo, + prCmdInfo->fgSetQuery, + 0, + WLAN_STATUS_NOT_ACCEPTED); + } + + cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to insert command into prCmdQueue +* +* \param prGlueInfo Pointer of GLUE Data Structure +* prQueueEntry Pointer of queue entry to be inserted +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalEnqueueCommand( + IN P_GLUE_INFO_T prGlueInfo, + IN P_QUE_ENTRY_T prQueueEntry + ) +{ + P_QUE_T prCmdQue; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prGlueInfo); + ASSERT(prQueueEntry); + + prCmdQue = &prGlueInfo->rCmdQueue; + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Handle EVENT_ID_ASSOC_INFO event packet by indicating to OS with +* proper information +* +* @param pvGlueInfo Pointer of GLUE Data Structure +* @param prAssocInfo Pointer of EVENT_ID_ASSOC_INFO Packet +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalHandleAssocInfo( + IN P_GLUE_INFO_T prGlueInfo, + IN P_EVENT_ASSOC_INFO prAssocInfo + ) +{ + // to do +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to get firmware load address from registry +* +* \param prGlueInfo Pointer of GLUE Data Structure +* +* \retval +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 +kalGetFwLoadAddress( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + ASSERT(prGlueInfo); + + return prGlueInfo->rRegInfo.u4LoadAddress; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to get firmware start address from registry +* +* \param prGlueInfo Pointer of GLUE Data Structure +* +* \retval +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 +kalGetFwStartAddress( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + ASSERT(prGlueInfo); + + return prGlueInfo->rRegInfo.u4StartAddress; +} + +/*----------------------------------------------------------------------------*/ +/*! + * * @brief Notify OS with SendComplete event of the specific packet. Linux should + * * free packets here. + * * + * * @param pvGlueInfo Pointer of GLUE Data Structure + * * @param pvPacket Pointer of Packet Handle + * * @param status Status Code for OS upper layer + * * + * * @return none + * */ +/*----------------------------------------------------------------------------*/ + +/// Todo +VOID +kalSecurityFrameSendComplete ( + IN P_GLUE_INFO_T prGlueInfo, + IN PVOID pvPacket, + IN WLAN_STATUS rStatus + ) +{ + ASSERT(pvPacket); + + dev_kfree_skb((struct sk_buff *) pvPacket); + GLUE_DEC_REF_CNT(prGlueInfo->i4TxPendingSecurityFrameNum); +} + +UINT_32 +kalGetTxPendingFrameCount( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + ASSERT(prGlueInfo); + + return (UINT_32)(prGlueInfo->i4TxPendingFrameNum); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to retrieve the number of pending commands +* (including MMPDU, 802.1X and command packets) +* +* \param prGlueInfo Pointer of GLUE Data Structure +* +* \retval +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 +kalGetTxPendingCmdCount( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + P_QUE_T prCmdQue; + + ASSERT(prGlueInfo); + prCmdQue = &prGlueInfo->rCmdQueue; + + return prCmdQue->u4NumElem; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Timer Initialization Procedure +* +* \param[in] prGlueInfo Pointer to GLUE Data Structure +* \param[in] prTimerHandler Pointer to timer handling function, whose only +* argument is "prAdapter" +* +* \retval none +* +*/ +/*----------------------------------------------------------------------------*/ + +//static struct timer_list tickfn; + +VOID +kalOsTimerInitialize ( + IN P_GLUE_INFO_T prGlueInfo, + IN PVOID prTimerHandler + ) +{ + + ASSERT(prGlueInfo); + + init_timer(&(prGlueInfo->tickfn)); + prGlueInfo->tickfn.function = prTimerHandler; + prGlueInfo->tickfn.data = (unsigned long) prGlueInfo; +} + +// Todo +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set the time to do the time out check. +* +* \param[in] prGlueInfo Pointer to GLUE Data Structure +* \param[in] rInterval Time out interval from current time. +* +* \retval TRUE Success. +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +kalSetTimer( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_32 u4Interval + ) +{ + ASSERT(prGlueInfo); + del_timer_sync(&(prGlueInfo->tickfn)); + + prGlueInfo->tickfn.expires = jiffies + u4Interval * HZ / MSEC_PER_SEC; + add_timer(&(prGlueInfo->tickfn)); + + return TRUE; /* success */ +} +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to cancel +* +* \param[in] prGlueInfo Pointer to GLUE Data Structure +* +* \retval TRUE : Timer has been canceled +* FALAE : Timer doens't exist +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +kalCancelTimer( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + ASSERT(prGlueInfo); + + clear_bit(GLUE_FLAG_TIMEOUT_BIT, &prGlueInfo->u4Flag); + + if (del_timer_sync(&(prGlueInfo->tickfn)) >=0) { + return TRUE; + } else { + return FALSE; + } +} +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is a callback function for scanning done +* +* \param[in] prGlueInfo Pointer to GLUE Data Structure +* +* \retval none +* +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalScanDone( + IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_KAL_NETWORK_TYPE_INDEX_T eNetTypeIdx, + IN WLAN_STATUS status + ) +{ + ASSERT(prGlueInfo); + //complete(&prGlueInfo->rScanComp); + kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_SCAN_COMPLETE, NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to generate a random number +* +* \param none +* +* \retval UINT_32 +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 +kalRandomNumber( + VOID + ) +{ + UINT_32 number = 0; + + get_random_bytes(&number, 4); + + return number; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief command timeout call-back function + * + * \param[in] prGlueInfo Pointer to the GLUE data structure. + * + * \retval (none) + */ +/*----------------------------------------------------------------------------*/ +VOID +kalTimeoutHandler (unsigned long arg) +{ + + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) arg; + + ASSERT(prGlueInfo); + + /* Notify tx thread for timeout event */ + set_bit(GLUE_FLAG_TIMEOUT_BIT, &prGlueInfo->u4Flag); + wake_up_interruptible(&prGlueInfo->waitq); + + return; +} + + +VOID +kalSetEvent (P_GLUE_INFO_T pr) { + set_bit(GLUE_FLAG_TXREQ_BIT, &pr->u4Flag); + wake_up_interruptible(&pr->waitq); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to check if configuration file (NVRAM/Registry) exists +* +* \param[in] +* prGlueInfo +* +* \return +* TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +kalIsConfigurationExist( + IN P_GLUE_INFO_T prGlueInfo + ) +{ +#if !defined(CONFIG_X86) + ASSERT(prGlueInfo); + + return prGlueInfo->fgNvramAvailable; +#else + /* there is no configuration data for x86-linux */ + return FALSE; +#endif +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to retrieve Registry information +* +* \param[in] +* prGlueInfo +* +* \return +* Pointer of REG_INFO_T +*/ +/*----------------------------------------------------------------------------*/ +P_REG_INFO_T +kalGetConfiguration( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + ASSERT(prGlueInfo); + + return &(prGlueInfo->rRegInfo); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to retrieve version information of corresponding configuration file +* +* \param[in] +* prGlueInfo +* +* \param[out] +* pu2Part1CfgOwnVersion +* pu2Part1CfgPeerVersion +* pu2Part2CfgOwnVersion +* pu2Part2CfgPeerVersion +* +* \return +* NONE +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalGetConfigurationVersion( + IN P_GLUE_INFO_T prGlueInfo, + OUT PUINT_16 pu2Part1CfgOwnVersion, + OUT PUINT_16 pu2Part1CfgPeerVersion, + OUT PUINT_16 pu2Part2CfgOwnVersion, + OUT PUINT_16 pu2Part2CfgPeerVersion + ) +{ + ASSERT(prGlueInfo); + + ASSERT(pu2Part1CfgOwnVersion); + ASSERT(pu2Part1CfgPeerVersion); + ASSERT(pu2Part2CfgOwnVersion); + ASSERT(pu2Part2CfgPeerVersion); + + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part1OwnVersion), + pu2Part1CfgOwnVersion); + + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part1PeerVersion), + pu2Part1CfgPeerVersion); + + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part2OwnVersion), + pu2Part2CfgOwnVersion); + + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part2PeerVersion), + pu2Part2CfgPeerVersion); + + return; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to check if the WPS is active or not +* +* \param[in] +* prGlueInfo +* +* \return +* TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +kalWSCGetActiveState( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + ASSERT(prGlueInfo); + + return (prGlueInfo->fgWpsActive); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief update RSSI and LinkQuality to GLUE layer +* +* \param[in] +* prGlueInfo +* eNetTypeIdx +* cRssi +* cLinkQuality +* +* \return +* None +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalUpdateRSSI( + IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_KAL_NETWORK_TYPE_INDEX_T eNetTypeIdx, + IN INT_8 cRssi, + IN INT_8 cLinkQuality + ) +{ + struct iw_statistics *pStats = (struct iw_statistics *)NULL; + + ASSERT(prGlueInfo); + + switch(eNetTypeIdx) { + case KAL_NETWORK_TYPE_AIS_INDEX: + pStats = (struct iw_statistics *) (&(prGlueInfo->rIwStats)); + break; +#if CFG_ENABLE_WIFI_DIRECT +#if CFG_SUPPORT_P2P_RSSI_QUERY + case KAL_NETWORK_TYPE_P2P_INDEX: + pStats = (struct iw_statistics *) (&(prGlueInfo->rP2pIwStats)); + break; +#endif +#endif + default: + break; + + } + + if (pStats) { + pStats->qual.qual = cLinkQuality; + pStats->qual.noise = 0; + pStats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_NOISE_UPDATED; + pStats->qual.level = 0x100 + cRssi; + pStats->qual.updated |= IW_QUAL_LEVEL_UPDATED; + } + + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Pre-allocate I/O buffer +* +* \param[in] +* none +* +* \return +* TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +kalInitIOBuffer( + VOID + ) +{ + UINT_32 u4Size; + + if(CFG_COALESCING_BUFFER_SIZE >= CFG_RX_COALESCING_BUFFER_SIZE) { + u4Size = CFG_COALESCING_BUFFER_SIZE + sizeof(ENHANCE_MODE_DATA_STRUCT_T); + } + else { + u4Size = CFG_RX_COALESCING_BUFFER_SIZE + sizeof(ENHANCE_MODE_DATA_STRUCT_T); + } + + pvIoBuffer = kmalloc(u4Size, GFP_KERNEL); + if(pvIoBuffer) { + pvIoBufferSize = u4Size; + pvIoBufferUsage = 0; + + return TRUE; + } + + return FALSE; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Free pre-allocated I/O buffer +* +* \param[in] +* none +* +* \return +* none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalUninitIOBuffer( + VOID + ) +{ + if(pvIoBuffer) { + kfree(pvIoBuffer); + + pvIoBuffer = (PVOID) NULL; + pvIoBufferSize = 0; + pvIoBufferUsage = 0; + } + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Dispatch pre-allocated I/O buffer +* +* \param[in] +* u4AllocSize +* +* \return +* PVOID for pointer of pre-allocated I/O buffer +*/ +/*----------------------------------------------------------------------------*/ +PVOID +kalAllocateIOBuffer( + IN UINT_32 u4AllocSize + ) +{ + PVOID ret = (PVOID)NULL; + + if(pvIoBuffer) { + if(u4AllocSize <= (pvIoBufferSize - pvIoBufferUsage)) { + ret = (PVOID)&(((PUINT_8)(pvIoBuffer))[pvIoBufferUsage]); + pvIoBufferUsage += u4AllocSize; + } + } + else { + /* fault tolerance */ + ret = (PVOID) kalMemAlloc(u4AllocSize, PHY_MEM_TYPE); + } + + return ret; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Release all dispatched I/O buffer +* +* \param[in] +* none +* +* \return +* none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalReleaseIOBuffer( + IN PVOID pvAddr, + IN UINT_32 u4Size + ) +{ + if(pvIoBuffer) { + pvIoBufferUsage -= u4Size; + } + else { + /* fault tolerance */ + kalMemFree(pvAddr, PHY_MEM_TYPE, u4Size); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalGetChannelList( + IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_BAND_T eSpecificBand, + IN UINT_8 ucMaxChannelNum, + IN PUINT_8 pucNumOfChannel, + IN P_RF_CHANNEL_INFO_T paucChannelList + ) +{ + rlmDomainGetChnlList(prGlueInfo->prAdapter, + eSpecificBand, + ucMaxChannelNum, + pucNumOfChannel, + paucChannelList); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +BOOL +kalIsAPmode( + IN P_GLUE_INFO_T prGlueInfo + ) +{ +#if CFG_ENABLE_WIFI_DIRECT + if (IS_NET_ACTIVE(prGlueInfo->prAdapter, NETWORK_TYPE_P2P_INDEX) && + prGlueInfo->prAdapter->rP2pFuncLkr.prP2pFuncIsApMode && + prGlueInfo->prAdapter->rP2pFuncLkr.prP2pFuncIsApMode( + prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo)) + return TRUE; +#endif + + return FALSE; +} + + +#if CFG_SUPPORT_802_11W +/*----------------------------------------------------------------------------*/ +/*! +* \brief to check if the MFP is active or not +* +* \param[in] +* prGlueInfo +* +* \return +* TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 +kalGetMfpSetting( + IN P_GLUE_INFO_T prGlueInfo + ) +{ + ASSERT(prGlueInfo); + + return (prGlueInfo->rWpaInfo.u4Mfp); +} +#endif + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_proc.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_proc.c new file mode 100755 index 000000000000..bef72b031316 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_proc.c @@ -0,0 +1,855 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/os/linux/gl_proc.c#1 $ +*/ + +/*! \file "gl_proc.c" + \brief This file defines the interface which can interact with users in /proc fs. + + Detail description. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: gl_proc.c $ + * + * 11 10 2011 cp.wu + * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer + * 1. eliminaite direct calls to printk in porting layer. + * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 12 10 2010 kevin.huang + * [WCXRP00000128] [MT6620 Wi-Fi][Driver] Add proc support to Android Driver for debug and driver status check + * Add Linux Proc Support +** \main\maintrunk.MT5921\19 2008-09-02 21:08:37 GMT mtk01461 +** Fix the compile error of SPRINTF() +** \main\maintrunk.MT5921\18 2008-08-10 18:48:28 GMT mtk01461 +** Update for Driver Review +** \main\maintrunk.MT5921\17 2008-08-04 16:52:01 GMT mtk01461 +** Add proc dbg print message of DOMAIN_INDEX level +** \main\maintrunk.MT5921\16 2008-07-10 00:45:16 GMT mtk01461 +** Remove the check of MCR offset, we may use the MCR address which is not align to DW boundary or proprietary usage. +** \main\maintrunk.MT5921\15 2008-06-03 20:49:44 GMT mtk01461 +** \main\maintrunk.MT5921\14 2008-06-02 22:56:00 GMT mtk01461 +** Rename some functions for linux proc +** \main\maintrunk.MT5921\13 2008-06-02 20:23:18 GMT mtk01461 +** Revise PROC mcr read / write for supporting TELNET +** \main\maintrunk.MT5921\12 2008-03-28 10:40:25 GMT mtk01461 +** Remove temporary set desired rate in linux proc +** \main\maintrunk.MT5921\11 2008-01-07 15:07:29 GMT mtk01461 +** Add User Update Desired Rate Set for QA in Linux +** \main\maintrunk.MT5921\10 2007-12-11 00:11:14 GMT mtk01461 +** Fix SPIN_LOCK protection +** \main\maintrunk.MT5921\9 2007-12-04 18:07:57 GMT mtk01461 +** Add additional debug category to proc +** \main\maintrunk.MT5921\8 2007-11-02 01:03:23 GMT mtk01461 +** Unify TX Path for Normal and IBSS Power Save + IBSS neighbor learning +** \main\maintrunk.MT5921\7 2007-10-25 18:08:14 GMT mtk01461 +** Add VOIP SCAN Support & Refine Roaming +** Revision 1.3 2007/07/05 07:25:33 MTK01461 +** Add Linux initial code, modify doc, add 11BB, RF init code +** +** Revision 1.2 2007/06/27 02:18:51 MTK01461 +** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "gl_os.h" +#include "gl_kal.h" + +#include "wlan_lib.h" +#include "debug.h" + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define PROC_MCR_ACCESS "mcr" +#define PROC_DRV_STATUS "status" +#define PROC_RX_STATISTICS "rx_statistics" +#define PROC_TX_STATISTICS "tx_statistics" +#define PROC_DBG_LEVEL "dbg_level" + +#define PROC_MCR_ACCESS_MAX_USER_INPUT_LEN 20 +#define PROC_RX_STATISTICS_MAX_USER_INPUT_LEN 10 +#define PROC_TX_STATISTICS_MAX_USER_INPUT_LEN 10 +#define PROC_DBG_LEVEL_MAX_USER_INPUT_LEN 20 +#define PROC_DBG_LEVEL_MAX_DISPLAY_STR_LEN 30 + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +static UINT_32 u4McrOffset = 0; + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* \brief The PROC function for reading MCR register to User Space, the offset of +* the MCR is specified in u4McrOffset. +* +* \param[in] page Buffer provided by kernel. +* \param[in out] start Start Address to read(3 methods). +* \param[in] off Offset. +* \param[in] count Allowable number to read. +* \param[out] eof End of File indication. +* \param[in] data Pointer to the private data structure. +* +* \return number of characters print to the buffer from User Space. +*/ +/*----------------------------------------------------------------------------*/ +static int +procMCRRead ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data + ) +{ + P_GLUE_INFO_T prGlueInfo; + PARAM_CUSTOM_MCR_RW_STRUC_T rMcrInfo; + UINT_32 u4BufLen; + char *p = page; + UINT_32 u4Count; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + + ASSERT(data); + + // Kevin: Apply PROC read method 1. + if (off != 0) { + return 0; // To indicate end of file. + } + + prGlueInfo = (P_GLUE_INFO_T) netdev_priv((struct net_device *)data); + + rMcrInfo.u4McrOffset = u4McrOffset; + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryMcrRead, + (PVOID)&rMcrInfo, + sizeof(rMcrInfo), + TRUE, + TRUE, + TRUE, + FALSE, + &u4BufLen); + + + SPRINTF(p, ("MCR (0x%08lxh): 0x%08lx\n", + rMcrInfo.u4McrOffset, rMcrInfo.u4McrData)); + + u4Count = (UINT_32)(p - page); + + *eof = 1; + + return (int)u4Count; + +} /* end of procMCRRead() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief The PROC function for writing MCR register to HW or update u4McrOffset +* for reading MCR later. +* +* \param[in] file pointer to file. +* \param[in] buffer Buffer from user space. +* \param[in] count Number of characters to write +* \param[in] data Pointer to the private data structure. +* +* \return number of characters write from User Space. +*/ +/*----------------------------------------------------------------------------*/ +static int +procMCRWrite ( + struct file *file, + const char *buffer, + unsigned long count, + void *data + ) +{ + P_GLUE_INFO_T prGlueInfo; + char acBuf[PROC_MCR_ACCESS_MAX_USER_INPUT_LEN + 1]; // + 1 for "\0" + int i4CopySize; + PARAM_CUSTOM_MCR_RW_STRUC_T rMcrInfo; + UINT_32 u4BufLen; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + + ASSERT(data); + + i4CopySize = (count < (sizeof(acBuf) - 1)) ? count : (sizeof(acBuf) - 1); + if (copy_from_user(acBuf, buffer, i4CopySize)) { + return 0; + } + acBuf[i4CopySize] = '\0'; + + switch (sscanf(acBuf, "0x%lx 0x%lx", + &rMcrInfo.u4McrOffset, &rMcrInfo.u4McrData)) { + case 2: + /* NOTE: Sometimes we want to test if bus will still be ok, after accessing + * the MCR which is not align to DW boundary. + */ + //if (IS_ALIGN_4(rMcrInfo.u4McrOffset)) + { + prGlueInfo = (P_GLUE_INFO_T) netdev_priv((struct net_device *)data); + + u4McrOffset = rMcrInfo.u4McrOffset; + + //printk("Write 0x%lx to MCR 0x%04lx\n", + //rMcrInfo.u4McrOffset, rMcrInfo.u4McrData); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetMcrWrite, + (PVOID)&rMcrInfo, + sizeof(rMcrInfo), + FALSE, + FALSE, + TRUE, + FALSE, + &u4BufLen); + + } + break; + + case 1: + //if (IS_ALIGN_4(rMcrInfo.u4McrOffset)) + { + u4McrOffset = rMcrInfo.u4McrOffset; + } + break; + + default: + break; + } + + return count; + +} /* end of procMCRWrite() */ + +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* \brief The PROC function for reading Driver Status to User Space. +* +* \param[in] page Buffer provided by kernel. +* \param[in out] start Start Address to read(3 methods). +* \param[in] off Offset. +* \param[in] count Allowable number to read. +* \param[out] eof End of File indication. +* \param[in] data Pointer to the private data structure. +* +* \return number of characters print to the buffer from User Space. +*/ +/*----------------------------------------------------------------------------*/ +static int +procDrvStatusRead ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data + ) +{ + P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv; + char *p = page; + UINT_32 u4Count; + + GLUE_SPIN_LOCK_DECLARATION(); + + + ASSERT(data); + + // Kevin: Apply PROC read method 1. + if (off != 0) { + return 0; // To indicate end of file. + } + + + SPRINTF(p, ("GLUE LAYER STATUS:")); + SPRINTF(p, ("\n==================")); + + SPRINTF(p, ("\n* Number of Pending Frames: %ld\n", + prGlueInfo->u4TxPendingFrameNum)); + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); + + wlanoidQueryDrvStatusForLinuxProc(prGlueInfo->prAdapter, p, &u4Count); + + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); + + u4Count += (UINT_32)(p - page); + + *eof = 1; + + return (int)u4Count; + +} /* end of procDrvStatusRead() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief The PROC function for reading Driver RX Statistic Counters to User Space. +* +* \param[in] page Buffer provided by kernel. +* \param[in out] start Start Address to read(3 methods). +* \param[in] off Offset. +* \param[in] count Allowable number to read. +* \param[out] eof End of File indication. +* \param[in] data Pointer to the private data structure. +* +* \return number of characters print to the buffer from User Space. +*/ +/*----------------------------------------------------------------------------*/ +static int +procRxStatisticsRead ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data + ) +{ + P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv; + char *p = page; + UINT_32 u4Count; + + GLUE_SPIN_LOCK_DECLARATION(); + + + ASSERT(data); + + // Kevin: Apply PROC read method 1. + if (off != 0) { + return 0; // To indicate end of file. + } + + + SPRINTF(p, ("RX STATISTICS (Write 1 to clear):")); + SPRINTF(p, ("\n=================================\n")); + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); + + wlanoidQueryRxStatisticsForLinuxProc(prGlueInfo->prAdapter, p, &u4Count); + + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); + + u4Count += (UINT_32)(p - page); + + *eof = 1; + + return (int)u4Count; + +} /* end of procRxStatisticsRead() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief The PROC function for reset Driver RX Statistic Counters. +* +* \param[in] file pointer to file. +* \param[in] buffer Buffer from user space. +* \param[in] count Number of characters to write +* \param[in] data Pointer to the private data structure. +* +* \return number of characters write from User Space. +*/ +/*----------------------------------------------------------------------------*/ +static int +procRxStatisticsWrite ( + struct file *file, + const char *buffer, + unsigned long count, + void *data + ) +{ + P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv; + char acBuf[PROC_RX_STATISTICS_MAX_USER_INPUT_LEN + 1]; // + 1 for "\0" + UINT_32 u4CopySize; + UINT_32 u4ClearCounter; + + GLUE_SPIN_LOCK_DECLARATION(); + + + ASSERT(data); + + u4CopySize = (count < (sizeof(acBuf) - 1)) ? count : (sizeof(acBuf) - 1); + copy_from_user(acBuf, buffer, u4CopySize); + acBuf[u4CopySize] = '\0'; + + if (sscanf(acBuf, "%ld", &u4ClearCounter) == 1) { + if (u4ClearCounter == 1) { + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); + + wlanoidSetRxStatisticsForLinuxProc(prGlueInfo->prAdapter); + + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); + } + } + + return count; + +} /* end of procRxStatisticsWrite() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief The PROC function for reading Driver TX Statistic Counters to User Space. +* +* \param[in] page Buffer provided by kernel. +* \param[in out] start Start Address to read(3 methods). +* \param[in] off Offset. +* \param[in] count Allowable number to read. +* \param[out] eof End of File indication. +* \param[in] data Pointer to the private data structure. +* +* \return number of characters print to the buffer from User Space. +*/ +/*----------------------------------------------------------------------------*/ +static int +procTxStatisticsRead ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data + ) +{ + P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv; + char *p = page; + UINT_32 u4Count; + + GLUE_SPIN_LOCK_DECLARATION(); + + + ASSERT(data); + + // Kevin: Apply PROC read method 1. + if (off != 0) { + return 0; // To indicate end of file. + } + + + SPRINTF(p, ("TX STATISTICS (Write 1 to clear):")); + SPRINTF(p, ("\n=================================\n")); + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); + + wlanoidQueryTxStatisticsForLinuxProc(prGlueInfo->prAdapter, p, &u4Count); + + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); + + u4Count += (UINT_32)(p - page); + + *eof = 1; + + return (int)u4Count; + +} /* end of procTxStatisticsRead() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief The PROC function for reset Driver TX Statistic Counters. +* +* \param[in] file pointer to file. +* \param[in] buffer Buffer from user space. +* \param[in] count Number of characters to write +* \param[in] data Pointer to the private data structure. +* +* \return number of characters write from User Space. +*/ +/*----------------------------------------------------------------------------*/ +static int +procTxStatisticsWrite ( + struct file *file, + const char *buffer, + unsigned long count, + void *data + ) +{ + P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv; + char acBuf[PROC_RX_STATISTICS_MAX_USER_INPUT_LEN + 1]; // + 1 for "\0" + UINT_32 u4CopySize; + UINT_32 u4ClearCounter; + + GLUE_SPIN_LOCK_DECLARATION(); + + + ASSERT(data); + + u4CopySize = (count < (sizeof(acBuf) - 1)) ? count : (sizeof(acBuf) - 1); + copy_from_user(acBuf, buffer, u4CopySize); + acBuf[u4CopySize] = '\0'; + + if (sscanf(acBuf, "%ld", &u4ClearCounter) == 1) { + if (u4ClearCounter == 1) { + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); + + wlanoidSetTxStatisticsForLinuxProc(prGlueInfo->prAdapter); + + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); + } + } + + return count; + +} /* end of procTxStatisticsWrite() */ +#endif + + +#if DBG +static UINT_8 aucDbModuleName[][PROC_DBG_LEVEL_MAX_DISPLAY_STR_LEN] = { + "DBG_INIT_IDX", + "DBG_HAL_IDX", + "DBG_INTR_IDX", + "DBG_REQ_IDX", + "DBG_TX_IDX", + "DBG_RX_IDX", + "DBG_RFTEST_IDX", + "DBG_EMU_IDX", + "DBG_SW1_IDX", + "DBG_SW2_IDX", + "DBG_SW3_IDX", + "DBG_SW4_IDX", + "DBG_HEM_IDX", + "DBG_AIS_IDX", + "DBG_RLM_IDX", + "DBG_MEM_IDX", + "DBG_CNM_IDX", + "DBG_RSN_IDX", + "DBG_BSS_IDX", + "DBG_SCN_IDX", + "DBG_SAA_IDX", + "DBG_AAA_IDX", + "DBG_P2P_IDX", + "DBG_QM_IDX", + "DBG_SEC_IDX", + "DBG_BOW_IDX" + }; + +extern UINT_8 aucDebugModule[]; + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief The PROC function for displaying current Debug Level. +* +* \param[in] page Buffer provided by kernel. +* \param[in out] start Start Address to read(3 methods). +* \param[in] off Offset. +* \param[in] count Allowable number to read. +* \param[out] eof End of File indication. +* \param[in] data Pointer to the private data structure. +* +* \return number of characters print to the buffer from User Space. +*/ +/*----------------------------------------------------------------------------*/ +static int +procDbgLevelRead ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data + ) +{ + char *p = page; + int i; + + + + // Kevin: Apply PROC read method 1. + if (off != 0) { + return 0; // To indicate end of file. + } + + for (i = 0; i < (sizeof(aucDbModuleName)/PROC_DBG_LEVEL_MAX_DISPLAY_STR_LEN); i++) { + SPRINTF(p, ("%c %-15s(0x%02x): %02x\n", + ((i == u4DebugModule) ? '*' : ' '), + &aucDbModuleName[i][0], + i, + aucDebugModule[i])); + } + + *eof = 1; + return (int)(p - page); +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief The PROC function for adjusting Debug Level to turn on/off debugging message. +* +* \param[in] file pointer to file. +* \param[in] buffer Buffer from user space. +* \param[in] count Number of characters to write +* \param[in] data Pointer to the private data structure. +* +* \return number of characters write from User Space. +*/ +/*----------------------------------------------------------------------------*/ +static int +procDbgLevelWrite ( + struct file *file, + const char *buffer, + unsigned long count, + void *data + ) +{ + char acBuf[PROC_DBG_LEVEL_MAX_USER_INPUT_LEN + 1]; // + 1 for "\0" + UINT_32 u4CopySize; + UINT_32 u4NewDbgModule, u4NewDbgLevel; + + + u4CopySize = (count < (sizeof(acBuf) - 1)) ? count : (sizeof(acBuf) - 1); + copy_from_user(acBuf, buffer, u4CopySize); + acBuf[u4CopySize] = '\0'; + + if (sscanf(acBuf, "0x%lx 0x%lx", &u4NewDbgModule, &u4NewDbgLevel) == 2) { + if (u4NewDbgModule < DBG_MODULE_NUM) { + u4DebugModule = u4NewDbgModule; + u4NewDbgLevel &= DBG_CLASS_MASK; + aucDebugModule[u4DebugModule] = (UINT_8)u4NewDbgLevel; + } + } + + return count; +} +#endif /* DBG */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function create a PROC fs in linux /proc/net subdirectory. +* +* \param[in] prDev Pointer to the struct net_device. +* \param[in] pucDevName Pointer to the name of net_device. +* +* \return N/A +*/ +/*----------------------------------------------------------------------------*/ +INT_32 +procInitProcfs ( + struct net_device *prDev, + char *pucDevName + ) +{ + P_GLUE_INFO_T prGlueInfo; + struct proc_dir_entry *prEntry; + + + ASSERT(prDev); + + if (init_net.proc_net == (struct proc_dir_entry *)NULL) { + DBGLOG(INIT, INFO, ("init proc fs fail: proc_net == NULL\n")); + return -ENOENT; + } + + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prDev); + + if (!prGlueInfo) { + DBGLOG(INIT, WARN, ("The OS context is NULL\n")); + return -ENOENT; + } + + + /* + /proc/net/wlan0 + |-- mcr (PROC_MCR_ACCESS) + |-- status (PROC_DRV_STATUS) + |-- rx_statistics (PROC_RX_STATISTICS) + |-- tx_statistics (PROC_TX_STATISTICS) + |-- dbg_level (PROC_DBG_LEVEL) + |-- (end) + */ + + /* + * Directory: Root (/proc/net/wlan0) + */ + + prGlueInfo->pProcRoot = proc_mkdir(pucDevName, init_net.proc_net); + if (prGlueInfo->pProcRoot == NULL) { + return -ENOENT; + } + + /* File Root/mcr (RW) */ + prEntry = create_proc_entry(PROC_MCR_ACCESS, 0, prGlueInfo->pProcRoot); + if (prEntry) { + prEntry->read_proc = procMCRRead; + prEntry->write_proc = procMCRWrite; + prEntry->data = (void *)prDev; + } + +#if 0 + /* File Root/status (RW) */ + prEntry = create_proc_read_entry(PROC_DRV_STATUS, 0, prGlueInfo->pProcRoot, + procDrvStatusRead, prDev); + + /* File Root/rx_statistics (RW) */ + prEntry = create_proc_entry(PROC_RX_STATISTICS, 0, prGlueInfo->pProcRoot); + if (prEntry) { + prEntry->read_proc = procRxStatisticsRead; + prEntry->write_proc = procRxStatisticsWrite; + prEntry->data = (void *)prDev; + } + + /* File Root/tx_statistics (RW) */ + prEntry = create_proc_entry(PROC_TX_STATISTICS, 0, prGlueInfo->pProcRoot); + if (prEntry) { + prEntry->read_proc = procTxStatisticsRead; + prEntry->write_proc = procTxStatisticsWrite; + prEntry->data = (void *)prDev; + } + +#if DBG + /* File Root/dbg_level (RW) */ + prEntry = create_proc_entry(PROC_DBG_LEVEL, 0644, prGlueInfo->pProcRoot); + if (prEntry) { + prEntry->read_proc = procDbgLevelRead; + prEntry->write_proc = procDbgLevelWrite; + } +#endif /* DBG */ +#endif + return 0; + +} /* end of procInitProcfs() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function clean up a PROC fs created by procInitProcfs(). +* +* \param[in] prDev Pointer to the struct net_device. +* \param[in] pucDevName Pointer to the name of net_device. +* +* \return N/A +*/ +/*----------------------------------------------------------------------------*/ +INT_32 +procRemoveProcfs ( + struct net_device *prDev, + char *pucDevName + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + + ASSERT(prDev); + + if (!prDev) { + return -ENOENT; + } + + if (init_net.proc_net == (struct proc_dir_entry *)NULL) { + DBGLOG(INIT, WARN, ("remove proc fs fail: proc_net == NULL\n")); + return -ENOENT; + } + + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prDev); + if (!prGlueInfo->pProcRoot) { + DBGLOG(INIT, WARN, ("The procfs root is NULL\n")); + return -ENOENT; + } +#if 0 +#if DBG + remove_proc_entry(PROC_DBG_LEVEL, prGlueInfo->pProcRoot); +#endif /* DBG */ + remove_proc_entry(PROC_TX_STATISTICS, prGlueInfo->pProcRoot); + remove_proc_entry(PROC_RX_STATISTICS, prGlueInfo->pProcRoot); + remove_proc_entry(PROC_DRV_STATUS, prGlueInfo->pProcRoot); +#endif + remove_proc_entry(PROC_MCR_ACCESS, prGlueInfo->pProcRoot); + + /* remove root directory (proc/net/wlan0) */ + remove_proc_entry(pucDevName, init_net.proc_net); + + return 0; + +} /* end of procRemoveProcfs() */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_rst.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_rst.c new file mode 100755 index 000000000000..9a1f1d195463 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_rst.c @@ -0,0 +1,517 @@ +/* +** $Id: @(#) gl_rst.c@@ +*/ + +/*! \file gl_rst.c + \brief Main routines for supporintg MT6620 whole-chip reset mechanism + + This file contains the support routines of Linux driver for MediaTek Inc. 802.11 + Wireless LAN Adapters. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: gl_rst.c $ + * + * 11 10 2011 cp.wu + * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer + * 1. eliminaite direct calls to printk in porting layer. + * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. + * + * 04 22 2011 cp.wu + * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for RESET_START and RESET_END events + * skip power-off handshaking when RESET indication is received. + * + * 04 14 2011 cp.wu + * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for RESET_START and RESET_END events + * sync. whole-chip resetting mechanism to V2.0 branch. + * + * 04 14 2011 cp.wu + * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for RESET_START and RESET_END events + * 1. add code to put whole-chip resetting trigger when abnormal firmware assertion is detected + * 2. add dummy function for both Win32 and Linux part. + * + * 03 30 2011 cp.wu + * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for RESET_START and RESET_END events + * use netlink unicast instead of broadcast + * +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "gl_os.h" +#include "debug.h" +#include "wlan_lib.h" +#include "gl_wext.h" +#include "precomp.h" +#include +#include +#include + +#if CFG_CHIP_RESET_SUPPORT + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define MAX_BIND_PROCESS (4) + +#define MTK_WIFI_FAMILY_NAME "MTK_WIFI" +#define MTK_WIFI_RESET_START_NAME "RESET_START" +#define MTK_WIFI_RESET_END_NAME "RESET_END" +#define MTK_WIFI_RESET_TEST_NAME "GENETLINK_START" + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +enum { + __MTK_WIFI_ATTR_INVALID, + MTK_WIFI_ATTR_MSG, + __MTK_WIFI_ATTR_MAX, +}; +#define MTK_WIFI_ATTR_MAX (__MTK_WIFI_ATTR_MAX - 1) + + +enum { + __MTK_WIFI_COMMAND_INVALID, + MTK_WIFI_COMMAND_BIND, + MTK_WIFI_COMMAND_RESET, + __MTK_WIFI_COMMAND_MAX, +}; +#define MTK_WIFI_COMMAND_MAX (__MTK_WIFI_COMMAND_MAX - 1) + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +static UINT_32 mtk_wifi_seqnum = 0; +static int num_bind_process = 0; +static pid_t bind_pid[MAX_BIND_PROCESS]; +static BOOLEAN fgIsResetting = FALSE; + +/* attribute policy */ +static struct nla_policy mtk_wifi_genl_policy[MTK_WIFI_ATTR_MAX + 1] = { + [MTK_WIFI_ATTR_MSG] = { .type = NLA_NUL_STRING }, +}; + +/* family definition */ +static struct genl_family mtk_wifi_gnl_family = { + .id = GENL_ID_GENERATE, + .hdrsize = 0, + .name = MTK_WIFI_FAMILY_NAME, + .version = 1, + .maxattr = MTK_WIFI_ATTR_MAX, +}; + +/* forward declaration */ +static int mtk_wifi_bind( + struct sk_buff *skb, + struct genl_info *info + ); + +static int mtk_wifi_reset( + struct sk_buff *skb, + struct genl_info *info + ); + +/* operation definition */ +static struct genl_ops mtk_wifi_gnl_ops_bind = { + .cmd = MTK_WIFI_COMMAND_BIND, + .flags = 0, + .policy = mtk_wifi_genl_policy, + .doit = mtk_wifi_bind, + .dumpit = NULL, +}; + +static struct genl_ops mtk_wifi_gnl_ops_reset = { + .cmd = MTK_WIFI_COMMAND_RESET, + .flags = 0, + .policy = mtk_wifi_genl_policy, + .doit = mtk_wifi_reset, + .dumpit = NULL, +}; + + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +extern int +mtk_wcn_wmt_msgcb_reg( + ENUM_WMTDRV_TYPE_T eType, + PF_WMT_CB pCb); + +extern int +mtk_wcn_wmt_msgcb_unreg( + ENUM_WMTDRV_TYPE_T eType + ); + +static void * +glResetCallback ( + ENUM_WMTDRV_TYPE_T eSrcType, + ENUM_WMTDRV_TYPE_T eDstType, + ENUM_WMTMSG_TYPE_T eMsgType, + void * prMsgBody, + unsigned int u4MsgLength + ); + +static BOOLEAN +glResetSendMessage ( + char *aucMsg, + u8 cmd + ); + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for + * 1. registering for reset callbacks + * 2. initialize netlink socket + * + * @param none + * + * @retval none + */ +/*----------------------------------------------------------------------------*/ +VOID +glResetInit( + VOID + ) +{ + /* 1. register for reset callback */ + mtk_wcn_wmt_msgcb_reg(WMTDRV_TYPE_WIFI, (PF_WMT_CB)glResetCallback); + + /* 2.1 registration for NETLINK_GENERIC family */ + if(genl_register_family(&mtk_wifi_gnl_family) != 0) { + DBGLOG(INIT, WARN, ("%s(): GE_NELINK family registration fail\n", __func__)); + } + else { + /* 2.2 operation registration */ + if(genl_register_ops(&mtk_wifi_gnl_family, &mtk_wifi_gnl_ops_bind) != 0) { + DBGLOG(INIT, WARN, ("%s(): BIND operation registration fail\n", __func__)); + } + + if(genl_register_ops(&mtk_wifi_gnl_family, &mtk_wifi_gnl_ops_reset) != 0) { + DBGLOG(INIT, WARN, ("%s(): RESET operation registration fail\n", __func__)); + } + } + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for + * 1. uninitialize netlink socket + * 2. deregistering for reset callbacks + * + * @param none + * + * @retval none + */ +/*----------------------------------------------------------------------------*/ +VOID +glResetUninit( + VOID + ) +{ + /* 1. release NETLINK_GENERIC family */ + genl_unregister_family(&mtk_wifi_gnl_family); + + /* 2. deregister for reset callback */ + mtk_wcn_wmt_msgcb_unreg(WMTDRV_TYPE_WIFI); + + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is invoked when there is reset messages indicated + * + * @param eSrcType + * eDstType + * eMsgType + * prMsgBody + * u4MsgLength + * + * @retval + */ +/*----------------------------------------------------------------------------*/ +static void * +glResetCallback ( + ENUM_WMTDRV_TYPE_T eSrcType, + ENUM_WMTDRV_TYPE_T eDstType, + ENUM_WMTMSG_TYPE_T eMsgType, + void * prMsgBody, + unsigned int u4MsgLength + ) +{ + switch(eMsgType) { + case WMTMSG_TYPE_RESET: + if(u4MsgLength == sizeof(ENUM_WMTRSTMSG_TYPE_T)) { + P_ENUM_WMTRSTMSG_TYPE_T prRstMsg = (P_ENUM_WMTRSTMSG_TYPE_T) prMsgBody; + + switch(*prRstMsg) { + case WMTRSTMSG_RESET_START: + fgIsResetting = TRUE; + glResetSendMessage(MTK_WIFI_RESET_START_NAME, MTK_WIFI_COMMAND_RESET); + break; + + case WMTRSTMSG_RESET_END: + glResetSendMessage(MTK_WIFI_RESET_END_NAME, MTK_WIFI_COMMAND_RESET); + fgIsResetting = FALSE; + break; + + default: + break; + } + } + + break; + + default: + break; + } + + return NULL; +} + + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine send out message via netlink socket + * + * @param aucMsg + * u4MsgLength + * + * @retval TRUE + * FALSE + */ +/*----------------------------------------------------------------------------*/ +static BOOLEAN +glResetSendMessage( + char * aucMsg, + u8 cmd + ) +{ + struct sk_buff *skb = NULL; + void *msg_head = NULL; + int rc = -1; + int i; + + if(num_bind_process == 0) { + /* no listening process */ + return FALSE; + } + + for(i = 0 ; i < num_bind_process ; i++) { + skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + + if(skb) { + msg_head = genlmsg_put(skb, 0, mtk_wifi_seqnum++, &mtk_wifi_gnl_family, 0, cmd); + + if(msg_head == NULL) { + nlmsg_free(skb); + return FALSE; + } + + rc = nla_put_string(skb, MTK_WIFI_ATTR_MSG, aucMsg); + if(rc != 0) { + nlmsg_free(skb); + return FALSE; + } + + /* finalize the message */ + genlmsg_end(skb, msg_head); + + /* sending message */ + rc = genlmsg_unicast(&init_net, skb, bind_pid[i]); + if(rc != 0) { + return FALSE; + } + } + else { + return FALSE; + } + } + + return TRUE; +} + + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is called to identify PID for process binding + * + * @param skb + * info + * + * @retval 0 + * nonzero + */ +/*----------------------------------------------------------------------------*/ +int mtk_wifi_bind( + struct sk_buff *skb, + struct genl_info *info + ) +{ + struct nlattr *na; + char * mydata; + + if (info == NULL) { + goto out; + } + + /*for each attribute there is an index in info->attrs which points to a nlattr structure + *in this structure the data is given + */ + + na = info->attrs[MTK_WIFI_ATTR_MSG]; + if (na) { + mydata = (char *)nla_data(na); + + /* no need to parse mydata */ + } + + /* collect PID */ + if(num_bind_process < MAX_BIND_PROCESS) { + bind_pid[num_bind_process] = info->snd_pid; + num_bind_process++; + } + else { + DBGLOG(INIT, WARN, ("%s(): exceeding binding limit %d\n", __func__, MAX_BIND_PROCESS)); + } + +out: + return 0; +} + + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is called for reset, shout not happen + * + * @param skb + * info + * + * @retval 0 + * nonzero + */ +/*----------------------------------------------------------------------------*/ +int mtk_wifi_reset( + struct sk_buff *skb, + struct genl_info *info + ) +{ + DBGLOG(INIT, WARN, ("%s(): should not be invoked\n", __func__)); + + return 0; +} + + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is called for generating reset request to WMT + * + * @param None + * + * @retval None + */ +/*----------------------------------------------------------------------------*/ +VOID +glSendResetRequest( + VOID + ) +{ + // WMT thread would trigger whole chip resetting itself + return; +} + + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is called for checking if MT6620 is resetting + * + * @param None + * + * @retval TRUE + * FALSE + */ +/*----------------------------------------------------------------------------*/ +BOOLEAN +kalIsResetting( + VOID + ) +{ + return fgIsResetting; +} + + +#endif // CFG_CHIP_RESET_SUPPORT diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_wext.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_wext.c new file mode 100755 index 000000000000..002c4e0364d0 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_wext.c @@ -0,0 +1,4548 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/os/linux/gl_wext.c#1 $ +*/ + +/*! \file gl_wext.c + \brief ioctl() (mostly Linux Wireless Extensions) routines for STA driver. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: gl_wext.c $ + * + * 01 20 2012 wh.su + * [ALPS00107209] [Need Patch] [Volunteer Patch][ICS][Wi-Fi] Legacy Wi-Fi with Driver band Cmd support + * Add back the engineer mode ioctl support + * + * 01 09 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Check in the Add Tx power Cmd to driver. + * + * 01 02 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Adding the proto type function for set_int set_tx_power and get int get_ch_list. + * + * 11 10 2011 cp.wu + * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer + * 1. eliminaite direct calls to printk in porting layer. + * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. + * + * 10 24 2011 terry.wu + * NULL + * Rollback to previous verson due to misbranch check-in + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 07 27 2011 wh.su + * [WCXRP00000877] [MT6620 Wi-Fi][Driver] Remove the netif_carry_ok check for avoid the wpa_supplicant fail to query the ap address + * Remove the netif check while query bssid and ssid + * + * 07 26 2011 chinglan.wang + * NULL + * [MT6620][WiFi Driver] Do not include the WSC IE in the association info packet when not do the wps connection.. + * + * 05 17 2011 eddie.chen + * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning + * Initilize the vairlabes. + * + * 05 11 2011 jeffrey.chang + * [WCXRP00000718] [MT6620 Wi-Fi] modify the behavior of setting tx power + * modify set_tx_pow ioctl + * + * 03 29 2011 terry.wu + * [WCXRP00000610] [MT 6620 Wi-Fi][Driver] Fix klocwork waring + * [MT6620 Wi-Fi][Driver] Fix klocwork warning. Add Null pointer check on wext_get_essid. Limit the upper bound of essid storage array. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 03 07 2011 terry.wu + * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message + * Toggle non-standard debug messages to comments. + * + * 02 21 2011 wh.su + * [WCXRP00000483] [MT6620 Wi-Fi][Driver] Check the kalIoctl return value before doing the memory copy at linux get essid + * fixed the potential error to do a larget memory copy while wlanoid get essid not actually running. + * + * 02 08 2011 george.huang + * [WCXRP00000422] [MT6620 Wi-Fi][Driver] support query power mode OID handler + * Support querying power mode OID. + * + * 01 29 2011 wh.su + * [WCXRP00000408] [MT6620 Wi-Fi][Driver] Not doing memory alloc while ioctl set ie with length 0 + * not doing mem alloc. while set ie length already 0 + * + * 01 20 2011 eddie.chen + * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control + * Remove debug text. + * + * 01 20 2011 eddie.chen + * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control + * Adjust OID order. + * + * 01 20 2011 eddie.chen + * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control + * Add Oid for sw control debug command + * + * 01 11 2011 chinglan.wang + * NULL + * Modify to reslove the CR :[ALPS00028994] Use WEP security to connect Marvell 11N AP. Connection establish successfully. + * Use the WPS function to connect AP, the privacy bit always is set to 1. . + * + * 01 07 2011 cm.chang + * [WCXRP00000336] [MT6620 Wi-Fi][Driver] Add test mode commands in normal phone operation + * Add a new compiling option to control if MCR read/write is permitted + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease physically continous memory demands + * separate kalMemAlloc() into virtually-continous and physically-continous types + * to ease slab system pressure + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease physically continous memory demands + * separate kalMemAlloc() into virtually-continous and physically-continous type to ease slab system pressure + * + * 12 31 2010 cm.chang + * [WCXRP00000336] [MT6620 Wi-Fi][Driver] Add test mode commands in normal phone operation + * Add some iwpriv commands to support test mode operation + * + * 12 15 2010 george.huang + * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function + * Support set PS profile and set WMM-PS related iwpriv. + * + * 12 15 2010 george.huang + * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function + * Allow change PS profile function (throught wext_set_power()). + * + * 12 14 2010 jeffrey.chang + * [WCXRP00000262] [MT6620 Wi-Fi][Driver] modify the scan request ioctl to handle hidden SSID + * handle hidden SSID + * + * 12 13 2010 chinglan.wang + * NULL + * Add WPS 1.0 feature flag to enable the WPS 1.0 function. + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * Fix compiling error + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 11 30 2010 cp.wu + * [WCXRP00000213] [MT6620 Wi-Fi][Driver] Implement scanning with specified SSID for wpa_supplicant with ap_scan=1 + * . + * + * 11 08 2010 wh.su + * [WCXRP00000171] [MT6620 Wi-Fi][Driver] Add message check code same behavior as mt5921 + * add the message check code from mt5921. + * + * 10 19 2010 jeffrey.chang + * [WCXRP00000121] [MT6620 Wi-Fi][Driver] Temporarily disable set power mode ioctl which may cause 6620 to enter power saving + * Temporarily disable set power mode ioctl which may cause MT6620 to enter power saving + * + * 10 18 2010 jeffrey.chang + * [WCXRP00000116] [MT6620 Wi-Fi][Driver] Refine the set_scan ioctl to resolve the Android UI hanging issue + * refine the scan ioctl to prevent hanging of Android UI + * + * 10 01 2010 wh.su + * [WCXRP00000067] [MT6620 Wi-Fi][Driver] Support the android+ WAPI function + * add the scan result with wapi ie. + * + * 09 30 2010 wh.su + * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue + * fixed the wapi ie assigned issue. + * + * 09 27 2010 wh.su + * NULL + * [WCXRP00000067][MT6620 Wi-Fi][Driver] Support the android+ WAPI function. + * + * 09 21 2010 kevin.huang + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * Eliminate Linux Compile Warning + * + * 09 09 2010 cp.wu + * NULL + * add WPS/WPA/RSN IE for Wi-Fi Direct scanning result. + * + * 09 06 2010 cp.wu + * NULL + * Androi/Linux: return current operating channel information + * + * 09 01 2010 wh.su + * NULL + * adding the wapi support for integration test. + * + * 08 02 2010 jeffrey.chang + * NULL + * enable remove key ioctl + * + * 08 02 2010 jeffrey.chang + * NULL + * 1) modify tx service thread to avoid busy looping + * 2) add spin lock declartion for linux build + * + * 07 28 2010 jeffrey.chang + * NULL + * 1) enable encyption ioctls + * 2) temporarily disable remove keys ioctl to prevent TX1 busy + * + * 07 28 2010 jeffrey.chang + * NULL + * 1) remove unused spinlocks + * 2) enable encyption ioctls + * 3) fix scan ioctl which may cause supplicant to hang + * + * 07 19 2010 jeffrey.chang + * + * add kal api for scanning done + * + * 07 19 2010 jeffrey.chang + * + * for linux driver migration + * + * 07 19 2010 jeffrey.chang + * + * Linux port modification + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 28 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * remove unused macro and debug messages + * + * 05 14 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Add dissassoication support for wpa supplicant + * + * 04 22 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * + * 1) modify rx path code for supporting Wi-Fi direct + * 2) modify config.h since Linux dont need to consider retaining packet + * + * 04 21 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * add for private ioctl support + * + * 04 19 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Add ioctl of power management + * + * 04 19 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * remove debug message + * + * 04 14 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * 1) prGlueInfo->pvInformationBuffer and prGlueInfo->u4InformationBufferLength are no longer used + * * 2) fix ioctl + * + * 04 12 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * remove debug messages for pre-release + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * rWlanInfo should be placed at adapter rather than glue due to most operations + * * * * * * * * are done in adapter layer. + * + * 04 02 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * fix ioctl type + * + * 04 01 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * enable pmksa cache operation + * + * 03 31 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * fix ioctl which may cause cmdinfo memory leak + * + * 03 31 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * modify the wapi related code for new driver's design. + * + * 03 30 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * emulate NDIS Pending OID facility + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port +** \main\maintrunk.MT5921\38 2009-10-08 10:33:22 GMT mtk01090 +** Avoid accessing private data of net_device directly. Replace with netdev_priv(). Add more checking for input parameters and pointers. +** \main\maintrunk.MT5921\37 2009-09-29 16:49:48 GMT mtk01090 +** Remove unused variables +** \main\maintrunk.MT5921\36 2009-09-28 20:19:11 GMT mtk01090 +** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. +** \main\maintrunk.MT5921\35 2009-09-03 11:42:30 GMT mtk01088 +** adding the wapi ioctl support +** \main\maintrunk.MT5921\34 2009-08-18 22:56:50 GMT mtk01090 +** Add Linux SDIO (with mmc core) support. +** Add Linux 2.6.21, 2.6.25, 2.6.26. +** Fix compile warning in Linux. +** \main\maintrunk.MT5921\33 2009-05-14 22:43:47 GMT mtk01089 +** fix compiling warning +** \main\maintrunk.MT5921\32 2009-05-07 22:26:18 GMT mtk01089 +** Add mandatory and private IO control for Linux BWCS +** \main\maintrunk.MT5921\31 2009-02-07 15:11:14 GMT mtk01088 +** fixed the compiling error +** \main\maintrunk.MT5921\30 2009-02-07 14:46:51 GMT mtk01088 +** add the privacy setting from linux supplicant ap selection +** \main\maintrunk.MT5921\29 2008-11-19 15:18:50 GMT mtk01088 +** fixed the compling error +** \main\maintrunk.MT5921\28 2008-11-19 11:56:18 GMT mtk01088 +** rename some variable with pre-fix to avoid the misunderstanding +** \main\maintrunk.MT5921\27 2008-08-29 16:59:43 GMT mtk01088 +** fixed compiling error +** \main\maintrunk.MT5921\26 2008-08-29 14:55:53 GMT mtk01088 +** adjust the code for meet the coding style, and add assert check +** \main\maintrunk.MT5921\25 2008-06-02 11:15:19 GMT mtk01461 +** Update after wlanoidSetPowerMode changed +** \main\maintrunk.MT5921\24 2008-05-30 15:13:12 GMT mtk01084 +** rename wlanoid +** \main\maintrunk.MT5921\23 2008-03-28 10:40:28 GMT mtk01461 +** Add set desired rate in Linux STD IOCTL +** \main\maintrunk.MT5921\22 2008-03-18 10:31:24 GMT mtk01088 +** add pmkid ioctl and indicate +** \main\maintrunk.MT5921\21 2008-03-11 15:21:24 GMT mtk01461 +** \main\maintrunk.MT5921\20 2008-03-11 14:50:55 GMT mtk01461 +** Refine WPS related priv ioctl for unified interface +** +** \main\maintrunk.MT5921\19 2008-03-06 16:30:41 GMT mtk01088 +** move the configuration code from set essid function, +** remove the non-used code +** \main\maintrunk.MT5921\18 2008-02-21 15:47:09 GMT mtk01461 +** Fix CR[489] +** \main\maintrunk.MT5921\17 2008-02-12 23:38:31 GMT mtk01461 +** Add Set Frequency & Channel oid support for Linux +** \main\maintrunk.MT5921\16 2008-01-24 12:07:34 GMT mtk01461 +** \main\maintrunk.MT5921\15 2008-01-24 12:00:10 GMT mtk01461 +** Modify the wext_essid for set up correct information for IBSS, and fix the wrong input ptr for prAdapter +** \main\maintrunk.MT5921\14 2007-12-06 09:30:12 GMT mtk01425 +** 1. Branch Test +** \main\maintrunk.MT5921\13 2007-12-04 18:07:59 GMT mtk01461 +** fix typo +** \main\maintrunk.MT5921\12 2007-11-30 17:10:21 GMT mtk01425 +** 1. Fix compiling erros +** +** \main\maintrunk.MT5921\11 2007-11-27 10:43:22 GMT mtk01425 +** 1. Add WMM-PS setting +** \main\maintrunk.MT5921\10 2007-11-06 20:33:32 GMT mtk01088 +** fixed the compiler error +** \main\maintrunk.MT5921\9 2007-11-06 19:33:15 GMT mtk01088 +** add WPS code +** \main\maintrunk.MT5921\8 2007-10-30 12:00:44 GMT MTK01425 +** 1. Update wlanQueryInformation +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "gl_os.h" + +#include "config.h" +#include "wlan_oid.h" + +#include "gl_wext.h" +#include "gl_wext_priv.h" + +#include "precomp.h" + +#if CFG_SUPPORT_WAPI +#include "gl_sec.h" +#endif + +/* compatibility to wireless extensions */ +#ifdef WIRELESS_EXT + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +const long channel_freq[] = { + 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 +}; + +#define MAP_CHANNEL_ID_TO_KHZ(ch, khz) { \ + switch (ch) \ + { \ + case 1: khz = 2412000; break; \ + case 2: khz = 2417000; break; \ + case 3: khz = 2422000; break; \ + case 4: khz = 2427000; break; \ + case 5: khz = 2432000; break; \ + case 6: khz = 2437000; break; \ + case 7: khz = 2442000; break; \ + case 8: khz = 2447000; break; \ + case 9: khz = 2452000; break; \ + case 10: khz = 2457000; break; \ + case 11: khz = 2462000; break; \ + case 12: khz = 2467000; break; \ + case 13: khz = 2472000; break; \ + case 14: khz = 2484000; break; \ + case 36: /* UNII */ khz = 5180000; break; \ + case 40: /* UNII */ khz = 5200000; break; \ + case 44: /* UNII */ khz = 5220000; break; \ + case 48: /* UNII */ khz = 5240000; break; \ + case 52: /* UNII */ khz = 5260000; break; \ + case 56: /* UNII */ khz = 5280000; break; \ + case 60: /* UNII */ khz = 5300000; break; \ + case 64: /* UNII */ khz = 5320000; break; \ + case 149: /* UNII */ khz = 5745000; break; \ + case 153: /* UNII */ khz = 5765000; break; \ + case 157: /* UNII */ khz = 5785000; break; \ + case 161: /* UNII */ khz = 5805000; break; \ + case 165: /* UNII */ khz = 5825000; break; \ + case 100: /* HiperLAN2 */ khz = 5500000; break; \ + case 104: /* HiperLAN2 */ khz = 5520000; break; \ + case 108: /* HiperLAN2 */ khz = 5540000; break; \ + case 112: /* HiperLAN2 */ khz = 5560000; break; \ + case 116: /* HiperLAN2 */ khz = 5580000; break; \ + case 120: /* HiperLAN2 */ khz = 5600000; break; \ + case 124: /* HiperLAN2 */ khz = 5620000; break; \ + case 128: /* HiperLAN2 */ khz = 5640000; break; \ + case 132: /* HiperLAN2 */ khz = 5660000; break; \ + case 136: /* HiperLAN2 */ khz = 5680000; break; \ + case 140: /* HiperLAN2 */ khz = 5700000; break; \ + case 34: /* Japan MMAC */ khz = 5170000; break; \ + case 38: /* Japan MMAC */ khz = 5190000; break; \ + case 42: /* Japan MMAC */ khz = 5210000; break; \ + case 46: /* Japan MMAC */ khz = 5230000; break; \ + case 184: /* Japan */ khz = 4920000; break; \ + case 188: /* Japan */ khz = 4940000; break; \ + case 192: /* Japan */ khz = 4960000; break; \ + case 196: /* Japan */ khz = 4980000; break; \ + case 208: /* Japan, means J08 */ khz = 5040000; break; \ + case 212: /* Japan, means J12 */ khz = 5060000; break; \ + case 216: /* Japan, means J16 */ khz = 5080000; break; \ + default: khz = 2412000; break; \ + } \ + } + + +#define NUM_CHANNELS (sizeof(channel_freq) / sizeof(channel_freq[0])) + +#define MAX_SSID_LEN 32 + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +/* NOTE: name in iwpriv_args only have 16 bytes */ +static const struct iw_priv_args rIwPrivTable[] = { + {IOCTL_SET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, ""}, + {IOCTL_GET_INT, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ""}, + {IOCTL_SET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, ""}, + {IOCTL_GET_INT, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, ""}, + {IOCTL_SET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, ""}, + + {IOCTL_GET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ""}, + {IOCTL_GET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ""}, + + {IOCTL_SET_INTS, IW_PRIV_TYPE_INT | 4, 0, ""}, + {IOCTL_GET_INT, 0, IW_PRIV_TYPE_INT | 50, ""}, + + /* added for set_oid and get_oid */ + {IOCTL_SET_STRUCT, 256, 0, ""}, + {IOCTL_GET_STRUCT, 0, 256, ""}, + + /* sub-ioctl definitions */ +#if 0 + {PRIV_CMD_REG_DOMAIN, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_reg_domain" }, + {PRIV_CMD_REG_DOMAIN, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_reg_domain" }, +#endif + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + {PRIV_CMD_CSUM_OFFLOAD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_tcp_csum" }, +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + + {PRIV_CMD_POWER_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_power_mode" }, + {PRIV_CMD_POWER_MODE, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_power_mode" }, + + {PRIV_CMD_WMM_PS, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "set_wmm_ps" }, + + {PRIV_CMD_TEST_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_test_mode" }, + {PRIV_CMD_TEST_CMD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_test_cmd" }, + {PRIV_CMD_TEST_CMD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_test_result" }, +#if CFG_SUPPORT_PRIV_MCR_RW + {PRIV_CMD_ACCESS_MCR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_mcr" }, + {PRIV_CMD_ACCESS_MCR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_mcr" }, +#endif + {PRIV_CMD_SW_CTRL, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_sw_ctrl" }, + {PRIV_CMD_SW_CTRL, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_sw_ctrl" }, + +#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS + {PRIV_CUSTOM_BWCS_CMD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_bwcs"}, + /* GET STRUCT sub-ioctls commands */ + {PRIV_CUSTOM_BWCS_CMD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_bwcs"}, +#endif + + /* SET STRUCT sub-ioctls commands */ + {PRIV_CMD_OID, 256, 0, "set_oid"}, + /* GET STRUCT sub-ioctls commands */ + {PRIV_CMD_OID, 0, 256, "get_oid"}, + + {PRIV_CMD_SET_TX_POWER, IW_PRIV_TYPE_INT | 4, 0, "set_txpower" }, + {PRIV_CMD_GET_CH_LIST, 0, IW_PRIV_TYPE_INT | 50, "get_ch_list" } +}; + +static const iw_handler rIwPrivHandler[] = { + [IOCTL_SET_INT - SIOCIWFIRSTPRIV] = priv_set_int, + [IOCTL_GET_INT - SIOCIWFIRSTPRIV] = priv_get_int, + [IOCTL_SET_ADDRESS - SIOCIWFIRSTPRIV] = NULL, + [IOCTL_GET_ADDRESS - SIOCIWFIRSTPRIV] = NULL, + [IOCTL_SET_STR - SIOCIWFIRSTPRIV] = NULL, + [IOCTL_GET_STR - SIOCIWFIRSTPRIV] = NULL, + [IOCTL_SET_KEY - SIOCIWFIRSTPRIV] = NULL, + [IOCTL_GET_KEY - SIOCIWFIRSTPRIV] = NULL, + [IOCTL_SET_STRUCT - SIOCIWFIRSTPRIV] = priv_set_struct, + [IOCTL_GET_STRUCT - SIOCIWFIRSTPRIV] = priv_get_struct, + [IOCTL_SET_STRUCT_FOR_EM - SIOCIWFIRSTPRIV] = priv_set_struct, + [IOCTL_SET_INTS - SIOCIWFIRSTPRIV] = priv_set_ints, + [IOCTL_GET_INTS - SIOCIWFIRSTPRIV] = priv_get_ints, +}; + +const struct iw_handler_def wext_handler_def = { + .num_standard = 0, + .num_private = (__u16)sizeof(rIwPrivHandler)/sizeof(iw_handler), + .num_private_args = (__u16)sizeof(rIwPrivTable)/sizeof(struct iw_priv_args), + .standard = (iw_handler *) NULL, + .private = rIwPrivHandler, + .private_args = rIwPrivTable, + .get_wireless_stats = wext_get_wireless_stats, +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Find the desired WPA/RSN Information Element according to desiredElemID. +* +* \param[in] pucIEStart IE starting address. +* \param[in] i4TotalIeLen Total length of all the IE. +* \param[in] ucDesiredElemId Desired element ID. +* \param[out] ppucDesiredIE Pointer to the desired IE. +* +* \retval TRUE Find the desired IE. +* \retval FALSE Desired IE not found. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +wextSrchDesiredWPAIE ( + IN PUINT_8 pucIEStart, + IN INT_32 i4TotalIeLen, + IN UINT_8 ucDesiredElemId, + OUT PUINT_8 *ppucDesiredIE + ) +{ + INT_32 i4InfoElemLen; + + ASSERT(pucIEStart); + ASSERT(ppucDesiredIE); + + while (i4TotalIeLen >= 2) { + i4InfoElemLen = (INT_32) pucIEStart[1] + 2; + + if (pucIEStart[0] == ucDesiredElemId && i4InfoElemLen <= i4TotalIeLen) { + if (ucDesiredElemId != 0xDD) { + /* Non 0xDD, OK! */ + *ppucDesiredIE = &pucIEStart[0]; + return TRUE; + } + else { + /* EID == 0xDD, check WPA IE */ + if (pucIEStart[1] >= 4) { + if (memcmp(&pucIEStart[2], "\x00\x50\xf2\x01", 4) == 0) { + *ppucDesiredIE = &pucIEStart[0]; + return TRUE; + } + } /* check WPA IE length */ + } /* check EID == 0xDD */ + } /* check desired EID */ + + /* Select next information element. */ + i4TotalIeLen -= i4InfoElemLen; + pucIEStart += i4InfoElemLen; + } + + return FALSE; +} /* parseSearchDesiredWPAIE */ + + +#if CFG_SUPPORT_WAPI +/*----------------------------------------------------------------------------*/ +/*! +* \brief Find the desired WAPI Information Element . +* +* \param[in] pucIEStart IE starting address. +* \param[in] i4TotalIeLen Total length of all the IE. +* \param[out] ppucDesiredIE Pointer to the desired IE. +* +* \retval TRUE Find the desired IE. +* \retval FALSE Desired IE not found. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +wextSrchDesiredWAPIIE ( + IN PUINT_8 pucIEStart, + IN INT_32 i4TotalIeLen, + OUT PUINT_8 *ppucDesiredIE + ) +{ + INT_32 i4InfoElemLen; + + ASSERT(pucIEStart); + ASSERT(ppucDesiredIE); + + while (i4TotalIeLen >= 2) { + i4InfoElemLen = (INT_32) pucIEStart[1] + 2; + + if (pucIEStart[0] == ELEM_ID_WAPI && i4InfoElemLen <= i4TotalIeLen) { + *ppucDesiredIE = &pucIEStart[0]; + return TRUE; + } /* check desired EID */ + + /* Select next information element. */ + i4TotalIeLen -= i4InfoElemLen; + pucIEStart += i4InfoElemLen; + } + + return FALSE; +} /* wextSrchDesiredWAPIIE */ +#endif + + +#if CFG_SUPPORT_WPS +/*----------------------------------------------------------------------------*/ +/*! +* \brief Find the desired WPS Information Element according to desiredElemID. +* +* \param[in] pucIEStart IE starting address. +* \param[in] i4TotalIeLen Total length of all the IE. +* \param[in] ucDesiredElemId Desired element ID. +* \param[out] ppucDesiredIE Pointer to the desired IE. +* +* \retval TRUE Find the desired IE. +* \retval FALSE Desired IE not found. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +wextSrchDesiredWPSIE ( + IN PUINT_8 pucIEStart, + IN INT_32 i4TotalIeLen, + IN UINT_8 ucDesiredElemId, + OUT PUINT_8 *ppucDesiredIE) +{ + INT_32 i4InfoElemLen; + + ASSERT(pucIEStart); + ASSERT(ppucDesiredIE); + + while (i4TotalIeLen >= 2) { + i4InfoElemLen = (INT_32) pucIEStart[1] + 2; + + if (pucIEStart[0] == ucDesiredElemId && i4InfoElemLen <= i4TotalIeLen) { + if (ucDesiredElemId != 0xDD) { + /* Non 0xDD, OK! */ + *ppucDesiredIE = &pucIEStart[0]; + return TRUE; + } + else { + /* EID == 0xDD, check WPS IE */ + if (pucIEStart[1] >= 4) { + if (memcmp(&pucIEStart[2], "\x00\x50\xf2\x04", 4) == 0) { + *ppucDesiredIE = &pucIEStart[0]; + return TRUE; + } + } /* check WPS IE length */ + } /* check EID == 0xDD */ + } /* check desired EID */ + + /* Select next information element. */ + i4TotalIeLen -= i4InfoElemLen; + pucIEStart += i4InfoElemLen; + } + + return FALSE; +} /* parseSearchDesiredWPSIE */ +#endif + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Get the name of the protocol used on the air. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[out] pcName Buffer to store protocol name string +* \param[in] pcExtra NULL. +* +* \retval 0 For success. +* +* \note If netif_carrier_ok, protocol name is returned; +* otherwise, "disconnected" is returned. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_get_name ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + OUT char *pcName, + IN char *pcExtra + ) +{ + ENUM_PARAM_NETWORK_TYPE_T eNetWorkType; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(pcName); + if (FALSE == GLUE_CHK_PR2(prNetDev, pcName)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T)netdev_priv(prNetDev); + + if (netif_carrier_ok(prNetDev)) { + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryNetworkTypeInUse, + &eNetWorkType, + sizeof(eNetWorkType), + TRUE, + FALSE, + FALSE, + FALSE, + &u4BufLen); + + /* strcpy(pucName, "IEEE 802.11bg"); */ + + // to fix + + #if 0 + + sprintf(pcName, + "IEEE 802.11%s", + (eNetWorkType == NETWORK_TYPE_OFDM24) ? "g/n" : "b"); + + #endif + } + else { + strcpy(pcName, "Disconnected"); + } + + return 0; +} /* wext_get_name */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set the operating channel in the wireless device. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL +* \param[in] prFreq Buffer to store frequency information +* \param[in] pcExtra NULL +* +* \retval 0 For success. +* \retval -EOPNOTSUPP If infrastructure mode is not NET NET_TYPE_IBSS. +* \retval -EINVAL Invalid channel frequency. +* +* \note If infrastructure mode is IBSS, new channel frequency is set to device. +* The range of channel number depends on different regulatory domain. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_set_freq ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN struct iw_freq *prIwFreq, + IN char *pcExtra + ) +{ + +#if 0 + UINT_32 u4ChnlFreq; /* Store channel or frequency information */ + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prIwFreq); + if (FALSE == GLUE_CHK_PR2(prNetDev, prIwFreq)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T)netdev_priv(prNetDev); + + /* + printk("set m:%d, e:%d, i:%d, flags:%d\n", + prIwFreq->m, prIwFreq->e, prIwFreq->i, prIwFreq->flags); + */ + + /* If setting by frequency, convert to a channel */ + if ((prIwFreq->e == 1) && + (prIwFreq->m >= (int) 2.412e8) && + (prIwFreq->m <= (int) 2.484e8)) { + + /* Change to KHz format */ + u4ChnlFreq = (UINT_32)(prIwFreq->m / (KILO / 10)); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetFrequency, + &u4ChnlFreq, + sizeof(u4ChnlFreq), + FALSE, + FALSE, + FALSE, + &u4BufLen); + + if (WLAN_STATUS_SUCCESS != rStatus) { + return -EINVAL; + } + } + /* Setting by channel number */ + else if ((prIwFreq->m > KILO) || (prIwFreq->e > 0)) { + return -EOPNOTSUPP; + } + else { + /* Change to channel number format */ + u4ChnlFreq = (UINT_32)prIwFreq->m; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetChannel, + &u4ChnlFreq, + sizeof(u4ChnlFreq), + FALSE, + FALSE, + FALSE, + &u4BufLen); + + + + + if (WLAN_STATUS_SUCCESS != rStatus) { + return -EINVAL; + } + } + +#endif + + return 0; + +} /* wext_set_freq */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To get the operating channel in the wireless device. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[out] prFreq Buffer to store frequency information. +* \param[in] pcExtra NULL. +* +* \retval 0 If netif_carrier_ok. +* \retval -ENOTCONN Otherwise +* +* \note If netif_carrier_ok, channel frequency information is stored in pFreq. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_get_freq ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + OUT struct iw_freq *prIwFreq, + IN char *pcExtra + ) +{ + UINT_32 u4Channel = 0; + + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prIwFreq); + if (FALSE == GLUE_CHK_PR2(prNetDev, prIwFreq)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prNetDev); + + /* GeorgeKuo: TODO skip checking in IBSS mode */ + if (!netif_carrier_ok(prNetDev)) { + return -ENOTCONN; + } + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryFrequency, + &u4Channel, + sizeof(u4Channel), + TRUE, + FALSE, + FALSE, + FALSE, + &u4BufLen); + + prIwFreq->m = (int) u4Channel; /* freq in KHz */ + prIwFreq->e = 3; + + return 0; + +} /* wext_get_freq */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set operating mode. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] pu4Mode Pointer to new operation mode. +* \param[in] pcExtra NULL. +* +* \retval 0 For success. +* \retval -EOPNOTSUPP If new mode is not supported. +* +* \note Device will run in new operation mode if it is valid. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_set_mode ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN unsigned int *pu4Mode, + IN char *pcExtra + ) +{ + ENUM_PARAM_OP_MODE_T eOpMode; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(pu4Mode); + if (FALSE == GLUE_CHK_PR2(prNetDev, pu4Mode)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T)netdev_priv(prNetDev); + + switch (*pu4Mode) { + case IW_MODE_AUTO: + eOpMode = NET_TYPE_AUTO_SWITCH; + break; + + case IW_MODE_ADHOC: + eOpMode = NET_TYPE_IBSS; + break; + + case IW_MODE_INFRA: + eOpMode = NET_TYPE_INFRA; + break; + + default: + DBGLOG(INIT, INFO, ("%s(): Set UNSUPPORTED Mode = %d.\n", __FUNCTION__, *pu4Mode)); + return -EOPNOTSUPP; + } + + //printk("%s(): Set Mode = %d\n", __FUNCTION__, *pu4Mode); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetInfrastructureMode, + &eOpMode, + sizeof(eOpMode), + FALSE, + FALSE, + TRUE, + FALSE, + &u4BufLen); + + + /* after set operation mode, key table are cleared */ + + /* reset wpa info */ + prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + prGlueInfo->rWpaInfo.u4KeyMgmt = 0; + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE; + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE; + prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; +#if CFG_SUPPORT_802_11W + prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; +#endif + + return 0; +} /* wext_set_mode */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To get operating mode. +* +* \param[in] prNetDev Net device requested. +* \param[in] prIwReqInfo NULL. +* \param[out] pu4Mode Buffer to store operating mode information. +* \param[in] pcExtra NULL. +* +* \retval 0 If data is valid. +* \retval -EINVAL Otherwise. +* +* \note If netif_carrier_ok, operating mode information is stored in pu4Mode. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_get_mode ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + OUT unsigned int *pu4Mode, + IN char *pcExtra + ) +{ + ENUM_PARAM_OP_MODE_T eOpMode; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(pu4Mode); + if (FALSE == GLUE_CHK_PR2(prNetDev, pu4Mode)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T)netdev_priv(prNetDev); + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryInfrastructureMode, + &eOpMode, + sizeof(eOpMode), + TRUE, + FALSE, + FALSE, + FALSE, + &u4BufLen); + + + + switch (eOpMode){ + case NET_TYPE_IBSS: + *pu4Mode = IW_MODE_ADHOC; + break; + + case NET_TYPE_INFRA: + *pu4Mode = IW_MODE_INFRA; + break; + + case NET_TYPE_AUTO_SWITCH: + *pu4Mode = IW_MODE_AUTO; + break; + + default: + DBGLOG(INIT, INFO, ("%s(): Get UNKNOWN Mode.\n", __FUNCTION__)); + return -EINVAL; + } + + return 0; +} /* wext_get_mode */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To get the valid range for each configurable STA setting value. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] prData Pointer to iw_point structure, not used. +* \param[out] pcExtra Pointer to buffer which is allocated by caller of this +* function, wext_support_ioctl() or ioctl_standard_call() in +* wireless.c. +* +* \retval 0 If data is valid. +* +* \note The extra buffer (pcExtra) is filled with information from driver. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_get_range ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + IN struct iw_point *prData, + OUT char *pcExtra + ) +{ + struct iw_range *prRange = NULL; + PARAM_RATES_EX aucSuppRate = {0}; /* data buffers */ + int i = 0; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(pcExtra); + if (FALSE == GLUE_CHK_PR2(prNetDev, pcExtra)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T)netdev_priv(prNetDev); + + prRange = (struct iw_range *) pcExtra; + + memset(prRange, 0, sizeof(*prRange)); + prRange->throughput = 20000000; /* 20Mbps */ + prRange->min_nwid = 0; /* not used */ + prRange->max_nwid = 0; /* not used */ + + /* scan_capa not implemented */ + + /* event_capa[6]: kernel + driver capabilities */ + prRange->event_capa[0] = (IW_EVENT_CAPA_K_0 + | IW_EVENT_CAPA_MASK(SIOCGIWAP) + | IW_EVENT_CAPA_MASK(SIOCGIWSCAN) + /* can't display meaningful string in iwlist + | IW_EVENT_CAPA_MASK(SIOCGIWTXPOW) + | IW_EVENT_CAPA_MASK(IWEVMICHAELMICFAILURE) + | IW_EVENT_CAPA_MASK(IWEVASSOCREQIE) + | IW_EVENT_CAPA_MASK(IWEVPMKIDCAND) + */ + ); + prRange->event_capa[1] = IW_EVENT_CAPA_K_1; + + /* report 2.4G channel and frequency only */ + prRange->num_channels = (__u16) NUM_CHANNELS; + prRange->num_frequency = (__u8) NUM_CHANNELS; + for (i = 0; i < NUM_CHANNELS; i++) { + /* iwlib takes this number as channel number */ + prRange->freq[i].i = i + 1; + prRange->freq[i].m = channel_freq[i]; + prRange->freq[i].e = 6; /* Values in table in MHz */ + } + + rStatus = kalIoctl( + prGlueInfo, + wlanoidQuerySupportedRates, + &aucSuppRate, + sizeof(aucSuppRate), + TRUE, + FALSE, + FALSE, + FALSE, + &u4BufLen); + + + + for (i = 0; i < IW_MAX_BITRATES && i < PARAM_MAX_LEN_RATES_EX ; i++) { + if (aucSuppRate[i] == 0) { + break; + } + prRange->bitrate[i] = (aucSuppRate[i] & 0x7F) * 500000; /* 0.5Mbps */ + } + prRange->num_bitrates = i; + + prRange->min_rts = 0; + prRange->max_rts = 2347; + prRange->min_frag = 256; + prRange->max_frag = 2346; + + prRange->min_pmp = 0; /* power management by driver */ + prRange->max_pmp = 0; /* power management by driver */ + prRange->min_pmt = 0; /* power management by driver */ + prRange->max_pmt = 0; /* power management by driver */ + prRange->pmp_flags = IW_POWER_RELATIVE; /* pm default flag */ + prRange->pmt_flags = IW_POWER_ON; /* pm timeout flag */ + prRange->pm_capa = IW_POWER_ON; /* power management by driver */ + + prRange->encoding_size[0] = 5; /* wep40 */ + prRange->encoding_size[1] = 16; /* tkip */ + prRange->encoding_size[2] = 16; /* ckip */ + prRange->encoding_size[3] = 16; /* ccmp */ + prRange->encoding_size[4] = 13; /* wep104 */ + prRange->encoding_size[5] = 16; /* wep128 */ + prRange->num_encoding_sizes = 6; + prRange->max_encoding_tokens = 6; /* token? */ + +#if WIRELESS_EXT < 17 + prRange->txpower_capa = 0x0002; /* IW_TXPOW_RELATIVE */ +#else + prRange->txpower_capa = IW_TXPOW_RELATIVE; +#endif + prRange->num_txpower = 5; + prRange->txpower[0] = 0; /* minimum */ + prRange->txpower[1] = 25; /* 25% */ + prRange->txpower[2] = 50; /* 50% */ + prRange->txpower[3] = 100; /* 100% */ + + prRange->we_version_compiled = WIRELESS_EXT; + prRange->we_version_source = WIRELESS_EXT; + + prRange->retry_capa = IW_RETRY_LIMIT; + prRange->retry_flags = IW_RETRY_LIMIT; + prRange->min_retry = 7; + prRange->max_retry = 7; + prRange->r_time_flags = IW_RETRY_ON; + prRange->min_r_time = 0; + prRange->max_r_time = 0; + + /* signal strength and link quality */ + /* Just define range here, reporting value moved to wext_get_stats() */ + prRange->sensitivity = -83; /* fixed value */ + prRange->max_qual.qual = 100; /* max 100% */ + prRange->max_qual.level = (__u8)(0x100 - 0); /* max 0 dbm */ + prRange->max_qual.noise = (__u8)(0x100 - 0); /* max 0 dbm */ + + /* enc_capa */ +#if WIRELESS_EXT > 17 + prRange->enc_capa = IW_ENC_CAPA_WPA | + IW_ENC_CAPA_WPA2 | + IW_ENC_CAPA_CIPHER_TKIP | + IW_ENC_CAPA_CIPHER_CCMP; +#endif + + /* min_pms; Minimal PM saving */ + /* max_pms; Maximal PM saving */ + /* pms_flags; How to decode max/min PM saving */ + + /* modul_capa; IW_MODUL_* bit field */ + /* bitrate_capa; Types of bitrates supported */ + + return 0; +} /* wext_get_range */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set BSSID of AP to connect. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] prAddr Pointer to struct sockaddr structure containing AP's BSSID. +* \param[in] pcExtra NULL. +* +* \retval 0 For success. +* +* \note Desired AP's BSSID is set to driver. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_set_ap ( + IN struct net_device *prDev, + IN struct iw_request_info *prIwrInfo, + IN struct sockaddr *prAddr, + IN char *pcExtra + ) +{ + return 0; +} /* wext_set_ap */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To get AP MAC address. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[out] prAddr Pointer to struct sockaddr structure storing AP's BSSID. +* \param[in] pcExtra NULL. +* +* \retval 0 If netif_carrier_ok. +* \retval -ENOTCONN Otherwise. +* +* \note If netif_carrier_ok, AP's mac address is stored in pAddr->sa_data. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_get_ap ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + OUT struct sockaddr *prAddr, + IN char *pcExtra + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prAddr); + if (FALSE == GLUE_CHK_PR2(prNetDev, prAddr)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T)netdev_priv(prNetDev); + + //if (!netif_carrier_ok(prNetDev)) { + // return -ENOTCONN; + //} + + if(prGlueInfo->eParamMediaStateIndicated == PARAM_MEDIA_STATE_DISCONNECTED){ + memset(prAddr, 0, 6); + return 0; + } + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryBssid, + prAddr->sa_data, + ETH_ALEN, + TRUE, + FALSE, + FALSE, + FALSE, + &u4BufLen); + + return 0; +} /* wext_get_ap */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set mlme operation request. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] prData Pointer of iw_point header. +* \param[in] pcExtra Pointer to iw_mlme structure mlme request information. +* +* \retval 0 For success. +* \retval -EOPNOTSUPP unsupported IW_MLME_ command. +* \retval -EINVAL Set MLME Fail, different bssid. +* +* \note Driver will start mlme operation if valid. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_set_mlme ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + IN struct iw_point *prData, + IN char *pcExtra + ) +{ + struct iw_mlme *prMlme = NULL; + + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(pcExtra); + if (FALSE == GLUE_CHK_PR2(prNetDev, pcExtra)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T)netdev_priv(prNetDev); + + prMlme = (struct iw_mlme *)pcExtra; + if (prMlme->cmd == IW_MLME_DEAUTH || prMlme->cmd == IW_MLME_DISASSOC) { + if (!netif_carrier_ok(prNetDev)) { + DBGLOG(INIT, INFO, ("[wifi] Set MLME Deauth/Disassoc, but netif_carrier_off\n")); + return 0; + } + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetDisassociate, + NULL, + 0, + FALSE, + FALSE, + TRUE, + FALSE, + &u4BufLen); + return 0; + } + else { + DBGLOG(INIT, INFO, ("[wifi] unsupported IW_MLME_ command :%d\n", prMlme->cmd)); + return -EOPNOTSUPP; + } +} /* wext_set_mlme */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To issue scan request. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] prData NULL. +* \param[in] pcExtra NULL. +* +* \retval 0 For success. +* \retval -EFAULT Tx power is off. +* +* \note Device will start scanning. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_set_scan ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + IN union iwreq_data *prData, + IN char *pcExtra + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + int essid_len = 0; + + ASSERT(prNetDev); + if (FALSE == GLUE_CHK_DEV(prNetDev)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prNetDev); + +#if WIRELESS_EXT > 17 + /* retrieve SSID */ + if(prData) { + essid_len = ((struct iw_scan_req *)(((struct iw_point*)prData)->pointer))->essid_len; + } +#endif + + init_completion(&prGlueInfo->rScanComp); + + // TODO: parse flags and issue different scan requests? + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetBssidListScan, + pcExtra, + essid_len, + FALSE, + FALSE, + FALSE, + FALSE, + &u4BufLen); + + //wait_for_completion_interruptible_timeout(&prGlueInfo->rScanComp, 2 * KAL_HZ); + //kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_SCAN_COMPLETE, NULL, 0); + + + return 0; +} /* wext_set_scan */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To write the ie to buffer +* +*/ +/*----------------------------------------------------------------------------*/ +static inline int snprintf_hex(char *buf, size_t buf_size, const u8 *data, + size_t len) +{ + size_t i; + char *pos = buf, *end = buf + buf_size; + int ret; + + if (buf_size == 0) + return 0; + + for (i = 0; i < len; i++) { + ret = snprintf(pos, end - pos, "%02x", + data[i]); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return pos - buf; + } + pos += ret; + } + end[-1] = '\0'; + return pos - buf; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To get scan results, transform results from driver's format to WE's. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[out] prData Pointer to iw_point structure, pData->length is the size of +* pcExtra buffer before used, and is updated after filling scan +* results. +* \param[out] pcExtra Pointer to buffer which is allocated by caller of this +* function, wext_support_ioctl() or ioctl_standard_call() in +* wireless.c. +* +* \retval 0 For success. +* \retval -ENOMEM If dynamic memory allocation fail. +* \retval -E2BIG Invalid length. +* +* \note Scan results is filled into pcExtra buffer, data size is updated in +* pData->length. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_get_scan ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + IN OUT struct iw_point *prData, + IN char *pcExtra + ) +{ + UINT_32 i = 0; + UINT_32 j = 0; + P_PARAM_BSSID_LIST_EX_T prList = NULL; + P_PARAM_BSSID_EX_T prBss = NULL; + P_PARAM_VARIABLE_IE_T prDesiredIE = NULL; + struct iw_event iwEvent; /* local iw_event buffer */ + + /* write pointer of extra buffer */ + char *pcCur = NULL; + /* pointer to the end of last full entry in extra buffer */ + char *pcValidEntryEnd = NULL; + char *pcEnd = NULL; /* end of extra buffer */ + + UINT_32 u4AllocBufLen = 0; + + /* arrange rate information */ + UINT_32 u4HighestRate = 0; + char aucRatesBuf[64]; + UINT_32 u4BufIndex; + + /* return value */ + int ret = 0; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prData); + ASSERT(pcExtra); + if (FALSE == GLUE_CHK_PR3(prNetDev, prData, pcExtra)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T)netdev_priv(prNetDev); + + /* Initialize local variables */ + pcCur = pcExtra; + pcValidEntryEnd = pcExtra; + pcEnd = pcExtra + prData->length; /* end of extra buffer */ + + /* Allocate another query buffer with the same size of extra buffer */ + u4AllocBufLen = prData->length; + prList = kalMemAlloc(u4AllocBufLen, VIR_MEM_TYPE); + if (prList == NULL) { + DBGLOG(INIT, INFO, ("[wifi] no memory for scan list:%d\n", prData->length)); + ret = -ENOMEM; + goto error; + } + prList->u4NumberOfItems = 0; + + /* wait scan done */ + //printk ("wait for scan results\n"); + //wait_for_completion_interruptible_timeout(&prGlueInfo->rScanComp, 4 * KAL_HZ); + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryBssidList, + prList, + u4AllocBufLen, + TRUE, + FALSE, + FALSE, + FALSE, + &u4BufLen); + + if (rStatus == WLAN_STATUS_INVALID_LENGTH) { + /* Buffer length is not large enough. */ + //printk(KERN_INFO "[wifi] buf:%d result:%ld\n", pData->length, u4BufLen); + +#if WIRELESS_EXT >= 17 + /* This feature is supported in WE-17 or above, limited by iwlist. + ** Return -E2BIG and iwlist will request again with a larger buffer. + */ + ret = -E2BIG; + /* Update length to give application a hint on result length */ + prData->length = (__u16)u4BufLen; + goto error; +#else + /* Realloc a larger query buffer here, but don't write too much to extra + ** buffer when filling it later. + */ + kalMemFree(prList, VIR_MEM_TYPE, u4AllocBufLen); + + u4AllocBufLen = u4BufLen; + prList = kalMemAlloc(u4AllocBufLen, VIR_MEM_TYPE); + if (prList == NULL) { + DBGLOG(INIT, INFO, ("[wifi] no memory for larger scan list :%ld\n", u4BufLen)); + ret = -ENOMEM; + goto error; + } + prList->NumberOfItems = 0; + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryBssidList, + prList, + u4AllocBufLen, + TRUE, + FALSE, + FALSE, + FALSE, + &u4BufLen); + + if (rStatus == WLAN_STATUS_INVALID_LENGTH) { + DBGLOG(INIT, INFO, ("[wifi] larger buf:%d result:%ld\n", u4AllocBufLen, u4BufLen)); + ret = -E2BIG; + prData->length = (__u16)u4BufLen; + goto error; + } +#endif /* WIRELESS_EXT >= 17 */ + + } + + + if (prList->u4NumberOfItems > CFG_MAX_NUM_BSS_LIST) { + DBGLOG(INIT, INFO, ("[wifi] strange scan result count:%ld\n", + prList->u4NumberOfItems)); + goto error; + } + + /* Copy required data from pList to pcExtra */ + prBss = &prList->arBssid[0]; /* set to the first entry */ + for (i = 0; i < prList->u4NumberOfItems; ++i) { + /* BSSID */ + iwEvent.cmd = SIOCGIWAP; + iwEvent.len = IW_EV_ADDR_LEN; + if ((pcCur + iwEvent.len) > pcEnd) + break; + iwEvent.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwEvent.u.ap_addr.sa_data, prBss->arMacAddress, ETH_ALEN); + memcpy(pcCur, &iwEvent, IW_EV_ADDR_LEN); + pcCur += IW_EV_ADDR_LEN; + + /* SSID */ + iwEvent.cmd = SIOCGIWESSID; + /* Modification to user space pointer(essid.pointer) is not needed. */ + iwEvent.u.essid.length = (__u16)prBss->rSsid.u4SsidLen; + iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.essid.length; + + if ((pcCur + iwEvent.len) > pcEnd) + break; + iwEvent.u.essid.flags = 1; + iwEvent.u.essid.pointer = NULL; + +#if WIRELESS_EXT <= 18 + memcpy(pcCur, &iwEvent, iwEvent.len); +#else + memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); + memcpy(pcCur + IW_EV_LCP_LEN, + &iwEvent.u.data.length, + sizeof(struct iw_point) - IW_EV_POINT_OFF); +#endif + memcpy(pcCur + IW_EV_POINT_LEN, prBss->rSsid.aucSsid, iwEvent.u.essid.length); + pcCur += iwEvent.len; + /* Frequency */ + iwEvent.cmd = SIOCGIWFREQ; + iwEvent.len = IW_EV_FREQ_LEN; + if ((pcCur + iwEvent.len) > pcEnd) + break; + iwEvent.u.freq.m = prBss->rConfiguration.u4DSConfig; + iwEvent.u.freq.e = 3; /* (in KHz) */ + iwEvent.u.freq.i = 0; + memcpy(pcCur, &iwEvent, IW_EV_FREQ_LEN); + pcCur += IW_EV_FREQ_LEN; + + /* Operation Mode */ + iwEvent.cmd = SIOCGIWMODE; + iwEvent.len = IW_EV_UINT_LEN; + if ((pcCur + iwEvent.len) > pcEnd) + break; + if (prBss->eOpMode == NET_TYPE_IBSS) { + iwEvent.u.mode = IW_MODE_ADHOC; + } + else if (prBss->eOpMode == NET_TYPE_INFRA) { + iwEvent.u.mode = IW_MODE_INFRA; + } + else { + iwEvent.u.mode = IW_MODE_AUTO; + } + memcpy(pcCur, &iwEvent, IW_EV_UINT_LEN); + pcCur += IW_EV_UINT_LEN; + + /* Quality */ + iwEvent.cmd = IWEVQUAL; + iwEvent.len = IW_EV_QUAL_LEN; + if ((pcCur + iwEvent.len) > pcEnd) + break; + iwEvent.u.qual.qual = 0; /* Quality not available now */ + /* -100 < Rssi < -10, normalized by adding 0x100 */ + iwEvent.u.qual.level = 0x100 + prBss->rRssi; + iwEvent.u.qual.noise = 0; /* Noise not available now */ + iwEvent.u.qual.updated = IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_UPDATED \ + | IW_QUAL_NOISE_INVALID; + memcpy(pcCur, &iwEvent, IW_EV_QUAL_LEN); + pcCur += IW_EV_QUAL_LEN; + + /* Security Mode*/ + iwEvent.cmd = SIOCGIWENCODE; + iwEvent.len = IW_EV_POINT_LEN; + if ((pcCur + iwEvent.len) > pcEnd) + break; + iwEvent.u.data.pointer = NULL; + iwEvent.u.data.flags = 0; + iwEvent.u.data.length = 0; + if(!prBss->u4Privacy) { + iwEvent.u.data.flags |= IW_ENCODE_DISABLED; + } +#if WIRELESS_EXT <= 18 + memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); +#else + memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); + memcpy(pcCur + IW_EV_LCP_LEN, + &iwEvent.u.data.length, + sizeof(struct iw_point) - IW_EV_POINT_OFF); +#endif + pcCur += IW_EV_POINT_LEN; + + /* rearrange rate information */ + u4BufIndex = sprintf(aucRatesBuf, "Rates (Mb/s):"); + u4HighestRate = 0; + for (j = 0; j < PARAM_MAX_LEN_RATES_EX; ++j) { + UINT_8 curRate = prBss->rSupportedRates[j] & 0x7F; + if (curRate == 0) { + break; + } + + if (curRate > u4HighestRate) { + u4HighestRate = curRate; + } + + if (curRate == RATE_5_5M) { + u4BufIndex += sprintf(aucRatesBuf + u4BufIndex, " 5.5"); + } + else { + u4BufIndex += sprintf(aucRatesBuf + u4BufIndex, " %d", curRate / 2); + } + #if DBG + if (u4BufIndex > sizeof(aucRatesBuf)) { + //printk("rate info too long\n"); + break; + } + #endif + } + /* Report Highest Rates */ + iwEvent.cmd = SIOCGIWRATE; + iwEvent.len = IW_EV_PARAM_LEN; + if ((pcCur + iwEvent.len) > pcEnd) + break; + iwEvent.u.bitrate.value = u4HighestRate * 500000; + iwEvent.u.bitrate.fixed = 0; + iwEvent.u.bitrate.disabled = 0; + iwEvent.u.bitrate.flags = 0; + memcpy(pcCur, &iwEvent, iwEvent.len); + pcCur += iwEvent.len; + + #if WIRELESS_EXT >= 15 /* IWEVCUSTOM is available in WE-15 or above */ + /* Report Residual Rates */ + iwEvent.cmd = IWEVCUSTOM; + iwEvent.u.data.length = u4BufIndex; + iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; + if ((pcCur + iwEvent.len) > pcEnd) + break; + iwEvent.u.data.flags = 0; + #if WIRELESS_EXT <= 18 + memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); + #else + memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); + memcpy(pcCur + IW_EV_LCP_LEN, + &iwEvent.u.data.length, + sizeof(struct iw_point) - IW_EV_POINT_OFF); + #endif + memcpy(pcCur + IW_EV_POINT_LEN, aucRatesBuf, u4BufIndex); + pcCur += iwEvent.len; + #endif /* WIRELESS_EXT >= 15 */ + + + if (wextSrchDesiredWPAIE(&prBss->aucIEs[sizeof(PARAM_FIXED_IEs)], + prBss->u4IELength - sizeof(PARAM_FIXED_IEs), + 0xDD, + (PUINT_8 *)&prDesiredIE)) { + iwEvent.cmd = IWEVGENIE; + iwEvent.u.data.flags = 1; + iwEvent.u.data.length = 2 + (__u16)prDesiredIE->ucLength; + iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; + if ((pcCur + iwEvent.len) > pcEnd) + break; +#if WIRELESS_EXT <= 18 + memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); +#else + memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); + memcpy(pcCur + IW_EV_LCP_LEN, + &iwEvent.u.data.length, + sizeof(struct iw_point) - IW_EV_POINT_OFF); +#endif + memcpy(pcCur + IW_EV_POINT_LEN, prDesiredIE, 2 + prDesiredIE->ucLength); + pcCur += iwEvent.len; + } + +#if CFG_SUPPORT_WPS /* search WPS IE (0xDD, 221, OUI: 0x0050f204 ) */ + if (wextSrchDesiredWPSIE(&prBss->aucIEs[sizeof(PARAM_FIXED_IEs)], + prBss->u4IELength - sizeof(PARAM_FIXED_IEs), + 0xDD, + (PUINT_8 *)&prDesiredIE)) { + iwEvent.cmd = IWEVGENIE; + iwEvent.u.data.flags = 1; + iwEvent.u.data.length = 2 + (__u16)prDesiredIE->ucLength; + iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; + if ((pcCur + iwEvent.len) > pcEnd) + break; +#if WIRELESS_EXT <= 18 + memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); +#else + memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); + memcpy(pcCur + IW_EV_LCP_LEN, + &iwEvent.u.data.length, + sizeof(struct iw_point) - IW_EV_POINT_OFF); +#endif + memcpy(pcCur + IW_EV_POINT_LEN, prDesiredIE, 2 + prDesiredIE->ucLength); + pcCur += iwEvent.len; + } +#endif + + + /* Search RSN IE (0x30, 48). pBss->IEs starts from timestamp. */ + /* pBss->IEs starts from timestamp */ + if (wextSrchDesiredWPAIE(&prBss->aucIEs[sizeof(PARAM_FIXED_IEs)], + prBss->u4IELength -sizeof(PARAM_FIXED_IEs), + 0x30, + (PUINT_8 *)&prDesiredIE)) { + + iwEvent.cmd = IWEVGENIE; + iwEvent.u.data.flags = 1; + iwEvent.u.data.length = 2 + (__u16)prDesiredIE->ucLength; + iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; + if ((pcCur + iwEvent.len) > pcEnd) + break; +#if WIRELESS_EXT <= 18 + memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); +#else + memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); + memcpy(pcCur + IW_EV_LCP_LEN, + &iwEvent.u.data.length, + sizeof(struct iw_point) - IW_EV_POINT_OFF); +#endif + memcpy(pcCur + IW_EV_POINT_LEN, prDesiredIE, 2 + prDesiredIE->ucLength); + pcCur += iwEvent.len; + } + +#if CFG_SUPPORT_WAPI /* Android+ */ + if (wextSrchDesiredWAPIIE(&prBss->aucIEs[sizeof(PARAM_FIXED_IEs)], + prBss->u4IELength -sizeof(PARAM_FIXED_IEs), + (PUINT_8 *)&prDesiredIE)) { + +#if 0 + iwEvent.cmd = IWEVGENIE; + iwEvent.u.data.flags = 1; + iwEvent.u.data.length = 2 + (__u16)prDesiredIE->ucLength; + iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; + if ((pcCur + iwEvent.len) > pcEnd) + break; +#if WIRELESS_EXT <= 18 + memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); +#else + memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); + memcpy(pcCur + IW_EV_LCP_LEN, + &iwEvent.u.data.length, + sizeof(struct iw_point) - IW_EV_POINT_OFF); +#endif + memcpy(pcCur + IW_EV_POINT_LEN, prDesiredIE, 2 + prDesiredIE->ucLength); + pcCur += iwEvent.len; +#else + iwEvent.cmd = IWEVCUSTOM; + iwEvent.u.data.length = (2 + prDesiredIE->ucLength) * 2 + 8 /* wapi_ie= */; + iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; + if ((pcCur + iwEvent.len) > pcEnd) + break; + iwEvent.u.data.flags = 1; + + memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); + memcpy(pcCur + IW_EV_LCP_LEN, + &iwEvent.u.data.length, + sizeof(struct iw_point) - IW_EV_POINT_OFF); + + pcCur += (IW_EV_POINT_LEN); + + pcCur += sprintf(pcCur, "wapi_ie="); + + snprintf_hex(pcCur, pcEnd - pcCur, (UINT_8 *)prDesiredIE, prDesiredIE->ucLength + 2); + + pcCur += (2 + prDesiredIE->ucLength) * 2 /* iwEvent.len */; +#endif + } +#endif + /* Complete an entry. Update end of valid entry */ + pcValidEntryEnd = pcCur; + /* Extract next bss */ + prBss = (P_PARAM_BSSID_EX_T)((char *)prBss + prBss->u4Length); + } + + /* Update valid data length for caller function and upper layer + * applications. + */ + prData->length = (pcValidEntryEnd - pcExtra); + //printk(KERN_INFO "[wifi] buf:%d result:%ld\n", pData->length, u4BufLen); + + //kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_SCAN_COMPLETE, NULL, 0); + +error: + /* free local query buffer */ + if (prList) { + kalMemFree(prList, VIR_MEM_TYPE, u4AllocBufLen); + } + + return ret; +} /* wext_get_scan */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set desired network name ESSID. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] prEssid Pointer of iw_point header. +* \param[in] pcExtra Pointer to buffer srtoring essid string. +* +* \retval 0 If netif_carrier_ok. +* \retval -E2BIG Essid string length is too big. +* \retval -EINVAL pcExtra is null pointer. +* \retval -EFAULT Driver fail to set new essid. +* +* \note If string lengh is ok, device will try connecting to the new network. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_set_essid ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + IN struct iw_point *prEssid, + IN char *pcExtra + ) +{ + PARAM_SSID_T rNewSsid; + UINT_32 cipher; + ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; + ENUM_PARAM_AUTH_MODE_T eAuthMode; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prEssid); + ASSERT(pcExtra); + if (FALSE == GLUE_CHK_PR3(prNetDev, prEssid, pcExtra)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prNetDev); + + if (prEssid->length > IW_ESSID_MAX_SIZE) { + return -E2BIG; + } + + + /* set auth mode */ + if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_DISABLED) { + eAuthMode = (prGlueInfo->rWpaInfo.u4AuthAlg == IW_AUTH_ALG_OPEN_SYSTEM) ? + AUTH_MODE_OPEN : AUTH_MODE_AUTO_SWITCH; + //printk(KERN_INFO "IW_AUTH_WPA_VERSION_DISABLED->Param_AuthMode%s\n", + // (eAuthMode == AUTH_MODE_OPEN) ? "Open" : "Shared"); + } + else { + /* set auth mode */ + switch(prGlueInfo->rWpaInfo.u4KeyMgmt) { + case IW_AUTH_KEY_MGMT_802_1X: + eAuthMode = + (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_WPA) ? + AUTH_MODE_WPA : AUTH_MODE_WPA2; + //printk("IW_AUTH_KEY_MGMT_802_1X->AUTH_MODE_WPA%s\n", + // (eAuthMode == AUTH_MODE_WPA) ? "" : "2"); + break; + case IW_AUTH_KEY_MGMT_PSK: + eAuthMode = + (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_WPA) ? + AUTH_MODE_WPA_PSK: AUTH_MODE_WPA2_PSK; + //printk("IW_AUTH_KEY_MGMT_PSK->AUTH_MODE_WPA%sPSK\n", + // (eAuthMode == AUTH_MODE_WPA_PSK) ? "" : "2"); + break; +#if CFG_SUPPORT_WAPI /* Android+ */ + case IW_AUTH_KEY_MGMT_WAPI_PSK: + break; + case IW_AUTH_KEY_MGMT_WAPI_CERT: + break; +#endif + +//#if defined (IW_AUTH_KEY_MGMT_WPA_NONE) +// case IW_AUTH_KEY_MGMT_WPA_NONE: +// eAuthMode = AUTH_MODE_WPA_NONE; +// //printk("IW_AUTH_KEY_MGMT_WPA_NONE->AUTH_MODE_WPA_NONE\n"); +// break; +//#endif +#if CFG_SUPPORT_802_11W + case IW_AUTH_KEY_MGMT_802_1X_SHA256: + eAuthMode = AUTH_MODE_WPA2; + break; + case IW_AUTH_KEY_MGMT_PSK_SHA256: + eAuthMode = AUTH_MODE_WPA2_PSK; + break; +#endif + default: + //printk(KERN_INFO DRV_NAME"strange IW_AUTH_KEY_MGMT : %ld set auto switch\n", + // prGlueInfo->rWpaInfo.u4KeyMgmt); + eAuthMode = AUTH_MODE_AUTO_SWITCH; + break; + } + } + + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetAuthMode, + &eAuthMode, + sizeof(eAuthMode), + FALSE, + FALSE, + FALSE, + FALSE, + &u4BufLen); + + /* set encryption status */ + cipher = prGlueInfo->rWpaInfo.u4CipherGroup | + prGlueInfo->rWpaInfo.u4CipherPairwise; + if (cipher & IW_AUTH_CIPHER_CCMP) { + //printk("IW_AUTH_CIPHER_CCMP->ENUM_ENCRYPTION3_ENABLED\n"); + eEncStatus = ENUM_ENCRYPTION3_ENABLED; + } + else if (cipher & IW_AUTH_CIPHER_TKIP) { + //printk("IW_AUTH_CIPHER_TKIP->ENUM_ENCRYPTION2_ENABLED\n"); + eEncStatus = ENUM_ENCRYPTION2_ENABLED; + } + else if (cipher & (IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40)) { + //printk("IW_AUTH_CIPHER_WEPx->ENUM_ENCRYPTION1_ENABLED\n"); + eEncStatus = ENUM_ENCRYPTION1_ENABLED; + } + else if (cipher & IW_AUTH_CIPHER_NONE){ + //printk("IW_AUTH_CIPHER_NONE->ENUM_ENCRYPTION_DISABLED\n"); + if (prGlueInfo->rWpaInfo.fgPrivacyInvoke) + eEncStatus = ENUM_ENCRYPTION1_ENABLED; + else + eEncStatus = ENUM_ENCRYPTION_DISABLED; + } + else { + //printk("unknown IW_AUTH_CIPHER->Param_EncryptionDisabled\n"); + eEncStatus = ENUM_ENCRYPTION_DISABLED; + } + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetEncryptionStatus, + &eEncStatus, + sizeof(eEncStatus), + FALSE, + FALSE, + FALSE, + FALSE, + &u4BufLen); + +#if WIRELESS_EXT < 21 + /* GeorgeKuo: a length error bug exists in (WE < 21) cases, kernel before + ** 2.6.19. Cut the trailing '\0'. + */ + rNewSsid.u4SsidLen = (prEssid->length) ? prEssid->length - 1 : 0; +#else + rNewSsid.u4SsidLen = prEssid->length; +#endif + kalMemCopy(rNewSsid.aucSsid, pcExtra, rNewSsid.u4SsidLen); + + /* + rNewSsid.aucSsid[rNewSsid.u4SsidLen] = '\0'; + printk("set ssid(%lu): %s\n", rNewSsid.u4SsidLen, rNewSsid.aucSsid); + */ + + if (kalIoctl(prGlueInfo, + wlanoidSetSsid, + (PVOID) &rNewSsid, + sizeof(PARAM_SSID_T), + FALSE, + FALSE, + TRUE, + FALSE, + &u4BufLen) != WLAN_STATUS_SUCCESS) { + //printk(KERN_WARNING "Fail to set ssid\n"); + return -EFAULT; + } + + + return 0; +} /* wext_set_essid */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To get current network name ESSID. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] prEssid Pointer to iw_point structure containing essid information. +* \param[out] pcExtra Pointer to buffer srtoring essid string. +* +* \retval 0 If netif_carrier_ok. +* \retval -ENOTCONN Otherwise. +* +* \note If netif_carrier_ok, network essid is stored in pcExtra. +*/ +/*----------------------------------------------------------------------------*/ +//static PARAM_SSID_T ssid; +static int +wext_get_essid ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + IN struct iw_point *prEssid, + OUT char *pcExtra + ) +{ + //PARAM_SSID_T ssid; + + P_PARAM_SSID_T prSsid; + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prEssid); + ASSERT(pcExtra); + + if (FALSE == GLUE_CHK_PR3(prNetDev, prEssid, pcExtra)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prNetDev); + + //if (!netif_carrier_ok(prNetDev)) { + // return -ENOTCONN; + //} + + prSsid = kalMemAlloc(sizeof(PARAM_SSID_T), VIR_MEM_TYPE); + + if(!prSsid) { + return -ENOMEM; + } + + rStatus = kalIoctl(prGlueInfo, + wlanoidQuerySsid, + prSsid, + sizeof(PARAM_SSID_T), + TRUE, + FALSE, + FALSE, + FALSE, + &u4BufLen); + + if ((rStatus == WLAN_STATUS_SUCCESS) && (prSsid->u4SsidLen <= MAX_SSID_LEN)) { + kalMemCopy(pcExtra, prSsid->aucSsid, prSsid->u4SsidLen); + prEssid->length = prSsid->u4SsidLen; + prEssid->flags = 1; + } + + kalMemFree(prSsid, VIR_MEM_TYPE, sizeof(PARAM_SSID_T)); + + return 0; +} /* wext_get_essid */ + + +#if 0 + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set tx desired bit rate. Three cases here +* iwconfig wlan0 auto -> Set to origianl supported rate set. +* iwconfig wlan0 18M -> Imply "fixed" case, set to 18Mbps as desired rate. +* iwconfig wlan0 18M auto -> Set to auto rate lower and equal to 18Mbps +* +* \param[in] prNetDev Pointer to the net_device handler. +* \param[in] prIwReqInfo Pointer to the Request Info. +* \param[in] prRate Pointer to the Rate Parameter. +* \param[in] pcExtra Pointer to the extra buffer. +* +* \retval 0 Update desired rate. +* \retval -EINVAL Wrong parameter +*/ +/*----------------------------------------------------------------------------*/ +int +wext_set_rate ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN struct iw_param *prRate, + IN char *pcExtra + ) +{ + PARAM_RATES_EX aucSuppRate = {0}; + PARAM_RATES_EX aucNewRate = {0}; + UINT_32 u4NewRateLen = 0; + UINT_32 i; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prRate); + if (FALSE == GLUE_CHK_PR2(prNetDev, prRate)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T)netdev_priv(prNetDev); + + /* + printk("value = %d, fixed = %d, disable = %d, flags = %d\n", + prRate->value, prRate->fixed, prRate->disabled, prRate->flags); + */ + + rStatus = wlanQueryInformation( + prGlueInfo->prAdapter, + wlanoidQuerySupportedRates, + &aucSuppRate, + sizeof(aucSuppRate), + &u4BufLen); + + /* Case: AUTO */ + if (prRate->value < 0) { + if (prRate->fixed == 0) { + /* iwconfig wlan0 rate auto */ + + /* set full supported rate to device */ + /* printk("wlanoidQuerySupportedRates():u4BufLen = %ld\n", u4BufLen); */ + rStatus = wlanSetInformation( + prGlueInfo->prAdapter, + wlanoidSetDesiredRates, + &aucSuppRate, + sizeof(aucSuppRate), + &u4BufLen); + return 0; + } + else { + /* iwconfig wlan0 rate fixed */ + + /* fix rate to what? DO NOTHING */ + return -EINVAL; + } + } + + + aucNewRate[0] = prRate->value / 500000; /* In unit of 500k */ + + for (i = 0; i < PARAM_MAX_LEN_RATES_EX; i++) { + /* check the given value is supported */ + if (aucSuppRate[i] == 0) { + break; + } + + if (aucNewRate[0] == aucSuppRate[i]) { + u4NewRateLen = 1; + break; + } + } + + if (u4NewRateLen == 0) { + /* the given value is not supported */ + /* return error or use given rate as upper bound? */ + return -EINVAL; + } + + if (prRate->fixed == 0) { + /* add all rates lower than desired rate */ + for (i = 0; i < PARAM_MAX_LEN_RATES_EX; ++i) { + if (aucSuppRate[i] == 0) { + break; + } + + if (aucSuppRate[i] < aucNewRate[0]) { + aucNewRate[u4NewRateLen++] = aucSuppRate[i]; + } + } + } + + rStatus = wlanSetInformation( + prGlueInfo->prAdapter, + wlanoidSetDesiredRates, + &aucNewRate, + sizeof(aucNewRate), + &u4BufLen); + return 0; +} /* wext_set_rate */ + +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To get current tx bit rate. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[out] prRate Pointer to iw_param structure to store current tx rate. +* \param[in] pcExtra NULL. +* +* \retval 0 If netif_carrier_ok. +* \retval -ENOTCONN Otherwise. +* +* \note If netif_carrier_ok, current tx rate is stored in pRate. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_get_rate ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + OUT struct iw_param *prRate, + IN char *pcExtra + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + UINT_32 u4Rate = 0; + + ASSERT(prNetDev); + ASSERT(prRate); + if (FALSE == GLUE_CHK_PR2(prNetDev, prRate)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T)netdev_priv(prNetDev); + + if (!netif_carrier_ok(prNetDev)) { + return -ENOTCONN; + } + + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryLinkSpeed, + &u4Rate, + sizeof(u4Rate), + TRUE, + FALSE, + FALSE, + FALSE, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + prRate->value = u4Rate * 100; /* u4Rate is in unit of 100bps */ + prRate->fixed = 0; + + return 0; +} /* wext_get_rate */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set RTS/CTS theshold. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] prRts Pointer to iw_param structure containing rts threshold. +* \param[in] pcExtra NULL. +* +* \retval 0 For success. +* \retval -EINVAL Given value is out of range. +* +* \note If given value is valid, device will follow the new setting. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_set_rts ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + IN struct iw_param *prRts, + IN char *pcExtra + ) +{ + PARAM_RTS_THRESHOLD u4RtsThresh; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prRts); + if (FALSE == GLUE_CHK_PR2(prNetDev, prRts)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T)netdev_priv(prNetDev); + + if (prRts->disabled == 1) { + u4RtsThresh = 2347; + } + else if (prRts->value < 0 || prRts->value > 2347) { + return -EINVAL; + } + else { + u4RtsThresh = (PARAM_RTS_THRESHOLD)prRts->value; + } + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetRtsThreshold, + &u4RtsThresh, + sizeof(u4RtsThresh), + FALSE, + FALSE, + FALSE, + FALSE, + &u4BufLen); + + + + prRts->value = (typeof(prRts->value ))u4RtsThresh; + prRts->disabled = (prRts->value > 2347) ? 1 : 0; + prRts->fixed = 1; + + return 0; +} /* wext_set_rts */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To get RTS/CTS theshold. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[out] prRts Pointer to iw_param structure containing rts threshold. +* \param[in] pcExtra NULL. +* +* \retval 0 Success. +* +* \note RTS threshold is stored in pRts. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_get_rts ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + OUT struct iw_param *prRts, + IN char *pcExtra + ) +{ + PARAM_RTS_THRESHOLD u4RtsThresh; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prRts); + if (FALSE == GLUE_CHK_PR2(prNetDev, prRts)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T)netdev_priv(prNetDev); + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryRtsThreshold, + &u4RtsThresh, + sizeof(u4RtsThresh), + TRUE, + FALSE, + FALSE, + FALSE, + &u4BufLen); + + + + prRts->value = (typeof(prRts->value ))u4RtsThresh; + prRts->disabled = (prRts->value > 2347 || prRts->value < 0) ? 1 : 0; + prRts->fixed = 1; + + return 0; +} /* wext_get_rts */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To get fragmentation threshold. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[out] prFrag Pointer to iw_param structure containing frag threshold. +* \param[in] pcExtra NULL. +* +* \retval 0 Success. +* +* \note RTS threshold is stored in pFrag. Fragmentation is disabled. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_get_frag ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + OUT struct iw_param *prFrag, + IN char *pcExtra + ) +{ + ASSERT(prFrag); + + prFrag->value = 2346; + prFrag->fixed = 1; + prFrag->disabled = 1; + return 0; +} /* wext_get_frag */ + +#if 1 +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set TX power, or enable/disable the radio. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] prTxPow Pointer to iw_param structure containing tx power setting. +* \param[in] pcExtra NULL. +* +* \retval 0 Success. +* +* \note Tx power is stored in pTxPow. iwconfig wlan0 txpow on/off are used +* to enable/disable the radio. +*/ +/*----------------------------------------------------------------------------*/ + +static int +wext_set_txpow ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + IN struct iw_param *prTxPow, + IN char *pcExtra + ) +{ + int ret = 0; + //PARAM_DEVICE_POWER_STATE ePowerState; + ENUM_ACPI_STATE_T ePowerState; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prTxPow); + if (FALSE == GLUE_CHK_PR2(prNetDev, prTxPow)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T)netdev_priv(prNetDev); + + if(prTxPow->disabled){ + /* <1> disconnect */ + rStatus = kalIoctl(prGlueInfo, + wlanoidSetDisassociate, + NULL, + 0, + FALSE, + FALSE, + TRUE, + FALSE, + &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, ("######set disassoc failed\n")); + } else { + DBGLOG(INIT, INFO, ("######set assoc ok\n")); + } + + /* <2> mark to power state flag*/ + ePowerState = ACPI_STATE_D0; + DBGLOG(INIT, INFO, ("set to acpi d3(0)\n")); + wlanSetAcpiState(prGlueInfo->prAdapter, ePowerState); + + } + else { + ePowerState = ACPI_STATE_D0; + DBGLOG(INIT, INFO, ("set to acpi d0\n")); + wlanSetAcpiState(prGlueInfo->prAdapter, ePowerState); + } + + prGlueInfo->ePowerState = ePowerState; + + return ret; +} /* wext_set_txpow */ + + +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To get TX power. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[out] prTxPow Pointer to iw_param structure containing tx power setting. +* \param[in] pcExtra NULL. +* +* \retval 0 Success. +* +* \note Tx power is stored in pTxPow. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_get_txpow ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + OUT struct iw_param *prTxPow, + IN char *pcExtra + ) +{ + //PARAM_DEVICE_POWER_STATE ePowerState; + + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prNetDev); + ASSERT(prTxPow); + if (FALSE == GLUE_CHK_PR2(prNetDev, prTxPow)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T)netdev_priv(prNetDev); + + /* GeorgeKuo: wlanoidQueryAcpiDevicePowerState() reports capability, not + * current state. Use GLUE_INFO_T to store state. + */ + //ePowerState = prGlueInfo->ePowerState; + + /* TxPow parameters: Fixed at relative 100% */ +#if WIRELESS_EXT < 17 + prTxPow->flags = 0x0002; /* IW_TXPOW_RELATIVE */ +#else + prTxPow->flags = IW_TXPOW_RELATIVE; +#endif + prTxPow->value = 100; + prTxPow->fixed = 1; + //prTxPow->disabled = (ePowerState != ParamDeviceStateD3) ? FALSE : TRUE; + prTxPow->disabled = TRUE; + + return 0; +} /* wext_get_txpow */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To get encryption cipher and key. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[out] prEnc Pointer to iw_point structure containing securiry information. +* \param[in] pcExtra Buffer to store key content. +* +* \retval 0 Success. +* +* \note Securiry information is stored in pEnc except key content. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_get_encode ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + OUT struct iw_point *prEnc, + IN char *pcExtra + ) +{ +#if 1 + //ENUM_ENCRYPTION_STATUS_T eEncMode; + ENUM_PARAM_ENCRYPTION_STATUS_T eEncMode; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prEnc); + if (FALSE == GLUE_CHK_PR2(prNetDev, prEnc)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T)netdev_priv(prNetDev); + + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryEncryptionStatus, + &eEncMode, + sizeof(eEncMode), + TRUE, + FALSE, + FALSE, + FALSE, + &u4BufLen); + + + + switch(eEncMode) { + case ENUM_WEP_DISABLED: + prEnc->flags = IW_ENCODE_DISABLED; + break; + case ENUM_WEP_ENABLED: + prEnc->flags = IW_ENCODE_ENABLED; + break; + case ENUM_WEP_KEY_ABSENT: + prEnc->flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + break; + default: + prEnc->flags = IW_ENCODE_ENABLED; + break; + } + + /* Cipher, Key Content, Key ID can't be queried */ + prEnc->flags |= IW_ENCODE_NOKEY; +#endif + return 0; +} /* wext_get_encode */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set encryption cipher and key. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] prEnc Pointer to iw_point structure containing securiry information. +* \param[in] pcExtra Pointer to key string buffer. +* +* \retval 0 Success. +* \retval -EINVAL Key ID error for WEP. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note Securiry information is stored in pEnc. +*/ +/*----------------------------------------------------------------------------*/ +static UINT_8 wepBuf[48]; + +static int +wext_set_encode ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + IN struct iw_point *prEnc, + IN char *pcExtra + ) +{ +#if 1 + ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; + ENUM_PARAM_AUTH_MODE_T eAuthMode; + //UINT_8 wepBuf[48]; + P_PARAM_WEP_T prWepKey = (P_PARAM_WEP_T) wepBuf; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prEnc); + ASSERT(pcExtra); + if (FALSE == GLUE_CHK_PR3(prNetDev, prEnc, pcExtra)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prNetDev); + + /* reset to default mode */ + prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + prGlueInfo->rWpaInfo.u4KeyMgmt = 0; + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE; + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE; + prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; +#if CFG_SUPPORT_802_11W + prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; +#endif + + /* iwconfig wlan0 key off */ + if ( (prEnc->flags & IW_ENCODE_MODE) == IW_ENCODE_DISABLED ) { + eAuthMode = AUTH_MODE_OPEN; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetAuthMode, + &eAuthMode, + sizeof(eAuthMode), + FALSE, + FALSE, + FALSE, + FALSE, + &u4BufLen); + + eEncStatus = ENUM_ENCRYPTION_DISABLED; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetEncryptionStatus, + &eEncStatus, + sizeof(eEncStatus), + FALSE, + FALSE, + FALSE, + FALSE, + &u4BufLen); + + return 0; + } + + /* iwconfig wlan0 key 0123456789 */ + /* iwconfig wlan0 key s:abcde */ + /* iwconfig wlan0 key 0123456789 [1] */ + /* iwconfig wlan0 key 01234567890123456789012345 [1] */ + /* check key size for WEP */ + if (prEnc->length == 5 || prEnc->length == 13 || prEnc->length == 16) { + /* prepare PARAM_WEP key structure */ + prWepKey->u4KeyIndex = (prEnc->flags & IW_ENCODE_INDEX) ? + (prEnc->flags & IW_ENCODE_INDEX) -1 : 0; + if (prWepKey->u4KeyIndex > 3) { + /* key id is out of range */ + return -EINVAL; + } + prWepKey->u4KeyIndex |= 0x80000000; + prWepKey->u4Length = 12 + prEnc->length; + prWepKey->u4KeyLength = prEnc->length; + kalMemCopy(prWepKey->aucKeyMaterial, pcExtra, prEnc->length); + + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetAddWep, + prWepKey, + prWepKey->u4Length, + FALSE, + FALSE, + TRUE, + FALSE, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, ("wlanoidSetAddWep fail 0x%lx\n", rStatus)); + return -EFAULT; + } + + /* change to auto switch */ + prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_SHARED_KEY | + IW_AUTH_ALG_OPEN_SYSTEM; + eAuthMode = AUTH_MODE_AUTO_SWITCH; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetAuthMode, + &eAuthMode, + sizeof(eAuthMode), + FALSE, + FALSE, + FALSE, + FALSE, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + //printk(KERN_INFO DRV_NAME"wlanoidSetAuthMode fail 0x%lx\n", rStatus); + return -EFAULT; + } + + prGlueInfo->rWpaInfo.u4CipherPairwise = + IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40; + prGlueInfo->rWpaInfo.u4CipherGroup = + IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40; + + eEncStatus = ENUM_WEP_ENABLED; + + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetEncryptionStatus, + &eEncStatus, + sizeof(ENUM_PARAM_ENCRYPTION_STATUS_T), + FALSE, + FALSE, + FALSE, + FALSE, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + //printk(KERN_INFO DRV_NAME"wlanoidSetEncryptionStatus fail 0x%lx\n", rStatus); + return -EFAULT; + } + + return 0; + } +#endif + return -EOPNOTSUPP; +} /* wext_set_encode */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set power management. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] prPower Pointer to iw_param structure containing tx power setting. +* \param[in] pcExtra NULL. +* +* \retval 0 Success. +* +* \note New Power Management Mode is set to driver. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_set_power ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + IN struct iw_param *prPower, + IN char *pcExtra + ) +{ +#if 1 + PARAM_POWER_MODE ePowerMode; + INT_32 i4PowerValue; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prPower); + if (FALSE == GLUE_CHK_PR2(prNetDev, prPower)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T)netdev_priv(prNetDev); + + //printk(KERN_INFO "wext_set_power value(%d) disabled(%d) flag(0x%x)\n", + // prPower->value, prPower->disabled, prPower->flags); + + if(prPower->disabled){ + ePowerMode = Param_PowerModeCAM; + } + else { + i4PowerValue = prPower->value; +#if WIRELESS_EXT < 21 + i4PowerValue /= 1000000; +#endif + if (i4PowerValue == 0) { + ePowerMode = Param_PowerModeCAM; + } else if (i4PowerValue == 1) { + ePowerMode = Param_PowerModeMAX_PSP; + } else if (i4PowerValue == 2) { + ePowerMode = Param_PowerModeFast_PSP; + } + else { + DBGLOG(INIT, INFO, ("%s(): unsupported power management mode value = %d.\n", + __FUNCTION__, + prPower->value)); + + return -EINVAL; + } + } + + + rStatus = kalIoctl(prGlueInfo, + wlanoidSet802dot11PowerSaveProfile, + &ePowerMode, + sizeof(ePowerMode), + FALSE, + FALSE, + TRUE, + FALSE, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + //printk(KERN_INFO DRV_NAME"wlanoidSet802dot11PowerSaveProfile fail 0x%lx\n", rStatus); + return -EFAULT; + } + +#endif + return 0; +} /* wext_set_power */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To get power management. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[out] prPower Pointer to iw_param structure containing tx power setting. +* \param[in] pcExtra NULL. +* +* \retval 0 Success. +* +* \note Power management mode is stored in pTxPow->value. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_get_power ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + OUT struct iw_param *prPower, + IN char *pcExtra + ) +{ + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + PARAM_POWER_MODE ePowerMode = Param_PowerModeCAM; + + ASSERT(prNetDev); + ASSERT(prPower); + if (FALSE == GLUE_CHK_PR2(prNetDev, prPower)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T)netdev_priv(prNetDev); + +#if 0 +#if defined(_HIF_SDIO) + rStatus = sdio_io_ctrl(prGlueInfo, + wlanoidQuery802dot11PowerSaveProfile, + &ePowerMode, + sizeof(ePowerMode), + TRUE, + TRUE, + &u4BufLen); +#else + rStatus = wlanQueryInformation(prGlueInfo->prAdapter, + wlanoidQuery802dot11PowerSaveProfile, + &ePowerMode, + sizeof(ePowerMode), + &u4BufLen); +#endif +#else + rStatus = wlanQueryInformation(prGlueInfo->prAdapter, + wlanoidQuery802dot11PowerSaveProfile, + &ePowerMode, + sizeof(ePowerMode), + &u4BufLen); +#endif + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + prPower->value = 0; + prPower->disabled = 1; + + if (Param_PowerModeCAM == ePowerMode) { + prPower->value = 0; + prPower->disabled = 1; + } + else if (Param_PowerModeMAX_PSP == ePowerMode ) { + prPower->value = 1; + prPower->disabled = 0; + } + else if (Param_PowerModeFast_PSP == ePowerMode ) { + prPower->value = 2; + prPower->disabled = 0; + } + + prPower->flags = IW_POWER_PERIOD | IW_POWER_RELATIVE; +#if WIRELESS_EXT < 21 + prPower->value *= 1000000; +#endif + + //printk(KERN_INFO "wext_get_power value(%d) disabled(%d) flag(0x%x)\n", + // prPower->value, prPower->disabled, prPower->flags); + + return 0; +} /* wext_get_power */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set authentication parameters. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] rpAuth Pointer to iw_param structure containing authentication information. +* \param[in] pcExtra Pointer to key string buffer. +* +* \retval 0 Success. +* \retval -EINVAL Key ID error for WEP. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note Securiry information is stored in pEnc. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_set_auth ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + IN struct iw_param *prAuth, + IN char *pcExtra + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prNetDev); + ASSERT(prAuth); + if (FALSE == GLUE_CHK_PR2(prNetDev, prAuth)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prNetDev); + + /* Save information to glue info and process later when ssid is set. */ + switch(prAuth->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: +#if CFG_SUPPORT_WAPI + if (wlanQueryWapiMode(prGlueInfo->prAdapter)){ + prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; + } + else { + prGlueInfo->rWpaInfo.u4WpaVersion = prAuth->value; + } +#else + prGlueInfo->rWpaInfo.u4WpaVersion = prAuth->value; +#endif + break; + + case IW_AUTH_CIPHER_PAIRWISE: + prGlueInfo->rWpaInfo.u4CipherPairwise = prAuth->value; + break; + + case IW_AUTH_CIPHER_GROUP: + prGlueInfo->rWpaInfo.u4CipherGroup = prAuth->value; + break; + + case IW_AUTH_KEY_MGMT: + prGlueInfo->rWpaInfo.u4KeyMgmt = prAuth->value; +#if CFG_SUPPORT_WAPI + if (prGlueInfo->rWpaInfo.u4KeyMgmt == IW_AUTH_KEY_MGMT_WAPI_PSK || + prGlueInfo->rWpaInfo.u4KeyMgmt == IW_AUTH_KEY_MGMT_WAPI_CERT) { + UINT_32 u4BufLen; + WLAN_STATUS rStatus; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetWapiMode, + &prAuth->value, + sizeof(UINT_32), + FALSE, + FALSE, + TRUE, + FALSE, + &u4BufLen); + DBGLOG(INIT, INFO, ("IW_AUTH_WAPI_ENABLED :%d\n", prAuth->value)); + } +#endif + if (prGlueInfo->rWpaInfo.u4KeyMgmt == IW_AUTH_KEY_MGMT_WPS) + prGlueInfo->fgWpsActive = TRUE; + else + prGlueInfo->fgWpsActive = FALSE; + break; + + case IW_AUTH_80211_AUTH_ALG: + prGlueInfo->rWpaInfo.u4AuthAlg = prAuth->value; + break; + + case IW_AUTH_PRIVACY_INVOKED: + prGlueInfo->rWpaInfo.fgPrivacyInvoke = prAuth->value; + break; +#if CFG_SUPPORT_802_11W + case IW_AUTH_MFP: + //printk("wext_set_auth IW_AUTH_MFP=%d\n", prAuth->value); + prGlueInfo->rWpaInfo.u4Mfp = prAuth->value; + break; +#endif +#if CFG_SUPPORT_WAPI + case IW_AUTH_WAPI_ENABLED: + { + UINT_32 u4BufLen; + WLAN_STATUS rStatus; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetWapiMode, + &prAuth->value, + sizeof(UINT_32), + FALSE, + FALSE, + TRUE, + FALSE, + &u4BufLen); + } + DBGLOG(INIT, INFO, ("IW_AUTH_WAPI_ENABLED :%d\n", prAuth->value)); + break; +#endif + default: + /* + printk(KERN_INFO "[wifi] unsupported IW_AUTH_INDEX :%d\n", prAuth->flags); + */ + break; + } + return 0; +} /* wext_set_auth */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set encryption cipher and key. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] prEnc Pointer to iw_point structure containing securiry information. +* \param[in] pcExtra Pointer to key string buffer. +* +* \retval 0 Success. +* \retval -EINVAL Key ID error for WEP. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note Securiry information is stored in pEnc. +*/ +/*----------------------------------------------------------------------------*/ +#if CFG_SUPPORT_WAPI + UINT_8 keyStructBuf[320]; /* add/remove key shared buffer */ +#else + UINT_8 keyStructBuf[100]; /* add/remove key shared buffer */ +#endif + +static int +wext_set_encode_ext ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + IN struct iw_point *prEnc, + IN char *pcExtra + ) +{ + P_PARAM_REMOVE_KEY_T prRemoveKey = (P_PARAM_REMOVE_KEY_T) keyStructBuf; + P_PARAM_KEY_T prKey = (P_PARAM_KEY_T) keyStructBuf; + + + P_PARAM_WEP_T prWepKey = (P_PARAM_WEP_T) wepBuf; + + struct iw_encode_ext *prIWEncExt = (struct iw_encode_ext *) pcExtra; + + ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; + ENUM_PARAM_AUTH_MODE_T eAuthMode; + //ENUM_PARAM_OP_MODE_T eOpMode = NET_TYPE_AUTO_SWITCH; + +#if CFG_SUPPORT_WAPI + P_PARAM_WPI_KEY_T prWpiKey = (P_PARAM_WPI_KEY_T) keyStructBuf; +#endif + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prEnc); + if (FALSE == GLUE_CHK_PR3(prNetDev, prEnc, pcExtra)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prNetDev); + + memset(keyStructBuf, 0, sizeof(keyStructBuf)); + +#if CFG_SUPPORT_WAPI + if (prIWEncExt->alg == IW_ENCODE_ALG_SMS4) { + if (prEnc->flags & IW_ENCODE_DISABLED) { + //printk(KERN_INFO "[wapi] IW_ENCODE_DISABLED\n"); + return 0; + } + /* KeyID */ + prWpiKey->ucKeyID = (prEnc->flags & IW_ENCODE_INDEX); + prWpiKey->ucKeyID --; + if (prWpiKey->ucKeyID > 1) { + /* key id is out of range */ + //printk(KERN_INFO "[wapi] add key error: key_id invalid %d\n", prWpiKey->ucKeyID); + return -EINVAL; + } + + if (prIWEncExt->key_len != 32) { + /* key length not valid */ + //printk(KERN_INFO "[wapi] add key error: key_len invalid %d\n", prIWEncExt->key_len); + return -EINVAL; + } + + //printk(KERN_INFO "[wapi] %d ext_flags %d\n", prEnc->flags, prIWEncExt->ext_flags); + + if (prIWEncExt->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + prWpiKey->eKeyType = ENUM_WPI_GROUP_KEY; + prWpiKey->eDirection = ENUM_WPI_RX; + } + else if (prIWEncExt->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + prWpiKey->eKeyType = ENUM_WPI_PAIRWISE_KEY; + prWpiKey->eDirection = ENUM_WPI_RX_TX; + } + +//#if CFG_SUPPORT_WAPI + handle_sec_msg_final(prIWEncExt->key, 32, prIWEncExt->key, NULL); +//#endif + /* PN */ + memcpy(prWpiKey->aucPN, prIWEncExt->tx_seq, IW_ENCODE_SEQ_MAX_SIZE * 2); + + /* BSSID */ + memcpy(prWpiKey->aucAddrIndex, prIWEncExt->addr.sa_data, 6); + + memcpy(prWpiKey->aucWPIEK, prIWEncExt->key, 16); + prWpiKey->u4LenWPIEK = 16; + + memcpy(prWpiKey->aucWPICK, &prIWEncExt->key[16], 16); + prWpiKey->u4LenWPICK = 16; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetWapiKey, + prWpiKey, + sizeof(PARAM_WPI_KEY_T), + FALSE, + FALSE, + TRUE, + FALSE, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + //printk(KERN_INFO "[wapi] add key error:%lx\n", rStatus); + } + + } + else +#endif + { + + if ( (prEnc->flags & IW_ENCODE_MODE) == IW_ENCODE_DISABLED) { + prRemoveKey->u4Length = sizeof(*prRemoveKey); + memcpy(prRemoveKey->arBSSID, prIWEncExt->addr.sa_data, 6); + /* + printk("IW_ENCODE_DISABLED: ID:%d, Addr:[" MACSTR "]\n", + prRemoveKey->KeyIndex, MAC2STR(prRemoveKey->BSSID)); + */ + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetRemoveKey, + prRemoveKey, + prRemoveKey->u4Length, + FALSE, + FALSE, + TRUE, + FALSE, + &u4BufLen); + + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, ("remove key error:%lx\n", rStatus)); + } + return 0; + } + + //return 0; + //printk ("alg %x\n", prIWEncExt->alg); + + switch (prIWEncExt->alg) { + case IW_ENCODE_ALG_NONE: + break; + case IW_ENCODE_ALG_WEP: + /* iwconfig wlan0 key 0123456789 */ + /* iwconfig wlan0 key s:abcde */ + /* iwconfig wlan0 key 0123456789 [1] */ + /* iwconfig wlan0 key 01234567890123456789012345 [1] */ + /* check key size for WEP */ + if (prIWEncExt->key_len == 5 || prIWEncExt->key_len == 13 || prIWEncExt->key_len == 16) { + /* prepare PARAM_WEP key structure */ + prWepKey->u4KeyIndex = (prEnc->flags & IW_ENCODE_INDEX) ? + (prEnc->flags & IW_ENCODE_INDEX) -1 : 0; + if (prWepKey->u4KeyIndex > 3) { + /* key id is out of range */ + return -EINVAL; + } + prWepKey->u4KeyIndex |= 0x80000000; + prWepKey->u4Length = 12 + prIWEncExt->key_len; + prWepKey->u4KeyLength = prIWEncExt->key_len; + //kalMemCopy(prWepKey->aucKeyMaterial, pcExtra, prIWEncExt->key_len); + kalMemCopy(prWepKey->aucKeyMaterial, prIWEncExt->key, prIWEncExt->key_len); + + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetAddWep, + prWepKey, + prWepKey->u4Length, + FALSE, + FALSE, + TRUE, + FALSE, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, ("wlanoidSetAddWep fail 0x%lx\n", rStatus)); + return -EFAULT; + } + + /* change to auto switch */ + prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_SHARED_KEY | + IW_AUTH_ALG_OPEN_SYSTEM; + eAuthMode = AUTH_MODE_AUTO_SWITCH; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetAuthMode, + &eAuthMode, + sizeof(eAuthMode), + FALSE, + FALSE, + FALSE, + FALSE, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, ("wlanoidSetAuthMode fail 0x%lx\n", rStatus)); + return -EFAULT; + } + + prGlueInfo->rWpaInfo.u4CipherPairwise = + IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40; + prGlueInfo->rWpaInfo.u4CipherGroup = + IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40; + + eEncStatus = ENUM_WEP_ENABLED; + + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetEncryptionStatus, + &eEncStatus, + sizeof(ENUM_PARAM_ENCRYPTION_STATUS_T), + FALSE, + FALSE, + FALSE, + FALSE, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, ("wlanoidSetEncryptionStatus fail 0x%lx\n", rStatus)); + return -EFAULT; + } + + } else { + DBGLOG(INIT, INFO, ("key length %x\n", prIWEncExt->key_len)); + DBGLOG(INIT, INFO, ("key error\n")); + } + + break; + case IW_ENCODE_ALG_TKIP: + case IW_ENCODE_ALG_CCMP: +#if CFG_SUPPORT_802_11W + case IW_ENCODE_ALG_AES_CMAC: +#endif + { + + /* KeyID */ + prKey->u4KeyIndex = (prEnc->flags & IW_ENCODE_INDEX) ? + (prEnc->flags & IW_ENCODE_INDEX) -1: 0; +#if CFG_SUPPORT_802_11W + if (prKey->u4KeyIndex > 5) +#else + if (prKey->u4KeyIndex > 3) +#endif + { + DBGLOG(INIT, INFO, ("key index error:0x%lx\n", prKey->u4KeyIndex)); + /* key id is out of range */ + return -EINVAL; + } + + /* bit(31) and bit(30) are shared by pKey and pRemoveKey */ + /* Tx Key Bit(31)*/ + if (prIWEncExt->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + prKey->u4KeyIndex |= 0x1UL << 31; + } + + /* Pairwise Key Bit(30) */ + if (prIWEncExt->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + /* group key */ + } + else { + /* pairwise key */ + prKey->u4KeyIndex |= 0x1UL << 30; + } + + } + /* Rx SC Bit(29) */ + if (prIWEncExt->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { + prKey->u4KeyIndex |= 0x1UL << 29; + memcpy(&prKey->rKeyRSC, prIWEncExt->rx_seq, IW_ENCODE_SEQ_MAX_SIZE); + } + + /* BSSID */ + memcpy(prKey->arBSSID, prIWEncExt->addr.sa_data, 6); + + /* switch tx/rx MIC key for sta */ + if (prIWEncExt->alg == IW_ENCODE_ALG_TKIP && prIWEncExt->key_len == 32) { + memcpy(prKey->aucKeyMaterial, prIWEncExt->key, 16); + memcpy(prKey->aucKeyMaterial + 16, prIWEncExt->key + 24, 8); + memcpy(prKey->aucKeyMaterial + 24, prIWEncExt->key + 16, 8); + } + else { + memcpy(prKey->aucKeyMaterial, prIWEncExt->key, prIWEncExt->key_len); + } + + prKey->u4KeyLength = prIWEncExt->key_len; + prKey->u4Length = ((UINT_32)&(((P_PARAM_KEY_T)0)->aucKeyMaterial)) + prKey->u4KeyLength; + + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetAddKey, + prKey, + prKey->u4Length, + FALSE, + FALSE, + TRUE, + FALSE, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, ("add key error:%lx\n", rStatus)); + return -EFAULT; + } + break; + } + } + + return 0; +} /* wext_set_encode_ext */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Set country code +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] pu4Mode Pointer to new operation mode. +* \param[in] pcExtra NULL. +* +* \retval 0 For success. +* \retval -EOPNOTSUPP If new mode is not supported. +* +* \note Device will run in new operation mode if it is valid. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_set_country ( + IN struct net_device *prNetDev, + IN struct iwreq *iwr + ) +{ + P_GLUE_INFO_T prGlueInfo; + WLAN_STATUS rStatus; + UINT_32 u4BufLen; + UINT_8 aucCountry[2]; + + ASSERT(prNetDev); + + /* iwr->u.data.pointer should be like "COUNTRY US", "COUNTRY EU" + * and "COUNTRY JP" + */ + if (FALSE == GLUE_CHK_PR2(prNetDev, iwr) || + !iwr->u.data.pointer || iwr->u.data.length < 10) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prNetDev); + + aucCountry[0] = *((PUINT_8)iwr->u.data.pointer + 8); + aucCountry[1] = *((PUINT_8)iwr->u.data.pointer + 9); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetCountryCode, + &aucCountry[0], + 2, + FALSE, + FALSE, + TRUE, + FALSE, + &u4BufLen); + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief ioctl() (Linux Wireless Extensions) routines +* +* \param[in] prDev Net device requested. +* \param[in] ifr The ifreq structure for seeting the wireless extension. +* \param[in] i4Cmd The wireless extension ioctl command. +* +* \retval zero On success. +* \retval -EOPNOTSUPP If the cmd is not supported. +* \retval -EFAULT If copy_to_user goes wrong. +* \retval -EINVAL If any value's out of range. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +wext_support_ioctl ( + IN struct net_device *prDev, + IN struct ifreq *prIfReq, + IN int i4Cmd + ) +{ + /* prIfReq is verified in the caller function wlanDoIOCTL() */ + struct iwreq *iwr = (struct iwreq*)prIfReq; + struct iw_request_info rIwReqInfo; + int ret = 0; + char *prExtraBuf = NULL; + UINT_32 u4ExtraSize = 0; + + /* prDev is verified in the caller function wlanDoIOCTL() */ + + //printk("%d CMD:0x%x\n", jiffies_to_msecs(jiffies), i4Cmd); + + /* Prepare the call */ + rIwReqInfo.cmd = (__u16)i4Cmd; + rIwReqInfo.flags = 0; + + switch (i4Cmd) { + case SIOCGIWNAME: /* 0x8B01, get wireless protocol name */ + ret = wext_get_name(prDev, &rIwReqInfo, (char *)&iwr->u.name, NULL); + break; + + /* case SIOCSIWNWID: 0x8B02, deprecated */ + /* case SIOCGIWNWID: 0x8B03, deprecated */ + + case SIOCSIWFREQ: /* 0x8B04, set channel */ + ret = wext_set_freq(prDev, NULL, &iwr->u.freq, NULL); + break; + + case SIOCGIWFREQ: /* 0x8B05, get channel */ + ret = wext_get_freq(prDev, NULL, &iwr->u.freq, NULL); + break; + + case SIOCSIWMODE: /* 0x8B06, set operation mode */ + ret = wext_set_mode(prDev, NULL, &iwr->u.mode, NULL); + //ret = 0; + break; + + case SIOCGIWMODE: /* 0x8B07, get operation mode */ + ret = wext_get_mode(prDev, NULL, &iwr->u.mode, NULL); + break; + + /* case SIOCSIWSENS: 0x8B08, unsupported */ + /* case SIOCGIWSENS: 0x8B09, unsupported */ + + /* case SIOCSIWRANGE: 0x8B0A, unused */ + case SIOCGIWRANGE: /* 0x8B0B, get range of parameters */ + if (iwr->u.data.pointer != NULL) { + /* Buffer size shoule be large enough */ + if (iwr->u.data.length < sizeof(struct iw_range)) { + ret = -E2BIG; + break; + } + + prExtraBuf = kalMemAlloc(sizeof(struct iw_range), VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = - ENOMEM; + break; + } + + /* reset all fields */ + memset(prExtraBuf, 0, sizeof(struct iw_range)); + iwr->u.data.length = sizeof(struct iw_range); + + ret = wext_get_range(prDev, NULL, &iwr->u.data, prExtraBuf); + /* Push up to the caller */ + if (copy_to_user(iwr->u.data.pointer, + prExtraBuf, + iwr->u.data.length)) { + ret = -EFAULT; + } + + kalMemFree(prExtraBuf, VIR_MEM_TYPE, sizeof(struct iw_range)); + prExtraBuf = NULL; + } + else { + ret = -EINVAL; + } + break; + + case SIOCSIWPRIV: /* 0x8B0C, Country */ + ret = wext_set_country(prDev, iwr); + break; + + /* case SIOCGIWPRIV: 0x8B0D, handled in wlan_do_ioctl() */ + /* caes SIOCSIWSTATS: 0x8B0E, unused */ + /* case SIOCGIWSTATS: + get statistics, intercepted by wireless_process_ioctl() in wireless.c, + redirected to dev_iwstats(), dev->get_wireless_stats(). + */ + /* case SIOCSIWSPY: 0x8B10, unsupported */ + /* case SIOCGIWSPY: 0x8B11, unsupported*/ + /* case SIOCSIWTHRSPY: 0x8B12, unsupported */ + /* case SIOCGIWTHRSPY: 0x8B13, unsupported*/ + + case SIOCSIWAP: /* 0x8B14, set access point MAC addresses (BSSID) */ + if (iwr->u.ap_addr.sa_data[0] == 0 && + iwr->u.ap_addr.sa_data[1] == 0 && + iwr->u.ap_addr.sa_data[2] == 0 && + iwr->u.ap_addr.sa_data[3] == 0 && + iwr->u.ap_addr.sa_data[4] == 0 && + iwr->u.ap_addr.sa_data[5] == 0) { + /* WPA Supplicant will set 000000000000 in + ** wpa_driver_wext_deinit(), do nothing here or disassoc again? + */ + ret = 0; + break; + } + else { + ret = wext_set_ap(prDev, NULL, &iwr->u.ap_addr, NULL); + } + break; + + case SIOCGIWAP: /* 0x8B15, get access point MAC addresses (BSSID) */ + ret = wext_get_ap(prDev, NULL, &iwr->u.ap_addr, NULL); + break; + + case SIOCSIWMLME: /* 0x8B16, request MLME operation */ + /* Fixed length structure */ + if (iwr->u.data.length != sizeof(struct iw_mlme)) { + DBGLOG(INIT, INFO, ("MLME buffer strange:%d\n", iwr->u.data.length)); + ret = -EINVAL; + break; + } + + if (!iwr->u.data.pointer) { + ret = -EINVAL; + break; + } + + prExtraBuf = kalMemAlloc(sizeof(struct iw_mlme), VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = - ENOMEM; + break; + } + + if (copy_from_user(prExtraBuf, iwr->u.data.pointer, sizeof(struct iw_mlme))) { + ret = -EFAULT; + } + else { + ret = wext_set_mlme(prDev, NULL, &(iwr->u.data), prExtraBuf); + } + + kalMemFree(prExtraBuf, VIR_MEM_TYPE, sizeof(struct iw_mlme)); + prExtraBuf = NULL; + break; + + /* case SIOCGIWAPLIST: 0x8B17, deprecated */ + case SIOCSIWSCAN: /* 0x8B18, scan request */ + if (iwr->u.data.pointer == NULL) { + ret = wext_set_scan(prDev, NULL, NULL, NULL); + } +#if WIRELESS_EXT > 17 + else if (iwr->u.data.length == sizeof(struct iw_scan_req)) { + prExtraBuf = kalMemAlloc(MAX_SSID_LEN, VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + if (copy_from_user(prExtraBuf, ((struct iw_scan_req *) (iwr->u.data.pointer))->essid, + ((struct iw_scan_req *) (iwr->u.data.pointer))->essid_len)) { + ret = -EFAULT; + } else { + ret = wext_set_scan(prDev, NULL, (union iwreq_data *) &(iwr->u.data), prExtraBuf); + } + + kalMemFree(prExtraBuf, VIR_MEM_TYPE, MAX_SSID_LEN); + prExtraBuf = NULL; + } +#endif + else { + ret = -EINVAL; + } + break; +#if 1 + case SIOCGIWSCAN: /* 0x8B19, get scan results */ + if (!iwr->u.data.pointer|| !iwr->u.essid.pointer) { + ret = -EINVAL; + break; + } + + u4ExtraSize = iwr->u.data.length; + /* allocate the same size of kernel buffer to store scan results. */ + prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = - ENOMEM; + break; + } + + /* iwr->u.data.length may be updated by wext_get_scan() */ + ret = wext_get_scan(prDev, NULL, &iwr->u.data, prExtraBuf); + if (ret != 0) { + if (ret == -E2BIG) { + DBGLOG(INIT, INFO, ("[wifi] wext_get_scan -E2BIG\n")); + } + } + else { + /* check updated length is valid */ + ASSERT(iwr->u.data.length <= u4ExtraSize); + if (iwr->u.data.length > u4ExtraSize) { + DBGLOG(INIT, INFO, ("Updated result length is larger than allocated (%d > %ld)\n", + iwr->u.data.length, u4ExtraSize)); + iwr->u.data.length = u4ExtraSize; + } + + if (copy_to_user(iwr->u.data.pointer, + prExtraBuf, + iwr->u.data.length)) { + ret = -EFAULT; + } + } + + kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); + prExtraBuf = NULL; + + break; + +#endif + +#if 1 + case SIOCSIWESSID: /* 0x8B1A, set SSID (network name) */ + if (iwr->u.essid.length > IW_ESSID_MAX_SIZE) { + ret = -E2BIG; + break; + } + if (!iwr->u.essid.pointer) { + ret = -EINVAL; + break; + } + + prExtraBuf = kalMemAlloc(IW_ESSID_MAX_SIZE + 4, VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = - ENOMEM; + break; + } + + if (copy_from_user(prExtraBuf, + iwr->u.essid.pointer, + iwr->u.essid.length)) { + ret = -EFAULT; + } + else { + /* Add trailing '\0' for printk */ + //prExtraBuf[iwr->u.essid.length] = 0; + //printk(KERN_INFO "wext_set_essid: %s (%d)\n", prExtraBuf, iwr->u.essid.length); + ret = wext_set_essid(prDev, NULL, &iwr->u.essid, prExtraBuf); + //printk ("set essid %d\n", ret); + } + + kalMemFree(prExtraBuf, VIR_MEM_TYPE, IW_ESSID_MAX_SIZE + 4); + prExtraBuf = NULL; + break; + +#endif + + case SIOCGIWESSID: /* 0x8B1B, get SSID */ + if (!iwr->u.essid.pointer) { + ret = -EINVAL; + break; + } + + if (iwr->u.essid.length < IW_ESSID_MAX_SIZE) { + DBGLOG(INIT, INFO, ("[wifi] iwr->u.essid.length:%d too small\n", + iwr->u.essid.length)); + ret = -E2BIG; /* let caller try larger buffer */ + break; + } + + prExtraBuf = kalMemAlloc(IW_ESSID_MAX_SIZE, VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + /* iwr->u.essid.length is updated by wext_get_essid() */ + + ret = wext_get_essid(prDev, NULL, &iwr->u.essid, prExtraBuf); + if (ret == 0) { + if (copy_to_user(iwr->u.essid.pointer, prExtraBuf, iwr->u.essid.length)) { + ret = -EFAULT; + } + } + + kalMemFree(prExtraBuf, VIR_MEM_TYPE, IW_ESSID_MAX_SIZE); + prExtraBuf = NULL; + + break; + + /* case SIOCSIWNICKN: 0x8B1C, not supported */ + /* case SIOCGIWNICKN: 0x8B1D, not supported */ + + case SIOCSIWRATE: /* 0x8B20, set default bit rate (bps) */ + //ret = wext_set_rate(prDev, &rIwReqInfo, &iwr->u.bitrate, NULL); + break; + + case SIOCGIWRATE: /* 0x8B21, get current bit rate (bps) */ + ret = wext_get_rate(prDev, NULL, &iwr->u.bitrate, NULL); + break; + + case SIOCSIWRTS: /* 0x8B22, set rts/cts threshold */ + ret = wext_set_rts(prDev, NULL, &iwr->u.rts, NULL); + break; + + case SIOCGIWRTS: /* 0x8B23, get rts/cts threshold */ + ret = wext_get_rts(prDev, NULL, &iwr->u.rts, NULL); + break; + + /* case SIOCSIWFRAG: 0x8B24, unsupported */ + case SIOCGIWFRAG: /* 0x8B25, get frag threshold */ + ret = wext_get_frag(prDev, NULL, &iwr->u.frag, NULL); + break; + + case SIOCSIWTXPOW: /* 0x8B26, set relative tx power (in %) */ + ret = wext_set_txpow(prDev, NULL, &iwr->u.txpower, NULL); + break; + + case SIOCGIWTXPOW: /* 0x8B27, get relative tx power (in %) */ + ret = wext_get_txpow(prDev, NULL, &iwr->u.txpower, NULL); + break; + + /* case SIOCSIWRETRY: 0x8B28, unsupported */ + /* case SIOCGIWRETRY: 0x8B29, unsupported */ + +#if 1 + case SIOCSIWENCODE: /* 0x8B2A, set encoding token & mode */ + /* Only DISABLED case has NULL pointer and length == 0 */ + if (iwr->u.encoding.pointer) { + if (iwr->u.encoding.length > 16) { + ret = -E2BIG; + break; + } + + u4ExtraSize = iwr->u.encoding.length; + prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + if (copy_from_user(prExtraBuf, + iwr->u.encoding.pointer, + iwr->u.encoding.length)) { + ret = -EFAULT; + } + } + else if (iwr->u.encoding.length != 0) { + ret = -EINVAL; + break; + } + + if (ret == 0) { + ret = wext_set_encode(prDev, NULL, &iwr->u.encoding, prExtraBuf); + } + + if (prExtraBuf) { + kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); + prExtraBuf = NULL; + } + break; + + case SIOCGIWENCODE: /* 0x8B2B, get encoding token & mode */ + /* check pointer */ + ret = wext_get_encode(prDev, NULL, &iwr->u.encoding, NULL); + break; + + case SIOCSIWPOWER: /* 0x8B2C, set power management */ + ret = wext_set_power(prDev, NULL, &iwr->u.power, NULL); + break; + + case SIOCGIWPOWER: /* 0x8B2D, get power management */ + ret = wext_get_power(prDev, NULL, &iwr->u.power, NULL); + break; + +#if WIRELESS_EXT > 17 + case SIOCSIWGENIE: /* 0x8B30, set gen ie */ + if (iwr->u.data.pointer) { + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)netdev_priv(prDev); + if (1 /* wlanQueryWapiMode(prGlueInfo->prAdapter) */) { + /* Fixed length structure */ +#if CFG_SUPPORT_WAPI + if (iwr->u.data.length > 42 /* The max wapi ie buffer */) { + ret = -EINVAL; + break; + } +#endif + u4ExtraSize = iwr->u.data.length; + if (u4ExtraSize) { + prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + if (copy_from_user(prExtraBuf, + iwr->u.data.pointer, + iwr->u.data.length)) { + ret = -EFAULT; + } + else { + WLAN_STATUS rStatus; + UINT_32 u4BufLen; +#if CFG_SUPPORT_WAPI + rStatus = kalIoctl(prGlueInfo, + wlanoidSetWapiAssocInfo, + prExtraBuf, + u4ExtraSize, + FALSE, + FALSE, + TRUE, + FALSE, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + //printk(KERN_INFO "[wapi] set wapi assoc info error:%lx\n", rStatus); +#endif +#if CFG_SUPPORT_WPS2 + PUINT_8 prDesiredIE = NULL; + if (wextSrchDesiredWPSIE(prExtraBuf, + u4ExtraSize, + 0xDD, + (PUINT_8 *)&prDesiredIE)) { + rStatus = kalIoctl(prGlueInfo, + wlanoidSetWSCAssocInfo, + prDesiredIE, + IE_SIZE(prDesiredIE), + FALSE, + FALSE, + TRUE, + FALSE, + &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + //printk(KERN_INFO "[WSC] set WSC assoc info error:%lx\n", rStatus); + } + } +#endif +#if CFG_SUPPORT_WAPI + } +#endif + } + kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); + prExtraBuf = NULL; + } + } + } + break; + + case SIOCGIWGENIE: /* 0x8B31, get gen ie, unused */ + break; + +#endif + + case SIOCSIWAUTH: /* 0x8B32, set auth mode params */ + ret = wext_set_auth(prDev, NULL, &iwr->u.param, NULL); + break; + + /* case SIOCGIWAUTH: 0x8B33, unused? */ + case SIOCSIWENCODEEXT: /* 0x8B34, set extended encoding token & mode */ + if (iwr->u.encoding.pointer) { + u4ExtraSize = iwr->u.encoding.length; + prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + if (copy_from_user(prExtraBuf, + iwr->u.encoding.pointer, + iwr->u.encoding.length)) { + ret = -EFAULT; + } + } + else if (iwr->u.encoding.length != 0) { + ret = -EINVAL; + break; + } + + if (ret == 0) { + ret = wext_set_encode_ext(prDev, NULL, &iwr->u.encoding, prExtraBuf); + } + + if (prExtraBuf) { + kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); + prExtraBuf = NULL; + } + break; + + /* case SIOCGIWENCODEEXT: 0x8B35, unused? */ + + case SIOCSIWPMKSA: /* 0x8B36, pmksa cache operation */ + #if 1 + if (iwr->u.data.pointer) { + /* Fixed length structure */ + if (iwr->u.data.length != sizeof(struct iw_pmksa)) { + ret = -EINVAL; + break; + } + + u4ExtraSize = sizeof(struct iw_pmksa); + prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + if (copy_from_user(prExtraBuf, + iwr->u.data.pointer, + sizeof(struct iw_pmksa))) { + ret = -EFAULT; + } + else { + switch(((struct iw_pmksa *)prExtraBuf)->cmd) { + case IW_PMKSA_ADD: + /* + printk(KERN_INFO "IW_PMKSA_ADD [" MACSTR "]\n", + MAC2STR(((struct iw_pmksa *)pExtraBuf)->bssid.sa_data)); + */ + { + P_GLUE_INFO_T prGlueInfo = + (P_GLUE_INFO_T)netdev_priv(prDev); + WLAN_STATUS rStatus; + UINT_32 u4BufLen; + P_PARAM_PMKID_T prPmkid; + + prPmkid =(P_PARAM_PMKID_T)kalMemAlloc(8 + sizeof(PARAM_BSSID_INFO_T), VIR_MEM_TYPE); + if (!prPmkid) { + DBGLOG(INIT, INFO, ("Can not alloc memory for IW_PMKSA_ADD\n")); + ret = -ENOMEM; + break; + } + + prPmkid->u4Length = 8 + sizeof(PARAM_BSSID_INFO_T); + prPmkid->u4BSSIDInfoCount = 1; + kalMemCopy(prPmkid->arBSSIDInfo->arBSSID, + ((struct iw_pmksa *)prExtraBuf)->bssid.sa_data, + 6); + kalMemCopy(prPmkid->arBSSIDInfo->arPMKID, + ((struct iw_pmksa *)prExtraBuf)->pmkid, + IW_PMKID_LEN); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetPmkid, + prPmkid, + sizeof(PARAM_PMKID_T), + FALSE, + FALSE, + TRUE, + FALSE, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, ("add pmkid error:%lx\n", rStatus)); + } + kalMemFree(prPmkid, VIR_MEM_TYPE, 8 + sizeof(PARAM_BSSID_INFO_T)); + } + break; + case IW_PMKSA_REMOVE: + /* + printk(KERN_INFO "IW_PMKSA_REMOVE [" MACSTR "]\n", + MAC2STR(((struct iw_pmksa *)buf)->bssid.sa_data)); + */ + break; + case IW_PMKSA_FLUSH: + /* + printk(KERN_INFO "IW_PMKSA_FLUSH\n"); + */ + { + P_GLUE_INFO_T prGlueInfo = + (P_GLUE_INFO_T)netdev_priv(prDev); + WLAN_STATUS rStatus; + UINT_32 u4BufLen; + P_PARAM_PMKID_T prPmkid; + + prPmkid =(P_PARAM_PMKID_T)kalMemAlloc(8, VIR_MEM_TYPE); + if (!prPmkid) { + DBGLOG(INIT, INFO, ("Can not alloc memory for IW_PMKSA_FLUSH\n")); + ret = -ENOMEM; + break; + } + + prPmkid->u4Length = 8; + prPmkid->u4BSSIDInfoCount = 0; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetPmkid, + prPmkid, + sizeof(PARAM_PMKID_T), + FALSE, + FALSE, + TRUE, + FALSE, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, ("flush pmkid error:%lx\n", rStatus)); + } + kalMemFree(prPmkid, VIR_MEM_TYPE, 8); + } + break; + default: + DBGLOG(INIT, INFO, ("UNKNOWN iw_pmksa command:%d\n", + ((struct iw_pmksa *)prExtraBuf)->cmd)); + ret = -EFAULT; + break; + } + } + + if (prExtraBuf) { + kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); + prExtraBuf = NULL; + } + } + else if (iwr->u.data.length != 0) { + ret = -EINVAL; + break; + } + #endif + break; + +#endif + + default: + /* printk(KERN_NOTICE "unsupported IOCTL: 0x%x\n", i4Cmd); */ + ret = -EOPNOTSUPP; + break; + } + + //printk("%ld CMD:0x%x ret:%d\n", jiffies_to_msecs(jiffies), i4Cmd, ret); + + return ret; +} /* wext_support_ioctl */ + + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To send an event (RAW socket pacekt) to user process actively. +* +* \param[in] prGlueInfo Glue layer info. +* \param[in] u4cmd Whcih event command we want to indicate to user process. +* \param[in] pData Data buffer to be indicated. +* \param[in] dataLen Available data size in pData. +* +* \return (none) +* +* \note Event is indicated to upper layer if cmd is supported and data is valid. +* Using of kernel symbol wireless_send_event(), which is defined in +* after WE-14 (2.4.20). +*/ +/*----------------------------------------------------------------------------*/ +void +wext_indicate_wext_event ( + IN P_GLUE_INFO_T prGlueInfo, + IN unsigned int u4Cmd, + IN unsigned char *pucData, + IN unsigned int u4dataLen + ) +{ + union iwreq_data wrqu; + unsigned char *pucExtraInfo = NULL; +#if WIRELESS_EXT >= 15 + unsigned char *pucDesiredIE = NULL; + unsigned char aucExtraInfoBuf[200]; +#endif +#if WIRELESS_EXT < 18 + int i; +#endif + + memset(&wrqu, 0, sizeof(wrqu)); + + switch (u4Cmd) { + case SIOCGIWTXPOW: + memcpy(&wrqu.power, pucData, u4dataLen); + break; + case SIOCGIWSCAN: + complete_all(&prGlueInfo->rScanComp); + break; + + case SIOCGIWAP: + if (pucData) { + memcpy(&wrqu.ap_addr.sa_data, pucData, ETH_ALEN); + } + else { + memset(&wrqu.ap_addr.sa_data, 0, ETH_ALEN); + } + break; + + case IWEVASSOCREQIE: +#if WIRELESS_EXT < 15 + /* under WE-15, no suitable Event can be used */ + goto skip_indicate_event; +#else + /* do supplicant a favor, parse to the start of WPA/RSN IE */ + if (wextSrchDesiredWPAIE(pucData, u4dataLen, 0x30, &pucDesiredIE)) { + /* RSN IE found */ + } +#if 0 + else if (wextSrchDesiredWPSIE(pucData, u4dataLen, 0xDD, &pucDesiredIE)) { + /* WPS IE found */ + } +#endif + else if (wextSrchDesiredWPAIE(pucData, u4dataLen, 0xDD, &pucDesiredIE)) { + /* WPA IE found */ + } +#if CFG_SUPPORT_WAPI /* Android+ */ + else if (wextSrchDesiredWAPIIE(pucData, u4dataLen, &pucDesiredIE)) { + //printk("wextSrchDesiredWAPIIE!!\n"); + /* WAPI IE found */ + } +#endif + else { + /* no WPA/RSN IE found, skip this event */ + goto skip_indicate_event; + } + + #if WIRELESS_EXT < 18 + /* under WE-18, only IWEVCUSTOM can be used */ + u4Cmd = IWEVCUSTOM; + pucExtraInfo = aucExtraInfoBuf; + pucExtraInfo += sprintf(pucExtraInfo, "ASSOCINFO(ReqIEs="); + /* printk(KERN_DEBUG "assoc info buffer size needed:%d\n", infoElemLen * 2 + 17); */ + /* translate binary string to hex string, requirement of IWEVCUSTOM */ + for (i = 0; i < pucDesiredIE[1] + 2 ; ++i) { + pucExtraInfo += sprintf(pucExtraInfo, "%02x", pucDesiredIE[i]); + } + pucExtraInfo = aucExtraInfoBuf; + wrqu.data.length = 17 + (pucDesiredIE[1] + 2) * 2; + #else + /* IWEVASSOCREQIE, indicate binary string */ + pucExtraInfo = pucDesiredIE; + wrqu.data.length = pucDesiredIE[1] + 2; + #endif +#endif /* WIRELESS_EXT < 15 */ + break; + + case IWEVMICHAELMICFAILURE: +#if WIRELESS_EXT < 15 + /* under WE-15, no suitable Event can be used */ + goto skip_indicate_event; +#else + if (pucData) { + P_PARAM_AUTH_REQUEST_T pAuthReq = (P_PARAM_AUTH_REQUEST_T)pucData; + /* under WE-18, only IWEVCUSTOM can be used */ + u4Cmd = IWEVCUSTOM; + pucExtraInfo = aucExtraInfoBuf; + pucExtraInfo += sprintf(pucExtraInfo, + "MLME-MICHAELMICFAILURE.indication "); + pucExtraInfo += sprintf(pucExtraInfo, + "%s", + (pAuthReq->u4Flags == PARAM_AUTH_REQUEST_GROUP_ERROR) ? + "groupcast " : "unicast "); + + wrqu.data.length = pucExtraInfo - aucExtraInfoBuf; + pucExtraInfo = aucExtraInfoBuf; + } +#endif /* WIRELESS_EXT < 15 */ + break; + + case IWEVPMKIDCAND: + if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_WPA2 && + prGlueInfo->rWpaInfo.u4KeyMgmt == IW_AUTH_KEY_MGMT_802_1X) { + + /* only used in WPA2 */ +#if WIRELESS_EXT >= 18 + P_PARAM_PMKID_CANDIDATE_T prPmkidCand = (P_PARAM_PMKID_CANDIDATE_T)pucData; + + struct iw_pmkid_cand rPmkidCand; + pucExtraInfo = aucExtraInfoBuf; + + rPmkidCand.flags = prPmkidCand->u4Flags; + rPmkidCand.index = 0; + kalMemCopy(rPmkidCand.bssid.sa_data, prPmkidCand->arBSSID, 6); + + kalMemCopy(pucExtraInfo, (PUINT_8)&rPmkidCand, sizeof(struct iw_pmkid_cand)); + wrqu.data.length = sizeof(struct iw_pmkid_cand); + + /* pmkid canadidate list is supported after WE-18 */ + /* indicate struct iw_pmkid_cand */ +#else + /* printk(KERN_INFO "IWEVPMKIDCAND event skipped, WE < 18\n"); */ + goto skip_indicate_event; +#endif + } + else { + /* printk(KERN_INFO "IWEVPMKIDCAND event skipped, NOT WPA2\n"); */ + goto skip_indicate_event; + } + break; + + case IWEVCUSTOM: + u4Cmd = IWEVCUSTOM; + pucExtraInfo = aucExtraInfoBuf; + kalMemCopy(pucExtraInfo, pucData, sizeof(PTA_IPC_T)); + wrqu.data.length = sizeof(PTA_IPC_T); + break; + + default: + /* printk(KERN_INFO "Unsupported wext event:%x\n", cmd); */ + goto skip_indicate_event; + } + + /* Send event to user space */ + wireless_send_event(prGlueInfo->prDevHandler, u4Cmd, &wrqu, pucExtraInfo); + +skip_indicate_event: + return; +} /* wext_indicate_wext_event */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief A method of struct net_device, to get the network interface statistical +* information. +* +* Whenever an application needs to get statistics for the interface, this method +* is called. This happens, for example, when ifconfig or netstat -i is run. +* +* \param[in] pDev Pointer to struct net_device. +* +* \return net_device_stats buffer pointer. +* +*/ +/*----------------------------------------------------------------------------*/ +struct iw_statistics * +wext_get_wireless_stats ( + struct net_device *prDev + ) +{ + + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + P_GLUE_INFO_T prGlueInfo = NULL; + struct iw_statistics *pStats = NULL; + INT_32 i4Rssi; + UINT_32 bufLen = 0; + + + + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prDev); + ASSERT(prGlueInfo); + if (!prGlueInfo) { + goto stat_out; + } + + pStats = (struct iw_statistics *) (&(prGlueInfo->rIwStats)); + + if (!prDev || !netif_carrier_ok(prDev)) { + /* network not connected */ + goto stat_out; + } + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryRssi, + &i4Rssi, + sizeof(i4Rssi), + TRUE, + TRUE, + TRUE, + FALSE, + &bufLen); + +stat_out: + return pStats; +} /* wlan_get_wireless_stats */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To report the private supported IOCTLs table to user space. +* +* \param[in] prNetDev Net device requested. +* \param[out] prIfReq Pointer to ifreq structure, content is copied back to +* user space buffer in gl_iwpriv_table. +* +* \retval 0 For success. +* \retval -E2BIG For user's buffer size is too small. +* \retval -EFAULT For fail. +* +*/ +/*----------------------------------------------------------------------------*/ +int +wext_get_priv ( + IN struct net_device *prNetDev, + IN struct ifreq *prIfReq + ) +{ + /* prIfReq is verified in the caller function wlanDoIOCTL() */ + struct iwreq *prIwReq = (struct iwreq *)prIfReq; + struct iw_point *prData= (struct iw_point *)&prIwReq->u.data; + UINT_16 u2BufferSize = 0; + + u2BufferSize = prData->length; + + /* update our private table size */ + prData->length = (__u16)sizeof(rIwPrivTable)/sizeof(struct iw_priv_args); + + if (u2BufferSize < prData->length) { + return -E2BIG; + } + + if (prData->length) { + if (copy_to_user(prData->pointer, rIwPrivTable, sizeof(rIwPrivTable))) { + return -EFAULT; + } + } + + return 0; +} /* wext_get_priv */ + +#endif /* WIRELESS_EXT */ + + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_wext_priv.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_wext_priv.c new file mode 100755 index 000000000000..c7c4fb150e1a --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/gl_wext_priv.c @@ -0,0 +1,2292 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/os/linux/gl_wext_priv.c#1 $ +*/ + +/*! \file gl_wext_priv.c + \brief This file includes private ioctl support. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: gl_wext_priv.c $ + * + * 02 06 2012 wh.su + * [ALPS00109161] [Need Patch] [Volunteer Patch] [Wi-Fi] Support the set tx power driver cmd + * Adding the AP mode channel query filter. + * + * 01 20 2012 cp.wu + * [ALPS00096191] [MT6620 Wi-Fi][Driver][Firmware] Porting to ALPS4.0_DEV branch + * sync to up-to-date changes including: + * 1. BOW bugfix + * 2. XLOG + * + * 01 09 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Check in the Add Tx power Cmd to driver. + * + * 01 02 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Adding the proto type function for set_int set_tx_power and get int get_ch_list. + * + * 11 10 2011 cp.wu + * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer + * 1. eliminaite direct calls to printk in porting layer. + * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. + * + * 11 03 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings + * Fixed typo. + * + * 10 24 2011 terry.wu + * NULL + * Rollback to previous verson due to misbranch check-in + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 03 07 2011 terry.wu + * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message + * Toggle non-standard debug messages to comments. + * + * 01 27 2011 cm.chang + * [WCXRP00000402] [MT6620 Wi-Fi][Driver] Enable MCR read/write by iwpriv by default + * . + * + * 01 26 2011 wh.su + * [WCXRP00000396] [MT6620 Wi-Fi][Driver] Support Sw Ctrl ioctl at linux + * adding the SW cmd ioctl support, use set/get structure ioctl. + * + * 01 20 2011 eddie.chen + * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control + * Adjust OID order. + * + * 01 20 2011 eddie.chen + * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control + * Add Oid for sw control debug command + * + * 01 07 2011 cm.chang + * [WCXRP00000336] [MT6620 Wi-Fi][Driver] Add test mode commands in normal phone operation + * Add a new compiling option to control if MCR read/write is permitted + * + * 12 31 2010 cm.chang + * [WCXRP00000336] [MT6620 Wi-Fi][Driver] Add test mode commands in normal phone operation + * Add some iwpriv commands to support test mode operation + * + * 12 15 2010 george.huang + * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function + * Support set PS profile and set WMM-PS related iwpriv. + * + * 11 08 2010 wh.su + * [WCXRP00000171] [MT6620 Wi-Fi][Driver] Add message check code same behavior as mt5921 + * add the message check code from mt5921. + * + * 10 18 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android + * complete implementation of Android NVRAM access + * + * 09 24 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * correct typo for NVRAM access. + * + * 09 23 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * add skeleton for NVRAM integration + * + * 08 04 2010 cp.wu + * NULL + * revert changelist #15371, efuse read/write access will be done by RF test approach + * + * 08 04 2010 cp.wu + * NULL + * add OID definitions for EFUSE read/write access. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 06 01 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * enable OID_CUSTOM_MTK_WIFI_TEST for RFTest & META tool + * + * 05 29 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * fix private ioctl for rftest + * + * 04 21 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * add for private ioctl support +** \main\maintrunk.MT5921\32 2009-10-08 10:33:25 GMT mtk01090 +** Avoid accessing private data of net_device directly. Replace with netdev_priv(). Add more checking for input parameters and pointers. +** \main\maintrunk.MT5921\31 2009-09-29 16:46:21 GMT mtk01090 +** Remove unused functions +** \main\maintrunk.MT5921\30 2009-09-29 14:46:47 GMT mtk01090 +** Fix compile warning +** \main\maintrunk.MT5921\29 2009-09-29 14:28:48 GMT mtk01090 +** Fix compile warning +** \main\maintrunk.MT5921\28 2009-09-28 22:21:38 GMT mtk01090 +** Refine lines to supress compile warning +** \main\maintrunk.MT5921\27 2009-09-28 20:19:14 GMT mtk01090 +** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. +** \main\maintrunk.MT5921\26 2009-08-18 22:56:53 GMT mtk01090 +** Add Linux SDIO (with mmc core) support. +** Add Linux 2.6.21, 2.6.25, 2.6.26. +** Fix compile warning in Linux. +** \main\maintrunk.MT5921\25 2009-05-07 22:26:15 GMT mtk01089 +** Add mandatory and private IO control for Linux BWCS +** \main\maintrunk.MT5921\24 2009-04-29 10:07:05 GMT mtk01088 +** fixed the compiling error at linux +** \main\maintrunk.MT5921\23 2009-04-24 09:09:45 GMT mtk01088 +** mark the code not used at linux supplicant v0.6.7 +** \main\maintrunk.MT5921\22 2008-11-24 21:03:51 GMT mtk01425 +** 1. Add PTA_ENABLED flag +** \main\maintrunk.MT5921\21 2008-08-29 14:55:59 GMT mtk01088 +** adjust the code for meet the coding style, and add assert check +** \main\maintrunk.MT5921\20 2008-07-16 15:23:20 GMT mtk01104 +** Support GPIO2 mode +** \main\maintrunk.MT5921\19 2008-07-15 17:43:11 GMT mtk01084 +** modify variable name +** \main\maintrunk.MT5921\18 2008-07-14 14:37:58 GMT mtk01104 +** Add exception handle about length in function priv_set_struct() +** \main\maintrunk.MT5921\17 2008-07-14 13:55:32 GMT mtk01104 +** Support PRIV_CMD_BT_COEXIST +** \main\maintrunk.MT5921\16 2008-07-09 00:20:15 GMT mtk01461 +** Add priv oid to support WMM_PS_TEST +** \main\maintrunk.MT5921\15 2008-06-02 11:15:22 GMT mtk01461 +** Update after wlanoidSetPowerMode changed +** \main\maintrunk.MT5921\14 2008-05-30 19:31:07 GMT mtk01461 +** Add IOCTL for Power Mode +** \main\maintrunk.MT5921\13 2008-05-30 18:57:15 GMT mtk01461 +** Not use wlanoidSetCSUMOffloadForLinux() +** \main\maintrunk.MT5921\12 2008-05-30 15:13:18 GMT mtk01084 +** rename wlanoid +** \main\maintrunk.MT5921\11 2008-05-29 14:16:31 GMT mtk01084 +** rename for wlanoidSetBeaconIntervalForLinux +** \main\maintrunk.MT5921\10 2008-04-17 23:06:37 GMT mtk01461 +** Add iwpriv support for AdHocMode setting +** \main\maintrunk.MT5921\9 2008-03-31 21:00:55 GMT mtk01461 +** Add priv IOCTL for VOIP setting +** \main\maintrunk.MT5921\8 2008-03-31 13:49:43 GMT mtk01461 +** Add priv ioctl to turn on / off roaming +** \main\maintrunk.MT5921\7 2008-03-26 15:35:14 GMT mtk01461 +** Add CSUM offload priv ioctl for Linux +** \main\maintrunk.MT5921\6 2008-03-11 14:50:59 GMT mtk01461 +** Unify priv ioctl +** \main\maintrunk.MT5921\5 2007-11-06 19:32:30 GMT mtk01088 +** add WPS code +** \main\maintrunk.MT5921\4 2007-10-30 12:01:39 GMT MTK01425 +** 1. Update wlanQueryInformation and wlanSetInformation +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "gl_os.h" +#include "gl_wext_priv.h" +#if CFG_SUPPORT_WAPI +#include "gl_sec.h" +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define NUM_SUPPORTED_OIDS (sizeof(arWlanOidReqTable) / sizeof(WLAN_REQ_ENTRY)) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +static int +priv_get_ndis ( + IN struct net_device *prNetDev, + IN NDIS_TRANSPORT_STRUCT* prNdisReq, + OUT PUINT_32 pu4OutputLen + ); + +static int +priv_set_ndis ( + IN struct net_device *prNetDev, + IN NDIS_TRANSPORT_STRUCT* prNdisReq, + OUT PUINT_32 pu4OutputLen + ); + +#if 0 /* CFG_SUPPORT_WPS */ +static int +priv_set_appie ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, + OUT char *pcExtra + ); + +static int +priv_set_filter ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, + OUT char *pcExtra + ); +#endif /* CFG_SUPPORT_WPS */ + +static BOOLEAN +reqSearchSupportedOidEntry ( + IN UINT_32 rOid, + OUT P_WLAN_REQ_ENTRY *ppWlanReqEntry + ); + +#if 0 +static WLAN_STATUS +reqExtQueryConfiguration ( + IN P_GLUE_INFO_T prGlueInfo, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +static WLAN_STATUS +reqExtSetConfiguration ( + IN P_GLUE_INFO_T prGlueInfo, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); +#endif + +static WLAN_STATUS +reqExtSetAcpiDevicePowerState ( + IN P_GLUE_INFO_T prGlueInfo, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +static UINT_8 aucOidBuf[4096] = {0}; + +/* OID processing table */ +/* Order is important here because the OIDs should be in order of + increasing value for binary searching. */ +static WLAN_REQ_ENTRY arWlanOidReqTable[] = { + /* + {(NDIS_OID)rOid, + (PUINT_8)pucOidName, + fgQryBufLenChecking, fgSetBufLenChecking, fgIsHandleInGlueLayerOnly, u4InfoBufLen, + pfOidQueryHandler, + pfOidSetHandler} + */ + /* General Operational Characteristics */ + + /* Ethernet Operational Characteristics */ + {OID_802_3_CURRENT_ADDRESS, + DISP_STRING("OID_802_3_CURRENT_ADDRESS"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, 6, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryCurrentAddr, + NULL}, + + /* OID_802_3_MULTICAST_LIST */ + /* OID_802_3_MAXIMUM_LIST_SIZE */ + /* Ethernet Statistics */ + + /* NDIS 802.11 Wireless LAN OIDs */ + {OID_802_11_SUPPORTED_RATES, + DISP_STRING("OID_802_11_SUPPORTED_RATES"), + TRUE, FALSE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_RATES_EX), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQuerySupportedRates, + NULL}, + /* + {OID_802_11_CONFIGURATION, + DISP_STRING("OID_802_11_CONFIGURATION"), + TRUE, TRUE, ENUM_OID_GLUE_EXTENSION, sizeof(PARAM_802_11_CONFIG_T), + (PFN_OID_HANDLER_FUNC_REQ)reqExtQueryConfiguration, + (PFN_OID_HANDLER_FUNC_REQ)reqExtSetConfiguration}, + */ + {OID_PNP_SET_POWER, + DISP_STRING("OID_PNP_SET_POWER"), + TRUE, FALSE, ENUM_OID_GLUE_EXTENSION, sizeof(PARAM_DEVICE_POWER_STATE), + NULL, + (PFN_OID_HANDLER_FUNC_REQ)reqExtSetAcpiDevicePowerState}, + + /* Custom OIDs */ + {OID_CUSTOM_OID_INTERFACE_VERSION, + DISP_STRING("OID_CUSTOM_OID_INTERFACE_VERSION"), + TRUE, FALSE, ENUM_OID_DRIVER_CORE, 4, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryOidInterfaceVersion, + NULL}, + + /* +#if PTA_ENABLED + {OID_CUSTOM_BT_COEXIST_CTRL, + DISP_STRING("OID_CUSTOM_BT_COEXIST_CTRL"), + FALSE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_BT_COEXIST_T), + NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetBtCoexistCtrl}, +#endif + */ + + /* + {OID_CUSTOM_POWER_MANAGEMENT_PROFILE, + DISP_STRING("OID_CUSTOM_POWER_MANAGEMENT_PROFILE"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryPwrMgmtProfParam, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetPwrMgmtProfParam}, + {OID_CUSTOM_PATTERN_CONFIG, + DISP_STRING("OID_CUSTOM_PATTERN_CONFIG"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_PATTERN_SEARCH_CONFIG_STRUC_T), + NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetPatternConfig}, + {OID_CUSTOM_BG_SSID_SEARCH_CONFIG, + DISP_STRING("OID_CUSTOM_BG_SSID_SEARCH_CONFIG"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, + NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetBgSsidParam}, + {OID_CUSTOM_VOIP_SETUP, + DISP_STRING("OID_CUSTOM_VOIP_SETUP"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, 4, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryVoipConnectionStatus, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetVoipConnectionStatus}, + {OID_CUSTOM_ADD_TS, + DISP_STRING("OID_CUSTOM_ADD_TS"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, 4, + NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidAddTS}, + {OID_CUSTOM_DEL_TS, + DISP_STRING("OID_CUSTOM_DEL_TS"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, 4, + NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidDelTS}, + */ + + /* +#if CFG_LP_PATTERN_SEARCH_SLT + {OID_CUSTOM_SLT, + DISP_STRING("OID_CUSTOM_SLT"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQuerySltResult, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetSltMode}, +#endif + + {OID_CUSTOM_ROAMING_EN, + DISP_STRING("OID_CUSTOM_ROAMING_EN"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, 4, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryRoamingFunction, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetRoamingFunction}, + {OID_CUSTOM_WMM_PS_TEST, + DISP_STRING("OID_CUSTOM_WMM_PS_TEST"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, 4, + NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetWiFiWmmPsTest}, + {OID_CUSTOM_COUNTRY_STRING, + DISP_STRING("OID_CUSTOM_COUNTRY_STRING"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryCurrentCountry, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetCurrentCountry}, + +#if CFG_SUPPORT_802_11D + {OID_CUSTOM_MULTI_DOMAIN_CAPABILITY, + DISP_STRING("OID_CUSTOM_MULTI_DOMAIN_CAPABILITY"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryMultiDomainCap, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetMultiDomainCap}, +#endif + + {OID_CUSTOM_GPIO2_MODE, + DISP_STRING("OID_CUSTOM_GPIO2_MODE"), + FALSE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(ENUM_PARAM_GPIO2_MODE_T), + NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetGPIO2Mode}, + {OID_CUSTOM_CONTINUOUS_POLL, + DISP_STRING("OID_CUSTOM_CONTINUOUS_POLL"), + FALSE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CONTINUOUS_POLL_T), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryContinuousPollInterval, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetContinuousPollProfile}, + {OID_CUSTOM_DISABLE_BEACON_DETECTION, + DISP_STRING("OID_CUSTOM_DISABLE_BEACON_DETECTION"), + FALSE, TRUE, ENUM_OID_DRIVER_CORE, 4, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryDisableBeaconDetectionFunc, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetDisableBeaconDetectionFunc}, + */ + + /* WPS */ + /* + {OID_CUSTOM_DISABLE_PRIVACY_CHECK, + DISP_STRING("OID_CUSTOM_DISABLE_PRIVACY_CHECK"), + FALSE, TRUE, ENUM_OID_DRIVER_CORE, 4, + NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetDisablePriavcyCheck}, + */ + + {OID_CUSTOM_MCR_RW, + DISP_STRING("OID_CUSTOM_MCR_RW"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_MCR_RW_STRUC_T), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryMcrRead, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetMcrWrite}, + + {OID_CUSTOM_EEPROM_RW, + DISP_STRING("OID_CUSTOM_EEPROM_RW"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_EEPROM_RW_STRUC_T), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryEepromRead, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetEepromWrite}, + + {OID_CUSTOM_SW_CTRL, + DISP_STRING("OID_CUSTOM_SW_CTRL"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_SW_CTRL_STRUC_T), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQuerySwCtrlRead, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetSwCtrlWrite}, + + {OID_CUSTOM_TEST_MODE, + DISP_STRING("OID_CUSTOM_TEST_MODE"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, + NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidRftestSetTestMode}, + + /* + {OID_CUSTOM_TEST_RX_STATUS, + DISP_STRING("OID_CUSTOM_TEST_RX_STATUS"), + FALSE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_RFTEST_RX_STATUS_STRUC_T), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryRfTestRxStatus, + NULL}, + {OID_CUSTOM_TEST_TX_STATUS, + DISP_STRING("OID_CUSTOM_TEST_TX_STATUS"), + FALSE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_RFTEST_TX_STATUS_STRUC_T), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryRfTestTxStatus, + NULL}, + */ + {OID_CUSTOM_ABORT_TEST_MODE, + DISP_STRING("OID_CUSTOM_ABORT_TEST_MODE"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, + NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidRftestSetAbortTestMode}, + {OID_CUSTOM_MTK_WIFI_TEST, + DISP_STRING("OID_CUSTOM_MTK_WIFI_TEST"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_MTK_WIFI_TEST_STRUC_T), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidRftestQueryAutoTest, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidRftestSetAutoTest}, + + /* OID_CUSTOM_EMULATION_VERSION_CONTROL */ + + /* BWCS */ +#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS + {OID_CUSTOM_BWCS_CMD, + DISP_STRING("OID_CUSTOM_BWCS_CMD"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, sizeof(PTA_IPC_T), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryBT, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetBT}, +#endif + +/* {OID_CUSTOM_SINGLE_ANTENNA, + DISP_STRING("OID_CUSTOM_SINGLE_ANTENNA"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, 4, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryBtSingleAntenna, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetBtSingleAntenna}, + {OID_CUSTOM_SET_PTA, + DISP_STRING("OID_CUSTOM_SET_PTA"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, 4, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryPta, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetPta}, + */ + + { OID_CUSTOM_MTK_NVRAM_RW, + DISP_STRING("OID_CUSTOM_MTK_NVRAM_RW"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryNvramRead, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetNvramWrite }, + + { OID_CUSTOM_CFG_SRC_TYPE, + DISP_STRING("OID_CUSTOM_CFG_SRC_TYPE"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, sizeof(ENUM_CFG_SRC_TYPE_T), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryCfgSrcType, + NULL }, + + { OID_CUSTOM_EEPROM_TYPE, + DISP_STRING("OID_CUSTOM_EEPROM_TYPE"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, sizeof(ENUM_EEPROM_TYPE_T), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryEepromType, + NULL }, + +#if CFG_SUPPORT_WAPI + {OID_802_11_WAPI_MODE, + DISP_STRING("OID_802_11_WAPI_MODE"), + FALSE, TRUE, ENUM_OID_DRIVER_CORE, 4, + NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetWapiMode}, + {OID_802_11_WAPI_ASSOC_INFO, + DISP_STRING("OID_802_11_WAPI_ASSOC_INFO"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, + NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetWapiAssocInfo}, + {OID_802_11_SET_WAPI_KEY, + DISP_STRING("OID_802_11_SET_WAPI_KEY"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_WPI_KEY_T), + NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetWapiKey}, +#endif + +#if CFG_SUPPORT_WPS2 + {OID_802_11_WSC_ASSOC_INFO, + DISP_STRING("OID_802_11_WSC_ASSOC_INFO"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, + NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetWSCAssocInfo}, +#endif + +}; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Dispatching function for private ioctl region (SIOCIWFIRSTPRIV ~ +* SIOCIWLASTPRIV). +* +* \param[in] prNetDev Net device requested. +* \param[in] prIfReq Pointer to ifreq structure. +* \param[in] i4Cmd Command ID between SIOCIWFIRSTPRIV and SIOCIWLASTPRIV. +* +* \retval 0 for success. +* \retval -EOPNOTSUPP If cmd is not supported. +* \retval -EFAULT For fail. +* +*/ +/*----------------------------------------------------------------------------*/ +int +priv_support_ioctl ( + IN struct net_device *prNetDev, + IN OUT struct ifreq *prIfReq, + IN int i4Cmd + ) +{ + /* prIfReq is verified in the caller function wlanDoIOCTL() */ + struct iwreq *prIwReq = (struct iwreq *)prIfReq; + struct iw_request_info rIwReqInfo; + + /* prDev is verified in the caller function wlanDoIOCTL() */ + + /* Prepare the call */ + rIwReqInfo.cmd = (__u16)i4Cmd; + rIwReqInfo.flags = 0; + + switch (i4Cmd) { + case IOCTL_SET_INT: + /* NOTE(Kevin): 1/3 INT Type <= IFNAMSIZ, so we don't need copy_from/to_user() */ + return priv_set_int(prNetDev, &rIwReqInfo, &(prIwReq->u), (char *) &(prIwReq->u)); + + case IOCTL_GET_INT: + /* NOTE(Kevin): 1/3 INT Type <= IFNAMSIZ, so we don't need copy_from/to_user() */ + return priv_get_int(prNetDev, &rIwReqInfo, &(prIwReq->u), (char *) &(prIwReq->u)); + + case IOCTL_SET_STRUCT: + case IOCTL_SET_STRUCT_FOR_EM: + return priv_set_struct(prNetDev, &rIwReqInfo, &prIwReq->u, (char *) &(prIwReq->u)); + + case IOCTL_GET_STRUCT: + return priv_get_struct(prNetDev, &rIwReqInfo, &prIwReq->u, (char *) &(prIwReq->u)); + + default: + return -EOPNOTSUPP; + + } /* end of switch */ + +}/* priv_support_ioctl */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Private ioctl set int handler. +* +* \param[in] prNetDev Net device requested. +* \param[in] prIwReqInfo Pointer to iwreq structure. +* \param[in] prIwReqData The ioctl data structure, use the field of sub-command. +* \param[in] pcExtra The buffer with input value +* +* \retval 0 For success. +* \retval -EOPNOTSUPP If cmd is not supported. +* \retval -EINVAL If a value is out of range. +* +*/ +/*----------------------------------------------------------------------------*/ +int +priv_set_int ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, + IN char *pcExtra + ) +{ + UINT_32 u4SubCmd; + PUINT_32 pu4IntBuf; + P_NDIS_TRANSPORT_STRUCT prNdisReq; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4BufLen = 0; + int status = 0; + P_PTA_IPC_T prPtaIpc; + + ASSERT(prNetDev); + ASSERT(prIwReqInfo); + ASSERT(prIwReqData); + ASSERT(pcExtra); + + if (FALSE == GLUE_CHK_PR3(prNetDev, prIwReqData, pcExtra)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prNetDev); + + u4SubCmd = (UINT_32) prIwReqData->mode; + pu4IntBuf = (PUINT_32) pcExtra; + + switch (u4SubCmd) { + case PRIV_CMD_TEST_MODE: + //printk("TestMode=%ld\n", pu4IntBuf[1]); + prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; + + if (pu4IntBuf[1] == PRIV_CMD_TEST_MAGIC_KEY) { + prNdisReq->ndisOidCmd = OID_CUSTOM_TEST_MODE; + } + else if (pu4IntBuf[1] == 0) { + prNdisReq->ndisOidCmd = OID_CUSTOM_ABORT_TEST_MODE; + } + else { + status = 0; + break; + } + prNdisReq->inNdisOidlength = 0; + prNdisReq->outNdisOidLength = 0; + + /* Execute this OID */ + status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); + break; + + case PRIV_CMD_TEST_CMD: + //printk("CMD=0x%08lx, data=0x%08lx\n", pu4IntBuf[1], pu4IntBuf[2]); + prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; + + kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); + + prNdisReq->ndisOidCmd = OID_CUSTOM_MTK_WIFI_TEST; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + /* Execute this OID */ + status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); + break; + +#if CFG_SUPPORT_PRIV_MCR_RW + case PRIV_CMD_ACCESS_MCR: + //printk("addr=0x%08lx, data=0x%08lx\n", pu4IntBuf[1], pu4IntBuf[2]); + prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; + + if (!prGlueInfo->fgMcrAccessAllowed) { + if (pu4IntBuf[1] == PRIV_CMD_TEST_MAGIC_KEY && + pu4IntBuf[2] == PRIV_CMD_TEST_MAGIC_KEY) { + prGlueInfo->fgMcrAccessAllowed = TRUE; + } + status = 0; + break; + } + + kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); + + prNdisReq->ndisOidCmd = OID_CUSTOM_MCR_RW; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + /* Execute this OID */ + status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); + break; +#endif + + case PRIV_CMD_SW_CTRL: + //printk("addr=0x%08lx, data=0x%08lx\n", pu4IntBuf[1], pu4IntBuf[2]); + prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; + + kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); + + prNdisReq->ndisOidCmd = OID_CUSTOM_SW_CTRL; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + /* Execute this OID */ + status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); + break; + + + #if 0 + case PRIV_CMD_BEACON_PERIOD: + rStatus = wlanSetInformation(prGlueInfo->prAdapter, + wlanoidSetBeaconInterval, + (PVOID)&pu4IntBuf[1], /* pu4IntBuf[0] is used as input SubCmd */ + sizeof(UINT_32), + &u4BufLen); + break; + #endif + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + case PRIV_CMD_CSUM_OFFLOAD: + { + UINT_32 u4CSUMFlags; + + + if (pu4IntBuf[1] == 1) { + u4CSUMFlags = CSUM_OFFLOAD_EN_ALL; + } + else if (pu4IntBuf[1] == 0) { + u4CSUMFlags = 0; + } + else { + return -EINVAL; + } + + if (kalIoctl(prGlueInfo, + wlanoidSetCSUMOffload, + (PVOID)&u4CSUMFlags, + sizeof(UINT_32), + FALSE, + FALSE, + TRUE, + FALSE, + &u4BufLen + ) == WLAN_STATUS_SUCCESS) { + if (pu4IntBuf[1] == 1) { + prNetDev->features |= NETIF_F_HW_CSUM; + } else if (pu4IntBuf[1] == 0) { + prNetDev->features &= ~NETIF_F_HW_CSUM; + } + } + } + break; +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + + case PRIV_CMD_POWER_MODE: + kalIoctl(prGlueInfo, + wlanoidSet802dot11PowerSaveProfile, + (PVOID)&pu4IntBuf[1], /* pu4IntBuf[0] is used as input SubCmd */ + sizeof(UINT_32), + FALSE, + FALSE, + TRUE, + FALSE, + &u4BufLen); + break; + + case PRIV_CMD_WMM_PS: + { + PARAM_CUSTOM_WMM_PS_TEST_STRUC_T rWmmPsTest; + + rWmmPsTest.bmfgApsdEnAc = (UINT_8)pu4IntBuf[1]; + rWmmPsTest.ucIsEnterPsAtOnce = (UINT_8)pu4IntBuf[2]; + rWmmPsTest.ucIsDisableUcTrigger = (UINT_8)pu4IntBuf[3]; + rWmmPsTest.reserved = 0; + + kalIoctl(prGlueInfo, + wlanoidSetWiFiWmmPsTest, + (PVOID)&rWmmPsTest, + sizeof(PARAM_CUSTOM_WMM_PS_TEST_STRUC_T), + FALSE, + FALSE, + TRUE, + FALSE, + &u4BufLen); + } + break; + + #if 0 + case PRIV_CMD_ADHOC_MODE: + rStatus = wlanSetInformation(prGlueInfo->prAdapter, + wlanoidSetAdHocMode, + (PVOID)&pu4IntBuf[1], /* pu4IntBuf[0] is used as input SubCmd */ + sizeof(UINT_32), + &u4BufLen); + break; + #endif + + case PRIV_CUSTOM_BWCS_CMD: + + DBGLOG(REQ, INFO, ("pu4IntBuf[1] = %x, size of PTA_IPC_T = %d.\n", pu4IntBuf[1], sizeof(PARAM_PTA_IPC_T))); + + prPtaIpc = (P_PTA_IPC_T) aucOidBuf; + prPtaIpc->u.aucBTPParams[0] = (UINT_8) (pu4IntBuf[1] >> 24); + prPtaIpc->u.aucBTPParams[1] = (UINT_8) (pu4IntBuf[1] >> 16); + prPtaIpc->u.aucBTPParams[2] = (UINT_8) (pu4IntBuf[1] >> 8); + prPtaIpc->u.aucBTPParams[3] = (UINT_8) (pu4IntBuf[1]); + + DBGLOG(REQ, INFO, ("BCM BWCS CMD : PRIV_CUSTOM_BWCS_CMD : aucBTPParams[0] = %02x, aucBTPParams[1] = %02x, aucBTPParams[2] = %02x, aucBTPParams[3] = %02x.\n", + prPtaIpc->u.aucBTPParams[0], + prPtaIpc->u.aucBTPParams[1], + prPtaIpc->u.aucBTPParams[2], + prPtaIpc->u.aucBTPParams[3])); + +#if 0 + status = wlanSetInformation(prGlueInfo->prAdapter, + wlanoidSetBT, + (PVOID)&aucOidBuf[0], + u4CmdLen, + &u4BufLen); +#endif + + status = wlanoidSetBT(prGlueInfo->prAdapter, + (PVOID)&aucOidBuf[0], + sizeof(PARAM_PTA_IPC_T), + &u4BufLen); + + if (WLAN_STATUS_SUCCESS != status) { + status = -EFAULT; + } + + break; + + default: + return -EOPNOTSUPP; + } + + return status; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Private ioctl get int handler. +* +* \param[in] pDev Net device requested. +* \param[out] pIwReq Pointer to iwreq structure. +* \param[in] prIwReqData The ioctl req structure, use the field of sub-command. +* \param[out] pcExtra The buffer with put the return value +* +* \retval 0 For success. +* \retval -EOPNOTSUPP If cmd is not supported. +* \retval -EFAULT For fail. +* +*/ +/*----------------------------------------------------------------------------*/ +int +priv_get_int ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, + IN OUT char *pcExtra + ) +{ + UINT_32 u4SubCmd; + PUINT_32 pu4IntBuf; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4BufLen = 0; + int status = 0; + P_NDIS_TRANSPORT_STRUCT prNdisReq; + INT_32 ch[50]; + + ASSERT(prNetDev); + ASSERT(prIwReqInfo); + ASSERT(prIwReqData); + ASSERT(pcExtra); + if (FALSE == GLUE_CHK_PR3(prNetDev, prIwReqData, pcExtra)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prNetDev); + + u4SubCmd = (UINT_32) prIwReqData->mode; + pu4IntBuf = (PUINT_32) pcExtra; + + switch (u4SubCmd) { + case PRIV_CMD_TEST_CMD: + //printk("CMD=0x%08lx, data=0x%08lx\n", pu4IntBuf[1], pu4IntBuf[2]); + prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; + + kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); + + prNdisReq->ndisOidCmd = OID_CUSTOM_MTK_WIFI_TEST; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + status = priv_get_ndis(prNetDev, prNdisReq, &u4BufLen); + if (status == 0) { + //printk("Result=%ld\n", *(PUINT_32)&prNdisReq->ndisOidContent[4]); + prIwReqData->mode = *(PUINT_32)&prNdisReq->ndisOidContent[4]; + /* + if (copy_to_user(prIwReqData->data.pointer, + &prNdisReq->ndisOidContent[4], 4)) { + printk(KERN_NOTICE "priv_get_int() copy_to_user oidBuf fail(3)\n"); + return -EFAULT; + } + */ + } + return status; + +#if CFG_SUPPORT_PRIV_MCR_RW + case PRIV_CMD_ACCESS_MCR: + //printk("addr=0x%08lx\n", pu4IntBuf[1]); + prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; + + if (!prGlueInfo->fgMcrAccessAllowed) { + status = 0; + break; + } + + kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); + + prNdisReq->ndisOidCmd = OID_CUSTOM_MCR_RW; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + status = priv_get_ndis(prNetDev, prNdisReq, &u4BufLen); + if (status == 0) { + //printk("Result=%ld\n", *(PUINT_32)&prNdisReq->ndisOidContent[4]); + prIwReqData->mode = *(PUINT_32)&prNdisReq->ndisOidContent[4]; + } + return status; +#endif + + case PRIV_CMD_SW_CTRL: + //printk(" addr=0x%08lx\n", pu4IntBuf[1]); + + prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; + + kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); + + prNdisReq->ndisOidCmd = OID_CUSTOM_SW_CTRL; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + status = priv_get_ndis(prNetDev, prNdisReq, &u4BufLen); + if (status == 0) { + //printk("Result=%ld\n", *(PUINT_32)&prNdisReq->ndisOidContent[4]); + prIwReqData->mode = *(PUINT_32)&prNdisReq->ndisOidContent[4]; + } + return status; + + #if 0 + case PRIV_CMD_BEACON_PERIOD: + rStatus = wlanQueryInformation(prGlueInfo->prAdapter, + wlanoidQueryBeaconInterval, + (PVOID)pu4IntBuf, + sizeof(UINT_32), + &u4BufLen); + break; + + case PRIV_CMD_POWER_MODE: + rStatus = wlanQueryInformation(prGlueInfo->prAdapter, + wlanoidQuery802dot11PowerSaveProfile, + (PVOID)pu4IntBuf, + sizeof(UINT_32), + &u4BufLen); + break; + + case PRIV_CMD_ADHOC_MODE: + rStatus = wlanQueryInformation(prGlueInfo->prAdapter, + wlanoidQueryAdHocMode, + (PVOID)pu4IntBuf, + sizeof(UINT_32), + &u4BufLen); + break; + #endif + + default: + break; + } + + u4SubCmd = (UINT_32) prIwReqData->data.flags; + + switch (u4SubCmd) { + case PRIV_CMD_GET_CH_LIST: + { + UINT_16 i, j = 0; + UINT_8 NumOfChannel = 50; + UINT_8 ucMaxChannelNum = 50; + RF_CHANNEL_INFO_T aucChannelList[50]; + + kalGetChannelList(prGlueInfo, BAND_NULL, ucMaxChannelNum, &NumOfChannel, aucChannelList); + if (NumOfChannel > 50) + NumOfChannel = 50; + + if (kalIsAPmode(prGlueInfo)) { + for (i = 0; i < NumOfChannel; i++) { + if ((aucChannelList[i].ucChannelNum <= 13) || + (aucChannelList[i].ucChannelNum == 36 || aucChannelList[i].ucChannelNum == 40 || + aucChannelList[i].ucChannelNum == 44 || aucChannelList[i].ucChannelNum == 48)) { + ch[j] = (INT_32)aucChannelList[i].ucChannelNum; + j++; + } + } + } + else { + for (j = 0; j < NumOfChannel; j++) { + ch[j] = (INT_32)aucChannelList[j].ucChannelNum; + } + } + + prIwReqData->data.length = j; + if (copy_to_user(prIwReqData->data.pointer, ch, NumOfChannel*sizeof(INT_32))) { + return -EFAULT; + } + else + return status; + } + default: + return -EOPNOTSUPP; + } + + return status; +} /* priv_get_int */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Private ioctl set int array handler. +* +* \param[in] prNetDev Net device requested. +* \param[in] prIwReqInfo Pointer to iwreq structure. +* \param[in] prIwReqData The ioctl data structure, use the field of sub-command. +* \param[in] pcExtra The buffer with input value +* +* \retval 0 For success. +* \retval -EOPNOTSUPP If cmd is not supported. +* \retval -EINVAL If a value is out of range. +* +*/ +/*----------------------------------------------------------------------------*/ +int +priv_set_ints ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, + IN char *pcExtra + ) +{ + UINT_32 u4SubCmd, u4BufLen; + P_GLUE_INFO_T prGlueInfo; + int status = 0; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_SET_TXPWR_CTRL_T prTxpwr; + + ASSERT(prNetDev); + ASSERT(prIwReqInfo); + ASSERT(prIwReqData); + ASSERT(pcExtra); + + if (FALSE == GLUE_CHK_PR3(prNetDev, prIwReqData, pcExtra)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prNetDev); + + u4SubCmd = (UINT_32) prIwReqData->data.flags; + + switch (u4SubCmd) { + case PRIV_CMD_SET_TX_POWER: + { + INT_32 *setting = prIwReqData->data.pointer; + UINT_16 i; + +#if 0 + printk("Tx power num = %d\n", prIwReqData->data.length); + + printk("Tx power setting = %d %d %d %d\n", + setting[0], setting[1], setting[2], setting[3]); +#endif + prTxpwr = &prGlueInfo->rTxPwr; + if (setting[0] == 0 && prIwReqData->data.length == 4 /* argc num */) { + /* 0 (All networks), 1 (legacy STA), 2 (Hotspot AP), 3 (P2P), 4 (BT over Wi-Fi) */ + if (setting[1] == 1 || setting[1] == 0) { + if (setting[2] == 0 || setting[2] == 1) + prTxpwr->c2GLegacyStaPwrOffset = setting[3]; + if (setting[2] == 0 || setting[2] == 2) + prTxpwr->c5GLegacyStaPwrOffset = setting[3]; + } + if (setting[1] == 2 || setting[1] == 0) { + if (setting[2] == 0 || setting[2] == 1) + prTxpwr->c2GHotspotPwrOffset = setting[3]; + if (setting[2] == 0 || setting[2] == 2) + prTxpwr->c5GHotspotPwrOffset = setting[3]; + } + if (setting[1] == 3 || setting[1] == 0) { + if (setting[2] == 0 || setting[2] == 1) + prTxpwr->c2GP2pPwrOffset = setting[3]; + if (setting[2] == 0 || setting[2] == 2) + prTxpwr->c5GP2pPwrOffset = setting[3]; + } + if (setting[1] == 4 || setting[1] == 0) { + if (setting[2] == 0 || setting[2] == 1) + prTxpwr->c2GBowPwrOffset = setting[3]; + if (setting[2] == 0 || setting[2] == 2) + prTxpwr->c5GBowPwrOffset = setting[3]; + } + } + else if (setting[0] == 1 && prIwReqData->data.length == 2) { + prTxpwr->ucConcurrencePolicy = setting[1]; + } + else if (setting[0] == 2 && prIwReqData->data.length == 3) { + if (setting[1] == 0) { + for (i=0; i<14; i++) + prTxpwr->acTxPwrLimit2G[i] = setting[2]; + } + else if (setting[1] <= 14) + prTxpwr->acTxPwrLimit2G[setting[1] - 1] = setting[2]; + } + else if (setting[0] == 3 && prIwReqData->data.length == 3) { + if (setting[1] == 0) { + for (i=0; i<4; i++) + prTxpwr->acTxPwrLimit5G[i] = setting[2]; + } + else if (setting[1] <= 4) + prTxpwr->acTxPwrLimit5G[setting[1] - 1] = setting[2]; + } + else if (setting[0] == 4 && prIwReqData->data.length == 2) { + if (setting[1] == 0) { + wlanDefTxPowerCfg(prGlueInfo->prAdapter); + } + rStatus = kalIoctl(prGlueInfo, + wlanoidSetTxPower, + prTxpwr, + sizeof(SET_TXPWR_CTRL_T), + TRUE, + FALSE, + FALSE, + FALSE, + &u4BufLen); + } + else + return -EFAULT; + } + return status; + default: + break; + } + + return status; +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Private ioctl get int array handler. +* +* \param[in] pDev Net device requested. +* \param[out] pIwReq Pointer to iwreq structure. +* \param[in] prIwReqData The ioctl req structure, use the field of sub-command. +* \param[out] pcExtra The buffer with put the return value +* +* \retval 0 For success. +* \retval -EOPNOTSUPP If cmd is not supported. +* \retval -EFAULT For fail. +* +*/ +/*----------------------------------------------------------------------------*/ +int +priv_get_ints ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, + IN OUT char *pcExtra + ) +{ + UINT_32 u4SubCmd; + P_GLUE_INFO_T prGlueInfo; + int status = 0; + INT_32 ch[50]; + + ASSERT(prNetDev); + ASSERT(prIwReqInfo); + ASSERT(prIwReqData); + ASSERT(pcExtra); + if (FALSE == GLUE_CHK_PR3(prNetDev, prIwReqData, pcExtra)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prNetDev); + + u4SubCmd = (UINT_32) prIwReqData->data.flags; + + switch (u4SubCmd) { + case PRIV_CMD_GET_CH_LIST: + { + UINT_16 i; + UINT_8 NumOfChannel = 50; + UINT_8 ucMaxChannelNum = 50; + RF_CHANNEL_INFO_T aucChannelList[50]; + + kalGetChannelList(prGlueInfo, BAND_NULL, ucMaxChannelNum, &NumOfChannel, aucChannelList); + if (NumOfChannel > 50) + NumOfChannel = 50; + + for (i = 0; i < NumOfChannel; i++) { + ch[i] = (INT_32)aucChannelList[i].ucChannelNum; + } + + prIwReqData->data.length = NumOfChannel; + if (copy_to_user(prIwReqData->data.pointer, ch, NumOfChannel*sizeof(INT_32))) { + return -EFAULT; + } + else + return status; + } + default: + break; + } + + return status; +} /* priv_get_int */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Private ioctl set structure handler. +* +* \param[in] pDev Net device requested. +* \param[in] prIwReqData Pointer to iwreq_data structure. +* +* \retval 0 For success. +* \retval -EOPNOTSUPP If cmd is not supported. +* \retval -EINVAL If a value is out of range. +* +*/ +/*----------------------------------------------------------------------------*/ +int +priv_set_struct ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, + IN char *pcExtra + ) +{ + UINT_32 u4SubCmd = 0; + int status = 0; + //WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4CmdLen = 0; + P_NDIS_TRANSPORT_STRUCT prNdisReq; + PUINT_32 pu4IntBuf = NULL; + + P_GLUE_INFO_T prGlueInfo = NULL; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + //ASSERT(prIwReqInfo); + ASSERT(prIwReqData); + //ASSERT(pcExtra); + + kalMemZero(&aucOidBuf[0], sizeof(aucOidBuf)); + + if (FALSE == GLUE_CHK_PR2(prNetDev, prIwReqData)) { + return -EINVAL; + } + prGlueInfo = (P_GLUE_INFO_T)netdev_priv(prNetDev); + + u4SubCmd = (UINT_32) prIwReqData->data.flags; + +#if 0 + printk(KERN_INFO DRV_NAME"priv_set_struct(): prIwReqInfo->cmd(0x%X), u4SubCmd(%ld)\n", + prIwReqInfo->cmd, + u4SubCmd + ); +#endif + + switch (u4SubCmd) { +#if 0 //PTA_ENABLED + case PRIV_CMD_BT_COEXIST: + u4CmdLen = prIwReqData->data.length * sizeof(UINT_32); + ASSERT(sizeof(PARAM_CUSTOM_BT_COEXIST_T) >= u4CmdLen); + if (sizeof(PARAM_CUSTOM_BT_COEXIST_T) < u4CmdLen) { + return -EFAULT; + } + + if (copy_from_user(&aucOidBuf[0], prIwReqData->data.pointer, u4CmdLen)) { + status = -EFAULT; //return -EFAULT; + break; + } + + rStatus = wlanSetInformation(prGlueInfo->prAdapter, + wlanoidSetBtCoexistCtrl, + (PVOID)&aucOidBuf[0], + u4CmdLen, + &u4BufLen); + if (WLAN_STATUS_SUCCESS != rStatus) { + status = -EFAULT; + } + break; +#endif + + case PRIV_CUSTOM_BWCS_CMD: + u4CmdLen = prIwReqData->data.length * sizeof(UINT_32); + ASSERT(sizeof(PARAM_PTA_IPC_T) >= u4CmdLen); + if (sizeof(PARAM_PTA_IPC_T) < u4CmdLen) { + return -EFAULT; + } +#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS && CFG_SUPPORT_BCM_BWCS_DEBUG + DBGLOG(REQ, INFO, ("ucCmdLen = %d, size of PTA_IPC_T = %d, prIwReqData->data = 0x%x.\n", u4CmdLen, sizeof(PARAM_PTA_IPC_T), prIwReqData->data)); + + DBGLOG(REQ, INFO, ("priv_set_struct(): prIwReqInfo->cmd(0x%X), u4SubCmd(%ld)\n", + prIwReqInfo->cmd, + u4SubCmd + )); + + DBGLOG(REQ, INFO, ("*pcExtra = 0x%x\n", *pcExtra)); + #endif + + if (copy_from_user(&aucOidBuf[0], prIwReqData->data.pointer, u4CmdLen)) { + status = -EFAULT; //return -EFAULT; + break; + } +#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS && CFG_SUPPORT_BCM_BWCS_DEBUG + DBGLOG(REQ, INFO, ("priv_set_struct(): BWCS CMD = %02x%02x%02x%02x\n", + aucOidBuf[2], aucOidBuf[3], aucOidBuf[4], aucOidBuf[5])); +#endif + +#if 0 + status = wlanSetInformation(prGlueInfo->prAdapter, + wlanoidSetBT, + (PVOID)&aucOidBuf[0], + u4CmdLen, + &u4BufLen); +#endif + +#if 1 + status = wlanoidSetBT(prGlueInfo->prAdapter, + (PVOID)&aucOidBuf[0], + u4CmdLen, + &u4BufLen); +#endif + + if (WLAN_STATUS_SUCCESS != status) { + status = -EFAULT; + } + + break; + +#if CFG_SUPPORT_WPS2 + case PRIV_CMD_WSC_PROBE_REQ: + { + /* retrieve IE for Probe Request */ + if (prIwReqData->data.length > 0) { + if (copy_from_user(prGlueInfo->aucWSCIE, prIwReqData->data.pointer, + prIwReqData->data.length)) { + status = -EFAULT; + break; + } + prGlueInfo->u2WSCIELen = prIwReqData->data.length; + } + else { + prGlueInfo->u2WSCIELen = 0; + } + } + break; +#endif +#if CFG_SUPPORT_WAPI + case PRIV_SEC_MSG_OID: + { + int msg_in_len =0; + int msg_out_len = 0; + unsigned char msg_out[1000]; + + DBGLOG(WAPI, TRACE, ("Set msg private ioctl!!!\n")); + + if (copy_from_user(&aucOidBuf[0], + prIwReqData->data.pointer, + prIwReqData->data.length)) { //+2 + status = -EFAULT; + break; + } + msg_in_len = prIwReqData->data.length; + + if(aucOidBuf[0] == 0x01) { + + handle_sec_msg_1(aucOidBuf, msg_in_len, msg_out , &msg_out_len); + + prIwReqData->data.length = msg_out_len; + if (copy_to_user(prIwReqData->data.pointer, + &(prIwReqData->data.length), + sizeof(__u16))) { + DBGLOG(REQ, INFO, ("copy_to_user oidBuf fail\n")); + status = -EFAULT; + break; + } + + if (copy_to_user((char *)prIwReqData->data.pointer + sizeof(__u16), + &msg_out[0], + prIwReqData->data.length)) { + DBGLOG(REQ, INFO, ("copy_to_user oidBuf fail\n")); + status = -EFAULT; + break; + } + + } + else if(aucOidBuf[0] == 0x02){ + + handle_sec_msg_2(aucOidBuf, msg_in_len, msg_out , &msg_out_len); + + prIwReqData->data.length = 0; + if (copy_to_user(prIwReqData->data.pointer, + &(prIwReqData->data.length), + sizeof(__u16))) { + DBGLOG(REQ, INFO, ("copy_to_user oidBuf fail\n")); + status = -EFAULT; + break; + } + } + else if(aucOidBuf[0] == 0x03){ + + handle_sec_msg_3(aucOidBuf, msg_in_len, msg_out , &msg_out_len); + + prIwReqData->data.length = 0; + if (copy_to_user(prIwReqData->data.pointer, + &(prIwReqData->data.length), + sizeof(__u16))) { + DBGLOG(REQ, INFO, ("copy_to_user oidBuf fail\n")); + status = -EFAULT; + break; + } + } + else if(aucOidBuf[0] == 0x04){ + + handle_sec_msg_4(aucOidBuf, msg_in_len, msg_out , &msg_out_len); + + prIwReqData->data.length = 0; + if (copy_to_user(prIwReqData->data.pointer, + &(prIwReqData->data.length), + sizeof(__u16))) { + DBGLOG(REQ, INFO, ("copy_to_user oidBuf fail\n")); + status = -EFAULT; + break; + } + } + else if(aucOidBuf[0] == 0x05){ + + handle_sec_msg_5(aucOidBuf, msg_in_len, msg_out , &msg_out_len); + + prIwReqData->data.length = 0; + if (copy_to_user(prIwReqData->data.pointer, + &(prIwReqData->data.length), + sizeof(__u16))) { + DBGLOG(REQ, INFO, ("copy_to_user oidBuf fail\n")); + status = -EFAULT; + break; + } + } + + } + break; +#endif + case PRIV_CMD_OID: + if (copy_from_user(&aucOidBuf[0], + prIwReqData->data.pointer, + prIwReqData->data.length)) { + status = -EFAULT; + break; + } + if (!kalMemCmp(&aucOidBuf[0], pcExtra, prIwReqData->data.length)) { + DBGLOG(REQ, INFO, ("pcExtra buffer is valid\n")); + } + else + DBGLOG(REQ, INFO, ("pcExtra 0x%p\n", pcExtra)); + + /* Execute this OID */ + status = priv_set_ndis(prNetDev, (P_NDIS_TRANSPORT_STRUCT)&aucOidBuf[0], &u4BufLen); + /* Copy result to user space */ + ((P_NDIS_TRANSPORT_STRUCT)&aucOidBuf[0])->outNdisOidLength = u4BufLen; + + if (copy_to_user(prIwReqData->data.pointer, + &aucOidBuf[0], + OFFSET_OF(NDIS_TRANSPORT_STRUCT, ndisOidContent))) { + DBGLOG(REQ, INFO, ("copy_to_user oidBuf fail\n")); + status = -EFAULT; + } + + break; + + case PRIV_CMD_SW_CTRL: + pu4IntBuf = (PUINT_32)prIwReqData->data.pointer; + prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; + + //kalMemCopy(&prNdisReq->ndisOidContent[0], prIwReqData->data.pointer, 8); + if (copy_from_user(&prNdisReq->ndisOidContent[0], + prIwReqData->data.pointer, + prIwReqData->data.length)) { + status = -EFAULT; + break; + } + prNdisReq->ndisOidCmd = OID_CUSTOM_SW_CTRL; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + /* Execute this OID */ + status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); + break; + + default: + return -EOPNOTSUPP; + } + + return status; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Private ioctl get struct handler. +* +* \param[in] pDev Net device requested. +* \param[out] pIwReq Pointer to iwreq structure. +* \param[in] cmd Private sub-command. +* +* \retval 0 For success. +* \retval -EFAULT If copy from user space buffer fail. +* \retval -EOPNOTSUPP Parameter "cmd" not recognized. +* +*/ +/*----------------------------------------------------------------------------*/ +int +priv_get_struct ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, + IN OUT char *pcExtra + ) +{ + UINT_32 u4SubCmd = 0; + P_NDIS_TRANSPORT_STRUCT prNdisReq= NULL; + + P_GLUE_INFO_T prGlueInfo = NULL; + UINT_32 u4BufLen = 0; + PUINT_32 pu4IntBuf = NULL; + int status = 0; + + kalMemZero(&aucOidBuf[0], sizeof(aucOidBuf)); + + ASSERT(prNetDev); + ASSERT(prIwReqData); + if (!prNetDev || !prIwReqData) { + DBGLOG(REQ, INFO, ("priv_get_struct(): invalid param(0x%p, 0x%p)\n", + prNetDev, prIwReqData)); + return -EINVAL; + } + + u4SubCmd = (UINT_32) prIwReqData->data.flags; + prGlueInfo = (P_GLUE_INFO_T)netdev_priv(prNetDev); + ASSERT(prGlueInfo); + if (!prGlueInfo) { + DBGLOG(REQ, INFO, ("priv_get_struct(): invalid prGlueInfo(0x%p, 0x%p)\n", + prNetDev, netdev_priv(prNetDev))); + return -EINVAL; + } + +#if 0 + printk(KERN_INFO DRV_NAME"priv_get_struct(): prIwReqInfo->cmd(0x%X), u4SubCmd(%ld)\n", + prIwReqInfo->cmd, + u4SubCmd + ); +#endif + memset(aucOidBuf, 0, sizeof(aucOidBuf)); + + switch (u4SubCmd) { + case PRIV_CMD_OID: + if (copy_from_user(&aucOidBuf[0], + prIwReqData->data.pointer, + sizeof(NDIS_TRANSPORT_STRUCT))) { + DBGLOG(REQ, INFO, ("priv_get_struct() copy_from_user oidBuf fail\n")); + return -EFAULT; + } + + prNdisReq = (P_NDIS_TRANSPORT_STRUCT)&aucOidBuf[0]; +#if 0 + printk(KERN_NOTICE "\n priv_get_struct cmd 0x%02x len:%d OID:0x%08x OID Len:%d\n", + cmd, + pIwReq->u.data.length, + ndisReq->ndisOidCmd, + ndisReq->inNdisOidlength); +#endif + if (priv_get_ndis(prNetDev, prNdisReq, &u4BufLen) == 0) { + prNdisReq->outNdisOidLength = u4BufLen; + if (copy_to_user(prIwReqData->data.pointer, + &aucOidBuf[0], + u4BufLen + sizeof(NDIS_TRANSPORT_STRUCT) - sizeof(prNdisReq->ndisOidContent))) { + DBGLOG(REQ, INFO, ("priv_get_struct() copy_to_user oidBuf fail(1)\n")); + return -EFAULT; + } + return 0; + } + else { + prNdisReq->outNdisOidLength = u4BufLen; + if (copy_to_user(prIwReqData->data.pointer, + &aucOidBuf[0], + OFFSET_OF(NDIS_TRANSPORT_STRUCT, ndisOidContent))) { + DBGLOG(REQ, INFO, ("priv_get_struct() copy_to_user oidBuf fail(2)\n")); + } + return -EFAULT; + } + break; + + case PRIV_CMD_SW_CTRL: + pu4IntBuf = (PUINT_32)prIwReqData->data.pointer; + prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; + + if (copy_from_user(&prNdisReq->ndisOidContent[0], + prIwReqData->data.pointer, + prIwReqData->data.length)) { + DBGLOG(REQ, INFO, ("priv_get_struct() copy_from_user oidBuf fail\n")); + return -EFAULT; + } + + prNdisReq->ndisOidCmd = OID_CUSTOM_SW_CTRL; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + status = priv_get_ndis(prNetDev, prNdisReq, &u4BufLen); + if (status == 0) { + prNdisReq->outNdisOidLength = u4BufLen; + //printk("len=%d Result=%08lx\n", u4BufLen, *(PUINT_32)&prNdisReq->ndisOidContent[4]); + + if (copy_to_user(prIwReqData->data.pointer, + &prNdisReq->ndisOidContent[4], + 4 /* OFFSET_OF(NDIS_TRANSPORT_STRUCT, ndisOidContent)*/)) { + DBGLOG(REQ, INFO, ("priv_get_struct() copy_to_user oidBuf fail(2)\n")); + } + } + return 0; + break; + + default: + DBGLOG(REQ, WARN, ("get struct cmd:0x%lx\n", u4SubCmd)); + return -EOPNOTSUPP; + } +} /* priv_get_struct */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief The routine handles a set operation for a single OID. +* +* \param[in] pDev Net device requested. +* \param[in] ndisReq Ndis request OID information copy from user. +* \param[out] outputLen_p If the call is successful, returns the number of +* bytes written into the query buffer. If the +* call failed due to invalid length of the query +* buffer, returns the amount of storage needed.. +* +* \retval 0 On success. +* \retval -EOPNOTSUPP If cmd is not supported. +* +*/ +/*----------------------------------------------------------------------------*/ +static int +priv_set_ndis ( + IN struct net_device *prNetDev, + IN NDIS_TRANSPORT_STRUCT* prNdisReq, + OUT PUINT_32 pu4OutputLen + ) +{ + P_WLAN_REQ_ENTRY prWlanReqEntry = NULL; + WLAN_STATUS status = WLAN_STATUS_SUCCESS; + P_GLUE_INFO_T prGlueInfo = NULL; + UINT_32 u4SetInfoLen = 0; + + ASSERT(prNetDev); + ASSERT(prNdisReq); + ASSERT(pu4OutputLen); + + if (!prNetDev || !prNdisReq || !pu4OutputLen) { + DBGLOG(REQ, INFO, ("priv_set_ndis(): invalid param(0x%p, 0x%p, 0x%p)\n", + prNetDev, prNdisReq, pu4OutputLen)); + return -EINVAL; + } + + prGlueInfo = (P_GLUE_INFO_T)netdev_priv(prNetDev); + ASSERT(prGlueInfo); + if (!prGlueInfo) { + DBGLOG(REQ, INFO, ("priv_set_ndis(): invalid prGlueInfo(0x%p, 0x%p)\n", + prNetDev, netdev_priv(prNetDev))); + return -EINVAL; + } + +#if 0 + printk(KERN_INFO DRV_NAME"priv_set_ndis(): prNdisReq->ndisOidCmd(0x%lX)\n", + prNdisReq->ndisOidCmd + ); +#endif + + if (FALSE == reqSearchSupportedOidEntry(prNdisReq->ndisOidCmd, + &prWlanReqEntry)) { + //WARNLOG(("Set OID: 0x%08lx (unknown)\n", prNdisReq->ndisOidCmd)); + return -EOPNOTSUPP; + } + + if (NULL == prWlanReqEntry->pfOidSetHandler) { + //WARNLOG(("Set %s: Null set handler\n", prWlanReqEntry->pucOidName)); + return -EOPNOTSUPP; + } + +#if 0 + printk(KERN_INFO DRV_NAME"priv_set_ndis(): %s\n", + prWlanReqEntry->pucOidName + ); +#endif + + if (prWlanReqEntry->fgSetBufLenChecking) { + if (prNdisReq->inNdisOidlength != prWlanReqEntry->u4InfoBufLen) { + DBGLOG(REQ, WARN, ("Set %s: Invalid length (current=%ld, needed=%ld)\n", + prWlanReqEntry->pucOidName, + prNdisReq->inNdisOidlength, + prWlanReqEntry->u4InfoBufLen)); + + *pu4OutputLen = prWlanReqEntry->u4InfoBufLen; + return -EINVAL; + } + } + + if (prWlanReqEntry->eOidMethod == ENUM_OID_GLUE_ONLY) { + /* GLUE sw info only */ + status = prWlanReqEntry->pfOidSetHandler(prGlueInfo, + prNdisReq->ndisOidContent, + prNdisReq->inNdisOidlength, + &u4SetInfoLen); + } + else if (prWlanReqEntry->eOidMethod == ENUM_OID_GLUE_EXTENSION) { + /* multiple sw operations */ + status = prWlanReqEntry->pfOidSetHandler(prGlueInfo, + prNdisReq->ndisOidContent, + prNdisReq->inNdisOidlength, + &u4SetInfoLen); + } + else if (prWlanReqEntry->eOidMethod == ENUM_OID_DRIVER_CORE) { + /* driver core*/ + + status = kalIoctl(prGlueInfo, + (PFN_OID_HANDLER_FUNC)prWlanReqEntry->pfOidSetHandler, + prNdisReq->ndisOidContent, + prNdisReq->inNdisOidlength, + FALSE, + FALSE, + TRUE, + FALSE, + &u4SetInfoLen); + } + else { + DBGLOG(REQ, INFO, ("priv_set_ndis(): unsupported OID method:0x%x\n", + prWlanReqEntry->eOidMethod)); + return -EOPNOTSUPP; + } + + *pu4OutputLen = u4SetInfoLen; + + switch (status) { + case WLAN_STATUS_SUCCESS: + break; + + case WLAN_STATUS_INVALID_LENGTH: + //WARNLOG(("Set %s: Invalid length (current=%ld, needed=%ld)\n", + // prWlanReqEntry->pucOidName, + //prNdisReq->inNdisOidlength, + //u4SetInfoLen)); + break; + } + + if (WLAN_STATUS_SUCCESS != status) { + return -EFAULT; + } + + return 0; +} /* priv_set_ndis */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief The routine handles a query operation for a single OID. Basically we +* return information about the current state of the OID in question. +* +* \param[in] pDev Net device requested. +* \param[in] ndisReq Ndis request OID information copy from user. +* \param[out] outputLen_p If the call is successful, returns the number of +* bytes written into the query buffer. If the +* call failed due to invalid length of the query +* buffer, returns the amount of storage needed.. +* +* \retval 0 On success. +* \retval -EOPNOTSUPP If cmd is not supported. +* \retval -EINVAL invalid input parameters +* +*/ +/*----------------------------------------------------------------------------*/ +static int +priv_get_ndis ( + IN struct net_device *prNetDev, + IN NDIS_TRANSPORT_STRUCT* prNdisReq, + OUT PUINT_32 pu4OutputLen + ) +{ + P_WLAN_REQ_ENTRY prWlanReqEntry = NULL; + UINT_32 u4BufLen = 0; + WLAN_STATUS status = WLAN_STATUS_SUCCESS; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prNetDev); + ASSERT(prNdisReq); + ASSERT(pu4OutputLen); + + if (!prNetDev || !prNdisReq || !pu4OutputLen) { + DBGLOG(REQ, INFO, ("priv_get_ndis(): invalid param(0x%p, 0x%p, 0x%p)\n", + prNetDev, prNdisReq, pu4OutputLen)); + return -EINVAL; + } + + prGlueInfo = (P_GLUE_INFO_T)netdev_priv(prNetDev); + ASSERT(prGlueInfo); + if (!prGlueInfo) { + DBGLOG(REQ, INFO, ("priv_get_ndis(): invalid prGlueInfo(0x%p, 0x%p)\n", + prNetDev, netdev_priv(prNetDev))); + return -EINVAL; + } + +#if 0 + printk(KERN_INFO DRV_NAME"priv_get_ndis(): prNdisReq->ndisOidCmd(0x%lX)\n", + prNdisReq->ndisOidCmd + ); +#endif + + if (FALSE == reqSearchSupportedOidEntry(prNdisReq->ndisOidCmd, + &prWlanReqEntry)) { + //WARNLOG(("Query OID: 0x%08lx (unknown)\n", prNdisReq->ndisOidCmd)); + return -EOPNOTSUPP; + } + + + if (NULL == prWlanReqEntry->pfOidQueryHandler) { + //WARNLOG(("Query %s: Null query handler\n", prWlanReqEntry->pucOidName)); + return -EOPNOTSUPP; + } + +#if 0 + printk(KERN_INFO DRV_NAME"priv_get_ndis(): %s\n", + prWlanReqEntry->pucOidName + ); +#endif + + if (prWlanReqEntry->fgQryBufLenChecking) { + if (prNdisReq->inNdisOidlength < prWlanReqEntry->u4InfoBufLen) { + /* Not enough room in InformationBuffer. Punt */ + //WARNLOG(("Query %s: Buffer too short (current=%ld, needed=%ld)\n", + //prWlanReqEntry->pucOidName, + //prNdisReq->inNdisOidlength, + //prWlanReqEntry->u4InfoBufLen)); + + *pu4OutputLen = prWlanReqEntry->u4InfoBufLen; + + status = WLAN_STATUS_INVALID_LENGTH; + return -EINVAL; + } + } + + + if (prWlanReqEntry->eOidMethod == ENUM_OID_GLUE_ONLY) { + /* GLUE sw info only */ + status = prWlanReqEntry->pfOidQueryHandler(prGlueInfo, + prNdisReq->ndisOidContent, + prNdisReq->inNdisOidlength, + &u4BufLen); + } + else if (prWlanReqEntry->eOidMethod == ENUM_OID_GLUE_EXTENSION) { + /* multiple sw operations */ + status = prWlanReqEntry->pfOidQueryHandler(prGlueInfo, + prNdisReq->ndisOidContent, + prNdisReq->inNdisOidlength, + &u4BufLen); + } + else if (prWlanReqEntry->eOidMethod == ENUM_OID_DRIVER_CORE) { + /* driver core*/ + + status = kalIoctl(prGlueInfo, + (PFN_OID_HANDLER_FUNC)prWlanReqEntry->pfOidQueryHandler, + prNdisReq->ndisOidContent, + prNdisReq->inNdisOidlength, + TRUE, + TRUE, + TRUE, + FALSE, + &u4BufLen); + } + else { + DBGLOG(REQ, INFO, ("priv_set_ndis(): unsupported OID method:0x%x\n", + prWlanReqEntry->eOidMethod)); + return -EOPNOTSUPP; + } + + *pu4OutputLen = u4BufLen; + + switch (status) { + case WLAN_STATUS_SUCCESS: + break; + + case WLAN_STATUS_INVALID_LENGTH: + //WARNLOG(("Set %s: Invalid length (current=%ld, needed=%ld)\n", + // prWlanReqEntry->pucOidName, + //prNdisReq->inNdisOidlength, + //u4BufLen)); + break; + } + + if (WLAN_STATUS_SUCCESS != status) { + return -EOPNOTSUPP; + } + + return 0; +} /* priv_get_ndis */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to search desired OID. +* +* \param rOid[in] Desired NDIS_OID +* \param ppWlanReqEntry[out] Found registered OID entry +* +* \retval TRUE: Matched OID is found +* \retval FALSE: No matched OID is found +*/ +/*----------------------------------------------------------------------------*/ +static BOOLEAN +reqSearchSupportedOidEntry ( + IN UINT_32 rOid, + OUT P_WLAN_REQ_ENTRY *ppWlanReqEntry + ) +{ + INT_32 i, j, k; + + i = 0; + j = NUM_SUPPORTED_OIDS - 1; + + while (i <= j) { + k = (i + j) / 2; + + if (rOid == arWlanOidReqTable[k].rOid) { + *ppWlanReqEntry = &arWlanOidReqTable[k]; + return TRUE; + } else if (rOid < arWlanOidReqTable[k].rOid) { + j = k - 1; + } else { + i = k + 1; + } + } + + return FALSE; +} /* reqSearchSupportedOidEntry */ + +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the radio configuration used in IBSS +* mode and RF test mode. +* +* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. +* \param[out] pvQueryBuffer Pointer to the buffer that holds the result of the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +static WLAN_STATUS +reqExtQueryConfiguration ( + IN P_GLUE_INFO_T prGlueInfo, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ) +{ + P_PARAM_802_11_CONFIG_T prQueryConfig = (P_PARAM_802_11_CONFIG_T)pvQueryBuffer; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4QueryInfoLen = 0; + + DEBUGFUNC("wlanoidQueryConfiguration"); + + + ASSERT(prGlueInfo); + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(PARAM_802_11_CONFIG_T); + if (u4QueryBufferLen < sizeof(PARAM_802_11_CONFIG_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvQueryBuffer); + + kalMemZero(prQueryConfig, sizeof(PARAM_802_11_CONFIG_T)); + + /* Update the current radio configuration. */ + prQueryConfig->u4Length = sizeof(PARAM_802_11_CONFIG_T); + +#if defined(_HIF_SDIO) + rStatus = sdio_io_ctrl(prGlueInfo, + wlanoidSetBeaconInterval, + &prQueryConfig->u4BeaconPeriod, + sizeof(UINT_32), + TRUE, + TRUE, + &u4QueryInfoLen); +#else + rStatus = wlanQueryInformation(prGlueInfo->prAdapter, + wlanoidQueryBeaconInterval, + &prQueryConfig->u4BeaconPeriod, + sizeof(UINT_32), + &u4QueryInfoLen); +#endif + if (rStatus != WLAN_STATUS_SUCCESS) { + return rStatus; + } + +#if defined(_HIF_SDIO) + rStatus = sdio_io_ctrl(prGlueInfo, + wlanoidQueryAtimWindow, + &prQueryConfig->u4ATIMWindow, + sizeof(UINT_32), + TRUE, + TRUE, + &u4QueryInfoLen); +#else + rStatus = wlanQueryInformation(prGlueInfo->prAdapter, + wlanoidQueryAtimWindow, + &prQueryConfig->u4ATIMWindow, + sizeof(UINT_32), + &u4QueryInfoLen); +#endif + if (rStatus != WLAN_STATUS_SUCCESS) { + return rStatus; + } + +#if defined(_HIF_SDIO) + rStatus = sdio_io_ctrl(prGlueInfo, + wlanoidQueryFrequency, + &prQueryConfig->u4DSConfig, + sizeof(UINT_32), + TRUE, + TRUE, + &u4QueryInfoLen); +#else + rStatus = wlanQueryInformation(prGlueInfo->prAdapter, + wlanoidQueryFrequency, + &prQueryConfig->u4DSConfig, + sizeof(UINT_32), + &u4QueryInfoLen); +#endif + if (rStatus != WLAN_STATUS_SUCCESS) { + return rStatus; + } + + prQueryConfig->rFHConfig.u4Length = sizeof(PARAM_802_11_CONFIG_FH_T); + + return rStatus; + +} /* end of reqExtQueryConfiguration() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set the radio configuration used in IBSS +* mode. +* +* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_NOT_ACCEPTED +*/ +/*----------------------------------------------------------------------------*/ +static WLAN_STATUS +reqExtSetConfiguration ( + IN P_GLUE_INFO_T prGlueInfo, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_PARAM_802_11_CONFIG_T prNewConfig = (P_PARAM_802_11_CONFIG_T)pvSetBuffer; + UINT_32 u4SetInfoLen = 0; + + DEBUGFUNC("wlanoidSetConfiguration"); + + + ASSERT(prGlueInfo); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_802_11_CONFIG_T); + + if (u4SetBufferLen < *pu4SetInfoLen) { + return WLAN_STATUS_INVALID_LENGTH; + } + + /* OID_802_11_CONFIGURATION. If associated, NOT_ACCEPTED shall be returned. */ + if (prGlueInfo->eParamMediaStateIndicated == PARAM_MEDIA_STATE_CONNECTED) { + return WLAN_STATUS_NOT_ACCEPTED; + } + + ASSERT(pvSetBuffer); + +#if defined(_HIF_SDIO) + rStatus = sdio_io_ctrl(prGlueInfo, + wlanoidSetBeaconInterval, + &prNewConfig->u4BeaconPeriod, + sizeof(UINT_32), + FALSE, + TRUE, + &u4SetInfoLen); +#else + rStatus = wlanSetInformation(prGlueInfo->prAdapter, + wlanoidSetBeaconInterval, + &prNewConfig->u4BeaconPeriod, + sizeof(UINT_32), + &u4SetInfoLen); +#endif + if (rStatus != WLAN_STATUS_SUCCESS) { + return rStatus; + } + +#if defined(_HIF_SDIO) + rStatus = sdio_io_ctrl(prGlueInfo, + wlanoidSetAtimWindow, + &prNewConfig->u4ATIMWindow, + sizeof(UINT_32), + FALSE, + TRUE, + &u4SetInfoLen); +#else + rStatus = wlanSetInformation(prGlueInfo->prAdapter, + wlanoidSetAtimWindow, + &prNewConfig->u4ATIMWindow, + sizeof(UINT_32), + &u4SetInfoLen); +#endif + if (rStatus != WLAN_STATUS_SUCCESS) { + return rStatus; + } + +#if defined(_HIF_SDIO) + rStatus = sdio_io_ctrl(prGlueInfo, + wlanoidSetFrequency, + &prNewConfig->u4DSConfig, + sizeof(UINT_32), + FALSE, + TRUE, + &u4SetInfoLen); +#else + rStatus = wlanSetInformation(prGlueInfo->prAdapter, + wlanoidSetFrequency, + &prNewConfig->u4DSConfig, + sizeof(UINT_32), + &u4SetInfoLen); +#endif + + if (rStatus != WLAN_STATUS_SUCCESS) { + return rStatus; + } + + return rStatus; + +} /* end of reqExtSetConfiguration() */ + +#endif +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set beacon detection function enable/disable state +* This is mainly designed for usage under BT inquiry state (disable function). +* +* \param[in] pvAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. +* \retval WLAN_STATUS_INVALID_LENGTH +* +*/ +/*----------------------------------------------------------------------------*/ +static WLAN_STATUS +reqExtSetAcpiDevicePowerState ( + IN P_GLUE_INFO_T prGlueInfo, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + ASSERT(prGlueInfo); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + /* WIFI is enabled, when ACPI is D0 (ParamDeviceStateD0 = 1). And vice versa */ + + //rStatus = wlanSetInformation(prGlueInfo->prAdapter, + // wlanoidSetAcpiDevicePowerState, + // pvSetBuffer, + // u4SetBufferLen, + // pu4SetInfoLen); + return rStatus; +} + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/arm.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/arm.c new file mode 100755 index 000000000000..eef362e4ffc3 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/arm.c @@ -0,0 +1,68 @@ +/****************************************************************************** +*[File] mt6516-evb.c +*[Version] v1.0 +*[Revision Date] 2010-03-01 +*[Author] +*[Description] +* dummy file for build system +*[Copyright] +* Copyright (C) 2010 MediaTek Incorporation. All Rights Reserved. +******************************************************************************/ + + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: mt6516-evb.c $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 04 19 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * remove debug message + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port +** +*/ diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/include/hif.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/include/hif.h new file mode 100755 index 000000000000..6f71eff4232a --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/include/hif.h @@ -0,0 +1,269 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/os/linux/hif/sdio/include/hif.h#1 $ +*/ + +/*! \file "hif.h" + \brief Functions for the driver to register bus and setup the IRQ + + Functions for the driver to register bus and setup the IRQ +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: hif.h $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 11 01 2010 yarco.yang + * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform + * Add GPIO debug function + * + * 10 19 2010 jeffrey.chang + * [WCXRP00000120] [MT6620 Wi-Fi][Driver] Refine linux kernel module to the license of MTK propietary and enable MTK HIF by default + * Refine linux kernel module to the license of MTK and enable MTK HIF + * + * 08 18 2010 jeffrey.chang + * NULL + * support multi-function sdio + * + * 08 17 2010 cp.wu + * NULL + * add ENE SDIO host workaround for x86 linux platform. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port +** \main\maintrunk.MT5921\4 2009-10-20 17:38:28 GMT mtk01090 +** Refine driver unloading and clean up procedure. Block requests, stop main thread and clean up queued requests, and then stop hw. +** \main\maintrunk.MT5921\3 2009-09-28 20:19:20 GMT mtk01090 +** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. +** \main\maintrunk.MT5921\2 2009-08-18 22:57:05 GMT mtk01090 +** Add Linux SDIO (with mmc core) support. +** Add Linux 2.6.21, 2.6.25, 2.6.26. +** Fix compile warning in Linux. +** \main\maintrunk.MT5921\2 2008-09-22 23:18:17 GMT mtk01461 +** Update driver for code review +** Revision 1.1 2007/07/05 07:25:33 MTK01461 +** Add Linux initial code, modify doc, add 11BB, RF init code +** +** Revision 1.3 2007/06/27 02:18:51 MTK01461 +** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API +** +*/ + +#ifndef _HIF_H +#define _HIF_H + + +#if MTK_WCN_HIF_SDIO +#include "hif_sdio.h" +#endif + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define SDIO_X86_WORKAROUND_WRITE_MCR 0x00C4 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/* host interface's private data structure, which is attached to os glue +** layer info structure. + */ +typedef struct _GL_HIF_INFO_T { +#if MTK_WCN_HIF_SDIO + MTK_WCN_HIF_SDIO_CLTCTX cltCtx; + const MTK_WCN_HIF_SDIO_FUNCINFO *prFuncInfo; +#else + struct sdio_func *func; +#endif + BOOLEAN fgIntReadClear; + BOOLEAN fgMbxReadClear; +} GL_HIF_INFO_T, *P_GL_HIF_INFO_T; + + +#if CFG_DBG_GPIO_PINS + +extern void +mtk_wcn_stp_debug_gpio_assert(UINT_32 dwIndex, UINT_32 dwMethod); + + +/* Platform DEPENDENT configurations: MT6516 GPIO pin name */ +#define GPIO_6516(x) (GPIO##x) +#define GPIO_PLATFORM(x) GPIO_6516(x) + +/* Platform independent configurations */ +#define DBG_TIE_DIR 0x40000000UL +#define DBG_LOW 0x0UL +#define DBG_HIGH 0x1UL +#define DBG_TIE_LOW (DBG_TIE_DIR | DBG_LOW) +#define DBG_TIE_HIGH (DBG_TIE_DIR | DBG_HIGH) + +#define DBG_TOGGLE(x) (0x80000000UL | x) +#define DBG_TOGGLE_NUM(x) (x & 0xFFF) +#define GPIO_INVALID 0xFFFF + +typedef enum { + IDX_ERR = 0, + IDX_TX_THREAD, + IDX_TX_REQ, + IDX_TX_PORT_WRITE, + IDX_STP_MTX_BT, + IDX_STP_MTX_FM, /* 5 */ + IDX_STP_MTX_GPS, + IDX_STP_MTX_WIFI, + IDX_STP_MTX_WMT, + IDX_LOOP_CNT, + IDX_NO_BUF, /*10 */ + IDX_BT_TX, + IDX_BT_RX, + IDX_GPS_RX, + IDX_GPS_2, + IDX_GPS_3, + IDX_GPS_TX, + IDX_STP_MAX +} DBG_PIN; + +#define DBG_MTX_OFFSET (IDX_STP_MTX_BT) /* index of mutex0 */ +#endif +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +WLAN_STATUS +glRegisterBus( + probe_card pfProbe, + remove_card pfRemove + ); + +VOID +glUnregisterBus( + remove_card pfRemove + ); + +VOID +glSetHifInfo ( + P_GLUE_INFO_T prGlueInfo, + UINT_32 u4Cookie + ); + +VOID +glClearHifInfo ( + P_GLUE_INFO_T prGlueInfo + ); + +BOOL +glBusInit ( + PVOID pvData + ); + +VOID +glBusRelease ( + PVOID pData + ); + +INT_32 +glBusSetIrq ( + PVOID pvData, + PVOID pfnIsr, + PVOID pvCookie + ); + +VOID +glBusFreeIrq ( + PVOID pvData, + PVOID pvCookie + ); + +VOID +glSetPowerState ( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_32 ePowerMode + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#endif /* _HIF_H */ diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/include/hif_sdio.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/include/hif_sdio.h new file mode 100755 index 000000000000..c444fe1214b0 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/include/hif_sdio.h @@ -0,0 +1,311 @@ + +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + */ +/* MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/os/linux/hif/sdio/include/hif_sdio.h#2 $ +*/ + +/*! \file "hif_sdio.h" + \brief + + +*/ + +/* +** $Log: $ + * + * 01 09 2012 terry.wu + * [WCXRP00001166] [Wi-Fi] [Driver] cfg80211 integration for p2p newtork + * cfg80211 integration for p2p network. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 08 18 2010 jeffrey.chang + * NULL + * support multi-function sdio + * + * 07 25 2010 george.kuo + * + * Move hif_sdio driver to linux directory. + * + * 07 23 2010 george.kuo + * + * Add MT6620 driver source tree + * , including char device driver (wmt, bt, gps), stp driver, interface driver (tty ldisc and hif_sdio), and bt hci driver. +** +** +*/ + +#ifndef _HIF_SDIO_H +#define _HIF_SDIO_H +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +#define HIF_SDIO_DEBUG (0) /* 0:trun off debug msg and assert, 1:trun off debug msg and assert */ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "mtk_porting.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define CFG_CLIENT_COUNT (9) + +#define HIF_DEFAULT_BLK_SIZE (256) +#define HIF_DEFAULT_VENDOR (0x037A) + +#define HIF_SDIO_LOG_LOUD 4 +#define HIF_SDIO_LOG_DBG 3 +#define HIF_SDIO_LOG_INFO 2 +#define HIF_SDIO_LOG_WARN 1 +#define HIF_SDIO_LOG_ERR 0 + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/* Function info provided by client driver */ +typedef struct _MTK_WCN_HIF_SDIO_FUNCINFO MTK_WCN_HIF_SDIO_FUNCINFO; + +/* Client context provided by hif_sdio driver for the following function call */ +typedef UINT32 MTK_WCN_HIF_SDIO_CLTCTX; + +/* Callback functions provided by client driver */ +typedef INT32 (*MTK_WCN_HIF_SDIO_PROBE)(MTK_WCN_HIF_SDIO_CLTCTX, const MTK_WCN_HIF_SDIO_FUNCINFO *); +typedef INT32 (*MTK_WCN_HIF_SDIO_REMOVE)(MTK_WCN_HIF_SDIO_CLTCTX); +typedef INT32 (*MTK_WCN_HIF_SDIO_IRQ)(MTK_WCN_HIF_SDIO_CLTCTX); + +/* Function info provided by client driver */ +struct _MTK_WCN_HIF_SDIO_FUNCINFO { + UINT16 manf_id; /* TPLMID_MANF: manufacturer ID */ + UINT16 card_id; /* TPLMID_CARD: card ID */ + UINT16 func_num; /* Function Number */ + UINT16 blk_sz; /* Function block size */ +}; + +/* Client info provided by client driver */ +typedef struct _MTK_WCN_HIF_SDIO_CLTINFO { + const MTK_WCN_HIF_SDIO_FUNCINFO *func_tbl; /* supported function info table */ + UINT32 func_tbl_size; /* supported function table info element number */ + MTK_WCN_HIF_SDIO_PROBE hif_clt_probe; /* callback function for probing */ + MTK_WCN_HIF_SDIO_REMOVE hif_clt_remove; /* callback function for removing */ + MTK_WCN_HIF_SDIO_IRQ hif_clt_irq; /* callback function for interrupt handling */ +} MTK_WCN_HIF_SDIO_CLTINFO; + +/* function info provided by registed function */ +typedef struct _MTK_WCN_HIF_SDIO_REGISTINFO { + const MTK_WCN_HIF_SDIO_CLTINFO *sdio_cltinfo; /* client's MTK_WCN_HIF_SDIO_CLTINFO pointer */ + const MTK_WCN_HIF_SDIO_FUNCINFO *func_info; /* supported function info pointer */ +} MTK_WCN_HIF_SDIO_REGISTINFO; + +/* Card info provided by probed function */ +typedef struct _MTK_WCN_HIF_SDIO_PROBEINFO { + struct sdio_func* func; /* probed sdio function pointer */ + void* private_data_p; /* clt's private data pointer */ + MTK_WCN_BOOL on_by_wmt; /* TRUE: on by wmt, FALSE: not on by wmt */ + /* added for sdio irq sync and mmc single_irq workaround */ + MTK_WCN_BOOL sdio_irq_enabled; /* TRUE: can handle sdio irq; FALSE: no sdio irq handling */ + INT8 clt_idx; /* registered function table info element number (initial value is -1) */ +} MTK_WCN_HIF_SDIO_PROBEINFO; + +/* work queue info needed by worker */ +typedef struct _MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO { + struct work_struct probe_work; /* work queue structure */ + MTK_WCN_HIF_SDIO_REGISTINFO *registinfo_p; /* MTK_WCN_HIF_SDIO_REGISTINFO pointer of the client */ + INT8 probe_idx; /* probed function table info element number (initial value is -1) */ +} MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO; + +/* error code returned by hif_sdio driver (use NEGATIVE number) */ +typedef enum { + HIF_SDIO_ERR_SUCCESS = 0, + HIF_SDIO_ERR_FAIL = HIF_SDIO_ERR_SUCCESS - 1, /* generic error */ + HIF_SDIO_ERR_INVALID_PARAM = HIF_SDIO_ERR_FAIL - 1, + HIF_SDIO_ERR_DUPLICATED = HIF_SDIO_ERR_INVALID_PARAM - 1, + HIF_SDIO_ERR_UNSUP_MANF_ID = HIF_SDIO_ERR_DUPLICATED - 1, + HIF_SDIO_ERR_UNSUP_CARD_ID = HIF_SDIO_ERR_UNSUP_MANF_ID - 1, + HIF_SDIO_ERR_INVALID_FUNC_NUM = HIF_SDIO_ERR_UNSUP_CARD_ID - 1, + HIF_SDIO_ERR_INVALID_BLK_SZ = HIF_SDIO_ERR_INVALID_FUNC_NUM - 1, + HIF_SDIO_ERR_NOT_PROBED = HIF_SDIO_ERR_INVALID_BLK_SZ - 1, + HIF_SDIO_ERR_ALRDY_ON = HIF_SDIO_ERR_NOT_PROBED -1, + HIF_SDIO_ERR_ALRDY_OFF = HIF_SDIO_ERR_ALRDY_ON -1, + HIF_SDIO_ERR_CLT_NOT_REG = HIF_SDIO_ERR_ALRDY_OFF - 1, +} MTK_WCN_HIF_SDIO_ERR ; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/*! + * \brief A macro used to describe an SDIO function + * + * Fill an MTK_WCN_HIF_SDIO_FUNCINFO structure with function-specific information + * + * \param manf the 16 bit manufacturer id + * \param card the 16 bit card id + * \param func the 16 bit function number + * \param b_sz the 16 bit function block size + */ +#define MTK_WCN_HIF_SDIO_FUNC(manf, card, func, b_sz) \ + .manf_id = (manf), .card_id = (card), .func_num = (func), .blk_sz = (b_sz) + +#define HIF_SDIO_LOUD_FUNC(fmt, arg...) if (gHifSdioDbgLvl >= HIF_SDIO_LOG_LOUD) { printk(KERN_INFO SDIO_TAG"[L]%s:" fmt, __FUNCTION__ ,##arg);} +#define HIF_SDIO_DBG_FUNC(fmt, arg...) if (gHifSdioDbgLvl >= HIF_SDIO_LOG_DBG) { printk(KERN_INFO SDIO_TAG"[D]%s:" fmt, __FUNCTION__ ,##arg);} +#define HIF_SDIO_INFO_FUNC(fmt, arg...) if (gHifSdioDbgLvl >= HIF_SDIO_LOG_INFO) { printk(KERN_INFO SDIO_TAG"[I]%s:" fmt, __FUNCTION__ ,##arg);} +#define HIF_SDIO_WARN_FUNC(fmt, arg...) if (gHifSdioDbgLvl >= HIF_SDIO_LOG_WARN) { printk(KERN_WARNING SDIO_TAG"[W]%s(%d):" fmt, __FUNCTION__ , __LINE__, ##arg);} +#define HIF_SDIO_ERR_FUNC(fmt, arg...) if (gHifSdioDbgLvl >= HIF_SDIO_LOG_ERR) { printk(KERN_WARNING SDIO_TAG"[E]%s(%d):" fmt, __FUNCTION__ , __LINE__, ##arg);} + +/*! + * \brief ASSERT function definition. + * + */ +#if HIF_SDIO_DEBUG +#define HIF_SDIO_ASSERT(expr) if ( !(expr) ) { \ + printk("assertion failed! %s[%d]: %s\n",\ + __FUNCTION__, __LINE__, #expr); \ + BUG_ON( !(expr) );\ + } +#else +#define HIF_SDIO_ASSERT(expr) do {} while(0) +#endif + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/*! + * \brief MTK hif sdio client registration function + * + * Client uses this function to do hif sdio registration + * + * \param pinfo a pointer of client's information + * + * \retval 0 register successfully + * \retval < 0 error code + */ +extern INT32 mtk_wcn_hif_sdio_client_reg ( + const MTK_WCN_HIF_SDIO_CLTINFO *pinfo + ); + +extern INT32 mtk_wcn_hif_sdio_client_unreg ( + const MTK_WCN_HIF_SDIO_CLTINFO *pinfo + ); + +extern INT32 mtk_wcn_hif_sdio_readb ( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + UINT32 offset, + PUINT8 pvb + ); + +extern INT32 mtk_wcn_hif_sdio_writeb ( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + UINT32 offset, + UINT8 vb + ); + +extern INT32 mtk_wcn_hif_sdio_readl ( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + UINT32 offset, + PUINT32 pvl + ); + +extern INT32 mtk_wcn_hif_sdio_writel ( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + UINT32 offset, + UINT32 vl + ); + +extern INT32 mtk_wcn_hif_sdio_read_buf ( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + UINT32 offset, + PUINT32 pbuf, + UINT32 len + ); + +extern INT32 mtk_wcn_hif_sdio_write_buf ( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + UINT32 offset, + PUINT32 pbuf, + UINT32 len + ); + +extern void mtk_wcn_hif_sdio_set_drvdata( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + void* private_data_p + ); + +extern void* mtk_wcn_hif_sdio_get_drvdata( + MTK_WCN_HIF_SDIO_CLTCTX ctx + ); + +extern void mtk_wcn_hif_sdio_get_dev( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + struct device **dev + ); + +extern void mtk_wcn_hif_sdio_enable_irq( + MTK_WCN_HIF_SDIO_CLTCTX ctx, + MTK_WCN_BOOL enable + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#endif /* _HIF_SDIO_H */ + + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/include/mtk_porting.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/include/mtk_porting.h new file mode 100755 index 000000000000..de75f1d83369 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/include/mtk_porting.h @@ -0,0 +1,53 @@ + +/* porting layer */ +/* Android */ + +#ifndef _MTK_PORTING_H_ +#define _MTK_PORTING_H_ + +#include /* include stddef.h for NULL */ + +/* Type definition for signed integers */ +typedef signed char INT8, *PINT8; +typedef signed short INT16, *PINT16; +typedef signed int INT32, *PINT32; + +/* Type definition for unsigned integers */ +typedef unsigned char UINT8, *PUINT8; +typedef unsigned short UINT16, *PUINT16; +typedef unsigned int UINT32, *PUINT32; + +//typedef void VOID, *PVOID; + +typedef int MTK_WCN_BOOL; +#ifndef MTK_WCN_BOOL_TRUE +#define MTK_WCN_BOOL_FALSE ((MTK_WCN_BOOL) 0) +#define MTK_WCN_BOOL_TRUE ((MTK_WCN_BOOL) 1) +#endif + +typedef int MTK_WCN_MUTEX; + +typedef int MTK_WCN_TIMER; + +/* system APIs */ +/* mutex */ +typedef MTK_WCN_MUTEX (*MUTEX_CREATE)(const char * const name); +typedef INT32 (*MUTEX_DESTROY)(MTK_WCN_MUTEX mtx); +typedef INT32 (*MUTEX_LOCK)(MTK_WCN_MUTEX mtx); +typedef INT32 (*MUTEX_UNLOCK)(MTK_WCN_MUTEX mtx, unsigned long flags); +/* debug */ +typedef INT32 (*DBG_PRINT)(const char *str, ...); +typedef INT32 (*DBG_ASSERT)(INT32 expr, const char *file, INT32 line); +/* timer */ +typedef void (*MTK_WCN_TIMER_CB)(void); +typedef MTK_WCN_TIMER (*TIMER_CREATE)(const char * const name); +typedef INT32 (*TIMER_DESTROY)(MTK_WCN_TIMER tmr); +typedef INT32 (*TIMER_START)(MTK_WCN_TIMER tmr, UINT32 timeout, MTK_WCN_TIMER_CB tmr_cb, void *param); +typedef INT32 (*TIMER_STOP)(MTK_WCN_TIMER tmr); +/* kernel lib */ +typedef void* (*SYS_MEMCPY)(void *dest, const void *src, UINT32 n); +typedef void* (*SYS_MEMSET)(void *s, INT32 c, UINT32 n); +typedef INT32 (*SYS_SPRINTF)(char *str, const char *format, ...); + +#endif /* _MTK_PORTING_H_ */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/sdio.S b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/sdio.S new file mode 100755 index 000000000000..e69de29bb2d1 diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/sdio.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/sdio.c new file mode 100755 index 000000000000..3556546a66c5 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/sdio.c @@ -0,0 +1,1281 @@ +/****************************************************************************** +*[File] sdio.c +*[Version] v1.0 +*[Revision Date] 2010-03-01 +*[Author] +*[Description] +* The program provides SDIO HIF driver +*[Copyright] +* Copyright (C) 2010 MediaTek Incorporation. All Rights Reserved. +******************************************************************************/ + + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: sdio.c $ + * + * 11 10 2011 cp.wu + * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer + * 1. eliminaite direct calls to printk in porting layer. + * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 18 2011 cp.wu + * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous memory consumption + * deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK. + * + * 03 15 2011 cp.wu + * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous memory consumption + * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK + * 2. Use common coalescing buffer for both TX/RX directions + * + * + * 03 07 2011 terry.wu + * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message + * Toggle non-standard debug messages to comments. + * + * 11 15 2010 jeffrey.chang + * [WCXRP00000181] [MT6620 Wi-Fi][Driver] fix the driver message "GLUE_FLAG_HALT skip INT" during unloading + * Fix GLUE_FALG_HALT message which cause driver to hang + * + * 11 08 2010 cp.wu + * [WCXRP00000166] [MT6620 Wi-Fi][Driver] use SDIO CMD52 for enabling/disabling interrupt to reduce transaction period + * correct typo + * + * 11 08 2010 cp.wu + * [WCXRP00000166] [MT6620 Wi-Fi][Driver] use SDIO CMD52 for enabling/disabling interrupt to reduce transaction period + * change to use CMD52 for enabling/disabling interrupt to reduce SDIO transaction time + * + * 11 01 2010 yarco.yang + * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform + * Add code to run WlanIST in SDIO callback. + * + * 10 19 2010 cp.wu + * [WCXRP00000122] [MT6620 Wi-Fi][Driver] Preparation for YuSu source tree integration + * remove HIF_SDIO_ONE flags because the settings could be merged for runtime detection instead of compile-time. + * + * 10 19 2010 jeffrey.chang + * [WCXRP00000120] [MT6620 Wi-Fi][Driver] Refine linux kernel module to the license of MTK propietary and enable MTK HIF by default + * Refine linux kernel module to the license of MTK and enable MTK HIF + * + * 08 21 2010 jeffrey.chang + * NULL + * 1) add sdio two setting + * 2) bug fix of sdio glue + * + * 08 18 2010 jeffrey.chang + * NULL + * support multi-function sdio + * + * 08 18 2010 cp.wu + * NULL + * #if defined(__X86__) is not working, change to use #ifdef CONFIG_X86. + * + * 08 17 2010 cp.wu + * NULL + * add ENE SDIO host workaround for x86 linux platform. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 07 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Fix hotplug bug + * + * 03 28 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * clear sdio interrupt + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "gl_os.h" + +#if MTK_WCN_HIF_SDIO +#include "hif_sdio.h" +#else +#include +#include +#include +#include /* sdio_readl(), etc */ +#include +#endif + +#include +//#ifndef CONFIG_X86 modify by Nicolas Luo +#ifdef CONFIG_ARM +#include +#endif +#include "mt6620_reg.h" + +#if CFG_DBG_GPIO_PINS/* FIXME: move to platform or custom header */ +#include +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#if MTK_WCN_HIF_SDIO + + +/* + * function prototypes + * + */ + +static INT32 +mtk_sdio_probe(MTK_WCN_HIF_SDIO_CLTCTX, const MTK_WCN_HIF_SDIO_FUNCINFO *); + +static INT32 +mtk_sdio_remove(MTK_WCN_HIF_SDIO_CLTCTX); +static INT32 mtk_sdio_interrupt(MTK_WCN_HIF_SDIO_CLTCTX); + +/* + * sdio function info table + */ + +static MTK_WCN_HIF_SDIO_FUNCINFO funcInfo[] = { +#if defined(MT6620) + { MTK_WCN_HIF_SDIO_FUNC(0x037a, 0x020a, 0x1, 512) }, + { MTK_WCN_HIF_SDIO_FUNC(0x037a, 0x020c, 0x2, 512) }, + { MTK_WCN_HIF_SDIO_FUNC(0x037a, 0x018a, 0x1, 512) }, + { MTK_WCN_HIF_SDIO_FUNC(0x037a, 0x018c, 0x2, 512) }, +#elif defined(MT5931) + { MTK_WCN_HIF_SDIO_FUNC(0x037a, 0x5931, 0x1, 512) }, +#elif defined(MT6628) + { MTK_WCN_HIF_SDIO_FUNC(0x037a, 0x6628, 0x1, 512) }, +#endif +}; + + +static MTK_WCN_HIF_SDIO_CLTINFO cltInfo = { + .func_tbl = funcInfo, + .func_tbl_size = sizeof(funcInfo)/sizeof(MTK_WCN_HIF_SDIO_FUNCINFO), + .hif_clt_probe = mtk_sdio_probe, + .hif_clt_remove = mtk_sdio_remove, + .hif_clt_irq = mtk_sdio_interrupt, +}; + +#else + +static const struct sdio_device_id mtk_sdio_ids[] = { +#if defined(MT6620) + { SDIO_DEVICE(0x037a, 0x020a) }, /* Not an SDIO standard class device */ + { SDIO_DEVICE(0x037a, 0x020b) }, /* Not an SDIO standard class device */ + { SDIO_DEVICE(0x037a, 0x020c) }, /* Not an SDIO standard class device */ +#elif defined(MT5931) + { SDIO_DEVICE(0x037a, 0x5931) }, /* Not an SDIO standard class device */ +#elif defined(MT6628) + { SDIO_DEVICE(0x037a, 0x6628) }, /* Not an SDIO standard class device */ +#endif + { /* end: all zeroes */ }, +}; + +MODULE_DEVICE_TABLE(sdio, mtk_sdio_ids); + +#endif + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +static probe_card pfWlanProbe = NULL; +static remove_card pfWlanRemove = NULL; + + +#if (MTK_WCN_HIF_SDIO == 0) +static struct sdio_driver mtk_sdio_driver = { + .name = "wlan", /* "MTK SDIO WLAN Driver" */ + .id_table = mtk_sdio_ids, + .probe = NULL, + .remove = NULL, +}; +#endif + + +#if CFG_DBG_GPIO_PINS + +/* debug pins */ +UINT_32 dbgPinSTP[] = { + GPIO_PLATFORM(33)/* CMFLASH, IDX_ERR J613 */ + , GPIO_PLATFORM(62)/* EINT3, IDX_TX_THREAD */ + , GPIO_PLATFORM(80)/* SPI_CS_N, IDX_TX_REQ J613 */ + , GPIO_PLATFORM(81)/* SPI_SCK, IDX_TX_PORT_WRITE J613 */ + , GPIO_PLATFORM(17) /* CMRST, IDX_STP_MTX_BT J618 */ + , GPIO_PLATFORM(18) /* CMPDN, IDX_STP_MTX_FM J613 */ + , GPIO_PLATFORM(19) /* CMVREF,IDX_STP_MTX_GPS J613 */ + , GPIO_INVALID /* REMOVED, IDX_STP_MTX_WIFI */ + , GPIO_INVALID /* REMOVED, IDX_STP_MTX_WMT */ + , GPIO_PLATFORM(135) /* SCL2, IDX_LOOP_CNT J616 */ + , GPIO_PLATFORM(136) /* SDA2, IDX_NO_BUF J616 */ + , GPIO_PLATFORM(30) /* CAM_MECHSH0, IDX_BT_TX, J613 low-active */ + , GPIO_PLATFORM(31) /* CAM_MECHSH1, IDX_BT_RX, J613 low-active */ + , GPIO_PLATFORM(124) /* GPS_PWR_EN, ThreadDSPIn [GPS] */ + , GPIO_PLATFORM(125) /* GPS_SYNC, mtk_sys_msg_recv [GPS] */ + , GPIO_PLATFORM(21) /* GPS_EINT8, dump_nmea_data [GPS] */ + , GPIO_PLATFORM(29) /* CAM_STROBE, IDX_GPS_TX, J613 low-active */ + , GPIO_PLATFORM(20) /*CMHREF, J613 UNUSED */ +// , GPIO_6516(64) /* EINT5, REMOVED!!! for MT6620-Wi-Fi Int */ +// , GPIO_6516(122) /* BT_PWR_EN, REMOVED!!! for MT6620-PMU_EN */ +// , GPIO_6516(123) /* BT_RESET, REMOVED!!! for MT6620-RST */ +}; +#endif +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#if CFG_DBG_GPIO_PINS +void debug_gpio_init(void) +{ + int i; + + for (i = 0; i < sizeof(dbgPinSTP)/sizeof(dbgPinSTP[0]); ++i) { + if (GPIO_INVALID == dbgPinSTP[i]) { + continue; + } + //printk(KERN_INFO "[%s] %ld \n", __FUNCTION__, dbgPinSTP[i]); + mt_set_gpio_pull_enable(dbgPinSTP[i], 0); /* disable pull */ + mt_set_gpio_dir(dbgPinSTP[i], GPIO_DIR_OUT); /* set output */ + mt_set_gpio_mode(dbgPinSTP[i], GPIO_MODE_00); /* set gpio mode */ + + /* toggle twice to check if ok: */ + mt_set_gpio_out(dbgPinSTP[i], GPIO_OUT_ZERO); /* tie low */ + mt_set_gpio_out(dbgPinSTP[i], GPIO_OUT_ONE); /* tie high*/ + mt_set_gpio_out(dbgPinSTP[i], GPIO_OUT_ZERO); /* tie low */ + mt_set_gpio_out(dbgPinSTP[i], GPIO_OUT_ONE); /* tie high*/ + } + //printk(KERN_INFO "[%s] initialization ok \n", __FUNCTION__); +} + +void debug_gpio_deinit(void) +{ + int i; + for (i = 0; i < sizeof(dbgPinSTP)/sizeof(dbgPinSTP[0]); ++i) { + if (GPIO_INVALID == dbgPinSTP[i]) { + continue; + } + //printk(KERN_INFO "[%s] %ld \n", __FUNCTION__, dbgPinSTP[i]); + mt_set_gpio_dir(dbgPinSTP[i], GPIO_DIR_IN); + } + + //printk(KERN_INFO "[%s] k\n", __FUNCTION__); +} + +void mtk_wcn_stp_debug_gpio_assert(UINT_32 dwIndex, UINT_32 dwMethod) +{ + unsigned int i; + + if (dwIndex >= (sizeof(dbgPinSTP)/sizeof(dbgPinSTP[0]))) { + //printk(KERN_INFO "[%s] invalid dwIndex(%ld) \n", __FUNCTION__, dwIndex); + return; + } + + if (dwIndex > IDX_STP_MAX) { + //printk(KERN_INFO "[%s] dwIndex(%ld) > IDX_STP_MAX(%d) \n", __FUNCTION__, dwIndex, IDX_STP_MAX); + } + + if (GPIO_INVALID == dbgPinSTP[dwIndex]) { + return; + } + + if (dwMethod & DBG_TIE_DIR) { + if (dwMethod & DBG_HIGH) { + mt_set_gpio_out(dbgPinSTP[dwIndex], GPIO_OUT_ONE); + } + else { + mt_set_gpio_out(dbgPinSTP[dwIndex], GPIO_OUT_ZERO); + } + return; + } + + if (dwMethod & DBG_TOGGLE(0)) { + for (i = 0; i < DBG_TOGGLE_NUM(dwMethod); ++i) { + mt_set_gpio_out(dbgPinSTP[dwIndex], GPIO_OUT_ZERO); + mt_set_gpio_out(dbgPinSTP[dwIndex], GPIO_OUT_ONE); + } + return; + } + + return; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is a SDIO interrupt callback function +* +* \param[in] func pointer to SDIO handle +* +* \return void +*/ +/*----------------------------------------------------------------------------*/ + +#if MTK_WCN_HIF_SDIO + +static INT32 mtk_sdio_interrupt(MTK_WCN_HIF_SDIO_CLTCTX cltCtx) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + INT32 ret = 0; + + prGlueInfo = mtk_wcn_hif_sdio_get_drvdata(cltCtx); + + ASSERT(prGlueInfo); + + if (!prGlueInfo) { + //printk(KERN_INFO DRV_NAME"No glue info in mtk_sdio_interrupt()\n"); + return (-HIF_SDIO_ERR_FAIL); + } + + if (prGlueInfo->u4Flag & GLUE_FLAG_HALT) { + //printk(KERN_INFO DRV_NAME"GLUE_FLAG_HALT skip INT\n"); + ret = mtk_wcn_hif_sdio_writel(cltCtx, MCR_WHLPCR, WHLPCR_INT_EN_CLR); + return ret; + } + + ret = mtk_wcn_hif_sdio_writel(cltCtx, MCR_WHLPCR, WHLPCR_INT_EN_CLR); + + set_bit (GLUE_FLAG_INT_BIT, &prGlueInfo->u4Flag); + + /* when we got sdio interrupt, we wake up the tx servie thread*/ + wake_up_interruptible(&prGlueInfo->waitq); + + return ret; +} + +#else + +static unsigned int in_interrupt = 0; + +static void mtk_sdio_interrupt(struct sdio_func *func) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + int ret = 0; + + prGlueInfo = sdio_get_drvdata(func); + ASSERT(prGlueInfo); + + if (!prGlueInfo) { + //printk(KERN_INFO DRV_NAME"No glue info in mtk_sdio_interrupt()\n"); + return; + } + + if (prGlueInfo->u4Flag & GLUE_FLAG_HALT) { + sdio_writel(prGlueInfo->rHifInfo.func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, &ret); + //printk(KERN_INFO DRV_NAME"GLUE_FLAG_HALT skip INT\n"); + return; + } + + sdio_writel(prGlueInfo->rHifInfo.func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, &ret); + + #if 0 + wlanISR(prGlueInfo->prAdapter, TRUE); + + if (prGlueInfo->u4Flag & GLUE_FLAG_HALT) { + /* Should stop now... skip pending interrupt */ + //printk(KERN_INFO DRV_NAME"ignore pending interrupt\n"); + } + else { + wlanIST(prGlueInfo->prAdapter); + } + #endif + + set_bit (GLUE_FLAG_INT_BIT, &prGlueInfo->u4Flag); + + /* when we got sdio interrupt, we wake up the tx servie thread*/ + wake_up_interruptible(&prGlueInfo->waitq); +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is a SDIO probe function +* +* \param[in] func pointer to SDIO handle +* \param[in] id pointer to SDIO device id table +* +* \return void +*/ +/*----------------------------------------------------------------------------*/ + +#if MTK_WCN_HIF_SDIO + +// FIXME: global variable +static const MTK_WCN_HIF_SDIO_FUNCINFO *prFunc; + + +static INT32 +mtk_sdio_probe(MTK_WCN_HIF_SDIO_CLTCTX cltCtx, const MTK_WCN_HIF_SDIO_FUNCINFO *prFuncInfo) +{ + INT32 ret = HIF_SDIO_ERR_SUCCESS; + + prFunc = prFuncInfo; + + if (pfWlanProbe((PVOID) &cltCtx) != WLAN_STATUS_SUCCESS) { + //printk(KERN_WARNING DRV_NAME"pfWlanProbe fail!call pfWlanRemove()\n"); + pfWlanRemove(); + ret = -(HIF_SDIO_ERR_FAIL); + } else { + //printk(KERN_INFO DRV_NAME"mtk_wifi_sdio_probe() done(%d)\n", ret); + } + return ret; +} +#else +static int mtk_sdio_probe ( + struct sdio_func *func, + const struct sdio_device_id *id + ) +{ + int ret = 0; + int i = 0; + + //printk(KERN_INFO DRV_NAME "mtk_sdio_probe()\n"); + + ASSERT(func); + ASSERT(id); + + //printk(KERN_INFO DRV_NAME "Basic struct size checking...\n"); + //printk(KERN_INFO DRV_NAME "sizeof(struct device) = %d\n", sizeof(struct device)); + //printk(KERN_INFO DRV_NAME "sizeof(struct mmc_host) = %d\n", sizeof(struct mmc_host)); + //printk(KERN_INFO DRV_NAME "sizeof(struct mmc_card) = %d\n", sizeof(struct mmc_card)); + //printk(KERN_INFO DRV_NAME "sizeof(struct mmc_driver) = %d\n", sizeof(struct mmc_driver)); + //printk(KERN_INFO DRV_NAME "sizeof(struct mmc_data) = %d\n", sizeof(struct mmc_data)); + //printk(KERN_INFO DRV_NAME "sizeof(struct mmc_command) = %d\n", sizeof(struct mmc_command)); + //printk(KERN_INFO DRV_NAME "sizeof(struct mmc_request) = %d\n", sizeof(struct mmc_request)); + //printk(KERN_INFO DRV_NAME "sizeof(struct sdio_func) = %d\n", sizeof(struct sdio_func)); + + //printk(KERN_INFO DRV_NAME "Card information checking...\n"); + //printk(KERN_INFO DRV_NAME "func = 0x%p\n", func); + //printk(KERN_INFO DRV_NAME "Number of info = %d:\n", func->card->num_info); + + for (i = 0; i < func->card->num_info; i++) { + //printk(KERN_INFO DRV_NAME "info[%d]: %s\n", i, func->card->info[i]); + } + + sdio_claim_host(func); + ret = sdio_enable_func(func); + sdio_release_host(func); + + if (ret) { + //printk(KERN_INFO DRV_NAME"sdio_enable_func failed!\n"); + goto out; + } + //printk(KERN_INFO DRV_NAME"sdio_enable_func done!\n"); + + if (pfWlanProbe((PVOID)func) != WLAN_STATUS_SUCCESS) { + //printk(KERN_WARNING DRV_NAME"pfWlanProbe fail!call pfWlanRemove()\n"); + pfWlanRemove(); + ret = -1; + } + else { +#if CFG_DBG_GPIO_PINS + //printk(KERN_INFO "[%s] init debug gpio, 20100815 \n", __FUNCTION__); + /* Debug pins initialization */ + debug_gpio_init(); +#endif + } + +out: + //printk(KERN_INFO DRV_NAME"mtk_sdio_probe() done(%d)\n", ret); + return ret; +} +#endif + + +#if MTK_WCN_HIF_SDIO +static INT32 +mtk_sdio_remove(MTK_WCN_HIF_SDIO_CLTCTX cltCtx) +{ + INT32 ret = HIF_SDIO_ERR_SUCCESS; + //printk(KERN_INFO DRV_NAME"pfWlanRemove done\n"); + pfWlanRemove(); + + return ret; +} +#else +static void +mtk_sdio_remove ( + struct sdio_func *func + ) +{ + //printk(KERN_INFO DRV_NAME"mtk_sdio_remove()\n"); + +#if CFG_DBG_GPIO_PINS + //printk(KERN_INFO "[%s] deinit debug gpio \n", __FUNCTION__); + debug_gpio_deinit(); +#endif + + ASSERT(func); + //printk(KERN_INFO DRV_NAME"pfWlanRemove done\n"); + pfWlanRemove(); + + sdio_claim_host(func); + sdio_disable_func(func); + //printk(KERN_INFO DRV_NAME"sdio_disable_func() done\n"); + sdio_release_host(func); + + //printk(KERN_INFO DRV_NAME"mtk_sdio_remove() done\n"); +} +#endif + +#if (MTK_WCN_HIF_SDIO == 0) +static int +mtk_sdio_suspend ( + struct device * pDev, + pm_message_t state + ) +{ + //printk(KERN_INFO "mtk_sdio: mtk_sdio_suspend dev(0x%p)\n", pDev); + //printk(KERN_INFO "mtk_sdio: MediaTek SDIO WLAN driver\n"); + + return 0; +} + +int mtk_sdio_resume ( + struct device * pDev + ) +{ + //printk(KERN_INFO "mtk_sdio: mtk_sdio_resume dev(0x%p)\n", pDev); + + return 0; +} +#endif + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will register sdio bus to the os +* +* \param[in] pfProbe Function pointer to detect card +* \param[in] pfRemove Function pointer to remove card +* +* \return The result of registering sdio bus +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +glRegisterBus ( + probe_card pfProbe, + remove_card pfRemove + ) +{ + int ret = 0; + + ASSERT(pfProbe); + ASSERT(pfRemove); + + //printk(KERN_INFO "mtk_sdio: MediaTek SDIO WLAN driver\n"); + //printk(KERN_INFO "mtk_sdio: Copyright MediaTek Inc.\n"); + + pfWlanProbe = pfProbe; + pfWlanRemove = pfRemove; + +#if MTK_WCN_HIF_SDIO + /* register MTK sdio client */ + ret = ((mtk_wcn_hif_sdio_client_reg(&cltInfo) == HIF_SDIO_ERR_SUCCESS) ? WLAN_STATUS_SUCCESS : WLAN_STATUS_FAILURE); +#else + mtk_sdio_driver.probe = mtk_sdio_probe; + mtk_sdio_driver.remove = mtk_sdio_remove; + + mtk_sdio_driver.drv.suspend = mtk_sdio_suspend; + mtk_sdio_driver.drv.resume = mtk_sdio_resume; + + ret = (sdio_register_driver(&mtk_sdio_driver) == 0) ? WLAN_STATUS_SUCCESS : WLAN_STATUS_FAILURE; +#endif + + return ret; +} /* end of glRegisterBus() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will unregister sdio bus to the os +* +* \param[in] pfRemove Function pointer to remove card +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +glUnregisterBus( + remove_card pfRemove + ) +{ + ASSERT(pfRemove); + pfRemove(); + +#if MTK_WCN_HIF_SDIO + /* unregister MTK sdio client */ + mtk_wcn_hif_sdio_client_unreg(&cltInfo); +#else + sdio_unregister_driver(&mtk_sdio_driver); +#endif + + return; +} /* end of glUnregisterBus() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function stores hif related info, which is initialized before. +* +* \param[in] prGlueInfo Pointer to glue info structure +* \param[in] u4Cookie Pointer to UINT_32 memory base variable for _HIF_HPI +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +glSetHifInfo ( + P_GLUE_INFO_T prGlueInfo, + UINT_32 u4Cookie + ) +{ + P_GL_HIF_INFO_T prHif = NULL; + + prHif = &prGlueInfo->rHifInfo; + +#if MTK_WCN_HIF_SDIO + //prHif->prFuncInfo = ((MTK_WCN_HIF_SDIO_FUNCINFO *) u4Cookie); + prHif->prFuncInfo = prFunc; + prHif->cltCtx = *((MTK_WCN_HIF_SDIO_CLTCTX *) u4Cookie); + mtk_wcn_hif_sdio_set_drvdata(prHif->cltCtx, prGlueInfo); + +#else + prHif->func = (struct sdio_func *) u4Cookie; + + //printk(KERN_INFO DRV_NAME"prHif->func->dev = 0x%p\n", &prHif->func->dev); + //printk(KERN_INFO DRV_NAME"prHif->func->vendor = 0x%04X\n", prHif->func->vendor); + //printk(KERN_INFO DRV_NAME"prHif->func->device = 0x%04X\n", prHif->func->device); + //printk(KERN_INFO DRV_NAME"prHif->func->func = 0x%04X\n", prHif->func->num); + + sdio_set_drvdata(prHif->func, prGlueInfo); + + SET_NETDEV_DEV(prGlueInfo->prDevHandler, &prHif->func->dev); +#endif + + return; +} /* end of glSetHifInfo() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function clears hif related info. +* +* \param[in] prGlueInfo Pointer to glue info structure +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +glClearHifInfo ( + P_GLUE_INFO_T prGlueInfo + ) +{ + //P_GL_HIF_INFO_T prHif = NULL; + //ASSERT(prGlueInfo); + //prHif = &prGlueInfo->rHifInfo; + + return; +} /* end of glClearHifInfo() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Initialize bus operation and hif related information, request resources. +* +* \param[out] pvData A pointer to HIF-specific data type buffer. +* For eHPI, pvData is a pointer to UINT_32 type and stores a +* mapped base address. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +BOOL +glBusInit ( + PVOID pvData + ) +{ +#if (MTK_WCN_HIF_SDIO == 0) + int ret = 0; + struct sdio_func *func = NULL; + + ASSERT(pvData); + + func = (struct sdio_func *) pvData; + + sdio_claim_host(func); + ret = sdio_set_block_size(func, 512); + sdio_release_host(func); + + if (ret) { + //printk(KERN_INFO DRV_NAME"sdio_set_block_size 512 failed!\n"); + } + else { + //printk(KERN_INFO DRV_NAME"sdio_set_block_size 512 done!\n"); + } + + //printk(KERN_INFO DRV_NAME"param: func->cur_blksize(%d)\n", func->cur_blksize); + //printk(KERN_INFO DRV_NAME"param: func->max_blksize(%d)\n", func->max_blksize); + //printk(KERN_INFO DRV_NAME"param: func->card->host->max_blk_size(%d)\n", func->card->host->max_blk_size); + //printk(KERN_INFO DRV_NAME"param: func->card->host->max_blk_count(%d)\n", func->card->host->max_blk_count); +#endif + return TRUE; +} /* end of glBusInit() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Stop bus operation and release resources. +* +* \param[in] pvData A pointer to struct net_device. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +glBusRelease ( + PVOID pvData + ) +{ + + return; +} /* end of glBusRelease() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Setup bus interrupt operation and interrupt handler for os. +* +* \param[in] pvData A pointer to struct net_device. +* \param[in] pfnIsr A pointer to interrupt handler function. +* \param[in] pvCookie Private data for pfnIsr function. +* +* \retval WLAN_STATUS_SUCCESS if success +* NEGATIVE_VALUE if fail +*/ +/*----------------------------------------------------------------------------*/ +INT_32 +glBusSetIrq ( + PVOID pvData, + PVOID pfnIsr, + PVOID pvCookie + ) +{ + int ret = 0; + +#if (MTK_WCN_HIF_SDIO == 0) + struct net_device *prNetDevice = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_GL_HIF_INFO_T prHifInfo = NULL; + + ASSERT(pvData); + if (!pvData) { + return -1; + } + prNetDevice = (struct net_device *) pvData; + + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prNetDevice); + ASSERT(prGlueInfo); + if (!prGlueInfo) { + return -1; + } + + prHifInfo = &prGlueInfo->rHifInfo; + + sdio_claim_host(prHifInfo->func); + ret = sdio_claim_irq(prHifInfo->func, mtk_sdio_interrupt); + sdio_release_host(prHifInfo->func); +#endif + return ret; +} /* end of glBusSetIrq() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Stop bus interrupt operation and disable interrupt handling for os. +* +* \param[in] pvData A pointer to struct net_device. +* \param[in] pvCookie Private data for pfnIsr function. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +glBusFreeIrq ( + PVOID pvData, + PVOID pvCookie + ) +{ +#if (MTK_WCN_HIF_SDIO == 0) + struct net_device *prNetDevice = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_GL_HIF_INFO_T prHifInfo = NULL; + int ret = 0; + + ASSERT(pvData); + if (!pvData) { + //printk(KERN_INFO DRV_NAME"%s null pvData\n", __FUNCTION__); + return; + } + prNetDevice = (struct net_device *) pvData; + + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prNetDevice); + ASSERT(prGlueInfo); + if (!prGlueInfo) { + //printk(KERN_INFO DRV_NAME"%s no glue info\n", __FUNCTION__); + return; + } + + prHifInfo = &prGlueInfo->rHifInfo; + + sdio_claim_host(prHifInfo->func); + ret = sdio_release_irq(prHifInfo->func); + sdio_release_host(prHifInfo->func); +#endif + + return; +} /* end of glBusreeIrq() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Read a 32-bit device register +* +* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. +* \param[in] u4Register Register offset +* \param[in] pu4Value Pointer to variable used to store read value +* +* \retval TRUE operation success +* \retval FALSE operation fail +*/ +/*----------------------------------------------------------------------------*/ +BOOL +kalDevRegRead ( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_32 u4Register, + OUT PUINT_32 pu4Value + ) +{ + int ret = 0; + + ASSERT(prGlueInfo); + ASSERT(pu4Value); + +#if MTK_WCN_HIF_SDIO + ret = mtk_wcn_hif_sdio_readl(prGlueInfo->rHifInfo.cltCtx, u4Register, (PUINT32) pu4Value); +#else + if (!in_interrupt) { + sdio_claim_host(prGlueInfo->rHifInfo.func); + } + + *pu4Value = sdio_readl(prGlueInfo->rHifInfo.func, u4Register, &ret); + + if (!in_interrupt) { + sdio_release_host(prGlueInfo->rHifInfo.func); + } +#endif + + if (ret) { + DBGLOG(HAL, ERROR, ("sdio_readl() reports error: %x", ret)); + } + + return (ret) ? FALSE : TRUE; +} /* end of kalDevRegRead() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Write a 32-bit device register +* +* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. +* \param[in] u4Register Register offset +* \param[in] u4Value Value to be written +* +* \retval TRUE operation success +* \retval FALSE operation fail +*/ +/*----------------------------------------------------------------------------*/ +BOOL +kalDevRegWrite ( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_32 u4Register, + IN UINT_32 u4Value + ) +{ + int ret = 0; + + ASSERT(prGlueInfo); + +#if MTK_WCN_HIF_SDIO + ret = mtk_wcn_hif_sdio_writel(prGlueInfo->rHifInfo.cltCtx, u4Register, u4Value); +#else + if (!in_interrupt) { + sdio_claim_host(prGlueInfo->rHifInfo.func); + } + + sdio_writel(prGlueInfo->rHifInfo.func, u4Value, u4Register, &ret); + + if (!in_interrupt) { + sdio_release_host(prGlueInfo->rHifInfo.func); + } +#endif + + if (ret) { + DBGLOG(HAL, ERROR, ("sdio_writel() reports error: %x", ret)); + } + + return (ret) ? FALSE : TRUE; +} /* end of kalDevRegWrite() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Read device I/O port +* +* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. +* \param[in] u2Port I/O port offset +* \param[in] u2Len Length to be read +* \param[out] pucBuf Pointer to read buffer +* \param[in] u2ValidOutBufSize Length of the buffer valid to be accessed +* +* \retval TRUE operation success +* \retval FALSE operation fail +*/ +/*----------------------------------------------------------------------------*/ +BOOL +kalDevPortRead ( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_16 u2Port, + IN UINT_16 u2Len, + OUT PUINT_8 pucBuf, + IN UINT_16 u2ValidOutBufSize + ) +{ + P_GL_HIF_INFO_T prHifInfo = NULL; + PUINT_8 pucDst = NULL; + int count = u2Len; + int ret = 0; + int bNum = 0; + +#if (MTK_WCN_HIF_SDIO == 0) + struct sdio_func *prSdioFunc = NULL; +#endif + + #if DBG + //printk(KERN_INFO DRV_NAME"++kalDevPortRead++ buf:0x%p, port:0x%x, length:%d\n", pucBuf, u2Port, u2Len); + #endif + + ASSERT(prGlueInfo); + prHifInfo = &prGlueInfo->rHifInfo; + + ASSERT(pucBuf); + pucDst = pucBuf; + + ASSERT(u2Len <= u2ValidOutBufSize); + +#if (MTK_WCN_HIF_SDIO == 0) + prSdioFunc = prHifInfo->func; + + ASSERT(prSdioFunc->cur_blksize > 0); + + if (!in_interrupt) { + sdio_claim_host(prSdioFunc); + } + + /* Split buffer into multiple single block to workaround hifsys */ + while (count >= prSdioFunc->cur_blksize) { + count -= prSdioFunc->cur_blksize; + bNum++; + } + if (count > 0 && bNum > 0) { + bNum++; + } + + if (bNum > 0) { + ret = sdio_readsb(prSdioFunc, pucDst, u2Port, prSdioFunc->cur_blksize * bNum); + +#ifdef CONFIG_X86 + /* ENE workaround */ + { + int tmp; + sdio_writel(prSdioFunc, 0x0, SDIO_X86_WORKAROUND_WRITE_MCR, &tmp); + } +#endif + + } + else { + ret = sdio_readsb(prSdioFunc, pucDst, u2Port, count); + } + + if (!in_interrupt) { + sdio_release_host(prSdioFunc); + } +#else + + /* Split buffer into multiple single block to workaround hifsys */ + while (count >= (prGlueInfo->rHifInfo).prFuncInfo->blk_sz) { + count -= ((prGlueInfo->rHifInfo).prFuncInfo->blk_sz); + bNum++; + } + if (count > 0 && bNum > 0) { + bNum++; + } + + if (bNum > 0) { + ret = mtk_wcn_hif_sdio_read_buf(prGlueInfo->rHifInfo.cltCtx, u2Port, (PUINT32) pucDst, + ((prGlueInfo->rHifInfo).prFuncInfo->blk_sz) * bNum); + } + else { + ret = mtk_wcn_hif_sdio_read_buf(prGlueInfo->rHifInfo.cltCtx, u2Port, (PUINT32) pucDst, count); + } +#endif + + if (ret) { + DBGLOG(HAL, ERROR, ("sdio_readsb() reports error: %x", ret)); + } + + return (ret) ? FALSE : TRUE; +} /* end of kalDevPortRead() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Write device I/O port +* +* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. +* \param[in] u2Port I/O port offset +* \param[in] u2Len Length to be write +* \param[in] pucBuf Pointer to write buffer +* \param[in] u2ValidInBufSize Length of the buffer valid to be accessed +* +* \retval TRUE operation success +* \retval FALSE operation fail +*/ +/*----------------------------------------------------------------------------*/ +BOOL +kalDevPortWrite ( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_16 u2Port, + IN UINT_16 u2Len, + IN PUINT_8 pucBuf, + IN UINT_16 u2ValidInBufSize + ) +{ + P_GL_HIF_INFO_T prHifInfo = NULL; + PUINT_8 pucSrc = NULL; + int count = u2Len; + int ret = 0; + int bNum = 0; + +#if (MTK_WCN_HIF_SDIO == 0) + struct sdio_func *prSdioFunc = NULL; +#endif + + #if DBG + //printk(KERN_INFO DRV_NAME"++kalDevPortWrite++ buf:0x%p, port:0x%x, length:%d\n", pucBuf, u2Port, u2Len); + #endif + + ASSERT(prGlueInfo); + prHifInfo = &prGlueInfo->rHifInfo; + + ASSERT(pucBuf); + pucSrc = pucBuf; + + ASSERT(u2Len <= u2ValidInBufSize); + +#if (MTK_WCN_HIF_SDIO == 0) + prSdioFunc = prHifInfo->func; + ASSERT(prSdioFunc->cur_blksize > 0); + + if (!in_interrupt) { + sdio_claim_host(prSdioFunc); + } + + /* Split buffer into multiple single block to workaround hifsys */ + while (count >= prSdioFunc->cur_blksize) { + count -= prSdioFunc->cur_blksize; + bNum++; + } + if (count > 0 && bNum > 0) { + bNum++; + } + + if (bNum > 0) { // block mode + ret = sdio_writesb(prSdioFunc, u2Port, pucSrc, prSdioFunc->cur_blksize * bNum); + +#ifdef CONFIG_X86 + /* ENE workaround */ + { + int tmp; + sdio_writel(prSdioFunc, 0x0, SDIO_X86_WORKAROUND_WRITE_MCR, &tmp); + } +#endif + + } + else { // byte mode + + ret = sdio_writesb(prSdioFunc, u2Port, pucSrc, count); + } + + if (!in_interrupt) { + sdio_release_host(prSdioFunc); + } +#else + /* Split buffer into multiple single block to workaround hifsys */ + while (count >= ((prGlueInfo->rHifInfo).prFuncInfo->blk_sz)) { + count -= ((prGlueInfo->rHifInfo).prFuncInfo->blk_sz); + bNum++; + } + if (count > 0 && bNum > 0) { + bNum++; + } + + if (bNum > 0) { // block mode + ret = mtk_wcn_hif_sdio_write_buf(prGlueInfo->rHifInfo.cltCtx, u2Port, (PUINT32) pucSrc, + ((prGlueInfo->rHifInfo).prFuncInfo->blk_sz) * bNum); + } + else { // byte mode + ret = mtk_wcn_hif_sdio_write_buf(prGlueInfo->rHifInfo.cltCtx, u2Port, (PUINT32) pucSrc, count); + } +#endif + + if (ret) { + DBGLOG(HAL, ERROR, ("sdio_writesb() reports error: %x", ret)); + } + + return (ret) ? FALSE : TRUE; +} /* end of kalDevPortWrite() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Write device I/O port in byte with CMD52 +* +* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. +* \param[in] u4Addr I/O port offset +* \param[in] ucData Single byte of data to be written +* +* \retval TRUE operation success +* \retval FALSE operation fail +*/ +/*----------------------------------------------------------------------------*/ +BOOL +kalDevWriteWithSdioCmd52 ( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_32 u4Addr, + IN UINT_8 ucData + ) +{ + int ret = 0; + +#if (MTK_WCN_HIF_SDIO == 0) + if (!in_interrupt) { + sdio_claim_host(prGlueInfo->rHifInfo.func); + } + + sdio_writeb(prGlueInfo->rHifInfo.func, ucData, u4Addr, &ret); + + if (!in_interrupt) { + sdio_release_host(prGlueInfo->rHifInfo.func); + } +#else + ret = mtk_wcn_hif_sdio_writeb(prGlueInfo->rHifInfo.cltCtx, u4Addr, ucData); +#endif + + if (ret) { + DBGLOG(HAL, ERROR, ("sdio_writeb() reports error: %x", ret)); + } + + return (ret) ? FALSE : TRUE; + +} /* end of kalDevWriteWithSdioCmd52() */ + + +VOID +glSetPowerState ( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_32 ePowerMode + ) +{ + return; +} + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/x86.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/x86.c new file mode 100755 index 000000000000..eef362e4ffc3 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/hif/sdio/x86.c @@ -0,0 +1,68 @@ +/****************************************************************************** +*[File] mt6516-evb.c +*[Version] v1.0 +*[Revision Date] 2010-03-01 +*[Author] +*[Description] +* dummy file for build system +*[Copyright] +* Copyright (C) 2010 MediaTek Incorporation. All Rights Reserved. +******************************************************************************/ + + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: mt6516-evb.c $ + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 04 19 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * remove debug message + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port +** +*/ diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_kal.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_kal.h new file mode 100755 index 000000000000..87360fb842b6 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_kal.h @@ -0,0 +1,1988 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/os/linux/include/gl_kal.h#1 $ +*/ + +/*! \file gl_kal.h + \brief Declaration of KAL functions - kal*() which is provided by GLUE Layer. + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: gl_kal.h $ + * + * 02 06 2012 wh.su + * [ALPS00109161] [Need Patch] [Volunteer Patch] [Wi-Fi] Support the set tx power driver cmd + * Adding the AP mode channel query filter. + * + * 01 20 2012 cp.wu + * [ALPS00096191] [MT6620 Wi-Fi][Driver][Firmware] Porting to ALPS4.0_DEV branch + * sync to up-to-date changes including: + * 1. BOW bugfix + * 2. XLOG + * + * 01 02 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Adding the proto type function for set_int set_tx_power and get int get_ch_list. + * + * 12 13 2011 cm.chang + * [WCXRP00001136] [All Wi-Fi][Driver] Add wake lock for pending timer + * Add wake lock if timer timeout value is smaller than 5 seconds + * + * 11 24 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * adjust the code for Non-DBG and no XLOG. + * + * 11 22 2011 cp.wu + * [WCXRP00001120] [MT6620 Wi-Fi][Driver] Modify roaming to AIS state transition from synchronous to asynchronous approach to avoid incomplete state termination + * 1. change RDD related compile option brace position. + * 2. when roaming is triggered, ask AIS to transit immediately only when AIS is in Normal TR state without join timeout timer ticking + * 3. otherwise, insert AIS_REQUEST into pending request queue + * + * 11 11 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * modify the xlog related code. + * + * 11 10 2011 cp.wu + * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer + * 1. eliminaite direct calls to printk in porting layer. + * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. + * + * 11 10 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Modify the QM xlog level and remove LOG_FUNC. + * + * 11 10 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Using the new XLOG define for dum Memory. + * + * 11 08 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Add xlog function. + * + * 11 08 2011 cm.chang + * NULL + * Add RLM and CNM debug message for XLOG + * + * 11 08 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters, eCurPsProf, for PS. + * + * 11 04 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters and periodically dump counters for Xlog debugging. + * + * 11 03 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Add dumpMemory8 at XLOG support. + * + * 11 02 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Add XLOG related code and define. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 04 12 2011 cp.wu + * [WCXRP00000635] [MT6620 Wi-Fi][Driver] Clear pending security frames when QM clear pending data frames for dedicated network type + * include link.h for linux's port. + * + * 04 12 2011 cp.wu + * [WCXRP00000635] [MT6620 Wi-Fi][Driver] Clear pending security frames when QM clear pending data frames for dedicated network type + * clear pending security frames for dedicated network type when BSS is being deactivated/disconnected + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 16 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage after system running for a long period + * 1. pre-allocate physical continuous buffer while module is being loaded + * 2. use pre-allocated physical continuous buffer for TX/RX DMA transfer + * + * The windows part remained the same as before, but added similiar APIs to hide the difference. + * + * 03 10 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add BOW table. + * + * 03 07 2011 terry.wu + * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message + * Toggle non-standard debug messages to comments. + * + * 03 06 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Sync BOW Driver to latest person development branch version.. + * + * 03 02 2011 cp.wu + * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right after connection is built. + * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. + * + * 02 24 2011 cp.wu + * [WCXRP00000490] [MT6620 Wi-Fi][Driver][Win32] modify kalMsleep() implementation because NdisMSleep() won't sleep long enough for specified interval such as 500ms + * modify cnm_timer and hem_mbox APIs to be thread safe to ease invoking restrictions + * + * 01 12 2011 cp.wu + * [WCXRP00000357] [MT6620 Wi-Fi][Driver][Bluetooth over Wi-Fi] add another net device interface for BT AMP + * implementation of separate BT_OVER_WIFI data path. + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease physically continous memory demands + * separate kalMemAlloc() into virtually-continous and physically-continous type to ease slab system pressure + * + * 12 31 2010 cp.wu + * [WCXRP00000335] [MT6620 Wi-Fi][Driver] change to use milliseconds sleep instead of delay to avoid blocking to system scheduling + * change to use msleep() and shorten waiting interval to reduce blocking to other task while Wi-Fi driver is being loaded + * + * 12 31 2010 jeffrey.chang + * [WCXRP00000332] [MT6620 Wi-Fi][Driver] add kal sleep function for delay which use blocking call + * modify the implementation of kalDelay to msleep + * + * 12 22 2010 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service Discovery + * 1. header file restructure for more clear module isolation + * 2. add function interface definition for implementing Service Discovery callbacks + * + * 11 30 2010 yuche.tsai + * NULL + * Invitation & Provision Discovery Indication. + * + * 11 26 2010 cp.wu + * [WCXRP00000209] [MT6620 Wi-Fi][Driver] Modify NVRAM checking mechanism to warning only with necessary data field checking + * 1. NVRAM error is now treated as warning only, thus normal operation is still available but extra scan result used to indicate user is attached + * 2. DPD and TX-PWR are needed fields from now on, if these 2 fields are not availble then warning message is shown + * + * 11 08 2010 cp.wu + * [WCXRP00000166] [MT6620 Wi-Fi][Driver] use SDIO CMD52 for enabling/disabling interrupt to reduce transaction period + * change to use CMD52 for enabling/disabling interrupt to reduce SDIO transaction time + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * 1) add NVRAM access API + * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) + * 3) add OID implementation for NVRAM read/write service + * + * 10 04 2010 wh.su + * [WCXRP00000081] [MT6620][Driver] Fix the compiling error at WinXP while enable P2P + * add a kal function for set cipher. + * + * 10 04 2010 wh.su + * [WCXRP00000081] [MT6620][Driver] Fix the compiling error at WinXP while enable P2P + * fixed compiling error while enable p2p. + * + * 09 28 2010 wh.su + * NULL + * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. + * + * 09 21 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS associated + * Do a complete reset with STA-REC null checking for RF test re-entry + * + * 09 21 2010 kevin.huang + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * Eliminate Linux Compile Warning + * + * 09 10 2010 wh.su + * NULL + * fixed the compiling error at win XP. + * + * 09 07 2010 wh.su + * NULL + * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. + * + * 09 06 2010 wh.su + * NULL + * let the p2p can set the privacy bit at beacon and rsn ie at assoc req at key handshake state. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 06 2010 cp.wu + * NULL + * driver hook modifications corresponding to ioctl interface change. + * + * 08 03 2010 cp.wu + * NULL + * [Wi-Fi Direct Driver Hook] change event indication API to be consistent with supplicant + * + * 08 03 2010 cp.wu + * NULL + * [Wi-Fi Direct] add framework for driver hooks + * + * 08 02 2010 jeffrey.chang + * NULL + * modify kalSetEvent declaration + * + * 07 29 2010 cp.wu + * NULL + * simplify post-handling after TX_DONE interrupt is handled. + * + * 07 23 2010 cp.wu + * + * 1) re-enable AIS-FSM beacon timeout handling. + * 2) scan done API revised + * + * 07 23 2010 jeffrey.chang + * + * fix kal header file + * + * 07 22 2010 jeffrey.chang + * + * use different spin lock for security frame + * + * 07 22 2010 jeffrey.chang + * + * add new spinlock + * + * 07 19 2010 jeffrey.chang + * + * add kal api for scanning done + * + * 07 19 2010 jeffrey.chang + * + * modify cmd/data path for new design + * + * 07 19 2010 jeffrey.chang + * + * add new kal api + * + * 07 19 2010 jeffrey.chang + * + * Linux port modification + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * change MAC address updating logic. + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * gl_kal merged + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add basic handling framework for wireless extension ioctls. + * + * 05 11 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add ioctl for controlling p2p scan phase parameters + * + * 05 10 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * fill network type field while doing frame identification. + * + * 05 10 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * implement basic wi-fi direct framework + * + * 05 07 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add basic framework for implementating P2P driver hook. + * + * 05 07 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * modify kalMemAlloc method + * + * 04 28 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * change prefix for data structure used to communicate with 802.11 PAL + * to avoid ambiguous naming with firmware interface + * + * 04 27 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add multiple physical link support + * + * 04 27 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * follow Linux's firmware framework, and remove unused kal API + * + * 04 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * when acquiring driver-own, wait for up to 8 seconds. + * + * 04 22 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * + * 1) modify rx path code for supporting Wi-Fi direct + * 2) modify config.h since Linux dont need to consider retaining packet + * + * 04 21 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * add for private ioctl support + * + * 04 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * don't need SPIN_LOCK_PWR_CTRL anymore, it will raise IRQL + * * and cause SdBusSubmitRequest running at DISPATCH_LEVEL as well. + * + * 04 14 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * information buffer for query oid/ioctl is now buffered in prCmdInfo + * * * * * * * * instead of glue-layer variable to improve multiple oid/ioctl capability + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * * * * * * * * * * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose + * + * 04 09 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * 1) add spinlock + * * * 2) add KAPI for handling association info + * + * 04 09 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * adding firmware download KAPI + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * finish non-glue layer access to glue variables + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * accessing to firmware load/start address, and access to OID handling information + * * * * are now handled in glue layer + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * rWlanInfo should be placed at adapter rather than glue due to most operations + * * * * * * * * * are done in adapter layer. + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access to prGlueInfo->eParamMediaStateIndicated from non-glue layer + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add KAL API: kalFlushPendingTxPackets(), and take use of the API + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access to prGlueInfo->rWlanInfo.eLinkAttr.ucMediaStreamMode from non-glue layer. + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * improve none-glue code portability + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) for some OID, never do timeout expiration + * * * * 2) add 2 kal API for later integration + * + * 03 30 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * emulate NDIS Pending OID facility + * + * 03 26 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * [WPD00003826] Initial import for Linux port + * adding firmware download KAPI + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port +** \main\maintrunk.MT5921\41 2009-09-28 20:19:23 GMT mtk01090 +** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. +** \main\maintrunk.MT5921\40 2009-08-18 22:57:09 GMT mtk01090 +** Add Linux SDIO (with mmc core) support. +** Add Linux 2.6.21, 2.6.25, 2.6.26. +** Fix compile warning in Linux. +** \main\maintrunk.MT5921\39 2009-06-23 23:19:15 GMT mtk01090 +** Add build option BUILD_USE_EEPROM and compile option CFG_SUPPORT_EXT_CONFIG for NVRAM support +** \main\maintrunk.MT5921\38 2009-02-09 14:03:17 GMT mtk01090 +** Add KAL function kalDevSetPowerState(). It is not implemented yet. Only add an empty macro. +** +** \main\maintrunk.MT5921\37 2009-01-22 13:05:59 GMT mtk01088 +** new defeine to got 1x value at packet reserved field +** \main\maintrunk.MT5921\36 2008-12-08 16:15:02 GMT mtk01461 +** Add kalQueryValidBufferLength() macro +** \main\maintrunk.MT5921\35 2008-11-13 20:33:15 GMT mtk01104 +** Remove lint warning +** \main\maintrunk.MT5921\34 2008-10-22 11:05:52 GMT mtk01461 +** Remove unused macro +** \main\maintrunk.MT5921\33 2008-10-16 15:48:17 GMT mtk01461 +** Update driver to fix lint warning +** \main\maintrunk.MT5921\32 2008-09-02 11:50:51 GMT mtk01461 +** SPIN_LOCK_SDIO_DDK_TX_QUE +** \main\maintrunk.MT5921\31 2008-08-29 15:58:30 GMT mtk01088 +** remove non-used function for code refine +** \main\maintrunk.MT5921\30 2008-08-21 00:33:29 GMT mtk01461 +** Update for Driver Review +** \main\maintrunk.MT5921\29 2008-06-19 13:29:14 GMT mtk01425 +** 1. Add declaration of SPIN_LOCK_SDIO_DDK_TX_QUE and SPIN_LOCK_SDIO_DDK_RX_QUE +** \main\maintrunk.MT5921\28 2008-05-30 20:27:34 GMT mtk01461 +** Rename KAL function +** \main\maintrunk.MT5921\27 2008-05-30 14:42:05 GMT mtk01461 +** Remove WMM Assoc Flag in KAL +** \main\maintrunk.MT5921\26 2008-05-29 14:15:18 GMT mtk01084 +** remove un-used function +** \main\maintrunk.MT5921\25 2008-04-23 14:02:20 GMT mtk01084 +** modify KAL port access function prototype +** \main\maintrunk.MT5921\24 2008-04-17 23:06:41 GMT mtk01461 +** Add iwpriv support for AdHocMode setting +** \main\maintrunk.MT5921\23 2008-04-08 15:38:50 GMT mtk01084 +** add KAL function to setting pattern search function enable/ disable +** \main\maintrunk.MT5921\22 2008-03-26 15:34:48 GMT mtk01461 +** Add update MAC address func +** \main\maintrunk.MT5921\21 2008-03-18 15:56:15 GMT mtk01084 +** update ENUM_NIC_INITIAL_PARAM_E +** \main\maintrunk.MT5921\20 2008-03-18 11:49:28 GMT mtk01084 +** update function for initial value access +** \main\maintrunk.MT5921\19 2008-03-18 10:21:31 GMT mtk01088 +** use kal update associate request at linux +** \main\maintrunk.MT5921\18 2008-03-14 18:03:41 GMT mtk01084 +** refine register and port access function +** \main\maintrunk.MT5921\17 2008-03-11 14:51:02 GMT mtk01461 +** Add copy_to(from)_user macro +** \main\maintrunk.MT5921\16 2008-03-06 23:42:21 GMT mtk01385 +** 1. add Query Registry Mac address function. +** \main\maintrunk.MT5921\15 2008-02-26 09:48:04 GMT mtk01084 +** modify KAL set network address/ checksum offload part +** \main\maintrunk.MT5921\14 2008-01-09 17:54:58 GMT mtk01084 +** Modify the argument of kalQueryPacketInfo +** \main\maintrunk.MT5921\13 2007-11-29 02:05:20 GMT mtk01461 +** Fix Windows RX multiple packet retain problem +** \main\maintrunk.MT5921\12 2007-11-26 19:43:45 GMT mtk01461 +** Add OS_TIMESTAMP macro +** +** \main\maintrunk.MT5921\11 2007-11-09 16:36:15 GMT mtk01425 +** 1. Modify for CSUM offloading with Tx Fragment +** \main\maintrunk.MT5921\10 2007-11-07 18:38:37 GMT mtk01461 +** Add Tx Fragmentation Support +** \main\maintrunk.MT5921\9 2007-11-06 19:36:50 GMT mtk01088 +** add the WPS related code +** \main\maintrunk.MT5921\8 2007-11-02 01:03:57 GMT mtk01461 +** Unify TX Path for Normal and IBSS Power Save + IBSS neighbor learning +** Revision 1.4 2007/07/05 07:25:33 MTK01461 +** Add Linux initial code, modify doc, add 11BB, RF init code +** +** Revision 1.3 2007/06/27 02:18:50 MTK01461 +** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API +** +** Revision 1.2 2007/06/25 06:16:23 MTK01461 +** Update illustrations, gl_init.c, gl_kal.c, gl_kal.h, gl_os.h and RX API +** +*/ + + +#ifndef _GL_KAL_H +#define _GL_KAL_H + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "config.h" +#include "gl_typedef.h" +#include "gl_os.h" +#include "link.h" +#include "nic/mac.h" +#include "nic/wlan_def.h" +#include "wlan_lib.h" +#include "wlan_oid.h" +#include "gl_wext_priv.h" + + +#if CFG_ENABLE_BT_OVER_WIFI + #include "nic/bow.h" +#endif + +#if DBG +extern int allocatedMemSize; +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +//#define USEC_PER_MSEC (1000) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_SPIN_LOCK_CATEGORY_E { + SPIN_LOCK_FSM = 0, + + /* FIX ME */ + SPIN_LOCK_RX_QUE, + SPIN_LOCK_TX_QUE, + SPIN_LOCK_CMD_QUE, + SPIN_LOCK_TX_RESOURCE, + SPIN_LOCK_CMD_RESOURCE, + SPIN_LOCK_QM_TX_QUEUE, + SPIN_LOCK_CMD_PENDING, + SPIN_LOCK_CMD_SEQ_NUM, + SPIN_LOCK_TX_MSDU_INFO_LIST, + SPIN_LOCK_TXING_MGMT_LIST, + SPIN_LOCK_TX_SEQ_NUM, + SPIN_LOCK_TX_COUNT, + SPIN_LOCK_TXS_COUNT, + /* end */ + SPIN_LOCK_TX, + SPIN_LOCK_IO_REQ, + SPIN_LOCK_INT, + + SPIN_LOCK_MGT_BUF, + SPIN_LOCK_MSG_BUF, + SPIN_LOCK_STA_REC, + + SPIN_LOCK_MAILBOX, + SPIN_LOCK_TIMER, + + SPIN_LOCK_BOW_TABLE, + + SPIN_LOCK_EHPI_BUS, /* only for EHPI */ + SPIN_LOCK_NUM +} ENUM_SPIN_LOCK_CATEGORY_E; + +/* event for assoc infomation update */ +typedef struct _EVENT_ASSOC_INFO { + UINT_8 ucAssocReq; /* 1 for assoc req, 0 for assoc rsp */ + UINT_8 ucReassoc; /* 0 for assoc, 1 for reassoc */ + UINT_16 u2Length; + PUINT_8 pucIe; +} EVENT_ASSOC_INFO, *P_EVENT_ASSOC_INFO; + +typedef enum _ENUM_KAL_NETWORK_TYPE_INDEX_T { + KAL_NETWORK_TYPE_AIS_INDEX = 0, +#if CFG_ENABLE_WIFI_DIRECT + KAL_NETWORK_TYPE_P2P_INDEX, +#endif +#if CFG_ENABLE_BT_OVER_WIFI + KAL_NETWORK_TYPE_BOW_INDEX, +#endif + KAL_NETWORK_TYPE_INDEX_NUM +} ENUM_KAL_NETWORK_TYPE_INDEX_T; + +typedef enum _ENUM_KAL_MEM_ALLOCATION_TYPE_E { + PHY_MEM_TYPE, /* physically continuous */ + VIR_MEM_TYPE, /* virtually continous */ + MEM_TYPE_NUM +} ENUM_KAL_MEM_ALLOCATION_TYPE; + +#if CONFIG_ANDROID /* Defined in Android kernel source */ +typedef struct wake_lock KAL_WAKE_LOCK_T, *P_KAL_WAKE_LOCK_T; +#else +typedef UINT_32 KAL_WAKE_LOCK_T, *P_KAL_WAKE_LOCK_T; +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Macros of SPIN LOCK operations for using in Driver Layer */ +/*----------------------------------------------------------------------------*/ +#define KAL_SPIN_LOCK_DECLARATION() UINT_32 __u4Flags + +#define KAL_ACQUIRE_SPIN_LOCK(_prAdapter, _rLockCategory) \ + kalAcquireSpinLock(((P_ADAPTER_T)_prAdapter)->prGlueInfo, _rLockCategory, &__u4Flags) + +#define KAL_RELEASE_SPIN_LOCK(_prAdapter, _rLockCategory) \ + kalReleaseSpinLock(((P_ADAPTER_T)_prAdapter)->prGlueInfo, _rLockCategory, __u4Flags) + +/*----------------------------------------------------------------------------*/ +/* Macros for accessing Reserved Fields of native packet */ +/*----------------------------------------------------------------------------*/ +#define KAL_GET_PKT_QUEUE_ENTRY(_p) GLUE_GET_PKT_QUEUE_ENTRY(_p) +#define KAL_GET_PKT_DESCRIPTOR(_prQueueEntry) GLUE_GET_PKT_DESCRIPTOR(_prQueueEntry) +#define KAL_GET_PKT_TID(_p) GLUE_GET_PKT_TID(_p) +#define KAL_GET_PKT_IS1X(_p) GLUE_GET_PKT_IS1X(_p) +#define KAL_GET_PKT_HEADER_LEN(_p) GLUE_GET_PKT_HEADER_LEN(_p) +#define KAL_GET_PKT_PAYLOAD_LEN(_p) GLUE_GET_PKT_PAYLOAD_LEN(_p) +#define KAL_GET_PKT_ARRIVAL_TIME(_p) GLUE_GET_PKT_ARRIVAL_TIME(_p) + +#define kalUpdateReAssocRspInfo(prGlueInfo, pucFrameBody, u4FrameBodyLen) + +/*----------------------------------------------------------------------------*/ +/* Macros of wake_lock operations for using in Driver Layer */ +/*----------------------------------------------------------------------------*/ +#if CONFIG_ANDROID /* Defined in Android kernel source */ +#define KAL_WAKE_LOCK_INIT(_prAdapter, _prWakeLock, _pcName) \ + wake_lock_init(_prWakeLock, WAKE_LOCK_SUSPEND, _pcName) + +#define KAL_WAKE_LOCK_DESTROY(_prAdapter, _prWakeLock) \ + wake_lock_destroy(_prWakeLock) + +#define KAL_WAKE_LOCK(_prAdapter, _prWakeLock) \ + wake_lock(_prWakeLock) + +#define KAL_WAKE_LOCK_TIMEOUT(_prAdapter, _prWakeLock, _u4Timeout) \ + wake_lock_timeout(_prWakeLock, _u4Timeout) + +#define KAL_WAKE_UNLOCK(_prAdapter, _prWakeLock) \ + wake_unlock(_prWakeLock) + +#else +#define KAL_WAKE_LOCK_INIT(_prAdapter, _prWakeLock, _pcName) +#define KAL_WAKE_LOCK_DESTROY(_prAdapter, _prWakeLock) +#define KAL_WAKE_LOCK(_prAdapter, _prWakeLock) +#define KAL_WAKE_LOCK_TIMEOUT(_prAdapter, _prWakeLock, _u4Timeout) +#define KAL_WAKE_UNLOCK(_prAdapter, _prWakeLock) +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Cache memory allocation +* +* \param[in] u4Size Required memory size. +* \param[in] eMemType Memory allocation type +* +* \return Pointer to allocated memory +* or NULL +*/ +/*----------------------------------------------------------------------------*/ +#if DBG +#define kalMemAlloc(u4Size, eMemType) ({ \ + void *pvAddr; \ + if(eMemType == PHY_MEM_TYPE) { \ + pvAddr = kmalloc(u4Size, GFP_KERNEL); \ + } \ + else { \ + pvAddr = vmalloc(u4Size); \ + } \ + if (pvAddr) { \ + allocatedMemSize += u4Size; \ + printk(KERN_INFO DRV_NAME "0x%p(%ld) allocated (%s:%s)\n", \ + pvAddr, (UINT_32)u4Size, __FILE__, __FUNCTION__); \ + } \ + pvAddr; \ + }) +#else +#define kalMemAlloc(u4Size, eMemType) ({ \ + void *pvAddr; \ + if(eMemType == PHY_MEM_TYPE) { \ + pvAddr = kmalloc(u4Size, GFP_KERNEL); \ + } \ + else { \ + pvAddr = vmalloc(u4Size); \ + } \ + pvAddr; \ + }) +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Free allocated cache memory +* +* \param[in] pvAddr Required memory size. +* \param[in] eMemType Memory allocation type +* \param[in] u4Size Allocated memory size. +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +#if DBG +#define kalMemFree(pvAddr, eMemType, u4Size) \ + { \ + if (pvAddr) { \ + allocatedMemSize -= u4Size; \ + printk(KERN_INFO DRV_NAME "0x%p(%ld) freed (%s:%s)\n", \ + pvAddr, (UINT_32)u4Size, __FILE__, __FUNCTION__); \ + } \ + if(eMemType == PHY_MEM_TYPE) { \ + kfree(pvAddr); \ + } \ + else { \ + vfree(pvAddr); \ + } \ + } +#else +#define kalMemFree(pvAddr, eMemType, u4Size) \ + { \ + if(eMemType == PHY_MEM_TYPE) { \ + kfree(pvAddr); \ + } \ + else { \ + vfree(pvAddr); \ + } \ + } +#endif + +#define kalUdelay(u4USec) udelay(u4USec) + +#define kalMdelay(u4MSec) mdelay(u4MSec) +#define kalMsleep(u4MSec) msleep(u4MSec) + +/* Copy memory from user space to kernel space */ +#define kalMemCopyFromUser(_pvTo, _pvFrom, _u4N) copy_from_user(_pvTo, _pvFrom, _u4N) + +/* Copy memory from kernel space to user space */ +#define kalMemCopyToUser(_pvTo, _pvFrom, _u4N) copy_to_user(_pvTo, _pvFrom, _u4N) + +/* Copy memory block with specific size */ +#define kalMemCopy(pvDst, pvSrc, u4Size) memcpy(pvDst, pvSrc, u4Size) + +/* Set memory block with specific pattern */ +#define kalMemSet(pvAddr, ucPattern, u4Size) memset(pvAddr, ucPattern, u4Size) + +/* Compare two memory block with specific length. + * Return zero if they are the same. + */ +#define kalMemCmp(pvAddr1, pvAddr2, u4Size) memcmp(pvAddr1, pvAddr2, u4Size) + +/* Zero specific memory block */ +#define kalMemZero(pvAddr, u4Size) memset(pvAddr, 0, u4Size) + +/* defined for wince sdio driver only */ +#if defined(_HIF_SDIO) +#define kalDevSetPowerState(prGlueInfo, ePowerMode) glSetPowerState(prGlueInfo, ePowerMode) +#else +#define kalDevSetPowerState(prGlueInfo, ePowerMode) +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Notify OS with SendComplete event of the specific packet. Linux should +* free packets here. +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* \param[in] pvPacket Pointer of Packet Handle +* \param[in] status Status Code for OS upper layer +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +#define kalSendComplete(prGlueInfo, pvPacket, status) \ + kalSendCompleteAndAwakeQueue(prGlueInfo, pvPacket) + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is used to locate the starting address of incoming ethernet +* frame for skb. +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* \param[in] pvPacket Pointer of Packet Handle +* +* \return starting address of ethernet frame buffer. +*/ +/*----------------------------------------------------------------------------*/ +#define kalQueryBufferPointer(prGlueInfo, pvPacket) \ + ((PUINT_8)((struct sk_buff *)pvPacket)->data) + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is used to query the length of valid buffer which is accessible during +* port read/write. +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* \param[in] pvPacket Pointer of Packet Handle +* +* \return starting address of ethernet frame buffer. +*/ +/*----------------------------------------------------------------------------*/ +#define kalQueryValidBufferLength(prGlueInfo, pvPacket) \ + ((UINT_32)((struct sk_buff *)pvPacket)->end - \ + (UINT_32)((struct sk_buff *)pvPacket)->data) + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is used to copy the entire frame from skb to the destination +* address in the input parameter. +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* \param[in] pvPacket Pointer of Packet Handle +* \param[in] pucDestBuffer Destination Address +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +#define kalCopyFrame(prGlueInfo, pvPacket, pucDestBuffer) \ + {struct sk_buff *skb = (struct sk_buff *)pvPacket; \ + memcpy(pucDestBuffer, skb->data, skb->len);} + +#define kalGetTimeTick() jiffies_to_msecs(jiffies) + +#define kalPrint printk + +#if CFG_SUPPORT_XLOG +#define XLOG_TAG "wlan" + +#define XLOG_FUNC(__LEVEL, __FMT...)\ + if (__LEVEL == ANDROID_LOG_ERROR) {\ + xlog_printk(ANDROID_LOG_ERROR, XLOG_TAG, ##__FMT);\ + } \ + else if (__LEVEL == ANDROID_LOG_WARN) {\ + xlog_printk(ANDROID_LOG_WARN, XLOG_TAG, ##__FMT);\ + } \ + else if (__LEVEL == ANDROID_LOG_INFO) {\ + xlog_printk(ANDROID_LOG_INFO, XLOG_TAG, ##__FMT);\ + } \ + else if (__LEVEL == ANDROID_LOG_DEBUG) {\ + xlog_printk(ANDROID_LOG_DEBUG, XLOG_TAG, ##__FMT);\ + } \ + else if (__LEVEL == ANDROID_LOG_VERBOSE) {\ + xlog_printk(ANDROID_LOG_VERBOSE, XLOG_TAG, ##__FMT);\ + } + +#define AIS_ERROR_LOGFUNC(_Fmt...) +#define AIS_WARN_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_WARN, XLOG_TAG, _Fmt) +#define AIS_INFO_LOGFUNC(_Fmt...) +#define AIS_STATE_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_INFO, XLOG_TAG, _Fmt) +#define AIS_EVENT_LOGFUNC(_Fmt...) +#define AIS_TRACE_LOGFUNC(_Fmt...) +#define AIS_LOUD_LOGFUNC(_Fmt...) +#define AIS_TEMP_LOGFUNC(_Fmt...) + +#define AIS_ERROR_LOGDUMP8(x, y) +#define AIS_WARN_LOGDUMP8(x, y) +#define AIS_INFO_LOGDUMP8(x, y) +#define AIS_STATE_LOGDUMP8(x, y) +#define AIS_EVENT_LOGDUMP8(x, y) +#define AIS_TRACE_LOGDUMP8(x, y) +#define AIS_LOUD_LOGDUMP8(x, y) +#define AIS_TEMP_LOGDUMP8(x, y) + +#define INTR_ERROR_LOGFUNC(_Fmt...) +#define INTR_WARN_LOGFUNC(_Fmt...) +#define INTR_INFO_LOGFUNC(_Fmt...) +#define INTR_STATE_LOGFUNC(_Fmt...) +#define INTR_EVENT_LOGFUNC(_Fmt...) +#define INTR_TRACE_LOGFUNC(_Fmt...) +#define INTR_LOUD_LOGFUNC(_Fmt...) +#define INTR_TEMP_LOGFUNC(_Fmt...) + +#define INTR_ERROR_LOGDUMP8(x, y) +#define INTR_WARN_LOGDUMP8(x, y) +#define INTR_INFO_LOGDUMP8(x, y) +#define INTR_STATE_LOGDUMP8(x, y) +#define INTR_EVENT_LOGDUMP8(x, y) +#define INTR_TRACE_LOGDUMP8(x, y) +#define INTR_LOUD_LOGDUMP8(x, y) +#define INTR_TEMP_LOGDUMP8(x, y) + +#define INIT_ERROR_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_ERROR, XLOG_TAG, _Fmt) +#define INIT_WARN_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_WARN, XLOG_TAG, _Fmt) +#define INIT_INFO_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_INFO, XLOG_TAG, _Fmt) +#define INIT_STATE_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_INFO, XLOG_TAG, _Fmt) +#define INIT_EVENT_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_INFO, XLOG_TAG, _Fmt) +#define INIT_TRACE_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_DEBUG, XLOG_TAG, _Fmt) +#define INIT_LOUD_LOGFUNC(_Fmt...) +#define INIT_TEMP_LOGFUNC(_Fmt...) + +#define INIT_ERROR_LOGDUMP8(x, y) +#define INIT_WARN_LOGDUMP8(x, y) +#define INIT_INFO_LOGDUMP8(x, y) +#define INIT_STATE_LOGDUMP8(x, y) +#define INIT_EVENT_LOGDUMP8(x, y) +#define INIT_TRACE_LOGDUMP8(x, y) +#define INIT_LOUD_LOGDUMP8(x, y) +#define INIT_TEMP_LOGDUMP8(x, y) + +#define AAA_ERROR_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_ERROR, XLOG_TAG, _Fmt) +#define AAA_WARN_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_WARN, XLOG_TAG, _Fmt) +#define AAA_INFO_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_INFO, XLOG_TAG, _Fmt) +#define AAA_STATE_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_INFO, XLOG_TAG, _Fmt) +#define AAA_EVENT_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_INFO, XLOG_TAG, _Fmt) +#define AAA_TRACE_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_DEBUG, XLOG_TAG, _Fmt) +#define AAA_LOUD_LOGFUNC(_Fmt...) +#define AAA_TEMP_LOGFUNC(_Fmt...) + +#define AAA_ERROR_LOGDUMP8(x, y) +#define AAA_WARN_LOGDUMP8(x, y) +#define AAA_INFO_LOGDUMP8(x, y) +#define AAA_STATE_LOGDUMP8(x, y) +#define AAA_EVENT_LOGDUMP8(x, y) +#define AAA_TRACE_LOGDUMP8(x, y) +#define AAA_LOUD_LOGDUMP8(x, y) +#define AAA_TEMP_LOGDUMP8(x, y) + +#define ROAMING_ERROR_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_ERROR, XLOG_TAG, _Fmt) +#define ROAMING_WARN_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_WARN, XLOG_TAG, _Fmt) +#define ROAMING_INFO_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_INFO, XLOG_TAG, _Fmt) +#define ROAMING_STATE_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_INFO, XLOG_TAG, _Fmt) +#define ROAMING_EVENT_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_INFO, XLOG_TAG, _Fmt) +#define ROAMING_TRACE_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_DEBUG, XLOG_TAG, _Fmt) +#define ROAMING_LOUD_LOGFUNC(_Fmt...) +#define ROAMING_TEMP_LOGFUNC(_Fmt...) + +#define ROAMING_ERROR_LOGDUMP8(x, y) +#define ROAMING_WARN_LOGDUMP8(x, y) +#define ROAMING_INFO_LOGDUMP8(x, y) +#define ROAMING_STATE_LOGDUMP8(x, y) +#define ROAMING_EVENT_LOGDUMP8(x, y) +#define ROAMING_TRACE_LOGDUMP8(x, y) +#define ROAMING_LOUD_LOGDUMP8(x, y) +#define ROAMING_TEMP_LOGDUMP8(x, y) + +#define REQ_ERROR_LOGFUNC(_Fmt...) +#define REQ_WARN_LOGFUNC(_Fmt...) +#define REQ_INFO_LOGFUNC(_Fmt...) +#define REQ_STATE_LOGFUNC(_Fmt...) +#define REQ_EVENT_LOGFUNC(_Fmt...) +#define REQ_TRACE_LOGFUNC(_Fmt...) +#define REQ_LOUD_LOGFUNC(_Fmt...) +#define REQ_TEMP_LOGFUNC(_Fmt...) + +#define REQ_ERROR_LOGDUMP8(x, y) +#define REQ_WARN_LOGDUMP8(x, y) +#define REQ_INFO_LOGDUMP8(x, y) +#define REQ_STATE_LOGDUMP8(x, y) +#define REQ_EVENT_LOGDUMP8(x, y) +#define REQ_TRACE_LOGDUMP8(x, y) +#define REQ_LOUD_LOGDUMP8(x, y) +#define REQ_TEMP_LOGDUMP8(x, y) + +#define TX_ERROR_LOGFUNC(_Fmt...) +#define TX_WARN_LOGFUNC(_Fmt...) +#define TX_INFO_LOGFUNC(_Fmt...) +#define TX_STATE_LOGFUNC(_Fmt...) +#define TX_EVENT_LOGFUNC(_Fmt...) +#define TX_TRACE_LOGFUNC(_Fmt...) +#define TX_LOUD_LOGFUNC(_Fmt...) +#define TX_TEMP_LOGFUNC(_Fmt...) + +#define TX_ERROR_LOGDUMP8(x, y) +#define TX_WARN_LOGDUMP8(x, y) +#define TX_INFO_LOGDUMP8(x, y) +#define TX_STATE_LOGDUMP8(x, y) +#define TX_EVENT_LOGDUMP8(x, y) +#define TX_TRACE_LOGDUMP8(x, y) +#define TX_LOUD_LOGDUMP8(x, y) +#define TX_TEMP_LOGDUMP8(x, y) + +#define RX_ERROR_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_ERROR, XLOG_TAG, _Fmt) +#define RX_WARN_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_WARN, XLOG_TAG, _Fmt) +#define RX_INFO_LOGFUNC(_Fmt...) +#define RX_STATE_LOGFUNC(_Fmt...) +#define RX_EVENT_LOGFUNC(_Fmt...) +#define RX_TRACE_LOGFUNC(_Fmt...) +#define RX_LOUD_LOGFUNC(_Fmt...) +#define RX_TEMP_LOGFUNC(_Fmt...) + +#define RX_ERROR_LOGDUMP8(x, y) +#define RX_WARN_LOGDUMP8(x, y) +#define RX_INFO_LOGDUMP8(x, y) +#define RX_STATE_LOGDUMP8(x, y) +#define RX_EVENT_LOGDUMP8(x, y) +#define RX_TRACE_LOGDUMP8(x, y) +#define RX_LOUD_LOGDUMP8(x, y) +#define RX_TEMP_LOGDUMP8(x, y) + +#define RFTEST_ERROR_LOGFUNC(_Fmt...) +#define RFTEST_WARN_LOGFUNC(_Fmt...) +#define RFTEST_INFO_LOGFUNC(_Fmt...) +#define RFTEST_STATE_LOGFUNC(_Fmt...) +#define RFTEST_EVENT_LOGFUNC(_Fmt...) +#define RFTEST_TRACE_LOGFUNC(_Fmt...) +#define RFTEST_LOUD_LOGFUNC(_Fmt...) +#define RFTEST_TEMP_LOGFUNC(_Fmt...) + +#define RFTEST_ERROR_LOGDUMP8(x, y) +#define RFTEST_WARN_LOGDUMP8(x, y) +#define RFTEST_INFO_LOGDUMP8(x, y) +#define RFTEST_STATE_LOGDUMP8(x, y) +#define RFTEST_EVENT_LOGDUMP8(x, y) +#define RFTEST_TRACE_LOGDUMP8(x, y) +#define RFTEST_LOUD_LOGDUMP8(x, y) +#define RFTEST_TEMP_LOGDUMP8(x, y) + +#define EMU_ERROR_LOGFUNC(_Fmt...) +#define EMU_WARN_LOGFUNC(_Fmt...) +#define EMU_INFO_LOGFUNC(_Fmt...) +#define EMU_STATE_LOGFUNC(_Fmt...) +#define EMU_EVENT_LOGFUNC(_Fmt...) +#define EMU_TRACE_LOGFUNC(_Fmt...) +#define EMU_LOUD_LOGFUNC(_Fmt...) +#define EMU_TEMP_LOGFUNC(_Fmt...) + +#define EMU_ERROR_LOGDUMP8(x, y) +#define EMU_WARN_LOGDUMP8(x, y) +#define EMU_INFO_LOGDUMP8(x, y) +#define EMU_STATE_LOGDUMP8(x, y) +#define EMU_EVENT_LOGDUMP8(x, y) +#define EMU_TRACE_LOGDUMP8(x, y) +#define EMU_LOUD_LOGDUMP8(x, y) +#define EMU_TEMP_LOGDUMP8(x, y) + +#define HEM_ERROR_LOGFUNC(_Fmt...) +#define HEM_WARN_LOGFUNC(_Fmt...) +#define HEM_INFO_LOGFUNC(_Fmt...) +#define HEM_STATE_LOGFUNC(_Fmt...) +#define HEM_EVENT_LOGFUNC(_Fmt...) +#define HEM_TRACE_LOGFUNC(_Fmt...) +#define HEM_LOUD_LOGFUNC(_Fmt...) +#define HEM_TEMP_LOGFUNC(_Fmt...) + +#define HEM_ERROR_LOGDUMP8(x, y) +#define HEM_WARN_LOGDUMP8(x, y) +#define HEM_INFO_LOGDUMP8(x, y) +#define HEM_STATE_LOGDUMP8(x, y) +#define HEM_EVENT_LOGDUMP8(x, y) +#define HEM_TRACE_LOGDUMP8(x, y) +#define HEM_LOUD_LOGDUMP8(x, y) +#define HEM_TEMP_LOGDUMP8(x, y) + +#define RLM_ERROR_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_ERROR, XLOG_TAG, _Fmt) +#define RLM_WARN_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_WARN, XLOG_TAG, _Fmt) +#define RLM_INFO_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_INFO, XLOG_TAG, _Fmt) +#define RLM_STATE_LOGFUNC(_Fmt...) +#define RLM_EVENT_LOGFUNC(_Fmt...) +#define RLM_TRACE_LOGFUNC(_Fmt...) +#define RLM_LOUD_LOGFUNC(_Fmt...) +#define RLM_TEMP_LOGFUNC(_Fmt...) + +#define RLM_ERROR_LOGDUMP8(x, y) +#define RLM_WARN_LOGDUMP8(x, y) +#define RLM_INFO_LOGDUMP8(x, y) +#define RLM_STATE_LOGDUMP8(x, y) +#define RLM_EVENT_LOGDUMP8(x, y) +#define RLM_TRACE_LOGDUMP8(x, y) +#define RLM_LOUD_LOGDUMP8(x, y) +#define RLM_TEMP_LOGDUMP8(x, y) + +#define MEM_ERROR_LOGFUNC(_Fmt...) +#define MEM_WARN_LOGFUNC(_Fmt...) +#define MEM_INFO_LOGFUNC(_Fmt...) +#define MEM_STATE_LOGFUNC(_Fmt...) +#define MEM_EVENT_LOGFUNC(_Fmt...) +#define MEM_TRACE_LOGFUNC(_Fmt...) +#define MEM_LOUD_LOGFUNC(_Fmt...) +#define MEM_TEMP_LOGFUNC(_Fmt...) + +#define MEM_ERROR_LOGDUMP8(x, y) +#define MEM_WARN_LOGDUMP8(x, y) +#define MEM_INFO_LOGDUMP8(x, y) +#define MEM_STATE_LOGDUMP8(x, y) +#define MEM_EVENT_LOGDUMP8(x, y) +#define MEM_TRACE_LOGDUMP8(x, y) +#define MEM_LOUD_LOGDUMP8(x, y) +#define MEM_TEMP_LOGDUMP8(x, y) + +#define CNM_ERROR_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_ERROR, XLOG_TAG, _Fmt) +#define CNM_WARN_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_WARN, XLOG_TAG, _Fmt) +#define CNM_INFO_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_INFO, XLOG_TAG, _Fmt) +#define CNM_STATE_LOGFUNC(_Fmt...) +#define CNM_EVENT_LOGFUNC(_Fmt...) +#define CNM_TRACE_LOGFUNC(_Fmt...) +#define CNM_LOUD_LOGFUNC(_Fmt...) +#define CNM_TEMP_LOGFUNC(_Fmt...) + +#define CNM_ERROR_LOGDUMP8(x, y) +#define CNM_WARN_LOGDUMP8(x, y) +#define CNM_INFO_LOGDUMP8(x, y) +#define CNM_STATE_LOGDUMP8(x, y) +#define CNM_EVENT_LOGDUMP8(x, y) +#define CNM_TRACE_LOGDUMP8(x, y) +#define CNM_LOUD_LOGDUMP8(x, y) +#define CNM_TEMP_LOGDUMP8(x, y) + +#define RSN_ERROR_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_ERROR, XLOG_TAG, _Fmt) +#define RSN_WARN_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_WARN, XLOG_TAG, _Fmt) +#define RSN_INFO_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_INFO, XLOG_TAG, _Fmt) +#define RSN_STATE_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_INFO, XLOG_TAG, _Fmt) +#define RSN_EVENT_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_INFO, XLOG_TAG, _Fmt) +#define RSN_TRACE_LOGFUNC(_Fmt...) +#define RSN_LOUD_LOGFUNC(_Fmt...) +#define RSN_TEMP_LOGFUNC(_Fmt...) + +#define RSN_ERROR_LOGDUMP8(x, y) +#define RSN_WARN_LOGDUMP8(x, y) +#define RSN_INFO_LOGDUMP8(x, y) +#define RSN_STATE_LOGDUMP8(x, y) +#define RSN_EVENT_LOGDUMP8(x, y) +#define RSN_TRACE_LOGDUMP8(x, y) +#define RSN_LOUD_LOGDUMP8(x, y) +#define RSN_TEMP_LOGDUMP8(x, y) + +#define BSS_ERROR_LOGFUNC(_Fmt...) +#define BSS_WARN_LOGFUNC(_Fmt...) +#define BSS_INFO_LOGFUNC(_Fmt...) +#define BSS_STATE_LOGFUNC(_Fmt...) +#define BSS_EVENT_LOGFUNC(_Fmt...) +#define BSS_TRACE_LOGFUNC(_Fmt...) +#define BSS_LOUD_LOGFUNC(_Fmt...) +#define BSS_TEMP_LOGFUNC(_Fmt...) + +#define BSS_ERROR_LOGDUMP8(x, y) +#define BSS_WARN_LOGDUMP8(x, y) +#define BSS_INFO_LOGDUMP8(x, y) +#define BSS_STATE_LOGDUMP8(x, y) +#define BSS_EVENT_LOGDUMP8(x, y) +#define BSS_TRACE_LOGDUMP8(x, y) +#define BSS_LOUD_LOGDUMP8(x, y) +#define BSS_TEMP_LOGDUMP8(x, y) + +#define SCN_ERROR_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_ERROR, XLOG_TAG, _Fmt) +#define SCN_WARN_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_WARN, XLOG_TAG, _Fmt) +#define SCN_INFO_LOGFUNC(_Fmt...) +#define SCN_STATE_LOGFUNC(_Fmt...) +#define SCN_EVENT_LOGFUNC(_Fmt...) +#define SCN_TRACE_LOGFUNC(_Fmt...) +#define SCN_LOUD_LOGFUNC(_Fmt...) +#define SCN_TEMP_LOGFUNC(_Fmt...) + +#define SCN_ERROR_LOGDUMP8(x, y) +#define SCN_WARN_LOGDUMP8(x, y) +#define SCN_INFO_LOGDUMP8(x, y) +#define SCN_STATE_LOGDUMP8(x, y) +#define SCN_EVENT_LOGDUMP8(x, y) +#define SCN_TRACE_LOGDUMP8(x, y) +#define SCN_LOUD_LOGDUMP8(x, y) +#define SCN_TEMP_LOGDUMP8(x, y) + +#define SAA_ERROR_LOGFUNC(_Fmt...) +#define SAA_WARN_LOGFUNC(_Fmt...) +#define SAA_INFO_LOGFUNC(_Fmt...) +#define SAA_STATE_LOGFUNC(_Fmt...) +#define SAA_EVENT_LOGFUNC(_Fmt...) +#define SAA_TRACE_LOGFUNC(_Fmt...) +#define SAA_LOUD_LOGFUNC(_Fmt...) +#define SAA_TEMP_LOGFUNC(_Fmt...) + +#define SAA_ERROR_LOGDUMP8(x, y) +#define SAA_WARN_LOGDUMP8(x, y) +#define SAA_INFO_LOGDUMP8(x, y) +#define SAA_STATE_LOGDUMP8(x, y) +#define SAA_EVENT_LOGDUMP8(x, y) +#define SAA_TRACE_LOGDUMP8(x, y) +#define SAA_LOUD_LOGDUMP8(x, y) +#define SAA_TEMP_LOGDUMP8(x, y) + +#define P2P_ERROR_LOGFUNC(_Fmt...) +#define P2P_WARN_LOGFUNC(_Fmt...) +#define P2P_INFO_LOGFUNC(_Fmt...) +#define P2P_STATE_LOGFUNC(_Fmt...) +#define P2P_EVENT_LOGFUNC(_Fmt...) +#define P2P_TRACE_LOGFUNC(_Fmt...) +#define P2P_LOUD_LOGFUNC(_Fmt...) +#define P2P_TEMP_LOGFUNC(_Fmt...) + +#define P2P_ERROR_LOGDUMP8(x, y) +#define P2P_WARN_LOGDUMP8(x, y) +#define P2P_INFO_LOGDUMP8(x, y) +#define P2P_STATE_LOGDUMP8(x, y) +#define P2P_EVENT_LOGDUMP8(x, y) +#define P2P_TRACE_LOGDUMP8(x, y) +#define P2P_LOUD_LOGDUMP8(x, y) +#define P2P_TEMP_LOGDUMP8(x, y) + +#define QM_ERROR_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_ERROR, XLOG_TAG, _Fmt) +#define QM_WARN_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_WARN, XLOG_TAG, _Fmt) +#define QM_INFO_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_INFO, XLOG_TAG, _Fmt) +#define QM_STATE_LOGFUNC(_Fmt...) +#define QM_EVENT_LOGFUNC(_Fmt...) +#define QM_TRACE_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_DEBUG, XLOG_TAG, _Fmt) +#define QM_LOUD_LOGFUNC(_Fmt...) +#define QM_TEMP_LOGFUNC(_Fmt...) + +#define QM_ERROR_LOGDUMP8(x, y) +#define QM_WARN_LOGDUMP8(x, y) +#define QM_INFO_LOGDUMP8(x, y) +#define QM_STATE_LOGDUMP8(x, y) +#define QM_EVENT_LOGDUMP8(x, y) +#define QM_TRACE_LOGDUMP8(x, y) +#define QM_LOUD_LOGDUMP8(x, y) +#define QM_TEMP_LOGDUMP8(x, y) + +#define SEC_ERROR_LOGFUNC(_Fmt...) +#define SEC_WARN_LOGFUNC(_Fmt...) +#define SEC_INFO_LOGFUNC(_Fmt...) +#define SEC_STATE_LOGFUNC(_Fmt...) +#define SEC_EVENT_LOGFUNC(_Fmt...) +#define SEC_TRACE_LOGFUNC(_Fmt...) +#define SEC_LOUD_LOGFUNC(_Fmt...) +#define SEC_TEMP_LOGFUNC(_Fmt...) + +#define SEC_ERROR_LOGDUMP8(x, y) +#define SEC_WARN_LOGDUMP8(x, y) +#define SEC_INFO_LOGDUMP8(x, y) +#define SEC_STATE_LOGDUMP8(x, y) +#define SEC_EVENT_LOGDUMP8(x, y) +#define SEC_TRACE_LOGDUMP8(x, y) +#define SEC_LOUD_LOGDUMP8(x, y) +#define SEC_TEMP_LOGDUMP8(x, y) + +#define BOW_ERROR_LOGFUNC(_Fmt...) +#define BOW_WARN_LOGFUNC(_Fmt...) +#define BOW_INFO_LOGFUNC(_Fmt...) +#define BOW_STATE_LOGFUNC(_Fmt...) +#define BOW_EVENT_LOGFUNC(_Fmt...) +#define BOW_TRACE_LOGFUNC(_Fmt...) +#define BOW_LOUD_LOGFUNC(_Fmt...) +#define BOW_TEMP_LOGFUNC(_Fmt...) + +#define BOW_ERROR_LOGDUMP8(x, y) +#define BOW_WARN_LOGDUMP8(x, y) +#define BOW_INFO_LOGDUMP8(x, y) +#define BOW_STATE_LOGDUMP8(x, y) +#define BOW_EVENT_LOGDUMP8(x, y) +#define BOW_TRACE_LOGDUMP8(x, y) +#define BOW_LOUD_LOGDUMP8(x, y) +#define BOW_TEMP_LOGDUMP8(x, y) + +#define HAL_ERROR_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_ERROR, XLOG_TAG, _Fmt) +#define HAL_WARN_LOGFUNC(_Fmt...) +#define HAL_INFO_LOGFUNC(_Fmt...) +#define HAL_STATE_LOGFUNC(_Fmt...) +#define HAL_EVENT_LOGFUNC(_Fmt...) +#define HAL_TRACE_LOGFUNC(_Fmt...) +#define HAL_LOUD_LOGFUNC(_Fmt...) +#define HAL_TEMP_LOGFUNC(_Fmt...) + +#define HAL_ERROR_LOGDUMP8(x, y) +#define HAL_WARN_LOGDUMP8(x, y) +#define HAL_INFO_LOGDUMP8(x, y) +#define HAL_STATE_LOGDUMP8(x, y) +#define HAL_EVENT_LOGDUMP8(x, y) +#define HAL_TRACE_LOGDUMP8(x, y) +#define HAL_LOUD_LOGDUMP8(x, y) +#define HAL_TEMP_LOGDUMP8(x, y) + +#define WAPI_ERROR_LOGFUNC(_Fmt...) +#define WAPI_WARN_LOGFUNC(_Fmt...) +#define WAPI_INFO_LOGFUNC(_Fmt...) +#define WAPI_STATE_LOGFUNC(_Fmt...) +#define WAPI_EVENT_LOGFUNC(_Fmt...) +#define WAPI_TRACE_LOGFUNC(_Fmt...) +#define WAPI_LOUD_LOGFUNC(_Fmt...) +#define WAPI_TEMP_LOGFUNC(_Fmt...) + +#define WAPI_ERROR_LOGDUMP8(x, y) +#define WAPI_WARN_LOGDUMP8(x, y) +#define WAPI_INFO_LOGDUMP8(x, y) +#define WAPI_STATE_LOGDUMP8(x, y) +#define WAPI_EVENT_LOGDUMP8(x, y) +#define WAPI_TRACE_LOGDUMP8(x, y) +#define WAPI_LOUD_LOGDUMP8(x, y) +#define WAPI_TEMP_LOGDUMP8(x, y) + +#define SW1_ERROR_LOGFUNC(_Fmt...) +#define SW1_WARN_LOGFUNC(_Fmt...) +#define SW1_INFO_LOGFUNC(_Fmt...) +#define SW1_STATE_LOGFUNC(_Fmt...) +#define SW1_EVENT_LOGFUNC(_Fmt...) +#define SW1_TRACE_LOGFUNC(_Fmt...) +#define SW1_LOUD_LOGFUNC(_Fmt...) +#define SW1_TEMP_LOGFUNC(_Fmt...) + +#define SW1_ERROR_LOGDUMP8(x, y) +#define SW1_WARN_LOGDUMP8(x, y) +#define SW1_INFO_LOGDUMP8(x, y) +#define SW1_STATE_LOGDUMP8(x, y) +#define SW1_EVENT_LOGDUMP8(x, y) +#define SW1_TRACE_LOGDUMP8(x, y) +#define SW1_LOUD_LOGDUMP8(x, y) +#define SW1_TEMP_LOGDUMP8(x, y) + +#define SW2_ERROR_LOGFUNC(_Fmt...) +#define SW2_WARN_LOGFUNC(_Fmt...) +#define SW2_INFO_LOGFUNC(_Fmt...) +#define SW2_STATE_LOGFUNC(_Fmt...) +#define SW2_EVENT_LOGFUNC(_Fmt...) +#define SW2_TRACE_LOGFUNC(_Fmt...) +#define SW2_LOUD_LOGFUNC(_Fmt...) +#define SW2_TEMP_LOGFUNC(_Fmt...) + +#define SW2_ERROR_LOGDUMP8(x, y) +#define SW2_WARN_LOGDUMP8(x, y) +#define SW2_INFO_LOGDUMP8(x, y) +#define SW2_STATE_LOGDUMP8(x, y) +#define SW2_EVENT_LOGDUMP8(x, y) +#define SW2_TRACE_LOGDUMP8(x, y) +#define SW2_LOUD_LOGDUMP8(x, y) +#define SW2_TEMP_LOGDUMP8(x, y) + +#define SW3_ERROR_LOGFUNC(_Fmt...) +#define SW3_WARN_LOGFUNC(_Fmt...) +#define SW3_INFO_LOGFUNC(_Fmt...) +#define SW3_STATE_LOGFUNC(_Fmt...) +#define SW3_EVENT_LOGFUNC(_Fmt...) +#define SW3_TRACE_LOGFUNC(_Fmt...) +#define SW3_LOUD_LOGFUNC(_Fmt...) +#define SW3_TEMP_LOGFUNC(_Fmt...) + +#define SW3_ERROR_LOGDUMP8(x, y) +#define SW3_WARN_LOGDUMP8(x, y) +#define SW3_INFO_LOGDUMP8(x, y) +#define SW3_STATE_LOGDUMP8(x, y) +#define SW3_EVENT_LOGDUMP8(x, y) +#define SW3_TRACE_LOGDUMP8(x, y) +#define SW3_LOUD_LOGDUMP8(x, y) +#define SW3_TEMP_LOGDUMP8(x, y) + +#define SW4_ERROR_LOGFUNC(_Fmt...) +#define SW4_WARN_LOGFUNC(_Fmt...) +#define SW4_INFO_LOGFUNC(_Fmt...) xlog_printk(ANDROID_LOG_INFO, XLOG_TAG, _Fmt) +#define SW4_STATE_LOGFUNC(_Fmt...) +#define SW4_EVENT_LOGFUNC(_Fmt...) +#define SW4_TRACE_LOGFUNC(_Fmt...) +#define SW4_LOUD_LOGFUNC(_Fmt...) +#define SW4_TEMP_LOGFUNC(_Fmt...) + +#define SW4_ERROR_LOGDUMP8(x, y) +#define SW4_WARN_LOGDUMP8(x, y) +#define SW4_INFO_LOGDUMP8(x, y) +#define SW4_STATE_LOGDUMP8(x, y) +#define SW4_EVENT_LOGDUMP8(x, y) +#define SW4_TRACE_LOGDUMP8(x, y) dumpMemory8(ANDROID_LOG_DEBUG, x, y) +#define SW4_LOUD_LOGDUMP8(x, y) +#define SW4_TEMP_LOGDUMP8(x, y) + +#endif + +#define kalBreakPoint() \ + do { \ + BUG(); \ + panic("Oops"); \ + } while(0) + +#define PRINTF_ARG(...) __VA_ARGS__ +#define SPRINTF(buf, arg) {buf += sprintf((char *)(buf), PRINTF_ARG arg);} + +#define USEC_TO_SYSTIME(_usec) ((_usec) / USEC_PER_MSEC) +#define MSEC_TO_SYSTIME(_msec) (_msec) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Routines in gl_kal.c */ +/*----------------------------------------------------------------------------*/ +VOID +kalAcquireSpinLock( + IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_SPIN_LOCK_CATEGORY_E rLockCategory, + OUT PUINT_32 pu4Flags + ); + +VOID +kalReleaseSpinLock( + IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_SPIN_LOCK_CATEGORY_E rLockCategory, + IN UINT_32 u4Flags + ); + +VOID +kalUpdateMACAddress( + IN P_GLUE_INFO_T prGlueInfo, + IN PUINT_8 pucMacAddr + ); + +VOID +kalPacketFree( + IN P_GLUE_INFO_T prGlueInfo, + IN PVOID pvPacket + ); + +PVOID +kalPacketAlloc( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_32 u4Size, + OUT PUINT_8 *ppucData + ); + +VOID +kalOsTimerInitialize( + IN P_GLUE_INFO_T prGlueInfo, + IN PVOID prTimerHandler + ); + +BOOL +kalSetTimer( + IN P_GLUE_INFO_T prGlueInfo, + IN OS_SYSTIME rInterval + ); + +WLAN_STATUS +kalProcessRxPacket( + IN P_GLUE_INFO_T prGlueInfo, + IN PVOID pvPacket, + IN PUINT_8 pucPacketStart, + IN UINT_32 u4PacketLen, + //IN PBOOLEAN pfgIsRetain, + IN BOOLEAN fgIsRetain, + IN ENUM_CSUM_RESULT_T aeCSUM[] + ); + +WLAN_STATUS +kalRxIndicatePkts( + IN P_GLUE_INFO_T prGlueInfo, + IN PVOID apvPkts[], + IN UINT_8 ucPktNum + ); + +VOID +kalIndicateStatusAndComplete( + IN P_GLUE_INFO_T prGlueInfo, + IN WLAN_STATUS eStatus, + IN PVOID pvBuf, + IN UINT_32 u4BufLen + ); + +VOID +kalUpdateReAssocReqInfo( + IN P_GLUE_INFO_T prGlueInfo, + IN PUINT_8 pucFrameBody, + IN UINT_32 u4FrameBodyLen, + IN BOOLEAN fgReassocRequest + ); + +#if CFG_TX_FRAGMENT +BOOLEAN +kalQueryTxPacketHeader( + IN P_GLUE_INFO_T prGlueInfo, + IN PVOID pvPacket, + OUT PUINT_16 pu2EtherTypeLen, + OUT PUINT_8 pucEthDestAddr + ); +#endif /* CFG_TX_FRAGMENT */ + +VOID +kalSendCompleteAndAwakeQueue( + IN P_GLUE_INFO_T prGlueInfo, + IN PVOID pvPacket + ); + +#if CFG_TCP_IP_CHKSUM_OFFLOAD +VOID +kalQueryTxChksumOffloadParam( + IN PVOID pvPacket, + OUT PUINT_8 pucFlag); + +VOID +kalUpdateRxCSUMOffloadParam( + IN PVOID pvPacket, + IN ENUM_CSUM_RESULT_T eCSUM[] + ); +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + + +BOOLEAN +kalRetrieveNetworkAddress( + IN P_GLUE_INFO_T prGlueInfo, + IN OUT PARAM_MAC_ADDRESS * prMacAddr + ); + + +/*----------------------------------------------------------------------------*/ +/* Routines in interface - ehpi/sdio.c */ +/*----------------------------------------------------------------------------*/ +BOOL +kalDevRegRead( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_32 u4Register, + OUT PUINT_32 pu4Value + ); + +BOOL +kalDevRegWrite( + P_GLUE_INFO_T prGlueInfo, + IN UINT_32 u4Register, + IN UINT_32 u4Value + ); + +BOOL +kalDevPortRead( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_16 u2Port, + IN UINT_16 u2Len, + OUT PUINT_8 pucBuf, + IN UINT_16 u2ValidOutBufSize + ); + +BOOL +kalDevPortWrite( + P_GLUE_INFO_T prGlueInfo, + IN UINT_16 u2Port, + IN UINT_16 u2Len, + IN PUINT_8 pucBuf, + IN UINT_16 u2ValidInBufSize + ); + +BOOL +kalDevWriteWithSdioCmd52 ( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_32 u4Addr, + IN UINT_8 ucData + ); + + + #if CFG_SUPPORT_EXT_CONFIG +UINT_32 +kalReadExtCfg ( + IN P_GLUE_INFO_T prGlueInfo + ); + #endif + +BOOL +kalQoSFrameClassifierAndPacketInfo ( + IN P_GLUE_INFO_T prGlueInfo, + IN P_NATIVE_PACKET prPacket, + OUT PUINT_8 pucPriorityParam, + OUT PUINT_32 pu4PacketLen, + OUT PUINT_8 pucEthDestAddr, + OUT PBOOLEAN pfgIs1X, + OUT PBOOLEAN pfgIsPAL, + OUT PUINT_8 pucNetworkType +); + +inline VOID +kalOidComplete ( + IN P_GLUE_INFO_T prGlueInfo, + IN BOOLEAN fgSetQuery, + IN UINT_32 u4SetQueryInfoLen, + IN WLAN_STATUS rOidStatus + ); + + +WLAN_STATUS +kalIoctl (IN P_GLUE_INFO_T prGlueInfo, + IN PFN_OID_HANDLER_FUNC pfnOidHandler, + IN PVOID pvInfoBuf, + IN UINT_32 u4InfoBufLen, + IN BOOL fgRead, + IN BOOL fgWaitResp, + IN BOOL fgCmd, + IN BOOL fgIsP2pOid, + OUT PUINT_32 pu4QryInfoLen + ); + +VOID +kalHandleAssocInfo( + IN P_GLUE_INFO_T prGlueInfo, + IN P_EVENT_ASSOC_INFO prAssocInfo + ); + +#if CFG_ENABLE_FW_DOWNLOAD + +PVOID +kalFirmwareImageMapping ( + IN P_GLUE_INFO_T prGlueInfo, + OUT PPVOID ppvMapFileBuf, + OUT PUINT_32 pu4FileLength + ); + +VOID +kalFirmwareImageUnmapping ( + IN P_GLUE_INFO_T prGlueInfo, + IN PVOID prFwHandle, + IN PVOID pvMapFileBuf + ); +#endif + + +/*----------------------------------------------------------------------------*/ +/* Card Removal Check */ +/*----------------------------------------------------------------------------*/ +BOOLEAN +kalIsCardRemoved( + IN P_GLUE_INFO_T prGlueInfo + ); + + +/*----------------------------------------------------------------------------*/ +/* TX */ +/*----------------------------------------------------------------------------*/ +VOID +kalFlushPendingTxPackets( + IN P_GLUE_INFO_T prGlueInfo + ); + + +/*----------------------------------------------------------------------------*/ +/* Media State Indication */ +/*----------------------------------------------------------------------------*/ +ENUM_PARAM_MEDIA_STATE_T +kalGetMediaStateIndicated( + IN P_GLUE_INFO_T prGlueInfo + ); + + +VOID +kalSetMediaStateIndicated( + IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_PARAM_MEDIA_STATE_T eParamMediaStateIndicate + ); + + +/*----------------------------------------------------------------------------*/ +/* OID handling */ +/*----------------------------------------------------------------------------*/ +VOID +kalOidCmdClearance( + IN P_GLUE_INFO_T prGlueInfo + ); + +VOID +kalOidClearance( + IN P_GLUE_INFO_T prGlueInfo + ); + +VOID +kalEnqueueCommand( + IN P_GLUE_INFO_T prGlueInfo, + IN P_QUE_ENTRY_T prQueueEntry + ); + +#if CFG_ENABLE_BT_OVER_WIFI +/*----------------------------------------------------------------------------*/ +/* Bluetooth over Wi-Fi handling */ +/*----------------------------------------------------------------------------*/ +VOID +kalIndicateBOWEvent( + IN P_GLUE_INFO_T prGlueInfo, + IN P_AMPC_EVENT prEvent + ); + +ENUM_BOW_DEVICE_STATE +kalGetBowState ( + IN P_GLUE_INFO_T prGlueInfo, + IN PARAM_MAC_ADDRESS rPeerAddr + ); + +BOOLEAN +kalSetBowState ( + IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_BOW_DEVICE_STATE eBowState, + PARAM_MAC_ADDRESS rPeerAddr + ); + +ENUM_BOW_DEVICE_STATE +kalGetBowGlobalState ( + IN P_GLUE_INFO_T prGlueInfo + ); + +UINT_32 +kalGetBowFreqInKHz( + IN P_GLUE_INFO_T prGlueInfo + ); + +UINT_8 +kalGetBowRole( + IN P_GLUE_INFO_T prGlueInfo, + IN PARAM_MAC_ADDRESS rPeerAddr + ); + +VOID +kalSetBowRole( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_8 ucRole, + IN PARAM_MAC_ADDRESS rPeerAddr + ); + +UINT_8 +kalGetBowAvailablePhysicalLinkCount( + IN P_GLUE_INFO_T prGlueInfo + ); + +#if CFG_BOW_SEPARATE_DATA_PATH +/*----------------------------------------------------------------------------*/ +/* Bluetooth over Wi-Fi Net Device Init/Uninit */ +/*----------------------------------------------------------------------------*/ +BOOLEAN +kalInitBowDevice( + IN P_GLUE_INFO_T prGlueInfo, + IN const char *prDevName + ); + +BOOLEAN +kalUninitBowDevice( + IN P_GLUE_INFO_T prGlueInfo + ); +#endif // CFG_BOW_SEPARATE_DATA_PATH +#endif // CFG_ENABLE_BT_OVER_WIFI + + +/*----------------------------------------------------------------------------*/ +/* Firmware Download Handling */ +/*----------------------------------------------------------------------------*/ +UINT_32 +kalGetFwStartAddress( + IN P_GLUE_INFO_T prGlueInfo + ); + +UINT_32 +kalGetFwLoadAddress( + IN P_GLUE_INFO_T prGlueInfo + ); + +/*----------------------------------------------------------------------------*/ +/* Security Frame Clearance */ +/*----------------------------------------------------------------------------*/ +VOID +kalClearSecurityFrames( + IN P_GLUE_INFO_T prGlueInfo + ); + +VOID +kalClearSecurityFramesByNetType( + IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx + ); + +VOID +kalSecurityFrameSendComplete ( + IN P_GLUE_INFO_T prGlueInfo, + IN PVOID pvPacket, + IN WLAN_STATUS rStatus + ); + + +/*----------------------------------------------------------------------------*/ +/* Management Frame Clearance */ +/*----------------------------------------------------------------------------*/ +VOID +kalClearMgmtFrames( + IN P_GLUE_INFO_T prGlueInfo + ); + +VOID +kalClearMgmtFramesByNetType( + IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx + ); + +UINT_32 +kalGetTxPendingFrameCount( + IN P_GLUE_INFO_T prGlueInfo + ); + +UINT_32 +kalGetTxPendingCmdCount( + IN P_GLUE_INFO_T prGlueInfo + ); + +BOOLEAN +kalSetTimer( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_32 u4Interval + ); + +BOOLEAN +kalCancelTimer( + IN P_GLUE_INFO_T prGlueInfo + ); + +VOID +kalScanDone( + IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_KAL_NETWORK_TYPE_INDEX_T eNetTypeIdx, + IN WLAN_STATUS status + ); + +UINT_32 +kalRandomNumber( + VOID + ); + +VOID +kalTimeoutHandler (unsigned long arg); + +VOID +kalSetEvent (P_GLUE_INFO_T pr); + + +/*----------------------------------------------------------------------------*/ +/* NVRAM/Registry Service */ +/*----------------------------------------------------------------------------*/ +BOOLEAN +kalIsConfigurationExist( + IN P_GLUE_INFO_T prGlueInfo + ); + +P_REG_INFO_T +kalGetConfiguration( + IN P_GLUE_INFO_T prGlueInfo + ); + +VOID +kalGetConfigurationVersion( + IN P_GLUE_INFO_T prGlueInfo, + OUT PUINT_16 pu2Part1CfgOwnVersion, + OUT PUINT_16 pu2Part1CfgPeerVersion, + OUT PUINT_16 pu2Part2CfgOwnVersion, + OUT PUINT_16 pu2Part2CfgPeerVersion + ); + +BOOLEAN +kalCfgDataRead16( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_32 u4Offset, + OUT PUINT_16 pu2Data + ); + +BOOLEAN +kalCfgDataWrite16( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_32 u4Offset, + IN UINT_16 u2Data + ); + +/*----------------------------------------------------------------------------*/ +/* WSC Connection */ +/*----------------------------------------------------------------------------*/ +BOOLEAN +kalWSCGetActiveState( + IN P_GLUE_INFO_T prGlueInfo + ); + +/*----------------------------------------------------------------------------*/ +/* RSSI Updating */ +/*----------------------------------------------------------------------------*/ +VOID +kalUpdateRSSI( + IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_KAL_NETWORK_TYPE_INDEX_T eNetTypeIdx, + IN INT_8 cRssi, + IN INT_8 cLinkQuality + ); + + +/*----------------------------------------------------------------------------*/ +/* I/O Buffer Pre-allocation */ +/*----------------------------------------------------------------------------*/ +BOOLEAN +kalInitIOBuffer( + VOID + ); + +VOID +kalUninitIOBuffer( + VOID + ); + +PVOID +kalAllocateIOBuffer( + IN UINT_32 u4AllocSize + ); + +VOID +kalReleaseIOBuffer( + IN PVOID pvAddr, + IN UINT_32 u4Size + ); + +VOID +kalGetChannelList( + IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_BAND_T eSpecificBand, + IN UINT_8 ucMaxChannelNum, + IN PUINT_8 pucNumOfChannel, + IN P_RF_CHANNEL_INFO_T paucChannelList + ); + +BOOL +kalIsAPmode( + IN P_GLUE_INFO_T prGlueInfo + ); + +#if CFG_SUPPORT_802_11W +/*----------------------------------------------------------------------------*/ +/* 802.11W */ +/*----------------------------------------------------------------------------*/ +UINT_32 +kalGetMfpSetting( + IN P_GLUE_INFO_T prGlueInfo + ); +#endif + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +int tx_thread(void *data); + +#endif /* _GL_KAL_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_os.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_os.h new file mode 100755 index 000000000000..4f6272c35a30 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_os.h @@ -0,0 +1,1093 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/os/linux/include/gl_os.h#2 $ +*/ + +/*! \file gl_os.h + \brief List the external reference to OS for GLUE Layer. + + In this file we define the data structure - GLUE_INFO_T to store those objects + we acquired from OS - e.g. TIMER, SPINLOCK, NET DEVICE ... . And all the + external reference (header file, extern func() ..) to OS for GLUE Layer should + also list down here. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: gl_os.h $ + * + * 01 09 2012 terry.wu + * [WCXRP00001166] [Wi-Fi] [Driver] cfg80211 integration for p2p newtork + * cfg80211 integration for p2p network. + * + * 01 09 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Check in the Add Tx power Cmd to driver. + * + * 12 13 2011 cm.chang + * [WCXRP00001136] [All Wi-Fi][Driver] Add wake lock for pending timer + * Add wake lock if timer timeout value is smaller than 5 seconds + * + * 11 19 2011 yuche.tsai + * NULL + * Fix type conflict. + * + * 11 19 2011 yuche.tsai + * NULL + * Add P2P RSSI Link Quality Query Support. (Default Off) + * + * 11 16 2011 yuche.tsai + * NULL + * Avoid using work thread. + * + * 11 11 2011 yuche.tsai + * NULL + * Fix work thread cancel issue. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 04 14 2011 cp.wu + * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for RESET_START and RESET_END events + * sync. whole-chip resetting mechanism to V2.0 branch. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 03 03 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * support concurrent network + * + * 03 03 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * modify net device relative functions to support multiple H/W queues + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * Add security check code. + * + * 02 21 2011 cp.wu + * [WCXRP00000482] [MT6620 Wi-Fi][Driver] Simplify logic for checking NVRAM existence in driver domain + * simplify logic for checking NVRAM existence only once. + * + * 02 16 2011 jeffrey.chang + * NULL + * Add query ipv4 and ipv6 address during early suspend and late resume + * + * 02 10 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Fix kernel API change issue. + * Before ALPS 2.2 (2.2 included), kfifo_alloc() is + * struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock); + * After ALPS 2.3, kfifo_alloc() is changed to + * int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask); + * + * 02 09 2011 wh.su + * [WCXRP00000433] [MT6620 Wi-Fi][Driver] Remove WAPI structure define for avoid P2P module with structure miss-align pointer issue + * always pre-allio WAPI related structure for align p2p module. + * + * 02 09 2011 terry.wu + * [WCXRP00000383] [MT6620 Wi-Fi][Driver] Separate WiFi and P2P driver into two modules + * Halt p2p module init and exit until TxThread finished p2p register and unregister. + * + * 02 01 2011 cm.chang + * [WCXRP00000415] [MT6620 Wi-Fi][Driver] Check if any memory leakage happens when uninitializing in DGB mode + * . + * + * 01 27 2011 cm.chang + * [WCXRP00000402] [MT6620 Wi-Fi][Driver] Enable MCR read/write by iwpriv by default + * . + * + * 01 12 2011 cp.wu + * [WCXRP00000357] [MT6620 Wi-Fi][Driver][Bluetooth over Wi-Fi] add another net device interface for BT AMP + * implementation of separate BT_OVER_WIFI data path. + * + * 01 12 2011 cp.wu + * [WCXRP00000356] [MT6620 Wi-Fi][Driver] fill mac header length for security frames 'cause hardware header translation needs such information + * fill mac header length information for 802.1x frames. + * + * 01 11 2011 chinglan.wang + * NULL + * Modify to reslove the CR :[ALPS00028994] Use WEP security to connect Marvell 11N AP. Connection establish successfully. + * Use the WPS function to connect AP, the privacy bit always is set to 1. + * + * 01 10 2011 cp.wu + * [WCXRP00000349] [MT6620 Wi-Fi][Driver] make kalIoctl() of linux port as a thread safe API to avoid potential issues due to multiple access + * use mutex to protect kalIoctl() for thread safe. + * + * 01 05 2011 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service Discovery + * ioctl implementations for P2P Service Discovery + * + * 11 04 2010 wh.su + * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID + * adding the p2p random ssid support. + * + * 10 18 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android + * complete implementation of Android NVRAM access + * + * 09 28 2010 wh.su + * NULL + * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. + * + * 09 23 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * add skeleton for NVRAM integration + * + * 09 13 2010 cp.wu + * NULL + * add waitq for poll() and read(). + * + * 09 07 2010 wh.su + * NULL + * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. + * + * 09 06 2010 wh.su + * NULL + * let the p2p can set the privacy bit at beacon and rsn ie at assoc req at key handshake state. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 09 01 2010 wh.su + * NULL + * adding the wapi support for integration test. + * + * 08 31 2010 kevin.huang + * NULL + * Use LINK LIST operation to process SCAN result + * + * 08 23 2010 cp.wu + * NULL + * revise constant definitions to be matched with implementation (original cmd-event definition is deprecated) + * + * 08 16 2010 cp.wu + * NULL + * P2P packets are now marked when being queued into driver, and identified later without checking MAC address + * + * 08 16 2010 cp.wu + * NULL + * revised implementation of Wi-Fi Direct io controls. + * + * 08 11 2010 cp.wu + * NULL + * 1) do not use in-stack variable for beacon updating. (for MAUI porting) + * 2) extending scanning result to 64 instead of 48 + * + * 08 06 2010 cp.wu + * NULL + * driver hook modifications corresponding to ioctl interface change. + * + * 08 03 2010 cp.wu + * NULL + * [Wi-Fi Direct] add framework for driver hooks + * + * 08 02 2010 jeffrey.chang + * NULL + * 1) modify tx service thread to avoid busy looping + * 2) add spin lock declartion for linux build + * + * 07 23 2010 jeffrey.chang + * + * add new KAL api + * + * 07 22 2010 jeffrey.chang + * + * modify tx thread and remove some spinlock + * + * 07 19 2010 jeffrey.chang + * + * add security frame pending count + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 06 01 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add ioctl to configure scan mode for p2p connection + * + * 05 31 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add cfg80211 interface, which is to replace WE, for further extension + * + * 05 14 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add ioctl framework for Wi-Fi Direct by reusing wireless extension ioctls as well + * + * 05 11 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * p2p ioctls revised. + * + * 05 11 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add ioctl for controlling p2p scan phase parameters + * + * 05 10 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * implement basic wi-fi direct framework + * + * 05 07 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * prevent supplicant accessing driver during resume + * + * 05 07 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add basic framework for implementating P2P driver hook. + * + * 05 05 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * change variable names for multiple physical link to match with coding convention + * + * 04 27 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * identify BT Over Wi-Fi Security frame and mark it as 802.1X frame + * + * 04 27 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add multiple physical link support + * + * 04 27 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * 1) fix firmware download bug + * 2) remove query statistics for acelerating firmware download + * + * 04 27 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * follow Linux's firmware framework, and remove unused kal API + * + * 04 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * surpress compiler warning + * + * 04 19 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * supporting power management + * + * 04 14 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * pvInformationBuffer and u4InformationBufferLength are no longer in glue + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * * * * * * * * * * * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * rWlanInfo should be placed at adapter rather than glue due to most operations + * * * * * * * * * * are done in adapter layer. + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Tag the packet for QoS on Tx path + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * (1)deliver the kalOidComplete status to upper layer + * * (2) fix spin lock + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * add timeout check in the kalOidComplete + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * improve none-glue code portability + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer + * + * 03 30 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * emulate NDIS Pending OID facility + * + * 03 26 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * [WPD00003826] Initial import for Linux port + * adding firmware download related data type + * + * 03 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) correct OID_802_11_CONFIGURATION with frequency setting behavior. + * * * * the frequency is used for adhoc connection only + * * * * 2) update with SD1 v0.9 CMD/EVENT documentation + * + * 03 25 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add Bluetooth-over-Wifi frame header check + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port +** \main\maintrunk.MT5921\30 2009-10-20 17:38:31 GMT mtk01090 +** Refine driver unloading and clean up procedure. Block requests, stop main thread and clean up queued requests, and then stop hw. +** \main\maintrunk.MT5921\29 2009-10-08 10:33:33 GMT mtk01090 +** Avoid accessing private data of net_device directly. Replace with netdev_priv(). Add more checking for input parameters and pointers. +** \main\maintrunk.MT5921\28 2009-09-28 20:19:26 GMT mtk01090 +** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. +** \main\maintrunk.MT5921\27 2009-08-18 22:57:12 GMT mtk01090 +** Add Linux SDIO (with mmc core) support. +** Add Linux 2.6.21, 2.6.25, 2.6.26. +** Fix compile warning in Linux. +** \main\maintrunk.MT5921\26 2009-07-06 21:42:25 GMT mtk01088 +** fixed the compiling error at linux +** \main\maintrunk.MT5921\25 2009-07-06 20:51:46 GMT mtk01088 +** adding the wapi 1x ether type define +** \main\maintrunk.MT5921\24 2009-06-23 23:19:18 GMT mtk01090 +** Add build option BUILD_USE_EEPROM and compile option CFG_SUPPORT_EXT_CONFIG for NVRAM support +** \main\maintrunk.MT5921\23 2009-02-07 15:05:06 GMT mtk01088 +** add the privacy flag to ingo driver the supplicant selected ap's security +** \main\maintrunk.MT5921\22 2009-02-05 15:34:09 GMT mtk01088 +** fixed the compiling error for using bits marco for only one parameter +** \main\maintrunk.MT5921\21 2009-01-22 13:02:13 GMT mtk01088 +** data frame is or not 802.1x value share with tid, using the same reserved byte, provide the function to set and get +** \main\maintrunk.MT5921\20 2008-10-24 12:04:16 GMT mtk01088 +** move the config.h from precomp.h to here for lint check +** \main\maintrunk.MT5921\19 2008-09-22 23:19:02 GMT mtk01461 +** Update driver for code review +** \main\maintrunk.MT5921\18 2008-09-05 17:25:13 GMT mtk01461 +** Update Driver for Code Review +** \main\maintrunk.MT5921\17 2008-08-01 13:32:47 GMT mtk01084 +** Prevent redundent driver assertion in driver logic when BUS is detached +** \main\maintrunk.MT5921\16 2008-05-30 14:41:43 GMT mtk01461 +** Remove WMM Assoc Flag in KAL +** \main\maintrunk.MT5921\15 2008-05-29 14:16:25 GMT mtk01084 +** remoev un-used variable +** \main\maintrunk.MT5921\14 2008-05-03 15:17:14 GMT mtk01461 +** Add Media Status variable in Glue Layer +** \main\maintrunk.MT5921\13 2008-04-24 11:58:41 GMT mtk01461 +** change threshold to 256 +** \main\maintrunk.MT5921\12 2008-03-11 14:51:05 GMT mtk01461 +** Remove redundant GL_CONN_INFO_T +** \main\maintrunk.MT5921\11 2008-01-07 15:07:41 GMT mtk01461 +** Adjust the netif stop threshold to 150 +** \main\maintrunk.MT5921\10 2007-11-26 19:43:46 GMT mtk01461 +** Add OS_TIMESTAMP macro +** +** \main\maintrunk.MT5921\9 2007-11-07 18:38:38 GMT mtk01461 +** Move definition +** \main\maintrunk.MT5921\8 2007-11-02 01:04:00 GMT mtk01461 +** Unify TX Path for Normal and IBSS Power Save + IBSS neighbor learning +** Revision 1.5 2007/07/12 11:04:28 MTK01084 +** update macro to delay for ms order +** +** Revision 1.4 2007/07/05 07:25:34 MTK01461 +** Add Linux initial code, modify doc, add 11BB, RF init code +** +** Revision 1.3 2007/06/27 02:18:51 MTK01461 +** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API +** +** Revision 1.2 2007/06/25 06:16:24 MTK01461 +** Update illustrations, gl_init.c, gl_kal.c, gl_kal.h, gl_os.h and RX API +** +*/ + +#ifndef _GL_OS_H +#define _GL_OS_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +/*------------------------------------------------------------------------------ + * Flags for LINUX(OS) dependent + *------------------------------------------------------------------------------ + */ +#define CFG_MAX_WLAN_DEVICES 1 /* number of wlan card will coexist*/ + +#define CFG_MAX_TXQ_NUM 4 /* number of tx queue for support multi-queue h/w */ + + +#define CFG_USE_SPIN_LOCK_BOTTOM_HALF 0 /* 1: Enable use of SPIN LOCK Bottom Half for LINUX + 0: Disable - use SPIN LOCK IRQ SAVE instead */ + +#define CFG_TX_PADDING_SMALL_ETH_PACKET 0 /* 1: Enable - Drop ethernet packet if it < 14 bytes. + And pad ethernet packet with dummy 0 if it < 60 bytes. + 0: Disable */ + +#define CFG_TX_STOP_NETIF_QUEUE_THRESHOLD 256 /* packets */ + +#define CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD 64 /* packets */ +#define CFG_TX_START_NETIF_PER_QUEUE_THRESHOLD 32 /* packets */ + + +#define ETH_P_1X 0x888E +#define IPTOS_PREC_OFFSET 5 +#define USER_PRIORITY_DEFAULT 0 + +#define ETH_WPI_1X 0x88B4 + +#define ETH_HLEN 14 +#define ETH_TYPE_LEN_OFFSET 12 +#define ETH_P_IP 0x0800 +#define ETH_P_1X 0x888E +#define ETH_P_PRE_1X 0x88C7 + +#define IPVERSION 4 +#define IP_HEADER_LEN 20 + +#define IPVH_VERSION_OFFSET 4 // For Little-Endian +#define IPVH_VERSION_MASK 0xF0 +#define IPTOS_PREC_OFFSET 5 +#define IPTOS_PREC_MASK 0xE0 + +#define SOURCE_PORT_LEN 2 +/* NOTE(Kevin): Without IP Option Length */ +#define LOOK_AHEAD_LEN (ETH_HLEN + IP_HEADER_LEN + SOURCE_PORT_LEN) + +/* 802.2 LLC/SNAP */ +#define ETH_LLC_OFFSET (ETH_HLEN) +#define ETH_LLC_LEN 3 +#define ETH_LLC_DSAP_SNAP 0xAA +#define ETH_LLC_SSAP_SNAP 0xAA +#define ETH_LLC_CONTROL_UNNUMBERED_INFORMATION 0x03 + +/* Bluetooth SNAP */ +#define ETH_SNAP_OFFSET (ETH_HLEN + ETH_LLC_LEN) +#define ETH_SNAP_LEN 5 +#define ETH_SNAP_BT_SIG_OUI_0 0x00 +#define ETH_SNAP_BT_SIG_OUI_1 0x19 +#define ETH_SNAP_BT_SIG_OUI_2 0x58 + +#define BOW_PROTOCOL_ID_SECURITY_FRAME 0x0003 + + +#if defined(MT6620) + #define DRV_NAME "[MT6620]: " +#elif defined(MT5931) + #define DRV_NAME "[MT5931]: " +#elif defined(MT6628) + #define DRV_NAME "[MT6628]: " +#endif + +/* Define if target platform is Android. + * It should already be defined in Android kernel source + */ +#ifndef CONFIG_ANDROID +#define CONFIG_ANDROID 0 +#endif + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include /* constant of kernel version */ + +#include /* bitops.h */ + +#include /* struct timer_list */ +#include /* jiffies */ +#include /* udelay and mdelay macro */ + +#if CONFIG_ANDROID +#include +#endif + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 12) +#include /* IRQT_FALLING */ +#endif + +#include /* struct net_device, struct net_device_stats */ +#include /* for eth_type_trans() function */ +#include /* struct iw_statistics */ +#include +#include /* struct in_device */ + +#include /* struct iphdr */ + +#include /* for memcpy()/memset() function */ +#include /* for offsetof() macro */ + +#include /* The proc filesystem constants/structures */ + +#include /* for rtnl_lock() and rtnl_unlock() */ +#include /* kthread_should_stop(), kthread_run() */ +#include /* for copy_from_user() */ +#include /* for firmware download */ +#include + +#include /* for kfifo interface */ +#include /* for cdev interface */ + +#include /* for firmware download */ + +#if defined(_HIF_SDIO) +#include +#include +#endif + +#include + + +#include /* readw and writew */ + +#if WIRELESS_EXT > 12 +#include +#endif + +#include "version.h" +#include "config.h" + +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 +#include +#include +#endif + +#include "gl_typedef.h" +#include "typedef.h" +#include "queue.h" +#include "gl_kal.h" +#if CFG_CHIP_RESET_SUPPORT + #include "gl_rst.h" +#endif +#include "hif.h" + + +#include "debug.h" + +#include "wlan_lib.h" +#include "wlan_oid.h" + + +extern BOOLEAN fgIsBusAccessFailed; + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define GLUE_FLAG_HALT BIT(0) +#define GLUE_FLAG_INT BIT(1) +#define GLUE_FLAG_OID BIT(2) +#define GLUE_FLAG_TIMEOUT BIT(3) +#define GLUE_FLAG_TXREQ BIT(4) +#define GLUE_FLAG_SUB_MOD_INIT BIT(5) +#define GLUE_FLAG_SUB_MOD_EXIT BIT(6) +#define GLUE_FLAG_SUB_MOD_MULTICAST BIT(7) +#define GLUE_FLAG_HALT_BIT (0) +#define GLUE_FLAG_INT_BIT (1) +#define GLUE_FLAG_OID_BIT (2) +#define GLUE_FLAG_TIMEOUT_BIT (3) +#define GLUE_FLAG_TXREQ_BIT (4) +#define GLUE_FLAG_SUB_MOD_INIT_BIT (5) +#define GLUE_FLAG_SUB_MOD_EXIT_BIT (6) +#define GLUE_FLAG_SUB_MOD_MULTICAST_BIT (7) + + + +#define GLUE_BOW_KFIFO_DEPTH (1024) +//#define GLUE_BOW_DEVICE_NAME "MT6620 802.11 AMP" +#define GLUE_BOW_DEVICE_NAME "ampc0" + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef struct _GL_WPA_INFO_T { + UINT_32 u4WpaVersion; + UINT_32 u4KeyMgmt; + UINT_32 u4CipherGroup; + UINT_32 u4CipherPairwise; + UINT_32 u4AuthAlg; + BOOLEAN fgPrivacyInvoke; +#if CFG_SUPPORT_802_11W + UINT_32 u4Mfp; +#endif +} GL_WPA_INFO_T, *P_GL_WPA_INFO_T; + +typedef enum _ENUM_RSSI_TRIGGER_TYPE { + ENUM_RSSI_TRIGGER_NONE, + ENUM_RSSI_TRIGGER_GREATER, + ENUM_RSSI_TRIGGER_LESS, + ENUM_RSSI_TRIGGER_TRIGGERED, + ENUM_RSSI_TRIGGER_NUM +} ENUM_RSSI_TRIGGER_TYPE; + +#if CFG_ENABLE_WIFI_DIRECT +typedef enum _ENUM_SUB_MODULE_IDX_T { + P2P_MODULE = 0, + SUB_MODULE_NUM +} ENUM_SUB_MODULE_IDX_T; +#endif + +typedef struct _GL_IO_REQ_T { + QUE_ENTRY_T rQueEntry; + //wait_queue_head_t cmdwait_q; + BOOL fgRead; + BOOL fgWaitResp; +#if CFG_ENABLE_WIFI_DIRECT + BOOL fgIsP2pOid; +#endif + P_ADAPTER_T prAdapter; + PFN_OID_HANDLER_FUNC pfnOidHandler; + PVOID pvInfoBuf; + UINT_32 u4InfoBufLen; + PUINT_32 pu4QryInfoLen; + WLAN_STATUS rStatus; + UINT_32 u4Flag; +} GL_IO_REQ_T, *P_GL_IO_REQ_T; + +#if CFG_ENABLE_BT_OVER_WIFI +typedef struct _GL_BOW_INFO { + BOOLEAN fgIsRegistered; + dev_t u4DeviceNumber; /* dynamic device number */ +// struct kfifo *prKfifo; /* for buffering indicated events */ + struct kfifo rKfifo; /* for buffering indicated events */ + spinlock_t rSpinLock; /* spin lock for kfifo */ + struct cdev cdev; + UINT_32 u4FreqInKHz; /* frequency */ + + UINT_8 aucRole[CFG_BOW_PHYSICAL_LINK_NUM]; /* 0: Responder, 1: Initiator */ + ENUM_BOW_DEVICE_STATE aeState[CFG_BOW_PHYSICAL_LINK_NUM]; + PARAM_MAC_ADDRESS arPeerAddr[CFG_BOW_PHYSICAL_LINK_NUM]; + + wait_queue_head_t outq; + + #if CFG_BOW_SEPARATE_DATA_PATH + /* Device handle */ + struct net_device *prDevHandler; + BOOLEAN fgIsNetRegistered; + #endif + +} GL_BOW_INFO, *P_GL_BOW_INFO; +#endif + +/* +* type definition of pointer to p2p structure +*/ +typedef struct _GL_P2P_INFO_T GL_P2P_INFO_T, *P_GL_P2P_INFO_T; + +struct _GLUE_INFO_T { + /* Device handle */ + struct net_device *prDevHandler; + + /* Device Index(index of arWlanDevInfo[]) */ + INT_32 i4DevIdx; + + /* Device statistics */ + struct net_device_stats rNetDevStats; + + /* Wireless statistics struct net_device */ + struct iw_statistics rIwStats; + + /* spinlock to sync power save mechanism */ + spinlock_t rSpinLock[SPIN_LOCK_NUM]; + + /* semaphore for ioctl */ + struct semaphore ioctl_sem; + + UINT_32 u4Flag; /* GLUE_FLAG_XXX */ + UINT_32 u4PendFlag; + //UINT_32 u4TimeoutFlag; + UINT_32 u4ReadyFlag; /* check if card is ready */ + + /* Number of pending frames, also used for debuging if any frame is + * missing during the process of unloading Driver. + * + * NOTE(Kevin): In Linux, we also use this variable as the threshold + * for manipulating the netif_stop(wake)_queue() func. + */ + INT_32 ai4TxPendingFrameNumPerQueue[4][CFG_MAX_TXQ_NUM]; + INT_32 i4TxPendingFrameNum; + INT_32 i4TxPendingSecurityFrameNum; + + /* current IO request for kalIoctl */ + GL_IO_REQ_T OidEntry; + + /* registry info*/ + REG_INFO_T rRegInfo; + + /* firmware */ + struct firmware *prFw; + + /* Host interface related information */ + /* defined in related hif header file */ + GL_HIF_INFO_T rHifInfo; + + /*! \brief wext wpa related information */ + GL_WPA_INFO_T rWpaInfo; + + + /* Pointer to ADAPTER_T - main data structure of internal protocol stack */ + P_ADAPTER_T prAdapter; + +#ifdef WLAN_INCLUDE_PROC + struct proc_dir_entry *pProcRoot; +#endif /* WLAN_INCLUDE_PROC */ + + /* Indicated media state */ + ENUM_PARAM_MEDIA_STATE_T eParamMediaStateIndicated; + + /* Device power state D0~D3 */ + PARAM_DEVICE_POWER_STATE ePowerState; + + struct completion rScanComp; /* indicate scan complete */ + struct completion rHaltComp; /* indicate main thread halt complete */ + struct completion rPendComp; /* indicate main thread halt complete */ +#if CFG_ENABLE_WIFI_DIRECT + struct completion rSubModComp; /*indicate sub module init or exit complete*/ +#endif + WLAN_STATUS rPendStatus; + + QUE_T rTxQueue; + + + /* OID related */ + QUE_T rCmdQueue; + //PVOID pvInformationBuffer; + //UINT_32 u4InformationBufferLength; + //PVOID pvOidEntry; + //PUINT_8 pucIOReqBuff; + //QUE_T rIOReqQueue; + //QUE_T rFreeIOReqQueue; + + wait_queue_head_t waitq; + struct task_struct *main_thread; + + struct timer_list tickfn; + + +#if CFG_SUPPORT_EXT_CONFIG + UINT_16 au2ExtCfg[256]; /* NVRAM data buffer */ + UINT_32 u4ExtCfgLength; /* 0 means data is NOT valid */ +#endif + +#if 1//CFG_SUPPORT_WAPI + /* Should be large than the PARAM_WAPI_ASSOC_INFO_T */ + UINT_8 aucWapiAssocInfoIEs[42]; + UINT_16 u2WapiAssocInfoIESz; +#endif + +#if CFG_ENABLE_BT_OVER_WIFI + GL_BOW_INFO rBowInfo; +#endif + +#if CFG_ENABLE_WIFI_DIRECT + P_GL_P2P_INFO_T prP2PInfo; +#if CFG_SUPPORT_P2P_RSSI_QUERY + /* Wireless statistics struct net_device */ + struct iw_statistics rP2pIwStats; +#endif +#endif + BOOLEAN fgWpsActive; + UINT_8 aucWSCIE[500]; /*for probe req*/ + UINT_16 u2WSCIELen; + UINT_8 aucWSCAssocInfoIE[200]; /*for Assoc req*/ + UINT_16 u2WSCAssocInfoIELen; + + /* NVRAM availability */ + BOOLEAN fgNvramAvailable; + + BOOLEAN fgMcrAccessAllowed; + + /* MAC Address Overriden by IOCTL */ + BOOLEAN fgIsMacAddrOverride; + PARAM_MAC_ADDRESS rMacAddrOverride; + + SET_TXPWR_CTRL_T rTxPwr; +}; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) + /* linux 2.4 */ + typedef void (*PFN_WLANISR)(int irq, void *dev_id, struct pt_regs *regs); +#else + typedef irqreturn_t (*PFN_WLANISR)(int irq, void *dev_id, struct pt_regs *regs); +#endif + +typedef void (*PFN_LINUX_TIMER_FUNC)(unsigned long); + + +/* generic sub module init/exit handler +* now, we only have one sub module, p2p +*/ +#if CFG_ENABLE_WIFI_DIRECT +typedef BOOLEAN (*SUB_MODULE_INIT)(P_GLUE_INFO_T prGlueInfo); +typedef BOOLEAN (*SUB_MODULE_EXIT)(P_GLUE_INFO_T prGlueInfo); + +typedef struct _SUB_MODULE_HANDLER { + SUB_MODULE_INIT subModInit; + SUB_MODULE_EXIT subModExit; + BOOLEAN fgIsInited; +} SUB_MODULE_HANDLER, *P_SUB_MODULE_HANDLER; + +#endif + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Macros of SPIN LOCK operations for using in Glue Layer */ +/*----------------------------------------------------------------------------*/ +#if CFG_USE_SPIN_LOCK_BOTTOM_HALF + #define GLUE_SPIN_LOCK_DECLARATION() + #define GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, rLockCategory) \ + { \ + if (rLockCategory < SPIN_LOCK_NUM) \ + spin_lock_bh(&(prGlueInfo->rSpinLock[rLockCategory])); \ + } + #define GLUE_RELEASE_SPIN_LOCK(prGlueInfo, rLockCategory) \ + { \ + if (rLockCategory < SPIN_LOCK_NUM) \ + spin_unlock_bh(&(prGlueInfo->rSpinLock[rLockCategory])); \ + } +#else /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ + #define GLUE_SPIN_LOCK_DECLARATION() UINT_32 __u4Flags = 0 + #define GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, rLockCategory) \ + { \ + if (rLockCategory < SPIN_LOCK_NUM) \ + spin_lock_irqsave(&(prGlueInfo)->rSpinLock[rLockCategory], __u4Flags); \ + } + #define GLUE_RELEASE_SPIN_LOCK(prGlueInfo, rLockCategory) \ + { \ + if (rLockCategory < SPIN_LOCK_NUM) \ + spin_unlock_irqrestore(&(prGlueInfo->rSpinLock[rLockCategory]), __u4Flags); \ + } +#endif /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ + + +/*----------------------------------------------------------------------------*/ +/* Macros for accessing Reserved Fields of native packet */ +/*----------------------------------------------------------------------------*/ +#define GLUE_GET_PKT_QUEUE_ENTRY(_p) \ + (&( ((struct sk_buff *)(_p))->cb[0] )) + +#define GLUE_GET_PKT_DESCRIPTOR(_prQueueEntry) \ + ((P_NATIVE_PACKET) ((UINT_32)_prQueueEntry - offsetof(struct sk_buff, cb[0])) ) + +#define GLUE_SET_PKT_FLAG_802_11(_p) \ + (*((PUINT_8) &( ((struct sk_buff *)(_p))->cb[4] )) |= BIT(7)) + +#define GLUE_SET_PKT_FLAG_1X(_p) \ + (*((PUINT_8) &( ((struct sk_buff *)(_p))->cb[4] )) |= BIT(6)) + +#define GLUE_SET_PKT_FLAG_PAL(_p) \ + (*((PUINT_8) &( ((struct sk_buff *)(_p))->cb[4] )) |= BIT(5)) + +#define GLUE_SET_PKT_FLAG_P2P(_p) \ + (*((PUINT_8) &( ((struct sk_buff *)(_p))->cb[4] )) |= BIT(4)) + + + +#define GLUE_SET_PKT_TID(_p, _tid) \ + (*((PUINT_8) &( ((struct sk_buff *)(_p))->cb[4] )) |= (((UINT_8)((_tid) & (BITS(0,3)))))) + + +#define GLUE_SET_PKT_FRAME_LEN(_p, _u2PayloadLen) \ + (*((PUINT_16) &( ((struct sk_buff *)(_p))->cb[6] )) = (UINT_16)(_u2PayloadLen)) + +#define GLUE_GET_PKT_FRAME_LEN(_p) \ + (*((PUINT_16) &( ((struct sk_buff *)(_p))->cb[6] )) ) + + +#define GLUE_GET_PKT_IS_802_11(_p) \ + ((*((PUINT_8) &( ((struct sk_buff *)(_p))->cb[4] )) ) & (BIT(7))) + +#define GLUE_GET_PKT_IS_1X(_p) \ + ((*((PUINT_8) &( ((struct sk_buff *)(_p))->cb[4] )) ) & (BIT(6))) + +#define GLUE_GET_PKT_TID(_p) \ + ((*((PUINT_8) &( ((struct sk_buff *)(_p))->cb[4] )) ) & (BITS(0,3))) + + +#define GLUE_GET_PKT_IS_PAL(_p) \ + ((*((PUINT_8) &( ((struct sk_buff *)(_p))->cb[4] )) ) & (BIT(5))) + +#define GLUE_GET_PKT_IS_P2P(_p) \ + ((*((PUINT_8) &( ((struct sk_buff *)(_p))->cb[4] )) ) & (BIT(4))) + + +#define GLUE_SET_PKT_HEADER_LEN(_p, _ucMacHeaderLen) \ + (*((PUINT_8) &( ((struct sk_buff *)(_p))->cb[5] )) = (UINT_8)(_ucMacHeaderLen)) + +#define GLUE_GET_PKT_HEADER_LEN(_p) \ + (*((PUINT_8) &( ((struct sk_buff *)(_p))->cb[5] )) ) + +#define GLUE_SET_PKT_ARRIVAL_TIME(_p, _rSysTime) \ + (*((POS_SYSTIME) &( ((struct sk_buff *)(_p))->cb[8] )) = (OS_SYSTIME)(_rSysTime)) + +#define GLUE_GET_PKT_ARRIVAL_TIME(_p) \ + (*((POS_SYSTIME) &( ((struct sk_buff *)(_p))->cb[8] )) ) + +/* Check validity of prDev, private data, and pointers */ +#define GLUE_CHK_DEV(prDev) \ + ((prDev && netdev_priv(prDev)) ? TRUE : FALSE) + +#define GLUE_CHK_PR2(prDev, pr2) \ + ((GLUE_CHK_DEV(prDev) && pr2) ? TRUE : FALSE) + +#define GLUE_CHK_PR3(prDev, pr2, pr3) \ + ((GLUE_CHK_PR2(prDev, pr2) && pr3) ? TRUE : FALSE) + +#define GLUE_CHK_PR4(prDev, pr2, pr3, pr4) \ + ((GLUE_CHK_PR3(prDev, pr2, pr3) && pr4) ? TRUE : FALSE) + +#define GLUE_SET_EVENT(pr) \ + kalSetEvent(pr) + +#define GLUE_INC_REF_CNT(_refCount) atomic_inc((atomic_t *)&(_refCount)) +#define GLUE_DEC_REF_CNT(_refCount) atomic_dec((atomic_t *)&(_refCount)) + + +#define DbgPrint(...) +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +#ifdef WLAN_INCLUDE_PROC +INT_32 +procRemoveProcfs ( + struct net_device *prDev, + char *pucDevName + ); + +INT_32 +procInitProcfs ( + struct net_device *prDev, + char *pucDevName + ); +#endif /* WLAN_INCLUDE_PROC */ + +#if CFG_ENABLE_BT_OVER_WIFI +BOOLEAN +glRegisterAmpc ( + P_GLUE_INFO_T prGlueInfo + ); + +BOOLEAN +glUnregisterAmpc ( + P_GLUE_INFO_T prGlueInfo + ); +#endif + +#if CFG_ENABLE_WIFI_DIRECT + +VOID +wlanSubModRunInit( + P_GLUE_INFO_T prGlueInfo + ); + +VOID +wlanSubModRunExit( + P_GLUE_INFO_T prGlueInfo + ); + +BOOLEAN +wlanSubModInit( + P_GLUE_INFO_T prGlueInfo + ); + +BOOLEAN +wlanSubModExit( + P_GLUE_INFO_T prGlueInfo + ); + +VOID +wlanSubModRegisterInitExit( + SUB_MODULE_INIT rSubModInit, + SUB_MODULE_EXIT rSubModExit, + ENUM_SUB_MODULE_IDX_T eSubModIdx + ); + +BOOLEAN +wlanExportGlueInfo( + P_GLUE_INFO_T *prGlueInfoExpAddr + ); + +BOOLEAN +wlanIsLaunched( + VOID + ); + +void +p2pSetMulticastListWorkQueueWrapper( + P_GLUE_INFO_T prGlueInfo + ); + + + +#endif + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _GL_OS_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_rst.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_rst.h new file mode 100755 index 000000000000..be2c30913096 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_rst.h @@ -0,0 +1,171 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/os/linux/include/gl_rst.h#1 $ +*/ + +/*! \file gl_rst.h + \brief Declaration of functions and finite state machine for + MT6620 Whole-Chip Reset Mechanism +*/ + +/******************************************************************************* +* Copyright (c) 2010 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + + +#ifndef _GL_RST_H +#define _GL_RST_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "gl_typedef.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* duplicated from wmt_exp.h for better driver isolation */ +typedef enum _ENUM_WMTDRV_TYPE_T { + WMTDRV_TYPE_BT = 0, + WMTDRV_TYPE_FM = 1, + WMTDRV_TYPE_GPS = 2, + WMTDRV_TYPE_WIFI = 3, + WMTDRV_TYPE_WMT = 4, + WMTDRV_TYPE_STP = 5, + WMTDRV_TYPE_SDIO1 = 6, + WMTDRV_TYPE_SDIO2 = 7, + WMTDRV_TYPE_LPBK = 8, + WMTDRV_TYPE_MAX +} ENUM_WMTDRV_TYPE_T, *P_ENUM_WMTDRV_TYPE_T; + +typedef enum _ENUM_WMTMSG_TYPE_T { + WMTMSG_TYPE_POWER_ON = 0, + WMTMSG_TYPE_POWER_OFF = 1, + WMTMSG_TYPE_RESET = 2, + WMTMSG_TYPE_STP_RDY= 3, + WMTMSG_TYPE_HW_FUNC_ON= 4, + WMTMSG_TYPE_MAX +} ENUM_WMTMSG_TYPE_T, *P_ENUM_WMTMSG_TYPE_T; + +typedef enum _ENUM_WMTRSTMSG_TYPE_T{ + WMTRSTMSG_RESET_START = 0x0, + WMTRSTMSG_RESET_END = 0x1, + WMTRSTMSG_RESET_MAX, + WMTRSTMSG_RESET_INVALID = 0xff +} ENUM_WMTRSTMSG_TYPE_T, *P_ENUM_WMTRSTMSG_TYPE_T; + +typedef void (*PF_WMT_CB)( + ENUM_WMTDRV_TYPE_T, /* Source driver type */ + ENUM_WMTDRV_TYPE_T, /* Destination driver type */ + ENUM_WMTMSG_TYPE_T, /* Message type */ + void *, /* READ-ONLY buffer. Buffer is allocated and freed by WMT_drv. Client + can't touch this buffer after this function return. */ + unsigned int /* Buffer size in unit of byte */ + ); + + +typedef enum _ENUM_WIFI_NETLINK_GRP_T{ + WIFI_NETLINK_GRP_RESET, + WIFI_NETLINK_GRP_MAX +} ENUM_WIFI_NETLINK_GRP_T, *P_ENUM_WIFI_NETLINK_GRP_T; + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/* Reset Initialization/Uninitialization */ +/*----------------------------------------------------------------------------*/ +VOID +glResetInit( + VOID + ); + +VOID +glResetUninit( + VOID + ); + +VOID +glSendResetRequest( + VOID + ); + +BOOLEAN +kalIsResetting( + VOID + ); + + +#endif /* _GL_RST_H */ diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_sec.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_sec.h new file mode 100755 index 000000000000..fe77d89ae78a --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_sec.h @@ -0,0 +1,64 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/os/linux/include/gl_sec.h#1 $ +*/ + +/*! \file p2p_fsm.h + \brief Declaration of functions and finite state machine for P2P Module. + + Declaration of functions and finite state machine for P2P Module. +*/ + +/******************************************************************************* +* Copyright (c) 2010 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + + +#ifndef _GL_SEC_H +#define _GL_SEC_H + +extern void handle_sec_msg_1(unsigned char *msg_in, int msg_in_len, unsigned char *msg_out, int *msg_out_len); +extern void handle_sec_msg_2(unsigned char *msg_in, int msg_in_len, unsigned char *msg_out, int *msg_out_len); +extern void handle_sec_msg_3(unsigned char *msg_in, int msg_in_len, unsigned char *msg_out, int *msg_out_len); +extern void handle_sec_msg_4(unsigned char *msg_in, int msg_in_len, unsigned char *msg_out, int *msg_out_len); +extern void handle_sec_msg_5(unsigned char *msg_in, int msg_in_len, unsigned char *msg_out, int *msg_out_len); +extern void handle_sec_msg_final(unsigned char *msg_in, int msg_in_len, unsigned char *msg_out, int *msg_out_len); + +#endif /* _GL_SEC_H */ diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_typedef.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_typedef.h new file mode 100755 index 000000000000..31b6b0d2fc33 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_typedef.h @@ -0,0 +1,320 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/os/linux/include/gl_typedef.h#1 $ +*/ + +/*! \file gl_typedef.h + \brief Definition of basic data type(os dependent). + + In this file we define the basic data type. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: gl_typedef.h $ + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 02 15 2011 jeffrey.chang + * NULL + * to support early suspend in android + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port +** \main\maintrunk.MT5921\6 2009-08-18 22:57:14 GMT mtk01090 +** Add Linux SDIO (with mmc core) support. +** Add Linux 2.6.21, 2.6.25, 2.6.26. +** Fix compile warning in Linux. +** \main\maintrunk.MT5921\5 2008-09-22 23:19:30 GMT mtk01461 +** Update comment for code review +** \main\maintrunk.MT5921\4 2008-09-05 17:25:16 GMT mtk01461 +** Update Driver for Code Review +** \main\maintrunk.MT5921\3 2007-11-09 11:00:50 GMT mtk01425 +** 1. Use macro to unify network-to-host and host-to-network related functions +** Revision 1.3 2007/06/27 02:18:51 MTK01461 +** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API +** +** Revision 1.2 2007/06/25 06:16:24 MTK01461 +** Update illustrations, gl_init.c, gl_kal.c, gl_kal.h, gl_os.h and RX API +** +*/ + +#ifndef _GL_TYPEDEF_H +#define _GL_TYPEDEF_H + +#if defined(CONFIG_HAS_EARLYSUSPEND) +#include +#endif + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* Define HZ of timer tick for function kalGetTimeTick() */ +#define KAL_HZ (HZ) + +/* Miscellaneous Equates */ +#ifndef FALSE + #define FALSE ((BOOL) 0) + #define TRUE ((BOOL) 1) +#endif /* FALSE */ + +#ifndef NULL + #if defined(__cplusplus) + #define NULL 0 + #else + #define NULL ((void *) 0) + #endif +#endif + +#if defined(CONFIG_HAS_EARLYSUSPEND) +typedef void (*early_suspend_callback)(struct early_suspend *h); +typedef void (*late_resume_callback) (struct early_suspend *h); +#endif + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* Type definition for void */ +typedef void VOID, *PVOID, **PPVOID; + +/* Type definition for Boolean */ +typedef unsigned char BOOL, *PBOOL, BOOLEAN, *PBOOLEAN; + +/* Type definition for signed integers */ +typedef signed char CHAR, *PCHAR, **PPCHAR; +typedef signed char INT_8, *PINT_8, **PPINT_8; +typedef signed short INT_16, *PINT_16, **PPINT_16; +typedef signed long INT_32, *PINT_32, **PPINT_32; +typedef signed long long INT_64, *PINT_64, **PPINT_64; + +/* Type definition for unsigned integers */ +typedef unsigned char UCHAR, *PUCHAR, **PPUCHAR; +typedef unsigned char UINT_8, *PUINT_8, **PPUINT_8, *P_UINT_8; +typedef unsigned short UINT_16, *PUINT_16, **PPUINT_16; +typedef unsigned long ULONG, UINT_32, *PUINT_32, **PPUINT_32; +typedef unsigned long long UINT_64, *PUINT_64, **PPUINT_64; + +typedef unsigned long OS_SYSTIME, *POS_SYSTIME, **PPOS_SYSTIME; + + +/* Type definition of large integer (64bits) union to be comptaible with + * Windows definition, so we won't apply our own coding style to these data types. + * NOTE: LARGE_INTEGER must NOT be floating variable. + * : Check for big-endian compatibility. + */ +typedef union _LARGE_INTEGER { + struct { + UINT_32 LowPart; + INT_32 HighPart; + } u; + INT_64 QuadPart; +} LARGE_INTEGER, *PLARGE_INTEGER; + +typedef union _ULARGE_INTEGER { + struct { + UINT_32 LowPart; + UINT_32 HighPart; + } u; + UINT_64 QuadPart; +} ULARGE_INTEGER, *PULARGE_INTEGER; + + +typedef INT_32 (*probe_card)(PVOID pvData); +typedef VOID (*remove_card)(VOID); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define IN //volatile +#define OUT //volatile + +#define __KAL_INLINE__ static __inline__ +#define __KAL_ATTRIB_PACKED__ __attribute__((__packed__)) +#define __KAL_ATTRIB_ALIGN_4__ __attribute__ ((aligned (4))) + + +#ifndef BIT +#define BIT(n) ((UINT_32) 1UL << (n)) +#endif /* BIT */ + +#ifndef BITS +/* bits range: for example BITS(16,23) = 0xFF0000 + * ==> (BIT(m)-1) = 0x0000FFFF ~(BIT(m)-1) => 0xFFFF0000 + * ==> (BIT(n+1)-1) = 0x00FFFFFF + */ +#define BITS(m,n) (~(BIT(m)-1) & ((BIT(n) - 1) | BIT(n))) +#endif /* BIT */ + + +/* This macro returns the byte offset of a named field in a known structure + type. + _type - structure name, + _field - field name of the structure */ +#ifndef OFFSET_OF + #define OFFSET_OF(_type, _field) ((UINT_32)&(((_type *)0)->_field)) +#endif /* OFFSET_OF */ + + +/* This macro returns the base address of an instance of a structure + * given the type of the structure and the address of a field within the + * containing structure. + * _addrOfField - address of current field of the structure, + * _type - structure name, + * _field - field name of the structure + */ +#ifndef ENTRY_OF + #define ENTRY_OF(_addrOfField, _type, _field) \ + ((_type *)((PINT_8)(_addrOfField) - (PINT_8)OFFSET_OF(_type, _field))) +#endif /* ENTRY_OF */ + + +/* This macro align the input value to the DW boundary. + * _value - value need to check + */ +#ifndef ALIGN_4 + #define ALIGN_4(_value) (((_value) + 3) & ~3u) +#endif /* ALIGN_4 */ + +/* This macro check the DW alignment of the input value. + * _value - value of address need to check + */ +#ifndef IS_ALIGN_4 + #define IS_ALIGN_4(_value) (((_value) & 0x3) ? FALSE : TRUE) +#endif /* IS_ALIGN_4 */ + +#ifndef IS_NOT_ALIGN_4 + #define IS_NOT_ALIGN_4(_value) (((_value) & 0x3) ? TRUE : FALSE) +#endif /* IS_NOT_ALIGN_4 */ + + +/* This macro evaluate the input length in unit of Double Word(4 Bytes). + * _value - value in unit of Byte, output will round up to DW boundary. + */ +#ifndef BYTE_TO_DWORD + #define BYTE_TO_DWORD(_value) ((_value + 3) >> 2) +#endif /* BYTE_TO_DWORD */ + +/* This macro evaluate the input length in unit of Byte. + * _value - value in unit of DW, output is in unit of Byte. + */ +#ifndef DWORD_TO_BYTE + #define DWORD_TO_BYTE(_value) ((_value) << 2) +#endif /* DWORD_TO_BYTE */ + +#if 1 // Little-Endian + #define CONST_NTOHS(_x) __constant_ntohs(_x) + + #define CONST_HTONS(_x) __constant_htons(_x) + + #define NTOHS(_x) ntohs(_x) + + #define HTONS(_x) htons(_x) + + #define NTOHL(_x) ntohl(_x) + + #define HTONL(_x) htonl(_x) + +#else // Big-Endian + + #define CONST_NTOHS(_x) + + #define CONST_HTONS(_x) + + #define NTOHS(_x) + + #define HTONS(_x) + +#endif + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _GL_TYPEDEF_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_wext.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_wext.h new file mode 100755 index 000000000000..138411a16b4a --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_wext.h @@ -0,0 +1,413 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/os/linux/include/gl_wext.h#1 $ +*/ + +/*! \file gl_wext.h + \brief This file is for Portable Driver linux wireless extension support. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: gl_wext.h $ + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 01 11 2011 chinglan.wang + * NULL + * Modify to reslove the CR :[ALPS00028994] Use WEP security to connect Marvell 11N AP. Connection establish successfully. + * Use the WPS function to connect AP, the privacy bit always is set to 1. . + * + * 09 27 2010 wh.su + * NULL + * [WCXRP00000067][MT6620 Wi-Fi][Driver] Support the android+ WAPI function. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 03 31 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * modify the wapi related code for new driver's design. + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port +** \main\maintrunk.MT5921\12 2009-10-20 17:38:33 GMT mtk01090 +** Refine driver unloading and clean up procedure. Block requests, stop main thread and clean up queued requests, and then stop hw. +** \main\maintrunk.MT5921\11 2009-09-28 20:19:28 GMT mtk01090 +** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. +** \main\maintrunk.MT5921\10 2009-09-03 12:12:35 GMT mtk01088 +** adding the function declaration +** \main\maintrunk.MT5921\9 2009-08-18 22:57:17 GMT mtk01090 +** Add Linux SDIO (with mmc core) support. +** Add Linux 2.6.21, 2.6.25, 2.6.26. +** Fix compile warning in Linux. +** \main\maintrunk.MT5921\8 2008-08-29 16:59:07 GMT mtk01088 +** fixed compiling error +** \main\maintrunk.MT5921\7 2008-08-29 14:13:28 GMT mtk01088 +** adjust the header file for code refine +** \main\maintrunk.MT5921\6 2008-03-28 10:40:31 GMT mtk01461 +** Add set desired rate in Linux STD IOCTL +** \main\maintrunk.MT5921\5 2008-03-11 14:51:08 GMT mtk01461 +** Refine private IOCTL functions +** \main\maintrunk.MT5921\4 2008-02-12 23:45:45 GMT mtk01461 +** Add Set Frequency & Channel oid support for Linux +** \main\maintrunk.MT5921\3 2007-11-06 19:36:19 GMT mtk01088 +** add the WPS related code +*/ + +#ifndef _GL_WEXT_H +#define _GL_WEXT_H + +#ifdef WIRELESS_EXT +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define KILO 1000 +#define RATE_5_5M 11 /* 5.5M */ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef struct _PARAM_FIXED_IEs { + UINT_8 aucTimestamp[8]; + UINT_16 u2BeaconInterval; + UINT_16 u2Capabilities; +} PARAM_FIXED_IEs; + +typedef struct _PARAM_VARIABLE_IE_T { + UINT_8 ucElementID; + UINT_8 ucLength; + UINT_8 aucData[1]; +} PARAM_VARIABLE_IE_T, *P_PARAM_VARIABLE_IE_T; + + +#if WIRELESS_EXT < 18 + +#define SIOCSIWMLME 0x8B16 /* request MLME operation; uses struct iw_mlme */ +/* MLME requests (SIOCSIWMLME / struct iw_mlme) */ +#define IW_MLME_DEAUTH 0 +#define IW_MLME_DISASSOC 1 + +/*! \brief SIOCSIWMLME data */ +struct iw_mlme { + __u16 cmd; /*!< IW_MLME_* */ + __u16 reason_code; + struct sockaddr addr; +}; + +#define SIOCSIWAUTH 0x8B32 /* set authentication mode params */ +#define SIOCGIWAUTH 0x8B33 /* get authentication mode params */ +/* SIOCSIWAUTH/SIOCGIWAUTH struct iw_param flags */ +#define IW_AUTH_INDEX 0x0FFF +#define IW_AUTH_FLAGS 0xF000 +/* SIOCSIWAUTH/SIOCGIWAUTH parameters (0 .. 4095) + * (IW_AUTH_INDEX mask in struct iw_param flags; this is the index of the + * parameter that is being set/get to; value will be read/written to + * struct iw_param value field) */ +#define IW_AUTH_WPA_VERSION 0 +#define IW_AUTH_CIPHER_PAIRWISE 1 +#define IW_AUTH_CIPHER_GROUP 2 +#define IW_AUTH_KEY_MGMT 3 +#define IW_AUTH_TKIP_COUNTERMEASURES 4 +#define IW_AUTH_DROP_UNENCRYPTED 5 +#define IW_AUTH_80211_AUTH_ALG 6 +#define IW_AUTH_WPA_ENABLED 7 +#define IW_AUTH_RX_UNENCRYPTED_EAPOL 8 +#define IW_AUTH_ROAMING_CONTROL 9 +#define IW_AUTH_PRIVACY_INVOKED 10 +#if CFG_SUPPORT_802_11W +#define IW_AUTH_MFP 12 + +#define IW_AUTH_MFP_DISABLED 0 /* MFP disabled */ +#define IW_AUTH_MFP_OPTIONAL 1 /* MFP optional */ +#define IW_AUTH_MFP_REQUIRED 2 /* MFP required */ +#endif + +/* IW_AUTH_WPA_VERSION values (bit field) */ +#define IW_AUTH_WPA_VERSION_DISABLED 0x00000001 +#define IW_AUTH_WPA_VERSION_WPA 0x00000002 +#define IW_AUTH_WPA_VERSION_WPA2 0x00000004 + +/* IW_AUTH_PAIRWISE_CIPHER and IW_AUTH_GROUP_CIPHER values (bit field) */ +#define IW_AUTH_CIPHER_NONE 0x00000001 +#define IW_AUTH_CIPHER_WEP40 0x00000002 +#define IW_AUTH_CIPHER_TKIP 0x00000004 +#define IW_AUTH_CIPHER_CCMP 0x00000008 +#define IW_AUTH_CIPHER_WEP104 0x00000010 + +/* IW_AUTH_KEY_MGMT values (bit field) */ +#define IW_AUTH_KEY_MGMT_802_1X 1 +#define IW_AUTH_KEY_MGMT_PSK 2 +#define IW_AUTH_KEY_MGMT_WPA_NONE 4 + +/* IW_AUTH_80211_AUTH_ALG values (bit field) */ +#define IW_AUTH_ALG_OPEN_SYSTEM 0x00000001 +#define IW_AUTH_ALG_SHARED_KEY 0x00000002 +#define IW_AUTH_ALG_LEAP 0x00000004 + +/* IW_AUTH_ROAMING_CONTROL values */ +#define IW_AUTH_ROAMING_ENABLE 0 /* driver/firmware based roaming */ +#define IW_AUTH_ROAMING_DISABLE 1 /* user space program used for roaming + * control */ + +#define SIOCSIWENCODEEXT 0x8B34 /* set encoding token & mode */ +#define SIOCGIWENCODEEXT 0x8B35 /* get encoding token & mode */ +/* SIOCSIWENCODEEXT definitions */ +#define IW_ENCODE_SEQ_MAX_SIZE 8 +/* struct iw_encode_ext ->alg */ +#define IW_ENCODE_ALG_NONE 0 +#define IW_ENCODE_ALG_WEP 1 +#define IW_ENCODE_ALG_TKIP 2 +#define IW_ENCODE_ALG_CCMP 3 +#if CFG_SUPPORT_802_11W +#define IW_ENCODE_ALG_AES_CMAC 5 +#endif + +/* struct iw_encode_ext ->ext_flags */ +#define IW_ENCODE_EXT_TX_SEQ_VALID 0x00000001 +#define IW_ENCODE_EXT_RX_SEQ_VALID 0x00000002 +#define IW_ENCODE_EXT_GROUP_KEY 0x00000004 +#define IW_ENCODE_EXT_SET_TX_KEY 0x00000008 + +struct iw_encode_ext { + __u32 ext_flags; /*!< IW_ENCODE_EXT_* */ + __u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /*!< LSB first */ + __u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /*!< LSB first */ + struct sockaddr addr; /*!< ff:ff:ff:ff:ff:ff for broadcast/multicast + * (group) keys or unicast address for + * individual keys */ + __u16 alg; /*!< IW_ENCODE_ALG_* */ + __u16 key_len; + __u8 key[0]; +}; + +#define SIOCSIWPMKSA 0x8B36 /* PMKSA cache operation */ +#define IW_PMKSA_ADD 1 +#define IW_PMKSA_REMOVE 2 +#define IW_PMKSA_FLUSH 3 + +#define IW_PMKID_LEN 16 + +struct iw_pmksa { + __u32 cmd; /*!< IW_PMKSA_* */ + struct sockaddr bssid; + __u8 pmkid[IW_PMKID_LEN]; +}; + +#define IWEVGENIE 0x8C05 /* Generic IE (WPA, RSN, WMM, ..) + * (scan results); This includes id and + * length fields. One IWEVGENIE may + * contain more than one IE. Scan + * results may contain one or more + * IWEVGENIE events. */ +#define IWEVMICHAELMICFAILURE 0x8C06 /* Michael MIC failure + * (struct iw_michaelmicfailure) + */ +#define IWEVASSOCREQIE 0x8C07 /* IEs used in (Re)Association Request. + * The data includes id and length + * fields and may contain more than one + * IE. This event is required in + * Managed mode if the driver + * generates its own WPA/RSN IE. This + * should be sent just before + * IWEVREGISTERED event for the + * association. */ +#define IWEVASSOCRESPIE 0x8C08 /* IEs used in (Re)Association + * Response. The data includes id and + * length fields and may contain more + * than one IE. This may be sent + * between IWEVASSOCREQIE and + * IWEVREGISTERED events for the + * association. */ +#define IWEVPMKIDCAND 0x8C09 /* PMKID candidate for RSN + * pre-authentication + * (struct iw_pmkid_cand) */ + +#endif /* WIRELESS_EXT < 18 */ + +#if WIRELESS_EXT < 17 +/* Statistics flags (bitmask in updated) */ +#define IW_QUAL_QUAL_UPDATED 0x1 /* Value was updated since last read */ +#define IW_QUAL_LEVEL_UPDATED 0x2 +#define IW_QUAL_NOISE_UPDATED 0x4 +#define IW_QUAL_QUAL_INVALID 0x10 /* Driver doesn't provide value */ +#define IW_QUAL_LEVEL_INVALID 0x20 +#define IW_QUAL_NOISE_INVALID 0x40 +#endif + +enum { + IEEE80211_FILTER_TYPE_BEACON = 1<<0, + IEEE80211_FILTER_TYPE_PROBE_REQ = 1<<1, + IEEE80211_FILTER_TYPE_PROBE_RESP = 1<<2, + IEEE80211_FILTER_TYPE_ASSOC_REQ = 1<<3, + IEEE80211_FILTER_TYPE_ASSOC_RESP = 1<<4, + IEEE80211_FILTER_TYPE_AUTH = 1<<5, + IEEE80211_FILTER_TYPE_DEAUTH = 1<<6, + IEEE80211_FILTER_TYPE_DISASSOC = 1<<7, + IEEE80211_FILTER_TYPE_ALL = 0xFF /* used to check the valid filter bits */ +}; + +#if CFG_SUPPORT_WAPI +#define IW_AUTH_WAPI_ENABLED 0x20 +#define IW_ENCODE_ALG_SMS4 0x20 +#endif + +#if CFG_SUPPORT_WAPI /* Android+ */ +#define IW_AUTH_KEY_MGMT_WAPI_PSK 3 +#define IW_AUTH_KEY_MGMT_WAPI_CERT 4 +#endif +#define IW_AUTH_KEY_MGMT_WPS 5 + +#if CFG_SUPPORT_802_11W +#define IW_AUTH_KEY_MGMT_802_1X_SHA256 7 +#define IW_AUTH_KEY_MGMT_PSK_SHA256 8 +#endif + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +extern const struct iw_handler_def wext_handler_def; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/* wireless extensions' ioctls */ +int +wext_support_ioctl( + IN struct net_device *prDev, + IN struct ifreq *prIfReq, + IN int i4Cmd + ); + +int +wext_set_rate ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN struct iw_param *prRate, + IN char *pcExtra + ); + +void +wext_indicate_wext_event( + IN P_GLUE_INFO_T prGlueInfo, + IN unsigned int u4Cmd, + IN unsigned char *pucData, + IN unsigned int u4DataLen + ); + +struct iw_statistics * +wext_get_wireless_stats ( + struct net_device *prDev + ); + +int +wext_get_priv ( + IN struct net_device *prNetDev, + IN struct ifreq *prIfReq + ); + +BOOLEAN +wextSrchDesiredWPAIE ( + IN PUINT_8 pucIEStart, + IN INT_32 i4TotalIeLen, + IN UINT_8 ucDesiredElemId, + OUT PUINT_8 *ppucDesiredIE + ); + +#if CFG_SUPPORT_WPS +BOOLEAN +wextSrchDesiredWPSIE ( + IN PUINT_8 pucIEStart, + IN INT_32 i4TotalIeLen, + IN UINT_8 ucDesiredElemId, + OUT PUINT_8 *ppucDesiredIE + ); +#endif + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* WIRELESS_EXT */ + +#endif /* _GL_WEXT_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_wext_priv.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_wext_priv.h new file mode 100755 index 000000000000..f49c30bfc235 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/include/gl_wext_priv.h @@ -0,0 +1,439 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/os/linux/include/gl_wext_priv.h#1 $ +*/ + +/*! \file gl_wext_priv.h + \brief This file includes private ioctl support. +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: gl_wext_priv.h $ + * + * 01 20 2012 cp.wu + * [ALPS00096191] [MT6620 Wi-Fi][Driver][Firmware] Porting to ALPS4.0_DEV branch + * sync to up-to-date changes including: + * 1. BOW bugfix + * 2. XLOG + * + * 01 09 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Check in the Add Tx power Cmd to driver. + * + * 01 02 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Adding the proto type function for set_int set_tx_power and get int get_ch_list. + * + * 11 08 2011 yuche.tsai + * [WCXRP00001094] [Volunteer Patch][Driver] Driver version & supplicant version query & set support for service discovery version check. + * Add a new priv CMD ID for P2P version set/query. + * + * 10 24 2011 terry.wu + * NULL + * Rollback to previous verson due to misbranch check-in + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * Add security check code. + * + * 01 27 2011 cm.chang + * [WCXRP00000402] [MT6620 Wi-Fi][Driver] Enable MCR read/write by iwpriv by default + * . + * + * 01 20 2011 eddie.chen + * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control + * Add Oid for sw control debug command + * + * 01 07 2011 cm.chang + * [WCXRP00000336] [MT6620 Wi-Fi][Driver] Add test mode commands in normal phone operation + * Add a new compiling option to control if MCR read/write is permitted + * + * 12 31 2010 cm.chang + * [WCXRP00000336] [MT6620 Wi-Fi][Driver] Add test mode commands in normal phone operation + * Add some iwpriv commands to support test mode operation + * + * 11 08 2010 wh.su + * [WCXRP00000171] [MT6620 Wi-Fi][Driver] Add message check code same behavior as mt5921 + * add the message check code from mt5921. + * + * 10 18 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android + * complete implementation of Android NVRAM access + * + * 09 23 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * add skeleton for NVRAM integration + * + * 08 04 2010 cp.wu + * NULL + * revert changelist #15371, efuse read/write access will be done by RF test approach + * + * 08 04 2010 cp.wu + * NULL + * add OID definitions for EFUSE read/write access. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 03 31 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * modify the wapi related code for new driver's design. + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port +** \main\maintrunk.MT5921\16 2009-09-29 16:47:23 GMT mtk01090 +** Remove unused functions +** \main\maintrunk.MT5921\15 2009-09-28 20:19:31 GMT mtk01090 +** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. +** \main\maintrunk.MT5921\14 2009-05-07 22:26:06 GMT mtk01089 +** add private IO control for Linux BWCS +** \main\maintrunk.MT5921\13 2008-08-29 14:55:20 GMT mtk01088 +** adjust the code to meet coding style +** \main\maintrunk.MT5921\12 2008-07-16 15:23:45 GMT mtk01104 +** Support GPIO2 mode +** \main\maintrunk.MT5921\11 2008-07-14 13:55:58 GMT mtk01104 +** Support PRIV_CMD_BT_COEXIST +** \main\maintrunk.MT5921\10 2008-07-09 00:20:24 GMT mtk01461 +** Add priv oid to support WMM_PS_TEST +** \main\maintrunk.MT5921\9 2008-05-30 20:27:24 GMT mtk01461 +** Add POWER_MODE Private IOCTL cmd +** \main\maintrunk.MT5921\8 2008-04-17 23:06:44 GMT mtk01461 +** Add iwpriv support for AdHocMode setting +** \main\maintrunk.MT5921\7 2008-03-31 21:01:24 GMT mtk01461 +** Add priv IOCTL for VOIP settings +** \main\maintrunk.MT5921\6 2008-03-31 13:49:47 GMT mtk01461 +** add priv ioctl arg definition for turning on / off roaming +** \main\maintrunk.MT5921\5 2008-03-26 15:35:09 GMT mtk01461 +** Add CSUM offload priv ioctl for Linux +** \main\maintrunk.MT5921\4 2008-03-11 14:51:11 GMT mtk01461 +** Refine private IOCTL functions +** \main\maintrunk.MT5921\3 2007-11-06 19:36:25 GMT mtk01088 +** add the WPS related code +*/ + +#ifndef _GL_WEXT_PRIV_H +#define _GL_WEXT_PRIV_H +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +/* If it is set to 1, iwpriv will support register read/write */ +#define CFG_SUPPORT_PRIV_MCR_RW 1 + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* New wireless extensions API - SET/GET convention (even ioctl numbers are + * root only) + */ +#define IOCTL_SET_INT (SIOCIWFIRSTPRIV + 0) +#define IOCTL_GET_INT (SIOCIWFIRSTPRIV + 1) + +#define IOCTL_SET_ADDRESS (SIOCIWFIRSTPRIV + 2) +#define IOCTL_GET_ADDRESS (SIOCIWFIRSTPRIV + 3) +#define IOCTL_SET_STR (SIOCIWFIRSTPRIV + 4) +#define IOCTL_GET_STR (SIOCIWFIRSTPRIV + 5) +#define IOCTL_SET_KEY (SIOCIWFIRSTPRIV + 6) +#define IOCTL_GET_KEY (SIOCIWFIRSTPRIV + 7) +#define IOCTL_SET_STRUCT (SIOCIWFIRSTPRIV + 8) +#define IOCTL_GET_STRUCT (SIOCIWFIRSTPRIV + 9) +#define IOCTL_SET_STRUCT_FOR_EM (SIOCIWFIRSTPRIV + 11) +#define IOCTL_SET_INTS (SIOCIWFIRSTPRIV + 12) +#define IOCTL_GET_INTS (SIOCIWFIRSTPRIV + 13) + +#define PRIV_CMD_REG_DOMAIN 0 +#define PRIV_CMD_BEACON_PERIOD 1 +#define PRIV_CMD_ADHOC_MODE 2 + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + #define PRIV_CMD_CSUM_OFFLOAD 3 +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + +#define PRIV_CMD_ROAMING 4 +#define PRIV_CMD_VOIP_DELAY 5 +#define PRIV_CMD_POWER_MODE 6 + +#define PRIV_CMD_WMM_PS 7 +#define PRIV_CMD_BT_COEXIST 8 +#define PRIV_GPIO2_MODE 9 + +#define PRIV_CUSTOM_SET_PTA 10 +#define PRIV_CUSTOM_CONTINUOUS_POLL 11 +#define PRIV_CUSTOM_SINGLE_ANTENNA 12 +#define PRIV_CUSTOM_BWCS_CMD 13 +#define PRIV_CUSTOM_DISABLE_BEACON_DETECTION 14//later +#define PRIV_CMD_OID 15 +#define PRIV_SEC_MSG_OID 16 + +#define PRIV_CMD_TEST_MODE 17 +#define PRIV_CMD_TEST_CMD 18 +#define PRIV_CMD_ACCESS_MCR 19 +#define PRIV_CMD_SW_CTRL 20 + +#if 1 /* ANTI_PRIVCY */ +#define PRIV_SEC_CHECK_OID 21 +#endif + +#define PRIV_CMD_WSC_PROBE_REQ 22 + +#define PRIV_CMD_P2P_VERSION 23 + +#define PRIV_CMD_GET_CH_LIST 24 + +#define PRIV_CMD_SET_TX_POWER 25 + +/* 802.3 Objects (Ethernet) */ +#define OID_802_3_CURRENT_ADDRESS 0x01010102 + +/* IEEE 802.11 OIDs */ +#define OID_802_11_SUPPORTED_RATES 0x0D01020E +#define OID_802_11_CONFIGURATION 0x0D010211 + +/* PnP and PM OIDs, NDIS default OIDS */ +#define OID_PNP_SET_POWER 0xFD010101 + +#define OID_CUSTOM_OID_INTERFACE_VERSION 0xFFA0C000 + +/* MT5921 specific OIDs */ +#define OID_CUSTOM_BT_COEXIST_CTRL 0xFFA0C580 +#define OID_CUSTOM_POWER_MANAGEMENT_PROFILE 0xFFA0C581 +#define OID_CUSTOM_PATTERN_CONFIG 0xFFA0C582 +#define OID_CUSTOM_BG_SSID_SEARCH_CONFIG 0xFFA0C583 +#define OID_CUSTOM_VOIP_SETUP 0xFFA0C584 +#define OID_CUSTOM_ADD_TS 0xFFA0C585 +#define OID_CUSTOM_DEL_TS 0xFFA0C586 +#define OID_CUSTOM_SLT 0xFFA0C587 +#define OID_CUSTOM_ROAMING_EN 0xFFA0C588 +#define OID_CUSTOM_WMM_PS_TEST 0xFFA0C589 +#define OID_CUSTOM_COUNTRY_STRING 0xFFA0C58A +#define OID_CUSTOM_MULTI_DOMAIN_CAPABILITY 0xFFA0C58B +#define OID_CUSTOM_GPIO2_MODE 0xFFA0C58C +#define OID_CUSTOM_CONTINUOUS_POLL 0xFFA0C58D +#define OID_CUSTOM_DISABLE_BEACON_DETECTION 0xFFA0C58E + +/* CR1460, WPS privacy bit check disable */ +#define OID_CUSTOM_DISABLE_PRIVACY_CHECK 0xFFA0C600 + +/* Precedent OIDs */ +#define OID_CUSTOM_MCR_RW 0xFFA0C801 +#define OID_CUSTOM_EEPROM_RW 0xFFA0C803 +#define OID_CUSTOM_SW_CTRL 0xFFA0C805 + + +/* RF Test specific OIDs */ +#define OID_CUSTOM_TEST_MODE 0xFFA0C901 +#define OID_CUSTOM_TEST_RX_STATUS 0xFFA0C903 +#define OID_CUSTOM_TEST_TX_STATUS 0xFFA0C905 +#define OID_CUSTOM_ABORT_TEST_MODE 0xFFA0C906 +#define OID_CUSTOM_MTK_WIFI_TEST 0xFFA0C911 + +/* BWCS */ +#define OID_CUSTOM_BWCS_CMD 0xFFA0C931 +#define OID_CUSTOM_SINGLE_ANTENNA 0xFFA0C932 +#define OID_CUSTOM_SET_PTA 0xFFA0C933 + +/* NVRAM */ +#define OID_CUSTOM_MTK_NVRAM_RW 0xFFA0C941 +#define OID_CUSTOM_CFG_SRC_TYPE 0xFFA0C942 +#define OID_CUSTOM_EEPROM_TYPE 0xFFA0C943 + + +#if CFG_SUPPORT_WAPI +#define OID_802_11_WAPI_MODE 0xFFA0CA00 +#define OID_802_11_WAPI_ASSOC_INFO 0xFFA0CA01 +#define OID_802_11_SET_WAPI_KEY 0xFFA0CA02 +#endif + +#if CFG_SUPPORT_WPS2 +#define OID_802_11_WSC_ASSOC_INFO 0xFFA0CB00 +#endif + + +/* Define magic key of test mode (Don't change it for future compatibity) */ +#define PRIV_CMD_TEST_MAGIC_KEY 2011 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* NIC BBCR configuration entry structure */ +typedef struct _PRIV_CONFIG_ENTRY { + UINT_8 ucOffset; + UINT_8 ucValue; +} PRIV_CONFIG_ENTRY, *PPRIV_CONFIG_ENTRY; + +typedef WLAN_STATUS (*PFN_OID_HANDLER_FUNC_REQ) ( + IN PVOID prAdapter, + IN OUT PVOID pvBuf, + IN UINT_32 u4BufLen, + OUT PUINT_32 pu4OutInfoLen + ); + +typedef enum _ENUM_OID_METHOD_T { + ENUM_OID_GLUE_ONLY, + ENUM_OID_GLUE_EXTENSION, + ENUM_OID_DRIVER_CORE +} ENUM_OID_METHOD_T, *P_ENUM_OID_METHOD_T; + +/* OID set/query processing entry */ +typedef struct _WLAN_REQ_ENTRY { + UINT_32 rOid; /* OID */ + PUINT_8 pucOidName; /* OID name text */ + BOOLEAN fgQryBufLenChecking; + BOOLEAN fgSetBufLenChecking; + ENUM_OID_METHOD_T eOidMethod; + UINT_32 u4InfoBufLen; + PFN_OID_HANDLER_FUNC_REQ pfOidQueryHandler; /* PFN_OID_HANDLER_FUNC*/ + PFN_OID_HANDLER_FUNC_REQ pfOidSetHandler; /* PFN_OID_HANDLER_FUNC */ +} WLAN_REQ_ENTRY, *P_WLAN_REQ_ENTRY; + +typedef struct _NDIS_TRANSPORT_STRUCT { + UINT_32 ndisOidCmd; + UINT_32 inNdisOidlength; + UINT_32 outNdisOidLength; + UINT_8 ndisOidContent[16]; +} NDIS_TRANSPORT_STRUCT, *P_NDIS_TRANSPORT_STRUCT; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +int +priv_set_int( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, + IN char *pcExtra + ); + +int +priv_get_int( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, + IN OUT char *pcExtra + ); + +int +priv_set_ints( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, + IN char *pcExtra + ); + +int +priv_get_ints( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, + IN OUT char *pcExtra + ); + +int +priv_set_struct( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, + IN char *pcExtra + ); + +int +priv_get_struct ( + IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, + IN OUT char *pcExtra + ); + +int +priv_support_ioctl ( + IN struct net_device *prDev, + IN OUT struct ifreq *prReq, + IN int i4Cmd + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _GL_WEXT_PRIV_H */ + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/platform.c b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/platform.c new file mode 100755 index 000000000000..7ae1b9c78cf8 --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/linux/platform.c @@ -0,0 +1,694 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + */ +/* MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/os/linux/platform.c#1 $ +*/ + +/*! \file "platform.c" + \brief This file including the protocol layer privacy function. + + This file provided the macros and functions library support for the + protocol layer security setting from wlan_oid.c and for parse.c and + rsn.c and nic_privacy.c + +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: platform.c $ + * + * 11 14 2011 cm.chang + * NULL + * Fix compiling warning + * + * 11 10 2011 cp.wu + * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer + * 1. eliminaite direct calls to printk in porting layer. + * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 09 13 2011 jeffrey.chang + * [WCXRP00000983] [MT6620][Wi-Fi Driver] invalid pointer casting causes kernel panic during p2p connection + * fix pointer casting + * + * 06 29 2011 george.huang + * [WCXRP00000818] [MT6620 Wi-Fi][Driver] Remove unused code segment regarding CONFIG_IPV6 + * . + * + * 06 28 2011 george.huang + * [WCXRP00000818] [MT6620 Wi-Fi][Driver] Remove unused code segment regarding CONFIG_IPV6 + * remove un-used code + * + * 05 09 2011 jeffrey.chang + * [WCXRP00000710] [MT6620 Wi-Fi] Support pattern filter update function on IP address change + * support ARP filter through kernel notifier + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 18 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * remove early suspend functions + * + * 03 03 2011 jeffrey.chang + * NULL + * add the ARP filter callback + * + * 02 15 2011 jeffrey.chang + * NULL + * to support early suspend in android + * + * 02 01 2011 cp.wu + * [WCXRP00000413] [MT6620 Wi-Fi][Driver] Merge 1103 changes on NVRAM file path change to DaVinci main trunk and V1.1 branch + * upon Jason Zhang(NVRAM owner)'s change, ALPS has modified its NVRAM storage from /nvram/... to /data/nvram/... + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 10 18 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android + * complete implementation of Android NVRAM access + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * 1) add NVRAM access API + * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) + * 3) add OID implementation for NVRAM read/write service + * +** +*/ +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 12) + #include +#endif + +#include "gl_os.h" + +#ifndef CONFIG_X86 +#if defined(CONFIG_HAS_EARLY_SUSPEND) + #include +#endif +#endif + + +extern BOOLEAN fgIsUnderEarlierSuspend; + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define WIFI_NVRAM_FILE_NAME "/data/nvram/APCFG/APRDEB/WIFI" +#define WIFI_NVRAM_CUSTOM_NAME "/data/nvram/APCFG/APRDEB/WIFI_CUSTOM" + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + + + +static int netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr) +{ + UINT_8 ip[4] = { 0 }; + UINT_32 u4NumIPv4 = 0; +//#ifdef CONFIG_IPV6 +#if 0 + UINT_8 ip6[16] = { 0 }; // FIX ME: avoid to allocate large memory in stack + UINT_32 u4NumIPv6 = 0; +#endif + struct in_ifaddr *ifa = (struct in_ifaddr *) ptr; + struct net_device *prDev = ifa->ifa_dev->dev; + UINT_32 i; + P_PARAM_NETWORK_ADDRESS_IP prParamIpAddr; + P_GLUE_INFO_T prGlueInfo = NULL; + + if (prDev == NULL) { + DBGLOG(REQ, INFO, ("netdev_event: device is empty.\n")); + return NOTIFY_DONE; + } + + if ((strncmp(prDev->name, "p2p", 3) != 0) && (strncmp(prDev->name, "wlan", 4) != 0)) { + DBGLOG(REQ, INFO, ("netdev_event: xxx\n")); + return NOTIFY_DONE; + } + + if (strncmp(prDev->name, "p2p", 3) == 0) { + // because we store the address of prGlueInfo in p2p's private date of net device + // *((P_GLUE_INFO_T *) netdev_priv(prGlueInfo->prP2PInfo->prDevHandler)) = prGlueInfo; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + } else { // wlan0 + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prDev); + } + + if (prGlueInfo == NULL) { + DBGLOG(REQ, INFO, ("netdev_event: prGlueInfo is empty.\n")); + return NOTIFY_DONE; + } + ASSERT(prGlueInfo); + + if (fgIsUnderEarlierSuspend == false) { + DBGLOG(REQ, INFO, ("netdev_event: PARAM_MEDIA_STATE_DISCONNECTED. (%d)\n", prGlueInfo->eParamMediaStateIndicated)); + return NOTIFY_DONE; + } + + + + // <3> get the IPv4 address + if(!prDev || !(prDev->ip_ptr)||\ + !((struct in_device *)(prDev->ip_ptr))->ifa_list||\ + !(&(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local))){ + DBGLOG(REQ, INFO, ("ip is not avaliable.\n")); + return NOTIFY_DONE; + } + + kalMemCopy(ip, &(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local), sizeof(ip)); + DBGLOG(REQ, INFO, ("ip is %d.%d.%d.%d\n", + ip[0],ip[1],ip[2],ip[3])); + + // todo: traverse between list to find whole sets of IPv4 addresses + if (!((ip[0] == 0) && + (ip[1] == 0) && + (ip[2] == 0) && + (ip[3] == 0))) { + u4NumIPv4++; + } + +//#ifdef CONFIG_IPV6 +#if 0 + if(!prDev || !(prDev->ip6_ptr)||\ + !((struct in_device *)(prDev->ip6_ptr))->ifa_list||\ + !(&(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local))){ + printk(KERN_INFO "ipv6 is not avaliable.\n"); + return NOTIFY_DONE; + } + + kalMemCopy(ip6, &(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local), sizeof(ip6)); + printk(KERN_INFO"ipv6 is %d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d\n", + ip6[0],ip6[1],ip6[2],ip6[3], + ip6[4],ip6[5],ip6[6],ip6[7], + ip6[8],ip6[9],ip6[10],ip6[11], + ip6[12],ip6[13],ip6[14],ip6[15] + ); + + // todo: traverse between list to find whole sets of IPv6 addresses + if (!((ip6[0] == 0) && + (ip6[1] == 0) && + (ip6[2] == 0) && + (ip6[3] == 0) && + (ip6[4] == 0) && + (ip6[5] == 0))) { + //u4NumIPv6++; + } +#endif + + // here we can compare the dev with other network's netdev to + // set the proper arp filter + // + // IMPORTANT: please make sure if the context can sleep, if the context can't sleep + // we should schedule a kernel thread to do this for us + + // <7> set up the ARP filter + { + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + UINT_32 u4SetInfoLen = 0; + UINT_8 aucBuf[32] = {0}; + UINT_32 u4Len = OFFSET_OF(PARAM_NETWORK_ADDRESS_LIST, arAddress); + P_PARAM_NETWORK_ADDRESS_LIST prParamNetAddrList = (P_PARAM_NETWORK_ADDRESS_LIST)aucBuf; + P_PARAM_NETWORK_ADDRESS prParamNetAddr = prParamNetAddrList->arAddress; + +//#ifdef CONFIG_IPV6 +#if 0 + prParamNetAddrList->u4AddressCount = u4NumIPv4 + u4NumIPv6; +#else + prParamNetAddrList->u4AddressCount = u4NumIPv4; +#endif + prParamNetAddrList->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; + for (i = 0; i < u4NumIPv4; i++) { + prParamNetAddr->u2AddressLength = sizeof(PARAM_NETWORK_ADDRESS_IP);//4;; + prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP;; +#if 0 + kalMemCopy(prParamNetAddr->aucAddress, ip, sizeof(ip)); + prParamNetAddr = (P_PARAM_NETWORK_ADDRESS)((UINT_32)prParamNetAddr + sizeof(ip)); + u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(ip); +#else + prParamIpAddr = (P_PARAM_NETWORK_ADDRESS_IP)prParamNetAddr->aucAddress; + kalMemCopy(&prParamIpAddr->in_addr, ip, sizeof(ip)); + prParamNetAddr = (P_PARAM_NETWORK_ADDRESS)((UINT_32)prParamNetAddr + sizeof(PARAM_NETWORK_ADDRESS)); + u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(PARAM_NETWORK_ADDRESS); +#endif + } +//#ifdef CONFIG_IPV6 +#if 0 + for (i = 0; i < u4NumIPv6; i++) { + prParamNetAddr->u2AddressLength = 6;; + prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP;; + kalMemCopy(prParamNetAddr->aucAddress, ip6, sizeof(ip6)); + prParamNetAddr = (P_PARAM_NETWORK_ADDRESS)((UINT_32)prParamNetAddr + sizeof(ip6)); + u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(ip6); + } +#endif + ASSERT(u4Len <= sizeof(aucBuf)); + + DBGLOG(REQ, INFO, ("kalIoctl (0x%x, 0x%x)\n", prGlueInfo, prParamNetAddrList)); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetNetworkAddress, + (PVOID)prParamNetAddrList, + u4Len, + FALSE, + FALSE, + TRUE, + FALSE, + &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, INFO, ("set HW pattern filter fail 0x%lx\n", rStatus)); + } + } + + return NOTIFY_DONE; + +} + +static struct notifier_block inetaddr_notifier = { + .notifier_call = netdev_event, +}; + +void wlanRegisterNotifier(void) +{ + register_inetaddr_notifier(&inetaddr_notifier); +} + +EXPORT_SYMBOL(wlanRegisterNotifier); + +void wlanUnregisterNotifier(void) +{ + unregister_inetaddr_notifier(&inetaddr_notifier); +} + +EXPORT_SYMBOL(wlanUnregisterNotifier); + +#ifndef CONFIG_X86 +#if defined(CONFIG_HAS_EARLYSUSPEND) + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will register platform driver to os +* +* \param[in] wlanSuspend Function pointer to platform suspend function +* \param[in] wlanResume Function pointer to platform resume function +* +* \return The result of registering earlysuspend +*/ +/*----------------------------------------------------------------------------*/ + +int glRegisterEarlySuspend( + struct early_suspend *prDesc, + early_suspend_callback wlanSuspend, + late_resume_callback wlanResume) +{ + int ret = 0; + + if(NULL != wlanSuspend) + prDesc->suspend = wlanSuspend; + else{ + DBGLOG(REQ, INFO, ("glRegisterEarlySuspend wlanSuspend ERROR.\n")); + ret = -1; + } + + if(NULL != wlanResume) + prDesc->resume = wlanResume; + else{ + DBGLOG(REQ, INFO, ("glRegisterEarlySuspend wlanResume ERROR.\n")); + ret = -1; + } + + register_early_suspend(prDesc); + return ret; +} + +EXPORT_SYMBOL(glRegisterEarlySuspend); + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will un-register platform driver to os +* +* \return The result of un-registering earlysuspend +*/ +/*----------------------------------------------------------------------------*/ + +int glUnregisterEarlySuspend(struct early_suspend *prDesc) +{ + int ret = 0; + + unregister_early_suspend(prDesc); + + prDesc->suspend = NULL; + prDesc->resume = NULL; + + return ret; +} + +EXPORT_SYMBOL(glUnregisterEarlySuspend); +#endif +#endif // !CONFIG_X86 + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Utility function for reading data from files on NVRAM-FS +* +* \param[in] +* filename +* len +* offset +* \param[out] +* buf +* \return +* actual length of data being read +*/ +/*----------------------------------------------------------------------------*/ +static int +nvram_read( + char *filename, + char *buf, + ssize_t len, + int offset) +{ +#if CFG_SUPPORT_NVRAM + struct file *fd; + int retLen = -1; + + mm_segment_t old_fs = get_fs(); + set_fs(KERNEL_DS); + + fd = filp_open(filename, O_RDONLY, 0644); + + if(IS_ERR(fd)) { + DBGLOG(INIT, INFO, ("[MT6620][nvram_read] : failed to open!!\n")); + return -1; + } + + do { + if ((fd->f_op == NULL) || (fd->f_op->read == NULL)) { + DBGLOG(INIT, INFO, ("[MT6620][nvram_read] : file can not be read!!\n")); + break; + } + + if (fd->f_pos != offset) { + if (fd->f_op->llseek) { + if(fd->f_op->llseek(fd, offset, 0) != offset) { + DBGLOG(INIT, INFO, ("[MT6620][nvram_read] : failed to seek!!\n")); + break; + } + } + else { + fd->f_pos = offset; + } + } + + retLen = fd->f_op->read(fd, + buf, + len, + &fd->f_pos); + + } while(FALSE); + + filp_close(fd, NULL); + + set_fs(old_fs); + + return retLen; + +#else // !CFG_SUPPORT_NVRAM + + return -EIO; + +#endif +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Utility function for writing data to files on NVRAM-FS +* +* \param[in] +* filename +* buf +* len +* offset +* \return +* actual length of data being written +*/ +/*----------------------------------------------------------------------------*/ +static int +nvram_write ( + char *filename, + char *buf, + ssize_t len, + int offset) +{ +#if CFG_SUPPORT_NVRAM + struct file *fd; + int retLen = -1; + + mm_segment_t old_fs = get_fs(); + set_fs(KERNEL_DS); + + fd = filp_open(filename, O_WRONLY|O_CREAT, 0644); + + if(IS_ERR(fd)) { + DBGLOG(INIT, INFO, ("[MT6620][nvram_write] : failed to open!!\n")); + return -1; + } + + do{ + if ((fd->f_op == NULL) || (fd->f_op->write == NULL)) { + DBGLOG(INIT, INFO, ("[MT6620][nvram_write] : file can not be write!!\n")); + break; + } /* End of if */ + + if (fd->f_pos != offset) { + if (fd->f_op->llseek) { + if(fd->f_op->llseek(fd, offset, 0) != offset) { + DBGLOG(INIT, INFO, ("[MT6620][nvram_write] : failed to seek!!\n")); + break; + } + } + else { + fd->f_pos = offset; + } + } + + retLen = fd->f_op->write(fd, + buf, + len, + &fd->f_pos); + + } while(FALSE); + + filp_close(fd, NULL); + + set_fs(old_fs); + + return retLen; + +#else // !CFG_SUPPORT_NVRAMS + + return -EIO; + +#endif +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief API for reading data on NVRAM +* +* \param[in] +* prGlueInfo +* u4Offset +* \param[out] +* pu2Data +* \return +* TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +kalCfgDataRead16( + IN P_GLUE_INFO_T prGlueInfo, + IN UINT_32 u4Offset, + OUT PUINT_16 pu2Data + ) +{ + if(pu2Data == NULL) { + return FALSE; + } + + if(nvram_read(WIFI_NVRAM_FILE_NAME, + (char *)pu2Data, + sizeof(unsigned short), + u4Offset) != sizeof(unsigned short)) { + return FALSE; + } + else { + return TRUE; + } +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief API for writing data on NVRAM +* +* \param[in] +* prGlueInfo +* u4Offset +* u2Data +* \return +* TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +kalCfgDataWrite16( + IN P_GLUE_INFO_T prGlueInfo, + UINT_32 u4Offset, + UINT_16 u2Data + ) +{ + if(nvram_write(WIFI_NVRAM_FILE_NAME, + (char *)&u2Data, + sizeof(unsigned short), + u4Offset) != sizeof(unsigned short)) { + return FALSE; + } + else { + return TRUE; + } +} + + diff --git a/drivers/mtk_wcn_combo/drv_wlan/wlan/os/version.h b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/version.h new file mode 100755 index 000000000000..a64c515c9bac --- /dev/null +++ b/drivers/mtk_wcn_combo/drv_wlan/wlan/os/version.h @@ -0,0 +1,197 @@ +/* +** $Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_2/os/version.h#1 $ +*/ + +/*! \file "version.h" + \brief Driver's version definition + +*/ + +/******************************************************************************* +* Copyright (c) 2007 MediaTek Inc. +* +* All rights reserved. Copying, compilation, modification, distribution +* or any other use whatsoever of this material is strictly prohibited +* except in accordance with a Software License Agreement with +* MediaTek Inc. +******************************************************************************** +*/ + +/******************************************************************************* +* LEGAL DISCLAIMER +* +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND +* AGREES THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK +* SOFTWARE") RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE +* PROVIDED TO BUYER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY +* DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +* PARTICULAR PURPOSE OR NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE +* ANY WARRANTY WHATSOEVER WITH RESPECT TO THE SOFTWARE OF ANY THIRD PARTY +* WHICH MAY BE USED BY, INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK +* SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY +* WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE +* FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S SPECIFICATION OR TO +* CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. +* +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL +* BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT +* ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY +* BUYER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +* +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT +* OF LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING +* THEREOF AND RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN +* FRANCISCO, CA, UNDER THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE +* (ICC). +******************************************************************************** +*/ + +/* +** $Log: version.h $ + * + * 10 19 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Branch 2.1 + * Davinci Maintrunk Label: MT6620_WIFI_DRIVER_FW_TRUNK_MT6620E5_111019_0926. + * + * 03 18 2011 cp.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 driver release based on label "MT6620_WIFI_DRIVER_V2_0_110318_1600" from main trunk + * + * 03 18 2011 chinglan.wang + * NULL + * Change the version number to v2.0.0.0. + * + * 02 11 2011 chinglan.wang + * NULL + * Change to the version 1.2.0.2. + * + * 02 10 2011 chinglan.wang + * NULL + * Change the version to 1.2.0.1. + * + * 02 08 2011 cp.wu + * [WCXRP00000427] [MT6620 Wi-Fi][Driver] Modify veresion information to match with release revision number + * change version number to v1.2.0.0 for preparing v1.2 software package release. + * + * 12 10 2010 kevin.huang + * [WCXRP00000128] [MT6620 Wi-Fi][Driver] Add proc support to Android Driver for debug and driver status check + * Add Linux Proc Support + * + * 10 07 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * [WINDDK] build system changes for MT5931 + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-12-14 14:10:55 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-11-17 22:41:00 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-11-13 16:20:33 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:27:13 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _VERSION_H +#define _VERSION_H +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#ifndef NIC_AUTHOR +#define NIC_AUTHOR "NIC_AUTHOR" +#endif +#ifndef NIC_DESC +#define NIC_DESC "NIC_DESC" +#endif + +#ifndef NIC_NAME + #if defined(MT6620) + #define NIC_NAME "MT6620" + #define NIC_DEVICE_ID "MT6620" + #define NIC_DEVICE_ID_LOW "mt6620" + #elif defined(MT5931) + #define NIC_NAME "MT5931" + #define NIC_DEVICE_ID "MT5931" + #define NIC_DEVICE_ID_LOW "mt5931" + #elif defined(MT6628) + #define NIC_NAME "MT6628" + #define NIC_DEVICE_ID "MT6628" + #define NIC_DEVICE_ID_LOW "mt6628" + #endif +#endif + +/* NIC driver information */ +#define NIC_VENDOR "MediaTek Inc." +#define NIC_VENDOR_OUI {0x00, 0x0C, 0xE7} + +#if defined(MT6620) + #define NIC_PRODUCT_NAME "MediaTek Inc. MT6620 Wireless LAN Adapter" + #define NIC_DRIVER_NAME "MediaTek Inc. MT6620 Wireless LAN Adapter Driver" +#elif defined(MT5931) + #define NIC_PRODUCT_NAME "MediaTek Inc. MT5931 Wireless LAN Adapter" + #define NIC_DRIVER_NAME "MediaTek Inc. MT5931 Wireless LAN Adapter Driver" +#elif defined(MT6628) + #define NIC_PRODUCT_NAME "MediaTek Inc. MT6628 Wireless LAN Adapter" + #define NIC_DRIVER_NAME "MediaTek Inc. MT6628 Wireless LAN Adapter Driver" +#endif + +/* Define our driver version */ +#define NIC_DRIVER_MAJOR_VERSION 2 +#define NIC_DRIVER_MINOR_VERSION 0 +#define NIC_DRIVER_VERSION 2,0,0,9 +#define NIC_DRIVER_VERSION_STRING "2.0.0.9" + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + + +#endif /* _VERSION_H */ + diff --git a/drivers/mtk_wcn_combo/gps/Makefile b/drivers/mtk_wcn_combo/gps/Makefile new file mode 100755 index 000000000000..db3b2a544d88 --- /dev/null +++ b/drivers/mtk_wcn_combo/gps/Makefile @@ -0,0 +1,49 @@ +# Copyright Statement: +# +# This software/firmware and related documentation ("MediaTek Software") are +# protected under relevant copyright laws. The information contained herein +# is confidential and proprietary to MediaTek Inc. and/or its licensors. +# Without the prior written permission of MediaTek inc. and/or its licensors, +# any reproduction, modification, use or disclosure of MediaTek Software, +# and information contained herein, in whole or in part, shall be strictly prohibited. + +# MediaTek Inc. (C) 2010. All rights reserved. +# +# BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES +# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") +# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON +# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. +# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE +# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR +# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH +# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES +# THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES +# CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK +# SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR +# STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND +# CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, +# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, +# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO +# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +# +# The following software/firmware and/or related documentation ("MediaTek Software") +# have been modified by MediaTek Inc. All revisions are subject to any receiver's +# applicable license agreements with MediaTek Inc. + + +# drivers/barcelona/gps/Makefile +# +# Makefile for the Barcelona GPS driver. +# +# Copyright (C) 2004,2005 TomTom BV +# Author: Dimitry Andric +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. + +obj-$(CONFIG_MTK_GPS) += gps.o + +# EOF diff --git a/drivers/mtk_wcn_combo/gps/gps.c b/drivers/mtk_wcn_combo/gps/gps.c new file mode 100755 index 000000000000..28bb7f4f012e --- /dev/null +++ b/drivers/mtk_wcn_combo/gps/gps.c @@ -0,0 +1,1117 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + */ +/* MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +/* drivers/barcelona/gps/gps.c + * + * Implementation of the GPS driver. + * + * Copyright (C) 2004,2005 TomTom BV + * Authors: + * Jeroen Taverne + * Dimitry Andric + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/******************************************************************************* +* Dependency +*******************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_ARCH_MT6573) +#include +#include +#elif defined(CONFIG_ARCH_MT6575) +#include +#include +#elif defined(CONFIG_ARCH_MT6516) +#include +#include +#include +#include +#endif + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif + +struct mt3326_gps_hardware{ + int (*ext_power_on)(int); + int (*ext_power_off)(int); +}; + +/****************************************************************************** + * Function Configuration +******************************************************************************/ +//#define FAKE_DATA +#define GPS_SUSPEND_RESUME +#define GPS_CONFIGURABLE_RESET_DELAY +/****************************************************************************** + * Definition +******************************************************************************/ +/* device name and major number */ +#define GPS_DEVNAME "mt3326-gps" +/****************************************************************************** + * Debug configuration +******************************************************************************/ +#define GPS_DBG_NONE(fmt, arg...) do {} while (0) +#define GPS_DBG_FUNC(fmt, arg...) printk(KERN_INFO PFX "%s: " fmt, __FUNCTION__ ,##arg) + +#define GPS_ERR(fmt, arg...) printk(KERN_ERR PFX "%s: " fmt, __FUNCTION__ ,##arg) +#define GPS_WARN(fmt, arg...) printk(KERN_WARNING PFX "%s: " fmt, __FUNCTION__ ,##arg) +#define GPS_NOTICE(fmt, arg...) printk(KERN_NOTICE PFX "%s: " fmt, __FUNCTION__ ,##arg) +#define GPS_INFO(fmt, arg...) printk(KERN_INFO PFX "%s: " fmt, __FUNCTION__ ,##arg) +#define GPS_TRC_FUNC(f) printk(PFX "<%s>\n", __FUNCTION__); +#define GPS_TRC_VERBOSE(fmt, arg...) printk(PFX fmt, ##arg) + +#define PFX "GPS: " +#define GPS_DBG GPS_DBG_FUNC +#define GPS_TRC GPS_DBG_NONE //GPS_TRC_FUNC +#define GPS_VER GPS_DBG_NONE //GPS_TRC_VERBOSE +#define IH_DBG GPS_DBG_NONE +/******************************************************************************* +* structure & enumeration +*******************************************************************************/ +enum { + GPS_PWRCTL_UNSUPPORTED = 0xFF, + GPS_PWRCTL_OFF = 0x00, + GPS_PWRCTL_ON = 0x01, + GPS_PWRCTL_RST = 0x02, + GPS_PWRCTL_OFF_FORCE = 0x03, + GPS_PWRCTL_RST_FORCE = 0x04, + GPS_PWRCTL_MAX = 0x05, +}; +enum { + GPS_PWR_UNSUPPORTED = 0xFF, + GPS_PWR_RESUME = 0x00, + GPS_PWR_SUSPEND = 0x01, + GPS_PWR_MAX = 0x02, +}; +enum { + GPS_STATE_UNSUPPORTED = 0xFF, + GPS_STATE_OFF = 0x00, /*cleanup/power off, default state*/ + GPS_STATE_INIT = 0x01, /*init*/ + GPS_STATE_START = 0x02, /*start navigating*/ + GPS_STATE_STOP = 0x03, /*stop navigating*/ + GPS_STATE_DEC_FREQ = 0x04, + GPS_STATE_SLEEP = 0x05, + GPS_STATE_MAX = 0x06, +}; +enum { + GPS_PWRSAVE_UNSUPPORTED = 0xFF, + GPS_PWRSAVE_DEC_FREQ = 0x00, + GPS_PWRSAVE_SLEEP = 0x01, + GPS_PWRSAVE_OFF = 0x02, + GPS_PWRSAVE_MAX = 0x03, +}; +/*---------------------------------------------------------------------------*/ +struct gps_data{ + int dat_len; + int dat_pos; + char dat_buf[4096]; + spinlock_t lock; + wait_queue_head_t read_wait; + struct semaphore sem; +}; +/*---------------------------------------------------------------------------*/ +struct gps_sta_itm { /*gps status record*/ + unsigned char year; /*current year - 1900*/ + unsigned char month; /*1~12*/ + unsigned char day; /*1~31*/ + unsigned char hour; /*0~23*/ + + unsigned char minute; /*0~59*/ + unsigned char sec; /*0~59*/ + unsigned char count; /*reborn count*/ + unsigned char reason; /*reason: 0: timeout; 1: force*/ +}; +/*---------------------------------------------------------------------------*/ +struct gps_sta_obj { + int index; + struct gps_sta_itm items[32]; +}; +/*---------------------------------------------------------------------------*/ +struct gps_drv_obj { + unsigned char pwrctl; + unsigned char suspend; + unsigned char state; + unsigned char pwrsave; + int rdelay; /*power reset delay*/ + struct kobject *kobj; + struct mutex sem; + struct gps_sta_obj status; + struct mt3326_gps_hardware *hw; +}; +/*---------------------------------------------------------------------------*/ +struct gps_dev_obj { + struct class *cls; + struct device *dev; + dev_t devno; + struct cdev chdev; + struct mt3326_gps_hardware *hw; +}; +/****************************************************************************** + * local variables +******************************************************************************/ +static struct gps_data gps_private= {0}; + +#if defined(FAKE_DATA) +static char fake_data[] = { +"$GPGGA,135036.000,2446.3713,N,12101.3605,E,1,5,1.61,191.1,M,15.1,M,,*51\r\n" +"$GPGSA,A,3,22,18,14,30,31,,,,,,,,1.88,1.61,0.98*09\r\n" +"$GPGSV,2,1,6,18,83,106,32,22,58,324,35,30,45,157,35,14,28,308,32*44\r\n" +"$GPGSV,2,2,6,40,21,254,,31,17,237,29*42\r\n" +"$GPRMC,135036.000,A,2446.37125,N,12101.36054,E,0.243,56.48,140109,,A*46\r\n" +"$GPVTG,56.48,T,,M,0.243,N,0.451,K,A*07\r\n" +}; +#endif //FAKE_DATA + +/*this should be synchronous with mnld.c +enum { + MNL_RESTART_NONE = 0x00, //recording the 1st of mnld + MNL_RESTART_TIMEOUT_INIT = 0x01, //restart due to timeout + MNL_RESTART_TIMEOUT_MONITOR = 0x02, //restart due to timeout + MNL_RESTART_TIMEOUT_WAKEUP = 0x03, //restart due to timeout + MNL_RESTART_TIMEOUT_TTFF = 0x04, //restart due to TTFF timeout + MNL_RESTART_FORCE = 0x04, //restart due to external command +}; +*/ +/*---------------------------------------------------------------------------*/ +static char *str_reason[] = {"none", "init", "monitor", "wakeup", "TTFF", "force", "unknown"}; +/****************************************************************************** + * Functions +******************************************************************************/ +static inline void mt3326_gps_power(struct mt3326_gps_hardware *hw, + unsigned int on, unsigned int force) +{ + /*FIX ME: PM_api should provide a function to get current status*/ + static unsigned int power_on = 1; + int err; + GPS_DBG("Switching GPS device %s\n", on ? "on" : "off"); + if (!hw) { + GPS_ERR("null pointer!!\n"); + return; + } + + if (power_on == on) { + GPS_DBG("ignore power control: %d\n", on); + } else if (on) { + /*power on*/ + if (hw->ext_power_on) { + err = hw->ext_power_on(0); + if (err) + GPS_ERR("ext_power_on fail\n"); + } +#if 0 +#ifndef MTK_MT6620 + if (!hwPowerOn(MT6516_POWER_V3GTX, VOL_2800,"MT3326")) { + GPS_ERR("power on fails!!\n"); + return; + } +#endif +#endif + if (hw->ext_power_on) { + err = hw->ext_power_on(1); + if (err) + GPS_ERR("ext_power_on fail\n"); + } + + #if 0 + if (!hwEnableClock(MT6516_PDN_PERI_UART2,"MT3326")) + GPS_ERR("enable clock fail"); + #endif + mdelay(120); + } else { + #if 0 + if (!hwDisableClock(MT6516_PDN_PERI_UART2,"MT3326")) + GPS_ERR("disable clock fail\n"); + #endif + if (hw->ext_power_off) { + err = hw->ext_power_off(force); + if (err) + GPS_ERR("ext_power_off fail\n"); + } +#if 0 +#ifndef MTK_MT6620 + if (force) { + /*TO FIX: the LDO pin is shared between modem + and external devices, it doesn't work if only + calling hwPowerDown*/ + typedef enum + { + V3GTX_ENABLE_WITH_SRCLKEN = 0, + V3GTX_ENABLE_WITH_V3GTX_EN + }v3gtx_on_sel_enum; + extern void pmic_v3gtx_on_sel(v3gtx_on_sel_enum); + pmic_v3gtx_on_sel(V3GTX_ENABLE_WITH_V3GTX_EN); + GPS_DBG("force power off!!\n"); + } + + if (!hwPowerDown(MT6516_POWER_V3GTX,"MT3326" )) + GPS_ERR("power off fail\n"); +#endif +#endif + } + power_on = on; +} +/*****************************************************************************/ +static inline void mt3326_gps_reset(struct mt3326_gps_hardware *hw, int delay, int force) +{ + mt3326_gps_power(hw, 1, FALSE); + mdelay(delay); + mt3326_gps_power(hw, 0, force); + mdelay(delay); + mt3326_gps_power(hw, 1, FALSE); +} +/******************************************************************************/ +static inline int mt3326_gps_set_suspend(struct gps_drv_obj* obj, + unsigned char suspend) +{ + if (!obj) + return -1; + mutex_lock(&obj->sem); + if (obj->suspend != suspend) { + GPS_DBG("issue sysfs_notify : %p\n", obj->kobj->sd); + sysfs_notify(obj->kobj, NULL, "suspend"); + } + obj->suspend = suspend; + mutex_unlock(&obj->sem); + return 0; +} +/******************************************************************************/ +static inline int mt3326_gps_set_pwrctl(struct gps_drv_obj* obj, + unsigned char pwrctl) +{ + int err = 0; + if (!obj) + return -1; + mutex_lock(&obj->sem); + + if ((pwrctl == GPS_PWRCTL_ON) || (pwrctl == GPS_PWRCTL_OFF)) { + obj->pwrctl = pwrctl; + mt3326_gps_power(obj->hw, pwrctl, FALSE); + } else if (pwrctl == GPS_PWRCTL_OFF_FORCE) { + obj->pwrctl = pwrctl; + mt3326_gps_power(obj->hw, pwrctl, TRUE); + } else if (pwrctl == GPS_PWRCTL_RST) { + mt3326_gps_reset(obj->hw, obj->rdelay, FALSE); + obj->pwrctl = GPS_PWRCTL_ON; + } else if (pwrctl == GPS_PWRCTL_RST_FORCE) { + mt3326_gps_reset(obj->hw, obj->rdelay, TRUE); + obj->pwrctl = GPS_PWRCTL_ON; + } else { + err = -1; + } + mutex_unlock(&obj->sem); + return err; +} + /******************************************************************************/ +static inline int mt3326_gps_set_status(struct gps_drv_obj* obj, + const char* buf, size_t count) +{ + int err = 0; + int year, mon, day, hour, minute, sec, cnt, reason, idx; + if (!obj) + return -1; + + mutex_lock(&obj->sem); + if (sscanf(buf, "(%d/%d/%d %d:%d:%d) - %d/%d", &year, &mon, &day, + &hour, &minute, &sec, &cnt, &reason) == 8) { + int number = (int)(sizeof(obj->status.items)/sizeof(obj->status.items[0])); + idx = obj->status.index % number; + obj->status.items[idx].year = (unsigned char)year; + obj->status.items[idx].month = (unsigned char)mon; + obj->status.items[idx].day = (unsigned char)day; + obj->status.items[idx].hour = (unsigned char)hour; + obj->status.items[idx].minute= (unsigned char)minute; + obj->status.items[idx].sec = (unsigned char)sec; + obj->status.items[idx].count = (unsigned char)cnt; + obj->status.items[idx].reason= (unsigned char)reason; + obj->status.index ++; + } else { + err = -1; + } + mutex_unlock(&obj->sem); + return err; +} +/******************************************************************************/ +static inline int mt3326_gps_set_state(struct gps_drv_obj* obj, + unsigned char state) +{ + int err = 0; + if (!obj) + return -1; + mutex_lock(&obj->sem); + if (state < GPS_STATE_MAX) + obj->state = state; + else + err = -1; + mutex_unlock(&obj->sem); + return err; +} +/******************************************************************************/ +static inline int mt3326_gps_set_pwrsave(struct gps_drv_obj* obj, + unsigned char pwrsave) +{ + int err = 0; + + if (!obj) + return -1; + mutex_lock(&obj->sem); + if (pwrsave < GPS_PWRSAVE_MAX) + obj->pwrsave = pwrsave; + else + err = -1; + mutex_unlock(&obj->sem); + return err; +} +/******************************************************************************/ +static inline int mt3326_gps_dev_suspend(struct gps_drv_obj *obj) +{ +#if defined(GPS_SUSPEND_RESUME) + int err; + + if ((err = mt3326_gps_set_suspend(obj, GPS_PWR_SUSPEND))) + GPS_DBG("set suspend fail: %d\n", err); + if ((err = mt3326_gps_set_pwrctl(obj, GPS_PWRCTL_OFF))) + GPS_DBG("set pwrctl fail: %d\n", err); + return err; +#endif +} +/******************************************************************************/ +static inline int mt3326_gps_dev_resume(struct gps_drv_obj *obj) +{ +#if defined(GPS_SUSPEND_RESUME) + int err; + + if ((err = mt3326_gps_set_suspend(obj, GPS_PWR_RESUME))) + GPS_DBG("set suspend fail: %d\n", err); + /*don't power on device automatically*/ + return err; +#endif +} +/******************************************************************************/ +static ssize_t mt3326_show_pwrctl(struct device* dev, + struct device_attribute *attr, char *buf) +{ + struct gps_drv_obj *obj; + ssize_t res; + if (!dev) { + GPS_DBG("dev is null!!\n"); + return 0; + } else if (!(obj = (struct gps_drv_obj*)dev_get_drvdata(dev))) { + GPS_DBG("drv data is null!!\n"); + return 0; + } + mutex_lock(&obj->sem); + res = snprintf(buf, PAGE_SIZE, "%d\n", obj->pwrctl); + mutex_unlock(&obj->sem); + return res; +} +/******************************************************************************/ +static ssize_t mt3326_store_pwrctl(struct device* dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct gps_drv_obj *obj; + if (!dev) { + GPS_DBG("dev is null!!\n"); + return 0; + } else if (!(obj = (struct gps_drv_obj*)dev_get_drvdata(dev))) { + GPS_DBG("drv data is null!!\n"); + return 0; + } + if ((count == 1) || + ((count == 2) && (buf[1] == '\n'))) { + unsigned char pwrctl = buf[0] - '0'; + if (!mt3326_gps_set_pwrctl(obj, pwrctl)) + return count; + } + GPS_DBG("invalid content: '%s', length = %d\n", buf, count); + return count; +} +/******************************************************************************/ +static ssize_t mt3326_show_suspend(struct device* dev, + struct device_attribute *attr, char *buf) +{ + struct gps_drv_obj *obj; + ssize_t res; + if (!dev) { + GPS_DBG("dev is null!!\n"); + return 0; + } else if (!(obj = (struct gps_drv_obj*)dev_get_drvdata(dev))) { + GPS_DBG("drv data is null!!\n"); + return 0; + } + mutex_lock(&obj->sem); + res = snprintf(buf, PAGE_SIZE, "%d\n", obj->suspend); + mutex_unlock(&obj->sem); + return res; +} +/******************************************************************************/ +static ssize_t mt3326_store_suspend(struct device* dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct gps_drv_obj *obj; + if (!dev) { + GPS_DBG("dev is null!!\n"); + return 0; + } else if (!(obj = (struct gps_drv_obj*)dev_get_drvdata(dev))) { + GPS_DBG("drv data is null!!\n"); + return 0; + } + if ((count == 1) || + ((count == 2) && (buf[1] == '\n'))) { + unsigned char suspend = buf[0] - '0'; + if (suspend == GPS_PWR_SUSPEND) { + if (!mt3326_gps_dev_suspend(obj)) + return count; + } else if (suspend == GPS_PWR_RESUME) { + if (!mt3326_gps_dev_resume(obj)) + return count; + } + } + GPS_DBG("invalid content: '%s', length = %d\n", buf, count); + return count; +} +/******************************************************************************/ +static ssize_t mt3326_show_status(struct device* dev, + struct device_attribute *attr, char *buf) +{ + int res, idx, num, left, cnt, len; + struct gps_drv_obj *obj; + char *reason = NULL; + int reason_max = (int)(sizeof(str_reason)/sizeof(str_reason[0])); + + if (!dev) { + GPS_DBG("dev is null!!\n"); + return 0; + } else if (!(obj = (struct gps_drv_obj*)dev_get_drvdata(dev))) { + GPS_DBG("drv data is null!!\n"); + return 0; + } + mutex_lock(&obj->sem); + num = (int)(sizeof(obj->status.items)/sizeof(obj->status.items[0])); + left = PAGE_SIZE; + cnt = 0; + len = 0; + for (idx = 0; idx < num; idx++) { + if (obj->status.items[idx].month == 0) + continue; + if (obj->status.items[idx].reason >= reason_max) + reason = str_reason[reason_max-1]; + else + reason = str_reason[obj->status.items[idx].reason]; + cnt = snprintf(buf+len, left, "[%d] %.4d/%.2d/%.2d %.2d:%.2d:%.2d - %d, %s\n", idx, + obj->status.items[idx].year + 1900, obj->status.items[idx].month, + obj->status.items[idx].day, obj->status.items[idx].hour, + obj->status.items[idx].minute, obj->status.items[idx].sec, + obj->status.items[idx].count, reason); + left -= cnt; + len += cnt; + } + res = PAGE_SIZE - left; + mutex_unlock(&obj->sem); + return res; +} +/******************************************************************************/ +static ssize_t mt3326_store_status(struct device* dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct gps_drv_obj *obj; + if (!dev) { + GPS_DBG("dev is null!!\n"); + return 0; + } else if (!(obj = (struct gps_drv_obj*)dev_get_drvdata(dev))) { + GPS_DBG("drv data is null!!\n"); + return 0; + } + if (!mt3326_gps_set_status(obj, buf, count)) + return count; + GPS_DBG("invalid content: '%s', length = %d\n", buf, count); + return count; +} +/******************************************************************************/ +static ssize_t mt3326_show_state(struct device* dev, + struct device_attribute *attr, char *buf) +{ + ssize_t res; + struct gps_drv_obj *obj; + if (!dev) { + GPS_DBG("dev is null!!\n"); + return 0; + } else if (!(obj = (struct gps_drv_obj*)dev_get_drvdata(dev))) { + GPS_DBG("drv data is null!!\n"); + return 0; + } + mutex_lock(&obj->sem); + res = snprintf(buf, PAGE_SIZE, "%d\n", obj->state); + mutex_unlock(&obj->sem); + return res; +} +/******************************************************************************/ +static ssize_t mt3326_store_state(struct device* dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct gps_drv_obj *obj; + if (!dev) { + GPS_DBG("dev is null!!\n"); + return 0; + } else if (!(obj = (struct gps_drv_obj*)dev_get_drvdata(dev))) { + GPS_DBG("drv data is null!!\n"); + return 0; + } + if ((count == 1) || + ((count == 2) && (buf[1] == '\n'))) { /*To Do: dynamic change according to input*/ + unsigned char state = buf[0] - '0'; + if (!mt3326_gps_set_state(obj, state)) + return count; + } + GPS_DBG("invalid content: '%s', length = %d\n", buf, count); + return count; +} +/******************************************************************************/ +static ssize_t mt3326_show_pwrsave(struct device* dev, + struct device_attribute *attr, char *buf) +{ + ssize_t res; + struct gps_drv_obj *obj; + if (!dev) { + GPS_DBG("dev is null!!\n"); + return 0; + } else if (!(obj = (struct gps_drv_obj*)dev_get_drvdata(dev))) { + GPS_DBG("drv data is null!!\n"); + return 0; + } + mutex_lock(&obj->sem); + res = snprintf(buf, PAGE_SIZE, "%d\n", obj->pwrsave); + mutex_unlock(&obj->sem); + return res; +} +/******************************************************************************/ +static ssize_t mt3326_store_pwrsave(struct device* dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct gps_drv_obj *obj; + if (!dev) { + GPS_DBG("dev is null!!\n"); + return 0; + } else if (!(obj = (struct gps_drv_obj*)dev_get_drvdata(dev))) { + GPS_DBG("drv data is null!!\n"); + return 0; + } + if ((count == 1) || + ((count == 2) && (buf[1] == '\n'))) { + unsigned char pwrsave = buf[0] - '0'; + if (!mt3326_gps_set_pwrsave(obj, pwrsave)) + return count; + } + GPS_DBG("invalid content: '%s', length = %d\n", buf, count); + return count; +} +/******************************************************************************/ +#if defined(GPS_CONFIGURABLE_RESET_DELAY) +/******************************************************************************/ +static ssize_t mt3326_show_rdelay(struct device* dev, + struct device_attribute *attr, char *buf) +{ + ssize_t res; + struct gps_drv_obj *obj; + if (!dev) { + GPS_DBG("dev is null!!\n"); + return 0; + } else if (!(obj = (struct gps_drv_obj*)dev_get_drvdata(dev))) { + GPS_DBG("drv data is null!!\n"); + return 0; + } + mutex_lock(&obj->sem); + res = snprintf(buf, PAGE_SIZE, "%d\n", obj->rdelay); + mutex_unlock(&obj->sem); + return res; +} +/******************************************************************************/ +static ssize_t mt3326_store_rdelay(struct device* dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct gps_drv_obj *obj; + int rdelay; + char *end; + if (!dev) { + GPS_DBG("dev is null!!\n"); + return 0; + } else if (!(obj = (struct gps_drv_obj*)dev_get_drvdata(dev))) { + GPS_DBG("drv data is null!!\n"); + return 0; + } + end = (char*)buf+count; + rdelay = (int)simple_strtol(buf, &end, 10); + if (rdelay < 2000) { + mutex_lock(&obj->sem); + obj->rdelay = rdelay; + mutex_unlock(&obj->sem); + return count; + } + GPS_DBG("invalid content: '%s', length = %d\n", buf, count); + return count; +} +/******************************************************************************/ +#endif +/******************************************************************************/ +DEVICE_ATTR(pwrctl, S_IWUSR | S_IWGRP | S_IRUGO, mt3326_show_pwrctl, mt3326_store_pwrctl); +DEVICE_ATTR(suspend, S_IWUSR | S_IWGRP | S_IRUGO, mt3326_show_suspend,mt3326_store_suspend); +DEVICE_ATTR(status, S_IWUSR | S_IWGRP | S_IRUGO, mt3326_show_status, mt3326_store_status); +DEVICE_ATTR(state, S_IWUSR | S_IWGRP | S_IRUGO, mt3326_show_state, mt3326_store_state); +DEVICE_ATTR(pwrsave, S_IWUSR | S_IWGRP | S_IRUGO, mt3326_show_pwrsave,mt3326_store_pwrsave); +#if defined(GPS_CONFIGURABLE_RESET_DELAY) +DEVICE_ATTR(rdelay, S_IWUSR | S_IWGRP | S_IRUGO, mt3326_show_rdelay ,mt3326_store_rdelay); +#endif +static struct device_attribute *gps_attr_list[] = { + &dev_attr_pwrctl, + &dev_attr_suspend, + &dev_attr_status, + &dev_attr_state, + &dev_attr_pwrsave, +#if defined(GPS_CONFIGURABLE_RESET_DELAY) + &dev_attr_rdelay, +#endif +}; +/******************************************************************************/ +static int mt3326_gps_create_attr(struct device *dev) +{ + int idx, err = 0; + int num = (int)(sizeof(gps_attr_list)/sizeof(gps_attr_list[0])); + if (!dev) + return -EINVAL; + + GPS_TRC(); + for (idx = 0; idx < num; idx++) { + if ((err = device_create_file(dev, gps_attr_list[idx]))) { + GPS_DBG("device_create_file (%s) = %d\n", gps_attr_list[idx]->attr.name, err); + break; + } + } + + return err; +} +/******************************************************************************/ +static int mt3326_gps_delete_attr(struct device *dev) +{ + int idx ,err = 0; + int num = (int)(sizeof(gps_attr_list)/sizeof(gps_attr_list[0])); + + if (!dev) + return -EINVAL; + + for (idx = 0; idx < num; idx++) + device_remove_file(dev, gps_attr_list[idx]); + + return err; +} +/******************************************************************************/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)) +static int mt3326_gps_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + return -ENOIOCTLCMD; +} +#else +long mt3326_gps_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + GPS_DBG("mt3326_gps_unlocked_ioctl!!\n"); + return -ENOIOCTLCMD; +} +#endif +/*****************************************************************************/ +static int mt3326_gps_open(struct inode *inode, struct file *file) +{ + GPS_TRC(); + file->private_data = &gps_private; //all files share the same buffer + return nonseekable_open(inode, file); +} +/*****************************************************************************/ +static int mt3326_gps_release(struct inode *inode, struct file *file) +{ + struct gps_data *dev = file->private_data; + + GPS_TRC(); + + if (dev) + file->private_data = NULL; + + return 0; +} +/******************************************************************************/ +static ssize_t mt3326_gps_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + struct gps_data *dev = file->private_data; + ssize_t ret = 0; + int copy_len = 0; + + GPS_TRC(); + + if (!dev) + return -EINVAL; + + //printk("%s: %d\n", __FUNCTION__, dev->dat_len); + if (signal_pending(current)) + return -ERESTARTSYS; + + if (down_interruptible(&dev->sem)) + return -ERESTARTSYS; + + if (dev->dat_len == 0){ /*no data to be read*/ + up(&dev->sem); + if (file->f_flags & O_NONBLOCK) /*non-block mode*/ + return -EAGAIN; + do {/*block mode*/ + ret = wait_event_interruptible(dev->read_wait, (dev->dat_len > 0)); + if (ret == -ERESTARTSYS) + return -ERESTARTSYS; + }while(ret == 0); + if (down_interruptible(&dev->sem)) + return -ERESTARTSYS; + } + + /*data is available*/ + copy_len = (dev->dat_len < (int)count) ? (dev->dat_len) : (int)(count); + if (copy_to_user(buf, dev->dat_buf+dev->dat_pos, (unsigned long)copy_len)){ + GPS_DBG("copy_to_user error: 0x%X 0x%X, %d\n", (unsigned int)buf, (unsigned int)dev->dat_buf, dev->dat_len); + ret = -EFAULT; + } else { + GPS_VER("mt3326_gps_read(%d,%d,%d) = %d\n", count, dev->dat_pos, dev->dat_len, copy_len); + if (dev->dat_len > (copy_len+dev->dat_pos)) { + dev->dat_pos += copy_len; + } else { + dev->dat_len = 0; + dev->dat_pos = 0; + } + ret = copy_len; + } + + up(&dev->sem); + GPS_VER("%s return %d bytes\n", __FUNCTION__, ret); + return ret; +} +/******************************************************************************/ +static ssize_t mt3326_gps_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +{ + struct gps_data *dev = file->private_data; + ssize_t ret = 0; + + GPS_TRC(); + + if (!dev) + return -EINVAL; + + if (!count) /*no data written*/ + return 0; + + if (signal_pending(current)) + return -ERESTARTSYS; + + if (down_interruptible(&dev->sem)) + return -ERESTARTSYS; + + if (copy_from_user(dev->dat_buf, buf, count)) { + GPS_DBG("copy_from_user error"); + ret = -EFAULT; + } else { + dev->dat_len = count; + dev->dat_pos = 0; + ret = count; + } + up(&dev->sem); + wake_up_interruptible(&dev->read_wait); + GPS_VER("%s: write %d bytes\n", __FUNCTION__, dev->dat_len); + return ret; +} +/******************************************************************************/ +static unsigned int mt3326_gps_poll(struct file *file, poll_table *wait) +{ + struct gps_data *dev = file->private_data; + unsigned int mask = 0; + + GPS_TRC(); + + if (!dev) + return 0; + + down(&dev->sem); + poll_wait(file, &dev->read_wait, wait); + if (dev->dat_len != 0) /*readable if data is available*/ + mask = (POLLIN|POLLRDNORM) | (POLLOUT|POLLWRNORM); + else /*always writable*/ + mask = (POLLOUT|POLLWRNORM); + up(&dev->sem); + GPS_VER("%s: mask : 0x%X\n", __FUNCTION__, mask); + return mask; +} +/*****************************************************************************/ +/* Kernel interface */ +static struct file_operations mt3326_gps_fops = { + .owner = THIS_MODULE, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)) + .ioctl = mt3326_gps_ioctl, +#else + .unlocked_ioctl = mt3326_gps_unlocked_ioctl, +#endif + .open = mt3326_gps_open, + .read = mt3326_gps_read, + .write = mt3326_gps_write, + .release = mt3326_gps_release, + .poll = mt3326_gps_poll, +}; +/*****************************************************************************/ +extern unsigned int reset_state; +/*****************************************************************************/ +static void mt3326_gps_hw_init(struct mt3326_gps_hardware *hw) +{ + mt3326_gps_power(hw, 1, FALSE); +} +/*****************************************************************************/ +static void mt3326_gps_hw_exit(struct mt3326_gps_hardware *hw) +{ + mt3326_gps_power(hw, 0, FALSE); +} +/*****************************************************************************/ +static int mt3326_gps_probe(struct platform_device *dev) +{ + int ret = 0, err = 0; + struct gps_drv_obj *drvobj = NULL; + struct mt3326_gps_hardware *hw = (struct mt3326_gps_hardware*)dev->dev.platform_data; + struct gps_dev_obj *devobj = NULL; + + if (!(devobj = kzalloc(sizeof(*devobj), GFP_KERNEL))) + { + GPS_ERR("-ENOMEM\n"); + err = -ENOMEM; + goto error; + } + + mt3326_gps_hw_init(hw); + + GPS_DBG("Registering chardev\n"); + ret = alloc_chrdev_region(&devobj->devno, 0, 1, GPS_DEVNAME); + if (ret) { + GPS_ERR("alloc_chrdev_region fail: %d\n", ret); + goto error; + } else { + GPS_DBG("major: %d, minor: %d\n", MAJOR(devobj->devno), MINOR(devobj->devno)); + } + cdev_init(&devobj->chdev, &mt3326_gps_fops); + devobj->chdev.owner = THIS_MODULE; + err = cdev_add(&devobj->chdev, devobj->devno, 1); + if (err) { + GPS_ERR("cdev_add fail: %d\n", err); + goto error; + } + + if (!(drvobj = kmalloc(sizeof(*drvobj), GFP_KERNEL))) { + err = -ENOMEM; + goto error; + } + memset(drvobj, 0 ,sizeof(*drvobj)); + + devobj->cls = class_create(THIS_MODULE, "gpsdrv"); + if (IS_ERR(devobj->cls)) { + GPS_ERR("Unable to create class, err = %d\n", (int)PTR_ERR(devobj->cls)); + goto error; + } + devobj->dev = device_create(devobj->cls, NULL, devobj->devno, drvobj, "gps"); + drvobj->hw = hw; + drvobj->pwrctl = 0; + drvobj->suspend = 0; + drvobj->state = GPS_STATE_UNSUPPORTED; + drvobj->pwrsave = GPS_PWRSAVE_UNSUPPORTED; + drvobj->rdelay = 50; + drvobj->kobj = &devobj->dev->kobj; + mutex_init(&drvobj->sem); + + if ((err = mt3326_gps_create_attr(devobj->dev))) + goto error; + + /*initialize members*/ + spin_lock_init(&gps_private.lock); + init_waitqueue_head(&gps_private.read_wait); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)) + init_MUTEX(&gps_private.sem); +#else + sema_init(&gps_private.sem, 1); +#endif + gps_private.dat_len = 0; + gps_private.dat_pos = 0; + memset(gps_private.dat_buf, 0x00, sizeof(gps_private.dat_buf)); + + /*set platform data: + a new device created for gps */ + platform_set_drvdata(dev, devobj); + + GPS_DBG("Done\n"); + return 0; + +error: + if (err == 0) + cdev_del(&devobj->chdev); + if (ret == 0) + unregister_chrdev_region(devobj->devno, 1); + return -1; +} +/*****************************************************************************/ +static int mt3326_gps_remove(struct platform_device *dev) +{ + struct gps_dev_obj *devobj = (struct gps_dev_obj*)platform_get_drvdata(dev); + struct gps_drv_obj *drvobj = (struct gps_drv_obj*)dev_get_drvdata(devobj->dev); + int err; + + if (!devobj || !drvobj) { + GPS_ERR("null pointer: %p, %p\n", devobj, drvobj); + return -1; + } + + GPS_DBG("Unregistering chardev\n"); + kfree(devobj); + + cdev_del(&devobj->chdev); + unregister_chrdev_region(devobj->devno, 1); + + mt3326_gps_hw_exit(devobj->hw); + if ((err = mt3326_gps_delete_attr(devobj->dev))) + GPS_ERR("delete attr fails: %d\n", err); + device_destroy(devobj->cls, devobj->devno); + class_destroy(devobj->cls); + GPS_DBG("Done\n"); + return 0; +} +/*****************************************************************************/ +static void mt3326_gps_shutdown(struct platform_device *dev) +{ + struct gps_dev_obj *devobj = (struct gps_dev_obj*)platform_get_drvdata(dev); + GPS_DBG("Shutting down\n"); + mt3326_gps_hw_exit(devobj->hw); +} +/*****************************************************************************/ +#ifdef CONFIG_PM +/*****************************************************************************/ +static int mt3326_gps_suspend(struct platform_device *dev, pm_message_t state) +{ + int err = 0; + struct gps_dev_obj *devobj = (struct gps_dev_obj*)platform_get_drvdata(dev); + struct gps_drv_obj *drvobj = (struct gps_drv_obj*)dev_get_drvdata(devobj->dev); + + if (!devobj || !drvobj) { + GPS_ERR("null pointer: %p, %p\n", devobj, drvobj); + return -1; + } + + GPS_DBG("dev = %p, event = %u,", dev, state.event); + if (state.event == PM_EVENT_SUSPEND) { + err = mt3326_gps_dev_suspend(drvobj); + } + return err; +} +/*****************************************************************************/ +static int mt3326_gps_resume(struct platform_device *dev) +{ + struct gps_dev_obj *devobj = (struct gps_dev_obj*)platform_get_drvdata(dev); + struct gps_drv_obj *drvobj = (struct gps_drv_obj*)dev_get_drvdata(devobj->dev); + + GPS_DBG(""); + return mt3326_gps_dev_resume(drvobj); +} +/*****************************************************************************/ +#endif /* CONFIG_PM */ +/*****************************************************************************/ +static struct platform_driver mt3326_gps_driver = +{ + .probe = mt3326_gps_probe, + .remove = mt3326_gps_remove, + .shutdown = mt3326_gps_shutdown, +#if defined(CONFIG_PM) + .suspend = mt3326_gps_suspend, + .resume = mt3326_gps_resume, +#endif + .driver = { + .name = GPS_DEVNAME, + .bus = &platform_bus_type, + }, +}; +/*****************************************************************************/ +static int __init mt3326_gps_mod_init(void) +{ + int ret = 0; + GPS_TRC(); + + //ret = driver_register(&mt3326_gps_driver); + ret = platform_driver_register(&mt3326_gps_driver); + + return ret; +} +/*****************************************************************************/ +static void __exit mt3326_gps_mod_exit(void) +{ + GPS_TRC(); + platform_driver_unregister(&mt3326_gps_driver); +} +/*****************************************************************************/ +module_init(mt3326_gps_mod_init); +module_exit(mt3326_gps_mod_exit); +/*****************************************************************************/ +MODULE_AUTHOR("MingHsien Hsieh "); +MODULE_DESCRIPTION("MT3326 GPS Driver"); +MODULE_LICENSE("GPL"); + + + diff --git a/include/linux/gps.h b/include/linux/gps.h new file mode 100755 index 000000000000..4a2a4a3e1e58 --- /dev/null +++ b/include/linux/gps.h @@ -0,0 +1,25 @@ + +#ifndef __GPS_H__ +#define __GPS_H__ + +//CC&C Johnson.Wang +//mtk gps device +static struct mt3326_gps_hardware { + int (*ext_power_on)(int); + int (*ext_power_off)(int); +}; + +static struct mt3326_gps_hardware mt3326_gps_hw = { + .ext_power_on = NULL, + .ext_power_off = NULL, +}; + +static struct platform_device mt3326_device_gps = { + .name = "mt3326-gps", + .id = -1, + .dev = { + .platform_data = &mt3326_gps_hw, + }, +}; + +#endif // __GPS_H__ From 9c85cb1d280bb409c8a42047e82f08f1423b8f78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=8B=E7=A7=80=E6=9D=B0?= Date: Fri, 10 Aug 2012 14:35:51 +0800 Subject: [PATCH 146/261] phonepad: solve "assignment from incompatible pointer type" warning in codec driver. --- sound/soc/codecs/rt3261-dsp.c | 206 +++------------------------------- sound/soc/codecs/rt3261.c | 78 +------------ 2 files changed, 23 insertions(+), 261 deletions(-) diff --git a/sound/soc/codecs/rt3261-dsp.c b/sound/soc/codecs/rt3261-dsp.c index a40e7de04202..af4d6fad1afa 100644 --- a/sound/soc/codecs/rt3261-dsp.c +++ b/sound/soc/codecs/rt3261-dsp.c @@ -32,19 +32,22 @@ static const u16 rt3261_dsp_init[][2] = { #define RT3261_DSP_INIT_NUM \ (sizeof(rt3261_dsp_init) / sizeof(rt3261_dsp_init[0])) -static const u16 rt3261_dsp_48[][2] = { +//static const u16 rt3261_dsp_48[][2] = { +unsigned short rt3261_dsp_48[][2] = { {0x22c8, 0x0026}, {0x22fe, 0x0fa0}, {0x22ff, 0x3893}, {0x22fa, 0x2487}, {0x2301, 0x0002}, }; #define RT3261_DSP_48_NUM (sizeof(rt3261_dsp_48) / sizeof(rt3261_dsp_48[0])) -static const u16 rt3261_dsp_441[][2] = { +//static const u16 rt3261_dsp_441[][2] = { +unsigned short rt3261_dsp_441[][2] = { {0x22c6, 0x0031}, {0x22c7, 0x0050}, {0x22c8, 0x0009}, {0x22fe, 0x0e5b}, {0x22ff, 0x3c83}, {0x22fa, 0x2484}, {0x2301, 0x0001}, }; #define RT3261_DSP_441_NUM (sizeof(rt3261_dsp_441) / sizeof(rt3261_dsp_441[0])) -static const u16 rt3261_dsp_16[][2] = { +//static const u16 rt3261_dsp_16[][2] = { +unsigned short rt3261_dsp_16[][2] = { {0x22c8, 0x0026}, {0x22fa, 0x2484}, {0x2301, 0x0002}, }; #define RT3261_DSP_16_NUM (sizeof(rt3261_dsp_16) / sizeof(rt3261_dsp_16[0])) @@ -394,142 +397,6 @@ static int rt3261_dsp_put(struct snd_kcontrol *kcontrol, return 0; } -static int rt3261_dsp_play_bp_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct rt3261_priv *rt3261 = snd_soc_codec_get_drvdata(codec); - - ucontrol->value.integer.value[0] = rt3261->dsp_play_pass; - - return 0; -} - -static int rt3261_dsp_play_bp_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct rt3261_priv *rt3261 = snd_soc_codec_get_drvdata(codec); - - if (rt3261->dsp_play_pass == ucontrol->value.integer.value[0]) - return 0; - rt3261->dsp_play_pass = ucontrol->value.integer.value[0]; - - rt3261_conn_mux_path(codec, "DAC L2 Mux", - rt3261->dsp_play_pass ? "IF2" : "TxDC"); - rt3261_conn_mux_path(codec, "DAC R2 Mux", - rt3261->dsp_play_pass ? "IF2" : "TxDC"); - - return 0; -} - -static int rt3261_dsp_rec_bp_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct rt3261_priv *rt3261 = snd_soc_codec_get_drvdata(codec); - - ucontrol->value.integer.value[0] = rt3261->dsp_rec_pass; - - return 0; -} - -static int rt3261_dsp_rec_bp_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct rt3261_priv *rt3261 = snd_soc_codec_get_drvdata(codec); - - if (rt3261->dsp_rec_pass == ucontrol->value.integer.value[0]) - return 0; - rt3261->dsp_rec_pass = ucontrol->value.integer.value[0]; - - rt3261_conn_mux_path(codec, "IF2 ADC L Mux", - rt3261->dsp_rec_pass ? "Mono ADC MIXL" : "TxDP"); - rt3261_conn_mux_path(codec, "IF2 ADC R Mux", - rt3261->dsp_rec_pass ? "Mono ADC MIXR" : "TxDP"); - - return 0; -} - -static int rt3261_dac_active_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct snd_soc_dapm_context *dapm = &codec->dapm; - struct snd_soc_dapm_widget *w; - - list_for_each_entry(w, &dapm->card->widgets, list) - { - if (!w->sname || w->dapm != dapm) - continue; - if (strstr(w->sname, "Playback")) { - pr_info("widget %s %s\n", w->name, w->sname); - ucontrol->value.integer.value[0] = w->active; - break; - } - } - return 0; -} - -static int rt3261_dac_active_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct snd_soc_dapm_context *dapm = &codec->dapm; - struct snd_soc_dapm_widget *w; - - list_for_each_entry(w, &dapm->card->widgets, list) - { - if (!w->sname || w->dapm != dapm) - continue; - if (strstr(w->sname, "Playback")) { - pr_info("widget %s %s\n", w->name, w->sname); - w->active = 1; - } - } - return 0; -} - -static int rt3261_adc_active_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct snd_soc_dapm_context *dapm = &codec->dapm; - struct snd_soc_dapm_widget *w; - - list_for_each_entry(w, &dapm->card->widgets, list) - { - if (!w->sname || w->dapm != dapm) - continue; - if (strstr(w->sname, "Capture")) { - pr_info("widget %s %s\n", w->name, w->sname); - ucontrol->value.integer.value[0] = w->active; - break; - } - } - return 0; -} - -static int rt3261_adc_active_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct snd_soc_dapm_context *dapm = &codec->dapm; - struct snd_soc_dapm_widget *w; - - list_for_each_entry(w, &dapm->card->widgets, list) - { - if (!w->sname || w->dapm != dapm) - continue; - if (strstr(w->sname, "Capture")) { - pr_info("widget %s %s\n", w->name, w->sname); - w->active = 1; - } - } - return 0; -} - /* DSP Path Control 1 */ static const char *rt3261_src_rxdp_mode[] = { "Normal", "Divided by 3"}; @@ -617,14 +484,6 @@ static const struct snd_kcontrol_new rt3261_dsp_snd_controls[] = { /* AEC */ SOC_ENUM_EXT("DSP Function Switch", rt3261_dsp_enum, rt3261_dsp_get, rt3261_dsp_put), - SOC_SINGLE_EXT("DSP Playback Bypass", 0, 0, 1, 0, - rt3261_dsp_play_bp_get, rt3261_dsp_play_bp_put), - SOC_SINGLE_EXT("DSP Record Bypass", 0, 0, 1, 0, - rt3261_dsp_rec_bp_get, rt3261_dsp_rec_bp_put), - SOC_SINGLE_EXT("DAC Switch", 0, 0, 1, 0, - rt3261_dac_active_get, rt3261_dac_active_put), - SOC_SINGLE_EXT("ADC Switch", 0, 0, 1, 0, - rt3261_adc_active_get, rt3261_adc_active_put), }; static int rt3261_dsp_patch_3(struct snd_soc_codec *codec) @@ -898,7 +757,8 @@ static int rt3261_dsp_rate(struct snd_soc_codec *codec, int rate) static int rt3261_dsp_set_mode(struct snd_soc_codec *codec, int mode) { struct rt3261_dsp_param param; - int ret, i, tab_num; + int ret, i; +/* unsigned short (*mode_tab)[2]; switch (mode) { @@ -925,12 +785,12 @@ static int rt3261_dsp_set_mode(struct snd_soc_codec *codec, int mode) dev_info(codec->dev, "Disable\n"); return 0; } - +*/ param.cmd_fmt = 0x00e0; param.cmd = RT3261_DSP_CMD_MW; - for (i = 0; i < tab_num; i++) { - param.addr = mode_tab[i][0]; - param.data = mode_tab[i][1]; + for (i = 0; i < RT3261_DSP_AEC_NUM; i++) { + param.addr = rt3261_dsp_aec_ns_fens[i][0]; + param.data = rt3261_dsp_aec_ns_fens[i][1]; ret = rt3261_dsp_write(codec, ¶m); if (ret < 0) goto mode_err; @@ -1118,27 +978,21 @@ static ssize_t rt3261_dsp_show(struct device *dev, struct i2c_client *client = to_i2c_client(dev); struct rt3261_priv *rt3261 = i2c_get_clientdata(client); struct snd_soc_codec *codec = rt3261->codec; - unsigned short (*rt3261_dsp_tab)[2]; +// unsigned short (*rt3261_dsp_tab)[2]; unsigned int val; - int cnt = 0, i, tab_num; + int cnt = 0, i; switch (rt3261->dsp_sw) { case RT3261_DSP_AEC_NS_FENS: cnt += sprintf(buf, "[ RT3261 DSP 'AEC' ]\n"); - rt3261_dsp_tab = rt3261_dsp_aec_ns_fens; - tab_num = RT3261_DSP_AEC_NUM; break; case RT3261_DSP_HFBF: cnt += sprintf(buf, "[ RT3261 DSP 'Beamforming' ]\n"); - rt3261_dsp_tab = rt3261_dsp_hfbf; - tab_num = RT3261_DSP_HFBF_NUM; break; case RT3261_DSP_FFP: cnt += sprintf(buf, "[ RT3261 DSP 'Far Field Pick-up' ]\n"); - rt3261_dsp_tab = rt3261_dsp_ffp; - tab_num = RT3261_DSP_FFP_NUM; break; case RT3261_DSP_DIS: @@ -1147,14 +1001,14 @@ static ssize_t rt3261_dsp_show(struct device *dev, goto dsp_done; } - for (i = 0; i < tab_num; i++) { + for (i = 0; i < RT3261_DSP_AEC_NUM; i++) { if (cnt + RT3261_DSP_REG_DISP_LEN >= PAGE_SIZE) break; - val = rt3261_dsp_read(codec, rt3261_dsp_tab[i][0]); + val = rt3261_dsp_read(codec, rt3261_dsp_aec_ns_fens[i][0]); if (!val) continue; cnt += snprintf(buf + cnt, RT3261_DSP_REG_DISP_LEN, - "%04x: %04x\n", rt3261_dsp_tab[i][0], val); + "%04x: %04x\n", rt3261_dsp_aec_ns_fens[i][0], val); } dsp_done: @@ -1221,32 +1075,6 @@ int rt3261_dsp_probe(struct snd_soc_codec *codec) } EXPORT_SYMBOL_GPL(rt3261_dsp_probe); -int do_rt3261_dsp_set_mode(struct snd_soc_codec *codec, int mode) { - struct rt3261_priv *rt3261 = snd_soc_codec_get_drvdata(codec); - dev_dbg(codec->dev, "%s mode=%d\n",__func__,mode); - if(rt3261->dsp_sw == mode) - return 0; - rt3261->dsp_sw = mode; - if(rt3261->dsp_sw == RT3261_DSP_DIS) - rt3261->dsp_play_pass = rt3261->dsp_rec_pass = 1; - else - rt3261->dsp_play_pass = rt3261->dsp_rec_pass = 0; - rt3261_conn_mux_path(codec, "DAC L2 Mux", - rt3261->dsp_play_pass ? "IF2" : "TxDC"); - rt3261_conn_mux_path(codec, "DAC R2 Mux", - rt3261->dsp_play_pass ? "IF2" : "TxDC"); - rt3261_conn_mux_path(codec, "IF2 ADC L Mux", - rt3261->dsp_rec_pass ? "Mono ADC MIXL" : "TxDP"); - rt3261_conn_mux_path(codec, "IF2 ADC R Mux", - rt3261->dsp_rec_pass ? "Mono ADC MIXR" : "TxDP"); - - if(rt3261->dsp_sw != RT3261_DSP_DIS) - rt3261_dsp_snd_effect(codec); - - return 0; -} -EXPORT_SYMBOL_GPL(do_rt3261_dsp_set_mode); - #ifdef RTK_IOCTL int rt_codec_dsp_ioctl_common(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg) { diff --git a/sound/soc/codecs/rt3261.c b/sound/soc/codecs/rt3261.c index aedd746de2fb..3762b2a7fe22 100644 --- a/sound/soc/codecs/rt3261.c +++ b/sound/soc/codecs/rt3261.c @@ -53,7 +53,7 @@ static struct snd_soc_codec *rt3261_codec; #endif #include "rt3261.h" -#if (CONFIG_SND_SOC_RT3261_MODULE | CONFIG_SND_SOC_RT3261) +#if defined (CONFIG_SND_SOC_RT3261) #include "rt3261-dsp.h" #endif @@ -533,72 +533,6 @@ int rt3261_headset_detect(struct snd_soc_codec *codec, int jack_insert) } EXPORT_SYMBOL(rt3261_headset_detect); -/** - * rt3261_conn_mux_path - connect MUX widget path. - * @codec: SoC audio codec device. - * @widget_name: widget name. - * @path_name: path name. - * - * Make MUX path connected and update register. - * - * Returns 0 for success or negative error code. - */ -int rt3261_conn_mux_path(struct snd_soc_codec *codec, - char *widget_name, char *path_name) -{ - struct snd_soc_dapm_context *dapm = &codec->dapm; - struct snd_soc_dapm_widget *w; - struct snd_soc_dapm_path *path; - struct snd_kcontrol_new *kcontrol; - struct soc_enum *em; - unsigned int val, mask, bitmask; - int i, update = 0; - - if (codec == NULL || widget_name == NULL || path_name == NULL) - return -EINVAL; - - list_for_each_entry(w, &dapm->card->widgets, list) - { - if (!w->name || w->dapm != dapm) - continue; - if (!(strcmp(w->name, widget_name))) { - if (w->id != snd_soc_dapm_mux) - return -EINVAL; - dev_info(codec->dev, "w->name=%s\n", w->name); - list_for_each_entry(path, &w->sources, list_sink) - { - if (!(strcmp(path->name, path_name))) - path->connect = 1; - else - path->connect = 0; - dev_info(codec->dev, - "path->name=%s path->connect=%d\n", - path->name, path->connect); - } - update = 1; - break; - } - } - - if (update) { - snd_soc_dapm_sync(dapm); - - kcontrol = &w->kcontrols[0]; - em = (struct soc_enum *)kcontrol->private_value; - for (i = 0; i < em->max; i++) - if (!(strcmp(path_name, em->texts[i]))) - break; - for (bitmask = 1; bitmask < em->max; bitmask <<= 1) - ; - val = i << em->shift_l; - mask = (bitmask - 1) << em->shift_l; - snd_soc_update_bits(codec, em->reg, mask, val); - } - - return 0; -} -EXPORT_SYMBOL(rt3261_conn_mux_path); - static const char *rt3261_dacr2_src[] = { "TxDC_R", "TxDP_R" }; static const SOC_ENUM_SINGLE_DECL(rt3261_dacr2_enum,RT3261_DUMMY_PR3F, @@ -2164,7 +2098,7 @@ static const struct snd_soc_dapm_route rt3261_dapm_routes[] = { {"DAC R2 Mux", "IF2", "IF2 DAC R"}, {"DAC R2 Mux", "IF3", "IF3 DAC R"}, -#if (CONFIG_SND_SOC_RT3261_MODULE | CONFIG_SND_SOC_RT3261) +#if defined (CONFIG_SND_SOC_RT3261) {"DAC R2 Volume", NULL, "Mono dacr Mux"}, {"Mono dacr Mux", "TxDC_R", "DAC R2 Mux"}, {"Mono dacr Mux", "TxDP_R", "IF2 ADC R Mux"}, @@ -2815,7 +2749,7 @@ static int rt3261_probe(struct snd_soc_codec *codec) ARRAY_SIZE(rt3261_dapm_routes)); #if 0 -#if (CONFIG_SND_SOC_RT3261_MODULE | CONFIG_SND_SOC_RT3261) +#if defined (CONFIG_SND_SOC_RT3261) rt3261->dsp_sw = RT3261_DSP_AEC_NS_FENS; rt3261_dsp_probe(codec); #endif @@ -2829,6 +2763,7 @@ static int rt3261_probe(struct snd_soc_codec *codec) ioctl_ops->ioctl_common = rt3261_ioctl_common; realtek_ce_init_hwdep(codec); #endif +#endif #endif ret = device_create_file(codec->dev, &dev_attr_index_reg); @@ -2837,7 +2772,6 @@ static int rt3261_probe(struct snd_soc_codec *codec) "Failed to create index_reg sysfs files: %d\n", ret); return ret; } -#endif rt3261_codec = codec; return 0; } @@ -2851,7 +2785,7 @@ static int rt3261_remove(struct snd_soc_codec *codec) #ifdef CONFIG_PM static int rt3261_suspend(struct snd_soc_codec *codec, pm_message_t state) { -#if (CONFIG_SND_SOC_RT3261_MODULE | CONFIG_SND_SOC_RT3261) +#if defined (CONFIG_SND_SOC_RT3261) /* After opening LDO of DSP, then close LDO of codec. * (1) DSP LDO power on * (2) DSP core power off @@ -2867,7 +2801,7 @@ static int rt3261_suspend(struct snd_soc_codec *codec, pm_message_t state) static int rt3261_resume(struct snd_soc_codec *codec) { rt3261_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -#if (CONFIG_SND_SOC_RT3261_MODULE | CONFIG_SND_SOC_RT3261) +#if defined (CONFIG_SND_SOC_RT3261) /* After opening LDO of codec, then close LDO of DSP. */ //rt3261_dsp_resume(codec); #endif From 08f419f6264c81e4f86626b8ce6d67169daf2f89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=8B=E7=A7=80=E6=9D=B0?= Date: Fri, 10 Aug 2012 15:20:43 +0800 Subject: [PATCH 147/261] phonepad: rt3261 add main mic and headset mic mute controls, add a solution for the speaker destroyed when playback. --- sound/soc/codecs/rt3261.c | 89 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt3261.c b/sound/soc/codecs/rt3261.c index 3762b2a7fe22..38c47f147e05 100644 --- a/sound/soc/codecs/rt3261.c +++ b/sound/soc/codecs/rt3261.c @@ -72,6 +72,9 @@ static struct rt3261_init_reg init_list[] = { {RT3261_ADDA_CLK1 , 0x1114},//73[2] = 1'b {RT3261_MICBIAS , 0x3030},//93[5:4] = 11'b {RT3261_CLS_D_OUT , 0xa000},//8d[11] = 0'b + {RT3261_CLS_D_OVCD , 0x0328},//8c[8] = 1'b + {RT3261_PRIV_INDEX , 0x001d},//PR1d[8] = 1'b; + {RT3261_PRIV_DATA , 0x0347}, {RT3261_PRIV_INDEX , 0x003d},//PR3d[12] = 0'b; PR3d[9] = 1'b {RT3261_PRIV_DATA , 0x2600}, {RT3261_PRIV_INDEX , 0x0012},//PR12 = 0aa8'h @@ -82,10 +85,10 @@ static struct rt3261_init_reg init_list[] = { {RT3261_PRIV_DATA , 0x6115}, {RT3261_PRIV_INDEX , 0x0023},//PR23 = 0804'h {RT3261_PRIV_DATA , 0x0804}, - {RT3261_SPK_VOL , 0x8b8b},//SPKMIX -> SPKVOL - {RT3261_HP_VOL , 0x8888}, - {RT3261_OUTPUT , 0x8888},//unmute OUTVOLL/R - {RT3261_SPO_CLSD_RATIO , 0x0001}, + {RT3261_SPK_VOL , 0x8b8b},//SPKMIX -> SPKVOL + {RT3261_HP_VOL , 0x8888}, + {RT3261_OUTPUT , 0x8888},//unmute OUTVOLL/R + {RT3261_SPO_CLSD_RATIO , 0x0001}, {RT3261_I2S1_SDP , 0xe000}, {RT3261_I2S2_SDP , 0x8040}, }; @@ -627,6 +630,69 @@ static int rt3261_dmic_put(struct snd_kcontrol *kcontrol, return 0; } +//bard 8-9 s +static int rt3261_mic1_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = + (snd_soc_read(codec, RT3261_REC_L2_MIXER) & RT3261_M_BST1_RM_L) >> RT3261_M_BST1_RM_L_SFT; + + return 0; +} + +static int rt3261_mic1_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + if(ucontrol->value.integer.value[0]) { + snd_soc_update_bits(codec, RT3261_REC_L2_MIXER, + RT3261_M_BST1_RM_L, 0); + snd_soc_update_bits(codec, RT3261_REC_R2_MIXER, + RT3261_M_BST1_RM_R, 0); + }else { + snd_soc_update_bits(codec, RT3261_REC_L2_MIXER, + RT3261_M_BST1_RM_L, RT3261_M_BST1_RM_L); + snd_soc_update_bits(codec, RT3261_REC_R2_MIXER, + RT3261_M_BST1_RM_R, RT3261_M_BST1_RM_R); + } + + return 0; +} + +static int rt3261_mic2_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = + (snd_soc_read(codec, RT3261_REC_L2_MIXER) & RT3261_M_BST1_RM_L) >> RT3261_M_BST1_RM_L_SFT; + + return 0; +} + +static int rt3261_mic2_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + if(ucontrol->value.integer.value[0]) { + snd_soc_update_bits(codec, RT3261_REC_L2_MIXER, + RT3261_M_BST4_RM_L, 0); + snd_soc_update_bits(codec, RT3261_REC_R2_MIXER, + RT3261_M_BST4_RM_R, 0); + }else { + snd_soc_update_bits(codec, RT3261_REC_L2_MIXER, + RT3261_M_BST4_RM_L, RT3261_M_BST4_RM_L); + snd_soc_update_bits(codec, RT3261_REC_R2_MIXER, + RT3261_M_BST4_RM_R, RT3261_M_BST4_RM_R); + } + + return 0; +} +//bard 8-9 e /* IN1/IN2 Input Type */ static const char *rt3261_input_mode[] = { @@ -675,7 +741,11 @@ static const char *rt3261_dmic_mode[] = {"Disable", "DMIC1", "DMIC2"}; static const SOC_ENUM_SINGLE_DECL(rt3261_dmic_enum, 0, 0, rt3261_dmic_mode); +//bard 8-9 s +static const char *rt3261_mic_mode[] = {"off", "on",}; +static const SOC_ENUM_SINGLE_DECL(rt3261_mic_enum, 0, 0, rt3261_mic_mode); +//bard 8-9 e #ifdef RT3261_REG_RW #define REGVAL_MAX 0xffff @@ -813,6 +883,16 @@ static const struct snd_kcontrol_new rt3261_snd_controls[] = { .put = rt3261_regctl_put, }, #endif +//bard 8-9 s + SOC_SINGLE_TLV("Main Mic Capture Volume", RT3261_IN1_IN2, + RT3261_BST_SFT1, 8, 0, bst_tlv), + SOC_SINGLE_TLV("Headset Mic Capture Volume", RT3261_IN3_IN4, + RT3261_BST_SFT2, 8, 0, bst_tlv), + SOC_ENUM_EXT("Main Mic Capture Switch", rt3261_mic_enum, + rt3261_mic1_get, rt3261_mic1_put), + SOC_ENUM_EXT("Headset Mic Capture Switch", rt3261_mic_enum, + rt3261_mic2_get, rt3261_mic2_put), +//bard 8-9 e }; /** @@ -2319,6 +2399,7 @@ static int rt3261_hw_params(struct snd_pcm_substream *substream, } dai_sel = get_sdp_info(codec, dai->id); + dai_sel |= (RT3261_U_IF1 | RT3261_U_IF2); if (dai_sel < 0) { dev_err(codec->dev, "Failed to get sdp info: %d\n", dai_sel); return -EINVAL; From d81f17d7a5be5063b27ea3079265ed68bdde64ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Fri, 10 Aug 2012 15:33:43 +0800 Subject: [PATCH 148/261] rk2928: support boot mode --- arch/arm/mach-rk2928/common.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-rk2928/common.c b/arch/arm/mach-rk2928/common.c index 54a3c8da29d8..be088090cfd7 100644 --- a/arch/arm/mach-rk2928/common.c +++ b/arch/arm/mach-rk2928/common.c @@ -13,7 +13,7 @@ #include #include #include -//#include +#include //#include static void __init rk2928_cpu_axi_init(void) @@ -86,11 +86,14 @@ static void __init rk2928_l2_cache_init(void) static int boot_mode; static void __init rk2928_boot_mode_init(void) { - u32 boot_flag = 0; - boot_mode = readl_relaxed(RK2928_GRF_BASE + GRF_OS_REG1); + u32 boot_flag = (readl_relaxed(RK2928_GRF_BASE + GRF_OS_REG4) | (readl_relaxed(RK2928_GRF_BASE + GRF_OS_REG5) << 16)) - SYS_KERNRL_REBOOT_FLAG; + boot_mode = readl_relaxed(RK2928_GRF_BASE + GRF_OS_REG6); + if (boot_flag == BOOT_RECOVER) { + boot_mode = BOOT_MODE_RECOVERY; + } if (boot_mode || boot_flag) - printk("Boot mode: %d flag: 0x%08x\n", boot_mode, boot_flag); + printk("Boot mode: %d flag: %d\n", boot_mode, boot_flag); } int board_boot_mode(void) From bb8e7819154aa313d736354306e3aa6ade03295f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Fri, 10 Aug 2012 15:41:10 +0800 Subject: [PATCH 149/261] rk2928: sdk: rename board-rk30-sdk-tps65910.c to board-rk2928-sdk-tps65910.c --- .../{board-rk30-sdk-tps65910.c => board-rk2928-sdk-tps65910.c} | 0 arch/arm/mach-rk2928/board-rk2928-sdk.c | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/arm/mach-rk2928/{board-rk30-sdk-tps65910.c => board-rk2928-sdk-tps65910.c} (100%) diff --git a/arch/arm/mach-rk2928/board-rk30-sdk-tps65910.c b/arch/arm/mach-rk2928/board-rk2928-sdk-tps65910.c similarity index 100% rename from arch/arm/mach-rk2928/board-rk30-sdk-tps65910.c rename to arch/arm/mach-rk2928/board-rk2928-sdk-tps65910.c diff --git a/arch/arm/mach-rk2928/board-rk2928-sdk.c b/arch/arm/mach-rk2928/board-rk2928-sdk.c index 604a79d7c685..fbb0e781c277 100755 --- a/arch/arm/mach-rk2928/board-rk2928-sdk.c +++ b/arch/arm/mach-rk2928/board-rk2928-sdk.c @@ -1080,7 +1080,7 @@ static struct i2c_board_info __initdata i2c0_info[] = { #ifdef CONFIG_I2C1_RK30 #ifdef CONFIG_MFD_TPS65910 #define TPS65910_HOST_IRQ RK2928_PIN3_PC6 -#include "board-rk30-sdk-tps65910.c" +#include "board-rk2928-sdk-tps65910.c" #endif static struct i2c_board_info __initdata i2c1_info[] = { From cf1a1774b3518e5b99eb36526405093109cda7a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Fri, 10 Aug 2012 15:47:37 +0800 Subject: [PATCH 150/261] rk2928: pm: build pm.c use Thumb instruction set --- arch/arm/mach-rk2928/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-rk2928/Makefile b/arch/arm/mach-rk2928/Makefile index 68053947e830..a2169a7bc77c 100644 --- a/arch/arm/mach-rk2928/Makefile +++ b/arch/arm/mach-rk2928/Makefile @@ -7,6 +7,7 @@ obj-y += iomux.o obj-y += clock.o obj-y += clock_data.o obj-$(CONFIG_PM) += pm.o +CFLAGS_pm.o += -Os -mthumb obj-$(CONFIG_MACH_RK2928_FPGA) += board-rk2928-fpga.o board-rk2928-fpga-key.o obj-$(CONFIG_MACH_RK2928_SDK) += board-rk2928-sdk.o board-rk2928-sdk-key.o From 5808110c436c83285786d430fb302b6f1dd6ea8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E7=9B=9B=E9=A3=9E?= Date: Fri, 10 Aug 2012 15:58:43 +0800 Subject: [PATCH 151/261] rk30:auto-dimming function about light-sensor and backlight-curve --- drivers/input/sensors/lsensor/cm3217.c | 3 ++- drivers/input/sensors/lsensor/ls_al3006.c | 3 ++- drivers/input/sensors/lsensor/ls_stk3171.c | 3 ++- drivers/input/sensors/sensor-dev.c | 1 + include/linux/sensor-dev.h | 1 + 5 files changed, 8 insertions(+), 3 deletions(-) mode change 100755 => 100644 drivers/input/sensors/lsensor/cm3217.c mode change 100755 => 100644 drivers/input/sensors/lsensor/ls_al3006.c mode change 100755 => 100644 drivers/input/sensors/lsensor/ls_stk3171.c mode change 100755 => 100644 drivers/input/sensors/sensor-dev.c mode change 100755 => 100644 include/linux/sensor-dev.h diff --git a/drivers/input/sensors/lsensor/cm3217.c b/drivers/input/sensors/lsensor/cm3217.c old mode 100755 new mode 100644 index 31f09b02d0fc..b21d12609d0b --- a/drivers/input/sensors/lsensor/cm3217.c +++ b/drivers/input/sensors/lsensor/cm3217.c @@ -197,7 +197,8 @@ struct sensor_operate light_cm3217_ops = { .precision = 8, //8 bits .ctrl_reg = CM3217_ADDR_COM1, //enable or disable .int_status_reg = SENSOR_UNKNOW_DATA, //intterupt status register - .range = {0,10}, //range + .range = {100,65535}, //range + .brightness ={10,255}, // brightness .trig = SENSOR_UNKNOW_DATA, .active = sensor_active, .init = sensor_init, diff --git a/drivers/input/sensors/lsensor/ls_al3006.c b/drivers/input/sensors/lsensor/ls_al3006.c old mode 100755 new mode 100644 index e9a1f52852f8..416df23002b4 --- a/drivers/input/sensors/lsensor/ls_al3006.c +++ b/drivers/input/sensors/lsensor/ls_al3006.c @@ -262,7 +262,8 @@ struct sensor_operate light_al3006_ops = { .precision = 8, //8 bits .ctrl_reg = CONFIG_REG, //enable or disable .int_status_reg = INT_STATUS_REG, //intterupt status register - .range = {0,10}, //range + .range = {100,65535}, //range + .brightness ={10,255}, // brightness .trig = IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED, .active = sensor_active, .init = sensor_init, diff --git a/drivers/input/sensors/lsensor/ls_stk3171.c b/drivers/input/sensors/lsensor/ls_stk3171.c old mode 100755 new mode 100644 index 9edd1bff906b..7913b6fa0244 --- a/drivers/input/sensors/lsensor/ls_stk3171.c +++ b/drivers/input/sensors/lsensor/ls_stk3171.c @@ -281,7 +281,8 @@ struct sensor_operate light_stk3171_ops = { .precision = 16, //8 bits .ctrl_reg = ALS_CMD, //enable or disable .int_status_reg = STA_TUS, //intterupt status register - .range = {0,10}, //range + .range = {100,65535}, //range + .brightness ={10,255}, //brightness .trig = IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED, .active = sensor_active, .init = sensor_init, diff --git a/drivers/input/sensors/sensor-dev.c b/drivers/input/sensors/sensor-dev.c old mode 100755 new mode 100644 index 4e7d0683ec4b..e5ac3e97a3d1 --- a/drivers/input/sensors/sensor-dev.c +++ b/drivers/input/sensors/sensor-dev.c @@ -1192,6 +1192,7 @@ int sensor_probe(struct i2c_client *client, const struct i2c_device_id *devid) sensor->input_dev->name = "lightsensor-level"; set_bit(EV_ABS, sensor->input_dev->evbit); input_set_abs_params(sensor->input_dev, ABS_MISC, sensor->ops->range[0], sensor->ops->range[1], 0, 0); + input_set_abs_params(sensor->input_dev, ABS_TOOL_WIDTH , sensor->ops->brightness[0],sensor->ops->brightness[1], 0, 0); break; case SENSOR_TYPE_PROXIMITY: sensor->input_dev->name = "proximity"; diff --git a/include/linux/sensor-dev.h b/include/linux/sensor-dev.h old mode 100755 new mode 100644 index 710ce1e36614..60880b84495e --- a/include/linux/sensor-dev.h +++ b/include/linux/sensor-dev.h @@ -100,6 +100,7 @@ struct sensor_operate { int type; int id_i2c; int range[2]; + int brightness[2];//backlight min_brightness max_brightness int read_reg; int read_len; int id_reg; From a311ad50b3d1f17c077dcf3717272f35769203f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Fri, 10 Aug 2012 16:03:37 +0800 Subject: [PATCH 152/261] rk2928: sdk: add board-rk2928-sdk-camera.c --- .../arm/mach-rk2928/board-rk2928-sdk-camera.c | 448 ++++++++++++++++++ arch/arm/mach-rk2928/board-rk2928-sdk.c | 448 +----------------- 2 files changed, 449 insertions(+), 447 deletions(-) create mode 100644 arch/arm/mach-rk2928/board-rk2928-sdk-camera.c diff --git a/arch/arm/mach-rk2928/board-rk2928-sdk-camera.c b/arch/arm/mach-rk2928/board-rk2928-sdk-camera.c new file mode 100644 index 000000000000..02f98b8b3f47 --- /dev/null +++ b/arch/arm/mach-rk2928/board-rk2928-sdk-camera.c @@ -0,0 +1,448 @@ +#ifdef CONFIG_VIDEO_RK29 +/*---------------- Camera Sensor Macro Define Begin ------------------------*/ +/*---------------- Camera Sensor Configuration Macro Begin ------------------------*/ +#define CONFIG_SENSOR_0 RK29_CAM_SENSOR_OV5642 /* back camera sensor */ +#define CONFIG_SENSOR_IIC_ADDR_0 0 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_0 4 +#define CONFIG_SENSOR_CIF_INDEX_0 0 +#define CONFIG_SENSOR_ORIENTATION_0 90 +#define CONFIG_SENSOR_POWER_PIN_0 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_0 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_0 RK2928_PIN3_PB3 +#define CONFIG_SENSOR_FALSH_PIN_0 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_0 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_0 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_0 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_0 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_0 30000 + +#define CONFIG_SENSOR_01 RK29_CAM_SENSOR_OV5642 /* back camera sensor 1 */ +#define CONFIG_SENSOR_IIC_ADDR_01 0x00 +#define CONFIG_SENSOR_CIF_INDEX_01 0 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_01 4 +#define CONFIG_SENSOR_ORIENTATION_01 90 +#define CONFIG_SENSOR_POWER_PIN_01 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_01 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_01 RK2928_PIN3_PB3 +#define CONFIG_SENSOR_FALSH_PIN_01 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_01 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_01 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_01 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_01 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_01 30000 + +#define CONFIG_SENSOR_02 RK29_CAM_SENSOR_OV5640 /* back camera sensor 2 */ +#define CONFIG_SENSOR_IIC_ADDR_02 0x00 +#define CONFIG_SENSOR_CIF_INDEX_02 0 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_02 4 +#define CONFIG_SENSOR_ORIENTATION_02 90 +#define CONFIG_SENSOR_POWER_PIN_02 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_02 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_02 RK2928_PIN3_PB3 +#define CONFIG_SENSOR_FALSH_PIN_02 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_02 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_02 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_02 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_02 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_02 30000 + +#define CONFIG_SENSOR_1 RK29_CAM_SENSOR_OV2659 /* front camera sensor 0 */ +#define CONFIG_SENSOR_IIC_ADDR_1 0x60 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_1 3 +#define CONFIG_SENSOR_CIF_INDEX_1 0 +#define CONFIG_SENSOR_ORIENTATION_1 270 +#define CONFIG_SENSOR_POWER_PIN_1 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_1 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_1 RK2928_PIN3_PB3 +#define CONFIG_SENSOR_FALSH_PIN_1 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_1 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_1 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_1 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_1 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_1 30000 + +#define CONFIG_SENSOR_11 RK29_CAM_SENSOR_OV2659 /* front camera sensor 1 */ +#define CONFIG_SENSOR_IIC_ADDR_11 0x00 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_11 3 +#define CONFIG_SENSOR_CIF_INDEX_11 0 +#define CONFIG_SENSOR_ORIENTATION_11 270 +#define CONFIG_SENSOR_POWER_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_FALSH_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_11 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_11 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_11 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_11 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_11 30000 + +#define CONFIG_SENSOR_12 RK29_CAM_SENSOR_OV2659//RK29_CAM_SENSOR_OV2655 /* front camera sensor 2 */ +#define CONFIG_SENSOR_IIC_ADDR_12 0x00 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_12 3 +#define CONFIG_SENSOR_CIF_INDEX_12 0 +#define CONFIG_SENSOR_ORIENTATION_12 270 +#define CONFIG_SENSOR_POWER_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_FALSH_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_12 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_12 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_12 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_12 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_12 30000 + + +#endif //#ifdef CONFIG_VIDEO_RK29 +/*---------------- Camera Sensor Configuration Macro End------------------------*/ +#include "../../../drivers/media/video/rk2928_camera.c" +/*---------------- Camera Sensor Macro Define End ---------*/ + +#define PMEM_CAM_SIZE PMEM_CAM_NECESSARY +/***************************************************************************************** + * camera devices + * author: ddl@rock-chips.com + *****************************************************************************************/ +#ifdef CONFIG_VIDEO_RK29 +#define CONFIG_SENSOR_POWER_IOCTL_USR 0 //define this refer to your board layout +#define CONFIG_SENSOR_RESET_IOCTL_USR 0 +#define CONFIG_SENSOR_POWERDOWN_IOCTL_USR 0 +#define CONFIG_SENSOR_FLASH_IOCTL_USR 0 + +static void rk_cif_power(int on) +{ + struct regulator *ldo_18,*ldo_28; + ldo_28 = regulator_get(NULL, "ldo7"); // vcc28_cif + ldo_18 = regulator_get(NULL, "ldo1"); // vcc18_cif + if (ldo_28 == NULL || IS_ERR(ldo_28) || ldo_18 == NULL || IS_ERR(ldo_18)){ + printk("get cif ldo failed!\n"); + return; + } + if(on == 0){ + regulator_disable(ldo_28); + regulator_put(ldo_28); + regulator_disable(ldo_18); + regulator_put(ldo_18); + mdelay(500); + } + else{ + regulator_set_voltage(ldo_28, 2800000, 2800000); + regulator_enable(ldo_28); + // printk("%s set ldo7 vcc28_cif=%dmV end\n", __func__, regulator_get_voltage(ldo_28)); + regulator_put(ldo_28); + + regulator_set_voltage(ldo_18, 1800000, 1800000); + // regulator_set_suspend_voltage(ldo, 1800000); + regulator_enable(ldo_18); + // printk("%s set ldo1 vcc18_cif=%dmV end\n", __func__, regulator_get_voltage(ldo_18)); + regulator_put(ldo_18); + } +} + +#if CONFIG_SENSOR_POWER_IOCTL_USR +static int sensor_power_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + //#error "CONFIG_SENSOR_POWER_IOCTL_USR is 1, sensor_power_usr_cb function must be writed!!"; + rk_cif_power(on); +} +#endif + +#if CONFIG_SENSOR_RESET_IOCTL_USR +static int sensor_reset_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + #error "CONFIG_SENSOR_RESET_IOCTL_USR is 1, sensor_reset_usr_cb function must be writed!!"; +} +#endif + +#if CONFIG_SENSOR_POWERDOWN_IOCTL_USR +static int sensor_powerdown_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + #error "CONFIG_SENSOR_POWERDOWN_IOCTL_USR is 1, sensor_powerdown_usr_cb function must be writed!!"; +} +#endif + +#if CONFIG_SENSOR_FLASH_IOCTL_USR +static int sensor_flash_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + #error "CONFIG_SENSOR_FLASH_IOCTL_USR is 1, sensor_flash_usr_cb function must be writed!!"; +} +#endif + +static struct rk29camera_platform_ioctl_cb sensor_ioctl_cb = { + #if CONFIG_SENSOR_POWER_IOCTL_USR + .sensor_power_cb = sensor_power_usr_cb, + #else + .sensor_power_cb = NULL, + #endif + + #if CONFIG_SENSOR_RESET_IOCTL_USR + .sensor_reset_cb = sensor_reset_usr_cb, + #else + .sensor_reset_cb = NULL, + #endif + + #if CONFIG_SENSOR_POWERDOWN_IOCTL_USR + .sensor_powerdown_cb = sensor_powerdown_usr_cb, + #else + .sensor_powerdown_cb = NULL, + #endif + + #if CONFIG_SENSOR_FLASH_IOCTL_USR + .sensor_flash_cb = sensor_flash_usr_cb, + #else + .sensor_flash_cb = NULL, + #endif +}; + +#if CONFIG_SENSOR_IIC_ADDR_0 +static struct reginfo_t rk_init_data_sensor_reg_0[] = +{ + {0x0000, 0x00,0,0} + }; +static struct reginfo_t rk_init_data_sensor_winseqreg_0[] ={ + {0x0000, 0x00,0,0} + }; +#endif + +#if CONFIG_SENSOR_IIC_ADDR_1 +static struct reginfo_t rk_init_data_sensor_reg_1[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_1[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_01 +static struct reginfo_t rk_init_data_sensor_reg_01[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_01[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_02 +static struct reginfo_t rk_init_data_sensor_reg_02[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_02[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_11 +static struct reginfo_t rk_init_data_sensor_reg_11[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_11[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_12 +static struct reginfo_t rk_init_data_sensor_reg_12[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_12[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +static rk_sensor_user_init_data_s rk_init_data_sensor[RK_CAM_NUM] = +{ + #if CONFIG_SENSOR_IIC_ADDR_0 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_0, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_0, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_0) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_0) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_1 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_1, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_1, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_1) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_1) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_01 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_01, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_01, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_01) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_01) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_02 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_02, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_02, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_02) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_02) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_11 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_11, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_11, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_11) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_11) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_12 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_12, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_12, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_12) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_12) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + + }; +#include "../../../drivers/media/video/rk2928_camera.c" + +#endif /* CONFIG_VIDEO_RK29 */ diff --git a/arch/arm/mach-rk2928/board-rk2928-sdk.c b/arch/arm/mach-rk2928/board-rk2928-sdk.c index fbb0e781c277..e3ea7c7ded96 100755 --- a/arch/arm/mach-rk2928/board-rk2928-sdk.c +++ b/arch/arm/mach-rk2928/board-rk2928-sdk.c @@ -59,454 +59,8 @@ #else #define RK30_FB0_MEM_SIZE 8*SZ_1M #endif -#ifdef CONFIG_VIDEO_RK29 -/*---------------- Camera Sensor Macro Define Begin ------------------------*/ -/*---------------- Camera Sensor Configuration Macro Begin ------------------------*/ -#define CONFIG_SENSOR_0 RK29_CAM_SENSOR_OV5642 /* back camera sensor */ -#define CONFIG_SENSOR_IIC_ADDR_0 0 -#define CONFIG_SENSOR_IIC_ADAPTER_ID_0 4 -#define CONFIG_SENSOR_CIF_INDEX_0 0 -#define CONFIG_SENSOR_ORIENTATION_0 90 -#define CONFIG_SENSOR_POWER_PIN_0 INVALID_GPIO -#define CONFIG_SENSOR_RESET_PIN_0 INVALID_GPIO -#define CONFIG_SENSOR_POWERDN_PIN_0 RK2928_PIN3_PB3 -#define CONFIG_SENSOR_FALSH_PIN_0 INVALID_GPIO -#define CONFIG_SENSOR_POWERACTIVE_LEVEL_0 RK29_CAM_POWERACTIVE_L -#define CONFIG_SENSOR_RESETACTIVE_LEVEL_0 RK29_CAM_RESETACTIVE_L -#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_0 RK29_CAM_POWERDNACTIVE_H -#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_0 RK29_CAM_FLASHACTIVE_L -#define CONFIG_SENSOR_QCIF_FPS_FIXED_0 15000 -#define CONFIG_SENSOR_240X160_FPS_FIXED_0 15000 -#define CONFIG_SENSOR_QVGA_FPS_FIXED_0 15000 -#define CONFIG_SENSOR_CIF_FPS_FIXED_0 15000 -#define CONFIG_SENSOR_VGA_FPS_FIXED_0 15000 -#define CONFIG_SENSOR_480P_FPS_FIXED_0 15000 -#define CONFIG_SENSOR_SVGA_FPS_FIXED_0 15000 -#define CONFIG_SENSOR_720P_FPS_FIXED_0 30000 - -#define CONFIG_SENSOR_01 RK29_CAM_SENSOR_OV5642 /* back camera sensor 1 */ -#define CONFIG_SENSOR_IIC_ADDR_01 0x00 -#define CONFIG_SENSOR_CIF_INDEX_01 0 -#define CONFIG_SENSOR_IIC_ADAPTER_ID_01 4 -#define CONFIG_SENSOR_ORIENTATION_01 90 -#define CONFIG_SENSOR_POWER_PIN_01 INVALID_GPIO -#define CONFIG_SENSOR_RESET_PIN_01 INVALID_GPIO -#define CONFIG_SENSOR_POWERDN_PIN_01 RK2928_PIN3_PB3 -#define CONFIG_SENSOR_FALSH_PIN_01 INVALID_GPIO -#define CONFIG_SENSOR_POWERACTIVE_LEVEL_01 RK29_CAM_POWERACTIVE_L -#define CONFIG_SENSOR_RESETACTIVE_LEVEL_01 RK29_CAM_RESETACTIVE_L -#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_01 RK29_CAM_POWERDNACTIVE_H -#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_01 RK29_CAM_FLASHACTIVE_L - -#define CONFIG_SENSOR_QCIF_FPS_FIXED_01 15000 -#define CONFIG_SENSOR_240X160_FPS_FIXED_01 15000 -#define CONFIG_SENSOR_QVGA_FPS_FIXED_01 15000 -#define CONFIG_SENSOR_CIF_FPS_FIXED_01 15000 -#define CONFIG_SENSOR_VGA_FPS_FIXED_01 15000 -#define CONFIG_SENSOR_480P_FPS_FIXED_01 15000 -#define CONFIG_SENSOR_SVGA_FPS_FIXED_01 15000 -#define CONFIG_SENSOR_720P_FPS_FIXED_01 30000 - -#define CONFIG_SENSOR_02 RK29_CAM_SENSOR_OV5640 /* back camera sensor 2 */ -#define CONFIG_SENSOR_IIC_ADDR_02 0x00 -#define CONFIG_SENSOR_CIF_INDEX_02 0 -#define CONFIG_SENSOR_IIC_ADAPTER_ID_02 4 -#define CONFIG_SENSOR_ORIENTATION_02 90 -#define CONFIG_SENSOR_POWER_PIN_02 INVALID_GPIO -#define CONFIG_SENSOR_RESET_PIN_02 INVALID_GPIO -#define CONFIG_SENSOR_POWERDN_PIN_02 RK2928_PIN3_PB3 -#define CONFIG_SENSOR_FALSH_PIN_02 INVALID_GPIO -#define CONFIG_SENSOR_POWERACTIVE_LEVEL_02 RK29_CAM_POWERACTIVE_L -#define CONFIG_SENSOR_RESETACTIVE_LEVEL_02 RK29_CAM_RESETACTIVE_L -#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_02 RK29_CAM_POWERDNACTIVE_H -#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_02 RK29_CAM_FLASHACTIVE_L - -#define CONFIG_SENSOR_QCIF_FPS_FIXED_02 15000 -#define CONFIG_SENSOR_240X160_FPS_FIXED_02 15000 -#define CONFIG_SENSOR_QVGA_FPS_FIXED_02 15000 -#define CONFIG_SENSOR_CIF_FPS_FIXED_02 15000 -#define CONFIG_SENSOR_VGA_FPS_FIXED_02 15000 -#define CONFIG_SENSOR_480P_FPS_FIXED_02 15000 -#define CONFIG_SENSOR_SVGA_FPS_FIXED_02 15000 -#define CONFIG_SENSOR_720P_FPS_FIXED_02 30000 - -#define CONFIG_SENSOR_1 RK29_CAM_SENSOR_OV2659 /* front camera sensor 0 */ -#define CONFIG_SENSOR_IIC_ADDR_1 0x60 -#define CONFIG_SENSOR_IIC_ADAPTER_ID_1 3 -#define CONFIG_SENSOR_CIF_INDEX_1 0 -#define CONFIG_SENSOR_ORIENTATION_1 270 -#define CONFIG_SENSOR_POWER_PIN_1 INVALID_GPIO -#define CONFIG_SENSOR_RESET_PIN_1 INVALID_GPIO -#define CONFIG_SENSOR_POWERDN_PIN_1 RK2928_PIN3_PB3 -#define CONFIG_SENSOR_FALSH_PIN_1 INVALID_GPIO -#define CONFIG_SENSOR_POWERACTIVE_LEVEL_1 RK29_CAM_POWERACTIVE_L -#define CONFIG_SENSOR_RESETACTIVE_LEVEL_1 RK29_CAM_RESETACTIVE_L -#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_1 RK29_CAM_POWERDNACTIVE_H -#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_1 RK29_CAM_FLASHACTIVE_L - -#define CONFIG_SENSOR_QCIF_FPS_FIXED_1 15000 -#define CONFIG_SENSOR_240X160_FPS_FIXED_1 15000 -#define CONFIG_SENSOR_QVGA_FPS_FIXED_1 15000 -#define CONFIG_SENSOR_CIF_FPS_FIXED_1 15000 -#define CONFIG_SENSOR_VGA_FPS_FIXED_1 15000 -#define CONFIG_SENSOR_480P_FPS_FIXED_1 15000 -#define CONFIG_SENSOR_SVGA_FPS_FIXED_1 15000 -#define CONFIG_SENSOR_720P_FPS_FIXED_1 30000 - -#define CONFIG_SENSOR_11 RK29_CAM_SENSOR_OV2659 /* front camera sensor 1 */ -#define CONFIG_SENSOR_IIC_ADDR_11 0x00 -#define CONFIG_SENSOR_IIC_ADAPTER_ID_11 3 -#define CONFIG_SENSOR_CIF_INDEX_11 0 -#define CONFIG_SENSOR_ORIENTATION_11 270 -#define CONFIG_SENSOR_POWER_PIN_11 INVALID_GPIO -#define CONFIG_SENSOR_RESET_PIN_11 INVALID_GPIO -#define CONFIG_SENSOR_POWERDN_PIN_11 INVALID_GPIO -#define CONFIG_SENSOR_FALSH_PIN_11 INVALID_GPIO -#define CONFIG_SENSOR_POWERACTIVE_LEVEL_11 RK29_CAM_POWERACTIVE_L -#define CONFIG_SENSOR_RESETACTIVE_LEVEL_11 RK29_CAM_RESETACTIVE_L -#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_11 RK29_CAM_POWERDNACTIVE_H -#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_11 RK29_CAM_FLASHACTIVE_L - -#define CONFIG_SENSOR_QCIF_FPS_FIXED_11 15000 -#define CONFIG_SENSOR_240X160_FPS_FIXED_11 15000 -#define CONFIG_SENSOR_QVGA_FPS_FIXED_11 15000 -#define CONFIG_SENSOR_CIF_FPS_FIXED_11 15000 -#define CONFIG_SENSOR_VGA_FPS_FIXED_11 15000 -#define CONFIG_SENSOR_480P_FPS_FIXED_11 15000 -#define CONFIG_SENSOR_SVGA_FPS_FIXED_11 15000 -#define CONFIG_SENSOR_720P_FPS_FIXED_11 30000 - -#define CONFIG_SENSOR_12 RK29_CAM_SENSOR_OV2659//RK29_CAM_SENSOR_OV2655 /* front camera sensor 2 */ -#define CONFIG_SENSOR_IIC_ADDR_12 0x00 -#define CONFIG_SENSOR_IIC_ADAPTER_ID_12 3 -#define CONFIG_SENSOR_CIF_INDEX_12 0 -#define CONFIG_SENSOR_ORIENTATION_12 270 -#define CONFIG_SENSOR_POWER_PIN_12 INVALID_GPIO -#define CONFIG_SENSOR_RESET_PIN_12 INVALID_GPIO -#define CONFIG_SENSOR_POWERDN_PIN_12 INVALID_GPIO -#define CONFIG_SENSOR_FALSH_PIN_12 INVALID_GPIO -#define CONFIG_SENSOR_POWERACTIVE_LEVEL_12 RK29_CAM_POWERACTIVE_L -#define CONFIG_SENSOR_RESETACTIVE_LEVEL_12 RK29_CAM_RESETACTIVE_L -#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_12 RK29_CAM_POWERDNACTIVE_H -#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_12 RK29_CAM_FLASHACTIVE_L - -#define CONFIG_SENSOR_QCIF_FPS_FIXED_12 15000 -#define CONFIG_SENSOR_240X160_FPS_FIXED_12 15000 -#define CONFIG_SENSOR_QVGA_FPS_FIXED_12 15000 -#define CONFIG_SENSOR_CIF_FPS_FIXED_12 15000 -#define CONFIG_SENSOR_VGA_FPS_FIXED_12 15000 -#define CONFIG_SENSOR_480P_FPS_FIXED_12 15000 -#define CONFIG_SENSOR_SVGA_FPS_FIXED_12 15000 -#define CONFIG_SENSOR_720P_FPS_FIXED_12 30000 - - -#endif //#ifdef CONFIG_VIDEO_RK29 -/*---------------- Camera Sensor Configuration Macro End------------------------*/ -#include "../../../drivers/media/video/rk2928_camera.c" -/*---------------- Camera Sensor Macro Define End ---------*/ - -#define PMEM_CAM_SIZE PMEM_CAM_NECESSARY -/***************************************************************************************** - * camera devices - * author: ddl@rock-chips.com - *****************************************************************************************/ -#ifdef CONFIG_VIDEO_RK29 -#define CONFIG_SENSOR_POWER_IOCTL_USR 0 //define this refer to your board layout -#define CONFIG_SENSOR_RESET_IOCTL_USR 0 -#define CONFIG_SENSOR_POWERDOWN_IOCTL_USR 0 -#define CONFIG_SENSOR_FLASH_IOCTL_USR 0 - -static void rk_cif_power(int on) -{ - struct regulator *ldo_18,*ldo_28; - ldo_28 = regulator_get(NULL, "ldo7"); // vcc28_cif - ldo_18 = regulator_get(NULL, "ldo1"); // vcc18_cif - if (ldo_28 == NULL || IS_ERR(ldo_28) || ldo_18 == NULL || IS_ERR(ldo_18)){ - printk("get cif ldo failed!\n"); - return; - } - if(on == 0){ - regulator_disable(ldo_28); - regulator_put(ldo_28); - regulator_disable(ldo_18); - regulator_put(ldo_18); - mdelay(500); - } - else{ - regulator_set_voltage(ldo_28, 2800000, 2800000); - regulator_enable(ldo_28); - // printk("%s set ldo7 vcc28_cif=%dmV end\n", __func__, regulator_get_voltage(ldo_28)); - regulator_put(ldo_28); - - regulator_set_voltage(ldo_18, 1800000, 1800000); - // regulator_set_suspend_voltage(ldo, 1800000); - regulator_enable(ldo_18); - // printk("%s set ldo1 vcc18_cif=%dmV end\n", __func__, regulator_get_voltage(ldo_18)); - regulator_put(ldo_18); - } -} - -#if CONFIG_SENSOR_POWER_IOCTL_USR -static int sensor_power_usr_cb (struct rk29camera_gpio_res *res,int on) -{ - //#error "CONFIG_SENSOR_POWER_IOCTL_USR is 1, sensor_power_usr_cb function must be writed!!"; - rk_cif_power(on); -} -#endif - -#if CONFIG_SENSOR_RESET_IOCTL_USR -static int sensor_reset_usr_cb (struct rk29camera_gpio_res *res,int on) -{ - #error "CONFIG_SENSOR_RESET_IOCTL_USR is 1, sensor_reset_usr_cb function must be writed!!"; -} -#endif - -#if CONFIG_SENSOR_POWERDOWN_IOCTL_USR -static int sensor_powerdown_usr_cb (struct rk29camera_gpio_res *res,int on) -{ - #error "CONFIG_SENSOR_POWERDOWN_IOCTL_USR is 1, sensor_powerdown_usr_cb function must be writed!!"; -} -#endif - -#if CONFIG_SENSOR_FLASH_IOCTL_USR -static int sensor_flash_usr_cb (struct rk29camera_gpio_res *res,int on) -{ - #error "CONFIG_SENSOR_FLASH_IOCTL_USR is 1, sensor_flash_usr_cb function must be writed!!"; -} -#endif - -static struct rk29camera_platform_ioctl_cb sensor_ioctl_cb = { - #if CONFIG_SENSOR_POWER_IOCTL_USR - .sensor_power_cb = sensor_power_usr_cb, - #else - .sensor_power_cb = NULL, - #endif - - #if CONFIG_SENSOR_RESET_IOCTL_USR - .sensor_reset_cb = sensor_reset_usr_cb, - #else - .sensor_reset_cb = NULL, - #endif - - #if CONFIG_SENSOR_POWERDOWN_IOCTL_USR - .sensor_powerdown_cb = sensor_powerdown_usr_cb, - #else - .sensor_powerdown_cb = NULL, - #endif - - #if CONFIG_SENSOR_FLASH_IOCTL_USR - .sensor_flash_cb = sensor_flash_usr_cb, - #else - .sensor_flash_cb = NULL, - #endif -}; - -#if CONFIG_SENSOR_IIC_ADDR_0 -static struct reginfo_t rk_init_data_sensor_reg_0[] = -{ - {0x0000, 0x00,0,0} - }; -static struct reginfo_t rk_init_data_sensor_winseqreg_0[] ={ - {0x0000, 0x00,0,0} - }; -#endif - -#if CONFIG_SENSOR_IIC_ADDR_1 -static struct reginfo_t rk_init_data_sensor_reg_1[] = -{ - {0x0000, 0x00,0,0} -}; -static struct reginfo_t rk_init_data_sensor_winseqreg_1[] = -{ - {0x0000, 0x00,0,0} -}; -#endif -#if CONFIG_SENSOR_IIC_ADDR_01 -static struct reginfo_t rk_init_data_sensor_reg_01[] = -{ - {0x0000, 0x00,0,0} -}; -static struct reginfo_t rk_init_data_sensor_winseqreg_01[] = -{ - {0x0000, 0x00,0,0} -}; -#endif -#if CONFIG_SENSOR_IIC_ADDR_02 -static struct reginfo_t rk_init_data_sensor_reg_02[] = -{ - {0x0000, 0x00,0,0} -}; -static struct reginfo_t rk_init_data_sensor_winseqreg_02[] = -{ - {0x0000, 0x00,0,0} -}; -#endif -#if CONFIG_SENSOR_IIC_ADDR_11 -static struct reginfo_t rk_init_data_sensor_reg_11[] = -{ - {0x0000, 0x00,0,0} -}; -static struct reginfo_t rk_init_data_sensor_winseqreg_11[] = -{ - {0x0000, 0x00,0,0} -}; -#endif -#if CONFIG_SENSOR_IIC_ADDR_12 -static struct reginfo_t rk_init_data_sensor_reg_12[] = -{ - {0x0000, 0x00,0,0} -}; -static struct reginfo_t rk_init_data_sensor_winseqreg_12[] = -{ - {0x0000, 0x00,0,0} -}; -#endif -static rk_sensor_user_init_data_s rk_init_data_sensor[RK_CAM_NUM] = -{ - #if CONFIG_SENSOR_IIC_ADDR_0 - { - .rk_sensor_init_width = INVALID_VALUE, - .rk_sensor_init_height = INVALID_VALUE, - .rk_sensor_init_bus_param = INVALID_VALUE, - .rk_sensor_init_pixelcode = INVALID_VALUE, - .rk_sensor_init_data = rk_init_data_sensor_reg_0, - .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_0, - .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_0) / sizeof(struct reginfo_t), - .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_0) / sizeof(struct reginfo_t), - }, - #else - { - .rk_sensor_init_width = INVALID_VALUE, - .rk_sensor_init_height = INVALID_VALUE, - .rk_sensor_init_bus_param = INVALID_VALUE, - .rk_sensor_init_pixelcode = INVALID_VALUE, - .rk_sensor_init_data = NULL, - .rk_sensor_init_winseq = NULL, - .rk_sensor_winseq_size = 0, - .rk_sensor_init_data_size = 0, - }, - #endif - #if CONFIG_SENSOR_IIC_ADDR_1 - { - .rk_sensor_init_width = INVALID_VALUE, - .rk_sensor_init_height = INVALID_VALUE, - .rk_sensor_init_bus_param = INVALID_VALUE, - .rk_sensor_init_pixelcode = INVALID_VALUE, - .rk_sensor_init_data = rk_init_data_sensor_reg_1, - .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_1, - .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_1) / sizeof(struct reginfo_t), - .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_1) / sizeof(struct reginfo_t), - }, - #else - { - .rk_sensor_init_width = INVALID_VALUE, - .rk_sensor_init_height = INVALID_VALUE, - .rk_sensor_init_bus_param = INVALID_VALUE, - .rk_sensor_init_pixelcode = INVALID_VALUE, - .rk_sensor_init_data = NULL, - .rk_sensor_init_winseq = NULL, - .rk_sensor_winseq_size = 0, - .rk_sensor_init_data_size = 0, - }, - #endif - #if CONFIG_SENSOR_IIC_ADDR_01 - { - .rk_sensor_init_width = INVALID_VALUE, - .rk_sensor_init_height = INVALID_VALUE, - .rk_sensor_init_bus_param = INVALID_VALUE, - .rk_sensor_init_pixelcode = INVALID_VALUE, - .rk_sensor_init_data = rk_init_data_sensor_reg_01, - .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_01, - .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_01) / sizeof(struct reginfo_t), - .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_01) / sizeof(struct reginfo_t), - }, - #else - { - .rk_sensor_init_width = INVALID_VALUE, - .rk_sensor_init_height = INVALID_VALUE, - .rk_sensor_init_bus_param = INVALID_VALUE, - .rk_sensor_init_pixelcode = INVALID_VALUE, - .rk_sensor_init_data = NULL, - .rk_sensor_init_winseq = NULL, - .rk_sensor_winseq_size = 0, - .rk_sensor_init_data_size = 0, - }, - #endif - #if CONFIG_SENSOR_IIC_ADDR_02 - { - .rk_sensor_init_width = INVALID_VALUE, - .rk_sensor_init_height = INVALID_VALUE, - .rk_sensor_init_bus_param = INVALID_VALUE, - .rk_sensor_init_pixelcode = INVALID_VALUE, - .rk_sensor_init_data = rk_init_data_sensor_reg_02, - .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_02, - .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_02) / sizeof(struct reginfo_t), - .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_02) / sizeof(struct reginfo_t), - }, - #else - { - .rk_sensor_init_width = INVALID_VALUE, - .rk_sensor_init_height = INVALID_VALUE, - .rk_sensor_init_bus_param = INVALID_VALUE, - .rk_sensor_init_pixelcode = INVALID_VALUE, - .rk_sensor_init_data = NULL, - .rk_sensor_init_winseq = NULL, - .rk_sensor_winseq_size = 0, - .rk_sensor_init_data_size = 0, - }, - #endif - #if CONFIG_SENSOR_IIC_ADDR_11 - { - .rk_sensor_init_width = INVALID_VALUE, - .rk_sensor_init_height = INVALID_VALUE, - .rk_sensor_init_bus_param = INVALID_VALUE, - .rk_sensor_init_pixelcode = INVALID_VALUE, - .rk_sensor_init_data = rk_init_data_sensor_reg_11, - .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_11, - .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_11) / sizeof(struct reginfo_t), - .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_11) / sizeof(struct reginfo_t), - }, - #else - { - .rk_sensor_init_width = INVALID_VALUE, - .rk_sensor_init_height = INVALID_VALUE, - .rk_sensor_init_bus_param = INVALID_VALUE, - .rk_sensor_init_pixelcode = INVALID_VALUE, - .rk_sensor_init_data = NULL, - .rk_sensor_init_winseq = NULL, - .rk_sensor_winseq_size = 0, - .rk_sensor_init_data_size = 0, - }, - #endif - #if CONFIG_SENSOR_IIC_ADDR_12 - { - .rk_sensor_init_width = INVALID_VALUE, - .rk_sensor_init_height = INVALID_VALUE, - .rk_sensor_init_bus_param = INVALID_VALUE, - .rk_sensor_init_pixelcode = INVALID_VALUE, - .rk_sensor_init_data = rk_init_data_sensor_reg_12, - .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_12, - .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_12) / sizeof(struct reginfo_t), - .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_12) / sizeof(struct reginfo_t), - }, - #else - { - .rk_sensor_init_width = INVALID_VALUE, - .rk_sensor_init_height = INVALID_VALUE, - .rk_sensor_init_bus_param = INVALID_VALUE, - .rk_sensor_init_pixelcode = INVALID_VALUE, - .rk_sensor_init_data = NULL, - .rk_sensor_init_winseq = NULL, - .rk_sensor_winseq_size = 0, - .rk_sensor_init_data_size = 0, - }, - #endif - - }; -#include "../../../drivers/media/video/rk2928_camera.c" - -#endif /* CONFIG_VIDEO_RK29 */ +#include "board-rk2928-sdk-camera.c" #if defined (CONFIG_EETI_EGALAX) #define TOUCH_RESET_PIN RK2928_PIN3_PC3 From 0bafc5d58369bcd88ba0cefd4282ab041076ad3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Fri, 10 Aug 2012 16:05:08 +0800 Subject: [PATCH 153/261] rk2928: sdk: board-rk2928-sdk.c include board-rk2928-sdk-key.c --- arch/arm/mach-rk2928/Makefile | 2 +- arch/arm/mach-rk2928/board-rk2928-sdk.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-rk2928/Makefile b/arch/arm/mach-rk2928/Makefile index a2169a7bc77c..6e92cad4f2bf 100644 --- a/arch/arm/mach-rk2928/Makefile +++ b/arch/arm/mach-rk2928/Makefile @@ -10,4 +10,4 @@ obj-$(CONFIG_PM) += pm.o CFLAGS_pm.o += -Os -mthumb obj-$(CONFIG_MACH_RK2928_FPGA) += board-rk2928-fpga.o board-rk2928-fpga-key.o -obj-$(CONFIG_MACH_RK2928_SDK) += board-rk2928-sdk.o board-rk2928-sdk-key.o +obj-$(CONFIG_MACH_RK2928_SDK) += board-rk2928-sdk.o diff --git a/arch/arm/mach-rk2928/board-rk2928-sdk.c b/arch/arm/mach-rk2928/board-rk2928-sdk.c index e3ea7c7ded96..b44fdc5b5038 100755 --- a/arch/arm/mach-rk2928/board-rk2928-sdk.c +++ b/arch/arm/mach-rk2928/board-rk2928-sdk.c @@ -61,6 +61,7 @@ #endif #include "board-rk2928-sdk-camera.c" +#include "board-rk2928-sdk-key.c" #if defined (CONFIG_EETI_EGALAX) #define TOUCH_RESET_PIN RK2928_PIN3_PC3 From a1f50a13670cc05ec88e2fcd203027eabe5e687d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Fri, 10 Aug 2012 16:08:29 +0800 Subject: [PATCH 154/261] rk2928: fpga: board-rk2928-fpga.c include board-rk2928-fpga-key.c --- arch/arm/mach-rk2928/Makefile | 2 +- arch/arm/mach-rk2928/board-rk2928-fpga.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-rk2928/Makefile b/arch/arm/mach-rk2928/Makefile index 6e92cad4f2bf..13a891691d1d 100644 --- a/arch/arm/mach-rk2928/Makefile +++ b/arch/arm/mach-rk2928/Makefile @@ -9,5 +9,5 @@ obj-y += clock_data.o obj-$(CONFIG_PM) += pm.o CFLAGS_pm.o += -Os -mthumb -obj-$(CONFIG_MACH_RK2928_FPGA) += board-rk2928-fpga.o board-rk2928-fpga-key.o +obj-$(CONFIG_MACH_RK2928_FPGA) += board-rk2928-fpga.o obj-$(CONFIG_MACH_RK2928_SDK) += board-rk2928-sdk.o diff --git a/arch/arm/mach-rk2928/board-rk2928-fpga.c b/arch/arm/mach-rk2928/board-rk2928-fpga.c index 7fd99583b24c..51411cbd4783 100755 --- a/arch/arm/mach-rk2928/board-rk2928-fpga.c +++ b/arch/arm/mach-rk2928/board-rk2928-fpga.c @@ -492,6 +492,8 @@ static rk_sensor_user_init_data_s rk_init_data_sensor[RK_CAM_NUM] = #endif /* CONFIG_VIDEO_RK29 */ +#include "board-rk2928-fpga-key.c" + /************************************************************************************************** * SDMMC devices, include the module of SD,MMC,and sdio.noted by xbw at 2012-03-05 **************************************************************************************************/ From 1995af3657df9093c08298961e83015bfe508a7f Mon Sep 17 00:00:00 2001 From: Zheng Yang Date: Fri, 10 Aug 2012 20:22:23 +0800 Subject: [PATCH 155/261] rk2928 acodec: audio record ok. --- sound/soc/codecs/rk2928_codec.c | 61 +++++++++++++++++++++++++-------- sound/soc/codecs/rk2928_codec.h | 2 ++ 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/rk2928_codec.c b/sound/soc/codecs/rk2928_codec.c index e877ae2e6e73..5a2fe5dc4d33 100755 --- a/sound/soc/codecs/rk2928_codec.c +++ b/sound/soc/codecs/rk2928_codec.c @@ -37,15 +37,17 @@ #include #include +#include + #include "rk2928_codec.h" static struct rk2928_codec_data { struct device *dev; - struct clk *hclk; int regbase; int regbase_phy; int regsize_phy; - int mute; + int mute; + int hdmi_enable; } rk2928_data; static const struct snd_soc_dapm_widget rk2928_dapm_widgets[] = { @@ -64,18 +66,14 @@ static const struct snd_soc_dapm_widget rk2928_dapm_widgets[] = { }; static const struct snd_soc_dapm_route rk2928_audio_map[] = { - {"DACL Drv", "DACL Amp", "DACL"}, - {"DACR Drv", "DACR Amp", "DACR"}, - {"SPKL", NULL, "DACL Drv"}, - {"SPKR", NULL, "DACR Drv"}, + {"SPKL", "DACL Amp", "DACL"}, + {"SPKR", "DACR Amp", "DACR"}, +// {"SPKL", NULL, "DACL Drv"}, +// {"SPKR", NULL, "DACR Drv"}, {"ADCL", NULL, "MICL"}, {"ADCR", NULL, "MICR"}, }; -void codec_set_spk(bool on) -{ - -} static unsigned int rk2928_read(struct snd_soc_codec *codec, unsigned int reg) { @@ -101,6 +99,22 @@ static int rk2928_write_mask(struct snd_soc_codec *codec, unsigned int reg, return rk2928_write(codec, reg, regvalue); } +void codec_set_spk(bool on) +{ + if(on == 0) { + DBG("%s speaker is disabled\n", __FUNCTION__); + rk2928_data.hdmi_enable = 1; + if(rk2928_data.mute = 0) + rk2928_write(NULL, CODEC_REG_DAC_MUTE, v_MUTE_DAC(1)); + } + else { + DBG("%s speaker is enabled\n", __FUNCTION__); + rk2928_data.hdmi_enable = 0; + if(rk2928_data.mute = 0) + rk2928_write(NULL, CODEC_REG_DAC_MUTE, v_MUTE_DAC(0)); + } +} + static int rk2928_audio_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -117,9 +131,9 @@ static int rk2928_audio_hw_params(struct snd_pcm_substream *substream, static int rk2928_audio_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { -// struct snd_soc_pcm_runtime *rtd = substream->private_data; -// struct snd_soc_codec *codec = rtd->codec; -// struct rk2928_codec_data *priv = snd_soc_codec_get_drvdata(codec); + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct rk2928_codec_data *priv = snd_soc_codec_get_drvdata(codec); int err = 0; DBG("%s cmd 0x%x", __FUNCTION__, cmd); @@ -128,10 +142,25 @@ static int rk2928_audio_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { +// rk2928_write(codec, CODEC_REG_DAC_GAIN, v_GAIN_DAC(DAC_GAIN_3DB_P)); + if(!rk2928_data.hdmi_enable) + rk2928_write(codec, CODEC_REG_DAC_MUTE, v_MUTE_DAC(0)); + rk2928_data.mute = 0; + } + else { + rk2928_write(codec, CODEC_REG_ADC_PGA_GAIN, 0xFF); +// rk2928_write(codec, 0x08, 0xff); +// rk2928_write(codec, 0x09, 0x07); + } break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + rk2928_write(codec, CODEC_REG_DAC_MUTE, v_MUTE_DAC(1)); + rk2928_data.mute = 1; + } break; default: err = -EINVAL; @@ -209,15 +238,17 @@ static int rk2928_probe(struct snd_soc_codec *codec) ret = -ENXIO; goto err1; } + // Select SDI input from internal audio codec + writel(0x04000400, RK2928_GRF_BASE + GRF_SOC_CON0); + // Mute and Power off codec rk2928_write(codec, CODEC_REG_DAC_MUTE, v_MUTE_DAC(1)); - rk2928_write(codec, CODEC_REG_DAC_GAIN, v_GAIN_DAC(DAC_GAIN_3DB_P)); rk2928_set_bias_level(codec, SND_SOC_BIAS_OFF); snd_soc_dapm_new_controls(dapm, rk2928_dapm_widgets, ARRAY_SIZE(rk2928_dapm_widgets)); snd_soc_dapm_add_routes(dapm, rk2928_audio_map, ARRAY_SIZE(rk2928_audio_map)); - + return 0; err1: diff --git a/sound/soc/codecs/rk2928_codec.h b/sound/soc/codecs/rk2928_codec.h index 42401a94afde..a2ca8ff14352 100755 --- a/sound/soc/codecs/rk2928_codec.h +++ b/sound/soc/codecs/rk2928_codec.h @@ -11,6 +11,8 @@ #ifndef __RK2928_CODEC_H__ #define __RK2928_CODEC_H__ +#define CODEC_REG_ADC_DIGITAL_GIAN_L 0x08 +#define CODEC_REG_ADC_DIGITAL_GIAN_H 0x09 #define CODEC_REG_ADC_PGA_GAIN 0x0b #define m_MIC_GAIN_CHANNEL_L (0x0F << 4) From 6eb300d28fd2622e8135d3b3af9dd3b6c2a772a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=99=B4?= Date: Sat, 11 Aug 2012 10:05:07 +0800 Subject: [PATCH 156/261] rk30:phone:Solve the power button interrupt failure --- arch/arm/mach-rk30/board-rk30-phone-twl60xx.c | 10 ++++++---- drivers/mfd/twl6030-irq.c | 6 ++++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-rk30/board-rk30-phone-twl60xx.c b/arch/arm/mach-rk30/board-rk30-phone-twl60xx.c index aa12cf7d7015..e4b54ef1577a 100755 --- a/arch/arm/mach-rk30/board-rk30-phone-twl60xx.c +++ b/arch/arm/mach-rk30/board-rk30-phone-twl60xx.c @@ -743,14 +743,16 @@ static struct twl4030_power_data tps80032_scripts_data __initdata = { void twl60xx_pmu_early_suspend(struct regulator_dev *rdev) { printk("%s\n", __func__); - - twl_reg_write(REG_INT_MSK_STS_A,TWL_MODULE_PIH, 0x00); //open vlow interrupt + int ret; + ret = twl_reg_read(REG_INT_MSK_STS_A,TWL_MODULE_PIH); + twl_reg_write(REG_INT_MSK_STS_A,TWL_MODULE_PIH, ret & (~(1 << 2))); //open vlow interrupt } void twl60xx_pmu_early_resume(struct regulator_dev *rdev) { printk("%s\n", __func__); - - twl_reg_write(REG_INT_MSK_STS_A,TWL_MODULE_PIH, 0x04); //close vlow interrupt + int ret; + ret = twl_reg_read(REG_INT_MSK_STS_A,TWL_MODULE_PIH); + twl_reg_write(REG_INT_MSK_STS_A,TWL_MODULE_PIH, ret |(1 << 2)); //close vlow interrupt } #else void twl60xx_pmu_early_suspend(struct regulator_dev *rdev) diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index 4d306b6273d0..36688ed208b1 100755 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -496,6 +496,7 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end, int i; int ret; u8 mask[4]; + u8 reg; static struct irq_chip twl6030_irq_chip; @@ -556,8 +557,9 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end, status = twl6030_vlow_init(twl6030_irq_base + TWL_VLOW_INTR_OFFSET); if (status < 0) goto fail_vlow; - - twl_i2c_write_u8(TWL_MODULE_PIH, 0x04,REG_INT_MSK_STS_A); //close vlow interrupt + + twl_i2c_write_u8(TWL_MODULE_PIH, ®,REG_INT_MSK_STS_A); + twl_i2c_write_u8(TWL_MODULE_PIH, reg | (1 << 2),REG_INT_MSK_STS_A); //close vlow interrupt return status; From 3e432635004a5d966e8ba00adfbe182f3e542d4a Mon Sep 17 00:00:00 2001 From: "lw@rock-chips.com" Date: Sat, 11 Aug 2012 11:37:28 +0800 Subject: [PATCH 157/261] phonepad:fix alarm lose intterupt problem --- drivers/mfd/tps65910-irq.c | 15 +++++-- drivers/rtc/rtc-tps65910.c | 87 ++++++++++++++++++++++++++++++++++-- include/linux/mfd/tps65910.h | 2 + 3 files changed, 97 insertions(+), 7 deletions(-) diff --git a/drivers/mfd/tps65910-irq.c b/drivers/mfd/tps65910-irq.c index bcec38371c94..1b781bfc93e5 100755 --- a/drivers/mfd/tps65910-irq.c +++ b/drivers/mfd/tps65910-irq.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include static inline int irq_to_tps65910_irq(struct tps65910 *tps65910, int irq) @@ -46,6 +48,7 @@ static irqreturn_t tps65910_irq(int irq, void *irq_data) u8 reg; int i; + wake_lock(&tps65910->irq_wake); tps65910->read(tps65910, TPS65910_INT_STS, 1, ®); irq_sts = reg; tps65910->read(tps65910, TPS65910_INT_STS2, 1, ®); @@ -69,7 +72,10 @@ static irqreturn_t tps65910_irq(int irq, void *irq_data) irq_sts &= ~irq_mask; if (!irq_sts) + { + wake_unlock(&tps65910->irq_wake); return IRQ_NONE; + } for (i = 0; i < tps65910->irq_num; i++) { @@ -90,7 +96,7 @@ static irqreturn_t tps65910_irq(int irq, void *irq_data) reg = irq_sts >> 8; tps65910->write(tps65910, TPS65910_INT_STS3, 1, ®); } - + wake_unlock(&tps65910->irq_wake); return IRQ_HANDLED; } @@ -188,14 +194,17 @@ int tps65910_irq_init(struct tps65910 *tps65910, int irq, tps65910->write(tps65910, TPS65910_INT_STS2, 1, ®); tps65910->read(tps65910, TPS65910_INT_STS3, 1, ®); tps65910->write(tps65910, TPS65910_INT_STS3, 1, ®); + tps65910->read(tps65910, TPS65910_RTC_STATUS, 1, ®); + tps65910->write(tps65910, TPS65910_RTC_STATUS, 1, ®);//clear alarm and timer interrupt /* Mask top level interrupts */ tps65910->irq_mask = 0xFFFFFF; - mutex_init(&tps65910->irq_lock); + mutex_init(&tps65910->irq_lock); + wake_lock_init(&tps65910->irq_wake, WAKE_LOCK_SUSPEND, "tps65910_irq_wake"); tps65910->chip_irq = irq; tps65910->irq_base = pdata->irq_base; - + switch (tps65910_chip_id(tps65910)) { case TPS65910: tps65910->irq_num = TPS65910_NUM_IRQ; diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index f6a8693cabcf..50eba3a7db48 100755 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -350,21 +350,43 @@ static int tps65910_rtc_irq_set_freq(struct device *dev, int freq) return ret; } - - static irqreturn_t tps65910_alm_irq(int irq, void *data) { struct tps65910_rtc *tps65910_rtc = data; + int ret; + u8 rtc_ctl; + /*Dummy read -- mandatory for status register*/ + ret = tps65910_reg_read(tps65910_rtc->tps65910, TPS65910_RTC_STATUS); + if (ret < 0) { + printk("%s:Failed to read RTC status: %d\n", __func__, ret); + return ret; + } + + ret = tps65910_reg_read(tps65910_rtc->tps65910, TPS65910_RTC_STATUS); + if (ret < 0) { + printk("%s:Failed to read RTC status: %d\n", __func__, ret); + return ret; + } + rtc_ctl = ret&0xff; + + //The alarm interrupt keeps its low level, until the micro-controller write 1 in the ALARM bit of the RTC_STATUS_REG register. + ret = tps65910_reg_write(tps65910_rtc->tps65910, TPS65910_RTC_STATUS,rtc_ctl); + if (ret < 0) { + printk("%s:Failed to read RTC status: %d\n", __func__, ret); + return ret; + } + rtc_update_irq(tps65910_rtc->rtc, 1, RTC_IRQF | RTC_AF); + printk("%s:irq=%d,rtc_ctl=0x%x\n",__func__,irq,rtc_ctl); return IRQ_HANDLED; } static irqreturn_t tps65910_per_irq(int irq, void *data) { struct tps65910_rtc *tps65910_rtc = data; - + rtc_update_irq(tps65910_rtc->rtc, 1, RTC_IRQF | RTC_UF); //printk("%s:irq=%d\n",__func__,irq); @@ -558,6 +580,7 @@ static int tps65910_rtc_probe(struct platform_device *pdev) //tps65910_set_bits(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS, // BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); + enable_irq_wake(alm_irq); // so tps65910 alarm irq can wake up system g_pdev = pdev; printk("%s:ok\n",__func__); @@ -610,6 +633,8 @@ static ssize_t rtc_tps65910_test_write(struct file *file, int nr = 0, ret; struct platform_device *pdev; struct rtc_time tm; + struct rtc_wkalrm alrm; + struct tps65910_rtc *tps65910_rtc; if(count > 3) return -EFAULT; @@ -618,7 +643,7 @@ static ssize_t rtc_tps65910_test_write(struct file *file, return -EFAULT; sscanf(nr_buf, "%d", &nr); - if(nr >= 2 || nr < 0) + if(nr > 5 || nr < 0) { printk("%s:data is error\n",__func__); return -EFAULT; @@ -629,6 +654,10 @@ static ssize_t rtc_tps65910_test_write(struct file *file, else pdev = g_pdev; + + tps65910_rtc = dev_get_drvdata(&pdev->dev); + + //test rtc time if(nr == 0) { tm.tm_wday = 6; @@ -662,6 +691,56 @@ static ssize_t rtc_tps65910_test_write(struct file *file, else printk("%s:error\n",__func__); + + //test rtc alarm + if(nr == 2) + { + //2000-01-01 00:00:30 + if(tm.tm_sec < 30) + { + alrm.time.tm_sec = tm.tm_sec+30; + alrm.time.tm_min = tm.tm_min; + } + else + { + alrm.time.tm_sec = tm.tm_sec-30; + alrm.time.tm_min = tm.tm_min+1; + } + alrm.time.tm_hour = tm.tm_hour; + alrm.time.tm_mday = tm.tm_mday; + alrm.time.tm_mon = tm.tm_mon; + alrm.time.tm_year = tm.tm_year; + tps65910_rtc_alarm_irq_enable(&pdev->dev, 1); + tps65910_rtc_setalarm(&pdev->dev, &alrm); + + dev_info(&pdev->dev, "Set alarm %4d-%02d-%02d(%d) %02d:%02d:%02d\n", + 1900 + alrm.time.tm_year, alrm.time.tm_mon + 1, alrm.time.tm_mday, alrm.time.tm_wday, + alrm.time.tm_hour, alrm.time.tm_min, alrm.time.tm_sec); + } + + + if(nr == 3) + { + ret = tps65910_reg_read(tps65910_rtc->tps65910, TPS65910_RTC_STATUS); + if (ret < 0) { + printk("%s:Failed to read RTC status: %d\n", __func__, ret); + return ret; + } + printk("%s:ret=0x%x\n",__func__,ret&0xff); + + ret = tps65910_reg_write(tps65910_rtc->tps65910, TPS65910_RTC_STATUS, ret&0xff); + if (ret < 0) { + printk("%s:Failed to read RTC status: %d\n", __func__, ret); + return ret; + } + } + + if(nr == 4) + tps65910_rtc_update_irq_enable(&pdev->dev, 1); + + if(nr == 5) + tps65910_rtc_update_irq_enable(&pdev->dev, 0); + return count; } diff --git a/include/linux/mfd/tps65910.h b/include/linux/mfd/tps65910.h index c093c477477b..c098040c7256 100755 --- a/include/linux/mfd/tps65910.h +++ b/include/linux/mfd/tps65910.h @@ -18,6 +18,7 @@ #define __LINUX_MFD_TPS65910_H #include +#include /* TPS chip id list */ #define TPS65910 0 @@ -802,6 +803,7 @@ struct tps65910 { struct i2c_client *i2c_client; struct regmap *regmap; struct mutex io_mutex; + struct wake_lock irq_wake; unsigned int id; int (*read)(struct tps65910 *tps65910, u8 reg, int size, void *dest); int (*write)(struct tps65910 *tps65910, u8 reg, int size, void *src); From 4ee78b7e3de96c1a4066d486ec4ecd054d77eec2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=99=B4?= Date: Sat, 11 Aug 2012 12:13:15 +0800 Subject: [PATCH 158/261] rk30:phonepad:clear rtc status when enter sleep --- arch/arm/mach-rk30/i2c_sram.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-rk30/i2c_sram.c b/arch/arm/mach-rk30/i2c_sram.c index e871a5b0218c..21537c85d301 100755 --- a/arch/arm/mach-rk30/i2c_sram.c +++ b/arch/arm/mach-rk30/i2c_sram.c @@ -303,12 +303,15 @@ void __sramfunc rk30_suspend_voltage_set(unsigned int vol) { uint8 slaveaddr; uint16 slavereg; - uint8 data,ret; + uint8 data,ret = 0; + uint8 rtc_status_reg = 0x11; slaveaddr = I2C_SADDR; //slave device addr slavereg = 0x22; // reg addr data = 0x23; //set arm 1.0v sram_i2c_init(); //init i2c device + ret = sram_i2c_read(slaveaddr, rtc_status_reg); + sram_i2c_write(slaveaddr, rtc_status_reg, ret); arm_voltage = sram_i2c_read(slaveaddr, slavereg); // sram_printhex(ret); sram_i2c_write(slaveaddr, slavereg, data);// @@ -320,7 +323,7 @@ void __sramfunc rk30_suspend_voltage_resume(unsigned int vol) { uint8 slaveaddr; uint16 slavereg; - uint8 data,ret; + uint8 data,ret = 0; slaveaddr = I2C_SADDR; //slave device addr slavereg = 0x22; // reg addr From 0e6ec11f61e1788159fb59d941aeb4c6438e46ff Mon Sep 17 00:00:00 2001 From: xbw Date: Sat, 11 Aug 2012 12:51:47 +0800 Subject: [PATCH 159/261] sdmmc: mask the SD Ver3.0 supported --- drivers/mmc/core/sd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index dd1bfdd97782..dcbd5b0e6dea 100755 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -306,7 +306,9 @@ static int mmc_read_switch(struct mmc_card *card) goto out; } - if (card->scr.sda_spec3) { + //mask the the SD Ver3.0 support,modifyed by xbw at 2012-8-09 + //if (card->scr.sda_spec3) { + if(0) { card->sw_caps.sd3_bus_mode = status[13]; /* Find out Driver Strengths supported by the card */ From 68f440aa8b94b3ad58f53ac8969e777ab8c2ea2c Mon Sep 17 00:00:00 2001 From: ddl Date: Sat, 11 Aug 2012 16:15:34 +0800 Subject: [PATCH 160/261] camera rk30: fix calculate ipp memory size is enough or not in try_fmt function, version update to v0.2.f --- drivers/media/video/rk30_camera_oneframe.c | 45 +++++++++------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/drivers/media/video/rk30_camera_oneframe.c b/drivers/media/video/rk30_camera_oneframe.c index 7bdcfb27b93b..bb58c49aa3ec 100755 --- a/drivers/media/video/rk30_camera_oneframe.c +++ b/drivers/media/video/rk30_camera_oneframe.c @@ -209,9 +209,10 @@ module_param(debug, int, S_IRUGO|S_IWUSR); *v0.x.b: specify the version is NOT sure stable. *v0.x.c: 1. add cif reset when resolution changed to avoid of collecting data erro 2. irq process is splitted to two step. -*v0.x.e: fix bugs of early suspend when display_pd is closed. +*v0.x.e: fix bugs of early suspend when display_pd is closed. +*v0.x.f: fix calculate ipp memory size is enough or not in try_fmt function; */ -#define RK_CAM_VERSION_CODE KERNEL_VERSION(0, 2, 0xe) +#define RK_CAM_VERSION_CODE KERNEL_VERSION(0, 2, 0xf) /* limit to rk29 hardware capabilities */ #define RK_CAM_BUS_PARAM (SOCAM_MASTER |\ @@ -1616,7 +1617,8 @@ static int rk_camera_try_fmt(struct soc_camera_device *icd, bool is_capture = rk_camera_fmt_capturechk(f); bool vipmem_is_overflow = false; struct v4l2_mbus_framefmt mf; - + int bytes_per_line_host; + usr_w = pix->width; usr_h = pix->height; RKCAMERA_DG("%s enter width:%d height:%d\n",__FUNCTION__,usr_w,usr_h); @@ -1657,13 +1659,14 @@ static int rk_camera_try_fmt(struct soc_camera_device *icd, goto RK_CAMERA_TRY_FMT_END; RKCAMERA_DG("%s mf.width:%d mf.height:%d\n",__FUNCTION__,mf.width,mf.height); #ifdef CONFIG_VIDEO_RK29_WORK_IPP - if ((mf.width > usr_w) && (mf.height > usr_h)) { + if ((mf.width != usr_w) || (mf.height != usr_h)) { + bytes_per_line_host = soc_mbus_bytes_per_line(mf.width,icd->current_fmt->host_fmt); if (is_capture) { - vipmem_is_overflow = (PAGE_ALIGN(pix->bytesperline*pix->height) > pcdev->vipmem_size); + vipmem_is_overflow = (PAGE_ALIGN(bytes_per_line_host*mf.height) > pcdev->vipmem_size); } else { /* Assume preview buffer minimum is 4 */ - vipmem_is_overflow = (PAGE_ALIGN(pix->bytesperline*pix->height)*4 > pcdev->vipmem_size); - } + vipmem_is_overflow = (PAGE_ALIGN(bytes_per_line_host*mf.height)*4 > pcdev->vipmem_size); + } if (vipmem_is_overflow == false) { pix->width = usr_w; pix->height = usr_h; @@ -1672,26 +1675,14 @@ static int rk_camera_try_fmt(struct soc_camera_device *icd, pix->width = mf.width; pix->height = mf.height; } - } else if ((mf.width < usr_w) && (mf.height < usr_h)) { - if (((usr_w>>1) < mf.width) && ((usr_h>>1) < mf.height)) { - if (is_capture) { - vipmem_is_overflow = (PAGE_ALIGN(pix->bytesperline*pix->height) > pcdev->vipmem_size); - } else { - vipmem_is_overflow = (PAGE_ALIGN(pix->bytesperline*pix->height)*4 > pcdev->vipmem_size); - } - if (vipmem_is_overflow == false) { - pix->width = usr_w; - pix->height = usr_h; - } else { - RKCAMERA_TR("vipmem for IPP is overflow, This resolution(%dx%d -> %dx%d) is invalidate!\n",mf.width,mf.height,usr_w,usr_h); - pix->width = mf.width; - pix->height = mf.height; - } - } else { - RKCAMERA_TR("The aspect ratio(%dx%d/%dx%d) is bigger than 2 !\n",mf.width,mf.height,usr_w,usr_h); - pix->width = mf.width; - pix->height = mf.height; - } + + if ((mf.width < usr_w) || (mf.height < usr_h)) { + if (((usr_w>>1) > mf.width) || ((usr_h>>1) > mf.height)) { + RKCAMERA_TR("The aspect ratio(%dx%d/%dx%d) is bigger than 2 !\n",mf.width,mf.height,usr_w,usr_h); + pix->width = mf.width; + pix->height = mf.height; + } + } } #else //need to change according to crop and scale capablicity From 13da9d54f5617551e07e5d25d225d7edec673995 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=99=B4?= Date: Sat, 11 Aug 2012 16:40:07 +0800 Subject: [PATCH 161/261] rk2928:fix alarm lose intterupt problem --- drivers/mfd/tps65910-irq.c | 13 +++++- drivers/rtc/rtc-tps65910.c | 87 ++++++++++++++++++++++++++++++++++-- include/linux/mfd/tps65910.h | 2 + 3 files changed, 96 insertions(+), 6 deletions(-) diff --git a/drivers/mfd/tps65910-irq.c b/drivers/mfd/tps65910-irq.c index bcec38371c94..8b53c05be689 100755 --- a/drivers/mfd/tps65910-irq.c +++ b/drivers/mfd/tps65910-irq.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include static inline int irq_to_tps65910_irq(struct tps65910 *tps65910, int irq) @@ -46,6 +48,7 @@ static irqreturn_t tps65910_irq(int irq, void *irq_data) u8 reg; int i; + wake_lock(&tps65910->irq_wake); tps65910->read(tps65910, TPS65910_INT_STS, 1, ®); irq_sts = reg; tps65910->read(tps65910, TPS65910_INT_STS2, 1, ®); @@ -69,7 +72,10 @@ static irqreturn_t tps65910_irq(int irq, void *irq_data) irq_sts &= ~irq_mask; if (!irq_sts) + { + wake_unlock(&tps65910->irq_wake); return IRQ_NONE; + } for (i = 0; i < tps65910->irq_num; i++) { @@ -90,7 +96,7 @@ static irqreturn_t tps65910_irq(int irq, void *irq_data) reg = irq_sts >> 8; tps65910->write(tps65910, TPS65910_INT_STS3, 1, ®); } - + wake_unlock(&tps65910->irq_wake); return IRQ_HANDLED; } @@ -188,11 +194,14 @@ int tps65910_irq_init(struct tps65910 *tps65910, int irq, tps65910->write(tps65910, TPS65910_INT_STS2, 1, ®); tps65910->read(tps65910, TPS65910_INT_STS3, 1, ®); tps65910->write(tps65910, TPS65910_INT_STS3, 1, ®); + tps65910->read(tps65910, TPS65910_RTC_STATUS, 1, ®); + tps65910->write(tps65910, TPS65910_RTC_STATUS, 1, ®);//clear alarm and timer interrupt /* Mask top level interrupts */ tps65910->irq_mask = 0xFFFFFF; - mutex_init(&tps65910->irq_lock); + mutex_init(&tps65910->irq_lock); + wake_lock_init(&tps65910->irq_wake, WAKE_LOCK_SUSPEND, "tps65910_irq_wake"); tps65910->chip_irq = irq; tps65910->irq_base = pdata->irq_base; diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index f6a8693cabcf..50eba3a7db48 100755 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -350,21 +350,43 @@ static int tps65910_rtc_irq_set_freq(struct device *dev, int freq) return ret; } - - static irqreturn_t tps65910_alm_irq(int irq, void *data) { struct tps65910_rtc *tps65910_rtc = data; + int ret; + u8 rtc_ctl; + /*Dummy read -- mandatory for status register*/ + ret = tps65910_reg_read(tps65910_rtc->tps65910, TPS65910_RTC_STATUS); + if (ret < 0) { + printk("%s:Failed to read RTC status: %d\n", __func__, ret); + return ret; + } + + ret = tps65910_reg_read(tps65910_rtc->tps65910, TPS65910_RTC_STATUS); + if (ret < 0) { + printk("%s:Failed to read RTC status: %d\n", __func__, ret); + return ret; + } + rtc_ctl = ret&0xff; + + //The alarm interrupt keeps its low level, until the micro-controller write 1 in the ALARM bit of the RTC_STATUS_REG register. + ret = tps65910_reg_write(tps65910_rtc->tps65910, TPS65910_RTC_STATUS,rtc_ctl); + if (ret < 0) { + printk("%s:Failed to read RTC status: %d\n", __func__, ret); + return ret; + } + rtc_update_irq(tps65910_rtc->rtc, 1, RTC_IRQF | RTC_AF); + printk("%s:irq=%d,rtc_ctl=0x%x\n",__func__,irq,rtc_ctl); return IRQ_HANDLED; } static irqreturn_t tps65910_per_irq(int irq, void *data) { struct tps65910_rtc *tps65910_rtc = data; - + rtc_update_irq(tps65910_rtc->rtc, 1, RTC_IRQF | RTC_UF); //printk("%s:irq=%d\n",__func__,irq); @@ -558,6 +580,7 @@ static int tps65910_rtc_probe(struct platform_device *pdev) //tps65910_set_bits(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS, // BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); + enable_irq_wake(alm_irq); // so tps65910 alarm irq can wake up system g_pdev = pdev; printk("%s:ok\n",__func__); @@ -610,6 +633,8 @@ static ssize_t rtc_tps65910_test_write(struct file *file, int nr = 0, ret; struct platform_device *pdev; struct rtc_time tm; + struct rtc_wkalrm alrm; + struct tps65910_rtc *tps65910_rtc; if(count > 3) return -EFAULT; @@ -618,7 +643,7 @@ static ssize_t rtc_tps65910_test_write(struct file *file, return -EFAULT; sscanf(nr_buf, "%d", &nr); - if(nr >= 2 || nr < 0) + if(nr > 5 || nr < 0) { printk("%s:data is error\n",__func__); return -EFAULT; @@ -629,6 +654,10 @@ static ssize_t rtc_tps65910_test_write(struct file *file, else pdev = g_pdev; + + tps65910_rtc = dev_get_drvdata(&pdev->dev); + + //test rtc time if(nr == 0) { tm.tm_wday = 6; @@ -662,6 +691,56 @@ static ssize_t rtc_tps65910_test_write(struct file *file, else printk("%s:error\n",__func__); + + //test rtc alarm + if(nr == 2) + { + //2000-01-01 00:00:30 + if(tm.tm_sec < 30) + { + alrm.time.tm_sec = tm.tm_sec+30; + alrm.time.tm_min = tm.tm_min; + } + else + { + alrm.time.tm_sec = tm.tm_sec-30; + alrm.time.tm_min = tm.tm_min+1; + } + alrm.time.tm_hour = tm.tm_hour; + alrm.time.tm_mday = tm.tm_mday; + alrm.time.tm_mon = tm.tm_mon; + alrm.time.tm_year = tm.tm_year; + tps65910_rtc_alarm_irq_enable(&pdev->dev, 1); + tps65910_rtc_setalarm(&pdev->dev, &alrm); + + dev_info(&pdev->dev, "Set alarm %4d-%02d-%02d(%d) %02d:%02d:%02d\n", + 1900 + alrm.time.tm_year, alrm.time.tm_mon + 1, alrm.time.tm_mday, alrm.time.tm_wday, + alrm.time.tm_hour, alrm.time.tm_min, alrm.time.tm_sec); + } + + + if(nr == 3) + { + ret = tps65910_reg_read(tps65910_rtc->tps65910, TPS65910_RTC_STATUS); + if (ret < 0) { + printk("%s:Failed to read RTC status: %d\n", __func__, ret); + return ret; + } + printk("%s:ret=0x%x\n",__func__,ret&0xff); + + ret = tps65910_reg_write(tps65910_rtc->tps65910, TPS65910_RTC_STATUS, ret&0xff); + if (ret < 0) { + printk("%s:Failed to read RTC status: %d\n", __func__, ret); + return ret; + } + } + + if(nr == 4) + tps65910_rtc_update_irq_enable(&pdev->dev, 1); + + if(nr == 5) + tps65910_rtc_update_irq_enable(&pdev->dev, 0); + return count; } diff --git a/include/linux/mfd/tps65910.h b/include/linux/mfd/tps65910.h index c093c477477b..c098040c7256 100755 --- a/include/linux/mfd/tps65910.h +++ b/include/linux/mfd/tps65910.h @@ -18,6 +18,7 @@ #define __LINUX_MFD_TPS65910_H #include +#include /* TPS chip id list */ #define TPS65910 0 @@ -802,6 +803,7 @@ struct tps65910 { struct i2c_client *i2c_client; struct regmap *regmap; struct mutex io_mutex; + struct wake_lock irq_wake; unsigned int id; int (*read)(struct tps65910 *tps65910, u8 reg, int size, void *dest); int (*write)(struct tps65910 *tps65910, u8 reg, int size, void *src); From 20a22cc9d4f7da1aec4e26d710f385078d78c2b9 Mon Sep 17 00:00:00 2001 From: xbw Date: Sun, 12 Aug 2012 13:20:07 +0800 Subject: [PATCH 162/261] SDMMC: add the power-off after closing of removing the card --- arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c | 2 + drivers/mmc/host/rk29_sdmmc.c | 151 +++++++++++----------- 2 files changed, 78 insertions(+), 75 deletions(-) diff --git a/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c b/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c index 817269750485..d57ef3c84572 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c +++ b/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c @@ -140,11 +140,13 @@ static void rk29_sdmmc_set_iomux_mmc0(unsigned int bus_width) gpio_request(RK30_PIN3_PA7,"sdmmc-power"); gpio_direction_output(RK30_PIN3_PA7,GPIO_HIGH); //power-off + #if 0 //replace the power control into rk29_sdmmc_set_ios(); modifyed by xbw at 2012-08-12 rk29_sdmmc_gpio_open(0, 0); gpio_direction_output(RK30_PIN3_PA7,GPIO_LOW); //power-on rk29_sdmmc_gpio_open(0, 1); + #endif } break; diff --git a/drivers/mmc/host/rk29_sdmmc.c b/drivers/mmc/host/rk29_sdmmc.c index d2d600ab7e53..95e52dfda300 100755 --- a/drivers/mmc/host/rk29_sdmmc.c +++ b/drivers/mmc/host/rk29_sdmmc.c @@ -69,6 +69,16 @@ int debug_level = 5; #define SDMMC_USE_INT_UNBUSY 1 #endif +#if defined(CONFIG_ARCH_RK29) +#define RK29_SDMMC0DETECTN_GPIO RK29_PIN2_PA2 +#define RK29_SDMMC0PWREN_GPIO RK29_PIN5_PD5 + +#elif defined(CONFIG_ARCH_RK30) +#define RK29_SDMMC0DETECTN_GPIO RK30_PIN3_PB6 +#define RK29_SDMMC0PWREN_GPIO RK30_PIN3_PA7 + +#endif + #define RK29_SDMMC_ERROR_FLAGS (SDMMC_INT_FRUN | SDMMC_INT_HLE ) #if SDMMC_USE_INT_UNBUSY @@ -84,7 +94,7 @@ int debug_level = 5; #define RK29_SDMMC_WAIT_DTO_INTERNVAL 4500 //The time interval from the CMD_DONE_INT to DTO_INT #define RK29_SDMMC_REMOVAL_DELAY 2000 //The time interval from the CD_INT to detect_timer react. -#define RK29_SDMMC_VERSION "Ver.4.01 The last modify date is 2012-08-09" +#define RK29_SDMMC_VERSION "Ver.4.02 The last modify date is 2012-08-12" #if !defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD) #define RK29_CTRL_SDMMC_ID 0 //mainly used by SDMMC @@ -1438,7 +1448,7 @@ static int sdmmc_send_cmd_start(struct rk29_sdmmc *host, unsigned int cmd) udelay(2); } - if(!tmo) + if(!tmo && test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags)) { printk(KERN_WARNING "%s.. %d set cmd(value=0x%x) register timeout error ! [%s]\n",\ __FUNCTION__,__LINE__, cmd, host->dma_name); @@ -2288,13 +2298,22 @@ static void rk29_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { case MMC_POWER_UP: rk29_sdmmc_write(host->regs, SDMMC_PWREN, POWER_ENABLE); - + //reset the controller if it is SDMMC0 if(RK29_CTRL_SDMMC_ID == host->pdev->id) { xbwprintk(7, "%s..%d..POWER_UP, call reset_controller, initialized_flags=%d [%s]\n",\ __FUNCTION__, __LINE__, host->mmc->re_initialized_flags,host->dma_name); + #if defined(CONFIG_ARCH_RK29) + //power-on; (#define RK29_SDMMC0PWREN_GPIO RK29_PIN5_PD5 in RK2918 platform) + gpio_direction_output(RK29_SDMMC0PWREN_GPIO,GPIO_LOW); + #elif defined(CONFIG_ARCH_RK30) + //power-on; (#define RK29_SDMMC0PWREN_GPIO RK30_PIN3_PA7 in RK3066 platform) + gpio_direction_output(RK29_SDMMC0PWREN_GPIO,GPIO_LOW); + #endif + //printk("##########vcc_sd power on##########\n"); + mdelay(5); rk29_sdmmc_hw_init(host); @@ -2307,7 +2326,7 @@ static void rk29_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { rk29_sdmmc_control_clock(host, FALSE); rk29_sdmmc_write(host->regs, SDMMC_PWREN, POWER_DISABLE); - + if(5 == host->bus_mode) { mdelay(5); @@ -2316,6 +2335,16 @@ static void rk29_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) rk29_sdmmc_reset_controller(host); } + + #if defined(CONFIG_ARCH_RK29) + //power-off + gpio_direction_output(RK29_SDMMC0PWREN_GPIO,GPIO_HIGH); + + #elif defined(CONFIG_ARCH_RK30) + //power-off + gpio_direction_output(RK29_SDMMC0PWREN_GPIO,GPIO_HIGH); + #endif + //printk("##########vcc_sd power off##########\n"); } @@ -3558,11 +3587,12 @@ static int rk29_sdmmc_probe(struct platform_device *pdev) host->write_protect = pdata->write_prt; #endif - - if(RK29_CTRL_SDMMC_ID != host->pdev->id) +#if 0 + if(RK29_CTRL_SDMMC_ID == host->pdev->id) { rk29_sdmmc_hw_init(host); } +#endif ret = request_irq(host->irq, rk29_sdmmc_interrupt, 0, dev_name(&pdev->dev), host); if (ret) @@ -3731,80 +3761,51 @@ static int __exit rk29_sdmmc_remove(struct platform_device *pdev) #ifdef CONFIG_PM +static irqreturn_t det_keys_isr(int irq, void *dev_id) +{ + struct rk29_sdmmc *host = dev_id; + dev_info(&host->pdev->dev, "sd det_gpio changed(%s), send wakeup key!\n", + gpio_get_value(RK29_SDMMC0DETECTN_GPIO)?"removed":"insert"); + rk29_sdmmc_detect_change((unsigned long)dev_id); + + return IRQ_HANDLED; +} + +static int rk29_sdmmc_sdcard_suspend(struct rk29_sdmmc *host) +{ + int ret = 0; + #if defined(CONFIG_ARCH_RK29) -static irqreturn_t det_keys_isr(int irq, void *dev_id) -{ - struct rk29_sdmmc *host = dev_id; - dev_info(&host->pdev->dev, "sd det_gpio changed(%s), send wakeup key!\n", - gpio_get_value(RK29_PIN2_PA2)?"removed":"insert"); - rk29_sdmmc_detect_change((unsigned long)dev_id); - - return IRQ_HANDLED; -} - -static int rk29_sdmmc_sdcard_suspend(struct rk29_sdmmc *host) -{ - int ret = 0; - rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_GPIO2A2); - gpio_request(RK29_PIN2_PA2, "sd_detect"); - gpio_direction_input(RK29_PIN2_PA2); - - host->gpio_irq = gpio_to_irq(RK29_PIN2_PA2); - ret = request_irq(host->gpio_irq, det_keys_isr, - (gpio_get_value(RK29_PIN2_PA2))?IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING, - "sd_detect", - host); - - enable_irq_wake(host->gpio_irq); - - return ret; -} -static void rk29_sdmmc_sdcard_resume(struct rk29_sdmmc *host) -{ - disable_irq_wake(host->gpio_irq); - free_irq(host->gpio_irq,host); - gpio_free(RK29_PIN2_PA2); - rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_SDMMC0_DETECT_N); -} - + rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_GPIO2A2); #elif defined(CONFIG_ARCH_RK30) -static irqreturn_t det_keys_isr(int irq, void *dev_id) -{ - struct rk29_sdmmc *host = dev_id; - dev_info(&host->pdev->dev, "sd det_gpio changed(%s), send wakeup key!\n", - gpio_get_value(RK30_PIN3_PB6)?"removed":"insert"); - rk29_sdmmc_detect_change((unsigned long)dev_id); - - return IRQ_HANDLED; -} - -static int rk29_sdmmc_sdcard_suspend(struct rk29_sdmmc *host) -{ - int ret = 0; rk29_mux_api_set(GPIO3B6_SDMMC0DETECTN_NAME, GPIO3B_GPIO3B6); - gpio_request(RK30_PIN3_PB6, "sd_detect"); - gpio_direction_input(RK30_PIN3_PB6); - - host->gpio_irq = gpio_to_irq(RK30_PIN3_PB6); - ret = request_irq(host->gpio_irq, det_keys_isr, - (gpio_get_value(RK30_PIN3_PB6))?IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING, - "sd_detect", - host); - - enable_irq_wake(host->gpio_irq); - - return ret; -} -static void rk29_sdmmc_sdcard_resume(struct rk29_sdmmc *host) -{ - disable_irq_wake(host->gpio_irq); - free_irq(host->gpio_irq,host); - gpio_free(RK30_PIN3_PB6); - rk29_mux_api_set(GPIO3B6_SDMMC0DETECTN_NAME, GPIO3B_SDMMC0_DETECT_N); -} - #endif + gpio_request(RK29_SDMMC0DETECTN_GPIO, "sd_detect"); + gpio_direction_input(RK29_SDMMC0DETECTN_GPIO); + + host->gpio_irq = gpio_to_irq(RK29_SDMMC0DETECTN_GPIO); + ret = request_irq(host->gpio_irq, det_keys_isr, + (gpio_get_value(RK29_SDMMC0DETECTN_GPIO))?IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING, + "sd_detect", + host); + + enable_irq_wake(host->gpio_irq); + + return ret; +} +static void rk29_sdmmc_sdcard_resume(struct rk29_sdmmc *host) +{ + disable_irq_wake(host->gpio_irq); + free_irq(host->gpio_irq,host); + gpio_free(RK29_SDMMC0DETECTN_GPIO); + +#if defined(CONFIG_ARCH_RK29) + rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_SDMMC0_DETECT_N); +#elif defined(CONFIG_ARCH_RK30) + rk29_mux_api_set(GPIO3B6_SDMMC0DETECTN_NAME, GPIO3B_SDMMC0_DETECT_N); +#endif +} static int rk29_sdmmc_suspend(struct platform_device *pdev, pm_message_t state) { From 3b4d3302d6c27bf81239364312fabefb5aba40b8 Mon Sep 17 00:00:00 2001 From: xbw Date: Sun, 12 Aug 2012 13:20:07 +0800 Subject: [PATCH 163/261] SDMMC: add the power-off after closing of removing the card --- arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c | 2 + drivers/mmc/host/rk29_sdmmc.c | 151 +++++++++++----------- 2 files changed, 78 insertions(+), 75 deletions(-) diff --git a/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c b/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c index 817269750485..d57ef3c84572 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c +++ b/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c @@ -140,11 +140,13 @@ static void rk29_sdmmc_set_iomux_mmc0(unsigned int bus_width) gpio_request(RK30_PIN3_PA7,"sdmmc-power"); gpio_direction_output(RK30_PIN3_PA7,GPIO_HIGH); //power-off + #if 0 //replace the power control into rk29_sdmmc_set_ios(); modifyed by xbw at 2012-08-12 rk29_sdmmc_gpio_open(0, 0); gpio_direction_output(RK30_PIN3_PA7,GPIO_LOW); //power-on rk29_sdmmc_gpio_open(0, 1); + #endif } break; diff --git a/drivers/mmc/host/rk29_sdmmc.c b/drivers/mmc/host/rk29_sdmmc.c index d2d600ab7e53..95e52dfda300 100755 --- a/drivers/mmc/host/rk29_sdmmc.c +++ b/drivers/mmc/host/rk29_sdmmc.c @@ -69,6 +69,16 @@ int debug_level = 5; #define SDMMC_USE_INT_UNBUSY 1 #endif +#if defined(CONFIG_ARCH_RK29) +#define RK29_SDMMC0DETECTN_GPIO RK29_PIN2_PA2 +#define RK29_SDMMC0PWREN_GPIO RK29_PIN5_PD5 + +#elif defined(CONFIG_ARCH_RK30) +#define RK29_SDMMC0DETECTN_GPIO RK30_PIN3_PB6 +#define RK29_SDMMC0PWREN_GPIO RK30_PIN3_PA7 + +#endif + #define RK29_SDMMC_ERROR_FLAGS (SDMMC_INT_FRUN | SDMMC_INT_HLE ) #if SDMMC_USE_INT_UNBUSY @@ -84,7 +94,7 @@ int debug_level = 5; #define RK29_SDMMC_WAIT_DTO_INTERNVAL 4500 //The time interval from the CMD_DONE_INT to DTO_INT #define RK29_SDMMC_REMOVAL_DELAY 2000 //The time interval from the CD_INT to detect_timer react. -#define RK29_SDMMC_VERSION "Ver.4.01 The last modify date is 2012-08-09" +#define RK29_SDMMC_VERSION "Ver.4.02 The last modify date is 2012-08-12" #if !defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD) #define RK29_CTRL_SDMMC_ID 0 //mainly used by SDMMC @@ -1438,7 +1448,7 @@ static int sdmmc_send_cmd_start(struct rk29_sdmmc *host, unsigned int cmd) udelay(2); } - if(!tmo) + if(!tmo && test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags)) { printk(KERN_WARNING "%s.. %d set cmd(value=0x%x) register timeout error ! [%s]\n",\ __FUNCTION__,__LINE__, cmd, host->dma_name); @@ -2288,13 +2298,22 @@ static void rk29_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { case MMC_POWER_UP: rk29_sdmmc_write(host->regs, SDMMC_PWREN, POWER_ENABLE); - + //reset the controller if it is SDMMC0 if(RK29_CTRL_SDMMC_ID == host->pdev->id) { xbwprintk(7, "%s..%d..POWER_UP, call reset_controller, initialized_flags=%d [%s]\n",\ __FUNCTION__, __LINE__, host->mmc->re_initialized_flags,host->dma_name); + #if defined(CONFIG_ARCH_RK29) + //power-on; (#define RK29_SDMMC0PWREN_GPIO RK29_PIN5_PD5 in RK2918 platform) + gpio_direction_output(RK29_SDMMC0PWREN_GPIO,GPIO_LOW); + #elif defined(CONFIG_ARCH_RK30) + //power-on; (#define RK29_SDMMC0PWREN_GPIO RK30_PIN3_PA7 in RK3066 platform) + gpio_direction_output(RK29_SDMMC0PWREN_GPIO,GPIO_LOW); + #endif + //printk("##########vcc_sd power on##########\n"); + mdelay(5); rk29_sdmmc_hw_init(host); @@ -2307,7 +2326,7 @@ static void rk29_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { rk29_sdmmc_control_clock(host, FALSE); rk29_sdmmc_write(host->regs, SDMMC_PWREN, POWER_DISABLE); - + if(5 == host->bus_mode) { mdelay(5); @@ -2316,6 +2335,16 @@ static void rk29_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) rk29_sdmmc_reset_controller(host); } + + #if defined(CONFIG_ARCH_RK29) + //power-off + gpio_direction_output(RK29_SDMMC0PWREN_GPIO,GPIO_HIGH); + + #elif defined(CONFIG_ARCH_RK30) + //power-off + gpio_direction_output(RK29_SDMMC0PWREN_GPIO,GPIO_HIGH); + #endif + //printk("##########vcc_sd power off##########\n"); } @@ -3558,11 +3587,12 @@ static int rk29_sdmmc_probe(struct platform_device *pdev) host->write_protect = pdata->write_prt; #endif - - if(RK29_CTRL_SDMMC_ID != host->pdev->id) +#if 0 + if(RK29_CTRL_SDMMC_ID == host->pdev->id) { rk29_sdmmc_hw_init(host); } +#endif ret = request_irq(host->irq, rk29_sdmmc_interrupt, 0, dev_name(&pdev->dev), host); if (ret) @@ -3731,80 +3761,51 @@ static int __exit rk29_sdmmc_remove(struct platform_device *pdev) #ifdef CONFIG_PM +static irqreturn_t det_keys_isr(int irq, void *dev_id) +{ + struct rk29_sdmmc *host = dev_id; + dev_info(&host->pdev->dev, "sd det_gpio changed(%s), send wakeup key!\n", + gpio_get_value(RK29_SDMMC0DETECTN_GPIO)?"removed":"insert"); + rk29_sdmmc_detect_change((unsigned long)dev_id); + + return IRQ_HANDLED; +} + +static int rk29_sdmmc_sdcard_suspend(struct rk29_sdmmc *host) +{ + int ret = 0; + #if defined(CONFIG_ARCH_RK29) -static irqreturn_t det_keys_isr(int irq, void *dev_id) -{ - struct rk29_sdmmc *host = dev_id; - dev_info(&host->pdev->dev, "sd det_gpio changed(%s), send wakeup key!\n", - gpio_get_value(RK29_PIN2_PA2)?"removed":"insert"); - rk29_sdmmc_detect_change((unsigned long)dev_id); - - return IRQ_HANDLED; -} - -static int rk29_sdmmc_sdcard_suspend(struct rk29_sdmmc *host) -{ - int ret = 0; - rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_GPIO2A2); - gpio_request(RK29_PIN2_PA2, "sd_detect"); - gpio_direction_input(RK29_PIN2_PA2); - - host->gpio_irq = gpio_to_irq(RK29_PIN2_PA2); - ret = request_irq(host->gpio_irq, det_keys_isr, - (gpio_get_value(RK29_PIN2_PA2))?IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING, - "sd_detect", - host); - - enable_irq_wake(host->gpio_irq); - - return ret; -} -static void rk29_sdmmc_sdcard_resume(struct rk29_sdmmc *host) -{ - disable_irq_wake(host->gpio_irq); - free_irq(host->gpio_irq,host); - gpio_free(RK29_PIN2_PA2); - rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_SDMMC0_DETECT_N); -} - + rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_GPIO2A2); #elif defined(CONFIG_ARCH_RK30) -static irqreturn_t det_keys_isr(int irq, void *dev_id) -{ - struct rk29_sdmmc *host = dev_id; - dev_info(&host->pdev->dev, "sd det_gpio changed(%s), send wakeup key!\n", - gpio_get_value(RK30_PIN3_PB6)?"removed":"insert"); - rk29_sdmmc_detect_change((unsigned long)dev_id); - - return IRQ_HANDLED; -} - -static int rk29_sdmmc_sdcard_suspend(struct rk29_sdmmc *host) -{ - int ret = 0; rk29_mux_api_set(GPIO3B6_SDMMC0DETECTN_NAME, GPIO3B_GPIO3B6); - gpio_request(RK30_PIN3_PB6, "sd_detect"); - gpio_direction_input(RK30_PIN3_PB6); - - host->gpio_irq = gpio_to_irq(RK30_PIN3_PB6); - ret = request_irq(host->gpio_irq, det_keys_isr, - (gpio_get_value(RK30_PIN3_PB6))?IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING, - "sd_detect", - host); - - enable_irq_wake(host->gpio_irq); - - return ret; -} -static void rk29_sdmmc_sdcard_resume(struct rk29_sdmmc *host) -{ - disable_irq_wake(host->gpio_irq); - free_irq(host->gpio_irq,host); - gpio_free(RK30_PIN3_PB6); - rk29_mux_api_set(GPIO3B6_SDMMC0DETECTN_NAME, GPIO3B_SDMMC0_DETECT_N); -} - #endif + gpio_request(RK29_SDMMC0DETECTN_GPIO, "sd_detect"); + gpio_direction_input(RK29_SDMMC0DETECTN_GPIO); + + host->gpio_irq = gpio_to_irq(RK29_SDMMC0DETECTN_GPIO); + ret = request_irq(host->gpio_irq, det_keys_isr, + (gpio_get_value(RK29_SDMMC0DETECTN_GPIO))?IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING, + "sd_detect", + host); + + enable_irq_wake(host->gpio_irq); + + return ret; +} +static void rk29_sdmmc_sdcard_resume(struct rk29_sdmmc *host) +{ + disable_irq_wake(host->gpio_irq); + free_irq(host->gpio_irq,host); + gpio_free(RK29_SDMMC0DETECTN_GPIO); + +#if defined(CONFIG_ARCH_RK29) + rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_SDMMC0_DETECT_N); +#elif defined(CONFIG_ARCH_RK30) + rk29_mux_api_set(GPIO3B6_SDMMC0DETECTN_NAME, GPIO3B_SDMMC0_DETECT_N); +#endif +} static int rk29_sdmmc_suspend(struct platform_device *pdev, pm_message_t state) { From 2ecaebc3663a466f148c880419ddf0d9c5a54372 Mon Sep 17 00:00:00 2001 From: xbw Date: Sun, 12 Aug 2012 14:38:27 +0800 Subject: [PATCH 164/261] SDMMC: No essential changes, just to simplify the code submitted. continue with the previous commit 3b4d3302d6c27bf81239364312fabefb5aba40b8 --- drivers/mmc/host/rk29_sdmmc.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/mmc/host/rk29_sdmmc.c b/drivers/mmc/host/rk29_sdmmc.c index 95e52dfda300..79c2740eada8 100755 --- a/drivers/mmc/host/rk29_sdmmc.c +++ b/drivers/mmc/host/rk29_sdmmc.c @@ -2305,13 +2305,8 @@ static void rk29_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) xbwprintk(7, "%s..%d..POWER_UP, call reset_controller, initialized_flags=%d [%s]\n",\ __FUNCTION__, __LINE__, host->mmc->re_initialized_flags,host->dma_name); - #if defined(CONFIG_ARCH_RK29) - //power-on; (#define RK29_SDMMC0PWREN_GPIO RK29_PIN5_PD5 in RK2918 platform) - gpio_direction_output(RK29_SDMMC0PWREN_GPIO,GPIO_LOW); - #elif defined(CONFIG_ARCH_RK30) //power-on; (#define RK29_SDMMC0PWREN_GPIO RK30_PIN3_PA7 in RK3066 platform) gpio_direction_output(RK29_SDMMC0PWREN_GPIO,GPIO_LOW); - #endif //printk("##########vcc_sd power on##########\n"); mdelay(5); @@ -2336,14 +2331,8 @@ static void rk29_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) rk29_sdmmc_reset_controller(host); } - #if defined(CONFIG_ARCH_RK29) //power-off gpio_direction_output(RK29_SDMMC0PWREN_GPIO,GPIO_HIGH); - - #elif defined(CONFIG_ARCH_RK30) - //power-off - gpio_direction_output(RK29_SDMMC0PWREN_GPIO,GPIO_HIGH); - #endif //printk("##########vcc_sd power off##########\n"); } From cc0132bc47f8fbaf05b900507e2d3232c6fbd1cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Mon, 13 Aug 2012 11:31:13 +0800 Subject: [PATCH 165/261] rk: make help only show rk board --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 15702f930dd7..ffcda4b707a3 100644 --- a/Makefile +++ b/Makefile @@ -1233,7 +1233,7 @@ rpm: include/config/kernel.release FORCE # Brief documentation of the typical targets used # --------------------------------------------------------------------------- -boards := $(wildcard $(srctree)/arch/$(SRCARCH)/configs/*_defconfig) +boards := $(wildcard $(srctree)/arch/$(SRCARCH)/configs/rk*_defconfig) boards := $(notdir $(boards)) board-dirs := $(dir $(wildcard $(srctree)/arch/$(SRCARCH)/configs/*/*_defconfig)) board-dirs := $(sort $(notdir $(board-dirs:/=))) From da1e33bfb73cc414b8ef9ca94fa57501fe1c568f Mon Sep 17 00:00:00 2001 From: lw Date: Mon, 13 Aug 2012 12:07:38 +0800 Subject: [PATCH 166/261] phonepad:add mt6620 support for phonepad board --- arch/arm/configs/rk30_phonepad_defconfig | 28 ++++++++++++++++-------- arch/arm/mach-rk30/board-rk30-phonepad.c | 28 ++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 11 deletions(-) mode change 100644 => 100755 arch/arm/mach-rk30/board-rk30-phonepad.c diff --git a/arch/arm/configs/rk30_phonepad_defconfig b/arch/arm/configs/rk30_phonepad_defconfig index 76c29f1ca897..7c3d8f1fb8e2 100755 --- a/arch/arm/configs/rk30_phonepad_defconfig +++ b/arch/arm/configs/rk30_phonepad_defconfig @@ -24,7 +24,7 @@ CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_ARCH_RK30=y CONFIG_CLK_SWITCH_TO_32K=y CONFIG_RK30_I2C_INSRAM=y -CONFIG_WIFI_CONTROL_FUNC=y +CONFIG_WIFI_COMBO_MODULE_CONTROL_FUNC=y CONFIG_MACH_RK30_PHONE_PAD=y # CONFIG_SWP_EMULATE is not set CONFIG_FIQ_DEBUGGER=y @@ -173,14 +173,14 @@ CONFIG_BT_SCO=y CONFIG_BT_RFCOMM=y CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y CONFIG_BT_HIDP=y -CONFIG_BT_HCIUART=y -CONFIG_BT_HCIUART_H4=y -CONFIG_BT_HCIUART_LL=y -CONFIG_BT_HCIBCM4325=y -CONFIG_BT_AUTOSLEEP=y +CONFIG_CFG80211=y +CONFIG_NL80211_TESTMODE=y +CONFIG_MAC80211=y CONFIG_RFKILL=y -CONFIG_RFKILL_RK=y +CONFIG_RFKILL_INPUT=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y # CONFIG_FIRMWARE_IN_KERNEL is not set @@ -208,7 +208,7 @@ CONFIG_PHYLIB=y # CONFIG_NETDEV_1000 is not set # CONFIG_NETDEV_10000 is not set CONFIG_WLAN_80211=y -CONFIG_RKWIFI=y +CONFIG_MT6620=y CONFIG_USB_USBNET=y CONFIG_PPP=y CONFIG_PPP_MULTILINK=y @@ -246,7 +246,7 @@ CONFIG_LIGHT_DEVICE=y # CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_RK29=y CONFIG_UART0_RK29=y -CONFIG_UART0_CTS_RTS_RK29=y +CONFIG_UART0_DMA_RK29=3 CONFIG_UART3_RK29=y CONFIG_UART3_CTS_RTS_RK29=y # CONFIG_HW_RANDOM is not set @@ -385,6 +385,7 @@ CONFIG_MMC_UNSAFE_RESUME=y CONFIG_MMC_EMBEDDED_SDIO=y CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_SDMMC_RK29=y +CONFIG_RK29_SDIO_IRQ_FROM_GPIO=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_GPIO=y @@ -400,6 +401,15 @@ CONFIG_ANDROID_LOGGER=y CONFIG_ANDROID_TIMED_GPIO=y CONFIG_ANDROID_LOW_MEMORY_KILLER=y # CONFIG_CMMB is not set +CONFIG_MTK_COMBO=y +CONFIG_MTK_COMBO_PLAT_PATH="rockchip" +CONFIG_MTK_COMBO_COMM=m +CONFIG_MTK_COMBO_BT_HW_TEST=m +CONFIG_MTK_COMBO_BT_HCI=m +CONFIG_MTK_COMBO_FM=m +CONFIG_MTK_COMBO_WIFI=m +CONFIG_MTK_GPS=m +CONFIG_MTK_COMBO_GPS=m CONFIG_EXT3_FS=y # CONFIG_EXT3_FS_XATTR is not set CONFIG_EXT4_FS=y diff --git a/arch/arm/mach-rk30/board-rk30-phonepad.c b/arch/arm/mach-rk30/board-rk30-phonepad.c old mode 100644 new mode 100755 index 873249de77ec..9ec49404edf8 --- a/arch/arm/mach-rk30/board-rk30-phonepad.c +++ b/arch/arm/mach-rk30/board-rk30-phonepad.c @@ -81,6 +81,10 @@ #include "../../../drivers/staging/android/timed_gpio.h" #endif +#if defined(CONFIG_MT6620) +#include +#endif + #ifdef CONFIG_THREE_FB_BUFFER #define RK30_FB0_MEM_SIZE 12*SZ_1M #else @@ -1353,6 +1357,7 @@ static struct platform_device device_ion = { #endif #define RK29SDK_WIFI_SDIO_CARD_DETECT_N RK30_PIN6_PB2 +#define RK29SDK_WIFI_SDIO_CARD_INT RK30_PIN3_PD2 #endif //endif ---#ifdef CONFIG_SDMMC_RK29 @@ -1408,6 +1413,12 @@ struct rk29_sdmmc_platform_data default_sdmmc0_data = { #else .use_dma = 0, #endif + +#if defined(CONFIG_WIFI_COMBO_MODULE_CONTROL_FUNC) + .status = rk29sdk_wifi_mmc0_status, + .register_status_notify = rk29sdk_wifi_mmc0_status_register, +#endif + .detect_irq = RK30_PIN3_PB6, // INVALID_GPIO .enable_sd_wakeup = 0, @@ -1472,7 +1483,7 @@ struct rk29_sdmmc_platform_data default_sdmmc1_data = { #endif #if !defined(CONFIG_USE_SDMMC1_FOR_WIFI_DEVELOP_BOARD) -#ifdef CONFIG_WIFI_CONTROL_FUNC +#if defined(CONFIG_WIFI_CONTROL_FUNC) || defined(CONFIG_WIFI_COMBO_MODULE_CONTROL_FUNC) .status = rk29sdk_wifi_status, .register_status_notify = rk29sdk_wifi_status_register, #endif @@ -1486,6 +1497,10 @@ struct rk29_sdmmc_platform_data default_sdmmc1_data = { .write_prt = INVALID_GPIO, #endif +#if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) + .sdio_INT_gpio = RK29SDK_WIFI_SDIO_CARD_INT, +#endif + #else .detect_irq = INVALID_GPIO, .enable_sd_wakeup = 0, @@ -1659,9 +1674,14 @@ static struct platform_device *devices[] __initdata = { #ifdef CONFIG_RK_IRDA &irda_device, #endif -#ifdef CONFIG_WIFI_CONTROL_FUNC +#if defined(CONFIG_WIFI_CONTROL_FUNC)||defined(CONFIG_WIFI_COMBO_MODULE_CONTROL_FUNC) &rk29sdk_wifi_device, #endif + +#if defined(CONFIG_MT6620) + &mt3326_device_gps, +#endif + #ifdef CONFIG_RK29_SUPPORT_MODEM &rk30_device_modem, #endif @@ -2070,6 +2090,10 @@ static void __init machine_rk30_board_init(void) rk29sdk_wifi_bt_gpio_control_init(); #endif dcr_en_low(); + +#if defined(CONFIG_MT6620) + clk_set_rate(clk_get_sys("rk_serial.0", "uart"), 16*1000000); +#endif } static void __init rk30_reserve(void) From cee1ab84481e00540d00988a8877e344deb40ae4 Mon Sep 17 00:00:00 2001 From: lw Date: Mon, 13 Aug 2012 13:03:43 +0800 Subject: [PATCH 167/261] phonepad:modify sdmmc gpio definition for phonepad --- arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c b/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c index d57ef3c84572..0c91aeeaf266 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c +++ b/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c @@ -445,6 +445,26 @@ static struct resource resources[] = { /////////////////////////////////////////////////////////////////////////////////// #elif defined(CONFIG_WIFI_COMBO_MODULE_CONTROL_FUNC) +#if defined(CONFIG_MACH_RK30_PHONE_PAD) + #if defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD) + #define USE_SDMMC_CONTROLLER_FOR_WIFI 0 + #define RK29SDK_WIFI_COMBO_GPIO_POWER_N RK30_PIN4_PD2 + #define RK29SDK_WIFI_COMBO_GPIO_RESET_N RK30_PIN4_PD1 + #define RK29SDK_WIFI_COMBO_GPIO_VDDIO RK30_PIN1_PA6 + #define RK29SDK_WIFI_COMBO_GPIO_BGF_INT_B RK30_PIN1_PA7 + #define RK29SDK_WIFI_COMBO_GPS_SYNC RK30_PIN3_PC7 + + #else + #define USE_SDMMC_CONTROLLER_FOR_WIFI 1 + #define RK29SDK_WIFI_COMBO_GPIO_POWER_N RK30_PIN3_PC7 + #define RK29SDK_WIFI_COMBO_GPIO_RESET_N RK30_PIN3_PD1 + #define RK29SDK_WIFI_COMBO_GPIO_WIFI_INT_B RK30_PIN3_PD2 + + //#define RK29SDK_WIFI_COMBO_GPIO_VDDIO RK30_PIN6_PB4 + #define RK29SDK_WIFI_COMBO_GPIO_BGF_INT_B RK30_PIN6_PA7 + #define RK29SDK_WIFI_COMBO_GPS_SYNC RK30_PIN3_PD0 + #endif +#else #if defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD) #define USE_SDMMC_CONTROLLER_FOR_WIFI 0 @@ -464,7 +484,7 @@ static struct resource resources[] = { #define RK29SDK_WIFI_COMBO_GPIO_BGF_INT_B RK30_PIN3_PC6 #define RK29SDK_WIFI_COMBO_GPS_SYNC RK30_PIN3_PC7 #endif - +#endif #define debug_combo_system 0 From 86f5b0369cbe19013ec68b50443c269f169dc5df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Mon, 13 Aug 2012 16:17:26 +0800 Subject: [PATCH 168/261] rk2928: register arm-pmu device --- arch/arm/mach-rk2928/devices.c | 14 ++++++++++++++ arch/arm/mach-rk2928/include/mach/irqs.h | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-rk2928/devices.c b/arch/arm/mach-rk2928/devices.c index 1dc4df27e90b..0e2c3290cd30 100755 --- a/arch/arm/mach-rk2928/devices.c +++ b/arch/arm/mach-rk2928/devices.c @@ -779,6 +779,19 @@ static struct platform_device device_acodec = { }; #endif +static struct resource resource_arm_pmu = { + .start = IRQ_ARM_PMU, + .end = IRQ_ARM_PMU, + .flags = IORESOURCE_IRQ, +}; + +struct platform_device device_arm_pmu = { + .name = "arm-pmu", + .id = ARM_PMU_DEVICE_CPU, + .num_resources = 1, + .resource = &resource_arm_pmu, +}; + static int __init rk2928_init_devices(void) { rk2928_init_dma(); @@ -817,6 +830,7 @@ static int __init rk2928_init_devices(void) #ifdef CONFIG_HDMI_RK2928 platform_device_register(&device_hdmi); #endif + platform_device_register(&device_arm_pmu); return 0; } arch_initcall(rk2928_init_devices); diff --git a/arch/arm/mach-rk2928/include/mach/irqs.h b/arch/arm/mach-rk2928/include/mach/irqs.h index d0d398074bac..1a7d885c128e 100644 --- a/arch/arm/mach-rk2928/include/mach/irqs.h +++ b/arch/arm/mach-rk2928/include/mach/irqs.h @@ -53,7 +53,7 @@ #define IRQ_SDMMC_DETECT 78 #define IRQ_SDIO_DETECT 79 -#define IRQ_ARM_PMU 86 +#define IRQ_ARM_PMU 118 //hhb@rock-chips.com this spi is used for fiq_debugger signal irq #define IRQ_UART_SIGNAL 127 From 1a17aefc23baf8421fc4b50d5fa23311e05255db Mon Sep 17 00:00:00 2001 From: gwl Date: Mon, 13 Aug 2012 16:39:23 +0800 Subject: [PATCH 169/261] modify to enable WIFI_COUNTROL_FUNC as default --- arch/arm/configs/rk2928_sdk_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/rk2928_sdk_defconfig b/arch/arm/configs/rk2928_sdk_defconfig index 32f9084f6244..df2f844b1dd1 100755 --- a/arch/arm/configs/rk2928_sdk_defconfig +++ b/arch/arm/configs/rk2928_sdk_defconfig @@ -22,6 +22,7 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_ARCH_RK2928=y +CONFIG_WIFI_CONTROL_FUNC=y CONFIG_RK_DEBUG_UART=2 CONFIG_FIQ_DEBUGGER=y CONFIG_FIQ_DEBUGGER_NO_SLEEP=y From 5c79ff3b98a943889d1c8f456bec4f9402a04edb Mon Sep 17 00:00:00 2001 From: hhb Date: Mon, 13 Aug 2012 17:56:26 +0800 Subject: [PATCH 170/261] dma memcpy test:add dam thread number from 2 to 8 --- arch/arm/plat-rk/dma_memcpy_test.c | 421 +++++++++++++++++++++++------ 1 file changed, 331 insertions(+), 90 deletions(-) diff --git a/arch/arm/plat-rk/dma_memcpy_test.c b/arch/arm/plat-rk/dma_memcpy_test.c index be658680dae4..3cd3a02cec94 100644 --- a/arch/arm/plat-rk/dma_memcpy_test.c +++ b/arch/arm/plat-rk/dma_memcpy_test.c @@ -10,19 +10,24 @@ * (at your option) any later version. * * Author: hhb@rock-chips.com - * Date: 2012.03.26 - * + * Create Date: 2012.03.26 + * * HOW TO USE IT? * enter the follow command at command line * echo 1 > sys/module/dma_memcpy_test/parameters/debug enable log output,default is enable - * echo 1 > sys/module/dma_memcpy_test/parameters/dmac1 set dmac1 memcpy - * echo 1 > sys/module/dma_memcpy_test/parameters/dmac2 set dmac2 memcpy * echo 1000 > sys/module/dma_memcpy_test/parameters/interval set dma transfer interval, default is 1000ms * echo 1 > /sys/devices/platform/dma_memcpy.0/dmamemcpy to start the dma test * */ - +/* +* Driver Version Note +* +*v1.0 : 1. add dam thread number from 2 to 8; +* +* +*/ +#define VERSION_AND_TIME "dma_memcpy_test.c v1.0 2012-08-13" #include #include @@ -51,56 +56,106 @@ struct Dma_MemToMem { //wait_queue_head_t dma_memcpy_wait; //enable log output -static int debug = 1; +static int debug = 8; module_param(debug,int,S_IRUGO|S_IWUSR); //set dma transfer interval time (unit ms) static int interval = 1000; module_param(interval,int,S_IRUGO|S_IWUSR); -static int dmac1 = 1; -module_param(dmac1,int,S_IRUGO|S_IWUSR); - -static int dmac2 = -1; -module_param(dmac2,int,S_IRUGO|S_IWUSR); - - -static struct Dma_MemToMem DmaMemInfo1; -static struct Dma_MemToMem DmaMemInfo2; - +#define DMA_THREAD 1 #define MEMCPY_DMA_DBG(fmt...) {if(debug > 0) printk(fmt);} +static struct Dma_MemToMem DmaMemInfo0; +static struct Dma_MemToMem DmaMemInfo1; +static struct Dma_MemToMem DmaMemInfo2; +static struct Dma_MemToMem DmaMemInfo3; +static struct Dma_MemToMem DmaMemInfo4; +static struct Dma_MemToMem DmaMemInfo5; +static struct Dma_MemToMem DmaMemInfo6; +static struct Dma_MemToMem DmaMemInfo7; static struct rk29_dma_client rk29_dma_memcpy_client = { .name = "rk29-dma-memcpy", }; - - -static void rk29_dma_memcpy_callback1(void *buf_id, int size, enum rk29_dma_buffresult result) +static void rk29_dma_memcpy_callback0(void *buf_id, int size, enum rk29_dma_buffresult result) { - if(result != RK29_RES_OK){ + if(result != RK29_RES_OK) { + MEMCPY_DMA_DBG("%s error:%d\n", __func__, result); return; } - MEMCPY_DMA_DBG("rk29_dma_memcpy_callback1 ok\n"); - if(wq_condition == 0){ + MEMCPY_DMA_DBG("%s ok\n", __func__); + if(wq_condition == 0) { wq_condition = 1; wake_up_interruptible(&wq); } - //wake_up_interruptible(&dma_memcpy_wait); + +} + +static void rk29_dma_memcpy_callback1(void *buf_id, int size, enum rk29_dma_buffresult result) +{ + if(result != RK29_RES_OK) { + MEMCPY_DMA_DBG("%s error:%d\n", __func__, result); + } + else + MEMCPY_DMA_DBG("%s ok\n", __func__); } static void rk29_dma_memcpy_callback2(void *buf_id, int size, enum rk29_dma_buffresult result) { - if(result != RK29_RES_OK){ - return; + if(result != RK29_RES_OK) { + MEMCPY_DMA_DBG("%s error:%d\n", __func__, result); } - MEMCPY_DMA_DBG("rk29_dma_memcpy_callback2 ok\n"); - if(wq_condition == 0){ - wq_condition = 1; - wake_up_interruptible(&wq); + else + MEMCPY_DMA_DBG("%s ok\n", __func__); +} + +static void rk29_dma_memcpy_callback3(void *buf_id, int size, enum rk29_dma_buffresult result) +{ + if(result != RK29_RES_OK) { + MEMCPY_DMA_DBG("%s error:%d\n", __func__, result); } - //wake_up_interruptible(&dma_memcpy_wait); + else + MEMCPY_DMA_DBG("%s ok\n", __func__); +} + +static void rk29_dma_memcpy_callback4(void *buf_id, int size, enum rk29_dma_buffresult result) +{ + if(result != RK29_RES_OK) { + MEMCPY_DMA_DBG("%s error:%d\n", __func__, result); + } + else + MEMCPY_DMA_DBG("%s ok\n", __func__); +} + +static void rk29_dma_memcpy_callback5(void *buf_id, int size, enum rk29_dma_buffresult result) +{ + if(result != RK29_RES_OK) { + MEMCPY_DMA_DBG("%s error:%d\n", __func__, result); + } + else + MEMCPY_DMA_DBG("%s ok\n", __func__); +} + + +static void rk29_dma_memcpy_callback6(void *buf_id, int size, enum rk29_dma_buffresult result) +{ + if(result != RK29_RES_OK) { + MEMCPY_DMA_DBG("%s error:%d\n", __func__, result); + } + else + MEMCPY_DMA_DBG("%s ok\n", __func__); +} + + +static void rk29_dma_memcpy_callback7(void *buf_id, int size, enum rk29_dma_buffresult result) +{ + if(result != RK29_RES_OK) { + MEMCPY_DMA_DBG("%s error:%d\n", __func__, result); + } + else + MEMCPY_DMA_DBG("%s ok\n", __func__); } //int slecount = 0; @@ -112,48 +167,131 @@ static ssize_t memcpy_dma_read(struct device *device,struct device_attribute *at static ssize_t memcpy_dma_write(struct device *device, struct device_attribute *attr, const char *argv, size_t count) { - int rt, i; - // struct Dma_MemToMem *DmaMemInfo1 = (struct Dma_MemToMem *)argv; + int i; MEMCPY_DMA_DBG("memcpy_dma_write\n"); - //dmac1 - if(dmac1 > 0) { - memset(DmaMemInfo1.src, 0x55, DMA_TEST_BUFFER_SIZE); - memset(DmaMemInfo1.dst, 0x0, DMA_TEST_BUFFER_SIZE); - rt = rk29_dma_devconfig(DMACH_DMAC1_MEMTOMEM, RK29_DMASRC_MEMTOMEM, DmaMemInfo1.SrcAddr); - rt = rk29_dma_enqueue(DMACH_DMAC1_MEMTOMEM, NULL, DmaMemInfo1.DstAddr, DmaMemInfo1.MenSize); - rt = rk29_dma_ctrl(DMACH_DMAC1_MEMTOMEM, RK29_DMAOP_START); - } - - //dmac2 - if(dmac2 > 0) { - memset(DmaMemInfo2.src, 0xaa, DMA_TEST_BUFFER_SIZE); - memset(DmaMemInfo2.dst, 0x0, DMA_TEST_BUFFER_SIZE); - rt = rk29_dma_devconfig(DMACH_DMAC2_MEMTOMEM, RK29_DMASRC_MEMTOMEM, DmaMemInfo2.SrcAddr); - rt = rk29_dma_enqueue(DMACH_DMAC2_MEMTOMEM, NULL, DmaMemInfo2.DstAddr, DmaMemInfo2.MenSize); - rt = rk29_dma_ctrl(DMACH_DMAC2_MEMTOMEM, RK29_DMAOP_START); - } - - if(dmac2 > 0 || dmac1 > 0) - wait_event_interruptible_timeout(wq, wq_condition, 500); - - if(dmac1 > 0) { - for(i = 0; i < 16; i++) { - MEMCPY_DMA_DBG("dmac1 src1:%x", *(DmaMemInfo1.src + i*(DMA_TEST_BUFFER_SIZE/16))); - MEMCPY_DMA_DBG(" -> dst1:%x\n", *(DmaMemInfo1.dst + i*(DMA_TEST_BUFFER_SIZE/16))); - } - } + switch(DMA_THREAD) { + case 8: + memset(DmaMemInfo7.src, 0x77, DMA_TEST_BUFFER_SIZE); + memset(DmaMemInfo7.dst, 0x0, DMA_TEST_BUFFER_SIZE); + rk29_dma_devconfig(DMACH_DMAC7_MEMTOMEM, RK29_DMASRC_MEMTOMEM, DmaMemInfo7.SrcAddr); + rk29_dma_enqueue(DMACH_DMAC7_MEMTOMEM, NULL, DmaMemInfo7.DstAddr, DmaMemInfo7.MenSize); + case 7: + memset(DmaMemInfo6.src, 0x66, DMA_TEST_BUFFER_SIZE); + memset(DmaMemInfo6.dst, 0x0, DMA_TEST_BUFFER_SIZE); + rk29_dma_devconfig(DMACH_DMAC6_MEMTOMEM, RK29_DMASRC_MEMTOMEM, DmaMemInfo6.SrcAddr); + rk29_dma_enqueue(DMACH_DMAC6_MEMTOMEM, NULL, DmaMemInfo6.DstAddr, DmaMemInfo6.MenSize); + case 6: + memset(DmaMemInfo5.src, 0x55, DMA_TEST_BUFFER_SIZE); + memset(DmaMemInfo5.dst, 0x0, DMA_TEST_BUFFER_SIZE); + rk29_dma_devconfig(DMACH_DMAC5_MEMTOMEM, RK29_DMASRC_MEMTOMEM, DmaMemInfo5.SrcAddr); + rk29_dma_enqueue(DMACH_DMAC5_MEMTOMEM, NULL, DmaMemInfo5.DstAddr, DmaMemInfo5.MenSize); + case 5: + memset(DmaMemInfo4.src, 0x44, DMA_TEST_BUFFER_SIZE); + memset(DmaMemInfo4.dst, 0x0, DMA_TEST_BUFFER_SIZE); + rk29_dma_devconfig(DMACH_DMAC4_MEMTOMEM, RK29_DMASRC_MEMTOMEM, DmaMemInfo4.SrcAddr); + rk29_dma_enqueue(DMACH_DMAC4_MEMTOMEM, NULL, DmaMemInfo4.DstAddr, DmaMemInfo4.MenSize); + case 4: + memset(DmaMemInfo3.src, 0x33, DMA_TEST_BUFFER_SIZE); + memset(DmaMemInfo3.dst, 0x0, DMA_TEST_BUFFER_SIZE); + rk29_dma_devconfig(DMACH_DMAC3_MEMTOMEM, RK29_DMASRC_MEMTOMEM, DmaMemInfo3.SrcAddr); + rk29_dma_enqueue(DMACH_DMAC3_MEMTOMEM, NULL, DmaMemInfo3.DstAddr, DmaMemInfo3.MenSize); + case 3: + memset(DmaMemInfo2.src, 0x22, DMA_TEST_BUFFER_SIZE); + memset(DmaMemInfo2.dst, 0x0, DMA_TEST_BUFFER_SIZE); + rk29_dma_devconfig(DMACH_DMAC2_MEMTOMEM, RK29_DMASRC_MEMTOMEM, DmaMemInfo2.SrcAddr); + rk29_dma_enqueue(DMACH_DMAC2_MEMTOMEM, NULL, DmaMemInfo2.DstAddr, DmaMemInfo2.MenSize); + case 2: + memset(DmaMemInfo1.src, 0xaa, DMA_TEST_BUFFER_SIZE); + memset(DmaMemInfo1.dst, 0x0, DMA_TEST_BUFFER_SIZE); + rk29_dma_devconfig(DMACH_DMAC1_MEMTOMEM, RK29_DMASRC_MEMTOMEM, DmaMemInfo1.SrcAddr); + rk29_dma_enqueue(DMACH_DMAC1_MEMTOMEM, NULL, DmaMemInfo1.DstAddr, DmaMemInfo1.MenSize); + case 1: + memset(DmaMemInfo0.src, 0xaa, DMA_TEST_BUFFER_SIZE); + memset(DmaMemInfo0.dst, 0x0, DMA_TEST_BUFFER_SIZE); + rk29_dma_devconfig(DMACH_DMAC0_MEMTOMEM, RK29_DMASRC_MEMTOMEM, DmaMemInfo0.SrcAddr); + rk29_dma_enqueue(DMACH_DMAC0_MEMTOMEM, NULL, DmaMemInfo0.DstAddr, DmaMemInfo0.MenSize); + break; + default: + printk("%s no channel\n", __func__); + break; - if(dmac2 > 0) { - for(i = 0; i < 16; i++) { - MEMCPY_DMA_DBG("dmac2 src2:%x", *(DmaMemInfo2.src + i*(DMA_TEST_BUFFER_SIZE/16))); - MEMCPY_DMA_DBG(" -> dst2:%x\n", *(DmaMemInfo2.dst + i*(DMA_TEST_BUFFER_SIZE/16))); - } } - msleep(interval); + + switch(DMA_THREAD) { + case 8: + rk29_dma_ctrl(DMACH_DMAC7_MEMTOMEM, RK29_DMAOP_START); + case 7: + rk29_dma_ctrl(DMACH_DMAC6_MEMTOMEM, RK29_DMAOP_START); + case 6: + rk29_dma_ctrl(DMACH_DMAC5_MEMTOMEM, RK29_DMAOP_START); + case 5: + rk29_dma_ctrl(DMACH_DMAC4_MEMTOMEM, RK29_DMAOP_START); + case 4: + rk29_dma_ctrl(DMACH_DMAC3_MEMTOMEM, RK29_DMAOP_START); + case 3: + rk29_dma_ctrl(DMACH_DMAC2_MEMTOMEM, RK29_DMAOP_START); + case 2: + rk29_dma_ctrl(DMACH_DMAC1_MEMTOMEM, RK29_DMAOP_START); + case 1: + rk29_dma_ctrl(DMACH_DMAC0_MEMTOMEM, RK29_DMAOP_START); + break; + default: + printk("%s no channel\n", __func__); + break; + + } + + wait_event_interruptible_timeout(wq, wq_condition, 500); + + switch(DMA_THREAD) { + case 8: + for(i = 0; i < 16; i++) { + MEMCPY_DMA_DBG("src7:%x", *(DmaMemInfo7.src + i*(DMA_TEST_BUFFER_SIZE/16))); + MEMCPY_DMA_DBG(" -> dst7:%x\n", *(DmaMemInfo7.dst + i*(DMA_TEST_BUFFER_SIZE/16))); + } + case 7: + for(i = 0; i < 16; i++) { + MEMCPY_DMA_DBG("src6:%x", *(DmaMemInfo6.src + i*(DMA_TEST_BUFFER_SIZE/16))); + MEMCPY_DMA_DBG(" -> dst6:%x\n", *(DmaMemInfo6.dst + i*(DMA_TEST_BUFFER_SIZE/16))); + } + case 6: + for(i = 0; i < 16; i++) { + MEMCPY_DMA_DBG("src5:%x", *(DmaMemInfo5.src + i*(DMA_TEST_BUFFER_SIZE/16))); + MEMCPY_DMA_DBG(" -> dst5:%x\n", *(DmaMemInfo5.dst + i*(DMA_TEST_BUFFER_SIZE/16))); + } + case 5: + for(i = 0; i < 16; i++) { + MEMCPY_DMA_DBG("src4:%x", *(DmaMemInfo4.src + i*(DMA_TEST_BUFFER_SIZE/16))); + MEMCPY_DMA_DBG(" -> dst4:%x\n", *(DmaMemInfo4.dst + i*(DMA_TEST_BUFFER_SIZE/16))); + } + case 4: + for(i = 0; i < 16; i++) { + MEMCPY_DMA_DBG("src3:%x", *(DmaMemInfo3.src + i*(DMA_TEST_BUFFER_SIZE/16))); + MEMCPY_DMA_DBG(" -> dst3:%x\n", *(DmaMemInfo3.dst + i*(DMA_TEST_BUFFER_SIZE/16))); + } + case 3: + for(i = 0; i < 16; i++) { + MEMCPY_DMA_DBG("src2:%x", *(DmaMemInfo2.src + i*(DMA_TEST_BUFFER_SIZE/16))); + MEMCPY_DMA_DBG(" -> dst2:%x\n", *(DmaMemInfo2.dst + i*(DMA_TEST_BUFFER_SIZE/16))); + } + case 2: + for(i = 0; i < 16; i++) { + MEMCPY_DMA_DBG("src1:%x", *(DmaMemInfo1.src + i*(DMA_TEST_BUFFER_SIZE/16))); + MEMCPY_DMA_DBG(" -> dst1:%x\n", *(DmaMemInfo1.dst + i*(DMA_TEST_BUFFER_SIZE/16))); + } + case 1: + for(i = 0; i < 16; i++) { + MEMCPY_DMA_DBG("src0:%x", *(DmaMemInfo0.src + i*(DMA_TEST_BUFFER_SIZE/16))); + MEMCPY_DMA_DBG(" -> dst0:%x\n", *(DmaMemInfo0.dst + i*(DMA_TEST_BUFFER_SIZE/16))); + } + break; + default: + printk("%s no channel\n", __func__); + break; + } + wq_condition = 0; - //init_waitqueue_head(&dma_memcpy_wait); - //interruptible_sleep_on(&dma_memcpy_wait); return 0; } @@ -167,28 +305,130 @@ static int __devinit dma_memcpy_probe(struct platform_device *pdev) ret = device_create_file(&pdev->dev, &dev_attr_dmamemcpy); printk(">>>>>>>>>>>>>>>>>>>>> dam_test_probe <<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); - //dmac1 - if (rk29_dma_request(DMACH_DMAC1_MEMTOMEM, &rk29_dma_memcpy_client, NULL) == -EBUSY) { - printk("DMACH_DMAC1_MEMTOMEM request fail\n"); - } else { - rk29_dma_config(DMACH_DMAC1_MEMTOMEM, 8, 16); - rk29_dma_set_buffdone_fn(DMACH_DMAC1_MEMTOMEM, rk29_dma_memcpy_callback1); - DmaMemInfo1.src = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo1.SrcAddr, GFP_KERNEL); - DmaMemInfo1.dst = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo1.DstAddr, GFP_KERNEL); - DmaMemInfo1.MenSize = DMA_TEST_BUFFER_SIZE; - printk("DMACH_DMAC1_MEMTOMEM request sucess\n"); - } - - //dmac2 - if (rk29_dma_request(DMACH_DMAC2_MEMTOMEM, &rk29_dma_memcpy_client, NULL) == -EBUSY) { - printk("DMACH_DMAC2_MEMTOMEM request fail\n"); - } else { - rk29_dma_config(DMACH_DMAC2_MEMTOMEM, 8, 16); - rk29_dma_set_buffdone_fn(DMACH_DMAC2_MEMTOMEM, rk29_dma_memcpy_callback2); - DmaMemInfo2.src = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo2.SrcAddr, GFP_KERNEL); - DmaMemInfo2.dst = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo2.DstAddr, GFP_KERNEL); - DmaMemInfo2.MenSize = DMA_TEST_BUFFER_SIZE; - printk("DMACH_DMAC2_MEMTOMEM request sucess\n"); + switch(DMA_THREAD) { + case 8: + if (rk29_dma_request(DMACH_DMAC7_MEMTOMEM, &rk29_dma_memcpy_client, NULL) == -EBUSY) { + printk("DMACH_DMAC7_MEMTOMEM request fail\n"); + } else { + rk29_dma_config(DMACH_DMAC7_MEMTOMEM, 8, 16); + rk29_dma_set_buffdone_fn(DMACH_DMAC7_MEMTOMEM, rk29_dma_memcpy_callback7); + DmaMemInfo7.src = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo7.SrcAddr, GFP_KERNEL); + DmaMemInfo7.dst = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo7.DstAddr, GFP_KERNEL); + DmaMemInfo7.MenSize = DMA_TEST_BUFFER_SIZE; + if(DmaMemInfo7.src == NULL || DmaMemInfo7.dst == NULL) + printk("DMACH_DMAC7_MEMTOMEM alloc memory fail\n"); + else + printk("DMACH_DMAC7_MEMTOMEM request sucess\n"); + } + + case 7: + if (rk29_dma_request(DMACH_DMAC6_MEMTOMEM, &rk29_dma_memcpy_client, NULL) == -EBUSY) { + printk("DMACH_DMAC6_MEMTOMEM request fail\n"); + } else { + rk29_dma_config(DMACH_DMAC6_MEMTOMEM, 8, 16); + rk29_dma_set_buffdone_fn(DMACH_DMAC6_MEMTOMEM, rk29_dma_memcpy_callback6); + DmaMemInfo6.src = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo6.SrcAddr, GFP_KERNEL); + DmaMemInfo6.dst = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo6.DstAddr, GFP_KERNEL); + DmaMemInfo6.MenSize = DMA_TEST_BUFFER_SIZE; + if(DmaMemInfo6.src == NULL || DmaMemInfo6.dst == NULL) + printk("DMACH_DMAC6_MEMTOMEM alloc memory fail\n"); + else + printk("DMACH_DMAC6_MEMTOMEM request sucess\n"); + } + + case 6: + if (rk29_dma_request(DMACH_DMAC5_MEMTOMEM, &rk29_dma_memcpy_client, NULL) == -EBUSY) { + printk("DMACH_DMAC5_MEMTOMEM request fail\n"); + } else { + rk29_dma_config(DMACH_DMAC5_MEMTOMEM, 8, 16); + rk29_dma_set_buffdone_fn(DMACH_DMAC5_MEMTOMEM, rk29_dma_memcpy_callback5); + DmaMemInfo5.src = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo5.SrcAddr, GFP_KERNEL); + DmaMemInfo5.dst = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo5.DstAddr, GFP_KERNEL); + DmaMemInfo5.MenSize = DMA_TEST_BUFFER_SIZE; + if(DmaMemInfo5.src == NULL || DmaMemInfo5.dst == NULL) + printk("DMACH_DMAC5_MEMTOMEM alloc memory fail\n"); + else + printk("DMACH_DMAC5_MEMTOMEM request sucess\n"); + } + + case 5: + if (rk29_dma_request(DMACH_DMAC4_MEMTOMEM, &rk29_dma_memcpy_client, NULL) == -EBUSY) { + printk("DMACH_DMAC4_MEMTOMEM request fail\n"); + } else { + rk29_dma_config(DMACH_DMAC4_MEMTOMEM, 8, 16); + rk29_dma_set_buffdone_fn(DMACH_DMAC4_MEMTOMEM, rk29_dma_memcpy_callback4); + DmaMemInfo4.src = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo4.SrcAddr, GFP_KERNEL); + DmaMemInfo4.dst = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo4.DstAddr, GFP_KERNEL); + DmaMemInfo4.MenSize = DMA_TEST_BUFFER_SIZE; + if(DmaMemInfo4.src == NULL || DmaMemInfo4.dst == NULL) + printk("DMACH_DMAC4_MEMTOMEM alloc memory fail\n"); + else + printk("DMACH_DMAC4_MEMTOMEM request sucess\n"); + } + + case 4: + if (rk29_dma_request(DMACH_DMAC3_MEMTOMEM, &rk29_dma_memcpy_client, NULL) == -EBUSY) { + printk("DMACH_DMAC3_MEMTOMEM request fail\n"); + } else { + rk29_dma_config(DMACH_DMAC3_MEMTOMEM, 8, 16); + rk29_dma_set_buffdone_fn(DMACH_DMAC3_MEMTOMEM, rk29_dma_memcpy_callback3); + DmaMemInfo3.src = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo3.SrcAddr, GFP_KERNEL); + DmaMemInfo3.dst = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo3.DstAddr, GFP_KERNEL); + DmaMemInfo3.MenSize = DMA_TEST_BUFFER_SIZE; + if(DmaMemInfo3.src == NULL || DmaMemInfo3.dst == NULL) + printk("DMACH_DMAC3_MEMTOMEM alloc memory fail\n"); + else + printk("DMACH_DMAC3_MEMTOMEM request sucess\n"); + } + + case 3: + if (rk29_dma_request(DMACH_DMAC2_MEMTOMEM, &rk29_dma_memcpy_client, NULL) == -EBUSY) { + printk("DMACH_DMAC2_MEMTOMEM request fail\n"); + } else { + rk29_dma_config(DMACH_DMAC2_MEMTOMEM, 8, 16); + rk29_dma_set_buffdone_fn(DMACH_DMAC2_MEMTOMEM, rk29_dma_memcpy_callback2); + DmaMemInfo2.src = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo2.SrcAddr, GFP_KERNEL); + DmaMemInfo2.dst = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo2.DstAddr, GFP_KERNEL); + DmaMemInfo2.MenSize = DMA_TEST_BUFFER_SIZE; + if(DmaMemInfo2.src == NULL || DmaMemInfo2.dst == NULL) + printk("DMACH_DMAC2_MEMTOMEM alloc memory fail\n"); + else + printk("DMACH_DMAC2_MEMTOMEM request sucess\n"); + } + + case 2: + if (rk29_dma_request(DMACH_DMAC1_MEMTOMEM, &rk29_dma_memcpy_client, NULL) == -EBUSY) { + printk("DMACH_DMAC1_MEMTOMEM request fail\n"); + } else { + rk29_dma_config(DMACH_DMAC1_MEMTOMEM, 8, 16); + rk29_dma_set_buffdone_fn(DMACH_DMAC1_MEMTOMEM, rk29_dma_memcpy_callback1); + DmaMemInfo1.src = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo1.SrcAddr, GFP_KERNEL); + DmaMemInfo1.dst = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo1.DstAddr, GFP_KERNEL); + DmaMemInfo1.MenSize = DMA_TEST_BUFFER_SIZE; + if(DmaMemInfo1.src == NULL || DmaMemInfo1.dst == NULL) + printk("DMACH_DMAC1_MEMTOMEM alloc memory fail\n"); + else + printk("DMACH_DMAC1_MEMTOMEM request sucess\n"); + } + + case 1: + if (rk29_dma_request(DMACH_DMAC0_MEMTOMEM, &rk29_dma_memcpy_client, NULL) == -EBUSY) { + printk("DMACH_DMAC0_MEMTOMEM request fail\n"); + } else { + rk29_dma_config(DMACH_DMAC0_MEMTOMEM, 8, 16); + rk29_dma_set_buffdone_fn(DMACH_DMAC0_MEMTOMEM, rk29_dma_memcpy_callback0); + DmaMemInfo0.src = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo0.SrcAddr, GFP_KERNEL); + DmaMemInfo0.dst = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo0.DstAddr, GFP_KERNEL); + DmaMemInfo0.MenSize = DMA_TEST_BUFFER_SIZE; + if(DmaMemInfo0.src == NULL || DmaMemInfo0.dst == NULL) + printk("DMACH_DMAC0_MEMTOMEM alloc memory fail\n"); + else + printk("DMACH_DMAC0_MEMTOMEM request sucess\n"); + } + break; + default: + printk("%s no channel\n", __func__); + break; } return 0; } @@ -227,9 +467,10 @@ static void __exit dma_test_exit(void) platform_driver_unregister(&dma_mempcy_driver); } -late_initcall(dma_test_init); +module_init(dma_test_init); module_exit(dma_test_exit); MODULE_DESCRIPTION("RK29 PL330 Dma Test Deiver"); MODULE_LICENSE("GPL V2"); MODULE_AUTHOR("ZhenFu Fang "); +MODULE_AUTHOR("Hong Huibin"); From b3a15f334a711433e77a9f7d3fb7f4067611b5d5 Mon Sep 17 00:00:00 2001 From: hxy Date: Tue, 14 Aug 2012 10:46:02 +0800 Subject: [PATCH 171/261] update rk3066b(rk31) sdk board according hw sch --- arch/arm/configs/rk3066b_sdk_defconfig | 143 ++ arch/arm/mach-rk30/Kconfig | 3 + arch/arm/mach-rk30/Makefile | 1 + arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c | 99 +- arch/arm/mach-rk30/board-rk3066b-sdk-key.c | 65 + arch/arm/mach-rk30/board-rk3066b-sdk-rfkill.c | 449 +++++ arch/arm/mach-rk30/board-rk3066b-sdk-sdmmc.c | 532 ++++++ arch/arm/mach-rk30/board-rk3066b-sdk-wm8326.c | 842 ++++++++ arch/arm/mach-rk30/board-rk3066b-sdk.c | 1688 +++++++++++++++++ arch/arm/mach-rk30/board-rk31-fpga.c | 2 +- arch/arm/mach-rk30/clock.h | 2 +- sound/soc/codecs/rk610_codec.c | 2 + 12 files changed, 3731 insertions(+), 97 deletions(-) create mode 100644 arch/arm/configs/rk3066b_sdk_defconfig create mode 100644 arch/arm/mach-rk30/board-rk3066b-sdk-key.c create mode 100644 arch/arm/mach-rk30/board-rk3066b-sdk-rfkill.c create mode 100644 arch/arm/mach-rk30/board-rk3066b-sdk-sdmmc.c create mode 100644 arch/arm/mach-rk30/board-rk3066b-sdk-wm8326.c create mode 100644 arch/arm/mach-rk30/board-rk3066b-sdk.c diff --git a/arch/arm/configs/rk3066b_sdk_defconfig b/arch/arm/configs/rk3066b_sdk_defconfig new file mode 100644 index 000000000000..ac9a01f128b7 --- /dev/null +++ b/arch/arm/configs/rk3066b_sdk_defconfig @@ -0,0 +1,143 @@ +CONFIG_EXPERIMENTAL=y +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_KERNEL_LZO=y +CONFIG_LOG_BUF_SHIFT=19 +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_CGROUP_SCHED=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="root" +CONFIG_INITRAMFS_COMPRESSION_GZIP=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_PANIC_TIMEOUT=1 +# CONFIG_SYSCTL_SYSCALL is not set +# CONFIG_ELF_CORE is not set +CONFIG_ASHMEM=y +# CONFIG_AIO is not set +CONFIG_EMBEDDED=y +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_ARCH_RK31=y +# CONFIG_DDR_TEST is not set +# CONFIG_RK29_LAST_LOG is not set +CONFIG_RK_DEBUG_UART=1 +CONFIG_MACH_RK3066B_SDK=y +# CONFIG_CACHE_L2X0 is not set +CONFIG_FIQ_DEBUGGER=y +CONFIG_FIQ_DEBUGGER_NO_SLEEP=y +CONFIG_FIQ_DEBUGGER_CONSOLE=y +CONFIG_FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +CONFIG_HIGHMEM=y +CONFIG_COMPACTION=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=32768 +CONFIG_CMDLINE="console=ttyFIQ0 androidboot.console=ttyFIQ0 init=/init debug" +CONFIG_VFP=y +CONFIG_WAKELOCK=y +CONFIG_PM_RUNTIME=y +CONFIG_SUSPEND_TIME=y +CONFIG_NET=y +CONFIG_UNIX=y +# CONFIG_NET_ACTIVITY_STATS is not set +# CONFIG_WIRELESS is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_FIRMWARE_IN_KERNEL is not set +CONFIG_MTD=y +CONFIG_MISC_DEVICES=y +# CONFIG_ANDROID_PMEM is not set +CONFIG_INPUT_POLLDEV=y +# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_SERIO is not set +# CONFIG_CONSOLE_TRANSLATIONS is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_HW_RANDOM is not set +CONFIG_I2C=y +CONFIG_I2C0_CONTROLLER_RK30=y +CONFIG_I2C1_CONTROLLER_RK30=y +CONFIG_I2C2_CONTROLLER_RK30=y +# CONFIG_I2C3_RK30 is not set +# CONFIG_ADC is not set +CONFIG_EXPANDED_GPIO_NUM=0 +CONFIG_EXPANDED_GPIO_IRQ_NUM=0 +CONFIG_SPI_FPGA_GPIO_NUM=0 +CONFIG_SPI_FPGA_GPIO_IRQ_NUM=0 +# CONFIG_HWMON is not set +# CONFIG_MFD_SUPPORT is not set +CONFIG_MEDIA_SUPPORT=y +CONFIG_VIDEO_DEV=y +CONFIG_SOC_CAMERA=y +CONFIG_SOC_CAMERA_OV2659=y +CONFIG_VIDEO_RK29=y +CONFIG_VIDEO_RK29_CAMMEM_ION=y +CONFIG_ION=y +CONFIG_ION_ROCKCHIP=y +CONFIG_FB=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set +CONFIG_DISPLAY_SUPPORT=y +CONFIG_LCD_TD043MGEA1=y +CONFIG_FB_ROCKCHIP=y +CONFIG_LCDC_RK31=y +CONFIG_LCDC1_RK31=y +# CONFIG_THREE_FB_BUFFER is not set +CONFIG_RGA_RK30=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +# CONFIG_SND_SUPPORT_OLD_API is not set +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_ARM is not set +CONFIG_SND_SOC=y +CONFIG_SND_RK29_SOC=y +CONFIG_SND_RK29_SOC_I2S_2CH=y +CONFIG_SND_I2S_DMA_EVENT_STATIC=y +CONFIG_SND_RK29_SOC_RK1000=y +CONFIG_SND_RK29_CODEC_SOC_SLAVE=y +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +CONFIG_MMC=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_SDMMC_RK29=y +# CONFIG_SDMMC1_RK29 is not set +CONFIG_RTC_CLASS=y +# CONFIG_CMMB is not set +# CONFIG_DNOTIFY is not set +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +# CONFIG_MISC_FILESYSTEMS is not set +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DETECT_HUNG_TASK=y +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +CONFIG_SLUB_DEBUG_ON=y +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_FTRACE is not set diff --git a/arch/arm/mach-rk30/Kconfig b/arch/arm/mach-rk30/Kconfig index 8570164a8175..bbf9fbd1bb63 100755 --- a/arch/arm/mach-rk30/Kconfig +++ b/arch/arm/mach-rk30/Kconfig @@ -33,6 +33,9 @@ choice config MACH_RK31_FPGA bool "RK31 FPGA board" +config MACH_RK3066B_SDK + bool "RK3066B(RK31) SDK board" + endchoice endif diff --git a/arch/arm/mach-rk30/Makefile b/arch/arm/mach-rk30/Makefile index dd80c7fbb443..36026827d73d 100755 --- a/arch/arm/mach-rk30/Makefile +++ b/arch/arm/mach-rk30/Makefile @@ -30,3 +30,4 @@ obj-$(CONFIG_MACH_RK30_DS1001B) += board-rk30-ds1001b.o board-rk30-ds1001b-key.o obj-$(CONFIG_MACH_RK30_PHONE_A22) += board-rk30-phone-a22.o board-rk30-phone-a22-key.o obj-$(CONFIG_MACH_RK31_FPGA) += board-rk31-fpga.o +obj-$(CONFIG_MACH_RK3066B_SDK) += board-rk3066b-sdk.o board-rk3066b-sdk-key.o board-rk3066b-sdk-rfkill.o diff --git a/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c b/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c index 1a1dd79c0d75..df39601eaf4b 100644 --- a/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c +++ b/arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c @@ -25,26 +25,17 @@ static void rk29_sdmmc_gpio_open(int device_id, int on) #ifdef CONFIG_SDMMC0_RK29 if(on) { - #if defined(CONFIG_ARCH_RK30) gpio_direction_output(GPIO3B_GPIO3B0,GPIO_HIGH);//set mmc0-clk to high gpio_direction_output(GPIO3B_GPIO3B1,GPIO_HIGH);// set mmc0-cmd to high. gpio_direction_output(GPIO3B_GPIO3B2,GPIO_HIGH);//set mmc0-data0 to high. gpio_direction_output(GPIO3B_GPIO3B3,GPIO_HIGH);//set mmc0-data1 to high. gpio_direction_output(GPIO3B_GPIO3B4,GPIO_HIGH);//set mmc0-data2 to high. gpio_direction_output(GPIO3B_GPIO3B5,GPIO_HIGH);//set mmc0-data3 to high. - #elif defined(CONFIG_ARCH_RK31) - gpio_direction_output(RK30_PIN3_PA2,GPIO_HIGH);//set mmc0-clk to high - gpio_direction_output(RK30_PIN3_PA3,GPIO_HIGH);// set mmc0-cmd to high. - gpio_direction_output(RK30_PIN3_PA4,GPIO_HIGH);//set mmc0-data0 to high. - gpio_direction_output(RK30_PIN3_PA5,GPIO_HIGH);//set mmc0-data1 to high. - gpio_direction_output(RK30_PIN3_PA6,GPIO_HIGH);//set mmc0-data2 to high. - gpio_direction_output(RK30_PIN3_PA7,GPIO_HIGH);//set mmc0-data3 to high. - #endif + mdelay(30); } else { - #if defined(CONFIG_ARCH_RK30) rk30_mux_api_set(GPIO3B0_SDMMC0CLKOUT_NAME, GPIO3B_GPIO3B0); gpio_request(RK30_PIN3_PB0, "mmc0-clk"); gpio_direction_output(RK30_PIN3_PB0,GPIO_LOW);//set mmc0-clk to low. @@ -68,31 +59,7 @@ static void rk29_sdmmc_gpio_open(int device_id, int on) rk30_mux_api_set(GPIO3B5_SDMMC0DATA3_NAME, GPIO3B_GPIO3B5); gpio_request(RK30_PIN3_PB5, "mmc0-data3"); gpio_direction_output(RK30_PIN3_PB5,GPIO_LOW);//set mmc0-data3 to low. - #elif defined(CONFIG_ARCH_RK31) - rk30_mux_api_set(GPIO3A2_SDMMC0CLKOUT_NAME, GPIO3A_GPIO3A2); - gpio_request(RK30_PIN3_PA2, "mmc0-clk"); - gpio_direction_output(RK30_PIN3_PA2,GPIO_LOW);//set mmc0-clk to low. - rk30_mux_api_set(GPIO3A3_SDMMC0CMD_NAME, GPIO3A_GPIO3A3); - gpio_request(RK30_PIN3_PA3, "mmc0-cmd"); - gpio_direction_output(RK30_PIN3_PA3,GPIO_LOW);//set mmc0-cmd to low. - - rk30_mux_api_set(GPIO3A4_SDMMC0DATA0_NAME, GPIO3A_GPIO3A4); - gpio_request(RK30_PIN3_PA4, "mmc0-data0"); - gpio_direction_output(RK30_PIN3_PA4,GPIO_LOW);//set mmc0-data0 to low. - - rk30_mux_api_set(GPIO3A5_SDMMC0DATA1_NAME, GPIO3A_GPIO3A5); - gpio_request(RK30_PIN3_PA5, "mmc0-data1"); - gpio_direction_output(RK30_PIN3_PA5,GPIO_LOW);//set mmc0-data1 to low. - - rk30_mux_api_set(GPIO3A6_SDMMC0DATA2_NAME, GPIO3A_GPIO3A6); - gpio_request(RK30_PIN3_PA6, "mmc0-data2"); - gpio_direction_output(RK30_PIN3_PA6,GPIO_LOW);//set mmc0-data2 to low. - - rk30_mux_api_set(GPIO3A7_SDMMC0DATA3_NAME, GPIO3A_GPIO3A7); - gpio_request(RK30_PIN3_PA7, "mmc0-data3"); - gpio_direction_output(RK30_PIN3_PA7,GPIO_LOW);//set mmc0-data3 to low. - #endif mdelay(30); } #endif @@ -114,7 +81,6 @@ static void rk29_sdmmc_gpio_open(int device_id, int on) } else { - #if defined(CONFIG_ARCH_RK30) rk30_mux_api_set(GPIO3C5_SDMMC1CLKOUT_NAME, GPIO3C_GPIO3C5); gpio_request(RK30_PIN3_PC5, "mmc1-clk"); gpio_direction_output(RK30_PIN3_PC5,GPIO_LOW);//set mmc1-clk to low. @@ -126,19 +92,7 @@ static void rk29_sdmmc_gpio_open(int device_id, int on) rk30_mux_api_set(GPIO3C1_SDMMC1DATA0_NAME, GPIO3C_GPIO3C1); gpio_request(RK30_PIN3_PC1, "mmc1-data0"); gpio_direction_output(RK30_PIN3_PC1,GPIO_LOW);//set mmc1-data0 to low. - #elif defined(CONFIG_ARCH_RK31) - rk30_mux_api_set(GPIO3C5_SDMMC1CLKOUT_RMIICLKOUT_RMIICLKIN_NAME, GPIO3C_GPIO3C5); - gpio_request(RK30_PIN3_PC5, "mmc1-clk"); - gpio_direction_output(RK30_PIN3_PC5,GPIO_LOW);//set mmc1-clk to low. - rk30_mux_api_set(GPIO3C0_SDMMC1CMD_RMIITXEN_NAME, GPIO3C_GPIO3C0); - gpio_request(RK30_PIN3_PC0, "mmc1-cmd"); - gpio_direction_output(RK30_PIN3_PC0,GPIO_LOW);//set mmc1-cmd to low. - - rk30_mux_api_set(GPIO3C1_SDMMC1DATA0_RMIITXD1_NAME, GPIO3C_GPIO3C1); - gpio_request(RK30_PIN3_PC1, "mmc1-data0"); - gpio_direction_output(RK30_PIN3_PC1,GPIO_LOW);//set mmc1-data0 to low. - #endif mdelay(100); } #endif @@ -160,15 +114,9 @@ static void rk29_sdmmc_set_iomux_mmc0(unsigned int bus_width) case 1://SDMMC_CTYPE_4BIT: { - #if defined(CONFIG_ARCH_RK30) rk30_mux_api_set(GPIO3B3_SDMMC0DATA1_NAME, GPIO3B_SDMMC0_DATA1); rk30_mux_api_set(GPIO3B4_SDMMC0DATA2_NAME, GPIO3B_SDMMC0_DATA2); rk30_mux_api_set(GPIO3B5_SDMMC0DATA3_NAME, GPIO3B_SDMMC0_DATA3); - #elif defined(CONFIG_ARCH_RK31) - rk30_mux_api_set(GPIO3A5_SDMMC0DATA1_NAME, GPIO3A_SDMMC0DATA1); - rk30_mux_api_set(GPIO3A6_SDMMC0DATA2_NAME, GPIO3A_SDMMC0DATA2); - rk30_mux_api_set(GPIO3A7_SDMMC0DATA3_NAME, GPIO3A_SDMMC0DATA3); - #endif } break; @@ -176,7 +124,6 @@ static void rk29_sdmmc_set_iomux_mmc0(unsigned int bus_width) break; case 0xFFFF: //gpio_reset { - #if defined(CONFIG_ARCH_RK30) rk30_mux_api_set(GPIO3A7_SDMMC0PWREN_NAME, GPIO3A_GPIO3A7); gpio_request(RK30_PIN3_PA7,"sdmmc-power"); gpio_direction_output(RK30_PIN3_PA7,GPIO_HIGH); //power-off @@ -186,26 +133,14 @@ static void rk29_sdmmc_set_iomux_mmc0(unsigned int bus_width) gpio_direction_output(RK30_PIN3_PA7,GPIO_LOW); //power-on rk29_sdmmc_gpio_open(0, 1); - #elif defined(CONFIG_ARCH_RK31) - rk30_mux_api_set(GPIO3A1_SDMMC0PWREN_NAME, GPIO3A_GPIO3A1); - gpio_request(RK30_PIN3_PA1,"sdmmc-power"); - gpio_direction_output(RK30_PIN3_PA1,GPIO_HIGH); //power-off - - rk29_sdmmc_gpio_open(0, 0); - - gpio_direction_output(RK30_PIN3_PA1,GPIO_LOW); //power-on - - rk29_sdmmc_gpio_open(0, 1); - #endif } break; default: //case 0://SDMMC_CTYPE_1BIT: { - #if defined(CONFIG_ARCH_RK30) - rk30_mux_api_set(GPIO3B1_SDMMC0CMD_NAME, GPIO3B_SDMMC0_CMD); - rk30_mux_api_set(GPIO3B0_SDMMC0CLKOUT_NAME, GPIO3B_SDMMC0_CLKOUT); - rk30_mux_api_set(GPIO3B2_SDMMC0DATA0_NAME, GPIO3B_SDMMC0_DATA0); + rk30_mux_api_set(GPIO3B1_SDMMC0CMD_NAME, GPIO3B_SDMMC0_CMD); + rk30_mux_api_set(GPIO3B0_SDMMC0CLKOUT_NAME, GPIO3B_SDMMC0_CLKOUT); + rk30_mux_api_set(GPIO3B2_SDMMC0DATA0_NAME, GPIO3B_SDMMC0_DATA0); rk30_mux_api_set(GPIO3B3_SDMMC0DATA1_NAME, GPIO3B_GPIO3B3); gpio_request(RK30_PIN3_PB3, "mmc0-data1"); @@ -218,23 +153,6 @@ static void rk29_sdmmc_set_iomux_mmc0(unsigned int bus_width) rk30_mux_api_set(GPIO3B5_SDMMC0DATA3_NAME, GPIO3B_GPIO3B5); gpio_request(RK30_PIN3_PB5, "mmc0-data3"); gpio_direction_output(RK30_PIN3_PB5,GPIO_HIGH);//set mmc0-data3 to high. - #elif defined(CONFIG_ARCH_RK31) - rk30_mux_api_set(GPIO3A3_SDMMC0CMD_NAME, GPIO3A_SDMMC0CMD); - rk30_mux_api_set(GPIO3A2_SDMMC0CLKOUT_NAME, GPIO3A_SDMMC0CLKOUT); - rk30_mux_api_set(GPIO3A4_SDMMC0DATA0_NAME, GPIO3A_SDMMC0DATA0); - - rk30_mux_api_set(GPIO3A5_SDMMC0DATA1_NAME, GPIO3A_GPIO3A5); - gpio_request(RK30_PIN3_PA5, "mmc0-data1"); - gpio_direction_output(RK30_PIN3_PA5,GPIO_HIGH);//set mmc0-data1 to high. - - rk30_mux_api_set(GPIO3A6_SDMMC0DATA2_NAME, GPIO3A_GPIO3A6); - gpio_request(RK30_PIN3_PA5, "mmc0-data2"); - gpio_direction_output(RK30_PIN3_PA5,GPIO_HIGH);//set mmc0-data2 to high. - - rk30_mux_api_set(GPIO3A7_SDMMC0DATA3_NAME, GPIO3A_GPIO3A7); - gpio_request(RK30_PIN3_PA7, "mmc0-data3"); - gpio_direction_output(RK30_PIN3_PA7,GPIO_HIGH);//set mmc0-data3 to high. - #endif } break; } @@ -242,21 +160,12 @@ static void rk29_sdmmc_set_iomux_mmc0(unsigned int bus_width) static void rk29_sdmmc_set_iomux_mmc1(unsigned int bus_width) { -#if defined(CONFIG_ARCH_RK30) rk30_mux_api_set(GPIO3C0_SMMC1CMD_NAME, GPIO3C_SMMC1_CMD); rk30_mux_api_set(GPIO3C5_SDMMC1CLKOUT_NAME, GPIO3C_SDMMC1_CLKOUT); rk30_mux_api_set(GPIO3C1_SDMMC1DATA0_NAME, GPIO3C_SDMMC1_DATA0); rk30_mux_api_set(GPIO3C2_SDMMC1DATA1_NAME, GPIO3C_SDMMC1_DATA1); rk30_mux_api_set(GPIO3C3_SDMMC1DATA2_NAME, GPIO3C_SDMMC1_DATA2); rk30_mux_api_set(GPIO3C4_SDMMC1DATA3_NAME, GPIO3C_SDMMC1_DATA3); -#elif defined(CONFIG_ARCH_RK31) - rk30_mux_api_set(GPIO3C0_SDMMC1CMD_RMIITXEN_NAME, GPIO3C_SDMMC1CMD); - rk30_mux_api_set(GPIO3C5_SDMMC1CLKOUT_RMIICLKOUT_RMIICLKIN_NAME, GPIO3C_SDMMC1CLKOUT); - rk30_mux_api_set(GPIO3C1_SDMMC1DATA0_RMIITXD1_NAME, GPIO3C_SDMMC1DATA0); - rk30_mux_api_set(GPIO3C2_SDMMC1DATA1_RMIITXD0_NAME, GPIO3C_SDMMC1DATA1); - rk30_mux_api_set(GPIO3C3_SDMMC1DATA2_RMIIRXD0_NAME, GPIO3C_SDMMC1DATA2); - rk30_mux_api_set(GPIO3C4_SDMMC1DATA3_RMIIRXD1_NAME, GPIO3C_SDMMC1DATA3); -#endif } static void rk29_sdmmc_set_iomux_mmc2(unsigned int bus_width) diff --git a/arch/arm/mach-rk30/board-rk3066b-sdk-key.c b/arch/arm/mach-rk30/board-rk3066b-sdk-key.c new file mode 100644 index 000000000000..24c71eb9cb16 --- /dev/null +++ b/arch/arm/mach-rk30/board-rk3066b-sdk-key.c @@ -0,0 +1,65 @@ +#include +#include + +#define EV_ENCALL KEY_F4 +#define EV_MENU KEY_F1 + +#define PRESS_LEV_LOW 1 +#define PRESS_LEV_HIGH 0 + +static struct rk29_keys_button key_button[] = { + { + .desc = "vol-", + .code = KEY_VOLUMEDOWN, + .gpio = RK30_PIN0_PB5, + .active_low = PRESS_LEV_LOW, + }, + { + .desc = "play", + .code = KEY_POWER, + .gpio = RK30_PIN0_PA4, + .active_low = PRESS_LEV_LOW, + .wakeup = 1, + }, + { + .desc = "vol+", + .code = KEY_VOLUMEUP, + .adc_value = 1, + .gpio = INVALID_GPIO, + .active_low = PRESS_LEV_LOW, + }, + { + .desc = "menu", + .code = EV_MENU, + .adc_value = 155, + .gpio = INVALID_GPIO, + .active_low = PRESS_LEV_LOW, + }, + { + .desc = "home", + .code = KEY_HOME, + .adc_value = 630, + .gpio = INVALID_GPIO, + .active_low = PRESS_LEV_LOW, + }, + { + .desc = "esc", + .code = KEY_BACK, + .adc_value = 386, + .gpio = INVALID_GPIO, + .active_low = PRESS_LEV_LOW, + }, + { + .desc = "camera", + .code = KEY_CAMERA, + .adc_value = 827, + .gpio = INVALID_GPIO, + .active_low = PRESS_LEV_LOW, + }, +}; +struct rk29_keys_platform_data rk29_keys_pdata = { + .buttons = key_button, + .nbuttons = ARRAY_SIZE(key_button), + .chn = 1, //chn: 0-7, if do not use ADC,set 'chn' -1 +}; + diff --git a/arch/arm/mach-rk30/board-rk3066b-sdk-rfkill.c b/arch/arm/mach-rk30/board-rk3066b-sdk-rfkill.c new file mode 100644 index 000000000000..ccb50e49d526 --- /dev/null +++ b/arch/arm/mach-rk30/board-rk3066b-sdk-rfkill.c @@ -0,0 +1,449 @@ +/* + * Copyright (C) 2010 ROCKCHIP, Inc. + * Author: roger_chen + * + * This program is the bluetooth device bcm4329's driver, + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DBG(x...) printk(KERN_INFO "[BT_RFKILL]: "x) +#else +#define DBG(x...) +#endif + +#define LOG(x...) printk(KERN_INFO "[BT_RFKILL]: "x) + +#ifdef CONFIG_BCM4329 +#define WIFI_BT_POWER_TOGGLE 1 +#else +#define WIFI_BT_POWER_TOGGLE 0 +#endif + +#define BT_WAKE_LOCK_TIMEOUT 10 //s + +#define BT_AUTO_SLEEP_TIMEOUT 3 + +/* + * IO Configuration for RK29 + */ +#ifdef CONFIG_ARCH_RK29 + +#define BT_WAKE_HOST_SUPPORT 0 + +/* IO configuration */ +// BT power pin +#define BT_GPIO_POWER RK29_PIN5_PD6 +#define IOMUX_BT_GPIO_POWER() rk29_mux_api_set(GPIO5D6_SDMMC1PWREN_NAME, GPIO5H_GPIO5D6); + +// BT reset pin +#define BT_GPIO_RESET RK29_PIN6_PC4 +#define IOMUX_BT_GPIO_RESET() + +// BT wakeup pin +#define BT_GPIO_WAKE_UP RK29_PIN6_PC5 +#define IOMUX_BT_GPIO_WAKE_UP() + +// BT wakeup host pin +#define BT_GPIO_WAKE_UP_HOST +#define IOMUX_BT_GPIO_WAKE_UP_HOST() + +//bt cts paired to uart rts +#define UART_RTS RK29_PIN2_PA7 +#define IOMUX_UART_RTS_GPIO() rk29_mux_api_set(GPIO2A7_UART2RTSN_NAME, GPIO2L_GPIO2A7) +#define IOMUX_UART_RTS() rk29_mux_api_set(GPIO2A7_UART2RTSN_NAME, GPIO2L_UART2_RTS_N) + +/* + * IO Configuration for RK30 + */ +#elif defined (CONFIG_ARCH_RK31) + +#define BT_WAKE_HOST_SUPPORT 1 + +/* IO configuration */ +// BT power pin +#define BT_GPIO_POWER RK30_PIN3_PC6 +#define IOMUX_BT_GPIO_POWER() rk29_mux_api_set(GPIO3C6_SDMMC1DETECTN_RMIIRXERR_NAME, GPIO3C_GPIO3C6); + +// BT reset pin +#define BT_GPIO_RESET RK30_PIN3_PD0 +#define IOMUX_BT_GPIO_RESET() rk29_mux_api_set(GPIO3D0_SDMMC1PWREN_MIIMD_NAME, GPIO3D_GPIO3D0); + +// BT wakeup pin +#define BT_GPIO_WAKE_UP RK30_PIN3_PC5 +#define IOMUX_BT_GPIO_WAKE_UP() rk29_mux_api_set(GPIO3C5_SDMMC1CLKOUT_RMIICLKOUT_RMIICLKIN_NAME, GPIO3C_GPIO3C5); + +// BT wakeup host pin +#define BT_GPIO_WAKE_UP_HOST RK30_PIN0_PA5 +#define BT_IRQ_WAKE_UP_HOST gpio_to_irq(BT_GPIO_WAKE_UP_HOST) +#define IOMUX_BT_GPIO_WAKE_UP_HOST() + +//bt cts paired to uart rts +#define UART_RTS RK30_PIN1_PA3 +#define IOMUX_UART_RTS_GPIO() rk29_mux_api_set(GPIO1A3_UART0RTSN_NAME, GPIO1A_GPIO1A3) +#define IOMUX_UART_RTS() rk29_mux_api_set(GPIO1A3_UART0RTSN_NAME, GPIO1A_UART0RTSN) + +#endif + +struct bt_ctrl +{ + struct rfkill *bt_rfk; +#if BT_WAKE_HOST_SUPPORT + struct timer_list tl; + bool b_HostWake; + struct wake_lock bt_wakelock; +#endif +}; + +static const char bt_name[] = +#if defined(CONFIG_RKWIFI) + #if defined(CONFIG_RKWIFI_26M) + "rk903_26M" + #else + "rk903" + #endif +#elif defined(CONFIG_BCM4329) + "bcm4329" +#elif defined(CONFIG_MV8787) + "mv8787" +#else + "bt_default" +#endif +; + +#if WIFI_BT_POWER_TOGGLE +extern int rk29sdk_bt_power_state; +extern int rk29sdk_wifi_power_state; +#endif + +struct bt_ctrl gBtCtrl; +struct timer_list bt_sleep_tl; + +void bcm4325_sleep(unsigned long bSleep); + +#if BT_WAKE_HOST_SUPPORT +void resetBtHostSleepTimer(void) +{ + mod_timer(&(gBtCtrl.tl),jiffies + BT_WAKE_LOCK_TIMEOUT*HZ);//再重新设置超时值。 +} + +void btWakeupHostLock(void) +{ + if(gBtCtrl.b_HostWake == false){ + DBG("** Lock **\n"); + wake_lock(&(gBtCtrl.bt_wakelock)); + gBtCtrl.b_HostWake = true; + } +} + +void btWakeupHostUnlock(void) +{ + if(gBtCtrl.b_HostWake == true){ + DBG("** UnLock **\n"); + wake_unlock(&(gBtCtrl.bt_wakelock)); //让系统睡眠 + gBtCtrl.b_HostWake = false; + } +} + +static void timer_hostSleep(unsigned long arg) +{ + DBG("b_HostWake=%d\n", gBtCtrl.b_HostWake); + btWakeupHostUnlock(); +} + +#ifdef CONFIG_PM +static irqreturn_t bcm4329_wake_host_irq(int irq, void *dev) +{ + DBG("%s\n",__FUNCTION__); + + btWakeupHostLock(); + resetBtHostSleepTimer(); + return IRQ_HANDLED; +} + +static void rfkill_do_wakeup(struct work_struct *work) +{ + // disable bt wakeup host + DBG("** free irq\n"); + free_irq(BT_IRQ_WAKE_UP_HOST, NULL); + + DBG("Enable UART_RTS\n"); + gpio_set_value(UART_RTS, GPIO_LOW); + IOMUX_UART_RTS(); +} + +static DECLARE_DELAYED_WORK(wakeup_work, rfkill_do_wakeup); + +static int bcm4329_rfkill_suspend(struct platform_device *pdev, pm_message_t state) +{ + DBG("%s\n",__FUNCTION__); + + cancel_delayed_work(&wakeup_work); + +#ifdef CONFIG_BT_AUTOSLEEP + bcm4325_sleep(1); +#endif + + DBG("Disable UART_RTS\n"); + //To prevent uart to receive bt data when suspended + IOMUX_UART_RTS_GPIO(); + gpio_request(UART_RTS, "uart_rts"); + gpio_set_value(UART_RTS, GPIO_HIGH); + + // enable bt wakeup host + DBG("Request irq for bt wakeup host\n"); + if (0 == request_irq(BT_IRQ_WAKE_UP_HOST, + bcm4329_wake_host_irq, + IRQF_TRIGGER_FALLING, + "bt_wake", + NULL)) + enable_irq_wake(BT_IRQ_WAKE_UP_HOST); + else + LOG("Failed to request BT_WAKE_UP_HOST irq\n"); + +#ifdef CONFIG_RFKILL_RESET + extern void rfkill_set_block(struct rfkill *rfkill, bool blocked); + rfkill_set_block(gBtCtrl.bt_rfk, true); +#endif + + return 0; +} + +static int bcm4329_rfkill_resume(struct platform_device *pdev) +{ + DBG("%s\n",__FUNCTION__); + + // 系统退出二级睡眠后需要拉低RTS,从而才允许BT发数据过来 + // 但是目前发现在resume函数中直接拉低RTS会导致BT数据丢失 + // 所以延迟1s后再拉低RTS + // 系统退出二级睡眠时释放掉BT_IRQ_WAKE_UP_HOST,在睡眠时候再 + // 次申请,目前发现中断回调函数比resume更晚执行,如果resume + // 时直接free掉IRQ,会导致中断回调函数不会被执行, + DBG("delay 1s\n"); + schedule_delayed_work(&wakeup_work, HZ); + + return 0; +} +#else +#define bcm4329_rfkill_suspend NULL +#define bcm4329_rfkill_resume NULL +#endif + +#else +#ifdef CONFIG_PM +static int bcm4329_rfkill_suspend(struct platform_device *pdev, pm_message_t state) +{ +#ifdef CONFIG_BT_AUTOSLEEP + bcm4325_sleep(1); +#endif + return 0; +} +#else +#define bcm4329_rfkill_suspend NULL +#endif +#define bcm4329_rfkill_resume NULL +#endif + +void bcm4325_sleep(unsigned long bSleep) +{ + DBG("*** bt sleep: %d ***\n", bSleep); +#ifdef CONFIG_BT_AUTOSLEEP + del_timer(&bt_sleep_tl);// cmy: 确保在唤醒BT时,不会因触发bt_sleep_tl而马上睡眠 +#endif + + IOMUX_BT_GPIO_WAKE_UP(); + gpio_set_value(BT_GPIO_WAKE_UP, bSleep?GPIO_LOW:GPIO_HIGH); + +#ifdef CONFIG_BT_AUTOSLEEP + if(!bSleep) + mod_timer(&bt_sleep_tl, jiffies + BT_AUTO_SLEEP_TIMEOUT*HZ);//再重新设置超时值。 +#endif +} + +static int bcm4329_set_block(void *data, bool blocked) +{ + DBG("set blocked :%d\n", blocked); + + IOMUX_BT_GPIO_POWER(); + IOMUX_BT_GPIO_RESET(); + + if (false == blocked) { + gpio_set_value(BT_GPIO_POWER, GPIO_HIGH); /* bt power on */ + mdelay(20); + + gpio_set_value(BT_GPIO_RESET, GPIO_LOW); + mdelay(20); + gpio_set_value(BT_GPIO_RESET, GPIO_HIGH); /* bt reset deactive*/ + + mdelay(20); + bcm4325_sleep(0); // ensure bt is wakeup + + pr_info("bt turn on power\n"); + } else { +#if WIFI_BT_POWER_TOGGLE + if (!rk29sdk_wifi_power_state) { +#endif + gpio_set_value(BT_GPIO_POWER, GPIO_LOW); /* bt power off */ + mdelay(20); + pr_info("bt shut off power\n"); +#if WIFI_BT_POWER_TOGGLE + }else { + pr_info("bt shouldn't shut off power, wifi is using it!\n"); + } +#endif + + gpio_set_value(BT_GPIO_RESET, GPIO_LOW); /* bt reset active*/ + mdelay(20); + } + +#if WIFI_BT_POWER_TOGGLE + rk29sdk_bt_power_state = !blocked; +#endif + return 0; +} + +static const struct rfkill_ops bcm4329_rfk_ops = { + .set_block = bcm4329_set_block, +}; + +static int __devinit bcm4329_rfkill_probe(struct platform_device *pdev) +{ + int rc = 0; + bool default_state = true; + + DBG("Enter %s\n",__FUNCTION__); + + /* default to bluetooth off */ + bcm4329_set_block(NULL, default_state); /* blocked -> bt off */ + + gBtCtrl.bt_rfk = rfkill_alloc(bt_name, + NULL, + RFKILL_TYPE_BLUETOOTH, + &bcm4329_rfk_ops, + NULL); + + if (!gBtCtrl.bt_rfk) + { + LOG("fail to rfkill_allocate\n"); + return -ENOMEM; + } + + rfkill_set_states(gBtCtrl.bt_rfk, default_state, false); + + rc = rfkill_register(gBtCtrl.bt_rfk); + if (rc) + { + LOG("failed to rfkill_register,rc=0x%x\n",rc); + rfkill_destroy(gBtCtrl.bt_rfk); + } + + gpio_request(BT_GPIO_POWER, NULL); + gpio_request(BT_GPIO_RESET, NULL); + gpio_request(BT_GPIO_WAKE_UP, NULL); + +#ifdef CONFIG_BT_AUTOSLEEP + init_timer(&bt_sleep_tl); + bt_sleep_tl.expires = 0; + bt_sleep_tl.function = bcm4325_sleep; + bt_sleep_tl.data = 1; + add_timer(&bt_sleep_tl); +#endif + +#if BT_WAKE_HOST_SUPPORT + init_timer(&(gBtCtrl.tl)); + gBtCtrl.tl.expires = 0; + gBtCtrl.tl.function = timer_hostSleep; + add_timer(&(gBtCtrl.tl)); + gBtCtrl.b_HostWake = false; + + wake_lock_init(&(gBtCtrl.bt_wakelock), WAKE_LOCK_SUSPEND, "bt_wake"); + + rc = gpio_request(BT_GPIO_WAKE_UP_HOST, "bt_wake"); + if (rc) { + LOG("Failed to request BT_WAKE_UP_HOST\n"); + } + + IOMUX_BT_GPIO_WAKE_UP_HOST(); + gpio_pull_updown(BT_GPIO_WAKE_UP_HOST,GPIOPullUp); + #endif + + LOG("bcm4329 module has been initialized,rc=0x%x\n",rc); + + return rc; +} + + +static int __devexit bcm4329_rfkill_remove(struct platform_device *pdev) +{ + if (gBtCtrl.bt_rfk) + rfkill_unregister(gBtCtrl.bt_rfk); + gBtCtrl.bt_rfk = NULL; +#if BT_WAKE_HOST_SUPPORT + del_timer(&(gBtCtrl.tl));//删掉定时器 + btWakeupHostUnlock(); + wake_lock_destroy(&(gBtCtrl.bt_wakelock)); +#endif +#ifdef CONFIG_BT_AUTOSLEEP + del_timer(&bt_sleep_tl); +#endif + + platform_set_drvdata(pdev, NULL); + + DBG("Enter %s\n",__FUNCTION__); + return 0; +} + +static struct platform_driver bcm4329_rfkill_driver = { + .probe = bcm4329_rfkill_probe, + .remove = __devexit_p(bcm4329_rfkill_remove), + .driver = { + .name = "rk29sdk_rfkill", + .owner = THIS_MODULE, + }, + .suspend = bcm4329_rfkill_suspend, + .resume = bcm4329_rfkill_resume, +}; + +/* + * Module initialization + */ +static int __init bcm4329_mod_init(void) +{ + int ret; + DBG("Enter %s\n",__FUNCTION__); + ret = platform_driver_register(&bcm4329_rfkill_driver); + LOG("ret=0x%x\n", ret); + return ret; +} + +static void __exit bcm4329_mod_exit(void) +{ + platform_driver_unregister(&bcm4329_rfkill_driver); +} + +module_init(bcm4329_mod_init); +module_exit(bcm4329_mod_exit); +MODULE_DESCRIPTION("bcm4329 Bluetooth driver"); +MODULE_AUTHOR("roger_chen cz@rock-chips.com, cmy@rock-chips.com"); +MODULE_LICENSE("GPL"); + diff --git a/arch/arm/mach-rk30/board-rk3066b-sdk-sdmmc.c b/arch/arm/mach-rk30/board-rk3066b-sdk-sdmmc.c new file mode 100644 index 000000000000..d444e52d411b --- /dev/null +++ b/arch/arm/mach-rk30/board-rk3066b-sdk-sdmmc.c @@ -0,0 +1,532 @@ +/* arch/arm/mach-rk30/board-rk30-sdk-sdmmc.c + * + * Copyright (C) 2012 ROCKCHIP, Inc. + * + * 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. + * + */ + +#ifdef CONFIG_SDMMC_RK29 + +#if !defined(CONFIG_SDMMC_RK29_OLD) +static void rk29_sdmmc_gpio_open(int device_id, int on) +{ + switch(device_id) + { + case 0://mmc0 + { + #ifdef CONFIG_SDMMC0_RK29 + if(on) + { + #if defined(CONFIG_ARCH_RK30) + gpio_direction_output(GPIO3B_GPIO3B0,GPIO_HIGH);//set mmc0-clk to high + gpio_direction_output(GPIO3B_GPIO3B1,GPIO_HIGH);// set mmc0-cmd to high. + gpio_direction_output(GPIO3B_GPIO3B2,GPIO_HIGH);//set mmc0-data0 to high. + gpio_direction_output(GPIO3B_GPIO3B3,GPIO_HIGH);//set mmc0-data1 to high. + gpio_direction_output(GPIO3B_GPIO3B4,GPIO_HIGH);//set mmc0-data2 to high. + gpio_direction_output(GPIO3B_GPIO3B5,GPIO_HIGH);//set mmc0-data3 to high. + #elif defined(CONFIG_ARCH_RK31) + gpio_direction_output(RK30_PIN3_PA2,GPIO_HIGH);//set mmc0-clk to high + gpio_direction_output(RK30_PIN3_PA3,GPIO_HIGH);// set mmc0-cmd to high. + gpio_direction_output(RK30_PIN3_PA4,GPIO_HIGH);//set mmc0-data0 to high. + gpio_direction_output(RK30_PIN3_PA5,GPIO_HIGH);//set mmc0-data1 to high. + gpio_direction_output(RK30_PIN3_PA6,GPIO_HIGH);//set mmc0-data2 to high. + gpio_direction_output(RK30_PIN3_PA7,GPIO_HIGH);//set mmc0-data3 to high. + #endif + mdelay(30); + } + else + { + #if defined(CONFIG_ARCH_RK30) + rk30_mux_api_set(GPIO3B0_SDMMC0CLKOUT_NAME, GPIO3B_GPIO3B0); + gpio_request(RK30_PIN3_PB0, "mmc0-clk"); + gpio_direction_output(RK30_PIN3_PB0,GPIO_LOW);//set mmc0-clk to low. + + rk30_mux_api_set(GPIO3B1_SDMMC0CMD_NAME, GPIO3B_GPIO3B1); + gpio_request(RK30_PIN3_PB1, "mmc0-cmd"); + gpio_direction_output(RK30_PIN3_PB1,GPIO_LOW);//set mmc0-cmd to low. + + rk30_mux_api_set(GPIO3B2_SDMMC0DATA0_NAME, GPIO3B_GPIO3B2); + gpio_request(RK30_PIN3_PB2, "mmc0-data0"); + gpio_direction_output(RK30_PIN3_PB2,GPIO_LOW);//set mmc0-data0 to low. + + rk30_mux_api_set(GPIO3B3_SDMMC0DATA1_NAME, GPIO3B_GPIO3B3); + gpio_request(RK30_PIN3_PB3, "mmc0-data1"); + gpio_direction_output(RK30_PIN3_PB3,GPIO_LOW);//set mmc0-data1 to low. + + rk30_mux_api_set(GPIO3B4_SDMMC0DATA2_NAME, GPIO3B_GPIO3B4); + gpio_request(RK30_PIN3_PB4, "mmc0-data2"); + gpio_direction_output(RK30_PIN3_PB4,GPIO_LOW);//set mmc0-data2 to low. + + rk30_mux_api_set(GPIO3B5_SDMMC0DATA3_NAME, GPIO3B_GPIO3B5); + gpio_request(RK30_PIN3_PB5, "mmc0-data3"); + gpio_direction_output(RK30_PIN3_PB5,GPIO_LOW);//set mmc0-data3 to low. + #elif defined(CONFIG_ARCH_RK31) + rk30_mux_api_set(GPIO3A2_SDMMC0CLKOUT_NAME, GPIO3A_GPIO3A2); + gpio_request(RK30_PIN3_PA2, "mmc0-clk"); + gpio_direction_output(RK30_PIN3_PA2,GPIO_LOW);//set mmc0-clk to low. + + rk30_mux_api_set(GPIO3A3_SDMMC0CMD_NAME, GPIO3A_GPIO3A3); + gpio_request(RK30_PIN3_PA3, "mmc0-cmd"); + gpio_direction_output(RK30_PIN3_PA3,GPIO_LOW);//set mmc0-cmd to low. + + rk30_mux_api_set(GPIO3A4_SDMMC0DATA0_NAME, GPIO3A_GPIO3A4); + gpio_request(RK30_PIN3_PA4, "mmc0-data0"); + gpio_direction_output(RK30_PIN3_PA4,GPIO_LOW);//set mmc0-data0 to low. + + rk30_mux_api_set(GPIO3A5_SDMMC0DATA1_NAME, GPIO3A_GPIO3A5); + gpio_request(RK30_PIN3_PA5, "mmc0-data1"); + gpio_direction_output(RK30_PIN3_PA5,GPIO_LOW);//set mmc0-data1 to low. + + rk30_mux_api_set(GPIO3A6_SDMMC0DATA2_NAME, GPIO3A_GPIO3A6); + gpio_request(RK30_PIN3_PA6, "mmc0-data2"); + gpio_direction_output(RK30_PIN3_PA6,GPIO_LOW);//set mmc0-data2 to low. + + rk30_mux_api_set(GPIO3A7_SDMMC0DATA3_NAME, GPIO3A_GPIO3A7); + gpio_request(RK30_PIN3_PA7, "mmc0-data3"); + gpio_direction_output(RK30_PIN3_PA7,GPIO_LOW);//set mmc0-data3 to low. + #endif + mdelay(30); + } + #endif + } + break; + + case 1://mmc1 + { + #ifdef CONFIG_SDMMC1_RK29 + if(on) + { + gpio_direction_output(RK30_PIN3_PC5,GPIO_HIGH);//set mmc1-clk to high + gpio_direction_output(RK30_PIN3_PC0,GPIO_HIGH);//set mmc1-cmd to high. + gpio_direction_output(RK30_PIN3_PC1,GPIO_HIGH);//set mmc1-data0 to high. + gpio_direction_output(RK30_PIN3_PC2,GPIO_HIGH);//set mmc1-data1 to high. + gpio_direction_output(RK30_PIN3_PC3,GPIO_HIGH);//set mmc1-data2 to high. + gpio_direction_output(RK30_PIN3_PC5,GPIO_HIGH);//set mmc1-data3 to high. + mdelay(100); + } + else + { + #if defined(CONFIG_ARCH_RK30) + rk30_mux_api_set(GPIO3C5_SDMMC1CLKOUT_NAME, GPIO3C_GPIO3C5); + gpio_request(RK30_PIN3_PC5, "mmc1-clk"); + gpio_direction_output(RK30_PIN3_PC5,GPIO_LOW);//set mmc1-clk to low. + + rk30_mux_api_set(GPIO3C0_SMMC1CMD_NAME, GPIO3C_GPIO3C0); + gpio_request(RK30_PIN3_PC0, "mmc1-cmd"); + gpio_direction_output(RK30_PIN3_PC0,GPIO_LOW);//set mmc1-cmd to low. + + rk30_mux_api_set(GPIO3C1_SDMMC1DATA0_NAME, GPIO3C_GPIO3C1); + gpio_request(RK30_PIN3_PC1, "mmc1-data0"); + gpio_direction_output(RK30_PIN3_PC1,GPIO_LOW);//set mmc1-data0 to low. + #elif defined(CONFIG_ARCH_RK31) + rk30_mux_api_set(GPIO3C5_SDMMC1CLKOUT_RMIICLKOUT_RMIICLKIN_NAME, GPIO3C_GPIO3C5); + gpio_request(RK30_PIN3_PC5, "mmc1-clk"); + gpio_direction_output(RK30_PIN3_PC5,GPIO_LOW);//set mmc1-clk to low. + + rk30_mux_api_set(GPIO3C0_SDMMC1CMD_RMIITXEN_NAME, GPIO3C_GPIO3C0); + gpio_request(RK30_PIN3_PC0, "mmc1-cmd"); + gpio_direction_output(RK30_PIN3_PC0,GPIO_LOW);//set mmc1-cmd to low. + + rk30_mux_api_set(GPIO3C1_SDMMC1DATA0_RMIITXD1_NAME, GPIO3C_GPIO3C1); + gpio_request(RK30_PIN3_PC1, "mmc1-data0"); + gpio_direction_output(RK30_PIN3_PC1,GPIO_LOW);//set mmc1-data0 to low. + #endif + mdelay(100); + } + #endif + } + break; + + case 2: //mmc2 + break; + + default: + break; + } +} + +static void rk29_sdmmc_set_iomux_mmc0(unsigned int bus_width) +{ + switch (bus_width) + { + + case 1://SDMMC_CTYPE_4BIT: + { + #if defined(CONFIG_ARCH_RK30) + rk30_mux_api_set(GPIO3B3_SDMMC0DATA1_NAME, GPIO3B_SDMMC0_DATA1); + rk30_mux_api_set(GPIO3B4_SDMMC0DATA2_NAME, GPIO3B_SDMMC0_DATA2); + rk30_mux_api_set(GPIO3B5_SDMMC0DATA3_NAME, GPIO3B_SDMMC0_DATA3); + #elif defined(CONFIG_ARCH_RK31) + rk30_mux_api_set(GPIO3A5_SDMMC0DATA1_NAME, GPIO3A_SDMMC0DATA1); + rk30_mux_api_set(GPIO3A6_SDMMC0DATA2_NAME, GPIO3A_SDMMC0DATA2); + rk30_mux_api_set(GPIO3A7_SDMMC0DATA3_NAME, GPIO3A_SDMMC0DATA3); + #endif + } + break; + + case 0x10000://SDMMC_CTYPE_8BIT: + break; + case 0xFFFF: //gpio_reset + { + #if defined(CONFIG_ARCH_RK30) + rk30_mux_api_set(GPIO3A7_SDMMC0PWREN_NAME, GPIO3A_GPIO3A7); + gpio_request(RK30_PIN3_PA7,"sdmmc-power"); + gpio_direction_output(RK30_PIN3_PA7,GPIO_HIGH); //power-off + + rk29_sdmmc_gpio_open(0, 0); + + gpio_direction_output(RK30_PIN3_PA7,GPIO_LOW); //power-on + + rk29_sdmmc_gpio_open(0, 1); + #elif defined(CONFIG_ARCH_RK31) + rk30_mux_api_set(GPIO3A1_SDMMC0PWREN_NAME, GPIO3A_GPIO3A1); + gpio_request(RK30_PIN3_PA1,"sdmmc-power"); + gpio_direction_output(RK30_PIN3_PA1,GPIO_HIGH); //power-off + + rk29_sdmmc_gpio_open(0, 0); + + gpio_direction_output(RK30_PIN3_PA1,GPIO_LOW); //power-on + + rk29_sdmmc_gpio_open(0, 1); + #endif + } + break; + + default: //case 0://SDMMC_CTYPE_1BIT: + { + #if defined(CONFIG_ARCH_RK30) + rk30_mux_api_set(GPIO3B1_SDMMC0CMD_NAME, GPIO3B_SDMMC0_CMD); + rk30_mux_api_set(GPIO3B0_SDMMC0CLKOUT_NAME, GPIO3B_SDMMC0_CLKOUT); + rk30_mux_api_set(GPIO3B2_SDMMC0DATA0_NAME, GPIO3B_SDMMC0_DATA0); + + rk30_mux_api_set(GPIO3B3_SDMMC0DATA1_NAME, GPIO3B_GPIO3B3); + gpio_request(RK30_PIN3_PB3, "mmc0-data1"); + gpio_direction_output(RK30_PIN3_PB3,GPIO_HIGH);//set mmc0-data1 to high. + + rk30_mux_api_set(GPIO3B4_SDMMC0DATA2_NAME, GPIO3B_GPIO3B4); + gpio_request(RK30_PIN3_PB4, "mmc0-data2"); + gpio_direction_output(RK30_PIN3_PB4,GPIO_HIGH);//set mmc0-data2 to high. + + rk30_mux_api_set(GPIO3B5_SDMMC0DATA3_NAME, GPIO3B_GPIO3B5); + gpio_request(RK30_PIN3_PB5, "mmc0-data3"); + gpio_direction_output(RK30_PIN3_PB5,GPIO_HIGH);//set mmc0-data3 to high. + #elif defined(CONFIG_ARCH_RK31) + rk30_mux_api_set(GPIO3A3_SDMMC0CMD_NAME, GPIO3A_SDMMC0CMD); + rk30_mux_api_set(GPIO3A2_SDMMC0CLKOUT_NAME, GPIO3A_SDMMC0CLKOUT); + rk30_mux_api_set(GPIO3A4_SDMMC0DATA0_NAME, GPIO3A_SDMMC0DATA0); + + rk30_mux_api_set(GPIO3A5_SDMMC0DATA1_NAME, GPIO3A_GPIO3A5); + gpio_request(RK30_PIN3_PA5, "mmc0-data1"); + gpio_direction_output(RK30_PIN3_PA5,GPIO_HIGH);//set mmc0-data1 to high. + + rk30_mux_api_set(GPIO3A6_SDMMC0DATA2_NAME, GPIO3A_GPIO3A6); + gpio_request(RK30_PIN3_PA5, "mmc0-data2"); + gpio_direction_output(RK30_PIN3_PA5,GPIO_HIGH);//set mmc0-data2 to high. + + rk30_mux_api_set(GPIO3A7_SDMMC0DATA3_NAME, GPIO3A_GPIO3A7); + gpio_request(RK30_PIN3_PA7, "mmc0-data3"); + gpio_direction_output(RK30_PIN3_PA7,GPIO_HIGH);//set mmc0-data3 to high. + #endif + } + break; + } +} + +static void rk29_sdmmc_set_iomux_mmc1(unsigned int bus_width) +{ +#if defined(CONFIG_ARCH_RK30) + rk30_mux_api_set(GPIO3C0_SMMC1CMD_NAME, GPIO3C_SMMC1_CMD); + rk30_mux_api_set(GPIO3C5_SDMMC1CLKOUT_NAME, GPIO3C_SDMMC1_CLKOUT); + rk30_mux_api_set(GPIO3C1_SDMMC1DATA0_NAME, GPIO3C_SDMMC1_DATA0); + rk30_mux_api_set(GPIO3C2_SDMMC1DATA1_NAME, GPIO3C_SDMMC1_DATA1); + rk30_mux_api_set(GPIO3C3_SDMMC1DATA2_NAME, GPIO3C_SDMMC1_DATA2); + rk30_mux_api_set(GPIO3C4_SDMMC1DATA3_NAME, GPIO3C_SDMMC1_DATA3); +#elif defined(CONFIG_ARCH_RK31) + rk30_mux_api_set(GPIO3C0_SDMMC1CMD_RMIITXEN_NAME, GPIO3C_SDMMC1CMD); + rk30_mux_api_set(GPIO3C5_SDMMC1CLKOUT_RMIICLKOUT_RMIICLKIN_NAME, GPIO3C_SDMMC1CLKOUT); + rk30_mux_api_set(GPIO3C1_SDMMC1DATA0_RMIITXD1_NAME, GPIO3C_SDMMC1DATA0); + rk30_mux_api_set(GPIO3C2_SDMMC1DATA1_RMIITXD0_NAME, GPIO3C_SDMMC1DATA1); + rk30_mux_api_set(GPIO3C3_SDMMC1DATA2_RMIIRXD0_NAME, GPIO3C_SDMMC1DATA2); + rk30_mux_api_set(GPIO3C4_SDMMC1DATA3_RMIIRXD1_NAME, GPIO3C_SDMMC1DATA3); +#endif +} + +static void rk29_sdmmc_set_iomux_mmc2(unsigned int bus_width) +{ + ;// +} + +static void rk29_sdmmc_set_iomux(int device_id, unsigned int bus_width) +{ + switch(device_id) + { + case 0: + #ifdef CONFIG_SDMMC0_RK29 + rk29_sdmmc_set_iomux_mmc0(bus_width); + #endif + break; + case 1: + #ifdef CONFIG_SDMMC1_RK29 + rk29_sdmmc_set_iomux_mmc1(bus_width); + #endif + break; + case 2: + rk29_sdmmc_set_iomux_mmc2(bus_width); + break; + default: + break; + } +} + +#endif + + +//int rk29sdk_wifi_power_state = 0; +//int rk29sdk_bt_power_state = 0; + +#ifdef CONFIG_WIFI_CONTROL_FUNC +//#define RK29SDK_WIFI_BT_GPIO_POWER_N RK30_PIN3_PD0 +//#define RK29SDK_WIFI_GPIO_RESET_N RK30_PIN3_PD0 +//#define RK29SDK_BT_GPIO_RESET_N RK30_PIN3_PD1 +#define RK30SDK_WIFI_GPIO_POWER_N RK30_PIN3_PC7 +//#define RK30SDK_BT_GPIO_POWER_N RK30_PIN3_PD1 + +#define PREALLOC_WLAN_SEC_NUM 4 +#define PREALLOC_WLAN_BUF_NUM 160 +#define PREALLOC_WLAN_SECTION_HEADER 24 + +#define WLAN_SECTION_SIZE_0 (PREALLOC_WLAN_BUF_NUM * 128) +#define WLAN_SECTION_SIZE_1 (PREALLOC_WLAN_BUF_NUM * 128) +#define WLAN_SECTION_SIZE_2 (PREALLOC_WLAN_BUF_NUM * 512) +#define WLAN_SECTION_SIZE_3 (PREALLOC_WLAN_BUF_NUM * 1024) + +#define WLAN_SKB_BUF_NUM 16 + +static struct sk_buff *wlan_static_skb[WLAN_SKB_BUF_NUM]; + +struct wifi_mem_prealloc { + void *mem_ptr; + unsigned long size; +}; + +static struct wifi_mem_prealloc wifi_mem_array[PREALLOC_WLAN_SEC_NUM] = { + {NULL, (WLAN_SECTION_SIZE_0 + PREALLOC_WLAN_SECTION_HEADER)}, + {NULL, (WLAN_SECTION_SIZE_1 + PREALLOC_WLAN_SECTION_HEADER)}, + {NULL, (WLAN_SECTION_SIZE_2 + PREALLOC_WLAN_SECTION_HEADER)}, + {NULL, (WLAN_SECTION_SIZE_3 + PREALLOC_WLAN_SECTION_HEADER)} +}; + +static void *rk29sdk_mem_prealloc(int section, unsigned long size) +{ + if (section == PREALLOC_WLAN_SEC_NUM) + return wlan_static_skb; + + if ((section < 0) || (section > PREALLOC_WLAN_SEC_NUM)) + return NULL; + + if (wifi_mem_array[section].size < size) + return NULL; + + return wifi_mem_array[section].mem_ptr; +} + +static int __init rk29sdk_init_wifi_mem(void) +{ + int i; + int j; + + for (i = 0 ; i < WLAN_SKB_BUF_NUM ; i++) { + wlan_static_skb[i] = dev_alloc_skb( + ((i < (WLAN_SKB_BUF_NUM / 2)) ? 4096 : 8192)); + + if (!wlan_static_skb[i]) + goto err_skb_alloc; + } + + for (i = 0 ; i < PREALLOC_WLAN_SEC_NUM ; i++) { + wifi_mem_array[i].mem_ptr = + kmalloc(wifi_mem_array[i].size, GFP_KERNEL); + + if (!wifi_mem_array[i].mem_ptr) + goto err_mem_alloc; + } + return 0; + +err_mem_alloc: + pr_err("Failed to mem_alloc for WLAN\n"); + for (j = 0 ; j < i ; j++) + kfree(wifi_mem_array[j].mem_ptr); + + i = WLAN_SKB_BUF_NUM; + +err_skb_alloc: + pr_err("Failed to skb_alloc for WLAN\n"); + for (j = 0 ; j < i ; j++) + dev_kfree_skb(wlan_static_skb[j]); + + return -ENOMEM; +} + +static int rk29sdk_wifi_cd = 0; /* wifi virtual 'card detect' status */ +static void (*wifi_status_cb)(int card_present, void *dev_id); +static void *wifi_status_cb_devid; + +static int rk29sdk_wifi_status(struct device *dev) +{ + return rk29sdk_wifi_cd; +} + +static int rk29sdk_wifi_status_register(void (*callback)(int card_present, void *dev_id), void *dev_id) +{ + if(wifi_status_cb) + return -EAGAIN; + wifi_status_cb = callback; + wifi_status_cb_devid = dev_id; + return 0; +} + +static int __init rk29sdk_wifi_bt_gpio_control_init(void) +{ + rk29sdk_init_wifi_mem(); + + rk29_mux_api_set(GPIO3D0_SDMMC1PWREN_NAME, GPIO3D_GPIO3D0); + + if (gpio_request(RK30SDK_WIFI_GPIO_POWER_N, "wifi_power")) { + pr_info("%s: request wifi power gpio failed\n", __func__); + return -1; + } + + /*if (gpio_request(RK29SDK_WIFI_GPIO_RESET_N, "wifi reset")) { + pr_info("%s: request wifi reset gpio failed\n", __func__); + gpio_free(RK30SDK_WIFI_GPIO_POWER_N); + return -1; + } + + if (gpio_request(RK29SDK_BT_GPIO_RESET_N, "bt reset")) { + pr_info("%s: request bt reset gpio failed\n", __func__); + gpio_free(RK29SDK_WIFI_GPIO_RESET_N); + return -1; + }*/ + + gpio_direction_output(RK30SDK_WIFI_GPIO_POWER_N, GPIO_LOW); + //gpio_direction_output(RK29SDK_WIFI_GPIO_RESET_N, GPIO_LOW); + //gpio_direction_output(RK29SDK_BT_GPIO_RESET_N, GPIO_LOW); + + #if defined(CONFIG_SDMMC1_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + + rk29_mux_api_set(GPIO3C2_SDMMC1DATA1_NAME, GPIO3C_GPIO3C2); + gpio_request(RK30_PIN3_PC2, "mmc1-data1"); + gpio_direction_output(RK30_PIN3_PC2,GPIO_LOW);//set mmc1-data1 to low. + + rk29_mux_api_set(GPIO3C3_SDMMC1DATA2_NAME, GPIO3C_GPIO3C3); + gpio_request(RK30_PIN3_PC3, "mmc1-data2"); + gpio_direction_output(RK30_PIN3_PC3,GPIO_LOW);//set mmc1-data2 to low. + + rk29_mux_api_set(GPIO3C4_SDMMC1DATA3_NAME, GPIO3C_GPIO3C4); + gpio_request(RK30_PIN3_PC4, "mmc1-data3"); + gpio_direction_output(RK30_PIN3_PC4,GPIO_LOW);//set mmc1-data3 to low. + + rk29_sdmmc_gpio_open(1, 0); //added by xbw at 2011-10-13 + #endif + pr_info("%s: init finished\n",__func__); + + return 0; +} + +static int rk29sdk_wifi_power(int on) +{ + pr_info("%s: %d\n", __func__, on); + if (on){ + gpio_set_value(RK30SDK_WIFI_GPIO_POWER_N, GPIO_HIGH); + + #if defined(CONFIG_SDMMC1_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + rk29_sdmmc_gpio_open(1, 1); //added by xbw at 2011-10-13 + #endif + + //gpio_set_value(RK29SDK_WIFI_GPIO_RESET_N, GPIO_HIGH); + mdelay(100); + pr_info("wifi turn on power\n"); + }else{ +// if (!rk29sdk_bt_power_state){ + gpio_set_value(RK30SDK_WIFI_GPIO_POWER_N, GPIO_LOW); + + #if defined(CONFIG_SDMMC1_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) + rk29_sdmmc_gpio_open(1, 0); //added by xbw at 2011-10-13 + #endif + + mdelay(100); + pr_info("wifi shut off power\n"); +// }else +// { +// pr_info("wifi shouldn't shut off power, bt is using it!\n"); +// } + //gpio_set_value(RK29SDK_WIFI_GPIO_RESET_N, GPIO_LOW); + + } + +// rk29sdk_wifi_power_state = on; + return 0; +} + +static int rk29sdk_wifi_reset_state; +static int rk29sdk_wifi_reset(int on) +{ + pr_info("%s: %d\n", __func__, on); + //gpio_set_value(RK29SDK_WIFI_GPIO_RESET_N, on); + //mdelay(100); + rk29sdk_wifi_reset_state = on; + return 0; +} + +int rk29sdk_wifi_set_carddetect(int val) +{ + pr_info("%s:%d\n", __func__, val); + rk29sdk_wifi_cd = val; + if (wifi_status_cb){ + wifi_status_cb(val, wifi_status_cb_devid); + }else { + pr_warning("%s, nobody to notify\n", __func__); + } + return 0; +} +EXPORT_SYMBOL(rk29sdk_wifi_set_carddetect); + +#define WIFI_HOST_WAKE RK30_PIN3_PD2 + +static struct resource resources[] = { + { + .start = WIFI_HOST_WAKE, + .flags = IORESOURCE_IRQ, + .name = "bcmdhd_wlan_irq", + }, +}; + +static struct wifi_platform_data rk29sdk_wifi_control = { + .set_power = rk29sdk_wifi_power, + .set_reset = rk29sdk_wifi_reset, + .set_carddetect = rk29sdk_wifi_set_carddetect, + .mem_prealloc = rk29sdk_mem_prealloc, +}; + +static struct platform_device rk29sdk_wifi_device = { + .name = "bcmdhd_wlan", + .id = 1, + .num_resources = ARRAY_SIZE(resources), + .resource = resources, + .dev = { + .platform_data = &rk29sdk_wifi_control, + }, +}; +#endif + + +#endif // endif --#ifdef CONFIG_SDMMC_RK29 + diff --git a/arch/arm/mach-rk30/board-rk3066b-sdk-wm8326.c b/arch/arm/mach-rk30/board-rk3066b-sdk-wm8326.c new file mode 100644 index 000000000000..bd79715161c0 --- /dev/null +++ b/arch/arm/mach-rk30/board-rk3066b-sdk-wm8326.c @@ -0,0 +1,842 @@ +#include +#include +#include +#include +#include + +#include + +#define cru_readl(offset) readl_relaxed(RK30_CRU_BASE + offset) +#define cru_writel(v, offset) do { writel_relaxed(v, RK30_CRU_BASE + offset); dsb(); } while (0) + +#define grf_readl(offset) readl_relaxed(RK30_GRF_BASE + offset) +#define grf_writel(v, offset) do { writel_relaxed(v, RK30_GRF_BASE + offset); dsb(); } while (0) + +#define CRU_CLKGATE5_CON_ADDR 0x00e4 +#define GRF_GPIO6L_DIR_ADDR 0x0030 +#define GRF_GPIO6L_DO_ADDR 0x0068 +#define GRF_GPIO6L_EN_ADDR 0x00a0 +#define CRU_CLKGATE5_GRFCLK_ON 0x00100000 +#define CRU_CLKGATE5_GRFCLK_OFF 0x00100010 +#define GPIO6_PB1_DIR_OUT 0x02000200 +#define GPIO6_PB1_DO_LOW 0x02000000 +#define GPIO6_PB1_DO_HIGH 0x02000200 +#define GPIO6_PB1_EN_MASK 0x02000200 +#define GPIO6_PB1_UNEN_MASK 0x02000000 + +/* wm8326 pmu*/ +#if defined(CONFIG_GPIO_WM831X) +static struct rk29_gpio_expander_info wm831x_gpio_settinginfo[] = { + { + .gpio_num = WM831X_P01, // tp3 + .pin_type = GPIO_OUT, + .pin_value = GPIO_LOW, + }, + { + .gpio_num = WM831X_P02, //tp4 + .pin_type = GPIO_IN, + }, + { + .gpio_num = WM831X_P03, //tp2 + .pin_type = GPIO_OUT, + .pin_value = GPIO_HIGH, + }, + { + .gpio_num = WM831X_P04, //tp1 + .pin_type = GPIO_IN, + }, + { + .gpio_num = WM831X_P05, //tp1 + .pin_type = GPIO_IN, + }, + { + .gpio_num = WM831X_P06, //tp1 + .pin_type = GPIO_OUT, + .pin_value = GPIO_HIGH, + }, + { + .gpio_num = WM831X_P07, //tp1 + .pin_type = GPIO_IN, + }, + { + .gpio_num = WM831X_P08, //tp1 + .pin_type = GPIO_OUT, + .pin_value = GPIO_HIGH, + }, + { + .gpio_num = WM831X_P09, //tp1 + .pin_type = GPIO_OUT, + .pin_value = GPIO_HIGH, + }, + { + .gpio_num = WM831X_P10, //tp1 + .pin_type = GPIO_IN, + }, + { + .gpio_num = WM831X_P11, //tp1 + .pin_type = GPIO_OUT, + .pin_value = GPIO_HIGH, + }, + { + .gpio_num = WM831X_P12, + .pin_type = GPIO_OUT, + .pin_value = GPIO_HIGH, + }, +}; +#endif + +#if defined(CONFIG_MFD_WM831X) + +#define UNLOCK_SECURITY_KEY ~(0x1<<5) +#define LOCK_SECURITY_KEY 0x00 +#define PMU_POWER_SLEEP RK30_PIN0_PA1 +static struct wm831x *Wm831x; + +static int wm831x_pre_init(struct wm831x *parm) +{ + int ret; + Wm831x = parm; +// printk("%s\n", __func__); + gpio_request(PMU_POWER_SLEEP, "NULL"); + gpio_direction_output(PMU_POWER_SLEEP, GPIO_LOW); + + #ifdef CONFIG_WM8326_VBAT_LOW_DETECTION + #ifdef CONFIG_BATTERY_RK30_VOL3V8 + wm831x_set_bits(parm,WM831X_SYSVDD_CONTROL ,0xc077,0xc035); //pvdd power on dect vbat voltage + printk("+++The vbat is too low+++\n"); + #endif + #endif + + ret = wm831x_reg_read(parm, WM831X_POWER_STATE) & 0xffff; + wm831x_reg_write(parm, WM831X_POWER_STATE, (ret & 0xfff8) | 0x04); + + wm831x_set_bits(parm, WM831X_RTC_CONTROL, WM831X_RTC_ALAM_ENA_MASK, 0x0400);//enable rtc alam + //BATT_FET_ENA = 1 + wm831x_reg_write(parm, WM831X_SECURITY_KEY, 0x9716); // unlock security key + wm831x_set_bits(parm, WM831X_RESET_CONTROL, 0x1003, 0x1001); + ret = wm831x_reg_read(parm, WM831X_RESET_CONTROL) & 0xffff & UNLOCK_SECURITY_KEY; // enternal reset active in sleep +// printk("%s:WM831X_RESET_CONTROL=0x%x\n", __func__, ret); + wm831x_reg_write(parm, WM831X_RESET_CONTROL, ret); + + wm831x_set_bits(parm,WM831X_DC1_ON_CONFIG ,0x0300,0x0000); //set dcdc mode is FCCM + wm831x_set_bits(parm,WM831X_DC2_ON_CONFIG ,0x0300,0x0000); + wm831x_set_bits(parm,WM831X_DC3_ON_CONFIG ,0x0300,0x0000); + wm831x_set_bits(parm,0x4066,0x0300,0x0000); + +#ifndef CONFIG_MACH_RK3066_SDK + wm831x_set_bits(parm,WM831X_LDO10_CONTROL ,0x0040,0x0040);// set ldo10 in switch mode +#endif + wm831x_set_bits(parm,WM831X_STATUS_LED_1 ,0xc300,0xc100);// set led1 on(in manual mode) + wm831x_set_bits(parm,WM831X_STATUS_LED_2 ,0xc300,0xc000);//set led2 off(in manual mode) + + wm831x_set_bits(parm,WM831X_LDO5_SLEEP_CONTROL ,0xe000,0x2000);// set ldo5 is disable in sleep mode + wm831x_set_bits(parm,WM831X_LDO1_SLEEP_CONTROL ,0xe000,0x2000);// set ldo1 is disable in sleep mode + + wm831x_reg_write(parm, WM831X_SECURITY_KEY, LOCK_SECURITY_KEY); // lock security key + + return 0; +} +static int wm831x_mask_interrupt(struct wm831x *Wm831x) +{ + /**************************clear interrupt********************/ + wm831x_reg_write(Wm831x,WM831X_INTERRUPT_STATUS_1,0xffff); + wm831x_reg_write(Wm831x,WM831X_INTERRUPT_STATUS_2,0xffff); + wm831x_reg_write(Wm831x,WM831X_INTERRUPT_STATUS_3,0xffff); + wm831x_reg_write(Wm831x,WM831X_INTERRUPT_STATUS_4,0xffff); + wm831x_reg_write(Wm831x,WM831X_INTERRUPT_STATUS_5,0xffff); + + wm831x_reg_write(Wm831x,WM831X_SYSTEM_INTERRUPTS_MASK,0xbedc); //mask interrupt which not used + return 0; + /*****************************************************************/ +} + +#ifdef CONFIG_WM8326_VBAT_LOW_DETECTION +static int wm831x_low_power_detection(struct wm831x *wm831x) +{ + #ifdef CONFIG_BATTERY_RK30_VOL3V8 + wm831x_reg_write(wm831x,WM831X_SYSTEM_INTERRUPTS_MASK,0xbe5c); + wm831x_set_bits(wm831x,WM831X_INTERRUPT_STATUS_1_MASK,0x8000,0x0000); + wm831x_set_bits(wm831x,WM831X_SYSVDD_CONTROL ,0xc077,0x0035); //set pvdd low voltage is 3.1v hi voltage is 3.3v + #else + wm831x_reg_write(wm831x,WM831X_AUXADC_CONTROL,0x803f); //open adc + wm831x_reg_write(wm831x,WM831X_AUXADC_CONTROL,0xd03f); + wm831x_reg_write(wm831x,WM831X_AUXADC_SOURCE,0x0001); + + wm831x_reg_write(wm831x,WM831X_COMPARATOR_CONTROL,0x0001); + wm831x_reg_write(wm831x,WM831X_COMPARATOR_1,0x2844); //set the low power is 3.1v + + wm831x_reg_write(wm831x,WM831X_INTERRUPT_STATUS_1_MASK,0x99ee); + wm831x_set_bits(wm831x,WM831X_SYSTEM_INTERRUPTS_MASK,0x0100,0x0000); + if (wm831x_reg_read(wm831x,WM831X_AUXADC_DATA)< 0x1844){ + printk("The vbat is too low.\n"); + wm831x_device_shutdown(wm831x); + } + #endif + return 0; +} +#endif + +#define AVS_BASE 172 +int wm831x_post_init(struct wm831x *Wm831x) +{ + struct regulator *dcdc; + struct regulator *ldo; + + + ldo = regulator_get(NULL, "ldo6"); //vcc_33 + regulator_set_voltage(ldo, 3300000, 3300000); + regulator_set_suspend_voltage(ldo, 3300000); + regulator_enable(ldo); +// printk("%s set ldo6 vcc_33=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "ldo4"); // vdd_11 + regulator_set_voltage(ldo, 1100000, 1100000); + regulator_set_suspend_voltage(ldo, 1000000); + regulator_enable(ldo); +// printk("%s set ldo4 vdd_11=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "ldo5"); //vcc_25 + regulator_set_voltage(ldo, 2500000, 2500000); + regulator_set_suspend_voltage(ldo, 2500000); + regulator_enable(ldo); +// printk("%s set ldo5 vcc_25=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + + dcdc = regulator_get(NULL, "dcdc4"); // vcc_io +#ifdef CONFIG_MACH_RK3066_SDK + regulator_set_voltage(dcdc, 3300000, 3300000); + regulator_set_suspend_voltage(dcdc, 3100000); +#else + regulator_set_voltage(dcdc, 3000000, 3000000); + regulator_set_suspend_voltage(dcdc, 2800000); +#endif + regulator_enable(dcdc); +// printk("%s set dcdc4 vcc_io=%dmV end\n", __func__, regulator_get_voltage(dcdc)); + regulator_put(dcdc); + udelay(100); + + dcdc = regulator_get(NULL, "vdd_cpu"); // vdd_arm + regulator_set_voltage(dcdc, 1100000, 1100000); + regulator_set_suspend_voltage(dcdc, 1000000); + regulator_enable(dcdc); + printk("%s set dcdc2 vdd_cpu(vdd_arm)=%dmV end\n", __func__, regulator_get_voltage(dcdc)); + regulator_put(dcdc); + udelay(100); + + dcdc = regulator_get(NULL, "vdd_core"); // vdd_log + + /* Read avs value under logic 1.1V*/ + regulator_set_voltage(dcdc, 1100000, 1100000); + avs_init_val_get(1,1100000,"wm8326 init"); + udelay(600); + avs_set_scal_val(AVS_BASE); + + regulator_set_voltage(dcdc, 1150000, 1150000); + regulator_set_suspend_voltage(dcdc, 1000000); + regulator_enable(dcdc); + printk("%s set dcdc1 vdd_core(vdd_log)=%dmV end\n", __func__, regulator_get_voltage(dcdc)); + regulator_put(dcdc); + udelay(100); + + dcdc = regulator_get(NULL, "dcdc3"); // vcc_ddr + regulator_set_voltage(dcdc, 1150000, 1150000); + regulator_set_suspend_voltage(dcdc, 1150000); + regulator_enable(dcdc); +// printk("%s set dcdc3 vcc_ddr=%dmV end\n", __func__, regulator_get_voltage(dcdc)); + regulator_put(dcdc); + udelay(100); + + ldo = regulator_get(NULL, "ldo7"); // vcc28_cif + regulator_set_voltage(ldo, 2800000, 2800000); + regulator_set_suspend_voltage(ldo, 2800000); + regulator_enable(ldo); +// printk("%s set ldo7 vcc28_cif=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "ldo1"); // vcc18_cif + regulator_set_voltage(ldo, 1800000, 1800000); + regulator_set_suspend_voltage(ldo, 1800000); + regulator_enable(ldo); +// printk("%s set ldo1 vcc18_cif=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "ldo8"); // vcca_33 + regulator_set_voltage(ldo, 3300000, 3300000); + regulator_set_suspend_voltage(ldo, 3300000); + regulator_enable(ldo); +// printk("%s set ldo8 vcca_33=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "ldo2"); //vccio_wl + regulator_set_voltage(ldo, 1800000, 1800000); + regulator_set_suspend_voltage(ldo, 1800000); + regulator_enable(ldo); +// printk("%s set ldo2 vccio_wl=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "ldo10"); //flash io + regulator_set_voltage(ldo, 1800000, 1800000); + regulator_set_suspend_voltage(ldo, 1800000); + regulator_enable(ldo); +// printk("%s set ldo10 vcca_wl=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + +#ifdef CONFIG_MACH_RK3066_SDK + ldo = regulator_get(NULL, "ldo3"); //vdd11_hdmi + regulator_set_voltage(ldo, 1100000, 1100000); + regulator_set_suspend_voltage(ldo, 1100000); +#else + ldo = regulator_get(NULL, "ldo3"); //vdd_12 + regulator_set_voltage(ldo, 1200000, 1200000); + regulator_set_suspend_voltage(ldo, 1200000); +#endif + regulator_enable(ldo); +// printk("%s set ldo3 vdd_12=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "ldo9"); //vcc_tp + regulator_set_voltage(ldo, 3300000, 3300000); + regulator_set_suspend_voltage(ldo, 3300000); + regulator_enable(ldo); +// printk("%s set ldo9 vcc_tp=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + wm831x_mask_interrupt(Wm831x); + + #ifdef CONFIG_WM8326_VBAT_LOW_DETECTION + wm831x_low_power_detection(Wm831x); + #endif + + printk("wm831x_post_init end"); + return 0; +} + +static int wm831x_last_deinit(struct wm831x *Wm831x) +{ + struct regulator *ldo; + + printk("%s\n", __func__); + ldo = regulator_get(NULL, "ldo1"); + regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo2"); + regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo3"); + regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo4"); + //regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo5"); +// regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo6"); +// regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo7"); + regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo8"); + regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo9"); + regulator_disable(ldo); + regulator_put(ldo); + + ldo = regulator_get(NULL, "ldo10"); + regulator_disable(ldo); + regulator_put(ldo); + + return 0; +} + +struct wm831x_status_pdata wm831x_status_platdata[WM831X_MAX_STATUS] = { + { + .default_src = WM831X_STATUS_OTP, + .name = "wm831x_status0", + .default_trigger = "wm831x_otp", + }, + { + .default_src = WM831X_STATUS_POWER, + .name = "wm831x_status1", + .default_trigger = "wm831x_power", + }, +}; + +static struct regulator_consumer_supply dcdc1_consumers[] = { + { + .supply = "vdd_core", + } +}; + +static struct regulator_consumer_supply dcdc2_consumers[] = { + { + .supply = "vdd_cpu", + } + +}; + +static struct regulator_consumer_supply dcdc3_consumers[] = { + { + .supply = "dcdc3", + } +}; + +static struct regulator_consumer_supply dcdc4_consumers[] = { + { + .supply = "dcdc4", + } +}; + +#if 0 +static struct regulator_consumer_supply epe1_consumers[] = { + { + .supply = "epe1", + } +}; + +static struct regulator_consumer_supply epe2_consumers[] = { + { + .supply = "epe2", + } +}; +#endif + +static struct regulator_consumer_supply ldo1_consumers[] = { + { + .supply = "ldo1", + } +}; + +static struct regulator_consumer_supply ldo2_consumers[] = { + { + .supply = "ldo2", + } +}; + +static struct regulator_consumer_supply ldo3_consumers[] = { + { + .supply = "ldo3", + } +}; + +static struct regulator_consumer_supply ldo4_consumers[] = { + { + .supply = "ldo4", + } +}; + +static struct regulator_consumer_supply ldo5_consumers[] = { + { + .supply = "ldo5", + } +}; + +static struct regulator_consumer_supply ldo6_consumers[] = { + { + .supply = "ldo6", + } +}; + +static struct regulator_consumer_supply ldo7_consumers[] = { + { + .supply = "ldo7", + } +}; + +static struct regulator_consumer_supply ldo8_consumers[] = { + { + .supply = "ldo8", + } +}; + +static struct regulator_consumer_supply ldo9_consumers[] = { + { + .supply = "ldo9", + } +}; + +static struct regulator_consumer_supply ldo10_consumers[] = { + { + .supply = "ldo10", + } +}; + +static struct regulator_consumer_supply ldo11_consumers[] = { + { + .supply = "ldo11", + } +}; + +struct regulator_init_data wm831x_regulator_init_dcdc[WM831X_MAX_DCDC] = { + { + .constraints = { + .name = "DCDC1", + .min_uV = 600000, + .max_uV = 1800000, //0.6-1.8V + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(dcdc1_consumers), + .consumer_supplies = dcdc1_consumers, + }, + { + .constraints = { + .name = "DCDC2", + .min_uV = 600000, + .max_uV = 1800000, //0.6-1.8V + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(dcdc2_consumers), + .consumer_supplies = dcdc2_consumers, + }, + { + .constraints = { + .name = "DCDC3", + .min_uV = 850000, + .max_uV = 3400000, //0.85-3.4V + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(dcdc3_consumers), + .consumer_supplies = dcdc3_consumers, + }, + { + .constraints = { + .name = "DCDC4", + .min_uV = 850000, + .max_uV = 3400000, //0.85-3.4V + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(dcdc4_consumers), + .consumer_supplies = dcdc4_consumers, + }, +}; + +#if 0 +struct regulator_init_data wm831x_regulator_init_epe[WM831X_MAX_EPE] = { + { + .constraints = { + .name = "EPE1", + .min_uV = 1200000, + .max_uV = 3000000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(epe1_consumers), + .consumer_supplies = epe1_consumers, + }, + { + .constraints = { + .name = "EPE2", + .min_uV = 1200000, + .max_uV = 3000000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(epe2_consumers), + .consumer_supplies = epe2_consumers, + }, +}; +#endif + +struct regulator_init_data wm831x_regulator_init_ldo[WM831X_MAX_LDO] = { + { + .constraints = { + .name = "LDO1", + .min_uV = 900000, + .max_uV = 3300000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo1_consumers), + .consumer_supplies = ldo1_consumers, + }, + { + .constraints = { + .name = "LDO2", + .min_uV = 900000, + .max_uV = 3300000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo2_consumers), + .consumer_supplies = ldo2_consumers, + }, + { + .constraints = { + .name = "LDO3", + .min_uV = 900000, + .max_uV = 3300000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo3_consumers), + .consumer_supplies = ldo3_consumers, + }, + { + .constraints = { + .name = "LDO4", + .min_uV = 900000, + .max_uV = 3300000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo4_consumers), + .consumer_supplies = ldo4_consumers, + }, + { + .constraints = { + .name = "LDO5", + .min_uV = 900000, + .max_uV = 3300000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo5_consumers), + .consumer_supplies = ldo5_consumers, + }, + { + .constraints = { + .name = "LDO6", + .min_uV = 900000, + .max_uV = 3300000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo6_consumers), + .consumer_supplies = ldo6_consumers, + }, + { + .constraints = { + .name = "LDO7", + .min_uV = 1000000, + .max_uV = 3500000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo7_consumers), + .consumer_supplies = ldo7_consumers, + }, + { + .constraints = { + .name = "LDO8", + .min_uV = 1000000, + .max_uV = 3500000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo8_consumers), + .consumer_supplies = ldo8_consumers, + }, + { + .constraints = { + .name = "LDO9", + .min_uV = 1000000, + .max_uV = 3500000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo9_consumers), + .consumer_supplies = ldo9_consumers, + }, + { + .constraints = { + .name = "LDO10", + .min_uV = 1000000, + .max_uV = 3500000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo10_consumers), + .consumer_supplies = ldo10_consumers, + }, + { + .constraints = { + .name = "LDO11", + .min_uV = 800000, + .max_uV = 1550000, + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo11_consumers), + .consumer_supplies = ldo11_consumers, + }, +}; + +static int wm831x_init_pin_type(struct wm831x *wm831x) +{ + struct wm831x_pdata *pdata; + struct rk29_gpio_expander_info *wm831x_gpio_settinginfo; + uint16_t wm831x_settingpin_num; + int i; + + if (!wm831x || !wm831x->dev) + goto out; + + pdata = wm831x->dev->platform_data; + if (!pdata) + goto out; + + wm831x_gpio_settinginfo = pdata->settinginfo; + if (!wm831x_gpio_settinginfo) + goto out; + + wm831x_settingpin_num = pdata->settinginfolen; + for (i = 0; i < wm831x_settingpin_num; i++) { + if (wm831x_gpio_settinginfo[i].pin_type == GPIO_IN) { + wm831x_set_bits(wm831x, + WM831X_GPIO1_CONTROL + i, + WM831X_GPN_DIR_MASK | WM831X_GPN_TRI_MASK, + 1 << WM831X_GPN_DIR_SHIFT | 1 << WM831X_GPN_TRI_SHIFT); + if (i == 1) { + wm831x_set_bits(wm831x, + WM831X_GPIO1_CONTROL + i, + WM831X_GPN_POL_MASK, + 0x0400); + wm831x_set_bits(wm831x, + WM831X_GPIO1_CONTROL + i, + WM831X_GPN_FN_MASK, + 0x0003); + } // set gpio2 sleep/wakeup + + if (i == 9) { + wm831x_set_bits(wm831x, + WM831X_GPIO1_CONTROL + i, + WM831X_GPN_PULL_MASK, + 0x0000); //disable pullup/down + wm831x_set_bits(wm831x, + WM831X_GPIO1_CONTROL + i, + WM831X_GPN_PWR_DOM_MASK, + 0x0800); + wm831x_set_bits(wm831x, + WM831X_GPIO1_CONTROL + i, + WM831X_GPN_ENA_MASK, + 0x0000); + } //set gpio10 as adc input + + } else { + wm831x_set_bits(wm831x, + WM831X_GPIO1_CONTROL + i, + WM831X_GPN_DIR_MASK | WM831X_GPN_TRI_MASK, + 1 << WM831X_GPN_TRI_SHIFT); + if (wm831x_gpio_settinginfo[i].pin_value == GPIO_HIGH) { + wm831x_set_bits(wm831x, WM831X_GPIO_LEVEL, 1 << i, 1 << i); + } else { + wm831x_set_bits(wm831x, WM831X_GPIO_LEVEL, 1 << i, 0 << i); + } + if (i == 2) { + wm831x_set_bits(wm831x, + WM831X_GPIO1_CONTROL + i, + WM831X_GPN_PWR_DOM_MASK | WM831X_GPN_POL_MASK |WM831X_GPN_FN_MASK, + 1 << WM831X_GPN_POL_SHIFT | 1 << WM831X_GPN_PWR_DOM_SHIFT | 1 << 0); + + } // set gpio3 as clkout output 32.768K + + } + } + +#if 0 + for (i = 0; i < pdata->gpio_pin_num; i++) { + wm831x_set_bits(wm831x, + WM831X_GPIO1_CONTROL + i, + WM831X_GPN_PULL_MASK | WM831X_GPN_POL_MASK | WM831X_GPN_OD_MASK | WM831X_GPN_TRI_MASK, + 1 << WM831X_GPN_POL_SHIFT | 1 << WM831X_GPN_TRI_SHIFT); + + ret = wm831x_reg_read(wm831x, WM831X_GPIO1_CONTROL + i); + printk("Gpio%d Pin Configuration = %x\n", i, ret); + } +#endif + +out: + return 0; +} + +void __sramfunc board_pmu_suspend(void) +{ + cru_writel(CRU_CLKGATE5_GRFCLK_ON,CRU_CLKGATE5_CON_ADDR); //open grf clk + grf_writel(GPIO6_PB1_DIR_OUT, GRF_GPIO6L_DIR_ADDR); + grf_writel(GPIO6_PB1_DO_HIGH, GRF_GPIO6L_DO_ADDR); //set gpio6_b1 output low + grf_writel(GPIO6_PB1_EN_MASK, GRF_GPIO6L_EN_ADDR); +} +void __sramfunc board_pmu_resume(void) +{ + grf_writel(GPIO6_PB1_DIR_OUT, GRF_GPIO6L_DIR_ADDR); + grf_writel(GPIO6_PB1_DO_LOW, GRF_GPIO6L_DO_ADDR); //set gpio6_b1 output high + grf_writel(GPIO6_PB1_EN_MASK, GRF_GPIO6L_EN_ADDR); +#ifdef CONFIG_CLK_SWITCH_TO_32K + sram_32k_udelay(10000); +#else + sram_udelay(10000); +#endif +} +static struct wm831x_pdata wm831x_platdata = { + + /** Called before subdevices are set up */ + .pre_init = wm831x_pre_init, + /** Called after subdevices are set up */ + .post_init = wm831x_post_init, + /** Called before subdevices are power down */ + .last_deinit = wm831x_last_deinit, + +#if defined(CONFIG_GPIO_WM831X) + .gpio_base = WM831X_GPIO_EXPANDER_BASE, + .gpio_pin_num = WM831X_TOTOL_GPIO_NUM, + .settinginfo = wm831x_gpio_settinginfo, + .settinginfolen = ARRAY_SIZE(wm831x_gpio_settinginfo), + .pin_type_init = wm831x_init_pin_type, + .irq_base = NR_GIC_IRQS + NR_GPIO_IRQS, +#endif + + /** LED1 = 0 and so on */ + .status = { &wm831x_status_platdata[0], &wm831x_status_platdata[1] }, + + /** DCDC1 = 0 and so on */ + .dcdc = { + &wm831x_regulator_init_dcdc[0], + &wm831x_regulator_init_dcdc[1], + &wm831x_regulator_init_dcdc[2], + &wm831x_regulator_init_dcdc[3], + }, + + /** EPE1 = 0 and so on */ + //.epe = { &wm831x_regulator_init_epe[0], &wm831x_regulator_init_epe[1] }, + + /** LDO1 = 0 and so on */ + .ldo = { + &wm831x_regulator_init_ldo[0], + &wm831x_regulator_init_ldo[1], + &wm831x_regulator_init_ldo[2], + &wm831x_regulator_init_ldo[3], + &wm831x_regulator_init_ldo[4], + &wm831x_regulator_init_ldo[5], + &wm831x_regulator_init_ldo[6], + &wm831x_regulator_init_ldo[7], + &wm831x_regulator_init_ldo[8], + &wm831x_regulator_init_ldo[9], + &wm831x_regulator_init_ldo[10], + }, +}; +#endif diff --git a/arch/arm/mach-rk30/board-rk3066b-sdk.c b/arch/arm/mach-rk30/board-rk3066b-sdk.c new file mode 100644 index 000000000000..97f86c821884 --- /dev/null +++ b/arch/arm/mach-rk30/board-rk3066b-sdk.c @@ -0,0 +1,1688 @@ +/* arch/arm/mach-rk30/board-rk30-sdk.c + * + * Copyright (C) 2012 ROCKCHIP, Inc. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_HDMI_RK30) + #include "../../../drivers/video/rockchip/hdmi/rk_hdmi.h" +#endif + +#if defined(CONFIG_SPIM_RK29) +#include "../../../drivers/spi/rk29_spim.h" +#endif +#if defined(CONFIG_MU509) +#include +#endif +#if defined(CONFIG_MW100) +#include +#endif +#if defined(CONFIG_MT6229) +#include +#endif +#if defined(CONFIG_ANDROID_TIMED_GPIO) +#include "../../../drivers/staging/android/timed_gpio.h" +#endif + +#ifdef CONFIG_THREE_FB_BUFFER +#define RK30_FB0_MEM_SIZE 12*SZ_1M +#else +#define RK30_FB0_MEM_SIZE 8*SZ_1M +#endif + +#ifdef CONFIG_VIDEO_RK29 +/*---------------- Camera Sensor Macro Define Begin ------------------------*/ +/*---------------- Camera Sensor Configuration Macro Begin ------------------------*/ +#define CONFIG_SENSOR_0 RK29_CAM_SENSOR_OV5642 /* back camera sensor */ +#define CONFIG_SENSOR_IIC_ADDR_0 0 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_0 4 +#define CONFIG_SENSOR_ORIENTATION_0 90 +#define CONFIG_SENSOR_POWER_PIN_0 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_0 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_0 RK30_PIN1_PD6 +#define CONFIG_SENSOR_FALSH_PIN_0 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_0 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_0 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_0 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_0 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_0 30000 + +#define CONFIG_SENSOR_01 RK29_CAM_SENSOR_OV5642 /* back camera sensor 1 */ +#define CONFIG_SENSOR_IIC_ADDR_01 0x00 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_01 4 +#define CONFIG_SENSOR_ORIENTATION_01 90 +#define CONFIG_SENSOR_POWER_PIN_01 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_01 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_01 RK30_PIN1_PD6 +#define CONFIG_SENSOR_FALSH_PIN_01 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_01 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_01 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_01 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_01 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_01 30000 + +#define CONFIG_SENSOR_02 RK29_CAM_SENSOR_OV5640 /* back camera sensor 2 */ +#define CONFIG_SENSOR_IIC_ADDR_02 0x00 +#define CONFIG_SENSOR_CIF_INDEX_02 0 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_02 4 +#define CONFIG_SENSOR_ORIENTATION_02 90 +#define CONFIG_SENSOR_POWER_PIN_02 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_02 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_02 INVALID_GPIO +#define CONFIG_SENSOR_FALSH_PIN_02 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_02 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_02 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_02 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_02 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_02 30000 + +#define CONFIG_SENSOR_1 RK29_CAM_SENSOR_OV2659 /* front camera sensor 0 */ +#define CONFIG_SENSOR_IIC_ADDR_1 0x60 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_1 3 +#define CONFIG_SENSOR_ORIENTATION_1 270 +#define CONFIG_SENSOR_POWER_PIN_1 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_1 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_1 RK30_PIN2_PC7 +#define CONFIG_SENSOR_FALSH_PIN_1 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_1 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_1 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_1 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_1 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_1 30000 + +#define CONFIG_SENSOR_11 RK29_CAM_SENSOR_OV2659 /* front camera sensor 1 */ +#define CONFIG_SENSOR_IIC_ADDR_11 0x00 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_11 3 +#define CONFIG_SENSOR_ORIENTATION_11 270 +#define CONFIG_SENSOR_POWER_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_11 INVALID_GPIO//RK30_PIN1_PB7 +#define CONFIG_SENSOR_FALSH_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_11 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_11 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_11 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_11 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_11 30000 + +#define CONFIG_SENSOR_12 RK29_CAM_SENSOR_OV2659//RK29_CAM_SENSOR_OV2655 /* front camera sensor 2 */ +#define CONFIG_SENSOR_IIC_ADDR_12 0x00 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_12 3 +#define CONFIG_SENSOR_ORIENTATION_12 270 +#define CONFIG_SENSOR_POWER_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_12 INVALID_GPIO//RK30_PIN1_PB7 +#define CONFIG_SENSOR_FALSH_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_12 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_12 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_12 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_12 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_12 30000 + + +#endif //#ifdef CONFIG_VIDEO_RK29 +/*---------------- Camera Sensor Configuration Macro End------------------------*/ +#include "../../../drivers/media/video/rk30_camera.c" +/*---------------- Camera Sensor Macro Define End ---------*/ + +#define PMEM_CAM_SIZE PMEM_CAM_NECESSARY +/***************************************************************************************** + * camera devices + * author: ddl@rock-chips.com + *****************************************************************************************/ +#ifdef CONFIG_VIDEO_RK29 +#define CONFIG_SENSOR_POWER_IOCTL_USR 1 //define this refer to your board layout +#define CONFIG_SENSOR_RESET_IOCTL_USR 0 +#define CONFIG_SENSOR_POWERDOWN_IOCTL_USR 0 +#define CONFIG_SENSOR_FLASH_IOCTL_USR 0 + +static void rk_cif_power(int on) +{ + struct regulator *ldo_18,*ldo_28; + ldo_28 = regulator_get(NULL, "ldo7"); // vcc28_cif + ldo_18 = regulator_get(NULL, "ldo1"); // vcc18_cif + if (ldo_28 == NULL || IS_ERR(ldo_28) || ldo_18 == NULL || IS_ERR(ldo_18)){ + printk("get cif ldo failed!\n"); + return; + } + if(on == 0){ + regulator_disable(ldo_28); + regulator_put(ldo_28); + regulator_disable(ldo_18); + regulator_put(ldo_18); + mdelay(500); + } + else{ + regulator_set_voltage(ldo_28, 2800000, 2800000); + regulator_enable(ldo_28); + // printk("%s set ldo7 vcc28_cif=%dmV end\n", __func__, regulator_get_voltage(ldo_28)); + regulator_put(ldo_28); + + regulator_set_voltage(ldo_18, 1800000, 1800000); + // regulator_set_suspend_voltage(ldo, 1800000); + regulator_enable(ldo_18); + // printk("%s set ldo1 vcc18_cif=%dmV end\n", __func__, regulator_get_voltage(ldo_18)); + regulator_put(ldo_18); + } +} + +#if CONFIG_SENSOR_POWER_IOCTL_USR +static int sensor_power_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + //#error "CONFIG_SENSOR_POWER_IOCTL_USR is 1, sensor_power_usr_cb function must be writed!!"; + rk_cif_power(on); +} +#endif + +#if CONFIG_SENSOR_RESET_IOCTL_USR +static int sensor_reset_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + #error "CONFIG_SENSOR_RESET_IOCTL_USR is 1, sensor_reset_usr_cb function must be writed!!"; +} +#endif + +#if CONFIG_SENSOR_POWERDOWN_IOCTL_USR +static int sensor_powerdown_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + #error "CONFIG_SENSOR_POWERDOWN_IOCTL_USR is 1, sensor_powerdown_usr_cb function must be writed!!"; +} +#endif + +#if CONFIG_SENSOR_FLASH_IOCTL_USR +static int sensor_flash_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + #error "CONFIG_SENSOR_FLASH_IOCTL_USR is 1, sensor_flash_usr_cb function must be writed!!"; +} +#endif + +static struct rk29camera_platform_ioctl_cb sensor_ioctl_cb = { + #if CONFIG_SENSOR_POWER_IOCTL_USR + .sensor_power_cb = sensor_power_usr_cb, + #else + .sensor_power_cb = NULL, + #endif + + #if CONFIG_SENSOR_RESET_IOCTL_USR + .sensor_reset_cb = sensor_reset_usr_cb, + #else + .sensor_reset_cb = NULL, + #endif + + #if CONFIG_SENSOR_POWERDOWN_IOCTL_USR + .sensor_powerdown_cb = sensor_powerdown_usr_cb, + #else + .sensor_powerdown_cb = NULL, + #endif + + #if CONFIG_SENSOR_FLASH_IOCTL_USR + .sensor_flash_cb = sensor_flash_usr_cb, + #else + .sensor_flash_cb = NULL, + #endif +}; + +#if CONFIG_SENSOR_IIC_ADDR_0 +static struct reginfo_t rk_init_data_sensor_reg_0[] = +{ + {0x0000, 0x00,0,0} + }; +static struct reginfo_t rk_init_data_sensor_winseqreg_0[] ={ + {0x0000, 0x00,0,0} + }; +#endif + +#if CONFIG_SENSOR_IIC_ADDR_1 +static struct reginfo_t rk_init_data_sensor_reg_1[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_1[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_01 +static struct reginfo_t rk_init_data_sensor_reg_01[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_01[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_02 +static struct reginfo_t rk_init_data_sensor_reg_02[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_02[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_11 +static struct reginfo_t rk_init_data_sensor_reg_11[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_11[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_12 +static struct reginfo_t rk_init_data_sensor_reg_12[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_12[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +static rk_sensor_user_init_data_s rk_init_data_sensor[RK_CAM_NUM] = +{ + #if CONFIG_SENSOR_IIC_ADDR_0 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_0, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_0, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_0) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_0) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_1 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_1, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_1, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_1) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_1) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_01 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_01, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_01, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_01) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_01) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_02 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_02, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_02, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_02) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_02) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_11 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_11, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_11, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_11) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_11) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_12 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_12, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_12, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_12) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_12) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + + }; +#include "../../../drivers/media/video/rk30_camera.c" + +#endif /* CONFIG_VIDEO_RK29 */ + +#if defined(CONFIG_TOUCHSCREEN_GT8XX) +#define TOUCH_RESET_PIN RK30_PIN2_PC0 +#define TOUCH_PWR_PIN INVALID_GPIO +int goodix_init_platform_hw(void) +{ + int ret; + + rk30_mux_api_set(GPIO4D0_SMCDATA8_TRACEDATA8_NAME, GPIO4D_GPIO4D0); + rk30_mux_api_set(GPIO4C2_SMCDATA2_TRACEDATA2_NAME, GPIO4C_GPIO4C2); + printk("%s:0x%x,0x%x\n",__func__,rk30_mux_api_get(GPIO4D0_SMCDATA8_TRACEDATA8_NAME),rk30_mux_api_get(GPIO4C2_SMCDATA2_TRACEDATA2_NAME)); + + if (TOUCH_PWR_PIN != INVALID_GPIO) { + ret = gpio_request(TOUCH_PWR_PIN, "goodix power pin"); + if (ret != 0) { + gpio_free(TOUCH_PWR_PIN); + printk("goodix power error\n"); + return -EIO; + } + gpio_direction_output(TOUCH_PWR_PIN, 0); + gpio_set_value(TOUCH_PWR_PIN, GPIO_LOW); + msleep(100); + } + + if (TOUCH_RESET_PIN != INVALID_GPIO) { + ret = gpio_request(TOUCH_RESET_PIN, "goodix reset pin"); + if (ret != 0) { + gpio_free(TOUCH_RESET_PIN); + printk("goodix gpio_request error\n"); + return -EIO; + } + gpio_direction_output(TOUCH_RESET_PIN, 1); + msleep(100); + //gpio_set_value(TOUCH_RESET_PIN, GPIO_LOW); + //msleep(100); + //gpio_set_value(TOUCH_RESET_PIN, GPIO_HIGH); + //msleep(500); + } + return 0; +} + +struct goodix_platform_data goodix_info = { + .model = 8105, + .irq_pin = RK30_PIN0_PD4, + .rest_pin = TOUCH_RESET_PIN, + .init_platform_hw = goodix_init_platform_hw, +}; +#endif + +static struct spi_board_info board_spi_devices[] = { +}; + +/*********************************************************** +* rk30 backlight +************************************************************/ +#ifdef CONFIG_BACKLIGHT_RK29_BL +#define PWM_ID 0 +#define PWM_MUX_NAME GPIO3D3_PWM0_NAME +#define PWM_MUX_MODE GPIO3D_PWM0 +#define PWM_MUX_MODE_GPIO GPIO3D_GPIO3D4 +#define PWM_GPIO RK30_PIN3_PD4 +#define PWM_EFFECT_VALUE 1 + +#define LCD_DISP_ON_PIN + +#ifdef LCD_DISP_ON_PIN +#define BL_EN_PIN RK30_PIN0_PA1 +#define BL_EN_VALUE GPIO_HIGH +#endif +static int rk29_backlight_io_init(void) +{ + int ret = 0; + rk30_mux_api_set(PWM_MUX_NAME, PWM_MUX_MODE); +#ifdef LCD_DISP_ON_PIN + // rk30_mux_api_set(BL_EN_MUX_NAME, BL_EN_MUX_MODE); + + ret = gpio_request(BL_EN_PIN, NULL); + if (ret != 0) { + gpio_free(BL_EN_PIN); + } + + gpio_direction_output(BL_EN_PIN, 0); + gpio_set_value(BL_EN_PIN, BL_EN_VALUE); +#endif + return ret; +} + +static int rk29_backlight_io_deinit(void) +{ + int ret = 0; +#ifdef LCD_DISP_ON_PIN + gpio_free(BL_EN_PIN); +#endif + rk30_mux_api_set(PWM_MUX_NAME, PWM_MUX_MODE_GPIO); + return ret; +} + +static int rk29_backlight_pwm_suspend(void) +{ + int ret = 0; + rk30_mux_api_set(PWM_MUX_NAME, PWM_MUX_MODE_GPIO); + if (gpio_request(PWM_GPIO, NULL)) { + printk("func %s, line %d: request gpio fail\n", __FUNCTION__, __LINE__); + return -1; + } + gpio_direction_output(PWM_GPIO, GPIO_LOW); +#ifdef LCD_DISP_ON_PIN + gpio_direction_output(BL_EN_PIN, 0); + gpio_set_value(BL_EN_PIN, !BL_EN_VALUE); +#endif + return ret; +} + +static int rk29_backlight_pwm_resume(void) +{ + gpio_free(PWM_GPIO); + rk30_mux_api_set(PWM_MUX_NAME, PWM_MUX_MODE); +#ifdef LCD_DISP_ON_PIN + msleep(30); + gpio_direction_output(BL_EN_PIN, 1); + gpio_set_value(BL_EN_PIN, BL_EN_VALUE); +#endif + return 0; +} + +static struct rk29_bl_info rk29_bl_info = { + .pwm_id = PWM_ID, + .bl_ref = PWM_EFFECT_VALUE, + .io_init = rk29_backlight_io_init, + .io_deinit = rk29_backlight_io_deinit, + .pwm_suspend = rk29_backlight_pwm_suspend, + .pwm_resume = rk29_backlight_pwm_resume, +}; + +static struct platform_device rk29_device_backlight = { + .name = "rk29_backlight", + .id = -1, + .dev = { + .platform_data = &rk29_bl_info, + } +}; + +#endif + +#ifdef CONFIG_RK29_SUPPORT_MODEM + +#define RK30_MODEM_POWER RK30_PIN2_PB0 +#define RK30_MODEM_POWER_IOMUX rk29_mux_api_set(GPIO2B0_LCDC1DATA8_SMCDATA8_TRACEDATA8_NAME, GPIO2B_GPIO2B0) + +static int rk30_modem_io_init(void) +{ + printk("%s\n", __FUNCTION__); + RK30_MODEM_POWER_IOMUX; + + return 0; +} + +static struct rk29_io_t rk30_modem_io = { + .io_addr = RK30_MODEM_POWER, + .enable = GPIO_HIGH, + .disable = GPIO_LOW, + .io_init = rk30_modem_io_init, +}; + +static struct platform_device rk30_device_modem = { + .name = "rk30_modem", + .id = -1, + .dev = { + .platform_data = &rk30_modem_io, + } +}; +#endif +#if defined(CONFIG_MU509) +static int mu509_io_init(void) +{ + + rk30_mux_api_set(GPIO2B0_LCDC1DATA8_SMCDATA8_TRACEDATA8_NAME, GPIO2B_GPIO2B0); + rk30_mux_api_set(GPIO2D1_LCDC1DEN_SMCWEN_NAME, GPIO2D_GPIO2D1); + rk30_mux_api_set(GPIO2B7_LCDC1DATA15_SMCADDR19_HSADCDATA7_NAME, GPIO2B_GPIO2B7); + rk30_mux_api_set(GPIO2C0_LCDCDATA16_GPSCLK_HSADCCLKOUT_NAME, GPIO2C_GPIO2C0); + return 0; +} + +static int mu509_io_deinit(void) +{ + + return 0; +} + +struct rk29_mu509_data rk29_mu509_info = { + .io_init = mu509_io_init, + .io_deinit = mu509_io_deinit, + .modem_power_en = RK30_PIN2_PB0, + .bp_power = RK30_PIN2_PB0, + .bp_reset = RK30_PIN2_PD1, + .ap_wakeup_bp = RK30_PIN2_PB7, + .bp_wakeup_ap = RK30_PIN6_PA0, +}; +struct platform_device rk29_device_mu509 = { + .name = "mu509", + .id = -1, + .dev = { + .platform_data = &rk29_mu509_info, + } + }; +#endif +#if defined(CONFIG_MW100) +static int mw100_io_init(void) +{ + rk30_mux_api_set(GPIO2B0_LCDC1DATA8_SMCDATA8_TRACEDATA8_NAME, GPIO2B_GPIO2B0); + rk30_mux_api_set(GPIO2D1_LCDC1DEN_SMCWEN_NAME, GPIO2D_GPIO2D1); + rk30_mux_api_set(GPIO2B7_LCDC1DATA15_SMCADDR19_HSADCDATA7_NAME, GPIO2B_GPIO2B7); + rk30_mux_api_set(GPIO2C0_LCDCDATA16_GPSCLK_HSADCCLKOUT_NAME, GPIO2C_GPIO2C0); + return 0; +} + +static int mw100_io_deinit(void) +{ + + return 0; +} + +struct rk29_mw100_data rk29_mw100_info = { + .io_init = mw100_io_init, + .io_deinit = mw100_io_deinit, + .modem_power_en = RK30_PIN6_PB0, + .bp_power = RK30_PIN2_PB0, + .bp_reset = RK30_PIN2_PD1, + .ap_wakeup_bp = RK30_PIN2_PB7, + .bp_wakeup_ap = RK30_PIN6_PA0, +}; +struct platform_device rk29_device_mw100 = { + .name = "mw100", + .id = -1, + .dev = { + .platform_data = &rk29_mw100_info, + } + }; +#endif +#if defined(CONFIG_MT6229) +static int mt6229_io_init(void) +{ + rk30_mux_api_set(GPIO2B0_LCDC1DATA8_SMCDATA8_TRACEDATA8_NAME, GPIO2B_GPIO2B0); + rk30_mux_api_set(GPIO2D1_LCDC1DEN_SMCWEN_NAME, GPIO2D_GPIO2D1); + rk30_mux_api_set(GPIO2B7_LCDC1DATA15_SMCADDR19_HSADCDATA7_NAME, GPIO2B_GPIO2B7); + rk30_mux_api_set(GPIO2C0_LCDCDATA16_GPSCLK_HSADCCLKOUT_NAME, GPIO2C_GPIO2C0); + return 0; +} + +static int mt6229_io_deinit(void) +{ + + return 0; +} + +struct rk29_mt6229_data rk29_mt6229_info = { + .io_init = mt6229_io_init, + .io_deinit = mt6229_io_deinit, + .modem_power_en = RK30_PIN2_PB0, + .bp_power = RK30_PIN2_PB0,//RK30_PIN2_PB6, + .bp_reset = RK30_PIN2_PD1, + .ap_wakeup_bp = RK30_PIN2_PC0, + .bp_wakeup_ap = RK30_PIN6_PA0, +}; +struct platform_device rk29_device_mt6229 = { + .name = "mt6229", + .id = -1, + .dev = { + .platform_data = &rk29_mt6229_info, + } + }; +#endif + +/*MMA8452 gsensor*/ +#if defined (CONFIG_GS_MMA8452) +#define MMA8452_INT_PIN RK30_PIN3_PD7 + +static int mma8452_init_platform_hw(void) +{ + rk30_mux_api_set(GPIO4C0_SMCDATA0_TRACEDATA0_NAME, GPIO4C_GPIO4C0); + + return 0; +} + +static struct sensor_platform_data mma8452_info = { + .type = SENSOR_TYPE_ACCEL, + .irq_enable = 1, + .poll_delay_ms = 30, + .init_platform_hw = mma8452_init_platform_hw, + .orientation = {-1, 0, 0, 0, 0, 1, 0, -1, 0}, +}; +#endif +#if defined (CONFIG_GS_LIS3DH) +#define LIS3DH_INT_PIN RK30_PIN3_PD7 + +static int lis3dh_init_platform_hw(void) +{ + rk30_mux_api_set(GPIO4C0_SMCDATA0_TRACEDATA0_NAME, GPIO4C_GPIO4C0); + + return 0; +} + +static struct sensor_platform_data lis3dh_info = { + .type = SENSOR_TYPE_ACCEL, + .irq_enable = 1, + .poll_delay_ms = 30, + .init_platform_hw = lis3dh_init_platform_hw, + .orientation = {-1, 0, 0, 0, 0, 1, 0, -1, 0}, +}; +#endif +#if defined (CONFIG_COMPASS_AK8975) +static struct sensor_platform_data akm8975_info = +{ + .type = SENSOR_TYPE_COMPASS, + .irq_enable = 1, + .poll_delay_ms = 30, + .m_layout = + { + { + {1, 0, 0}, + {0, 1, 0}, + {0, 0, 1}, + }, + + { + {1, 0, 0}, + {0, 1, 0}, + {0, 0, 1}, + }, + + { + {1, 0, 0}, + {0, 1, 0}, + {0, 0, 1}, + }, + + { + {1, 0, 0}, + {0, 1, 0}, + {0, 0, 1}, + }, + } +}; + +#endif + +#if defined(CONFIG_GYRO_L3G4200D) + +#include +#define L3G4200D_INT_PIN RK30_PIN0_PB4 + +static int l3g4200d_init_platform_hw(void) +{ + rk30_mux_api_set(GPIO4C3_SMCDATA3_TRACEDATA3_NAME, GPIO4C_GPIO4C3); + + return 0; +} + +static struct sensor_platform_data l3g4200d_info = { + .type = SENSOR_TYPE_GYROSCOPE, + .irq_enable = 1, + .poll_delay_ms = 30, + .orientation = {0, 1, 0, -1, 0, 0, 0, 0, 1}, + .init_platform_hw = l3g4200d_init_platform_hw, + .x_min = 40,//x_min,y_min,z_min = (0-100) according to hardware + .y_min = 40, + .z_min = 20, +}; + +#endif + +#ifdef CONFIG_LS_CM3217 +static struct sensor_platform_data cm3217_info = { + .type = SENSOR_TYPE_LIGHT, + .irq_enable = 0, + .poll_delay_ms = 500, +}; + +#endif + +#ifdef CONFIG_FB_ROCKCHIP + +#define LCD_CS_PIN RK30_PIN0_PB0 +#define LCD_CS_VALUE GPIO_HIGH + +#define LCD_EN_PIN RK30_PIN0_PB0 +#define LCD_EN_VALUE GPIO_LOW + +static int rk_fb_io_init(struct rk29_fb_setting_info *fb_setting) +{ + int ret = 0; + ret = gpio_request(LCD_CS_PIN, NULL); + if (ret != 0) + { + gpio_free(LCD_CS_PIN); + printk(KERN_ERR "request lcd cs pin fail!\n"); + return -1; + } + else + { + gpio_direction_output(LCD_CS_PIN, LCD_CS_VALUE); + } + ret = gpio_request(LCD_EN_PIN, NULL); + if (ret != 0) + { + gpio_free(LCD_EN_PIN); + printk(KERN_ERR "request lcd en pin fail!\n"); + return -1; + } + else + { + gpio_direction_output(LCD_EN_PIN, LCD_EN_VALUE); + } + return 0; +} +static int rk_fb_io_disable(void) +{ + gpio_set_value(LCD_CS_PIN, LCD_CS_VALUE? 0:1); + gpio_set_value(LCD_EN_PIN, LCD_EN_VALUE? 0:1); + return 0; +} +static int rk_fb_io_enable(void) +{ + gpio_set_value(LCD_CS_PIN, LCD_CS_VALUE); + gpio_set_value(LCD_EN_PIN, LCD_EN_VALUE); + return 0; +} + +#if defined(CONFIG_LCDC0_RK31) +struct rk29fb_info lcdc0_screen_info = { + .prop = PRMRY, //primary display device + .io_init = rk_fb_io_init, + .io_disable = rk_fb_io_disable, + .io_enable = rk_fb_io_enable, + .set_screen_info = set_lcd_info, +}; +#endif + +#if defined(CONFIG_LCDC1_RK31) +struct rk29fb_info lcdc1_screen_info = { + #if defined(CONFIG_HDMI_RK30) + .prop = EXTEND, //extend display device + .lcd_info = NULL, + .set_screen_info = hdmi_init_lcdc, + #endif +}; +#endif + +static struct resource resource_fb[] = { + [0] = { + .name = "fb0 buf", + .start = 0, + .end = 0,//RK30_FB0_MEM_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "ipp buf", //for rotate + .start = 0, + .end = 0,//RK30_FB0_MEM_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [2] = { + .name = "fb2 buf", + .start = 0, + .end = 0,//RK30_FB0_MEM_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device device_fb = { + .name = "rk-fb", + .id = -1, + .num_resources = ARRAY_SIZE(resource_fb), + .resource = resource_fb, +}; +#endif + +#ifdef CONFIG_ANDROID_TIMED_GPIO +static struct timed_gpio timed_gpios[] = { + { + .name = "vibrator", + .gpio = RK30_PIN0_PA4, + .max_timeout = 1000, + .active_low = 0, + .adjust_time =20, //adjust for diff product + }, +}; + +static struct timed_gpio_platform_data rk29_vibrator_info = { + .num_gpios = 1, + .gpios = timed_gpios, +}; + +static struct platform_device rk29_device_vibrator = { + .name = "timed-gpio", + .id = -1, + .dev = { + .platform_data = &rk29_vibrator_info, + }, + +}; +#endif + +#ifdef CONFIG_LEDS_GPIO_PLATFORM +static struct gpio_led rk29_leds[] = { + { + .name = "button-backlight", + .gpio = RK30_PIN2_PB3, + .default_trigger = "timer", + .active_low = 0, + .retain_state_suspended = 0, + .default_state = LEDS_GPIO_DEFSTATE_OFF, + }, +}; + +static struct gpio_led_platform_data rk29_leds_pdata = { + .leds = rk29_leds, + .num_leds = ARRAY_SIZE(rk29_leds), +}; + +static struct platform_device rk29_device_gpio_leds = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &rk29_leds_pdata, + }, +}; +#endif + +#ifdef CONFIG_RK_IRDA +#define IRDA_IRQ_PIN RK30_PIN0_PA3 + +static int irda_iomux_init(void) +{ + int ret = 0; + + //irda irq pin + ret = gpio_request(IRDA_IRQ_PIN, NULL); + if (ret != 0) { + gpio_free(IRDA_IRQ_PIN); + printk(">>>>>> IRDA_IRQ_PIN gpio_request err \n "); + } + gpio_pull_updown(IRDA_IRQ_PIN, PullDisable); + gpio_direction_input(IRDA_IRQ_PIN); + + return 0; +} + +static int irda_iomux_deinit(void) +{ + gpio_free(IRDA_IRQ_PIN); + return 0; +} + +static struct irda_info rk29_irda_info = { + .intr_pin = IRDA_IRQ_PIN, + .iomux_init = irda_iomux_init, + .iomux_deinit = irda_iomux_deinit, + //.irda_pwr_ctl = bu92747guw_power_ctl, +}; + +static struct platform_device irda_device = { +#ifdef CONFIG_RK_IRDA_NET + .name = "rk_irda", +#else + .name = "bu92747_irda", +#endif + .id = -1, + .dev = { + .platform_data = &rk29_irda_info, + } +}; +#endif + +#ifdef CONFIG_ION +#define ION_RESERVE_SIZE (80 * SZ_1M) +static struct ion_platform_data rk30_ion_pdata = { + .nr = 1, + .heaps = { + { + .type = ION_HEAP_TYPE_CARVEOUT, + .id = ION_NOR_HEAP_ID, + .name = "norheap", + .size = ION_RESERVE_SIZE, + } + }, +}; + +static struct platform_device device_ion = { + .name = "ion-rockchip", + .id = 0, + .dev = { + .platform_data = &rk30_ion_pdata, + }, +}; +#endif + +/************************************************************************************************** + * SDMMC devices, include the module of SD,MMC,and sdio.noted by xbw at 2012-03-05 +**************************************************************************************************/ +#ifdef CONFIG_SDMMC_RK29 +#include "board-rk3066b-sdk-sdmmc.c" + +#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) +#define SDMMC0_WRITE_PROTECT_PIN RK30_PIN3_PB7 //According to your own project to set the value of write-protect-pin. +#endif + +#if defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT) +#define SDMMC1_WRITE_PROTECT_PIN RK30_PIN3_PC7 //According to your own project to set the value of write-protect-pin. +#endif + +#define RK29SDK_WIFI_SDIO_CARD_DETECT_N RK30_PIN6_PB2 + +#endif //endif ---#ifdef CONFIG_SDMMC_RK29 + +#ifdef CONFIG_SDMMC0_RK29 +static int rk29_sdmmc0_cfg_gpio(void) +{ +#ifdef CONFIG_SDMMC_RK29_OLD + rk30_mux_api_set(GPIO3B1_SDMMC0CMD_NAME, GPIO3B_SDMMC0_CMD); + rk30_mux_api_set(GPIO3B0_SDMMC0CLKOUT_NAME, GPIO3B_SDMMC0_CLKOUT); + rk30_mux_api_set(GPIO3B2_SDMMC0DATA0_NAME, GPIO3B_SDMMC0_DATA0); + rk30_mux_api_set(GPIO3B3_SDMMC0DATA1_NAME, GPIO3B_SDMMC0_DATA1); + rk30_mux_api_set(GPIO3B4_SDMMC0DATA2_NAME, GPIO3B_SDMMC0_DATA2); + rk30_mux_api_set(GPIO3B5_SDMMC0DATA3_NAME, GPIO3B_SDMMC0_DATA3); + + rk30_mux_api_set(GPIO3B6_SDMMC0DETECTN_NAME, GPIO3B_GPIO3B6); + + rk30_mux_api_set(GPIO3A7_SDMMC0PWREN_NAME, GPIO3A_GPIO3A7); + gpio_request(RK30_PIN3_PA7, "sdmmc-power"); + gpio_direction_output(RK30_PIN3_PA7, GPIO_LOW); + +#else + rk29_sdmmc_set_iomux(0, 0xFFFF); + + rk30_mux_api_set(GPIO3B0_SDMMC0DETECTN_NAME, GPIO3B_SDMMC0DETECTN); + +#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) + gpio_request(SDMMC0_WRITE_PROTECT_PIN, "sdmmc-wp"); + gpio_direction_input(SDMMC0_WRITE_PROTECT_PIN); +#endif + +#endif + + return 0; +} + +#define CONFIG_SDMMC0_USE_DMA +struct rk29_sdmmc_platform_data default_sdmmc0_data = { + .host_ocr_avail = + (MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 | MMC_VDD_28_29 | + MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | + MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36), + .host_caps = + (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), + .io_init = rk29_sdmmc0_cfg_gpio, + +#if !defined(CONFIG_SDMMC_RK29_OLD) + .set_iomux = rk29_sdmmc_set_iomux, +#endif + + .dma_name = "sd_mmc", +#ifdef CONFIG_SDMMC0_USE_DMA + .use_dma = 1, +#else + .use_dma = 0, +#endif + .detect_irq = RK30_PIN3_PB6, // INVALID_GPIO + .enable_sd_wakeup = 0, + +#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) + .write_prt = SDMMC0_WRITE_PROTECT_PIN, +#else + .write_prt = INVALID_GPIO, +#endif +}; +#endif // CONFIG_SDMMC0_RK29 + +#ifdef CONFIG_SDMMC1_RK29 +#define CONFIG_SDMMC1_USE_DMA +static int rk29_sdmmc1_cfg_gpio(void) +{ +#if defined(CONFIG_SDMMC_RK29_OLD) + rk30_mux_api_set(GPIO3C0_SMMC1CMD_NAME, GPIO3C_SMMC1_CMD); + rk30_mux_api_set(GPIO3C5_SDMMC1CLKOUT_NAME, GPIO3C_SDMMC1_CLKOUT); + rk30_mux_api_set(GPIO3C1_SDMMC1DATA0_NAME, GPIO3C_SDMMC1_DATA0); + rk30_mux_api_set(GPIO3C2_SDMMC1DATA1_NAME, GPIO3C_SDMMC1_DATA1); + rk30_mux_api_set(GPIO3C3_SDMMC1DATA2_NAME, GPIO3C_SDMMC1_DATA2); + rk30_mux_api_set(GPIO3C4_SDMMC1DATA3_NAME, GPIO3C_SDMMC1_DATA3); + //rk30_mux_api_set(GPIO3C6_SDMMC1DETECTN_NAME, GPIO3C_SDMMC1_DETECT_N); + +#else + +#if defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT) + gpio_request(SDMMC1_WRITE_PROTECT_PIN, "sdio-wp"); + gpio_direction_input(SDMMC1_WRITE_PROTECT_PIN); +#endif + +#endif + + return 0; +} + +struct rk29_sdmmc_platform_data default_sdmmc1_data = { + .host_ocr_avail = + (MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 | MMC_VDD_28_29 | + MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | + MMC_VDD_33_34), + +#if !defined(CONFIG_USE_SDMMC1_FOR_WIFI_DEVELOP_BOARD) + .host_caps = (MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ | + MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), +#else + .host_caps = + (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), +#endif + + .io_init = rk29_sdmmc1_cfg_gpio, + +#if !defined(CONFIG_SDMMC_RK29_OLD) + .set_iomux = rk29_sdmmc_set_iomux, +#endif + + .dma_name = "sdio", +#ifdef CONFIG_SDMMC1_USE_DMA + .use_dma = 1, +#else + .use_dma = 0, +#endif + +#if !defined(CONFIG_USE_SDMMC1_FOR_WIFI_DEVELOP_BOARD) +#ifdef CONFIG_WIFI_CONTROL_FUNC + .status = rk29sdk_wifi_status, + .register_status_notify = rk29sdk_wifi_status_register, +#endif +#if 0 + .detect_irq = RK29SDK_WIFI_SDIO_CARD_DETECT_N, +#endif + +#if defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT) + .write_prt = SDMMC1_WRITE_PROTECT_PIN, +#else + .write_prt = INVALID_GPIO, +#endif + +#else + .detect_irq = INVALID_GPIO, + .enable_sd_wakeup = 0, +#endif + +}; +#endif //endif--#ifdef CONFIG_SDMMC1_RK29 + +/************************************************************************************************** + * the end of setting for SDMMC devices +**************************************************************************************************/ + +#ifdef CONFIG_BATTERY_RK30_ADC +static struct rk30_adc_battery_platform_data rk30_adc_battery_platdata = { + .dc_det_pin = RK30_PIN0_PB2, + .batt_low_pin = RK30_PIN0_PB1, + .charge_set_pin = INVALID_GPIO, + .charge_ok_pin = RK30_PIN0_PA6, + .dc_det_level = GPIO_LOW, + .charge_ok_level = GPIO_HIGH, +}; + +static struct platform_device rk30_device_adc_battery = { + .name = "rk30-battery", + .id = -1, + .dev = { + .platform_data = &rk30_adc_battery_platdata, + }, +}; +#endif + +#ifdef CONFIG_RK29_VMAC +#define PHY_PWR_EN_GPIO RK30_PIN1_PD6 +#include "board-rk30-sdk-vmac.c" +#endif + +#ifdef CONFIG_RFKILL_RK +// bluetooth rfkill device, its driver in net/rfkill/rfkill-rk.c +static struct rfkill_rk_platform_data rfkill_rk_platdata = { + .type = RFKILL_TYPE_BLUETOOTH, + + .poweron_gpio = { // BT_REG_ON + .io = RK30_PIN3_PC6, + .enable = GPIO_HIGH, + .iomux = { + .name = GPIO3C6_SDMMC1DETECTN_RMIIRXERR_NAME, + .fgpio = GPIO3C_GPIO3C6, + }, + }, + + .reset_gpio = { // BT_RST + .io = RK30_PIN3_PD0, // set io to INVALID_GPIO for disable it + .enable = GPIO_LOW, + .iomux = { + .name = GPIO3D0_SDMMC1PWREN_MIIMD_NAME, + .fgpio = GPIO3D_GPIO3D0, + }, + }, + + .wake_gpio = { // BT_WAKE, use to control bt's sleep and wakeup + .io = RK30_PIN3_PC5, // set io to INVALID_GPIO for disable it + .enable = GPIO_HIGH, + .iomux = { + .name = GPIO3C5_SDMMC1CLKOUT_RMIICLKOUT_RMIICLKIN_NAME, + .fgpio = GPIO3C_GPIO3C5, + }, + }, + + .wake_host_irq = { // BT_HOST_WAKE, for bt wakeup host when it is in deep sleep + .gpio = { + .io = RK30_PIN0_PA5, // set io to INVALID_GPIO for disable it + .enable = GPIO_LOW, // set GPIO_LOW for falling, set 0 for rising + .iomux = { + .name = NULL, + }, + }, + }, + + .rts_gpio = { // UART_RTS, enable or disable BT's data coming + .io = RK30_PIN1_PA3, // set io to INVALID_GPIO for disable it + .enable = GPIO_LOW, + .iomux = { + .name = GPIO1A3_UART0RTSN_NAME, + .fgpio = GPIO1A_GPIO1A3, + .fmux = GPIO1A_UART0RTSN, + }, + }, +}; + +static struct platform_device device_rfkill_rk = { + .name = "rfkill_rk", + .id = -1, + .dev = { + .platform_data = &rfkill_rk_platdata, + }, +}; +#endif + +static struct platform_device *devices[] __initdata = { +#ifdef CONFIG_BACKLIGHT_RK29_BL + &rk29_device_backlight, +#endif +#ifdef CONFIG_FB_ROCKCHIP + &device_fb, +#endif +#ifdef CONFIG_ION + &device_ion, +#endif +#ifdef CONFIG_ANDROID_TIMED_GPIO + &rk29_device_vibrator, +#endif +#ifdef CONFIG_LEDS_GPIO_PLATFORM + &rk29_device_gpio_leds, +#endif +#ifdef CONFIG_RK_IRDA + &irda_device, +#endif +#ifdef CONFIG_WIFI_CONTROL_FUNC + &rk29sdk_wifi_device, +#endif +#ifdef CONFIG_RK29_SUPPORT_MODEM + &rk30_device_modem, +#endif +#if defined(CONFIG_MU509) + &rk29_device_mu509, +#endif +#if defined(CONFIG_MW100) + &rk29_device_mw100, +#endif +#if defined(CONFIG_MT6229) + &rk29_device_mt6229, +#endif +#ifdef CONFIG_BATTERY_RK30_ADC + &rk30_device_adc_battery, +#endif +#ifdef CONFIG_RFKILL_RK + &device_rfkill_rk, +#endif +}; + +// i2c +#ifdef CONFIG_I2C0_RK30 +static struct i2c_board_info __initdata i2c0_info[] = { +#if defined (CONFIG_GS_MMA8452) + { + .type = "gs_mma8452", + .addr = 0x1d, + .flags = 0, + .irq = MMA8452_INT_PIN, + .platform_data = &mma8452_info, + }, +#endif +#if defined (CONFIG_GS_LIS3DH) + { + .type = "gs_lis3dh", + .addr = 0x19, //0x19(SA0-->VCC), 0x18(SA0-->GND) + .flags = 0, + .irq = LIS3DH_INT_PIN, + .platform_data = &lis3dh_info, + }, +#endif +#if defined (CONFIG_COMPASS_AK8975) + { + .type = "ak8975", + .addr = 0x0d, + .flags = 0, + .irq = RK30_PIN0_PD5, + .platform_data = &akm8975_info, + }, +#endif +#if defined (CONFIG_GYRO_L3G4200D) + { + .type = "l3g4200d_gryo", + .addr = 0x69, + .flags = 0, + .irq = L3G4200D_INT_PIN, + .platform_data = &l3g4200d_info, + }, +#endif +#if defined (CONFIG_SND_SOC_RK1000) + { + .type = "rk1000_i2c_codec", + .addr = 0x60, + .flags = 0, + }, + { + .type = "rk1000_control", + .addr = 0x40, + .flags = 0, + }, +#endif +#if defined (CONFIG_SND_SOC_RT5631) + { + .type = "rt5631", + .addr = 0x1a, + .flags = 0, + }, +#endif + +#ifdef CONFIG_MFD_RK610 + { + .type = "rk610_ctl", + .addr = 0x40, + .flags = 0, + }, +#ifdef CONFIG_RK610_TVOUT + { + .type = "rk610_tvout", + .addr = 0x42, + .flags = 0, + }, +#endif +#ifdef CONFIG_RK610_HDMI + { + .type = "rk610_hdmi", + .addr = 0x46, + .flags = 0, + .irq = RK29_PIN5_PA2, + }, +#endif +#ifdef CONFIG_SND_SOC_RK610 + {//RK610_CODEC addr from 0x60 to 0x80 (0x60~0x80) + .type = "rk610_i2c_codec", + .addr = 0x60, + .flags = 0, + }, +#endif +#endif + +}; +#endif + +#ifdef CONFIG_I2C1_RK30 +#include "board-rk3066b-sdk-wm8326.c" + +static struct i2c_board_info __initdata i2c1_info[] = { +#if defined (CONFIG_MFD_WM831X_I2C) + { + .type = "wm8326", + .addr = 0x34, + .flags = 0, + .irq = RK30_PIN0_PB3, + .platform_data = &wm831x_platdata, + }, +#endif +}; +#endif + +#ifdef CONFIG_I2C2_RK30 +static struct i2c_board_info __initdata i2c2_info[] = { +#if defined (CONFIG_TOUCHSCREEN_GT8XX) + { + .type = "Goodix-TS", + .addr = 0x55, + .flags = 0, + .irq = RK30_PIN0_PD4, + .platform_data = &goodix_info, + }, +#endif +#if defined (CONFIG_LS_CM3217) + { + .type = "lightsensor", + .addr = 0x10, + .flags = 0, + .platform_data = &cm3217_info, + }, +#endif +}; +#endif + +#ifdef CONFIG_I2C3_RK30 +static struct i2c_board_info __initdata i2c3_info[] = { +}; +#endif + +#ifdef CONFIG_I2C4_RK30 +static struct i2c_board_info __initdata i2c4_info[] = { +}; +#endif + +#ifdef CONFIG_I2C_GPIO_RK30 +#define I2C_SDA_PIN INVALID_GPIO// RK30_PIN2_PD6 //set sda_pin here +#define I2C_SCL_PIN INVALID_GPIO//RK30_PIN2_PD7 //set scl_pin here +static int rk30_i2c_io_init(void) +{ + //set iomux (gpio) here + //rk30_mux_api_set(GPIO2D7_I2C1SCL_NAME, GPIO2D_GPIO2D7); + //rk30_mux_api_set(GPIO2D6_I2C1SDA_NAME, GPIO2D_GPIO2D6); + + return 0; +} +struct i2c_gpio_platform_data default_i2c_gpio_data = { + .sda_pin = I2C_SDA_PIN, + .scl_pin = I2C_SCL_PIN, + .udelay = 5, // clk = 500/udelay = 100Khz + .timeout = 100,//msecs_to_jiffies(100), + .bus_num = 5, + .io_init = rk30_i2c_io_init, +}; +static struct i2c_board_info __initdata i2c_gpio_info[] = { +}; +#endif + +static void __init rk30_i2c_register_board_info(void) +{ +#ifdef CONFIG_I2C0_RK30 + i2c_register_board_info(0, i2c0_info, ARRAY_SIZE(i2c0_info)); +#endif +#ifdef CONFIG_I2C1_RK30 + i2c_register_board_info(1, i2c1_info, ARRAY_SIZE(i2c1_info)); +#endif +#ifdef CONFIG_I2C2_RK30 + i2c_register_board_info(2, i2c2_info, ARRAY_SIZE(i2c2_info)); +#endif +#ifdef CONFIG_I2C3_RK30 + i2c_register_board_info(3, i2c3_info, ARRAY_SIZE(i2c3_info)); +#endif +#ifdef CONFIG_I2C4_RK30 + i2c_register_board_info(4, i2c4_info, ARRAY_SIZE(i2c4_info)); +#endif +#ifdef CONFIG_I2C_GPIO_RK30 + i2c_register_board_info(5, i2c_gpio_info, ARRAY_SIZE(i2c_gpio_info)); +#endif +} +//end of i2c + +#define POWER_ON_PIN RK30_PIN0_PA0 //power_hold +static void rk30_pm_power_off(void) +{ + printk(KERN_ERR "rk30_pm_power_off start...\n"); + gpio_direction_output(POWER_ON_PIN, GPIO_LOW); +#if defined(CONFIG_MFD_WM831X) + wm831x_set_bits(Wm831x,WM831X_GPIO_LEVEL,0x0001,0x0000); //set sys_pwr 0 + wm831x_device_shutdown(Wm831x);//wm8326 shutdown +#endif + while (1); +} + +static void __init machine_rk30_board_init(void) +{ + avs_init(); + gpio_request(POWER_ON_PIN, "poweronpin"); + gpio_direction_output(POWER_ON_PIN, GPIO_HIGH); + + pm_power_off = rk30_pm_power_off; + + rk30_i2c_register_board_info(); + spi_register_board_info(board_spi_devices, ARRAY_SIZE(board_spi_devices)); + platform_add_devices(devices, ARRAY_SIZE(devices)); + board_usb_detect_init(RK30_PIN0_PA7); + +#ifdef CONFIG_WIFI_CONTROL_FUNC + rk29sdk_wifi_bt_gpio_control_init(); +#endif +} + +static void __init rk30_reserve(void) +{ +#ifdef CONFIG_ION + rk30_ion_pdata.heaps[0].base = board_mem_reserve_add("ion", ION_RESERVE_SIZE); +#endif +#ifdef CONFIG_FB_ROCKCHIP + resource_fb[0].start = board_mem_reserve_add("fb0", RK30_FB0_MEM_SIZE); + resource_fb[0].end = resource_fb[0].start + RK30_FB0_MEM_SIZE - 1; + resource_fb[1].start = board_mem_reserve_add("ipp buf", RK30_FB0_MEM_SIZE); + resource_fb[1].end = resource_fb[1].start + RK30_FB0_MEM_SIZE - 1; + resource_fb[2].start = board_mem_reserve_add("fb2", RK30_FB0_MEM_SIZE); + resource_fb[2].end = resource_fb[2].start + RK30_FB0_MEM_SIZE - 1; +#endif +#ifdef CONFIG_VIDEO_RK29 + rk30_camera_request_reserve_mem(); +#endif + board_mem_reserved(); +} + +/** + * dvfs_cpu_logic_table: table for arm and logic dvfs + * @frequency : arm frequency + * @cpu_volt : arm voltage depend on frequency + * @logic_volt : logic voltage arm requests depend on frequency + * comments : min arm/logic voltage + */ +static struct dvfs_arm_table dvfs_cpu_logic_table[] = { + {.frequency = 252 * 1000, .cpu_volt = 1075 * 1000, .logic_volt = 1125 * 1000},//0.975V/1.000V + {.frequency = 504 * 1000, .cpu_volt = 1100 * 1000, .logic_volt = 1125 * 1000},//0.975V/1.000V + {.frequency = 816 * 1000, .cpu_volt = 1125 * 1000, .logic_volt = 1150 * 1000},//1.000V/1.025V + {.frequency = 1008 * 1000, .cpu_volt = 1125 * 1000, .logic_volt = 1150 * 1000},//1.025V/1.050V + {.frequency = 1200 * 1000, .cpu_volt = 1175 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V + {.frequency = 1272 * 1000, .cpu_volt = 1225 * 1000, .logic_volt = 1200 * 1000},//1.150V/1.100V + {.frequency = 1416 * 1000, .cpu_volt = 1300 * 1000, .logic_volt = 1200 * 1000},//1.225V/1.100V + {.frequency = 1512 * 1000, .cpu_volt = 1350 * 1000, .logic_volt = 1250 * 1000},//1.300V/1.150V + {.frequency = 1608 * 1000, .cpu_volt = 1425 * 1000, .logic_volt = 1300 * 1000},//1.325V/1.175V + {.frequency = CPUFREQ_TABLE_END}, +}; + +static struct cpufreq_frequency_table dvfs_gpu_table[] = { + {.frequency = 266 * 1000, .index = 1050 * 1000}, + {.frequency = 400 * 1000, .index = 1275 * 1000}, + {.frequency = CPUFREQ_TABLE_END}, +}; + +static struct cpufreq_frequency_table dvfs_ddr_table[] = { + {.frequency = 300 * 1000, .index = 1050 * 1000}, + {.frequency = 400 * 1000, .index = 1125 * 1000}, + {.frequency = CPUFREQ_TABLE_END}, +}; + +#define DVFS_CPU_TABLE_SIZE (ARRAY_SIZE(dvfs_cpu_logic_table)) +static struct cpufreq_frequency_table cpu_dvfs_table[DVFS_CPU_TABLE_SIZE]; +static struct cpufreq_frequency_table dep_cpu2core_table[DVFS_CPU_TABLE_SIZE]; + +void __init board_clock_init(void) +{ + rk30_clock_data_init(periph_pll_default, codec_pll_default, RK30_CLOCKS_DEFAULT_FLAGS); + dvfs_set_arm_logic_volt(dvfs_cpu_logic_table, cpu_dvfs_table, dep_cpu2core_table); + dvfs_set_freq_volt_table(clk_get(NULL, "gpu"), dvfs_gpu_table); + dvfs_set_freq_volt_table(clk_get(NULL, "ddr"), dvfs_ddr_table); +} + +MACHINE_START(RK30, "RK30board") + .boot_params = PLAT_PHYS_OFFSET + 0x800, + .fixup = rk30_fixup, + .reserve = &rk30_reserve, + .map_io = rk30_map_io, + .init_irq = rk30_init_irq, + .timer = &rk30_timer, + .init_machine = machine_rk30_board_init, +MACHINE_END diff --git a/arch/arm/mach-rk30/board-rk31-fpga.c b/arch/arm/mach-rk30/board-rk31-fpga.c index bc4a3c22f344..0288970da293 100644 --- a/arch/arm/mach-rk30/board-rk31-fpga.c +++ b/arch/arm/mach-rk30/board-rk31-fpga.c @@ -754,7 +754,7 @@ static struct platform_device *devices[] __initdata = { * SDMMC devices, include the module of SD,MMC,and sdio.noted by xbw at 2012-03-05 **************************************************************************************************/ #ifdef CONFIG_SDMMC_RK29 -#include "board-rk30-sdk-sdmmc.c" +#include "board-rk3066b-sdk-sdmmc.c" #if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) #define SDMMC0_WRITE_PROTECT_PIN RK30_PIN3_PB7 //According to your own project to set the value of write-protect-pin. diff --git a/arch/arm/mach-rk30/clock.h b/arch/arm/mach-rk30/clock.h index fdecd15d4975..a7f2de30c9f8 100644 --- a/arch/arm/mach-rk30/clock.h +++ b/arch/arm/mach-rk30/clock.h @@ -1,7 +1,7 @@ #ifndef __MACH_CLOCK_H__ #define __MACH_CLOCK_H__ -#ifndef CONFIG_ARCH_RK30 +#if (!defined(CONFIG_ARCH_RK30) && !defined(CONFIG_ARCH_RK31)) #define RK30_CLK_OFFBOARD_TEST #endif diff --git a/sound/soc/codecs/rk610_codec.c b/sound/soc/codecs/rk610_codec.c index 6be43cfad000..70ce8727422b 100755 --- a/sound/soc/codecs/rk610_codec.c +++ b/sound/soc/codecs/rk610_codec.c @@ -44,6 +44,8 @@ #ifdef CONFIG_ARCH_RK30 #define RK610_SPK_CTRL_PIN RK30_PIN4_PC6 +#elif defined(CONFIG_ARCH_RK31) +#define RK610_SPK_CTRL_PIN RK30_PIN2_PA0 #else #define RK610_SPK_CTRL_PIN RK29_PIN6_PB6 #endif From 4b8505896020e2fd8398db594f312114c8476526 Mon Sep 17 00:00:00 2001 From: ddl Date: Tue, 14 Aug 2012 15:11:25 +0800 Subject: [PATCH 172/261] camera rk30: fix struct rk_camera_work may be reentrant,version update to v0.2.11, and add support sp2518 sensor --- arch/arm/plat-rk/include/plat/rk_camera.h | 3 + drivers/media/video/Kconfig | 13 +- drivers/media/video/Makefile | 1 + drivers/media/video/rk30_camera_oneframe.c | 653 ++-- drivers/media/video/sp2518.c | 3293 ++++++++++++++++++++ include/media/v4l2-chip-ident.h | 31 +- 6 files changed, 3580 insertions(+), 414 deletions(-) create mode 100755 drivers/media/video/sp2518.c diff --git a/arch/arm/plat-rk/include/plat/rk_camera.h b/arch/arm/plat-rk/include/plat/rk_camera.h index 2a1dca105a2f..d4659d3f4708 100755 --- a/arch/arm/plat-rk/include/plat/rk_camera.h +++ b/arch/arm/plat-rk/include/plat/rk_camera.h @@ -66,6 +66,7 @@ #define RK29_CAM_SENSOR_HI704 hi704 #define RK29_CAM_SENSOR_NT99250 nt99250 #define RK29_CAM_SENSOR_SP0838 sp0838 +#define RK29_CAM_SENSOR_SP2518 sp2518 #define RK29_CAM_SENSOR_GC0329 gc0329 #define RK29_CAM_SENSOR_S5K5CA s5k5ca @@ -97,6 +98,7 @@ #define RK29_CAM_SENSOR_NAME_HI704 "hi704" #define RK29_CAM_SENSOR_NAME_NT99250 "nt99250" #define RK29_CAM_SENSOR_NAME_SP0838 "sp0838" +#define RK29_CAM_SENSOR_NAME_SP2518 "sp2518" #define RK29_CAM_SENSOR_NAME_GC0329 "gc0329" #define RK29_CAM_SENSOR_NAME_S5K5CA "s5k5ca" @@ -126,6 +128,7 @@ #define hi704_FULL_RESOLUTION 0x30000 // 0.3 megapixel #define nt99250_FULL_RESOLUTION 0x200000 // 2 megapixel #define sp0838_FULL_RESOLUTION 0x30000 // 0.3 megapixel +#define sp2518_FULL_RESOLUTION 0x200000 // 2 megapixel #define gc0329_FULL_RESOLUTION 0x30000 // 0.3 megapixel #define s5k5ca_FULL_RESOLUTION 0x300000 // 3 megapixel /*---------------- Camera Sensor Must Define Macro End ------------------------*/ diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index f3d35931decd..491fb082e5df 100755 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -1251,11 +1251,22 @@ config SOC_CAMERA_SP0838 help This is a sp0838 camera driver for rockchip -config S5K5CA_USER_DEFINED_SERIES +config SP0838_USER_DEFINED_SERIES depends on SOC_CAMERA_SP0838 bool "sp0838 user defined init series" default n +config SOC_CAMERA_SP2518 + tristate "sp2518 camera support for rockchip" + depends on SOC_CAMERA && I2C + help + This is a sp2518 camera driver for rockchip + +config SP2518_USER_DEFINED_SERIES + depends on SOC_CAMERA_SP2518 + bool "sp2518 user defined init series" + default n + config SOC_CAMERA_OV9640 tristate "ov9640 camera support" diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 30585000fc03..a2f53c3ed0af 100755 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -115,6 +115,7 @@ obj-$(CONFIG_SOC_CAMERA_HI704) += hi704.o obj-$(CONFIG_SOC_CAMERA_NT99250) += nt99250.o obj-$(CONFIG_SOC_CAMERA_GC0329) += gc0329.o obj-$(CONFIG_SOC_CAMERA_SP0838) += sp0838.o +obj-$(CONFIG_SOC_CAMERA_SP2518) += sp2518.o obj-$(CONFIG_SOC_CAMERA_S5K5CA) += s5k5ca.o # And now the v4l2 drivers: diff --git a/drivers/media/video/rk30_camera_oneframe.c b/drivers/media/video/rk30_camera_oneframe.c index bb58c49aa3ec..2a77b42d67d9 100755 --- a/drivers/media/video/rk30_camera_oneframe.c +++ b/drivers/media/video/rk30_camera_oneframe.c @@ -53,105 +53,105 @@ module_param(debug, int, S_IRUGO|S_IWUSR); #define RKCAMERA_DG(format, ...) dprintk(1, format, ## __VA_ARGS__) // CIF Reg Offset -#define CIF_CIF_CTRL 0x00 -#define CIF_CIF_INTEN 0x04 -#define CIF_CIF_INTSTAT 0x08 -#define CIF_CIF_FOR 0x0c -#define CIF_CIF_LINE_NUM_ADDR 0x10 -#define CIF_CIF_FRM0_ADDR_Y 0x14 -#define CIF_CIF_FRM0_ADDR_UV 0x18 -#define CIF_CIF_FRM1_ADDR_Y 0x1c -#define CIF_CIF_FRM1_ADDR_UV 0x20 -#define CIF_CIF_VIR_LINE_WIDTH 0x24 -#define CIF_CIF_SET_SIZE 0x28 -#define CIF_CIF_SCM_ADDR_Y 0x2c -#define CIF_CIF_SCM_ADDR_U 0x30 -#define CIF_CIF_SCM_ADDR_V 0x34 -#define CIF_CIF_WB_UP_FILTER 0x38 -#define CIF_CIF_WB_LOW_FILTER 0x3c +#define CIF_CIF_CTRL 0x00 +#define CIF_CIF_INTEN 0x04 +#define CIF_CIF_INTSTAT 0x08 +#define CIF_CIF_FOR 0x0c +#define CIF_CIF_LINE_NUM_ADDR 0x10 +#define CIF_CIF_FRM0_ADDR_Y 0x14 +#define CIF_CIF_FRM0_ADDR_UV 0x18 +#define CIF_CIF_FRM1_ADDR_Y 0x1c +#define CIF_CIF_FRM1_ADDR_UV 0x20 +#define CIF_CIF_VIR_LINE_WIDTH 0x24 +#define CIF_CIF_SET_SIZE 0x28 +#define CIF_CIF_SCM_ADDR_Y 0x2c +#define CIF_CIF_SCM_ADDR_U 0x30 +#define CIF_CIF_SCM_ADDR_V 0x34 +#define CIF_CIF_WB_UP_FILTER 0x38 +#define CIF_CIF_WB_LOW_FILTER 0x3c #define CIF_CIF_WBC_CNT 0x40 -#define CIF_CIF_CROP 0x44 -#define CIF_CIF_SCL_CTRL 0x48 -#define CIF_CIF_SCL_DST 0x4c -#define CIF_CIF_SCL_FCT 0x50 -#define CIF_CIF_SCL_VALID_NUM 0x54 -#define CIF_CIF_LINE_LOOP_CTR 0x58 -#define CIF_CIF_FRAME_STATUS 0x60 -#define CIF_CIF_CUR_DST 0x64 -#define CIF_CIF_LAST_LINE 0x68 -#define CIF_CIF_LAST_PIX 0x6c +#define CIF_CIF_CROP 0x44 +#define CIF_CIF_SCL_CTRL 0x48 +#define CIF_CIF_SCL_DST 0x4c +#define CIF_CIF_SCL_FCT 0x50 +#define CIF_CIF_SCL_VALID_NUM 0x54 +#define CIF_CIF_LINE_LOOP_CTR 0x58 +#define CIF_CIF_FRAME_STATUS 0x60 +#define CIF_CIF_CUR_DST 0x64 +#define CIF_CIF_LAST_LINE 0x68 +#define CIF_CIF_LAST_PIX 0x6c //The key register bit descrition // CIF_CTRL Reg , ignore SCM,WBC,ISP, #define DISABLE_CAPTURE (0x00<<0) #define ENABLE_CAPTURE (0x01<<0) -#define MODE_ONEFRAME (0x00<<1) -#define MODE_PINGPONG (0x01<<1) -#define MODE_LINELOOP (0x02<<1) -#define AXI_BURST_16 (0x0F << 12) +#define MODE_ONEFRAME (0x00<<1) +#define MODE_PINGPONG (0x01<<1) +#define MODE_LINELOOP (0x02<<1) +#define AXI_BURST_16 (0x0F << 12) //CIF_CIF_INTEN -#define FRAME_END_EN (0x01<<1) -#define BUS_ERR_EN (0x01<<6) -#define SCL_ERR_EN (0x01<<7) +#define FRAME_END_EN (0x01<<1) +#define BUS_ERR_EN (0x01<<6) +#define SCL_ERR_EN (0x01<<7) //CIF_CIF_FOR -#define VSY_HIGH_ACTIVE (0x01<<0) -#define VSY_LOW_ACTIVE (0x00<<0) -#define HSY_LOW_ACTIVE (0x01<<1) -#define HSY_HIGH_ACTIVE (0x00<<1) -#define INPUT_MODE_YUV (0x00<<2) -#define INPUT_MODE_PAL (0x02<<2) -#define INPUT_MODE_NTSC (0x03<<2) -#define INPUT_MODE_RAW (0x04<<2) -#define INPUT_MODE_JPEG (0x05<<2) -#define INPUT_MODE_MIPI (0x06<<2) -#define YUV_INPUT_ORDER_UYVY(ori) (ori & (~(0x03<<5))) -#define YUV_INPUT_ORDER_YVYU(ori) ((ori & (~(0x01<<6)))|(0x01<<5)) -#define YUV_INPUT_ORDER_VYUY(ori) ((ori & (~(0x01<<5))) | (0x1<<6)) -#define YUV_INPUT_ORDER_YUYV(ori) (ori|(0x03<<5)) -#define YUV_INPUT_422 (0x00<<7) -#define YUV_INPUT_420 (0x01<<7) -#define INPUT_420_ORDER_EVEN (0x00<<8) -#define INPUT_420_ORDER_ODD (0x01<<8) -#define CCIR_INPUT_ORDER_ODD (0x00<<9) -#define CCIR_INPUT_ORDER_EVEN (0x01<<9) -#define RAW_DATA_WIDTH_8 (0x00<<11) -#define RAW_DATA_WIDTH_10 (0x01<<11) -#define RAW_DATA_WIDTH_12 (0x02<<11) -#define YUV_OUTPUT_422 (0x00<<16) -#define YUV_OUTPUT_420 (0x01<<16) -#define OUTPUT_420_ORDER_EVEN (0x00<<17) -#define OUTPUT_420_ORDER_ODD (0x01<<17) -#define RAWD_DATA_LITTLE_ENDIAN (0x00<<18) -#define RAWD_DATA_BIG_ENDIAN (0x01<<18) -#define UV_STORAGE_ORDER_UVUV (0x00<<19) -#define UV_STORAGE_ORDER_VUVU (0x01<<19) +#define VSY_HIGH_ACTIVE (0x01<<0) +#define VSY_LOW_ACTIVE (0x00<<0) +#define HSY_LOW_ACTIVE (0x01<<1) +#define HSY_HIGH_ACTIVE (0x00<<1) +#define INPUT_MODE_YUV (0x00<<2) +#define INPUT_MODE_PAL (0x02<<2) +#define INPUT_MODE_NTSC (0x03<<2) +#define INPUT_MODE_RAW (0x04<<2) +#define INPUT_MODE_JPEG (0x05<<2) +#define INPUT_MODE_MIPI (0x06<<2) +#define YUV_INPUT_ORDER_UYVY(ori) (ori & (~(0x03<<5))) +#define YUV_INPUT_ORDER_YVYU(ori) ((ori & (~(0x01<<6)))|(0x01<<5)) +#define YUV_INPUT_ORDER_VYUY(ori) ((ori & (~(0x01<<5))) | (0x1<<6)) +#define YUV_INPUT_ORDER_YUYV(ori) (ori|(0x03<<5)) +#define YUV_INPUT_422 (0x00<<7) +#define YUV_INPUT_420 (0x01<<7) +#define INPUT_420_ORDER_EVEN (0x00<<8) +#define INPUT_420_ORDER_ODD (0x01<<8) +#define CCIR_INPUT_ORDER_ODD (0x00<<9) +#define CCIR_INPUT_ORDER_EVEN (0x01<<9) +#define RAW_DATA_WIDTH_8 (0x00<<11) +#define RAW_DATA_WIDTH_10 (0x01<<11) +#define RAW_DATA_WIDTH_12 (0x02<<11) +#define YUV_OUTPUT_422 (0x00<<16) +#define YUV_OUTPUT_420 (0x01<<16) +#define OUTPUT_420_ORDER_EVEN (0x00<<17) +#define OUTPUT_420_ORDER_ODD (0x01<<17) +#define RAWD_DATA_LITTLE_ENDIAN (0x00<<18) +#define RAWD_DATA_BIG_ENDIAN (0x01<<18) +#define UV_STORAGE_ORDER_UVUV (0x00<<19) +#define UV_STORAGE_ORDER_VUVU (0x01<<19) //CIF_CIF_SCL_CTRL -#define ENABLE_SCL_DOWN (0x01<<0) -#define DISABLE_SCL_DOWN (0x00<<0) -#define ENABLE_SCL_UP (0x01<<1) -#define DISABLE_SCL_UP (0x00<<1) -#define ENABLE_YUV_16BIT_BYPASS (0x01<<4) -#define DISABLE_YUV_16BIT_BYPASS (0x00<<4) -#define ENABLE_RAW_16BIT_BYPASS (0x01<<5) -#define DISABLE_RAW_16BIT_BYPASS (0x00<<5) -#define ENABLE_32BIT_BYPASS (0x01<<6) -#define DISABLE_32BIT_BYPASS (0x00<<6) +#define ENABLE_SCL_DOWN (0x01<<0) +#define DISABLE_SCL_DOWN (0x00<<0) +#define ENABLE_SCL_UP (0x01<<1) +#define DISABLE_SCL_UP (0x00<<1) +#define ENABLE_YUV_16BIT_BYPASS (0x01<<4) +#define DISABLE_YUV_16BIT_BYPASS (0x00<<4) +#define ENABLE_RAW_16BIT_BYPASS (0x01<<5) +#define DISABLE_RAW_16BIT_BYPASS (0x00<<5) +#define ENABLE_32BIT_BYPASS (0x01<<6) +#define DISABLE_32BIT_BYPASS (0x00<<6) //CRU,PIXCLOCK -#define CRU_PCLK_REG30 0xbc -#define ENANABLE_INVERT_PCLK_CIF0 ((0x1<<24)|(0x1<<8)) -#define DISABLE_INVERT_PCLK_CIF0 ((0x1<<24)|(0x0<<8)) -#define ENANABLE_INVERT_PCLK_CIF1 ((0x1<<28)|(0x1<<12)) -#define DISABLE_INVERT_PCLK_CIF1 ((0x1<<28)|(0x0<<12)) +#define CRU_PCLK_REG30 0xbc +#define ENANABLE_INVERT_PCLK_CIF0 ((0x1<<24)|(0x1<<8)) +#define DISABLE_INVERT_PCLK_CIF0 ((0x1<<24)|(0x0<<8)) +#define ENANABLE_INVERT_PCLK_CIF1 ((0x1<<28)|(0x1<<12)) +#define DISABLE_INVERT_PCLK_CIF1 ((0x1<<28)|(0x0<<12)) -#define CRU_CIF_RST_REG30 0x128 -#define MASK_RST_CIF0 (0x01 << 30) -#define MASK_RST_CIF1 (0x01 << 31) -#define RQUEST_RST_CIF0 (0x01 << 14) -#define RQUEST_RST_CIF1 (0x01 << 15) +#define CRU_CIF_RST_REG30 0x128 +#define MASK_RST_CIF0 (0x01 << 30) +#define MASK_RST_CIF1 (0x01 << 31) +#define RQUEST_RST_CIF0 (0x01 << 14) +#define RQUEST_RST_CIF1 (0x01 << 15) #define MIN(x,y) ((xy) ? x: y) @@ -177,8 +177,8 @@ module_param(debug, int, S_IRUGO|S_IWUSR); #define CAM_IPPWORK_IS_EN() ((pcdev->zoominfo.a.c.width != pcdev->icd->user_width) || (pcdev->zoominfo.a.c.height != pcdev->icd->user_height)) #endif #else //CONFIG_VIDEO_RK29_WORK_IPP -#define CAM_WORKQUEUE_IS_EN() (false) -#define CAM_IPPWORK_IS_EN() (false) +#define CAM_WORKQUEUE_IS_EN() (false) +#define CAM_IPPWORK_IS_EN() (false) #endif #define IS_CIF0() (pcdev->hostid == RK_CAM_PLATFORM_DEV_ID_0) @@ -211,8 +211,9 @@ module_param(debug, int, S_IRUGO|S_IWUSR); 2. irq process is splitted to two step. *v0.x.e: fix bugs of early suspend when display_pd is closed. *v0.x.f: fix calculate ipp memory size is enough or not in try_fmt function; +*v0.x.11: fix struct rk_camera_work may be reentrant */ -#define RK_CAM_VERSION_CODE KERNEL_VERSION(0, 2, 0xf) +#define RK_CAM_VERSION_CODE KERNEL_VERSION(0, 2, 0x11) /* limit to rk29 hardware capabilities */ #define RK_CAM_BUS_PARAM (SOCAM_MASTER |\ @@ -268,6 +269,8 @@ struct rk_camera_work struct videobuf_buffer *vb; struct rk_camera_dev *pcdev; struct work_struct work; + struct list_head queue; + unsigned int index; }; struct rk_camera_frmivalenum { @@ -338,6 +341,8 @@ struct rk_camera_dev struct rk_camera_reg reginfo_suspend; struct workqueue_struct *camera_wq; struct rk_camera_work *camera_work; + struct list_head camera_work_queue; + spinlock_t camera_work_lock; unsigned int camera_work_count; struct rk_camera_timer fps_timer; struct rk_camera_work camera_reinit_work; @@ -387,6 +392,8 @@ static int rk_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, icd->current_fmt->host_fmt); int bytes_per_line_host = soc_mbus_bytes_per_line(pcdev->host_width, icd->current_fmt->host_fmt); + unsigned int i; + struct rk_camera_work *wk; dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size); @@ -394,7 +401,6 @@ static int rk_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, return bytes_per_line_host; /* planar capture requires Y, U and V buffers to be page aligned */ - //*size = PAGE_ALIGN(bytes_per_line*icd->user_height); /* Y pages UV pages, yuv422*/ *size = PAGE_ALIGN(bytes_per_line*icd->user_height); /* Y pages UV pages, yuv422*/ pcdev->vipmem_bsize = PAGE_ALIGN(bytes_per_line_host * pcdev->host_height); @@ -415,19 +421,21 @@ static int rk_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, } if (pcdev->camera_work == NULL) { - int wk_index = 0; - struct rk_camera_work *wk; - pcdev->camera_work = kmalloc(sizeof(struct rk_camera_work)*(*count), GFP_KERNEL); + pcdev->camera_work = wk = kzalloc(sizeof(struct rk_camera_work)*(*count), GFP_KERNEL); if (pcdev->camera_work == NULL) { RKCAMERA_TR("\n %s kmalloc fail\n", __FUNCTION__); BUG(); } - for(;wk_index < *count;wk_index++){ - wk = pcdev->camera_work+wk_index; - INIT_WORK(&wk->work, rk_camera_capture_process); - } - pcdev->camera_work_count = *count; + INIT_LIST_HEAD(&pcdev->camera_work_queue); + + for (i=0; i<(*count); i++) { + wk->index = i; + list_add_tail(&wk->queue, &pcdev->camera_work_queue); + wk++; + } + pcdev->camera_work_count = (*count); } + } pcdev->video_vq = vq; RKCAMERA_DG("%s..%d.. videobuf size:%d, vipmem_buf size:%d, count:%d \n",__FUNCTION__,__LINE__, *size,pcdev->vipmem_size, *count); @@ -471,15 +479,9 @@ static int rk_videobuf_prepare(struct videobuf_queue *vq, struct videobuf_buffer dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, vb, vb->baddr, vb->bsize); - - //RK29CAMERA_TR("\n%s..%d.. \n",__FUNCTION__,__LINE__); - + /* Added list head initialization on alloc */ - WARN_ON(!list_empty(&vb->queue)); - - /* This can be useful if you want to see if we actually fill - * the buffer with something */ - //memset((void *)vb->baddr, 0xaa, vb->bsize); + WARN_ON(!list_empty(&vb->queue)); BUG_ON(NULL == icd->current_fmt); @@ -507,7 +509,7 @@ static int rk_videobuf_prepare(struct videobuf_queue *vq, struct videobuf_buffer } vb->state = VIDEOBUF_PREPARED; } - //RK29CAMERA_TR("\n%s..%d.. \n",__FUNCTION__,__LINE__); + return 0; fail: rk_videobuf_free(vq, buf); @@ -535,7 +537,6 @@ static inline void rk_videobuf_capture(struct videobuf_buffer *vb,struct rk_came } write_cif_reg(pcdev->base,CIF_CIF_FRM0_ADDR_Y, y_addr); write_cif_reg(pcdev->base,CIF_CIF_FRM0_ADDR_UV, uv_addr); - //printk("y_addr = 0x%x, uv_addr = 0x%x \n",read_cif_reg(pcdev->base, CIF_CIF_FRM0_ADDR_Y),read_cif_reg(pcdev->base, CIF_CIF_FRM0_ADDR_UV)); write_cif_reg(pcdev->base,CIF_CIF_FRM1_ADDR_Y, y_addr); write_cif_reg(pcdev->base,CIF_CIF_FRM1_ADDR_UV, uv_addr); write_cif_reg(pcdev->base,CIF_CIF_FRAME_STATUS, 0x00000002);//frame1 has been ready to receive data,frame 2 is not used @@ -616,11 +617,9 @@ static void rk_camera_capture_process(struct work_struct *work) down(&pcdev->zoominfo.sem); ipp_req.timeout = 3000; ipp_req.flag = IPP_ROT_0; - // if(pcdev->icd->user_width != pcdev->zoominfo.vir_width) ipp_req.store_clip_mode =1; ipp_req.src0.w = pcdev->zoominfo.a.c.width/scale_times; ipp_req.src0.h = pcdev->zoominfo.a.c.height/scale_times; - //ipp_req.src_vir_w = pcdev->zoominfo.a.c.width; ipp_req.src_vir_w = pcdev->zoominfo.vir_width; rk_pixfmt2ippfmt(pcdev->pixfmt, &ipp_req.src0.fmt); ipp_req.dst0.w = pcdev->icd->user_width/scale_times; @@ -628,7 +627,6 @@ static void rk_camera_capture_process(struct work_struct *work) ipp_req.dst_vir_w = pcdev->icd->user_width; rk_pixfmt2ippfmt(pcdev->pixfmt, &ipp_req.dst0.fmt); vipdata_base = pcdev->vipmem_phybase + vb->i*pcdev->vipmem_bsize; - //src_y_size = pcdev->zoominfo.a.c.width*pcdev->zoominfo.a.c.height; src_y_size = pcdev->host_width*pcdev->host_height; //vipmem dst_y_size = pcdev->icd->user_width*pcdev->icd->user_height; for (h=0; hboff + dst_y_offset; ipp_req.dst0.CbrMst = vb->boff + dst_y_size + dst_uv_offset; - // printk("ipp_req.src0.YrgbMst = 0x%x , ipp_req.src0.CbrMst = 0x%x\n",ipp_req.src0.YrgbMst,ipp_req.src0.CbrMst); - // printk("ipp_req.dst0.YrgbMst = 0x%x , ipp_req.dst0.CbrMst = 0x%x\n",ipp_req.dst0.YrgbMst,ipp_req.dst0.CbrMst); - // printk("%dx%d@(%d,%d)->%dx%d\n",pcdev->zoominfo.a.c.width,pcdev->zoominfo.a.c.height,pcdev->zoominfo.a.c.left,pcdev->zoominfo.a.c.top,pcdev->icd->user_width,pcdev->icd->user_height); - // printk("ipp_req.src_vir_w:0x%x ipp_req.dst_vir_w :0x%x\n",ipp_req.src_vir_w ,ipp_req.dst_vir_w); - while(ipp_times-- > 0) - { + while(ipp_times-- > 0) { if (ipp_blit_sync(&ipp_req)){ RKCAMERA_TR("ipp do erro,do again,ipp_times = %d!\n",ipp_times); - } - else{ + } else { break; - } - } - if (ipp_times <= 0) - { + } + } + + if (ipp_times <= 0) { spin_lock_irqsave(&pcdev->lock, flags); vb->state = VIDEOBUF_NEEDS_INIT; spin_unlock_irqrestore(&pcdev->lock, flags); @@ -686,6 +678,9 @@ static void rk_camera_capture_process(struct work_struct *work) do_ipp_err: up(&pcdev->zoominfo.sem); wake_up(&(camera_work->vb->done)); + spin_lock_irqsave(&pcdev->camera_work_lock, flags); + list_add_tail(&camera_work->queue, &pcdev->camera_work_queue); + spin_unlock_irqrestore(&pcdev->camera_work_lock, flags); return; } static irqreturn_t rk_camera_irq(int irq, void *data) @@ -695,10 +690,8 @@ static irqreturn_t rk_camera_irq(int irq, void *data) struct rk_camera_work *wk; struct timeval tv; unsigned long tmp_intstat; - unsigned long tmp_cifctrl; - - - #if 1 + unsigned long tmp_cifctrl; + tmp_intstat = read_cif_reg(pcdev->base,CIF_CIF_INTSTAT); tmp_cifctrl = read_cif_reg(pcdev->base,CIF_CIF_CTRL); if(pcdev->stop_cif == true) @@ -713,7 +706,7 @@ static irqreturn_t rk_camera_irq(int irq, void *data) write_cif_reg(pcdev->base,CIF_CIF_CTRL, (tmp_cifctrl & ~ENABLE_CAPTURE)); return IRQ_HANDLED; } -#endif + /* ddl@rock-chps.com : Current VIP is run in One Frame Mode, Frame 1 is validate */ if (read_cif_reg(pcdev->base,CIF_CIF_FRAME_STATUS) & 0x01) { write_cif_reg(pcdev->base,CIF_CIF_INTSTAT,0x01); /* clear vip interrupte single */ @@ -748,17 +741,10 @@ static irqreturn_t rk_camera_irq(int irq, void *data) pcdev->active = NULL; if (!list_empty(&pcdev->capture)) { pcdev->active = list_entry(pcdev->capture.next, struct videobuf_buffer, queue); - if (pcdev->active && (pcdev->active->state == VIDEOBUF_QUEUED)) { + if (pcdev->active) { + WARN_ON(pcdev->active->state != VIDEOBUF_QUEUED); rk_videobuf_capture(pcdev->active,pcdev); } - else if(pcdev->active){ - printk("vb state is wrong ,del it \n"); - list_del_init(&(pcdev->active->queue)); - pcdev->active->state = VIDEOBUF_NEEDS_INIT; - wake_up(&pcdev->active->done); - pcdev->active = NULL; - - } } if (pcdev->active == NULL) { RKCAMERA_DG("%s video_buf queue is empty!\n",__FUNCTION__); @@ -770,11 +756,14 @@ static irqreturn_t rk_camera_irq(int irq, void *data) vb->field_count++; } if (CAM_WORKQUEUE_IS_EN()) { - wk = pcdev->camera_work + vb->i; - //INIT_WORK(&(wk->work), rk_camera_capture_process); - wk->vb = vb; - wk->pcdev = pcdev; - queue_work(pcdev->camera_wq, &(wk->work)); + if (!list_empty(&pcdev->camera_work_queue)) { + wk = list_entry(pcdev->camera_work_queue.next, struct rk_camera_work, queue); + list_del_init(&wk->queue); + INIT_WORK(&(wk->work), rk_camera_capture_process); + wk->vb = vb; + wk->pcdev = pcdev; + queue_work(pcdev->camera_wq, &(wk->work)); + } } else { wake_up(&vb->done); } @@ -815,13 +804,13 @@ static void rk_videobuf_release(struct videobuf_queue *vq, break; } #endif - if(vb->i == 0){ - // printk("flush work queue.......\n"); + if (vb->i == 0) { flush_workqueue(pcdev->camera_wq); - } + } + if (vb == pcdev->active) { RKCAMERA_DG("%s Wait for this video buf(0x%x) write finished!\n ",__FUNCTION__,(unsigned int)vb); - interruptible_sleep_on_timeout(&vb->done, 100); + interruptible_sleep_on_timeout(&vb->done, msecs_to_jiffies(500)); flush_workqueue(pcdev->camera_wq); RKCAMERA_DG("%s This video buf(0x%x) write finished, release now!!\n",__FUNCTION__,(unsigned int)vb); } @@ -919,8 +908,6 @@ static int rk_camera_activate(struct rk_camera_dev *pcdev, struct soc_camera_dev static void rk_camera_deactivate(struct rk_camera_dev *pcdev) { - //pcdev->active = NULL; - // printk("rk_camera_deactivate enter\n"); clk_disable(pcdev->aclk_cif); clk_disable(pcdev->hclk_cif); @@ -953,9 +940,8 @@ static int rk_camera_add_device(struct soc_camera_device *icd) goto ebusy; } - dev_info(&icd->dev, "RK Camera driver attached to camera%d(%s)\n", - icd->devnum,dev_name(icd->pdev)); - + RKCAMERA_DG("RK Camera driver attached to %s\n",dev_name(icd->pdev)); + pcdev->frame_inval = RK_CAM_FRAME_INVAL_INIT; pcdev->active = NULL; pcdev->icd = NULL; @@ -1005,7 +991,6 @@ static int rk_camera_add_device(struct soc_camera_device *icd) pcdev->icd_frmival[0].icd = icd; pcdev->icd_frmival[0].fival_list = kzalloc(sizeof(struct rk_camera_frmivalenum),GFP_KERNEL); } - RKCAMERA_TR("%s..%d.. \n",__FUNCTION__,__LINE__); ebusy: mutex_unlock(&camera_lock); @@ -1020,8 +1005,7 @@ static void rk_camera_remove_device(struct soc_camera_device *icd) mutex_lock(&camera_lock); BUG_ON(icd != pcdev->icd); - dev_info(&icd->dev, "RK Camera driver detached from camera%d(%s)\n", - icd->devnum,dev_name(icd->pdev)); + RKCAMERA_DG("RK Camera driver detached from %s\n",dev_name(icd->pdev)); /* ddl@rock-chips.com: Application will call VIDIOC_STREAMOFF before close device, but stream may be turn on again before close device, if suspend and resume happened. */ @@ -1044,7 +1028,7 @@ static void rk_camera_remove_device(struct soc_camera_device *icd) if(pcdev->fps_timer.istarted){ hrtimer_cancel(&pcdev->fps_timer.timer); pcdev->fps_timer.istarted = false; - } + } flush_work(&(pcdev->camera_reinit_work.work)); flush_workqueue((pcdev->camera_wq)); @@ -1052,6 +1036,7 @@ static void rk_camera_remove_device(struct soc_camera_device *icd) kfree(pcdev->camera_work); pcdev->camera_work = NULL; pcdev->camera_work_count = 0; + INIT_LIST_HEAD(&pcdev->camera_work_queue); } rk_camera_deactivate(pcdev); pcdev->active = NULL; @@ -1119,27 +1104,21 @@ static int rk_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) cif_ctrl_val = read_cif_reg(pcdev->base,CIF_CIF_FOR); RKCAMERA_DG("%s..%d..cif_ctrl_val = 0x%x\n",__FUNCTION__,__LINE__,cif_ctrl_val); if (common_flags & SOCAM_PCLK_SAMPLE_FALLING) { - if(IS_CIF0()) - { + if(IS_CIF0()) { write_cru_reg(CRU_PCLK_REG30, read_cru_reg(CRU_PCLK_REG30) | ENANABLE_INVERT_PCLK_CIF0); RKCAMERA_DG("enable cif0 pclk invert\n"); - } - else - { + } else { write_cru_reg(CRU_PCLK_REG30, read_cru_reg(CRU_PCLK_REG30) | ENANABLE_INVERT_PCLK_CIF1); RKCAMERA_DG("enable cif1 pclk invert\n"); - } + } } else { - if(IS_CIF0()) - { + if(IS_CIF0()){ write_cru_reg(CRU_PCLK_REG30, (read_cru_reg(CRU_PCLK_REG30) & 0xFFFFEFF ) | DISABLE_INVERT_PCLK_CIF0); RKCAMERA_DG("diable cif0 pclk invert\n"); - } - else - { + } else { write_cru_reg(CRU_PCLK_REG30, (read_cru_reg(CRU_PCLK_REG30) & 0xFFFEFFF) | DISABLE_INVERT_PCLK_CIF1); RKCAMERA_DG("diable cif1 pclk invert\n"); - } + } } if (common_flags & SOCAM_HSYNC_ACTIVE_LOW) { cif_ctrl_val |= HSY_LOW_ACTIVE; @@ -1221,33 +1200,33 @@ static void rk_camera_setup_format(struct soc_camera_device *icd, __u32 host_pix { case V4L2_PIX_FMT_NV16: cif_fmt_val &= ~YUV_OUTPUT_422; - cif_fmt_val &= ~UV_STORAGE_ORDER_UVUV; - pcdev->frame_inval = RK_CAM_FRAME_INVAL_DC; - pcdev->pixfmt = host_pixfmt; + cif_fmt_val &= ~UV_STORAGE_ORDER_UVUV; + pcdev->frame_inval = RK_CAM_FRAME_INVAL_DC; + pcdev->pixfmt = host_pixfmt; break; - case V4L2_PIX_FMT_NV61: - cif_fmt_val &= ~YUV_OUTPUT_422; - cif_fmt_val |= UV_STORAGE_ORDER_VUVU; - pcdev->frame_inval = RK_CAM_FRAME_INVAL_DC; - pcdev->pixfmt = host_pixfmt; - break; + case V4L2_PIX_FMT_NV61: + cif_fmt_val &= ~YUV_OUTPUT_422; + cif_fmt_val |= UV_STORAGE_ORDER_VUVU; + pcdev->frame_inval = RK_CAM_FRAME_INVAL_DC; + pcdev->pixfmt = host_pixfmt; + break; case V4L2_PIX_FMT_NV12: cif_fmt_val |= YUV_OUTPUT_420; - cif_fmt_val &= ~UV_STORAGE_ORDER_UVUV; + cif_fmt_val &= ~UV_STORAGE_ORDER_UVUV; if (pcdev->frame_inval != RK_CAM_FRAME_INVAL_INIT) pcdev->frame_inval = RK_CAM_FRAME_INVAL_INIT; pcdev->pixfmt = host_pixfmt; break; - case V4L2_PIX_FMT_NV21: - cif_fmt_val |= YUV_OUTPUT_420; - cif_fmt_val |= UV_STORAGE_ORDER_VUVU; - if (pcdev->frame_inval != RK_CAM_FRAME_INVAL_INIT) - pcdev->frame_inval = RK_CAM_FRAME_INVAL_INIT; - pcdev->pixfmt = host_pixfmt; - break; - default: /* ddl@rock-chips.com : vip output format is hold when pixfmt is invalidate */ - cif_fmt_val |= YUV_OUTPUT_422; - break; + case V4L2_PIX_FMT_NV21: + cif_fmt_val |= YUV_OUTPUT_420; + cif_fmt_val |= UV_STORAGE_ORDER_VUVU; + if (pcdev->frame_inval != RK_CAM_FRAME_INVAL_INIT) + pcdev->frame_inval = RK_CAM_FRAME_INVAL_INIT; + pcdev->pixfmt = host_pixfmt; + break; + default: /* ddl@rock-chips.com : vip output format is hold when pixfmt is invalidate */ + cif_fmt_val |= YUV_OUTPUT_422; + break; } switch (icd_code) { @@ -1267,37 +1246,34 @@ static void rk_camera_setup_format(struct soc_camera_device *icd, __u32 host_pix cif_fmt_val = YUV_INPUT_ORDER_YUYV(cif_fmt_val); break; } -#if 1 - { - mdelay(100); - if(IS_CIF0()){ - // pmu_set_idle_request(IDLE_REQ_VIO, true); - cru_set_soft_reset(SOFT_RST_CIF0, true); - udelay(5); - cru_set_soft_reset(SOFT_RST_CIF0, false); - // pmu_set_idle_request(IDLE_REQ_VIO, false); - }else{ - // pmu_set_idle_request(IDLE_REQ_VIO, true); - cru_set_soft_reset(SOFT_RST_CIF1, true); - udelay(5); - cru_set_soft_reset(SOFT_RST_CIF1, false); - // pmu_set_idle_request(IDLE_REQ_VIO, false); - } + { + mdelay(100); + if(IS_CIF0()){ + // pmu_set_idle_request(IDLE_REQ_VIO, true); + cru_set_soft_reset(SOFT_RST_CIF0, true); + udelay(5); + cru_set_soft_reset(SOFT_RST_CIF0, false); + // pmu_set_idle_request(IDLE_REQ_VIO, false); + + }else{ + // pmu_set_idle_request(IDLE_REQ_VIO, true); + cru_set_soft_reset(SOFT_RST_CIF1, true); + udelay(5); + cru_set_soft_reset(SOFT_RST_CIF1, false); + // pmu_set_idle_request(IDLE_REQ_VIO, false); } + } write_cif_reg(pcdev->base,CIF_CIF_CTRL,AXI_BURST_16|MODE_ONEFRAME|DISABLE_CAPTURE); /* ddl@rock-chips.com : vip ahb burst 16 */ write_cif_reg(pcdev->base,CIF_CIF_INTEN, 0x01|0x200); //capture complete interrupt enable -#endif write_cif_reg(pcdev->base,CIF_CIF_FOR,cif_fmt_val); /* ddl@rock-chips.com: VIP capture mode and capture format must be set before FS register set */ // read_cif_reg(pcdev->base,CIF_CIF_INTSTAT); /* clear vip interrupte single */ - write_cif_reg(pcdev->base,CIF_CIF_INTSTAT,0xFFFFFFFF); - if((read_cif_reg(pcdev->base,CIF_CIF_CTRL) & MODE_PINGPONG) - ||(read_cif_reg(pcdev->base,CIF_CIF_CTRL) & MODE_LINELOOP)) // it is one frame mode - { - BUG(); - } - else{ // this is one frame mode + write_cif_reg(pcdev->base,CIF_CIF_INTSTAT,0xFFFFFFFF); + if((read_cif_reg(pcdev->base,CIF_CIF_CTRL) & MODE_PINGPONG) + ||(read_cif_reg(pcdev->base,CIF_CIF_CTRL) & MODE_LINELOOP)) { + BUG(); + } else{ // this is one frame mode cif_crop = (rect->left+ (rect->top<<16)); cif_fs = ((rect->width ) + (rect->height<<16)); } @@ -1307,10 +1283,9 @@ static void rk_camera_setup_format(struct soc_camera_device *icd, __u32 host_pix write_cif_reg(pcdev->base,CIF_CIF_SET_SIZE, cif_fs); write_cif_reg(pcdev->base,CIF_CIF_VIR_LINE_WIDTH, rect->width); write_cif_reg(pcdev->base,CIF_CIF_FRAME_STATUS, 0x00000003); - //MUST bypass scale + + //MUST bypass scale write_cif_reg(pcdev->base,CIF_CIF_SCL_CTRL,0x10); - //pcdev->host_width = rect->width; -// pcdev->host_height = rect->height; RKCAMERA_DG("%s.. crop:0x%x fs:0x%x cif_fmt_val:0x%x CIF_CIF_FOR:0x%x\n",__FUNCTION__,cif_crop,cif_fs,cif_fmt_val,read_cif_reg(pcdev->base,CIF_CIF_FOR)); return; } @@ -1491,8 +1466,6 @@ static int rk_camera_set_fmt(struct soc_camera_device *icd, RKCAMERA_DG("ratio = %d ,host:%d*%d\n",ratio,pcdev->host_width,pcdev->host_height); } else{ // needn't crop ,just scaled by ipp - // pcdev->host_width = usr_w; - // pcdev->host_height = usr_h; pcdev->host_width = mf.width; pcdev->host_height = mf.height; } @@ -1822,12 +1795,7 @@ static int rk_camera_suspend(struct soc_camera_device *icd, pm_message_t state) pcdev->reginfo_suspend.cifFmt= read_cif_reg(pcdev->base,CIF_CIF_FOR); pcdev->reginfo_suspend.cifVirWidth = read_cif_reg(pcdev->base,CIF_CIF_VIR_LINE_WIDTH); pcdev->reginfo_suspend.cifScale= read_cif_reg(pcdev->base,CIF_CIF_SCL_CTRL); - //pcdev->reginfo_suspend.VipCrm = read_vip_reg(pcdev->base,RK29_VIP_CRM); - - //tmp = pcdev->reginfo_suspend.cifFs>>16; /* ddl@rock-chips.com */ - //tmp += pcdev->reginfo_suspend.cifCrop>>16; - //pcdev->reginfo_suspend.cifFs = (pcdev->reginfo_suspend.cifFs & 0xffff) | (tmp<<16); - + pcdev->reginfo_suspend.Inval = Reg_Validate; rk_camera_deactivate(pcdev); @@ -1882,14 +1850,9 @@ static int rk_camera_resume(struct soc_camera_device *icd) static void rk_camera_reinit_work(struct work_struct *work) { - struct device *control; struct v4l2_subdev *sd; - struct v4l2_mbus_framefmt mf; - const struct soc_camera_format_xlate *xlate; - int ret; struct rk_camera_work *camera_work = container_of(work, struct rk_camera_work, work); struct rk_camera_dev *pcdev = camera_work->pcdev; - struct videobuf_buffer *tmp_vb; struct soc_camera_link *tmp_soc_cam_link; int index = 0; unsigned long flags = 0; @@ -1916,89 +1879,27 @@ static void rk_camera_reinit_work(struct work_struct *work) RKCAMERA_TR("CIF_CIF_FRM0_ADDR_UV = 0X%x\n",read_cif_reg(pcdev->base,CIF_CIF_FRM0_ADDR_UV)); RKCAMERA_TR("CIF_CIF_FRAME_STATUS = 0X%x\n",read_cif_reg(pcdev->base,CIF_CIF_FRAME_STATUS)); } - if(1/*pcdev->reinit_times++ >= 2*/) - { - pcdev->stop_cif = true; - write_cif_reg(pcdev->base,CIF_CIF_CTRL, (read_cif_reg(pcdev->base,CIF_CIF_CTRL)&(~ENABLE_CAPTURE))); - RKCAMERA_DG("the reinit times = %d\n",pcdev->reinit_times); - #if 0 - while (!list_empty(&pcdev->capture)) { - tmp_vb = list_entry(pcdev->capture.next, struct videobuf_buffer, queue); - if (tmp_vb/* && (tmp_vb->state == VIDEOBUF_QUEUED)*/) - { - printk("wake up video buffer index = %d ,state = %d, !!!\n",tmp_vb->i,tmp_vb->state); - tmp_vb->state = VIDEOBUF_ERROR; - list_del_init(&(tmp_vb->queue)); - wake_up(&tmp_vb->done); - } - } - #else - spin_lock_irqsave(pcdev->video_vq->irqlock, flags); - for (index = 0; index < VIDEO_MAX_FRAME; index++) { - if (NULL == pcdev->video_vq->bufs[index]) - continue; - if (pcdev->video_vq->bufs[index]->state == VIDEOBUF_QUEUED) - { - list_del_init(&pcdev->video_vq->bufs[index]->queue); - pcdev->video_vq->bufs[index]->state = VIDEOBUF_NEEDS_INIT; - wake_up_all(&pcdev->video_vq->bufs[index]->done); - printk("wake up video buffer index = %d !!!\n",index); - } - } - spin_unlock_irqrestore(pcdev->video_vq->irqlock, flags); + + pcdev->stop_cif = true; + write_cif_reg(pcdev->base,CIF_CIF_CTRL, (read_cif_reg(pcdev->base,CIF_CIF_CTRL)&(~ENABLE_CAPTURE))); + RKCAMERA_DG("the reinit times = %d\n",pcdev->reinit_times); + + spin_lock_irqsave(pcdev->video_vq->irqlock, flags); + for (index = 0; index < VIDEO_MAX_FRAME; index++) { + if (NULL == pcdev->video_vq->bufs[index]) + continue; - #endif - RKCAMERA_TR("the %d reinit times ,wake up video buffers!\n ",pcdev->reinit_times); - }/*else{ //the first time,just reinit sensor ,don't wake up vb - // rk_cif_poweroff(pcdev); - RKCAMERA_DG("first time to reinit\n"); - // return; - if(IS_CIF0()){ - // write_cru_reg(CRU_CIF_RST_REG30,(read_cru_reg(CRU_CIF_RST_REG30)|MASK_RST_CIF0|RQUEST_RST_CIF0 )); - - // write_cru_reg(CRU_CIF_RST_REG30,(read_cru_reg(CRU_CIF_RST_REG30)&(~RQUEST_RST_CIF0)) | MASK_RST_CIF0); - rk_camera_store_register(pcdev); - rk_camera_deactivate(pcdev); - pmu_set_idle_request(IDLE_REQ_VIO, true); - cru_set_soft_reset(SOFT_RST_CIF0, true); - udelay(50); - cru_set_soft_reset(SOFT_RST_CIF0, false); - pmu_set_idle_request(IDLE_REQ_VIO, false); - rk_camera_activate(pcdev,NULL); - rk_camera_restore_register(pcdev); - rk_videobuf_capture(pcdev->active,pcdev); - printk("clean cru register reset cif0 0x%x\n",read_cru_reg(CRU_CIF_RST_REG30)); + if (pcdev->video_vq->bufs[index]->state == VIDEOBUF_QUEUED) + { + list_del_init(&pcdev->video_vq->bufs[index]->queue); + pcdev->video_vq->bufs[index]->state = VIDEOBUF_NEEDS_INIT; + wake_up_all(&pcdev->video_vq->bufs[index]->done); + printk("wake up video buffer index = %d !!!\n",index); + } + } + spin_unlock_irqrestore(pcdev->video_vq->irqlock, flags); - }else{ - // write_cru_reg(CRU_CIF_RST_REG30,MASK_RST_CIF1|RQUEST_RST_CIF1 | (read_cru_reg(CRU_CIF_RST_REG30))); - // write_cru_reg(CRU_CIF_RST_REG30,(read_cru_reg(CRU_CIF_RST_REG30)&(~RQUEST_RST_CIF1)) | MASK_RST_CIF1); - rk_camera_store_register(pcdev); - rk_camera_deactivate(pcdev); - pmu_set_idle_request(IDLE_REQ_VIO, true); - cru_set_soft_reset(SOFT_RST_CIF1, true); - udelay(50); - cru_set_soft_reset(SOFT_RST_CIF1, false); - pmu_set_idle_request(IDLE_REQ_VIO, false); - rk_camera_activate(pcdev,NULL); - rk_camera_restore_register(pcdev); - rk_videobuf_capture(pcdev->active,pcdev); - } - tmp_soc_cam_link->power(pcdev->icd->pdev,0); - // rk_cif_poweron(pcdev); - tmp_soc_cam_link->power(pcdev->icd->pdev,1); - control = to_soc_camera_control(pcdev->icd); - sd = dev_get_drvdata(control); - ret = v4l2_subdev_call(sd,core, init, 1); - - mf.width = pcdev->icd->user_width; - mf.height = pcdev->icd->user_height; - xlate = soc_camera_xlate_by_fourcc(pcdev->icd, pcdev->icd->current_fmt->host_fmt->fourcc); - mf.code = xlate->code; - ret |= v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); - write_cif_reg(pcdev->base,CIF_CIF_CTRL, (read_cif_reg(pcdev->base,CIF_CIF_CTRL)|ENABLE_CAPTURE)); - - RKCAMERA_TR("first time Camera host haven't recevie data from sensor,Reinit sensor now! ret:0x%x\n",ret); - }*/ + RKCAMERA_TR("the %d reinit times ,wake up video buffers!\n ",pcdev->reinit_times); } static enum hrtimer_restart rk_camera_fps_func(struct hrtimer *timer) { @@ -2121,11 +2022,6 @@ static int rk_camera_s_stream(struct soc_camera_device *icd, int enable) write_cif_reg(pcdev->base,CIF_CIF_CTRL, cif_ctrl_val); pcdev->stop_cif = true; spin_unlock_irqrestore(&pcdev->lock, flags); - // printk("flush work end!!!!!!!!!\n"); - // mdelay(3*1000); - // write_cif_reg(pcdev->base,CIF_CIF_FRAME_STATUS, 0x00000003);//frame1 has been ready to receive data,frame 2 is not used - // write_cif_reg(pcdev->base,CIF_CIF_INTSTAT,0xFFFFFFFF); /* clear vip interrupte single */ - // write_cif_reg(pcdev->base,CIF_CIF_FRAME_STATUS,0); /* clear vip interrupte single */ flush_workqueue((pcdev->camera_wq)); RKCAMERA_DG("STREAM_OFF cancel timer and flush work:0x%x \n", ret); } @@ -2237,48 +2133,7 @@ static int rk_camera_set_digit_zoom(struct soc_camera_device *icd, struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct rk_camera_dev *pcdev = ici->priv; - #if 0 - unsigned int cif_fs = 0,cif_crop = 0; - int work_index =0,stream_on = 0; -/* ddl@rock-chips.com : The largest resolution is 2047x1088, so larger resolution must be operated some times - (Assume operate times is 4),but resolution which ipp can operate ,it is width and height must be even. */ - a.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - a.c.width = pcdev->host_width*100/zoom_rate; - a.c.width &= ~0x03; - a.c.height = pcdev->host_height*100/zoom_rate; - a.c.height &= ~0x03; - - a.c.left = (((pcdev->host_width - a.c.width)>>1) +pcdev->host_left)&(~0x01); - a.c.top = (((pcdev->host_height - a.c.height)>>1) + pcdev->host_top)&(~0x01); - stream_on = read_cif_reg(pcdev->base,CIF_CIF_CTRL); - if (stream_on & ENABLE_CAPTURE) - write_cif_reg(pcdev->base,CIF_CIF_CTRL, (stream_on & (~ENABLE_CAPTURE))); - if (CAM_IPPWORK_IS_EN() && (stream_on & ENABLE_CAPTURE)){ - for(;work_index < pcdev->camera_work_count;work_index++) - flush_work(&((pcdev->camera_work + work_index)->work)); - pcdev->frame_inval = RK_CAM_FRAME_INVAL_DC; - } - //printk("host_left = %d , host_top = %d\n",pcdev->host_left,pcdev->host_top); - down(&pcdev->zoominfo.sem); - pcdev->zoominfo.a.c.height = a.c.height; - pcdev->zoominfo.a.c.width = a.c.width; - pcdev->zoominfo.a.c.top = 0; - pcdev->zoominfo.a.c.left = 0; - pcdev->zoominfo.vir_width = a.c.width; - up(&pcdev->zoominfo.sem); - - cif_crop = a.c.left+ (a.c.top<<16); - cif_fs = a.c.width + ((a.c.height)<<16); -//cif do the crop , ipp do the scale - write_cif_reg(pcdev->base,CIF_CIF_CROP, cif_crop); - write_cif_reg(pcdev->base,CIF_CIF_SET_SIZE, cif_fs); - write_cif_reg(pcdev->base,CIF_CIF_VIR_LINE_WIDTH, a.c.width); - write_cif_reg(pcdev->base,CIF_CIF_FRAME_STATUS, 0x00000003); - write_cif_reg(pcdev->base,CIF_CIF_SCL_CTRL,0x10); - if (stream_on & ENABLE_CAPTURE) - write_cif_reg(pcdev->base,CIF_CIF_CTRL, stream_on); - #else //change the crop and scale parameters a.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; a.c.width = pcdev->host_width*100/zoom_rate; @@ -2294,8 +2149,6 @@ static int rk_camera_set_digit_zoom(struct soc_camera_device *icd, pcdev->zoominfo.a.c.left = a.c.left; pcdev->zoominfo.vir_width = pcdev->host_width; up(&pcdev->zoominfo.sem); - - #endif RKCAMERA_DG("%s..zoom_rate:%d (%dx%d at (%d,%d)-> %dx%d)\n",__FUNCTION__, zoom_rate,a.c.width, a.c.height, a.c.left, a.c.top, icd->user_width, icd->user_height ); return 0; @@ -2418,7 +2271,9 @@ static int rk_camera_probe(struct platform_device *pdev) int irq,i; int err = 0; - RKCAMERA_DG("%s..%s..%d \n",__FUNCTION__,__FILE__,__LINE__); + RKCAMERA_TR("RK30 Camera driver version: v%d.%d.%d\n",(RK_CAM_VERSION_CODE&0xff0000)>>16, + (RK_CAM_VERSION_CODE&0xff00)>>8,RK_CAM_VERSION_CODE&0xff); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); if (!res || irq < 0) { @@ -2436,16 +2291,13 @@ static int rk_camera_probe(struct platform_device *pdev) pcdev->hostid = pdev->id; /*config output clk*/ // must modify start if(IS_CIF0()){ - // printk("it is cif 0!!!!!!!1\n"); pcdev->pd_cif = clk_get(NULL, "pd_cif0"); pcdev->aclk_cif = clk_get(NULL, "aclk_cif0"); pcdev->hclk_cif = clk_get(NULL, "hclk_cif0"); pcdev->cif_clk_in = clk_get(NULL, "cif0_in"); pcdev->cif_clk_out = clk_get(NULL, "cif0_out"); rk_camera_cif_iomux(0); - } - else{ - // printk("it is cif 1!!!!!!!1\n"); + } else { pcdev->pd_cif = clk_get(NULL, "pd_cif1"); pcdev->aclk_cif = clk_get(NULL, "aclk_cif1"); pcdev->hclk_cif = clk_get(NULL, "hclk_cif1"); @@ -2453,12 +2305,14 @@ static int rk_camera_probe(struct platform_device *pdev) pcdev->cif_clk_out = clk_get(NULL, "cif1_out"); rk_camera_cif_iomux(1); - } + } + if(IS_ERR(pcdev->pd_cif) || IS_ERR(pcdev->aclk_cif) || IS_ERR(pcdev->hclk_cif) || IS_ERR(pcdev->cif_clk_in) || IS_ERR(pcdev->cif_clk_out)){ - RKCAMERA_TR(KERN_ERR "failed to get cif clock source\n"); + RKCAMERA_TR(KERN_ERR "%s(%d): failed to get cif clock source\n",__FUNCTION__,__LINE__); err = -ENOENT; goto exit_reqmem_vip; - } + } + dev_set_drvdata(&pdev->dev, pcdev); pcdev->res = res; pcdev->pdata = pdev->dev.platform_data; /* ddl@rock-chips.com : Request IO in init function */ @@ -2470,63 +2324,62 @@ static int rk_camera_probe(struct platform_device *pdev) if (pcdev->pdata && IS_CIF0()) { pcdev->vipmem_phybase = pcdev->pdata->meminfo.start; pcdev->vipmem_size = pcdev->pdata->meminfo.size; - RKCAMERA_TR("\n%s Memory(start:0x%x size:0x%x) for IPP obtain \n",__FUNCTION__, pcdev->pdata->meminfo.start,pcdev->pdata->meminfo.size); - } - else if (pcdev->pdata){ + RKCAMERA_TR("%s(%d): Memory(start:0x%x size:0x%x) for IPP obtain \n",__FUNCTION__,__LINE__, pcdev->pdata->meminfo.start,pcdev->pdata->meminfo.size); + } else if (pcdev->pdata) { pcdev->vipmem_phybase = pcdev->pdata->meminfo_cif1.start; pcdev->vipmem_size = pcdev->pdata->meminfo_cif1.size; - RKCAMERA_TR("\n%s Memory(start:0x%x size:0x%x) for IPP obtain \n",__FUNCTION__, pcdev->pdata->meminfo.start,pcdev->pdata->meminfo.size); - } - else{ + RKCAMERA_TR("%s(%d): Memory(start:0x%x size:0x%x) for IPP obtain \n",__FUNCTION__,__LINE__, pcdev->pdata->meminfo.start,pcdev->pdata->meminfo.size); + } else { RKCAMERA_TR("\n%s Memory for IPP have not obtain! IPP Function is fail\n",__FUNCTION__); pcdev->vipmem_phybase = 0; pcdev->vipmem_size = 0; } #endif INIT_LIST_HEAD(&pcdev->capture); + INIT_LIST_HEAD(&pcdev->camera_work_queue); spin_lock_init(&pcdev->lock); + spin_lock_init(&pcdev->camera_work_lock); sema_init(&pcdev->zoominfo.sem,1); /* * Request the regions. */ - if(res){ - if (!request_mem_region(res->start, res->end - res->start + 1, - RK29_CAM_DRV_NAME)) { - err = -EBUSY; - goto exit_reqmem_vip; - } - pcdev->base = ioremap(res->start, res->end - res->start + 1); - if (pcdev->base == NULL) { - dev_err(pcdev->dev, "ioremap() of registers failed\n"); - err = -ENXIO; - goto exit_ioremap_vip; - } - } + if(res) { + if (!request_mem_region(res->start, res->end - res->start + 1, + RK29_CAM_DRV_NAME)) { + err = -EBUSY; + goto exit_reqmem_vip; + } + pcdev->base = ioremap(res->start, res->end - res->start + 1); + if (pcdev->base == NULL) { + dev_err(pcdev->dev, "ioremap() of registers failed\n"); + err = -ENXIO; + goto exit_ioremap_vip; + } + } pcdev->irq = irq; pcdev->dev = &pdev->dev; /* config buffer address */ /* request irq */ - if(irq > 0){ - err = request_irq(pcdev->irq, rk_camera_irq, 0, RK29_CAM_DRV_NAME, - pcdev); - if (err) { - dev_err(pcdev->dev, "Camera interrupt register failed \n"); - goto exit_reqirq; - } + if(irq > 0){ + err = request_irq(pcdev->irq, rk_camera_irq, 0, RK29_CAM_DRV_NAME, + pcdev); + if (err) { + dev_err(pcdev->dev, "Camera interrupt register failed \n"); + goto exit_reqirq; + } } #ifdef CONFIG_VIDEO_RK29_WORK_IPP - if(IS_CIF0()){ - pcdev->camera_wq = create_workqueue("rk_cam_wkque_cif0"); - } - else{ - pcdev->camera_wq = create_workqueue("rk_cam_wkque_cif1"); - } - if (pcdev->camera_wq == NULL) - goto exit_free_irq; + if(IS_CIF0()) { + pcdev->camera_wq = create_workqueue("rk_cam_wkque_cif0"); + } else { + pcdev->camera_wq = create_workqueue("rk_cam_wkque_cif1"); + } + if (pcdev->camera_wq == NULL) + goto exit_free_irq; #endif pcdev->camera_reinit_work.pcdev = pcdev; @@ -2550,8 +2403,8 @@ static int rk_camera_probe(struct platform_device *pdev) hrtimer_init(&(pcdev->fps_timer.timer), CLOCK_MONOTONIC, HRTIMER_MODE_REL); pcdev->fps_timer.timer.function = rk_camera_fps_func; pcdev->icd_cb.sensor_cb = NULL; -// rk29_camdev_info_ptr = pcdev; - RKCAMERA_DG("%s..%s..%d \n",__FUNCTION__,__FILE__,__LINE__); + + RKCAMERA_DG("%s(%d) Exit \n",__FUNCTION__,__LINE__); return 0; exit_free_irq: @@ -2588,7 +2441,7 @@ static int rk_camera_probe(struct platform_device *pdev) kfree(pcdev); exit_alloc: -// rk_camdev_info_ptr = NULL; + exit: return err; } @@ -2627,7 +2480,7 @@ static int __devexit rk_camera_remove(struct platform_device *pdev) } kfree(pcdev); - // rk_camdev_info_ptr = NULL; + dev_info(&pdev->dev, "RK28 Camera driver unloaded\n"); return 0; diff --git a/drivers/media/video/sp2518.c b/drivers/media/video/sp2518.c new file mode 100755 index 000000000000..1c4e17a2826b --- /dev/null +++ b/drivers/media/video/sp2518.c @@ -0,0 +1,3293 @@ + +/* +o* Driver for MT9M001 CMOS Image Sensor from Micron + * + * Copyright (C) 2008, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +static int debug=0; +module_param(debug, int, S_IRUGO|S_IWUSR); + +#define dprintk(level, fmt, arg...) do { \ + if (debug >= level) \ + printk(KERN_WARNING fmt , ## arg); } while (0) + +#define SENSOR_TR(format, ...) printk(KERN_ERR format, ## __VA_ARGS__) +#define SENSOR_DG(format, ...) dprintk(1, format, ## __VA_ARGS__) + + +#define _CONS(a,b) a##b +#define CONS(a,b) _CONS(a,b) + +#define __STR(x) #x +#define _STR(x) __STR(x) +#define STR(x) _STR(x) + +#define MIN(x,y) ((xy) ? x: y) + +/* Sensor Driver Configuration */ +#define SENSOR_NAME RK29_CAM_SENSOR_SP2518 +#define SENSOR_V4L2_IDENT V4L2_IDENT_SP2518 +#define SENSOR_ID 0x53 +#define SENSOR_ID_REG 0x02 +#define SENSOR_MIN_WIDTH 640 +#define SENSOR_MIN_HEIGHT 480 +#define SENSOR_MAX_WIDTH 1600 +#define SENSOR_MAX_HEIGHT 1200 +#define SENSOR_INIT_WIDTH 800 /* Sensor pixel size for sensor_init_data array */ +#define SENSOR_INIT_HEIGHT 600 +#define SENSOR_INIT_WINSEQADR sensor_vga +#define SENSOR_INIT_PIXFMT V4L2_MBUS_FMT_YUYV8_2X8 + +#define CONFIG_SENSOR_WhiteBalance 1 +#define CONFIG_SENSOR_Brightness 0 +#define CONFIG_SENSOR_Contrast 0 +#define CONFIG_SENSOR_Saturation 0 +#define CONFIG_SENSOR_Effect 1 +#define CONFIG_SENSOR_Scene 1 +#define CONFIG_SENSOR_DigitalZoom 0 +#define CONFIG_SENSOR_Focus 0 +#define CONFIG_SENSOR_Exposure 0 +#define CONFIG_SENSOR_Flash 0 +#define CONFIG_SENSOR_Mirror 0 +#define CONFIG_SENSOR_Flip 0 + +#define CONFIG_SENSOR_I2C_SPEED 100000 ///250000 /* Hz */ +/* Sensor write register continues by preempt_disable/preempt_enable for current process not be scheduled */ +#define CONFIG_SENSOR_I2C_NOSCHED 0 +#define CONFIG_SENSOR_I2C_RDWRCHK 0 + +#define SENSOR_BUS_PARAM (SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |\ + SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |\ + SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8 |SOCAM_MCLK_24MHZ) + +#define COLOR_TEMPERATURE_CLOUDY_DN 6500 +#define COLOR_TEMPERATURE_CLOUDY_UP 8000 +#define COLOR_TEMPERATURE_CLEARDAY_DN 5000 +#define COLOR_TEMPERATURE_CLEARDAY_UP 6500 +#define COLOR_TEMPERATURE_OFFICE_DN 3500 +#define COLOR_TEMPERATURE_OFFICE_UP 5000 +#define COLOR_TEMPERATURE_HOME_DN 2500 +#define COLOR_TEMPERATURE_HOME_UP 3500 + +#define SENSOR_NAME_STRING(a) STR(CONS(SENSOR_NAME, a)) +#define SENSOR_NAME_VARFUN(a) CONS(SENSOR_NAME, a) + +#define SENSOR_AF_IS_ERR (0x00<<0) +#define SENSOR_AF_IS_OK (0x01<<0) +#define SENSOR_INIT_IS_ERR (0x00<<28) +#define SENSOR_INIT_IS_OK (0x01<<28) + +//AE +#define SP2518_P0_0xf7 0x78///0x80//78 +#define SP2518_P0_0xf8 0x6e///0x74//6e +#define SP2518_P0_0xf9 0x74///0x80//74 +#define SP2518_P0_0xfa 0x6a///0x74//6a + +//HEQ +#define SP2518_P0_0xdd 0x7c //0x80 modify by sp_yjp,20120814 +#define SP2518_P0_0xde 0x90 //0x95 modify by sp_yjp,20120814 + +//auto lum +#define SP2518_NORMAL_Y0ffset 0x10 //0x0f modify by sp_yjp,20120813 +#define SP2518_LOWLIGHT_Y0ffset 0x20 + + + + + +struct reginfo +{ + u8 reg; + u8 val; +}; +///=========SP2518-modify by sp_yjp,20120529================= +/* init 640X480 VGA */ +static struct reginfo sensor_init_data[] = +{ + #if 1 + {0xfd,0x00}, + {0x1b,0x1a},//maximum drv ability //0x02 modify by sp_yjp,20120809 + {0x0e,0x01}, + + {0x0f,0x2f}, + {0x10,0x2e}, + {0x11,0x00}, + {0x12,0x4f}, + {0x14,0x20}, + {0x16,0x02}, + {0x17,0x10}, + {0x1a,0x1f}, + {0x1e,0x81}, + {0x21,0x00}, + {0x22,0x1b}, + {0x25,0x10}, + {0x26,0x25}, + {0x27,0x6d}, + {0x2c,0x31},//Ronlus remove balck dot0x45}, + {0x2d,0x75}, + {0x2e,0x38},//sxga 0x18 + + {0x31,0x10},//mirror upside down + {0x44,0x03}, + {0x6f,0x00}, + {0xa0,0x04}, + {0x5f,0x01}, + {0x32,0x00}, + {0xfd,0x01}, + {0x2c,0x00}, + {0x2d,0x00}, + {0xfd,0x00}, + {0xfb,0x83}, + {0xf4,0x09}, + //Pregain + {0xfd,0x01}, + {0xc6,0x90}, + {0xc7,0x90}, + {0xc8,0x90}, + {0xc9,0x90}, + //blacklevel + {0xfd,0x00}, + {0x65,0x08}, + {0x66,0x08}, + {0x67,0x08}, + {0x68,0x08}, + + //bpc + {0x46,0xff}, + //rpc + {0xfd,0x00}, + {0xe0,0x6c}, + {0xe1,0x54}, + {0xe2,0x48}, + {0xe3,0x40}, + {0xe4,0x40}, + {0xe5,0x3e}, + {0xe6,0x3e}, + {0xe8,0x3a}, + {0xe9,0x3a}, + {0xea,0x3a}, + {0xeb,0x38}, + {0xf5,0x38}, + {0xf6,0x38}, + {0xfd,0x01}, + {0x94,0xc0},//f8 + {0x95,0x38}, + {0x9c,0x6c}, + {0x9d,0x38}, + + + #if 0 + ///SP2518 UXGA 24MEclk 3倍频 1分频 50Hz fix 11fps + {0xfd , 0x00}, + {0x03 , 0x03}, + {0x04 , 0xa8}, + {0x05 , 0x00}, + {0x06 , 0x6d}, + {0x07 , 0x00}, + {0x08 , 0x6d}, + {0x09 , 0x00}, + {0x0a , 0xe4}, + {0x2f , 0x00}, + {0x30 , 0x08}, + {0xf0 , 0x9c}, + {0xf1 , 0x00}, + {0xfd , 0x01}, + {0x90 , 0x09}, + {0x92 , 0x01}, + {0x98 , 0x9c}, + {0x99 , 0x00}, + {0x9a , 0x01}, + {0x9b , 0x00}, + ///Status + {0xfd , 0x01}, + {0xce , 0x7c}, + {0xcf , 0x05}, + {0xd0 , 0x7c}, + {0xd1 , 0x05}, + {0xd7 , 0x98}, + {0xd8 , 0x00}, + {0xd9 , 0x9c}, + {0xda , 0x00}, + {0xfd , 0x00}, + #endif + + #if 1 + ///SP2518 UXGA 24MEclk 3倍频 1分频 50Hz fix 10fps + {0xfd , 0x00}, + {0x03 , 0x03}, + {0x04 , 0x66}, + {0x05 , 0x00}, + {0x06 , 0x8b}, + {0x07 , 0x00}, + {0x08 , 0x8b}, + {0x09 , 0x01}, + {0x0a , 0x3b}, + {0x2f , 0x00}, + {0x30 , 0x08}, + {0xf0 , 0x91}, + {0xf1 , 0x00}, + {0xfd , 0x01}, + {0x90 , 0x0a}, + {0x92 , 0x01}, + {0x98 , 0x91}, + {0x99 , 0x00}, + {0x9a , 0x01}, + {0x9b , 0x00}, + ///Status + {0xfd , 0x01}, + {0xce , 0xaa}, + {0xcf , 0x05}, + {0xd0 , 0xaa}, + {0xd1 , 0x05}, + {0xd7 , 0x8d}, + {0xd8 , 0x00}, + {0xd9 , 0x91}, + {0xda , 0x00}, + {0xfd , 0x00}, + #endif + + + #if 0 + /// UXGA 24MEclk 3倍频 1分频 50Hz fix 9fps + {0xfd , 0x00}, + {0x03 , 0x03}, + {0x04 , 0x42}, + {0x05 , 0x00}, + {0x06 , 0xf0}, + {0x07 , 0x00}, + {0x08 , 0xf0}, + {0x09 , 0x01}, + {0x0a , 0x71}, + {0x2f , 0x00}, + {0x30 , 0x08}, + {0xf0 , 0x8b}, + {0xf1 , 0x00}, + {0xfd , 0x01}, + {0x90 , 0x0b}, + {0x92 , 0x01}, + {0x98 , 0x8b}, + {0x99 , 0x00}, + {0x9a , 0x01}, + {0x9b , 0x00}, + ///Status + {0xfd , 0x01}, + {0xce , 0xf9}, + {0xcf , 0x05}, + {0xd0 , 0xf9}, + {0xd1 , 0x05}, + {0xd7 , 0x87}, + {0xd8 , 0x00}, + {0xd9 , 0x8b}, + {0xda , 0x00}, + {0xfd , 0x00}, + #endif + + #if 0 + /*24*3pll 8~13fps 50hz*/ + {0xfd , 0x00}, + {0x03 , 0x03}, + {0x04 , 0xf6}, + {0x05 , 0x00}, + {0x06 , 0x00}, + {0x07 , 0x00}, + {0x08 , 0x00}, + {0x09 , 0x00}, + {0x0a , 0x8b}, + ///////////////////SP2518_write_cmos_sensor(0x2f , 0x00}, modify by sp_yjp,20120809 + {0x30 , 0x08}, //0x08 modify by sp_yjp,20120809 + {0xf0 , 0xa9}, + {0xf1 , 0x00}, + {0xfd , 0x01}, + {0x90 , 0x0c}, + {0x92 , 0x01}, + {0x98 , 0xa9}, + {0x99 , 0x00}, + {0x9a , 0x01}, + {0x9b , 0x00}, + + //Status + {0xfd , 0x01}, + {0xce , 0xec}, + {0xcf , 0x07}, + {0xd0 , 0xec}, + {0xd1 , 0x07}, + {0xd7 , 0xa5}, + {0xd8 , 0x00}, + {0xd9 , 0xa9}, + {0xda , 0x00}, + {0xfd , 0x00}, + #endif + + {0xfd,0x01}, + {0xca,0x30},//mean dummy2low + {0xcb,0x50},//mean low2dummy + {0xcc,0xc0},//f8;rpc low + {0xcd,0xc0},//rpc dummy + {0xd5,0x80},//mean normal2dummy + {0xd6,0x90},//mean dummy2normal + {0xfd,0x00}, + + //lens shading + {0xfd,0x00}, + {0xa1,0x20}, + {0xa2,0x20}, + {0xa3,0x20}, + {0xa4,0xff}, + {0xa5,0x80}, + {0xa6,0x80}, + {0xfd,0x01}, + {0x64,0x1e},//28 + {0x65,0x1c},//25 + {0x66,0x1c},//2a + {0x67,0x16},//25 + {0x68,0x1c},//25 + {0x69,0x1c},//29 + {0x6a,0x1a},//28 + {0x6b,0x16},//20 + {0x6c,0x1a},//22 + {0x6d,0x1a},//22 + {0x6e,0x1a},//22 + {0x6f,0x16},//1c + {0xb8,0x04},//0a + {0xb9,0x13},//0a + {0xba,0x00},//23 + {0xbb,0x03},//14 + {0xbc,0x03},//08 + {0xbd,0x11},//08 + {0xbe,0x00},//12 + {0xbf,0x02},//00 + {0xc0,0x04},//05 + {0xc1,0x0e},//05 + {0xc2,0x00},//18 + {0xc3,0x05},//08 + //raw filter + {0xfd,0x01}, + {0xde,0x0f}, + {0xfd,0x00}, + {0x57,0x08},//raw_dif_thr + {0x58,0x08},//a + {0x56,0x08},//a + {0x59,0x10}, + + {0x5a,0xa0},//raw_rb_fac_outdoor + {0xc4,0xa0},//60raw_rb_fac_indoor + {0x43,0xa0},//40raw_rb_fac_dummy + {0xad,0x40},//raw_rb_fac_low + + {0x4f,0xa0},//raw_gf_fac_outdoor + {0xc3,0xa0},//60raw_gf_fac_indoor + {0x3f,0xa0},//40raw_gf_fac_dummy + {0x42,0x40},//raw_gf_fac_low + {0xc2,0x15}, + + {0xb6,0x80},//raw_gflt_fac_outdoor + {0xb7,0x80},//60raw_gflt_fac_normal + {0xb8,0x40},//40raw_gflt_fac_dummy + {0xb9,0x20},//raw_gflt_fac_low + + {0xfd,0x01}, + {0x50,0x0c},//raw_grgb_thr + {0x51,0x0c}, + {0x52,0x10}, + {0x53,0x10}, + {0xfd,0x00}, + // awb1 + {0xfd,0x01}, + {0x11,0x10}, + {0x12,0x1f}, + {0x16,0x1c}, + {0x18,0x00}, + {0x19,0x00}, + {0x1b,0x96}, + {0x1a,0x9a},//95 + {0x1e,0x2f}, + {0x1f,0x29}, + {0x20,0xff}, + {0x22,0xff}, + {0x28,0xce}, + {0x29,0x8a}, + {0xfd,0x00}, + {0xe7,0x03}, + {0xe7,0x00}, + {0xfd,0x01}, + {0x2a,0xf0}, + {0x2b,0x10}, + {0x2e,0x04}, + {0x2f,0x18}, + {0x21,0x60}, + {0x23,0x60}, + {0x8b,0xab}, + {0x8f,0x12}, + //awb2 + {0xfd,0x01}, + {0x1a,0x80}, + {0x1b,0x80}, + {0x43,0x80}, + //d65 + {0x35,0xd6},//d6;b0 + {0x36,0xf0},//f0;d1;e9 + {0x37,0x7a},//8a;70 + {0x38,0x9a},//dc;9a;af + //indoor + {0x39,0xab}, + {0x3a,0xca}, + {0x3b,0xa3}, + {0x3c,0xc1}, + //f + {0x31,0x82},//7d + {0x32,0xa5},//a0;74 + {0x33,0xd6},//d2 + {0x34,0xec},//e8 + {0x3d,0xa5},//a7;88 + {0x3e,0xc2},//be;bb + {0x3f,0xa7},//b3;ad + {0x40,0xc5},//c5;d0 + //Color Correction + {0xfd,0x01}, + {0x1c,0xc0}, + {0x1d,0x95}, + {0xa0,0xa6},//b8 + {0xa1,0xda},//;d5 + {0xa2,0x00},//;f2 + {0xa3,0x06},//;e8 + {0xa4,0xb2},//;95 + {0xa5,0xc7},//;03 + {0xa6,0x00},//;f2 + {0xa7,0xce},//;c4 + {0xa8,0xb2},//;ca + {0xa9,0x0c},//;3c + {0xaa,0x30},//;03 + {0xab,0x0c},//;0f + {0xac,0xc0},//b8 + {0xad,0xc0},//d5 + {0xae,0x00},//f2 + {0xaf,0xf2},//e8 + {0xb0,0xa6},//95 + {0xb1,0xe8},//03 + {0xb2,0x00},//f2 + {0xb3,0xe7},//c4 + {0xb4,0x99},//ca + {0xb5,0x0c},//3c + {0xb6,0x33},//03 + {0xb7,0x0c},//0f + //Saturation + {0xfd,0x00}, + {0xbf,0x01}, + {0xbe,0xbb}, + {0xc0,0xb0}, + {0xc1,0xf0}, + + {0xd3,0x68}, //0x77 modify by sp_yjp,20120814 + {0xd4,0x68}, //0x77 modify by sp_yjp,20120814 + {0xd6,0x68}, //0x77 modify by sp_yjp,20120814 + {0xd7,0x68}, //0x77 modify by sp_yjp,20120814 + {0xd8,0x68}, //0x77 modify by sp_yjp,20120814 + {0xd9,0x68}, //0x77 modify by sp_yjp,20120814 + {0xda,0x68}, //0x77 modify by sp_yjp,20120814 + {0xdb,0x68}, //0x77 modify by sp_yjp,20120814 + //uv_dif + {0xfd,0x00}, + {0xf3,0x03}, + {0xb0,0x00}, + {0xb1,0x23}, + //gamma1 + {0xfd,0x00},// + {0x8b,0x0 },//0 ;0 + {0x8c,0xA },//14;A + {0x8d,0x13},//24;13 + {0x8e,0x25},//3a;25 + {0x8f,0x43},//59;43 + {0x90,0x5D},//6f;5D + {0x91,0x74},//84;74 + {0x92,0x88},//95;88 + {0x93,0x9A},//a3;9A + {0x94,0xA9},//b1;A9 + {0x95,0xB5},//be;B5 + {0x96,0xC0},//c7;C0 + {0x97,0xCA},//d1;CA + {0x98,0xD4},//d9;D4 + {0x99,0xDD},//e1;DD + {0x9a,0xE6},//e9;E6 + {0x9b,0xEF},//f1;EF + {0xfd,0x01},//01;01 + {0x8d,0xF7},//f9;F7 + {0x8e,0xFF},//ff;FF + //gamma2 + {0xfd,0x00},// + {0x78,0x0 },//0 + {0x79,0xA },//14 + {0x7a,0x13},//24 + {0x7b,0x25},//3a + {0x7c,0x43},//59 + {0x7d,0x5D},//6f + {0x7e,0x74},//84 + {0x7f,0x88},//95 + {0x80,0x9A},//a3 + {0x81,0xA9},//b1 + {0x82,0xB5},//be + {0x83,0xC0},//c7 + {0x84,0xCA},//d1 + {0x85,0xD4},//d9 + {0x86,0xDD},//e1 + {0x87,0xE6},//e9 + {0x88,0xEF},//f1 + {0x89,0xF7},//f9 + {0x8a,0xFF},//ff + //gamma_ae + {0xfd,0x01}, + {0x96,0x46}, + {0x97,0x14}, + {0x9f,0x06}, + //HEQ + {0xfd,0x00},// + {0xdd,SP2518_P0_0xdd},//0x80 + {0xde,SP2518_P0_0xde},//a0 + {0xdf,0x80},// + //Ytarget + {0xfd,0x00},// + {0xec,0x70},//6a + {0xed,0x86},//7c + {0xee,0x70},//65 + {0xef,0x86},//78 + {0xf7,0x80},//78 + {0xf8,0x74},//6e + {0xf9,0x80},//74 + {0xfa,0x74},//6a + //sharpen + {0xfd,0x01}, + {0xdf,0x0f}, + {0xe5,0x10}, + {0xe7,0x10}, + {0xe8,0x20}, + {0xec,0x20}, + {0xe9,0x20}, + {0xed,0x20}, + {0xea,0x10}, + {0xef,0x10}, + {0xeb,0x10}, + {0xf0,0x10}, + //;gw + {0xfd,0x01},// + {0x70,0x76},// + {0x7b,0x40},// + {0x81,0x30},// + //;Y_offset + {0xfd,0x00}, + {0xb2,0X10}, + {0xb3,0x1f}, + {0xb4,0x30}, + {0xb5,0x50}, + //;CNR + {0xfd,0x00}, + {0x5b,0x20}, + {0x61,0x80}, + {0x77,0x80}, + {0xca,0x80}, + //;YNR + {0xab,0x00}, + {0xac,0x02}, + {0xae,0x08}, + {0xaf,0x20}, + {0xfd,0x00}, + {0x31,0x10}, + {0x32,0x0d}, + {0x33,0xcf},//ef + {0x34,0x7f},//3f + + {0x35,0x40},//3 + + {0x1b,0x02}, + {0xe7,0x03}, + {0xe7,0x00}, + + //SP2518_config_window(WINDOW_SIZE_VGA} + #if 1 + {0xfd,0x00}, + {0x4b,0x00}, + {0x4c,0x00}, + {0x47,0x00}, + {0x48,0x00}, + {0x4d,0x06}, + {0x4e,0x40}, + {0x49,0x04}, + {0x4a,0xb0}, + + {0xfd,0x01}, + {0x06,0x00}, + {0x07,0x50}, + {0x08,0x00}, + {0x09,0x50}, + {0x0a,0x01}, //480 + {0x0b,0xe0}, + {0x0c,0x02}, //640 + {0x0d,0x80}, + {0x0e,0x01}, + {0xfd,0x00}, + #else + {0xfd,0x00}, + {0x4b,0x00}, + {0x4c,0x00}, + {0x47,0x00}, + {0x48,0x00}, + {0x4d,0x06}, + {0x4e,0x40}, + {0x49,0x04}, + {0x4a,0xb0}, + + {0xfd,0x01}, + {0x06,0x00}, + {0x07,0x40}, + {0x08,0x00}, + {0x09,0x40}, + {0x0a,0x02}, //600 + {0x0b,0x58}, + {0x0c,0x03}, //800 + {0x0d,0x20}, + + {0x0e,0x01}, + #endif + #endif + + {0x5d,0x0e}, + {0xff,0xff}//The end flag +}; + + +/* 1600X1200 UXGA */ +static struct reginfo sensor_uxga[] = +{ + {0xfd,0x00}, + {0x47,0x00}, + {0x48,0x00}, + {0x49,0x04}, + {0x4a,0xb0}, + + {0x4b,0x00}, + {0x4c,0x00}, + {0x4d,0x06}, + {0x4e,0x40}, + + {0xfd,0x01}, + {0x0e,0x00}, + {0xfd,0x00}, + {0xfd,0x00}, + + {0xff,0xff}//The end flag +}; + + +/* 1280X1024 SXGA */ +static struct reginfo sensor_sxga[] = +{ + {0xfd,0x00}, + {0x47,0x00}, + {0x48,0x50}, + {0x49,0x04}, + {0x4a,0x00}, + + {0x4b,0x00}, + {0x4c,0x90}, + {0x4d,0x05}, + {0x4e,0x00}, + + {0xfd,0x01}, + {0x0e,0x00}, + {0xfd,0x00}, + {0xff,0xff} +}; + +/* 800X600 SVGA*/ +static struct reginfo sensor_svga[] = +{ + {0xfd,0x00}, + + {0x47,0x00}, + {0x48,0x00}, + {0x49,0x04}, + {0x4a,0xb0}, + + {0x4b,0x00}, + {0x4c,0x00}, + {0x4d,0x06}, + {0x4e,0x40}, + {0xfd,0x01}, + {0x06,0x00}, + {0x07,0x40}, + {0x08,0x00}, + {0x09,0x40}, + {0x0a,0x02}, //600 + {0x0b,0x58}, + {0x0c,0x03}, //800 + {0x0d,0x20}, + {0x0e,0x01}, + {0xfd,0x00}, + + {0xff,0xff}//The end flag +}; + +/* 640X480 VGA */ +static struct reginfo sensor_vga[] = +{ + {0xfd,0x00}, + + {0x47,0x00}, + {0x48,0x00}, + {0x49,0x04}, + {0x4a,0xb0}, + + {0x4b,0x00}, + {0x4c,0x00}, + {0x4d,0x06}, + {0x4e,0x40}, + + {0xfd,0x01}, + {0x06,0x00}, + {0x07,0x50}, + {0x08,0x00}, + {0x09,0x50}, + {0x0a,0x01}, //480 + {0x0b,0xe0}, + {0x0c,0x02}, //640 + {0x0d,0x80}, + {0x0e,0x01}, + {0xfd,0x00}, + + {0xff,0xff}//The end flag + + +}; +///=========SP2518-modify by sp_yjp,20120529================= + +/* 352X288 CIF */ +static struct reginfo sensor_cif[] = +{ + {0xfd, 0x00}, + {0xff,0xff} +}; + +/* 320*240 QVGA */ +static struct reginfo sensor_qvga[] = +{ + {0xfd,0x00}, + + {0x47,0x00}, + {0x48,0x00}, + {0x49,0x04}, + {0x4a,0xb0}, + {0x4b,0x00}, + {0x4c,0x00}, + {0x4d,0x06}, + {0x4e,0x40}, + + {0xfd,0x01}, + + {0x06,0x00}, + {0x07,0xa0}, + {0x08,0x00}, + {0x09,0xa0}, + + {0x0a,0x00}, //240 + {0x0b,0xf0}, + {0x0c,0x01}, //320 + {0x0d,0x40}, + + {0x0e,0x01}, + {0xfd,0x00}, + + {0xff,0xff}//The end flag +}; + +/* 176X144 QCIF*/ +static struct reginfo sensor_qcif[] = +{ + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_ClrFmt_YUYV[]= +{ + {0xfd, 0x00},{0xff,0xff} +}; + +static struct reginfo sensor_ClrFmt_UYVY[]= +{ + {0xfd, 0x00},{0xff,0xff} +}; + +///=========SP2518-modify by sp_yjp,20120529================= + +#if CONFIG_SENSOR_WhiteBalance +static struct reginfo sensor_WhiteB_Auto[]= +{ + {0xfd, 0x01}, + {0x28, 0xce}, + {0x29, 0x8a}, + {0xfd, 0x00}, + {0x32, 0x0d}, + {0xfd, 0x00}, + {0xff, 0xff} +}; +/* Cloudy Colour Temperature : 6500K - 8000K */ +static struct reginfo sensor_WhiteB_Cloudy[]= +{ + {0xfd,0x00}, + {0x32,0x05}, + {0xfd,0x01}, + {0x28,0xe2}, + {0x29,0x82}, + {0xfd,0x00}, + {0xfd,0x00}, + {0xff,0xff} +}; +/* ClearDay Colour Temperature : 5000K - 6500K */ +static struct reginfo sensor_WhiteB_ClearDay[]= +{ + {0xfd,0x00}, + {0x32,0x05}, + {0xfd,0x01}, + {0x28,0xc1}, + {0x29,0x88}, + {0xfd,0x00}, + {0xfd,0x00}, + {0xff,0xff} +}; +/* Office Colour Temperature : 3500K - 5000K */ +static struct reginfo sensor_WhiteB_TungstenLamp1[]= +{ + {0xfd,0x00}, + {0x32,0x05}, + {0xfd,0x01}, + {0x28,0x7b}, + {0x29,0xd3}, + {0xfd,0x00}, + {0xfd,0x00}, + {0xff,0xff} + +}; +/* Home Colour Temperature : 2500K - 3500K */ +static struct reginfo sensor_WhiteB_TungstenLamp2[]= +{ + {0xfd,0x00}, + {0x32,0x05}, + {0xfd,0x01}, + {0x28,0xae}, + {0x29,0xcc}, + {0xfd,0x00}, + {0xfd,0x00}, + {0xff,0xff} +}; +static struct reginfo *sensor_WhiteBalanceSeqe[] = {sensor_WhiteB_Auto, sensor_WhiteB_TungstenLamp1,sensor_WhiteB_TungstenLamp2, + sensor_WhiteB_ClearDay, sensor_WhiteB_Cloudy,NULL, +}; +#endif + + +///=========SP2518-modify by sp_yjp,20120529================= +#if CONFIG_SENSOR_Brightness +static struct reginfo sensor_Brightness0[]= +{ + {0xfd, 0x00}, + {0xdc, 0xe0}, + {0xff, 0xff} +}; + +static struct reginfo sensor_Brightness1[]= +{ + {0xfd, 0x00}, + {0xdc, 0xf0}, + {0xff, 0xff} +}; + +static struct reginfo sensor_Brightness2[]= +{ + {0xfd, 0x00}, + {0xdc, 0x00}, + {0xfd, 0x00}, + {0xff, 0xff} +}; + +static struct reginfo sensor_Brightness3[]= +{ + {0xfd, 0x00}, + {0xdc, 0x10}, + {0xff, 0xff} +}; + +static struct reginfo sensor_Brightness4[]= +{ + {0xfd, 0x00}, + {0xdc, 0x20}, + {0xff, 0xff} +}; + +static struct reginfo sensor_Brightness5[]= +{ + {0xfd, 0x00}, + {0xdc, 0x30}, + {0xff, 0xff} +}; +static struct reginfo *sensor_BrightnessSeqe[] = {sensor_Brightness0, sensor_Brightness1, sensor_Brightness2, sensor_Brightness3, + sensor_Brightness4, sensor_Brightness5,NULL, +}; + +#endif + +///=========SP2518-modify by sp_yjp,20120529================= +#if CONFIG_SENSOR_Effect +static struct reginfo sensor_Effect_Normal[] = +{ + {0xfd, 0x00}, + {0x62, 0x00}, + {0x63, 0x80}, + {0x64, 0x80}, + {0xff, 0xff} +}; + +static struct reginfo sensor_Effect_WandB[] = +{ + {0xfd, 0x00}, + {0x62, 0x20}, + {0x63, 0x80}, + {0x64, 0x80}, + {0xff, 0xff} +}; + +static struct reginfo sensor_Effect_Sepia[] = +{ + {0xfd, 0x00}, + {0x62, 0x10}, + {0x63, 0xb0}, + {0x64, 0x40}, + {0xff, 0xff} +}; + +static struct reginfo sensor_Effect_Negative[] = +{ + {0xfd, 0x00}, + {0x62, 0x04}, + {0x63, 0x80}, + {0x64, 0x80}, + {0xff, 0xff} +}; +static struct reginfo sensor_Effect_Bluish[] = +{ + {0xfd, 0x00}, + {0x62, 0x10}, + {0x63, 0x80}, + {0x64, 0xb0}, + {0xff, 0xff} +}; + +static struct reginfo sensor_Effect_Green[] = +{ + {0xfd, 0x00}, + {0x62, 0x10}, + {0x63, 0x50}, + {0x64, 0x50}, + {0xff, 0xff} +}; +static struct reginfo *sensor_EffectSeqe[] = {sensor_Effect_Normal, sensor_Effect_WandB, sensor_Effect_Negative,sensor_Effect_Sepia, + sensor_Effect_Bluish, sensor_Effect_Green,NULL, +}; +#endif + +///=========SP2518-modify by sp_yjp,20120529================= +#if CONFIG_SENSOR_Exposure +static struct reginfo sensor_Exposure0[]= +{ + //level -3 + {0xfd,0x00}, + {0xed,SP2518_P0_0xf7-0x18+0x04}, + {0xf7,SP2518_P0_0xf7-0x18}, + {0xf8,SP2518_P0_0xf8-0x18}, + {0xec,SP2518_P0_0xf8-0x18-0x04}, + {0xef,SP2518_P0_0xf9-0x18+0x04}, + {0xf9,SP2518_P0_0xf9-0x18}, + {0xfa,SP2518_P0_0xfa-0x18}, + {0xee,SP2518_P0_0xfa-0x18-0x04}, + + {0xfd, 0x00}, + {0xff,0xff} +}; + +static struct reginfo sensor_Exposure1[]= +{ + //level -2 + {0xfd,0x00}, + {0xed,SP2518_P0_0xf7-0x10+0x04}, + {0xf7,SP2518_P0_0xf7-0x10}, + {0xf8,SP2518_P0_0xf8-0x10}, + {0xec,SP2518_P0_0xf8-0x10-0x04}, + {0xef,SP2518_P0_0xf9-0x10+0x04}, + {0xf9,SP2518_P0_0xf9-0x10}, + {0xfa,SP2518_P0_0xfa-0x10}, + {0xee,SP2518_P0_0xfa-0x10-0x04}, + + {0xfd, 0x00}, + {0xff,0xff} +}; + +static struct reginfo sensor_Exposure2[]= +{ + //level -1 + {0xfd,0x00}, + {0xed,SP2518_P0_0xf7-0x08+0x04}, + {0xf7,SP2518_P0_0xf7-0x08}, + {0xf8,SP2518_P0_0xf8-0x08}, + {0xec,SP2518_P0_0xf8-0x08-0x04}, + {0xef,SP2518_P0_0xf9-0x08+0x04}, + {0xf9,SP2518_P0_0xf9-0x08}, + {0xfa,SP2518_P0_0xfa-0x08}, + {0xee,SP2518_P0_0xfa-0x08-0x04}, + + {0xfd, 0x00}, + {0xff,0xff} +}; + +static struct reginfo sensor_Exposure3[]= +{ + //level 0 + {0xfd,0x00}, + {0xed,SP2518_P0_0xf7+0x04}, + {0xf7,SP2518_P0_0xf7}, + {0xf8,SP2518_P0_0xf8}, + {0xec,SP2518_P0_0xf8-0x04}, + {0xef,SP2518_P0_0xf9+0x04}, + {0xf9,SP2518_P0_0xf9}, + {0xfa,SP2518_P0_0xfa}, + {0xee,SP2518_P0_0xfa-0x04}, + + {0xfd, 0x00}, + {0xff,0xff} +}; + +static struct reginfo sensor_Exposure4[]= +{ + //level +1 + {0xfd,0x00}, + {0xed,SP2518_P0_0xf7+0x08+0x04}, + {0xf7,SP2518_P0_0xf7+0x08}, + {0xf8,SP2518_P0_0xf8+0x08}, + {0xec,SP2518_P0_0xf8+0x08-0x04}, + {0xef,SP2518_P0_0xf9+0x08+0x04}, + {0xf9,SP2518_P0_0xf9+0x08}, + {0xfa,SP2518_P0_0xfa+0x08}, + {0xee,SP2518_P0_0xfa+0x08-0x04}, + + {0xfd, 0x00}, + {0xff,0xff} +}; + +static struct reginfo sensor_Exposure5[]= +{ + //level +2 + {0xfd,0x00}, + {0xed,SP2518_P0_0xf7+0x10+0x04}, + {0xf7,SP2518_P0_0xf7+0x10}, + {0xf8,SP2518_P0_0xf8+0x10}, + {0xec,SP2518_P0_0xf8+0x10-0x04}, + {0xef,SP2518_P0_0xf9+0x10+0x04}, + {0xf9,SP2518_P0_0xf9+0x10}, + {0xfa,SP2518_P0_0xfa+0x10}, + {0xee,SP2518_P0_0xfa+0x10-0x04}, + + {0xfd, 0x00}, + {0xff,0xff} +}; + +static struct reginfo sensor_Exposure6[]= +{ + //level +3 + {0xfd,0x00}, + {0xed,SP2518_P0_0xf7+0x18+0x04}, + {0xf7,SP2518_P0_0xf7+0x18}, + {0xf8,SP2518_P0_0xf8+0x18}, + {0xec,SP2518_P0_0xf8+0x18-0x04}, + {0xef,SP2518_P0_0xf9+0x18+0x04}, + {0xf9,SP2518_P0_0xf9+0x18}, + {0xfa,SP2518_P0_0xfa+0x18}, + {0xee,SP2518_P0_0xfa+0x18-0x04}, + + {0xfd, 0x00}, + {0xff,0xff} +}; + +static struct reginfo *sensor_ExposureSeqe[] = {sensor_Exposure0, sensor_Exposure1, sensor_Exposure2, sensor_Exposure3, + sensor_Exposure4, sensor_Exposure5,sensor_Exposure6,NULL, +}; +#endif + +///=========SP2518-modify by sp_yjp,20120529================= +#if CONFIG_SENSOR_Saturation +static struct reginfo sensor_Saturation0[]= +{ + {0xfd, 0x00}, + {0xff, 0xff} +}; + +static struct reginfo sensor_Saturation1[]= +{ + {0xfd, 0x00}, + {0xff, 0xff} +}; + +static struct reginfo sensor_Saturation2[]= +{ + {0xfd, 0x00}, + {0xff, 0xff} +}; +static struct reginfo *sensor_SaturationSeqe[] = {sensor_Saturation0, sensor_Saturation1, sensor_Saturation2, NULL,}; + +#endif + +///=========SP2518-modify by sp_yjp,20120529================= +#if CONFIG_SENSOR_Contrast +static struct reginfo sensor_Contrast0[]= +{ + //level -3 + {0xfd , 0x00}, + {0xdd , SP2518_P0_0xdd-0x30}, + {0xde , SP2518_P0_0xde-0x30}, + {0xff , 0xff} +}; + +static struct reginfo sensor_Contrast1[]= +{ + //level -2 + {0xfd , 0x00}, + {0xdd , SP2518_P0_0xdd-0x20}, + {0xde , SP2518_P0_0xde-0x20}, + {0xff , 0xff} +}; + +static struct reginfo sensor_Contrast2[]= +{ + //level -1 + {0xfd , 0x00}, + {0xdd , SP2518_P0_0xdd-0x10}, + {0xde , SP2518_P0_0xde-0x10}, + {0xff , 0xff} +}; + +static struct reginfo sensor_Contrast3[]= +{ + //level 0 + {0xfd , 0x00}, + {0xdd , SP2518_P0_0xdd}, + {0xde , SP2518_P0_0xde}, + {0xff , 0xff} +}; + +static struct reginfo sensor_Contrast4[]= +{ + //level +1 + {0xfd , 0x00}, + {0xdd , SP2518_P0_0xdd+0x10}, + {0xde , SP2518_P0_0xde+0x10}, + {0xff , 0xff} +}; + + +static struct reginfo sensor_Contrast5[]= +{ + //level +2 + {0xfd , 0x00}, + {0xdd , SP2518_P0_0xdd+0x20}, + {0xde , SP2518_P0_0xde+0x20}, + {0xff , 0xff} +}; + +static struct reginfo sensor_Contrast6[]= +{ + //level +3 + {0xfd , 0x00}, + {0xdd , SP2518_P0_0xdd+0x30}, + {0xde , SP2518_P0_0xde+0x30}, + {0xff , 0xff} +}; + + + + +static struct reginfo *sensor_ContrastSeqe[] = {sensor_Contrast0, sensor_Contrast1, sensor_Contrast2, sensor_Contrast3, + sensor_Contrast4, sensor_Contrast5, sensor_Contrast6, NULL, +}; + +#endif + + +///=========SP2518-modify by sp_yjp,20120529================= +#if CONFIG_SENSOR_Mirror +static struct reginfo sensor_MirrorOn[]= +{ + {0xfd, 0x00}, + {0x31, 0x30}, + {0xff, 0xff} +}; + +static struct reginfo sensor_MirrorOff[]= +{ + {0xfd, 0x00}, + {0x31, 0x10}, + {0xff, 0xff} +}; +static struct reginfo *sensor_MirrorSeqe[] = {sensor_MirrorOff, sensor_MirrorOn,NULL,}; +#endif +#if CONFIG_SENSOR_Flip +static struct reginfo sensor_FlipOn[]= +{ + {0xfd, 0x00}, + {0x31, 0x50}, + {0xff, 0xff} +}; + +static struct reginfo sensor_FlipOff[]= +{ + {0xfd, 0x00}, + {0x31, 0x10}, + {0xff, 0xff} +}; +static struct reginfo *sensor_FlipSeqe[] = {sensor_FlipOff, sensor_FlipOn,NULL,}; + +#endif + +///=========SP2518-modify by sp_yjp,20120529================= +#if CONFIG_SENSOR_Scene//? zch +static struct reginfo sensor_SceneAuto[] = +{ + #if 1 + {0xfd, 0x00}, + {0xb2,SP2518_NORMAL_Y0ffset}, + {0xb3,0x1f}, + + ///SP2518 UXGA 24MEclk 3PLL 50Hz fix 10fps + {0xfd , 0x00}, + {0x03 , 0x03}, + {0x04 , 0x66}, + {0x05 , 0x00}, + {0x06 , 0x8b}, + {0x07 , 0x00}, + {0x08 , 0x8b}, + {0x09 , 0x01}, + {0x0a , 0x3b}, + {0xf0 , 0x91}, + {0xf1 , 0x00}, + {0xfd , 0x01}, + {0x90 , 0x0a}, + {0x92 , 0x01}, + {0x98 , 0x91}, + {0x99 , 0x00}, + {0x9a , 0x01}, + {0x9b , 0x00}, + ///Status + {0xfd , 0x01}, + {0xce , 0xaa}, + {0xcf , 0x05}, + {0xd0 , 0xaa}, + {0xd1 , 0x05}, + {0xd7 , 0x8d}, + {0xd8 , 0x00}, + {0xd9 , 0x91}, + {0xda , 0x00}, + {0xfd , 0x00}, + #endif + + {0xfd, 0x00}, + {0xff, 0xff} +}; + +static struct reginfo sensor_SceneNight[] = +{ + #if 1 + {0xfd,0x00}, + {0xb2,SP2518_LOWLIGHT_Y0ffset}, + {0xb3,0x1f}, + + //SP2518 UXGA 24MEclk 3PLL 50Hz fix 6fps + {0xfd , 0x00}, + {0x03 , 0x01}, + {0x04 , 0xfe}, + {0x05 , 0x00}, + {0x06 , 0x6d}, + {0x07 , 0x00}, + {0x08 , 0x6d}, + {0x09 , 0x04}, + {0x0a , 0xa8}, + {0xf0 , 0x55}, + {0xf1 , 0x00}, + {0xfd , 0x01}, + {0x90 , 0x10}, + {0x92 , 0x01}, + {0x98 , 0x55}, + {0x99 , 0x00}, + {0x9a , 0x01}, + {0x9b , 0x00}, + ///Status + {0xfd , 0x01}, + {0xce , 0x50}, + {0xcf , 0x05}, + {0xd0 , 0x50}, + {0xd1 , 0x05}, + {0xd7 , 0x51}, + {0xd8 , 0x00}, + {0xd9 , 0x55}, + {0xda , 0x00}, + #endif + + {0xfd,0x00}, + {0xff,0xff} +}; + + + +static struct reginfo *sensor_SceneSeqe[] = {sensor_SceneAuto, sensor_SceneNight,NULL,}; + +#endif + +///=========SP2518-modify by sp_yjp,20120529================= +#if CONFIG_SENSOR_DigitalZoom +static struct reginfo sensor_Zoom0[] = +{ + {0xfd,0x00}, + {0xff,0xff} +}; + +static struct reginfo sensor_Zoom1[] = +{ + {0xfd,0x00}, + {0xff,0xff} +}; + +static struct reginfo sensor_Zoom2[] = +{ + {0xfd,0x00}, + {0xff,0xff} +}; + + +static struct reginfo sensor_Zoom3[] = +{ + {0xfd,0x00}, + {0xff,0xff} +}; +static struct reginfo *sensor_ZoomSeqe[] = {sensor_Zoom0, sensor_Zoom1, sensor_Zoom2, sensor_Zoom3, NULL,}; +#endif + + +///=========SP2518-modify by sp_yjp,20120529================= +static const struct v4l2_querymenu sensor_menus[] = +{ + #if CONFIG_SENSOR_WhiteBalance + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 0, .name = "auto", .reserved = 0, }, { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 1, .name = "incandescent", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 2, .name = "fluorescent", .reserved = 0,}, { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 3, .name = "daylight", .reserved = 0,}, + { .id = V4L2_CID_DO_WHITE_BALANCE, .index = 4, .name = "cloudy-daylight", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Effect + { .id = V4L2_CID_EFFECT, .index = 0, .name = "none", .reserved = 0, }, { .id = V4L2_CID_EFFECT, .index = 1, .name = "mono", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 2, .name = "negative", .reserved = 0,}, { .id = V4L2_CID_EFFECT, .index = 3, .name = "sepia", .reserved = 0,}, + { .id = V4L2_CID_EFFECT, .index = 4, .name = "posterize", .reserved = 0,} ,{ .id = V4L2_CID_EFFECT, .index = 5, .name = "aqua", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Scene + { .id = V4L2_CID_SCENE, .index = 0, .name = "auto", .reserved = 0,} ,{ .id = V4L2_CID_SCENE, .index = 1, .name = "night", .reserved = 0,}, + #endif + + #if CONFIG_SENSOR_Flash + { .id = V4L2_CID_FLASH, .index = 0, .name = "off", .reserved = 0, }, { .id = V4L2_CID_FLASH, .index = 1, .name = "auto", .reserved = 0,}, + { .id = V4L2_CID_FLASH, .index = 2, .name = "on", .reserved = 0,}, { .id = V4L2_CID_FLASH, .index = 3, .name = "torch", .reserved = 0,}, + #endif +}; + +static const struct v4l2_queryctrl sensor_controls[] = +{ + #if CONFIG_SENSOR_WhiteBalance + { + .id = V4L2_CID_DO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "White Balance Control", + .minimum = 0, + .maximum = 4, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Brightness + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness Control", + .minimum = -3, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Effect + { + .id = V4L2_CID_EFFECT, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Effect Control", + .minimum = 0, + .maximum = 5, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Exposure + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure Control", + .minimum = 0, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Saturation + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation Control", + .minimum = 0, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Contrast + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast Control", + .minimum = -3, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Mirror + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + #endif + + #if CONFIG_SENSOR_Flip + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + #endif + + #if CONFIG_SENSOR_Scene + { + .id = V4L2_CID_SCENE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Scene Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_DigitalZoom + { + .id = V4L2_CID_ZOOM_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DigitalZoom Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_ZOOM_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DigitalZoom Control", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif + + #if CONFIG_SENSOR_Focus + { + .id = V4L2_CID_FOCUS_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Focus Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_FOCUS_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Focus Control", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 125, + }, + #endif + + #if CONFIG_SENSOR_Flash + { + .id = V4L2_CID_FLASH, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Flash Control", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + }, + #endif +}; + +static int sensor_probe(struct i2c_client *client, const struct i2c_device_id *did); +static int sensor_video_probe(struct soc_camera_device *icd, struct i2c_client *client); +static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl); +static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl); +static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg); +static int sensor_resume(struct soc_camera_device *icd); +static int sensor_set_bus_param(struct soc_camera_device *icd,unsigned long flags); +static unsigned long sensor_query_bus_param(struct soc_camera_device *icd); +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value); +static int sensor_deactivate(struct i2c_client *client); + +static struct soc_camera_ops sensor_ops = +{ + .suspend = sensor_suspend, + .resume = sensor_resume, + .set_bus_param = sensor_set_bus_param, + .query_bus_param = sensor_query_bus_param, + .controls = sensor_controls, + .menus = sensor_menus, + .num_controls = ARRAY_SIZE(sensor_controls), + .num_menus = ARRAY_SIZE(sensor_menus), +}; + +/* only one fixed colorspace per pixelcode */ +struct sensor_datafmt { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; +}; + +/* Find a data format by a pixel code in an array */ +static const struct sensor_datafmt *sensor_find_datafmt( + enum v4l2_mbus_pixelcode code, const struct sensor_datafmt *fmt, + int n) +{ + int i; + for (i = 0; i < n; i++) + if (fmt[i].code == code) + return fmt + i; + + return NULL; +} + +static const struct sensor_datafmt sensor_colour_fmts[] = { + {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG} +}; + +typedef struct sensor_info_priv_s +{ + int whiteBalance; + int brightness; + int contrast; + int saturation; + int effect; + int scene; + int digitalzoom; + int focus; + int flash; + int exposure; + bool snap2preview; + bool video2preview; + unsigned char mirror; /* HFLIP */ + unsigned char flip; /* VFLIP */ + unsigned int winseqe_cur_addr; + struct sensor_datafmt fmt; + unsigned int funmodule_state; +} sensor_info_priv_t; + +struct sensor +{ + struct v4l2_subdev subdev; + struct i2c_client *client; + sensor_info_priv_t info_priv; + int model; /* V4L2_IDENT_OV* codes from v4l2-chip-ident.h */ +#if CONFIG_SENSOR_I2C_NOSCHED + atomic_t tasklock_cnt; +#endif + struct rk29camera_platform_data *sensor_io_request; + struct rk29camera_gpio_res *sensor_gpio_res; +}; + +static struct sensor* to_sensor(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct sensor, subdev); +} + +static int sensor_task_lock(struct i2c_client *client, int lock) +{ +#if CONFIG_SENSOR_I2C_NOSCHED + int cnt = 3; + struct sensor *sensor = to_sensor(client); + + if (lock) { + if (atomic_read(&sensor->tasklock_cnt) == 0) { + while ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt>0)) { + SENSOR_TR("\n %s will obtain i2c in atomic, but i2c bus is locked! Wait...\n",SENSOR_NAME_STRING()); + msleep(35); + cnt--; + } + if ((atomic_read(&client->adapter->bus_lock.count) < 1) && (cnt<=0)) { + SENSOR_TR("\n %s obtain i2c fail in atomic!!\n",SENSOR_NAME_STRING()); + goto sensor_task_lock_err; + } + preempt_disable(); + } + + atomic_add(1, &sensor->tasklock_cnt); + } else { + if (atomic_read(&sensor->tasklock_cnt) > 0) { + atomic_sub(1, &sensor->tasklock_cnt); + + if (atomic_read(&sensor->tasklock_cnt) == 0) + preempt_enable(); + } + } + return 0; +sensor_task_lock_err: + return -1; +#else + return 0; +#endif + +} + +/* sensor register write */ +static int sensor_write(struct i2c_client *client, u8 reg, u8 val) +{ + int err,cnt; + u8 buf[2]; + struct i2c_msg msg[1]; + + buf[0] = reg & 0xFF; + buf[1] = val; + + msg->addr = client->addr; + msg->flags = client->flags; + msg->buf = buf; + msg->len = sizeof(buf); + msg->scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg->read_type = 0; /* fpga i2c:0==I2C_NORMAL : direct use number not enum for don't want include spi_fpga.h */ + + cnt = 3; + err = -EAGAIN; + + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + err = i2c_transfer(client->adapter, msg, 1); + + if (err >= 0) { + return 0; + } else { + SENSOR_TR("\n %s write reg(0x%x, val:0x%x) failed, try to write again!\n",SENSOR_NAME_STRING(),reg, val); + udelay(10); + } + } + + return err; +} + +/* sensor register read */ +static int sensor_read(struct i2c_client *client, u8 reg, u8 *val) +{ + int err,cnt; + //u8 buf[2]; + u8 buf[1]; + struct i2c_msg msg[2]; + + //buf[0] = reg >> 8; + buf[0] = reg; + buf[1] = reg & 0xFF; + + msg[0].addr = client->addr; + msg[0].flags = client->flags; + msg[0].buf = buf; + msg[0].len = sizeof(buf); + msg[0].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg[0].read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */ + + msg[1].addr = client->addr; + msg[1].flags = client->flags|I2C_M_RD; + msg[1].buf = buf; + msg[1].len = 1; + msg[1].scl_rate = CONFIG_SENSOR_I2C_SPEED; /* ddl@rock-chips.com : 100kHz */ + msg[1].read_type = 2; /* fpga i2c:0==I2C_NO_STOP : direct use number not enum for don't want include spi_fpga.h */ + + cnt = 1; + err = -EAGAIN; + while ((cnt-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */ + err = i2c_transfer(client->adapter, msg, 2); + + if (err >= 0) { + *val = buf[0]; + return 0; + } else { + SENSOR_TR("\n %s read reg(0x%x val:0x%x) failed, try to read again! \n",SENSOR_NAME_STRING(),reg, *val); + udelay(10); + } + } + + return err; +} + +/* write a array of registers */ +static int sensor_write_array(struct i2c_client *client, struct reginfo *regarray) +{ + int err; + int i = 0; + + while((regarray[i].reg != 0xff) || (regarray[i].val != 0xff)) + { + err = sensor_write(client, regarray[i].reg, regarray[i].val); + if (err != 0) + { + SENSOR_TR("%s..write failed current i = %d\n", SENSOR_NAME_STRING(),i); + return err; + } + i++; + } + + return 0; +} +#if CONFIG_SENSOR_I2C_RDWRCHK +static int sensor_check_array(struct i2c_client *client, struct reginfo *regarray) +{ + int ret; + int i = 0; + + u8 value; + + while((regarray[i].reg != 0xff) || (regarray[i].val != 0xff)) + { + ret = sensor_read(client,regarray[i].reg,&value); + if(ret !=0) + { + SENSOR_TR("read value failed\n"); + + } + if(regarray[i].val != value) + { + SENSOR_DG("%s reg[0x%x] check err,writte :0x%x read:0x%x\n",__FUNCTION__,regarray[i].reg,regarray[i].val,value); + } + + } + + + return 0; +} +#endif +static int sensor_ioctrl(struct soc_camera_device *icd,enum rk29sensor_power_cmd cmd, int on) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + int ret = 0; + + SENSOR_DG("%s %s cmd(%d) on(%d)\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd,on); + switch (cmd) + { + case Sensor_PowerDown: + { + if (icl->powerdown) { + ret = icl->powerdown(icd->pdev, on); + if (ret == RK29_CAM_IO_SUCCESS) { + if (on == 0) { + mdelay(2); + if (icl->reset) + icl->reset(icd->pdev); + } + } else if (ret == RK29_CAM_EIO_REQUESTFAIL) { + ret = -ENODEV; + goto sensor_power_end; + } + } + break; + } + case Sensor_Flash: + { + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + if (sensor->sensor_io_request && sensor->sensor_io_request->sensor_ioctrl) { + sensor->sensor_io_request->sensor_ioctrl(icd->pdev,Cam_Flash, on); + } + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown!",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } +sensor_power_end: + return ret; +} + +static int sensor_init(struct v4l2_subdev *sd, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + const struct sensor_datafmt *fmt; + int ret; + + SENSOR_DG("\n%s..%s.. \n",SENSOR_NAME_STRING(),__FUNCTION__); + + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_INIT_ERR; + } + msleep(10); + if (sensor_ioctrl(icd, Sensor_PowerDown, 1) < 0) { + ret = -ENODEV; + goto sensor_INIT_ERR; + } + msleep(10); + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_INIT_ERR; + } + msleep(10); + + /* soft reset */ + if (sensor_task_lock(client,1)<0) + goto sensor_INIT_ERR; + /* ret = sensor_write(client, 0x12, 0x80); + if (ret != 0) + { + SENSOR_TR("%s soft reset sensor failed\n",SENSOR_NAME_STRING()); + ret = -ENODEV; + goto sensor_INIT_ERR; + } + + mdelay(5); */ //delay 5 microseconds + + ret = sensor_write_array(client, sensor_init_data); + if (ret != 0) + { + SENSOR_TR("error: %s initial failed\n",SENSOR_NAME_STRING()); + goto sensor_INIT_ERR; + } + + sensor_task_lock(client,0); + + sensor->info_priv.winseqe_cur_addr = (int)SENSOR_INIT_WINSEQADR; + fmt = sensor_find_datafmt(SENSOR_INIT_PIXFMT,sensor_colour_fmts, ARRAY_SIZE(sensor_colour_fmts)); + if (!fmt) { + SENSOR_TR("error: %s initial array colour fmts is not support!!",SENSOR_NAME_STRING()); + ret = -EINVAL; + goto sensor_INIT_ERR; + } + sensor->info_priv.fmt = *fmt; + + /* sensor sensor information for initialization */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + if (qctrl) + sensor->info_priv.whiteBalance = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_BRIGHTNESS); + if (qctrl) + sensor->info_priv.brightness = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + if (qctrl) + sensor->info_priv.effect = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EXPOSURE); + if (qctrl) + sensor->info_priv.exposure = qctrl->default_value; + + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SATURATION); + if (qctrl) + sensor->info_priv.saturation = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_CONTRAST); + if (qctrl) + sensor->info_priv.contrast = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_HFLIP); + if (qctrl) + sensor->info_priv.mirror = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_VFLIP); + if (qctrl) + sensor->info_priv.flip = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_SCENE); + if (qctrl) + sensor->info_priv.scene = qctrl->default_value; + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE); + if (qctrl) + sensor->info_priv.digitalzoom = qctrl->default_value; + + /* ddl@rock-chips.com : if sensor support auto focus and flash, programer must run focus and flash code */ + #if CONFIG_SENSOR_Focus + sensor_set_focus(); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FOCUS_ABSOLUTE); + if (qctrl) + sensor->info_priv.focus = qctrl->default_value; + #endif + + #if CONFIG_SENSOR_Flash + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FLASH); + if (qctrl) + sensor->info_priv.flash = qctrl->default_value; + #endif + + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),((val == 0)?__FUNCTION__:"sensor_reinit"),icd->user_width,icd->user_height); + sensor->info_priv.funmodule_state |= SENSOR_INIT_IS_OK; + return 0; +sensor_INIT_ERR: + sensor->info_priv.funmodule_state &= ~SENSOR_INIT_IS_OK; + sensor_task_lock(client,0); + sensor_deactivate(client); + return ret; +} + +static int sensor_deactivate(struct i2c_client *client) +{ + struct soc_camera_device *icd = client->dev.platform_data; + //u8 reg_val; + struct sensor *sensor = to_sensor(client); + SENSOR_DG("\n%s..%s.. Enter\n",SENSOR_NAME_STRING(),__FUNCTION__); + + /* ddl@rock-chips.com : all sensor output pin must change to input for other sensor */ + sensor_ioctrl(icd, Sensor_PowerDown, 1); + msleep(100); + + /* ddl@rock-chips.com : sensor config init width , because next open sensor quickly(soc_camera_open -> Try to configure with default parameters) */ + icd->user_width = SENSOR_INIT_WIDTH; + icd->user_height = SENSOR_INIT_HEIGHT; + sensor->info_priv.funmodule_state &= ~SENSOR_INIT_IS_OK; + + return 0; +} +static struct reginfo sensor_power_down_sequence[]= +{ + {0xfd,0x00}, + {0xff,0xff} +}; +static int sensor_suspend(struct soc_camera_device *icd, pm_message_t pm_msg) +{ + int ret; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if (pm_msg.event == PM_EVENT_SUSPEND) { + SENSOR_DG("\n %s Enter Suspend.. \n", SENSOR_NAME_STRING()); + ret = sensor_write_array(client, sensor_power_down_sequence) ; + if (ret != 0) { + SENSOR_TR("\n %s..%s WriteReg Fail.. \n", SENSOR_NAME_STRING(),__FUNCTION__); + return ret; + } else { + ret = sensor_ioctrl(icd, Sensor_PowerDown, 1); + if (ret < 0) { + SENSOR_TR("\n %s suspend fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + } + } else { + SENSOR_TR("\n %s cann't suppout Suspend..\n",SENSOR_NAME_STRING()); + return -EINVAL; + } + return 0; +} + +static int sensor_resume(struct soc_camera_device *icd) +{ + int ret; + + ret = sensor_ioctrl(icd, Sensor_PowerDown, 0); + if (ret < 0) { + SENSOR_TR("\n %s resume fail for turn on power!\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + + SENSOR_DG("\n %s Enter Resume.. \n", SENSOR_NAME_STRING()); + + return 0; + +} + +static int sensor_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + + return 0; +} + +static unsigned long sensor_query_bus_param(struct soc_camera_device *icd) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + unsigned long flags = SENSOR_BUS_PARAM; + + return soc_camera_apply_sensor_flags(icl, flags); +} + +static int sensor_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + + mf->width = icd->user_width; + mf->height = icd->user_height; + mf->code = sensor->info_priv.fmt.code; + mf->colorspace = sensor->info_priv.fmt.colorspace; + mf->field = V4L2_FIELD_NONE; + + return 0; +} +static bool sensor_fmt_capturechk(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + bool ret = false; + + if ((mf->width == 1024) && (mf->height == 768)) { + ret = true; + } else if ((mf->width == 1280) && (mf->height == 1024)) { + ret = true; + } else if ((mf->width == 1600) && (mf->height == 1200)) { + ret = true; + } else if ((mf->width == 2048) && (mf->height == 1536)) { + ret = true; + } else if ((mf->width == 2592) && (mf->height == 1944)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is capture format\n", __FUNCTION__, mf->width, mf->height); + return ret; +} + +static bool sensor_fmt_videochk(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + bool ret = false; + + if ((mf->width == 1280) && (mf->height == 720)) { + ret = true; + } else if ((mf->width == 1920) && (mf->height == 1080)) { + ret = true; + } + + if (ret == true) + SENSOR_DG("%s %dx%d is video format\n", __FUNCTION__, mf->width, mf->height); + return ret; +} +static int sensor_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + const struct sensor_datafmt *fmt; + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + struct soc_camera_device *icd = client->dev.platform_data; + struct reginfo *winseqe_set_addr=NULL; + int ret=0, set_w,set_h; + + fmt = sensor_find_datafmt(mf->code, sensor_colour_fmts, + ARRAY_SIZE(sensor_colour_fmts)); + if (!fmt) { + ret = -EINVAL; + goto sensor_s_fmt_end; + } + + if (sensor->info_priv.fmt.code != mf->code) { + switch (mf->code) + { + case V4L2_MBUS_FMT_YUYV8_2X8: + { + winseqe_set_addr = sensor_ClrFmt_YUYV; + break; + } + case V4L2_MBUS_FMT_UYVY8_2X8: + { + winseqe_set_addr = sensor_ClrFmt_UYVY; + break; + } + default: + break; + } + if (winseqe_set_addr != NULL) { + sensor_write_array(client, winseqe_set_addr); + sensor->info_priv.fmt.code = mf->code; + sensor->info_priv.fmt.colorspace= mf->colorspace; + SENSOR_DG("%s v4l2_mbus_code:%d set success!\n", SENSOR_NAME_STRING(),mf->code); + } else { + SENSOR_TR("%s v4l2_mbus_code:%d is invalidate!\n", SENSOR_NAME_STRING(),mf->code); + } + } + + set_w = mf->width; + set_h = mf->height; + + if (((set_w <= 176) && (set_h <= 144)) && sensor_qcif[0].reg) + { + winseqe_set_addr = sensor_qcif; + set_w = 176; + set_h = 144; + } + else if (((set_w <= 320) && (set_h <= 240)) && sensor_qvga[0].reg) + { + winseqe_set_addr = sensor_qvga; + set_w = 320; + set_h = 240; + } + else if (((set_w <= 352) && (set_h<= 288)) && sensor_cif[0].reg) + { + winseqe_set_addr = sensor_cif; + set_w = 352; + set_h = 288; + } + else if (((set_w <= 640) && (set_h <= 480)) && sensor_vga[0].reg) + { + winseqe_set_addr = sensor_vga; + set_w = 640-16; + set_h = 480-16; + } + else if (((set_w <= 800) && (set_h <= 600)) && sensor_svga[0].reg) + { + winseqe_set_addr = sensor_svga; + set_w = 800; + set_h = 600; + } + else if (((set_w <= 1280) && (set_h <= 1024)) && sensor_sxga[0].reg) + { + winseqe_set_addr = sensor_sxga; + set_w = 1280; + set_h = 1024; + } + else if (((set_w <= 1600) && (set_h <= 1200)) && sensor_uxga[0].reg) + { + winseqe_set_addr = sensor_uxga; + set_w = 1600; + set_h = 1200; + } + else + { + winseqe_set_addr = SENSOR_INIT_WINSEQADR; /* ddl@rock-chips.com : Sensor output smallest size if isn't support app */ + set_w = SENSOR_INIT_WIDTH; + set_h = SENSOR_INIT_HEIGHT; + SENSOR_TR("\n %s..%s Format is Invalidate. pix->width = %d.. pix->height = %d\n",SENSOR_NAME_STRING(),__FUNCTION__,mf->width,mf->height); + } + + if ((int)winseqe_set_addr != sensor->info_priv.winseqe_cur_addr) { + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,mf) == true) { /* ddl@rock-chips.com : Capture */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_On); + SENSOR_DG("%s flash on in capture!\n", SENSOR_NAME_STRING()); + } + } else { /* ddl@rock-chips.com : Video */ + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_DG("%s flash off in preivew!\n", SENSOR_NAME_STRING()); + } + } + #endif + ret |= sensor_write_array(client, winseqe_set_addr); + if (ret != 0) { + SENSOR_TR("%s set format capability failed\n", SENSOR_NAME_STRING()); + #if CONFIG_SENSOR_Flash + if (sensor_fmt_capturechk(sd,mf) == true) { + if ((sensor->info_priv.flash == 1) || (sensor->info_priv.flash == 2)) { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + SENSOR_TR("%s Capture format set fail, flash off !\n", SENSOR_NAME_STRING()); + } + } + #endif + goto sensor_s_fmt_end; + } + + sensor->info_priv.winseqe_cur_addr = (int)winseqe_set_addr; + + if (sensor_fmt_capturechk(sd,mf) == true) { /* ddl@rock-chips.com : Capture */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + if (sensor->info_priv.whiteBalance != 0) { + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + } + sensor->info_priv.snap2preview = true; + } else if (sensor_fmt_videochk(sd,mf) == true) { /* ddl@rock-chips.com : Video */ + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + sensor->info_priv.video2preview = true; + } else if ((sensor->info_priv.snap2preview == true) || (sensor->info_priv.video2preview == true)) { + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_EFFECT); + sensor_set_effect(icd, qctrl,sensor->info_priv.effect); + qctrl = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_DO_WHITE_BALANCE); + sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance); + msleep(600); + sensor->info_priv.video2preview = false; + sensor->info_priv.snap2preview = false; + } + + SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),__FUNCTION__,set_w,set_h); + } + else + { + SENSOR_DG("\n %s .. Current Format is validate. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),set_w,set_h); + } + + mf->width = set_w; + mf->height = set_h; + +sensor_s_fmt_end: + return ret; +} + +static int sensor_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct sensor *sensor = to_sensor(client); + const struct sensor_datafmt *fmt; + int ret = 0,set_w,set_h; + + fmt = sensor_find_datafmt(mf->code, sensor_colour_fmts, + ARRAY_SIZE(sensor_colour_fmts)); + if (fmt == NULL) { + fmt = &sensor->info_priv.fmt; + mf->code = fmt->code; + } + + if (mf->height > SENSOR_MAX_HEIGHT) + mf->height = SENSOR_MAX_HEIGHT; + else if (mf->height < SENSOR_MIN_HEIGHT) + mf->height = SENSOR_MIN_HEIGHT; + + if (mf->width > SENSOR_MAX_WIDTH) + mf->width = SENSOR_MAX_WIDTH; + else if (mf->width < SENSOR_MIN_WIDTH) + mf->width = SENSOR_MIN_WIDTH; + + set_w = mf->width; + set_h = mf->height; + + if (((set_w <= 176) && (set_h <= 144)) && sensor_qcif[0].reg) + { + set_w = 176; + set_h = 144; + } + else if (((set_w <= 320) && (set_h <= 240)) && sensor_qvga[0].reg) + { + set_w = 320; + set_h = 240; + } + else if (((set_w <= 352) && (set_h<= 288)) && sensor_cif[0].reg) + { + set_w = 352; + set_h = 288; + } + else if (((set_w <= 640) && (set_h <= 480)) && sensor_vga[0].reg) + { + set_w = 640; + set_h = 480; + } + else if (((set_w <= 800) && (set_h <= 600)) && sensor_svga[0].reg) + { + set_w = 800; + set_h = 600; + } + else if (((set_w <= 1280) && (set_h <= 1024)) && sensor_sxga[0].reg) + { + set_w = 1280; + set_h = 1024; + } + else if (((set_w <= 1600) && (set_h <= 1200)) && sensor_uxga[0].reg) + { + set_w = 1600; + set_h = 1200; + } + else + { + set_w = SENSOR_INIT_WIDTH; + set_h = SENSOR_INIT_HEIGHT; + } + + mf->width = set_w; + mf->height = set_h; + + mf->colorspace = fmt->colorspace; + + return ret; +} + + static int sensor_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *id) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) + return -EINVAL; + + if (id->match.addr != client->addr) + return -ENODEV; + + id->ident = SENSOR_V4L2_IDENT; /* ddl@rock-chips.com : Return OV9650 identifier */ + id->revision = 0; + + return 0; +} +#if CONFIG_SENSOR_Brightness +static int sensor_set_brightness(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_BrightnessSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_BrightnessSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Effect +static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_EffectSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_EffectSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Exposure +static int sensor_set_exposure(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_ExposureSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_ExposureSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Saturation +static int sensor_set_saturation(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_SaturationSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_SaturationSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Contrast +static int sensor_set_contrast(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_ContrastSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_ContrastSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Mirror +static int sensor_set_mirror(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_MirrorSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_MirrorSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Flip +static int sensor_set_flip(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_FlipSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_FlipSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Scene +static int sensor_set_scene(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_SceneSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_SceneSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_WhiteBalance +static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) + { + if (sensor_WhiteBalanceSeqe[value - qctrl->minimum] != NULL) + { + if (sensor_write_array(client, sensor_WhiteBalanceSeqe[value - qctrl->minimum]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + } + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_DigitalZoom +static int sensor_set_digitalzoom(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int *value) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl_info; + int digitalzoom_cur, digitalzoom_total; + + qctrl_info = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_ZOOM_ABSOLUTE); + if (qctrl_info) + return -EINVAL; + + digitalzoom_cur = sensor->info_priv.digitalzoom; + digitalzoom_total = qctrl_info->maximum; + + if ((*value > 0) && (digitalzoom_cur >= digitalzoom_total)) + { + SENSOR_TR("%s digitalzoom is maximum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur); + return -EINVAL; + } + + if ((*value < 0) && (digitalzoom_cur <= qctrl_info->minimum)) + { + SENSOR_TR("%s digitalzoom is minimum - %x\n", SENSOR_NAME_STRING(), digitalzoom_cur); + return -EINVAL; + } + + if ((*value > 0) && ((digitalzoom_cur + *value) > digitalzoom_total)) + { + *value = digitalzoom_total - digitalzoom_cur; + } + + if ((*value < 0) && ((digitalzoom_cur + *value) < 0)) + { + *value = 0 - digitalzoom_cur; + } + + digitalzoom_cur += *value; + + if (sensor_ZoomSeqe[digitalzoom_cur] != NULL) + { + if (sensor_write_array(client, sensor_ZoomSeqe[digitalzoom_cur]) != 0) + { + SENSOR_TR("%s..%s WriteReg Fail.. \n",SENSOR_NAME_STRING(), __FUNCTION__); + return -EINVAL; + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, *value); + return 0; + } + + return -EINVAL; +} +#endif +#if CONFIG_SENSOR_Flash +static int sensor_set_flash(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +{ + if ((value >= qctrl->minimum) && (value <= qctrl->maximum)) { + if (value == 3) { /* ddl@rock-chips.com: torch */ + sensor_ioctrl(icd, Sensor_Flash, Flash_Torch); /* Flash On */ + } else { + sensor_ioctrl(icd, Sensor_Flash, Flash_Off); + } + SENSOR_DG("%s..%s : %x\n",SENSOR_NAME_STRING(),__FUNCTION__, value); + return 0; + } + + SENSOR_TR("\n %s..%s valure = %d is invalidate.. \n",SENSOR_NAME_STRING(),__FUNCTION__,value); + return -EINVAL; +} +#endif + +static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct sensor *sensor = to_sensor(client); + const struct v4l2_queryctrl *qctrl; + + qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + return -EINVAL; + } + + switch (ctrl->id) + { + case V4L2_CID_BRIGHTNESS: + { + ctrl->value = sensor->info_priv.brightness; + break; + } + case V4L2_CID_SATURATION: + { + ctrl->value = sensor->info_priv.saturation; + break; + } + case V4L2_CID_CONTRAST: + { + ctrl->value = sensor->info_priv.contrast; + break; + } + case V4L2_CID_DO_WHITE_BALANCE: + { + ctrl->value = sensor->info_priv.whiteBalance; + break; + } + case V4L2_CID_EXPOSURE: + { + ctrl->value = sensor->info_priv.exposure; + break; + } + case V4L2_CID_HFLIP: + { + ctrl->value = sensor->info_priv.mirror; + break; + } + case V4L2_CID_VFLIP: + { + ctrl->value = sensor->info_priv.flip; + break; + } + default : + break; + } + return 0; +} + + + +static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct sensor *sensor = to_sensor(client); + struct soc_camera_device *icd = client->dev.platform_data; + const struct v4l2_queryctrl *qctrl; + + + qctrl = soc_camera_find_qctrl(&sensor_ops, ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ctrl->id); + return -EINVAL; + } + + switch (ctrl->id) + { +#if CONFIG_SENSOR_Brightness + case V4L2_CID_BRIGHTNESS: + { + if (ctrl->value != sensor->info_priv.brightness) + { + if (sensor_set_brightness(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.brightness = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Exposure + case V4L2_CID_EXPOSURE: + { + if (ctrl->value != sensor->info_priv.exposure) + { + if (sensor_set_exposure(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.exposure = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Saturation + case V4L2_CID_SATURATION: + { + if (ctrl->value != sensor->info_priv.saturation) + { + if (sensor_set_saturation(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.saturation = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Contrast + case V4L2_CID_CONTRAST: + { + if (ctrl->value != sensor->info_priv.contrast) + { + if (sensor_set_contrast(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.contrast = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_WhiteBalance + case V4L2_CID_DO_WHITE_BALANCE: + { + if (ctrl->value != sensor->info_priv.whiteBalance) + { + if (sensor_set_whiteBalance(icd, qctrl,ctrl->value) != 0) + { + return -EINVAL; + } + sensor->info_priv.whiteBalance = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Mirror + case V4L2_CID_HFLIP: + { + if (ctrl->value != sensor->info_priv.mirror) + { + if (sensor_set_mirror(icd, qctrl,ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.mirror = ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Flip + case V4L2_CID_VFLIP: + { + if (ctrl->value != sensor->info_priv.flip) + { + if (sensor_set_flip(icd, qctrl,ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.flip = ctrl->value; + } + break; + } +#endif + default: + break; + } + + return 0; +} +static int sensor_g_ext_control(struct soc_camera_device *icd , struct v4l2_ext_control *ext_ctrl) +{ + const struct v4l2_queryctrl *qctrl; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + + qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + return -EINVAL; + } + + switch (ext_ctrl->id) + { + case V4L2_CID_SCENE: + { + ext_ctrl->value = sensor->info_priv.scene; + break; + } + case V4L2_CID_EFFECT: + { + ext_ctrl->value = sensor->info_priv.effect; + break; + } + case V4L2_CID_ZOOM_ABSOLUTE: + { + ext_ctrl->value = sensor->info_priv.digitalzoom; + break; + } + case V4L2_CID_ZOOM_RELATIVE: + { + return -EINVAL; + } + case V4L2_CID_FOCUS_ABSOLUTE: + { + ext_ctrl->value = sensor->info_priv.focus; + break; + } + case V4L2_CID_FOCUS_RELATIVE: + { + return -EINVAL; + } + case V4L2_CID_FLASH: + { + ext_ctrl->value = sensor->info_priv.flash; + break; + } + default : + break; + } + return 0; +} +static int sensor_s_ext_control(struct soc_camera_device *icd, struct v4l2_ext_control *ext_ctrl) +{ + const struct v4l2_queryctrl *qctrl; + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct sensor *sensor = to_sensor(client); + int val_offset; + + qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); + + if (!qctrl) + { + SENSOR_TR("\n %s ioctrl id = %d is invalidate \n", SENSOR_NAME_STRING(), ext_ctrl->id); + return -EINVAL; + } + + val_offset = 0; + switch (ext_ctrl->id) + { +#if CONFIG_SENSOR_Scene + case V4L2_CID_SCENE: + { + if (ext_ctrl->value != sensor->info_priv.scene) + { + if (sensor_set_scene(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.scene = ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_Effect + case V4L2_CID_EFFECT: + { + if (ext_ctrl->value != sensor->info_priv.effect) + { + if (sensor_set_effect(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.effect= ext_ctrl->value; + } + break; + } +#endif +#if CONFIG_SENSOR_DigitalZoom + case V4L2_CID_ZOOM_ABSOLUTE: + { + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; + + if (ext_ctrl->value != sensor->info_priv.digitalzoom) + { + val_offset = ext_ctrl->value -sensor->info_priv.digitalzoom; + + if (sensor_set_digitalzoom(icd, qctrl,&val_offset) != 0) + return -EINVAL; + sensor->info_priv.digitalzoom += val_offset; + + SENSOR_DG("%s digitalzoom is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.digitalzoom); + } + + break; + } + case V4L2_CID_ZOOM_RELATIVE: + { + if (ext_ctrl->value) + { + if (sensor_set_digitalzoom(icd, qctrl,&ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.digitalzoom += ext_ctrl->value; + + SENSOR_DG("%s digitalzoom is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.digitalzoom); + } + break; + } +#endif +#if CONFIG_SENSOR_Focus + case V4L2_CID_FOCUS_ABSOLUTE: + { + if ((ext_ctrl->value < qctrl->minimum) || (ext_ctrl->value > qctrl->maximum)) + return -EINVAL; + + if (ext_ctrl->value != sensor->info_priv.focus) + { + val_offset = ext_ctrl->value -sensor->info_priv.focus; + + sensor->info_priv.focus += val_offset; + } + + break; + } + case V4L2_CID_FOCUS_RELATIVE: + { + if (ext_ctrl->value) + { + sensor->info_priv.focus += ext_ctrl->value; + + SENSOR_DG("%s focus is %x\n", SENSOR_NAME_STRING(), sensor->info_priv.focus); + } + break; + } +#endif +#if CONFIG_SENSOR_Flash + case V4L2_CID_FLASH: + { + if (sensor_set_flash(icd, qctrl,ext_ctrl->value) != 0) + return -EINVAL; + sensor->info_priv.flash = ext_ctrl->value; + + SENSOR_DG("%s flash is %x\n",SENSOR_NAME_STRING(), sensor->info_priv.flash); + break; + } +#endif + default: + break; + } + + return 0; +} + +static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + int i, error_cnt=0, error_idx=-1; + + + for (i=0; icount; i++) { + if (sensor_g_ext_control(icd, &ext_ctrl->controls[i]) != 0) { + error_cnt++; + error_idx = i; + } + } + + if (error_cnt > 1) + error_idx = ext_ctrl->count; + + if (error_idx != -1) { + ext_ctrl->error_idx = error_idx; + return -EINVAL; + } else { + return 0; + } +} + +static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + int i, error_cnt=0, error_idx=-1; + + + for (i=0; icount; i++) { + if (sensor_s_ext_control(icd, &ext_ctrl->controls[i]) != 0) { + error_cnt++; + error_idx = i; + } + } + + if (error_cnt > 1) + error_idx = ext_ctrl->count; + + if (error_idx != -1) { + ext_ctrl->error_idx = error_idx; + return -EINVAL; + } else { + return 0; + } +} + +/* Interface active, can use i2c. If it fails, it can indeed mean, that + * this wasn't our capture interface, so, we wait for the right one */ +static int sensor_video_probe(struct soc_camera_device *icd, + struct i2c_client *client) +{ + char pid = 0; + int ret; + struct sensor *sensor = to_sensor(client); + + /* We must have a parent by now. And it cannot be a wrong one. + * So this entire test is completely redundant. */ + if (!icd->dev.parent || + to_soc_camera_host(icd->dev.parent)->nr != icd->iface) + return -ENODEV; + + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_video_probe_err; + } + msleep(10); + if (sensor_ioctrl(icd, Sensor_PowerDown, 1) < 0) { + ret = -ENODEV; + goto sensor_video_probe_err; + } + msleep(10); + if (sensor_ioctrl(icd, Sensor_PowerDown, 0) < 0) { + ret = -ENODEV; + goto sensor_video_probe_err; + } + msleep(10); + + /* check if it is an sensor sensor */ + ret = sensor_read(client, SENSOR_ID_REG, &pid); + if (ret != 0) { + SENSOR_TR("%s read chip id high byte failed\n",SENSOR_NAME_STRING()); + ret = -ENODEV; + goto sensor_video_probe_err; + } + + SENSOR_DG("\n %s pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + + if (pid == SENSOR_ID) { + sensor->model = SENSOR_V4L2_IDENT; + } else { + SENSOR_TR("error: %s mismatched pid = 0x%x\n", SENSOR_NAME_STRING(), pid); + ret = -ENODEV; + goto sensor_video_probe_err; + } + return 0; + +sensor_video_probe_err: + + return ret; +} + +static long sensor_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = client->dev.platform_data; + struct sensor *sensor = to_sensor(client); + int ret = 0; + + int i; + + + SENSOR_DG("\n%s..%s..cmd:%x \n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + switch (cmd) + { + case RK29_CAM_SUBDEV_DEACTIVATE: + { + sensor_deactivate(client); + break; + } + + case RK29_CAM_SUBDEV_IOREQUEST: + { + sensor->sensor_io_request = (struct rk29camera_platform_data*)arg; + if (sensor->sensor_io_request != NULL) { + sensor->sensor_gpio_res = NULL; + for (i=0; isensor_io_request->gpio_res[i].dev_name && + (strcmp(sensor->sensor_io_request->gpio_res[i].dev_name, dev_name(icd->pdev)) == 0)) { + sensor->sensor_gpio_res = (struct rk29camera_gpio_res*)&sensor->sensor_io_request->gpio_res[i]; + } + } + if (sensor->sensor_gpio_res == NULL) { + SENSOR_TR("%s %s obtain gpio resource failed when RK29_CAM_SUBDEV_IOREQUEST \n",SENSOR_NAME_STRING(),__FUNCTION__); + ret = -EINVAL; + goto sensor_ioctl_end; + } + } else { + SENSOR_TR("%s %s RK29_CAM_SUBDEV_IOREQUEST fail\n",SENSOR_NAME_STRING(),__FUNCTION__); + ret = -EINVAL; + goto sensor_ioctl_end; + } + /* ddl@rock-chips.com : if gpio_flash havn't been set in board-xxx.c, sensor driver must notify is not support flash control + for this project */ + #if CONFIG_SENSOR_Flash + if (sensor->sensor_gpio_res) { + if (sensor->sensor_gpio_res->gpio_flash == INVALID_GPIO) { + for (i = 0; i < icd->ops->num_controls; i++) { + if (V4L2_CID_FLASH == icd->ops->controls[i].id) { + memset((char*)&icd->ops->controls[i],0x00,sizeof(struct v4l2_queryctrl)); + } + } + sensor->info_priv.flash = 0xff; + SENSOR_DG("%s flash gpio is invalidate!\n",SENSOR_NAME_STRING()); + } + } + #endif + break; + } + default: + { + SENSOR_TR("%s %s cmd(0x%x) is unknown !\n",SENSOR_NAME_STRING(),__FUNCTION__,cmd); + break; + } + } +sensor_ioctl_end: + return ret; + +} +static int sensor_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + if (index >= ARRAY_SIZE(sensor_colour_fmts)) + return -EINVAL; + + *code = sensor_colour_fmts[index].code; + return 0; +} +static struct v4l2_subdev_core_ops sensor_subdev_core_ops = { + .init = sensor_init, + .g_ctrl = sensor_g_control, + .s_ctrl = sensor_s_control, + .g_ext_ctrls = sensor_g_ext_controls, + .s_ext_ctrls = sensor_s_ext_controls, + .g_chip_ident = sensor_g_chip_ident, + .ioctl = sensor_ioctl, +}; + +static struct v4l2_subdev_video_ops sensor_subdev_video_ops = { + .s_mbus_fmt = sensor_s_fmt, + .g_mbus_fmt = sensor_g_fmt, + .try_mbus_fmt = sensor_try_fmt, + .enum_mbus_fmt = sensor_enum_fmt, +}; + +static struct v4l2_subdev_ops sensor_subdev_ops = { + .core = &sensor_subdev_core_ops, + .video = &sensor_subdev_video_ops, +}; + +static int sensor_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct sensor *sensor; + struct soc_camera_device *icd = client->dev.platform_data; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct soc_camera_link *icl; + int ret; + + SENSOR_DG("\n%s..%s..%d..\n",__FUNCTION__,__FILE__,__LINE__); + if (!icd) { + dev_err(&client->dev, "%s: missing soc-camera data!\n",SENSOR_NAME_STRING()); + return -EINVAL; + } + + icl = to_soc_camera_link(icd); + if (!icl) { + dev_err(&client->dev, "%s driver needs platform data\n", SENSOR_NAME_STRING()); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { + dev_warn(&adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_I2C\n"); + return -EIO; + } + + sensor = kzalloc(sizeof(struct sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + v4l2_i2c_subdev_init(&sensor->subdev, client, &sensor_subdev_ops); + + /* Second stage probe - when a capture adapter is there */ + icd->ops = &sensor_ops; + + sensor->info_priv.fmt = sensor_colour_fmts[0]; + + #if CONFIG_SENSOR_I2C_NOSCHED + atomic_set(&sensor->tasklock_cnt,0); + #endif + + ret = sensor_video_probe(icd, client); + if (ret < 0) { + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + kfree(sensor); + sensor = NULL; + } + SENSOR_DG("\n%s..%s..%d ret = %x \n",__FUNCTION__,__FILE__,__LINE__,ret); + return ret; +} + +static int sensor_remove(struct i2c_client *client) +{ + struct sensor *sensor = to_sensor(client); + struct soc_camera_device *icd = client->dev.platform_data; + + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + client->driver = NULL; + kfree(sensor); + sensor = NULL; + return 0; +} + +static const struct i2c_device_id sensor_id[] = { + {SENSOR_NAME_STRING(), 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sensor_id); + +static struct i2c_driver sensor_i2c_driver = { + .driver = { + .name = SENSOR_NAME_STRING(), + }, + .probe = sensor_probe, + .remove = sensor_remove, + .id_table = sensor_id, +}; + +static int __init sensor_mod_init(void) +{ + return i2c_add_driver(&sensor_i2c_driver); +} + +static void __exit sensor_mod_exit(void) +{ + i2c_del_driver(&sensor_i2c_driver); +} + +device_initcall_sync(sensor_mod_init); +module_exit(sensor_mod_exit); + +MODULE_DESCRIPTION(SENSOR_NAME_STRING(Camera sensor driver)); +MODULE_AUTHOR("ddl "); +MODULE_LICENSE("GPL"); + + diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h index 8e69f2013d65..accadbddbc0e 100755 --- a/include/media/v4l2-chip-ident.h +++ b/include/media/v4l2-chip-ident.h @@ -338,21 +338,26 @@ enum { V4L2_IDENT_UPD64083 = 64083, - V4L2_IDENT_GT2005 = 64099, /* ddl@rock-chips.com : GT2005 support */ - V4L2_IDENT_GC0307 = 64100, /* ddl@rock-chips.com : GC0308 support */ - V4L2_IDENT_GC0308 = 64101, /* ddl@rock-chips.com : GC0308 support */ - V4L2_IDENT_GC0309 = 64102, /* ddl@rock-chips.com : GC0309 support */ - V4L2_IDENT_SIV120B = 64103, /* ddl@rock-chips.com : siv120b support */ + V4L2_IDENT_NT99250 = 64100, /* ddl@rock-chips.com : nt99250 support */ + V4L2_IDENT_SID130B = 64101, /* ddl@rock-chips.com : sid130B support */ - V4L2_IDENT_GC2015 = 64105, /* ddl@rock-chips.com : gc2015 support */ - V4L2_IDENT_HI253 = 64106, /* ddl@rock-chips.com : hi253 support */ - V4L2_IDENT_HI704 = 64107, /* ddl@rock-chips.com : hi704 support */ - V4L2_IDENT_NT99250 = 64108, /* ddl@rock-chips.com : nt99250 support */ - V4L2_IDENT_SID130B = 64109, /* ddl@rock-chips.com : sid130B support */ - V4L2_IDENT_SP0838 = 64110, /* ddl@rock-chips.com : SP0838 support */ - V4L2_IDENT_GC0329 = 64111, /* ddl@rock-chips.com : GC0329 support */ + V4L2_IDENT_GT2005 = 64110, /* ddl@rock-chips.com : GT2005 support */ + V4L2_IDENT_GC0307 = 64111, /* ddl@rock-chips.com : GC0308 support */ + V4L2_IDENT_GC0308 = 64112, /* ddl@rock-chips.com : GC0308 support */ + V4L2_IDENT_GC0309 = 64113, /* ddl@rock-chips.com : GC0309 support */ + V4L2_IDENT_GC2015 = 64114, /* ddl@rock-chips.com : gc2015 support */ + V4L2_IDENT_GC0329 = 64115, /* ddl@rock-chips.com : GC0329 support */ + + V4L2_IDENT_SP0838 = 64120, /* ddl@rock-chips.com : SP0838 support */ + V4L2_IDENT_SP2518 = 64121, /* ddl@rock-chips.com : SP2518 support */ + + V4L2_IDENT_HI253 = 64130, /* ddl@rock-chips.com : hi253 support */ + V4L2_IDENT_HI704 = 64131, /* ddl@rock-chips.com : hi704 support */ + + V4L2_IDENT_SIV120B = 64140, /* ddl@rock-chips.com : siv120b support */ + V4L2_IDENT_SIV121D= 64141, /* ddl@rock-chips.com : sid130B support */ + - V4L2_IDENT_SIV121D= 64112, /* ddl@rock-chips.com : sid130B support */ /* Don't just add new IDs at the end: KEEP THIS LIST ORDERED BY ID! */ }; From afaf51341ff50fd0a89ac2e1c37c4409e2679146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=99=B4?= Date: Tue, 14 Aug 2012 16:11:16 +0800 Subject: [PATCH 173/261] =?UTF-8?q?rk30:Compatib=20with=20wm8326=A1=A2tps6?= =?UTF-8?q?5910=20and=20discrete=20dcdc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arch/arm/mach-rk30/board-rk30-phonepad.c | 3 --- arch/arm/mach-rk30/board-rk30-sdk-tps65910.c | 14 +++++--------- drivers/regulator/rk30-pwm-regulator.c | 4 ++-- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/arch/arm/mach-rk30/board-rk30-phonepad.c b/arch/arm/mach-rk30/board-rk30-phonepad.c index 9ec49404edf8..c06b3936f0bc 100755 --- a/arch/arm/mach-rk30/board-rk30-phonepad.c +++ b/arch/arm/mach-rk30/board-rk30-phonepad.c @@ -1653,9 +1653,6 @@ static struct platform_device device_rfkill_rk = { #endif static struct platform_device *devices[] __initdata = { -#ifdef CONFIG_RK30_PWM_REGULATOR - &pwm_regulator_device[0], -#endif #ifdef CONFIG_BACKLIGHT_RK29_BL &rk29_device_backlight, #endif diff --git a/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c b/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c index d1fb1cfd80ed..d61ef3f69c36 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c +++ b/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c @@ -52,6 +52,7 @@ int tps65910_pre_init(struct tps65910 *tps65910){ printk(KERN_ERR "Unable to write TPS65910_DEVCTRL2 reg\n"); return err; } + #if 1 /* set PSKIP=0 */ val = tps65910_reg_read(tps65910, TPS65910_DCDCCTRL); @@ -238,6 +239,10 @@ int tps65910_post_init(struct tps65910 *tps65910) g_pmic_type = PMIC_TYPE_TPS65910; printk("%s:g_pmic_type=%d\n",__func__,g_pmic_type); + + #ifdef CONFIG_RK30_PWM_REGULATOR + platform_device_register(&pwm_regulator_device[0]); + #endif dcdc = regulator_get(NULL, "vio"); //vcc_io regulator_set_voltage(dcdc, 3000000, 3000000); @@ -315,15 +320,6 @@ int tps65910_post_init(struct tps65910 *tps65910) printk("%s set vmmc vcc28_cif=%dmV end\n", __func__, regulator_get_voltage(ldo)); regulator_put(ldo); udelay(100); - - #ifdef CONFIG_RK30_PWM_REGULATOR - dcdc = regulator_get(NULL, "vdd_core"); // vdd_log - regulator_set_voltage(dcdc, 1100000, 1100000); - regulator_enable(dcdc); - printk("%s set vdd_core=%dmV end\n", __func__, regulator_get_voltage(dcdc)); - regulator_put(dcdc); - udelay(100); - #endif printk("%s,line=%d END\n", __func__,__LINE__); diff --git a/drivers/regulator/rk30-pwm-regulator.c b/drivers/regulator/rk30-pwm-regulator.c index f046b4496c0c..8b914cd565cc 100755 --- a/drivers/regulator/rk30-pwm-regulator.c +++ b/drivers/regulator/rk30-pwm-regulator.c @@ -255,7 +255,7 @@ static int __devinit pwm_regulator_probe(struct platform_device *pdev) int id = pdev->id; int ret ; char gpio_name[20]; - + if (!pdata) return -ENODEV; @@ -451,7 +451,7 @@ static void __exit pwm_regulator_module_exit(void) } -subsys_initcall(pwm_regulator_module_init); +fs_initcall(pwm_regulator_module_init); module_exit(pwm_regulator_module_exit); From 20a1e646de8c586d463187db9f07d75c8a2e38b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=99=B4?= Date: Tue, 14 Aug 2012 16:34:41 +0800 Subject: [PATCH 174/261] rk30:sdk:support pwm set voltage --- arch/arm/mach-rk30/board-rk30-sdk.c | 55 +++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/arch/arm/mach-rk30/board-rk30-sdk.c b/arch/arm/mach-rk30/board-rk30-sdk.c index dc753d662cff..2cf324e4ea6d 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk.c +++ b/arch/arm/mach-rk30/board-rk30-sdk.c @@ -44,6 +44,7 @@ #include #include #include +#include #if defined(CONFIG_HDMI_RK30) #include "../../../drivers/video/rockchip/hdmi/rk_hdmi.h" #endif @@ -1401,6 +1402,60 @@ static struct platform_device rk30_device_adc_battery = { }; #endif +#if CONFIG_RK30_PWM_REGULATOR +const static int pwm_voltage_map[] = { + 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 1400000 +}; + +static struct regulator_consumer_supply pwm_dcdc1_consumers[] = { + { + .supply = "vdd_core", + } +}; + +struct regulator_init_data pwm_regulator_init_dcdc[1] = +{ + { + .constraints = { + .name = "PWM_DCDC1", + .min_uV = 600000, + .max_uV = 1800000, //0.6-1.8V + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(pwm_dcdc1_consumers), + .consumer_supplies = pwm_dcdc1_consumers, + }, +}; + +static struct pwm_platform_data pwm_regulator_info[1] = { + { + .pwm_id = 3, + .pwm_gpio = RK30_PIN0_PD7, + .pwm_iomux_name = GPIO0D7_PWM3_NAME, + .pwm_iomux_pwm = GPIO0D_PWM3, + .pwm_iomux_gpio = GPIO0D_GPIO0D6, + .pwm_voltage = 1100000, + .suspend_voltage = 1050000, + .min_uV = 1000000, + .max_uV = 1400000, + .coefficient = 455, //45.5% + .pwm_voltage_map = pwm_voltage_map, + .init_data = &pwm_regulator_init_dcdc[0], + }, +}; + +struct platform_device pwm_regulator_device[1] = { + { + .name = "pwm-voltage-regulator", + .id = 0, + .dev = { + .platform_data = &pwm_regulator_info[0], + } + }, +}; +#endif + #ifdef CONFIG_RK29_VMAC #define PHY_PWR_EN_GPIO RK30_PIN1_PD6 #include "board-rk30-sdk-vmac.c" From 54a19342c7ccab9ae4aab69f0d145c2076278908 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=8B=E7=A7=80=E6=9D=B0?= Date: Tue, 14 Aug 2012 17:04:01 +0800 Subject: [PATCH 175/261] phonepad: fix record can not work bug. --- sound/soc/codecs/rt3261.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/codecs/rt3261.c b/sound/soc/codecs/rt3261.c index 38c47f147e05..e8f1405fb8d8 100644 --- a/sound/soc/codecs/rt3261.c +++ b/sound/soc/codecs/rt3261.c @@ -631,6 +631,7 @@ static int rt3261_dmic_put(struct snd_kcontrol *kcontrol, } //bard 8-9 s +#if 0 static int rt3261_mic1_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -692,6 +693,7 @@ static int rt3261_mic2_put(struct snd_kcontrol *kcontrol, return 0; } +#endif //bard 8-9 e /* IN1/IN2 Input Type */ @@ -742,9 +744,11 @@ static const char *rt3261_dmic_mode[] = {"Disable", "DMIC1", "DMIC2"}; static const SOC_ENUM_SINGLE_DECL(rt3261_dmic_enum, 0, 0, rt3261_dmic_mode); //bard 8-9 s +#if 0 static const char *rt3261_mic_mode[] = {"off", "on",}; static const SOC_ENUM_SINGLE_DECL(rt3261_mic_enum, 0, 0, rt3261_mic_mode); +#endif //bard 8-9 e #ifdef RT3261_REG_RW @@ -884,6 +888,7 @@ static const struct snd_kcontrol_new rt3261_snd_controls[] = { }, #endif //bard 8-9 s +#if 0 SOC_SINGLE_TLV("Main Mic Capture Volume", RT3261_IN1_IN2, RT3261_BST_SFT1, 8, 0, bst_tlv), SOC_SINGLE_TLV("Headset Mic Capture Volume", RT3261_IN3_IN4, @@ -892,6 +897,7 @@ static const struct snd_kcontrol_new rt3261_snd_controls[] = { rt3261_mic1_get, rt3261_mic1_put), SOC_ENUM_EXT("Headset Mic Capture Switch", rt3261_mic_enum, rt3261_mic2_get, rt3261_mic2_put), +#endif //bard 8-9 e }; From 1fb22447a51c243733c024cef573643dd0f431e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Tue, 14 Aug 2012 17:29:10 +0800 Subject: [PATCH 176/261] rk30: cru: fix typo, PEIRPH -> PERIPH --- arch/arm/mach-rk30/clock_data.c | 8 ++++---- arch/arm/mach-rk30/include/mach/cru.h | 8 ++++---- arch/arm/mach-rk30/pm.c | 22 +++++++++++----------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/arch/arm/mach-rk30/clock_data.c b/arch/arm/mach-rk30/clock_data.c index 7579235ebabd..e28a2df3f528 100644 --- a/arch/arm/mach-rk30/clock_data.c +++ b/arch/arm/mach-rk30/clock_data.c @@ -1521,7 +1521,7 @@ static struct clk aclk_periph = { .name = "aclk_periph", .parent = &general_pll_clk, .mode = gate_mode, - .gate_idx = CLK_GATE_ACLK_PEIRPH, + .gate_idx = CLK_GATE_ACLK_PERIPH, .recalc = clksel_recalc_div, .set_rate = clksel_set_rate_freediv, .clksel_con = CRU_CLKSELS_CON(10), @@ -1529,13 +1529,13 @@ static struct clk aclk_periph = { CRU_SRC_SET(1,15), CRU_PARENTS_SET(aclk_periph_parents), }; -GATE_CLK(periph_src, aclk_periph, PEIRPH_SRC); +GATE_CLK(periph_src, aclk_periph, PERIPH_SRC); static struct clk pclk_periph = { .name = "pclk_periph", .parent = &aclk_periph, .mode = gate_mode, - .gate_idx = CLK_GATE_PCLK_PEIRPH, + .gate_idx = CLK_GATE_PCLK_PERIPH, .recalc = clksel_recalc_shift, .set_rate = clksel_set_rate_shift, .clksel_con = CRU_CLKSELS_CON(10), @@ -1546,7 +1546,7 @@ static struct clk hclk_periph = { .name = "hclk_periph", .parent = &aclk_periph, .mode = gate_mode, - .gate_idx = CLK_GATE_HCLK_PEIRPH, + .gate_idx = CLK_GATE_HCLK_PERIPH, .recalc = clksel_recalc_shift, .set_rate = clksel_set_rate_shift, .clksel_con = CRU_CLKSELS_CON(10), diff --git a/arch/arm/mach-rk30/include/mach/cru.h b/arch/arm/mach-rk30/include/mach/cru.h index c0e809c69036..113af41c2181 100755 --- a/arch/arm/mach-rk30/include/mach/cru.h +++ b/arch/arm/mach-rk30/include/mach/cru.h @@ -210,10 +210,10 @@ enum cru_clk_gate { CLK_GATE_UART3, CLK_GATE_FRAC_UART3, - CLK_GATE_PEIRPH_SRC = CLK_GATE_CLKID(2), - CLK_GATE_ACLK_PEIRPH, - CLK_GATE_HCLK_PEIRPH, - CLK_GATE_PCLK_PEIRPH, + CLK_GATE_PERIPH_SRC = CLK_GATE_CLKID(2), + CLK_GATE_ACLK_PERIPH, + CLK_GATE_HCLK_PERIPH, + CLK_GATE_PCLK_PERIPH, CLK_GATE_SMC, CLK_GATE_MAC, CLK_GATE_HSADC, diff --git a/arch/arm/mach-rk30/pm.c b/arch/arm/mach-rk30/pm.c index 464667b9e587..1463afca801b 100644 --- a/arch/arm/mach-rk30/pm.c +++ b/arch/arm/mach-rk30/pm.c @@ -42,13 +42,13 @@ void __sramfunc sram_printch(char byte) u32 clk_gate2, clk_gate4, clk_gate8; gate_save_soc_clk(0 - | (1 << CLK_GATE_ACLK_PEIRPH % 16) - | (1 << CLK_GATE_HCLK_PEIRPH % 16) - | (1 << CLK_GATE_PCLK_PEIRPH % 16) + | (1 << CLK_GATE_ACLK_PERIPH % 16) + | (1 << CLK_GATE_HCLK_PERIPH % 16) + | (1 << CLK_GATE_PCLK_PERIPH % 16) , clk_gate2, CRU_CLKGATES_CON(2), 0 - | (1 << ((CLK_GATE_ACLK_PEIRPH % 16) + 16)) - | (1 << ((CLK_GATE_HCLK_PEIRPH % 16) + 16)) - | (1 << ((CLK_GATE_PCLK_PEIRPH % 16) + 16))); + | (1 << ((CLK_GATE_ACLK_PERIPH % 16) + 16)) + | (1 << ((CLK_GATE_HCLK_PERIPH % 16) + 16)) + | (1 << ((CLK_GATE_PCLK_PERIPH % 16) + 16))); gate_save_soc_clk((1 << CLK_GATE_ACLK_CPU_PERI % 16) , clk_gate4, CRU_CLKGATES_CON(4), (1 << ((CLK_GATE_ACLK_CPU_PERI % 16) + 16))); @@ -375,8 +375,8 @@ static void __sramfunc rk30_sram_suspend(void) gate_save_soc_clk(0, clkgt_regs[1], CRU_CLKGATES_CON(1), 0xffff); if(clkgt_regs[8]&((1<<12)|(1<13))){ gate_save_soc_clk(0 - | (1 << CLK_GATE_PEIRPH_SRC % 16) - | (1 << CLK_GATE_PCLK_PEIRPH % 16) + | (1 << CLK_GATE_PERIPH_SRC % 16) + | (1 << CLK_GATE_PCLK_PERIPH % 16) , clkgt_regs[2], CRU_CLKGATES_CON(2), 0xffff); }else{ gate_save_soc_clk(0 @@ -489,9 +489,9 @@ static int rk30_pm_enter(suspend_state_t state) | (1 << CLK_GATE_DDR_GPLL % 16) , clkgt_regs[1], CRU_CLKGATES_CON(1), 0xffff); gate_save_soc_clk(0 - | (1 << CLK_GATE_PEIRPH_SRC % 16) - | (1 << CLK_GATE_PCLK_PEIRPH % 16) - | (1 << CLK_GATE_ACLK_PEIRPH % 16) + | (1 << CLK_GATE_PERIPH_SRC % 16) + | (1 << CLK_GATE_PCLK_PERIPH % 16) + | (1 << CLK_GATE_ACLK_PERIPH % 16) , clkgt_regs[2], CRU_CLKGATES_CON(2), 0xffff); gate_save_soc_clk(0, clkgt_regs[3], CRU_CLKGATES_CON(3), 0xff9f); gate_save_soc_clk(0 From 6bcf52d724d87e72aee68bccd2065310a47cc931 Mon Sep 17 00:00:00 2001 From: xxx Date: Mon, 13 Aug 2012 21:13:29 -0700 Subject: [PATCH 177/261] add video_state function which can reduce reset ddr rate when playing video --- arch/arm/mach-rk30/Makefile | 2 +- arch/arm/mach-rk30/clock_data.c | 15 ++- arch/arm/mach-rk30/cpufreq.c | 17 ++- arch/arm/mach-rk30/ddr.c | 2 +- arch/arm/mach-rk30/ddr_freq.c | 130 ++++++++++++++------- arch/arm/mach-rk30/dvfs.c | 29 ++++- arch/arm/mach-rk30/include/mach/ddr.h | 2 + arch/arm/mach-rk30/video_state.c | 161 ++++++++++++++++++++++++++ 8 files changed, 311 insertions(+), 47 deletions(-) mode change 100755 => 100644 arch/arm/mach-rk30/Makefile mode change 100755 => 100644 arch/arm/mach-rk30/cpufreq.c mode change 100755 => 100644 arch/arm/mach-rk30/ddr.c mode change 100755 => 100644 arch/arm/mach-rk30/ddr_freq.c create mode 100755 arch/arm/mach-rk30/video_state.c diff --git a/arch/arm/mach-rk30/Makefile b/arch/arm/mach-rk30/Makefile old mode 100755 new mode 100644 index 2167eef284c7..3777e6549650 --- a/arch/arm/mach-rk30/Makefile +++ b/arch/arm/mach-rk30/Makefile @@ -16,7 +16,7 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o -obj-$(CONFIG_CPU_FREQ) += cpufreq.o +obj-$(CONFIG_CPU_FREQ) += cpufreq.o video_state.o obj-$(CONFIG_DVFS) += dvfs.o obj-$(CONFIG_DDR_FREQ) += ddr_freq.o obj-$(CONFIG_RK30_I2C_INSRAM) += i2c_sram.o diff --git a/arch/arm/mach-rk30/clock_data.c b/arch/arm/mach-rk30/clock_data.c index e28a2df3f528..340b86028f3f 100644 --- a/arch/arm/mach-rk30/clock_data.c +++ b/arch/arm/mach-rk30/clock_data.c @@ -26,6 +26,7 @@ #include "clock.h" #include #include +#include #define MHZ (1000*1000) #define KHZ (1000) @@ -1115,12 +1116,24 @@ static int ddr_clk_set_rate(struct clk *c, unsigned long rate) return 0; } +static long ddr_clk_round_rate(struct clk *clk, unsigned long rate) +{ + return ddr_set_pll(rate/MHZ,0)*MHZ; +} +static unsigned long ddr_clk_recalc_rate(struct clk *clk) +{ + u32 shift = get_cru_bits(clk->clksel_con,clk->div_mask,clk->div_shift); + unsigned long rate = clk->parent->recalc(clk->parent)>> shift; + pr_debug("%s new clock rate is %lu (shift %u)\n", clk->name, rate, shift); + return rate; +} static struct clk *clk_ddr_parents[2] = {&ddr_pll_clk, &general_pll_clk}; static struct clk clk_ddr = { .name = "ddr", .parent = &ddr_pll_clk, - .recalc = clksel_recalc_shift, + .recalc = ddr_clk_recalc_rate, .set_rate = ddr_clk_set_rate, + .round_rate = ddr_clk_round_rate, .clksel_con = CRU_CLKSELS_CON(26), //CRU_DIV_SET(0x3,0,4), //CRU_SRC_SET(1,8), diff --git a/arch/arm/mach-rk30/cpufreq.c b/arch/arm/mach-rk30/cpufreq.c old mode 100755 new mode 100644 index 31b0f0f829c8..f4e51ba215d2 --- a/arch/arm/mach-rk30/cpufreq.c +++ b/arch/arm/mach-rk30/cpufreq.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #ifdef DEBUG #define FREQ_PRINTK_DBG(fmt, args...) pr_debug(fmt, ## args) #define FREQ_PRINTK_LOG(fmt, args...) pr_debug(fmt, ## args) @@ -68,6 +70,7 @@ static struct clk *cpu_gpll; static DEFINE_MUTEX(cpufreq_mutex); static struct clk *gpu_clk; +static struct clk *ddr_clk; #define GPU_MAX_RATE 350*1000*1000 static int cpufreq_scale_rate_for_dvfs(struct clk *clk, unsigned long rate, dvfs_set_rate_callback set_rate); @@ -220,11 +223,20 @@ static int rk30_verify_speed(struct cpufreq_policy *policy) return cpufreq_frequency_table_verify(policy, freq_table); } +uint32_t ddr_set_rate(uint32_t nMHz); + +int ddr_scale_rate_for_dvfs(struct clk *clk, unsigned long rate, dvfs_set_rate_callback set_rate) +{ + #if defined (CONFIG_DDR_FREQ) + ddr_set_rate(rate/(1000*1000)); + #endif + return 0; +} + static int rk30_cpu_init(struct cpufreq_policy *policy) { if (policy->cpu == 0) { int i; - struct clk *ddr_clk; gpu_clk = clk_get(NULL, "gpu"); if (!IS_ERR(gpu_clk)) @@ -233,8 +245,9 @@ static int rk30_cpu_init(struct cpufreq_policy *policy) ddr_clk = clk_get(NULL, "ddr"); if (!IS_ERR(ddr_clk)) { + dvfs_clk_register_set_rate_callback(ddr_clk, ddr_scale_rate_for_dvfs); clk_enable_dvfs(ddr_clk); - clk_set_rate(ddr_clk,clk_get_rate(ddr_clk)-1); + //clk_set_rate(ddr_clk,clk_get_rate(ddr_clk)-1); } cpu_clk = clk_get(NULL, "cpu"); diff --git a/arch/arm/mach-rk30/ddr.c b/arch/arm/mach-rk30/ddr.c old mode 100755 new mode 100644 index 970cbec38934..ad62e0dcc981 --- a/arch/arm/mach-rk30/ddr.c +++ b/arch/arm/mach-rk30/ddr.c @@ -2978,7 +2978,6 @@ uint32_t __sramfunc ddr_change_freq(uint32_t nMHz) DDR_RESTORE_SP(save_sp); local_fiq_enable(); local_irq_restore(flags); - clk_set_rate(clk_get(NULL, "ddr_pll"), 0); return ret; } @@ -3221,6 +3220,7 @@ int ddr_init(uint32_t dram_speed_bin, uint32_t freq) ddr_adjust_config(mem_type); value=ddr_change_freq(freq); + clk_set_rate(clk_get(NULL, "ddr_pll"), 0); ddr_print("init success!!! freq=%dMHz\n", value); for(value=0;value<4;value++) diff --git a/arch/arm/mach-rk30/ddr_freq.c b/arch/arm/mach-rk30/ddr_freq.c old mode 100755 new mode 100644 index c0a40c12790c..c81af12621eb --- a/arch/arm/mach-rk30/ddr_freq.c +++ b/arch/arm/mach-rk30/ddr_freq.c @@ -4,82 +4,132 @@ #include #include #include +#include #define ddr_print(x...) printk( "DDR DEBUG: " x ) -struct ddr{ - int suspend; - struct early_suspend early_suspend; +struct ddr { + int suspend; + struct early_suspend early_suspend; + struct clk *ddr_pll; }; -struct ddr *ddr = NULL; + +static void ddr_early_suspend(struct early_suspend *h); +static void ddr_late_resume(struct early_suspend *h); + +static struct ddr ddr = { + .early_suspend = { + .suspend = ddr_early_suspend, + .resume = ddr_late_resume, + .level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 50, + }, +}; + +static volatile bool __sramdata cpu1_pause; +static inline bool is_cpu1_paused(void) { smp_rmb(); return cpu1_pause; } +static inline void set_cpu1_pause(bool pause) { cpu1_pause = pause; smp_wmb(); } +#define MAX_TIMEOUT (16000000UL << 6) //>0.64s + +static void __ddr_change_freq(void *info) +{ + uint32_t *value = info; + u32 timeout = MAX_TIMEOUT; + + while (!is_cpu1_paused() && --timeout); + if (timeout == 0) + return; + + *value = ddr_change_freq(*value); + + set_cpu1_pause(false); +} + +/* Do not use stack, safe on SMP */ +static void __sramfunc pause_cpu1(void *info) +{ + u32 timeout = MAX_TIMEOUT; + unsigned long flags; + local_irq_save(flags); + + set_cpu1_pause(true); + while (is_cpu1_paused() && --timeout); + + local_irq_restore(flags); +} + +static uint32_t _ddr_change_freq(uint32_t nMHz) +{ + int this_cpu = get_cpu(); + + set_cpu1_pause(false); + if (this_cpu == 0) { + if (smp_call_function_single(1, (smp_call_func_t)pause_cpu1, NULL, 0) == 0) { + u32 timeout = MAX_TIMEOUT; + while (!is_cpu1_paused() && --timeout); + if (timeout == 0) + goto out; + } + + nMHz = ddr_change_freq(nMHz); + + set_cpu1_pause(false); + } else { + smp_call_function_single(0, __ddr_change_freq, &nMHz, 0); + + pause_cpu1(NULL); + } + + clk_set_rate(ddr.ddr_pll, 0); +out: + put_cpu(); + + return nMHz; +} + +uint32_t ddr_set_rate(uint32_t nMHz) +{ + _ddr_change_freq(nMHz); + return 0; +} + #ifdef CONFIG_HAS_EARLYSUSPEND static void ddr_early_suspend(struct early_suspend *h) { - uint32_t value; - bool cpu1_online; //Enable auto self refresh 0x01*32 DDR clk cycle ddr_set_auto_self_refresh(true); - - cpu1_online = cpu_online(1); - if(cpu1_online) - cpu_down(1); - value=ddr_change_freq(100); + value = _ddr_change_freq(100); - if(cpu1_online) - cpu_up(1); ddr_print("init success!!! freq=%dMHz\n", value); return; } -static void ddr_early_resume(struct early_suspend *h) +static void ddr_late_resume(struct early_suspend *h) { - uint32_t value; - bool cpu1_online; //Disable auto self refresh ddr_set_auto_self_refresh(false); - cpu1_online = cpu_online(1); - if(cpu1_online) - cpu_down(1); + value = _ddr_change_freq(DDR_FREQ); - value=ddr_change_freq(DDR_FREQ); - - if(cpu1_online) - cpu_up(1); ddr_print("init success!!! freq=%dMHz\n", value); return; } -#endif - static int rk30_ddr_late_init (void) { - - ddr = kmalloc(sizeof(struct ddr), GFP_KERNEL); - if(!ddr) - { - ddr_print("%s: kmalloc fail!\n",__FUNCTION__); - return -ENOMEM; - } - memset(ddr, 0, sizeof(struct ddr)); -#ifdef CONFIG_HAS_EARLYSUSPEND - ddr->early_suspend.suspend = ddr_early_suspend; - ddr->early_suspend.resume = ddr_early_resume; - ddr->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 50; - register_early_suspend(&ddr->early_suspend); -#endif + ddr.ddr_pll = clk_get(NULL, "ddr_pll"); + register_early_suspend(&ddr.early_suspend); return 0; } late_initcall(rk30_ddr_late_init); - +#endif #ifdef CONFIG_DDR_TEST #include diff --git a/arch/arm/mach-rk30/dvfs.c b/arch/arm/mach-rk30/dvfs.c index d9c9fa9267df..f1fc2eafe714 100644 --- a/arch/arm/mach-rk30/dvfs.c +++ b/arch/arm/mach-rk30/dvfs.c @@ -33,6 +33,10 @@ #else #define DVFS_DBG(fmt, args...) printk(KERN_DEBUG "DVFS DBG:\t"fmt, ##args) #endif + +#define DVFS_SET_VOLT_FAILURE 1 +#define DVFS_SET_VOLT_SUCCESS 0 + #define DVFS_ERR(fmt, args...) printk(KERN_ERR "DVFS ERR:\t"fmt, ##args) #define DVFS_LOG(fmt, args...) printk(KERN_DEBUG "DVFS LOG:\t"fmt, ##args) @@ -394,6 +398,21 @@ int clk_enable_dvfs(struct clk *clk) } #endif dvfs_vd_get_newvolt_byclk(dvfs_clk); + if(dvfs_clk->vd->cur_voltset_volt) + { + int ret; + mutex_lock(&rk_dvfs_mutex); + ret = dvfs_regulator_set_voltage_readback(dvfs_clk->vd->regulator, dvfs_clk->set_volt, dvfs_clk->set_volt); + if (ret < 0) { + dvfs_clk->vd->volt_set_flag = DVFS_SET_VOLT_FAILURE; + dvfs_clk->enable_dvfs = 0; + DVFS_ERR("dvfs enable clk %s,set volt error \n", dvfs_clk->name); + mutex_unlock(&rk_dvfs_mutex); + return -1; + } + dvfs_clk->vd->volt_set_flag = DVFS_SET_VOLT_SUCCESS; + mutex_unlock(&rk_dvfs_mutex); + } dvfs_clk->enable_dvfs++; } else { DVFS_ERR("dvfs already enable clk enable = %d!\n", dvfs_clk->enable_dvfs); @@ -694,8 +713,7 @@ static int dvfs_set_depend_post(struct clk_node *dvfs_clk, unsigned long rate_ol return 0; } #endif -#define DVFS_SET_VOLT_FAILURE 1 -#define DVFS_SET_VOLT_SUCCESS 0 + #define ARM_HIGHER_LOGIC (150 * 1000) #define LOGIC_HIGHER_ARM (100 * 1000) @@ -1019,6 +1037,8 @@ int dvfs_target_cpu(struct clk *clk, unsigned long rate_hz) /* need round rate */ rate_old = clk_get_rate(clk); rate_new = clk_round_rate_nolock(clk, rate_hz); + if(rate_new==rate_old) + return 0; DVFS_DBG("dvfs(%s) round rate (%lu)(rount %lu) old (%lu)\n", dvfs_clk->name, rate_hz, rate_new, rate_old); @@ -1145,6 +1165,8 @@ int dvfs_target_core(struct clk *clk, unsigned long rate_hz) /* need round rate */ rate_old = clk_get_rate(clk); rate_new = clk_round_rate_nolock(clk, rate_hz); + if(rate_new==rate_old) + return 0; DVFS_DBG("dvfs(%s) round rate (%lu)(rount %lu) old (%lu)\n", dvfs_clk->name, rate_hz, rate_new, rate_old); @@ -1270,18 +1292,21 @@ static struct cpufreq_frequency_table dep_cpu2core_table[] = { static struct vd_node vd_cpu = { .name = "vd_cpu", .regulator_name = "vdd_cpu", + .volt_set_flag =DVFS_SET_VOLT_FAILURE, .vd_dvfs_target = dvfs_target_cpu, }; static struct vd_node vd_core = { .name = "vd_core", .regulator_name = "vdd_core", + .volt_set_flag =DVFS_SET_VOLT_FAILURE, .vd_dvfs_target = dvfs_target_core, }; static struct vd_node vd_rtc = { .name = "vd_rtc", .regulator_name = "vdd_rtc", + .volt_set_flag =DVFS_SET_VOLT_FAILURE, .vd_dvfs_target = NULL, }; diff --git a/arch/arm/mach-rk30/include/mach/ddr.h b/arch/arm/mach-rk30/include/mach/ddr.h index b4c8aef5873b..fd733fc54952 100755 --- a/arch/arm/mach-rk30/include/mach/ddr.h +++ b/arch/arm/mach-rk30/include/mach/ddr.h @@ -149,5 +149,7 @@ void __sramfunc ddr_resume(void); uint32_t __sramfunc ddr_change_freq(uint32_t nMHz); int ddr_init(uint32_t dram_type, uint32_t freq); void ddr_set_auto_self_refresh(bool en); +uint32_t __sramlocalfunc ddr_set_pll(uint32_t nMHz, uint32_t set); + #endif diff --git a/arch/arm/mach-rk30/video_state.c b/arch/arm/mach-rk30/video_state.c new file mode 100755 index 000000000000..9e0589bcc73d --- /dev/null +++ b/arch/arm/mach-rk30/video_state.c @@ -0,0 +1,161 @@ +/* arch/arm/mach-rk30/video_state.c + * + * Copyright (C) 2012 ROCKCHIP, Inc. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef CONFIG_DDR_SDRAM_FREQ +#define DDR_FREQ (CONFIG_DDR_SDRAM_FREQ) +#else +#define DDR_FREQ 400 +#endif + + +int rk_video_state=0; +static struct clk * ddr_clk; + + +#define VIDEO_STATE_NAME "video_state" +#define BUFFER_SIZE 16 + +MODULE_AUTHOR("Mike Lockwood "); +MODULE_DESCRIPTION("Key chord input driver"); +MODULE_SUPPORTED_DEVICE("video_state"); +MODULE_LICENSE("GPL"); + +/* + * video_state_read is used to read video_state events from the driver + */ +static ssize_t video_state_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) +{ + return count; +} + +/* + * video_state_write is used to configure the driver + */ +static ssize_t video_state_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + char *parameters= 0; + int vedeo_state; + int set_rate=0; + int set_rate_old=0; + + if(DDR_FREQ<=333) + return count; + //if (count < sizeof(struct input_keychord)) + // return -EINVAL; + parameters = kzalloc(count, GFP_KERNEL); + if (!parameters) + return -ENOMEM; + + /* read list of keychords from userspace */ + if (copy_from_user(parameters, buffer, count)) { + kfree(parameters); + return -EFAULT; + } + sscanf(parameters, "%d", &vedeo_state); + + //printk("video_state %d\n",vedeo_state); + switch(vedeo_state) + { + case 0: + rk_video_state=0; + set_rate=DDR_FREQ; + break; + case 1: + rk_video_state=1; + set_rate=300; + break; + default: + rk_video_state=0; + return -EFAULT; + } + set_rate_old=clk_get_rate(ddr_clk); + set_rate=clk_round_rate(ddr_clk,set_rate*1000*1000); + if(set_rate_old!=set_rate) + { + clk_set_rate(ddr_clk,set_rate); + //printk("ddr rate=%d\n",set_rate/(1000*1000)); + } + kfree(parameters); + return count; +} + +static unsigned int video_state_poll(struct file *file, poll_table *wait) +{ + return 0; +} + +static int video_state_open(struct inode *inode, struct file *file) +{ + + + return 0; +} + +static int video_state_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static const struct file_operations video_state_fops = { + .owner = THIS_MODULE, + .open = video_state_open, + .release = video_state_release, + .read = video_state_read, + .write = video_state_write, + .poll = video_state_poll, +}; + +static struct miscdevice video_state = { + .fops = &video_state_fops, + .name = VIDEO_STATE_NAME, + .minor = MISC_DYNAMIC_MINOR, +}; + + +static int __init video_state_init(void) +{ + ddr_clk=clk_get(NULL,"ddr"); + if(IS_ERR(ddr_clk)) + return -1; + + + return misc_register(&video_state); +} + +static void __exit video_state_exit(void) +{ + misc_deregister(&video_state); +} + +module_init(video_state_init); +module_exit(video_state_exit); + + + From ec06a08e6fcf2a17bb22de68c172b3db3bd87c17 Mon Sep 17 00:00:00 2001 From: hxy Date: Tue, 14 Aug 2012 15:49:04 +0800 Subject: [PATCH 178/261] update rk3066b(rk31) sdk board according hw sch again --- arch/arm/mach-rk30/Makefile | 2 +- arch/arm/mach-rk30/board-rk3066b-sdk-rfkill.c | 449 ------------------ 2 files changed, 1 insertion(+), 450 deletions(-) delete mode 100644 arch/arm/mach-rk30/board-rk3066b-sdk-rfkill.c diff --git a/arch/arm/mach-rk30/Makefile b/arch/arm/mach-rk30/Makefile index 36026827d73d..2d7b649a3627 100755 --- a/arch/arm/mach-rk30/Makefile +++ b/arch/arm/mach-rk30/Makefile @@ -30,4 +30,4 @@ obj-$(CONFIG_MACH_RK30_DS1001B) += board-rk30-ds1001b.o board-rk30-ds1001b-key.o obj-$(CONFIG_MACH_RK30_PHONE_A22) += board-rk30-phone-a22.o board-rk30-phone-a22-key.o obj-$(CONFIG_MACH_RK31_FPGA) += board-rk31-fpga.o -obj-$(CONFIG_MACH_RK3066B_SDK) += board-rk3066b-sdk.o board-rk3066b-sdk-key.o board-rk3066b-sdk-rfkill.o +obj-$(CONFIG_MACH_RK3066B_SDK) += board-rk3066b-sdk.o board-rk3066b-sdk-key.o diff --git a/arch/arm/mach-rk30/board-rk3066b-sdk-rfkill.c b/arch/arm/mach-rk30/board-rk3066b-sdk-rfkill.c deleted file mode 100644 index ccb50e49d526..000000000000 --- a/arch/arm/mach-rk30/board-rk3066b-sdk-rfkill.c +++ /dev/null @@ -1,449 +0,0 @@ -/* - * Copyright (C) 2010 ROCKCHIP, Inc. - * Author: roger_chen - * - * This program is the bluetooth device bcm4329's driver, - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if 0 -#define DBG(x...) printk(KERN_INFO "[BT_RFKILL]: "x) -#else -#define DBG(x...) -#endif - -#define LOG(x...) printk(KERN_INFO "[BT_RFKILL]: "x) - -#ifdef CONFIG_BCM4329 -#define WIFI_BT_POWER_TOGGLE 1 -#else -#define WIFI_BT_POWER_TOGGLE 0 -#endif - -#define BT_WAKE_LOCK_TIMEOUT 10 //s - -#define BT_AUTO_SLEEP_TIMEOUT 3 - -/* - * IO Configuration for RK29 - */ -#ifdef CONFIG_ARCH_RK29 - -#define BT_WAKE_HOST_SUPPORT 0 - -/* IO configuration */ -// BT power pin -#define BT_GPIO_POWER RK29_PIN5_PD6 -#define IOMUX_BT_GPIO_POWER() rk29_mux_api_set(GPIO5D6_SDMMC1PWREN_NAME, GPIO5H_GPIO5D6); - -// BT reset pin -#define BT_GPIO_RESET RK29_PIN6_PC4 -#define IOMUX_BT_GPIO_RESET() - -// BT wakeup pin -#define BT_GPIO_WAKE_UP RK29_PIN6_PC5 -#define IOMUX_BT_GPIO_WAKE_UP() - -// BT wakeup host pin -#define BT_GPIO_WAKE_UP_HOST -#define IOMUX_BT_GPIO_WAKE_UP_HOST() - -//bt cts paired to uart rts -#define UART_RTS RK29_PIN2_PA7 -#define IOMUX_UART_RTS_GPIO() rk29_mux_api_set(GPIO2A7_UART2RTSN_NAME, GPIO2L_GPIO2A7) -#define IOMUX_UART_RTS() rk29_mux_api_set(GPIO2A7_UART2RTSN_NAME, GPIO2L_UART2_RTS_N) - -/* - * IO Configuration for RK30 - */ -#elif defined (CONFIG_ARCH_RK31) - -#define BT_WAKE_HOST_SUPPORT 1 - -/* IO configuration */ -// BT power pin -#define BT_GPIO_POWER RK30_PIN3_PC6 -#define IOMUX_BT_GPIO_POWER() rk29_mux_api_set(GPIO3C6_SDMMC1DETECTN_RMIIRXERR_NAME, GPIO3C_GPIO3C6); - -// BT reset pin -#define BT_GPIO_RESET RK30_PIN3_PD0 -#define IOMUX_BT_GPIO_RESET() rk29_mux_api_set(GPIO3D0_SDMMC1PWREN_MIIMD_NAME, GPIO3D_GPIO3D0); - -// BT wakeup pin -#define BT_GPIO_WAKE_UP RK30_PIN3_PC5 -#define IOMUX_BT_GPIO_WAKE_UP() rk29_mux_api_set(GPIO3C5_SDMMC1CLKOUT_RMIICLKOUT_RMIICLKIN_NAME, GPIO3C_GPIO3C5); - -// BT wakeup host pin -#define BT_GPIO_WAKE_UP_HOST RK30_PIN0_PA5 -#define BT_IRQ_WAKE_UP_HOST gpio_to_irq(BT_GPIO_WAKE_UP_HOST) -#define IOMUX_BT_GPIO_WAKE_UP_HOST() - -//bt cts paired to uart rts -#define UART_RTS RK30_PIN1_PA3 -#define IOMUX_UART_RTS_GPIO() rk29_mux_api_set(GPIO1A3_UART0RTSN_NAME, GPIO1A_GPIO1A3) -#define IOMUX_UART_RTS() rk29_mux_api_set(GPIO1A3_UART0RTSN_NAME, GPIO1A_UART0RTSN) - -#endif - -struct bt_ctrl -{ - struct rfkill *bt_rfk; -#if BT_WAKE_HOST_SUPPORT - struct timer_list tl; - bool b_HostWake; - struct wake_lock bt_wakelock; -#endif -}; - -static const char bt_name[] = -#if defined(CONFIG_RKWIFI) - #if defined(CONFIG_RKWIFI_26M) - "rk903_26M" - #else - "rk903" - #endif -#elif defined(CONFIG_BCM4329) - "bcm4329" -#elif defined(CONFIG_MV8787) - "mv8787" -#else - "bt_default" -#endif -; - -#if WIFI_BT_POWER_TOGGLE -extern int rk29sdk_bt_power_state; -extern int rk29sdk_wifi_power_state; -#endif - -struct bt_ctrl gBtCtrl; -struct timer_list bt_sleep_tl; - -void bcm4325_sleep(unsigned long bSleep); - -#if BT_WAKE_HOST_SUPPORT -void resetBtHostSleepTimer(void) -{ - mod_timer(&(gBtCtrl.tl),jiffies + BT_WAKE_LOCK_TIMEOUT*HZ);//再重新设置超时值。 -} - -void btWakeupHostLock(void) -{ - if(gBtCtrl.b_HostWake == false){ - DBG("** Lock **\n"); - wake_lock(&(gBtCtrl.bt_wakelock)); - gBtCtrl.b_HostWake = true; - } -} - -void btWakeupHostUnlock(void) -{ - if(gBtCtrl.b_HostWake == true){ - DBG("** UnLock **\n"); - wake_unlock(&(gBtCtrl.bt_wakelock)); //让系统睡眠 - gBtCtrl.b_HostWake = false; - } -} - -static void timer_hostSleep(unsigned long arg) -{ - DBG("b_HostWake=%d\n", gBtCtrl.b_HostWake); - btWakeupHostUnlock(); -} - -#ifdef CONFIG_PM -static irqreturn_t bcm4329_wake_host_irq(int irq, void *dev) -{ - DBG("%s\n",__FUNCTION__); - - btWakeupHostLock(); - resetBtHostSleepTimer(); - return IRQ_HANDLED; -} - -static void rfkill_do_wakeup(struct work_struct *work) -{ - // disable bt wakeup host - DBG("** free irq\n"); - free_irq(BT_IRQ_WAKE_UP_HOST, NULL); - - DBG("Enable UART_RTS\n"); - gpio_set_value(UART_RTS, GPIO_LOW); - IOMUX_UART_RTS(); -} - -static DECLARE_DELAYED_WORK(wakeup_work, rfkill_do_wakeup); - -static int bcm4329_rfkill_suspend(struct platform_device *pdev, pm_message_t state) -{ - DBG("%s\n",__FUNCTION__); - - cancel_delayed_work(&wakeup_work); - -#ifdef CONFIG_BT_AUTOSLEEP - bcm4325_sleep(1); -#endif - - DBG("Disable UART_RTS\n"); - //To prevent uart to receive bt data when suspended - IOMUX_UART_RTS_GPIO(); - gpio_request(UART_RTS, "uart_rts"); - gpio_set_value(UART_RTS, GPIO_HIGH); - - // enable bt wakeup host - DBG("Request irq for bt wakeup host\n"); - if (0 == request_irq(BT_IRQ_WAKE_UP_HOST, - bcm4329_wake_host_irq, - IRQF_TRIGGER_FALLING, - "bt_wake", - NULL)) - enable_irq_wake(BT_IRQ_WAKE_UP_HOST); - else - LOG("Failed to request BT_WAKE_UP_HOST irq\n"); - -#ifdef CONFIG_RFKILL_RESET - extern void rfkill_set_block(struct rfkill *rfkill, bool blocked); - rfkill_set_block(gBtCtrl.bt_rfk, true); -#endif - - return 0; -} - -static int bcm4329_rfkill_resume(struct platform_device *pdev) -{ - DBG("%s\n",__FUNCTION__); - - // 系统退出二级睡眠后需要拉低RTS,从而才允许BT发数据过来 - // 但是目前发现在resume函数中直接拉低RTS会导致BT数据丢失 - // 所以延迟1s后再拉低RTS - // 系统退出二级睡眠时释放掉BT_IRQ_WAKE_UP_HOST,在睡眠时候再 - // 次申请,目前发现中断回调函数比resume更晚执行,如果resume - // 时直接free掉IRQ,会导致中断回调函数不会被执行, - DBG("delay 1s\n"); - schedule_delayed_work(&wakeup_work, HZ); - - return 0; -} -#else -#define bcm4329_rfkill_suspend NULL -#define bcm4329_rfkill_resume NULL -#endif - -#else -#ifdef CONFIG_PM -static int bcm4329_rfkill_suspend(struct platform_device *pdev, pm_message_t state) -{ -#ifdef CONFIG_BT_AUTOSLEEP - bcm4325_sleep(1); -#endif - return 0; -} -#else -#define bcm4329_rfkill_suspend NULL -#endif -#define bcm4329_rfkill_resume NULL -#endif - -void bcm4325_sleep(unsigned long bSleep) -{ - DBG("*** bt sleep: %d ***\n", bSleep); -#ifdef CONFIG_BT_AUTOSLEEP - del_timer(&bt_sleep_tl);// cmy: 确保在唤醒BT时,不会因触发bt_sleep_tl而马上睡眠 -#endif - - IOMUX_BT_GPIO_WAKE_UP(); - gpio_set_value(BT_GPIO_WAKE_UP, bSleep?GPIO_LOW:GPIO_HIGH); - -#ifdef CONFIG_BT_AUTOSLEEP - if(!bSleep) - mod_timer(&bt_sleep_tl, jiffies + BT_AUTO_SLEEP_TIMEOUT*HZ);//再重新设置超时值。 -#endif -} - -static int bcm4329_set_block(void *data, bool blocked) -{ - DBG("set blocked :%d\n", blocked); - - IOMUX_BT_GPIO_POWER(); - IOMUX_BT_GPIO_RESET(); - - if (false == blocked) { - gpio_set_value(BT_GPIO_POWER, GPIO_HIGH); /* bt power on */ - mdelay(20); - - gpio_set_value(BT_GPIO_RESET, GPIO_LOW); - mdelay(20); - gpio_set_value(BT_GPIO_RESET, GPIO_HIGH); /* bt reset deactive*/ - - mdelay(20); - bcm4325_sleep(0); // ensure bt is wakeup - - pr_info("bt turn on power\n"); - } else { -#if WIFI_BT_POWER_TOGGLE - if (!rk29sdk_wifi_power_state) { -#endif - gpio_set_value(BT_GPIO_POWER, GPIO_LOW); /* bt power off */ - mdelay(20); - pr_info("bt shut off power\n"); -#if WIFI_BT_POWER_TOGGLE - }else { - pr_info("bt shouldn't shut off power, wifi is using it!\n"); - } -#endif - - gpio_set_value(BT_GPIO_RESET, GPIO_LOW); /* bt reset active*/ - mdelay(20); - } - -#if WIFI_BT_POWER_TOGGLE - rk29sdk_bt_power_state = !blocked; -#endif - return 0; -} - -static const struct rfkill_ops bcm4329_rfk_ops = { - .set_block = bcm4329_set_block, -}; - -static int __devinit bcm4329_rfkill_probe(struct platform_device *pdev) -{ - int rc = 0; - bool default_state = true; - - DBG("Enter %s\n",__FUNCTION__); - - /* default to bluetooth off */ - bcm4329_set_block(NULL, default_state); /* blocked -> bt off */ - - gBtCtrl.bt_rfk = rfkill_alloc(bt_name, - NULL, - RFKILL_TYPE_BLUETOOTH, - &bcm4329_rfk_ops, - NULL); - - if (!gBtCtrl.bt_rfk) - { - LOG("fail to rfkill_allocate\n"); - return -ENOMEM; - } - - rfkill_set_states(gBtCtrl.bt_rfk, default_state, false); - - rc = rfkill_register(gBtCtrl.bt_rfk); - if (rc) - { - LOG("failed to rfkill_register,rc=0x%x\n",rc); - rfkill_destroy(gBtCtrl.bt_rfk); - } - - gpio_request(BT_GPIO_POWER, NULL); - gpio_request(BT_GPIO_RESET, NULL); - gpio_request(BT_GPIO_WAKE_UP, NULL); - -#ifdef CONFIG_BT_AUTOSLEEP - init_timer(&bt_sleep_tl); - bt_sleep_tl.expires = 0; - bt_sleep_tl.function = bcm4325_sleep; - bt_sleep_tl.data = 1; - add_timer(&bt_sleep_tl); -#endif - -#if BT_WAKE_HOST_SUPPORT - init_timer(&(gBtCtrl.tl)); - gBtCtrl.tl.expires = 0; - gBtCtrl.tl.function = timer_hostSleep; - add_timer(&(gBtCtrl.tl)); - gBtCtrl.b_HostWake = false; - - wake_lock_init(&(gBtCtrl.bt_wakelock), WAKE_LOCK_SUSPEND, "bt_wake"); - - rc = gpio_request(BT_GPIO_WAKE_UP_HOST, "bt_wake"); - if (rc) { - LOG("Failed to request BT_WAKE_UP_HOST\n"); - } - - IOMUX_BT_GPIO_WAKE_UP_HOST(); - gpio_pull_updown(BT_GPIO_WAKE_UP_HOST,GPIOPullUp); - #endif - - LOG("bcm4329 module has been initialized,rc=0x%x\n",rc); - - return rc; -} - - -static int __devexit bcm4329_rfkill_remove(struct platform_device *pdev) -{ - if (gBtCtrl.bt_rfk) - rfkill_unregister(gBtCtrl.bt_rfk); - gBtCtrl.bt_rfk = NULL; -#if BT_WAKE_HOST_SUPPORT - del_timer(&(gBtCtrl.tl));//删掉定时器 - btWakeupHostUnlock(); - wake_lock_destroy(&(gBtCtrl.bt_wakelock)); -#endif -#ifdef CONFIG_BT_AUTOSLEEP - del_timer(&bt_sleep_tl); -#endif - - platform_set_drvdata(pdev, NULL); - - DBG("Enter %s\n",__FUNCTION__); - return 0; -} - -static struct platform_driver bcm4329_rfkill_driver = { - .probe = bcm4329_rfkill_probe, - .remove = __devexit_p(bcm4329_rfkill_remove), - .driver = { - .name = "rk29sdk_rfkill", - .owner = THIS_MODULE, - }, - .suspend = bcm4329_rfkill_suspend, - .resume = bcm4329_rfkill_resume, -}; - -/* - * Module initialization - */ -static int __init bcm4329_mod_init(void) -{ - int ret; - DBG("Enter %s\n",__FUNCTION__); - ret = platform_driver_register(&bcm4329_rfkill_driver); - LOG("ret=0x%x\n", ret); - return ret; -} - -static void __exit bcm4329_mod_exit(void) -{ - platform_driver_unregister(&bcm4329_rfkill_driver); -} - -module_init(bcm4329_mod_init); -module_exit(bcm4329_mod_exit); -MODULE_DESCRIPTION("bcm4329 Bluetooth driver"); -MODULE_AUTHOR("roger_chen cz@rock-chips.com, cmy@rock-chips.com"); -MODULE_LICENSE("GPL"); - From 23bf6545a1e9a05c7a5a22d4c5c4b5eaf11bf89d Mon Sep 17 00:00:00 2001 From: ddl Date: Tue, 14 Aug 2012 18:13:06 +0800 Subject: [PATCH 179/261] camera rk31: camera iomux for rk31 --- drivers/media/video/rk30_camera.c | 569 ++++++++++++++++++++++++++++++ 1 file changed, 569 insertions(+) diff --git a/drivers/media/video/rk30_camera.c b/drivers/media/video/rk30_camera.c index dba7ff4fbdd8..31e8a5bfa746 100644 --- a/drivers/media/video/rk30_camera.c +++ b/drivers/media/video/rk30_camera.c @@ -847,6 +847,575 @@ static int rk_sensor_iomux(int pin) break; } } +#elif defined(CONFIG_ARCH_RK31) + switch (pin) + { + case RK30_PIN0_PA0: + case RK30_PIN0_PA1: + case RK30_PIN0_PA2: + case RK30_PIN0_PA3: + case RK30_PIN0_PA4: + case RK30_PIN0_PA5: + case RK30_PIN0_PA6: + case RK30_PIN0_PA7: + case RK30_PIN0_PB0: + case RK30_PIN0_PB1: + case RK30_PIN0_PB2: + case RK30_PIN0_PB3: + case RK30_PIN0_PB4: + case RK30_PIN0_PB5: + case RK30_PIN0_PB6: + case RK30_PIN0_PB7: + case RK30_PIN0_PC0: + { + rk30_mux_api_set(GPIO0C0_FLASHDATA8_NAME,0); + break; + } + case RK30_PIN0_PC1: + { + rk30_mux_api_set(GPIO0C1_FLASHDATA9_NAME,0); + break; + } + case RK30_PIN0_PC2: + { + rk30_mux_api_set(GPIO0C2_FLASHDATA10_NAME,0); + break; + } + case RK30_PIN0_PC3: + { + rk30_mux_api_set(GPIO0C3_FLASHDATA11_NAME,0); + break; + } + case RK30_PIN0_PC4: + { + rk30_mux_api_set(GPIO0C4_FLASHDATA12_NAME,0); + break; + } + case RK30_PIN0_PC5: + { + rk30_mux_api_set(GPIO0C5_FLASHDATA13_NAME,0); + break; + } + case RK30_PIN0_PC6: + { + rk30_mux_api_set(GPIO0C6_FLASHDATA14_NAME,0); + break; + } + case RK30_PIN0_PC7: + { + rk30_mux_api_set(GPIO0C7_FLASHDATA15_NAME,0); + break; + } + case RK30_PIN0_PD0: + { + rk30_mux_api_set(GPIO0D0_FLASHDQS_EMMCCLKOUT_NAME,0); + break; + } + case RK30_PIN0_PD1: + { + rk30_mux_api_set(GPIO0D1_FLASHCSN1_NAME,0); + break; + } + case RK30_PIN0_PD2: + { + rk30_mux_api_set(GPIO0D2_FLASHCSN2_EMMCCMD_NAME,0); + break; + } + case RK30_PIN0_PD3: + { + rk30_mux_api_set(GPIO0D3_FLASHCSN3_EMMCRSTNOUT_NAME,0); + break; + } + case RK30_PIN0_PD4: + { + rk30_mux_api_set(GPIO0D4_SPI1RXD_NAME,0); + break; + } + case RK30_PIN0_PD5: + { + rk30_mux_api_set(GPIO0D5_SPI1TXD_NAME,0); + break; + } + case RK30_PIN0_PD6: + { + rk30_mux_api_set(GPIO0D6_SPI1CLK_NAME,0); + break; + } + case RK30_PIN0_PD7: + { + rk30_mux_api_set(GPIO0D7_SPI1CSN0_NAME,0); + break; + } + case RK30_PIN1_PA0: + { + rk30_mux_api_set(GPIO1A0_UART0SIN_NAME,0); + break; + } + case RK30_PIN1_PA1: + { + rk30_mux_api_set(GPIO1A1_UART0SOUT_NAME,0); + break; + } + case RK30_PIN1_PA2: + { + rk30_mux_api_set(GPIO1A2_UART0CTSN_NAME,0); + break; + } + case RK30_PIN1_PA3: + { + rk30_mux_api_set(GPIO1A3_UART0RTSN_NAME,0); + break; + } + case RK30_PIN1_PA4: + { + rk30_mux_api_set(GPIO1A4_UART1SIN_SPI0RXD_NAME,0); + break; + } + case RK30_PIN1_PA5: + { + rk30_mux_api_set(GPIO1A5_UART1SOUT_SPI0TXD_NAME,0); + break; + } + case RK30_PIN1_PA6: + { + rk30_mux_api_set(GPIO1A6_UART1CTSN_SPI0CLK_NAME,0); + break; + } + case RK30_PIN1_PA7: + { + rk30_mux_api_set(GPIO1A7_UART1RTSN_SPI0CSN0_NAME,0); + break; + } + case RK30_PIN1_PB0: + { + rk30_mux_api_set(GPIO1B0_UART2SIN_JTAGTDI_NAME,0); + break; + } + case RK30_PIN1_PB1: + { + rk30_mux_api_set(GPIO1B1_UART2SOUT_JTAGTDO_NAME,0); + break; + } + case RK30_PIN1_PB2: + { + rk30_mux_api_set(GPIO1B2_UART3SIN_GPSMAG_NAME,0); + break; + } + case RK30_PIN1_PB3: + { + rk30_mux_api_set(GPIO1B3_UART3SOUT_GPSSIG_NAME,0); + break; + } + case RK30_PIN1_PB4: + { + rk30_mux_api_set(GPIO1B4_UART3CTSN_GPSRFCLK_NAME,0); + break; + } + case RK30_PIN1_PB5: + { + rk30_mux_api_set(GPIO1B5_UART3RTSN_NAME,0); + break; + } + case RK30_PIN1_PB6: + { + rk30_mux_api_set(GPIO1B6_SPDIFTX_SPI1CSN1_NAME,0); + break; + } + case RK30_PIN1_PB7: + { + rk30_mux_api_set(GPIO1B7_SPI0CSN1_NAME,0); + break; + } + case RK30_PIN1_PC0: + { + rk30_mux_api_set(GPIO1C0_I2SCLK_NAME,0); + break; + } + case RK30_PIN1_PC1: + { + rk30_mux_api_set(GPIO1C1_I2SSCLK_NAME,0); + break; + } + case RK30_PIN1_PC2: + { + rk30_mux_api_set(GPIO1C2_I2SLRCLKRX_NAME,0); + break; + } + case RK30_PIN1_PC3: + { + rk30_mux_api_set(GPIO1C3_I2SLRCLKTX_NAME,0); + break; + } + case RK30_PIN1_PC4: + { + rk30_mux_api_set(GPIO1C4_I2SSDI_NAME,0); + break; + } + case RK30_PIN1_PC5: + case RK30_PIN1_PC6: + case RK30_PIN1_PC7: + break; + case RK30_PIN1_PD0: + { + rk30_mux_api_set(GPIO1D0_I2C0SDA_NAME,0); + break; + } + case RK30_PIN1_PD1: + { + rk30_mux_api_set(GPIO1D1_I2C0SCL_NAME,0); + break; + } + case RK30_PIN1_PD2: + { + rk30_mux_api_set(GPIO1D2_I2C1SDA_NAME,0); + break; + } + case RK30_PIN1_PD3: + { + rk30_mux_api_set(GPIO1D3_I2C1SCL_NAME,0); + break; + } + case RK30_PIN1_PD4: + { + rk30_mux_api_set(GPIO1D4_I2C2SDA_NAME,0); + break; + } + case RK30_PIN1_PD5: + { + rk30_mux_api_set(GPIO1D5_I2C2SCL_NAME,0); + break; + } + case RK30_PIN1_PD6: + { + rk30_mux_api_set(GPIO1D6_I2C4SDA_NAME,0); + break; + } + case RK30_PIN1_PD7: + { + rk30_mux_api_set(GPIO1D7_I2C4SCL_NAME,0); + break; + } + case RK30_PIN2_PA0: + { + rk30_mux_api_set(GPIO2A0_LCDC1DATA0_SMCDATA0_TRACEDATA0_NAME,0); + break; + } + case RK30_PIN2_PA1: + { + rk30_mux_api_set(GPIO2A1_LCDC1DATA1_SMCDATA1_TRACEDATA1_NAME,0); + break; + } + case RK30_PIN2_PA2: + { + rk30_mux_api_set(GPIO2A2_LCDC1DATA2_SMCDATA2_TRACEDATA2_NAME,0); + break; + } + case RK30_PIN2_PA3: + { + rk30_mux_api_set(GPIO2A3_LCDC1DATA3_SMCDATA3_TRACEDATA3_NAME,0); + break; + } + case RK30_PIN2_PA4: + { + rk30_mux_api_set(GPIO2A4_LCDC1DATA4_SMCDATA4_TRACEDATA4_NAME,0); + break; + } + case RK30_PIN2_PA5: + { + rk30_mux_api_set(GPIO2A5_LCDC1DATA5_SMCDATA5_TRACEDATA5_NAME,0); + break; + } + case RK30_PIN2_PA6: + { + rk30_mux_api_set(GPIO2A6_LCDC1DATA6_SMCDATA6_TRACEDATA6_NAME,0); + break; + } + case RK30_PIN2_PA7: + { + rk30_mux_api_set(GPIO2A7_LCDC1DATA7_SMCDATA7_TRACEDATA7_NAME,0); + break; + } + case RK30_PIN2_PB0: + { + rk30_mux_api_set(GPIO2B0_LCDC1DATA8_SMCDATA8_TRACEDATA8_NAME,0); + break; + } + case RK30_PIN2_PB1: + { + rk30_mux_api_set(GPIO2B1_LCDC1DATA9_SMCDATA9_TRACEDATA9_NAME,0); + break; + } + case RK30_PIN2_PB2: + { + rk30_mux_api_set(GPIO2B2_LCDC1DATA10_SMCDATA10_TRACEDATA10_NAME,0); + break; + } + case RK30_PIN2_PB3: + { + rk30_mux_api_set(GPIO2B3_LCDC1DATA11_SMCDATA11_TRACEDATA11_NAME,0); + break; + } + case RK30_PIN2_PB4: + { + rk30_mux_api_set(GPIO2B4_LCDC1DATA12_SMCDATA12_TRACEDATA12_NAME,0); + break; + } + case RK30_PIN2_PB5: + { + rk30_mux_api_set(GPIO2B5_LCDC1DATA13_SMCDATA13_TRACEDATA13_NAME,0); + break; + } + case RK30_PIN2_PB6: + { + rk30_mux_api_set(GPIO2B6_LCDC1DATA14_SMCDATA14_TRACEDATA14_NAME,0); + break; + } + case RK30_PIN2_PB7: + { + rk30_mux_api_set(GPIO2B7_LCDC1DATA15_SMCDATA15_TRACEDATA15_NAME,0); + break; + } + case RK30_PIN2_PC0: + { + rk30_mux_api_set(GPIO2C0_LCDC1DATA16_SMCADDR0_TRACECLK_NAME,0); + break; + } + case RK30_PIN2_PC1: + { + rk30_mux_api_set(GPIO2C1_LCDC1DATA17_SMCADDR1_TRACECTL_NAME,0); + break; + } + case RK30_PIN2_PC2: + { + rk30_mux_api_set(GPIO2C2_LCDC1DATA18_SMCADDR2_NAME,0); + break; + } + case RK30_PIN2_PC3: + { + rk29_mux_api_set(GPIO2C3_LCDC1DATA19_SMCADDR3_NAME,0); + break; + } + case RK30_PIN2_PC4: + { + rk30_mux_api_set(GPIO2C4_LCDC1DATA20_SMCADDR4_NAME,0); + break; + } + case RK30_PIN2_PC5: + { + rk30_mux_api_set(GPIO2C5_LCDC1DATA21_SMCADDR5_NAME,0); + break; + } + case RK30_PIN2_PC6: + { + rk30_mux_api_set(GPIO2C6_LCDC1DATA22_SMCADDR6_NAME,0); + break; + } + case RK30_PIN2_PC7: + { + rk30_mux_api_set(GPIO2C7_LCDC1DATA23_SMCADDR7_NAME,0); + break; + } + case RK30_PIN2_PD0: + { + rk30_mux_api_set(GPIO2D0_LCDC1DCLK_SMCCSN0_NAME,0); + break; + } + case RK30_PIN2_PD1: + { + rk30_mux_api_set(GPIO2D1_LCDC1DEN_SMCWEN_NAME,0); + break; + } + case RK30_PIN2_PD2: + { + rk30_mux_api_set(GPIO2D2_LCDC1HSYNC_SMCOEN_NAME,0); + break; + } + case RK30_PIN2_PD3: + { + rk30_mux_api_set(GPIO2D3_LCDC1VSYNC_SMCADVN_NAME,0); + break; + } + case RK30_PIN2_PD4: + { + rk30_mux_api_set(GPIO2D4_SMCBLSN0_NAME,0); + break; + } + case RK30_PIN2_PD5: + { + rk30_mux_api_set(GPIO2D5_SMCBLSN1_NAME,0); + break; + } + case RK30_PIN2_PD6: + { + rk30_mux_api_set(GPIO2D6_SMCCSN1_NAME,0); + break; + } + case RK30_PIN2_PD7: + { + rk30_mux_api_set(GPIO2D7_TESTCLOCKOUT_NAME,0); + break; + } + case RK30_PIN3_PA0: + { + rk30_mux_api_set(GPIO3A0_SDMMC0RSTNOUT_NAME,0); + break; + } + case RK30_PIN3_PA1: + { + rk30_mux_api_set(GPIO3A1_SDMMC0PWREN_NAME,0); + break; + } + case RK30_PIN3_PA2: + { + rk30_mux_api_set(GPIO3A2_SDMMC0CLKOUT_NAME,0); + break; + } + case RK30_PIN3_PA3: + { + rk30_mux_api_set(GPIO3A3_SDMMC0CMD_NAME,0); + break; + } + case RK30_PIN3_PA4: + { + rk30_mux_api_set(GPIO3A4_SDMMC0DATA0_NAME,0); + break; + } + case RK30_PIN3_PA5: + { + rk30_mux_api_set(GPIO3A5_SDMMC0DATA1_NAME,0); + break; + } + case RK30_PIN3_PA6: + { + rk30_mux_api_set(GPIO3A6_SDMMC0DATA2_NAME,0); + break; + } + case RK30_PIN3_PA7: + { + rk30_mux_api_set(GPIO3A7_SDMMC0DATA3_NAME,0); + break; + } + case RK30_PIN3_PB0: + { + rk30_mux_api_set(GPIO3B0_SDMMC0DETECTN_NAME,0); + break; + } + case RK30_PIN3_PB1: + { + rk30_mux_api_set(GPIO3B1_SDMMC0WRITEPRT_NAME,0); + break; + } + case RK30_PIN3_PB2: + break; + case RK30_PIN3_PB3: + { + rk30_mux_api_set(GPIO3B3_CIFCLKOUT_NAME,0); + break; + } + case RK30_PIN3_PB4: + { + rk30_mux_api_set(GPIO3B4_CIFDATA0_HSADCDATA8_NAME,0); + break; + } + case RK30_PIN3_PB5: + { + rk30_mux_api_set(GPIO3B5_CIFDATA1_HSADCDATA9_NAME,0); + break; + } + case RK30_PIN3_PB6: + { + rk30_mux_api_set(GPIO3B6_CIFDATA10_I2C3SDA_NAME,0); + break; + } + case RK30_PIN3_PB7: + { + rk30_mux_api_set(GPIO3B7_CIFDATA11_I2C3SCL_NAME,0); + break; + } + case RK30_PIN3_PC0: + { + rk30_mux_api_set(GPIO3C0_SDMMC1CMD_RMIITXEN_NAME,0); + break; + } + case RK30_PIN3_PC1: + { + rk30_mux_api_set(GPIO3C1_SDMMC1DATA0_RMIITXD1_NAME,0); + break; + } + case RK30_PIN3_PC2: + { + rk30_mux_api_set(GPIO3C2_SDMMC1DATA1_RMIITXD0_NAME,0); + break; + } + case RK30_PIN3_PC3: + { + rk30_mux_api_set(GPIO3C3_SDMMC1DATA2_RMIIRXD0_NAME,0); + break; + } + case RK30_PIN3_PC4: + { + rk30_mux_api_set(GPIO3C4_SDMMC1DATA3_RMIIRXD1_NAME,0); + break; + } + case RK30_PIN3_PC5: + { + rk30_mux_api_set(GPIO3C5_SDMMC1CLKOUT_RMIICLKOUT_RMIICLKIN_NAME,0); + break; + } + case RK30_PIN3_PC6: + { + rk30_mux_api_set(GPIO3C6_SDMMC1DETECTN_RMIIRXERR_NAME,0); + break; + } + case RK30_PIN3_PC7: + { + rk30_mux_api_set(GPIO3C7_SDMMC1WRITEPRT_RMIICRS_NAME,0); + break; + } + case RK30_PIN3_PD0: + { + rk30_mux_api_set(GPIO3D0_SDMMC1PWREN_MIIMD_NAME,0); + break; + } + case RK30_PIN3_PD1: + { + rk30_mux_api_set(GPIO3D1_SDMMC1BACKENDPWR_MIIMDCLK_NAME,0); + break; + } + case RK30_PIN3_PD2: + { + rk30_mux_api_set(GPIO3D2_SDMMC1INTN_NAME,0); + break; + } + case RK30_PIN3_PD3: + { + rk30_mux_api_set(GPIO3D3_PWM0_NAME,0); + break; + } + case RK30_PIN3_PD4: + { + rk30_mux_api_set(GPIO3D4_PWM1_JTAGTRSTN_NAME,0); + break; + } + case RK30_PIN3_PD5: + { + rk30_mux_api_set(GPIO3D5_PWM2_JTAGTCK_OTGDRVVBUS_NAME,0); + break; + } + case RK30_PIN3_PD6: + { + rk30_mux_api_set(GPIO3D6_PWM3_JTAGTMS_HOSTDRVVBUS_NAME,0); + break; + } + case RK30_PIN3_PD7: + break; + default: + { + printk("Pin=%d isn't RK GPIO, Please init it's iomux yourself!",pin); + break; + } + } + #endif return 0; } From 32eb239e65f54982bd2f85754fbedfa12eb05265 Mon Sep 17 00:00:00 2001 From: chenxing Date: Tue, 14 Aug 2012 18:45:41 +0800 Subject: [PATCH 180/261] rk2928:sdk: add cpufreq and dvfs support, BUT NOT compile --- arch/arm/mach-rk2928/Makefile | 2 + arch/arm/mach-rk2928/board-rk2928-sdk.c | 48 +- arch/arm/mach-rk2928/clock.c | 19 +- arch/arm/mach-rk2928/clock_data.c | 30 +- arch/arm/mach-rk2928/cpufreq.c | 711 ++++++++ arch/arm/mach-rk2928/dvfs.c | 1923 ++++++++++++++++++++++ arch/arm/mach-rk2928/include/mach/dvfs.h | 183 ++ 7 files changed, 2898 insertions(+), 18 deletions(-) mode change 100755 => 100644 arch/arm/mach-rk2928/clock.c create mode 100644 arch/arm/mach-rk2928/cpufreq.c create mode 100644 arch/arm/mach-rk2928/dvfs.c create mode 100644 arch/arm/mach-rk2928/include/mach/dvfs.h diff --git a/arch/arm/mach-rk2928/Makefile b/arch/arm/mach-rk2928/Makefile index 13a891691d1d..6acd3f120855 100644 --- a/arch/arm/mach-rk2928/Makefile +++ b/arch/arm/mach-rk2928/Makefile @@ -6,6 +6,8 @@ obj-y += devices.o obj-y += iomux.o obj-y += clock.o obj-y += clock_data.o +obj-$(CONFIG_CPU_FREQ) += cpufreq.o +obj-$(CONFIG_DVFS) += dvfs.o obj-$(CONFIG_PM) += pm.o CFLAGS_pm.o += -Os -mthumb diff --git a/arch/arm/mach-rk2928/board-rk2928-sdk.c b/arch/arm/mach-rk2928/board-rk2928-sdk.c index b44fdc5b5038..fb48103c0245 100755 --- a/arch/arm/mach-rk2928/board-rk2928-sdk.c +++ b/arch/arm/mach-rk2928/board-rk2928-sdk.c @@ -33,7 +33,7 @@ #include #include #include -//#include +#include #include #include @@ -762,10 +762,56 @@ static void __init rk2928_reserve(void) #endif board_mem_reserved(); } +/** + * dvfs_cpu_logic_table: table for arm and logic dvfs + * @frequency : arm frequency + * @cpu_volt : arm voltage depend on frequency + * @logic_volt : logic voltage arm requests depend on frequency + * comments : min arm/logic voltage + */ +static struct dvfs_arm_table dvfs_cpu_logic_table[] = { + {.frequency = 216 * 1000, .cpu_volt = 1200 * 1000, .logic_volt = 1200 * 1000},//0.975V/1.000V + {.frequency = 312 * 1000, .cpu_volt = 1200 * 1000, .logic_volt = 1200 * 1000},//0.975V/1.000V + {.frequency = 408 * 1000, .cpu_volt = 1200 * 1000, .logic_volt = 1200 * 1000},//1.000V/1.025V + {.frequency = 504 * 1000, .cpu_volt = 1200 * 1000, .logic_volt = 1200 * 1000},//1.000V/1.025V + {.frequency = 600 * 1000, .cpu_volt = 1200 * 1000, .logic_volt = 1200 * 1000},//1.025V/1.050V + {.frequency = 696 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.000V/1.025V + {.frequency = 816 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V + {.frequency = 912 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V +#if 0 + {.frequency = 1008 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V + {.frequency = 1104 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V + {.frequency = 1200 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V + {.frequency = 1104 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V + {.frequency = 1248 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V +#endif + //{.frequency = 1000 * 1000, .cpu_volt = 1225 * 1000, .logic_volt = 1200 * 1000},//1.150V/1.100V + {.frequency = CPUFREQ_TABLE_END}, +}; + +static struct cpufreq_frequency_table dvfs_gpu_table[] = { + {.frequency = 266 * 1000, .index = 1050 * 1000}, + {.frequency = 400 * 1000, .index = 1275 * 1000}, + {.frequency = CPUFREQ_TABLE_END}, +}; + +static struct cpufreq_frequency_table dvfs_ddr_table[] = { + {.frequency = 300 * 1000, .index = 1050 * 1000}, + {.frequency = 400 * 1000, .index = 1125 * 1000}, + {.frequency = CPUFREQ_TABLE_END}, +}; + +#define DVFS_CPU_TABLE_SIZE (ARRAY_SIZE(dvfs_cpu_logic_table)) +static struct cpufreq_frequency_table cpu_dvfs_table[DVFS_CPU_TABLE_SIZE]; +static struct cpufreq_frequency_table dep_cpu2core_table[DVFS_CPU_TABLE_SIZE]; void __init board_clock_init(void) { rk2928_clock_data_init(periph_pll_default, codec_pll_default, RK30_CLOCKS_DEFAULT_FLAGS); + dvfs_set_arm_logic_volt(dvfs_cpu_logic_table, cpu_dvfs_table, dep_cpu2core_table); + dvfs_set_freq_volt_table(clk_get(NULL, "gpu"), dvfs_gpu_table); + //dvfs_set_freq_volt_table(clk_get(NULL, "ddr"), dvfs_ddr_table); + printk("%s end\n", __func__); } diff --git a/arch/arm/mach-rk2928/clock.c b/arch/arm/mach-rk2928/clock.c old mode 100755 new mode 100644 index 9fe7ae46d5b1..b9bb52d2adc2 --- a/arch/arm/mach-rk2928/clock.c +++ b/arch/arm/mach-rk2928/clock.c @@ -23,7 +23,7 @@ #include #include #include "clock.h" -//#include +#include #include #define CLOCK_PRINTK_DBG(fmt, args...) pr_debug(fmt, ## args); @@ -126,6 +126,7 @@ int clk_register(struct clk *clk) return -EINVAL; //INIT_LIST_HEAD(&clk->sibling); INIT_LIST_HEAD(&clk->children); + /* * trap out already registered clocks */ @@ -138,11 +139,10 @@ int clk_register(struct clk *clk) else if (clk->parents) clk->parent =clk_default_get_parent(clk); - if (clk->parent){ + if (clk->parent) list_add(&clk->sibling, &clk->parent->children); - } else { + else list_add(&clk->sibling, &root_clks); - } list_add(&clk->node, &clocks); mutex_unlock(&clocks_mutex); return 0; @@ -318,7 +318,7 @@ int clk_set_parent_nolock(struct clk *clk, struct clk *parent) return ret; } /**********************************dvfs****************************************************/ -#if 0 + struct clk_node *clk_get_dvfs_info(struct clk *clk) { return clk->dvfs_info; @@ -338,7 +338,7 @@ void clk_register_dvfs(struct clk_node *dvfs_clk, struct clk *clk) { clk->dvfs_info = dvfs_clk; } -#endif + /*------------------------------------------------------------------------- * Optional clock functions defined in include/linux/clk.h @@ -398,10 +398,9 @@ int clk_set_rate(struct clk *clk, unsigned long rate) } if (rate == clk->rate) return 0; -#if 0 if (clk->dvfs_info!=NULL&&is_support_dvfs(clk->dvfs_info)) return dvfs_set_rate(clk, rate); -#endif + LOCK(); ret = clk_set_rate_nolock(clk, rate); UNLOCK(); @@ -703,7 +702,8 @@ void clk_register_dump_ops(struct clk_dump_ops *ops) { dump_def_ops=ops; } - + +#ifdef CONFIG_RK_CLOCK_PROC static int proc_clk_show(struct seq_file *s, void *v) { struct clk* clk; @@ -747,4 +747,5 @@ static int __init clk_proc_init(void) } late_initcall(clk_proc_init); +#endif /* CONFIG_RK_CLOCK_PROC */ diff --git a/arch/arm/mach-rk2928/clock_data.c b/arch/arm/mach-rk2928/clock_data.c index 8584e6d4d955..8b311cc95776 100644 --- a/arch/arm/mach-rk2928/clock_data.c +++ b/arch/arm/mach-rk2928/clock_data.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "clock.h" //#include @@ -126,8 +127,19 @@ struct pll_clk_set { } static const struct apll_clk_set apll_clks[] = { - _APLL_SET_CLKS( 650, 6, 325, 2, 1, 1, 0, 41, 21, 81, 21, 21), - _APLL_SET_CLKS(1000, 3, 125, 1, 1, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS(1248, 1, 52, 1, 1, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS(1200, 1, 50, 1, 1, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS(1104, 1, 46, 1, 1, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS(1008, 1, 42, 1, 1, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS( 912, 1, 38, 1, 1, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS( 816, 1, 34, 1, 1, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS( 696, 1, 29, 1, 1, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS( 600, 1, 25, 1, 1, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS( 504, 1, 21, 1, 1, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS( 408, 1, 17, 1, 1, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS( 312, 1, 52, 2, 2, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS( 216, 1, 36, 2, 2, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS( 0, 1, 0, 1, 1, 1, 0, 41, 21, 41, 21, 21), }; #define _PLL_SET_CLKS(_mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac) \ @@ -734,7 +746,7 @@ static int apll_clk_set_rate(struct clk *clk, unsigned long rate) CLKDATA_DBG("pllcon0 %08x\n", cru_readl(PLL_CONS(0,0))); CLKDATA_DBG("pllcon1 %08x\n", cru_readl(PLL_CONS(0,1))); CLKDATA_DBG("pllcon2 %08x\n", cru_readl(PLL_CONS(0,2))); - CLKDATA_DBG("pllcon3 %08x\n", cru_readl(PLL_CONS(0,3))); + //CLKDATA_DBG("pllcon3 %08x\n", cru_readl(PLL_CONS(0,3))); CLKDATA_DBG("clksel0 %08x\n", cru_readl(CRU_CLKSELS_CON(0))); CLKDATA_DBG("clksel1 %08x\n", cru_readl(CRU_CLKSELS_CON(1))); if(clk_set->rate==rate) { @@ -761,7 +773,7 @@ static int apll_clk_set_rate(struct clk *clk, unsigned long rate) //rk2928_clock_udelay(5); //wating lock state - rk2928_clock_udelay(clk_set->rst_dly); + rk2928_clock_udelay(clk_set->rst_dly); pll_wait_lock(pll_id); //return form slow @@ -1003,7 +1015,7 @@ static int arm_core_clk_set_rate(struct clk *c, unsigned long rate) //set arm pll div 1 //set_cru_bits_w_msk(0,c->div_mask,c->div_shift,c->clksel_con); - CLKDATA_DBG("Failed to change clk pll %s to %lu\n",c->name,rate); + CLKDATA_DBG("change clk pll %s to %lu\n",c->name,rate); ret = clk_set_rate_nolock(c->parent, rate); if (ret) { CLKDATA_ERR("Failed to change clk pll %s to %lu\n",c->name,rate); @@ -1013,6 +1025,7 @@ static int arm_core_clk_set_rate(struct clk *c, unsigned long rate) return 0; } static struct clk clk_core_pre = { + //.name = "cpu", .name = "core_pre", .parent = &arm_pll_clk, .recalc = clksel_recalc_div, @@ -1599,6 +1612,7 @@ static struct clk clk_saradc = { // name: gpu_aclk static struct clk *clk_gpu_pre_parents[] = SELECT_FROM_2PLLS_CG; static struct clk clk_gpu_pre = { + //.name = "gpu", .name = "gpu_pre", .parent = &general_pll_clk, .mode = gate_mode, @@ -2428,7 +2442,7 @@ static void __init rk2928_clock_common_init(unsigned long gpll_rate,unsigned lon { CLKDATA_DBG("ENTER %s\n", __func__); - clk_set_rate_nolock(&clk_core_pre, 1000 * MHZ);//816 + clk_set_rate_nolock(&clk_core_pre, 816 * MHZ);//816 //general clk_set_rate_nolock(&general_pll_clk, gpll_rate); //code pll @@ -2530,8 +2544,8 @@ void __init _rk2928_clock_data_init(unsigned long gpll,unsigned long cpll,int fl void __init rk2928_clock_data_init(unsigned long gpll,unsigned long cpll,u32 flags) { - printk("%s version: 2012-8-7\n", __func__); + printk("%s version: 2012-8-14\n", __func__); _rk2928_clock_data_init(gpll,cpll,flags); - //rk2928_dvfs_init(); + rk30_dvfs_init(); } diff --git a/arch/arm/mach-rk2928/cpufreq.c b/arch/arm/mach-rk2928/cpufreq.c new file mode 100644 index 000000000000..4f796715415d --- /dev/null +++ b/arch/arm/mach-rk2928/cpufreq.c @@ -0,0 +1,711 @@ +/* + * Copyright (C) 2012 ROCKCHIP, Inc. + * + * 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. + * + */ +//#define DEBUG 1 +#define pr_fmt(fmt) "cpufreq: " fmt +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef DEBUG +#define FREQ_PRINTK_DBG(fmt, args...) pr_debug(fmt, ## args) +#define FREQ_PRINTK_LOG(fmt, args...) pr_debug(fmt, ## args) +#else +#define FREQ_PRINTK_DBG(fmt, args...) do {} while(0) +#define FREQ_PRINTK_LOG(fmt, args...) do {} while(0) +#endif +#define FREQ_PRINTK_ERR(fmt, args...) pr_err(fmt, ## args) + +/* Frequency table index must be sequential starting at 0 */ +static struct cpufreq_frequency_table default_freq_table[] = { + {.frequency = 816 * 1000, .index = 1100 * 1000}, + {.frequency = CPUFREQ_TABLE_END}, +}; + +static struct cpufreq_frequency_table *freq_table = default_freq_table; +static unsigned int max_freq = -1; + +/*********************************************************/ + +/* additional symantics for "relation" in cpufreq with pm */ +#define DISABLE_FURTHER_CPUFREQ 0x10 +#define ENABLE_FURTHER_CPUFREQ 0x20 +#define MASK_FURTHER_CPUFREQ 0x30 +/* With 0x00(NOCHANGE), it depends on the previous "further" status */ +static int no_cpufreq_access; +static unsigned int suspend_freq = 816 * 1000; + +static struct workqueue_struct *freq_wq; +static struct clk *cpu_clk; +static struct clk *cpu_pll; +static struct clk *cpu_gpll; + + +static DEFINE_MUTEX(cpufreq_mutex); + +static struct clk *gpu_clk; +#define GPU_MAX_RATE 350*1000*1000 + +static int cpufreq_scale_rate_for_dvfs(struct clk *clk, unsigned long rate, dvfs_set_rate_callback set_rate); + +/*******************************************************/ +static unsigned int rk30_getspeed(unsigned int cpu) +{ + unsigned long rate; + + if (cpu >= NR_CPUS) + return 0; + + rate = clk_get_rate(cpu_clk) / 1000; + return rate; +} + +static bool rk30_cpufreq_is_ondemand_policy(struct cpufreq_policy *policy) +{ + char c = 0; + if (policy && policy->governor) + c = policy->governor->name[0]; + return (c == 'o' || c == 'i' || c == 'c' || c == 'h'); +} + +/**********************thermal limit**************************/ +#define CONFIG_RK30_CPU_FREQ_LIMIT_BY_TEMP + +#ifdef CONFIG_RK30_CPU_FREQ_LIMIT_BY_TEMP +static void rk30_cpufreq_temp_limit_work_func(struct work_struct *work); + +static DECLARE_DELAYED_WORK(rk30_cpufreq_temp_limit_work, rk30_cpufreq_temp_limit_work_func); + +static unsigned int temp_limt_freq = -1; +module_param(temp_limt_freq, uint, 0444); + +#define TEMP_LIMIT_FREQ 816000 + +static const struct cpufreq_frequency_table temp_limits[] = { + {.frequency = 1416 * 1000, .index = 50}, + {.frequency = 1200 * 1000, .index = 55}, + {.frequency = 1008 * 1000, .index = 60}, + {.frequency = 816 * 1000, .index = 75}, +}; + +//extern int rk30_tsadc_get_temp(unsigned int chn); + +//#define get_cpu_thermal() rk30_tsadc_get_temp(0) +static void rk30_cpufreq_temp_limit_work_func(struct work_struct *work) +{ + struct cpufreq_policy *policy; + int temp = 25, i; + unsigned int new = -1; + + if (clk_get_rate(gpu_clk) > GPU_MAX_RATE) + goto out; + + //temp = max(rk30_tsadc_get_temp(0), rk30_tsadc_get_temp(1)); + FREQ_PRINTK_LOG("cpu_thermal(%d)\n", temp); + + for (i = 0; i < ARRAY_SIZE(temp_limits); i++) { + if (temp > temp_limits[i].index) { + new = temp_limits[i].frequency; + } + } + if (temp_limt_freq != new) { + temp_limt_freq = new; + if (new != -1) { + FREQ_PRINTK_DBG("temp_limit set rate %d kHz\n", temp_limt_freq); + policy = cpufreq_cpu_get(0); + cpufreq_driver_target(policy, policy->cur, CPUFREQ_RELATION_L); + cpufreq_cpu_put(policy); + } + } + +out: + queue_delayed_work(freq_wq, &rk30_cpufreq_temp_limit_work, HZ); +} + +static int rk30_cpufreq_notifier_policy(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct cpufreq_policy *policy = data; + + if (val != CPUFREQ_NOTIFY) + return 0; + + if (rk30_cpufreq_is_ondemand_policy(policy)) { + FREQ_PRINTK_DBG("queue work\n"); + queue_delayed_work(freq_wq, &rk30_cpufreq_temp_limit_work, 0); + } else { + FREQ_PRINTK_DBG("cancel work\n"); + cancel_delayed_work_sync(&rk30_cpufreq_temp_limit_work); + } + + return 0; +} + +static struct notifier_block notifier_policy_block = { + .notifier_call = rk30_cpufreq_notifier_policy +}; +#endif + +/************************************dvfs tst************************************/ +//#define CPU_FREQ_DVFS_TST +#ifdef CPU_FREQ_DVFS_TST +static unsigned int freq_dvfs_tst_rate; +static void rk30_cpufreq_dvsf_tst_work_func(struct work_struct *work); +static DECLARE_DELAYED_WORK(rk30_cpufreq_dvsf_tst_work, rk30_cpufreq_dvsf_tst_work_func); +static int test_count; +#define TEST_FRE_NUM 11 +static int test_tlb_rate[TEST_FRE_NUM] = { 504, 1008, 504, 1200, 252, 816, 1416, 252, 1512, 252, 816 }; +//static int test_tlb_rate[TEST_FRE_NUM]={504,1008,504,1200,252,816,1416,126,1512,126,816}; + +#define TEST_GPU_NUM 3 + +static int test_tlb_gpu[TEST_GPU_NUM] = { 360, 400, 180 }; +static int test_tlb_ddr[TEST_GPU_NUM] = { 401, 200, 500 }; + +static int gpu_ddr = 0; + +static void rk30_cpufreq_dvsf_tst_work_func(struct work_struct *work) +{ + struct cpufreq_policy *policy = cpufreq_cpu_get(0); + + gpu_ddr++; + +#if 0 + FREQ_PRINTK_LOG("cpufreq_dvsf_tst,ddr%u,gpu%u\n", + test_tlb_ddr[gpu_ddr % TEST_GPU_NUM], + test_tlb_gpu[gpu_ddr % TEST_GPU_NUM]); + clk_set_rate(ddr_clk, test_tlb_ddr[gpu_ddr % TEST_GPU_NUM] * 1000 * 1000); + clk_set_rate(gpu_clk, test_tlb_gpu[gpu_ddr % TEST_GPU_NUM] * 1000 * 1000); +#endif + + test_count++; + freq_dvfs_tst_rate = test_tlb_rate[test_count % TEST_FRE_NUM] * 1000; + FREQ_PRINTK_LOG("cpufreq_dvsf_tst,cpu set rate %d\n", freq_dvfs_tst_rate); + cpufreq_driver_target(policy, policy->cur, CPUFREQ_RELATION_L); + cpufreq_cpu_put(policy); + + queue_delayed_work(freq_wq, &rk30_cpufreq_dvsf_tst_work, msecs_to_jiffies(1000)); +} +#endif /* CPU_FREQ_DVFS_TST */ + +/***********************************************************************/ +static int rk30_verify_speed(struct cpufreq_policy *policy) +{ + if (!freq_table) + return -EINVAL; + return cpufreq_frequency_table_verify(policy, freq_table); +} + +static int rk30_cpu_init(struct cpufreq_policy *policy) +{ + if (policy->cpu == 0) { + int i; + struct clk *ddr_clk; + gpu_clk = clk_get(NULL, "gpu"); + if (!IS_ERR(gpu_clk)) + clk_enable_dvfs(gpu_clk); +#if 0 + + ddr_clk = clk_get(NULL, "ddr"); + if (!IS_ERR(ddr_clk)) + { + clk_enable_dvfs(ddr_clk); + clk_set_rate(ddr_clk,clk_get_rate(ddr_clk)-1); + } + +#endif + cpu_clk = clk_get(NULL, "cpu"); + cpu_pll = clk_get(NULL, "arm_pll"); + + cpu_gpll = clk_get(NULL, "arm_gpll"); + if (IS_ERR(cpu_clk)) + return PTR_ERR(cpu_clk); + + dvfs_clk_register_set_rate_callback(cpu_clk, cpufreq_scale_rate_for_dvfs); + freq_table = dvfs_get_freq_volt_table(cpu_clk); + if (freq_table == NULL) { + freq_table = default_freq_table; + } + max_freq = freq_table[0].frequency; + for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) { + max_freq = max(max_freq, freq_table[i].frequency); + } + clk_enable_dvfs(cpu_clk); + + /* Limit gpu frequency between 133M to 400M */ +#if 0 + dvfs_clk_enable_limit(gpu_clk, 133000000, 400000000); +#endif + + freq_wq = create_singlethread_workqueue("rk30_cpufreqd"); +#ifdef CONFIG_RK30_CPU_FREQ_LIMIT_BY_TEMP + if (rk30_cpufreq_is_ondemand_policy(policy)) { + queue_delayed_work(freq_wq, &rk30_cpufreq_temp_limit_work, 0*HZ); + } + cpufreq_register_notifier(¬ifier_policy_block, CPUFREQ_POLICY_NOTIFIER); +#endif +#ifdef CPU_FREQ_DVFS_TST + queue_delayed_work(freq_wq, &rk30_cpufreq_dvsf_tst_work, msecs_to_jiffies(20 * 1000)); +#endif + } + //set freq min max + cpufreq_frequency_table_cpuinfo(policy, freq_table); + //sys nod + cpufreq_frequency_table_get_attr(freq_table, policy->cpu); + + policy->cur = rk30_getspeed(0); + + policy->cpuinfo.transition_latency = 40 * NSEC_PER_USEC; // make ondemand default sampling_rate to 40000 + + /* + * On rk30 SMP configuartion, both processors share the voltage + * and clock. So both CPUs needs to be scaled together and hence + * needs software co-ordination. Use cpufreq affected_cpus + * interface to handle this scenario. Additional is_smp() check + * is to keep SMP_ON_UP build working. + */ + if (is_smp()) + cpumask_setall(policy->cpus); + + return 0; +} + +static int rk30_cpu_exit(struct cpufreq_policy *policy) +{ + if (policy->cpu != 0) + return 0; + + cpufreq_frequency_table_cpuinfo(policy, freq_table); + clk_put(cpu_clk); +#ifdef CONFIG_RK30_CPU_FREQ_LIMIT_BY_TEMP + cpufreq_unregister_notifier(¬ifier_policy_block, CPUFREQ_POLICY_NOTIFIER); + if (freq_wq) + cancel_delayed_work(&rk30_cpufreq_temp_limit_work); +#endif + if (freq_wq) { + flush_workqueue(freq_wq); + destroy_workqueue(freq_wq); + freq_wq = NULL; + } + + return 0; +} + +static struct freq_attr *rk30_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +/**************************earlysuspend freeze cpu frequency******************************/ +static struct early_suspend ff_early_suspend; + +#define FILE_GOV_MODE "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor" +#define FILE_SETSPEED "/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed" +#define FILE_CUR_FREQ "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" + +#define FF_DEBUG(fmt, args...) printk(KERN_DEBUG "FREEZE FREQ DEBUG:\t"fmt, ##args) +#define FF_ERROR(fmt, args...) printk(KERN_ERR "FREEZE FREQ ERROR:\t"fmt, ##args) + +static int ff_read(char *file_path, char *buf) +{ + struct file *file = NULL; + mm_segment_t old_fs; + loff_t offset = 0; + + FF_DEBUG("read %s\n", file_path); + file = filp_open(file_path, O_RDONLY, 0); + + if (IS_ERR(file)) { + FF_ERROR("%s error open file %s\n", __func__, file_path); + return -1; + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + file->f_op->read(file, (char *)buf, 32, &offset); + sscanf(buf, "%s", buf); + + set_fs(old_fs); + filp_close(file, NULL); + + file = NULL; + + return 0; + +} + +static int ff_write(char *file_path, char *buf) +{ + struct file *file = NULL; + mm_segment_t old_fs; + loff_t offset = 0; + + FF_DEBUG("write %s %s size = %d\n", file_path, buf, strlen(buf)); + file = filp_open(file_path, O_RDWR, 0); + + if (IS_ERR(file)) { + FF_ERROR("%s error open file %s\n", __func__, file_path); + return -1; + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + file->f_op->write(file, (char *)buf, strlen(buf), &offset); + + set_fs(old_fs); + filp_close(file, NULL); + + file = NULL; + + return 0; + +} + +static void ff_scale_votlage(char *name, int volt) +{ + struct regulator* regulator; + int ret = 0; + + FF_DEBUG("enter %s\n", __func__); + regulator = dvfs_get_regulator(name); + if (!regulator) { + FF_ERROR("get regulator %s ERROR\n", name); + return ; + } + + ret = regulator_set_voltage(regulator, volt, volt); + if (ret != 0) { + FF_ERROR("set voltage error %s %d, ret = %d\n", name, volt, ret); + } + +} +int clk_set_parent_force(struct clk *clk, struct clk *parent); +static void ff_early_suspend_func(struct early_suspend *h) +{ + char buf[32]; + FF_DEBUG("enter %s\n", __func__); + if (ff_read(FILE_GOV_MODE, buf) != 0) { + FF_ERROR("read current governor error\n"); + return ; + } else { + FF_DEBUG("current governor = %s\n", buf); + } + + strcpy(buf, "userspace"); + if (ff_write(FILE_GOV_MODE, buf) != 0) { + FF_ERROR("set current governor error\n"); + return ; + } + + strcpy(buf, "252000"); + if (ff_write(FILE_SETSPEED, buf) != 0) { + FF_ERROR("set speed to 252MHz error\n"); + return ; + } + + if (!IS_ERR(cpu_pll)&&!IS_ERR(cpu_gpll)&&!IS_ERR(cpu_clk)) + { + clk_set_parent_force(cpu_clk,cpu_gpll); + clk_set_rate(cpu_clk,300*1000*1000); + + clk_disable_dvfs(cpu_clk); + } + if (!IS_ERR(gpu_clk)) + dvfs_clk_enable_limit(gpu_clk,75*1000*1000,133*1000*1000); + + //ff_scale_votlage("vdd_cpu", 1000000); + //ff_scale_votlage("vdd_core", 1000000); +#ifdef CONFIG_HOTPLUG_CPU + cpu_down(1); +#endif +} + +static void ff_early_resume_func(struct early_suspend *h) +{ + char buf[32]; + FF_DEBUG("enter %s\n", __func__); + + if (!IS_ERR(cpu_pll)&&!IS_ERR(cpu_gpll)&&!IS_ERR(cpu_clk)) + { + clk_set_parent_force(cpu_clk,cpu_pll); + clk_set_rate(cpu_clk,300*1000*1000); + clk_enable_dvfs(cpu_clk); + } + + if (!IS_ERR(gpu_clk)) + dvfs_clk_disable_limit(gpu_clk); +#ifdef CONFIG_HOTPLUG_CPU + cpu_up(1); +#endif + if (ff_read(FILE_GOV_MODE, buf) != 0) { + FF_ERROR("read current governor error\n"); + return ; + } else { + FF_DEBUG("current governor = %s\n", buf); + } + + if (ff_read(FILE_CUR_FREQ, buf) != 0) { + FF_ERROR("read current frequency error\n"); + return ; + } else { + FF_DEBUG("current frequency = %s\n", buf); + } + + strcpy(buf, "interactive"); + if (ff_write(FILE_GOV_MODE, buf) != 0) { + FF_ERROR("set current governor error\n"); + return ; + } + + strcpy(buf, "interactive"); + if (ff_write(FILE_GOV_MODE, buf) != 0) { + FF_ERROR("set current governor error\n"); + return ; + } +} + +static int __init ff_init(void) +{ + FF_DEBUG("enter %s\n", __func__); + ff_early_suspend.suspend = ff_early_suspend_func; + ff_early_suspend.resume = ff_early_resume_func; + ff_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 100; + register_early_suspend(&ff_early_suspend); + return 0; +} + +static void __exit ff_exit(void) +{ + FF_DEBUG("enter %s\n", __func__); + unregister_early_suspend(&ff_early_suspend); +} + + +/**************************target freq******************************/ +static unsigned int cpufreq_scale_limt(unsigned int target_freq, struct cpufreq_policy *policy) +{ + bool is_ondemand = rk30_cpufreq_is_ondemand_policy(policy); + static bool is_booting = true; + + if (is_ondemand && clk_get_rate(gpu_clk) > GPU_MAX_RATE) // high performance? + return max_freq; + if (is_ondemand && is_booting && target_freq >= 1600 * 1000) { + s64 boottime_ms = ktime_to_ms(ktime_get_boottime()); + if (boottime_ms > 30 * MSEC_PER_SEC) { + is_booting = false; + } else { + target_freq = 1416 * 1000; + } + } +#ifdef CONFIG_RK30_CPU_FREQ_LIMIT_BY_TEMP + if (is_ondemand && target_freq > policy->cur && policy->cur >= TEMP_LIMIT_FREQ) { + unsigned int i; + if (cpufreq_frequency_table_target(policy, freq_table, policy->cur + 1, CPUFREQ_RELATION_L, &i) == 0) { + unsigned int f = freq_table[i].frequency; + if (f < target_freq) { + target_freq = f; + } + } + } + /* + * If the new frequency is more than the thermal max allowed + * frequency, go ahead and scale the mpu device to proper frequency. + */ + if (is_ondemand) { + target_freq = min(target_freq, temp_limt_freq); + } +#endif +#ifdef CPU_FREQ_DVFS_TST + if (freq_dvfs_tst_rate) { + target_freq = freq_dvfs_tst_rate; + freq_dvfs_tst_rate = 0; + } +#endif + return target_freq; +} + +int cpufreq_scale_rate_for_dvfs(struct clk *clk, unsigned long rate, dvfs_set_rate_callback set_rate) +{ + unsigned int i; + int ret = -EINVAL; + struct cpufreq_freqs freqs; + + freqs.new = rate / 1000; + freqs.old = rk30_getspeed(0); + + for_each_online_cpu(freqs.cpu) { + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + } + FREQ_PRINTK_DBG("cpufreq_scale_rate_for_dvfs(%lu)\n", rate); + ret = set_rate(clk, rate); + +#ifdef CONFIG_SMP + /* + * Note that loops_per_jiffy is not updated on SMP systems in + * cpufreq driver. So, update the per-CPU loops_per_jiffy value + * on frequency transition. We need to update all dependent CPUs. + */ + for_each_possible_cpu(i) { + per_cpu(cpu_data, i).loops_per_jiffy = loops_per_jiffy; + } +#endif + + freqs.new = rk30_getspeed(0); + /* notifiers */ + for_each_online_cpu(freqs.cpu) { + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } + return ret; + +} + +static int rk30_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) +{ + unsigned int i, new_rate = 0; + int ret = 0; + + if (!freq_table) { + FREQ_PRINTK_ERR("no freq table!\n"); + return -EINVAL; + } + + mutex_lock(&cpufreq_mutex); + + if (relation & ENABLE_FURTHER_CPUFREQ) + no_cpufreq_access--; + if (no_cpufreq_access) { +#ifdef CONFIG_PM_VERBOSE + pr_err("denied access to %s as it is disabled temporarily\n", __func__); +#endif + ret = -EINVAL; + goto out; + } + if (relation & DISABLE_FURTHER_CPUFREQ) + no_cpufreq_access++; + relation &= ~MASK_FURTHER_CPUFREQ; + + ret = cpufreq_frequency_table_target(policy, freq_table, target_freq, relation, &i); + if (ret) { + FREQ_PRINTK_ERR("no freq match for %d(ret=%d)\n", target_freq, ret); + goto out; + } + new_rate = freq_table[i].frequency; + if (!no_cpufreq_access) + new_rate = cpufreq_scale_limt(new_rate, policy); + + FREQ_PRINTK_LOG("cpufreq req=%u,new=%u(was=%u)\n", target_freq, new_rate, rk30_getspeed(0)); + if (new_rate == rk30_getspeed(0)) + goto out; + ret = clk_set_rate(cpu_clk, new_rate * 1000); +out: + mutex_unlock(&cpufreq_mutex); + FREQ_PRINTK_DBG("cpureq set rate (%u) end\n", new_rate); + return ret; +} + +static int rk30_cpufreq_pm_notifier_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + int ret = NOTIFY_DONE; + struct cpufreq_policy *policy = cpufreq_cpu_get(0); + + if (!policy) + return ret; + + if (!rk30_cpufreq_is_ondemand_policy(policy)) + goto out; + + switch (event) { + case PM_SUSPEND_PREPARE: + ret = cpufreq_driver_target(policy, suspend_freq, DISABLE_FURTHER_CPUFREQ | CPUFREQ_RELATION_H); + if (ret < 0) { + ret = NOTIFY_BAD; + goto out; + } + ret = NOTIFY_OK; + break; + case PM_POST_RESTORE: + case PM_POST_SUSPEND: + cpufreq_driver_target(policy, suspend_freq, ENABLE_FURTHER_CPUFREQ | CPUFREQ_RELATION_H); + ret = NOTIFY_OK; + break; + } +out: + cpufreq_cpu_put(policy); + return ret; +} + +static struct notifier_block rk30_cpufreq_pm_notifier = { + .notifier_call = rk30_cpufreq_pm_notifier_event, +}; + +static int rk30_cpufreq_reboot_notifier_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct cpufreq_policy *policy = cpufreq_cpu_get(0); + + if (policy) { + cpufreq_driver_target(policy, suspend_freq, DISABLE_FURTHER_CPUFREQ | CPUFREQ_RELATION_H); + cpufreq_cpu_put(policy); + } + + return NOTIFY_OK; +} + +static struct notifier_block rk30_cpufreq_reboot_notifier = { + .notifier_call = rk30_cpufreq_reboot_notifier_event, +}; + +static struct cpufreq_driver rk30_cpufreq_driver = { + .flags = CPUFREQ_CONST_LOOPS, + .verify = rk30_verify_speed, + .target = rk30_target, + .get = rk30_getspeed, + .init = rk30_cpu_init, + .exit = rk30_cpu_exit, + .name = "rk30", + .attr = rk30_cpufreq_attr, +}; + +static int __init rk30_cpufreq_init(void) +{ + register_pm_notifier(&rk30_cpufreq_pm_notifier); + register_reboot_notifier(&rk30_cpufreq_reboot_notifier); + return cpufreq_register_driver(&rk30_cpufreq_driver); +} + +static void __exit rk30_cpufreq_exit(void) +{ + cpufreq_unregister_driver(&rk30_cpufreq_driver); +} + +MODULE_DESCRIPTION("cpufreq driver for rock chip rk30"); +MODULE_LICENSE("GPL"); +device_initcall(rk30_cpufreq_init); +module_exit(rk30_cpufreq_exit); diff --git a/arch/arm/mach-rk2928/dvfs.c b/arch/arm/mach-rk2928/dvfs.c new file mode 100644 index 000000000000..5e1111939953 --- /dev/null +++ b/arch/arm/mach-rk2928/dvfs.c @@ -0,0 +1,1923 @@ +/* arch/arm/mach-rk30/rk30_dvfs.c + * + * Copyright (C) 2012 ROCKCHIP, Inc. + * + * 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 +#include +#include +#include +#include +#include +#include +#include "clock.h" +#include +#include +#include +#include +#include +#include + +#if 1 +#define DVFS_DBG(fmt, args...) {while(0);} +#else +#define DVFS_DBG(fmt, args...) printk(KERN_DEBUG "DVFS DBG:\t"fmt, ##args) +#endif +#define DVFS_ERR(fmt, args...) printk(KERN_ERR "DVFS ERR:\t"fmt, ##args) +#define DVFS_LOG(fmt, args...) printk(KERN_DEBUG "DVFS LOG:\t"fmt, ##args) + +#define dvfs_regulator_get(dev,id) regulator_get((dev),(id)) +#define dvfs_regulator_put(regu) regulator_put((regu)) +#define dvfs_regulator_set_voltage(regu,min_uV,max_uV) regulator_set_voltage((regu),(min_uV),(max_uV)) +#define dvfs_regulator_get_voltage(regu) regulator_get_voltage((regu)) + +#define dvfs_clk_get(a,b) clk_get((a),(b)) +#define dvfs_clk_get_rate_kz(a) (clk_get_rate((a))/1000) +#define dvfs_clk_set_rate(a,b) clk_set_rate((a),(b)) +#define dvfs_clk_enable(a) clk_enable((a)) +#define dvfs_clk_disable(a) clk_disable((a)) + +#define DVFS_MHZ (1000*1000) +#define DVFS_KHZ (1000) + +#define DVFS_V (1000*1000) +#define DVFS_MV (1000) + +static LIST_HEAD(rk_dvfs_tree); +static DEFINE_MUTEX(mutex); +static DEFINE_MUTEX(rk_dvfs_mutex); + +extern int rk30_clk_notifier_register(struct clk *clk, struct notifier_block *nb); +extern int rk30_clk_notifier_unregister(struct clk *clk, struct notifier_block *nb); + +static int dump_dbg_map(char* buf); + +#define PD_ON 1 +#define PD_OFF 0 + +#define get_volt_up_delay(new_volt, old_volt) \ + ((new_volt) > (old_volt) ? (((new_volt) - (old_volt)) >> 9) : 0) + +int dvfs_regulator_set_voltage_readback(struct regulator *regulator, int min_uV, int max_uV) +{ + int ret = 0, read_back = 0; + ret = dvfs_regulator_set_voltage(regulator, max_uV, max_uV); + if (ret < 0) { + DVFS_ERR("%s now read back to check voltage\n", __func__); + + /* read back to judge if it is already effect */ + mdelay(2); + read_back = dvfs_regulator_get_voltage(regulator); + if (read_back == max_uV) { + DVFS_ERR("%s set ERROR but already effected, volt=%d\n", __func__, read_back); + ret = 0; + } else { + DVFS_ERR("%s set ERROR AND NOT effected, volt=%d\n", __func__, read_back); + } + } + return ret; +} + +struct regulator* dvfs_get_regulator(char *regulator_name) +{ + struct vd_node *vd; + list_for_each_entry(vd, &rk_dvfs_tree, node) { + if (strcmp(regulator_name, vd->regulator_name) == 0) { + return vd->regulator; + } + } + return NULL; +} + +int dvfs_clk_enable_limit(struct clk *clk, unsigned int min_rate, unsigned max_rate) +{ + struct clk_node* dvfs_clk; + dvfs_clk = clk->dvfs_info; + + dvfs_clk->freq_limit_en = 1; + dvfs_clk->min_rate = min_rate; + dvfs_clk->max_rate = max_rate; + + return 0; +} + +int dvfs_clk_disable_limit(struct clk *clk) +{ + struct clk_node* dvfs_clk; + dvfs_clk = clk->dvfs_info; + + dvfs_clk->freq_limit_en = 0; + + return 0; +} + +int is_support_dvfs(struct clk_node *dvfs_info) +{ + return (dvfs_info->vd && dvfs_info->vd->vd_dvfs_target && dvfs_info->enable_dvfs); +} + +int dvfs_set_rate(struct clk *clk, unsigned long rate) +{ + int ret = 0; + struct vd_node *vd; + DVFS_DBG("%s(%s(%lu))\n", __func__, clk->name, rate); + if (!clk->dvfs_info) { + DVFS_ERR("%s :This clk do not support dvfs!\n", __func__); + ret = -1; + } else { + vd = clk->dvfs_info->vd; + // mutex_lock(&vd->dvfs_mutex); + mutex_lock(&rk_dvfs_mutex); + ret = vd->vd_dvfs_target(clk, rate); + mutex_unlock(&rk_dvfs_mutex); + // mutex_unlock(&vd->dvfs_mutex); + } + DVFS_DBG("%s(%s(%lu)),is end\n", __func__, clk->name, rate); + return ret; +} + +static int dvfs_clk_get_ref_volt_depend(struct depend_list *depend, int rate_khz, + struct cpufreq_frequency_table *clk_fv) +{ + int i = 0; + if (rate_khz == 0 || !depend || !depend->dep_table) { + return -1; + } + clk_fv->frequency = rate_khz; + clk_fv->index = 0; + + for (i = 0; (depend->dep_table[i].frequency != CPUFREQ_TABLE_END); i++) { + if (depend->dep_table[i].frequency >= rate_khz) { + clk_fv->frequency = depend->dep_table[i].frequency; + clk_fv->index = depend->dep_table[i].index; + return 0; + } + } + clk_fv->frequency = 0; + clk_fv->index = 0; + return -1; +} +static int dvfs_clk_get_ref_volt(struct clk_node *dvfs_clk, int rate_khz, + struct cpufreq_frequency_table *clk_fv) +{ + int i = 0; + if (rate_khz == 0 || !dvfs_clk || !dvfs_clk->dvfs_table) { + /* since no need */ + return -1; + } + clk_fv->frequency = rate_khz; + clk_fv->index = 0; + + for (i = 0; (dvfs_clk->dvfs_table[i].frequency != CPUFREQ_TABLE_END); i++) { + if (dvfs_clk->dvfs_table[i].frequency >= rate_khz) { + clk_fv->frequency = dvfs_clk->dvfs_table[i].frequency; + clk_fv->index = dvfs_clk->dvfs_table[i].index; + // DVFS_DBG("%s,%s rate=%ukhz(vol=%d)\n",__func__,dvfs_clk->name, + // clk_fv->frequency, clk_fv->index); + return 0; + } + } + clk_fv->frequency = 0; + clk_fv->index = 0; + // DVFS_DBG("%s get corresponding voltage error! out of bound\n", dvfs_clk->name); + return -1; +} + +static int dvfs_pd_get_newvolt_byclk(struct pd_node *pd, struct clk_node *dvfs_clk) +{ + struct clk_list *child; + int volt_max = 0; + + if (!pd || !dvfs_clk) + return 0; + + if (dvfs_clk->set_volt >= pd->cur_volt) { + return dvfs_clk->set_volt; + } + + list_for_each_entry(child, &pd->clk_list, node) { + // DVFS_DBG("%s ,pd(%s),dvfs(%s),volt(%u)\n",__func__,pd->name, + // dvfs_clk->name,dvfs_clk->set_volt); + volt_max = max(volt_max, child->dvfs_clk->set_volt); + } + return volt_max; +} + +void dvfs_update_clk_pds_volt(struct clk_node *dvfs_clk) +{ + struct pd_node *pd; + int i; + if (!dvfs_clk) + return; + for (i = 0; (dvfs_clk->pds[i].pd != NULL); i++) { + pd = dvfs_clk->pds[i].pd; + // DVFS_DBG("%s dvfs(%s),pd(%s)\n",__func__,dvfs_clk->name,pd->name); + pd->cur_volt = dvfs_pd_get_newvolt_byclk(pd, dvfs_clk); + } +} + +static int dvfs_vd_get_newvolt_bypd(struct vd_node *vd) +{ + struct pd_node *pd; + struct depend_list *depend; + int volt_max_vd = 0; + list_for_each_entry(pd, &vd->pd_list, node) { + // DVFS_DBG("%s pd(%s,%u)\n",__func__,pd->name,pd->cur_volt); + volt_max_vd = max(volt_max_vd, pd->cur_volt); + } + + /* some clks depend on this voltage domain */ + if (!list_empty(&vd->req_volt_list)) { + list_for_each_entry(depend, &vd->req_volt_list, node2vd) { + volt_max_vd = max(volt_max_vd, depend->req_volt); + } + } + return volt_max_vd; +} + +static int dvfs_vd_get_newvolt_byclk(struct clk_node *dvfs_clk) +{ + if (!dvfs_clk) + return -1; + dvfs_update_clk_pds_volt(dvfs_clk); + return dvfs_vd_get_newvolt_bypd(dvfs_clk->vd); +} + +void dvfs_clk_register_set_rate_callback(struct clk *clk, clk_dvfs_target_callback clk_dvfs_target) +{ + struct clk_node *dvfs_clk = clk_get_dvfs_info(clk); + dvfs_clk->clk_dvfs_target = clk_dvfs_target; +} + +struct cpufreq_frequency_table *dvfs_get_freq_volt_table(struct clk *clk) +{ + struct clk_node *info = clk_get_dvfs_info(clk); + struct cpufreq_frequency_table *table; + if (!info || !info->dvfs_table) { + return NULL; + } + mutex_lock(&mutex); + table = info->dvfs_table; + mutex_unlock(&mutex); + return table; +} + +int dvfs_set_freq_volt_table(struct clk *clk, struct cpufreq_frequency_table *table) +{ + struct clk_node *info = clk_get_dvfs_info(clk); + if (!table || !info) + return -1; + + mutex_lock(&mutex); + info->dvfs_table = table; + mutex_unlock(&mutex); + return 0; +} + +int dvfs_set_depend_table(struct clk *clk, char *vd_name, struct cpufreq_frequency_table *table) +{ + struct vd_node *vd; + struct depend_list *depend; + struct clk_node *info; + + info = clk_get_dvfs_info(clk); + if (!table || !info || !vd_name) { + DVFS_ERR("%s :DVFS SET DEPEND TABLE ERROR! table or info or name empty\n", __func__); + return -1; + } + + list_for_each_entry(vd, &rk_dvfs_tree, node) { + if (0 == strcmp(vd->name, vd_name)) { + DVFS_DBG("FOUND A MATCH\n"); + mutex_lock(&mutex); + list_for_each_entry(depend, &info->depend_list, node2clk) { + if (vd == depend->dep_vd && info == depend->dvfs_clk) { + depend->dep_table = table; + break; + } + } + mutex_unlock(&mutex); + return 0; + } + } + DVFS_ERR("%s :DVFS SET DEPEND TABLE ERROR! can not find vd:%s\n", __func__, vd_name); + + return 0; +} + +int dvfs_set_arm_logic_volt(struct dvfs_arm_table *dvfs_cpu_logic_table, + struct cpufreq_frequency_table *cpu_dvfs_table, + struct cpufreq_frequency_table *dep_cpu2core_table) +{ + int i = 0; + for (i = 0; dvfs_cpu_logic_table[i].frequency != CPUFREQ_TABLE_END; i++) { + cpu_dvfs_table[i].frequency = dvfs_cpu_logic_table[i].frequency; + cpu_dvfs_table[i].index = dvfs_cpu_logic_table[i].cpu_volt; + + dep_cpu2core_table[i].frequency = dvfs_cpu_logic_table[i].frequency; + dep_cpu2core_table[i].index = dvfs_cpu_logic_table[i].logic_volt; + } + + cpu_dvfs_table[i].frequency = CPUFREQ_TABLE_END; + dep_cpu2core_table[i].frequency = CPUFREQ_TABLE_END; + + dvfs_set_freq_volt_table(clk_get(NULL, "cpu"), cpu_dvfs_table); + dvfs_set_depend_table(clk_get(NULL, "cpu"), "vd_core", dep_cpu2core_table); + return 0; +} + +int clk_enable_dvfs(struct clk *clk) +{ + struct clk_node *dvfs_clk; + struct cpufreq_frequency_table clk_fv; + if (!clk) { + DVFS_ERR("clk enable dvfs error\n"); + return -1; + } + dvfs_clk = clk_get_dvfs_info(clk); + if (!dvfs_clk || !dvfs_clk->vd) { + DVFS_ERR("%s clk(%s) not support dvfs!\n", __func__, clk->name); + return -1; + } + if (dvfs_clk->enable_dvfs == 0) { + + if (IS_ERR_OR_NULL(dvfs_clk->vd->regulator)) { + //regulator = NULL; + if (dvfs_clk->vd->regulator_name) + dvfs_clk->vd->regulator = dvfs_regulator_get(NULL, dvfs_clk->vd->regulator_name); + if (!IS_ERR_OR_NULL(dvfs_clk->vd->regulator)) { + // DVFS_DBG("dvfs_regulator_get(%s)\n",dvfs_clk->vd->regulator_name); + dvfs_clk->vd->cur_volt = dvfs_regulator_get_voltage(dvfs_clk->vd->regulator); + } else { + //dvfs_clk->vd->regulator = NULL; + dvfs_clk->enable_dvfs = 0; + DVFS_ERR("%s can't get regulator in %s\n", dvfs_clk->name, __func__); + return -1; + } + } else { + dvfs_clk->vd->cur_volt = dvfs_regulator_get_voltage(dvfs_clk->vd->regulator); + // DVFS_DBG("%s(%s) vd volt=%u\n",__func__,dvfs_clk->name,dvfs_clk->vd->cur_volt); + } + + dvfs_clk->set_freq = dvfs_clk_get_rate_kz(clk); + // DVFS_DBG("%s ,%s get freq%u!\n",__func__,dvfs_clk->name,dvfs_clk->set_freq); + + if (dvfs_clk_get_ref_volt(dvfs_clk, dvfs_clk->set_freq, &clk_fv)) { + if (dvfs_clk->dvfs_table[0].frequency == CPUFREQ_TABLE_END) { + DVFS_ERR("%s table empty\n", __func__); + dvfs_clk->enable_dvfs = 0; + return -1; + } else { + DVFS_ERR("WARNING: %s table all value are smaller than default, use default, just enable dvfs\n", __func__); + dvfs_clk->enable_dvfs++; + return 0; + } + } + + dvfs_clk->set_volt = clk_fv.index; + // DVFS_DBG("%s,%s,freq%u(ref vol %u)\n",__func__,dvfs_clk->name, + // dvfs_clk->set_freq,dvfs_clk->set_volt); +#if 0 + if (dvfs_clk->dvfs_nb) { + // must unregister when clk disable + rk30_clk_notifier_register(clk, dvfs_clk->dvfs_nb); + } +#endif + dvfs_vd_get_newvolt_byclk(dvfs_clk); + dvfs_clk->enable_dvfs++; + } else { + DVFS_ERR("dvfs already enable clk enable = %d!\n", dvfs_clk->enable_dvfs); + dvfs_clk->enable_dvfs++; + } + return 0; +} + +int clk_disable_dvfs(struct clk *clk) +{ + struct clk_node *dvfs_clk; + dvfs_clk = clk->dvfs_info; + if (!dvfs_clk->enable_dvfs) { + DVFS_DBG("clk is already closed!\n"); + return -1; + } else { + dvfs_clk->enable_dvfs--; + if (0 == dvfs_clk->enable_dvfs) { + DVFS_ERR("clk closed!\n"); + rk30_clk_notifier_unregister(clk, dvfs_clk->dvfs_nb); + DVFS_DBG("clk unregister nb!\n"); + } + } + return 0; +} + +static int rk_dvfs_clk_notifier_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct clk_notifier_data *noti_info; + struct clk *clk; + struct clk_node *dvfs_clk; + noti_info = (struct clk_notifier_data *)ptr; + clk = noti_info->clk; + dvfs_clk = clk->dvfs_info; + + switch (event) { + case CLK_PRE_RATE_CHANGE: + DVFS_DBG("%s CLK_PRE_RATE_CHANGE\n", __func__); + break; + case CLK_POST_RATE_CHANGE: + DVFS_DBG("%s CLK_POST_RATE_CHANGE\n", __func__); + break; + case CLK_ABORT_RATE_CHANGE: + DVFS_DBG("%s CLK_ABORT_RATE_CHANGE\n", __func__); + break; + case CLK_PRE_ENABLE: + DVFS_DBG("%s CLK_PRE_ENABLE\n", __func__); + break; + case CLK_POST_ENABLE: + DVFS_DBG("%s CLK_POST_ENABLE\n", __func__); + break; + case CLK_ABORT_ENABLE: + DVFS_DBG("%s CLK_ABORT_ENABLE\n", __func__); + break; + case CLK_PRE_DISABLE: + DVFS_DBG("%s CLK_PRE_DISABLE\n", __func__); + break; + case CLK_POST_DISABLE: + DVFS_DBG("%s CLK_POST_DISABLE\n", __func__); + dvfs_clk->set_freq = 0; + break; + case CLK_ABORT_DISABLE: + DVFS_DBG("%s CLK_ABORT_DISABLE\n", __func__); + + break; + default: + break; + } + return 0; +} + +static struct notifier_block rk_dvfs_clk_notifier = { + .notifier_call = rk_dvfs_clk_notifier_event, +}; + +static struct clk_node *dvfs_get_dvfs_clk_byname(char *name) +{ + struct vd_node *vd; + struct pd_node *pd; + struct clk_list *child; + list_for_each_entry(vd, &rk_dvfs_tree, node) { + list_for_each_entry(pd, &vd->pd_list, node) { + list_for_each_entry(child, &pd->clk_list, node) { + if (0 == strcmp(child->dvfs_clk->name, name)) { + return child->dvfs_clk; + } + } + } + } + return NULL; +} +static int rk_regist_vd(struct vd_node *vd) +{ + if (!vd) + return -1; + mutex_lock(&mutex); + //mutex_init(&vd->dvfs_mutex); + list_add(&vd->node, &rk_dvfs_tree); + INIT_LIST_HEAD(&vd->pd_list); + INIT_LIST_HEAD(&vd->req_volt_list); + + mutex_unlock(&mutex); + return 0; +} + +static int rk_regist_pd(struct pd_node_lookup *pd_lookup) +{ + struct vd_node *vd; + struct pd_node *pd; + + mutex_lock(&mutex); + pd = pd_lookup->pd; + + list_for_each_entry(vd, &rk_dvfs_tree, node) { + if (vd == pd->vd) { + list_add(&pd->node, &vd->pd_list); + INIT_LIST_HEAD(&pd->clk_list); + break; + } + } + mutex_unlock(&mutex); + return 0; +} + +static int rk_regist_clk(struct clk_node *dvfs_clk) +{ + struct pd_node *pd; + struct clk_list *child; + struct clk *clk; + int i = 0; + + if (!dvfs_clk) + return -1; + + if (!dvfs_clk->pds) + return -1; + mutex_lock(&mutex); + dvfs_clk->enable_dvfs = 0; + dvfs_clk->vd = dvfs_clk->pds[0].pd->vd; + for (i = 0; dvfs_clk->pds[i].pd != NULL; i++) { + child = &(dvfs_clk->pds[i].clk_list); + child->dvfs_clk = dvfs_clk; + pd = dvfs_clk->pds[i].pd; + list_add(&child->node, &pd->clk_list); + } + clk = dvfs_clk_get(NULL, dvfs_clk->name); + dvfs_clk->clk = clk; + clk_register_dvfs(dvfs_clk, clk); + INIT_LIST_HEAD(&dvfs_clk->depend_list); + mutex_unlock(&mutex); + return 0; +} + +static int rk_regist_depends(struct depend_lookup *dep_node) +{ + struct depend_list *depend_list; + struct clk_node *dvfs_clk; + + if (!dep_node) { + DVFS_ERR("%s : DVFS BAD depend node!\n", __func__); + return -1; + } + + if (!dep_node->clk_name || !dep_node->dep_vd) { + DVFS_ERR("%s : DVFS BAD depend members!\n", __func__); + return -1; + } + + depend_list = &dep_node->dep_list; + dvfs_clk = dvfs_get_dvfs_clk_byname(dep_node->clk_name); + + mutex_lock(&mutex); + + depend_list->dvfs_clk = dvfs_clk; + depend_list->dep_vd = dep_node->dep_vd; + depend_list->dep_table = dep_node->dep_table; + + list_add(&depend_list->node2clk, &dvfs_clk->depend_list); + list_add(&depend_list->node2vd, &depend_list->dep_vd->req_volt_list); + + mutex_unlock(&mutex); + return 0; +} +#if 0 +static int dvfs_set_depend_pre(struct clk_node *dvfs_clk, unsigned long rate_old, unsigned long rate_new) +{ + struct depend_list *depend; + struct cpufreq_frequency_table clk_fv; + int ret = -1; + int volt = 0; + struct regulator *regulator; + + if (rate_old >= rate_new) { + return 0; + } + list_for_each_entry(depend, &dvfs_clk->depend_list, node2clk) { + ret = dvfs_clk_get_ref_volt_depend(depend, rate_new / 1000, &clk_fv); + if (ret != 0) { + DVFS_ERR("%s LOGIC DVFS CAN NOT GET REF VOLT!, frequency too large!\n", __func__); + return -1; + } + + if (!depend->dep_vd->regulator) { + DVFS_DBG("%s regulator empty\n", __func__); + regulator = dvfs_regulator_get(NULL, depend->dep_vd->regulator_name); + if (!regulator) { + DVFS_ERR("%s get regulator err\n", __func__); + return -1; + } + + depend->dep_vd->regulator = regulator; + } + if (IS_ERR_OR_NULL(depend->dep_vd->regulator)) { + DVFS_ERR("%s vd's(%s) regulator not NULL but error\n", __func__, depend->dep_vd->name); + return -1; + } + + if (clk_fv.index == dvfs_regulator_get_voltage(depend->dep_vd->regulator)) { + depend->req_volt = clk_fv.index; + DVFS_DBG("%s same voltage\n", __func__); + return 0; + } + + depend->req_volt = clk_fv.index; + volt = dvfs_vd_get_newvolt_bypd(depend->dep_vd); + DVFS_DBG("%s setting voltage = %d\n", __func__, volt); + ret = dvfs_regulator_set_voltage_readback(depend->dep_vd->regulator, volt, volt); + if (0 != ret) { + DVFS_ERR("%s set voltage = %d ERROR, ret = %d\n", __func__, volt, ret); + return -1; + } + udelay(200); + DVFS_DBG("%s set voltage = %d OK, ret = %d\n", __func__, volt, ret); + if (ret != 0) { + DVFS_ERR("%s err, ret = %d\n", __func__, ret); + return -1; + } + } + + return 0; +} + +static int dvfs_set_depend_post(struct clk_node *dvfs_clk, unsigned long rate_old, unsigned long rate_new) +{ + struct depend_list *depend; + struct cpufreq_frequency_table clk_fv; + int ret = -1; + int volt = 0; + struct regulator *regulator; + + if (rate_old <= rate_new) + return 0; + list_for_each_entry(depend, &dvfs_clk->depend_list, node2clk) { + ret = dvfs_clk_get_ref_volt_depend(depend, rate_new / 1000, &clk_fv); + if (ret != 0) { + DVFS_ERR("%s LOGIC DVFS CAN NOT GET REF VOLT!, frequency too large!\n", __func__); + return -1; + } + + if (!depend->dep_vd->regulator) { + DVFS_DBG("%s regulator empty\n", __func__); + regulator = dvfs_regulator_get(NULL, depend->dep_vd->regulator_name); + if (!regulator) { + DVFS_ERR("%s get regulator err\n", __func__); + return -1; + } + + depend->dep_vd->regulator = regulator; + } + if (IS_ERR_OR_NULL(depend->dep_vd->regulator)) { + DVFS_ERR("%s vd's(%s) regulator not NULL but error\n", __func__, depend->dep_vd->name); + return -1; + } + + if (clk_fv.index == dvfs_regulator_get_voltage(depend->dep_vd->regulator)) { + depend->req_volt = clk_fv.index; + DVFS_DBG("%s same voltage\n", __func__); + return 0; + } + + depend->req_volt = clk_fv.index; + volt = dvfs_vd_get_newvolt_bypd(depend->dep_vd); + DVFS_DBG("%s setting voltage = %d\n", __func__, volt); + ret = dvfs_regulator_set_voltage_readback(depend->dep_vd->regulator, volt, volt); + if (0 != ret) { + DVFS_ERR("%s set voltage = %d ERROR, ret = %d\n", __func__, volt, ret); + return -1; + } + udelay(200); + DVFS_DBG("%s set voltage = %d OK, ret = %d\n", __func__, volt, ret); + if (ret != 0) { + DVFS_ERR("%s err, ret = %d\n", __func__, ret); + return -1; + } + } + + return 0; +} +#endif +#define DVFS_SET_VOLT_FAILURE 1 +#define DVFS_SET_VOLT_SUCCESS 0 +#define ARM_HIGHER_LOGIC (150 * 1000) +#define LOGIC_HIGHER_ARM (100 * 1000) + +int check_volt_correct(int volt_old, int *volt_new, int volt_dep_old, int *volt_dep_new, + int clk_biger_than_dep, int dep_biger_than_clk) +{ + int up_boundary = 0, low_boundary = 0; + DVFS_DBG("%d %d\n", clk_biger_than_dep, dep_biger_than_clk); + up_boundary = volt_old + dep_biger_than_clk; + low_boundary = volt_old - clk_biger_than_dep; + + if (volt_dep_old < low_boundary || volt_dep_old > up_boundary) { + DVFS_ERR("%s current volt out of bondary volt=%d(old=%d), volt_dep=%d(dep_old=%d), up_bnd=%d(dn=%d)\n", + __func__, *volt_new, volt_old, *volt_dep_new, volt_dep_old, up_boundary, low_boundary); + return -1; + } + + up_boundary = *volt_new + dep_biger_than_clk; + low_boundary = *volt_new - clk_biger_than_dep; + + if (*volt_dep_new < low_boundary || *volt_dep_new > up_boundary) { + + if (*volt_dep_new < low_boundary) { + *volt_dep_new = low_boundary; + + } else if (*volt_dep_new > up_boundary) { + *volt_new = *volt_dep_new - dep_biger_than_clk; + } + DVFS_LOG("%s target volt out of bondary volt=%d(old=%d), volt_dep=%d(dep_old=%d), up_bnd=%d(dn=%d)\n", + __func__, *volt_new, volt_old, *volt_dep_new, volt_dep_old, up_boundary, low_boundary); + return 0; + } + return 0; + +} +int dvfs_scale_volt(struct vd_node *vd_clk, struct vd_node *vd_dep, + int volt_old, int volt_new, int volt_dep_old, int volt_dep_new, int clk_biger_than_dep, int dep_biger_than_clk) +{ + struct regulator *regulator, *regulator_dep; + int volt = 0, volt_dep = 0, step = 0, step_dep = 0; + int volt_pre = 0, volt_dep_pre = 0; + int ret = 0; + + DVFS_DBG("ENTER %s, volt=%d(old=%d), volt_dep=%d(dep_old=%d)\n", __func__, volt_new, volt_old, volt_dep_new, volt_dep_old); + regulator = vd_clk->regulator; + regulator_dep = vd_dep->regulator; + + if (IS_ERR_OR_NULL(regulator) || IS_ERR(regulator_dep)) { + DVFS_ERR("%s dvfs_clk->vd->regulator or depend->dep_vd->regulator == NULL\n", __func__); + return -1; + } + + volt = volt_old; + volt_dep = volt_dep_old; + + step = volt_new - volt_old > 0 ? 1 : (-1); + step_dep = volt_dep_new - volt_dep_old > 0 ? 1 : (-1); + + DVFS_DBG("step=%d step_dep=%d %d\n", step, step_dep, step * step_dep); + + DVFS_DBG("Volt_new=%d(old=%d), volt_dep_new=%d(dep_old=%d)\n", + volt_new, volt_old, volt_dep_new, volt_dep_old); + do { + volt_pre = volt; + volt_dep_pre = volt_dep; + if (step * step_dep < 0) { + // target is between volt_old and volt_dep_old, just + // need one step + DVFS_DBG("step * step_dep < 0\n"); + volt = volt_new; + volt_dep = volt_dep_new; + + } else if (step > 0) { + // up voltage + DVFS_DBG("step > 0\n"); + + if (volt > volt_dep) { + if (volt_dep == volt_dep_new) { + volt = volt_dep + clk_biger_than_dep; + } else { + volt_dep = volt + dep_biger_than_clk; + } + } else { + if (volt == volt_new) { + volt_dep = volt + dep_biger_than_clk; + } else { + volt = volt_dep + clk_biger_than_dep; + } + } + volt = volt > volt_new ? volt_new : volt; + volt_dep = volt_dep > volt_dep_new ? volt_dep_new : volt_dep; + + } else if (step < 0) { + // down voltage + DVFS_DBG("step < 0\n"); + if (volt > volt_dep) { + if (volt == volt_new) { + volt_dep = volt - clk_biger_than_dep; + } else { + volt = volt_dep - dep_biger_than_clk; + } + } else { + if (volt_dep == volt_dep_new) { + volt = volt_dep - dep_biger_than_clk; + } else { + volt_dep = volt - clk_biger_than_dep; + } + } + volt = volt < volt_new ? volt_new : volt; + volt_dep = volt_dep < volt_dep_new ? volt_dep_new : volt_dep; + + } else { + DVFS_ERR("Oops, some bugs here:Volt_new=%d(old=%d), volt_dep_new=%d(dep_old=%d)\n", + volt_new, volt_old, volt_dep_new, volt_dep_old); + goto fail; + } + + DVFS_DBG("\t\tNOW:Volt=%d, volt_dep=%d\n", volt, volt_dep); + + if (vd_clk->cur_volt != volt) { + ret = dvfs_regulator_set_voltage_readback(regulator, volt, volt); + udelay(get_volt_up_delay(volt, volt_pre)); + if (ret < 0) { + DVFS_ERR("%s %s set voltage up err ret = %d, Vnew = %d(was %d)mV\n", + __func__, vd_clk->name, ret, volt_new, volt_old); + goto fail; + } + vd_clk->cur_volt = volt; + } + + if (vd_dep->cur_volt != volt_dep) { + ret = dvfs_regulator_set_voltage_readback(regulator_dep, volt_dep, volt_dep); + udelay(get_volt_up_delay(volt_dep, volt_dep_pre)); + if (ret < 0) { + DVFS_ERR("depend %s %s set voltage up err ret = %d, Vnew = %d(was %d)mV\n", + __func__, vd_dep->name, ret, volt_dep_new, volt_dep_old); + goto fail; + } + vd_dep->cur_volt = volt_dep; + } + + } while (volt != volt_new || volt_dep!= volt_dep_new); + + vd_clk->volt_set_flag = DVFS_SET_VOLT_SUCCESS; + vd_clk->cur_volt = volt_new; + + return 0; +fail: + DVFS_ERR("+++++++++++++++++FAIL AREA\n"); + vd_clk->cur_volt = volt_old; + vd_dep->cur_volt = volt_dep_old; + vd_clk->volt_set_flag = DVFS_SET_VOLT_FAILURE; + ret = dvfs_regulator_set_voltage_readback(regulator, volt_old, volt_old); + if (ret < 0) { + vd_clk->volt_set_flag = DVFS_SET_VOLT_FAILURE; + DVFS_ERR("%s %s set callback voltage err ret = %d, Vnew = %d(was %d)mV\n", + __func__, vd_clk->name, ret, volt_new, volt_old); + } + + ret = dvfs_regulator_set_voltage_readback(regulator_dep, volt_dep_old, volt_dep_old); + if (ret < 0) { + vd_dep->volt_set_flag = DVFS_SET_VOLT_FAILURE; + DVFS_ERR("%s %s set callback voltage err ret = %d, Vnew = %d(was %d)mV\n", + __func__, vd_dep->name, ret, volt_dep_new, volt_dep_old); + } + + return -1; +} + +int dvfs_scale_volt_direct(struct vd_node *vd_clk, int volt_new) +{ + int ret = 0; + DVFS_DBG("ENTER %s, volt=%d(old=%d)\n", __func__, volt_new, vd_clk->cur_volt); + if (IS_ERR_OR_NULL(vd_clk)) { + DVFS_ERR("%s vd_node error\n", __func__); + return -1; + } + + DVFS_DBG("ENTER %s, volt=%d(old=%d)\n", __func__, volt_new, vd_clk->cur_volt); + if (!IS_ERR_OR_NULL(vd_clk->regulator)) { + ret = dvfs_regulator_set_voltage_readback(vd_clk->regulator, volt_new, volt_new); + if (ret < 0) { + vd_clk->volt_set_flag = DVFS_SET_VOLT_FAILURE; + DVFS_ERR("%s %s set voltage up err ret = %d, Vnew = %d(was %d)mV\n", + __func__, vd_clk->name, ret, volt_new, vd_clk->cur_volt); + return -1; + } + + } else { + DVFS_ERR("%s up volt dvfs_clk->vd->regulator == NULL\n", __func__); + return -1; + } + + vd_clk->volt_set_flag = DVFS_SET_VOLT_SUCCESS; + vd_clk->cur_volt = volt_new; + + return 0; + +} + +int dvfs_scale_volt_bystep(struct vd_node *vd_clk, struct vd_node *vd_dep, int volt_new, int volt_dep_new, + int clk_biger_than_dep, int dep_biger_than_clk) + +{ + int ret = 0; + int volt_old = 0, volt_dep_old = 0; + + volt_old = vd_clk->cur_volt; + volt_dep_old = vd_dep->cur_volt; + + DVFS_DBG("ENTER %s, volt=%d(old=%d) vd_dep=%d(dep_old=%d)\n", __func__, + volt_new, volt_old, volt_dep_new, volt_dep_old); + + if (check_volt_correct(volt_old, &volt_new, volt_dep_old, &volt_dep_new, + clk_biger_than_dep, dep_biger_than_clk) < 0) { + DVFS_ERR("CURRENT VOLT INCORRECT, VD=%s, VD_DEP=%s\n", vd_clk->name, vd_dep->name); + return -1; + } + DVFS_DBG("ENTER %s, volt=%d(old=%d), volt_dep=%d(dep_old=%d)\n", __func__, + volt_new, volt_old, volt_dep_new, volt_dep_old); + ret = dvfs_scale_volt(vd_clk, vd_dep, volt_old, volt_new, volt_dep_old, volt_dep_new, + clk_biger_than_dep, dep_biger_than_clk); + if (ret < 0) { + vd_clk->volt_set_flag = DVFS_SET_VOLT_FAILURE; + DVFS_ERR("set volt error\n"); + return -1; + } + + return 0; +} + +int dvfs_reset_volt(struct vd_node *dvfs_vd) +{ + int flag_set_volt_correct = 0; + if (!IS_ERR_OR_NULL(dvfs_vd->regulator)) + flag_set_volt_correct = dvfs_regulator_get_voltage(dvfs_vd->regulator); + else { + DVFS_ERR("dvfs regulator is ERROR\n"); + return -1; + } + if (flag_set_volt_correct <= 0) { + DVFS_ERR("%s (clk:%s), try to reload arm_volt error %d!!! stop scaling\n", + __func__, dvfs_vd->name, flag_set_volt_correct); + return -1; + } + dvfs_vd->volt_set_flag = DVFS_SET_VOLT_SUCCESS; + DVFS_ERR("%s (clk:%s), try to reload arm_volt! arm_volt_correct = %d\n", + __func__, dvfs_vd->name, flag_set_volt_correct); + + /* Reset vd's voltage */ + dvfs_vd->cur_volt = flag_set_volt_correct; + + return dvfs_vd->cur_volt; +} + +int dvfs_get_depend_volt(struct clk_node *dvfs_clk, struct vd_node *dvfs_vd_dep, int rate_new) +{ + struct depend_list *depend; + struct cpufreq_frequency_table clk_fv_dep; + int ret = 0; + + DVFS_DBG("ENTER %s, rate_new=%d\n", __func__, rate_new); + list_for_each_entry(depend, &dvfs_clk->depend_list, node2clk) { + DVFS_DBG("--round depend clk:%s(depend:%s)\n", depend->dvfs_clk->name, depend->dep_vd->name); + // this place just consider ONE depend voltage domain, + // multi-depends must have some differece + clk_fv_dep.index = 0; + if (depend->dep_vd == dvfs_vd_dep) { + ret = dvfs_clk_get_ref_volt_depend(depend, rate_new / 1000, &clk_fv_dep); + if (ret < 0) { + DVFS_ERR("%s get dvfs_ref_volt_depend error\n", __func__); + return -1; + } + depend->req_volt = clk_fv_dep.index; + return depend->req_volt; + } + } + + DVFS_ERR("%s can not find vd node %s\n", __func__, dvfs_vd_dep->name); + return -1; +} +static struct clk_node *dvfs_clk_cpu; +static struct vd_node vd_core; +int dvfs_target_cpu(struct clk *clk, unsigned long rate_hz) +{ + struct clk_node *dvfs_clk; + int volt_new = 0, volt_dep_new = 0, clk_volt_store = 0; + struct cpufreq_frequency_table clk_fv; + int ret = 0; + unsigned long rate_new, rate_old; + + if (!clk) { + DVFS_ERR("%s is not a clk\n", __func__); + return -1; + } + dvfs_clk = clk_get_dvfs_info(clk); + DVFS_DBG("enter %s: clk(%s) rate = %lu Hz\n", __func__, dvfs_clk->name, rate_hz); + + if (!dvfs_clk || dvfs_clk->vd == NULL || IS_ERR_OR_NULL(dvfs_clk->vd->regulator)) { + DVFS_ERR("dvfs(%s) is not register regulator\n", dvfs_clk->name); + return -1; + } + + if (dvfs_clk->vd->volt_set_flag == DVFS_SET_VOLT_FAILURE) { + /* It means the last time set voltage error */ + ret = dvfs_reset_volt(dvfs_clk->vd); + if (ret < 0) { + return -1; + } + } + + /* Check limit rate */ + if (dvfs_clk->freq_limit_en) { + if (rate_hz < dvfs_clk->min_rate) { + rate_hz = dvfs_clk->min_rate; + } else if (rate_hz > dvfs_clk->max_rate) { + rate_hz = dvfs_clk->max_rate; + } + } + + /* need round rate */ + rate_old = clk_get_rate(clk); + rate_new = clk_round_rate_nolock(clk, rate_hz); + DVFS_DBG("dvfs(%s) round rate (%lu)(rount %lu) old (%lu)\n", + dvfs_clk->name, rate_hz, rate_new, rate_old); + + /* find the clk corresponding voltage */ + if (0 != dvfs_clk_get_ref_volt(dvfs_clk, rate_new / 1000, &clk_fv)) { + DVFS_ERR("dvfs(%s) rate %luhz is larger,not support\n", dvfs_clk->name, rate_hz); + return -1; + } + clk_volt_store = dvfs_clk->set_volt; + dvfs_clk->set_volt = clk_fv.index; + volt_new = dvfs_vd_get_newvolt_byclk(dvfs_clk); + + /* if up the rate */ + if (rate_new > rate_old) { + if (!list_empty(&dvfs_clk->depend_list)) { + // update depend's req_volt + ret = dvfs_get_depend_volt(dvfs_clk, &vd_core, rate_new); + if (ret <= 0) + goto fail_roll_back; + + volt_dep_new = dvfs_vd_get_newvolt_bypd(&vd_core); + if (volt_dep_new <= 0) + goto fail_roll_back; + ret = dvfs_scale_volt_direct(dvfs_clk->vd, volt_new); + + //ret = dvfs_scale_volt_bystep(dvfs_clk->vd, &vd_core, volt_new, volt_dep_new, + // ARM_HIGHER_LOGIC, LOGIC_HIGHER_ARM); + if (ret < 0) + goto fail_roll_back; + } else { + ret = dvfs_scale_volt_direct(dvfs_clk->vd, volt_new); + if (ret < 0) + goto fail_roll_back; + } + } + + /* scale rate */ + if (dvfs_clk->clk_dvfs_target) { + ret = dvfs_clk->clk_dvfs_target(clk, rate_new, clk_set_rate_locked); + } else { + ret = clk_set_rate_locked(clk, rate_new); + } + + if (ret < 0) { + DVFS_ERR("%s set rate err\n", __func__); + goto fail_roll_back; + } + dvfs_clk->set_freq = rate_new / 1000; + + DVFS_DBG("dvfs %s set rate %lu ok\n", dvfs_clk->name, clk_get_rate(clk)); + + /* if down the rate */ + if (rate_new < rate_old) { + if (!list_empty(&dvfs_clk->depend_list)) { + // update depend's req_volt + ret = dvfs_get_depend_volt(dvfs_clk, &vd_core, rate_new); + if (ret <= 0) + goto out; + + volt_dep_new = dvfs_vd_get_newvolt_bypd(&vd_core); + if (volt_dep_new <= 0) + goto out; + ret = dvfs_scale_volt_direct(dvfs_clk->vd, volt_new); + + //ret = dvfs_scale_volt_bystep(dvfs_clk->vd, &vd_core, volt_new, volt_dep_new, + // ARM_HIGHER_LOGIC, LOGIC_HIGHER_ARM); + if (ret < 0) + goto out; + } else { + ret = dvfs_scale_volt_direct(dvfs_clk->vd, volt_new); + if (ret < 0) + goto out; + } + } + + return ret; +fail_roll_back: + dvfs_clk->set_volt = clk_volt_store; + ret = dvfs_get_depend_volt(dvfs_clk, &vd_core, rate_old); + if (ret <= 0) { + DVFS_ERR("%s dvfs_get_depend_volt error when roll back!\n", __func__); + } +out: + return -1; +} + +int dvfs_target_core(struct clk *clk, unsigned long rate_hz) +{ + struct clk_node *dvfs_clk; + int volt_new = 0, volt_dep_new = 0, clk_volt_store = 0; + + struct cpufreq_frequency_table clk_fv; + + int ret = 0; + unsigned long rate_new, rate_old; + + if (!clk) { + DVFS_ERR("%s is not a clk\n", __func__); + return -1; + } + dvfs_clk = clk_get_dvfs_info(clk); + DVFS_DBG("enter %s: clk(%s) rate = %lu Hz\n", __func__, dvfs_clk->name, rate_hz); + + if (!dvfs_clk || dvfs_clk->vd == NULL || IS_ERR_OR_NULL(dvfs_clk->vd->regulator)) { + DVFS_ERR("dvfs(%s) is not register regulator\n", dvfs_clk->name); + return -1; + } + + if (dvfs_clk->vd->volt_set_flag == DVFS_SET_VOLT_FAILURE) { + /* It means the last time set voltage error */ + ret = dvfs_reset_volt(dvfs_clk->vd); + if (ret < 0) { + return -1; + } + } + + /* Check limit rate */ + if (dvfs_clk->freq_limit_en) { + if (rate_hz < dvfs_clk->min_rate) { + rate_hz = dvfs_clk->min_rate; + } else if (rate_hz > dvfs_clk->max_rate) { + rate_hz = dvfs_clk->max_rate; + } + } + + /* need round rate */ + rate_old = clk_get_rate(clk); + rate_new = clk_round_rate_nolock(clk, rate_hz); + DVFS_DBG("dvfs(%s) round rate (%lu)(rount %lu) old (%lu)\n", + dvfs_clk->name, rate_hz, rate_new, rate_old); + + /* find the clk corresponding voltage */ + if (0 != dvfs_clk_get_ref_volt(dvfs_clk, rate_new / 1000, &clk_fv)) { + DVFS_ERR("dvfs(%s) rate %luhz is larger,not support\n", dvfs_clk->name, rate_hz); + return -1; + } + clk_volt_store = dvfs_clk->set_volt; + dvfs_clk->set_volt = clk_fv.index; + volt_new = dvfs_vd_get_newvolt_byclk(dvfs_clk); + + /* if up the rate */ + if (rate_new > rate_old) { + DVFS_DBG("-----------------------------rate_new > rate_old\n"); + volt_dep_new = dvfs_vd_get_newvolt_byclk(dvfs_clk_cpu); + + if (volt_dep_new < 0) + goto fail_roll_back; + + ret = dvfs_scale_volt_bystep(dvfs_clk->vd, dvfs_clk_cpu->vd, volt_new, volt_dep_new, + LOGIC_HIGHER_ARM, ARM_HIGHER_LOGIC); + if (ret < 0) + goto fail_roll_back; + } + + /* scale rate */ + if (dvfs_clk->clk_dvfs_target) { + ret = dvfs_clk->clk_dvfs_target(clk, rate_new, clk_set_rate_locked); + } else { + + ret = clk_set_rate_locked(clk, rate_new); + } + + if (ret < 0) { + DVFS_ERR("%s set rate err\n", __func__); + goto fail_roll_back; + } + dvfs_clk->set_freq = rate_new / 1000; + + DVFS_DBG("dvfs %s set rate %lu ok\n", dvfs_clk->name, clk_get_rate(clk)); + + /* if down the rate */ + if (rate_new < rate_old) { + DVFS_DBG("-----------------------------rate_new < rate_old\n"); + volt_dep_new = dvfs_vd_get_newvolt_byclk(dvfs_clk_cpu); + + if (volt_dep_new < 0) + goto out; + + ret = dvfs_scale_volt_bystep(dvfs_clk->vd, dvfs_clk_cpu->vd, volt_new, volt_dep_new, + LOGIC_HIGHER_ARM, ARM_HIGHER_LOGIC); + if (ret < 0) + goto out; + } + + return ret; +fail_roll_back: + dvfs_clk->set_volt = clk_volt_store; + ret = dvfs_get_depend_volt(dvfs_clk, &vd_core, rate_old); + if (ret <= 0) { + DVFS_ERR("%s dvfs_get_depend_volt error when roll back!\n", __func__); + } + +out: + return -1; +} + +/*****************************init**************************/ +/** + * rate must be raising sequence + */ +static struct cpufreq_frequency_table cpu_dvfs_table[] = { + // {.frequency = 48 * DVFS_KHZ, .index = 920*DVFS_MV}, + // {.frequency = 126 * DVFS_KHZ, .index = 970 * DVFS_MV}, + // {.frequency = 252 * DVFS_KHZ, .index = 1040 * DVFS_MV}, + // {.frequency = 504 * DVFS_KHZ, .index = 1050 * DVFS_MV}, + {.frequency = 816 * DVFS_KHZ, .index = 1050 * DVFS_MV}, + // {.frequency = 1008 * DVFS_KHZ, .index = 1100 * DVFS_MV}, + {.frequency = CPUFREQ_TABLE_END}, +}; + +static struct cpufreq_frequency_table ddr_dvfs_table[] = { + // {.frequency = 100 * DVFS_KHZ, .index = 1100 * DVFS_MV}, + {.frequency = 200 * DVFS_KHZ, .index = 1000 * DVFS_MV}, + {.frequency = 300 * DVFS_KHZ, .index = 1050 * DVFS_MV}, + {.frequency = 400 * DVFS_KHZ, .index = 1100 * DVFS_MV}, + {.frequency = 500 * DVFS_KHZ, .index = 1150 * DVFS_MV}, + {.frequency = 600 * DVFS_KHZ, .index = 1200 * DVFS_MV}, + {.frequency = CPUFREQ_TABLE_END}, +}; + +static struct cpufreq_frequency_table gpu_dvfs_table[] = { + {.frequency = 90 * DVFS_KHZ, .index = 1100 * DVFS_MV}, + {.frequency = 180 * DVFS_KHZ, .index = 1150 * DVFS_MV}, + {.frequency = 300 * DVFS_KHZ, .index = 1100 * DVFS_MV}, + {.frequency = 400 * DVFS_KHZ, .index = 1150 * DVFS_MV}, + {.frequency = 500 * DVFS_KHZ, .index = 1200 * DVFS_MV}, + {.frequency = CPUFREQ_TABLE_END}, +}; + +static struct cpufreq_frequency_table peri_aclk_dvfs_table[] = { + {.frequency = 100 * DVFS_KHZ, .index = 1000 * DVFS_MV}, + {.frequency = 200 * DVFS_KHZ, .index = 1050 * DVFS_MV}, + {.frequency = 300 * DVFS_KHZ, .index = 1070 * DVFS_MV}, + {.frequency = 500 * DVFS_KHZ, .index = 1100 * DVFS_MV}, + {.frequency = CPUFREQ_TABLE_END}, +}; + +static struct cpufreq_frequency_table dep_cpu2core_table[] = { + // {.frequency = 252 * DVFS_KHZ, .index = 1025 * DVFS_MV}, + // {.frequency = 504 * DVFS_KHZ, .index = 1025 * DVFS_MV}, + {.frequency = 816 * DVFS_KHZ, .index = 1050 * DVFS_MV},//logic 1.050V + // {.frequency = 1008 * DVFS_KHZ,.index = 1050 * DVFS_MV}, + // {.frequency = 1200 * DVFS_KHZ,.index = 1050 * DVFS_MV}, + // {.frequency = 1272 * DVFS_KHZ,.index = 1050 * DVFS_MV},//logic 1.050V + // {.frequency = 1416 * DVFS_KHZ,.index = 1100 * DVFS_MV},//logic 1.100V + // {.frequency = 1512 * DVFS_KHZ,.index = 1125 * DVFS_MV},//logic 1.125V + // {.frequency = 1608 * DVFS_KHZ,.index = 1175 * DVFS_MV},//logic 1.175V + {.frequency = CPUFREQ_TABLE_END}, +}; + +static struct vd_node vd_cpu = { + .name = "vd_cpu", + .regulator_name = "vdd_cpu", + .vd_dvfs_target = dvfs_target_cpu, +}; + +static struct vd_node vd_core = { + .name = "vd_core", + .regulator_name = "vdd_core", + .vd_dvfs_target = dvfs_target_core, +}; + +static struct vd_node vd_rtc = { + .name = "vd_rtc", + .regulator_name = "vdd_rtc", + .vd_dvfs_target = NULL, +}; + +static struct vd_node *rk30_vds[] = {&vd_cpu, &vd_core, &vd_rtc}; + +static struct pd_node pd_a9_0 = { + .name = "pd_a9_0", + .vd = &vd_cpu, +}; +static struct pd_node pd_a9_1 = { + .name = "pd_a9_1", + .vd = &vd_cpu, +}; +static struct pd_node pd_debug = { + .name = "pd_debug", + .vd = &vd_cpu, +}; +static struct pd_node pd_scu = { + .name = "pd_scu", + .vd = &vd_cpu, +}; +static struct pd_node pd_video = { + .name = "pd_video", + .vd = &vd_core, +}; +static struct pd_node pd_vio = { + .name = "pd_vio", + .vd = &vd_core, +}; +static struct pd_node pd_gpu = { + .name = "pd_gpu", + .vd = &vd_core, +}; +static struct pd_node pd_peri = { + .name = "pd_peri", + .vd = &vd_core, +}; +static struct pd_node pd_cpu = { + .name = "pd_cpu", + .vd = &vd_core, +}; +static struct pd_node pd_alive = { + .name = "pd_alive", + .vd = &vd_core, +}; +static struct pd_node pd_rtc = { + .name = "pd_rtc", + .vd = &vd_rtc, +}; +#define LOOKUP_PD(_ppd) \ +{ \ + .pd = _ppd, \ +} +static struct pd_node_lookup rk30_pds[] = { + LOOKUP_PD(&pd_a9_0), + LOOKUP_PD(&pd_a9_1), + LOOKUP_PD(&pd_debug), + LOOKUP_PD(&pd_scu), + LOOKUP_PD(&pd_video), + LOOKUP_PD(&pd_vio), + LOOKUP_PD(&pd_gpu), + LOOKUP_PD(&pd_peri), + LOOKUP_PD(&pd_cpu), + LOOKUP_PD(&pd_alive), + LOOKUP_PD(&pd_rtc), +}; + +#define CLK_PDS(_ppd) \ +{ \ + .pd = _ppd, \ +} + +static struct pds_list cpu_pds[] = { + CLK_PDS(&pd_a9_0), + CLK_PDS(&pd_a9_1), + CLK_PDS(NULL), +}; + +static struct pds_list ddr_pds[] = { + CLK_PDS(&pd_cpu), + CLK_PDS(NULL), +}; + +static struct pds_list gpu_pds[] = { + CLK_PDS(&pd_gpu), + CLK_PDS(NULL), +}; + +static struct pds_list aclk_periph_pds[] = { + CLK_PDS(&pd_peri), + CLK_PDS(NULL), +}; + +#define RK_CLKS(_clk_name, _ppds, _dvfs_table, _dvfs_nb) \ +{ \ + .name = _clk_name, \ + .pds = _ppds,\ + .dvfs_table = _dvfs_table, \ + .dvfs_nb = _dvfs_nb, \ +} + +static struct clk_node rk30_clks[] = { + RK_CLKS("cpu", cpu_pds, cpu_dvfs_table, &rk_dvfs_clk_notifier), + //RK_CLKS("ddr", ddr_pds, ddr_dvfs_table, &rk_dvfs_clk_notifier), + RK_CLKS("gpu", gpu_pds, gpu_dvfs_table, &rk_dvfs_clk_notifier), + //RK_CLKS("aclk_periph", aclk_periph_pds, peri_aclk_dvfs_table, &rk_dvfs_clk_notifier), +}; + +#define RK_DEPPENDS(_clk_name, _pvd, _dep_table) \ +{ \ + .clk_name = _clk_name, \ + .dep_vd = _pvd,\ + .dep_table = _dep_table, \ +} + +static struct depend_lookup rk30_depends[] = { + RK_DEPPENDS("cpu", &vd_core, dep_cpu2core_table), + //RK_DEPPENDS("gpu", &vd_cpu, NULL), + //RK_DEPPENDS("gpu", &vd_cpu, NULL), +}; + +int rk30_dvfs_init(void) +{ + int i = 0; + for (i = 0; i < ARRAY_SIZE(rk30_vds); i++) { + rk_regist_vd(rk30_vds[i]); + } + for (i = 0; i < ARRAY_SIZE(rk30_pds); i++) { + rk_regist_pd(&rk30_pds[i]); + } + for (i = 0; i < ARRAY_SIZE(rk30_clks); i++) { + rk_regist_clk(&rk30_clks[i]); + } + for (i = 0; i < ARRAY_SIZE(rk30_depends); i++) { + rk_regist_depends(&rk30_depends[i]); + } + dvfs_clk_cpu = dvfs_get_dvfs_clk_byname("cpu"); + return 0; +} + +/*******************************AVS AREA****************************************/ +/* + * To use AVS function, you must call avs_init in machine_rk30_board_init(void)(board-rk30-sdk.c) + * And then call(vdd_log): + * regulator_set_voltage(dcdc, 1100000, 1100000); + * avs_init_val_get(1,1100000,"wm8326 init"); + * udelay(600); + * avs_set_scal_val(AVS_BASE); + * in wm831x_post_init(board-rk30-sdk-wm8326.c) + * AVS_BASE can use 172 + */ + +static int avs_scale_volt = 0; +static int avs_get_scal_val(int vol); + +int dvfs_avs_scale_table(struct clk *clk, char *depend_vd_name) +{ + /* if depend_vd_name == NULL scale clk table + * else scale clk's depend table, named depend_vd_name + * */ + struct vd_node *vd; + struct depend_list *depend; + struct clk_node *info = clk_get_dvfs_info(clk); + struct cpufreq_frequency_table *table = NULL; + int i; + + if (NULL == depend_vd_name) { + table = info->dvfs_table; + } else { + list_for_each_entry(vd, &rk_dvfs_tree, node) { + if (0 == strcmp(vd->name, depend_vd_name)) { + DVFS_DBG("%s FOUND A MATCH vd\n", __func__); + mutex_lock(&mutex); + list_for_each_entry(depend, &info->depend_list, node2clk) { + if (vd == depend->dep_vd && info == depend->dvfs_clk) { + DVFS_DBG("%s FOUND A MATCH table\n", __func__); + table = depend->dep_table; + break; + } + } + mutex_unlock(&mutex); + } + } + } + + if (table == NULL) { + DVFS_ERR("%s can not find match table\n", __func__); + return -1; + } + if (avs_scale_volt != 0) { + DVFS_DBG("AVS scale %s, depend name = %s, voltage = %d\n", + info->name, depend_vd_name, avs_scale_volt); + for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { + table[i].index = avs_get_scal_val(table[i].index); + } + } + return 0; +} + +static void __iomem *rk30_nandc_base; + +#define nandc_readl(offset) readl_relaxed(rk30_nandc_base + offset) +#define nandc_writel(v, offset) do { writel_relaxed(v, rk30_nandc_base + offset); dsb(); } while (0) +static u8 rk30_get_avs_val(void) +{ + u32 nanc_save_reg[4]; + unsigned long flags; + u32 paramet = 0; + u32 count = 100; + preempt_disable(); + local_irq_save(flags); + + nanc_save_reg[0] = nandc_readl(0); + nanc_save_reg[1] = nandc_readl(0x130); + nanc_save_reg[2] = nandc_readl(0x134); + nanc_save_reg[3] = nandc_readl(0x158); + + nandc_writel(nanc_save_reg[0] | 0x1 << 14, 0); + nandc_writel(0x5, 0x130); + + nandc_writel(7, 0x158); + nandc_writel(1, 0x134); + + while(count--) { + paramet = nandc_readl(0x138); + if((paramet & 0x1)) + break; + udelay(1); + }; + paramet = (paramet >> 1) & 0xff; + nandc_writel(nanc_save_reg[0], 0); + nandc_writel(nanc_save_reg[1], 0x130); + nandc_writel(nanc_save_reg[2], 0x134); + nandc_writel(nanc_save_reg[3], 0x158); + + local_irq_restore(flags); + preempt_enable(); + return (u8)paramet; + +} +#define init_avs_times 10 +#define init_avs_st_num 5 + +struct init_avs_st { + int is_set; + u8 paramet[init_avs_times]; + int vol; + char *s; +}; + +static struct init_avs_st init_avs_paramet[init_avs_st_num]; + +void avs_init_val_get(int index, int vol, char *s) +{ + int i; + if(index >= init_avs_times) + return; + init_avs_paramet[index].vol = vol; + init_avs_paramet[index].s = s; + init_avs_paramet[index].is_set++; + for(i = 0; i < init_avs_times; i++) { + init_avs_paramet[index].paramet[i] = rk30_get_avs_val(); + mdelay(1); + } +} + +void avs_init(void) +{ + memset(&init_avs_paramet[0].is_set, 0, sizeof(init_avs_paramet)); + rk30_nandc_base = ioremap(RK2928_NANDC_PHYS, RK2928_NANDC_SIZE); + //avs_init_val_get(0,1150000,"board_init"); +} + +#define VOL_DYN_STEP (12500) //mv +#define AVS_VAL_PER_STEP (4) //mv + +static u8 avs_init_get_min_val(void) +{ + int i, j; + u8 min_avs = 0xff; + for(i = 0; i < init_avs_st_num; i++) { + if(init_avs_paramet[i].is_set && init_avs_paramet[i].vol == (1100 * 1000)) { + for(j = 0; j < init_avs_times; j++) + min_avs = (u8)min(min_avs, init_avs_paramet[i].paramet[j]); + } + + } + return min_avs; +} + +static int avs_get_scal_val(int vol) +{ + vol += avs_scale_volt; + if(vol < 1000 * 1000) + vol = 1000 * 1000; + if(vol > 1400 * 1000) + vol = 1400 * 1000; + return vol; +} +#if 0 +u8 avs_test_date[] = {172, 175, 176, 179, 171, 168, 165, 162, 199, 0}; +u8 avs_test_date_cunt = 0; +#endif +int avs_set_scal_val(u8 avs_base) +{ + u8 avs_test = avs_init_get_min_val(); + s8 step = 0; + + if (avs_base < avs_test) { + DVFS_DBG("AVS down voltage, ignore\n"); + return 0; + } + step = (avs_base - avs_test) / AVS_VAL_PER_STEP; + step = (avs_base > avs_test) ? (step + 1) : step; + if (step > 2) + step += 1; + avs_scale_volt = (step) * (VOL_DYN_STEP); + + DVFS_DBG("avs_set_scal_val test=%d,base=%d,step=%d,scale_vol=%d\n", + avs_test, avs_base, step, avs_scale_volt); + return 0; +} + +/*************************interface to get avs value and dvfs tree*************************/ +#define USE_NORMAL_TIME +#ifdef USE_NORMAL_TIME +static struct timer_list avs_timer; +#else +static struct hrtimer dvfs_hrtimer; +#endif + +static u32 avs_dyn_start = 0; +static u32 avs_dyn_data_cnt; +static u8 *avs_dyn_data = NULL; +static u32 show_line_cnt = 0; +static u8 dly_min; +static u8 dly_max; + +#define val_per_line (30) +#define line_pre_show (30) +#define avs_dyn_data_num (3*1000*1000) + +static u32 print_avs_init(char *buf) +{ + char *s = buf; + int i, j; + + for(j = 0; j < init_avs_st_num; j++) { + if(init_avs_paramet[j].vol <= 0) + continue; + s += sprintf(s, "%s ,vol=%d,paramet following\n", + init_avs_paramet[j].s, init_avs_paramet[j].vol); + for(i = 0; i < init_avs_times; i++) { + s += sprintf(s, "%d ", init_avs_paramet[j].paramet[i]); + } + + s += sprintf(s, "\n"); + } + return (s - buf); +} + +static ssize_t avs_init_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + return print_avs_init(buf); +} + +static ssize_t avs_init_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n) +{ + + return n; +} +static ssize_t avs_now_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", rk30_get_avs_val()); +} + +static ssize_t avs_now_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n) +{ + return n; +} +static ssize_t avs_dyn_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + char *s = buf; + u32 i; + + if(avs_dyn_start) { + int start_cnt; + int end_cnt; + end_cnt = (avs_dyn_data_cnt ? (avs_dyn_data_cnt - 1) : 0); + if(end_cnt > (line_pre_show * val_per_line)) + start_cnt = end_cnt - (line_pre_show * val_per_line); + else + start_cnt = 0; + + dly_min = avs_dyn_data[start_cnt]; + dly_max = avs_dyn_data[start_cnt]; + + //s += sprintf(s,"data start=%d\n",i); + for(i = start_cnt; i <= end_cnt;) { + s += sprintf(s, "%d", avs_dyn_data[i]); + dly_min = min(dly_min, avs_dyn_data[i]); + dly_max = max(dly_max, avs_dyn_data[i]); + i++; + if(!(i % val_per_line)) { + s += sprintf(s, "\n"); + } else + s += sprintf(s, " "); + } + + s += sprintf(s, "\n"); + + s += sprintf(s, "new data is from=%d to %d\n", start_cnt, end_cnt); + //s += sprintf(s,"\n max=%d,min=%d,totolcnt=%d,line=%d\n",dly_max,dly_min,avs_dyn_data_cnt,show_line_cnt); + + + } else { + if(show_line_cnt == 0) { + dly_min = avs_dyn_data[0]; + dly_max = avs_dyn_data[0]; + } + + + for(i = show_line_cnt * (line_pre_show * val_per_line); i < avs_dyn_data_cnt;) { + s += sprintf(s, "%d", avs_dyn_data[i]); + dly_min = min(dly_min, avs_dyn_data[i]); + dly_max = max(dly_max, avs_dyn_data[i]); + i++; + if(!(i % val_per_line)) { + s += sprintf(s, "\n"); + } else + s += sprintf(s, " "); + if(i >= ((show_line_cnt + 1)*line_pre_show * val_per_line)) + break; + } + + s += sprintf(s, "\n"); + + s += sprintf(s, "max=%d,min=%d,totolcnt=%d,line=%d\n", + dly_max, dly_min, avs_dyn_data_cnt, show_line_cnt); + show_line_cnt++; + if(((show_line_cnt * line_pre_show)*val_per_line) >= avs_dyn_data_cnt) { + + show_line_cnt = 0; + + s += sprintf(s, "data is over\n"); + } + } + return (s - buf); +} + +static ssize_t avs_dyn_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n) +{ + const char *pbuf; + + if((strncmp(buf, "start", strlen("start")) == 0)) { + pbuf = &buf[strlen("start")]; + avs_dyn_data_cnt = 0; + show_line_cnt = 0; + if(avs_dyn_data) { +#ifdef USE_NORMAL_TIME + mod_timer(&avs_timer, jiffies + msecs_to_jiffies(5)); +#else + hrtimer_start(&dvfs_hrtimer, ktime_set(0, 5 * 1000 * 1000), HRTIMER_MODE_REL); +#endif + avs_dyn_start = 1; + } + //sscanf(pbuf, "%d %d", &number, &voltage); + //DVFS_DBG("---------ldo %d %d\n", number, voltage); + + } else if((strncmp(buf, "stop", strlen("stop")) == 0)) { + pbuf = &buf[strlen("stop")]; + avs_dyn_start = 0; + show_line_cnt = 0; + //sscanf(pbuf, "%d %d", &number, &voltage); + //DVFS_DBG("---------dcdc %d %d\n", number, voltage); + } + + + + return n; +} + +static ssize_t dvfs_tree_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n) +{ + return n; +} +static ssize_t dvfs_tree_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + return dump_dbg_map(buf); + +} + +static void avs_timer_fn(unsigned long data) +{ + int i; + for(i = 0; i < 1; i++) { + if(avs_dyn_data_cnt >= avs_dyn_data_num) + return; + avs_dyn_data[avs_dyn_data_cnt] = rk30_get_avs_val(); + avs_dyn_data_cnt++; + } + if(avs_dyn_start) + mod_timer(&avs_timer, jiffies + msecs_to_jiffies(10)); +} +#if 0 +struct hrtimer dvfs_hrtimer; +static enum hrtimer_restart dvfs_hrtimer_timer_func(struct hrtimer *timer) +{ + int i; + for(i = 0; i < 1; i++) { + if(avs_dyn_data_cnt >= avs_dyn_data_num) + return HRTIMER_NORESTART; + avs_dyn_data[avs_dyn_data_cnt] = rk30_get_avs_val(); + avs_dyn_data_cnt++; + } + if(avs_dyn_start) + hrtimer_start(timer, ktime_set(0, 1 * 1000 * 1000), HRTIMER_MODE_REL); + +} +#endif +/*********************************************************************************/ +static struct kobject *dvfs_kobj; +struct dvfs_attribute { + struct attribute attr; + ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr, + char *buf); + ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n); +}; + +static struct dvfs_attribute dvfs_attrs[] = { + /* node_name permision show_func store_func */ + __ATTR(dvfs_tree, S_IRUGO | S_IWUSR, dvfs_tree_show, dvfs_tree_store), + __ATTR(avs_init, S_IRUGO | S_IWUSR, avs_init_show, avs_init_store), + //__ATTR(avs_dyn, S_IRUGO | S_IWUSR, avs_dyn_show, avs_dyn_store), + __ATTR(avs_now, S_IRUGO | S_IWUSR, avs_now_show, avs_now_store), +}; + +static int __init dvfs_init(void) +{ + int i, ret = 0; +#ifdef USE_NORMAL_TIME + init_timer(&avs_timer); + //avs_timer.expires = jiffies+msecs_to_jiffies(1); + avs_timer.function = avs_timer_fn; + //mod_timer(&avs_timer,jiffies+msecs_to_jiffies(1)); +#else + hrtimer_init(&dvfs_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + dvfs_hrtimer.function = dvfs_hrtimer_timer_func; + //hrtimer_start(&dvfs_hrtimer,ktime_set(0, 5*1000*1000),HRTIMER_MODE_REL); +#endif + avs_dyn_data = kmalloc(avs_dyn_data_num, GFP_KERNEL); + + dvfs_kobj = kobject_create_and_add("dvfs", NULL); + if (!dvfs_kobj) + return -ENOMEM; + for (i = 0; i < ARRAY_SIZE(dvfs_attrs); i++) { + ret = sysfs_create_file(dvfs_kobj, &dvfs_attrs[i].attr); + if (ret != 0) { + DVFS_ERR("create index %d error\n", i); + return ret; + } + } + + return ret; +} +subsys_initcall(dvfs_init); + +/** + * dump_dbg_map() : Draw all informations of dvfs while debug + */ +static int dump_dbg_map(char *buf) +{ + int i; + struct vd_node *vd; + struct pd_node *pd, *clkparent; + struct clk_list *child; + struct clk_node *dvfs_clk; + struct depend_list *depend; + char* s = buf; + + s += sprintf(s, "-------------DVFS TREE-----------\n\n\n"); + s += sprintf(s, "RK30 DVFS TREE:\n"); + list_for_each_entry(vd, &rk_dvfs_tree, node) { + s += sprintf(s, "|\n|- voltage domain:%s\n", vd->name); + s += sprintf(s, "|- current voltage:%d\n", vd->cur_volt); + list_for_each_entry(depend, &vd->req_volt_list, node2vd) { + s += sprintf(s, "|- request voltage:%d, clk:%s\n", depend->req_volt, depend->dvfs_clk->name); + } + + list_for_each_entry(pd, &vd->pd_list, node) { + s += sprintf(s, "| |\n| |- power domain:%s, status = %s, current volt = %d\n", + pd->name, (pd->pd_status == PD_ON) ? "ON" : "OFF", pd->cur_volt); + + list_for_each_entry(child, &pd->clk_list, node) { + dvfs_clk = child->dvfs_clk; + s += sprintf(s, "| | |\n| | |- clock: %s current: rate %d, volt = %d, enable_dvfs = %s\n", + dvfs_clk->name, dvfs_clk->set_freq, dvfs_clk->set_volt, + dvfs_clk->enable_dvfs == 0 ? "DISABLE" : "ENABLE"); + for (i = 0; dvfs_clk->pds[i].pd != NULL; i++) { + clkparent = dvfs_clk->pds[i].pd; + s += sprintf(s, "| | | |- clock parents: %s, vd_parent = %s\n", + clkparent->name, clkparent->vd->name); + } + + for (i = 0; (dvfs_clk->dvfs_table[i].frequency != CPUFREQ_TABLE_END); i++) { + s += sprintf(s, "| | | |- freq = %d, volt = %d\n", + dvfs_clk->dvfs_table[i].frequency, + dvfs_clk->dvfs_table[i].index); + + } + + list_for_each_entry(depend, &dvfs_clk->depend_list, node2clk) { + s += sprintf(s, "| | | | |- DEPEND VD: %s\n", depend->dep_vd->name); + for (i = 0; (depend->dep_table[i].frequency != CPUFREQ_TABLE_END); i++) { + s += sprintf(s, "| | | | |- freq = %d, req_volt = %d\n", + depend->dep_table[i].frequency, + + depend->dep_table[i].index); + } + } + } + } + } + s += sprintf(s, "-------------DVFS TREE END------------\n"); + return s - buf; +} + + diff --git a/arch/arm/mach-rk2928/include/mach/dvfs.h b/arch/arm/mach-rk2928/include/mach/dvfs.h new file mode 100644 index 000000000000..59ec37d4704b --- /dev/null +++ b/arch/arm/mach-rk2928/include/mach/dvfs.h @@ -0,0 +1,183 @@ +/* arch/arm/mach-rk30/rk30_dvfs.h + * + * Copyright (C) 2012 ROCKCHIP, Inc. + * + * 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. + * + */ +#ifndef _RK30_DVFS_H_ +#define _RK30_DVFS_H_ + +#include + +typedef int (*vd_dvfs_target_callback)(struct clk *clk, unsigned long rate); + +typedef int (*dvfs_set_rate_callback)(struct clk *clk, unsigned long rate); + +typedef int (*clk_dvfs_target_callback)(struct clk *clk, unsigned long rate, + dvfs_set_rate_callback set_rate); + +/** + * struct vd_node: To Store All Voltage Domains' info + * @name: Voltage Domain's Name + * @regulator_name: Voltage domain's regulator name + * @cur_volt: Voltage Domain's Current Voltage + * @regulator: Voltage Domain's regulator point + * @node: Point of he Voltage Domain List Node + * @pd_list: Head of Power Domain List Belongs to This Voltage Domain + * @req_volt_list: The list of clocks requests + * @dvfs_mutex: Lock + * @vd_dvfs_target: Callback function + */ + +struct vd_node { + char *name; + char *regulator_name; + int cur_volt; + int volt_set_flag; + struct regulator *regulator; + struct list_head node; + struct list_head pd_list; + struct list_head req_volt_list; + //struct mutex dvfs_mutex; + vd_dvfs_target_callback vd_dvfs_target; +}; + +/** + * struct pd_node: To Store All Power Domains' info + * @name: Power Domain's Name + * @cur_volt: Power Domain's Current Voltage + * @pd_status: Power Domain's status + * @vd: Voltage Domain the power domain belongs to + * @pd_clk: Look power domain as a clock + * @node: List node to Voltage Domain + * @clk_list: Head of Power Domain's Clocks List + */ +struct pd_node { + char *name; + int cur_volt; + unsigned char pd_status; + struct vd_node *vd; + //struct clk *pd_clk; + struct list_head node; + struct list_head clk_list; +}; + +struct pd_node_lookup { + struct pd_node *pd; +}; + +struct clk_list{ + struct clk_node *dvfs_clk; + struct list_head node; +}; + +struct pds_list { + struct clk_list clk_list; + struct pd_node *pd; +}; + +struct depend_list { + int req_volt; + struct clk_node *dvfs_clk; + struct vd_node *dep_vd; + struct list_head node2clk; + struct list_head node2vd; + struct cpufreq_frequency_table *dep_table; +}; + +struct depend_lookup { + char *clk_name; + struct clk_node *dvfs_clk; + struct vd_node *dep_vd; + struct depend_list dep_list; + struct cpufreq_frequency_table *dep_table; +}; + +/** + * struct clk_node: To Store All dvfs clocks' info + * @name: Dvfs clock's Name + * @set_freq: Dvfs clock's Current Frequency + * @set_volt: Dvfs clock's Current Voltage + * @enable_dvfs: Sign if DVFS clock enable + * @clk: System clk's point + * @pds: Power Domains dvfs clock belongs to + * @vd: Voltage Domains dvfs clock belongs to + * @depend_list: Dvfs Clock depend list + * @dvfs_nb: Notify list + * @dvfs_table: Frequency and voltage table for dvfs + * @clk_dvfs_target: Callback function + */ +struct clk_node { + char *name; + int set_freq; //KHZ + int set_volt; //MV + int enable_dvfs; + int freq_limit_en; //sign if use limit frequency + unsigned int min_rate; //limit min frequency + unsigned int max_rate; //limit max frequency + struct clk *clk; + struct pds_list *pds; + struct vd_node *vd; + struct list_head depend_list; + struct notifier_block *dvfs_nb; + struct cpufreq_frequency_table *dvfs_table; + clk_dvfs_target_callback clk_dvfs_target; +}; + +struct dvfs_arm_table { + unsigned int frequency; /* kHz - doesn't need to be in ascending + * order */ + unsigned int cpu_volt; /* any */ + + unsigned int logic_volt; +}; + +#ifdef CONFIG_DVFS +int rk30_dvfs_init(void); +int is_support_dvfs(struct clk_node *dvfs_info); +int dvfs_set_rate(struct clk *clk, unsigned long rate); +int clk_enable_dvfs(struct clk *clk); +int clk_disable_dvfs(struct clk *clk); +void dvfs_clk_register_set_rate_callback(struct clk *clk, clk_dvfs_target_callback clk_dvfs_target); +struct cpufreq_frequency_table *dvfs_get_freq_volt_table(struct clk *clk); +int dvfs_set_freq_volt_table(struct clk *clk, struct cpufreq_frequency_table *table); +int dvfs_set_depend_table(struct clk *clk, char *vd_name, struct cpufreq_frequency_table *table); +int dvfs_set_arm_logic_volt(struct dvfs_arm_table *dvfs_cpu_logic_table, struct cpufreq_frequency_table *cpu_dvfs_table, struct cpufreq_frequency_table *dep_cpu2core_table); +struct regulator* dvfs_get_regulator(char *regulator_name); +int dvfs_clk_enable_limit(struct clk *clk, unsigned int min_rate, unsigned max_rate); +int dvfs_clk_disable_limit(struct clk *clk); + +void avs_init(void); +void avs_init_val_get(int index,int vol,char *s); +int avs_set_scal_val(u8 avs_base); +int dvfs_avs_scale_table(struct clk* clk, char* depend_vd_name); +#else +static inline int rk30_dvfs_init(void) { return 0; } +static inline int is_support_dvfs(struct clk_node *dvfs_info) { return 0; } +static inline int dvfs_set_rate(struct clk *clk, unsigned long rate) { return 0; } +static inline int clk_enable_dvfs(struct clk *clk) { return 0; } +static inline int clk_disable_dvfs(struct clk *clk) { return 0; } +static inline void dvfs_clk_register_set_rate_callback(struct clk *clk, clk_dvfs_target_callback clk_dvfs_target) {} +static inline struct cpufreq_frequency_table *dvfs_get_freq_volt_table(struct clk *clk) { return NULL; } +static inline int dvfs_set_freq_volt_table(struct clk *clk, struct cpufreq_frequency_table *table) { return 0; } +static inline int dvfs_set_depend_table(struct clk *clk, char *vd_name, struct cpufreq_frequency_table *table) {return 0;} +static inline int dvfs_set_arm_logic_volt(struct dvfs_arm_table *dvfs_cpu_logic_table, struct cpufreq_frequency_table *cpu_dvfs_table, struct cpufreq_frequency_table *dep_cpu2core_table){ return 0; } +static inline struct regulator* dvfs_get_regulator(char *regulator_name){ return NULL; } +static inline int dvfs_clk_enable_limit(struct clk *clk, unsigned int min_rate, unsigned max_rate){ return 0; } +static inline int dvfs_clk_disable_limit(struct clk *clk){ return 0; }; + +static inline void avs_init(void){}; +static inline void avs_init_val_get(int index, int vol, char *s){}; +static inline int avs_set_scal_val(u8 avs_base){ return 0; }; +static inline int dvfs_avs_scale_table(struct clk* clk, char* depend_vd_name){ return 0; }; +#endif + +#endif From 3e38132b627057b072ce358ed5f82df731d5ceb3 Mon Sep 17 00:00:00 2001 From: lw Date: Tue, 14 Aug 2012 20:44:58 +0800 Subject: [PATCH 181/261] phonepad:select all sensor items and modify orientation --- arch/arm/configs/rk30_phonepad_defconfig | 7 ++ arch/arm/mach-rk30/board-rk30-phonepad.c | 127 ++++++++++++++++++++++- 2 files changed, 129 insertions(+), 5 deletions(-) diff --git a/arch/arm/configs/rk30_phonepad_defconfig b/arch/arm/configs/rk30_phonepad_defconfig index 7c3d8f1fb8e2..d797e47a2899 100755 --- a/arch/arm/configs/rk30_phonepad_defconfig +++ b/arch/arm/configs/rk30_phonepad_defconfig @@ -234,13 +234,20 @@ CONFIG_INPUT_KEYCHORD=y CONFIG_INPUT_UINPUT=y CONFIG_COMPASS_AK8975=y CONFIG_GS_MMA8452=y +CONFIG_GS_LIS3DH=y CONFIG_GYRO_L3G4200D=y CONFIG_LS_CM3217=y CONFIG_SENSOR_DEVICE=y CONFIG_GSENSOR_DEVICE=y +CONFIG_GS_KXTIK=y CONFIG_COMPASS_DEVICE=y CONFIG_GYROSCOPE_DEVICE=y CONFIG_LIGHT_DEVICE=y +CONFIG_LS_AL3006=y +CONFIG_LS_STK3171=y +CONFIG_PROXIMITY_DEVICE=y +CONFIG_PS_AL3006=y +CONFIG_PS_STK3171=y # CONFIG_SERIO is not set # CONFIG_CONSOLE_TRANSLATIONS is not set # CONFIG_LEGACY_PTYS is not set diff --git a/arch/arm/mach-rk30/board-rk30-phonepad.c b/arch/arm/mach-rk30/board-rk30-phonepad.c index c06b3936f0bc..f70b558721cc 100755 --- a/arch/arm/mach-rk30/board-rk30-phonepad.c +++ b/arch/arm/mach-rk30/board-rk30-phonepad.c @@ -1049,8 +1049,27 @@ static struct sensor_platform_data lis3dh_info = { .irq_enable = 1, .poll_delay_ms = 30, .init_platform_hw = lis3dh_init_platform_hw, - .orientation = {-1, 0, 0, 0, 0, 1, 0, -1, 0}, + .orientation = {-1, 0, 0, 0, 0, -1, 0, 1, 0}, }; +#endif +#if defined (CONFIG_GS_KXTIK) +#define KXTIK_INT_PIN RK30_PIN4_PC0 + +static int kxtik_init_platform_hw(void) +{ + rk30_mux_api_set(GPIO4C0_SMCDATA0_TRACEDATA0_NAME, GPIO4C_GPIO4C0); + + return 0; +} + +static struct sensor_platform_data kxtik_info = { + .type = SENSOR_TYPE_ACCEL, + .irq_enable = 1, + .poll_delay_ms = 30, + .init_platform_hw = kxtik_init_platform_hw, + .orientation = {0, 1, 0, 0, 0, -1, 1, 0, 0}, +}; + #endif #if defined (CONFIG_COMPASS_AK8975) static struct sensor_platform_data akm8975_info = @@ -1061,9 +1080,9 @@ static struct sensor_platform_data akm8975_info = .m_layout = { { - {1, 0, 0}, {0, 1, 0}, - {0, 0, 1}, + {1, 0, 0}, + {0, 0, -1}, }, { @@ -1104,7 +1123,7 @@ static struct sensor_platform_data l3g4200d_info = { .type = SENSOR_TYPE_GYROSCOPE, .irq_enable = 1, .poll_delay_ms = 30, - .orientation = {0, 1, 0, -1, 0, 0, 0, 0, 1}, + .orientation = {0, 1, 0, -1, 0, 0, 0, 0, -1}, .init_platform_hw = l3g4200d_init_platform_hw, .x_min = 40,//x_min,y_min,z_min = (0-100) according to hardware .y_min = 40, @@ -1122,6 +1141,42 @@ static struct sensor_platform_data cm3217_info = { #endif + +#if defined(CONFIG_PS_AL3006) +static struct sensor_platform_data proximity_al3006_info = { + .type = SENSOR_TYPE_PROXIMITY, + .irq_enable = 1, + .poll_delay_ms = 200, +}; +#endif + +#if defined(CONFIG_PS_STK3171) +static struct sensor_platform_data proximity_stk3171_info = { + .type = SENSOR_TYPE_PROXIMITY, + .irq_enable = 1, + .poll_delay_ms = 200, +}; +#endif + + +#if defined(CONFIG_LS_AL3006) +static struct sensor_platform_data light_al3006_info = { + .type = SENSOR_TYPE_LIGHT, + .irq_enable = 1, + .poll_delay_ms = 200, +}; +#endif + +#if defined(CONFIG_LS_STK3171) +static struct sensor_platform_data light_stk3171_info = { + .type = SENSOR_TYPE_LIGHT, + .irq_enable = 1, + .poll_delay_ms = 200, +}; +#endif + + + #ifdef CONFIG_FB_ROCKCHIP #define LCD_CS_MUX_NAME GPIO4C7_SMCDATA7_TRACEDATA7_NAME @@ -1729,6 +1784,18 @@ static struct i2c_board_info __initdata i2c0_info[] = { .platform_data = &lis3dh_info, }, #endif + +#if defined (CONFIG_GS_KXTIK) + { + .type = "gs_kxtik", + .addr = 0x0F, + .flags = 0, + .irq = KXTIK_INT_PIN, + .platform_data = &kxtik_info, + }, +#endif + + #if defined (CONFIG_COMPASS_AK8975) { .type = "ak8975", @@ -1747,6 +1814,56 @@ static struct i2c_board_info __initdata i2c0_info[] = { .platform_data = &l3g4200d_info, }, #endif +#if defined (CONFIG_INPUT_LPSENSOR_AL3006) + { + .type = "al3006", + .addr = 0x1c, //sel = 0; if sel =1, then addr = 0x1D + .flags = 0, + .irq = RK30_PIN6_PA2, + }, +#endif + +#if defined (CONFIG_LS_AL3006) + { + .type = "light_al3006", + .addr = 0x1c, //sel = 0; if sel =1, then addr = 0x1D + .flags = 0, + .irq = RK30_PIN6_PA2, + .platform_data = &light_al3006_info, + }, +#endif +#if defined (CONFIG_LS_STK3171) + { + .type = "ls_stk3171", + .addr = 0x48, + .flags = 0, + .irq = RK30_PIN6_PA2, + .platform_data = &light_stk3171_info, + }, +#endif + + +#if defined (CONFIG_PS_AL3006) + { + .type = "proximity_al3006", + .addr = 0x1c, //sel = 0; if sel =1, then addr = 0x1D + .flags = 0, + .irq = RK30_PIN6_PA2, + .platform_data = &proximity_al3006_info, + }, +#endif + +#if defined (CONFIG_PS_STK3171) + { + .type = "ps_stk3171", + .addr = 0x48, + .flags = 0, + .irq = RK30_PIN6_PA2, + .platform_data = &proximity_stk3171_info, + }, +#endif + + #if defined (CONFIG_SND_SOC_RK1000) { .type = "rk1000_i2c_codec", @@ -1944,7 +2061,7 @@ static struct i2c_board_info __initdata i2c2_info[] = { #endif #if defined (CONFIG_LS_CM3217) { - .type = "lightsensor", + .type = "light_cm3217", .addr = 0x10, .flags = 0, .platform_data = &cm3217_info, From e9e26116cf21957e5027efd60be5b5393406fbd1 Mon Sep 17 00:00:00 2001 From: xxx Date: Mon, 8 Dec 2014 21:02:39 -0800 Subject: [PATCH 182/261] uart support 1m or 3M --- arch/arm/mach-rk30/clock_data.c | 14 +++++++------- arch/arm/mach-rk30/include/mach/board.h | 9 +++++++++ 2 files changed, 16 insertions(+), 7 deletions(-) mode change 100644 => 100755 arch/arm/mach-rk30/include/mach/board.h diff --git a/arch/arm/mach-rk30/clock_data.c b/arch/arm/mach-rk30/clock_data.c index 340b86028f3f..c95809aabbe1 100644 --- a/arch/arm/mach-rk30/clock_data.c +++ b/arch/arm/mach-rk30/clock_data.c @@ -42,6 +42,8 @@ #define CLK_FLG_MAX_I2S_22579_2KHZ (1<<2) #define CLK_FLG_MAX_I2S_24576KHZ (1<<3) #define CLK_FLG_MAX_I2S_49152KHZ (1<<4) +//uart 1m\3m +#define CLK_FLG_UART_1_3M (1<<5) @@ -1081,6 +1083,7 @@ static const struct pll_clk_set cpll_clks[] = { _PLL_SET_CLKS(552000, 1, 23, 1), _PLL_SET_CLKS(600000, 1, 25, 1), _PLL_SET_CLKS(742500, 8, 495, 2), + _PLL_SET_CLKS(768000, 1, 32, 1), _PLL_SET_CLKS(798000, 4, 133, 1), _PLL_SET_CLKS(1188000,2, 99, 1), _PLL_SET_CLKS( 0, 4, 133, 1), @@ -1784,8 +1787,6 @@ static int clk_uart_set_rate(struct clk *clk, unsigned long rate) parent = clk->parents[UART_SRC_FRAC]; } - - CRU_PRINTK_DBG(" %s set rate=%lu parent %s(old %s)\n", clk->name,rate,parent->name,clk->parent->name); @@ -3303,11 +3304,10 @@ static void __init rk30_clock_common_init(unsigned long gpll_rate,unsigned long clk_set_rate_nolock(&clk_spi1, clk_spi1.parent->rate); // uart - #if 0 - clk_set_parent_nolock(&clk_uart_pll, &codec_pll_clk); - #else - clk_set_parent_nolock(&clk_uart_pll, &general_pll_clk); - #endif + if(rk30_clock_flags&CLK_FLG_UART_1_3M) + clk_set_parent_nolock(&clk_uart_pll, &codec_pll_clk); + else + clk_set_parent_nolock(&clk_uart_pll, &general_pll_clk); //mac if(!(gpll_rate%(50*MHZ))) clk_set_parent_nolock(&clk_mac_pll_div, &general_pll_clk); diff --git a/arch/arm/mach-rk30/include/mach/board.h b/arch/arm/mach-rk30/include/mach/board.h old mode 100644 new mode 100755 index d2a17e483efe..f23e46519265 --- a/arch/arm/mach-rk30/include/mach/board.h +++ b/arch/arm/mach-rk30/include/mach/board.h @@ -114,6 +114,7 @@ enum _codec_pll { codec_pll_552mhz = 552000000, /* for HDMI */ codec_pll_600mhz = 600000000, codec_pll_742_5khz = 742500000, + codec_pll_768mhz = 768000000, codec_pll_798mhz = 798000000, codec_pll_1188mhz = 1188000000, }; @@ -125,6 +126,8 @@ enum _codec_pll { #define CLK_FLG_MAX_I2S_22579_2KHZ (1<<2) #define CLK_FLG_MAX_I2S_24576KHZ (1<<3) #define CLK_FLG_MAX_I2S_49152KHZ (1<<4) +//uart 1m\3m +#define CLK_FLG_UART_1_3M (1<<5) @@ -136,8 +139,14 @@ enum _codec_pll { #else + #define RK30_CLOCKS_DEFAULT_FLAGS (CLK_FLG_MAX_I2S_12288KHZ/*|CLK_FLG_EXT_27MHZ*/) + +#if (RK30_CLOCKS_DEFAULT_FLAGS&CLK_FLG_UART_1_3M) +#define codec_pll_default codec_pll_768mhz +#else #define codec_pll_default codec_pll_798mhz +#endif #define periph_pll_default periph_pll_297mhz #endif From d06d84962dd8a16f561140b18d584441e2441b63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=8B=E7=A7=80=E6=9D=B0?= Date: Tue, 14 Aug 2012 22:51:49 +0800 Subject: [PATCH 183/261] phonepad: change record route, must update asound.conf. --- sound/soc/codecs/rt3261.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt3261.c b/sound/soc/codecs/rt3261.c index e8f1405fb8d8..f7e18dd050a7 100644 --- a/sound/soc/codecs/rt3261.c +++ b/sound/soc/codecs/rt3261.c @@ -89,8 +89,6 @@ static struct rt3261_init_reg init_list[] = { {RT3261_HP_VOL , 0x8888}, {RT3261_OUTPUT , 0x8888},//unmute OUTVOLL/R {RT3261_SPO_CLSD_RATIO , 0x0001}, - {RT3261_I2S1_SDP , 0xe000}, - {RT3261_I2S2_SDP , 0x8040}, }; #define RT3261_INIT_REG_LEN ARRAY_SIZE(init_list) @@ -2370,6 +2368,8 @@ static int rt3261_hw_params(struct snd_pcm_substream *substream, int pre_div, bclk_ms, frame_size; rt3261->lrck[dai->id] = params_rate(params); + if(dai->id == 1) + rt3261->lrck[dai->id] = 8000; pre_div = get_clk_info(rt3261->sysclk, rt3261->lrck[dai->id]); if (pre_div < 0) { dev_err(codec->dev, "Unsupported clock setting\n"); From ba1561048042525a8291e772cd4c019834b7f4bd Mon Sep 17 00:00:00 2001 From: "lw@rock-chips.com" Date: Wed, 15 Aug 2012 11:52:46 +0800 Subject: [PATCH 184/261] sensor:add gsensor disable irq operation --- drivers/input/sensors/sensor-dev.c | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/drivers/input/sensors/sensor-dev.c b/drivers/input/sensors/sensor-dev.c index e5ac3e97a3d1..6008deb94f34 100644 --- a/drivers/input/sensors/sensor-dev.c +++ b/drivers/input/sensors/sensor-dev.c @@ -35,8 +35,6 @@ #include #include -#define SENSOR_ON 1 -#define SENSOR_OFF 0 #if 0 #define SENSOR_DEBUG_TYPE SENSOR_TYPE_ACCEL @@ -300,7 +298,7 @@ static int sensor_irq_init(struct i2c_client *client) goto error; } client->irq = irq; - if((sensor->pdata->type == SENSOR_TYPE_GYROSCOPE)) + if((sensor->pdata->type == SENSOR_TYPE_GYROSCOPE) || (sensor->pdata->type == SENSOR_TYPE_ACCEL)) disable_irq_nosync(client->irq);//disable irq printk("%s:use irq=%d\n",__func__,irq); } @@ -399,8 +397,8 @@ static long gsensor_dev_ioctl(struct file *file, } if(sensor->pdata->irq_enable) { - //printk("%s:enable irq,irq=%d\n",__func__,client->irq); - //enable_irq(client->irq); //enable irq + DBG("%s:enable irq,irq=%d\n",__func__,client->irq); + enable_irq(client->irq); //enable irq } else { @@ -429,8 +427,8 @@ static long gsensor_dev_ioctl(struct file *file, if(sensor->pdata->irq_enable) { - //printk("%s:disable irq,irq=%d\n",__func__,client->irq); - //disable_irq_nosync(client->irq);//disable irq + DBG("%s:disable irq,irq=%d\n",__func__,client->irq); + disable_irq_nosync(client->irq);//disable irq } else cancel_delayed_work_sync(&sensor->delaywork); @@ -451,20 +449,8 @@ static long gsensor_dev_ioctl(struct file *file, mutex_unlock(&sensor->operation_mutex); goto error; } - if(sensor->status_cur == SENSOR_OFF) - { - if(sensor->pdata->irq_enable) - { - //printk("%s:enable irq,irq=%d\n",__func__,client->irq); - //enable_irq(client->irq); //enable irq - } - else - { - PREPARE_DELAYED_WORK(&sensor->delaywork, sensor_delaywork_func); - schedule_delayed_work(&sensor->delaywork, msecs_to_jiffies(sensor->pdata->poll_delay_ms)); - } - sensor->status_cur = SENSOR_ON; - } + + sensor->status_cur = SENSOR_ON; mutex_unlock(&sensor->operation_mutex); DBG("%s:GSENSOR_IOCTL_APP_SET_RATE OK\n", __func__); break; From e0c50d130369edcb2d1bc0b1d0c7abcbfbdcdaaf Mon Sep 17 00:00:00 2001 From: lw Date: Wed, 15 Aug 2012 14:35:16 +0800 Subject: [PATCH 185/261] phonepad:delete lpsensor item because of i2c address conflict --- arch/arm/configs/rk30_phonepad_defconfig | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/arm/configs/rk30_phonepad_defconfig b/arch/arm/configs/rk30_phonepad_defconfig index d797e47a2899..be12e87ab36c 100755 --- a/arch/arm/configs/rk30_phonepad_defconfig +++ b/arch/arm/configs/rk30_phonepad_defconfig @@ -236,18 +236,11 @@ CONFIG_COMPASS_AK8975=y CONFIG_GS_MMA8452=y CONFIG_GS_LIS3DH=y CONFIG_GYRO_L3G4200D=y -CONFIG_LS_CM3217=y CONFIG_SENSOR_DEVICE=y CONFIG_GSENSOR_DEVICE=y CONFIG_GS_KXTIK=y CONFIG_COMPASS_DEVICE=y CONFIG_GYROSCOPE_DEVICE=y -CONFIG_LIGHT_DEVICE=y -CONFIG_LS_AL3006=y -CONFIG_LS_STK3171=y -CONFIG_PROXIMITY_DEVICE=y -CONFIG_PS_AL3006=y -CONFIG_PS_STK3171=y # CONFIG_SERIO is not set # CONFIG_CONSOLE_TRANSLATIONS is not set # CONFIG_LEGACY_PTYS is not set From 0c3cb26b930d1a7a887f9195a640d4bfc3161bb5 Mon Sep 17 00:00:00 2001 From: lw Date: Wed, 15 Aug 2012 15:15:54 +0800 Subject: [PATCH 186/261] phonepad:set ddr frequency 300M --- arch/arm/configs/rk30_phonepad_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/rk30_phonepad_defconfig b/arch/arm/configs/rk30_phonepad_defconfig index be12e87ab36c..9dd90e82d2ba 100755 --- a/arch/arm/configs/rk30_phonepad_defconfig +++ b/arch/arm/configs/rk30_phonepad_defconfig @@ -22,6 +22,7 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_ARCH_RK30=y +CONFIG_DDR_SDRAM_FREQ=300 CONFIG_CLK_SWITCH_TO_32K=y CONFIG_RK30_I2C_INSRAM=y CONFIG_WIFI_COMBO_MODULE_CONTROL_FUNC=y From 532d0404a8897335fce51972cb635f43cb84df10 Mon Sep 17 00:00:00 2001 From: lw Date: Wed, 15 Aug 2012 17:01:33 +0800 Subject: [PATCH 187/261] phonepad:uart0 support 1-3Mbps baud rate --- arch/arm/mach-rk30/board-rk30-phonepad.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-rk30/board-rk30-phonepad.c b/arch/arm/mach-rk30/board-rk30-phonepad.c index f70b558721cc..6cf7dee27e75 100755 --- a/arch/arm/mach-rk30/board-rk30-phonepad.c +++ b/arch/arm/mach-rk30/board-rk30-phonepad.c @@ -2206,7 +2206,7 @@ static void __init machine_rk30_board_init(void) dcr_en_low(); #if defined(CONFIG_MT6620) - clk_set_rate(clk_get_sys("rk_serial.0", "uart"), 16*1000000); + clk_set_rate(clk_get_sys("rk_serial.0", "uart"), 48*1000000); #endif } @@ -2267,7 +2267,8 @@ static struct cpufreq_frequency_table dep_cpu2core_table[DVFS_CPU_TABLE_SIZE]; void __init board_clock_init(void) { - rk30_clock_data_init(periph_pll_default, codec_pll_default, RK30_CLOCKS_DEFAULT_FLAGS); + //support uart 1-3Mbits/s + rk30_clock_data_init(periph_pll_default, codec_pll_768mhz, RK30_CLOCKS_DEFAULT_FLAGS | CLK_FLG_UART_1_3M); dvfs_set_arm_logic_volt(dvfs_cpu_logic_table, cpu_dvfs_table, dep_cpu2core_table); dvfs_set_freq_volt_table(clk_get(NULL, "gpu"), dvfs_gpu_table); dvfs_set_freq_volt_table(clk_get(NULL, "ddr"), dvfs_ddr_table); From e592356dbbf6b403b4389d0ec2e1c4d4048b5fa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=99=B4?= Date: Wed, 15 Aug 2012 17:20:59 +0800 Subject: [PATCH 188/261] rk2928:sdk:support pwm set voltage --- .../mach-rk2928/board-rk2928-sdk-tps65910.c | 13 +- arch/arm/mach-rk2928/board-rk2928-sdk.c | 64 ++++++- drivers/regulator/rk30-pwm-regulator.c | 161 ++++++++++++++---- include/linux/regulator/rk29-pwm-regulator.h | 5 + 4 files changed, 200 insertions(+), 43 deletions(-) mode change 100644 => 100755 include/linux/regulator/rk29-pwm-regulator.h diff --git a/arch/arm/mach-rk2928/board-rk2928-sdk-tps65910.c b/arch/arm/mach-rk2928/board-rk2928-sdk-tps65910.c index 51cf60dc2029..4b8d6058d3ee 100755 --- a/arch/arm/mach-rk2928/board-rk2928-sdk-tps65910.c +++ b/arch/arm/mach-rk2928/board-rk2928-sdk-tps65910.c @@ -237,6 +237,10 @@ int tps65910_post_init(struct tps65910 *tps65910) struct regulator *dcdc; struct regulator *ldo; printk("%s,line=%d\n", __func__,__LINE__); + + #ifdef CONFIG_RK30_PWM_REGULATOR + platform_device_register(&pwm_regulator_device[0]); + #endif dcdc = regulator_get(NULL, "vio"); //vcc_io regulator_set_voltage(dcdc, 3300000, 3300000); @@ -315,15 +319,6 @@ int tps65910_post_init(struct tps65910 *tps65910) regulator_put(ldo); udelay(100); - #ifdef CONFIG_RK30_PWM_REGULATOR - dcdc = regulator_get(NULL, "vdd_core"); // vdd_log - regulator_set_voltage(dcdc, 1100000, 1100000); - regulator_enable(dcdc); - printk("%s set vdd_core=%dmV end\n", __func__, regulator_get_voltage(dcdc)); - regulator_put(dcdc); - udelay(100); - #endif - printk("%s,line=%d END\n", __func__,__LINE__); return 0; diff --git a/arch/arm/mach-rk2928/board-rk2928-sdk.c b/arch/arm/mach-rk2928/board-rk2928-sdk.c index fb48103c0245..57eef7b606de 100755 --- a/arch/arm/mach-rk2928/board-rk2928-sdk.c +++ b/arch/arm/mach-rk2928/board-rk2928-sdk.c @@ -379,6 +379,59 @@ static struct platform_device device_ion = { }; #endif +#if CONFIG_RK30_PWM_REGULATOR +const static int pwm_voltage_map[] = { + 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 1400000 +}; + +static struct regulator_consumer_supply pwm_dcdc1_consumers[] = { + { + .supply = "vdd_core", + } +}; + +struct regulator_init_data pwm_regulator_init_dcdc[1] = +{ + { + .constraints = { + .name = "PWM_DCDC1", + .min_uV = 600000, + .max_uV = 1800000, //0.6-1.8V + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(pwm_dcdc1_consumers), + .consumer_supplies = pwm_dcdc1_consumers, + }, +}; + +static struct pwm_platform_data pwm_regulator_info[1] = { + { + .pwm_id = 2, + .pwm_gpio = RK2928_PIN0_PD4, + .pwm_iomux_name = GPIO0D4_PWM_2_NAME, + .pwm_iomux_pwm = GPIO0D_PWM_2, + .pwm_iomux_gpio = GPIO0D_GPIO0D4, + .pwm_voltage = 1200000, + .suspend_voltage = 1050000, + .min_uV = 1000000, + .max_uV = 1400000, + .coefficient = 455, //45.5% + .pwm_voltage_map = pwm_voltage_map, + .init_data = &pwm_regulator_init_dcdc[0], + }, +}; + +struct platform_device pwm_regulator_device[1] = { + { + .name = "pwm-voltage-regulator", + .id = 0, + .dev = { + .platform_data = &pwm_regulator_info[0], + } + }, +}; +#endif /************************************************************************************************** * SDMMC devices, include the module of SD,MMC,and sdio.noted by xbw at 2012-03-05 **************************************************************************************************/ @@ -717,10 +770,15 @@ static void __init rk30_i2c_register_board_info(void) //end of i2c #define POWER_ON_PIN RK2928_PIN3_PC5 //power_hold -static void rk30_pm_power_off(void) +static void rk2928_pm_power_off(void) { - printk(KERN_ERR "rk30_pm_power_off start...\n"); + printk(KERN_ERR "rk2928_pm_power_off start...\n"); + + #if defined(CONFIG_MFD_TPS65910) + tps65910_device_shutdown();//tps65910 shutdown + #endif gpio_direction_output(POWER_ON_PIN, GPIO_LOW); + }; static void __init rk2928_board_init(void) @@ -729,7 +787,7 @@ static void __init rk2928_board_init(void) gpio_direction_output(POWER_ON_PIN, GPIO_HIGH); gpio_free(POWER_ON_PIN); - pm_power_off = rk30_pm_power_off; + pm_power_off = rk2928_pm_power_off; rk30_i2c_register_board_info(); spi_register_board_info(board_spi_devices, ARRAY_SIZE(board_spi_devices)); diff --git a/drivers/regulator/rk30-pwm-regulator.c b/drivers/regulator/rk30-pwm-regulator.c index 7a89527b0b06..ce7aee35eee5 100755 --- a/drivers/regulator/rk30-pwm-regulator.c +++ b/drivers/regulator/rk30-pwm-regulator.c @@ -66,34 +66,37 @@ struct rk_pwm_dcdc { #define pwm_read_reg(id, addr) __raw_readl(addr+(RK30_PWM01_BASE+(id>>1)*0x20000+id*0x10)) #elif defined(CONFIG_ARCH_RK29) #define pwm_write_reg(id, addr, val) __raw_writel(val, addr+(RK29_PWM_BASE+id*0x10)) -#define pwm_read_reg(id, addr) __raw_readl(addr+(RK29_PWM_BASE+id*0x10)) +#define pwm_read_reg(id, addr) __raw_readl(addr+(RK29_PWM_BASE+id*0x10)) +#elif defined(CONFIG_ARCH_RK2928) +#define pwm_write_reg(id, addr, val) __raw_writel(val, addr+(RK2928_PWM_BASE+id*0x10)) +#define pwm_read_reg(id, addr) __raw_readl(addr+(RK2928_PWM_BASE+id*0x10)) #endif const static int pwm_voltage_map[] = { - 850000,875000,900000,925000,950000, 975000, 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000, 1325000 + 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 1400000 }; static struct clk *pwm_clk[2]; +static struct rk_pwm_dcdc *g_dcdc; static int pwm_set_rate(struct pwm_platform_data *pdata,int nHz,u32 rate) { u32 divh,divTotal; int id = pdata->pwm_id; unsigned long clkrate; - - if ( id >3 || id <0 ) + /* + if ( id >2 || id <0 ) { printk("%s:pwm id error,id=%d\n",__func__,id); return -1; } if((id==0) || (id == 1)) + */ clkrate = clk_get_rate(pwm_clk[0]); - else - clkrate = clk_get_rate(pwm_clk[1]); - DBG("%s:id=%d,rate=%d,clkrate=%d\n",__func__,id,rate,clkrate); - + DBG("%s:id=%d,rate=%d,clkrate=%d\n",__func__,id,rate,clkrate); + if(rate == 0) { // iomux pwm to gpio @@ -101,9 +104,9 @@ static int pwm_set_rate(struct pwm_platform_data *pdata,int nHz,u32 rate) //disable pull up or down gpio_pull_updown(pdata->pwm_gpio,PullDisable); // set gpio to low level - gpio_set_value(pdata->pwm_gpio,GPIO_LOW); + gpio_direction_output(pdata->pwm_gpio,GPIO_LOW); } - else if (rate <= 100) + else if (rate < 100) { // iomux pwm rk29_mux_api_set(pdata->pwm_iomux_name, pdata->pwm_iomux_pwm); @@ -119,6 +122,16 @@ static int pwm_set_rate(struct pwm_platform_data *pdata,int nHz,u32 rate) pwm_write_reg(id,PWM_REG_CNTR,0); pwm_write_reg(id, PWM_REG_CTRL,pwm_read_reg(id,PWM_REG_CTRL)|PWM_DIV|PWM_ENABLE|PWM_TimeEN); } + else if (rate == 100) + { + // iomux pwm to gpio + rk29_mux_api_set(pdata->pwm_iomux_name, pdata->pwm_iomux_gpio); + //disable pull up or down + gpio_pull_updown(pdata->pwm_gpio,PullDisable); + // set gpio to low level + gpio_direction_output(pdata->pwm_gpio,GPIO_HIGH); + + } else { printk("%s:rate error\n",__func__); @@ -132,8 +145,9 @@ static int pwm_set_rate(struct pwm_platform_data *pdata,int nHz,u32 rate) static int pwm_regulator_list_voltage(struct regulator_dev *dev,unsigned int index) { - if (index < sizeof(pwm_voltage_map)/sizeof(int)) - return pwm_voltage_map[index]; + struct rk_pwm_dcdc *dcdc = rdev_get_drvdata(dev); + if (index < dcdc->desc.n_voltages) + return dcdc->pdata->pwm_voltage_map[index]; else return -1; } @@ -176,15 +190,14 @@ static int pwm_regulator_set_voltage(struct regulator_dev *dev, #endif { struct rk_pwm_dcdc *dcdc = rdev_get_drvdata(dev); - const int *voltage_map = pwm_voltage_map; - - int min_mV = min_uV, max_mA = max_uV; - - u32 size = sizeof(pwm_voltage_map)/sizeof(int), i, vol,pwm_value; + const int *voltage_map = dcdc->pdata->pwm_voltage_map; + int max = dcdc->pdata->max_uV; + int coefficient = dcdc->pdata->coefficient; + u32 size = dcdc->desc.n_voltages, i, vol,pwm_value; DBG("%s: min_uV = %d, max_uV = %d\n",__FUNCTION__, min_uV,max_uV); - if (min_mV < voltage_map[0] ||max_mA > voltage_map[size-1]) + if (min_uV < voltage_map[0] ||max_uV > voltage_map[size-1]) { printk("%s:voltage is out of table\n",__func__); return -EINVAL; @@ -192,7 +205,7 @@ static int pwm_regulator_set_voltage(struct regulator_dev *dev, for (i = 0; i < size; i++) { - if (voltage_map[i] >= min_mV) + if (voltage_map[i] >= min_uV) break; } @@ -201,9 +214,8 @@ static int pwm_regulator_set_voltage(struct regulator_dev *dev, dcdc->pdata->pwm_voltage = vol; - // VDD12 = 1.42 - 0.56*D , 其中D为PWM占空比, - pwm_value = (1325000-vol)/5800; // pwm_value % - + // VDD12 = 1.40 - 0.455*D , 其中D为PWM占空比, + pwm_value = (max-vol)/coefficient/10; // pwm_value %, coefficient *1000 if (pwm_set_rate(dcdc->pdata,1000*1000,pwm_value)!=0) { @@ -242,7 +254,6 @@ static int __devinit pwm_regulator_probe(struct platform_device *pdev) struct pwm_platform_data *pdata = pdev->dev.platform_data; struct rk_pwm_dcdc *dcdc; int pwm_id = pdata->pwm_id; - struct regulator_dev *rdev; int id = pdev->id; int ret ; char gpio_name[20]; @@ -251,8 +262,23 @@ static int __devinit pwm_regulator_probe(struct platform_device *pdev) return -ENODEV; if (!pdata->pwm_voltage) - pdata->pwm_voltage = 1200000; // default 1.2v + pdata->pwm_voltage = 1100000; // default 1.1v + if(!pdata->pwm_voltage_map) + pdata->pwm_voltage_map = pwm_voltage_map; + + if(!pdata->max_uV) + pdata->max_uV = 1400000; + + if(!pdata->min_uV) + pdata->min_uV = 1000000; + + if(pdata->suspend_voltage < pdata->min_uV) + pdata->suspend_voltage = pdata->min_uV; + + if(pdata->suspend_voltage > pdata->max_uV) + pdata->suspend_voltage = pdata->max_uV; + dcdc = kzalloc(sizeof(struct rk_pwm_dcdc), GFP_KERNEL); if (dcdc == NULL) { dev_err(&pdev->dev, "Unable to allocate private data\n"); @@ -263,11 +289,11 @@ static int __devinit pwm_regulator_probe(struct platform_device *pdev) dcdc->desc.name = dcdc->name; dcdc->desc.id = id; dcdc->desc.type = REGULATOR_VOLTAGE; - dcdc->desc.n_voltages = 50; + dcdc->desc.n_voltages = ARRAY_SIZE(pwm_voltage_map); dcdc->desc.ops = &pwm_voltage_ops; dcdc->desc.owner = THIS_MODULE; dcdc->pdata = pdata; - + printk("%s:n_voltages=%d\n",__func__,dcdc->desc.n_voltages); dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev, pdata->init_data, dcdc); if (IS_ERR(dcdc->regulator)) { @@ -297,10 +323,17 @@ static int __devinit pwm_regulator_probe(struct platform_device *pdev) pwm_clk[1] = clk_get(NULL, "pwm23"); clk_enable(pwm_clk[1]); } +#elif defined(CONFIG_ARCH_RK2928) + pwm_clk[0] = clk_get(NULL, "pwm01"); + if (IS_ERR(pwm_clk[0])) { + printk("pwm_clk get error %p\n", pwm_clk[0]); + return -EINVAL; + } + clk_enable(pwm_clk[0]); #endif - - - platform_set_drvdata(pdev, dcdc); + + g_dcdc = dcdc; + platform_set_drvdata(pdev, dcdc); printk(KERN_INFO "pwm_regulator.%d: driver initialized\n",id); return 0; @@ -314,10 +347,73 @@ static int __devinit pwm_regulator_probe(struct platform_device *pdev) } +static int __sramdata g_PWM_REG_LRC = 0; +static int __sramdata g_PWM_REG_HRC = 0; +void pwm_suspend_voltage(void) +{ + struct rk_pwm_dcdc *dcdc = g_dcdc; + int suspend_voltage = 0; + int pwm_id = 0; + + if(!dcdc) + return; + pwm_id = dcdc->pdata->pwm_id; + suspend_voltage = dcdc->pdata->suspend_voltage; + + g_PWM_REG_LRC = pwm_read_reg(pwm_id, PWM_REG_LRC); + g_PWM_REG_HRC = pwm_read_reg(pwm_id,PWM_REG_HRC); + + switch(suspend_voltage) + { + case 1000000: + pwm_write_reg(pwm_id, PWM_REG_LRC, 0x25); + pwm_write_reg(pwm_id,PWM_REG_HRC,0x20); // 1 .00 + break; + + case 1050000: + pwm_write_reg(pwm_id, PWM_REG_LRC, 0x25); + pwm_write_reg(pwm_id,PWM_REG_HRC,0x1c); // 1 .05 + break; + + case 1100000: + pwm_write_reg(pwm_id, PWM_REG_LRC, 0x25); + pwm_write_reg(pwm_id,PWM_REG_HRC,0x18); // 1 .1 + break; + + case 1150000: + pwm_write_reg(pwm_id, PWM_REG_LRC, 0x25); + pwm_write_reg(pwm_id,PWM_REG_HRC,0x13); // 1 .15 + break; + + default: + pwm_write_reg(pwm_id, PWM_REG_LRC, 0x25); + pwm_write_reg(pwm_id,PWM_REG_HRC,0x20); // 1 .00 + break; + + } + +} + +void pwm_resume_voltage(void) + { + struct rk_pwm_dcdc *dcdc = g_dcdc; + int pwm_id = 0; + + if(!dcdc) + return; + pwm_id = dcdc->pdata->pwm_id; + pwm_write_reg(pwm_id, PWM_REG_LRC, g_PWM_REG_LRC); + pwm_write_reg(pwm_id,PWM_REG_HRC, g_PWM_REG_HRC); + +} + + static int pwm_regulator_suspend(struct platform_device *pdev, pm_message_t state) { struct pwm_platform_data *pdata = pdev->dev.platform_data; - pwm_set_rate(pdata,1000*1000,0);//pwm clk will change to 24M after suspend + //struct rk_pwm_dcdc *dcdc = platform_get_drvdata(pdev); + //unsigned selector = 0; + //pwm_regulator_set_voltage(dcdc->regulator, 1100000, 1100000, &selector); DBG("%s,pwm_id=%d\n",__func__,pdata->pwm_id); return 0; } @@ -325,6 +421,9 @@ static int pwm_regulator_suspend(struct platform_device *pdev, pm_message_t stat static int pwm_regulator_resume(struct platform_device *pdev) { struct pwm_platform_data *pdata = pdev->dev.platform_data; + //struct rk_pwm_dcdc *dcdc = platform_get_drvdata(pdev); + //unsigned selector = 0; + //pwm_regulator_set_voltage(dcdc->regulator, 1150000, 1150000, &selector); DBG("%s,pwm_id=%d\n",__func__,pdata->pwm_id); return 0; } @@ -361,7 +460,7 @@ static void __exit pwm_regulator_module_exit(void) } -subsys_initcall(pwm_regulator_module_init); +fs_initcall(pwm_regulator_module_init); module_exit(pwm_regulator_module_exit); diff --git a/include/linux/regulator/rk29-pwm-regulator.h b/include/linux/regulator/rk29-pwm-regulator.h old mode 100644 new mode 100755 index e0a0487d2a85..e74b812f73d3 --- a/include/linux/regulator/rk29-pwm-regulator.h +++ b/include/linux/regulator/rk29-pwm-regulator.h @@ -57,6 +57,11 @@ struct pwm_platform_data { unsigned int pwm_iomux_pwm; int pwm_iomux_gpio; int pwm_voltage; + int suspend_voltage; + int coefficient; + int min_uV; + int max_uV; + int *pwm_voltage_map; struct regulator_init_data *init_data; }; From b514287dc91664abc047bc0b864856d6c9199d35 Mon Sep 17 00:00:00 2001 From: chenxing Date: Wed, 15 Aug 2012 18:39:11 +0800 Subject: [PATCH 189/261] rk30:sdk: dvfs add err info when current voltage out of bound --- arch/arm/mach-rk30/dvfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-rk30/dvfs.c b/arch/arm/mach-rk30/dvfs.c index f1fc2eafe714..a2838794d264 100644 --- a/arch/arm/mach-rk30/dvfs.c +++ b/arch/arm/mach-rk30/dvfs.c @@ -929,7 +929,7 @@ int dvfs_scale_volt_bystep(struct vd_node *vd_clk, struct vd_node *vd_dep, int v if (check_volt_correct(volt_old, &volt_new, volt_dep_old, &volt_dep_new, clk_biger_than_dep, dep_biger_than_clk) < 0) { - DVFS_ERR("CURRENT VOLT INCORRECT\n"); + DVFS_ERR("CURRENT VOLT INCORRECT, VD=%s, VD_DEP=%s\n", vd_clk->name, vd_dep->name); return -1; } DVFS_DBG("ENTER %s, volt=%d(old=%d), volt_dep=%d(dep_old=%d)\n", __func__, From 43e39f9617ad5a24b8b38ebfe625f8ebbe2ccd1e Mon Sep 17 00:00:00 2001 From: chenxing Date: Wed, 15 Aug 2012 20:05:59 +0800 Subject: [PATCH 190/261] rk2928:sdk: use lowest rate when all div rates are higher then request --- arch/arm/mach-rk2928/clock_data.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/mach-rk2928/clock_data.c b/arch/arm/mach-rk2928/clock_data.c index 8b311cc95776..50eb07b4e6f4 100644 --- a/arch/arm/mach-rk2928/clock_data.c +++ b/arch/arm/mach-rk2928/clock_data.c @@ -62,6 +62,7 @@ struct pll_clk_set { #define CLKDATA_LOG(fmt, args...) do {} while(0) #endif #define CLKDATA_ERR(fmt, args...) printk(KERN_ERR "CLKDATA_ERR:\t"fmt, ##args) +#define CLKDATA_WARNNING(fmt, args...) printk("CLKDATA_WANNING:\t"fmt, ##args) #define cru_readl(offset) readl_relaxed(RK2928_CRU_BASE + offset) #define cru_writel(v, offset) do { writel_relaxed(v, RK2928_CRU_BASE + offset); dsb(); } while (0) @@ -330,6 +331,12 @@ static int clksel_set_rate_freediv(struct clk *clk, unsigned long rate) CLKDATA_DBG("clksel_set_rate_freediv for clock %s to rate %ld (div %d)\n", clk->name, rate, div + 1); return 0; } + if (div == clk->div_max - 1) { + CLKDATA_WARNNING("%s clk=%s, div=%u, rate=%lu, new_rate=%u\n", + __func__, clk->name, div, rate, new_rate); + set_cru_bits_w_msk(div,clk->div_mask,clk->div_shift,clk->clksel_con); + return 0; + } } return -ENOENT; } From 24424b7461bf0713d612fed1bfa8de9dea1be006 Mon Sep 17 00:00:00 2001 From: gwl Date: Wed, 15 Aug 2012 21:08:54 +0800 Subject: [PATCH 191/261] Add wifi reset control (for RK2928) --- arch/arm/mach-rk2928/board-rk2928-sdk-sdmmc.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-rk2928/board-rk2928-sdk-sdmmc.c b/arch/arm/mach-rk2928/board-rk2928-sdk-sdmmc.c index e74fb1ab7ab0..69be61c317f1 100644 --- a/arch/arm/mach-rk2928/board-rk2928-sdk-sdmmc.c +++ b/arch/arm/mach-rk2928/board-rk2928-sdk-sdmmc.c @@ -203,6 +203,7 @@ static void rk29_sdmmc_set_iomux(int device_id, unsigned int bus_width) #ifdef CONFIG_WIFI_CONTROL_FUNC #define RK30SDK_WIFI_GPIO_POWER_N RK2928_PIN0_PD6 +#define RK29SDK_WIFI_GPIO_RESET_N RK2928_PIN3_PC2 #define PREALLOC_WLAN_SEC_NUM 4 #define PREALLOC_WLAN_BUF_NUM 160 @@ -309,12 +310,12 @@ static int __init rk29sdk_wifi_bt_gpio_control_init(void) return -1; } - /*if (gpio_request(RK29SDK_WIFI_GPIO_RESET_N, "wifi reset")) { + if (gpio_request(RK29SDK_WIFI_GPIO_RESET_N, "wifi reset")) { pr_info("%s: request wifi reset gpio failed\n", __func__); gpio_free(RK30SDK_WIFI_GPIO_POWER_N); return -1; } - + /* if (gpio_request(RK29SDK_BT_GPIO_RESET_N, "bt reset")) { pr_info("%s: request bt reset gpio failed\n", __func__); gpio_free(RK29SDK_WIFI_GPIO_RESET_N); @@ -322,7 +323,7 @@ static int __init rk29sdk_wifi_bt_gpio_control_init(void) }*/ gpio_direction_output(RK30SDK_WIFI_GPIO_POWER_N, GPIO_LOW); - //gpio_direction_output(RK29SDK_WIFI_GPIO_RESET_N, GPIO_LOW); + gpio_direction_output(RK29SDK_WIFI_GPIO_RESET_N, GPIO_LOW); //gpio_direction_output(RK29SDK_BT_GPIO_RESET_N, GPIO_LOW); #if defined(CONFIG_SDMMC1_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) @@ -351,12 +352,12 @@ static int rk29sdk_wifi_power(int on) pr_info("%s: %d\n", __func__, on); if (on){ gpio_set_value(RK30SDK_WIFI_GPIO_POWER_N, GPIO_HIGH); - + mdelay(50); #if defined(CONFIG_SDMMC1_RK29) && !defined(CONFIG_SDMMC_RK29_OLD) rk29_sdmmc_gpio_open(1, 1); //added by xbw at 2011-10-13 #endif - //gpio_set_value(RK29SDK_WIFI_GPIO_RESET_N, GPIO_HIGH); + gpio_set_value(RK29SDK_WIFI_GPIO_RESET_N, GPIO_HIGH); mdelay(100); pr_info("wifi turn on power\n"); }else{ @@ -373,7 +374,7 @@ static int rk29sdk_wifi_power(int on) // { // pr_info("wifi shouldn't shut off power, bt is using it!\n"); // } - //gpio_set_value(RK29SDK_WIFI_GPIO_RESET_N, GPIO_LOW); + gpio_set_value(RK29SDK_WIFI_GPIO_RESET_N, GPIO_LOW); } @@ -385,8 +386,8 @@ static int rk29sdk_wifi_reset_state; static int rk29sdk_wifi_reset(int on) { pr_info("%s: %d\n", __func__, on); - //gpio_set_value(RK29SDK_WIFI_GPIO_RESET_N, on); - //mdelay(100); + gpio_set_value(RK29SDK_WIFI_GPIO_RESET_N, on); + mdelay(100); rk29sdk_wifi_reset_state = on; return 0; } From bbc68b65d9fbba7bb10cf89644e4d984f536c059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Wed, 15 Aug 2012 10:41:41 +0800 Subject: [PATCH 192/261] i2c: rk: only rk29/rk30 need idle lock --- drivers/i2c/busses/i2c-rk29.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/i2c/busses/i2c-rk29.c b/drivers/i2c/busses/i2c-rk29.c index 69af912074c8..4e5f1e136751 100755 --- a/drivers/i2c/busses/i2c-rk29.c +++ b/drivers/i2c/busses/i2c-rk29.c @@ -111,7 +111,9 @@ struct rk29_i2c_data { #endif }; +#if defined(CONFIG_ARCH_RK29) || defined(CONFIG_ARCH_RK30) static struct wake_lock idlelock; /* only for i2c0 */ +#endif static void rk29_set_ack(struct rk29_i2c_data *i2c) { @@ -558,8 +560,10 @@ static int rk29_i2c_xfer(struct i2c_adapter *adap, i2c->udelay_time = RK29_UDELAY_TIME(i2c->scl_rate); i2c->ack_timeout = RK29_I2C_ACK_TIMEOUT_COUNT * i2c->udelay_time; +#if defined(CONFIG_ARCH_RK29) || defined(CONFIG_ARCH_RK30) if (adap->nr == 0) wake_lock(&idlelock); +#endif for (i = 0; i < num; i++) { @@ -572,8 +576,10 @@ static int rk29_i2c_xfer(struct i2c_adapter *adap, } } +#if defined(CONFIG_ARCH_RK29) || defined(CONFIG_ARCH_RK30) if (adap->nr == 0) wake_unlock(&idlelock); +#endif /* if( --retry && num < 0) @@ -887,7 +893,9 @@ static struct platform_driver rk29_i2c_driver = { static int __init rk29_i2c_adap_init(void) { +#if defined(CONFIG_ARCH_RK29) || defined(CONFIG_ARCH_RK30) wake_lock_init(&idlelock, WAKE_LOCK_IDLE, "i2c0"); +#endif return platform_driver_register(&rk29_i2c_driver); } From 7db28b5ce2007ca5440b4c03561f4493352671b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Thu, 16 Aug 2012 09:18:32 +0800 Subject: [PATCH 193/261] rk2928: sram: fix loop use Thumb instruction set --- arch/arm/mach-rk2928/include/mach/sram.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-rk2928/include/mach/sram.h b/arch/arm/mach-rk2928/include/mach/sram.h index eba76bccf64d..4dec061dfeca 100644 --- a/arch/arm/mach-rk2928/include/mach/sram.h +++ b/arch/arm/mach-rk2928/include/mach/sram.h @@ -4,7 +4,7 @@ #include #define SRAM_LOOPS_PER_USEC 24 -#define SRAM_LOOP(loops) do { unsigned int i = (loops); if (i < 7) i = 7; barrier(); while (--i) barrier(); } while (0) +#define SRAM_LOOP(loops) do { unsigned int i = (loops); if (i < 7) i = 7; barrier(); asm volatile(".align 4; 1: subs %0, %0, #1; bne 1b;" : "+r" (i)); } while (0) /* delay on slow mode */ #define sram_udelay(usecs) SRAM_LOOP((usecs)*SRAM_LOOPS_PER_USEC) /* delay on deep slow mode */ From c5066ca24849fdb2e6ea4095b276c7567c7291b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Thu, 16 Aug 2012 09:43:53 +0800 Subject: [PATCH 194/261] rk2928: add initial pm support --- arch/arm/mach-rk2928/pm.c | 453 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 453 insertions(+) diff --git a/arch/arm/mach-rk2928/pm.c b/arch/arm/mach-rk2928/pm.c index b8bcc0292339..0591da0f482f 100755 --- a/arch/arm/mach-rk2928/pm.c +++ b/arch/arm/mach-rk2928/pm.c @@ -14,13 +14,47 @@ #include #include +#include +#include #include #include #include +#include +#include + +#define cru_readl(offset) readl_relaxed(RK2928_CRU_BASE + offset) +#define cru_writel(v, offset) do { writel_relaxed(v, RK2928_CRU_BASE + offset); dsb(); } while (0) + +#define grf_readl(offset) readl_relaxed(RK2928_GRF_BASE + offset) +#define grf_writel(v, offset) do { writel_relaxed(v, RK2928_GRF_BASE + offset); dsb(); } while (0) + +#define gate_save_soc_clk(val, _save, cons, w_msk) \ + do { \ + (_save) = cru_readl(cons); \ + cru_writel(((~(val) | (_save)) & (w_msk)) | ((w_msk) << 16), cons); \ + } while (0) void __sramfunc sram_printch(char byte) { #ifdef DEBUG_UART_BASE + u32 clk_gate2, clk_gate4, clk_gate8; + + gate_save_soc_clk(0 + | (1 << CLK_GATE_ACLK_PERIPH % 16) + | (1 << CLK_GATE_HCLK_PERIPH % 16) + | (1 << CLK_GATE_PCLK_PERIPH % 16) + , clk_gate2, CRU_CLKGATES_CON(2), 0 + | (1 << ((CLK_GATE_ACLK_PERIPH % 16) + 16)) + | (1 << ((CLK_GATE_HCLK_PERIPH % 16) + 16)) + | (1 << ((CLK_GATE_PCLK_PERIPH % 16) + 16))); + gate_save_soc_clk((1 << CLK_GATE_ACLK_CPU_PERI % 16) + , clk_gate4, CRU_CLKGATES_CON(4), + (1 << ((CLK_GATE_ACLK_CPU_PERI % 16) + 16))); + gate_save_soc_clk((1 << ((CLK_GATE_PCLK_UART0 + CONFIG_RK_DEBUG_UART) % 16)), + clk_gate8, CRU_CLKGATES_CON(8), + (1 << (((CLK_GATE_PCLK_UART0 + CONFIG_RK_DEBUG_UART) % 16) + 16))); + sram_udelay(1); + writel_relaxed(byte, DEBUG_UART_BASE); dsb(); @@ -28,8 +62,427 @@ void __sramfunc sram_printch(char byte) while (!(readl_relaxed(DEBUG_UART_BASE + 0x14) & 0x40)) barrier(); + cru_writel(0xffff0000 | clk_gate2, CRU_CLKGATES_CON(2)); + cru_writel(0xffff0000 | clk_gate4, CRU_CLKGATES_CON(4)); + cru_writel(0xffff0000 | clk_gate8, CRU_CLKGATES_CON(8)); + if (byte == '\n') sram_printch('\r'); #endif } +__weak void __sramfunc ddr_suspend(void) {} +__weak void __sramfunc ddr_resume(void) {} +__weak uint32_t __sramfunc ddr_change_freq(uint32_t nMHz) { return nMHz; } + +#ifdef CONFIG_DDR_TEST +static int ddr_debug=0; +module_param(ddr_debug, int, 0644); + +static int inline calc_crc32(u32 addr, size_t len) +{ + return crc32_le(~0, (const unsigned char *)addr, len); +} + +static void ddr_testmode(void) +{ + int32_t g_crc1, g_crc2; + uint32_t nMHz; + uint32_t n = 0; + uint32_t min,max; + extern char _stext[], _etext[]; + + + if (ddr_debug == 1) { + max=500; + min=100; + for (;;) { + sram_printascii("\n change freq:"); + g_crc1 = calc_crc32((u32)_stext, (size_t)(_etext-_stext)); + do + { + nMHz = min + random32(); + nMHz %= max; + }while(nMHz < min); + sram_printhex(nMHz); + sram_printch(' '); + nMHz = ddr_change_freq(nMHz); + sram_printhex(n++); + sram_printch(' '); + g_crc2 = calc_crc32((u32)_stext, (size_t)(_etext-_stext)); + if (g_crc1!=g_crc2) { + sram_printascii("fail\n"); + } + //ddr_print("check image crc32 success--crc value = 0x%x!, count:%d\n",g_crc1, n++); + // sram_printascii("change freq success\n"); + } + } else if(ddr_debug == 2) { + for (;;) { + sram_printch(' '); + sram_printch('9'); + sram_printch('9'); + sram_printch('9'); + sram_printch(' '); + g_crc1 = calc_crc32((u32)_stext, (size_t)(_etext-_stext)); + nMHz = (random32()>>13);// 16.7s max + ddr_suspend(); + sram_udelay(nMHz); + ddr_resume(); + sram_printhex(nMHz); + sram_printch(' '); + sram_printhex(n++); + g_crc2 = calc_crc32((u32)_stext, (size_t)(_etext-_stext)); + if (g_crc1 != g_crc2) { + sram_printch(' '); + sram_printch('f'); + sram_printch('a'); + sram_printch('i'); + sram_printch('l'); + } + // ddr_print("check image crc32 fail!, count:%d\n", n++); + // sram_printascii("self refresh fail\n"); + //else + //ddr_print("check image crc32 success--crc value = 0x%x!, count:%d\n",g_crc1, n++); + // sram_printascii("self refresh success\n"); + } + } else if (ddr_debug == 3) { + extern int memtester(void); + memtester(); + } + else + { + ddr_change_freq(ddr_debug); + ddr_debug=0; + } +} +#else +static void ddr_testmode(void) {} +#endif + +static noinline void rk2928_pm_dump_irq(void) +{ + u32 irq_gpio = (readl_relaxed(RK2928_GICD_BASE + GIC_DIST_PENDING_SET + (IRQ_GPIO0 / 32) * 4) >> (IRQ_GPIO0 % 32)) & 0xF; + printk("wakeup irq: %08x %08x %08x\n", + readl_relaxed(RK2928_GICD_BASE + GIC_DIST_PENDING_SET + 4), + readl_relaxed(RK2928_GICD_BASE + GIC_DIST_PENDING_SET + 8), + readl_relaxed(RK2928_GICD_BASE + GIC_DIST_PENDING_SET + 12)); + if (irq_gpio & 1) + printk("wakeup gpio0: %08x\n", readl_relaxed(RK2928_GPIO0_BASE + GPIO_INT_STATUS)); + if (irq_gpio & 2) + printk("wakeup gpio1: %08x\n", readl_relaxed(RK2928_GPIO1_BASE + GPIO_INT_STATUS)); + if (irq_gpio & 4) + printk("wakeup gpio2: %08x\n", readl_relaxed(RK2928_GPIO2_BASE + GPIO_INT_STATUS)); + if (irq_gpio & 8) + printk("wakeup gpio3: %08x\n", readl_relaxed(RK2928_GPIO3_BASE + GPIO_INT_STATUS)); +} + +#define DUMP_GPIO_INTEN(ID) \ +do { \ + u32 en = readl_relaxed(RK2928_GPIO##ID##_BASE + GPIO_INTEN); \ + if (en) { \ + sram_printascii("GPIO" #ID "_INTEN: "); \ + sram_printhex(en); \ + sram_printch('\n'); \ + } \ +} while (0) + +static noinline void rk2928_pm_dump_inten(void) +{ + DUMP_GPIO_INTEN(0); + DUMP_GPIO_INTEN(1); + DUMP_GPIO_INTEN(2); + DUMP_GPIO_INTEN(3); +} + +static void pm_pll_wait_lock(int pll_idx) +{ + u32 pll_state[4] = { 1, 0, 2, 3 }; + u32 bit = 0x10u << pll_state[pll_idx]; + u32 delay = pll_idx == APLL_ID ? 24000000U : 2400000000U; + while (delay > 0) { + if (grf_readl(GRF_SOC_STATUS0) & bit) + break; + delay--; + } + if (delay == 0) { + //CRU_PRINTK_ERR("wait pll bit 0x%x time out!\n", bit); + sram_printch('p'); + sram_printch('l'); + sram_printch('l'); + sram_printhex(pll_idx); + sram_printch('\n'); + } +} + +#define power_on_pll(id) \ + cru_writel(PLL_PWR_DN_W_MSK|PLL_PWR_ON,PLL_CONS((id),3));\ + pm_pll_wait_lock((id)) + +#define DDR_SAVE_SP(save_sp) do { save_sp = ddr_save_sp(((unsigned long)SRAM_DATA_END & (~7))); } while (0) +#define DDR_RESTORE_SP(save_sp) do { ddr_save_sp(save_sp); } while (0) + +static unsigned long save_sp; + +static noinline void interface_ctr_reg_pread(void) +{ + u32 addr; + + flush_cache_all(); + outer_flush_all(); + local_flush_tlb_all(); + + for (addr = (u32)SRAM_CODE_OFFSET; addr < (u32)SRAM_DATA_END; addr += PAGE_SIZE) + readl_relaxed(addr); + readl_relaxed(RK2928_GRF_BASE); + readl_relaxed(RK2928_DDR_PCTL_BASE); + readl_relaxed(RK2928_DDR_PHY_BASE); +// readl_relaxed(RK2928_I2C1_BASE); +} + +__weak void board_gpio_suspend(void) {} +__weak void board_gpio_resume(void) {} +__weak void __sramfunc board_pmu_suspend(void) {} +__weak void __sramfunc board_pmu_resume(void) {} +__weak void __sramfunc rk30_suspend_voltage_set(unsigned int vol) {} +__weak void __sramfunc rk30_suspend_voltage_resume(unsigned int vol) {} + +__weak void rk30_pwm_suspend_voltage_set(void) {} +__weak void rk30_pwm_resume_voltage_set(void) {} + +__weak void __sramfunc rk30_pwm_logic_suspend_voltage(void) {} +__weak void __sramfunc rk30_pwm_logic_resume_voltage(void) {} + +static void __sramfunc rk2928_sram_suspend(void) +{ + u32 cru_clksel0_con; + u32 clkgt_regs[CRU_CLKGATES_CON_CNT]; + int i; + + sram_printch('5'); + ddr_suspend(); + sram_printch('6'); + rk30_suspend_voltage_set(1000000); + rk30_pwm_logic_suspend_voltage(); + sram_printch('7'); + + for (i = 0; i < CRU_CLKGATES_CON_CNT; i++) { + clkgt_regs[i] = cru_readl(CRU_CLKGATES_CON(i)); + } + gate_save_soc_clk(0 + | (1 << CLK_GATE_CORE_PERIPH) + | (1 << CLK_GATE_DDRPHY_SRC) + | (1 << CLK_GATE_ACLK_CPU) + | (1 << CLK_GATE_HCLK_CPU) + | (1 << CLK_GATE_PCLK_CPU) + | (1 << CLK_GATE_ACLK_CORE) + , clkgt_regs[0], CRU_CLKGATES_CON(0), 0xffff); + if (!(clkgt_regs[8] & (0xf << (CLK_GATE_PCLK_GPIO0 % 16)))) { + gate_save_soc_clk(0 + | (1 << CLK_GATE_PERIPH_SRC % 16) + | (1 << CLK_GATE_PCLK_PERIPH % 16) + , clkgt_regs[2], CRU_CLKGATES_CON(2), 0xffff); + } else { + gate_save_soc_clk(0, clkgt_regs[2], CRU_CLKGATES_CON(2), 0xffff); + } + gate_save_soc_clk(0 + | (1 << CLK_GATE_ACLK_STRC_SYS % 16) + | (1 << CLK_GATE_ACLK_INTMEM % 16) + , clkgt_regs[4], CRU_CLKGATES_CON(4), 0xffff); + gate_save_soc_clk(0 + | (1 << CLK_GATE_PCLK_GRF % 16) + | (1 << CLK_GATE_PCLK_DDRUPCTL % 16) + , clkgt_regs[5], CRU_CLKGATES_CON(5), 0xffff); + gate_save_soc_clk(0, clkgt_regs[7], CRU_CLKGATES_CON(7), 0xffff); + gate_save_soc_clk(0 + | (1 << CLK_GATE_CLK_L2C % 16) + , clkgt_regs[9], CRU_CLKGATES_CON(9), 0x07ff); + + board_pmu_suspend(); + cru_clksel0_con = cru_readl(CRU_CLKSELS_CON(0)); + cru_writel((0x1f << 16) | 0x1f, CRU_CLKSELS_CON(0)); + + dsb(); + wfi(); + + cru_writel((0x1f << 16) | cru_clksel0_con, CRU_CLKSELS_CON(0)); + board_pmu_resume(); + + for (i = 0; i < CRU_CLKGATES_CON_CNT; i++) { + cru_writel(clkgt_regs[i] | 0xffff0000, CRU_CLKGATES_CON(i)); + } + + sram_printch('7'); + rk30_pwm_logic_resume_voltage(); + rk30_suspend_voltage_resume(1100000); + + sram_printch('6'); + ddr_resume(); + sram_printch('5'); +} + +static void noinline rk2928_suspend(void) +{ + DDR_SAVE_SP(save_sp); + rk2928_sram_suspend(); + DDR_RESTORE_SP(save_sp); +} + +static int rk2928_pm_enter(suspend_state_t state) +{ + u32 i; + u32 clkgt_regs[CRU_CLKGATES_CON_CNT]; + u32 clk_sel0, clk_sel1, clk_sel10; + u32 cru_mode_con; + + // dump GPIO INTEN for debug + rk2928_pm_dump_inten(); + + sram_printch('0'); + +#ifdef CONFIG_DDR_TEST + // memory tester + if (ddr_debug != 0) + ddr_testmode(); +#endif + + sram_printch('1'); + local_fiq_disable(); + + for (i = 0; i < CRU_CLKGATES_CON_CNT; i++) { + clkgt_regs[i] = cru_readl(CRU_CLKGATES_CON(i)); + } + + gate_save_soc_clk(0 + | (1 << CLK_GATE_CORE_PERIPH) + | (1 << CLK_GATE_DDRPHY_SRC) + | (1 << CLK_GATE_ACLK_CPU) + | (1 << CLK_GATE_HCLK_CPU) + | (1 << CLK_GATE_PCLK_CPU) + | (1 << CLK_GATE_ACLK_CORE) + , clkgt_regs[0], CRU_CLKGATES_CON(0), 0xffff); + gate_save_soc_clk(0, clkgt_regs[1], CRU_CLKGATES_CON(1), 0xffff); + gate_save_soc_clk(0 + | (1 << CLK_GATE_PERIPH_SRC % 16) + | (1 << CLK_GATE_PCLK_PERIPH % 16) + | (1 << CLK_GATE_ACLK_PERIPH % 16) + , clkgt_regs[2], CRU_CLKGATES_CON(2), 0xffff); + gate_save_soc_clk(0, clkgt_regs[3], CRU_CLKGATES_CON(3), 0xff9f); + gate_save_soc_clk(0 + | (1 << CLK_GATE_HCLK_PERI_AXI_MATRIX % 16) + | (1 << CLK_GATE_PCLK_PERI_AXI_MATRIX % 16) + | (1 << CLK_GATE_ACLK_CPU_PERI % 16) + | (1 << CLK_GATE_ACLK_PERI_AXI_MATRIX % 16) + | (1 << CLK_GATE_ACLK_STRC_SYS % 16) + | (1 << CLK_GATE_ACLK_INTMEM % 16) + , clkgt_regs[4], CRU_CLKGATES_CON(4), 0xffff); + gate_save_soc_clk(0 + | (1 << CLK_GATE_PCLK_GRF % 16) + | (1 << CLK_GATE_PCLK_DDRUPCTL % 16) + , clkgt_regs[5], CRU_CLKGATES_CON(5), 0xffff); + gate_save_soc_clk(0, clkgt_regs[6], CRU_CLKGATES_CON(6), 0xffff); + gate_save_soc_clk(0 + |(1 << CLK_GATE_PCLK_PWM01%16) + , clkgt_regs[7], CRU_CLKGATES_CON(7), 0xffff); + gate_save_soc_clk(0, clkgt_regs[8], CRU_CLKGATES_CON(8), 0x01ff); + gate_save_soc_clk(0 + | (1 << CLK_GATE_CLK_L2C % 16) + | (1 << CLK_GATE_HCLK_PERI_ARBI % 16) + | (1 << CLK_GATE_ACLK_PERI_NIU % 16) + , clkgt_regs[9], CRU_CLKGATES_CON(9), 0x07ff); + + sram_printch('2'); + + cru_mode_con = cru_readl(CRU_MODE_CON); + + //cpll + cru_writel(PLL_MODE_SLOW(CPLL_ID), CRU_MODE_CON); + + //gpll + clk_sel10 = cru_readl(CRU_CLKSELS_CON(10)); + cru_writel(PLL_MODE_SLOW(GPLL_ID), CRU_MODE_CON); + cru_writel(PERI_SET_ACLK_DIV(1) + | PERI_SET_A2H_RATIO(RATIO_11) + | PERI_SET_A2P_RATIO(RATIO_11) + , CRU_CLKSELS_CON(10)); + + //apll + clk_sel0 = cru_readl(CRU_CLKSELS_CON(0)); + clk_sel1 = cru_readl(CRU_CLKSELS_CON(1)); + cru_writel(PLL_MODE_SLOW(APLL_ID), CRU_MODE_CON); + cru_writel(CLK_CORE_DIV(1) | ACLK_CPU_DIV(1), CRU_CLKSELS_CON(0)); + cru_writel(CLK_CORE_PERI_DIV(1) | ACLK_CORE_DIV(1) | HCLK_CPU_DIV(1) | PCLK_CPU_DIV(1), CRU_CLKSELS_CON(1)); + + sram_printch('3'); + rk30_pwm_suspend_voltage_set(); + + board_gpio_suspend(); + + interface_ctr_reg_pread(); + + sram_printch('4'); + rk2928_suspend(); + sram_printch('4'); + + board_gpio_resume(); + rk30_pwm_resume_voltage_set(); + sram_printch('3'); + + //apll + cru_writel(0xffff0000 | clk_sel1, CRU_CLKSELS_CON(1)); + cru_writel(0xffff0000 | clk_sel0, CRU_CLKSELS_CON(0)); + cru_writel((PLL_MODE_MSK(APLL_ID) << 16) | (PLL_MODE_MSK(APLL_ID) & cru_mode_con), CRU_MODE_CON); + + //gpll + cru_writel(0xffff0000 | clk_sel10, CRU_CLKSELS_CON(10)); + cru_writel(clk_sel10, CRU_CLKSELS_CON(10)); + cru_writel((PLL_MODE_MSK(GPLL_ID) << 16) | (PLL_MODE_MSK(GPLL_ID) & cru_mode_con), CRU_MODE_CON); + + //cpll + cru_writel((PLL_MODE_MSK(CPLL_ID) << 16) | (PLL_MODE_MSK(CPLL_ID) & cru_mode_con), CRU_MODE_CON); + + sram_printch('2'); + + for (i = 0; i < CRU_CLKGATES_CON_CNT; i++) { + cru_writel(clkgt_regs[i] | 0xffff0000, CRU_CLKGATES_CON(i)); + } + + local_fiq_enable(); + sram_printch('1'); + + sram_printascii("0\n"); + + rk2928_pm_dump_irq(); + + return 0; +} + +static int rk2928_pm_prepare(void) +{ + /* disable entering idle by disable_hlt() */ + disable_hlt(); + return 0; +} + +static void rk2928_pm_finish(void) +{ + enable_hlt(); +} + +static struct platform_suspend_ops rk2928_pm_ops = { + .enter = rk2928_pm_enter, + .valid = suspend_valid_only_mem, + .prepare = rk2928_pm_prepare, + .finish = rk2928_pm_finish, +}; + +static int __init rk2928_pm_init(void) +{ + suspend_set_ops(&rk2928_pm_ops); + +#ifdef CONFIG_EARLYSUSPEND + pm_set_vt_switch(0); /* disable vt switch while suspend */ +#endif + + return 0; +} +__initcall(rk2928_pm_init); From 278d2a1ab231c04241452583bf3f55bc45202aac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Thu, 16 Aug 2012 11:51:17 +0800 Subject: [PATCH 195/261] gpio: rk2928: enable support rk30_gpiolib_pull_updown --- drivers/gpio/gpio-rk30.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-rk30.c b/drivers/gpio/gpio-rk30.c index 14417a33a4a9..911636cf49c1 100755 --- a/drivers/gpio/gpio-rk30.c +++ b/drivers/gpio/gpio-rk30.c @@ -318,10 +318,9 @@ static void rk30_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val) spin_unlock_irqrestore(&bank->lock, flags); } - static int rk30_gpiolib_pull_updown(struct gpio_chip *chip, unsigned offset, unsigned enable) { -#if defined(CONFIG_ARCH_RK30) +#if defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK2928) struct rk30_gpio_bank *bank = to_rk30_gpio_bank(chip); unsigned long flags; @@ -335,7 +334,6 @@ static int rk30_gpiolib_pull_updown(struct gpio_chip *chip, unsigned offset, uns return 0; } - static int rk30_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset) { return chip->base + offset; From 0f084084478be55633d9bdf17a17307a3f883dac Mon Sep 17 00:00:00 2001 From: ywj Date: Thu, 16 Aug 2012 14:25:47 +0800 Subject: [PATCH 196/261] add gsensor orientation node for factorytool --- drivers/input/sensors/accel/kxtik.c | 602 +++++++++++--------- drivers/input/sensors/accel/lis3dh.c | 757 ++++++++++++++------------ drivers/input/sensors/accel/mma8452.c | 681 ++++++++++++----------- 3 files changed, 1121 insertions(+), 919 deletions(-) diff --git a/drivers/input/sensors/accel/kxtik.c b/drivers/input/sensors/accel/kxtik.c index ba131f729536..e9c5a754985d 100755 --- a/drivers/input/sensors/accel/kxtik.c +++ b/drivers/input/sensors/accel/kxtik.c @@ -1,268 +1,334 @@ -/* drivers/input/sensors/access/kxtik.c - * - * Copyright (C) 2012-2015 ROCKCHIP. - * Author: luowei - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_HAS_EARLYSUSPEND -#include -#endif -#include -#include - -#if 0 -#define SENSOR_DEBUG_TYPE SENSOR_TYPE_ACCEL -#define DBG(x...) if(sensor->pdata->type == SENSOR_DEBUG_TYPE) printk(x) -#else -#define DBG(x...) -#endif - - - -/****************operate according to sensor chip:start************/ - -static int sensor_active(struct i2c_client *client, int enable, int rate) -{ - struct sensor_private_data *sensor = - (struct sensor_private_data *) i2c_get_clientdata(client); - int result = 0; - int status = 0; - - sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg); - - //register setting according to chip datasheet - if(enable) - { - status = KXTIK_ENABLE; //kxtik - sensor->ops->ctrl_data |= status; - } - else - { - status = ~KXTIK_ENABLE; //kxtik - sensor->ops->ctrl_data &= status; - } - - DBG("%s:reg=0x%x,reg_ctrl=0x%x,enable=%d\n",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable); - result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); - if(result) - printk("%s:fail to active sensor\n",__func__); - - return result; - -} - -static int sensor_init(struct i2c_client *client) -{ - struct sensor_private_data *sensor = - (struct sensor_private_data *) i2c_get_clientdata(client); - int result = 0; - - result = sensor->ops->active(client,0,0); - if(result) - { - printk("%s:line=%d,error\n",__func__,__LINE__); - return result; - } - - sensor->status_cur = SENSOR_OFF; - - result = sensor_write_reg(client, KXTIK_DATA_CTRL_REG, KXTIK_ODR400F); - if(result) - { - printk("%s:line=%d,error\n",__func__,__LINE__); - return result; - } - - if(sensor->pdata->irq_enable) //open interrupt - { - result = sensor_write_reg(client, KXTIK_INT_CTRL_REG1, 0x34);//enable int,active high,need read INT_REL - if(result) - { - printk("%s:line=%d,error\n",__func__,__LINE__); - return result; - } - } - - sensor->ops->ctrl_data = (KXTIK_RES_12BIT | KXTIK_G_2G); - result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); - if(result) - { - printk("%s:line=%d,error\n",__func__,__LINE__); - return result; - } - - return result; -} - -static int sensor_convert_data(struct i2c_client *client, char high_byte, char low_byte) -{ - s64 result; - struct sensor_private_data *sensor = - (struct sensor_private_data *) i2c_get_clientdata(client); - //int precision = sensor->ops->precision; - switch (sensor->devid) { - case KXTIK_DEVID: - result = (((int)high_byte << 8) | ((int)low_byte ))>>4; - if (result < KXTIK_BOUNDARY) - result = result* KXTIK_GRAVITY_STEP; - else - result = ~( ((~result & (0x7fff>>(16-KXTIK_PRECISION)) ) + 1) - * KXTIK_GRAVITY_STEP) + 1; - break; - - default: - printk(KERN_ERR "%s: devid wasn't set correctly\n",__func__); - return -EFAULT; - } - - return (int)result; -} - -static int gsensor_report_value(struct i2c_client *client, struct sensor_axis *axis) -{ - struct sensor_private_data *sensor = - (struct sensor_private_data *) i2c_get_clientdata(client); - - /* Report acceleration sensor information */ - input_report_abs(sensor->input_dev, ABS_X, axis->x); - input_report_abs(sensor->input_dev, ABS_Y, axis->y); - input_report_abs(sensor->input_dev, ABS_Z, axis->z); - input_sync(sensor->input_dev); - DBG("Gsensor x==%d y==%d z==%d\n",axis->x,axis->y,axis->z); - - return 0; -} - -#define GSENSOR_MIN 10 -static int sensor_report_value(struct i2c_client *client) -{ - struct sensor_private_data *sensor = - (struct sensor_private_data *) i2c_get_clientdata(client); - struct sensor_platform_data *pdata = sensor->pdata; - int ret = 0; - int x,y,z; - struct sensor_axis axis; - char buffer[6] = {0}; - char value = 0; - - if(sensor->ops->read_len < 6) //sensor->ops->read_len = 6 - { - printk("%s:lenth is error,len=%d\n",__func__,sensor->ops->read_len); - return -1; - } - - memset(buffer, 0, 6); - - /* Data bytes from hardware xL, xH, yL, yH, zL, zH */ - do { - *buffer = sensor->ops->read_reg; - ret = sensor_rx_data(client, buffer, sensor->ops->read_len); - if (ret < 0) - return ret; - } while (0); - - //this gsensor need 6 bytes buffer - x = sensor_convert_data(sensor->client, buffer[1], buffer[0]); //buffer[1]:high bit - y = sensor_convert_data(sensor->client, buffer[3], buffer[2]); - z = sensor_convert_data(sensor->client, buffer[5], buffer[4]); - - axis.x = (pdata->orientation[0])*x + (pdata->orientation[1])*y + (pdata->orientation[2])*z; - axis.y = (pdata->orientation[3])*x + (pdata->orientation[4])*y + (pdata->orientation[5])*z; - axis.z = (pdata->orientation[6])*x + (pdata->orientation[7])*y + (pdata->orientation[8])*z; - - DBG( "%s: axis = %d %d %d \n", __func__, axis.x, axis.y, axis.z); - - //Report event only while value is changed to save some power - if((abs(sensor->axis.x - axis.x) > GSENSOR_MIN) || (abs(sensor->axis.y - axis.y) > GSENSOR_MIN) || (abs(sensor->axis.z - axis.z) > GSENSOR_MIN)) - { - gsensor_report_value(client, &axis); - - /* 互斥地缓存数据. */ - mutex_lock(&(sensor->data_mutex) ); - sensor->axis = axis; - mutex_unlock(&(sensor->data_mutex) ); - } - - if((sensor->pdata->irq_enable)&& (sensor->ops->int_status_reg >= 0)) //read sensor intterupt status register - { - - value = sensor_read_reg(client, sensor->ops->int_status_reg); - DBG("%s:sensor int status :0x%x\n",__func__,value); - } - - return ret; -} - -struct sensor_operate gsensor_ops = { - .name = "kxtik", - .type = SENSOR_TYPE_ACCEL, //sensor type and it should be correct - .id_i2c = ACCEL_ID_KXTIK, //i2c id number - .read_reg = KXTIK_XOUT_L, //read data - .read_len = 6, //data length - .id_reg = KXTIK_WHO_AM_I, //read device id from this register - .id_data = KXTIK_DEVID, //device id - .precision = KXTIK_PRECISION, //12 bits - .ctrl_reg = KXTIK_CTRL_REG1, //enable or disable - .int_status_reg = KXTIK_INT_REL, //intterupt status register - .range = {-KXTIK_RANGE,KXTIK_RANGE}, //range - .trig = IRQF_TRIGGER_LOW|IRQF_ONESHOT, - .active = sensor_active, - .init = sensor_init, - .report = sensor_report_value, -}; - -/****************operate according to sensor chip:end************/ - -//function name should not be changed -struct sensor_operate *gsensor_get_ops(void) -{ - return &gsensor_ops; -} - -EXPORT_SYMBOL(gsensor_get_ops); - -static int __init gsensor_init(void) -{ - struct sensor_operate *ops = gsensor_get_ops(); - int result = 0; - int type = ops->type; - result = sensor_register_slave(type, NULL, NULL, gsensor_get_ops); - printk("%s\n",__func__); - return result; -} - -static void __exit gsensor_exit(void) -{ - struct sensor_operate *ops = gsensor_get_ops(); - int type = ops->type; - sensor_unregister_slave(type, NULL, NULL, gsensor_get_ops); -} - - -module_init(gsensor_init); -module_exit(gsensor_exit); - - +/* drivers/input/sensors/access/kxtik.c + * + * Copyright (C) 2012-2015 ROCKCHIP. + * Author: luowei + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include + +#if 0 +#define SENSOR_DEBUG_TYPE SENSOR_TYPE_ACCEL +#define DBG(x...) if(sensor->pdata->type == SENSOR_DEBUG_TYPE) printk(x) +#else +#define DBG(x...) +#endif + +struct i2c_client *this_client=NULL; +static struct class *sensor_class = NULL; + +static ssize_t sensor_setoratitention(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int i=0; + char gsensororatation[20]; + + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(this_client); + struct sensor_platform_data *pdata = sensor->pdata; + + + char *p = strstr(buf,"gsensor"); + int start = strcspn(p,"{"); + int end = strcspn(p,"}"); + + strncpy(gsensororatation,p+start,end-start+1); + char *tmp=gsensororatation; + + + while(strncmp(tmp,"}",1)!=0) + { + if((strncmp(tmp,",",1)==0)||(strncmp(tmp,"{",1)==0)) + { + + tmp++; + continue; + } + else if(strncmp(tmp,"-",1)==0) + { + pdata->orientation[i++]=-1; + DBG("i=%d,data=%d\n",i,pdata->orientation[i]); + tmp++; + } + else + { + pdata->orientation[i++]=tmp[0]-48; + DBG("----i=%d,data=%d\n",i,pdata->orientation[i]); + } + tmp++; + + + } + + for(i=0;i<9;i++) + DBG("i=%d gsensor_info=%d\n",i,pdata->orientation[i]); + return 0; + +} + +static CLASS_ATTR(oratiention, 0777, NULL,sensor_setoratitention); + +static int sensor_sys_init(void) +{ + int ret ; + sensor_class = class_create(THIS_MODULE, "gsensor"); + ret = class_create_file(sensor_class, &class_attr_oratiention); + if (ret) + { + printk("Fail to creat class oratiention.\n"); + } + return 0; +} + +/****************operate according to sensor chip:start************/ + +static int sensor_active(struct i2c_client *client, int enable, int rate) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + int status = 0; + + sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg); + + //register setting according to chip datasheet + if(enable) + { + status = KXTIK_ENABLE; //kxtik + sensor->ops->ctrl_data |= status; + } + else + { + status = ~KXTIK_ENABLE; //kxtik + sensor->ops->ctrl_data &= status; + } + + DBG("%s:reg=0x%x,reg_ctrl=0x%x,enable=%d\n",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable); + result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); + if(result) + printk("%s:fail to active sensor\n",__func__); + + return result; + +} + +static int sensor_init(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + + result = sensor->ops->active(client,0,0); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + this_client = client; + + sensor->status_cur = SENSOR_OFF; + + result = sensor_write_reg(client, KXTIK_DATA_CTRL_REG, KXTIK_ODR400F); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + if(sensor->pdata->irq_enable) //open interrupt + { + result = sensor_write_reg(client, KXTIK_INT_CTRL_REG1, 0x34);//enable int,active high,need read INT_REL + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + } + + sensor->ops->ctrl_data = (KXTIK_RES_12BIT | KXTIK_G_2G); + result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + sensor_sys_init(); + return result; +} + +static int sensor_convert_data(struct i2c_client *client, char high_byte, char low_byte) +{ + s64 result; + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + //int precision = sensor->ops->precision; + switch (sensor->devid) { + case KXTIK_DEVID: + result = (((int)high_byte << 8) | ((int)low_byte ))>>4; + if (result < KXTIK_BOUNDARY) + result = result* KXTIK_GRAVITY_STEP; + else + result = ~( ((~result & (0x7fff>>(16-KXTIK_PRECISION)) ) + 1) + * KXTIK_GRAVITY_STEP) + 1; + break; + + default: + printk(KERN_ERR "%s: devid wasn't set correctly\n",__func__); + return -EFAULT; + } + + return (int)result; +} + +static int gsensor_report_value(struct i2c_client *client, struct sensor_axis *axis) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + + /* Report acceleration sensor information */ + input_report_abs(sensor->input_dev, ABS_X, axis->x); + input_report_abs(sensor->input_dev, ABS_Y, axis->y); + input_report_abs(sensor->input_dev, ABS_Z, axis->z); + input_sync(sensor->input_dev); + DBG("Gsensor x==%d y==%d z==%d\n",axis->x,axis->y,axis->z); + + return 0; +} + +#define GSENSOR_MIN 10 +static int sensor_report_value(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + struct sensor_platform_data *pdata = sensor->pdata; + int ret = 0; + int x,y,z; + struct sensor_axis axis; + char buffer[6] = {0}; + char value = 0; + + if(sensor->ops->read_len < 6) //sensor->ops->read_len = 6 + { + printk("%s:lenth is error,len=%d\n",__func__,sensor->ops->read_len); + return -1; + } + + memset(buffer, 0, 6); + + /* Data bytes from hardware xL, xH, yL, yH, zL, zH */ + do { + *buffer = sensor->ops->read_reg; + ret = sensor_rx_data(client, buffer, sensor->ops->read_len); + if (ret < 0) + return ret; + } while (0); + + //this gsensor need 6 bytes buffer + x = sensor_convert_data(sensor->client, buffer[1], buffer[0]); //buffer[1]:high bit + y = sensor_convert_data(sensor->client, buffer[3], buffer[2]); + z = sensor_convert_data(sensor->client, buffer[5], buffer[4]); + + axis.x = (pdata->orientation[0])*x + (pdata->orientation[1])*y + (pdata->orientation[2])*z; + axis.y = (pdata->orientation[3])*x + (pdata->orientation[4])*y + (pdata->orientation[5])*z; + axis.z = (pdata->orientation[6])*x + (pdata->orientation[7])*y + (pdata->orientation[8])*z; + + DBG( "%s: axis = %d %d %d \n", __func__, axis.x, axis.y, axis.z); + + //Report event only while value is changed to save some power + if((abs(sensor->axis.x - axis.x) > GSENSOR_MIN) || (abs(sensor->axis.y - axis.y) > GSENSOR_MIN) || (abs(sensor->axis.z - axis.z) > GSENSOR_MIN)) + { + gsensor_report_value(client, &axis); + + /* 互斥地缓存数据. */ + mutex_lock(&(sensor->data_mutex) ); + sensor->axis = axis; + mutex_unlock(&(sensor->data_mutex) ); + } + + if((sensor->pdata->irq_enable)&& (sensor->ops->int_status_reg >= 0)) //read sensor intterupt status register + { + + value = sensor_read_reg(client, sensor->ops->int_status_reg); + DBG("%s:sensor int status :0x%x\n",__func__,value); + } + + return ret; +} + +struct sensor_operate gsensor_ops = { + .name = "kxtik", + .type = SENSOR_TYPE_ACCEL, //sensor type and it should be correct + .id_i2c = ACCEL_ID_KXTIK, //i2c id number + .read_reg = KXTIK_XOUT_L, //read data + .read_len = 6, //data length + .id_reg = KXTIK_WHO_AM_I, //read device id from this register + .id_data = KXTIK_DEVID, //device id + .precision = KXTIK_PRECISION, //12 bits + .ctrl_reg = KXTIK_CTRL_REG1, //enable or disable + .int_status_reg = KXTIK_INT_REL, //intterupt status register + .range = {-KXTIK_RANGE,KXTIK_RANGE}, //range + .trig = IRQF_TRIGGER_LOW|IRQF_ONESHOT, + .active = sensor_active, + .init = sensor_init, + .report = sensor_report_value, +}; + +/****************operate according to sensor chip:end************/ + +//function name should not be changed +struct sensor_operate *gsensor_get_ops(void) +{ + return &gsensor_ops; +} + +EXPORT_SYMBOL(gsensor_get_ops); + +static int __init gsensor_init(void) +{ + struct sensor_operate *ops = gsensor_get_ops(); + int result = 0; + int type = ops->type; + result = sensor_register_slave(type, NULL, NULL, gsensor_get_ops); + printk("%s\n",__func__); + return result; +} + +static void __exit gsensor_exit(void) +{ + struct sensor_operate *ops = gsensor_get_ops(); + int type = ops->type; + sensor_unregister_slave(type, NULL, NULL, gsensor_get_ops); +} + + +module_init(gsensor_init); +module_exit(gsensor_exit); + + diff --git a/drivers/input/sensors/accel/lis3dh.c b/drivers/input/sensors/accel/lis3dh.c index ac9c059f71ad..2dcea964c28f 100755 --- a/drivers/input/sensors/accel/lis3dh.c +++ b/drivers/input/sensors/accel/lis3dh.c @@ -1,345 +1,412 @@ -/* drivers/input/sensors/access/kxtik.c - * - * Copyright (C) 2012-2015 ROCKCHIP. - * Author: luowei - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_HAS_EARLYSUSPEND -#include -#endif -#include - -#if 0 -#define SENSOR_DEBUG_TYPE SENSOR_TYPE_ACCEL -#define DBG(x...) if(sensor->pdata->type == SENSOR_DEBUG_TYPE) printk(x) -#else -#define DBG(x...) -#endif - -#define LIS3DH_INT_COUNT (0x0E) -#define LIS3DH_WHO_AM_I (0x0F) - -/* full scale setting - register & mask */ -#define LIS3DH_TEMP_CFG_REG (0x1F) -#define LIS3DH_CTRL_REG1 (0x20) -#define LIS3DH_CTRL_REG2 (0x21) -#define LIS3DH_CTRL_REG3 (0x22) -#define LIS3DH_CTRL_REG4 (0x23) -#define LIS3DH_CTRL_REG5 (0x24) -#define LIS3DH_CTRL_REG6 (0x25) -#define LIS3DH_REFERENCE (0x26) -#define LIS3DH_STATUS_REG (0x27) -#define LIS3DH_OUT_X_L (0x28) -#define LIS3DH_OUT_X_H (0x29) -#define LIS3DH_OUT_Y_L (0x2a) -#define LIS3DH_OUT_Y_H (0x2b) -#define LIS3DH_OUT_Z_L (0x2c) -#define LIS3DH_OUT_Z_H (0x2d) -#define LIS3DH_FIFO_CTRL_REG (0x2E) - -#define LIS3DH_INT1_CFG (0x30) -#define LIS3DH_INT1_SRC (0x31) -#define LIS3DH_INT1_THS (0x32) -#define LIS3DH_INT1_DURATION (0x33) - -#define LIS3DH_DEVID (0x33) //chip id -#define LIS3DH_ACC_DISABLE (0x08) - -#define LIS3DH_RANGE 2000000 - -/* LIS3DH */ -#define LIS3DH_PRECISION 16 -#define LIS3DH_BOUNDARY (0x1 << (LIS3DH_PRECISION - 1)) -#define LIS3DH_GRAVITY_STEP (LIS3DH_RANGE / LIS3DH_BOUNDARY) - -#define ODR1 0x10 /* 1Hz output data rate */ -#define ODR10 0x20 /* 10Hz output data rate */ -#define ODR25 0x30 /* 25Hz output data rate */ -#define ODR50 0x40 /* 50Hz output data rate */ -#define ODR100 0x50 /* 100Hz output data rate */ -#define ODR200 0x60 /* 200Hz output data rate */ -#define ODR400 0x70 /* 400Hz output data rate */ -#define ODR1250 0x90 /* 1250Hz output data rate */ - - - -struct sensor_reg_data { - char reg; - char data; -}; - - -/****************operate according to sensor chip:start************/ - -static int sensor_active(struct i2c_client *client, int enable, int rate) -{ - struct sensor_private_data *sensor = - (struct sensor_private_data *) i2c_get_clientdata(client); - int result = 0; - int status = 0; - - sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg); - - sensor->ops->ctrl_data |= ODR100; //100HZ,if 0 then power down - - //register setting according to chip datasheet - if(!enable) - { - status = LIS3DH_ACC_DISABLE; //lis3dh - sensor->ops->ctrl_data |= status; - } - else - { - status = ~LIS3DH_ACC_DISABLE; //lis3dh - sensor->ops->ctrl_data &= status; - } - - DBG("%s:reg=0x%x,reg_ctrl=0x%x,enable=%d\n",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable); - result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); - if(result) - printk("%s:fail to active sensor\n",__func__); - - return result; - -} - -static int sensor_init(struct i2c_client *client) -{ - struct sensor_private_data *sensor = - (struct sensor_private_data *) i2c_get_clientdata(client); - int result = 0; - int i; - struct sensor_reg_data reg_data[] = - { - {LIS3DH_CTRL_REG2,0X00}, - {LIS3DH_CTRL_REG4,0x08}, //High resolution output mode: 1, Normal mode - {LIS3DH_CTRL_REG6,0x40}, - {LIS3DH_TEMP_CFG_REG,0x00}, // - {LIS3DH_FIFO_CTRL_REG,0x00}, // - {LIS3DH_INT1_CFG,0xFF}, //6 direction position recognition - {LIS3DH_INT1_THS,0x7F}, //Interrupt 1 threshold - {LIS3DH_INT1_DURATION,0x7F}, //Duration value 0x00->ox7f - }; - - result = sensor->ops->active(client,0,0); - if(result) - { - printk("%s:line=%d,error\n",__func__,__LINE__); - return result; - } - - sensor->status_cur = SENSOR_OFF; - - for(i=0;i<(sizeof(reg_data)/sizeof(struct sensor_reg_data));i++) - { - result = sensor_write_reg(client, reg_data[i].reg, reg_data[i].data); - if(result) - { - printk("%s:line=%d,i=%d,error\n",__func__,__LINE__,i); - return result; - } - } - - - if(sensor->pdata->irq_enable) - { - - result = sensor_write_reg(client, LIS3DH_CTRL_REG3, 0x40);//I1_AOI1 =1 if motion - if(result) - { - printk("%s:line=%d,error\n",__func__,__LINE__); - return result; - } - - result = sensor_write_reg(client, LIS3DH_CTRL_REG5, 0x08); - if(result) - { - printk("%s:line=%d,error\n",__func__,__LINE__); - return result; - } - - } - - return result; -} - -static int sensor_convert_data(struct i2c_client *client, char high_byte, char low_byte) -{ - s64 result; - struct sensor_private_data *sensor = - (struct sensor_private_data *) i2c_get_clientdata(client); - //int precision = sensor->ops->precision; - switch (sensor->devid) { - case LIS3DH_DEVID: - result = ((int)high_byte << 8) | (int)low_byte; - if (result < LIS3DH_BOUNDARY) - result = result* LIS3DH_GRAVITY_STEP; - else - result = ~( ((~result & (0x7fff>>(16-LIS3DH_PRECISION)) ) + 1) - * LIS3DH_GRAVITY_STEP) + 1; - break; - - default: - printk(KERN_ERR "%s: devid wasn't set correctly\n",__func__); - return -EFAULT; - } - - return (int)result; -} - -static int gsensor_report_value(struct i2c_client *client, struct sensor_axis *axis) -{ - struct sensor_private_data *sensor = - (struct sensor_private_data *) i2c_get_clientdata(client); - - /* Report acceleration sensor information */ - input_report_abs(sensor->input_dev, ABS_X, axis->x); - input_report_abs(sensor->input_dev, ABS_Y, axis->y); - input_report_abs(sensor->input_dev, ABS_Z, axis->z); - input_sync(sensor->input_dev); - DBG("Gsensor x==%d y==%d z==%d\n",axis->x,axis->y,axis->z); - - return 0; -} - -#define GSENSOR_MIN 10 -static int sensor_report_value(struct i2c_client *client) -{ - struct sensor_private_data *sensor = - (struct sensor_private_data *) i2c_get_clientdata(client); - struct sensor_platform_data *pdata = sensor->pdata; - int ret = 0; - int x,y,z; - struct sensor_axis axis; - char buffer[6] = {0}; - char value = 0; - - if(sensor->ops->read_len < 6) //sensor->ops->read_len = 6 - { - printk("%s:lenth is error,len=%d\n",__func__,sensor->ops->read_len); - return -1; - } - - memset(buffer, 0, 6); - - value = sensor_read_reg(client, LIS3DH_STATUS_REG); - if((value & 0x0f) == 0) - { - printk("%s:line=%d,value=0x%x,data is not ready\n",__func__,__LINE__,value); - return -1; - } - - - /* Data bytes from hardware xL, xH, yL, yH, zL, zH */ - do { - *buffer = sensor->ops->read_reg; - ret = sensor_rx_data(client, buffer, sensor->ops->read_len); - if (ret < 0) - return ret; - } while (0); - - //this gsensor need 6 bytes buffer - x = sensor_convert_data(sensor->client, buffer[1], buffer[0]); //buffer[1]:high bit - y = sensor_convert_data(sensor->client, buffer[3], buffer[2]); - z = sensor_convert_data(sensor->client, buffer[5], buffer[4]); - - axis.x = (pdata->orientation[0])*x + (pdata->orientation[1])*y + (pdata->orientation[2])*z; - axis.y = (pdata->orientation[3])*x + (pdata->orientation[4])*y + (pdata->orientation[5])*z; - axis.z = (pdata->orientation[6])*x + (pdata->orientation[7])*y + (pdata->orientation[8])*z; - - DBG( "%s: axis = %d %d %d \n", __func__, axis.x, axis.y, axis.z); - - //Report event only while value is changed to save some power - if((abs(sensor->axis.x - axis.x) > GSENSOR_MIN) || (abs(sensor->axis.y - axis.y) > GSENSOR_MIN) || (abs(sensor->axis.z - axis.z) > GSENSOR_MIN)) - { - gsensor_report_value(client, &axis); - - /* 互斥地缓存数据. */ - mutex_lock(&(sensor->data_mutex) ); - sensor->axis = axis; - mutex_unlock(&(sensor->data_mutex) ); - } - - if((sensor->pdata->irq_enable)&& (sensor->ops->int_status_reg >= 0)) //read sensor intterupt status register - { - - value = sensor_read_reg(client, sensor->ops->int_status_reg); - DBG("%s:sensor int status :0x%x\n",__func__,value); - } - - return ret; -} - -struct sensor_operate gsensor_ops = { - .name = "lis3dh", - .type = SENSOR_TYPE_ACCEL, //sensor type and it should be correct - .id_i2c = ACCEL_ID_LIS3DH, //i2c id number - .read_reg = (LIS3DH_OUT_X_L | 0x80), //read data - .read_len = 6, //data length - .id_reg = LIS3DH_WHO_AM_I, //read device id from this register - .id_data = LIS3DH_DEVID, //device id - .precision = LIS3DH_PRECISION, //12 bits - .ctrl_reg = LIS3DH_CTRL_REG1, //enable or disable - .int_status_reg = LIS3DH_INT1_SRC, //intterupt status register - .range = {-LIS3DH_RANGE,LIS3DH_RANGE}, //range - .trig = (IRQF_TRIGGER_LOW|IRQF_ONESHOT), - .active = sensor_active, - .init = sensor_init, - .report = sensor_report_value, -}; - -/****************operate according to sensor chip:end************/ - -//function name should not be changed -struct sensor_operate *gsensor_get_ops(void) -{ - return &gsensor_ops; -} - -EXPORT_SYMBOL(gsensor_get_ops); - -static int __init gsensor_init(void) -{ - struct sensor_operate *ops = gsensor_get_ops(); - int result = 0; - int type = ops->type; - result = sensor_register_slave(type, NULL, NULL, gsensor_get_ops); - printk("%s\n",__func__); - return result; -} - -static void __exit gsensor_exit(void) -{ - struct sensor_operate *ops = gsensor_get_ops(); - int type = ops->type; - sensor_unregister_slave(type, NULL, NULL, gsensor_get_ops); -} - - -module_init(gsensor_init); -module_exit(gsensor_exit); - - +/* drivers/input/sensors/access/kxtik.c + * + * Copyright (C) 2012-2015 ROCKCHIP. + * Author: luowei + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include + +#if 0 +#define SENSOR_DEBUG_TYPE SENSOR_TYPE_ACCEL +#define DBG(x...) if(sensor->pdata->type == SENSOR_DEBUG_TYPE) printk(x) +#else +#define DBG(x...) +#endif + +#define LIS3DH_INT_COUNT (0x0E) +#define LIS3DH_WHO_AM_I (0x0F) + +/* full scale setting - register & mask */ +#define LIS3DH_TEMP_CFG_REG (0x1F) +#define LIS3DH_CTRL_REG1 (0x20) +#define LIS3DH_CTRL_REG2 (0x21) +#define LIS3DH_CTRL_REG3 (0x22) +#define LIS3DH_CTRL_REG4 (0x23) +#define LIS3DH_CTRL_REG5 (0x24) +#define LIS3DH_CTRL_REG6 (0x25) +#define LIS3DH_REFERENCE (0x26) +#define LIS3DH_STATUS_REG (0x27) +#define LIS3DH_OUT_X_L (0x28) +#define LIS3DH_OUT_X_H (0x29) +#define LIS3DH_OUT_Y_L (0x2a) +#define LIS3DH_OUT_Y_H (0x2b) +#define LIS3DH_OUT_Z_L (0x2c) +#define LIS3DH_OUT_Z_H (0x2d) +#define LIS3DH_FIFO_CTRL_REG (0x2E) + +#define LIS3DH_INT1_CFG (0x30) +#define LIS3DH_INT1_SRC (0x31) +#define LIS3DH_INT1_THS (0x32) +#define LIS3DH_INT1_DURATION (0x33) + +#define LIS3DH_DEVID (0x33) //chip id +#define LIS3DH_ACC_DISABLE (0x08) + +#define LIS3DH_RANGE 2000000 + +/* LIS3DH */ +#define LIS3DH_PRECISION 16 +#define LIS3DH_BOUNDARY (0x1 << (LIS3DH_PRECISION - 1)) +#define LIS3DH_GRAVITY_STEP (LIS3DH_RANGE / LIS3DH_BOUNDARY) + +#define ODR1 0x10 /* 1Hz output data rate */ +#define ODR10 0x20 /* 10Hz output data rate */ +#define ODR25 0x30 /* 25Hz output data rate */ +#define ODR50 0x40 /* 50Hz output data rate */ +#define ODR100 0x50 /* 100Hz output data rate */ +#define ODR200 0x60 /* 200Hz output data rate */ +#define ODR400 0x70 /* 400Hz output data rate */ +#define ODR1250 0x90 /* 1250Hz output data rate */ + + + +struct sensor_reg_data { + char reg; + char data; +}; + +struct i2c_client *this_client=NULL; +static struct class *sensor_class = NULL; + +static ssize_t sensor_setoratitention(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int i=0; + char gsensororatation[20]; + + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(this_client); + struct sensor_platform_data *pdata = sensor->pdata; + + + char *p = strstr(buf,"gsensor"); + int start = strcspn(p,"{"); + int end = strcspn(p,"}"); + + strncpy(gsensororatation,p+start,end-start+1); + char *tmp=gsensororatation; + + + while(strncmp(tmp,"}",1)!=0) + { + if((strncmp(tmp,",",1)==0)||(strncmp(tmp,"{",1)==0)) + { + + tmp++; + continue; + } + else if(strncmp(tmp,"-",1)==0) + { + pdata->orientation[i++]=-1; + DBG("i=%d,data=%d\n",i,pdata->orientation[i]); + tmp++; + } + else + { + pdata->orientation[i++]=tmp[0]-48; + DBG("----i=%d,data=%d\n",i,pdata->orientation[i]); + } + tmp++; + + + } + + for(i=0;i<9;i++) + DBG("i=%d gsensor_info=%d\n",i,pdata->orientation[i]); + return 0; + +} + +static CLASS_ATTR(oratiention, 0777, NULL,sensor_setoratitention); + +static int sensor_sys_init(void) +{ + int ret ; + sensor_class = class_create(THIS_MODULE, "gsensor"); + ret = class_create_file(sensor_class, &class_attr_oratiention); + if (ret) + { + printk("Fail to creat class oratiention.\n"); + } + return 0; +} + +/****************operate according to sensor chip:start************/ + +static int sensor_active(struct i2c_client *client, int enable, int rate) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + int status = 0; + + sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg); + + sensor->ops->ctrl_data |= ODR100; //100HZ,if 0 then power down + + //register setting according to chip datasheet + if(!enable) + { + status = LIS3DH_ACC_DISABLE; //lis3dh + sensor->ops->ctrl_data |= status; + } + else + { + status = ~LIS3DH_ACC_DISABLE; //lis3dh + sensor->ops->ctrl_data &= status; + } + + DBG("%s:reg=0x%x,reg_ctrl=0x%x,enable=%d\n",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable); + result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); + if(result) + printk("%s:fail to active sensor\n",__func__); + + return result; + +} + +static int sensor_init(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + int i; + struct sensor_reg_data reg_data[] = + { + {LIS3DH_CTRL_REG2,0X00}, + {LIS3DH_CTRL_REG4,0x08}, //High resolution output mode: 1, Normal mode + {LIS3DH_CTRL_REG6,0x40}, + {LIS3DH_TEMP_CFG_REG,0x00}, // + {LIS3DH_FIFO_CTRL_REG,0x00}, // + {LIS3DH_INT1_CFG,0xFF}, //6 direction position recognition + {LIS3DH_INT1_THS,0x7F}, //Interrupt 1 threshold + {LIS3DH_INT1_DURATION,0x7F}, //Duration value 0x00->ox7f + }; + + result = sensor->ops->active(client,0,0); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + this_client = client; + + sensor->status_cur = SENSOR_OFF; + + for(i=0;i<(sizeof(reg_data)/sizeof(struct sensor_reg_data));i++) + { + result = sensor_write_reg(client, reg_data[i].reg, reg_data[i].data); + if(result) + { + printk("%s:line=%d,i=%d,error\n",__func__,__LINE__,i); + return result; + } + } + + + if(sensor->pdata->irq_enable) + { + + result = sensor_write_reg(client, LIS3DH_CTRL_REG3, 0x40);//I1_AOI1 =1 if motion + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + result = sensor_write_reg(client, LIS3DH_CTRL_REG5, 0x08); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + } + sensor_sys_init(); + + return result; +} + +static int sensor_convert_data(struct i2c_client *client, char high_byte, char low_byte) +{ + s64 result; + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + //int precision = sensor->ops->precision; + switch (sensor->devid) { + case LIS3DH_DEVID: + result = ((int)high_byte << 8) | (int)low_byte; + if (result < LIS3DH_BOUNDARY) + result = result* LIS3DH_GRAVITY_STEP; + else + result = ~( ((~result & (0x7fff>>(16-LIS3DH_PRECISION)) ) + 1) + * LIS3DH_GRAVITY_STEP) + 1; + break; + + default: + printk(KERN_ERR "%s: devid wasn't set correctly\n",__func__); + return -EFAULT; + } + + return (int)result; +} + +static int gsensor_report_value(struct i2c_client *client, struct sensor_axis *axis) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + + /* Report acceleration sensor information */ + input_report_abs(sensor->input_dev, ABS_X, axis->x); + input_report_abs(sensor->input_dev, ABS_Y, axis->y); + input_report_abs(sensor->input_dev, ABS_Z, axis->z); + input_sync(sensor->input_dev); + DBG("Gsensor x==%d y==%d z==%d\n",axis->x,axis->y,axis->z); + + return 0; +} + +#define GSENSOR_MIN 10 +static int sensor_report_value(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + struct sensor_platform_data *pdata = sensor->pdata; + int ret = 0; + int x,y,z; + struct sensor_axis axis; + char buffer[6] = {0}; + char value = 0; + + if(sensor->ops->read_len < 6) //sensor->ops->read_len = 6 + { + printk("%s:lenth is error,len=%d\n",__func__,sensor->ops->read_len); + return -1; + } + + memset(buffer, 0, 6); + + value = sensor_read_reg(client, LIS3DH_STATUS_REG); + if((value & 0x0f) == 0) + { + printk("%s:line=%d,value=0x%x,data is not ready\n",__func__,__LINE__,value); + return -1; + } + + + /* Data bytes from hardware xL, xH, yL, yH, zL, zH */ + do { + *buffer = sensor->ops->read_reg; + ret = sensor_rx_data(client, buffer, sensor->ops->read_len); + if (ret < 0) + return ret; + } while (0); + + //this gsensor need 6 bytes buffer + x = sensor_convert_data(sensor->client, buffer[1], buffer[0]); //buffer[1]:high bit + y = sensor_convert_data(sensor->client, buffer[3], buffer[2]); + z = sensor_convert_data(sensor->client, buffer[5], buffer[4]); + + axis.x = (pdata->orientation[0])*x + (pdata->orientation[1])*y + (pdata->orientation[2])*z; + axis.y = (pdata->orientation[3])*x + (pdata->orientation[4])*y + (pdata->orientation[5])*z; + axis.z = (pdata->orientation[6])*x + (pdata->orientation[7])*y + (pdata->orientation[8])*z; + + DBG( "%s: axis = %d %d %d \n", __func__, axis.x, axis.y, axis.z); + + //Report event only while value is changed to save some power + if((abs(sensor->axis.x - axis.x) > GSENSOR_MIN) || (abs(sensor->axis.y - axis.y) > GSENSOR_MIN) || (abs(sensor->axis.z - axis.z) > GSENSOR_MIN)) + { + gsensor_report_value(client, &axis); + + /* 互斥地缓存数据. */ + mutex_lock(&(sensor->data_mutex) ); + sensor->axis = axis; + mutex_unlock(&(sensor->data_mutex) ); + } + + if((sensor->pdata->irq_enable)&& (sensor->ops->int_status_reg >= 0)) //read sensor intterupt status register + { + + value = sensor_read_reg(client, sensor->ops->int_status_reg); + DBG("%s:sensor int status :0x%x\n",__func__,value); + } + + return ret; +} + +struct sensor_operate gsensor_ops = { + .name = "lis3dh", + .type = SENSOR_TYPE_ACCEL, //sensor type and it should be correct + .id_i2c = ACCEL_ID_LIS3DH, //i2c id number + .read_reg = (LIS3DH_OUT_X_L | 0x80), //read data + .read_len = 6, //data length + .id_reg = LIS3DH_WHO_AM_I, //read device id from this register + .id_data = LIS3DH_DEVID, //device id + .precision = LIS3DH_PRECISION, //12 bits + .ctrl_reg = LIS3DH_CTRL_REG1, //enable or disable + .int_status_reg = LIS3DH_INT1_SRC, //intterupt status register + .range = {-LIS3DH_RANGE,LIS3DH_RANGE}, //range + .trig = (IRQF_TRIGGER_LOW|IRQF_ONESHOT), + .active = sensor_active, + .init = sensor_init, + .report = sensor_report_value, +}; + +/****************operate according to sensor chip:end************/ + +//function name should not be changed +struct sensor_operate *gsensor_get_ops(void) +{ + return &gsensor_ops; +} + +EXPORT_SYMBOL(gsensor_get_ops); + +static int __init gsensor_init(void) +{ + struct sensor_operate *ops = gsensor_get_ops(); + int result = 0; + int type = ops->type; + result = sensor_register_slave(type, NULL, NULL, gsensor_get_ops); + printk("%s\n",__func__); + return result; +} + +static void __exit gsensor_exit(void) +{ + struct sensor_operate *ops = gsensor_get_ops(); + int type = ops->type; + sensor_unregister_slave(type, NULL, NULL, gsensor_get_ops); +} + + +module_init(gsensor_init); +module_exit(gsensor_exit); + + diff --git a/drivers/input/sensors/accel/mma8452.c b/drivers/input/sensors/accel/mma8452.c index a5e5f40f2e1a..bb698d46ca72 100755 --- a/drivers/input/sensors/accel/mma8452.c +++ b/drivers/input/sensors/accel/mma8452.c @@ -1,306 +1,375 @@ -/* drivers/input/sensors/access/mma8452.c - * - * Copyright (C) 2012-2015 ROCKCHIP. - * Author: luowei - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_HAS_EARLYSUSPEND -#include -#endif -#include -#include - -#if 0 -#define SENSOR_DEBUG_TYPE SENSOR_TYPE_ACCEL -#define DBG(x...) if(sensor->pdata->type == SENSOR_DEBUG_TYPE) printk(x) -#else -#define DBG(x...) -#endif - - -#define MMA8451_DEVID 0x1a -#define MMA8452_DEVID 0x2a -#define MMA8453_DEVID 0x3a - -#define MMA8452_ENABLE 1 - - -/****************operate according to sensor chip:start************/ - -static int sensor_active(struct i2c_client *client, int enable, int rate) -{ - struct sensor_private_data *sensor = - (struct sensor_private_data *) i2c_get_clientdata(client); - int result = 0; - int status = 0; - - sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg); - - //register setting according to chip datasheet - if(enable) - { - status = MMA8452_ENABLE; //mma8452 - sensor->ops->ctrl_data |= status; - } - else - { - status = ~MMA8452_ENABLE; //mma8452 - sensor->ops->ctrl_data &= status; - } - - DBG("%s:reg=0x%x,reg_ctrl=0x%x,enable=%d\n",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable); - result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); - if(result) - printk("%s:fail to active sensor\n",__func__); - - return result; - -} - -static int sensor_init(struct i2c_client *client) -{ - int tmp; - int ret = 0; - struct sensor_private_data *sensor = - (struct sensor_private_data *) i2c_get_clientdata(client); - - ret = sensor->ops->active(client,0,0); - if(ret) - { - printk("%s:line=%d,error\n",__func__,__LINE__); - return ret; - } - - sensor->status_cur = SENSOR_OFF; - - /* disable FIFO FMODE = 0*/ - ret = sensor_write_reg(client,MMA8452_REG_F_SETUP,0); - DBG("%s: MMA8452_REG_F_SETUP:%x\n",__func__, sensor_read_reg(client,MMA8452_REG_F_SETUP)); - - /* set full scale range to 2g */ - ret = sensor_write_reg(client,MMA8452_REG_XYZ_DATA_CFG,0); - DBG("%s: MMA8452_REG_XYZ_DATA_CFG:%x\n",__func__, sensor_read_reg(client,MMA8452_REG_XYZ_DATA_CFG)); - - /* set bus 8bit/14bit(FREAD = 1,FMODE = 0) ,data rate*/ - tmp = (MMA8452_RATE_12P5<< MMA8452_RATE_SHIFT) | FREAD_MASK; - ret = sensor_write_reg(client,MMA8452_REG_CTRL_REG1,tmp); - - sensor->ops->ctrl_data = tmp; - - DBG("mma8452 MMA8452_REG_CTRL_REG1:%x\n",sensor_read_reg(client,MMA8452_REG_CTRL_REG1)); - - DBG("mma8452 MMA8452_REG_SYSMOD:%x\n",sensor_read_reg(client,MMA8452_REG_SYSMOD)); - - ret = sensor_write_reg(client,MMA8452_REG_CTRL_REG3,5); - DBG("mma8452 MMA8452_REG_CTRL_REG3:%x\n",sensor_read_reg(client,MMA8452_REG_CTRL_REG3)); - - ret = sensor_write_reg(client,MMA8452_REG_CTRL_REG4,1); - DBG("mma8452 MMA8452_REG_CTRL_REG4:%x\n",sensor_read_reg(client,MMA8452_REG_CTRL_REG4)); - - ret = sensor_write_reg(client,MMA8452_REG_CTRL_REG5,1); - DBG("mma8452 MMA8452_REG_CTRL_REG5:%x\n",sensor_read_reg(client,MMA8452_REG_CTRL_REG5)); - - DBG("mma8452 MMA8452_REG_SYSMOD:%x\n",sensor_read_reg(client,MMA8452_REG_SYSMOD)); - - return ret; -} - -static int sensor_convert_data(struct i2c_client *client, char high_byte, char low_byte) -{ - s64 result; - struct sensor_private_data *sensor = - (struct sensor_private_data *) i2c_get_clientdata(client); - //int precision = sensor->ops->precision; - switch (sensor->devid) { - case MMA8451_DEVID: - swap(high_byte,low_byte); - result = ((int)high_byte << (MMA8451_PRECISION-8)) - | ((int)low_byte >> (16-MMA8451_PRECISION)); - if (result < MMA8451_BOUNDARY) - result = result* MMA8451_GRAVITY_STEP; - else - result = ~( ((~result & (0x7fff>>(16-MMA8451_PRECISION)) ) + 1) - * MMA8451_GRAVITY_STEP) + 1; - break; - - case MMA8452_DEVID: - swap(high_byte,low_byte); - result = ((int)high_byte << (MMA8452_PRECISION-8)) - | ((int)low_byte >> (16-MMA8452_PRECISION)); - if (result < MMA8452_BOUNDARY) - result = result* MMA8452_GRAVITY_STEP; - else - result = ~( ((~result & (0x7fff>>(16-MMA8452_PRECISION)) ) + 1) - * MMA8452_GRAVITY_STEP) + 1; - break; - - case MMA8453_DEVID: - swap(high_byte,low_byte); - result = ((int)high_byte << (MMA8453_PRECISION-8)) - | ((int)low_byte >> (16-MMA8453_PRECISION)); - if (result < MMA8453_BOUNDARY) - result = result* MMA8453_GRAVITY_STEP; - else - result = ~( ((~result & (0x7fff>>(16-MMA8453_PRECISION)) ) + 1) - * MMA8453_GRAVITY_STEP) + 1; - break; - - default: - printk(KERN_ERR "%s: devid wasn't set correctly\n",__func__); - return -EFAULT; - } - - return (int)result; -} - -static int gsensor_report_value(struct i2c_client *client, struct sensor_axis *axis) -{ - struct sensor_private_data *sensor = - (struct sensor_private_data *) i2c_get_clientdata(client); - - /* Report acceleration sensor information */ - input_report_abs(sensor->input_dev, ABS_X, axis->x); - input_report_abs(sensor->input_dev, ABS_Y, axis->y); - input_report_abs(sensor->input_dev, ABS_Z, axis->z); - input_sync(sensor->input_dev); - DBG("Gsensor x==%d y==%d z==%d\n",axis->x,axis->y,axis->z); - - return 0; -} - -#define GSENSOR_MIN 10 -static int sensor_report_value(struct i2c_client *client) -{ - struct sensor_private_data *sensor = - (struct sensor_private_data *) i2c_get_clientdata(client); - struct sensor_platform_data *pdata = sensor->pdata; - int ret = 0; - int x,y,z; - struct sensor_axis axis; - char buffer[6] = {0}; - char value = 0; - - if(sensor->ops->read_len < 6) //sensor->ops->read_len = 6 - { - printk("%s:lenth is error,len=%d\n",__func__,sensor->ops->read_len); - return -1; - } - - memset(buffer, 0, 6); - - /* Data bytes from hardware xL, xH, yL, yH, zL, zH */ - do { - *buffer = sensor->ops->read_reg; - ret = sensor_rx_data(client, buffer, sensor->ops->read_len); - if (ret < 0) - return ret; - } while (0); - - - //this gsensor need 6 bytes buffer - x = sensor_convert_data(sensor->client, buffer[1], buffer[0]); //buffer[1]:high bit - y = sensor_convert_data(sensor->client, buffer[3], buffer[2]); - z = sensor_convert_data(sensor->client, buffer[5], buffer[4]); - - axis.x = (pdata->orientation[0])*x + (pdata->orientation[1])*y + (pdata->orientation[2])*z; - axis.y = (pdata->orientation[3])*x + (pdata->orientation[4])*y + (pdata->orientation[5])*z; - axis.z = (pdata->orientation[6])*x + (pdata->orientation[7])*y + (pdata->orientation[8])*z; - - DBG( "%s: axis = %d %d %d \n", __func__, axis.x, axis.y, axis.z); - - //Report event only while value is changed to save some power - if((abs(sensor->axis.x - axis.x) > GSENSOR_MIN) || (abs(sensor->axis.y - axis.y) > GSENSOR_MIN) || (abs(sensor->axis.z - axis.z) > GSENSOR_MIN)) - { - gsensor_report_value(client, &axis); - - /* 互斥地缓存数据. */ - mutex_lock(&(sensor->data_mutex) ); - sensor->axis = axis; - mutex_unlock(&(sensor->data_mutex) ); - } - - if((sensor->pdata->irq_enable)&& (sensor->ops->int_status_reg >= 0)) //read sensor intterupt status register - { - - value = sensor_read_reg(client, sensor->ops->int_status_reg); - DBG("%s:sensor int status :0x%x\n",__func__,value); - } - - return ret; -} - - -struct sensor_operate gsensor_ops = { - .name = "mma8452", - .type = SENSOR_TYPE_ACCEL, //sensor type and it should be correct - .id_i2c = ACCEL_ID_MMA845X, //i2c id number - .read_reg = MMA8452_REG_X_OUT_MSB, //read data - .read_len = 6, //data length - .id_reg = MMA8452_REG_WHO_AM_I, //read device id from this register - .id_data = MMA8452_DEVID, //device id - .precision = MMA8452_PRECISION, //12 bit - .ctrl_reg = MMA8452_REG_CTRL_REG1, //enable or disable - .int_status_reg = MMA8452_REG_INTSRC, //intterupt status register - .range = {-MMA845X_RANGE,MMA845X_RANGE}, //range - .trig = IRQF_TRIGGER_LOW|IRQF_ONESHOT, - .active = sensor_active, - .init = sensor_init, - .report = sensor_report_value, -}; - -/****************operate according to sensor chip:end************/ - -//function name should not be changed -struct sensor_operate *gsensor_get_ops(void) -{ - return &gsensor_ops; -} - -EXPORT_SYMBOL(gsensor_get_ops); - -static int __init gsensor_init(void) -{ - struct sensor_operate *ops = gsensor_get_ops(); - int result = 0; - int type = ops->type; - result = sensor_register_slave(type, NULL, NULL, gsensor_get_ops); - printk("%s\n",__func__); - return result; -} - -static void __exit gsensor_exit(void) -{ - struct sensor_operate *ops = gsensor_get_ops(); - int type = ops->type; - sensor_unregister_slave(type, NULL, NULL, gsensor_get_ops); -} - - -module_init(gsensor_init); -module_exit(gsensor_exit); - - - +/* drivers/input/sensors/access/mma8452.c + * + * Copyright (C) 2012-2015 ROCKCHIP. + * Author: luowei + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include + +#if 0 +#define SENSOR_DEBUG_TYPE SENSOR_TYPE_ACCEL +#define DBG(x...) if(sensor->pdata->type == SENSOR_DEBUG_TYPE) printk(x) +#else +#define DBG(x...) +#endif + + +#define MMA8451_DEVID 0x1a +#define MMA8452_DEVID 0x2a +#define MMA8453_DEVID 0x3a + +#define MMA8452_ENABLE 1 + +struct i2c_client *this_client=NULL; +static struct class *sensor_class = NULL; + +static ssize_t sensor_setoratitention(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int i=0; + char gsensororatation[20]; + + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(this_client); + struct sensor_platform_data *pdata = sensor->pdata; + + + char *p = strstr(buf,"gsensor"); + int start = strcspn(p,"{"); + int end = strcspn(p,"}"); + + strncpy(gsensororatation,p+start,end-start+1); + char *tmp=gsensororatation; + + + while(strncmp(tmp,"}",1)!=0) + { + if((strncmp(tmp,",",1)==0)||(strncmp(tmp,"{",1)==0)) + { + + tmp++; + continue; + } + else if(strncmp(tmp,"-",1)==0) + { + pdata->orientation[i++]=-1; + DBG("i=%d,data=%d\n",i,pdata->orientation[i]); + tmp++; + } + else + { + pdata->orientation[i++]=tmp[0]-48; + DBG("----i=%d,data=%d\n",i,pdata->orientation[i]); + } + tmp++; + + + } + + for(i=0;i<9;i++) + DBG("i=%d gsensor_info=%d\n",i,pdata->orientation[i]); + return 0; + +} + +static CLASS_ATTR(oratiention, 0777, NULL,sensor_setoratitention); + +static int sensor_sys_init(void) +{ + int ret ; + sensor_class = class_create(THIS_MODULE, "gsensor"); + ret = class_create_file(sensor_class, &class_attr_oratiention); + if (ret) + { + printk("Fail to creat class oratiention.\n"); + } + return 0; +} + +/****************operate according to sensor chip:start************/ + +static int sensor_active(struct i2c_client *client, int enable, int rate) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + int status = 0; + + sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg); + + //register setting according to chip datasheet + if(enable) + { + status = MMA8452_ENABLE; //mma8452 + sensor->ops->ctrl_data |= status; + } + else + { + status = ~MMA8452_ENABLE; //mma8452 + sensor->ops->ctrl_data &= status; + } + + DBG("%s:reg=0x%x,reg_ctrl=0x%x,enable=%d\n",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable); + result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); + if(result) + printk("%s:fail to active sensor\n",__func__); + + return result; + +} + +static int sensor_init(struct i2c_client *client) +{ + int tmp; + int ret = 0; + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + + ret = sensor->ops->active(client,0,0); + if(ret) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return ret; + } + + this_client=client; + + sensor->status_cur = SENSOR_OFF; + + /* disable FIFO FMODE = 0*/ + ret = sensor_write_reg(client,MMA8452_REG_F_SETUP,0); + DBG("%s: MMA8452_REG_F_SETUP:%x\n",__func__, sensor_read_reg(client,MMA8452_REG_F_SETUP)); + + /* set full scale range to 2g */ + ret = sensor_write_reg(client,MMA8452_REG_XYZ_DATA_CFG,0); + DBG("%s: MMA8452_REG_XYZ_DATA_CFG:%x\n",__func__, sensor_read_reg(client,MMA8452_REG_XYZ_DATA_CFG)); + + /* set bus 8bit/14bit(FREAD = 1,FMODE = 0) ,data rate*/ + tmp = (MMA8452_RATE_12P5<< MMA8452_RATE_SHIFT) | FREAD_MASK; + ret = sensor_write_reg(client,MMA8452_REG_CTRL_REG1,tmp); + + sensor->ops->ctrl_data = tmp; + + DBG("mma8452 MMA8452_REG_CTRL_REG1:%x\n",sensor_read_reg(client,MMA8452_REG_CTRL_REG1)); + + DBG("mma8452 MMA8452_REG_SYSMOD:%x\n",sensor_read_reg(client,MMA8452_REG_SYSMOD)); + + ret = sensor_write_reg(client,MMA8452_REG_CTRL_REG3,5); + DBG("mma8452 MMA8452_REG_CTRL_REG3:%x\n",sensor_read_reg(client,MMA8452_REG_CTRL_REG3)); + + ret = sensor_write_reg(client,MMA8452_REG_CTRL_REG4,1); + DBG("mma8452 MMA8452_REG_CTRL_REG4:%x\n",sensor_read_reg(client,MMA8452_REG_CTRL_REG4)); + + ret = sensor_write_reg(client,MMA8452_REG_CTRL_REG5,1); + DBG("mma8452 MMA8452_REG_CTRL_REG5:%x\n",sensor_read_reg(client,MMA8452_REG_CTRL_REG5)); + + DBG("mma8452 MMA8452_REG_SYSMOD:%x\n",sensor_read_reg(client,MMA8452_REG_SYSMOD)); + + sensor_sys_init(); + + return ret; +} + +static int sensor_convert_data(struct i2c_client *client, char high_byte, char low_byte) +{ + s64 result; + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + //int precision = sensor->ops->precision; + switch (sensor->devid) { + case MMA8451_DEVID: + swap(high_byte,low_byte); + result = ((int)high_byte << (MMA8451_PRECISION-8)) + | ((int)low_byte >> (16-MMA8451_PRECISION)); + if (result < MMA8451_BOUNDARY) + result = result* MMA8451_GRAVITY_STEP; + else + result = ~( ((~result & (0x7fff>>(16-MMA8451_PRECISION)) ) + 1) + * MMA8451_GRAVITY_STEP) + 1; + break; + + case MMA8452_DEVID: + swap(high_byte,low_byte); + result = ((int)high_byte << (MMA8452_PRECISION-8)) + | ((int)low_byte >> (16-MMA8452_PRECISION)); + if (result < MMA8452_BOUNDARY) + result = result* MMA8452_GRAVITY_STEP; + else + result = ~( ((~result & (0x7fff>>(16-MMA8452_PRECISION)) ) + 1) + * MMA8452_GRAVITY_STEP) + 1; + break; + + case MMA8453_DEVID: + swap(high_byte,low_byte); + result = ((int)high_byte << (MMA8453_PRECISION-8)) + | ((int)low_byte >> (16-MMA8453_PRECISION)); + if (result < MMA8453_BOUNDARY) + result = result* MMA8453_GRAVITY_STEP; + else + result = ~( ((~result & (0x7fff>>(16-MMA8453_PRECISION)) ) + 1) + * MMA8453_GRAVITY_STEP) + 1; + break; + + default: + printk(KERN_ERR "%s: devid wasn't set correctly\n",__func__); + return -EFAULT; + } + + return (int)result; +} + +static int gsensor_report_value(struct i2c_client *client, struct sensor_axis *axis) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + + /* Report acceleration sensor information */ + input_report_abs(sensor->input_dev, ABS_X, axis->x); + input_report_abs(sensor->input_dev, ABS_Y, axis->y); + input_report_abs(sensor->input_dev, ABS_Z, axis->z); + input_sync(sensor->input_dev); + DBG("Gsensor x==%d y==%d z==%d\n",axis->x,axis->y,axis->z); + + return 0; +} + +#define GSENSOR_MIN 10 +static int sensor_report_value(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + struct sensor_platform_data *pdata = sensor->pdata; + int ret = 0; + int x,y,z; + struct sensor_axis axis; + char buffer[6] = {0}; + char value = 0; + + if(sensor->ops->read_len < 6) //sensor->ops->read_len = 6 + { + printk("%s:lenth is error,len=%d\n",__func__,sensor->ops->read_len); + return -1; + } + + memset(buffer, 0, 6); + + /* Data bytes from hardware xL, xH, yL, yH, zL, zH */ + do { + *buffer = sensor->ops->read_reg; + ret = sensor_rx_data(client, buffer, sensor->ops->read_len); + if (ret < 0) + return ret; + } while (0); + + + //this gsensor need 6 bytes buffer + x = sensor_convert_data(sensor->client, buffer[1], buffer[0]); //buffer[1]:high bit + y = sensor_convert_data(sensor->client, buffer[3], buffer[2]); + z = sensor_convert_data(sensor->client, buffer[5], buffer[4]); + + axis.x = (pdata->orientation[0])*x + (pdata->orientation[1])*y + (pdata->orientation[2])*z; + axis.y = (pdata->orientation[3])*x + (pdata->orientation[4])*y + (pdata->orientation[5])*z; + axis.z = (pdata->orientation[6])*x + (pdata->orientation[7])*y + (pdata->orientation[8])*z; + + DBG( "%s: axis = %d %d %d \n", __func__, axis.x, axis.y, axis.z); + + //Report event only while value is changed to save some power + if((abs(sensor->axis.x - axis.x) > GSENSOR_MIN) || (abs(sensor->axis.y - axis.y) > GSENSOR_MIN) || (abs(sensor->axis.z - axis.z) > GSENSOR_MIN)) + { + gsensor_report_value(client, &axis); + + /* 互斥地缓存数据. */ + mutex_lock(&(sensor->data_mutex) ); + sensor->axis = axis; + mutex_unlock(&(sensor->data_mutex) ); + } + + if((sensor->pdata->irq_enable)&& (sensor->ops->int_status_reg >= 0)) //read sensor intterupt status register + { + + value = sensor_read_reg(client, sensor->ops->int_status_reg); + DBG("%s:sensor int status :0x%x\n",__func__,value); + } + + return ret; +} + + +struct sensor_operate gsensor_ops = { + .name = "mma8452", + .type = SENSOR_TYPE_ACCEL, //sensor type and it should be correct + .id_i2c = ACCEL_ID_MMA845X, //i2c id number + .read_reg = MMA8452_REG_X_OUT_MSB, //read data + .read_len = 6, //data length + .id_reg = MMA8452_REG_WHO_AM_I, //read device id from this register + .id_data = MMA8452_DEVID, //device id + .precision = MMA8452_PRECISION, //12 bit + .ctrl_reg = MMA8452_REG_CTRL_REG1, //enable or disable + .int_status_reg = MMA8452_REG_INTSRC, //intterupt status register + .range = {-MMA845X_RANGE,MMA845X_RANGE}, //range + .trig = IRQF_TRIGGER_LOW|IRQF_ONESHOT, + .active = sensor_active, + .init = sensor_init, + .report = sensor_report_value, +}; + +/****************operate according to sensor chip:end************/ + +//function name should not be changed +struct sensor_operate *gsensor_get_ops(void) +{ + return &gsensor_ops; +} + +EXPORT_SYMBOL(gsensor_get_ops); + +static int __init gsensor_init(void) +{ + struct sensor_operate *ops = gsensor_get_ops(); + int result = 0; + int type = ops->type; + result = sensor_register_slave(type, NULL, NULL, gsensor_get_ops); + printk("%s\n",__func__); + return result; +} + +static void __exit gsensor_exit(void) +{ + struct sensor_operate *ops = gsensor_get_ops(); + int type = ops->type; + sensor_unregister_slave(type, NULL, NULL, gsensor_get_ops); +} + + +module_init(gsensor_init); +module_exit(gsensor_exit); + + + From 03d6b5fe194d42add34022f91d083939ff6d7845 Mon Sep 17 00:00:00 2001 From: ywj Date: Thu, 16 Aug 2012 14:27:56 +0800 Subject: [PATCH 197/261] add node of rk29_backlight and rk29_keys for factorytool --- drivers/input/keyboard/rk29_keys.c | 70 ++++++++++++++++++++++++ drivers/video/backlight/rk29_backlight.c | 40 ++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/drivers/input/keyboard/rk29_keys.c b/drivers/input/keyboard/rk29_keys.c index b5881d5b5e93..79e1b678ecd5 100755 --- a/drivers/input/keyboard/rk29_keys.c +++ b/drivers/input/keyboard/rk29_keys.c @@ -30,6 +30,7 @@ #define EMPTY_ADVALUE 950 #define DRIFT_ADVALUE 70 #define INVALID_ADVALUE 10 +#define EV_MENU KEY_F1 #if 0 @@ -57,6 +58,68 @@ struct rk29_keys_drvdata { }; static struct input_dev *input_dev; +struct rk29_keys_Arrary { + char keyArrary[20]; +}; + +static ssize_t rk29key_set(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rk29_keys_platform_data *pdata = dev->platform_data; + int i,j,start,end; + char rk29keyArrary[400]; + struct rk29_keys_Arrary Arrary[]={"menu","home","esc","sensor","play","vol+","vol-"}; + char *p; + + for(i=0;i<7;i++) + { + + p = strstr(buf,&Arrary[i]); + + start = strcspn(p,":"); + + if(i<6) + end = strcspn(p,","); + else + end = strcspn(p,"}"); + + memset(rk29keyArrary,0,sizeof(rk29keyArrary)); + + strncpy(rk29keyArrary,p+start+1,end-start-1); + + for(j=0;j<7;j++) + { + if(strcmp(pdata->buttons[j].desc,&Arrary[i])==0) + { + if(strcmp(rk29keyArrary,"MENU")==0) + pdata->buttons[j].code = EV_MENU; + else if(strcmp(rk29keyArrary,"HOME")==0) + pdata->buttons[j].code = KEY_HOME; + else if(strcmp(rk29keyArrary,"ESC")==0) + pdata->buttons[j].code = KEY_BACK; + else if(strcmp(rk29keyArrary,"sensor")==0) + pdata->buttons[j].code = KEY_CAMERA; + else if(strcmp(rk29keyArrary,"PLAY")==0) + pdata->buttons[j].code = KEY_POWER; + else if(strcmp(rk29keyArrary,"VOLUP")==0) + pdata->buttons[j].code = KEY_VOLUMEUP; + else if(strcmp(rk29keyArrary,"VOLDOWN")==0) + pdata->buttons[j].code = KEY_VOLUMEDOWN; + else + continue; + } + + } + + } + + for(i=0;i<7;i++) + printk("desc=%s, code=%d\n",pdata->buttons[i].desc,pdata->buttons[i].code); + return 0; + +} + +static DEVICE_ATTR(rk29key,0777, NULL, rk29key_set); void rk29_send_power_key(int state) { @@ -322,6 +385,13 @@ static int __devinit keys_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, wakeup); error = device_create_file(&pdev->dev, &dev_attr_get_adc_value); + error = device_create_file(&pdev->dev,&dev_attr_rk29key); + if(error ) + { + pr_err("failed to create key file error: %d\n", error); + } + + input_dev = input; return error; diff --git a/drivers/video/backlight/rk29_backlight.c b/drivers/video/backlight/rk29_backlight.c index a60a0245797c..95ca486472fb 100755 --- a/drivers/video/backlight/rk29_backlight.c +++ b/drivers/video/backlight/rk29_backlight.c @@ -50,6 +50,41 @@ static struct clk *pwm_clk; static struct backlight_device *rk29_bl; static int suspend_flag = 0; + +int convertint(char s[]) +{ + int i; + int n = 0; + for (i = 0; s[i] >= '0' && s[i] <= '9'; ++i) + { + n = 10 * n + (s[i] - '0'); + } + return n; +} + +static ssize_t backlight_write(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + struct rk29_bl_info *rk29_bl_info = bl_get_data(rk29_bl); + int number; + + number = convertint(buf); + + rk29_bl_info->min_brightness=number; + return 0; +} + + +static ssize_t backlight_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rk29_bl_info *rk29_bl_info = bl_get_data(rk29_bl); + + printk("rk29_bl_info->min_brightness=%d\n",rk29_bl_info->min_brightness); +} +static DEVICE_ATTR(rk29backlight, 0777, backlight_read, backlight_write); + static int rk29_bl_update_status(struct backlight_device *bl) { u32 divh,div_total; @@ -232,6 +267,11 @@ static int rk29_backlight_probe(struct platform_device *pdev) rk29_bl->props.brightness = BL_STEP / 2; schedule_delayed_work(&rk29_backlight_work, msecs_to_jiffies(rk29_bl_info->delay_ms)); + ret = device_create_file(&pdev->dev,&dev_attr_rk29backlight); + if(ret) + { + dev_err(&pdev->dev, "failed to create sysfs file\n"); + } register_early_suspend(&bl_early_suspend); From c353c8fed9216ef79b7e46336e618c6eda19cdb5 Mon Sep 17 00:00:00 2001 From: ywj Date: Thu, 16 Aug 2012 14:29:57 +0800 Subject: [PATCH 198/261] new add rk30_factory_adc_battery driver for factorytool --- arch/arm/mach-rk30/board-rk30-sdk.c | 4 +- drivers/power/Kconfig | 10 +- drivers/power/Makefile | 1 + drivers/power/rk30_factory_adc_battery.c | 1611 ++++++++++++++++++++++ 4 files changed, 1622 insertions(+), 4 deletions(-) create mode 100644 drivers/power/rk30_factory_adc_battery.c diff --git a/arch/arm/mach-rk30/board-rk30-sdk.c b/arch/arm/mach-rk30/board-rk30-sdk.c index 4865314c883f..7d668480ac6d 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk.c +++ b/arch/arm/mach-rk30/board-rk30-sdk.c @@ -1316,7 +1316,7 @@ struct rk29_sdmmc_platform_data default_sdmmc1_data = { * the end of setting for SDMMC devices **************************************************************************************************/ -#ifdef CONFIG_BATTERY_RK30_ADC +#if defined(CONFIG_BATTERY_RK30_ADC)||defined(CONFIG_BATTERY_RK30_ADC_FAC) static struct rk30_adc_battery_platform_data rk30_adc_battery_platdata = { .dc_det_pin = RK30_PIN6_PA5, .batt_low_pin = RK30_PIN6_PA0, @@ -1439,7 +1439,7 @@ static struct platform_device *devices[] __initdata = { #if defined(CONFIG_SEW868) &rk30_device_sew868, #endif -#ifdef CONFIG_BATTERY_RK30_ADC +#if defined(CONFIG_BATTERY_RK30_ADC)||defined(CONFIG_BATTERY_RK30_ADC_FAC) &rk30_device_adc_battery, #endif #ifdef CONFIG_RFKILL_RK diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index acd40a735dab..3f99360e4463 100755 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -323,15 +323,21 @@ config BATTERY_RK30_ADC help Say Y to enable support for the battery on the RK30. +config BATTERY_RK30_ADC_FAC + tristate "RK30 ADC Battery Factory" + depends on ADC_RK30 + help + Say Y to enable support for the battery on the RK30. + config BATTERY_RK30_AC_CHARGE tristate "RK30 AC CHARGE" - depends on BATTERY_RK30_ADC + depends on BATTERY_RK30_ADC||BATTERY_RK30_ADC_FAC help say Y to enable suspport for the AC battery charge config BATTERY_RK30_VOL3V8 tristate "the battery voltage is 3.8V" - depends on BATTERY_RK30_ADC + depends on BATTERY_RK30_ADC||BATTERY_RK30_ADC_FAC help say Y to enable suspport for the battery voltage 3.8V diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 6d77beaacf0a..c774f10a69e2 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -45,3 +45,4 @@ obj-$(CONFIG_TWL6030_BCI_BATTERY) += twl6030_bci_battery.o obj-$(CONFIG_BATTERY_RK29_ADC) += rk29_adc_battery.o obj-$(CONFIG_BATTERY_RK30_ADC) += rk30_adc_battery.o obj-$(CONFIG_POWER_ON_CHARGER_DISPLAY) += rk29_charger_display.o +obj-$(CONFIG_BATTERY_RK30_ADC_FAC) += rk30_factory_adc_battery.o diff --git a/drivers/power/rk30_factory_adc_battery.c b/drivers/power/rk30_factory_adc_battery.c new file mode 100644 index 000000000000..02396a374fc1 --- /dev/null +++ b/drivers/power/rk30_factory_adc_battery.c @@ -0,0 +1,1611 @@ +/* drivers/power/rk30_adc_battery.c + * + * battery detect driver for the rk30 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +static int rk30_battery_dbg_level = 1; +module_param_named(dbg_level, rk30_battery_dbg_level, int, 0644); +#define pr_bat( args...) \ + do { \ + if (rk30_battery_dbg_level) { \ + pr_info(args); \ + } \ + } while (0) + + +/*******************以下参数可以修改******************************/ +#define TIMER_MS_COUNTS 1000 //定时器的长度ms +//以下参数需要根据实际测试调整 +#define SLOPE_SECOND_COUNTS 15 //统计电压斜率的时间间隔s +#define DISCHARGE_MIN_SECOND 45 //最快放电电1%时间 +#define CHARGE_MIN_SECOND 45 //最快充电电1%时间 +#define CHARGE_MID_SECOND 90 //普通充电电1%时间 +#define CHARGE_MAX_SECOND 250 //最长充电电1%时间 +#define CHARGE_FULL_DELAY_TIMES 10 //充电满检测防抖时间 +#define USBCHARGE_IDENTIFY_TIMES 5 //插入USB混流,pc识别检测时间 + +#define NUM_VOLTAGE_SAMPLE ((SLOPE_SECOND_COUNTS * 1000) / TIMER_MS_COUNTS) +#define NUM_DISCHARGE_MIN_SAMPLE ((DISCHARGE_MIN_SECOND * 1000) / TIMER_MS_COUNTS) +#define NUM_CHARGE_MIN_SAMPLE ((CHARGE_MIN_SECOND * 1000) / TIMER_MS_COUNTS) +#define NUM_CHARGE_MID_SAMPLE ((CHARGE_MID_SECOND * 1000) / TIMER_MS_COUNTS) +#define NUM_CHARGE_MAX_SAMPLE ((CHARGE_MAX_SECOND * 1000) / TIMER_MS_COUNTS) +#define NUM_CHARGE_FULL_DELAY_TIMES ((CHARGE_FULL_DELAY_TIMES * 1000) / TIMER_MS_COUNTS) //充电满状态持续时间长度 +#define NUM_USBCHARGE_IDENTIFY_TIMES ((USBCHARGE_IDENTIFY_TIMES * 1000) / TIMER_MS_COUNTS) //充电满状态持续时间长度 + +#define BAT_2V5_VALUE 2500 + + +#define BATT_FILENAME "/data/bat_last_capacity.dat" + +static struct wake_lock batt_wake_lock; + + +struct batt_vol_cal{ + u32 disp_cal; + u32 dis_charge_vol; + u32 charge_vol; +}; +#if 0 + +#ifdef CONFIG_BATTERY_RK30_VOL3V8 + +#define BATT_MAX_VOL_VALUE 4120 //满电时的电池电压 +#define BATT_ZERO_VOL_VALUE 3400 //关机时的电池电压 +#define BATT_NOMAL_VOL_VALUE 3800 +//divider resistance +#define BAT_PULL_UP_R 200 +#define BAT_PULL_DOWN_R 200 + +static struct batt_vol_cal batt_table[] = { + {0,3400,3520},{1,3420,3525},{2,3420,3575},{3,3475,3600},{5,3505,3620},{7,3525,3644}, + {9,3540,3662},{11,3557,3670},{13,3570,3684},{15,3580,3700},{17,3610,3715}, + {19,3630,3720},{21,3640,3748},{23,3652,3756},{25,3662,3775},{27,3672,3790}, + {29,3680,3810},{31,3687,3814},{33,3693,3818},{35,3699,3822},{37,3705,3825}, + {39,3710,3830},{41,3714,3832},{43,3718,3834},{45,3722,3836},{47,3726,3837}, + {49,3730,3839},{51,3734,3841},{53,3738,3842},{55,3742,3844},{57,3746,3844}, + {59,3750,3855},{61,3756,3860},{63,3764,3864},{65,3774,3871},{67,3786,3890}, + {69,3800,3910},{71,3808,3930},{73,3817,3977},{75,3827,3977},{77,3845,3997}, + {79,3950,4030},{81,3964,4047},{83,3982,4064},{85,4002,4080},{87,4026,4096}, + {89,4030,4132},{91,4034,4144},{93,4055,4150},{95,4085,4195},{97,4085,4195},{100,4120,4200}, +}; +#else +#define BATT_MAX_VOL_VALUE 8284 //Full charge voltage +#define BATT_ZERO_VOL_VALUE 6800 // power down voltage +#define BATT_NOMAL_VOL_VALUE 7600 + +//定义ADC采样分压电阻,以实际值为准,单位K + +#define BAT_PULL_UP_R 300 +#define BAT_PULL_DOWN_R 100 + +static struct batt_vol_cal batt_table[] = { + {0,6800,7400}, {1,6840,7440}, {2,6880,7480}, {3,6950,7450}, {5,7010,7510}, {7,7050,7550}, + {9,7080,7580}, {11,7104,7604}, {13,7140,7640}, {15,7160,7660}, {17,7220,7720}, + {19,7260,7760}, {21,7280,7780}, {23,7304,7802}, {25,7324,7824}, {27,7344,7844}, + {29,7360,7860}, {31,7374,7874}, {33,7386,7886}, {35,7398,7898}, {37,7410,7910},//500 + {39,7420,7920}, {41,7424,7928}, {43,7436,7947}, {45,7444,7944}, {47,7450,7958}, //508 + {49,7460,7965}, {51,7468,7975}, {53, 7476,7990}, {55,7482,8000}, {57,7492,8005}, // 5 14 + {59,7500,8011}, {61,7510,8033}, {63,7528,8044}, {65,7548,8055}, {67,7560,8066},//506 + {69,7600,8070}, {71,7618,8075}, {73,7634,8080}, {75,7654,8085}, {77,7690,8100}, //400 + {79,7900,8180}, {81,7920,8210}, {83,7964,8211}, {85,8000,8214}, {87,8002,8218},//290 + {89,8012, 8220}, {91,8022,8235}, {93,8110,8260}, {95,8140,8290}, {97,8170,8300}, {100,8200 ,8310},//110 + +}; +#endif + + + +#define BATT_NUM ARRAY_SIZE(batt_table) +#endif + +#define BATTERY_APK + +#ifdef BATTERY_APK + +#define BATT_NUM 11 +#include +int battery_dbg_level = 0; +int battery_test_flag = 0; +int gVoltageCnt = 3400; +int gDoubleVoltageCnt = 6800; +#ifdef CONFIG_BATTERY_RK30_VOL3V8 +#define BATT_MAX_VOL_VALUE 4120 //满电时的电池电压 +#define BATT_ZERO_VOL_VALUE 3400 //关机时的电池电压 +#define BATT_NOMAL_VOL_VALUE 3800 + +//int pull_up_res =100; +//int pull_down_res = 100; + + +static int batt_table[2*BATT_NUM+6] = +{ + 0x4B434F52,0x7461625F,0x79726574,0,100,100, + 3496, 3548, 3599, 3626, 3655, 3697, 3751, 3812, 3877, 3949, 4030, //discharge + 3540, 3785, 3842, 3861, 3915, 3980, 4041, 4135, 4169, 4175, 4185 //charge +}; +#define adc_to_voltage(adc_val) ((adc_val * BAT_2V5_VALUE * (batt_table[4] +batt_table[5])) / (1024 *batt_table[5])) +#else +#define BATT_MAX_VOL_VALUE 8284 //Full charge voltage +#define BATT_ZERO_VOL_VALUE 6800 // power down voltage +#define BATT_NOMAL_VOL_VALUE 7600 +//int pull_up_res =300; +//int pull_down_res = 100; +//定义ADC采样分压电阻,以实际值为准,单位K + +static int batt_table[2*BATT_NUM+6] = +{ + 0x4B434F52,0x7461625F,0x79726574,1,300,100, + 6800,7242,7332,7404,7470,7520,7610,7744,7848,8016,8284, + 7630, 7754, 7852, 7908, 7956, 8024, 8112, 8220, 8306, 8318, 8328 +}; +#define adc_to_voltage(adc_val) ((adc_val * BAT_2V5_VALUE * (batt_table[4] +batt_table[5])) / (1024 *batt_table[5])) + + +#endif +#else +//#define adc_to_voltage(adc_val) ((adc_val * BAT_2V5_VALUE * (BAT_PULL_UP_R + BAT_PULL_DOWN_R)) / (1024 * BAT_PULL_DOWN_R)) +#endif +int Cnt=0; +unsigned long gSecondsCnt = 0; + +char gDischargeFlag[3] = {"on "}; + + +/********************************************************************************/ + +extern int dwc_vbus_status(void); +extern int get_msc_connect_flag(void); + +struct rk30_adc_battery_data { + int irq; + + //struct timer_list timer; + struct workqueue_struct *wq; + struct delayed_work delay_work; + struct work_struct dcwakeup_work; + struct work_struct lowerpower_work; + bool resume; + + struct rk30_adc_battery_platform_data *pdata; + + int full_times; + + struct adc_client *client; + int adc_val; + int adc_samples[NUM_VOLTAGE_SAMPLE+2]; + + int bat_status; + int bat_status_cnt; + int bat_health; + int bat_present; + int bat_voltage; + int bat_capacity; + int bat_change; + + int old_charge_level; + int *pSamples; + int gBatCapacityDisChargeCnt; + int gBatCapacityChargeCnt; + int capacitytmp; + int poweron_check; + int suspend_capacity; + + int status_lock; + +}; +static struct rk30_adc_battery_data *gBatteryData; + + +#ifdef BATTERY_APK +#define BAT_ADC_TABLE_LEN 11 +static ssize_t bat_param_read(struct device *dev,struct device_attribute *attr, char *buf) +{ +#if 1 + int i; + for(i=0;ipdata; + + return sprintf(buf, + "gBatVol=%d,gBatCap=%d,charge_ok=%d,%s\n", + gBatteryData->bat_voltage,gBatteryData->bat_capacity, + gpio_get_value(pdata->charge_ok_pin),gDischargeFlag); +} + +static ssize_t rkbatt_restore_state_attrs(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + return size; +} + +static ssize_t rkbatt_show_value_attrs(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "pull_up_res =%d,\npull_down_res=%d\n", batt_table[4],batt_table[5]); +} + +static ssize_t rkbatt_restore_value_attrs(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int liUp = 0; + int liDown = 0; + + sscanf(buf, "%d,%d", &liUp,&liDown); + + if(liUp != 0 && liDown != 0) + { + batt_table[4] = liUp; + batt_table[5] = liDown; + } + else + { + //nothing + } + return size; +} + +static ssize_t rkbatt_show_flag_attrs(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "rk29_battery_test_flag=%d\n", battery_test_flag); +} +static ssize_t rkbatt_restore_flag_attrs(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int liFlag; + + sscanf(buf, "%d", &liFlag); + + if(liFlag != 0) + { + battery_test_flag = liFlag; + } + return size; +} +static struct device_attribute rkbatt_attrs[] = { + __ATTR(state, 0664, rkbatt_show_state_attrs, rkbatt_restore_state_attrs), + __ATTR(debug, 0664, rkbatt_show_debug_attrs, rkbatt_restore_debug_attrs), + __ATTR(value, 0666, rkbatt_show_value_attrs, rkbatt_restore_value_attrs), + __ATTR(flag, 0666, rkbatt_show_flag_attrs, rkbatt_restore_flag_attrs), +}; + +static int create_sysfs_interfaces(struct device *dev) +{ + int liTmep; + for (liTmep = 0; liTmep < ARRAY_SIZE(rkbatt_attrs); liTmep++) + { + if (device_create_file(dev, rkbatt_attrs + liTmep)) + { + goto error; + } + } + + return 0; + +error: + for ( ; liTmep >= 0; liTmep--) + { + device_remove_file(dev, rkbatt_attrs + liTmep); + } + + dev_err(dev, "%s:Unable to create sysfs interface\n", __func__); + return -1; +} + +#endif + + + +enum { + BATTERY_STATUS = 0, + BATTERY_HEALTH = 1, + BATTERY_PRESENT = 2, + BATTERY_CAPACITY = 3, + BATTERY_AC_ONLINE = 4, + BATTERY_STATUS_CHANGED = 5, + AC_STATUS_CHANGED = 6, + BATTERY_INT_STATUS = 7, + BATTERY_INT_ENABLE = 8, +}; + +typedef enum { + CHARGER_BATTERY = 0, + CHARGER_USB, + CHARGER_AC +} charger_type_t; + + + + + +static int rk30_adc_battery_load_capacity(void) +{ + char value[4]; + int* p = (int *)value; + long fd = sys_open(BATT_FILENAME,O_RDONLY,0); + + if(fd < 0){ + pr_bat("rk30_adc_battery_load_capacity: open file /data/bat_last_capacity.dat failed\n"); + return -1; + } + + sys_read(fd,(char __user *)value,4); + sys_close(fd); + + return (*p); +} + +static void rk30_adc_battery_put_capacity(int loadcapacity) +{ + char value[4]; + int* p = (int *)value; + long fd = sys_open(BATT_FILENAME,O_CREAT | O_RDWR,0); + + if(fd < 0){ + pr_bat("rk30_adc_battery_put_capacity: open file /data/bat_last_capacity.dat failed\n"); + return; + } + + *p = loadcapacity; + sys_write(fd, (const char __user *)value, 4); + + sys_close(fd); +} + +static void rk30_adc_battery_charge_enable(struct rk30_adc_battery_data *bat) +{ + struct rk30_adc_battery_platform_data *pdata = bat->pdata; + + if (pdata->charge_set_pin != INVALID_GPIO){ + gpio_direction_output(pdata->charge_set_pin, pdata->charge_set_level); + } +} + +static void rk30_adc_battery_charge_disable(struct rk30_adc_battery_data *bat) +{ + struct rk30_adc_battery_platform_data *pdata = bat->pdata; + + if (pdata->charge_set_pin != INVALID_GPIO){ + gpio_direction_output(pdata->charge_set_pin, 1 - pdata->charge_set_level); + } +} + +//extern int suspend_flag; +static int rk30_adc_battery_get_charge_level(struct rk30_adc_battery_data *bat) +{ + int charge_on = 0; + struct rk30_adc_battery_platform_data *pdata = bat->pdata; + +#if defined (CONFIG_BATTERY_RK30_AC_CHARGE) + if (pdata->dc_det_pin != INVALID_GPIO){ + if (gpio_get_value (pdata->dc_det_pin) == pdata->dc_det_level){ + charge_on = 1; + } + } +#endif + +#if defined (CONFIG_BATTERY_RK30_USB_CHARGE) + if (charge_on == 0){ + if (suspend_flag) + return; + if (1 == dwc_vbus_status()) { //检测到USB插入,但是无法识别是否是充电器 + //通过延时检测PC识别标志,如果超时检测不到,说明是充电 + if (0 == get_msc_connect_flag()){ //插入充电器时间大于一定时间之后,开始进入充电状态 + if (++gBatUsbChargeCnt >= NUM_USBCHARGE_IDENTIFY_TIMES){ + gBatUsbChargeCnt = NUM_USBCHARGE_IDENTIFY_TIMES + 1; + charge_on = 1; + } + } //否则,不进入充电模式 + } + else{ + gBatUsbChargeCnt = 0; + if (2 == dwc_vbus_status()) { + charge_on = 1; + } + } + } +#endif + return charge_on; +} + +//int old_charge_level; +static int rk30_adc_battery_status_samples(struct rk30_adc_battery_data *bat) +{ + int charge_level; + + struct rk30_adc_battery_platform_data *pdata = bat->pdata; + + charge_level = rk30_adc_battery_get_charge_level(bat); + + //检测充电状态变化情况 + if (charge_level != bat->old_charge_level){ + bat->old_charge_level = charge_level; + bat->bat_change = 1; + + if(charge_level) { + rk30_adc_battery_charge_enable(bat); + } + else{ + rk30_adc_battery_charge_disable(bat); + } + bat->bat_status_cnt = 0; //状态变化开始计数 + } + + if(charge_level == 0){ + //discharge + bat->full_times = 0; + bat->bat_status = POWER_SUPPLY_STATUS_NOT_CHARGING; + } + else{ + //CHARGE + if (pdata->charge_ok_pin == INVALID_GPIO){ //no charge_ok_pin + + if (bat->bat_capacity == 100){ + if (bat->bat_status != POWER_SUPPLY_STATUS_FULL){ + bat->bat_status = POWER_SUPPLY_STATUS_FULL; + bat->bat_change = 1; + } + } + else{ + bat->bat_status = POWER_SUPPLY_STATUS_CHARGING; + } + } + else{ // pin of charge_ok_pin + if (gpio_get_value(pdata->charge_ok_pin) != pdata->charge_ok_level){ + + bat->full_times = 0; + bat->bat_status = POWER_SUPPLY_STATUS_CHARGING; + } + else{ + //检测到充电满电平标志 + bat->full_times++; + + if (bat->full_times >= NUM_CHARGE_FULL_DELAY_TIMES) { + bat->full_times = NUM_CHARGE_FULL_DELAY_TIMES + 1; + } + + if ((bat->full_times >= NUM_CHARGE_FULL_DELAY_TIMES) && (bat->bat_capacity >= 99)){ + if (bat->bat_status != POWER_SUPPLY_STATUS_FULL){ + bat->bat_status = POWER_SUPPLY_STATUS_FULL; + bat->bat_capacity = 100; + bat->bat_change = 1; + } + } + else{ + bat->bat_status = POWER_SUPPLY_STATUS_CHARGING; + } + } + } + } + + return charge_level; +} + +static int *pSamples; +static void rk30_adc_battery_voltage_samples(struct rk30_adc_battery_data *bat) +{ + int value; + int i,*pStart = bat->adc_samples, num = 0; + int level = rk30_adc_battery_get_charge_level(bat); + + + value = bat->adc_val; + adc_async_read(bat->client); + + *pSamples++ = adc_to_voltage(value); + + bat->bat_status_cnt++; + if (bat->bat_status_cnt > NUM_VOLTAGE_SAMPLE) bat->bat_status_cnt = NUM_VOLTAGE_SAMPLE + 1; + + num = pSamples - pStart; + + if (num >= NUM_VOLTAGE_SAMPLE){ + pSamples = pStart; + num = NUM_VOLTAGE_SAMPLE; + + } + + value = 0; + for (i = 0; i < num; i++){ + value += bat->adc_samples[i]; + } + bat->bat_voltage = value / num; + + /*消除毛刺电压*/ +if(battery_test_flag == 0) +{ + if(1 == level){ + if(bat->bat_voltage >= batt_table[2*BATT_NUM +5]+ 10) + bat->bat_voltage = batt_table[2*BATT_NUM +5] + 10; + else if(bat->bat_voltage <= batt_table[BATT_NUM +6] - 10) + bat->bat_voltage = batt_table[BATT_NUM +6] - 10; + } + else{ + if(bat->bat_voltage >= batt_table[BATT_NUM +5]+ 10) + bat->bat_voltage = batt_table[BATT_NUM +5] + 10; + else if(bat->bat_voltage <= batt_table[6] - 10) + bat->bat_voltage = batt_table[6] - 10; + + } +}else if(battery_test_flag == 2) +/**************************************************/ + { + if(batt_table[3] == 0) + { + if(bat->bat_voltage < 3400) + { + //printk("gSecondsCnt=%ld,get_seconds()=%ld,(get_seconds() - gSecondsCnt)=%ld-------------------1\n",gSecondsCnt,get_seconds(),(get_seconds() - gSecondsCnt)); + if((get_seconds() - gSecondsCnt) > 30) + { + gSecondsCnt = get_seconds(); + //printk("gSecondsCnt=%ld,gVoltageCnt=%d,(gVoltageCnt - bat->bat_voltage)=%d,bat->bat_voltage=%d-------------------2\n",gSecondsCnt,gVoltageCnt,(gVoltageCnt - bat->bat_voltage),bat->bat_voltage); + if((gVoltageCnt - bat->bat_voltage) > 15) + { + //gVoltageCnt = bat->bat_voltage; + //printk("gVoltageCnt=%d-------------------3\n",gVoltageCnt); + strncpy(gDischargeFlag, "off" ,3); + } + gVoltageCnt = bat->bat_voltage; + + } + } + + if(bat->bat_voltage < 3400) + { + bat->bat_voltage = 3400; + } + } + else + { + if(bat->bat_voltage < 6800) + { + //printk("gSecondsCnt=%ld,get_seconds()=%ld,(get_seconds() - gSecondsCnt)=%ld-------------------1\n",gSecondsCnt,get_seconds(),(get_seconds() - gSecondsCnt)); + if((get_seconds() - gSecondsCnt) > 30) + { + gSecondsCnt = get_seconds(); + //printk("gSecondsCnt=%ld,gVoltageCnt=%d,(gVoltageCnt - bat->bat_voltage)=%d,bat->bat_voltage=%d-------------------2\n",gSecondsCnt,gVoltageCnt,(gVoltageCnt - bat->bat_voltage),bat->bat_voltage); + if((gDoubleVoltageCnt - bat->bat_voltage) > 30) + { + //gVoltageCnt = bat->bat_voltage; + //printk("gVoltageCnt=%d-------------------3\n",gVoltageCnt); + strncpy(gDischargeFlag, "off" ,3); + } + gDoubleVoltageCnt =bat->bat_voltage; + } + } + if(bat->bat_voltage < 6800) + { + bat->bat_voltage = 6800; + } + } + } +/****************************************************/ +} +static int rk30_adc_battery_voltage_to_capacity(struct rk30_adc_battery_data *bat, int BatVoltage) +{ + int i = 0; + int capacity = 0; + + int *p; + p = batt_table; + + if (rk30_adc_battery_get_charge_level(bat)){ //charge + if(BatVoltage >= (p[2*BATT_NUM +5])){ + capacity = 100; + } + else{ + if(BatVoltage <= (p[BATT_NUM +6])){ + capacity = 0; + } + else{ + for(i = BATT_NUM +6; i <2*BATT_NUM +6; i++){ + + if(((p[i]) <= BatVoltage) && (BatVoltage < (p[i+1]))){ + capacity = (i-BATT_NUM +6)*10 + ((BatVoltage - p[i]) * 10)/ (p[i+1]- p[i]); + break; + } + } + } + } + + } + else{ //discharge + if(BatVoltage >= (p[BATT_NUM +5])){ + capacity = 100; + } + else{ + if(BatVoltage <= (p[6])){ + capacity = 0; + } + else{ + for(i = 6; i < BATT_NUM +6; i++){ + if(((p[i]) <= BatVoltage) && (BatVoltage < (p[i+1]))){ + capacity = (i-6)*10+ ((BatVoltage - p[i]) *10 )/ (p[i+1]- p[i]) ; + break; + } + } + } + + } + + + } + return capacity; +} + +static void rk30_adc_battery_capacity_samples(struct rk30_adc_battery_data *bat) +{ + int capacity = 0; + struct rk30_adc_battery_platform_data *pdata = bat->pdata; + + //充放电状态变化后,Buffer填满之前,不更新 + if (bat->bat_status_cnt < NUM_VOLTAGE_SAMPLE) { + bat->gBatCapacityDisChargeCnt = 0; + bat->gBatCapacityChargeCnt = 0; + return; + } + + capacity = rk30_adc_battery_voltage_to_capacity(bat, bat->bat_voltage); + + if (rk30_adc_battery_get_charge_level(bat)){ + if (capacity > bat->bat_capacity){ + //实际采样到的容量比显示的容量大,逐级上升 + if (++(bat->gBatCapacityDisChargeCnt) >= NUM_CHARGE_MIN_SAMPLE){ + bat->gBatCapacityDisChargeCnt = 0; + if (bat->bat_capacity < 99){ + bat->bat_capacity++; + bat->bat_change = 1; + } + } + bat->gBatCapacityChargeCnt = 0; + } + else{ // 实际的容量比采样比 显示的容量小 + bat->gBatCapacityDisChargeCnt = 0; + (bat->gBatCapacityChargeCnt)++; + + if (pdata->charge_ok_pin != INVALID_GPIO){ + if (gpio_get_value(pdata->charge_ok_pin) == pdata->charge_ok_level){ + //检测到电池充满标志,同时长时间内充电电压无变化,开始启动计时充电,快速上升容量 + if (bat->gBatCapacityChargeCnt >= NUM_CHARGE_MIN_SAMPLE){ + bat->gBatCapacityChargeCnt = 0; + if (bat->bat_capacity < 99){ + bat->bat_capacity++; + bat->bat_change = 1; + } + } + } + else{ +#if 0 + if (capacity > capacitytmp){ + //过程中如果电压有增长,定时器复位,防止定时器模拟充电比实际充电快 + gBatCapacityChargeCnt = 0; + } + else if (/*bat->bat_capacity >= 85) &&*/ (gBatCapacityChargeCnt > NUM_CHARGE_MAX_SAMPLE)){ + gBatCapacityChargeCnt = (NUM_CHARGE_MAX_SAMPLE - NUM_CHARGE_MID_SAMPLE); + + if (bat->bat_capacity < 99){ + bat->bat_capacity++; + bat->bat_change = 1; + } + } + } +#else // 防止电池老化后出现冲不满的情况, + if (capacity > bat->capacitytmp){ + //过程中如果电压有增长,定时器复位,防止定时器模拟充电比实际充电快 + bat->gBatCapacityChargeCnt = 0; + } + else{ + + if ((bat->bat_capacity >= 85) &&((bat->gBatCapacityChargeCnt) > NUM_CHARGE_MAX_SAMPLE)){ + bat->gBatCapacityChargeCnt = (NUM_CHARGE_MAX_SAMPLE - NUM_CHARGE_MID_SAMPLE); + + if (bat->bat_capacity < 99){ + bat->bat_capacity++; + bat->bat_change = 1; + } + } + } + } +#endif + + } + else{ + //没有充电满检测脚,长时间内电压无变化,定时器模拟充电 + if (capacity > bat->capacitytmp){ + //过程中如果电压有增长,定时器复位,防止定时器模拟充电比实际充电快 + bat->gBatCapacityChargeCnt = 0; + } + else{ + + if ((bat->bat_capacity >= 85) &&(bat->gBatCapacityChargeCnt > NUM_CHARGE_MAX_SAMPLE)){ + bat->gBatCapacityChargeCnt = (NUM_CHARGE_MAX_SAMPLE - NUM_CHARGE_MID_SAMPLE); + + if (bat->bat_capacity < 99){ + bat->bat_capacity++; + bat->bat_change = 1; + } + } + } + + + } + } + } + else{ + //放电时,只允许电压下降 + if (capacity < bat->bat_capacity){ + if (++(bat->gBatCapacityDisChargeCnt) >= NUM_DISCHARGE_MIN_SAMPLE){ + bat->gBatCapacityDisChargeCnt = 0; + if (bat->bat_capacity > 0){ + bat->bat_capacity-- ; + bat->bat_change = 1; + } + } + } + else{ + bat->gBatCapacityDisChargeCnt = 0; + } + bat->gBatCapacityChargeCnt = 0; + } + bat->capacitytmp = capacity; +} + +//static int poweron_check = 0; +static void rk30_adc_battery_poweron_capacity_check(void) +{ + + int new_capacity, old_capacity; + + new_capacity = gBatteryData->bat_capacity; + old_capacity = rk30_adc_battery_load_capacity(); + if ((old_capacity <= 0) || (old_capacity >= 100)){ + old_capacity = new_capacity; + } + + if (gBatteryData->bat_status == POWER_SUPPLY_STATUS_FULL){ + if (new_capacity > 80){ + gBatteryData->bat_capacity = 100; + } + } + else if (gBatteryData->bat_status != POWER_SUPPLY_STATUS_NOT_CHARGING){ + //chargeing state + //问题: +// //1)长时间关机放置后,开机后读取的容量远远大于实际容量怎么办? +// //2)如果不这样做,短时间关机再开机,前后容量不一致又该怎么办? +// //3)一下那种方式合适? + //gBatteryData->bat_capacity = new_capacity; + gBatteryData->bat_capacity = (new_capacity > old_capacity) ? new_capacity : old_capacity; + }else{ + + if(new_capacity > old_capacity + 50 ) + gBatteryData->bat_capacity = new_capacity; + else + gBatteryData->bat_capacity = (new_capacity < old_capacity) ? new_capacity : old_capacity; //avoid the value of capacity increase + } + + + //printk("capacity = %d, new_capacity = %d, old_capacity = %d\n",gBatteryData->bat_capacity, new_capacity, old_capacity); + + gBatteryData->bat_change = 1; +} + +#if defined(CONFIG_BATTERY_RK30_USB_CHARGE) +static int rk30_adc_battery_get_usb_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + charger_type_t charger; + charger = CHARGER_USB; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + if (psy->type == POWER_SUPPLY_TYPE_USB) + val->intval = get_msc_connect_flag(); + printk("%s:%d\n",__FUNCTION__,val->intval); + break; + + default: + return -EINVAL; + } + + return 0; + +} + +static enum power_supply_property rk30_adc_battery_usb_props[] = { + + POWER_SUPPLY_PROP_ONLINE, +}; + +static struct power_supply rk30_usb_supply = +{ + .name = "usb", + .type = POWER_SUPPLY_TYPE_USB, + + .get_property = rk30_adc_battery_get_usb_property, + + .properties = rk30_adc_battery_usb_props, + .num_properties = ARRAY_SIZE(rk30_adc_battery_usb_props), +}; +#endif + +#if defined(CONFIG_BATTERY_RK30_AC_CHARGE) +static irqreturn_t rk30_adc_battery_dc_wakeup(int irq, void *dev_id) +{ + queue_work(gBatteryData->wq, &gBatteryData->dcwakeup_work); + return IRQ_HANDLED; +} + + +static int rk30_adc_battery_get_ac_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + int ret = 0; + charger_type_t charger; + charger = CHARGER_USB; + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + if (psy->type == POWER_SUPPLY_TYPE_MAINS) + { + if (rk30_adc_battery_get_charge_level(gBatteryData)) + { + val->intval = 1; + } + else + { + val->intval = 0; + } + } + DBG("%s:%d\n",__FUNCTION__,val->intval); + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static enum power_supply_property rk30_adc_battery_ac_props[] = +{ + POWER_SUPPLY_PROP_ONLINE, +}; + +static struct power_supply rk30_ac_supply = +{ + .name = "ac", + .type = POWER_SUPPLY_TYPE_MAINS, + + .get_property = rk30_adc_battery_get_ac_property, + + .properties = rk30_adc_battery_ac_props, + .num_properties = ARRAY_SIZE(rk30_adc_battery_ac_props), +}; + +static void rk30_adc_battery_dcdet_delaywork(struct work_struct *work) +{ + int ret; + struct rk30_adc_battery_platform_data *pdata; + int irq; + int irq_flag; + + pdata = gBatteryData->pdata; + irq = gpio_to_irq(pdata->dc_det_pin); + irq_flag = gpio_get_value (pdata->dc_det_pin) ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING; + + rk28_send_wakeup_key(); // wake up the system + + free_irq(irq, NULL); + ret = request_irq(irq, rk30_adc_battery_dc_wakeup, irq_flag, "ac_charge_irq", NULL);// reinitialize the DC irq + if (ret) { + free_irq(irq, NULL); + } + + power_supply_changed(&rk30_ac_supply); + + gBatteryData->bat_status_cnt = 0; //the state of battery is change + +} + + +#endif + +static int rk30_adc_battery_get_status(struct rk30_adc_battery_data *bat) +{ + return (bat->bat_status); +} + +static int rk30_adc_battery_get_health(struct rk30_adc_battery_data *bat) +{ + return POWER_SUPPLY_HEALTH_GOOD; +} + +static int rk30_adc_battery_get_present(struct rk30_adc_battery_data *bat) +{ + return (bat->bat_voltage < BATT_MAX_VOL_VALUE) ? 0 : 1; +} + +static int rk30_adc_battery_get_voltage(struct rk30_adc_battery_data *bat) +{ + return (bat->bat_voltage ); +} + +static int rk30_adc_battery_get_capacity(struct rk30_adc_battery_data *bat) +{ + return (bat->bat_capacity); +} + +static int rk30_adc_battery_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + int ret = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = rk30_adc_battery_get_status(gBatteryData); + DBG("gBatStatus=%d\n",val->intval); + break; + case POWER_SUPPLY_PROP_HEALTH: + val->intval = rk30_adc_battery_get_health(gBatteryData); + DBG("gBatHealth=%d\n",val->intval); + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = rk30_adc_battery_get_present(gBatteryData); + DBG("gBatPresent=%d\n",val->intval); + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val ->intval = rk30_adc_battery_get_voltage(gBatteryData); + DBG("gBatVoltage=%d\n",val->intval); + break; + // case POWER_SUPPLY_PROP_CURRENT_NOW: + // val->intval = 1100; + // break; + case POWER_SUPPLY_PROP_CAPACITY: + if(battery_test_flag == 2) + val->intval = 50; + else + val->intval = rk30_adc_battery_get_capacity(gBatteryData); + DBG("gBatCapacity=%d%%\n",val->intval); + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = POWER_SUPPLY_TECHNOLOGY_LION; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + val->intval = BATT_MAX_VOL_VALUE; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + val->intval = BATT_ZERO_VOL_VALUE; + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static enum power_supply_property rk30_adc_battery_props[] = { + + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_VOLTAGE_NOW, +// POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, +}; + +static struct power_supply rk30_battery_supply = +{ + .name = "battery", + .type = POWER_SUPPLY_TYPE_BATTERY, + + .get_property = rk30_adc_battery_get_property, + + .properties = rk30_adc_battery_props, + .num_properties = ARRAY_SIZE(rk30_adc_battery_props), +}; + +#ifdef CONFIG_PM +static void rk30_adc_battery_resume_check(void) +{ + int i; + int level,oldlevel; + int new_capacity, old_capacity; + struct rk30_adc_battery_data *bat = gBatteryData; + + bat->old_charge_level = -1; + pSamples = bat->adc_samples; + + adc_sync_read(bat->client); //start adc sample + level = oldlevel = rk30_adc_battery_status_samples(bat);//init charge status + + for (i = 0; i < NUM_VOLTAGE_SAMPLE; i++) { //0.3 s + + mdelay(1); + rk30_adc_battery_voltage_samples(bat); //get voltage + level = rk30_adc_battery_status_samples(bat); //check charge status + if (oldlevel != level){ + oldlevel = level; //if charge status changed, reset sample + i = 0; + } + } + new_capacity = rk30_adc_battery_voltage_to_capacity(bat, bat->bat_voltage); + old_capacity =gBatteryData-> suspend_capacity; + + if (bat->bat_status != POWER_SUPPLY_STATUS_NOT_CHARGING){ + //chargeing state + bat->bat_capacity = (new_capacity > old_capacity) ? new_capacity : old_capacity; + } + else{ + bat->bat_capacity = (new_capacity < old_capacity) ? new_capacity : old_capacity; // aviod the value of capacity increase dicharge + } + +} + +static int rk30_adc_battery_suspend(struct platform_device *dev, pm_message_t state) +{ + int irq; + gBatteryData->suspend_capacity = gBatteryData->bat_capacity; + cancel_delayed_work(&gBatteryData->delay_work); + + if( gBatteryData->pdata->batt_low_pin != INVALID_GPIO){ + + irq = gpio_to_irq(gBatteryData->pdata->batt_low_pin); + enable_irq(irq); + enable_irq_wake(irq); + } + + return 0; +} + +static int rk30_adc_battery_resume(struct platform_device *dev) +{ + int irq; + gBatteryData->resume = true; + queue_delayed_work(gBatteryData->wq, &gBatteryData->delay_work, msecs_to_jiffies(100)); + if( gBatteryData->pdata->batt_low_pin != INVALID_GPIO){ + + irq = gpio_to_irq(gBatteryData->pdata->batt_low_pin); + disable_irq_wake(irq); + disable_irq(irq); + } + return 0; +} +#else +#define rk30_adc_battery_suspend NULL +#define rk30_adc_battery_resume NULL +#endif + + +unsigned long AdcTestCnt = 0; +static void rk30_adc_battery_timer_work(struct work_struct *work) +{ +#ifdef CONFIG_PM + if (gBatteryData->resume) { + rk30_adc_battery_resume_check(); + gBatteryData->resume = false; + } +#endif + + + rk30_adc_battery_status_samples(gBatteryData); + + if (gBatteryData->poweron_check){ + gBatteryData->poweron_check = 0; + rk30_adc_battery_poweron_capacity_check(); + } + + rk30_adc_battery_voltage_samples(gBatteryData); + rk30_adc_battery_capacity_samples(gBatteryData); + + if( 1 == rk30_adc_battery_get_charge_level(gBatteryData)){ // charge + if(0 == gBatteryData->status_lock ){ + wake_lock(&batt_wake_lock); //lock + gBatteryData->status_lock = 1; + } + } + else{ + if(1 == gBatteryData->status_lock ){ + wake_unlock(&batt_wake_lock); //unlock + gBatteryData->status_lock = 0; + } + + } + + + /*update battery parameter after adc and capacity has been changed*/ + if(gBatteryData->bat_change){ + gBatteryData->bat_change = 0; + rk30_adc_battery_put_capacity(gBatteryData->bat_capacity); + power_supply_changed(&rk30_battery_supply); + } + + if (rk30_battery_dbg_level){ + if (++AdcTestCnt >= 2) + { + AdcTestCnt = 0; + + printk("Status = %d, RealAdcVal = %d, RealVol = %d,gBatVol = %d, gBatCap = %d, RealCapacity = %d, dischargecnt = %d, chargecnt = %d\n", + gBatteryData->bat_status, gBatteryData->adc_val, adc_to_voltage(gBatteryData->adc_val), + gBatteryData->bat_voltage, gBatteryData->bat_capacity, gBatteryData->capacitytmp, gBatteryData->gBatCapacityDisChargeCnt,gBatteryData-> gBatCapacityChargeCnt); + + } + } + queue_delayed_work(gBatteryData->wq, &gBatteryData->delay_work, msecs_to_jiffies(TIMER_MS_COUNTS)); + +} + + +static int rk30_adc_battery_io_init(struct rk30_adc_battery_platform_data *pdata) +{ + int ret = 0; + + if (pdata->io_init) { + pdata->io_init(); + } + + //charge control pin + if (pdata->charge_set_pin != INVALID_GPIO){ + ret = gpio_request(pdata->charge_set_pin, NULL); + if (ret) { + printk("failed to request dc_det gpio\n"); + goto error; + } + gpio_direction_output(pdata->charge_set_pin, 1 - pdata->charge_set_level); + } + + //dc charge detect pin + if (pdata->dc_det_pin != INVALID_GPIO){ + ret = gpio_request(pdata->dc_det_pin, NULL); + if (ret) { + printk("failed to request dc_det gpio\n"); + goto error; + } + + gpio_pull_updown(pdata->dc_det_pin, GPIOPullUp);//important + ret = gpio_direction_input(pdata->dc_det_pin); + if (ret) { + printk("failed to set gpio dc_det input\n"); + goto error; + } + } + + //charge ok detect + if (pdata->charge_ok_pin != INVALID_GPIO){ + ret = gpio_request(pdata->charge_ok_pin, NULL); + if (ret) { + printk("failed to request charge_ok gpio\n"); + goto error; + } + + gpio_pull_updown(pdata->charge_ok_pin, GPIOPullUp);//important + ret = gpio_direction_input(pdata->charge_ok_pin); + if (ret) { + printk("failed to set gpio charge_ok input\n"); + goto error; + } + } + //batt low pin + if( pdata->batt_low_pin != INVALID_GPIO){ + ret = gpio_request(pdata->batt_low_pin, NULL); + if (ret) { + printk("failed to request batt_low_pin gpio\n"); + goto error; + } + + gpio_pull_updown(pdata->batt_low_pin, GPIOPullUp); + ret = gpio_direction_input(pdata->batt_low_pin); + if (ret) { + printk("failed to set gpio batt_low_pin input\n"); + goto error; + } + } + + return 0; +error: + return -1; +} + +//extern void kernel_power_off(void); +static void rk30_adc_battery_check(struct rk30_adc_battery_data *bat) +{ + int i; + int level,oldlevel; + struct rk30_adc_battery_platform_data *pdata = bat->pdata; + //printk("%s--%d:\n",__FUNCTION__,__LINE__); + + bat->old_charge_level = -1; + bat->capacitytmp = 0; + bat->suspend_capacity = 0; + + pSamples = bat->adc_samples; + + adc_sync_read(bat->client); //start adc sample + level = oldlevel = rk30_adc_battery_status_samples(bat);//init charge status + + bat->full_times = 0; + for (i = 0; i < NUM_VOLTAGE_SAMPLE; i++){ //0.3 s + mdelay(1); + rk30_adc_battery_voltage_samples(bat); //get voltage + //level = rk30_adc_battery_status_samples(bat); //check charge status + level = rk30_adc_battery_get_charge_level(bat); + + if (oldlevel != level){ + oldlevel = level; //if charge status changed, reset sample + i = 0; + } + } + + bat->bat_capacity = rk30_adc_battery_voltage_to_capacity(bat, bat->bat_voltage); //init bat_capacity + + + bat->bat_status = POWER_SUPPLY_STATUS_NOT_CHARGING; + if (rk30_adc_battery_get_charge_level(bat)){ + bat->bat_status = POWER_SUPPLY_STATUS_CHARGING; + + if (pdata->charge_ok_pin != INVALID_GPIO){ + if (gpio_get_value(pdata->charge_ok_pin) == pdata->charge_ok_level){ + bat->bat_status = POWER_SUPPLY_STATUS_FULL; + bat->bat_capacity = 100; + } + } + } + + + +#if 1 + rk30_adc_battery_poweron_capacity_check(); +#else + gBatteryData->poweron_check = 1; +#endif + gBatteryData->poweron_check = 0; + +/******************************************* +//开机采样到的电压和上次关机保存电压相差较大,怎么处理? +if (bat->bat_capacity > old_capacity) +{ +if ((bat->bat_capacity - old_capacity) > 20) +{ + +} +} +else if (bat->bat_capacity < old_capacity) +{ +if ((old_capacity > bat->bat_capacity) > 20) +{ + +} +} +*********************************************/ + if (bat->bat_capacity == 0) bat->bat_capacity = 1; + + +#if 0 + if ((bat->bat_voltage <= batt_table[0].dis_charge_vol+ 50)&&(bat->bat_status != POWER_SUPPLY_STATUS_CHARGING)){ + kernel_power_off(); + } +#endif +} + +static void rk30_adc_battery_callback(struct adc_client *client, void *param, int result) +{ +#if 0 + struct rk30_adc_battery_data *info = container_of(client, struct rk30_adc_battery_data, + client); + info->adc_val = result; +#endif + if (result < 0){ + pr_bat("adc_battery_callback resule < 0 , the value "); + return; + } + else{ + gBatteryData->adc_val = result; + pr_bat("result = %d, gBatteryData->adc_val = %d\n", result, gBatteryData->adc_val ); + } + return; +} + +#if 1 +static void rk30_adc_battery_lowerpower_delaywork(struct work_struct *work) +{ + int irq; + if( gBatteryData->pdata->batt_low_pin != INVALID_GPIO){ + irq = gpio_to_irq(gBatteryData->pdata->batt_low_pin); + disable_irq(irq); + } + + printk("lowerpower\n"); + rk28_send_wakeup_key(); // wake up the system + return; +} + + +static irqreturn_t rk30_adc_battery_low_wakeup(int irq,void *dev_id) +{ + queue_work(gBatteryData->wq, &gBatteryData->lowerpower_work); + return IRQ_HANDLED; +} + +#endif + +static int rk30_adc_battery_probe(struct platform_device *pdev) +{ + int ret; + int irq; + int irq_flag; + struct adc_client *client; + struct rk30_adc_battery_data *data; + struct rk30_adc_battery_platform_data *pdata = pdev->dev.platform_data; + gSecondsCnt = get_seconds(); + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) { + ret = -ENOMEM; + goto err_data_alloc_failed; + } + gBatteryData = data; + + platform_set_drvdata(pdev, data); + + data->pdata = pdata; + data->status_lock = 0; + ret = rk30_adc_battery_io_init(pdata); + if (ret) { + goto err_io_init; + } + + memset(data->adc_samples, 0, sizeof(int)*(NUM_VOLTAGE_SAMPLE + 2)); + + //register adc for battery sample + client = adc_register(0, rk30_adc_battery_callback, NULL); //pdata->adc_channel = ani0 + if(!client) + goto err_adc_register_failed; + + //variable init + data->client = client; + data->adc_val = adc_sync_read(client); + + ret = power_supply_register(&pdev->dev, &rk30_battery_supply); + if (ret){ + printk(KERN_INFO "fail to battery power_supply_register\n"); + goto err_battery_failed; + } +#ifdef BATTERY_APK + ret = device_create_file(&pdev->dev,&dev_attr_batparam); + if(ret) + { + printk(KERN_ERR "failed to create bat param file\n"); + goto err_battery_failed; + } + +#endif +#if defined (CONFIG_BATTERY_RK30_USB_CHARGE) + ret = power_supply_register(&pdev->dev, &rk30_usb_supply); + if (ret){ + printk(KERN_INFO "fail to usb power_supply_register\n"); + goto err_usb_failed; + } +#endif + wake_lock_init(&batt_wake_lock, WAKE_LOCK_SUSPEND, "batt_lock"); + + data->wq = create_singlethread_workqueue("adc_battd"); + INIT_DELAYED_WORK(&data->delay_work, rk30_adc_battery_timer_work); + //Power on Battery detect + rk30_adc_battery_check(data); + queue_delayed_work(data->wq, &data->delay_work, msecs_to_jiffies(TIMER_MS_COUNTS)); + +#if defined (CONFIG_BATTERY_RK30_AC_CHARGE) + ret = power_supply_register(&pdev->dev, &rk30_ac_supply); + if (ret) { + printk(KERN_INFO "fail to ac power_supply_register\n"); + goto err_ac_failed; + } + //init dc dectet irq & delay work + if (pdata->dc_det_pin != INVALID_GPIO){ + INIT_WORK(&data->dcwakeup_work, rk30_adc_battery_dcdet_delaywork); + + irq = gpio_to_irq(pdata->dc_det_pin); + irq_flag = gpio_get_value (pdata->dc_det_pin) ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING; + ret = request_irq(irq, rk30_adc_battery_dc_wakeup, irq_flag, "ac_charge_irq", NULL); + if (ret) { + printk("failed to request dc det irq\n"); + goto err_dcirq_failed; + } + enable_irq_wake(irq); + + } +#endif + +#if 1 + // batt low irq lowerpower_work + if( pdata->batt_low_pin != INVALID_GPIO){ + INIT_WORK(&data->lowerpower_work, rk30_adc_battery_lowerpower_delaywork); + + irq = gpio_to_irq(pdata->batt_low_pin); + ret = request_irq(irq, rk30_adc_battery_low_wakeup, IRQF_TRIGGER_LOW, "batt_low_irq", NULL); + + if (ret) { + printk("failed to request batt_low_irq irq\n"); + goto err_lowpowerirq_failed; + } + disable_irq(irq); + + } +#endif + +#ifdef BATTERY_APK + ret = create_sysfs_interfaces(&pdev->dev); + if (ret < 0) + { + dev_err(&pdev->dev, + "device rk30_adc_batterry sysfs register failed\n"); + goto err_sysfs; + } + +#endif + printk(KERN_INFO "rk30_adc_battery: driver initialized\n"); + + return 0; +err_sysfs: +#if defined (CONFIG_BATTERY_RK30_USB_CHARGE) +err_usb_failed: + power_supply_unregister(&rk30_usb_supply); +#endif + +err_ac_failed: +#if defined (CONFIG_BATTERY_RK30_AC_CHARGE) + power_supply_unregister(&rk30_ac_supply); +#endif + +err_battery_failed: + power_supply_unregister(&rk30_battery_supply); + +err_dcirq_failed: + free_irq(gpio_to_irq(pdata->dc_det_pin), data); +#if 1 + err_lowpowerirq_failed: + free_irq(gpio_to_irq(pdata->batt_low_pin), data); +#endif +err_adc_register_failed: +err_io_init: +err_data_alloc_failed: + kfree(data); + + printk("rk30_adc_battery: error!\n"); + + return ret; +} + +static int rk30_adc_battery_remove(struct platform_device *pdev) +{ + struct rk30_adc_battery_data *data = platform_get_drvdata(pdev); + struct rk30_adc_battery_platform_data *pdata = pdev->dev.platform_data; + + cancel_delayed_work(&gBatteryData->delay_work); +#if defined(CONFIG_BATTERY_RK30_USB_CHARGE) + power_supply_unregister(&rk30_usb_supply); +#endif +#if defined(CONFIG_BATTERY_RK30_AC_CHARGE) + power_supply_unregister(&rk30_ac_supply); +#endif + power_supply_unregister(&rk30_battery_supply); + + free_irq(gpio_to_irq(pdata->dc_det_pin), data); + + kfree(data); + + return 0; +} + +static struct platform_driver rk30_adc_battery_driver = { + .probe = rk30_adc_battery_probe, + .remove = rk30_adc_battery_remove, + .suspend = rk30_adc_battery_suspend, + .resume = rk30_adc_battery_resume, + .driver = { + .name = "rk30-battery", + .owner = THIS_MODULE, + } +}; + +static int __init rk30_adc_battery_init(void) +{ + return platform_driver_register(&rk30_adc_battery_driver); +} + +static void __exit rk30_adc_battery_exit(void) +{ + platform_driver_unregister(&rk30_adc_battery_driver); +} + +subsys_initcall(rk30_adc_battery_init);//subsys_initcall(rk30_adc_battery_init); +module_exit(rk30_adc_battery_exit); + +MODULE_DESCRIPTION("Battery detect driver for the rk30"); +MODULE_AUTHOR("luowei lw@rock-chips.com"); +MODULE_LICENSE("GPL"); From 1f3bc5a9192a479d4306f39271c406dc523ebed0 Mon Sep 17 00:00:00 2001 From: ywj Date: Thu, 16 Aug 2012 14:31:09 +0800 Subject: [PATCH 199/261] new add LCD driver for factorytool --- drivers/video/display/screen/Kconfig | 2 + drivers/video/display/screen/Makefile | 1 + drivers/video/display/screen/lcd_common.c | 79 +++++++++++++++++++++++ 3 files changed, 82 insertions(+) create mode 100644 drivers/video/display/screen/lcd_common.c diff --git a/drivers/video/display/screen/Kconfig b/drivers/video/display/screen/Kconfig index 850ba6518c8d..0b62f51a534b 100644 --- a/drivers/video/display/screen/Kconfig +++ b/drivers/video/display/screen/Kconfig @@ -90,6 +90,8 @@ config LCD_HDMI_800x480 if support RK610, this setting can support dual screen output config LCD_HV070WSA100 bool "HV070WSA-100 1024X600" +config LCD_COMMON + bool "LCD COMMON" endchoice diff --git a/drivers/video/display/screen/Makefile b/drivers/video/display/screen/Makefile index 93aff20cc013..08f3f71b6d8b 100644 --- a/drivers/video/display/screen/Makefile +++ b/drivers/video/display/screen/Makefile @@ -41,3 +41,4 @@ obj-$(CONFIG_LCD_B101EW05) += lcd_b101ew05.o obj-$(CONFIG_LCD_HJ050NA_06A) += lcd_hj050na_06a.o obj-$(CONFIG_LCD_HSD100PXN_FOR_TDW851) += lcd_hsd100pxn_for_tdw851.o obj-$(CONFIG_LCD_HV070WSA100) += lcd_hv070wsa.o +obj-$(CONFIG_LCD_COMMON) += lcd_common.o diff --git a/drivers/video/display/screen/lcd_common.c b/drivers/video/display/screen/lcd_common.c new file mode 100644 index 000000000000..4d18e7b442aa --- /dev/null +++ b/drivers/video/display/screen/lcd_common.c @@ -0,0 +1,79 @@ +#include +#include +#include "../../rk29_fb.h" +#include +#include +#include +#include "screen.h" + +/* Base */ +#define OUT_TYPE SCREEN_RGB + +#define OUT_FACE OUT_D888_P666 + + +#define OUT_CLK 71000000 +#define LCDC_ACLK 300000000 //29 lcdc axi DMA 频率 + +/* Timing */ +#define H_PW 10 +#define H_BP 100 +#define H_VD 1280 +#define H_FP 18 + +#define V_PW 2 +#define V_BP 8 +#define V_VD 800 +#define V_FP 6 + +#define LCD_WIDTH 216 +#define LCD_HEIGHT 135 +/* Other */ +#define DCLK_POL 0 +#define SWAP_RB 0 + + +u32 lcdpamara[]={0x4B434F52,0x64636C5F,0x61746164,SCREEN_RGB,OUT_D888_P666,71000000,300000000,10,100,1280,18,2,8,800,6,216,135,0,0}; + +void set_lcd_info(struct rk29fb_screen *screen, struct rk29lcd_info *lcd_info ) +{ + /* screen type & face */ + screen->type = lcdpamara[3]; + screen->face = lcdpamara[4]; + + /* Screen size */ + screen->x_res = lcdpamara[9]; + screen->y_res = lcdpamara[13]; + + screen->width = lcdpamara[15]; + screen->height = lcdpamara[16]; + + /* Timing */ + screen->lcdc_aclk = lcdpamara[6]; + screen->pixclock = lcdpamara[5]; + screen->left_margin = lcdpamara[8]; + screen->right_margin = lcdpamara[10]; + screen->hsync_len = lcdpamara[7]; + screen->upper_margin = lcdpamara[12]; + screen->lower_margin = lcdpamara[14]; + screen->vsync_len = lcdpamara[11]; + + /* Pin polarity */ + screen->pin_hsync = 0; + screen->pin_vsync = 0; + screen->pin_den = 0; + screen->pin_dclk = lcdpamara[17]; + + /* Swap rule */ + screen->swap_rb = lcdpamara[18]; + screen->swap_rg = 0; + screen->swap_gb = 0; + screen->swap_delta = 0; + screen->swap_dumy = 0; + + /* Operation function*/ + screen->init = NULL; + screen->standby = NULL; + +} + From 170a300423a13c3c9a082b10756ef8c17110858c Mon Sep 17 00:00:00 2001 From: ywj Date: Thu, 16 Aug 2012 14:33:38 +0800 Subject: [PATCH 200/261] new add bmp logo for factorytool --- drivers/video/logo/Kconfig | 4 + drivers/video/logo/Makefile | 14 +- drivers/video/logo/logo.c | 20 +- drivers/video/rockchip/rk_fb.c | 41 ++- include/linux/linux_logo.h | 2 + scripts/Makefile | 1 + scripts/bmptologo.c | 494 +++++++++++++++++++++++++++++++++ 7 files changed, 566 insertions(+), 10 deletions(-) create mode 100644 scripts/bmptologo.c diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig index 3abc2bca9f8f..a783e87086c2 100755 --- a/drivers/video/logo/Kconfig +++ b/drivers/video/logo/Kconfig @@ -27,6 +27,10 @@ config LOGO_LINUX_CLUT224 bool "Standard 224-color Linux logo" default y +config LOGO_LINUX_BMP + bool "bmp logo" + default y + config LOGO_BLACKFIN_VGA16 bool "16-colour Blackfin Processor Linux logo" depends on BLACKFIN diff --git a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile index 3f68c8bc72b2..86849cd3262e 100755 --- a/drivers/video/logo/Makefile +++ b/drivers/video/logo/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_LOGO_SUPERH_VGA16) += logo_superh_vga16.o obj-$(CONFIG_LOGO_SUPERH_CLUT224) += logo_superh_clut224.o obj-$(CONFIG_LOGO_M32R_CLUT224) += logo_m32r_clut224.o obj-$(CONFIG_LOGO_G3_CLUT224) += logo_g3_clut224.o +obj-$(CONFIG_LOGO_LINUX_BMP) += logo_bmp.o obj-$(CONFIG_LOGO_CHARGER_CLUT224) += logo_charger00_clut224.o logo_charger01_clut224.o logo_charger02_clut224.o logo_charger03_clut224.o logo_charger04_clut224.o logo_charger05_clut224.o logo_charger06_clut224.o logo_charger07_clut224.o logo_charger08_clut224.o @@ -41,6 +42,9 @@ extra-y += $(call logo-cfiles,_clut224,ppm) # Gray 256 extra-y += $(call logo-cfiles,_gray256,pgm) +extra-y += $(call logo-cfiles,_bmp,bmp) + +bmptologo := scripts/bmptologo pnmtologo := scripts/pnmtologo # Create commands like "pnmtologo -t mono -n logo_mac_mono -o ..." @@ -49,6 +53,11 @@ quiet_cmd_logo = LOGO $@ -t $(patsubst $*_%,%,$(notdir $(basename $<))) \ -n $(notdir $(basename $<)) -o $@ $< +quiet_cmd_bmplogo = LOGO $@ + cmd_bmplogo = $(bmptologo) \ + -t $(patsubst $*_%,%,$(notdir $(basename $<))) \ + -n $(notdir $(basename $<)) -o $@ $< + $(obj)/%_mono.c: $(src)/%_mono.pbm $(pnmtologo) FORCE $(call if_changed,logo) @@ -61,5 +70,8 @@ $(obj)/%_clut224.c: $(src)/%_clut224.ppm $(pnmtologo) FORCE $(obj)/%_gray256.c: $(src)/%_gray256.pgm $(pnmtologo) FORCE $(call if_changed,logo) +$(obj)/%_bmp.c: $(src)/%_bmp.bmp $(bmptologo) FORCE + $(call if_changed,bmplogo) + # Files generated that shall be removed upon make clean -clean-files := *.o *_mono.c *_vga16.c *_clut224.c *_gray256.c +clean-files := *.o *_mono.c *_vga16.c *_clut224.c *_gray256.c *_bmp.c diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c index 32e998ff609b..284c96d0d23e 100644 --- a/drivers/video/logo/logo.c +++ b/drivers/video/logo/logo.c @@ -120,12 +120,20 @@ const struct linux_logo * __init_refok fb_find_logo(int depth) #ifdef CONFIG_LOGO_CRUZ_CLUT224 logo = &logo_cruz_clut224; #endif - logo->width = ((logo->data[0] << 8) + logo->data[1]); - logo->height = ((logo->data[2] << 8) + logo->data[3]); - logo->clutsize = logo->clut[0]; - logo->data += 4; - logo->clut += 1; - + if (depth >= 24) + { + #ifdef CONFIG_LOGO_LINUX_BMP + logo = &logo_bmp; + #endif + } + else + { + logo->width = ((logo->data[0] << 8) + logo->data[1]); + logo->height = ((logo->data[2] << 8) + logo->data[3]); + logo->clutsize = logo->clut[0]; + logo->data += 4; + logo->clut += 1; + } } m_logo = logo; return m_logo; diff --git a/drivers/video/rockchip/rk_fb.c b/drivers/video/rockchip/rk_fb.c index d526cdba2cd9..9e70bca3f1c1 100644 --- a/drivers/video/rockchip/rk_fb.c +++ b/drivers/video/rockchip/rk_fb.c @@ -31,6 +31,7 @@ #include #include #include "hdmi/rk_hdmi.h" +#include @@ -377,6 +378,8 @@ static int rk_fb_set_par(struct fb_info *info) u32 yvir = var->yres_virtual; u8 data_format = var->nonstd&0xff; var->pixclock = dev_drv->pixclock; + + printk("-----data_format=%d\n",data_format); #if defined(CONFIG_HDMI_RK30) #if defined(CONFIG_DUAL_DISP_IN_KERNEL) if(hdmi_get_hotplug() == HDMI_HPD_ACTIVED) @@ -564,7 +567,11 @@ static struct fb_var_screeninfo def_var = { .green = {5,6,0}, .blue = {0,5,0}, .transp = {0,0,0}, + #ifdef CONFIG_LOGO_LINUX_BMP + .nonstd = HAL_PIXEL_FORMAT_RGBA_8888, + #else .nonstd = HAL_PIXEL_FORMAT_RGB_565, //(ypos<<20+xpos<<8+format) format + #endif .grayscale = 0, //(ysize<<20+xsize<<8) .activate = FB_ACTIVATE_NOW, .accel_flags = 0, @@ -891,7 +898,21 @@ static int init_lcdc_device_driver(struct rk_lcdc_device_driver *dev_drv, return 0; } +static struct linux_logo *logo = NULL; +char fb_prepare_bmp_logo(struct fb_info *info, int rotate) +{ + logo = fb_find_logo(24); + if (logo == NULL) + printk("%s....%s..error\n",__FILE__,__FUNCTION__); + return 1; +} +void fb_show_bmp_logo(struct fb_info *info, int rotate) +{ + char *framebase = info->screen_base; + memcpy(framebase,logo->data,(logo->width)*(logo->height)*4); + +} int rk_fb_register(struct rk_lcdc_device_driver *dev_drv, struct rk_lcdc_device_driver *def_drv,int id) { @@ -961,7 +982,12 @@ int rk_fb_register(struct rk_lcdc_device_driver *dev_drv, fbi->var.xres = fb_inf->lcdc_dev_drv[lcdc_id]->screen->x_res; fbi->var.yres = fb_inf->lcdc_dev_drv[lcdc_id]->screen->y_res; fbi->var.grayscale |= (fbi->var.xres<<8) + (fbi->var.yres<<20); - fbi->var.bits_per_pixel = 16; + //fbi->var.bits_per_pixel = 16; + #ifdef CONFIG_LOGO_LINUX_BMP + fbi->var.bits_per_pixel = 32; + #else + fbi->var.bits_per_pixel = 16; + #endif fbi->var.xres_virtual = fb_inf->lcdc_dev_drv[lcdc_id]->screen->x_res; fbi->var.yres_virtual = fb_inf->lcdc_dev_drv[lcdc_id]->screen->y_res; fbi->var.width = fb_inf->lcdc_dev_drv[lcdc_id]->screen->width; @@ -994,12 +1020,21 @@ int rk_fb_register(struct rk_lcdc_device_driver *dev_drv, { fb_inf->fb[fb_inf->num_fb-2]->fbops->fb_open(fb_inf->fb[fb_inf->num_fb-2],1); fb_inf->fb[fb_inf->num_fb-2]->fbops->fb_set_par(fb_inf->fb[fb_inf->num_fb-2]); - if(fb_prepare_logo(fb_inf->fb[fb_inf->num_fb-2], FB_ROTATE_UR)) { + #ifdef CONFIG_LOGO_LINUX_BMP + if(fb_prepare_bmp_logo(fb_inf->fb[fb_inf->num_fb-2], FB_ROTATE_UR)) { + /* Start display and show logo on boot */ + fb_set_cmap(&fb_inf->fb[fb_inf->num_fb-2]->cmap, fb_inf->fb[fb_inf->num_fb-2]); + fb_show_bmp_logo(fb_inf->fb[fb_inf->num_fb-2], FB_ROTATE_UR); + fb_inf->fb[fb_inf->num_fb-2]->fbops->fb_pan_display(&(fb_inf->fb[fb_inf->num_fb-2]->var), fb_inf->fb[fb_inf->num_fb-2]); + } + #else + if(fb_prepare_logo(fb_inf->fb[fb_inf->num_fb-2], FB_ROTATE_UR)) { /* Start display and show logo on boot */ fb_set_cmap(&fb_inf->fb[fb_inf->num_fb-2]->cmap, fb_inf->fb[fb_inf->num_fb-2]); fb_show_logo(fb_inf->fb[fb_inf->num_fb-2], FB_ROTATE_UR); - fb_inf->fb[fb_inf->num_fb-2]->fbops->fb_pan_display(&(fb_inf->fb[fb_inf->num_fb-2]->var), fb_inf->fb[fb_inf->num_fb-2]); + fb_inf->fb[fb_inf->num_fb-2]->fbops->fb_pan_display(&(fb_inf->fb[fb_inf->num_fb-2]->var), fb_inf->fb[fb_inf->num_fb-2]); } + #endif } #endif return 0; diff --git a/include/linux/linux_logo.h b/include/linux/linux_logo.h index 0bc9cca1bbe9..1ac3f1ebcf28 100644 --- a/include/linux/linux_logo.h +++ b/include/linux/linux_logo.h @@ -21,6 +21,7 @@ #define LINUX_LOGO_VGA16 2 /* 16 colors VGA text palette */ #define LINUX_LOGO_CLUT224 3 /* 224 colors */ #define LINUX_LOGO_GRAY256 4 /* 256 levels grayscale */ +#define LINUX_LOGO_bmp 5 /* truecolours*/ struct linux_logo { @@ -48,6 +49,7 @@ extern const struct linux_logo logo_superh_clut224; extern const struct linux_logo logo_m32r_clut224; extern const struct linux_logo logo_spe_clut224; extern const struct linux_logo logo_g3_clut224; +extern const struct linux_logo logo_bmp; extern const struct linux_logo *fb_find_logo(int depth); diff --git a/scripts/Makefile b/scripts/Makefile index df7678febf27..905d59e06bc8 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -10,6 +10,7 @@ hostprogs-$(CONFIG_KALLSYMS) += kallsyms hostprogs-$(CONFIG_LOGO) += pnmtologo +hostprogs-y += bmptologo hostprogs-$(CONFIG_VT) += conmakehash hostprogs-$(CONFIG_IKCONFIG) += bin2c hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount diff --git a/scripts/bmptologo.c b/scripts/bmptologo.c new file mode 100644 index 000000000000..fdac7cfc8498 --- /dev/null +++ b/scripts/bmptologo.c @@ -0,0 +1,494 @@ + +/* + * Convert a logo in ASCII PNM format to C source suitable for inclusion in + * the Linux kernel + * + * (C) Copyright 2001-2003 by Geert Uytterhoeven + * + * -------------------------------------------------------------------------- + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of the Linux + * distribution for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static const char *programname; +static const char *filename; +static const char *logoname = "linux_logo"; +static const char *outputname; +static FILE *out; + +//#define debug 0 +#define LINUX_LOGO_MONO 1 /* monochrome black/white */ +#define LINUX_LOGO_VGA16 2 /* 16 colors VGA text palette */ +#define LINUX_LOGO_CLUT224 3 /* 224 colors */ +#define LINUX_LOGO_GRAY256 4 /* 256 levels grayscale */ +#define LINUX_LOGO_bmp 5 /* truecolours*/ + +static const char *logo_types[LINUX_LOGO_bmp+1] = { + [LINUX_LOGO_MONO] = "LINUX_LOGO_MONO", + [LINUX_LOGO_VGA16] = "LINUX_LOGO_VGA16", + [LINUX_LOGO_CLUT224] = "LINUX_LOGO_CLUT224", + [LINUX_LOGO_GRAY256] = "LINUX_LOGO_GRAY256", + [LINUX_LOGO_bmp] = "LINUX_LOGO_bmp" +}; + +#define MAX_LINUX_LOGO_COLORS 224 + +struct color { + char blue; + char green; + char red; +}; + +static const struct color clut_vga16[16] = { + { 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0xaa }, + { 0x00, 0xaa, 0x00 }, + { 0x00, 0xaa, 0xaa }, + { 0xaa, 0x00, 0x00 }, + { 0xaa, 0x00, 0xaa }, + { 0xaa, 0x55, 0x00 }, + { 0xaa, 0xaa, 0xaa }, + { 0x55, 0x55, 0x55 }, + { 0x55, 0x55, 0xff }, + { 0x55, 0xff, 0x55 }, + { 0x55, 0xff, 0xff }, + { 0xff, 0x55, 0x55 }, + { 0xff, 0x55, 0xff }, + { 0xff, 0xff, 0x55 }, + { 0xff, 0xff, 0xff }, +}; + +unsigned char data_name[] = { + 0x6C, 0x6F, 0x67, + 0x6F, 0x5F, 0x52, + 0x4B, 0x6C, 0x6F, + 0x67, 0x6F, 0x5F, + 0x64, 0x61, 0x74, + 0x61 +}; + +unsigned char clut_name[] = { + 0x62, 0x6D, 0x70, + 0x6C, 0x6F, 0x67, + 0x6F, 0x5F, 0x52, + 0x4B, 0x6C, 0x6F, + 0x67, 0x6F, 0x5F, + 0x63, 0x6C, 0x75, + 0x74, 0x00 +}; + +static int logo_type = LINUX_LOGO_CLUT224; +static unsigned long logo_width; +static unsigned long logo_height; +static unsigned long data_long; +static unsigned long data_start; +static unsigned char *logo_data; +static struct color logo_clut[MAX_LINUX_LOGO_COLORS]; +static unsigned int logo_clutsize; + +static void die(const char *fmt, ...) + __attribute__ ((noreturn)) __attribute ((format (printf, 1, 2))); +static void usage(void) __attribute ((noreturn)); + +static unsigned int get_number(FILE *fp) +{ + int c, val; + + /* Skip leading whitespace */ + do { + c = fgetc(fp); + if (c == EOF) + die("%s: end of file\n", filename); + if (c == '#') { + /* Ignore comments 'till end of line */ + do { + c = fgetc(fp); + if (c == EOF) + die("%s: end of file\n", filename); + } while (c != '\n'); + } + } while (isspace(c)); + + /* Parse decimal number */ + val = 0; + while (isdigit(c)) { + val = 10*val+c-'0'; + c = fgetc(fp); + if (c == EOF) + die("%s: end of file\n", filename); + } + return val; +} + +static unsigned int get_number255(FILE *fp, unsigned int maxval) +{ + unsigned int val = get_number(fp); + return (255*val+maxval/2)/maxval; +} + +static void read_image(void) +{ + FILE *fp; + unsigned long i; + struct stat s; + char j = 0; + int magic; + unsigned int maxval; + char read_buf[0x28]; + long ret = 0; + unsigned char *data; + + /* open image file */ + fp = open(filename, O_RDONLY); + if (!fp) + die("Cannot open file isll.. %s: %s\n", filename, strerror(errno)); + + if (fstat(fp, &s) < 0) { + die("Cannot stat file isll.. %s: %s\n", filename, strerror(errno)); + } +#if 0 + ret = fread(read_buf,1,0x26,fp); + if (ret != 0x26) + die("read file %s: error read_buf=%ld\n", filename,ret); + + logo_height = (read_buf[0x19]<<24) + (read_buf[0x18]<<16) +(read_buf[0x17]<<8) +(read_buf[0x16]); + logo_width = (read_buf[0x15]<<24) + (read_buf[0x14]<<16) +(read_buf[0x13]<<8) +(read_buf[0x12]); + data_start = (read_buf[0x0d]<<24) + (read_buf[0x0c]<<16) +(read_buf[0x0b]<<8) +(read_buf[0x0a]); + data_long = (read_buf[0x25]<<24) + (read_buf[0x24]<<16) +(read_buf[0x023]<<8) +(read_buf[0x22]); +#endif + /* allocate image data */ + //logo_data = (char *)malloc(logo_height * logo_width * 3); + //data_long = logo_height * logo_width * 3; +//#ifdef debug +#if 0 + die("%s..logo_height=%ld,logo_width=%ld,data_start=%ld,data_long=%ld,sizeof(struct color)=%d, \ + read_buf[0x17]=%d read_buf[0x13]=%d\n\n",filename,logo_height,logo_width,data_start, \ + data_long,sizeof(struct color),read_buf[0x17],read_buf[0x13]); + if ((logo_width*logo_height*3) != data_long) + die("something is wront in scripts/bmptologo.c\n"); + +#endif +#if 0 + fseek(fp,data_start,SEEK_SET); + ret = fread(logo_data,1,data_long,fp); + if (ret != data_long) + die("read file %s: error logo_data=%ld\n", filename,ret); +#else + data = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fp, 0); + if (data == MAP_FAILED) + die("read file %s: error logo_data\n", filename); + logo_data = data + 54; + logo_height = (data[0x19]<<24) + (data[0x18]<<16) +(data[0x17]<<8) +(data[0x16]); + logo_width = (data[0x15]<<24) + (data[0x14]<<16) +(data[0x13]<<8) +(data[0x12]); + data_start = (data[0x0d]<<24) + (data[0x0c]<<16) +(data[0x0b]<<8) +(data[0x0a]); + data_long = (data[0x25]<<24) + (data[0x24]<<16) +(data[0x023]<<8) +(data[0x22]); + data_long = logo_height * logo_width * 3; +#if 0 + die("%s..logo_height=%ld,logo_width=%ld,data_start=%ld,data_long=%ld,sizeof(struct color)=%d, \ + read_buf[0x17]=%d read_buf[0x13]=%d\n\n",filename,logo_height,logo_width,data_start, \ + data_long,sizeof(struct color),read_buf[0x17],read_buf[0x13]); + if ((logo_width*logo_height*3) != data_long) + die("something is wront in scripts/bmptologo.c\n"); +#endif +#endif +#ifdef debug + die("logo_data is:%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x:over\n", \ + logo_data[0],logo_data[1],logo_data[2],logo_data[3],logo_data[4],logo_data[5],logo_data[6],logo_data[7],logo_data[8], \ +logo_data[9],logo_data[10],logo_data[11]); +#endif + /* close file */ + close(fp); +} + + +static inline int is_black(struct color c) +{ + return c.red == 0 && c.green == 0 && c.blue == 0; +} + +static inline int is_white(struct color c) +{ + return c.red == 255 && c.green == 255 && c.blue == 255; +} + +static inline int is_gray(struct color c) +{ + return c.red == c.green && c.red == c.blue; +} + +static inline int is_equal(struct color c1, struct color c2) +{ + return c1.red == c2.red && c1.green == c2.green && c1.blue == c2.blue; +} + +static int write_hex_cnt; + +static void write_hex(unsigned char byte) +{ + if (write_hex_cnt % 12) + fprintf(out, ", 0x%02x", byte); + else if (write_hex_cnt) + fprintf(out, ",\n\t0x%02x", byte); + else + fprintf(out, "\t0x%02x", byte); + write_hex_cnt++; +} + +static void write_header(void) +{ + /* open logo file */ + if (outputname) { + out = fopen(outputname, "w"); + if (!out) + die("Cannot create file %s: %s\n", outputname, strerror(errno)); + } else { + out = stdout; + } + + fputs("/*\n", out); + fputs(" * DO NOT EDIT THIS FILE!\n", out); + fputs(" *\n", out); + fprintf(out, " * It was automatically generated from %s\n", filename); + fputs(" *\n", out); + fprintf(out, " * Linux logo %s\n", logoname); + fputs(" */\n\n", out); + fputs("#include \n\n", out); + fprintf(out, "static unsigned char %s_data[] __initdata = {\n", + logoname); +} + +static void write_footer(void) +{ + fputs("\n};\n\n", out); + fprintf(out, "const struct linux_logo %s __initconst = {\n", logoname); + fprintf(out, "\t.type\t\t= %s,\n", logo_types[logo_type]); + + if (logo_type == LINUX_LOGO_bmp) { + fprintf(out, "\t.width\t\t= %ld,\n", logo_width); + fprintf(out, "\t.height\t\t= %ld,\n", logo_height); + //fprintf(out, "\t.data\t\t= %s_data,\n", logoname); + fprintf(out, "\t.data\t\t= &(%s_data[%ld]),\n", logoname,sizeof(data_name) + 8); + fprintf(out, "\t.clut\t\t= %s_clut\n", logoname); + } + + fputs("};\n\n", out); + + /* close logo file */ + if (outputname) + fclose(out); +} + + +static void write_logo_bmp(void) +{ + unsigned long i=0, j=0; + unsigned char *position ; + + /* validate image */ +/*statistics how many colours ,and if have over 224 + logo_clutsize = 0; + for (i = 0; i < logo_height; i++) + for (j = 0; j < logo_width; j++) { + for (k = 0; k < logo_clutsize; k++) + if (is_equal(logo_data[i][j], logo_clut[k])) + break; + if (k == logo_clutsize) { + if (logo_clutsize == MAX_LINUX_LOGO_COLORS) + die("Image has more than %d colors\n" + "Use ppmquant(1) to reduce the number of colors\n", + MAX_LINUX_LOGO_COLORS); + logo_clut[logo_clutsize++] = logo_data[i][j]; + } + } + +*/ + write_hex_cnt = 0; + + + /* write file header */ + write_header(); +#if 1 + write_hex((unsigned char)(logo_width >> 8)); + write_hex((unsigned char)logo_width); + write_hex((unsigned char)(logo_height >> 8)); + write_hex((unsigned char)logo_height); + + for (i = 0; i < sizeof(data_name); i++){ + write_hex(data_name[i]); + } + write_hex((unsigned char)(logo_width >> 8)); + write_hex((unsigned char)logo_width); + write_hex((unsigned char)(logo_height >> 8)); + write_hex((unsigned char)logo_height); +#endif + +#if 0 + /* write logo data */ + for (i = 0; i < logo_height; i++) + for (j = 0; j < logo_width; j++) { + for (k = 0; k < logo_clutsize; k++) + if (is_equal(logo_data[i][j], logo_clut[k])) + break; + write_hex(k+32); + } + fputs("\n};\n\n", out); + + + + /* write logo clut */ + fprintf(out, "static unsigned char %s_clut[] __initdata = {\n", + logoname); + + write_hex_cnt = 0; + + for (i = 0; i < sizeof(clut_name); i++){ + write_hex(clut_name[i]); + } + write_hex(logo_clutsize); + + for (i = 0; i < logo_clutsize; i++) { + write_hex(logo_clut[i].red); + write_hex(logo_clut[i].green); + write_hex(logo_clut[i].blue); + } + + for (i = logo_clutsize; i < (MAX_LINUX_LOGO_COLORS * 3); i++) + { + write_hex(32); + } + + /* write logo structure and file footer */ +#endif + +#if 1 + for (i=logo_height; i>0; i--) + { + for (j=0; j\n" + "\n" + "Valid options:\n" + " -h : display this usage information\n" + " -n : specify logo name (default: linux_logo)\n" + " -o : output to file instead of stdout\n" + " -t : specify logo type, one of\n" + " bmp : truecolour\n" + "\n", programname); +} + +int main(int argc, char *argv[]) +{ + int opt; + + programname = argv[0]; + + opterr = 0; + while (1) { + opt = getopt(argc, argv, "hn:o:t:"); + if (opt == -1) + break; + + switch (opt) { + case 'h': + usage(); + break; + + case 'n': + logoname = optarg; + break; + + case 'o': + outputname = optarg; + break; + + case 't': + if (!strcmp(optarg, "bmp")) + logo_type = LINUX_LOGO_bmp; + else + die("logo_type is wrong without bmp\n"); + break; + + default: + usage(); + break; + } + } + if (optind != argc-1) + usage(); + + filename = argv[optind]; + + read_image(); + switch (logo_type) { + case LINUX_LOGO_bmp: + write_logo_bmp(); + break; + default : + die("logo_type is wrong\n"); + } + exit(0); +} + From 475f235898a07dc0b8531d0277fbf2e947788177 Mon Sep 17 00:00:00 2001 From: zsq Date: Thu, 16 Aug 2012 14:43:06 +0800 Subject: [PATCH 201/261] fix no async bug --- drivers/video/rockchip/rga/rga_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/rockchip/rga/rga_drv.c b/drivers/video/rockchip/rga/rga_drv.c index 507751400069..734af2cbb802 100755 --- a/drivers/video/rockchip/rga/rga_drv.c +++ b/drivers/video/rockchip/rga/rga_drv.c @@ -356,7 +356,7 @@ static int rga_check_param(const struct rga_req *req) return -EINVAL; } - if (unlikely((req->dst.vir_w <= 0) || (req->dst.vir_w > 2048) || (req->dst.vir_h <= 0) || (req->dst.vir_h > 2048))) + if (unlikely((req->dst.vir_w <= 0) || (req->dst.vir_w > 4096) || (req->dst.vir_h <= 0) || (req->dst.vir_h > 2048))) { ERR("invalid destination resolution vir_w = %d, vir_h = %d\n", req->dst.vir_w, req->dst.vir_h); return -EINVAL; @@ -951,7 +951,7 @@ static long rga_ioctl(struct file *file, uint32_t cmd, unsigned long arg) } else { - ret = rga_blit_sync(session, req); + ret = rga_blit_async(session, req); } break; case RGA_FLUSH: From 28ef1d8c93c668c535145d9e94385335138247e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Thu, 16 Aug 2012 12:57:25 +0800 Subject: [PATCH 202/261] Input: rk29_keys: close debug print, open by 9ea1329 --- drivers/input/keyboard/rk29_keys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/keyboard/rk29_keys.c b/drivers/input/keyboard/rk29_keys.c index d184b51a1e0a..b5881d5b5e93 100755 --- a/drivers/input/keyboard/rk29_keys.c +++ b/drivers/input/keyboard/rk29_keys.c @@ -32,7 +32,7 @@ #define INVALID_ADVALUE 10 -#if 1 +#if 0 #define key_dbg(bdata, format, arg...) \ dev_printk(KERN_INFO , &bdata->input->dev , format , ## arg) #else From 9e0aa7b6bbef569e756d42a15946cd2b3c445c50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Thu, 16 Aug 2012 15:55:57 +0800 Subject: [PATCH 203/261] rga: refactor rga_drv.c for support rk30/rk31/rk2928 --- drivers/video/rockchip/rga/rga_drv.c | 41 ++++++---------------------- 1 file changed, 8 insertions(+), 33 deletions(-) diff --git a/drivers/video/rockchip/rga/rga_drv.c b/drivers/video/rockchip/rga/rga_drv.c index 734af2cbb802..6bf2399a59b8 100755 --- a/drivers/video/rockchip/rga/rga_drv.c +++ b/drivers/video/rockchip/rga/rga_drv.c @@ -60,21 +60,11 @@ #define RGA_MAJOR 255 -#if 1 -#if CONFIG_ARCH_RK2928 -#define RK30_RGA_PHYS 0x1010C000 -#define RK30_RGA_SIZE SZ_8K -#define RGA_RESET_TIMEOUT 1000 -#elif CONFIG_ARCH_RK30 -#define RK30_RGA_PHYS 0x10114000 -#define RK30_RGA_SIZE SZ_8K -#define RGA_RESET_TIMEOUT 1000 -#elif CONFIG_ARCH_RK31 -#define RK30_RGA_PHYS 0x10114000 -#define RK30_RGA_SIZE SZ_8K -#define RGA_RESET_TIMEOUT 1000 -#endif +#if defined(CONFIG_ARCH_RK2928) +#define RK30_RGA_PHYS RK2928_RGA_PHYS +#define RK30_RGA_SIZE RK2928_RGA_SIZE #endif +#define RGA_RESET_TIMEOUT 1000 /* Driver information */ #define DRIVER_DESC "RGA Device Driver" @@ -136,7 +126,6 @@ static inline u32 rga_read(u32 r) return __raw_readl(drvdata->rga_base + r); } -#if 1//defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) static void rga_soft_reset(void) { u32 i; @@ -157,7 +146,6 @@ static void rga_soft_reset(void) if(i == RGA_RESET_TIMEOUT) ERR("soft reset timeout.\n"); } -#endif static void rga_dump(void) { @@ -580,7 +568,7 @@ static void rga_try_set_reg(void) udelay(1); rga_copy_reg(reg, 0); - rga_reg_from_wait_to_run(reg); + rga_reg_from_wait_to_run(reg); dmac_flush_range(&rga_service.cmd_buff[0], &rga_service.cmd_buff[28]); outer_flush_range(virt_to_phys(&rga_service.cmd_buff[0]),virt_to_phys(&rga_service.cmd_buff[28])); @@ -606,6 +594,7 @@ static void rga_try_set_reg(void) printk("%.8x %.8x %.8x %.8x\n", p[0 + i*4], p[1+i*4], p[2 + i*4], p[3 + i*4]); } #endif + /* master mode */ rga_write((0x1<<2)|(0x1<<3), RGA_SYS_CTRL); @@ -1039,7 +1028,6 @@ static irqreturn_t rga_irq_thread(int irq, void *dev_id) rga_del_running_list(); rga_try_set_reg(); } - //printk("****** rga irq prc avil ******\n"); mutex_unlock(&rga_service.lock); return IRQ_HANDLED; @@ -1096,27 +1084,14 @@ static int __devinit rga_drv_probe(struct platform_device *pdev) data->aclk_rga = clk_get(NULL, "aclk_rga"); data->hclk_rga = clk_get(NULL, "hclk_rga"); - /* map the memory */ - #if defined(CONFIG_ARCH_RK2928) - if (!request_mem_region(RK2928_RGA_PHYS, RK2928_RGA_SIZE, "rga_io")) - #elif defined(CONFIG_ARCH_RK30) - if (!request_mem_region(RK30_RGA_PHYS, RK30_RGA_SIZE, "rga_io")) - #elif defined(CONFIG_ARCH_RK31) - if (!request_mem_region(RK30_RGA_PHYS, RK30_RGA_SIZE, "rga_io")) - #endif + if (!request_mem_region(RK30_RGA_PHYS, RK30_RGA_SIZE, "rga_io")) { pr_info("failed to reserve rga HW regs\n"); return -EBUSY; } - #if defined(CONFIG_ARCH_RK2928) - data->rga_base = (void*)ioremap_nocache(RK2928_RGA_PHYS, RK2928_RGA_SIZE); - #elif defined(CONFIG_ARCH_RK30) - data->rga_base = (void*)ioremap_nocache(RK30_RGA_PHYS, RK30_RGA_SIZE); - #elif defined(CONFIG_ARCH_RK31) - data->rga_base = (void*)ioremap_nocache(RK30_RGA_PHYS, RK30_RGA_SIZE); - #endif + data->rga_base = (void*)ioremap_nocache(RK30_RGA_PHYS, RK30_RGA_SIZE); if (data->rga_base == NULL) { ERR("rga ioremap failed\n"); From ab49eaa2e0f709eb6cbee3e9deee351f49901f01 Mon Sep 17 00:00:00 2001 From: Zheng Yang Date: Thu, 16 Aug 2012 17:45:11 +0800 Subject: [PATCH 204/261] rk30 hdmi: 1. Need not take tmds_clk pull up to 3.3V as a hdmi connection condition. 2. When parse unkown edid extensions, return false and set it as a hdmi sink. --- drivers/video/rockchip/hdmi/rk30_hdmi_edid.c | 4 ++-- drivers/video/rockchip/hdmi/rk30_hdmi_hw.c | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/video/rockchip/hdmi/rk30_hdmi_edid.c b/drivers/video/rockchip/hdmi/rk30_hdmi_edid.c index 9fec195fea3c..7a25775493e1 100755 --- a/drivers/video/rockchip/hdmi/rk30_hdmi_edid.c +++ b/drivers/video/rockchip/hdmi/rk30_hdmi_edid.c @@ -345,8 +345,8 @@ static int hdmi_edid_parse_extensions(unsigned char *buf, struct hdmi_edid *pedi hdmi_edid_debug("[EDID-EXTEND] It is a Digital Packet Video Link Extension.\n"); break; default: - hdmi_edid_debug("[EDID-EXTEND] Unkowned extension.\n"); - break; + hdmi_edid_error("[EDID-EXTEND] Unkowned extension.\n"); + return E_HDMI_EDID_UNKOWNDATA; } return E_HDMI_EDID_SUCCESS; diff --git a/drivers/video/rockchip/hdmi/rk30_hdmi_hw.c b/drivers/video/rockchip/hdmi/rk30_hdmi_hw.c index 8cb76ebfb14d..90bade5ae1bb 100755 --- a/drivers/video/rockchip/hdmi/rk30_hdmi_hw.c +++ b/drivers/video/rockchip/hdmi/rk30_hdmi_hw.c @@ -61,6 +61,8 @@ int rk30_hdmi_detect_hotplug(void) int value = HDMIRdReg(HPD_MENS_STA); hdmi_dbg(hdmi->dev, "[%s] value %02x\n", __FUNCTION__, value); + #if 0 + // When HPD and TMDS_CLK was high, HDMI is actived. value &= m_HOTPLUG_STATUS | m_MSEN_STATUS; if(value == (m_HOTPLUG_STATUS | m_MSEN_STATUS) ) return HDMI_HPD_ACTIVED; @@ -68,6 +70,15 @@ int rk30_hdmi_detect_hotplug(void) return HDMI_HPD_INSERT; else return HDMI_HPD_REMOVED; + #else + // When HPD was high, HDMI is actived. + if(value & m_HOTPLUG_STATUS) + return HDMI_HPD_ACTIVED; + else if(value & m_MSEN_STATUS) + return HDMI_HPD_INSERT; + else + return HDMI_HPD_REMOVED; + #endif } #define HDMI_EDID_DDC_CLK 90000 From 4cf1f94c060071ca1758814c2d4a2e2a74ef7d1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=8B=E7=A7=80=E6=9D=B0?= Date: Thu, 16 Aug 2012 17:58:48 +0800 Subject: [PATCH 205/261] phonepad: codec set slave when BT incall, and set pll. --- sound/soc/rk29/rk29_rt3261.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/rk29/rk29_rt3261.c b/sound/soc/rk29/rk29_rt3261.c index c4573578ba13..3fe929b354e7 100644 --- a/sound/soc/rk29/rk29_rt3261.c +++ b/sound/soc/rk29/rk29_rt3261.c @@ -126,7 +126,7 @@ static int rt3261_voice_hw_params(struct snd_pcm_substream *substream, DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBM_CFM ); + SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS ); switch(params_rate(params)) { case 8000: @@ -152,7 +152,7 @@ static int rt3261_voice_hw_params(struct snd_pcm_substream *substream, /*Set the system clk for codec*/ snd_soc_dai_set_pll(codec_dai, 0, RT3261_PLL1_S_MCLK, pll_out, 256 * 8000); - ret = snd_soc_dai_set_sysclk(codec_dai, 0, 256 * 8000, SND_SOC_CLOCK_IN); + ret = snd_soc_dai_set_sysclk(codec_dai, RT3261_SCLK_S_PLL1, 256 * 8000, SND_SOC_CLOCK_IN); if (ret < 0) { From 101aadaefedc91d1a793b21328ab2c8a77a9e129 Mon Sep 17 00:00:00 2001 From: CMY Date: Thu, 16 Aug 2012 19:20:03 +0800 Subject: [PATCH 206/261] 3G: Support for more 3g devices --- drivers/usb/serial/option.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 8e8430342230..ab31c05b731a 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1108,13 +1108,41 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(ZTE_VENDOR_ID, 0xFFFF) }, { USB_DEVICE(LEADCORE_VENDOR_ID, 0x5700) }, { USB_DEVICE(LEADCORE_VENDOR_ID, 0x6341) }, - { USB_DEVICE(0x230d, 0x000d) }, + { USB_DEVICE(0x230D, 0x000D) }, { USB_DEVICE(0x0E8D, 0x00A2) }, { USB_DEVICE(0x1E89, 0x1A20) }, { USB_DEVICE(0x12D1, 0x1C05) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0007, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0167, 0xff, 0xff, 0xff) }, + { USB_DEVICE(HUAWEI_VENDOR_ID, 0x14A8) }, { USB_DEVICE(0x20A6, 0x1105) }, + { USB_DEVICE(0x1EE8, 0x005F) }, // Onda-MSA14.4 + { USB_DEVICE(0x0421, 0x061E) }, // Nokia CS-11 + { USB_DEVICE(0x0BDB, 0x190A) }, + { USB_DEVICE(0x1d09, 0x1010) }, + { USB_DEVICE(0x19D2, 0x1181) }, + { USB_DEVICE(0x2020, 0x1005)},//S830 3G Dongle +// cmy end +//xxh + { USB_DEVICE_AND_INTERFACE_INFO(0x05c6, 0x1000, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x05c6, 0x6000, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x20A6, 0xF00E, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x20A6, 0x1105, 0xff, 0xff, 0xff) }, + { USB_DEVICE(0x21f5, 0x1101)}, + { USB_DEVICE(0x230d,0x0101)}, + { USB_DEVICE_AND_INTERFACE_INFO(0x230d, 0x1101, 0xff, 0xff, 0xff) }, + { USB_DEVICE(0x2077,0xa000)}, + { USB_DEVICE(0x1c9e,0x6061)}, + { USB_DEVICE(0x1c9e,0x9605)}, + { USB_DEVICE(0x19d2, 0x0170) }, + { USB_DEVICE(0x19d2, 0xffe8) }, + { USB_DEVICE(0x19D2,0x1177) },//K3770-Z + { USB_DEVICE(0x230D, 0x000c) }, + { USB_DEVICE(0x21F5, 0x2009) }, + { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353) }, + { USB_DEVICE(0x15eb,0x0001)}, +//xxh end + { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) }, { USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */ From b4996adcf8a14a76128940c3272f3e1bf8a50c5c Mon Sep 17 00:00:00 2001 From: xbw Date: Thu, 16 Aug 2012 20:56:48 +0800 Subject: [PATCH 207/261] sdmmc: modify the card is easy to run overtime due to data-busy. --- drivers/mmc/core/core.c | 10 +++++--- drivers/mmc/host/rk29_sdmmc.c | 47 ++++++++++++++++++++--------------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 87bf16383c2e..b9e3ae536102 100755 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -236,7 +236,7 @@ void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) //calculate the timeout value for SDMMC; added by xbw at 2011-09-27 if(mrq->data) { - unit = 3*(1<<20);// unit=3MB + unit = 2*(1<<20);// unit=2MB datasize = mrq->data->blksz*mrq->data->blocks; multi = datasize/unit; multi += (datasize%unit)?1:0; @@ -260,8 +260,12 @@ void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) { host->doneflag = 0; mrq->cmd->error = -EIO; - printk(KERN_WARNING "%s..%d.. !!!!! wait for CMD%d timeout [%s]\n",\ - __FUNCTION__, __LINE__, mrq->cmd->opcode, mmc_hostname(host)); + + if(0 == mrq->cmd->retries) + { + printk(KERN_WARNING "%s..%d.. !!!!! wait for CMD%d timeout [%s]\n",\ + __FUNCTION__, __LINE__, mrq->cmd->opcode, mmc_hostname(host)); + } } #else wait_for_completion(&complete); diff --git a/drivers/mmc/host/rk29_sdmmc.c b/drivers/mmc/host/rk29_sdmmc.c index 79c2740eada8..fc6e5b28d6b2 100755 --- a/drivers/mmc/host/rk29_sdmmc.c +++ b/drivers/mmc/host/rk29_sdmmc.c @@ -979,8 +979,8 @@ static void rk29_sdmmc_control_host_dma(struct rk29_sdmmc *host, bool enable) static void send_stop_cmd(struct rk29_sdmmc *host) { int ret; - int timeout = 250; - unsigned int value; + // int timeout = 250; + // unsigned int value; if(host->mrq->cmd->error) @@ -1001,7 +1001,8 @@ static void send_stop_cmd(struct rk29_sdmmc *host) __FUNCTION__, __LINE__, host->dma_name); } } - + +#if 0 //modifyed at 2012-08-16 while (--timeout > 0) { value = rk29_sdmmc_read(host->regs, SDMMC_STATUS); @@ -1033,7 +1034,8 @@ static void send_stop_cmd(struct rk29_sdmmc *host) __FUNCTION__, __LINE__, host->dma_name); } } - +#endif + host->errorstep = 0xe1; mod_timer(&host->request_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_SEND_START_TIMEOUT+2500)); @@ -1056,7 +1058,7 @@ static void send_stop_cmd(struct rk29_sdmmc *host) { rk29_sdmmc_start_error(host); - //host->state = STATE_IDLE; + host->state = STATE_IDLE; host->complete_done = 4; } host->errorstep = 0xe2; @@ -1096,7 +1098,9 @@ static int rk29_sdmmc_submit_data_dma(struct rk29_sdmmc *host, struct mmc_data * if (data->blksz & 3) { - printk(KERN_WARNING "%s..%d... data_len not aligned to 4bytes. [%s]\n", __FUNCTION__, __LINE__, host->dma_name); + printk(KERN_ERR "%s..%d...data_len not aligned to 4bytes. [%s]\n", \ + __FUNCTION__, __LINE__, host->dma_name); + return -EINVAL; } @@ -1942,12 +1946,12 @@ static void rk29_sdmmc_INT_CMD_DONE_timeout(unsigned long host_data) if(STATE_SENDING_CMD == host->state) { - if(0==host->cmd->retries) + if((0==host->cmd->retries)&&(12 != host->cmd->opcode)) { printk(KERN_WARNING "%d... cmd=%d, INT_CMD_DONE timeout, errorStep=0x%x, host->state=%x [%s]\n",\ __LINE__,host->cmd->opcode, host->errorstep,host->state,host->dma_name); } - + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, 0xFFFFFFFE); // clear INT,except for SDMMC_INT_CD rk29_sdmmc_dealwith_timeout(host); } @@ -1972,7 +1976,7 @@ static void rk29_sdmmc_INT_DTO_timeout(unsigned long host_data) printk(KERN_WARNING "%s..%d...cmd=%d DTO_timeout,cmdr=0x%x, errorStep=0x%x, Hoststate=%x [%s]\n", \ __FUNCTION__, __LINE__,host->cmd->opcode,host->cmdr ,host->errorstep,host->state,host->dma_name); } - + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, 0xFFFFFFFE); // clear INT,except for SDMMC_INT_CD rk29_sdmmc_dealwith_timeout(host); } rk29_sdmmc_enable_irq(host, true); @@ -2176,7 +2180,7 @@ static void rk29_sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) } else { - if(host->error_times++ % (RK29_ERROR_PRINTK_INTERVAL*3) ==0) + if(host->error_times++ % (RK29_ERROR_PRINTK_INTERVAL*10) ==0) { printk(KERN_INFO "%s: Refuse to run CMD%2d(arg=0x%8x) due to the removal of card. 3==[%s]==\n", \ __FUNCTION__, mrq->cmd->opcode, mrq->cmd->arg, host->dma_name); @@ -2266,7 +2270,6 @@ static void rk29_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct rk29_sdmmc *host = mmc_priv(mmc); rk29_sdmmc_enable_irq(host, false); - //spin_lock(&host->lock); if(test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags) || (RK29_CTRL_SDMMC_ID == host->pdev->id)) { @@ -2381,7 +2384,6 @@ static void rk29_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) rk29_sdmmc_change_clk_div(host, ios->clock); } out: - //spin_unlock(&host->lock); rk29_sdmmc_enable_irq(host, true); } @@ -2776,7 +2778,9 @@ static int rk29_sdmmc_command_complete(struct rk29_sdmmc *host, cmd->resp[0] = rk29_sdmmc_read(host->regs, SDMMC_RESP0); } } - + + #if 0 + //debug if(cmd->error) { del_timer_sync(&host->DTO_timer); @@ -2793,6 +2797,8 @@ static int rk29_sdmmc_command_complete(struct rk29_sdmmc *host, } } + #endif + del_timer_sync(&host->request_timer); @@ -2923,7 +2929,7 @@ static void rk29_sdmmc_tasklet_func(unsigned long priv) ** use DTO_timer for waiting for INT_UNBUSY. ** max 250ms in specification, but adapt 500 for the compatibility of all kinds of sick sdcard. */ - mod_timer(&host->DTO_timer, jiffies + msecs_to_jiffies(2000)); + mod_timer(&host->DTO_timer, jiffies + msecs_to_jiffies(5000)); } else { @@ -3037,12 +3043,15 @@ static void rk29_sdmmc_tasklet_func(unsigned long priv) { host->errorstep = 0xf2; - if(0) //(12==host->cmd->opcode) + #if 0 + //debug + if(12==host->cmd->opcode) { printk(KERN_ERR "%d... cmd=%d(arg=0x%x),blksz=%d,blocks=%d,errorStep=0x%x,\n host->state=%x, statusReg=0x%x [%s]\n",\ __LINE__,host->mrq->cmd->opcode, host->mrq->cmd->arg, host->mrq->cmd->data->blksz, host->mrq->cmd->data->blocks,\ host->errorstep,host->state,rk29_sdmmc_read(host->regs, SDMMC_STATUS),host->dma_name); } + #endif spin_unlock(&host->lock);//spin_unlock_irqrestore(&host->lock, iflags); rk29_sdmmc_enable_irq(host, true); @@ -3074,7 +3083,7 @@ static inline void rk29_sdmmc_cmd_interrupt(struct rk29_sdmmc *host, u32 status) host->errorstep = 0xfc; if((MMC_STOP_TRANSMISSION != host->cmd->opcode) && (host->cmdr & SDMMC_CMD_DAT_EXP)) { - unit = 3*1024*1024; + unit = 2*1024*1024; multi = rk29_sdmmc_read(host->regs, SDMMC_BYTCNT)/unit; multi += ((rk29_sdmmc_read(host->regs, SDMMC_BYTCNT)%unit) ? 1 :0 ); multi = (multi>0) ? multi : 1; @@ -3153,9 +3162,6 @@ static irqreturn_t rk29_sdmmc_interrupt(int irq, void *dev_id) } - xbwprintk(1,"\n*******test***********\n%s:INT_CD=0x%x,INT-En=%d,hostState=%d, cmd=%d,present Old=%d ==> New=%d [%s]\n",\ - __FUNCTION__, pending, host->mmc->re_initialized_flags, host->state, host->cmd->opcode,present_old, present, host->dma_name); - if (pending & SDMMC_INT_CMD_DONE) { xbwprintk(6, "%s..%d.. CMD%d INT_CMD_DONE INT=0x%x [%s]\n", \ @@ -3233,7 +3239,8 @@ static irqreturn_t rk29_sdmmc_interrupt(int irq, void *dev_id) printk(KERN_WARNING "%s: INT=0x%x Oh!My God,let me see!What happened?Why?Where? CMD%d(arg=0x%x, retries=%d). [%s]\n", \ __FUNCTION__, pending, host->cmd->opcode, host->cmd->arg, host->cmd->retries,host->dma_name); - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_FRUN); + //rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_FRUN); + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,0xFFFFFFFE); goto Exit_INT; } From e392c72196073042938ea2cf4d5ebd503e01f97a Mon Sep 17 00:00:00 2001 From: root Date: Fri, 17 Aug 2012 10:25:57 +0800 Subject: [PATCH 208/261] camera rk30 : fix conflict when merge 2928 --- arch/arm/mach-rk30/include/mach/rk30_camera.h | 9 ++ drivers/media/video/rk30_camera.c | 26 +++++- drivers/media/video/rk30_camera_oneframe.c | 85 +++++++++++++------ 3 files changed, 93 insertions(+), 27 deletions(-) diff --git a/arch/arm/mach-rk30/include/mach/rk30_camera.h b/arch/arm/mach-rk30/include/mach/rk30_camera.h index 5365fabe9aac..38e771f81e8c 100755 --- a/arch/arm/mach-rk30/include/mach/rk30_camera.h +++ b/arch/arm/mach-rk30/include/mach/rk30_camera.h @@ -21,8 +21,17 @@ #ifndef __ASM_ARCH_CAMERA_RK30_H_ #define __ASM_ARCH_CAMERA_RK29_H_ +#ifdef CONFIG_ARCH_RK30 #define RK29_CAM_DRV_NAME "rk-camera-rk30" +#define RK_SUPPORT_CIF0 1 +#define RK_SUPPORT_CIF1 1 +#endif +#ifdef CONFIG_ARCH_RK31 +#define RK29_CAM_DRV_NAME "rk-camera-rk31" +#define RK_SUPPORT_CIF0 1 +#define RK_SUPPORT_CIF1 0 +#endif #include #endif diff --git a/drivers/media/video/rk30_camera.c b/drivers/media/video/rk30_camera.c index a516643730d5..6d7c3766dca9 100755 --- a/drivers/media/video/rk30_camera.c +++ b/drivers/media/video/rk30_camera.c @@ -854,6 +854,7 @@ static int rk_sensor_iomux(int pin) static u64 rockchip_device_camera_dmamask = 0xffffffffUL; +#if RK_SUPPORT_CIF0 static struct resource rk_camera_resource_host_0[] = { [0] = { .start = RK30_CIF0_PHYS, @@ -866,6 +867,8 @@ static struct resource rk_camera_resource_host_0[] = { .flags = IORESOURCE_IRQ, } }; +#endif +#if RK_SUPPORT_CIF1 static struct resource rk_camera_resource_host_1[] = { [0] = { .start = RK30_CIF1_PHYS, @@ -878,7 +881,10 @@ static struct resource rk_camera_resource_host_1[] = { .flags = IORESOURCE_IRQ, } }; +#endif + /*platform_device : */ +#if RK_SUPPORT_CIF0 struct platform_device rk_device_camera_host_0 = { .name = RK29_CAM_DRV_NAME, .id = RK_CAM_PLATFORM_DEV_ID_0, /* This is used to put cameras on this interface */ @@ -890,6 +896,9 @@ static struct resource rk_camera_resource_host_1[] = { .platform_data = &rk_camera_platform_data, } }; +#endif + +#if RK_SUPPORT_CIF1 /*platform_device : */ struct platform_device rk_device_camera_host_1 = { .name = RK29_CAM_DRV_NAME, @@ -902,6 +911,7 @@ static struct resource rk_camera_resource_host_1[] = { .platform_data = &rk_camera_platform_data, } }; +#endif static void rk_init_camera_plateform_data(void) { @@ -923,8 +933,8 @@ static void rk_init_camera_plateform_data(void) static void rk30_camera_request_reserve_mem(void) { -#ifdef CONFIG_VIDEO_RK29_WORK_IPP - #ifdef CONFIG_VIDEO_RKCIF_WORK_SIMUL_OFF +#ifdef CONFIG_VIDEO_RK29_WORK_IPP + #if defined(CONFIG_VIDEO_RKCIF_WORK_SIMUL_OFF) || ((RK_SUPPORT_CIF0 && RK_SUPPORT_CIF1) == false) rk_camera_platform_data.meminfo.name = "camera_ipp_mem"; rk_camera_platform_data.meminfo.start = board_mem_reserve_add("camera_ipp_mem",PMEM_CAMIPP_NECESSARY); rk_camera_platform_data.meminfo.size= PMEM_CAMIPP_NECESSARY; @@ -958,15 +968,25 @@ static int rk_register_camera_devices(void) for (i=0; i #include #include @@ -38,9 +38,16 @@ #include #include #include + +#if defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) #include #include #include +#endif + +#if defined(CONFIG_ARCH_RK2928) +#include +#endif static int debug ; module_param(debug, int, S_IRUGO|S_IWUSR); @@ -140,6 +147,7 @@ module_param(debug, int, S_IRUGO|S_IWUSR); #define ENABLE_32BIT_BYPASS (0x01<<6) #define DISABLE_32BIT_BYPASS (0x00<<6) +#if (defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31)) //CRU,PIXCLOCK #define CRU_PCLK_REG30 0xbc #define ENANABLE_INVERT_PCLK_CIF0 ((0x1<<24)|(0x1<<8)) @@ -152,6 +160,7 @@ module_param(debug, int, S_IRUGO|S_IWUSR); #define MASK_RST_CIF1 (0x01 << 31) #define RQUEST_RST_CIF0 (0x01 << 14) #define RQUEST_RST_CIF1 (0x01 << 15) +#endif #define MIN(x,y) ((xy) ? x: y) @@ -162,9 +171,18 @@ module_param(debug, int, S_IRUGO|S_IWUSR); #define read_cif_reg(base,addr) __raw_readl(addr+(base)) #define mask_cif_reg(addr, msk, val) write_cif_reg(addr, (val)|((~(msk))&read_cif_reg(addr))) +#if (defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31)) #define write_cru_reg(addr, val) __raw_writel(val, addr+RK30_CRU_BASE) #define read_cru_reg(addr) __raw_readl(addr+RK30_CRU_BASE) #define mask_cru_reg(addr, msk, val) write_cru_reg(addr,(val)|((~(msk))&read_cru_reg(addr))) +#endif + +#if defined(CONFIG_ARCH_RK2928) +#define write_cru_reg(addr, val) +#define read_cru_reg(addr) 0 +#define mask_cru_reg(addr, msk, val) +#endif + //when work_with_ipp is not enabled,CONFIG_VIDEO_RK29_DIGITALZOOM_IPP_OFF is not defined.something wrong with it #ifdef CONFIG_VIDEO_RK29_WORK_IPP//CONFIG_VIDEO_RK29_DIGITALZOOM_IPP_OFF @@ -940,8 +958,9 @@ static int rk_camera_add_device(struct soc_camera_device *icd) goto ebusy; } - RKCAMERA_DG("RK Camera driver attached to %s\n",dev_name(icd->pdev)); - + dev_info(&icd->dev, "RK Camera driver attached to camera%d(%s)\n", + icd->devnum,dev_name(icd->pdev)); + pcdev->frame_inval = RK_CAM_FRAME_INVAL_INIT; pcdev->active = NULL; pcdev->icd = NULL; @@ -1005,7 +1024,8 @@ static void rk_camera_remove_device(struct soc_camera_device *icd) mutex_lock(&camera_lock); BUG_ON(icd != pcdev->icd); - RKCAMERA_DG("RK Camera driver detached from %s\n",dev_name(icd->pdev)); + dev_info(&icd->dev, "RK Camera driver detached from camera%d(%s)\n", + icd->devnum,dev_name(icd->pdev)); /* ddl@rock-chips.com: Application will call VIDIOC_STREAMOFF before close device, but stream may be turn on again before close device, if suspend and resume happened. */ @@ -1246,26 +1266,29 @@ static void rk_camera_setup_format(struct soc_camera_device *icd, __u32 host_pix cif_fmt_val = YUV_INPUT_ORDER_YUYV(cif_fmt_val); break; } +#if 1 + { +#ifdef CONFIG_ARCH_RK30 + mdelay(100); + if(IS_CIF0()){ + // pmu_set_idle_request(IDLE_REQ_VIO, true); + cru_set_soft_reset(SOFT_RST_CIF0, true); + udelay(5); + cru_set_soft_reset(SOFT_RST_CIF0, false); + // pmu_set_idle_request(IDLE_REQ_VIO, false); - { - mdelay(100); - if(IS_CIF0()){ - // pmu_set_idle_request(IDLE_REQ_VIO, true); - cru_set_soft_reset(SOFT_RST_CIF0, true); - udelay(5); - cru_set_soft_reset(SOFT_RST_CIF0, false); - // pmu_set_idle_request(IDLE_REQ_VIO, false); - - }else{ - // pmu_set_idle_request(IDLE_REQ_VIO, true); - cru_set_soft_reset(SOFT_RST_CIF1, true); - udelay(5); - cru_set_soft_reset(SOFT_RST_CIF1, false); - // pmu_set_idle_request(IDLE_REQ_VIO, false); + }else{ + // pmu_set_idle_request(IDLE_REQ_VIO, true); + cru_set_soft_reset(SOFT_RST_CIF1, true); + udelay(5); + cru_set_soft_reset(SOFT_RST_CIF1, false); + // pmu_set_idle_request(IDLE_REQ_VIO, false); + } +#endif } - } write_cif_reg(pcdev->base,CIF_CIF_CTRL,AXI_BURST_16|MODE_ONEFRAME|DISABLE_CAPTURE); /* ddl@rock-chips.com : vip ahb burst 16 */ write_cif_reg(pcdev->base,CIF_CIF_INTEN, 0x01|0x200); //capture complete interrupt enable +#endif write_cif_reg(pcdev->base,CIF_CIF_FOR,cif_fmt_val); /* ddl@rock-chips.com: VIP capture mode and capture format must be set before FS register set */ // read_cif_reg(pcdev->base,CIF_CIF_INTSTAT); /* clear vip interrupte single */ @@ -2173,7 +2196,9 @@ static int rk_camera_set_ctrl(struct soc_camera_device *icd, struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); const struct v4l2_queryctrl *qctrl; +#ifdef CONFIG_VIDEO_RK29_DIGITALZOOM_IPP_ON struct rk_camera_dev *pcdev = ici->priv; +#endif int ret = 0; qctrl = rk_camera_soc_camera_find_qctrl(ici->ops, sctrl->id); @@ -2234,6 +2259,7 @@ static struct soc_camera_host_ops rk_soc_camera_host_ops = }; static void rk_camera_cif_iomux(int cif_index) { +#ifdef CONFIG_ARCH_RK30 switch(cif_index){ case 0: rk30_mux_api_set(GPIO1B3_CIF0CLKOUT_NAME, GPIO1B_CIF0_CLKOUT); @@ -2260,6 +2286,8 @@ static void rk_camera_cif_iomux(int cif_index) default: printk("cif index is erro!!!\n"); } +#else +#endif } @@ -2271,9 +2299,18 @@ static int rk_camera_probe(struct platform_device *pdev) int irq,i; int err = 0; - RKCAMERA_TR("RK30 Camera driver version: v%d.%d.%d\n",(RK_CAM_VERSION_CODE&0xff0000)>>16, - (RK_CAM_VERSION_CODE&0xff00)>>8,RK_CAM_VERSION_CODE&0xff); + RKCAMERA_DG("%s(%d) Enter..\n",__FUNCTION__,__LINE__); + if ((pdev->id == RK_CAM_PLATFORM_DEV_ID_1) && (RK_SUPPORT_CIF1 == 0)) { + RKCAMERA_TR("%s(%d): This chip is not support CIF1!!\n",__FUNCTION__,__LINE__); + BUG(); + } + + if ((pdev->id == RK_CAM_PLATFORM_DEV_ID_0) && (RK_SUPPORT_CIF0 == 0)) { + RKCAMERA_TR("%s(%d): This chip is not support CIF0!!\n",__FUNCTION__,__LINE__); + BUG(); + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); if (!res || irq < 0) { @@ -2372,7 +2409,7 @@ static int rk_camera_probe(struct platform_device *pdev) } } -#ifdef CONFIG_VIDEO_RK29_WORK_IPP +//#ifdef CONFIG_VIDEO_RK29_WORK_IPP if(IS_CIF0()) { pcdev->camera_wq = create_workqueue("rk_cam_wkque_cif0"); } else { @@ -2380,7 +2417,7 @@ static int rk_camera_probe(struct platform_device *pdev) } if (pcdev->camera_wq == NULL) goto exit_free_irq; -#endif +//#endif pcdev->camera_reinit_work.pcdev = pcdev; INIT_WORK(&(pcdev->camera_reinit_work.work), rk_camera_reinit_work); From 6ef0af5a9b983cc81192d2b04ea650e0e7cb9a1c Mon Sep 17 00:00:00 2001 From: zyc Date: Fri, 17 Aug 2012 10:31:42 +0800 Subject: [PATCH 209/261] camera : fix conflict when merge to rk30 --- drivers/media/video/rk30_camera_oneframe.c | 331 +++++++-------------- 1 file changed, 106 insertions(+), 225 deletions(-) diff --git a/drivers/media/video/rk30_camera_oneframe.c b/drivers/media/video/rk30_camera_oneframe.c index 23139426138d..b77d345e94ce 100755 --- a/drivers/media/video/rk30_camera_oneframe.c +++ b/drivers/media/video/rk30_camera_oneframe.c @@ -57,7 +57,7 @@ module_param(debug, int, S_IRUGO|S_IWUSR); printk(KERN_WARNING"rk_camera: " fmt , ## arg); } while (0) #define RKCAMERA_TR(format, ...) printk(KERN_ERR format, ## __VA_ARGS__) -#define RKCAMERA_DG(format, ...) dprintk(0, format, ## __VA_ARGS__) +#define RKCAMERA_DG(format, ...) dprintk(1, format, ## __VA_ARGS__) // CIF Reg Offset #define CIF_CIF_CTRL 0x00 @@ -227,9 +227,11 @@ module_param(debug, int, S_IRUGO|S_IWUSR); *v0.x.b: specify the version is NOT sure stable. *v0.x.c: 1. add cif reset when resolution changed to avoid of collecting data erro 2. irq process is splitted to two step. -*v0.x.e: fix bugs of early suspend when display_pd is closed. +*v0.x.e: fix bugs of early suspend when display_pd is closed. +*v0.x.f: fix calculate ipp memory size is enough or not in try_fmt function; +*v0.x.11: fix struct rk_camera_work may be reentrant */ -#define RK_CAM_VERSION_CODE KERNEL_VERSION(0, 2, 0xe) +#define RK_CAM_VERSION_CODE KERNEL_VERSION(0, 2, 0x11) /* limit to rk29 hardware capabilities */ #define RK_CAM_BUS_PARAM (SOCAM_MASTER |\ @@ -251,7 +253,6 @@ module_param(debug, int, S_IRUGO|S_IWUSR); #define RK_CAM_FRAME_INVAL_INIT 3 #define RK_CAM_FRAME_INVAL_DC 3 /* ddl@rock-chips.com : */ #define RK30_CAM_FRAME_MEASURE 5 - extern void videobuf_dma_contig_free(struct videobuf_queue *q, struct videobuf_buffer *buf); extern dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf); @@ -286,6 +287,8 @@ struct rk_camera_work struct videobuf_buffer *vb; struct rk_camera_dev *pcdev; struct work_struct work; + struct list_head queue; + unsigned int index; }; struct rk_camera_frmivalenum { @@ -356,6 +359,8 @@ struct rk_camera_dev struct rk_camera_reg reginfo_suspend; struct workqueue_struct *camera_wq; struct rk_camera_work *camera_work; + struct list_head camera_work_queue; + spinlock_t camera_work_lock; unsigned int camera_work_count; struct rk_camera_timer fps_timer; struct rk_camera_work camera_reinit_work; @@ -405,6 +410,8 @@ static int rk_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, icd->current_fmt->host_fmt); int bytes_per_line_host = soc_mbus_bytes_per_line(pcdev->host_width, icd->current_fmt->host_fmt); + unsigned int i; + struct rk_camera_work *wk; dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size); @@ -432,19 +439,21 @@ static int rk_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, } if (pcdev->camera_work == NULL) { - int wk_index = 0; - struct rk_camera_work *wk; - pcdev->camera_work = kmalloc(sizeof(struct rk_camera_work)*(*count), GFP_KERNEL); + pcdev->camera_work = wk = kzalloc(sizeof(struct rk_camera_work)*(*count), GFP_KERNEL); if (pcdev->camera_work == NULL) { RKCAMERA_TR("\n %s kmalloc fail\n", __FUNCTION__); BUG(); } - for(;wk_index < *count;wk_index++){ - wk = pcdev->camera_work+wk_index; - INIT_WORK(&wk->work, rk_camera_capture_process); - } - pcdev->camera_work_count = *count; + INIT_LIST_HEAD(&pcdev->camera_work_queue); + + for (i=0; i<(*count); i++) { + wk->index = i; + list_add_tail(&wk->queue, &pcdev->camera_work_queue); + wk++; + } + pcdev->camera_work_count = (*count); } + } pcdev->video_vq = vq; RKCAMERA_DG("%s..%d.. videobuf size:%d, vipmem_buf size:%d, count:%d \n",__FUNCTION__,__LINE__, *size,pcdev->vipmem_size, *count); @@ -687,6 +696,9 @@ static void rk_camera_capture_process(struct work_struct *work) do_ipp_err: up(&pcdev->zoominfo.sem); wake_up(&(camera_work->vb->done)); + spin_lock_irqsave(&pcdev->camera_work_lock, flags); + list_add_tail(&camera_work->queue, &pcdev->camera_work_queue); + spin_unlock_irqrestore(&pcdev->camera_work_lock, flags); return; } static irqreturn_t rk_camera_irq(int irq, void *data) @@ -739,7 +751,7 @@ static irqreturn_t rk_camera_irq(int irq, void *data) if(!vb){ printk("no acticve buffer!!!\n"); goto RK_CAMERA_IRQ_END; - } + } /* ddl@rock-chips.com : this vb may be deleted from queue */ if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) { list_del_init(&vb->queue); @@ -747,17 +759,10 @@ static irqreturn_t rk_camera_irq(int irq, void *data) pcdev->active = NULL; if (!list_empty(&pcdev->capture)) { pcdev->active = list_entry(pcdev->capture.next, struct videobuf_buffer, queue); - if (pcdev->active && (pcdev->active->state == VIDEOBUF_QUEUED)) { + if (pcdev->active) { + WARN_ON(pcdev->active->state != VIDEOBUF_QUEUED); rk_videobuf_capture(pcdev->active,pcdev); } - else if(pcdev->active){ - RKCAMERA_TR("%s : vb state is wrong ,del it \n",__FUNCTION__); - list_del_init(&(pcdev->active->queue)); - pcdev->active->state = VIDEOBUF_NEEDS_INIT; - wake_up(&pcdev->active->done); - pcdev->active = NULL; - - } } if (pcdev->active == NULL) { RKCAMERA_DG("%s video_buf queue is empty!\n",__FUNCTION__); @@ -769,10 +774,14 @@ static irqreturn_t rk_camera_irq(int irq, void *data) vb->field_count++; } if (CAM_WORKQUEUE_IS_EN()) { - wk = pcdev->camera_work + vb->i; - wk->vb = vb; - wk->pcdev = pcdev; - queue_work(pcdev->camera_wq, &(wk->work)); + if (!list_empty(&pcdev->camera_work_queue)) { + wk = list_entry(pcdev->camera_work_queue.next, struct rk_camera_work, queue); + list_del_init(&wk->queue); + INIT_WORK(&(wk->work), rk_camera_capture_process); + wk->vb = vb; + wk->pcdev = pcdev; + queue_work(pcdev->camera_wq, &(wk->work)); + } } else { wake_up(&vb->done); } @@ -819,7 +828,7 @@ static void rk_videobuf_release(struct videobuf_queue *vq, if (vb == pcdev->active) { RKCAMERA_DG("%s Wait for this video buf(0x%x) write finished!\n ",__FUNCTION__,(unsigned int)vb); - interruptible_sleep_on_timeout(&vb->done, 100); + interruptible_sleep_on_timeout(&vb->done, msecs_to_jiffies(500)); flush_workqueue(pcdev->camera_wq); RKCAMERA_DG("%s This video buf(0x%x) write finished, release now!!\n",__FUNCTION__,(unsigned int)vb); } @@ -921,7 +930,12 @@ static void rk_camera_deactivate(struct rk_camera_dev *pcdev) clk_disable(pcdev->hclk_cif); clk_disable(pcdev->cif_clk_in); + clk_disable(pcdev->cif_clk_out); + clk_enable(pcdev->cif_clk_out); + clk_set_rate(pcdev->cif_clk_out,48*1000*1000); + clk_disable(pcdev->cif_clk_out); + clk_disable(pcdev->pd_cif); return; } @@ -996,7 +1010,6 @@ static int rk_camera_add_device(struct soc_camera_device *icd) pcdev->icd_frmival[0].icd = icd; pcdev->icd_frmival[0].fival_list = kzalloc(sizeof(struct rk_camera_frmivalenum),GFP_KERNEL); } - RKCAMERA_TR("%s..%d.. \n",__FUNCTION__,__LINE__); ebusy: mutex_unlock(&camera_lock); @@ -1043,6 +1056,7 @@ static void rk_camera_remove_device(struct soc_camera_device *icd) kfree(pcdev->camera_work); pcdev->camera_work = NULL; pcdev->camera_work_count = 0; + INIT_LIST_HEAD(&pcdev->camera_work_queue); } rk_camera_deactivate(pcdev); pcdev->active = NULL; @@ -1206,33 +1220,33 @@ static void rk_camera_setup_format(struct soc_camera_device *icd, __u32 host_pix { case V4L2_PIX_FMT_NV16: cif_fmt_val &= ~YUV_OUTPUT_422; - cif_fmt_val &= ~UV_STORAGE_ORDER_UVUV; - pcdev->frame_inval = RK_CAM_FRAME_INVAL_DC; - pcdev->pixfmt = host_pixfmt; + cif_fmt_val &= ~UV_STORAGE_ORDER_UVUV; + pcdev->frame_inval = RK_CAM_FRAME_INVAL_DC; + pcdev->pixfmt = host_pixfmt; break; - case V4L2_PIX_FMT_NV61: - cif_fmt_val &= ~YUV_OUTPUT_422; - cif_fmt_val |= UV_STORAGE_ORDER_VUVU; - pcdev->frame_inval = RK_CAM_FRAME_INVAL_DC; - pcdev->pixfmt = host_pixfmt; - break; + case V4L2_PIX_FMT_NV61: + cif_fmt_val &= ~YUV_OUTPUT_422; + cif_fmt_val |= UV_STORAGE_ORDER_VUVU; + pcdev->frame_inval = RK_CAM_FRAME_INVAL_DC; + pcdev->pixfmt = host_pixfmt; + break; case V4L2_PIX_FMT_NV12: cif_fmt_val |= YUV_OUTPUT_420; - cif_fmt_val &= ~UV_STORAGE_ORDER_UVUV; + cif_fmt_val &= ~UV_STORAGE_ORDER_UVUV; if (pcdev->frame_inval != RK_CAM_FRAME_INVAL_INIT) pcdev->frame_inval = RK_CAM_FRAME_INVAL_INIT; pcdev->pixfmt = host_pixfmt; break; - case V4L2_PIX_FMT_NV21: - cif_fmt_val |= YUV_OUTPUT_420; - cif_fmt_val |= UV_STORAGE_ORDER_VUVU; - if (pcdev->frame_inval != RK_CAM_FRAME_INVAL_INIT) - pcdev->frame_inval = RK_CAM_FRAME_INVAL_INIT; - pcdev->pixfmt = host_pixfmt; - break; - default: /* ddl@rock-chips.com : vip output format is hold when pixfmt is invalidate */ - cif_fmt_val |= YUV_OUTPUT_422; - break; + case V4L2_PIX_FMT_NV21: + cif_fmt_val |= YUV_OUTPUT_420; + cif_fmt_val |= UV_STORAGE_ORDER_VUVU; + if (pcdev->frame_inval != RK_CAM_FRAME_INVAL_INIT) + pcdev->frame_inval = RK_CAM_FRAME_INVAL_INIT; + pcdev->pixfmt = host_pixfmt; + break; + default: /* ddl@rock-chips.com : vip output format is hold when pixfmt is invalidate */ + cif_fmt_val |= YUV_OUTPUT_422; + break; } switch (icd_code) { @@ -1278,13 +1292,11 @@ static void rk_camera_setup_format(struct soc_camera_device *icd, __u32 host_pix write_cif_reg(pcdev->base,CIF_CIF_FOR,cif_fmt_val); /* ddl@rock-chips.com: VIP capture mode and capture format must be set before FS register set */ // read_cif_reg(pcdev->base,CIF_CIF_INTSTAT); /* clear vip interrupte single */ - write_cif_reg(pcdev->base,CIF_CIF_INTSTAT,0xFFFFFFFF); - if((read_cif_reg(pcdev->base,CIF_CIF_CTRL) & MODE_PINGPONG) - ||(read_cif_reg(pcdev->base,CIF_CIF_CTRL) & MODE_LINELOOP)) // it is one frame mode - { - BUG(); - } - else{ // this is one frame mode + write_cif_reg(pcdev->base,CIF_CIF_INTSTAT,0xFFFFFFFF); + if((read_cif_reg(pcdev->base,CIF_CIF_CTRL) & MODE_PINGPONG) + ||(read_cif_reg(pcdev->base,CIF_CIF_CTRL) & MODE_LINELOOP)) { + BUG(); + } else{ // this is one frame mode cif_crop = (rect->left+ (rect->top<<16)); cif_fs = ((rect->width ) + (rect->height<<16)); } @@ -1294,10 +1306,9 @@ static void rk_camera_setup_format(struct soc_camera_device *icd, __u32 host_pix write_cif_reg(pcdev->base,CIF_CIF_SET_SIZE, cif_fs); write_cif_reg(pcdev->base,CIF_CIF_VIR_LINE_WIDTH, rect->width); write_cif_reg(pcdev->base,CIF_CIF_FRAME_STATUS, 0x00000003); - //MUST bypass scale + + //MUST bypass scale write_cif_reg(pcdev->base,CIF_CIF_SCL_CTRL,0x10); - //pcdev->host_width = rect->width; -// pcdev->host_height = rect->height; RKCAMERA_DG("%s.. crop:0x%x fs:0x%x cif_fmt_val:0x%x CIF_CIF_FOR:0x%x\n",__FUNCTION__,cif_crop,cif_fs,cif_fmt_val,read_cif_reg(pcdev->base,CIF_CIF_FOR)); return; } @@ -1478,8 +1489,6 @@ static int rk_camera_set_fmt(struct soc_camera_device *icd, RKCAMERA_DG("ratio = %d ,host:%d*%d\n",ratio,pcdev->host_width,pcdev->host_height); } else{ // needn't crop ,just scaled by ipp - // pcdev->host_width = usr_w; - // pcdev->host_height = usr_h; pcdev->host_width = mf.width; pcdev->host_height = mf.height; } @@ -1604,7 +1613,8 @@ static int rk_camera_try_fmt(struct soc_camera_device *icd, bool is_capture = rk_camera_fmt_capturechk(f); bool vipmem_is_overflow = false; struct v4l2_mbus_framefmt mf; - + int bytes_per_line_host; + usr_w = pix->width; usr_h = pix->height; RKCAMERA_DG("%s enter width:%d height:%d\n",__FUNCTION__,usr_w,usr_h); @@ -1645,13 +1655,14 @@ static int rk_camera_try_fmt(struct soc_camera_device *icd, goto RK_CAMERA_TRY_FMT_END; RKCAMERA_DG("%s mf.width:%d mf.height:%d\n",__FUNCTION__,mf.width,mf.height); #ifdef CONFIG_VIDEO_RK29_WORK_IPP - if ((mf.width > usr_w) && (mf.height > usr_h)) { + if ((mf.width != usr_w) || (mf.height != usr_h)) { + bytes_per_line_host = soc_mbus_bytes_per_line(mf.width,icd->current_fmt->host_fmt); if (is_capture) { - vipmem_is_overflow = (PAGE_ALIGN(pix->bytesperline*pix->height) > pcdev->vipmem_size); + vipmem_is_overflow = (PAGE_ALIGN(bytes_per_line_host*mf.height) > pcdev->vipmem_size); } else { /* Assume preview buffer minimum is 4 */ - vipmem_is_overflow = (PAGE_ALIGN(pix->bytesperline*pix->height)*4 > pcdev->vipmem_size); - } + vipmem_is_overflow = (PAGE_ALIGN(bytes_per_line_host*mf.height)*4 > pcdev->vipmem_size); + } if (vipmem_is_overflow == false) { pix->width = usr_w; pix->height = usr_h; @@ -1660,26 +1671,14 @@ static int rk_camera_try_fmt(struct soc_camera_device *icd, pix->width = mf.width; pix->height = mf.height; } - } else if ((mf.width < usr_w) && (mf.height < usr_h)) { - if (((usr_w>>1) < mf.width) && ((usr_h>>1) < mf.height)) { - if (is_capture) { - vipmem_is_overflow = (PAGE_ALIGN(pix->bytesperline*pix->height) > pcdev->vipmem_size); - } else { - vipmem_is_overflow = (PAGE_ALIGN(pix->bytesperline*pix->height)*4 > pcdev->vipmem_size); - } - if (vipmem_is_overflow == false) { - pix->width = usr_w; - pix->height = usr_h; - } else { - RKCAMERA_TR("vipmem for IPP is overflow, This resolution(%dx%d -> %dx%d) is invalidate!\n",mf.width,mf.height,usr_w,usr_h); - pix->width = mf.width; - pix->height = mf.height; - } - } else { - RKCAMERA_TR("The aspect ratio(%dx%d/%dx%d) is bigger than 2 !\n",mf.width,mf.height,usr_w,usr_h); - pix->width = mf.width; - pix->height = mf.height; - } + + if ((mf.width < usr_w) || (mf.height < usr_h)) { + if (((usr_w>>1) > mf.width) || ((usr_h>>1) > mf.height)) { + RKCAMERA_TR("The aspect ratio(%dx%d/%dx%d) is bigger than 2 !\n",mf.width,mf.height,usr_w,usr_h); + pix->width = mf.width; + pix->height = mf.height; + } + } } #else //need to change according to crop and scale capablicity @@ -1819,12 +1818,7 @@ static int rk_camera_suspend(struct soc_camera_device *icd, pm_message_t state) pcdev->reginfo_suspend.cifFmt= read_cif_reg(pcdev->base,CIF_CIF_FOR); pcdev->reginfo_suspend.cifVirWidth = read_cif_reg(pcdev->base,CIF_CIF_VIR_LINE_WIDTH); pcdev->reginfo_suspend.cifScale= read_cif_reg(pcdev->base,CIF_CIF_SCL_CTRL); - //pcdev->reginfo_suspend.VipCrm = read_vip_reg(pcdev->base,RK29_VIP_CRM); - - //tmp = pcdev->reginfo_suspend.cifFs>>16; /* ddl@rock-chips.com */ - //tmp += pcdev->reginfo_suspend.cifCrop>>16; - //pcdev->reginfo_suspend.cifFs = (pcdev->reginfo_suspend.cifFs & 0xffff) | (tmp<<16); - + pcdev->reginfo_suspend.Inval = Reg_Validate; rk_camera_deactivate(pcdev); @@ -1880,12 +1874,8 @@ static int rk_camera_resume(struct soc_camera_device *icd) static void rk_camera_reinit_work(struct work_struct *work) { struct v4l2_subdev *sd; - struct v4l2_mbus_framefmt mf; - const struct soc_camera_format_xlate *xlate; - int ret; struct rk_camera_work *camera_work = container_of(work, struct rk_camera_work, work); struct rk_camera_dev *pcdev = camera_work->pcdev; - struct videobuf_buffer *tmp_vb; struct soc_camera_link *tmp_soc_cam_link; int index = 0; unsigned long flags = 0; @@ -1912,89 +1902,27 @@ static void rk_camera_reinit_work(struct work_struct *work) RKCAMERA_TR("CIF_CIF_FRM0_ADDR_UV = 0X%x\n",read_cif_reg(pcdev->base,CIF_CIF_FRM0_ADDR_UV)); RKCAMERA_TR("CIF_CIF_FRAME_STATUS = 0X%x\n",read_cif_reg(pcdev->base,CIF_CIF_FRAME_STATUS)); } - if(1/*pcdev->reinit_times++ >= 2*/) - { - pcdev->stop_cif = true; - write_cif_reg(pcdev->base,CIF_CIF_CTRL, (read_cif_reg(pcdev->base,CIF_CIF_CTRL)&(~ENABLE_CAPTURE))); - RKCAMERA_DG("the reinit times = %d\n",pcdev->reinit_times); - #if 0 - while (!list_empty(&pcdev->capture)) { - tmp_vb = list_entry(pcdev->capture.next, struct videobuf_buffer, queue); - if (tmp_vb/* && (tmp_vb->state == VIDEOBUF_QUEUED)*/) - { - printk("wake up video buffer index = %d ,state = %d, !!!\n",tmp_vb->i,tmp_vb->state); - tmp_vb->state = VIDEOBUF_ERROR; - list_del_init(&(tmp_vb->queue)); - wake_up(&tmp_vb->done); - } - } - #else - spin_lock_irqsave(pcdev->video_vq->irqlock, flags); - for (index = 0; index < VIDEO_MAX_FRAME; index++) { - if (NULL == pcdev->video_vq->bufs[index]) - continue; - if (pcdev->video_vq->bufs[index]->state == VIDEOBUF_QUEUED) - { - list_del_init(&pcdev->video_vq->bufs[index]->queue); - pcdev->video_vq->bufs[index]->state = VIDEOBUF_NEEDS_INIT; - wake_up_all(&pcdev->video_vq->bufs[index]->done); - printk("wake up video buffer index = %d !!!\n",index); - } - } - spin_unlock_irqrestore(pcdev->video_vq->irqlock, flags); + + pcdev->stop_cif = true; + write_cif_reg(pcdev->base,CIF_CIF_CTRL, (read_cif_reg(pcdev->base,CIF_CIF_CTRL)&(~ENABLE_CAPTURE))); + RKCAMERA_DG("the reinit times = %d\n",pcdev->reinit_times); + + spin_lock_irqsave(pcdev->video_vq->irqlock, flags); + for (index = 0; index < VIDEO_MAX_FRAME; index++) { + if (NULL == pcdev->video_vq->bufs[index]) + continue; - #endif - RKCAMERA_TR("the %d reinit times ,wake up video buffers!\n ",pcdev->reinit_times); - }/*else{ //the first time,just reinit sensor ,don't wake up vb - // rk_cif_poweroff(pcdev); - RKCAMERA_DG("first time to reinit\n"); - // return; - if(IS_CIF0()){ - // write_cru_reg(CRU_CIF_RST_REG30,(read_cru_reg(CRU_CIF_RST_REG30)|MASK_RST_CIF0|RQUEST_RST_CIF0 )); - - // write_cru_reg(CRU_CIF_RST_REG30,(read_cru_reg(CRU_CIF_RST_REG30)&(~RQUEST_RST_CIF0)) | MASK_RST_CIF0); - rk_camera_store_register(pcdev); - rk_camera_deactivate(pcdev); - pmu_set_idle_request(IDLE_REQ_VIO, true); - cru_set_soft_reset(SOFT_RST_CIF0, true); - udelay(50); - cru_set_soft_reset(SOFT_RST_CIF0, false); - pmu_set_idle_request(IDLE_REQ_VIO, false); - rk_camera_activate(pcdev,NULL); - rk_camera_restore_register(pcdev); - rk_videobuf_capture(pcdev->active,pcdev); - printk("clean cru register reset cif0 0x%x\n",read_cru_reg(CRU_CIF_RST_REG30)); + if (pcdev->video_vq->bufs[index]->state == VIDEOBUF_QUEUED) + { + list_del_init(&pcdev->video_vq->bufs[index]->queue); + pcdev->video_vq->bufs[index]->state = VIDEOBUF_NEEDS_INIT; + wake_up_all(&pcdev->video_vq->bufs[index]->done); + printk("wake up video buffer index = %d !!!\n",index); + } + } + spin_unlock_irqrestore(pcdev->video_vq->irqlock, flags); - }else{ - // write_cru_reg(CRU_CIF_RST_REG30,MASK_RST_CIF1|RQUEST_RST_CIF1 | (read_cru_reg(CRU_CIF_RST_REG30))); - // write_cru_reg(CRU_CIF_RST_REG30,(read_cru_reg(CRU_CIF_RST_REG30)&(~RQUEST_RST_CIF1)) | MASK_RST_CIF1); - rk_camera_store_register(pcdev); - rk_camera_deactivate(pcdev); - pmu_set_idle_request(IDLE_REQ_VIO, true); - cru_set_soft_reset(SOFT_RST_CIF1, true); - udelay(50); - cru_set_soft_reset(SOFT_RST_CIF1, false); - pmu_set_idle_request(IDLE_REQ_VIO, false); - rk_camera_activate(pcdev,NULL); - rk_camera_restore_register(pcdev); - rk_videobuf_capture(pcdev->active,pcdev); - } - tmp_soc_cam_link->power(pcdev->icd->pdev,0); - // rk_cif_poweron(pcdev); - tmp_soc_cam_link->power(pcdev->icd->pdev,1); - control = to_soc_camera_control(pcdev->icd); - sd = dev_get_drvdata(control); - ret = v4l2_subdev_call(sd,core, init, 1); - - mf.width = pcdev->icd->user_width; - mf.height = pcdev->icd->user_height; - xlate = soc_camera_xlate_by_fourcc(pcdev->icd, pcdev->icd->current_fmt->host_fmt->fourcc); - mf.code = xlate->code; - ret |= v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); - write_cif_reg(pcdev->base,CIF_CIF_CTRL, (read_cif_reg(pcdev->base,CIF_CIF_CTRL)|ENABLE_CAPTURE)); - - RKCAMERA_TR("first time Camera host haven't recevie data from sensor,Reinit sensor now! ret:0x%x\n",ret); - }*/ + RKCAMERA_TR("the %d reinit times ,wake up video buffers!\n ",pcdev->reinit_times); } static enum hrtimer_restart rk_camera_fps_func(struct hrtimer *timer) { @@ -2117,11 +2045,6 @@ static int rk_camera_s_stream(struct soc_camera_device *icd, int enable) write_cif_reg(pcdev->base,CIF_CIF_CTRL, cif_ctrl_val); pcdev->stop_cif = true; spin_unlock_irqrestore(&pcdev->lock, flags); - // printk("flush work end!!!!!!!!!\n"); - // mdelay(3*1000); - // write_cif_reg(pcdev->base,CIF_CIF_FRAME_STATUS, 0x00000003);//frame1 has been ready to receive data,frame 2 is not used - // write_cif_reg(pcdev->base,CIF_CIF_INTSTAT,0xFFFFFFFF); /* clear vip interrupte single */ - // write_cif_reg(pcdev->base,CIF_CIF_FRAME_STATUS,0); /* clear vip interrupte single */ flush_workqueue((pcdev->camera_wq)); RKCAMERA_DG("STREAM_OFF cancel timer and flush work:0x%x \n", ret); } @@ -2233,48 +2156,7 @@ static int rk_camera_set_digit_zoom(struct soc_camera_device *icd, struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct rk_camera_dev *pcdev = ici->priv; - #if 0 - unsigned int cif_fs = 0,cif_crop = 0; - int work_index =0,stream_on = 0; -/* ddl@rock-chips.com : The largest resolution is 2047x1088, so larger resolution must be operated some times - (Assume operate times is 4),but resolution which ipp can operate ,it is width and height must be even. */ - a.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - a.c.width = pcdev->host_width*100/zoom_rate; - a.c.width &= ~0x03; - a.c.height = pcdev->host_height*100/zoom_rate; - a.c.height &= ~0x03; - - a.c.left = (((pcdev->host_width - a.c.width)>>1) +pcdev->host_left)&(~0x01); - a.c.top = (((pcdev->host_height - a.c.height)>>1) + pcdev->host_top)&(~0x01); - stream_on = read_cif_reg(pcdev->base,CIF_CIF_CTRL); - if (stream_on & ENABLE_CAPTURE) - write_cif_reg(pcdev->base,CIF_CIF_CTRL, (stream_on & (~ENABLE_CAPTURE))); - if (CAM_IPPWORK_IS_EN() && (stream_on & ENABLE_CAPTURE)){ - for(;work_index < pcdev->camera_work_count;work_index++) - flush_work(&((pcdev->camera_work + work_index)->work)); - pcdev->frame_inval = RK_CAM_FRAME_INVAL_DC; - } - //printk("host_left = %d , host_top = %d\n",pcdev->host_left,pcdev->host_top); - down(&pcdev->zoominfo.sem); - pcdev->zoominfo.a.c.height = a.c.height; - pcdev->zoominfo.a.c.width = a.c.width; - pcdev->zoominfo.a.c.top = 0; - pcdev->zoominfo.a.c.left = 0; - pcdev->zoominfo.vir_width = a.c.width; - up(&pcdev->zoominfo.sem); - - cif_crop = a.c.left+ (a.c.top<<16); - cif_fs = a.c.width + ((a.c.height)<<16); -//cif do the crop , ipp do the scale - write_cif_reg(pcdev->base,CIF_CIF_CROP, cif_crop); - write_cif_reg(pcdev->base,CIF_CIF_SET_SIZE, cif_fs); - write_cif_reg(pcdev->base,CIF_CIF_VIR_LINE_WIDTH, a.c.width); - write_cif_reg(pcdev->base,CIF_CIF_FRAME_STATUS, 0x00000003); - write_cif_reg(pcdev->base,CIF_CIF_SCL_CTRL,0x10); - if (stream_on & ENABLE_CAPTURE) - write_cif_reg(pcdev->base,CIF_CIF_CTRL, stream_on); - #else //change the crop and scale parameters a.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; a.c.width = pcdev->host_width*100/zoom_rate; @@ -2290,8 +2172,6 @@ static int rk_camera_set_digit_zoom(struct soc_camera_device *icd, pcdev->zoominfo.a.c.left = a.c.left; pcdev->zoominfo.vir_width = pcdev->host_width; up(&pcdev->zoominfo.sem); - - #endif RKCAMERA_DG("%s..zoom_rate:%d (%dx%d at (%d,%d)-> %dx%d)\n",__FUNCTION__, zoom_rate,a.c.width, a.c.height, a.c.left, a.c.top, icd->user_width, icd->user_height ); return 0; @@ -2446,7 +2326,6 @@ static int rk_camera_probe(struct platform_device *pdev) pcdev->zoominfo.zoom_rate = 100; pcdev->hostid = pdev->id; - /*config output clk*/ // must modify start if(IS_CIF0()){ pcdev->pd_cif = clk_get(NULL, "pd_cif0"); @@ -2494,7 +2373,9 @@ static int rk_camera_probe(struct platform_device *pdev) } #endif INIT_LIST_HEAD(&pcdev->capture); + INIT_LIST_HEAD(&pcdev->camera_work_queue); spin_lock_init(&pcdev->lock); + spin_lock_init(&pcdev->camera_work_lock); sema_init(&pcdev->zoominfo.sem,1); /* From 4dd108cba4dfd5de0845b3b8cc5d66c646ad1f54 Mon Sep 17 00:00:00 2001 From: xbw Date: Fri, 17 Aug 2012 10:49:17 +0800 Subject: [PATCH 210/261] sdmmc: prepare for RK2918 and RK31 --- drivers/mmc/host/rk29_sdmmc.c | 42 +++++++++++++++++++++++------------ drivers/mmc/host/rk29_sdmmc.h | 6 ++--- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/drivers/mmc/host/rk29_sdmmc.c b/drivers/mmc/host/rk29_sdmmc.c index fc6e5b28d6b2..5584f198a924 100755 --- a/drivers/mmc/host/rk29_sdmmc.c +++ b/drivers/mmc/host/rk29_sdmmc.c @@ -70,13 +70,17 @@ int debug_level = 5; #endif #if defined(CONFIG_ARCH_RK29) -#define RK29_SDMMC0DETECTN_GPIO RK29_PIN2_PA2 -#define RK29_SDMMC0PWREN_GPIO RK29_PIN5_PD5 - + #define RK29_SDMMC0DETECTN_GPIO RK29_PIN2_PA2 + #define RK29_SDMMC0PWREN_GPIO RK29_PIN5_PD5 #elif defined(CONFIG_ARCH_RK30) -#define RK29_SDMMC0DETECTN_GPIO RK30_PIN3_PB6 -#define RK29_SDMMC0PWREN_GPIO RK30_PIN3_PA7 - + #define RK29_SDMMC0DETECTN_GPIO RK30_PIN3_PB6 + #define RK29_SDMMC0PWREN_GPIO RK30_PIN3_PA7 +#elif defined(CONFIG_ARCH_RK2928) + #define RK29_SDMMC0DETECTN_GPIO RK2928_PIN1_PC7 + #define RK29_SDMMC0PWREN_GPIO RK2928_PIN1_PB6 +#elif defined(CONFIG_ARCH_RK31) + #define RK29_SDMMC0DETECTN_GPIO RK30_PIN3_PB0 + #define RK29_SDMMC0PWREN_GPIO RK30_PIN3_PA1 #endif #define RK29_SDMMC_ERROR_FLAGS (SDMMC_INT_FRUN | SDMMC_INT_HLE ) @@ -1534,7 +1538,7 @@ int rk29_sdmmc_reset_controller(struct rk29_sdmmc *host) /* reset */ #if defined(CONFIG_ARCH_RK29) rk29_sdmmc_write(host->regs, SDMMC_CTRL,(SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET )); -#elif defined(CONFIG_ARCH_RK30) +#else rk29_sdmmc_write(host->regs, SDMMC_CTRL,(SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET)); #endif timeOut = 1000; @@ -1946,7 +1950,7 @@ static void rk29_sdmmc_INT_CMD_DONE_timeout(unsigned long host_data) if(STATE_SENDING_CMD == host->state) { - if((0==host->cmd->retries)&&(12 != host->cmd->opcode)) + if((0==host->cmd->retries)&&(12 != host->cmd->opcode)/*&&(55 != host->cmd->opcode)*/) { printk(KERN_WARNING "%d... cmd=%d, INT_CMD_DONE timeout, errorStep=0x%x, host->state=%x [%s]\n",\ __LINE__,host->cmd->opcode, host->errorstep,host->state,host->dma_name); @@ -3551,12 +3555,14 @@ static int rk29_sdmmc_probe(struct platform_device *pdev) ret = rk29_dma_config(host->dma_info.chn, 4, 16); } else - { - #if defined(CONFIG_ARCH_RK30) - ret = rk29_dma_config(host->dma_info.chn, 4, 16); // a unified set the burst value to 16 in RK30,noted at 2012-07-16 - #else - ret = rk29_dma_config(host->dma_info.chn, 4, 1); // to maintain set this value to 1 in RK29,noted at 2012-07-16 - #endif + { + #if defined(CONFIG_ARCH_RK29) + // to maintain set this value to 1 in RK29,noted at 2012-07-16 + ret = rk29_dma_config(host->dma_info.chn, 4, 1); + #else + // a unified set the burst value to 16 in RK30,noted at 2012-07-16 + ret = rk29_dma_config(host->dma_info.chn, 4, 16); + #endif } #endif if(ret < 0) @@ -3775,6 +3781,10 @@ static int rk29_sdmmc_sdcard_suspend(struct rk29_sdmmc *host) rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_GPIO2A2); #elif defined(CONFIG_ARCH_RK30) rk29_mux_api_set(GPIO3B6_SDMMC0DETECTN_NAME, GPIO3B_GPIO3B6); +#elif defined(CONFIG_ARCH_RK2928) + rk29_mux_api_set(GPIO1C1_MMC0_DETN_NAME, GPIO1C_GPIO1C1); +#elif defined(CONFIG_ARCH_RK31) + rk29_mux_api_set(GPIO3B0_SDMMC0DETECTN_NAME, GPIO3B_GPIO3B0); #endif gpio_request(RK29_SDMMC0DETECTN_GPIO, "sd_detect"); @@ -3800,6 +3810,10 @@ static void rk29_sdmmc_sdcard_resume(struct rk29_sdmmc *host) rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_SDMMC0_DETECT_N); #elif defined(CONFIG_ARCH_RK30) rk29_mux_api_set(GPIO3B6_SDMMC0DETECTN_NAME, GPIO3B_SDMMC0_DETECT_N); +#elif defined(CONFIG_ARCH_RK2928) + rk29_mux_api_set(GPIO1C1_MMC0_DETN_NAME, GPIO1C_MMC0_DETN); +#elif defined(CONFIG_ARCH_RK31) + rk29_mux_api_set(GPIO3B0_SDMMC0DETECTN_NAME, GPIO3B_SDMMC0DETECTN); #endif } diff --git a/drivers/mmc/host/rk29_sdmmc.h b/drivers/mmc/host/rk29_sdmmc.h index 60bb6c7ef23f..17b6d2b209b8 100755 --- a/drivers/mmc/host/rk29_sdmmc.h +++ b/drivers/mmc/host/rk29_sdmmc.h @@ -48,7 +48,7 @@ #if defined(CONFIG_ARCH_RK29) #define SDMMC_DATA (0x100) -#elif defined(CONFIG_ARCH_RK30) +#elif defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) || defined(CONFIG_ARCH_RK2928) #define SDMMC_VERID (0x06c) //Version ID register #define SDMMC_UHS_REG (0x074) //UHS-I register #define SDMMC_RST_n (0x078) //Hardware reset register @@ -102,7 +102,7 @@ /* Interrupt status & mask register defines(base+0x24) */ #if defined(CONFIG_ARCH_RK29) #define SDMMC_INT_SDIO RK2818_BIT(16) //SDIO interrupt -#elif defined(CONFIG_ARCH_RK30) +#elif defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) || defined(CONFIG_ARCH_RK2928) #define SDMMC_INT_SDIO RK2818_BIT(24) //SDIO interrupt #define SDMMC_INT_UNBUSY RK2818_BIT(16) //data no busy interrupt #endif @@ -181,7 +181,7 @@ #define RX_WMARK (0xF) //RX watermark level set to 15 #define TX_WMARK (0x10) //TX watermark level set to 16 -#elif defined(CONFIG_ARCH_RK30) +#elif defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) || defined(CONFIG_ARCH_RK2928) #define FIFO_DEPTH (0x100) //FIFO depth = 256 word #define RX_WMARK_SHIFT (16) #define TX_WMARK_SHIFT (0) From 3161f4afe426eac72dca36cd8646fd666331f0c8 Mon Sep 17 00:00:00 2001 From: ywj Date: Fri, 17 Aug 2012 11:32:40 +0800 Subject: [PATCH 211/261] amend DEVICE_ATTR of rk30_factory_adc_battery for cts --- drivers/power/rk30_factory_adc_battery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/rk30_factory_adc_battery.c b/drivers/power/rk30_factory_adc_battery.c index 02396a374fc1..04527ec71050 100644 --- a/drivers/power/rk30_factory_adc_battery.c +++ b/drivers/power/rk30_factory_adc_battery.c @@ -249,7 +249,7 @@ static ssize_t bat_param_read(struct device *dev,struct device_attribute *attr, #endif return 0; } -DEVICE_ATTR(batparam, 0777, bat_param_read,NULL); +DEVICE_ATTR(batparam, 0664, bat_param_read,NULL); static ssize_t rkbatt_show_debug_attrs(struct device *dev, From 852aaf411c5cc8ebf08fb2d8ff7562933e789a1f Mon Sep 17 00:00:00 2001 From: ddl Date: Fri, 17 Aug 2012 12:24:33 +0800 Subject: [PATCH 212/261] camera rk29: add support zoom by arm, version update to v0.x.11 --- arch/arm/mach-rk29/include/mach/rk29_camera.h | 19 + arch/arm/plat-rk/include/plat/rk_camera.h | 7 + drivers/media/video/rk29_camera_oneframe.c | 327 ++++++++++++++++-- 3 files changed, 318 insertions(+), 35 deletions(-) diff --git a/arch/arm/mach-rk29/include/mach/rk29_camera.h b/arch/arm/mach-rk29/include/mach/rk29_camera.h index 66c9f68b5b60..1e4fc5fad006 100755 --- a/arch/arm/mach-rk29/include/mach/rk29_camera.h +++ b/arch/arm/mach-rk29/include/mach/rk29_camera.h @@ -25,4 +25,23 @@ #include + +#define CONFIG_CAMERA_SCALE_CROP_MACHINE RK_CAM_SCALE_CROP_IPP + +#if (CONFIG_CAMERA_SCALE_CROP_MACHINE==RK_CAM_SCALE_CROP_ARM) + #define CAMERA_SCALE_CROP_MACHINE "arm" +#elif (CONFIG_CAMERA_SCALE_CROP_MACHINE==RK_CAM_SCALE_CROP_IPP) + #define CAMERA_SCALE_CROP_MACHINE "ipp" +#elif (CONFIG_CAMERA_SCALE_CROP_MACHINE==RK_CAM_SCALE_CROP_RGA) + #define CAMERA_SCALE_CROP_MACHINE "rga" +#elif (CONFIG_CAMERA_SCALE_CROP_MACHINE==RK_CAM_SCALE_CROP_PP) + #define CAMERA_SCALE_CROP_MACHINE "pp" +#endif + +#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_ARM) + #define CAMERA_VIDEOBUF_ARM_ACCESS 1 +#else + #define CAMERA_VIDEOBUF_ARM_ACCESS 0 +#endif + #endif diff --git a/arch/arm/plat-rk/include/plat/rk_camera.h b/arch/arm/plat-rk/include/plat/rk_camera.h index d4659d3f4708..729f87c74149 100755 --- a/arch/arm/plat-rk/include/plat/rk_camera.h +++ b/arch/arm/plat-rk/include/plat/rk_camera.h @@ -154,6 +154,12 @@ #define RK29_CAM_FLASHACTIVE_H (0x01< #include #include - +#include static int debug; module_param(debug, int, S_IRUGO|S_IWUSR|S_IWGRP); @@ -160,8 +160,9 @@ module_param(debug, int, S_IRUGO|S_IWUSR|S_IWGRP); *v0.x.c : fix work queue havn't been finished after close device; *v0.x.d : fix error when calculate crop left-top point coordinate; *v0.x.f : fix struct rk29_camera_work may be reentrant. +*v0.x.11: add support zoom by arm; */ -#define RK29_CAM_VERSION_CODE KERNEL_VERSION(0, 1, 0xf) +#define RK29_CAM_VERSION_CODE KERNEL_VERSION(0, 1, 0x11) /* limit to rk29 hardware capabilities */ #define RK29_CAM_BUS_PARAM (SOCAM_MASTER |\ @@ -238,6 +239,14 @@ struct rk29_camera_zoominfo struct v4l2_crop a; int zoom_rate; }; +#if CAMERA_VIDEOBUF_ARM_ACCESS +struct rk29_camera_vbinfo +{ + unsigned int phy_addr; + void __iomem *vir_addr; + unsigned int size; +}; +#endif struct rk29_camera_dev { struct soc_camera_host soc_host; @@ -270,8 +279,13 @@ struct rk29_camera_dev unsigned long frame_interval; unsigned int pixfmt; unsigned int vipmem_phybase; + void __iomem *vipmem_virbase; unsigned int vipmem_size; unsigned int vipmem_bsize; +#if CAMERA_VIDEOBUF_ARM_ACCESS + struct rk29_camera_vbinfo *vbinfo; + unsigned int vbinfo_count; +#endif int host_width; int host_height; int icd_width; @@ -378,6 +392,22 @@ static int rk29_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, } pcdev->camera_work_count = (*count); } +#if CAMERA_VIDEOBUF_ARM_ACCESS + if (pcdev->vbinfo && (pcdev->vbinfo_count != *count)) { + kfree(pcdev->vbinfo); + pcdev->vbinfo = NULL; + pcdev->vbinfo_count = 0x00; + } + + if (pcdev->vbinfo == NULL) { + pcdev->vbinfo = kzalloc(sizeof(struct rk29_camera_vbinfo)*(*count), GFP_KERNEL); + if (pcdev->vbinfo == NULL) { + RK29CAMERA_TR("\n %s vbinfo kmalloc fail\n", __FUNCTION__); + BUG(); + } + pcdev->vbinfo_count = *count; + } +#endif } RK29CAMERA_DG("%s..%d.. videobuf size:%d, vipmem_buf size:%d, count:%d \n",__FUNCTION__,__LINE__, *size,pcdev->vipmem_size, *count); @@ -498,7 +528,8 @@ static void rk29_videobuf_queue(struct videobuf_queue *vq, struct soc_camera_device *icd = vq->priv_data; struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct rk29_camera_dev *pcdev = ici->priv; - + struct rk29_camera_vbinfo *vb_info; + dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, vb, vb->baddr, vb->bsize); @@ -512,6 +543,31 @@ static void rk29_videobuf_queue(struct videobuf_queue *vq, else BUG(); /* ddl@rock-chips.com : The same videobuffer queue again */ } +#if CAMERA_VIDEOBUF_ARM_ACCESS + if (pcdev->vbinfo) { + vb_info = pcdev->vbinfo+vb->i; + if ((vb_info->phy_addr != vb->boff) || (vb_info->size != vb->bsize)) { + if (vb_info->vir_addr) { + iounmap(vb_info->vir_addr); + release_mem_region(vb_info->phy_addr, vb_info->size); + vb_info->vir_addr = NULL; + vb_info->phy_addr = 0x00; + vb_info->size = 0x00; + } + + if (request_mem_region(vb->boff,vb->bsize,"rk29_camera_vb")) { + vb_info->vir_addr = ioremap_cached(vb->boff,vb->bsize); + } + + if (vb_info->vir_addr) { + vb_info->size = vb->bsize; + vb_info->phy_addr = vb->boff; + } else { + RK29CAMERA_TR("%s..%d:ioremap videobuf %d failed\n",__FUNCTION__,__LINE__, vb->i); + } + } + } +#endif if (!pcdev->active) { pcdev->active = vb; rk29_videobuf_capture(vb); @@ -541,7 +597,8 @@ static int rk29_pixfmt2ippfmt(unsigned int pixfmt, int *ippfmt) rk29_pixfmt2ippfmt_err: return -1; } -static void rk29_camera_capture_process(struct work_struct *work) +#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_IPP) +static int rk29_camera_scale_crop_ipp(struct work_struct *work) { struct rk29_camera_work *camera_work = container_of(work, struct rk29_camera_work, work); struct videobuf_buffer *vb = camera_work->vb; @@ -550,7 +607,8 @@ static void rk29_camera_capture_process(struct work_struct *work) unsigned long int flags; int src_y_offset,src_uv_offset,dst_y_offset,dst_uv_offset,src_y_size,dst_y_size; int scale_times,w,h,vipdata_base; - + int ret = 0; + /* *ddl@rock-chips.com: * IPP Dest image resolution is 2047x1088, so scale operation break up some times @@ -564,8 +622,6 @@ static void rk29_camera_capture_process(struct work_struct *work) memset(&ipp_req, 0, sizeof(struct rk29_ipp_req)); - down(&pcdev->zoominfo.sem); - ipp_req.timeout = 100; ipp_req.flag = IPP_ROT_0; ipp_req.src0.w = pcdev->zoominfo.a.c.width/scale_times; @@ -614,21 +670,170 @@ static void rk29_camera_capture_process(struct work_struct *work) RK29CAMERA_TR("ipp_req.src_vir_w:0x%x ipp_req.dst_vir_w :0x%x\n",ipp_req.src_vir_w ,ipp_req.dst_vir_w); RK29CAMERA_TR("ipp_req.timeout:0x%x ipp_req.flag :0x%x\n",ipp_req.timeout,ipp_req.flag); - goto do_ipp_err; + goto rk29_camera_scale_crop_ipp_end; } } } + +rk29_camera_scale_crop_ipp_end: + return ret; +} +#endif +#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_ARM) +static int rk29_camera_scale_crop_arm(struct work_struct *work) +{ + struct rk29_camera_work *camera_work = container_of(work, struct rk29_camera_work, work); + struct videobuf_buffer *vb = camera_work->vb; + struct rk29_camera_dev *pcdev = camera_work->pcdev; + struct rk29_camera_vbinfo *vb_info; + unsigned char *psY,*pdY,*psUV,*pdUV; + unsigned char *src,*dst; + unsigned long src_phy,dst_phy; + int srcW,srcH,cropW,cropH,dstW,dstH; + long zoomindstxIntInv,zoomindstyIntInv; + long x,y; + long yCoeff00,yCoeff01,xCoeff00,xCoeff01; + long sX,sY; + long r0,r1,a,b,c,d; + int ret = 0; + - if (pcdev->icd_cb.sensor_cb) - (pcdev->icd_cb.sensor_cb)(vb); - -do_ipp_err: - up(&pcdev->zoominfo.sem); - wake_up(&(camera_work->vb->done)); - spin_lock_irqsave(&pcdev->camera_work_lock, flags); - list_add_tail(&camera_work->queue, &pcdev->camera_work_queue); - spin_unlock_irqrestore(&pcdev->camera_work_lock, flags); - return; + src_phy = pcdev->vipmem_phybase + vb->i*pcdev->vipmem_bsize; + src = psY = (unsigned char*)(pcdev->vipmem_virbase + vb->i*pcdev->vipmem_bsize); + psUV = psY + pcdev->host_width*pcdev->host_height; + srcW = pcdev->host_width; + srcH = pcdev->host_height; + cropW = pcdev->zoominfo.a.c.width; + cropH = pcdev->zoominfo.a.c.height; + psY = psY + pcdev->host_width - pcdev->zoominfo.a.c.width; + psUV = psUV + pcdev->host_width - pcdev->zoominfo.a.c.width; + + vb_info = pcdev->vbinfo+vb->i; + dst_phy = vb_info->phy_addr; + dst = pdY = (unsigned char*)vb_info->vir_addr; + pdUV = pdY + pcdev->icd->user_width*pcdev->icd->user_height; + dstW = pcdev->icd->user_width; + dstH = pcdev->icd->user_height; + + zoomindstxIntInv = ((unsigned long)cropW<<16)/dstW + 1; + zoomindstyIntInv = ((unsigned long)cropH<<16)/dstH + 1; + + //y + //for(y = 0; y> 16); + + for(x = 0; x> 16); + + a = psY[sY*srcW + sX]; + b = psY[sY*srcW + sX + 1]; + c = psY[(sY+1)*srcW + sX]; + d = psY[(sY+1)*srcW + sX + 1]; + + r0 = (a * xCoeff01 + b * xCoeff00)>>16 ; + r1 = (c * xCoeff01 + d * xCoeff00)>>16 ; + r0 = (r0 * yCoeff01 + r1 * yCoeff00)>>16; + + pdY[x] = r0; + } + pdY += dstW; + } + + dstW /= 2; + dstH /= 2; + srcW /= 2; + srcH /= 2; + + //UV + //for(y = 0; y> 16); + + for(x = 0; x> 16); + + //U + a = psUV[(sY*srcW + sX)*2]; + b = psUV[(sY*srcW + sX + 1)*2]; + c = psUV[((sY+1)*srcW + sX)*2]; + d = psUV[((sY+1)*srcW + sX + 1)*2]; + + r0 = (a * xCoeff01 + b * xCoeff00)>>16 ; + r1 = (c * xCoeff01 + d * xCoeff00)>>16 ; + r0 = (r0 * yCoeff01 + r1 * yCoeff00)>>16; + + pdUV[x*2] = r0; + + //V + a = psUV[(sY*srcW + sX)*2 + 1]; + b = psUV[(sY*srcW + sX + 1)*2 + 1]; + c = psUV[((sY+1)*srcW + sX)*2 + 1]; + d = psUV[((sY+1)*srcW + sX + 1)*2 + 1]; + + r0 = (a * xCoeff01 + b * xCoeff00)>>16 ; + r1 = (c * xCoeff01 + d * xCoeff00)>>16 ; + r0 = (r0 * yCoeff01 + r1 * yCoeff00)>>16; + + pdUV[x*2 + 1] = r0; + } + pdUV += dstW*2; + } + +rk29_camera_scale_crop_arm_end: + + dmac_flush_range((void*)src,(void*)(src+pcdev->vipmem_bsize)); + outer_flush_range((phys_addr_t)src_phy,(phys_addr_t)(src_phy+pcdev->vipmem_bsize)); + + dmac_flush_range((void*)dst,(void*)(dst+vb_info->size)); + outer_flush_range((phys_addr_t)dst_phy,(phys_addr_t)(dst_phy+vb_info->size)); + + return ret; +} +#endif + +static void rk29_camera_capture_process(struct work_struct *work) +{ + struct rk29_camera_work *camera_work = container_of(work, struct rk29_camera_work, work); + struct videobuf_buffer *vb = camera_work->vb; + struct rk29_camera_dev *pcdev = camera_work->pcdev; + //enum v4l2_mbus_pixelcode icd_code = pcdev->icd->current_fmt->code; + unsigned long flags = 0; + int err = 0; + + if (!CAM_WORKQUEUE_IS_EN()) + goto rk29_camera_capture_process_end; + + down(&pcdev->zoominfo.sem); + if (pcdev->icd_cb.scale_crop_cb) + err = (pcdev->icd_cb.scale_crop_cb)(work); + up(&pcdev->zoominfo.sem); + + if (pcdev->icd_cb.sensor_cb) + (pcdev->icd_cb.sensor_cb)(vb); + +rk29_camera_capture_process_end: + if (err) { + vb->state = VIDEOBUF_ERROR; + } else { + if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) { + vb->state = VIDEOBUF_DONE; + vb->field_count++; + } + } + wake_up(&(camera_work->vb->done)); + spin_lock_irqsave(&pcdev->camera_work_lock, flags); + list_add_tail(&camera_work->queue, &pcdev->camera_work_queue); + spin_unlock_irqrestore(&pcdev->camera_work_lock, flags); + return; } static irqreturn_t rk29_camera_irq(int irq, void *data) { @@ -680,13 +885,8 @@ static irqreturn_t rk29_camera_irq(int irq, void *data) if (pcdev->active == NULL) { RK29CAMERA_DG("%s video_buf queue is empty!\n",__FUNCTION__); } - - if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) { - vb->state = VIDEOBUF_DONE; - do_gettimeofday(&vb->ts); - vb->field_count++; - } - + + do_gettimeofday(&vb->ts); if (CAM_WORKQUEUE_IS_EN()) { if (!list_empty(&pcdev->camera_work_queue)) { wk = list_entry(pcdev->camera_work_queue.next, struct rk29_camera_work, queue); @@ -697,6 +897,10 @@ static irqreturn_t rk29_camera_irq(int irq, void *data) queue_work(pcdev->camera_wq, &(wk->work)); } } else { + if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) { + vb->state = VIDEOBUF_DONE; + vb->field_count++; + } wake_up(&vb->done); } } @@ -713,6 +917,8 @@ static void rk29_videobuf_release(struct videobuf_queue *vq, struct soc_camera_device *icd = vq->priv_data; struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct rk29_camera_dev *pcdev = ici->priv; + struct rk29_camera_vbinfo *vb_info =NULL; + #ifdef DEBUG dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, vb->baddr, vb->bsize); @@ -732,17 +938,26 @@ static void rk29_videobuf_release(struct videobuf_queue *vq, dev_dbg(&icd->dev, "%s (unknown)\n", __func__); break; } -#endif - if(vb->i == 0){ - flush_workqueue(pcdev->camera_wq); - } - +#endif if (vb == pcdev->active) { RK29CAMERA_DG("%s Wait for this video buf(0x%x) write finished!\n ",__FUNCTION__,(unsigned int)vb); interruptible_sleep_on_timeout(&vb->done, msecs_to_jiffies(500)); - flush_workqueue(pcdev->camera_wq); RK29CAMERA_DG("%s This video buf(0x%x) write finished, release now!!\n",__FUNCTION__,(unsigned int)vb); } + + flush_workqueue(pcdev->camera_wq); +#if CAMERA_VIDEOBUF_ARM_ACCESS + if (pcdev->vbinfo) { + vb_info = pcdev->vbinfo + vb->i; + + if (vb_info->vir_addr) { + iounmap(vb_info->vir_addr); + release_mem_region(vb_info->phy_addr, vb_info->size); + memset(vb_info, 0x00, sizeof(struct rk29_camera_vbinfo)); + } + + } +#endif rk29_videobuf_free(vq, buf); } @@ -961,7 +1176,9 @@ static void rk29_camera_remove_device(struct soc_camera_device *icd) struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct rk29_camera_dev *pcdev = ici->priv; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - + struct rk29_camera_vbinfo *vb_info; + unsigned int i; + mutex_lock(&camera_lock); BUG_ON(icd != pcdev->icd); @@ -982,7 +1199,22 @@ static void rk29_camera_remove_device(struct soc_camera_device *icd) pcdev->camera_work_count = 0; INIT_LIST_HEAD(&pcdev->camera_work_queue); } - +#if CAMERA_VIDEOBUF_ARM_ACCESS + if (pcdev->vbinfo) { + vb_info = pcdev->vbinfo; + for (i=0; ivbinfo_count; i++) { + if (vb_info->vir_addr) { + iounmap(vb_info->vir_addr); + release_mem_region(vb_info->phy_addr, vb_info->size); + memset(vb_info, 0x00, sizeof(struct rk29_camera_vbinfo)); + } + vb_info++; + } + kfree(pcdev->vbinfo); + pcdev->vbinfo = NULL; + pcdev->vbinfo_count = 0; + } +#endif pcdev->active = NULL; pcdev->icd = NULL; pcdev->icd_cb.sensor_cb = NULL; @@ -2053,8 +2285,8 @@ static int rk29_camera_probe(struct platform_device *pdev) int irq,i; int err = 0; - RK29CAMERA_TR("RK29 Camera driver version: v%d.%d.%d\n",(RK29_CAM_VERSION_CODE&0xff0000)>>16, - (RK29_CAM_VERSION_CODE&0xff00)>>8,RK29_CAM_VERSION_CODE&0xff); + RK29CAMERA_TR("RK29 Camera driver version: v%d.%d.%d Zoom by %s\n",(RK29_CAM_VERSION_CODE&0xff0000)>>16, + (RK29_CAM_VERSION_CODE&0xff00)>>8,RK29_CAM_VERSION_CODE&0xff,CAMERA_SCALE_CROP_MACHINE); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); @@ -2117,11 +2349,24 @@ static int rk29_camera_probe(struct platform_device *pdev) if (pcdev->pdata && (strcmp(pcdev->pdata->meminfo.name,"camera_ipp_mem")==0)) { pcdev->vipmem_phybase = pcdev->pdata->meminfo.start; pcdev->vipmem_size = pcdev->pdata->meminfo.size; + + if (!request_mem_region(pcdev->vipmem_phybase,pcdev->vipmem_size,"rk29_vipmem")) { + err = -EBUSY; + goto exit_ioremap_vipmem; + } + pcdev->vipmem_virbase = ioremap_cached(pcdev->vipmem_phybase,pcdev->vipmem_size); + if (pcdev->vipmem_virbase == NULL) { + dev_err(pcdev->dev, "ioremap() of vip internal memory(Ex:IPP process/raw process) failed\n"); + err = -ENXIO; + goto exit_ioremap_vipmem; + } + RK29CAMERA_DG("\n%s Memory(start:0x%x size:0x%x) for IPP obtain \n",__FUNCTION__, pcdev->pdata->meminfo.start,pcdev->pdata->meminfo.size); } else { RK29CAMERA_TR("\n%s Memory for IPP have not obtain! IPP Function is fail\n",__FUNCTION__); pcdev->vipmem_phybase = 0; pcdev->vipmem_size = 0; + pcdev->vipmem_virbase = 0; } #endif INIT_LIST_HEAD(&pcdev->capture); @@ -2183,6 +2428,11 @@ static int rk29_camera_probe(struct platform_device *pdev) pcdev->fps_timer.function = rk29_camera_fps_func; pcdev->icd_cb.sensor_cb = NULL; +#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_IPP) + pcdev->icd_cb.scale_crop_cb = rk29_camera_scale_crop_ipp; +#elif (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_ARM) + pcdev->icd_cb.scale_crop_cb = rk29_camera_scale_crop_arm; +#endif RK29CAMERA_DG("%s..%s..%d \n",__FUNCTION__,__FILE__,__LINE__); return 0; @@ -2207,6 +2457,10 @@ static int rk29_camera_probe(struct platform_device *pdev) iounmap(pcdev->base); exit_ioremap: release_mem_region(res->start, res->end - res->start + 1); +exit_ioremap_vipmem: + if (pcdev->vipmem_virbase) + iounmap(pcdev->vipmem_virbase); + release_mem_region(pcdev->vipmem_phybase,pcdev->vipmem_size); exit_reqmem: if (pcdev->aclk_ddr_lcdc) { clk_put(pcdev->aclk_ddr_lcdc); @@ -2277,6 +2531,9 @@ static int __devexit rk29_camera_remove(struct platform_device *pdev) soc_camera_host_unregister(&pcdev->soc_host); + iounmap((void __iomem*)pcdev->vipmem_phybase); + release_mem_region(pcdev->vipmem_phybase, pcdev->vipmem_size); + res = pcdev->res; release_mem_region(res->start, res->end - res->start + 1); From 3fd8816a56e3ed45b8eb6799acd7cb2c49da29b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=99=B4?= Date: Fri, 17 Aug 2012 14:30:45 +0800 Subject: [PATCH 213/261] rk30:sdk:support wm8326 early suspend and modify dcdc or ldo mode when in early suspend --- arch/arm/mach-rk30/board-rk30-sdk-wm8326.c | 133 ++++++++++++++++++--- drivers/mfd/wm831x-core.c | 17 ++- drivers/regulator/wm831x-ldo.c | 2 +- 3 files changed, 135 insertions(+), 17 deletions(-) diff --git a/arch/arm/mach-rk30/board-rk30-sdk-wm8326.c b/arch/arm/mach-rk30/board-rk30-sdk-wm8326.c index fbba1ea0aeb3..ac7108154434 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk-wm8326.c +++ b/arch/arm/mach-rk30/board-rk30-sdk-wm8326.c @@ -5,6 +5,7 @@ #include #include +#include #define cru_readl(offset) readl_relaxed(RK30_CRU_BASE + offset) #define cru_writel(v, offset) do { writel_relaxed(v, RK30_CRU_BASE + offset); dsb(); } while (0) @@ -498,7 +499,8 @@ struct regulator_init_data wm831x_regulator_init_dcdc[WM831X_MAX_DCDC] = { .min_uV = 600000, .max_uV = 1800000, //0.6-1.8V .apply_uV = true, - .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST | REGULATOR_MODE_IDLE, }, .num_consumer_supplies = ARRAY_SIZE(dcdc1_consumers), .consumer_supplies = dcdc1_consumers, @@ -509,7 +511,8 @@ struct regulator_init_data wm831x_regulator_init_dcdc[WM831X_MAX_DCDC] = { .min_uV = 600000, .max_uV = 1800000, //0.6-1.8V .apply_uV = true, - .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST | REGULATOR_MODE_IDLE, }, .num_consumer_supplies = ARRAY_SIZE(dcdc2_consumers), .consumer_supplies = dcdc2_consumers, @@ -520,7 +523,8 @@ struct regulator_init_data wm831x_regulator_init_dcdc[WM831X_MAX_DCDC] = { .min_uV = 850000, .max_uV = 3400000, //0.85-3.4V .apply_uV = true, - .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST | REGULATOR_MODE_IDLE, }, .num_consumer_supplies = ARRAY_SIZE(dcdc3_consumers), .consumer_supplies = dcdc3_consumers, @@ -531,7 +535,8 @@ struct regulator_init_data wm831x_regulator_init_dcdc[WM831X_MAX_DCDC] = { .min_uV = 850000, .max_uV = 3400000, //0.85-3.4V .apply_uV = true, - .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST | REGULATOR_MODE_IDLE, }, .num_consumer_supplies = ARRAY_SIZE(dcdc4_consumers), .consumer_supplies = dcdc4_consumers, @@ -572,7 +577,8 @@ struct regulator_init_data wm831x_regulator_init_ldo[WM831X_MAX_LDO] = { .min_uV = 900000, .max_uV = 3300000, .apply_uV = true, - .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_IDLE | REGULATOR_MODE_NORMAL, }, .num_consumer_supplies = ARRAY_SIZE(ldo1_consumers), .consumer_supplies = ldo1_consumers, @@ -583,7 +589,8 @@ struct regulator_init_data wm831x_regulator_init_ldo[WM831X_MAX_LDO] = { .min_uV = 900000, .max_uV = 3300000, .apply_uV = true, - .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_IDLE | REGULATOR_MODE_NORMAL, }, .num_consumer_supplies = ARRAY_SIZE(ldo2_consumers), .consumer_supplies = ldo2_consumers, @@ -594,7 +601,8 @@ struct regulator_init_data wm831x_regulator_init_ldo[WM831X_MAX_LDO] = { .min_uV = 900000, .max_uV = 3300000, .apply_uV = true, - .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_IDLE | REGULATOR_MODE_NORMAL, }, .num_consumer_supplies = ARRAY_SIZE(ldo3_consumers), .consumer_supplies = ldo3_consumers, @@ -605,7 +613,8 @@ struct regulator_init_data wm831x_regulator_init_ldo[WM831X_MAX_LDO] = { .min_uV = 900000, .max_uV = 3300000, .apply_uV = true, - .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_IDLE | REGULATOR_MODE_NORMAL, }, .num_consumer_supplies = ARRAY_SIZE(ldo4_consumers), .consumer_supplies = ldo4_consumers, @@ -616,7 +625,8 @@ struct regulator_init_data wm831x_regulator_init_ldo[WM831X_MAX_LDO] = { .min_uV = 900000, .max_uV = 3300000, .apply_uV = true, - .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_IDLE | REGULATOR_MODE_NORMAL, }, .num_consumer_supplies = ARRAY_SIZE(ldo5_consumers), .consumer_supplies = ldo5_consumers, @@ -627,7 +637,8 @@ struct regulator_init_data wm831x_regulator_init_ldo[WM831X_MAX_LDO] = { .min_uV = 900000, .max_uV = 3300000, .apply_uV = true, - .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_IDLE | REGULATOR_MODE_NORMAL, }, .num_consumer_supplies = ARRAY_SIZE(ldo6_consumers), .consumer_supplies = ldo6_consumers, @@ -638,7 +649,8 @@ struct regulator_init_data wm831x_regulator_init_ldo[WM831X_MAX_LDO] = { .min_uV = 1000000, .max_uV = 3500000, .apply_uV = true, - .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_IDLE | REGULATOR_MODE_NORMAL, }, .num_consumer_supplies = ARRAY_SIZE(ldo7_consumers), .consumer_supplies = ldo7_consumers, @@ -649,7 +661,8 @@ struct regulator_init_data wm831x_regulator_init_ldo[WM831X_MAX_LDO] = { .min_uV = 1000000, .max_uV = 3500000, .apply_uV = true, - .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_IDLE | REGULATOR_MODE_NORMAL, }, .num_consumer_supplies = ARRAY_SIZE(ldo8_consumers), .consumer_supplies = ldo8_consumers, @@ -660,7 +673,8 @@ struct regulator_init_data wm831x_regulator_init_ldo[WM831X_MAX_LDO] = { .min_uV = 1000000, .max_uV = 3500000, .apply_uV = true, - .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_IDLE | REGULATOR_MODE_NORMAL, }, .num_consumer_supplies = ARRAY_SIZE(ldo9_consumers), .consumer_supplies = ldo9_consumers, @@ -671,7 +685,8 @@ struct regulator_init_data wm831x_regulator_init_ldo[WM831X_MAX_LDO] = { .min_uV = 1000000, .max_uV = 3500000, .apply_uV = true, - .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_IDLE | REGULATOR_MODE_NORMAL, }, .num_consumer_supplies = ARRAY_SIZE(ldo10_consumers), .consumer_supplies = ldo10_consumers, @@ -682,7 +697,8 @@ struct regulator_init_data wm831x_regulator_init_ldo[WM831X_MAX_LDO] = { .min_uV = 800000, .max_uV = 1550000, .apply_uV = true, - .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_IDLE | REGULATOR_MODE_NORMAL, }, .num_consumer_supplies = ARRAY_SIZE(ldo11_consumers), .consumer_supplies = ldo11_consumers, @@ -777,6 +793,93 @@ static int wm831x_init_pin_type(struct wm831x *wm831x) return 0; } +#ifdef CONFIG_HAS_EARLYSUSPEND +void wm831x_pmu_early_suspend(struct regulator_dev *rdev) +{ + struct regulator *dcdc; + struct regulator *ldo; + printk("%s\n", __func__); + + dcdc = regulator_get(NULL, "dcdc4"); //vcc_io + regulator_set_voltage(dcdc, 2800000, 2800000); + regulator_set_mode(dcdc, REGULATOR_MODE_STANDBY); + regulator_enable(dcdc); + printk("%s set dcdc4 vcc_io=%dmV end\n", __func__, regulator_get_voltage(dcdc)); + regulator_put(dcdc); + udelay(100); + + ldo = regulator_get(NULL, "ldo1"); // + regulator_set_mode(ldo, REGULATOR_MODE_IDLE); + regulator_enable(ldo); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "ldo4"); + regulator_set_mode(ldo, REGULATOR_MODE_IDLE); + regulator_enable(ldo); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "ldo6"); + regulator_set_mode(ldo, REGULATOR_MODE_IDLE); + regulator_enable(ldo); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "ldo8"); + regulator_set_mode(ldo, REGULATOR_MODE_IDLE); + regulator_enable(ldo); + regulator_put(ldo); + udelay(100); + +} +void wm831x_pmu_early_resume(struct regulator_dev *rdev) +{ + struct regulator *dcdc; + struct regulator *ldo; + printk("%s\n", __func__); + + dcdc = regulator_get(NULL, "dcdc4"); //vcc_io + regulator_set_voltage(dcdc, 3000000, 3000000); + regulator_set_mode(dcdc, REGULATOR_MODE_FAST); + regulator_enable(dcdc); + printk("%s set dcdc4 vcc_io=%dmV end\n", __func__, regulator_get_voltage(dcdc)); + regulator_put(dcdc); + udelay(100); + + ldo = regulator_get(NULL, "ldo1"); // + regulator_set_mode(ldo, REGULATOR_MODE_NORMAL); + regulator_enable(ldo); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "ldo4"); + regulator_set_mode(ldo, REGULATOR_MODE_NORMAL); + regulator_enable(ldo); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "ldo6"); + regulator_set_mode(ldo, REGULATOR_MODE_NORMAL); + regulator_enable(ldo); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "ldo8"); + regulator_set_mode(ldo, REGULATOR_MODE_NORMAL); + regulator_enable(ldo); + regulator_put(ldo); + udelay(100); +} +#else +void wm831x_pmu_early_suspend(struct regulator_dev *rdev) +{ +} +void wm831x_pmu_early_resume(struct regulator_dev *rdev) +{ +} +#endif + void __sramfunc board_pmu_wm8326_suspend(void) { cru_writel(CRU_CLKGATE5_GRFCLK_ON,CRU_CLKGATE5_CON_ADDR); //open grf clk diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 504314e87de1..6ff1849eba14 100755 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -29,6 +29,11 @@ #include #include +#include + +#ifdef CONFIG_HAS_EARLYSUSPEND +static struct early_suspend wm831x_early_suspend; +#endif /* Current settings - values are 2*2^(reg_val/4) microamps. These are * exported since they are used by multiple drivers. @@ -1465,6 +1470,10 @@ static struct mfd_cell backlight_devs[] = { /* * Instantiate the generic non-control parts of the device. */ + +__weak void wm831x_pmu_early_suspend(struct regulator_dev *rdev) {} +__weak void wm831x_pmu_early_resume(struct regulator_dev *rdev) {} + int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) { struct wm831x_pdata *pdata = wm831x->dev->platform_data; @@ -1729,7 +1738,13 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) goto err_irq; } } - + #ifdef CONFIG_HAS_EARLYSUSPEND + wm831x_early_suspend.level = 0xffff; + wm831x_early_suspend.suspend = wm831x_pmu_early_suspend; + wm831x_early_suspend.resume = wm831x_pmu_early_resume; + register_early_suspend(&wm831x_early_suspend); + #endif + return 0; err_irq: diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index a5fc30d8b3ca..aff55c8e08b0 100755 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -206,7 +206,7 @@ static int wm831x_gp_ldo_set_mode(struct regulator_dev *rdev, int on_reg = ldo->base + WM831X_LDO_ON_CONTROL; int ret; - printk("%s base=%x,mode=%x\n", __FUNCTION__,ldo->base,mode); +// printk("%s base=%x,mode=%x\n", __FUNCTION__,ldo->base,mode); switch (mode) { case REGULATOR_MODE_NORMAL: ret = wm831x_set_bits(wm831x, on_reg, From c4915c3f0f1f4b5a84fa761b16cc7a9c9055f0a1 Mon Sep 17 00:00:00 2001 From: Zheng Yang Date: Fri, 17 Aug 2012 14:33:23 +0800 Subject: [PATCH 214/261] rk2929 acodec: for internal audio codec, mclk = 64*bclk = 256*lrclk. --- sound/soc/rk29/rk2928-card.c | 31 +++---------------------------- 1 file changed, 3 insertions(+), 28 deletions(-) diff --git a/sound/soc/rk29/rk2928-card.c b/sound/soc/rk29/rk2928-card.c index 8d08942bd86d..412460cb4cdf 100755 --- a/sound/soc/rk29/rk2928-card.c +++ b/sound/soc/rk29/rk2928-card.c @@ -55,35 +55,10 @@ static int rk2928_dai_hw_params(struct snd_pcm_substream *substream, #endif if (ret < 0) return ret; - - switch(params_rate(params)) { - case 8000: - case 16000: - case 24000: - case 32000: - case 48000: - case 96000: - pll_out = 12288000; - break; - case 11025: - case 22050: - case 44100: - case 88200: - pll_out = 11289600; - break; - case 176400: - pll_out = 11289600*2; - break; - case 192000: - pll_out = 12288000*2; - break; - default: - DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params)); - return -EINVAL; - break; - } + DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params)); - + pll_out = 256 * params_rate(params); + #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0); #endif From 1c9e9080691b9ce4f7e8c42643fa026bb020c596 Mon Sep 17 00:00:00 2001 From: gwl Date: Fri, 17 Aug 2012 15:10:37 +0800 Subject: [PATCH 215/261] add usb wifi rtl8188eus support. --- drivers/net/wireless/Kconfig | 1 + drivers/net/wireless/Makefile | 1 + drivers/net/wireless/rtl8188eu/8188eu.uu | 13701 ++++++++++++++++ drivers/net/wireless/rtl8188eu/Kconfig | 8 + drivers/net/wireless/rtl8188eu/Makefile | 13 + drivers/net/wireless/rtl8188eu/wifi_power.c | 114 + drivers/net/wireless/rtl8188eu/wifi_power.h | 87 + .../net/wireless/rtl8188eu/wifi_power_ops.c | 112 + .../net/wireless/rtl8188eu/wifi_power_usb.c | 118 + drivers/net/wireless/rtl8188eu/wifi_version.h | 13 + .../net/wireless/wifi_sys/rkwifi_sys_iface.c | 9 +- 11 files changed, 14175 insertions(+), 2 deletions(-) create mode 100644 drivers/net/wireless/rtl8188eu/8188eu.uu create mode 100755 drivers/net/wireless/rtl8188eu/Kconfig create mode 100755 drivers/net/wireless/rtl8188eu/Makefile create mode 100644 drivers/net/wireless/rtl8188eu/wifi_power.c create mode 100644 drivers/net/wireless/rtl8188eu/wifi_power.h create mode 100644 drivers/net/wireless/rtl8188eu/wifi_power_ops.c create mode 100644 drivers/net/wireless/rtl8188eu/wifi_power_usb.c create mode 100755 drivers/net/wireless/rtl8188eu/wifi_version.h diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index e3abd49317a2..4f17933e371a 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -70,6 +70,7 @@ choice (4) Murata SP-8HEP-P source "drivers/net/wireless/rtl8192c/Kconfig" +source "drivers/net/wireless/rtl8188eu/Kconfig" source "drivers/net/wireless/ar6003/Kconfig" source "drivers/net/wireless/rkwifi/Kconfig" endchoice diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 82d98f770478..b3278607c1f8 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_BCM4329) += bcm4329/ obj-$(CONFIG_MV8686) += mv8686/ obj-$(CONFIG_BCM4319) += bcm4319/ obj-$(CONFIG_RTL8192CU) += rtl8192c/ +obj-$(CONFIG_RTL8188EUS) += rtl8188eu/ obj-$(CONFIG_AR6003) += ar6003/ obj-$(CONFIG_RKWIFI) += rkwifi/ #obj-m += wlan/ diff --git a/drivers/net/wireless/rtl8188eu/8188eu.uu b/drivers/net/wireless/rtl8188eu/8188eu.uu new file mode 100644 index 000000000000..66fb8fc7a83f --- /dev/null +++ b/drivers/net/wireless/rtl8188eu/8188eu.uu @@ -0,0 +1,13701 @@ +begin 644 8188eu.o +M?T5,1@$!`0````````````$`*``!```````````````05P8`````!30````` +M`"@`'P`<`![_+^$>_R_A1#"0Y>(C`^,"(-/G``!2XPP```H&+P+C`B#3YP`` +M4N,(```:L"#1X3D`4N,%```:!""1Y0`@DN4$`%+C`""@$P$@H`,#``#JL"#1 +MX3L`4N,`(*`3`2"@`^$;`^,!,-/G`S"2X0``H`,>_R\!0`#0Y0``4.(!`*`3 +M'O\OX3@PD.4!,(/B.#"`Y1[_+^$!`*#C'O\OX03@+>4,T$WB"""-XK(08N$_ +M$*#C9#L#XP_@H.$#\)#G#-"-X@"`O>@$X"WE#-!-X@@@C>(!$&+E-!"@XV0[ +M`^,/X*#A`_"0YPS0C>(`@+WH$$`MZ0%`H.$#`)'I_O__ZP0`H.$<$*#C_O__ +MZQ"`O>@00"WI`4"@X0,`D>G^___K!`"@X1P0H./^___K$("]Z!!`+>D`0*#A +ML##0X0X`4^,0`%,3`@``"@0`D.4($)3E_O__ZPP`E.4``%#C`P``"A`0E.4` +M`%'C````"O[__^L$`*#A'!"@X_[__^L0@+WH$$`MZ0$`H.'^___K$("]Z'!` +M+>D`0*#A`5"@X0Q@D>5;#8#B.`"`X@00D>7^___K``!0XQD```H`,-;EV#"` +MY=0P@.7^___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/E;#"4Y0$($^,"```* +M@``3XX`PPQ-L,(05;#"4Y0$P@^-L,(3E#2"@X7\]PN,_,,/C!""3Y0$@0N($ +M((/E_O__ZP4`H.'^___K<("]Z!!`+>D!0*#A6PV`XC@`@.(,$)'E_O__ZP0` +MH.'^___K$("]Z/!!+>D`4*#A`6"@X01`D>4",-'E``!3XP4```H`,`#C`#!` +MXP`0D^5%#H#B"`"`XO[__^M%#H7B"`"`XO[__^O^___K#2"@X7\]PN,_,,/C +M!""3Y0$@@N($((/E;#"5Y1``$^,/```*6WV%XCAPA^($0(3B!P"@X000H.'^ +M___K``!0XP0``!H'`*#A!!"@X?[__^L``%#C1P``"@4`H.'^___K1```ZFP` +MA>+^___K`'"@X?[__^L-(*#A?SW"XS\PP^,$()/E`2""X@0@@^4``%?C#@`` +M&H0`A>+^___K`'!0X@<``!H-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K +M+```ZO[__^L0`(?E`@``Z@<`H.&$$(7B_O__ZW0PU.5U(-3E`B2#X78PU.4# +M*(+A=S#4Y0,L@N%X((+B`"#$Y2(TH.$!,,3E(CB@X0(PQ.4B/*#A`S#$Y1P` +MA^($$*#A_O__ZW0PU.5U(-3E`B2#X78PU.4#*(+A=S#4Y0,L@N'<`(7B!!"@ +MX7@@@N+^___K;#"5Y8`PP^-L,(7E#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E +M_O__ZPT@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^L&`*#A_O__Z_"!O>@0 +M0"WI`4"@X0(PT>4#`%/C!@``&@`P`.,`,$#C`!"3Y44.@.((`(#B_O__ZP<` +M`.H``%/C!0``"@`P`.,`,$#C`!"3Y44.@.((`(#B_O__ZP0`H.'^___K$("] +MZ'!`+>D`4*#A`4"@X0(PT>4``%/C#@``"O[__^L-(*#A?SW"XS\PP^,$()/E +M`2""X@0@@^5L()7E`2""XVP@A>4$()/E`2!"X@0@@^7^___K<("]Z/[__^L$ +M`*#A_O__ZW"`O>@00"WI`4"@X0(PT>4#`%/C!@``&@`P`.,`,$#C`!"3Y4D. +M@.($`(#B_O__ZP<``.H``%/C!0``"@`P`.,`,$#C`!"3Y4D.@.($`(#B_O__ +MZP0`H.'^___K$("]Z!!`+>G^___K$("]Z#!`+>D,T$WB`$"@X6PPD.5``!/C +M+0``&B``$^,K```:!0!1XP'QGY7^___K!`"@ +MX2<0H.,%(*#A9#L#XP_@H.$#\)3G!@``ZO[__^N(,P/C`P"$YP0`H.'^___K +M````ZO[__^L,T(WB,("]Z/!'+>D`0*#A_O__ZVPPE.4!`!/C+0``"A`UE.5D +M`%/C!0``B@PEE.5D`%+C`&"@DP9PH)$&H*"1!P``F@PEE.4"`%/A`&"@DP%P +MH),'H*"1`6"@@P!PH(,&H*"!^@Y3XP4``(H,)93E^@Y2XP!0H),%@*"1!9"@ +MD0<``)H,)93E`@!3X0%0H),`@*"3!9"@D0!0H(,!@*"#")"@@10UE.4,)93E +M`B"#X`@`4N,$``"*`@!3XP(``(H$`*#A_O__ZPH``.H$`*#A_O__ZP<``.H$ +M`*#A_O__ZP!0H.,%@*#A!9"@X05@H.$%<*#A!:"@X0`PH.,0-83E##6$Y10U +MA.48I<3E&77$Y1IEQ.4;E<3E'(7$Y1U5Q.4$`*#A8#L#XP_@H.$#\)3G\(>] +MZ/!!+>D`4*#A`$!1X@0`H`/P@;T(`#"4Y0$P0^(+`%/C`_&?EU,``.JT!P`` +MU`@``-0(``#(!P``W`<``/P'```,"```'`@``"P(``#4"```Q`@``.P'```% +M`*#A"!"4Y00@E.7^___K0@``Z@4`H.$($)3E!""4Y?[__^L]``#J!0"@X000 +MU.7^___K.0``Z@4`H.&T$-3A_O__ZS4``.H%`*#A!!#4Y?[__^LQ``#J!0"@ +MX000U.7^___K+0``Z@4`H.$$$)3E_O__ZRD``.H%`*#A_O__ZP``4.,E```* +MS#"0Y0``4^,`8*`#%'0``V2`H`,%```*'@``Z@@`H.'^___K`6"&X@L`5N,9 +M```*!0"@X0<0H.'^___K_P3`X_\PT./T__\:"@!6XQ$``,J^.`'CLR"5X0$@ +MPN.S((7AO#@!X[,@E>$!(,+CLR"%X04`H.$%$*#C`""@XP(PH.'^___K`P`` +MZ@4`H.$^$*#C`""@X_[__^L(`)3E``!0XP4```H$$)3E``!1XP(``-K^___K +M``"@X_"!O>@``*#C\(&]Z'!`+>D`0*#A`%`/X8``#/$-(*#A?SW"XS\PP^,$ +M()/E`2""X@0@@^7^___K``!0XP!`H!,`,)0%%$!#`A@@E`44$)0%!""!!0`0 +M@@44,(0%&#"$!07P(>$-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^4`,)/E`@`3 +MXP````K^___K!`"@X7"`O>@00"WI&`"`XO[__^L0@+WH\$\MZ1303>(`4*#A +M!4N`XBB`A.(```#C``!`XP`0`.,`$$#C_O__ZP\`H./^___K3#0!XP,PE><$ +M,(WE`2"@XV@T`>,#(,7G-$"$X@A`C>4$`*#A_O__ZP"`C>4-(*#A?ZW"XS^@ +MRN,,H(WES&L#X]![`^,``)WE_O__ZP``4.-2```*!C"5YP$`4^-/```*!S"5 +MYP$`4^-,```*7)0!XP.PH.,&,)7G`0!3XT<```H',)7G`0!3XT0```H(`*#A +M_O__ZP!`4.+I__\*"`"@X000H.'^___K``!0XPLPH`$",,0%'@``"@DPE>4$$)3E_O__Z[`P +MU.$_`%/C!#"@@P(PQ(4-``"*`"``XP`@0..#,8+@!#"3Y0``4^,#```*!0"@ +MX000G>4S_R_A`@#$Y4@D`>,",-7G`3"#X@(PQ>>P,-3A/P!3XPP``(H`(`#C +M`"!`XX,Q@N#\,9/E``!3XP(``!H$`*#A_O__ZP4``.H%`*#A!!"@X3/_+^$! +M``#J!`"@X?[__^L,,)KE!#"3Y0`PD^4!`!/CN/__"@PPG>4,`)/E_O__Z[3_ +M_^H`(*#C:#0!XP,@Q><(`*#A_O__ZP``4.,!```*_O__Z_G__^H(`)WE_O__ +MZP``H.,`$*#A_O__ZQ!`+>D`,*#A``!1XQ4```H`0`_A@``,\0T`H.%_+<#C +M/R#"XP0`DN4!`(#B!`""Y10`@>(#$*#A_O__ZP3P(>$-(*#A?SW"XS\PP^,$ +M()/E`2!"X@0@@^4`,)/E`@`3XP````K^___K`0"@XQ"`O>AP0"WI`&"@X0!0 +M4>(`0*`##@``"@40H.'^___K`$!0X@(``!H%`*#A_O__ZP<``.H8`(;B!1"@ +MX?[__^L`0*#A`0!0XP$``!H&`*#A_O__ZP0`H.%P@+WH\$$MZ0!PH.$<`*#C +M_O__ZP!0H.$`0*#A``!0XP``H`/P@;T(#`"@X_[__^L`8*#A``!0XP0``!H% +M`*#A'!"@X_[__^L``*#C\(&]Z`L@H.,`((#E`%"@XP10@.4(4(#E%`"$XO[_ +M_^LY,*#CL##$X01@A.4,,*#C"#"$Y0Q0A.404(3E!0N'XB@`@.($$*#A_O__ +MZW``[^;P@;WH\$$MZ0!PH.$<`*#C_O__ZP!0H.$`0*#A``!0XP``H`/P@;T( +M#`"@X_[__^L`8*#A``!0XP0``!H%`*#A'!"@X_[__^L``*#C\(&]Z`D@H.,` +M((#E`%"@XP10@.4(4(#E%`"$XO[__^LY,*#CL##$X01@A.4,,*#C"#"$Y0Q0 +MA.404(3E!0N'XB@`@.($$*#A_O__ZW``[^;P@;WH\$$MZ0!PH.$<`*#C_O__ +MZP!0H.$`0*#A``!0XP``H`/P@;T(#`"@X_[__^L`8*#A``!0XP0``!H%`*#A +M'!"@X_[__^L``*#C\(&]Z`0@H.,`((#E`%"@XPA0@.44`(3B_O__ZSDPH..P +M,,3A!&"$Y0PPH.,(,(3E#%"$Y1!0A.4%"X?B*`"`X@00H.'^___K<`#OYO"! +MO>CP02WI`$"@X0%@H.$L.@/C`S"0YP``4^,!`*`#\(&]"!P`H./^___K`'"@ +MX0!0H.$``%#C``"@`_"!O0@,`*#C_O__ZP"`H.$``%#C!```&@<`H.$<$*#C +M_O__ZP``H./P@;WH"""@XT0`@.@`8*#C"&"`Y10`A^+^___K.3"@X[`PQ^$$ +M@(?E##"@XP@PA^4,8(?E$&"'Y04+A.(H`(#B!Q"@X?[__^MP`._F\(&]Z/!! +M+>D(T$WB`$"@X0%@H.$"4*#A"""-X@`PH.,!,&+E`1"@XVP[`^,/X*#A`_"0 +MYP4``%/C`0"@`RD```H!`%7C(P``&AP`H./^___K`'"@X0!0H.$``%#C +M``"@`R````H,`*#C_O__ZP"`H.$``%#C!```&@<`H.$<$*#C_O__ZP``H.,6 +M``#J!B"@XT0`@.@`8*#C"&"`Y10`A^+^___K.3"@X[`PQ^$$@(?E##"@XP@P +MA^4,8(?E$&"'Y04+A.(H`(#B!Q"@X?[__^MP`._F`P``Z@0`H.$&$*#A_O__ +MZP$`H.,(T(WB\(&]Z/!'+>D`H*#A`8"@X1P`H./^___K`%"@X0!`H.$``%#C +M``"@`_"'O0@,`*#C_O__ZP!@H.$``%#C!```&@4`H.$<$*#C_O__ZP``H./P +MA[WH#'"@XX`!@.@`4*#C"%"`Y10`A.+^___K.3"@X[`PQ.'``(3I#%"$Y1!0 +MA.4%"XKB*`"`X@00H.'^___K<`#OYO"'O>CP02WI`%"@X0%@H.$``%+C(P`` +M"AP`H./^___K`'"@X0!`H.$``%#C``"@`_"!O0@,`*#C_O__ZP"`H.$``%#C +M!```&@<`H.$<$*#C_O__ZP``H./P@;WH!2"@XT0`@.@`8*#C"&"`Y10`A^+^ +M___K.3"@X[`PQ^$$@(?E##"@XP@PA^4,8(?E$&"'Y04+A>(H`(#B!Q"@X?[_ +M_^MP`._F\(&]Z/[__^L!`*#C\(&]Z/!!+>D`@*#A`7"@X1P`H./^___K`%"@ +MX0!`H.$``%#C``"@`_"!O0@!`*#C_O__ZP!@H.$``%#C!```&@4`H.$<$*#C +M_O__ZP``H./P@;WH`'#`Y10`A>+^___K/3"@X[`PQ>$$8(7E`3"@XP@PA>4` +M,*#C##"%Y1`PA>4%"XCB*`"`X@40H.'^___K<`#OYO"!O>CP02WI`("@X0%P +MH.$<`*#C_O__ZP!0H.$`0*#A``!0XP``H`/P@;T(!`"@X_[__^L`8*#A``!0 +MXP0``!H%`*#A'!"@X_[__^L``*#C\(&]Z`!P@.44`(7B_O__ZSPPH..P,,7A +M!&"%Y00PH.,(,(7E`#"@XPPPA>40,(7E!0N(XB@`@.(%$*#A_O__ZW``[^;P +M@;WH\$$MZ0!PH.$!0*#A`E"@X7\`4>-``%$3*P``B@$`H./^___K`&"@X0`` +M4.,F```*`$#`Y0``5>,8```*'`"@X_[__^L`4%#B!```&@8`H.$!$*#C_O__ +MZP!0H.,;``#J%`"%XO[__^L[,*#CL##%X01@A>4!,*#C"#"%Y0`PH.,,,(7E +M$#"%Y04+A^(H`(#B!1"@X?[__^MP4._F!P``Z@<`H.$&$*#A_O__ZP%0<.(` +M4*`S!@"@X0$0H./^___K`0!5XU9%QP4```#J`%"@XP4`H.'P@;WH\$$MZ0!P +MH.$<`*#C_O__ZP!0H.$`0*#A``!0XP``H`/P@;T(#`"@X_[__^L`8*#A``!0 +MXP0``!H%`*#A'!"@X_[__^L``*#C\(&]Z`$@H.,`((#E`%"@XP10@.4(4(#E +M%`"$XO[__^LY,*#CL##$X01@A.4,,*#C"#"$Y0Q0A.404(3E!0N'XB@`@.($ +M$*#A_O__ZW``[^;P@;WH\$+^___K+3"@X[`PQ>$$8(7E +M##"@XP@PA>4`,*#C##"%Y1`PA>4%"XKB*`"`X@40H.'^___K<`#OYO"'O>CP +M1RWI`("@X0%PH.$<`*#C_O__ZP!0H.$`0*#A``!0XP``H`/PA[T(!@"@X_[_ +M_^L`8*#A`*"@X0``4.,$```:!0"@X1P0H./^___K``"@X_"'O>@$`*#C_O__ +MZP"04.('```:!0"@X1P0H./^___K!@"@X080H./^___K``"@X_"'O>@4`(7B +M_O__ZQ8PH..P,,7A!&"%Y08@H.,(((7E#)"%Y00PH.,0,(7E!@"@X0<0H.'^ +M___K!0N(XB@`@.(%$*#A_O__ZW``[^;PA[WH\$]"`0`H./^___K`&"@X0"@H.$``%#C!``` +M&@4`H.$<$*#C_O__ZP``H./PA[WH%`"%XO[__^LG,*#CL##%X01@A>4$,*#C +M"#"%Y0QPA>4T,*#C$#"%Y0`PH.,`,(;E!0N(XB@`@.(%$*#A_O__ZW``[^;P +MA[WH\$]"#0` +MH./^___K`&"@X0"@H.$``%#C!```&@4`H.$<$*#C_O__ZP``H./PA[WH%`"% +MXO[__^LF,*#CL##%X01@A>4T(*#C"""%Y0`PH.,,,(7E$#"%Y08`H.$'$*#A +M_O__ZP4+B.(H`(#B!1"@X?[__^MP`._F\(>]Z/A/+>D`@*#A`9"@X0)PH.$` +M`%/C`P``&@(0H.'^___K`0"@X_B/O>@<`*#C_O__ZP!0H.$`0*#A``!0XP`` +MH`/XC[T(&`"@X_[__^L`8*#A`*"@X0``4.,$```:!0"@X1P0H./^___K``"@ +MX_B/O>@(`*#C_O__ZP"P4.('```:!0"@X1P0H./^___K!@"@X1@0H./^___K +M``"@X_B/O>@4`(7B_O__ZQ4PH..P,,7A!&"%Y1@PH.,(,(7E#+"%Y0@PH.,0 +M,(7E!@"@X>`0B>(&(*#C_O__ZP`PH.,&,,;E!W#&Y04+B.(H`(#B!1"@X?[_ +M_^MP`._F^(^]Z/A/+>D`4*#A`:"@X0*0H.$<`*#C_O__ZP!@H.$`0*#A``!0 +MXP``H`/XC[T(&`"@X_[__^L`<*#A`("@X0``4.,$```:!@"@X1P0H./^___K +M``"@X_B/O>@(`*#C_O__ZP"P4.('```:!@"@X1P0H./^___K!P"@X1@0H./^ +M___K``"@X_B/O>@*8*#A%`"$XO[__^L5,*#CL##$X01PA.48,*#C"#"$Y0RP +MA.4(,*#C$#"$Y0<`H.'@$(KB!B"@X_[__^ML,)7E"``3X\PX`1,#,)47!C#' +M%0X``!K(.`'C`S"5YP,`4^,#\9^7"0``ZF08``!D&```=!@``&08``#,.`'C +M`S"5YP8PQ^4!``#J[#":Y08PQ^4!`%GC"`"(`A$>A@(H.0$3`Q"5%P$2A1`( +M`(@2&1R!$BP0@1(0(*#C_O__ZP$@H.,A/`'C`R#%YP4+A>(H`(#B!!"@X?[_ +M_^MP`._F^(^]Z/!'+>D`@*#A`7"@X1P`H./^___K`%"@X0!`H.$``%#C``"@ +M`_"'O0@$`*#C_O__ZP!@H.$`H*#A``!0XP0``!H%`*#A'!"@X_[__^L``*#C +M\(>]Z!0`A>+^___K$3"@X[`PQ>$$8(7E!#"@XP@PA>4`,*#C##"%Y1`PA>4` +M<,;E!0N(XB@`@.(%$*#A_O__ZW``[^;PA[WH\$$MZ0!PH.$<`*#C_O__ZP!@ +MH.$`0*#A``!0XP``H`/P@;T(!`"@X_[__^L`4%#B!```&@8`H.$<$*#C_O__ +MZP``H./P@;WH%`"&XO[__^L/,*#CL##&X010AN4$,*#C"#"&Y0`PH.,,,(;E +M$#"&Y04+A^(H`(#B!A"@X?[__^MP`._F\(&]Z/!%+>D,T$WB`$"@X0%0H.%X +M8)'EY#8#XP,PD.<``%/C`0``"@@0H.,S_R_A'`"@X_[__^L`<*#A``!0XW@` +M``IL,)3E*``3XP8``!H``%;C(#"#`VPPA`4"```*`0!6XP@P@P-L,(0%!VN$ +MXCA@AN(``%;C`P``&AP0H./^___K``"@XV8``.H&`*#A`!"@X]XOH./^___K +MD""5Y08`H.$<$(7B>"""XO[__^NL/`'C`R"4YR0U`N,#(,3G#"!"XOX`4N,E +M#(3B)0"`XG(=A.(\$('B_R"@@_[__^L`(*#CK#P!XP,@A.>,-)3E`@!3X0,` +M`!JX`(3B(!"%X@8@H./^___KE*"%XG*-A.(P@(CB!`"@X0H0H.$((*#AD#"5 +MY?[__^NL/`'C`P"$YP`PH./,-(3E>SL"XP,PU.<``%/C#0``"I`PE>4``(WE +M!`"@X0H0H.$((*#A_O__ZZP\`>,#,)3G``!3X:P\`1,#`(07`3"@$P`PH`/, +M-(3E`#"@X]@TA.7Z/@+C`S#4YP``4^,.```*S#@!XP,PE.5R+83B+"""X@`@C>4$`*#A"A"@X0@@H.'^___K"@"@ +MX9`0E>7^___KR@O$Y:P\`>,#,)3G>#"#X@@PA^44`(?B_O__ZPXPH..P,,?A +M!&"'Y0`PH.,,,(?E$#"'Y04+A.(H`(#B!Q"@X?[__^MP`._F#-"-XO"%O>CP +M02WI`'"@X0%0H.$"8*#A'`"@X_[__^L`0%#B\(&]"!0`A.+^___K$#"@X[`P +MQ.%@`(3I`#"@XPPPA.40,(3E!0N'XB@`@.($$*#A_O__ZW``[^;P@;WH<$`M +MZ0!`H.'D-@/C`S"0YP``4^,!```*"!"@XS/_+^$<`*#C_O__ZP!04.)P@+T( +M%`"%XO[__^L0,*#CL##%X:X]A.(",(/B!#"%Y?8[`N.S,)3A^"L"X[(@E.$" +M.(/A>#"#X@@PA>4`(*#C#""%Y1`@A>6"*P+CLC"$X2,XH.&$*P+CLC"$X04+ +MA.(H`(#B!1"@X?[__^MP`._F<("]Z/!'+>D`H*#A`8"@X0)PH.$<`*#C_O__ +MZP!0H.$`0*#A``!0XP``H`/PA[T(`0"@X_[__^L`8*#A`)"@X0``4.,$```: +M!0"@X1P0H./^___K``"@X_"'O>@4`(7B_O__ZP0PH..P,,7A!&"%Y0$@H.,( +M((7E#'"%Y1`PA>4`@,;E!0N*XB@`@.(%$*#A_O__ZW``[^;PA[WH\$]Z!0`A>+^___K +M!3"@X[`PQ>$$8(7E"#"@XP@PA>4`,*#C##"%Y1`PA>4`!8;H!0N)XB@`@.(% +M$*#A_O__ZW``[^;PA[WH\$]Z!0`A>+^___K`C"@X[`PQ>$$8(7E`3"@XP@PA>4,<(7E +M$#"%Y0"`QN4%"XKB*`"`X@40H.'^___K<`#OYO"'O>CP1RWI`)"@X0&`H.$" +MH*#A'`"@X_[__^L`4*#A`$"@X0``4.,``*`#\(>]"`(`H./^___K`&"@X0!P +MH.$``%#C!```&@4`H.$<$*#C_O__ZP``H./PA[WH%`"%XO[__^L#,*#CL##% +MX01@A>4",*#C"#"%Y0`PH.,,,(7E$#"%Y0"`QN4!H,;E!0N)XB@`@.(%$*#A +M_O__ZW``[^;PA[WH\$]Z!0`A>+^___K'S"@X[`PQ>$$8(7E`C"@XP@PA>4`,*#C##"% +MY1`PA>4!@,;E`*#&Y04+B>(H`(#B!1"@X?[__^MP`._F\(>]Z/!'+>D`@*#A +M`7"@X1P`H./^___K`%"@X0!`H.$``%#C``"@`_"'O0@-`*#C_O__ZP!@H.$` +MH*#A``!0XP0``!H%`*#A'!"@X_[__^L``*#C\(>]Z!0`A>+^___K&3"@X[`P +MQ>$$8(7E#2"@XP@@A>4`,*#C##"%Y1`PA>4&`*#A!Q"@X?[__^L%"XCB*`"` +MX@40H.'^___K<`#OYO"'O>CP1RWI`("@X0%PH.$<`*#C_O__ZP!0H.$`0*#A +M``!0XP``H`/PA[T(#@"@X_[__^L`8*#A`*"@X0``4.,$```:!0"@X1P0H./^ +M___K``"@X_"'O>@4`(7B_O__ZQLPH..P,,7A!&"%Y0XPH.,(,(7E`#"@XPPP +MA>40,(7E!@"@X04PH.,!,,#D!Q"@X0T@H./^___K!0N(XB@`@.(%$*#A_O__ +MZW``[^;PA[WH^$\MZ0!PH.$!8*#A`H"@X0`0H.,!(*#C_O__ZP<`H.$"$*#C +M`2"@X_[__^L<`*#C_O__ZP!`H.$`H*#A``!0XUD```I3#Z#C_O__ZP!0H.$` +MD*#A``!0XP0``!H$`*#A'!"@X_[__^L`0*#C3@``Z@<`H.$`$*#C_O__ZQ0` +MA.+^___K$C"@X[`PQ.$$4(3E4S^@XP@PA.4`$*#C#!"$Y1`0A.4P,*#C!#"% +MY5@UE^4(,(GD"0"@X5$OH./^___K``!6XQ0```H``%CC$@``V@!`H.,$4*#A +M)+"@XP00AN`$,);G``!3XP(```H$`(G@"R"@X?[__^L!4(7B)$"$X@4`6.$` +M,*#3`3"@PP@`5>,`,*##``!3X^___QIL,)?E`CN#XVPPA^4!,*#C<##'Y04+ +MA^(H`(#B"A"@X?[__^MP0._F`0!4XQ(``!K^___KR`2'Y0`P`.,`,$#C`!"3 +MY4D.A^($`(#B,AZ!XO[__^OD-@/C`S"7YP``4^,"```*!P"@X080H.,S_R_A +M'C"@XU0TA^4$``#J;#"7Y0([P^-L,(?E`#"@XW`PQ^4$`*#A^(^]Z/!!+>D` +M@*#A`7"@X1P`H./^___K`%"@X0!`H.$``%#C``"@`_"!O0@$`*#C_O__ZP!@ +MH.$``%#C!```&@4`H.$<$*#C_O__ZP``H./P@;WH`'"`Y10`A>+^___K*S"@ +MX[`PQ>$$8(7E!#"@XP@PA>4`,*#C##"%Y1`PA>4%"XCB*`"`X@40H.'^___K +M<`#OYO"!O>@00"WI`$!0XA"`O0@@`(3B_O__ZP0`H.'^___K#`"$XO[__^LH +M`)3E``!0XP$```H&'*#C_O__ZS``E.4``%#C$("]"($?H./^___K$("]Z!!` +M+>G^___K$("]Z!!`+>D`0*#A`!"@X_[__^L`,*#C##"$Y0$`H.,0@+WH$$`M +MZ?[__^L0@+WH$$`MZ0!`H.$`$*#C_O__ZPP`A.(`$*#C_O__ZQ@`A.+^___K +M`3"@XR`PQ.4&#*#C_O__ZR@`A.4``%#C$0``"G\/P.,#`,#C`@R`XB0`A.6! +M#Z#C_O__ZS``A.4``%#C"```"@,`P.,$`(#B+`"$Y0`PH.,\,(3E.#"$Y30P +MA.4!`*#C$("]Z```H.,0@+WH$$`MZ?[__^L0@+WH\`4MZ0`PH.,`,(#E!#"` +MY0#`H.$`0*#A"##$Y0$P@^(!0(3B`0Q3X_K__QH!K(SB`$"@XP0PH.$(@*#C +M"&#4`8,7E"'#,Y0$P@^(" +M`%/A`#"@(P'`C.(*`%SA[___&O`%O>@>_R_A\`\MZ0&PH.$``%/C&@``"@`0 +MH.,(0*#C`9#2YP"@D.4!H(KB_Z`*X@I@@.`$8(;@`,#6Y02`D.4(@(S@_X`( +MX@AP@.`$<(?@`%#7Y0"@@.4$@(#E`,#'Y0!0QN4,P(7@?,#@Y@3`W.<,D"G@ +M`9#+YP$0@>(#`%'AYO__&O`/O>@>_R_AH!"@X0@0`>*`$X'AH#&@X:`3@>$$ +M,`/BH"*@X0,P@>$"(`+B@!*@X0(P@^%`$`'B@"&@X0$P@^$@(`+B@`"@X0(P +M@^$0``#B``"#X7``[^8>_R_A\$\MZ1303>(`L*#A!!"-Y0`P`.,`,$#C`#"3 +MY0``4^,D```:Y$"?Y0!0H.,(D*#CMVT!X\%D0.-U`._FVO__ZP`,H.$),*#A +M``!0XX``)K"``*"A`3!3XOK__QH@>*#A((2@X0"@H.$@#*#ASO__ZP``Q.5W +M`._FR___ZP$`Q.5X`._FR/__ZP(`Q.5Z`._FQ?__ZP,`Q.4!4(7B!$"$X@$, +M5>/C__\:`#``XP`P0.,!(*#C`""#Y00PG>4``%/C``#@TPX``-H$0)WE`#"@ +MXP``X.,`P`#C`,!`XP00H.,#(-OG`B`@X/\@`N("(8S@`2"2YR`$(N`!,(/B +M!`!3X?;__QH``.#A%-"-XO"/O>@$`````""@XP(PH.$#P-#G@Q&@X1PA@N$! +M,(/B!`!3X_G__QH"`*#A'O\OX0`0P.4A-*#A`3#@Y2$XH.$!,.#E(1R@X0$0 +MP.4>_R_A`#"0Y0@P@.4$,)#E##"`Y0`PH.,4,(#E$#"`Y1[_+^%P0"WI`$"@ +MX0%0H.$!`*#AX/__ZP``A.4$`(7BW?__ZP0`A.4$`*#A[/__ZW"`O>@4,)#E +M@\&@X1`@D.41+(+A$""`Y0$P@^(4,(#E`P!3XQ[_+Y$(P)#E#"`BX`P0D.7B +M%R'@`B"!X/_$PN/_S,SC_SC"XR,TH.$,-(/A`3`CX`(@@^#B/B/@`B"#X&(Q +M(^`,,(#E`B"#X`@@@.4`,*#C$#"`Y10P@.4>_R_A\$$MZ0!PH.$!8*#A`%!2 +MXO"!O0@`0*#C!P"@X000UN?^___K`4"$X@4`5.'Y__\:\(&]Z'!`+>D`0*#A +M`6"@X5H0H./^___K!`"@X0`0H./^___K!`"@X0`0H./^___K!`"@X0`0H./^ +M___K!`"@X0`0H./^___K%#"4Y0``4^,&```*`%"@XP0`H.$%$*#A_O__ZQ0P +ME.4``%/C^?__&@8`H.$($)3EF?__ZP0`AN(,$)3EEO__ZP0`H.&<___K<("] +MZ/!`+>DDT$WB`,"@X0%`H.$"8*#A`W"@X3Q0W>4`,*#C!##-Y04PS>4&,,WE +M!S#-Y0@`C>(,$*#A_O__ZP10S>4$4*#A`3#UY0$`$^,+```*"`"-XA`0A.(& +M(*#C_O__ZP`PU>4"`!/C"`"-XA@0A!(*$(0"!B"@X_[__^L*``#J"`"-X@00 +MA.(&(*#C_O__ZP`PU>4"`!/C"`"-XA`0A!(*$(0"!B"@X_[__^L(0(WB!`"@ +MX000C>($(*#C_O__ZP0`H.$&$*#A!R"@X?[__^L$`*#A.!"=Y?[__^LDT(WB +M\("]Z/`/+>D(T$WBL##`X0"@H.$C.*#ALC#JX0"`H.$!P-+E`##2Y0PT@^&T +M,.CA`'"@X0/`TN4",-+E##2#X;8PY^$`0*#A!<#2Y00PTN4,-(/AN##DX0`@ +MH.,`,`#C`#!`X[!0U.$!P`+BC)"@X0E@@>`$8(WE`Y0&0B>()D('@`)"- +MY0"PV>4+M*#A!9`FX`N0*>`IE*#A`9R)XHF0@^`%8";@=F#OYH9@@^"P4-GA +MLX090)>"P8-#A!E"%X'50_^:P4,#A`I",XHF0H.$!8*#A"9#VYP%@UN4& +M9*#A"6`FX`5@)N`F9*#A`6R&XH9@@^`%D"G@>9#OYHF0@^"P4-;AL X090 +M)>"P8-KA!E"%X'50_^:P4,KA!)",XHF0H.$!8*#A"9#VYP%@UN4&9*#A"6`F +MX`5@)N`F9*#A`6R&XH9@@^`%D"G@>9#OYHF0@^"P4-;AL X090)>"P8-CA +M!E"%X'50_^:P4,CA!L",XHS`H.$!8*#A#,#VYP%@UN4&9*#A#&`FX`5@)N`F +M9*#A`6R&XH9@@^`%4"S@=5#OYH50@^"PP-;AL%#5X07`+."P4-?A!<",X'S` +M_^:PP,?A!)"=Y0!0V>4`L)WE`&#;Y09DH.&PD-3A!6`FX`Q@)N`F9*#A`6R& +MXH9@@^`,4"7@=5#OYH50@^"PP-;ALX0E0@N`&P"S@#,"%X+#`Q.$!((+B +M"`!2XX___QH(T(WB\`^]Z![_+^'P#RWI$-!-X@#`H.,$0(WBO%"2X;Q0A.$" +MP(SB"@!&P0-3A!(`H +MX+1`W>$$@(C@>(#_Y@)`T>4#4-'E!52@X010)>`(4"7@)52@X0%*%4(+@ +M"$`DX'1`[^:$0(+@L'#5X;!`U.$$<"?@MD#=X01PA^!W4% +M5*#A!%`EX`=0)>`E5*#A`5R%XH50@N`'0"3@=$#OYH1`@N"P8-7AL$#4X01@ +M)N"X0-WA!&"&X'9@_^8&0-'E!U#1Y054H.$$4"7@!E`EX"54H.$!7(7BA5"" +MX`9`).!T0._FA$""X+!0U>&P0-3A!%`EX+I`W>$$4(7@=5#_Y@A`T>4)D-'E +M"92@X020*>`%D"G@*92@X0&*)D(+@!;`DX'NP[^:+L(+@L$#9X;"0V^$) +M0"3@O)#=X0E`A.!T0/_F"K#1Y0N0T>4)E*#A"Y`IX`20*>`IE*#A`9R)XHF0 +M@N`$L"O@>[#OYHNP@N"P(-GAL)#;X0D@(N`"H(K@>J#_Y@V0T>4,(-'E"22" +MX0H@(N""EZ#AHB")X0*`B.!X(/_FM"#-X0^0T>4.@-'E"82(X0*`*."()Z#A +MJ(""X0APA^!W&E(*#AA54"-(/A"J`C +MX,J@H.$#H,#E`#"@XP00C>*S()'A!"#`Y2(DH.$%(,#E`C"#X@(`@.(,`%/C +M]___&A#0C>+P#[WH'O\OX01`+>4`,*#C`T#1YP/`T.<,P"3@`\#"YP$P@^(0 +M`%/C^/__&A``O>@>_R_A!$`MY0`PH.,#0-'G`\#0YPS`).`#P,+G`3"#X@0` +M4^/X__\:$`"]Z![_+^$`,`#C`#!`XP`P@^``!-/E'O\OX7!`+>D0T$WB`$"@ +MX0%0H.$-,*#AH""?Y0<`DN@'`(/H#0#4Y?#__^L,`,WE#@#4Y>W__^L-`,WE +M#P#4Y>K__^L.`,WE!&"@X0P`]N7F___K#P#-Y1`PC>(%4(/@$%!5Y00`H.$, +M$(WB!""@X=/__^L`,-3E`S`EX`10H.$$,,7D!0"@X000H.$%(*#AR___ZPA` +MA.($`*#A!1"@X00@H.'&___K!@"@X000H.$&(*#APO__ZQ#0C>)P@+WH``4` +M`'!`+>D`4*#A`6"@X0!`H.,$`-7GQ/__ZP0`QN4%,-#E`3#!Y0HPT.4",,'E#S#0Y0,PP>4$,-#E!##!Y0DPT.4% +M,,'E#C#0Y08PP>4#,-#E!S#!Y0@PT.4(,,'E#3#0Y0DPP>4",-#E"C#!Y0

4!,-#E#3#!Y08PT.4.,,'E"S#0Y0\PP>4>_R_A\$`M +MZ2303>(`0*#A`7"@X0`PH.,<`(WB`\"@X1O@H./3$)3A``!1XP/@P+<#P,"G +M`3"#X@0`4^/X__\:`B#4Y1`@S>4#,-3E$3#-Y000H.$!`-'D$@#-Y0`0T>43 +M$,WE%##-Y14`S>46$,WE%R#-Y7\``.(,`,WE?Q`!X@T0S>5_(`+B#B#-Y7\P +M`^(/,,WE##"-X@,`0^(#(-/E@B"@X7(@[^8#(,/ETA#3X0``4>,!((*S`R## +MM0$P0^(``%/A]/__&@PPW>6#,*#A###-Y1A0C>(<`(WB#!"-X@4@H.%:___K +M"&"-X@0`H.$%$*#A!B"@X57__^L(,-WE!##-Y0D@W>4((,WE"B#=Y0D@S>4+ +M(-WE"B#-Y0LPS>4$0(WB!0"@X080H.$$(*#A1___ZPU0H.$0`(WB%!"-X@T@ +MH.%"___K!`"@X0T0H.$'(*#A/O__ZR30C>+P@+WH\$\MZ4S03>(4$(WE`H"@ +MX0`PH.,8$(WB`R#0YP,@P>(HD(WB +M!+")X@0PA^(`,(WE"#")X@0PC>4(,(?B"#"-Y0PPB>(,,(WE##"'XA`PC>48 +MH(WB!%"@X0$``.H!4(7B`6"&X@5`H.$``%7C!P``&@H`H.$4$)WE"""@X0O_ +M_^L*`*#A`!"@XR/__^OR___J"@!5XPP``!HX4(WB"`"@X040H.%,___K*$"- +MX@4`H.$$$*#A4___ZP0`H.$8$(WB"""@X?G^_^L9``#J"`"@X0<0H.%`___K +M!P"@X0D0H.%(___K"0"@X0<0H.%F___K"P"@X0`0G>5C___K`P"=Z6'__^L, +M`)WE$!"=Y5[__^L'`*#A"A"@X0@@H.'C_O_K"@"@X040H.'[_O_K"@!6X\G_ +M_]I,T(WB\(^]Z/``+>D00)WE%,"=Y5E0H.,`4,#E`5"@X0)PH.$`8%'B`6"@ +M$P``4N,``%$3'B#3%0\@`A(!(,`5``!7XP!@H!,!8`8"``!6XQ@@TQ4/(`(2 +M`2#`%0``4>,`(*`#`2#`!0(@H.,*$-/E`A#`YP$@@N(!,(/B"`!2X_G__QH% +M,*#C`Q#_R_A\``MZ0#`H.,,0*#A#$#`YP'`C.(0`%SC^___&A#` +MT>4`P,#E$<#1Y0'`P.42P-'E`L#`Y1/`T>4#P,#E%,#1Y03`P.45P-'E!<#` +MY0#`H.,&P,#E!\#`Y0QP4N`!<*`3#`!3X0#`H!,!P`<"``!,-'E#S`# +MX@XPP.4`,*#C#S#`Y?``O>@>_R_A<``MZ0Q0G>408)WE`,"@XPQ`H.$,0,#G +M`<",XA``7./[__\:`<"@XP#`P.4`P%+B`<"@$P``4>,``%(3'B#3%0\@`A(! +M(,`5``!1XP`0H!,!$`P"``!1XQ@@TQ4/(`(2`2#`%0(@H.,*$-/E`A#`YP$@ +M@N(!,(/B"`!2X_G__QH%,*#C`Q#5YP(0P.<#P-#G +M#,`DX`/`PN4"`%/C`0"@$U0``!I`H('B6PV&XC@` +M@.(*$*#A_O__ZP``4.-,```*1C#4Y0$`$^-5<-05!V*&$!E\AA(L<(<2$7Z` +M`B$PU.4#((7@,!#4Y0,`@>``4(7@=&"4Y09@8^`&8&'@`C#2Y0!`H.,30,?G +M`##2Y1-$S^<$,-+E$TC7YP4PTN433-_G!A#2Y0`PH.,1,,?G!R#2Y1(TS^<1 +MCHWB),B@X0@`H.$'$*#A"B"@X0,XC.&7_/_K$JZ-X@H`H.$'$*#A"""@X70P +M_^8<_?_K!$"-X@0`H.$*$*#A$""@XT'[_^L$`*#A!1"@X04@H.$&,*#A7?O_ +MZP4`H.$$$$;BD/O_ZPP!C>4&,(7@`3!3Y2`,4^$0```:!C"%X`XAW>4",%/E +M`P!2X0L``!H&,(7@#2'=Y0,P4^4#`%+A!@``&@90A>`,`=WE!#!5Y0,`4.$` +M`*`3`0"@`P```.H``*#C3=^-XO"%O>CP3RWI3]]-X@"PH.$!8*#A;%"1Y0`` +M5>-]```*=8#1Y1TPT>4"`%/C>P``&EP`D>4``%#C!0``&EL-B^(X`(#B1A"! +MXO[__^L``%#C<```"D8PUN4!`!/C*#D!$P,PFQ<#,HL0&3R#$BPP@Q(`,(T5 +M$0Z``@``C05XD*_F!)")XHF1H.%YD._F"9"%X$`@AN($((WE`*"@XUD``.JR +M(=;A`C")X!Z`UN4"@(C@"(")X`(@T^420,?G`"#3Y1)$S^<$(-/E$DC7YP4@ +MT^423-_G!B#3Y1)PQ^<',-/E$W3/YR0XH.%&#XWB!@"=Z`5&+XWB=##_YK3\_^L!H(KB'##6Y0,`6N$9```:LC'6X1A0EN4%4&/@ +M'C#6Y0508^`?,-;E!5!CX`@`H.$%$*#A)_O_ZQ0!C>4,`(WB2A^-XA`@H./+ +M^O_K#`"-X@@0H.$((*#A!3"@X>?Z_^L,`(WB!1"(X$4OC>($,*#CXOK_ZR`` +M`.JR,=;A-"4!XP)0F^<%4&/@'C#6Y0508^`?,-;E!5!CX`@`H.$%$*#A#/O_ +MZQ0!C>4,`(WB2A^-XA`@H..P^O_K#`"-X@@0H.$((*#A!3"@X($,*#CQ_K_ZS0E`>,",)OG`Y")X`,P&>(!,*`3*9&#X`F1H.$< +M,-;E`P!:X:+__[H!``#J``"@XP```.H!`*#C3]^-XO"/O>CP3RWIK-!-X@"0 +MH.$<$(WE#""-Y2`PC>6P0-+A_$`$XI``C>(`$*#C$""@X_[__^N``(WB`!"@ +MXQ`@H./^___K<`"-X@`0H.,0(*#C_O__ZV``C>(`$*#C$""@X_[__^M0`(WB +M`!"@XQ`@H./^___K0`"-X@`0H.,0(*#C_O__ZS``C>(`$*#C$""@X_[__^L< +M`)WE&@!0XQ@`4!,`(*`3`2"@`P$@(N)R(._F)#*@X0@P0^(#`%/C``"@@P4` +M`(H<$)WE&@!1XQPPG14",(,2'#"-%0$`H.,,,)WE',"=Y0P0\^>@$,WE`1#3 +MY:$0S>4$$-/EHA#-Y040T^6C$,WE!A#3Y:00S>4',-/EI3#-Y10`C>40((WE +MD$"-XB``G>4``(WEH#"-X@0PC>4$`*#A%!"=Y0PPG>7S_?_K@&"-X@8`H.$< +M$)WE#""=Y1G^_^MP<(WB!P"@X0P0C>(.`)'H.?[_ZR`0G>4/$`'B)!"-Y2`@ +MG>4BLJ#A'#"=Y0@P@^(8,(WE0%"-X@D`H.$$$*#A!2"@X8?]_^M00(WB!0"@ +MX080H.$$(*#AF_[_ZPD`H.$$$*#A!2"@X7[]_^L%`*#A!Q"@X00@H.&3_O_K +M"0"@X000H.$%(*#A=OW_ZP``6^,84)T%$P``"@S`G>48`)WE`%",X`!`H.-` +M8(WB4'"-X@8`H.$%$*#A!R"@X8+^_^L)`*#A!Q"@X08@H.%E_?_K`4"$XA!0 +MA>(+`%3A\___&A@0G>4+4H'@)""=Y0``4N,<```*`#"@XS`0C>(#(*#A`R#! +MYP$P@^(0`%/C^___&@`PH.,P`(WB#,"=Y040C.`DP)WE`R#1YP,@P.)00(WB!@"@X3`0C>($(*#A7/[_ZPD`H.$$ +M$*#A!B"@X3_]_^L`,*#C*`"-XD`0C>(#(-'G`R#`YP$P@^((`%/C^O__&@`P +MH.,,$)WE!5"!X"@0C>(#(-'G`R#%YP$P@^((`%/C^O__&AT``.H!<(?BH""- +MXH0`C>@(`*#A$!"=Y10@G>4,,)WE#_[_ZPD`H.$($*#A"B"@X2']_^L&4*#A +M"@"@X080H.$$(*#A-?[_ZP`PH.,#(-3G`R#%YP$P@^(0`%/C^O__&A!@AN(+ +M`%?AY?__&A@PG>4+,H/@&#"-Y0D``.H``%OC!P``"@S`G>48`)WE`&",X`!P +MH.-@@(WB0*"-XE!`C>+7___J)!"=Y0``4>,P```*H#"-X@`PC>4!L(OB!+"- +MY6``C>(0$)WE%""=Y0PPG>7C_?_K`#"@XS`0C>(#(*#A`R#!YP$P@^(0`%/C +M^___&@`PH.,,P)WE&`"=Y0`@C.`P`(WB),"=Y0)0H.$#$-+G`Q#`YP$P@^(, +M`%/A^?__&D!`C>()`*#A8!"-X@0@H.'A_/_K!`"@X3`0C>)0((WB]OW_ZP`P +MH.-0$(WB)`"=Y0,@T><#(,7G`3"#X@``4^'Z__\:&!"=Y20@G>4"$('@&!"- +MY:`PC>(`,(WE`$"@XP1`C>5@`(WB$!"=Y10@G>4,,)WELOW_ZS`@C>($,*#A +M!##"YP%`A.(0`%3C^___&APPG>4@P)WE#""#X`P`G>4"((#@`#"@XS``C>(( +M$-+E`Q#`YP$P@^(!((+B"`!3X_G__QI`0(WB"0"@X6`0C>($(*#AL/S_ZP0` +MH.$P$(WB4""-XL7]_^L`,*#C#!"=Y1@@G>4"`('@4!"-X@,@T><#(,#G`3"# +MX@@`4^/Z__\:`0"@XZS0C>+PC[WH\$,^```* +M=7#1Y1TPT>4$`%/C/```&ER@D>4``%KC!0``&EL-@.(X`(#B1A"!XO[__^L` +MH%#B,0``"D8PU.4!`!/C*#D!$P.@EA<*HH80&:R*$BR@BA(1KHH"=X"OY@2` +MB.*(@:#A>(#OY@B`A>``4*#C-'4!XQT``.H!4(7B!0!3X0H``!JR$=3A&,"4 +MY0S`8>`>,-3E#,!CX!\PU.4*`*#A"""@X0PP8^"!_O_K#P``ZK(1U.$'P);G +M#,!AX!XPU.4,P&/@'S#4Y0H`H.$((*#A##!CX';^_^L',);G`X"(X`,P&.(! +M,*`3*(&#X`B!H.$<,-3E`P!5X=[__[H!``#J``"@X_"'O>@!`*#C\(>]Z/!/ +M+>FLT$WB`+"@X1P0C>4"@*#A)#"-Y;!`TN'\0`3BD`"-X@`0H.,0(*#C_O__ +MZX``C>(`$*#C$""@X_[__^MP`(WB`!"@XQ`@H./^___K8`"-X@`0H.,0(*#C +M_O__ZU``C>(`$*#C$""@X_[__^M``(WB`!"@XQ`@H./^___K,`"-X@`0H.,0 +M(*#C_O__ZR00G>4($$'B(!"-Y2&BH.$/(`'B&""-Y0@PH.$4!(-/EH2#-Y00@T^6B(,WE!2#3Y:,@S>4&(-/EI"#-Y04:`%+C`3"@`PPPC044( +M((+B%""-Y0``6N,"0*`!(0``"A0PG>4#8(C@`'"@XV"0C>)00(WB`7"'XJ#` +MC>(`P(WE!'"-Y0D`H.$0$)WE#""=Y0@PH.'>_/_K"P"@X0D0H.%`((WB\/O_ +MZP90H.%``(WB!A"@X00@H.$$_?_K`#"@XP,@U.<#(,7G`3"#XA``4^/Z__\: +M$&"&X@H`5^'D__\:%!"=Y0I"@>`8()WE``!2XRH```J@,(WB`#"-Y0$PBN($ +M,(WE8`"-XA`0G>4,()WE"#"@X;[\_^L`,*#C,!"-X@,@H.$#(,'G`3"#XA`` +M4^/[__\:`#"@XP1`B.`P$(WB&`"=Y010H.$#(-3G`R#!YP$P@^(``%/A^?__ +M&D!`C>(+`*#A8!"-X@0@H.&^^__K!`"@X3`0C>)0((WBT_S_ZP`PH.-0$(WB +M&`"=Y0,@T><#(,7G`3"#X@``4^'Z__\:)#"=Y0@@@^(@,,WE`3#8Y:$PS>4$,-CEHC#-Y04P +MV.6C,,WE!C#8Y:0PS>4',-CEI3#-Y0P@G>608(WB_$.?Y2#`G>4`P(WEH#"- +MX@0PC>4&`*#A`A"@X1`@G>4$,*#AY?O_ZX!PC>('`*#A'!"=Y00@H.$+_/_K +M<("-X@@`H.$$$*#A$""=Y0PPG>4J_/_K0%"-X@L`H.$&$*#A!2"@X8#[_^M0 +M0(WB!0"@X0<0H.$$(*#AE/S_ZPL`H.$$$*#A!2"@X7?[_^L%`*#A"!"@X00@ +MH.&,_/_K"P"@X000H.$%(*#A;_O_ZP``6N,44)T%$P``"D1#G^44$)WE`4"$ +MX`!0H.-`8(WB4'"-X@8`H.$$$*#A!R"@X7O\_^L+`*#A!Q"@X08@H.%>^__K +M`5"%XA!`A.(*`%7A\___&A0@G>4*4H+@&#"=Y0``4^,<```*`#"@XS`0C>(# +M(*#A`R#!YP$P@^(0`%/C^___&@`PH.,P`(WBQ!*?Y040@>`8P)WE`R#1YP,@ +MP.)00(WB!@"@X3`0C>($(*#A5?S_ +MZPL`H.$$$*#A!B"@X3C[_^L`,*#C*`"-XD`0C>(#(-'G`R#`YP$P@^((`%/C +M^O__&@`PH.-0(I_E!5""X"@0C>(#(-'G`R#%YP$P@^((`%/C^O__&AP``.H! +M8(;BH!"-XD(`C>@'`*#A$!"=Y0P@G>4),*#A"/S_ZPL`H.$'$*#A"""@X1K[ +M_^L(`*#A!!"@X04@H.$O_/_K`#"@XP,@U><#(,3G`3"#XA``4^/Z__\:$$"$ +MX@H`5N'F__\:%""=Y0HB@N`4((WE"@``Z@``6N,(```*L$&?Y10PG>4#0(3@ +M`&"@XV!PC>*+7___J&,"=Y0``7.,P```*H#"-X@`PC>4! +MH(KB!*"-Y6``C>(0$)WE#""=Y60QG^7<^__K`#"@XS`0C>(#(*#A`R#!YP$P +M@^(0`%/C^___&@`PH.,\(9_E%!"=Y0$@@N`P`(WB&,"=Y0)0H.$#$-+G`Q#` +MYP$P@^(,`%/A^?__&D!`C>(+`*#A8!"-X@0@H.':^O_K!`"@X3`0C>)0((WB +M[_O_ZP`PH.-0$(WB&`"=Y0,@T><#(,7G`3"#X@``4^'Z__\:%""=Y1@PG>4# +M((+@%""-Y:`PC>(`,(WE`$"@XP1`C>5@`(WB$!"=Y0P@G>6@,)_EJ_O_ZS`@ +MC>($,*#A!##"YP%`A.(0`%3C^___&@`PH.,P`(WB',"=Y200G>4!((S@;!"? +MY0(0@>`#(-'G`R#`YP$P@^((`%/C^O__&D!`C>(+`*#A8!"-X@0@H.&J^O_K +M!`"@X3`0C>)0((WBO_O_ZP`PH.,H`)_E%""=Y0(`@.!0$(WB`R#1YP,@P.@$!```<$`MZ0!0H.$!0*#A?&"1Y2\P +MT>4$`%/C`0"@$W"`O1A;#87B.`"`XD`0@>+^___K``!0XP``H`-P@+T(1C#4 +MY0$`$^-5`-05``*%$!D,@!(L`(`2$0Z``B$0U.5TP)3E#,!AX#`PU.4&(*#A +M##!CX"3^_^L!`*#C<("]Z/!%+>E'WTWB`%"@X0%`H.%\8)'E+S#1Y04`4^,! +M`%,3)0``&E6`T>49/8CB!#"#X@,Q@.`$H)/E#7"@X2$0T>4-`*#A`1"&X`,@ +MH./^___K8X^(X@&`B.((4H7@`P"-X@00A>(*(*#A_O__ZR$PU.4P(-3E=%"4 +MY0508^`%4&+@`S""X`-@AN`00(WB!`"@X0T0H.$#((KB^_;_ZP0`H.$&$*#A +M!B"@X04PH.$7]__K!@"@X0001>)*]__K1]^-XO"%O>CP3RWI3=]-X@!@H.$! +M0*#A;""1Y0``4N-I```*=1#1Y1TPU.4%`%/C`0!3$V0``!IQH*_F!*"*XHJA +MH.%ZH._F"J""X-`X`>,#,)#G&3V#X@0P@^(#,8#@!#"3Y00PC>4`@*#C%#"- +MX@,P@^((,(WE-+4!XR20C>($,)WE`S"#X@PPC>4$4*#A2@``ZK(1U>$4`(WB +M`1"*X`,@H./^___KT#@!XP,0EN=C'X'B`1"!X@$2AN`(`)WE!!"!X@0@G>7^ +M___K'C#5Y;(AU>$#<(+@!W"*X`&`B.(<$-7E`0!8X1<``!H80)7E!$!BX`1` +M8^`?$-7E!$!AX`<`H.$$$*#A!_?_ZRP!C>4)`*#A%!"-X@P@G>6K]O_K"0"@ +MX0<0H.$'(*#A!#"@X($,*#CPO;_ZQP``.H+0);G +M!$!BX`1`8^`?$-7E!$!AX`<`H.$$$*#A[_;_ZRP!C>4)`*#A%!"-X@P@G>63 +M]O_K"0"@X0<0H.$'(*#A!#"@X:_V_^L)`*#A!!"'X$LOC>($,*#CJO;_ZPLP +MEN<#H(K@`S`:X@$PH!,JH8/@"J&@X1PPU>4#`%CAL?__NDW?C>+PC[WH$$`M +MZ0`PH.%2#8#B!`"`XHPD`>,/X*#A`O"3YQ"`O>@00"WI`#"@X5(-@.($`(#B +MD"0!XP_@H.$"\)/G$("]Z!!`+>D`,*#A4@V`X@0`@.*4)`'C#^"@X0+PD^<0 +M@+WH$$`MZ0#`H.',"P/C``"D`P*#A4@V`X@0`@.*X1`'C#^"@ +MX03PG.<0@+WH$$`MZ0#`H.',"P/C``"G4-`'C`S"0YP``4^,0 +M@+T(4@V`X@0`@.(S_R_A$("]Z!!`+>D`P*#A4@V`X@0`@.+(1`'C#^"@X03P +MG.<0@+WH$$`MZ,,P)#G``!G8-`'C`S"0YP``4^,0@+T(4@V`X@0`@.(S_R_A$("]Z!!`+>E2/:#C +M`P"`YX0T`>,#`(#G'""`XH@T`>,#((#G4@V`X@P`@.+^___K`0"@XQ"`O>@0 +M0"WI`#"@X5(-@.($`(#BL,0!XP_@H.$,\)/G_O__ZQ"`O>@00"WI`#"@X5(- +M@.($`(#BK,0!XP_@H.$,\)/G_O__ZQ"`O>@00"WI`#"@X5(-@.($`(#BJ,0! +MXP_@H.$,\)/G_O__ZQ"`O>@00"WI`,"@X5(-@.($`(#BI$0!XP_@H.$$\)SG +M_O__ZQ"`O>@00"WI`#"@X5(-@.($`(#BH,0!XP_@H.$,\)/G_O__ZQ"`O>@0 +M0"WI`#"@X5(-@.($`(#BG,0!XP_@H.$,\)/G_O__ZQ"`O>@00"WI`#"@X5(- +M@.($`(#BF,0!XP_@H.$,\)/G_O__ZQ"`O>@`$)#E(`!1XQ0``(H``%'C%``` +M"@0PT.4@,$/B +M_R_A`0!1XP``H(-8%8"5`0"@DQ[_+^$00"WI`2"@X_[__^L0@+WH<$`MZ0!0 +MH.$!0*#A`0"@X0`0`.,`$$#C_O__ZP``4.,-```*!`"@X0`0`.,`$$#C_O__ +MZP``4.,"$*`#!P``"@0`H.$`$`#C`!!`X_[__^L``%#C!1"@`P````H`$*#C +M!0"@X?[__^MP@+WH\$`MZ0S03>(`4*#A`4"@X0`PH.,$,(WELC#-X0$PS>5L +M,)#E`0`3XP(``!I``!/C``"@`U````IT,-3E=2#4Y0(T@^%V(-3E`CB#X7<@ +MU.4"/(/AA`"$XBT0H.,$((WB##!#XO[__^L`$%#B$```"@0PG>4``%/C#0`` +M"@%@H.$"`(WB!1"!X@(@H./^___K`C#VY0$@UN4"-(/ATW#@YV``$^,`8*`# +M`6"@$P$0H.,"``#J`&"@XP9PH.$&$*#A8##4Y0$@0^)R(._F_0!2XP``H(,) +M``"*``"@XW\P`^(``%/A`P"@(6$PU.4!0(3B`2!#XG(@[^;]`%+C]O__F@$` +M4>.@`*`1&P``&@4`H.$4$*#C`2"-XF@[`^,/X*#A`_"5YP$PW>4#`%/C"0`` +M&@``5^,#```*``!6XY8`H!.'`*`##```Z@``5N-(`*`300"@`P@``.H``%?C +M`P``"@X!`.,``%;C2P^@$P(``.H``%;CD`"@$X(`H`,,T(WB\("]Z!!`+>D` +M,*#A!""1Y0T1TN,3```:`0,2XP<``!H9/(#B+#"#X@,@`N("`H/@`!"@XQ`@ +MH./^___K"0``ZEL-@.(X`(#BX!"#XO[__^L``%#C`P``"A$.@.(`$*#C$""@ +MX_[__^L!`*#C$("]Z/!!+>D!0*#A`6"@X0!0H.$!`'#B``"@,Z$/D.$5```: +M`P!1XQ,``(IC?87B%`"'X@$"@.``$*#C$""@X_[__^L%`*#A"!"'X@0@H.$` +M,*#C_O__ZQE-A.($0(3B!$&%X`1`A.(`,*#C`#"$Y0,`4.`!`*`3\(&]Z``` +MH./P@;WH<$`MZ0!`H.$!4*#A!&"1Y0-AQN,$`%;C``"@PW"`O<@(,)'E!0!3 +MXP$@H`/,.`$#`R"$!P8```H-`%/C`""@$\PX`1,#((07!2"@`\PX`0,#((0' +M8P^&X@$`@.(``H3@!`"`X@P0A>((()7E_O__ZQD]AN($,(/B`S&$X`@@E>4$ +M((/ET#@!XP-@A.<$`*#A8QV$X@@0@>(&(*#A`3"@X_[__^L``%#B`0"@$W"` +MO>CP1RWI"-!-X@!`H.$!4*#A!#"1Y0``4^,"``"Z`0$3XRX```H\`0#J`0$3 +MXRL```I;#8#B.`"`XN`0A.+^___K``!0XP0```K(.`'C`S"4YP(`4^/L8)`% +M`0``"LPX`>,#8)3G!##5Y0``4^,J`0`:##"5Y0$`<^,J`0`:L"'5X?\_#^,# +M`%+A)@$`&B(!`.H(,)7E(`!3XQ\!`!I,``#J!`!6XPD``!H(,)7E$`!3XP8` +M``H@`%/C%P$`&A`PH.,(,(7E`'"@XP<@H.%$``#J!0!6XP$`5A,/`0`*/``` +MZC`\`>,#,)3G`P!3XQ,``(HD.0'C`S"4YP``4^,/```:"#"5Y04`4^,!(*`# +MS#@!`P,@A`<&```*#0!3XP`@H!/,.`$3`R"$%P4@H`/,.`$#`R"$!\PX`>,# +M8)3G`0``ZB0Y`>,#8)3G;#"4Y2``$^,&```*##"5Y0$`<^/N```:L"'5X?\_ +M#^,#`%+AZ@``&@(`5N,#```:"#"5Y2``4^/E```:"```Z@0`5N,&```:"#"5 +MY1``4^,@`%,3W@``&B``4^,0,*`#"#"%!01PE>77?>#G;#"4Y2``$^,'```* +M`0`3XP%PH!,'(*`1`P``"@,``.H`<*#C!R"@X0```.H!(*#CR#@!XP,PE.<" +M`%/C)@``"@4`5N,!`%83(P``&@@@E>4@((+BL#\!XP,@A.<$8)7E`F'&X[0_ +M`>,#8(3G"""5Y;@_`>,#((3G('"%XGZ-A.(\`(CB!Q"@X0@@E>7^___K8S^& +MX@$P@^(#,H3@!`"#X@<0H.$(()7E_O__ZQD]AN($,(/B`S&$X`@@E>4$((/E +MT#@!XP-@A.<$`*#A,!"(XO[__^L!`*#CHP``Z@0PE>4"`A/C&P``"@$`4N,, +M```:V('%X0``X./_'P_C`"`(X`$P">`($(WB^"!AX6<-A.(X`(#B#1"@X0@@ +MH./^___K#@``ZMB!Q>$``.#C_Q\/XP`@".`!,`G@"!"-XO@@8>%G#83B,`"` +MX@T0H.$((*#C_O__ZU```.H!`%+C3@``&@$`5^,$(-4%*#D!`P,@A`<$,)7E +M`P`3XWH```H9;(3B+&"&X@,P`^(#`H;@`!"@XQ`@H./^___K97V$XBQPA^($ +M`-7E`P``X@`"A^``$*#C$""@X_[__^MFC83B+("(X@0`U>4#``#B``*(X``0 +MH.,0(*#C_O__ZP0PE>4!`A/C"P``"@,P`^(#`H?@,!"%X@@@H./^___K!`#5 +MY0,``.(``HC@.!"%X@@@H./^___K"@``Z@,P`^(#`H?@.!"%X@@@H./^___K +M!`#5Y0,``.(``HC@,!"%X@@@H./^___K!`#5Y0,``.(``H;@(!"%X@@@E>7^ +M___K!#"5Y0,P`^($,(7E`3"@XR`L`>,",,3G`!"@XR(L`>,"$,3G!`"@X6,= +MA.(($('B!""5Y?[__^L``%#B`0"@$S,``.I;#83B.`"`XN`0A.+^___K`(!0 +MX@$`H`,L```*$:Z(X@H`H.$`$*#C$""@X_[__^L@D(7B"@"@X0D0H.$0(*#C +M_O__ZP(`5N,6```:`""@XR$\`>,#(,3G!#"5Y0$"$^,(```*\`"(XA`0B>(( +M(*#C_O__ZP$,B.(8$(GB"""@X_[__^L'``#J\`"(XA@0B>(((*#C_O__ZP$, +MB.(0$(GB"""@X_[__^L``%?C!`"@X0@0H.$`(*`3`2"@`_[__^L``%#B`0"@ +M$P```.H``*#C"-"-XO"'O>@"`%;CV_[_&M;^_^H00"WI8SV`X@@P@^(P+`'C +M`A"`YP,`4>,"$*"#R"@!@P(0@(<#$*#A_O__ZP$`4.,``*`3`0"@`Q"`O>AP +M0"WI`$!0XAH```KA.P/C`S#4YP``4^,6```*;#"4Y2(-$^,5```:JY0$` +M4^,2```*_O__ZPTPH.%_74!,(/B!#"%Y00`H.$`$*#C`2"@ +MX?[__^L`0*#A!#"5Y0$P0^($,(7E_O__ZP(``.H`0*#C````Z@%`H.,$`*#A +M<("]Z!!`+>D`0*#A_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B!""#Y6PPE.4! +M`!/C!@``"@0`H.'^___K!`"@X?[__^L$`*#A`1"@X_[__^L-(*#A?SW"XS\P +MP^,$()/E`2!"X@0@@^7^___K`0"@XQ"`O>AP0"WI`$"@X0%0H.$X,9#E`0!3 +MX3\```K^___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/E;#"4Y0$`$^,"```: +M."&4Y0``4N,$```:!`"@X?[__^ML,)3E`0`3XP$``!I``!/C!0``"@0`H.$! +M$*#C_O__ZVPPE.4!`!/C!```&C@QE.4!`%/C`0``"@``4^,!```:!`"@X?[_ +M_^LX,93E!`!3XP,``!H`,.#CV#"$Y00`H.'^___K.%&$Y6PPE.5X,,/C;#"$ +MY0$`5>,(,(,#;#"$!0@```H@,(,S;#"$-04``#H$`%7C`P``&A`P@^-L,(3E +M!`"@X?[__^L-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K`0"@XW"`O>AP +M0"WI`$"@X?[__^L-(*#A?SW"XS\PP^,$()/E`2""X@0@@^6$,)3E`2#@X]@@ +MA.5L()3E@"""XVP@A.5X,(3E`3"@XW$PQ.6$`(3B_O__ZP$`4.,4```:#2"@ +MX7\]PN,_,,/C!""3Y0$@0N($((/E_O__ZVPPE.6`,,/C;#"$Y1@UU.4``%/C +M`@``"G(PU.4``%/C0P``"@0`H.&4$(3B`2"@X_[__^MP@+WH#2"@X7\]PN,_ +M,,/C!""3Y0$@0N($((/E_O__ZVP`A.+^___K`0!0XPL``!H`,*#C<3#$Y0`P +M`.,`,$#C`!"3Y44.A.((`(#BHA^!X@(0@>+^___K`0"@XW"`O>AL,)3E(``3 +MXQ<```I`,*#C;#"$Y:YMA.(.4(;B!0"@X0`0H.,D(*#C_O__ZP4`H.&4$(3B +M)""@X_[__^L$`*#A_O__ZP8`AN+^___K!`"@X?[__^L!`%#C``"@$P`PH`-Q +M,,0%`0"@`W"`O>B`,,/C;#"$Y1@UU.4``%/C`@``"G(PU.4``%/C!```"@0` +MH.&4$(3B`2"@X_[__^MP@+WH`0"@XW"`O>AP0"WI`$"@X0%0H.'A.P/C`S#0 +MYP``4^,`0*`#<```"O[__^L-(*#A?SW"XS\PP^,$()/E`2""X@0@@^5L,)3E +M`@L3XS@``!J``!/C6@``&D$`$^,T```*E""4Y0`PE>4#`%+A(0``&I@`A.($ +M$(7B_O__ZP$`4.,<```:;#"4Y0@`$^,4```:!`"@X<`0A.+^___K``!0XT<` +M`!H$`*#A_O__ZVPPE.4!`!/C`0``"@0`H.'^___K!`"@X0$0H./^___K;#"4 +MY4``$^-`,,,3(#"#$VPPA!43``#J!`"@X0$0H.,!(*#A_O__ZPX``.H$`*#A +M_O__ZVPPE.4!`!/C`0``"@0`H.'^___K!`"@X0$0H./^___K;#"4Y4``$^-` +M,,,3(#"#$VPPA!4H-P+C`S#4YP$`4^,+```:_O__ZRPW`N,#,)3G`#!CX'`G +M`>,"`%/A&@``F@`PH.,H)P+C`C#$YRPG`N,",(3G!0"@X?[__^L``%#C$0`` +M"I0`A.(%$*#A)""@X_[__^L`,*#CC#2$Y6PPE.4""Q/C`3"@$W$PQ!4#0*`1 +M!@``&@0`H.'^___K`$"@X0(``.H!0*#C````Z@!`H.,-(*#A?SW"XS\PP^,$ +M()/E`2!"X@0@@^7^___K!`"@X7"`O>AP0"WI`$"@X0%0H.$`,-'E``!3XP\` +M`!H!(-'E``!2XPP``!H",-'E``!3XQH``!H#,-'E``!3XQ<``!H$,-'E``!3 +MXQ0``!H%,-'E``!3XQ$``!IA``#J_P!3XPX``!H!,-7E_P!3XPL``!H",-7E +M_P!3XP@``!H#,-7E_P!3XP4``!H$,-7E_P!3XP(``!H%,-7E_P!3XU````K^ +M___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/E;#"4Y0(+$^,<```:@``3XSL` +M`!I!`!/C&```"N``A.(%$*#A!B"@X_[__^L!`%#C`P``&FPPE.4(`!/C,``` +M"@X``.H$`*#A_O__ZVPPE.4!`!/C`0``"@0`H.'^___K!`"@X0$0H./^___K +M;#"4Y4``$^-`,,,3(#"#$VPPA!4H-P+C`S#4YP$`4^,,```:_O__ZRPW`N,# +M,)3G`#!CX'`G`>,"`%/A`$"@DQ4``)H`,*#C*"<"XP(PQ.@$0"WE%-!-X@#`H.$`,`#C`#!`XPU`H.$/ +M`)/H!P"DZ``PQ.4`,-WE``!3XPX```H,`%/A`#"@`P4``!H!``#J#`!2X00` +M`!H!`*#C$`.@X08``.H`,*#C#1"@X0$P@^(#(-'G``!2X_3__QH``*#C%-"- +MXA``O>@>_R_A`##0Y0``4^,8```*?S`#X@0`4^,"`%,3$@``"@L`4^,0```* +M%@!3XP`@H!,(```:#```ZG\P`^($`%/C`@!3$P@```H+`%/C!@``"A8`4^,$ +M```*`2""X@(PT.<``%/C\___&@$``.H!`*#C'O\OX0``H.,>_R_A`##0Y0`` +M4^,.```*`""@XW\P`^("`%/C!`!3$P4```H+`%/C`P``"A8`4^,!```*``"@ +MXQ[_+^$!((+B`C#0YP``4^/Q__\:`0"@XQ[_+^$00"WI`$"@X0X`4N,$``#: +M_O__ZP$`4.,$`*`3``"@`Q"`O>C^___K`0!0XQ"`O0@$`*#A_O__ZP$`4.,# +M`*`#`@"@$Q"`O>@P`"WI``!3XPP``-H`P*#C`,""Y0!`T.4!`%3A`3#0!0`P +M@@4&```*`4#0Y0)0A.(%P(S@#`!3X04`@,#T___*``"@XS``O>@>_R_A`##0 +MY0``4^,`,*`3`@``&@4``.H-`%/C`P``"@$P@^(#(-#G``!2X_G__QH#`*#A +M'O\OX1!`+>D!P*#A`C"@X3`0H.,,(*#A_O__ZQ"`O>@`,*#A,`!`XG``[^8) +M`%#C'O\OD6$@0^)R(._F!0!2XU<`0Y)P`.^6'O\OD4$@0^)R(._F!0!2X_\` +MH(,W`$.2<`#OEA[_+^%P0"WI`5"@X>K__^L`0*#A!0"@X>?__^L$083@A`"` +MX'``[^9P@+WH<$`MZ0%0H.'@___K`$"@X04`H.'=___K!`*`X7``[^9P@+WH +M`0!1XPH``!H`,-#E(`!3XPD``!H-``#J`1!!X@$PT.<``%/C"P``&@``4>/Y +M__\:!@``Z@``4>,$```*`1!!X@$PT.<``%/C]O__"@$``.H!`*#C'O\OX0`` +MH.,>_R_A##``X@0`4^,)```*"`!3XQ@PH!,.```:@``0XQ@PH`,:,*`3`PP` +MX@,,4.,&,(,"!P``ZO`@`.+`,$+B$`!3XQ`PH(,`,`"3`#!`DP(A@Y#P,A*5 +M`P"@X1[_+^$00"WI`D"@X0`0P.4B)*#A`B#`Y0%`P.4`$%/B`@``"@,`@.($ +M(*#A_O__ZP,`A.(0@+WH\$`MZ0S03>(`<%#B20``"@`P`.,`,$#C`$"3Y0`` +M5.,.```*`&"@XPU0H.$``-3E`1#4Y?[__^L&`,7G`6"&X@-`A.(&`%;C]___ +M&@<`H.$-$*#A!B"@X_[__^L#``#J#0"@X0<0H.$&(*#C_O__ZP`PW>7_`%/C +M#P``&@$@W>7_`%+C#```&@(PW>7_`%/C*```&@,PW>7_`%/C)0``&@0PW>7_ +M`%/C(@``&@4PW>7_`%/C'P``&A```.H``%/C'```&@$PW>4``%/C&0``&@(P +MW>4``%/C%@``&@,PW>4``%/C$P``&@0PW>4``%/C$```&@4PW>4``%/C#0`` +M&@`PH.,`,,WE'R#@XP$@S>5,(*#C`B#-Y7@@X.,#(,WE!##-Y04PS>4'`*#A +M#1"@X08@H./^___K#-"-XO"`O>AP0"WI`$"@X0)0H.$08)WE`!#`Y0$@Q.4` +M`%+C`@``"@(`@.(#$*#A_O__ZP(`A>(`,);E`#"#X``PAN4``(3@<("]Z'!` +M+>D`8*#A`4"@X0-0H.$"$*#A!""@X?[__^L`,)7E!#"#X``PA>4$`(;@<("] +MZ/!!+>D`8*#A`5"@X0)`H.$"`*#A`!"@X[@@H./^___K`0!5XP``H).5``": +M`##6Y0$0]N4"4$7B`2"@X04`4>&4``"*`6"&X@``H./R<`7C3,`)XP<``.H" +M8(;@`##6Y0$0]N4"4$7B`2"@X0$`5>&(```Z`6"&XB0`4^.`8(0%A!#$!7L` +M``H@``"*!`!3XR!@A`4D$,0%=@``"@T``(H!`%/C"&"$!0P0Q`5Q```*`&"$ +M-000Q#5N```Z`@!3XQ!@A`44$,0%:@``"@,`4^-G```:+P``Z@8`4^,P8(0% +M-!#$!6,```HH8(0U+!#$-6```#H0`%/C.&"$!3P0Q`5<```*(0!3XUD``!I5 +M``#J-@!3XXA@A`6,$,0%50``"@X``(HM`%/CH&"$!:00Q`50```*`@``BBH` +M4^-,```:%P``ZC``4^-88(0%7!#$!4@```HR`%/C10``&A,``.HX`%/CF&"$ +M!9P0Q`5!```*D&"$-900Q#4^```Z/0!3XZA@A`6L$,0%.@``"MT`4^,W```: +M"```ZAA@A.4<$,3E-```ZD!@A.5$$,3E,0``ZDA@A.5,$,3E+@``Z@,`4N,F +M``":`C#6Y0"`UN4(.(/A`8#6Y0@T@^$'`%/A`@``"@P`4^$=```:%P``Z@,P +MUN4"`%/C"```"@0`4^-P8(0%=!#$!1L```H!`%/C4&"$!500Q`41```:%@`` +MZ@0`4N,.``":!##6Y0$`4^-@8(259!#$E0\``)H"`%/C!P``&FA@A.5L$,3E +M"@``Z@,PUN4S`%/CL&"$!;00Q`4%```*`0"`X@,``.IX8(3E?!#$Y0```.H! +M`(#B!5!BX`$`5>-T__^*``!5XP(``!H``%#B`0"@$_"!O>@``.#C\(&]Z'!` +M+>D`4*#A`4"@X0`0H.,0(*#C_O__ZQ0`5.-P@+V(`3"@XQ-$H.$4,`#C$3!` +MXP,P!.```%/C#```&@@]`.,`,$#C`S`$X```4^,,```:`@`4XW"`O0@%`*#A +M`!``XP`00.,$(*#C_O__ZW"`O>@%`*#A-!"?Y0@@H./^___K<("]Z`!``.,` +M0$#C!0"@X000H.$$(*#C_O__ZP0`A>($$(3B"""@X_[__^MP@+WH]`,``/!! +M+>D0T$WB`$"@X;HHT.&Z+,#A"C"@XPPPC>7,`(#B`B"@X[`@P.$M(-3E`P!2 +MXR(@H`.P(,`!NB?4X;P7U.$!&)+AL"#0$1`@@A.P(,`1##"=Y0(P@^(08(WB +M!#`FY;8UU.&X)=3A`&"-Y0(`@.(`$*#C`BB#X5HPA.+^___K`("@X2H0U.4? +M`%'C!0``&K(YU.&T&=3A`1B#X0X`4>,4$*"#"Q"@DZIPA.('`*#A_O__ZP<` +MH.'^___K`""@X0!0H.$(`%#C%0``V@!@C>4(`*#A`1"@XP@@H.,',*#A_O__ +MZP!@C>4#$*#C`2"@XY(PA.+^___K`&"-Y080H.,"(*#CCC"$XO[__^L`8(WE +M,A"@XP@@1>*R,(3B_O__ZPX``.H`8(WE"`"@X0$0H.,',*#A_O__ZP!@C>4# +M$*#C`2"@XY(PA.+^___K`&"-Y080H.,"(*#CCC"$XO[__^L,`)WE$-"-XO"! +MO>CP1RWI"-!-X@!0H.$!<*#A`H"@X0.@H.$H8)WE`#``XP`P0.-4,)/E!#"- +MY0``5N,`,*`3`#"&%0`PT.7=`%/C)P``&@(`@.($$(WB!""@X_[__^L!`%#C +M(0``&@9`A>($,&7@`P!7X1T``)H"D-3E`3#4Y0F4@^$#D(GB>9#_Y@`PU.4( +M`%/A$0``&@<``.H"D-3E`3#4Y0F4@^$#D(GB>9#_Y@`PU.4(`%/A"```&@`` +M6N,#```*"@"@X000H.$)(*#A_O__ZP``5N,`D(85!```Z@E`A.`$,&7@!P!3 +MX>K__SH`0*#C!`"@X0C0C>+PA[WH<$`MZ1#03>(#4*#A($"=Y0``5.,`,*`3 +M`#"$%0PPC>(`,(WE`#"@X_[__^L`8%#B#@``"@P@G>4``%+C"P``"@``5>,# +M```*!0"@X0,0AN(#($+B_O__ZP``5.,,,)T5`S!#$@`PA!4#`(;B````Z@`` +MH.,0T(WB<("]Z/!/+>D4T$WB`%"@X0%PH.$$((WE`"``XP`@0.-8()+E#""- +MY0"P4^(`,*`3`#"+%0``4>,B```*`$"@XPR@C>($D*#C`8"@XP1@A>``,-;E +MW0!3XQ0``!H"`(3B``"%X`H0H.$)(*#A_O__ZP$`4.,-```:!A"@X00PG>4` +M`%/C`P``"@$@UN4$`)WE`B""XO[__^L``%OC!$"%$`$PU!4",(,2`#"+%08` +M`.H$,(7@"##3YP(P@^(#0(3@!`!7X>#__XH`8*#C!@"@X130C>+PC[WH\$\M +MZ1S03>(`L*#A#!"-Y70PT.5U$-#E`12#X78PT.4#&('A=S#0Y0,<@>&$`(#B +M#!!!X@`@H.,4,(WB_O__ZP"04.)+```*%&"=Y0!PH.,!@(GB$#"-X@`PC>4) +M`*#A!A"@X0P@G>4',*#A_O__ZP!`4.(7```*$""=Y0``4N,4```*`J"$X`E0 +M:N`&4(7@!`"@X0<0H.'^___K!`"@X0H0H.$%(*#A_O__ZP4`A.`'$*#A$""= +MY?[__^L`(-CE$##=Y0(P8^``,,CE$#"=Y09@8^#>___J%!"=Y08`4>$D```* +M`1")X`:0B>!X0(OB!$!AX'0PV^5U(-OE`C2#X78@V^4".(/A=R#;Y0(\@^$# +M0(3@"0"@X00@H.'^___K!`")X``0H.,4()WE`B!FX/[__^MT,-OE=2#;Y0(T +M@^%V(-OE`CB#X7<@V^4"+(/A%#"=Y0(P8^`&8(/@=&#+Y28TH.%U,,OE)CB@ +MX78PR^4F;*#A=V#+Y1S0C>+PC[WH,$`MZ0S03>(`4*#A`4"@X0`@H.,$,(WB +M_O__ZP``5>$.```:!#"=Y0``4^,+```*!C"%X@,@9>`"`%3A!P``F@(0T^4! +M(-/E`22"X0,@@N(",(/@`R!EX`(`5.'W__^*#-"-XC"`O>CP1RWI"-!-X@!0 +MH.$!<*#A`H"@X0.@H.$H8)WE`#``XP`P0.-<,)/E!#"-Y0``5N,`,*`3`#"& +M%0`PT.7=`%/C*P``&@(`@.($$(WB!""@X_[__^L!`%#C)0``&@9`A>($,&7@ +M`P!7X2$``)H"D-3E`S#4Y0F4@^$$D(GB>9#_Y@`@U.4!,-3E`C2#X0@`4^$3 +M```:"0``Z@*0U.4#,-3E"92#X020B>)YD/_F`"#4Y0$PU.4"-(/A"`!3X0@` +M`!H``%KC`P``"@H`H.$$$*#A"2"@X?[__^L``%;C`)"&%00``.H)0(3@!#!E +MX`<`4^'H__\Z`$"@XP0`H.$(T(WB\(>]Z'!`+>D0T$WB`U"@X2!`G>4``%3C +M`#"@$P`PA!4,,(WB`#"-Y0`PH./^___K`&!0X@X```H,()WE``!2XPL```H` +M`%7C`P``"@4`H.$$$(;B!"!"XO[__^L``%3C##"=%00P0Q(`,(05!`"&X@`` +M`.H``*#C$-"-XG"`O>CP3RWI%-!-X@!0H.$!<*#A!""-Y0`@`.,`($#C8""2 +MY0P@C>4`L%/B`#"@$P`PBQ4``%'C``!0$R0```H``%'C(@``"@!`H.,,H(WB +M!)"@XP&`H.,$8(7@`##6Y=T`4^,4```:`@"$X@``A>`*$*#A"2"@X?[__^L! +M`%#C#0``&@80H.$$,)WE``!3XP,```H!(-;E!`"=Y0(@@N+^___K``!;XP1` +MA1`!,-05`C"#$@`PBQ4&``#J!#"%X`@PT^<",(/B`T"$X`0`5^'@__^*`&"@ +MXP8`H.$4T(WB\(^]Z#!`+>D,T$WB`%"@X0%`H.$`(*#C!#"-XO[__^L``%7A +M#@``&@0PG>4``%/C"P``"@8PA>(#(&7@`@!4X0<``)H"$-/E`R#3Y0$D@N$$ +M((+B`C"#X`,@9>`"`%3A]___B@S0C>(P@+WH\$$MZ0%PH.$`8*#A`$"@X0%0 +MU.4$`*#A!1"@X?[__^L$`*#A!1"@X?[__^L"4(7B!4"$X`0P9N`'`%/A\___ +MFO"!O>@P0"WI#-!-X@%0H.$`,`#C`#!`XV0PD^4$,(WE`$!0X@L```H`,-3E +MW0!3XP@``!H"`(3B!!"-X@0@H./^___K`0!0XP$PU`4",(,"`#"%!0````H` +M`*#C#-"-XC"`O>CP3RWI%-!-X@!@H.$!@*#A!""-Y0.0H.$`,`#C`#!`XV@P +MD^4,,(WE#`!1XSP``)H,0*#C`:"@XP1PAN``4-?EW0!5XQH``!H"L(3B"P"& +MX`P0C>($(*#C_O__ZP$`4.,3```:`4"$X@1`AN``(-3E.`"=Y0<0H.$"((+B +M_O__ZP`0U.4"(('B`#"@XP@P@^)S,._F`@!3X?O__[H"$('B/#"=Y;`0P^$` +M0-3E!$"+X!D``.HP`%7C$P``&@%0A.(%4(;@`"#5Y00`G>4'$*#A`B""XO[_ +M_^L`$-7E`B"!X@`PH.,(,(/B$"0(3B`##5 +MY0-`A.`#``#J!#"&X`HPT^<"0(3B`T"$X`0`6.'$__^*/#"=Y;``T^&P,-GA +M`P"`X!30C>+PC[WH$$`MZ0!`H.&`$)_E!""@X_[__^L!`%#C$("]"`0`H.%L +M$)_E!""@X_[__^L!`%#C`@"@`Q"`O0@$`*#A5!"?Y00@H./^___K`0!0XP@` +MH`,0@+T(!`"@X3P0G^4$(*#C_O__ZP$`4.,0`*`#$("]"`0`H.$D$)_E!""@ +MX_[__^L!`%#C!`"@`P``H!,0@+WH_`,````$```$!```"`0```P$``#P02WI +M`E"@X0-`H.$``%'C+0``V@`PT.4P`%/C*@``&@(P0>(!(-#E(#`%;C!0``V@<`H.'^___K``"%Y01PA^($8$;B`0``Z@`` +M5N,9``#*`0!6XQ0``-H!@-?E`##7Y0B$D^$3```*`F!&X@@!5N$0``"Z``!8 +MXQ```-H"8(?B`'"@XP!0E.4&`*#A_O__ZP4`@.$``(3E!&"&X@%PA^('`%CA +M]O__R@0``.H!`%;B`0"@$_"!O>@``*#C\(&]Z`$`H./P@;WH$$`MZ0!`H.&` +M$)_E!""@X_[__^L!`%#C$("]"`0`H.%L$)_E!""@X_[__^L!`%#C`@"@`Q"` +MO0@$`*#A5!"?Y00@H./^___K`0!0XP@`H`,0@+T(!`"@X3P0G^4$(*#C_O__ +MZP$`4.,0`*`#$("]"`0`H.$D$)_E!""@X_[__^L!`%#C!`"@`P``H!,0@+WH +M$`0``!0$```8!```'`0``"`$``#P02WI`$"@X0)@H.$#<*#A`%!1XC,``-H` +M,-#EW0!3XS```!H",$7B`2#0Y7,P[^8#`%+A*P``&@(`@.*T$)_E!""@X_[_ +M_^L!`%#C)0``&@A`A.((4$7B`P!5XP4``-H$`*#A_O__ZP``AN4$0(3B!%!% +MX@$``.H``%7C&0``R@$`5>,4``#:`8#4Y0`PU.4(A)/A$P``"@)01>((`57A +M$```N@``6.,0``#:`E"$X@!@H.,`0)?E!0"@X?[__^L$`(#A``"'Y010A>(! +M8(;B!@!8X?;__\H$``#J`0!5X@$`H!/P@;WH``"@X_"!O>@!`*#C\(&]Z"0$ +M``#P3RWI'-!-X@!@H.$$$(WE`E"@X0`P`.,`,$#C;#"3Y0PPC>44<(WBW8"@ +MXPR@C>($D*#C`;#@XP@0H.$'(*#A!3"@X?[__^L`0%#B$```"@(`A.(*$*#A +M"2"@X?[__^L``%#C#@``"A(`C>(&$(3B`B"@X_[__^NR,=WA`0!3XP<``!H! +M,-3E!""=Y0`P@N4/``#J`#"@XP0@G>4`,(+E"P``ZA0PG>4+(&/@`B"&X`50 +M@N`%4&3@``!5XP(P@\(#`(3`V___R@!`H.,$,)WE`$"#Y00`H.$_R_A +M``"@XQ[_+^$*`(#B'O\OX1[_+^$(`(#B'O\OX,#,)#G``!3XP,```I, +M`)'E``!0X@$`H!,>_R_A3`"1Y0$`4.(!`*`3'O\OX1[_+^$>_R_A'O\OX6PP +MD.40`!/C!0``&H@S`>,#,)#G`0!3XQ\`H`,9```:'O\OX6,]H.,#,-#G``!3 +MXQ$```H&+(/B#2""X@(A@.`$()+E``!2XP3`H`,&```*"0``Z@8L@^(-((+B +M`B&`X`P0DN<``%'C`P``&@$P0^)S,._F``!3X_7__QH!,(/B@>_R_A\`4MZ1APG>4,`%/C``"@DS8``)H, +M`*#C`E"@XP-@H.,$@*#C`4"@XP#`T>?=`%SC)P``&@#`@>`%P-SG``!`#`-'G +M`P#,YP$P@^()`%/C^O__&@D`A^('((+@!S"@XP$PPN4&$(+B`#"@XP`PP>4( +M((+B`##"Y08``.H`P('@!,#_R_A!.`MY0S03>(`,*#A`""@X]0D@.70)(#EW"2`Y=@DD.4``%+C"@`` +M"@(O`N,"(-#G`0!2XP`@H!,'(,WE)!"@XP<@C>)DRP/C#^"@X0SPD^<&``#J +M"""-X@$0H.,!$&+E)!"@XV3+`^,/X*#A#/"3YPS0C>(`@+WH<$`MZ0!`H.&N +M78#B!@"%X@T;A.(1$('B!B"@X_[__^L.`(7B*QR$XCP0@>(D(*#C_O__ZP`P +MH..^*P+C(!"@X[(0A.&O+:#CLC"$X<(K`N-D$*#CLA"$X<0K`N.R,(3ASBL" +MX[(PA.'0*P+CLC"$X=(K`N.R,(3AU"L"X[(PA.'6*P+CLC"$X=@K`N.R,(3A +MVBL"X[(PA.'<*P+CLC"$X7"`O>@$X"WE#-!-XG@`@.+^___K`!"@X08`C>(" +M(*#C_O__Z[8`W>$,T(WB`("]Z'!`+>D`4*#A`4"@X48PT>4!`!/C<("]&`PU +MD.5C`%/C<("]F#!@T>5<`)'E``!0XP4``!I;#87B.`"`XD80@>+^___K``!0 +MXW"`O0B$-I#E`0!3XW"`O1B(-I#E`0!3XW"`O1B<-M#EFQ;0Y5,FH.%1)H+A +M`0`2XW"`O1@!(*#C$C:#X9PVP.4%`*#A!A"@X48@A.+^___K<("]Z'!`+>D( +MT$WB`$"@X=@TD.4``%/C5```"M([T.4``%/C40``"M$[T.4``%/C3@``"MPT +MD.4``%/C"@``&OP^`N,#,-#G`0!3XP8``!H"/P+C`S#0YP$`4^,`,*`#`3"@ +M$]PT@.4$``#J_#X"XP,PU.<"`%/C`3"@`]PTA`4(,(WB``"@XP0`(^4,4('B +M#&!"X@4`H.$M$*#C`R"@X08PH.'^___K``!0XPD```H$,)WE``!3XP8``-H$ +M,-#E`S`#X@,P@^(!(*#C$C.@X7,P[^;H-(3E"""-X@`PH.,$,"+E!0"@X3T0 +MH.,&,*#A_O__Z_L^`N,#,-3G``!3XQ,```KV.P#CLS"4X0(`$^,/```*%SS4 +MY00`$^,,```*`3"@X]\WQ.47/-3E`S`#X@$`4^,!,*`#X#?$!00```H#`%/C +M`#"@$^`WQ!4",*`#X#?$!?8[`..S,)3A4S'AY]8[Q.48/-3E`S`#XM,[Q.4( +MT(WB<("]Z/!/+>E$T$WB`$"@X0%@H.$"H*#A:)"=Y0`0`.,`$$#C%""-X@,` +MD>@$`(+DLA#"X"$8H.$`$,+E`""@X]@DA.4,8(;B/'"-X@R`0^(&`*#A+1"@ +MXP<@H.$(,*#A_O__ZP``4.-%```*/#"=Y0``4^-"```*S#24Y0``4^,(```: +M``"9Y0"0C>4``(K@W1"@XP<@H.,4,(WB_O__ZP$PH./,-(3E`+"9Y1P`C>(` +M$*#C&B"@X_[__^OB,`'CO#'-X6Q;`^,$`*#A!1"@XQ`@C>(/X*#A!?"4YP0` +MH.$$$*#C#""-X@_@H.$%\)3G!`"@X0L0H.,X((WB#^"@X07PE.7,*`'C`B"4YP0`4N,<,(,#'C#-!0"0C>4+`(K@+1"@XQH@H.,<,(WB +M_O__ZP$PH./8-(3E!@"@X3T0H.,'(*#A"#"@X?[__^L`,%#B"```"CP@G>46 +M`%+C!0``&@``F>4`D(WE``"*X#T0H.,",(/B_O__Z]@$E.5$T(WB\(^]Z!!` +M+>D`0*#A*PR`XC@`@.+,.`'C`Q"4YP`04>(!$*`3`#"@X[(K`N.R$(3AM"L" +MXP`0H..R$(3AMBL"X[(PA.&X*P+CLC"$X6([`N,#,-3G`3!#XAX`4^,#\9^7 +M/0``ZBA^``!$?@``1'X``&!^``"D?@``I'X``*1^``!$?@``I'X``$1^``!$ +M?@``I'X``*1^``"D?@``I'X``*1^``"D?@``I'X``*1^``!@?@``I'X``*1^ +M``"D?@``I'X``*1^``"D?@``I'X``*1^``"D?@``I'X``'Q^``"Z.P+C`2"@ +MX[,@A.&\.P+C`!"@X[,0A.$7``#JNCL"XP,@H..S((3AO#L"XP`0H..S$(3A +M$```ZKH[`N,"(*#CLR"$X;P[`N,`$*#CLQ"$X0D``.IA.P+C`S#4YPX`4^.Z +M.P+C`B"@@P,@H).S((3AO#L"XP`0H..S$(3A83L"XP,@U.?*.P+CLR"$X`"`XH([`N.S`(3A(`B@X80[`N.S`(3A$("]Z/A/+>D`8*#A`I"@X3`\`>,# +MH)#G`@"@X0P@H./^___K!J!*X@$`6N/=H*"#,*"@DQ@Z`>,#,-;G`0!3XPL` +M`!H<3`'C#`")XAH($$*#A +M`B""XO[__^L%L-;G#K"+X@8`H.$*$*#A!""@X?[__^NX<(;B)UR&XC!0A>(` +M0*#C!H"@XP`PU>4``%/C!P``"@0#AN`G#(#B,0"`X@<0H.$((*#A_O__ZP$` +M4.,$```*`4"$XD!0A>(0`%3C\/__&@,``.H0`%3C`0``"@``5.,!``"J"P"@ +MX?B/O>@P`%KC$P``&@E0H.$-,/7E%`!3XP\``(H!,*#C"S#)YP.PB^``,*#C +M"S#)YP$`B^($$X;@``")X"<<@>(W$('B$""@X_[__^L1L(OB`##5Y1(P@^(` +M,,7E"P"@X?B/O>@P0"WI#-!-X@!`H.$!4*#A>`"`XO[__^L`$*#A!@"-X@(@ +MH./^___K>`"%XO[__^L`$*#A!`"-X@(@H./^___K###4Y0T@U.4")(/A#C#4 +MY0,H@N$/,-3E`RR"X0PPU>4-$-7E`32#X0X0U>4!.(/A#Q#5Y0$\@^$#`%+A +M&```&@0`A.($$(7B!B"@X_[__^L!`%#C$@``&@PPU.4-(-3E`C2#X0X@U.4" +M.(/A#R#4Y1``A.(0$(7B`BR#X?[__^L!`%#C!@``&K0@W>&V,-WA`S`BX`,` +M$^,``*`3`0"@`P```.H``*#C#-"-XC"`O>CP1RWI`%"@X0%`H.$"8*#A<(#1 +MY7&@T>4T,-'E-7#1Y0=T@^$V,-'E`WB'X34#?(?A`@"@X040H.$$(*#A +MC#L#XP_@H.$#\);G;#"6Y0$`$^,W```*W`"&X@00H.&J___K``!0XS(```J< +M-@'C`S#6YW`PQ.6=-@'C`S#6YW$PQ.5E`%/C&P``"C0PU>4U(-7E`B2#X38P +MU>4#*(+A-S#5Y0,L@N$T,-3E-1#4Y0$T@^$V$-3E`3B#X3<0U.4!/(/A`B&# +MX&4"/(/A-##$Y2,DH.$U +M(,3E(RB@X38@Q.4C/*#A-S#$Y3X``.IQ,-3E90!3XRD```IP(-7E<##4Y0(A +M@^#-/`SCS#Q,XY,2@N`B(:#A<"#$Y7$0U>5Q(-3E`2&"X),"@^`C,:#A<3#$ +MY30PU>4U$-7E`12#X38PU>4#&('A-S#5Y0,<@>$T,-3E-2#4Y0(T@^$V(-3E +M`CB#X3<@U.4"/(/A`1&#X&5Q,,3E-##5Y34@ +MU>4"-(/A-B#5Y0(X@^$W(-7E`CR#X30PQ.4C)*#A-2#$Y2,HH.$V(,3E(SR@ +MX3@0 +M0"WI###0Y0T@T.4")(/A#C#0Y0,H@N$/,-#E`RR"X0PPT>4-P-'E##2#X0[` +MT>4,.(/A#\#1Y0P\@^$#`%+A``"@$Q"`O1@0`(#B$!"!XO[__^L!`%#C``"@ +M$P$`H`,0@+WH\$$MZ0C03>(`4*#A`7"@X0`PH.,`,,WE`3#-Y0(PS>4#,,WE +M!##-Y04PS>4-`*#A!B"@X_[__^L``%#C$```&@!`E>4$`%7A#0``"@:`H.,$ +M8*#A!P"@X2`0A.(((*#A_O__ZP$`4.,#```*`$"4Y00`5>'U__\:`0``Z@4` +M5.$````:`&"@XP8`H.$(T(WB\(&]Z!!`+>G^___K$("]Z'!`+>D`0*#A`5"@ +MX0``D.4``%#C<("]"``0D>7^___K`#"@XP`PA>4`,(3E<("]Z'!`+>D`0*#A +M<6Z`XG)>@.($`(;B!!"%XNS__^L(`(;B"!"%XNG__^L,`(;B#!"%XN;__^MS +M;H3B!0"@X080H.'B___K'5V$X@0`AN(($(7BWO__ZP@`AN(,$(7BV___ZW5. +MA.(,`(;B!!"@X=?__^L%`*#A!!"$XM3__^L$`(7B"!"$XM'__^MP@+WH^$\M +MZ0!PH.$!8*#A`I"@X0.PH.$<`*#C_O__ZP"`H.$`4*#A``!0XTP```H4`*#C +M_O__ZP"@H.$`0*#A``!0XP0``!H(`*#A'!"@X_[__^L``*#C^(^]Z``0H.,4 +M(*#C_O__ZP`PEN4"`%/C7#"6!00PEA4`,,KE>3#OY@$PRN4#L,KE5"77Y0$0 +MH.,1,X+A5#7'Y0`PVN4!,$/B!`!3XP/QGY`0(*#C_O__ZP$PH.,",,KE!@``ZF00AN($ +M`(KB"1*!X!`@H./^___K`3"@XP(PRN44,*#CL##%X02@A>4(,(7E`#"@XPPP +MA>40,(7E%`"%XO[__^L%"X?B*`"`X@40H.'^___K^(^]Z```H./XC[WH\$]"`0`H./^___K +M`&"@X0!PH.$``%#C!```&@4`H.$<$*#C_O__ZP``H./PA[WH`!"@XP0@H./^ +M___K`#"8Y0`PQN43,*#CL##%X01@A>4$,*#C"#"%Y0`PH.,,,(7E$#"%Y10` +MA>+^___K!0N*XB@`@.(%$*#A_O__Z_"'O>AP0"WI`&"@X0!`D.4`4*#C!@"@ +MX000H.'^___K`0!0XPT```H$(*#A##"4Y0$`4^,'```*``!5XP0```H0$)3E +M$#"5Y0$P8^```%/C````J@)0H.$`0)3E[/__Z@4`H.%P@+WH$$`MZ0!`4.(0 +M@+T(X3L#XP,PU.<``%/C$("]",P[`^,#,)3G`0!3XQ"`O0C0.P/C`S"4YP$` +M4^,0@+T(K#P#XP,PE.D`0*#A``!1XA"`O0@,,)#E`0!3XQ"`O0@,`)#H +M!#""Y0`@@^4``(#E!`"`Y1`0A.+^___K)#"4Y0$P0^(D,(3E$("]Z!!`+>G^ +M___K$("]Z'!`+>D`8*#A`%!1X@T```K^___K#3"@X7]-P^,_0,3C!#"4Y0$P +M@^($,(3E!0"@X080H.'^___K!#"4Y0$P0^($,(3E_O__ZP$`H.-P@+WH$$`M +MZ?[__^L0@+WH$$`MZ0!`H.$8$)'E_O__ZP0`H.'^___K$("]Z!!`+>G^___K +M$("]Z!!`+>D`0*#A_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B!""#Y6P@E.4" +M*\+C;""$Y0`@H.-P(,3E!""3Y0$@0N($((/E_O__ZP0`H.$!$*#C_O__ZQ"` +MO>@00"WI`$"@X6PPD.6!,,/C;#"`Y>0V`^,#,)#G``!3XP$```H#$*#C,_\O +MX7(PU.4``%/C`0``&@0`H.'^___K!`"@X0,0H.,!(*#C_O__ZP0`H.$`$*#C +M`2"@X_[__^L0@+WH$$`MZ0!`H.$``%'CP!"``G(PT.4``%/C$("]")0`@.(H +M$('B)""@X_[__^L`,*#CC#2$Y00`H.'^___K`0!0XQ"`O0AR,-3E`3!#XG,P +M[^9R,,3E``!3X_7__QH$`*#A_O__ZQ"`O>AP0"WI`%"@X0%@H.'^___K#3"@ +MX7]-P^,_0,3C!#"4Y0$P@^($,(3E!0"@X080H.'^___K!#"4Y0$P0^($,(3E +M_O__ZW"`O>CP02WI`$"@X6Q0@.+,.P/C`S"0YP``4^/P@;T8T#L#XP,PD.<` +M`%/C\(&]&/[__^L-(*#A?SW"XS\PP^,$()/E`2""X@0@@^5R,-3E``!3XPT` +M``IR,-3E`3!#XG,P[^9R,,3E``!3XP0```H$`*#A_O__ZP$`4./U__\:+0`` +MZ@0`H.'^___K*@``Z@0`H.'^___K_O__ZPTPH.%_;D`0*#A +M`""@XW$@P.4S$*#C9#L#XP_@H.$#\)#G;#"4Y0$P@^-L,(3EY#8#XP,PE.<` +M`%/C`@``"@0`H.$"$*#C,_\OX00`H.'^___K`#"@XW(PQ.40@+WH\$$MZ0!` +MH.$!8*#A`7"@X2\,@.(,`(#B_O__ZP``4./P@;T(;#"4Y1``$^,Z```*6PV$ +MXC@`@.(&$*#A_O__ZP!04.+P@;T(_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B +M!""#Y0@XE>4``%/C$0``"@P(E>4``%#C#@``"O[__^L`8%#B#```"@R(E>4& +M`*#A"!B5Y0@@H.'^___K"`B5Y0P8E>7^___K`#"@XP@XA>4,.(7E````Z@!@ +MH.,-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K``!6XP``6!,&```*!`"@ +MX080H.$((*#A_O__ZP8`H.$($*#A_O__ZP0`H.$%$*#A_O__ZP0`H.$%$*#A +M_O__Z_"!O>A;783B.%"%X@4`H.$&$*#A_O__ZP``4./P@;T8!0"@X080H.'^ +M___K`%!0XO"!O0@`,*#CW#"%Y0@PEN78,(7E>#L#XP/`E.<``%SC!```"@0` +MH.$`$*#C!2"@X0$PH.,\_R_A!`"@X040H.'^___KR#@!XP,PE.<"`%/CS#@! +M`P,PE`?L,(4%`#"@X^@PA>7^___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/E +M;#"4Y4``$^,!```:(``3XQD```H(.`'C`S"4YP(`4^,5```:_O__ZPT@H.%_ +M/<+C/S##XP0@D^4!((+B!""#Y80`A.+@$(3B_O__ZP``4.,!,*`3##"`%0T@ +MH.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^L$`*#A_O__ZPT@H.%_/<+C/S## +MXP0@D^4!($+B!""#Y?[__^L$`*#A!1"@X?[__^OP@;WH^$\MZ0!`H.$!4*#A +M(`"!XN`0A.(&(*#C_O__ZP!@H.&0,)7E>#"#XAPPA>7>#U/C,P$`BO[__^L- +M$*#A?SW!XS\PP^,$()/E`2""X@0@@^48,)7E``!3XQ$!`-K^___K#2"@X7\] +MPN,_,,/C!""3Y0$@@N($((/E`#``XP`P0.,`(*#C`"##Y6PPE.6``!/C^P`` +M"EN]A.(XL(OB`0`3XRT```H!`%;C!```&H0`A.+@$(3B_O__ZP!@H.$R``#J +MA'"$XN!@A.('`*#A!A"@X?[__^L``%#C`#"@$PPP@!4+`*#A!A"@X?[__^L` +M@%#B#0``"O[__^L-,*#A?VW#XS]@QN,$,);E`3"#X@0PAN4$`*#A"!"@X?[_ +M_^L$,);E`3!#X@0PAN7^___K!P"@X2`0A>+^___K`&"@X6PPE.4(`!/C$``` +M"@``4.,!,*`3##"`%0X``!I+``#JA`"$XB`0A>+^___K`&"@X6PPE.4(`!/C +M!```"@``4.,!,*`3##"`%0(``!H_``#J``!6XST```K<`(3B'!"%XAP@E>7^ +M___K&#"5Y=0PA.5:K83B**"*X@!P`.,`<$#C`#"7Y=R6`>,)$)3G9""@XY(! +M`>#3C03C8H!!XY@A@>`*`*#A(1.#X/[__^N,(-;EG#8!XP,@Q.>-(-;EG38! +MXP,@Q.>,(-;E`2""XJ(@H.%?($+BFC8!XP,@Q.<`,)?E"2"4YV00H..1`@+@ +MF!*(X`H`H.$H$X/@_O__ZW@PE>4``%/C(#"@`VPPA`4#```*`0!3XP@PH`,` +M,*`3;#"$Y00`H.$6'H3B4"&4Y?[__^L$`*#A51^$XE`AE.7^___K;#"4Y0@` +M$^-S```*!P``Z@T@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^N5``#J('"% +MX@L`H.$'$*#A_O__ZP!@4.($```:"P"@X0<0H.'^___K`&!0XE4```H8,)7E +MU#"&Y0`PH./8,(;E>#L#XP/`E.<``%SC!```"@0`H.$`$*#C!B"@X0$PH.,\ +M_R_AR#@!XP,PE.<"`%/C'P``&@!0H.,@/`'C`U#$YR$\`>,#4,3G(SP!XP-0 +MQ.,#,)3G[#"&Y1$.AN(%$*#A$""@X_[__^L!#(;B!1"@ +MX1`@H./^___K\`"&X@40H.$0(*#C_O__ZQ(.AN(%$*#A"""@X_[__^M*#X;B +M!1"@X0@@H./^___K>C^&X@`@H.,"P*#A`!#@XT``H.,`P,/ELA##X;00P^$& +M`,/E`2""XD@P@^(0`%+C]___&@0`H.'^___K``!0XPP```IZ/X#B`""@XP+` +MH.$`$.#C0`"@XP#`P^6R$,/AM!##X08`P^4!((+B2#"#XA``4N/W__\:!`"@ +MX080H.'^___K;#"4Y0@`$^,(```:"0``Z@T0H.%_/<'C/S##XP0@D^4!($+B +M!""#Y?[__^LL``#J!`"@X?[__^M%#H3B"`"`XO[__^L-(*#A?SW"XS\PP^,$ +M()/E`2!"X@0@@^7^___K'P``Z@T0H.%_/<'C/S##XP0@D^4!($+B!""#Y?[_ +M_^L7``#J!`!SXPP``!H$`*#A_O__ZP`P`.,`,$#C`!"3Y44.A.((`(#B_O__ +MZVPPE.6``!/C@###$VPPA!4(``#J`#``XP`P0.,`$)/E10Z$X@@`@.+^___K +M;#"4Y8`PP^-L,(3E#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__Z_B/O>CP +M02WI`$"@X0%0H.%L,)#E&``3XQ(```I;#8#B.`"`XN`0A.+^___K`'"@X?[_ +M_^L-(*#A?VW"XS]@QN,$,);E`3"#X@0PAN4$`*#A!Q"@X?[__^L$,);E`3!# +MX@0PAN7^___K;#"4Y7``$^,4```*!`"@X?[__^L$`*#A_O__ZP!PH.'^___K +M#3"@X7]MP^,_8,;C!#"6Y0$P@^($,(;E!`"@X0<0H.'^___K!#"6Y0$P0^($ +M,(;E_O__ZP0`H.'^___K``!5XP8```K^___K#2"@X7\]PN,_,,/C!""3Y0$@ +M@N($((/EA`"$XN`0A.+^___K`!!0X@`PH!,,,($5;#"4Y4``$^,%```*"#@! +MXP,PE.(`,*#A-"P!XP+`D.=, +M()'E&`H!XP``T^6@`('B#!!#X@`@H.,$,(WB_O__ZP`` +M4.(!`*`3%P``Z@(/`N,``-/G`0!0XP$`H!,%```:`0!""1Y3@QD^4#`%+A``"@$PC0C>(0@+WH\$\MZ1303>(`0*#A`'"@XP]PS>7^ +M___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/E&&"$X@@PE.4`,(WE&#"4Y0PP +MA.5,D(3B++"$XH`@A.($((WE;(!$X@:@H.,V``#J##"4Y0-0H.$``%/C6``` +M"@`PD^4,,(3E(#24Y0$`4^,%```:(`"%X@D0H.$*(*#A_O__ZP``4.,G```* +M*""4Y0``4N,'```**#"5Y0,`4N$A```:+`"%X@L0H.'^___K``!0XQP```H( +M`*#A!1"@X?[__^L``%#C%P``"@8PU.4``%/C#0``"A``E>7^___KSS<`XP,` +M4.$/``#**""5Y7PPE.4#`%+A"P``&BP`A>($$)WE_O__ZP$`4.,&```:``!7 +MXP,```I0()?E4#"5Y0,`4N$```"J!7"@X08`H.$,$)3E_O__ZP``4./#__\* +M``!7XQX```H`4)WE`#"4Y0$`$^,&```*!0"@X?[__^L%`*#A_O__ZP4`H.$` +M$*#C_O__ZP4`H.$!$*#C#R"-XFP[`^,/X*#A`_"5YP\PW>4!`%/C!0``&@4` +MH.$"$*#C#B"-XFP[`^,/X*#A`_"5YP4`H.$'$*#A_O__ZP!`H.$```#J`$"@ +MXPT@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^L$`*#A%-"-XO"/O>@00"WI +M`$"@X?[__^L-(*#A?SW"XS\PP^,$()/E`2""X@0@@^4$`*#A_O__ZP$`4.,` +M0*`#`$"4%00PE!4`()05!#""%0`@@Q4`0(05!$"$%0T@H.%_/<+C/S##XP0@ +MD^4!($+B!""#Y?[__^L$`*#A$("]Z!!`+>D`0*#A_O__ZP(PH.,`,,3E$3"@ +MXP$PQ.5X,.#C`C#$Y0,`Q.4@-*#A!##$Y2`(H.$%`,3E$("]Z/!`+>D,T$WB +M`$"@X0%0H.$!<*#A6PV`XC@`@.+^___K`&!0X@@```JX/=;A`S2@X0@@C>*R +M,&+A!`"@X4$0H.-D.P/C#^"@X0/PE.=L,)3E$``3XP0```H$`*#A!Q"@X;8@ +MU>'^___KA0``ZFQPA.($`*#A_O__Z_[__^L-(*#A?SW"XS\PP^,$()/E`2"" +MX@0@@^5L,)3E"``3XRD```IR,-3E``!3XP$P0Q(*/P(#`S#4!W(PQ.6V(-7A +M_S\/XP,`4N$`,*`34'`*#A_O__ZPT@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^L$`*#AP!"$ +MXO[__^ML,)3E0``3XP$``!H@`!/C0@``"O[__^L-,*#A?UW#XS]0Q>,$,)7E +M`3"#X@0PA>4$`*#A!A"@X?[__^L$,)7E`3!#X@0PA>7^___K"#@!XP,PE.CP02WI`$"@X?[__^L-`*#A?SW`XS\PP^,$()/E`2"" +MX@0@@^4`,*#C7#>$Y6PPE.4""Q/C!P``"DD.A.($`(#B_O__ZVPPE.4".\/C +M;#"$Y0`PH.-P,,3E`#``XP`P0.,`,)/EW"8!XP(@E.=D$*#CD0(!X-,M!.-B +M($'CD@&!X%H-A.(H`(#B(1.#X/[__^MQ,-3E`0!3XUX``!IL`(3B;#"4Y2`` +M$^,H```*`0`3XU@``!J`,(/C;#"$Y?[__^L!`%#C"```&@`P`.,`,$#C`!"3 +MY44.A.((`(#BHA^!X@(0@>+^___K2@``ZFPPE.4".\/C;#"$Y0!@H.-P8,3E +MKGV$X@Y0A^(%`*#A!A"@X20@H./^___K!0"@X900A.(D(*#C_O__ZP0`H.'^ +M___K!@"'XO[__^M`,*#C;#"$Y00`H.'^___K<6#$Y3$``.J`,(/C;#"$Y0`P +MH.-Q,,3E_O__ZP$`4.,(```:`#``XP`P0.,`$)/E10Z$X@@`@.*B'X'B`A"! +MXO[__^LA``#J`@!0XP4``!IL,)3E@###XVPPA.4$`*#A_O__ZQD``.IR,-3E +M``!3XQ,```H!,$/BD`4*#A +M`F"@X0!`4>)P@+T(##"4Y0$`4^-P@+T(_O__ZP`@E>5``!+C`@``&B``$N,4 +M(*`#````"@$@H.,``%;C!@``&A`PE.4``&/@'S4(X^LQ1>.3$(/@HP)2X7"` +MO8C^___K#3"@X7]MP^,_8,;C!#"6Y0$P@^($,(;E#`"4Z`0P@N4`((/E`$"$ +MY01`A.4$`*#A$!"%XO[__^LD,)7E`3!#XB0PA>4$,);E`3!#X@0PAN7^___K +M<("]Z!!`+>G^___K$("]Z/!!+>D`0*#A`6"@X6QP@.+^___K#2"@X7\]PN,_ +M,,/C!""3Y0$@@N($((/EA%"$XH1`E.4$``#J!!"@X0!`E.4'`*#A!B"@X?[_ +M_^L%`*#A!!"@X?[__^L``%#C]?__"@T@H.%_/<+C/S##XP0@D^4!($+B!""# +MY?[__^OP@;WH$$`MZ?[__^L0@+WH<$`MZ0!0H.'^___K#2"@X7\]PN,_,,/C +M!""3Y0$@@N($((/E$`"%XO[__^L!`%#C`$"@`P\```H00)7E#`"4Z`0P@N4` +M((/E`$"$Y01`A.4`8*#C"&"$Y0Q@A.7^___K$`"$Y11@A.488(3E)#"5Y0$P +M@^(D,(7E#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__ZP0`H.%P@+WH$$`M +MZ?[__^L0@+WH\$GW_^L``%#C"0``&@``5N,$```*$""4Y1`PEN4",&/@``!3XP`` +M`*H%8*#A`$"4Y>K__^H(`*#A!!"@X?[__^L!`%#C/P``&GP`BN+^___K`0!0 +MXQ@``!H*`*#A`A"@XW(@A^)L.P/C#^"@X0/PFN=T,-?E=2#7Y0(T@^%V(-?E +M`CB#X7<@U^4"+(/A'`"&X@<0H.%X((+B_O__ZP!`H.,,0(;E_O__ZQ``AN4( +M0(;E%$"&Y1A`AN4U``#J;`"*XO[__^L`4%#B,0``"G0PU^5U(-?E`C2#X78@ +MU^4".(/A=T#7Y01,@^%X0(3B`$#'Y20TH.$!,,?E)#B@X0(PQ^4D/*#A`S#' +MY0H`H.$"$*#C('$*#A!""@X?[__^O^___K +M$`"%Y04`H.$($*#A_O__ZQ(``.K^___K$`"%Y70PU^5U(-?E`C2#X78@U^4" +M.(/A=R#7Y0(\@^&0()7E`P!2X0(``)H*,-?E`0!3XP,```H<`(7B!Q"@X0H@ +MH.'!]__K#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__Z_"'O>AP0"WI`$"@ +MX0%@H.$!`*#A#A"@X_[__^ML,)3E`0`3XPT```K<4(3B!0"@X080H.%P]__K +M``!0XP<```H%`*#A!A"@X00@H.&F]__K!`"@X18>A.)0(93E_O__ZP0`H.$& +M$*#A_O__ZW"`O>AP0"WI`%"@X0%`H.%T,-'E=2#1Y0(T@^%V(-'E`CB#X7<@ +MT>4"/(/A>#"#XMX/4^-P@+V(_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B!""# +MY6PPE>5``!/C*0``"N``A>($$(3B!B"@X_[__^L``%#C(P``"GA@A.)5#X7B +M!A"@X0@@H./^___K_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B!""#Y80`A>($ +M$(3B_O__ZP``4.,+```*E`"`X@80H.$((*#C_O__ZPT@H.%_/<+C/S##XP0@ +MD^4!($+B!""#Y?[__^L2``#J#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__ +MZVPPE>6``!/C"```&A`PU.4``%/C###$!0TPQ`4.,,0%#S#$!04`H.$$$*#A +M_O__ZPT@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^MP@+WH$$`MZ0!`H.'^ +M___K&`"$XO[__^L@`(3B_O__ZQ"`O>@00"WI`$"@X?[__^L``%3C$("]"`0` +MH.'^___K(`"4Y0``4.,0@+T(`!H,XP$00./^___K$("]Z!!`+>G^___K$("] +MZ/!!+>D`<*#A=`"'Y0!`H.-X0(#E;$"`Y0(PH.,X,8#E`3"@XU@U@.5L`(#B +M_O__ZWP`A^+^___KA`"'XO[__^O^___K#2"@X7\]PN,_,,/C!""3Y0$@@N($ +M((/ED$"'Y00@D^4!($+B!""#Y?[__^N4`(?B!!"@X20@H./^___K``H,XP$` +M0./^___K`$!0XO"!O0B,0(?E?&"'XG);A.("7(7B!`"@X?[__^L$`*#A!A"@ +MX?[__^OE3X3B!0!4X??__QH'`*#A_O__ZP$`H./P@;WH$$`MZ?[__^L0@+WH +M`##0Y0``4^,(```*`0!3X0,``!H(``#J#`"`X@$`4^$%```*###0Y0``4^/Y +M__\:``!3X@$`H!,>_R_A`0"@XQ[_+^$`,*#C?\#@XP,`T>=_(`#B`B!"XBX` +M4N,"\9^7,```ZMRF``#DI@``W*8``.2F``#DI@``Y*8``.2F``#DI@``Y*8` +M`-RF``#_R_A`0"@ +MXQ[_+^$!`*#C'O\OX0$`H.,>_R_A`0"@XQ[_+^$!`*#C'O\OX?!!+>D`@*#A +M`7"@X7PPD>484-/E`#"@XP-`H.$`8`#C`&!`XX,P@^`#,8;@`""3Y0(`5>$# +M```:"`"@X0<0H.$/X*#A"/"3Y0%`A.($,*#A"P!4X_+__QH!`*#C\(&]Z`$` +MH.,>_R_A$$`MZ0`PH.'0*P/C`B"0YP$`4N,0@+T(S"L#XP(@D.@P`"WI,-!-X@%`H.$`4`#C`%!`XPW`H.$/`+7H +M#P"LZ`\`M>@/`*SH#P"5Z`<`K.@`,,SE`##=Y00`4^$)```*`3"@XPT0H.$# +M(-'G!`!2X00```H!,(/B+0!3X_G__QH``*#C````Z@$`H.,PT(WB,`"]Z![_ +M+^$$X"WE#-!-X@`PH.$<*Y#E`R`"X@(`4N,$```:#!"@XP0@C>)LRP/C#^"@ +MX0SPD^<,T(WB`("]Z```4.,>_R\!A#:0Y0$`4^,>_R\1B#:0Y0$`4^,>_R\1 +MG#;0Y0``4^,`,*`3G#;`%1[_+^$``*#C'O\OX03@+>4,T$WB`#"@X0`@T>4$ +M`%+C`R"@`QPK@`4'(,T%#```"@$`4N,&```:'"N0Y0,@PN,"((+C'"N`Y0(@ +MH.,'(,WE`P``Z@``4N,!(*`#`""@$P<@S>4#`*#A`A"@XP<@C>)DRP/C#^"@ +MX0SPD^<``*#C#-"-X@"`O>@`,-'E`P!3XS`[@)4``*#C'O\OX0``4>,$`*`# +M``"@$Q[_+^$P`"WI`#"@X0``H.,&+:#C6A^@XP)`D^@>_R_A`#"@ +MX=@DD.4!`%+C``"@`Q[_+P%\)P#CLB"3X00`$N,'```:3Y0``4>,,```* +M!"""XWP7`..Q((/A`0"@XP@``.IP%Y/E``!1XP0``!H$(,+C?!<`X[$@@^$! +M`*#C````Z@``H.-\)P#CLB"3X1``$N,*```:T!23Y0``4>,"```:>!>3Y0`` +M4>,1```*$"""XWP7`..Q((/A`0"`X@D``.K0%)/E``!1XQ@``!IX%Y/E``!1 +MXP8``!H0(,+C?!<`X[$@@^$!`(#BT"23Y0``4N,.```:?"<`X[(@D^$$`!+C +M"@``&O`DD^4"#!+C`P``"G0GD^4``%+C`B"@$P0``!IX)Y/E`"!2X@$@H!,` +M``#J`R"@XWP7`..Q$)/A`\`!X@(`7.$>_R\!`Q#!XP$@@N%\QP#CO""#X0$` +M@.(>_R_A`#"@X\@WP.4@)`'C`C#`YV`W@.5D-X#E:#>`Y7`W@.70-(#E=#>` +MY6PW@.5X-X#E?"<`X[(P@.$#$*#A`R"`X`8K@N(\((+B`!""Y00P@^*``%/C +M^/__&@`PH..`-X#EB#>`Y8PW@.6@-X#EJ#>`Y1[_+^$``%'C!`"@`P``H!,> +M_R_A!0"@XQ[_+^$%`*#C'O\OX?A/+>D`8*#A`4"@X0)0H.$"`*#A`!"@XW(O +MH./^___K?P!4XT``5!,``*"#^(^]B&([`N,#,-;G`@`3XP!@H`,&(*`!!@`` +M"G\`5.,"8*`#`"``$P`@0!.$(((0,%0$@H.,$`!/C`+"@`PN0H`$&```* +M?P!4XP6PH`,`,``3`#!`$X0P@Q`QL-,5`9"@XP``4N,``*`#+0``"@`P`.,` +M,$#C!B)FX`(P@^#"`-/E``!0XR8```H`,*#C`R"@X0;"9N`4$9_E#,"!X`.@ +MH.$!<*#C`A#<)`%3C"P``&@&`0>)X@._F"@!8XP,0A9`$<(&5$``` +MF@P00>)Q$._F`@!1XP,0A9`$H(&5"@``ZA,`5.,*`%03`P``"@``5N,#$(40 +M!'"!%0,``!H+`%'C`Q"%X`1P@94$H(&%`2""X@PP@^)R$._F`0!0X=___XH` +M`%GC^(^]"``P`.,`,$#C"R&+X`(A@N`",(/@&,'3Y0``7./XC[T(`#"@XP*P +MH.%88)_E`F"&X`&`H.,#<*#A`R#6YS$00N)Q$._F8P!1XP@``)J`$(#@`1&% +MX``@P>43`%3C"""@$0<@H`$$(('E`0"`XG``[^8!,(/B___Z^('Q.4``*#C$("]Z'!`+>D`4*#A`4"@X0$`H.$`$*#C6""@X_[_ +M_^L8,*#CNC#$X0$PH.,4,,3E!S"@XR@PQ.4`,*#C*C#$Y1(@H.-/(,3E##"$ +MY>$WU>4!`!/C!C"@$P4PH`-',,3E`#"@XQ4PQ.4",,3E13#$Y48PQ.5(,,3E +M23#$Y4HPQ.7<-P#CLS"5X;8PQ.$!,*#C4S#$Y7"`O>CP12WI#-!-X@"`H.$! +M8*#AT#"1Y0$`$^-=```*``!1XUL```H!4*#A`'"@XP=`H.$P`=7E``!0XP(` +M``I_``#B_O__ZP!PA^$!0(3B`5"%XA``5./U__\:A#:6Y0``4^,`4*`#'P`` +M"@@`H.$4$*#C!R"-XF@[`^,/X*#A`_"8YP?@W>4"`%[C$."@`PC@H!,`,*#C +MF,8`XP%`H.,'((/B``!3XP,@H*'"(8;@#"""X`@0TN7#+Z#AHBZ@X0(`@^`' +M``#B`"!BX%$BH.$!`!+C#""#$A1RAQ$!,(/B#@!3X>W__[J:5M;E)#&8Y0X` +M4^,$``":_S['X_\BT^,4`*`3!`"@`P8``.K_/L?C_R+3XPL`H!,"```:_PX7 +MXP,`H!,!`*`#_O__ZP!`H.$/`L?C_O__Z]0PEN4?`%/C%```BC^@`.+8(-;E +M'R`"XH`@@N,!`%7C!P``&@@`H.$$'H?A("""XX0[`^,/X*#A`_"8YT"@BN,$ +M``#J"`"@X00>A^&$.P/C#^"@X0/PF.=.0<;E3Z'&Y0S0C>+PA;WH\$(!0*#A>("!XG0PT>5U$-'E`32#X780U.4!.(/A=Q#4Y0$\@^&$`(3B`A"@ +MX00@C>(,,$/B_O__ZP!P4.(R```*!)"=Y0``6>,O```*`I")X@20C>5T,-3E +M=6#4Y09D@^%V,-3E`VB&X7+PA[WH +M`&"@X_+__^KP3RWI#-!-X@%0H.$"0*#A`Z"@X3!@W>5X@('B=##1Y77@T>4. +MY(/A=C#1Y0/HCN%W<-'E!^R.X0P`7N,7``":"'"@X0$@H.&$,/+E`P!4X1(` +M`#H$`%/A##"@$PD``!H$``#J`R"'X``0TN4$`%'A"@``B@,``!H"`*#A`<#2 +MY0$PH.,&``#J`@"@X0'`TN4"((SB`C"#X`,`7N'P__^*`#"@XP``4.,``%P3 +M`'"@`S,```H"P(SB#""`X``@C>4`<&C@#N!GX`*PH.$``%/C`+"@$0QP7N`I +M```*!P"@X?[__^L`D*#A`#!0X@$PH!,$,(WE`""=Y0``4N,``%`3`@``"@(0 +MH.$'(*#A_O__ZP%`R^0+0*#A`6#$Y`0`H.$*$*#A!B"@X?[__^L&0(3@!#"= +MY0``4^,&```*!`"@X0D0H.$'(*#A_O__ZPD`H.$'$*#A_O__ZP1`:.`'<(3@ +M='#%Y24G?*#A=W#%Y0S0C>+PC[WH`4#+Y`M`H.$! +M8,3D!`"@X0H0H.$&(*#A_O__ZP9`A.#K___J\$$MZ0!0H.$!8*#A`$"@XP9P +MH..&@0#C!!"&X`4`H.$A$('B!R"@X?[__^L``%#C`0``"@$`H./P@;WH)T"$ +MX@@`5.'S__\:``"@X_"!O>CP0"WI#-!-X@!PH.$!0*#A`F"@X0TPH.%H()_E +M`P"2Z`0`@^2P$,/A?%"6Y0@PE.4``%/C$0``"@10A>(%`*#A#1N'XA$0@>(& +M(*#C_O__ZP``4.,%```:!0"@X0T0H.$&(*#C_O__ZP``4.,#```*!P"@X080 +MH.$/X*#A"/"4Y0S0C>+P@+WH;!$``/!'+>D(T$WB`'"@X0%0H.$"0*#A?&"1 +MY70PD>48,$/B!#"-Y0,,4^,A`0"*`@"@X0`0H./>+Z#C_O__Z[`PUN'\,`/B +M@`!3XP$PH`,`,*`3"C#$Y0B`C>($(#CE>#""X@`PQ.4C%*#A`1#$Y2,8H.$" +M$,3E(SR@X0,PQ.5T(,3E(C2@X74PQ.4B.*#A=C#$Y2(\H.%W,,3E>`"$XA@0 +MAN+^___KVS;5X30PQ.4C+*#A-2#$Y38@Q.4W(,3E93#5Y7$PQ.5M,-7E<##$ +MY0<`H.$"$*#C4(`%+CMP``B@H`H.$" +M$('B_O__ZP20G>5T,-3E=2#4Y0(T@^%V(-3E`CB#X7<@U.4"/(/A!0"@X3(0 +MH.,((*#A##!#XO[__^L`$%#B!@``"@0@G>40,&GB`@!3X:$``#H)`(K@`A"! +MXO[__^L`H*#C`Q"@XS@0Q.4YH,3E.J#$Y3N@Q.5T,-3E=2#4Y0(T@^%V(-3E +M`CB#X7<@U.4"/(/A!0"@X0@@H.$,,$/B_O__ZTB@Q.5)H,3E2J#$Y4N@Q.4\ +MH,3E/:#$Y3Z@Q.4_H,3E``!0XP4```H",-#E2##$Y4F@Q.5*H,3E2Z#$Y2`` +M`.IT,-3E=2#4Y0(T@^%V(-3E`CB#X7<@U.4"/(/A!0"@X3T0H.,((*#A##!# +MXO[__^L``%#C!@``"@(PT.5(,,3E`#"@XTDPQ.5*,,3E2S#$Y0L``.K(.9?E +M`P!3X]`YEP4,(*`#DG,C`.0WTP7>-]<52##$Y0`PH.-),,3E2C#$Y4LPQ.5X +M`(3B_O__ZP`0H.%``(3B`B"@X_[__^L$`*#A_O__ZP"@H.$!`!#C"@``"@`P +MH.,!(*#C7"#$Y5TPQ.5>,,3E7S#$Y00`A.(*$(;B!B"@X_[__^L(``#J`#"@ +MXUPPQ.5=,,3E7C#$Y5\PQ.4$`(3B$!"&X@8@H./^___K$``:XP`PH.,!(*`3 +M,"#$%3`PQ`4Q,,3E,C#$Y3,PQ.4`,*#C1##$Y44PQ.5&,,3E1S#$Y0(_`N,# +M,-?G`0!3XQP``!K<.]?E``!3XQD``!IT,-3E=2#4Y0(T@^%V(-3E`CB#X7<@ +MU.4"/(/A!0"@X2T0H.,((*#A##!#XO[__^L``%#C"```"@0PG>4``%/C!0`` +M"@,PT.5``!/CU#27%0$P@Q+4-(<5`@``ZM`TE^4!,(/BT#2'Y4@PU.5)(-3E +M`C2#X4H@U.4".(/A2R#4Y0(L@^'0.9?E@S"#X`-QA^#D-]?E`P!2X64PH!-Q +M,,05`0"@XP```.H``*#C"-"-XO"'O>@00"WIWA?0Y>`GT.7?-]#E_O__ZP$` +MH.,0@+WH$$`MZ0!`H.$?#8#B"`"`XO[__^L$`*#A_O__ZQ"`O>AP0"WI`%"@ +MX0%`H.$`()'E4FCGYQ@`5N,7``"*`#``XP`P0..&,8/@Y#*3Y0``4^,"```* +MCREN5\-`'C`R"5YP$@@N(#((7G``"@XW"`O>CP02WI`'"@X1P` +MH./^___K`%"@X0!`H.$``%#C``"@`_"!O0C>#Z#C_O__ZP!@H.$``%;C!``` +M&@4`H.$<$*#C_O__ZP``H./P@;WHPAZ'X@P0@>+>+Z#C_O__ZQ0`A>+^___K +M-S"@X[`PQ>$$8(7EWC^@XP@PA>4`,*#C##"%Y1`PA>4%"X?B*`"`X@40H.'^ +M___K<`#OYO"!O>CP1RWI$-!-X@%0H.$"<*#A`V"@X0!`4.+;```*(#0!XP,P +MU.<``%/CUP``"O[__^L-(*#A?SW"XS\PP^,$()/E`2""X@0@@^4%`%7C`@`` +M"MT`5>._```:;@``ZLJ.A.($D(CBOC@!X[,PE.&^,,WA$("(XJ`\E.4(`*#A +M!1"@XP0@C>(,,$/B_O__ZP!04.(*```*!'"=Y0``5^,'```*`G"'X@1PC>4' +MH(7@!3!IX*`LE.4",&/@`W!GX!8``.H`,*#C!#"-Y3A(%H(3@RJZ* +MX@2@BN*@?)3E!U!EX`0PG>4%<&/@"E"@X0``5^,`@*`#"```"@<`H.'^___K +M`("@X0``4.,``%H3`@``"@H0H.$'(*#A_O__ZP4PH.,!,,7DOC@!X[,PE.'_ +M#!/C`P``"OP`$^,%,*`3!#"-%0$``!H$,*#C!#"-Y00PG>4!,,7D`#"@XP$P +MQ>0!,*#C`3#%Y+XX`>.S,)3A`0`3XP$PH!,`,*`#`3#%Y`0PG>4$`%/C#C#= +M!0$PQ00&```*!0!3XP0``!H%`*#A#A"-X@(@H./^___K`E"%X@``6.,&```* +M!0"@X0@0H.$'(*#A_O__ZP@`H.$'$*#A_O__ZP50:>`'<(7@H'R$Y00`H.'^ +M___K3P``ZG0!G^4'$*#A!""@X_[__^L``%#C20``&F`!G^4'$*#A!""@X_[_ +M_^L``%#C0P``&DP!G^4'$*#A!""@X_[__^L``%#C.0``"@`@H.,0,(WB#"`C +MY`'4%7@`*"@`P<```H%`*#A_O__ZP"@4.(#```*"@"@X0<0B.`% +M(*#A_O__ZX`7E.4``%'C'P``"@$@T>4$((WE`B""X@DP@N`%,(/@`PQ3XPX` +M`(H(`*#A_O__ZP0`G>4``%KC!```"@(`@.(``(C@"A"@X04@H.'^___K!#"= +MY0(P@^(),(/@!3"#X*`\A.4``%KC!P``"@H`H.$%$*#A_O__ZP,``.I0`)_E +M!Q"@X00@H./^___K`3"@X\@WQ.4-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^ +M___K``!6XP$```H$`*#A_O__ZQ#0C>+PA[WHT`0``-0$``#8!```W`0``'!` +M+>D`4*#A`4"@X5@WD>4``%/C#0``JI4WT>4``%/C&```&@$PH..5-\'E8#>0 +MY0$P@^)@-X#E`0!3XQ$``!HJ$*#C`""@X_[__^L-``#JE3?1Y0``4^,*```* +M`#"@XY4WP>5@-Y#E`3!#XF`W@.4``%/C`P``&BH0H.,`(*#C`3"@X_[__^M4 +M-P#CLS"4X0$+$^,1```:EC?4Y0``4^,@```:`3"@XY8WQ.5D-Y7E`3"#XF0W +MA>7A)]7E`0!2XQ@``)H!`%/C%@``&@4`H.'_$*#C`""@X_[__^L1``#JEC?4 +MY0``4^,.```*`#"@XY8WQ.5D-Y7E`3!#XF0WA>7A)]7E`0!2XP8``)H``%/C +M!```&@4`H.'_$*#C`""@XP$PH./^___K6#>4Y8``$^,1```:ES?4Y0``4^,@ +M```:`3"@XY7A)]7E`0!2XQ@``)H!`%/C%@``&@4` +MH.'_$*#C`""@X_[__^L1``#JES?4Y0``4^,.```*`#"@XY7A)]7E`0!2XP8``)H``%/C!```&@4`H.'_$*#C`""@XP$PH./^___K +M6#>4Y0(+$^,<```*G#:4Y5,T[^>9)]3E``!2XP`@H!.9)\05T"25%0$@0A+0 +M)(45$``3XP8``!J8)]3E``!2XP$@H`.8)\0%<">5!0$@@@)P)X4%`@`3XP\` +M`!J:-]3E``!3XPP``!H!,*#CFC?$Y70WE>4!,(/B=#>%Y08``.J9-]3E``!3 +MXP$PH`.9-\0%T#25!0$P@P+0-(4%!0"@X83Z_^L``%#C<("]V`4`H.$M$*#C +M`""@XP(PH.'^___K!0"@X3T0H.,`(*#C`3"@X_[__^MP@+WH\$$MZ0!`H.'( +M.9#E`0!3X_"!O=@#`%/CT#F0!0$P@P+0.8`%#C0!XP,PT.(`4*#A`4"@X1P[D.4#,`/B`P!3XQP` +M`!H&,-'E``!3XP,``!H'$-'E_O__ZP$`H.,H``#J`6"@X5L-@.(X`(#B_O__ +MZP``4.,A```*!B#4Y=@PD.4!$$/B&P!1XQP``(H#,(/B`B&@X0A`A.(`0(WE +M!0"@X7,0[^8"*8+C!C"@X?[__^L!`*#C$@``Z@8@T>4``%+C`P``&@<0T>7^ +M___K``"@XPL``.H"(:#A"#"!X@`PC>4$$*#C`BF"XP0PH.'^___K!C#4Y3@[ +MA>4``*#C````Z@4`H.,(T(WB<("]Z`3@+>44T$WB`#"@XP@PS>4),,WE"C#- +MY0LPS>4,,,WE#3#-Y0,PT>4``%/C`3#1%3P[@!4!,-'E@RC@X03`T>2B*.#A +M#"&"X0`0C>4#$*#A+^___K``"@XQ30C>(`@+WH$$`MZ0!`H.$` +M,)#E``!3XQ"`O0C,*P/C`C"3YP$`4^,0@+T8O0Z`X@0`@.+^___K`PN$X@@` +M@.+^___K$("]Z'!`+>D`0*#A_O__ZP``4.,#```:!`"@X?[__^L``%#C<("] +M"&1;`^,$`*#A"Q"@XP`@H.,/X*#A!?"4YP0`H.$$$*#C`"``XP`@0.,/X*#A +M!?"4YP!0H./?5\3EX%?$Y00`H.'>%]3E!2"@X04PH.'^___K!`"@X?[__^L< +M6X3E!`"@X0(0H./^___K3PV$XA@`@.+^___K<("]Z#!`+>D,T$WB`$"@X0`` +M4>,-``"J"""-X@$PH.,!,&+E9%L#XPT0H.,/X*#A!?"4YP0`H.$$$*#C`"`` +MXP`@0.,/X*#A!?"4YV4``.H<.Y#E`S`#X@$`4^,+```:_O__ZP!04.((```* +MV#"5Y8,RA."D7X/E!`"@X=@0E>7^___K!`"@X=@0E>7^___K!`"@X0\2X.,! +M(*#C_O__ZP0`H.'^___K9%L#XP0`H.$&$*#C,BV$X@P@@N(/X*#A!?"4YP0` +MH.$.$*#C+RV$X@8@@N(/X*#A!?"4YP0`H.'(.P#CLQ"4X?[__^L$`*#A_O__ +MZP0`H.'^___K!`"@X=X7U.7@)]3EWS?4Y?[__^M;#83B.`"`XL,>A.+^___K +M`%!0XAP```K8,)7E@S*$X*1?@^4$`*#A!1"@X?[__^MD.P/C`S"4YP``4^,( +M```*F`"?Y9@0G^7^___K!`"@X4`0H./8((7B9#L#XP_@H.$#\)3GN#W5X0,T +MH.$!,(/C"""-XK0P8N$$`*#A01"@XV0[`^,/X*#A`_"4YP@@C>(",*#C`3!B +MY00`H.$-$*#C9#L#XP_@H.$#\)3G'#N4Y0,P`^("`%/C`@``&@0`H.%]'H3B +M_O__ZP0`H.$"$*#C`""@X_[__^L,T(WB,("]Z!P````T$@``<$`MZ0!0H.$! +M0*#A_O__Z]@TE>4``%/C#0``"@$PH..$-H3EW#25Y8@VA.4%`*#AOQZ%X@80 +M@>+^___K``!0XP$PH!.:-L05`3"@X]PPA.4$``#J`#"@XX0VA.6(-H3EFC;$ +MY=PPA.7?-]7EF#;$Y>`WU>69-L3E`#"@XYLVQ.6<-L3ES#25Y0``4^,!,*`3 +MW#"$%0$PH./0,(3E<("]Z/!'+>D`<*#A`8"@X0*@H.$<`*#C_O__ZP!@H.$` +M0*#A``!0X_"'O0@4`*#C_O__ZP!04.(#```:!@"@X1P0H./^___K\(>]Z!0` +MAN+^___K.#"@X[`PQN$4,*#C"#"&Y010AN4`,*#C##"&Y1`PAN4,,*#CL##% +MX0LPH.,",,7E?0Z'X@@`@.+^___K`P#%Y0A0A>(%`*#A"!"@X08@H./^___K +M"*"%Y04+A^(H`(#B!A"@X?[__^OPA[WH\$$MZ0C03>(`<*#A`8"@X;8@S>$< +M`*#C_O__ZP!@H.$`0*#A``!0XR4```H0`*#C_O__ZP!04.(#```:!@"@X1P0 +MH./^___K'0``ZA0`AN+^___K.#"@X[`PQN$0,*#C"#"&Y010AN4`,*#C##"& +MY1`PAN4(,*#CL##%X0PPH.,",,7E?0Z'X@@`@.+^___K`P#%Y0@`A>(($*#A +M!B"@X_[__^L.`(7B!A"-X@(@H./^___K!0N'XB@`@.(&$*#A_O__ZPC0C>+P +M@;WH\$$MZ0!@H.$<`*#C_O__ZP!PH.$`0*#A``!0X_"!O0@,`*#C_O__ZP!0 +M4.(#```:!P"@X1P0H./^___K\(&]Z!0`A^+^___K.#"@X[`PQ^$,,*#C"#"' +MY010A^4`,*#C##"'Y1`PA^4$,*#CL##%X0DPH.,",,7E?0Z&X@@`@.+^___K +M`P#%YCP02WI`8"@X0!@4.+P +M@;T('`"@X_[__^L`<*#A`$"@X0``4./P@;T(#@V@X_[__^L`4%#B`P``&@<` +MH.$<$*#C_O__Z_"!O>@4`(?B_O__ZS@PH..P,,?A#CV@XP@PA^4$4(?E`#"@ +MXPPPA^40,(?EWC^@X[`PQ>$(,*#C`C#%Y7T.AN(#`(#@_O__ZP,`Q>4&`*#A +M"!"@X0@@A>+^___K``!0XP8``!H'`*#A'!"@X_[__^L%`*#A#AV@X_[__^OP +M@;WH!0N&XB@`@.('$*#A_O__Z\PYEN4!,(/BS#F&Y?"!O>CP02WI`'"@X0&` +MH.$<`*#C_O__ZP!0H.$`0*#A``!0X_"!O0CG#Z#C_O__ZP!@4.(#```:!0"@ +MX1P0H./^___K\(&]Z!0`A>+^___K.#"@X[`PQ>'G/Z#C"#"%Y01@A>4`,*#C +M##"%Y1`PA>7E/Z#CL##&X0HPH.,",,;E?0Z'X@@`@.+^___K`P#&Y0A0AN(D +M`(;BPAZ'X@P0@>+>+Z#C_O__ZQ2`A>48@(7E!P"@X040H.'^___K!0N'XB@` +M@.($$*#A_O__Z_"!O>AP0"WI`$"@X0%0H.$"8*#AP@Z`X@P`@.+^___K`!"@ +MX04`H.$&(*#C_O__ZP``4.,3```*'#N4Y0,@`^("`%+C#P``&@$)$^,&```* +M`#"@XQP[A.4$`*#A!1"@X08@H.'^___K!@``ZB<,$^,$```*`#"@XQP[A.4$ +M`*#A`1#@X_[__^L!`*#C<("]Z#!`+>D,T$WB`$"@X<)>@.(,4(7B=#R0Y=XW +MP.4%`*#A_O__Z\8[`..S`(3A!`"@X?[__^L%`*#A_O__ZP!0H.$$`*#A!1"@ +MX?[__^L!`!7C)```"@0`H.$"$*#C_O__ZS`[E.4"`%/CS#"@`\\PH!,(((WB +M`3!BY00`H.$2$*#C9#L#XP_@H.$#\)3G!`"@X=X7U.7@)]3EWS?4Y?[__^O& +M.P#CLP"4X?[__^L`,`#C`#!`XP`PD^5D$*#CD0`!X-,M!.-B($'CD@&!X$\- +MA.(8`(#B(1.#X/[__^L",0#C'#N$Y1<``.H"`!7C%0``"@0`H.$!$*#C_O__ +MZP@@C>(P,.#C`3!BY00`H.$2$*#C9#L#XP_@H.$#\)3G!`"@X=X7U.7@)]3E +MWS?4Y?[__^L$`*#A_O__ZP$0H.,<&X3E!`"@X?[__^L,T(WB,("]Z'!`+>D` +M4*#A_O__ZP!`4.(.```*!0"@X?[__^L``%#C!```&@4`H.$$$*#A_O__ZP!` +MH.,%``#J`S"@XV0PA.5P`(3E$#"0Y6PPA.440(#E!`"@X7"`O>CP3RWII-!- +MX@!`H.&,,(WB`""@XP0@@^0$((/D!""#Y``@@^74-)#E`@!3X:\```K0-)#E +M`@!3X:P```K<.]#E`0!3XZD```H$,*#CGS#-Y9X@S>53#8#B(`"`XO[__^L` +M<%#BH0``"@0`H.$($(?B_O__ZVP`E^4`$*#C:""@X_[__^ML8)?E!E"@X0`P +MH.,H,.7E`3#%Y<*.A.(,@(CB"`"@X?[__^L`$*#A+`"&X@8@H./^___K,@"& +MX@T;A.(1$('B!B"@X_[__^L(`*#A_O__ZP`0H.$X`(;B!B"@X_[__^L&(*#A +MOA/RX=PW`..S`)3A#Q`!X@`2@>&P$,+ALR"4X0$@@N*S((3AL##5X?PPP^/0 +M,(/CL##%X0>PH.$8,*#C%#"KY4``AN(!$*#CGR"-X@LPH.'^___K`1"@XYX@ +MC>(+,*#A_O__ZPP`C>74-)3E``!3XP<``-J@,(WB!""@XY`@8^4`L(WE2!"@ +MXP$@H./^___K#`"-Y10`C>(`$*#C>""@X_[__^O0-)3E``!3XU```-K^___K +M#2"@X7\]PN,_,,/C!""3Y0$@@N($((/EA("$XH1@E.40H(WB+9"@XP10H.$( +M`*#A!A"@X?[__^L!`%#C&```"@9`H.$`8);ED#"4Y:``A.()$*#A"B"@X0PP +M0^+^___K``!0XP(```H0,)WE``!3X^W__QID,)3E`2!#X@T`4N/I__^*H,"- +MX@,PC.`!(*#CC"!#Y10PW>4``%/C%"#-!>'__^H%0*#A#<"@X7\]S.,_,,/C +M!""3Y0$@0N($((/E_O__ZQ10C>(`8*#C`:"@XPJ0H.$3@.#C#`"=Y0`PU>4! +M`%/C$0``&HQ@S>4*(*#A"3"@X0,0U>+PC[WH\$$MZ1C03>(`0*#A +M`8"@X0<@S>6T,,WA`S"@XQ53#8#B(`"`XO[__^L`4%#BRP``"@0`H.$( +M$(7B_O__ZVP`E>4`$*#C:""@X_[__^ML<)7E!V"@X0`PH.,H,.;E`3#&Y2P` +MA^(($*#A!B"@X_[__^LR`(?B#1N$XA$0@>(&(*#C_O__Z\(.A.(,`(#B_O__ +MZP`0H.$X`(?B!B"@X_[__^L'(*#AOA/RX=PW`..S`)3A#Q`!X@`2@>&P$,+A +MLR"4X0$@@N*S((3AL##6X?PPP^/0,(/CL##&X05@H.$8,*#C%#"FY4``A^(! +M$*#C%R"-X@8PH.'^___K`1"@XP<@C>(&,*#A_O__Z[0@W>$7,-WE`P!3XXP` +M`!H',-WE`0!3XS<```K:.]0U`@``.@(`4^.%```:=P``Z@$P@^)S,._F``!3 +MX_O__PK:.\3E`1"@X[TNA.(*((+B!C"@X?[__^NT,-WA#S`#X@,QH.$!.H/C +M`C"#XQ@@C>*T,&+A`A"@XP8PH.'^___K&""-XH@S`>.X,&+A`A"@XP8PH.'^ +M___K`'"@X5L-A.(X`(#B"!"@X?[__^L``%#C"P``"K0@W>$'(`+B@C"`X+@W +MT^$/.L/C`3"#XG,P_^8S+H+B@@"`X+0PP.$#,J#AOC#-X0<`H.$"$*#C#B"- +MX@8PH.'^___K40``Z@$0H..]+H3B#2""X@8PH.'^___K`A"@XP0@C>(&,*#A +M_O__ZP!PH.$$`*#A"Q"@XP@@C>)L.P/C#^"@X0/PE.<(,)WE`P!3XP4``!K> +M.P#CLS"4X3\P`^(!.H/CM#'-X18``.H"`%/C!0``&MX[`..S,)3A/S`#X@([ +M@^.T,$&``#J``!3 +MX]X[`..S,)3A/S`#X@(\@P,!.H,3M#'-X?X^`N,#,-3G``!3X[0QW0$!,,,# +MM#'-`0,```H!`%/CM#'=`0$P@P.T,+P@;WH\$$MZ0!`H.$!8*#A!'"!XEL-@.(X`(#B!Q"@X?[__^L`4%#B +M&0``"AP[E.4!"1/C`@``"M`KU.4``%+C`@``&@,P`^(#`%/C"P``&@0`H.$' +M$*#A`""@X[`PUN'^___K`#``XP`P0.,`$)/E&PZ%XL@0@>+^___K!```Z@`P +MEN6<)M7E`1"@XQ$SPN&<-L7E``"@X_"!O>CP1RWI`&"@X0%`H.$"@*#A'#N0 +MY0,@`^(#`%+C`0``"@$)$^,V```*6PV&XC@`@.(($*#A_O__ZP!04.(P```* +M``!4XQ,``!IZ7X7B`G"@XP2@H.$`D.#C`"#5Y0$`4N,'```:A#"@X08`H.$( +M$*#A!R"@X1XP`^+^___K`*#%Y;*0Q>$!0(3B2%"%XA``5./P__\:&@``Z@$` +M5.,8```:`$"@XP*@H.,!D*#C!'"@X9LVU>53-*#A`0`3XPT```J$,*#A`3"# +MXP8`H.$($*#A"B"@X1\P`^+^___K&73@X9LVU>4#,`?@FS;%Y9PVU>4#<`?@ +MG';%Y0%`A.(0`%3CZ?__&@$`H./PA[WH<$`MZ0!@H.$!0*#AU#"1Y0$P@^+8 +M,('E>#L#XP/`D.<``%SC`P``"@`0H.,$(*#A`3"@XSS_+^'(.`'C`S"6YP(` +M4^,!,*`#`#"@$^@PA.4&`*#A!!"@X?[__^N$-I3E``!3XQ0```K<-);EB#:$ +MY?`DEN6<-I3E4S3OYR(T`^!@`!/C`3"@$YHVQ!7P));EG#:4Y5,T[^!0A.(&`*#A`!"@XP4@H.'^___K!@"@X0$0H.,%(*#A_O__ZP`0 +MH..;%L3EG!;$Y58/A.)8(*#C_O__Z_[__^L-(*#A?SW"XS\PP^,$()/E`2"" +MX@0@@^70()3E`2""X]`@A.4$()/E`2!"X@0@@^7^___K<("]Z!!`+>E8-Y'E +M`@P3XP$@H!,`(*`#W""!Y(`0*#A`:"@X;8@ +MS>%3#8#B(`"`XO[__^L`4%#B-@``"@0`H.$($(7B_O__ZP"`H.-;@,7E;`"5 +MY0@0H.%H(*#C_O__ZVQPE>4'8*#A*(#FY0&`QN4L`(?B"A"@X08@H./^___K +M,@"'X@T;A.(1$('B!B"@X_[__^O"#H3B#`"`XO[__^L`$*#A.`"'X@8@H./^ +M___K!R"@X;X3\N'<-P#CLP"4X0\0`>(`$H'AL!#"X;,@E.$!((+BLR"$X;`P +MUN'\,,/CP#"#X[`PQN$%,*#A&""@XQ0@H^5``(?B`A"@XP8@C>+^___K%#"5 +MY1@PA>4$`*#A!1"@X?[__^L,T(WB\(6]Z'!`+>D`0*#A`%!1XG"`O0B5-]7E +M``!3XPH```H`,*#CE3?%Y6`WD.4!,$/B8#>`Y0``4^,#```:*A"@XP`@H.,! +M,*#C_O__ZY8WU>4``%/C#@``"@`PH..6-\7E9#>4Y0$P0^)D-X3EX2?4Y0$` +M4N,&``":``!3XP0``!H$`*#A_Q"@XP`@H.,!,*#C_O__ZY4``%/C#@`` +M"@`PH..7-\7E:#>4Y0$P0^)H-X3EX2?4Y0$`4N,&``":``!3XP0``!H$`*#A +M_Q"@XP`@H.,!,*#C_O__ZY@WU>4``%/C`#"@$Y@WQ15P-Y05`3!#$G`WA!69 +M-]7E``!3XP`PH!.9-\45T#24%0$P0Q+0-(05FC?5Y0``4^,`,*`3FC?%%70W +ME!4!,$,2=#>$%00`H.&8]/_K``!0XPD``-H$`*#A+1"@XP`@H.,",*#A_O__ +MZP0`H.$]$*#C`""@XP$PH./^___KX&"%X@0`H.$`$*#C!B"@X?[__^L$`*#A +M`1"@XP8@H.'^___K`#"@XYLVQ>6<-L7E!`"@X080H.$#(*#C_O__Z]@@U>4# +M((+B!`"@X040H.%R(._F`3"@X_[__^NH/`/C`S"4YP0PD^4#`%/C!```&@0` +MH.$&$*#A`R"@X_[__^L"``#J!`"@X040H.'^___K_O__ZPTPH.%_;4``%/C'0``"@$P +M0^+(-H7E``!3XQD``!H;/87BQ":5Y<`6E>4$(('E`!""Y<`VA>7$-H7E!#"8 +MY0$P0^($,(CE_O__Z_[__^L$,)KE`3"#X@0PBN4&`*#A!1"@X?[__^L$,)GE +M`3!#X@0PB>7^___K_O__ZP0PF^4!,(/B!#"+Y0<`H.$$$*#A_O__ZP``4./7 +M__\*#3"@X7]-P^,_0,3C!#"4Y0$P0^($,(3E_O__Z_[__^L$,)3E`3"#X@0P +MA.4&>X;B('"'XB`X`>,#4);G.(@!XP"@H.,!D*#C/@``ZFM.1>((0$3B`%"5 +MY00`H.'^___K``!0XP@PEA?(-H05!*C$%<@VE.4``%/C,@``"@$P0^+(-H3E +M6">4Y0(+$N,8```*FR;4Y0``4N,"```:!"C4Y0``4N,2```*"""6YS(00N(! +M`%/A!*C$EAP0"WI"-!-X@!0H.$-,*#AR""?Y0,` +MDN@$`(/DL!##X1P[E>4#,`/B`P!3XR@``!K^___K#2"@X7\]PN,_,,/C!""3 +MY0$@@N($((/E!FN%XB!@AN(@.`'C`T"5YPP``.IK'D3B"!!!X@!`E.5K/H'B +M"#"#XKPFD>6X!I'E!""`Y0``@N6X-H'EO#:!Y04`H.'^___K!@"@X000H.'^ +M___K``!0X^W__PH-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K!0"@X0T0 +MH.$#(*#C_O__ZP``H.,(T(WB<("]Z%02``!P0"WI`$"@X0`PH./(-\#E("0! +MXP(PP.?^___K!`"@X?[__^L$`*#A_O__ZP!@H.'^___K#3"@X7]=P^,_4,7C +M!#"5Y0$P@^($,(7E!`"@X080H.'^___K!#"5Y0$P0^($,(7E_O__ZP0`H.'^ +M___K;`"$XO[__^MP@+WH<$`MZ0!`H.$`4*#CR%?`Y2`T`>,#4,#G_O__ZQQ; +MA.4$`*#A_O__ZP0`H.'^___K`&"@X?[__^L-,*#A?UW#XS]0Q>,$,)7E`3"# +MX@0PA>4$`*#A!A"@X?[__^L$,)7E`3!#X@0PA>7^___K'PV$X@@`@.+^___K +M<("]Z#!`+>D,T$WB`$"@X?[__^L``%#C`P``"@0`H.'#'H3B`R"@X_[__^L` +M(*#C'"N$Y61;`^,$`*#A"Q"@XP_@H.$%\)3G!`"@X000H.,`(`#C`"!`XP_@ +MH.$%\)3G'#N4Y0,P`^(#`%/C`0!3$P8``!H(((WB`#"@XP$P8N4$`*#A"!"@ +MXP_@H.$%\)3G!`"@X0(0H./^___K`%"@XQQ;A.7?5\3EX%?$Y00`H.'>%]3E +M!2"@X04PH.'^___K!`"@X?[__^M/#83B&`"`XO[__^L%`*#A#-"-XC"`O>CP +M3RWI#-!-X@!`H.$!8*#APEZ`X@Q0A>(!<*#A'#N0Y0$)$^,4```*`@`3XP(` +M``K#'H3B`R"@X_[__^L`@*#C'(N$Y00`H.'^___K3PV$XA@`@.+^___K!`"@ +MX0(0H./^___K!`"@X0L0H.,((*#A9#L#XP_@H.$#\)3G!`"@X7(0U^4`(*#C +M_O__ZP0`H.'^___K`#"@X]\WQ.7@-\3ESCO$Y$!((+BLR"%X;`P +MUN'\,,/CR#"#X[`PQN$:,*#C%#"$Y1@PA.4%`*#A!!"@X?[__^OPA[WH\$]"%,-A.(@`(#B_O__ZP!04.+PA[T(!`"@X0@0A>+^___K +M`("@XUN`Q>5L`)7E"!"@X6@@H./^___K;'"5Y2APA^('8*#A`(#'Y0&`Q^4< +M.Y3E`S`#X@,`4^,`@,8%`C"@`P$PQP4$```*`@!3XP`PH`,`,,<%`3"@`P$P +MQP4``%KC!P``"@`PUN4!(-;E`C2#X0$Z@^-S,/_F`##&Y2,TH.$!,,;EPHZ$ +MX@R`B.((`*#A_O__ZP`0H.$$`(;B!B"@X_[__^L*`(;B#1N$XA$0@>(&(*#C +M_O__ZP@`H.'^___K`!"@X1``AN(&(*#C_O__Z[8A]N'<-P#CLQ"4X0\@`N(! +M(H+AL"#&X;,@E.$!((+BLR"$X;`PU^'\,,/C2#"#X[`PQ^$8,*#C%#"%Y1@P +MA>4$`*#A!1"@X?[__^OPA[WH\$\MZ57?3>(`0*#A4QV`XB`0@>(,$(WE`!"@ +MXR01C>4D`(WB_R"@X_[__^L,`)WE_O__ZP"`4.+@`0`*!`"@X0@0B.+^___K +M;`"8Y0`0H.-H(*#C_O__ZVQ0F.4%8*#A`*"@XRB@YN4!H,;EPGZ$X@QPA^(' +M`*#A_O__ZP`0H.$L`(7B!B"@X_[__^L-*X3B$2""XA@@C>4R`(7B`A"@X08@ +MH./^___K!P"@X?[__^L`$*#A.`"%X@8@H./^___K!2"@X;X3\N'<-P#CLP"4 +MX0\0`>(`$H'AL!#"X;,@E.$!((+BLR"$X;`PUN'\,,/CL##&X4!@A>(8,*#C +M%#"(Y%"`(7B`B"@X_[__^L4,)CE`C"#X@@0H.$4,*'E$!"-Y3@L +ME.4`$(WE1`"%X@H0H.'#/H3B##"#XO[__^L4`(WE!`"@X4H?C>))+XWB_O__ +MZ]XWU.4.`%/C!#"@`R0QC06,?-3E``!7XS(```H!,*#C`R"$X(PLTN4``%+C +M"P``&B3!G>45[HWB**!^Y8JLX.&JK.#A>J#OY@`@H.,"8*#A?U#@XQ>PX.," +MD*#A!P``Z@$P@^(0`%/C[/__&N___^H&,(3@C'S3Y0``5^,6```*``!$#```*`3"# +MX@P`4^'W__\:`P``ZA4>C>(",('@"W##YP$@@N(!8(;B$`!6X^3__QH"8*#A +M``!2XP8``!H,`)WE44`)WE`1"@XP@@H.,%,*#A_O__ZQ`PG>4`,(WE,A"@XP@@ +M1N((,(7B_O__ZP"PH.$&``#J$!"=Y0`0C>44`)WE`1"@XTX_C>+^___K`+"@ +MXA.)2;XWBH#R4Y04`H.$P$*#C!B"@X0PP0^+^___K`#!0X@<```H0()WE +M`""-Y0L`H.$P$*#C2"&=Y0(P@^+^___K`+"@X=@TE.4!`%/C4@``&J`\E.4% +M`*#A+1"@XP8@H.$,,$/B_O__ZP!04.)*```*!`"@X?[__^L``%#C1@``&K\. +MA.(&`(#B`A"%XB`@H./^___K^SX"XP,PU.<``%/C]CL`X[,@E.%"(,(#`B"" +M$[,@A.'V.P#CLR"4X0P@@N.S((3A!`"@X100H.-1+XWB`R""XF@[`^,/X*#A +M`_"4YT4#`%/C#```&OT^`N,#,-3G``!3X_8[`!.S()01`2R"$[,@A!&_ +M#H3B"0"`XL`3G^40(*#C_O__ZQ4``.K]/@+C`S#4YP,`4^,(```*X2?4Y0@` +M$N,!```*`0!3XP,```H0`!+C!0``"@(`4^,#```:]CL`X[,@E.$"+(+CLR"$ +MX;\.A.()`(#B:!.?Y1`@H./^___KOSZ$XA`0G>4`$(WE"P"@X2T0H.-((9WE +M!C"#XO[__^L`L*#AH#R4Y0P`4^,Y``":RJZ$X@2@BN(,8*#C`#``XP`P0..$ +M((/B%""-Y020H..,$(/B#!"-Y8@P@^(<,(WE!'"@X090BN``,-7EW0!3XR$` +M`!H"0(7B!`"@X100G>4)(*#A_O__ZP``4.,+```:!`"@X1P0G>4)(*#A_O__ +MZP``4.,%```:!`"@X0P0G>4)(*#A_O__ZP``4.,.```*!`"@X0P0G>4)(*#A +M_O__ZP``4.,.(*`3`2#%%0$@U>40,)WE`#"-Y0L`H.'=$*#C`C"%XO[__^L` +ML*#A`3#5Y0(P@^(#8(;@H#R7Y08`4^'3__^*!T"@X4`$(WE"P"@X=T0H.,&(*#C*#*?Y?[__^L`L*#AJ#P#XP,PE.<``%/C`@`` +M&A`"G^7W%P#C_O__ZP`PD^4``%/C`@``&O@!G^4Y%P#C_O__ZR$RT^4``%/C +M#```"K`7E.4``%'C;```"L0GE.4``%+C:0``"@L`H.'^___K%""8Y<0WE.4# +M,(+@%#"(Y6(``.HL.@/C`S"4YP``4^->```*`0!3XUP```I0,*#C)##-Y1\P +M@^(E,,WE93#@XR8PS>5O,(/B)S#-Y0(PH.,H,,WE)%"-XK4PQ>$>,(/B*S#- +MY0`PH.,L,,WE"#"#XBTPS>4$(*#CNB#%X0`PX..\,,7AOC#%X0XP@^(T,,WE +M>CH#XP,PU.<5,(/BL3'%X1,`A>(8$)WE!B"@X_[__^O$.@/C`S"4YP$P0^(! +M`%/C`CN@DP(YH(.Y,<7A'AR@X[L1Q>$D8(WB`#`%X_(T0.,=,(;E`2R@X[$B +MQ>$`,*#C1S#-Y1`Q`>.T,L7A>GH#XP<@U.>R/[_FMC+%X>D=A.),`(WB&A"! +MXO[__^L',-3G*#"#XA4>C>(#(('@$!"@XRP10N4!,(/B#2"@X[,@A>$"4(/B +M.GR$XC!PA^(%`(;@!Q"@X08@H./^___K!E"%XA4>C>(%,('@`2"@XRPA0^4" +M4(7@!0"&X`<0H.$%((+B_O__ZQ`@G>4`((WE"P"@X=T0H.,&((7B!C"@X?[_ +M_^L4,)CE&#"(Y00`H.$($*#A_O__ZU7?C>+PC[WHX`0``/`$````````)``` +M`'!`+>D`4*#A3TV`XAA`A.($`*#A_O__ZQP[E>4#/,/C"3N#XQP[A>4%`*#A +M_O__ZP`P`.,`,$#C`!"3Y00`H.$>$('B_O__ZW"`O>CP3RWI)-!-X@!`H.$" +M8*#A`Z"@X;X0S>%3#8#B(`"`XO[__^L`4%#B_0``"@0`H.$($(7B_O__ZVP` +ME>4`$*#C:""@X_[__^ML<)7E*("'X@B0H.$`,*#C`##(Y0$PR.4L`(?BX!"& +MX@8@H./^___K,@"'X@T;A.(1$('B!B"@X_[__^O"#H3B#`"`XO[__^L`$*#A +M.`"'X@8@H./^___KOB/WX=PW`..S$)3A#R`"X@$B@N&P(,?ALR"4X0$@@N*S +M((3A,`!:XQ``6A/4```:RKZ$X@2PB^*P,-CA_###XP.@BN&PH,CA&!"@X[(1 +MQ>$4,)7E&#"#X@6@H.$4,*KE&("(X@L`H.'^___K('"-XK``T.&R`&?A"`"@ +MX0(0H.,'(*#A"C"@X?[__^L"$*#C#B"-X@HPH.'^___KM#W6X0,YX.$C.>#A +MOC'-X0(0H.,'(*#A"C"@X?[__^M`(9;E"`!2XP4``(H`H(WE`1"@XQ,^AN+^ +M___K"`"-Y0L``.H`H(WE`1"@XP@@H.,3/H;B_O__ZT`AEN4`H(WE,A"@XP@@ +M0N)./X;B_O__ZP@`C>58-Y;E`@L3XS0```K8-)3E``!3XS$```H@<(WB`#"@ +MXP@P)^4,@(OBH#R4Y0@`H.$M$*#C!R"@X0PP0^+^___K`!!0X@X```H8()WE +M``!2XPL```H(`)WE`B""XO[__^L8,)WE`B"#X@@0G>4"$('@"!"-Y10@E>4" +M,(/@`C"#XA0PA>6@/)3E"`"@X3T0H.,'(*#A##!#XO[__^L`$%#B#@``"A@@ +MG>4``%+C"P``"@@`G>4"((+B_O__ZQ@PG>4"((/B"!"=Y0(0@>`($(WE%""5 +MY0(P@^`",(/B%#"%Y5@WEN4"#!/C+@``"LPTE.4``%/C*P``"@`PH.,8,(WE +M$#"-XG`AG^4#`)+H!`"#Y+`0P^$,`(OB&("-XMV0H.,0L(WBH,R4Y0[`3.() +M$*#A"""@X1@PG>4,,&/@_O__ZP!P4.(7```*`@"'X@L0H.$&(*#C_O__ZP`` +M4.-````*"`"=Y0<0H.$8()WE`B""XO[__^L8,)WE`B"#X@@0G>4"$('@"!"- +MY10@E>4",(/@`C"#XA0PA>4"``#J`C"#X@,`A^#>___JRCO4Y0$`4^,'```: +M`*"-Y0@`G>7=$*#C!B"@XP`P`.,`,$#C_O__ZP@`C>6,%Y3E``!1XPL```J< +M)Y3E``!2XP@```H(`)WE_O__ZYPWE.4(()WE`R""X`@@C>44()7E`S""X!0P +MA>4D.@/C`S"4YP,`4^,*```:K#?6Y0$`4^,'```:W0V$XB``@.(($)WEK2?6 +MY?[__^L4,)7E`#"#X!0PA>44,)7E&#"%Y00`H.$%$*#A_O__ZP,``.H8,)WE +M``!3X\K__QK,___J)-"-XO"/O>A<$@``\$\MZ1303>(`0*#A`8"@X0*@H.%3 +M#8#B(`"`XO[__^L`8%#BN0``"@0`H.$($(;B_O__ZVP`EN4`$*#C:""@X_[_ +M_^MLD);E"7"@X0`PH.,H,.?E`3#'Y0D@H.&^$_+AW#<`X[,`E.$/$`'B`!*! +MX;`0PN&S()3A`2""XK,@A.&P,-?A_###X[`P@^.P,,?A0)")XA@PH.,4,(;E +M``!8XS<```H$`(?BX!"(X@8@H./^___K#5N$XA%0A>(*`(?B!1"@X08@H./^ +M___K$`"'X@40H.$&(*#C_O__Z]"VF.5[L/_F"S"@X;JPS>$``%KC`+"@$PLP +MH!&Z,,T1`0``&@"P6^(!L*`3"G"-XA10AN()`*#A`A"@XP<@H.$%,*#A_O__ +MZ\PVF.6Z,,WA`A"@XP<@H.$%,*#A_O__Z[J@S>$"$*#C!R"@X04PH.'^___K +MS#:8Y0(`4^-D```:T#"8Y:,T&^!A```*`%"-Y1`0H..`(*#C;3Z(X@0P@^+^ +M___K6@``ZL)>A.(,4(7B!0"@X?[__^L`$*#A!`"'X@8@H./^___K"@"'X@T; +MA.(1$('B!B"@X_[__^L%`*#A_O__ZP`0H.$0`(?B!B"@X_[__^LPNY3E`0!; +MXP"PH!,!L*`#NK#-X2P[E.4#`%/C$```&AP[E.6C-!O@#0``"D`[E.4\&Y3E +M`1^#X1`@C>($$"+E`3"#XD`[A.4)`*#A!!"@XQ0PAN+^___K`)"@X00PH.,> +M,,;E"H"-XA10AN()`*#A`A"@XP@@H.$%,*#A_O__ZRP[E.6Z,,WA`A"@XP@@ +MH.$%,*#A_O__Z[J@S>$"$*#C"""@X04PH.'^___K+#N4Y0,`4^,9```:'#N4 +MY:,T&^`6```*`%"-Y1`0H..`(*#C+3V$X@0P@^+^___K`##7Y0$@U^4"-(/A +M`3F#XW,P_^8`,,?E(S2@X0$PQ^48,*#CLC'&X0$PH.,=,,;E!#"@XQ\PQN44 +M,);E!#"#XA0PAN44,);E&#"&Y00`H.$&$*#A_O__ZP0`H.$&$*#A_O__ZQ30 +MC>+PC[WH$$`MZ0!`H.$<.Y#E`0P3XP0```H`,*#C'#N`Y0(0X./^___K$("] +MZ`(,$^,6```*(#N0Y0$P@^(@.X#E`@!3XP0``)H`,*#C'#N`Y0`0X./^___K +M$("]Z`$PH.,L.X#E`!"@XP$@H.'^___K`#``XP`P0.,`$)/E3PV$XA@`@.(> +M$('B_O__ZQ"`O>@""A/C$("]""0[D.4!,(/B)#N`Y0(`4^,$``":`#"@XQP[ +M@.4!$.#C_O__ZQ"`O>C^___K`#``XP`P0.,`$)/E3PV$XA@`@.(>$('B_O__ +MZQ"`O>AP0"WI`$"@X4]M@.(88(;B!@"@X?[__^L<.Y3E`3S#XP(\@^,<.X3E +M`3"@XRP[A.4`4*#C(%N$Y21;A.4H6X3E!`"@X<,>A.(#(*#C_O__ZP0`H.$% +M$*#A!2"@X?[__^L`,`#C`#!`XP`0D^4&`*#A'A"!XO[__^MP@+WH\$`MZ0S0 +M3>(`4*#A?$"1Y71PD>4-"X#B$0"`X@1@H.&P,-3A`0P3XP(@H!,`(*`#TS3@ +MYP,P@N$!`%/C!!"$`@$```H0$(0B!!"$,@8@H./^___K``!0XT,```H<.Y7E +M`@P3XT````JP,-;A`0D3XP0PH!,`,*`#`S"$X+HAT^&\,=/A``!3XPX```H- +M`%/C!```&C`[E>4!`%/C`#"@`P$PH!,P.X7E`#``XP`P0.,`$)/E3PV%XA@` +M@.+^___K``"@XRL``.H"`%+C'0``&C`[E>4!`%/C'P``&AX`A.(0$*#C!""- +MXAXP1^+^___K`!!0XAX```HM#87B!`"`X@(0@>($()WE_O__ZP,PH.,L.X7E +M!0"@X0`0H.,!(*#A_O__ZP`P`.,`,$#C`!"3Y4\-A>(8`(#B'A"!XO[__^L! +M`*#C"P``Z@0`4N,(```:,#N5Y0$`4^,%```:!0"@X?[__^L!`*#C`@``Z@$` +MH.,```#J``"@XPS0C>+P@+WH\$(`8*#A`9"@X0)0H.$`,*#C%#"- +MY0PPC>(`(I_E`P"2Z`0`@^2P$,/A4PV&XB``@.+^___K`$!0XG8```H&`*#A +M"!"$XO[__^ML`)3E`!"@XV@@H./^___K;'"4Y2APA^('@*#A#:N&XA&@BN(` +M,*#C`##'Y0$PQ^4#`%7A#@``&L)>AN(,4(7B!0"@X?[__^L`$*#A!`"'X@8@ +MH./^___K!0"@X?[__^L`$*#A$`"'X@8@H./^___K"```Z@Q0C>($`(?B!1"@ +MX08@H./^___K$`"'X@40H.$&(*#C_O__ZPH`B.(*$*#A!B"@X_[__^NV(?CA +MW#<`X[,0EN$/(`+B`2*"X;`@R.&S();A`2""XK,@AN&P,-?A_###XT`P@^,' +M`*#AN#'`X!@PH.,4,(3E``!9XPDPH!$$(),4%!"$$@`0C14`$*`3%#"$`@`P +MC04`$*`#`2"@`0$PH`'^___K`%"@X08`H.$8$(WB%""-XO[__^L4()WE"`!2 +MXPX``-H4<(3B&("-X@!PC>4%`*#A`1"@XP@@H.,(,*#A_O__ZP!PC>4R$*#C +M%""=Y0@@0N((,(CB_O__ZP4``.H4,(3B`#"-Y04`H.$!$*#C&#"-XO[__^M< +M)Y;E`1!"XOXQ`.,#`%'A!@``BE4>AN(,$('B_O__ZQ0@E.5<-Y;E`S""X!0P +MA.44,)3E&#"$Y08`H.$$$*#A_O__ZRC0C>+PA[WH9!(``/!/+>D(`(*#C%#"-XO[__^N( +M-Y3E`)"@X0``4^,``%`3+P``"A1@G>4``%;C+```"LH>A.($$('B`(!AX*"\ +ME.4+L&C@"[!FX`<`H.$((*#A_O__ZPAPA^`4,)7E"#"#X!0PA>6(-Y3E`2#3 +MY10@C>4"((+B"#""X`,,4^,)``"*!P"@X8@7E.7^___K%#"=Y0(@@^("<(?@ +M%""5Y0(P@^`",(/B%#"%Y10PG>4",(/B"("#X`N`B.`##%CC9```B@<`H.$& +M$(G@"R"@X?[__^L+<(?@%#"5Y0NP@^`4L(7E6P``Z@<`H.'*'H3B!!"!XJ`L +ME.7^___KH#R4Y0-PA^`4()7E`S""X!0PA>50``#J"("'XB`PH.,4,(7ERFZ$ +MX@1@AN(&`*#A_O__ZP`0H.$(`*#A`B"@X_[__^L*@(?B%#"5Y0(P@^(4,(7E +M!@"@X?[__^L`$*#A"`"@X0(@H./^___K%#"5Y0(P@^(%8*#A%#"FY3@LE.4` +M8(WE#`"'X@`0H./#/H3B##"#XO[__^L`D*#A,GV$X@QPA^('`*#A_O__ZP"` +MH.$`8(WE"0"@X0$0H.,(`%CC"""@,0@@H",',*#A_O__ZP!@C>4#$*#C`2"@ +MX\<^A.($,(/B_O__ZP!PH.$<.Y3E`S`#X@$`4^,-```:`""@XQ,@S>48,(WB +M#"`CY0!@C>4&$*#C`B"@X_[__^L`8(WE*A"@XP$@H.,3,(WB_O__ZP!PH.$( +M`%CC!P``F@!@C>4'`*#A,A"@XP@@2.+)/H3B!#"#XO[__^L`<*#A)#H#XP,P +ME.<#`%/C(@``&@``6N,@```*J#P#XP,PE.<``%/C`@``&H@`G^7W%P#C_O__ +MZP`PD^4``%/C`@``&G``G^4Y%P#C_O__ZR$RT^4``%/C"```"L!GE.6L%Y3E +M``!1XP``5A,(```*!P"@X08@H.'^___K!```ZMT-A.(@`(#B!Q"@X?[__^L` +M8*#A%#"5Y09@@^`48(7E%#"5Y1@PA>4$`*#A!1"@X?[__^L4'8*#A`#"@XR@PYN4! +M,,;E+`"'XA`0C>(&(*#C_O__ZS(`A^(-&X3B$1"!X@8@H./^___KP@Z$X@P` +M@.+^___K`!"@X3@`A^(&(*#C_O__ZP4``%SC`@``&L0#G^4Y%P#C_O__Z\H>A.($$('B`&!AX`.0@.`"H&;@"J!C +MX"$"W.4``%#C)@``"H`WE.4``%/C&P``"I`WE.4``%/C&```"@<`H.$&(*#A +M_O__ZP9PA^`4,)7E!F"#X!1@A>4'`*#A@!>4Y9`GE.7^___KD#>4Y0-@A^`4 +M()7E`S""X!0PA>4&`*#A"1"@X0H@H.'^___K"G"&X!0PE>4*H(/@%*"%Y40` +M`.H'`*#A_O__ZZ`\E.4#<(?@%""5Y0,P@N`4,(7E/```Z@<`H.$#((;@_O__ +MZPPPG>4#,(;@`X"'X!0@E>4#,(+@%#"%Y1`T!>.P,,CA`CN@X[(PR.$>+*#C +MM"#(X0`P!>/R-$#C!C"(Y0$\H..Z,,CA$#$!X[PPR.%ZN@/C"S#4Y[,_O^:^ +M,,CA$`"(XND=A.(:$('B"R#4Y_[__^L+,-3G$#"#X@9@A^`,(-WE`B!"X@(@ +M@^`!(,;E`X"(X!0@E>4#,(+@%#"%Y0@`H.$)$*#A"B"@X?[__^L*<(C@%#"5 +MY0J@@^`4H(7E"0``Z@<`H.'*'H3B!!"!XJ`LE.7^___KH#R4Y0-PA^`4()7E +M`S""X!0PA>4D.@/C`S"4YP,`4^-J```:J#P#XP,PE.<``%/C`@``&N0!G^7W +M%P#C_O__ZP`PD^4``%/C`@``&LP!G^4Y%P#C_O__ZR$RT^4``%/C"```"K1G +ME.6@%Y3E``!1XP``5A,(```*!P"@X08@H.'^___K!```ZMT-A.(@`(#B!Q"@ +MX?[__^L`8*#A%#"5Y09@@^`48(7E2```Z@B`A^(@,*#C%#"%Y4",(/B%#"%Y08`H.'^ +M___K`!"@X0@`H.$"(*#C_O__ZQ0PE>4",(/B!6"@X10PIN4X+)3E`&"-Y0P` +MA^(`$*#CPSZ$X@PP@^+^___K`*"@X3)]A.(,<(?B!P"@X?[__^L`@*#A`&"- +MY0H`H.$!$*#C"`!8XP@@H#$((*`C!S"@X?[__^L`8(WE`Q"@XP$@H./'/H3B +M!#"#XO[__^L`(*#C#"#-Y1@PC>(0("/E`&"-Y080H.,"(*#C_O__ZP!@C>4J +M$*#C`2"@XPPPC>+^___K"`!8XP4``)H`8(WE,A"@XP@@2.+)/H3B!#"#XO[_ +M_^L`,*#CR#?$Y0T@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^L4,)7E(""# +MX@(,4N,#``"*&#"%Y00`H.$%$*#A_O__ZQS0C>+PC[WH;!(``"0```#P02WI +M"-!-X@!`H.$`4*#C"&"-X@%09N5H>P/C$X"@XP0`H.'^___K_O__ZP0`H.$( +M$*#A!B"@X0_@H.$'\)3G!S#=Y0``4^,"```:`5"%XF0`5>/Q__\:9`!5X@$` +MH!,(T(WB\(&]Z/!/+>E$T$WB`$"@X0%0H.$`,*#C/#"-Y0`0`.,`$$#CY#.1 +MY2`PC>48,(WB^A^!X@,`D>@$`(/DL!##X6PPE.40`!/CF0(`"@,,4N.7`@#* +M56^$XE`AA.4&`*#A`!"@XP,LH./^___K!@"@X040H.%0(93E_O__ZS@QE.4$ +M`%/CB@(`&@!0H.,0483EX`"$X@T;A.(1$('B!B"@X_[__^L&`*#A_O__ZP$@ +MT.4`,-#E`C2#X1PQA.4!@-;E5#'4Y0B$@^$,D(;B/&"-XE`QE.4)`*#A!1"@ +MX08@H.$,,$/B_O__ZP!04.(,```*/#"=Y0``4^,)```*Z`"$X@`0H.,D(*#C +M_O__Z^P`A.("$(7B/""=Y?[__^L\,)WEZ#"$Y0`PH.,8,83E4#&4Y0D`H.$# +M$*#C!B"@X0PP0^+^___K``!0XP,```H\,)WE``!3XP)PT!4````:`'"@XR1Q +MA.4D`(WB`!"@XQ`@H./^___K4#&4Y0D`H.$!$*#C!B"@X0PP0^+^___K`!!0 +MX@!0H`,$```*)`"-X@(0@>(\()WE_O__ZSQ0G>50,93E"0"@X3(0H.,&(*#A +M##!#XO[__^L`$%#B!@``"B0`C>(%`(#@`A"!XCP@G>7^___K/#"=Y0-0A>`D +M`(WB!1"@X0<@H.'^___K<+#OYD\OA.($((WE`@"@X0L0H.'^___K4#&4Y0D` +MH.$J$*#C!B"@X0PP0^+^___K`!!0X@0```H\,)WE``!3XP$```H$`*#A_O__ +MZQ``&.,!,*`3`#"@`PPQA.4`,*#C!"H!XP(PA.,",(3G +M%"H!XP(PA.=0,93E"0"@X3`0H.,&(*#A##!#XO[__^L``%#C&```"CP0G>4` +M`%'C%0``"@(0@>(X((WB-#"-XO[__^L!`%#C#P``&@(@H./(.`'C`R"$YP$@ +MH.,:/*#C`R"$YP0Z`>,#()3G`B""XP,@A.4T,(WE""H!XP(PA.<0*@'C`C"$YPD`H.'=<*#C +M(("-X@2@H.-0P93E#L!,X@<0H.$&(*#A/#"=Y0PP8^#^___K`%!0XB$```H" +M`(7B"!"@X0H@H.'^___K``!0X]4!``H%`*#A/!"=Y0(0@>(X((WB-#"-XO[_ +M_^L!`%#C$P``&@(@H./(.`'C`R"$YP$@H.,:/*#C`R"$YP0Z`>,#()3G`2"" +MXP,@A.#4___J +M`#"@XSPPC>7,-(3E>SL"XP,PU.<``%/C'```"@D`H.'=<*#C&("-X@:@H.-0 +MP93E#L!,X@<0H.$&(*#A/#"=Y0PP8^#^___K`%!0X@\```H"`(7B"!"@X0H@ +MH.'^___K``!0XZ,!``H!,*#CS#2$Y0@P]>6#/.#AHSS@X0`PQ>4"``#J`C"# +MX@,`A>#F___J4#&4Y0D`H.$M$*#C!B"@X0PP0^+^___K`%!0XB,```H\,)WE +M``!3XR````H"<(7B"+"+XP0`H.$4$*#C%R"-XF@[`^,/X*#A`_"4YQ`Z`>,# +M,)3G$``3XP,``!H4.@'C`S"4YQ``$^,"```*`C#7Y1PP@^,",,?E%S#=Y0,` +M4^,`,.`#`S#'!0`PH`,$,,<%3PZ$X@$`@.("$(7B/""=Y?[__^L%<*#A`5"@ +MXP$``.H`4*#C!7"@X5`QE.4)`*#A/1"@XP8@H.$,,$/B_O__ZP!@4.("```* +M/#"=Y0``4^,````:`&"@XPL`6^,1``"*>S"OY@$@H.,2(Z#A##P`XP`P0.,# +M,`+@``!3XP,PH!,4,805"0``&A``$N,",*`3%#&$%04``!H"`!+C`3"@$Q0Q +MA!4!```:`S"@XQ0QA.7(L(3E`#"@X]@TA.7Z/@+C`S#4YP``4^,`4*`#`5`% +M$@``5>,,```*`3"@X]@TA.7,-(3E_#X"XP,PU.53,>+G0""-XBLP8N5D6P/C +M!`"@X2(0H.,/X*#A!?"4YP0`H.$C$*#C%B"-X@_@H.$%\)3G]CL`X[,PE.%3 +M,>'GUCO$Y=@PE.4!`%/C`0``"@0`H.'^___K!`"@X0,0H./^___KX+"$XF1K +M`^,$`*#A!!"@XPL@H.$/X*#A!O"4YT!0C>(7,@/C+S!`XS0P)>4$`*#A'1"@ +MXP4@H.$/X*#A!O"4YQ,$#C##"-Y00`H.$>$*#C!2"@X0_@H.$&\)3G +M*S0*XUXP0.,,,(WE!`"@X1\0H.,%(*#A#^"@X0;PE.=$-`KC##"-Y00`H.$@ +M$*#C!2"@X0_@H.$&\)3GR#@!XP,PE.<"`%/CS#"@`\\PH!-`((WB*3!BY090 +MH.$$`*#A$A"@XP_@H.$&\)3G!`"@X0X0H.,2((WB#^"@X0;PE.<$`*#A!!"= +MY5'G_^L$`*#A!A"@XP0@G>4/X*#A!O"4Y]@PE.4!`%/C`P``"@0`H.$/$N#C +M`2"@X_[__^M0,93E"@"@X3T0H.,(((WB##!#XO[__^L``%#C%0``"@@PG>4` +M`%/C$@``"OL^`N,#,-3G``!3XPX```H#,-#E!``3XPL```H#,`/B`2!#X@(` +M4N,`4*"#`6"@@P$P0Y(`(`"3`"!`DP,@@I#P8]*5]%/2E0$``.H`4*#C!6"@ +MX00`H.$)$*#A!2"@X08PH.'^___KWI?$Y=]GQ.7@5\3ER#"4Y>$WQ.4$`*#A +M_O__ZP@`H.$'$*#AW""4Y?[__^OJ#83B(@"`XNP0A.+H()3E_O__Z^@@E.7" +M.@/C`R#$YR`T`>,#,-3G`0!3XP8``!H$`*#A!1"@XP`@H.,",*#A_O__ZP0` +MH.'^___K!`"@X?[__^L`@%#B3@``"@`0H./4$(CE`5"@X]A0B.7<$(CEA!:( +MY>@0B.56#XCB6""@X_[__^L$`)WE_O__ZP!PH.$$`)WE!Q"@X04@H.'^___K +M$PZ(XD\?A.('(*#A_O__ZT!QB.4``%?C"@``V@A0H.$`8*#C,`'5Y0``4.,! +M```*?P``XO[__^L!8(;B`5"%X@8`5^'V__\:)`&4Y0X`4.,57J"##U"@DPX` +M4.,$`*"#`0"@D_[__^L`8*#A!0"@X?[__^L_<`#B>#L#XP/`E.<``%SC!``` +M"@0`H.$`$*#C"""@X0$PH.,\_R_AV"#8Y1\@`N($`*#A!AZ%X8`@@N.$.P/C +M#^"@X0/PE.=.84``%/C/_[_&D'^_^H\,)WE``!3XU_^_QIA_O_J +M^$\MZ0!0H.'^___K``!0XP0`H`/XC[T(!0"@X?[__^L`<%#B/```"KXX`>.S +M,)7A`0`3XS@```K,,)?E``!3XS4```H*`*#C_O__Z_[__^L-(*#A?SW"XS\P +MP^,$()/E`2""X@0@@^7$H(?BQ&"7Y0&`H.,1D*#CE+L#XQ@``.H&0*#A`&"6 +MY00PE.4$,(;E`&"#Y0!`A.4$0(3ES#"7Y0$P0^+,,(?E``!3XU2`Q!4`,*`# +M5##$!5:`Q.57D,3E!0"@X000H.$/X*#A"_"5YP$`4.,"```:!0"@X000H.'^ +M___K"@"@X080H.'^___K``!0X^'__PH-(*#A?SW"XS\PP^,$()/E`2!"X@0@ +M@^7^___K``"@X_B/O>@``*#C^(^]Z#!`+>D,T$WB`$"@X0%0H.$<.Y#E`R`# +MX@$`4N,<```:`0D3XQ(``!I]'H3B_O__ZP0`H.'^___K``!0XPD``!K8,)7E +M?3"#XH,RA.`(,(/B`""@XP`@@^4<.Y3E`3`CXAP[A.43``#J'#N4Y0$Y@^,< +M.X3E"""-X@(PH.,!,&+E!`"@X0T0H.-D.P/C#^"@X0/PE.?8,)7E@S*$X*1? +M@^4$`*#AV!"5Y?[__^L$`*#A!1"@X?[__^L,T(WB,("]Z#!`+>D,T$WB`$"@ +MX<)>@.(,4(7B=#R0Y=XWP.4%`*#A_O__Z\8[`..S`(3A!`"@X?[__^L%`*#A +M_O__ZP!0H.$$`*#A!1"@X?[__^L"`!7C,```"@@@C>(P,.#C`3!BY00`H.$2 +M$*#C9#L#XP_@H.$#\)3G!`"@X=X7U.4`(*#C`C"@X?[__^L$`*#A_O__ZP$0 +MH.,<&X3E!`"@X?[__^L$`*#A_O__ZP``4.,%```:!`"@X0`0X./^___K`#"@ +MXQP[A.43``#J9%L#XP0`H.$$$*#CKBV$X@8@@N(/X*#A!?"4YP@@C>(`,*#C +M`C!BY00`H.$-$*#C#^"@X07PE.<$`*#A`1"@X_[__^L<.Y3E`3F#XQP[A.4, +MT(WB,("]Z'!`+>D`0*#A`5"@X5PPT>5=(-'E`C2#X5X@T>4".(/A7R#1Y0(\ +M@^$$`%/C+P``"@``4^,M```:_O__ZP!@H./?9\3EX&?$Y4" +M)(/A=C#5Y0,H@N%W,-7E`RR"X:`LA.4##%+C!`"@@W"`O8C*#H3B!`"`XG@0 +MA>+^___K!`"@X?[__^L``*#C<("]Z```H.-P@+WH\$\MZ87?3>(`0*#A@C^- +MXJ@CG^4#`)+H!`"#Y+`0P^'_4*#C0@^-X@`0H.,%(*#A_O__ZP@`C>(`$*#C +M!2"@X?[__^M3#83B(`"`XO[__^L`8%#BUP``"@0`H.$($(;B_O__ZVP`EN4` +M$*#C:""@X_[__^ML@);E"'"@X0`PH.,H,.?E`3#'Y8)?C>(L`(CB!1"@X08@ +MH./^___K.`"(X@40H.$&(*#C_O__ZS(`B.(-&X3B$1"!X@8@H./^___K"""@ +MX;X3\N'<-P#CLP"4X0\0`>(`$H'AL!#"X;,@E.$!((+BLR"$X;`PU^'\,,/C +M0#"#X[`PQ^%``(CB&#"@XQ0PAN4L.@/C`S"4YP8`4^,(```:"#@#XP,@E.<4 +M,(;B`#"-Y0`0H.,..X3B##"#XO[__^L&``#J%#"&X@`PC>4`$*#C!R"@X^D] +MA.(+,(/B_O__ZQ1PAN(`<(WE`1"@XP@@H./I/83B`S"#XO[__^L`H*#AJ#P# +MXP,PE.<``%/C`@``&C@"G^7W%P#C_O__ZP`PD^4``%/C`@``&B`"G^4Y%P#C +M_O__ZR$RT^4``%/C%0``"H07E.4``%'C>```"J0WE.4``%/C=0``"I0GE.7^ +M___K%""6Y90WE.4#,(+@%#"&Y90'E.4``(K@I!>4Y;@GE.7^___K%""6Y;@W +ME.4#,(+@%#"&Y64``.HA7HWB`(`%X_*$0.,(@27E$#H$X[0PQ>$!O*#CMK#% +MX1`PH.,0,%ZF@/C"2#4Y[(_O^:[,,7A#0"%XND=A.(:$('B +M_O__ZPD@U.<-((+B$#0%X[(PA>$"((+B`CN@X[(PA>$"((+B'CR@X[(PA>$" +M((+B`H"%YP0@@N*RL(7A`'"-Y0H`H.'=$*#C`B""X@4PH.'^___K4#"@XP@P +MS>5O,*#C"3#-Y64PX.,*,,WE"3"@XPLPS>4"(*#C#"#-Y0@PC>*U(,/A(""@ +MXP\@S>4`(*#C$"#-Y08@H.,1(,WE!2"@X[H@P^%5(*#C%"#-Y5,@H.,5(,WE +M!""@XQ8@S>51$*#C%Q#-Y>D=H.,!$-3G&!#-Y0@0H.,9$,WELB'#X0`@X..T +M(4%(*#CN2'#X54P +MH.,C,,WE4S"@XR0PS>4$,*#C)3#-Y5$PH.,F,,WE03H#XP,PU.7=$*#C"#"-XO[__^L4,);E&#"&Y00`H.$&$*#A_O__ZX7?C>+PC[WH +MB!(``"0```#P3RWI'-!-X@!@H.&S/`/C`S#0YP``4^,````*_O__ZP8`H.'^ +M___K``!0XW8```K#3H;B6PV&XC@`@.($$*#A_O__ZP``4..D```*7C^@X].` +M@.$7/J#CT""#X0*@F.`#L*G@!CV@X]`@@^$"@)K@`Y"KX!8^H./3H(#A5C^@ +MX]`@@^$"H)K@`["KX/"AS>%:/Z#CTZ"`X=`AS>$*()+@"S"CX`(`6.$J```: +M`P!9X2@``!H0-`'C`S"6YP<`4^,;``"*``!3XQ0``!HL.@/C`S"6YP``4^," +M```*!@"@X?[__^L-``#JPTZ&X@A`A.(&`*#A!!"@X0`@H./^___K!@"@X000 +MH.$`(*#C_O__ZP8`H.$$$*#A`""@X_[__^L0-`'C`R"6YP$@@N(#((;G%P`` +MZ@!0H.,0-`'C`U"&YP8`H.$$$*#A_R\/X_[__^LH6X;E80``Z@`@H.,0-`'C +M`R"&YU8_H./30(#A%SZ@X_-`@.$6/J#CTT"`X5X_H./S0(#A6C^@X]-`@.$& +M/:#C\T"`X08PH.%()0'C`B"SYP0`D^5@-0'C`Q"6YP(`4>$.```:`S"&X`0P +MD^4``%/A"@``&B@[EN4!((/B*"N&Y0\`4^-!```:!@"@X0`0H./^___K`#"@ +MXR@[AN4[``#J!C"@X6`5`>,!(*/G!`"#Y0`PH.,H.X;E-```Z@8`H.'^___K +M``!0XS````K^3H;B"$"$XDY=AN(H4(7B`)"@XQ9^H.-6CZ#C`#"4Y0$`4^,C +M```:!!`4Y0``4>,@```*!`"4Y=B@@>'7(('A"B"2X`LPH^#P(`0@>+_+P_C_O__ZP8``.H(D(3E!R"1YP@PD><#,(+@ +M:"&1Y0(P@^`$,(3E($"$X@4`5.'5__\:'-"-XO"/O>CP02WI"-!-X@!`H.$` +M,*#C`#"-Y2PZ`^,#,)#G!0!3XPX``!I]*@/C`B#0YP``4N/0*9#E`B"`$#HL +M@A(X(((2!!#2%0%0H!."(((``B&``'XN@@($$-(%"%"2!0D``.H``%/C`0`` +M"@$`4^-2```:T"F4Y8(@@N`"(83@?BZ"X@00TN4(4)+E``!1XTH```K0.93E +M``!3XP0``!H$`*#A`""@XP(PH.'^___K`0``Z@0`H.'^___K`0!5XR\``!HL +M.@/C`S"4YP,`4^,!```*!0!3XP8``!H$`*#A_O__ZP0`H.'^___K!`"@X?[_ +M_^LB``#JG6Z$X@A@AN(`<*#C`8"@XP`PEN4``%/C#```"H=1A^`%4:#AG5Z% +MX@A0A>(%4(3@!`"@X040H.$((*#A_O__ZP0`H.$%$*#A"""@X?[__^L!<(?B +M)&"&X@D`5^/K__\:U#F4Y0$`4^,'```:!`"@X0`0H.,!(*#C_O__ZP0`H.$` +M$*#C`2"@X_[__^L`,`#C`#!`XP`PD^4,)`'CLB"4X600H..1`@'@TRT$XV(@ +M0>.2`8'@3@V$XB0`@.(A$X/@_O__ZXL``.H#`%/C`0``"@4`4^,K```:?3H# +MXP,PU.<"`%/C)P``B@0`H.'I/:#C`Q#4YP`@H.,",*#A_O__ZRPZ`^,#,)3G +M!`!3XP0@H!,L.@,3`R"$%P`PH./(.83E"""-XO\PH.,(,"+E!`"@X2X0H.,- +M(*#A9#L#XP_@H.$#\)3G!`"@X?[__^L`,`#C`#!`XP`PD^5"*@/C`B#4YQ`7 +M`N.1`@'@TRT$XV(@0>.2`8'@W0V$XB0`@.(A$X/@_O__ZUL``.H$`*#AB#L# +MXP_@H.$#\)3G``!0XPX```H`,*#CS#F$Y0`PX./0.83E##0!XS(@H..S((3A +M`#``XP`P0.,`$)/E3@V$XB0`@.(%$('B_O__ZT8``.HL.@/C`S"4YP,`4^,! +M```*!0!3XP(``!H"(*#C+#H#XP,@A.<$,*#CR#F$Y2PZ`^,#,)3G"@!3XP@` +M`!I\.@/C`Q#4YP``4>,$```*!`"@X>`GU.7?-]3E_O__ZP0``.H$`*#AWA?4 +MY>`GU.7?-]3E_O__ZP@@C>(`,*#C`3!BY61;`^,$`*#A#!"@XP_@H.$%\)3G +M'!O4Y00`H.$#$`'B_O__ZP@@C>+_,*#C"#`BY00`H.$N$*#C#2"@X0_@H.$% +M\)3G!`"@X?[__^L$`*#A_O__ZP$`4.,"```:!`"@X0`0H./^___K!`"@X?[_ +M_^L,-`'C9`"@X[,`A.$`,*#CR#F$Y00`H.%1[/_K!`"@X4_L_^L$`*#A3>S_ +MZPC0C>+P@;WH\$(`0*#A`8"@X<@YD.4``%/C.```&CL0H.,`(*#C +M9#L#XP_@H.$#\)3G`3"@X\@YA.4`8*#CS&F$Y01PH.'0::?E"%"@X0APA^(& +MH*#A()"@XP@PE>4``%/C`*"'!0H```J&$8;@`1&@X0$`A.`!$(C@G0Z`X@P` +M@.(,$('B"2"@X?[__^L(,)7E`#"'Y0%@AN(D4(7B)'"'X@D`5N/K__\:`#"8 +MY=0YA.4$`*#A_O__ZP$`4.,/```:`C"@X\@YA.4$`*#A`1"@X_[__^L$`*#A +M`1"@X_[__^L`,`#C`#!`XP`0D^5.#83B)`"`X@40@>+^___K+P``ZL@YE.4! +M,$/B`0!3XRD``(H$`*#A_O__ZP0`H.$`$*#C`2"@X?[__^NH/`/C`S"4YP`` +M4^,"```:C`"?Y?<7`./^___K`#"3Y0``4^,"```:=`"?Y3D7`./^___K(3+3 +MY0$`4^,P,*`#'C"@$P`PC>5D6P/C!`"@X2X0H.,-(*#A#^"@X07PE.<$`*#A +M`!"@X_[__^L(((WB`3"@XP$P8N4$`*#A#!"@XP_@H.$%\)3G`S"@X\@YA.4$ +M`*#A_O__ZP``H.,(T(WB\(>]Z"0```#P1RWI1M]-X@!`H.$!H*#A`Y"@X0\@ +MS>4$,*#C%S'-Y0D@H.,6((`$*#C_R"@ +MX_[__^M3#83B(`"`XO[__^L`4%#BBP``"@0`H.$($(7B_O__ZVP`E>4`$*#C +M:""@X_[__^ML<)7E!V"@X0"`H.,H@.;E`8#&Y2P`A^(*$*#A!B"@X_[__^LR +M`(?B#1N$XA$0@>(&(*#C_O__ZS@`A^(*$*#A!B"@X_[__^L'(*#AOA/RX=PW +M`..S`)3A#Q`!X@`2@>&P$,+ALR"4X0$@@N*S((3AL##6X?PPP^/0,(/CL##& +MX05@H.$8,*#C%#"FY4``A^(!$*#C12^-X@,@@N(&,*#A_O__ZP$0H.-%+XWB +M`B""X@8PH.'^___K!!"@XQ$NC>(&,*#A_O__ZP$0H.-#+XWB`R""X@8PH.'^ +M___K$'"-X@$0H.,!($?B!C"@X?[__^M0,*#C$##-Y6\PH.,1,,WE93#@XQ(P +MS>4),*#C$S#-Y12`S>4!$*#CM1#'X0@`6>$H```*%X#-Y04@H.,8(,WE`L"@ +MX[G`Q^$W,.#C&S#-Y1PPS>4+,*#C'3#-Y1`0H..^$,?A51"@XR`0S>53$*#C +M(1#-Y000H.,B$,WE4>"@XR/@S>4D,,WE`>"@XR7@S>4FP,WE`\"@XR?`S>4H +M$,WE*2#-Y08@H.,J(,WE!R"@XRL@S>4((*#C+"#-Y0D@H.,M(,WE"B"@XRX@ +MS>4O,,WE(""@XPD``.H!,*#C%S#-Y04PH.,8,,WE`C"@X[DPQ^$W,.#C&S#- +MY1PPS>4-(*#C`&"-Y=T0H.,0,(WB_O__ZQ0PE>48,(7E!`"@X040H.'^___K +M1M^-XO"'O>CP3RWI2=]-X@!@H.$!H*#A!#"@XQ\QS>4),*#C'C'-Y5`_!N.: +M.4#C&#&-Y0-`H.,7053#8;B(`"`XO[_ +M_^L`@%#BS0``"@8`H.$($(CB_O__ZVP`F.4`$*#C:""@X_[__^ML4)CE!4"@ +MX0`@H.,H(.3E`2#$Y2P`A>(*$*#A!B"@X_[__^L-FX;B$9")XC(`A>()$*#A +M!B"@X_[__^LX`(7B"A"@X08@H./^___K!2"@X;X3\N'<-P#CLP"6X0\0`>(` +M$H'AL!#"X;,@EN$!((+BLR"&X;`PU.'\,,/CT#"#X[`PQ.$(<*#A&#"@XQ0P +MI^5``(7B`1"@XT(#((+B!S"@X?[__^L!$*#C1R^-X@(@@N(',*#A_O__ +MZP00H.-&+XWB!S"@X?[__^L!$*#C12^-X@,@@N(',*#A_O__ZQA`C>(!$*#C +M`2!$X@5E,.#C&C#-Y0D0H.,; +M$,WE!0"@XQP`S>4"X*#CM>#$X340P*#COL#$X57`H.,HP,WE4\"@XRG`S>4$P*#C*L#- +MY5%0H.,K4,WE+##-Y2T@S>4NX,WE`R"@XR\@S>4PP,WE,0#-Y08@H.,R(,WE +M!R"@XS,@S>4((*#C-"#-Y340S>4*(*#C-B#-Y34/,*#C.##-Y6=8`^,% +M,-;G!C"#XK$RQ.$C`(3B"A"@X08@H./^___K*0"$XN$=AN('$('B!2#6Y_[_ +M_^L%4-;G*5"%XG50[^;XK@_C_Z]/XQ+.C>(%,(S@#2"@XPH@P^/*#CM3"$X0)0A>)U4._F`#`%X_(T0.,% +M,(3G!%"%XG50[^8!S*#CM<"$X0)0A>)U4._F$BZ-X@4P@N`*H(/@`#"@XP`P +MRN4!4(7B=5#OYA`Q`>.U,(3A`E"%XG50[^8+(-;GLC^_YK4PA.$"4(7B=5#O +MY@4`A.#I'8;B&A"!XO[__^L+,-;G`U"%X`!PC>4,`)WEW1"@XW4@[^8$,*#A +M_O__ZQ0PF.48,(CE!@"@X0@0H.'^___K2=^-XO"/O>CP3RWI1=]-X@!`H.$! +M4*#A`K"@X00PH.,/,50/P;CFCE`XP@QC>4",*#C!S'-Y0@` +MC>(`$*#C_R"@X_[__^M3#83B(`"`XO[__^L`8%#BJ0``"@0`H.$($(;B_O__ +MZVP`EN4`$*#C:""@X_[__^ML@);E"'"@X0"@H.,HH.?E`:#'Y2P`B.(%$*#A +M!B"@X_[__^L-6X3B$5"%XC(`B.(%$*#A!B"@X_[__^LX`(CB!1"@X08@H./^ +M___K"""@X;X3\N'<-P#CLP"4X0\0`>(`$H'AL!#"X;,@E.$!((+BLR"$X;`P +MU^'\,,/CT#"#X[`PQ^$&4*#A&#"@XQ0PI>5``(CB`1"@XT,OC>(#((+B!3"@ +MX?[__^L!$*#C0R^-X@(@@N(%,*#A_O__ZP00H.-"+XWB!3"@X?[__^L!$*#C +M02^-X@,@@N(%,*#A_O__ZP$0H./J+83B!3"@X?[__^L`D*#A4#"@XP@PS>5O +M,*#C"3#-Y64PX.,*,,WE"3"@XPLPS>4,H,WE"'"-X@$0H..U$,?A#[#-Y0(P +MH.,0,,WEN3#'X2`PH.,3,,WE%*#-Y1$PH.,5,,WE!3"@X[XPQ^%5,*#C&##- +MY5,PH.,9,,WE!#"@XQHPS>51,*#C&S#-Y20Z`^,#,)3G`@!3XWPZ`P-!.@,3 +M`S#4YQPPS>4+,*#C'3#-Y51,*#C(S#-Y20@S>4E`(WBZQV$X@L0@>+^___K""#4YQT@ +M@N)R(._F)#H#XP,PE.<#`%/C&P``&A$>C>(",('@#Q"@XP@10^4!((+B('`(K@.AR$XC`0@>(&(*#C +M_O__ZP9PA^)W<._F!P"*X.H=A.(!$('B""#4Y_[__^L((-3G`G"'X'<@[^8` +M4(WE"0"@X=T0H.,(,(WB_O__ZQ0PEN48,(;E!`"@X080H.'^___K1=^-XO"/ +MO>CP3RWIA]]-X@!`H.$!<*#A!#"@XQ4),*#C%C+-Y5`_!N.:.4#C$#*- +MY0!0H.,/4LWE_V"@XQ$.C>(%$*#A!B"@X?[__^L0`(WB!1"@X08@H.'^___K +M4PV$XB``@.+^___K`(!0XBL!``H$`*#A"!"(XO[__^ML`)CE!1"@X6@@H./^ +M___K;&"8Y090H.$`,*#C*##EY0$PQ>4L`(;B!Q"@X08@H./^___K#:N$XA&@ +MBN(R`(;B"A"@X08@H./^___K.`"&X@H0H.$&(*#C_O__ZP8@H.&^$_+AW#<` +MX[,`E.$/$`'B`!*!X;`0PN&S()3A`2""XK,@A.&P,-7A_###X]`P@^.P,,7A +M"'"@X1@PH.,4,*?E0`"&X@$0H..%+XWB`R""X@(" +M((+B!S"@X?[__^L$$*#C(2Z-X@(#((+B!S"@X?[_ +M_^L!$*#CZCV@XP,0Q.<#((3@!S"@X?[__^N&/XWB`"`%X_(D0.,((2/E$"H$ +MX[0@P^$!'*#CMA##X1`@H.,8(7= +M$*#C#R"@XQ$^C>+^___K#`"-Y5`PH.,0,,WE;S"@XQ$PS>5E,.#C$C#-Y0D0 +MH.,3$,WE`C"@XQ0PS>404(WBM3#%X2`@H.,7(,WE`""@XQ@@S>4$8*#C&6#- +MY0$@H..Z(,7A4BH#XP(@U.>"(*#A`2""XQP@S>4%`*#C'0#-Y;XPQ>$W,.#C +M(##-Y2$PS>4&(*#C(B#-Y;,!Q>%5D*#C)9#-Y5.PH.,FL,WE)V#-Y5'@H.,H +MX,WEZ3V@XP,PU.6[8<7A`##@X[TQQ>&_,<7A,1#-Y;(B +MQ>$D`(7B"A"@X?[__^L+,*#C.C#-Y>(WU.4%((/BNR+%X3V0S>4^L,WE/V#- +MY5$0H.-`$,WE03#-Y0``4^,R(*`#$@``"@`PH.,R(*#C^`T/X_\/3^-^SJ#C +MAN^-X@(0CN"#X(/@#N&$X`S@CN`$X-[E`.#!YP$@@N)R(._F`3"#XG,P[^;B +M%]3E`P!1X?'__XKX;0_C_V]/XX8?C>(",('@#1"@XP80P^$"((+B40D(WB`@")X`H0H.$&(*#C_O__ +MZP@@G>4&H(+B>J#OYL@Z`^.S,)3ALS^_YKHPA>$"H(KB>J#OYAX\H..Z,(7A +M`J"*XGJ@[^8`,`7C\C1`XPHPB><$H(KB>J#OY@'LH..ZX(7A`J"*XGJ@[^:& +M'XWB"C"!X`8P@^``(*#C`"##Y0&@BN)ZH._F$#$!X[HPA>$"H(KB>J#OY@L@ +MU.>R/[_FNC"%X0*@BN)ZH._F"@")X.D=A.(:$('B_O__ZPL@U.<"((K@(",([@$1"@XP80P^7=$*#CD`4*#A?$"1Y71@D>4-"X#B$0"`X@00A.(&(*#C +M_O__ZP``4.,F```*!#"@X1@@\^5_`%+C(@``&@$0D^4Q'[_F"2H)XV\@1>," +M`%'A'```&J@L`^,"()7G``!2XP(``!ID`)_E]Q<`X_[__^L`()+E``!2XP(` +M`!I,`)_E.1<`X_[__^LA(M+E``!2XP0```H%`*#A!!"@X08@H.'^___K!P`` +MZ@4PT^4!`%/C!```&MT-A>(@`(#B!!"@X08@H.'^___K`0"@XW"`O>@D```` +M\$\MZ47?3>(`0*#A`8"@X600H.,!+(WBOA#"X0`0H..\$,+A#`"-XO\@H./^ +M___K+#<#X[,`E.'^___K"P#-Y5,-A.(@`(#B_O__ZP!@4.(#`0`*!`"@X0@0 +MAN+^___K;`"6Y0`0H.-H(*#C_O__ZVQPEN4'4*#A#:N$XA&@BN(`D*#C*)#E +MY0&0Q>4L`(?B"!"@X08@H./^___K,@"'X@H0H.$&(*#C_O__ZS@`A^(*$*#A +M!B"@X_[__^L'(*#AOA/RX=PW`..S`)3A#Q`!X@`2@>&P$,+ALR"4X0$@@N*S +M((3A`##5Y0$@U>4"-(/A_###XP,XH.$C.*#A4#"#XP`PQ>4C-*#A`3#%Y1@P +MH..R,<;A(#"@XQ0PAN5(`(?B0Q^-X@(0@>("(*#C_O__ZQ0PEN4",(/B%#"& +MY0$*\,-'A0CZ#XQ$>C>*T,&'A2@"'X@(@H./^___K%#"6Y0(P@^(&@*#A +M%#"HY>E=A.(`@(WE3`"'X@D0H.$'(*#C"S"%XO[__^L`@(WE`1"@XP@@H.,# +M,(7B_O__ZZ@\`^,#,)3G"0!3X0(``!JX`I_E]Q<`X_[__^L`,)/E``!3XP(` +M`!J@`I_E.1<`X_[__^LA,M/E``!3XPH```H+,-WE``!3XP<```H`@(WE`Q"@ +MXP$@H.,,,(WB`3!#XO[__^L`<*#A!0``Z@"`C>4#$*#C`2"@X^D]A.+^___K +M`'"@X:@\`^,#,)3G``!3XP(``!HT`I_E]Q<`X_[__^L`,)/E``!3XP(``!H< +M`I_E.1<`X_[__^LA,M/E``!3XQ8```J(%Y3E``!1XW@```JH-Y3E``!3XW4` +M``H'`*#AF">4Y?[__^L4();EF#>4Y0,P@N`4,(;EF`>4Y0``A^"H%Y3EO">4 +MY?[__^L4();EO#>4Y0,P@N`4,(;E9```ZA%>C>(`L`7C\K1`XP2Q)>40.@3C +MM##%X0&40-`3CN3#%X;N0Q>$!,*#C&3#-Y1`K`^.^ +M(,7AL)'%X1XPS>40-P3CLS'%X0$JH..U(<7A%P"%X@H0H.$&(*#C_O__ZQ`Q +M`N.W,L7A!SR@X[DRQ>$K`(7B`!``XP`00.,'(*#C_O__ZQ`S`N.R,\7A!JR@ +MX[2CQ>$V`(7B`!``XP`00.,&(*#C_O__ZQ`T`N.\,\7AOI/%X3$PH.-,,,WE +M$#($X[$TQ>&SI,7A10"%X@`0`.,`$$#C!B"@X_[__^L0-`7CNS3%X0(;H..] +M%,7A'BR@X[\DQ>%1L(7EM97%X1`Q`>.W-<7A>JH#XPH@U.>R/[_FN37%X5L` +MA>+I'83B&A"!XO[__^L*(-3G6S""XH$>H..S$(7A73""X@($`@(WE!P"@X=T0H.-A((+B!3"@X?[__^L`$*#A +MW0V$XB``@.+^___K%#"6Y0`P@^`4,(;E%#"6Y1@PAN4$`*#A!A"@X?[__^M% +MWXWB\(^]Z"0````00"WI_O__ZP$`H.,0@+WH\$(`0*#A`8"@X0*@ +MH.$#D*#A!#"@XW4),*#C=C#-Y0$PH.-U,,WE4#\&XYHY0.-P,(WE!S"@ +MXV\PS>4(`(WB`!"@XV0@H./^___K4PV$XB``@.+^___K`%!0XF8```H$`*#A +M"!"%XO[__^ML`)7E`!"@XV@@H./^___K;'"5Y0=@H.$`,*#C*##FY0$PQN4L +M`(?B"!"@X08@H./^___K,@"'X@T;A.(1$('B!B"@X_[__^LX`(?B"!"@X08@ +MH./^___K!R"@X;X3\N'<-P#CLP"4X0\0`>(`$H'AL!#"X;,@E.$!((+BLR"$ +MX;`PUN'\,,/CT#"#X[`PQN$%8*#A&#"@XQ0PIN5``(?B`1"@XW<@C>(&,*#A +M_O__ZP$0H.-V((WB!C"@X?[__^L$$*#C<""-X@8PH.'^___K`1"@XV\@C>(& +M,*#A_O__ZP$0H.-U((WB!C"@X?[__^L`<*#AF#"=Y0`PC>7=#83B(`"`X@<0 +MH.$*(*#A"3"@X?[__^L4,)7E`#"#X!0PA>5X,(WB`"`%X_(D0.-P("/E$"H$ +MX[0@P^$!+*#CMB##X1`@H.,0(,WE@2Z@X[D@P^$"+*#CNR##X0XKH..R()3A +MLB^_YKT@P^$`8(WE``"'X-T0H.,/(*#C_O__ZQ0PE>48,(7E!`"@X040H.'^ +M___K>-"-XO"'O>@P0"WI#-!-X@!`H.$!4*#A?!"1Y2PZ`^,#,)#G!@!3XRH` +M`!HX.`/C`S#0YP$`4^-````:#@N`XC(`@.(*$('B!B"@X_[__^L``%#C.0`` +M"B0Z`^,#,)3G`@!3XPP``!H`(*#C.#@#XP,@Q.<.*X3B"#@#XP,PU.CP3RWIC=]-X@!`H.$!8*#A`K"@X0PPC>58 +M$MWE%!"-Y00PH.,O,LWE"3"@XRXRS>50/P;CFCE`XR@RC>4!,*#C)S+-Y?]0 +MH.-*#XWB`!"@XP4@H.'^___K*`"-X@`0H.,%(*#A_O__ZP`PH.,D,(WE\BT/ +MX_\O3^,C[HWBLC".X1PPC>53#83B(`"`XO[__^L`<%#B>@$`"@0`H.$($(?B +M_O__ZVP`E^4`$*#C:""@X_[__^ML@)?E"%"@X0"0H.,HD.7E`9#%Y2P`B.(& +M$*#A!B"@X_[__^L-JX3B$:"*XC(`B.(*$*#A!B"@X_[__^LX`(CB"A"@X08@ +MH./^___K"""@X;X3\N'<-P#CLP"4X0\0`>(`$H'AL!#"X;,@E.$!((+BLR"$ +MX;`PU>'\,,/CT#"#X[`PQ>$'8*#A&#"@XQ0PIN5``(CB`1"@XXLOC>(#((+B +M!C"@X?[__^L!$*#CBR^-X@(@@N(&,*#A_O__ZP00H..*+XWB!C"@X?[__^L! +M$*#CB2^-X@,@@N(&,*#A_O__ZP<@V^7J/:#C`R#$YP$0H.,#((3@!C"@X?[_ +M_^L0`(WE2H^-XB10C>((`(OB#""=Y0@00N(((*#A!3"@X?[__^L<,(WB`#"- +MY0@`H.$D$)WE$B`!XP(P1>+^___K\ET/X_]?3^,C[HWBM3">X;,_O^:U,([A +M"`"@X0D0H.'_(*#C_O__ZP`P!>/R-$#C`#"(Y00PH.,0*@3CLR"(X0(P@^(D +M,(WE`1R@X[,0B.$D,)WE(^Z-X@,@CN`0$*#C!A%"Y0,P@^(D,(WE$"(!X[,@ +MB.$D,)WE`C"#XB0PC>4"'*#CLQ"(X20PG>4",(/B)#"-Y;4@GN$!`%+C!2R@ +M`[,@B`$$```*!0!2XP'LH`.SX(@!`1N@$[,0B!$D,)WE`C"#XB0PC>7A783B +M`E"%X@4`H.$`$`#C`!!`XP,@H./^___K``!0XQ,```KR/0_C_S]/XR,NC>*S +M,)+A`0!3XP4``!H%`*#A`!``XP`00.,#(*#C_O__ZP<``.H%`%/C!0"@X0`0 +M``,`$$`#`!``$P`00!,#(*#C_O__ZP!@C>40`)WEW1"@XR0@G>5*/XWB_O__ +MZQ``C>50,*#C*##-Y6\PH.,I,,WE93#@XRHPS>4),*#C*S#-Y0`PH.,L,,WE +M*%"-X@$PH..U,,7A%."=Y2_@S>4",*#C,##-Y;DPQ>$D.@/C`S"4YP(`4^,` +M,*`#(#"@$S,PS>4`,*#C-##-Y00PH.,U,,WE`1"@X[X0Q>%9.@/C`S#4YP$` +M$^-2.@/C`S#4YX,PH.$!,(,#.##-Y04PH.,Y,,WE`B"@X[(AQ>$W(.#C/"#- +MY3T@S>41(*#C/B#-Y;%5@*#C08#-Y5.0H.-"D,WE!+"@XT.PS>51X*#C +M1.#-Y4$Z`^,#,-3G13#-Y0DPH.-&,,WE!B"@X[\AQ>$H`(WB(0"`X@H0H.'^ +M___K"S"@XT\PS>7B-]3E!2"#XK@BQ>%2@,WE4Y#-Y52PS>51$*#C51#-Y58P +MS>4``%/C+R"@`Q(```H`,*#C+R"@X_@-#^/_#T_C?LZ@XR/NC>("$([@@^"# +MX`[AA.`,X([@!.#>Y0#@P>'Q__^* +M^(T/X_^/3^,C'HWB`C"!X`T0H.,($,/G`2""XG(@[^9ZN@/C"S#4YQ4P@^*R +M,(7A`B""XG(@[^8,((WE*)"-X@(`B>`*$*#A!B"@X_[__^L,,)WE!B"#XG(@ +M[^;(.@/CLS"4X;,_O^:R,(7A`B""XG(@[^8>[*#CLN"%X0(@@N)R(._F`#`% +MX_(T0.,",(GG!#""XG,P[^8!'*#CLQ"%X0(P@^)S,._F(^Z-X@,@CN`(@(+@ +M`""@XP`@R.4!@(/B>(#OYA`Q`>.X,(7A`H"(XGB`[^8+(-3GLC^_YK@PA>$" +M@(CB>(#OY@@`B>#I'83B&A"!XO[__^L+(-3G`H"(X'@@[^8D.@/C`S"4YP,` +M4^,;```:(QZ-X@(P@>`/$*#C"!)#Y0$P@N)S,._FH8H#XP@@U.<&((+BLR"% +MX0(P@^)S4._F**"-X@4`BN`Z'(3B,!"!X@8@H./^___K!E"%XG50[^8%`(K@ +MZAV$X@$0@>(((-3G_O__ZP@@U.<"((7@40`)WEW1"@XR@PC>+^ +M___K%#"7Y1@PA^4$`*#A!Q"@X?[__^N-WXWB\(^]Z/!'+>E(T$WB`%"@X7Q` +MD>5TH)'E`#"@XSPPS>4],,WE/C#-Y3\PS>5`,,WE03#-Y;ART>$J8-'E!("@ +MX0T+@.(1`(#B!!"$X@8@H./^___K``!0XT,!``H/8`;B!W*&X7=P_^:P,-3A +M`@L3XP0```HB-`'CLS"5X0<`4^$``*`#.0$`"B(T`>.S<(7A!&"@X1@P]N4$ +M`%/C,@$`&@$PUN4)`%/C+P$`&@(@EN4R+[_F"3H)XV\P1>,#`%+A*0$`&J@\ +M`^,#,)7G``!3XP(``!J#87B&`"`XO[__^LH.@/C`S"5YRPJ`^,"()7G`@!3X2PJ`Q,",(47+#H# +MXP,PE><)`%/C!```"B@J`^,"()7G`@!3X2@J`Q,",(47#IN%XCR0B>()`*#A +M/!"-X@8@H./^___K"D"(X@D`H.$$$*#A!B"@X_[__^L'`*#A!A"@X0H@H.'^ +M___K``"-Y04`H.$$$*#A!B"@X0HPH.'^___K`#``XP`P0.,`$)/EW@V%XA@` +M@.)]'X'B_O__ZP$`H./+``#J+#H#XP,PE><)`%/CQ@``&MY-A>(80(3B!`"@ +MX?[__^L'`*#A!A"@X0H@H.'^___K`""@X6`W`^,#`)7G"A"(XO[__^L!(*#C +MZCV@XP,@Q>=4,$/B`S"5YPL`4^.R```:U#*?Y0`0D^4$`*#A?1^!XO[__^L! +M`*#CK```Z@<`H.$&$*#A"B"@X?[__^L!`*#CI@``Z@@`AN(($$KB`""@XT0P +MC>+^___K``!0XYX```H,,(WB`""@XP0@@^0$((/D!""#Y`0@@^0$((/D!""# +MY`0@@^0$((/D!""#Y+`@P^$X((WE#$"-XC@PC>(`,(WE1!"=Y0\@H.,$,*#A +M_O__Z^D-A>(3`(#B!!"@X08@H./^___K+#H#XP,PE><,`%/C#""@$RPZ`Q,# +M((47Z4V%XA-`A.($`*#AX1V%XBD0@>+^___K!R#6Y>\Y`^,#(,7G`#!0X@$P +MH!,%`*#A!!"@X?[__^L!`*#C<```Z@`@H.,X(,WE-""-Y0@`AN(($$KB1#"- +MXO[__^L``%#C9@``"C0PC>(`,(WE1!"=Y0`@H.,X,(WB_O__ZS0PG>4!`%/C +M$P``&C@PW>4``%/C"```&B0Z`^,#,)7G`@!3XU8```H"(*#C)#H#XP,@A>=*``#J)#H#XP,P +ME><" +M`%/A*"H#$P(PA1#87B&`"`XGT?@>+^___K`0"@XQ4``.K>;87B&&"&X@8`H.'^___K+#H# +MXP,PE><'`%/C!R"@$RPZ`Q,#((47!P"@X000H.'^___K`#``XP`P0.,`$)/E +M!@"@X7T?@>+^___K`0"@XP```.H!`*#C2-"-XO"'O>@D`````````/!!+>D` +M4*#A?$"1Y01@H.$-"X#B$0"`X@00A.(&(*#C_O__ZP``4.-7```*'#N5Y0,@ +M`^(#`%+C`0``"@$)$^-1```*"G"&XEL-A>(X`(#B!Q"@X?[__^L``%#C2@`` +M"A@P].4#`%/C1P``&M`[U>4``%/C1```"@$PU.4!`%/C%@``"@(``#H"`%/C +M/@``&B<``.J];H7B#6"&X@8`H.$"$(3B!R"@X_[__^L%`*#A!A"@X0<@H.'^ +M___KVSO5Y0$`4^,%`*#A!Q"@X0$@H.,`,*`#)3"@$_[__^LJ``#J!3#4Y5,1 +MXN<$(-3E`S#4Y0(TD^$)```:`3"@XQ,QH.%S,._FFR;0Y0(@@^&;)L#EG";0 +MY0,PPN&<-L#E&@``ZILVT.4!(*#C$A'#X9L6P.45``#J`S#TY0@`$^,*```: +M(S*@X0$@H..;%M#E$C/!X9LVP.4`$-3E(1*@X9PVT.42(/H/B`""@XP@@P^4`(.#CNB##X0$`H./P@;WH\$$MZ0!` +MH.%\4)'E!7"@X1!@A>+"#H#B#`"`XO[__^L`$*#A!@"@X08@H./^___K``!0 +MXRP```JX(=7A;#"4Y1``$^,C```*6PV$XC@`@.(*$(7B_O__ZP!@4.(B```* +M_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B!""#Y6M>AN((4(7B!0"@X?[__^L` +M`%#C"```&KPVEN6X)I;E!#""Y0`@@^6X5H;EO%:&Y00`H.$&$*#A_O__ZPT@ +MH.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^L$``#J!`"@X080H.'^___K`#"@ +MXQ@UQ.4!`*#C\(&]Z/!!+>D`0*#A?%"1Y05PH.$08(7BP@Z`X@P`@.+^___K +M`!"@X08`H.$&(*#C_O__ZP``4.,L```*N"'5X6PPE.40`!/C(P``"EL-A.(X +M`(#B"A"%XO[__^L`8%#B(@``"O[__^L-(*#A?SW"XS\PP^,$()/E`2""X@0@ +M@^5K7H;B"%"%X@4`H.'^___K``!0XP@``!J\-I;EN":6Y00P@N4`((/EN%:& +MY;Q6AN4$`*#A!A"@X?[__^L-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K +M!```Z@0`H.$&$*#A_O__ZP`PH.,8-<3E`0"@X_"!O>CX3RWI`%"@X7Q`D>5T +M@)'E#0N`XA$`@.($8*#AL##4X0$,$^,"(*`3`""@`],TX.<#,(+A`0!3XP00 +MA`(!```*$!"$(@00A#(&(*#C_O__ZP``4.-/```*'#N5Y0D+$^-,```*`0D3 +MXTH``!I/#87B&`"`XO[__^NZ,=;A``!3XP`PH!,<.X45`Z#@$SX``!JX,=;A +MR"L`X[(PA>$!"Q/C"3"@$Q0PH`/+.\7EO*'6X0JIH.$JJ:#AQ#L`X[.@A>$> +M`%CC*```FAY@H./,D)_E!K"@XP9PA.``,-?E+0!3XQ$```H"``"**@!3XQD` +M`!H5``#J/0!3XP\```K=`%/C%```&@(`A^()$*#A"R"@X?[__^L``%#C#@`` +M"@4`H.$'$*#A_O__ZPH``.H%`*#A!Q"@X?[__^L&``#J!0"@X0<0H.'^___K +M`@``Z@4`H.$'$*#A_O__ZP$PU^4",(/B`V"&X`8`6.'9__^*'#N5Y0(ZP^,! +M.8/C'#N%Y04`H.$R'87B#!"!XG+8_^L%`*#A"A"@X?[__^L!`*#C^(^]Z``% +M``#P3RWI'-!-X@!`H.%\8)'E=)"1Y1P[D.4#,`/B`P!3XP``H!/$```:!B"@ +MX<@X`>,#@)3GNC'6X00PC>6XH=;A`@!8XP8``!K,.`'C`S"4YP$`4^.]```* +M!0!3X[L```H`@*#C`;!XX@"PH#,``%KC`#"@`P$P"Q(``%/CL```&@$P>N(` +M,*`S##"-Y0$`6.,``%H#J@``"EM=A.(X4(7B"B""X@@@C>4%`*#A`A"@X?[_ +M_^L`<%#B"@``&@4`H.$($)WE_O__ZP!P4.(18*`#E```"@$\H./0,(?E`#"@ +MX\PVA^49``#J_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B!""#Y6M>A^((4(7B +M!0"@X?[__^L``%#C!0``&KPVE^6X)I?E!#""Y0`@@^6X5H?EO%:'Y0T@H.%_ +M/<+C/S##XP0@D^4!($+B!""#Y?[__^O^___K#2"@X7\]PN,_,,/C!""3Y0$@ +M@N($((/E&UV'X@4`H.'^___K``!0XP,```H%`*#A!AN$XB@0@>+^___K#2"@ +MX7\]PN,_,,/C!""3Y0$@0N($((/E_O__Z\PVE^4``%/C,#@!`P,PE`?(-H<% +M!%"=Y,#,)3GR#:'Y="F +MA^4C``#J`0!5XP<``!K0,)?E`3S#XP(\@^/0,(?ET*:'Y0(PH./,-H?E&0`` +MZ@,`5>,C```:(@"&XA`0H.,4((WB(C!)XO[__^L``%#C'@``"A0PG>4``%/C +M&P``"FT>A^("`(#B!!"!XH`@H./^___K``!0XQ0```K0,)?E`CS#XP$[@^/0 +M,(?E-#@!XP,PE.?(-H?E`5"%XLQ6A^4$`*#A!Q"@X0`@H./^___KT#"7Y0$+ +M$^,`,*`3S#:'%0$`H.,6``#J#F"@XP```.H/8*#C``!7XPP```H`4`#C`%!` +MXPAPA>('`*#A`!"@XR$MH./^___K`C"@X]0VA>7H`(7B"!"=Y08@H./^___K +M!`"@X0<0H.$&(*#A_O__ZP``H.,N(` +M,*`S##"-Y0"PH.-,___J\$\MZ4'?3>(`0*#A`2"@X4`PC>+0&9_E`P"1Z`0` +M@^2P$,/A?%"2Y71@DN4`,*#C*#"-Y1P[E.4#,`/B`P!3XUH"`!JPH-7A_*`: +MX@2`H`,*@*`3&#"(X@,`5N%3`@`Z"I"%XEL-A.(X`(#B"1"@X?[__^L`<%#B +M.@(`"AD0U>48(-7ET#"7Y0$+$^,!.\,3`CJ#$]`PAQ4$```:`0D3XP$YPQ," +M.H,3T#"'%2T"``H8D$;B"9!HX!B`B.((@(7@`22"X50W`..S((?A"`"@X0D0 +MH.%(((WB`3"@X_[__^L!`'#C)0(`"D@PG>4``%/C(@(`"@R0C>4(`*#A`!"@ +MXSP@C>(),*#A_O__ZP"PH.$\,)WE``!3XQ@"``H"`(#BPQZ$X@P0@>(X+)3E +M_O__ZP``4.,!L*`#`0``"@&P>^(`L*`S.#R4Y3P@G>4#`%+A"@(`&@``6^,) +M`@`:"`"@X0$0H.,\((WB##"=Y?[__^L`$%#B`0(`"BP`C>("$('B/""=Y?[_ +M_^L!+(WBQ#`RY1`PC>4(`*#A,A"@XPPPG>7^___K`!!0X@L```H0,)WE$`!3 +MXP@``(HL`(WB`P"`X`(0@>(\()WE_O__ZSPPG>40()WE`R""X!`@C>40,)WE +M0#&'Y1,.A^(L$(WB$""=Y?[__^L`$*#C7!>'Y6`7A^5D%X?E:!>'Y6P7A^4' +M,*#ACY04P@^(0,(WE`P"@X2`@H./^___K!#H!XP,PE.<"`!/C(P``"J`@ +MG>4``%+C(```"@`PH.,@,(WE)#"-Y10@C>6D,-WE&#"-Y0(`0N("$(/B(""- +MXB0PC>+^___K`0!0X](!`!H!,*#C7#>'Y6`WE^4",(/C8#>'Y0PZ`>,#,)3G +M(""=Y0,P`N!H-X?E%"H!XP(0E.4@,(WEF""=Y10@ +MC>6<,-WE&#"-Y0(`0N("$(/B)""-XB`PC>+^___K`0!0XZL!`!H!,*#C7#>' +MY6`WE^4!,(/C8#>'Y0@Z`>,#,)3G)""=Y0,P`N!D-X?E$"H!XP(0E.<@()WE +M`2`"X&PGA^4``%/C*;"@`P``4N.6`0`*``!;XX8!`!I8-Y?E`SK#XU@WA^44 +M()WE``!2XQL``!JX()WE``!2XP$Z@Q,".H,#6#>'Y00Z`>,#,)3G``!3XR8` +M``I8-Y?E`PH3XR,```J`-Y3E``!3XR````H`(*#C`3R-XN`@8^4`((WE@`>4 +MY9`7E.5!(`'C_O__ZR`PW>4``%/C$;"@`V4!``H3``#J!"H!XP(@E.<``%+C +M*+"@`U\!``JX()WE``!2XP$Z@Q-8-X<5"0``&A@PG>4"((/B(`!2XR`@H",` +M`%+C`P``VA``G>44,)WE`A!#XO[__^M8-Y?E`CS#XU@WA^4`,*#CW#"'Y:`W +MQ^4!(*#CIB?'Y:4WQ^6D-\?EHS?'Y:(WQ^7,-)3E``!3XT\```H!+(WB`#"@ +MX\0P(N40((WE"`"@X11@C>484(WE'*"-Y0Q@G>4(H*#A!X"@X01PH.$"4*#A +MW1"@XP4@H.$&,*#A_O__ZP!`4.(V```*`@"$XD`0C>(&(*#C_O__ZP``4.,L +M```*#$"-Y11@G>484)WE!T"@X0APH.$*@*#A'*"=Y5@WE^4"/(/C6#>'Y0$P +MH./<,(?E#""=Y0@PTN6@-\?ETR+AYZ$GQ^4/,`/B#P!3XP$PH!,`,*`#IC?' +MY:`WU^4/`!/C'0``"@$`$^,#,*`3`#"@`Z4WQ^6@-]?E`@`3XP,PH!,`,*`# +MI#?'Y:`WU^4$`!/C`S"@$P`PH`.B-\?EH#?7Y0@`$^,#,*`3`#"@`Z,WQ^4) +M``#J/`"=Y0(`@.(``(3@PO__ZA1@G>484)WE!T"@X0APH.$*@*#A'*"=Y6D^ +MA^(-,(/B##"-Y0,`H.$`$*#C&B"@X_[__^OH,)WE``!3XPH```KL,-WE&0!3 +MXP<``)I8-Y?E"CR#XU@WA^4,`)WEZ!"=Y1H@H./^___K`@``ZE@WE^4".\/C +M6#>'Y=@TE.4``%/C`@``&E@WE^4""Q/CT@``&EC'E^4"P8SC6,>'Y4`!E^4` +M`%#C$0``"C`QU^5_,`/B%@!3XP<@H-$`,*#3"```V@0``.HQ$=+E?Q`!X@$@ +M@N(6`%'C`@``V@+!S.-8QX?E`@``Z@$P@^(``%/A]/__&E0W`..S,)?A(``3 +MXU@WE^6`,(,3@###`U@WA^4`,*#CK#?'Y20Z`^,#,)3G`P!3XQ0``!H(`*#A +M"1"@X0`@H.,H,(WB_O__ZP``4.,-```*`3"@XZPWQ^7=#83B(`"`X@40H.$& +M(*#A!S"@X?[__^MP`._F``!0XZT'QQ4*L*`3F@``&@```.H``*#CK0?'Y=0P +ME^4``%/C&0``&@$P@^+4,(?E/#@!XP,PE.<``%/C`3"#`I\``!H'``#J`!"2 +MY0``4>,$```*`3"#XM0PA^4$((+B(0!3X_?__QIC+:#CLB"4X0,`4N$`,*`S +MU#"'-1&PH#-]```Z!CR#X@,QA.`X<(/ET#"7Y0(ZP^,!.8/CT#"'Y?[__^L- +M(*#A?SW"XS\PP^,$()/E`2""X@0@@^4;C8?B"`"@X?[__^L``%#C!0``&L0V +ME^7`)I?E!#""Y0`@@^7`AH?EQ(:'Y0TPH.%_C@JL*#C[___ZBBPH./M +M___J`C"@X]0PA^5A+83B7/__ZE@WE^4#.L/C6#>'Y63^_^J0$@``^$\MZ0!` +MH.%\8)'E='"1Y<@YD.4#`%/C`0``&O[__^MU``#J!E"@X<(.@.(,`(#B_O__ +MZP`0H.$0`(;B!B"@X_[__^L``%#C:P``"GV.A.(<*Y3E`0P2XPH```H8`(;B +M&!!'XO[__^O*"\3E"`"@X080H.$'(*#A_O__ZP0`H.'^___K7```ZEL-A.(X +M`(#B'!N4Y0,P!.,`,$#C`S`!X`(0!.,!`%/A'```&@H0AN+^___K`#!0XD\` +M``H6+J#CTJ"#X58OH./2`(/A`(":X`&0J^!:+Z#CT@"#X0"@F.`!L*G@#X"@ +MXP"0H.,(``K@"1`+X`$@D.$#```:!`"@X080H.$'(*#A_O__ZP0`H.$8$(;B +M&"!'XO[__^LV``#J`R`"X@$`4N,S```:"J"&X@H0H.'^___K`#!0XA0```H6 +M+J#CTJ"#X58OH./2`(/A`(":X`&0J^!:+Z#CT@"#X0"@F.`!L*G@#X"@XP"0 +MH.,(``K@"1`+X`$@D.$>```:!`"@X080H.$'(*#A_O__ZQD``.H$`*#A_O__ +MZP!0H.$@`%#C%```"@0`H.$D$(;B)"!'X@4PH.'^___K``!0XP4``!I],(7B +M@S*$X`@P@^(`(*#C`""#Y0<``.H(`*#A!A"@X0<@H.'^___K!`"@X0H0H.$% +M(*#A_O__ZP$`H./XC[WH\$`MZ0S03>(`0*#A?%"1Y71PD>4L.@/C`S"0YP`` +M4^,I```*`0!3XR<```HD*@/C`B"0YP(`4N,C```*!0!3XR$```H#`%/C'P`` +M"E8PT>4#`%/C'```FMT-@.(@`(#B!1"@X0<@H.'^___K<&#OY@$`5N,5```: +M)#H#XP,PE.$!#!+C`C"@$P`PH`/2).#G`C"#X0$`4^,0 +M$(4"!```"@H0A3("```Z`@!3XQ@0A1(*$(4"!`"@X?[__^LQ``#J`&"@XVPP +ME.4(`!/C+0``&@$`$^,!```:4``3XRD```H8`(7B`!"@XP0@C>(8,$?B_O__ +MZP``4.,B```*`0!6XPD```H$,)WE``!3XP8```H"`(#BPQZ$X@P0@>(X+)3E +M_O__ZP``4.,6```*;#"4Y0$`$^,3```*V#"4Y0$`4^,0```:L"#5X0$,$N," +M,*`3`#"@`](DX.<",(/A`0!3XQ`0A0($```*"A"%,@(``#H"`%/C&!"%$@H0 +MA0($`*#A!B"@X?[__^L!`*#C#-"-XO"`O>CP0"WI#-!-X@!@H.$!0*#A#3"@ +MX3@AG^4#`)+H!`"#Y+`0P^%\4)3E!7"@X;`PU>$,`!/C1```&@10A>(%`*#A +M#1N&XA$0@>(&(*#C_O__ZP``4.,%```:!0"@X0T0H.$&(*#C_O__ZP``4.,V +M```*L##7X?PP`^)#$J#A#0!1XS$``,J!$('@R""?Y0$1@N!``%/C%P``"@0` +M`,H``%/C$```"B``4^,>```:#0``ZK``4^,$```*T`!3XQ4```J``%/C%P`` +M&@X``.IL,);E$``3XP`P`!,`,$`3`#```P`P0`,(,('E!@"@X00@H.$PU__K +M%```Z@8`H.$$(*#A+-?_ZQ```.H&`*#A!""@X2C7_^L,``#J!@"@X00@H.$D +MU__K"```Z@8`H.$$(*#A(-?_ZVPPEN40`!/C`@``"@8`H.$$$*#A_O__ZPS0 +MC>+P@+WHF!(```@%``#P0"WI)-!-X@!`H.'0!X3E$,"-XE@QG^4/`)/H!P"L +MZ``PS.4-,*#A`%"@XP10@^0$4(/D!%"#Y`!0P^4!8*#C`6#-Y0)PH.,"<,WE +M`S"@XP,PS>4`,.#C!##-Y7T.A.((`(#B!1"@X?[__^O<-P#CLU"$X6$[`N,# +M,-3GWC?$Y=]7Q.7@5\3E$#0!XP-0A.=B.P+C`S#4Y^$WQ.6;#H3B"0"`XA`0 +MC>(-(*#C_O__ZYH.A.(,`(#B#1"@X0T@H./^___KR%F$Y=!9A.7,683E#C0! +MXP-0Q.<<6X3E(%N$Y21;A.4H6X3E+%N$Y3!;A.4\6X3E0%N$Y3A;A.4T6X3E +M+0V$X@0`@.(%$*#A@""@X_[__^L),*#CRSO$Y-D(*#CLR"$X=1GQ.4&`*#A)-"-XO"`O>B@$@````!1XQD``-H`,-#E?S`# +MX@0`4^,"`%,3$@``"@L`4^,0```*%@!3XP`@H!,)```:#```Z@(PT.=_,`/B +M!`!3XP(`4Q,'```*"P!3XP4```H6`%/C`P``"@$@@N(!`%+A\___&@$``.H! +M`*#C'O\OX0``H.,>_R_A``!1XPX``-H`,*#C`R#0YW\@`N("`%+C!`!2$P4` +M``H+`%+C`P``"A8`4N,!```*``"@XQ[_+^$!,(/B`0!3X?'__QH!`*#C'O\O +MX0$`0.)P`._F$P!0XP0`H(,`,`"3`#!`DP``TY<>_R_A<$`MZ0%`H.$"8*#A +MWC?0Y0X`4^,$``":T`O0Y0``4.,4`*`3!`"@`W"`O>C06]#E``!5XPA0H!,` +M4*`#`0"@X0(0H.'^___K`0!0XP$`A0-P@+T(!`"@X080H.'^___K`0!0XP,` +MA0,"`(43<("]Z'\``.(+`%#C``"@@P`P`),`,$"3``"#D!0`T)4>_R_A<$`M +MZ0!0H.$!8*#A`$"@XP0PA>"L"=/E`C"`XG,P[^8!`%/C!```FO[__^L&`%#A +M`0``&@$`H.-P@+WH`4"$X@T`5./Q__\:``"@XW"`O>CP1RWI`("@X0&@H.&; +M3H#B"4"$XB=M@.(&8(;B`'"@XW^0X.,``-3E_@!0XPL```K_`%#C#```"O[_ +M_^L`4*#A"`"@X040H.'^___K`0!0XPE0A0%U4.\&!U#*YP%PA^(!0(3B!@!4 +MX>W__QH'`*#A\(>]Z`3@+>4,T$WB"""-X@$PH.,!,&+E%A"@XV0[`^,/X*#A +M`_"0YPS0C>(`@+WH!.`MY0S03>((((WB`#"@XP$P8N46$*#C9#L#XP_@H.$# +M\)#G#-"-X@"`O>@$X"WE#-!-X@`PH.$$$(WE`0!2XQ<0H`,8$*`3!""-XF3+ +M`^,/X*#A#/"3YPS0C>(`@+WH!.`MY0S03>((((WB`1!BY0`0H.-D.P/C#^"@ +MX0/PD.<,T(WB`("]Z!!`+>E<.P/C`S"0YP``4^,0@+T(,_\OX1"`O>@00"WI +M6#L#XP,PD.<``%/C$("]"#/_+^$0@+WH<$`MZ0!`H.$#8*#A`E"@X0``4N,` +M`%,3`0``&O[__^L$``#J`0!2XP(0@0("$$$2<1#OYO[__^L$`*#A!A"@X04@ +MH.'^___K<("]Z`$`$.,#`*`3T`#@!Q[_+^$$`(#B'O\OX0``4.,``*`#'O\O +M`1PKD.4#,`3C`#!`XP,P`N`"``3C``!3X0``H!,!`*`#'O\OX1PKD.4#,`3C +M`#!`XP,P`N`!``3C``!3X0``H!,!`*`#'O\OX>@_D.4!`%/C"P``"@`@H.," +M,(#@`3J#X@@P@^(`,)/E`0!3XP0```H@((+B.@Y2X_;__QH!`*#C'O\OX0`` +MH.,>_R_A``&@X6\W`>,#`%#A<`_R_A!.`M +MY0S03>((((WB`1!BY1D0H.-D.P/C#^"@X0/PD.<,T(WB`("]Z!!`+>D:$*#C +M`""@XV0[`^,/X*#A`_"0YQ"`O>CP3RWI%-!-X@!PH.$$((WE`V"@X8&QH.$% +M4(OB!$"@XV2+`^,(H(WB&Y"@XP$``.H!0$3B`5!%X@$PE.("```*`0!3XQ\` +M`!H.``#J`"#6Y000G>4"*('A`1#6Y0$L@N$(((WE"["#X`RPC>4'`*#A&Q"@ +MXP@@C>)D.P/C#^"@X0/PE^4,4(WE!P"@X0D0H.$*(*#A#^"@X0CPE^<``%3CQ/__JA30C>+PC[WH!.`M +MY2303>(`(*#C&"#-Y1D@S>4:(,WE&R#-Y1P@S>4=(,WE"#"-X@0@@^0$((/D +M!""#Y``@@^4(,(WB`#"-Y1@PC>+^___K)-"-X@"`O>CH/Y#E``!3XP(@H`,% +M```*`3J`X@@P@^(#(*#C`!"3Y0``4>,'```:@C*`X`$0H..H'X/E^@Z#X@@` +M@.(`,*#C"#"`Y0,``.H!((+B(#"#XB``4N/P__\:`@"@X1[_+^'P3RWI#-!- +MX@!0H.'-.]#E``!3XU4UP`54```*`#"@XP7AA]#E`0!8XPJ`H`,0@*`3 +MODZ`X@9`A.*_;H#B!F"&XF2K`^,-D*#A';"@XP9PH.$`,-3E4V+@YP$@U.4/ +M$`+B(B*@X0(FH.$!)(+ALA#4X0$H@N$/$`/BRPO5Y9"!(>!Q$._F`2""X0`@ +MC>73,N'G`P!3XP/QGY$*#C#2"@X0_@H.$*\)7G!S#=Y09A@^$'8,WE!P``Z@4`H.$+ +M$*#A#2"@X0_@H.$*\)7G!S#=Y89A@^$'8,WE!$"$X@<`5.'%__\:>CL"XP,P +MU>+PC[WH\$`MZ0S03>(`0*#A``!1XST```K8-)#E``!3XSH```H!,*#C +MT3O`Y0$PT>4``%/C'```"K\N@.(&((+B`#"@XP(`4^,%```*`P"!X`+`T.4` +M`-+E```,X```PN4,``#J^,O4Y00`T>4#<`SB`V``X@8`5^$#8`S2'%`,XAS@ +M`.(.`%7A'``,PAP``-(&`(#A^`O$Y0$P@^(!((+B`0#1Y0,`4.'E__^*!`"@ +MX100H.,'((WB:#L#XP_@H.$#\)3GOTZ$X@E`A.(`,*#C`,``XP#`0.,```#C +M``!`XP<@W>4``%+C`P!2$P`0TP<,$-,7`"#4Y0(@`>``(,3E`3"#X@%`A.(0 +M`%/C\___&@S0C>+P@+WH,$`MZ0S03>(`0*#ATCO0Y0``4^,4```*T3O0Y0`` +M4^,1```*`3"@X]`[P.7X.]#E`R`#X@<@S>53,>+G"""-X@(P8N5D6P/C(A"@ +MXP_@H.$%\)3G!`"@X2,0H.,'((WB#^"@X07PE.4>_R_A`#"@XTTQP>5,,<'E'O\OX7\``.($`$#B:`!0XP#QGY=J``#J +M*&0!`-AC`0#88P$`V&,!`-AC`0#88P$`V&,!`"!D`0`09`$`V&,!`-AC`0#8 +M8P$`V&,!`-AC`0`(9`$`V&,!`-AC`0#88P$`&&0!`-AC`0``9`$`V&,!`-AC +M`0#88P$`V&,!`-AC`0#88P$`V&,!`-AC`0#88P$`V&,!`-AC`0#X8P$`V&,! +M`-AC`0#88P$`V&,!`-AC`0#88P$`V&,!`-AC`0#88P$`V&,!`-AC`0#P8P$` +MV&,!`-AC`0#88P$`V&,!`-AC`0#88P$`V&,!`-AC`0#88P$`V&,!`-AC`0#8 +M8P$`V&,!`-AC`0#88P$`V&,!`-AC`0#88P$`V&,!`-AC`0#88P$`V&,!`-AC +M`0#H8P$`V&,!`-AC`0#88P$`V&,!`-AC`0#88P$`V&,!`-AC`0#88P$`V&,! +M`-AC`0#88P$`V&,!`-AC`0#88P$`V&,!`-AC`0#88P$`V&,!`-AC`0#88P$` +MV&,!`-AC`0#@8P$`V&,!`-AC`0#88P$`V&,!`-AC`0#88P$`V&,!`-AC`0#8 +M8P$`V&,!`-AC`0#08P$`"P"@XQ[_+^$``*#C'O\OX0H`H.,>_R_A"0"@XQ[_ +M+^$(`*#C'O\OX0<`H.,>_R_A!@"@XQ[_+^$%`*#C'O\OX00`H.,>_R_A`P"@ +MXQ[_+^$"`*#C'O\OX0$`H.,>_R_A\$$MZ0!@H.$-`%'C`5"@,0U0H",``%7C +M`'"@`PH```H`<*#C!T"@X0&`H.,$`-;G@``0XP$```K^___K&'"'X0%`A.(% +M`%3A]___&@<`H.'P@;WH\$$MZ0!PH.$-`%'C`6"@,0U@H",``%;C`%"@`P@` +M``H`4*#C!4"@X0&`H.,$`-?G_O__ZQA0A>$!0(3B!@!4X?G__QH%`*#A\(&] +MZ`0@T.4#,-#E`S:@X0(*@^$>_R_AT#O0Y0``4^,,```*RCO0Y00`4^,)```* +MWS?0Y0$`$^,&,*`3!3"@`P`@T>4!`-'E``2"X5`#H.$!``#B'O\OX0``H.,> +M_R_A`@,0XQLPH!,#```:&C"@XP$@H.,2$Q#@`0``"G,`[^8>_R_A`3!#X@$` +M<^/X__\:``"@XQ[_+^$$(-#E`S#0Y0(D@^$""1+C#P"@$P8``!H.`*#C4C"@ +MX0$`$^,"```:`0!`X@$`<./Y__\:<`#OYA[_+^$00"WI?#L#XP_@H.$#\)#G +M$("]Z!!`+>G^___K$("]Z!!`+>G8$)'E_O__ZQ"`O>@00"WIRCO0Y00`4^,) +M```*"`!3XP(```H!`%/C$```&@L``.H!,*#CU#O`Y0`PH./5.\#E$("]Z``@ +MH./4*\#E`3"@X]4[P.4$$.#C_O__ZQ"`O>@$$.#C`""@X_[__^L0@+WH`#"@ +MX]0[P.4!,*#CU3O`Y1"`O>@P0"WI#-!-X@!`H.$!4*#A(``1XPP```K,.]#E +M`P!3XQ4```H(((WB`3"@XP$P8N4#,*#CS#O`Y1$0H.-D.P/C#^"@X0/PE.<+ +M``#JS#O0Y0$`4^,(```*"""-X@`PH.,!,&+E`3"@X\P[P.41$*#C9#L#XP_@ +MH.$#\)3G`@`5XQ0PH!/+.\05$@``&N$WU.4*`!/C"P``"@$+%>,$```*RSO4 +MY0D`4^,),*`3RSO$%0@``.K+.]3E%`!3XQ0PH!/+.\05`P``ZA0`$^,),*`3 +M%#"@`\L[Q.4$`*#A#Q"@XR\MA.(+((+B9#L#XP_@H.$#\)3G#-"-XC"`O>@> +M_R_A,``MZ1@0@>($,)'E`""@XTC,`./\((#A`!"1Y0%`@N$#4*#A_$"`X3`` +MO>@>_R_A$$`MZ0D0H.,`(*#C9#L#XP_@H.$#\)#G$("]Z!!`+>GN/:#C#^"@ +MX0/PD.<0@+WH<$`MZ0!`H.$!4*#A6PV`XC@`@.("$*#A_O__ZP``4.-P@+T( +M`2#5Y5(AX^>"(8+@@C&`X!X^@^(`(.#CNB##X=LKU.4!`%+C`""@$P$@H`,( +M(,/E<("]Z/!!+>D(T$WB`("@X0%0H.$#0*#A!&"-X@)PH.$!`*#A`1"@XP8@ +MH.$',*#A_O__ZP`04.(4```*A$*(X/M.A.($0(3B!`"@X0(0@>($()WE_O__ +MZP2`G>4%`*#A,A"@XP8@H.$',*#A_O__ZP`04.(!`*`#!```"@@`A.`"$('B +M!""=Y?[__^L!`*#C"-"-XO"!O>@00"WIX3?0Y0$`$^.!`H#@^PZ`X@0`@.(` +M$``3`!!`$P@0GP4$(*#C_O__ZQ"`O>C(!0``$$`MZ0$PH.$!(-'E`0!2XQ"` +MO8@!(*#CSBO`Y2\-@.(/`(#B`A"!X@$@T^7^___K$("]Z/!/+>D4T$WB`&"@ +MX0%PH.$`,(WE)(!2XD4```I;K8#B.*"*XL,>@.($$(WE`$"@XP&PH.,$D*#A +M`#``XP`P0.,,,(WE"$"-Y210A.(%4(?@`##5Y2H`4^,J```*/0!3XRX``!H` +M`%7C+```"@,PU>4$`!/C"2"@`0@PG04)```*`S`#X@$@0^("`%+C"2"@@0LP +MH($!,$.2#!"=E0,@@9`@,-*5)"#2E=\7UN4#`%'A`P``&N`7UN4"`%'AW)O& +M!18```K`GQN4*`*#A!!"=Y?[__^L``%#C#@``"H0VD.4``%/C +MWS?6%9@VP!7@-]85F3;`%9B6P`69EL`%!0``Z@8`H.$%$*#A_O__ZP8`H.$` +M$)WE_O__ZP$PU>4",(/B`T"$X`0`6.'$__^*%-"-XO"/O>@00"WI`#!1XA"` +MO0C8))#E``!2XQ"`O0@!(-/E%@!2XQ"`O8@!(*#CTBO`Y<$.@.(&`(#B`A"# +MX@$@T^7^___K$("]Z!!`+>G,-)#E``!3XP!`H`/-2\`%!`"@`1"`O0@!0*#C +MS4O`Y;X.@.($`(#B"!"!XA(@H./^___K!`"@X1"`O>CP0"WI#-!-X@!`H.$R +M78#B#%"%X@4`H.'^___KTCO4Y0``4^,#```*T3O4Y0``4^,!,*`3T#O$%=XW +MU.4.`%/C!```FM![U.4``%?C%'"@$P1PH`,0``#JT'O4Y0``5^,(<*`3`'"@ +M`P!@H.$%`*#A!A"@X?[__^L!`%#C`7"'`P4```H%`*#A!A"@X?[__^L!`%#C +M`W"'`P)PAQ-B.P+C`S#4YP-P!^#A=\3E`G!'XG=P[^8!`%?C"CH`DPX^`(.V +M,,WA!`"@X1`0H.,&((WB9#L#XP_@H.$#\)3G#-"-XO"`O>CP3RWI'-!-X@"@ +MH.$!@*#A#`!1XUX``)H,4*#C`'``XP!P0.,(L(?B!3"'X`0PC>40,(?B"#"- +MY120A^(8,(?B##"-Y1PPA^(0,(WE(#"'XA0PC>4%8(K@`##6Y=T`4^-!```: +M`D"&X@0`H.$+$*#A`R"@X_[__^L``%#C0```&@0`H.$$$)WE`R"@X_[__^L` +M`%#C.@``&@0`H.$($)WE`R"@X_[__^L``%#C-@``&@0`H.$)$*#A`R"@X_[_ +M_^L``%#C,```&@0`H.$)$*#A`R"@X_[__^L``%#C*@``&@0`H.$,$)WE`R"@ +MX_[__^L``%#C"`"@$R8``!H$`*#A$!"=Y0,@H./^___K``!0XP0`H!,?```: +M!`"@X100G>4#(*#C_O__ZP``4.,&`*`3&```&@0`H.$D$(?B`R"@X_[__^L` +M`%#C`0"@$Q$``!H$`*#A*!"'X@,@H./^___K``!0XPL`H!,*```:`3#6Y0(P +M@^(#4(7@!0!8X;3__XH#``#J!0"@XP(``.H#`*#C````Z@``H.,D,T$WB`'"@X<(.@.(,`(#B_O__ZQ``$.,P```*H#R7Y0P`4^,M``": +MRHZ'X@2`B.(,0*#C`)``XP"00.,$H*#C`+``XP"P0.,`,`#C`#!`XP0PC>4$ +M8(C@`##6Y3``4^,/```*W0!3XQ,``!H"4(;B!0"@X0L0H.$*(*#A_O__ZP`` +M4.,,```*#`"%X@00G>4*(*#A_O__ZP``4.,&```*#```Z@H`AN()$*#A"B"@ +MX?[__^L``%#C!@``&@$PUN4",(/B`T"$X*`\E^4$`%/AW___B@$``.H!`*#C +M````Z@``H.,,T(WB\(^]Z!!`+>D`0*#A&A"@XP`@H.-D.P/C#^"@X0/PD.?Z +M#H3B!`"`X@`0H.,!*Z#C_O__ZQ"`O>CP0"WI%-!-X@!0H.$!<*#A`F"@X0U` +MH.$-`*#A`!"@XPT@H./^___K!0"@X0T0H.'^___K`""@X0``AN4'`*#A#1"@ +MX?[__^L4T(WB\("]Z`3@+>4,T$WB>`"`XO[__^L`$*#A!@"-X@(@H./^___K +MM@#=X0S0C>(`@+WH<$`MZ0C03>(`0*#A#U`!XA@S`^,#,-#G!0!3X2(```K0 +M.P/C`S"0YP$`4^,#```*X3L#XP,PT.<``%/C`P``&@P@H.,9,P/C`R#$YQ8` +M`.K,.P/C`S"0YP$`4^,!```:`0!5XQ```)H:8P/C!C#4YP,PA>$(((WB`3!B +MY1@S`^,#4,3G!`"@X240H.-D.P/C#^"@X0/PE.<&,-3G@#`CX@8PQ.<9,P/C +M`U#$YPC0C>)P@+WH`#"@XQ0PP.4>_R_A$$`MZ9`[`^,#,)#G``!3XP$`H`,0 +M@+T(,_\OX1"`O>@00"WI`$"@X0`PH.,`,<#E^#"0Y0``4^,!```*[`"`XO[_ +M_^L`,*#C^#"$Y?PPA.40@+WH$$`MZ1XPH./T,(#E`#``XP`P0./X,(#E`#`` +MXP`P0./\,(#E[`"`XO[__^L0@+WH$$`MZ>Q`0.(`,=3E``!3XQ"`O0@S#$3B +M#`!`XO[__^L`,*#C`#'$Y1"`O>@00"WI,TR`X@Q`A.($`*#A_O__ZP0`H.'^ +M___K$("]Z'!`+>D`0*#A,VR`X@Q@AN(&`*#A`1"@X_[__^L`4*#CV#,#XP-0 +MA.=$,P/C`U"$YT@S`^,#4(3G;SL"XP,PU.?.+:#C`C#$YX$C`^,",,3G?2Z@ +MX\@S`^,#((3GS#,#XP-0Q.>1,P/C`U#$YY(S`^,#4,3GXS,#XP-0Q.>#,P/C +M`U#$YVX[`N,#,-3GA",#XP(PQ.<%,%/@`3"@$X(C`^,",,3GA3,#XP-0Q.<8 +M,P/C`U#$YPP@H.,9,P/C`R#$YQPS`^,#4,3G<#L"XP,@U.<=,P/C`R#$YW\@ +MX.,:,P/C`R#$YP`@`..D,P/C`"!`XP,@A.>H,P/C`T"$Y\X-A.(4`(#B!1"@ +MX04@H.'^___K!#0#XP-0A.<&`*#A_O__ZW"`O>@00"WI`$"@X6PPD.4!`!/C +M$("]"``0H.,!(*#A_O__ZP0`H.$%$*#C`""@X_[__^L0@+WH$$`MZ0!`H.'^ +M___KB#,#XP,PE.<`,&/@8P!3XQ@``)IL,)3E`0`3XQ4```H""Q/C$P``&A`` +M$^,1```:0``3XP\``!H@`!/C#0``&I(S`^,#,-3G`0!3XPD```K(.`'C`S"4 +MYP(`4^,!`*`3$("]&"`\`>,#`-3G``!0X@$`H!,0@+WH``"@XQ"`O>@P0"WI +M#-!-X@!`H.$"4*#A!Q#-Y0H`4>,Y``"*'#,#XP,PT.)D.P/C#^"@X0/PE.>%,P/C`U#$ +MYQP``.H$`*#A_O__ZP``4.,8```*`2"@XX4S`^,#(,3G"""-X@$0(P@+WH$$`MZ0!` +MH.'^___K``!0XQ"`O0B",P/C`S#4YP``4^,0@+T(@S,#XP,PU.(`0*#A`#"@XP6" +M,P/C`S#0YP``4^,?```*'#,#XP,PT.<``%/C&P``"@`0H.,!(*#A_O__Z_[_ +M_^L`H*#A:&L#XP=PC>(H@*#CT%L#XV20H.,$`*#A"!"@X0<@H.$/X*#A!O"4 +MYP4``%/C"0``&@4PE.<``%/C!@``&@H`H.'^___K9`!0XP(``,H)`*#A +M_O__Z^W__^H`(*#C-#,#XP,@Q.<(T(WB\(>]Z!!`+>D`0*#AXC,#XP,PT.<` +M`%/C#P``"O[__^L`,`#C`#!`XP`PD^7((P/C`B"4YV00H..1`@'@TRT$XV(@ +M0>.2`8'@S@V$XA0`@.(A$X/@_O__ZQ"`O>AL,)#E$``3XQ```!I``!/C#@`` +M&B``$^,,```:@2@`XP`@0.,"(`/@``!2XP<``!HD/`/C`S"0YP``4^,#```* +M+#H#XP,PD.<``%/C#@``"@`P`.,`,$#C`#"3Y<@C`^,"()3G9!"@XY$"`>#3 +M+03C8B!!XY(!@>#.#83B%`"`XB$3@^#^___K$("]Z-@S`^,#,)#G``!3XQ"` +MO1C0,P/C`S"0YP``4^,0@+T8`B"@X]PS`^,#((#G`""@X\PS`^,#(,#G_O__ +MZQ"`O>CX3RWI`$"@X6-M@.((8(;B,UR`X@Q0A>(%`*#A_O__Z]@S`^,#,)3G +M`@!3XS<``!K0,P/C`S"4YP``4^,S```:`("@X]PS`^,#@(3G2#,#XP,@E.,(D*#A`;"@ +MXU0UU.53.*#A`0`3XP@```H*,)3G"`!3X00`H.$&$*#A"""@X0LPH`$),*`1 +M_O__ZP!PH.$!@(CB!`!8X^___QH`,*#CT",#XP(PA.?C(P/C`C#$YS0C`^," +M,,3G````Z@%PH.,%`*#A_O__ZP<`H.'XC[WH$$`MZ0!`H.&0,P/C`S"0Y_\T +MP^/_,,/C`0A3XS,```J1,P/C`S#0YP$`4^,#```:K#P#XP,PD.AP0"WI`$"@X3-<@.(,4(7B!0"@X?[__^L!(*#CT#,#XP,@A.>!,P/C +M`R#4Y\X]H.,#(,3G1#,#XP,0E.,S`P,#(,0'!`"@X?[__^L"(*#CV#,#XP,@ +MA.<`(*#CT#,#XP,@A.<%`*#A_O__ZW"`O>@00"WI`$"@X=`S`^,#,)#G`0!3 +MXQ"`O0CB,P/C`S#0YP``4^,:```*_O__Z]@S`^,#,)3G`P!0X1$```H"`%#C +M"@``&@(@H./<,P/C`R"$YP$PH./D(P/C`C#$Y]0K`^,",(3G!`"@X?[__^L$ +M``#J`""@X]PS`^,#((3G!`"@X?[__^O,,P/C`R#4YP$@@N(#(,3GA#,#XP,P +MU.<``%/C$("]"-@S`^,#,)3G``!3XQ"`O1C,,P/C`S#4YP,`$^,0@+T8;""4 +MY8$X`.,`,$#C`S`"X```4^,0@+T8$``2XQ"`O1A``!+C$("]&"``$N,0@+T8 +M)#P#XP,PE.<``%/C$("]""PZ`^,#,)3G``!3XQ"`O1@"(*#CW#,#XP,@A.<$ +M`*#A_O__ZQ"`O>@P`"WI`#``XP`P0.,`P)/E``!$(```:`#`` +MXP`P0..",8/@"`"3Y0D``.H`,*#C`%``XP!00.,$0*#C`3"#XG,P[^8#(*#A +M#`!3X>W__[H``*#C;#D`XP(`7.$#`*`!,`"]Z![_+^$P`"WI`#``XP`P0.,` +MP)/E``!$(```:`#``XP`P0..",8/@!`"3Y0D``.H`,*#C`%`` +MXP!00.,(0*#C`3"#XG,P[^8#(*#A#`!3X>W__[H``*#C`@!%Q$/_F@P""X+``T.$! +M`%#A@S""$+`0PQ$!`*`3'O\O$0``H.,>_R_A\`,MZ71`D>7$7Z#A%CR@X].` +M@.$(8)3@"7"EX/-@@.$0-9#E`3"#XA`U@.4T,)'E`0!SXP,``!JXP]'A_S\/ +MXP,`7.$$```*-##1Y0$`$^,4-9`%`3"#`A0U@`4``%+C`@``&HP@D>4``%+C +M"P``"EH_H./3@(+A`6"@XP!PH.,&`)C@!Q"IX/,`@N%B/Z#CTV""X08`E.`' +M$*7@\P""X?`#O>@>_R_A,``MZ0K`T.6V(-#A_S\/XP,`4N&V$,`!`5"@X;8P +MT.$!0&/@`@L4XP``H!,6```:`P!1X04``!H!$('B`1J@X2$:H.&V$,#A`0"@ +MXPX``.H,,*#A`2!"X@(@C.`"(&'@`@L2XP$`H`,'```*`$!,&.B +M`3ICL@$P@[(#$('@MA#`X0$`H.,P`+WH'O\OX1!`+>F8-@'C`S#0YP``4^,) +M```*F38!XP,PT.><)@'C`C#`YP$P@^*C,*#A7S!#XIHF`>,",,#G.0``ZNPV +M`>,#,-#G``!3XP#`H!,,(*`1[38!`P,@T`?A-@$#`\#0!P$PH./L%@'C`3#` +MY^`6`>,!,,#G;#"0Y0(+$^,H```:G#8!XP,PT.>#((+@JQH*XZH:2N.1,H'@ +MH1"@X8$0@>`!`%+AJQH*XZH:2N.1,H'@H1"@X0$0@1)D`%'C9!"@(YTV`>,# +M,-#G@S",X*LJ"N.J*DKCDL."X*(@H.&"((+@`@!3X:LJ"N.J*DKCDL.#X*,P +MH.$!,(,2G"8!XP(0P.*:)@'C`A#`YV0`4^-D,*`CG28! +MXP(PP.<`,`#C`#!`XP`PD^7<)@'C`B"0YV00H..1`@'@TRT$XV(@0>.2P8'@ +M6@V`XB@`@.(A$X/@_O__ZQ"`O>AP0"WI`5"@X0Q@@.(,0)#E"0``ZK@BU.&X +M,M7A`A!CX`(+$>,`0)05`P``&@,`4N$``*`#!0``&G"`O>@&`*#A!!"@X?[_ +M_^L``%#C\/__"@P`E>@$,(+E`""#Y0!0A>4$4(7E!0"@X000H.'^___K`0"@ +MXW"`O>AP0"WI`$"@X0%@H.$04)#E_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B +M!""#Y0P`E.@$,(+E`""#Y0!`A.4$0(3E!`"@X080H.'^___K``!5XP8```I7 +M/87B&#"#X@,`5N'P-0$#`R"5!P$@@@(#((4'#2"@X7\]PN,_,,/C!""3Y0$@ +M0N($((/E_O__ZP$`H.-P@+WH\$$MZ0C03>(`0*#A$("0Y0``4.,`<*`#?'"0 +M%2\PT.4``%/C#```"C$@T.4``%#C"0``"H`PD.4#,&+@@#"`Y7P0D.4!`%/A +M`C"#,(`P@#5T,)`E`R!B('0@@"4P4-3E(3#4Y0-0A>`%8(?@!@"@X0`0`.,` +M$$#C!B"@X_[__^L``%#C#0``"@90A>(%4(?@!0"@X801G^4"(*#C_O__ZP`` +M4.,%```:!0"@X7`1G^4"(*#C_O__ZP``4.,%```*!@"@X5P1G^4&(*#C_O__ +MZP``4.-+```*,"#4Y2$PU.4#,(+@`6"@XP8@H.,",(/@M"?4X0(@8^"V(,WA +M;""8Y0$($N,:```*`W"'X'@@X.,`(,?E$B"@XP$@Q^4``%3C`%"@`P40H`$, +M```*)#!#XGQ0E.4#4(7@?%"$Y8`@E.4"`%7A!5!C@'Q0A(4`4*"#=""4E0(P +M8Y!T,(25>!"4Y04`H.$8(*#C_O__ZQA0A>(0``#JAB"@X0``5.,`4*`##``` +M"@XP0^(",(/@?%"4Y0-0A>!\4(3E@""4Y0(`5>$%,&.`?#"$A0!0H(-T()25 +M`C!CD'0PA)4%`*#A-!"$X@8@H./^___K!@"%XCH0A.(&(*#C_O__ZP``5N,& +M```:MC#=X;,_O^8($(WBLC!AX0P`A>("(*#C_O__ZP$`H.,(T(WB\(&]Z"$@ +MU.4P,-3E`S""X`!@H.,&(*#ALO__ZK`'``"T!P``N`<``/A/+>D`0*#A`5"@ +MX0*0H.%\<)'E6VV`XCA@AN+@H(#B-(#1Y6PPD.4(`!/C0```"@$`$^,!```: +M@``3XSP```JP,-?A_"`#XD@`4N->```*B"`#XH@`4N,!```:<``3XUD``!H- +M>X3B$7"'X@<`H.$Z$(7B!B"@X_[__^L``%#C40``&@&`".('`*#A-!"%X@8@ +MH./^___K``!0XP$``!H``%CC2```"DQPA>('`*#A`!``XP`00.,&(*#C_O__ +MZP``4.-````:"@"@X0`0`.,`$$#C!B"@X_[__^L``%#C.0``&@<`H.$*$*#A +M!B"@X_[__^L``%#C,P``"@``6.,#```*!`"@X?[__^L``(GE`P``Z@8`H.%, +M$(7B_O__ZP``B>4``)GE``!0X@$`H!/XC[WH`0@3XR,```H!`!/C(0``"C2` +MA>((`*#A!!"'X@8@H./^___K.K"%X@L`H.$*$(?B!B"@X_[__^M,0(7B!`"@ +MX1`0A^(&(*#C_O__ZT8`A>(($*#A!B"@X_[__^M``(7B"Q"@X08@H./^___K +M!`"@X0H0H.$&(*#C_O__ZP8`H.$$$*#A_O__ZP``B>4``%#B`0"@$_B/O>@` +M`*#C^(^]Z/A/+>D`8*#A`4"@X0)PH.%\H)'EX)"`XC2`T>4!@`CB;#"0Y2`` +M$^,!```:0``3XR<```H-6X;B$5"%X@4`H.$Z$(3B!B"@X_[__^L``%#C90`` +M&@4`H.$T$(3B!B"@X_[__^L``%#C`0``&@``6.-=```*3%"$X@4`H.$`$`#C +M`!!`XP8@H./^___K``!0XU4``!H)`*#A`!``XP`00.,&(*#C_O__ZP``4.-. +M```:!0"@X0D0H.$&(*#C_O__ZP``4.,Z$(02`5"@$SD``!I%``#J"``3XP@` +M``I,`('B.A"!X@8@H./^___K``!0XTP0A!(!4*`3+@``&CH``.H0`!/C#P`` +M"@``6.,$```*3##1Y0$`$^,!4*`3)P``&C$``.I,`('B-!"!X@8@H./^___K +M``!0XSH0A!(!4*`3(@``&B@``.H!"!/C`!"@`P%0H`$7```*-+"$X@L`H.$$ +M$(KB!B"@X_[__^LZ4(3B!0"@X0H0BN(&(*#C_O__ZTP`A.(0$(KB!B"@X_[_ +M_^M&`(3B"Q"@X08@H./^___K0`"$X@40H.$&(*#C_O__ZPD0H.$!4*#C``!8 +MXP,```H&`*#A_O__ZP``A^4#``#J6PV&XC@`@.+^___K``"'Y0`PE^4``%/C +M````&@!0H.,%`*#A^(^]Z'!`+>D`4*#A_O__ZPT@H.%_/<+C/S##XP0@D^4! +M((+B!""#Y04`H.'^___K`0!0XP!`H`,/```*`$"5Y0P`E.@$,(+E`""#Y0!` +MA.4$0(3E$""4Y0``4N,&```*5SV"XA@P@^(#`%7A\#4!`P,0D@G^___K +M$("]Z/A/+>D`4*#A`4"@X7QPD>4'8*#AL##7X0PP`^($`%/CCP``&@0`A^(- +M&X7B$1"!X@8@H./^___K``!0XX@```JP,-?A_#`#XJ0`4^.$```:LH#7X5L- +MA>(X`(#B"A"'XO[__^L`8%#B?0``"@B)H.$HB:#AU#"6Y0@`4^%X```:%CZ@ +MX].@AN$!@*#C`)"@XP@`FN`)$*O@\P"&X24PU.4'`%/C$0``BM4RU.$!(*#C +M$C.@X<``$^,)```:,``3XP0``!H&`!/C"```"J(WUN4",`/@!P``ZJ0WUN4! +M,`/B!```ZJ4WUN4!,`/B`0``ZJ,WUN4!,`/B``!3XU@``!K0,);E!``3XU4` +M``J\.`'CLR"5X=0PEN52,Z#A`0`3XT\```K^___K#2"@X7\]PN,_,,/C!""3 +MY0$@@N($((/E!@"@X<1`L.4$$*#A_O__ZP``4.,F```:#`"4Z`0P@N4`((/E +M`$"$Y01`A.7,,);E`3!#XLPPAN4``%/C`3"@$P`PH`-4,,3E`3"@XU8PQ.4% +M`*#A!!"@X90[`^,/X*#A`_"5YP$`4.,"```:!0"@X000H.'^___KS#"6Y0`` +M4^,@```:OC@!X]0@EN6S$)7A`0"@XQ`BP>&S((7A!0"@X040H.,`(*#C`C"@ +MX?[__^L4``#JOC@!X[,@E>'4,);E4C.@X0$`$^,.```*S#"6Y0``4^,`,*`3 +MS#"&%;XX`>/4();ELQ"5X0$`H.,0(L'ALR"%X04`H.$%$*#C`""@XP(PH.'^ +M___K#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__ZP``H./XC[WH<$`MZ0!0 +MH.$!0*#A6PV`XC@`@.(Z$('B_O__ZP`04.)P@+T(W#"1Y0``4^-P@+T(H#?1 +MY0\`$^-P@+T(T#"1Y00`$^-P@+T()2#4Y0<`4N,1``"*4``%/C`@``"@4` +MH.'^___K<("]Z`4`H.'@$('B_O__ZW"`O>AP0"WI`$"@X7Q0D>5;#8#B.`"` +MXCH0@>+^___KL##5X0`04.)P@+T(`0H3XP4```K0,)'E!``3XW"`O1@$`*#A +M_O__ZW"`O>C0,)'E!``3XW"`O0@$`*#A_O__ZW"`O>CP02WI`%"@X0%`H.$" +M8*#A?'"1Y6PPD.40`!/C*0``"DP`@>+@$(7B!B"@X_[__^L``%#C)0``"EL- +MA>(X`(#B.A"$XO[__^L``(;E``!0XQX```H%`*#A!!"@X?[__^NP,-?A_"`# +MXD@`4N,%```:!0"@X000H.$`();E_O__ZP``H./P@;WHB#`#XH@`4^,,```: +MR`!2XP4``!H%`*#A!!"@X0`@EN7^___K``"@X_"!O>@%`*#A!!"@X?[__^L! +M`*#C\(&]Z`$`H./P@;WH``"@X_"!O>CP3RWI#-!-X@"0H.$!0*#A`#"@XP0P +MC>5\4)'E!;"@X;!@U>$!'!;B`B"@$P,@H`'6-.#G`R""X0$`4N,$H(4"`0`` +M"A"@A2($H(4R``!1XP(@H!,`(*`#`R""X0$`4N,0@(4"!```"@J`A3("```Z +M`@!2XQB`A1(*@(4"``!1XP(0H!,`$*`#`S"!X0,`4^,#\9^7`P``ZH"*`0"( +MB@$`D(H!`)B*`0``<*#C!@``ZA!PA>($``#J"G"%X@(``.H$<(7B````Z@1P +MA>(``%?CM0``"C0`A.(*$*#A!B"@X_[__^LZ`(3B"!"@X08@H./^___K3`"$ +MX@<0H.$&(*#C_O__ZR(PU.4#`%/C`_&?ES0``.KTB@$`*(L!`%R+`0"0BP$` +M1@"$X@H0H.$&(*#C_O__ZT``A.(($*#A!B"@X_[__^L)`*#A!!"@X00@C>+^ +M___K)```ZD8`A.(*$*#A!B"@X_[__^M``(3B!Q"@X08@H./^___K"0"@X000 +MH.$$((WB_O__ZQ<``.I&`(3B!Q"@X08@H./^___K0`"$X@@0H.$&(*#C_O__ +MZPD`H.$$$*#A!""-XO[__^L*``#J1@"$X@00A>(&(*#C_O__ZT``A.(*$(7B +M!B"@X_[__^L``*#C<0``Z@``H.,``%#C;@``"@0PG>4``%/C:@``"HPPA.4` +M,*#C(S#$Y20PU.4!`%/C$```&A@P^^4/,`/B)3#$Y;`@V^'2(^#G(R#$Y2(@ +MU.4#`%+C(""@`QH@H!,A(,3E``!3XP,`4Q,!(*`3^#4!$P,@B1<&``#J`#"@ +MXR4PQ.4B,-3E`P!3XQXPH`,8,*`3(3#$Y2PPU.4``%/C(3#4%00P@Q(A,,05 +M)3#4Y8,Q@^`$()WE@S&"X'D_@^*0,(3E!`"@X=85X.>D((+B_O__ZP``4.,[ +M```*+3#4Y0``4^,R```*R#@!XP,PF><#`%/C`_&?EPX``.J\C`$`O(P!`,R, +M`0"\C`$`S#@!XP,PF>+PC[WH$$`MZ0%`H.$O,-'E``!3 +MXR0```HA,-'E?""1Y0,P@N`#,-/E(S.@X54PP>4O,-'E'```"BX@T>4``%+C +M`P``"B@L`>,"()#G`0!2XQ4``!H`(*#C+#P!XP,@@.D4T$WB +M`%"@X0%`H.%;#8#B.`"`XD`0@>+^___K+S#4Y0(`4^,!`*`37P``&@``4.-1 +M```*1C#4Y0$`$^,!#(`""```"E4@U.4@/`'C`S#5YP``4^,``*`#`@*%$&8- +M@!(L`(`24```"B$PU.4P8-3E='"4Y0=P8^`Q(-3E!W!BX`AP1^('<&;@?!"4 +MY0-@AN`&8('@"#"-X@`PC>4E,-3E!#"-Y08@H.$',*#A_O__ZP=@AN``(*#C +M`C"@X0C`C>(#`-SG`Q#6YP$`4.$!(*`3`3"#X@@`4^/X__\:`0!2XQL``!IT +M()3E``!2XP,```H`,*#C"#"#X@(`4^'\__\Z1A#4Y0$0`>(!`%'C`2"@$P0` +M`!I5(-3E/#N5Y0,`4N$`(*`3`2"@`RXPU.4!`%/C`#"@$P$P`@(``%/C``"@ +M`PX```H%`*#A_O__ZP``H.,*``#J(CP!XP,PU><``%/C!0``&D8PU.4!`!/C +M`0"@$R(\`1,#`,47````&@$`H.,``%3C"```"H`@E.4(,$+B@#"$Y7P0E.4! +M`%/A@""$-70PE"4(,$,B=#"$)130C>+P@+WH<$`MZ0!`H.$`4`_A@``,\0T@ +MH.%_/<+C/S##XP0@D^4!((+B!""#Y?[__^L!`%#C`$"@`P!`E!4$,)05`""4 +M%00P@A4`((,5`$"$%01`A!4%\"'A#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E +M`#"3Y0(`$^,````*_O__ZP0`H.%P@+WH$$`MZ0`PH.$`0`_A@``,\0W`H.%_ +M+,&```*5SV%XA@P@^(#`%;A\#4!`P,@E0E+WTWB`&"@X1`0 +MC>57#8#B&`"`XAP`C>4A(-'E``!1XPL```I\,)'E`C"#X'PP@>40`)WE@!"0 +MY0$`4^$#,&*`?#"`A1`0G95T,)&5`R!BD'0@@940()WE,##2Y0``4^,-```* +M``!2XPL```I\()+E`R""X!``G>5\((#E@!"0Y0$`4N$",&.`?#"`A1`0G95T +M()&5`C!CD'0P@940()WE=("2Y7R@DN4.`%CCP```V@Q0VN4-,-KE!52#X060 +MH.$.L(7B"P!8X;D``+H`<*#C!C"@X0I@H.$#H*#A"0``Z@5@AN`+8(;@#%#6 +MY0TPUN4%5(/A!9"@X0ZPA>(!<(?B"`!;X:H``,H.8(;B#`")XO[__^L`0%#B +M#```"J@PE.4,,(/BJ#"$Y9PPE.4,,(/BG#"$Y00`H.$%$*#A_O__ZP80H.$% +M(*#A_O__ZPL``.H0,)WE"`"3Y2`0H./^___K`$!0X@I@H`%W<.\&'```"JA@ +MA.504(3E!3"&X)PPA.4H`(WB!T&`YS\`5^,*8*`!`7"'`G=P[P81```*#H!( +MX@F`6.`*8*`!`7"'`G=P[P8+```*`[`+X@2P:^($`%OC`+"@`P@`6^%Y``#* +M"(!KX`X`6./!___*"F"@X0%PA^)W<._F``!7XW$```H0$)WE.K"!XC0@@>($ +M((WE`7!'XG>0[^8!D(GB"9&@X0!PH.,HH(WB_CX/X_\_3^,(,(WE`@!*X@P` +MC>4`,`#C`#!`XQ0PC>40$(/B&!"-Y0=0FN>H`)7E!D#0Y0>`T.50,)7E!P!3 +MXR```)H4$)WE!B"@X_[__^L``%#C!0``"@1$B.'S(`CC-S$(XP(`5.$#`%01 +M!0``&J@`E>48$)WE!B"@X_[__^L``%#C#P``"@4`H.$&$*#C_O__ZP4`H.$& +M$*#C_O__ZPL0H.$&(*#C_O__ZP4`H.$&$*#C_O__ZP00G>4&(*#C_O__ZQ8` +M`.I0,)7ELS^_YDH?C>((`)WEL#"!X04`H.$"$*#C_O__ZPP0G>4"(*#C_O__ +MZP4`H.$&$*#C_O__ZPL0H.$&(*#C_O__ZP4`H.$&$*#C_O__ZP00G>4&(*#C +M_O__ZP``5>,9```*_O__ZP@\`^,#,);G:C^#X@!`D^7^___K``!4XP4```IL +M,);E*``3XP(```H&`*#A!1"@X?[__^L(3`/C!0"@X000EN?^___KM@;%X00P +MEN<4,(7E9##5Y1\QP^=D,,7E!0"@X?[__^L$<(?B"0!7X:'__QH`,*#C$""= +MY70P@N40`)WE'!"=Y?[__^L!`*#C2]^-XO"/O>CX3RWI`'"@X0%@H.$,@('B +M#%"1Y0$`4N,%```:"`"@X?[__^L``%#C-@``&K@RU>&V,,;A5[V'XABPB^+, +MJP/CT)L#XRD``.H%0*#AMB#6X;@RU>$",&/@`@L3XRD``!H`4)7E!#"4Y00P +MA>4`4(/E`$"$Y01`A.6V,-;AN"+4X0,`4N$!,(,"`SJ@`2,ZH`&V,,8!(S#4 +MY0``4^,)```:"C"7YP``4^,0```:"3"7YP``4^,-```:!P"@X000H.'^___K +M"0``Z@$`4^,'```:!P"@X000H.'^___K`0!0XP(```H$`*#A"Q"@X?[__^L( +M`*#A_O__ZP``4./1__\*``"@X_B/O>@!`*#C^(^]Z'!`+>D`4*#A`$"0Y(#$('B_O__ZPT@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^MP +M@+WH<$`MZ0!@H.$!0*#AD%"1Y2,PT>4``%/C(```&@$`H.'^___K)##4Y0$` +M4^,,```*S#L#XP,PEN<``%/C7P``&M`[`^,#,);G``!3XUL``!H&`*#A!!"@ +MX?[__^L!`*#C<("]Z`0PU>4``%/C&0``&K@BU.&V(,7A!@"@X000H.'^___K +MMC#5X0$P@^(#.J#A(SJ@X;8PQ>$!`*#C<("]Z`$`4^,+```:!##5Y0``4^,( +M```:N#+1X;8PQ>'^___KMC#5X0$P@^(#.J#A(SJ@X;8PQ>%P@+WH_O__ZPT@ +MH.%_/<+C/S##XP0@D^4!((+B!""#Y04`H.&X$M3A_O__ZP``4.,D```*!0"@ +MX000H.'^___K``!0XQ\```H&`*#A!1"@X0`@H./^___K`0!0XPX``!H`,`#C +M`#!`XP`0D^44`(7B`Q"!XO[__^L-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^ +M___K`0"@XW"`O>@-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K%`"%XO[_ +M_^L!`*#C<("]Z`T@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^L``*#C<("] +MZ```H.-P@+WH<$`MZ0!`H.$!8*#AV#20Y0$`4^,+```:_O__ZP$`4.,;```* +MS#L#XP,PE.<``%/C%P``&M`[`^,#4)3G`%!5X@%0H!,3``#J`0"@X?[__^L` +M4*#A`0!0XPX``!K,.P/C`S"4YP``4^,'```:T#L#XP,PE.<``%/C`P``&@0` +MH.$&$*#A_O__ZP(``.H`4*#C````Z@%0H.,%`*#A<("]Z'!`+>D(T$WB`%"@ +MX0`PH..V,,WA6PV`XC@`@.(`0%'B`&"@`WQ@E!5`$(3B_O__Z\@X`>,#,)7G +M`@!3XQD``!H``%#C%P``"N@PD.4``%/C%```"B$0U.4P,-3E`Q"!X`80@>(& +M`(WB`1"&X`(@H./^___KMC#=X;,_O^9S,/_FCB@(XP(`4^$&```*MC#-X00` +MH.%7'87B&!"!XO[__^L``*#C````Z@0`H.$(T(WB<("]Z/!!+>D`4*#A`6"@ +MX0AP@.('`*#A_O__ZP!`E>4#``#J!`"@X0!`E.4&$*#A_O__ZP4`H.$$$*#A +M_O__ZP``4./V__\*!P"@X?[__^OP@;WH\$4!<*#C0P``Z@90H.$J,-;E!P!3 +MX0<```H$`*#A"1"@X?[__^L*`*#A"1"@X?[__^L`0*#C/P``Z@%P@^)W<._F +M(3#6Y3`@UN4``%;C"P``"@,@@N!R(._F?#"6Y0(P@^!\,(;E@!"6Y0$`4^$# +M,&*`?#"&A70PEI4#(&*0=""&E3$@U.4``%3C%P``"H`PE.4#,&+@@#"$Y7P0 +ME.4!`%/A`C"#,(`PA#5T,)0E`R!B('0@A"6``)3E?!"5Y70@E>7^___K=""5 +MY8`PE.4",(/@@#"$Y800E.4!`%/A`S!B@(`PA(4(``"*!```ZH``E.5\$)7E +M=""5Y?[__^L"``#J=#"4Y0(@@^!T((3E,3#5Y3$PQ.4`8);E"`"@X080H.'^ +M___K``!0X[;__PH*`*#A"1"@X?[__^L$`*#A\(>]Z/!'+>D`8*#A`4"@X5>- +M@.(8@(CB*W#1Y2J@T>5;#8#B.`"`XD`0@>+^___K``!0XYR0@!((```:?#"4 +MY0`PT^4,,`/B"`!3XP"0H`,"```*!@"@X?[__^N,'```*!`"@X0D0H.'^___K!@"@ +MX0D0H.'^___K`%"@X00``.H$`*#A"!"@X?[__^L`4*#C#0``Z@``5>,+```* +M+3#5Y0``4^,(```*!@"@X040H.'^___K``!0XP,``!H%`*#A"!"@X?[__^L` +M4*#C!0"@X?"'O>CX3RWI`$"@X0%0H.%\$)'E6PV`XC@`@.(*$('B_O__ZP`` +M4.,&```*5C^@X].@@.$!@*#C`)"@XPA@FN`)<*O@\V"`X00`H.$%$*#A_O__ +MZP`04.(!```*!`"@X?[__^L!`*#C^(^]Z/!/+>D,T$WB`%"@X0%`H.%\,)'E +M`"#3Y0,@`N+(&9#E`P!1XP<``!K0&9#E@1"!X`$1@.!^'H'B"!"!X@0`D>4! +M`(#B!`"!Y0``4N-6```:`R"@X;`0T^%Q<._F#&`'X@$,$>/1%.#G`@"@$P`` +MH`,`$('A(A#$Y180\^4/$`'B*A#$Y;`PT^$C,J#AN#+$X;`PTN%3-N#G)C#$ +MY;`PTN%3->#G*S#$Y;`PTN'3-N#G)S#$Y;`PTN%3-^#G+3#$Y;`PTN&C-Z#A +M+##$Y04`H.$&$*#C!R"-XFP[`^,/X*#A`_"5YP4!`%/C"```"@(`4^," +M```:``!6XPH```H#``#J`P!3XP$``!H(`%;C#P``"@0`5N,(```*"`!6XPL` +M``H``%;C'P``&@4`H.$$$*#A_O__ZP``H.,;``#J!0"@X000H.'^___K``"@ +MXQ8``.KD-@/C`S"5YP``4^,"```*!0"@X040H.,S_R_AIW.@X21PQ.4%`*#A +M!!"@X?[__^L``%#C"```&A`V`>/3H(7A`8"@XP"0H.,(8)K@"7"KX/-@A>$` +M``#J``"@XPS0C>+PC[WH\$/3H(3A`8"@XP"0H.,(8)K@"7"KX/-@A.'0C[WH$$`MZ0!`H.'^___K +M`#"@XW0PA.40@+WH$$`MZ0!`H.'^___K"`"$XO[__^L0`(3B_O__Z[P`A.+^ +M___K$("]Z'!`+>D`0*#A'%"0Y?[__^L$`*#A_O__ZQ``E.4``%#C`0``"I4< +MH./^___K!0"@X2@[`^,/X*#A`_"5YW"`O>CP02WI`("@X0%@H.'^___K"`"@ +MX?[__^L(`(CB_O__ZQQ@B.4!/*#C&#"(Y0@`H.$&$*#A_O__ZY4,H./^___K +M$`"(Y0``4.,`4*`#*P``"O\`@.+_0,#C%$"(Y0APH.$E6X3B!`"@X?[__^L$ +M`*#A!Q"@X?[__^L&`*#A!!"@X?[__^L08(3EE$"$X@4`5.'S__\:`3"@XV@P +MR.58`(CB`!"@X_[__^L&`*#A)#L#XP_@H.$#\);G`%"@X=!`B.(`,`#C`#!` +MX^`PB.7D8(CE!`"@X0`0H.,!(*#A_O__Z_H_H.,$,8CE`#``XP`P0.,`$)/E +M!`"@X600@>+^___K!0"@X?"!O>@00"WI`$"@X0`0H.,L(*#C_O__ZP0`H.'^ +M___K!`"$XO[__^L0@+WH`0"@XQ[_+^'P02WI"-!-X@!`H.$!4*#A`"``XP`@ +M0.,-,*#A`P"2Z`0`@^2P$,/A``!5XP!@H`,P```*`##5Y0$`$^,-4*`1` +MY0$PU>4&82/@`C#5Y09A(^`#,-7E!F$CX`0PU>4&82/@!3#5Y09A(^`F9";@ +M'V`&XO[__^L-(*#A?SW"XS\PP^,$()/E`2""X@0@@^4"8(;BAG&$X(9!E.<& +M@*#C!P``Z@A@1.+8`(3B!1"@X0@@H.'^___K`0!0XP8```H`0)3E!P"@X000 +MH.'^___K``!0X_+__PH`8*#C#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__ +MZP8`H.$(T(WB\(&]Z`3@+>4,T$WB`""@X0TPH.$@$)_E`P"1Z`0`@^2P$,/A +M6PV"XC@`@.(-$*#A_O__ZPS0C>(`@+WHZ!(``/!/+>D,T$WB!`"-Y0!P4>+$ +M```*4TV`XB!`A.+^___K#0"@X7^MP.,_H,KC!#":Y0$P@^($,(KE!`"@X<00 +MA^+^___K`("@X\R`A^4$`*#A7!"'XO[__^M4,(?B6""7Y500E^4$(('E`!"" +MY50PA^58,(?E!`"@X4@0A^+^___K0#"'XD0@E^5`$)?E!""!Y0`0@N5`,(?E +M1#"'Y00`H.$T$(?B_O__ZRPPA^(P()?E+!"7Y00@@>4`$(+E+#"'Y3`PA^4$ +M`*#A(!"'XO[__^L8,(?B'""7Y1@0E^4$(('E`!""Y1@PA^4<,(?E!#":Y0$P +M0^($,(KE_O__ZP@PA^(,()?E"!"7Y00@@>4`$(+E"#"'Y0PPA^4(.`'C!!"= +MY0,@D>57;8+B +M&&"&X@J0H.$'L*#AB%&(X(51H.$%`(?@?@^`XO[__^O^___K!#":Y0$P@^($ +M,(KE!5"'X!]>A>+P09OE"```Z@0`H.$`0)3E!#"0Y00PA.4`0(/E``"`Y00` +M@.4&$*#A_O__ZP4`H.'^___K``!0X_+__PH$,)GE`3!#X@0PB>7^___K`8"( +MXDBPB^(0`%CCW?__&G@[`^,$`)WE`\"0YP``7.,#```*`!"@XP<@H.$!,*#A +M//\OX?[__^L-$*#A?SW!XS\PP^,$()/E`2""X@0@@^4;+8?BQ!:7Y<`&E^4$ +M$(#E``"!Y<`FA^7$)H?E!""3Y0$@0N($((/E_O__ZP`PH./(-H?EJ#>'Y:`W +MQ^6A-\?EHC?'Y:,WQ^6D-\?EI3?'Y:8WQ^6\.`'C`2"@X]0`E^4$P)WELQ"< +MX1(0P>&S$(SAOC@!X]0`E^6S$)SA$B#!X;,@C.'4,)?E``!3XPP```H!,$/B +M!BR#X@X@@N("(8S@!""2Y0<`4N$%```:!CR#X@,1C.`\$('B`#"@XP`P@>74 +M,(+E`#"@XP0XQ^7^___K#0"@X7]-P.,_0,3C!#"4Y0$P@^($,(3E!P"@X00@ +MG>47'(+B_O__ZP0PE.4!,$/B!#"$Y?[__^L!`*#C#-"-XO"/O>CP1RWI`'"@ +MX?[__^L`8*#A"#@!XP,PE^]"/[__^L-(*#A?SW"XS\PP^,$()/E +M`2""X@0@@^47K(?B"*"*X@"`H.,N7HCB`5"%XH51A^``0)KE!0``Z@@01.(` +M0)3E`0!6X0$```H'`*#A_O__ZP4`H.$$$*#A_O__ZP``4./T__\*`8"(X@B@ +MBN(@`%CCZ___&@T@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^OPA[WH$$`M +MZ0!`H.'^___K&`"$XO[__^LL`(3B_O__ZT``A.+^___K5`"$XO[__^L0@+WH +M$$`MZ0!`H.$``%3C````"O[__^L0`(3B_O__ZY@`A.+^___KI`"$XO[__^L0 +M@+WH<$`MZ0!`H.'^___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/E"%"$X@A` +ME.4"``#J!`"@X0!`E.7^___K!0"@X000H.'^___K``!0X_?__PH-(*#A?SW" +MXS\PP^,$()/E`2!"X@0@@^7^___K<("]Z'!`+>D`0*#A_O__ZQ!0A.(%`*#A +M_O__ZP4`H.'^___K20^$XO[__^M'#X3B_O__ZTY/A.($`*#A_O__ZP0`H.'^ +M___K<("]Z!!`+>D`0%#B!P``"@0`H.'^___K``"4Y0``4.,"```*!!@`XP$0 +M0./^___K`0"@XQ"`O>AP0"WI`$"@X0`0H.,A+:#C_O__ZP0`H.'^___K!`"@ +MX?[__^L(`(3B_O__Z\0`A.+^___K`%"@X\Q0A.40`(3B_O__ZY@`A.+^___K +M:PZ$X@@`@.+^___K&PV$XO[__^O(5H3E6%>$Y50G`..R4(3A=%?$Y957Q.66 +M5\3EEU?$Y9A7Q.695\3EFE?$Y018Q.5P@+WH\$\MZ0S03>(`<*#A`4"@X0`@ +MX..V(,WA_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B!""#Y0@`A^+^___K`0!0 +MXP@``!H-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K`&"@XUD``.H(8)?E +M#`"6Z`0P@N4`((/E`&"&Y01@AN4-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^ +M___K!@"@X?[__^O@`(;B!!"@X08@H./^___K`%#4Y0$PU.4%42/@`C#4Y051 +M(^`#,-3E!5$CX`0PU.4%42/@!3#4Y051(^`E5"7@'U`%XO[__^L-,*#A?TW# +MXS]`Q.,$,)3E`3"#X@0PA.4"$(7B"`"&XH$1A^#^___K$#&7Y0$P@^(0,8?E +M!#"4Y0$P0^($,(3E_O__ZZ10AN(`0*#C!H"-X@*@H.,$`(7@"!"@X0H@H.'^ +M___K`D"$XB``5./X__\:)`&7Y080H.'^___K>T^&X@!0H.,%D*#A`*#@XT"P +MH.,D,9?E"#`$Y0201.6RH$3AL*#$X0*PQ.6%@87@B(&@X0@`AN`?#H#B_O__ +MZP@`AN!Y#X#B_O__ZP%0A>)(0(3B$`!5X^W__QH`,.#C$#B&Y10XAN4&`*#A +M#-"-XO"/O>@$X"WE#-!-X@`@H.$-,*#A,!"?Y0,`D>@$`(/DL!##X5L-@N(X +M`(#B#1"@X?[__^L``%#C`3"@$]@P@!4!`*#C#-"-X@"`O>CP$@``\$$MZ0!@ +MH.$$"`#C`0!`X_[__^L``(;E``!0X_"!O0@#`,#C!`"`X@0`AN4(<(;B!P"@ +MX?[__^L0`(;B_O__ZP!`H.,008;E10^&XO[__^M'#X;B_O__ZP10EN4%`*#A +M_O__ZP(`A.*``8;@_O__ZP4`H.$'$*#A_O__ZR%=A>(!0(3B(`!4X_/__QH` +M,*#C<2^@X[(PAN'&(0#CLC"&X4H/AN+^___K$PZ&XO[__^M.3X;B!`"@X?[_ +M_^L$`*#A_O__ZP,PH.,X,8;E/#&&Y3PPH.-`,8;EA4,)'E*"#1Y0<`4N,+``"*V"+1X0$0H.,1(J#AP``2XU0P@Q(&```: +M,``2XT`P@Q(#```:!@`2XRPP@Q(````:&#"#XA``D^4>_R_A%B#0Y;HPT.$# +M((+@##"0Y0@P@^(",(/@%2#0Y0(`4N,(,(,"%P#0Y0``@^`>_R_A\`,MZ60P +MD>4/,`/B`0!3XQD``!H"0*#AQ%^@X54]H./3@(#A"&"4X`EPI>#S8(#A=##1 +MY0PED.4#,(+@##6`Y5PPD>4``%/C"P``"F8OH.-T@-'E`)"@X])@@^$&`)C@ +M!Q"IX/(`@^$:+J#CTF"#X08`E.`'$*7@\@"#X?`#O>@>_R_A!P!2XQ```(H! +M`*#C$"*@X<``$N-4`($2`""@$P`@PQ4>_R\1,``2XT``@1(!(*`3`"##%1[_ +M+Q$&`!+C+`"!$@,@H!,`(,,5'O\O$1@`@>("(*#C`"##Y1[_+^$``%'C'O\O +MT0`PH.,#P*#A@R&`X`3`@N4!,(/B`0!3X?K__QH>_R_A^$\MZ0"`H.$!4*#A +M_O__ZPT0H.%_/<'C/S##XP0@D^4!((+B!""#Y<2@A>+$8)7E`7"@XY2[`^,` +MD*#C0P``Z@9`H.$`8);E,##4Y0<`4^,0``"*T#/4X16H-Y7E`3!#XJ@WA>4``%/C5'#$%5B0Q!54D,0%6'#$!59PQ.4( +M`*#A!!"@X0_@H.$+\)CG`0!0XP(``!H(`*#A!!"@X?[__^NH-Y7E``!3XPP` +M`!JF-]7E``!3XPD``!K4()7EOA@!X[$PF.$7,L/AL3"(X0@`H.$%$*#C"2"@ +MX0DPH.'^___K"@"@X080H.'^___K``!0X[;__PH-(*#A?SW"XS\PP^,$()/E +M`2!"X@0@@^7^___K^(^]Z/!/+>D4T$WB`&"@X0%0H.'^___K#1"@X7^MP>,_ +MH,KC!#":Y0$P@^($,(KEQ""%X@0@C>7$<)7E"I"@X0`PH.,(,(WE`8"@X[ZX +M`>,,@(WE5```Z@=`H.$`<)?E!#"4Y00PA^4`<(/E`$"$Y01`A.4P,-3E!P!3 +MXQ```(K0,]3A&#.@X<``$^,)```:,``3XP0``!H&`!/C"```"J(GU>4"(`+B +M!P``ZJ0GU>4"(`+B!```ZJ4GU>4"(`+B`0``ZJ,GU>4"(`+BS#"5Y0$P0^+, +M,(7E``!3XU2`Q!4`$*`#5!#$!0``4N,)```*J#>5Y0$P0^*H-X7E``!3XU2` +MQ!4`(*`36"#$%0`PH`-4,,0%6(#$!5:`Q.4$,)KE`3!#X@0PBN7^___K!@"@ +MX000H.&4*P/C#^"@X0+PEN7,,)7E``!3XPX``!K4()7ENS"6X1@RP^&[,(;AT#"5Y00`$^,$ +M,",2T#"%%=0@E>6\&`'CL3"6X1@RP^&Q,(;A#""=Y0@@C>4$`)WE!Q"@X?[_ +M_^L``%#CI?__"@T0H.%_/<'C/S##XP0@D^4!($+B!""#Y?[__^L&`*#A_O__ +MZP!04.)6```*O#@!X[,@EN'^/P_C`#!`XP,P`N```%/C1P``&O[__^L-(*#A +M?XW"XS^`R.,$,)CE`3"#X@0PB.7$,(7B!#"-Y<1PE>4(H*#A`9"@X[ZX`>,M +M``#J!T"@X0!PE^4$,)3E!#"'Y0!P@^4`0(3E!$"$Y4!,$/BS#"%Y0`` +M4^-4D,05`!"@`U00Q`56D,3E!#"8Y0$P0^($,(CE_O__ZP8`H.$$$*#AE"L# +MXP_@H.$"\);G`0!0XP(``!H&`*#A!!"@X?[__^O^___K!#":Y0$P@^($,(KE +MS#"5Y0``4^,)```:NS"6X0$PP^.[,(;AO!@!X[$PEN$!,,/CL3"&X0@@G>4" +M((+C"""-Y00`G>4'$*#A_O__ZP``4./,__\*#1"@X7\]P>,_,,/C!""3Y0$@ +M0N($((/E_O__ZP@@G>4``%+C!```"@8`H.$%$*#C`""@XP(PH.'^___K%-"- +MXO"/O>CP02WI`%"@X0%`H.%&<-'E;#"0Y1``$^.=```*7&"1Y0``5N,%```: +M6PV`XC@`@.)&$('B_O__ZP!@4.*4```*`7`'XE8PU.4!`%/C!0``&@``5^,1 +M,*`35S#$%0!`H!.,```:B@``Z@``5^,L```*_O__ZPT@H.%_/<+C/S##XP0@ +MD^4!((+B!""#Y;PX`>.S,)7A``!3XP!`H`,8```*#`"4Z`0P@N4`((/E`$"$ +MY01`A.4$`*#AQ!"&XO[__^O,,);E`3"#XLPPAN6^.`'CLR"5X0$@@N.S((7A +MO#@!X[,@E>$!((+CLR"%X04`H.$%$*#C`""@XP(PH.'^___K`4"@XPT@H.%_ +M/<+C/S##XP0@D^4!($+B!""#Y?[__^M<``#J_O__ZPT@H.%_/<+C/S##XP0@ +MD^4!((+B!""#Y=`PEN4$`!/C1@``"KPX`>.S()7AU#"6Y5(SH.$!`!/C0``` +M"@P`E.@$,(+E`""#Y0!`A.4$0(3E!`"@X<00AN+^___KS#"6Y0$P@^+,,(;E +M,##4Y0<`4^,1``"*T#/4X0$@H.,2,Z#AP``3XPD``!HP`!/C!```&@8`$^,( +M```*HC?6Y0(P`^`'``#JI#?6Y0$P`^($``#JI3?6Y0$P`^(!``#JHS?6Y0$P +M`^(``%/C"0``"J@GEN4!((+BJ">&Y:8GUN4``%+C`#"@$P$P`P(``%/C`P`` +M&A0``.JF-];E``!3XQ$```J^.`'CU""6Y;,0E>$!`*#C$"*!X;,@A>',,);E +M``!3X0@``!H%`*#A!1"@XP`@H.,",*#A_O__ZP%`H.,"``#J`$"@XP```.H! +M0*#C#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__ZP```.H`0*#C!`"@X?"! +MO>CP1RWI"-!-X@!@H.$!@*#A:#4!XP.@D.<"<*#A`$"2Y0>0C>(1``#J!%"@ +MX0!`E.4&`*#A!1"@X?[__^L&`*#A"!"@X3`@U>4),*#A_O__ZQ`PD.4!,$/B +M$#"`Y06#,8K@!""3Y0$@0N($((/E!P"@X000H.'^___K``!0X^C__PH( +MT(WB\(>]Z/!!+>D`4*#A`4"@X?[__^L`8*#A_O__ZPTPH.%_?/4()3ELQ"5X0$`H.,0(H'ALR"% +MX04`H.$$$*#A7""$XL/__^M4,(3B6""4Y500E.4$(('E`!""Y50PA.58,(3E +M!0"@X000H.%(((3BN/__ZT`PA.)$()3E0!"4Y00@@>4`$(+E0#"$Y40PA.4% +M`*#A!!"@X2`@A.*M___K&#"$XAP@E.48$)3E!""!Y0`0@N48,(3E'#"$Y04` +MH.$$$*#A-""$XJ+__^LL,(3B,""4Y2P0E.4$(('E`!""Y2PPA.4P,(3E!0"@ +MX080H.$@((;BE___ZQ@PAN(<();E&!"6Y00@@>4`$(+E&#"&Y1PPAN4$,)?E +M`3!#X@0PA^7^___K\(&]Z#!`+>DLT$WB`%"@X0%`H.$``)#E!1"@X?[__^L% +M`*#A&!"-X@X@H./^___KM##4X0(+4^,&```:!0"@X000C>(4(*#C_O__ZP4P +MW>6C,J#A`P``ZHXH".,"`%/A!S"@`P`PH!,H,,3E&C"@X[HPQ.%W,.#C`3#$ +MY2S0C>(P@+WH53#@XP`PP.4!,,#E`S"@XP(PP.7S,`CC-\$(XP,`4>$,`%$1 +M`#``$P`P0!,`,``#`#!``P#`T^4#P,#E`<#3Y03`P.4",-/E!3#`Y;$?O^:V +M$,#A"`"@XQ[_+^'P3RWI%-!-X@!@H.$!H*#A`$"1Y?[__^L(/`/C`S"6YVH_ +M@^(`<)/E_O__Z_[__^L-(*#A?SW"XS\PP^,$()/E`2""X@0@@^6H4)3E`##5 +MY0$P(^(``%?C`'"@`P%P`Q(``%?C*@``"@9PA>('`*#A/1R&X@P0@>(&(*#C +M_O__ZP``4.,B```*O##5X8$`4^,D```*"`!3XT$``!KS#8;B/@"`X@<0H.$& +M(*#C_O__ZP``4.,Z```:"#T#XP,PEN<``%/C-@``"@<`H.$-&X;B$1"!X@8@ +MH./^___K`#``XP`P0.,`()/E"#T#XP,PEN<4((/E#2"@X7\]PN,_,,/C!""3 +MY0$@0N($((/E_O__Z]8``.J\,-7A@0!3XP"`H!,(<*`1#0``&KZ`U>$.,*#C +M`P#@XZ@@E.4#$(+@L!"1X;,0@N$",$/B`@!3X_C__QH$`*#A!!"@X_[__^L! +M<*#CJ%"4Y08`A>(]'(;B#!"!X@8@H./^___K``!0XPH``!J\,-7A"`!3XT(` +M`!H]#(;B$@"`XAH0A>($(*#C_O__ZP$``.H`@*#C"'"@X:B0E.6\,-GA"`!3 +MXS8``!KSO8;B/K"+X@90B>(+`*#A!1"@X08@H./^___K``!0XQH```H&`*#A +M!1"@X1H@B>+^___K"#T#XP,`AN<``%#C)0``"J@0E.4+`*#A!A"!X@8@H./^ +M___KJ!"4Y3T,AN($`(#B&A"!X@0@H./^___K`#``XP`P0.,`()/E"#T#XP,P +MEN<4((/E`%"@XQ,``.H(/0/C`R"6YP``4N,%```*`#``XP`P0.,`,)/E%#"" +MY0!0H.,)``#J"P"@X080H./^___K/0R&X@0`@.($$*#C_O__ZP%0H.,```#J +M`5"@XPT@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^L``%7C3P``"@8`H.$$ +M$*#A`2"@X_[__^L``%#C,```&@``5^,0```*!`"@X000H./^___K`#"@XP0` +MH..H()3E`Q""X+`0D>&S$(+A`C"#X@P`4^/X__\:J#"4Y8$@H..\(,/AJ#"4 +MY;Z`P^$$`*#A(!"@X_[__^L`4%#B`P``&J@!G^7^___K``#@XV```.H$`*#A +M_O__ZP!0BN4``%?C!4"@`0X```JH,)7EOH#3X0XPH.,#`.#CJ""5Y0,0@N"P +M$)'ALQ""X0(P0^("`%/C^/__&@4`H.$$$*#C_O__ZP5`H.%4,)3E``!3XPD` +M``H\`9_E/!&?Y?[__^M4$)3E``!1XP,```H$`*#A_O__ZP``4.-````*!@"@ +MX000H.$"(*#C_O__ZP``4.,%``"J`@!PXS4``!K\`)_E_O__ZP``X.,R``#J +MJ`"4Y08`@.(-&X;B$1"!X@8@H./^___K!@"@X000H.'^___K``!7XQ````H$ +M`*#A!!"@X_[__^L`,*#C!`"@XZ@@E.4#$(+@L!"1X;,0@N$",(/B#`!3X_C_ +M_QJH,)3E@2"@X[P@P^&H,)3EOH##X:A0E.4&0(7B!`"@X0T;AN(1$('B!B"@ +MX_[__^L``%#C#```"@`0U.4'(-7E"##5Y0D`U>4``(WE"@#5Y00`C>4+`-7E +M"`"-Y3@`G^7^___K``#@XP```.H``*#C%-"-XO"/O>@```#C``!`X_[__^L` +M`.#C^/__ZJ@!``#$`0``^!(``.`!`````@``$$`MZ6@U`>,#,)#G``!3XQ"` +MO0AL)0'C`A#0YP,`H.&!$:#A_O__ZQ"`O>AP0"WI`$"@X6Q5`>,$,*#C!3#` +MYR``H./^___K:#4!XP,`A.<%,-3G!0!3XPL``!H5/(3B&""#X@`@@.40((/B +M"""`Y0@@@^(0((#E&#"`Y5--A.(X0(3B($"`Y7"`O>@$`%/C<("]&!4\A.(0 +M((/B`""`Y0@@@^((((#E4TV$XCA`A.(00(#E&#"`Y7"`O>CP0"WI#-!-X@!` +MH.$!4*#A:#4!XP-@D.=<$)'E``!1XPD``!I;#8#B.`"`XD80A>+^___K`!!0 +MX@,``!IT`)_E_O__ZP``H.,8``#J!`"@X3`@U>4',(WB_O__ZP!`H.$`<*#A +M_O__ZP``4.,#```*!S#=Y00`H.&#$9;G_O__ZP4`H.$($(3B_O__ZQ`PE.4! +M,(/B$#"$Y06#88;@!#"6Y0$P@^($,(;E`0"@XPS0C>+P@+WH7`(``!!` +M+>G^___K``!0X@$`H!,0@+WH\$\MZ2S03>(`$(WE`D"@X5@@D.4`,*#C&#"- +MY0$PH.,<,(WE`C"@XR`PC>4#,*#C)#"-Y0(_`N,#,-+G`0!3XRD``!K`,)#E +M"#"-Y;PPD.4,,(WEM#"0Y1`PC>6X,)#E%#"-Y0#@H.,!P*#C##"@X1\@X.,/ +M4.#C````Z@'`H.$H`(WB`Q&`X`(`D>4!,(/B`P!3 +MXPP0H-'H___:`1",X@,`4>,,X*#1`3"@T>/__]K^___K#0"@X7\]P.,_,,/C +M!""3Y0$@@N($((/E``!4XS(``-H$0:#A!$"-Y0"@H.,8L(WB"I";YP`@G>6) +MD8+@`("9Y0!`F.4?``#J!&"@X0APA.((4)3E!P"@X040H.'^___K``!0XQ8` +M`!H,`)7H!#""Y0`@@^4`4(7E!%"%Y1`PE.4!,$/B$#"$Y0``5>,,```*!#"9 +MY0$P0^($,(GE!P"@X?[__^L``%#C$```"@P`E.@$,(+E`""#Y0!`AN4$0(;E +M"@``Z@!`E.4(`*#A!!"@X?[__^L``%#CVO__"@2@BN($,)WE`P!:X=#__QH` +M4*#C#6"@X7\]QN,_,,/C!""3Y0$@0N($((/E_O__ZP4`H.$LT(WB\(^]Z!!` +M+>D`0*#A4PV`XC@`@.+^___K``!0XPX```H5#(3B_O__ZP``4.,*```*%0R$ +MX@@`@.+^___K``!0XP4```H5#(3B$`"`XO[__^L!`'#B``"@,Q"`O>@!`*#C +M$("]Z/!!+>D`4*#A6'"0Y0!`4>(A```*_O__ZPT@H.%_/<+C/S##XP0@D^4! +M((+B!""#Y00`H.$,`)3H!#""Y0`@@^4`0(3E!$"$Y6!@E.4``%;C`#"@$V`P +MA!5,$(7B_O__ZT@PE>4!,(/B2#"%Y0T@H.%_/<+C/S##XP0@D^4!($+B!""# +MY?[__^L``%;C`@``"@<`H.$&$*#A_O__ZP$`H./P@;WH<$`MZ0!@H.$!4*#A +M_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B!""#Y0!`E>4#``#J!!"@X0!`E.4& +M`*#A_O__ZP4`H.$$$*#A_O__ZP``4./V__\*#2"@X7\]PN,_,,/C!""3Y0$@ +M0N($((/E_O__ZW"`O>@00"WI``!1XP````K^___K`0"@XQ"`O>CP02WI`("@ +MX0%PH.$"4*#A`4"@X3XPTN548)+E``!6XPD``!H!`!/C`@``"O[__^L`8*#A +M!```ZEL-@.(X`(#B/A""XO[__^L`8*#A!P"@X0`0H.-`(*#C_O__ZP`PU.4! +M(-3E`B2#X0,_#^,`,$#C`S`"X`,@`N(`(,3E(R2@X0$@Q.4!(-7E`C"#X0`P +MQ.4C)*#A`2#$Y0$@U>4(`!+CK```"FP@F.4(`!+C$P``"@$\@^,`,,3E(S2@ +MX0$PQ.4$`(3BX!"(X@8@H./^___K"@"$XC(0A>(&(*#C_O__ZQ``A.(L$(7B +M!B"@X_[__^O,-)CE``!3XRH``!HK``#J$``2XQ,```H"/(/C`##$Y2,TH.$! +M,,3E!`"$XBP0A>(&(*#C_O__ZPH`A.+@$(CB!B"@X_[__^L0`(3B,A"%X@8@ +MH./^___KW#"6Y0``4^,4```:%0``ZB``$N,"```:0``2XP``H`/P@;T(!`"$ +MXBP0A>(&(*#C_O__ZPH`A.(R$(7B!B"@X_[__^L0`(3BX!"(X@8@H./^___K +MW#"6Y0``4^,!```*`3"@XP```.H`,*#C3"#5Y0``4N,'```*`"#4Y0$0U.4! +M)(+A`BJ"XW(@_^8`(,3E(B2@X0$@Q.45(-7E``!2XP<```H`(-3E`1#4Y0$D +M@N$!*8+C*!(H+AL"##X0``5N,[```**##5Y3PP@^*#,(;@L"#3X0$@@N*P +M(,/A*"#5Y3P@@N*"((;@L##2X0,ZH.$C.J#AL##"X2@PU>6#,(;@N#?3X;8P +MQ>&V(??A#R`"X@,R@N&P,,?A1C#5Y0``4^,)```*B#:6Y0``4^,&```*FR;6 +MY2@PU>52,Z#A`0`3XP$PH!-+,,45`@``&DLPU>4!`%/C%@``&B@0U>4/$`'B +M,SZ!XH,PAN"T(-/AMC#5X0,`8N`""Q#C`#"@$TLPQ14!`*`3\(&]&`,`4N$S +M'H'B@6"&X`$P@@(!,(,2`SJ@X2,ZH.&T,,;A`0"@XTL`Q>7P@;WH`0"@X_"! +MO>CP02WI`%"@X5APD.7^___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/E3`"% +MXO[__^L!`%#C`$"@`RX```I,0)7E#`"4Z`0P@N4`((/E`$"$Y01`A.4``%3C +M)@``"D@PE>4!,$/B2#"%Y0!@H.-L8(3E<&"$Y0@`A.(&$*#A6""@X_[__^L! +M,*#C9#"$Y6!@A.5U,,3E=##$Y4@PE>4!`%/C%```&@@\`^,#,)?GL"&3Y0(P +MH.$($+/E`0`1XPT``!H&`%+A!0``&DP`G^5*%P#C_O__ZT0`G^7^___K!0`` +MZ@`@#^&```SQ`!"3Y0$0@>,`$(/E`O`AX0T@H.%_/<+C/S##XP0@D^4!($+B +M!""#Y?[__^L$`*#A\(&]Z(`"``"<`@``\$\MZ4303>(`8*#A`8"@X5-]@.(@ +M<(?B!P"@X?[__^L`0%#B``#@`W0!``K^___K"#P#XP,PEN=J/X/B`%"3Y?[_ +M_^L``%7C#```"FPPEN4H`!/C"0``"@8`H.$($*#A_O__ZP$`<.,$```:!P"@ +MX000H.'^___K``#@XU\!`.H`L)CE&%"-X@L`H.$%$*#A_O__ZS"0C>(%`*#A +M"1"@X0X@H./^___KO#/=X;,_O^:\,,3A-%"$X@4`H.$)$*#A!B"@X_[__^LZ +MH(3B"@"@X080B>(&(*#C_O__ZP`PH.-5,,3E;#"6Y2``$^,!```:0``3XP@` +M``I&`(3B!1"@X08@H./^___K0`"$X@H0H.$&(*#C_O__ZQ0``.H(`!/C"``` +M"D8`A.+@$(;B!B"@X_[__^M``(3B"A"@X08@H./^___K"0``ZA``$^,'```* +M1@"$X@40H.$&(*#C_O__ZT``A.+@$(;B!B"@X_[__^L<,)WE%#"$Y;PPU.$" +M"U/C&@``&A@`C>(-$*#A&""@X_[__^L`,*#C"S#$Y1HQ`.,<()WE`P!2X1`` +M`)J\,-3A`@M3XPT``!H5,-WE1`!3XP,``!H7,-WE0P!3XPT``!H$``#J0P!3 +MXP0``!H7,-WE1`!3XP$``!H!,*#C"S#$Y;PPU.&.*`CC!A@`XP(`4^$!`%,1 +M`@``"@LPU.4!`%/C`P``&@8`H.$$$*#C`2"@X_[__^M&D-3E`9`9X@0```H& +M`*#A_O__ZP!04.(,```:P0``ZEL-AN(X`(#B1A"$XO[__^L`4%#BNP``"FPP +MEN40`!/C`@``"M`PE>4!`!/CM0``"@B@A.+8,)7E,C#$Y5Q0A.4`,*#C,3#$ +MY0X@H..P(<3A&""@X[(AQ.$((*#C"2#$Y3`PQ.5L,);E<``3XP8```K<,)7E +M``!3XR0```H8`(WB"A"@X6S[_^L@``#JS#26Y0``4^,=```*&`"-X@H0H.%E +M^__K5376Y0``4^,7```*,"#4Y0<`4N,4``"*T"/4X0$0H.,1(J#A"0`2XP0` +M`!K``!+C"@``&C``$N,$```:"@``Z@(`$^,",*`3,##$%08``.H$`!/C`S"@ +M$S`PQ!4"``#J"``3XP4PH!,P,,05Z#"5Y0$`4^,)```:`#"@XQTPQ.6\(-3A +MCC@(XP,`4N%%```*;#"6Y0$($^-"```:<```ZL@X`>,#,);G`P!3XP/QGY<, +M``#J,,L!`##+`0!`RP$`,,L!`,PX`>,#,);G'3#$Y00``.H``%GC)#D!$P,P +MEA?L,)4%'3#$Y<@X`>,#,);G`P!3XP/QGY<-``#J>,L!`'C+`0"(RP$`>,L! +M`-`X`>,#,);G3##$Y0<``.H``%GC*#D!$P,PEA<`,*`#3##$Y0$``.H`,*#C +M3##$Y1TPU.4!,$/B!`!3XP/QGY<5``#JT,L!`.#+`0`4S`$`!,P!`-#+`0`$ +M,*#C'C#$Y1\PQ.4/``#J"#"@XQXPQ.4$,*#C'S#$Y2$\`>,#,-;G``!3XP<` +M`!HR``#J"#"@XQXPQ.4?,,3E`@``Z@`PH.,>,,3E'S#$Y1TPU.4``%/C"@`` +M"B0\`>,#,);G`0!3XP,```HL/`'C`S"6YP``4^,"```:`3"@XPHPQ.4!``#J +M`#"@XPHPQ.4+`*#A"A"@X?[__^L`,*#C5##$Y5@PQ.56,,3EW""5Y4T@Q.6$ +M)I7E3B#$Y4XAU>5/(,3EF";5Y5`@Q.69)M7E42#$Y9HFU>52(,3E4S#$Y5LP +MQ.4`,)CE8#"$Y>0V`^,#,);G``!3XP4``!H'``#J!P"@X000H.'^___K``#@ +MXR<``.H&`*#A!!"@XS/_+^$P,-3E5S#$Y?[__^L-(*#A?SW"XS\PP^,$()/E +M`2""X@0@@^4&`*#A!!"@X?[__^L!`%#C"```&@T@H.%_/<+C/S##XP0@D^4! +M($+B!""#Y?[__^L!`*#C#0``Z@T@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[_ +M_^L&`*#A!!"@X90[`^,/X*#A`_"6YP$`<.(``*`S1-"-XO"/O>AP0"WI`%"@ +MX0!@#^&```SQ#2"@X7\]PN,_,,/C!""3Y0$@@N($((/EQ`"`XO[__^L!`%#C +M`$"@`PL```K$0)7E#`"4Z`0P@N4`((/E`$"$Y01`A.4``%3CW#"5%0$P0Q+< +M,(45`#"@$Q0PA!4&\"'A#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E`#"3Y0(` +M$^,````*_O__ZP0`H.%P@+WH<$`MZ0!`H.$``%'B``"@`W"`O0@`4`_A@``, +M\0T@H.%_/<+C/S##XP0@D^4!((+B!""#Y0P`D.@$,(+E`""#Y0``@.4$`(#E +MX!"$XO[__^OP,)3E`3"#XO`PA.4%\"'A#2"@X7\]PN,_,,/C!""3Y0$@0N($ +M((/E`#"3Y0(`$^,!`*`#<("]"/[__^L!`*#C<("]Z'!`+>D`0*#A``!1XP`` +MH`-P@+T(N#'1X0``4^,#```*!`"@X?[__^L!`*#C<("]Z`!0#^&```SQ#2"@ +MX7\]PN,_,,/C!""3Y0$@@N($((/E#`"1Z`0P@N4`((/E`!"!Y000@>4!`*#A +MQ!"$XO[__^O<,)3E`3"#XMPPA.4%\"'A#2"@X7\]PN,_,,/C!""3Y0$@0N($ +M((/E`#"3Y0(`$^,!`*`#<("]"/[__^L!`*#C<("]Z'!`+>D`4*#A`&`/X8`` +M#/$-(*#A?SW"XS\PP^,$()/E`2""X@0@@^7@`(#B_O__ZP$`4.,`0*`#"P`` +M"N!`E>4,`)3H!#""Y0`@@^4`0(3E!$"$Y0``5./P,)45`3!#$O`PA14`,*`3 +M%#"$%0;P(>$-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^4`,)/E`@`3XP````K^ +M___K!`"@X7"`O>@00"WI"-!-X@!`H.$",*#A/"4!XP(@T.<``%+C`""@`STU +M`0,#(,`'%P``"@$`4N,5```*`0"@X2H0H.,$((WB_O__ZP``4.,`(*`#/34! +M`P,@Q`<,```*`C#0Y0(`$^,`(*`#/34!`P,@Q`<&```*9SL"XP,PU.(0@+WH\$\MZ7S03>(4`(WE`6"@X0)`H.$@ +M((WE`@"@X4:0\.4@`(WE`9`)XA00G>5;'8'B.!"!XAP0C>4!`*#A(!"=Y?[_ +M_^L`H%#B50(`"FPPE.4``%/C!```&F`)G^5@&9_E_O__ZP``H.--`@#JU2?4 +MX00@@N*"(:#A4",(/@"#"-Y10`G>4#$*#A"""$XO[__^L``%#C +M`P``&B`)G^7^___K``"@XSP"`.I@4(WB!@"@X040H.'^___K!0"@X0`0H..P +M(=3A_O__ZS0U`>,4()WE`S"2YP0P0^(,,(WE*#"$XB0PC>4@`(3B&`"-Y0A@ +MG>4`@*#C8+"-X@90H.&P,-;A`3N#X[`PQN&R<=3A!V"&X`P0G>4!<&?@'C#4 +MY0``4^.T```*'3#4Y0$P0^($`%/C`_&?EZ@``.K\T0$`8-(!`(S4`0"`TP$` +M_-$!`"`QVN4@,,3E(3':Y2$PQ.4B,=KE(C#$Y4PPU.4#,Z#A(S#$Y1(.H./0 +M((KA_Q3@XP$`4N$#```:``!3XP``H`,`$*`#`P``"@$`H.,`$*#C`@"0X`,0 +MH>`2+J#C\@"*X8H``.H``%GC(P``"B$QVN4@,,3E(3':Y5\P`^(@,(/C(3#$ +MY2`QVN4B,,3E3##4Y0,SH.$@,(/C(S#$Y2(QVN4D,,3E(S':Y24PQ.4D,=KE +M)C#$Y24QVN4G,,3E$@Z@X]`@BN$!`'+C!```&O\?#^,!`%/A``"@`P`0H`,# +M```*`0"@XP`0H.,"`)#@`Q"AX!(NH./R`(KA9```ZB$QVN4@,,3E(3':Y5\P +M`^(@,(/C(3#$Y2`QVN4B,,3E(#"@XR,PQ.4B,=KE)##$Y2,QVN4E,,3E)#': +MY28PQ.4E,=KE)S#$Y1(.H./0((KA`0!RXP0``!K_'P_C`0!3X0``H`,`$*`# +M`P``"@$`H.,`$*#C`@"0X`,0H>`2+J#C\@"*X4(``.H``%GC(0``"B`QVN4@ +M,,3E(3':Y2$PQ.4`,*#C(C#$Y4PPU.4#,Z#A(#"#XR,PQ.4B,=KE)##$Y2,Q +MVN4E,,3E)#':Y28PQ.4E,=KE)S#$Y1(.H./0((KA`0!RXP0``!K_'P_C`0!3 +MX0``H`,`$*`#`P``"@$`H.,`$*#C`@"0X`,0H>`2+J#C\@"*X1X``.H@,=KE +M(##$Y2$QVN4A,,3E`#"@XR(PQ.4@`*#C(P#$Y2(QVN4D,,3E(S':Y24PQ.4D +M,=KE)C#$Y24QVN4G,,3E$AZ@X]$@BN$!`'+C!```&O\/#^,``%/A``"@`P`0 +MH`,#```*`0"@XP`0H.,"`)#@`Q"AX!(NH./R`(KA!@"@X1@0G>4>(-3E_O__ +MZQXPU.4#8(;@!W!CX```6.,`,*`3!#"-%04``!H&`*#AO!#4X?[__^L$`(WE +M`&"&X`=P8.`?,-3E``!3XP(```H*(-3E``!2XP=P8Q```%GC"P"@X080H.$4 +M()05!R"@`?[__^L`<*#A`&"&X!\@U.4``%+C!P``"@HPU.4``%/C!```"@8` +MH.$D$)WE_O__ZQ\PU.4#8(;@`8"(X@``6>,#```:"P"@X?[__^L!`%#CNP`` +M&GB`[^8<@,3ELB'4X1X0U.4$`)WE`0!8XP``H!,$`(WE"C#4Y0``4^,?,-05 +M`B"!X`=P@N`$$)WE`7"'X`-PA^`8<(3EL##5X0$[P^.P,,7A`#"@XUPPS>5= +M,,WE7C#-Y5\PS>5&8-3E7%"4Y0,`5>$#```:'`"=Y2`0G>7^___K`%"@X75P +MU.4=,-3E`@!3XY(``!H``%7CD```"D0PC>(`(*#C!""#Y`0@@^0$((/D`""# +MY6R`E.4!`!;C$P``"B@Y`>,4()WE`P"2YP`"@N!E#8#B+`"`XD00C>(0(*#C +M_O__ZP$`4.,%`0`**#D!XQ0`G>4#$)#G`1*`X"P`C>)E'8'B+!"!XO[__^L( +M``#J\`"%XD00C>(0(*#C_O__ZP$`4./V```*+`"-XO`0A>+^___K=W"OY@1P +MA^*'<:#A=W#OY@=PB.`'4*#A`3#UY0$`$^,+```*+`"-XA`0A^(&(*#C_O__ +MZP`PU>4"`!/C+`"-XA@0AQ(*$(<"!B"@X_[__^L*``#J+`"-X@00A^(&(*#C +M_O__ZP`PU>4"`!/C+`"-XA`0AQ(*$(<"!B"@X_[__^M-,-3E``!3XS`PU!5< +M,,T5+`"-XEP0C>($(*#C_O__ZP!@H.,TA0'C+*"-X@:PH.$$4*#A)P``Z@-` +M%^(!0*`3)W&$X+(1U>$>(-7E`0""X`=Q@.`!8(;B`P!6X0T``!H8,)7E`Q!A +MX`$@8N`*,-7E``!3XPLPH`$?,-45`D!CX`H`H.$'$*#A!""@X?[__^L$<(?@ +M#P``ZA0PG>4(0)/G!!!AX`$@8N`*,-7E``!3XPM`H`$?0-45`D!DX`H`H.$' +M$*#A!""@X?[__^L?,-7E`T"$X`1PA^`<,-7E`P!6X=3__[H%0*#A5%"-XBP` +MC>(%$*#A_O__ZP<`H.$%$*#A"""@X_[__^L8()3E""""XA@@A.4``%+C`P`` +M"@`PH.,(,(/B`@!3X?S__SH*,-3E``!3XPH``!H>``#J`S`6X@$PH!,F88/@ +M$`"=Y09A@.`&`*#A"!"=Y;(AU.'^___K3_[_ZATPU.4!,$/B!`!3XP/QGY4$$*#A_O__ZP``6>,`,*`3,S#$%0$`H!->```:7#"4 +MY1P@U.4!`%+C-"4!$Q0`G14"$)`7&!"4!10`G>7A)]#E!P!2XP,``)H"+P+C +M`B#0YP``4N,2```*:"L"XQ0`G>6R()#A`0!2X0$`H#,S`,0U2```.DTAT^4` +M`%+C`0"@$S,`Q!5#```:3#'3Y0``4^,",*`3`#"@`S,PQ.4!`*#C/```ZA0` +MG>7**]#E!0!2XPD``!I3(-3E`0!2XP8``!K,*`'C`B"0YP0`4N,",*`#,S#$ +M!0$`H`,N```*4R^@X[(@D^$``%+C"@``"DTAT^4``%+C`0"@$S,`Q!4E```: +M3#'3Y0``4^,",*`3,S#$%0$`H.,?``#J3C#4Y0``4^,.```*%""=Y=,[TN7? +M)]+E``!2XP0```H",$/B6S,)#A`P!1X0$`H(,S`,2%!@``BE,PU.4!`%/C`0"@ +M`S,`Q`4`,*`3,S#$%0$`H!-\T(WB\(^]Z````.,``$#C_O__ZP``H./X___J +MX`(```P3``#X`@``$$`MZ0!`H.'^___K!`"@X?[__^L,`(3B_O__ZR``A.+^ +M___K*`"$XO[__^LP`(3B_O__ZS@`A.+^___K0`"$XO[__^M4`(3B_O__Z\P` +MA.+^___KU`"$XO[__^L0@+WH\$$MZ0"`H.%88)#E1$"0Y=APD.4&`*#A(#L# +MXP_@H.$#\);G"`"@X?[__^M$,)CE``!3X_"!O0@>6X3B!@"@X000H.'^___K +M>$"$X@4`5.'Y__\:!U"@X0I-A^)2?*#C!@"@X040H.$'(*#A_O__ZZ!0A>($ +M`%7A^/__&D``F.4``%#C`0``"@08!^/^___KU`"8Y0``4.,!```*H1^@X_[_ +M_^OH`(CB_O__Z^Q`F.4%6X3B`GN@XP8`H.$$$*#A!R"@X?[__^N@0(3B!0!4 +MX?C__QKH`)CE``!0XP$```H$%`'C_O__ZP8`H.'^___K\(&]Z!!`+>D`0*#A +M_O__ZP@`A.+^___K`#"@XQ`PA.40@+WH$$`MZ0!`H.$`$*#CB""@X_[__^L$ +M`*#A_O__ZP@`A.+N___K'`"$XNS__^LP`(3BZO__ZT0`A.+H___K6`"$XO[_ +M_^M@`(3B_O__ZQ"`O>CP3RWI#-!-X@"@H.$!<*#A_O__ZPH`H.$`$*#C_O__ +MZPP`BN(`$*#C_O__ZUAPBN48`(KB_O__ZR``BN+^___K*`"*XO[__^LP`(KB +M_O__ZS@`BN+^___K3`"*XO[__^L$"`?C_O__ZT``BN4``%#C`&"@`T1@B@5X +M```*`P"`X@-`P.-$0(KE3("*XAY;A.(`8*#C!`"@X?[__^MH<(3E9&"$Y6!@ +MA.5L8(3E<&"$Y00`H.$($*#A_O__ZWA`A.(%`%3A\O__&@$\H.-(,(KE*CD` +MXU0PBN7$`(KB_O__Z\P`BN+^___KH0^@X_[__^O4`(KE``!0XU<```H#`(#B +M`T#`X]A`BN7$L(KB'CZ$X@0PC>4`4*#C4IR@XP2`H.$$`*#A_O__ZQ10A.4( +M<(3EN%'$X0<`H.$$$*#A"2"@X?[__^L`8%#B1```"KI1Q.$$`*#A"Q"@X?[_ +M_^L$,)WE`P!4X:!`A!+K__\:!#"@X]PPBN7@`(KB_O__ZP0$`>/^___KZ`"* +MY0``4.,R```*`P"`X@-`P./L0(KEX#"*X@0PC>5-C83B(("(X@"0H.,!L*#C +M!%"@X00`H.'^___K%)"$Y0APA.6XL<3A!P"@X000H.$"*Z#C_O__ZP!@4.(> +M```*!`"@X000G>7^___K"`!4X:!`A!+M__\:(#"@X_`PBN4'`*#A_O__ZX@` +MFN6,$-KE_O__ZP$PH..<,,KED`"*X@`0H./^___K`#"@X[0PBN6X,(KEO#"* +MY<`PBN4<.P/C`S"7YP``4^,#```*!P"@X3/_+^$```#J`&"@XP8`H.$,T(WB +M\(^]Z```4N,-``#:`##1Y0``4^$`,*`3`P``&@8``.H#P-'G``!_R_A`0"@XQ[_ +M+^$!`*#C'O\OX1!`+>D(T$WB`$"@X0<0S>4!`%'C$```&N$Z`^,#,-#G``!3 +MXPP```H=,P/C`S#0YP``4^,(```*`""@XQTS`^,#(,#G)A"@XS,LA.(<((+B +M9#L#XP_@H.$#\)3G!`"@X2D0H.,'((WB9#L#XP_@H.$#\)3G!S#=Y0``4^,; +M```:X"H#XP(PQ.?A*@/C`C#$Y^(J`^,",,3GXRH#XP(PQ.?8*@/C`C#$YX4S +M`^,#,-3G`0!3XPT``!H=,P/C`S#4YP``4^,)```:`B"@XQTS`^,#(,3G!`"@ +MX280H.,S+(3B'"""XF0[`^,/X*#A`_"4YPC0C>(0@+WH<$`MZ1#03>*HS`/C +M#,"0YP``7.,"```:^`"?Y?<7`./^___K`%","```:X`"?Y3D7`./^ +M___K`<"@X1A`_.4$`%3C*P``&@9@W.4!0-SE"0!4XRH``!H"7(7B!D"@X0$` +M5N,*```*`@``.@<`5N,D```:"0``Z@``4^,A```*(C#5Y0``4^,>```:_O__ +MZQP``.H``%/C(C#%!1D``.H`,*#C##"-Y0@PC>4B,,7E"`",XB`00N(#(*#A +M##"-XO[__^L``%#C#@``"@@PC>(`,(WE#!"=Y0\@H.,`,*#C_O__ZP``4.,` +M,*`3`3"@`R(PQ>4#``#J?P!4XP5`W`4````*`$#@XP0`H.$0T(WB<("]Z&0# +M``#P3RWI=-!-X@!0H.$`P*#C<#"-X@3`(^4($('B&!"-Y0@@0N(4((WE`0"@ +MX0(0H.$,(*#A_O__ZP!`4.(`(*`#'""-!9````HX,(7B+#"-Y:?/A>(HP(WE +M*BZ%X@(@@N(D((WE`#"@XQPPC>4T8(WB!'"&X@2`A^($H(CB!)"*X@2PB>($ +MP(OB#,"-Y00@C.(0((WE!#""XB`PC>4`(*#C:R#-Y5P@C>5@(,WE`""&Y0`@ +MA^4`((CE`""*Y0`@B>4`((OE#,"=Y0`@C.40,)WE`""#Y2`PG>4$((/DL"## +MX60@C>4!,*#C(#/%Y60PC>(`,(WE!`"@X6P0G>5K,(WB_O__ZV0PG>4!`%/C +M+P``&FO`W>44*`%/C"C"@$\PRA17R +M(M7E^1+5Y:$PH.$#`%+A!```FL0RE>4#`%/C`S"@$\0RA14;``#J`P!2X00` +M`"K$,I7E`@!3XP(PH!/$,H45%```Z@$`$>,$```*Q#*5Y0(`4^,",*`3Q#*% +M%0T``.K$,I7E`P!3XP,PH!/$,H45"```ZL0RE>4!`%/C`3"@$\0RA17,,I7E +M"P!3XPLPH!/,,H45+@``Z@`0H.-D$(WE!@"@X28@H./^___K9#"-X@`PC>4$ +M`*#A;!"=Y0\@H.,&,*#A_O__ZP``4.,(```**`"=Y080H.$&(*#C_O__ZR0` +MG>4&$(;B9""=Y08@0N+^___K`#"@XV0PC>5D,(WB`#"-Y00`H.%L$)WE$2"@ +MXUPPC>+^___K``!0XV`PW14<,\45<#"-X@0`,^44()WE`A!@X!C`G>4$(&S@ +M``"$X`$08N``(*#C_O__ZP!`4.*#__\:'`"=Y730C>+PC[WH\$#<#XP-`A.?=#83B)`"`X@40H.$%(*#A_O__ZP`@`..H-P/C +M`"!`XP,@A.>L-P/C`T"$Y]X-A.(8`(#B!1"@X04@H.'^___K`"``X]PW`^,` +M($#C`R"$Y^`W`^,#0(3GWPV$X@P`@.(%$*#A!2"@X?[__^M].@/C`U#$Y_[_ +M_^NK.@KCJCI*XY,@@^"C,*#A@S"#X```8^`!`(#B0BH#XP(`Q.<."X3B!1"@ +MX3P@H./^___K#CN@X[-0A.$)`(?@!1"@X0P@H./^___K!("@XWXZ`^.S@(3A +M`2"@X^H]H.,#(,3G`P"$X`(`@.`%$*#A(""@X_[__^NA.@/C`U#$Y\0Z`^,# +M4(3GR#H#XV(OH..S((3ARCH#XP-0Q.?K#83B"P"`X@40H.$-(*#C_O__ZP)@ +MAN(&`*#A!1"@X0@@H.'^___K!@"@X0D0H.$*(*#A_O__ZSP`A^(%$*#A)B"@ +MX_[__^OPA[WH<$`MZ0!`H.$!4*#A`3!!X@(`4^,2``"*`!``XP`00./^___K +M``!0XW"`O0@$`*#A!1"@X?[__^MX.P/C`\"4YP``7.-#```*!`"@X0$0H.,` +M(*#C`3"@X3S_+^$!`*#C<("]Z```4>,Z```:+#H#XP,PD.<``%/C&0``"MT- +M@.(D`(#B_O__Z]X-A.(8`(#B_O__Z]\-A.(,`(#B_O__ZRPZ`^,#,)3G``!3 +MXP`@H!,L.@,3`R"$%R0Z`^,#,)3G``!3XP`@H!,D.@,3`R"$%PX+A.(\`(#B +M`!"@XPH@H./^___K>#L#XP/`E.<``%SC!```"@0`H.$!$*#C`""@XP(PH.$\ +M_R_AT#,#XP,PE.<``%/C#P``&@`P`.,`,$#C`#"3Y<@C`^,"()3G9!"@XY$" +M`>#3+03C8B!!XY(!@>#.#83B%`"`XB$3@^#^___K`0"@XW"`O>@!`*#C<("] +MZ'!`+>D`4*#AVTV`XC!`A.($`*#A`!"@XW`@H./^___K`"``XS<\H.,`($#C +M`R"%YP0W`^,#4(7G!`"@X0`0H.,!(*#A_O__ZW"`O>@00"WI+#H#XP,PD.<` +M`%/C$("]"`$0H./^___K$("]Z!!`+>DL.@/C`S"0YP``4^,0@+T(?3H#XP,@ +MT.D%$*#C_O__ZQ"`O>@00"WI`$"@ +MX2PZ`^,#,)#G``!3XQ"`O0C^___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/E +M+#H#XP,PE.<&`%/C!P``&C@X`^,#,-3G`0!3XPP``!H$`*#A`A"@X_[__^L( +M``#J"0!3XP8``!KZ.0/C`S#4YP$`4^,"```:!`"@X0,0H./^___K#2"@X7\] +MPN,_,,/C!""3Y0$@0N($((/E_O__ZQ"`O>CP02WI`$"@X0%0H.$L.@/C`S"0 +MYP``4^,S```*W#H#XP,PD.<%`%/A+P``"M@Z`^,#,-#G``!3XRL```K<.@/C +M`Q"`YP``4N,C```*'`"@X_[__^L`<*#A`&"@X0``4.,``*`#\(&]"`P`H./^ +M___K`("@X0``4.,$```:!P"@X1P0H./^___K``"@X_"!O>@'(*#C)`"`Z`!0 +MH.,(4(#E%`"'XO[__^LY,*#CL##'X02`A^4,,*#C"#"'Y0Q0A^404(?E!0N$ +MXB@`@.('$*#A_O__ZW``[^;P@;WH!1"@X?[__^L!`*#C\(&]Z`$`H./P@;WH +M\$\MZ4??3>((`(WE`5"@X0)@H.$`0*#C%$&-Y10`C>($$*#A`2R@X_[__^L0 +M0(WE+#H#XP@`G>4#,)#G!`!3X9,```H,`%;CD0``F@Q0A>(,8$;B!0"@X080 +MH.$$(*#A13^-XO[__^L`0%#BB```"A1PC>(0@(WB#*"@XT6?C>(`L*#C`("- +MY00`H.$4$9WE"B"@X04"(-'G +M``!2XP,```K@*@/C`B#1YP,`4N%Q```*X"H#XP@`G>4",,#G%3#=Y:,3H.'B +M*@/C`A#`YW\P`^+A*@/C`C#`YQ`PG>4"`%/C`%"@DRL``)H($)WEZSV!XBB0 +M@^(PL(/B.#"#X@PPC>4`4*#C`D"@X_RN#^/_KT_C%'"-X@2`H.,(()WE!3"" +MX.L]@^(@,(/B1@^-X@0@@.`*(-+G!"##Y05AH.$!$(3B!@")X'$0Y^8((*#A +M_O__ZP40A.(&`(O@<1#GY@@@H.'^___K"1"$X@P@G>4&`(+@<1#GY@@@H.'^ +M___K#4"$XG1`[^8!4(7B=5#OYA`PG>4#`%3AW___.N,Z`^,(`)WE`U#`Y^(Z +M`^,#,-#G`0!3XPH``!H!(*#CV#H#XP,@P.>%,P/C`S#0YP(`4^$I```:"`"= +MY0(0H.'^___K)0``Z@``5>,'```*`2"@X]@Z`^,($)WE`R#!YP@`G>4"$*#A +M_O__ZQL``.K8.@/C"""=Y0,PTN@00"WI`#"@ +MX2PJ`^,"()#G"0!2XP$```H+`%+C!0``&B0J`^,"()/G`0!2XP$0H!,D*@,3 +M`A"#%R@J`^,"()/G+!H#XP$0D^DMH.,"$-/G`""@XP(PH.'^___K$("]Z!!`+>D0T$WB`$"@X20W +M`^,#$-#GWC?0Y0$`4^$#```*WA?`Y0`@H.,",*#A_O__ZR@Z`^,#,)3G+"H# +MXP(@E.<"`%/A+"H#$P(PA!=8-P/C`P"4YU`W`^/4((/A-QR$XB@0@>(`$(WE +M3!<#XP$0E.<$$(WET!"@XP@0C>7^___K$-"-XA"`O>@P0"WI#-!-X@!`H.$( +M4(WB`3"@XP$P9>7P.0/C`Q#0YP`@H.,",*#A_O__ZP0`H.$,$*#C!2"@X60[ +M`^,/X*#A`_"4YP0`H.'^___K`#``XP`P0.,`$)/EWPV$X@P`@.(*$('B_O__ +MZPS0C>(P@+WH,$`MZ0S03>(`0*#A"%"-X@$PH.,!,&7E`C@#XP,0T.<`(*#C +M`C"@X?[__^L$`*#A#!"@XP4@H.%D.P/C#^"@X0/PE.<$`*#A_O__ZP`P`.,` +M,$#C`!"3Y=\-A.(,`(#B"A"!XO[__^L,T(WB,("]Z#!`+>DLT$WB`%"@X01` +MC>($`*#A`!"@XR0@H./^___K!`"$XND=A>(+$('B!R"@X_[__^L',*#C!#"- +MY2PZ`^,#,)7G!0!3XP4@H!,L.@,3`R"%%_[__^L-,*#A?TW#XS]`Q.,$,)3E +M`3"#X@0PA.4%`*#A!!"-X@$@H./^___K!#"4Y0$P0^($,(3E_O__ZRS0C>(P +M@+WH$$`MZ04`4>,!\9^7#@``ZHSP`0"4\`$`G/`!`*3P`0"P\`$`K/`!`/[_ +M_^L0@+WH_O__ZQ"`O>C^___K$("]Z/[__^L0@+WH_O__ZQ"`O>@P0"WI1]]- +MX@%0H.$/(,WE&$"-X@0`H.$`$*#C`2R@X_[__^L`$*#C%!"-Y5`PH.,8,,WE +M;S"@XQDPS>5E,.#C&C#-Y0DPH.,;,,WE!`"$X@$@H.,0,(WB`3!#XO[__^L$ +M((#B%#"-X@`PC>4%`*#AW1"@XP0PH.'^___K%`"=Y4??C>(P@+WH\$$MZ1'> +M3>(`0*#A`6"@X0*`H.$#<*#A$%"-X@4`H.$`$*#C`2R@X_[__^L`,*#C##"- +MY5`@H.,0(,WE;R"@XQ$@S>5E(.#C$B#-Y0D@H.,3(,WE`B"@XQ0@S>46,,WE +M%2#-Y2`@H.,7(,WE&##-Y0TPH.,9,,WE&C/4Y14@@^(B)*#A&R#-Y14P@^(: +M,,WE#`"%XBT>A.(&(*#C_O__ZV0SE.4#`%/C`#"@XR(PS>5_,.`#"#"@$R,P +MS>4`,*#C)##-Y1X@H.,E(,WE)C#-Y5`@H.,G(,WE#2#@XR@@S>4$(*#C*2#- +MY2HPS>4!(*#C*R#-Y2PPS>40,*#C+3#-Y1$PH.,N,,WE&B/4Y4(TH.$O,,WE +M,"#-Y3$`C>*^'X3B`A"!XO[__^L:4]3E(5"%XL0RE.4"`%/C%0``&A$NC>(% +M,(+@#R"@XP`A0^4!,(7B$$"-X@00@^`&((?B(@2@X0$`P>4#(,3G`P"%X@`` +MA.`H$9WE!B"@X_[__^L)4(7B!0"$X`@0H.$'(*#A_O__ZP50A^`,,(WB`#"- +MY08`H.'=$*#C!2"@X1`PC>+^___K#`"=Y1'>C>+P@;WH\$`MZ47?3>(`8*#A +M`7"@X1``C>(`$*#C`2R@X_[__^L`,*#C"#"-Y5`PH.,0,,WE;S"@XQ$PS>5E +M,.#C$C#-Y0DPH.,3,,WE_CX/X_\_3^,B*0#C$1Z-XK,@@>',,I;E#0!3X_X^ +M#P/_/T\#(BD$`[,@@0$00(WB!`"$X@(0H.,!(*#A`C!$XO[__^L$4(#B!0"$ +MX`,0H.,&(*#C+3Z&XO[__^L`((7@"#"-X@`PC>4'`*#AW1"@XP0PH.'^___K +M"`"=Y47?C>+P@+WH\$(`4*#A`9"@X0\@S>4.,,WE`&"0Y7\PH.,_ +M,4T`(WB`!"@XP$LH./^___K%#"-X@`@ +MH.,$((/D!""#Y`0@@^0$((/D!""#Y`0@@^0$((/D`""#Y5,-AN(@`(#B_O__ +MZP!`4.)A```*!@"@X0@0A.+^___K;`"4Y0`0H.-H(*#C_O__ZVR`E.4(<*#A +M`*"@XRB@Y^4!H,?E+`"(X@D0H.$&(*#C_O__Z[5?A>("4(7B,@"(X@40H.$& +M(*#C_O__ZS@`B.(%$*#A!B"@X_[__^L((*#AOA/RX=PW`..S`);A#Q`!X@`2 +M@>&P$,+ALR"6X0$@@N*S((;AL##7X?PPP^/0,(/CL##'X010H.$8,*#C%#"E +MY4``B.(!$*#C3R^-X@,@@N(%,*#A_O__ZP00H.-.+XWB!3"@X?[__^L!$*#C +M32^-X@,@@N(%,*#A_O__ZQ"`C>(!$*#C`B!(X@4PH.'^___K`)"@X5`PH.,T +M,,WE;S"@XS4PS>5E,.#C-C#-Y0DPH.,W,,WE-'"-X@0`A^(*$*#A`2"@XP$P +M2.+^___K!("`X@$PH.,4,,WE%:#-Y0@`A^`,$*#C`B"@XQ0PC>+^___K`""( +MX`!0C>4)`*#AW1"@XP]Z!!`+>D!,*#A"A"!X@`@H.,>,-/E=/__ZP$`H.,0@+WH\$(! +M0*#A`Y"@X0!0D.4$,*#C=S#-Y0DPH.-V,,WE!S#2Y74PS>50/P;CFCE`XW`P +MC>4(,*#C;S#-Y0,`C>``$*#C9""@X_[__^M3#87B(`"`XO[__^L`8%#B6@`` +M"@4`H.$($(;B_O__ZVP`EN4`$*#C:""@X_[__^ML@);E"'"@X0"@H.,HH.?E +M`:#'Y2P`B.($$*#A!B"@X_[__^L-2X7B$4"$XC(`B.($$*#A!B"@X_[__^LX +M`(CB!!"@X08@H./^___K"""@X;X3\N'<-P#CLP"5X0\0`>(`$H'AL!#"X;,@ +ME>$!((+BLR"%X;`PU^'\,,/CT#"#X[`PQ^$&0*#A&#"@XQ0PI.5``(CB`1"@ +MXW<@C>($,*#A_O__ZP$0H.-V((WB!#"@X?[__^L$$*#C<""-X@0PH.'^___K +M`1"@XV\@C>($,*#A_O__ZP$0H.-U((WB!#"@X?[__^L(H,WE4#"@XPDPS>4- +M,.#C"C#-Y00PH.,+,,WE$#"@XPPPS>4(,*#C#3#-Y0Z@S>4",*#C#S#-Y2DT +MH.$0,,WE$9#-Y0!`C>7=$*#C"B"@XP@PC>+^___K%#"6Y1@PAN4%`*#A!A"@ +MX?[__^MXT(WB\(>]Z/!/+>FLT$WB`%"@X0B@@>((D$+B"@"@X0D0H.$`(*#C +MH#"-XO[__^L``%#C`#"@$R@PC14%```:S#*5Y0L`4^,+,*`3S#*%%0(PH.,H +M,(WE"@"@X0D0H.$`(*#CI#"-XO[__^L`0%#B"@``&L0RE>4!`%/C`3"@$\0R +MA17,,I7E"P!3XPLPH!/,,H45`C"@XR@PC>7<``#J`""@XY\@S>68((WEC""- +MY9`@S>64((WE,#"-X@0@@^0$((/D!""#Y`0@@^0$((/D!""#Y`0@@^0$((/D +M!""#Y`0@@^0$((/D!""#Y+`@P^$OOH7B`["+XB"PC>6G/X7B%#"-Y2T^A>(L +M,(WE*CZ%X@(P@^(,,(WE,CZ%X@$P@^(D,(WEVC^%X@,P@^(0,(WEGX"-XIA@ +MC>(P,(WB!3"#XA@PC>5D<(WB!C"'XAPPC>4`8(WE!`"@X:00G>4`(*#C"#"@ +MX?[__^N8,)WE`0!3XPT``!J?,-WE``!3XPH```K$,I7E`0!3XP$PH!/$,H45 +MS#*5Y0L`4^,+,*`3S#*%%9\PW>4H,(WEF0``Z@`PH..8,(WE`&"-Y00`H.&D +M$)WE"2"@XPLPH.'^___K``!0XP8```J8,)WE!@!3XP,```H@`)WE`!"@XP8@ +MH./^___K`#"@XY\PS>68,(WE`&"-Y00`H.&D$)WE!""@XP@PH.'^___K``!0 +MXT0```J?(-WE^2+%Y?(RU>6B(*#A`@!3X2```!H/`%/C#0``&L0RE>4!`%/C +M`3"@$\0RA17,,I7E"P!3XPLPH!/,,H45Q#*5Y0,`4^,),*`3*#"-%2\``!HD +M``#JS#*5Y0H`4^,*,*`3S#*%%9\PW>4!`!/C!```"L0RE>4"`%/C`C"@$\0R +MA14B``#JQ#*5Y0,`4^,#,*`3Q#*%%14``.H"`%/A"```FLPRE>4*`%/C"C"@ +M$\PRA17$,I7E`P!3XP,PH!/$,H45"@``ZLPRE>4*`%/C"C"@$\PRA17$,I7E +M`@!3XP(PH!/$,H45"0``Z@DPH.,H,(WE%`"=Y2P0G>4&(*#C_O__ZPP`G>4D +M$)WE02/5Y?[__^L`,*#CF#"-Y0!@C>4$`*#AI!"=Y1$@H..,,(WB_O__ZP`` +M4..0,-T5'#/%%90PC>(`,(WE!`"@X:00G>4+(*#C,#"-XO[__^L``%#C!``` +M"C0@W>5J(\7E$`"=Y1@0G>7^___K`!"@XY@0C>4'`*#A)B"@X_[__^L`8(WE +M!`"@X:00G>4/(*#C!S"@X?[__^L``%#C"```"A0`G>4'$*#A!B"@X_[__^L, +M`)WE'!"=Y9@@G>4&($+B_O__ZZ0`G>4)$&#@!#!JX```A.`!$&/@`""@XZ0P +MC>+^___K`$!0XD[__QHH`)WEK-"-XO"/O>CP3RWIE-!-X@!`H.$`,*#CC#"- +MY8@PC>6V.,WA@#"-Y60SD.4``%/C!0``&LPRD.4+`%/C"S"@$\PR@!4!D*#C +MXP``Z@AP@>((@$+B!P"@X0@0H.$`(*#CB#"-XO[__^L`8%#B(P``"N)0A.(% +M`*#A`!``XP`00.,#(*#C_O__ZP``4.,B```*@#"-X@`PC>4&`*#AB!"=Y1(@ +M`>.&,(WB_O__Z[8XW>&S/[_F$!`%/C!0``&@4`H.$`$`#C`!!` +MXP,@H./^___K#P``Z@4`4^,%`*#A`!```P`00`,`$``3`!!`$P,@H./^___K +M!@``ZLPRE.4+`%/C"S"@$\PRA!4"D*`3L```&JX``.H'`*#A"!"@X0`@H.., +M,(WB_O__ZP!04.(&```:S#*4Y0L`4^,+,*`3S#*$%0*0H!.B```:H```ZJ4J+H3B`B""XB@@C>4R/H3B`3"#XB0PC>4OKH3B`Z"* +MXBR@C>4`D*#C0&"-X@2PAN($((OB#""-Y00P@N(0,(WE!""#XA0@C>4$,(+B +M&#"-Y00@@^(<((WE!#""XB`PC>4$((/B/""-Y3B0C>4"D*#A`#"@XW\PS>5X +M,(WE`#"&Y0`PB^4,()WE`#""Y1`@G>4`,(+E%""=Y0`P@N48()WE`#""Y1P@ +MG>4`,(+E(""=Y0`P@N4)(*#A!#""Y`0P@N0$,(+D!#""Y+`PPN%T,(WES#*4 +MY0D`4^,),*`3S#*$%7@PC>(`,(WE!0"@X8P0G>4$(*#C?S"-XO[__^L``%#C +M*```"G\@W>7Y(L3E\C+4Y:(@H.$"`%/A%P``&@\`4^,(```:Q#*4Y0$`4^,) +M,*`#.#"-!0$PH!/$,H05"2"@$S@@C147``#J?S#=Y0$`$^,$```*Q#*4Y0(` +M4^,",*`3Q#*$%0\``.K$,I3E`P!3XP,PH!/$,H0500``Z@(`4^$$``":Q#*4 +MY0,`4^,#,*`3Q#*$%3H``.K$,I3E`@!3XP(PH!/$,H05`#"@XW@PC>5X,(WB +M`#"-Y04`H.&,$)WE"2"@XPHPH.'^___K``!0XP8```IX,)WE!@!3XP,```HL +M`)WE`!"@XP8@H./^___K=#"-X@`PC>4%`*#AC!"=Y0L@H.,&,*#A_O__ZP`` +M4.,+```*X0+4Y040AN)T(-WE_O__ZP``4.,%```:S#*4Y0L`4^,+,*`3S#*$ +M%0>0H.,,``#JD#"-X@0`,^4($&#@!2!GX```A>`!$&+@`""@X_[__^L`4%#B +M@/__&CB0G>4```#J`I"@XPD`H.&4T(WB\(^]Z#0`G>4P$)WE!B"@X_[__^LH +M`)WE)!"=Y4$CU.7^___KO___ZG!`+>D8T$WB`%"@X0%`H.$`,*#C%#"-Y1`P +MC>6^,,WA&&"!XB``@>(($$+B`R"@X10PC>+^___K``!0XS(```H0,(WB`#"- +MY100G>4((`'C#C"-XO[__^L``%#C*@``"KXPW>&S/[_F$(`%/C +M"```"@(``(H$`%/C'```&@H``.J``%/C#@``"@$,4^,7```:$0``ZN(`A>(` +M$`#C`!!`XP,@H./^___K$```ZN(`A>(`$`#C`!!`XP,@H./^___K"@``ZN(` +MA>(`$`#C`!!`XP,@H./^___K!```ZN(`A>(`$`#C`!!`XP,@H./^___K!0"@ +MX0H0A.(&(*#AOC#=X3_]_^L!`*#C&-"-XG"`O>CP3RWI/-!-X@-@H.$`,*#C +M-#"-Y;(SS>$L,(WEQ#*0Y0,`4^,%`*`3?@``&K`PT>'\,`/B``!3XP0PH`,* +M,*`3&`"#X@``@>`0`(WE&"!"X@(@8^`,((WE`A"@X0`@H.,L,(WB_O__ZP!` +M4.($`*`#;```"GH>AN(.$('B%!"-Y7L^AN(&((/B'""-Y0@P@^(8,(WE'SV& +MX@$P@^(D,(WE?AZ&X@00@>(@$(WE-*"-X@*PH.,`@*#C!%"@X0"@C>4%`*#A +M+!"=Y0L@H.$R,(WB_O__ZP``4..R,]T1M#?&%0"@C>4%`*#A+!"=Y0T@H.,( +M,*#A_O__ZP``4.,]```*-`"=Y?[__^L`<%#B.0``"@"@C>4%`*#A+!"=Y0T@ +MH.,',*#A_O__ZQ0`G>4'$*#A!B"@X_[__^L<`)WE!A"'X@L@H.'^___KMB<` +MX[(PEN&S/[_FLC"&X0B0A^(8`)WE"1"@X0@@H./^___K"$#9Y0F0B>(``%3C +MP(?&!0@```K`1\;EA$&@X20`G>4)$*#A(`!4XP0@H#$@(*`C_O__ZP20B>#B +M-P#CLX"&X;`PV>&S/[_F,!`%/A"0``&K(@V>&R+[_F`!$&/@"""@X2PPC>+^___K`%!0XJ3__QH\T(WB +M\(^]Z/!/+>E($P"/E'V#1Y2``@>(( +M$$+B#""@X?[__^L`0%#BL@``"A0PC>(`(*#C!""#Y`0@@^0$((/D!""#Y`0@ +M@^0$((/D!""#Y`0@@^0$((/DL"##X3P@C>6P),WA3""-Y4PPC>(`,(WE!`"@ +MX500G>4/(*#C%#"-XO[__^L``%#CF@``"BT.BN(4$(WB!B"@X_[__^L``%#C +ME@``"@T-BN("`(#B&A"-XF(CVN7^___K``!0XX\```H`,*#C3#"-Y4PPC>(` +M,(WE!`"@X500G>4#(*#C/#"-XO[__^L``%#CA```"O[__^L-(*#A?SW"XS\P +MP^,$()/E`2""X@0@@^4&>X7B('"'XB`X`>,#0)7G")"@XP&`H.-G``#J:UY$ +MX@A01>(`0)3EK#?5Y0``4^-@```*M#?5Y0(`$^-=```*>@Z%X@X`@.(\$(WB +M!B"@X_[__^L``%#C5@``"@"`FN5_,*#C43#-Y5`_!N.:.4#C2#"-Y0,PH.-2 +M,,WE`#"@XU,PS>53#8CB(`"`XO[__^L`<%#B`)"@`TP```H(`*#A"!"'XO[_ +M_^ML`)?E`!"@XV@@H./^___K;#"7Y0PPC>4#D*#A`""@XR@@Z>4!(,GE+`"# +MXN`0A>(&(*#C_O__Z[5/BN("0(3B##"=Y3(`@^($$*#A!B"@X_[__^L,()WE +M.`""X@00H.$&(*#C_O__ZPP@G>6^$_+AW#<`X[,`F.$/$`'B`!*!X;`0PN&S +M()CA`2""XK,@B.&P,-GA_###X]`P@^.P,,GA!T"@X1@PH.,4,*3E##"=Y4`` +M@^(!$*#C42"-X@0PH.'^___K!!"@XT@@C>($,*#A_O__ZP$0H.-2((WB!#"@ +MX?[__^L!$*#C4R"-X@0PH.'^___K%#"7Y1@PA^4(`*#A!Q"@X?[__^L`D*#C +M!0``Z@B0H.$'`*#A!!"@X?[__^L``%#CDO__"@T@H.%_/<+C/S##XP0@D^4! +M($+B!""#Y?[__^L"``#J")"@XP```.H$D*#C4Y#-Y5)@S>4`8)KE!#"@XU$P +MS>4),*#C2##-Y5`_!N.:.4#C1#"-Y08PH.-,,,WE`#"@XSPPC>5`,(WE4PV& +MXB``@.+^___K`%!0XE@```H&`*#A"!"%XO[__^ML`)7E`!"@XV@@H./^___K +M;("5Y0APH.$`,*#C*##GY0$PQ^4L`(CB"A"+X@8@H./^___K+4Z*XC(`B.($ +M$*#A!B"@X_[__^LX`(CB!!"@X08@H./^___K"""@X;X3\N'<-P#CLP"6X0\0 +M`>(`$H'AL!#"X;,@EN$!((+BLR"&X;`PU^'\,,/CT#"#X[`PQ^$%0*#A&#"@ +MXQ0PI.5``(CB`1"@XU$@C>($,*#A_O__ZP$0H.-(((WB!#"@X?[__^L$$*#C +M1""-X@0PH.'^___K`1"@XTP@C>($,*#A_O__ZP$0H.-2((WB!#"@X?[__^L` +M@*#A4#"@XSPPS>5O,*#C/3#-Y64PX.,^,,WE"3"@XS\PS>4\<(WB!`"'X@`0 +MH.,!(*#C4S"-XO[__^L$((#B`$"-Y0@`H.'=$*#C!S"@X?[__^L4,)7E&#"% +MY08`H.$%$*#A_O__ZP$`>>(``*`S7-"-XO"/O>CP3RWI1]]-X@!PH.$($(WE +M&`"-X@`0H.,!+*#C_O__ZP`@H.,4((WE4#"@XQ@PS>5O,*#C&3#-Y64PX.,: +M,,WE"3"@XQLPS>4",*#C'##-Y1X@S>4=,,WE(C"@XQ\PS>7$,I?E`P!3XP<` +M`!H),*#C(##-Y($,(+@"""@XPH@P^<#((3B!1""X``PX.,&,,'G`C#%YP4@A.(% +M$(+@!C#!YP(PQ><',(3B1B^-X@,P@N`-(*#C"B##YP@PA.(%$(/@&B/7Y14` +M@N(@!*#A!@#!YQ4@@N(#(,7G"@"$X@``A>`M'H?B!B"@X_[__^O:/Z#CLR"7 +MX2(4H.$0,(3B!1#CYP8@P^<2,(3B!8#CYQX@H.,&(,/G%#"$X@6`X^=0(*#C +M!B##YPT@X.,"(,/E`Y##Y1@PA.(%@./G!F##YQHPA.)&+XWB`S""X`J@@^`` +M@,KE&S"$XA`@H.,%(./G$2"@XP8@P^<:(]?E0A2@X1TPA.(%$./G!B##YQ]` +MA.($`(7@OA^'X@(0@>+^___K&H/7Y0B`A.#$,I?E`P!3XW(``!H`0)?E`0R@ +MX_[__^L,`(WE_O__ZPT@H.%_/<+C/S##XP0@D^4&((+@!""#Y09[A.(@<(?B +M(#@!XP-0E.<,8)WE!J"@X0"PH..VEP#C1```ZFM.1>((0$3B`%"5Y:PWU.4` +M`%/C/@``"@$`AN)Z'H3B#A"!X@8@H./^___K!P"&XN`0A.(&(*#C_O__Z[0W +MU.4-,,;E!C"@X;D@E.$B)*#A#B#CY;D@E.$!(,/E$`"&XGL>A.(($('B"""@ +MX_[__^L$$*#AP#?QY1@PQN498(;BP"?4Y08`H.$!$('B@B&@X?[__^O`-]3E +M@V&&X.(G`..R,)3A``!3XQ(```H0,*#C`##&Y1$@H.,!(,;EXB<`X[(PE.$C +M-*#A`C#FY;(PE.$!,,;E`F"&X@8`H.%^'H3B!!"!XK(@E.'^___KXB<`X[(P +ME.$#8(;@!C!JX',P[^8!($/B`"#*Y0NP@^![L/_F!J"@X0<`H.$%$*#A_O__ +MZP``4..U__\*#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__ZP``6^,`0*`# +M!@``"A@`C>((`(#@#A"@XPL@H.$,,)WE_O__ZP!`H.$,`)WE`1R@X_[__^L$ +M@(C@%#"-X@`PC>4(`)WEW1"@XP@@H.$8,(WB_O__ZQ0`G>5'WXWB\(^]Z/!` +M+>D4T$WB`&"@X0``H.,,`(WE"`"-Y1`PC>(,`"/E&%"!XAA`0N($<*#A!0"@ +MX0$0H.,#(*#A!#"@X?[__^L$$)WE!`!1XQ$``,H``%'C*P``V@#`H.,,(*#A +M`C#0Y0(`4^,$`%,3`P``"@L`4^,!```*%@!3XP'`H!,!((+B`0"`X@$`4N'S +M__\:``!(',*#A_O__ZP!PH.'$,I;E`0!3XP$` +M``H#`%/C$```&@4`H.$$$*#A`""@XPPPC>+^___K``!0XPD```H``%?C!P`` +M"@(`A^*Z'X;B`Q"!X@<@H./^___K``!0X@$`H!,```#J``"@XQ30C>+P@+WH +M!$`MY0``4>,.``#:@T&@X0#`T.4"`%SA!0``&@'`T.4#`%SA`@``&@$`5.$" +M`(#2!0``V@'`T.6,$4'@``!1XXP!@,#Q___*``"@XQ``O>@>_R_A``!1XQ[_ +M+P$@/0/C`S"0YP``4^,>_R\1J#"1Y;P@T^$(`%+C'O\O$0XP@^()(-/E$0!2 +MXQ[_+Q$`(-/E#R`"X@(Q@^`#$*#AL"#3X1$+4N,>_R\1LB#3X4,,4N,>_R\1 +M"#"#XF,B".-3(T;C[`"3Y0(`4.$>_R\1NB#3X8``$N,>_R\1@"""X[H@P^&V +M,-'A`S#@X7,P\N9#*+#A`@``"G,P\N9#*+#A_/__&@,PX.&V,,'A'O\OX7!` +M+>D8T$WB`&"@X0)0H.$$0(WB!`"@X1$0H./^___K`3"@XP0PS>4'`(3B!1"@ +MX00@H./^___K!##=Y0$`4^,(```:"S#=Y0P@W>4#("+@#3#=Y0,@(N`.,-WE +M`R`BX`\@`N)?``#J`P!3XQ0``!H%,-WE!B#=Y0,@(N`',-WE`R`BX`@PW>4# +M("+@"3#=Y0,@(N`*,-WE`R`BX`LPW>4#("+@###=Y0,@(N`-,-WE`R`BX`XP +MW>4#("+@#R`"XD@``.H$`%/C!@``&@4PW>4&(-WE`R`BX`4#("+@#R`" +MXC\``.H%`%/C$0``&@8PW>4%(-WE`R`BX`4@(N(',-WE`R`BX`@PW>4#("+@ +M"3#=Y0,@(N`*,-WE`R`BX`LPW>4#("+@###=Y0,@(N`/(`+B*P``Z@(`4^,@ +M```:!3#=Y08@W>4#("+@!S#=Y0,@(N`(,-WE`R`BX`DPW>4#("+@"C#=Y0,@ +M(N`+,-WE`R`BX`PPW>4#("+@#3#=Y0,@(N`.,-WE`R`BX`\PW>4#("+@$##= +MY0,@(N`1,-WE`R`BX!(PW>4#("+@$S#=Y0,@(N`4,-WE`R`BX`\@`N((``#J +M`""@XP(PH.$$`(WB`Q#0YP$@(N`!,(/B$0!3X_K__QH/(`+B\BZ"X@P@@N(" +M(8;@!$"2Y0``5.,+```*!%"-XA%@H.,8`(3B!1"@X08@H.'^___K``!0XP0` +MH`$#```*`$"4Y0``5./U__\:``"@XQC0C>)P@+WH<$`MZ0!0H.$!0*#A$1"@ +MX_[__^L%`*#A`C"@XP$PP.0$$*#A$""@X_[__^MP@+WH$$`MZ?[__^L-(*#A +M?SW"XS\PP^,$()/E`2""X@0@@^4$()/E`2!"X@0@@^7^___K$("]Z/!!+>D` +M0*#A`7"@X0)0H.'^___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/E`##5Y0$` +M4^,(```:""#5Y04#("+@"3#5Y0,@(N`*,-7E`R`BX`\@`N)>``#J`P!3 +MXQ0``!H"(-7E`3#5Y0,@(N`#,-7E`R`BX`0PU>4#("+@!3#5Y0,@(N`&,-7E +M`R`BX`4#("+@"##5Y0,@(N`),-7E`R`BX`HPU>4#("+@#R`"XD<``.H$ +M`%/C!@``&@(@U>4!,-7E`R`BX`,PU>4#("+@#R`"XCX``.H%`%/C$0``&@$@ +MU>4",-7E`R`BX`4@(N(#,-7E`R`BX`0PU>4#("+@!3#5Y0,@(N`&,-7E`R`B +MX`4#("+@"##5Y0,@(N`/(`+B*@``Z@(`4^,`(*`3`C"@$2```!H"(-7E +M`3#5Y0,@(N`#,-7E`R`BX`0PU>4#("+@!3#5Y0,@(N`&,-7E`R`BX`4# +M("+@"##5Y0,@(N`),-7E`R`BX`HPU>4#("+@"S#5Y0,@(N`,,-7E`R`BX`TP +MU>4#("+@#C#5Y0,@(N`/,-7E`R`BX!`PU>4#("+@#R`"X@4``.H#$-7G`2`B +MX`$P@^(1`%/C^O__&@\@`N+R+H+B#"""X@(AA.`$0)+E``!4XR0```H18*#C +M&`"$X@40H.$&(*#A_O__ZP``4.,:```:`#``XP`P0.,`()/E=2Q"XA0PE.4" +M,&/@,`!3XPD``%JH`)?E#!"$X@8@H./^___K"$"$XI\_E.$!,(/BDR^$X0`` +M,N/Z__\:#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__ZP$`H./P@;WH`$"4 +MY0``5./;__\:#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__ZP``H./P@;WH +M<$`MZ0!0H.$"0*#A`C"!X)P@D.4"`%/A$```BE``D.4``%3A#0``B@,`4N$+ +M```Z`B!CX```4N,"``#:`0"@X0,0H.'^___K4!"5Y04`H.$!$&3@_O__ZP`` +MH.-P@+WH``#@XW"`O>CP1RWI`'"@X0&@H.$"4*#A_O__ZPT@H.%_/<+C/S## +MXP0@D^4!((+B!""#Y0`PU>4!`%/C"```&@B`U>4',-7E`X`HX`DPU>4#@"C@ +M"C#5Y0.`*.`/@`CB7@``Z@,`4^,4```:`H#5Y0$PU>4#@"C@`S#5Y0.`*.`$ +M,-7E`X`HX`4PU>4#@"C@!C#5Y0.`*.`',-7E`X`HX`@PU>4#@"C@"3#5Y0.` +M*.`*,-7E`X`HX`^`".)'``#J!`!3XP8``!H"@-7E`3#5Y0.`*.`#,-7E`X`H +MX`^`".(^``#J!0!3XQ$``!H!@-7E`C#5Y0.`*.`%@"CB`S#5Y0.`*.`$,-7E +M`X`HX`4PU>4#@"C@!C#5Y0.`*.`',-7E`X`HX`@PU>4#@"C@#X`(XBH``.H" +M`%/C`("@$P@PH!$@```:`H#5Y0$PU>4#@"C@`S#5Y0.`*.`$,-7E`X`HX`4P +MU>4#@"C@!C#5Y0.`*.`',-7E`X`HX`@PU>4#@"C@"3#5Y0.`*.`*,-7E`X`H +MX`LPU>4#@"C@###5Y0.`*.`-,-7E`X`HX`XPU>4#@"C@#S#5Y0.`*.`0,-7E +M`X`HX`^`".(%``#J`R#5YP*`*.`!,(/B$0!3X_K__QH/@`CB\CZ(X@PP@^(# +M,8?@!$"3Y0``5.,9```*$6"@XQ@`A.(%$*#A!B"@X?[__^L``%#C#P``&@P` +MA.(*$*#A!B"@X_[__^L`,`#C`#!`XP`PD^44,(3E#2"@X7\]PN,_,,/C!""3 +MY0$@0N($((/E_O__Z_"'O>@`0)3E``!4X^;__QHL`*#C_O__ZP!`4.('```: +M#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__Z_"'O>@8`(3B!1"@X1$@H./^ +M___K#`"$X@H0H.$&(*#C_O__ZP$PH.,(,(3E`#``XP`P0.,`,)/E%#"$Y?(^ +MB.(,,(/B`S&'X`0PD^4`,(3E``!3XP1`@Q7RCHCB#("(X@B!A^`$0(CE!("( +MX@2`A.4-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K\(>]Z/!%+>E4'`(3B#!"(X@0@H./^___KJ!"7Y08`H.$&$('B +M!""@X0G__^L&`*#A-O[_ZP``H./%`P#J$("(XD1`C>($`*#A$1"@X_[__^L! +M,*#C1##-Y0<`A.(($*#A!""@X_[__^L&`*#A!Q"@X00@H.$R_O_K``!0X[,# +M`!H#,-CE_P!3XP4``!JH`)?E_Q"@XP8@H./^___K``"@XZL#`.JH`)?E/1R& +MX@P0@>(&(*#C_O__ZP``H..D`P#J"!8`XP$`4^%&```:#E"%XK(PU>$(`%/C +M!0``"K,_O^:$#I_E("`%3C!```"@,`5.,< +M```*`0!4XXT#`!J.`P#J"`"@X0T;AN(1$('B!B"@X_[__^L$,-7E`X"(X$1` +MC>($`*#A$1"@X_[__^L!,*#C1##-Y0<`A.(($*#A!""@X_[__^NH$)?E!@"@ +MX080@>($(*#AN?[_ZP8`H.'F_?_K``"@XW4#`.H$H-7E!3#5Y8J@B.`#H(K@ +M1$"-X@0`H.$1$*#C_O__ZP$PH.-$,,WE!P"$X@H0H.$$(*#C_O__ZP8`H.$' +M$*#A!""@X=_]_^L%`-7E!##5Y0,`@.```(C@J!"7Y08@H./^___K``"@XUH# +M`.H%&@[C`0!3X30!`(H`(`#C`"!`X[`@TN&P),WAJ%"7Y0Y0A>*!)P/C`@!3 +MX40```I``(WB!1"@X0(@H./^___K``!0XSX```H`,-7EJ@!3XS(``!HL+9_E +M.#"-X@00@N(#`)'H!`"#Y``0P^4P,(WB#!""X@,`D>@$`(/D`!##Y0@PC>(4 +M((+B`P"2Z`0`@^0`$,/E`U"%XC@`C>(%$*#A!2"@X_[__^L``%#C!5"%`B,` +M``HP`(WB!1"@X04@H./^___K``!0XP50A0(`@*`#)P,`"@@`C>(%$*#A!2"@ +MX_[__^L``%#C!8"%`@!0H`,?`P`*`!#5Y0$@U>4",-7E`P#5Y0``C>4$`-7E +M!`"-Y70,G^7^___K``#@XQ(#`.K@`%/C#0,`&@-0A>)``(WB!1"@X0(@H./^ +M___K``!0XP8#`!H``%7C`("@`[4```H"`%3C"P``"@,`5.,\```*`0!4X_T" +M`!JH`)?E!@"`XA80A>(&(*#C_O__ZP``4./X`@`*]0(`ZA:`A>*H`)?E!@"` +MX@@0H.$&(*#C_O__ZP``4.,3```:1$"-X@0`H.$1$*#C_O__ZP,PH.-$,,WE +M`0"$XA(0A>($(*#C_O__ZP4`A.(<$(7B`B"@X_[__^L-&X;B"`"@X1$0@>(& +M(*#C_O__ZPT``.I$0(WB!`"@X1$0H./^___K`S"@XT0PS>4!`(3B$A"%X@0@ +MH./^___K!0"$XA80A>(&(*#C_O__ZZ@0E^4&`*#A!A"!XD0@C>()_O_K!@"@ +MX3;]_^L``*#CQ0(`Z@J`A>(-"X;B$0"`X@@0H.$&(*#C_O__ZP``4.,7```: +M1$"-X@0`H.$1$*#C_O__ZP,PH.-$,,WE`0"$X@80A>($(*#C_O__ZP4`A.(0 +M$(7B`B"@X_[__^L&`*#A!Q"@X00@H.$G_?_K"`"@X:@0E^4&(*#C_O__ZP`` +MH..E`@#J1$"-X@0`H.$1$*#C_O__ZP,PH.-$,,WE`0"$X@80A>($(*#C_O__ +MZP4`A.(*$(7B!B"@X_[__^L&`*#A!Q"@X00@H.$/_?_K``"@XY$"`.H$,-7E +M!@!3XP(``!H%,-7E!`!3XP,```I,"I_E_O__ZP``X..'`@#J`@!4XP0```H# +M`%3C'```"@$`5.-^`@`:?P(`Z@@`A>(-&X;B$1"!X@8@H./^___K1$"-X@0` +MH.$1$*#C_O__ZP0PH.-$,,WE`0"$X@\0A>("(*#C_O__ZQ$PU>5',,WEJ!"7 +MY08`H.$&$('B!""@X:K]_^L&`*#AU_S_ZP``H.-F`@#J1$"-X@0`H.$1$*#C +M_O__ZP0PH.-$,,WE`0"$XAD0A>("(*#C_O__ZQLPU>5',,WE!@"@X0<0H.$$ +M(*#ATOS_ZQ(`A>*H$)?E!B"@X_[__^L``*#C4`(`Z@``6.-+`@`*`@!4XP(` +M``H#`%3C1P(`&A0``.I$0(WB!`"@X1$0H./^___K!#"@XT0PS>4!`(3B!A"( +MX@(@H./^___K"3#8Y46H$)?E!@"@X080@>($(*#A>/W_ZP8`H.&E_/_K +M``"@XS0"`.I$0(WB!`"@X1$0H./^___K!#"@XT0PS>4!`(3B`Q"(X`(@H./^ +M___K"##8Y44&`*#A!Q"@X00@H.&@_/_K``"@XR("`.J(%`;CB`,&XP$` +M4^$``%,1?`$`&@Z`A>("`%3C"0``"@,`5./6```*`0!4XQ,"`!H",-CE`R#8 +MY0(DD^$``*`#`0"@$Q`"`.H",-CE`R#8Y0(DD^&B```:`3#8Y1D`4^,)`%,3 +M!0(`&B0]`^,#,);G``!3XX$```H(4(WB!C"(X@0@V.4%$-CE`22"X0-`H.&R +M+[_F!Q$/_F!!"!X@%`A.`$$&/@`@!1X?#__[HH``#J``!4XR8```H",-3E`V#4 +MY09D@^&V;[_F=F#_Y@PPAN(H`%/C`P``FJ@'G^7^___K``#@X]T!`.H,`(7B +M!!"$X@8@H.'^___K!P"@X000H.$$((;B^_S_ZP``4.,#``"J=`>?Y?[__^L` +M`.#CSP$`Z@0PV.4%(-CE`C2#X;,_O^9S,/_F!#!#X@,P9N"S/[_F4/,(/B`3#%Y0@PAN*S/[_F4C-*#A`S#%Y8$V"./_/T_CM##%X:@0E^4&`(7B!A"!X@8@H./^___K +MJ("7Y0(PU>4#8-7E!F2#X01@AN)4,)?E``!3XP`PH!.@()<%G#"7!0(P8P`# +M`%;A`P``VK0&G^7^___K``#@XYX!`.H.0(CB!P"@X080H.'^___K%'"(X@0P +MU.4%(-3E`B2#X;(OO^8&`(?@!Q"@X7(@_^;^___K!##4Y04@U.4"-(/ALS^_ +MYG,P]N:S/[_F($`*#A$1"@X_[__^L%,*#C1##-Y0$`A.("$(CB`B"@ +MX_[__^L#`(3B!1"@X08@H./^___KJ!"7Y08`H.$&$('B!""@X9;\_^L&`*#A +MP_O_ZR0]`^,#,);G``!3XT\!`!KT/`/C`S"6YP``4^-+`0`*J`"7Y?,=AN(& +M`(#B.!"!X@8@H./^___K``!0X_0\`P,#`(8'0@$`"D`!`.H!,-CE!P!3XP`@ +MH!,!(*`#!P!3XV4`4Q-_```:)#T#XP,PEN<``%/C:0``"@8PB.($$-CE!0#8 +MY0`4@>$#0*#AL1^_YG$0_^8+``#J`L#4Y0,`U.4!X-3E`Y0;DCN!^X/_F +M$0Y>XP<```H,!(#@<`#_Y@0`@.(`0(3@!`!CX`$`4.'P__^Z`0``Z@``5.,# +M```:I`2?Y?[__^L``.#C&`$`Z@)@U.4#,-3E!F2#X'9@_^8!,-3E`!#4Y0$4 +M@^!Q$/_F!P!6XP`PH(,!,*"3$0Y1XP$P@Q,``%/C!```"EP$G^4&$*#A_O__ +MZP``X.,$`0#J!*"@X000H.&T`/'AL`^_YG``_^:&,0CC`P!0X0D```H``%+C +M`!``XP`00.,`,`#C`#!`XP,0H`$4!)_E_O__ZP``X./R``#J!0"@X0(0@>(& +M(*#C_O__ZP@`5N,$4*"#`%"@DP<`H.$%$(3@#"!EX@W\_^L``%#C`P``JM0# +MG^7^___K``#@X^$``.H$,-CE!2#8Y0(D@^&R+[_F##!%XG(P\^:S/[_F/3``#:"#!&XK,_O^9S,/_F`C#$Y2,TH.$#,,3E +M``"@X\P``.KT/`/C`S"6YP``4^,#```:9`.?Y?[__^L``.#CQ```ZO,=AN(% +M`*#A.!"!X@8@H./^___K!2"@X_0\`^,#((;G``"@X[H``.H",-CE`R#8Y0(D +MD^&S```*1$"-X@0`H.$1$*#C_O__ZP4PH.-$,,WE`0"$X@(0B.("(*#C_O__ +MZP,`A.(&$(7B!B"@X_[__^L&`*#A!Q"@X00@H.$@^__K!@"@X1'[_^L``*#C +MH```ZH@>".,!`%/A!@``&@(`4N.8``"*`#``XP`P0.,$,8/@&`"3Y98``.KB +M'PKCX@X*XP$`4^$``%,1!@``&@(`4N.,``"*`#``XP`P0.,$,8/@)`"3Y8H` +M`.J&+0WC`@!3X80``!I0,)?E#C!#XB@`4^,#``"*5`*?Y?[__^L``.#C?P`` +MZ@Z`A>("`%3C!P``"@,`5.-M```*`0!4XW4``!H`,-7E`0`3XW0``!IQ``#J +M"*"(X@H`H.$4$I_E$""@X_[__^L``%#C;```"D1`C>($`*#A"A"@X($(*#AI/O_ZP8`H.'1^O_K!C#8Y3H`4^->```:4!"7Y3H` +M4>-;``":J`"7Y3800>(-2X;B$4"$XC8P\.6%`%/C#```&@<`4>-2``#:"`"` +MX@@00>(!(*#C`C"@X=_Y_^L``%#C2P``"@00H.$&(*#C_O__ZUT``.J&`%/C +M#```&@\`4>-#``#:$`"`XA`00>(!(*#C`C"@X=#Y_^L``%#C/```"@00H.$& +M(*#C_O__ZTX``.J'`%/C#```&A<`4>,T``#:&`"`XA@00>(!(*#C`C"@X<'Y +M_^L``%#C+0``"@00H.$&(*#C_O__ZS\``.J(`%/C#```&A<`4>,E``#:&`"` +MXA@00>("(*#C`3"@X[+Y_^L``%#C'@``"@00H.$&(*#C_O__ZS```.J)`%/C +M&```&B<`4>,6``#:*`"`XB@00>("(*#C`3"@XZ/Y_^L``%#C#P``"@00H.$& +M(*#C_O__ZR$``.I$0(WB!`"@X1@0B.)K^O_K!@"@X0<0H.$$(*#A@/K_ZP`` +MH.,"``#J``#@XP```.H``*#C7-"-XO"%O>@``%7C:?W_&JG]_^JL`P``S`,` +M`#03``#P`P``)`0``%`$``!L!```H`0``,@$```0!0``.`4``'`%``"8!0`` +MS`4```@&``!H$P``J%"7Y390A>(`8*#CLF#%X;1`V.$%`*#A!!"@X08@H.'^ +M___K-"^_Y@``C>4*`*#A&!"(XCHTH./^___K8#B`X`,PX.$C.*#ALC#%X08` +MH.'5___J\$$MZ0!0H.$!0*#AJ#"1Y0`@T^4!`!+C>@``&KP@T^&!`%+C`'"@ +M$P=@H!$-```:OG#3X0XPH.,#`.#CJ""4Y0,0@N"P$)'ALQ""X0(P0^("`%/C +M^/__&@0`H.$$$*#C_O__ZP%@H.,8/0/C`S"5YP``4^,P```:_O__ZPT@H.%_ +M/<+C/S##XP0@D^4!((+B!""#Y3`]`^,#,)7G``!3XQ@``!JH@)3EO##8X0@` +M4^,4```:/0R%X@0`@.(>$(CB!""@X_[__^L``%#C#0``&O,=A>((`*#A/A"! +MX@8@H./^___K#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__ZP!0H.,I``#J +M#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__ZP4`H.$$$*#A`R"@X_[__^L` +M4*#A'```ZJ@0E.6\,-'A"`!3XP<``!H]#(7B$@"`XAX0@>($(*#C_O__ZP`` +M4.,*```*#P``Z@@F`.,"`%/A#```&CT,A>(2`(#B)A"!X@0@H./^___K``!0 +MXP4``!H%`*#A!!"@X0,@H./^___K`%"@X0```.H`4*#C``!6XQ````H$`*#A +M!!"@X_[__^L`,*#C!`"@XZ@@E.4#$(+@L!"1X;,0@N$",(/B#`!3X_C__QJH +M,)3E@2"@X[P@P^&H,)3EOG##X0$`=>,``.`#\(&]"```H./P@;WH\$\MZ130 +M3>(`<*#A_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B!""#Y?,]A^(^((/B#""- +MY3TLA^($((+B"""-Y?*=A^(TD(GB-#"#X@0PC>4(C0/C`*"@XRRPH./88)_E +M`$"9Y0``5.,F```*`%"4Y0`PEN5U/$/B%""4Y0,P8N`P`%/C'```2@@PA.*? +M+Y/A`2!"XI(?@^$``#'C^O__&@``4N,4```:"#"7YP0`4^$&```:#`"=Y080 +MH./^___K"`"=Y000H./^___K"*"'YPP`E.@`((/E`#"4Y0``4^,$()05!""# +M%0"@A.4$H(3E!`"@X0L0H.'^___K``!5XP5`H!'8__\:!)")X@0PG>4#`%GA +MT?__&@T@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^L4T(WB\(^]Z`````#P +M3RWI#-!-X@!@H.'^___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/E\[V&XCXP +MB^($,(WE/2R&X@0@@N(`((WE\IV&XC20B>(TL(OB"'T#XP"`H.,LH*#C`$"9 +MY0``5.,8```*`%"4Y04&$*#C_O__ZP``G>4$$*#C +M_O__ZP>`AN<,`)3H`""#Y0`PE.4``%/C!""4%00@@Q4`@(3E!("$Y00`H.$* +M$*#A_O__ZP``5>,%0*`1YO__&@20B>(+`%GAX/__&@T@H.%_/<+C/S##XP0@ +MD^4!($+B!""#Y?[__^L,T(WB\(^]Z`(,4>,``*`C'O\O(0`P`.,`,$#C`##3 +MY0``4^,&```:`#``XP`P0.,!$(/@!##1Y0`PPN4!`*#C'O\OX0```.,``$#C +M`3!#XH,$@.`!$(#@!#+1Y0`PPN4!`*#C'O\OX0(,4>,``*`C'O\O(0`P`.,` +M,$#C`##3Y0``4^,%```:`#``XP`P0.,!$(/@!"#!Y0$`H.,>_R_A````XP`` +M0.,!,$/B@P2`X`$0@.`$(L'E`0"@XQ[_+^$00"WIK#L#XP_@H.$#\)#G$("] +MZ!!`+>FX.P/C#^"@X0/PD.<0@+WH`#"@X0$`(.(!``#B`@`3XP$`@`)P`.\& +M!``3XP$`@`)P`.\&"``3XP$`@`)P`.\&'O\OX03@+>4,T$WB%,#=Y1#@G>4` +MX(WE!,"-Y;#+`^,/X*#A#/"0YPS0C>(`@+WH!.`MY0S03>(0P-WE`,"-Y;3+ +M`^,/X*#A#/"0YPS0C>(`@+WH$$`MZ;S+`^,/X*#A#/"0YQ"`O>@$X"WE#-!- +MXA#`W>4`P(WE[\V@XP_@H.$,\)#G#-"-X@"`O>@$X"WE#-!-XA#`W>4`P(WE +MR,L#XP_@H.$,\)#G#-"-X@"`O>@!`!#C`##1!0`PP@4!,-$%`3#"!0(`$.," +M,-$%`C#"!0,PT04#,,(%!``0XP0PT04$,,(%!3#1!04PP@4(`!#C!C#1!08P +MP@4',-$%!S#"!1[_+^$$X"WE#-!-XA#`W>4`P(WEQ,L#XP_@H.$,\)#G#-"- +MX@"`O>CP3RWI%-!-X@!@H.$!L*#A`D"@X0.@H.$XD)WE`%"@X[Y0S>&\4,WA +M`%"-Y040H.$!(*#C#C"-XO[__^L`4(WE!@"@X040H.$#(*#C##"-XO[__^N^ +M,-WA!`!3X2D``#H!`%OC`(``$P"`0!,%```:!""*X+PPW>$#`%+A(0``R@"` +M`.,`@$#C!@"@X0L0H.$!(*#C_O__ZP``6N,3``#:OC#=X00`4^$`4*"#!0`` +MB@X``.H!0(3B=$#_YKXPW>$$`%/A"0``F@8`H.$$$*#A!2")X#C_+^$`<%#B +M!```"@%0A>(*`%7A\?__N@```.H`<*#C!@"@X0L0H.$`(*#C_O__ZP```.H` +M<*#C!P"@X130C>+PC[WH!.`MY1303>(`$*#C`!"-Y0,@H.,.,(WB_O__Z[X` +MW>$4T(WB`("]Z'!`+>D`0*#A`5"@X0`0H.,!(*#C_O__ZP0`H.$`$*#C`2"@ +MX?[__^NP`,7A!`"@X0`0H.,!(*#A_O__ZP$`H.-P@+WH\$`MZ1303>(`8*#A +M`5"@X0)`H.$#<*#A`!"@XQ`PC>*R$&/A`!"-Y00@H./^___K!2"$X+XPW>$# +M`%+A``"@PQ```,H&`*#A`!"@XP$@H./^___K`'"-Y0!PH.,$<(WE!@"@X0<0 +MH.$%(*#A!#"@X?[__^L&`*#A!Q"@X0<@H.'^___K`0"@XQ30C>+P@+WH\$`M +MZ1303>(`8*#A`5"@X0)`H.$#<*#A`""@XQ`PC>*R(&/A`""-Y0$0H.,$(*#C +M_O__ZP4@A."^,-WA`P!2X0``H,,0``#*!@"@X0`0H.,!(*#C_O__ZP!PC>4` +M<*#C!'"-Y08`H.$!$*#C!2"@X00PH.'^___K!@"@X0<0H.$'(*#A_O__ZP$` +MH.,4T(WB\("]Z/!%+>D4T$WB`&"@X0&`H.$"H*#A`W"@X0!`H.,04(WBLD!E +MX000H.$!(*#C_O__ZP!PC>4&`*#A"!"@X00@H.,%,*#A_O__Z[XPW>$`H(WE +M!'"-Y08`H.$($*#A!""@X?[__^L&`*#A!!"@X00@H.'^___K%-"-XO"%O>@! +M`%'C!0``&@(@@.`-*X+B&"""X@,@TN4`(,/E'O\OX0(`4>,*```:`B"`X`T; +M@N(8$('B`Q#1Y;`0P^$-*X+B&2""X@,@TN4"%('AL!##X1[_+^$$`%'C'O\O +M$0(`@.`-*X#B&"""X@,0TN4`$(/E#2N`XAD@@N(#(-+E`A2!X0`0@^4-*X#B +M&B""X@,@TN4"*('A`""#Y0T+@.(;`(#B`Q#0Y0$L@N$`((/E'O\OX1[_+^'P +M02WI`$``XP!`0.,$`(3B_Q"@XP(LH./^___K`@N$X@0`@.+_$*#C`2R@X_[_ +M_^L)#(3B!`"`XO\0H.,!+*#C_O__ZPI,A.($0(3B!ER$X@)LH./_<*#C!`"@ +MX080H.$'(*#A_O__ZP),A.(%`%3A^/__&@!``.,`0$#C_PY$X@0`0.+_$*#C +M`2N@X_[__^N_#D3B!`!`XO\0H.,!*Z#C_O__ZU1`G^4&7(3B_V"@XP)\H.,$ +M`*#A!A"@X0<@H.'^___K`DR$X@4`5.'X__\:`$``XP!`0.-_#D3B!`!`XO\0 +MH.,!*Z#C_O__Z_T/1.+_$*#C`2N@X_[__^OP@;WH6!8``'!`+>D0T$WB`$"@ +MX0%@H.$"4*#A$#"-X@`@H..R(&/A`%"-Y00@H./^___K$#0#XP,PU.'^___K!0``Z@0`H.$&$*#A#2N$XAL@@N(% +M,*#A_O__ZQ#0C>)P@+WH\$\MZ3303>(`L*#A`6"@X0)0H.$#D*#A`""@XS`P +MC>*Z(&/A`""-Y0$0H.,$(*#C_O__ZQQ@C>6V`MWA!C"%X```4^&-``#*_O__ +MZP``4.,8`(WEB0``"@L`H.$`$*#CMB+=X1@PG>7^___K`'!0XGX```H+`*#A +M`1"@XP$@H.'^___KUF'GYR@`C>+_$*#C"""@X_[__^L<`)WE!S``X@$`$.,` +M0*`##R"@`U(```H<`)WE`!#9Y1C`G>4`(-SG`@!1X0\@H`,+```*PR"@X0$0 +MH.,1(N#A#R`"XC#@C>(#$([@&,"=Y0``C.`!`%#E"0!!Y0``V>4(`$'E`3"# +MX@%`H.,\``#J!0!4X3X```H%$&3@`0!1XQ(``!H$`-GG'."=Y0X0A.`8X)WE +M`<#>YP``7.$)```*P\"@X0'@H.,>+,+A,,"-X@,PC.`(`$/E&."=Y0$0CN`! +M$-'E!Q!#Y0%`A.(H``#J!,"@X000V><<`)WE``"$X!0`C>48X)WE`.#>YP$` +M7N$-```:!`")X`P`C>48X)WE%`"=Y0#@CN`4X(WE#."=Y0'@WN4,X(WE%."= +MY0$`WN4,X)WE``!>X0@```K#`*#A`>"@XQX@PN$PX(WB`P".X`@00.4,P(G@ +M`1#(`H*#C!P!3X[[__]H/ +M`%+C!P``"@"@C>4+`*#A!A"@X0@PH.'^___K<'#OY@``5^,*```*!0!4X0@` +M``H!8(;B=F#OY@@`H.'_$*#C"""@X_[__^L*,*#A#R"@X^C__^H+`*#A`1"@ +MXP`@H./^___K&`"=Y;82W>'^___K````Z@!PH.,'`*#A--"-XO"/O>CP3RWI +M--!-X@"PH.$!8*#A`E"@X0.0H.$`$*#C,#"-XKH08^$`$(WE!""@X_[__^L< +M8(WEM@+=X08PA>```%/AC0``RO[__^L``%#C&`"-Y8D```H+`*#A`!"@X[8B +MW>$8,)WE_O__ZP!P4.)^```*"P"@X0$0H.,!(*#A_O__Z]9AY^48P)WE +M`"#$/(*`#"P``"L,@H.$!$*#C$2+@X0\@`N(PX(WB`Q".X!C`G>4` +M`(S@`0!0Y0D`0>4``-GE"`!!Y0$P@^(!0*#C/```Z@4`5.$^```*!1!DX`$` +M4>,2```:!`#9YQS@G>4.$(3@&."=Y0'`WN<``%SA"0``"L/`H.$!X*#C'BS" +MX3#`C>(#,(S@"`!#Y1C@G>4!$([@`1#1Y0<00^4!0(3B*```Z@3`H.$$$-GG +M'`"=Y0``A.`4`(WE&."=Y0#@WN`,`(WE&."=Y10`G>4` +MX([@%."-Y0S@G>4!X-[E#."-Y13@G>4!`-[E#."=Y0``7N$(```*PP"@X0'@ +MH.,>(,+A,."-X@,`CN`($$#E#,")X`$0W.4'$$#E`D"$X@0`5>$",(,2`@`` +M&@,``.HH@(WB`*"@XP<`4^.^___:#P!2XP<```H`H(WE"P"@X080H.$(,*#A +M_O__ZW!P[^8``%?C"@``"@4`5.$(```*`6"&XG9@[^8(`*#A_Q"@XP@@H./^ +M___K"C"@X0\@H./H___J"P"@X0$0H.,`(*#C_O__ZQ@`G>6V$MWA_O__ZP`` +M`.H`<*#C!P"@X330C>+PC[WH<$`MZ0!0H.$!0*#A`F"@X0``4^,!```*_O__ +MZW"`O>@Q$*#C="#OYO[__^L%`*#A,A"@X_[__^M41.'G_"``X@4`H.$R$*#C +M!"""X?[__^L%`*#A,!"@XP8@H.'^___K!0"@X3,0H./R(*#C_O__ZP!`H.,S +M8*#C`0``Z@%`A.)T0._F!0"@X080H.'^___K@``0XP$```ID`%3C]O__&F,` +M5.,``*"#`0"@DW"`O>@00"WI`"#2Y0`PH./^___K$("]Z/!!+>D`4*#A`4"@ +MX0)PH.$``%/C`0``"O[__^OP@;WH,1"@XW0@[^;^___K!0"@X3(0H./^___K +M5$3AY_P@`.(%`*#A,A"@XP0@@N'^___K!0"@X3,0H.-R(*#C_O__ZP!`H.,S +M8*#C`0``Z@%`A.)T0._F!0"@X080H.'^___K@``0XP(``!ID`%3C]O__&@<` +M`.IC`%3C!0``B@4`H.$P$*#C_O__ZP``Q^4!`*#C\(&]Z``PX.,`,,?E``"@ +MX_"!O>@00"WI`#"@X_[__^L0@+WH<$`MZ1#03>(`4*#A`4"@X0)@H.$`$*#C +M$#"-XK(08^$`$(WE`2"@X_[__^N^,-WA!`!3X2<``)H%`*#A,!"@XP8@H.'^ +M___K!0"@X3$0H.-T(._F_O__ZP4`H.$R$*#C_O__ZU1$X>?\(`#B!0"@X3(0 +MH.,$((+A_O__ZP4`H.$S$*#C_O__ZX`LX.&B+.#A!0"@X3,0H.-R(._F_O__ +MZP4`H.$S$*#C_O__ZP!`H.,S8*#C!0``Z@4`H.$&$*#A_O__ZP%`A.)D`%3C +M`0``"H``$./W__\:$-"-XG"`O>AP0"WI$-!-X@!0H.$!0*#A`!"@XQ`PC>*R +M$&/A`!"-Y0$@H./^___KOC#=X00`4^'_`*"3)```F@4`H.$Q$*#C="#OYO[_ +M_^L%`*#A,A"@X_[__^M41.'G_"``X@4`H.$R$*#C!"""X?[__^L%`*#A,Q"@ +MX_[__^M_(`#B!0"@X3,0H./^___K!0"@X3,0H./^___K`$"@XS-@H.,%``#J +M!0"@X080H.'^___K`4"$XOH/5.,!```*@``0X_?__PH%`*#A,!"@X_[__^L0 +MT(WB<("]Z/!!+>D`4*#A`4"@X0*`H.$``%/C`0``"O[__^OP@;WH,1"@XW0@ +M[^;^___K!0"@X3(0H./^___K5$3AY_P@`.(%`*#A,A"@XP0@@N'^___K!0"@ +MX3,0H./^___K?R``X@4`H.$S$*#C_O__ZP4`H.$P$*#C_O__ZP``4.,.``"Z +M`$"@XS!@H.,/=P+C!0"@X080H.'^___K`4"$XG1`_^8'`%3A`#"@@P$PH),` +M`%#C`#"@LP``4^/S__\:,@"@X_[__^L%`*#A,!"@X_[__^L``,CE\(&]Z!!` +M+>E$.P/C`S"0YP``4^,0@+T(,_\OX1"`O>@00"WI2#L#XP,PD.<``%/C$("] +M"#/_+^$0@+WH$$`MZ3P[`^,#,)#G``!3XQ"`O0@S_R_A$("]Z!!`+>DT.P/C +M`S"0YP``4^,0@+T(,_\OX1"`O>@00"WI.#L#XP,PD.<``%/C$("]"#/_+^$0 +M@+WH$$`MZ2P[`^,#,)#G``!3XQ"`O0@S_R_A$("]Z!!`+>DP.P/C`S"0YP`` +M4^,0@+T(,_\OX1"`O>@00"WI`$"@X0`@H./A.P/C`R#`YP@[`^,/X*#A`_"0 +MYP$`4.,!(*`#X3L#`P,@Q`<`(*`3X3L#$P,@Q!<0@+WH$$`MZ0!`H.$,.P/C +M#^"@X0/PD.ED.P/C`S"0YP``4^,0 +M@+T(,_\OX1"`O>@00"WI:#L#XP,PD.<``%/C$("]"#/_+^$0@+WH$-!-X@W` +MH.$/`(SH$-"-XA[_+^$``-WE``!0XP(`H!$&```:@``1XP,``!I_`%+C0`!2 +M$P(`H)$>_R^1?P`!XG\`4.-``%`3`P"@@1[_+^$[/*#C`Q"0YP`PH..%(P/C +M`C#`YQDJ`N,",,'G'O\OX0`PH.,#`-'G@``0XYX```I_``#B`@!`XFH`4.,` +M\9^7F0``ZB!``@#<0`(`,$`"`-Q``@#<0`(`W$`"`-Q``@#<0`(`W$`"`$!` +M`@!@0`(`W$`"`-Q``@#<0`(`W$`"`-Q``@!P0`(`W$`"`-Q``@#<0`(`4$`" +M`-Q``@"`0`(`W$`"`-Q``@#<0`(`W$`"`-Q``@#<0`(`W$`"`-Q``@#<0`(` +MW$`"`-Q``@"00`(`W$`"`-Q``@#<0`(`W$`"`-Q``@#<0`(`W$`"`-Q``@#< +M0`(`W$`"`-Q``@"@0`(`W$`"`-Q``@#<0`(`W$`"`-Q``@#<0`(`W$`"`-Q` +M`@#<0`(`W$`"`-Q``@#<0`(`W$`"`-Q``@#<0`(`W$`"`-Q``@#<0`(`W$`" +M`-Q``@#<0`(`W$`"`-Q``@"P0`(`W$`"`-Q``@#<0`(`W$`"`-Q``@#<0`(` +MW$`"`-Q``@#<0`(`W$`"`-Q``@#<0`(`W$`"`-Q``@#<0`(`W$`"`-Q``@#< +M0`(`W$`"`-Q``@#<0`(`W$`"`-Q``@#`0`(`W$`"`-Q``@#<0`(`W$`"`-Q` +M`@#<0`(`W$`"`-Q``@#<0`(`W$`"`-Q``@#00`(`L`#2X0$`@..P`,+A*@`` +MZK``TN$"`(#CL`#"X28``.JP`-+A!`"`X[``PN$B``#JL`#2X0@`@..P`,+A +M'@``ZK``TN$0`(#CL`#"X1H``.JP`-+A(`"`X[``PN$6``#JL`#2X4``@..P +M`,+A$@``ZK``TN&``(#CL`#"X0X``.JP`-+A`0R`X[``PN$*``#JL`#2X0(, +M@..P`,+A!@``ZK``TN$!"X#CL`#"X0(``.JP`-+A`@N`X[``PN$!,(/B$`!3 +MXUK__QH>_R_A!@!2XP+QGY<;``#J%$$"`"!!`@`X00(`1$$"`%!!`@!<00(` +M+$$"`$`@H.,`(,/E'O\OX0$LH..P(,/A'O\OX0$LH..P(,/A'O\OX>X@H..P +M(,/A'O\OX>X@H..P(,/A'O\OX0(LH..P(,/A'O\OX1(@H.,`(,/E'O\OX0`@ +MH.,`(,/E'O\OX08`4N,"\9^7&P``ZIQ!`@"H00(`P$$"`,Q!`@#800(`Y$$" +M`+1!`@!`(*#C`"##Y1[_+^$!+*#CL"##X1[_+^$!+*#CL"##X1[_+^'N(*#C +ML"##X1[_+^'N(*#CL"##X1[_+^$"+*#CL"##X1[_+^$2(*#C`"##Y1[_+^$` +M(*#C`"##Y1[_+^$00"WI",#=Y0``7.,!```*_O__ZQ"`O>C^___K$("]Z![_ +M+^$`,`#C`#!`XP@P@.4`,`#C`#!`XRPP@.4`,`#C`#!`XS`P@.4`,`#C`#!` +MXS0P@.4`,`#C`#!`XU`P@.4`,`#C`#!`XU0P@.4`,`#C`#!`XU@P@.4`,`#C +M`#!`XWPP@.4`,`#C`#!`XX`P@.4`,`#C`#!`XX0P@.4`,`#C`#!`XY0P@.4` +M,`#C`#!`XY@P@.4`,`#C`#!`XYPP@.4`,`#C`#!`XZ`P@.4`,`#C`#!`XZ0P +M@.4`,`#C`#!`XZ@P@.4`,`#C`#!`XZPP@.4`,`#C`#!`X[`P@.4`,`#C`#!` +MX[0P@.4`,`#C`#!`X[@P@.4`,`#C`#!`X[PP@.4`,`#C`#!`XVPP@.4`,`#C +M`#!`XW`P@.4>_R_AL"#1X2DQ".,#`%+A`2"@$P`@H`,0-`/C`R#`YQ[_+^$` +M`%+C!0``"@`PH./A(P/C`C#`YY,C`^,",,#G'O\OX0<_`N,#,-#G`@!3X\(@ +MT040(`("X3,#`P,@P`?A(P,3`C#`%\(@T>52(^#GDS,#XP,@P.<>_R_A.SR@ +MXP,PD.<``%+C(!"@$]PH`A,"$,,7'O\O$;D@T>7<&`+C`2##Y_\`4N,@$*`# +MW"@"`P(0PP<>_R_A.SR@XP,PD.<``%+CP2#1!:(BH`$`(*`30R##Y1[_+^$[ +M/*#C`S"0YP``4N,!(*`33B##%1[_+Q'$(-'E3B##Y?\`4N,`(*`#3B##!1[_ +M+^$[/*#C`S"0YP``4N/%(-$%3"##!0`@H!-,(,,532##%1[_+^$[/*#C`S"0 +MYP``4N,`$*`3V2@#$P(0PQ<>_R\1!2\"XP(@T.<"`%+CV0@#$P`@PQ<)```: +M`2"@X<'`\N7

'GV0@#XP#`P^<`(-+E_P!2XP``H`/9*`,#`@##!\D@T>7: +M&`/C`2##Y_\`4N,!$*`#VB@#`P(0PP<>_R_A.SR@XP,PD.<``%+C&""@$U$@ +MPQ4#```:NB#1Y5$@P^7_`%+C'O\O$0$@H.-2(,/E&""@XU$@P^4>_R_A'O\O +MX1!`+>D[/*#C`\"0YQPZ`N,#X)SG#D"!X0)`Q.$#0(SG51Z@XW0@[^;^___K +M$("]Z#!`+>D,T$WB`%"@X0@PC>(`(*#C`2!CY3LLH.,"0)#G`1"@X\(@H./^ +M___K!S#=Y1``$^,&```*-S,#XP,PU><``%/C`2"@$]XX`Q,#(,07`@``&@`@ +MH./>.`/C`R#$Y]XX`^,#`-3G#-"-XC"`O>@00"WI"-!-X@!`H.$``%'C_Q"@ +M`[@0T14#/P+C`S#0YP`@C>4#(*#A"C"@X_[__^M6!<3E"-"-XA"`O>CP3RWI +M3-!-X@@0C>4$((WE.SR@XP.PD.<0`(WB`!"@XS8@H./^___K!`"=Y0``4.,+ +M```:$,"-X@R`H.$,4*#A`#"@XQ`0H.,#8*#A#Y#@XP!`C>4,L(WE`["@X0A` +MG>63``#J$!"-X@%0H.$!`*#A`&"@XRT@H.,!D*#A`<#@XP)PH.,$H*#C!("@ +MX1L``.H#(,'G`T"`X`P@Q.4!,(/B!@!3X_G__QH&,8G@)C"#X@%`H.,!``#J +M`4"$X@$P@^(!`%3C)G#%!1Z@Q07Y__\*`,##Y0C`P^40P$/E",!#Y0,`5./S +M__^:`6"&X@80@>(%`(#B!%"%X@(`5N-U```*`#"@X^'__^H`<*#A`R#0YP,@ +MS.?_`%+C+2"@`P,@R@`,(,#E_P!2 +MXRT@H`,,(,`%`3"#X@%PA^(%`%/C]?__&@L0@>(0`(WB"S&`X"XP@^(&(*#A +M!*"@XP5PH.$``%+C%P``&BY@R.4!`(3@`%#0Y?\`5>,"4*`#)E#(!00```HE +M4J#A"%!#Y0@`%>,)4(41"%!#%0``T.7_`%#C$*!#!00```H/``#B$`!#Y0@` +M$.,)`(`1$`!#%1A@0^4!$('B*P``Z@$`A.``4-#E_P!5XP%0X`,`4,,%!``` +M"B52H.$`4,/E"``5XPE0A1$`4,,5``#0Y?\`4.,!`.`#"`!#!00```H/``#B +M"`!#Y0@`$.,)`(`1"`!#%0$0@>(!`(3@`%#0Y?\`5>,!4.`#$%!#!00```HE +M4J#A$%!#Y0@`%>,)4(41$%!#%0``T.7_`%#C`0#@`Q@`0P4$```*#P``XA@` +M0^4(`!#C"0"`$1@`0Q4!$('B`2""X@$P@^($`%+CM?__&@&PB^(%4(?B!L", +MX@2`B.("`%OC`P``"@8PH.$!`(3@#*"@X9#__^H`0)WE#+"=Y0$PH.-0,,OE +M````Z@A`H.%",-OE``!3XX(```H`P*#C#'"@X040H.,`$(WE$""-XAH@@N(, +M((WE<@``ZG(P[^8.`%/C$```B@(`4^,S``":!0!3XP%`H),Q``":"`!3XP)` +MH),N``":"P!3XP-`H),K``":#0!3XP1`H),H``":#@!3XW<``!I_``#J*`!3 +MXP=`H)$_``":,`!3XP%`H),\``":.`!3XP)`H),Y``":0`!3XP-`H),V``": +M:`!3XP1`H),S``":<`!3XV,``)IX`%/C80``FH``4^,&0*"3+```FH@`4^,' +M0*"3*0``FI``4^,(0*"3)@``FID`4^,)0*"3(P``FJ$`4^,*0*"3(```FK$` +M4^,+0*"3'0``Z@=`H.$,$*#A!&"@X0(`BN"178#B*%"%X@2`B>`X@%CE`(#% +MY0X`4^,*```:`3*@X8$P0^`#,(O@`B"#X)(M@N(!$8'@2#"-X@$0@^`H,%'E +M!##"Y0H``.J2#8#B!`"`X@$1@>!(4(WB`1"%X`80@>`L,%'E`##`Y0$@@N(/ +M`%+CI?__&A``C>(,,8#@%C"#XI(NC.((((+B`B&+X`P0G>4,`8'@`!#3Y0`0 +MPN4($-/E"!#"Y1`0T^40$,+E&!#3Y1@0PN4!,(/B`2""X@``4^'S__\:`<", +MXGS`[^9",-OE#`!3X0<``)H'(*#AC)"@X0RB:>`*H(O@#)")X$@PC>*)D(/@ +MA/__Z@1`G>4``%3C`#"@$T\PRQ4A```:"#"=Y<$@\^4'(`+B3R#+Y0`PT^7_ +M`%/C`#"@`T\PRP48``#J`$"=Y`X4%7E`%##Y;K__^H,$*#AC`"@X0PR8.`#,(O@`C"#X)$]@^(H,(/B#`"` +MX$A0C>*``(7@,P!0Y0``P^4%0*#CH?__ZDS0C>+PC[WH<$`MZ0!`H.$!4*#A +M$#0#XP,PT.<``%/C#```&AHT`^,#,-#G`0!3XW"`O0@`$*#C`2"@X?[__^L% +M`*#A#1N$XAL0@>("+*#C_O__ZW"`O>@:-`/C`S#0YP``4^,"```:`!"@XP$@ +MH.'^___K!0"@X0T;A.(;$('B`BR@X_[__^MP@+WH$$`MZ0!`H.$!+*#A(BB@ +MX1X>H.,"(8+C_O__ZP0`H.$>'J#C_O__ZR`_L.'_`*`3<`#O!A"`O>@00"WI +M`$"@X0$H.,!(8+C_O__ZP0`H.$>'J#C_O__ZP$`H.,0 +M@+WH\$$MZ0!@H.$!<*#A`!"@XP%01^(&``#J`4"!X@8`H.$$(*#A_O__ZP$` +M4./P@;T8!!"@X04`4>'V__\Z!@"@X040H.'_(*#C_O__ZP$`4./P@;T8!P`` +MZ@00H.$!0('B!@"@X00@H.'^___K`0!0XP0```KP@;WHKP!7XP<0H)'U__^: +M`0``ZK``5./Q__\:!@"@X;`0H.,'(*#A_O__Z_"!O>@00"WI"A"@X_[__^L0 +M``#B``!0XP8`H!,$`*`#$("]Z/!/+>D40`(WB_Q"@XP@@H./^___K`0`7XPJPH!$/H*`3)@``&@&0BN)YD/_F!`"@ +MX0H0H.$`(-CE!C"@X?[__^L!L(GB>[#_Y@2`C>4$`*#A"1"@X0@PH.$!(//E +M!#"-Y08PH.'^___K$%"-X@0`H.$*$*#A!2"@X08PH.'^___K!`"@X0D0H.$! +M((7B!C"@X?[__^L`(-CE$##=Y0,`4N$%```:!#"=Y0`@T^41,-WE`P!2X0^@ +MH`,````*#J"@XP(`%^,+D*`1*@``&@$PB^)S,/_F"`&-Z00`H.$+$*#A"#"@ +MX0(@\^4(,(WE!C"@X?[__^L$,)WE`9"#XGF0_^8,@(WE!`"@X0,0H.$(,*#A +M`R#SY0PPC>4&,*#A_O__ZQ!0C>($`*#A"Q"@X0(@A>(&,*#A_O__ZP0`H.$$ +M$)WE`R"%X@8PH.'^___K"#"=Y0`@T^42,-WE`P!2X00``!H,,)WE`"#3Y1,P +MW>4#`%+A````"OV@"N($`!?C";"@$2H``!H!,(GBD$`*#A"1"@ +MX0@PH.$$(//E"#"-Y08PH.'^___K!#"=Y0&P@^)[L/_F#("-Y00`H.$#$*#A +M"#"@X04@\^4,,(WE!C"@X?[__^L04(WB!`"@X0D0H.$$((7B!C"@X?[__^L$ +M`*#A!!"=Y04@A>(&,*#A_O__ZP@PG>4`(-/E%##=Y0,`4N$$```:##"=Y0`@ +MT^45,-WE`P!2X0````K[H`KB"``7XR```!H!D(OB>9#_Y@APH.$$`*#A"Q"@ +MX08@]^4&,*#A_O__ZP0`H.$)$*#A!R#XY08PH.'^___K$%"-X@0`H.$+$*#A +M!B"%X@8PH.'^___K!`"@X0D0H.$'((7B!C"@X?[__^L`(-?E%C#=Y0,`4N$# +M```:`"#8Y14#`%+A````"O>@"N(*`*#A'-"-XO"/O>@$X"WE#-!-XA#` +MW>4``%SC`,"@`P#`C>5`___K#-"-X@"`O>CP3RWI1-!-X@"@H.$($(WE`G"@ +MX0-@H.$`(*#C0#"-X@T@8^4`8(WE`A"@X?[__^L``%?CF@``"C,PW>4(()WE +M`@!3X98``#H'`*#A_Q"@XP@@H./^___K-`"-XO\0H.,((*#C_O__ZP"0H.,) +M4*#A#)"-Y0%`H.,_L(WB&)"-Y?^!`.,0D(WE`0`4XUT```H*`*#A!1"@X0L@ +MH.$&,*#A_O__ZP``4.-D```*/Y#=Y?\`6>-A```*'S`)X@\`4^,I0J`1#Y`) +M$A"0C140```:`5"%XG50_^8*`*#A!1"@X0L@H.$&,*#A_O__ZS\PW>4/(`/B +M#P!2XP%0A0)U4/\&3```"O`0`^*A0*#AJ4*$X1`@C>40`)WE_O__ZPP`C>4( +M,)WE`P!4X2\``!J`(*#A'""-Y0``4N,D``#:`)"@XQA`G>4!,*#C%#"-Y0,@ +MA>"P(LWA*%"-Y2QPC>4<<)WE()D(+@##!)Y10@G>7_`%/C`""@$Q0@C>4!0(3B +M=$#OY@20H.$'`%3AZO__NBA0G>4L<)WE%#"=Y0``4^,@0*`#&0``"@%0A>(, +M()WE@C"@X750\^9U4/_F`4"@XQ(``.H!4(7B#""=Y8(PH.%U4//F=5#_Y@%` +MH.,+``#J(``4XPD```H0`)WE-!"-X@<@H.'^___K`5"%X@P@G>6",*#A=5#S +MYG50_^8!0*#C"`!5X9'__YH`,-?E_P!3XQ<``!H!,-?E_P!3XQ0``!H",-?E +M_P!3XQ$``!H#,-?E_P!3XPX``!H$,-?E_P!3XPL``!H%,-?E_P!3XP@``!H& +M,-?E_P!3XP4``!H'`-?E_P!0X@$`H!,"``#J``"@XP```.H!`*#C1-"-XO"/ +MO>@00"WI``!3XP$```I-___K$("]Z``PH.-*___K$("]Z/!`+>D,T$WB`$"@ +MX0`PH..V,,WA`%!1X@0```H`,`#C`#!`X[`PT^&V,,WA(0``ZC<0H.,&((WB +M:#L#XP_@H.$#\)3G&P``Z@4`W>7_`%#C)```"A\@`.(/`%+C#P``$@X``!H! +M,(/B$$`*#A!B"@X04PH.'^___K!0#=Y0\P`.(/`%/C#P``$K8P +MW0$!,(,"MC#-`0<```K^___KMC#=X0$P@^*`,(/@MC#-X0$``.H%8(WB_W$` +MXP0`H.&V$-WA!B"@X04PH.'^___K``!0XP(```JV,-WA!P!3X=?__YH``%7C +M!```"@`P`.,`,$#CMB#=X0`@@^4%``#J!`"@X3<0H.,&((WB9#L#XP_@H.$# +M\)3GM@#=X0S0C>+P@+WH$$`MZ0`04N(!```*L?__ZQ"`O>@`$*#CKO__ZQ"` +MO>CP1RWI$-!-X@!PH.$!D*#A`D"@X0-@H.$P@-WEL*#3X0A0C>(%`*#A_Q"@ +MXP@@H./^___K!P"@X0`0U.4%(*#A"#"@X?[__^L``%#C&@``"@$0BN(!(-3E +M`("-Y0<`H.%Q$/_F"#"-XO[__^L`(*#A#P!0XPL```H`$-3E`("-Y0<`H.$( +M,(WB_O__ZP``4.,/```*!P"@X0D0H.$((*#A_O__ZP@``.H*`-3E@`"*X`$` +M@.)P`/_F`P``Z@H`U.6``(K@`0"`XG``_^:P`,;A`0"@XQ#0C>+PA[WH\$\M +MZ3S03>(`8*#A`8"@X0)PH.$#H*#A8%#=Y0!`H.,X,(WBL$%CX0!0C>4$$*#A +M`R"@X_[__^L&`*#A!!"@X04@H.'^___KN#+=X0``4^&9`0":+D"-X@0`H.'_ +M$*#C"""@X_[__^LL@,WE+7#-Y0<`H.$*$*#A!""@X?[__^LM`-WE_O__ZS8` +MS>4`0*#C*T#-Y;9"S>&R0LWAM$+-X0!0C>4&`*#A!!"@X0(@H.,B,(WB_O__ +MZP!0C>4&`*#A!!"@X0$@H.,D,(WB_O__ZP0`5>$,```*`#``XP`P0..P,-/A +M@SN@X:,[H.&V,LWAMA+=X;(RW>$!`%/A`""@@PP@C84+``"*:P$`Z@8`H.$W +M$*#C)B"-XF@[`^,/X*#A`_"6Y[8RW>&#.Z#AHSN@X;8RS>'M___J!@"@X2L@ +MC>(%,*#A_O__ZP``4.-U```**T#=Y?\`5.-R```*'S`$X@\`4^,DHJ`1#X`$ +M$A```!JV$MWA`1"!XG$0_^:V$LWA!@"@X2L@C>(%,*#A_O__ZRN`W>4(H*#A +M#S`(X@\`4^-%`0`*\*`(XJJ@H.&DHHKA`X"@X0@`H.'^___K`'"@X2PPW>4* +M`%/A3```&K:RW>$!L(OB>[#_YH"@H.$``%KC$@``V@"0H.,,0)WE"Q"$X`8` +MH.%Q$/_F*""-X@4PH.'^___K``!0XP(```HH,-WE_P!3XP&0H!,!0(3B=$#O +MY@H`5.'P__^Z``!9XS,``!HM,-WE`0`3XP(``!H!`!CC#D"@`P````H/0*#C +M`@`3XP$``!H"`!CC_4`$`@0`$^,!```:!``8X_M`!`((`!/C`0``&@@`&./W +M0`0"#P!4XQX```JV$MWA`1"!X@!0C>4&`*#A<1#_Y@0@H.$N,(WB_O__ZP`@ +MH.$/`%#C!@``"BP0W>4`4(WE!@"@X2XPC>+^___K``!0X_L```HM`-WE`#"@ +MXU0CH.$!`!+C`2"@`Q(#@`%P`.\&`3"#X@0`4^/W__\:+0#-Y?[__^LV`,WE +MMA+=X0$0@>*'<*#A<1#WYG$0_^:V$LWALC+=X0$`4^&$__^*Y```ZK:2W>$L +M,-WE#P!3XXP``)JTDLWA`$"@X[)"S>$H0,WE`%"-Y08`H.$$$*#A`B"@XR(P +MC>+^___K**"-XA2PC>)V``#J+(#=Y8B"H.$/@(CC>(#OY@8`H.$((*#A!3"@ +MX?[__^L&`*#AM!+=X0H@H.$%,*#A_O__ZRAPW>7_`%?C%0``&@,`5.-K``"* +M`4"$XG1`[^8#``#J!`!4XV8```H!0(3B=$#OY@8`H.&T$MWA"""@X04PH.'^ +M___K!@"@X;02W>$*(*#A!3"@X?[__^LH<-WE_P!7X^[__PH(`%?A20``&K02 +MW>$!$('B<1#_YK02S>$L@-WE>(`(XBTPW>6(@(/A!@"@X0@@H.$%,*#A_O__ +MZP8`H.&T$MWA"B"@X04PH.'^___K*##=Y?\`4^,5```:`P!4XS\``(H!0(3B +M=$#OY@,``.H$`%3C.@``"@%`A.)T0._F!@"@X;02W>$((*#A!3"@X?[__^L& +M`*#AM!+=X0H@H.$%,*#A_O__ZR@PW>7_`%/C[O__"@\0`^(/`%'C!P``&@,` +M5.,F``"*`4"$XG1`[^:T,MWA`3"#XK0RS>$9``#J`P!8X0$PH`,;```*\#`# +MXJ=RH.&C,(?A%##-Y2@`W>4/``#B%0#-Y?[__^L>`,WE`%"-Y08`H.$`$*#C +M"R"@X20PC>)^_O_K``!0XP4``!H+``#J'W`'X@\`5^.T,MT!`C"#`K0RS0&T +M$MWALC+=X0$`4^&$__^*`#"@X[22W>$_``#J`#"@XST``.H`,*#C*##-Y;*2 +MS>$L<-WE+3#=Y0=R@^%W<._F!@"@X0D0H.$'(*#A!3"@X?[__^L&`*#ALA+= +MX2@@C>(%,*#A_O__ZR@PW>7_`%/C`4"@`RB`C0($```*$```Z@0`5.,C```* +M`4"$XG1`[^8&`*#ALA+=X0<@H.$%,*#A_O__ZP8`H.&R$MWA"""@X04PH.'^ +M___K*##=Y?\`4^/N__\*!P!3X0$PH`,/```*(S*@X10PS>4H`-WE#P``XA4` +MS>7^___K'@#-Y0!0C>4&`*#A`!"@XQ0@C>(B,(WB-?[_ZP``4.,"```*`#"@ +MX[*2W>$```#J`#"@XP``4^,3```*`1")XBT@W>4`4(WE!@"@X7$0_^8N,(WB +M_O__ZP`@H.$/`%#C`0"@`PD```HX,(WB#!!SY0!0C>4&`*#A`C"#XO[__^L` +M`%#B`0"@$P```.H``*#C/-"-XO"/O>@$X"WE#-!-XA#`W>4``%SC`,"@`P#` +MC>5&_O_K#-"-X@"`O>@00"WI`$"@X3L\H.,#`)#G``!0XQ"`O0CE':#C_O__ +MZP`@H.,[/*#C`R"$YQ"`O>CP3RWI)-!-X@"@H.$,$(WE"""-Y10PC>5(D-WE +M``"@X[H!S>$!,(+@`@Q3XP(``-I,`Y_E_O__Z\\``.H"#*#C_O__ZP``4.,0 +M`(WER@``"D``H.,$$*#C`B"@X_[__^L`0*#A!`"-Y0``4..\```*`#"@XP`@ +MX.,#$)3GL"#!X0,0E.>R(,'A`Q"4Y[0@P>$#$)3GMB#!X00P@^(!#%/C]/__ +M&@H`H.$`$*#C'""-X@DPH.'^___K''#=Y?\`5^.G```*NC'=X0$P@^*Z,($@*#A'S`'X@\`4^,G,J`1#V`'$A\``!H*`*#A!1"@X0L@H.$) +M,*#A_O__ZQQ@W>4/,`;B#P!3XQ```!H!0(7B=$#_Y@H`H.$$$*#A"R"@X0DP +MH.'^___K'"#=Y?\P4N(!,*`3_P!4XP`PH(,``%/C3```"@%`A.)T4/_F0@`` +MZO`P!N*G)U4/_FNC'=X0$P@^*Z +M,6T((/A_P!5XV```(H*`*#A!1"@X0L@H.$),*#A_O__ZP%0 +MA>)U4/_FNC'=X0$P@^*Z,4`$*#C`>"@X0X` +M`.H!`)3GLP"0X0``PN4!`)3GLP"0X2`$H.$!`,+E`C"#X@(@@N((`%/C]/__ +M&@C`C.($$('B`0Q1XP(```H,(*#A#C"@X>W__^H(,)WE``!3XPL```H`,*#C +M$,"=Y0P`G>4`$(S@"`"=Y13`G>4#(-'G`R#,YP$P@^)S(/_F`@!0X?G__XH* +M`*#A-Q"@XQH@C>)D.P/C#^"@X0/PFN<+``#J!`"=Y4`0H.,$(*#C`C"@X_[_ +M_^L+``#J"@"@X040H.$+(*#A"3"@X?[__^N____J$`"=Y0(@H!@``!.`MY0S03>("$*#A`R"@X1`PG>44P-WE +M``!(`@+WH<$`MZ0!`H.$!4*#A`0!2XRT``!K/ +M$*#C:2"@X_[__^L$`*#A`!"@X_[__^L""1#C!0``&H`HX.&B*.#A!`"@X0`0 +MH.-R(/_F_O__ZP0`H.$"$*#C_O__ZP$*$.,$```:`2J`XP0`H.$"$*#C-P@+T8!`"@X3<0H./^___K#R``X@0`H.$W$*#CL"""X_[__^MP +M@+WHSQ"@XP`@H./^___K`0!5XW"`O1@$`*#A-Q"@X_[__^M_(`#B!`"@X3<0 +MH./^___K<("]Z!!`+>D`0*#A``!1XPX```J`$*#C_O__ZP$@@.,$`*#A@!"@ +MXW(@[^;^___K!`"@X8(0H./^___K]R``X@0`H.&"$*#C_O__ZQ"`O>B`$*#C +M_O__Z_X@`.($`*#A@!"@X_[__^L$`*#A@1"@XP`@H./^___K$("]Z'!`+>D` +M0*#A`Q"@X_[__^L`4*#A!`"@X0,0H./[(`7B_O__ZP0@A>,$`*#A`Q"@XW(@ +M[^;^___K<("]Z/!'+>D@T$WB`%"@X3L\H.,#0)#G\!"@X_[__^L"E2#BV9O@ +MY]"IX.=0AN/G4`S@YR``A.4%`*#A]!"@X_[__^L`<*#C&'"$Y04`H.%H$*#C +M_O__ZU`AX.<8,)3E`S""X0$G`.('`%+A`B"@$P<@H`$",(/A`24`X@<`4N$$ +M(*`3!R"@`0(P@^$8,(3ET`#@YQP`A.4<<,WE$("-Y12@C>4'4*#A&'"-Y0R0 +MC>4%8*#C"&"-Y1@PC>(#`)/H#3"@X0,`@^@(,(WB#P"3Z/[__^L4<,3E"("$ +MY0R@A.40<(3E0`*$Z`,PH.-!,,3E`3"@XT(PQ.4@T(WB\(>]Z'!`+>D[S*#C +M#$"0YZE-A.(00(3B`0!1XQ4```H"```Z`@!1XW"`O1@7``#J`E"@X0``4^,( +M```*!`"@X3`0H..X+=+A!3"@X?[__^L$`*#AV!#5Y?[__^MP@+WH!`"@X3`0 +MH..X+=+A`#"@X_[__^MP@+WH!`"@X2<0H./_(`/B`#"@X_[__^MP@+WH!`"@ +MX2@0H./_(`/B`#"@X_[__^MP@+WH\$\MZ0S03>(`<*#A`!"-Y0*0H.$$$(WE +MG:((XY>C1>.:,HK@*J.PX0$`H`,/```*`%"=Y0%*H.,`8*#CQ("@XP<`H.$$ +M$*#A"""@X04PH.'^___K``!0XS$```H!8(;BQ$"$XL10A>(*`%;A\___&IVR +M"..7LT7CFSF+X"NSH.'$,*#CDYMKX```6^,D```*DPH)X*N!L.$0```*`4J) +MX@0PG>4)4(/@`&"@XPB@H.,'`*#A!!"@X0H@H.$%,*#A_O__ZP``4.,5```* +M`6"&X@A`A.((4(7B"`!6X?/__QH'8!OB#@``"HB!B>`!6HCB`$"@XP`PG>4( +M@(/@!P"@X040H.$$(-CG_O__ZP``4.,#```*`4"$X@%0A>(&`%3A]?__&@S0 +MC>+PC[WH\$$MZ0!`H.$!4*#A`F"@X0-PH.&"$*#C_O__ZP<@P.,'4`7B!2"" +MX00`H.&"$*#CDDT$WB +M`&"@X3L\H.,#4)#G#`"@X_[__^L8`(WE``!0XP!PH`.M```*`2"@XP`@@.4` +M0`#C`$!`XP1`@.64*0/C"""`Y;0@U.&V(L7A!C#4Y;HRQ>&P,-3AO#+%X;`@ +MU.'P/P_C`#!`XP,P`N#`*`CCP!()XP(`4^$!`%,1!@``"B,,4^,$```*X"@( +MXP(`4^&4*0,3#""-%0(``!H@0(3B=#D#XPPPC>4&`*#A@!"@X_[__^N``!#C +M!0``"@8`H.&`$*#C`""@X_[__^L&`*#A_O__ZP8`H.$!$*#CT_[_Z_[__^L( +M`(WE#""=Y2*&H.$(-H3@'#"-Y0`@H.,4((WE@)"@XSN\H./T.0#C`#!`XPP@ +MG>4#,`+@$#"-Y01`C>4!JJ#C!@"@X0D0H.'^___K!""`XP8`H.$)$*#A((`%3A]/__&@!PH.$0 +M,)WE``!3XPH```H&`*#A"!"@X1P@G>5^___K`'"@X00``.H&`*#A!!"=Y0P@ +MG>4M___K`'"@X0$`5^,!```:"P``Z@!PH.$(`)WE_O__ZWT/4./,___:%""= +MY0,`4N,[```*`3""XG,P[^84,(WEQ?__Z@8`H.$`$*#CA?[_ZP!`H..`4*#C +MZ8,`XP8`H.$%$*#A_O__ZP0`$.,#```:`4"$X@@`5.'W__\:(P``ZOH/5.,A +M```J!@"@X8`0H./^___K`B"`XP8`H.&`$*#C0"#"X_[__^L&`*#A`Q"@X_[_ +M_^L`0*#A!@"@X0,0H./[(`3B_O__ZP0@A.,&`*#A`Q"@XW(@[^;^___K`$"@ +MXX!0H.,%@*#C!@"@X040H.'^___K0``0XPP``!H(`*#A_O__Z_H/5.,!0(02 +M]?__&@!PH.,%``#J!P"@X230C>+PC[WH!@"@X0`0H.--_O_K&`"=Y0P0H./^ +M___K]?__Z@$`$.,`,*`3!@``&@$PH.,P(Z#A`0`2XP(``!H!,(/B(`!3X_G_ +M_QH#`*#A'O\OX1[_+^$$0"WE.\R@XPP`D.<.#%'C!@``&I7%`N,,P-#G#,.` +MX);-C.(8P(SB`#",Y1@``.H$S@#C#`!1X0H``!J5Q0+C#,#0YPS#@."6S8SB +M',",X@`PC.5LR`#C#`!1X0#`H!,!P*`#%P``Z@C.`.,,`%'A!P``&I7%`N,, +MP-#G#,.`X);-C.(PP(SB`#",Y0#`H.,5``#J;$@`XP0`4>$`P*`3`<"@`P$, +M$.4>,&```:E44" +MXP1`T.<$0X#@EDV$XB!`A.(`,(3E$P``ZA1.`.,$`%'A!@``&I5%`N,$0-#G +M!$.`X)9-A.(D0(3B`#"$Y1,``.H83@#C!`!1X08``!J510+C!$#0YP1#@."6 +M383B*$"$X@`PA.42``#J'$X`XP0`4>$&```:E44"XP1`T.<$0X#@EDV$XBQ` +MA.(`,(3E$@``ZH,.4>,&```:E44"XP1`T.<$0X#@EDV$XCA`A.(`,(3E$@`` +MZC1(`.,$`%'A!@``&I5%`N,$0-#G!$.`X)9-A.(\0(3B`#"$Y0@``.HX2`#C +M!`!1X04``!J510+C!$#0YP1#@."7383B$$"$X@`PA.7_`%+C`""@$P$@#`(` +M`%+C!0``"I4E`N,"(-#G`B.`X)$&```:E24"XP(@T.<"`X#@EPV` +MX@0`@.(`,(#E%0``ZDPH`.,"`%'A!@``&I4E`N,"(-#G`@.`X)<-@.((`(#B +M`#"`Y0L``.IH*`#C`@!1X0@``!J5)0+C`A#0YP$3@."7'8'B#!"!X@`P@>4" +M,-#G`3"#X@(PP.<0`+WH'O\OX0$`H.,>_R_A`0"@XQ[_+^$!$$'B!P!1XP

('`%'C!P#@@P`P`),`,$"3`1&#D"``D96B`(#@'O\OX?!!+>D`0*#A +M`8"@X3L\H.,#4)#G`1"@XX4U`N,#(-7G_O__ZP!PH.&&-0+C`V#5YX0U`N,# +M(-7G`B"&X`0`H.$"$*#CDPT$WB.\R@XPP`D.(24(7BL&0"XP:@@>"2C8'B +M-("(XI)-@>($4(WE``!4`D,+EJ)0"XPF0T.<$ +M4-3E#Y`)X@F0A>``D,/E!I#0YP10U.4/D`GB"9"%X%!0G>4`D,7E!)#4Y52P +MG>4`D,OEA@``Z@$`7.,;```:D9V!XC:0B>(`D-GE`9#"Y0"PVN4/L`OB&+#- +MY0"PV.4/D`OB&+#=Y0E0B^`$D-3E"9"%X`&0P^6T5`+C!9#0YP!0V.4$L-3E +M*9*+X"62B>!04)WE`9#%Y9*=@>(.D(GB!)#9Y52PG>4!D,OE:```Z@(`7.,K +M```:DIV!X@20B>(`D-GE`I#"Y0"PVN4/L`OB&+#-Y0"PV.4/D`OB&%#=Y0F0 +MA>"2O8'B.+"+X@10U.4%D(G@&)#-Y0"0V^4/D`GB()#-Y1A0W>4)4(7@+%"- +MY0)0P^4`D-KE&)"-Y0"0V.4IDJ#A&%"=Y252B>`84,WE`+#;Y2RPC>4$L-3E +M"Y"%X"Q0G>4EDHG@4+"=Y0*0R^62G8'B')")X@20V>544)WE`I#%Y3H``.H# +M`%SC.```&@2PG>4`D-OE`Y#"Y0"PVN4/L`OB&+#-Y0"PV.4/D`OB&%#=Y0F0 +MA>"2O8'B.+"+X@10U.4%D(G@+)#-Y0"0V^4/D`GB()#-Y9)=@>(\4(7B&%"- +MY0"0U>40D,WE+)#=Y2!0W>4%4(G@(%#-Y1!0W>4/4`7B()#=Y060B>`LD(WE +M`Y##Y0!0VN4`D-CE*9*@X262B>`@D,WE`+#;Y2RPC>4$L-3E"[")X""PS>48 +M4)WE`%#5Y0Q0C>4L4)WE)9*+X`RPG>4KDHG@4%"=Y0.0Q>62G8'B*I")X@20 +MV>54L)WE`Y#+Y0'`C.)\P._F#`!7X5[__XHPT(WB\`^]Z![_+^$['*#C`1"0 +MYP``TN6%)0+C`@#!YP`@T^6&-0+C`R#!YP`PG>4`(-/EAS4"XP,@P><$,)WE +M`"#3Y8@U`N,#(,'G'O\OX?!!+>D`4*#A`6"@X3L\H.,#<)#G`1"@XP8@H.'Y +M_O_K`$"@X04`H.$($*#C!B"@X?3^_^N$-0+C`S#7YP`@8^```%+C`#"@TP`P +M8\!S,._&DWV'X@`@H.,`0,?E.##'Y1PPQ^4.0,?E1C#'Y2HPQ^4!((+B,!$*`#/!##Y1[_+^$>_R_A`0"@XQ[_+^'P12WI'-!-X@!@H.$! +MH*#A%%"-XA!PC>(,@(WB`("-Y0A`C>($0(WE!2"@X04&`*#A"A"@X04@H.$',*#A_O__ZP8`H.$%$*#A_O__ZP"@C>4&`*#A!Q"@ +MX0@@H.$$,*#A_O__ZQS0C>+PA;WH\$$MZ0!PH.$!@*#A`D"@X0-@H.$!`'+C +M!0``"O[__^L`4*#A!`"@X>O]_^L$0,7A%F"$X0<`H.$($*#A!B"@X?[__^OP +M@;WH$$`MZ0!`H.$(&0#C_R\/XP`PH./^___K!`"@X0@9`./_+P_C`S@`X_[_ +M_^L$`*#A"!D`X_\O#^,&.@#C_O__ZP0`H.$(&0#C_R\/XP$[`^,#,-#G``!3XPP``!I.$*#C_O__ZX`LX.&B+.#A!`"@X4X0 +MH.-R(._F_O__ZP0`H.%X&`#C`BJ@XP$PH./^___K``!5XP<```H``%;C!`"@ +MX608`.-@(*#C`3"@$P(PH`/^___K<("]Z```5N,$`*#AAAZ@XP,LH.,",*`3 +M`3"@`_[__^MP@+WH$$`MZ3L\H.,#,)#G`""3Y0$@0N(!`%+C!0``BA`PD^4" +M`%/C`@``&@$@H./,___K$("]Z``@H./)___K$("]Z/!!+>D`4*#A.SR@XP-` +MD.H./_(*#C_O__ZY$U`N,#`,3G!0"@X5@< +M`./_(*#C_O__ZY(U`N,#`,3G!0"@X<8>H./_(*#C_O__ZY,U`N,#`,3G!0"@ +MX6@<`./_(*#C_O__ZY0U`N,#`,3G!0"@X3@<`./_(*#C_O__ZXDU`N,#`,3G +M!0"@X30<`.,`(.#C_O__ZXPU`N,#`(3G<("]Z!!`+>G^___K$("]Z/!!+>D` +M0*#A.UR@XP4PD.>'+J#C\!@"XP$@@^H./X*`+C`A"#YV0H`..ES:#C#""#Y_S(`N,,$(/G1!D"XP$@@^8&0+C`2"#Y^`9 +M`N,!((/G@AZ@XPPI`N,"$(/G*!@`XU0I`N,"$(/G)!@`XQ`I`N,"$(/G+!@` +MXU@I`N,"$(/G6"@`XQ09`N,!((/G7!D"XP$@@^=<*`#CI!D"XP$@@^?L&0+C +M`2"#Y\4>H.,8*0+C`A"#YU@<`.-@*0+C`A"#Y\8>H..H*0+C`A"#YV@<`./P +M*0+C`A"#YU0<`.,<*0+C`A"#YUP<`.-D*0+C`A"#YV0<`..L*0+C`A"#YVP< +M`./T*0+C`A"#YQ0<`.,@*0+C`A"#YQP<`.-H*0+C`A"#YR0<`..P*0+C`A"# +MYRP<`./X*0+C`A"#Y\$>H.,D*0+C`A"#YQ@<`.-L*0+C`A"#Y\(>H..T*0+C +M`A"#YR@<`./\*0+C`A"#YS(=H.,H*0+C`A"#YX@<`.-P*0+C`A"#Y\D>H..X +M*0+C`A"#YY@<`.,J+*#C`A"#YX0<`.,L*0+C`A"#YXP<`.-T*0+C`A"#YY0< +M`..\*0+C`A"#YYP<`.,$*@+C`A"#YXH>H.,P*0+C`A"#YZ08`.-X*0+C`A"# +MYZ@8`..G+:#C`A"#YZP8`.,(*@+C`A"#Y[@8`.,T*0+C`A"#Y[P8`.-\*0+C +M`A"#YP(0H./^___K`BJ`XP,@@N,$`*#A`A"@XW(@_^;^___K!`"@X1\0H.,' +M(*#C_O__ZP0`H.$"$*#C%R"@X_[__^L$`*#A%1"@X^D@H./^___K!7"4YZE= +MA^(04(7B!0"@X0`0H./^___K`6!0X@%@H!,!`%;C"@``&A`T`^,#,-3G``!3 +MXP`@H`.5-0(#`R#'!P4`H.$!$*#C_O__ZP$`4.,`8*`#!@"@X?"!O>AP0"WI +M`$"@X3L\H.,#`)#GJ0V`XA``@.+^___K`%"@X00`H.'*%`#C"R"@X_[__^L! +M`%7B`0"@$W"`O>CP1RWI`$"@X0%@H.$[/*#C`W"0YW*@[^8D&`#C`"#@X_[_ +M_^L`@*#A``!6XQT```J&D8;@B9&'X"F(0D(GB!`"@X0`0F>4`(.#C_O__ +MZW\$P.,"5<#C!`"@X208`.,`(.#C`C'(X_[__^L*`*#C_O__ZXI;A>$$`*#A +M`!"9Y0`@X.,",87C_O__ZV0`H./^___K"@"@X_[__^L!`%;C+```&AH``.H$ +M`*#A)!@`XP`@X.,",]Z(9AAN"& +M<8?@*7R'XC!PA^($`*#A`!"7Y?\O#^,/($#C_O__Z_"'O>CP1RWI`&"@X0%` +MH.$"@*#A`W"@X2"@G>7_/P_C#S!`XP,`5^$%```*E/__ZP!0H.$'`*#AA?O_ +MZP=0Q>$:H(7A.SR@XP,PEN>$083@A$&#X"E,A.+_I,KC#Z;*X_\P".(&`*#A +M`!"4Y0`@X.,#.HKA_O__Z_"'O>CP12WI#-!-X@!0H.$!0*#A.SR@XP,PD.<\ +M$-/E0"#3Y04`4N,J```*``!4XP%`H`,\0,/ES"L#XP(@D.<``%+C(@``&M`K +M`^,"()#G``!2XQX``!H[/*#C`V"0YP00H.'^___K!("@X4(PUN4``%/C%P`` +M"@!`H./_?P_C#W!`XQB@H.,J/83B!#"#X@,AEN?_+\+C`R#"XP@@@N$#(8;G +M`""-Y04`H.$$$*#A"B"@X0W__XH` +M``#J/!##Y0S0C>+PA;WH<$`MZ0-`H.%'___K`%"@X00`H.$X^__K!$`%X#0` +MH.%P@+WH\$\MZ3303>(`@*#A`7"@X0*PH.$0P(WB'#&?Y0\`D^@/`(SH`3R@ +MXR`PC>4)/*#C)#"-Y0([H.,H,(WE`S"@XRPPC>4`0*#C`9"@XP10H.$,8*#A +M_Z\/XP^@0.,P((WB!S&"X!`P0^(,,(WE`P!7XP?QGY<#``#J)'P"`*A[`@"H +M>P(`U'L"``"0H.,>``#J##"=Y0!0D^4(`*#A!1"@X00@EN?^___K"`"@X040 +MH.'^___K`%"@X1,``.H$,);G`SJ@X2,ZH.$$,(;G`#"-Y0@`H.$+$*#A`R"@ +MXPHPH.'^___K"@"@X_[__^L(`*#A"Q"@X0,@H.,`,.#C_O__ZP!0H.$*`*#C +M_O__ZP0PEN<%`%/A!```&@1`A.(0`%3C`@``"@-0H.'/___J`)"@XPD`H.$T +MT(WB\(^]Z+P3```>_R_A<``MZ0S03>(<0)WE(,"=Y3M,5```*`!"@XP-`X.,X`)7E``!0XPA@C>(!`(;@`6#2!P%@TQ<$8,#G +M"&"-X@$`AN`$`-#G`&B@X0!LAN$`8(;A``2&X0$!C.4! +M`%#AZ___B@S0C>)P`+WH'O\OX?`/+>DHT$WB#!"-Y1PPC>4[/*#C`\"0YT^P +MW.6578'B*%"%X@50C.``,*#C`Q"@X0-PH.$#D*#A`Z"@X22`C>+Z"0_C^0E/ +MXQ0`C>449`'C%&1!XQA@C>4#`%OC"_&?EWX``.J(?0(`P'T"`'!^`@"(?@(` +M``!1XP@`H!,``*`#`@"`X)8.@.(&`(#B``&4%`%3C`9"@DPX``)H,8)WE"`!6XP*0H),*``":#`"= +MY0L`4.,#D*"3!@``F@Q`G>4-`%3C!)"@DP(``)H,8)WE#@!6XP60H`,``%'C +M"$"@$P!`H`,)`H+@!`"`X)8.@.(&`(#B``&"63H3B!D"$X@1!G.=_,*#C$T4$X#1%H.%T0._F`$#(YQ`PG>4# +M`%3A`'#(QP$`@.($`%#C[/__&@90H.$$,)WE)P#=Y29`W>4$2*#A`$R$X20` +MW>4`0(3A)0#=Y0!$A.$!`%+C'&"=E4A@G84#`);G!$"`X`J0H.$,``#J``!1 +MXP@`H!,``*`#``""X)8.@.(&`(#B``&("`%'C7O__&BC0C>+P#[WH'O\OX0`P +M`.,`,$#C`1-AX`(@@>""`9/G'O\OX0```.,``$#C`1-AX`(0@>#_-,/C#S;# +MXX$Q@.>!$8#@`3"@XP4>_R_A````XP``0.,!$V'@`A"!X($!@.`$,,#E +M'O\OX0```.,``$#C`1-AX`(0@>"!`8#@!C#`Y1[_+^'P02WI`&"@X0!0H.,% +M<*#A`8"@XPT``.HF,$3B`0!3XP8`H.$%$*#A!""@X0("`%7C\(&]"`=`H.'O___J\$$MZ0!@H.$`4*#C!7"@ +MX0&`H.,-``#J)C!$X@$`4^,&`*#A!1"@X00@H.$',*"!"#"@D?[__^L!0(3B +M0`!4X_3__QH!4(7B`@!5X_"!O0@'0*#A[___Z@``H.,`P`#C`,!`XP`@H.$+ +M``#J`""#Y00@P^4&(,/E!2##Y0<@P^4!$('B"#"#XD``4>/V__\:`0"`X@(` +M4.,>_R\!@#2@X8`Q0^`#,(S@`A"@X>[__^H$X"WE#-!-X@`P`.,`,$#C`<-A +MX`+`C.",,8/@!3#3Y0$`4^,0```:`#``XP`P0.,!PV'@`L",X(PQ@^`&,-/E +M`0!3XP@``!H`,`#C`#!`XP'#8>`"P(S@C#&3YP`PC>7_/P_C#S!`X_[__^L, +MT(WB`("]Z/!!+>D`8*#A`%"@XP5PH.$)``#J!@"@X040H.$$(*#A_O__ZP%` +MA.)``%3C^/__&@%0A>("`%7C\(&]"`=`H.'S___J!.`MY0S03>([/*#C`S"0 +MYP``4>,"```*`0!1XQ8``!H*``#J$!H"XP$@D^<#*X+C`2"#YP`@C>4`$*#C +M&""@X_\_#^,/,$#C_O__ZPH``.H0&@+C`2"3YP,KPN,!*X+C`2"#YP`@C>4` +M$*#C&""@X_\_#^,/,$#C_O__ZPS0C>(`@+WH<$`MZ0%`H.$"4*#A`#``XP`P +M0.,!(V'@!2""X((Q@^`$,-/E`0!3XP``H!-P@+T8!2"@X?\_#^,/,$#C_O__ +MZP`P`.,`,$#C!"-DX`4@@N"",9/G`P!0X08```H`,`#C`#!`XP0C9.`%((+@ +M@C&#X`$@H.,%(,/E`#``XP`P0.,$0V3@!5"$X(4Q@^`%`-/E<("]Z/!!+>D` +M8*#A`%"@XP5PH.$)``#J!@"@X040H.$$(*#A_O__ZP%`A.)``%3C^/__&@%0 +MA>("`%7C\(&]"`=`H.'S___J\$\MZ0S03>(`@*#A.SR@XP,PD.=!(-/E`P!2 +MXP$@H`,"(*`30B##Y3L\H.,#H)#G0C#:Y0``4^,!4*`#?0``"JDMBN(0((+B +M!""-Y0`PH.,`,(WE`W"@X0%@H.,#L*#A!U"@X0,`5^,'\9^7%```ZA2$`@`X +MA`(`%(0"`#B$`@"',8?@@S&*X`@`H.'P*`+C`A"3YQ`@H./^___K``"-Y0<` +M`.J',8?@@S&*X`@`H.'P*`+C`A"3YP$FH./^___K``"-Y861A>")D8K@HTV) +MXCA`A.((`*#A!!"4Y0$FH.,&,*#A_O__ZP8`H.'^___K"`"@X0`0E.40(*#C +M!C"@X?[__^L&`*#A_O__ZRE,B>(00(3B"`"@X0`0E.4!*Z#C"S"@X?[__^L& +M`*#A_O__ZP@`H.$`$)3E`BN@XPLPH.'^___K!@"@X?[__^L``%?C`@``"@$` +M5^,0```:!P``Z@0`G>4%$*#A!2"@X?[__^L!`%#C"T"@`1$``!H1``#J!`"= +MY040H.$%(*#A_O__ZP$`4.,+0*`!$P``&A,``.H#`%?C!_&?EP,``.I8A0(` +M@(4"`%B%`@"`A0(`!D"@X1(``.H&0*#AA5&%X(51BN`(`*#A\#@"XP,0E><0 +M(*#C`#"=Y?[__^L(``#J!D"@X851A>"%48K@"`"@X?`H`N,"$)7G`2:@XP`P +MG>7^___K`0!4XP8``!H!<(?B=W#OYD(PVN4'`%/AC/__B@10H.$```#J!%"@ +MX04`H.$,T(WB\(^]Z'!`+>D0T$WB`$"@X3L\H.,#`)#G`#"@XP@PC>4,,(WE +MR#F4Y0,`4^,=```:/S\#XS\_0^,,,(WE`##1Y0,HH.$#)(+A`R""X0,\@N$( +M,(WE(`!3XP0``)KI.`+C`S#0YP``4^,@,*`3"#"-%0$PT>4#**#A`R2"X0,@ +M@N$#/(+A##"-Y2``4^,O``":Z3@"XP,PT.<``%/C(#"@$PPPC14I``#J1CH" +MXP,PT.,0,$'C"#"-Y0PPC>4@``#J`@!3XQX```H`,-'E +M`RR@X0,D@N$#((+A`SB"X0@PC>4!,-'E`RB@X0,D@N$#((+A`SR"X0PPC>5/ +M,-#E``!3XP\``!JP-0+C`S"0YP@@G>4#,(+@M"4"XP(@D.<"-(/@"#"-Y=`U +M`N,#,)#G#""=Y0,P@N#4)0+C`B"0YP(\@^`,,(WE","-XA!@C>(`4*#C/^"@ +MXPP0H.$%,*#A`R#1YS\`4N,#X,&'`3"#X@0`4^/Y__\:!,",X@8`7.'T__\: +MJ0V`XA``@.(!$*#C`R"-X@0PC>+^___K`S#=Y0$`4^,'```:!#"=Y0@@G>4# +M((+@"""-Y0P@G>4#,(+@##"-Y0@``.H"`%/C!@``&@0PG>4(()WE`B!CX`@@ +MC>4,()WE`C!CX`PPC>4$`*#A"!X`X_\LH.,(,-WE_O__ZP0`H.%L&`#C_R#@ +MXP@PG>4C-*#A_O__ZP0`H.%L&`#C_R"@XP\PW>7^___K!`"@X3@8`./_(.#C +M##"=Y?\TP^/^___K$-"-XG"`O>CP3RWI;-!-X@"0H.&0P-WE),"-Y3O,H.,, +M0)#G),"=Y0#`C>58P(WB!,"-Y5#`C>((P(WE_O__ZZD-A.(0`(#B`!"@XTL@ +MC>),,(WB_O__ZP`0H.,4$(WE&!"-Y7^@H.-$8(WB4#"-X@`PC>5@,(WB!#"- +MY0D`H.$D$)WE&""=Y5@PC>+^___K2S#=Y0$`4^,'```:3#"=Y6`@G>4#((+@ +M8""-Y60@G>4#,(+@9#"-Y0@``.H"`%/C!@``&DPPG>5@()WE`B!CX&`@C>5D +M()WE`C!CX&0PC>4[/*#C`S"9YQPPC>4X,(WB`,``XP#`0.,'`)SH!P"#Z"PP +MC>*@P9_E!P"5@((WB!Q&2YPLPH.&#(:#A&@(! +MX#`BH.%R(._F`R#&YS\`4N,_P*"#`\#&AP$P@^($`%/C]/__&D>`W>5&,-WE +M`SB@X0@\@^%$(-WE`C"#X44@W>4"-(/A=R#OY@``4N,X((T"%!"=!;%`D@$L +M((T2%,"=%;Q`DA$)`*#A!!"@X0`@X./^___K'!"=Y4$PT>4"`%/C!0``&F@X +M`.,<+@#C`P!4X0(`5!$%```**```ZD@X`.,4+@#C`P!4X0(`5!$C```:%#X` +MXQPN`.,#`%3A`@!4$4)`*#A!!"%X'@@[^;^___K`5"%X@,` +M5>/H__\:`7"'X@(`5^.G__\:&""=Y0$P@N)S,._F&#"-Y10PG>4",(/B%#"- +MY1C`G>4&`%SC+PC[WHV!,``#L\H.,#`)#GV3@#XP,PT.<``%/C +M'O\O`30PT>4U`-'E`#2#X38`T>4`.(/A-P#1Y0`\@^$T`-+E-<#2Y0P$@.$V +MP-+E#`B`X3?`TN4,#(#A``!3X1[_+[$T,,+E(P2@X34`PN4C"*#A-@#"Y2,\ +MH.$W,,+E_R_A$$`MZ3L\H.,#,)#GV2@#XP(@T^<``%+C%@`` +M"FP@D.4!`!+C$P``&KP+P+C`A#3YP(`4>,!$*`#`A"@$P(0P^<`(*#C_O__ZP$`H.,0 +M@+WH``"@XQ"`O>@00"WI.SR@XP,`D.>I#8#B$`"`XO[__^L0@+WH\$$MZ0!@ +MH.$[3*#C!`"0YZE]@.(0<(?B*@R`XB0`@.(`$*#C+""@X_[__^L$4);GJ4V% +MXA!`A.($`*#A`!"@XP0@H./^___K4#H"XP-@A><$`*#A`!"@XP0@H./^___K +M!`"@X0(0H..X(=;A_O__ZP0`H.$$$*#C$""@X_[__^L$`*#A!A"@XP`@H./^ +M___K!`"@X040H.,!(*#C_O__ZP0@E>4$`*#A`Q"@XP$`4N,`(*`3`2"@`_[_ +M_^L$`*#A#!"@X[0BU>'^___K!`"@X0X0H.,"/P+C`R#6Y_[__^M!,-7E`P!3 +MXP4``!H$`*#A!Q"@XP`@H.,`,*#C_O__ZPX``.H"`%/C!0``&@0`H.$'$*#C +M`B"@XP`PH./^___K!@``Z@``4^,$```:!`"@X0<0H.,!(*#C`#"@X_[__^L% +M)*#C*#H"XP,@A><$`*#A`1"@XP4DH.,`,*#C_O__ZP<`H.'^___K!P"@X?[_ +M_^OP@;WH<$`MZ0C03>(`0*#A"""-X@$PH.,!,&+E.SR@XP-@D.>%,P/C`U#0 +MYR@0H.-H.P/C#^"@X0/PD.?8.@/C`S#4YP``4^,`,*`3!S#-%>$[`^,#,-3G +M`0!3XS8``!H``%7C-```&@4``%/C,0``"FP@E.40`!+C`@``&F``$N,! +M(`("!```"@@X`>,#()3G`@!2XP`@H-,!(*##J5V&XA!0A>(%`*#A*1"@X_\@ +M`N(`,*#C_O__ZSL\H.,#,)3G;""4Y0$`$N,)```:-"H"XP(@D^<``%+C"@`` +M&@`0H.,\*@+C`A"#YVP@E.4!`!+C!```"C0J`N,"$)/G/"H"XP(0@^<#``#J +M-"H"XP(0D^<\*@+C`A"#YSPZ`N,#();G!0"@X2H0H./"/Z#A_O__ZP4`H.'^ +M___K"-"-XG"`O>CP1RWI`("@X3M*_(`#C*#H"XP$E0.,#((3G!0"@X;\@`.,!)4#C`#"@X_[__^L%`*#A +M$1"@XU4MB.+^___K!0"@X1(0H.,6+(CB_O__ZP4`H.$3$*#C?BZ(X@$@@N+^ +M___K!0"@X140H.,]((3B_O__ZP4`H.$6$*#C8RV(X@P@@N+^___K!0"@X1<0 +MH.,X((3B_O__ZP4`H.$8$*#C/""$XO[__^L%`*#A)A"@X_(MB.(L((+B_O__ +MZP4`H.$?$*#C<""(XO[__^L%`*#A(!"@XS,LB.(T((+B_O__ZP4`H.$O$*#C +M_R"@X_[__^L&0*#A,&"@XP1PH.$%`*#A!A"@X70@_^8',*#A_O__ZP%`A.(@ +M`%3C]___&@H`H.'^___K`"#@XS0]`^,#(,CG\(>]Z'!`+>D`0*#A`5"@X>PV +M`>,#,-#G``!3XP8```H`,*#C\"8!XP(P@.?T)@'C`C"`Y^PF`>,",,#G\#8! +MXP,0E.7T-@'C`R"4YP(`@.`#`(3G_O__Z^TV`>,#`,3G +M``!4XP``51-P@+T(X#8!XP,PU.<``%/C!@``"@`PH./D)@'C`C"$Y^@F`>," +M,(3GX"8!XP(PQ.?D-@'C`Q"4YP$0@>(#$(3G90#5Y>@V`>,#()3G`@"`X`,` +MA.?^___KX38!XP,`Q.=P@+WH\$\MZ0S03>(`0*#A`8"@X1!0D.4[/*#C`Z"5 +MYV20@.(`,*#C`C#-Y0,PS>4$,,WE`P!0X0-@H`%\8)`5!G"@X;`PUN$,(`/B +M!`!2XW<```JR(]#A``!2XW0``!H!#!/C`B"@$P`@H`/3-.#G`S""X0,`4^,# +M\9^7`P``ZH21`@",D0(`E)$"`)R1`@```*#C!@``ZA``AN($``#J"@"&X@(` +M`.H$`(;B````Z@0`AN+@$(7B!B"@X_[__^L``%#C6@``"@$PH.,",,WEL"#7 +MX0$,$N,",*`3`#"@`](DX.<",(/A`0!3XP0`A@(!```*$`"&(@0`AC(-&X7B +M$1"!X@8@H./^___K``!0X@$`H!,#`,WE`C#=Y0``4^-&```*L##7X?PP`^*` +M`%/C0@``&@$PH.,$,,WE;#"5Y0@`$^/@L(42"0``Z@$`4^,*L(8R!@``.@(` +M4^,8L(82`P``&@$``.H0L(;B````Z@JPAN(`,.#C`3#-Y5L-A>(X`(#B"Q"@ +MX?[__^L`8%#BV#"6%0$PS156(-3E"#"-X@@@8^6I#8KB$`"`X@D0H.$((*#A +M#3"@X?[__^L`,*#CC#"$Y0(PW>4``%/C"0``"FPPE>40`!/C!@``"@``5N,A +M```*C&"$Y04`H.$$$*#A_O__ZQP``.H#,-WE``!3XP(``!H$,-WE``!3XQ8` +M``IL,)7E8``3XP$```H``%;CC&"$%04`H.$$$*#A_O__ZPT``.H``*#C`@#- +MY;3__^H`,*#C!##-Y;`PU^$!#!/C`""@`P(@H!/3-.#G`S""X0$`4^.X__\: +MOO__Z@S0C>+PC[WH,$`MZ1S03>(`0*#A`#"1Y0`PC>4$,)'E!#"-Y0@PD>4( +M,(WE##"1Y0PPC>40,)'E$#"-Y10PD>44,(WE#5"@X1P`@.(`$*#C6""@X_[_ +M_^L!,-WE4S/@YS(PQ.4-,-WE4S/AYUDPQ.4``%/C*@``&K`PW>%3,.WGO#'$ +MX0(PW>53(./G@B&@X1\@Q.4#(-WE4A'@YQX0Q.4(("+BTB'@YRX@Q.53(N+G +M+R#$Y=,SX.X +M,L3A"3#=Y5,RX^73,^#G,S#$Y1<``.H!`%/C!```&@@PH..\,<3A`#"@ +MXQ\PQ.40``#J`@!3XPH``!JP,-WA`SN@X2,[H.&\,<3A`#"@XQ\PQ.40,)WE +M7#"$Y10PG>5@,(3E`P``Z@,`4^.P,-T!4S#M![PQQ`$_R_A'O\OX1[_+^%P0"WI`%"@X0%` +MH.$"8*#A`""@XP`@P>4!(,'E!`"!X@,0H.$&(*#C_O__ZPH`A.(-&X7B$1"! +MX@8@H./^___K$`"$XL,>A>(&(*#C_O__ZP0PH.&V(?/A#R`"XK`@P^$`,-3E +M`2#4Y0(T@^'\,,/C`SB@X2,XH.%0,(/C`##$Y2,TH.$!,,3EH"R5Y0,,4N-P +M@+V(&`"$XLH>A>($$('B_O__ZZ`\E>48,(/B`#"&Y7"`O>CP3RWI+-!-X@!` +MH.$!L*#A`I"@X10PC>4[/*#C`S"0YQ`PC>4$@)/E`0!8XP"`H!,!@*`#`#"@ +MXR0PC>4@,(WEL#P#XP,PT.<``%/C>```"A00G>4``%'C=0``"@<`4N-S``"* +MT#L#XP,PD.49&@+C`1#2YP00C>5D0*#C4%`*#A!A"@X?[__^L'``#@<`#OY@``6.,"```*``!0XU8```H&``#J``!0 +MXP0``!H%`*#A"!"=Y?[__^L``%#C3@``"@``5.-)```*`4!$XNK__^H<`)WE +M%!"=Y0D@H.'^___K&0``ZAP`G>44$)WE`R"@X_[__^L@`(WB%""=Y0,0@N(8 +M()WE_O__ZP0PG>5\8(/B!F&@X1@0G>4``%'C"@``"@!`H.,!<*#A!0"@X000 +MAN`@,(WB!"#3Y_[__^L!0(3B=##OY@,`5^'V__^*!!"=Y71`@>($0:#A`&"@ +MXP4`H.$$$(;@!B#:Y_[__^L!8(;B!`!6X_C__QH``%CC"P``&@4`H.%S'Z#C +M_O__ZP0@G>50`J#A`0`0XPP```H%0*#A!0"@X0<=@N+_(*#C_O__ZP0PG>4! +M((/B`R`"XADZ`N,0$)WE`R#!YP$`H.,(``#J#""=Y0``4N,!`*`#!```"@PP +MG>4!,$/B##"-Y9C__^H``*#C+-"-XO"/O>@`L,KE`P!9X['__YJU___J!.`M +MY0S03>((,(WB!!!CY200H.,!(*#C9/__ZPS0C>(`@+WH!.`MY0S03>((,(WB +MLA!CX0$0H.,"(*#C6___ZPS0C>(`@+WH!.`MY0S03>(%`%'C`?&?ER```.J$ +MF`(`M)@"`,28`@#0F`(`\)@"`."8`@``,*#C`##-Y1TS`^,#,-#G`S*@X0$P +MS>4!,*#C`C#-Y7P[`N,#,-#G`S#-Y1X``.H!,*#C`##-Y0`PH.,B``#J`3"@ +MXP`PS>4?``#J`3"@XP`PS>4",*#C&P``Z@(PH.,`,,WE`#"@XQ<``.H`,*#C +M`##-Y1TS`^,#,-#G`S*@X0$PS>4!,*#C`C#-Y7P[`N,#,-#G`S#-Y0``4>," +M```*`#"@XP0PS>4!``#J##"@XP0PS>4@$*#C!2"@XPTPH.$=___K#-"-X@"` +MO>@=(P/C`B#0YP(R@^$!,,WE`3"@XP(PS>5\.P+C`S#0YP,PS>7J___J$$`M +MZ0`P4>($`*`#$("]"``0T^4!(-/E`C"#X@G__^L``*#C$("]Z/A/+>D`8*#A +M`5"@X0*@H.$#<*#A*(#=Y2RPW>4PD-WE-"#=Y0%`H.$`,*#C`##!Y0$PP>4# +M`%+A`##!%1`PH!,!,,$5.#&0Y0$`4^,"```*!`!3XS(``!H8``#J`##1Y0$@ +MT>4"-(/A`3R#XW,P_^8`,,'E(S2@X0$PP>7"#H#B#`"`XO[__^L`$*#A!`"% +MX@8@H./^___K"@"%X@T;AN(1$('B!B"@X_[__^L0`(7B!Q"@X08@H./^___K +M*```Z@`PT>4!(-'E`C2#X0(\@^-S,/_F`##!Y2,TH.$!,,'E!`"!X@<0H.$& +M(*#C_O__Z\(.AN(,`(#B_O__ZP`0H.$*`(7B!B"@X_[__^L0`(7B#1N&XA$0 +M@>(&(*#C_O__ZP\``.H$`('B!Q"@X08@H./^___K"@"%X@T;AN(1$('B!B"@ +MX_[__^O"#H;B#`"`XO[__^L`$*#A$`"%X@8@H./^___KMC'TX0\P`^*P,,3A +M`0!8XQ```!JP,-7A_###X\@P@^.P,,7A`9`)XA@PU>49(-7E#Q`+X@(T@^$# +M,('A"9*#X7F0_^88D,7E*92@X1F0Q>4:,*#C!```ZK`PU>'\,,/C2#"#X[`P +MQ>$8,*#C`#"*Y?B/O>CP02WI`%"@X0%`H.$"<*#A`#"@XP`PP>408*#C`6#! +MY;`PT>'\,,/CI#"#X[`PP>'$.P#CLS"0X0,YX.$C.>#ALC#!X<(.@.(,`(#B +M_O__ZP`0H.$$`(3B!B"@X_[__^L*`(3B#1N%XA$0@>(&(*#C_O__ZP!@A^7P +M@;WH\$4MZ1S03>(`4*#A`4"@X0*@H.$`(`#C`"!`XPPPC>(#`)+H!`"#Y+`0 +MP^$`,*#C`##$Y0$PQ.4$`(3B#!"-X@8@H./^___K"@"$X@T;A>(1$('B!B"@ +MX_[__^O"#H7B#`"`XO[__^L`$*#A$`"$X@8@H./^___K!#"@X;8A\^$/(`+B +ML"##X;`PU.'\,,/C@#"#XP1PH.&P,L?@(#"@XQ0PC>7*;H7B!&"&X@8`H.'^ +M___K`!"@X0<`H.$"(*#C_O__ZR)PA.(4,)WE`C"#XA0PC>4&`*#A_O__ZP`0 +MH.$'`*#A`B"@X_[__^LD`(3B%#"=Y0(P@^(4,(WE'"N5Y0,@`N(#`%+C!@`` +M&J`LM>4,($+B`R""X!0@C>40$(7B_O__ZR\``.HX+)7E%&"-X@!@C>4`$*#C +MPSZ%X@PP@^+^___K`("@X3)-A>(,0(3B!`"@X?[__^L`<*#A`&"-Y0@`H.$! +M$*#C"`!7XP<@H#$((*`C!#"@X?[__^L`8(WE`Q"@XP$@H./'/H7B!#"#XO[_ +M_^L<.Y7E`S`#X@$`4^,'```:&#"-X@`@H.,0("/E%""-X@`@C>4&$*#C`B"@ +MX_[__^L(`%?C!@``FA0PC>(`,(WE,A"@XP@@1^+)/H7B!#"#XO[__^L4,)WE +M(""#X@(,4N,`,(J5'-"-XO"%O>CP3RWI1-!-X@!@H.$[/*#C`S"0YP$`4>,1 +M`0`:&#"-Y<0[`..S()#A`BG@X2(IX.&H%@#C<&`*#A`1$`X_[__^L&`*#A`!"@XP@@H./^___K!@"@ +MX1`0H.,`(*#C_O__ZR!*`N,8,)WE!"#3YT`0`N(<$(WE!@"@X2(4`.._(`+B +M_O__ZQ@@G>4$,-+G0###XP0PPN=3/8;B(#"#XA0PC>7"'H;B#!"!XA`0C>4` +ML*#C"W"@X08`H.$*$@#C_O__ZP$@@.,&`*#A"A(`XW(@[^;^___K^@^@X_[_ +M_^L`0%#BD0``"CLLH.,"@);G!@"@X2@0A.(\((WB_O__ZSQ0G>4@4(7B?S`5 +MX@$PH!.E4X/@_U`%X@$`5>,"4*`#W3@#XP-0R.>%HZ#A**"*XB50S>4&`*#A +M"A"$X#0@C>+^___K(!!*X@!PC>4&`*#A`1"$X#0@G>4!,*#C_O__ZS0@G>4@ +M((+B?S`2X@$PH!.B,X/@!U4._F@X.*X'B`_^8F4,WE$`"=Y?[_ +M_^L`,*#A`'"-Y01PC>4(<(WE#'"-Y08`H.$($(3@,""-XO[__^L@$$CB`'"- +MY08`H.$!$(3@,""=Y0(#_YB10S>40`)WE_O__ZP`PH.$`<(WE!@"@X0@0A.`X +M((WB_O__ZR`02.(`<(WE!@"@X0$0A.`X()WE!S"@X?[__^LX()WE("""XG\P +M$N(!,*`3HC.#X',P[^:#@XC@`U"%X"=0S>7X7P_C`%!`XP50".`0`)WE_O__ +MZP`PH.$!(*#CA`"-Z`APC>4,<(WE!@"@X040A.`L((WB_O__ZR`01>(`<(WE +M!@"@X0$0A.`L()WE!S"@X?[__^LLH)WE%`"=Y?[__^L`@%#B%@``"@I0A>`& +M`*#A"!"(XO[__^L0,*#C5S#(Y2@P1>(8,(CE%#"(Y6P`F.4$$*#A!2"@X?[_ +M_^L&`*#A"!"@X9@[`^,/X*#A`_"6YP8`H.$'$*#A!2"@XR0PC>(B_?_K!`"@ +MX?H?H./^___K_O__ZP8`H.$*$@#C_O__ZP&`$.(8```:!U"@X0J@H.,*D@#C +M`5"%XG50[^8*`*#A_O__ZP8`H.$)$*#A_O__ZP&`$.(`,*`3`3"@`Q,`5>,` +M(*"#`2`#D@``4N/P__\:`;"+XGNP[^8$`%OC`#"@@P$P`Y(``%/C0O__&@!` +MH.$&`*#A"!"@XP`@H./^___K!@"@X0`0H.,0(*#C_O__ZQP0G>4``%'C"P`` +M"B!:`N,8,)WE!2#3YT`@@N,&`*#A(A0`XW(@[^;^___K&!"=Y04PT>=`,(/C +M!3#!YP``6.,$```*`2"$XP8`H.$*$@#C?^ +M(`+B`R#!YP8`H.$!$0#C_O__ZT30C>+PC[WH\$`MZ0S03>(!0*#A`E"@X3L\ +MH.,#<)#G#V+!XP8`H.'^___KU3+@YP`PC>6I#8?B$`"`XA\0!>(D+J#A!C"@ +MX?[__^L,T(WB\("]Z#!`+>D4T$WB`$"@X000C>4[/*#C`R"0YQHZ`N,#,-+G +M`0!3XP``H!,.```:#%"-X@4`H.$`$*#C`R"@X_[__^L%`*#A!!"-X@,@H./^ +M___K!`"@X4`0H.,#(*#C!3"@X:O\_^L!`*#C%-"-XC"`O>@$0"WE.SR@XP,P +MD.@``&CL\H.,#,)#G`A\"XP$0T.<`$%'B`1"@$P(`4N,$```*`P!2XRX` +M``H!`%+C;@``&EL``.H``%'C%```"CDLH.,"$)/GYB@#XP(0P^?\*`/C`B"3 +MY^<(`^,`(,/GZ`@#XP`0P^?I&`/C`2##Y^H8`^,!(,/GZQ@#XP$@P^?L&`/C +M`2##Y^T8`^,!(,/G5@``ZOPH`^,"()/GYA@#XP$@P^?G&`/C`2##YSD,6```*_"@#XP(@D^?F&`/C`2##YSD@>_R_A'O\OX1[_+^$>_R_A'O\OX?A/+>D`0*#A4GV`X@1PA^+$ +M-`'C`X"0YX`@H.,\-@'C`R"`YX@V`>,#4)#GV+"%XCRF`>,`D*#CE&8!XP<` +MH.$*$)3G"2"@X04PH.$X_R_A``!0XP@```H&,)3G`3!#X@8PA.<+`%7A`0`` +M&@$`H./XC[WH2%"%XN___^H``*#C^(^]Z![_+^$[/*#C`Q"0YP`@H.,:.@+C +M`R#!Y^,S`^,#,-#G`@!3X1DZ`@,#(,$'`#"@XWPG`^,",,'GL"`#XP(PP>>5 +M)0+C`C#!YPT@H.,N(,'EW2`#XP(PP><#`*#A`R"!X,,M@N(5((+B``#"Y0$P +M@^((`%/C^/__&A[_+^$!`*#C'O\OX1!`+>D`0*#AY0V@X_[__^L[/*#C`P"$ +MY^4MH.,$.P/C`R"$YP`@`.,(.P/C`"!`XP,@A.<`(`#C##L#XP`@0.,#((3G +M`"``XQ0[`^,`($#C`R"$YP`@`.,8.P/C`"!`XP,@A.<`(`#C'#L#XP`@0.,# +M((3G`"``XR`[`^,`($#C`R"$YP`@`.,D.P/C`"!`XP,@A.<`(`#C*#L#XP`@ +M0.,#((3G`"``XRP[`^,`($#C`R"$YP`@`.,P.P/C`"!`XP,@A.<`(`#C[3V@ +MXP`@0.,#((3G`"``XT0[`^,`($#C`R"$YP`@`.-(.P/C`"!`XP,@A.<`(`#C +M9#L#XP`@0.,#((3G`"``XV@[`^,`($#C`R"$YP`@`.-L.P/C`"!`XP,@A.<` +M(`#C<#L#XP`@0.,#((3G`"``XWP[`^,`($#C`R"$YP`@`./N/:#C`"!`XP,@ +MA.<`(`#CE#L#XP`@0.,#((3G`"``XY@[`^,`($#C`R"$YP`@`..0.P/C`"!` +MXP,@A.<[#(3B"`"`XO[__^L0@+WH$$`MZ3L\H.,#0)#G!P!1XP4```H-`%'C +M0```"@8`4>,``*`3$("]&#<``.H`,-+E``!3XP0``!H`(*#C<#H"XP,@A.@#`%/C!0``&G`Z`N,#()3G`2/" +MXP,@A.H./^___K8#X"XP,`Q.AP0"WI@M]-X@!`H.$(4(WB!1"@X?[__^L$`*#A!1"@ +MX?[__^L[/*#C`S"4YQ`D`^,"(-3G``!2XPD``!H(((WBL!W2X;04P^&R+=+A +MMB3#X5,(,/E,B#@XTT@P^4'``#J>"8%X[0DP^$T(@'CMB3#X50@X.-, +M(,/E,B#@XTT@P^40-`/C`R#4YP`0`.,`$$#C#3"@X0,`D>@$`(/DL!##X0`` +M4N,2```*`"#=Y1$T`^,#(,3G`2#=Y1(T`^,#(,3G`B#=Y1,T`^,#(,3G`R#= +MY10T`^,#(,3G!"#=Y14T`^,#(,3G!2#=Y18T`^,#(,3G!0``Z@T+A.(1`(#B +MX!"-X@$00>(&(*#C_O__ZPA@C>(05`/C!`"@X080H.$%(-3G_O__ZP0`H.$& +M$*#A!2#4Y_[__^L$`*#A!A"@X04@U.?^___K!`"@X080H.$%(-3G_O__ZP0` +MH.$&$*#A!2#4Y_[__^L$`*#A!A"@X04@U.?^___K!`"@X080H.$%(-3G_O__ +MZP0`H.$&$*#A!2#4Y_[__^L$`*#A_O__ZX+?C>)P@+WH$$`MZ0!`H.'^___K +MX#L#XP,`Q.?^___K.SR@XP,PE.<$(*#C0"##Y00`H.$*$*#C_O__ZU`BX.<: +M-`/C`R#$YR``(.+0`N#G$#0#XP,`Q.<$`*#A?___ZQ"`O>AP0"WI`$"@X3L\ +MH.,#4)#G51Z@XQ`@`>/^___K!`"@X14=H.,$)`;C_O__ZP0`H.%8%0#C!2"@ +MX_[__^L$`*#A614`XP(@H./^___K!`"@X5$>H.,/)@;C_O__ZP0`H.%5'J#C +M_O__ZQPZ`N,#`(7G!`"@X2(5`./^___K&SH"XP,`Q><$`*#A(A0`X_[__^L@ +M.@+C`P#%YP0`H.%"%0#C_O__ZR$Z`N,#`,7G!`"@X0$1`./^___K(CH"XP,` +MQ>=P@+WH<$`MZ0!`H.$[/*#C`U"0YP0PE>4!`%/C%0``&B!J`N,&(-7G0""" +MXR(4`.-R(._F_O__ZP8PU>=`,(/C!C#%YP0`H.%!%0#C_R"@X_[__^LA.@+C +M`R#5YP$@@N-R(._F`R#%YP0`H.%"%0#C_O__ZW"`O>@B%0#C_O__ZP`@H.$; +M.@+C`P#%YP0`H.$B%0#COR`"XO[__^MP@+WH<$`MZ0!0H.$!0*#A$1V@XW0@ +M[^;^___K!0"@X4$4`.-4).?G_O__ZP$`5.,`(*"3!0``F@`@H..D0*#A`2"" +MXG(@[^8!`%3C^O__B@4`H.$2':#C_O__ZW"`O>AP0"WI`$"@X3L\H.,#4)#G +M!#"5Y0$`4^,3```:(&H"XP8@U><$ +M`*#A014`XV0@H./^___K(3H"XP,@U>?^(`+B`R#%YP0`H.%"%0#C_O__ZW"` +MO>@B%0#C_O__ZP`@H.$;.@+C`P#%YP0`H.$B%0#C0"""X_[__^MP@+WH$$`M +MZ0!`H.$<$*#C`""@X_[__^L$`*#A!!"@XQ(H"./^___K$("]Z!!`+>D`0*#A +MX3,#XP,PT.<``%/C!```"EP0H./^___K@``0XPL```H,``#J0Q"@X_[__^OW +M(`#B!`"@X4,0H./^___K!`"@X4(0H./^___K"``0XP$```H``*#C$("]Z`(` +MH.,0@+WH<$`MZ0!`H.%4%0#CQCL`X[,@D.'^___K!`"@X5H5`.,"(*#C_O__ +MZP0`H.$[___K!`"@X1L5`.,)(*#C_O__ZP0`H.$$%@#C_O__ZP%0P.,$`*#A +M!!8`XP4@H.'^___K!`"@X006`.,!((7C_O__ZP0`H.%>%0#C4""@X_[__^L$ +M`*#A7Q4`XU`@H./^___K!`"@X54>H.,:(*#C_O__ZP0`H.$E%0#C;R"@X_[_ +M_^L$`*#A2O__ZP0`H.%5'J#C_O__ZP(@@.,$`*#A51Z@XW(@[^;^___K<("] +MZ'!`+>D`0*#A`E"@X3L\H.,#,)#G!A!!XC$`4>,!\9^77P``ZNBP`@#PL`(` +MH+$"`*"Q`@"@L0(`H+$"`*"Q`@"@L0(`H+$"`*"Q`@"@L0(`H+$"`*"Q`@`$ +ML0(`1+$"`#2Q`@"@L0(`H+$"`*"Q`@"@L0(`H+$"`*"Q`@"@L0(`H+$"`*"Q +M`@"@L0(`H+$"`*"Q`@"@L0(`H+$"`*"Q`@"@L0(`H+$"`*"Q`@!0L0(`H+$" +M`*"Q`@"@L0(`H+$"`*"Q`@"@L0(`H+$"`*"Q`@"@L0(`A+$"`*"Q`@"@L0(` +MH+$"`*"Q`@"4L0(`OC/3X;`PPN$$`*#A(A4`X_[__^L``,7E<("]Z((?H./^ +M___K`""@X0$($.-P@+T(!`"@X8(?H.,!*(+C_O__ZP$PH.,`,,7E<("]Z'`J +M`N,",)/G`##%Y7"`O>A!,-/E`##"Y7"`O>C8,P/C`S"0YP(`4^,!,*`#`##" +M!7"`O0@!'*#C_O__Z\``$.,!,*`3`#"@`P`PQ>5P@+WHV"@#XP(PT^<`,,7E +M<("]Z/(H`^.R()/AL"#%X7"`O>CP3RWI#-!-X@!`H.$!4*#A.SR@XP.`D.,P```:'@``ZC)] +M@.(,<(?B!P"@X?[__^L`D*#A!`"@X0<0H.$)(*#A_O__ZP\``.+^___K`*"@ +MX0<`H.$)$*#A_O__ZP!PH.'0.]3E``!3XP``H`,"```*OPZ$X@8`@.+^___K +M!W"`X00`H.&_'H3B!A"!XO[__^L`L%#B`;"@$R,``.K]#H#B!`"`XO[__^L` +M<*#AX3?4Y0$`$^,!`*`3`@"@`_[__^L`H*#A,@V$X@P`@.('$*#A_O__ZP!P +MH.$`L*#C$@``ZH%R@.#[?H?B!'"'X@<`H.'^___K`)"@X00`H.$'$*#A"2"@ +MX?[__^L/``#B_O__ZP"@H.$R#83B#`"`X@D0H.'^___K`'"@X0"PH.,'`*#A +M_O__ZS^0`.(:.@+C`S#8YP$`4^,$```:4'&&Y00`H.$'$*#A_O__ZP8``.H` +ML(WEJ0V(XA``@.)U$._F"B"@X0D(T$WB`#"@X0)`H.$[+*#C`B"0YPT`4>,!\9^7#0``ZK2S`@#&T@MWAN*+=X4,?H./^___K`U`%X@-`!.($1*#A!F.@X055A.'`8`;B`W`' +MX@90A>$#@`CB!W*%X0B&A^$*IXCA!P``X@"@BN$)`*#A0Q^@X_(`0*#A`F"@X3L\H.,#4)#GJ0V%XA``@.)! +M`%'C`?&?EUD#`.H(MP(`,+<"`%RW`@"TN`(`V+@"`&C#`@``N0(`G+D"`+"Y +M`@#PN0(`T+H"`!R[`@!@NP(`G+P"`&"]`@!TO0(`\+T"`%2^`@!TO@(`:,," +M`&C#`@"(O@(`F+X"`,"^`@`$OP(`'+\"`,R_`@#@OP(`:,,"``S``@`@P`(` +M-,`"`%3``@!HP`(`O,`"`!3!`@"PP0(`:,,"`-#!`@`0P@(`:,,"`&C#`@!H +MPP(`:,,"`&C#`@!HPP(`(,("`&C#`@!HPP(`:,,"`&C#`@!8P@(`8,("`&C# +M`@!HPP(`B,("`&C#`@!HPP(`F,("`&C#`@!HPP(`:,,"`&C#`@!,P@(`0,," +M`%S#`@`$`*#A`A$`X_[__^L,(`#B`##6Y00`H.$"$0#C`R""X?[__^L-`P#J +M!`"@X0(1`./^___K`##6Y0,@`.(#(8+A!`"@X0(1`.-R(._F_O__ZP(#`.H` +M4-+E``!5XP(`51,&```:!`"@X:']_^L$`*#A51Z@XQD@H./^___K00``Z@$` +M5>,&```:!`"@X5K]_^L$`*#A51Z@XQH@H./^___K.```Z@,`5>,V```:!`"@ +MX5']_^L$`*#A$A"@X^T@H./^___K!`"@X0@6`...(@+C`"!'X_[__^L$`*#A +MI!8`X_\O#^/^___K!`"@X:(6`.,!*Z#C_O__ZP0`H.%9%0#C`B"@X_[__^L$ +M`*#A6!4`XP4@H./^___K!`"@X5H5`.,*(*#C_O__ZP0`H.%1'J#C`""@X_[_ +M_^L$`*#A%1V@XP0D!N/^___K!`"@X5,5`.,!(*#C_O__ZP0`H.$8$*#C`""@ +MX_[__^L$`*#A4A4`X_[__^L(((#C!`"@X5(5`.-R(._F_O__ZP0`H.$"$0#C +M_O__ZPP@`.($`*#A`A$`XP4@@N'^___KK`(`Z@!0H.,$`*#A81Z%X@4@UN?^ +M___K`5"%X@8`5>/X__\:HP(`Z@!0H.,$`*#A81Z%X@@0@>(%(-;G_O__ZP%0 +MA>(&`%7C]___&ID"`.H0((WB`#"@X[(P8N$$`*#A!A"@X?[__^N^,-WA%3X# +MX@TP@^.^,,WAOC/%X;X@W>$!((+C$$`*#A$1V@XW(@[^;^___K +MOB#=X00`H.%!%`#C(B2@X?[__^N^,-WA`0!3XP`@H),&``":`""@XZ,PH.$! +M((+BH./^___K\R``X@0`H.%5'J#C_O__ZUT"`.H8-`'CTV"$X<8[`..S()3A +M`B6@X08`H.$'$*#APC^@X?[__^L`C`_C_X]/XP"0X.,(();@"3"GX`)@H.$# +M<*#A`&!6X`%PQ^`<.Y3E`S`#X@,`4^,!`%,3`0``&@0`H.'I_/_K!`"@X54> +MH./^___K]R``X@0`H.%5'J#C_O__ZP0`H.%6'J#C!B"@X?[__^L$`*#A9!4` +MXP<@H.'^___K!`"@X54>H./^___K"""`XP0`H.%5'J#CH./^___K$""`XP0`H.%5'J#CH./^___K[R``X@0`H.%5'J#C_O__ZP\``.H#`%/C&0``&@0`H.$(%@#C +M_O__ZP(K@.,$`*#A"!8`X_[__^L$`*#A51Z@X_[__^OO(`#B!`"@X54>H./^ +M___K'#N4Y0,P`^(#`%/C!P``&@0`H.$(%@#C_O__ZX`@@.,$`*#A"!8`X_[_ +M_^NZ`0#J!`"@X0@6`./^___KP""`XP0`H.$(%@#C_O__Z[(!`.H`,-+E``!3 +MXQ$``!H$`*#AI!8`X_\O#^/^___K!`"@X0@6`./^___KP""`XP0`H.$(%@#C +M_O__ZVPPE.4(`!/C%P``"K0RU>$2`%/C%@``&A,``.H!`%/C!0``&@0`H.&D +M%@#C`""@X_[__^LP(*#C#@``Z@(`4^,+```:!`"@X54>H./^___K[R``X@0` +MH.%5'J#C_O__ZVPPE.5@`!/C`0``"@<@H.,```#J,""@XP0`H.$J%`#C`B2" +MX?[__^N!`0#J!`"@X505`..P(-+A_O__ZWP!`.H$`*#A&Q4`XP`@TN7^___K +MS3O4Y0``4^-U`0`:X3?4Y0$`4^,*,*`#$#"@$\M;U.6%4(/@=5#OY@0`H.$% +M'*#C!2"@X?[__^L$`*#A!!4`XP4@H.'^___K!`"@X0@5`.,%(*#A_O__ZP0` +MH.$,%0#C!2"@X?[__^M=`0#J!`"@X145`.,`(-+E_O__ZP0`H.$7%0#C`2#6 +MY?[__^L$`*#A*10`XP`@UN7^___K!`"@X3L6`.,`(-;E_O__ZP0`H.$]%@#C +M`"#6Y?[__^L$`*#A/Q8`XP`@UN7^___K1`$`Z@`@TN4$`*#A0A0`XP``4N.` +M(*`3`""@`_[__^L\`0#J!`"@X1H=H.,`(-+E_O__ZS<8`0#J<#H"XP`0DN4#()7G`B`!X`,@A><2 +M`0#J`##2Y8.AH.$!<*#C`&"@XP:`H.%TE@#C9[Z@XP,P`^(0,(/C!#"-Y00` +M`.H`@*#C`6"&XG9@[^8!<(?B=W#OY@``5N,,```:!#"=Y0.`B.$*4(;@!`"@ +MX0D0H.$((*#A_O__ZP(AA>,$`*#A"Q"@X0$H@N/^___K[/__Z@I0AN`$`*#A +M"1"@X0`@H./^___K`B&%XP0`H.$+$*#A`2B"X_[__^L'`%?CW___FN8``.H$ +M`*#A9QZ@XP,AH./^___KX0``Z@0`H.%T%@#C`""2Y?[__^L$();E`B&"XP0` +MH.%G'J#C`2B"X_[__^O6``#J!`"@X04,$(((3^R`"`@(`%>,"(((3_2`"`@0` +MH.$7':#C_O__ZZH``.H`4-+E!P!5XZ<``(K,.`'C`S"4YP4`4^,'8*"#`"`` +MDP`@0),#,(*0"E00`H.%<%`#C_O__Z_@@`.($`*#A7!0`XP4`5N$&(((A +M!2"",?[__^N4``#J`#``XP`P0.,0,)/E"#"-Y0`PTN4#`%/CC0``B@(P@^(! +MD*#C&9.@X7F0[^8/`%GC#Y"@(PF`H.$)('H*#A!3#6Y_`@ +M`^('`%+A#S`#P@,PBL$%,,;'!3#6YP\@`^("`%CA\#`#L@,PB;$%,,:W!`"@ +MX44>A>(($('B!2#6Y_[__^L!4(7B!`!5X^O__QIM``#J`"#2Y0``4N,^.0,# +M`R#5!P0`H.$*':#C_O__ZV4``.H`8-+E``!6XP@```H`,)7E`3!#X@$`4^," +M``"*$#"5Y0(`4^,!```*`1"@X_[__^L$`*#A!A"@X?[__^M5``#J!`"@X0`0 +MTN7^___K40``Z@`0DN7_`%'C83X"`P,0U0=@/@(3`R#5%V$^`A,#(,47<1#O +M%O[__^M&``#JL!#2X?[__^M#``#J_O__ZT$``.H`0-+EV#@#XP,PU><$`%/A +M/```"@00H.'^___KV#@#XP-`Q>,S`^,#,-3G`0!3XR8` +M``H$`*#AAQ(`X_[__^L!)X#C!`"@X8<2`./^___K9%"@XX=B`.,$`*#A!A"@ +MX?[__^L""!#C`P``"@``5>,!4$42=5#O%O;__QH$`*#AA1^@XP`@H./^___K +M!`"@X0(T4`.-R +M(._F_O__ZP(``.H$`*#AL!#2X?[__^L4T(WB\(^]Z!!`+>G^___K`0"@XQ"` +MO>@00"WI"-!-X@!`H.'L%`#C_O__Z_T@`.($`*#A[!0`X_[__^L$`*#A`1R@ +MXP`@H./^___K`#``XP`P0.,`,(WE!`"@X?\0H.,/(*#C`C"@X_[__^L$`*#A +M@!"@X_[__^N``!#C"@``"K`\`^,#,-3G``!3XP8```H$`*#A`Q"@X_[__^O[ +M(`#B!`"@X0,0H./^___K!`"@X8`0H.,`(*#C_O__ZP0`H.%E'Z#C_O__Z_X@ +M`.($`*#A91^@X_[__^L`,`#C`#!`XP`PC>4$`*#A_Q"@XP\@H.,",*#C_O__ +MZP0`H.$=$*#C_O__Z_<@`.($`*#A'1"@X_[__^L$`*#A'1"@X_[__^L(((#C +M!`"@X1T0H.-R(._F_O__ZP0`H.%$$*#C_O__ZP`@H.$$`*#A11"@X_[__^L$ +M`*#A1A"@X_\@H./^___K!`"@X4(0H./^___K`"*`X00`H.%"$*#C(0@+WH$$`M +MZ0!`H.'C,P/C`S#0YP``4^,)```*XC,#XP,PT.<``%/C%```"N$S`^,#,-#G +M``!3XQ````I0^O_K#@``ZN$[`^,#,-#G`0!3XPH``!K^___KXC,#XP,PU.<` +M`%/C!0``"N$S`^,#,-3G``!3XP$```H$`*#A0/K_ZP$`H.,0@+WH\$`MZ0S0 +M3>(`0*#A`F"@X3L\H.,#4)#G``!1XP(```H"`%'CA`$`BJ```.H!`%+C00`` +M&A$0H./^___K"2"`XP0`H.$1$*#C<>H.,`(.#CH#4"X]LS +M1N/^___K!P``Z@,`4^,%```:!`"@X><>H.,`(.#CH#4"XQLS1N/^___KE3T" +MXP,P0.,`,(WE!`"@X0`0H.,!(*#A_S\/XP\P0./^___K03#5Y0(`4^-)`0`: +ME3T"XP,P0.,`,(WE!`"@X0$0H.,`(*#C_S\/XP\P0./^___K/P$`ZB@0H..! +M(*#C_O__ZP0`H.$D$*#C#R`(X_[__^L!`*#C_O__ZP0`H.$1$*#C_O__ZPD@ +M@.,$`*#A$1"@XW(@[^;^___K03#5Y0(`4^,$`*#A>!@`XS@@``,X($`#.""@ +M$P$PH./^___K!`"@X00<`./P(*#C`3"@X_[__^L$`*#A`AN@XP(@H.,`,*#C +M_O__ZT$PU>4"`%/C!@``&@0`H.'G'J#C`"#@XZ`U`N/;,T;C_O__ZP<``.H# +M`%/C!0``&@0`H.'G'J#C`"#@XZ`U`N,;,T;C_O__ZY4]`N,#,$#C`#"-Y00` +MH.$`$*#C`2"@X?\_#^,/,$#C_O__ZT$PU>4"`%/C"```&I4]`N,#,$#C`#"- +MY00`H.$!$*#C`""@X_\_#^,/,$#C_O__ZP0`H.$&'*#C_O__Z[\@`.($`*#A +M!AR@X_[__^L*`*#C_O__ZP0`H.$"$*#C%R"@X_[__^L$`*#A(A4`XP`@H./^ +M___KX@``ZA$0H./^___K`#"5Y0$P0^(!`%/C!@``B@PPE>4!`%/C`P``&@@P +ME>4!`%/C_G```@````KV<`#B`0!6XUH``!H$`*#A>!@`XP`@X./^___KZ#,# +MXP,`A.<$`*#A!!P`XP`@X./^___K[#,#XP,`A.<$`*#A`AN@XP`@X./^___K +M\#,#XP,`A.=!,-7E`@!3XP8``!H$`*#A>!@`XS@@`.,X($#C`#"@X_[__^L& +M``#J`P!3XP0``!H$`*#A>!@`XS@@H.,`,*#C_O__ZP0`H.$$'`#C\""@XP`P +MH./^___K!`"@X0(;H.,"(*#C`3"@X_[__^L$`*#AYQZ@XP`@X./^___K]#,# +MXP,`A.=!,-7E`@!3XP8``!H$`*#AYQZ@XP`@X..@-0+CVS!`X_[__^L'``#J +M`P!3XP4``!H$`*#AYQZ@XP`@X..@-0+C&S!`X_[__^L`(*#C`""-Y00`H.$" +M$*#A_S\/XP\P0./^___K03#5Y0(`4^,&```:`""@XP`@C>4$`*#A`1"@X_\_ +M#^,/,$#C_O__ZP0`H.$1$*#C!R"@X?[__^MW``#J!`"@X2(5`./_(*#C_O__ +MZP`@H.,`((WE!`"@X0(0H.'_,*#C_O__ZP0`H.$&'*#C0""@X_[__^L*`*#C +M_O__ZP0`H.$"$*#C%B"@X_[__^L$`*#A>!@`XP`@X./^___KZ#,#XP,`A.<$ +M`*#A!!P`XP`@X./^___K[#,#XP,`A.<$`*#A`AN@XP`@X./^___K\#,#XP,` +MA.=!,-7E`@!3XP8``!H$`*#A>!@`XS@@`.,X($#C`#"@X_[__^L&``#J`P!3 +MXP0``!H$`*#A>!@`XS@@H.,`,*#C_O__ZP0`H.$$'`#C\""@XP`PH./^___K +M!`"@X0(;H.,"(*#C`3"@X_[__^L$`*#AYQZ@XP`@X./^___K]#,#XP,`A.=! +M,-7E`@!3XP8``!H$`*#AYQZ@XP`@X..@-0+CVS!`X_[__^L'``#J`P!3XP4` +M`!H$`*#AYQZ@XP`@X..@-0+C&S!`X_[__^L`(*#C`""-Y00`H.$"$*#A_S\/ +MXP\P0./^___K03#5Y0(`4^,&```:`""@XP`@C>4$`*#A`1"@X_\_#^,/,$#C +M_O__ZP0`H.$1$*#C!R"@X?[__^L$`*#A*!"@XX`@H./^___K`0"@X_[__^L$ +M`*#A)!"@XP\H"N/^___K#-"-XO"`O>CP12WI%-!-X@!`H.$[/*#C`V"0Y_[_ +M_^OC,P/C`S#4YP``4^,4```*?#<#XP,PUN<``%/C`P``"@0`H.$!$*#C_O__ +MZP4``.H$`*#A`!"@X_[__^L!(*#C?#<#XP,@QN>I#8;B$`"`XO[__^L$`*#A +M_O__ZP%0H.-8`@#J`#``XP`P0.,`,(WE!`"@X?\0H.,/(*#C`C"@X_[__^L` +M`%#C`%"@`TT"``H$`*#A`1R@XP`@H./^___K!`"@X0$P4`./^___K`R"`XP0`H.'L%`#CH./P+0SC_O__ZP0`H.%-'J#C`""@X_[_ +M_^L$`*#A_O__ZP!0H.$!`%#C!0``"@`PH..P+`/C`C#$YQHJ`N,",,;G#`(` +MZ@$@H..P/`/C`R#$YP`@H.,:.@+C`R#&YP0`H.'^___K-C,#XP,PU.?E8,P@I"T,=.1`#"-Y00PC>4(,(WE!`"@X0,0H.$#(*#AFOG_ +MZR,``.KD.`/C`S#2YP,P0^)S,._F`P!3XP`0H(,!,*"!Q":?E8,@@I"\,=*1 +MM!+2D0(O`N,"(-3G``!2XP$`H!$#(*`1`P"@`0$@H`$)`(WH"#"-Y00`H.&# +M^?_K#```Z@(_`N,#(-3G`S"@XP`PC>4$,(WE"#"-Y00`H.$!$*#C``!2XP$@ +MH`$"(*`3`C"@XW7Y_^L$`*#A%A$`X_\C`N/^___K!`"@X4$?H.,1(*#C_O__ +MZP0`H.$/%@#C!""@X_[__^L$`*#A21^@XP`@X./^___K!`"@X1(>H.,`(.#C +M_O__ZV%>H.,6=@#C!3"$X"X\@^(!,(/B!`"@X040H.$`(-/E_O__ZP%0A>(' +M`%7A]?__&@0`H.$!'*#C_O__ZP,HP.,$`*#A`1R@XP(H@N/^___K.UR@XP4P +ME.?/(`;C`"!'XS`@@^4$`*#A"!8`X_[__^L$`*#A8AZ@XP`@X./^___K!`"@ +MX206`.,`(.#C_O__ZP0`H.$1':#C_O__ZR`JH.'Q/P_C#S!`XP0`H.$1':#C +M`BJ#X?[__^L$`*#A*!0`XQ`@`>/^___K!`"@X2H4`.,P(`/C_O__ZP0`H.$H +M%`#C"B`!X_[__^L$`*#A.A8`XPH@`>/^___K!`"@X105`.,*(`'C_O__ZP0` +MH.$6%0#C"B`!X_[__^L$`*#A"!4`XRLD"N->($#C_O__ZP0`H.$,%0#C3R0* +MX_[__^L$`*#A!!4`XR0C"N->($#C_O__ZP0`H.$%'*#C)B(*XR\@0./^___K +M!`"@X4(>H./^___K@"S@X:(LX.$$`*#A0AZ@XW(@[^;^___K!`"@X1D=H.-` +M(*#C_O__ZP6`E.<"/P+C`S#4YP``4^,`(*`3,#D#$P,@R!#^,] +M.0/C`R#7Y_[__^L4``#J!`"@X0H=H.,^.0/C`R#7Y_[__^L_.0/C`R#7YP0` +MH.&!$@#C'R`"XO[__^L$`*#A71X/XSPY`^,#(-?G_O__ZP0`H.%<'@_C/3D# +MXP,@U^?^___K,CD#XX`@H..S((?A`""@X^\X`^,#(,CG!`"@X3SV_^L$`*#A +M`1R@X_[__^L`+>#A(BW@X00`H.$!'*#C!@`XP(JH.,!,*#C_O__ZP0`H.&&'J#C`RR@X_[__^L"`%#C`B"@ +M`P$@H!/8.`/C`R#'YP0`H.',%`#C_R\/XP$B0./^___K!`"@X2,4`./_(*#C +M_O__ZP(_`N,#,-3G``!3XP,```H$`*#A1AZ@XP`@H./^___K!`"@X5(6`.,` +M(*#C_O__ZP0`H.'^___KV',#XP`PH.,',(3G!`"@X2$4`.,/(*#C_O__ZP0` +MH.'3%`#C`2"@X_[__^L$`*#A3QZ@X_`M`^/^___K!S"4YP``4^,2```:?#<# +MXP,PUN<``%/C`P``"@0`H.$!$*#C_O__ZP4``.H$`*#A`!"@X_[__^L!(*#C +M?#<#XP,@QN>I#8;B$`"`XO[__^L$`*#A_O__ZP0`H.%8'@_C`""@X_[__^MA +M;J#C%G8`XP0`H.$&$*#A_O__ZP%@AN('`%;A^?__&@4`H.$4T(WB\(6]Z`0@ +MH.-`(,/E`R"@XT$@P^4#_O_J[!,```(PH.,(,(#E`#"@XPPPP.4.,,#E#S#` +MY1`PP.41,,#E$C#`Y1,PP.44,(#E&#"`Y1[_+^$00"WI`$"@X1P`@.+^___K +M!`"@X>S__^L0@+WH$$`MZ0!`H.$V#(#B'`"`XO/__^O9#83B/`"`XO#__^L0 +M@+WH$$`MZ0%`H.$%`('H`0"@X=W__^L`,`#C`#!`XRPPA.4P0(3E'`"$X@`0 +MH.,!(*#A_O__ZP(\H.-0,(3E5#"$XE0PA.58,(3E`#``XP`P0.-<,(3E$("] +MZ!!`+>D`0*#A`"``X^0V`^,`($#C`R"`YS8<@.(<$('B`2"@X]___^L$`*#A +MV1V$XCP0@>("(*#CVO__ZQ"`O>@00"WI`#"0Y=`K`^,"()/G`0!2XQ"`O0C, +M*P/C`C"3YP$`4^,0@+T(4`"`XO[__^L0@+WH<$`MZ0!`H.$!4*#A.SR@XP,@ +MD.?0.P/C`S"0YP$`4^,C```*S#L#XP,PD.4!`%/C`@`` +M"@(`4^,:```:$@``ZMDX`^,#,-+G``!3XP8```I.$*#C_O__ZP0`H.%.$*#C +MZ""@X_[__^L.``#J3!"@X_[__^MP(`#B!`"@X4P0H.,(((+C_O__ZP8``.I- +M$*#C_O__ZW`@`.($`*#A31"@XP@@@N/^___K`#"@XPPPQ>5P@+WH<$`MZ0!0 +MH.$[/*#C`S"0YTPPT^4&`%/C-DR`$AQ`A!+938`"/$"$`@$00>(&`%'C`?&? +MEU8``.HPV`(`,-@"`##8`@#+^___K<("]Z`XPU.4``%/C<("]&`@PE.4&`%/C +M<("]"`$PH.,.,,3E"C"@XP@PA.4",*#C%#"$Y0PPU.4``%/C`C"@$P$PH`,8 +M,(3E`#``XP`P0.,`$)/E'`"$X@40@>+^___K<("]Z`(PH.,(,(3E&#"$Y0XP +MU.4``%/C`P``"AP`A.+^___K`#"@XPXPQ.4%`*#A!!"@X6K__^MP@+WH<$`M +MZ0!`H.'0.P/C`S"0YP$`4^-P@+T(S#L#XP,PD.4!`%/C`P`` +M&AP`A>+^___K`#"@XPXPQ>4!,*#C#S#%Y0,P@^((,(7E###5Y0``4^,",*`3 +M`3"@`Q@PA>5H/9_E`!"3Y1P`A>)D$('B_O__ZW"`O>@0,-7E``!3XW"`O1@( +M,)7E!@!3XW"`O0@+`%/C"0!3$W"`O0@3,-7E``!3XW"`O1@/,-7E`0!3XP,` +M`!H<`(7B_O__ZP`PH.,/,,7E#C#5Y0$`4^,#```:'`"%XO[__^L`,*#C#C#% +MY0$PH.,0,,7E`C"#X@@PA>4,,-7E``!3XP(PH!,!,*`#&#"%Y<0\G^4`$)/E +M'`"%XC(0@>+^___K<("]Z!@UU.4``%/C`@``"FPPE.4!`!/C<("]&!(PU>4` +M`%/C<("]&`@PE>4+`%/C"0!3$W"`O0@3,-7E``!3XW"`O1@/,-7E`0!3XP,` +M`!H<`(7B_O__ZP`PH.,/,,7E$##5Y0$`4^,#```:'`"%XO[__^L`,*#C$##% +MY0XPU>4!`%/C`P``&AP`A>+^___K`#"@XPXPQ>4!,*#C$C#%Y04P@^((,(7E +M$C"#XA0PA>4,,-7E``!3XP(PH!,!,*`#&#"%Y>P[G^4`$)/E'`"%XA(0@>+^ +M___K<("]Z`XPU>4``%/C<("]&`@PE>4&`%/C<("]"`L`4^,)`%,3<("]"!,P +MU>4``%/C<("]&`\PU>4!`%/C`P``&AP`A>+^___K`#"@XP\PQ>40,-7E`0!3 +MXP,``!H<`(7B_O__ZP`PH.,0,,7E`3"@XPXPQ>4),(/B"#"%Y0(PH.,4,(7E +M###5Y0``4^,",*`3`3"@`Q@PA>5`.Y_E`!"3Y1P`A>(%$('B_O__ZW"`O>@3 +M,-7E``!3XW"`O1@/,-7E`0!3XP,``!H<`(7B_O__ZP`PH.,/,,7E$##5Y0$` +M4^,#```:'`"%XO[__^L`,*#C$##%Y0XPU>4!`%/C`P``&AP`A>+^___K`#"@ +MXPXPQ>42,-7E`0!3XP,``!H<`(7B_O__ZP`PH.,2,,7E`3"@XQ,PQ>4),*#C +M"#"%Y0PPU>4``%/C`C"@$P$PH`,8,(7E`#``XP`P0.,`$)/E'`"%XA(0@>+^ +M___K<("]Z`\PU>4!`%/C`P``&AP`A>+^___K`#"@XP\PQ>40,-7E`0!3XP,` +M`!H<`(7B_O__ZP`PH.,0,,7E#C#5Y0$`4^,#```:'`"%XO[__^L`,*#C#C#% +MY1(PU>4!`%/C`P``&AP`A>+^___K`#"@XQ(PQ>43,-7E``!3XP$PH`,3,,4% +M`0``"AP`A>+^___K"S"@XP@PA>4,,-7E``!3XP@```H",*#C&#"%Y0`P`.,` +M,$#C`!"3Y1P`A>)]'X'B_O__ZW"`O>@!,*#C&#"%Y0`P`.,`,$#C`!"3Y1P` +MA>+^___K<("]Z!,PU>4``%/C`P``"AP`A>+^___K`#"@XQ,PQ>4!,*#C#S#% +MY00PH.,(,(7E###5Y0``4^,",*`3`3"@`Q@PA>4`,`#C`#!`XP`0D^4<`(7B +M9!"!XO[__^MP@+WH`C"@XP@PA>48,(7E#S#5Y0``4^,#```*'`"%XO[__^L` +M,*#C#S#%Y1`PU>4``%/C`P``"AP`A>+^___K`#"@XQ`PQ>4.,-7E``!3XP,` +M``H<`(7B_O__ZP`PH.,.,,7E$S#5Y0``4^,#```*'`"%XO[__^L`,*#C$S#% +MY1(PU>4``%/C`P``"AP`A>+^___K`#"@XQ(PQ>4$`*#A!1"@X8-Y_E`!"3Y38,A.(X`(#B$A"!XO[__^MP@+WH*C8#XP,P +MU.<``%/C<("]&&PPE.4!`!/C<("]""0V`^,#,)3G!@!3XW"`O0@+`%/C"0!3 +M$W"`O0@O-@/C`S#4YP``4^-P@+T8`2"@XRHV`^,#(,3G"2""X@8P0^(#((3G +M`B"@XPPP@^(#((3G"#!#X@,PU.<``%/C`2"@`S0V`^,#((3G^#:?Y0`0D^4V +M#(3B.`"`X@40@>+^___K<("]Z`$PH.,D)@/C`C"$YS0F`^,",(3G*C8#XP,P +MU.<``%/C!0``"C8,A.(X`(#B_O__ZP`@H.,J-@/C`R#$YRXV`^,#,-3G``!3 +MXP4```HV#(3B.`"`XO[__^L`(*#C+C8#XP,@Q.<`,`#C`#!`XP`0D^4V#(3B +M.`"`XO[__^MP@+WH+S8#XP,PU.<``%/C<("]&"HV`^,#,-3G`0!3XP4``!HV +M#(3B.`"`XO[__^L`(*#C*C8#XP,@Q.@`$*#C+R8#XP(0Q.?8(P/C +M`B"4YP$`4N$#```*!`"@X0,0H.$._?_K<("]Z`$PH.,D)@/C`C"$YS0F`^," +M,(3G`#``XP`P0.,`$)/E-@R$XC@`@.+^___K<("]Z``0H.,O)@/C`A#$Y]@C +M`^,"()3G`0!2X0,```H$`*#A`Q"@X??\_^MP@+WH`C"@XR0F`^,",(3G-"8# +MXP(PA.<`,`#C`#!`XP`0D^4V#(3B.`"`XO[__^MP@+WH+C8#X[,PE.$``%/C +M<("]&`(P@^(D)@/C`C"$YQ`@@N(",(3GZ#2?Y0`0D^4V#(3B.`"`XO[__^MP +M@+WH`C"@XR0F`^,",(3G-"8#XP(PA.,! +M\9^7L0,`ZO3E`@!(Z`(`5.4"`%3E`@"0Y`(`B.@"`$CH`@"8Y@(`3.<"`)CF +M`@#PYP(`JY0``4^-P@+T8+C8#XP,PU.<``%/C<("]&"0V`^,#,)3G"P!3 +MXPD`4Q-P@+T(+S8#XP,PU.<``%/C<("]&"HV`^,#,-3G`0!3XP4``!HV#(3B +M.`"`XO[__^L`(*#C*C8#XP,@Q.+^___K<("]Z"HV`^,#,-3G``!3XW"`O1AL,)3E`0`3 +MXW"`O0@D-@/C`S"4YP8`4^-P@+T("P!3XPD`4Q-P@+T(+S8#XP,PU.<``%/C +M<("]&`$@H.,J-@/C`R#$YPD@@N(&,$/B`R"$YP(@H.,,,(/B`R"$YP@P0^(# +M,-3G``!3XP$@H`,T-@/C`R"$YZ0RG^4`$)/E-@R$XC@`@.(%$('B_O__ZW"` +MO>@D-@/C`S"4YPL`4^,)`%,3<("]""\V`^,#,-3G``!3XW"`O1@!,*#C)"8# +MXP(PA.+^___K<("]Z"\V`^,#,-3G``!3XP$@ +MH`,O-@,#`R#$!P4```HV#(3B.`"`XO[__^L`(*#C+S8#XP,@Q.<+(*#C)#8# +MXP,@A.@!(*#C-#8#XP,@A.<`,`#C`#!`XP`0D^4V +M#(3B.`"`XO[__^MP@+WH+S8#XP,PU.<``%/C!0``"C8,A.(X`(#B_O__ZP`@ +MH.,O-@/C`R#$YP(PH.,D)@/C`C"$YS0F`^,",(3G`#``XP`P0.,`$)/E-@R$ +MXC@`@.+^___K<("]Z"XV`^.S,)3A``!3XW"`O1@",(/B)"8#XP(PA.<0((+B +M`C"$YQ`PG^4`$)/E-@R$XC@`@.+^___K<("]Z``````",*#C)"8#XP(PA.@",$'B"P!3XP/QGY=Z`@#JU.H"`-3J`@#H +M[`(`Z.P"`/#K`@!<\0(`<.D"`*3M`@`$[P(`I.T"`(#O`@!H\`(`CS8#XP,P +MU.<``%/C$P``"@`@H../-@/C`R#$Y]H-A.(8`(#B_O__ZP(PH..4)@/C`C"$ +MYQ`@0N(",(3GB#8#XP,PU.<``%/C!```"D`Q'^4`$)/E-@R$XC@`@.+^___K +M+38#XP,PU.<``%/C<("]&"0V`^,#,)3G!@!3XW"`O0@+`%/C"0!3$W"`O0@O +M-@/C`S#4YP``4^-P@+T8*C8#XP,PU.+^___K<("]Z`$@H.,T +M-@/C`R"$YSPR'^4`$)/E-@R$XC@`@.(*$('B_O__ZW"`O>@"`%'C%P``&H\V +M`^,#,-3G``!3XQ,```H`(*#CCS8#XP,@Q.?:#83B&`"`XO[__^L",*#CE"8# +MXP(PA.<0($+B`C"$YX@V`^,#,-3G``!3XP0```JL,A_E`!"3Y38,A.(X`(#B +M_O__ZRLV`^,#,-3G``!3XW"`O1@D-@/C`S"4YP8`4^-P@+T("P!3XPD`4Q-P +M@+T(+S8#XP,PU.<``%/C<("]&"HV`^,#,-3G`0!3XP4``!HV#(3B.`"`XO[_ +M_^L`(*#C*C8#XP,@Q.+^___K +M<("]Z!@UU.4``%/C`@``"FPPE.4!`!/C<("]&"XV`^,#,-3G``!3XW"`O1@D +M-@/C`S"4YPL`4^,)`%,3<("]""\V`^,#,-3G``!3XW"`O1@K-@/C`S#4YP$` +M4^,%```:-@R$XC@`@.+^___K`""@XRLV`^,#(,3G*C8#XP,PU.B/-@/C`S#4YP`` +M4^,3```*`""@XX\V`^,#(,3GV@V$XA@`@.+^___K`C"@XY0F`^,",(3G$"!" +MX@(PA.>(-@/C`S#4YP``4^,$```*=#4?Y0`0D^4V#(3B.`"`XO[__^LO-@/C +M`S#4YP``4^-P@+T8*S8#XP,PU.@!(*#C-#8#XP,@A.=L +M-A_E`!"3Y38,A.(X`(#B"A"!XO[__^MP@+WH+S8#XP,PU.<``%/C!0``"C8, +MA.(X`(#B_O__ZP`@H.,O-@/C`R#$YP$@H.,K-@/C`R#$YP0@H.,D-@/C`R"$ +MYR@V`^,#,-3G``!3XP(@H!,!(*`#-#8#XP,@A.<`,`#C`#!`XP`0D^4V#(3B +M.`"`XF00@>+^___K<("]Z"\V`^,#,-3G``!3XP4```HV#(3B.`"`XO[__^L` +M(*#C+S8#XP,@Q.(`,`#C`#!`XP`0D^4%`*#A9!"! +MXO[__^N/-@/C`S#4YP``4^,!(*`#CS8#`P,@Q`<"```*V@V$XA@`@.+^___K +M"R"@XX0V`^,#((3GB#8#XP,PU.<``%/C`B"@$P$@H`.4-@/C`R"$YP`P`.,` +M,$#C`!"3Y04`H.$*$('B_O__ZW"`O>@O-@/C`S#4YP``4^,%```*-@R$XC@` +M@.+^___K`""@XR\V`^,#(,3G`2"@XRLV`^,#(,3G!""@XR0V`^,#((3G*#8# +MXP,PU.<``%/C`B"@$P$@H`,T-@/C`R"$YS9+^___KCS8#XP,PU.<``%/C`2"@`X\V`P,#(,0'`@``"MH-A.(8 +M`(#B_O__ZPP@H..$-@/C`R"$YPH@H..0-@/C`R"$YX@V`^,#,-3G``!3XP(@ +MH!,!(*`#E#8#XP,@A.<`,`#C`#!`XP`0D^4%`*#A"A"!XO[__^MP@+WH`C"@ +MXR0F`^,",(3G-"8#XP(PA./-@/C`S#4YP``4^,% +M```*V@V$XA@`@.+^___K`""@XX\V`^,#(,3G`""@XY0V`^,#((3G!`"@X38< +MA.(<$('B'?G_ZP0`H.'9'83B/!"!XAGY_^MP@+WH!`"@X4;Y_^MP@+WH`0!1 +MXW"`O3@#`%'C`@``F@<`4>-P@+T8#@``ZC94!`%/C`@``"@(`4^,8```:$0`` +MZMDX`^,#,-+G``!3XP8```I.$*#C_O__ZP0`H.%.$*#CX""@X_[__^L,``#J +M3!"@X_[__^MP(`#B!`"@X4P0H./^___K!0``ZDT0H./^___K<"``X@0`H.%- +M$*#C_O__ZP$PH.,,,,7E<("]Z/!!+>D`0*#A`%"0Y=`[`^,#,)7G`0!3X_"! +MO0C,.P/C`S"5YP$`4^/P@;T(W#8#XP,PE><&`%/C`_&?ER,$`.I$]`(`W/4" +M`/CY`@#H^P(`S/X"`"@"`P!8!`,`&#"0Y0$`4^,#```:!0"@X000H.&T___K +M`@``Z@4`H.$$$*#AJ_C_ZQ0@E.4!($+B%""$Y0@PE.4(`%/C!P``"@D`4^,1 +M```*`P!3XP$PH!,0```:`3!RX@`PH#,-``#J;#"5Y0$`$^,`,*`#!```"B`` +M$^,,```:0``3XPH``!K3,>#G``!2XP0```H!``#J`3!RX@`PH#,``%/C$``` +M"FPPE>4!`!/C"0``"@PPU.4``%/CX0,`&@4`H.$$$*#AB?__ZP(``.H%`*#A +M!!"@X8#X_^L`,*#C%#"$Y0XPQ.7P@;WH&#"4Y0$`4^,",*`#`3"@$Q@PA.4( +M,)3E`S!#X@8`4^,#\9^7&P``ZFSU`@"(]0(`P/4"`,#U`@#`]0(`B/4"`*3U +M`@``,`#C`#!`XP`0D^4<`(3B"A"!XO[__^OP@;WH`#``XP`P0.,`$)/E'`"$ +MXA00@>+^___K\(&]Z``P`.,`,$#C`!"3Y1P`A.(H$('B_O__Z_"!O>@`,`#C +M`#!`XP`0D^4<`(3B%!"!XO[__^OP@;WH.SR@XP-PE>?9;87B/&"&XDPPU^4& +M`%/C!D"@`1@PE.4!`%/C`P``&@4`H.$$$*#A1___ZP(``.H%`*#A!!"@X3[X +M_^M,,-?E``!3XR<``!IL,)7E`0`3XQ(```J)-@/C`S#5YP``4^,&```:!0"@ +MX080H.$V___K`2"@XXDV`^,#(,7G&0``ZH@V`^,#,-7G``!3XQ4``!H%`*#A +M!A"@X2O__^L1``#JB38#XP,PU><``%/C!@``&@4`H.$&$*#A'OC_ZP$@H..) +M-@/C`R#%YP8``.J(-@/C`S#5YP``4^,"```*!0"@X080H.$3^/_KV#,#XP,P +ME><``%/C!0``"@4`H.$$$*#A#/C_ZP0`H.&Z]__K\(&]Z`@PE.4#,$/B"`!3 +MXP/QGY=K`P#J7/<"`"SW`@"X!`,`C/<"`+@$`P"X!`,`4/D"`&SX`@"`^0(` +M###4Y0``4^,",*`3`3"@`Q@PA.4`,`#C`#!`XP`0D^4<`(3B9!"!XO[__^OP +M@;WH###4Y0``4^,",*`3`3"@`Q@PA.4`,`#C`#!`XP`0D^4<`(3B,A"!XO[_ +M_^OP@;WH%#"4Y0$P0^(4,(3E``!3XR8``!IL,)7E`3`#X@$`4^,.```:$##$ +MY0,PH.,(,(3E###4Y0``4^,",*`3`3"@`Q@PA.4`,`#C`#!`XP`0D^4<`(3B +M,A"!XO[__^L0``#J``!3XPX``!H!,*#C#S#$Y00PH.,(,(3E###4Y0``4^," +M,*`3`3"@`Q@PA.4`,`#C`#!`XP`0D^4<`(3B9!"!XO[__^L`,*#C$C#$Y?"! +MO>@,,-3E``!3XP(PH!,!,*`#&#"$Y0`P`.,`,$#C`!"3Y1P`A.(2$('B_O__ +MZ_"!O>@4,)3E`3!#XA0PA.4``%/C)P``&FPPE>4!,`/B`0!3XPX``!H0,,3E +M`S"@XP@PA.4,,-3E``!3XP(PH!,!,*`#&#"$Y0`P`.,`,$#C`!"3Y1P`A.(R +M$('B_O__ZQ```.H``%/C#@``&@$PH.,/,,3E!#"@XP@PA.4,,-3E``!3XP(P +MH!,!,*`#&#"$Y0`P`.,`,$#C`!"3Y1P`A.)D$('B_O__ZP`PH.,4,(3E#C#$ +MY?"!O>@,,-3E``!3XP(PH!,!,*`#&#"$Y0`P`.,`,$#C`!"3Y1P`A.(%$('B +M_O__Z_"!O>@,,-3E``!3XP(PH!,!,*`#&#"$Y0`P`.,`,$#C`!"3Y1P`A.(2 +M$('B_O__Z_"!O>@8,)3E`0!3XQ$```H!,*#C$##$Y0,PH.,(,(3E###4Y0`` +M4^,",*`3`3"@`Q@PA.4`,`#C`#!`XP`0D^4<`(3B,A"!XO[__^L`,*#C$S#$ +MY?"!O>@",*#C&#"$Y0`P`.,`,$#C`!"3Y1P`A.)]'X'B_O__Z_"!O>@8,)#E +M`0!3XP,``!H%`*#A!!"@X4?^_^L"``#J!0"@X000H.$^]__K"#"4Y08`4^," +M```*"@!3X_"!O1@U``#J%#"4Y0$P0^(4,(3E``!3XQP``!K8,P/C`S"5YP`` +M4^,#```*!0"@X000H.$L]__K$0``ZFPPE>4!,`/B`0!3XP4``!H(,(3E&#"$ +MY04`H.$$$*#A)_[_ZP<``.H``%/C!0``&@(PH.,(,(3E&#"$Y04`H.$$$*#A +M&??_ZP`PH.,2,,3E\(&]Z-@S`^,#,)7G``!3XP,```H%`*#A!!"@X0_W_^OP +M@;WH###4Y0``4^,",*`3`3"@`Q@PA.4`,`#C`#!`XP`0D^4<`(3B$A"!XO[_ +M_^OP@;WH%#"4Y0$P0^(4,(3E``!3XQP``!K8,P/C`S"5YP``4^,#```*!0"@ +MX000H.'V]O_K$0``ZFPPE>4!,`/B`0!3XP4``!H(,(3E&#"$Y04`H.$$$*#A +M\?W_ZP<``.H``%/C!0``&@(PH.,(,(3E&#"$Y04`H.$$$*#AX_;_ZP`PH.,. +M,,3E\(&]Z-@S`^,#,)7G``!3XP,```H%`*#A!!"@X=GV_^OP@;WH###4Y0`` +M4^,",*`3`3"@`Q@PA.4`,`#C`#!`XP`0D^4<`(3B!1"!XO[__^OP@;WH&#"0 +MY0$`4^,#```:!0"@X000H.'+_?_K!0``Z@@PD.4+`%/CG0``"@4`H.$$$*#A +MO_;_ZP@PE.4&,$/B!0!3XP/QGY4!,`/B`0!3XP@``!H(,(3E&#"$Y0PPU.4``%/C#@`` +M&@4`H.$$$*#AH/W_ZPH``.H``%/C"```&@(PH.,(,(3E&#"$Y0PPU.4``%/C +M`@``"@4`H.$$$*#AC_;_ZP`PH.,2,,3E\(&]Z-@S`^,#,)7G``!3XP,```H% +M`*#A!!"@X87V_^OP@;WH###4Y0``4^,",*`3`3"@`Q@PA.4`,`#C`#!`XP`0 +MD^4<`(3B$A"!XO[__^OP@;WH%#"4Y0$P0^(4,(3E``!3XR(``!K8,P/C`S"5 +MYP``4^,#```*!0"@X000H.%L]O_K%P``ZFPPE>4!,`/B`0!3XP@``!H(,(3E +M&#"$Y0PPU.4``%/C#@``&@4`H.$$$*#A9/W_ZPH``.H``%/C"```&@(PH.,( +M,(3E&#"$Y0PPU.4``%/C`@``"@4`H.$$$*#A4_;_ZP`PH.,.,,3E\(&]Z-@S +M`^,#,)7G``!3XP,```H%`*#A!!"@X4GV_^OP@;WH###4Y0``4^,",*`3`3"@ +M`Q@PA.4`,`#C`#!`XP`0D^4<`(3B!1"!XO[__^OP@;WH###4Y0``4^,",*`3 +M`3"@`Q@PA.4`,`#C`#!`XP`0D^4<`(3B$A"!XO[__^OP@;WH&#"4Y0$`4^,( +M```:`C"@XQ@PA.4`,`#C`#!`XP`0D^4<`(3B?1^!XO[__^OP@;WHV#,#XP,P +ME><``%/C`P``"@4`H.$$$*#A'?;_ZP4``.H!,*#C"#"$Y1@PA.4%`*#A!!"@ +MX1O]_^L`,*#C$S#$Y?"!O>@8,)#E`0!3XP,``!H%`*#A!!"@X1+]_^L"``#J +M!0"@X000H.$)]O_KCS8#XP,PU><``%/C#```&I0V`^,#,)7G``!3XP@``!H" +M,*#CE"8#XP(PA>>$)@/C`C"%YP4`H.'9'87B/!"!XOCU_^L(,)3E!#!#X@@` +M4^,#\9^76@$`ZG#_`@"X!`,`]/\"`+@$`P"@_P(`3`$#`&```P"@`0,`T`$# +M``PPU.4``%/C`C"@$P$PH`,8,(3E`#``XP`P0.,`$)/E'`"$XF00@>+^___K +M\(&]Z`PPU.4``%/C"```"@(PH.,8,(3E`#``XP`P0.,`$)/E'`"$XA00@>+^ +M___K\(&]Z`$PH.,8,(3E`#``XP`P0.,`$)/E'`"$X@H0@>+^___K\(&]Z!0P +ME.4!,$/B%#"$Y=@S`^,#,)7G``!3XP<```HX,P/C`S"5YP("4^,#``":!0"@ +MX000H.&[]?_K\(&]Z`PPU.4``%/C`C"@$P$PH`,8,(3E`#``XP`P0.,`$)/E +M'`"$XA(0@>+^___K\(&]Z!0PE.4!,$/B%#"$Y0``4^,=```:V#,#XP,PE><` +M`%/C!P``"C@S`^,#,)7G`@)3XP,``)H%`*#A!!"@X9[U_^L.``#J`3"@XP\P +MQ.4$,*#C"#"$Y0PPU.4``%/C`C"@$P$PH`,8,(3E`#``XP`P0.,`$)/E'`"$ +MXF00@>+^___K`#"@XPXPQ.7P@;WHV#,#XP,PE><``%/C!P``"C@S`^,#,)7G +M`@)3XP,``)H%`*#A!!"@X8#U_^OP@;WH###4Y0``4^,",*`3`3"@`Q@PA.4` +M,`#C`#!`XP`0D^4<`(3B!1"!XO[__^OP@;WH###4Y0``4^,(```*`C"@XQ@P +MA.4`,`#C`#!`XP`0D^4<`(3B%!"!XO[__^OP@;WH`3"@XQ@PA.4`,`#C`#!` +MXP`0D^4<`(3B"A"!XO[__^OP@;WH###4Y0``4^,",*`3`3"@`Q@PA.4`,`#C +M`#!`XP`0D^4<`(3B"A"!XO[__^OP@;WH%#"4Y0$P0^(4,(3E``!3XP0``!H, +M,-3E``!3XZ<```H!,*#C%#"$Y0PPU.4``%/C`C"@$P$PH`,8,(3E`#``XP`P +M0.,`$)/E'`"$X@H0@>+^___K\(&]Z!@PD.4!`%/C`P``&@4`H.$$$*#A._S_ +MZP(``.H%`*#A!!"@X3+U_^L(,)3E!@!3XP(```H*`%/C\(&]&#T``.H4,)3E +M`3!#XA0PA.4``%/C(```&M@S`^,#,)7G``!3XPT```HX,P/C`S"5YP("4^,) +M``":`C"@XP@PA.48,(3E###4Y0``4^,/```*!0"@X000H.$6]?_K"P``Z@$P +MH.,(,(3E&#"$Y0PPU.4``%/C!0``&@`P`.,`,$#C`!"3Y1P`A.(%$('B_O__ +MZP`PH.,2,,3E\(&]Z-@S`^,#,)7G``!3XP<```HX,P/C`S"5YP("4^,#``": +M!0"@X000H.'[]/_K\(&]Z`PPU.4``%/C`C"@$P$PH`,8,(3E`#``XP`P0.,` +M$)/E'`"$XA(0@>+^___K\(&]Z!0PE.4!,$/B%#"$Y0``4^,@```:V#,#XP,P +ME><``%/C#0``"C@S`^,#,)7G`@)3XPD``)H",*#C"#"$Y1@PA.4,,-3E``!3 +MXP\```H%`*#A!!"@X=CT_^L+``#J`3"@XP@PA.48,(3E###4Y0``4^,%```: +M`#``XP`P0.,`$)/E'`"$X@40@>+^___K`#"@XPXPQ.7P@;WHV#,#XP,PE><` +M`%/C!P``"C@S`^,#,)7G`@)3XP,``)H%`*#A!!"@X;WT_^OP@;WH###4Y0`` +M4^,",*`3`3"@`Q@PA.4`,`#C`#!`XP`0D^4<`(3B!1"!XO[__^OP@;WH&#"0 +MY0$`4^,#```:!0"@X000H.&O^__K\(&]Z`4`H.$$$*#AIO3_Z_"!O>@!`%/C +M(OS_&A[\_^H*,*#C%#"$Y0$PH.,8,(3E`#``XP`P0.,`$)/E'`"$XC(0@>+^ +M___K\(&]Z!!`+>E0`$#B_O__ZQ"`O>@>_R_A5S#0Y1(`4^,"`*"#`"``DP`@ +M0),#`9*7'O\OX1!`+>D[/*#C`S"0YR``@>+X*`/C`A"3Y_[__^L!`''B``"@ +M,Q"`O>B^P=#A#,B@X1S`@.4`,*#C`R"@X;,0D.$!("+@`C"#XB``4^/Z__\: +M#"""X1P@@.4>_R_A%3#0Y0``4^,>_R\!`B#0Y0``4N,>_R\1`3!#X@0`4^,# +M\9^7&```ZH0%`P"@!0,`H`4#`+P%`P"$!0,`!#"1Y0$U@^,$,('E"#"1Y04!-8/C!#"!Y0@PD>4'-H/C"#"!Y1[_+^$$,)'E`S6# +MXP0P@>4(,)'E!S:#XP@P@>4>_R_A*S#0Y0$`4^,"```*`@!3XP<``!H#``#J +M`#"1Y0$Z@^,`,('E`@``Z@`PD>4".X/C`#"!Y2LPT.4``%/C`#"1%0(Z@Q,` +M,($5'O\OX48PT.4``%/C'O\O`0`PD>5((-#E`0`2XP(DH!,`(*`#`R""X0`@ +M@>5),-#E`0!3XP$F@@,`(($%'O\O`0(`4^,")H(#`""!!1[_+P$``%/C`R:" +M$P`@@14>_R_A`#"@X1X0T.6R(=#A`A"!X!0`D.4*(-/E``!2XQ\@TQ4(`(#B +M`0"`X`(`@.`=,-/E`@!3XP@`@`(>_R_A\$$MZ0)0H.$#8*#A&'#=Y0%`H.$! +M`*#A`!"@XR`@H./^___K`#"4Y2,S@^,"-H/C=5#_Y@50@^$`4(3E!#"4Y1(\ +M@^,$,(3E``!6XP$V@Q,$,(05$#"4!8`P@P,0,(0%##"4!0(Q@P,,,(0%`0!7 +MXP@PE`4"-8,#"#"$!1`PE.4!/(/C$#"$Y00`H.'^___K\(&]Z/A/+>D`8*#A +M`E"@X6APD.4[+*#C`K"7YP%`H.%&H-#E`:`*X@"04^(&```:!P"@X040H.'^ +M___K``!0XPA`A`(!@*`#````"@"`H.,$`*#A`!"@XR`@H./^___K`#"4Y2,S +M@^,"-H/C=5#_Y@50@^$`4(3E``!:XP%4A1,`4(05``!9XP<``!H``%CC!0`` +M"G4PUN5S(*_F``!2XPD``-H!,$/B=3#&Y74PUN5S(*_F``!2XP,]H,$?,P/" +M!""4Q0,P@L$$,(3%$#"4Y0$\@^,0,(3E9#"6Y0\P`^(!`%/C:0``&@B@AN(R +M(-;E/R`"X@0PE.4#((+A!""$Y5#`P,V@Q,4 +M,(3E+#H#XP,PE^<``%/C%#"4%00P@Q,4,(05#```Z@@`4^,*```*!#"4Y08X +M@^,$,(/C!#"$Y;X@UN$`,`#C_S]`XP(X`^`,()3E`S""X0PPA.5-,-;E``!3 +MXP4``!H,,)3E`C&#XPPPA.40,)3E@#"#XQ`PA.4$`*#A_O__ZP<`H.%D$);E +M!""@X?[__^L(`*#A^(^]Z/!/+>DLT$WB!`"-Y1`0C>4[/*#C`S"0YR0PC>7X +M.`/C)!"=Y0,PD><,,(WE``!2XQ@@C>4%```:$`"=Y?[__^L``%#C&`"-Y0`` +MH`/I```*$`"=Y0`0H./^___K$`"=Y8@0D.6,(-#E_O__ZP!04.($```:$`"= +MY1@0G>7^___K``"@X]L``.H8()WE<""%Y1`PDN5L,(7E%%""Y0$PH.-T,,7E +M=3#%Y00`G>5@$)7E!2"@X?[__^L$`)WE!1"@X?[__^L%`*#AL?[_Z]5'U>&$ +M08#@($"$X@>0%.(!D*`3I)&)X(F1H.$,,)WE"0!3X10PC84!$*"#"!"-A0<` +M`(H)`*#A#!"=Y?[__^L,()WED"(@X!0`C>4`,*#C"#"-Y5R@E>4P,-7E!P!3 +MXPL``(K0,]7A`2"@XQ(SH.'``!/C5*"*$@8``!HP`!/C0*"*$@,``!H&`!/C +M+*"*$@```!H8H(KB_O__ZPT0H.%_/<'C/S##XP0@D^4!((+B!""#Y0@@BN(< +M((WE"(":Y2!`C>4`L*#C!6"@X4P``.H(0*#A`("8Y72PQ.5UL,3E!`"@X7?^ +M_^L@<(GB`'"'X`=0%^(!4*`3IU&%X(51H.$%"E7C!0``F@90H.$!,*#C=##$ +MY74PQ.4@<)WE00``Z@P`E.@$,(+E`""#Y0!`A.4$0(3E$#":Y0$P0^(0,(KE +M&!"=Y1`PD>4)D(/@;)"$Y00`G>5@$)3E!""@X?[__^L$`)WE!!"@X?[__^L$ +M`*#A;!"4Y1@@E.4!,*#CA?[_ZQ``G>4$$*#A_O__ZW0PUN4!,(/B4%`%+A"P``F@@0G>4!,('B4D$)WE,2D# +MXP(PT><(()WE`@!3X0@``!H&4*#A$0``Z@4`H.$,$)WE_O__ZPPPG>60,R#@ +M%`"-Y0BPC>4@<(WE!9"@X1P`G>4($*#A_O__ZP``4..M__\*!E"@X2!PG>4` +M``#J!E"@X0@`BN+^___K`0!0XP0``!H,`)KH!#""Y0`@@^4`H(KE!*"*Y0T0 +MH.%_/<'C/S##XP0@D^4!($+B!""#Y?[__^N\,-7ACB@(XP88`.,!`%/A`@!3 +M$04```H+,-7E`0!3XP(```H$`)WE!1"@X?[__^L'`*#A#!"=Y?[__^L``%'C +M!@``&@AP1^)L,)7E"#"#XFPPA>5U,-7E`3!#XG4PQ>4%`*#A;!"5Y1@@E>4! +M,*#C+O[_ZP4`H.'^___K`!"@X00`G>4'(*#A&#"=Y?[__^O5-]7A="#5Y8(B +MH.$`(&+B@R%"X`0`G>4%$*#A!R""X/[__^L0`)WE!1"@X?[__^L!`*#C+-"- +MXO"/O>CP3RWI%-!-X@!0H.$!0*#A!""-Y7`PD>4(,(WE4SV`XB`P@^(,,(WE +M9#"1Y0$`4^,*```:O##1X08H`.,"`%/A!@``"HXH".,"`%/A`P``"@LPT>4! +M`%/C````"O[__^ML8)3E'"#4Y0``4N,T``#:`'"@XS25`>,DO`'C`2!"X@<` +M4N$8@)0%!@``"@F`E><$@$CB"S"5YP``4^,`,*`3'S#4!0B`8^`$`*#A!A"@ +MX0@@H.$`,*#CZ?W_ZP``4.,(8(82;&"$%2"@B!(HH(@"!`"@X?[__^L`$*#A +M!#"=Y0$`4^,$```:!0"@X0H@H.$(,)WE_O__ZP,``.H%`*#A"B"@X0@PG>7^ +M___K!0"@X000H.$((*#A_O__ZP%PA^(<(-3E!P!2X04``-H*8(;@`S`6X@$P +MH!,F88/@!F&@XD!(*#CIO__ +MZQ"`O>@00"WI`""@XZ+__^L0@+WH\$+^___K``!0XR@``,IL +M,)3E(@T3XR4``!H&`*#A_O__ZP!P4.(A```*#2"@X7\]PN,_,,/C!""3Y0$@ +M0N($((/E_O__ZW!PA>40,)?E;#"%Y110A^4$`*#A8!"5Y04@H.'^___K`0!0 +MXP4``!H$`*#A!1"@X0`@H.-T___K`0"@X_"'O>BH`)_EJ!"?Y?[__^L&`*#A +M!Q"@X?[__^L&`*#A!1"@X?[__^L!`*#C\(>]Z`0`H.$%$*#A_O__ZP!PH.$- +M(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K`0!7XP``H`/PA[T(!@"@X040 +MH.'^___K2#4!X].`A.$`8.#C`'#@XP8`F.`'$*G@\P"$X5`U`>/3@(3A`6"@ +MXP!PH.,&`)C@!Q"IX/,`A.$!`*#C\(>]Z,0&``!D%```$$`MZ0`@H.-!___K +M$("]Z!!`+>D`(*#A5@V`X@`0`.,`$$#C_O__ZP$`H.,0@+WH`#"@XSPP@>48 +M,('E"#"!Y1`PD>4``%/C)#"!%1PP@14@,($5#SN#$B@P@14>_R_A<$`MZ0!@ +MH.&(-@'C`T"0YQ)>A.(&`*#A!!"@X?[__^M(0(3B!0!4X?G__QJ$-@'C`P"6 +MYP``4.,!```*21^@X_[__^M9;8;B.`"&XO[__^LL`(;B_O__ZW"`O>CP1RWI +M`$"@X5D-@.(8`(#B`!``XP`00.,$(*#A_O__ZUH-A.(,`(#B_O__ZTD/H./^ +M___KA#8!XP,`A.<``%#C`*"@`T0```H`$*#C22^@X_[__^N$-@'C`U"4YP-0 +MA>(#4,7CB#8!XP-0A.?8<(7B#VN@XP"`H.,%`*#A_O__ZP@`A>+^___K-&"% +MY00`H.$%$*#A_O__ZP"@4.($```*"("%Y0Q`A>4'`%7A2%"%$O#__QH$(*#C +ME#8!XP,@A.=9C83B.#"(XG@F`>,",(3G?"8!XP(PA.<`8*#C6CV@XP-@A.,#8(3G"%P#XR!PH.,%`)3G!1"@X0<@ +MH.'^___K`!!0X@L```H%,)3G%#"!Y:@@D>4',`+B"#!CX@,@@N"H(('EG""1 +MY0,P@N"<,('E"`"@X?[__^L!8(;B"`!6X^K__QH*`*#A\(>]Z$C`D.4`()#E +M.SR@XP,PDN>``%'C!```&@``G.6`,`CC`#!,XP`$@^$>_R_A@0!1XP0``!H` +M`)SE@#``XP(P3.,`!(/A'O\OX0<`4>,``*"#'O\O@0`@G.4")*#A`R&"XW$0 +MX^;C'8'B(!"!X@8`T>4/``#B@`>"X1[_+^$>_R_A'O\OX04PH..T,<#A$3"@ +MX[8QP.$>_R_A$$`MZ0!`H.$`$*#C4""@X_[__^L`,`#C`#!`XP`PA.4`,`#C +M`#!`XP0PA.4`,`#C`#!`XP@PA.4`,`#C`#!`XR@PA.4`,`#C`#!`XS@PA.4` +M,`#C`#!`XPPPA.4`,`#C`#!`XQ`PA.4`,`#C`#!`XQ0PA.4`,`#C`#!`XQ@P +MA.4`,`#C`#!`XRPPA.4`,`#C`#!`XSPPA.4`,`#C`#!`XT`PA.4`,`#C`#!` +MXT@PA.4`,`#C`#!`XTPPA.40@+WH\$4``%#C````"O[__^L!0(3B!%"%X@@`5./W +M__\:!P!6X0,```J@8(;B!E"@X0A`H.'Q___JS#4!XP-@FN=-?8;B('"'X@"` +MH.,*``#J0`"5Y0``4.,````*_O__ZP%`A.($4(7B"`!4X_?__QH'`%;A\(>] +M"*!@AN(&4*#A"$"@X?'__^IP0"WI`#"0Y8@F`>,"0)/G`1"@X[$L`^,"$,/G +MV%"$X@%@H.%$8,3E+`"4Y0``4.,````*_O__ZP4`5.%P@+T(2$"$XO;__^KX +M3RWI`7"@X0*0H.$HL)WE`$"0Y0-0H.$4@)/E9*"4Y,_,,/C!!"3Y0$0@>($$(/E +M!@!7XP?QGY,# +M$)3G`1"!X@,0A.<`,*#CNC'%X1D``.J<-0'C`Q"4YP$0@>(#$(3G`1"@X[H1 +MQ>$2``#JE#4!XP,0E.,#$)3G`1"! +MX@,0A.<#$*#CNA'%X00``.H&,*#CNC'%X0$``.H`$*#CNA'%X0+P(>$-(*#A +M?SW"XS\PP^,$()/E`2!"X@0@@^4`,)/E`@`3XP````K^___K0&"5Y1P`A.(' +M$*#A#___ZVPPF.4HH(;E,`"&Y4`PAN50D(;E`#``XP`P0.-T,(;E<%"&Y08` +MH.$@$*#C_O__ZP``6^,"``"J`0!PX@``H#/XC[WH``!;XP)QX`,"```*"P"@ +MX?[__^L`<*#A`$"@XVQ`A>5P`(7B`!``XP`00./^___K`3"@XV0PQ>5H0(7E +M;`"%X@<0H.'^___K!`!0X6@`E14$```:!@"@X?[__^MH`)7E`@!PXVT`X`,! +M`'#B``"@,_B/O>@$X"WE#-!-XHC#`>,`P(WE(`@+WH!.`MY0S0 +M3>(`P.#C`,"-Y6G__^L,T(WB`("]Z/!!+>D`<*#A<%"0Y0A`E>53;83B(&"& +MXKHQU>$&`%/C`_&?EQP``.KL&`,``!D#`!09`P`H&0,`1!D#`$09`P`\&0,` +MH#4!XP,@E.,# +M()3G`2!"X@,@A.<&``#JF#4!XP,@E.+^___K!@"@X040H.'^ +M___K5CV$X@`0#^&```SQ!""SY0$`@N,``(/E`?`AX0$`$N/P@;T85@V$XO[_ +M_^OP@;WH\$\MZ3303>(`0*#A`8"@X0)@H.$#<*#AO+7=X6"0W>4`4)#E2*"0 +MY=`[`^,#,)7G``!3XVD``!J0,P/C`S#5YP``4^-E```:_@!;XQ5`X(-C``"* +M,""$XB@@C>4"`*#A_O__ZT!`E.480(WE``!4XPM`X`-6```*:#"%XB0PC>4! +M(*#C(""-Y1RPC>4!.D;B48`)WE`!"@XQP@G>7^___K`0!9XP4` +M`!H`0)KE!$2@X0)!A..`0(3CP#"@XP<``.H`0)KE!$2@X0)!A.,8`)WE6!"= +MY1P@G>7^___K0#"@X\``C>@8()WE"""-Y1P@G>4,((WE?2^@XQ`@C>4*`*#A +M!!"@X0@@H.'^___K`$"@X0L`4.$)```:)`"=Y0`0H./^___K`0!9XQL``!I8 +M`)WE&!"=Y1P@G>7^___K%@``Z@``4.,%``"J;`!PXQ,`48$)WE'""=Y?[__^LD`)WE_O__ +MZP0`4.,!(*##T#L#PP,@A<<+``#*+#"=Y?\O`.,"`%/A!P``FAPPG>4#`%3A +M!```"B`@G>4!((+B(""-Y0L`4N.P__\:*`"=Y?[__^L```#J`$#@XP0`H.$T +MT(WB\(^]Z/!!+>D1WDWB`%"@X0&`H.$"8*#A`W"@X1!`C>($`*#A`!"@X_X@ +MH./^___K!%"5Y79@_^8$`*#A!Q"@X08@H.'^___K4`"-Z``PH.,(,(WE!0"@ +MX040H.-X(/_F:___ZQ'>C>+P@;WH!.`MY1S03>($`)#E&#"-X@0@(^5Q(/_F +M`#"-Y00PH.,$,(WE`#"@XP@PC>4%$*#C7/__ZQS0C>(`@+WH!.`MY1S03>($ +M`)#E&#"-XK(@8^%Q(/_F`#"-Y0(PH.,$,(WE`#"@XP@PC>4%$*#C3?__ZQS0 +MC>(`@+WH!.`MY1S03>($`)#E&#"-X@$@8^5Q(/_F`#"-Y0$PH.,$,(WE`#"@ +MXP@PC>4%$*#C/O__ZQS0C>(`@+WH!.`MY1S03>(`,*#C&,"-X@0P+.4$`)#E +M<2#_Y@#`C>4$$*#C!!"-Y0$0H.,($(WE!1"@XR[__^L4`)WE'-"-X@"`O>@$ +MX"WE'-!-X@`PH.,8P(WBLC!LX00`D.5Q(/_F`,"-Y0(0H.,$$(WE`1"@XP@0 +MC>4%$*#C'?__Z[8!W>$4(!,&SE!`"0 +MY7$@_^8`P(WE`1"@XP00C>4($(WE!1"@XPW__^L7`-WE'-"-X@"`O>CP02WI +M`7"@X01@D.4`0);E2("6Y +M```:D",#XP(@U.<``%+C6@``&@-0H.%$,-/E``!3XP(```I`,)7E``!3XP8` +M`!I9#83B+`"`XO[__^M``(7E``!0XP$PH!-$,,45``!5XTH```H$`*#A!1"@ +MX?[__^M$,-7E``!3XP(```I`,)7E``!3XQH``!H('`/C`0"4YR`@H./^___K +M0`"%Y0``4.,Z```*J""0Y06H()/E(""%Y9P@D^4D((7EH""3Y2@@A>6H,)/E$#"%Y0P` +M`.JD,)/E'#"%Y4`PE>6H()/E(""%Y9P@D^4D((7EH""3Y2@@A>6H,)/E$#"% +MY0`PH.-$,,7E63V@XP,@U.4&`*#A!Q"@X2[]_^L0,)7E +M*("$Y3``A.5`,(3E#SN@XU`PA.4`,`#C`#!`XW0PA.5P4(3E!`"@X2`0H./^ +M___K`0"`X@$`4.,``*"#`0"@D_"!O>@``*#C\(&]Z'!`+>D`8*#A<%"0Y0Q` +ME>59/:#C`R#4YP$@0N(#(,3GT#L#XP,PE.<``%/C!P``&LP[`^,#,)3G``!3 +MXP,``!JQ/`/C`S#4YP``4^,"```*`3"@XT0PQ>5P@+WH.#"0Y0``4^,R```: +M5""0Y1@@0N+H.P/C`P!2X0@``)H!,*#C1##%Y00`H.$\-@'C`Q"4YP`@H.,% +M,*#A_O__ZW"`O>AH`(3B`!"@X_[__^M4,);E/#"%Y4``E>54$);E_O__ZUD- +MA.(X`(#B0!"5Y?[__^M:/:#C`S"4YP$`4^,+``"*63V$X@`0#^&```SQ'""S +MY0$`@N,``(/E`?`AX0$`$N,"```:60V$XA@`@.+^___K`""@XT`@A>5$(,7E +M!`"@X3PV`>,#$)3G!3"@X?[__^MP@+WH:`"$XO[__^L$`%#C`2"@P]`[`\,# +M((3'.#"6Y2``<^,+```*!```RFP`<^,(```*1P!SXW"`O1@)``#J$P!SXP,` +M``H"`'/C`0``"A8`<^-P@+T8`2"@X\P[`^,#((3G<("]Z`$PH.-$,,7E!`"@ +MX3PV`>,#$)3G`""@XP4PH.'^___K<("]Z/!'+>D`0*#A4WV`XB!PA^)L,)#E +M`@L3X_"'O1C,6P/CT&L#X[*,`^,`H*#C!3"4YP$`4^/PA[T(!C"4YP$`4^/P +MA[T("##4YP$`4^/PA[T(!`"@X0<0H.$*(*#A_O__ZP``4./P__\:\(>]Z/!/ +M+>D\T$WB`)"@X5D]@.(X$(/B+!"-Y5<@,(WE&#"=Y5!0D^6H<)/E"H#7Y2`0G>6I +M'8'B$!"!XB00C>4`(*#C*""-Y10`G>7^___K`$!0XK,```H<<(WE!`"@X?[_ +M_^L`,*#CB#"$Y70PA.4$`*#A!Q"@X?[__^LR,-3E``!3XP,```H$`*#A%!"= +MY?[__^NC``#J'C#4Y0``4^,%```*63#4Y0``4^,@,-0%&#"#`@,PAP`H,(T% +MO*'4X1]@U.4&8(K@&&"&X@6PH.$%`%;A`#"@DP$PH(,``%KC`3"#`P``4^,# +M```*!`"@X100G>7^___KB@``ZB0PU.4``%/C!C"@$P`PH`,0,(WENC+4X0$, +M4^,.$(H2#!"-%04``!IR%@#C`0!:X1HMH),,((V5#C"*@@PPC84(+`/C`@"9 +MYPP0G>4@(*#C_O__ZP!04.(B```*"!P#XP$PF><4,(7E"%"$Y:@`E>4',`#B +M"#!CX@,`@."<()7E`S""X!`@G>4"`(#@J`"%Y0(P@^"<,(7E'Q#4Y1@0@>(! +M$(?@"B"@X?[__^NH,)7E@#"$Y7PPA.5X,(3EJ""5Y0P0G>4!((+@A""$Y0HP +M@^"`,(3E`@!3X0.@:H"`H(2%"P``B@<``.H8`)WE(!"@X_[__^L(`(3E!`"@ +MX100G>7^___K2```ZG0PE.4*H(/@=*"$Y1XPU.4``%/C!0``"EDPU.4``%/C +M`@``&@0`H.$H$)WE_O__ZR`0G>4X*0/C`C"1YP(`4^,)```*`P!3XP$```H! +M`%/C"@``&G\P%N(!,*`3IF.#X(9CH.%V8/_F!```Z@,P%N(!,*`3)F&#X`9A +MH.%V8/_F63#4Y0``4^,"```:!`"@X?[__^L0``#J`0!3XP(``!HT`)WE_O__ +MZP@``.H"`%/C!@``&GP0E.6\(=3A7#"4Y6``E.4``(WE)`"=Y?[__^L$`*#A +M%!"=Y?[__^L!@$CB>(#_Y@M09N```%7C`#"@TP$PH,,``%CC`""@$P$@`P(` +M`%+C'""=%0J`TA4``%CC`#"@`P$P`Q(``%/C!G"'$$?__QH8$)WEJ#"1Y9PP +M@>4`(*#C4""!Y3``G>48$)WE_O__ZRP`G>7^___K``!0XQ@`C>4B__\:/-"- +MXO"/O>A7,-#E$@!3XQ$``(K7-=#A`2"@XQ(CH.'`,`#C!S!`XP,P`N```%/C +M!`"@$Q[_+Q$P`!+C"```&@8`$N,$```*:""0Y0(_`N,#,-+G``!3XP$``!H& +M`*#C'O\OX04`H.,>_R_A,$`MZ0S03>(!0*#A`E"@X0T0H.,'((WB;#L#XP_@ +MH.$#\)#G!S#=Y0$`4^,$```:#T`$X@$`5.,`0*`3`4"@`P4``.H"`%/C(@`` +M&@]`!.(#`%3C`$"@$P%`H`,``%3C'```"G1`G^4$`*#A_O__ZVP`G^4`$)7E +M_O__ZV0`G^4$$)7E_O__ZUP`G^4($)7E_O__ZU0`G^4,$)7E_O__ZTP`G^40 +M$)7E_O__ZT0`G^44$)7E_O__ZSP`G^48$)7E_O__ZS0`G^4<$)7E_O__ZP0` +MH.'^___K#-"-XC"`O>CT!@``'`<``"P'```\!P``3`<``%P'``!L!P``?`<` +M`(P'```%,*#C&#"`Y0`@H.,`,*#C\"'`X1[_+^$>_R_A'O\OX1[_+^$>_R_A +M'O\OX1[_+^$>_R_A'O\OX1[_+^$!`*#C'O\OX1!`+>D!`*#A_O__ZQ"`O>@0 +M0"WI$""!Y10`@>4!`*#A`!"@XP$@H.'^___K$("]Z!!`+>D`,`#C`#!`XP`P +MD^5D`*#CD`("X-/-!.-BP$'CG`*"X`$`H.$B$X/@_O__ZQ"`O>@00"WI_O__ +MZQ"`O>@00"WI_O__ZQ"`O>@00"WI_O__ZQ"`O>@00"WI_O__ZQ"`O>@00"WI +M_O__ZQ"`O>@00"WI`0"@X0(0H.$#(*#A_O__ZQ"`O>@00"WI`0"@X0(0H.'^ +M___K$("]Z!!`+>D!0*#A`@"@X?[__^L``(3E$("]Z!!`+>D``)#E_O__ZQ"` +MO>@$X"WE#-!-X@``D.40P)WE`,"-Y?[__^L,T(WB`("]Z!!`+>D``)#E_O__ +MZQ"`O>@00"WI``"0Y?[__^L0@+WH$$`MZ0``D.7^___K$("]Z!!`+>D``)#E +M_O__ZQ"`O>@00"WI``"0Y?[__^L0@+WH$$`MZ0``D.7^___K$("]Z!!`+>D` +M`)#E_O__ZQ"`O>@00"WI``"0Y?[__^L0@+WH$$`MZ0``D.7^___K$("]Z!!` +M+>D``)#E_O__ZQ"`O>AP,._F8R"#XG(@[^9V`%+C``"@@Q[_+X$``%#C9`"@ +MHV0P@[)S`.^V'O\OX0``H.,>_R_A``"@XQ[_+^$D(-#E`2!"XG(@[^8!`%+C +M+```B@$PH.$S($'B,0!2XV0PH),G``":*2!#X@D`4N.!,*"1(P``FA\@0^() +M`%+C)#"!DA\``)H5($/B"0!2XR(P@9(;``":"B!#X@H`4N,'``"*"A!!XH$0 +MH.%6)07C525%XY(!P^#!/T/@*C"#XA```.H%($/B!`!2XP4``(J!$('@#S!! +MXJ,_@^##,*#A%C"#X@<``.H!,$/B`P!3XP$PH($!$$&2@1"!D*$?@9#!,*"1 +M!C"#D@,`H.$>_R_A$$`MZ1\PT.4(`%/C#```&B0PT.4``%/C!```"C,PT.4* +M`%/C!@``&O[__^L0@+WH,S#0Y1,`4^,!```:_O__ZQ"`O>C^___K$("]Z``` +MH.,>_R_A\$\MZ1303>(`0*#A`6"@X0.`H.$"4*#A`##3Y0,`4^,`,*"#`3"@ +MDPPPC>4`,.#C`C#!Y0,PP>4,`)WE``!0XQ4!``JV/Z#CTP"$X0&@H.,`L*#C +M"@"0X`L0H>#S`(3A'+#4Y060TN4H,)3E,``3XVT```H?,`GBJ9*@X0<`6>,) +M\9^73P``ZN0K`P#0*P,`@"L#`&`K`P!`*P,`("L#```K`P#4*@,`&P!3XYP` +MH(,(`(V%_S1CDO\X@Y+_/(.2Z3"#DH,PH)%S,.^6"#"-E3P``.K_-&/B_SB# +MXO\\@^+J,(/B@S"@X7,P[^8(,(WE-```ZO\T8^+_.(/B_SR#XO(P@^*#,*#A +M4L``#J_S1CXO\X@^+_/(/B]3"#XH,PH.%S,._F"#"-Y20``.K_ +M-&/B_SB#XO\\@^+[,(/B@S"@X7,P[^8(,(WE'```Z@``6^,(```*`S#@X8.@ +MH.$&H(KB>J#OY@B@C>5Z`*_F_O__ZP!PH.&7``#J`C!CXH.@H.$&H(KB>J#O +MY@B@C>5Z`*_F_O__ZP!PH.$1``#J!*!CXHJ@H.%ZH._F"*"-Y0,``.H'H&/B +MBJ"@X7J@[^8(H(WE"!"=Y0:@@>)ZH._F"*"-Y7H`K^;^___K`'"@X0``6^-\ +M```:3P!7XP4``)I0<$?BAS"@X5`P@^*G<(/@_W`'X@0``.H4,$?B2=W#OEF0`5^-L``"*;```Z@``6^,D```:*3.@X0,`4^,#\9^7/P`` +MZN`L`P#`+`,`H"P#`(`L`P`^H`GB_Z1JXO^HBN+_K(KBTJ"*XGJ@[^8(H(WE +M,P``ZCZ@">+_I&KB_ZB*XO^LBN+FH(KB>J#OY@B@C>4K``#J/J`)XO^D:N+_ +MJ(KB_ZR*XO2@BN)ZH._F"*"-Y2,``.H^H`GB$*!JXGJ@[^8(H(WE'@``ZMDR +MX><#`%/C`_&?EQH``.I<+0,`1"T#`"PM`P`4+0,`'S`)XBV@X..#H$K@>J#O +MY@B@C>40``#J'S`)XAF@X..#H$K@>J#OY@B@C>4*``#J'S`)X@N@X..#H$K@ +M>J#OY@B@C>4$``#J'Z`)XHJ@H.$0H&KB>J#OY@B@C>4(()WE<@"OYO[__^L` +M<*#A+S#4Y0$`4^,4```:@``9XP0``!I>`%#C!G"`DG=P[Y8(``":%P``ZB8` +M4.,0<$""=W#OA@,``(H0`%?C5W'GEPQP1X)W<.^&&C!'XG,P[^8B`%/C!G"' +MDG=P[Y8*``#J8P!0XPAP0()W<.^&!@``BC,P1^)S,._F$0!3XP1PAY)W<.^6 +M````ZF1PH.,`<,;E"'#&Y0@PG>4',,;E`C#8Y0``4^.S```*'S#4Y0@`4^,) +M```:,S#4Y1,`4^,&```:`#"@XP`PC>4$`*#A#!"=Y0<@H.'R_O_K%0``ZB@` +M5^,"``":-##4Y0``4^,/```*!##5Y4``4^,``*"##```BA,`4^,)``":0#!C +MXF0@H..2`P/@Z2(*XXLN0N.2H\#@PS^@X<`!8^!P`._F````ZF0`H.,!`,;E +M`@#&Y0`PX.,#,,;EBP``ZBX^H.,!H*#C`+"@X],`A.$*`)#@"Q"AX/,`A.$! +ML*#C`*"@XPB@C>4*D*#A!G"@X0)@H.$#``#J`:"*XGJ@[^8!L(OB>[#OY@I0 +MH.$=,-3E4SJ@X0$`$^,(`)T5`3"`$G,P[Q8(,(T5"@#6YS\``.(W`$#B@`"@ +MX7``[^8*,(?@"@##Y7``K^;^___K"9"`X'F0[^8O,-3E`0!3XQ```!H*,-;G +M@``3XP4```I>`%#C9`"@@P8`@))P`.^6!```F@<``.H0`%#CT`'GEQ``0()P +M`.^&!#!`XG,P[^8>`%/C`P"@D04PA^`$`,/E!2"&X`\@TN6B(*#A!5"$X,@B +MQ>4,(,/E`C#8Y0``4^,/```*'S#4Y0@`4^,,```:,S#4Y1,`4^,)```:``!: +MXP<``!H``(WE!`"@X0P0G>4`(*#C`C"@X83^_^L!`,?EN?__Z@$`6^.W__^: +M!E"@X0=@H.$$<-7EIW"@X6YP1^)W<._F=P"OYO[__^L``,;E"`#&Y09PQN4' +M<,;E'S#4Y0@`4^,"```:,S#4Y1,`4^,Z```*``#8Y10`0.)P`._F!P!0XP(` +MH),!`*"#!2"@X0`PH.-DP*#CW1#2X<$?`>!Q<._F(`!QXP4``+H`$&?B@1"! +MX'$0[^9Q<*_F8P!7XP```!H,$*#A`G#8Y0``5^,%```*<1#OYG-P[^8``%?C +M`1#&!0-PAN`"$,?E`3"#X@$@@N)S$._F`0!0X>7__XH6``#J!`"@X0<0H.'^ +M___K"0#&Y08``.H)`*#A"!"=Y?[__^MP$._F!`"@X?[__^L)`,;E&S#5Y=,S +MX.?Z,L3E&S#5Y5,SX.?[,L3E&S#5Y5,PX.?\,L3E%-"-XO"/O>@($)WE``!1 +MX_'__PKI___J'O\OX?A/+>D!,-+E_P!3X_B/O0@#P8#@G$"4`8)/E!5"&X`!0@^4! +M,-+E[#"#XI,,(^`,,(/@``"3Y0$`@.(``(/E#@``ZN0P@^($P*#CDPPCX`PP +M@^``4-'E`&"3Y050AN``4(/E`3#2Y?0P@^*3#"/@##"#X```D^4!`(#B``"# +MY0``TN446)3E&&B4Y0,PTN4``%/C`@``&@0PTN4``%/C^(^]"`,`4.,M``": +M!3#1Y0``4^,$,-$%#@``"@0@T>4"`%/A`@"@(0,@H"$#`*`Q`C"@X0(@8.`" +M`%+C!0``V@4`4N,!,$/2`@``V@D`4N,",$/2`S!#P@``5N,`8-'5#0``V@`@ +MT>4&`%+AAB&&X()@AN`&,(/@9R8&XV8F1N.2$\:`PS^@@<9A8X`!8(:"DA/" +MD,,_H)'"86.0@CZ@X],`A.$`H)#@`;"AX`&`H.,`D*#C"`"*X0D0B^'S`(3A +M%0``Z@``5>,`4-'5#0``V@`PT>4%`%/AA2&%X()0A>`#,(7@9R8&XV8F1N.2 +M$\6`PS^@@<518X`!4(6"DA/"D,,_H)'"46.0@CZ@X],`A.$`@)#@`9"AX/.` +MA.$H&-3E/P!1XP<``)I`$*#C*!C$Y00PH.$@B+/E!`"3Y0`PH.,#P*#A!0`` +MZ@$0@>)Q$._F*!C$Y0``4>/T__\:&P``ZB!P8^(X(Z#A$">"X2!P4^(P)Z!1 +M`2`"X@+`C.`!,(/B,$```*`0!LX)8,#."5P"#@_O__ZP`` +M`.H``*#C%%B$Y1AHA.40"(3E^(^]Z```TN446)3E&&B4Y8#__^H>_R_A'O\O +MX1!`+>DH,)#E$`!3XP```!K^___K``"@XQ"`O>@00"WI`$"@X2@PD.40`%/C +M5```&@``4>,!```:_O__ZP(``.H!`%'C````&O[__^L0,)3E``!3XTH``*H8 +M,)3E`P!3XT<``)HH,)3E`@!3XP(``!H4`9_E_O__ZQ<``.H$`%/C`@``&@0! +MG^7^___K$@``Z@@`4^,"```:]`"?Y?[__^L-``#J$`!3XP(``!KD`)_E_O__ +MZP@``.H@`%/C`@``&M0`G^7^___K`P``ZD``4^,!```:Q`"?Y?[__^O``)_E +MP!"?Y?[__^L0,)3E``!3XR,``*H8,)3E`P!3XR```)HH,)3E`@!3XP(``!IX +M`)_E_O__ZQ<``.H$`%/C`@``&F@`G^7^___K$@``Z@@`4^,"```:6`"?Y?[_ +M_^L-``#J$`!3XP(``!I(`)_E_O__ZP@``.H@`%/C`@``&C@`G^7^___K`P`` +MZD``4^,!```:*`"?Y?[__^LL`)_E)!"?Y?[__^L``*#C$("]Z)P'``"H!P`` +MM`<``,0'``#4!P``X`<``.P'``!X%```-`@``'!`+>D`0*#A`E"@X1`PD.4` +M`%/C(P``JA@PD.4#`%/C(```FB@PD.4"`%/C`@``&FP"G^7^___K%P``Z@0` +M4^,"```:7`*?Y?[__^L2``#J"`!3XP(``!I,`I_E_O__ZPT``.H0`%/C`@`` +M&CP"G^7^___K"```ZB``4^,"```:+`*?Y?[__^L#``#J0`!3XP$``!H<`I_E +M_O__ZQ@"G^48$I_E_O__ZR@PE.40`%/C40``&@``5>,!```:!`"@X?[__^L0 +M,)3E``!3XW(``*H8,)3E`P!3XTH``)HH,)3E`@!3XP(``!JT`9_E_O__ZQ<` +M`.H$`%/C`@``&J0!G^7^___K$@``Z@@`4^,"```:E`&?Y?[__^L-``#J$`!3 +MXP(``!J$`9_E_O__ZP@``.H@`%/C`@``&G0!G^7^___K`P``ZD``4^,!```: +M9`&?Y?[__^MH`9_E8!&?Y?[__^L0,)3E``!3XTL``*H8,)3E`P!3XR,``)HH +M,)3E`@!3XP(``!H8`9_E_O__ZQ<``.H$`%/C`@``&@@!G^7^___K$@``Z@@` +M4^,"```:^`"?Y?[__^L-``#J$`!3XP(``!KH`)_E_O__ZP@``.H@`%/C`@`` +M&M@`G^7^___K`P``ZD``4^,!```:R`"?Y?[__^O0`)_EQ!"?Y?[__^L0,)3E +M``!3XR0``*H8,)3E!`!3XR$``)HH,)3E`@!3XP(``!I\`)_E_O__ZQ<``.H$ +M`%/C`@``&FP`G^7^___K$@``Z@@`4^,"```:7`"?Y?[__^L-``#J$`!3XP(` +M`!I,`)_E_O__ZP@``.H@`%/C`@``&CP`G^7^___K`P``ZD``4^,!```:+`"? +MY?[__^LX`)_E*!"?Y04@H.'^___K``"@XW"`O>BD`0*#A`6"@X0-0H.'^ +M___KZ#74Y0$`4^,*```:`S#5Y0``4^,"```:!##5Y0``4^-P@+T(!`"@X0$0 +MU>4&(*#A_O__ZW"`O>@$`*#A!A"@X04@H.'^___K<("]Z!!`+>G^___K$("] +MZ"\`4>,!\9^74```ZJ`Z`P"8.@,`J#H#`+`Z`P"X.@,`P#H#`,@Z`P#0.@,` +MX#H#`.@Z`P#P.@,`^#H#```[`P`(.P,`$#L#`!@[`P`<.P,`'#L#`!P[`P`< +M.P,`'#L#`!P[`P`<.P,`'#L#`!P[`P`<.P,`'#L#`!P[`P`<.P,`'#L#`!P[ +M`P`<.P,`'#L#`!P[`P`<.P,`'#L#`!P[`P`<.P,`'#L#`!P[`P`<.P,`'#L# +M`!P[`P`<.P,`'#L#`!P[`P`<.P,`V#H#`"`@@.4>``#J'R#`Y1P``.HD(,#E +M&@``ZID@P.48``#J*""`Y18``.HL(,#E%```ZBT@P.42``#J+B#`Y1```.H\ +M(,#E#@``ZB\@P.4,``#J,"#`Y0H``.HQ(,#E"```ZC(@P.4&``#J,R#`Y00` +M`.HT(,#E`@``ZC4@P.4```#J-B#`Y0PPH./@/<#EX3W`Y0`PH./C/<#E'O\O +MX1`00>(6`%'C`?&?ET,``.J@.P,`J#L#`+`[`P"X.P,`P#L#`,@[`P#0.P,` +MV#L#`.`[`P#H.P,`\#L#`/@[`P``/`,`"#P#`!`\`P`8/`,`(#P#`"@\`P`P +M/`,`.#P#`$`\`P!(/`,`4#P#`$0@@.4>_R_A2""`Y1[_+^%,((#E'O\OX5`@ +M@.4>_R_A5""`Y1[_+^%8((#E'O\OX5P@@.4>_R_A8""`Y1[_+^%D((#E'O\O +MX6@@@.4>_R_A;""`Y1[_+^%P((#E'O\OX70@@.4>_R_A?""`Y1[_+^%X((#E +M'O\OX8`@@.4>_R_AA""`Y1[_+^&(((#E'O\OX?@E@.4>_R_A_"6`Y1[_+^$` +M)H#E'O\OX8P@@.4>_R_AD""`Y1[_+^$P`%'C`@&``)PP@`4>_R_A`1!!XBT` +M4>,!\9^700``ZC`]`P"`/0,`@#T#`(`]`P"`/0,`@#T#`#@]`P"`/0,`@#T# +M`(`]`P"`/0,`@#T#`(`]`P"`/0,`@#T#`(`]`P"`/0,`@#T#`(`]`P"`/0,` +M@#T#`(`]`P"`/0,`@#T#`(`]`P"`/0,`@#T#`(`]`P"`/0,`@#T#`(`]`P"` +M/0,`@#T#`(`]`P"`/0,`@#T#`(`]`P"`/0,`0#T#`$@]`P!0/0,`6#T#`&`] +M`P!L/0,`=#T#`'P]`P`@((#E'O\OX2X@P.4>_R_AE"#`Y1[_+^&5(,#E'O\O +MX98@P.4>_R_AER#`Y1[_+^$0((#E%#"`Y1[_+^$8((#E'O\OX4$FP.4>_R_A +M0B;`Y1[_+^%@,)#E`##3Y0$`4^,1```:6#"0Y0`PT^4!`%/C!P``&F0PD.4` +M,-/E`C!#XAXPP.4`(*#A`#"@XP/`H.$)``#J`@!3XV0PD`4`,-,%`C"#`AXP +MP`7U___J9#"0Y0`PT^4>,,#E\?__ZIP0DN4``%'C`<",$GS`[Q8!,(/B_R_A``!1XP`D@`4>_R\! +M`0!1X_PC@`4>_R\!!0!1XP$PH`/X,\`%'O\O`08`4>,`,*`#^#/`!1[_+P$" +M`%'C`P``&AX`4N,>(*`C$B3`Y1[_+^$#`%'C`P``&@``4N,!(*`#%B3`Y1[_ +M+^$$`%'C'O\O$5``4N-0(*`C%23`Y1[_+^$O`%#C'O\OP3`P8.('`%/C,`"@ +MTP@`@,(>_R_A`C"@XS`TP.4Q-,#E,C3`Y3,TP.4`,*#C-#2`Y3@TP.4>_R_A +M`#"@XV_R_A`#"@XW@U@.5\-8#EZ#7`Y0`@X.-8)<#E8C7`Y54PX.-E +M-<#E'O\OX2`PD.5``!/C'O\O`68UT.4!`%/A'O\O$6`UT.4"`%/C!P``&@`P +MTN5P)9#E`S""X'`U@.5X-9#E`3"#XG@U@.4>_R_A`##2Y70ED.4#,(+@=#6` +MY7PUD.4!,(/B?#6`Y1[_+^$>_R_A'O\OX4`VT.4!`%/C`#"@$S\VP.4`,*#C +M0S;`Y3(PH.-!-L#E%#"@XT(VP.4>_R_A'O\OX1[_+^$>_R_A'O\OX0`@D.4[ +M/*#C`S"2YP`@H.-$&@+C`2##YT4:`N,!(,/G1AH"XP$@P^<>_R_A'O\OX1[_ +M+^$>_R_A'O\OX1[_+^$>_R_A'O\OX1[_+^$>_R_A``"@XQ[_+^$>_R_A`3"@ +MXUXVP.4`(*#C7";`Y5TFP.5?-L#E'O\OX1!`+>G^___K$("]Z![_+^$>_R_A +M<`#_Y@`P`.,`,$#CMC'3X0,`4.$,``":`#``XP`P0.,!(*#COA+3X0$`4.$' +M``":`2""XG(@[^88,(/B"`!2X_?__QI@`*#C'O\OX0`@H.,`,`#C`#!`XX(0 +M@N"!,8/@L##3X0,`4.$`,*"3#```F@`P`.,`,$#C@A""X($1@^`!,*#CLL#1 +MX0P`4.$$``":`3"#XG,P[^8"$('B#`!3X_?__QJ"((+@`C&#X`$`@^(>_R_A +M'O\OX0$PH.-L-<#E;37`Y1[_+^'P1RWI`*"@X0&`H.$"<*#A`&!3XO"'O0@` +M0*#C!%"@X0"0X.,*`*#A!!"8YPD@H.$$,)?G_O__ZP%0A>($0(3B!@!5X?;_ +M_QKPA[WH$$`MZ0$PH.&&'J#C`RR@X_[__^L0@+WH$$`MZ0!`H.&7,-#E_P!3 +MXP(PH`,Q-,`%"P``"C`DT.4!`%+C!```&B(`4^,`,*"#`3"@DS$TP.4#``#J +M'@!3XP$PH),`,*"#,33`Y3$TU.4P)-3E`P!2X1"`O0@``%/C"```&BXPU.4" +M`%/C!`"@X00<`./_(*#C$S"@`R,PH!/^___K!```Z@0`H.$$'`#C_R"@XS,P +MH./^___K,334Y3`TQ.40@+WH\$'V__\: +M\(>]Z'!`+>D`0*#A`3"@X0)0H.$(&`#C_R,`X_[__^L$`*#A"!@`XP$EH.,! +M,*#C_O__ZQX`H./^___K!`"@X0@8`.,!):#C`#"@X_[__^L$`*#AM!@`XP`@ +MX./^___K<`#_YO[__^L<4$7B``"%X'"`O>CP02WI`$"@X0%0H.$S<-#E*`!7 +MXQE@H!,M8*`#*`!7XQYPH!,R<*`#.#30Y0``4^,9```:=!@`XP`@X./^___K +MH.,`(.#C_O__Z]`!X.=`!(3E!`"@X5P8`.,` +M(.#C_O__ZR`,H.%$!(3E!`"@X70:`.,`(.#C_O__ZU`&X^=(!(3E`3"@XS@T +MQ.4``%7C`3"@$S,TQ!40```:ES#4Y?\`4^,",*`#,S3$!0L```HR)-3E`0!2 +MXP0``!H#`%?A`#"@DP$PH(,S-,3E`P``Z@,`5N$!,*`C`#"@,S,TQ.4S--3E +M,B34Y0,`4N'P@;T(``!3XRL``!HH,)3E"`!3XP0``!H$`*#A=!@`XR`@H.,! +M,*#C_O__ZP0`H.%T&`#C!R>@XP(PH./^___K!`"@X<<>H.,((*#C`#"@X_[_ +M_^L$`*#A7!@`X_\DH.-C,*#C_O__ZP0`H.%T&`#C`RF@XP(PH./^___K!`"@ +MX70:`.,/*J#C`S"@X_[__^L$`*#A&!@`XP$BH.,`,*#C_O__ZP0`H.$8&`#C +M`2*@XP$PH./^___K(```Z@0`H.%T&`#CH.,( +M(*#C0#24Y?[__^L$`*#A7!@`X_\DH.-$-)3E_O__ZP0`H.%T&@#C#RJ@XT@T +ME.7^___K!`"@X1@8`.,!(J#C`#"@X_[__^LH,)3E"`!3XP0``!H$`*#A=!@` +MXR`@H.,`,*#C_O__ZS,TU.4R-,3E\(&]Z!!`+>DH,)#E%``3XQ"`O1@@()#E +M@``2XQ"`O0@?(-#E#``2XQ"`O0@"`%/C!```&BXPT.4"`%/C`0``&O[__^L0 +M@+WH`!"@X_[__^L0@+WH$$`MZ0!`H.'%'J#C?R"@X_[__^L0!,3E(S"@X_PS +MA.4H,*#C`#2$Y1D^H.,$-(3E^C^@XP@TA.4^,*#C%33$Y1XPH.,6-,3E"C"@ +MXQ(TQ.4,,*#C$S3$Y0,PX.,4-,3E`##@XQ@TQ.5\,.#C&33$Y1XPH.,=-,3E +M`#"@XQPTQ.4@-(3E)2"@XR0DQ.4E),3E)C3$Y2CP +M3RWII-!-X@!`H.$!@*#A(,"-XC!?G^4/`+7H#P"LZ`\`M>@/`*SH#P"UZ`\` +MK.@/`)7H#P",Z"@PE.4*`!/CO@,`"B`@E.5``!+CNP,`"@(`4^,.```:!`"@ +MX0@8`.,#*Z#C`S"@X_[__^L$`*#A"!@`XP,JH.,!,*#C_O__ZP0`H.$(&`#C +M`RF@XP`PH./^___K_V\/XP]@0.,$`*#A`!"@XQ@@H.,&,*#A_O__ZQ@`C>4$ +M`*#A`!"@XP$@H.$&,*#A_O__ZQ0`C>4$`*#AAAZ@XP,LH.,",*#C_O__ZPH` +MH./^___K!`"@X8P8`.,`(.#C_O__ZP"PH.$$`*#A"!P`XP`@X./^___K$`"- +MY00`H.%T&`#C`"#@X_[__^L,`(WE!`"@X<4>H.,`(.#C_O__ZP@`C>4@H(WB +M8)"-X@0`H.$*$*#A"2"@X1`PH./^___K!`"@X0@8`.,#*:#C`#"@X_[__^L! +M<*#C`'"-Y00`H.$`$*#C&""@XP8PH.'^___KI%4"X]M?1N,$`*#AYQZ@XP`@ +MX.,%,*#A_O__ZP0`H.%T'@#C`"#@XP4PH.'^___K!`"@X7@>`.,`(.#C!3"@ +MX?[__^L$`*#A?!X`XP`@X.,%,*#A_O__ZP0`H.$Z':#C`"#@XP4PH.'^___K +M!`"@X80>`.,`(.#C!3"@X?[__^L$`*#AB!X`XP`@X.,%,*#A_O__ZP0`H.&, +M'@#C`"#@XP4PH.'^___K!`"@X>T>H.,`(.#C!3"@X?[__^L$`*#AU!X`XP`@ +MX.,%,*#A_O__ZP0`H.'8'@#C`"#@XP4PH.'^___K!`"@X=P>`.,`(.#C!3"@ +MX?[__^L$`*#A[AZ@XP`@X.,%,*#A_O__ZP0`H.'L'@#C`"#@XP4PH.'^___K +M!`"@X5P8`.,`(.#C!3"@X?[__^L$`*#A;!X`XP`@X.,%,*#A_O__ZP0`H.&, +M&`#C`"#@X\`P`./P/$SC_O__ZP0`H.$('`#C`"#@X^0P`.,(,$#C_O__ZP0` +MH.%T&`#C`"#@XP`P".,@,D+C_O__ZP0`H.'C'J#C`"#@XQP\".,`,$'C_O__ +MZP0`H.$Y':#C`"#@XP`\!^,`,4#C_O__ZP0`H.%H&P#C`"#@XP(WH./^___K +M!`"@X6@;`.,`(.#C]C:@X_[__^L$`*#A1!X`XP`@X.,`.`3C`#%`X_[__^L$ +M`*#A-!X`XP`@X.,?/`CC`#!!X_[__^L$`*#A.!X`XP`@X.,(,`#C%3)(X_[_ +M_^L$`*#A/!X`XP`@X.,(,`#C%3A"X_[__^L$`*#A3!X`XP`@X./0.`+C$#!` +MX_[__^L(,`#C!3!`XP`PC>4$`*#A`!"@XP$@H.$&,*#A_O__ZP0`H.$H'@#C +M`"#@XP`P`..`,$CC_O__ZP0`H.%('@#C`"#@XSXSH./^___K^@^@X_[__^L$ +M`*#A#A"@XUH@H./^___K``!0XP!0H"$`4*`S!`"@X0X0H.-:(*#C_O__ZP4` +M4.$%`*`Q'`"-Y00`H.&&'J#C`RR@XP +M`.,`(.#C`#"@X_[__^L$`*#AAAZ@XP,LH.,",*#C_O__ZP0`H.&,&`#C`"#@ +MXPLPH.'^___K!`"@X0@<`.,`(.#C$#"=Y?[__^L$`*#A=!@`XP`@X.,,,)WE +M_O__ZP0`H.'%'J#C?R"@XT`PH./^___K!`"@X<4>H.,`(.#C"#"=Y?[__^L8 +M$)WE`!"-Y00`H.$`$*#C&""@XP8PH.'^___K%""=Y0`@C>4$`*#A`!"@XP$@ +MH.$&,*#A_O__ZP0`H.$*$*#A"2"@X1`PH./^___KT*'$X4``H.,`$*#C`"`* +MX`$P"^`#$)+A?P``"A@PE.4#`%/C?```FB@PE.4"`%/C`@``&B@)G^7^___K +M%P``Z@0`4^,"```:&`F?Y?[__^L2``#J"`!3XP(``!H("9_E_O__ZPT``.H0 +M`%/C`@``&O@(G^7^___K"```ZB``4^,"```:Z`B?Y?[__^L#``#J0`!3XP$` +M`!K8")_E_O__Z]0(G^74&)_EERZ@XQPPG>7^___KT*'$X4``H.,`$*#C`"`* +MX`$P"^`#$)+A4@``"A@PE.4#`%/C3P``FB@PE.4"`%/C`@``&G0(G^7^___K +M%P``Z@0`4^,"```:9`B?Y?[__^L2``#J"`!3XP(``!I4")_E_O__ZPT``.H0 +M`%/C`@``&D0(G^7^___K"```ZB``4^,"```:-`B?Y?[__^L#``#J0`!3XP$` +M`!HD")_E_O__ZR@(G^4@&)_EERZ@XP?Y?[__^L2``#J"`!3XP(``!J@!Y_E_O__ZPT``.H0 +M`%/C`@``&I`'G^7^___K"```ZB``4^,"```:@`>?Y?[__^L#``#J0`!3XP$` +M`!IP!Y_E_O__ZW@'G^5L%Y_EERZ@XP4PH.'^___K*#"4Y0@`4^,\`0`:`@!8 +MXW4``!H<()WE8P!2XV```)H!,(+B!P!3X2X``"H`,*#C;37$Y=!AQ.%``*#C +M`!"@XP`@!N`!,`?@`Q"2X;D!``H8,)3E`P!3X[8!`)HH,)3E`@!3XP(``!K8 +M!I_E_O__ZQ<``.H$`%/C`@``&L@&G^7^___K$@``Z@@`4^,"```:N`:?Y?[_ +M_^L-``#J$`!3XP(``!JH!I_E_O__ZP@``.H@`%/C`@``&I@&G^7^___K`P`` +MZD``4^,!```:B`:?Y?[__^N4!I_EA!:?Y?[__^L!`*#CE`$`Z@$PH.-M-<3E +MT&'$X4``H.,`$*#C`"`&X`$P!^`#$)+AB@$`"A@PE.4#`%/CAP$`FB@PE.4" +M`%/C`@``&AP&G^7^___K%P``Z@0`4^,"```:#`:?Y?[__^L2``#J"`!3XP(` +M`!K\!9_E_O__ZPT``.H0`%/C`@``&NP%G^7^___K"```ZB``4^,"```:W`6? +MY?[__^L#``#J0`!3XP$``!K,!9_E_O__Z]P%G^7(%9_E_O__ZP$`H.-E`0#J +MT&'$X4``H.,`$*#C`"`&X`$P!^`#$)+A!P``"A@PE.4#`%/C!```FGP%G^7^ +M___KG`6?Y805G^7^___K``"@XVT%Q.53`0#J``!8XU`!`!ID,$7B$0!3XTT! +M`(H!,(7B'""=Y0(`4^$M```J`#"@XVPUQ.70@<3A0`"@XP`0H.,`(`C@`3`) +MX`,0DN%1```*&#"4Y0,`4^-.``":*#"4Y0(`4^,"```:]`2?Y?[__^L7``#J +M!`!3XP(``!KD!)_E_O__ZQ(``.H(`%/C`@``&M0$G^7^___K#0``ZA``4^," +M```:Q`2?Y?[__^L(``#J(`!3XP(``!JT!)_E_O__ZP,``.I``%/C`0``&J0$ +MG^7^___KO`2?Y:`4G^7^___K+```Z@$PH.-L-<3ET('$X4``H.,`$*#C`"`( +MX`$P">`#$)+A(P``"A@PE.4#`%/C(```FB@PE.4"`%/C`@``&CP$G^7^___K +M%P``Z@0`4^,"```:+`2?Y?[__^L2``#J"`!3XP(``!H('`%7A+@``*@`PH.-M-<3ET&'$ +MX4``H.,`$*#C`"`&X`$P!^`#$)+AX@``"A@PE.4#`%/CWP``FB@PE.4"`%/C +M`@``&GP#G^7^___K%P``Z@0`4^,"```:;`.?Y?[__^L2``#J"`!3XP(``!I< +M`Y_E_O__ZPT``.H0`%/C`@``&DP#G^7^___K"```ZB``4^,"```:/`.?Y?[_ +M_^L#``#J0`!3XP$``!HL`Y_E_O__ZTP#G^4H$Y_E_O__ZP$`H..]``#J`3"@ +MXVTUQ.708<3A0`"@XP`0H.,`(`;@`3`'X`,0DN&S```*&#"4Y0,`4^.P``": +M*#"4Y0(`4^,"```:P`*?Y?[__^L7``#J!`!3XP(``!JP`I_E_O__ZQ(``.H( +M`%/C`@``&J`"G^7^___K#0``ZA``4^,"```:D`*?Y?[__^L(``#J(`!3XP(` +M`!J``I_E_O__ZP,``.I``%/C`0``&G`"G^7^___KE`*?Y6P2G^7^___K`0"@ +MXXX``.H"`%/CBP``&AP@G>5C`%+C=```F@(P@N('`%/A-```*@`PH.-L-<3E +M`3"@XVTUQ.4$`*#AAAZ@XP,LH./^___KT&'$X4``H.,`$*#C`"`&X`$P!^`# +M$)+A=@``"A@PE.4#`%/C4"`%?A`0"@(VP%Q"5M +M!<0E2@``*@$PH.-L-<3E`#"@XVTUQ.4$`*#AAAZ@XP,LH.,",*#C_O__Z]!A +MQ.%``*#C`!"@XP`@!N`!,`?@`Q"2X3D```H8,)3E`P!3XS8``)HH,)3E`@!3 +MXP(``!K8`)_E_O__ZQ<``.H$`%/C`@``&L@`G^7^___K$@``Z@@`4^,"```: +MN`"?Y?[__^L-``#J$`!3XP(``!JH`)_E_O__ZP@``.H@`%/C`@``&I@`G^7^ +M___K`P``ZD``4^,!```:B`"?Y?[__^N4`)_EA!"?Y?[__^L!`*#C%```ZM!A +MQ.%``*#C`!"@XP`@!N`!,`?@`Q"2X0<```H8,)3E`P!3XP0``)HP`)_E_O__ +MZU@`G^5`$)_E_O__ZP$PH.-L-<3E``"@XVT%Q.4```#J`0"@XZ30C>+PC[WH +MD`0*#A`7"@X0*@ +MH.$#4*#A06;0Y4*&T.4`,-/E`P!3XP/QGY<+``#J5%8#`%16`P#L50,`^%4# +M``5@AN)V8._F%@``Z@5@AN)V8._F!8"(XGB`[^81``#J````XP``0.,`$`#C +M`!!`X_[__^L8D9_E````XP``0.,`$`#C`!!`XPD@H.%M/0#C_O__ZP```.,` +M`$#C"1"@X0`@U>7^___K!P!6X0%@H+,"``"Z"`!7X0)@H,,#8*#3`##5Y0`` +M6N,&`%,!``"@`_"'O0C0@<3A`@"@XP`0H.,`(`C@`3`)X`,0DN$E```*&#"4 +MY0,`4^,B``":*#"4Y0(`4^,"```:B`"?Y?[__^L7``#J!`!3XP(``!IX`)_E +M_O__ZQ(``.H(`%/C`@``&F@`G^7^___K#0``ZA``4^,"```:6`"?Y?[__^L( +M``#J(`!3XP(``!I(`)_E_O__ZP,``.I``%/C`0``&C@`G^7^___K-`"?Y100 +MG^4`(-7E!C"@X?[__^L`8,7E`0"@X_"'O>C0%0``;`D``'@)``"$"0``E`D` +M`*0)``"P"0``!`P``-!`+>D`0*#A(#"0Y0@`$^/0@+T(*#"0Y2``4^.L`0`* +M`QN@XP(AH.,!,*#C_O__ZP0`H.$-'*#C`B&@XP$PH./^___K!`"@X<\>H.,` +M(.#C_O__ZW`P_^8`-83E(`B@X00%A.4$`*#AVAZ@XP`@X./^___K<##_Y@@U +MA.4@"*#AY`2$Y00`H.&D'0#C`"#@X_[__^MP,/_FZ#2$Y2`(H.'L!(3E!`"@ +MX:@=`.,`(.#C_O__ZW``_^;P!(3EZ"24Y>0TE.4#,(+@["24Y0(P@^``)93E +M`C"#X`0EE.4",(/@``"#X/0$A.4H,)3E$`!3XP<``!H$`*#AQ!@`XP`@X./^ +M___K<##_YA@UA.4@"*#A%`6$Y00`H.$L&@#C`2J@XP$PH./^___K!`"@X2P: +M`.,!*:#C`3"@X_[__^L$`*#A7!H`X_\@H./^___K^`2$Y00`H.%8&@#C_R2@ +MX_[__^L`#*#A^#24Y2`(@^#X!(3E!`"@X:8>H.,`(.#C_O__ZU`TY^<`#*#A +M(`B#X0P%A.4$)93E`#64Y0,P@N#D))3E`C"#X.@DE.4",(/@["24Y0(P@^#P +M))3E`C"#X/@DE.4",(/@_#2$Y0@UE.4#`(#@$`6$Y2@PE.4'`%/C,0``F@0` +MH.$,'`#C`B&@XP$PH./^___K!`"@X0P<`.,"(:#C`#"@X_[__^L$`*#A#1R@ +MXP(CH.,!,*#C_O__ZP0`H.$-'*#C`B.@XP`PH./^___K!`"@X0,;H.,"(:#C +M`#"@X_[__^L$`*#A#1R@XP(AH.,`,*#C_O__ZP0`H.$L&@#C`RJ@XP`PH./^ +M___K!`"@X2P:`.,#*J#C`C"@X_[__^L$`*#A+!H`XP,IH.,`,*#C_O__ZP0` +MH.$L&@#C`RF@XP(PH./^___KT&'$X0@`H.,`$*#C`"`&X`$P!^`#$)+AT("] +M"!@PE.4#`%/CT("]F"@PE.4"`%/C`@``&DP$G^7^___K%P``Z@0`4^,"```: +M/`2?Y?[__^L2``#J"`!3XP(``!HL!)_E_O__ZPT``.H0`%/C`@``&AP$G^7^ +M___K"```ZB``4^,"```:#`2?Y?[__^L#``#J0`!3XP$``!K\`Y_E_O__Z_@# +MG^7X$Y_E_O__Z]!AQ.$(`*#C`!"@XP`@!N`!,`?@`Q"2X="`O0@8,)3E`P!3 +MX]"`O9@H,)3E`@!3XP(``!J@`Y_E_O__ZQ<``.H$`%/C`@``&I`#G^7^___K +M$@``Z@@`4^,"```:@`.?Y?[__^L-``#J$`!3XP(``!IP`Y_E_O__ZP@``.H@ +M`%/C`@``&F`#G^7^___K`P``ZD``4^,!```:4`.?Y?[__^M4`Y_E3!.?Y0`E +ME.4$-93E_O__Z]!AQ.$(`*#C`!"@XP`@!N`!,`?@`Q"2X="`O0@8,)3E`P!3 +MX]"`O9@H,)3E`@!3XP(``!KL`I_E_O__ZQ<``.H$`%/C`@``&MP"G^7^___K +M$@``Z@@`4^,"```:S`*?Y?[__^L-``#J$`!3XP(``!J\`I_E_O__ZP@``.H@ +M`%/C`@``&JP"G^7^___K`P``ZD``4^,!```:G`*?Y?[__^ND`I_EF!*?Y>0D +ME.7H-)3E_O__Z]!AQ.$(`*#C`!"@XP`@!N`!,`?@`Q"2X="`O0@8,)3E`P!3 +MX]"`O9@H,)3E`@!3XP(``!HX`I_E_O__ZQ<``.H$`%/C`@``&B@"G^7^___K +M$@``Z@@`4^,"```:&`*?Y?[__^L-``#J$`!3XP(``!H(`I_E_O__ZP@``.H@ +M`%/C`@``&O@!G^7^___K`P``ZD``4^,!```:Z`&?Y?[__^OT`9_EY!&?Y>PD +ME.7P-)3E_O__Z]!AQ.$(`*#C`!"@XP`@!N`!,`?@`Q"2X="`O0@8,)3E`P!3 +MX]"`O9@H,)3E`@!3XP(``!J$`9_E_O__ZQ<``.H$`%/C`@``&G0!G^7^___K +M$@``Z@@`4^,"```:9`&?Y?[__^L-``#J$`!3XP(``!I4`9_E_O__ZP@``.H@ +M`%/C`@``&D0!G^7^___K`P``ZD``4^,!```:-`&?Y?[__^M$`9_E,!&?Y?@D +ME.7^___KT&'$X0@`H.,`$*#C`"`&X`$P!^`#$)+AT("]"!@PE.4#`%/CT("] +MF"@PE.4"`%/C`@``&M0`G^7^___K%P``Z@0`4^,"```:Q`"?Y?[__^L2``#J +M"`!3XP(``!JT`)_E_O__ZPT``.H0`%/C`@``&J0`G^7^___K"```ZB``4^," +M```:E`"?Y?[__^L#``#J0`!3XP$``!J$`)_E_O__ZY@`G^6`$)_E_"24Y?[_ +M_^O0@+WH2!\`X_\O#^/^___K]`2$Y00`H.%<&@#C_R\/X_[__^OX!(3E]#24 +MY0,`@.#\!(3E!`"@X5@;`.,!(*#C`C"@X?[__^L$`*#A6!L`XP$@H.,`,*#C +M_O__Z]"`O>AL"0``>`D``(0)``"4"0``I`D``+`)```@#```Y!4``%`,``"` +M#```L`P``-P,``#T#```<$`MZ0!`H.$!4*#A$#30Y0$`4^&H```*'S#0Y0P` +M$^,:```**#"0Y2``4^,-```*`6"@X<4>H.-_(*#C!3"@X?[__^LH,)3E$`!3 +MXW$```H$`*#A6!P`XW\@H.,%,*#A_O__ZVL``.K%'J#C`"#@XP4PH.'^___K +M!`"@X>4>H.,`(.#C!3"@X?[__^MA``#J`P`3XU\```J(,)#E`##3Y0$`4^,> +M```*`@``.@(`4^-8```:.```ZB@PD.4@`%/C#0``"@%@H.'%'J#C?R"@XP4P +MH.'^___K*#"4Y1``4^-,```*!`"@X5@<`.-_(*#C!3"@X?[__^M&``#JQ1Z@ +MXP`@X.,%,*#A_O__ZP0`H.'E'J#C`"#@XP4PH.'^___K/```ZB@PD.4@`%/C +M#@``"L4>H.-_(*#C!3"@X?[__^LH,)3E$`!3XS(```H%`*#A_O__ZP`PH.$$ +M`*#A6!P`XW\@H./^___K*@``ZL4>H.,`(.#C!3"@X?[__^L%`*#A_O__ZP`P +MH.$$`*#AY1Z@XP`@X./^___K'@``ZB@PD.4@`%/C#P``"@$`H.'^___K`#"@ +MX00`H.'%'J#C?R"@X_[__^LH,)3E$`!3XQ$```H$`*#A6!P`XW\@H.,%,*#A +M_O__ZPL``.H!`*#A_O__ZP`PH.$$`*#AQ1Z@XP`@X./^___K!`"@X>4>H.,` +M(.#C!3"@X?[__^L0,)3E`0`3XR0```H8,)3E`P!3XR$``)HH,)3E`@!3XP(` +M`!H<`9_E_O__ZQ<``.H$`%/C`@``&@P!G^7^___K$@``Z@@`4^,"```:_`"? +MY?[__^L-``#J$`!3XP(``!KL`)_E_O__ZP@``.H@`%/C`@``&MP`G^7^___K +M`P``ZD``4^,!```:S`"?Y?[__^O(`)_ER!"?Y04@H.'^___K$%3$Y1`PE.4! +M`!/C<("]"!@PE.4#`%/C<("]F"@PE.4"`%/C`@``&G@`G^7^___K%P``Z@0` +M4^,"```::`"?Y?[__^L2``#J"`!3XP(``!I8`)_E_O__ZPT``.H0`%/C`@`` +M&D@`G^7^___K"```ZB``4^,"```:.`"?Y?[__^L#``#J0`!3XP$``!HH`)_E +M_O__ZRP`G^4D$)_E!2"@X?[__^MP@+WH;`D``'@)``"$"0``E`D``*0)``"P +M"0``$`T```06```L#0``\$TMZ0!`H.$05-#E$#"0Y0$`$^,C```*&#"0Y0,` +M4^,@``":*#"0Y0(`4^,"```:G`V?Y?[__^L7``#J!`!3XP(``!J,#9_E_O__ +MZQ(``.H(`%/C`@``&GP-G^7^___K#0``ZA``4^,"```:;`V?Y?[__^L(``#J +M(`!3XP(``!I<#9_E_O__ZP,``.I``%/C`0``&DP-G^7^___K2`V?Y4@=G^7^ +M___K(#"4Y0DP`^()`%/C)P``"A`PE.4!`!/C\(V]"!@PE.4#`%/C\(V]F"@P +ME.4"`%/C`@``&O`,G^7^___K%P``Z@0`4^,"```:X`R?Y?[__^L2``#J"`!3 +MXP(``!K0#)_E_O__ZPT``.H0`%/C`@``&L`,G^7^___K"```ZB``4^,"```: +ML`R?Y?[__^L#``#J0`!3XP$``!J@#)_E_O__ZZ0,G^6<')_E_O__Z_"-O>B` +M,)3E`##3Y0``4^,G```*$#"4Y0$`$^/PC;T(&#"4Y0,`4^/PC;V8*#"4Y0(` +M4^,"```:0`R?Y?[__^L7``#J!`!3XP(``!HP#)_E_O__ZQ(``.H(`%/C`@`` +M&B`,G^7^___K#0``ZA``4^,"```:$`R?Y?[__^L(``#J(`!3XP(``!H`#)_E +M_O__ZP,``.I``%/C`0``&O`+G^7^___K^`N?Y>P;G^7^___K\(V]Z#XVU.4` +M`%/C)P``&A`PE.4!`!/C\(V]"!@PE.4#`%/C\(V]F"@PE.4"`%/C`@``&I0+ +MG^7^___K%P``Z@0`4^,"```:A`N?Y?[__^L2``#J"`!3XP(``!IT"Y_E_O__ +MZPT``.H0`%/C`@``&F0+G^7^___K"```ZB``4^,"```:5`N?Y?[__^L#``#J +M0`!3XP$``!I$"Y_E_O__ZU`+G^5`&Y_E_O__Z_"-O>@H,)3E!`!3XS,``!I$ +M()3E`"#2Y0$`4N,7```:<""4Y0`@TN4``%+C"0``"B1DU.66(-3E``!2XP"` +MH`,"```*)H34Y0&`>.(`@*`S>(#OYCL``.HE9-3EEB#4Y0``4N,`@*`#`@`` +M"B>$U.4!@'CB`("@,WB`[^8Q``#J5""4Y0`@TN4"`%+C"0``&B1DU.66(-3E +M``!2XP"`H`,"```*)H34Y0&`>.(`@*`S>(#OYA(``.HE9-3EEB#4Y0``4N,` +M@*`#`@``"B>$U.4!@'CB`("@,WB`[^8(``#J)&34Y98@U.4``%+C`("@`P(` +M``HFA-3E`8!XX@"`H#-X@._F"@`3XPX```HO(-3E`0!2XP(```HP(-3E``!2 +MXP@```H?(-3E`P`2XRYPH`-"`*`#1B"@`S!PH!-"`*`3`""@$0<``.H?(-3E +M`P`2XQYPH`,R`*`#/B"@`R!PH!,R`*`3`""@$980U.4``%'CBP``"@@`4^,+ +M```:ER#4Y0HP@N(^`%/C/C"@PQ4TQ,6N``#*'0!3XQXPH-,5-,35"B""PA4D +MQ,6H``#JEQ#4Y10P@>("`%/A%23$Q0,``,H'`%/A%73$M100@:(5%,2EFC#4 +MY0``4^-6```*EV#4Y08`5^$'8*"!`0``B@8`4.$`8*`Q$#"4Y0$`$^.3```* +M&#"4Y0,`4^.0``":*#"4Y0(`4^,"```:!`F?Y?[__^L7``#J!`!3XP(``!KT +M")_E_O__ZQ(``.H(`%/C`@``&N0(G^7^___K#0``ZA``4^,"```:U`B?Y?[_ +M_^L(``#J(`!3XP(``!K$")_E_O__ZP,``.I``%/C`0``&K0(G^7^___KQ`B? +MY;`8G^4&(*#A_O__ZQ`PE.4!`!/C:P``"A@PE.4#`%/C:```FB@PE.4"`%/C +M`@``&F0(G^7^___K%P``Z@0`4^,"```:5`B?Y?[__^L2``#J"`!3XP(``!I$ +M")_E_O__ZPT``.H0`%/C`@``&C0(G^7^___K"```ZB``4^,"```:)`B?Y?[_ +M_^L#``#J0`!3XP$``!H4")_E_O__ZR@(G^40&)_EER#4Y?[__^M%``#J*#"4 +MY1``4^-"```:(#"4Y4``$^,_```*/##4Y0$`4^,\```:*&34Y="AQ.%``*#C +M`!"@XP`@"N`!,`O@`Q"2X30```H8,)3E`P!3XS$``)J@!Y_E_O__Z\`'G^6D +M%Y_E*"24Y?[__^LJ``#J%23$Y1`PE.4!`!/C)0``"A@PE.4#`%/C(@``FB@P +ME.4"`%/C`@``&E`'G^7^___K%P``Z@0`4^,"```:0`>?Y?[__^L2``#J"`!3 +MXP(``!HP!Y_E_O__ZPT``.H0`%/C`@``&B`'G^7^___K"```ZB``4^,"```: +M$`>?Y?[__^L#``#J0`!3XP$``!H`!Y_E_O__ZQP'G^7\%I_E_O__ZP=@H.$` +M``#J!V"@X?PDE.40-P+C`P!2X3L``)H0,)3E`0`3XR,```H8,)3E`P!3XR`` +M`)HH,)3E`@!3XP(``!J8!I_E_O__ZQ<``.H$`%/C`@``&H@&G^7^___K$@`` +MZ@@`4^,"```:>`:?Y?[__^L-``#J$`!3XP(``!IH!I_E_O__ZP@``.H@`%/C +M`@``&E@&G^7^___K`P``ZD``4^,!```:2`:?Y?[__^MH!I_E1!:?Y?[__^L< +M)-3E`2""XG(@[^8<),3E'334Y0,`5>$=5,2%`3"@@QPTQ(4>``"*`@!2XQP` +M`)H5)-3E`1"#X@(`4>$6),3%`3"#TA8TQ-7A/J#C(#2$Y1,``.H@-)3E``!3 +MXP$P0Q(@-(05#@``&APTU.4``%/C"```&ATTU.4!($/B!@!2X1UDQ+469,2U +M`2!#HATDQ*46-,2E`@``Z@,`4^,`,*`#'#3$!98PU.4``%/C;@``"A`PE.4! +M`!/C(P``"A@PE.4#`%/C(```FB@PE.4"`%/C`@``&DP%G^7^___K%P``Z@0` +M4^,"```:/`6?Y?[__^L2``#J"`!3XP(``!HL!9_E_O__ZPT``.H0`%/C`@`` +M&AP%G^7^___K"```ZB``4^,"```:#`6?Y?[__^L#``#J0`!3XP$``!K\!)_E +M_O__ZR`%G^7X%)_E_O__ZP``6.,H```*EU#4Y1`PE.4!`!/C(@$`"A@PE.4# +M`%/C)@$`FB@PE.4"`%/C`@``&J0$G^7^___K%P``Z@0`4^,"```:E`2?Y?[_ +M_^L2``#J"`!3XP(``!J$!)_E_O__ZPT``.H0`%/C`@``&G0$G^7^___K"``` +MZB``4^,"```:9`2?Y?[__^L#``#J0`!3XP$``!I4!)_E_O__ZWP$G^50%)_E +M_O__ZU```.HH,)3E!`!3XPP``!K\-)3E!@Q3XP)0A8)U4.^&2```B@$+4^,! +M4(6"=5#OAD0``(K_`%/C`5!%DG50[Y9```#J_#24Y0$+4^,"4(6"=5#OACL` +M`(H##%/C`5"%@G50[X8W``"*`@Q3XP%013)U4.\V,P``ZA`PE.4!`!/C(P`` +M"A@PE.4#`%/C(```FB@PE.4"`%/C`@``&I`#G^7^___K%P``Z@0`4^,"```: +M@`.?Y?[__^L2``#J"`!3XP(``!IP`Y_E_O__ZPT``.H0`%/C`@``&F`#G^7^ +M___K"```ZB``4^,"```:4`.?Y?[__^L#``#J0`!3XP$``!I``Y_E_O__ZVP# +MG^4\$Y_E_O__Z_PTE.40)P+C`@!3X0)0A8)U4.^&!@``BGT-4^,!4(6"=5#O +MA@(``(I]#U/C`5!%,G50[S80,)3E`0`3XZD```H8,)3E`P!3XZT``)HH,)3E +M`@!3XP(``!K``I_E_O__ZQ<``.H$`%/C`@``&K`"G^7^___K$@``Z@@`4^," +M```:H`*?Y?[__^L-``#J$`!3XP(``!J0`I_E_O__ZP@``.H@`%/C`@``&H`" +MG^7^___K`P``ZD``4^,!```:<`*?Y?[__^N@`I_E;!*?Y?[__^L5)-3E%C34 +MY0(`5>$"4*`A`P!5X0-0H#$0,)3E`0`3XW4```H8,)3E`P!3XW(``)HH,)3E +M`@!3XP(``!H,`I_E_O__ZQ<``.H$`%/C`@``&OP!G^7^___K$@``Z@@`4^," +M```:[`&?Y?[__^L-``#J$`!3XP(``!K<`9_E_O__ZP@``.H@`%/C`@``&LP! +MG^7^___K`P``ZD``4^,!```:O`&?Y?[__^OP`9_EN!&?Y14DU.46--3E_O__ +MZQ`PE.4!`!/C3```"A@PE.4#`%/C20``FB@PE.4"`%/C`@``&F@!G^7^___K +M%P``Z@0`4^,"```:6`&?Y?[__^L2``#J"`!3XP(``!I(`9_E_O__ZPT``.H0 +M`%/C`@``&C@!G^7^___K"```ZB``4^,"```:*`&?Y?[__^L#``#J0`!3XP$` +M`!H8`9_E_O__ZU`!G^44$9_E_"24Y?[__^L0,)3E`0`3XR0```H8,)3E`P!3 +MXR$``)HH,)3E`@!3XP(``!K(`)_E_O__ZQ<``.H$`%/C`@``&K@`G^7^___K +M$@``Z@@`4^,"```:J`"?Y?[__^L-``#J$`!3XP(``!J8`)_E_O__ZP@``.H@ +M`%/C`@``&H@`G^7^___K`P``ZD``4^,!```:>`"?Y?[__^NT`)_E=!"?Y04@ +MH.'^___K!`"@X040H.'^___KEC#4Y28TQ.4D9,3E\(V]Z!4DU.46--3E`@!5 +MX0)0H"$#`%7A`U"@,?'__^H5)-3E%C34Y0(`5>$"4*`A`P!5X0-0H#'J___J +M;`D``'@)``"$"0``E`D``*0)``"P"0``5`T``!06``!H#0``N`T``.0-```0 +M#@``4`X``'@.``"L#@``R`X``/@.```8#P``-`\``%@/``"`#P``Q`\``.0/ +M``#00"WI`$"@X=!AP.$!`:#C`!"@XP`@!N`!,`?@`Q"2X="`O0@8,)3E`P!3 +MX]"`O9@H,)3E`@!3XP(``!HT`Y_E_O__ZQ<``.H$`%/C`@``&B0#G^7^___K +M$@``Z@@`4^,"```:%`.?Y?[__^L-``#J$`!3XP(``!H$`Y_E_O__ZP@``.H@ +M`%/C`@``&O0"G^7^___K`P``ZD``4^,!```:Y`*?Y?[__^O@`I_EX!*?Y?[_ +M_^O08<3A`0&@XP`0H.,`(`;@`3`'X`,0DN'0@+T(&#"4Y0,`4^/0@+V8*#"4 +MY0(`4^,"```:B`*?Y?[__^L7``#J!`!3XP(``!IX`I_E_O__ZQ(``.H(`%/C +M`@``&F@"G^7^___K#0``ZA``4^,"```:6`*?Y?[__^L(``#J(`!3XP(``!I( +M`I_E_O__ZP,``.I``%/C`0``&C@"G^7^___K/`*?Y302G^64(-3E_O__Z]!A +MQ.$!`:#C`!"@XP`@!N`!,`?@`Q"2X="`O0@8,)3E`P!3X]"`O9@H,)3E`@!3 +MXP(``!K8`9_E_O__ZQ<``.H$`%/C`@``&L@!G^7^___K$@``Z@@`4^,"```: +MN`&?Y?[__^L-``#J$`!3XP(``!JH`9_E_O__ZP@``.H@`%/C`@``&I@!G^7^ +M___K`P``ZD``4^,!```:B`&?Y?[__^N0`9_EA!&?Y94@U.7^___KT&'$X0$! +MH.,`$*#C`"`&X`$P!^`#$)+AT("]"!@PE.4#`%/CT("]F"@PE.4"`%/C`@`` +M&B@!G^7^___K%P``Z@0`4^,"```:&`&?Y?[__^L2``#J"`!3XP(``!H(`9_E +M_O__ZPT``.H0`%/C`@``&O@`G^7^___K"```ZB``4^,"```:Z`"?Y?[__^L# +M``#J0`!3XP$``!K8`)_E_O__Z^0`G^74$)_EEB#4Y?[__^O08<3A`0&@XP`0 +MH.,`(`;@`3`'X`,0DN'0@+T(&#"4Y0,`4^/0@+V8*#"4Y0(`4^,"```:>`"? +MY?[__^L7``#J!`!3XP(``!IH`)_E_O__ZQ(``.H(`%/C`@``&E@`G^7^___K +M#0``ZA``4^,"```:2`"?Y?[__^L(``#J(`!3XP(``!HX`)_E_O__ZP,``.I` +M`%/C`0``&B@`G^7^___K.`"?Y200G^67(-3E_O__Z]"`O>AL"0``>`D``(0) +M``"4"0``I`D``+`)```($```'!8``"P0``!$$```7!```'`0``#00"WI`$"@ +MX=!AP.$!`:#C`!"@XP`@!N`!,`?@`Q"2X;@!``H8,)3E`P!3X[4!`)HH,)3E +M`@!3XP(``!J(!Y_E_O__ZQ<``.H$`%/C`@``&G@'G^7^___K$@``Z@@`4^," +M```::`>?Y?[__^L-``#J$`!3XP(``!I8!Y_E_O__ZP@``.H@`%/C`@``&D@' +MG^7^___K`P``ZD``4^,!```:.`>?Y?[__^LT!Y_E-!>?Y?[__^O08<3A`0&@ +MXP`0H.,`(`;@`3`'X`,0DN&-`0`*&#"4Y0,`4^.*`0":*#"4Y0(`4^,"```: +MW`:?Y?[__^L7``#J!`!3XP(``!K,!I_E_O__ZQ(``.H(`%/C`@``&KP&G^7^ +M___K#0``ZA``4^,"```:K`:?Y?[__^L(``#J(`!3XP(``!J?Y?[__^L2``#J"`!3XP(``!KH!Y_E_O__ZPT``.H0`%/C`@`` +M&M@'G^7^___K"```ZB``4^,"```:R`>?Y?[__^L#``#J0`!3XP$``!JX!Y_E +M_O__Z\@'G^6T%Y_E*""4Y?[__^O08<3A`0&@XP`0H.,`(`;@`3`'X`,0DN'0 +M@+T(&#"4Y0,`4^/0@+V8*#"4Y0(`4^,"```:6`>?Y?[__^L7``#J!`!3XP(` +M`!I(!Y_E_O__ZQ(``.H(`%/C`@``&C@'G^7^___K#0``ZA``4^,"```:*`>? +MY?[__^L(``#J(`!3XP(``!H8!Y_E_O__ZP,``.I``%/C`0``&@@'G^7^___K +M'`>?Y007G^4L(-3E_O__Z]!AQ.$!`:#C`!"@XP`@!N`!,`?@`Q"2X="`O0@8 +M,)3E`P!3X]"`O9@H,)3E`@!3XP(``!JH!I_E_O__ZQ<``.H$`%/C`@``&I@& +MG^7^___K$@``Z@@`4^,"```:B`:?Y?[__^L-``#J$`!3XP(``!IX!I_E_O__ +MZP@``.H@`%/C`@``&F@&G^7^___K`P``ZD``4^,!```:6`:?Y?[__^MP!I_E +M5!:?Y2T@U.7^___KT&'$X0$!H.,`$*#C`"`&X`$P!^`#$)+AT("]"!@PE.4# +M`%/CT("]F"@PE.4"`%/C`@``&O@%G^7^___K%P``Z@0`4^,"```:Z`6?Y?[_ +M_^L2``#J"`!3XP(``!K8!9_E_O__ZPT``.H0`%/C`@``&L@%G^7^___K"``` +MZB``4^,"```:N`6?Y?[__^L#``#J0`!3XP$``!JH!9_E_O__Z\0%G^6D%9_E +M+B#4Y?[__^O08<3A`0&@XP`0H.,`(`;@`3`'X`,0DN'0@+T(&#"4Y0,`4^/0 +M@+V8*#"4Y0(`4^,"```:2`6?Y?[__^L7``#J!`!3XP(``!HX!9_E_O__ZQ(` +M`.H(`%/C`@``&B@%G^7^___K#0``ZA``4^,"```:&`6?Y?[__^L(``#J(`!3 +MXP(``!H(!9_E_O__ZP,``.I``%/C`0``&O@$G^7^___K&`6?Y?04G^4O(-3E +M_O__Z]!AQ.$!`:#C`!"@XP`@!N`!,`?@`Q"2X="`O0@8,)3E`P!3X]"`O9@H +M,)3E`@!3XP(``!J8!)_E_O__ZQ<``.H$`%/C`@``&H@$G^7^___K$@``Z@@` +M4^,"```:>`2?Y?[__^L-``#J$`!3XP(``!IH!)_E_O__ZP@``.H@`%/C`@`` +M&E@$G^7^___K`P``ZD``4^,!```:2`2?Y?[__^ML!)_E1!2?Y3`@U.7^___K +MT&'$X0$!H.,`$*#C`"`&X`$P!^`#$)+AT("]"!@PE.4#`%/CT("]F"@PE.4" +M`%/C`@``&N@#G^7^___K%P``Z@0`4^,"```:V`.?Y?[__^L2``#J"`!3XP(` +M`!K(`Y_E_O__ZPT``.H0`%/C`@``&K@#G^7^___K"```ZB``4^,"```:J`.? +MY?[__^L#``#J0`!3XP$``!J8`Y_E_O__Z\`#G^64$Y_E,2#4Y?[__^O08<3A +M`0&@XP`0H.,`(`;@`3`'X`,0DN'0@+T(&#"4Y0,`4^/0@+V8*#"4Y0(`4^," +M```:.`.?Y?[__^L7``#J!`!3XP(``!HH`Y_E_O__ZQ(``.H(`%/C`@``&A@# +MG^7^___K#0``ZA``4^,"```:"`.?Y?[__^L(``#J(`!3XP(``!KX`I_E_O__ +MZP,``.I``%/C`0``&N@"G^7^___K%`.?Y>02G^4R(-3E_O__Z]!AQ.$!`:#C +M`!"@XP`@!N`!,`?@`Q"2X="`O0@8,)3E`P!3X]"`O9@H,)3E`@!3XP(``!J( +M`I_E_O__ZQ<``.H$`%/C`@``&G@"G^7^___K$@``Z@@`4^,"```::`*?Y?[_ +M_^L-``#J$`!3XP(``!I8`I_E_O__ZP@``.H@`%/C`@``&D@"G^7^___K`P`` +MZD``4^,!```:.`*?Y?[__^MH`I_E-!*?Y3,@U.7^___KT&'$X0$!H.,`$*#C +M`"`&X`$P!^`#$)+AT("]"!@PE.4#`%/CT("]F"@PE.4"`%/C`@``&M@!G^7^ +M___K%P``Z@0`4^,"```:R`&?Y?[__^L2``#J"`!3XP(``!JX`9_E_O__ZPT` +M`.H0`%/C`@``&J@!G^7^___K"```ZB``4^,"```:F`&?Y?[__^L#``#J0`!3 +MXP$``!J(`9_E_O__Z[P!G^6$$9_E-"#4Y?[__^O08<3A`0&@XP`0H.,`(`;@ +M`3`'X`,0DN'0@+T(&#"4Y0,`4^/0@+V8*#"4Y0(`4^,"```:*`&?Y?[__^L7 +M``#J!`!3XP(``!H8`9_E_O__ZQ(``.H(`%/C`@``&@@!G^7^___K#0``ZA`` +M4^,"```:^`"?Y?[__^L(``#J(`!3XP(``!KH`)_E_O__ZP,``.I``%/C`0`` +M&M@`G^7^___K$`&?Y=00G^4U(-3E_O__Z]!AQ.$!`:#C`!"@XP`@!N`!,`?@ +M`Q"2X="`O0@8,)3E`P!3X]"`O9@H,)3E`@!3XP(``!IX`)_E_O__ZQ<``.H$ +M`%/C`@``&F@`G^7^___K$@``Z@@`4^,"```:6`"?Y?[__^L-``#J$`!3XP(` +M`!I(`)_E_O__ZP@``.H@`%/C`@``&C@`G^7^___K`P``ZD``4^,!```:*`"? +MY?[__^MD`)_E)!"?Y38@U.7^___KT("]Z&P)``!X"0``A`D``)0)``"D"0`` +ML`D``*01``!,%@``Q!$``.`1``#\$0``&!(``#02``!,$@``9!(``'@2``", +M$@``H!(``+`2``#$$@``V!(``/`2```$$P``^$\MZ0!0H.$`0)#E.SR@XP,P +ME.<"+P+C`B#4YP$`4N-3```*RBO4Y0\`4N-0``"*^!4!XP$0E.<``%'C0@`` +M&E4]H./3@(3A6#4!X]-@A.$(`*#A"1"@X08`4.`'$,'@%CR@X].@A.$8-@'C +MTV"$X0J`H.$+D*#A!H!8X`>0R>`$,$+B$.``"*`0``&@@`4.$+``"*`6"@XPD``.H`8*#C`3&@X2`_ +M@^$``:#A`P!9X0(``(H"```:``!8X0```)H!8*#C\#65Y08`4^$"```:[#75 +MY0``4^,0```:!@!2XP<``!KA-]3E"``3XP0```H`,`#C`#!`XQ(@AN("(9/G +M`@``Z@`P`.,`,$#C!B&3YP0`H.$(%0#C_O__Z_!EA>4!,*#C[#7%Y0D``.KL +M)=#E``!2XP8```H$`*#A"!4`X^PH`N,"()/G_O__ZP`PH./L-<7E`""@X_@U +M`>,#((3G53V@X],`A.%8-0'C\P"$X18\H./3`(3A!X_,`A.'XC[WHT$`M +MZ0!`H.'08<#A`0B@XP`0H.,`(`;@`3`'X`,0DN$C```*&#"4Y0,`4^,@``": +M*#"4Y0(`4^,"```:0`&?Y?[__^L7``#J!`!3XP(``!HP`9_E_O__ZQ(``.H( +M`%/C`@``&B`!G^7^___K#0``ZA``4^,"```:$`&?Y?[__^L(``#J(`!3XP(` +M`!H``9_E_O__ZP,``.I``%/C`0``&O``G^7^___K[`"?Y>P0G^7^___K(#"4 +MY0$($^/0@+T('S#4Y00`4^,!```:!`"@X?[__^O08<3A`0B@XP`0H.,`(`;@ +M`3`'X`,0DN'0@+T(&#"4Y0,`4^/0@+V8*#"4Y0(`4^,"```:=`"?Y?[__^L7 +M``#J!`!3XP(``!ID`)_E_O__ZQ(``.H(`%/C`@``&E0`G^7^___K#0``ZA`` +M4^,"```:1`"?Y?[__^L(``#J(`!3XP(``!HT`)_E_O__ZP,``.I``%/C`0`` +M&B0`G^7^___K*`"?Y2`0G^7^___KT("]Z&P)``!X"0``A`D``)0)``"D"0`` +ML`D``"@3``!D%@``7!,``-!`+>D`0*#A`!"0Y0`PH./L-<#E[37`Y?@E`>," +M,('GT&'`X0$(H.,`$*#C`"`&X`$P!^`#$)+AT("]"!@PE.4#`%/CT("]F"@P +ME.4"`%/C`@``&K@"G^7^___K%P``Z@0`4^,"```:J`*?Y?[__^L2``#J"`!3 +MXP(``!J8`I_E_O__ZPT``.H0`%/C`@``&H@"G^7^___K"```ZB``4^,"```: +M>`*?Y?[__^L#``#J0`!3XP$``!IH`I_E_O__ZP0`H.$%'*#C_O__ZP`@H.%4 +M`I_E5!*?Y?[__^O08<3A`0B@XP`0H.,`(`;@`3`'X`,0DN'0@+T(&#"4Y0,` +M4^/0@+V8*#"4Y0(`4^,"```:_`&?Y?[__^L7``#J!`!3XP(``!KL`9_E_O__ +MZQ(``.H(`%/C`@``&MP!G^7^___K#0``ZA``4^,"```:S`&?Y?[__^L(``#J +M(`!3XP(``!J\`9_E_O__ZP,``.I``%/C`0``&JP!G^7^___K!`"@X005`./^ +M___K`""@X:`!G^68$9_E_O__Z]!AQ.$!"*#C`!"@XP`@!N`!,`?@`Q"2X="` +MO0@8,)3E`P!3X]"`O9@H,)3E`@!3XP(``!I``9_E_O__ZQ<``.H$`%/C`@`` +M&C`!G^7^___K$@``Z@@`4^,"```:(`&?Y?[__^L-``#J$`!3XP(``!H0`9_E +M_O__ZP@``.H@`%/C`@``&@`!G^7^___K`P``ZD``4^,!```:\`"?Y?[__^L$ +M`*#A"!4`X_[__^L`(*#AZ`"?Y=P0G^7^___KT&'$X0$(H.,`$*#C`"`&X`$P +M!^`#$)+AT("]"!@PE.4#`%/CT("]F"@PE.4"`%/C`@``&H0`G^7^___K%P`` +MZ@0`4^,"```:=`"?Y?[__^L2``#J"`!3XP(``!ID`)_E_O__ZPT``.H0`%/C +M`@``&E0`G^7^___K"```ZB``4^,"```:1`"?Y?[__^L#``#J0`!3XP$``!HT +M`)_E_O__ZP0`H.$,%0#C_O__ZP`@H.$P`)_E(!"?Y?[__^O0@+WH;`D``'@) +M``"$"0``E`D``*0)``"P"0``D!,``'@6``"P$P``T!,``/`3``#00"WI`$"@ +MX=!AP.%``*#C`!"@XP`@!N`!,`?@`Q"2X2,```H8,)3E`P!3XR```)HH,)3E +M`@!3XP(``!K\`)_E_O__ZQ<``.H$`%/C`@``&NP`G^7^___K$@``Z@@`4^," +M```:W`"?Y?[__^L-``#J$`!3XP(``!K,`)_E_O__ZP@``.H@`%/C`@``&KP` +MG^7^___K`P``ZD``4^,!```:K`"?Y?[__^NH`)_EJ!"?Y?[__^L`,*#C<#6$ +MY7@UA.5T-83E?#6$Y0(@H.-@)<3E827$Y0`@X.-8)<3E7#6$Y6(`0*#A``"0 +MY2`PE.4!!!/C$```"F`VU.4``%/C"@``&F`PH.,`,(WE!`"@X0`0H.,D(*#C +M_S\/XP\P0./^___K`3"@XV`VQ.4"``#J_O__ZP`PH.-@-L3E"-"-XA"`O>@0 +M0"WI'S#0Y00`4^,0@+T8_O__ZQ"`O>@00"WI`$"@X5L>@.($$('B_O__ZP0` +MH.'E'H3B_O__ZQ"`O>@00"WI6QZ`X@00@>+^___K$("]Z`3@+>4,T$WB`#`` +MXP`P0.,`,(WE6QZ`X@00@>(`(`#C`"!`XP`PH./^___K#-"-X@"`O>CP3RWI +MI-!-X@``D.40`(WE.SR@XP,PD.<4,(WE(`"-X@`0H..`(*#C_O__ZQ``G>5L +M,)#E`0`3XWL```H8,(WB["&?Y0,`DN@$`(/DL!##X?[__^L-$*#A?SW!XS\P +MP^,$()/E`2""X@0@@^40()WE#2N"XA$@@N(`((WE$#"=Y1>\@^((L(OB``"@ +MXP0`C>7_$*#C"!"-Y0P`C>4`D*#A!G"@XQB@C>(NCHGB`8"(XA`@G>6(@8+@ +M`%";Y28``.H(8$7B`%"5Y>!`AN($`*#A"A"@X0<@H.'^___K``!0XQT``!H$ +M`*#A`!"=Y0<@H.'^___K``!0XQ<``!K0,);E`0`3XQ0```H0.);E"`"=Y0,` +M4.$#`*"A"`"-Y0P0G>4#`%'A`Q"@L0P0C>4!`'/C"0``"J``C>($$)WE`2&` +MX-@0EN4#.('A@#`"Y00@G>4!,(+B4(`*#A!1"@X?[__^L``%#C +MT___"@&0B>((L(OB(`!9X\G__QH4<)WE#0"@X7\]P.,_,,/C!""3Y0$@0N($ +M((/E_O__ZP00G>4``%'C$@``VJFMA^(0H(KB`5&@X0!`H.,@8(WB&HH"XP0@ +MEN<``%+C!@``"@@PU^7_`%/C-#H"$P@`G14#`(<7 +M`""@`S0Z`@,#((<'I-"-XO"/O>B@%@``$$`MZ2`PD.40`!/C$("]"!\PT.4$ +M`%/C$("]&/[__^L0@+WH\$`MZ1S03>(`8*#A`7"@X0W`H.$XX)_E#P"^Z`\` +MK.@#`)[H`P",Z`!`H.,-4*#A!@"@X000E><'(*#A_O__ZP1`A.(8`%3C^/__ +M&AS0C>+P@+WHJ!8``'!`+>D`0*#A`5"@X1DTT.4!`%/A`@``"@H:`.,%(*#A +M_O__ZQDTU.48-,3E&53$Y7"`O>@00"WI(#"0Y2@`$^,0@+T(,##0Y0``4^,0 +M@+T8EC#0Y0``4^,+```*ES#0Y1D`4^/-$*"##0``B@LP0^)S,._F#@!3XP8` +M`)KX-)#E^@]3XP,``(H$``#J^#20Y?H/4^,!``":@Q"@XP```.I`$*#C_O__ +MZQ"`O>CP0"WI'-!-X@!0D.4[/*#C`V"5YPW`H.%$X)_E#P"^Z`\`K.@#`)[H +M`P",Z`!`H.,-<*#A!#"&X*D]@^(',(/B!0"@X001E^<`(-/E_O__ZP%`A.(& +M`%3C]?__&AS0C>+P@+WHP!8``/!`+>D+P@+WHV!8``!!`+>D`0*#A +M)!@`XP(LH./^___K'`#$Y00`H.$$'`#C#R"@X_[__^L=`,3E!`"@X?[__^L0 +M@+WH$$`MZ0!`H.'^___K!`"@X?[__^L$`*#A_O__ZP0`H.'^___K!`"@X?[_ +M_^L$`*#A_O__ZP0`H.'^___K!`"@X?[__^L$`*#A_O__ZP0`H.'^___K!`"@ +MX?[__^L$`*#A_O__ZQ"`O>@00"WI`$"@X?[__^L$`*#A_O__ZP0`H.'^___K +M!`"@X?[__^L$`*#A_O__ZP0`H.'^___K!`"@X?[__^L$`*#A_O__ZP0`H.'^ +M___K!`"@X?[__^L$`*#A_O__ZP0`H.'^___K!`"@X?[__^L0@+WH,``MZ4#0 +M3>(`4*#A`$``XP!`0.,$P(WB#P"TZ`\`K.@/`+3H#P"LZ`\`M.@/`*SH!P"4 +MZ`,`K.BR(,S@(BB@X0`@S.4.`%7C$```FA(PW>4%`%/A#C"@`P0```H$((WB +M#S"@XP\0TN4%`%'A`@``&@TP0^)S`._F!0``Z@$P@^)S,._F`2""XCL`4^/T +M__\:``"@XT#0C>(P`+WH'O\OX=!`+>D`0*#A`#"0Y;8QT^$+,$/B#>/O?0SCL(&?Y021 +MH.$)$)CG`3"$X@,AF.?,/0SCS3U,XP,`4>$#``"*"@"@X7(@[^;^___K6P`` +MZ@`@G>4"`%'A*@``"O\P`>($()WE`P`2X0`@H!,!(*`#'P!3XP`PH`,!,`(2 +M``!3XP4``!I1-.?G!P!3XP(``!I1&.?G#P!1XQH```H"((3B`T"$X@0QF.<% +M`%/A!P!3$1(```K-'0SC`0!3X0\```JO`%+C#0``B@`0H.,)D(C@S0T,XP(@ +M@N(!,(G@%#"3Y04`4^$'`%,1!```"@``4^$"```*"!"!XJ\`4N/T__^:`D!" +MXBT``.H"0(3B!!&8YP$PA.(#(9CG!0!2X0<`4A$6```*S3T,XP,`4N$5```* +MKP!4XQ$``(H`8*#C"9"(X`.PH.$*`*#AB8"P``S3T,X\T]3.,#`%#A +M`0"@`Q[_+P'_,`#B`P`1X0`@H!,!(*`#'P!3XP`PH`,!,`(2``!3XP<``!I0 +M-.?G!P!3XP0``!I0".?G#P!0XP``H!,!`*`#'O\OX0``H.,>_R_A\$\MZ0S0 +M3>(`D*#A+S#0Y?\T@^(D(-#E`C2#X!\@T.4"*(/@!""-Y0!`H..M7@WC[WT, +MXX2AG^7-C0SC!"&@X0`@C>4"$)KG`3"$X@,QFN?,+0SCS2U,XP(`4>$#``"* +M"0"@X0`@X./^___K3@``Z@$`H.$$$)WER/__ZP``4.,9```:`B"$X@-`A.($ +M,9KG!0!3X0<`4Q$1```*"`!3X0\```H!`%+C#0``B@`0H.,`,)WE`P"*X`(@ +M@N(!,(#@%#"3Y04`4^$'`%,1!```"@@`4^$"```*"!"!X@$`4N/T__^:`D!" +MXB\``.H"0(3B!!&:YP$PA.(#,9KG!0!3X0<`4Q$8```*"`!3X1@```H!`%3C +M%```B@!@H.,`L.#C`""=Y0(@BN``((WE"0"@X0L@H.'^___K`D"$X@`@G>4& +M,(+@$!"3Y10PD^4%`%/A!P!3$00```H(`%/A!```"@A@AN(!`%3C[___F@4` +M4^$-```*`0!4XPL``(H$,*#A`""@XP1!BN`",(/B`A"$X`P0D>4%`%'A`@`` +M"@@@@N(!`%/C]___F@-`H.$"0(3B`P!4XZ#__YH,T(WB\(^]Z&`.``#P3RWI +M#-!-X@"0H.$O,-#E_S2#XB0@T.4"-(/@'R#0Y0(H@^`$((WE`$"@XYRAG^6M +M7@WC[XT,XWEA`.,$(:#A`""-Y0(0FN57___K``!0XQL``!H"((3B`T"$ +MX@0QFN<%`%/A"`!3$1,```K-'0SC`0!3X1````H&`%+A#@``B@`0H.,`,)WE +M`P"*X,W-#.,"((+B`3"`X!0PD^4%`%/A"`!3$00```H,`%/A`@``"@@0@>(& +M`%+A]/__F@)`0N(Q``#J`D"$X@01FN4)`*#A"R"@ +MX?[__^L"0(3B`""=Y04%`%'A`@``"@@@@N(&`%/A]___F@-`H.$"0(3B7P]4XYS_ +M_SH,T(WB\(^]Z'`.``#P3RWI#-!-X@"0H.$O,-#E_S2#XB0@T.4"-(/@'R#0 +MY0(H@^`$((WE`$"@XXRAG^6M7@WC[WT,X\V-#.,$(:#A`""-Y0(0FN7B +M_O_K``!0XQD``!H"((3B`T"$X@0QFN<%`%/A!P!3$1$```H(`%/A#P``"OT` +M4N,-``"*`!"@XP`PG>4#`(K@`B""X@$P@.`4,)/E!0!3X0<`4Q$$```*"`!3 +MX0(```H($('B_0!2X_3__YH"0$+B+P``Z@)`A.($$9KG`3"$X@,QFN<%`%/A +M!P!3$1@```H(`%/A&```"OT`5.,4``"*`&"@XP"PX.,`()WE`B"*X``@C>4) +M`*#A"R"@X?[__^L"0(3B`""=Y08P@N`0$)/E%#"3Y04`4^$'`%,1!```"@@` +M4^$$```*"&"&XOT`5./O__^:!0!3X0T```K]`%3C"P``B@0PH.$`(*#C!$&* +MX`(P@^("$(3@#!"1Y04`4>$"```*""""XOT`4^/W__^:`T"@X0)`A.+_`%3C +MH/__F@S0C>+PC[WH8!0``/!/+>D,T$WB`*"@X2\PT.7_-(/B)"#0Y0(T@^`? +M(-#E`BB#X`0@C>4`0*#CS2T,X\TM3.,`((WEK5X-X^]]#..H@9_E!)&@X0D0 +MF.,:```*`B"$X@-`A.($,9CG!0!3X0<`4Q$2 +M```*S1T,XP$`4^$/```*PP!2XPT``(H`$*#C"9"(X,T-#.,"((+B`3")X!0P +MD^4%`%/A!P!3$00```H``%/A`@``"@@0@>+#`%+C]/__F@)`0N(L``#J`D"$ +MX@01F.A@&````0"@XQ[_+^$>_R_A<$,MZ0%0H.$"8*#A +M.SR@XP-`D.=@.@+CTX"$X0$#H.,`$*#C`"`(X`$P">`#$)+A<(.]"&@Z`N,# +M,)3G`P!3XW"#O9AX.@+C`S"4YP(`4^,"```:2`&?Y?[__^L7``#J!`!3XP(` +M`!HX`9_E_O__ZQ(``.H(`%/C`@``&B@!G^7^___K#0``ZA``4^,"```:&`&? +MY?[__^L(``#J(`!3XP(``!H(`9_E_O__ZP,``.I``%/C`0``&O@`G^7^___K +M]`"?Y?00G^4%(*#A_O__ZV`Z`N/3@(3A`0.@XP`0H.,`(`C@`3`)X`,0DN%P +M@[T(:#H"XP,PE.<#`%/C<(.]F'@Z`N,#,)3G`@!3XP(``!J,`)_E_O__ZQ<` +M`.H$`%/C`@``&GP`G^7^___K$@``Z@@`4^,"```:;`"?Y?[__^L-``#J$`!3 +MXP(``!I<`)_E_O__ZP@``.H@`%/C`@``&DP`G^7^___K`P``ZD``4^,!```: +M/`"?Y?[__^L``%;C`"``XP`@0.,`,`#C`#!`XP,@H`$H`)_E(!"?Y?[__^MP +M@[WHW!0``.@4``#T%```!!4``!05```@%0``+!4``-10``!H%0``\$\MZ3S0 +M3>(4$(WE&""-Y1PPC>4[/*#C`X"0YP`P`.,`,$#CN#'3X;0SS>$`,)CE`3!# +MX@$`4^,%``"*$#"8Y0(`4^,!`*`#(`"-!0B0H`,"```*`!"@XR`0C>4$D*#C +M8#H"X]-`B.$!`Z#C`!"@XP`@!.`!,`7@`P"2X2<```IH.@+C`S"8YP,`4^,C +M``":>#H"XP,PF.<"`%/C`@``&@@$G^7^___K%P``Z@0`4^,"```:^`.?Y?[_ +M_^L2``#J"`!3XP(``!KH`Y_E_O__ZPT``.H0`%/C`@``&M@#G^7^___K"``` +MZB``4^,"```:R`.?Y?[__^L#``#J0`!3XP$``!JX`Y_E_O__Z[0#G^6T$Y_E +M&""=Y1PPG>7^___K``!9XP"@H`-N```*%!"=Y1@@G>6"`` +M4*#C`6"@XP6@H.$%0*#A`#``XP`P0.,D,(WE`#``XP`P0.,H,(WE`#``XP`P +M0.,L,(WE!3"7YP4@F^<"`%/A`S!BP`(P8]`%`%/C4```FF`Z`N/3`(CA`""@ +MX0$PH.$!`Z#C`!"@XP`@`N`!,`/@`Q"2X2D```IH.@+C`S"8YP,`4^,E``": +M>#H"XP,PF.<"`%/C`@``&M`"G^7^___K%P``Z@0`4^,"```:P`*?Y?[__^L2 +M``#J"`!3XP(``!JP`I_E_O__ZPT``.H0`%/C`@``&J`"G^7^___K"```ZB`` +M4^,"```:+`"=Y?[__^L#``#J0`!3XP$``!HH`)WE_O__ZP4PF^<`,(WE)`"= +MY702G^4$(*#A!3"7Y_[__^L&`%3C`@!4$Q<``!H``%KC%0``&@8QH.$#$)?G +M!2"7YP(@@>```%+C!```&C@@C>(D,8+@'`"=Y00`0^4,``#J`R";YP4PF^<# +M,(+@``!3XS@0C0(D,8$`&""=!00@0P4!,*`3$Z2*$0$``.H!,*#C$Z2*X0%` +MA.(!8(;B!%"%X@D`5.&B__\:8#H"X]-`B.$!`Z#C`!"@XP`@!.`!,`7@`P"2 +MX28```IH.@+C`S"8YP,`4^,B``":>#H"XP,PF.<"`%/C`@``&H`!G^7^___K +M%P``Z@0`4^,"```:<`&?Y?[__^L2``#J"`!3XP(``!I@`9_E_O__ZPT``.H0 +M`%/C`@``&E`!G^7^___K"```ZB``4^,"```:0`&?Y?[__^L#``#J0`!3XP$` +M`!HP`9_E_O__ZS0!G^4L$9_E"B"@X?[__^L``%KC'@``&BF1L.$!`*`#.P`` +M"@+`H.,!`*#C`$"@XS10C>($8*#A%'"=Y000U>?_`%'C#0``"@0QH.$,`%/A +M"0``*H$2A^`#(:#A`A"!X`(@A^`$`)'D8`""Y0$P@^($((+B`P!48()WE@@*!X`$@ +MH.$`,*#C`Q"0YV`0@N4$,(/B!"""XA``4^/Y__\:$```ZO``&N,@`)WE`#"@ +M$P$P``(``%/C"@``"A00G>48,)WE@R*!X`$PH.$0`('B$!"2Y7`0@^4$((+B +M!#"#X@``4^'Y__\:``"@XSS0C>+PC[WHW!0``.@4``#T%```!!4``!05```@ +M%0``B!4``/!0```H%@``\$-G```:T('`X0$$ +MH.,`$*#C`"`(X`$P">`#$)+A)0``"A@PE>4#`%/C(@``FB@PE>4"`%/C`@`` +M&H0"G^7^___K%P``Z@0`4^,"```:=`*?Y?[__^L2``#J"`!3XP(``!ID`I_E +M_O__ZPT``.H0`%/C`@``&E0"G^7^___K"```ZB``4^,"```:1`*?Y?[__^L# +M``#J0`!3XP$``!HT`I_E_O__ZS`"G^4P$I_EX"W5Y>,]U>7^___KX"W5Y>(] +MU>4#`%+A`3"@DP`PQI7B3=65X#W5E0(PH(,`,,:%X$W5A>(]U84$0&/@=$#O +MYM"!Q>$!!*#C`!"@XP`@".`!,`G@`Q"2X6,```H8,)7E`P!3XV```)HH,)7E +M`@!3XP(``!J<`9_E_O__ZQ<``.H$`%/C`@``&HP!G^7^___K$@``Z@@`4^," +M```:?`&?Y?[__^L-``#J$`!3XP(``!IL`9_E_O__ZP@``.H@`%/C`@``&EP! +MG^7^___K`P``ZD``4^,!```:3`&?Y?[__^M(`9_E2!&?Y>`MU>7C/=7E_O__ +MZSP``.H!`%'C`$"@$SX``!K0@<#A`02@XP`0H.,`(`C@`3`)X`,0DN$E```* +M&#"5Y0,`4^,B``":*#"5Y0(`4^,"```:V`"?Y?[__^L7``#J!`!3XP(``!K( +M`)_E_O__ZQ(``.H(`%/C`@``&K@`G^7^___K#0``ZA``4^,"```:J`"?Y?[_ +M_^L(``#J(`!3XP(``!J8`)_E_O__ZP,``.I``%/C`0``&H@`G^7^___KC`"? +MY800G^7D+=7EYCW5Y?[__^OD+=7EYCW5Y0,`4N$!,*"3`##&E>9-U97D/=65 +M`C"@@P`PQH7D3=6%YCW5A01`8^!T0._F!0!4XP(``)H`,-;E`0!3XP9`H`,$ +M.*#A!#2#X00P@^$$3(/A`$"'Y?"'O>C<%```Z!0``/04```$%0``%!4``"`5 +M``!L%@``#%$``)P6``!P3RWI`6"@X0)0H.$[/*#C`S"0YZE-@^(00(3B8"H" +MX]*@@^$!@Z#C`)"@XP@`"N`)$`O@`2"0X24```IH*@+C`B"3YP,`4N,A``": +M>"H"XP(PD^<"`%/C`@``&L``G^7^___K%P``Z@0`4^,"```:L`"?Y?[__^L2 +M``#J"`!3XP(``!J@`)_E_O__ZPT``.H0`%/C`@``&I``G^7^___K"```ZB`` +M4^,"```:@`"?Y?[__^L#``#J0`!3XP$``!IP`)_E_O__ZVP`G^5L$)_E_O__ +MZP0`H.$`$);E/R"@X_[__^L$(-7E!`"@X000EN7W(`+B_O__ZP@@U>4$`*#A +M"!"6Y?<@`N+^___K#"#5Y00`H.$,$);EWR`"XO[__^MPC[WHW!0``.@4``#T +M%```!!4``!05```@%0``X!8``"11``#P02WI"-!-X@!0H.$!<*#A.SR@XP-` +MD.>I383B$$"$X@0`H.$#'0#C_O__ZP!@H.%P`!#C#```"@0`H.$#'0#CCR`& +MXO[__^L%`*#A`!"@XP$@H.'_/P#C_O__ZP"`H.$``%?C3@``"A8``.H$`*#A +M(A4`X_\@H./^___K!0"@X0`0H.,8(*#C_S\`X_[__^L""8#C``"-Y00`H.$` +M$*#C&""@X_\_`./^___K9`"@X_[__^L$`*#A(A4`XP`@H./^___K5P``Z@4` +MH.$!$*#C`""@X_\_`./^___K`'"@X?\TR./W.,/C`3B#XP`PC>4$`*#A`!"@ +MXP$@H.'_/P#C_O__Z_\TQ^/W.,/C`3B#XP`PC>4$`*#A`1"@XP`@H./_/P#C +M_O__ZP4`H.$`$*#C&""@X_\_`./^___K`@F`XP``C>4$`*#A`!"@XQ@@H./_ +M/P#C_O__ZV0`H./^___K!`"@X0,=`.,&(*#A_O__ZP"`C>4$`*#A`!"@XP$@ +MH.'_/P#C_O__ZP!PC>4$`*#A`1"@XP`@H./_/P#C_O__ZR```.K_-,#C]SC# +MXP$X@^,`,(WE!`"@X0`0H.,!(*#A_S\`X_[__^L%`*#A`!"@XQ@@H./_/P#C +M_O__ZP()@.,``(WE!`"@X0`0H.,8(*#C_S\`X_[__^MD`*#C_O__ZP0`H.$# +M'0#C!B"@X?[__^L`@(WE!`"@X0`0H.,!(*#A_S\`X_[__^L(T(WB\(&]Z/!' +M+>D`H*#A.SR@XP-0D.=P.@+C`S"5YP$#$^/PA[T(T#H"XP,PE><`,-/E``!3 +MXPX```H`0*#C,G"@X]!J`N//AP#C!P"@X?[__^LR0(3B!C"5YP`@T^4`,%+B +M`3"@$P@`5.$`,*"#``!3X_3__QH!(*#C?3<#XP,@Q><0,)7E`@!3XPH`H.$" +M$*`!`!"@$_[__^L`(*#C?3<#XP,@Q>=@.@+CTV"%X0$#H.,`$*#C`"`&X`$P +M!^`#$)+A\(>]"&@Z`N,#,)7G`P!3X_"'O9AX.@+C`S"5YP(`4^,"```:?`"? +MY?[__^L7``#J!`!3XP(``!IL`)_E_O__ZQ(``.H(`%/C`@``&EP`G^7^___K +M#0``ZA``4^,"```:3`"?Y?[__^L(``#J(`!3XP(``!H\`)_E_O__ZP,``.I` +M`%/C`0``&BP`G^7^___K*`"?Y2@0G^7H.@+C`R#5Y_[__^OPA[WHW!0``.@4 +M``#T%```!!4``!05```@%0``"!<``$!1``#P1RWI"-!-X@&@H.$"@*#A`W"@ +MX3L\H.,#0)#GJ6V$XA!@AN+^___K``!0XST```I@.@+CTP"$X?``S>$!`Z#C +M`!"@X]`@S>$`(`+@`3`#X`,0DN$E```*:#H"XP,PE.<#`%/C(0``FG@Z`N,# +M,)3G`@!3XP(``!JP`)_E_O__ZQ<``.H$`%/C`@``&J``G^7^___K$@``Z@@` +M4^,"```:D`"?Y?[__^L-``#J$`!3XP(``!J``)_E_O__ZP@``.H@`%/C`@`` +M&G``G^7^___K`P``ZD``4^,!```:8`"?Y?[__^M<`)_E7!"?Y?[__^L``%?C +M"P``"@!`H.,$4*#A`)#@XP8`H.$$$)KG"2"@X?[__^L$`(CG`5"%X@1`A.(' +M`%7A]O__&@C0C>+PA[WHW!0``.@4``#T%```!!4``!05```@%0``+!<``%A1 +M``#P1RWI`5"@X3L\H.,#,)#GJ4V#XA!`A.)@*@+CTH"#X0%CH.,`<*#C!@`( +MX`<0">`!()#A*P``"F@J`N,"()/G`P!2XR<``)IX*@+C`C"3YP(`4^,"```: +MR`"?Y?[__^L7``#J!`!3XP(``!JX`)_E_O__ZQ(``.H(`%/C`@``&J@`G^7^ +M___K#0``ZA``4^,"```:F`"?Y?[__^L(``#J(`!3XP(``!J(`)_E_O__ZP,` +M`.I``%/C`0``&G@`G^7^___K``!5XP`@`.,`($#C`#``XP`P0.,#(*`!7`"? +MY5P0G^7^___K``!5XP`Q`.,`,4#C`U"@$0%4H`,$`*#A@AZ@XP`@X.,%,*#A +M_O__ZP0`H.$H&`#C`"#@XP4PH.'^___K\(>]Z-P4``#H%```]!0```05```4 +M%0``(!4``%07``!P40``T$,MZ3L\H.,#,)#GJ4V#XA!`A.)@*@+CTH"#X0%C +MH.,`<*#C!@`(X`<0">`!()#A)0``"F@J`N,"()/G`P!2XR$``)IX*@+C`C"3 +MYP(`4^,"```:M`"?Y?[__^L7``#J!`!3XP(``!JD`)_E_O__ZQ(``.H(`%/C +M`@``&I0`G^7^___K#0``ZA``4^,"```:A`"?Y?[__^L(``#J(`!3XP(``!IT +M`)_E_O__ZP,``.I``%/C`0``&F0`G^7^___K8`"?Y6`0G^7^___K!`"@X2@> +M`.,`(.#C`#"@X_[__^L$`*#A(1V@XP`@X.,!.*#C_O__ZP0`H.$H'@#C`"#@ +MXP`P`..`,$CC_O__Z]"#O>C<%```Z!0``/04```$%0``%!4``"`5``!T%P`` +MA%$``/!-+>D(T$WB`7"@X0)`H.$#@*#A.SR@XP,PD.>I;8/B$&"&XF`J`N/2 +M`(/A\`#-X0&CH.,`L*#C"@``X`L0`>`!()#A)0``"F@J`N,"()/G`P!2XR$` +M`)IX*@+C`C"3YP(`4^,"```:]`"?Y?[__^L7``#J!`!3XP(``!KD`)_E_O__ +MZQ(``.H(`%/C`@``&M0`G^7^___K#0``ZA``4^,"```:Q`"?Y?[__^L(``#J +M(`!3XP(``!JT`)_E_O__ZP,``.I``%/C`0``&J0`G^7^___KH`"?Y:`0G^7^ +M___K``!4XZ15`@,;6T`#I%4"$]M40!,``%CC"```&@8`H.$`$)?E`"#@XZ`U +M`N,;.T#C_O__ZZ!5`N/;6T#C!```Z@8`H.$`$)?E`"#@XP4PH.'^___K`4"@ +MXP"`X.,&`*#A!!&7YP@@H.$%,*#A_O__ZP%`A.(0`%3C]___&@C0C>+PC;WH +MW!0``.@4``#T%```!!4``!05```@%0``D!<``)A1``#P1RWI"-!-X@&@H.$" +M@*#A`W"@X3L\H.,#,)#GJ6V#XA!@AN)@*@+CT@"#X?``S>$!0Z#C`%"@XP0` +M`.`%$`'@`2"0X24```IH*@+C`B"3YP,`4N,A``":>"H"XP(PD^<"`%/C`@`` +M&K``G^7^___K%P``Z@0`4^,"```:H`"?Y?[__^L2``#J"`!3XP(``!J0`)_E +M_O__ZPT``.H0`%/C`@``&H``G^7^___K"```ZB``4^,"```:<`"?Y?[__^L# +M``#J0`!3XP$``!I@`)_E_O__ZUP`G^5<$)_E_O__ZP``5^,+```*`$"@XP10 +MH.$`D.#C!@"@X000FN<)(*#A!#"8Y_[__^L!4(7B!$"$X@<`5>'V__\:"-"- +MXO"'O>C<%```Z!0``/04```$%0``%!4``"`5``"@%P``J%$``/!/+>D,T$WB +M`5"@X0)PH.$#8*#A,*#=Y3L\H.,#0)#G8#H"X].`A.$!`Z#C`!"@XP`@".`! +M,`G@`P"2X2L```IH.@+C`S"4YP,`4^,G``":>#H"XP,PE.<"`%/C`@``&C0# +MG^7^___K%P``Z@0`4^,"```:)`.?Y?[__^L2``#J"`!3XP(``!H4`Y_E_O__ +MZPT``.H0`%/C`@``&@0#G^7^___K"```ZB``4^,"```:]`*?Y?[__^L#``#J +M0`!3XP$``!KD`I_E_O__ZP``5>,`(`#C`"!`XP`P`.,`,$#C`R"@`<@"G^7( +M$I_E_O__Z_\`5N.F```*``!5XZ0```JI783B$%"%X@4`H.&('`#C`"#@X_[_ +M_^L@FZ#AAF*'X!!PEN4"#!?C!WO@$2=[X!&9!PC@*+2@X6`Z`N/3`(3A\`#- +MX0$#H.,`$*#CT"#-X0`@`N`!,`/@`Q"2X2<```IH.@+C`S"4YP,`4^,C``": +M>#H"XP,PE.<"`%/C`@``&A0"G^7^___K%P``Z@0`4^,"```:!`*?Y?[__^L2 +M``#J"`!3XP(``!KT`9_E_O__ZPT``.H0`%/C`@``&N0!G^7^___K"```ZB`` +M4^,"```:U`&?Y?[__^L#``#J0`!3XP$``!K$`9_E_O__Z\@!G^7`$9_E!R"@ +MX0LPH.'^___K!0"@X8@<`./_(P#C"S"@X?[__^L%`*#A3!P`XP(CH./8,^#G +M_O__ZQ1PEN4"#!?C!WO@$2=[X!&9!PG@*82@X0BPH.%@.@+CTP"$X?``S>$! +M`Z#C`!"@X]`@S>$`(`+@`3`#X`,0DN$G```*:#H"XP,PE.<#`%/C(P``FG@Z +M`N,#,)3G`@!3XP(``!H(`9_E_O__ZQ<``.H$`%/C`@``&O@`G^7^___K$@`` +MZ@@`4^,"```:Z`"?Y?[__^L-``#J$`!3XP(``!K8`)_E_O__ZP@``.H@`%/C +M`@``&L@`G^7^___K`P``ZD``4^,!```:N`"?Y?[__^O``)_EM!"?Y0<@H.$+ +M,*#A_O__ZP4`H.&<'`#C#R*@XULSX^?^___K!0"@X8@<`.,_**#C/S`(XO[_ +M_^L%`*#A3!P`XP(DH./9,^#G_O__ZP``6N,0```:!0"@X1P<`./_(P#C&#"6 +MY?[__^L<,);E!0"@X1P<`.,_*Z#C/S`#XO[__^L<,);E!0"@X7@<`.,/*J#C +M4S/CY_[__^L,T(WB\(^]Z-P4``#H%```]!0```05```4%0``(!4``.`7``#$ +M40``!!@``"08``#P3RWI%-!-X@%0H.$"<*#A`V"@X3B@W>4[/*#C`T"0YV`Z +M`N/3@(3A`0.@XP`0H.,`(`C@`3`)X`,`DN$K```*:#H"XP,PE.<#`%/C)P`` +MFG@Z`N,#,)3G`@!3XP(``!KT`Y_E_O__ZQ<``.H$`%/C`@``&N0#G^7^___K +M$@``Z@@`4^,"```:U`.?Y?[__^L-``#J$`!3XP(``!K$`Y_E_O__ZP@``.H@ +M`%/C`@``&K0#G^7^___K`P``ZD``4^,!```:I`.?Y?[__^L``%7C`"``XP`@ +M0.,`,`#C`#!`XP,@H`&(`Y_EB!.?Y?[__^O_`%;CU@``"@``5>/4```*J5V$ +MXA!0A>(%`*#A,AV@XP`@X./^___K()N@X89RA^``8)?E`@P6XP9KX!$F:^`1 +MF08(X"BTH.%@.@+CTP"$X?@`S>$!`Z#C`!"@X]@@S>$`(`+@`3`#X`,0DN$H +M```*:#H"XP,PE.<#`%/C)```FG@Z`N,#,)3G`@!3XP(``!K4`I_E_O__ZQ<` +M`.H$`%/C`@``&L0"G^7^___K$@``Z@@`4^,"```:M`*?Y?[__^L-``#J$`!3 +MXP(``!JD`I_E_O__ZP@``.H@`%/C`@``&I0"G^7^___K`P``ZD``4^,!```: +MA`*?Y?[__^L`D(WEA`*?Y7P2G^4&(*#A"S"@X?[__^L%`*#A,AV@X_\C`.,+ +M,*#A_O__ZP4`H.%,'`#C`B&@X]@SX.?^___K!&"7Y0(,%N,&:^`1)FO@$9D& +M">`IA*#A"+"@X6`Z`N/3`(3A^`#-X0$#H.,`$*#CV"#-X0`@`N`!,`/@`Q"2 +MX2<```IH.@+C`S"4YP,`4^,C``":>#H"XP,PE.<"`%/C`@``&L0!G^7^___K +M%P``Z@0`4^,"```:M`&?Y?[__^L2``#J"`!3XP(``!JD`9_E_O__ZPT``.H0 +M`%/C`@``&I0!G^7^___K"```ZB``4^,"```:A`&?Y?[__^L#``#J0`!3XP$` +M`!IT`9_E_O__ZWP!G^5P$9_E!B"@X0LPH.'^___K!0"@X90<`.,/(J#C6S/C +MY_[__^L%`*#A,AV@XS\HH.,_,`CB_O__ZP4`H.%,'`#C`B*@X]DSX.?^___K +M``!:XRX```I@.@+CTV"$X0$#H.,`$*#C`"`&X`$P!^`#`)+A-P``"F@Z`N,# +M,)3G`P!3XS,``)IX.@+C`S"4YP(`4^,"```:P`"?Y?[__^L7``#J!`!3XP(` +M`!JP`)_E_O__ZQ(``.H(`%/C`@``&J``G^7^___K#0``ZA``4^,"```:D`"? +MY?[__^L(``#J(`!3XP(``!J``)_E_O__ZP,``.I``%/C`0``&G``G^7^___K +M?`"?Y6P0G^7^___K$```Z@4`H.$4'`#C_R,`XP@PE^7^___K##"7Y04`H.$4 +M'`#C/RN@XS\P`^+^___K##"7Y04`H.'*'J#C#R*@XU,SX^?^___K%-"-XO"/ +MO>C<%```Z!0``/04```$%0``%!4``"`5``!$&```W%$``&@8``"8&```M!@` +M`/!/+>D,T$WB.SR@XP-`D.>I783B$%"%XF`Z`N/38(3A`0.@XP`0H.,`(`;@ +M`3`'X`,`DN%3```*:#H"XP,PE.<#`%/C3P``FG@Z`N,#,)3G`@!3XP(``!I4 +M!Y_E_O__ZQ<``.H$`%/C`@``&D0'G^7^___K$@``Z@@`4^,"```:-`>?Y?[_ +M_^L-``#J$`!3XP(``!HD!Y_E_O__ZP@``.H@`%/C`@``&A0'G^7^___K`P`` +MZD``4^,!```:!`>?Y?[__^L`!Y_E`!>?Y?[__^M@.@+CTV"$X0$#H.,`$*#C +M`"`&X`$P!^`#$)+A)0``"F@Z`N,#,)3G`P!3XR$``)IX.@+C`S"4YP(`4^," +M```:G`:?Y?[__^L7``#J!`!3XP(``!J,!I_E_O__ZQ(``.H(`%/C`@``&GP& +MG^7^___K#0``ZA``4^,"```:;`:?Y?[__^L(``#J(`!3XP(``!I8>H.,`(.#C +M`C"@X_[__^L%`*#AYAZ@XP`@X.,`,*#C_O__ZV`Z`N/38(3A`0.@XP`0H.,` +M(`;@`3`'X`,`DN$F```*:#H"XP,PE.<#`%/C(@``FG@Z`N,#,)3G`@!3XP(` +M`!J\!9_E_O__ZQ<``.H$`%/C`@``&JP%G^7^___K$@``Z@@`4^,"```:G`6? +MY?[__^L-``#J$`!3XP(``!J,!9_E_O__ZP@``.H@`%/C`@``&GP%G^7^___K +M`P``ZD``4^,!```:;`6?Y?[__^MT!9_E:!6?Y0H@H./^___K"@"@X_[__^L% +M`*#AK!X`XP`@X./^___K`&"@X6`Z`N/3@(3A`0.@XP`0H.,`(`C@`3`)X`,0 +MDN$F```*:#H"XP,PE.<#`%/C(@``FG@Z`N,#,)3G`@!3XP(``!KD!)_E_O__ +MZQ<``.H$`%/C`@``&M0$G^7^___K$@``Z@@`4^,"```:Q`2?Y?[__^L-``#J +M$`!3XP(``!JT!)_E_O__ZP@``.H@`%/C`@``&J0$G^7^___K`P``ZD``4^,! +M```:E`2?Y?[__^N@!)_ED!2?Y08@H.'^___K!0"@X;0>`.,`(.#C_O__ZP!P +MH.%@.@+CTX"$X0$#H.,`$*#C`"`(X`$P">`#`)+A)@``"F@Z`N,#,)3G`P!3 +MXR(``)IX.@+C`S"4YP(`4^,"```:%`2?Y?[__^L7``#J!`!3XP(``!H$!)_E +M_O__ZQ(``.H(`%/C`@``&O0#G^7^___K#0``ZA``4^,"```:Y`.?Y?[__^L( +M``#J(`!3XP(``!K4`Y_E_O__ZP,``.I``%/C`0``&L0#G^7^___KU`.?Y<`3 +MG^4'(*#A_O__ZP4`H.&\'@#C`"#@X_[__^L`@*#A8#H"X].@A.$!`Z#C`!"@ +MXP`@"N`!,`O@`Q"2X28```IH.@+C`S"4YP,`4^,B``":>#H"XP,PE.<"`%/C +M`@``&D0#G^7^___K%P``Z@0`4^,"```:-`.?Y?[__^L2``#J"`!3XP(``!HD +M`Y_E_O__ZPT``.H0`%/C`@``&A0#G^7^___K"```ZB``4^,"```:!`.?Y?[_ +M_^L#``#J0`!3XP$``!KT`I_E_O__ZP@#G^7P$I_E"""@X?[__^L%`*#AQ!X` +MXP`@X./^___K`*"@X6`Z`N/3`(3A\`#-X0$#H.,`$*#CT"#-X0`@`N`!,`/@ +M`Q"2X28```IH.@+C`S"4YP,`4^,B``":>#H"XP,PE.<"`%/C`@``&FP"G^7^ +M___K%P``Z@0`4^,"```:7`*?Y?[__^L2``#J"`!3XP(``!I,`I_E_O__ZPT` +M`.H0`%/C`@``&CP"G^7^___K"```ZB``4^,"```:+`*?Y?[__^L#``#J0`!3 +MXP$``!H<`I_E_O__ZS0"G^48$I_E"B"@X?[__^L%`*#AS!X`XP`@X./^___K +M`%"@X6`Z`N/3`(3A\`#-X0$#H.,`$*#CT"#-X0`@`N`!,`/@`Q"2X28```IH +M.@+C`S"4YP,`4^,B``":>#H"XP,PE.<"`%/C`@``&I0!G^7^___K%P``Z@0` +M4^,"```:A`&?Y?[__^L2``#J"`!3XP(``!IT`9_E_O__ZPT``.H0`%/C`@`` +M&F0!G^7^___K"```ZB``4^,"```:5`&?Y?[__^L#``#J0`!3XP$``!I$`9_E +M_O__ZV`!G^5`$9_E!2"@X?[__^L``%;C0```NE=XZ>=",0#C`P!7X3P```I8 +MB.GG0@!8XSD```H!`1;C!P``&EJHZ>#H"XP,PE.<"`%/C`@``&HP`G^7^___K%P``Z@0`4^,"```: +M?`"?Y?[__^L2``#J"`!3XP(``!IL`)_E_O__ZPT``.H0`%/C`@``&EP`G^7^ +M___K"```ZB``4^,"```:3`"?Y?[__^L#``#J0`!3XP$``!H\`)_E_O__ZUP` +MG^4X$)_E_O__ZP$`H.,"``#J``"@XP```.H!`*#C#-"-XO"/O>C<%```Z!0` +M`/04```$%0``%!4``"`5``#@&```]%$``/08```8&0``3!D``&`9``!T&0`` +MB!D``)P9``"P&0``\$\MZ0S03>([/*#C`U"0YZE-A>(00(3B8#H"X]-@A>$! +M`Z#C`!"@XP`@!N`!,`?@`Q"2X5,```IH.@+C`S"5YP,`4^-/``":>#H"XP,P +ME><"`%/C`@``&JP/G^7^___K%P``Z@0`4^,"```:G`^?Y?[__^L2``#J"`!3 +MXP(``!J,#Y_E_O__ZPT``.H0`%/C`@``&J0/G^7^___K"```ZB``4^,"```: +MJ`^?Y?[__^L#``#J0`!3XP$``!J8#Y_E_O__ZTP/G^64'Y_E_O__ZV`Z`N/3 +M8(7A`0.@XP`0H.,`(`;@`3`'X`,0DN$E```*:#H"XP,PE><#`%/C(0``FG@Z +M`N,#,)7G`@!3XP(``!KT#I_E_O__ZQ<``.H$`%/C`@``&N0.G^7^___K$@`` +MZ@@`4^,"```:U`Z?Y?[__^L-``#J$`!3XP(``!KL#I_E_O__ZP@``.H@`%/C +M`@``&O`.G^7^___K`P``ZD``4^,!```:X`Z?Y?[__^N8#I_EW!Z?Y?[__^L$ +M`*#A*!X`XP`@X.,`,*#C_O__Z_]O#^,/8$#CH#``XP@P0.,`,(WE!`"@X0`0 +MH./O(*#C!C"@X?[__^L#.*#C`#"-Y00`H.$`$*#C,""@XP8PH.'^___K#S"@ +MXP`PC>4$`*#A`!"@XS$@H.,&,*#A_O__ZWLQ`>,/,$#C`#"-Y00`H.$`$*#C +M,B"@XP8PH.'^___K!`"@X2@>`.,`(.#C`#``XX`P2./^___K!`"@X3D=H.,` +M(.#C`#P'XP`Q0./^___K!`"@X40>`.,`(.#C`#@$XP`Q2./^___K!`"@X>,> +MH.,`(.#C'#P(XP`P0>/^___K!`"@X30>`.,`(.#C'#P(XP`P0^/^___K!`"@ +MX3@>`.,`(.#C!#@`XQ8R2./^___K!`"@X3P>`.,`(.#C`#``XQ8X0N/^___K +M8#H"X]-@A>$!`Z#C`!"@XP`@!N`!,`?@`Q"2X24```IH.@+C`S"5YP,`4^,A +M``":>#H"XP,PE><"`%/C`@``&@`-G^7^___K%P``Z@0`4^,"```:\`R?Y?[_ +M_^L2``#J"`!3XP(``!K@#)_E_O__ZPT``.H0`%/C`@``&O@,G^7^___K"``` +MZB``4^,"```:_`R?Y?[__^L#``#J0`!3XP$``!KL#)_E_O__ZZ@,G^7H')_E +M_O__ZP0`H.%,'@#C`"#@XQ$Y"N-&,$#C_O__ZV`Z`N/38(7A`0.@XP`0H.,` +M(`;@`3`'X`,0DN$E```*:#H"XP,PE><#`%/C(0``FG@Z`N,#,)7G`@!3XP(` +M`!HP#)_E_O__ZQ<``.H$`%/C`@``&B`,G^7^___K$@``Z@@`4^,"```:$`R? +MY?[__^L-``#J$`!3XP(``!HH#)_E_O__ZP@``.H@`%/C`@``&BP,G^7^___K +M`P``ZD``4^,!```:'`R?Y?[__^O<"Y_E&!R?Y?[__^L$`*#A2!X`XP`@X./Y +M-*#C_O__ZP0`H.%('@#C`"#@XSXSH./^___K8#H"X]-@A>$!`Z#C`!"@XP`@ +M!N`!,`?@`Q"2X28```IH.@+C`S"5YP,`4^,B``":>#H"XP,PE><"`%/C`@`` +M&E`+G^7^___K%P``Z@0`4^,"```:0`N?Y?[__^L2``#J"`!3XP(``!HP"Y_E +M_O__ZPT``.H0`%/C`@``&D@+G^7^___K"```ZB``4^,"```:3`N?Y?[__^L# +M``#J0`!3XP$``!H\"Y_E_O__ZP`+G^4X&Y_E"B"@X_[__^L*`*#C_O__ZP0` +MH.&L'@#C`"#@X_[__^L`8*#A8#H"X].`A>$!`Z#C`!"@XP`@".`!,`G@`Q"2 +MX28```IH.@+C`S"5YP,`4^,B``":>#H"XP,PE><"`%/C`@``&G@*G^7^___K +M%P``Z@0`4^,"```::`J?Y?[__^L2``#J"`!3XP(``!I8"I_E_O__ZPT``.H0 +M`%/C`@``&G`*G^7^___K"```ZB``4^,"```:=`J?Y?[__^L#``#J0`!3XP$` +M`!ID"I_E_O__ZRP*G^5@&I_E!B"@X?[__^L$`*#AE!X`XP`@X./^___K`("@ +MX6`Z`N/3H(7A`0.@XP`0H.,`(`K@`3`+X`,0DN$F```*:#H"XP,PE><#`%/C +M(@``FG@Z`N,#,)7G`@!3XP(``!JH"9_E_O__ZQ<``.H$`%/C`@``&I@)G^7^ +M___K$@``Z@@`4^,"```:B`F?Y?[__^L-``#J$`!3XP(``!J@"9_E_O__ZP@` +M`.H@`%/C`@``&J0)G^7^___K`P``ZD``4^,!```:E`F?Y?[__^M@"9_ED!F? +MY0@@H.'^___K!`"@X9P>`.,`(.#C_O__ZP!PH.%@.@+CTZ"%X0$#H.,`$*#C +M`"`*X`$P"^`#$)+A)@``"F@Z`N,#,)7G`P!3XR(``)IX.@+C`S"5YP(`4^," +M```:V`B?Y?[__^L7``#J!`!3XP(``!K(")_E_O__ZQ(``.H(`%/C`@``&K@( +MG^7^___K#0``ZA``4^,"```:T`B?Y?[__^L(``#J(`!3XP(``!K4")_E_O__ +MZP,``.I``%/C`0``&L0(G^7^___KE`B?Y<`8G^4'(*#A_O__ZP$"%N-Y`@`: +M`#``X_\S0.,#,`C@0B$`XR,(4N%S`@`*5WCIYT(`5^-P`@`*`C&#XQ\[@^,' +M<(/A!`"@X3D=H.,`(.#C!S"@X?[__^M@.@+CTX"%X0$#H.,`$*#C`"`(X`$P +M">`#$)+A60``"F@Z`N,#,)7G`P!3XU4``)IX.@+C`S"5YP(`4^,"```:T`>? +MY?[__^L7``#J!`!3XP(``!K`!Y_E_O__ZQ(``.H(`%/C`@``&K`'G^7^___K +M#0``ZA``4^,"```:R`>?Y?[__^L(``#J(`!3XP(``!K,!Y_E_O__ZP,``.I` +M`%/C`0``&KP'G^7^___K!`"@X3D=H.,`(.#C_O__ZP`@H.%\!Y_EI!>?Y0

$!`Z#C`!"@XP`@!N`!,`?@`Q"2X24```IH.@+C`S"5 +MYP,`4^,A``":>#H"XP,PE><"`%/C`@``&@`'G^7^___K%P``Z@0`4^,"```: +M\`:?Y?[__^L2``#J"`!3XP(``!K@!I_E_O__ZPT``.H0`%/C`@``&O@&G^7^ +M___K"```ZB``4^,"```:_`:?Y?[__^L#``#J0`!3XP$``!KL!I_E_O__Z\0& +MG^7H%I_E_O__ZP0`H.$H'@#C`"#@XP`PH./^___K_V\/XP]@0..@,`#C"#!` +MXP`PC>4$`*#A`!"@X^\@H.,&,*#A_O__ZP,XH.,`,(WE!`"@X0`0H.,P(*#C +M!C"@X?[__^L/,*#C`#"-Y00`H.$`$*#C,2"@XP8PH.'^___K^C\'XP\P0.,` +M,(WE!`"@X0`0H.,R(*#C!C"@X?[__^L$`*#A*!X`XP`@X.,`,`#C@#!(X_[_ +M_^L$`*#A1!X`XP`@X.,`.`3C`#%`X_[__^L$`*#AXQZ@XP`@X.,`.,` +M(.#C$3D*XT8P0./^___K8#H"X]-@A>$!`Z#C`!"@XP`@!N`!,`?@`Q"2X24` +M``IH.@+C`S"5YP,`4^,A``":>#H"XP,PE><"`%/C`@``&E0$G^7^___K%P`` +MZ@0`4^,"```:1`2?Y?[__^L2``#J"`!3XP(``!HT!)_E_O__ZPT``.H0`%/C +M`@``&DP$G^7^___K"```ZB``4^,"```:4`2?Y?[__^L#``#J0`!3XP$``!I` +M!)_E_O__ZP`$G^4\%)_E_O__ZP0`H.%('@#C`"#@X_DTH./^___K!`"@X4@> +M`.,`(.#C/C.@X_[__^M@.@+CTV"%X0$#H.,`$*#C`"`&X`$P!^`#$)+A)@`` +M"F@Z`N,#,)7G`P!3XR(``)IX.@+C`S"5YP(`4^,"```:=`.?Y?[__^L7``#J +M!`!3XP(``!ID`Y_E_O__ZQ(``.H(`%/C`@``&E0#G^7^___K#0``ZA``4^," +M```:;`.?Y?[__^L(``#J(`!3XP(``!IP`Y_E_O__ZP,``.I``%/C`0``&F`# +MG^7^___K)`.?Y5P3G^4*(*#C_O__ZPH`H./^___K!`"@X:P>`.,`(.#C_O__ +MZP!@H.%@.@+CTX"%X0$#H.,`$*#C`"`(X`$P">`#$)+A)@``"F@Z`N,#,)7G +M`P!3XR(``)IX.@+C`S"5YP(`4^,"```:G`*?Y?[__^L7``#J!`!3XP(``!J, +M`I_E_O__ZQ(``.H(`%/C`@``&GP"G^7^___K#0``ZA``4^,"```:E`*?Y?[_ +M_^L(``#J(`!3XP(``!J8`I_E_O__ZP,``.I``%/C`0``&H@"G^7^___K4`*? +MY802G^4&(*#A_O__ZP0`H.&4'@#C`"#@X_[__^L`<*#A8#H"X].`A>$!`Z#C +M`!"@XP`@".`!,`G@`Q"2X28```IH.@+C`S"5YP,`4^,B``":>#H"XP,PE><" +M`%/C`@``&LP!G^7^___K%P``Z@0`4^,"```:O`&?Y?[__^L2``#J"`!3XP(` +M`!JL`9_E_O__ZPT``.H0`%/C`@``&L0!G^7^___K"```ZB``4^,"```:R`&? +MY?[__^L#``#J0`!3XP$``!JX`9_E_O__ZX0!G^6T$9_E!R"@X?[__^L$`*#A +MG!X`XP`@X./^___K`'"@X6`Z`N/3@(7A`0.@XP`0H.,`(`C@`3`)X`,0DN$F +M```*:#H"XP,PE><#`%/C(@``FG@Z`N,#,)7G`@!3XP(``!K\`)_E_O__ZQ<` +M`.H$`%/C`@``&NP`G^7^___K$@``Z@@`4^,"```:W`"?Y?[__^L-``#J$`!3 +MXP(``!KT`)_E_O__ZP@``.H@`%/C`@``&O@`G^7^___K`P``ZD``4^,!```: +MZ`"?Y?[__^NX`)_EY!"?Y0<@H.'^___K!`"@X:0>`.,`(.#C_O__ZP!`H.%@ +M.@+CTX"%X0$#H.,`$*#C`"`(X`$P">`#$)+A/0``"F@Z`N,#,)7G`P!3XSD` +M`)IX.@+C`S"5YP(`4^,"```:+`"?Y?[__^LN``#J!`!3XP(``!H<`)_E_O__ +MZRD``.H(`%/C&0``&@P`G^7^___K)```ZMP4``#H%```]!0``,P9``#D&0`` +M%!H``/08```T&@``3!D``&@:``!\&@``D!H``+0:```$%0``Y!H``-P4``#H +M%```]!0```05```4%0``(!4``/@:```(4@``$`!3XP(``!HX`!_E_O__ZP@` +M`.H@`%/C`@``&C0`'^7^___K`P``ZD``4^,!```:1``?Y?[__^MD`!_E2!`? +MY00@H.'^___K`@,6XP<``!I42.GG,C$`XP,`5.$#```*5FCIYS8`5N,#`*`3 +M,@``&F`Z`N/38(7A`0.@XP`0H.,`(`;@`3`'X`,0DN$I```*:#H"XP,PE><# +M`%/C)0``FG@Z`N,#,)7G`@!3XP(``!K8`!_E_O__ZQ<``.H$`%/C`@``&N@` +M'^7^___K$@``Z@@`4^,"```:^``?Y?[__^L-``#J$`!3XP(``!H(`1_E_O__ +MZP@``.H@`%/C`@``&A@!'^7^___K`P``ZD``4^,!```:*`$?Y?[__^LL`1_E +M+!$?Y?[__^L!`*#C`@``Z@``H.,```#J`0"@XPS0C>+PC[WH^$\MZ3L\H.,# +M0)#GJ5V$XA!0A>)@.@+CTV"$X0$#H.,`$*#C`"`&X`$P!^`#$)+A4P``"F@Z +M`N,#,)3G`P!3XT\``)IX.@+C`S"4YP(`4^,"```:;`>?Y?[__^L7``#J!`!3 +MXP(``!I?Y?[__^L(``#J(`!3XP(``!HL!Y_E_O__ZP,``.I``%/C`0``&AP'G^7^ +M___K&`>?Y1@7G^7^___K8#H"X]-@A.$!`Z#C`!"@XP`@!N`!,`?@`Q"2X24` +M``IH.@+C`S"4YP,`4^,A``":>#H"XP,PE.<"`%/C`@``&K0&G^7^___K%P`` +MZ@0`4^,"```:I`:?Y?[__^L2``#J"`!3XP(``!J4!I_E_O__ZPT``.H0`%/C +M`@``&H0&G^7^___K"```ZB``4^,"```:=`:?Y?[__^L#``#J0`!3XP$``!ID +M!I_E_O__ZV@&G^5@%I_E_O__ZP4`H.'C'J#C`"#@XQP\".,`,$'C_O__ZP4` +MH.$T'@#C`"#@XQP\".,`,$/C_O__ZP4`H.$X'@#C`"#@XRHS`.,4,DCC_O__ +MZP4`H.$\'@#C`"#@XP`P`.,6.$+C_O__ZV`Z`N/38(3A`0.@XP`0H.,`(`;@ +M`3`'X`,0DN$E```*:#H"XP,PE.<#`%/C(0``FG@Z`N,#,)3G`@!3XP(``!J< +M!9_E_O__ZQ<``.H$`%/C`@``&HP%G^7^___K$@``Z@@`4^,"```:?`6?Y?[_ +M_^L-``#J$`!3XP(``!IL!9_E_O__ZP@``.H@`%/C`@``&EP%G^7^___K`P`` +MZD``4^,!```:3`6?Y?[__^M4!9_E2!6?Y?[__^L%`*#A3!X`XP`@X.,1.0+C +M1C!`X_[__^M@.@+CTV"$X0$#H.,`$*#C`"`&X`$P!^`#$)+A)0``"F@Z`N,# +M,)3G`P!3XR$``)IX.@+C`S"4YP(`4^,"```:S`2?Y?[__^L7``#J!`!3XP(` +M`!J\!)_E_O__ZQ(``.H(`%/C`@``&JP$G^7^___K#0``ZA``4^,"```:G`2? +MY?[__^L(``#J(`!3XP(``!J,!)_E_O__ZP,``.I``%/C`0``&GP$G^7^___K +MB`2?Y7@4G^7^___K!0"@X4@>`.,`(.#C^32@X_[__^L%`*#A2!X`XP`@X.,^ +M,Z#C_O__ZV`Z`N/38(3A`0.@XP`0H.,`(`;@`3`'X`,0DN$F```*:#H"XP,P +ME.<#`%/C(@``FG@Z`N,#,)3G`@!3XP(``!KL`Y_E_O__ZQ<``.H$`%/C`@`` +M&MP#G^7^___K$@``Z@@`4^,"```:S`.?Y?[__^L-``#J$`!3XP(``!J\`Y_E +M_O__ZP@``.H@`%/C`@``&JP#G^7^___K`P``ZD``4^,!```:G`.?Y?[__^NL +M`Y_EF!.?Y0H@H./^___K"@"@X_[__^L%`*#AK!X`XP`@X./^___K`&"@X6`Z +M`N/3@(3A`0.@XP`0H.,`(`C@`3`)X`,0DN$F```*:#H"XP,PE.<#`%/C(@`` +MFG@Z`N,#,)3G`@!3XP(``!H4`Y_E_O__ZQ<``.H$`%/C`@``&@0#G^7^___K +M$@``Z@@`4^,"```:]`*?Y?[__^L-``#J$`!3XP(``!KD`I_E_O__ZP@``.H@ +M`%/C`@``&M0"G^7^___K`P``ZD``4^,!```:Q`*?Y?[__^O8`I_EP!*?Y08@ +MH.'^___K!0"@X90>`.,`(.#C_O__ZP!PH.%@.@+CTX"$X0$#H.,`$*#C`"`( +MX`$P">`#$)+A)@``"F@Z`N,#,)3G`P!3XR(``)IX.@+C`S"4YP(`4^,"```: +M1`*?Y?[__^L7``#J!`!3XP(``!HT`I_E_O__ZQ(``.H(`%/C`@``&B0"G^7^ +M___K#0``ZA``4^,"```:%`*?Y?[__^L(``#J(`!3XP(``!H$`I_E_O__ZP,` +M`.I``%/C`0``&O0!G^7^___K#`*?Y?`1G^4'(*#A_O__ZP4`H.&<'@#C`"#@ +MX_[__^L`@*#A8#H"X].@A.$!`Z#C`!"@XP`@"N`!,`O@`Q"2X28```IH.@+C +M`S"4YP,`4^,B``":>#H"XP,PE.<"`%/C`@``&G0!G^7^___K%P``Z@0`4^," +M```:9`&?Y?[__^L2``#J"`!3XP(``!I4`9_E_O__ZPT``.H0`%/C`@``&D0! +MG^7^___K"```ZB``4^,"```:-`&?Y?[__^L#``#J0`!3XP$``!HD`9_E_O__ +MZT`!G^4@$9_E"""@X?[__^L%`*#AI!X`XP`@X./^___K`%"@X6`Z`N/3H(3A +M`0.@XP`0H.,`(`K@`3`+X`,0DN$F```*:#H"XP,PE.<#`%/C(@``FG@Z`N,# +M,)3G`@!3XP(``!JD`)_E_O__ZQ<``.H$`%/C`@``&I0`G^7^___K$@``Z@@` +M4^,"```:A`"?Y?[__^L-``#J$`!3XP(``!IT`)_E_O__ZP@``.H@`%/C`@`` +M&F0`G^7^___K`P``ZD``4^,!```:5`"?Y?[__^MT`)_E4!"?Y04@H.'^___K +M`0(6XP<``!I7>.GG0C$`XP,`5^$#```*6(CIYT(`6.(!`*`3^(^]Z```H./X +MC[WHW!0``.@4``#T%```!!4``!05```@%0``%!L``!A2```H&P``%!H``/08 +M```T&@``3!D``&@:``!\&@``Y!H``/A/+>D!8*#A`G"@X3L\H.,#,)#GJ5V# +MXA!0A>)@*@+CTJ"#X0&#H.,`D*#C"``*X`D0"^`!()#A)0``"F@J`N,"()/G +M`P!2XR$``)IX*@+C`C"3YP(`4^,"```:I`"?Y?[__^L7``#J!`!3XP(``!J4 +M`)_E_O__ZQ(``.H(`%/C`@``&H0`G^7^___K#0``ZA``4^,"```:=`"?Y?[_ +M_^L(``#J(`!3XP(``!ID`)_E_O__ZP,``.I``%/C`0``&E0`G^7^___K4`"? +MY5`0G^7^___K`$"@XP4`H.$$$);G!"#7Y_[__^L$0(3B#`!4X_C__QH%`*#A +M#!"6Y0P@E^7^___K^(^]Z-P4``#H%```]!0```05```4%0``(!4``$0;```L +M4@``^$\MZ0%@H.$"<*#A.SR@XP,PD.>I78/B$%"%XF`J`N/2H(/A`8.@XP"0 +MH.,(``K@"1`+X`$@D.$E```*:"H"XP(@D^<#`%+C(0``FG@J`N,",)/G`@!3 +MXP(``!JD`)_E_O__ZQ<``.H$`%/C`@``&I0`G^7^___K$@``Z@@`4^,"```: +MA`"?Y?[__^L-``#J$`!3XP(``!IT`)_E_O__ZP@``.H@`%/C`@``&F0`G^7^ +M___K`P``ZD``4^,!```:5`"?Y?[__^M0`)_E4!"?Y?[__^L`0*#C!0"@X000 +MEN?^___K!`"'YP1`A.(,`%3C^/__&@4`H.$,$);E_O__ZPP`A^7XC[WHW!0` +M`.@4``#T%```!!4``!05```@%0``9!L``$12``#P3RWIG-!-X@!PH.$($(WE +M`I"@X0.@H.$[/*#C`U"0YZF-A>(0@(CB`$``XP!`0.-8P(WB8N^$X@\`ON@/ +M`*SH#P"^Z`\`K.@/`+[H#P"LZ`\`GN@/`(SH2,"-XG(_A.(/`)/H#P",Z"3` +MC>)V3X3B#P"TZ`\`K.@/`+3H#P"LZ``PE.4`,(SE``!9XT4``!I@.@+CTP"% +MX?``S>$!`Z#C`!"@X]`@S>$`(`+@`3`#X`,0DN$L```*:#H"XP,PE><#`%/C +M*```FG@Z`N,#,)7G`@!3XP(``!H$#I_E_O__ZQ<``.H$`%/C`@``&O0-G^7^ +M___K$@``Z@@`4^,"```:Y`V?Y?[__^L-``#J$`!3XP(``!K4#9_E_O__ZP@` +M`.H@`%/C`@``&L0-G^7^___K`P``ZD``4^,!```:M`V?Y?[__^L``%KC`"`` +MXP`@0.,`,`#C`#!`XP,@H`&8#9_EF!V?Y0DPH.'^___K!P"@X5@0C>+>+87B +M$#"@X_[__^O?387B!P"@X4@0C>($(*#A_O__ZP<`H.$D$(WB-""$X@DPH./^ +M___K8#H"X],`A>'P`,WA`0.@XP`0H./0(,WA`"`"X`$P`^`#$)+A+```"F@Z +M`N,#,)7G`P!3XR@``)IX.@+C`S"5YP(`4^,"```:[`R?Y?[__^L7``#J!`!3 +MXP(``!K<#)_E_O__ZQ(``.H(`%/C`@``&LP,G^7^___K#0``ZA``4^,"```: +MO`R?Y?[__^L(``#J(`!3XP(``!JL#)_E_O__ZP,``.I``%/C`0``&IP,G^7^ +M___K``!:XP`@`.,`($#C`#``XP`P0.,#(*`!@`R?Y8`?),`/C`S#5YP``4^,"```:!P"@X0$0H./^___K"`"@X0(;H.,!)*#C +M`#"@X_[__^L(`*#A!!P`XP`@X.,`-@7CH#-`X_[__^L(`*#A"!P`XP`@X./D +M,`#C"#!`X_[__^L(`*#A=!@`XP`@X.,`,`3C(#)"X_[__^L(`*#AAQZ@XP$K +MH.,!,*#C_O__ZP@`H.&''J#C`2.@XP$PH./^___K"`"@X88>H.,!*Z#C`#"@ +MX_[__^L(`*#A9!@`XP$KH.,`,*#C_O__ZP``6N,9```*"`"@X2$=H.,`(.#C +M`3B@X_[__^L(`*#A1!@`XP`@X.,!.*#C_O__Z]^]A>('`*#A2!"-X@L@H.'^ +M___K"`"@X6@;`.,`(.#C]C:@X_[__^L(`*#A;!L`XP`@X./V-J#C_O__ZPD` +M`.K?O87B!P"@X4@0C>(+(*#A_O__ZP@`H.%H&P#C`"#@X_8VH./^___K8#H" +MX],`A>'P`,WA`0.@XP`0H./0(,WA`"`"X`$P`^`#$)+A)0``"F@Z`N,#,)7G +M`P!3XR$``)IX.@+C`S"5YP(`4^,"```:?`J?Y?[__^L7``#J!`!3XP(``!IL +M"I_E_O__ZQ(``.H(`%/C`@``&EP*G^7^___K#0``ZA``4^,"```:3`J?Y?[_ +M_^L(``#J(`!3XP(``!H\"I_E_O__ZP,``.I``%/C`0``&BP*G^7^___K,`J? +MY2@:G^7^___K"`"@X2@>`.,`(.#C`#``XX`P2./^___K"`"@X3D=H.,`(.#C +M`#P'XP`Q0./^___K"`"@X40>`.,`(.#C`#@$XP`Q2./^___K!P"@X0H0H.'^ +M___K`0!0XP0```H'`*#A"A"@X?[__^L!`%#C/0``&F`Z`N/3`(7A\`#-X0$# +MH.,`$*#CT"#-X0`@`N`!,`/@`Q"2X24```IH.@+C`S"5YP,`4^,A``":>#H" +MXP,PE><"`%/C`@``&DP)G^7^___K%P``Z@0`4^,"```:/`F?Y?[__^L2``#J +M"`!3XP(``!HL"9_E_O__ZPT``.H0`%/C`@``&AP)G^7^___K"```ZB``4^," +M```:#`F?Y?[__^L#``#J0`!3XP$``!K\")_E_O__ZP0)G^7X&)_E_O__ZP@P +MG>6)0H/@"`"@X90>`.,`(.#C_O__ZU`(Z><``(3E"`"@X9P>`.,`(.#C_O__ +MZU`(Z><$`(3E`$"@XP`P`.,`,$#C%#"-Y0`P`.,`,$#C&#"-Y0`P`.,`,$#C +M'#"-Y0<`H.$*$*#A_O__ZP!@H.$#`%#C/@``&F`Z`N/3`(7A\`#-X0$#H.,` +M$*#CT"#-X0`@`N`!,`/@`Q"2X24```IH.@+C`S"5YP,`4^,A``":>#H"XP,P +ME><"`%/C`@``&A0(G^7^___K%P``Z@0`4^,"```:!`B?Y?[__^L2``#J"`!3 +MXP(``!KT!Y_E_O__ZPT``.H0`%/C`@``&N0'G^7^___K"```ZB``4^,"```: +MU`>?Y?[__^L#``#J0`!3XP$``!K$!Y_E_O__Z]`'G^7`%Y_E_O__ZP@PG>6) +M0H/@"`"@X:0>`.,`(.#C_O__ZU`(Z><(`(3E"`"@X:P>`.,`(.#C_O__ZU`( +MZ><,`(3E9```ZF`Z`N/3`(7A\`#-X0$#H.,`$*#CT"#-X0`@`N`!,`/@`Q"2 +MX24```IH.@+C`S"5YP,`4^,A``":>#H"XP,PE><"`%/C`@``&A@'G^7^___K +M%P``Z@0`4^,"```:"`>?Y?[__^L2``#J"`!3XP(``!KX!I_E_O__ZPT``.H0 +M`%/C`@``&N@&G^7^___K"```ZB``4^,"```:'`"=Y?[__^L#``#J0`!3XP$` +M`!H8`)WE_O__ZQ0`G>7$%I_E_O__ZP%`A.("`%3CA___&@``5N,O```:8#H" +MX],`A>'P`,WA`0.@XP`0H./0(,WA`"`"X`$P`^`#$)+A)0``"F@Z`N,#,)7G +M`P!3XR$``)IX.@+C`S"5YP(`4^,"```:1`:?Y?[__^L7``#J!`!3XP(``!HT +M!I_E_O__ZQ(``.H(`%/C`@``&B0&G^7^___K#0``ZA``4^,"```:%`:?Y?[_ +M_^L(``#J(`!3XP(``!H$!I_E_O__ZP,``.I``%/C`0``&O0%G^7^___K!`:? +MY?`5G^7^___K``!:X]L```H'`*#A_O__ZP<`H.%8$(WB`""@XPHPH.'^___K +M"#"=Y8DR@^``,(WE`$"@XP`P`.,`,$#C%#"-Y0`P`.,`,$#C&#"-Y0`P`.,` +M,$#C'#"-Y0<`H.'^___K`&"@X0,`4.-,```:8#H"X],`A>'X`,WA`0.@XP`0 +MH./8(,WA`"`"X`$P`^`#$)+A)0``"F@Z`N,#,)7G`P!3XR$``)IX.@+C`S"5 +MYP(`4^,"```:&`6?Y?[__^L7``#J!`!3XP(``!H(!9_E_O__ZQ(``.H(`%/C +M`@``&O@$G^7^___K#0``ZA``4^,"```:Z`2?Y?[__^L(``#J(`!3XP(``!K8 +M!)_E_O__ZP,``.I``%/C`0``&L@$G^7^___KW`2?Y<04G^7^___K"`"@X;0> +M`.,`(.#C_O__ZU`(Z><`,)WE$`"#Y0@`H.&\'@#C`"#@X_[__^M0".GG`!"= +MY10`@>4(`*#AQ!X`XP`@X./^___K4`CIYP`PG>48`(/E"`"@X

`.,`(.#C +M_O__ZU`(Z><`$)WE'`"!Y74``.H!`%3C`0!0`ST``!I@.@+CTP"%X?@`S>$! +M`Z#C`!"@X]@@S>$`(`+@`3`#X`,0DN$E```*:#H"XP,PE><#`%/C(0``FG@Z +M`N,#,)7G`@!3XP(``!K8`Y_E_O__ZQ<``.H$`%/C`@``&L@#G^7^___K$@`` +MZ@@`4^,"```:N`.?Y?[__^L-``#J$`!3XP(``!JH`Y_E_O__ZP@``.H@`%/C +M`@``&AP`G>7^___K`P``ZD``4^,!```:&`"=Y?[__^L4`)WEA!.?Y?[__^L( +M`*#AM!X`XP`@X./^___K4`CIYP`PG>40`(/E"`"@X;P>`.,`(.#C_O__ZU`( +MZ><`$)WE%`"!Y0%`A.("`%3C:?__&@``5N,O```:8#H"X],`A>'P`,WA`0.@ +MXP`0H./0(,WA`"`"X`$P`^`#$)+A50``"F@Z`N,#,)7G`P!3XRL``)IX.@+C +M`S"5YP(`4^,"```:S`*?Y?[__^L7``#J!`!3XP(``!J\`I_E_O__ZQ(``.H( +M`%/C`@``&JP"G^7^___K#0``ZA``4^,"```:G`*?Y?[__^L(``#J(`!3XP(` +M`!J,`I_E_O__ZP,``.I``%/C`0``&GP"G^7^___KE`*?Y7@2G^7^___K8#H" +MX],`A>'P`,WA`0.@XP`0H./0(,WA`"`"X`$P`^`#$)+A)0``"F@Z`N,#,)7G +M`P!3XR$``)IX.@+C`S"5YP(`4^,"```:#`*?Y?[__^L7``#J!`!3XP(``!K\ +M`9_E_O__ZQ(``.H(`%/C`@``&NP!G^7^___K#0``ZA``4^,"```:W`&?Y?[_ +M_^L(``#J(`!3XP(``!K,`9_E_O__ZP,``.I``%/C`0``&KP!G^7^___KV`&? +MY;@1G^7^___K"`"@X2@>`.,`(.#C`#"@X_[__^L``%GC+P``"LDP`^,#,-7G +M``!3XP(``!H'`*#A`!"@X_[__^L'`*#A6!"-XMXMA>(0,*#C_O__ZP<`H.%( +M$(WB"R"@X?[__^L'`*#A)!"-XM\MA>(T((+B"3"@X_[__^L(`*#A(1V@XP`@ +MX./3/@+C`S!`X_[__^L``%KC!0``"@@`H.%$&`#C`"#@X],^`N,#,$#C_O__ +MZP!,".,`04#C"`"@X>,>H.,`(.#C!#"@X?[__^L(`*#A-!X`XP`@X.,$,*#A +M_O__ZV`Z`N/38(7A`0.@XP`0H.,`(`;@`3`'X`,`DN$E```*:#H"XP,PE><# +M`%/C(0``FG@Z`N,#,)7G`@!3XP(``!IX`)_E_O__ZQ<``.H$`%/C`@``&F@` +MG^7^___K$@``Z@@`4^,"```:6`"?Y?[__^L-``#J$`!3XP(``!I(`)_E_O__ +MZP@``.H@`%/C`@``&C@`G^7^___K`P``ZD``4^,!```:*`"?Y?[__^M(`)_E +M)!"?Y?[__^N<#`%/C(0``FG@Z`N,#,)7G`@!3XP(``!JL +M"Y_E_O__ZQ<``.H$`%/C`@``&IP+G^7^___K$@``Z@@`4^,"```:C`N?Y?[_ +M_^L-``#J$`!3XP(``!I\"Y_E_O__ZP@``.H@`%/C`@``&FP+G^7^___K`P`` +MZD``4^,!```:7`N?Y?[__^M8"Y_E6!N?Y?[__^L&`*#A3!"-XM\MA>(0((+B +M"3"@X_[__^O$`@#J8#H"X].`A>$!`Z#C`!"@XP`@".`!,`G@`P"2X24```IH +M.@+C`S"5YP,`4^,A``":>#H"XP,PE><"`%/C`@``&M@*G^7^___K%P``Z@0` +M4^,"```:R`J?Y?[__^L2``#J"`!3XP(``!JX"I_E_O__ZPT``.H0`%/C`@`` +M&J@*G^7^___K"```ZB``4^,"```:F`J?Y?[__^L#``#J0`!3XP$``!J("I_E +M_O__ZXP*G^6$&I_E_O__ZW!PC>(@D(?B!S"@X0`@H.,`((/E(""#Y4`@@^5@ +M((/E!#"#X@D`4^'X__\:`$"@XW"`C>(!L*#C!*"@X0`PE>4!,$/B`0!3XP@` +M`(H0,)7E`@!3XP4``!H&`*#A"!"@X00@H.$+,*#A_O__ZP0``.H&`*#A"!"@ +MX00@H.$*,*#A_O__ZP$`5.,X```:!@"@X0@0H.$*(*#A"S"@X?[__^L``%#C +M`D"@`^/__PI@.@+CTX"%X0$#H.,`$*#C`"`(X`$P">`#$)+AJ@``"F@Z`N,# +M,)7G`P!3XZ8``)IX.@+C`S"5YP(`4^,"```:=`F?Y?[__^L7``#J!`!3XP(` +M`!ID"9_E_O__ZQ(``.H(`%/C`@``&E0)G^7^___K#0``ZA``4^,"```:1`F? +MY?[__^L(``#J(`!3XP(``!HT"9_E_O__ZP,``.I``%/C`0``&B0)G^7^___K +M+`F?Y2`9G^4`(*#C_O__ZP!`H.."``#J`@!4XWD``!H&`*#A$!`Z#C`!"@XP`@".`!,`G@`P"2X7`` +M``IH.@+C`S"5YP,`4^-L``":>#H"XP,PE><"`%/C`@``&HP(G^7^___K%P`` +MZ@0`4^,"```:?`B?Y?[__^L2``#J"`!3XP(``!IL")_E_O__ZPT``.H0`%/C +M`@``&EP(G^7^___K"```ZB``4^,"```:3`B?Y?[__^L#``#J0`!3XP$``!H\ +M")_E_O__ZT@(G^4X&)_E`""@X_[__^L`0*#C2```Z@8`H.%P$(WB`2"@XP(P +MH./^___K``!0XW`PC0(`0*`#+P``"F`Z`N/3@(7A`0.@XP`0H.,`(`C@`3`) +MX`,0DN'M`0`*:#H"XP,PE><#`%/CZ0$`FG@Z`N,#,)7G`@!3XP(``!JD!Y_E +M_O__ZQ<``.H$`%/C`@``&I0'G^7^___K$@``Z@@`4^,"```:A`>?Y?[__^L- +M``#J$`!3XP(``!IT!Y_E_O__ZP@``.H@`%/C`@``&F0'G^7^___K`P``ZD`` +M4^,!```:5`>?Y?[__^MD!Y_E4!>?Y0$@H./^___KQ0$`ZF`@D^4"0(3@!#"# +MX@,`6>'Z__\:``!4X_]`H`,#0*`3!@``Z@%`A.)T0._F`@!4XS+__YK_0*#C +M````Z@!`H.-P((WB@+""X@`P`.,`,$#C/#"-Y0`P`.,`,$#C0#"-Y0`P`.,` +M,$#C1#"-Y31`C>4X8(WE`("7Y00PE^4P,(WE")"7Y0Q`E^40H)?E%&"7Y1@` +ME^4H`(WE'!"7Y2P0C>5@.@+CTP"%X?`"S>$!`Z#C`!"@X]`BS>$`(`+@`3`# +MX`,0DN$N```*:#H"XP,PE><#`%/C*@``FG@Z`N,#,)7G`@!3XP(``!H\!I_E +M_O__ZQ<``.H$`%/C`@``&BP&G^7^___K$@``Z@@`4^,"```:'`:?Y?[__^L- +M``#J$`!3XP(``!H,!I_E_O__ZP@``.H@`%/C`@``&D0`G>7^___K`P``ZD`` +M4^,!```:0`"=Y?[__^L`D(WE$`2-Z0Q@C>4H()WE$""-Y2PPG>44,(WE/`"= +MY<$`/C`8"%YP00@^("L)'GH!`#XP&PA><( +M$(/B`I"1YW00$^4L$(WE$!"#X@*@D>>D(`/C`J"%YVQP$^6H(`/C`G"%YV@@ +M$^4H((WE9#`3Y2`PC>5@.@+CTP"%X0`@H.$!,*#A`0.@XP`0H.,`(`+@`3`# +MX`,0DN&?```*:#H"XP,PE><#`%/CFP``FG@Z`N,#,)7G`@!3XP(``!K4!)_E +M_O__ZQ<``.H$`%/C`@``&L0$G^7^___K$@``Z@@`4^,"```:M`2?Y?[__^L- +M``#J$`!3XP(``!JD!)_E_O__ZP@``.H@`%/C`@``&I0$G^7^___K`P``ZD`` +M4^,!```:A`2?Y?[__^N8!)_E@!2?Y3`@G>7^___K8#H"X],`A>$`(*#A`3"@ +MX0$#H.,`$*#C`"`"X`$P`^`#$)+A;@``"F@Z`N,#,)7G`P!3XVH``)IX.@+C +M`S"5YP(`4^,"```:$`2?Y?[__^L7``#J!`!3XP(``!H`!)_E_O__ZQ(``.H( +M`%/C`@``&O`#G^7^___K#0``ZA``4^,"```:X`.?Y?[__^L(``#J(`!3XP(` +M`!K0`Y_E_O__ZP,``.I``%/C`0``&L`#G^7^___K`)"-Y2P@G>4$!(WI#'"- +MY2@PG>40,(WE(`"=Y10`C>6X`Y_EG!.?Y0@@H.$+,*#A_O__ZP%PH.,'$*#A +M/0``ZF`Z`N/3`(7A\`+-X0$#H.,`$*#CT"+-X0`@`N`!,`/@`Q"2X24```IH +M.@+C`S"5YP,`4^,A``":>#H"XP,PE><"`%/C`@``&AP#G^7^___K%P``Z@0` +M4^,"```:#`.?Y?[__^L2``#J"`!3XP(``!K\`I_E_O__ZPT``.H0`%/C`@`` +M&NP"G^7^___K"```ZB``4^,"```:W`*?Y?[__^L#``#J0`!3XP$``!K,`I_E +M_O__Z^@"G^7($I_E_O__ZP$\H..D(`/C`C"%YYP@`^,",(7G`'"@XZ@P`^,# +M<(7GH#`#XP-PA><'$*#A`0``Z@%PH.,'$*#A``!8XP8```H!D'GB`)"@,P"0 +MC>4&`*#A<""-X@0PH.'^___K`#"5Y0$P0^(!`%/C#0``BA`PE>4"`%/C"@`` +M&@``6N,(```**""=Y0$P<#`%/C(@``FG@Z`N,#,)7G`@!3XP(``!I<`9_E_O__ZQ<``.H$`%/C +M`@``&DP!G^7^___K$@``Z@@`4^,"```:/`&?Y?[__^L-``#J$`!3XP(``!HL +M`9_E_O__ZP@``.H@`%/C`@``&AP!G^7^___K`P``ZD``4^,!```:#`&?Y?[_ +M_^LL`9_E"!&?Y0<@H.'^___K!@"@X4P0C>+?+87B$"""X@DPH./^___K8#H" +MX]-@A>$!`Z#C`!"@XP`@!N`!,`?@`Q"2X2@```IH.@+C`S"5YP,`4^,D``": +M>#H"XP,PE><"`%/C`@``&H@`G^7^___K%P``Z@0`4^,"```:>`"?Y?[__^L2 +M``#J"`!3XP(``!IH`)_E_O__ZPT``.H0`%/C`@``&E@`G^7^___K"```ZB`` +M4^,"```:2`"?Y?[__^L#``#J0`!3XP$``!HX`)_E_O__ZUP`G^4T$)_E_O__ +MZP$``.H!0*#C1_[_ZO30C>+PC[WHZ%(``-P4``#H%```]!0```05```4%0`` +M(!4``.P<```,4P``)!T``#@=``!H'0``F!T``"@>``#('0``3!X``'`>``"4 +M'@``T$`MZ0!`H.'C/=#E`0!3XP(```KG/=#E`0!3X]"`O1C08<3A`02@XP`0 +MH.,`(`;@`3`'X`,0DN$E```*&#"4Y0,`4^,B``":*#"4Y0(`4^,"```:F`"? +MY?[__^L7``#J!`!3XP(``!J(`)_E_O__ZQ(``.H(`%/C`@``&G@`G^7^___K +M#0``ZA``4^,"```::`"?Y?[__^L(``#J(`!3XP(``!I8`)_E_O__ZP,``.I` +M`%/C`0``&D@`G^7^___K9#"4Y4``G^5`$)_E`"#3Y?[__^MD,)3E``"4Y0`0 +MT^7^___K`#"@X^,]Q.7G/<3ET("]Z-P4``#H%```]!0```05```4%0``(!4` +M`*@>```D4P``\$\MZ8303>(`D*#A.SR@XP-`D.<`X`#C`.!`XU3`C>*:7X[B +M#P"UZ`\`K.@/`)7H!P"LZ+`PS.$TP(WBHN^.X@\`ON@/`*SH#P">Z`<`K.BP +M,,SAJ8V$XA"`B.((`*#A_O__Z\PP`^,#()3G`2""X@,@A.$!`Z#C`!"@X]`BS>$`(`+@`3`#X`,0DN$M```*:#H"XP,PE.<#`%/C*0`` +MFG@Z`N,#,)3G`@!3XP(``!ID#9_E_O__ZQ<``.H$`%/C`@``&E0-G^7^___K +M$@``Z@@`4^,"```:1`V?Y?[__^L-``#J$`!3XP(``!HT#9_E_O__ZP@``.H@ +M`%/C`@``&EP-G^7^___K`P``ZD``4^,!```:9`V?Y?[__^MV8*_F`&"-Y0@- +MG^58'9_E,BV@XP4PH.'^___K`@``Z@$P@^(K`%/CO___&I@P`^,#,)3G?#"- +MY=Q\G^7<;)_E`%"@XP"P`.,`L$#C`#``XP`P0.,H,(WE`#``XP`P0.,L,(WE +MT#`#XP,PU.<``%/C00``"@@`H.%\$(WB!R"@X00PH./^___K``!0X[```!IU +M8._F-C@#XP-0Q.=@.@+CTP"$X?`"S>$!`Z#C`!"@X]`BS>$`(`+@`3`#X`,0 +MDN&I```*:#H"XP,PE.<#`%/CI0``FG@Z`N,#,)3G`@!3XP(``!H4#)_E_O__ +MZQ<``.H$`%/C`@``&@0,G^7^___K$@``Z@@`4^,"```:]`N?Y?[__^L-``#J +M$`!3XP(``!KD"Y_E_O__ZP@``.H@`%/C`@``&@P,G^7^___K`P``ZD``4^,! +M```:%`R?Y?[__^MV,*_F`#"-Y=`P`^,#,-3G!#"-Y;@+G^7\&Y_E)"H`XWPP +MG>7^___K>P``ZF`Z`N/3`(3A\`+-X0$#H.,`$*#CT"+-X0`@`N`!,`/@`Q"2 +MX2D```IH.@+C`S"4YP,`4^,E``":>#H"XP,PE.<"`%/C`@``&C0+G^7^___K +M%P``Z@0`4^,"```:)`N?Y?[__^L2``#J"`!3XP(``!H4"Y_E_O__ZPT``.H0 +M`%/C`@``&@0+G^7^___K"```ZB``4^,"```:+`"=Y?[__^L#``#J0`!3XP$` +M`!HH`)WE_O__ZP`PUN4`,(WE"P"@X2@;G^5\()WE!3"@X?[__^L(`*#A?!"- +MX@8@H.$$,*#C_O__ZP``4.,Z```:=6#OYC8X`^,#4,3G8#H"X],`A.'P`LWA +M`0.@XP`0H./0(LWA`"`"X`$P`^`#$)+A,P``"F@Z`N,#,)3G`P!3XR\``)IX +M.@+C`S"4YP(`4^,"```:/`J?Y?[__^L7``#J!`!3XP(``!HL"I_E_O__ZQ(` +M`.H(`%/C`@``&AP*G^7^___K#0``ZA``4^,"```:#`J?Y?[__^L(``#J(`!3 +MXP(``!HT"I_E_O__ZP,``.I``%/C`0``&CP*G^7^___K=C"OY@`PC>70,`/C +M`S#4YP0PC>7D"9_E)!J?Y20J`.-\,)WE_O__ZP4``.H!4(7B"'"'X@A@AN(A +M`%7C/O__&@!@H..U,`/C`S#4YP``4^,+```:42#4Y;4P`^,#(,3GMC`#XP.@ +MQ.>W,`/C`Z#$YW0@W>72,`/C`R#$Y]$P`^,#8,3GR#`#XP,PU.<``%/C+0`` +M"F`Z`N/38(3A`0.@XP`0H.,`(`;@`3`'X`,`DN$E```*:#H"XP,PE.<#`%/C +M(0``FG@Z`N,#,)3G`@!3XP(``!K\")_E_O__ZQ<``.H$`%/C`@``&NP(G^7^ +M___K$@``Z@@`4^,"```:W`B?Y?[__^L-``#J$`!3XP(``!K,")_E_O__ZP@` +M`.H@`%/C`@``&O0(G^7^___K`P``ZD``4^,!```:_`B?Y?[__^N\")_E^!B? +MY?[__^O!,`/C`R#4YP(@A.#"+8+B."""X@&@PN4#(-3G`2""XG(@[^8#(,3G +M!`!2XP`@H`,#(,0'`#"@XP,`H.$#$*#A`R"$X,(M@N(Y((+B`"#2Y0``4N," +M`(`0`1"!$G$0[Q8!,(/B!`!3X_3__QH``%'C,```"O[__^MPH._F8#H"X]-@ +MA.$!`Z#C`!"@XP`@!N`!,`?@`Q"2X28```IH.@+C`S"4YP,`4^,B``":>#H" +MXP,PE.<"`%/C`@``&L@'G^7^___K%P``Z@0`4^,"```:N`>?Y?[__^L2``#J +M"`!3XP(``!JH!Y_E_O__ZPT``.H0`%/C`@``&I@'G^7^___K"```ZB``4^," +M```:P`>?Y?[__^L#``#J0`!3XP$``!K(!Y_E_O__ZXP'G^7$%Y_E"B"@X?[_ +M_^O(,`/C`S#4YP``4^,*```*43#4Y0,`6N$*,&.``S!JD'-P[^8`,*#CR"`# +MXP(PQ.?4(`/C`C#$YPD``.K4,`/C`S#4YP``4^.U,`,3`S#4%U$PU`4#`%KA +M"C!C@`,P:I!S<._FMC`#XP-0U.<%`%KA"E!E@`50:I!U4._FMS`#XP-@U.<& +M`%KA"F!F@`9@:I!V8._F8#H"X],`A.$`(*#A`3"@X0$#H.,`$*#C`"`"X`$P +M`^`#$)+A9@``"F@Z`N,#,)3G`P!3XV(``)IX.@+C`S"4YP(`4^,"```:<`:? +MY?[__^L7``#J!`!3XP(``!I@!I_E_O__ZQ(``.H(`%/C`@``&E`&G^7^___K +M#0``ZA``4^,"```:0`:?Y?[__^L(``#J(`!3XP(``!IH!I_E_O__ZP,``.I` +M`%/C`0``&G`&G^7^___KM3`#XP,PU.=1(-3EA`"-Z`A0C>4,8(WE(`:?Y506 +MG^4*(*#A_O__ZV`Z`N/3`(3A`""@X0$PH.$!`Z#C`!"@XP`@`N`!,`/@`Q"2 +MX2\```IH.@+C`S"4YP,`4^,K``":>#H"XP,PE.<"`%/C`@``&I0%G^7^___K +M%P``Z@0`4^,"```:A`6?Y?[__^L2``#J"`!3XP(``!IT!9_E_O__ZPT``.H0 +M`%/C`@``&F0%G^7^___K"```ZB``4^,"```:C`6?Y?[__^L#``#J0`!3XP$` +M`!J4!9_E_O__Z[8P`^,#(-3G`3"#X@,PU.=9%P/C`1#4YP`0C>58%P/C`1#4 +MYP00C>4X!9_E:!6?Y?[__^L'`%7C`P``FK8P`^,#H,3G"0"@X?[__^L``%?C +M=@$`"J\P`^,#,-3G``!3XW(!``I1,-3E`P!:X0H`8X`#`&J0<`#OY@,`6N$` +MP*"3`<"@@P,`6N$/,*"#`#"@DX`@C>(#,(+@3#!3Y0``4^$`,*"##P``BC0@ +MC>(,(H+@`B!LX`$PH.,!$-+E``!1X0,``)H``%/C`3!#$G,P[Q8$``#J`3"# +MXG,P[^8!((+B#P!3X_/__QJ``(WB#"*`X`+`;.`.`%/C`S",D`XPC((L,%/E +MTB`#XP)0U.<%4(/@=5#OYGA0S>71(`/C`B#4YP(P@^!S<._F8#H"X],`A.$` +M(*#A`3"@X0$#H.,`$*#C`"`"X`$P`^`#$)+A*0``"F@Z`N,#,)3G`P!3XR4` +M`)IX.@+C`S"4YP(`4^,"```:N`.?Y?[__^L7``#J!`!3XP(``!JH`Y_E_O__ +MZQ(``.H(`%/C`@``&I@#G^7^___K#0``ZA``4^,"```:B`.?Y?[__^L(``#J +M(`!3XP(``!JP`Y_E_O__ZP,``.I``%/C`0``&K@#G^7^___KB`.?Y;03G^72 +M,`/C`R#4YP$P0^(#,-3G_O__ZW4PK^8J`%/C*C"@PW@PS<4#``#*=5"OY@4` +M5>,&,*#3>##-U7=0K^;%7\7A(`!5XR!0H*-U4._F8#H"X],`A.'P`LWA`0.@ +MXP`0H./0(LWA`"`"X`$P`^`#$)+A)P``"F@Z`N,#,)3G`P!3XR,``)IX.@+C +M`S"4YP(`4^,"```:L`*?Y?[__^L7``#J!`!3XP(``!J@`I_E_O__ZQ(``.H( +M`%/C`@``&I`"G^7^___K#0``ZA``4^,"```:@`*?Y?[__^L(``#J(`!3XP(` +M`!JH`I_E_O__ZP,``.I``%/C`0``&K`"G^7^___KA`*?Y:P2G^78)]WA=3"O +MYO[__^NO,`/C`S#4YP``4^/)```*`2"@X]0P`^,#(,3G>##=Y0`@`.,`($#C +M`R&2YR(KH.$@((WEY"`#XP)PE.?H(`/C`K"4YS`H`^,",,3G-"@#XP)0Q.^`1(%"=Y94'`^!3-.GG*#"-Y0(,&^,+N^`1*[O@$94+!>!55.GG +M8#H"X],`A.$`(*#A`3"@X0$#H.,`$*#C`"`"X`$P`^`#$)+AC```"F@Z`N,# +M,)3G`P!3XX@``)IX.@+C`S"4YP(`4^,"```:#`&?Y?[__^L7``#J!`!3XP(` +M`!K\`)_E_O__ZQ(``.H(`%/C`@``&NP`G^7^___K#0``ZA``4^,"```:W`"? +MY?[__^L(``#J(`!3XP(``!H$`9_E_O__ZP,``.I``%/C`0``&@P!G^7^___K +M*""=Y20`C>@@,)WE"#"-Y0QPC>40L(WES`"?Y?`0G^4'(*#A"S"@X?[__^M@ +M.@+CTP"$X?`"S>$!`Z#C`!"@X]`BS>$`(`+@`3`#X`,0DN%4```*:#H"XP,P +ME.<#`%/C4```FG@Z`N,#,)3G`@!3XP(``!HL`)_E_O__ZS,``.H$`%/C`@`` +M&AP`G^7^___K+@``Z@@`4^,>```:#`"?Y?[__^LI``#JW!0``.@4``#T%``` +M!!4``-`>```<'P``6H +M`!_EC!`?Y04@H.$',*#A_O__ZP<`5N,&``":"`"@X?[__^NW,`/C`Z#$YPD` +MH.$`$*#C_O__ZZ\P`^,#,-3G``!3X[4P`Q,#H,078#H"X]-@A.$!`Z#C`!"@ +MXP`@!N`!,`?@`P"2X24```IH.@+C`S"4YP,`4^,A``":>#H"XP,PE.<"`%/C +M`@``&C`!'^7^___K%P``Z@0`4^,"```:0`$?Y?[__^L2``#J"`!3XP(``!I0 +M`1_E_O__ZPT``.H0`%/C`@``&F`!'^7^___K"```ZB``4^,"```:<`$?Y?[_ +M_^L#``#J0`!3XP$``!J``1_E_O__ZX0!'^6$$1_E_O__ZP`@H..L,`/C`R#$ +MYX30C>+PC[WH\$$MZ0!0H.$!0*#A`G"@X0-@H.'^`%'C`@``&C(`H./^___K +M&P``ZOT`4>,"```:!0"@X_[__^L6``#J_`!1XP(``!H!`*#C_O__ZQ$``.K[ +M`%'C`@``&C(`H./^___K#```ZOH`4>,"```:!0"@X_[__^L'``#J^0!1XP(` +M`!H!`*#C_O__ZP(``.HD.@#C`P!1X4AF@`4%`*#A!!"@X0<@H.$&,*#A_O__ +MZP$`H./^___K$#"5Y0``4^/P@;VH&#"5Y00`4^/P@;V8*#"5Y0(`4^,"```: +M?`"?Y?[__^L7``#J!`!3XP(``!IL`)_E_O__ZQ(``.H(`%/C`@``&EP`G^7^ +M___K#0``ZA``4^,"```:3`"?Y?[__^L(``#J(`!3XP(``!H\`)_E_O__ZP,` +M`.I``%/C`0``&BP`G^7^___K*`"?Y2@0G^4$(*#A!C"@X?[__^OP@;WH`",` +M``PC```8(P``*",``#@C``!$(P``4",``*Q3``#P0"WI#-!-X@!0H.$!0*#A +M`G"@X0-@H.'^`%'C`@``&C(`H./^___K%P``ZOT`4>,"```:!0"@X_[__^L2 +M``#J_`!1XP(``!H!`*#C_O__ZPT``.K[`%'C`@``&C(`H./^___K"```ZOH` +M4>,"```:!0"@X_[__^L#``#J^0!1XP$``!H!`*#C_O__ZQ`PE>4``%/C)@`` +MJA@PE>4$`%/C(P``FB@PE>4"`%/C`@``&H0`G^7^___K%P``Z@0`4^,"```: +M=`"?Y?[__^L2``#J"`!3XP(``!ID`)_E_O__ZPT``.H0`%/C`@``&E0`G^7^ +M___K"```ZB``4^,"```:1`"?Y?[__^L#``#J0`!3XP$``!HT`)_E_O__ZP!@ +MC>4L`)_E+!"?Y00@H.$',*#A_O__ZPS0C>+P@+WH`",```PC```8(P``*",` +M`#@C``!$(P``C",``,13``!P0"WI`$"@X0%0H.$#8*#A_O__ZP$`H./^___K +M$#"4Y0``4^-P@+VH&#"4Y00`4^-P@+V8*#"4Y0(`4^,"```:?`"?Y?[__^L7 +M``#J!`!3XP(``!IL`)_E_O__ZQ(``.H(`%/C`@``&EP`G^7^___K#0``ZA`` +M4^,"```:3`"?Y?[__^L(``#J(`!3XP(``!H\`)_E_O__ZP,``.I``%/C`0`` +M&BP`G^7^___K*`"?Y2@0G^4%(*#A!C"@X?[__^MP@+WH`",```PC```8(P`` +M*",``#@C``!$(P``T",``.13``!P0"WI`$"@X0%0H.$"8*#A_O__ZQ`PE.4` +M`%/C<("]J!@PE.4$`%/C<("]F"@PE.4"`%/C`@``&GP`G^7^___K%P``Z@0` +M4^,"```:;`"?Y?[__^L2``#J"`!3XP(``!I<`)_E_O__ZPT``.H0`%/C`@`` +M&DP`G^7^___K"```ZB``4^,"```:/`"?Y?[__^L#``#J0`!3XP$``!HL`)_E +M_O__ZR@`G^4H$)_E!2"@X08PH.'^___K<("]Z``C```,(P``&",``"@C```X +M(P``1",```PD``#\4P``!.`MY0S03>+^SP#C#`!1X0(``!HR`*#C_O__ZR`` +M`.K]`%'C`@``&@4`H./^___K&P``ZOP`4>,"```:`0"@X_[__^L6``#J^P!1 +MXP(``!HR`*#C_O__ZQ$``.KZ`%'C`@``&@4`H./^___K#```ZOD`4>,"```: +M`0"@X_[__^L'``#J`""-Y0,0H.$0()WE_S\/XP\P0./^___K`0"@X_[__^L, +MT(WB`("]Z'!`+>D(T$WB`$"@X0%0H.$"8*#A`!"-Y0$PH./^___K$#"4Y0`` +M4^,E``"J&#"4Y00`4^,B``":*#"4Y0(`4^,"```:@`"?Y?[__^L7``#J!`!3 +MXP(``!IP`)_E_O__ZQ(``.H(`%/C`@``&F``G^7^___K#0``ZA``4^,"```: +M4`"?Y?[__^L(``#J(`!3XP(``!I``)_E_O__ZP,``.I``%/C`0``&C``G^7^ +M___K+`"?Y2P0G^4%(*#A!C"@X?[__^L(T(WB<("]Z``C```,(P``&",``"@C +M```X(P``1",``$PD```05```<$`MZ0C03>(`0*#A`5"@X0)@H.$`$(WE`#"@ +MX_[__^L0,)3E``!3XR4``*H8,)3E!`!3XR(``)HH,)3E`@!3XP(``!J``)_E +M_O__ZQ<``.H$`%/C`@``&G``G^7^___K$@``Z@@`4^,"```:8`"?Y?[__^L- +M``#J$`!3XP(``!I0`)_E_O__ZP@``.H@`%/C`@``&D``G^7^___K`P``ZD`` +M4^,!```:,`"?Y?[__^LL`)_E+!"?Y04@H.$&,*#A_O__ZPC0C>)P@+WH`",` +M``PC```8(P``*",``#@C``!$(P``B"0``"Q4```P`"WI`#"@X0$C@.#0P(+B +M$P"@XP``S.4!`,SE`@#,Y0``H.,#`,SE`Q"!X@$#P^'J#C`!"%Y000C.4$`,/EZ,""X@%` +MH.,&0,SE\!""XGPR">/_/T_CL##!X;0`S.&T`,7AO@W"X;`.PN&R#L+AM`[" +MX0``C.4"`,'E`P#!Y01`P>4%`,'E!<"@XP;`P>7X((+B/\#@XP3`PN4'`,'E +M``#"Y0$`PN4"`,+E`P#"Y3``O>@>_R_A\$$` +M,*`#"@``"@`0`.,`$$#C`3"@X[+`T>$%`%SA!```"@$P@^)S,._F`A"!X@4` +M4^/W__\:``!2XP`PH`,+```*`0!2XP0``!H!,(/B`"?Y?[__^L7``#J!`!3XP(``!IH`)_E_O__ZQ(``.H(`%/C`@``&E@` +MG^7^___K#0``ZA``4^,"```:2`"?Y?[__^L(``#J(`!3XP(``!HX`)_E_O__ +MZP,``.I``%/C`0``&B@`G^7^___K)`"?Y200G^6P(]3A_O__Z_"'O>C$)``` +MT"0``-PD``#L)```_"0```@E```4)0``5%0``/!/+>D`^?Y?[__^L(``#J(`!3XP(``!IH#Y_E +M_O__ZP,``.I``%/C`0``&E@/G^7^___K5`^?Y50?G^7^___K+C#4Y0``4^/4 +M!``**#"4Y0``4^/1!``*#3#4Y0X@U.4#$$+B`0!3X0(``+H#((+B`@!3X0(` +M`-H`,*#C,C#$Y3,PQ.428-3E$3#4Y0,`5N$#8*`A`#``XP`P0.,&((/@#;#4 +MY4`@TN4"`%OA`+"@@P&PH).+(J#A"R%"X`(P@^`&,(/@7'#3Y="!Q>$"#*#C +M`!"@XP`@".`!,`G@`Q"2X20```H8,)7E!`!3XR$``)HH,)7E`@!3XP(``!IT +M#I_E_O__ZQ<``.H$`%/C`@``&F0.G^7^___K$@``Z@@`4^,"```:5`Z?Y?[_ +M_^L-``#J$`!3XP(``!I$#I_E_O__ZP@``.H@`%/C`@``&C0.G^7^___K`P`` +MZD``4^,!```:)`Z?Y?[__^LH#I_E(!Z?Y1@@E.7^___K`"``XP`@0..4$*#C +MAP"'X(`P@N`!P-/GO('4X1B@E.68K"C@E<#3Y;ZAU.&:C"S@`0"`XH`@@N`! +M(-+GL!+4X9'"(>"7(-/EL@+4X9`2(N"8,-/EM!+4X9$C(^`8,(3ET('%X0(, +MH.,`$*#C`"`(X`$P">`#$)+A*@``"A@PE>4$`%/C)P``FB@PE>4"`%/C`@`` +M&F0-G^7^___K%P``Z@0`4^,"```:5`V?Y?[__^L2``#J"`!3XP(``!I$#9_E +M_O__ZPT``.H0`%/C`@``&C0-G^7^___K"```ZB``4^,"```:)`V?Y?[__^L# +M``#J0`!3XP$``!H4#9_E_O__ZQP=G^4&,*#CDQ(8()3EG`,#X/[__^L8()3E`#``XP`P0..'$(?@@3"#X)DPT^4H$)3ED0,# +MX`,`4N$",&.``#"@DQ@PA.4`,`#C`#!`XP8P@^`@@=/E`@R@XP`0H./0(<7A +M`"`"X`$P`^`#$)+A)```"A@PE>4$`%/C(0``FB@PE>4"`%/C`@``&EP,G^7^ +M___K%P``Z@0`4^,"```:3`R?Y?[__^L2``#J"`!3XP(``!H\#)_E_O__ZPT` +M`.H0`%/C`@``&BP,G^7^___K"```ZB``4^,"```:'`R?Y?[__^L#``#J0`!3 +MXP$``!H,#)_E_O__ZQP,G^4(')_E%""4Y?[__^L`(`#C`"!`XY00H..(`(C@ +M@#""X`'`T^>\D=3A%*"4Y9FL+."5H-/EOI'4X9G**>`!`(#B@"""X`$@TN>P +MHM3AFI(JX)<@T^6RPM3AG*(LX)@PT^6T(M3ADL,CX!0PA.4"#*#C`!"@X]`A +MQ>$`(`+@`3`#X`,0DN$J```*&#"5Y00`4^,G``":*#"5Y0(`4^,"```:3`N? +MY?[__^L7``#J!`!3XP(``!H\"Y_E_O__ZQ(``.H(`%/C`@``&BP+G^7^___K +M#0``ZA``4^,"```:'`N?Y?[__^L(``#J(`!3XP(``!H,"Y_E_O__ZP,``.I` +M`%/C`0``&OP*G^7^___K!!N?Y08PH..3&"/@F3#3Y2C`E.7\"I_E*!"!XA0@ +ME.6<`P/@_O__ZQ0@E.4`,`#C`#!`XX@0B."!,(/@F3#3Y2@0E.61`P/@`P!2 +MX0(P8X``,*"3%#"$Y1`@E>4`,@#C`#!(XP,P`N```%/C+0``"A@PE>4#`%/C +M*@``FB@PE>4"`%/C`@``&E@*G^7^___K%P``Z@0`4^,"```:2`J?Y?[__^L2 +M``#J"`!3XP(``!HX"I_E_O__ZPT``.H0`%/C`@``&B@*G^7^___K"```ZB`` +M4^,"```:&`J?Y?[__^L#``#J0`!3XP$``!H("I_E_O__ZPT@U.6``8WH"&"- +MY1@PE.4,,(WE%#"4Y1`PC>4,,-3E%#"-Y?P)G^7@&9_E"S"@X?[__^L`,`#C +M`#!`XX8P@^!//X/BL##3X1@@E.4#`%+A!@``.@`P`.,`,$#C!C"#X+PBU.%T +M,=/E`P!2X7$!`)K08<7A`@R@XP`0H.,`(`;@`3`'X`,0DN$C```*&#"5Y00` +M4^,@``":*#"5Y0(`4^,"```:2`F?Y?[__^L7``#J!`!3XP(``!HX"9_E_O__ +MZQ(``.H(`%/C`@``&B@)G^7^___K#0``ZA``4^,"```:&`F?Y?[__^L(``#J +M(`!3XP(``!H("9_E_O__ZP,``.I``%/C`0``&O@(G^7^___K%`F?Y109G^7^ +M___K``!4XRL``!K08<7A`@R@XP`0H.,`(`;@`3`'X`,0DN'D`@`*&#"5Y0,` +M4^/A`@":*#"5Y0(`4^,"```:E`B?Y?[__^L7``#J!`!3XP(``!J$")_E_O__ +MZQ(``.H(`%/C`@``&G0(G^7^___K#0``ZA``4^,"```:9`B?Y?[__^L(``#J +M(`!3XP(``!I4")_E_O__ZP,``.I``%/C`0``&D0(G^7^___K:`B?Y6`8G^7^ +M___KOP(`ZA%PU.43@-3E$F#4Y="AQ>$"#*#C`!"@XP`@"N`!,`O@`Q"2X2@` +M``H8,)7E!`!3XR4``)HH,)7E`@!3XP(``!K8!Y_E_O__ZQ<``.H$`%/C`@`` +M&L@'G^7^___K$@``Z@@`4^,"```:N`>?Y?[__^L-``#J$`!3XP(``!JH!Y_E +M_O__ZP@``.H@`%/C`@``&I@'G^7^___K`P``ZD``4^,!```:B`>?Y?[__^L` +M8(WE###4Y00PC>6D!Y_EF!>?Y0<@H.$(,*#A_O__ZP8`5^$;``"*###4Y0`` +M4^,`,*`3###$%0=@H!$5```:"`!7X0A@H)$2``":``!7XP\```H!8$?B=F#O +MY@8`6.$+```J"#"4Y0$@H.,2)A/@`2"@`P(```H&``#J$A83X`0``!H!8$;B +M=F#OY@8`6.'Y__\Z!V"@X3(PU.4!`%/C!0``&@(PH.,R,,3E,S#4Y0$P@^(S +M,,3E!```Z@``4^,`,*`3,C#$%3,PQ!4#```:,S#4Y0,`4^,$,*"#,S#$A1!@ +MQ.4%`*#A!!"@X0(@H.-'_?_KT('%X0(,H.,`$*#C`"`(X`$P">`#$)+A4`(` +M"A@PE>4#`%/C)P``FB@PE>4"`%/C`@``&D0&G^7^___K%P``Z@0`4^,"```: +M-`:?Y?[__^L2``#J"`!3XP(``!HD!I_E_O__ZPT``.H0`%/C`@``&A0&G^7^ +M___K"```ZB``4^,"```:!`:?Y?[__^L#``#J0`!3XP$``!KT!9_E_O__ZR`& +MG^40%I_E_O__Z]"!Q>$"#*#C`!"@XP`@".`!,`G@`Q"2X24"``H8,)7E!`!3 +MXRD``)HH,)7E`@!3XP(``!J8!9_E_O__ZQ<``.H$`%/C`@``&H@%G^7^___K +M$@``Z@@`4^,"```:>`6?Y?[__^L-``#J$`!3XP(``!IH!9_E_O__ZP@``.H@ +M`%/C`@``&E@%G^7^___K`P``ZD``4^,!```:2`6?Y?[__^N4!9_E9!6?Y3(@ +MU.4S,-3E_O__Z]"!Q>$"#*#C`!"@XP`@".`!,`G@`Q"2X?@!``H8,)7E`P!3 +MXRD``)HH,)7E`@!3XP(``!KD!)_E_O__ZQ<``.H$`%/C`@``&M0$G^7^___K +M$@``Z@@`4^,"```:Q`2?Y?[__^L-``#J$`!3XP(``!JT!)_E_O__ZP@``.H@ +M`%/C`@``&J0$G^7^___K`P``ZD``4^,!```:E`2?Y?[__^O$!)_EL!2?Y08@ +MH.$,,-3E_O__Z]!AQ>$"#*#C`!"@XP`@!N`!,`?@`Q"2X4$`%/C(@``FB@PE>4"`%/C +M`@``&O0!G^7^___K%P``Z@0`4^,"```:Y`&?Y?[__^L2``#J"`!3XP(``!K4 +M`9_E_O__ZPT``.H0`%/C`@``&L0!G^7^___K"```ZB``4^,"```:M`&?Y?[_ +M_^L#``#J0`!3XP$``!JD`9_E_O__Z^0!G^7T$9_E"""@X04# +M`%/C(```FB@PE>4"`%/C`@``&@0!G^7^___K%P``Z@0`4^,"```:]`"?Y?[_ +M_^L2``#J"`!3XP(``!KD`)_E_O__ZPT``.H0`%/C`@``&M0`G^7^___K"``` +MZB``4^,"```:Q`"?Y?[__^L#``#J0`!3XP$``!JT`)_E_O__Z_@`G^4$$9_E +M_O__ZP<`6.$0```J`6"(XG9@[^8&`%?A1```.@@PE.4!(*#C$B83X`$@H`," +M```*/P``ZA(6$^`]```:`6"&XG9@[^8&`%?A^?__*C<``.H'`%CA!V"@$34` +M`!H/,-3E``!3XP<```H,(-3E`0!2XP$PH!,,,,05"&"@$2P``!H!`%/C*0`` +M"@`PH.,,,,3E"&"@X28``.K$)```T"0``-PD``#L)```_"0```@E```T)0`` +M<%0``%PE``!(5```>"4``*@E``#$)0``["4``%0F``#850``>"8``*@F``#D +M)@``/"<``&@G``",)P``L"<``-PG````*```,"@```PG``!,*```)%8``'`H +M``#$)```T"0``-PD``#L)```_"0```@E``"L*```<%0```A@H.$R(-3E`#`` +MXP`P0.,S$-3E`3"#X/`QT^4$,(/B`P!2X0`PH`,R,,0%`2""$C(@Q!408,3E +MT('%X0(,H.,`$*#C`"`(X`$P">`#$)+A?```"A@PE>4#`%/C*```FB@PE>4" +M`%/C`@``&I0`'^7^___K%P``Z@0`4^,"```:I``?Y?[__^L2``#J"`!3XP(` +M`!JT`!_E_O__ZPT``.H0`%/C`@``&L0`'^7^___K"```ZB``4^,"```:U``? +MY?[__^L#``#J0`!3XP$``!KD`!_E_O__ZQ0!'^4,$1_E!B"@X?[__^O08<7A +M`@R@XP`0H.,`(`;@`3`'X`,0DN%0```*&#"5Y00`4^--``":*#"5Y0(`4^," +M```:1`$?Y?[__^L7``#J!`!3XP(``!I4`1_E_O__ZQ(``.H(`%/C`@``&F0! +M'^7^___K#0``ZA``4^,"```:=`$?Y?[__^L(``#J(`!3XP(``!J$`1_E_O__ +MZP,``.I``%/C`0``&I0!'^7^___KP`$?Y;P1'^4R(-3E,S#4Y?[__^O08<7A +M`@R@XP`0H.,`(`;@`3`'X`,0DN$C```*&#"5Y00`4^,@``":*#"5Y0(`4^," +M```:^`$?Y?[__^L7``#J!`!3XP(``!H(`A_E_O__ZQ(``.H(`%/C`@``&A@" +M'^7^___K#0``ZA``4^,"```:*`(?Y?[__^L(``#J(`!3XP(``!HX`A_E_O__ +MZP,``.I``%/C`0``&D@"'^7^___K<`(?Y7`2'^7^___K$"#4Y1$PU.4#`%+A +M"```&@`P`.,`,$#C`"#3Y0$@@N)R(._F`"##Y0,`4N,%``"*-P``Z@`P`.,` +M,$#C`""@XP`@P^4R``#J!0"@X000H.$!(*#CV?K_Z]!AQ>$"#*#C`!"@XP`@ +M!N`!,`?@`Q"2X2,```H8,)7E`P!3XR```)HH,)7E`@!3XP(``!K\`A_E_O__ +MZQ<``.H$`%/C`@``&@P#'^7^___K$@``Z@@`4^,"```:'`,?Y?[__^L-``#J +M$`!3XP(``!HL`Q_E_O__ZP@``.H@`%/C`@``&CP#'^7^___K`P``ZD``4^,! +M```:3`,?Y?[__^ML`Q_E4!,?Y?[__^L`,`#C`#!`XP`@H.,`(,/E$"#4Y1$@ +MQ.4`,`#C`#!`XX(P@^!/+X/BL"#2X6D_@^*P,-/A`S""X,,PH.$4,(3E&#"$ +MY=!AQ>$"#*#C`!"@XP`@!N`!,`?@`Q"2X2,```H8,)7E!`!3XR```)HH,)7E +M`@!3XP(``!KL`Q_E_O__ZQ<``.H$`%/C`@``&OP#'^7^___K$@``Z@@`4^," +M```:#`0?Y?[__^L-``#J$`!3XP(``!HD`0*#A`5"@X0)@H.'0@<#A`@R@XP`0H.,`(`C@`3`)X`,0DN$E```* +M&#"4Y00`4^,B``":*#"4Y0(`4^,"```:G`"?Y?[__^L7``#J!`!3XP(``!J, +M`)_E_O__ZQ(``.H(`%/C`@``&GP`G^7^___K#0``ZA``4^,"```:;`"?Y?[_ +M_^L(``#J(`!3XP(``!I<`)_E_O__ZP,``.I``%/C`0``&DP`G^7^___K2`"? +MY4@0G^4%(*#A!C"@X?[__^L'`%7C`#"@DP$PH(,``%3C`3"#`P``4^,%0X0` +MS6#$!7"#O>C$)```T"0``-PD``#L)```_"0```@E``#4*```0%8``/!'+>D` +M,*#A!P!1XP`@H),!(*"#``!0XP$@@@,``%+C`$"@$R\``!H!4*#A`2.`X/9` +MTN70@<#A`FR@XP!PH.,&``C@!Q`)X`$@D.$E```*&""3Y00`4N,B``":*#"3 +MY0(`4^,"```:@`"?Y?[__^L7``#J!`!3XP(``!IP`)_E_O__ZQ(``.H(`%/C +M`@``&F``G^7^___K#0``ZA``4^,"```:4`"?Y?[__^L(``#J(`!3XP(``!I` +M`)_E_O__ZP,``.I``%/C`0``&C``G^7^___K+`"?Y2P0G^4%(*#A!#"@X?[_ +M_^L$`*#A\(>]Z,0D``#0)```W"0``.PD``#\)```""4``/`H``!85@``\$$"#*#C`!"@XP`@!N`!,`?@`Q"2X28```H8,)7E!`!3XR,``)HH,)7E`@!3 +MXP(``!J(`)_E_O__ZQ<``.H$`%/C`@``&G@`G^7^___K$@``Z@@`4^,"```: +M:`"?Y?[__^L-``#J$`!3XP(``!I8`)_E_O__ZP@``.H@`%/C`@``&D@`G^7^ +M___K`P``ZD``4^,!```:.`"?Y?[__^L$,X7@,`"?Y3`0G^4$(*#AS##3Y?[_ +M_^L$0X7@S`#4Y?"!O>C$)```T"0``-PD``#L)```_"0```@E```T*0``E%8` +M`/!!+>D`4*#AT&'`X0(,H.,`$*#C`"`&X`$P!^`#$)+A(P``"A@PE>4#`%/C +M(```FB@PE>4"`%/C`@``&IP`G^7^___K%P``Z@0`4^,"```:C`"?Y?[__^L2 +M``#J"`!3XP(``!I\`)_E_O__ZPT``.H0`%/C`@``&FP`G^7^___K"```ZB`` +M4^,"```:7`"?Y?[__^L#``#J0`!3XP$``!I,`)_E_O__ZT@`G^5($)_E_O__ +MZP!`H..\2\7A!0"@X000H.'^___K`4"$XG1`[^8(`%3C^/__&@``H./P@;WH +MQ"0``-`D``#<)```["0``/PD```()0``3"D``*Q6``#00"WI`$"@X=!AP.$" +M#*#C`!"@XP`@!N`!,`?@`Q"2X2,```H8,)3E`P!3XR```)HH,)3E`@!3XP(` +M`!J$`)_E_O__ZQ<``.H$`%/C`@``&G0`G^7^___K$@``Z@@`4^,"```:9`"? +MY?[__^L-``#J$`!3XP(``!I4`)_E_O__ZP@``.H@`%/C`@``&D0`G^7^___K +M`P``ZD``4^,!```:-`"?Y?[__^LP`)_E,!"?Y?[__^LH,)3E$`!3XP$PH`/` +M,L0%T("]Z,0D``#0)```W"0``.PD``#\)```""4``%PI``#`5@``\$\MZ3S0 +M3>(`4*#A`6"@X0*PH.$@,(WET('`X0(,H.,`$*#C`"`(X`$P">`#$)+A)@`` +M"A@PE>4#`%/C(P``FB@PE>4"`%/C`@``&C0)G^7^___K%P``Z@0`4^,"```: +M)`F?Y?[__^L2``#J"`!3XP(``!H4"9_E_O__ZPT``.H0`%/C`@``&@0)G^7^ +M___K"```ZB``4^,"```:]`B?Y?[__^L#``#J0`!3XP$``!KD")_E_O__ZP"P +MC>7<")_EW!B?Y2`@G>5@,)WE_O__ZZNQH.%\@@GC`$"@XP`P`.,`,$#C-#"- +MY0`P`.,`,$#C)#"-Y:,O@^(H((WE`#``XP`P0.,L,(WE`#``XP`P0.,P,(WE +M!P!4XP1PH(%9`0"*'P!4XR`P1((!(*"#8!"=A1(S`8`!,*"3(""=E1,T`I`$ +M<*#A``!3XTX!``H$,X7@V*"#XK`0UN&T$,KAVI"#X@(@UN6T(,GAW,"#X@,@ +MUN6T(,SAW@"#X@0@UN6T(,#AX!"#X@4@UN6T(,'A!B#6Y>@P@^*T(,/AM)#9 +MX;2@VN$*D(G@M*#"TH-#A"I")X+2@T>$*D(G@`I")X`"0@^4``%GC +M`P$`"@(,H.,`$*#CT"'%X0`@`N`!,`/@`Q"2X3<```H8,)7E`P!3XS0``)HH +M,)7E`@!3XP(``!J`!Y_E_O__ZQ<``.H$`%/C`@``&G`'G^7^___K$@``Z@@` +M4^,"```:8`>?Y?[__^L-``#J$`!3XP(``!I0!Y_E_O__ZP@``.H@`%/C`@`` +M&C``G>7^___K`P``ZD``4^,!```:+`"=Y?[__^L'(X7@Z#""XKP=TN$`$(WE +MOAW2X000C>6P'M+A"!"-Y;(>TN$,$(WEM"[2X1`@C>6T(-/A%""-Y2`@G>48 +M((WE8!"=Y1P0C>7L!I_E*!"=Y00@H.$`,)/E_O__ZP,0A^(!$X7@!S.%X/0P +MT^4``%/CNP``"@#[,-/E!`!3XP(``(H%`*#AA?C_ZZD``.H%`%/C:``` +M&@#P((/B`!"@XP40PN7Z,-/E`P!3XP/QGY<>``#JC#D$`'`Y!`!4.00` +M.#D$``#0,-/E&`!3XP#0,-/E`@!3XP#-(-/E+P!2X_`P@Y(`(*"3!B## +ME38``)H',X7@]3#3Y0$`4^,L```:!S.%X/#Y,-/E +M!1""X@$`4^$'``#*!2!"X@(`4^$$``"Z!S.%X-`@T^7X,-/E`P!2X1(```H' +M,X7@]C#3Y0``4^,',X4``2"@`_8@PP4$```*`0!3XP`#(*`#!2"@$_8@ +MP^4',X7@S2#3Y?D@P^7P,(/B`""@XP<@P^4.``#J!S.%X/@@@^(`$*#C`Q#" +MY?`P@^('(-/E`2""X@<@P^4%``#J!R.%X/`0@N(`,*#C!C#!Y?@@@N(#,,+E +M!S.%X-`@T^7X(,/E/@``Z@#HD)/EB9*@X;P]T^$B(*#CDP(#X`,`6>$` +M(*`S$0``.B0@G>6J#X+B`2"@XPB@H.$!P-#EOH'1X9@\(^`#`%GA!P``.@$@ +M@N)R(._F`A"!X@$`@.(%`%+C]/__&@J`H.$```#J"H"@X:(@H.$',X7@]A#3 +MY0$0@>*A$*#A`0!2X0`0H",!$&(P<1#O-@#X,(/B!"#3Y2(!H.&B((#@ +M`B""X@$B@N!R(._F!"##Y<``4N,$``":!S.%X#\@X./\(,/E!C"@XP(``.JB +M,J#A!C`3X@$```H!,$/B"\+M+A`P!2XP`PH(,'(X7@]C#"Y0#[,-/E!0!3XP4#`%/C +M(```FB@PE>4"`%/C`@``&G`#G^7^___K%P``Z@0`4^,"```:8`.?Y?[__^L2 +M``#J"`!3XP(``!I0`Y_E_O__ZPT``.H0`%/C`@``&D`#G^7^___K"```ZB`` +M4^,"```:,`"=Y?[__^L#``#J0`!3XP$``!HL`)WE_O__ZS0`G>4H$)WE_O__ +MZP=SA>"P/]?A`P!8X0.`H"$!0(3B=$#OY@0`6^$(8(:"F?[_BM!AQ>$"#*#C +M`!"@XP`@!N`!,`?@`Q"2X2,```H8,)7E!`!3XR```)HH,)7E`@!3XP(``!J@ +M`I_E_O__ZQ<``.H$`%/C`@``&I`"G^7^___K$@``Z@@`4^,"```:@`*?Y?[_ +M_^L-``#J$`!3XP(``!IP`I_E_O__ZP@``.H@`%/C`@``&F`"G^7^___K`P`` +MZD``4^,!```:4`*?Y?[__^M8`I_E6!*?Y?[__^N\.]7A"`!3X3````K08<7A +M`@R@XP`0H.,`(`;@`3`'X`,0DN$E```*&#"5Y0,`4^,B``":*#"5Y0(`4^," +M```:Z`&?Y?[__^L7``#J!`!3XP(``!K8`9_E_O__ZQ(``.H(`%/C`@``&L@! +MG^7^___K#0``ZA``4^,"```:N`&?Y?[__^L(``#J(`!3XP(``!JH`9_E_O__ +MZP,``.I``%/C`0``&I@!G^7^___KJ`&?Y:`1G^6\*]7A"#"@X?[__^L``)7E +M"!"@X?[__^N\B\7AT&'%X0(,H.,`$*#C`"`&X`$P!^`#$)+A3@``"A@PE>4$ +M`%/C)P``FB@PE>4"`%/C`@``&B0!G^7^___K%P``Z@0`4^,"```:%`&?Y?[_ +M_^L2``#J"`!3XP(``!H$`9_E_O__ZPT``.H0`%/C`@``&O0`G^7^___K"``` +MZB``4^,"```:Y`"?Y?[__^L#``#J0`!3XP$``!K4`)_E_O__Z^@`G^7<$)_E +M_O__Z]!AQ>$"#*#C`!"@XP`@!N`!,`?@`Q"2X2,```H8,)7E`P!3XR```)HH +M,)7E`@!3XP(``!IX`)_E_O__ZQ<``.H$`%/C`@``&F@`G^7^___K$@``Z@@` +M4^,"```:6`"?Y?[__^L-``#J$`!3XP(``!I(`)_E_O__ZP@``.H@`%/C`@`` +M&C@`G^7^___K`P``ZD``4^,!```:*`"?Y?[__^M``)_E)!"?Y?[__^L\T(WB +M\(^]Z,0D``#0)```W"0``.PD``#\)```""4``(`I``#45@``T"D``#@J``#X +M5@``8"H``)0J``"\*@``$$`MZ0$@H.%/'J#C_O__ZQ"`O>CP32WI"-!-X@!` +MH.$!4*#A`F"@X0-PH.$H@-WET*'`X0(,H.,`$*#C`"`*X`$P"^`#`)+A)@`` +M"A@PE.4#`%/C(P``FB@PE.4"`%/C`@``&L0$G^7^___K%P``Z@0`4^,"```: +MM`2?Y?[__^L2``#J"`!3XP(``!JD!)_E_O__ZPT``.H0`%/C`@``&I0$G^7^ +M___K"```ZB``4^,"```:A`2?Y?[__^L#``#J0`!3XP$``!IT!)_E_O__ZX`! +MC>AL!)_E;!2?Y04@H.$&,*#A_O__ZP<`5>,`,*"3`3"@@P``5.,!,(,#``!3 +MXP@!`!H#,(7B`V/$YP,CA.`$<(+E!2.$X,^`PN4#,]3G#P!3XP/QGY=<``#J +M,$$$`$Q!!`!H000`A$$$`*!!!`"\000`T$$$`&1"!`!D0@0`9$($`&1"!`!D +M0@0`Y$$$``1"!``D0@0`1$($``4CA.#$$)+E%3`/XX\_0.,#,`'@R#""Y4@` +M`.H%(X3@Q!"2Y1`P#^.//T#C`S`!X,@P@N5!``#J!2.$X,00DN4%,`_CCS]` +MXP,P`>#(,(+E.@``Z@4CA.#$$)+E`#`/XX\_0.,#,`'@R#""Y3,``.H%(X3@ +MQ!"2Y?4_`.,`,$#C`S`!X,@P@N4L``#J!3.$X,0@D^7_+@+BR""#Y2<``.H% +M,X3@Q""3Y0T@`N+(((/E(@``Z@0`H.%$%`#C_O__ZP4SA.#$()/E`B``X,@@ +M@^4:``#J!`"@X4@4`./^___K!3.$X,0@D^4"(`#@R""#Y1(``.H$`*#A3!0` +MX_[__^L%,X3@Q""3Y0(@`.#(((/E"@``Z@0`H.%%'J#C_O__ZP4SA.#$()/E +M`B``X,@@@^4"``#J!3.$X,0@D^7(((/E!3.$X,@@D^4``%+C#@``"@$"$N,< +M,*`3!```&ALPH.,!$*#C$0,2X`,```IS,._F!2.$X-(PPN4'``#J`3!#X@$` +M<^/V__\:!P``Z@4SA.#0,(/B`""@XP(@P^4%,X3@R#"3Y0``4^,0```*!3.$ +MX,@@D^4!`!+C`#"@$P0``!H!,*#C`Q"@X1$#$N`#```*4X`)_E,!"?Y00PD^7^___K"-"-XO"-O>C$)```T"0` +M`-PD``#L)```_"0```@E``#H*@``$%<``"`K```L5P``3"L``![_+^$`,*#C +M3S3`Y4TTP.5.-,#E4#3`Y4PTP.4>_R_A3P30Y1[_+^$>_R_AT$`MZ0!`H.$\ +M,-#E`0!3X]"`O1@H-)#E%C3`Y=!AP.%``*#C`!"@XP`@!N`!,`?@`Q"2X="` +MO0@8,)3E`P!3X]"`O9@H,)3E`@!3XP(``!IX`)_E_O__ZQ<``.H$`%/C`@`` +M&F@`G^7^___K$@``Z@@`4^,"```:6`"?Y?[__^L-``#J$`!3XP(``!I(`)_E +M_O__ZP@``.H@`%/C`@``&C@`G^7^___K`P``ZD``4^,!```:*`"?Y?[__^LD +M`)_E)!"?Y2@DE.7^___KT("]Z*0K``"P*P``O"L``,PK``#<*P``Z"L``/0K +M``!$5P``\$\MZ2303>(`4*#AQ1Z@XX`@H.,!,*#C_O__ZP5`H.$%@*#A`!"@ +MXQ`0C>4($(WE`;"@X?\@H.,,((WE`9"@X0`P`.,`,$#C%#"-Y0`P`.,`,$#C +M&#"-Y0`P`.,`,$#C'#"-Y9PPE.4``%/C>P$`"K03E.4``%'C`'"@`P(```IT +M`Y3E_O__ZP!PH.'4$Y3E``!1XP!@H`,"```*E`.4Y?[__^L`8*#A!@!7X0"@ +MH(,!H*"30`"@XP`0H./0(<7A`"`"X`$P`^`#$)+AA```"A@PE>4#`%/C@0`` +MFB@PE>4"`%/C`@``&L`&G^7^___K%P``Z@0`4^,"```:L`:?Y?[__^L2``#J +M"`!3XP(``!J@!I_E_O__ZPT``.H0`%/C`@``&I`&G^7^___K"```ZB``4^," +M```:@`:?Y?[__^L#``#J0`!3XP$``!IP!I_E_O__Z[0SE.4`,(WE9`:?Y606 +MG^4)(*#A=#.4Y?[__^M``*#C`!"@X]`AQ>$`(`+@`3`#X`,0DN%5```*&#"5 +MY0,`4^-2``":*#"5Y0(`4^,"```:!`:?Y?[__^L7``#J!`!3XP(``!KT!9_E +M_O__ZQ(``.H(`%/C`@``&N0%G^7^___K#0``ZA``4^,"```:U`6?Y?[__^L( +M``#J(`!3XP(``!K$!9_E_O__ZP,``.I``%/C`0``&K0%G^7^___KU#.4Y0`P +MC>6P!9_EJ!6?Y0D@H.&4,Y3E_O__ZT``H.,`$*#CT"'%X0`@`N`!,`/@`Q"2 +MX28```H8,)7E`P!3XR,``)HH,)7E`@!3XP(``!I(!9_E_O__ZQ<``.H$`%/C +M`@``&C@%G^7^___K$@``Z@@`4^,"```:*`6?Y?[__^L-``#J$`!3XP(``!H8 +M!9_E_O__ZP@``.H@`%/C`@``&@@%G^7^___K`P``ZD``4^,!```:^`2?Y?[_ +M_^L`8(WE_`2?Y?`4G^4)(*#A!S"@X?[__^L'`%;A!C"@(04``%/C +M``!7`P9PH`$"```*`0!3XP``5@,'8*`!!P!6X0=@H"$,,)WE`P!6X1"@C34, +M8(TU!0"@X608`.,X(*#C"C"@X?[__^L%`*#A9!@`XP%``*#C`!"@ +MXP`@!N`!,`?@`Q"2X:@```H8,)7E`P!3XZ4``)HH,)7E`@!3XP(``!K4`Y_E +M_O__ZQ<``.H$`%/C`@``&L0#G^7^___K$@``Z@@`4^,"```:M`.?Y?[__^L- +M``#J$`!3XP(``!JD`Y_E_O__ZP@``.H@`%/C`@``&I0#G^7^___K`P``ZD`` +M4^,!```:A`.?Y?[__^L4`)WE@!.?Y0H@H.'^___KT&'%X4``H.,`$*#C`"`& +MX`$P!^`#$)+A?```"A@PE>4#`%/C>0``FB@PE>4"`%/C`@``&B0#G^7^___K +M%P``Z@0`4^,"```:%`.?Y?[__^L2``#J"`!3XP(``!H$`Y_E_O__ZPT``.H0 +M`%/C`@``&O0"G^7^___K"```ZB``4^,"```:Y`*?Y?[__^L#``#J0`!3XP$` +M`!K4`I_E_O__ZQ@`G>70$I_E7"/8Y?[__^O08<7A0`"@XP`0H.,`(`;@`3`' +MX`,0DN%0```*&#"5Y0,`4^--``":*#"5Y0(`4^,"```:=`*?Y?[__^L7``#J +M!`!3XP(``!ID`I_E_O__ZQ(``.H(`%/C`@``&E0"G^7^___K#0``ZA``4^," +M```:1`*?Y?[__^L(``#J(`!3XP(``!HT`I_E_O__ZP,``.I``%/C`0``&B0" +MG^7^___K'`"=Y2`2G^5D(]CE_O__Z]!AQ>%``*#C`!"@XP`@!N`!,`?@`Q"2 +MX20```H8,)7E`P!3XR$``)HH,)7E`@!3XP(``!K$`9_E_O__ZQ<``.H$`%/C +M`@``&K0!G^7^___K$@``Z@@`4^,"```:I`&?Y?[__^L-``#J$`!3XP(``!J4 +M`9_E_O__ZP@``.H@`%/C`@``&H0!G^7^___K`P``ZD``4^,!```:=`&?Y?[_ +M_^N``9_E4#`%+A"0``&@4`H.%D&`#C.""@X_[__^L%`*#A +M9!@`XP708<7A0`"@XP`0H.,`(`;@`3`'X`,0 +MDN$D```*&#"5Y0,`4^,A``":*#"5Y0(`4^,"```:B`"?Y?[__^L7``#J!`!3 +MXP(``!IX`)_E_O__ZQ(``.H(`%/C`@``&F@`G^7^___K#0``ZA``4^,"```: +M6`"?Y?[__^L(``#J(`!3XP(``!I(`)_E_O__ZP,``.I``%/C`0``&C@`G^7^ +M___K2`"?Y300G^40()WE_O__ZRBTA>4(()WE+"2%Y230C>+PC[WHI"L``+`K +M``"\*P``S"L``-PK``#H*P``."P``%Q7``!D+```D"P``/PL```0+0``\$$M +MZ2@0D.40`%'C`@``&B`PD.5``!/C*@``&M!AP.%`0*#C`%"@XP0@!N`%,`?@ +M`\"2X?"!O0@8,)#E`P!3X_"!O9@"`%'C`@``&M0`G^7^___K%P``Z@0`4>," +M```:Q`"?Y?[__^L2``#J"`!1XP(``!JT`)_E_O__ZPT``.H0`%'C`@``&J0` +MG^7^___K"```ZB``4>,"```:E`"?Y?[__^L#``#J0`!1XP$``!J$`)_E_O__ +MZX``G^6`$)_E_O__Z_"!O>B6,-#E``!3XP\``!K08<#A0$"@XP!0H.,$(`;@ +M!3`'X`,0DN'P@;T(&#"0Y0,`4^/P@;V8,`"?Y?[__^L\`)_E-!"?Y?[__^OP +M@;WH/##0Y0$`4^/P@;T8_O__Z_"!O>BD*P``L"L``+PK``#,*P``W"L``.@K +M```D+0``<%<``%PM``#P02WI`$"@X=!AP.%``*#C`!"@XP`@!N`!,`?@`Q"2 +MX2,```H8,)3E`P!3XR```)HH,)3E`@!3XP(``!I,`I_E_O__ZQ<``.H$`%/C +M`@``&CP"G^7^___K$@``Z@@`4^,"```:+`*?Y?[__^L-``#J$`!3XP(``!H< +M`I_E_O__ZP@``.H@`%/C`@``&@P"G^7^___K`P``ZD``4^,!```:_`&?Y?[_ +M_^OX`9_E^!&?Y?[__^L$`*#A!#"@X0`0H.,!(*#A]"+`Y0`C@^4<(X/E.".# +MY0$0@>(!`(#B!#"#X@8`4>/V__\:`%"@XUA3A.544\3E!`"@X4P0H.,`(.#C +M_O__ZPHU@.,$`*#A3!"@XP`@X./^___K!`"@X;07`.,`(.#C_O__ZP,X@.,$ +M`*#AM!<`XP`@X./^___K!`"@X;07`./_+P_C!3"@X?[__^L$`*#A>QZ@XP`@ +MX.,%,*#A_O__ZP0`H.&''J#C`RR@XP4PH.'^___K!`"@X608`.,!*Z#C!3"@ +MX?[__^L$`*#A+!L`XP$EH.,%,*#A_O__ZP0`H.$L&P#C`B&@XP$PH./^___K +M!`"@X:0<`.,`(.#CH#"@X_[__^N9,-3E!0!3X0H``!H$`*#A6!@`XPBD*P`` +ML"L``+PK``#,*P``W"L``.@K``"L+0``I%<``-!`+>D`0*#AT&'`X4``H.,` +M$*#C`"`&X`$P!^`#$)+A(P``"A@PE.4#`%/C(```FB@PE.4"`%/C`@``&A`! +MG^7^___K%P``Z@0`4^,"```:``&?Y?[__^L2``#J"`!3XP(``!KP`)_E_O__ +MZPT``.H0`%/C`@``&N``G^7^___K"```ZB``4^,"```:T`"?Y?[__^L#``#J +M0`!3XP$``!K``)_E_O__Z[P`G^6\$)_E_O__ZP0`H.%,$*#C`"#@X_[__^L* +M-8#C!`"@X4P0H.,`(.#C_O__ZP0`H.&''J#C`RR@XP`PH./^___K!`"@X608 +M`.,!*Z#C`#"@X_[__^L$`*#A+!L`XP$EH.,!,*#C_O__ZP0`H.$L&P#C`B&@ +MXP$PH./^___K!`"@X:0<`.,`(.#CH#"@X_[__^L$`*#AQ1Z@XX`@H.,!,*#C +M_O__Z]"`O>BD*P``L"L``+PK``#,*P``W"L``.@K``#,+0``O%<``-!`+>D` +M0*#A*#"0Y1``4^/0@+T8T&'`X4``H.,`$*#C`"`&X`$P!^`#$)+A.@``"A@P +ME.4#`%/C-P``FA@!G^7^___K%`&?Y101G^4\(-3E_O__Z]!AQ.%``*#C`!"@ +MXP`@!N`!,`?@`Q"2X2H```H8,)3E`P!3XR<``)HH,)3E`@!3XP(``!K8`)_E +M_O__ZQ<``.H$`%/C`@``&L@`G^7^___K$@``Z@@`4^,"```:N`"?Y?[__^L- +M``#J$`!3XP(``!J0`)_E_O__ZP@``.H@`%/C`@``&I0`G^7^___K`P``ZD`` +M4^,!```:A`"?Y?[__^N9$-3E``!1XP`@`.,`($#C`#``XP`P0.,#(*`!9`"? +MY4@0G^7^___K/##4Y0(`4^,"```:!`"@X?[__^O0@+WH`0!3XP(``!H$`*#A +M_O__Z]"`O>@$`%/CT("]&`0`H.'^___KT("]Z,PK``#L+0``T%<``*0K``"P +M*P``O"L``-PK``#H*P``'"X``/!/+>D,T$WB!`"-Y0&@H.$"@*#A`["@X3!` +MG>4`D*#C!G#4Y050U.6P8-3A!`#4Y5`"X^<#,-3E4Q+CYP(@U.4/,`/B`P`8 +MX2\```H"`!KA+0``"@$`&^$K```*`0!`X@,`4.,`\9^7)P``ZH!7!`"L5P0` +M]%<$`'A7!``!`*#C)```Z@0`G>4&$*#A_O__ZP4@P.$'4`7@!2""X00`G>4& +M$*#A4&$*#A_O__ZP4``.```%?A`3"@`P(` +M``H*`*#C_O__ZP`PH..((P'C`@!9X0H``(H!D(GB``!3X^___PH$``#J``!7 +MXP8`H`'Z/Z`3DP8`$/[__^L(0(3BPO__Z@``H.,,T(WB\(^]Z```X.&@#Z#A +M'O\OX0``@.4$`(#E'O\OX0`PD.4``%/A``"@$P$`H`,>_R_A`#"1Y00`@^4` +M,(#E!!"`Y0``@>4>_R_A!#"1Y00`@>4*`(#H``"#Y1[_+^$$,(#B"@"`Z`@P +M@.4>_R_A'O\OX1[_+^$>_R_A'O\OX0T@H.%_/<+C/S##XP0@D^4!((+B!""# +MY1[_+^$-(*#A?SW"XS\PP^,$()/E`2""X@0@@^4>_R_A$$`MZ?[__^L0@+WH +M$$`MZ?[__^L0@+WH``!1X0``H!,!`*`#'O\OX0`P`.,`,$#C``"3Y1[_+^'Z +M/Z#CDP`#X!\E"./K(47CDA."X*("H.$>_R_A`#``XP`P0.,`,)/E`S!@X/HO +MH..2`P/@'R4(X^LA1>.2$X+@H@*@X1[_+^$!$&#@^C^@XY,!`>`?-0CCZS%% +MXY,A@^"C`J#A'O\OX0`0@.4>_R_A``"0Y1[_+^&?/Y#A`3"#X),O@.$``#+C +M^O__&A[_+^&?/Y#A`3!#X),O@.$``#+C^O__&A[_+^&?/Y#A`3"#XI,O@.$` +M`#+C^O__&A[_+^&?/Y#A`3!#XI,O@.$``#+C^O__&A[_+^$`,*#AGP^3X0$` +M@."0+X/A```RX_K__QH>_R_A`#"@X9\/D^$!`$#@D"^#X0``,N/Z__\:'O\O +MX0`PH.&?#Y/A`0"`XI`O@^$``#+C^O__&A[_+^$`,*#AGP^3X0$`0.*0+X/A +M```RX_K__QH>_R_A\$$MZ0!0H.$!<*#A`F"@X1`PD.4``%/C&```"@@PD^4` +M`%/C%0``"@``4N,`0*#3$```VB"`@.(`0*#C$,"5Y04`H.$$$(?@!B!DX`@P +MH.$/X*#A"/"@``.#C\(&]Z!!`+>D"0*#A_O__ZP(`H.$#$*#A$("]Z!!`+>D"0*#A +M_O__ZP$`H.$`$*#C$("]Z'!`+>D`0*#A`5"@X0@`H.,!$*#C`2"@X?[__^L` +M`%#C`#"@$0!4HQ4$0(,5<("]Z!!`+>D`0*#A`0"@X0(0H.$#(*#A_O__ZP$* +M<.,`,*"#`#"$A0``A)4``*"3$("]Z!!`+>D`$*#C_O__ZP``H.,0@+WH\$("<*#A`#"@X0%0H.$``%#C``!1$Q5`X`,O```*!`"-X@,0H.%!(*#C +MMC$`X^#__^L`0%#B*```&@T@H.%_/<+C/S##XPB0D^4`(*#C"""#Y01@G>40 +M,);E`@!3X1<```H,,)/E`@!3X10```H`@%?B$P``VB"@AN($<*#A$,"6Y08` +MH.$'$(7@""!GX`HPH.$/X*#A#/"7!___K +MQ`_$X0C0C>+PA[WH\$$MZ0C03>("8*#A`#"@X0%0H.$``%#C``!1$Q5`X`,4 +M```*!`"-X@,0H.$`(*#C`C"@X:3__^L`0%#B#0``&@TPH.%_?4%$*#A!B"@X5[__^L`0*#A"("'Y00`G>6@___KQ`_$ +MX0C0C>+P@;WH<$`MZ0C03>(`$*#C`2"@X?[__^L`0*#A`0IPXP!0H($2``"* +M#2"@X7\]PN,_,,/C"&"3Y0`@H.,(((/E!Q"-X@$@H.-%___K`0!0XP10H!$` +M4*`##2"@X7\]PN,_,,/C"&"#Y00`H.$`$*#C_O__ZP$`=>(``*`S"-"-XG"` +MO>@00"WI`"``XP`@0.,`,0#C$#!`XP`@DN4#`%+A$("]"``@`.,`($#C`#(` +MXR`P0.,$()+E`P!2X1"`O0@```#C``!`X_[__^L0@+WH$$`MZ0`@`.,`($#C +M`#$`XQ`P0.,`()+E`P!2X1"`O0@`(`#C`"!`XP`R`.,@,$#C!""2Y0,`4N$0 +M@+T(````XP``0./^___K$("]Z!!`+>D`(`#C`"!`XP`Q`.,0,$#C`""2Y0,` +M4N$0@+T(`"``XP`@0.,`,@#C(#!`XP0@DN4#`%+A$("]"````.,``$#C_O__ +MZQ"`O>@00"WI````XP``0.,`$*#C`"``XP`@0./^___K$("]Z!!`+>G^___K +M$("]Z!!`+>G^___K$("]Z'!`+>D`0%#B<("]"+!5!N-F5D#C!0"@X?[__^L! +M0%3B^___&G"`O>@00"WI?0Y0XP$`H*/3/02S8C!!LY,@P[#`#Z"Q0P-@L`$` +M@++^___K$("]Z!!`+>G^___K$("]Z!!`+>ED,*#CDP``X-,M!.-B($'CDC#" +MX,`/H.%"`V#@``!0XP$`H`,-(*#A?SW"XS\PP^,,,)/E`2"@XP`@@^7^___K +M$("]Z!!`+>D-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^4`,)/E`@`3XQ"`O0C^ +M___K$("]Z!!`+>D-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^4`,)/E`@`3XQ"` +MO0C^___K$("]Z!!`+>D`$`#C`!!`XP0@G^7^___K$("]Z*`X```00"WI_O__ +MZP$`<.(``*`S$("]Z!!`+>G^___K$("]Z!!`+>D``%+C$("]"/[__^L0@+WH +M$$`MZ?[__^L!`'#B``"@,Q"`O>@00"WI_O__ZQ"`O>AP0"WI`$"@X0%@H.$( +M/`/C`U"0YP``4.,O```*##P#XP,`D.<``%#C`P``"O[__^L`(*#C##P#XP,@ +MA.?^___K``!0XP(``!H%`*#A_O__ZP(``.H%`*#A`!"@X_[__^L,/`/C`U"$ +MYP0`H.'^___K`%!0XA@```I@,)3E(#"#XC`RA>5@`)3E(`"`X@40H.'^___K +M!0"@X080H.'^___K=`&5Y0T;A.(1$('B!B"@X_[__^O^___K``!0XP(``!H% +M`*#A_O__ZP$``.H%`*#A_O__ZP``4.-P@+T(``#@XW"`O>@00"WI_O__ZQ"` +MO>@00"WID0("X`$1H.&3$B'@_O__ZQ"`O>@00"WI(!"@X_[__^L0@+WH<$`M +MZ0!0H.'^___K`$!0X@0```H``%7C`@``"@0`H.$%$*#A_O__ZP0`H.%P@+WH +M\$$MZ0!`H.$!4*#A`F"@X0!QH.&0`0#@DG`@X/[__^L`(*#A``!0X_"!O0@` +M`%3C!P``VI4&!>`'<(#@`#"@XP-Q@.@00"WI_O__ZQ"`O>@00"WI`$!0XA"`O0@`!)3E``!0XQ"`O0C^___K!`"@ +MX?[__^L0@+WH$$`MZ?[__^L0@+WH<$`MZ0!0H.'^___K`$!0X@0```H``%7C +M`@``"@0`H.$%$*#A_O__ZP0`H.%P@+WH\$$MZ0!`H.$(`*#C`1"@XP$@H.'^ +M___K`&!0XA$```H!>X;B!`"@X?[__^L`4*#A`("@X0``4.,#```*``!4XP$` +M``H$$*#A_O__ZP"`A^4``%7C!$"'%0(``!H&`*#A_O__ZP!@H.,&`*#A\(&] +MZ``$D.5(-0'C`R"0YRP\`^,#((#G"#8!XP,@D.,#()#G +M1#P#XP,@@.<0-@'C`R"0Y_$]H.,#((#G53V@XP,@D.D`0*#A_O__ZP$PH./4*P/C`C"$YZPL`^,",(3G +MY#8#XP,PE.<``%/C`@``"@0`H.$'$*#C,_\OX00`H.'^___K`""@X]0[`^,# +M((3G$("]Z'!`+>D`0*#A`#"@XZPL`^,",(#GS"L#XP(P@.?0*P/C`C"`Y]0K +M`^,",(#G`2"@XR0\`^,#((#G_O__ZP``4.,9```*#SN@XP,PE.<``%/C`0`` +M"@0`H.$S_R_A`%``XP!00.,`,)7ER",#XP(@E.=D$*#CD0(!X-,M!.-B($'C +MD@&!X,X-A.(4`(#B(1.#X/[__^L`$)7E4@Z$XGT?@>+^___K`0"@XW"`O>@` +M`*#C)#P#XP,`A.=P@+WH$$`MZ0!`H.'M/:#C#^"@X0/PD.<`,*#CL2P#XP(P +MQ.>R+`/C`C#$Y[,L`^,",,3G'B"@XU0DA.70(P/C`C"$Y]@C`^,",(3GDB,# +MXP(PQ.<``*#C`!"@XT@E`>/R`(3A""8!X_(`A.$8-<3E;""4Y2(MPN-L((3E +MS",#XP(PQ.?(.83E`#``XP`P0.,`,)/EW"8!XP(@E.=D$*#CD0(!X-,M!.-B +M($'CD@&!X%H-A.(H`(#B(1.#X/[__^L!`*#C$("]Z'!`+>D`0*#A_O__ZP0` +MH.'^___K!`"@X?[__^L`4*#AY#8#XP,PE.<``%/C`@``"@0`H.$#$*#C,_\O +MX04`H.%P@+WH<$`MZ0!`H.$(/`/C`U"0YRPZ`^,#,)#G``!3XPX```K=#8#B +M)`"`XO[__^O>#83B&`"`XO[__^O?#83B#`"`XO[__^LL.@/C`S"4YP``4^,` +M(*`3+#H#$P,@A!?R#83B-`"`XO[__^M]#H3B_O__ZP4+A.(H`(#B_O__ZU$- +MA.(P`(#B_O__ZVP`A.+^___K4PV$XB``@.+^___K6PV$XC@`@.+^___K5PV$ +MXA@`@.+^___K!`"@X?[__^L$`*#A$#L#XP_@H.$#\)3G##P#XP,`E.<``%#C +M`P``"O[__^L`(*#C##P#XP,@A.<``%7C`0``"@4`H.'^___K`0"@XW"`O>@0 +M0"WI`$"@X44.@.((`(#B_O__ZTD.A.($`(#B_O__ZU(.A.+^___K!`"@X?[_ +M_^O.#83B%`"`XO[__^O;#83B,`"`XO[__^M:#83B*`"`XO[__^L$`*#A_O__ +MZQ"`O>AP0"WI`$"@X68[`N,#(-#G/#4!XP,@P.=G.P+C`S#0YSTE`>,",,#G +M/B4!XP(PP.=J.P+CLR"0X30U`>,#((#G'C"@XU0T@.4!8*#C6&6`Y0!0H./< +M5(#E(#P!XP-0P.=X.P+C`R#0YR0\`>,#((#G>3L"XP,@T.,#4(#GS#@!XP-0@.?0.`'C`U"`YR0Y`>,#4(#G*#D!XP-@@.

,#8(#G_O__ZP0`H.'^___K!`"@X>T]H.,/X*#A`_"4Y[$\`^,#4,3G +MLCP#XP-0Q.>S/`/C`U#$YP8`H.%P@+WH<$`MZ0!`H.$%"X#B*`"`XO[__^L` +M`%#C,@``"FPT`>,#0(3G40V$XC``@.+^___K``!0XRL```H$`*#A_O__ZP`` +M4.,G```*!`"@X?[__^L$`*#A_O__ZP``4.,A```*4PV$XB``@.($$*#A_O__ +MZP``4.,;```*5PV$XA@`@.($$*#A_O__ZP``4.,5```*6PV$XC@`@.+^___K +M``!0XQ````H<.`'C`T"$YP0`H.'^___K!`"@X?[__^L$`*#A_O__ZP!0H.$$ +M`*#A_O__ZP0`H.'^___K\@V$XC0`@.+^___K````Z@!0H.,%`*#A<("]Z!!` +M+>D`0*#A!0N`XB@`@.+^___KZ#L#XP,PE.<``%/C$("]"`4+A.(T`(#B_O__ +MZQ"`O>@00"WI`$"@X0```.,``$#C!!"@X08LH./^___KZ#L#XP,`A.<``%#C +M``"@LQ"`O;@%"X3B-`"`XO[__^L!`*#C$("]Z'!`+>D`4*#A`$20Y0`P`.,` +M,$#C`#"3Y0$`4^,(```:`#``XP`P0.,`,)/E`0!3XP,```J0`I_E_O__ZP`` +MH.-P@+WH`#``XP`P0.,`(*#C`""#Y=0S`^,#,)3G`0!3XP(`H`&L/`,#`P"$ +M!W"`O0@D/`/C`S"4YP``4^,C```:S"L#XP(PA.?0*P/C`C"$Y]0K`^,",(3G +M!`"@X?[__^L``%#C<0``"@0`H.'^___K``!0XVT```H$`*#A_O__ZP``4.-I +M```*#SN@XP,PE.<``%/C`0``"@0`H.$S_R_A!`"@X?[__^OD-@/C`S"4YP`` +M4^,"```*!`"@X0,0H.,S_R_A`2"@XR0\`^,#((3G`""@XZP\`^,#((3G`#`` +MXP`P0.,`$)/E4@Z$XL@0@>+^___KA#,#XP,PU.<``%/C`P``&N(S`^,#,-3G +M``!3XQ````H`(*#CT#,#XP,@A.<`,`#C`#!`XP`PD^7((P/C`B"4YV00H..1 +M`@'@TRT$XV(@0>.2`8'@S@V$XA0`@.(A$X/@_O__Z[`AE>4",*#A"!"SY0$` +M$>,&```:`"`/X8``#/$`$)/E`1#!XP`0@^4"\"'A"0``Z@``#^&```SQ`!"3 +MY0'`P>,`P(/E`/`AX0$`$>,!```*!`"2Y?[__^O^___K"#P#XP,PE.=J/X/B +M`#"3Y0``4^,2```*````XP``0.,`$`#C`!!`X_[__^L`4%#B"P``"CT,A.(, +M`(#B=!&5Y08@H./^___K`"`/X8``#/$`,I7E`!"3Y0$00>(`$(/E`O`AX0$@ +MH.,D/0/C`R"$Y_[__^L``*#C<("]Z``@H.,D/`/C`R"$YP4`H.'^___KL#&5 +MY0``4^,&```:.`"?Y4H7`./^___K,`"?Y?[__^L``.#C<("]Z``@#^&```SQ +M"!"SY0$0@>,`$(/E`O`AX0``X.-P@+WH4"X``)`N``"L+@``$$`MZ0`P`.,` +M,$#C`2"@XP`@@^4``%'C`0``"O[__^L$``#J``20Y?[__^L!`%#C``"@`P`` +MX!,`,`#C`#!`XP`@H.,`((/E$("]Z!!`+>D`!)#E)#P#XP,PD.<``%/C!``` +M&@T+@.(1`(#B`A"!X@8@H./^___K``"@XQ"`O>CP02WI`!!0X@,```HX#0/C +M_O__ZP!PH.$"``#J.`T#X_[__^L`<*#A``!7XZD```H`1)?E"#P#XP-PA.<` +M,`#C`#!`X^`PA^5+/Z#CR#&'Y0`P`.,`,$#CV#"'Y0!@`.,`8$#C!""6Y3@[ +M`N,#(,3G`%``XP!00.,`()7E.3L"XP,@Q.<(();E.CL"XP,@Q.<,();E8#L" +MXP,@Q.>M#83B`!``XP`00.,#(*#C_O__ZP,@H.,\.P+C`R"$YP0@E>5A.P+C +M`R#$YP@@E>5B.P+C`R#$YPP@E>5F.P+C`R#$YQ`@E>5G.P+C`R#$YV@[`N.T +M(=7ALR"$X6H[`N.X(=7ALR"$X1P@E>5E.P+C`R#$YR`@E>5C.P+C`R#$YR0@ +ME>5L.P+C`R#$YQ`@EN5M.P+C`R#$YR@@E>5P.P+C`R#$YRP@E>5N.P+C`R#$ +MYS`@E>5O.P+C`R#$YS0@E>5D.P+C`R#$YS@@E>5Q.P+C`R#$YSP@E>5R.P+C +M`R#$YW0[`N.P)-7ALR"$X10@EN5V.P+C`R#$YQ@@EN5W.P+C`R#$YQP@EN5X +M.P+C`R#$YR`@EN5Y.P+C`R#$YR0@EN5Z.P+C`R#$YT0@E>5[.P+C`R#$YR@@ +MEN5\.P+C`R#$YRP@EN5].P+C`R#$YS`@EN5^.P+C`R#$YS0@EN5_.P+C`R#$ +MYS@@EN6N/:#C`R#$YSP@EN6!.P+C`R#$YT@@E>7Z/@+C`R#$YTP@E>7[/@+C +M`R#$YU`@E>7\/@+C`R#$YU0@E>7]/@+C`R#$YT`@EN7^/@+C`R#$YU@@E>7_ +M/@+C`R#$YUP@E>4O/*#C`R#$YT0@EN4!/P+C`R#$YT@@EN4"/P+C`R#$YV`@ +ME>4#/P+C`R#$YV0@E>4$/P+C`R#$YV@@E>4%/P+C`R#$YVP@E>4'/P+C`R#$ +MYTP@EN4(/P+C`R#$YW`@E>4)/P+C`R#$YW0@E>4*/P+C`R#$YP<`H.'P@;WH +M$$`MZ0!$D.61,P/C`S#4YP$`4^,%```:V#,#XP,PE.<"`%/C`2"@`]0S`P,# +M((0'`2"@XZP\`^,#((3GV#,#XP,PE.<``%/C&P``&@``4.,2```*L"&0Y0(P +MH.$($+/E`0`1XPT``!H``%+C!0``&BP!G^5*%P#C_O__ZR0!G^7^___K!0`` +MZ@`@#^&```SQ`!"3Y0$0@>,`$(/E`O`AX>0V`^,#,)3G``!3XP(```H$`*#A +M!Q"@XS/_+^$$`*#A_O__ZZ@\`^,#,)3G``!3XP(``!K0`)_E]Q<`X_[__^L` +M,)/E``!3XP(``!JX`)_E.1<`X_[__^LA(M/E`0!2XP`@H`,A(L,%!`"@X0`0 +MH./^___KJ#P#XP,PE.<``%/C`@``&H``G^7W%P#C_O__ZP``D^4``%#C`@`` +M&F@`G^4Y%P#C_O__ZP(,@.(!$*#C_O__ZZ@\`^,#,)3G``!3XP(``!I``)_E +M]Q<`X_[__^L`,)/E``!3XP(``!HH`)_E.1<`X_[__^L``*#C(P+#Y:@\`^,# +M,)3G!B"@XP0@@^40@+WHD"X``*PN``#T+@``$$`MZ0!`H.'^___K!`"@X?[_ +M_^L``*#C$("]Z!!`+>D4.P/C`S"0YP``4^,0@+T(,_\OX1"`O>@00"WI```` +MXP``0.,`$`#C`!!`X_[__^O^___K````XP``0.,`,*#C<#"`Y?[__^O^___K +M$("]Z!!`+>G^___K$("]Z!!`+>D`0*#A)#P#XP,PD.D@`(#B_O__ZP!0H.$`1)#E)#P#XP,PE.<``%/C +M2@``"LP[`^,#,)3G``!3XT8``!K0.P/C`S"4YP``4^-"```:``!4XP``X`-P +M@+T(`2"@XY(S`^,#(,3G!`"@X?[__^L$`*#A_O__ZS-LA.(,8(;B!@"@X?[_ +M_^L``%7C$```"@4`H.'^___KL#&5Y0``4^,%```:N`"?Y4H7`./^___KL`"? +MY?[__^L%``#J`"`/X8``#/$($+/E`1"!XP`0@^4"\"'A!`"@X0`0H./^___K +M;#"4Y0@`$^,"```*`0`3XP$PH!-R,,05!`"@X?[__^L$`*#A`1"@X_[__^L$ +M`*#A`1"@X_[__^L$`*#AF?__ZP8`H.'^___K;#"4Y0(+$^,"```*!`"@X0$0 +MH./^___K;#"4Y8``$^,#```*!`"@X?[__^L``*#C<("]Z```H.-P@+WHC"\` +M`*@O``#P02WI`%"@X2!@@.(&`*#A_O__ZP!PH.$`1)#E!@"@X0`0H./^___K +M``!4XSX```JH/`/C`X"4YS,,A.(,`(#B_O__ZP0`H.'^___K;#"4Y0$`$^," +M```*!`"@X0`0H./^___K`#``XP`P0.-P,)/E`0!3XP$@H`/0.P,#`R"$!P0` +MH.'^___K`#"4Y0$`4^,#```*``!7XP$```H'`*#A_O__ZP0`H.'^___K!`"@ +MX5G__^LA,-3E`@!3XP%@H!,#```:(Y0$`5N,`8*`3`6"@`_P[`^,#,)3G +M``!3XP$```H$`*#A,_\OX00`H.'^___K"`"@X?[__^L@`)7E:`!`XO[__^L! +M`%;C\(&]&"``E>5H`$#B&#"0Y0``4^/P@;T(_O__Z_"!O>@@`)7E:`!`XO[_ +M_^OP@;WH$$`MZ0!`H.$8.P/C`S"0YP``4^,````*,_\OX00`H.'^___K$("] +MZ!!`+>D```#C``!`XP`0`.,`$$#C_O__ZP`P`.,`,$#C`$"@XP!`@^7^___K +M_O__Z_[__^L```#C``!`XP$PH.-P,(#E!!"@X0`@`.,`($#C_O__ZQ"`O>@0 +M0"WI_O__ZQ"`O>AP0"WI`$!0XB0```H(/`/C`V"4YS-@0 +M0"WI(`"`XO[__^L`!)#E`#``XP`P0.,!(*#C`""#Y9$S`^,#,-#G``!3XP$` +M``K^___K$("]Z`0T`^,#,)#G``!3XP0```H!(*#C##0#XP,@P.<``*#C$("] +MZ/[__^L0@+WH<$`MZ0!`H.%@`)#E(`"`XO[__^L``%3C``#@`W"`O0@`4*#A +M,VR$X@Q@AN(&`*#A_O__ZP$@H./0,P/C`R"$YP0`H.'^___K!0"@X0`0H./^ +M___K``!0XP,```H&`*#A_O__ZP``X.-P@+WH!0"@X?[__^L%`*#A_O__Z[`A +ME>4",*#A"!"SY0$`$>,&```:`"`/X8``#/$`$)/E`1#!XP`0@^4"\"'A"0`` +MZ@``#^&```SQ`!"3Y0'`P>,`P(/E`/`AX0$`$>,!```*!`"2Y?[__^L`4*#C +MXS,#XP-0Q.?D,P/C`U#$Y]@S`^,#4(3GT#,#XP-0A.<&`*#A_O__ZP4`H.%P +M@+WH<$`MZ0!`H.%@`)#E(`"`XO[__^LD/`/C`S"4YP``4^--```*S#L#XP,P +ME.<``%/C20``&M`[`^,#,)3G``!3XT4``!H``%3C0P``"@!0H.$$`*#A_O__ +MZS-LA.(,8(;B!@"@X?[__^L!(*#CT#,#XP,@A.<``%7C$```"@4`H.'^___K +ML#&5Y0``4^,%```:S`"?Y4H7`./^___KQ`"?Y?[__^L%``#J`"`/X8``#/$( +M$+/E`1"!XP`0@^4"\"'A!`"@X0`0H./^___K;#"4Y0$`$^,.```*`3##XVPP +MA.7D-@/C`S"4YP``4^,"```*!`"@X0,0H.,S_R_A!`"@X?[__^L$`*#A`Q"@ +MXP`@H./^___K!`"@X0$0H./^___K!`"@X0$0H./^___K!`"@X?[__^L"(*#C +MV#,#XP,@A.<`4*#C"#!#X@-0A.<&`*#A_O__ZP4`H.%P@+WH``#@XW"`O>B, +M+P``J"\``!!`+>D`0*#A7#"0Y0``4^,"```*6`"0Y0X1`./^___K3`"$XO[_ +M_^L!`*#C$("]Z!!`+>G^___K$("]Z/!'+>D`8*#A`4"@X2``D.5H`$#B_O__ +MZP`PH.,`$`#C`!!`XP`@`.,"<*#A`'!`XP-0H.$`(`#C`H"@X0"`0.,`(`#C +M`J"@X0"@0.,#(('@ML#2X0/@D>>T`-+ALB#4X0(`4.$&```:M"#4X0P`4N$# +M```:`@`>XP!0AQ4`4(@5`%"*%0@P@^(P`%/C[O__&@``H./^___K`'!0XE@` +M``H@@(;B,(*'Y0!$E^4!4*#CS#L#XP-0A.<<0(3E8&"$Y2`PEN5H,$/B9#"$ +MY00`H.$($*#A_O__ZP@`H.$'$*#A_O__Z[A1Q.$`,*#CM#'$X00`H.'^___K +M!`"@X?[__^L`(`#C^#L#XP`@0.,#((3G`"``X_P[`^,`($#C`R"$YP`@`.,/ +M.Z#C`"!`XP,@A.<`(`#C!#P#XP`@0.,#((3G!`"@X50``.L%`%#A-@``&@0` +MH.'^___K!`"@X?[__^L``%#C,```"I,S`^,#,-3G``!3XPD```ID,)3E_"+3 +MY04@@N'\(L/E&##6Y0@P@^,8,,;E"`"@X040H.'^___K!P"@X;`PG^4`$)/E +M_O__ZPU;A.(14(7B!0"@X?[__^MT`9?E!1"@X08@H./^___KB#"?Y0@`D^4` +M`%#C`P``"O[__^L,$*#C`2"@X_[__^L'`*#A_O__ZP``4./PA[T("0``ZB`` +MMN5H`$#B_O__ZP8`H.$`$*#C_O__ZP``H.-S___K$@#@X_"'O>@@`);E:`!` +MXO[__^L(`*#A`!"@X_[__^L$`*#A:?__ZP<`H.'^___K$@#@X_"'O>@````` +M_#@``!!`+>D`0*#A3`"`XO[__^L.`0#C_O__ZU@`A.4``%#C6`"$!0\`@!(/ +M`,`37`"$%0$`H!,0@+WH\$$MZ0!`H.%D8)#E8""0Y1P`A.4`,*#C)##`Y24P +MP.4`X)+EP#&6Y00PT^4A,,#E`C#>Y2`PP.4$4-[E(E#`Y0``5>,B``#:`#"@ +MXP,@H.$,$)[E`Q"1X!@```H#P-'E`\`,X@(`7.,T```:TG#1X0``5^,S``"J +M),#4Y0'`C.(DP,3E"@``ZM+`T>$``%SC),#4M0'`C+(DP,2U!```ZM+`T>$` +M`%SC)<#4I0'`C*(EP,2E`A#1Y0\0`>(H$(#E`2""XBPP@^($`(#B!0!2X=[_ +M_[H<,);E`P!3XP$PH`,`,*`3(S#$Y00`H.'^___K`%"@X00`H.'^___K``!0 +MXP!0H`,!```*`%!5X@%0H!-``(3B`!"@X_[__^L$`*#A_O__ZP0`H.'^___K +M:`"$X@`0H./^___K!0"@X?"!O>@#`%SCS___"@(`7./8__\:TO__ZC`P0.)S +M,._F"0!3XS``0)(>_R^183!`XG,P[^8%`%/C5P!`DA[_+Y%!,$#B,"`(/G`A"@ +MXS`L`>,"$(/G`Q"@X\@H`>,"$(/G'O\OX0(`$>,(```*``"@XS0L`>,"`(/G +M`2"@XS`<`>,!((/GR!@!XP$@@^<>_R_A`0`1XPD```HP+`'C`B"3YP,`4N,( +M``"*``"@XS`L`>,"`(/GR"@!XP(`@^<>_R_A!``1XQ4`X`,>_R\!``"@XQ[_ +M+^$``*#C'O\OX0`TD.5L,)/E"``3XP(PH!,`,((5"@``&D``$^,!```:(``3 +MXP(```H!,*#C`#""Y0,``.H0`!/C`S"@$P`PH`,`,(+E``"@XQ[_+^$``*#C +M``""Y00`PN4!,*#C!3#"Y1[_+^$`%)#E:#L"X[,PD>$`,(+E``"@XP0`PN4> +M_R_A`!20Y04PTN4``%/C!```"BHI`.,T-0'C`R"!YP``H.,>_R_A`#"2Y0$, +M0^(J*`#C`@!0X14`X(,!,,.3-"4!DP(P@9<``*"3'O\OX0`4D.4T-0'C`S"1 +MYP`P@N4``*#C!`#"Y1[_+^$',*#C`#""Y0``H.,$`,+E`3"@XP4PPN4>_R_A +M``"@XP``@N4$`,+E`3"@XP4PPN4>_R_A$$`MZ0C03>(`Q)#E#@"3Z``PC>4, +M`*#A_S\/XP\P0..H2P/C#^"@X03PG.<``*#C"-"-XA"`O>@``.#C'O\OX0`` +MX.,>_R_A``"@XQ[_+^$``*#C'O\OX0``H.,>_R_A``"@XQ[_+^$`-)#ES!L# +MXP$0D^<"`*#A`2!RX@`@H#,``%'C`A"@`0$0@A,``%'C%0#@$Q[_+Q$`()#E +M`@!2XP``H(,",8.0!!"PE000@Y4`,`"3`#!`DP`0D)4"$8.7``"@DQ[_+^$> +M_R_A'O\OX?!'+>D(T$WB`%"@X100H.,'((WB:#L#XP_@H.$#\)#G!S#=Y0,` +M4^,``%,3`:"@`P*@H!,`8*#C!I"@X:1[`^,`@.#C"P``Z@4`H.$&$*#A!""@ +MX0@PH.$/X*#A!_"5YP%`A.(!#%3C]O__&@%@AN(*`%;A`0``J@E`H.'Q___J +M"-"-XO"'O>@``*#C'O\OX0`$D.5L,)#E`0`3XP<``!H`,*#CABP#XP(PP.>' +M+`/C`C#`YX@L`^,",,#G#@``ZITV`>,#$-#GGC8!XP,@T.><-@'C`\#0YP'` +MC.*LP*#A7\!,XH<\`^,#P,#GACP#XP,0P.>(/`/C`R#`YP\@H..)/`/C`R#` +MY_(-@.($`(#B'O\OX7!`+>D(T$WB`F"@X;1`TN$$`*#A_O__ZP!04.(+`.`# +M+```"@`0EN4-(*#A?SW"XS\PP^,(,)/E!""1X`,@TC``,*`S``!3XP4``!H% +M`*#A!""@X?[__^L``%#C"@``"@0``.H``%3C!P``"@4`H.$$$*#A_O__ZP4` +MH.$$$*#A_O__ZPT`X.,2``#J"`"-X@10(.4`$`#C`!!`X_[__^L``%#C`@`` +M"@`PT.4``%/C!```&@4`H.$$$*#A_O__ZPT`X.,#``#J!0"@X000H.'^___K +M``"@XPC0C>)P@+WH<$`MZ0C03>(#8*#A`%20Y0)`H.$`,*#C!#"-Y0`0DN4- +M(*#A?SW"XS\PP^,(,)/E!""1X@,@TC``,*`S``!3XP,``!H$`(WB!""@X_[_ +M_^L"``#J!`"-X@00H./^___KS#L#XP,PE>4!`%/C"```&N0V`^,#,)7G +M``!3XQH```H%`*#A"1"@XS/_+^$``*#C%@``Z@(`4^,(```:Y#8#XP,PE><` +M`%/C#P``"@4`H.$*$*#C,_\OX0``H.,+``#J`P!3XP@``!KD-@/C`S"5YP`` +M4^,$```*!0"@X0P0H.,S_R_A``"@XP```.H``*#C"-"-XG"`O>AP0"WI`T"@ +MX0#$D.4,`*#A!@"3Z/\_#^,/,$#CI%L#XP_@H.$%\)SG`""@X00`H.$`$`#C +M`!!`X_[__^L``*#C<("]Z/!/+>DTT$WB`T"@X0`PH..Z,4D8(WE,*"-X@1`*N4$``#J#`!6XP<```H< +M((WB!@""YP1@AN(*`*#A)!N?Y?[__^L``%#C]?__&@B`C>4<8)WE!@"@X0`0 +M`.,`$$#C_O__ZP``4.,_```:!0"@X0`0H.,!+*#C"("=Y68^B.+^___K``!0 +MXZ\"``H$`*#AU!J?Y0(@H./^___K`#"@XPPPC>4`H`#C`*!`XPS`G>40P(WE +M!`"@X;`:G^4$(*#A##"@X?[__^L`4*#C#`"=Y0!@B.`%,(;@!`"@X0H0H.$$ +M(*#A8#;3Y?[__^L!4(7B"`!5X_;__QH$`*#A +M@N((,)WE!5"#X`A@H.,$`*#A"A"@X00@H.$(,-7E_O__ZP%@AN)V8/_F`5"% +MXA``5N/U__\:!`"@X2@:G^4$(*#A_O__ZPS`G>40P(SB#,"-Y0$,7./0__\: +M=0(`Z@8`H.$`$`#C`!!`X_[__^L``%#C,0``&B``G>4``%#C:@(`"B1@G>4` +M`%;C9P(`"BB`C>(($*#A$""@X_[__^L`H*#A!@"@X0@0H.$*(*#C_O__ZW!@ +M_^8``%;C6P(`"GJ`_^8`$*#C`!"-Y04`H.$#(*#C&C"-XO[__^L(((;@NC'= +MX0,`4N%0`@#*!0"@X0@0H.$&(*#A"3"@X?[__^L``%#C30(`"@!0H.,`4,3E +M6(F?Y04``.H$`*#A"!"@X00@H.$%,-GG_O__ZP%0A>)U,/_F`P!6X?;__XH] +M`@#J!@"@X0`0`.,`$$#C_O__ZP``4.,G```:`+"-Y04`H.$`$*#C`2"@X0(\ +MH./^___K``!0XS$"``H$`*#AW!B?Y0(@H./^___K`%"@X^!HG^7@B)_ES*B? +MY00`H.$&$*#A!""@X04PV^?^___K#R`%X@\`4N,$```:!`"@X:@8G^4$(*#A +M_O__ZP8``.H',`7B!P!3XP0`H.$*$*`!"!"@$00@H.'^___K`5"%X@(,5>/H +M__\:#P(`Z@8`H.$`$`#C`!!`X_[__^L``%#C(P``&@`0H.,`$(WE!0"@X0,@ +MH.,:,(WB_O__Z[HQW>$%`%/C`@(`V@4`H.$`$*#C!B"@XPDPH.'^___K``!0 +MX_L!``H`4*#C`%#$Y11HG^48B)_E!`"@X080H.$$(*#A!3#9Y_[__^MU,/_F +M!0!3XP,```H$`*#A"!"@X00@H.'^___K`5"%X@8`5>/P__\:Y0$`Z@8`H.$` +M$`#C`!!`X_[__^L``%#C(P``&@`0H.,`$(WE!0"@X0,@H.,:,(WB_O__Z[HQ +MW>$#`%/CV`$`V@4`H.$`$*#C!""@XPDPH.'^___K``!0X]$!``H`4*#C`%#$ +MY7AGG^5XAY_E!`"@X080H.$$(*#A!3#9Y_[__^MU,/_F`P!3XP,```H$`*#A +M"!"@X00@H.'^___K`5"%X@0`5>/P__\:NP$`Z@8`H.$`$`#C`!!`X_[__^L` +M`%#C#```&@4`H.$8$(WB_O__ZP4`H.'^___KN"'=X0`@8N`$`*#A`!``XP`0 +M0./^___K`%"@XZL!`.H&`*#A`!``XP`00./^___K``!0XT```!H(`)WEYCZ` +MX@4`H.$`$*#C`2N@XP,P@^+^___K``!0XYL!``H$`*#AA!:?Y0(@H./^___K +M`""@XPP@C>4`H`#C`*!`XPPPG>40,(WE!`"@X806G^4$(*#A_O__ZP!0H.,, +MP)WE#&"(X`4PAN`$`*#A"A"@X00@H.%C/M/E_O__ZP%0A>((`%7C]O__&@0` +MH.$D%I_E!""@X?[__^L0`)WEYEZ`X@@@G>4%4(+@`U"%X@A@H.,$`*#A"A"@ +MX00@H.$(,-7E_O__ZP%@AN)V8/_F`5"%XA``5N/U__\:!`"@X=@5G^4$(*#A +M_O__ZPPPG>40,(/B##"-Y0(,4^/0__\:80$`Z@8`H.$`$`#C`!!`X_[__^L` +M`%#C0```&@C`G>7F/HSB!0"@X0`0H.,!*Z#C`S"#XO[__^L``%#C5`$`"@0` +MH.%H%9_E`B"@X_[__^L(`)WE`JR`X@(LH.,,((WE`(``XP"`0.,,8)WE!`"@ +MX605G^4$(*#A!C"@X?[__^L`4*#C!3"*X`0`H.$($*#A!""@X6,^T^7^___K +M`5"%X@@`5>/V__\:!`"@X0@5G^4$(*#A_O__Z^9>AN((,)WE!5"#X`-0A>(( +M8*#C!`"@X0@0H.$$(*#A"##5Y?[__^L!8(;B=F#_Y@%0A>(0`%;C]?__&@0` +MH.'`%)_E!""@X?[__^L,P)WE$,",X@S`C>40H(KB`0MH#_Y@`PH.,`,(WE!0"@X0$0H.,#(*#C&C"-XO[__^L(((;@NC'=X0,` +M4N'X``#*!0"@X0@0H.$&(*#A"3"@X?[__^L``%#C\0``"@!0H.,`4,3E!(2? +MY04``.H$`*#A"!"@X00@H.$%,-GG_O__ZP%0A>)U,/_F!@!3X?;__SKA``#J +M!@"@X0`0`.,`$$#C_O__ZP``4.,]```:!`"@X0`0`.,`$$#C`B"@X_[__^L` +M4*#C`*``XP"@0.,,L(WE$)"-Y0BPG>4(<(WE!7"@X0B0H.$'@*#A!`"@X7@3 +MG^4$(*#A!S"@X?[__^L`4*#C!V")X`4PAN"!/8/B)C"#X@0`H.$*$*#A!""@ +MX0`PT^7^___K`5"%X@@`5>/T__\:!`"@X1`3G^4$(*#A_O__ZPA0B^"!787B +M)E"%X@A@H.,$`*#A"A"@X00@H.$(,-7E_O__ZP%@AN)V8/_F`5"%XA``5N/U +M__\:!`"@X40D)WE"'"=Y9T` +M`.H&`*#A`!``XP`00./^___K``!0XSX``!H$`*#A`!``XP`00.,"(*#C_O__ +MZP@`G>4"K(#B`ER@XP"``.,`@$#C#+"-Y1"0C>4`D*#A!["@X05PH.$'8*#A +M!`"@X602G^4$(*#A!S"@X?[__^L`4*#C!3"*X($]@^(F,(/B!`"@X0@0H.$$ +M(*#A`##3Y?[__^L!4(7B"`!5X_3__QH$`*#A`!*?Y00@H.'^___K!E")X(%= +MA>(F4(7B"&"@XP0`H.$($*#A!""@X0@PU>7^___K`6"&XG9@_^8!4(7B$`!6 +MX_7__QH$`*#AO!&?Y00@H.'^___K$'"'XA"@BN(!"U?CT___&A"0G>4+<*#A +M#+"=Y5@``.H&`*#A`!``XP`00./^___K``!0XSX``!H$`*#A`!``XP`00.," +M(*#C_O__ZP!@H.,`,`#C`U"@X0!00.,`H`#C`*!`XPRPC>40D(WE%'"-Y0BP +MH.$&@*#A!7"@X0B0H.$$`*#A)!&?Y00@H.$(,*#A_O__ZP!0H.,(8(O@!3"& +MX`0`H.$'$*#A!""@X6`WT^7^___K`5"%X@@`5>/V__\:!`"@X>@0G^4$(*#A +M_O__ZW9>B>((()WE!5""X`A@H.,$`*#A"A"@X00@H.$(,-7E_O__ZP%@AN)V +M8/_F`5"%XA``5N/U__\:!`"@X:00G^4$(*#A_O__ZQ"`B.(!#%CCU?__&@RP +MG>40D)WE%'"=Y1,``.H$`*#A`!``XP`00.,3(*#C_O__ZP!0H.,/``#J"P"@ +MX0$;H./^___K``!5XP(``!H$`*#A_O__Z[0`Q^$%`*#A--"-XO"/O>@54.#C +M`@``Z@!0H.,```#J#5#@XPD`H.$!&Z#C_O__ZP``6^/J__\:[/__Z@`P```4 +M,```&#```"PP```P,```/#```%`P``!8,```8#```&PP``!X,```K#```,@P +M``#P3RWI+-!-X@.`H.$`,*#CLC'-X0!DD.4[/*#C`Z"6YP$+H./^___K`'!0 +MX@!`H`,+8.`#!%"@`:X!``H!"Z#C_O__ZP"04.(+8.`#`%"@`P5`H`&Y`0`* +M`0R@X_[__^L`0%#B"V#@`P!0H`.S`0`*`@R@X_[__^L`4%#B"V#@`ZX!``H` +M,*#C%#"-Y1@PC>4<,(WE*+"-X@2`*^4#@*#A!```Z@P`6.,'```*%#"-X@@` +M@^<$@(CB"P"@X906G^7^___K``!0X_7__QH4@)WE"`"@X8`6G^7^___K``!0 +MXRX``!H8`)WE``!0XXX!``H<@)WE``!8XXL!``H@$(WB$""@X_[__^L,`(WE +M"`"@X?[__^MP`/_F`0`0XX(!`!J@L+#A`*"@$W\!``H$``#J`@!8Y0$06.7^ +M___K"@#'YP&@BN("@(CB"P!:X??__SH,,)WE4``%CC+P$`"@@`H.'^___K +M<`#_Y@$`$.,J`0`:H+"PX2@!``H&`%OC`*"@DRD!`(H$``#J`@!8Y0$06.7^ +M___K"@#'YP&@BN("@(CB"P!:X??__SH`$*#C`!"-Y08`H.$#(*#C$C"-XO[_ +M_^NR,=WA`P!;X1T` +M`,H&`*#A`!"@XPL@H.$',*#A_O__ZP``4./D```:Y0``Z@@`H.&\$Y_E_O__ +MZP``4.,P```:&`"=Y0``4./9```*'("=Y0``6./6```*(!"-XA`@H./^___K +M#`"-Y0@`H.'^___K<`#_Y@$`$./-```:H+"PX0"@H!/*```*!```Z@(`6.4! +M$%CE_O__ZPH`Q^4&`*#A`1"@XP,@H.,2,(WB_O__ZP@@B^"R,=WA`P!2X;<``,H&`*#A"!"@ +MX0L@H.$',*#A_O__ZP``4..N```:KP``Z@@`H.'H$I_E_O__ZP``4.,A```: +M&`"=Y0``4..C```*'&"=Y0``5N.@```*(!"-XA`@H./^___K``J@X2`*H.$, +M`(WE!@"@X?[__^MP`/_F`0`0XY4``!J@L+#A`("@$PPPG14#H(H0!P``&H\` +M`.H"`%;E`1!6Y?[__^L(,(K@@3V#XB8`P^4!@(CB`F"&X@L`6.'U__\ZA@`` +MZ@@`H.%0$I_E_O__ZP``4.,(```:@3V*X@8`H.$`$*#C`2N@XR8P@^+^___K +M`0!0XWD```IZ``#J"`"@X1P2G^7^___K``!0XP<``!H&`*#A`!"@XP$KH.-V +M/HKB_O__ZP$`4.-L```*;0``Z@@`H.'L$9_E_O__ZP``4.,8```:20V*XH$= +MBN(C`(#B)A"!X@$KH./^___K`#"@XP`PC>4&`*#A`1"@XP,@H.,2,(WB_O__ +MZ[(QW>$``%/C6```"H$]BN(&`*#A`!"@XP$KH.,F,(/B_O__ZP``4.-.```: +M3P``Z@@`H.%X$9_E_O__ZP``4.,0```:`!"@XP`0C>4&`*#A`R"@XQ(PC>+^ +M___KLC'=X0``4^-!```*!@"@X0`0H.,!+*#C=CZ*XO[__^L``%#C.```&CD` +M`.H(`*#A)!&?Y?[__^L``%#C,@``&A@`G>4``%#C+0``"AQ@G>4``%;C*@`` +M"B`0C>(0(*#C_O__ZP`*H.$@"J#A#`"-Y08`H.'^___K<`#_Y@$`$.,?```: +MH+"PX0"`H!,,,)T5`Z"*$`8``!H9``#J`@!6Y0$05N7^___K"#"*X&`'P^4! +M@(CB`F"&X@L`6.'V__\Z$0``Z@D`H.$!&Z#C_O__ZP``5.,"```*!`"@X0$< +MH./^___K``!5XP(```H%`*#A`AR@X_[__^L&`*#A+-"-XO"/O>@58.#C`@`` +MZ@!@H.,```#J#6#@XP<`H.$!&Z#C_O__ZP``6>/E__\:Y___Z@`P```,,0`` +M%#$``%PP``!D,```'#$``"0Q```L,0``.#$``$0Q``!0,0``7#$``'!`+>D" +M0*#A`%20Y6P@E>4!`!+C"```&D``$N,&```:``"@X[0`Q.&V,-3A@SC@X:,X +MX.&V,,3A<("]Z`8@U.4``%+C!```"@0`4N,5`."#`2!"D@(``)IP@+WHT"@! +MXP(@E>,!\9^7-P``ZIB7!`"`EP0` +M1)@$`("7!``LF`0`1)@$`"R8!````*#CM`#$X8S(X.&LR.#AML#$X7"`O>@9 +M'8+B!!"!X@$1A>"T$-'AM!#$X0``4>,7```*8Q^"X@$0@>(!$H7@&2V"X@0@ +M@N("(87@`P"@X000@>($()+E_O__Z[8@U.&V(,3A,#P!XP,PE><``%/C`BJ" +M`[8@Q`$``*`#<("]"`$`4^,!*8(#MB#$`0``H.-P@+WH``"@X[0`Q.&,R.#A +MK,C@X;;`Q.%P@+WH$#"@X[0PQ.$*RXSCML#$X0``H.-P@+WH``"@X[0`Q.&, +MR.#AK,C@X;;`Q.%P@+WH$$`MZ0``4^('```*#L"@X[3`PN$!,*#CMC#"X0`0 +M`.,`$$#C#""@X?[__^L``*#C$("]Z!!`+>D"0*#A`!20Y6P@D>4!`!+C`@`` +M&D``$N,``.`#$("]".@@D>6T(,3A`P"@X>P0@>+^___K`3"@X[8PQ.$``*#C +M$("]Z/!`+>D4T$WB`E"@X0!$D.40/`/C`S#4YP``4^,)```:`#``XP`P0.,/ +M"X3B$`"`X@`0D^40(*#C_O__ZP`@H.,?/`/C`R#$Y[0PU>$0`%/C6P``B@`0 +ME>4-(*#A?SW"XS\PP^,(,)/E$""1X@,@TC``,*`S``!3XP4``!H-`*#A$""@ +MX_[__^L``%#C!0``"DL``.H-`*#A$!"@X_[__^L-4.#C1P``Z@]KA.(08(;B +M!@"@X0T0H.'^___K``!0XP!0H`,_```*!`"@X0T0H.'^___K`%!0XCH``!H/ +M"X3B$`"`X@`0`.,`$$#C"2"@X_[__^L!`%#C"@``&B$\`^,#(-3G%3U#X@$P +M0^(#(,3G!`"@X?[__^L@/`/C`R#4YX$S`^,#(,3G#7"@X08`H.$-$*#A$""@ +MX_[__^L`(*#C'SP#XP,@Q.<-`*#A`!``XP`00.,)(*#C_O__ZP$`4.,8```: +M!`"@X0$0H./^___KY#8#XP,PE.<``%/C`@``"@0`H.$'$*#C,_\OX>`V`^,# +M$-3G(2P#XP(0Q.<`8*#C`V#$YP0`H.'^___K@3,#XP,0U.<@+`/C`A#$YP-@ +MQ.<```#J#5#@XP4`H.$4T(WB\("]Z/!'+>E0T$WB`%"@X0*@H.$#0*#A`P"@ +MX0`0`.,`$$#C!B"@X_[__^L``%#C<```"K0PVN$&,$/BM##*X0:0A.(`=)7E +M`&"@XSQ@C>6P9,WA*#"-X@1@@^0$8(/D!&"#Y`1@@^0`8,/E*$"-X@0`H.$) +M$*#A$2"@X_[__^L\4(WB``#4Y0$0U.7^___K!@#%YP%@AN(#0(3B!@!6X_?_ +M_QK^___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/EA%"'XH1`E^4\8(WB!G"@ +MXP4`H.$$$*#A_O__ZP$`4.,M```*!("@X2``A.(&$*#A!R"@X?[__^L``%#C +M)```"@`@H.-$((WEOB3-X4@@C>60$)3EH`"$X@P00>)$,(WB_O__ZP``4.,; +M```*2#"-X@`PC>5$$)WE""`!XTXPC>+^___K2#"=Y0``4^,2```*OB3=X;(O +MO^9R(/_FOB3-X0D`H.$`$`#C`!!`X_[__^L``)KE"1"@X0@@H./^___K`#": +MY0`@H.,((,/E`4"@XP(``.H`0)3ES/__Z@!`H.,-(*#A?SW"XS\PP^,$()/E +M`2!"X@0@@^7^___K``!4XXP``!H)`*#A`!``XP`00.,)(*#C_O__ZP``FN4) +M$*#A"""@X_[__^L`,)KE`""@XP@@P^5_``#J!`"@X0`0`.,`$$#C!2"@X_[_ +M_^L``%#C>```"K0PVN$%,$/BM##*X060A.(`=)7E`&"@XSQ@C>6P9,WA*#"- +MX@1@@^0$8(/D!&"#Y`1@@^0`8,/E*$"-X@0`H.$)$*#A$2"@X_[__^L\4(WB +M``#4Y0$0U.7^___K!@#%YP%@AN(#0(3B!@!6X_?__QK^___K#2"@X7\]PN,_ +M,,/C!""3Y0$@@N($((/EA%"'XH1`E^4\8(WB!G"@XP4`H.$$$*#A_O__ZP$` +M4.,V```*!("@X2``A.(&$*#A!R"@X?[__^L``%#C+0``"@`@H.-(((WE"#"- +MX@0@@^0$((/D!""#Y`0@@^0$((/D!""#Y`0@@^0`((/E1""-Y9`0E.6@`(3B +M#!!!XD@PC>+^___K``!0XQP```I$,(WB`#"-Y4@0G>41(`'C"#"-XO[__^M$ +M,)WE``!3XQ,```H)`*#A`!``XP`00.,(((WB_O__ZP``FN4)$*#A1""=Y00@ +M@N+^___K`"":Y40PG>4#,(+@!#"#X@`@H.,`(,/E`4"@XP(``.H`0)3EP___ +MZ@!`H.,-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K``!4XPL``!H)`*#A +M`!``XP`00.,)(*#C_O__ZP``FN4)$*#A"""@X_[__^L`,)KE`""@XP@@P^4` +M`*#C4-"-XO"'O>CP0"WI%-!-X@!@H.$"0*#A`U"@X0``DN4`$`#C`!!`XP8@ +MH./^___K``!0XQ,```H`9);E+'H#XP4`H.$`$`#C`!!`XP<@EN?^___K!0"@ +MX?[__^NT`,3A!S"6YP(`4^-I```:!@"@X>D]H.,#$-;G`""@XP(PH.'^___K +M8@``Z@``E.4`$`#C`!!`XP0@H./^___K``!0XPH```H`));E!0"@X0`0`.,` +M$$#C)#H#XP,@DN?^___K!0"@X?[__^NT`,3A4```Z@``E.4`$`#C`!!`XP@@ +MH./^___K``!0XQ@```H`%);E4SH#XP,@T>=4.@/C`S#1YU4*`^,``-'G``"- +MY58*`^,``-'G!`"-Y5<*`^,``-'G"`"-Y5@*`^,`$-'G#!"-Y04`H.$`$`#C +M`!!`X_[__^L%`*#A_O__Z[0`Q.$P``#J``"4Y0`0`.,`$$#C!B"@X_[__^L` +M`%#C"@``"@`DEN4%`*#A`!``XP`00./A+8+B`B""XO[__^L%`*#A_O__Z[0` +MQ.$>``#J``"4Y0`0`.,`$$#C"2"@X_[__^L``%#C%P``"@`4EN4\.`/C`R#1 +MYSTX`^,#,-'G/@@#XP``T><``(WE/P@#XP``T><$`(WEX0V@XP``T><(`(WE +M00@#XP`0T><,$(WE!0"@X0`0`.,`$$#C_O__ZP4`H.'^___KM`#$X0``H.,4 +MT(WB\("]Z/!%+>D4T$WB`$20Y0-@H.$`,*#C"#"-Y;PPS>$`,(WEM##-X0T` +MH.$&$(;B!B"@X_[__^L`,);E`0!3XRH``!H-`*#A"!"-X@8@H./^___K`0!0 +MXU````H`4*#C#7"@X0:`H.,%H*#A!0.$X"<,@.(Q`(#B#1"@X0@@H.'^___K +M`0!0XP\``!H%HZ#A"@"$X"<,@.(W`(#B%!"&XA`@H./^___K"J"$X">LBN(P +MH(KB`0"@XP``RN4`4(7@,#L"XP-0Q./C__\:-0``Z@`@ +MH.,P.P+C`R#$YP$`H.,N``#J`@!3XQT``!H`4*#C#6"@X09PH.,%@*#A!0.$ +MX"<,@.(Q`(#B#1"@X0<@H.'^___K`0!0XPT``!H%@Z#A"`"$X"<,@.(Q`(#B +M`!"@XP8@H./^___K"$"$X"=,A.(P0(3B`#"@XP`PQ.4!`*#C$@``Z@%0A>(0 +M`%7CY?__&@T``.H#`%/C"0``&B<,A.(P`(#B`!"@XP$KH./^___K`""@XS`[ +M`N,#(,3G`0"@XP(``.H``*#C````Z@$`H.,4T(WB\(6]Z#!;`N,%`-3G``.$ +MX"<,@.(Q`(#B#1"@X08@H./^___K!0#4YP`#A.`G#(#B-P"`XA00AN(0(*#C +M_O__ZP4PU.<#,X3@)SR#XC`P@^(!(*#C`"##Y04PU.<",(/@`0A>(&(*#C_O__ +MZP,``.H$`*#A`!"@XP8@H./^___K``"@XW"`O>CP3RWI9-!-X@!@H.$"4*#A +M`T"@X0,`H.$`$`#C`!!`XP<@H./^___K``!0XR,```H`5);E!S#4Y3``4^,( +M```*,0!3XP%`H`,&```*,@!3XP)`H`,#```*,P!3XP-`H`,````*`$"@XP4` +MH.$$$*#A_O__ZP``4..3`@`*``!4XY$"``HL.@/C`S"5YP(`4^/I/:`#`Q#5 +M!P`PH`,#(*`!WA?5%4$Z`Q,#$,47X"?5%=\WU14%`*#A_O__ZX("`.H$`*#A +M`!``XP`00.,&(*#C_O__ZP``4.,2```*M##5X08P0^)S,/_FM##%X0!DEN5Z +M>@/C`3!#X@$`5);E+#H#XP,PE><``%/C60(`"@1@H.$-,/;E,`!3XP@``!KA#87B +M*0"`X@`0H..&(0#C_O__ZP`@H.-[.@/C`R#%YTP"`.I[.@/C`S#5YPD`4^-( +M`@"*!'"@X0"`H.-[J@/CB)@#XR>PH.,*0-7G#@#7Y0\0U^7^___KFU0DX`A` +MA.`)0(3@`@#$Y0&`B.(#<(?B!@!8X_/__QI[2@/C!`#5YV@X`^,G(*#CDE`@ +MX`,`@.`3P-;E$A#6Y0$1@>`0P$SB@1",X`$0P.4$$-7GD@$"X`(`A>`#,(#@ +MX0V`XBH`@.(4$(;B`2#3Y?[__^L$,-7G`3"#X@0PQ><>`@#J!`"@X0`0`.,` +M$$#C"B"@X_[__^L``%#C!0$`"K0PU>$*,$/BM##%X0IPA.(`9);E"&"-Y0`@ +MH.-0((WEM"7-X1PPC>($((/D!""#Y`0@@^0$((/D!""#Y`0@@^0$((/D!""# +MY`0@@^0$((/D!""#Y`0@@^2P(,/A7""-Y5@@C>4L.@/C`S"6YP(`4^'Z`0`* +M`0!3X_@!``H.6X;B+""%X@P@C>4"`*#A`!"@XP8@H./^___K,C"%XA`PC>4# +M`*#A`!"@XP8@H./^___K"%"%XA10C>4%`*#A`!"@XR0@H./^___K`&"@XP(X +M`^,($)WELV"!X00X`^.S8('A.#@#XP-@P>=04(WB"@#4Y0L0U.7^___K!@#% +MYP%@AN(#0(3B!@!6X_?__QH2<(?B!P"@X0`0`.,`$$#C!R"@X_[__^L``%#C +M!```"@X[H.,((*#C"!"=Y;,@@>$A``#J!P"@X0`0`.,`$$#C!R"@X_[__^L` +M`%#C!```"@X[H.,!+*#C"!"=Y;,@@>$5``#J!P"@X0`0`.,`$$#C`R"@X_[_ +M_^L``%#C!```"@X[H..`(*#C"!"=Y;,@@>$)``#J!P"@X<`6G^4%(*#C_O__ +MZP``4..I`0`*#CN@XP0@H.,($)WELR"!X?[__^L-(*#A?SW"XS\PP^,$()/E +M`2""X@0@@^4(,)WEA("#XH1`D^4`<*#C7*"-X@>0H.$<8(WB6+"-X@10H.$( +M`*#A!1"@X?[__^L!`%#C*0``"@5PH.&0$)7EH`"%X@P00>()(*#A"C"@X?[_ +M_^L`0%#B'@``"@"PC>4$`*#A7!"=Y0,@H.,&,*#A_O__ZP``4.,'```*!@"@ +MX5`0C>(&(*#C_O__ZP``4.,0```*9$"5Y1$``.H`L(WE!`"@X5P0G>4-(*#C +M!C"@X?[__^L``%#C!@``"@8`H.%0$(WB!B"@X_[__^L``%#C9$"5%0(``!H` +M4)7ET/__Z@!`H.,-$*#A?SW!XS\PP^,$()/E`2!"X@0@@^7^___K``!4XUP! +M``H0`)WE(!"'X@8@H./^___K#`"=Y5`0C>(&(*#C_O__ZP(X`^,(()WELT"" +MX0$@H.,X.`/C"!"=Y0,@P>4#,)+G!@!3XP8@H!,L.@,3"!"=%0,@@14H$(?B)""@X_[__^L.``#J`0!3XP$```H#`%/C"@``&@@P +MG>4."X/B#`"`XND=@^(+$('B!R"@X_[__^L'(*#C"#@#XP@0G>4#(('G"`"= +MY700[^8`(*#C`C"@X?[__^L`0`#C`$!`XP`0E.4(()WEWPV"X@P`@.(*$('B +M_O__ZP`0E.4(,)WEW@V#XA@`@.)]'X'B_O__ZQ$!`.H$`*#A`!``XP`00.,% +M(*#C_O__ZP``4.-K```*M##5X04P0^*T,,7A`%26Y0`PH.-0,(WEM#7-X2PZ +M`^,#,)7G``!3X_\```H!`%/C_0``"L0Z`^,#,)7G``!3X_D```H$8*#A`'"@ +MXU!`C>(%`-;E!A#6Y?[__^L'`,3G`7"'X@-@AN(&`%?C]___&O[__^L-$*#A +M?SW!XS\PP^,$()/E`2""X@0@@^6$<(7BA$"5Y0!@H.-0@(WB!J"@XP<`H.$$ +M$*#A_O__ZP$`4.,)```*!&"@X2``A.(($*#A"B"@X?[__^L``%#C9$"4%0(` +M`!H`0)3E\/__Z@!`H.,-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K``!4 +MX\D```KG?87B,`"'X@`0H.,,(*#C_O__ZSP`A^(`$*#C)B"@X_[__^OP.0/C +MLT"%X30`A^(@$(;B!B"@X_[__^L!(*#C^CD#XP,@Q><)`%/C"2"@$RPZ`Q,#((47M$*?Y0`0 +ME.7?#87B#`"`X@H0@>+^___K`!"4Y=X-A>(8`(#B?1^!XO[__^N>``#J!`"@ +MX0`0`.,`$$#C!R"@X_[__^L``%#C%P``"K0PU>$(,$/B$'0(3B +M`%26Y5(J`^,"`-7G`0!3XP(```H"`%/C!P``&@,``.H``-3E,`!`XG``[^8" +M``#J``#4Y0$0U.7^___K#P!0XU(Z`Y,#`,67?P``Z@0`H.$`$`#C`!!`XP4@ +MH./^___K``!0XQ````JT,-7A!3!#XK0PQ>$%0(3B`%26Y00`H.'^___K`""@ +MX>H-A>(!`(#B!!"@X?[__^L$`*#A_O__ZZ$Z`^,#`,7G9P``Z@0`H.$`$`#C +M`!!`XPP@H./^___K``!0XQD```JT,-7A##!#XK0PQ>$`));E###4Y3``4^,` +M$*`#Q#H#`P,0@@=6```*,0!3XP$0H`/$.@,#`Q""!U$```HR`%/C`A"@`\0Z +M`P,#$(('3```"C,`4^,#$*`#`!"@$\0Z`^,#$(+G1@``Z@0`H.$`$`#C`!!` +MXPH@H./^___K``!0XQ\```JT,-7A"S!#XG,P_^:T,,7A"D"$X@!4EN7I+:#C +M`A#5YP$`4^,"```*`@!3XP@``!H#``#J`!#4Y3`00>)Q$._F`P``Z@``U.4! +M$-3E_O__ZP`0H.$!,$'B<%`*#A`""@XP(P +MH.'^___K'P``Z@0`H.$`$`#C`!!`XP8@H./^___K``!0XQ@```JT,-7A!S!# +MXG,P_^:T,,7A!D"$X@!4EN5!*@/C`@#5YP$`4^,"```*`@!3XP<``!H#``#J +M``#4Y3``0.)P`._F`@``Z@``U.4!$-3E_O__ZP$P0.)S,._F#`!3XT$Z`Y,# +M`,67``"@XV30C>+PC[WHF#(````````00"WI&-!-X@!$D.4`(*#C#""-Y10@ +MC>40((WE$""-X@`@C>4#`*#A`!``XP`00.,,((WB%#"-XO[__^L,,)WE`@!3 +MXPH```H$`%/C#@``"@$`4^,5`.`3$```&@0`H.$4$)WE$"#=Y?[__^L``*#C +M"@``Z@0`H.$4$)WEL"'=X?[__^L``*#C!```Z@0`H.$4$)WE$""=Y?[__^L` +M`*#C&-"-XA"`O>CP02WI$-!-X@!DD.4``)+E<$#_YE`8Y^<$,)+E##"-Y2`, +MH.%Q`$#B#@!0XP#QGY?:``#J2*\$`'BR!`"+($`+BO!`#8KP0`>+($ +M`'BR!`!XL@0`>+($`'BR!`!XL@0`>+($`'BR!``8L`0``@!1XP@```H$`%'C +M"P``"@$`4>/%```:!@"@X000H.%S(._F_O__Z\```.H&`*#A!!"@X7,@_^;^ +M___KNP``Z@8`H.$$$*#A`R"@X?[__^NV``#J!@"@X000H.$`(.#CH,L#XP_@ +MH.$,\);GKP``Z@`PC>4&`*#A!""@X0`PX..HRP/C#^"@X0SPEN>G``#J``!1 +MXP`@H`.8-@$#`R#&!Z(```H!`%'CH```&@$@H..8-@'C`R#&YPP@G>5D`%+C +M9""@(YDV`>,#(,;GEP``ZA$`4>.S+`,#`C#&!Y,```H*``"*!@!1XQ@```H" +M``"*!0!1XXT``!H/``#J"0!1XR(```H,`%'CB```&D```.K=`%'C5P``"@(` +M`(JJ`%'C@@``&DP``.KN`%'C8```"OT`4>-]```:4T/0/C`R#&YRT``.H``%/C`@``&@8` +MH.'^___K*```Z@$`4^,"```:!@"@X?[__^LC``#J`@!3XR$``!H&`*#A_O__ +MZQX``.H/`%/C!@``&@8`H.$'$*#C"""-XFP[`^,/X*#A`_"6YQ4``.H&`*#A +M!Q"@XPP@C>)P.P/C#^"@X0/PEN<&`*#A!Q"@XP@@C>)L.P/C#^"@X0/PEN<( +M``#J=$#OY@8`H.'%'J#C!""@X?[__^L&`*#A6!P`XP0@H.'^___K``"@XQ#0 +MC>+P@;WH$$`MZ0`$D.4`$-+E`2"@X_[__^L!`%#C``#@$P``H`,0@+WH\$\M +MZ3S03>(`5)#ES#L#XP,PE><"H*#A`2!RX@`@H#,``%/C`C"@`0$P@A,``%/C +M`$"@`QY@H`,%```*C```Z@8`H.'^___K`4"$XF4`5.,"```*;#"5Y2(-$^/W +M__\:`""@X[8@RN&T,-KA'P!3XW\``)H`$)KE#2"@X7\]PN,_,,/C"#"3Y2`@ +MD>(#(-(P`#"@,P``4^,%```:#`"-XB`@H./^___K``!0XP4```IO``#J#`"- +MXB`0H./^___K%0#@XVT``.K^___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/E +MA$"%XH2`E>4`D*#C#+"-XBQPC>*`!(WH!*"@X0H`H.$($*#A_O__ZP$`4.,\ +M```*"4"@X0M0H.$``-7E0_+_ZP!@4.(0``"Z`0#UY3_R_^L``%#C#```N@%0 +MA>(&8H#A!&#'YP0`5.,#``#*`##5Y3H`4^,$```:`5"%X@%`A.(&`%3CZ___ +M&D4``.H-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K%0#@XSH``.J@4(3B +MD""4Y04`H.$T$(WB#"!"XO[__^L``%#C!0``"C0PG>4``%/C!*"=%0$PH!.V +M,,H1#P``&I`@E.4%`*#A-!"-X@P@0N+^___K``!0XP4```HT,)WE``!3XP2@ +MG14"(*`3MB#*$0(``!H`@)CEO?__Z@2@G>4-(*#A?SW"XS\PP^,$()/E`2!" +MX@0@@^7^___KM##:X2$`4^,1``":``":Y2``@.(-(*#A?SW"XS\PP^,(,)/E +M`2"0X@,@TC``,*`S``!3XP0``!H&$(KB`2"@X_[__^L``%#C`0``"A4`X.,` +M``#J``"@XSS0C>+PC[WH"$"@X0``G>4@$(CB!B"@X_[__^L!`%#CUO__&KK_ +M_^KP12WI#-!-X@)`H.$`5)#EMX0``5N.+```*`#"2Y0``4^.(```*MJ#2 +MX08`H.'^___K`(!0X@M`X`.#```*`!"4Y0T@H.%_/<+C/S##XP@PD^4&()'@ +M`R#2,``PH#,``%/C!0``&@@`H.$&(*#A_O__ZP``4.-W```:!@``Z@``5N,$ +M```*"`"@X080H.'^___K#4#@XW(``.H(<*#A`#"8Y2(`4^,50."#;0``B@AP +MB.(&`%/C-@``"@0``(H"`%/C!P``"@,`4^-*```:&@``Z@<`4^,W```*'P!3 +MXT4``!H^``#J!#"7Y0(`4^,(```*!`!3XPL```H!`%/C/0``&@4`H.$`$)?E +M_O__ZP@`A^4X``#J!0"@X0`0E^7^___K"`"'Y3,``.H%`*#A`!"7Y?[__^L( +M`(?E+@``Z@0PE^4"`%/C"```"@0`4^,+```*`0!3XR<``!H%`*#A`!"7Y0@@ +MU^7^___K(@``Z@4`H.$`$)?EN"#7X?[__^L=``#J!0"@X0`0E^4(()?E_O__ +MZQ@``.H%`*#A`!#7Y00@U^4`,.#CI,L#XP_@H.$,\)7G"`"'Y0\``.H`$-?E +M!"#7Y0@PE^4`,(WE!0"@X0`PX..HRP/C#^"@X0SPE><%``#J!0"@X2\0H.,` +M(*#C9#L#XP_@H.$#\)7G>J#OY@``6N,6```:``"4Y0T@H.%_/<+C/S##XP@P +MD^4&()#@`R#2,``PH#,``%/C!@"@$0(``!H($*#A!B"@X?[__^L``%#C!@`` +M"@,``.H50.#C!`"@X0S0C>+PA;WH#4#@XP```.H`0*#C"`"@X080H.'^___K +M]?__ZO!!+>D(T$WB`E"@X0.`H.$`=)#EM$#2X00`H.'^___K`&!0X@L`X`-( +M```*`!"5Y0T@H.%_/<+C/S##XP@PD^4$()'@`R#2,``PH#,``%/C!0``&@8` +MH.$$(*#A_O__ZP``4.,%```:"0``Z@``5.,'```*!@"@X000H.'^___K!@"@ +MX000H.'^___K#0#@XRX``.H`,*#C`#"-Y00PC>4&`*#A`!``XP`00.,-(*#A +M!#"-XO[__^L`,)WE`@!3XPT```H$`%/C%```"@$`4^,5`.`3'0``&@<`H.$$ +M$)WE_O__ZP`@H.$(`*#A`!``XP`00./^___K$```Z@<`H.$$$)WE_O__ZP`@ +MH.$(`*#A`!``XP`00./^___K!P``Z@<`H.$$$)WE_O__ZP`@H.$(`*#A`!`` +MXP`00./^___K!@"@X000H.'^___K``"@XPC0C>+P@;WH<$`MZ2#03>("4*#A +M`V"@X0!$D.4$`(WB`!"@XQP@H./^___KMC#5X0()$^,,```*`2"@XS0\`>,# +M((3G``"@X\PX`>,#`(3G)#D!XP,`A.?(.`'C`P"$YS`\`>,#`(3G8@``ZO\@ +M$^(%```*!`!2XQ4`X(,!($*2`1"@DP,``)I:``#JT"@!XP(@E.<`$*#C`@H3 +MXPL```H`,*#C-`P!XP`PA.?("`'C`#"$Y\P(`>,`,(3G)`D!XP`PA.,` +M,(3GS`@!XP`PA.,`,(3G"""-Y;0PU>$``%/C!@``"@4` +M4^,%,*"3#3"@@PPPC>4,,(/B!#"-Y1L``.H`,*#C##"-Y0$`4>,7```:T#@! +MXP,@A.<9+8+B!"""X@(AA.`$,)+E!0!3XP4```H-`%/C``"@$\PX`1,#`(07 +M'0``&@0``.H!(*#CS#@!XP,@A.<``*#C%P``Z@4@H./,.`'C`R"$YP``H.,2 +M``#J"#"=Y0(Q@^,(,(WE!%"-X@P`A>(&$*#A#""=Y?[__^L$`*#A!1"@X?[_ +M_^L``%#C!```&M@S`^,#,)3G``!3XUX`X`,````*``"@XR#0C>)P@+WH\$4;,,'EOC+1X3`P@^("`%/ATP``B@0PD>4!`'/C +MT```&K@@T>'_/P_C`P!2X(' +M`*#A`!``XP`00./^___K``!0XT4``!H`(*#C-#P!XP,@A>=8((+B`C"%YR2`U.6^,M3A!`!8XQ5`X(.V``"*``!3X[$```H%`%/C!9"@ +MDPV0H(,,H(GB"@"@X?[__^L`<%#BJP``"@<`H.$`$*#C"B"@X?[__^L(D(?E +M`*"'Y0T`6>,%,*`#S"@!`P(PA0=8((("`C"%!P(QB.,$,(?E#)"'X@D`H.$P +M$(3B"""7Y?[__^L<,-3E``!3XP4```H%`*#A!Q"@X?[__^L``%#CE0``"I(` +M`.H#`%CCD@``BF,/B.(``H7@%`"`X@D0H.$(()?E_O__ZQD]B.(#,87@"""7 +MY10@@^4%`*#A!A"@X0@@H.$`,*#C_O__ZP!`H.."``#JR#@!XP,PE><"`%/C +M>```&FP@E>4(,`#C`3!`XP,P`N```%/C<@``"EL-A>(X`(#BX!"%XO[__^L` +M@%#B5@``"@<`H.'0$9_E_O__ZP``4.,`,*`3Z#"(%30\`>,#,)7G!@!3XP0` +M4Q/,.`$#`S"5!^PPB`4<,-3E`0!3XQL``!HP8(3BOB+4X1$.B.(&$*#A$`!2 +MXQ`@H"/^___K!P"@X7@1G^7^___K``!0XPH``!KP`(CB$!"&X@@@H./^___K +M`0R(XA@0AN(((*#C_O__ZP`@H.,A/`'C`R#%YP4`H.$($*#A`2"@X_[__^LJ +M``#J)`#4Y08`@.(``H7@8PV`XC"`A.*^(M3A#`"`X@@0H.$0`%+C$""@(_[_ +M_^LD`-3E"@"`X@`"A>!C#8#B#`"`XA`0B.(((*#C_O__ZR0`U.4.`(#B``*% +MX&,-@.(,`(#B&!"(X@@@H./^___K`3"@XR`L`>,",,7G)!#4Y;XO0N("$(7G +M!0"@X080H.$D(-3E_O__ZRPZ`^,#,)7G#0!3XPX@H`,L.@,#`R"%!P4`H.'^ +M___K`$!0XA$```H'`*#A9!"?Y?[__^L``%#C`#"@$^@PA!4T/`'C`S"5YP8` +M4^,$`%,3!@``&LPX`>,#,)7G[#"$Y0!`H.,"``#J%4#@XP```.H`0*#C!`"@ +MX?"'O>@`0*#C````ZEY`X.,'`*#A"A"@X?[__^OV___J##,``!0S``#P1RWI +M`*"@X0*`H.$#4*#AMF+3X4!@AN(&`*#A_O__ZP!`H.$`<*#A``!0XT$```H` +M$*#C!B"@X?[__^L$`*#A`S"@XP0P@.3_$*#C!B"@X_[__^NT,M7A`P!3XP/Q +MGY4(`!/C`3"@$QPPQQ4&,-CE`3!#XB0PQ^4`,)7E`@`3XP,```HE +M`(?B#!"%X@@@H./^___KMC+5X0``4^,$```*OC+'X3``A^(H$(7BMB+5X?[_ +M_^L*`*#A!Q"@X08@H.'*_O_K`%"@X00`H.$&$*#A_O__ZP```.H`4.#C!0"@ +MX?"'O>AP0"WI`%"@X0)`H.$`9)#EMC#2X0,ZH.$C.J#A"@!3XP/QGY<*``#J +M&,$$`!C!!``8P00`&,$$`&C`!`"0P`0`X,`$`!C!!``8P00`8,`$`!C!!`!> +M`.#C<("]Z``PDN4``%/C`2"@$R@W`A,#(,87``"@$P``H`,H-P(#`P#&!W"` +MO>@T/`'C`S"6YP``4^,=```*`#"2Y0``4^,:```*`2"@XS0\`>,#((;G``"@ +MX\PX`>,#`(;G)#D!XP,`AN?(.`'C`P"&YS`\`>,#`(;G<("]Z&PPEN4!`!/C +M!@``"@8`H.'^___K!@"@X?[__^L&`*#A`1"@X_[__^L%`*#A`!"4Y0'O_^MP +M@+WH``"@XW"`O>CP3RWI%-!-X@!@H.$"0*#A`#"@XPPPC>4(,(WE`5"@X0,` +M4>$`$*`3`1"@`X``4N,!,*"1`3"!@P``4^,&```*`""@XQ@Z`>,#(,#G`@!1 +MX0)`H!$50.`#W```Z@``4N,`0*`#V0``"@2PH.$$`*#A_O__ZP!P4.(+0.`# +MTP``"@<`H.$%$*#A"R"@X?[__^L$4*#A``!4XP,``-H`,*#C"#"#X@,`5>'\ +M___*`P!4XP!`X)/3``":!P"@X040H.$,((WB"#"-XO[__^L!`%#C"@``&@(@ +MH./(.`'C`R"&YP0@H.,P/`'C`R"&YR8,AN(D`(#B!Q"@X0L@H.'^___K!P"@ +MX040H.$,((WB"#"-XO[__^L!`%#C"@``&@(@H./(.`'C`R"&YP<@H.,P/`'C +M`R"&YR8,AN(D`(#B!Q"@X0L@H.'^___K##"=Y0$P0^(/`%/C`_&?ES$``.J\ +MP@0`V,($`$3#!``LPP0`1,,$`$3#!`!$PP0`],($`$3#!`!$PP0`1,,$`$3# +M!`!$PP0`1,,$`$3#!``0PP0``""@XR0Y`>,#((;G`2"@XS0\`>,#((;G&@`` +MZ@$@H.,D.0'C`R"&YP`@H.,T/`'C`R"&YQ,``.H"(*#C)#D!XP,@AN<$(*#C +M-#P!XP,@AN<,``#J!""@XR0Y`>,#((;G!B"@XS0\`>,#((;G!0``Z@4@H.,D +M.0'C`R"&YP`@H.,T/`'C`R"&YP@PG>4!,$/B#P!3XP/QGY,#((;G!""@XS0\`>,# +M((;G0P``Z@0@H./,.`'C`R"&YP8@H.,T/`'C`R"&YSP``.H%(*#CS#@!XP,@ +MAN<`(*#C-#P!XP,@AN,#(,;G`#``XP`P0.,`,)/E!#"- +MY30``.H%@*#A!:"'X``PVN7=`%/C'0``&@(`A>(``(?@!!"-X@0@H./^___K +M`0!0XQ8``!H!0*#C"H"@X00@VN<"((+B`@Q2XP(LH*,!U4/_F!0!4X=7__XH,``#J!`"@ +MX130C>+PC[WH`""@XQ@Z`>,#(,;G`#``XP`P0.,`,)/E!#"-Y0!0H.,!D*#C +MQ___Z@!`H.,'`*#A"Q"@X?[__^OM___J$$`MZ0`$D.4#$*#AM"#2X?3^_^L0 +M@+WH\$$MZ0C03>("0*#A`#"@XP0PC>4`5)#ELC#-X0$PS>5L,)7E`0`3XP(` +M`!I``!/C``#@`UD```I0,97E%@Z%XBT0H.,$((WB##!#XO[__^L`$%#B$``` +M"@0PG>4``%/C#0``"@%@H.$"`(WB!1"!X@(@H./^___K`C#VY0$@UN4"-(/A +MTW#@YV``$^,`8*`#`6"@$P&`H.,"``#J`&"@XP9PH.$&@*#A/#'5Y0$@0^)R +M(._F_0!2XP`0H(,,``"*!2"@X0`0H.,!P*#A?S`#X@$`4^$#$*`A!,#$Y3TQ +MTN4!((+B`0!#XG``[^;]`%#C]?__F@$`6.,C```:!0"@X100H.,!((WB:#L# +MXP_@H.$#\)7G`3#=Y0,`4^,)```:``!7XP,```H``%;CEF"@$X=@H`,-``#J +M``!6XTA@H!-!8*`#"0``Z@``5^,$```*#C$`XP``5N,#8*`!2V^@$P(``.H` +M`%;CD&"@$X)@H`.&(*#A(#$*XPD@T$WB`%20Y0!`DN4$X-+E#<"@ +MX3`QG^4/`)/H!P"LZ``PS.4!`'3C,```"J1"H.'%.@7C?#I`XY,D@^"C,Z#A +M;@!3XP5`H`,I```*#P``BC<`4^,"0*`#)0``"@4``(H*`%/C`$"@`R$```H4 +M`%/C'@``&A4``.H\`%/C`T"@`QL```I:`%/C&```&A$``.KP`%/C"$"@`Q4` +M``H%``"*>`!3XP9`H`,1```*M`!3XPX``!H)``#J6@]3XPE`H`,+```*'@Y3 +MXP@``!H%``#J`4"@XP8``.H$0*#C!```Z@=`H.,"``#J"D"@XP```.H+0*#C +M`#"@XPW`H.$0`(WB`&#@XP,@W.<$`%+A`V#`%P(``!H#(,#G``!>XP(```H! +M,(/B#0!3X_7__QH%`*#A$!"-XO[__^L!`%#C``"@`P``X!,@T(WB<("]Z)!; +M``#P0"WI#-!-X@)@H.$`1)#E`#"@XP0PC>5L,)3E00`3XSL```I0,93E%@Z$ +MXBT0H.,$((WB##!#XO[__^L``%#C`'"@`P(```H$<)WE`'!7X@%PH!-/7X3B +M!0"@X?[__^L!`%#C"```&@$`5^,&`*#A$!"@XP`@``,`($`#`"``$P`@0!/^ +M___K)@``Z@4`H.'^___K`0!0XP@``!H!`%?C!@"@X1`0H.,`(``#`"!``P`@ +M`!,`($`3_O__ZQD``.HD,93E#@!3XP@``)H!`%?C!@"@X1`0H.,`(``#`"!` +M`P`@`!,`($`3_O__ZPT``.H!`%?C!@"@X1`0H.,`(``#`"!``P`@`!,`($`3 +M_O__ZP0``.H"`*#A$!"@XP`@`.,`($#C_O__ZP``H.,,T(WB\("]Z/A/+>D# +M<*#A`$20Y8X_H..T,,+A!P"@X0`0H.,#(*#A_O__ZT`[!.-,,$#C`#"'Y60P +MH.,L,,?E+3#'Y2XPQ^4',*#C+S#'Y5P@H.,P(,?E32#@XS$@Q^4`4*#C,E#' +MY3,PQ^4$,*#C-##'Y0`P`.,`,$#C`""3Y3@@A^4$()/E/""'Y0@@D^5`((?E +M##"3Y40PA^4!/*#CP#"'Y2HY`./$,(?EO%W'X18PH.,8,/K__\:$SZ@X[-@A^$R8$D,93E!C#%Y0D``.K>!]3E_O__ZZ`V".,!,$#CDP`#X``P +MA>4!,*#CM##%X=XWU.4&,,7E``"@XW"`O>CP3RWIQ=]-X@`0H.$"L*#A`T"@ +MX0`PH./T,HWE`BR-XK([PN$L.@/C`S"0YP``4^,1```*`0!3XP\```HL`(OB +MZ1V!X@L0@>('(*#C_O__ZP``4./*`@`*`""@XS$^C>)D("/ED!";Y:``B^(, +M$$'B_O__ZP``4./!`@`*%3L(X_\_3^,"+(WBOC_"X0$PH.,#+(WBL##"X0,, +MC>("`(#B(!"+X@8@H./^___K%&"$XC@SG>4&`%/A"P``FC%>C>(4(*#CM"%E +MX00`H.$%$*#A!""@X_[__^L$`(3B!!"%XA`@H./^___K!D"@X1L["./_/T_C +M`BR-XKX_PN$!,*#C`RR-XK8PPN&X,MOA(`!3XR`PH".T,,+A+*"+X@@P@^(# +M<(3@.".=Y0<`4N$0``":,5Z-XK0Q9>$$8*#C!`"@X040H.$&(*#A_O__ZP8` +MA.`($(7B!B"@X?[__^L(`(3B"A"@X0,\C>*T(-/A_O__ZP=`H.&@((OB&""- +MY9`PF^4"`*#A+1"@X[TOC>(,,$/B_O__ZP`04.(4```*]#*=Y0``4^,1```* +M`5"@X2L.C>("`(#B!1"!X@(@H./^___K`C#UY0$@U>4"-(/ATR#@YR0@C>5@ +M`!/C`#"@`P$PH!,4,(WE`2"@XQ`@C>4#``#J`#"@XQ0PC>4D,(WE$#"-Y0$[ +M"./_/T_C`BR-XKX_PN%\4(OB!0"@X?[__^L!`%#C"0``&A`PG>4!`%/C`PR- +MXA`0H.,`(``#`"!``P`@`!,`($`3_O__ZR,``.H%`*#A_O__ZP$`4.,)```: +M$""=Y0$`4N,##(WB$!"@XP`@``,`($`#`"``$P`@0!/^___K%0``ZF0PF^4. +M`%/C"0``FA`PG>4!`%/C`PR-XA`0H.,`(``#`"!``P`@`!,`($`3_O__ZP@` +M`.H0()WE`0!2XP,,C>(0$*#C`"```P`@0`,`(``3`"!`$_[__^L48(3B.#.= +MY08`4^$+``":,5Z-XA0@H..T(67A!`"@X040H.$$(*#C_O__ZP0`A.($$(7B +M$""@X_[__^L&0*#A!SL(X_\_3^,"+(WBOC_"X90PB^(,,(WE`P"@X?[__^L` +M$*#AO@^-X@(`@.("(*#C_O__ZP(LC>*Z/]+A`P`3XQ0```H!`!/C`S"@$P$P +MH`,`,XWE"("$XC@SG>4(`%/A#```FC%>C>(((*#CM"%EX01@H.,$`*#A!1"@ +MX08@H.'^___K!@"$X`80A>`&(*#A_O__ZP```.H$@*#A9#";Y0``4^,!,*`# +M9#"+!04["./_/T_C`BR-XKX_PN%D`)OE_O__ZZ`V".,!,$#CDP`#X``SC>4! +M,*#C`RR-XK0PPN%D,)OE!C/-Y0Q0B.(X,YWE!0!3X0L``)HQ3HWB#""@X[0A +M9.$(`*#A!!"@X00@H./^___K!`"(X@00A.(((*#C_O__ZP6`H.$K.PCC_S]/ +MXP(LC>*^/\+ANC_2X1``$^,".Z`3`CF@`P,LC>*V,,+A`#"@XP,LC>*T,,+A +M"%"(XC@SG>4%`%/A$0``FC%.C>(((*#CM"%DX01@H.,(`*#A!!"@X08@H.'^ +M___K!@"(X`@0A.(&(*#A_O__ZP4`H.$*$*#A`SR-XK0@T^'^___K!8"@X:U_ +MC>('`*#A0!"@XP`@`.,`($#C_O__ZWP@V^4``%+C`&"@`Q\```JM3XWB`$"$ +MX`M0H.$`8*#C0'"'X@"0`.,`D$#C`#``XP`P0.,<,(WE`*``XP"@0.,@@(WE +M`X"@X7\P`N(&`%/A`V"@(0<09."C,*#A`0`2XP@@H`$)(*`1`""-Y00`H.$* +M(*#A_O__ZWT@U>4!4(7B``!2XP!`A!#N__\:(("=Y1`@G>4!`%+C+P``&@(L +MC>*R.]+A`@D3XPP```HD,)WE``!3XP0```H.80#C%""=Y0``4N-+;Z`3(@`` +MZA0PG>4``%/CD&"@$X)@H`,=``#J@``3XPH```HD()WE``!2XP,```H4,)WE +M``!3XQ0``!H/``#J%""=Y0``4N,.```:"0``ZB0PG>4``%/C`P``"A0@G>4` +M`%+C"0``&@0``.H4,)WE``!3XP,``!I!8*#C!```ZH=@H.,"``#J2&"@XP`` +M`.J68*#CAF"@X2$["./_/T_C`BR-XKX_PN$`,*#C!3/-Y00SS>4@,0KC!S!` +MXY,&`^``,XWE#%"(XC@SG>4%`%/A"P``FC%.C>(,(*#CM"%DX0@`H.$$$*#A +M!""@X_[__^L$`(CB!!"$X@@@H./^___K!8"@X0`PH.,"+(WBL#O"X;PZPN&0 +M$)OE2S^-X@`PC>4K/HWB!#"-Y0P`G>4L((WBJS^-XO[__^L"+(WBL#O2X0`` +M4^-@```*BT^-X@0`H.$`$*#C@""@X_[__^L`,`#C`#!`XP,`D^@#`(3H`BR- +MXK`[TN$``%/C#P``"B->C>(#4(7B`$"@XP!@`.,`8$#C2W^-X@4`H.$&$*#A +M!"#7Y_[__^L`4(7@`4"$X@(LC>*P.]+A!`!3X?7__XJ_#XWB`!"@XQ0@H./^ +M___K`CP(X_\_3^,"+(WBOC_"X8L/C>+^___K<##_Y@,LC>*T,,+A"#"#X@-@ +MB.`X(YWE!@!2X1```)HQ3HWBM#%DX010H.,(`*#A!!"@X04@H.'^___K!0"( +MX`@0A.(%(*#A_O__ZP@`B.*+'XWB`SR-XK0@T^'^___K!H"@X;\/C>(`$*#C +M%""@X_[__^L%/`CC_S]/XP(LC>*^/\+AL#O2X0,LC>*T,,+A"#"#X@-@B.`X +M(YWE!@!2X1```)HQ3HWBM#%DX010H.,(`*#A!!"@X04@H.'^___K!0"(X`@0 +MA.(%(*#A_O__ZP@`B.)+'XWB`SR-XK0@T^'^___K!H"@X0(LC>*\.M+A``!3 +MXV````J+3XWB!`"@X0`0H..`(*#C_O__ZP`P`.,`,$#C`P"3Z`,`A.@"+(WB +MO#K2X0``4^,/```*(UZ-X@-0A>(`0*#C`&``XP!@0.,L<(WB!0"@X080H.$$ +M(-?G_O__ZP!0A>`!0(3B`BR-XKPZTN$$`%/A]?__BK\/C>(`$*#C%""@X_[_ +M_^L"/`CC_S]/XP(LC>*^/\+ABP^-XO[__^MP,/_F`RR-XK0PPN$(,(/B`V"( +MX#@CG>4&`%+A$```FC%.C>*T,63A!%"@XP@`H.$$$*#A!2"@X?[__^L%`(C@ +M"!"$X@4@H.'^___K"`"(XHL?C>(#/(WBM"#3X?[__^L&@*#AOP^-X@`0H.,4 +M(*#C_O__ZP4\"./_/T_C`BR-XKX_PN&\.M+A`RR-XK0PPN$(,(/B`V"(X#@C +MG>4&`%+A$```FC%.C>*T,63A!%"@XP@`H.$$$*#A!2"@X?[__^L%`(C@"!"$ +MX@4@H.'^___K"`"(XBP0C>(#/(WBM"#3X?[__^L&@*#A`#"@XZPRC>60<)OE +M#'!7XC<```H#0*#AJZ^-X@4L"./_+T_C#""-Y;\_C>((,(/B$#"-Y0&0H.,$ +M4*#A%+"-Y0>PH.$8<)WE!6"'X`8`H.$*$*#A_O__ZP``4.,=```*K#*=Y0(` +M4^,:``":#""=Y0(\C>*^+\/AO#K3X0,LC>*T,,+A"#"#X@-`B.`X(YWE!`!2 +MX0\``)H"+(WBO#_"X0@`H.&_'XWB!""@X_[__^L$`(CB$!"=Y00@H./^___K +M"`"(X@80H.$#/(WBM"#3X?[__^L$@*#A!3"'X`DPT^<",(/B`U"%X`4`6^'5 +M__^*%+"=Y0$\"./_/T_C`BR-XKX_PN%+,*#C`S/-Y8PPV^4!,(/BHS"@X5\P +M0^(!,\WEC3#;Y0`SS>4`,*#C`C/-Y0A@B.(X,YWE!@!3X0X``)HQ3HWB"""@ +MX[0A9.$$4*#C"`"@X000H.$%(*#A_O__ZP4`B.`%$(3@!2"@X?[__^L&@*#A +M````Z@2`H.$(`*#AQ=^-XO"/O>CP3RWI'-!-XA00C>4,((WE$#"-Y0!DD.6T +ML-+A"["#X.0S`^,#,-;G``!3XP0```K,.P/C`S"6YP``4^,50.`31@``&BPZ +M`^,#4);G``!5X\A0H!-D4*`#`$"@XQYPH.,$``#J!P"@X?[__^L!0(3B!`!5 +MX0(``#IL,);E`@L3X_?__QK^___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/E +MA*"&XH1`EN5^?H;B!'"'XA"`G>7_D@#C"@"@X000H.'^___K`0!0XQ8```H+ +M,&C@"0!3X09`X-,3``#:!%"@X0<`H.%D$)3E_O__ZP$`4.,*```:*`"$XO[_ +M_^L!`%#C!@``&@"PC>4&`*#A%!"=Y00@H.$(,*#AT_S_ZP"`H.$`0)3EX___ +MZ@!`H.,-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K$#"=Y0B`8^`,()WE +MM(#"X0`PH..V,,+A!`"@X1S0C>+PC[WH$$`MZ0`$D.4``%/C#0``"K`PT^$` +M`%/C`P``"@$`4^->`.`3$("]&`,``.K^___K``!0XP,```H$``#J_O__ZP`` +M4.,!```:``#@XQ"`O>@``*#C$("]Z/!`+>D4T$WB`%"@X0%`H.$!`*#A_O__ +MZP$,4.,:``"*`0$`X_[__^L`8%#B%@``"@0`H.'^___K`""@X08`H.$$$*#A +M_O__ZPUPH.$-`*#A`!"@XQ`@H./^___K!`"@X?[__^NT`,WA"#P#XP,`E><" +M'`CC#2"@X08PH.'^___K!@"@X0$1`./^___K%-"-XO"`O>@P0"WI%-!-X@!0 +MH.$-0*#A#0"@X0`0H.,0(*#C_O__ZP$PH..P,,WA`@"-X@`0H.,&(*#C_O__ +MZP@\`^,#`)7G%1L(XPT@H.$`,*#C_O__ZQ30C>(P@+WH,$`MZ1303>(`4*#A +M#4"@X0T`H.$`$*#C$""@X_[__^L!,*#CL##-X0(`C>+@$(7B!B"@X_[__^L( +M/`/C`P"5YQ4;".,-(*#A`#"@X_[__^L4T(WB,("]Z#!`+>D4T$WB`%"@X0U` +MH.$-`*#A`!"@XQ`@H./^___K"#P#XP,`E><9&PCC#2"@X0`PH./^___K%-"- +MXC"`O>CX3RWI`+"@X0&0H.$"@*#A`Z"@X1P`H./^___K`&"@X0!`H.$``%#C +M``"@`_B/O0@4`*#C_O__ZP!PH.$`4*#A``!0XP0``!H&`*#A'!"@X_[__^L` +M`*#C^(^]Z``0H.,4(*#C_O__ZP&@Q^4`@,?E`3"@XP,PQ^4!@$CB>(#OY@0` +M6.,0(*"#`#``DP`P0),(@(.0%"#8E00`A^()$*#A_O__ZQ0PH..P,,;A!'"& +MY0@PAN4`,*#C##"&Y1`PAN44`(;B_O__ZP4+B^(H`(#B!A"@X?[__^OXC[WH +M$$`MZ04@0N)R(._F"`!2XP`@H(,`P`"3`,!`DP(@C)`<(-*5OO__ZQ"`O>CP +M3RWI%-!-X@!0H.$!0*#A_#L(XP,`4N&<```*_CL(XP,`4N$$```*\3D(XP,` +M4N%>4.`3S`,`&L<#`.JT`='A/P!0XX\``)H0,)'E``!3XXP```K^___K`'"@ +MX0!@H.$``%#C"U#@`[\#``H0$)3EM"'4X0T`H.%_/<#C/S##XP@PD^4"`)'@ +M`P#0,``PH#,``%/C!```&@<`H.'^___K``!0XPH```H$``#J``!2XP<```H' +M`*#A`A"@X?[__^L'`*#AM!'4X?[__^L-4.#CI0,`Z@`PEN4!,$/B`P!3XP/Q +MGY<#``#J&-P$`-#4,,-;E!P!3 +MXP@``(K<,-;A`0"@XQ`SH.'<`!/C(0``&B``$^,;```:`@`3XP$``!I>4.#C +M.P``Z@(`H./(.`'C`P""Y_\0`>(!`%'C`@``"@``4>$3```:!@``Z@0PH.,P +M'`'C`3""YS0<`>,!,(+G`%"@XRL``.H'$*#C,#P!XP,0@N<&$*#C-#P!XP,0 +M@N<`4*#C(P``Z@4`H.$6Z/_K`%"@X1\``.H`4*#C'0``Z@`$E>4P$(;BO"#6 +MX0_Y_^L`4*#A%P``Z@4`H.$&$*#AM"'4X8?W_^L`4*#A$0``Z@`$E>4,,);E +M`0!3XP,```H"`%/C7E#@$PH``!H#``#J_O__ZP``4.,#```:!```ZO[__^L` +M`%#C`0``"@!0H.,```#J`%#@XP``5>,/```:$`"4Y;0AU.$-$*#A?SW!XS\P +MP^,(,)/E`A"0X`,0T3``,*`S``!3XP(``!H&$*#A_O__ZP`@H.$``%+C#5#@ +M$P<`H.&T$=3A_O__ZS@#`.H54.#C-@,`Z@`DM>7A.P/C`S#2YP``4^,`4.`# +M,`,`"A`PD>4``%/C%5#@`RP#``JT`='A_O__ZP0`C>4`8*#A``!0XPM0X`,E +M`P`*$!"4Y;0AU.$-`*#A?SW`XS\PP^,(,)/E`@"1X`,`T#``,*`S``!3XP0` +M`!H&`*#A_O__ZP``4.,*```*!```Z@``4N,'```*!@"@X0(0H.'^___K!`"= +MY;01U.'^___K#5#@XPL#`.H`,);E`3!#XA(`4^,#\9^7$@``ZKS>!`#8W@0` +ML-\$`+3>!``(Z`0`Y.`$`+3>!`"TW@0`M-X$`+3>!`"TW@0`M-X$`+3>!`"T +MW@0`M-X$`'S@!`"8Z`0`..D$`*SI!`!>4.#CUP(`Z@!0E>4%`*#A_O__ZP4` +MH.'^___K`%"@X=`"`.H`<)7E;#"7Y1$`$^,O```*!#"6Y0$`<^,#```:N"#6 +MX0$X@^(#`%+A*```"EL-A^(X`(#B!!"&XO[__^L`4%#B"U#@`[X"``H0@);E +MO##6X=0PA>43#H7B%!"&XA`@H./^___K`@P8XP$PH!,`,*`#W#"%Y5I#H7B#0"`XB00 +MAN(:(*#C_O__Z]@TE^4``%/CA#:%!0<`H.$%$*#A_O__ZP!0H..<`@#J%5#@ +MXYH"`.H`<)7E;#"7Y1$`$^,L```*!#"6Y0$`<^,#```:N"#6X0$X@^(#`%+A +M)0``"EL-A^(X`(#B!!"&XO[__^L`4%#B`%"@`X@"``K^___K#1"@X7\]P>,_ +M,,/C!""3Y0$@@N($((/E:XZ%X@B`B.((`*#A_O__ZP``4.,(```:O#:5Y;@F +ME>4$,(+E`""#Y;B&A>6\AH7E!P"@X040H.'^___K#2"@X7\]PN,_,,/C!""3 +MY0$@0N($((/E_O__ZP!0H.-I`@#J%5#@XV<"`.JT<=3A`%"5Y6PPE>40`!/C +M$@``"F,-A>(,$(;B`B"@X_[__^MC/:#CLS"5X0$P0^)S,/_F'P!3XV,]H(,@ +M`*"#LP"%@04`H.$.$(;B#B!'XO[__^L!`%#C`%"@`T\"``H54.#C30(`ZK0A +MU.$`<)7E`#"@XR`PAN4;,,;EOC+6X4`P@^(#`%+A:P(`&@0PEN4!`'/C!P`` +M&K@@UN$!.(/B`P!2X0,``!HD,-;E`P!3XV$"`(H&``#J6PV'XC@`@.($$(;B +M_O__ZP"`4.)0`@`:5P(`Z@Q0AN(%`*#A8!F?Y?[__^L``%#C40(`"@4`H.%0 +M&9_E_O__ZP$`<.(``*`S``!0XP$PH`,`@*`#4P``"B2`UN6^DM;A`3!YX@`P +MH#,#`%CC`3"#@P``4^-"`@`:``!9XP!0H`,%H*`!#0``"@4`6>,%D*"3#9"@ +M@PR@B>(*`*#A_O__ZP!04.(T`@`*!0"@X0`0H.,*(*#A_O__ZPB0A>4`H(7E +M!("%Y0R0A>()`*#A,!"&X@@@E>7^___K'##6Y0``4^,@```*`""@XS0\`>,# +M((?G`3"@X\PH`>,",(?G6"""X@(PA^<(,)7E#0!3XP4PH`-8($("`C"'!U@@ +M@@(",(<'T#@!XP.`A^=C#XCB``*'X!0`@.()$*#A"""5Y?[__^L9/8CB`S&' +MX`@@E>44((/E!P"@X0P0A>(((-7E"#"@X13^_^M3`0#J8P^(X@`"A^`4`(#B +M"1"@X0@@E>7^___K&3V(X@,QA^`(()7E%""#Y0<`H.$,$(7B""#5Y0@PH.$$ +M_O_K0P$`Z@``4^-P```*;#"7Y1``$^-M```*'##6Y0$`4^/L`0`:``!0XQ(` +M``HD`-;E!@"`X@`"A^!C#8#BOB+6X0P`@.(P$(;B$`!2XQ`@H"/^___K`2"@ +MXR0Y`>,#((?GOC+6X0T`4^,$(((")#D!`P,@AP<\``#J!0"@X6P7G^7^___K +M``!0XR$``!H"(*#C)#D!XP,@A^,#,)?G[#"`Y5P!`.K(.`'C`R"7YP(`4N,`,*`3`3"@`P``6.,`,*`# +M``!3XW@!``IL,)?E$``3XW4!``H<,-;E`0!3XU8``!HPH(;BOB+6X1$.B.(* +M$*#A$`!2XQ`@H"/^___K!0"@X;@5G^7^___K``!0XP8``!H!,*#C[#"(Y;XR +MUN$-`%/C!3"@`^PPB`49``#J!0"@X8P5G^7^___K``!0XPT``!H",*#C[#"( +MY?``B.(0$(KB"""@X_[__^L!#(CB&!"*X@@@H./^___K`2"@XR$\`>,#(,?G +M!@``Z@4`H.%$%9_E_O__ZP``4.,$,*`#`#"@$^PPB.4<`*#C_O__ZP"@H.$` +M`%#C(0``"A@`H./^___K`)"@X0"PH.$``%#C`P``&@H`H.$<$*#C_O__ZQ<` +M`.H4`(KB_O__ZQ40H..P$,KA!)"*Y1@PH.,(,(KE`#"@XPPPBN40,(KE[#"8 +MY08PR>4)`*#AX!"(X@8@H./^___K"`")XA$>B.(0(*#C_O__ZP4+A^(H`(#B +M"A"@X?[__^L`4*#CZ%"(Y?8``.H``%#C$@``"B0`UN4&`(#B``*'X&,-@.*^ +M(M;A#`"`XC`0AN(0`%+C$""@(_[__^L!(*#C)#D!XP,@A^>^,M;A#0!3XP0@ +M@@(D.0$#`R"'!SP``.H%`*#A*!2?Y?[__^L``%#C(0``&@(@H.,D.0'C`R"' +MYR0`UN4&`(#B``*'X&,-@.(P4(;BOB+6X0P`@.(%$*#A$`!2XQ`@H"/^___K +M)`#6Y0H`@.(``H?@8PV`X@P`@.(0$(7B"""@X_[__^LD`-;E#@"`X@`"A^!C +M#8#B#`"`XA@0A>(((*#C_O__ZP$@H.,A/`'C`R#'YQ4``.H%`*#AD!.?Y?[_ +M_^L``%#C#0``&@0@H.,D.0'C`R"'YR0`UN4&`(#B``*'X&,-@.*^(M;A#`"` +MXC`0AN(0`%+C$""@(_[__^L"``#J`""@XR0Y`>,#((?G)"#6Y2@Y`>,#((?G +M`2"@X[X_@^(#(,?GOS]#X@,@E^=8,$/B`R"'YP<`H.$P$(;B.)```*!0"@X0H0H.'^___K`%"@XX0``.H`,)7E;""3Y1$`$N,=```*!""6 +MY0$`4"((+B(`!2XR`@H",, +M((;E=QZ!XA``AN(%$('B_O__ZP!0H.-B``#J%5#@XV```.JT<=3A+#*?Y2@P +MD^4,,(WE`%"5Y6PPE>40`!/C'0``"@YP1^*`!Y7E``!0XP,```J0%Y7E_O__ +MZP`PH..`-X7E``!7XP!0H---``#:!P"@X?[__^N`!X7ED'>%Y0``4.,,```* +M#A"&X@<@H.'^___K!0"@X=T0H.,,((WB`3"@X_[__^L!(*#C(#0!XP,@Q><` +M4*#C.@``ZA50X.,X``#JM''4X0!0E>5L,)7E$``3XQ4```H.<$?BB`>5Y0`` +M4.,#```*F!>5Y?[__^L`,*#CB#>%Y0``5^,`4*#3*```V@<`H.'^___KB`>% +MY9AWA>4``%#C!```"@X0AN('(*#A_O__ZP!0H.,=``#J%5#@XQL``.JT<=3A +M`%"5Y6PPE>40`!/C%0``"@YP1^*,!Y7E``!0XP,```J<%Y7E_O__ZP`PH.., +M-X7E``!7XP!0H-,+``#:!P"@X?[__^N,!X7EG'>%Y0``4.,$```*#A"&X@<@ +MH.'^___K`%"@XP```.H54.#C``!5XP\``!H0`)3EM"'4X0T0H.%_/<'C/S## +MXP@PD^4"$)#@`Q#1,``PH#,``%/C`@``&@80H.'^___K`""@X0``4N,-4.`3 +M!`"=Y;01U.'^___K`P``Z@4`H.'Q*0CC_O__ZP!0H.$%`*#A%-"-XO"/O>@, +M4(;B!0"@X200G^7^___K`0!PX@``H#,`,*#C"O[_Z@!0H./8___J%5#@X];_ +M_^H,,P``"#,``!0S```<,P``C%L``!!`+>F0,P/C`S"0Y_\TP^/_,,/C`0A3 +MXRH```J$,P/C`S#0YP``4^,H```*D3,#XP,PT..2P8'@S@V`XA0`@.(A$X/@_O__ZP$`H.,0@+WH``"@ +MXQ"`O>@!`*#C$("]Z/!!+>D(T$WB`&"@X0)0H.$#0*#A`P"@X0`0`.,`$$#C +M!""@X_[__^L``%#C)P``"K0@U>$$($+B$$,(3B`(26Y0$@0N(! +M`%+C`P``"@(`4N,`<*`3"```&@,``.H`<-/E,'!'XG=P[^8#``#J``#3Y0$0 +MT^7^___K`'"@X0H`5^,0``"*A#,#XP,PV.<'`%/A#```"@``5^,"(*`3@S,# +M$P,@R!(` +M,*#C!#`BY00`A.(`$`#C`!!`X_[__^L$,)WE`0!3XQ,``(J!(P/C`C#%YP$@ +MH..$,P/C`R#%YP`P`.,`,$#C`#"3Y<@C`^,"()7G9!"@XY$"`>#3+03C8B!! +MXY(!@>#.#87B%`"`XB$3@^#^___K!P``Z@(`4^,%```:!0"@X?[__^L``%#C +M`""@$X0S`Q,#(,47``"@XPC0C>+P@;WH\$4MZ2S03>("4*#A`V"@X0!$D.4$ +M`*#A_O__ZP``4.-?```*)#P#XP,PE.<``%/C6P``"K2`U>$@`%CC!@#@@UH` +M`(IL,)3E$``3XU0``!HP/`'C`Z"4Y[8PU>$``%/C40``"@``6.-/```*(`!8 +MXR"`H",$4(WB!0"@X0`0H.,D(*#C_O__ZRAPC>(D@"?E!`"%X@80H.$((*#A +M_O__Z_[__^L-(*#A?SW"XS\PP^,$()/E`2""X@0@@^6$8(3BA#"4Y7@PA.4$ +M<(?B!@"@X7@0E.7^___K`0!0XR$```IX4)3E!0"@X2PPD.1X,(3E!Q"@X00@ +MG>7^___K`0!0X_'__QHH()7E!#"=Y0,`4N'M__\:;#"4Y2``$^,#```*>""5 +MY3@QE.4#`%+AYO__&@0`H.%X$)7E_O__ZP``4.,(```:#2"@X7\]PN,_,,/C +M!""3Y0$@0N($((/E_O__ZP``X.,1``#J#2"@X7\]PN,_,,/C!""3Y0$@0N($ +M((/E_O__ZP0`H.$*$*#A_O__ZP0`H.$$$(WB_O__ZP``4.,!```:``#@XP`` +M`.H``*#C+-"-XO"%O>CP3RWI4]]-X@)0H.$#8*#A`$20Y00`H.'^___K``!0 +MXZ@```K,.P/C`S"4YP``4^.D```:)#P#XP,PE.<``%/CH```"N$[`^,#,-3G +M``!3XYP```H8-=3E`0!3XP,``!H$`*#A_O__ZP``H..6``#J;#"4Y2(-$^,# +M```*!`"@X?[__^L``*#CCP``ZBPZ`^,#,)3G``!3XPL```H!`%/C"0``"@4` +M4^,%(*`3+#H#$P,@A!<`(*#C?3H#XP,@Q.<$`*#A`1"@X_[__^L$`(WB`!"@ +MXU$OH./^___KM##5X4\/4^,;```:MC#5X0(`$^-T```*`5#6Y2``5>,@4*"C +M"`"-XA00AN(%(*#A_O__ZP10C>7^___K#1"@X7]=P>,_4,7C!#"5Y0$P@^($ +M,(7E!`"@X000C>(!(*#C_O__ZP!`H.$$,)7E`3!#X@0PA>7^___K6```Z@L` +M4^-3``":!@"@X6@1G^4,(*#C_O__ZP$`4.--```:M(#5X0R`2.(,8(;B`'"@ +MXP>@H.$DD*#C!+"-XC(``.H!,-;D`8!(XD@`4^,"8(8"`H!(`BP```H&``"* +M00!3XP)@A@("@$@")P``"D,`4^,D```:'0``ZE,`4^,&```*5`!3XP%@A@(! +M@$@"'@``"E``4^,;```:%P``Z@``6.,8``#:`5#6Y`&`2.(``%7C"P``"@4` +M6.$)``"ZF0<#X%(?C>(#(('@1%$"Y0,PB^`$`(/B!A"@X04@H.'^___K`7"' +MX@5@AN`(@&7@!@``Z@%@AN(!@$CB`P``Z@)@AN("@$CB````Z@J`H.$``%CC +MRO__RO[__^L-,*#A?UW#XS]0Q>,$,)7E`3"#X@0PA>4$`*#A!!"-X@D@H./^ +M___K`$"@X00PE>4!,$/B!#"%Y?[__^L"``#J!`"@X?[__^L`0*#A``!4XP`` +MH!,````:``#@XU/?C>+PC[WHN%L``/!/+>E,T$WB`*"@X0&PH.$"@*#A%#"- +MY0"4D.4"8*#AM%#2X05PH.$%`*#A_O__ZP!`4.(+4.`#"@$`"@`0F.4-(*#A +M?SW"XS\PP^,(,)/E!R"1X`,@TC``,*`S``!3XP4``!H$`*#A!R"@X?[__^L` +M`%#C"@``"@0``.H``%?C!P``"@0`H.$'$*#A_O__ZP0`H.$'$*#A_O__ZPU0 +MX./P``#JMA#6X68G".,"`%'A`#"@$P$PH`,(`%7C`#"@TP``4^,6```*`#`` +MXP`P0.,\,)/E.#"-Y0`PU.7=`%/CW```&@(`A.(X$(WB!""@X_[__^L!`%#C +MU@``&@(,5>,"7*"C50Z)X@P`@.($$*#A!2"@X?[__^M<5XGE`%"@X\T``.H+ +M`%7C#```V@0`H.$\$Y_E#""@X_[__^L!`%#C!@``&@H`H.$+$*#A"""@X00P +MH.'S_O_K`%"@X;X``.H$`*#A_O__ZQ<`4.,`\9^7FP``ZK#S!`#$\P0`I/0$ +M`,3T!`#8\P0`'/0$`,#U!`#`]00`P/4$`,#U!`#`]00`P/4$`,#U!`#`]00` +MP/4$`,#U!`#`]00`P/4$`.3T!`#`]00`P/4$`,#U!`#`]00`9/0$``D`H.$` +M$`#C`!!`XS+Y_^N#``#J"0"@X0`0`.,`$$#C+?G_ZWX``.IL,)GE`0`3XP<` +M``H$`*#A`!``XP`00./L((GBFC8!X],PF>'^___K5']/_K``!0XP`@H!,H$)T% +M@SX-`QLS1`.3(<,`P1^@`4,I80`$`*#A`!``XP`00./^___K6P``ZG01FN4` +M(-'E`3#1Y0(`T>4``(WE`P#1Y00`C>4$`-'E"`"-Y040T>4,$(WE!`"@X0`0 +M`.,`$$#C_O__ZTL``.H!,*#C6#6)Y00`H.$`$`#C`!!`XP,@H./^___K0P`` +MZ@`PH.-8-8GE!`"@X0`0`.,`$$#C`R"@X_[__^L[``#J`#"@XT0PC>4X4(WB +M!`"@X0`0`.,`$$#C!2"@X?[__^L%`*#A`!``XP`00./^___K``!0XP`PH`-$ +M,(T%%@``"C@`C>(`$`#C`!!`X_[__^L``%#C`C"@`T0PC04.```*.`"-X@`0 +M`.,`$$#C_O__ZP``4.,%,*`#1#"-!08```HX`(WB`!``XP`00./^___K``!0 +MXPPPH`-$,(T%&%"-X@4`H.%$$(WB!""@X_[__^L*`*#A"Q"@X04@H.$4,)WE +M-N__ZP0`H.$`$`#C`!!`XP,@H./^___K!```Z@0`H.$`$`#C`!!`XP,@H./^ +M___K`%"6Y;1@UN$$`*#A_O__ZP$@@.)R(/_F`@!6X08@H#$-$*#A?SW!XS\P +MP^,(,)/E`A"5X`,0T3``,*`S``!3XP,``!H%`*#A!!"@X?[__^L`(*#A``!2 +MXPU0X!,````:`%"@XP0`H.$'$*#A_O__ZP4`H.%,T(WB\(^]Z+A;``#P1RWI +M`F"@X0!$D.4$`*#A_O__ZP``4.-!```*)#P#XP,PE.<``%/C/0``"K`PUN$! +M`%/C%0#@$_"'O1@P/`'C`Z"4Y_[__^L-(*#A?SW"XS\PP^,$()/E`2""X@0@ +M@^6$@(3BA#"4Y7@PA.4"8(;B!G"@XP@`H.%X$)3E_O__ZP$`4.,6```*>%"4 +MY04`H.$@,)#D>#"$Y080H.$'(*#A_O__ZP$`4./Q__\:!`"@X7@0E>7^___K +M``!0XP@``!H-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K``#@X_"'O>@- +M(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K!`"@X0H0H.'^___K!`"@X080 +MH.'^___K``!0XP``H!/PA[T8``#@X_"'O>AP0"WI`E"@X0!$D.4$`*#A_O__ +MZP``4.,>```*X3L#XP,PU.<``%/C&@``"@`PE>4#`%/C`_&?EP,``.K<]P0` +MU/<$`.SW!`#D]P0`%0#@XW"`O>@`4*#C!```Z@)0H.,"``#J!%"@XP```.H! +M4*#C!`"@X040H.'^___K``!0XP0```H$`*#A!1"@X?[__^L``*#C<("]Z``` +MX.-P@+WH#""0Y10PD.4#((+@$#"0Y0(`8^`>_R_A``"!Y:@PD.4,,('E$#"! +MY5`@D.44(('E#`"!Z1[_+^$$`)#E`0!PX@``H#,>_R_A'O\OX?!/+>D,T$WB +M`("@X0%0H.'^___K#1"@X7\]P>,_,,/C!""3Y0$@@N($((/E!JN(XB"@BN(@ +M.`'C`T"8YP9PH.,@L*#C2)4!XSH``.IK;D3B`$"4Y=A@AN*H$)7E!@"@X080 +M@>('(*#A_O__ZP``4.,P```*!0"@X0L0H.'^___K!`"-Y0``4.,:```*J`"0 +MY080H.$'(*#A_O__ZP@`H.$$$(WB_O__ZP``4.,*``"J4"4!X](`B.$!(*#C +M`#"@XP`@DN`!,*/@4!4!X_$@B.$$`)WE_O__ZQ8``.K9`(CA`2"@XP`PH.,` +M()+@`3"CX/D@B.$/``#J4#4!X]-@B.$!0*#C`%"@XP0`EN`%$*?@\P"(X0T@ +MH.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^L``*#C#@``Z@H`H.$$$*#A_O__ +MZP``4..___\*#1"@X7\]P>,_,,/C!""3Y0$@0N($((/E_O__ZP4`H.'^___K +M`0"@XPS0C>+PC[WHT$,MZ0C03>($`(WE`$21Y00`H.'^___K``!0XS````H` +M,`#C`#!`XP`PD^4``%/C'@``&FPPE.40`!/C&P``"@00G>6H,)'E`"#3Y0$` +M4N,&```:`2#3Y0``4N,3```:`C#3Y5X`4^,0```:!P``ZC,`4N,-```:`2#3 +MY3,`4N,*```:`C#3Y?\`4^,'```**#4!XP,PE.=``%/C`P``F@0`H.'^___K +M`0!0XQ4```H$`*#A!!"-XO[__^L``%#C!P``ND@U`>/3@(3A`6"@XP!PH.,& +M`)C@!Q"IX/,`A.$(``#J4#4!X].`A.$!8*#C`'"@XP8`F.`'$*G@\P"$X00` +MG>7^___K``"@XPC0C>+0@[WH$$`MZ0!`4.(0@+T(_O__ZPT@H.%_/<+C/S## +MXP0@D^4!((+B!""#Y00`H.'^___K``!0XPH```I6/83B`!`/X8``#/$$(+/E +M`0""XP``@^4!\"'A`0`2XP$``!I6#83B_O__ZPT@H.%_/<+C/S##XP0@D^4! +M($+B!""#Y?[__^L0@+WH$$`MZ0%`H.$(/`/C`S"0Y[`AD^4",*#A"!"SY0$` +M$>,)```*```/X8``#/$`$)/E`<#!XP#`@^4`\"'A`0`1XP$```H$`)+E_O__ +MZP0`H.'^___K$("]Z!!`+>D!0*#A8!"1Y0``4>,````*_O__ZP`PH.-@,(3E +M$("]Z/!!+>D!8*#A`G"@X0%0H.$`0*#C0`"5Y0``4.,````*_O__ZP%`A.($ +M4(7B"`!4X_?__QH,`);E``!0X_"!O0@'$*#A_O__Z_"!O>CP02WI`4"@X0(` +MH.'^___K#`"$Y0``4.,4```*?P^`X@,`@.*@!*#A@`2@X1``A.4`4*#C8%"$ +MY05@H.'0<*#C!@"@X0<0H.'^___K0`"$Y0``4.,%```*`5"%X@1`A.((`%7C +M]?__&@$`H./P@;WH``"@X_"!O>AP0"WI`$"@X0%@H.$"4*#A_O__ZP4`4.$` +M4*`Q``!6XP4```H4$)3E"0"4Z`$08^`&(*#A!3"@X?[__^L0,)3E!3"#X!`P +MA.4$,)3E`S!EX`0PA.4%`*#A<("]Z#!`+>D4T$WB`$"@X0``4>,5```*U#"1 +MY2``4^,2``"*!CR#X@TP@^(#,8#@!#"3Y0$`4^$,```:$%"-X@$@H..P(67A +M`@"%XN`0@^(&(*#C_O__ZP@\`^,#`)3G!!P(XPT@H.$`,*#C_O__ZQ30C>(P +M@+WH,$`MZ1303>(`0*#A``!1XQ4```K4,)'E(`!3XQ(``(H&/(/B#3"#X@,Q +M@.`$,)/E`0!3X0P``!H04(WB`2"@X[`A9>$"`(7BX!"#X@8@H./^___K"#P# +MXP,`E.<#'`CC#2"@X0`PH./^___K%-"-XC"`O>@00"WI`$"@X0`@`..T,P'C +M`"!`XP,@@.>X,P'C`P"$YTX-@.(D`(#B`!"@XP$@H.'^___K`"``X^@S`>,` +M($#C`R"$Y^PS`>,#0(3G3PV$XA@`@.(`$*#C`2"@X?[__^L0@+WH$$`MZ0`P +M`.,`,$#CP#&!Y<01@>4;#H'B`!"@XP$@H.'^___K$("]Z!!`+>D`0*#A`#`` +MXP`P0.-H-(#E;`2$Y44.@.((`(#B`!"@XP$@H.'^___K`#``XP`P0..D-(3E +MJ$2$Y4D.A.($`(#B`!"@XP$@H.'^___K`#``XP`P0.,P-83E-$6$Y5(.A.(` +M$*#C`2"@X?[__^L0@+WH$$`MZ?[__^L0@+WH$$`MZ?[__^L0@+WH$$`MZ?[_ +M_^L0@+WH\$\MZ0S03>(`0*#AR#@!XP,PD.<"`%/C)@``&@!0`.,`4$#C!0"@ +MX0`0H.,!*Z#C_O__ZR=LA.(P8(;B!0"@X080H.$!*Z#C_O__ZS![`N,'D-3G +M*(<"XPBPU.5C#83B"`"`X@`0H.-P(@'C_O__ZP8`H.$% +M$*#A`2N@X_[__^L'D,3G"+#$YP0PG>4*,(3G`""@XS`\`>,#((3G`2"@XS0\ +M`>,#((3G$0``Z@`PH./(*`'C`C"`Y\PH`>,",(#GT"@!XP(P@.,!,(#G-!P!XP$@@.<8*@'C`C#`YPS0C>+PC[WH +M\$(`D*#A`F"@X=T`4>,Z```:`0R@X_[__^L`H*#A`!"@XP$LH./^ +M___K"@"@X0`0`.,`$$#C$B"@X_[__^L14(KB`7#6Y0)PA^(!#%?C`7R@(P`` +M5^,-```*`#"@XP-`H.$`@`#C`(!`XP4`H.$($*#A`R#6Y_[__^L`4(7@`4"$ +MXG1`[^8$,*#A!`!7X?7__XH%`*#A`!``XP`00.,"(*#C_O__ZPU`H.$-`*#A +M`!"@XQ`@H./^___K`3"%X@,P:N!S,/_F`0Q3XP$\H".T,,WA"#P#XP,`F><" +M'`CC#2"@X0HPH.'^___K``!:XP(```H*`*#A`1R@X_[__^L0T(WB\(>]Z!!` +M+>D`0*#A"#P#XP,`D.?^___K!`"@X?[__^L$`*#A_O__ZP0`H.'^___K$("] +MZ!!`+>D`0*#AJ#P#XP,PD.<``%/C`@``&C``G^7W%P#C_O__ZP``D^4``%#C +M`@``&A@`G^4Y%P#C_O__ZP(,@.+^___K!`"@X?[__^L0@+WHD#0``!!`+>D` +M0*#A_O__ZP0`H.'^___K"#P#XP,`E.?^___K#`"4Y0``4.,0@+T(_O__ZPX0 +MH.,!(*#C_O__ZQ"`O>@00"WI`$"@X?[__^L`,`#C`#!`XP`0D^52#H3BR!"! +MXO[__^L0@+WH$$`MZ?[__^L0@+WH$$`MZ?[__^L0@+WH`0"@XQ[_+^$`,*#C +M"#"!Y0PP@>4!`*#C'O\OX1[_+^$>_R_A$$`MZ0`P`.,`,$#C)#"`Y2@`@.44 +M`(#B`!"@XP$@H.'^___K$("]Z!!`+>G^___K$("]Z'!`+>D`4*#A`4"@X0@P +MD>4!,$/B"#"!Y4``D>7^___K`#"@XT`PA.5$,,3E.##4Y0``4^-P@+T8!0"@ +MX3PV`>,#$)7G`""@XP0PH.'^___K<("]Z/!'+>D`8*#A`7"@X5>-@.(8@(CB +M"$"1Y0``5.-,```*?#"1Y:@PA.6`,)'EG#"$Y70PD>50,(3E;#"0Y1``$^,B +M```*`0"@X310\.4-&X;B$1"!X@8@H./^___K``!0XQH``!H!H!7B!P``"@8` +MH.'^___K`%"@X00`H.$@$*#C_O__ZP"0H.$%``#J6PV&XC@`@.(T$(?B_O__ +MZP!0H.$`D*#C``!5XP@```H(/`/C`R"6YQ0@A.4$`*#A`Q"6Y_[__^L``%KC +M&@``"@E`H.'^___K"#P#XP,PEN=J/X/B`%"3Y?[__^L``%7C!0``"FPPEN4H +M`!/C`@``"@8`H.$$$*#A_O__ZV0PU.4?,@``%'C`@``"@$`H.$($*#A_O__ZQ`V`>/3@(;A`4"@XP!0H.,$`)C@ +M!1"IX/,`AN$``*#C\(>]Z'!`+>DXT$WB`$"@X0%0H.$D-P+C`S"0YP``4^,# +M```:_O__ZR0W`N,#`(3G$@``ZO[__^LD-P+C`R"4YP`@8N!O-P'C`P!2X0@` +M`(H!(*#C*#<"XP,@Q.<`(*#C)#<"XP,@A.(%$*#A'""@X_[__^L,,)WE"#"#XPPPC>40``#J"#P#XP,`E.<` +M4*#C`%"-Y2`PH.,$,(WEN!"$X@4@H.$`,.#C_O__ZPP`C>(%$*#A'""@X_[_ +M_^L,,)WE!#"#XPPPC>4!,*#CL#'-X0Q@C>(&`(;BN!"$X@8@H./^___K*%"- +MX@4`H.$`$*#C$""@X_[__^L<,*#CO#+-X0@\`^,#`)3G!AP(XP4@H.$&,*#A +M_O__ZSC0C>)P@+WH$$`MZ0%`H.$L`)'E``!0XP````K^___K0`"4Y0``4.,` +M```*_O__ZP$`H.,0@+WH<$`MZ0%`H.$`4*#C.%#!Y04`H.'0$*#C_O__ZRP` +MA.5`4(3E1%#$Y1!0A.444(3E*%"$Y210A.4<4(3E(%"$Y3Q0A.484(3E!0!0 +MX`$`H!-P@+WH`0!1XP8``!JV,$#B#@!3XP`!@.#Z#H"23@V`@@@`@((>_R_A +M#@!0X[0)``,>_R\!#0!0XP``H,,``8#0E@Z`T@<`@-(>_R_A'O\OX1!`+>D` +M``#C``!`XP`0`.,`$$#C_O__ZP``H.,0@+WH$$`MZ0%`H.$```#C``!`XQ`0 +MG^7^___K##"@XP`PA.4``*#C$("]Z/A=```00"WI````XP``0.,($)_E_O__ +MZP``H.,0@+WH%%X``!!`+>D```#C``!`XP@0G^7^___K``"@XQ"`O>@P7@`` +M$$`MZ0```.,``$#C"!"?Y?[__^L``*#C$("]Z%!>```00"WI````XP``0.,( +M$)_E_O__ZP``H.,0@+WH:%X``/!!+>D`4*#A`4"@X0!@4N($<(`27'"``@`` +M`.,``$#C^!"?Y08@H.$$,*#A_O__ZP``5.,$```:``"@XP``A^4!,*#C;#.% +MY?"!O>@"/`KC#S!`XP,`5.$<```*!@``B@$`5.,-```*`3P*XP\P0.,#`%3A +M'0``&@P``.H$/`KC#S!`XP,`5.$4```*!3P*XP\P0.,#`%3A%```&@<``.H` +M,*#C`#"'Y0$PH.,6``#J`3"@XP`PA^4`,*#C$@``Z@4PH.,`,(?E`#"@XPX` +M`.H",*#C`#"'Y00PH.,*``#J!#"@XP`PA^4&,*#C!@``Z@```.,``$#C!!"@ +MX?[__^OT#0_C_P]/X_"!O>@``%;C``"@`VPSA14``*`3\(&]Z(!>```00"WI +M````XP``0.,($)_E_O__ZP``H.,0@+WHF%X``!!`+>D```#C``!`XP@0G^7^ +M___K``"@XQ"`O>BT7@``$$`MZ0```.,``$#C"!"?Y?[__^L``*#C$("]Z,Q> +M```00"WI````XP``0.,($)_E_O__ZP``H.,0@+WHZ%X``!!`+>D```#C``!` +MXP@0G^7^___K``"@XQ"`O>@$7P``$$`MZ0```.,``$#C"!"?Y?[__^L``*#C +M$("]Z"!?```00"WI````XP``0.,($)_E_O__ZP``H.,0@+WH.%\``!!`+>D` +M``#C``!`XP@0G^7^___K``"@XQ"`O>A87P``$$`MZ0```.,``$#C"!"?Y?[_ +M_^L``*#C$("]Z'!?```00"WI````XP``0.,($)_E_O__ZP``H.,0@+WHB%\` +M`!!`+>D```#C``!`XP00G^7^___K$("]Z+!?```00"WI````XP``0.,($)_E +M_O__ZP``H.,0@+WHW%\``!!`+>D```#C``!`XP@0G^7^___K``"@XQ"`O>C\ +M7P``$$`MZ0$PH.,",,#E8A@!X[`0P.$#$*#C`Q#`Y0<0H.,$$,#E$3#`Y0,` +M4N,)```:`##@XP4PP.4`,*#C!C#`Y0$@H.,)(,#E:2#@XP\@P.40,,#E$("] +MZ`(`4N,``%(3"```&@`PX.,%,,#E!C#`Y0$PH.,),,#E+""@XP\@P.40,,#E +M$("]Z`@`G^4($)_E_O__ZQ"`O>CD-```'&```!!`+>D(T$WBJ"P#XP(@D.<` +M0)+E%!"@XP<@C>)HRP/C#^"@X0SPD.<```#C``!`XS00G^4'(-WE_O__ZY`` +ME.44`(#B`!"@XP<@W>7#___KE`"4Y10`@.(!$*#C!R#=Y;[__^L(T(WB$("] +MZ#A@```00"WI``!0XP(``!H<`)_E.1<`X_[__^L```#C``!`XPP0G^7^___K +M``"@XQ"`O>@,-0``4&```!!`+>D``%#C`@``&AP`G^4Y%P#C_O__ZP```.,` +M`$#C#!"?Y?[__^L``*#C$("]Z`PU``!H8```<$`MZ0%`H.$`4%#B`@``&EP` +MG^4Y%P#C_O__ZP```.,``$#C3!"?Y00@H.'^___K``!4XPP```H"7(7B!`"@ +MX?[__^L$`*#A_O__ZPPPE>4$`%/A!```&AP`G^7^___K`#"@XPPPA>40,,7E +M``"@XW"`O>@,-0``@&```#0U``#P1RWI`'"@X0%0H.$(/`/C`X"0YP```.,` +M`$#C;!&?Y0<@H.'^___K%@Z@X_[__^L`H*#A`$"@X0``4.,#```:3`&?Y?[_ +M_^L+4.#C30``Z@```.,``$#C*!"@X_[__^L``(KE``!0XP,``!HD`9_E_O__ +MZPM0X.,_``#JH%"`Y:@\`^,#H(?G:*&(Y0``FN4``%#C`@``&OP`G^4Y%P#C +M_O__ZP)<@.(`8*#C#&"%Y1!@Q>4`H(7E!'"%Y0A@A>6##X#B_O__ZR%@Q>4B +M8,7E(V#%Y1"`BN4&,*#C!#"*Y0`PFN4!(*#C*""#Y0D@H.,P(,/E"2R@X[(C +MP^$$$*#C@A##Y0`@X..P*,/A3B,`X[`BP^$`(`#C`"!`X[4/@N(0`(/EOR^" +MXC@@@^4T$(/E`"``XP`@0./X$(+BD!"#Y4DO@N*4((/E``":Y?[__^L`4%#B +M!```JD``G^7^___K``":Y?[__^L#``#J`#":Y:`PD^4P,HCE`@``Z@H`H.$6 +M'J#C_O__ZP4`H.'PA[WHH&```&0U``"(-0``##4``*@U```00"WI`2"@X0`` +M4.,"```:2`"?Y3D7`./^___K!$*0Y0```.,``$#C-!"?Y?[__^O;#83B,`"` +MXO[__^LH.@/C`S"4YRPJ`^,"()3G`@!3X2PJ`Q,",(07``"@XQ"`O>@,-0`` +MZ&````3@+>4,T$WB``!0XP(``!HL`)_E.1<`X_[__^L```#C``!`XQP0G^7^ +M___K#0"@X0@0H./^___K``"@XPS0C>(`@+WH##4``!!A```00"WI`2"@X0`` +M4.,"```:2`"?Y3D7`./^___K!$*0Y0```.,``$#C-!"?Y?[__^ML,)3E`0`3 +MXP8```H$`*#A_O__ZP0`H.'^___K!`"@X0$0H./^___K``"@XQ"`O>@,-0`` +M+&$``/!/+>E<``%/C`@``&E`*G^7W%P#C_O__ZP`PD^4``%/C`@`` +M&C@*G^4Y%P#C_O__ZR0RT^4``%/C#V#@$WP"`!H%`*#A'!J?Y?[__^L``%#C +M=`(`"FPPE>40`!/C<0(`&@@PE.4``%/C<`(`"@PPE.4``%/C;0(`"B``4^,& +M8."#:P(`BC1@C>(&`*#A`!"@XR0@H./^___K#""4Y30@C>4$`(;B"!"4Y?[_ +M_^L$`)3E``!0XPH```H`$-#E`2#0Y0(PT.4#P-#E`,"-Y03`T.4$P(WE!0#0 +MY0@`C>6("9_E_O__ZVP@E>4B#1+C!```"G@)G^5L&9_E_O__ZP]@X.-+`@#J +M_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B!""#Y81PA>*$,)7E>#"%Y0!@H.,X +MH(WB!H"@XP<`H.%X$)7E_O__ZP$`4.,`<*`#/0``"GA@E>4`,);E>#"%Y000 +ME.4``%'C!```"B``AN(((*#A_O__ZP``4./N__\*"!"4Y0``4>,)```*#""4 +MY0``4N,&```**#"6Y0,`4N'E__\:+`"&XO[__^L``%#CX?__"@00E.4``%'C +M#P``"B``AN(((*#A_O__ZP$`4./9__\:G`B?Y?[__^LH,);E6`"-XB0P(.4$ +M`(#B+!"&XB@@EN7^___K`7"@XQ(``.H(,)3E``!3X\O__PH,,)3E``!3X\C_ +M_PHL`(;B"A"@X30@G>7^___K`0!0X\+__QHH();E-#"=Y0,`4N&^__\:-`B? +MY?[__^L!<*#C#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__ZP$P)^(``%;C +M`3"#`P$`$^,#```*_`>?Y?[__^L/8.#CZ@$`Z@4`H.%X$);E_O__ZP``4./B +M`0`*`2"@XS0\`>,#((7G`#"@X\PH`>,",(7G)"D!XP(PA>?(*`'C`C"%YS`L +M`>,",(7G(&"4Y0```.,``$#CH!>?Y08@H.'^___K``!6XP`@H`,P/`$#`R"% +M!P,```H#`!;C!""@$S`\`1,#((47$&"4Y0```.,``$#C:!>?Y08@H.'^___K +M`0!6XQ````H%```Z!`!6XQ0``!H#(*#CR#@!XP,@A><3``#J`""@X\@X`>,# +M((7GVC^#X@,PE><#`%/C`B""@L@X`8,#((6'"0``Z@$@H./(.`'C`R"%YP`@ +MH./;/X/B`R"%YP(``.H`(*#CR#@!XP,@A>=CK87B"*"*XB@PE.4``%/C`&"@ +M`P4```H*`*#A+!"4Y0$@H.,8_?_K`&!0XIL!`+K(.`'C`S"5YP,`4^,!`%,3 +M+@``&EDPU.44,(WE6##4Y10@G>4$`%+CCP$`B@``4^.-`0`*!0!3XP6PH),- +ML*"##("+X@@`H.'^___K`)"@X0!PH.$``%#C"V#@`X,!``H`$*#C"""@X?[_ +M_^L(L(GE`(")Y0T`6^,%,*`#S"@!`P(PA0=8((("`C"%!Q0@G>4",8+C!#") +MY0P`B>)4$)3E"""9Y?[__^L%`*#A"1"@X?[__^L``%#C4D,(WE +M`P!6X0`PH!,!,*`##@U4XP,@H)$!((.#``!2XP8```H`$*#C&"H!XP(0Q>(L,(WB_O__ZP$`4.,- +M```:`B"@X\@X`>,#((7G`B""XMH_@^(#((7G)@R%XB0`@.()$*#A*""=Y0(@ +M@N+^___K0`2?Y?[__^L``%OC%P``"B00G>4``%'C%```V@L`H.$"$('B,""- +MXBPPC>+^___K`0!0XPT``!H"(*#CR#@!XP,@A><%((+BVC^#X@,@A>4!,$/B#P!3XP/QGY<`(*#C,3Z#X@,@A><3``#J`B"@XR0Y`>,#((7G +M`B""XC$^@^(#((7G#```Z@0@H.,D.0'C`R"%YP(@@N(Q/H/B`R"%YP4``.H% +M(*#C)#D!XP,@A><`(*#C,3Z#X@,@A><:``#J +M`2"@X\PX`>,#((7G`""@X]H_@^(#((7G$P``Z@(@H./,.`'C`R"%YP(@@N+: +M/X/B`R"%YPP``.H$(*#CS#@!XP,@A><"((+BVC^#X@,@A><%``#J!2"@X\PX +M`>,#((7G`""@X]H_@^(#((7G`&"@XQ@Z`>,#8,7G%#*?Y=@SD^4@,(WE6#"- +MXCQ@(^4'`*#A!!"@X08@H.'^___K`*"@X2$``.H(,(K@%#"-Y0`PT^7=`%/C +M%P``&@(`B.(``(K@(!"-X@0@H./^___K`0!0XQ```!H(@(K@`2#8Y0(@@N(" +M#%+C`BR@HQP\`>,#((7G&@R%XAD`@.(4$)WE_O__ZP``6>,``%L#`2"@`Q@Z +M`0,#(,4'"```Z@B`BN`!,-CE`C"#X@-@AN!V8/_F!H"@X1PPG>4#`%;AV?__ +M.@`@H.-8,(WB/"`CY0<`H.$$$*#A_O__ZP"`4.(`8*`#-```"K`WE>4``%/C +M!0``"L07E>4`8*#CQ&>%Y0,`H.'^___KL&>%Y1P`G>7^___KL`>%Y0``4.,% +M```:^`"?Y?@0G^4'*0#C_O__ZP!@H.,@``#J"!"@X1P@G>7^___K'#"=Y<0W +MA>4`8*#C&0``Z@``5N,4``"Z!0"@X3`\`>,#$)7G_O__ZP4`H.$T$(WB_O__ +MZP``4.,(```*H`"?Y<@X`>,#$)7G!#"#X@,@E>=8,(/B`S"5Y_[__^L"``#J +M`&#@XP```.H58.#C!@"@X5S0C>+PC[WH!P"@X000H.'^___KX?__Z@D`H.$( +M$*#A_O__ZUY@X./S___J##4``$1A```8-@``0#8``&`V``!T-@``B#8``%QA +M``!\80``X#8``)AA``#T-@``##<``!PW```H-P``W%T``#@W``"X80``6#<` +M`'!`+>D"4*#A`V"@X0``4.,"```:X`"?Y3D7`./^___K!$*0Y0``4N,O```* +M;#"4Y0@`$^,8```*`0`3XQ8```H"`*#AX!"$X@8@H./^___K``!0XR0```H` +M,);E0""#XP`@AN6<)@'C`B#4YP$@@N*B(*#A7R!"XAD@QN7`,(/C`#"&Y00` +MH.'<$(3B_O__ZP`Q@."#,*#AOC'&X6PPE.4@`!/C`P``&D``$^,!```:$``3 +MXPX```H!`!/C#```"EL-A.(X`(#B!1"@X?[__^L``%#C!@``&B``G^4@$)_E +M_O__ZP$`X.-P@+WH`0#@XW"`O>@``*#C<("]Z`PU``"H-P``T&$``/!'+>D0 +MT$WB`D"@X0"4D>4```#C``!`X\01G^7^___K;#"9Y1$`$^,$```:M`&?Y:P1 +MG^7^___K%0#@XV8``.H``%3C!P``&@```.,``$#C_O__ZPD`H.'^___K"0"@ +MX?[__^M<``#J!%"@X01@H.$$<*#A!("@X02@H.$`$-3E`2#UY0(P]N4#`/?E +M``"-Y00`^.4$`(WE!0#ZY0@`C>4```#C``!`X_[__^L`,-3E_P!3XP\``!H` +M,-7E_P!3XPP``!H`,-;E_P!3XPD``!H`,-?E_P!3XP8``!H`,-CE_P!3XP,` +M`!H`,-KE_P!3XQ4`X`,X```*_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B!""# +MY09[B>(@<(?B(#@!XP-0F><&@*#C&@``ZFL>1>((8$'B`%"5Y00`H.'8$('B +M"""@X?[__^L``%#C$0``"EPWEN4!`%/C`@``&G0WUN4``%/C"P``"FL^AN(( +M,(/BO":6Y;@6EN4$(('E`!""Y;@VAN6\-H;E"0"@X080H.'^___K!```Z@<` +MH.$%$*#A_O__ZP``4./?__\*#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__ +MZP```.,``$#C#!"?Y?[__^L``*#C$-"-XO"'O>CL80``R#<``/!%+>D4T$WB +M`<"@X0)`H.$`,*#C##"-Y0@PC>4``%#C`@``&C0"G^4Y%P#C_O__ZP12D.40 +M,)+E%""2Y0`@C>4```#C``!`XQ02G^4,(*#A_O__ZVPPE>40`!/C>P``"A`P +ME.47`%/C>```VA0`E.4``(/@_O__ZP!@4.(+4.`#(8($+B_O__ZQ``E.48`$#B``"&X`00E.44()3E_O__ZQ"`E.44,)3E +M`X"(X!B@2.(,<(;B)(!(X@<`H.$($*#A`""@XPPPC>+^___K``!0XP(```IX +M`9_E#!"=Y?[__^L'`*#A"!"@X0`@H.,(,(WB_O__ZP``4.,"```*5`&?Y0@0 +MG>7^___K!0"@X080H.$(()WE"B!BX/[__^L!`%#C%5#@$SX``!H'`*#A"!"@ +MX0`@H.,(,(WB_O__ZP``4.,`4*`#-@``"BPZ`^,#,)7G``!3XQ,``!K\`)_E +M_O__ZP4`H.$#$*#C_O__ZZ@\`^,#,)7G``!3XP(``!K(`)_E]Q<`X_[__^L` +M,)/E``!3XP$@H!,A(L,5'0``&J@`G^4Y%P#C_O__Z]T-A>(D`(#B_O__Z]X- +MA>(8`(#B_O__Z]\-A>(,`(#B_O__ZXP`G^4($)WE_O__ZR0Z`^,#,)7G`P!3 +MXP,@H!,D.@,3`R"%%RPZ`^,#,)7G"@!3XPH@H!,L.@,3`R"%%P\@H.-2.@/C +M`R#%Y]XGU>5!.@/C`R#%YP!0H.,4$)3E$#"4Y08`H.$#$('@_O__ZP```.H5 +M4.#C!0"@X130C>+PA;WH##4```AB``"(.```H#@``+0X``#<.```\$$MZ0%0 +MH.$"8*#A`$!0X@(``!H\`)_E.1<`X_[__^L$@`$*#C%""@X_[__^L!H,?E`(#'Y0$PH.,#,,?E`8!(XGB`[^8$`%CC$""@ +M@P`P`),`,$"3"("#D%PDV)4$`(?B"1"@X?[__^L4,*#CL##&X01PAN4(,(;E +M`#"@XPPPAN40,(;E%`"&XO[__^L%"XOB*`"`X@80H.'^___K^(^]Z!!`+>D% +M($+B(!@*#A`G"@X0-0H.$XD)WE/$"=Y0``4.,"```:H`V?Y3D7`./^___K`"*P +MY00@C>4$L)#E````XP``0..$'9_E"""@X0DPH.'^___K````XP``0.,0$)3E +M_O__ZP```.,``$#C"!"4Y?[__^L```#C``!`XPP0E.7^___K````XP``0.,' +M$*#A_O__ZP```.,``$#C!1"@X?[__^L(8)3E0&"&X@8`H.'^___K`%"@X0"@ +MH.$``%#C`$#@`R8#``H`$*#C!B"@X?[__^L#,*#C!2"@X00P@N0(((WE`@"@ +MX?\0H.,&(*#C_O__ZQ`@E.4"/`KC#S!`XP,`4N$8```*!@``B@$`4N,2```* +M`3P*XP\P0.,#`%+A"```&@H``.H$/`KC#S!`XP,`4N$/```*!3P*XP\P0.,# +M`%+A`@``"O1-#^/_3T_C`P,`Z@`0`.,`$$#C!P``Z@`0`.,`$$#C!```Z@`0 +M`.,`$$#C`0``Z@`0`.,`$$#C##"*X@PPC>4#`*#A$""@X_[__^L``%GC#@`` +M"@$@V>4",-GE`R`"X``PV>4#(`+@`S#9Y0,@`N`$,-GE`R`"X`4PV>4#,`+@ +M_P!3XP$PH!,<,,H5`0``&@`PH.,<,,KE)'#*Y0P@E.4``%+C!```"@00E.4` +M`%'C`0``"B4`BN+^___K"#"4Y0``4^,'```*`""4Y0``4N,$```*OC+*X3`` +MBN(`$)3E"""4Y?[__^ML$)OE"``1X_````H`1)CE````XP``0..$&Y_E_O__ +MZP`PH.,@,(KE&S#*Y;XRVN$P,(/B`P!6X=P``#H$,)KE`0!SX]D``!JX(-KA +M_S\/XP,`4N'5```:)##:Y0,`4^/2``"*8WV$X@APA^(,`)WE`!``XP`00./^ +M___K``!0XT@``!H`(*#C-#P!XP,@A.4`L(GE +M#0!2XP4PH`/,*`$#`C"$!U@@@@(",(0'`C&(XP0PB>4,,(GB!#"-Y0,`H.$P +M$(KB"""9Y?[__^L<,-KE``!3XP4```H$`*#A"1"@X?[__^L``%#C>P(`"G@" +M`.H#`%CC>`(`BF,/B.(``H3@%`"`X@00G>4(()GE_O__ZQD]B.(#,83@"""9 +MY10@@^4$`*#A!Q"@X0@@H.$`,*#C_O__ZP!`H.-H`@#JR#@!XP,PE.<"`%/C +M?P``&FP@E.4(,`#C`3!`XP,P`N```%/C>0``"EL-A.(X`(#BX!"$XO[__^L` +M@%#B`P``&K@)G^6P&9_E_O__ZUD``.H,`)WEJ!F?Y?[__^L``%#C`#"@$^@P +MB!4T/`'C`S"4YP8`4^,$`%,3S#@!`P,PE`?L,(@%'##:Y0$`4^,>```:<`F? +MY6`9G^7^___K,'"*XKXBVN$1#HCB!Q"@X1``4N,0(*`C_O__ZPP`G>5(&9_E +M_O__ZP``4.,*```:\`"(XA`0A^(((*#C_O__ZP$,B.(8$(?B"""@X_[__^L` +M(*#C(3P!XP,@Q.<$`*#A"!"@X0$@H./^___K*@``ZB0`VN4&`(#B``*$X&,- +M@.(P@(KBOB+:X0P`@.(($*#A$`!2XQ`@H"/^___K)`#:Y0H`@.(``H3@8PV` +MX@P`@.(0$(CB"""@X_[__^LD`-KE#@"`X@`"A.!C#8#B#`"`XA@0B.(((*#C +M_O__ZP$PH.,@+`'C`C#$YR00VN6^+T+B`A"$YP0`H.$'$*#A)"#:Y?[__^LL +M.@/C`S"4YPT`4^,.(*`#+#H#`P,@A`<$`*#A_O__ZP!P4.(1```*#`"=Y3`8 +MG^7^___K``!0XP`PH!/H,(<5-#P!XP,PE.<&`%/C!`!3$P8``!K,.`'C`S"4 +MY^PPA^4`0*#C`@``ZA5`X.,```#J`$"@X_0'G^7<%Y_E!""@X?[__^O5`0#J +M$``1X\X!``H``%GC`P``"@@`G>4)$*#A!B"@X_[__^L`=)CE`#"@XR`PBN4; +M,,KEOC+:X4`P@^(#`%;AX`$`&@0PFN4!`'/C!P``&K@@VN'_/P_C`P!2X0,` +M`!HD,-KE`P!3X]8!`(H&``#J6PV'XC@`@.($$(KB_O__ZP"`4.+%`0`:S`$` +MZ@P`G>5(%Y_E_O__ZP``4./'`0`*#`"=Y407G^7^___K`0!PX@``H#,``%#C +M4P``"B20VN6^LMKA`3![X@`PH#,#`%GC`3"#@P``4^.Z`0`:``!;XP!`H`,$ +M@*`!#0``"@4`6^,%L*"3#;"@@PR`B^((`*#A_O__ZP!`4.*L`0`*!`"@X0`0 +MH.,((*#A_O__ZPBPA.4`@(3E!)"$Y0RPA.(+`*#A,!"*X@@@E.7^___K'##: +MY0``4^,@```*`""@XS0\`>,#((?G`3"@X\PH`>,",(?G6"""X@(PA^<(,)3E +M#0!3XP4PH`-8($("`C"'!U@@@@(",(<'T#@!XP.0A^=C#XGB``*'X!0`@.(+ +M$*#A"""4Y?[__^L9/8GB`S&'X`@@E.44((/E!P"@X0P0A.(((-3E"3"@X0/^ +M_^M7`0#J8P^)X@`"A^`4`(#B"Q"@X0@@E.7^___K&3V)X@,QA^`(()3E%""# +MY0<`H.$,$(3B""#4Y0DPH.'S_?_K1P$`Z@"`H.,!,*#C``!3XW````IL,)?E +M$``3XVT```H<,-KE``!3XV(!`!H``%#C$@``"B0`VN4&`(#B``*'X&,-@.*^ +M(MKA#`"`XC`0BN(0`%+C$""@(_[__^L!(*#C)#D!XP,@A^>^,MKA#0!3XP0@ +M@@(D.0$#`R"'!SP``.H,`)WE5!6?Y?[__^L``%#C(0``&@(@H.,D.0'C`R"' +MYR0`VN4&`(#B``*'X&,-@.(P0(KBOB+:X0P`@.($$*#A$`!2XQ`@H"/^___K +M)`#:Y0H`@.(``H?@8PV`X@P`@.(0$(3B"""@X_[__^LD`-KE#@"`X@`"A^!C +M#8#B#`"`XA@0A.(((*#C_O__ZP$@H.,A/`'C`R#'YQ4``.H,`)WEQ!2?Y?[_ +M_^L``%#C#0``&@0@H.,D.0'C`R"'YR0`VN4&`(#B``*'X&,-@.*^(MKA#`"` +MXC`0BN(0`%+C$""@(_[__^L"``#J`""@XR0Y`>,#((?G)"#:Y2@Y`>,#((?G +M`2"@X[X_@^(#(,?GOS]#X@,@E^=8,$/B`R"'YP<`H.$P$(KB,#()?G`@!2XP`PH!,!,*`#``!8XP`PH`,``%/C[@``"FPPE^40`!/CZP`` +M"APPVN4!`%/C6```&C!`BN*^(MKA$0Z(X@00H.$0`%+C$""@(_[__^L,`)WE +MK!.?Y?[__^L``%#C!@``&@$PH./L,(CEOC+:X0T`4^,%,*`#[#"(!1D``.H, +M`)WE=!.?Y?[__^L``%#C#0``&@(PH./L,(CE\`"(XA`0A.(((*#C_O__ZP$, +MB.(8$(3B"""@X_[__^L!(*#C(3P!XP,@Q^<&``#J#`"=Y303G^7^___K``!0 +MXP0PH`,`,*`3[#"(Y1P`H./^___K`*"@X0``4.,A```*&`"@X_[__^L`D*#A +M`+"@X0``4.,#```:"@"@X1P0H./^___K%P``ZA0`BN+^___K%2"@X[`@RN$$ +MD(KE&#"@XP@PBN4`,*#C##"*Y1`PBN7L,)CE!C#)Y0D`H.'@$(CB!B"@X_[_ +M_^L(`(GB$1Z(XA`@H./^___K!0N'XB@`@.(*$*#A_O__ZP!`H./H0(CE`3"@ +MXW0WR.5V``#J``!0XQ(```HD`-KE!@"`X@`"A^!C#8#BOB+:X0P`@.(P$(KB +M$`!2XQ`@H"/^___K`2"@XR0Y`>,#((?GOC+:X0T`4^,$(((")#D!`P,@AP<\ +M``#J#`"=Y0@2G^7^___K``!0XR$``!H"(*#C)#D!XP,@A^,#()?GS#@!XP,@A^<'`*#A,!"*XG(@[^8D,-KE??S_ZP<`H.'^___K +M``!0XRH```H`0*#CZ$"`Y20Y`>,#,)?G[#"`Y0L``.H``%3C"0``"@0`H.$( +M$*#A_O__ZP!`H.,$``#JJ`"?Y00PG>4$()/E_O__ZP!`H.,%`*#A!A"@X?[_ +M_^L$`*#A%-"-XO"/O>@`0*#C````ZEY`X.-D`)_E3!"?Y00@H.'^___K"0"@ +MX0L0H.'^___K[O__Z@P`G>4`$`#C`!!`X_[__^L!`'#B``"@,P`PH..4_O_J +M`$"@X^3__^H50.#CXO__Z@PU``!,8@``9&(``(PY``!T.0``K#D``'PY``#0 +M.0``<#D``(0Y``#<.0``\$$MZ0C03>("4*#A``!0XP(``!J@`9_E.1<`X_[_ +M_^L"#(#B!$"0Y0!@D.4!`*#A_O__ZP``4.-<```:!`"@X7@1G^7^___K``!0 +MXU<```H$@);E:`&?Y6`1G^4((*#A!3"@X?[__^L%,%C@`3"@$P(`5>,&```* +M`P!5XRP```H!`%7C7@#@$P!PH`-(```:.0``Z@``4^,T```*)#H#XP,PE.<# +M`%/C,```&MT-A.(D`(#B_O__Z]X-A.(8`(#B_O__Z]\-A.(,`(#B_O__ZR0Z +M`^,#,)3G`0!3XP$@H!,D.@,3`R"$%R@Z`^,#,)3G+"H#XP(@E.<"`%/A+"H# +M$P(PA!6P`)_EI!"?Y20Z`^,#()3G"#"#X@,PE.?^___K +M`7"@XQ$``.H``%/C#@``"BPZ`^,#,)3G``!3XPH```HD.@/C`S"4YP,`4^,& +M```*`R"@XR0Z`^,#((3G!'"@XP(``.H!<*#C````Z@1PH.,$4(;E!`"@X0<0 +MH.'^___K``!0XP2`A@4``.`#!0``"@0`H.$'$*#A_O__ZP``H.,```#J``#@ +MXPC0C>+P@;WH##4``(!B````.@``)#H``/!`+>D,T$WB`5"@X0)`H.$``%#C +M`@``&L@!G^4Y%P#C_O__ZP1BD.4`((WE````XP``0..P$9_E!B"@X04PH.'^ +M___K"0!4XU<``(H!,*#C$T2@X;XS`.,`,$#C`S`$X```4^,`0*`34P``&D`` +M%.--```*J#P#XP,PEN<``%/C`@``&EP!G^7W%P#C_O__ZP!PD^4``%?C`@`` +M&D0!G^4Y%P#C_O__ZP)\A^(```#C``!`XS01G^7^___K``!5XP!`H`,58.`# +M+P``"@4`H.'^___K`""@X04`H.$0$(?B_O__ZP``4.,(```:#$"7Y0``5.,% +M```*]`"?Y>P0G^4%(*#A_O__ZP!@H.,>``#J"`"@XP$0H.,!(*#A_O__ZP!` +M4.(+8.`#%P``"B,C`.,!/*#CLR"$X00`H.$%$*#A$""@X_[__^L`,*#C#S#$ +MY:`PG^7@,(3E!#"@X0!DH^4X+0/C!""#Y00`H.'^___K`&!0XA<``!H,0(?E +M$`"'X@40H.$1(*#C_O__ZPPPE^4`8(WE````XP``0.-,$)_E!""@X?[__^L# +M``#J````XP``0./^___K`$"@XP```.,``$#C!!"@X?[__^L$`*#A#-"-XO"` +MO>@$`*#A_O__ZP!`H./H___J##4``)QB``"\8@``?#H``-AB``#P3RWI%-!- +MX@!`H.$!(*#A`(21Y0```.,``$#CW!&?Y?[__^M0()3E!P!2XVX``)JH$)3E +M`##1Y0``4^-J```:`A"!X@$`T>4`,-'E`#2#X0,0H.$#`%+A8P``.@X`4^," +M```*F`&?Y?[__^M>``#J!`"@X?[__^NH8)3E!E"@X0`PUN4!$-;E`12#X0PP +M`>((`%/C)0``&H``$>,`L*`#`K"@$P,<`>(##%'C&)"@$QZ0H`,-<*#A!F"@ +MXPT`H.$$$(7B!B"@X?[__^L(H(WB"@"@X0H0A>(&(*#A_O__ZPL0B>`$`*#A +M!A!!XO[__^NH4)3E!0"@X0T0H.$&(*#A_O__ZP8`A>`*$*#A!B"@X?[__^OL +M`)_E_O__ZP0`H.$(/`/C`Q"8Y_[__^LQ``#J_!`!XM``4>,I```:4*"4Y0@` +MH.$&$*#A"B"@X0$PH./^___K``!0XR,``+I3#8CB(`"`XO[__^L`<%#B'@`` +M"@@`H.$($(?B_O__ZP`0H.-;$,?E;`"7Y6@@H./^___K;%"7Y2A0A>(%`*#A +M!A"@X0H@H.'^___K%*"'Y;8AU>$B(J#AW#<`X[,@B.&^(,?ALR"8X0$@@N*S +M((CA%#"7Y1@PA^4(`*#A!Q"@X?[__^L!``#J(`"?Y?[__^L$`*#A_O__ZP`` +MH.,4T(WB\(^]Z%AC``#P.@``%#L``"P[``#P02WI*-!-X@!PH.$!4*#A`D"@ +MX0-@H.$`(*#C)""-Y2`@C>4$@*#A`0"@X000H.$D,(WB_O__ZP``4.,"```* +M)#"=Y0``4^,)```:!0"@X0@0H.$`(*#C(#"-XO[__^L``%#C&`$`"B`PG>4` +M`%/C%0$`"@``5^,3`0`*`@!6XV0```H$`%;CZP``"@$`5N,-`0`:`#"@XQ0P +MC>4<,(WE"#"-Y0PPC>50,*#C"3#-Y0TPX.,*,,WE!#"@XPLPS>4`9)?E```` +MXP``0.,$%)_E!R"@X00PH.'^___K``!4XP``H-/Y``#:!D"@X04`H.$($*#A +M`""@XQ0PC>+^___K`'!0XAT```J`-Y;E``!3XP4```J0%Y;E`&"@XY!GA.4# +M`*#A_O__ZX!GA.44`)WE_O__ZX`'A.4``%#C!0``&I0#G^6,$Y_EZR\`X_[_ +M_^L5`.#CW0``Z@<0H.$4()WE_O__ZQ0PG>60-X3E!`"@X=T0H.,(((WB`3"@ +MX_[__^L4$)WE`0"%X`@08>``(*#C'#"-XO[__^L`4%#B&```"J`WE.4``%/C +M!0``"K07E.4`8*#CM&>$Y0,`H.'^___KH&>$Y1P`G>7^___KH`>$Y0``4.,% +M```:_`*?Y?02G^4+(`'C_O__ZQ4`X..W``#J!1"@X1P@G>7^___K'#"=Y;0W +MA.4!(*#C(#0!XP,@Q.<``*#CK0``Z@`PH.,<,(WE&#"-Y0`TE^4``%3C@``` +MV@-`H.$%`*#A"!"@X0`@H.,<,(WB_O__ZP!@4.(G```*`#"@XQ0PC>6(-Y3E +M``!3XP4```J8%Y3E`'"@XYAWA.4#`*#A_O__ZXAWA.4<`)WE_O__ZX@'A.4` +M`%#C!0``&D0"G^5$$I_E02`!X_[__^L5`.#CB0``ZA0PC>(`,(WE!@"@X1P0 +MG>4((`'C`#"@X_[__^L``%#CL##0$8,XX!&C..`1L##`$8@'E.4&$*#A'""= +MY?[__^L<,)WEF#>$Y1P0G>4!`(7@"!!AX``@H.,8,(WB_O__ZP!04.)(```* +M`#"@XQ`PC>6T,4%`*#A&!"=Y0(@H.,4,(WB_O__ZP``4.,) +M```*M!'=X2$4H.$!`!'C!0``"HP!G^7^___KK#>4Y0``4^,;```:(```ZJ@W +ME.4``%/C!0``"KP7E.4`8*#CO&>$Y0,`H.'^___KJ&>$Y1@`G>7^___KJ`>$ +MY0``4.,%```:-`&?Y301G^6!(`'C_O__ZQ4`X.-%``#J!1"@X1@@G>7^___K +M&#"=Y;PWA.4``*#C/@``ZL`7E.4`8*#CP&>$Y:P'E.7^___KK&>$Y1@`G>7^ +M___KK`>$Y0``4.,%```:U`"?Y=00G^64(`'C_O__ZQ4`X.,M``#J!1"@X1@@ +MG>7^___K&#"=Y<`WA.4``*#C)@``Z@``H.,D``#J`&27Y0```.,``$#CF!"? +MY00@H.'^___K``!4XP``H-,;``#:!D"@X8PWEN4``%/C!0``"IP7EN4`8*#C +MG&>$Y0,`H.'^___KC&>$Y0@`H.'^___KC`>$Y0``4.,%```:.`"?Y4`0G^6Y +M(`'C_O__ZQ4`X.,&``#J!1"@X0@@H.'^___KG(>$Y0``H.,```#J``"@XRC0 +MC>+P@;WH?&,``#@W``"@8P``6#L``,AC``#P3RWIG=]-X@!`H.$!H*#A`I"@ +MX0!0H.,"'(WBOE;!X6A2C>5:CXWB_V"@XP@`H.$%$*#A!B"@X?[__^MH`(WB +M!1"@X08@H.'^___K9%"-Y6!0C>5<4(WE'`"-X@40H.%`(*#C_O__ZZH]#^/_ +M/T_C)RZ-XK-0@N$44(WE!#"@XQ,PS>4),*#C$C#-Y0$PH.,1,,WE4#\&XYHY +M0.,,,(WE!S"@XPLPS>53;83B(&"&X@Y[A.(RL(?B!%"*X@L`H.$%$*#A!B"@ +MX_[__^LL`(?B!1"@X08@H./^___K#CN@XX#`H..SP(3A(%"*XB!P2>(%`*#A +M!Q"@X0@@H.%@,(WB_O__ZYH_C>(`,(WE"`"@X6`0G>42(`'CFS^-X@(P@^+^ +M___K`AR-XKXVT>&S/[_F$%`%/C`_&?EQ0``.KT.@4`!#L%`#`[ +M!0`P.P4`%#L%`"0[!0`..Z#C!""@X[,@A.$*``#J#CN@XPC`H..SP(3A!@`` +MZ@X[H..`$*#CLQ"$X0(``.H..Z#C`2R@X[,@A.$%`*#A!Q"@X6@@C>)D,(WB +M_O__ZP``4.,/```*:%"-XAQPC>)<,(WB`#"-Y04`H.%D$)WE#2"@XP4%`*#A9!"=Y0(@H.,",$?B_O__ZUH/C>(`$*#C_R"@X_[_ +M_^MH`(WB`!"@X_\@H./^___K`#"@XV0PC>4&`*#A_O__ZP!@4.*2```*!`"@ +MX0@0AN+^___K;`"6Y0`0H.-H(*#C_O__ZVR`EN4(4*#A`)"@XRB0Y>4!D,7E +M+`"(X@L0H.$&(*#C_O__ZS(`B.(-&X3B$1"!X@8@H./^___K.`"(X@L0H.$& +M(*#C_O__ZP@@H.&^$_+AW#<`X[,`E.$/$`'B`!*!X;`0PN&S()3A`2""XK,@ +MA.&P,-7A_###X]`P@^.P,,7A!G"@X1@PH.,4,*?E%*"-XD``B.(!$*#C`2!* +MX@($$*#C!2"@X0(',*#A_O__ZP$0H.,#($KB!S"@X?[__^L`H*#A4#"@XV@PS>5O +M,*#C:3#-Y64PX.-J,,WE"3"@XVLPS>4"(*#C;"#-Y6Z0S>5M(,WE:%"-XAR` +MC>('`(7B`A!(XO[__^L-,*#C<3#-Y5P@G>52-.?G4,`(7B"!"@ +MX?[__^MD,(WB`#"-Y0H`H.'=$*#C7""=Y0P@@N(%,*#A_O__ZQ0@EN5D,)WE +M`S""X!0PAN4G/HWB`"`%X_(D0.,((2/E!""@XQ`:!..R$(/A`B""XF`@C>4! +MS*#CLL"#X6`@G>4GSHWB`A",X!#`H.,&P4'E`R""XF`@C>6!'J#CLA"#X6`@ +MG>4"((+B8""-Y0+,H..RP(/A8""=Y0(@@N)@((WE#AN@X[$0E.&Q'[_FLA"# +MX6`@G>4"((+B8""-Y0!PC>7=$*#C_O__ZQ0PEN48,(;E!`"@X080H.'^___K +MG=^-XO"/O>AP0"WI"-!-X@!`H.$!4*#A`F"@X0`PH./^___KW@?4Y0X`4.,` +M$*#3`1"@PP7R_^L`$*#A"#P#XP,`E.<@,*#C`#"-Y04@H.$&,*#A_O__ZPC0 +MC>)P@+WH<$`MZ0C03>(`0*#A`5"@X0)@H.$`,*#C_O__Z]X'U.4.`%#C`!"@ +MTP$0H,/O\?_K`!"@X0@\`^,#`)3G(#"@XP`PC>4%(*#A!C"@X?[__^L(T(WB +M<("]Z'!`+>F0T$WB`%"@X0%@H.&V(,WA#$"-X@0`H.$`$*#C@""@X_[__^L` +M``#C``!`X[P0G^4%(*#A_O__ZP`PH.,`,,3E`3#$Y00`A.(-&X7B$1"!X@8@ +MH./^___K"@"$X@80H.$&(*#C_O__Z\(.A>(,`(#B_O__ZP`0H.$0`(3B!B"@ +MX_[__^L$,*#AM@'SX=PG`..R$)7A#P``X@$"@.&P`,/A`1"!XK(0A>&P,-3A +M_###X\`P@^,$`*#AN#'`X!@PH..,,(WE`A"@XP8@C>*,,(WB_O__ZP@\`^,# +M`)7G!!"@X8P@G>7^___KD-"-XG"`O>CP8P``\$$MZ0!0H.$!8*#A`G"@X:@\ +M`^,#0)#G````XP``0.-($)_E!2"@X?[__^L"$*#C!!"$Y0```.,``$#C_O__ +MZP@\`^,#`)7G!A"@X0<@H.'^___K````XP``0.,$$)3E_O__ZP,PH.,$,(3E +M\(&]Z!1D``#P1RWI,=Y-X@"`H.$!0*#A"#"-XI0AG^4#`)+H!`"#Y+`0P^&H +M/`/C`S"8YP!PD^6T!M3A#@!0XP`0H),!$*"#>?'_ZP`0H.$'`*#A_O__ZP"0 +MH.$`,`#C`#!`XP``D^7^___KE%"$X@4`H.'^___K!0"@X?[__^N,H-3E`:"* +MXJJ@H.%?H$KB9#"@XY,*"N`Q;HWB`#"@XP`S9N4!,,;E!C"@X;8A\^$/(`+B +ML"##X28PU.4!`%/C"0``&@0`AN(($(WB!B"@X_[__^L0,(WBL"#3X?P@PN.` +M((+CL"##X0D``.H$`(;B#1N(XA$0@>(&(*#C_O__ZQ`PC>*P(-/A_"#"XU`@ +M@N.P(,/A(%"$X@H`AN(%$*#A!B"@X_[__^L0`(;B!1"@X08@H./^___K*`"- +MXI00A.*0()3E_O__ZY`0E.484('BH`"$X@P00>(`(*#C`C"@X?[__^L``%#C +M`@``"D@`G^5($)_E_O__ZP"@C>4@,*#C!#"-Y0<`H.$)$*#A$""-X@4PH.'^ +M___K``!0XP``H!,"```:&`"?Y?[__^L5`.#C,=Z-XO"'O>@T9```^#L``#QD +M```(/```\$$MZ0"`H.&H/`/C`S"0YP``4^,"```:Q`"?Y?<7`./^___K`#"3 +MY0``4^,"```:K`"?Y3D7`./^___K_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B +M!""#Y81PB.*$0)CE?FZ(X@1@AN('`*#A!!"@X?[__^L!`%#C#@``"@10H.$& +M`*#A9!"4Y?[__^L!`%#C!@``&B@`A.+^___K`0!0XP(``!H(`*#A!!"@X6/_ +M_^L`0)3EZ___Z@T@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^L(`*#A`!"@ +MX_[__^OP@;WH##4``/!/+>E7WTWB`8"@X0)@H.$``%#C`@``&A@$G^4Y%P#C +M_O__ZP2BD.6H/`/C`S":YP``4^,"```:^`.?Y?<7`./^___K`$"3Y0``5.," +M```:X`.?Y3D7`./^___K`%"2Y2!PDN7^___K#2"@X7\]PN,_,,/C!""3Y0$@ +M@N($((/E"&*$Y00@D^4!($+B!""#Y?[__^L*`*#AG!.?Y?[__^L``%#CW@`` +M"@4`H.$``%7C/0``"@`0`.,`$$#C!R"@X_[__^L``%#C-P``"@P`EN40$);E +M`""@XP(PH.'^___K``!0XS````HL.@/C`S":YP``4^,1```:"@"@X0$0H./^ +M___KJ#P#XP,PFN<``%/C`@``&AP#G^7W%P#C_O__ZP`PD^4``%/C`2"@$R$B +MPQ4'```:_`*?Y3D7`./^___K*"H#XP(@FN<"`%/A*"H#$P(PBA7^___K$#"=Y90WB.40`)WE!W!@X```A.`' +M$*#A`""@XPPPC>+^___K`$!0XA<```JD-YCE``!3XP4```JX%YCE`+"@X[BW +MB.4#`*#A_O__ZZ2WB.4'`*#A_O__ZZ0'B.4``%#C!```&H`!G^6`$9_EF28` +MX_[__^L$``#J!!"@X0P@G>7^___K##"=Y;@WB.48-=KE`0!3XP,``!I4`9_E +M1!&?Y?[__^M)``#J;"":Y2(-$N,#```*/`&?Y2@1G^7^___K0@``ZBPZ`^,# +M,)KG``!3XPT```H!`%/C"P``"@4`4^,%(*`3+#H#$P,@BA<*`*#A`1"@X_[_ +M_^L``%GC`""@`P(@H!-].@/C`R#*YQ0`C>(`$*#C42^@X_[__^L$,);E``!3 +MXQ4``-H`<*#C!T"@X12`C>*$`83@``&(X`0`@.(%$*#A("#5Y?[__^L@,-7E +M!S"(YP%`A.(A4(7B)'"'X@0@EN4$`%+A`#"@TP$PH,,(`%3C`#"@PP``4^/L +M__\:_O__ZPTPH.%_3,``*`3``#@`P(``.H*`*#A_O__ +MZP``H.-7WXWB\(^]Z`PU``!49```.#<``&AD```P/```3#P``'!`+>D`0*#A +M`5"@X?[__^L-(*#A?SW"XS\PP^,$()/E`2""X@0@@^4(`)3E``!0XPL```H` +M,)3E%""0Y0`PD^4#`%+A`@``"C0`G^7^___K`0``Z@40H.'^___K`#"@XP@P +MA.4-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K<("]Z&`\``!P0"WI`$"@ +MX0```.,``$#CC!"?Y00@H.'^___K``!4XW"`O0@`4)3E``!5XP(``!IP`)_E +M.1<`X_[__^L"7(7B````XP``0.-4$)_E_O__ZP4`H.$!$*#C_O__ZPPPE>4` +M`%/C!@``"CP`G^4P$)_E_O__ZPP`E>7^___K#`"5Y?[__^L``)3E_O__ZP`` +ME.7^___K!`"@X18>H./^___K<("]Z(QD```,-0``K#P``/!!+>D`0*#A`2"@ +MXPXT`>,#(,#G`%"@XP!@`.,`8$#C@'"?Y12`H.,*``#J!@"@X0<0H.'^___K +M"`"@X?[__^L!4(7B"P!5XP(``!I8`)_E_O__ZP(``.IL,)3E`@L3X_'__QJH +M/`/C`S"4YP``4^,"```:-`"?Y?<7`./^___K``"3Y0``4.,"```:'`"?Y3D7 +M`./^___K`@R`X@$0H./^___K\(&]Z)QD``#T/```##4``/!/+>D4T$WB`9"@ +MX0)0H.%$<(WB@`F7Z#Q@W>4``%#C`@``&NP!G^4Y%P#C_O__ZP1"D.4`<(OE +M`#"@XP0PB^6T`-+A_O__ZP``C>4X,)WE!#"-Y0```.,``$#CN!&?Y0D@H.$( +M,*#A_O__ZP```.,``$#C!A"@X?[__^L`,-?E`2#7Y0(D@^'0`%+C#0``"E`` +M4N,%```:@`&?Y7@1G^7^___K`4"@XP"@H.-*``#J;`&?Y6`1G^7^___K`4"@ +MXP"@H.-$``#J!`"@X9[__^NT`-7A_O__Z]XWU.4#`%#A!P``"K0`U>'^___K +M70$*#C#!"-Y0D`H.'^___K!`"@X080H.'^ +M___K#0``Z@!`H.,$H*#A````XP``0.,P$)_E!""@X?[__^O0(,OA@`&-Z`A` +MC>70$*#C#!"-Y0D`H.'^___K"@"@X130C>+PC[WH##4``+1D``!D4T$WB`7"@X0)@H.$#H*#A.)"=Y3RPG>4``%#C`@``&L`!G^4Y%P#C +M_O__ZP1"D.6T`-+A_O__ZW"`[^:H49_E`)"-Y0```.,``$#C!1"@X0<@H.$( +M,*#A_O__ZP0`H.$%$*#A_O__ZP``4.,-`.`#6@``"E@W`^,#<(3G-PR$XB@` +M@.(&$*#A)""@X_[__^M,-P/C`Z"$Y]``R^%0-P/C\P"$X=`@R^%`!(WH")"- +MY=`0H.,,$(WE!P"@X?[__^O>)]3E)#<#XP,@Q.=L,)3E`@L3XP$```H$`*#A +M#___Z]XWU.4(`%/A"P``"GX.A.($`(#B"!"@X?[__^L``%#C!0``"MZ'Q.4$ +M`*#A"!"@X0`@H.,",*#A_O__ZRPZ`^,#,)3G``!3XQ$``!H$`*#A`1"@X_[_ +M_^NH/`/C`S"4YP``4^,"```:F`"?Y?<7`./^___K`#"3Y0``4^,!(*`3(2+# +M%0<``!IX`)_E.1<`X_[__^LH*@/C`B"4YP(`4^$H*@,3`C"$%RPZ`^,#,)3G +M`@!3XP(@H!,L.@,3`R"$%]XGU.7I/:#C`R#$YP`P`.,`,$#C`#"3Y600H..1 +M"0G@TRT$XV(@0>.2"8'@VPV$XC``@.(A$X/@_O__ZP``H.,4T(WB\(^]Z`PU +M``#,9```,$`MZ1303>(`0*#AJ#P#XP-0D.<```#C``!`XS@1G^4$(*#A_O__ +MZP0PE>4"`%/C"`!3$T8``!IL,)3E$``3XT,``!HL.@/C`S"4YP``4^,?```* +MW0V$XB0`@.+^___KW@V$XA@`@.+^___KWPV$X@P`@.+^___K*#H#XP,PE.4!(*#C"""-Y1\@@N(,((WE +M""P#XP(`E.<#$*#A`R"@X?[__^L)``#J`@!3XP<``!H>,(/B`#"-Y0@\`^,# +M`)3G`!"@XP$@H.$!,*#A_O__ZQ@`G^5<$)7E_O__ZQ30C>(P@+WH[&0``"0Z +M``#D4T$WB`$"@X:@\`^,#4)#G````XP``0.,L$9_E!""@ +MX?[__^L$,)7E`@!3XP@`4Q-#```:;#"4Y1``$^-````:+#H#XP,PE.<``%/C +M&@``"B@J`^,"()3G`@!3X2@J`Q,",(07)#H#XP,PE.<"`%/C`B"@$R0Z`Q,# +M((07+#H#XP,PE.<*`%/C"B"@$RPZ`Q,#((07*#H#XP,PE.<`,(WEJ`"?Y:`0 +MG^4D.@/C`R"4YP@P@^(#,)3G_O__ZW(PU.4``%/C#0``"@@\`^,#`)3G4#&4 +MY0PP0^(`,(WE`!"@XP00C>4($(WE(#"@XPPPC>7@((3B%CZ$XO[__^L0``#J +M3`"?Y5P0E>7^___K`#"@XP`PC>4$,(WE"#"-Y2`@H.,,((WE""P#XP(`E.?@ +M$(3B`R"@X?[__^L8`)_E7!"5Y?[__^L4T(WB,("]Z!!E```D.@``W#T``/0] +M```$X"WE'-!-XG0!D.4`,-#E`<#0Y0#`C>4"P-#E!,"-Y0/`T.4(P(WE!,#0 +MY0S`C>4%`-#E$`"-Y0$`H.$"$*#A`"``XP`@0./^___K'-"-X@"`O>@$X"WE +M#-!-X@`TD.5L`)/E`0`0XP``H`,(```*F@8!X]``D^$``(WE`0"@X0(0H.$` +M(`#C`"!`X^PP@^+^___K#-"-X@"`O>AP0"WI`$"@X0%0H.$`,`#C`#!`XV`` +MD^7^___K`"24Y:@\`^,#,)+G``!3XP(``!HX`)_E]Q<`X_[__^L`,)/E``!3 +MXP(``!H@`)_E.1<`X_[__^L`4(7@`2#5Y3`@4N(!(*`3)"+#Y0``H.-P@+WH +M0#X``!!`+>ET,9#E`0"@X0,0H.$&(*#C_O__ZP8`H.,0@+WH<$`MZ0!0H.$! +M0*#A`#``XP`P0.-(`)/E_O__ZP$0@.(`!)7E`1"$X/[__^L!`%#C``"@`P`` +MX!-P@+WH<$`MZ0%0H.$"0*#A`!20Y0$`H.'<$('B_O__ZP`PH.$%`*#A!!"@ +MX0`@`.,`($#C_O__ZW"`O>CP02WI`'"@X0!`H.,`4`#C`%!`XP1AE><&`*#A +M_O__ZP`@H.$'`*#A!A"@X?[__^L``%#C`@``"@%`A.(9`%3C\___&@0`H.'P +M@;WH,$`MZ1303>(`0*#A`5"@X?[__^L0$)7E``!1XQ5`X`.U```*#0"@X7\] +MP.,_,,/C"#"3Y0P@D>(#(-(P`#"@,P``4^,&```:!`"-X@P@H./^___K``!0 +MXPU`X!,%```*I0``Z@0`C>(,$*#C_O__ZPU`X..@``#J#`"=Y=`0H./^___K +M`%!0X@M`X`.:```*!!"=Y0P@G>4-`*#A?SW`XS\PP^,(,)/E`@"1X`,`T#`` +M,*`S``!3XY,``!H-`*#A?SW`XS\PP^,(,)/E`@"1X`,`T#``,*`S``!3XP0` +M`!H%`*#A_O__ZP``4..&```:!@``Z@``4N,$```*!0"@X0(0H.'^___K#4#@ +MXW\``.H%`*#A_O__ZP`P4.)7```*#P!3XU4```H!,$/B%P!3XP/QGY=+``#J +M<%0%`(A3!0"<4P4`L%,%`,13!0!P5`4`<%0%`'!4!0!P5`4`<%0%`'!4!0!P +M5`4`<%0%`!14!0!85`4`<%0%`'!4!0``5`4`<%0%`'!4!0!P5`4`*%0%`-A3 +M!0#L4P4```24Y0$0H./^___K``"@XS@``.H`!)3E`!"@X_[__^L``*#C,P`` +MZ@0`H.$%$*#A#""=Y?[__^LK``#J!`"@X040H.$,()WE_O__ZR8``.H$`*#A +M!1"@X0P@G>7^___K(0``Z@0`H.$%$*#A#""=Y?[__^L<``#J!`"@X040H.$, +M()WE_O__ZQ<``.H$`*#A!1"@X0P@G>7^___K$@``ZN`PG^58`)/E_O__ZP,@ +M@.("$(7@`C!1Y00`H.$,P)WE#"!BX#`P0^+^___K!@``Z@4`H.$#$*#CK""? +MY?[__^L"`*#C`P``Z@``H.,``%#C`$"@L1\``+H``%#C`P``&@PPG>4``%/C +M`#"@PP`PQ<4,()WE``!2X0$@@,((((WE!`"=Y0T0H.%_/<'C/S##XP@PD^4" +M$)#@`Q#1,``PH#,``%/C`@``&@40H.'^___K`""@X0``4N,`0*`#!0``"@,` +M`.K^___K!`"@X130C>(P@+WH#4#@X_[__^L%`*#A_O__Z_?__^I8+```:#X` +M`*7&A/B9[HWV#?^]UK'>5)%08`,"J'718 +M+C0M-K+<[K3[6_:D379AM\Y]>U(^W7%>EQ/UIFBY```LP6!`'^/(>>VVOM1& +MC=EG2W+>E-28Z+!*A6N[*L7E3Q;MQ8;7FE5FE!'/BA#I!@2!_O"@1'BZ)>-+ +M\Z+^7<"`B@6M/[PA2'`$\=]CP7=UKV-","`:Y0[];;],@108-28OP^&^HC7, +MB#DN5Y/R58+\1WJLR.>Z*S*5YJ#`F!G1GG^C9D1^5*L[@PO*C"G'TVL\*'FG +MXKP=%G:M.]M69$YT'A3;D@H,;$CDN%V?;KWO0Z;$J#FD,3?3B_(RU4.+66ZW +MVHP!9+'2G.!)M-CZK`?S)<^ORH[TZ4<8$-5OB/!O2G)<)#CQ5\=S49%!ZI8\#^%F`"1<:VF4QU\:$ +MN-##@K`I=UH1'LM[_*C6;3HLQJ7XA.Z9]HW_#=:]WK&15&!0`@/.J59]YQFU +M8DWF[)J/11^=B4#ZA^\5LNN.R?L+0>RS9U_]1>HCOU/WY):;6W7"X1P]KDQJ +M;%I^0?4"@T]H7%'TT33Y".*3JW-B4RH_"`R54D9EG5XP*#>A"@\OM0X))#8; +MF]\]S29.:7_-ZI\2&QV>6'0T+C8MW+*T[EO[I/9V3;=A?]T^7G$3EZ;U +MN6@``,$L0&#C'WG(MNW4OHU&9]ER2Y3>F-2PZ(5*NVO%*D_E[1:&Q9K79E41 +ME(K/Z1`$!OZ!H/!X1"6Z2^.B\UW^@,`%BC^M(;QP2/$$8]]WP:]U0F,@,.4: +M_0Z_;8%,&!0F-<,OON$UHHC,+CF35U7R_()Z1\BLNN#8M*SZ\P?/)74),Z*5Z`X]9^`F`&A=EVM\NH_&W6+#IC?'=[\FMOQ3`! +M9RO^UZMVRH+)??I91_"MU**OG*1RP+?]DR8V/_?,-*7E\7'8,14$QR/#&)8% +MF@<2@.+K)[)U"8,L&AMN6J!2.]:S*>,OA%/1`.T@_+%;:LN^.4I,6,_0[ZK[ +M0TTSA47Y`G]0/)^H4:-`CY*=./6\MMHA$/_STLT,$^Q?ET07Q*=^/61=&7-@ +M@4_<(BJ0B$;NN!3>7@O;X#(Z"DD&)%S"TZQBD97D>>?(-VV-U4ZI;%;TZF5Z +MK@BZ>"4N'*:TQNC==!]+O8N*<#ZU9D@#]@YA-5>YAL$=GN'XF!%IV8Z4FQZ' +MZ@X,=="PL6"X:&C0M&QLVLFYNW.Y: +M6K3[H*!;]E)2I$T[.W9AUM:WSK.S?7LI*5(^X^/=<2\O7I>$A!/U4U.F:-'1 +MN0`````L[>W!8"`@0!_\_./(L;%Y[5M;MKYJ:M1&R\N-V;Z^9TLY.7+>2DJ4 +MU$Q,F.A86+!*S\^%:]#0NRKO[\7EJJI/%OO[[<5#0X;734V:53,S9I2%A1'/ +M146*$/GYZ08"`@2!?W_^\%!0H$0\/'BZGY\EXZBH2_-14:+^HZ-=P$!`@(J/ +MCP6MDI(_O)V=(4@X.'`$]?7QW[R\8\&VMG=UVMJO8R$A0C`0$"`:___E#O/S +M_6W2TK],S?]S[NQ].XN&L\%!0H>=[>I^)>7KP="PL6=MO;K3O@ +MX-M6,C)D3CHZ=!X*"A3;24F2"@8&#&PD)$CD7%RX7<+"GV[3T[WOK*Q#IF)B +MQ*B1D3FDE94Q-^3DTXMY>?(RY^?50\C(BUDW-VZW;6W:C(V-`635U;'23DZ< +MX*FI2;1L;-CZ5E:L!_3T\R7JZL^O967*CGIZ].FNKD<8"`@0U;JZ;XAX>/!O +M)25*NT+FY:9&&AA=8P<&9)QT=.KF>GB'9$_CXZ[.8F"LS$1$B +MNVEITG#9V:F)CHX'IY24,[:;FRTB'AX\DH>'%2#IZR["P>_Q45*C6N[MM.A86+%"G]%%394%^PZ07&I9>)SK+:ZL[\46= +M'ZM8^JR3`^-+5?HP(/9M=JV1=LR()4P"]?S7Y4_7RRK%@$0U)H^C8K5)6K'> +M9QNZ)9@.ZD7AP/Y=`G4OPQ+P3(&CET:-QOG3:^=?CP.5G)(5ZWIMO]I94I4M +M@[[4TR%T6"EIX$E$R,F.:HG"=7AYCO1K/EB9W7&Y)[9/X;X7K8CP9JP@R;0Z +MSGT82M]C@C$:Y6`S49=%?U-BX'=DL82N:[L +ME+?X>U(CTW.KX@)+/'^,JJU5F!RCKL@/"M2^:>\6&I0@WT_*'*#"RI;\C +MNFH#`ER"%NTK',^*DK1YI_#R!_.AXFE.S?3:9=6^!08?8C31BOZFQ)U3+C2@ +M5?.B,N&*!77K]J0Y[(,+JN]@0`:?<5Y1$&Z]^8HA/CT&W9:N!3[=1KWF3;6- +M5)$%7<1Q;]0&!/\54&`D^Y@9E^F]ULQ#0(EWGMEGO4+HL(B+B04<*?*'I#T)\R1Z$^`````"#AH`)2.TK,JQP$1Y.U:X] +M)SDM-F39#PHAIEQHT51;FSHN-B2Q9PH,#^=7D]*6[K2>D9L;3\7`@*(@W&%I +M2W=:%AH2'`JZD^+E*J#`0^`B/!T7&Q(+#0D.K<>+\KFHMBW(J1X4A1GQ5TP' +M=:^[W9GN_6!_HY\F`?>\]7)2XRMPQ +MUQ"%8T)`(I<3(!'&A'TD2H7X/;O2$3+YKFVA*<=++YX=\S"RW.Q2A@W0X\%W +M;!:S*YFY<*GZ2)01(F3I1\2,_*@:/_"@V"Q]5N^0,R+'3DF'P=$XV?ZBRHPV +M"]28SX'UIBC>>J4FCK?:I+^M/^2=.BP-DGA0F\Q?:F)&?E3"$XWVZ+C8D%[W +M.2[UK\."OH!=GWR3T&FI+=5OLQ(ESSN9K,BG?1@0;F.";-]!A9 +M;@&WFNRHFD^#96Z5YG[F_ZH(S[PAYN@5[]F;Y[K.-F]*U`F?ZM9\L"FOLJ0Q +M,2,_*C"4I<;`9J(U-[Q.=*;*@ORPT)#@%=BG,TJ8!/'WVNQ!#E#-?R_VD1>- +MUDUV3;#O0U1-JLS?!);DX[71GAN(:DRX'RS!?U%E1@3J7IU=-8P!S4M+;DC-6$.D31]9MC&'7FGH,H3>.%/A9B3P3Z^XGJ4< +MX3RQ1WI9W]*('SK\H^Q&BY +M+#0D.%]`H\)RPQT6#"7BO(M)/"A!E0W_<0&H.=ZS#`B-G820V*L`C+S3"O?D6`6XLT4&T"P>C\H_#P+!K[T# +M`1.*:SJ1$4%/9]SJE_+/SO"TYG.6K'0BYZTUA>+Y-^@<==]N1_$:<1TIQ8EO +MMV(.JAB^&_Q6/DO&TGD@FMO`_GC-6O0?W:@SB`?',;$2$%DG@.Q?8%%_J1FU +M2@TMY7J?D\F<[Z#@.TVN*O6PR.N[/(-3F6$7*P1^NG?6)N%I%&-5(0Q]`0($ +M"!`@0(`;-@```@0+%@P2&"0P2&!L``````H````0````$````!`````0```` +M$````!`````0````$````!`````0````$````!`````0````$````!`````* +M````4&^:"5!OF@D`4/($`%#R!`!0\@0`4/(!`%#R`0!0\@(``0``)"8H*BPN +M,#(T-C@Z/#Y`9&9H:FQN<')T=GAZ?'Z`@H2&B(J,E9>9FYV?H:.E`````A$" +M"@$!`0`!``$``0`!"0,)`P````(/`0@"!@(+`@D!`0(%`1(`!`(0```````` +M`````````````````````````0`"``,`!``"!``!`PP`"P`%```````````` +M``````8`!P`(``D""@`"``,##0,.`@\````````````````"$````0(#!`4& +M!P@)"@L,#0`-`0(#!`4&!P@)"@L-#0`-`0(#!`4&!P@)"@L````+`0(#!`4& +M!P@)"@L,#0X."@L,#0`````````````$```````````````````````````` +M```````D*"PP-#@\0&1H;'!T>'R`A(B,```````3)"@L,#0X/$!D:&QP='A\ +M@(2(C)69G:&E&"0H+#`T.#Q`9&AL<'1X?("$E9F=H:4``!8D*"PP-#@\0&1H +M;'!T>'R`A(B,E9F=H:48)"@L,)69G:&E````````````````````"20H+#`T +M.#Q`E9F=H:4```````````````TD*"PP-#@\0)69G:$````````````````, +ME9F=H:4`````````````````````````!20H+#`T.#Q````````````````` +M``````@D*"PP-#@\0&1H;'!TB(R5F9VAI0`````4)"@L,#0X/$!D:&QP='A\ +ME9F=H:4`````%"0H+#`T.#Q`9&AL<'1X?("$B(P``````!,D*"PP-#@\0``` +M```````````````````(9&AL<'1X?("$B(P`````````````````"S@\0&1H +M;'!TB(R5F9VAI0````````````\X/$"5F9VAI0`````````````````````( +M)"@L,#0X/$!D:&QP=(2(C)69G:&E````%20H+#`````````````````````` +M``````0`________```````````````````````````````````````````` +M```````````````````````````````````````````````````````$```` +M````````````````#``````````(```````````````````````````````` +M```````````````````````````````````````````````````````````` +M``````````````````````````````````!M;&UE97AT7VIO:6YB`````!R='=?>&UI=&9R86UE7V-O86QE`FP```/____\` +M`````````/____\`````````````````````````````````````^?____C_ +M___X____^/____C____X____^/____C____Y____^/____C____X____^/__ +M__C____X____^/___R?P__\OH%6J)P```"]0JE4`#@0.$`X4#A@.'`XP"#0( +M/`A("$P(:`C_______\```#@3(&(`@````8&!@`&``!!J'*Y`P`!`````@`# +M`````P`"``$````"``$``@````,````#`````@````$````!```````````` +M```"`````@````(````"`````@````(````"`````@````0````&````!0`` +M`'AM:71F_"-`)`@M:#-P-C0]S$903 +M]Q6F&*<;!Q_1(A`GU"LM,2TWZ3UW1?%-YX`-B8**@^23H_8(W_GL^JGP[?LB +MB8**@^SZX*/(Q8+(S,6#S/"CR,6"R,S%@\S?ZM[H@-N)@HJ#Y).C\@C?^8#, +MB/#O8`$.3F##B/#M)`*T!`!0N?6"ZR0"M`0`4*\C(T6"(Y!"4'.[`0F)@HJ# +M^.`H\")0`R?W(KO^!?CC*/,BBH.)@OCDDR@BNP$/^.6"*?6"Y8,Z]8/@*/`B +M4`G%@BGXY8(F]B*[_@G%@BGXXB6"\B+XZB6#]8/IDR@BQ?#XH^`H\,7P^.6" +M%8)P`A6#X#CP(N]+_^Y*_NU)_>Q(_"+@_*/@_:/@_J/@_R*D)8+U@N7P-8/U +M@R+@^Z/@^J/@^2+K\*/J\*/I\"+0@]""^.23"CM?`VW_:`,HB"C(.'\`GDDZ.U +M\"7?]8`AB(*,@^/U\`G@H[7P%-_U@!"(@HR#X_7P">23H[7P`M_T`D4:@(>` +MZ8"0@-2`/H`5@&Z`?H"=@+>`C8"C@%&`=(`\`D4FB8**@^SZY)/U\*/(Q8+( +MS,6#S.23H\C%@LC,Q8/,M?!VW^/>X8!PB8**@^23]?"CX@BU\&+?](!>B8** +M@^#U\*/F"+7P4=_U@$V)@HJ#X/7PH^((M?!`W_6`/(F"BH/DD_7PH^8(M?`N +MW_2`*H`"@%>)@HJ#[/KDD_7PH\C%@LC,Q8/,X*/(Q8+(S,6#S+7P!M_DWN*` +M`'__M?`"#R)``G\!(HF"BH/L^N#U\*/(Q8+(S,6#S."CR,6"R,S%@\RU\-7? +MY=[C@,^)@HJ#[/K@]?"CR,6"R,S%@\SDDZ/(Q8+(S,6#S+7PK]_DWN*`J8CP +M[V`!#DY@J^TD`K0$`%"8]8+K)`*T!`!0CB,C18(CD$1B<\*O@/XR$D69A=`+ +M==`(JN#"C.6*)&?UBN6,-'GUC-*,["2+^.:\!`)T_\.5@;1``$#.>05X@!;F +M"'`+PJ_F,.$#1!CVTJ\(V>WJB]`BY0S_(R2!^`\("+\%!'\`>('F,.3R`.4, +MPY]0(`4,=(HE#/CF_::!".:N#+X$`G3_S?CH;6#@".;`X(#VY0S3GT`GY0PD +MB_CFK@R^!`)T__T8YLWXY8%M8`;0X/88@/7E#"2*R/85#(#3Y0PC)('X?P3" +MK^8PX`,0X@Q_`##A!S#C!'\(5/14?,;2KU2`0@(JF@70$8`;_"';_W_M_ +M!>1X@/8(]@C?^GB!=C"023%T`9/`X.23P.!#B0%UBF!UC'G2C-*O(@3OTY0$ +M0`-__R)T@2\O^.8@Y?3"K^9$,/;2KZX,[L.?4"$.=(HN^.;Y".88O@0"=/_] +M[6E@"0GG&1GW"0F`\Q86@-KNTY]`!`6!!8'NTY]`(G2*+O@(YOGNM0P"J8$8 +M!@;F_>UI8`D9&><)"?<9@/,>@-GO)(KXY@3X[R\$D$DQD_8([R^3]G\`(N_3 +ME`1``W__(N\C)('XYC#E],*OYE2,]M*OY0RU!PITBB_XYO6!`D7B4"YTBR_X +MYK\$`G3__1CF^72*+_C[YOSI;&`(J`7G]AT9@/2H`Z8%'^4,M0?C?P`B=(LO +M^.;]&(8!#W2*+_BF`0B&!.4,M0<"K('M;&`(#0FH!>;W@/3E#+4'WHF!?P`B +M[].4!$`#?_\B[R,D@?C"K^8PY04PX`+2Y-+BQM*O?P`PX@$/`D7AC_#D__[E +M#",D@/C"J3#W#7\(YF`++?9@,%`N@`23H_A4!R0,R,,SQ%0/1"#(@T`$]%:``4;V +MW^2`"P$"!`@0($"`D$DDY'X!DV"\H_]4/S#E"50?_N23HV`!#L]4P"7@8*A` +MN.23H_KDDZ/XY).CR,6"R,K%@\KPH\C%@LC*Q8/*W^G>YX"^BTV*3HE/JU"J +M4:E2$A^D_JM-JDZI3Q(?I/]N<"OO8`WE5!54<`(54Q1%4W`#?P`B=`$E3_5/ +MY#5.]4YT`252]5+D-5'U48"^JTVJ3JE/$A^D_]/N9(#X[V2`F$`#?P$B?_\B +M`$P!!@TP`08-<`%CL8)9B!&-79)S`X,#PP(/`@L#0==``P`#``<`"P`/` +M!,`%P`;`!Y`!Q'0[\'1)H_!3D>\29QWE.C#F`C&3_43Q]>'\"43Q]`G\#43R0!@K@1`?PD($QH^"0!5CPD("CX+0!%)"! +M)>!4^_"0@2G@(.(-?0%_!(`,D($EX$0$\")]`7\$TQ"O`9"#5.!D#&`"8?V1`N]D`6`" +M8?V1NV']D(-4X+0.!Y$"OP$"D7F0@U3@M`8"D5.0@U3@M`P'D0*_`0*1NY"# +M5.!D!'!=$FLB[V0!<%6Q4X!1D(-4X+0.!Y$"OP$"D7F0@U3@M`8"D5.0@U3@ +MM`P'D0*_`0*1NY"#5.!P!'\!D:&0@U3@M`0;$FO1@!:0@U3@M`P/D($EX/\3 +M$U0_,.`#$E]ET-"2KR(24BGO9`%@")`!N'0!\(`XD($DX/\3$Q-4'S#@")`! +MN'0"\(`C[\14#S#@")`!N'0$\(`4D($HX-.4!$`(D`&X=`CP@`-_`2*0`;ET +M`O!_`"*0@27@D`8$(.`,X$1`\)"!*70$\(`*X%1_\)"!*70,\)`%(N3P(I"! +M)>##$R#@")"!*70,\(`1D`8$X$1`\.!$@/"0@2ET!/"0!2+D\"*0@UOO\!)H +MIY"#6^!@!9`%(N3PD($I=`3P(I"`H^!D`7`MD($EX%3]\)`%(G1O\'\!\8V_ +M`0Z0@23@1(#PD($I=`[P(I`!N70!\)`!N`3P(N]P.WT!_[$[?7A_`K$[?0)_ +M`[$[?_O9T,"_U@N0T`?6#[O`BD`4B=/_P$FA? +MD`$W=`+P_7\#43P26LSDD($I\"+#$U0!_Y""?N_P?X!^"!(M7)"!/Q(@SI"" +M?N"0@3=@!>!$`?`BX%3^\"*0@GL20X\2'Z0PX&>Q<)``1N!4\_U_1A(R'I`` +M1^!$#/U_1Q(R'I"">Q)#AA(?I!,35#^0`$@PX!+@1`S]?T@2,AZ0@3?@1`+P +M@!#@1`3]?T@2,AZ0@3?@5/WPD`!1X$0,_7]1$C(>?09_`=%`?0=_`8`SY/^Q +M=9``1^!4\_U_1Q(R'I``2.!4\_U_2!(R'I"!-^!4_?!]!G\!T5%]!W\!T5'D +M_R&KK@=T-2[XYDWV_>XD4/\",AZN!W0U+OCF_^WT7_;][B10_P(R'I"!*>!D +M!F`D$FF6D($EX!,3$U0?,.`5D($LX/^CX&]P"Q)I&PD($IX,.4!%`"4:8BD($G +MX&!%D($EX/\3$Q-4'S#@$I`!.^`PY`NQ,9"!+.`4D`5S\)"#3>1U\`$20TO# +MD(-.X)2`D(--X&2`E(!`"Y`!F.!4_O#@1`'P\<.0@EO@,.`MD("CX+0!)I"# +M7.`$\."T"@N0@EW@!/#DD(-<\)""7>#_D()2C\/&+(O%6D($LX!20 +M!7/P?0)_`E$\@+B0@2?@8"Z0@*/@9`%P)I"!+?`$8!^0@2K@1!#PY/4=D($N +M$E))D`%7=`7PD($IX"#B`E&F(N3_CPT2:#&_`1B0@`026SBM!ZP&KPT2:^60 +M!!]T(/!_`2)_`"*0!@3@5'_PD`4BY/"0@2ET#/`BD()>X##@+)""8>`$\.#_ +MD()?X+4''9`&DN!4''`*\8N0@F+@!/"`!I`&DG0<\.20@F'P(L#@P/#`@\"" +MP-!UT`#``,`!P`+``\`$P`7`!L`'D`'$=/?P=$^C\!)G4^5!,.`",=/E03#C +M`Q)GK>5!,.0%?P(21[SE0S#@`A&KY4,PX0,23L'E0S#B`Q).9>5#,.,",7KE +M0S#D`C&;Y4,PY0(Q1^5#,.8",2SE1##A`Q)GNN5$,.(#$F@7Y40PXP,2:"1T +M]P20`<3P=$^C\-`'T`;0!=`$T`/0`M`!T`#0T-""T(/0\-#@,N3_D($GX&!X +MD("CX&0!<'"0@2;@Q%0/8"0D_F`#!'`?D($MX!3PX/Y@!I"!+^!@#^YP!I"! +M+."C\'\!@`)_`>]@/I"!*N!$$/"0@2_@8`.T`0GD]1V0@2_@@`WD]1V0@2_@ +M=?`#I"3^_Y"!+N`O44J0`5=T!?"0@2G@(.(#$DJF(I"`H^"T`1.0@2?@8`V0 +M@2K@5/[P5`=P`C')(I"`H^"T`120@2?@8`Z0@2;@5`]D`F`"@`-Q&"(2:#&_ +M`1"0@`/@_^3]$EL\D`0?="#P(I"`H^!D`7`8D($GX&`2D`%7Y/"0`3QT`E%" +MD`%7=`7P(I"`H^!D`7`ED($GX&`?D`%7Y/"0`3QT`O"0@23@5/OPD($JX%3] +M\%0'<`(QR2*0@2C@_WT!`DJJD($FX/_$5`\D_5`"@$?O5`]@.Y`!6^3PD`$\ +M=`3P42GO9`%P,/4=D($UX,,35'_U'N3[_7]8?@%14Y`!6W0%\)`&DG0!\)"! +M).!$"/`B42F_`0(QR2*0!!K@]&`#?P`BD`0;X%0'9`=_`6`"?P`B\.3U'9"! +M-.#U'N3[_7]4?@&.&8\:Y1Y4!\0S5."%&8.%&H+PY1U4!\0S5.#_Y1X3$Q-4 +M'T^C\.M4!\0S5.#_Y1T3$Q-4'T^%&H*%&8.CH_"]`0R%&H*.@Z.CHW0#\"*% +M&H*%&8.CHZ-T`?`BD`:IX)""8_#@5,!P#)"!*N!4_O!4_?`AR9""8^`PYB&0 +M@2?@9`%P()"!*N!$`?"0@2;@5`]D`F`$,6.`"W$8@`>0@2K@5/[PD()CX)"! +M*C#G$^!$`E%"D`%7=`7PD($DX$0$\"+@5/WP(I`!7^3PD`$\=`CPY/4=D($U +MX,,35'_U'N3[_7]0!I#@1`'P(M,0KP'#P-"0@I9T"/#DH_"C\)`! +M'^#^D`$>X'P`)`#_[#Z0@HSPH^_PD`*"X)""E?"0@4/@(.`"H`D&"__(I"!)^!@,Y`&DN`PX"/D]1V0@37@PQ-4?_4>Y/O]?UA^`5%3 +MD`%;=`7PD`:2=`'P(I"!).!4]_`QR2*0@2?@8#.0!I+@,.$CY/4=D($UX,,3 +M5'_U'N3[_7]0`<1T=_!T5J/P4Y'?$F>`Y4DPX0+Q1.5) +M,.("T0/E23#C`M$]Y4HPX`,29\3E3##A!7\#$D>\Y4PPY`,23T/E3##E`G%B +MY4PPY@+Q!W1W!)`!Q/!T5J/PT`?0!M`%T`30`]`"T`'0`-#0T(+0@]#PT.`R +MD($DX/_$$Q,35`$PX"OO5'_PD`3@X)"!)3#A!N!$`O"`#^!4_?"0`;ET`?"0 +M`;@$\)"!)^!@`C')?P%AEY"!)^!@`O&6(GT!$EL\D(-7L="0@U>CX"\D-OGD +M-/QU$P'U%(D5=18$>P%Z@7E5$BOMY/]T&"_U@N0T!O6#X/YT22_U@N0T@?6# +M[O`/[[0&XR*0@23@_Q,35#\PX!'O5/OPD($JX%3]\%0'<$&`/9"!+^`$\)"! +M*N!4[_"0@2_@_[0!`H`$[[0"!I`%6.`$\)"!,^#_D($OX-.?0`^0@*/@M`$* +MD($EX%3[\"(QR2*0`/?@(.<)X'\!(.8,?P(BD`#WX##F`G\#(A)7\Y"``>_P +M$2"0`61T`?`"+:<1BQ&[$4T1;.3U-?4V]3?U.*TU?U`2,AZM-G]1$C(>K3=_ +M4A(R'JTX?U,",AYU/1#D]3YU/P=U0`*0`3#E/?"CY3[PH^4_\*/E0/`B=44. +M=48!=4<#=4ABD`$XY47PH^5&\*/E1_"CY4CP(I`!,.3PH_"C\*/PD`$X\*/P +MH_"C\/U_4!(R'N3]?U$2,A[D_7]2$C(>Y/U_4P(R'I`!-'3_\*/PH_"C\)`! +M//"C\*/PH_#]?U02,AY]_W]5$C(>??]_5A(R'GW_?U<",AZ0`(#@1(#]?X`2 +M,AZ0_0#@5+_P,;X2,G<29I=_`1)&JI""6G0"\/\21JJ0@EK@!/!_`Q)&JI"" +M6N`$\'\$$D:JD():X`3P$0TQ3Y``@.!$0/U_@!(R'G4@_S&O$F;'Y/\"1S,Q +MJ3&V$FI$,6TQQI""7N!4_O"C=`/PH_#DH_"C\"*0@4/@5/[PD(%(X%3^\)`& +MD.!$(/"0@43@5/[P5/WP5/OP5/?P5._P5-_P5+_P5'_PY*/PH_"CX%3^\"+D +MD("C\")UZ`-UJ(0BY)"`G?"C\"*0`93@1`'P(I""6^!4_O!4?_"C=`KPY*/P +M(C&"D`$_=`3PD(`!X+0!!Y#]`.!4[_`B[Y`$[&!.X%3=\)""4.#_46V0`1?@ +M_I`!%N!\`"0`_^P^D("?\*/O\)`&">!4_O"0!2)T__!1S)`"AN!$!/!17!)H +MIY`%(N3PD`$T=`CP_>3_`DH\X$0B\'T(Y/\233N0!I#D\)`"AN!4^_`AV!)L +MAY`"A^!P]Y`&D.!$`O`B?0%Q/'0`+_GD-/QU$P'U%(D5=18(>P%Z@7E:$BOM +MD(%:X)"!8O"0@5O@D(%C\)"!7."0@63PD(%=X)"!9?"0@5[@D(%F\)"!7^"0 +M@6?PD(%@X)"!:/"0@6'@D(%I\"(2:%^0A;L2(-K,\`#`?XQ^"!(NHI"%NQ(@ +MV@```!1_<'X.$BZBD(66$B#:`````.3]_Q(Q37]\?@@2+5SL1(#\D(-'$B#. +MD(-'$D-ND(6[$B#.?WQ^"!(NHI`!`'0_\*/@5/WPD`53X$0@\"+@_WT!TQ"O +M`0@T_@D`0E\)"#4.!@#G0/+_6"Y#3\ +M]8/@1(#PKP5T""_U@N0T_/6#Y/!T"2_U@N0T_/6#X%3P\'0A+?6"Y#3\]8/@ +M5/?PK@2O!=#0DJ\BD(*O$D./$F@Q[V0!8`*!0T_/I[`9""M>#]D720@K:CX"0P^>0T_/I[`<`#P`+``9""LA)# +MAHL3BA2)%746!M`!T`+0`Q(K[9""MJ/@_Z/@+R0Z^>0T_/I[`<`#P`+``9"" +MLA)#AHL3BA2)%746!M`!T`+0`Q(K[9""MJ/@_Z/@+R1`^>0T_/I[`<`#P`+` +M`9""KQ)#AHL3BA2)%746!-`!T`+0`Q(K[9`&,.!$$/"0!!]T(/`BD(*\[?"0 +M@KD20X_DD(*]\*/P$E7>D(*][_"0@KD20X82;JN0@K[O\)"!6>`D_&`:%&`' +M%&`$)`5P67L!>H%Y6I""O.#]$GCW@!M[`7J!>6*0@L(20X^0@KS@D(+%\'J! +M>5H2=WN0@K[@_Y""N1)#AI""O>!\`"GY[#KZP^F?^>J4`/IU$P%U%(%U%5JC +MX/46$BOM(M,0KP'#P-`2'Z3_5`'^D(%#X%3^3O[P[U0"_^Y4_4__\!(?I/Y4 +M!/WO5/M-_Y"!0_#N5`C^[U3W3O_P$A^D_E00_>]4[TW_D(%#\.Y4(/[O5-]. +M\)`!%^#^D`$6X'P`)`#_[#Z0@)_PH^_PD`'"=`'PD(%#X,,35`'_\6Z0@4/@ +M$Q-4`?_Q19`!PG0"\)"!0^`3$Q-4`?_Q2Y"!0^#$5`'_\5&0`<)T`_"0@4/@ +MQ!-4`?_Q5Y`!PG0$\)"!0^!4`?\Q[Y`!PG0%\-#0DJ\BD()X$D./[Q)#F%X4 +M`%X=`5XF`EXO`UXW!%Y`(%Y((5Y1(UY98%YB85YK8EY\@%YT@5Z$@EZ,@UZ5 +MA```7IZ0@G@20X8"99J0@G@20X8"9/20@G@20X8"9>*0@G@20X;ANY"">!)# +MA@)QAI"">!)#AH!>D()X$D.&`F8:D()X$D.&X5V0@G@20X8"2?>0@G@20X8" +M39J0@G@20X8"9F"0@G@20X:A")"">!)#AN';D()X$D.&X:&0@G@20X8"Q)#C_%Z +MD($GX/\23/&0@2?@8!F0@GL20X:0``$2'[U4#_^0``(2'[W]$FKQ(I"">^_P +M(I"">^_P(I"">^_P(I"">^_P(A(?I)"!,/`B4_`2'Z20@D[PD``!$A^]D()/\"(2'Z3_5`'^D();X%3^3O#OPQ,PX`J0 +M``$2'[V0@ESP(M,0KP'#P-`2'Z3\(.`%,=@"8)$2'Z3_5`'^D(%$X%3^3O[P +M[U0"_^Y4_4__\!(?I/Y4!/WO5/M-_Y"!1/#N5`C^[U3W3O_P$A^D_E00_>]4 +M[TW_D(%$\.Y4(/[O5-].__`2'Z3^5$#][U2_3?^0@43P[E2`_N]4?T[P[!,3 +M5#\PX`>0!I#@1`3P$A^D$Q,35!\PX`>0!I#@1`CPD(`!X+0"%)```1(?O9"! +M1?"0``(2'[V0@4;PT-"2KR+DD()J\)"":N!D`?`DEI`!Q/!T8*/PD($IX/^0 +M@2C@;V`#$E')D($DX##@!S&GOP$"$>"0@2G@D`&\\)"`H^"0`;WP,9X21>*` +MN],0KP'#P-"0@2G@<`!_`##G`G\![V4.8#[#D()LX)2( +MD()KX)030`B0`<#@1!#P(I"":^1U\`$20TM_%'X`$C*JTY"";."4,I"":^"4 +M`$"YD`'&X##@LB*0@3#@_7^3$C(>D``(X$00_7\($C(>?P$Q&9``D.!$`?U_ +MD!(R'G\4?@`",JHBD`"0X"#@^2)_`I""6N#^[\.>4!#O)>`D@?CF,.0#?P`B +M#X#F?P$BD`*'X&`(D`&X=`'P@">0@4/@,.`.D`*"X&`(D`&X=`+P@!*0`H;@ +M(.$(D`&X=`3P@`-_`2*0`;ET"/!_`"+D^_K]?P$21^.0@FWO\&#P41B`[-,0 +MKP'#P-"0`H)Y7$27=:0@TO@!/#@5`/P02F0`<#@1`+PD`%-X&2`\)"#2^"0`(GPT-"2 +MKR+D^_K]?P$21^.0@H#O\&#P<6N`[-,0KP'#P-"0@)[@_Y"`G>#^M0<$?P&` +M`G\`[V0!8$60`:_@<#_N=?`/I/^N\"0'^72`/OI[`<`"P`%T"2_Y=(`^^I"" +MA!)#C]`!T`)QU)"`G>`$\.!_`+0*`G\![V`%Y)"`G?#0T)*O(M,0KP'#P-"0 +M@H$20X^0@TS@_P3PD``![Q(?_'^O?@&11N]@29""@1)#AHL3BA2)%746`GL! +M>@%YH!(K[9""A!)#AHL3BA2)%9""@1)#AA(?I/_$5`_U%GL!>@%YHA(K[9`! +MKW3_\)`!R^!D@/#0T)*O(M,0KP'#P-"0@H?N\*/O\.2C\*/PD(*'X/ZCX/6" +MCH/@8"W#D(**X)3HD(*)X)0#0`N0`<#@1(#P?P"`%9""B>1U\`$20TM_"GX` +M$C*J@,5_`=#0DJ\BY/OZ_7\!$D?CD(*+[_!@\)&VOP'K$E/V@.;DD(-5\*/P +MD`*&X"#A+,.0@U;@E-"0@U7@E`=`"I`!P>!$!/!_`"*0@U7D=?`!$D-+?PI^ +M`!(RJH#-?P$B(I"">Q)#CY```1(?O?_^$A^D_<,3,.`2D()[$D.&D``"$A^] +MD()_\(`%D()_[_"0@G[N\)""?^#^D()^X/_3GE`XD()[$D.&$A^D5`'^=*,O +M]8+D-(#U@^[P=*,O]8+D-(#U@^!P!+&9@`>0@G[@_Y'SD()^X`3P@+J0@*/@ +M<"60@2G@<`3_$DRAD($IX&0,8`,23["0@23@5/?P5._P5+_P5'_P(B*0`@G@ +M_1(?I/ZO!>TND(`"\)```1(?O?_M+Y"``_"0``(2'[W_[2^0@`3PD``#$A^] +M_^TOD(`%\)``!!(?O?^N!>TOD(`&\"+3$*\!P\#0$A^D_Y"!(_"_`1*0``$2 +M'[UD`6`7D`4B=&_P@`^0``$2'[UD`6`%D`4BY/#0T)*O(I```A(?O?\PX"82 +M'Z20@3/PD``!$A^]D($T\.]4_O^CX%0!3_"0``,2'[V0@3;P(I"!,W0!\*-T +M`_"CX%0!1"CPHW0%\"(2'Z1^`'@8PS/.,\[8^?_[J@;J,Y7@^?B0@3\20V[L +M5`/\$D-AD($[`B#.D(-9[_`BD(-:[_`BD`$!X$0$\)`!G'1^\*-TDO"C=*#P +MHW0D\)`!FW1)\)`!FG3@\)`!F>3PD`&8!/`BY)"":/"C\)`!F.!_`##D`G\! +M[V0!8#[#D()IX)2(D()HX)030`B0`<'@1!#P(I"":.1U\`$20TM_%'X`$C*J +MTY"":>"4,I"":."4`$"YD`'&X##CLB*0`%3@537U.:/@53;U.J/@53?U.Z/@ +M53CU/*TY?U02,AZM.G]5$C(>K3M_5A(R'JT\?U<",AZ0`33@53WU0:/@53[U +M0J/@53_U0Z/@54#U1)`!-.5!\*/E0O"CY4/PH^5$\"*0`3S@547U2:/@54;U +M2J/@54?U2Z/@54CU3)`!/.5)\*/E2O"CY4OPH^5,\"*0@4/@,.`%?P021[PB +MD($GX&`#$DZ2(A)I*Y""9._PX/Q4`?Z0@23@5/Y.\.PPYA&0`2_@,.<$Y/"` +M!I`!+W2`\)"!).`PX!J0@3'D\*-T!_"0@3&CX)`%6/"0!.S@5-WP(I`$[.!$ +M(O`BD($WX##@!>3_$DFK(I"!-^`PX`5_`1))JR+3$*\!P\#0D`0=X&`:D`4B +MX%208`>0`<#@1`CPD`'&X##AY'\`@`)_`=#0DJ\BY)"#4?"C\)`%^.!P#Z/@ +M<`NCX'`'H^!P`W\!(M.0@U+@E.B0@U'@E`-`"I`!P.!$(/!_`")_,GX`$C*J +MD(-1Y'7P`1)#2X"_TQ"O`!$`O"0`0!T__"0!K=T"?"0!K1TAO!_ +M?'X($BU<[%1__)"#0Q(@SI"#0Q)#;I"%NQ(@SG]\?@@2+J*0A;L2(-K,P`#` +M?XQ^"!(NHI"%NQ(@V@#``!1_<'X.$BZBD(66$B#:``,^8.3]_Q(Q3=#0DJ\B +M$:>0@2ET#/`BY)""9?"C\*/PD`"#X)""9?"0`(/@_I""9>#_M08!(L.0@F?@ +ME&20@F;@E`!`#9`!P.!$0/"0@F7@_R*0@F;D=?`!$D-+@,+O%)`%<_"0`3]T +M$/#]?P-T12_XYDW^]G0X+_6"Y#0!]8/N\"*0@*/@9`%@`D$KD($GX'`"02N0 +M@2;@Q%0/9`%P(I`&J^"0@2WPD`:JX)"!+/"CX/]P")"!+.#^_X``D($M[_"0 +M@27@1`3PY)"!+_"0@3&CX)`%6/"0`5?D\)`!/'0"\)"!*N!4_?!4[_"0@2;@ +M_\14#R3]4`*``Q)2KI"!)>`3$Q-4'S#@#Y"!+.#_H^"U!P4Q3PHW0"\.20 +M@2KPD($DX%3^\)"!*'0,\)"!).!4W_"0@2ET#/"0@23@5+_P5'_PH^!4_O!4 +M_?!4]_"0@`'@_[0!")"!,'21\(`/[Y"!,+0#!720\(`#=$#PD($S=`'PHW0# +M\*/@5`%$*/"C=`7P(N\D_F`,!'`HD($L=`'PH_`B[7`*D($VX)"!+/"`!9"! +M+.WPD($LX*/PD($EX$0(\"(24BGO9`%@")`!N'0!\(!4D($JX/]4`V`(D`&X +M=`+P@$.0@2C@_N3#GE`(D`&X=`3P@#'O,.((D`&X=`CP@"60@2K@,.0(D`&X +M=!#P@!:0@27@$Q-4/R#@")`!N'0@\(`#?P$BD`&Y=`3P?P`B[V`^D("CX&0! +M<#:0@27@5/[PD`4B=`_PD`8$X%2_\.3_$D^-OP$.D($DX$1`\)"!*70&\"*0 +M`;ET`?"0`;AT"/`BD`4B=&_PD`4GX%2_\)"!*70&\")T'RWU@N0T_/6#X%0_ +M\.]@'70A+?6"Y#3\]8/@1!#P=!\M]8+D-/SU@^!$@/`B="$M]8+D-/SU@^!4 +M[_!T'RWU@N0T_/6#X$1`\"*K!ZH&[2O[Y#KZPY"`H.";D("?X)I0$Z/@)`'_ +MD("?X#0`_L/KG_OJGOKJD/T1\*\#=``O]8+D-/OU@^#_(N#^H^#_D`*$[_#N +MH_"CX$0!\)`!O.`$\"*0`1_@_I`!'N!\`"0`_^P^D()[\*/O\)`"A^#YD(%# +MX"#@`J%9Y/OKPYE``J%9D()[X/RCX/WLD/T1\'0"+?6"Y#3[]8/@5`\S,S-4 +M^/IT`2WU@N0T^_6#X/YT`"WU@N0T^_6#X'P`)`#_[#Y4/ZT'_.HD&/_D,_[O +M+?WN//R0@*'@_J/@_[%:K0>0@GONC_`20TN0@)_@_J/@_Y"">^#\H^#3G^R> +M0"*0@GO@_J/@_Y"`G^#\H^`D`?WD//S#[YW_[IR0@GOPH^_PD()[D6X+@:XB +M[X[P$D.^;7@`0&V@`(!MRP$`;=\"`&WW!````&X4[50_<`3^_X`$?@!_0.\M +M_^X\_N]X!L[#$\X3V/EX!L,SSC/.V/F`)NU4?W`$_O^`!'X`?X#O+?_N//[O +M>`?.PQ/.$]CY>`?#,\XSSMCY_:P&@$GM<`3^_X`$?@%_`.\M[CQ]`/R`->Q4 +M`4UP!/[_@`1^`G\`[RWN/,,3?0"`&NQ4`TUP!/[_@`1^!'\`[RWN/!,35#]] +M`"7@)>#\K@2O!2*0@4C@_R#@!Y`!/^`PXA3O1`&0@4CPD(%$X,14#R#@`W\` +M(G\!(N^0`<>TH`;@1`3P@`3@1`CPD(%(X$0!\"+D_G00+O6"Y#0&]8/@_72? +M+O6"Y#2"]8/M\.\N)`3U@N0T^_6#X/UTF2[U@N0T@O6#[?`.[K0&RGB??()] +M`7L!>H)YF7X`?P8217'O?P!P`G\!(M,0KP'#P-"0@SD20X_DD(,\\)"#.1)# +MANDD$/GD.HL3]12)%746!GL!>H-Y/1(K[750`751@7523W53`'54!GL!>H-Y +M/1)(P>]P!9""3H`#D()/X)"!6?"0@5G@%&`1%&`6)/Y@$A1@!Q1@!"0&@!"0 +M@SQT!/"`#9"#/'0(\(`%Y)"#//"0@SS@_]#0DJ\BD(*9[_"C[?!XH7R"?0%[ +M_WI`>*=\@GT!>_]Z0'G&?@!_!!)"T'BK?()]`7O_>D!YRGX` +M?P020M"0@IK@_Y""F>`O_R0&]8+D-/OU@^!D"&`#`G"!=``D"OGD-/MU$P'U%(D5=18&>P%Z@GF;$BOMD(*: +MX/^0@IG@+R00^>0T^W43`?44B15U%@9[`7J">:$2*^V0@IK@_Y""F>`O)!;Y +MY#3[=1,!]12)%746!'L!>H)YIQ(K[7B;?()]`7L!>H%Y27X`?P8217'O<%B0 +M@IK@_Y""F>`O)"#YY#3[=1,!]12)%746!'L!>H)YJQ(K[7BK?()]`7L!>H%Y +M57X`?P0217'O:&0@K(20X_DD(*U\'J">:<"6Z60!C#@1"#P(G0` +M+_6"Y#3[]8/@5`QD"'!B[RW^)`;U@N0T^_6#X&2(<%%T!R[U@N0T^_6#X&2. +M<$+O+2O^)`'U@N0T^_6#X&0#<#!T!B[U@N0T^_6#X##C&Y"!1.#$$Q-4`S#@ +M%I`!Q^!$`?"0@4C@1`'P(I`!Q^!$`O`BD`()X/T2'Z3^KP7M+I""4/"0``$2 +M'[W_[2^0@E'PD``"$A^]_^TOD()2\)```Q(?O?_M+Y""4_"0``02'[W_[2^0 +M@E3PD``%$A^]_^TOD()5\)``!A(?O?^N!>TOD()6\"*0`@G@_1(?I/ZO!>TN +MD()7\)```1(?O?_M+Y""6/"0``(2'[W_K@7M+Y""6?`B$A^D_U0!_I""7N!4 +M_D[P[\,3,.`4D``!$A^]D()?\)```A(?O9""8/`BD(+'$D./D(+*[?#DD(,6 +M\)"#%N#_PY1`4!1TTR_U@N0T@O6#Y/"0@Q;@!/"`XI""QQ)#AHL3BA2)%9"" +MRN#U%GL!>H)YTQ(K[>20@M+PD(+2X/_#E$!0%G33+_6"Y#2"]8/@9#;PD(+2 +MX`3P@."0@LL20X:0@L[@__6"=8,`=(`2'_SO=?`(I"0`_^7P-`+\D`!^$A_\ +M[Y``?Q(?_.20@Q/PH_"0@Q/@_J/@_\.4P.Z4`$`"@0/#[Y1`[I0`4%*C=$#P +M=-,O^>0T@OI[`71`1(C]$B@(D(,3H^`DU_GD-(+Z>P&CX$2)_1(H")"#$Z/@ +M)-OYY#2"^GL!H^!$BOT2*`B0@Q.CX"3?^>0T@OI[`6%$Y)"#%?"0@LL20X:0 +M@Q/@_J/@*?GJ/OKI),#YZC3_^G2(_1(H")""RQ)#AI"#$^#^H^`I^>H^^NDD +MQ/GJ-/_ZH^!$B?T2*`B0@LL20X:0@Q/@_J/@*?GJ/OKI),CYZC3_^J/@1(K] +M$B@(D(++$D.&D(,3X/ZCX"GYZC[ZZ23,^>HT__JCX$2+_1(H")"#%>!$D)`! +MC/#DD(,7\*/PD`&,X"#D#\.0@QC@E!"0@Q?@E"=0$W\!?@`2,JJ0@Q?D=?`! +M$D-+@->0@Q?@_J/@_\.4$.Z4)T`,D`8QX$0!\.Z0!C;PD(,4X%0_9#!P2Y"# +M%_"C\)`!C.`PY0_#D(,8X)00D(,7X)0G4!-_`7X`$C*JD(,7Y'7P`1)#2X#7 +MD(,7X/ZCX/_#E!#NE"=`#)`&,>!$`O#ND`8V\)"#$^1U\!`20TM!5)""SQ)# +MANDD$/GD.OI]@!(JCY""SQ)#ANDD#/GD.OI]@1(JCY""SQ)#ANDD"/GD.OI] +M@A(JCY""SQ)#ANDD!/GD.OI]@Q(JCY""SQ)#AGV$$BJ/Y)"#%O"0@Q;@_\.4 +M0%`4=-,O]8+D-(+U@^3PD(,6X`3P@.*0@L<20X:+$XH4B160@LK@]19[`7J" +M>=,2*^WDD(+2\)""TN#_PY1`4!9TTR_U@N0T@O6#X&1<\)""TN`$\(#@Y)"" +MTO"0@L\20X:0@M+@__6"=8,`$A^]_I""RQ)#AH^"=8,`[A(?_)""TN`$\."T +M%-.0@LL20X:0`!1T@!(?_)""TG05\)""TN#_PY0^4!>0@LL20X:/@G6#`.02 +M'_R0@M+@!/"`WY""RQ)#AI``/G0"$A_\D``_=*`2'_SDD(,3\*/PD(,3X/ZC +MX/_#E(#NE`!``L'LP^^40.Z4`%!2HW1`\'33+_GD-(+Z>P%T0$2(_1(H")"# +M$Z/@)-?YY#2"^GL!H^!$B?T2*`B0@Q.CX"3;^>0T@OI[`:/@1(K]$B@(D(,3 +MH^`DW_GD-(+Z>P'!+>20@Q7PD(++$D.&D(,3X/ZCX"GYZC[ZZ23`^>HT__IT +MB/T2*`B0@LL20X:0@Q/@_J/@*?GJ/OKI),3YZC3_^J/@1(G]$B@(D(++$D.& +MD(,3X/ZCX"GYZC[ZZ23(^>HT__JCX$2*_1(H")""RQ)#AI"#$^#^H^`I^>H^ +M^NDDS/GJ-/_ZH^!$B_T2*`B0@Q7@1)"0`8SPY)"#%_"C\)`!C.`@Y`_#D(,8 +MX)00D(,7X)0G4!-_`7X`$C*JD(,7Y'7P`1)#2X#7D(,7X/ZCX/_#E!#NE"=` +M#)`&,>!$`?#ND`8V\)"#%.!4/V0P<$N0@Q?PH_"0`8S@,.4/PY"#&."4$)"# +M%^"4)U`3?P%^`!(RJI"#%^1U\`$20TN`UY"#%^#^H^#_PY00[I0G0`R0!C'@ +M1`+P[I`&-O"0@Q/D=?`0$D-+H3V0@L\20X;I)!#YY#KZ?8`2*H^0@L\20X;I +M)`SYY#KZ?8$2*H^0@L\20X;I)`CYY#KZ?8(2*H^0@L\20X;I)`3YY#KZ?8,2 +M*H^0@L\20X9]A`(JC\/NE`%`"@WM$Y#]$/#D+_\BP^Z4`4`DD/T1X&UP&I`! +M%^"U!0V0`>1T=_"0_1'D\(`&[020_1'PY"__(I""OQ)#CY""Q>!@`P)X4I"" +MPA)#AA(?I/1@`P)X1Q(?ZI""PA)#AI```1(?O?1@`P)X-Y```1(?_)```A(? +MO?1P;Y""PA)#AI```N02'_R0``,2'[WT<$Z0@L(20X:0``/D$A_\D``$$A^] +M]'`MD(+"$D.&D``$Y!(?_)``!1(?O9""PK3_#!)#AI``!>02'_R`1!)#AI`` +M!8`JD(+"$D.&D``$@!^0@L(20X:0``.`%)""PA)#AI```H`)D(+"$D.&D``! +M=`$20QB`"Y""PA)#AG0!$D+VD(+"$D.&$A^D_Y""OQ)#AN\2'^J0@L(20X:0 +M``$2'[W_D(*_$D.&D``![Q(?_)```N02'_R0``-T(!(?_)""PA)#AI```A(? +MO?^0@K\20X:0``3O$A_\D(+"$D.&D``#$A^]_Y""OQ)#AI``!>\2'_R0@L(2 +M0X:0``02'[W_D(*_$D.&D``&[Q(?_)""PA)#AI``!1(?O?^0@K\20X:0``?O +M`A_\D(+"[?"0@K\20X^0``,2'[V0@L;PD(*_$D.&BQ.*%(D5=18#>P%Z@GG# +M$BOMD(+"X'!&_W3#+_6"Y#2"]8/@M/\.=,,O]8+D-(+U@^3P@`]TPR_U@N0T +M@O6#X`3P@`4/[[0#T'43`744@G45PW46`Y""OQ)#AA(K[2(`8'!P:'E?05!# +M86QI8G)A=&5?.#$X.$4```#__P``<&AY7U-I;75L87)I='E#;VUP87)E7S@Q +M.#A%`$]$35]4>%!W`!?4$A97U!A=&A!1FEL +M;$E12TUA=')I>`!P:'E?4&%T:$)?25%+7S@Q.#A%`'!H>5]0871H05]2>$E1 +M2P!P:'E?4&%T:$%?25%+7S@Q.#A%`%]02%E?4F5L;V%D34%#4F5G:7-T97)S +M`%]02%E?4V%V94U!0U)E9VES=&5R`P` +M`(`,``"(#```E`P``)P,``"@#```4$A97TE10V%L:6)R871E7S@Q.#A%```` +M;V1M7U1X4'=R5')A8VM39710=W(X.$4````"`P0$!08'!P@)"@H+``#__OW\ +M_/S\^_GX]_?V`````@0&"`H,#A`2%!88&AL``@0&"`H,#A`2%!89&1D``&]D +M;5]46%!O=V5R5')A8VMI;F=#86QL8F%C:U]4:&5R;6%L365T97)?.#$X.$4` +M`&]D;5]#;VYF:6="0E]02%E?.#$X.$4``&]D;5]#;VYF:6="0E]02%E?4D5' +M7U!'7S@Q.#A%````;V1M7T-O;F9I9T)"7T%'0U\X,3@X10``;V1M7T-O;F9I +M9TU!0U\X,3@X10!O9&U?0V]N9FEG4D9?4F%D:6]"7S@Q.#A%````;V1M7T-O +M;F9I9U)&7U)A9&EO05\X,3@X10```&H8U#`^2:AA$GI\DF]D;5]39714>%)0 +M5%1I;6EN9U\X,3@X10````!O9&U?4F%T941E8VES:6]N7S@Q.#A%```````` +M```````D)BH8&AT?(2`"@`,@!0`'@`R``8`4`!E@"@`/``:`'T`5@"(`/H`P$!`0$!`@,$!08' +M"`$"`P0%!@<(!08'"`D*"PQO9&U?4F%T941O=VY?.#$X.$4```0`!``(`!`` +M&``D`#``2`!@`)``P`#8`#P`4`!D`*``\`"0`3`"@`(L`4`!X`'0`N@#L`1` +M!M`';V1M7U)A=&55<%\X,3@X10`````""A@H/````$]$35]205]397124U-) +M7S@Q.#A%`````$]$35]205]'971(=U!W&``@``!O9&U?4D%4>%)0 +M5%1I;65R4V5T=&EN9P!/1$U?4D%?57!D871E4F%T94EN9F]?.#$X.$4`;V1M +M7T%21D)2969R97-H7S@Q.#A%````3T1-7T1)1U],;W=E5\X.$4` +M````;V1M7T9A4EN:71?.#A%```````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M````````.#$X.&5U+G)T=U]M8S)U7V1I&UI=``X,3@X974N'0```````#CBP`````` +M`&UP7VEO8W1L``````````#DBP```4@``&%P:6YF;P````````````#EBP`` +M`D@``'-E='!I9`````````````#FBP```4@``'=P0#HBP```4@``'=P"4P,G@E,#)X +M)3`R>"4P,G@*`$Y!5#(U.B!!<'!L971A;&L@04%24"!386YI='D@8VAE8VL@ +M9F%I;"$*````4TE$('1A9R!L96YG=&@@=&]O(&QO;F71E +M"Q2 +M871E4T=)(#T@)60L($1E8VES:6]N4F%T92`](#!X)3`R>"`L4%13=&%G92`] +M("5D"@```#T]/B`E&1W,"@P>"4P.'@I"@``='AD=S$H,'@E,#AX*0H``'1X9'"D*``!T>&1W,R@P>"4P.'@I"@``='AD=S0H,'@E,#AX*0H``'1X9'"D*``!T>&1W-B@P>"4P.'@I"@``='AD=S0H`````)7,H*3H@(#T]/3X@<&AY7T-O;F9I9T)"5VET:$AE +M861E0H`````)7,H*3H@4$A97T-O;F9I9U)&5VET:$AE861E"DN(`H`)7,H*3H@3T1-7U=R:71E7T1) +M1R@I.D-U"`*`"5S*"DZ(&]D;5]$243TE9`H`)7,H*3H@8DQI;FME +M9#TE9`H````E71E`H````E"5X"@```"5S*"DZ($-U=%9E7!E/25D"@`E'1,3D$])60*`````"5S*"DZ($5X=%!!/25D"@`E +M'144E-7/25D"@```"5S*"DZ(%!A=&-H240])60*````)7,H*3H@ +M8DEN2&-T5&5S=#TE9`H`````)7,H*3H@8E=)1DE497-T/25D"@`E"5X"@``)7,H*3H@3W)G:6YI86P@ +M5DD@4$%204TZ(#!X)7@*```E`H``"5S*"DZ($]R9VEN:6%L($)+(%!!4D%-.B`P>"5X"@``)7,H*3H@4U=! +M4SI);FET(%-7($%N=&5N;F$@4W=I=&-H"@``4W=!;G1E;FYA4W=I=&-H5&EM +M97(`````6T]$32TY,D-=(```6T]$32TY,D1=(```6T]$32TX-S(S05T@```` +M`%M/1$TM.#$X.$5=(`````!;3T1-+3@X,3)=(`!;3T1-+3@X,C%=(``E5]3:6UU;&%R:71Y0V]M<&%R95\X +M,3@X12!C,2`E9"!C,B`E9"$A(0H``"5S*"DZ($E12SIP:'E?4VEM=6QA4-O;7!A"`E9"!C +M;VUP87)E,2`P>"5X(&-O;7!A"5X+"!46#%?02`](#!X)7@*```` +M)7,H*3H@62`](#!X)7@L(%18,5]#(#T@,'@E>`H````E"P@5%@P7T$@ +M/2`P>"5X+"!/;&1V86Q?,"`P>"5X"@`````E"P@5%@@ +M/2`P>"5X"@``)7,H*3H@7U!(65]0871H049I;&Q)44M-871R:7@@;VYL>2!4 +M>"!/2PH````E&5A8R`](#!X)7@* +M`"5S*"DZ(#!X96(T(#T@,'@E>`H`)7,H*3H@,'AE8F,@/2`P>"5X"@`E&5C-"`](#!X)7@*`"5S*"DZ(#!X96-C(#T@,'@E>`H`)7,H*3H@4&%T +M:"!"(%)X($E12R!F86EL(2$*`"5S*"DZ(%!A=&@@02!2>"!)44LA"@```"5S +M*"DZ(%!A=&@M02!2>"!)44L@;6]D:69Y(%)825%+(&UO9&4@=&%B;&4A"@`` +M`"5S*"DZ($Q/(&-A;&EB`H`)7,H*3H@,'AE.6,@/2`P>"5X"@`E&4T +M,"`](#!X)7@@=31T;7`@/2`P>"5X(`H````E2!26$E12R!M;V1E('1A8FQE(#(A"@`E&5A-"`](#!X +M)7@*`"5S*"DZ(%!A=&@@02!2>"!)44L@9F%I;"$A"@`E"!)44L@1F%I;"$A"@`E2$*```E"!296=%030])7@@ +M4F5G14%#/25X(%)E9T5"-#TE>"!296=%0D,])7@@4F5G14,T/25X(%)E9T5# +M0STE>`H@`````"5S*"DZ($E12SH@9FEN86Q?8V%N9&ED871E(&ES("5X"@`` +M`"5S*"DZ($E12SH@1D%)3"!U"!P"5X($5% +M4%)/371H97)M86QM971E"5X"@`E"5X+"!/1D1-7VEN9&5X/3!X)7@*```E"5X+"!#0TM?:6YD97@],'@E>"P@8V@@,30@ +M)60*`"5S*"DZ(%)E9T$R-#H@,'@E6"P@0T-+4W=I;F=486)L95]#:#%?0V@Q +M,ULE9%U;,ETZ($-#2U-W:6YG5&%B;&5?0V@Q7T-H,3-;:5U;,ETZ(#!X)5@* +M```E"5X+"!#0TM?:6YD97@],'@E +M>"P@8V@Q-"`E9`H``"5S*"DZ(')E;&]A9"!O9F1M(&EN9&5X(&9O"5X(`H` +M````)7,H*3H@4F5A9&)A8VL@5&AE"!%15!23TUT:&5R;6%L;65T97(@,'@E>"!D96QT +M82`P>"5X(&1E;'1A7TQ#2R`P>"5X(&1E;'1A7TE12R`P>"5X(`H````E"!P"!D96QT85],0TM?8F]U;F0@,'@E>"!D96QT85])44M?8F]U +M;F0@,'@E>`H``"5S*"DZ('1E;7`@3T9$35]!7VEN9&5X/3!X)7@L($-#2U]I +M;F1E>#TP>"5X"@```"5S*"DZ(&YE=R!/1D1-7T%?:6YD97@],'@E>"P@0T-+ +M7VEN9&5X/3!X)7@*`````"5S*"DZ(%1X4'=R5')A8VMI;F<@9F]R('!A=&@@ +M03H@6"`](#!X)7@L(%D@/2`P>"5X(&5L95]!(#T@,'@E>"!E;&5?0R`](#!X +M)7@@96QE7T0@/2`P>"5X(#!X93DT(#T@,'@E>"`P>&4Y8R`](#!X)7@*```` +M`"5S*"DZ(%1X4'=R5')A8VMI;F<@,'AC.#`@/2`P>"5X+"`P>&,Y-"`](#!X +M)7@@4D8@,'@R-"`](#!X)7@*```E"5X"@`````E"!2871E240] +M)60@3G-C1&]W;CTE9"!.'1E;F0@4E!4(%1I;6EN9PH` +M```E`H`````)7,H*3H@($UA8TE$/25D($1E8VES:6]N4F%T93TP>"5X +M"@``)7,H*3H@36%C240])60@4T=)/25D"@``)7,H*3H@/3T]/3T^"@```"5S +M*"DZ(#T]/3T]/D]$35]205-U<'!O%)05#)(86YD;&5?.#$X.$4H*3H@=F%L:60P/25D('9A;&ED +M,3TE9"!"=69F97),96YG=&@])60*````)7,H*3H@;6%C:60])60@5&]T86P] +M)60@4C`])60@4C$])60@4C(])60@4C,])60@4C0])60@1#`])60@=F%L:60P +M/25X('9A;&ED,3TE>`H`````)7,H*3H@(%1/5$%,/3`A(2$A"@`E"4P-'@@;6EN4G!T5&EM93TP>"4P-'@*`````"5S*"DZ +M("`\/3T]/3UO9&U?4D%4>%)05%1I;65R4V5T=&EN9R@I"@`E"5X(%)A=&5-87-K/3!X)7@@4T=)16YA8FQE/25D"@`` +M)7,H*3H@3T1-7T%21D)2969R97-H7S@Q.#A%*"DZ(%!436]D95-3/25D"@`E +M"!(:6=H97-T4F%T93TE9`H`6T]$ +M32TY,D-=(```6T]$32TY,D1=(```6T]$32TX-S(S05T@`````%M/1$TM.#$X +M.$5=(`````!;3T1-+3@X,3)=(`!;3T1-+3@X,C%=(``E`````` +M"4P,G@)````)7,E,#)8(``E"4P,E@@````"4P,E@`````)7,L`&%B;&5R87<`6V%V86EL86)L92!R87<@ +M"4P,E@@``!B=&9F86ME`&)T8F9A:V4`=VQR9FMM87`` +M````)7,@)3`R6`!#;VUM86YD(&YO="!F;W5N9"$``'=M87``````=W)A=P`` +M``!B='=M87```&)T=V9A:V4`8G1D=6UP9F%K90``=VQD=6UP9F%K90``8G1F +M:S)M87``````=VQF:S)M87``````=VQW9F%K90`\5TE&24!214%,5$5+/@`` +M9&ES86)L925D````=W!S0TT]```*"DT])2XT9``````*"DT],#`P,`````!D +M979./0````H*3CTE7!A9```<&)C`&QA8F5L````;F5G;ST```!I;G1E;G0] +M`'-S:60]````9V]T7W=P"4P,E@``#!X)3`T6```,'@E,#A8``!7 +M15``;F]N90````!42TE0`````$-#35``````245%12`X,#(N,3%B;@```$E% +M144@.#`R+C$Q8@````!)145%(#@P,BXQ,6)G;@``245%12`X,#(N,3%B9P`` +M`$E%144@.#`R+C$Q86X```!)145%(#@P,BXQ,6$`````245%12`X,#(N,3%G +M;@```$E%144@.#`R+C$Q9P````!U;F%S#HE,#)X.B4P,G@Z)3`R>``E*G,@)7,``%53``!%50``2E```$-.``!! +M4U-/0TE.1D\H4F5Q245S/0```"4P,G@`````*0```&EN8VQU9&4O;F5T+V-F +M9S@P,C$Q+F@``"5S"@`E"5X"@``56YS +M=7!P;W)T960@8VEP:&5R.B`P>"5X"@```"5S+"!E7!E/25D +M"@```"5S.G)F7W1Y<&4])60*``!I;F-L=61E+VYE="]C9F3TE<"P@:V5Y7VQE +M;CTE9"P@:V5Y7VED>#TE9`H`8G-S:60])3`R>#HE,#)X.B4P,G@Z)3`R>#HE +M,#)X.B4P,G@*`````"5S+"!F=U]S=&%T93TP>"5X+"!G;W1O(&5X:70*```` +M;6%T8VAE9"!B>2!B"5X"@```$EN=F%L:60@:V5Y(&UG=#H@,'@E>`H``"5S+"!I95]L +M96X])60*``!G;W0@=W!A7VEE"@!G;W0@=W!A,E]I90H`````)7,H*2TE9#H@ +M3TE9`H``"5S+"!S=&%?:6YF;R!I#HE,#)X.B4P,G@Z)3`R>#HE,#)X"@`````M)7,*```` +M`"5S*&YE=&1E=CTE<"DL(&)E86-O;E]H96%D7VQE;CTE9"P@8F5A8V]N7W1A +M:6Q?;&5N/25D"@``861D(&)C;BP@=W!S7VEE;&5N/25D"@``9V]T('`R<%]I +M92P@;&5N/25D"@!%;F%B;&4@4#)0(&9U;F-T:6]N(&9O`H````` +M:V5Y7VQE;CTP>"5X"@```'-E<5]L96X],'@E>`H```!K97E?:6YD97@])60* +M````<&%I7!T+G-E=%]T>"`]/3$@"@```"5S+"!R970])60*`&5R"5X+"!I9G1Y<&4])60*`````"5S+"!O;&1?:69T>7!E/25D +M+"!N97=?:69T>7!E/25D"@```"5S+"!R;VQE/25D+"!P,G!?7!E/25D"@`````E&ES=&5D"@``)7,L(&YD978])7`L('!M;VY?;F1E=CTE<"P@"5X"@`E"P@:7-?1T\*````)7,L(&EE;&5N/25D"@```&EF='EP93TE9"!B969O +M7!E7W9A;&ED/25D"@``)7,L(&9C(#T]($E% +M144X,#(Q,5]35%E015]04D]"15]215-0"@```"5S+"!F#HE +M,#)X.B4P,G@Z)3`R>#HE,#)X.B4P,G@`)7,@&ET7VUO9'5L90!M=C@X=S@V.#9?:69?``"P +ML*Z`W!X``+"PKH!\'P``L+"N@!P@``"PL*Z`O"```+"PKH!H(0``KPBQ@!PC +M``"PL*R`L",``+"PJ(``)```L+"H@`PD``"PL*B`+"0``+"PJ(`X)```L+"H +M@,@D``"PL*B`U"0``+!?@(!8)0``L+"G@-PE``"PL+"`,"8``+"O!(!$)P`` +ML+"P@&PG``"PL+"`C"<``+"PL("L)P``L+"J@-PG``"PL+"`6"@``+"PK(", +M*```L+"J@!PI``"PJPB``"H``+"G`8`L+```L*<#@/@N``"PL*"`)"\``+"P +MH(!0+P``L+"P@&0O``"PJ@.`)#```+"PJH!0,```L+"P@-0P``"PJPB`,#(` +M`+"O$H"$,P``L+"C@#`T``"PL+"`Q#0``+"PHX#8-0``L+"B@)0V``"PL*"` +MP#8``+"PL(#0-@```````%`X``"O/PZ`>#H``+"O*H"P/P``L+"N@-1```"P +MKRJ`S$<``+"PJH!(2```#`````Q)``"O/PR`V$H``+"PJ(#X2@``L+"H@!A+ +M``"PL*B`.$L``+"PJ(!X2P``L+"H@)A+``"PL*B`V$L``+"PJ(#\2P``L+"H +M@!Q,``"PL*B`1$P``+"PJ(!H3```L+"H@)Q,``"PL*B`P$P``+"PJ(#D3``` +ML+"H@`A-``"PL*B`+$T``+"PJ(!030``L+"H@'1-``"PL*B`F$T``+"PL(`( +M3@``L+"P@!Q.``"PL*B`+$X``+"PJH"83@``L*L"@!Q0``"PL*B`B%```+"P +MK(`(40``L+"J@+A1``"PK@&`[%8``+"PJ(`H5P``L+"J@+17``"PL*B`)%@` +M`+"PJH!$60``L+"J@/1:``"PL*J`X%P``+"PJH#,7@``L*`$@$A?``"PL+"` +MP%\``+"PL(`08```L+"H@%A@``"PL*&`I&```+"PL(#88```L+"H@/1@``"P +ML+"`/&$``+"PJH!D80``L+"J@(AA``"PL+"`Z&$``+"PL(!$8@``L+"H@'AB +M``"PJP*`N&,``+"PJH#\8P``L+"J@"QD``"PL*R`S&8``+"PJH"`9P``L*P# +M@.QH``"PK@&`X&D``+"J`X!<:@``L*\$@#!K``"PKP:`L&P``+"I`H`8;0`` +ML*X!@!QN``"PJ@.`F&X``+"O!(!X;P``L*D"@.!O``"PL*R`)'```+"I`H"$ +M<```L*\$@,!Q``"PL*B`9'(``+"PK(!````L+"P@&AX````A`*`X'@``+"PJH"$>0```(0"@+!Y``"P +ML*J`3'H``+"J`8#`>P``L*\0@$Q]``"PL*B`+'\``*\(L8"P@```L*D"@*"! +M``"PL*Z`*(0``+"PJ(",A```L*P!@""%``"PL*B`+(4``+"PJH!(L``+"PJH#`BP``L+"L@!B-``"PL*B`=(T``+"P +MK(#DCP``KPBQ@`B5``"PL*R`7)8``+"H`8`0EP``L*\$@!"9``"PL*B`A)D` +M`+"PJ(#`F0``L*L"@$R<``"PL*R`K)X``+"PJH!LGP``L+"H@'B?``"PL*R` +M^)\``+"PJ(`$H```L+"J@*"@``"PL*B`K*```+"PKH"XH@``L+"J@"2C``"P +ML*J`>*0``+"PJ("8I```L+"H@-"D``"PL*B`W*0``+"PK("PI0``L+"H@+RE +M``"PL+"``*8``+"PL(#TI@``L+"P@/RF``"PL+"`!*<``+"PL(`,IP``L+"P +M@!2G``"PL+"`'*<``+"PK(!\IP``L+"P@(2G``"PL*B`O*<``+"A"X`TJ``` +M`(0"@&RH``"PL+"`H*@``+"PL("HJ````(0"@"2I``"PL+"`.*D``+"PL(!( +MJ0``L+"A@,2I``"PL+"`"*L``+"PL(!\JP``L+"P@(RK``"PL+"`E*L``+"P +ML(".H``+"PJH#$Z@``L*\(@/3N``"PKP2`#/(` +M`+"PJ(#L\@``L+"J@&CS``"PJP*`Z/0``+"N"8`4]P``L*\&@"S[``"PKP:` +M;``!`+"L`8#4``$`L*\0@+`+`0"O"+&`U`P!`+"I`H"4#0$`L*D"@+0.`0"P +ML*J`K`\!`*\$LH!T$P$`L*\&@%P6`0"PK`&`4!H!`+"N`8`@'`$`KC\%@+0> +M`0"O/PB`4"(!`*\_!(!<)0$`KP:R@(`J`0"PL*J`5"L!`*\_!(#$+P$`L+"H +M@-0O`0"PKAV`X#$!`+"I`H`D,P$`KPRR@+`Y`0"PKA&`+#\!`+"PK(#`0`$` +ML+"L@+1!`0"PL*R`J$(!`*\(L8!,1`$`L*\&@+!'`0"O/P"`H%$!`*\(L8"D +M4P$`L*L"@$15`0"PJP*`H%8!`+"K"(`86`$`L+"P@)!8`0"PL+"`W%@!`+"P +ML(#\6`$`L+"J@&Q9`0"PL+"`C%D!`+"PJH#<60$`L+"N@%!:`0``A`*`?%H! +M``"$`H"H6@$``(0"@-Q:`0``A`*`!%L!`+"PJ(`@6P$`L+"H@#Q;`0"PL*J` +MB%L!`+"PL("86P$`L+"P@*!;`0"PL+"`T%L!`+"PL(#T6P$`L+"P@#A<`0"P +ML+"`7%P!``"$`H"$7`$`L+"H@*!<`0"PKP2`Q%T!``"$"(`47@$`L+"P@'1> +M`0"PKP*`[%\!`+"K`H``80$`L*D"@'QA`0"PL+"`&&(!`+"PL(`P9`$`L+"L +M@(1D`0"PL*R`T&0!`+"PL(#D9`$`L+"P@"QE`0"PL+"`9&4!`+"PL("@90$` +ML+"H@+1E`0"PL*B`P&4!`+"PJ(#090$`L+"H@$AF`0"PJ0*`1&`$`L+"H +M@)AY`0"PL*&`-'H!`+"PH8#,>@$`L+"P@!![`0"PL*6`N'L!`+"PH8!,?`$` +ML+"H@*Q]`0"PL*J`)'X!`+"PJH"X?@$`L*P!@.2``0"O"+&`N((!`*\(L8"P +MA`$`L+"J@$R%`0"PL*B`6(4!`*\(L8#$AP$`L+"J@)B(`0"PL*J`^(@!`+"P +MK(#0B0$`L*\"@(B-`0"PL*B`<(X!`+"K!(`HD`$`L+"J@*R0`0"PL*B`))$! +M`+"PJ("`0"O +M"+&`D)X!`+"O`H!(H`$`L+"N@"RA`0"P_82`:*$!`+"PJ("`H0$`L+"H@*BA +M`0"PL*J`Z*$!`+"PK(#PH@$`L+"H@!BC`0"PL+"`(*,!`+"L`8`DI`$``(0" +M@&"D`0"PKP*`E*@'3:`0"PL*B`U-H!`+"PK(#(VP$`L+"H +M@.C;`0"PL*B`.-P!`+"O`H"DW@$`L+"P@.S>`0"PL+"`]-X!`+"PL(#\W@$` +ML+"P@`3?`0"PJ`&`_-\!`+"J`X`8X0$`L*\<@+#C`0"PL*Z`H.@(`7X0"@/1Z`@"P +ML*J`&'L"`+"O#(!8?`(`L+"P@%Q\`@"PH@*`%'T"`+"G"8#\?P(`L+"P@!2` +M`@"PL+"`0(`"`+"PL(!<@`(`L+"P@'B``@"PL*R`T(`"`+"PK(`H@0(`L+"P +M@("!`@``A`*`]($"`+"PK(`X@@(``(0"@+R"`@"PL*J`4(,"`+"PK("4@P(` +ML*\"@-B%`@"PJ@.`*(@"`+"O&H#0B@(`L+"P@%"+`@"PL*B`T(L"`+"PJ(#L +MBP(`L+"L@&"-`@"PJ@&`H(X"`+"PKH`)D"`+"PJ("@F0(`KPBQ@'B;`@"PL*R` +M])L"`%^$!H#TG0(`L*\0@&"B`@"PJP*`K*("`+"I!(`$$#`+"PJ(`@0@,`L+"N@&Q"`P"PL*J`W$(#`+"PK(`D10,`L+"H@'1%`P"P +ML*B`&$8#`+"O*("P50,`L+"N@&!7`P"P#82`Q%X#`+"PJH!(8@,`L-^$@'AP +M`P"P#82`('0#`+`-A(`T?`,`L`V$@)B'`P"O"+&`/(D#`+`-A(#DB@,`L`V$ +M@"2.`P"P#82`A(\#`+"H`8#LCP,`L+"H@`20`P"PL*B`*)`#`+"PJ(`\D`,` +M`(0"@'"0`P"PKRB`J)(#`+"PJ(#,D@,`L*L&@"23`P"PL*J`6),#`+"PJ(#0 +MDP,`L*L&@#B4`P"PJP:`I)0#`+"PJ(#$@!"C`P"PKPZ` +MY*<#`+"PKH#@J@,`L/>$@"2L`P"PK`&`5*X#`+"PKH#8KP,`L*X!@"BQ`P"P +ML*Z`<+(#`+`]A("@LP,`WX0!@"2U`P"PK@&`9+8#`+"O`H`HN@,`L*\$@+"^ +M`P"PKP*`I,8#`+"O`H!0V`,`KPBQ@%C@`P"O"+&`@.$#`*\(L8"HX@,`L*\F +M@,SQ`P"PKSR`5/X#`+`-A(!H_P,`L*\@@+`1!`"PL*R`+!,$`+"K`H"(%`0` +ML+"J@&P5!`"PL*J`2!8$``"$`H#T%@0`L*H!@.`7!`"PJ@&`S!@$`+"PH8"H +M&00`L+"N@!0;!`"PKP:`Y"\$`+`WA(#L,`0`L+"N@/PQ!`"PL*Z`##,$`+"P +MK(`<-`0`L+"L@!PU!`"P#82`!#8$`+"O#H#$/P0`L+"H@-@_!`#?A`&`($4$ +M`+"PL(`D100`L+"P@$!%!`"PL+"`2$4$`+"PL(!,100`L`V$@#Q&!`"PKPB` +M'$X$`+"PK(!H3P0`L+"L@!A2!`"PL*R`"%0$`+`-A(!\500`L`V$@/Q6!`"P +MKP*`'%@$`+"PL(`H6`0`L+"P@#18!`"PL+"`2%@$`+"PL(!@6`0`L+"P@'18 +M!`"PL+"`A%@$`+"PL("(6`0`L+"P@(Q8!`"PL+"`D%@$`+"PL("46`0`L+"P +M@+!8!`"PL+"`S%@$`+"PJ(#86`0`L+"H@.18!`"PL+"`]%@$`+"PL(`$600` +ML+"P@"!9!`"PL+"`3%D$`+"PL(!L600`L+"P@'19!`"PL+"`?%D$`+"PL("4 +M600`L+"P@*Q9!`"PL+"`Q%D$`+"PL(#<600`L+"P@/A9!`"PL+"`%%H$`+"P +ML(`P6@0`L+"P@$Q:!`"PL*R`U%H$`+"PJ(#L6@0`L+"H@`1;!`"PL*J`-%L$ +M`+"PJ(!D6P0`L+"H@'A;!`"PK@&`:%P$`+"L`8#L7`0`L*H!@&Q=!`"PL*B` +MN%T$`+"PJ(`$7@0`L+"H@%!>!`"PL*B`<%X$`+"PJ(!\7@0`L+"H@(A>!`"P +ML*J`L%X$`+"PJ(#<7@0`L+"H@.A>!`"PL*B`,%\$`+"PJ(!@7P0`L+"H@)!? +M!`"PL*B`K%\$`+"PJ(#`7P0`L+"H@,Q?!`"PL*B`X%\$`+"PJ(#T7P0`L+"H +M@`!@!`"PL*J`Y&`$`+"PJ(#P8`0`L+"H@`AA!`"PL*B`&&$$`+"PJH!(800` +ML+"L@*1A!`"PL*B`L&$$`+"PJ(#8800`L+"H@.1A!`"PL*J`%&($`+"PK("$ +M8@0`L+"P@/1B!`"PL*B`1&,$`+"PJ("88P0`L+"J@%1D!`"PL*B`&&4$`+"P +MJH!<900`L+"J@&!F!`"PL*B`P&8$`+"PJH"T9P0`L+"J@*AH!`"PL*B`W&@$ +M`+"PJ(`@:00`L+"J@/AK!`"PL*B`1&P$`+"PJ(!X;`0`L+"L@%AO!`"PL*B` +M"'$$`+"PJ(`D<00`L+"H@$!Q!`"PL*B`>'$$`+"PJ("$<00`L+"H@`AR!`"P +ML*J`:',$`+"PK("D=`0`L+"H@,QT!`"PL*B`)'4$`+"PJ(`P=00`L+"J@-AU +M!`"PL*B`/'8$`+"PJH!$=P0`L+"J@+!X!`"PL*B`X'@$`+"PJ(#L>`0`L+"N +M@%![!`"PL*B`B'L$`+"PK(#`&+L$`+"PKH#(O@0`L+"N@`S`!`"PL*J`(,$$`+"O!(`XQ00` +ML+"H@%#%!`"PK`&`^,8$`+"J!X!,R`0`L*L"@(#)!`"O"+&`P,H$`+"PJH`T +MRP0`KT2R@,C6!`"PKP:`--@$`+"PJ(",V`0`L*L$@"#9!`"PJ02`>-D$`+"I +M!(#0V00`L*D$@!#:!`"O"+&`[-H$`+"PJ(`8VP0`L*\$@-3J!`"PL*B`K.L$ +M`+"L`8!,[00`7X0*@`3O!`"O/Q*`W/$$`+"O$H!4]@0`L+"N@(#W!`"PL*J` +M(/@$`+"PL(`X^`0`L+"P@%CX!`"PL+"`:/@$`+"PL(!L^`0`L*\"@.CY!``] +MA`&`_/H$`+"PJ("`^P0`L+"H@-C[!`"PL*B`_/L$`+"PK(!(_`0`L+"L@,#\ +M!`"PL*J`'/T$`+"I!("0_00`L*D$@`3^!`"PL*B`:/X$`+"PJ("0_@0`L+"H +M@`3_!`"PL*B`$/\$`+"PJ(`<_P0`L+"H@"C_!`"PKP*`,``%`+"N`X`\`04` +ML+"H@&P!!0"PL*B`P`$%`+"PJ(```@4`L+"H@"@"!0"PL*B`-`(%`+"PJ(!` +M`@4`L+"P@$@"!0"PL+"`7`(%`+"PL(!@`@4`L+"P@&0"!0"PL*B`C`(%`+"P +MJ("8`@4`L+"J@.P"!0"PL*Z`>`0%`+"J#8#````.`5``!\````]!4``(`````(%@``A````!P6``"(```` +M,!8``(P```!$%@``(@```#(4```F````1A0``"H```!:%```+@```&X4``"X +M````.!,``+P```!,$P``P````&`3``#$````=!,``-````"P$P``U````,03 +M``#8````V!,``*JJ`P``````@3<``(#S``"JJ@,``/@`````^``3````I)X" +M`!,```!T7@(`$P```*0.`@`3````T,X!`!,```!`GP$`$P```'!.`0`3```` +MH`8!`!,```!PQ@``$P```*""```3````<$(``!,```!``@``*Z1>`"ND7@`K +MI%X`3Z0``$^D7@`<0UX`*Z1>`"ND7@`KI%X`*Z->`"ND7@`B0UX`(J1>`$^D +M``!/I```(J->`#"F``!/I```(D->`")#7@`B0UX`3Z1>`$^D```KI%X`*Z1> +M`"ND7@`KI%X`*Z1>`#"F```<0UX````````````````````````````````` +M```````````````````````````````````````````````````````````` +M````_@&`?^(!@'C'`````!P4````````( +M!0``*P````D%``"D````"@4``%X````+!0````````P%``!/````#04``*0` +M```.!0````````\%````````$@4``!P````4!0``"@```!8%```*````)04` +M`$\```!0!0``$````%$%```0````604```(```!=!0``_P````4&```P```` +M"`8```X````)!@``*@```"`&``#_````(08``/\````B!@``_P```",&``#_ +M````)`8``/\````E!@``_P```"8&``#_````)P8``/\```!2!@``(````#P& +M```*````/08```X````^!@``"@```#\&```.````0`8``$````!N!@``!0`` +M```'```A`````0<``$,````"!P``90````,'``"'````"`<``"$````)!P`` +M0P````H'``!E````"P<``(<````P#```2JSI:3P,```8EY<*``@`````!(`$ +M"````P````@(````_```#`@```H````0"```,1,`$!0(```0/0P"&`@``(4# +M(`(<"````````"`(`````0`!)`@```0".0`H"````````"P(````````,`@` +M```````T"````````#@(````````/`@```````!`"``````!`$0(```````` +M2`@```````!,"````````%`(````````5`@```````!8"```J1&:5EP(```4 +M```!8`@``!`!]F9D"```008?!F@(````````;`@````G)R=P"```8`<`!W0( +M````0``E>`@```@(``!\"````````(`(```<#`"PA`@```$```"("``````` +M`(P(``#``,#,D`@````(``"4"```_O___Y@(```0(#!`G`@``%!@<```"0`` +M``````0)```C````"`D````````,"0``$1$2@1`)```"````%`D````!```` +M"@``R$?0``0*```,`/^`"`H```"#@XP,"@``#Q)_+A`*``!XNP"5%`H``"C0 +M%!$8"@``%Q&(`!P*````#Q2)(`H`````&QHD"@``%Q,."2@*```$`@``+`H` +M````TP!P"@```+\?$'0*```'````>`H````)``!\"@``!@9;(H`*``"Q=8`A +M+`L``````(``#```0!T'2`0,```15J`#"`P``.0````,#```;&QL;!`,```` +M`(`(%`P````!`$`8#`````"`"!P,`````0!`(`P````````D#````````"@, +M````````+`P````````P#```1ZSI:30,``"O4I9&.`P``)19>4D\#```')>7 +M"D`,```_0'P?1`P``+<``0!(#```!P$"[$P,``!_`W\`4`P``"`T56E4#``` +ME`"\0U@,``!I,0$`7`P``)($)0!@#````````&0,``"+A!)Q:`P``/\+P$=L +M#```-@```'`,```-`'\L=`P``-L0!@)X#```'P```'P,```2%KD`@`P````! +M`$"$#`````#V((@,`````0!`C`P`````(""0#```(14)`)0,````````F`P` +M`"`8$@"<#```?W\``*`,````````I`P``*```P"H#````````*P,```````` +ML`P```````"T#````````+@,````````O`P``````"C`#````````,0,```` +M````R`P```````#,#````````-`,````````U`P```````#8#```)R2R9-P, +M```R:78`X`P``"(B(@#D#````````.@,```"0V0W[`P```S4ER\`#0``0`<` +M``0-```!!`(`"`T``'^0```,#0```0(!(!`-```S,V.@%`T``$.\,S,8#0`` +M;UN/>BP-``!UF9?,,`T````````T#0```(!@@#@-````````/`T``%-S$@!` +M#0```````$0-````````2`T```````!,#0```````%`-```*%#=D5`T````` +M``!8#0``@@(``%P-``!D(`,P8`T``&C>4T9D#0``/(I1!&@-```!(0``;`T` +M`!8<("IP#0``+C82&'0-```@(BPR>`T``"0\#@``#@``+2TM+00.```M+2TM +M"`X``"TGD`,0#@``+2TM+10.```M+2TM&`X``"TM+2T<#@``+2TM+2@.```` +M````,`X``!_<`!`T#@``'XP`$#@.```"`10"/`X``,($%FA`#@```'P``40. +M````2``!2`X``````/M,#@``T2@``%`.```?W``05`X``!^,`!!8#@```@$4 +M`EP.```%#18H8`X```@```!H#@``I"4;`&P.```4`,``<`X``!0`P`!T#@`` +M%````7@.```4```!?`X``!0```&`#@``%````80.```4`,``B`X``!0```&, +M#@``%`#``-`.```4`,``U`X``!0`P`#8#@``%`#``-P.```4````X`X``!0` +M``#L#@``%`#``4P/``````````\````#``!X#````0``^W@,```!``'[>`P` +M``$``OMX#````0`#^W@,```!``3[>`P```$`!?MX#````0`&^G@,```!``?Y +M>`P```$`"/AX#````0`)]W@,```!``KV>`P```$`"_5X#````0`,]'@,```! +M``WS>`P```$`#O)X#````0`/\7@,```!`!#P>`P```$`$>]X#````0`2[G@, +M```!`!/M>`P```$`%.QX#````0`5ZW@,```!`!;J>`P```$`%^EX#````0`8 +MZ'@,```!`!GG>`P```$`&N9X#````0`;Y7@,```!`!SD>`P```$`'>-X#``` +M`0`>XG@,```!`!_A>`P```$`((IX#````0`AB7@,```!`"*(>`P```$`(X=X +M#````0`DAG@,```!`"6%>`P```$`)H1X#````0`G@W@,```!`"B">`P```$` +M*6MX#````0`J:G@,```!`"MI>`P```$`+&AX#````0`M9W@,```!`"YF>`P` +M``$`+V5X#````0`P9'@,```!`#%C>`P```$`,F)X#````0`S87@,```!`#1& +M>`P```$`-45X#````0`V1'@,```!`#=#>`P```$`.$)X#````0`Y07@,```! +M`#I`>`P```$`.T!X#````0`\0'@,```!`#U`>`P```$`/D!X#````0`_0'@, +M```!`$#[>`P```$`0?MX#````0!"^W@,```!`$/[>`P```$`1/MX#````0!% +M^W@,```!`$;[>`P```$`1_MX#````0!(^W@,```!`$GZ>`P```$`2OEX#``` +M`0!+^'@,```!`$SW>`P```$`3?9X#````0!.]7@,```!`$_T>`P```$`4/-X +M#````0!1\G@,```!`%+Q>`P```$`4_!X#````0!4[W@,```!`%7N>`P```$` +M5NUX#````0!7['@,```!`%CK>`P```$`6>IX#````0!:Z7@,```!`%OH>`P` +M``$`7.=X#````0!=YG@,```!`%[E>`P```$`7^1X#````0!@XW@,```!`&'B +M>`P```$`8L-X#````0!CPG@,```!`&3!>`P```$`98MX#````0!FBG@,```! +M`&>)>`P```$`:(AX#````0!IAW@,```!`&J&>`P```$`:X5X#````0!LA'@, +M```!`&UG>`P```$`;F9X#````0!O97@,```!`'!D>`P```$`<6-X#````0!R +M8G@,```!`'-A>`P```$`=&!X#````0!U1G@,```!`'9%>`P```$`=T1X#``` +M`0!X0W@,```!`'E">`P```$`>D%X#````0![0'@,```!`'Q`>`P```$`?4!X +M#````0!^0'@,```!`']``````````P`(`````$`(`!@````'!```&0```!(` +M```>````"0`(`!\```"`"```+P```&"@`0`_`````````$(```#`8```5P`` +M````#0!8````@.$+`&<```!2%0``@P````````"P````_/@/`+$`````1`4` +ML@```!G,#`"T`````S`$`+8````^E00`MP```!C'`0"X````_V```+D````! +M``@`N@``````!`"[``````0``+\```````P`P@`````D``##````"0```,0` +M``"1#`0`Q0```)F9"0#&````HP```,<````@B`@`R`````9L!P#)```````` +M`,H```````@`WP```(`!``#O````H`$``%$```!]L@8`'P0/_\VK``!2```` +MW>0'`,W-S````````````!X``````````````````````````0```/05?``````` +M`````!X``````````````````````````0````@6@````````````!X````` +M`````````````````````0```!P6A````````````!X````````````````` +M`````````0```#`6B````````````!X``````````````````````````0`` +M`$06C````````````!X``````````````````````````0```'$6E0`````` +M`````!X``````````````````````````0```(46F0```````````!X````` +M`````````````````````0```)D6G0```````````!X````````````````` +M`````````0```*T6H0```````````!X``````````````````````````0`` +M`,$6I0```````````!X``````````````````````````0```"`7N``````` +M`````!X``````````````````````````0```#07O````````````!X````` +M`````````````````````0```$@7P````````````!X````````````````` +M`````````0```%P7Q````````````!X``````````````````````````0`` +M`'`7R````````````!X``````````````````````````0```(07S``````` +M`````!X``````````````````````````0```)@7T````````````!X````` +M`````````````````````0```*P7U````````````!X````````````````` +M`````````0```,`7V````````````!X`````````````````````````;#X` +M`'0^``!\/@``B#X``)@^``"@/@``K#X``+P^``#,/@``W#X``.P^````/P`` +M$#\``!P_```L/P``/#\``$@_``!0/P``6#\``&`_``!L/P``>#\``(0_``"8 +M/P``H#\`````````1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N +M,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H +M1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N +M,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H +M1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N +M,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H +M1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N +M,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H +M1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N +M,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H +M1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N +M,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H +M1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N +M,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H +M1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N +M,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H +M1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N +M,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H +M1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N +M,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H +M1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N +M,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H +M1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N +M,P``1T-#.B`H1TY5*2`T+C0N,P!!*@```&%E86)I``$@````!36UT86(`+G-T&ET7VUO9'5L90`N'1A8@`N&ED>``N0P` +MB`(``!RL#@",`@``'/\+`,@"```<*0L`W`(``!RW#`#L`@``'+`,`/@"```< +MI`L```,``!S_"P`H`P``'$\*`$P#```0P`*`4``"NM#0`L!0``+*T-`#P%```<>0P`1`4``!QG +M"P!0!0``'"H.`(0%```"`0``B`4```(!``",!0```@$``)`%```"`0``E`4` +M``(!``"8!0```@$``*0%```<30T`K`4``!Q-#0#L!0``'$T-``P&```<7PP` +M'`8``!Q-#0`D!@``'$T-`#@&```<+`L`[`8``!PY"@#X!@``'$T-``0'```< +M30T`A`<```(!``"(!P```@$``(P'```"`0``D`<```(!``"4!P```@$``)@' +M```"`0``G`<```(!``"@!P```@$``*0'```"`0``J`<```(!``"L!P```@$` +M`+`'```"`0``P`<``!SI"@#4!P``'`0,`.0'```#`!X"P``'*`-`(0+```<9PL`D`L``!P3#@"<"P``'.\.`-@+ +M```PT`^`P``!PJ#0`0#0`` +M'&4,`"P-```<90P`1`T``!P^"@!H#0``''L-`)0-```<*@T`K`T``!QE#`#( +M#0``'&4,`.`-````X``!QE +M#`"0#@``'#X*`+`.```<>PT`W`X``!PJ#0`T#P``'&4,`%`/```<90P`:`\` +M`!P^"@"(#P``''L-`+0/```<*@T`R`\``!QA#0#H#P``'&4,``00```<90P` +M'!```!P^"@`\$```''L-`&`0```<*@T`A!```!QE#`"@$```'&4,`+@0```< +M/@H`V!```!Q[#0`$$0``'"H-`!`1```PT`.!(``!PJ#0!D$@``'&4,`(02```<90P`F!(``!P^"@"H$@`` +M''L-`-@2```<*@T`[!(``!S_"@``$P``'#X*`"@3```<90P`1!,``!QE#`!< +M$P``'#X*`(`3```<>PT`K!,``!PJ#0#,$P``'&4,`.@3```<90P``!0``!P^ +M"@`8%```'(`*`"`4```<>PT`4!0``!PJ#0!L%```'&4,`(@4```<90P`I!0` +M`!P^"@"T%```'&4,`,@4```PT` +MX!D``!PJ#0`<&@``'&4,`&@:```PT`"!P``!PJ#0`L'```'&4,`#P<```<>PT`9!P``!PJ#0"4'```'&4, +M`*0<```<>PT`!!T``!PJ#0`D'0``'&4,`$`=```<90P`7!T``!P^"@!L'0`` +M''L-`)P=```<*@T`O!T``!QE#`#8'0``'&4,`/0=``````<90P`=!X``!QE#`"0'@``'#X*`*`>```<>PT`T!X``!PJ +M#0#P'@``'&4,``P?```<90P`*!\``!P^"@`X'P``''L-`'`?```<*@T`D!\` +M`!QE#`"L'P``'&4,`,@?```PT`H"```!R`"@"P(```'"H-`,P@```< +M90P`Z"```!QE#``$(0``'#X*`!0A```<>PT`3"$``!R`"@!<(0``'"H-`(`A +M```<10L`D"$``!S,#`"8(0``'&4,`+`A```<90P`S"$``!P^"@#@(0``'(0. +M`.@A```<>PT`)"(``!RI"@!<(@``'(`*`*0B```<*@T`M"(``!Q?#`"\(@`` +M*ZT-`,`B```LK0T`U"(``!QY#``L(P``'&4,`$@C```<90P`8",``!P^"@!T +M(P``''L-`*0C```<*@T`P",``!Q_"@#((P``'&4-`-`C```<90T`Y",``!P^ +M"@#X(P``'#X*``0D```"@``!P-"@"<*```'`T*`*@H```<#0H`M"@``!P-"@#`*```'`T*`,PH +M```<#0H`Z"@``!P-"@!4*0``'%L.`'@I```<3@H`E"D``!Q."@"H*0``'$X* +M`,0I```<3@H`V"D``!Q."@#H*0``'$X*`/0I```<2`P`6"H``"MT``!<*@`` +M+'0``&PL```K=```<"P``"QT``!0+P``*W0``%0O```L=```(#````("```$ +M-P``'"D+`)0X```<*0L`I#H``!RI"@"T.@``'*D*`,0Z```$X``!R;#0"03@``'/L)`/Q.```%4``!R`"@"050``'(`*`*A5```<@`H`P%4``!R`"@#X50``'"<-`!16```< +M*0L`-%8``!RI"@!(5@``'(`*`'A6```<@`H`B%8``!R`"@"<5@``'(`*`*Q6 +M```<@`H`Q%8``!Q4#``45P``'-T+`%Q7```<_PL`A%<``!R_"@"85P``'(P+ +M`+Q7```<_PL`Z%<``!PS"@#P5P``')P+`/Q7``````<@`H`D%X``!PU#0"X7@`` +M'(P+`-A>```KT```W%X``"S0```@8```'"H,`#1@```<1PH`1&```!PJ#`#L +M8```''X-`"QB```KT```,&(``"S0``!L8@``'(`*`(AB```K:@X`C&(``"QJ +M#@"L8@``'+8.`-!B```<@`H`Y&(``!R`"@"L8P``'(`*`.!C```<@`H`%&0` +M`!R`"@!(9```'*D*`.!F```0``'(`*`)!Y```<_`P` +MH'D``!R`"@#P>0``'"D+`$1Z```<#PH`['H``!Q^#0`X>P``''X-`-A[```K +M&P$`W'L``"P;`0`0P`3)(``!RY"P!< +MD@``'#X+`(B2````P` +MF)0``"NM#0"0P`Q)0``"NM#0#(E```+*T-`-B4```< +M>0P``)4``!R,"P`LE0``'"D+`#25```<_PL`6)4``!P\"@!HE0``'(P+`'R5 +M```<"@L`A)4``!SK#0",E0``'/\+`+"5```)D``!R,"P",F0``'%\,`-R9```<*0L`))H` +M`!SB#``TF@``'/0,`#B:```<_PL`E)H``!RR#`"0P`8)T``!RI"@!P +MG0``'(`*`'B=```<*0T`@)T``!PE#`"0G0``'!@*`*R=```<"PH`N)T``"NM +M#0"\G0``+*T-`-2=```<>0P`])T``!RP#``HG@``'+\*`$R>`````````<)0L` +MS)X``!Q?#``0GP``'/\+`$B?```#0!,H@``'%\,`+"B````H`&+<``!R`"@!`MP``'(`*`,"W```PT`J,```!PJ#0#@ +MP```'%(*`/C````<*0L`.,$``!R"#0!4P0``'%(*`'C!```<@@T`\,$``!R" +M#0`LP@``'*P.`#C"```PT`N,8``!SK"0#,Q@``'(`*`-S&```<@`H`[,8``!PJ +M#0`$QP``'&4,`!S'```<90P`,,<``!P^"@`\QP``''L-`'C'```-<``!SZ"@",UP``'/H*`*#7 +M```<'0P`L-<``!P=#`#,UP``'/H-`.C7```<.`H`#-@``!P<#@`"@!8VP``'+X+`'S;``````<@`H`U-X``!P""P", +MWP``'*P.`)3?```<(@P`I-\```(-``#`WP``'%<*`-3?```<2@T`".```!RI +M"@#,X```'(`*`.#@```<@`H`[.```!P0"@#\X```'(`*`$CA```<-@P`:.$` +M`!Q7"@!\X0``'$H-`)3A```0P``/,``!RL#@`X +M\P``'/H-`$CS```<*0H`3/,``"NM#0!0\P``+*T-`&#S```<>0P`N/,``!P" +M"P`0]```*ZT-`!3T```LK0T`)/0``!QY#`!4]```''X-`'#T```<@`H`B/0` +M`!PI"@",]```*ZT-`)#T```LK0T`I/0``!QY#`#(]```'#4*`"#U```<5PH` +M-/4``!Q*#0!$]0``'*D*`'SU```<$`H`C/4``!R`"@"4]0``'!`*`*3U```< +M@`H`O/4``!R`"@#,]0``'(`*`-SU```<@`H`3/8``!RT"@!@]@``'`T.`(SV +M````$!`!Q]#0"T`0$`''X-`-@!`0`0P`#!D!`"NM#0`0&0$`+*T-`"09`0`<>0P` +MA!D!`!SF#`"<&0$`'.8,`,P9`0`<+PT`]!D!`!SE#`#\&0$`'"\+`!`:`0`< +MN@X`&!H!`!S(#`#8&@$`'(`*``0;`0`<+PL`(!L!`!RZ#@`L&P$`'+H.`#`; +M`0`KK0T`-!L!`"RM#0!(&P$`''D,`&0;`0`<.`X`=!L!`!Q^"@"0&P$`''0+ +M`*@;`0`<=`L`X!L!`!PO#0`,'`$`'`4+`!P<`0`"`P``9!P!`!Q"#0!P'`$` +M'%<*`(0<`0`<2@T`E!P!`!RI"@"X'`$`'(`*`,P<`0`<@`H`W!P!`!R`"@`X +M'0$`'$@-`$P=`0`<2`T`7!T!`!Q(#0!P'0$`'$@-`(0=`0`<2`T`E!X!`!RT +M"@"H'@$`'#8,`/0>`0`<0@T`!!\!`!Q7"@`8'P$`'$H-`"@?`0`#`!`!R`"@",,`$`'(`*`)PP`0`<@`H`]#`!`!Q(#0`$,0$`'$@-`!0Q`0`< +M2`T`)#$!`!Q(#0`T,0$`'$@-`%@Q`0`0P`=#P!`!S& +M#`"0/`$`'+\+`.@\`0`<<0T`_#P!`!R`"@`L/0$`'$P-`$P]`0`<)0H`<#T! +M`!R_"P"0/0$`''$-`!P^`0`<`0P`-#X!`!Q`#0!,/@$`'(T+`&`^`0`<@`H` +MH#X!`"NM#0"D/@$`+*T-`+@^`0`<>0P`T#X!`!RL#@#T/@$`'`H*`/@^`0`K +MK0T`_#X!`"RM#0`,/P$`''D,`"0_`0`"`P``*#\!``*M#0!,/P$`'`(+`(`_ +M`0`<*0L`U#\!`!R`"@#D/P$`'$P+``1``0`&,!``(!``!\8P$``@$``(!C`0`"`0``A&,!``(!``"(8P$``@$` +M`(QC`0`"`0``D&,!``(!``"48P$``@$``)AC`0`"`0``G&,!``(!``"@8P$` +M`@$``*1C`0`"`0``J&,!``(!``"L8P$``@$``+!C`0`"`0``M&,!``(!``"X +M8P$``@$``+QC`0`"`0``P&,!``(!``#$8P$``@$``,AC`0`"`0``S&,!``(! +M``!H9`$`'%@-`+1D`0`<6`T`N&4!`!R,#0#(90$`'%,-`!QF`0`0P`Y'`$`''T,`&1X`0`<$PX` +ME'@!`!P,#@#4>`$`'(H+`.QX`0`<\0X`D'D!`!RC"P"<>0$`*V,"`*!Y`0`L +M8P(`N'D!`"MC`@"\>0$`+&,"`.1Y`0`K8P(`Z'D!`"QC`@#\>0$`*V,"``!Z +M`0`L8P(`.'H!`"MC`@`\>@$`+&,"`%1Z`0`K8P(`6'H!`"QC`@"`>@$`*V," +M`(1Z`0`L8P(`F'H!`"MC`@"<>@$`+&,"`'!]`0`KK0T`='T!`"RM#0"D?0$` +M''D,`/!]`0`#0`T?@$`'/\+`&Q^`0`($!`!P""P"4@0$`*W$"`)B!`0`L<0(` +MH($!`!P""P"P@0$`*W$"`+2!`0`L<0(`O($!`!P""P#4@0$`'`(+`.R!`0`< +MZPT``((!`!PI"P`X@@$`'(`*`$R"`0`<@`H`8((!`!R`"@!P@@$`'(`*`("" +M`0`<@`H`D((!`!R`"@"<@@$`'"D+``"#`0`<`@L`&(,!`!P""P`T@P$`*W$" +M`#B#`0`L<0(`0(,!`!P""P!0@P$`*W$"`%2#`0`L<0(`7(,!`!P""P!T@P$` +M'`(+`*"#`0`<`@L`Z(,!`!P""P`@A`$`'(`*`#2$`0`<@`H`1(0!`!R`"@!4 +MA`$`'(`*`&2$`0`<@`H`?(0!`!SK#0"0A`$`'"D+`+B$`0`<_PL`V(0!`!R! +M#`!`A0$`'(P+`%"%`0`<9@L`C(4!`!P""P"XA0$`'"D+`'R&`0`<_PL`I(8! +M`!R^"P`,AP$`'#D-`$2'`0`<^@H`G()0!`"QN`@"LE`$`'`(+`-R4`0`<`@L`\)0!`!Q9#`#\ +ME`$`')8,``B5`0`<@`H`%)4!`!R6#``@E0$`'(`*`$25`0`0P`Q)0P`,)D!`!R,"P!4F0$` +M'(P+`%R9`0``0`<`PH`1)X!`!PI"P!TG@$`'!L*`(2> +M`0`<]`D`Q)\!`!RT"P#8GP$`'-$.`!"@`0`"P#$H@$`'.X-`-"B`0`KK0T` +MU*(!`"RM#0#DH@$`''D,``"C`0`PT`P*D!`!Q[#0#(J0$`'!D,`-BI`0`PT`1*H!`!S_"P!DJ@$`'($,`(BJ`0`*L!`!R` +M"@"0JP$`',<+`-"K`0`<&0P`W*L!`!Q'#0`TK`$`'+<,`%"L`0`"`@``9*P! +M`!Q#"P"(K`$`'!D,`)"L`0`PT``*T!`!Q[#0`,K0$`'#T*`!2M`0`< +M/0H`T*X!`!S_"P#0KP$`'#D-`!"P`0`<^@H`'+`!`!R^"P!`L`$`'(P+`%BP +M`0`<_PL`;+$!`!R,"P"4L0$`'#D-`)BQ`0`<_PL`^+$!`!R^"P`#0"0 +MM`$`'/H*`+"T`0`#0`@OP$`')X-`%"_ +M`0`"`P``6+\!`!QR#@!4P`$`'/\+`+3``0`PT`V-L!`!P9#`#XVP$`'*D*``#<`0`PT`>-T!`!S*"@"0W0$`')X-`+#=`0`<&0P`N-T!`!Q#"P#TW0$`''L-`!#> +M`0`#0!`W@$`'+P+`$S>`0`<[0X`8-X!`!Q_"P`.!`"`!SR"@"$$`(` +M'/\+`*P0`@``@`< +M\@H`0!\"`!P`#0!8'P(`'/(*`'@?`@`<``T``"`"`!SR"@`\(`(`'``-`%0@ +M`@`<.PH`>"`"`!QC"@"P(`(`'/(*`-@@`@`<\PP`Z"`"`!P`#0`$(0(`'/(* +M`"@A`@`<5`T`0"$"`!SR"@!0(0(`'/(*`*0A`@`<\PP`5"("`!P`#0"D(@(` +M'``-`-0B`@`K/@,`V"("`"P^`P#<(@(`*S\#`.`B`@`L/P,`["("`!P`#0`$ +M(P(`'/(*`#`C`@`<``T`I","`!P`#0#`(P(`'/(*`/0C`@`<5`T`#"0"`!SR +M"@`<)`(`'/(*`%0D`@`K/0,`6"0"`"P]`P"$)`(`*ST#`(@D`@`L/0,`N"0" +M`!P`#0``)0(`'/,,`)@E`@`<\@H`U"4"`!SR"@`0)@(`'/(*`$PF`@`<\@H` +MB"8"`!SR"@#8)@(``@,``-PF`@`"`P``X"8"``("``#D)@(``@,``.@F`@`" +M`P``["8"``(#``#P)@(``@,``/0F`@`"`P``^"8"``(#``#\)@(``@,````G +M`@`"`P``!"<"``(#```()P(``@,```PG`@`"`P``$"<"``(#```4)P(``@(` +M`#@G`@`<80H`4"<"`!P)"P#,)P(`'%D,`.0G`@`<_PL`,"@"`!SS#`!,*`(` +M'/(*`&@H`@``P!P+@(`+%X#`(`N`@`<@@X`["X"`!R"#@`<+P(`'!D. +M`$`O`@`<@@X`4"\"`!S?"P!D+P(`'((.`)PO`@`<&0X`P"\"`!R"#@#@+P(` +M'"T+`/`O`@`<@@X`,#`"`!P9#@!4,`(`'((.`'0P`@`<+0L`A#`"`!R"#@#` +M,`(`'((.`-@P`@`<&0X`]#`"`!PM"P`$,0(`'((.`,@Q`@`K4`,`S#$"`"Q0 +M`P#<,0(`'*D*`/`Q`@`#D"`!R"#`"8.0(`',\-`,`Y`@`#X"``(!``!\/@(``@$``(`^`@`"`0``A#X"``(!``"( +M/@(``@$``(P^`@`"`0``D#X"``(!``"4/@(``@$``)@^`@`"`0``G#X"``(! +M``"@/@(``@$``*0^`@`"`0``J#X"``(!``"L/@(``@$``+`^`@`"`0``M#X" +M``(!``"X/@(``@$``+P^`@`"`0``P#X"``(!``#$/@(``@$``,@^`@`"`0`` +MS#X"``(!``#0/@(``@$``-0^`@`"`0``V#X"``(!``#%4"`!P9#@"(50(` +M'-\+`*A5`@``@`@H`B&`"`!S5#`"4 +M8`(`''H*`+1@`@`0H`G&L" +M`!QY"@#(;P(`'+$+`.1O`@`<&@T`\&\"`!SP#@`(<`(`'(4.`#!P`@`'$"`!P@"P"8<0(`'"`+`#QR`@``(`'`(*`&QX`@`<`@H`B'@"`!P@"P"0>`(`'/$-`*AX`@`< +M(`L`L'@"`!SQ#0"X>`(`'/$-`-AX`@`<(`L`X'@"`!SQ#0`(>0(`'"`+`!!Y +M`@`<\0T`&'D"`!SQ#0`H>0(`'`(*`$!Y`@`<`@H`<'D"`!P""@"8>0(`'`(* +M`!!Z`@`<(`L`>'H"`!SO"@#,>@(`'!@,`)![`@`"`0``E'L"``(!``"8>P(` +M`@$``)Q[`@`"`0``O'L"`!P*#@#(>P(`'-(+`/A[`@`<&`P``'P"`!Q5"@`4 +M?`(`'&(*`"!\`@`<50H`5'P"``("``!X?0(``@$``'Q]`@`"`0``@'T"``(! +M``"$?0(``@$``/Q_`@`K_P,``(`"`"S_`P`4@`(`*_\#`!B``@`L_P,`0(`" +M`"O_`P!$@`(`+/\#`%R``@`K_P,`8(`"`"S_`P"L@`(`'.H+``2!`@`<``L` +M+($"`"O_`P`P@0(`+/\#`(B!`@`K_P,`C($"`"S_`P"H@0(`*_\#`*R!`@`L +M_P,`R($"`"O_`P#,@0(`+/\#`.B!`@`<&`P`%(("`!PP"@"`@@(`'!@,`+"" +M`@`<&`P`R(("`"O_`P#,@@(`+/\#`/B"`@`<8@H`_(("`"O_`P``@P(`+/\# +M`!B#`@`K_P,`'(,"`"S_`P`T@P(`*_\#`#B#`@`L_P,`<(,"`!S<"P`$A`(` +M`@$```B$`@`"`0``#(0"``(!```0A`(``@$``"R$`@`<`@H`4(0"`!P""@!X +MA`(`'"`+`("$`@`<\0T`E(0"`!P@"P"(4"`!P@"P"@A0(`'"`+`'2'`@`<``H` +MV(<"`!P@"P#PAP(`'"`+``2(`@`<(`L`'(@"`!P@"P!`@`<#PT`<)X"`!P/#0"4 +MG@(`'((,`-">`@`*@"`"O8#0"`J`(`+-@-`(BH`@`K=0L`D*@"`"QU"P"8J`(`*]D.`*"H`@`L +MV0X`J*@"`"L"#@"PJ`(`+`(.`+BH`@`K'`T`P*@"`"P<#0#(J`(`*U8,`-"H +M`@`L5@P`V*@"`"M+#0#@J`(`+$L-`.BH`@`K100`\*@"`"Q%!```J0(`'!T. +M`/2I`@`"@`@L@(`'%H,`$"R`@`<2@L` +M5+("`!Q9"P!LL@(`'*P*`(2R`@`"P"XL@(`'*P*`,RR`@`< +M6@H`U+("`!S>"@#HL@(`'%H,`/BR`@`+,"``(!``!\LP(``@$``("S`@`"`0``A+,"``(!``"(LP(``@$` +M`(RS`@`"`0``D+,"``(!``"4LP(``@$``)BS`@`"`0``G+,"``(!``"@LP(` +M`@$``*2S`@`"`0``J+,"``(!``#`LP(`'"D+`'RT`@`<3`H`F+0"`!Q/"P"T +MM`(`'/X.`!2U`@`<``T`5+4"``(#``!\M0(`''H*`,RU`@`+8"``(!``!\M@(``@$``("V`@`"`0``A+8"``(!``"(M@(` +M`@$``(RV`@`"`0``D+8"``(!``"4M@(``@$``)BV`@`"`0``G+8"``(!``"@ +MM@(``@$``*2V`@`"`0``J+8"``(!``"LM@(``@$``+"V`@`"`0``M+8"``(! +M``"XM@(``@$``+RV`@`"`0``P+8"``(!``#$M@(``@$``,BV`@`"`0``S+8" +M``(!``#0M@(``@$``-2V`@`"`0``V+8"``(!``#,("`!S^"P"DP@(`'((,`+#"`@`<>@H`U,("`!S2 +M"P#DP@(`'`H.`/C"`@`P0`:-8"`"Q[!`"`U@(`'.X-`)C6 +M`@`K?`0`G-8"`"Q\!`"PU@(`*WX$`+C6`@`L?@0`%-<"`!PH#@!\UP(`',\- +M`(S7`@`<@@P`F-<"`!S/#0"LUP(`'((,`+C7`@`0P`(-D"`"NM#0`DV0(`+*T-`#39`@`<>0P`6-D" +M`!RL#@`0V@(``@$``!3:`@`"`0``&-H"``(!```-H"``(!``!\V@(``@$``(#: +M`@`"`0``A-H"``(!``#(V@(`'*P.`.3:`@``@`<>0P`(-X"`!RL +M#@`\W@(`'*P.`%C>`@``@`KK0T`O-X" +M`"RM#0#,W@(`''D,`-S>`@`KK0T`X-X"`"RM#0#LW@(`''D,``3?`@`0P`;-\"`!RL#@"(WP(`'*P.`*3?`@`< +MK`X`P-\"`!RL#@#0P`F.$"`!QY#`#,X0(` +M'*P.`/3A`@`0P`2.("`!RL#@!P +MX@(`'*P.`)SB`@`KK0T`H.("`"RM#0"PX@(`''D,`/CB`@`KK0T`_.("`"RM +M#0`,XP(`''D,`%3C`@`KK0T`6.,"`"RM#0!HXP(`''D,`*3C`@`<>0P`V.," +M`!RL#@``Y`(`'*P.`"CD`@`0P` +M9.0"``(!``!HY`(``@$``&SD`@`"`0``<.0"``(!``!TY`(``@$``'CD`@`" +M`0``?.0"``(!``"`Y`(``@$``(3D`@`"`0``B.0"``(!``",Y`(``@$``.CD +M`@`0P`<.<"`!RL#@"HYP(`*ZT-`*SG`@`LK0T`P.<"`!QY#`#4 +MYP(`*ZT-`-CG`@`LK0T`Z.<"`!QY#``(Z`(`'*P.`"SH`@`KK0T`,.@"`"RM +M#0!`Z`(`''D,`'SH`@`<>0P`A.@"``*M#0"TZ`(`'*P.`-SH`@`0P`).H"`!RL#@!,Z@(`'*P.`*3J`@`<>0P`S.H"`!QY#```ZP(`'*P. +M`#CK`@`<>0P`D.L"`!RL#@#HZP(`''D,`%3L`@`0P`+.X"`!RL#@!4 +M[@(`'*P.`'SN`@`0P`F.\"`!RL#@#D[P(`*ZT-`.CO`@`LK0T`^.\" +M`!QY#``@\`(`'*P.`$SP`@`KK0T`4/`"`"RM#0!@\`(`''D,`(#P`@`0P`"/$"`!RL#@!`\0(`*ZT-`$3Q`@`L +MK0T`5/$"`!QY#`"(\0(`'*P.`+#Q`@`0P`D/,"`!S/#0"@\P(`'((,`*SS`@``@#`!PA"@`8"0,`'&H,`"0)`P`< +M+@P`7`D#`!Q/"P"`"0,`'$P*`)P)`P`<_@X`T`H#`!P?#0#@"@,`',\+`"@+ +M`P`PP`5!(#`!RG#@!X$@,`'#X*`(02 +M`P`<40T`C!(#`!Q1#0"D$@,`*VT.`*@2`P`L;0X`L!(#`!Q[#`"\$@,`'!D, +M`,02`P`<90P`Y!(#`!RI"@`0$P,`''L-`!@3`P`"@!@'@,`')$.`(@>`P` +M"P"<)`,`'!8*`+`D`P`<``T`V"0#`!PX#0#D)`,`'`,*`$PE`P`<``P`5"4# +M`!R>"@`\)@,`'``-`$@F`P`<``T`5"8#`!P`#0!@)@,`'``-`&PF`P`<``T` +M>"8#`!P`#0"$)@,`'``-`)`F`P`<``T`G"8#`!P`#0"D)@,`'``-`+`F`P`" +M`P``M"8#``(#``"X)@,``@,``+PF`P`"`P``P"8#``(#``#$)@,``@,``,@F +M`P`"`P``S"8#``(#``#0)@,``@,``"`G`P`$0#`!P\"P",1`,`'#P+ +M`*1$`P`#`!X +M2@,`'-X,`)A*`P`#0"P2@,`'-X,`,Q*`P`#``\2P,`'#P+`%!+`P`%4#``(#``!\50,``@,``(!5`P`"`P``A%4#``("``"(50,``@,``(Q5`P`" +M`P``D%4#``(#``"450,``@,``)A5`P`"`P``G%4#``(#``"@50,``@,``*15 +M`P`"`P``J%4#``(#``"L50,``@,``-Q5`P`"`0``X%4#``(!``#D50,``@$` +M`.A5`P`"`0``#%8#`"MS!0`05@,`+',%`!16`P`K=`4`&%8#`"QT!0`<5@,` +M'``-`"16`P`K=04`*%8#`"QU!0`L5@,`*W8%`#!6`P`L=@4`/%8#`!P`#0!` +M5@,`*W<%`$16`P`L=P4`4%8#`!P`#0"X5@,`'``-`,Q6`P`<``T`X%8#`!P` +M#0#T5@,`'``-``A7`P`<``T`'%<#`!P`#0`P5P,`'``-`$!7`P`"`@``1%<# +M``(#``!(5P,``@,``$Q7`P`"`P``4%<#``(#``!45P,``@,``%A7`P`"`P`` +M7%<#``(#``",5P,`'#P+`*!7`P`%D#`!P\"P",60,`'#P+ +M`*!9`P``P`<``T`'%X#`!P`#0`L7@,`'``-`#Q>`P`<*`H`4%X#`!PH"@!T7@,` +M'#P+`(A>`P``P`"`P``G%X#``(#``"@ +M7@,``@,``*1>`P`"`P``J%X#``(#``"L7@,``@(``+!>`P`"`P``M%X#``(# +M``"X7@,``@,``+Q>`P`"`P``P%X#``(#```$7P,`'#P+`"1?`P`&$#`!P`#0"H80,`'``-`+QA`P`<``T`T&$#`!P`#0#D80,` +M'``-`/AA`P`<``T`#&(#`!P`#0`<8@,`'``-`"1B`P`"`P``*&(#``(#```L +M8@,``@,``#!B`P`"`P``-&(#``(#```X8@,``@,``#QB`P`"`P``0&(#``(" +M``!$8@,``@,``'QB`P`<``T`D&(#`!P`#0"D8@,`'``-`+AB`P`<``T`S&(# +M`!P`#0#@8@,`'``-`.QB`P`<``T`*&,#`!P`#0`\8P,`'``-`%!C`P`<``T` +M9&,#`!P`#0!X8P,`'``-`(QC`P`<``T`F&,#`!P`#0#88P,`'``-`.QC`P`< +M``T``&0#`!P`#0`49`,`'``-`"AD`P`<``T`/&0#`!P`#0!(9`,`'``-`(1D +M`P`<``T`F&0#`!P`#0"L9`,`'``-`,!D`P`<``T`U&0#`!P`#0#H9`,`'``- +M`/1D`P`<``T`%&<#`!P`#0`H9P,`'``-`#QG`P`<``T`4&<#`!P`#0!D9P,` +M'``-`'AG`P`<``T`B&<#`!P`#0"T9P,`'``-`,AG`P`<``T`W&<#`!P`#0#P +M9P,`'``-``1H`P`<``T`&&@#`!P`#0`H:`,`'``-`(1H`P`<``T`E&@#`!P` +M#0#(:`,`'``-`-QH`P`<``T`\&@#`!P`#0`$:0,`'``-`!AI`P`<``T`+&D# +M`!P`#0`X:0,`'``-`(!I`P`<``T`E&D#`!P`#0"H:0,`'``-`+QI`P`<``T` +MT&D#`!P`#0#D:0,`'``-`/!I`P`<``T`S&H#`!P`#0#@:@,`'``-`/1J`P`< +M``T`"&L#`!P`#0`<:P,`'``-`#!K`P`<``T`/&L#`!P`#0!T:P,`'``-`(AK +M`P`<``T`G&L#`!P`#0"P:P,`'``-`,1K`P`<``T`V&L#`!P`#0#D:P,`'``- +M`(AL`P`<``T`G&P#`!P`#0"P;`,`'``-`,1L`P`<``T`V&P#`!P`#0#L;`,` +M'``-`/AL`P`<``T`6&T#`!P`#0!L;0,`'``-`(!M`P`<``T`E&T#`!P`#0"H +M;0,`'``-`+QM`P`<``T`R&T#`!P`#0`,;@,`'``-`"!N`P`<``T`-&X#`!P` +M#0!(;@,`'``-`%QN`P`<``T`<&X#`!P`#0"$;@,`'``-`+!N`P`<``T`Q&X# +M`!P`#0#8;@,`'``-`.QN`P`<``T``&\#`!P`#0`4;P,`'``-`"1O`P`<``T` +M4&\#`!P`#0!D;P,`'``-`'AO`P`<``T`C&\#`!P`#0"@;P,`'``-`+1O`P`< +M``T`Q&\#`!P`#0#0;P,`'*4.`!QP`P`"`P``('`#``(#```D<`,``@,``"AP +M`P`"`P``+'`#``(#```P<`,``@,``#1P`P`"`P``.'`#``("```\<`,``@,` +M`$!P`P`"`P``1'`#``(#``!(<`,``@,``$QP`P`"`P``4'`#``(#``!4<`,` +M`@,``%AP`P`"`P``7'`#``(#``!@<`,``@,``&1P`P`"`P``:'`#``(#``!L +M<`,``@,``'!P`P`"`P``='`#``(#``"X<`,`'``-`,QP`P`<``T`X'`#`!P` +M#0#T<`,`'``-``AQ`P`<``T`''$#`!P`#0`H<0,`'``-`&1Q`P`<``T`>'$# +M`!P`#0",<0,`'``-`*!Q`P`<``T`M'$#`!P`#0#(<0,`'``-`-AQ`P`<``T` +M%'(#`!P`#0`H<@,`'``-`#QR`P`<``T`4'(#`!P`#0!D<@,`'``-`'AR`P`< +M``T`B'(#`!P`#0#$<@,`'``-`-AR`P`<``T`['(#`!P`#0```,`'``-`!AX`P`<``T`+'@#`!P`#0!` +M>`,`'``-`%1X`P`<``T`D'@#`!P`#0"D>`,`'``-`+AX`P`<``T`S'@#`!P` +M#0#@>`,`'``-`/1X`P`<``T`"'D#`!P`#0!$>0,`'``-`%AY`P`<``T`;'D# +M`!P`#0"`>0,`'``-`)1Y`P`<``T`J'D#`!P`#0"\>0,`'``-`/AY`P`<``T` +M#'H#`!P`#0`@>@,`'``-`#1Z`P`<``T`2'H#`!P`#0!<>@,`'``-`'!Z`P`< +M``T`K'H#`!P`#0#`>@,`'``-`-1Z`P`<``T`Z'H#`!P`#0#\>@,`'``-`!![ +M`P`<``T`)'L#`!P`#0!L>P,`'``-`(![`P`<``T`E'L#`!P`#0"H>P,`'``- +M`+Q[`P`<``T`T'L#`!P`#0#D>P,`'``-`.Q[`P`"`P``\'L#``(#``#T>P,` +M`@,``/A[`P`"`P``_'L#``(#````?`,``@,```1\`P`"`P``"'P#``("```, +M?`,``@,``!!\`P`"`P``%'P#``(#```8?`,``@,``!Q\`P`"`P``('P#``(# +M```D?`,``@,``"A\`P`"`P``+'P#``(#```P?`,``@,``'1\`P`<``T`B'P# +M`!P`#0"(<#``(#``!\AP,``@,``("'`P`"`P``A(<#``(# +M``"(AP,``@,``(R'`P`"`P``D(<#``(#``"4AP,``@,``*B(`P`KA@4`K(@# +M`"R&!0"\B`,`*X8%`,"(`P`LA@4`T(@#`!P*#@``B0,`'`H.`'R)`P`<``T` +MD(D#`!P`#0"DB0,`'``-`+B)`P`<``T`S(D#`!P`#0#@B0,`'``-`.R)`P`< +M``T`#(H#`!PU"P!(B@,`'``-`%R*`P`<``T`<(H#`!P`#0"$B@,`'``-`)B* +M`P`<``T`K(H#`!P`#0"XB@,`'``-`,"*`P`"`P``Q(H#``(#``#(B@,``@,` +M`,R*`P`"`P``T(H#``(#``#4B@,``@,``-B*`P`"`P``W(H#``("``#@B@,` +M`@,``#R+`P`<``T`4(L#`!P`#0!DBP,`'``-`'B+`P`<``T`C(L#`!P`#0"@ +MBP,`'``-`*R+`P`@L`R),#`!P,"P`)0#`!S/#0"@E`,``@(``+24`P`<*`H`R)0#`!PH"@#4E`,` +M'%8.`.24`P` +M"@`XH0,``@T``*"A`P`<``T`M*$#`!P`#0#(H0,`'``-`-RA`P`<``T`\*$# +M`!P`#0`$H@,`'``-`!2B`P`<``T`7*(#`!P`#0!PH@,`'``-`(2B`P`<``T` +MF*(#`!P`#0"LH@,`'``-`,"B`P`<``T`R*(#`"O3!0#,H@,`+-,%`-"B`P`K +MU`4`U*(#`"S4!0#DH@,`'``-`.RB`P`"`P``\*(#``(#``#TH@,``@,``/BB +M`P`"`P``_*(#``(#````HP,``@,```2C`P`"`P``"*,#``("```,HP,``@,` +M`"RC`P`KUP4`,*,#`"S7!0"THP,`'``-`,BC`P`<``T`W*,#`!P`#0#PHP,` +M'``-``2D`P`<``T`&*0#`!P`#0`LI`,`'``-`&"D`P`KV`4`9*0#`"S8!0!L +MI`,`*]D%`'"D`P`LV04`>*0#`"O:!0!\I`,`+-H%`.RD`P`<``T``*4#`!P` +M#0`4I0,`'``-`"BE`P`<``T`/*4#`!P`#0!0I0,`'``-`&RE`P`<``T`/*8# +M`!P`#0!0I@,`'``-`&2F`P`<``T`>*8#`!P`#0",I@,`'``-`*"F`P`<``T` +ML*8#`!P`#0#`IP,``@,``,2G`P`"`P``R*<#``(#``#,IP,``@,``-"G`P`" +M`P``U*<#``(#``#8IP,``@,``-RG`P`"`@``X*<#``(#```TJ`,`'``-`$BH +M`P`<``T`7*@#`!P`#0!PJ`,`'``-`(2H`P`<``T`F*@#`!P`#0"LJ`,`'``- +M`!RI`P`<``T`,*D#`!P`#0!$J0,`'``-`%BI`P`<``T`;*D#`!P`#0"`J0,` +M'``-`)2I`P`<``T`X*D#`!P`#0#TJ0,`'``-``BJ`P`<``T`'*H#`!P`#0`P +MJ@,`'``-`$2J`P`<``T`6*H#`!P`#0"\J@,``@,``,"J`P`"`P``Q*H#``(# +M``#(J@,``@,``,RJ`P`"`P``T*H#``(#``#4J@,``@,``-BJ`P`"`@``W*H# +M``(#``!`JP,`'``-`%2K`P`<``T`:*L#`!P`#0!\JP,`'``-`)"K`P`<``T` +MI*L#`!P`#0"PJP,`'``-`,"K`P`<>@L`U*L#`!QZ"P#HJP,`''H+`/RK`P`< +M>@L`!*P#``(#```(K`,``@,```RL`P`"`P``$*P#``(#```4K`,``@,``!BL +M`P`"`P``'*P#``(#```@K`,``@(``$RL`P`<\`P`:*P#`!QZ"P!\K`,`'&(* +M`)RL`P`<>@L`L*P#`!QB"@#,K`,`'$0,`-2L`P`<_`D`Y*P#`!QZ"P#\K`,` +M'&(*`"2M`P`<1`P`2*T#`!Q$#`!@L`2*X#`!Q$#`"+X#`!P\"P"$O@,``@,``(B^`P`" +M`P``C+X#``(#``"0O@,``@,``)2^`P`"`P``F+X#``(#``",T#`!P` +M#0"(S0,`'"@*`-3-`P`<``T`Z,T#`!P`#0#\S0,`'``-`!#.`P`<``T`),X# +M`!P`#0`XS@,`'``-`$C.`P`<``T`E,X#`!P\"P#-H# +M`!P`#0",V@,`'``-`*#:`P`<``T`M-H#`!P`#0#(V@,`'``-`-S:`P`<``T` +MZ-H#`!P`#0``VP,`'#P+`$C;`P`<``T`7-L#`!P`#0!PVP,`'``-`(3;`P`< +M``T`F-L#`!P`#0"LVP,`'``-`+C;`P`<``T`S-L#`!P\"P#@VP,`'#P+`"C< +M`P`<``T`/-P#`!P`#0!0W`,`'``-`&3<`P`<``T`>-P#`!P`#0",W`,`'``- +M`)S<`P`<``T`I-P#`!S\"0"TW`,`'"@*``#=`P`<``T`%-T#`!P`#0`HW0,` +M'``-`#S=`P`<``T`4-T#`!P`#0!DW0,`'``-`'3=`P`<``T`A-T#`!PH"@#0 +MW0,`'``-`.3=`P`<``T`^-T#`!P`#0`,W@,`'``-`"#>`P`<``T`--X#`!P` +M#0!$W@,`'``-`%3>`P`<*`H`H-X#`!P`#0"TW@,`'``-`,C>`P`<``T`W-X# +M`!P`#0#PW@,`'``-``3?`P`<``T`%-\#`!P`#0`DWP,`'"@*`'#?`P`<``T` +MA-\#`!P`#0"8WP,`'``-`*S?`P`<``T`P-\#`!P`#0#4WP,`'``-`.3?`P`< +M``T`&.`#``(#```@L`6.$#`!Q&#`!@X0,``@,``&3A`P`"`P``:.$#``(# +M``!LX0,``@,``'#A`P`"`P``=.$#``(#``!XX0,``@,``'SA`P`"`@``X.$# +M`!P`#0#TX0,`'``-``CB`P`<``T`'.(#`!P`#0`PX@,`'``-`$3B`P`<``T` +M4.(#`!P`#0!@X@,`'/`,`'SB`P``H$`!P`#0"L"@0`'``-`,0*!``@L`J!4$`!P`#0"\%00`'``-`-`5!``<``T`Y!4$ +M`!P`#0#X%00`'``-``P6!``<``T`(!8$`!P`#0`H%@0``@,``"P6!``"`P`` +M,!8$``(#```T%@0``@,``#@6!``"`P``/!8$``(#``!`%@0``@,``$06!``" +M`@``8!8$`!S9#`!T%@0`'/P)`(@6!``<_`D`G!8$`!Q-#@"P%@0`'$T.`,06 +M!``<30X`X!8$`!Q$#`#H%@0`'$T.`!`7!``<8@X`/!<$`!P`#0!0%P0`'``- +M`&07!``<``T`>!<$`!P`#0",%P0`'``-`*`7!``<``T`M!<$`!P`#0#`%P0` +M`@,``,07!``"`P``R!<$``(#``#,%P0``@,``-`7!``"`P``U!<$``(#``#8 +M%P0``@,``-P7!``"`@``_!<$`!QB#@`H&`0`'``-`#P8!``<``T`4!@$`!P` +M#0!D&`0`'``-`'@8!``<``T`C!@$`!P`#0"@&`0`'``-`*P8!``"`P``L!@$ +M``(#``"T&`0``@,``+@8!``"`P``O!@$``(#``#`&`0``@,``,08!``"`P`` +MR!@$``("``#$&00`*T(&`,@9!``L0@8`+!H$`"M"!@`P&@0`+$(&`'@:!``< +M``T`C!H$`!P`#0"@&@0`'``-`+0:!``<``T`R!H$`!P`#0#<&@0`'``-`.P: +M!``<``T`]!H$``(#``#X&@0``@,``/P:!``"`P```!L$``(#```$&P0``@,` +M``@;!``"`P``#!L$``(#```0&P0``@(``%P;!``<``T`!``<``T` +M-!X$`"M"!@`X'@0`+$(&`&`>!``K0@8`9!X$`"Q"!@"H'@0`'``-`+P>!``< +M``T`T!X$`!P`#0#D'@0`'``-`/@>!``<``T`#!\$`!P`#0`<'P0`'``-`"`? +M!``K0@8`)!\$`"Q"!@"X'P0`'``-`,P?!``<``T`X!\$`!P`#0#T'P0`'``- +M``@@!``<``T`'"`$`!P`#0!$(`0`'``-`$P@!``K0@8`4"`$`"Q"!@"L(`0` +M'``-`,`@!``<``T`U"`$`!P`#0#H(`0`'``-`/P@!``<``T`$"$$`!P`#0!$ +M(00`'``-`$@A!``K0@8`3"$$`"Q"!@!H(00`*T(&`&PA!``L0@8`O"$$`!P` +M#0#0(00`'``-`.0A!``<``T`^"$$`!P`#0`,(@0`'``-`"`B!``<``T`+"($ +M`!P`#0!P(@0`'``-`(0B!``<``T`F"($`!P`#0"L(@0`'``-`,`B!``<``T` +MU"($`!P`#0#@(@0`'``-`"PC!``<``T`0",$`!P`#0!4(P0`'``-`&@C!``< +M``T`?",$`!P`#0"0(P0`'``-`+`C!``<``T`P"0$`!P`#0#4)`0`'``-`.@D +M!``<``T`_"0$`!P`#0`0)00`'``-`"0E!``<``T`,"4$`!P`#0!L)00`'``- +M`(`E!``<``T`E"4$`!P`#0"H)00`'``-`+PE!``<``T`T"4$`!P`#0#D)00` +M'``-`"`F!``<``T`-"8$`!P`#0!()@0`'``-`%PF!``<``T`<"8$`!P`#0"$ +M)@0`'``-`)@F!``<``T`U"8$`!P`#0#H)@0`'``-`/PF!``<``T`$"<$`!P` +M#0`D)P0`'``-`#@G!``<``T`1"<$`!P`#0!,)P0`*T(&`%`G!``L0@8`I"<$ +M`!P`#0"X)P0`'``-`,PG!``<``T`X"<$`!P`#0#T)P0`'``-``@H!``<``T` +M%"@$`!P`#0!8*`0`'``-`&PH!``<``T`@"@$`!P`#0"4*`0`'``-`*@H!``< +M``T`O"@$`!P`#0#(*`0`'``-`!`I!``<``T`)"D$`!P`#0`X*00`'``-`$PI +M!``<``T`8"D$`!P`#0!T*00`'``-`(@I!``<``T``"H$`!P`#0`4*@0`'``- +M`"@J!``<``T`/"H$`!P`#0!0*@0`'``-`&0J!``<``T`<"H$`!P`#0`(*P0` +M`@,```PK!``"`P``$"L$``(#```4*P0``@,``!@K!``"`P``'"L$``(#```@ +M*P0``@,``"0K!``"`@``*"L$``(#```L*P0``@(``#`K!``"`P``-"L$``(# +M```X*P0``@,``#PK!``"`P``0"L$``(#``!$*P0``@(``$@K!``"`P``3"L$ +M``(#``!0*P0``@,``%0K!``"`P``6"L$``(#``!<*P0``@,``&`K!``"`P`` +M9"L$``(#``!H*P0``@,``&PK!``"`P``<"L$``(#``!T*P0``@,``'@K!``" +M`@``?"L$``(#``"`*P0``@,``(0K!``"`P``B"L$``(#``",*P0``@,``)`K +M!``"`P``E"L$``(#``"8*P0``@,``)PK!``"`@``J"L$`"M"!@"L*P0`+$(& +M`!`L!``<``T`)"P$`!P`#0`X+`0`'``-`$PL!``<``T`8"P$`!P`#0!T+`0` +M'``-`(0L!``<``T`P"P$`!P`#0#4+`0`'``-`.@L!``<``T`_"P$`!P`#0`0 +M+00`'``-`"0M!``<``T`."T$`!P`#0!T+00`'``-`(@M!``<``T`G"T$`!P` +M#0"P+00`'``-`,0M!``<``T`V"T$`!P`#0#D+00`'``-`/@M!``K2`8`_"T$ +M`"Q(!@`<+@0`*T@&`"`N!``L2`8`>"X$`!P`#0",+@0`'``-`*`N!``<``T` +MM"X$`!P`#0#(+@0`'``-`-PN!``<``T`Z"X$`!P`#0#L+@0`*T@&`/`N!``L +M2`8`!"\$`"M"!@`(+P0`+$(&`&@O!``<``T`?"\$`!P`#0"0+P0`'``-`*0O +M!``<``T`N"\$`!P`#0#,+P0`'``-`-@O!``<``T`+#`$`!P`#0!`,`0`'``- +M`%0P!``<``T`:#`$`!P`#0!\,`0`'``-`)`P!``<``T`I#`$`!P`#0#,,`0` +M`@,``-`P!``"`P``U#`$``(#``#8,`0``@,``-PP!``"`P``X#`$``(#``#D +M,`0``@,``.@P!``"`@``6#$$`!P`#0!L,00`'``-`(`Q!``<``T`E#$$`!P` +M#0"H,00`'``-`+PQ!``<``T`T#$$`!P`#0#<,00``@,``.`Q!``"`P``Y#$$ +M``(#``#H,00``@,``.PQ!``"`P``\#$$``(#``#T,00``@,``/@Q!``"`@`` +M:#($`!P`#0!\,@0`'``-`)`R!``<``T`I#($`!P`#0"X,@0`'``-`,PR!``< +M``T`X#($`!P`#0#L,@0``@,``/`R!``"`P``]#($``(#``#X,@0``@,``/PR +M!``"`P```#,$``(#```$,P0``@,```@S!``"`@``<#,$`!P`#0"$,P0`'``- +M`)@S!``<``T`K#,$`!P`#0#`,P0`'``-`-0S!``<``T`[#,$`!P`#0#\,P0` +M`@,````T!``"`P``!#0$``(#```(-`0``@,```PT!``"`P``$#0$``(#```4 +M-`0``@,``!@T!``"`@``7#0$`!P`#0!P-`0`'``-`(0T!``<``T`F#0$`!P` +M#0"L-`0`'``-`,`T!``<``T`S#0$`!P`#0#@-`0`'&`.`/PT!``"`P```#4$ +M``(#```$-00``@,```@U!``"`P``##4$``(#```0-00``@,``!0U!``"`P`` +M$``("``!<-00`'``-`'`U!``<``T`A#4$`!P`#0"8-00`'``-`*PU!``< +M``T`P#4$`!P`#0#,-00`'``-`.0U!``"`P``Z#4$``(#``#L-00``@,``/`U +M!``"`P``]#4$``(#``#X-00``@,``/PU!``"`P```#8$``("``!4-@0`'``- +M`&@V!``<``T`?#8$`!P`#0"0-@0`'``-`*0V!``<``T`N#8$`!P`#0#0-@0` +M'``-`.`V!``K5@8`Y#8$`"Q6!@#L-@0`*T(&`/`V!``L0@8``#<$`"M7!@`$ +M-P0`+%<&``PW!``K6`8`$#<$`"Q8!@`(.`0`'``-`!PX!``<``T`,#@$`!P` +M#0!$.`0`'``-`%@X!``<``T`;#@$`!P`#0#(.`0`'``-`"@Y!``"`0``+#D$ +M``(!```P.00``@$``#0Y!``"`0``&#P$`!P`#0`L/`0`'``-`$`\!``<``T` +M5#P$`!P`#0!H/`0`'``-`'P\!``<``T`B#P$`!P`#0#H/`0`'``-`/P\!``< +M``T`$#T$`!P`#0`D/00`'``-`#@]!``<``T`3#T$`!P`#0!8/00`'``-`*`] +M!``<``T`M#T$`!P`#0#(/00`'``-`-P]!``<``T`\#T$`!P`#0`$/@0`'``- +M`!@^!``<``T`)#X$`!PW"P!D/@0`'``-`'@^!``<``T`C#X$`!P`#0"@/@0` +M'``-`+0^!``<``T`R#X$`!P`#0#4/@0`'``-`!`_!``<``T`)#\$`!P`#0`X +M/P0`'``-`$P_!``<``T`8#\$`!P`#0!T/P0`'``-`(`_!``<``T`C#\$``(# +M``"0/P0``@,``)0_!``"`P``F#\$``(#``"$H$`!P`#0"(2@0`'``-`,1*!``<``T`V$H$`!P`#0#L2@0` +M'``-``!+!``<``T`%$L$`!P`#0`H2P0`'``-`#A+!``<``T`=$L$`!P`#0"( +M2P0`'``-`)Q+!``<``T`L$L$`!P`#0#$2P0`'``-`-A+!``<``T`Z$L$`!P` +M#0`D3`0`'``-`#A,!``<``T`3$P$`!P`#0!@3`0`'``-`'1,!``<``T`B$P$ +M`!P`#0"83`0`'``-`-Q,!``%4$``(" +M``"\500`'``-`,Q5!``<``T`"%8$`!P`#0`<5@0`'``-`#!6!``<``T`1%8$ +M`!P`#0!85@0`'``-`&Q6!``<``T`>%8$`"N1!@!\5@0`+)$&`(!6!``KD@8` +MA%8$`"R2!@"45@0`'``-`*A6!``PT`W%@$`!S?"@#T6`0`*ZT-`/A8!``LK0T`(%D$`"NM#0`D +M600`+*T-`-Q:!``<*PP`]%H$`!PK#``<6P0`'.X)`$A;!``<\0D`;%L$`!P% +M#@#\7`0`'/$)`%A=!``!``K +MS`8`#%X$`"S,!@`D7@0`*\P&`"A>!``LS`8`0%X$`"O,!@!$7@0`+,P&`$A> +M!``!``KT`8`9%X$`"S0!@!H7@0`'/`* +M`'1>!``!``<]`X`X%X$`!ST#@`H7P0` +M'*(+`%A?!``<7`P`B%\$`!Q<#`"47P0`*]H&`)A?!``LV@8`H%\$`!P##0"H +M7P0``@X``+!?!``<&PX`Q%\$`!S1"@#87P0`'$(-`.1?!``<\PP`^%\$`!SR +M"@`L8`0`',T,`#Q@!``<40H`3&`$`!R2"@!<8`0`'#D+`&Q@!``0P`V&0$`"NM#0#<9`0`+*T-``QE!``<>0P`(&4$`!Q?#``H +M900`'!<,`#!E!``',$`!PC"@",`0`'(D+`%1X +M!``<10L`8'@$`!RR#`!L>`0`'(0.`'1X!```0``@,` +M`*QX!``"`P``S'@$`!P^"@#4>`0`'$T+`.1X!``<@PT``'D$`!S4"P`(>00` +M*W,'``QY!``L00`+-H+`"!Y!``KEPT`*'D$`"R7#0`L +M>00`*Y@+`#1Y!``LF`L`@'D$`!S!#@#`>00`'.L,`,QY!``00`'`X*`.QY!``K=`<`]'D$`"QT!P#\>00`*V\'``1Z!``L;P<`#'H$ +M`"M4!P`4>@0`+%0'`!QZ!``K8@<`)'H$`"QB!P!`>@0`'.P*`$AZ!``<`0T` +MB'H$`!Q8#`"8>@0`'+T,`*AZ!``@0`'&P.`-AZ!``< +M;0P`X'H$`!RX#`#X>@0`'*<+``1[!``P0`')P.`#Q[ +M!``P0``@X``%Q[!``(T$`!S$#0"@C00`*\T' +M`*2-!``LS0<`J(T$`!R;#0"XC00`*\L'`+R-!``LRP<`Q(T$`!SR"@#,C00` +M*\`'`-2-!``LP`<`V(T$`"O.!P#)($`!RI#@"@ +MD@0`'+8.`,R2!``<&0X`[)($`!PK#@`$DP0`')L-`#"3!``<+PX`/),$`!RI +M#@!DDP0`'+8.`*"3!``<&0X`Q),$`!P8#@#!``LY@<`")X$`!S$#0`!``!``<\@H`D)X$`!R`"@#$G@0`*^H'`,B>!``L +MZ@<`T)X$`!P""P#HG@0`*^L'`.R>!``LZP<`])X$`!S$#0#\G@0`'*D.`"2? +M!``0P`V*D$`"L!"`#0P`F*L$`!QY#`"DJP0`*P((`*BK!``L`@@`L*L$`!P""P`( +MK`0`'&0+`""L!``K`P@`)*P$`"P#"``LK`0`'`(+`%"L!``@H`A+8$`!S2"P"XM@0`'((,`,RV +M!``@H`V+@$`"L9"`#< +MN`0`+!D(`."X!``,,$``(!``!\PP0``@$``(##!``"`0``A,,$ +M``(!``"(PP0``@$``(S#!``"`0``D,,$``(!``"4PP0``@$``##$!``K,@@` +M-,0$`"PR"`!HQ`0`'`(+`*#$!``<@`H`",4$`"LR"``,Q00`+#((`##%!``< +M/@H`G,4$`!Q^#0#$Q00`'(`*`##(!```L`@,L$`!P""P"DRP0`'+\+`-S+!``<@`H` +M",P$`!SR"@`8S`0`'/(*`'S,!``<\@H`C,P$`!SR"@"@S`0`'/(*`,3,!``< +M?@T`\,P$`!R`"@!,S00`'$<*`&C-!``K/`@`;,T$`"P\"`!PS00`*ST(`'3- +M!``L/0@`>,T$`!QS"@"$S00`'"H,`*#-!``K/@@`I,T$`"P^"`"HS00`*S\( +M`*S-!``L/P@`L,T$`!QS"@#4S00`*T`(`-C-!``L0`@`W,T$`"M!"`#@S00` +M+$$(`.3-!``<`L`8,\$`!SR"@!PSP0`'/(*`-C/!``<\@H`Z,\$ +M`!SR"@#\SP0`'/(*`!#0!``K3`@`%-`$`"Q,"``8T`0`'',*`$#0!``K30@` +M1-`$`"Q-"`!(T`0`*TX(`$S0!``L3@@`5-`$`"M/"`!8T`0`+$\(`)#0!``< +M!``< +M/@H`:-X$``(!``!LW@0``@$``'#>!``"`0``=-X$``(!``!XW@0``@$``'S> +M!``"`0``@-X$``(!``"$W@0``@$``(C>!``"`0``C-X$``(!``"0W@0``@$` +M`)3>!``"`0``F-X$``(!``"!``"`0``I-X$``(!``"HW@0` +M`@$``*S>!``"`0``L-X$``(!``#$W@0`'+0-`,S>!``<4`L`$-\$`!PI"P`X +MWP0`'(`*`(3?!``<@`H`G-\$`!QN"P#HWP0`'"D+`/C?!``<_PL`(.`$`!S? +M"@!,X`0`'!X*`&C@!```@`%/0$`!SR"@!4]`0`*WD(`%CT!``L>0@`7/0$`!S$#0"4]`0`*WH(`)CT +M!``L>@@`G/0$`!S$#0"P]`0`*W@(`+3T!``L>`@`O/0$`!SR"@#0]`0`*W@( +M`-3T!``L>`@`W/0$`!SR"@#T]`0`*WL(`/CT!``L>P@``/4$`!S^#``(]00` +M*WP(``SU!``L?`@`$/4$`!R;#0`H]00`*WT(`"SU!``L?0@`,/4$`!R;#0!( +M]00`*WX(`$SU!``L?@@`4/4$`!R;#0!H]00`*W\(`&SU!``L?P@``@`L/4$`"QX"`"X]00`'/(*`,3U!``K>`@`R/4$ +M`"QX"`#0]00`'/(*`.#U!``#@`, +M^@0`+)X.`(SZ!``<>@T`H/H$`!PV#@#L^@0`'#X,``C[!``<_PL`*/L$`!SM +M"0!<^P0`'$X.`'C[!``0P`+`(%`!QQ"P`X`@4`'*,-`&@"!0`K70P`;`(%`"Q=#`"$`@4` +M'.X-`)`"!0`0T`-`0%`!P#"@!0!`4`'`,*`)@$!0`<7PP`J`0% +M`!Q?#`#H!`4`'%\,`!P%!0`!D%`!P` +M#0"@&04`'#X*`+`9!0`!0`< +M``T`*!X%`!R8#0!('@4`'+\+`&P>!0`<``T`>!X%`!R""P"4'@4`''0+`+0> +M!0`<=`L`P!X%`!RL#@#,'@4`'*P.`-@>!0`"@%`!R`"@"X*`4`'(`*`#@I!0`<@`H`:"D%`!R;#0"H*04` +M'(`*`,@I!0`<@`H`Z"D%`!R`"@`$*@4`')L-`$`J!0`<@`H`E"H%`!SK#0`, +M*P4`'(`*`!@K!0`$8%`!R`"@"P +M1@4`'/\+`-A&!0`$<% +M`!P`#0"$1P4`'$D*`*A'!0`@D` +MS$<%`!P`#0#L1P4`''0+`/1'!0`K>PD`^$<%`"Q["0``2`4`'``-``Q(!0`< +M,PL`)$@%`!P`#0`L2`4`')(*`#1(!0`$X%`!Q."P"$3@4`'``-`)!.!0`"`@``E$X% +M``(#``"83@4``@,``)Q.!0`"`P``M$X%`"L8"0"X3@4`+!@)`,1.!0`<``T` +M7$\%`!P`#0"<3P4`'-8+`*Q/!0`<``T`V$\%`!R1#`#D3P4`'``-`/!/!0`" +M`@``]$\%``(#``#X3P4``@,``/Q/!0`"`P``0%`%`"O:"0!$4`4`+-H)`$A0 +M!0`<"0"L4`4`+-X) +M`+10!0`"0"T404`+-X)`,!1!0``@` +M`"H!``"`"```*@$``(@(```J`0``D`@``"H!``"8"```*@$``*`(```J`0`` +MJ`@``"H!``"P"```*@$``+@(```J`0``P`@``"H!``#("```*@$``-`(```J +M`0``V`@``"H!``#@"```*@$``.@(```J`0``\`@``"H!``#X"```*@$````) +M```J`0``"`D``"H!```0"0``*@$``!@)```J`0``(`D``"H!```H"0``*@$` +M`#`)```J`0``.`D``"H!``!`"0``*@$``$@)```J`0``4`D``"H!``!8"0`` +M*@$``&`)```J`0``:`D``"H!``!P"0``*@$``'@)```J`0``@`D``"H!``"( +M"0``*@$``)`)```J`0``F`D``"H!``"@"0``*@$``*@)```J`0``L`D``"H! +M``"X"0``*@$``,`)```J`0``R`D``"H!``#0"0``*@$``-@)```J`0``X`D` +M`"H!``#H"0``*@$``/`)```J`0``^`D``"H!````"@``*@$```@*```J`0`` +M$`H``"H!```8"@``*@$``"`*```J`0``*`H``"H!```P"@``*@$``#@*```J +M`0``0`H``"H!``!("@``*@$``%`*```J`0``6`H``"H!``!@"@``*@$``&@* +M```J`0``<`H``"H!``!X"@``*@$``(`*```J`0``B`H``"H!``"0"@``*@$` +M`)@*```J`0``H`H``"H!``"H"@``*@$``+`*```J`0``N`H``"H!``#`"@`` +M*@$``,@*```J`0``T`H``"H!``#0"@```(0*`-@*```J`0``X`H``"H!``#H +M"@``*@$``/`*```J`0``^`H``"H!````"P``*@$```@+```J`0``$`L``"H! +M```8"P``*@$``"`+```J`0``*`L``"H!```P"P``*@$``#@+```J`0``0`L` +M`"H!``!("P``*@$``%`+```J`0``6`L``"H!``!@"P``*@$``&@+```J`0`` +M<`L``"H!``!X"P``*@$``(`+```J`0``B`L``"H!``"0"P``*@$``)@+```J +M`0``H`L``"H!``"H"P``*@$``+`+```J`0``N`L``"H!``#`"P``*@$``,@+ +M```J`0``T`L``"H!``#8"P``*@$``.`+```J`0``Z`L``"H!``#P"P``*@$` +M`/@+```J`0````P``"H!```(#```*@$``!`,```J`0``&`P``"H!```@#``` +M*@$``"@,```J`0``,`P``"H!```X#```*@$``$`,```J`0``2`P``"H!``!0 +M#```*@$``%@,```J`0``8`P``"H!``!H#```*@$``'`,```J`0``>`P``"H! +M``"`#```*@$``(@,```J`0``D`P``"H!``"8#```*@$``*`,```J`0``H`P` +M``"$"@"H#```*@$``+`,```J`0``N`P``"H!``#`#```*@$``,@,```J`0`` +MT`P``"H!``#8#```*@$``.`,```J`0``Z`P``"H!``#P#```*@$``/@,```J +M`0````T``"H!```(#0``*@$``!`-```J`0``&`T``"H!```@#0``*@$``"@- +M```J`0``,`T``"H!```P#0```(0*`#@-```J`0``0`T``"H!``!`#0```(0* +M`$@-```J`0``4`T``"H!``!8#0``*@$``&`-```J`0``:`T``"H!``!P#0`` +M*@$``'@-```J`0``@`T``"H!``"(#0``*@$``)`-```J`0``F`T``"H!``"@ +M#0``*@$``*@-```J`0``L`T``"H!``"X#0``*@$``,`-```J`0``R`T``"H! +M``#0#0``*@$``-@-```J`0``X`T``"H!``#H#0``*@$``/`-```J`0``^`T` +M`"H!````#@``*@$```@.```J`0``$`X``"H!```8#@``*@$``"`.```J`0`` +M*`X``"H!```P#@``*@$``#@.```J`0``0`X``"H!``!(#@``*@$``%`.```J +M`0``6`X``"H!``!@#@``*@$``&@.```J`0``<`X``"H!``!X#@``*@$``(`. +M```J`0``@`X```"$"@"(#@``*@$``)`.```J`0``F`X``"H!``"@#@``*@$` +M`*@.```J`0``L`X``"H!``"X#@``*@$``,`.```J`0``R`X``"H!``#0#@`` +M*@$``-@.```J`0``X`X``"H!``#H#@``*@$``/`.```J`0``\`X```"$"@#X +M#@``*@$````/```J`0``"`\``"H!```0#P``*@$``!@/```J`0``(`\``"H! +M```H#P``*@$``#`/```J`0``.`\``"H!``!`#P``*@$``$@/```J`0``4`\` +M`"H!``!8#P``*@$``&`/```J`0``:`\``"H!``!P#P``*@$``'@/```J`0`` +M@`\``"H!``"(#P``*@$``)`/```J`0``F`\``"H!``"@#P``*@$``*@/```J +M`0``L`\``"H!``"X#P``*@$``,`/```J`0``R`\``"H!``#0#P``*@$``-@/ +M```J`0``X`\``"H!``#H#P``*@$``/`/```J`0``^`\``"H!````$```*@$` +M``@0```J`0``$!```"H!```0$````(0*`!@0```J`0``(!```"H!```H$``` +M*@$``#`0```J`0``.!```"H!``!`$```*@$``$@0```J`0``4!```"H!``!8 +M$```*@$``&`0```J`0``:!```"H!``!P$```*@$``'@0```J`0``@!```"H! +M``"($```*@$``)`0```J`0``F!```"H!``"@$```*@$``*@0```J`0``L!`` +M`"H!``"X$```*@$``,`0```J`0``R!```"H!``#0$```*@$``-@0```J`0`` +MX!```"H!``#H$```*@$``/`0```J`0``^!```"H!````$0``*@$```@1```J +M`0``$!$``"H!```8$0``*@$``"`1```J`0``*!$``"H!```H$0```(0*`#`1 +M```J`0``.!$``"H!``!`$0``*@$``$@1```J`0``4!$``"H!``!8$0``*@$` +M`&`1```J`0``:!$``"H!``!P$0``*@$``'@1```J`0``@!$``"H!``"($0`` +M*@$``(@1````A`H`D!$``"H!``"8$0``*@$``*`1```J`0``J!$``"H!``"P +M$0``*@$``+@1```J`0``P!$``"H!``#($0``*@$``-`1```J`0``V!$``"H! +M``#@$0``*@$``.@1```J`0``\!$``"H!``#X$0``*@$````2```J`0``"!(` +M`"H!```0$@``*@$``!@2```J`0``(!(``"H!```H$@``*@$``#`2```J`0`` +M.!(``"H!``!`$@``*@$``$@2```J`0``4!(``"H!``!8$@``*@$``&`2```J +M`0``:!(``"H!``!P$@``*@$``'@2```J`0``@!(``"H!``"`$@```(0*`(@2 +M```J`0``D!(``"H!``"8$@``*@$``*`2```J`0``J!(``"H!``"P$@``*@$` +M`+@2```J`0``P!(``"H!``#($@``*@$``-`2```J`0``V!(``"H!``#8$@`` +M`(0*`.`2```J`0``Z!(``"H!``#H$@```(0*`/`2```J`0``^!(``"H!```` +M$P``*@$```@3```J`0``$!,``"H!```8$P``*@$``"`3```J`0``*!,``"H! +M```P$P``*@$``#@3```J`0``0!,``"H!``!($P``*@$``%`3```J`0``6!,` +M`"H!``!@$P``*@$``&@3```J`0``!8``"H!``"`%@``*@$``(@6 +M```J`0``D!8``"H!``"8%@``*@$``*`6```J`0``H!8```"$"@"H%@``*@$` +M`+`6```J`0``N!8``"H!``#`%@``*@$``,@6```J`0``T!8``"H!``#8%@`` +M*@$``.`6```J`0``Z!8``"H!``#P%@``*@$``/@6```J`0```!<``"H!```( +M%P``*@$``!`7```J`0``&!<``"H!```@%P``*@$``"@7```J`0``,!<``"H! +M```X%P``*@$``$`7```J`0``2!<``"H!``!0%P``*@$``%@7```J`0``8!<` +M`"H!``!H%P``*@$``'`7```J`0``>!<``"H!``"`%P``*@$``(@7```J`0`` +MD!<``"H!``"0%P```(0*`)@7```J`0``H!<``"H!``"H%P``*@$``+`7```J +M`0``N!<``"H!``#`%P``*@$``,@7```J`0``T!<``"H!``#8%P``*@$``.`7 +M```J`0``Z!<``"H!``#P%P``*@$``/`7````A`H`^!<``"H!````&```*@$` +M``@8```J`0``$!@``"H!```8&```*@$``"`8```J`0``*!@``"H!```P&``` +M*@$``#@8```J`0``0!@``"H!``!(&```*@$``%`8```J`0``6!@``"H!``!@ +M&```*@$``&@8```J`0`````J`0``$!X``"H!```8'@``*@$``"`>```J`0`` +M*!X``"H!```H'@```(0*`#`>```J`0``.!X``"H!``!`'@``*@$``$@>```J +M`0``4!X``"H!``!8'@``*@$``&`>```J`0``8!X```"$"@!H'@``*@$``'`> +M```J`0``>!X``"H!``"`'@``*@$``(@>```J`0``D!X``"H!``"8'@``*@$` +M`*`>```J`0``J!X``"H!``"P'@``*@$``+@>```J`0``P!X``"H!``#`'@`` +M`(0*`,@>```J`0``T!X``"H!``#8'@``*@$``.`>```J`0``Z!X``"H!``#P +M'@``*@$``/@>```J`0```!\``"H!```('P``*@$``!`?```J`0``&!\``"H! +M```8'P```(0*`"`?```J`0``(!\```"$"@`H'P``*@$``#`?```J`0``.!\` +M`"H!``!`'P``*@$``$@?```J`0``4!\``"H!``!8'P``*@$``&`?```J`0`` +M:!\``"H!``!P'P``*@$``'@?```J`0``@!\``"H!``"('P``*@$``)`?```J +M`0``F!\``"H!``"@'P``*@$``*@?```J`0``L!\``"H!``"X'P``*@$``,`? +M```J`0``R!\``"H!``#0'P``*@$``-@?```J`0``X!\``"H!``#H'P``*@$` +M`/`?```J`0``^!\``"H!````(```*@$```@@```J`0``$"```"H!```8(``` +M*@$``"`@```J`0``*"```"H!```P(```*@$``#@@```J`0``0"```"H!``!( +M(```*@$``%`@```J`0``6"```"H!``!@(```*@$``&@@```J`0``<"```"H! +M``!X(```*@$``(`@```J`0``B"```"H!``"0(```*@$``)@@```J`0``H"`` +M`"H!``"H(```*@$``+`@```J`0``N"```"H!``#`(```*@$``,@@```J`0`` +MT"```"H!``#8(```*@$``.`@```J`0``Z"```"H!``#P(```*@$``/@@```J +M`0```"$``"H!```((0``*@$``!`A```J`0``&"$``"H!```@(0``*@$``"@A +M```J`0``,"$``"H!```X(0``*@$``#@A````A`H`0"$``"H!``!((0``*@$` +M`%`A```J`0``6"$``"H!``!@(0``*@$``&@A```J`0``<"$``"H!``!X(0`` +M*@$``(`A```J`0``B"$``"H!``"0(0``*@$``)@A```J`0``H"$``"H!``"H +M(0``*@$``+`A```J`0``N"$``"H!``#`(0``*@$``,@A```J`0``R"$```"$ +M"@#0(0``*@$``-@A```J`0``X"$``"H!``#H(0``*@$``/`A```J`0``^"$` +M`"H!````(@``*@$```@B```J`0``$"(``"H!```8(@``*@$``"`B```J`0`` +M*"(``"H!```P(@``*@$``#@B```J`0``0"(``"H!``!((@``*@$``%`B```J +M`0``6"(``"H!``!8(@```(0*`&`B```J`0``:"(``"H!``!P(@``*@$``'@B +M```J`0``@"(``"H!``"((@``*@$``)`B```J`0``F"(``"H!``"@(@``*@$` +M`*@B```J`0``L"(``"H!``"X(@``*@$``,`B```J`0``R"(``"H!``#0(@`` +M*@$``-@B```J`0``X"(``"H!``#H(@``*@$``/`B```J`0``^"(``"H!```` +M(P``*@$```@C```J`0``$",``"H!```8(P``*@$``"`C```J`0``*",``"H! +M```P(P``*@$``#@C```J`0``0",``"H!``!((P``*@$``%`C```J`0``6",` +M`"H!``!@(P``*@$``&@C```J`0``<",``"H!``!X(P``*@$``(`C```J`0`` +MB",``"H!``"0(P``*@$``)@C```J`0``H",``"H!``"H(P``*@$``+`C```J +M`0``N",``"H!``#`(P``*@$``,@C```J`0``T",``"H!``#8(P``*@$``.`C +M```J`0``Z",``"H!``#P(P``*@$``/@C```J`0```"0``"H!```()```*@$` +M`!`D```J`0``&"0``"H!```@)```*@$``"@D```J`0``,"0``"H!```X)``` +M*@$``$`D```J`0``2"0``"H!``!0)```*@$``%@D```J`0``8"0``"H!``!H +M)```*@$``'`D```J`0``>"0``"H!``"`)```*@$``(@D```J`0``D"0``"H! +M``"0)````(0*`)@D```J`0``H"0``"H!``"H)```*@$``+`D```J`0``N"0` +M`"H!``#`)```*@$``,@D```J`0``T"0``"H!``#8)```*@$``.`D```J`0`` +MZ"0``"H!``#P)```*@$``/`D````A`H`^"0``"H!````)0``*@$```@E```J +M`0``$"4``"H!```8)0``*@$``"`E```J`0``*"4``"H!```P)0``*@$``#@E +M```J`0``0"4``"H!``!()0``*@$``%`E```J`0``6"4``"H!``!@)0``*@$` +M`&@E```J`0``<"4``"H!``!P)0```(0*`'@E```J`0``@"4``"H!``"()0`` +M*@$``)`E```J`0``F"4``"H!``"@)0``*@$``*@E```J`0``L"4``"H!``"X +M)0``*@$``,`E```J`0``R"4``"H!``#()0```(0*`-`E```J`0``V"4``"H! +M``#@)0``*@$``.@E```J`0``\"4``"H!``#X)0``*@$````F```J`0``""8` +M`"H!```0)@``*@$``!@F```J`0``("8``"H!```H)@``*@$``#`F```J`0`` +M."8``"H!``!`)@``*@$``$@F```J`0``4"8``"H!``!8)@``*@$``&`F```J +M`0``:"8``"H!``!P)@``*@$``'@F```J`0``@"8``"H!``"()@``*@$``)`F +M```J`0``F"8``"H!``"@)@``*@$``*@F```J`0``L"8``"H!``"X)@``*@$` +M`,`F```J`0``R"8``"H!``#0)@``*@$``-@F```J`0``X"8``"H!``#H)@`` +M*@$``/`F```J`0``^"8``"H!````)P``*@$```@G```J`0``$"<``"H!```8 +M)P``*@$``"`G```J`0``*"<``"H!```P)P``*@$``#@G```J`0``0"<``"H! +M``!()P``*@$``%`G```J`0``6"<``"H!``!@)P``*@$``&@G```J`0``<"<` +M`"H!``!X)P``*@$``(`G```J`0``B"<``"H!``"0)P``*@$``)@G```J`0`` +MF"<```"$"@"@)P``*@$``*@G```J`0``L"<``"H!``"X)P``*@$``,`G```J +M`0``R"<``"H!``#0)P``*@$```0````"&`L`#`````(8"P`4`````A@+`!P` +M```"&`L`)`````(8"P`L`````A@+`'0````"W`P`?`````*(#@"$`````A\. +M`(P````"6@L`E`````+J"@"<`````I(+`*0````"!P\`K`````+Z"0!L`0`` +M`OD-`+P!```"4PL`Q`$```*;#@#,`0```N\)`-0!```"HPX`W`$```+_"@#D +M`0```G,,`.P!```"^PL`]`$```++#``,`@```BX*`!P"```"+@H`;`(```)S +M"P!T`@```FX.`'P"```"H@H`C`(```+*"P"D`@```FD-`*P"```"RPH`4`0` +M``(#``!4!````@H,`%P$```"`P``8`0```)>#@!H!````@,``&P$```"DPX` +M=`0```(#``!X!````GP*`(`$```"`P``A`0```+V"P",!````@,``)`$```" +M"@P`F`0```(#``""(` +M``(U"`!\(@```J('`(`B```"E`<`A"(```*6!P"((@```I@'`(PB```"H@<` +MD"(```*B!P"4(@```J('`)@B```"F@<`G"(```(;"`"@(@```M0'`*0B```" +MH@<`J"(```*"0`0)``` +M`H<)`!0D```"&PD`&"0```*!"0`@)````L@(`"@D```"Q@@`1"0```(-``!( +M)````@T``'`D```"#0``="0```(-``!8+````@,``%PL```"`P``8"P```(# +M``!D+````@,``&@L```"`P``;"P```(#``!P+````@,``'0L```"`P``>"P` +M``(#``!\+````@,``(`L```"`P``A"P```(#``"(+````@,``(PL```"`P`` +MD"P```(#``"4+````@,``)@L```"`P``G"P```(#``"@+````@,``*0L```" +M`P``J"P```(#``"L+````@,``+`L```"`P``M"P```(#``"X+````@,````` +M```````````````````````````````````#``$``````````````````P`# +M``````````````````,`!0`````````````````#``8````````````````` +M`P`(``````````````````,`"@`````````````````#``P````````````` +M`````P`.``````````````````,`#P`````````````````#`!$````````` +M`````````P`3``````````````````,`%``````````````````#`!8````` +M`````````````P`8``````````````````,`&0`````````````````#`!H` +M`````````````````P`;``$```````````````0`\?\+```````````````` +M``$`"P````0````````````!``L````(`````````````0`+````A``````` +M``````$`"P```)0````````````!``L```"<`````````````0`+````Q``` +M``````````$`"P```.P````````````!``L````,`0```````````0`+```` +M+`$```````````$`"P```'P!```````````!``L```",`0```````````0`+ +M````*`(```````````$`"P```$P"```````````!``L````P!``````````` +M`0`+````C`0```````````$`"P```/`$```````````!``L```!,!0`````` +M`````0`+````6`4```````````$`#@```(0%```````````!``L```"&\```````````$`"P`` +M`.!O```````````!``L````D<````````````0`+````A'````````````$` +M"P```,!Q```````````!``X```!0<@```````````0`+````9'(````````` +M``$`"P```$!S```````````!``X```#0`X```0````!``,`5@(``'P.```$`````0`#`&("``"`#@``!`````$` +M`P!N`@``A`X```0````!``,`>@(``/`#```$`````0`6``X```#P`P`````` +M````%@"(`@``]`,```@````!`!8`EP(`````````````!`#Q_PL```#`=0`` +M`````````0`+````]'4```````````$`"P```/QU```````````!``L````` +M=@```````````0`+````"'8```````````$`"P```#AV```````````!``L` +M```\=@```````````0`+````0'8```````````$`"P```$1V```````````! +M``L```#\=@```````````0`+````:'<```````````$`"P```&QW```````` +M```!``L```!D>````````````0`+````:'@```````````$`"P```.!X```` +M```````!``L```"$>0```````````0`+````L'D```````````$`"P```$QZ +M```````````!``L```#`>P```````````0`;````B`X```````````,`"P`` +M`$Q]```````````!``X```"L?0```````````0`+````*'X```````````$` +M"P```"Q_```````````!`*("``"P@```\`````(``0`+````L(`````````` +M``$`L@(``*"!``"(`@```@`!``L```"@@0```````````0`+````*(0````` +M``````$`"P```(R$```````````!``L````@A0```````````0#!`@``+(4` +M`#`````"``$`"P```"R%```````````!``L```!(L```````````$`"P```,"+```````````!``L` +M```8C0```````````0`+````=(T```````````$`"P```.2/```````````! +M`)X````$#```````````&``+````")4```````````$`"P```%R6```````` +M```!``L````0EP```````````0`+````$)D```````````$`"P```(29```` +M```````!``L```#`F0```````````0`+````3)P```````````$`"P```*R> +M```````````!``L```!LGP```````````0`+````>)\```````````$`"P`` +M`/B?```````````!``L````$H````````````0`+````H*````````````$` +M"P```*R@```````````!``L```"XH@```````````0`+````)*,````````` +M``$`"P```'BD```````````!``L```"8I````````````0`+````T*0````` +M``````$`"P```-RD```````````!``L```"PI0```````````0#7`@``B`X` +M``<````!``,`#@```(@.```````````#`.,"```$#````0````$`&`#O`@`` +M```````````$`/'_"P```+RE```````````!`/X"````I@``]`````(``0`+ +M`````*8```````````$`#@```""F```````````!``L```#,X```````````$`"P```.31```` +M```````!``L```!\T@```````````0`+````B-,```````````$`"P```-#4 +M```````````!``L````@U0```````````0`+````+-8```````````$`"P`` +M`%S8```````````!``L```"\V@```````````0`.````G-L```````````$` +M"P```*#;```````````!``L`````0`````````! +M``L```!T7@$``````````0`.````%%\!``````````$`"P```"1?`0`````` +M```!``L```#L7P$``````````0`+`````&$!``````````$`"P```'QA`0`` +M```````!``L````88@$``````````0`.````+&(!``````````$`"P```-!C +M`0`````````!``L````P9`$``````````0`+````A&0!``````````$`"P`` +M`-!D`0`````````!``L```#D9`$``````````0`+````+&4!``````````$` +M"P```&1E`0`````````!``L```"@90$``````````0`+````M&4!```````` +M``$`"P```,!E`0`````````!``L```#090$``````````0`+````2&8!```` +M``````$`"P```$1G`0`````````!``L```!(9P$``````````0`+````>&@$``````````0`.```` +M_`4``````````!8`"`4`````````````!`#Q_PL```#,>@$``````````0`+ +M````$'L!``````````$`"P```+A[`0`````````!``L```!,?`$````````` +M`0`+````K'T!``````````$`"P```"1^`0`````````!``L```"X?@$````` +M`````0`;````J`<``````````!8`#@```-B``0`````````!``L```#D@`$` +M`````````0">````V!(```````````,`"P```+B"`0`````````!``L```"P +MA`$``````````0`+````3(4!``````````$`"P```%B%`0`````````!``L` +M``#$AP$``````````0`+````F(@!``````````$`"P```/B(`0`````````! +M``L```#0B0$``````````0`.````:(H!``````````$`"P```'B*`0`````` +M```!``X```#DB@$``````````0`+````](H!``````````$`#@```*R,`0`` +M```````!``L```"\C`$``````````0`.````_(P!``````````$`"P```!"- +M`0`````````!``L```"(C0$``````````0`.````^(T!``````````$`"P`` +M``R.`0`````````!``L```!PC@$``````````0`+````*)`!``````````$` +M"P```*R0`0`````````!``L````DD0$``````````0`+````G)$!```````` +M``$`"P```$B2`0`````````!``L````DE@$``````````0`+````-)`0`````````!``L```"0G@$``````````0`+ +M````2*`!``````````$`"P```"RA`0`````````!``L```!HH0$````````` +M`0`+````@*$!``````````$`"P```*BA`0`````````!``L```#HH0$````` +M`````0`+````\*(!``````````$`$P4``*@'```&`````0`6``X```"H!P`` +M````````%@`F!0``L`<```(````!`!8`.`4``+0'```"`````0`6`%4%``"X +M!P``!@````$`%@!N!0`````````````$`/'_"P```!BC`0`````````!``L` +M```@HP$``````````0`;````X!(```````````,`"P```"2D`0`````````! +M``X```!`0`````````!``L```#T +MW@$``````````0`+````_-X!``````````$`"P````3?`0`````````!``L` +M``#\WP$``````````0`.````%.$!``````````$`"P```!CA`0`````````! +M``L```"PXP$``````````0`6````?`,```````````4`[0$``(0#```````` +M```%`"P&``!LZ0$`,`````(``0!%!@``3.D!`"`````"``$`908``*SI`0"H +M`````@`!``L```"@YP$``````````0`;````)!,```````````,`"P````#I +M`0`````````!`'\&``"!P``"#D"`!0````"``$`"P````0O`@`` +M```````!``L````L+P(``````````0`+````<"\"``````````$`"P`````P +M`@`````````!``L```"4,`(``````````0`+````$#$"``````````$`"P`` +M`,`Q`@`````````!``L```#$,0(``````````0">````3#0``````````!@` +M#@```,0R`@`````````!``L```#(,@(``````````0`+````/#,"```````` +M``$`"P```,PU`@`````````!``L```!8.`(``````````0`+````"#D"```` +M``````$`"P```!PY`@`````````!``L```#@.0(``````````0`+````\#D" +M``````````$`"P```-`Z`@`````````!``L```"D.P(``````````0`.```` +M5!0``````````!@`ZP<`````````````!`#Q_PL```!\/`(``````````0`+ +M````F#P"``````````$`"P```+0\`@`````````!``L```#0/`(````````` +M`0`+````[#P"``````````$`"P````@]`@`````````!``L````D/0(````` +M`````0`+````0#T"``````````$`"P```(`]`@`````````!``L```"H/0(` +M`````````0`+````Q#T"``````````$`]@<`````````````!`#Q_PL```#@ +M/0(``````````0`+````]#T"``````````$```@`````````````!`#Q_PL` +M```P/@(``````````0`+````4#X"``````````$`#@```'0^`@`````````! +M``L````@0`(``````````0`+````[$`"``````````$`#@```/A``@`````` +M```!``L````400(``````````0`+````=$$"``````````$`#@```(!!`@`` +M```````!``L```"<00(``````````0`4"```_$$"`"`````"``$`"P```/Q! +M`@`````````!``L````<0@(``````````0`+````($("``````````$`-@@` +M`#!<`@`P`````@`!`$T(``#,80(`_`````(``0!H"```&&`"```!```"``$` +M@@@``.A?`@`P`````@`!`)4(``!(5`(`(`````(``0"R"````%,"`"`````" +M``$`S@@```Q<`@`D`````@`!`.L(```D4`(`)`````(``0`+````.$,"```` +M``````$`"P```%A#`@`````````!``L```"P0P(``````````0`+````[$," +M``````````$`"P````Q$`@`````````!``L````\1`(``````````0`+```` +M8$0"``````````$`"P```-Q$`@`````````!``L````810(``````````0`+ +M````'$4"``````````$`"P```$Q%`@`````````!``L```"\10(````````` +M`0`+````^$4"``````````$`"P```)!+`@`````````!``L````43`(````` +M`````0`+````3$P"``````````$`"P```(!,`@`````````!``L````D30(` +M`````````0`."0``1$T"`.`"```"``$`"P```$1-`@`````````!``L````D +M4`(``````````0`K"0``2%`"`+@"```"``$`"P```$A0`@`````````!``L` +M````4P(``````````0!'"0``(%,"`"@!```"``$`"P```"!3`@`````````! +M``L```!(5`(``````````0!E"0``:%0"`-P````"``$`"P```&A4`@`````` +M```!`'\)``!$50(`R`8```(``0`+````1%4"``````````$`"P````Q<`@`` +M```````!``L````P7`(``````````0"<"0``8%P"`(@#```"``$`"P```&!< +M`@`````````!``X```#D7P(``````````0`+````Z%\"``````````$`"P`` +M`!A@`@`````````!`+()```880(`>`````(``0`+````&&$"``````````$` +M"P```)!A`@`````````!``L```#,80(``````````0`+````R&("```````` +M``$`Q`D``&QC`@`L`0```@`!``L```!L8P(``````````0#0"0``F&0"`$P` +M```"``$`"P```)AD`@`````````!``L```#D9`(``````````0#;"0`````` +M```````$`/'_[0D``/!G`@`P`````@`!``L```#P9P(``````````0`+```` +M(&@"``````````$`"P```"1H`@`````````!``L```#,:@(``````````0`+ +M````U&H"``````````$``PH``-QJ`@`X`````@`!``L```#<:@(````````` +M`0`;````?!,```````````,`"P```!1K`@`````````!``L````X:P(````` +M`````0`+````L&L"``````````$`"P```)!N`@`````````!``L```#4;@(` +M`````````0`+````8&\"``````````$`"P```&1O`@`````````!``L```!H +M;P(``````````0`+````C&\"``````````$`"P```)!O`@`````````!``L` +M``"8;P(``````````0`+````%'`"``````````$`"P```%QP`@`````````! +M`!4*```$<0(`G`````(``0`+````!'$"``````````$`"P```*!Q`@`````` +M```!``L```#@<0(``````````0`+````O',"``````````$`"P```.!S`@`` +M```````!``L```"`=`(``````````0`+````C'0"``````````$`"P```.1W +M`@`````````!`"H*```@>`(`@`$```(``0`+````('@"``````````$`"P`` +M`*!Y`@`````````!``L````8>@(``````````0`+````]'H"``````````$` +M"P```!A[`@`````````!``X```"0>P(``````````0`+````H'L"```````` +M``$`#@```%1\`@`````````!`#L*``!\$P``(`````$``P`.````?!,````` +M``````,`1@H``)P3```@`````0`#`%$*``"\$P``$`````$``P`.````Q`<` +M`````````!8`70H`````````````!`#Q_PL```!8?`(``````````0`+```` +M7'P"``````````$`"P```!1]`@`````````!``X```!X?0(``````````0`+ +M````B'T"``````````$`"P```/Q_`@`````````!`!L```!D-``````````` +M&``+````%(`"``````````$`"P```$"``@`````````!``L```!<@`(````` +M`````0`+````>(`"``````````$`"P```-"``@`````````!``L````H@0(` +M`````````0`+````@($"``````````$`"P```/2!`@`````````!``L````X +M@@(``````````0`+````O(("``````````$`"P```%"#`@`````````!``L` +M``"4@P(``````````0`.````!(0"``````````$`"P```!2$`@`````````! +M``X```!`A0(``````````0`+````4(4"``````````$`"P```-B%`@`````` +M```!``L````HB`(``````````0">````S!,```````````,`#@```,R*`@`` +M```````!`&\*``#,$P``#`````$``P`.````S!,```````````,`>PH``-@3 +M```,`````0`#`(<*``!D-```\`,```$`&`"1"@`````````````$`/'_"P`` +M`-"*`@`````````!``L```!0BP(``````````0`+````T(L"``````````$` +M"P```.R+`@`````````!``L```!@C0(``````````0`+````H(X"```````` +M``$`GPH`````````````!`#Q_PL````)L"``````````$`"P```/2;`@`````````!`!L```#D +M$P```````````P`+````])T"``````````$`"P```&"B`@`````````!``L` +M``"LH@(``````````0#/"@``Y!,```8````!``,`#@```.03```````````# +M`-L*``````````````0`\?\+````'*,"``````````$`"P```%RF`@`````` +M```!``L```!@I@(``````````0`+````9*8"``````````$`"P```&BF`@`` +M```````!``L```!LI@(``````````0`+````\*8"``````````$`Z0H``/2F +M`@!X`````@`!``L```#TI@(``````````0`&"P``;*<"``@````"``$`"P`` +M`&RG`@`````````!``L```!TIP(``````````0`8"P``Y*L"`%P````"``$` +M"P````BI`@`````````!`"X+```\J@(`J`$```(``0`+````/*H"```````` +M``$`&P```.P3```````````#``L```#DJP(``````````0!%"P``0*P"`,0` +M```"``$`"P```$"L`@`````````!`%L+```$K0(`G`````(``0`+````!*T" +M``````````$`"P```*"M`@`````````!`&H+``#\K0(`E`````(``0`+```` +M_*T"``````````$`=PL``)"N`@`H`````@`!``L```"0K@(``````````0`+ +M````N*X"``````````$`"P```""O`@`````````!``L```#\KP(````````` +M`0`.````(+`"``````````$`"P```.BP`@`````````!``L```"DL0(````` +M`````0`+````4+,"``````````$`#@```'2S`@`````````!``L```"LLP(` +M`````````0`.````5+4"``````````$`CPL``%BU`@!\`````@`!``L```!8 +MM0(``````````0`+````U+4"``````````$`#@````"V`@`````````!``L` +M```(MP(``````````0`+````<,,"``````````$`"P```(##`@`````````! +M``L````0Q0(``````````0`+````E,4"``````````$`"P```-C+`@`````` +M```!``X```#8U0(``````````0"J"P``[!,```8````!``,`#@```.P3```` +M```````#`+8+``#T$P``!@````$``P#!"P``_!,```0````!``,`S0L````4 +M```(`````0`#`-@+```(%```"`````$``P#C"P``$!0```@````!``,`[@L` +M````````````!`#Q__X+``#!0#``0````"``$`"P```'@4`P`` +M```````!``L```!\%`,``````````0`+````D!0#``````````$`+0T``)0= +M`P!``````@`!`#<-``!0'0,`1`````(``0!"#0``#!T#`$0````"``$`30T` +M`-0=`P"X`0```@`!`%L-``#0'`,`/`````(``0!F#0``E!P#`#P````"``$` +M<@T``%@<`P`\`````@`!`'X-``#P&P,`:`````(``0")#0``C!@#`!P````" +M``$`G@T``'`8`P`<`````@`!`+(-````%@,`2`````(``0#'#0``4!4#`+`` +M```"``$`"P```%`5`P`````````!``L`````%@,``````````0#=#0``2!8# +M`"@"```"``$`"P```$@6`P`````````!``X```#<%@,``````````0`+```` +M^!8#``````````$`[`T``*@8`P!8`0```@`!`!L```!4.```````````&``+ +M````$$#``````````$`"P```"!"`P`````````!``L```!L0@,````` +M`````0`+````W$(#``````````$`"P```"1%`P`````````!``L```!T10,` +M`````````0`+````&$8#``````````$`#@```&15`P`````````!``L```"P +M50,``````````0`.````W%4#``````````$`"P```.Q5`P`````````!`-$. +M``!H"P``````````!0#7#@``B`L```````````4`W0X``)`+```````````% +M`.,.``"L"P``````````!0#I#@``X`L```````````4`#@```$!7`P`````` +M```!``L```!@5P,``````````0`.````D%X#``````````$`"P```,1>`P`` +M```````!``X````D8@,``````````0`+````2&(#``````````$`#@```!QP +M`P`````````!``L```!X<`,``````````0`.````\',#``````````$`"P`` +M`"!T`P`````````!``X```#L>P,``````````0`+````-'P#``````````$` +M#@```#R'`P`````````!``L```"8AP,``````````0">````'`@````````` +M`!8`"P```#R)`P`````````!``X```#`B@,``````````0`+````Y(H#```` +M``````$`#@```/B-`P`````````!``L````DC@,``````````0`.````9(\# +M``````````$`"P```(2/`P`````````!``L```#LCP,``````````0`+```` +M!)`#``````````$`"P```"B0`P`````````!``L````\D`,``````````0#O +M#@``-!0```````````4`"P```'"0`P`````````!``X```"DD@,````````` +M`0`+````J)(#``````````$`"P```,R2`P`````````!``X````@DP,````` +M`````0`+````)),#``````````$`"P```%B3`P`````````!``L```#0DP,` +M`````````0`.````-)0#``````````$`"P```#B4`P`````````!``X```"@ +ME`,``````````0`+````I)0#``````````$`"P```-R4`P`````````!``L` +M``!$E0,``````````0`.````L!0```````````,`]0X``'`5``!``````0`# +M``$/``"P%0``'P````$``P`0#P``T!4``!$````!``,`'P\``.05```@```` +M`0`#`"X/```$%@``#@````$``P`]#P``%!8```@````!``,`3`\``!P6```8 +M`````0`#`%L/```T%@``%@````$``P!J#P``3!8``!8````!``,`>0\``&06 +M```3`````0`#`(@/``!X%@``$@````$``P"7#P``C!8``!$````!``,`I@\` +M`*`6```&`````0`#`+(/``"H%@``&`````$``P"^#P``P!8``!@````!``,` +MR@\``-@6```8`````0`#``X````<"```````````%@#6#P`````````````$ +M`/'_"P```+25`P`````````!`!L```#P%@```````````P`+````5)8#```` +M``````$`#@```'"7`P`````````!`.$/``#P%@``.P````$``P`.````\!8` +M``````````,`[0\``"P7```3`````0`#`/P/``````````````0`\?\+```` +MD)<#``````````$`#@```(B9`P`````````!``X```"8"P``````````%@`0 +M$``````````````$`/'_(Q```(R9`P!@`````@`!``L```",F0,````````` +M`0`+````[)D#``````````$`#@```*R;`P`````````!``L```"PFP,````` +M`````0`.````@)T#``````````$`"P```(2=`P`````````!``X```!$GP,` +M`````````0`.````8`X``````````!8`,A``````````````!`#Q_PL```!( +MGP,``````````0`.````.*$#``````````$`#@```&`8```````````6`$40 +M``````````````0`\?\.````0!<```````````,`6!``````````````!`#Q +M_PL````\H0,``````````0`+````1*$#``````````$`"P```$BA`P`````` +M```!`(<#``!@%0``````````!0""`P``6!4```````````4`#@```.RB`P`` +M```````!``L````0HP,``````````0`;````U%````````````,`<`<``,05 +M```````````%`'@#```@%0``````````!0!S`P``%!4```````````4`#@`` +M`,"G`P`````````!``L```#DIP,``````````0`.````O*H#``````````$` +M"P```."J`P`````````!``X````$K`,``````````0`+````)*P#```````` +M``$`"P```%2N`P`````````!``X```"XKP,``````````0`+````V*\#```` +M``````$`#@````BQ`P`````````!``L````HL0,``````````0#=#@``4!<` +M``````````4`UPX``$P7```````````%``X```!0L@,``````````0`+```` +M<+(#``````````$`#@```("S`P`````````!``L```"@LP,``````````0`. +M````!+4#``````````$`"P```"2U`P`````````!``X```!$M@,````````` +M`0`+````9+8#``````````$`:1```-@7```````````%`&\0``#0%P`````` +M````!0`.`````+H#``````````$`"P```"BZ`P`````````!``X```"$O@,` +M`````````0`+````L+X#``````````$`#@```&3&`P`````````!``L```"D +MQ@,``````````0`.````L-8#``````````$`"P````S7`P`````````!``L` +M``!0V`,``````````0`.````&.`#``````````$`"P```%C@`P`````````! +M``X```!@X0,``````````0`+````@.$#``````````$`#@```(CB`P`````` +M```!``L```"HX@,``````````0!U$````!P```````````4`>Q```%0<```` +M```````%``X```",\0,``````````0`+````S/$#``````````$`@1```,@= +M```````````%``X````,_@,``````````0`+````5/X#``````````$`#@`` +M`$C_`P`````````!``L```!H_P,``````````0"'$```Y!\```````````4` +M#@```*P/!``````````!``L````<$`0``````````0"-$```U%```!8````! +M``,`G!```.Q0```"`````0`#``X```#L4````````````P"H$```\%```!P` +M```!``,`MQ````Q1```8`````0`#`,80```D40``&P````$``P#5$```0%$` +M`!8````!``,`Y!```%A1```7`````0`#`/,0``!P40``$@````$``P`"$0`` +MA%$``!(````!``,`$1$``)A1```0`````0`#`"`1``"H40``&0````$``P`O +M$0``Q%$``!@````!``,`/A$``-Q1```8`````0`#`$T1``#T40``%`````$` +M`P!<$0``"%(``!`````!``,`:Q$``!A2```4`````0`#`'H1```L4@``&``` +M``$``P")$0``1%(``!8````!``,`F!$``%Q2``!``````0`#`*01``"<4@`` +M$`````$``P"P$0``K%(``"0````!``,`O!$``-!2```6`````0`#`,L1``#H +M4@``)`````$``P#7$0``#%,``!8````!``,`YA$``"13```8`````0`#`/41 +M```\4P``'@````$``P`!$@``7%,``!X````!``,`#1(``'Q3```O`````0`# +M`!P2``````````````0`\?\+````L!$$``````````$`#@````P3!``````` +M```!``L````L$P0``````````0`.````:!0$``````````$`"P```(@4!``` +M```````!``X```!,%00``````````0`+````;!4$``````````$`#@```"@6 +M!``````````!``L```!(%@0``````````0`+````]!8$``````````$`#@`` +M`,`7!``````````!``L```#@%P0``````````0`.````K!@$``````````$` +M,1(``*Q3```7`````0`#`$`2``#$4P``'@````$``P!/$@``Y%,``!<````! +M``,`7A(``/Q3```4`````0`#`&T2```05```&@````$``P!\$@``+%0``!H` +M```!``,`BQ(`````````````!`#Q_PL```#,&`0``````````0"B$@``J!D$ +M`&P!```"``$`"P```*@9!``````````!`!L```!(5````````````P`.```` +M]!H$``````````$`NQ(``!0;!`#0%````@`!``L````4&P0``````````0`. +M````""L$``````````$`"P```*`K!``````````!`)X```!4.``````````` +M&``+````Y"\$``````````$`#@```,PP!``````````!``L```#L,`0````` +M`````0`.````W#$$``````````$`"P```/PQ!``````````!``X```#L,@0` +M`````````0`+````##,$``````````$`#@```/PS!``````````!``L````< +M-`0``````````0`.````_#0$``````````$`"P```!PU!``````````!``X` +M``#D-00``````````0`+````!#8$``````````$`TA(``"0J```````````% +M`'@#```()0``````````!0!S`P``_"0```````````4`#@```"@Y!``````` +M```!``L````X.00``````````0`.````C#\$``````````$`"P```,0_!``` +M```````!``L```#8/P0``````````0`.````\$`$``````````$`"P```#!! +M!``````````!``X```#T1`0``````````0#8$@``2%0```P````!``,`#@`` +M`$A4```````````#`.L2``!45```&0````$``P#Z$@``<%0``!<````!``,` +M"1,``(A4```<`````0`#`!@3``"D5```.`````$``P`J$P``W%0``(H````! +M``,`.!,``&A5```<`````0`#`$T3``"$50``.`````$``P!=$P``O%4``!P` +M```!``,`;Q,``-A5```3`````0`#`'X3``#L50``.`````$``P"/$P``)%8` +M`!$````!``,`GA,``#A6```%`````0`#`+,3``!`5@``%0````$``P#"$P`` +M6%8``!P````!``,`T1,``'16```=`````0`#`.`3``"45@``&`````$``P#O +M$P``K%8``!0````!``,`_A,``,!6```3`````0`#``T4``#45@``&@````$` +M`P`<%```\%8```8````!``,`)Q0``/A6```8`````0`#`#84```05P``'``` +M``$``P!%%```+%<``!8````!``,`#@```%0X```````````8`%04``!4.``` +M`0````$`&`!T%``````````````$`/'_"P```"!%!``````````!``L````D +M100``````````0`+````0$4$``````````$`"P```$A%!``````````!``L` +M``!,100``````````0`.````'$8$``````````$`"P```#Q&!``````````! +M`-@%``#`+```````````!0!P!P``U"P```````````4`@Q0``.@L```````` +M```%``X```#L300``````````0`+````'$X$``````````$`#@```$1/!``` +M```````!``L```!H3P0``````````0`.````^%$$``````````$`"P```!A2 +M!``````````!``X```#H4P0``````````0`+````"%0$``````````$`#@`` +M`%Q5!``````````!``L```!\500``````````0")%```%"X```````````4` +MZ0X```PN```````````%``X```#85@0``````````0"/%```1%<``!<````! +M``,`GA0``%Q7```1`````0`#`*T4``!P5P``&0````$``P#F$0``C%<``!@` +M```!``,`O!0``*17```5`````0`#`,L4``"\5P``%`````$``P#:%```T%<` +M`!T````!``,`Z10`````````````!`#Q_PL```#\5@0``````````0`.```` +M:%<$``````````$`"P```'A7!``````````!`/@4``````````````0`\?\. +M````>!L``````````!8`"14`````````````!`#Q_PL````<6`0````````` +M`0`+````*%@$``````````$`"P```#18!``````````!``L```!(6`0````` +M`````0`+````8%@$``````````$`"P```'18!``````````!``L```"$6`0` +M`````````0`+````B%@$``````````$`"P```(Q8!``````````!``L```"0 +M6`0``````````0`+````E%@$``````````$`"P```+!8!``````````!``L` +M``#,6`0``````````0`+````V%@$``````````$`"P```.18!``````````! +M``L```#T6`0``````````0`+````!%D$``````````$`"P```"!9!``````` +M```!``L```!,600``````````0`+````;%D$``````````$`"P```'19!``` +M```````!``L```!\600``````````0`+````E%D$``````````$`"P```*Q9 +M!``````````!``L```#$600``````````0`+````W%D$``````````$`"P`` +M`/A9!``````````!``L````46@0``````````0`+````,%H$``````````$` +M&14``$Q:!`"(`````@`!``L```!,6@0``````````0`+````U%H$```````` +M``$`"P```.Q:!``````````!``L````$6P0``````````0`B%0``-%L$`#`` +M```"``$`"P```#1;!``````````!`"L5``!D6P0`%`````(``0`+````9%L$ +M``````````$`"P```'A;!``````````!``L```!H7`0``````````0`+```` +M[%P$``````````$`"P```&Q=!``````````!`!L```!8.```````````&``+ +M````N%T$``````````$`"P````1>!``````````!``L```!07@0````````` +M`0`1````/"X```````````4`"P```'!>!``````````!``L```!\7@0````` +M`````0`+````B%X$``````````$`"P```+!>!``````````!``L```#<7@0` +M`````````0`+````Z%X$``````````$`"P```#!?!``````````!``L```!@ +M7P0``````````0`+````D%\$``````````$`%@```$@N```````````%``X` +M``"H7P0``````````0`+````K%\$``````````$`"P```,!?!``````````! +M``L```#,7P0``````````0`+````X%\$``````````$`"P```/1?!``````` +M```!``L`````8`0``````````0`+````Y&`$``````````$`"P```/!@!``` +M```````!``L````(800``````````0`+````&&$$``````````$`"P```$AA +M!``````````!``L```"D800``````````0`+````L&$$``````````$`"P`` +M`-AA!``````````!``L```#D800``````````0`+````%&($``````````$` +M#@```%@X```````````8`#45``!8.```2`````$`&`!&%0``H#@````````! +M`!@`4A4`````````````!`#Q_UT5``"$8@0`<`````(``0`+````A&($```` +M``````$`"P```/1B!``````````!``L```!$8P0``````````0`+````F&,$ +M``````````$`"P```%1D!``````````!``L````8900``````````0`+```` +M7&4$``````````$`"P```&!F!``````````!``L```#`9@0``````````0`+ +M````M&<$``````````$`"P```*AH!``````````!``L```#<:`0````````` +M`0`+````(&D$``````````$`&P```*`X```````````8`!8```",+@`````` +M````!0`.````[&L$``````````$`"P```/AK!``````````!`&\5``!$;`0` +M-`````(``0`+````1&P$``````````$`"P```'AL!``````````!`)X```#P +M5P```````````P!&`P``<"```````````!8`A<```Q:```5`````0`#`)07```D6@``%P````$``P"P%P``/%H` +M`!0````!``,`R1<``%!:```>`````0`#`.P7``!P6@``%@````$``P`'&``` +MB%H``!,````!``,`'Q@``)Q:```3`````0`#`#<8``"P6@``&`````$``P!4 +M&```R%H``!,````!``,`;!@``-Q:```3`````0`#`(08``#P6@``&`````$` +M`P"A&```"%L``!@````!``,`OA@``"!;```3`````0`#`-88```T6P``#@`` +M``$``P#I&```1%L``!0````!``,``AD````````$`````0`&``X````````` +M````````!@`0&0``["```"0````!`!8`#@```'`@```````````6`!\9```` +M````$`````$`"``.``````````````````@`.!D``!`````0`````0`(`%89 +M```@````$`````$`"`!M&0``,````!`````!``@`AQD``$`````0`````0`( +M`)X9``!0````$`````$`"`"R&0``8````!`````!``@`R1D``'`````0```` +M`0`(`-\9``"`````$`````$`"`#U&0``D````!`````!``@`"AH``*`````0 +M`````0`(`"$:``"P````$`````$`"``W&@``P````!`````!``@`5!H``-`` +M```0`````0`(`&P:``#@````$`````$`"`"`&@``\````!`````!``@`F1H` +M```!```0`````0`(`+(:```0`0``$`````$`"`#(&@``(`$``!`````!``@` +MX!H``#`!```0`````0`(`/4:``!``0``$`````$`"``4&P``4`$``!`````! +M``@`*QL``&`!```0`````0`(`#\;``!P`0``$`````$`"`!3&P``@`$``!`` +M```!``@`;!L``)`!```0`````0`(`(`;``"@`0``$`````$`"`"4&P``L`$` +M`!`````!``@`K1L``,`!```0`````0`(`,8;``#0`0``$`````$`"`#:&P`` +MX`$``!`````!``@`Z1L``/`!```0`````0`(`/X;``````````````0`\?\) +M'```)'$$`!P````"``$`"P```"1Q!``````````!``L```!`<00````````` +M`0`1````/"\```````````4`%@```(0O```````````%`!L````0(0`````` +M````%@`+````>'$$``````````$`&!P``(1Q!`"$`````@`!``L```"$<00` +M`````````0`G'```"'($`&`!```"``$`"P````AR!``````````!``X```!@ +M`0``````````0!;'```X'@$``P````"``$`"P`` +M`.!X!``````````!`&P<``#L>`0`9`(```(``0`+````['@$``````````$` +M1@,``%A;```````````#`'D<``"(>P0`5`$```(``0`.````2'L$```````` +M``$`"P```%![!``````````!``L```"(>P0``````````0"('```6%L``#`` +M```!``,`#@```%A;```````````#`)\<````````"`````$`"@`.```````` +M``````````H`QQP``#0````>`````0`.`.\<````````"`````$`#``.```` +M``````````````P`$QT````````:`````0`.`#<=```:````&@````$`#@!; +M'0``4@```!X````!``X`@QT``!`A``!T`````0`6``X````0(0`````````` +M%@"+'0``A"$``"@````!`!8`FAT````````(`````0`/``X````````````` +M````#P#"'0````````@````!`!$`#@`````````````````1`.8=```````` +M``````0`\?_T'0``W'P$`$`````"``$`"P```-Q\!``````````!`/X=```< +M?00`J`````(``0`+````''T$``````````$`$!X``,1]!``(`````@`!``L` +M``#$?00``````````0`@'@``S'T$`$P````"``$`"P```,Q]!``````````! +M`#`>```8?@0`&`````(``0`+````&'X$``````````$`0!X``#!^!``<```` +M`@`!``L````P?@0``````````0!/'@``3'X$`$P````"``$`"P```$Q^!``` +M```````!`%\>``"8?@0`'`````(``0`+````F'X$``````````$`;QX``+1^ +M!``<`````@`!``L```"T?@0``````````0"`'@``T'X$`!@````"``$`"P`` +M`-!^!``````````!`)$>``#H?@0`.`````(``0`+````Z'X$``````````$` +MH1X``"!_!``(`````@`!``L````@?P0``````````0"R'@``*'\$``@````" +M``$`"P```"A_!``````````!`+@>```P?P0`"`````(``0`+````,'\$```` +M``````$`U!X``#A_!``(`````@`!``L````X?P0``````````0#K'@``0'\$ +M``@````"``$`"P```$!_!``````````!``$?``!(?P0`"`````(``0`+```` +M2'\$``````````$`$!\``%!_!`!@`````@`!``L```!0?P0``````````0`+ +M````L'\$``````````$`"P```+1_!``````````!``L```"X?P0````````` +M`0`<'P``0(`$``@````"``$`"P```$"`!``````````!`"4?``!(@`0`A``` +M``(``0`+````2(`$``````````$`/!\``,R`!`#@`````@`!``L```#,@`0` +M`````````0`1`````#````````````4`11\``*R!!``H`0```@`!``L```"L +M@00``````````0!3'P``U(($`$0````"``$`"P```-2"!``````````!`!8` +M```$,```````````!0!B'P``&(,$`$`,```"``$`"P```!B#!``````````! +M`.T!```,,```````````!0!X`P``)#````````````4`AP,``#0P```````` +M```%`-@%``!(,```````````!0!S'P``7#````````````4`>1\``&0P```` +M```````%`-<.``!\,```````````!0#=#@``A#````````````4`XPX``*0P +M```````````%`(D4``"X,```````````!0!_'P``P#````````````4`:1`` +M`-0P```````````%`&X#```4,```````````!0"%'P``W#````````````4` +MBQ\``.0P```````````%`)$?``#P,```````````!0"7'P``^#`````````` +M``4`#@```"2/!``````````!`)T?``!8CP0`B`<```(``0`+````6(\$```` +M``````$`#@```+"6!``````````!`*X?``#@E@0`?`$```(``0`+````X)8$ +M``````````$`#@```&27!``````````!``L```"`EP0``````````0"]'P`` +M7)@$`#0````"``$`"P```%R8!``````````!`,T?``!D,0``````````!0#3 +M'P``D)@$`$@````"``$`"P```)"8!``````````!`.0?``#8F`0`U`$```(` +M`0`+````V)@$``````````$`]A\``'0Q```````````%`/P?``"LF@0```0` +M``(``0`+````K)H$``````````$`"2```(`Q```````````%``\@``"(,0`` +M````````!0`5(```E#$```````````4`&R```*`Q```````````%`"$@``"H +M,0``````````!0`G(```L#$```````````4`+2```*R>!``8`@```@`!``L` +M``"LG@0``````````0`Y(```O#$```````````4`/R```,0Q```````````% +M`$4@``#4,0``````````!0!+(```W#$```````````4`42```.PQ```````` +M```%`%<@``#X,0``````````!0!=(```'#(```````````4`8R```"0R```` +M```````%`&D@```P,@``````````!0!O(```/#(```````````4`=2```,2@ +M!``@`@```@`!``L```#$H`0``````````0"&(```Y*($`&P````"``$`"P`` +M`.2B!``````````!`)4@``!0HP0`X`H```(``0`+````4*,$``````````$` +MH2```%@R```````````%`*<@``!@,@``````````!0"M(```:#(````````` +M``4`=1```'@R```````````%`+,@``"$,@``````````!0"Y(```C#(````` +M``````4`>Q```)0R```````````%`+\@``"@,@``````````!0#%(```J#(` +M``````````4`RR```+`R```````````%`-$@``"X,@``````````!0#7(``` +MR#(```````````4`W2```-0R```````````%``X````HK@0``````````0#C +M(```,*X$`*@````"``$`"P```#"N!``````````!`/(@``#<,@`````````` +M!0#X(```V*X$`*P#```"``$`"P```-BN!``````````!``X````,KP0````` +M`````0`+````2*\$``````````$`!2$``(2R!``D`````@`!``L```"$L@0` +M`````````0`=(0``J+($`*@"```"``$`"P```*BR!``````````!`"TA``!0 +MM00`>`(```(``0`+````4+4$``````````$`/B$``,BW!`!8`0```@`!``L` +M``#(MP0``````````0"!$```Z#(```````````4`3"$``/`R```````````% +M`%(A``#X,@``````````!0!8(0```#,```````````4`7B$``""Y!`#X`0`` +M`@`!``L````@N00``````````0!M(0``&+L$`+`#```"``$`"P```!B[!``` +M```````!`(`A```(,P``````````!0`.````P+X$``````````$`AB$``,B^ +M!`!$`0```@`!``L```#(O@0``````````0`.````++\$``````````$`"P`` +M`#R_!``````````!`)DA```,,P``````````!0"?(0``%#,```````````4` +MI2$``!PS```````````%`*LA```,P`0`%`$```(``0`+````#,`$```````` +M``$`#@```#3`!``````````!``L```!@P`0``````````0"[(0``(,$$`!@$ +M```"``$`"P```"#!!``````````!``X```!\P@0``````````0`+````O,($ +M``````````$`#@```%C#!``````````!``L```"8PP0``````````0`;```` +MC%L```````````,`RB$``#C%!``8`````@`!``L````XQ00``````````0#< +M(0``4,4$`*@!```"``$`"P```%#%!``````````!`.PA``#XQ@0`5`$```(` +M`0`+````^,8$``````````$`#@```$C(!``````````!`/PA``!,R`0`-`$` +M``(``0`+````3,@$``````````$`#"(``"0S```````````%`!(B```T,P`` +M````````!0"'$```1#,```````````4`&"(``%0S```````````%`!XB``!D +M,P``````````!0`D(@``=#,```````````4`[PX``(0S```````````%`"HB +M``"4,P``````````!0`P(@``I#,```````````4`-B(``(#)!`!``0```@`! +M``L```"`R00``````````0">````K"$``````````!8`1R(``,#*!`!T```` +M`@`!``L```#`R@0``````````0!7(@``-,L$`)0+```"``$`"P```#3+!``` +M```````!`&8B``"T,P``````````!0!L(@``R#,```````````4`!``````````!``L```"TW@0````````` +M`0`.````P.H$``````````$`"P```-3J!``````````!`.,B``"LZP0`H`$` +M``(``0`+````K.L$``````````$`[B(``.PS```````````%`/0B``#T,P`` +M````````!0#Z(@``_#,```````````4``",``$SM!`"X`0```@`!``L```!, +M[00``````````0`1(P``!.\$`-@"```"``$`"P````3O!``````````!``X` +M``#8\00``````````0`A(P``W/$$`'@$```"``$`"P```-SQ!``````````! +M``X```!0\P0``````````0`+````L/,$``````````$`,2,````T```````` +M```%`#@C```(-```````````!0`_(P``$#0```````````4`1B,``!PT```` +M```````%`$TC```@-```````````!0!4(P``,#0```````````4`6R,``%@T +M```````````%`&(C``!@-```````````!0!I(P``9#0```````````4`<",` +M`&@T```````````%`'`````$` +M%@`5)``````````````$`/'_"P```"#X!``````````!``L````X^`0````` +M`````0`+````6/@$``````````$`"P```&CX!``````````!``L```!L^`0` +M`````````0`+````Z/D$``````````$`"P```/SZ!``````````!``L```"` +M^P0``````````0`+````V/L$``````````$`"P```/S[!``````````!``L` +M``!(_`0``````````0`+````P/P$``````````$`(B0`````````````!`#Q +M_PL````<_00``````````0`+````D/T$``````````$`"P````3^!``````` +M```!``L```!H_@0``````````0`+````D/X$``````````$`"P````3_!``` +M```````!``L````0_P0``````````0`+````'/\$``````````$`"P```"C_ +M!``````````!`!L````0.0``````````&``+````,``%``````````$`$0`` +M`'`T```````````%`!8```"$-```````````!0#M`0``C#0```````````4` +M"P```#P!!0`````````!``L```!L`04``````````0`.````O`$%```````` +M``$`"P```,`!!0`````````!``L``````@4``````````0`+````*`(%```` +M``````$`"P```#0"!0`````````!``X````0.0``````````&``O)```$#D` +M```$```!`!@`/R0`````````````!`#Q_PL```!``@4``````````0`+```` +M2`(%``````````$`"P```%P"!0`````````!``L```!@`@4``````````0`+ +M````9`(%``````````$`"P```(P"!0`````````!``L```"8`@4````````` +M`0`+````[`(%``````````$`"P```'@$!0`````````!``L```#)@``G`D%`"`````"``$`"P```)P)!0`````````! +M``X```"X"04``````````0`S)@``O`D%`"`````"``$`"P```+P)!0`````` +M```!``X```#8"04``````````0!;)@``W`D%`!P````"``$`"P```-P)!0`` +M```````!``X```#T"04``````````0"&)@``^`D%`"`````"``$`"P```/@) +M!0`````````!``X````4"@4``````````0"D)@``&`H%`"`````"``$`"P`` +M`!@*!0`````````!``X````T"@4``````````0#!)@``.`H%`*`````"``$` +M"P```#@*!0`````````!``X```#0"@4``````````0`+````V`H%```````` +M``$`````3",``````````!8`#@```,@-!0`````````!`"@G``#<#04`:``` +M``(``0`+````W`T%``````````$`#@```#P.!0`````````!`$XG``!$#@4` +M3`````(``0`+````1`X%``````````$`#@```(@.!0`````````!`&(@``H#T```````````4`#@```#!+!0`` +M```````!`.```>`````0`#`$(I``!07@``&`````$``P!1*0``:%X``!<` +M```!``,`8"D``(!>```8`````0`#`&\I``"87@``&0````$``P!^*0``M%X` +M`!@````!``,`C2D``,Q>```:`````0`#`)PI``#H7@``'`````$``P"K*0`` +M!%\``!D````!``,`NBD``"!?```8`````0`#`,DI```X7P``'0````$``P#8 +M*0``6%\``!4````!``,`YRD``'!?```5`````0`#`/8I``"(7P``*`````$` +M`P`%*@``L%\``"L````!``,`%"H``-Q?```>`````0`#`",J``#\7P``'0`` +M``$``P`R*@``'&```!L````!``,`02H``#A@```8`````0`#`%`J``!08``` +M%P````$``P!?*@``:&```!<````!``,`;BH``(!@```>`````0`#`'TJ``"@ +M8```#P````$``P",*@``L&```"@````!``,`#@```+1@```````````#`*TJ +M``#88```$`````$``P"_*@``Z&```"8````!``,`SBH``!!A```9`````0`# +M`-TJ```L80``&`````$``P#L*@``1&$``!4````!``,`^RH``%QA```=```` +M`0`#``HK``!\80``&P````$``P`9*P``F&$``!D````!``,`*"L``+1A```$ +M`````0`#`#0K``"X80``&`````$``P!#*P``T&$``!D````!``,`4BL``.QA +M```9`````0`#`&$K```(8@``&`````$``P!P*P``(&(``!@````!``,`?RL` +M`#AB```%`````0`#`(HK``!`8@``"0````$``P"5*P``3&(``!4````!``,` +MI"L``&1B```<`````0`#`+,K``"`8@``&@````$``P#"*P``G&(``!X````! +M``,`T2L``+QB```<`````0`#`.`K``#88@``@`````$``P#\*P``6&,``",` +M```!``,`"RP``'QC```A`````0`#`!HL``"@8P``)0````$``P`I+```R&,` +M`"4````!``,`."P``/!C```C`````0`#`$`0`(```` +M$@`!`*TO```0EP````(``!(``0#4+P`````````````0````W2\``-PG``!\ +M````$@`!`/(O``!TIP(`E`$``!(``0`(,```N!,``*0````2``$`&3```)A; +M`0`(````$@`!`"8P```LU@(`)````!(``0`],```;``!`&@````2``$`23`` +M`-0O`0`,`@``$@`!`&4P``!XV00`6````!(``0"!,```:*8"``0````2``$` +MCC```"RA`0`\````$@`!`)TP``#T;P$`,````!(``0"X,```!``H````$@`!`%8U```D30(`(``` +M`!(``0!I-0``*,L``%@````2``$`?#4```@```!\````$@`!`(LU``!,A0$` +M#````!(``0"A-0``_%@!`'`````2``$`M#4``#B4`P!L````$@`!`-4U``"D +MW@$`2````!(``0#P-0`````````````0````_#4``.`7!`#L````$@`!`!8V +M``!8^`0`$````!(``0`G-@``0'$$`#@````2``$`138`````````````$``` +M`%(V``#T>@(`)````!(``0!J-@`````````````0```````I````!(``0`Y-P``:+\!``@"```2``$`3#<` +M`.`T`P`<````$@`!`&@W``#<600`'````!(``0!Z-P``J#T"`!P````2``$` +MBS<``'".`0"X`0``$@`!`)PW```8HP$`"````!(``0"L-P``?(D``$@````2 +M``$`Q3<`````````````$````,XW``#,!`,`!````!(``0#G-P``_/L$`$P` +M```2``$``3@`````````````$`````HX```X:P(`>````!(``0`C.```A'D` +M`"P````2``$`-C@``!1K`@`D````$@`!`$@X``#X2@``(````!(``0!4.``` +M5!0```$````1`!@`8C@``"P_`0"4`0``$@`!`'`X``!<900`!`$``!(``0"` +M.```J%H!`#0````2``$`CS@``)!8!``$````$@`!`*(X``#T7P0`#````!(` +M`0"N.```'/\$``P````2``$`P#@``&P!!0!4````$@`!`-HX``"((```!``` +M`!$`%@#J.``````````````0`````3D``+!>!``L````$@`!``\Y``!XGP`` +M@````!(``0`G.0``7"4!`"0%```2``$`/#D``.SR``!\````$@`!`$PY```4 +M00,`3````!(``0!G.0``7`T"`+@````2``$`=SD```!``P`$````$@`!`(LY +M```0Q0(`A````!(``0"@.0``W)0#`&@````2``$`KSD``-`\`@`<````$@`! +M`+LY``!8*`````0``!$`&`#..0``P'4``#0````2``$`V#D``!1B!`!P```` +M$@`!`.LY`````````````!````#].0``M)4#`*`````2``$`&3H``#A<`0`D +M````$@`!`#@Z`````````````!````!;.@``N'L!`)0````2``$`;CH``,"9 +M``",`@``$@`!`(@Z``#0!0```P```!$`%@"6.@``2+@``!P````2``$`ISH` +M``@]`@`<````$@`!`+!L``%@````1`!8`ZCP``)BD```X````$@`!`/X\ +M```HL0,`2`$``!(``0`0/0`````````````0````)#T``,P@```$````$0`6 +M`#(]``"@K0(`7````!(``0!(/0``A%P!`!P````2``$`6ST``#@.``"P```` +M$@`!`&\]``!H(0``M`$``!(``0""/0``8%<#`&0'```2``$`HCT``/PT`P"4 +M`0``$@`!`+T]``"P%```P````!$``P#-/0``+$X``&P````2``$`W3T``/A% +M`@"8!0``$@`!`/0]``!()P,`-````!(``0`!/@``J-\``*@!```2``$`%#X` +M`$A%!``$````$@`!`"H^``#0I```#````!(``0`]/@``B%L```0````1``,` +M3#X``$C\!`!X````$@`!`&<^``",`0``G````!(``0"'/@``E)D!`*`````2 +M``$`H3X``,@5``"@````$@`!`+(^``"LJ`$`<````!(``0#(/@``[(\#`!@` +M```2``$`X3X``.Q``@"(````$@`!```_`````````````!`````#/P``\`0` +M`!`````1`!8`#S\``%2N`P"$`0``$@`!`"4_``#`0`$`]````!(``0`P/P`` +MV"D#`$P````2``$`1S\``/PX```$````$0`8`%8_``#,:@(`"````!(``0!X +M/P``/*$#``@````2``$`C3\``/@!``#X`0``$0`6`)X_````00,`!````!(` +M`0"U/P``>(`"`%@````2``$`TS\``+P&`P"4````$@`!`.T_``",K0$`,``` +M`!(``0`50```W%@!`"`````2``$`*4```#18!``4````$@`!`#M````'$$``P````2``$` +M`D(``!`G`P`(````$@`!`!%"```8900`1````!(``0`@0@``0!<``)0Y```1 +M``,`,T(``*2Y``"D`P``$@`!`$%"``"P;```:````!(``0!-0@`````````` +M```0````4T(``/!1!0`H`P``$@`!`&A"``!H3P0`L`(``!(``0"`0@``A*T` +M`#0````2``$`CT(``%R``@`<````$@`!`*M"``!T+0(`5````!(``0#$0@`` +MX%\$`!0````2``$`T$(``.BO```<`0``$@`!`.)"```81@,`F`\``!(``0`! +M0P``7!8!`/0#```2``$`#4,``"!T`P`4"```$@`!`"-#``#L/P,`!````!(` +M`0`X0P``)#T"`!P````2``$`2D,`````````````$````%Q#``"4IP$`N``` +M`!(``0!Q0P``>`0%`&0!```2``$`B4,``"23`P`T````$@`!`*%#```DD0$` +M>````!(``0"]0P``$`0```0````1`!8`TT,``#`^`@`@````$@`!`/-#``#< +MI```U````!(``0`'1```Q%D$`!@````2``$`$D0``.BA`0`(`0``$@`!`"9$ +M``#4;@(`C````!(``0!`1```M%<``'`````2``$`7$0``.@1`P`@````$@`! +M`'5$``"080(`/````!(``0"#1```S#D#`&@!```2``$`DT0``*"H```(```` +M$@`!`)Q$``!4K`$`[````!(``0"O1```X&\``$0````2``$`N$0``-`<``"H +M````$0`6`-)$```L^P``0`4``!(``0#?1```3)P``&`"```2``$`_40``"PD +M```,````$@`!``]%```<_00`=````!(``0`O10``%'`"`$@````2``$`144` +M`*!1`0`$`@``$@`!`$Y%``#L&0``+`(``!(``0!>10``<)`#`#@"```2``$` +M=44``+RG``!X````$@`!`(9%``#T004`Z````!(``0"M10``!"\"`"@````2 +M``$`OD4``(0@```$````$0`6`,U%```0HP,`U`0``!(``0#I10``(*,!``0! +M```2``$`^44``(!T`@`,````$@`!``M&``"4LP$`H`(``!(``0`N1@``=!,! +M`.@"```2``$`0$8``,@L`@`L````$@`!`%!&``#4#`$`P````!(``0!O1@`` +MH%L!`#`````2``$`BD8``.1,```D````$@`!`)Q&``!(2```Q````!(``0"L +M1@``>&\``&@````2``$`N$8``"Q'!0"(````$@`!`-A&``"X)P,`&````!(` +M`0#J1@``F(<#`*0!```2``$`_T8``,![``",`0``$@`!`!5'``#8#P``E``` +M`!(``0`K1P``Z)H!`%`````2``$`1$<`````````````$````%]'``#4Z@0` +MV````!(``0!P1P``E"````0````1`!8`@4<``$PH`P`0````$@`!`(Y'``"0 +M6`$`3````!(``0"D1P``3'H``'0!```2``$`MD<``&!F!`!@````$@`!`,M' +M``"L.```!````!$`&`#<1P``!%L$`#`````2``$`_4<```25`@`$````$@`! +M`!1(``#D800`,````!(``0`B2```9+@``"`````2``$`-$@``&P0``"P```` +M$@`!`$A(``!\600`&````!(``0!32```'*,"`$`#```2``$`<4@``*`@```$ +M````$0`6`'Y(```4+`(`6````!(``0"<2```T&0!`!0````2``$`K$@``.@X +M```$````$0`8`+I(``"H9P$`6````!(``0#,2```B%@$``0````2``$`W$@` +M````````````$````/)(```,,P0`$`$``!(``0`*20``O-H``.0````2``$` +M&$D``%B8`@`@`0``$@`!`#-)``!D;P(`!````!(``0!020``L`L!`"0!```2 +M``$`7DD``#`$```$````$0`6`'Y)````````!````!(``0"120``2+`!`$P# +M```2``$`I$D``*@=``"<````$@`!`+5)``!@7P0`,````!(``0#%20``Y&0! +M`$@````2``$`UDD``*BH``!\````$@`!`.1)``#4!```!````!$`%@#L20`` +M<'`!`"0!```2``$``DH``-3:`0#T````$@`!`!9*```P9`$`5````!(``0`H +M2@```"D#``@````2``$`8TH``+!'`0#P"0``$@`!`&Y*``#\`P``!````!$` +M%@"$2@``+`0```0````1`!8`FTH``-`$```$````$0`6`*=*```\80``*``` +M`!(``0"U2@``R"T"`"0````2``$`STH``+"$`0"<````$@`!`.-*```L`0`` +M4````!(``0#T2@``./@$`"`````2``$`!DL``)P````H````$@`!`!]+```` +M:`$`E````!(``0`W2P``!%L!`!P````2``$`14L``%!P`0`@````$@`!`%M+ +M``#\/P,`!````!(``0!N2P``B-,``$@!```2``$`A4L``/QU```$````$@`! +M`*!+``#\?P(`&````!(``0"Q2P``5(H``%@````2``$`RDL``$1G`0`$```` +M$@`!`-U+```P!```7````!(``0#V2P`````````````0````_$L``%"S`@`( +M`@``$@`!`!%,``"830``<````!(``0`C3```?%4$`(`!```2``$`0$P``)AY +M`0"<````$@`!`$Q,``!07@0`(````!(``0!B3```C"@#`!`````2``$`<4P` +M`/A9!``<````$@`!`(-,``!<*`,`$````!(``0"13``````````````0```` +MH$P``!P1``"4````$@`!`+!,``!T6`0`$````!(``0"_3```R&@!`#0````2 +M``$`SDP``+QJ`0#D````$@`!`.-,``"@YP$`8`$``!(``0#R3```E,4"`$0& +M```2``$`!DT``$Q``P"T````$@`!`!--``"8;@``X````!(``0`B30``]&($ +M`%`````2``$`-4T``,@@```$````$0`6`$I-```D,P$`C`8``!(``0!@30`` +M/`$%`#`````2``$`>TT``$1W!`!L`0``$@`!`(I-``!8)`````0``!$`&`"9 +M30`````````````0````J4T``.S_`0`8`0``$@`!`,)-``",60$`4````!(` +M`0#/30``[(L"`'0!```2``$`Y4T```20`P`D````$@`!`/I-``!TC0``<`(` +M`!(``0`53@``)*D``!0````2``$`(4X``'P_`P`$````$@`!`#U.```````` +M`````!````!73@``"&$$`!`````2``$`8TX``/`%```#````$0`6`'%.``#@ +M!`!(````$@`!`-U/``",;P(`!````!(``0#U3P``]%H``.P!```2``$` +M"5```(#[!`!8````$@`!`!U0`````````````!`````N4```V&```!P````2 +M``$`/E```*0^`P`<````$@`!`$Q0`````````````!````!=4```Q(D```P` +M```2``$`=5```+!K`@#@`@``$@`!`(A0``!XS@``;`,``!(``0"84```C(0` +M`)0````2``$`JE```"B>`0!H````$@`!`,-0``"<*`,`$````!(``0#14``` +M[`0#`"@````2``$`Y5```*"9`@#8`0``$@`!`/]0``!U(``.0O!``(`0`` +M$@`!`)!2```TF`(`)````!(``0"O4@``L!$$`'P!```2``$`QE(``-`E`P`$ +M`0``$@`!`-A2``",S0$`H````!(``0#J4@``,%$%`#P````2``$``E,``!A+ +M```@````$@`!``Y3``"DQ@,`K!$``!(``0`>4P`````````````0````*E,` +M````````````$````#13`````````````!````!$4P``+"H#`#@'```2``$` +M95,``(!,`@"D````$@`!`')3``#8(```!````!$`%@"!4P``N"````0````1 +M`!8`CU,``/06!`#L````$@`!`*E3``"\@@(`E````!(``0"]4P``4(<``*0` +M```2``$`RE,``$Q\`0!@`0``$@`!`.13``"`+`(`%````!(``0#Y4P``W$(# +M`$@"```2``$`!U0``+@_`P`$````$@`!`"E4``!X<`,`J`,``!(``0!!5``` +M+'\``(0!```2``$`550``+!A!``H````$@`!`&54```P6@0`'````!(``0!W +M5```@#\#``0````2``$`D%0``,@R`@!T````$@`!`*94``"\(```K````!(` +M`0"Z5```M"L"`&`````2``$`V50``$"``@`<````$@`!`/14``"("0``"`$` +M`!$`%@`+50``6#@"`+`````2``$`'E4``.C[`0`$!```$@`!`#]5``"LH``` +M#`(``!(``0!:50`````````````0````:54``*A"`0"D`0``$@`!`'15``#D +M)P,`&````!(``0"'50``[%H$`!@````2``$`E54``*!6`0!X`0``$@`!`*A5 +M``"P50,`L`$``!(``0"Y50``6$,"`%@````2``$`U%4``+`Y`0!\!0``$@`! +M`.15``#,=`0`6````!(``0`"5@``Y(\``"0%```2``$`'E8````````````` +M$````#)6``"\10(`/````!(``0!.5@``C*L```@````2``$`6E8``(A0``"` +M````$@`!`'16```P``4`#`$``!(``0"&5@``8$$#`!@````2``$`E58````` +M````````$````*96`````````````!````"U5@``-`,"`-@$```2``$`S58` +M`(2=`P#$`0``$@`!`/!6``"4600`&````!(``0#[5@``3`4```P````2``$` +M#U<``-S"``#T`0``$@`!`"Y7``#0)P,`%````!(``0`]5P``P#\%`'0````2 +M``$`75<```1>!`!,````$@`!`'57``!(H`$`Y````!(``0!_5P``?*<```@` +M```2``$`BE<``(0````0````$@`!`)I7``!(GP,`]`$``!(``0"\5P``;*@` +M`#0````2``$`S%<``&CX!``$````$@`!`.97``"DE`,`.````!(``0#]5P`` +MY`4```,````1`!8`!U@``.C"`0`8````$@`!`!U8``#@/0(`%````!(``0`L +M6```^"@#``@````2``$`9E@``)`4`P#`````$@`!`'U8``"X?@$`+`(``!(` +M`0"/6```&$`#``0````2``$`L%@``%1D!`#$````$@`!`,%8``"@>0(`>``` +M`!(``0#76```S%@$``P````2``$`YU@``&P5!`#<````$@`!`/M8``!LGP`` +M#````!(``0`,60``3$0!`&0#```2``$`$UD``'S2```,`0``$@`!`!Y9```` +M`````````!`````L60``X#$!`$0!```2``$`-UD``+`1``"4````$@`!`$E9 +M``!@%`````0``!$`%@!@60``V,D``%`!```2``$`<%D``$AF`0#\````$@`! +M`']9``"@;P$`(````!(``0"560``A)D``#P````2``$`KED``%`X```H`@`` +M$@`!`+]9``"(LP``P`0``!(``0#060``1$`#``0````2``$`ZUD``#R)`P"H +M`0``$@`!`/Y9``!(7P``>````!(``0`76@`````````````0````(EH``$Q, +M`@`T````$@`!`"Q:``!X9P$`'````!(``0`X6@``)`8#`%P````2``$`2%H` +M`/PF`P`$````$@`!`%E:``"T?P0`!````!(``0!E6@``A(\#`&@````2``$` +M@%H``/S?`0`<`0``$@`!`)5:`````````````!````"B6@``Y'<"`#P````2 +M``$`M5H``%@L````!```$0`8`,A:``"$IP``.````!(``0#76@``\*(!`"@` +M```2``$`[UH``*"S`P"$`0``$@`!`/]:```$#0``G````!(``0`46P``S)70``Y)0"`"`````2``$`-%T``&00`P!T +M`0``$@`!`$==```0F0``=````!(``0!<70`````````````0````;UT````` +M````````$````'A=``"$9`$`3````!(``0".70``!`0```0````1`!8`I%T` +M````````````$````+5=``",`@4`#````!(``0#:70``M`4```8````1`!8` +MYUT``/18!``0````$@`!`/Q=``"8`@4`5````!(``0`-7@``'$P``"@````2 +M``$`(EX``!0$```$````$0`6`#E>```8+0(`%````!(``0!,7@``6"P``&0` +M```1`!8`85X``!AA!``P````$@`!`&Y>``#\!0``!````!$`%@!^7@``K%D$ +M`!@````2``$`B5X``#C<`0!L`@``$@`!`)U>```D/@,`@````!(``0"]7@`` +MV`4#`$P````2``$`S5X``&PG`@`0`@``$@`!`.!>```(N0``G````!(``0#R +M7@`````````````0````^UX``#Q$`@`D````$@`!`!=?`````````````!`` +M```I7P``P&\!`#0````2``$`1E\``&`"!0`$````$@`!`%I?``!P7@0`#``` +M`!(``0!G7P``?*L``!`````2``$`=5\``+A_!`"(````$@`!`(%?``!0@P(` +M1````!(``0"87P``<+(#`#`!```2``$`JE\``&PE`P!D````$@`!`+Q?```H +M_P0`"`$``!(``0#37P`````````````0````W5\```#"``!`````$@`!`/!? +M`````````````!````#]7P``)'X!`)0````2``$`$V```$1C!`!4````$@`! +M`"1@```\=@``!````!(``0`]8```M!X!`)P#```2``$`6F````0G`P`$```` +M$@`!`&]@``#86`0`#````!(``0"`8```=$T``"0````2``$`C&```-QH!`!$ +M````$@`!`*)@`````````````!````"_8```.)L!`)P!```2``$`T&```*AH +M!``T````$@`!`.5@```4#@(`/`(``!(``0#T8```((4```P````2``$`!6$` +M`-"``@!8````$@`!`"1A``"LG@``P````!(``0`V80``'*<``&`````2``$` +M/V$``,`!!0!`````$@`!`%=A``!0BP(`@````!(``0!O80``P+8!`$0!```2 +M``$`?6$```3_!``,````$@`!`(YA```0404`(````!(``0"K80`````````` +M```0````PV$``%![!``X````$@`!`-9A``"D.P(`V````!(``0#D80`````` +M```````0````[V$``$`]`@!`````$@`!`/QA`````````````!`````%8@`` +M//$!`+P!```2``$`)&(`````````````$````#=B``!,J`$`,````!(``0!4 +M8@``G$P``"0````2``$`9V(``'`O`@"0````$@`!`'IB``"P6`0`'````!(` +M`0"+8@``2&(#`#`.```2``$`DV(``!2``@`L````$@`!`*5B``"0EP,`_`$` +M`!(``0#%8@`````````````0````U6(``'@=``"H````$0`6`.MB``!(ZP$` +MG`(``!(``0#]8@``@&<``&P!```2``$`#6,``'A+```@````$@`!`!HM``"L +M(0``,````!$`%@`<8P``[&@``/0````2``$`+6,``-`@```$````$0`6`#YC +M``#0B0$`N`,``!(``0!78P``+&0``*`"```2``$`FD``!`Q`@"P````$@`!`(MI``#T=0`` +M"````!(``0"F:0``^#\#``0````2``$`O&D`````````````$````,-I```` +M"0``B````!(``0#4:0`````````````0````VVD``+1G!`#T````$@`!`.MI +M``"<4`4`=````!(``0`!:@`````````````0````#FH``&"-`@!``0``$@`! +M`"5J``"4,`(`?````!(``0`V:@``:%P$`(0````2``$`3&H``*11!0!,```` +M$@`!`&9J```D100`'````!(``0!Z:@`````````````0````B6H``)BI`0"4 +M````$@`!`)MJ``"0(```!````!$`%@"I:@`````````````0````NFH``"!% +M!``$````$@`!`,]J```,.0``!````!$`&`#=:@``'$4"`#`````2``$`ZVH` +M`!@^!0!8````$@`!``UK``"L*`,`$````!(``0`;:P``!-\!`/@````2``$` +M*6L``&2F`@`$````$@`!`#5K```8>@(`W````!(``0!%:P``&$4"``0````2 +M``$`66L``$B]``"<`@``$@`!`&AK``#`0`(````$@`!``=O``"@<0(`0````!(``0`D;P`````````````0 +M````*V\``'PI`@!``0``$@`!`#MO``!X00,`J````!(``0!&;P``S&8``+0` +M```2``$`76\``)A.``"$`0``$@`!`'9O``!D`@4`*````!(``0"*;P``_&,` +M`#`````2``$`FV\``%@<`````0``$0`8`*QO``"XK0``E````!(``0#$;P`` +MV!$#`!`````2``$`V&\``*RR``!0````$@`!`/)O``#8`0` +M,````!(``0`A=```9'@```0````2``$`2W0``%C@`P`H`0``$@`!`&-T``!H +M;P(`)````!(``0!V=```N#@```0````1`!@`@G0```19!``<````$@`!`)1T +M````8`0`Y````!(``0"F=```"'8``#`````2``$`MW0``!R0`@#4````$@`! +M`-%T``"@90$`%````!(``0#A=```E`````@````2``$`[G0``.`@```$```` +M$0`6`/UT`````````````!`````5=0``]`4```8````1`!8`)'4``"B$``!D +M````$@`!`#!U```L%0``G````!(``0!!=0``?&$!`)P````2``$`3'4``#AV +M```$````$@`!`&AU``#0B@(`@````!(``0!]=0``K%\$`!0````2``$`C'4` +M`+P@```$````$0`6`)UU``#4``$`W`H``!(``0"S=0``O*4``$0````2``$` +MUW4``"@"!0`,````$@`!`/%U`````````````!````#X=0`````````````0 +M`````78``.AA``!<````$@`!`!9V``!@6`0`%````!(``0`K=@``W%X$``P` +M```2``$`.78``(@)```0````$@`!`$EV``!T(```!````!$`%@!5=@``U#@` +M``0````1`!@`9W8``,"+``!8`0``$@`!`(%V``!\)P,`#````!(``0".=@`` +MH`T``)@````2``$`F78``!PT!````0``$@`!`*UV``"$<```/`$``!(``0"\ +M=@``@,,"`)`!```2``$`T78``,0]`@`<````$@`!`.)V``"X700`3````!(` +M`0#S=@``!`````0````2``$`!7<``,0'``!8````$0`6`"5W```````````` +M`!`````M=P``S'H!`$0````2``$`.G<``$P$``"$````$0`6`$=W```8)P,` +M$````!(``0!7=P``K#0%`.P$```2``$`=G<``&!$`@!\````$@`!`))W``#@ +M<0(`W`$``!(``0"E=P``,&X!`#0````2``$`N7<``#A``P`,````$@`!`-%W +M``"0"@``"`$``!$`%@#D=P``Z-L!`%`````2``$`_'<``#27`0"8````$@`! +M`"!X``#P/P,`!````!(``0`W>```\&`$`!@````2``$`0W@``.PM`@`8`0`` +M$@`!`%1X``!D\`$`4````!(``0!H>```5/X#`!0!```2``$`@'@``#PH`P`0 +M````$@`!`(YX``!``@4`"````!(``0"H>```T#@```0````1`!@`NG@``$RN +M``"<`0``$@`!`--X``"\/P,`!````!(``0#O>```O#@```0````1`!@`!'D` +M````````````$`````QY```X:@$`1````!(``0`<>0``)%@``"`!```2``$` +M/WD``%@4`````@``$0`8`%!Y`````````````!````!<>0``*"<#`"`````2 +M``$`<'D``*#B``#8!P``$@`!`']Y``!H#```G````!(``0".>0``[%8``#P` +M```2``$`L7D``"#X!``8````$@`!`,-Y```(5`0`=`$``!(``0#7>0``V$H` +M`"`````2``$`XGD````G`P`$````$@`!`/-Y```$0`,`!````!(``0`*>@`` +MF`L``,@"```1`!8`'GH``/SZ!`"$````$@`!`#-Z``"07P0`'````!(``0!# +M>@``V#\$`$@%```2``$`7WH``(`@```$````$0`6`&QZ``#P'P``@````!$` +M%@"$>@``_*\"`*@!```2``$`DWH``)@@```$````$0`6`*!Z``#`3```)``` +M`!(``0"S>@``<,4``+P````2``$`R'H``)@)```(`@``$@`!`-=Z``#`90$` +M$````!(``0#D>@``H"<#``P````2``$`]WH``-1J`@`(````$@`!``Y[``!$ +M=@``N````!(``0`@>P``)'```&`````2``$`+GL`````````````$````#1[ +M```<3@0`3`$``!(``0!->P`````````````0````9'L``)#^!`!T````$@`! +M`'A[``#0-@``@`$``!(``0")>P``H&L!`*`!```2``$`F'L``&Q1!0`X```` +M$@`!`+-[```P`````````````0````TGL``"2D`0`\ +M````$@`!`.=[`````````````!````#T>P``G,<``.0````2``$`"'P````` +M````````$````!=\``!T7@$`>`$``!(``0`E?```8#D#`&`````2``$`0GP` +M`'Q>!``,````$@`!`%!\``#L)@,`!````!(``0!D?```]#T"`#P````2``$` +M?7P```P$```$````$0`6`)5\`````````````!````"D?```Q#\$`!0````2 +M``$`NGP``%@6````!@``$0`8`,U\``#$Z@``,`0``!(``0#;?```Y-$``)@` +M```2``$`YGP``"#5```,`0``$@`!`/-\``#,*`,`+````!(``0`,?0``?!0# +M`!0````2``$`(GT`````````````$````"M]``"P!0``!````!$`%@`S?0`` +MV`0```0````1`!8`.WT``%Q<`0`H````$@`!`$M]``#@!```$````!$`%@!7 +M?0``I+$"`*P!```2``$`;WT``/0_`P`$````$@`!`(9]``"\*@(`^````!(` +M`0"7?0`````````````0````HGT`````````````$````+-]``!8-```!``` +M`!$`&`#&?0``2)(!`-P#```2``$`U'T``/AK!`!,````$@`!`.-]```L30`` +M)````!(``0#P?0`````````````0````^GT``+BN`@!H````$@`!``A^``!D +M;@$`4````!(``0`5?@``&'L"`$`!```2``$`*'X``.@.``#P````$@`!`#]^ +M``!TV@$`8````!(``0!8?@``5%`%`$@````2``$`;7X`````````````$``` +M`'I^``#`7P0`#````!(``0"'?@``'#D"`,0````2``$`F7X```A-```D```` +M$@`!`*5^`````````````!````"W?@``7'`"`*@````2``$`RGX``#PS`@"0 +M`@``$@`!`.%^``#T+`(`)````!(``0#Z?@``>)D"`"@````2``$`#W\````` +M````````$````")_```LQ@``S````!(``0`W?P``($("`!@!```2``$`3'\` +M`"`>``"H````$0`6`&%_``"T#@$`^````!(``0!O?P``Q*X!`(0!```2``$` +MC'\``&2I`0`T````$@`!`)]_``#\)P,`$````!(``0"L?P``Y+\``,P````2 +M``$`O7\``'3"`0!T````$@`!`-9_``#TFP(```(``!(``0#F?P``W`@``*P` +M```1`!8`]7\``$A8!``8````$@`!``J``````````````!`````8@```_%8$ +M`"`!```2``$`+(```&QX`0`L`0``$@`!`#V```#,-0(`C`(``!(``0!1@``` +MH#@```0````1`!@`8(``````````````$````&F``````````````!````!Z +M@``````````````0````B8````R5`@"T````$@`!`)N``````````````!`` +M``"K@``````````````0````M8```-0%```#````$0`6`,.```!P(```!``` +M`!$`%@#/@```W"$``!@````1`!8`X(```(3'`0`(!@``$@`!`.F```#8!0`` +M`P```!$`%@#W@```4%H!`"P````2``$`"8$``$BI``!\````$@`!`!J!``!8 +M'@````8``!$`&``I@0``Q`4```0````1`!8`/H$``&C_`P!($@``$@`!`&V! +M``"4@P(`1`(``!(``0"$@0``Y"````0````1`!8`FH$`````````````$``` +M`*N!``#H]```+`(``!(``0"Z@0``L#\``"0!```2``$`RH$``.R9`P#$`0`` +M$@`!`.V!``#T@0(`1````!(``0`%@@``.$,"`"`````2``$`'8(``"!H`@`$ +M````$@`!`#2"``!(`@4`%````!(``0!/@@``?&H!`$`````2``$`88(```## +M`0!@`P``$@`!`'*"``#`.```!````!$`&`"'@@``!`$"`#`"```2``$`H((` +M`$@$```$````$0`6`+:"`````````````!````#*@@``E"<#``P````2``$` +MUX(`````````````$````.V"``#8%@(`E!```!(``0#]@@``I&$$``P````2 +M``$`"8,``.!N`0"T````$@`!`!:#``#L7`0`@````!(``0`K@P```#D```P` +M```1`!@`,H,``!`=``"8````$@`!`$.#```,"`(`[`,``!(``0!;@P``U"8# +M`!@````2``$`<(,``.CS`@#4$```$@`!`'V#``#,.```!````!$`&`".@P`` +M"`0```0````1`!8`I(,``&#&`0`D`0``$@`!`+B#``"L)P``,````!(``0#) +M@P``W$0"`#P````2``$`XH,``(A;`0`0````$@`!`.Z#``#\I@``"````!(` +M`0#[@P``[%\!`!0!```2``$`"X0``,P8!`#<````$@`!`!N$```````````` +M`!`````UA```2!8$`*P````2``$`2X0``"26`0`0`0``$@`!`&:$````Z0$` +M3````!(``0"(A```$/\$``P````2``$`F(0``"2U`P!``0``$@`!`+&$``"L +MH@(`<````!(``0#'A```P#\#`"P````2``$`WH0``-"+`@`<````$@`!`/:$ +M``#X.```!````!$`&``"A0``)(X#`&`!```2``$`$X4`````````````$``` +M`!V%``"T(0,`N`,``!(``0`TA0``C`0``&0````2``$`3H4``"PM`@`D```` +M$@`!`&*%``"HH0$`0````!(``0!VA0``_&@!`#P!```2``$`B84``)B^`0"\ +M````$@`!`)V%``#`,0(`!````!(``0"OA0``8*("`$P````2``$`Q84``-#! +M`0"D````$@`!`-B%``"8.04`@`0``!(``0`!A@``^"8#``0````2``$`$X8` +M`(P@```$````$0`6`""&```HD`$`A````!(``0`TA@``*+H#`(@$```2``$` +M3(8``'@@```$````$0`6`%Z&```DK`,`,`(``!(``0!TA@``(%L!`!P````2 +M``$`?H8``,`%```$````$0`6`(Z&``#$+P$`$````!(``0"GA@``Y.T!`(`` +M```2``$`P88``%PT```$````$0`8`-*&``!L+`(`%````!(``0#DA@``$&`` +M`$@````2``$`^X8``/B?```,````$@`!`!*'```HB`(`J`(``!(``0`TAP`` +M;%D!`"`````2``$`2H<``%`^`@"<`@``$@`!`&*'``"8W```W````!(``0!Q +MAP``D)X!`+@!```2``$`A8<``$"N`0!<````$@`!`)F'``#0&P``6````!$` +M%@"QAP``&!P``%@````2``$`QH<````D```,````$@`!`-B'```````````` +M`!````#WAP``*($"`%@````2``$`"X@``&@Q`P!P`P``$@`!`"&(```($@,` +M,````!(``0`XB```?*@!`#`````2``$`2H@```2G```(````$@`!`%>(``!$ +M$`,`$````!(``0!LB```^(@!`-@````2``$`?H@``/@+`@`0`0``$@`!`)>( +M```,20``S`$``!(``0"GB```(-D$`%@````2``$`QH@``!P@``"@````$@`! +M`-N(``#82P``)````!(``0#QB```A+@``(0````2``$`_H@````````````` +M$`````Z)`````````````!`````@B0``]#@```0````1`!@`,8D``!AM```$ +M`0``$@`!`$*)``#@N`$`_`0``!(``0!3B0``E'$!`#0````2``$`:8D``%26 +M`P`\`0``$@`!`'R)```XJ0``$````!(``0"(B0``X*H#`$0!```2``$`HXD` +M`,1>`P"$`P``$@`!`+&)``!0``G````!(` +M`0`&BP```%`%`%0````2``$`'HL``%#A``!0`0``$@`!`"V+``#``"H````$0`6`$"-```D:`(`J`(``!(``0!``!\````$@`!`)>-```(J0(`-`$``!(``0"LC0``V#0#``0` +M```2``$`S(T```P&!0!4````$@`!`.J-```4IP``"````!(``0#WC0``.((" +M`(0````2``$`%XX``'AB``!``0``$@`!`">.``#46@0`&````!(``0`VC@`` +M#$`#``0````2``$`5HX``%`B`0`,`P``$@`!`&N.`````````````!````!\ +MC@``G"````0````1`!8`BXX``-P$```$````$0`6`)..``!/```X +M!```!````!$`%@!=CP`````````````0````;X\``-B%`@!0`@``$@`!`)"/ +M```\=@0`"`$``!(``0">CP``"*L``'0````2``$`K(\``+1U`0`D`0``$@`! +M`+:/`````````````!````"]CP``:*$!`!@````2``$`T(\``#2H```X```` +M$@`!`/./```84@0`\`$``!(``0`(D```(`0```0````1`!8`()````Q$`@`P +M````$@`!`#N0``#$AP$`U````!(``0!.D```*!P``*@````1`!8`:9```#0[ +M`P`D`0``$@`!`'F0`````````````!````"#D```[#`$`!`!```2``$`GY`` +M`)B(`0!@````$@`!`+.0```T`@4`#````!(``0#,D```L#@```0````1`!@` +MV)```&RF`@"$````$@`!`.V0```LB@``'````!(``0`(D0``2&2``!XBP``2````!(` +M`0`SD@``7(4``(P````2``$`3I(``!C;!`"\#P``$@`!`%B2```````````` +M`!````!KD@`````````````0````?9(``(@4!`#D````$@`!``!R='=?8VUD +M+F,`)&$`)&0`+DQ#,``N3$,Q`"Y,04Y#2$]2,`!R='=?7!T`&-R8S,R7W)E=F5R'1?:V5Y`&)Y=&5?#$`%]T86)L90!#+C8P-BXT,S`V.0!B8W)C,S)I;FET:6%L:7IE9`!C +M2YC`')T=U]I;V-T;%]S970N8P`N3$,R`')T=U]I +M965E.#`R,3$N8P!K97E?8VAA2XT,C@W-`!R='=?;6QM95]E>'0N8P!5<&1A=&5" +M5]S=7-P96YD`')T=U]L +M871E7W)EF5?.#$X.&4`:&%L7T5F=7-E1FEX2&5A9&5R4')O8V5S6-F9RYC`'!H>5]#86QC=6QA=&5":713:&EF=`!P:'E?1&)M5&]4 +M>%!W`!?4$A97U-E=%)&4&%T:%-W:71C:`!P:'E?4D9397)I86Q296%D +M`$-35U1#2"XV,#4`0U-75$-(+C8P.`!#+C4X."XT-#0P-@!R=&PX,3@X95]R +M9C8P-3(N8P!#+C4X-"XT-#0R-@!#+C4X-2XT-#0R-P!21E]3:&%D;W<`&1E$)E86-O +M;@!R=&PX,3DR8W5?:'=?<&]W97)?9&]W;@!?26YI=$YO0!#+C8Q,"XT-#DW.0!#4U=40T@N-C4T`$,N-C(U+C0U-#8Y`$-3 +M5U1#2"XV-#<`0U-75$-(+C8U,`!#4U=40T@N-C4Q`')T;#@Q.#AE=5]L960N +M8P!297-E=$QE9%-T871U6YC`'5S8E]W%)05%1I;6EN9U\X,3@X10!O9&U?4F%T941E8VES:6]N7S@Q.#A%`"Y,0S,V +M`$1Y;F%M:6-4>%)05%1I;6EN9P!?7V9U;F-?7RXT-#`Y,P!?7V9U;F-?7RXT +M-#4V.0!24U-)7U1(4D532$],1`!2151265]014Y!3%197TE$6`!2151265]0 +M14Y!3%19`%)%5%)97U!%3D%,5%E?55!?2418`$Y?5$A215-(3TQ$7TQ/5P!$ +M4D]024Y'7TY%0T534T%260!?7V9U;F-?7RXT-#$T-`!.7U1(4D532$],1%]( +M24=(`%]?9G5N8U]?+C0T,S0Y`%!E;F1I;F=&;W)2871E57!&86EL`%]?9G5N +M8U]?+C0U-#`W`%]?9G5N8U]?+C0U,S(R`%]?9G5N8U]?+C0U,C@S`%]?9G5N +M8U]?+C0U,C0S`%]?9G5N8U]?+C0U,C`Y`%]?9G5N8U]?+C0U,38Q`%]?9G5N +M8U]?+C0U-#8P`%!47U!%3D%,5%D`7U]F=6YC7U\N-#4P.#0`7U]F=6YC7U\N +M-#4S-C0`7U]F=6YC7U\N-#0X.34`1'EN86UI8U1X4E!45&EM:6YG0V]U;G1E +M2XT +M,C(T,`!O%]R;V%M:6YG7W1I;65S`%]? +M<&%R86U?6UT86)?;78X.'6UT86)?"YC`&AE>#)N=6U?:0!W<&%?%]G971?%]G971?0!R='=?=WA?0!R='=?=WA?%]R96%D7W)F`')T=U]M<%]E9G5S95]G970`+DQ#,3,`+DQ#,34` +M+DQ#,C,`+DQ#,C8`+DQ#,C<`+DQ#,C@`+DQ#,CD`%]S971?875T:`!R='=?%]G971?;F%M90`N3$,X,``N3$,X,0`N3$,X,P`N3$,X +M-``N3$,X-0`N3$,X-P`N3$,X.`!R='=?=WA?9V5T7W)A;F=E`')T=U]W>%]G +M971?9G)E<0!T5]P87)A;7,`8V9G.#`R,3%?`!C9F'1R85]C;61?:&1L`$]$35]3=T%N=$1I=D-H:U!E5]M6YA;6EC5'A0;W=E&1E5]I;F-L=61E9`!(86Q?26YI=%!'1&%T83@X10!C +M9F6YA;6EC +M4')I;6%R>4-#05]$=7!25%,`&UI=&9R +M86UE`')T=U]C;61?9FEL=&5R`')T=U]D97%U975E7W)E8W9F%!O=V5R4V%V95!O=V5R26YD +M97@`&UI=%]R97-O=7)C95]F%!O=V5R3&5V +M96PX,3@X10!R='=?9V5T7V-A<&%B:6QI='D`<&AY7U1X4'=R261X5&]$8FT` +M7W)T=U]R96%D,38`9F%K945F=7-E0F%N:P!/;D%C=&EO;E]B86-K`')T=U]F +M5]T:6UE5]S=7-P96YD`')T=U]C +M%!O=V5R5W)I +M=&5686Q">5)E9W5L871O`!R=&PX,3@X +M15]P;W=E5]C;60`;V1M7T9A;'-E06QA +M5]A='1R:6)U90!N971W;W)K='EP95]T;U]R86ED`')T=U]I7!T;W(`7W)T=U]R;V%M:6YG`&]D;5]);FET7U)3 +M4TE&;W)$30!O9&U?0V]M;6]N26YF;U-E;&95<&1A=&4`7!E.#A%`%]R='=?96YQ=65U +M95]N971W;W)K`&1Y;F%M:6-?8VAK7W=K7VAD;`!S:71E`!02%E? +M4V5T5'A0;W=E6YA;6EC7V-H:U]W:U]C;60`;V1M7T-M +M;DEN9F]);FET7T1E8G5G`')T=U]A;&QO8U]N971W;W)K`')O8VMC:&EP7W=I +M9FE?97AI=%]M;V1U;&4`3T1-7T9I;&Q(,D-#;60`6YA;6EC +M5'A0;W=E61O;F5?979E;G1? +M8V%L;&)A8VL`969U4-O;7!A'1? +M0!O9&U?161C851U%]P=W(`3T1-7U-E=$)"4F5G`&-C:W)A +M=&5S;VYL>5]I;F-L=61E9`!R='=?=7!D871E7VAT7V-A<`!R='=?8V%N8V5L +M7V%L;%]T:6UE<@!R='=?;F5T=V]R:U]M;V1E`')T=U]A;&QO8U]E=&AE&UI=%]P71E`$%43TU)0U]354)?4D54 +M55).`$]$35]3971-04-296<`971H7W1Y<&5?=')A;G,`5]35]O;E]C:&%N;F5L`%]R='=?;6%L;&]C`$)23T%$0T]-7T]5 +M23,`F5R;U]P86-K971?8VAK +M`$-O;G-T5]T:6UE<@!I&UI=&)U9@!R='=?86YD0!?F4`3T1-7U)&7U-A=FEN9P!O9&U?4F5F +M0!R='=?;6]D=6QA'1? +M<')I=@!/1$U?4D%3=&%T94-H96-K`$AA;%]296%D4&]W97)3879I;F=-;V1E +M.#A%`$]N06-T:6]N7W!U8FQI8P!M=C@X=S@V.#9?:69?'1?:F]I;F)S0!R='=?8V9G.#`R,3%?:6YD:6-A=&5?&UI=&9R86UE +M7V5X`&1U;7!?8VAI<%]I;F9O`&]D;5]3:6=N86Q38V%L94UA<'!I;F=?.3)# +M4V5R:65S7W!A=&-H7U)47T-)1%\X,3EX7TQE;F]V;P!R=&PX,3@X975?&1E0!49#``5U!!7T-)4$A%4E]354E415]42TE0`')T;#@Q.#AE +M7W-E=%]P,G!?8W1W7W!E%]B96%C;VY?8VUD`&MI +M;&Q?<&ED`$AA;%]%9G5S95!A0!G971?='AF:69O7VAW861D<@!R='=?5]E +M=F5N=%]C86QL8F%C:P!I0!R='=?9FEN9%]N971W;W)K`%!(65]21E-H861O +M=U)E8V]R=F5R1FQA9U-E=$%L;`!?&UI=%]P +M6YC`')T=U]E9G5S95]M87!?71E`')T=U]I;F1I8V%T95]C;VYN96-T`%)%04Q414M?3U5)`')T +M=U]F0!R='=?:6YI=%]N971D979?;F%M +M90!?7W1A%!A=&@`3T1-7U-W06YT1&EV4F5S971"969O6YA;6EC5'A0;W=E`!/;D%C=&EO;E]P,G``7W)T=U]W'1?%]I;FET`')T;#@Q.#AE7TAA;$1M5V%T8VA$;V<`169U4-#05]);FET`'5S8E]D97)E9VES=&5R`%]R='=? +M:6YI=%]S=&%I;F9O`')T=U]S8V%N7VUO9&4`:FEF9FEE4%N=$1I=@!R='=?5]0;W=E&9R86UE'!I5]0871H05])44M?.#$X.$4`5]S=7-P96YD`&5N86)L95]R871E7V%D87!T:79E`%]?;65M>F5R;P!R='=? +M9'5M<%]X9G)A;64`5]E7!T7V1E8W)Y<'1? +M9G)O;5]R96=I7!R:78`7U!(65]296QO861-04-296=I3@Q.3)#`')T=U]M<%]M;V1E`')T=U]S>7-T:6UE7W1O7VUS +M`')T=U]C:&%N9V5?:69N86UE`')T=U]I3@X +M10!02%E?4V5T0E=-;V1E.#$X.$4`9FQU0!O9&U? +M5%A0;W=E%!O=V5R7SDR0P!R='=?;69R964R9`!R +M='=?969U%]I;FET`$]$35]205]5<&1A=&52871E26YF;U\X,3@X10!R +M='=?=F-S7W1Y<&4`%]M86-?:60`5\X.$4`8V9G.#`R,3%?%]A5-T871U%!W7!E`'-T&UI=`!"4D]!1$-/35]/54DR`%-A=F5?1$U?1G5N8U]&;&%G`&-H:U]S +M=&%?:7-?86QI=F4`0E1%9G5S94-O;G1E;G0`8FUC7W-U<'!O5]#;VYF:6="0D5X=&5R;F%L4$$`7!E`$]N06-T:6]N7W%O5],0T-A;&EB7!T`')T=U]I;F1I8V%T95]W>%]D:7-A0!R='=? +M;6,R=5]D:7-A8FQE`')T=U]G971?=W!S7V%T='(``!,96%V94%L;%!O=V5R4V%V94UO9&4`3T1-7U)EF57;W)K271E;0!S=')L96X`5]F$%G9W(X,3@X155S8@!W:7!H>5]F5]2861I;T%?,51?.#$X.$4`07)R87E?4$A97U)%1U]-4%\X +M,3@X10!?5]L;70`0V]N5]E +M=F5N=%]C86QL8F%C:P!/1$U?1$U);FET`&ES +#include +#include +#include + +#include "wifi_power.h" + +/* + * rtw_channel_plan : The initialization parameter of wifi channel, + * Allow number is "0" "2" and "5". + * 0 => 11 ( channel 1 ~ 11 is SCAN_ACTIVE ) + * 2 => 13 ( channel 1 ~ 13 is SCAN_ACTIVE ) + * 5 => 14 ( channel 1 ~ 14 is SCAN_ACTIVE ) + * default number is "2". + */ +char init_channel_plan = 2; + +#if (WIFI_GPIO_POWER_CONTROL == 1) + +/* + * GPIO to control LDO/DCDC. + * + * 鐢ㄤ簬鎺у埗WIFI鐨勭數婧愶紝閫氬父鏄3.3V鍜1.8V锛屽彲鑳1.2V涔熷湪鍏朵腑銆 + * + * 濡傛灉鏄墿灞旾O锛岃鍙傝冧笅闈㈢殑渚嬪瓙: + * POWER_USE_EXT_GPIO, 0, 0, 0, PCA9554_Pin1, GPIO_HIGH + */ +struct wifi_power power_gpio = +{ + //POWER_NOT_USE_GPIO, 0, 0, 0, 0, 0 + + // RBOX + //POWER_USE_GPIO, POWER_GPIO_IOMUX, + //GPIO5D6_SDMMC1PWREN_NAME, GPIO5H_GPIO5D6, RK29_PIN5_PD6, GPIO_HIGH + +#define GPIO_WIFI_POWER RK29_PIN6_PC0 + + // YIFANG M803 + //POWER_USE_GPIO, 0, + //0, 0, GPIO_WIFI_POWER, GPIO_HIGH + + //SDK + POWER_NOT_USE_GPIO, 0, 0, 0, 0, 0 +}; + +/* + * GPIO to control WIFI PowerDOWN/RESET. + * + * 鎺у埗WIFI鐨凱owerDown鑴氥傛湁浜涙ā缁凱owerDown鑴氭槸鍜孯eset鑴氱煭鎺ュ湪涓璧枫 + */ +struct wifi_power power_save_gpio = +{ + POWER_NOT_USE_GPIO, 0, 0, 0, 0, 0 +}; + +/* + * GPIO to reset WIFI. Keep this as NULL normally. + * + * 鎺у埗WIFI鐨凴eset鑴氾紝閫氬父WiFi妯$粍娌℃湁鐢ㄥ埌杩欎釜寮曡剼銆 + */ +struct wifi_power power_reset_gpio = +{ + POWER_NOT_USE_GPIO, 0, 0, 0, 0, 0 +}; + +/* + * 鍦╓IFI琚笂鐢靛墠锛屼細璋冪敤杩欎釜鍑芥暟銆 + */ +void wifi_turn_on_callback(void) +{ +} + +/* + * 鍦╓IFI琚笅鐢靛悗锛屼細璋冪敤杩欎釜鍑芥暟銆 + */ +void wifi_turn_off_callback(void) +{ +} + +/* + * If external GPIO chip such as PCA9554 is being used, please + * implement the following 2 function. + * + * id: is GPIO identifier, such as GPIOPortF_Pin0, or external + * name defined in struct wifi_power. + * sens: the value should be set to GPIO, usually is GPIO_HIGH or GPIO_LOW. + * + * 濡傛灉鏈夌敤鎵╁睍GPIO鏉ユ帶鍒禬IFI锛岃瀹炵幇涓嬮潰鐨勫嚱鏁: + * 鍑芥暟鐨勫姛鑳芥槸锛氭帶鍒舵寚瀹氱殑IO鍙d锛屼娇鍏剁姸鎬佸垏鎹负瑕佹眰鐨剆ens鐘舵併 + * id : 鏄疘O鐨勬爣璇嗗彿锛屼互鏁存暟鐨勫舰寮忔爣璇嗐 + * sens: 鏄姹傜殑IO鐘舵侊紝涓洪珮鎴栦綆銆 + */ +void wifi_extgpio_operation(u8 id, u8 sens) +{ + //pca955x_gpio_direction_output(id, sens); +} + +/* + * 鍦ㄧ郴缁熶腑濡傛灉瑕佽皟鐢╓IFI鐨処O鎺у埗锛屽皢WIFI涓嬬數锛屽彲浠ヨ皟鐢ㄥ涓嬫帴鍙o細 + * void rockchip_wifi_shutdown(void); + * 浣嗘敞鎰忛渶瑕佸湪瀹廤IFI_GPIO_POWER_CONTROL鐨勬帶鍒朵笅銆 + */ + +#endif /* WIFI_GPIO_POWER_CONTROL */ + diff --git a/drivers/net/wireless/rtl8188eu/wifi_power.h b/drivers/net/wireless/rtl8188eu/wifi_power.h new file mode 100644 index 000000000000..ea21f11060ae --- /dev/null +++ b/drivers/net/wireless/rtl8188eu/wifi_power.h @@ -0,0 +1,87 @@ +/* + * wifi_power.h + * + * WIFI power control. + * + * Yongle Lai + */ + +#ifndef WIFI_POWER_H +#define WIFI_POWER_H + +#include + +#define DONT_SWITCH_USB 0 /* Don't switch USB automaticately. */ +#define WIFI_USE_OTG 1 /* WiFi will be connected to USB OTG. */ +#define WIFI_USE_HOST11 2 /* WiFi will be connected to USB HOST 1.1. */ + +#define WIFI_USE_IFACE WIFI_USE_HOST11 /* Select USB Controler */ +#define WIFI_GPIO_POWER_CONTROL 1 /* Enable GPIO Control Power */ + +#if (WIFI_GPIO_POWER_CONTROL == 1) + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25) +#include +#include +#else +//#include +#include +#endif + +#define WIFI_CHIP_MV8686 0 +#define WIFI_CHIP_AR6002 1 +#define WIFI_CHIP_BCM4319 2 +#define WIFI_CHIP_NRX700 3 +#define WIFI_CHIP_RT3070 4 +#define WIFI_CHIP_RTL8192C 5 + +#define POWER_NOT_USE_GPIO 0 +#define POWER_USE_GPIO 1 +#define POWER_USE_EXT_GPIO 2 /* External GPIO chip is used, such as PCA9554. */ + +#define POWER_GPIO_NOT_IOMUX 0 +#define POWER_GPIO_IOMUX 1 + +#define GPIO_SWITCH_OFF 0 +#define GPIO_SWITCH_ON 1 + +struct wifi_power +{ + u16 use_gpio; /* If uses GPIO to control wifi power supply. 0 - no, 1 - yes. */ + u16 gpio_iomux; /* If the GPIO is iomux. 0 - no, 1 - yes. */ + char *iomux_name; /* IOMUX name */ + u16 iomux_value; /* IOMUX value - which function is choosen. */ + u16 gpio_id; /* GPIO number */ + u16 sensi_level; /* GPIO sensitive level. */ +}; + +int wifi_turn_on_card(int module); +int wifi_turn_off_card(void); +int wifi_reset_card(void); +void wifi_extgpio_operation(u8 id, u8 sens); + +void rockchip_wifi_shutdown(void); + +#endif /* WIFI_GPIO_POWER_CONTROL */ + +#define WIFI_NETWORK_BUSY 0 +#define WIFI_NETWORK_IDLE 1 + +int wifi_power_save_init(void); +int wifi_power_save_exit(void); +int wifi_power_save_stop(void); +int wifi_power_save_state(void); +void wifi_power_save_suspend(void); +void wifi_power_save_resume(void); +int wifi_power_save_register_callback(int (*callback)(int status)); + +void wifi_turn_on_callback(void); +void wifi_turn_off_callback(void); + +/* usb wifi */ +int wifi_activate_usb(void); +int wifi_deactivate_usb(void); +void wifi_usb_init(void); + +#endif /* WIFI_POWER_H */ + diff --git a/drivers/net/wireless/rtl8188eu/wifi_power_ops.c b/drivers/net/wireless/rtl8188eu/wifi_power_ops.c new file mode 100644 index 000000000000..4096bdac15fd --- /dev/null +++ b/drivers/net/wireless/rtl8188eu/wifi_power_ops.c @@ -0,0 +1,112 @@ +/* + * wifi_power.c + * + * Yongle Lai @ Rockchip Fuzhou @ 20100303. + * + * Power control for WIFI module. + * + * There are Power supply and Power Up/Down controls for WIFI typically. + */ +#include +#include +#include +#include + +#include "wifi_power.h" + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25) +#include +#include +#else +#include +#include +#endif + + +#if (WIFI_GPIO_POWER_CONTROL == 1) + +extern struct wifi_power power_gpio; +extern struct wifi_power power_save_gpio; +extern struct wifi_power power_reset_gpio; + +#define OS_IOMUX(name, value) rk29_mux_api_set((name), (value)); + +int wifi_gpio_operate(struct wifi_power *gpio, int flag) +{ + int sensitive; + + if (gpio->use_gpio == POWER_NOT_USE_GPIO) + return 0; + + if (gpio->gpio_iomux == POWER_GPIO_IOMUX) + { + OS_IOMUX(gpio->iomux_name, gpio->iomux_value); + } + + if (flag == GPIO_SWITCH_ON) + sensitive = gpio->sensi_level; + else + sensitive = 1 - gpio->sensi_level; + + if (gpio->use_gpio == POWER_USE_EXT_GPIO) + { + wifi_extgpio_operation(gpio->gpio_id, sensitive); + } + else + { + int ret; + + ret = gpio_request(gpio->gpio_id, NULL); + if (ret != 0) + printk("Request GPIO for WIFI POWER error!\n"); + + gpio_direction_output(gpio->gpio_id, sensitive); + gpio_set_value(gpio->gpio_id, sensitive); + + gpio_free(gpio->gpio_id); + } + + return 0; +} + +/* + * WiFi power up sequence + */ +int wifi_turn_on_rtl8192c_card(void) +{ + wifi_gpio_operate(&power_gpio, GPIO_SWITCH_ON); + if (power_gpio.use_gpio != POWER_NOT_USE_GPIO) + msleep(1000); + + return 0; +} + +int wifi_turn_on_card(int module) +{ + wifi_turn_on_callback(); + + wifi_turn_on_rtl8192c_card(); + + return 0; +} + +int wifi_turn_off_card(void) +{ + wifi_gpio_operate(&power_gpio, GPIO_SWITCH_OFF); + msleep(5); + + wifi_turn_off_callback(); + + return 0; +} + +void rockchip_wifi_shutdown(void) +{ + printk("rockchip_wifi_shutdown....\n"); + + wifi_turn_off_card(); +} +EXPORT_SYMBOL(rockchip_wifi_shutdown); + +#endif /* WIFI_GPIO_POWER_CONTROL */ + diff --git a/drivers/net/wireless/rtl8188eu/wifi_power_usb.c b/drivers/net/wireless/rtl8188eu/wifi_power_usb.c new file mode 100644 index 000000000000..c979cc34958c --- /dev/null +++ b/drivers/net/wireless/rtl8188eu/wifi_power_usb.c @@ -0,0 +1,118 @@ +/* + * wifi_power.c + * + * Power control for WIFI module. + * + * There are Power supply and Power Up/Down controls for WIFI typically. + */ +#include +#include +#include +#include + +#include "wifi_power.h" + +#if (WIFI_GPIO_POWER_CONTROL == 1) + +int wifi_change_usb_mode = 0; +int usb_wifi_status = 0; + +void wifi_usb_init(void) +{ + wifi_change_usb_mode = 0; + usb_wifi_status = 0; +} + +#if (WIFI_USE_IFACE == WIFI_USE_OTG) + +#define USB_NORMAL 0 +#define USB_FORCE_HOST 1 +#define USB_FORCE_DEVICE 2 + +extern int usb_force_usb_for_wifi(int mode); + +/* + * Change USB mode to HOST. + */ +int wifi_activate_usb(void) +{ + wifi_turn_on_card(WIFI_CHIP_RTL8192C); + + wifi_change_usb_mode = usb_force_usb_for_wifi(USB_FORCE_HOST); + msleep(1000); + + usb_wifi_status = 1; + + return 0; +} + +/* + * Change USB mode to be original. + */ +int wifi_deactivate_usb(void) +{ + if (wifi_change_usb_mode == 1) + { + usb_force_usb_for_wifi(USB_FORCE_DEVICE); + msleep(1000); + usb_force_usb_for_wifi(USB_NORMAL); + msleep(1000); + } + wifi_turn_off_card(); + + usb_wifi_status = 0; + + return 0; +} + +#elif (WIFI_USE_IFACE == WIFI_USE_HOST11) + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25) +extern int usb_switch_usb_host11_for_wifi(int enabled); +#endif + +int wifi_deactivate_usb(void) +{ +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25) + usb_switch_usb_host11_for_wifi(0); + msleep(1000); +#endif + + wifi_turn_off_card(); + msleep(100); + + return 0; +} + +int wifi_activate_usb(void) +{ + wifi_turn_on_card(WIFI_CHIP_RTL8192C); + msleep(100); + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25) + usb_switch_usb_host11_for_wifi(1); + msleep(1000); +#endif + + return 0; +} + +#else + +int wifi_deactivate_usb(void) +{ + wifi_turn_off_card(); + msleep(1000); + return 0; +} + +int wifi_activate_usb(void) +{ + wifi_turn_on_card(WIFI_CHIP_RTL8192C); + msleep(1000); + return 0; +} +#endif + +#endif /* WIFI_GPIO_POWER_CONTROL */ + diff --git a/drivers/net/wireless/rtl8188eu/wifi_version.h b/drivers/net/wireless/rtl8188eu/wifi_version.h new file mode 100755 index 000000000000..154a0140063e --- /dev/null +++ b/drivers/net/wireless/rtl8188eu/wifi_version.h @@ -0,0 +1,13 @@ +/* + * Yongle Lai @ Rockchip + */ +#ifndef _WIFI_VERSION_H_ +#define _WIFI_VERSION_H_ + +/* + * Broadcom BCM4319 driver version. + */ +#define RTL8192_DRV_VERSION "1.01" + +#endif /* WIFI_VERSION_H */ + diff --git a/drivers/net/wireless/wifi_sys/rkwifi_sys_iface.c b/drivers/net/wireless/wifi_sys/rkwifi_sys_iface.c index 8963eae6c6ec..50414a87d644 100644 --- a/drivers/net/wireless/wifi_sys/rkwifi_sys_iface.c +++ b/drivers/net/wireless/wifi_sys/rkwifi_sys_iface.c @@ -19,8 +19,13 @@ static ssize_t wifi_chip_read(struct class *cls, char *_buf) #endif #ifdef CONFIG_RTL8192CU - count = sprintf(_buf, "%s", "RTL8188"); - printk("Current WiFi chip is RTL8188.\n"); + count = sprintf(_buf, "%s", "RTL8188CU"); + printk("Current WiFi chip is RTL8188CU.\n"); +#endif + +#ifdef CONFIG_RTL8188EUS + count = sprintf(_buf, "%s", "RTL8188EU"); + printk("Current WiFi chip is RTL8188EU.\n"); #endif #ifdef CONFIG_BCM4330 From 92fcf2abad9b3d48d5f0aadc429cf6194305a5dc Mon Sep 17 00:00:00 2001 From: yangkai Date: Fri, 17 Aug 2012 16:20:17 +0800 Subject: [PATCH 216/261] merge rk2928 usb --- drivers/usb/dwc_otg/dwc_otg_cil.c | 10 ++ drivers/usb/dwc_otg/dwc_otg_driver.c | 99 +++++++++++++-- drivers/usb/dwc_otg/dwc_otg_hcd.c | 56 ++++++++- drivers/usb/dwc_otg/dwc_otg_pcd.c | 147 ++++++++++++++++++++++- drivers/usb/dwc_otg/linux/dwc_otg_plat.h | 9 ++ 5 files changed, 303 insertions(+), 18 deletions(-) diff --git a/drivers/usb/dwc_otg/dwc_otg_cil.c b/drivers/usb/dwc_otg/dwc_otg_cil.c index 9f44adc2796f..406aad103928 100755 --- a/drivers/usb/dwc_otg/dwc_otg_cil.c +++ b/drivers/usb/dwc_otg/dwc_otg_cil.c @@ -731,6 +731,16 @@ void dwc_otg_core_dev_init(dwc_otg_core_if_t *_core_if) dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[2], 0x008002b0 ); //ep5 tx fifo dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[3], 0x00800330 ); //ep7 tx fifo dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[4], 0x001003b0 ); //ep9 tx fifo +#endif +#ifdef CONFIG_ARCH_RK2928 //@lyz the same with RK30 + /* Configure data FIFO sizes, RK30 otg has 0x3cc dwords total */ + dwc_write_reg32( &global_regs->grxfsiz, 0x00000120 ); + dwc_write_reg32( &global_regs->gnptxfsiz, 0x00100120 ); //ep0 tx fifo + dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[0], 0x01000130 ); //ep1 tx fifo 256*4Byte + dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[1], 0x00800230 ); //ep3 tx fifo 128*4Byte + dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[2], 0x008002b0 ); //ep5 tx fifo 128*4Byte + dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[3], 0x00800330 ); //ep7 tx fifo 128*4Byte + dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[4], 0x001003b0 ); //ep9 tx fifo 16*4Byte #endif if(_core_if->en_multiple_tx_fifo && _core_if->dma_enable) { diff --git a/drivers/usb/dwc_otg/dwc_otg_driver.c b/drivers/usb/dwc_otg/dwc_otg_driver.c index 5efdecdd4705..e7bdd6d2d970 100755 --- a/drivers/usb/dwc_otg/dwc_otg_driver.c +++ b/drivers/usb/dwc_otg/dwc_otg_driver.c @@ -1203,6 +1203,9 @@ static __devinit int dwc_otg_driver_probe(struct platform_device *pdev) #ifdef CONFIG_ARCH_RK30 unsigned int * otg_phy_con = (unsigned int*)(USBGRF_UOC0_CON2); #endif +#ifdef CONFIG_ARCH_RK2928 + unsigned int * otg_phy_con = (unsigned int*)(USBGRF_UOC0_CON5); +#endif #ifdef CONFIG_ARCH_RK29 regval = * otg_phy_con1; @@ -1291,6 +1294,35 @@ static __devinit int dwc_otg_driver_probe(struct platform_device *pdev) clk_disable(phyclk); clk_disable(ahbclk); #endif +#endif +//need to be checked @wlf +#ifdef CONFIG_ARCH_RK2928 +#ifndef CONFIG_USB20_HOST + otg_phy_con = (unsigned int*)(USBGRF_UOC1_CON5); + /* + * disable usb host 2.0 phy if not support + */ + phyclk = clk_get(NULL, "otgphy1"); + if (IS_ERR(phyclk)) { + retval = PTR_ERR(phyclk); + DWC_ERROR("can't get USBPHY1 clock\n"); + goto fail; + } + clk_enable(phyclk); + + ahbclk = clk_get(NULL, "hclk_otg1"); + if (IS_ERR(ahbclk)) { + retval = PTR_ERR(ahbclk); + DWC_ERROR("can't get USBOTG1 ahb bus clock\n"); + goto fail; + } + clk_enable(ahbclk); + + *otg_phy_con = ((0x01<<0)|(0x00<<1)|(0x05<<4))|(((0x01<<0)|(0x01<<1)|(0x07<<4))<<16); // enter suspend. + udelay(3); + clk_disable(phyclk); + clk_disable(ahbclk); +#endif #endif dwc_otg_device = kmalloc(sizeof(dwc_otg_device_t), GFP_KERNEL); @@ -1385,6 +1417,42 @@ static __devinit int dwc_otg_driver_probe(struct platform_device *pdev) dwc_otg_device->phyclk = phyclk; dwc_otg_device->ahbclk = ahbclk; #endif +//need to be checked @wlf +#if 0//def CONFIG_ARCH_RK2928 + otg_phy_con = (unsigned int*)(USBGRF_UOC0_CON5); + cru_set_soft_reset(SOFT_RST_USBPHY0, true); + cru_set_soft_reset(SOFT_RST_OTGC0, true); + cru_set_soft_reset(SOFT_RST_USBOTG0, true); + udelay(1); + + cru_set_soft_reset(SOFT_RST_USBOTG0, false); + cru_set_soft_reset(SOFT_RST_OTGC0, false); + cru_set_soft_reset(SOFT_RST_USBPHY0, false); + + phyclk = clk_get(NULL, "otgphy0"); + if (IS_ERR(phyclk)) { + retval = PTR_ERR(phyclk); + DWC_ERROR("can't get USBPHY0 clock\n"); + goto fail; + } + clk_enable(phyclk); + + ahbclk = clk_get(NULL, "hclk_otg0"); + if (IS_ERR(ahbclk)) { + retval = PTR_ERR(ahbclk); + DWC_ERROR("can't get USB otg0 ahb bus clock\n"); + goto fail; + } + clk_enable(ahbclk); + + /* + * Enable usb phy 0 + */ + *otg_phy_con = (0x01<<16); + + dwc_otg_device->phyclk = phyclk; + dwc_otg_device->ahbclk = ahbclk; +#endif /* * Map the DWC_otg Core memory into virtual address space. */ @@ -1519,6 +1587,9 @@ static __devinit int dwc_otg_driver_probe(struct platform_device *pdev) #endif #ifdef CONFIG_ARCH_RK30 USB_IOMUX_INIT(GPIO0A5_OTGDRVVBUS_NAME, GPIO0A_OTG_DRV_VBUS); +#endif +#ifdef CONFIG_ARCH_RK2928 + USB_IOMUX_INIT(GPIO3C1_OTG_DRVVBUS_NAME, GPIO3C_OTG_DRVVBUS); #endif /* * Initialize the HCD @@ -2057,7 +2128,10 @@ static __devinit int host20_driver_probe(struct platform_device *pdev) unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC1_CON2); *otg_phy_con1 = ((0x01<<2)<<16); // exit suspend. #endif - +#ifdef CONFIG_ARCH_RK2928 + unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC1_CON5); + *otg_phy_con1 = (0x01<<16); // exit suspend. +#endif #if 0 *otg_phy_con1 |= (0x01<<2); *otg_phy_con1 |= (0x01<<3); // exit suspend. @@ -2084,6 +2158,9 @@ static __devinit int host20_driver_probe(struct platform_device *pdev) #ifdef CONFIG_ARCH_RK30 *(unsigned int*)(USBGRF_UOC1_CON2+4) = ((1<<5)|((1<<5)<<16)); #endif +#ifdef CONFIG_ARCH_RK2928 + *(unsigned int*)(USBGRF_UOC1_CON5-4) = ((1<<5)|((1<<5)<<16)); +#endif if (dwc_otg_device == 0) { dev_err(dev, "kmalloc of dwc_otg_device failed\n"); @@ -2108,6 +2185,9 @@ static __devinit int host20_driver_probe(struct platform_device *pdev) #ifdef CONFIG_ARCH_RK30 ahbclk = clk_get(NULL, "hclk_otg1"); #endif +#ifdef CONFIG_ARCH_RK2928 + ahbclk = clk_get(NULL, "hclk_otg1"); //need to be checked @wlf +#endif if (IS_ERR(ahbclk)) { retval = PTR_ERR(ahbclk); DWC_ERROR("can't get USBOTG1 ahb bus clock\n"); @@ -2213,15 +2293,6 @@ static __devinit int host20_driver_probe(struct platform_device *pdev) #endif #ifdef CONFIG_ARCH_RK30 USB_IOMUX_INIT(GPIO0A6_HOSTDRVVBUS_NAME, GPIO0A_HOST_DRV_VBUS); -#ifdef CONFIG_MACH_RK30_DS1001B - USB_IOMUX_INIT(GPIO0A5_OTGDRVVBUS_NAME, GPIO0A_GPIO0A5); - if(gpio_request(RK30_PIN0_PA5,"host_drv")<0){ - DWC_ERROR("request of host power control failed\n"); - gpio_free(RK30_PIN0_PA5); - } - gpio_direction_output(RK30_PIN0_PA5, GPIO_HIGH); - gpio_set_value(RK30_PIN0_PA5, GPIO_HIGH); -#endif #endif /* * Initialize the DWC_otg core. @@ -2246,9 +2317,15 @@ static __devinit int host20_driver_probe(struct platform_device *pdev) #ifndef CONFIG_USB20_HOST_EN clk_disable(phyclk); clk_disable(ahbclk); +#if defined(CONFIG_ARCH_RK29) otgreg &= ~(0x01<<14); // suspend. - otgreg |= (0x01<<13); // software control + otgreg |= (0x01<<13); // software control enable *otg_phy_con1 = otgreg; +#elif defined(CONFIG_ARCH_RK30) + *otg_phy_con1 = ((0x01<<2)|(0x00<<3)|(0x05<<6))|(((0x01<<2)|(0x01<<3)|(0x07<<6))<<16); // enter suspend. +#elif defined(CONFIG_ARCH_RK2928) + *otg_phy_con1 = ((0x01<<0)|(0x00<<1)|(0x05<<4))|(((0x01<<0)|(0x01<<1)|(0x07<<4))<<16); // enter suspend. +#endif #endif return 0; diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd.c b/drivers/usb/dwc_otg/dwc_otg_hcd.c index bef6e0db01d9..b2fb7519f5b6 100755 --- a/drivers/usb/dwc_otg/dwc_otg_hcd.c +++ b/drivers/usb/dwc_otg/dwc_otg_hcd.c @@ -69,8 +69,10 @@ static int dwc_otg_hcd_suspend(struct usb_hcd *hcd) return 0; } hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0); +#ifdef CONFIG_USB_SUSPEND if((!dwc_otg_hcd->host_enabled)||(!hprt0.b.prtena)) return 0; +#endif DWC_PRINT("%s suspend, HPRT0:0x%x\n",hcd->self.bus_name,hprt0.d32); if(hprt0.b.prtconnsts) // usb device connected { @@ -128,8 +130,10 @@ static int dwc_otg_hcd_resume(struct usb_hcd *hcd) DWC_PRINT("%s, usb device mode\n", __func__); return 0; } +#ifdef CONFIG_USB_SUSPEND if(!dwc_otg_hcd->host_enabled) return 0; +#endif #ifndef CONFIG_DWC_REMOTE_WAKEUP clk_enable(core_if->otg_dev->phyclk); clk_enable(core_if->otg_dev->ahbclk); @@ -149,8 +153,10 @@ static int dwc_otg_hcd_resume(struct usb_hcd *hcd) dwc_write_reg32(&core_if->core_global_regs->gintmsk, gintmsk.d32); hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0); +#ifdef CONFIG_USB_SUSPEND if(!hprt0.b.prtena) return 0; +#endif DWC_PRINT("%s resume, HPRT0:0x%x\n",hcd->self.bus_name,hprt0.d32); if(hprt0.b.prtconnsts) { @@ -617,6 +623,24 @@ static int32_t dwc_otg_phy_suspend_cb( void *_p, int suspend) udelay(3); DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n"); } +#endif +#if 0//def CONFIG_ARCH_RK2928 + unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC0_CON5); + if(exitsuspend && (pcd->phy_suspend == 1)) { + clk_enable(pcd->otg_dev->ahbclk); + clk_enable(pcd->otg_dev->phyclk); + pcd->phy_suspend = 0; + *otg_phy_con1 = (0x01<<16); // exit suspend. + DWC_DEBUGPL(DBG_PCDV, "enable usb phy\n"); + } + if( !exitsuspend && (pcd->phy_suspend == 0)) { + pcd->phy_suspend = 1; + *otg_phy_con1 = 0x55 |(0x7f<<16); // enter suspend. + udelay(3); + clk_disable(pcd->otg_dev->phyclk); + clk_disable(pcd->otg_dev->ahbclk); + DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n"); + } #endif return suspend; } @@ -663,7 +687,7 @@ static struct tasklet_struct reset_tasklet = { .func = reset_tasklet_func, .data = 0, }; -#ifdef CONFIG_ARCH_RK30 +#if defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK2928) static void dwc_otg_hcd_enable(struct work_struct *work) { dwc_otg_hcd_t *dwc_otg_hcd; @@ -721,7 +745,11 @@ static void dwc_otg_hcd_connect_detect(unsigned long pdata) local_irq_save(flags); // DWC_PRINT("%s hprt %x, grfstatus 0x%x\n", __func__, dwc_read_reg32(core_if->host_if->hprt0), usbgrf_status& (7<<22)); +#ifdef CONFIG_ARCH_RK30 if(usbgrf_status & (7<<22)){ +#else //CONFIG_ARCH_RK2928 + if(usbgrf_status & (7<<12)){ +#endif // usb device connected dwc_otg_hcd->host_setenable = 1; } @@ -732,7 +760,11 @@ static void dwc_otg_hcd_connect_detect(unsigned long pdata) } if(dwc_otg_hcd->host_setenable != dwc_otg_hcd->host_enabled){ - DWC_PRINT("%s schedule delaywork \n", __func__, dwc_read_reg32(core_if->host_if->hprt0), usbgrf_status& (7<<22)); +#ifdef CONFIG_ARCH_RK30 + DWC_PRINT("%s schedule delaywork 0x%x, 0x%x\n", __func__, dwc_read_reg32(core_if->host_if->hprt0), usbgrf_status& (7<<22)); +#else //CONFIG_ARCH_RK2928 + DWC_PRINT("%s schedule delaywork \n", __func__, dwc_read_reg32(core_if->host_if->hprt0), usbgrf_status& (7<<12)); +#endif schedule_delayed_work(&dwc_otg_hcd->host_enable_work, 8); } // dwc_otg_hcd->connect_detect_timer.expires = jiffies + (HZ<<1); /* 1 s */ @@ -1116,6 +1148,24 @@ static int32_t host20_phy_suspend_cb( void *_p, int suspend) udelay(3); DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n"); } +#endif +#if 0//def CONFIG_ARCH_RK2928 + unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC0_CON5); + if(exitsuspend && (pcd->phy_suspend == 1)) { + clk_enable(pcd->otg_dev->ahbclk); + clk_enable(pcd->otg_dev->phyclk); + pcd->phy_suspend = 0; + *otg_phy_con1 = (0x01<<16); // exit suspend. + DWC_DEBUGPL(DBG_PCDV, "enable usb phy\n"); + } + if( !exitsuspend && (pcd->phy_suspend == 0)) { + pcd->phy_suspend = 1; + *otg_phy_con1 = 0x55 |(0x7f<<16); // enter suspend. + udelay(3); + clk_disable(pcd->otg_dev->phyclk); + clk_disable(pcd->otg_dev->ahbclk); + DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n"); + } #endif return suspend; } @@ -1266,7 +1316,7 @@ int __devinit host20_hcd_init(struct device *dev) goto error3; } -#ifdef CONFIG_ARCH_RK30 +#if defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK2928) dwc_otg_hcd->host_setenable = 1; dwc_otg_hcd->connect_detect_timer.function = dwc_otg_hcd_connect_detect; dwc_otg_hcd->connect_detect_timer.data = (unsigned long)(dwc_otg_hcd); diff --git a/drivers/usb/dwc_otg/dwc_otg_pcd.c b/drivers/usb/dwc_otg/dwc_otg_pcd.c index 6f6d975e09c6..81456fd70dbd 100755 --- a/drivers/usb/dwc_otg/dwc_otg_pcd.c +++ b/drivers/usb/dwc_otg/dwc_otg_pcd.c @@ -189,7 +189,7 @@ void request_nuke( dwc_otg_pcd_ep_t *_ep ) * This function assigns periodic Tx FIFO to an periodic EP * in shared Tx FIFO mode */ - #ifdef CONFIG_ARCH_RK30 + #if defined(CONFIG_ARCH_RK30)||defined(CONFIG_ARCH_RK2928) //@lyz static uint32_t assign_perio_tx_fifo(dwc_otg_core_if_t *core_if) { uint32_t PerTxMsk = 1; @@ -218,7 +218,7 @@ static void release_perio_tx_fifo(dwc_otg_core_if_t *core_if, uint32_t fifo_num) * This function assigns periodic Tx FIFO to an periodic EP * in Dedicated FIFOs mode */ -#ifdef CONFIG_ARCH_RK30 +#if defined(CONFIG_ARCH_RK30)||defined(CONFIG_ARCH_RK2928) //@lyz static uint32_t assign_tx_fifo(dwc_otg_core_if_t *core_if) { uint32_t TxMsk = 1; @@ -304,7 +304,7 @@ static int dwc_otg_pcd_ep_enable(struct usb_ep *_ep, if(ep->dwc_ep.is_in) { -#ifndef CONFIG_ARCH_RK29 +#if defined(CONFIG_ARCH_RK30)||defined(CONFIG_ARCH_RK2928) //@lyz if(!pcd->otg_dev->core_if->en_multiple_tx_fifo) { ep->dwc_ep.tx_fifo_num = 0; @@ -1497,6 +1497,10 @@ void dwc_otg_pcd_reinit(dwc_otg_pcd_t *_pcd) * EP8&EP9 of rk30 are IN&OUT ep, we use ep8 as OUT EP default */ #ifdef CONFIG_ARCH_RK30 + if(i == 8) + continue; + #endif + #ifdef CONFIG_ARCH_RK2928 //@lyz the same with rk30 if(i == 8) continue; #endif @@ -1558,6 +1562,10 @@ void dwc_otg_pcd_reinit(dwc_otg_pcd_t *_pcd) * EP8&EP9 of rk30 are IN&OUT ep, we use ep9 as IN EP default */ #ifdef CONFIG_ARCH_RK30 + if(i == 9) + continue; + #endif + #ifdef CONFIG_ARCH_RK2928 //@lyz the same with rk30 if(i == 9) continue; #endif @@ -1663,7 +1671,25 @@ int dwc_otg20phy_suspend( int exitsuspend ) DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n"); } #endif - +#ifdef CONFIG_ARCH_RK2928 + unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC0_CON5); + if(exitsuspend && (pcd->phy_suspend == 1)) { + clk_enable(pcd->otg_dev->ahbclk); + clk_enable(pcd->otg_dev->phyclk); + pcd->phy_suspend = 0; + *otg_phy_con1 = (0x01<<16); // exit suspend. + DWC_DEBUGPL(DBG_PCDV, "enable usb phy\n"); + } + if( !exitsuspend && (pcd->phy_suspend == 0)) { + pcd->phy_suspend = 1; + *otg_phy_con1 = 0x55 |(0x7f<<16); // enter suspend. + // *otg_phy_con1 = 0x1D5 |(0x1ff<<16); // enter suspend. enable dm,dp debug_wlf @2012.8.10 + udelay(3); + clk_disable(pcd->otg_dev->phyclk); + clk_disable(pcd->otg_dev->ahbclk); + DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n"); + } +#endif return pcd->phy_suspend; } @@ -1873,6 +1899,69 @@ static void dwc_otg_pcd_check_vbus_timer( unsigned long pdata ) return; } +#endif +#ifdef CONFIG_ARCH_RK2928 +static void dwc_otg_pcd_check_vbus_timer( unsigned long pdata ) +{ + dwc_otg_pcd_t * _pcd = (dwc_otg_pcd_t *)pdata; + unsigned long flags; + unsigned int usbgrf_status = *(unsigned int*)(USBGRF_SOC_STATUS0);//@lyz USBGRF_SOC_STATUS0结构有变 + + local_irq_save(flags); + _pcd->check_vbus_timer.expires = jiffies + (HZ); /* 1 s */ + if((usbgrf_status &(1<<10)) == 0){ // id low //@lyz SOC_STATUS0[10] represents id_dig + + if( _pcd->phy_suspend) + dwc_otg20phy_suspend( 1 ); + } + else if(usbgrf_status & (1<<7)){ //@lyz SOC_STATUS0[7] represents bvalid + /* if usb not connect before ,then start connect */ + if( _pcd->vbus_status == 0 ) { + DWC_PRINT("********vbus detect*********************************************\n"); + dwc_otg_msc_lock(_pcd); + _pcd->vbus_status = 1; + if(_pcd->conn_en) + goto connect; + else + dwc_otg20phy_suspend( 0 ); + } + else if((_pcd->conn_en)&&(_pcd->conn_status>=0)&&(_pcd->conn_status <3)){ + DWC_PRINT("********soft reconnect******************************************\n"); + goto connect; + } + else if(_pcd->conn_status ==3){ + //*连接不上时释放锁,允许系统进入二级睡眠,yk@rk,20100331*// + dwc_otg_msc_unlock(_pcd); + _pcd->conn_status++; + if((dwc_read_reg32((uint32_t*)((uint8_t *)_pcd->otg_dev->base + DWC_OTG_HOST_PORT_REGS_OFFSET))&0xc00) == 0xc00) + _pcd->vbus_status = 2; + } + }else { + _pcd->vbus_status = 0; + if(_pcd->conn_status) + { + _pcd->conn_status = 0; + dwc_otg_msc_unlock(_pcd); + } + /* every 500 ms open usb phy power and start 1 jiffies timer to get vbus */ + if( _pcd->phy_suspend == 0 ) + /* no vbus detect here , close usb phy */ + dwc_otg20phy_suspend( 0 ); + } + add_timer(&_pcd->check_vbus_timer); + local_irq_restore(flags); + return; + +connect: + if( _pcd->phy_suspend == 1 ) + dwc_otg20phy_suspend( 1 ); + schedule_delayed_work( &_pcd->reconnect , 8 ); /* delay 1 jiffies */ + _pcd->check_vbus_timer.expires = jiffies + (HZ<<1); /* 1 s */ + add_timer(&_pcd->check_vbus_timer); + local_irq_restore(flags); + return; +} + #endif #ifdef CONFIG_ARCH_RK29 /* @@ -1980,6 +2069,56 @@ int dwc_otg_check_dpdm(void) return bus_status; } +EXPORT_SYMBOL(dwc_otg_check_dpdm); +#endif +#ifdef CONFIG_ARCH_RK2928 +int dwc_otg_check_dpdm(void) +{ + static uint8_t * reg_base = 0; + volatile unsigned int * otg_dctl; + volatile unsigned int * otg_gotgctl; + volatile unsigned int * otg_hprt0; + int bus_status = 0; + unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC0_CON5);//@lyz modify UOC0_CON2 to CON5 + + // softreset & clockgate //@lyz modify RK2928_CRU_BASE + *(unsigned int*)(RK2928_CRU_BASE+0x120) = ((7<<5)<<16)|(7<<5); // otg0 phy clkgate + udelay(3); + *(unsigned int*)(RK2928_CRU_BASE+0x120) = ((7<<5)<<16)|(0<<5); // otg0 phy clkgate + dsb(); + *(unsigned int*)(RK2928_CRU_BASE+0xd4) = ((1<<5)<<16); // otg0 phy clkgate + *(unsigned int*)(RK2928_CRU_BASE+0xe4) = ((1<<13)<<16); // otg0 hclk clkgate + *(unsigned int*)(RK2928_CRU_BASE+0xf4) = ((3<<10)<<16); // hclk usb clkgate//@lyz to be check + + // exit phy suspend + *otg_phy_con1 = ((0x01<<0)<<16); // exit suspend.@lyz + + // soft connect + if(reg_base == 0){ + reg_base = ioremap(RK2928_USBOTG20_PHYS,USBOTG_SIZE);//@lyz + if(!reg_base){ + bus_status = -1; + goto out; + } + } + mdelay(105); + printk("regbase %p 0x%x, otg_phy_con%p, 0x%x\n", + reg_base, *(reg_base), otg_phy_con1, *otg_phy_con1); + otg_dctl = (unsigned int * )(reg_base+0x804); + otg_gotgctl = (unsigned int * )(reg_base); + otg_hprt0 = (unsigned int * )(reg_base + DWC_OTG_HOST_PORT_REGS_OFFSET); + if(*otg_gotgctl &(1<<19)){ + bus_status = 1; + *otg_dctl &= ~(0x01<<1);//@lyz exit soft-disconnect mode + mdelay(50); // delay about 10ms + // check dp,dm + if((*otg_hprt0 & 0xc00)==0xc00)//@lyz check hprt[11:10] + bus_status = 2; + } +out: + return bus_status; +} + EXPORT_SYMBOL(dwc_otg_check_dpdm); #endif void dwc_otg_pcd_start_vbus_timer( dwc_otg_pcd_t * _pcd ) diff --git a/drivers/usb/dwc_otg/linux/dwc_otg_plat.h b/drivers/usb/dwc_otg/linux/dwc_otg_plat.h index e3f7d6e99640..1fa1f5c886a6 100755 --- a/drivers/usb/dwc_otg/linux/dwc_otg_plat.h +++ b/drivers/usb/dwc_otg/linux/dwc_otg_plat.h @@ -67,6 +67,15 @@ #define USB_IOMUX_INIT(a,b) rk30_mux_api_set(a,b) #endif +#ifdef CONFIG_ARCH_RK2928 +#include +#define GRF_REG_BASE RK2928_GRF_BASE +#define USBOTG_SIZE RK2928_USBOTG20_SIZE +#define USBGRF_SOC_STATUS0 (GRF_REG_BASE+0x14c) +#define USBGRF_UOC0_CON5 (GRF_REG_BASE+0x17c) +#define USBGRF_UOC1_CON5 (GRF_REG_BASE+0x194) +#define USB_IOMUX_INIT(a,b) rk30_mux_api_set(a,b) +#endif /** * @file * From 8476fc265f6a0a10060a4521928a9b42a0e6823c Mon Sep 17 00:00:00 2001 From: ywj Date: Fri, 17 Aug 2012 17:57:15 +0800 Subject: [PATCH 217/261] add bmp photo for factory and del fb test log --- drivers/video/logo/logo_bmp.bmp | Bin 0 -> 3072054 bytes drivers/video/rockchip/rk_fb.c | 1 - 2 files changed, 1 deletion(-) create mode 100644 drivers/video/logo/logo_bmp.bmp diff --git a/drivers/video/logo/logo_bmp.bmp b/drivers/video/logo/logo_bmp.bmp new file mode 100644 index 0000000000000000000000000000000000000000..df5298e35b05decfae43132ee563afe69e453f30 GIT binary patch literal 3072054 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

iMV$NTax7@ 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

WoavyF`nhnoqcb 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
@ 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¬vs;0HMsN7mwU6JA6XxDYNjIafs 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

%+oqZz1pLR`89yOJ(p=C}#I41m(ZI-Mc6+%#xv; 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 z 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℞GX)}^Km_|Duwem54*lbL*)p!i?k&oG@(5x*_T_($x@xP76!ki%g zbL|SYm>-buLf{C#`bASikQeJJVs#vlL2HYDUHK^CV3;}}t-zZ|UaTV~|C0QIxds3ynwU;$Pr*NWJlh9-?p- zIa2=xi{er%t0Kw$_s`Vhe)H2K(j4L9i%|QC<>+^og)_!%QV{;aP5Z!XRAA-BATV11 zsy?*kUx@f&B*ljMhJROHrV^PRxq)9~P54(|-=? zkSPCxlkn`9*N(rs?y^JyRRJ^nTQZeHISeqW#uD}$WIi1Yw^UoCm58$n5|@|->q`<| z4So3t@f5T~gUYZ{_PvlnV*HgycczN;Pv6f`RhVGsEazxw2~|T z&ZJnhVL2NX{xugC6iok+6wpRP5c_}d z3vSgV#h)knGhx5*FWbT|6zmG)chBSMeENfnrvYSAMrU1M7hk(e@GmPOxkhj&_c+zF z<=^E41N^ejd>~686^cP%<9}~U!DUrFnbWmWvrWW>-%W3v8A#BW!l{}6S(oMm;#qE+ zoX}1?E;@sMm`i!Wc*-E&(v}2*~+%LXUFUN_?N+Y zVQ+W1WG6#BS79^MD{R>egMYJH1eSw_1VoIn5m&L&wA-JKrHf7`1y-B6qD1(Y?Kbve z)zpls_0nnoR4KZX`y>s29KnKuPH>OTI(BwHFW{JTgN>2_$iGdtEW*dkJ3m@Q+k zmnct!b9@?8XRpE+TC|MgDBO|Y-@z26QO>eL4c^q}zBlkT zHMGfvae{5lHva~ls{alG3LiCqR|LKnekB_Jj4YHBsvTEVlnh}Ne7IH+Yssg8T^s(5 z5_&)XhJ1Hje+NcW3sw$}Q}lpeYQn$pEP^j<9!E-aUqN1K(~s_iFDOX&Pb;b?W_5%x>=s@z$(XNY*N^9uq`3YKS6gnhK&DfluE zz&@aQidBvHViV-cm&Qzj@-9%xPmpi2&^qozO}=V>plI=x7^{uZlo_IscE zf1}93ntpF0=~>FP>dHHls}^Ve$vBQ|#~z8~mHs z#|a-<`#U`Fyez&Bc`tbQ`~3HnkC!A&LwJ0TVv9y>jZ8wNEr6LR}f=MrAw zg}vT{(jJ3OBZcne9{A-}>3>Gp#XM}EV{h|9@)FpUWd^SvEDLob1WUe9ZM(ZtDqZf} z>1^SEU)to7(MfWcLT^c^@5;t+=h^-_Vh7uib=zi_*nBu`0bQ?jSy@PRzY$hBm#kfUr5=soGfGU)ZSI%xio@8#*5Kag`$>K zO{|lVWl?7Jf4=qf9w3YseETela5Z0-ykr@UM8n}3sDPW*ks#mNiW0E`@pHI9vk>P2 zh2$`h@AW5k-um&0%Re~rvwzxo=^u73{lm^H|8(NDAM9ND4~TgG_LGNq2*Ep#B6FJH zU(>YW{Csi$UG!fSA0qo$-vkZl6ybP@1U&rkB|uom$oHQ^tsc zsKlla3|w$%Nsup?19%dc87EaFKVo}{tJN z^e=b6`M+<&!T=yd2}MGkMNYU9@fY|#{q>0db^YI{v52aW=E=|AJoS5Hgpp8P#wd}t zTw=U1pM_H~j2UrO5jILL^%ZlEzli&EayyTjxu&p8JxdX|hxgsVoAcMAS!Ycp4!IA7 z9sag9rUCy2Hz7b6u;pJa@QV5DBNIIuP+uZ;C;R+Zb!?Vuk%Ob`vpxLeb(R1o^E3Icco-mDe_R^OCx=4{^?i!qTuPf! z-^#XU|Bwjuk1vz|nX=NA^SHvo6tvySyFCBA4iEqCGNsJRmWQ9!v7uUCA6^_5_S)8Y zOT;99<`i2{cPsw)ZzE^r3S(m60W z_Q6H63hdlD$CfFw1_E~xG_C@ByATrFioa~hq<7MOiL_TQ9Ft@(>8%>L;o@s}m5`kv zeb>o5&o%`#Gkf%D0B`+a7WQtOVFY1&#fZP>cPFcE6E1x$hehK~Ia1S3xI1*k6elE6 zej(o*XAkMmqxRCi9W|GGEu%wHAUes}_?LM5$im9O+#!Xbhs?|jD8|}6#j;04;{3Jq z^Davrz4#Dq7VI<%eidp+syFFeb9EVJkBVu8GvEHRk^2)*~#p5&4U53ncp^y*Bm1z z521b)D0t@E{CCnvyZ+IuOyd*bWr8d@sx7sZjJQ8la;O@uX_{G)Q*-Y%C z6ks?-1rUb=zm*cY#Z<#it3rWMr&R`VV`Xhs*3zp1=2fxufL~#@s_vrZDf{XWI8SLS zMk47a!oS$1Sev*&v)V{8cA#!?IMykKC}yf|&oxkE23wP}n^QT92BZwM%;xw~?!Wji z`*>N`B<8A|#noAxy!()8T53*XSI0PKyNVg1?=|4>gWm_XlU#|w-=Su-;Sfh?3OmBG zs{`*o^&K(@q3{j>nKJG@ND?;Dr!;IL{6>reRoZOSlwn(0$PKH~24aGeEJ3HG-cm1T zg|NKaiVogJtp&Wag#;YK3{$!a7EF= zZ+7_k`il=Jo|XQl`MnCWUNUboetLcd`Ik@m_5*0a`IY}a!rt`BuH#Je18Tihg_WX4 zEp7TLyB4w~((pO!c`^oXx^?iSq4H?+LQTY_ABn0R;K?zqA1HTP{HAsek>v%Z9zgzDW|9T-&gc~Ou z0!h|?S6Q$;T#Jj%%Njf*<}x?~t#oz^jipi%SWxVq05AN@_|GnQOcvB>2{JQ54DXne zm*QW;FUzycQ2!17WeP(bR&GYC!)-d_!~k#jH}y<;NtcnybYiab+}ik8)2`Q|InpOE zt85<3o(5Yw1aI?_89Wsxai;#f%(Tw&4lYLg9oWg5_WZE}OU1u?3jbnGU|L{fz`w>` zZ9hTF&;i*e{reX7?Oi|_B3U#9Dr(kBek_~;cENCjFQ!qfBe^%T`Gw(EX+L4@%D?h? zHYUq7A~Xz*;NUXMC-61~n2ofu2S-dV-b%^Kp+odE|7sWDCE?#5+l8>1uO$!Q7xJZ! zW!Q%TGMRsA#B_vzd)i)P#prRi6~r2dFtMM z{wO(}l*1WBtr?!--|(F!PQ?X>e@P()y%NkD-UK0WA%-QZ^D{t7a;iOWD2)+S(NBk- z-%HV1+R2xc(efxJW0j(YUmhO;z47QKFxg?bxpEMd7HP6L9>27g9gb+^B^T#&Inq-t z7K_!h!_K@*OZfvje+-SBOFIHF^;|^%MHtzzk9T+DU);R;mqGp>>Mc^cGCa%YnJH%Tu{D>5O+y=kA>^-x6=;^H-@ettl zfR2IL+$Z2Iw@p;w+(I04Yo#$ zeXMbvTBA?}_6XL_N2Gk$roa?uz;m`|1^#c49|-(=bS3<2cWBU9h112qXv)V|^b<^> z;9oWtCoh)xR|{zPJfA4e&xzg8svRAO3&u@a840v6l7}+w@6b1VRqLX zMBY&rIh}@rrCO${z%RP+kkejevSa$o42U~473M_dJ_>csiPQtLbq>|^3bfXRV)1Nd zUKXDl|2p)EZtyG}n4=5-vfAwaN|QxnF4f^*CT>M1c?K`DISgw?Mi*8IBm2q)mTgNU zt_nsj{0rO0S(-nd3rd_-z*kDhmpT;%e}#D~5tnY32_g++2o?UdHH8s{_!|zzvI^3w zf^BA*gZ@4E7m0ySjA3T8O$>`+R-N&}wp|dGx?xj|ZrKw=Efh|7d>ja@)A?V#=LjY! z`b$!%`R%A6TZ`Axl_ zpkUy)V(cVnjsLR+Vu5oQ*%yg>Gc8GAB?L}!A1)%G4mGFVdAFng68RftnHXN_zd81k z;TgAKv9Osp+HP35>b&|AT=K1!?}~5OU$RJqZqfOJcSb{#_|b>+eE%*!!TXMne1Z_t<}>#5AYo^9#I^qoa)j%u8&?j^V+PfM50nM!NNi{i43z^GVdn-WEd#mQb)~@LR*4 z5yJw%Ag!rZzHK%6XWBU`1&Wnlb?fBFqLCEP*j=)$Fqv$9fxxujVn;Gk3XP>j$yJCl zv#%Z5t1S42f+YlNFJQ~QhnBGUFPnf+*yISaP=UIR|HVqABnuWtHA*yDK70t|$G`6W zkv((1b9nihr}plC`NWZ*ojLLL*@Lg1T=&$@IS;P+n}Z9c?YnRA!2N@V7watf9Acp2 zyGZQb#u0Wr5&tR^jvXKs1ISJ&!w;;(UPbQdc}LNpZu6WB|3(z1vG?#Min3i{c#~Jw zalr{cjBeHJbIf%L{?8cs6xsi-g8&h~+DmymI|?{{&T(~az#9=w!M~6N0x@s_k64cj zk8lKR#kL9%CRHz9&8WA3W%C;Kw6H5TS|WTME-Gk3)iou7NaAAJ%}oJea0%sc)=T5` zpYh}Uc;wD_aeM|KCI{WJFAsGbp3yGZ`3OJ*yM~?c83e|y8dyg01p2_{$7h~D3~$mh${xY$hU2j!f8{BCjy~gw!yN;n z$rR0r5o*QM5@hkOrl1saN>7ZeMvD0wUuZ6_aN`l2yrA_x@LB%jC2Hg9%$Ei@6ZUIIbbgu=y$cyX~mAuvH zSSu0`uKS07Ipzn_21)n;IB=WQj8V2;LVo?x4yC~2CixLuT*x=#Z*Hd?Az$t*+Bv39 zg||RpO6$X&Nzon4Y7hPi$idmD+J5^<*T$`@Ky~hO2L&WG9M6SZqq%P#9nAB>$`S>( zr5@&`4jogX1qXXW$3bI`JamH(tsOkQhWzb3$iwVm)LFTbFUQH%YL6p_a^J1)aX~%{ z&LyOm4Dd>Yr}$s(i}WDgAY{RkLkPYiO7DDp1qf{Yx9~4s(4@ffCgWt=TP+`z;4LoD z4+xOyAP_!=H_IA!J}N_*$2zU}IT=3K8~%L?L z?3QqGrbybUz^BR%ZC9&ImuVM1*NHew)=bt(ghhMUIeprKc4l_@Q5$}FsYyJduuq9q zAX5SB!gQQ-h1DGsLgojy3a-&MLa<5HpOyK|vQ=29&ziq{iG->;|?u{=PK+1vnfGZ zv2ED79tFQ}G<3|Bb1C{5c&E5gVlh{<%3LlLcIHpA^K;REIek7Eu@ILP{~P`d0#hd! zR^k184}8^z-y8+Jq20#3{&IrMjgIxJ(E*mE;;&BMpf7xhB`mY@)ctEH?xNY07EE5$EXOnN98a+x`da@@5Pq$XRh+jxLS7EX!OB3x1Fb0=Ji@;5$c>ET-|NM*NM=TlfEE7-^%B1>$crUX{JuEclk; z&itED4z)0BGOU?WHSSIJjiE!v!w@dVT!cookX@ltt+3ZaG^>t{bJ+!{Nx&JXH6UB_ z9U|J7ft|tDOP#nevrV2h(W_CwjP{g9$IKushh{~T2_h3mrWL8cOnJSoR)Y5THtiemI5_>{qN=*mm$4tu1 z(V4HisGB*RmQ4EXB`uAba~2)g0%`QX;!$FI+2mJj&L6-v@f=%B;t>IF-B+<$8eVB9 zG#J`-o=?-Rh#11f!tp-8v4SG|N(-=uTQ~pJ$e|Ujr+~M!J22Oge2fGf=5_i|Y%L5e zju>MTZ8@EB}Uk`;i6?EyewB6skq}MgKj#L;-OwpstBkn`y>lP%YV5 zlg!Wia0tJ5VDmlqJh1MCn?Jq$hpQj`?#lbW{@~)T-v98omp=UuH{SW(hbJ#Rv;3Le z)ArmuI6j{QS@==Q@{~EcdeB*JhS7TDu}rk@dfUn5fF-jl0ubu(TDe3zevl*Gg1|E# z-$qHaFIjO0an!_x62$8M*@I2Y|g0c6BYRIe+LFQqv`BZR2{ z$aHq>WGd!aZ2^p?HshIHQr4{evN@43_L-eXZ&7%8NeJhRXLi$vT+oA0ZlN?_X|zH` z8lQ7pg>Ye8Kp5a9t5syjR*&+_OVBC&g`}%=#F8mX_G5*qB43iPn8a4>c|^c3oA^L* z6i~~ZA!YXQL9_+^kU_K05#*ceNN+uNIBBDXp5HV0+-{D-$yeY<_%z9%1(>1Eu&THc zX_dI$*N)D7RWM62{|aMqONM-V_!!ge+~HyLVg(c*;1s>ZrL@)29{73`W%m400NMK= z6(4Lqg8h%U4lF$D)g!RB{vJNgB5(MYm--+}(&+&9w%B3X>A*k5-wfL-&$Ir1{vG}d zINi?DB6l3850>y}z8}6reh5pzQGOfthI9E=1HYhda$%L<1wOSLpKm_rvNWMBsPbEQ zxr3j07SY7y<;JI)9g}}VG%?!&v*NM0OSs*;CDMNcV(zyl5OZsBz0{d3g@WQl0plahsIFNTpxvy3p7XqsV^XtZg3jTpBp{|-{uqU%Kd zE2bnsI3YPcQ7%b&85U-SVk7%D19m6J)H5fxBaPHEIc8!_JwDI8MF(cg%*8YU#nc<~ ziexLXQqRIQ*9ki_Wz*QDW6qVqV9{CEG~pKKXR~l-e0@4g?tG99kJuO-Q)F)>^A%px z+wa$+{pKHH@Qf0{v~w;RF)hMdj4Ow9jo{qn%`C8L#JMc&vq6UQU(taUj@Uw&Rk5rl zOet#wvZJhJ6puc57PHDaZ_GK4#jbN>xrj}>z^{%5TaK~!bVNF_0Vx~Og^D_01Y-C_ z`6c0%mET}&fcK7L!`oP=4T_uc8!MM?n6)vOB>>qf&ap{LXu)L1QlmX2(;3TIwluak z(h}`9%Q4O+?Al_d9>X5fT}FG5)^8Q_9z)$lR(RAU+|@KQ+;wNcVeg^b5-7hqnROhHS47ut<8bH9O?C}6ojL!H2{`B#dq0al2b zIN$rG34XuAzXgQp&lP;-sKeo6eH@?FHpI_59r-4vh8>7{)h8zB|` zmD@8~@VvYF`3GUod>j7XyZlRC-;940fhylj@YXW1xYZ>;P<~&X9ue6;L|IiZ>gJ23 zvl{s&3nq1iw!HtXrkt z47u`G`IozeZrqtExw~lWzElTeubzb(2rL%}r`~E0h#n}Oo%W>oDN}zxdOU#I>Dytv zJe7LMQ$uH-XdX|WE9_;-%b?A5^vqJPPx>AFtFr)V-sP+~jnsuQwbSTjw+O*)@W}|n zyHi(56ehh@ad@t2oLdq<#q?GmUc0ycvwLEFD8eq4r{(8(}*{rAQh)+HxXO5 zY7lTO`zD_W@OuaUg20s4-hh`Dpt!wE2yiZi`Gh4V>npiKksGMDRH7AxWtB;Z&|9+T z4!LwF7)5yW*h+0(q@6yb1>^pw0xWy~-`J4xg?5Yd7xHNJ?YM7j*WB-&Si9%k=}-Rs z&0qcV=ePgy=Cv=cUH#3+H~w(_cmMVGpZ^d4@b(`*KK1^ye}81z2&u7-EFol=Z8t|w zuGM~>MC76JAnu^pJ}A#djtU8sf8!>K_?JfOxy?>S;RSwYKE8e0*)8mIRK%%=H;jpY zX|=Azw;DXoIwh0)83KXD3p&2Qnxc(nS27@#>LTuOFNB+7ZaN`Ab8Wa50w^|8fd! zYyKU9g~3t^iMe>|#l5810=?b&;4uG@wnKt*OW~Rlf6qhHl5rdGQsMNxgnU!lU&Y@R zE~Z7mF60OQrF!G74gZcHVe{{>0Wp8Ti+jlet(4cGG}k04^a~20Mqv-hqUUxM-asym zR6yY1Fux9cXoQ7ZdpnCh5rvVJ>&k|9M+*EZ`Lpw1!N0(4;aLX)bI;J&fH(JBdkOq< z;}tEKdr$PbeeB5{lrH>o54R;9Kp6OCOD`UWXugqs;~K%8FD@oJ_^BO)00(>9Go|Gw zhX7mWolu8^#=J$*qnC787J1>^uktUAUj9;=J05N8zv5r-f292IWWLHqNO(c(CCvNK z`srtYT){8NpV4;Pw!fpN;NlHqr`DtJW~prik8Alqi+=}>uIfL6Tg!?p;&BZB;^-2k zSnz8vXu+?;K+uAF$5s*^qLCIi8d#`|+_+hGzg)3|skkLjSc8>_Fhcybx}d zWV0U2F)v$Ve|AA)=U;7P&t3*nS~VfsBf8CiZ4zwr<{kW-mmD*h(w~_ZCY@sb1zL4k z(Ab%^Bd zF*tI%0<6esFUbxqIlvLYv`p|XeXyx8hv=EW zF^-mia}29um5F~1rx;X)VU4;ny==3^Y~v*->fFGuC5)JMImW1qbyoymlQm|fa;1{j z#r#`9bu#=4U@Zs79F5vb3ok>sNX8}MRaJyz%I002ZvK^#Y@<4m8@$C@rXv1D?(w@3 zlCYEM7F$|AnI_yA?Lyr|3fsJI9-Fe{QMkOlkxcpy9dn{A|0esIh0~d%l4u!HxBdz%A?+KtlpUQbku<+hvOGjdO zv1j(;nYN($He=6#u0-`xwA63rrNU}|gWpKNF@e%ZOJ3#_5wxIKQm^bTyFhc4m4z{e zQ#AWX;%jX*rd*ec2h!M~0OMi(Y8bc%%FL;+hF5&2>e+L;hz z5_7Tt$kP6O^QLb6?%y9>b>{L57k>ZomEV5+-i`O(`Q+XAZd|%}^MiM9UApl3<;%an ze)B*5=H1_2-Sq7Eto;&}Yb4njNG z?U$Yb8II)38iq$2=AalFbsG)?zsdG2HQDd#EL3JvWBq8?@N>I{p4+8V#>k`49Pz5o z?W}NGZ)P;a&PtB<73uX!XAeTQijY3^Ba_G4A z!Qq(*<&o!i^Ud)8^1ne zyvz}vP1rB*(!!CrV8X5e;qWgm@`$1&i?yXzyUY-J$gSeBq!+8+0F61a+oF8}= zXn}kw(Q|=cDgj=Od8`7wp<{&L^l1;>;F)zaDh1XfntG55hIyR`n%&0ne`duDk7((?EWxo05^f~s-&F(bdwv9u=+)YG97kpL`8~0^ z$F@o*Rt%DYo|s>IN3#Vv+qXf!fnWGn3wo^PIp~A94@Sr+zh3BDNsIYc zQgE%&(0W99u_)BDBhu)x)kL5$6l-ykA=(KE8Hz^^uNY+KDtjvZP`CM&R)REmAX-H>a7jEh!&5pyH&M)M8! zLcvr*&8;Pkh{d#^|9U$ErJ@2q74idR+XISujoC1hX5hC?g=yqSJB@8_)hTtJg?uT> zg4JBJyn@Y36~if0e4D%FtYxWJe@UfaxmwxRD@-l(z?K6i(qHh4T~Q%d1_mjxNVaLW z=VnF7kl+)m1%llYd!`*}(bBzHSmcXMWz#4Y4o8_uXv8s=u&=Bvh??P9GptN0TVk=w zFwAI|wrl2ctV<;7a*__MEN$*DG;VoZN%8@rxnUI64ZOkWzc2ki-4i5Wt zPLY+45Zrcb;Vu3QKGfzq?ZuLZa~lFT>zy5h&A-k0Q&zgWag^P@%$cvqms_zyI9%(3 z-%2Qh#^f$^2wH20080QQFcq~|jAIRvOQocpqsZ6r%TZKo&e8?BY;(TN>4r5fB|w8` zyUx9k8ftHKc-FgYbw zuR*vdx#r>tVYjUq7-k!#wo3VF_>wz68I9c^j(U-3{nNxRUGUreeLKIJu9@Fd*Sve` zQeF}`T#C8KgQ}ZEo~%3t zz%q|g60J{wGd=x~M%(47)U%ltq|k0!{5+;l89nN%S045pMZq3AB;!^PW-wup0d*%v zm8`8Tlm*Jt5GpRuzhA2`WO{8FdBGqW~QPT z5XbW}(q?Qdds+oYd&c{%OiGRiQx zsx5#g@h=-p$hsf`i@Z|s?|%4KVB3no*8D5~H*60U_N4;Dwo6HA(r}nYOd#WP5sm}D zTqk{aiwr7kpMhD`2mBIKoRlm!$z*OJE6`{GLi=TKHKXw`yI8`o)_+Hjt{5}_k^*b! z;1ax`2edU(L14PElP}r_%q#!Engt7SL@h^`^&MW)w`b1q=6jYrvg5)ZuYUPI{_)c7 zORv8F`nmVtc>SYy-}vO>YoEOL$|rBX{maY0`0u~G`A=V*dFz>P?w>z(>vskYEf_w@ z-kpi*+t52r8XWjnX;K zidjw~EV{)_n*EPP9xWS^VuVvrqpGiQ=t#s25m;vb8fbmiX=gd{V2kg}hV z`1gs;r0t!~MnX>(0WO3h>?ODoxX^w#WUoRIc66tsfM>AD4%-zywR8B1qVWMT6YvY_ zf>F_k9V;3&Styi5SRA!=(QY=Y%|1RLTT(U&W~t-)i+YRavl3F(2w%is`1i#FvtMHS z9!35_c^n}@ie3_RTVr)0)~2O`mT?sxVKZNc^jecGQM%z@119du=& zQ5LW1$k`Mm;O7ax#y{EH_?meGxuM~RnU&vPrddm@riO7(r zw9^`}?x#gU-UY7RGA#Yq$rCIAM+g@7;!4fH>!DRKCWjOwjFL+kbq0ovz=2o{1#lOHWo2@Iw zA`7sfE@3zj)btxSaouWia>PHYovCQWs4pipK^rb1dc zs@j#Y zQUX?)EwQvb^6%+D<-13n0M1bmSIy;y8P>O zG+q9cb&APqEKOakifwETl?03hi+$VVV3;=mYyO2*r3%#$U@A=;l2L6>OIh00oTeq3 z5hi*(IkO8ACOR#Je=T6ehF3SY7vtO+o|E%g#=I$@NWj?brsLu=UH3L>%o{maj8j$M zKu30EO?!cka8209oT7FbgFk*Z{0k{dzstJ-k@+k9E0EzOXy)tSbS+#8{|4UzbhM<= zI&TYog?z=oCcB(v;8n1&JbtwuQsv*cC$@;ILvjtaFO){eWEs&(r+54cm22(hq)7c1CTGvs~^OhFZ*{>mVA8*AS`$2 zNjfjTdt+GYyqlK--Ym#)*?hW}V)UnWPJwo{?NMF2iCCO1fb|6NKzZRP@T(`N74Nd0 zCre97EB|(gl_fgExhx;?Ap68T!de02LGy~1Dm-@%?Qd&bY1BaB=N;D$F>D#>dj7O-W_ zFuu^#qt6C}%RpN7U#_pg(<3d%jF!5-2WnM9%7$Fwhtac@DOUq zA@=0e#vB7|uH;Bz8j&^}|GRty)IGGce|*8zeRHSoozu5xuFD)OtNsHE+45uP$Wk&~ z;rXoiUn1!cQxII@D0qTBG-3Jq-#NBw&&#K-{`uCIfBC~(*WP>e@;m20y72PlcVGVK z!mFQNdgHSX-oE|Ohrjyt`ak^q{o5bje`rbH`fm&$oMm4s2O-@UnQJkD>1R^GS z2$xhmLuc0E>Kyo$7qpdME+PY-z+rFQJHqktZKG_|`?$6V1_yu$k?d1S0X_WK=HBBI zTdA_)k({5at8;KTJR(n2Z9qc^Fiz1sdQWc~dU7kp{?9l+v;WZ^w7jurN%Mxl(ozDWAqAh}EFdDRrh#B2h67UPK+y1c^_9xHt1o_I9 z_W<#y5g+9~Ejc*n9-1yKSRjmMs$GO80%?hgm1{9Yy6Vdyt@2+X=_(pmd8oXjZgoGl z(h36a7qm+Ab@FGl;Frg7c*gTNvM>3sz+UORuFyzDNP8abSfR%=UpqeIwPQ%Y!^*X_ zn~zH>t(n4MJ3o_9+Fs521IWQeEHhrs=Z{c;ad|kOJ3RZA-ObL{`SKM}$4bB1sOxlk=F z$p{_h4G6~z8cfcY&o3ASUli;TWgoX^JOpr+*Zlw{qYJYD!u`XK?(|jx-nc+#d4!h8 zzEm0rs~aB6&+eZ2?4D^)?F4wabpc+mm$>!rUP!zZX?Wm~jRO^Uc|gLyy7}{rINCR0 z%R|A#MLkf=^OZ-BTv*b1EBWS;)Vt~65QaR?tW6~ybkl#~UkVSnyrX&K846CV8^m3i zosY8l5zLz`Sc(GXEwTqh{9QGy+*Xo+iT{OdOa80lt4TFK3ja#pCEAzqiagRQ*&RuR zl+jLiUp$7ax4ps zxJE06m$X#ggxyP&@Gs=cI4m@VpuGgjM1Z!-$nOb)u~cer#{7^kp3+Pu!0hP3B_rhE zVjn%}xmsV1=QHFh_;nO8jqq<2;W#-nD>coxrM(IimzTirF2nDh`J?+6Q}Bfj)oMYQ zDUzM;HBriYD(xJZL)&yoAHl3AO3lC4g43BJ-7+=jYQA7iX5}ecGdNcZ5pxk1qO0=D zH6sU$i%q+1+7K3@%7(V>s9=@+FrnS8GzTJI8(&G8=L+&e{1F1da_a!x%lw>Md-mx=rOA zg}_z+E!I9gt$9WK4G5Rc3C1*Qzz&0WL<>kE3$cj+B-~ojRnTEalc7=k`)9 z9Xh5nA)-Pg$g5J7pcOjfrF#}Y3o#{47VpwO#T*w|lb*%l)>lvrEQJmbpZ$SNf>kM2 zABFwO|Cve))U{KzUUrMIH<7<(7htQv3jVE*&_J=AqVbVddS^&>*3|piGI&PW`EAM&BxDmpzsvHpN26H}28towxEU*BmBc*_k|9iej* z^2cxsCBU2;wcLl?pV4_~p?_W2@l%6?1QGNlOg?vhR)j*n-2W^Y@nlg^OMO6EB}+-X zm1j_#Tb(i5xx?9;+c>Nzn(LT++mp`Y-%54|Mgo@p%k$1zRSu>?@&T=(xg|%DFT;*U zBn>Ia$7RQ6rMJTEIk6ia3`4jaJ(_t7;HbI|?hwOT0%jy+2+cM|Y@{v+7#0BQ+9Lz0 zV3rHo@kVtnIJwYBkxx#0m(wBH1fgW)HyUeL_5{(qniJbgUM!{$mQR@- z2DX!cq9kx;dP<$G=e6{jl4;9PIhwz`gv(r(D=35~^OvW#Ok~V)3J7AN^sL9sNW0d1 z-BXjS=St19P_3s(mVz@UGV?N->N=jRl~tpzOJ`Ef44xy*o5@<&bQytj4Z@kw+bMjI zoW$C@zARENOYZW2-aQwSgJb{hIT#+=laZzP1Ar>bJC}k38^wkSim>*u@UlO3*8dl1 z-JbNzTFh4za1;S7qNKo*I^f({+9?TBDhh7`$IyInvC~?$kZspR(sWQ?`9;>gumgU3S-$RbQX7*$+o}Byn1-y^aFF&KC|!ah37u_^(WVV|I44< zxcu_fi|0PM_|t3ezxC%Ipk@=aN&*(lX!>3md@zzNY7%tvC@-RF0Zc>D=&EsgnBHV{J37ql3bn<5e zCa1u%39XGpEfZtUW2h?*amyIty=OKKA{IZkZSX8ft~McNO~*U*?1tW>>xUmj7iMFZ z^&r6DqhtiyG5Xl{u}8P^5i-cpt-yq*@KPqKSJAtpB;Ykua7?8qj*!}mNGFN5dZ>aS zp%R3-Xm(%=MTA06G+dWac3Dyy=Y4Px`kiPO)z8=AboNwg2+UiMm*5M4ZON3#o%O=L zSwBI4)J8m`$drKdi~FHAkT!eTO51ggDao2{2Y!);iFGwQ6BWyLMSH!yuQE+py@fjW zshzEke!NGl4Gg|=P(I18Dwr4K1U6yJ?lwczNgf3Vqa(`=TVSga@Zk@mxVwJGVDIA68{Iz1|Lo;xbepRY5 zW$ZkB4a~ABFqYE`8v_gRS-@VkJ3ZcP# zW2`WMuE}}Dw=FI<1^fFK)dIp`Z;+Xn@>d6DD=90vH^IC$-8a9l^j`#DT(bF51ivJO z)}BY;E%!k1mRln7Zf>DO{?eEZ^hpQ$0MWybZy9=Q^N@7y(y*R!Kjx~~KZFc;_&<-Z721Ov1|C>DC^>lj$jJ?(N*%v$7`<5j&nt+h z=rLlj^AQ^%;UJBhG@JaMAj#fZj!6p5u5CE6;0P^AS0fny&#OjGtnD3Ltt<*`;)ahj zGO^QP$^Y5gqay^fFOqy_NQ^+E3hJ;upAEkVz6`TC;q>9*Y|b4$vXTPodf{=YmM9@& z-XfXvzQqW;Y-We|j(`{VWf!D_%hiWin99ZM4#3(b6zo1r2EkIilExRY)e(eCPo@t= z(6FHDee_rzW&9sKxD-;3_{#*;kBn=tX(k=8w~sx4q20PWl2qV5^GI8v{+a=`yv%&Z zY)A+&?^-6tcY09|7i+lNJj+y=l8H4lW6q*OCT=)4ExJ@kO6K})cINafM5m=p<<_9X z)V#}Vn+0vGg-I^W_JWQTQ6yt8o)=QKO)|0PuiwH%=||p`L4tSLz3dJ=iE!=478O9w zZ}p`X|FMo7-i6u2TWAD1kz=f{a zLV*ro1YX*nkIm1eLN z&B7U|xsk7V7RUl;(3KtvAb#{ao_P+JxhaJk4k+Ki@) z1Os77_6%C2(<6ooC!>(Ek*>S-(PzQk(Q_5;TlL>~K?itg&+bTl4iH8f7Qo&=YwCS7 zDKM|FmkKQG5M6mJ&w*Qs+clU+|DAhRAEmJ^JwwnA>?OPxa26m#zUq^-SAg>j{Z$r= zBM?h6cIi4%vtQDk{A;;fUuIoWh~}FwM|A8jlMWO7>u;VGei!|YIgv)U2dFuH3cE@z zxx0TEYH!K%&CjGC+WZ?{*1eY%64N)AQU~`@HyUY)Z$Mm{>um<%PAItsVR~}6borOR z4K#*%CDf*9pKEPwEvE<`qUg3fJ2+SS!D;-PhX}CMR@(IRl2IXF*V94IODDOyo;WW( z(VnLd{w)uwpI>=LSLL^@ckx8$k#9n98B93E<3m80F-JoUEp-@ye9OXGxHz4~zaGJW z-!`(jg0?IE?GB+H_X58f9-(0KuS8qc12bTHZBXZ$f;rNMl9ysww}*nMhktYYYGXR< zUC!cMRzBxbXj zaql;G{&4z^dxmy?zi-#~rtbN{!1%m@LyJfU?OBYCMzklKS#dog1_wLOP-n#z5>mOaX^7&_9{PXXYKCoiy zsu=_O?;UzzdG8di&iFj97DE;#i33c z8wBQv{Veb3hlIe{ibXz|?Eg!2FpX%+I6ObHLHtWlvXJ2Dn%K1)a639&6t(RCO(Emet zTkqlJ5d6!^iSGe!2JWuu)iIu%ikEbe zA5okyvTv5N@=zD2jz>1d%|i=Wiuzwa`p~8n@h^J;JNXs-3;d3q+CYi`OTZ+y0)AKZ zh#fw@(l{*s?Z;hNxSPOi>Jw3Ih|oD5f5!GnK$$JX|atQMRq(Vx&5nRwu^ zwg9GuHN%mk%as)$cW9hpj1uH4Xl8xAzI$n!Wc(KewxCY^v#OXPq z9B~SkIiFqy-)4Z*BoXe+gH3Pe10PT^mL z@mk@i7pSsy)He-%g4XCd`g3XZ^?ZI11n>Ut~75s7?j%L`ft&Wv^ zbGPUQsP};GjS9R0?Q-*Y+oO{CId>7aQ+{r*nMnUN{Pt&Y2E^uux08czW)rKNF0}X~ z(V53Vbt7;d9D%LbHh3$Z*5Wrjk>x{eU^E&!?rxv6zYNB zyu1U1H6V0{l*ziVMxl%w9%t}N!FPH9_+9($sq4PY!W{z|BV@+FvWQog^=M~Uqd>KE z(0U-)8!l!TG!$n%u}A1I4JiyiAtH9hI3S@XP#?de}CNv}o!fo)dIBzuyZjGAL zO~>hsJrL9_{k=$@nO)tOtR?u)m32Xd)pe3z?O!ZnMt;pXJ%s7Vr``FguN45+-g2J_Z?8%*DPi&Xf&1Ko2 z^w{FQL%4j;C!IBJ)x(c&lLUNr+t{PqXFauZ_ES4&l0;XSfcVP}zgvdLc4bXX*h^@n z-AWPHlndJA3y%azQUOLNkZ! z@SWIyHrPcA6~Iaru$N7Xp4~}yXmnnfH)?O=-?&TzcZB^)1txqD6ytq-c*_&8-y{M2@OPveyYfC9IW)ox${PJCyf+d=h zb8Pte-MB{2;ve^S&Tk~qwr&JWC0@|&r=f*k%~{KoH7oqf&nm4S9ohZ>@c~Fnes^vF z`e=p33nN)P3G;G0Aq^uCb4SsFFFnkgm)t)FVZ-v%yYNiNz1p&1fx4)`U~Fz+-qkKh zH5W8)&lEhF;Z_Cz@-F*=xxWI0x%n*$^SGh^;^#cT-bQtI;IMG>h{mU4Q~~(j3;4{s z{?ls)aPuIe9m`7WQ&zV#%hFcRICRYV74X~0SMbZmzK-4O<)=QcGn1hORJD-JCirCg! zu;Tfgm(3kouGF5Gn6SjoHJOzf_mi`69z~lP$WyvZi%hR&k=e7PX24oBhq{p#VJ|av zJ<=^jEndggQugF`X;GtLnQp2}w-wcLlr3SiAtnUJLc0W5v9YghjC7;kMdLJT5uT6J zTP1Hv@K#E$Td07#6pS2b7oWFc0=b=+yhTsWQa38L$BOA?)Qx4;)g3~|XujcJ?5o&X z4UMtBWPoug-1)3=G&-h5?O|cAUnw}q+_&MogPRo=r%W<{XT%pfF!NH*isn`-xFbrS z@yn<@=^XNH^}@gD857sCFA!aHAHPf;len15G}?fdb#1{&-jbNp5qztAGbXy^DjFT( zE1SO>_Ee%tq4~zzmq|~NTx$uKo}5d;j1M4V%yTKo*C~m}P2{&o!28YqWja^a0YEAW zrOr!9Z;(q^rXJNT2<#RJB@7!l5~!vCGA7nSOs)&Qa#kZL6Io$c*fwVcU13mbBrmm1W=Z36}z*F!ymdmk{C(~}FwWI%5XXEg%_60`m{cHRy2WGsN z5r4zKtDfWxDb3)_a4&mxK;)z2YHvhKA zBy2nJ(oawxD`;0@E@%0Xf`(E-JQItj0a4-#lbB4`_Uhsag6 zw2vHCNE>Y4fqjL4-L854Y=gM%zIzU@-16+flW#up%JrYU{mY9lee&AT*UoNua{T^d z>%PGTPb`?@N@sHs+Yf_~J(6M;4vsIFH4gtCfBxh1mwpBR-hBPj4`01``Hh<&;Q9Q{ zwF~dv`ta?WAG~qxy_Y}y*@wTn_S?VwaT)n)md)txpF4Vr^fl{<)FZ{K(q55y1}{gI z^}z4QnYF{G*Y@izD46|^)*|&1?Mn&y7XGb5lD(h{|H>ir%!cV_w@iP`0lb9kp525F z1^@OQVK-9JJ8vJY{5#5JPp%wdSEk+fkC54We91I&<2-_c=+++m`}p>m&+M9o<0uFK z{}TNB6h6#b3G&6WG{V^({Hr`g_CWjxHOjrfpk$

bncKGbB74AUBbWI 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
  • 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

    &HzZ?kDyZ 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

    dP-5Gc$XNm`5}Gs{scjoUx5G| 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 PWiGV-itYY~fBgReG}zsQ literal 0 HcmV?d00001 diff --git a/drivers/video/rockchip/rk_fb.c b/drivers/video/rockchip/rk_fb.c index 9e70bca3f1c1..fb1a94096c6a 100644 --- a/drivers/video/rockchip/rk_fb.c +++ b/drivers/video/rockchip/rk_fb.c @@ -379,7 +379,6 @@ static int rk_fb_set_par(struct fb_info *info) u8 data_format = var->nonstd&0xff; var->pixclock = dev_drv->pixclock; - printk("-----data_format=%d\n",data_format); #if defined(CONFIG_HDMI_RK30) #if defined(CONFIG_DUAL_DISP_IN_KERNEL) if(hdmi_get_hotplug() == HDMI_HPD_ACTIVED) From 67d9247a137f15fd66c3e5b310ebcfa94b69e3ea Mon Sep 17 00:00:00 2001 From: zyc Date: Fri, 17 Aug 2012 18:01:02 +0800 Subject: [PATCH 218/261] camera : support arm and rga to do digital zoom. --- .../arm/mach-rk2928/board-rk2928-sdk-camera.c | 6 +- .../mach-rk2928/include/mach/rk2928_camera.h | 19 + arch/arm/plat-rk/include/plat/rk_camera.h | 7 + drivers/media/video/rk2928_camera.c | 2 +- drivers/media/video/rk30_camera_oneframe.c | 603 ++++++++++++++++-- 5 files changed, 572 insertions(+), 65 deletions(-) diff --git a/arch/arm/mach-rk2928/board-rk2928-sdk-camera.c b/arch/arm/mach-rk2928/board-rk2928-sdk-camera.c index 02f98b8b3f47..ad549249f5c2 100644 --- a/arch/arm/mach-rk2928/board-rk2928-sdk-camera.c +++ b/arch/arm/mach-rk2928/board-rk2928-sdk-camera.c @@ -2,8 +2,8 @@ /*---------------- Camera Sensor Macro Define Begin ------------------------*/ /*---------------- Camera Sensor Configuration Macro Begin ------------------------*/ #define CONFIG_SENSOR_0 RK29_CAM_SENSOR_OV5642 /* back camera sensor */ -#define CONFIG_SENSOR_IIC_ADDR_0 0 -#define CONFIG_SENSOR_IIC_ADAPTER_ID_0 4 +#define CONFIG_SENSOR_IIC_ADDR_0 0x78// 0 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_0 0 #define CONFIG_SENSOR_CIF_INDEX_0 0 #define CONFIG_SENSOR_ORIENTATION_0 90 #define CONFIG_SENSOR_POWER_PIN_0 INVALID_GPIO @@ -71,7 +71,7 @@ #define CONFIG_SENSOR_720P_FPS_FIXED_02 30000 #define CONFIG_SENSOR_1 RK29_CAM_SENSOR_OV2659 /* front camera sensor 0 */ -#define CONFIG_SENSOR_IIC_ADDR_1 0x60 +#define CONFIG_SENSOR_IIC_ADDR_1 0// 0x60 #define CONFIG_SENSOR_IIC_ADAPTER_ID_1 3 #define CONFIG_SENSOR_CIF_INDEX_1 0 #define CONFIG_SENSOR_ORIENTATION_1 270 diff --git a/arch/arm/mach-rk2928/include/mach/rk2928_camera.h b/arch/arm/mach-rk2928/include/mach/rk2928_camera.h index 733a95f5e726..bb0239343d29 100644 --- a/arch/arm/mach-rk2928/include/mach/rk2928_camera.h +++ b/arch/arm/mach-rk2928/include/mach/rk2928_camera.h @@ -25,5 +25,24 @@ #define RK_SUPPORT_CIF1 0 #include +#define CONFIG_CAMERA_SCALE_CROP_MACHINE RK_CAM_SCALE_CROP_ARM + +#if (CONFIG_CAMERA_SCALE_CROP_MACHINE==RK_CAM_SCALE_CROP_ARM) + #define CAMERA_SCALE_CROP_MACHINE "arm" +#elif (CONFIG_CAMERA_SCALE_CROP_MACHINE==RK_CAM_SCALE_CROP_IPP) + #define CAMERA_SCALE_CROP_MACHINE "ipp" +#elif (CONFIG_CAMERA_SCALE_CROP_MACHINE==RK_CAM_SCALE_CROP_RGA) + #define CAMERA_SCALE_CROP_MACHINE "rga" +#elif (CONFIG_CAMERA_SCALE_CROP_MACHINE==RK_CAM_SCALE_CROP_PP) + #define CAMERA_SCALE_CROP_MACHINE "pp" +#endif + +#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_ARM) + #define CAMERA_VIDEOBUF_ARM_ACCESS 1 +#else + #define CAMERA_VIDEOBUF_ARM_ACCESS 0 +#endif + + #endif diff --git a/arch/arm/plat-rk/include/plat/rk_camera.h b/arch/arm/plat-rk/include/plat/rk_camera.h index 8c3780322eb4..05dad8a22512 100755 --- a/arch/arm/plat-rk/include/plat/rk_camera.h +++ b/arch/arm/plat-rk/include/plat/rk_camera.h @@ -138,6 +138,12 @@ #define RK29_CAM_FLASHACTIVE_H (0x01< +#include "../../video/rockchip/rga/rga.h" #endif - +#include static int debug ; module_param(debug, int, S_IRUGO|S_IWUSR); @@ -253,6 +254,7 @@ module_param(debug, int, S_IRUGO|S_IWUSR); #define RK_CAM_FRAME_INVAL_INIT 3 #define RK_CAM_FRAME_INVAL_DC 3 /* ddl@rock-chips.com : */ #define RK30_CAM_FRAME_MEASURE 5 + extern void videobuf_dma_contig_free(struct videobuf_queue *q, struct videobuf_buffer *buf); extern dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf); @@ -305,8 +307,17 @@ struct rk_camera_zoominfo struct semaphore sem; struct v4l2_crop a; int vir_width; + int vir_height; int zoom_rate; }; +#if CAMERA_VIDEOBUF_ARM_ACCESS +struct rk29_camera_vbinfo +{ + unsigned int phy_addr; + void __iomem *vir_addr; + unsigned int size; +}; +#endif struct rk_camera_timer{ struct rk_camera_dev *pcdev; struct hrtimer timer; @@ -337,10 +348,14 @@ struct rk_camera_dev unsigned int pixfmt; //for ipp unsigned int vipmem_phybase; + void __iomem *vipmem_virbase; unsigned int vipmem_size; unsigned int vipmem_bsize; - - int host_width; //croped size +#if CAMERA_VIDEOBUF_ARM_ACCESS + struct rk29_camera_vbinfo *vbinfo; + unsigned int vbinfo_count; +#endif + int host_width; int host_height; int host_left; //sensor output size ? int host_top; @@ -406,22 +421,32 @@ static int rk_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, struct soc_camera_device *icd = vq->priv_data; struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct rk_camera_dev *pcdev = ici->priv; - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - int bytes_per_line_host = soc_mbus_bytes_per_line(pcdev->host_width, - icd->current_fmt->host_fmt); - unsigned int i; + unsigned int i; struct rk_camera_work *wk; + struct soc_mbus_pixelfmt fmt; + int bytes_per_line; + int bytes_per_line_host; + fmt.packing = SOC_MBUS_PACKING_1_5X8; + + bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + if(icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_RGB565) + bytes_per_line_host = soc_mbus_bytes_per_line(pcdev->host_width, + &fmt); + else if(icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_RGB24) + bytes_per_line_host = pcdev->host_width*3; + else + bytes_per_line_host = soc_mbus_bytes_per_line(pcdev->host_width, + icd->current_fmt->host_fmt); + printk("user code = %d,packing = %d",icd->current_fmt->code,fmt.packing); dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size); if (bytes_per_line_host < 0) return bytes_per_line_host; - /* planar capture requires Y, U and V buffers to be page aligned */ *size = PAGE_ALIGN(bytes_per_line*icd->user_height); /* Y pages UV pages, yuv422*/ pcdev->vipmem_bsize = PAGE_ALIGN(bytes_per_line_host * pcdev->host_height); - if (CAM_WORKQUEUE_IS_EN()) { #ifdef CONFIG_VIDEO_RK29_DIGITALZOOM_IPP_OFF if (CAM_IPPWORK_IS_EN()) @@ -453,7 +478,22 @@ static int rk_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, } pcdev->camera_work_count = (*count); } - +#if CAMERA_VIDEOBUF_ARM_ACCESS + if (pcdev->vbinfo && (pcdev->vbinfo_count != *count)) { + kfree(pcdev->vbinfo); + pcdev->vbinfo = NULL; + pcdev->vbinfo_count = 0x00; + } + + if (pcdev->vbinfo == NULL) { + pcdev->vbinfo = kzalloc(sizeof(struct rk29_camera_vbinfo)*(*count), GFP_KERNEL); + if (pcdev->vbinfo == NULL) { + RKCAMERA_TR("\n %s vbinfo kmalloc fail\n", __FUNCTION__); + BUG(); + } + pcdev->vbinfo_count = *count; + } +#endif } pcdev->video_vq = vq; RKCAMERA_DG("%s..%d.. videobuf size:%d, vipmem_buf size:%d, count:%d \n",__FUNCTION__,__LINE__, *size,pcdev->vipmem_size, *count); @@ -567,6 +607,7 @@ static void rk_videobuf_queue(struct videobuf_queue *vq, struct soc_camera_device *icd = vq->priv_data; struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct rk_camera_dev *pcdev = ici->priv; + struct rk29_camera_vbinfo *vb_info; dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, vb, vb->baddr, vb->bsize); @@ -580,6 +621,31 @@ static void rk_videobuf_queue(struct videobuf_queue *vq, else BUG(); /* ddl@rock-chips.com : The same videobuffer queue again */ } +#if CAMERA_VIDEOBUF_ARM_ACCESS + if (pcdev->vbinfo) { + vb_info = pcdev->vbinfo+vb->i; + if ((vb_info->phy_addr != vb->boff) || (vb_info->size != vb->bsize)) { + if (vb_info->vir_addr) { + iounmap(vb_info->vir_addr); + release_mem_region(vb_info->phy_addr, vb_info->size); + vb_info->vir_addr = NULL; + vb_info->phy_addr = 0x00; + vb_info->size = 0x00; + } + + if (request_mem_region(vb->boff,vb->bsize,"rk_camera_vb")) { + vb_info->vir_addr = ioremap_cached(vb->boff,vb->bsize); + } + + if (vb_info->vir_addr) { + vb_info->size = vb->bsize; + vb_info->phy_addr = vb->boff; + } else { + RKCAMERA_TR("%s..%d:ioremap videobuf %d failed\n",__FUNCTION__,__LINE__, vb->i); + } + } + } +#endif if (!pcdev->active) { pcdev->active = vb; rk_videobuf_capture(vb,pcdev); @@ -609,16 +675,181 @@ static int rk_pixfmt2ippfmt(unsigned int pixfmt, int *ippfmt) rk_pixfmt2ippfmt_err: return -1; } -static void rk_camera_capture_process(struct work_struct *work) + +static int rk_pixfmt2rgafmt(unsigned int pixfmt, int *ippfmt) +{ + switch (pixfmt) + { + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_UYVY: // yuv 422, but sensor has defined this format(in fact ,should be defined yuv 420), treat this as yuv 420. + case V4L2_PIX_FMT_YUYV: + { + *ippfmt = RK_FORMAT_YCbCr_420_SP; + break; + } + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_YVYU: + { + *ippfmt = RK_FORMAT_YCrCb_420_SP; + break; + } + case V4L2_PIX_FMT_RGB565: + { + *ippfmt = RK_FORMAT_RGB_565; + break; + } + case V4L2_PIX_FMT_RGB24: + { + *ippfmt = RK_FORMAT_RGB_888; + break; + } + default: + goto rk_pixfmt2rgafmt_err; + } + + return 0; +rk_pixfmt2rgafmt_err: + return -1; +} + +#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_RGA) +extern rga_service_info rga_service; +extern int rga_blit_sync(rga_session *session, struct rga_req *req); +extern void rga_service_session_clear(rga_session *session); +static int rk_camera_scale_crop_rga(struct work_struct *work){ + struct rk_camera_work *camera_work = container_of(work, struct rk_camera_work, work); + struct videobuf_buffer *vb = camera_work->vb; + struct rk_camera_dev *pcdev = camera_work->pcdev; + int vipdata_base; + unsigned long int flags; + int scale_times,w,h; + int src_y_offset; + struct rga_req req; + rga_session session; + int rga_times = 3; + const struct soc_mbus_pixelfmt *fmt; + int ret = 0; + fmt = soc_mbus_get_fmtdesc(pcdev->icd->current_fmt->code); + vipdata_base = pcdev->vipmem_phybase + vb->i*pcdev->vipmem_bsize; + if((pcdev->icd->current_fmt->host_fmt->fourcc != V4L2_PIX_FMT_RGB565) + && (pcdev->icd->current_fmt->host_fmt->fourcc != V4L2_PIX_FMT_RGB24)){ + RKCAMERA_TR("RGA not support this format !\n"); + goto do_ipp_err; + } + if ((pcdev->icd->user_width > 0x800) || (pcdev->icd->user_height > 0x800)) { + scale_times = MAX((pcdev->icd->user_width/0x800),(pcdev->icd->user_height/0x800)); + scale_times++; + } else { + scale_times = 1; + } + session.pid = current->pid; + INIT_LIST_HEAD(&session.waiting); + INIT_LIST_HEAD(&session.running); + INIT_LIST_HEAD(&session.list_session); + init_waitqueue_head(&session.wait); + /* no need to protect */ + list_add_tail(&session.list_session, &rga_service.session); + atomic_set(&session.task_running, 0); + atomic_set(&session.num_done, 0); + + memset(&req,0,sizeof(struct rga_req)); + req.src.act_w = pcdev->zoominfo.a.c.width/scale_times; + req.src.act_h = pcdev->zoominfo.a.c.height/scale_times; + + req.src.vir_w = pcdev->zoominfo.vir_width; + req.src.vir_h =pcdev->zoominfo.vir_height; + req.src.yrgb_addr = vipdata_base; + req.src.uv_addr =vipdata_base + req.src.vir_w*req.src.vir_h; + req.src.v_addr = req.src.uv_addr ; + req.src.format =fmt->fourcc; + rk_pixfmt2rgafmt(fmt->fourcc,&req.src.format); + req.src.x_offset = pcdev->zoominfo.a.c.left; + req.src.y_offset = pcdev->zoominfo.a.c.top; + + req.dst.act_w = pcdev->icd->user_width/scale_times; + req.dst.act_h = pcdev->icd->user_height/scale_times; + + req.dst.vir_w = pcdev->icd->user_width; + req.dst.vir_h = pcdev->icd->user_height; + req.dst.x_offset = 0; + req.dst.y_offset = 0; + req.dst.yrgb_addr = vb->boff; + rk_pixfmt2rgafmt(pcdev->icd->current_fmt->host_fmt->fourcc,&req.dst.format); + req.clip.xmin = 0; + req.clip.xmax = req.dst.vir_w-1; + req.clip.ymin = 0; + req.clip.ymax = req.dst.vir_h -1; + + req.rotate_mode = 1; + req.scale_mode = 2; + + req.sina = 0; + req.cosa = 65536; + req.mmu_info.mmu_en = 0; + + for (h=0; hzoominfo.a.c.left+w*pcdev->zoominfo.a.c.width/scale_times; + req.src.y_offset = pcdev->zoominfo.a.c.top+h*pcdev->zoominfo.a.c.height/scale_times; + req.dst.x_offset = pcdev->icd->user_width*w/scale_times; + req.dst.y_offset = pcdev->icd->user_height*h/scale_times; + req.dst.yrgb_addr = vb->boff ; + // RKCAMERA_TR("src.act_w = %d , src.act_h = %d! vir_w = %d , vir_h = %d,off_x = %d,off_y = %d\n",req.src.act_w,req.src.act_h ,req.src.vir_w,req.src.vir_h,req.src.x_offset,req.src.y_offset); + // RKCAMERA_TR("dst.act_w = %d , dst.act_h = %d! vir_w = %d , vir_h = %d,off_x = %d,off_y = %d\n",req.dst.act_w,req.dst.act_h ,req.dst.vir_w,req.dst.vir_h,req.dst.x_offset,req.dst.y_offset); + // RKCAMERA_TR("req.src.yrgb_addr = 0x%x,req.dst.yrgb_addr = 0x%x\n",req.src.yrgb_addr,req.dst.yrgb_addr); + + while(rga_times-- > 0) { + if (rga_blit_sync(&session, &req)){ + RKCAMERA_TR("rga do erro,do again,rga_times = %d!\n",rga_times); + } else { + break; + } + } + + if (rga_times <= 0) { + spin_lock_irqsave(&pcdev->lock, flags); + vb->state = VIDEOBUF_NEEDS_INIT; + spin_unlock_irqrestore(&pcdev->lock, flags); + mutex_lock(&rga_service.lock); + list_del(&session.list_session); + rga_service_session_clear(&session); + mutex_unlock(&rga_service.lock); + goto session_done; + } + } + } + session_done: + mutex_lock(&rga_service.lock); + list_del(&session.list_session); + rga_service_session_clear(&session); + mutex_unlock(&rga_service.lock); + + do_ipp_err: + + return ret; + +} + +#endif +#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_IPP) + +static int rk_camera_scale_crop_ipp(struct work_struct *work) { struct rk_camera_work *camera_work = container_of(work, struct rk_camera_work, work); struct videobuf_buffer *vb = camera_work->vb; struct rk_camera_dev *pcdev = camera_work->pcdev; - struct rk29_ipp_req ipp_req; + int vipdata_base; unsigned long int flags; - int src_y_offset,src_uv_offset,dst_y_offset,dst_uv_offset,src_y_size,dst_y_size; - int scale_times,w,h,vipdata_base; - + + struct rk29_ipp_req ipp_req; + int src_y_offset,src_uv_offset,dst_y_offset,dst_uv_offset,src_y_size,dst_y_size; + int scale_times,w,h; + int ret = 0; /* *ddl@rock-chips.com: * IPP Dest image resolution is 2047x1088, so scale operation break up some times @@ -632,7 +863,6 @@ static void rk_camera_capture_process(struct work_struct *work) memset(&ipp_req, 0, sizeof(struct rk29_ipp_req)); - down(&pcdev->zoominfo.sem); ipp_req.timeout = 3000; ipp_req.flag = IPP_ROT_0; ipp_req.store_clip_mode =1; @@ -691,15 +921,166 @@ static void rk_camera_capture_process(struct work_struct *work) } } - if (pcdev->icd_cb.sensor_cb) - (pcdev->icd_cb.sensor_cb)(vb); do_ipp_err: - up(&pcdev->zoominfo.sem); - wake_up(&(camera_work->vb->done)); - spin_lock_irqsave(&pcdev->camera_work_lock, flags); - list_add_tail(&camera_work->queue, &pcdev->camera_work_queue); - spin_unlock_irqrestore(&pcdev->camera_work_lock, flags); - return; + return ret; +} +#endif +#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_ARM) +static int rk_camera_scale_crop_arm(struct work_struct *work) +{ + struct rk_camera_work *camera_work = container_of(work, struct rk_camera_work, work); + struct videobuf_buffer *vb = camera_work->vb; + struct rk_camera_dev *pcdev = camera_work->pcdev; + struct rk29_camera_vbinfo *vb_info; + unsigned char *psY,*pdY,*psUV,*pdUV; + unsigned char *src,*dst; + unsigned long src_phy,dst_phy; + int srcW,srcH,cropW,cropH,dstW,dstH; + long zoomindstxIntInv,zoomindstyIntInv; + long x,y; + long yCoeff00,yCoeff01,xCoeff00,xCoeff01; + long sX,sY; + long r0,r1,a,b,c,d; + int ret = 0; + + src_phy = pcdev->vipmem_phybase + vb->i*pcdev->vipmem_bsize; + src = psY = (unsigned char*)(pcdev->vipmem_virbase + vb->i*pcdev->vipmem_bsize); + psUV = psY + pcdev->host_width*pcdev->host_height; + + srcW = pcdev->zoominfo.vir_width; + srcH = pcdev->zoominfo.vir_height; + cropW = pcdev->zoominfo.a.c.width; + cropH = pcdev->zoominfo.a.c.height; + + psY = psY + (srcW-cropW); + psUV = psUV + (srcW-cropW); + + vb_info = pcdev->vbinfo+vb->i; + dst_phy = vb_info->phy_addr; + dst = pdY = (unsigned char*)vb_info->vir_addr; + pdUV = pdY + pcdev->icd->user_width*pcdev->icd->user_height; + dstW = pcdev->icd->user_width; + dstH = pcdev->icd->user_height; + + zoomindstxIntInv = ((unsigned long)cropW<<16)/dstW + 1; + zoomindstyIntInv = ((unsigned long)cropH<<16)/dstH + 1; + + //y + //for(y = 0; y> 16); + + for(x = 0; x> 16); + + a = psY[sY*srcW + sX]; + b = psY[sY*srcW + sX + 1]; + c = psY[(sY+1)*srcW + sX]; + d = psY[(sY+1)*srcW + sX + 1]; + + r0 = (a * xCoeff01 + b * xCoeff00)>>16 ; + r1 = (c * xCoeff01 + d * xCoeff00)>>16 ; + r0 = (r0 * yCoeff01 + r1 * yCoeff00)>>16; + + pdY[x] = r0; + } + pdY += dstW; + } + + dstW /= 2; + dstH /= 2; + srcW /= 2; + srcH /= 2; + + //UV + //for(y = 0; y> 16); + + for(x = 0; x> 16); + + //U + a = psUV[(sY*srcW + sX)*2]; + b = psUV[(sY*srcW + sX + 1)*2]; + c = psUV[((sY+1)*srcW + sX)*2]; + d = psUV[((sY+1)*srcW + sX + 1)*2]; + + r0 = (a * xCoeff01 + b * xCoeff00)>>16 ; + r1 = (c * xCoeff01 + d * xCoeff00)>>16 ; + r0 = (r0 * yCoeff01 + r1 * yCoeff00)>>16; + + pdUV[x*2] = r0; + + //V + a = psUV[(sY*srcW + sX)*2 + 1]; + b = psUV[(sY*srcW + sX + 1)*2 + 1]; + c = psUV[((sY+1)*srcW + sX)*2 + 1]; + d = psUV[((sY+1)*srcW + sX + 1)*2 + 1]; + + r0 = (a * xCoeff01 + b * xCoeff00)>>16 ; + r1 = (c * xCoeff01 + d * xCoeff00)>>16 ; + r0 = (r0 * yCoeff01 + r1 * yCoeff00)>>16; + + pdUV[x*2 + 1] = r0; + } + pdUV += dstW*2; + } + +rk_camera_scale_crop_arm_end: + + dmac_flush_range((void*)src,(void*)(src+pcdev->vipmem_bsize)); + outer_flush_range((phys_addr_t)src_phy,(phys_addr_t)(src_phy+pcdev->vipmem_bsize)); + + dmac_flush_range((void*)dst,(void*)(dst+vb_info->size)); + outer_flush_range((phys_addr_t)dst_phy,(phys_addr_t)(dst_phy+vb_info->size)); + + return ret; +} +#endif +static void rk_camera_capture_process(struct work_struct *work) +{ + struct rk_camera_work *camera_work = container_of(work, struct rk_camera_work, work); + struct videobuf_buffer *vb = camera_work->vb; + struct rk_camera_dev *pcdev = camera_work->pcdev; + //enum v4l2_mbus_pixelcode icd_code = pcdev->icd->current_fmt->code; + unsigned long flags = 0; + int err = 0; + + if (!CAM_WORKQUEUE_IS_EN()) + goto rk_camera_capture_process_end; + + down(&pcdev->zoominfo.sem); + if (pcdev->icd_cb.scale_crop_cb){ + err = (pcdev->icd_cb.scale_crop_cb)(work); + } + up(&pcdev->zoominfo.sem); + + if (pcdev->icd_cb.sensor_cb) + (pcdev->icd_cb.sensor_cb)(vb); + +rk_camera_capture_process_end: + if (err) { + vb->state = VIDEOBUF_ERROR; + } else { + if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) { + vb->state = VIDEOBUF_DONE; + vb->field_count++; + } + } + wake_up(&(camera_work->vb->done)); + spin_lock_irqsave(&pcdev->camera_work_lock, flags); + list_add_tail(&camera_work->queue, &pcdev->camera_work_queue); + spin_unlock_irqrestore(&pcdev->camera_work_lock, flags); + return; } static irqreturn_t rk_camera_irq(int irq, void *data) { @@ -751,7 +1132,7 @@ static irqreturn_t rk_camera_irq(int irq, void *data) if(!vb){ printk("no acticve buffer!!!\n"); goto RK_CAMERA_IRQ_END; - } + } /* ddl@rock-chips.com : this vb may be deleted from queue */ if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) { list_del_init(&vb->queue); @@ -768,11 +1149,7 @@ static irqreturn_t rk_camera_irq(int irq, void *data) RKCAMERA_DG("%s video_buf queue is empty!\n",__FUNCTION__); } - if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) { - vb->state = VIDEOBUF_DONE; - do_gettimeofday(&vb->ts); - vb->field_count++; - } + do_gettimeofday(&vb->ts); if (CAM_WORKQUEUE_IS_EN()) { if (!list_empty(&pcdev->camera_work_queue)) { wk = list_entry(pcdev->camera_work_queue.next, struct rk_camera_work, queue); @@ -783,6 +1160,10 @@ static irqreturn_t rk_camera_irq(int irq, void *data) queue_work(pcdev->camera_wq, &(wk->work)); } } else { + if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) { + vb->state = VIDEOBUF_DONE; + vb->field_count++; + } wake_up(&vb->done); } @@ -802,6 +1183,7 @@ static void rk_videobuf_release(struct videobuf_queue *vq, struct soc_camera_device *icd = vq->priv_data; struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct rk_camera_dev *pcdev = ici->priv; + struct rk29_camera_vbinfo *vb_info =NULL; #ifdef DEBUG dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, vb->baddr, vb->bsize); @@ -822,16 +1204,25 @@ static void rk_videobuf_release(struct videobuf_queue *vq, break; } #endif - if (vb->i == 0) { - flush_workqueue(pcdev->camera_wq); - } - if (vb == pcdev->active) { RKCAMERA_DG("%s Wait for this video buf(0x%x) write finished!\n ",__FUNCTION__,(unsigned int)vb); interruptible_sleep_on_timeout(&vb->done, msecs_to_jiffies(500)); - flush_workqueue(pcdev->camera_wq); RKCAMERA_DG("%s This video buf(0x%x) write finished, release now!!\n",__FUNCTION__,(unsigned int)vb); } + + flush_workqueue(pcdev->camera_wq); +#if CAMERA_VIDEOBUF_ARM_ACCESS + if (pcdev->vbinfo) { + vb_info = pcdev->vbinfo + vb->i; + + if (vb_info->vir_addr) { + iounmap(vb_info->vir_addr); + release_mem_region(vb_info->phy_addr, vb_info->size); + memset(vb_info, 0x00, sizeof(struct rk29_camera_vbinfo)); + } + + } +#endif rk_videobuf_free(vq, buf); } @@ -925,12 +1316,11 @@ static int rk_camera_activate(struct rk_camera_dev *pcdev, struct soc_camera_dev } static void rk_camera_deactivate(struct rk_camera_dev *pcdev) -{ +{ clk_disable(pcdev->aclk_cif); clk_disable(pcdev->hclk_cif); clk_disable(pcdev->cif_clk_in); - clk_disable(pcdev->cif_clk_out); clk_enable(pcdev->cif_clk_out); clk_set_rate(pcdev->cif_clk_out,48*1000*1000); @@ -1020,6 +1410,8 @@ static void rk_camera_remove_device(struct soc_camera_device *icd) struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct rk_camera_dev *pcdev = ici->priv; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + struct rk29_camera_vbinfo *vb_info; + unsigned int i; mutex_lock(&camera_lock); BUG_ON(icd != pcdev->icd); @@ -1059,6 +1451,22 @@ static void rk_camera_remove_device(struct soc_camera_device *icd) INIT_LIST_HEAD(&pcdev->camera_work_queue); } rk_camera_deactivate(pcdev); +#if CAMERA_VIDEOBUF_ARM_ACCESS + if (pcdev->vbinfo) { + vb_info = pcdev->vbinfo; + for (i=0; ivbinfo_count; i++) { + if (vb_info->vir_addr) { + iounmap(vb_info->vir_addr); + release_mem_region(vb_info->phy_addr, vb_info->size); + memset(vb_info, 0x00, sizeof(struct rk29_camera_vbinfo)); + } + vb_info++; + } + kfree(pcdev->vbinfo); + pcdev->vbinfo = NULL; + pcdev->vbinfo_count = 0; + } +#endif pcdev->active = NULL; pcdev->icd = NULL; pcdev->icd_cb.sensor_cb = NULL; @@ -1207,6 +1615,18 @@ static const struct soc_mbus_pixelfmt rk_camera_formats[] = { .bits_per_sample = 8, .packing = SOC_MBUS_PACKING_2X8_PADHI, .order = SOC_MBUS_ORDER_LE, + },{ + .fourcc = V4L2_PIX_FMT_RGB565, + .name = "RGB565", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_2X8_PADHI, + .order = SOC_MBUS_ORDER_LE, + },{ + .fourcc = V4L2_PIX_FMT_RGB24, + .name = "RGB888", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_2X8_PADHI, + .order = SOC_MBUS_ORDER_LE, } }; @@ -1216,37 +1636,47 @@ static void rk_camera_setup_format(struct soc_camera_device *icd, __u32 host_pix struct rk_camera_dev *pcdev = ici->priv; unsigned int cif_fs = 0,cif_crop = 0; unsigned int cif_fmt_val = read_cif_reg(pcdev->base,CIF_CIF_FOR) | INPUT_MODE_YUV|YUV_INPUT_422|INPUT_420_ORDER_EVEN|OUTPUT_420_ORDER_EVEN; + + const struct soc_mbus_pixelfmt *fmt; + fmt = soc_mbus_get_fmtdesc(icd_code); + + if((host_pixfmt == V4L2_PIX_FMT_RGB565) || (host_pixfmt == V4L2_PIX_FMT_RGB24)){ + if(fmt->fourcc == V4L2_PIX_FMT_NV12) + host_pixfmt = V4L2_PIX_FMT_NV12; + else if(fmt->fourcc == V4L2_PIX_FMT_NV21) + host_pixfmt = V4L2_PIX_FMT_NV21; + } switch (host_pixfmt) { case V4L2_PIX_FMT_NV16: cif_fmt_val &= ~YUV_OUTPUT_422; - cif_fmt_val &= ~UV_STORAGE_ORDER_UVUV; - pcdev->frame_inval = RK_CAM_FRAME_INVAL_DC; - pcdev->pixfmt = host_pixfmt; + cif_fmt_val &= ~UV_STORAGE_ORDER_UVUV; + pcdev->frame_inval = RK_CAM_FRAME_INVAL_DC; + pcdev->pixfmt = host_pixfmt; break; - case V4L2_PIX_FMT_NV61: - cif_fmt_val &= ~YUV_OUTPUT_422; - cif_fmt_val |= UV_STORAGE_ORDER_VUVU; - pcdev->frame_inval = RK_CAM_FRAME_INVAL_DC; - pcdev->pixfmt = host_pixfmt; - break; + case V4L2_PIX_FMT_NV61: + cif_fmt_val &= ~YUV_OUTPUT_422; + cif_fmt_val |= UV_STORAGE_ORDER_VUVU; + pcdev->frame_inval = RK_CAM_FRAME_INVAL_DC; + pcdev->pixfmt = host_pixfmt; + break; case V4L2_PIX_FMT_NV12: cif_fmt_val |= YUV_OUTPUT_420; - cif_fmt_val &= ~UV_STORAGE_ORDER_UVUV; + cif_fmt_val &= ~UV_STORAGE_ORDER_UVUV; if (pcdev->frame_inval != RK_CAM_FRAME_INVAL_INIT) pcdev->frame_inval = RK_CAM_FRAME_INVAL_INIT; pcdev->pixfmt = host_pixfmt; break; - case V4L2_PIX_FMT_NV21: - cif_fmt_val |= YUV_OUTPUT_420; - cif_fmt_val |= UV_STORAGE_ORDER_VUVU; - if (pcdev->frame_inval != RK_CAM_FRAME_INVAL_INIT) - pcdev->frame_inval = RK_CAM_FRAME_INVAL_INIT; - pcdev->pixfmt = host_pixfmt; - break; - default: /* ddl@rock-chips.com : vip output format is hold when pixfmt is invalidate */ - cif_fmt_val |= YUV_OUTPUT_422; - break; + case V4L2_PIX_FMT_NV21: + cif_fmt_val |= YUV_OUTPUT_420; + cif_fmt_val |= UV_STORAGE_ORDER_VUVU; + if (pcdev->frame_inval != RK_CAM_FRAME_INVAL_INIT) + pcdev->frame_inval = RK_CAM_FRAME_INVAL_INIT; + pcdev->pixfmt = host_pixfmt; + break; + default: /* ddl@rock-chips.com : vip output format is hold when pixfmt is invalidate */ + cif_fmt_val |= YUV_OUTPUT_422; + break; } switch (icd_code) { @@ -1306,8 +1736,7 @@ static void rk_camera_setup_format(struct soc_camera_device *icd, __u32 host_pix write_cif_reg(pcdev->base,CIF_CIF_SET_SIZE, cif_fs); write_cif_reg(pcdev->base,CIF_CIF_VIR_LINE_WIDTH, rect->width); write_cif_reg(pcdev->base,CIF_CIF_FRAME_STATUS, 0x00000003); - - //MUST bypass scale + //MUST bypass scale write_cif_reg(pcdev->base,CIF_CIF_SCL_CTRL,0x10); RKCAMERA_DG("%s.. crop:0x%x fs:0x%x cif_fmt_val:0x%x CIF_CIF_FOR:0x%x\n",__FUNCTION__,cif_crop,cif_fs,cif_fmt_val,read_cif_reg(pcdev->base,CIF_CIF_FOR)); return; @@ -1377,6 +1806,22 @@ static int rk_camera_get_formats(struct soc_camera_device *icd, unsigned int idx dev_dbg(dev, "Providing format %s using code %d\n", rk_camera_formats[3].name,code); } + formats++; + if (xlate) { + xlate->host_fmt = &rk_camera_formats[4]; + xlate->code = code; + xlate++; + dev_dbg(dev, "Providing format %s using code %d\n", + rk_camera_formats[4].name,code); + } + formats++; + if (xlate) { + xlate->host_fmt = &rk_camera_formats[5]; + xlate->code = code; + xlate++; + dev_dbg(dev, "Providing format %s using code %d\n", + rk_camera_formats[5].name,code); + } break; default: break; @@ -1538,6 +1983,7 @@ static int rk_camera_set_fmt(struct soc_camera_device *icd, pcdev->zoominfo.a.c.top = 0; } pcdev->zoominfo.vir_width = pcdev->host_width; + pcdev->zoominfo.vir_height = pcdev->host_height; up(&pcdev->zoominfo.sem); /* ddl@rock-chips.com: IPP work limit check */ @@ -2171,6 +2617,7 @@ static int rk_camera_set_digit_zoom(struct soc_camera_device *icd, pcdev->zoominfo.a.c.top = a.c.top; pcdev->zoominfo.a.c.left = a.c.left; pcdev->zoominfo.vir_width = pcdev->host_width; + pcdev->zoominfo.vir_height= pcdev->host_height; up(&pcdev->zoominfo.sem); RKCAMERA_DG("%s..zoom_rate:%d (%dx%d at (%d,%d)-> %dx%d)\n",__FUNCTION__, zoom_rate,a.c.width, a.c.height, a.c.left, a.c.top, icd->user_width, icd->user_height ); @@ -2326,6 +2773,7 @@ static int rk_camera_probe(struct platform_device *pdev) pcdev->zoominfo.zoom_rate = 100; pcdev->hostid = pdev->id; + /*config output clk*/ // must modify start if(IS_CIF0()){ pcdev->pd_cif = clk_get(NULL, "pd_cif0"); @@ -2361,15 +2809,38 @@ static int rk_camera_probe(struct platform_device *pdev) if (pcdev->pdata && IS_CIF0()) { pcdev->vipmem_phybase = pcdev->pdata->meminfo.start; pcdev->vipmem_size = pcdev->pdata->meminfo.size; + + if (!request_mem_region(pcdev->vipmem_phybase,pcdev->vipmem_size,"rk29_vipmem")) { + err = -EBUSY; + goto exit_ioremap_vipmem; + } + pcdev->vipmem_virbase = ioremap_cached(pcdev->vipmem_phybase,pcdev->vipmem_size); + if (pcdev->vipmem_virbase == NULL) { + dev_err(pcdev->dev, "ioremap() of vip internal memory(Ex:IPP process/raw process) failed\n"); + err = -ENXIO; + goto exit_ioremap_vipmem; + } RKCAMERA_TR("%s(%d): Memory(start:0x%x size:0x%x) for IPP obtain \n",__FUNCTION__,__LINE__, pcdev->pdata->meminfo.start,pcdev->pdata->meminfo.size); } else if (pcdev->pdata) { pcdev->vipmem_phybase = pcdev->pdata->meminfo_cif1.start; pcdev->vipmem_size = pcdev->pdata->meminfo_cif1.size; + + if (!request_mem_region(pcdev->vipmem_phybase,pcdev->vipmem_size,"rk29_vipmem")) { + err = -EBUSY; + goto exit_ioremap_vipmem; + } + pcdev->vipmem_virbase = ioremap_cached(pcdev->vipmem_phybase,pcdev->vipmem_size); + if (pcdev->vipmem_virbase == NULL) { + dev_err(pcdev->dev, "ioremap() of vip internal memory(Ex:IPP process/raw process) failed\n"); + err = -ENXIO; + goto exit_ioremap_vipmem; + } RKCAMERA_TR("%s(%d): Memory(start:0x%x size:0x%x) for IPP obtain \n",__FUNCTION__,__LINE__, pcdev->pdata->meminfo.start,pcdev->pdata->meminfo.size); } else { RKCAMERA_TR("\n%s Memory for IPP have not obtain! IPP Function is fail\n",__FUNCTION__); pcdev->vipmem_phybase = 0; pcdev->vipmem_size = 0; + pcdev->vipmem_virbase = 0; } #endif INIT_LIST_HEAD(&pcdev->capture); @@ -2441,6 +2912,13 @@ static int rk_camera_probe(struct platform_device *pdev) pcdev->fps_timer.timer.function = rk_camera_fps_func; pcdev->icd_cb.sensor_cb = NULL; +#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_IPP) + pcdev->icd_cb.scale_crop_cb = rk_camera_scale_crop_ipp; +#elif (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_ARM) + pcdev->icd_cb.scale_crop_cb = rk_camera_scale_crop_arm; +#elif (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_RGA) + pcdev->icd_cb.scale_crop_cb = rk_camera_scale_crop_rga; +#endif RKCAMERA_DG("%s(%d) Exit \n",__FUNCTION__,__LINE__); return 0; @@ -2465,7 +2943,10 @@ static int rk_camera_probe(struct platform_device *pdev) iounmap(pcdev->base); exit_ioremap_vip: release_mem_region(res->start, res->end - res->start + 1); - +exit_ioremap_vipmem: + if (pcdev->vipmem_virbase) + iounmap(pcdev->vipmem_virbase); + release_mem_region(pcdev->vipmem_phybase,pcdev->vipmem_size); exit_reqmem_vip: if(pcdev->aclk_cif) pcdev->aclk_cif = NULL; From f22b396074dff7f3a52f5c3f20d4e9d930e3c951 Mon Sep 17 00:00:00 2001 From: ywj Date: Fri, 17 Aug 2012 18:20:55 +0800 Subject: [PATCH 219/261] gsensor code result in system reboot,gsensor code by lw update --- drivers/input/sensors/accel/kxtik.c | 70 -------------------------- drivers/input/sensors/accel/lis3dh.c | 69 ------------------------- drivers/input/sensors/accel/mma8452.c | 72 +-------------------------- 3 files changed, 2 insertions(+), 209 deletions(-) diff --git a/drivers/input/sensors/accel/kxtik.c b/drivers/input/sensors/accel/kxtik.c index 3a014208704d..ac0eca4b950d 100755 --- a/drivers/input/sensors/accel/kxtik.c +++ b/drivers/input/sensors/accel/kxtik.c @@ -40,73 +40,6 @@ #define DBG(x...) #endif -struct i2c_client *kxtik_client=NULL; -static struct class *sensor_class = NULL; - -static ssize_t sensor_setoratitention(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int i=0; - char gsensororatation[20]; - - struct sensor_private_data *sensor = - (struct sensor_private_data *) i2c_get_clientdata(kxtik_client); - struct sensor_platform_data *pdata = sensor->pdata; - - - char *p = strstr(buf,"gsensor"); - int start = strcspn(p,"{"); - int end = strcspn(p,"}"); - - strncpy(gsensororatation,p+start,end-start+1); - char *tmp=gsensororatation; - - - while(strncmp(tmp,"}",1)!=0) - { - if((strncmp(tmp,",",1)==0)||(strncmp(tmp,"{",1)==0)) - { - - tmp++; - continue; - } - else if(strncmp(tmp,"-",1)==0) - { - pdata->orientation[i++]=-1; - DBG("i=%d,data=%d\n",i,pdata->orientation[i]); - tmp++; - } - else - { - pdata->orientation[i++]=tmp[0]-48; - DBG("----i=%d,data=%d\n",i,pdata->orientation[i]); - } - tmp++; - - - } - - for(i=0;i<9;i++) - DBG("i=%d gsensor_info=%d\n",i,pdata->orientation[i]); - return 0; - -} - -static CLASS_ATTR(oratiention, 0777, NULL,sensor_setoratitention); - -static int sensor_sys_init(void) -{ - int ret ; - sensor_class = class_create(THIS_MODULE, "gsensor"); - ret = class_create_file(sensor_class, &class_attr_oratiention); - if (ret) - { - printk("Fail to creat class oratiention.\n"); - } - return 0; -} - - /****************operate according to sensor chip:start************/ static int sensor_active(struct i2c_client *client, int enable, int rate) @@ -152,7 +85,6 @@ static int sensor_init(struct i2c_client *client) return result; } - kxtik_client=client; sensor->status_cur = SENSOR_OFF; result = sensor_write_reg(client, KXTIK_DATA_CTRL_REG, KXTIK_ODR400F); @@ -180,8 +112,6 @@ static int sensor_init(struct i2c_client *client) return result; } - sensor_sys_init(); - return result; } diff --git a/drivers/input/sensors/accel/lis3dh.c b/drivers/input/sensors/accel/lis3dh.c index 7d6852271abc..1ca48a8cece9 100755 --- a/drivers/input/sensors/accel/lis3dh.c +++ b/drivers/input/sensors/accel/lis3dh.c @@ -91,73 +91,6 @@ struct sensor_reg_data { char data; }; -struct i2c_client *lis3dgh_client=NULL; -static struct class *sensor_class = NULL; - -static ssize_t sensor_setoratitention(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int i=0; - char gsensororatation[20]; - - struct sensor_private_data *sensor = - (struct sensor_private_data *) i2c_get_clientdata(lis3dgh_client); - struct sensor_platform_data *pdata = sensor->pdata; - - - char *p = strstr(buf,"gsensor"); - int start = strcspn(p,"{"); - int end = strcspn(p,"}"); - - strncpy(gsensororatation,p+start,end-start+1); - char *tmp=gsensororatation; - - - while(strncmp(tmp,"}",1)!=0) - { - if((strncmp(tmp,",",1)==0)||(strncmp(tmp,"{",1)==0)) - { - - tmp++; - continue; - } - else if(strncmp(tmp,"-",1)==0) - { - pdata->orientation[i++]=-1; - DBG("i=%d,data=%d\n",i,pdata->orientation[i]); - tmp++; - } - else - { - pdata->orientation[i++]=tmp[0]-48; - DBG("----i=%d,data=%d\n",i,pdata->orientation[i]); - } - tmp++; - - - } - - for(i=0;i<9;i++) - DBG("i=%d gsensor_info=%d\n",i,pdata->orientation[i]); - return 0; - -} - -static CLASS_ATTR(oratiention, 0777, NULL,sensor_setoratitention); - -static int sensor_sys_init(void) -{ - int ret ; - sensor_class = class_create(THIS_MODULE, "gsensor"); - ret = class_create_file(sensor_class, &class_attr_oratiention); - if (ret) - { - printk("Fail to creat class oratiention.\n"); - } - return 0; -} - - /****************operate according to sensor chip:start************/ static int sensor_active(struct i2c_client *client, int enable, int rate) @@ -216,7 +149,6 @@ static int sensor_init(struct i2c_client *client) printk("%s:line=%d,error\n",__func__,__LINE__); return result; } - lis3dgh_client = client; sensor->status_cur = SENSOR_OFF; @@ -250,7 +182,6 @@ static int sensor_init(struct i2c_client *client) } - sensor_sys_init(); return result; } diff --git a/drivers/input/sensors/accel/mma8452.c b/drivers/input/sensors/accel/mma8452.c index 5258a8b0e510..0264e5f009d2 100755 --- a/drivers/input/sensors/accel/mma8452.c +++ b/drivers/input/sensors/accel/mma8452.c @@ -48,73 +48,6 @@ #define MMA8452_ENABLE 1 -struct i2c_client *mma8452_client=NULL; -static struct class *sensor_class = NULL; - -static ssize_t sensor_setoratitention(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int i=0; - char gsensororatation[20]; - - struct sensor_private_data *sensor = - (struct sensor_private_data *) i2c_get_clientdata(mma8452_client); - struct sensor_platform_data *pdata = sensor->pdata; - - - char *p = strstr(buf,"gsensor"); - int start = strcspn(p,"{"); - int end = strcspn(p,"}"); - - strncpy(gsensororatation,p+start,end-start+1); - char *tmp=gsensororatation; - - - while(strncmp(tmp,"}",1)!=0) - { - if((strncmp(tmp,",",1)==0)||(strncmp(tmp,"{",1)==0)) - { - - tmp++; - continue; - } - else if(strncmp(tmp,"-",1)==0) - { - pdata->orientation[i++]=-1; - DBG("i=%d,data=%d\n",i,pdata->orientation[i]); - tmp++; - } - else - { - pdata->orientation[i++]=tmp[0]-48; - DBG("----i=%d,data=%d\n",i,pdata->orientation[i]); - } - tmp++; - - - } - - for(i=0;i<9;i++) - DBG("i=%d gsensor_info=%d\n",i,pdata->orientation[i]); - return 0; - -} - -static CLASS_ATTR(oratiention, 0777, NULL,sensor_setoratitention); - -static int sensor_sys_init(void) -{ - int ret ; - sensor_class = class_create(THIS_MODULE, "gsensor"); - ret = class_create_file(sensor_class, &class_attr_oratiention); - if (ret) - { - printk("Fail to creat class oratiention.\n"); - } - return 0; -} - - /****************operate according to sensor chip:start************/ static int sensor_active(struct i2c_client *client, int enable, int rate) @@ -161,7 +94,6 @@ static int sensor_init(struct i2c_client *client) return ret; } - mma8452_client=client; sensor->status_cur = SENSOR_OFF; /* disable FIFO FMODE = 0*/ @@ -193,8 +125,8 @@ static int sensor_init(struct i2c_client *client) DBG("mma8452 MMA8452_REG_SYSMOD:%x\n",sensor_read_reg(client,MMA8452_REG_SYSMOD)); - sensor_sys_init(); - + printk("------sensor_chip_init\n"); + return ret; } From f962867a8fc2e5b8c45df80bb3ebad0f8d14551b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Fri, 17 Aug 2012 19:17:19 +0800 Subject: [PATCH 220/261] bmptologo: fix gcc warning --- scripts/bmptologo.c | 64 +++++++-------------------------------------- 1 file changed, 10 insertions(+), 54 deletions(-) diff --git a/scripts/bmptologo.c b/scripts/bmptologo.c index fdac7cfc8498..443cdda4da24 100644 --- a/scripts/bmptologo.c +++ b/scripts/bmptologo.c @@ -104,69 +104,25 @@ static unsigned long logo_height; static unsigned long data_long; static unsigned long data_start; static unsigned char *logo_data; -static struct color logo_clut[MAX_LINUX_LOGO_COLORS]; -static unsigned int logo_clutsize; static void die(const char *fmt, ...) __attribute__ ((noreturn)) __attribute ((format (printf, 1, 2))); static void usage(void) __attribute ((noreturn)); -static unsigned int get_number(FILE *fp) -{ - int c, val; - - /* Skip leading whitespace */ - do { - c = fgetc(fp); - if (c == EOF) - die("%s: end of file\n", filename); - if (c == '#') { - /* Ignore comments 'till end of line */ - do { - c = fgetc(fp); - if (c == EOF) - die("%s: end of file\n", filename); - } while (c != '\n'); - } - } while (isspace(c)); - - /* Parse decimal number */ - val = 0; - while (isdigit(c)) { - val = 10*val+c-'0'; - c = fgetc(fp); - if (c == EOF) - die("%s: end of file\n", filename); - } - return val; -} - -static unsigned int get_number255(FILE *fp, unsigned int maxval) -{ - unsigned int val = get_number(fp); - return (255*val+maxval/2)/maxval; -} - static void read_image(void) { - FILE *fp; - unsigned long i; + int fd; struct stat s; - char j = 0; - int magic; - unsigned int maxval; - char read_buf[0x28]; - long ret = 0; unsigned char *data; /* open image file */ - fp = open(filename, O_RDONLY); - if (!fp) + fd = open(filename, O_RDONLY); + if (fd < 0) die("Cannot open file isll.. %s: %s\n", filename, strerror(errno)); - if (fstat(fp, &s) < 0) { - die("Cannot stat file isll.. %s: %s\n", filename, strerror(errno)); - } + if (fstat(fd, &s) < 0) + die("Cannot stat file isll.. %s: %s\n", filename, strerror(errno)); + #if 0 ret = fread(read_buf,1,0x26,fp); if (ret != 0x26) @@ -195,9 +151,9 @@ static void read_image(void) if (ret != data_long) die("read file %s: error logo_data=%ld\n", filename,ret); #else - data = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fp, 0); - if (data == MAP_FAILED) - die("read file %s: error logo_data\n", filename); + data = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) + die("read file %s: error logo_data\n", filename); logo_data = data + 54; logo_height = (data[0x19]<<24) + (data[0x18]<<16) +(data[0x17]<<8) +(data[0x16]); logo_width = (data[0x15]<<24) + (data[0x14]<<16) +(data[0x13]<<8) +(data[0x12]); @@ -218,7 +174,7 @@ static void read_image(void) logo_data[9],logo_data[10],logo_data[11]); #endif /* close file */ - close(fp); + close(fd); } From 3be93856a121d7ff2af3d0315eb8b504532a64a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Fri, 17 Aug 2012 19:20:47 +0800 Subject: [PATCH 221/261] gitignore: ignore scripts/bmptologo --- scripts/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/.gitignore b/scripts/.gitignore index 105b21f08185..78085220ba3a 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -3,6 +3,7 @@ # conmakehash kallsyms +bmptologo pnmtologo bin2c unifdef From 6214df8abbae942321d9770f18a356f63b8b12b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Fri, 17 Aug 2012 22:08:08 +0800 Subject: [PATCH 222/261] rk2928: sdk: fix gcc warning, "CONFIG_RK30_PWM_REGULATOR" is not defined --- arch/arm/mach-rk2928/board-rk2928-sdk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-rk2928/board-rk2928-sdk.c b/arch/arm/mach-rk2928/board-rk2928-sdk.c index 57eef7b606de..0eb825055991 100755 --- a/arch/arm/mach-rk2928/board-rk2928-sdk.c +++ b/arch/arm/mach-rk2928/board-rk2928-sdk.c @@ -379,7 +379,7 @@ static struct platform_device device_ion = { }; #endif -#if CONFIG_RK30_PWM_REGULATOR +#ifdef CONFIG_RK30_PWM_REGULATOR const static int pwm_voltage_map[] = { 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 1400000 }; From 9c60c70b72364fef9b3dbffdec0ece684037386c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Fri, 17 Aug 2012 22:08:24 +0800 Subject: [PATCH 223/261] rk30: sdk: fix gcc warning, "CONFIG_RK30_PWM_REGULATOR" is not defined --- arch/arm/mach-rk30/board-rk30-sdk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-rk30/board-rk30-sdk.c b/arch/arm/mach-rk30/board-rk30-sdk.c index e168aa134d87..4d3ebcd60802 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk.c +++ b/arch/arm/mach-rk30/board-rk30-sdk.c @@ -1402,7 +1402,7 @@ static struct platform_device rk30_device_adc_battery = { }; #endif -#if CONFIG_RK30_PWM_REGULATOR +#ifdef CONFIG_RK30_PWM_REGULATOR const static int pwm_voltage_map[] = { 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 1400000 }; From 8bee22ca2d7b4108393ec9bfc9684534ac7f9632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Fri, 17 Aug 2012 22:08:40 +0800 Subject: [PATCH 224/261] rk30: phonepad: fix gcc warning, "CONFIG_RK30_PWM_REGULATOR" is not defined --- arch/arm/mach-rk30/board-rk30-phonepad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-rk30/board-rk30-phonepad.c b/arch/arm/mach-rk30/board-rk30-phonepad.c index 6cf7dee27e75..fbf98380cd33 100755 --- a/arch/arm/mach-rk30/board-rk30-phonepad.c +++ b/arch/arm/mach-rk30/board-rk30-phonepad.c @@ -1586,7 +1586,7 @@ static struct platform_device rk30_device_adc_battery = { }, }; #endif -#if CONFIG_RK30_PWM_REGULATOR +#ifdef CONFIG_RK30_PWM_REGULATOR const static int pwm_voltage_map[] = { 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 1400000 }; From aea3c212d47f9fb902cf8d97032c219f40fc8d0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Fri, 17 Aug 2012 22:16:19 +0800 Subject: [PATCH 225/261] rk30: sdk: board-rk30-sdk.c include board-rk30-sdk-camera.c and board-rk30-sdk-key.c --- arch/arm/mach-rk30/Makefile | 4 +- arch/arm/mach-rk30/board-rk30-sdk-camera.c | 448 ++++++++++++++++++++ arch/arm/mach-rk30/board-rk30-sdk.c | 450 +-------------------- 3 files changed, 452 insertions(+), 450 deletions(-) create mode 100644 arch/arm/mach-rk30/board-rk30-sdk-camera.c diff --git a/arch/arm/mach-rk30/Makefile b/arch/arm/mach-rk30/Makefile index 356ad42dbb8f..f19d13d0f7a5 100644 --- a/arch/arm/mach-rk30/Makefile +++ b/arch/arm/mach-rk30/Makefile @@ -23,8 +23,8 @@ obj-$(CONFIG_DVFS) += dvfs.o obj-$(CONFIG_DDR_FREQ) += ddr_freq.o obj-$(CONFIG_RK30_I2C_INSRAM) += i2c_sram.o -obj-$(CONFIG_MACH_RK3066_SDK) += board-rk30-sdk.o board-rk30-sdk-key.o -obj-$(CONFIG_MACH_RK30_SDK) += board-rk30-sdk.o board-rk30-sdk-key.o +obj-$(CONFIG_MACH_RK3066_SDK) += board-rk30-sdk.o +obj-$(CONFIG_MACH_RK30_SDK) += board-rk30-sdk.o obj-$(CONFIG_MACH_RK30_PHONE) += board-rk30-phone.o board-rk30-phone-key.o obj-$(CONFIG_MACH_RK30_PHONE_PAD) += board-rk30-phonepad.o board-rk30-phonepad-key.o board-rk30-phonepad-rfkill.o obj-$(CONFIG_MACH_RK30_PHONE_LOQUAT) += board-rk30-phone-loquat.o board-rk30-phone-loquat-key.o diff --git a/arch/arm/mach-rk30/board-rk30-sdk-camera.c b/arch/arm/mach-rk30/board-rk30-sdk-camera.c new file mode 100644 index 000000000000..4570d41fa02c --- /dev/null +++ b/arch/arm/mach-rk30/board-rk30-sdk-camera.c @@ -0,0 +1,448 @@ +#ifdef CONFIG_VIDEO_RK29 +/*---------------- Camera Sensor Macro Define Begin ------------------------*/ +/*---------------- Camera Sensor Configuration Macro Begin ------------------------*/ +#define CONFIG_SENSOR_0 RK29_CAM_SENSOR_OV5642 /* back camera sensor */ +#define CONFIG_SENSOR_IIC_ADDR_0 0x78 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_0 4 +#define CONFIG_SENSOR_CIF_INDEX_0 1 +#define CONFIG_SENSOR_ORIENTATION_0 90 +#define CONFIG_SENSOR_POWER_PIN_0 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_0 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_0 RK30_PIN1_PD6 +#define CONFIG_SENSOR_FALSH_PIN_0 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_0 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_0 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_0 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_0 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_0 30000 + +#define CONFIG_SENSOR_01 RK29_CAM_SENSOR_OV5642 /* back camera sensor 1 */ +#define CONFIG_SENSOR_IIC_ADDR_01 0x00 +#define CONFIG_SENSOR_CIF_INDEX_01 1 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_01 4 +#define CONFIG_SENSOR_ORIENTATION_01 90 +#define CONFIG_SENSOR_POWER_PIN_01 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_01 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_01 RK30_PIN1_PD6 +#define CONFIG_SENSOR_FALSH_PIN_01 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_01 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_01 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_01 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_01 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_01 30000 + +#define CONFIG_SENSOR_02 RK29_CAM_SENSOR_OV5640 /* back camera sensor 2 */ +#define CONFIG_SENSOR_IIC_ADDR_02 0x00 +#define CONFIG_SENSOR_CIF_INDEX_02 1 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_02 4 +#define CONFIG_SENSOR_ORIENTATION_02 90 +#define CONFIG_SENSOR_POWER_PIN_02 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_02 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_02 RK30_PIN1_PD6 +#define CONFIG_SENSOR_FALSH_PIN_02 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_02 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_02 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_02 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_02 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_02 30000 + +#define CONFIG_SENSOR_1 RK29_CAM_SENSOR_OV2659 /* front camera sensor 0 */ +#define CONFIG_SENSOR_IIC_ADDR_1 0x60 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_1 3 +#define CONFIG_SENSOR_CIF_INDEX_1 0 +#define CONFIG_SENSOR_ORIENTATION_1 270 +#define CONFIG_SENSOR_POWER_PIN_1 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_1 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_1 RK30_PIN1_PB7 +#define CONFIG_SENSOR_FALSH_PIN_1 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_1 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_1 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_1 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_1 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_1 30000 + +#define CONFIG_SENSOR_11 RK29_CAM_SENSOR_OV2659 /* front camera sensor 1 */ +#define CONFIG_SENSOR_IIC_ADDR_11 0x00 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_11 3 +#define CONFIG_SENSOR_CIF_INDEX_11 0 +#define CONFIG_SENSOR_ORIENTATION_11 270 +#define CONFIG_SENSOR_POWER_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_11 INVALID_GPIO//RK30_PIN1_PB7 +#define CONFIG_SENSOR_FALSH_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_11 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_11 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_11 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_11 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_11 30000 + +#define CONFIG_SENSOR_12 RK29_CAM_SENSOR_OV2659//RK29_CAM_SENSOR_OV2655 /* front camera sensor 2 */ +#define CONFIG_SENSOR_IIC_ADDR_12 0x00 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_12 3 +#define CONFIG_SENSOR_CIF_INDEX_12 0 +#define CONFIG_SENSOR_ORIENTATION_12 270 +#define CONFIG_SENSOR_POWER_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_12 INVALID_GPIO//RK30_PIN1_PB7 +#define CONFIG_SENSOR_FALSH_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_12 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_12 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_12 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_12 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_12 30000 + + +#endif //#ifdef CONFIG_VIDEO_RK29 +/*---------------- Camera Sensor Configuration Macro End------------------------*/ +#include "../../../drivers/media/video/rk30_camera.c" +/*---------------- Camera Sensor Macro Define End ---------*/ + +#define PMEM_CAM_SIZE PMEM_CAM_NECESSARY +/***************************************************************************************** + * camera devices + * author: ddl@rock-chips.com + *****************************************************************************************/ +#ifdef CONFIG_VIDEO_RK29 +#define CONFIG_SENSOR_POWER_IOCTL_USR 1 //define this refer to your board layout +#define CONFIG_SENSOR_RESET_IOCTL_USR 0 +#define CONFIG_SENSOR_POWERDOWN_IOCTL_USR 0 +#define CONFIG_SENSOR_FLASH_IOCTL_USR 0 + +static void rk_cif_power(int on) +{ + struct regulator *ldo_18,*ldo_28; + ldo_28 = regulator_get(NULL, "ldo7"); // vcc28_cif + ldo_18 = regulator_get(NULL, "ldo1"); // vcc18_cif + if (ldo_28 == NULL || IS_ERR(ldo_28) || ldo_18 == NULL || IS_ERR(ldo_18)){ + printk("get cif ldo failed!\n"); + return; + } + if(on == 0){ + regulator_disable(ldo_28); + regulator_put(ldo_28); + regulator_disable(ldo_18); + regulator_put(ldo_18); + mdelay(500); + } + else{ + regulator_set_voltage(ldo_28, 2800000, 2800000); + regulator_enable(ldo_28); + // printk("%s set ldo7 vcc28_cif=%dmV end\n", __func__, regulator_get_voltage(ldo_28)); + regulator_put(ldo_28); + + regulator_set_voltage(ldo_18, 1800000, 1800000); + // regulator_set_suspend_voltage(ldo, 1800000); + regulator_enable(ldo_18); + // printk("%s set ldo1 vcc18_cif=%dmV end\n", __func__, regulator_get_voltage(ldo_18)); + regulator_put(ldo_18); + } +} + +#if CONFIG_SENSOR_POWER_IOCTL_USR +static int sensor_power_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + //#error "CONFIG_SENSOR_POWER_IOCTL_USR is 1, sensor_power_usr_cb function must be writed!!"; + rk_cif_power(on); +} +#endif + +#if CONFIG_SENSOR_RESET_IOCTL_USR +static int sensor_reset_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + #error "CONFIG_SENSOR_RESET_IOCTL_USR is 1, sensor_reset_usr_cb function must be writed!!"; +} +#endif + +#if CONFIG_SENSOR_POWERDOWN_IOCTL_USR +static int sensor_powerdown_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + #error "CONFIG_SENSOR_POWERDOWN_IOCTL_USR is 1, sensor_powerdown_usr_cb function must be writed!!"; +} +#endif + +#if CONFIG_SENSOR_FLASH_IOCTL_USR +static int sensor_flash_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + #error "CONFIG_SENSOR_FLASH_IOCTL_USR is 1, sensor_flash_usr_cb function must be writed!!"; +} +#endif + +static struct rk29camera_platform_ioctl_cb sensor_ioctl_cb = { + #if CONFIG_SENSOR_POWER_IOCTL_USR + .sensor_power_cb = sensor_power_usr_cb, + #else + .sensor_power_cb = NULL, + #endif + + #if CONFIG_SENSOR_RESET_IOCTL_USR + .sensor_reset_cb = sensor_reset_usr_cb, + #else + .sensor_reset_cb = NULL, + #endif + + #if CONFIG_SENSOR_POWERDOWN_IOCTL_USR + .sensor_powerdown_cb = sensor_powerdown_usr_cb, + #else + .sensor_powerdown_cb = NULL, + #endif + + #if CONFIG_SENSOR_FLASH_IOCTL_USR + .sensor_flash_cb = sensor_flash_usr_cb, + #else + .sensor_flash_cb = NULL, + #endif +}; + +#if CONFIG_SENSOR_IIC_ADDR_0 +static struct reginfo_t rk_init_data_sensor_reg_0[] = +{ + {0x0000, 0x00,0,0} + }; +static struct reginfo_t rk_init_data_sensor_winseqreg_0[] ={ + {0x0000, 0x00,0,0} + }; +#endif + +#if CONFIG_SENSOR_IIC_ADDR_1 +static struct reginfo_t rk_init_data_sensor_reg_1[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_1[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_01 +static struct reginfo_t rk_init_data_sensor_reg_01[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_01[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_02 +static struct reginfo_t rk_init_data_sensor_reg_02[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_02[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_11 +static struct reginfo_t rk_init_data_sensor_reg_11[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_11[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_12 +static struct reginfo_t rk_init_data_sensor_reg_12[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_12[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +static rk_sensor_user_init_data_s rk_init_data_sensor[RK_CAM_NUM] = +{ + #if CONFIG_SENSOR_IIC_ADDR_0 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_0, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_0, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_0) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_0) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_1 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_1, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_1, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_1) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_1) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_01 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_01, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_01, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_01) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_01) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_02 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_02, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_02, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_02) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_02) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_11 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_11, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_11, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_11) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_11) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_12 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_12, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_12, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_12) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_12) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + + }; +#include "../../../drivers/media/video/rk30_camera.c" + +#endif /* CONFIG_VIDEO_RK29 */ diff --git a/arch/arm/mach-rk30/board-rk30-sdk.c b/arch/arm/mach-rk30/board-rk30-sdk.c index 4d3ebcd60802..af011c661fcc 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk.c +++ b/arch/arm/mach-rk30/board-rk30-sdk.c @@ -78,454 +78,8 @@ #define RK30_FB0_MEM_SIZE 8*SZ_1M #endif -#ifdef CONFIG_VIDEO_RK29 -/*---------------- Camera Sensor Macro Define Begin ------------------------*/ -/*---------------- Camera Sensor Configuration Macro Begin ------------------------*/ -#define CONFIG_SENSOR_0 RK29_CAM_SENSOR_OV5642 /* back camera sensor */ -#define CONFIG_SENSOR_IIC_ADDR_0 0x78 -#define CONFIG_SENSOR_IIC_ADAPTER_ID_0 4 -#define CONFIG_SENSOR_CIF_INDEX_0 1 -#define CONFIG_SENSOR_ORIENTATION_0 90 -#define CONFIG_SENSOR_POWER_PIN_0 INVALID_GPIO -#define CONFIG_SENSOR_RESET_PIN_0 INVALID_GPIO -#define CONFIG_SENSOR_POWERDN_PIN_0 RK30_PIN1_PD6 -#define CONFIG_SENSOR_FALSH_PIN_0 INVALID_GPIO -#define CONFIG_SENSOR_POWERACTIVE_LEVEL_0 RK29_CAM_POWERACTIVE_L -#define CONFIG_SENSOR_RESETACTIVE_LEVEL_0 RK29_CAM_RESETACTIVE_L -#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_0 RK29_CAM_POWERDNACTIVE_H -#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_0 RK29_CAM_FLASHACTIVE_L - -#define CONFIG_SENSOR_QCIF_FPS_FIXED_0 15000 -#define CONFIG_SENSOR_240X160_FPS_FIXED_0 15000 -#define CONFIG_SENSOR_QVGA_FPS_FIXED_0 15000 -#define CONFIG_SENSOR_CIF_FPS_FIXED_0 15000 -#define CONFIG_SENSOR_VGA_FPS_FIXED_0 15000 -#define CONFIG_SENSOR_480P_FPS_FIXED_0 15000 -#define CONFIG_SENSOR_SVGA_FPS_FIXED_0 15000 -#define CONFIG_SENSOR_720P_FPS_FIXED_0 30000 - -#define CONFIG_SENSOR_01 RK29_CAM_SENSOR_OV5642 /* back camera sensor 1 */ -#define CONFIG_SENSOR_IIC_ADDR_01 0x00 -#define CONFIG_SENSOR_CIF_INDEX_01 1 -#define CONFIG_SENSOR_IIC_ADAPTER_ID_01 4 -#define CONFIG_SENSOR_ORIENTATION_01 90 -#define CONFIG_SENSOR_POWER_PIN_01 INVALID_GPIO -#define CONFIG_SENSOR_RESET_PIN_01 INVALID_GPIO -#define CONFIG_SENSOR_POWERDN_PIN_01 RK30_PIN1_PD6 -#define CONFIG_SENSOR_FALSH_PIN_01 INVALID_GPIO -#define CONFIG_SENSOR_POWERACTIVE_LEVEL_01 RK29_CAM_POWERACTIVE_L -#define CONFIG_SENSOR_RESETACTIVE_LEVEL_01 RK29_CAM_RESETACTIVE_L -#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_01 RK29_CAM_POWERDNACTIVE_H -#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_01 RK29_CAM_FLASHACTIVE_L - -#define CONFIG_SENSOR_QCIF_FPS_FIXED_01 15000 -#define CONFIG_SENSOR_240X160_FPS_FIXED_01 15000 -#define CONFIG_SENSOR_QVGA_FPS_FIXED_01 15000 -#define CONFIG_SENSOR_CIF_FPS_FIXED_01 15000 -#define CONFIG_SENSOR_VGA_FPS_FIXED_01 15000 -#define CONFIG_SENSOR_480P_FPS_FIXED_01 15000 -#define CONFIG_SENSOR_SVGA_FPS_FIXED_01 15000 -#define CONFIG_SENSOR_720P_FPS_FIXED_01 30000 - -#define CONFIG_SENSOR_02 RK29_CAM_SENSOR_OV5640 /* back camera sensor 2 */ -#define CONFIG_SENSOR_IIC_ADDR_02 0x00 -#define CONFIG_SENSOR_CIF_INDEX_02 1 -#define CONFIG_SENSOR_IIC_ADAPTER_ID_02 4 -#define CONFIG_SENSOR_ORIENTATION_02 90 -#define CONFIG_SENSOR_POWER_PIN_02 INVALID_GPIO -#define CONFIG_SENSOR_RESET_PIN_02 INVALID_GPIO -#define CONFIG_SENSOR_POWERDN_PIN_02 RK30_PIN1_PD6 -#define CONFIG_SENSOR_FALSH_PIN_02 INVALID_GPIO -#define CONFIG_SENSOR_POWERACTIVE_LEVEL_02 RK29_CAM_POWERACTIVE_L -#define CONFIG_SENSOR_RESETACTIVE_LEVEL_02 RK29_CAM_RESETACTIVE_L -#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_02 RK29_CAM_POWERDNACTIVE_H -#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_02 RK29_CAM_FLASHACTIVE_L - -#define CONFIG_SENSOR_QCIF_FPS_FIXED_02 15000 -#define CONFIG_SENSOR_240X160_FPS_FIXED_02 15000 -#define CONFIG_SENSOR_QVGA_FPS_FIXED_02 15000 -#define CONFIG_SENSOR_CIF_FPS_FIXED_02 15000 -#define CONFIG_SENSOR_VGA_FPS_FIXED_02 15000 -#define CONFIG_SENSOR_480P_FPS_FIXED_02 15000 -#define CONFIG_SENSOR_SVGA_FPS_FIXED_02 15000 -#define CONFIG_SENSOR_720P_FPS_FIXED_02 30000 - -#define CONFIG_SENSOR_1 RK29_CAM_SENSOR_OV2659 /* front camera sensor 0 */ -#define CONFIG_SENSOR_IIC_ADDR_1 0x60 -#define CONFIG_SENSOR_IIC_ADAPTER_ID_1 3 -#define CONFIG_SENSOR_CIF_INDEX_1 0 -#define CONFIG_SENSOR_ORIENTATION_1 270 -#define CONFIG_SENSOR_POWER_PIN_1 INVALID_GPIO -#define CONFIG_SENSOR_RESET_PIN_1 INVALID_GPIO -#define CONFIG_SENSOR_POWERDN_PIN_1 RK30_PIN1_PB7 -#define CONFIG_SENSOR_FALSH_PIN_1 INVALID_GPIO -#define CONFIG_SENSOR_POWERACTIVE_LEVEL_1 RK29_CAM_POWERACTIVE_L -#define CONFIG_SENSOR_RESETACTIVE_LEVEL_1 RK29_CAM_RESETACTIVE_L -#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_1 RK29_CAM_POWERDNACTIVE_H -#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_1 RK29_CAM_FLASHACTIVE_L - -#define CONFIG_SENSOR_QCIF_FPS_FIXED_1 15000 -#define CONFIG_SENSOR_240X160_FPS_FIXED_1 15000 -#define CONFIG_SENSOR_QVGA_FPS_FIXED_1 15000 -#define CONFIG_SENSOR_CIF_FPS_FIXED_1 15000 -#define CONFIG_SENSOR_VGA_FPS_FIXED_1 15000 -#define CONFIG_SENSOR_480P_FPS_FIXED_1 15000 -#define CONFIG_SENSOR_SVGA_FPS_FIXED_1 15000 -#define CONFIG_SENSOR_720P_FPS_FIXED_1 30000 - -#define CONFIG_SENSOR_11 RK29_CAM_SENSOR_OV2659 /* front camera sensor 1 */ -#define CONFIG_SENSOR_IIC_ADDR_11 0x00 -#define CONFIG_SENSOR_IIC_ADAPTER_ID_11 3 -#define CONFIG_SENSOR_CIF_INDEX_11 0 -#define CONFIG_SENSOR_ORIENTATION_11 270 -#define CONFIG_SENSOR_POWER_PIN_11 INVALID_GPIO -#define CONFIG_SENSOR_RESET_PIN_11 INVALID_GPIO -#define CONFIG_SENSOR_POWERDN_PIN_11 INVALID_GPIO//RK30_PIN1_PB7 -#define CONFIG_SENSOR_FALSH_PIN_11 INVALID_GPIO -#define CONFIG_SENSOR_POWERACTIVE_LEVEL_11 RK29_CAM_POWERACTIVE_L -#define CONFIG_SENSOR_RESETACTIVE_LEVEL_11 RK29_CAM_RESETACTIVE_L -#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_11 RK29_CAM_POWERDNACTIVE_H -#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_11 RK29_CAM_FLASHACTIVE_L - -#define CONFIG_SENSOR_QCIF_FPS_FIXED_11 15000 -#define CONFIG_SENSOR_240X160_FPS_FIXED_11 15000 -#define CONFIG_SENSOR_QVGA_FPS_FIXED_11 15000 -#define CONFIG_SENSOR_CIF_FPS_FIXED_11 15000 -#define CONFIG_SENSOR_VGA_FPS_FIXED_11 15000 -#define CONFIG_SENSOR_480P_FPS_FIXED_11 15000 -#define CONFIG_SENSOR_SVGA_FPS_FIXED_11 15000 -#define CONFIG_SENSOR_720P_FPS_FIXED_11 30000 - -#define CONFIG_SENSOR_12 RK29_CAM_SENSOR_OV2659//RK29_CAM_SENSOR_OV2655 /* front camera sensor 2 */ -#define CONFIG_SENSOR_IIC_ADDR_12 0x00 -#define CONFIG_SENSOR_IIC_ADAPTER_ID_12 3 -#define CONFIG_SENSOR_CIF_INDEX_12 0 -#define CONFIG_SENSOR_ORIENTATION_12 270 -#define CONFIG_SENSOR_POWER_PIN_12 INVALID_GPIO -#define CONFIG_SENSOR_RESET_PIN_12 INVALID_GPIO -#define CONFIG_SENSOR_POWERDN_PIN_12 INVALID_GPIO//RK30_PIN1_PB7 -#define CONFIG_SENSOR_FALSH_PIN_12 INVALID_GPIO -#define CONFIG_SENSOR_POWERACTIVE_LEVEL_12 RK29_CAM_POWERACTIVE_L -#define CONFIG_SENSOR_RESETACTIVE_LEVEL_12 RK29_CAM_RESETACTIVE_L -#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_12 RK29_CAM_POWERDNACTIVE_H -#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_12 RK29_CAM_FLASHACTIVE_L - -#define CONFIG_SENSOR_QCIF_FPS_FIXED_12 15000 -#define CONFIG_SENSOR_240X160_FPS_FIXED_12 15000 -#define CONFIG_SENSOR_QVGA_FPS_FIXED_12 15000 -#define CONFIG_SENSOR_CIF_FPS_FIXED_12 15000 -#define CONFIG_SENSOR_VGA_FPS_FIXED_12 15000 -#define CONFIG_SENSOR_480P_FPS_FIXED_12 15000 -#define CONFIG_SENSOR_SVGA_FPS_FIXED_12 15000 -#define CONFIG_SENSOR_720P_FPS_FIXED_12 30000 - - -#endif //#ifdef CONFIG_VIDEO_RK29 -/*---------------- Camera Sensor Configuration Macro End------------------------*/ -#include "../../../drivers/media/video/rk30_camera.c" -/*---------------- Camera Sensor Macro Define End ---------*/ - -#define PMEM_CAM_SIZE PMEM_CAM_NECESSARY -/***************************************************************************************** - * camera devices - * author: ddl@rock-chips.com - *****************************************************************************************/ -#ifdef CONFIG_VIDEO_RK29 -#define CONFIG_SENSOR_POWER_IOCTL_USR 1 //define this refer to your board layout -#define CONFIG_SENSOR_RESET_IOCTL_USR 0 -#define CONFIG_SENSOR_POWERDOWN_IOCTL_USR 0 -#define CONFIG_SENSOR_FLASH_IOCTL_USR 0 - -static void rk_cif_power(int on) -{ - struct regulator *ldo_18,*ldo_28; - ldo_28 = regulator_get(NULL, "ldo7"); // vcc28_cif - ldo_18 = regulator_get(NULL, "ldo1"); // vcc18_cif - if (ldo_28 == NULL || IS_ERR(ldo_28) || ldo_18 == NULL || IS_ERR(ldo_18)){ - printk("get cif ldo failed!\n"); - return; - } - if(on == 0){ - regulator_disable(ldo_28); - regulator_put(ldo_28); - regulator_disable(ldo_18); - regulator_put(ldo_18); - mdelay(500); - } - else{ - regulator_set_voltage(ldo_28, 2800000, 2800000); - regulator_enable(ldo_28); - // printk("%s set ldo7 vcc28_cif=%dmV end\n", __func__, regulator_get_voltage(ldo_28)); - regulator_put(ldo_28); - - regulator_set_voltage(ldo_18, 1800000, 1800000); - // regulator_set_suspend_voltage(ldo, 1800000); - regulator_enable(ldo_18); - // printk("%s set ldo1 vcc18_cif=%dmV end\n", __func__, regulator_get_voltage(ldo_18)); - regulator_put(ldo_18); - } -} - -#if CONFIG_SENSOR_POWER_IOCTL_USR -static int sensor_power_usr_cb (struct rk29camera_gpio_res *res,int on) -{ - //#error "CONFIG_SENSOR_POWER_IOCTL_USR is 1, sensor_power_usr_cb function must be writed!!"; - rk_cif_power(on); -} -#endif - -#if CONFIG_SENSOR_RESET_IOCTL_USR -static int sensor_reset_usr_cb (struct rk29camera_gpio_res *res,int on) -{ - #error "CONFIG_SENSOR_RESET_IOCTL_USR is 1, sensor_reset_usr_cb function must be writed!!"; -} -#endif - -#if CONFIG_SENSOR_POWERDOWN_IOCTL_USR -static int sensor_powerdown_usr_cb (struct rk29camera_gpio_res *res,int on) -{ - #error "CONFIG_SENSOR_POWERDOWN_IOCTL_USR is 1, sensor_powerdown_usr_cb function must be writed!!"; -} -#endif - -#if CONFIG_SENSOR_FLASH_IOCTL_USR -static int sensor_flash_usr_cb (struct rk29camera_gpio_res *res,int on) -{ - #error "CONFIG_SENSOR_FLASH_IOCTL_USR is 1, sensor_flash_usr_cb function must be writed!!"; -} -#endif - -static struct rk29camera_platform_ioctl_cb sensor_ioctl_cb = { - #if CONFIG_SENSOR_POWER_IOCTL_USR - .sensor_power_cb = sensor_power_usr_cb, - #else - .sensor_power_cb = NULL, - #endif - - #if CONFIG_SENSOR_RESET_IOCTL_USR - .sensor_reset_cb = sensor_reset_usr_cb, - #else - .sensor_reset_cb = NULL, - #endif - - #if CONFIG_SENSOR_POWERDOWN_IOCTL_USR - .sensor_powerdown_cb = sensor_powerdown_usr_cb, - #else - .sensor_powerdown_cb = NULL, - #endif - - #if CONFIG_SENSOR_FLASH_IOCTL_USR - .sensor_flash_cb = sensor_flash_usr_cb, - #else - .sensor_flash_cb = NULL, - #endif -}; - -#if CONFIG_SENSOR_IIC_ADDR_0 -static struct reginfo_t rk_init_data_sensor_reg_0[] = -{ - {0x0000, 0x00,0,0} - }; -static struct reginfo_t rk_init_data_sensor_winseqreg_0[] ={ - {0x0000, 0x00,0,0} - }; -#endif - -#if CONFIG_SENSOR_IIC_ADDR_1 -static struct reginfo_t rk_init_data_sensor_reg_1[] = -{ - {0x0000, 0x00,0,0} -}; -static struct reginfo_t rk_init_data_sensor_winseqreg_1[] = -{ - {0x0000, 0x00,0,0} -}; -#endif -#if CONFIG_SENSOR_IIC_ADDR_01 -static struct reginfo_t rk_init_data_sensor_reg_01[] = -{ - {0x0000, 0x00,0,0} -}; -static struct reginfo_t rk_init_data_sensor_winseqreg_01[] = -{ - {0x0000, 0x00,0,0} -}; -#endif -#if CONFIG_SENSOR_IIC_ADDR_02 -static struct reginfo_t rk_init_data_sensor_reg_02[] = -{ - {0x0000, 0x00,0,0} -}; -static struct reginfo_t rk_init_data_sensor_winseqreg_02[] = -{ - {0x0000, 0x00,0,0} -}; -#endif -#if CONFIG_SENSOR_IIC_ADDR_11 -static struct reginfo_t rk_init_data_sensor_reg_11[] = -{ - {0x0000, 0x00,0,0} -}; -static struct reginfo_t rk_init_data_sensor_winseqreg_11[] = -{ - {0x0000, 0x00,0,0} -}; -#endif -#if CONFIG_SENSOR_IIC_ADDR_12 -static struct reginfo_t rk_init_data_sensor_reg_12[] = -{ - {0x0000, 0x00,0,0} -}; -static struct reginfo_t rk_init_data_sensor_winseqreg_12[] = -{ - {0x0000, 0x00,0,0} -}; -#endif -static rk_sensor_user_init_data_s rk_init_data_sensor[RK_CAM_NUM] = -{ - #if CONFIG_SENSOR_IIC_ADDR_0 - { - .rk_sensor_init_width = INVALID_VALUE, - .rk_sensor_init_height = INVALID_VALUE, - .rk_sensor_init_bus_param = INVALID_VALUE, - .rk_sensor_init_pixelcode = INVALID_VALUE, - .rk_sensor_init_data = rk_init_data_sensor_reg_0, - .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_0, - .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_0) / sizeof(struct reginfo_t), - .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_0) / sizeof(struct reginfo_t), - }, - #else - { - .rk_sensor_init_width = INVALID_VALUE, - .rk_sensor_init_height = INVALID_VALUE, - .rk_sensor_init_bus_param = INVALID_VALUE, - .rk_sensor_init_pixelcode = INVALID_VALUE, - .rk_sensor_init_data = NULL, - .rk_sensor_init_winseq = NULL, - .rk_sensor_winseq_size = 0, - .rk_sensor_init_data_size = 0, - }, - #endif - #if CONFIG_SENSOR_IIC_ADDR_1 - { - .rk_sensor_init_width = INVALID_VALUE, - .rk_sensor_init_height = INVALID_VALUE, - .rk_sensor_init_bus_param = INVALID_VALUE, - .rk_sensor_init_pixelcode = INVALID_VALUE, - .rk_sensor_init_data = rk_init_data_sensor_reg_1, - .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_1, - .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_1) / sizeof(struct reginfo_t), - .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_1) / sizeof(struct reginfo_t), - }, - #else - { - .rk_sensor_init_width = INVALID_VALUE, - .rk_sensor_init_height = INVALID_VALUE, - .rk_sensor_init_bus_param = INVALID_VALUE, - .rk_sensor_init_pixelcode = INVALID_VALUE, - .rk_sensor_init_data = NULL, - .rk_sensor_init_winseq = NULL, - .rk_sensor_winseq_size = 0, - .rk_sensor_init_data_size = 0, - }, - #endif - #if CONFIG_SENSOR_IIC_ADDR_01 - { - .rk_sensor_init_width = INVALID_VALUE, - .rk_sensor_init_height = INVALID_VALUE, - .rk_sensor_init_bus_param = INVALID_VALUE, - .rk_sensor_init_pixelcode = INVALID_VALUE, - .rk_sensor_init_data = rk_init_data_sensor_reg_01, - .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_01, - .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_01) / sizeof(struct reginfo_t), - .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_01) / sizeof(struct reginfo_t), - }, - #else - { - .rk_sensor_init_width = INVALID_VALUE, - .rk_sensor_init_height = INVALID_VALUE, - .rk_sensor_init_bus_param = INVALID_VALUE, - .rk_sensor_init_pixelcode = INVALID_VALUE, - .rk_sensor_init_data = NULL, - .rk_sensor_init_winseq = NULL, - .rk_sensor_winseq_size = 0, - .rk_sensor_init_data_size = 0, - }, - #endif - #if CONFIG_SENSOR_IIC_ADDR_02 - { - .rk_sensor_init_width = INVALID_VALUE, - .rk_sensor_init_height = INVALID_VALUE, - .rk_sensor_init_bus_param = INVALID_VALUE, - .rk_sensor_init_pixelcode = INVALID_VALUE, - .rk_sensor_init_data = rk_init_data_sensor_reg_02, - .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_02, - .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_02) / sizeof(struct reginfo_t), - .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_02) / sizeof(struct reginfo_t), - }, - #else - { - .rk_sensor_init_width = INVALID_VALUE, - .rk_sensor_init_height = INVALID_VALUE, - .rk_sensor_init_bus_param = INVALID_VALUE, - .rk_sensor_init_pixelcode = INVALID_VALUE, - .rk_sensor_init_data = NULL, - .rk_sensor_init_winseq = NULL, - .rk_sensor_winseq_size = 0, - .rk_sensor_init_data_size = 0, - }, - #endif - #if CONFIG_SENSOR_IIC_ADDR_11 - { - .rk_sensor_init_width = INVALID_VALUE, - .rk_sensor_init_height = INVALID_VALUE, - .rk_sensor_init_bus_param = INVALID_VALUE, - .rk_sensor_init_pixelcode = INVALID_VALUE, - .rk_sensor_init_data = rk_init_data_sensor_reg_11, - .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_11, - .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_11) / sizeof(struct reginfo_t), - .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_11) / sizeof(struct reginfo_t), - }, - #else - { - .rk_sensor_init_width = INVALID_VALUE, - .rk_sensor_init_height = INVALID_VALUE, - .rk_sensor_init_bus_param = INVALID_VALUE, - .rk_sensor_init_pixelcode = INVALID_VALUE, - .rk_sensor_init_data = NULL, - .rk_sensor_init_winseq = NULL, - .rk_sensor_winseq_size = 0, - .rk_sensor_init_data_size = 0, - }, - #endif - #if CONFIG_SENSOR_IIC_ADDR_12 - { - .rk_sensor_init_width = INVALID_VALUE, - .rk_sensor_init_height = INVALID_VALUE, - .rk_sensor_init_bus_param = INVALID_VALUE, - .rk_sensor_init_pixelcode = INVALID_VALUE, - .rk_sensor_init_data = rk_init_data_sensor_reg_12, - .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_12, - .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_12) / sizeof(struct reginfo_t), - .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_12) / sizeof(struct reginfo_t), - }, - #else - { - .rk_sensor_init_width = INVALID_VALUE, - .rk_sensor_init_height = INVALID_VALUE, - .rk_sensor_init_bus_param = INVALID_VALUE, - .rk_sensor_init_pixelcode = INVALID_VALUE, - .rk_sensor_init_data = NULL, - .rk_sensor_init_winseq = NULL, - .rk_sensor_winseq_size = 0, - .rk_sensor_init_data_size = 0, - }, - #endif - - }; -#include "../../../drivers/media/video/rk30_camera.c" - -#endif /* CONFIG_VIDEO_RK29 */ +#include "board-rk30-sdk-camera.c" +#include "board-rk30-sdk-key.c" #if defined(CONFIG_TOUCHSCREEN_GT8XX) #define TOUCH_RESET_PIN RK30_PIN4_PD0 From 2465250f7e9c350fd0390fc910db235e95161424 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Fri, 17 Aug 2012 22:37:19 +0800 Subject: [PATCH 226/261] rk2928: devices.c: add dummy i2c check idle --- arch/arm/mach-rk2928/devices.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/arm/mach-rk2928/devices.c b/arch/arm/mach-rk2928/devices.c index 0e2c3290cd30..9be98c671c93 100755 --- a/arch/arm/mach-rk2928/devices.c +++ b/arch/arm/mach-rk2928/devices.c @@ -280,10 +280,16 @@ static struct platform_device device_lcdc = { #endif #ifdef CONFIG_I2C0_RK30 +static int i2c0_check_idle(void) +{ + return I2C_IDLE; +} + static struct rk30_i2c_platform_data default_i2c0_data = { .bus_num = 0, .is_div_from_arm = 1, .adap_type = I2C0_ADAP_TYPE, + .check_idle = &i2c0_check_idle, }; static struct resource resources_i2c0[] = { @@ -311,10 +317,16 @@ static struct platform_device device_i2c0 = { #endif #ifdef CONFIG_I2C1_RK30 +static int i2c1_check_idle(void) +{ + return I2C_IDLE; +} + static struct rk30_i2c_platform_data default_i2c1_data = { .bus_num = 1, .is_div_from_arm = 1, .adap_type = I2C1_ADAP_TYPE, + .check_idle = &i2c1_check_idle, }; static struct resource resources_i2c1[] = { @@ -342,10 +354,16 @@ static struct platform_device device_i2c1 = { #endif #ifdef CONFIG_I2C2_RK30 +static int i2c2_check_idle(void) +{ + return I2C_IDLE; +} + static struct rk30_i2c_platform_data default_i2c2_data = { .bus_num = 2, .is_div_from_arm = 0, .adap_type = I2C2_ADAP_TYPE, + .check_idle = &i2c2_check_idle, }; static struct resource resources_i2c2[] = { @@ -373,10 +391,16 @@ static struct platform_device device_i2c2 = { #endif #ifdef CONFIG_I2C3_RK30 +static int i2c3_check_idle(void) +{ + return I2C_IDLE; +} + static struct rk30_i2c_platform_data default_i2c3_data = { .bus_num = 3, .is_div_from_arm = 0, .adap_type = I2C3_ADAP_TYPE, + .check_idle = &i2c3_check_idle, }; static struct resource resources_i2c3[] = { From e2c42c5690091a8278e0f790444f18c2e7a7a9d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Fri, 17 Aug 2012 22:40:12 +0800 Subject: [PATCH 227/261] rk2928: sdk: defconfig: disable bmp logo --- arch/arm/configs/rk2928_sdk_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/rk2928_sdk_defconfig b/arch/arm/configs/rk2928_sdk_defconfig index df2f844b1dd1..9217699d4362 100755 --- a/arch/arm/configs/rk2928_sdk_defconfig +++ b/arch/arm/configs/rk2928_sdk_defconfig @@ -276,6 +276,7 @@ CONFIG_RK_LVDS=y CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set +# CONFIG_LOGO_LINUX_BMP is not set CONFIG_SOUND=y CONFIG_SND=y # CONFIG_SND_SUPPORT_OLD_API is not set From 21d650142f9341a8524b6c4ad291fba811477023 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Fri, 17 Aug 2012 22:59:47 +0800 Subject: [PATCH 228/261] Revert "add usb wifi rtl8188eus support." This reverts commit 1c9e9080691b9ce4f7e8c42643fa026bb020c596. Conflicts: drivers/net/wireless/Kconfig drivers/net/wireless/Makefile drivers/net/wireless/wifi_sys/rkwifi_sys_iface.c --- drivers/net/wireless/rtl8188eu/8188eu.uu | 13701 ---------------- drivers/net/wireless/rtl8188eu/Kconfig | 8 - drivers/net/wireless/rtl8188eu/Makefile | 13 - drivers/net/wireless/rtl8188eu/wifi_power.c | 114 - drivers/net/wireless/rtl8188eu/wifi_power.h | 87 - .../net/wireless/rtl8188eu/wifi_power_ops.c | 112 - .../net/wireless/rtl8188eu/wifi_power_usb.c | 118 - drivers/net/wireless/rtl8188eu/wifi_version.h | 13 - .../net/wireless/wifi_sys/rkwifi_sys_iface.c | 9 +- 9 files changed, 2 insertions(+), 14173 deletions(-) delete mode 100644 drivers/net/wireless/rtl8188eu/8188eu.uu delete mode 100755 drivers/net/wireless/rtl8188eu/Kconfig delete mode 100755 drivers/net/wireless/rtl8188eu/Makefile delete mode 100644 drivers/net/wireless/rtl8188eu/wifi_power.c delete mode 100644 drivers/net/wireless/rtl8188eu/wifi_power.h delete mode 100644 drivers/net/wireless/rtl8188eu/wifi_power_ops.c delete mode 100644 drivers/net/wireless/rtl8188eu/wifi_power_usb.c delete mode 100755 drivers/net/wireless/rtl8188eu/wifi_version.h diff --git a/drivers/net/wireless/rtl8188eu/8188eu.uu b/drivers/net/wireless/rtl8188eu/8188eu.uu deleted file mode 100644 index 66fb8fc7a83f..000000000000 --- a/drivers/net/wireless/rtl8188eu/8188eu.uu +++ /dev/null @@ -1,13701 +0,0 @@ -begin 644 8188eu.o -M?T5,1@$!`0````````````$`*``!```````````````05P8`````!30````` -M`"@`'P`<`![_+^$>_R_A1#"0Y>(C`^,"(-/G``!2XPP```H&+P+C`B#3YP`` -M4N,(```:L"#1X3D`4N,%```:!""1Y0`@DN4$`%+C`""@$P$@H`,#``#JL"#1 -MX3L`4N,`(*`3`2"@`^$;`^,!,-/G`S"2X0``H`,>_R\!0`#0Y0``4.(!`*`3 -M'O\OX3@PD.4!,(/B.#"`Y1[_+^$!`*#C'O\OX03@+>4,T$WB"""-XK(08N$_ -M$*#C9#L#XP_@H.$#\)#G#-"-X@"`O>@$X"WE#-!-X@@@C>(!$&+E-!"@XV0[ -M`^,/X*#A`_"0YPS0C>(`@+WH$$`MZ0%`H.$#`)'I_O__ZP0`H.$<$*#C_O__ -MZQ"`O>@00"WI`4"@X0,`D>G^___K!`"@X1P0H./^___K$("]Z!!`+>D`0*#A -ML##0X0X`4^,0`%,3`@``"@0`D.4($)3E_O__ZPP`E.4``%#C`P``"A`0E.4` -M`%'C````"O[__^L$`*#A'!"@X_[__^L0@+WH$$`MZ0$`H.'^___K$("]Z'!` -M+>D`0*#A`5"@X0Q@D>5;#8#B.`"`X@00D>7^___K``!0XQD```H`,-;EV#"` -MY=0P@.7^___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/E;#"4Y0$($^,"```* -M@``3XX`PPQ-L,(05;#"4Y0$P@^-L,(3E#2"@X7\]PN,_,,/C!""3Y0$@0N($ -M((/E_O__ZP4`H.'^___K<("]Z!!`+>D!0*#A6PV`XC@`@.(,$)'E_O__ZP0` -MH.'^___K$("]Z/!!+>D`4*#A`6"@X01`D>4",-'E``!3XP4```H`,`#C`#!` -MXP`0D^5%#H#B"`"`XO[__^M%#H7B"`"`XO[__^O^___K#2"@X7\]PN,_,,/C -M!""3Y0$@@N($((/E;#"5Y1``$^,/```*6WV%XCAPA^($0(3B!P"@X000H.'^ -M___K``!0XP0``!H'`*#A!!"@X?[__^L``%#C1P``"@4`H.'^___K1```ZFP` -MA>+^___K`'"@X?[__^L-(*#A?SW"XS\PP^,$()/E`2""X@0@@^4``%?C#@`` -M&H0`A>+^___K`'!0X@<``!H-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K -M+```ZO[__^L0`(?E`@``Z@<`H.&$$(7B_O__ZW0PU.5U(-3E`B2#X78PU.4# -M*(+A=S#4Y0,L@N%X((+B`"#$Y2(TH.$!,,3E(CB@X0(PQ.4B/*#A`S#$Y1P` -MA^($$*#A_O__ZW0PU.5U(-3E`B2#X78PU.4#*(+A=S#4Y0,L@N'<`(7B!!"@ -MX7@@@N+^___K;#"5Y8`PP^-L,(7E#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E -M_O__ZPT@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^L&`*#A_O__Z_"!O>@0 -M0"WI`4"@X0(PT>4#`%/C!@``&@`P`.,`,$#C`!"3Y44.@.((`(#B_O__ZP<` -M`.H``%/C!0``"@`P`.,`,$#C`!"3Y44.@.((`(#B_O__ZP0`H.'^___K$("] -MZ'!`+>D`4*#A`4"@X0(PT>4``%/C#@``"O[__^L-(*#A?SW"XS\PP^,$()/E -M`2""X@0@@^5L()7E`2""XVP@A>4$()/E`2!"X@0@@^7^___K<("]Z/[__^L$ -M`*#A_O__ZW"`O>@00"WI`4"@X0(PT>4#`%/C!@``&@`P`.,`,$#C`!"3Y4D. -M@.($`(#B_O__ZP<``.H``%/C!0``"@`P`.,`,$#C`!"3Y4D.@.($`(#B_O__ -MZP0`H.'^___K$("]Z!!`+>G^___K$("]Z#!`+>D,T$WB`$"@X6PPD.5``!/C -M+0``&B``$^,K```:!0!1XP'QGY7^___K!`"@ -MX2<0H.,%(*#A9#L#XP_@H.$#\)3G!@``ZO[__^N(,P/C`P"$YP0`H.'^___K -M````ZO[__^L,T(WB,("]Z/!'+>D`0*#A_O__ZVPPE.4!`!/C+0``"A`UE.5D -M`%/C!0``B@PEE.5D`%+C`&"@DP9PH)$&H*"1!P``F@PEE.4"`%/A`&"@DP%P -MH),'H*"1`6"@@P!PH(,&H*"!^@Y3XP4``(H,)93E^@Y2XP!0H),%@*"1!9"@ -MD0<``)H,)93E`@!3X0%0H),`@*"3!9"@D0!0H(,!@*"#")"@@10UE.4,)93E -M`B"#X`@`4N,$``"*`@!3XP(``(H$`*#A_O__ZPH``.H$`*#A_O__ZP<``.H$ -M`*#A_O__ZP!0H.,%@*#A!9"@X05@H.$%<*#A!:"@X0`PH.,0-83E##6$Y10U -MA.48I<3E&77$Y1IEQ.4;E<3E'(7$Y1U5Q.4$`*#A8#L#XP_@H.$#\)3G\(>] -MZ/!!+>D`4*#A`$!1X@0`H`/P@;T(`#"4Y0$P0^(+`%/C`_&?EU,``.JT!P`` -MU`@``-0(``#(!P``W`<``/P'```,"```'`@``"P(``#4"```Q`@``.P'```% -M`*#A"!"4Y00@E.7^___K0@``Z@4`H.$($)3E!""4Y?[__^L]``#J!0"@X000 -MU.7^___K.0``Z@4`H.&T$-3A_O__ZS4``.H%`*#A!!#4Y?[__^LQ``#J!0"@ -MX000U.7^___K+0``Z@4`H.$$$)3E_O__ZRD``.H%`*#A_O__ZP``4.,E```* -MS#"0Y0``4^,`8*`#%'0``V2`H`,%```*'@``Z@@`H.'^___K`6"&X@L`5N,9 -M```*!0"@X0<0H.'^___K_P3`X_\PT./T__\:"@!6XQ$``,J^.`'CLR"5X0$@ -MPN.S((7AO#@!X[,@E>$!(,+CLR"%X04`H.$%$*#C`""@XP(PH.'^___K`P`` -MZ@4`H.$^$*#C`""@X_[__^L(`)3E``!0XP4```H$$)3E``!1XP(``-K^___K -M``"@X_"!O>@``*#C\(&]Z'!`+>D`0*#A`%`/X8``#/$-(*#A?SW"XS\PP^,$ -M()/E`2""X@0@@^7^___K``!0XP!`H!,`,)0%%$!#`A@@E`44$)0%!""!!0`0 -M@@44,(0%&#"$!07P(>$-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^4`,)/E`@`3 -MXP````K^___K!`"@X7"`O>@00"WI&`"`XO[__^L0@+WH\$\MZ1303>(`4*#A -M!4N`XBB`A.(```#C``!`XP`0`.,`$$#C_O__ZP\`H./^___K3#0!XP,PE><$ -M,(WE`2"@XV@T`>,#(,7G-$"$X@A`C>4$`*#A_O__ZP"`C>4-(*#A?ZW"XS^@ -MRN,,H(WES&L#X]![`^,``)WE_O__ZP``4.-2```*!C"5YP$`4^-/```*!S"5 -MYP$`4^-,```*7)0!XP.PH.,&,)7G`0!3XT<```H',)7G`0!3XT0```H(`*#A -M_O__ZP!`4.+I__\*"`"@X000H.'^___K``!0XPLPH`$",,0%'@``"@DPE>4$$)3E_O__Z[`P -MU.$_`%/C!#"@@P(PQ(4-``"*`"``XP`@0..#,8+@!#"3Y0``4^,#```*!0"@ -MX000G>4S_R_A`@#$Y4@D`>,",-7G`3"#X@(PQ>>P,-3A/P!3XPP``(H`(`#C -M`"!`XX,Q@N#\,9/E``!3XP(``!H$`*#A_O__ZP4``.H%`*#A!!"@X3/_+^$! -M``#J!`"@X?[__^L,,)KE!#"3Y0`PD^4!`!/CN/__"@PPG>4,`)/E_O__Z[3_ -M_^H`(*#C:#0!XP,@Q><(`*#A_O__ZP``4.,!```*_O__Z_G__^H(`)WE_O__ -MZP``H.,`$*#A_O__ZQ!`+>D`,*#A``!1XQ4```H`0`_A@``,\0T`H.%_+<#C -M/R#"XP0`DN4!`(#B!`""Y10`@>(#$*#A_O__ZP3P(>$-(*#A?SW"XS\PP^,$ -M()/E`2!"X@0@@^4`,)/E`@`3XP````K^___K`0"@XQ"`O>AP0"WI`&"@X0!0 -M4>(`0*`##@``"@40H.'^___K`$!0X@(``!H%`*#A_O__ZP<``.H8`(;B!1"@ -MX?[__^L`0*#A`0!0XP$``!H&`*#A_O__ZP0`H.%P@+WH\$$MZ0!PH.$<`*#C -M_O__ZP!0H.$`0*#A``!0XP``H`/P@;T(#`"@X_[__^L`8*#A``!0XP0``!H% -M`*#A'!"@X_[__^L``*#C\(&]Z`L@H.,`((#E`%"@XP10@.4(4(#E%`"$XO[_ -M_^LY,*#CL##$X01@A.4,,*#C"#"$Y0Q0A.404(3E!0N'XB@`@.($$*#A_O__ -MZW``[^;P@;WH\$$MZ0!PH.$<`*#C_O__ZP!0H.$`0*#A``!0XP``H`/P@;T( -M#`"@X_[__^L`8*#A``!0XP0``!H%`*#A'!"@X_[__^L``*#C\(&]Z`D@H.,` -M((#E`%"@XP10@.4(4(#E%`"$XO[__^LY,*#CL##$X01@A.4,,*#C"#"$Y0Q0 -MA.404(3E!0N'XB@`@.($$*#A_O__ZW``[^;P@;WH\$$MZ0!PH.$<`*#C_O__ -MZP!0H.$`0*#A``!0XP``H`/P@;T(#`"@X_[__^L`8*#A``!0XP0``!H%`*#A -M'!"@X_[__^L``*#C\(&]Z`0@H.,`((#E`%"@XPA0@.44`(3B_O__ZSDPH..P -M,,3A!&"$Y0PPH.,(,(3E#%"$Y1!0A.4%"X?B*`"`X@00H.'^___K<`#OYO"! -MO>CP02WI`$"@X0%@H.$L.@/C`S"0YP``4^,!`*`#\(&]"!P`H./^___K`'"@ -MX0!0H.$``%#C``"@`_"!O0@,`*#C_O__ZP"`H.$``%#C!```&@<`H.$<$*#C -M_O__ZP``H./P@;WH"""@XT0`@.@`8*#C"&"`Y10`A^+^___K.3"@X[`PQ^$$ -M@(?E##"@XP@PA^4,8(?E$&"'Y04+A.(H`(#B!Q"@X?[__^MP`._F\(&]Z/!! -M+>D(T$WB`$"@X0%@H.$"4*#A"""-X@`PH.,!,&+E`1"@XVP[`^,/X*#A`_"0 -MYP4``%/C`0"@`RD```H!`%7C(P``&AP`H./^___K`'"@X0!0H.$``%#C -M``"@`R````H,`*#C_O__ZP"`H.$``%#C!```&@<`H.$<$*#C_O__ZP``H.,6 -M``#J!B"@XT0`@.@`8*#C"&"`Y10`A^+^___K.3"@X[`PQ^$$@(?E##"@XP@P -MA^4,8(?E$&"'Y04+A.(H`(#B!Q"@X?[__^MP`._F`P``Z@0`H.$&$*#A_O__ -MZP$`H.,(T(WB\(&]Z/!'+>D`H*#A`8"@X1P`H./^___K`%"@X0!`H.$``%#C -M``"@`_"'O0@,`*#C_O__ZP!@H.$``%#C!```&@4`H.$<$*#C_O__ZP``H./P -MA[WH#'"@XX`!@.@`4*#C"%"`Y10`A.+^___K.3"@X[`PQ.'``(3I#%"$Y1!0 -MA.4%"XKB*`"`X@00H.'^___K<`#OYO"'O>CP02WI`%"@X0%@H.$``%+C(P`` -M"AP`H./^___K`'"@X0!`H.$``%#C``"@`_"!O0@,`*#C_O__ZP"`H.$``%#C -M!```&@<`H.$<$*#C_O__ZP``H./P@;WH!2"@XT0`@.@`8*#C"&"`Y10`A^+^ -M___K.3"@X[`PQ^$$@(?E##"@XP@PA^4,8(?E$&"'Y04+A>(H`(#B!Q"@X?[_ -M_^MP`._F\(&]Z/[__^L!`*#C\(&]Z/!!+>D`@*#A`7"@X1P`H./^___K`%"@ -MX0!`H.$``%#C``"@`_"!O0@!`*#C_O__ZP!@H.$``%#C!```&@4`H.$<$*#C -M_O__ZP``H./P@;WH`'#`Y10`A>+^___K/3"@X[`PQ>$$8(7E`3"@XP@PA>4` -M,*#C##"%Y1`PA>4%"XCB*`"`X@40H.'^___K<`#OYO"!O>CP02WI`("@X0%P -MH.$<`*#C_O__ZP!0H.$`0*#A``!0XP``H`/P@;T(!`"@X_[__^L`8*#A``!0 -MXP0``!H%`*#A'!"@X_[__^L``*#C\(&]Z`!P@.44`(7B_O__ZSPPH..P,,7A -M!&"%Y00PH.,(,(7E`#"@XPPPA>40,(7E!0N(XB@`@.(%$*#A_O__ZW``[^;P -M@;WH\$$MZ0!PH.$!0*#A`E"@X7\`4>-``%$3*P``B@$`H./^___K`&"@X0`` -M4.,F```*`$#`Y0``5>,8```*'`"@X_[__^L`4%#B!```&@8`H.$!$*#C_O__ -MZP!0H.,;``#J%`"%XO[__^L[,*#CL##%X01@A>4!,*#C"#"%Y0`PH.,,,(7E -M$#"%Y04+A^(H`(#B!1"@X?[__^MP4._F!P``Z@<`H.$&$*#A_O__ZP%0<.(` -M4*`S!@"@X0$0H./^___K`0!5XU9%QP4```#J`%"@XP4`H.'P@;WH\$$MZ0!P -MH.$<`*#C_O__ZP!0H.$`0*#A``!0XP``H`/P@;T(#`"@X_[__^L`8*#A``!0 -MXP0``!H%`*#A'!"@X_[__^L``*#C\(&]Z`$@H.,`((#E`%"@XP10@.4(4(#E -M%`"$XO[__^LY,*#CL##$X01@A.4,,*#C"#"$Y0Q0A.404(3E!0N'XB@`@.($ -M$*#A_O__ZW``[^;P@;WH\$+^___K+3"@X[`PQ>$$8(7E -M##"@XP@PA>4`,*#C##"%Y1`PA>4%"XKB*`"`X@40H.'^___K<`#OYO"'O>CP -M1RWI`("@X0%PH.$<`*#C_O__ZP!0H.$`0*#A``!0XP``H`/PA[T(!@"@X_[_ -M_^L`8*#A`*"@X0``4.,$```:!0"@X1P0H./^___K``"@X_"'O>@$`*#C_O__ -MZP"04.('```:!0"@X1P0H./^___K!@"@X080H./^___K``"@X_"'O>@4`(7B -M_O__ZQ8PH..P,,7A!&"%Y08@H.,(((7E#)"%Y00PH.,0,(7E!@"@X0<0H.'^ -M___K!0N(XB@`@.(%$*#A_O__ZW``[^;PA[WH\$]"`0`H./^___K`&"@X0"@H.$``%#C!``` -M&@4`H.$<$*#C_O__ZP``H./PA[WH%`"%XO[__^LG,*#CL##%X01@A>4$,*#C -M"#"%Y0QPA>4T,*#C$#"%Y0`PH.,`,(;E!0N(XB@`@.(%$*#A_O__ZW``[^;P -MA[WH\$]"#0` -MH./^___K`&"@X0"@H.$``%#C!```&@4`H.$<$*#C_O__ZP``H./PA[WH%`"% -MXO[__^LF,*#CL##%X01@A>4T(*#C"""%Y0`PH.,,,(7E$#"%Y08`H.$'$*#A -M_O__ZP4+B.(H`(#B!1"@X?[__^MP`._F\(>]Z/A/+>D`@*#A`9"@X0)PH.$` -M`%/C`P``&@(0H.'^___K`0"@X_B/O>@<`*#C_O__ZP!0H.$`0*#A``!0XP`` -MH`/XC[T(&`"@X_[__^L`8*#A`*"@X0``4.,$```:!0"@X1P0H./^___K``"@ -MX_B/O>@(`*#C_O__ZP"P4.('```:!0"@X1P0H./^___K!@"@X1@0H./^___K -M``"@X_B/O>@4`(7B_O__ZQ4PH..P,,7A!&"%Y1@PH.,(,(7E#+"%Y0@PH.,0 -M,(7E!@"@X>`0B>(&(*#C_O__ZP`PH.,&,,;E!W#&Y04+B.(H`(#B!1"@X?[_ -M_^MP`._F^(^]Z/A/+>D`4*#A`:"@X0*0H.$<`*#C_O__ZP!@H.$`0*#A``!0 -MXP``H`/XC[T(&`"@X_[__^L`<*#A`("@X0``4.,$```:!@"@X1P0H./^___K -M``"@X_B/O>@(`*#C_O__ZP"P4.('```:!@"@X1P0H./^___K!P"@X1@0H./^ -M___K``"@X_B/O>@*8*#A%`"$XO[__^L5,*#CL##$X01PA.48,*#C"#"$Y0RP -MA.4(,*#C$#"$Y0<`H.'@$(KB!B"@X_[__^ML,)7E"``3X\PX`1,#,)47!C#' -M%0X``!K(.`'C`S"5YP,`4^,#\9^7"0``ZF08``!D&```=!@``&08``#,.`'C -M`S"5YP8PQ^4!``#J[#":Y08PQ^4!`%GC"`"(`A$>A@(H.0$3`Q"5%P$2A1`( -M`(@2&1R!$BP0@1(0(*#C_O__ZP$@H.,A/`'C`R#%YP4+A>(H`(#B!!"@X?[_ -M_^MP`._F^(^]Z/!'+>D`@*#A`7"@X1P`H./^___K`%"@X0!`H.$``%#C``"@ -M`_"'O0@$`*#C_O__ZP!@H.$`H*#A``!0XP0``!H%`*#A'!"@X_[__^L``*#C -M\(>]Z!0`A>+^___K$3"@X[`PQ>$$8(7E!#"@XP@PA>4`,*#C##"%Y1`PA>4` -M<,;E!0N(XB@`@.(%$*#A_O__ZW``[^;PA[WH\$$MZ0!PH.$<`*#C_O__ZP!@ -MH.$`0*#A``!0XP``H`/P@;T(!`"@X_[__^L`4%#B!```&@8`H.$<$*#C_O__ -MZP``H./P@;WH%`"&XO[__^L/,*#CL##&X010AN4$,*#C"#"&Y0`PH.,,,(;E -M$#"&Y04+A^(H`(#B!A"@X?[__^MP`._F\(&]Z/!%+>D,T$WB`$"@X0%0H.%X -M8)'EY#8#XP,PD.<``%/C`0``"@@0H.,S_R_A'`"@X_[__^L`<*#A``!0XW@` -M``IL,)3E*``3XP8``!H``%;C(#"#`VPPA`4"```*`0!6XP@P@P-L,(0%!VN$ -MXCA@AN(``%;C`P``&AP0H./^___K``"@XV8``.H&`*#A`!"@X]XOH./^___K -MD""5Y08`H.$<$(7B>"""XO[__^NL/`'C`R"4YR0U`N,#(,3G#"!"XOX`4N,E -M#(3B)0"`XG(=A.(\$('B_R"@@_[__^L`(*#CK#P!XP,@A.>,-)3E`@!3X0,` -M`!JX`(3B(!"%X@8@H./^___KE*"%XG*-A.(P@(CB!`"@X0H0H.$((*#AD#"5 -MY?[__^NL/`'C`P"$YP`PH./,-(3E>SL"XP,PU.<``%/C#0``"I`PE>4``(WE -M!`"@X0H0H.$((*#A_O__ZZP\`>,#,)3G``!3X:P\`1,#`(07`3"@$P`PH`/, -M-(3E`#"@X]@TA.7Z/@+C`S#4YP``4^,.```*S#@!XP,PE.5R+83B+"""X@`@C>4$`*#A"A"@X0@@H.'^___K"@"@ -MX9`0E>7^___KR@O$Y:P\`>,#,)3G>#"#X@@PA^44`(?B_O__ZPXPH..P,,?A -M!&"'Y0`PH.,,,(?E$#"'Y04+A.(H`(#B!Q"@X?[__^MP`._F#-"-XO"%O>CP -M02WI`'"@X0%0H.$"8*#A'`"@X_[__^L`0%#B\(&]"!0`A.+^___K$#"@X[`P -MQ.%@`(3I`#"@XPPPA.40,(3E!0N'XB@`@.($$*#A_O__ZW``[^;P@;WH<$`M -MZ0!`H.'D-@/C`S"0YP``4^,!```*"!"@XS/_+^$<`*#C_O__ZP!04.)P@+T( -M%`"%XO[__^L0,*#CL##%X:X]A.(",(/B!#"%Y?8[`N.S,)3A^"L"X[(@E.$" -M.(/A>#"#X@@PA>4`(*#C#""%Y1`@A>6"*P+CLC"$X2,XH.&$*P+CLC"$X04+ -MA.(H`(#B!1"@X?[__^MP`._F<("]Z/!'+>D`H*#A`8"@X0)PH.$<`*#C_O__ -MZP!0H.$`0*#A``!0XP``H`/PA[T(`0"@X_[__^L`8*#A`)"@X0``4.,$```: -M!0"@X1P0H./^___K``"@X_"'O>@4`(7B_O__ZP0PH..P,,7A!&"%Y0$@H.,( -M((7E#'"%Y1`PA>4`@,;E!0N*XB@`@.(%$*#A_O__ZW``[^;PA[WH\$]Z!0`A>+^___K -M!3"@X[`PQ>$$8(7E"#"@XP@PA>4`,*#C##"%Y1`PA>4`!8;H!0N)XB@`@.(% -M$*#A_O__ZW``[^;PA[WH\$]Z!0`A>+^___K`C"@X[`PQ>$$8(7E`3"@XP@PA>4,<(7E -M$#"%Y0"`QN4%"XKB*`"`X@40H.'^___K<`#OYO"'O>CP1RWI`)"@X0&`H.$" -MH*#A'`"@X_[__^L`4*#A`$"@X0``4.,``*`#\(>]"`(`H./^___K`&"@X0!P -MH.$``%#C!```&@4`H.$<$*#C_O__ZP``H./PA[WH%`"%XO[__^L#,*#CL##% -MX01@A>4",*#C"#"%Y0`PH.,,,(7E$#"%Y0"`QN4!H,;E!0N)XB@`@.(%$*#A -M_O__ZW``[^;PA[WH\$]Z!0`A>+^___K'S"@X[`PQ>$$8(7E`C"@XP@PA>4`,*#C##"% -MY1`PA>4!@,;E`*#&Y04+B>(H`(#B!1"@X?[__^MP`._F\(>]Z/!'+>D`@*#A -M`7"@X1P`H./^___K`%"@X0!`H.$``%#C``"@`_"'O0@-`*#C_O__ZP!@H.$` -MH*#A``!0XP0``!H%`*#A'!"@X_[__^L``*#C\(>]Z!0`A>+^___K&3"@X[`P -MQ>$$8(7E#2"@XP@@A>4`,*#C##"%Y1`PA>4&`*#A!Q"@X?[__^L%"XCB*`"` -MX@40H.'^___K<`#OYO"'O>CP1RWI`("@X0%PH.$<`*#C_O__ZP!0H.$`0*#A -M``!0XP``H`/PA[T(#@"@X_[__^L`8*#A`*"@X0``4.,$```:!0"@X1P0H./^ -M___K``"@X_"'O>@4`(7B_O__ZQLPH..P,,7A!&"%Y0XPH.,(,(7E`#"@XPPP -MA>40,(7E!@"@X04PH.,!,,#D!Q"@X0T@H./^___K!0N(XB@`@.(%$*#A_O__ -MZW``[^;PA[WH^$\MZ0!PH.$!8*#A`H"@X0`0H.,!(*#C_O__ZP<`H.$"$*#C -M`2"@X_[__^L<`*#C_O__ZP!`H.$`H*#A``!0XUD```I3#Z#C_O__ZP!0H.$` -MD*#A``!0XP0``!H$`*#A'!"@X_[__^L`0*#C3@``Z@<`H.$`$*#C_O__ZQ0` -MA.+^___K$C"@X[`PQ.$$4(3E4S^@XP@PA.4`$*#C#!"$Y1`0A.4P,*#C!#"% -MY5@UE^4(,(GD"0"@X5$OH./^___K``!6XQ0```H``%CC$@``V@!`H.,$4*#A -M)+"@XP00AN`$,);G``!3XP(```H$`(G@"R"@X?[__^L!4(7B)$"$X@4`6.$` -M,*#3`3"@PP@`5>,`,*##``!3X^___QIL,)?E`CN#XVPPA^4!,*#C<##'Y04+ -MA^(H`(#B"A"@X?[__^MP0._F`0!4XQ(``!K^___KR`2'Y0`P`.,`,$#C`!"3 -MY4D.A^($`(#B,AZ!XO[__^OD-@/C`S"7YP``4^,"```*!P"@X080H.,S_R_A -M'C"@XU0TA^4$``#J;#"7Y0([P^-L,(?E`#"@XW`PQ^4$`*#A^(^]Z/!!+>D` -M@*#A`7"@X1P`H./^___K`%"@X0!`H.$``%#C``"@`_"!O0@$`*#C_O__ZP!@ -MH.$``%#C!```&@4`H.$<$*#C_O__ZP``H./P@;WH`'"`Y10`A>+^___K*S"@ -MX[`PQ>$$8(7E!#"@XP@PA>4`,*#C##"%Y1`PA>4%"XCB*`"`X@40H.'^___K -M<`#OYO"!O>@00"WI`$!0XA"`O0@@`(3B_O__ZP0`H.'^___K#`"$XO[__^LH -M`)3E``!0XP$```H&'*#C_O__ZS``E.4``%#C$("]"($?H./^___K$("]Z!!` -M+>G^___K$("]Z!!`+>D`0*#A`!"@X_[__^L`,*#C##"$Y0$`H.,0@+WH$$`M -MZ?[__^L0@+WH$$`MZ0!`H.$`$*#C_O__ZPP`A.(`$*#C_O__ZQ@`A.+^___K -M`3"@XR`PQ.4&#*#C_O__ZR@`A.4``%#C$0``"G\/P.,#`,#C`@R`XB0`A.6! -M#Z#C_O__ZS``A.4``%#C"```"@,`P.,$`(#B+`"$Y0`PH.,\,(3E.#"$Y30P -MA.4!`*#C$("]Z```H.,0@+WH$$`MZ?[__^L0@+WH\`4MZ0`PH.,`,(#E!#"` -MY0#`H.$`0*#A"##$Y0$P@^(!0(3B`0Q3X_K__QH!K(SB`$"@XP0PH.$(@*#C -M"&#4`8,7E"'#,Y0$P@^(" -M`%/A`#"@(P'`C.(*`%SA[___&O`%O>@>_R_A\`\MZ0&PH.$``%/C&@``"@`0 -MH.,(0*#C`9#2YP"@D.4!H(KB_Z`*X@I@@.`$8(;@`,#6Y02`D.4(@(S@_X`( -MX@AP@.`$<(?@`%#7Y0"@@.4$@(#E`,#'Y0!0QN4,P(7@?,#@Y@3`W.<,D"G@ -M`9#+YP$0@>(#`%'AYO__&O`/O>@>_R_AH!"@X0@0`>*`$X'AH#&@X:`3@>$$ -M,`/BH"*@X0,P@>$"(`+B@!*@X0(P@^%`$`'B@"&@X0$P@^$@(`+B@`"@X0(P -M@^$0``#B``"#X7``[^8>_R_A\$\MZ1303>(`L*#A!!"-Y0`P`.,`,$#C`#"3 -MY0``4^,D```:Y$"?Y0!0H.,(D*#CMVT!X\%D0.-U`._FVO__ZP`,H.$),*#A -M``!0XX``)K"``*"A`3!3XOK__QH@>*#A((2@X0"@H.$@#*#ASO__ZP``Q.5W -M`._FR___ZP$`Q.5X`._FR/__ZP(`Q.5Z`._FQ?__ZP,`Q.4!4(7B!$"$X@$, -M5>/C__\:`#``XP`P0.,!(*#C`""#Y00PG>4``%/C``#@TPX``-H$0)WE`#"@ -MXP``X.,`P`#C`,!`XP00H.,#(-OG`B`@X/\@`N("(8S@`2"2YR`$(N`!,(/B -M!`!3X?;__QH``.#A%-"-XO"/O>@$`````""@XP(PH.$#P-#G@Q&@X1PA@N$! -M,(/B!`!3X_G__QH"`*#A'O\OX0`0P.4A-*#A`3#@Y2$XH.$!,.#E(1R@X0$0 -MP.4>_R_A`#"0Y0@P@.4$,)#E##"`Y0`PH.,4,(#E$#"`Y1[_+^%P0"WI`$"@ -MX0%0H.$!`*#AX/__ZP``A.4$`(7BW?__ZP0`A.4$`*#A[/__ZW"`O>@4,)#E -M@\&@X1`@D.41+(+A$""`Y0$P@^(4,(#E`P!3XQ[_+Y$(P)#E#"`BX`P0D.7B -M%R'@`B"!X/_$PN/_S,SC_SC"XR,TH.$,-(/A`3`CX`(@@^#B/B/@`B"#X&(Q -M(^`,,(#E`B"#X`@@@.4`,*#C$#"`Y10P@.4>_R_A\$$MZ0!PH.$!8*#A`%!2 -MXO"!O0@`0*#C!P"@X000UN?^___K`4"$X@4`5.'Y__\:\(&]Z'!`+>D`0*#A -M`6"@X5H0H./^___K!`"@X0`0H./^___K!`"@X0`0H./^___K!`"@X0`0H./^ -M___K!`"@X0`0H./^___K%#"4Y0``4^,&```*`%"@XP0`H.$%$*#A_O__ZQ0P -ME.4``%/C^?__&@8`H.$($)3EF?__ZP0`AN(,$)3EEO__ZP0`H.&<___K<("] -MZ/!`+>DDT$WB`,"@X0%`H.$"8*#A`W"@X3Q0W>4`,*#C!##-Y04PS>4&,,WE -M!S#-Y0@`C>(,$*#A_O__ZP10S>4$4*#A`3#UY0$`$^,+```*"`"-XA`0A.(& -M(*#C_O__ZP`PU>4"`!/C"`"-XA@0A!(*$(0"!B"@X_[__^L*``#J"`"-X@00 -MA.(&(*#C_O__ZP`PU>4"`!/C"`"-XA`0A!(*$(0"!B"@X_[__^L(0(WB!`"@ -MX000C>($(*#C_O__ZP0`H.$&$*#A!R"@X?[__^L$`*#A.!"=Y?[__^LDT(WB -M\("]Z/`/+>D(T$WBL##`X0"@H.$C.*#ALC#JX0"`H.$!P-+E`##2Y0PT@^&T -M,.CA`'"@X0/`TN4",-+E##2#X;8PY^$`0*#A!<#2Y00PTN4,-(/AN##DX0`@ -MH.,`,`#C`#!`X[!0U.$!P`+BC)"@X0E@@>`$8(WE`Y0&0B>()D('@`)"- -MY0"PV>4+M*#A!9`FX`N0*>`IE*#A`9R)XHF0@^`%8";@=F#OYH9@@^"P4-GA -MLX090)>"P8-#A!E"%X'50_^:P4,#A`I",XHF0H.$!8*#A"9#VYP%@UN4& -M9*#A"6`FX`5@)N`F9*#A`6R&XH9@@^`%D"G@>9#OYHF0@^"P4-;AL X090 -M)>"P8-KA!E"%X'50_^:P4,KA!)",XHF0H.$!8*#A"9#VYP%@UN4&9*#A"6`F -MX`5@)N`F9*#A`6R&XH9@@^`%D"G@>9#OYHF0@^"P4-;AL X090)>"P8-CA -M!E"%X'50_^:P4,CA!L",XHS`H.$!8*#A#,#VYP%@UN4&9*#A#&`FX`5@)N`F -M9*#A`6R&XH9@@^`%4"S@=5#OYH50@^"PP-;AL%#5X07`+."P4-?A!<",X'S` -M_^:PP,?A!)"=Y0!0V>4`L)WE`&#;Y09DH.&PD-3A!6`FX`Q@)N`F9*#A`6R& -MXH9@@^`,4"7@=5#OYH50@^"PP-;ALX0E0@N`&P"S@#,"%X+#`Q.$!((+B -M"`!2XX___QH(T(WB\`^]Z![_+^'P#RWI$-!-X@#`H.,$0(WBO%"2X;Q0A.$" -MP(SB"@!&P0-3A!(`H -MX+1`W>$$@(C@>(#_Y@)`T>4#4-'E!52@X010)>`(4"7@)52@X0%*%4(+@ -M"$`DX'1`[^:$0(+@L'#5X;!`U.$$<"?@MD#=X01PA^!W4% -M5*#A!%`EX`=0)>`E5*#A`5R%XH50@N`'0"3@=$#OYH1`@N"P8-7AL$#4X01@ -M)N"X0-WA!&"&X'9@_^8&0-'E!U#1Y054H.$$4"7@!E`EX"54H.$!7(7BA5"" -MX`9`).!T0._FA$""X+!0U>&P0-3A!%`EX+I`W>$$4(7@=5#_Y@A`T>4)D-'E -M"92@X020*>`%D"G@*92@X0&*)D(+@!;`DX'NP[^:+L(+@L$#9X;"0V^$) -M0"3@O)#=X0E`A.!T0/_F"K#1Y0N0T>4)E*#A"Y`IX`20*>`IE*#A`9R)XHF0 -M@N`$L"O@>[#OYHNP@N"P(-GAL)#;X0D@(N`"H(K@>J#_Y@V0T>4,(-'E"22" -MX0H@(N""EZ#AHB")X0*`B.!X(/_FM"#-X0^0T>4.@-'E"82(X0*`*."()Z#A -MJ(""X0APA^!W&E(*#AA54"-(/A"J`C -MX,J@H.$#H,#E`#"@XP00C>*S()'A!"#`Y2(DH.$%(,#E`C"#X@(`@.(,`%/C -M]___&A#0C>+P#[WH'O\OX01`+>4`,*#C`T#1YP/`T.<,P"3@`\#"YP$P@^(0 -M`%/C^/__&A``O>@>_R_A!$`MY0`PH.,#0-'G`\#0YPS`).`#P,+G`3"#X@0` -M4^/X__\:$`"]Z![_+^$`,`#C`#!`XP`P@^``!-/E'O\OX7!`+>D0T$WB`$"@ -MX0%0H.$-,*#AH""?Y0<`DN@'`(/H#0#4Y?#__^L,`,WE#@#4Y>W__^L-`,WE -M#P#4Y>K__^L.`,WE!&"@X0P`]N7F___K#P#-Y1`PC>(%4(/@$%!5Y00`H.$, -M$(WB!""@X=/__^L`,-3E`S`EX`10H.$$,,7D!0"@X000H.$%(*#AR___ZPA` -MA.($`*#A!1"@X00@H.'&___K!@"@X000H.$&(*#APO__ZQ#0C>)P@+WH``4` -M`'!`+>D`4*#A`6"@X0!`H.,$`-7GQ/__ZP0`QN4%,-#E`3#!Y0HPT.4",,'E#S#0Y0,PP>4$,-#E!##!Y0DPT.4% -M,,'E#C#0Y08PP>4#,-#E!S#!Y0@PT.4(,,'E#3#0Y0DPP>4",-#E"C#!Y0

    4!,-#E#3#!Y08PT.4.,,'E"S#0Y0\PP>4>_R_A\$`M -MZ2303>(`0*#A`7"@X0`PH.,<`(WB`\"@X1O@H./3$)3A``!1XP/@P+<#P,"G -M`3"#X@0`4^/X__\:`B#4Y1`@S>4#,-3E$3#-Y000H.$!`-'D$@#-Y0`0T>43 -M$,WE%##-Y14`S>46$,WE%R#-Y7\``.(,`,WE?Q`!X@T0S>5_(`+B#B#-Y7\P -M`^(/,,WE##"-X@,`0^(#(-/E@B"@X7(@[^8#(,/ETA#3X0``4>,!((*S`R## -MM0$P0^(``%/A]/__&@PPW>6#,*#A###-Y1A0C>(<`(WB#!"-X@4@H.%:___K -M"&"-X@0`H.$%$*#A!B"@X57__^L(,-WE!##-Y0D@W>4((,WE"B#=Y0D@S>4+ -M(-WE"B#-Y0LPS>4$0(WB!0"@X080H.$$(*#A1___ZPU0H.$0`(WB%!"-X@T@ -MH.%"___K!`"@X0T0H.$'(*#A/O__ZR30C>+P@+WH\$\MZ4S03>(4$(WE`H"@ -MX0`PH.,8$(WB`R#0YP,@P>(HD(WB -M!+")X@0PA^(`,(WE"#")X@0PC>4(,(?B"#"-Y0PPB>(,,(WE##"'XA`PC>48 -MH(WB!%"@X0$``.H!4(7B`6"&X@5`H.$``%7C!P``&@H`H.$4$)WE"""@X0O_ -M_^L*`*#A`!"@XR/__^OR___J"@!5XPP``!HX4(WB"`"@X040H.%,___K*$"- -MX@4`H.$$$*#A4___ZP0`H.$8$(WB"""@X?G^_^L9``#J"`"@X0<0H.%`___K -M!P"@X0D0H.%(___K"0"@X0<0H.%F___K"P"@X0`0G>5C___K`P"=Z6'__^L, -M`)WE$!"=Y5[__^L'`*#A"A"@X0@@H.'C_O_K"@"@X040H.'[_O_K"@!6X\G_ -M_]I,T(WB\(^]Z/``+>D00)WE%,"=Y5E0H.,`4,#E`5"@X0)PH.$`8%'B`6"@ -M$P``4N,``%$3'B#3%0\@`A(!(,`5``!7XP!@H!,!8`8"``!6XQ@@TQ4/(`(2 -M`2#`%0``4>,`(*`#`2#`!0(@H.,*$-/E`A#`YP$@@N(!,(/B"`!2X_G__QH% -M,*#C`Q#_R_A\``MZ0#`H.,,0*#A#$#`YP'`C.(0`%SC^___&A#` -MT>4`P,#E$<#1Y0'`P.42P-'E`L#`Y1/`T>4#P,#E%,#1Y03`P.45P-'E!<#` -MY0#`H.,&P,#E!\#`Y0QP4N`!<*`3#`!3X0#`H!,!P`<"``!,-'E#S`# -MX@XPP.4`,*#C#S#`Y?``O>@>_R_A<``MZ0Q0G>408)WE`,"@XPQ`H.$,0,#G -M`<",XA``7./[__\:`<"@XP#`P.4`P%+B`<"@$P``4>,``%(3'B#3%0\@`A(! -M(,`5``!1XP`0H!,!$`P"``!1XQ@@TQ4/(`(2`2#`%0(@H.,*$-/E`A#`YP$@ -M@N(!,(/B"`!2X_G__QH%,*#C`Q#5YP(0P.<#P-#G -M#,`DX`/`PN4"`%/C`0"@$U0``!I`H('B6PV&XC@` -M@.(*$*#A_O__ZP``4.-,```*1C#4Y0$`$^-5<-05!V*&$!E\AA(L<(<2$7Z` -M`B$PU.4#((7@,!#4Y0,`@>``4(7@=&"4Y09@8^`&8&'@`C#2Y0!`H.,30,?G -M`##2Y1-$S^<$,-+E$TC7YP4PTN433-_G!A#2Y0`PH.,1,,?G!R#2Y1(TS^<1 -MCHWB),B@X0@`H.$'$*#A"B"@X0,XC.&7_/_K$JZ-X@H`H.$'$*#A"""@X70P -M_^8<_?_K!$"-X@0`H.$*$*#A$""@XT'[_^L$`*#A!1"@X04@H.$&,*#A7?O_ -MZP4`H.$$$$;BD/O_ZPP!C>4&,(7@`3!3Y2`,4^$0```:!C"%X`XAW>4",%/E -M`P!2X0L``!H&,(7@#2'=Y0,P4^4#`%+A!@``&@90A>`,`=WE!#!5Y0,`4.$` -M`*`3`0"@`P```.H``*#C3=^-XO"%O>CP3RWI3]]-X@"PH.$!8*#A;%"1Y0`` -M5>-]```*=8#1Y1TPT>4"`%/C>P``&EP`D>4``%#C!0``&EL-B^(X`(#B1A"! -MXO[__^L``%#C<```"D8PUN4!`!/C*#D!$P,PFQ<#,HL0&3R#$BPP@Q(`,(T5 -M$0Z``@``C05XD*_F!)")XHF1H.%YD._F"9"%X$`@AN($((WE`*"@XUD``.JR -M(=;A`C")X!Z`UN4"@(C@"(")X`(@T^420,?G`"#3Y1)$S^<$(-/E$DC7YP4@ -MT^423-_G!B#3Y1)PQ^<',-/E$W3/YR0XH.%&#XWB!@"=Z`5&+XWB=##_YK3\_^L!H(KB'##6Y0,`6N$9```:LC'6X1A0EN4%4&/@ -M'C#6Y0508^`?,-;E!5!CX`@`H.$%$*#A)_O_ZQ0!C>4,`(WB2A^-XA`@H./+ -M^O_K#`"-X@@0H.$((*#A!3"@X>?Z_^L,`(WB!1"(X$4OC>($,*#CXOK_ZR`` -M`.JR,=;A-"4!XP)0F^<%4&/@'C#6Y0508^`?,-;E!5!CX`@`H.$%$*#A#/O_ -MZQ0!C>4,`(WB2A^-XA`@H..P^O_K#`"-X@@0H.$((*#A!3"@X($,*#CQ_K_ZS0E`>,",)OG`Y")X`,P&>(!,*`3*9&#X`F1H.$< -M,-;E`P!:X:+__[H!``#J``"@XP```.H!`*#C3]^-XO"/O>CP3RWIK-!-X@"0 -MH.$<$(WE#""-Y2`PC>6P0-+A_$`$XI``C>(`$*#C$""@X_[__^N``(WB`!"@ -MXQ`@H./^___K<`"-X@`0H.,0(*#C_O__ZV``C>(`$*#C$""@X_[__^M0`(WB -M`!"@XQ`@H./^___K0`"-X@`0H.,0(*#C_O__ZS``C>(`$*#C$""@X_[__^L< -M`)WE&@!0XQ@`4!,`(*`3`2"@`P$@(N)R(._F)#*@X0@P0^(#`%/C``"@@P4` -M`(H<$)WE&@!1XQPPG14",(,2'#"-%0$`H.,,,)WE',"=Y0P0\^>@$,WE`1#3 -MY:$0S>4$$-/EHA#-Y040T^6C$,WE!A#3Y:00S>4',-/EI3#-Y10`C>40((WE -MD$"-XB``G>4``(WEH#"-X@0PC>4$`*#A%!"=Y0PPG>7S_?_K@&"-X@8`H.$< -M$)WE#""=Y1G^_^MP<(WB!P"@X0P0C>(.`)'H.?[_ZR`0G>4/$`'B)!"-Y2`@ -MG>4BLJ#A'#"=Y0@P@^(8,(WE0%"-X@D`H.$$$*#A!2"@X8?]_^M00(WB!0"@ -MX080H.$$(*#AF_[_ZPD`H.$$$*#A!2"@X7[]_^L%`*#A!Q"@X00@H.&3_O_K -M"0"@X000H.$%(*#A=OW_ZP``6^,84)T%$P``"@S`G>48`)WE`%",X`!`H.-` -M8(WB4'"-X@8`H.$%$*#A!R"@X8+^_^L)`*#A!Q"@X08@H.%E_?_K`4"$XA!0 -MA>(+`%3A\___&A@0G>4+4H'@)""=Y0``4N,<```*`#"@XS`0C>(#(*#A`R#! -MYP$P@^(0`%/C^___&@`PH.,P`(WB#,"=Y040C.`DP)WE`R#1YP,@P.)00(WB!@"@X3`0C>($(*#A7/[_ZPD`H.$$ -M$*#A!B"@X3_]_^L`,*#C*`"-XD`0C>(#(-'G`R#`YP$P@^((`%/C^O__&@`P -MH.,,$)WE!5"!X"@0C>(#(-'G`R#%YP$P@^((`%/C^O__&AT``.H!<(?BH""- -MXH0`C>@(`*#A$!"=Y10@G>4,,)WE#_[_ZPD`H.$($*#A"B"@X2']_^L&4*#A -M"@"@X080H.$$(*#A-?[_ZP`PH.,#(-3G`R#%YP$P@^(0`%/C^O__&A!@AN(+ -M`%?AY?__&A@PG>4+,H/@&#"-Y0D``.H``%OC!P``"@S`G>48`)WE`&",X`!P -MH.-@@(WB0*"-XE!`C>+7___J)!"=Y0``4>,P```*H#"-X@`PC>4!L(OB!+"- -MY6``C>(0$)WE%""=Y0PPG>7C_?_K`#"@XS`0C>(#(*#A`R#!YP$P@^(0`%/C -M^___&@`PH.,,P)WE&`"=Y0`@C.`P`(WB),"=Y0)0H.$#$-+G`Q#`YP$P@^(, -M`%/A^?__&D!`C>()`*#A8!"-X@0@H.'A_/_K!`"@X3`0C>)0((WB]OW_ZP`P -MH.-0$(WB)`"=Y0,@T><#(,7G`3"#X@``4^'Z__\:&!"=Y20@G>4"$('@&!"- -MY:`PC>(`,(WE`$"@XP1`C>5@`(WB$!"=Y10@G>4,,)WELOW_ZS`@C>($,*#A -M!##"YP%`A.(0`%3C^___&APPG>4@P)WE#""#X`P`G>4"((#@`#"@XS``C>(( -M$-+E`Q#`YP$P@^(!((+B"`!3X_G__QI`0(WB"0"@X6`0C>($(*#AL/S_ZP0` -MH.$P$(WB4""-XL7]_^L`,*#C#!"=Y1@@G>4"`('@4!"-X@,@T><#(,#G`3"# -MX@@`4^/Z__\:`0"@XZS0C>+PC[WH\$,^```* -M=7#1Y1TPT>4$`%/C/```&ER@D>4``%KC!0``&EL-@.(X`(#B1A"!XO[__^L` -MH%#B,0``"D8PU.4!`!/C*#D!$P.@EA<*HH80&:R*$BR@BA(1KHH"=X"OY@2` -MB.*(@:#A>(#OY@B`A>``4*#C-'4!XQT``.H!4(7B!0!3X0H``!JR$=3A&,"4 -MY0S`8>`>,-3E#,!CX!\PU.4*`*#A"""@X0PP8^"!_O_K#P``ZK(1U.$'P);G -M#,!AX!XPU.4,P&/@'S#4Y0H`H.$((*#A##!CX';^_^L',);G`X"(X`,P&.(! -M,*`3*(&#X`B!H.$<,-3E`P!5X=[__[H!``#J``"@X_"'O>@!`*#C\(>]Z/!/ -M+>FLT$WB`+"@X1P0C>4"@*#A)#"-Y;!`TN'\0`3BD`"-X@`0H.,0(*#C_O__ -MZX``C>(`$*#C$""@X_[__^MP`(WB`!"@XQ`@H./^___K8`"-X@`0H.,0(*#C -M_O__ZU``C>(`$*#C$""@X_[__^M``(WB`!"@XQ`@H./^___K,`"-X@`0H.,0 -M(*#C_O__ZR00G>4($$'B(!"-Y2&BH.$/(`'B&""-Y0@PH.$4!(-/EH2#-Y00@T^6B(,WE!2#3Y:,@S>4&(-/EI"#-Y04:`%+C`3"@`PPPC044( -M((+B%""-Y0``6N,"0*`!(0``"A0PG>4#8(C@`'"@XV"0C>)00(WB`7"'XJ#` -MC>(`P(WE!'"-Y0D`H.$0$)WE#""=Y0@PH.'>_/_K"P"@X0D0H.%`((WB\/O_ -MZP90H.%``(WB!A"@X00@H.$$_?_K`#"@XP,@U.<#(,7G`3"#XA``4^/Z__\: -M$&"&X@H`5^'D__\:%!"=Y0I"@>`8()WE``!2XRH```J@,(WB`#"-Y0$PBN($ -M,(WE8`"-XA`0G>4,()WE"#"@X;[\_^L`,*#C,!"-X@,@H.$#(,'G`3"#XA`` -M4^/[__\:`#"@XP1`B.`P$(WB&`"=Y010H.$#(-3G`R#!YP$P@^(``%/A^?__ -M&D!`C>(+`*#A8!"-X@0@H.&^^__K!`"@X3`0C>)0((WBT_S_ZP`PH.-0$(WB -M&`"=Y0,@T><#(,7G`3"#X@``4^'Z__\:)#"=Y0@@@^(@,,WE`3#8Y:$PS>4$,-CEHC#-Y04P -MV.6C,,WE!C#8Y:0PS>4',-CEI3#-Y0P@G>608(WB_$.?Y2#`G>4`P(WEH#"- -MX@0PC>4&`*#A`A"@X1`@G>4$,*#AY?O_ZX!PC>('`*#A'!"=Y00@H.$+_/_K -M<("-X@@`H.$$$*#A$""=Y0PPG>4J_/_K0%"-X@L`H.$&$*#A!2"@X8#[_^M0 -M0(WB!0"@X0<0H.$$(*#AE/S_ZPL`H.$$$*#A!2"@X7?[_^L%`*#A"!"@X00@ -MH.&,_/_K"P"@X000H.$%(*#A;_O_ZP``6N,44)T%$P``"D1#G^44$)WE`4"$ -MX`!0H.-`8(WB4'"-X@8`H.$$$*#A!R"@X7O\_^L+`*#A!Q"@X08@H.%>^__K -M`5"%XA!`A.(*`%7A\___&A0@G>4*4H+@&#"=Y0``4^,<```*`#"@XS`0C>(# -M(*#A`R#!YP$P@^(0`%/C^___&@`PH.,P`(WBQ!*?Y040@>`8P)WE`R#1YP,@ -MP.)00(WB!@"@X3`0C>($(*#A5?S_ -MZPL`H.$$$*#A!B"@X3C[_^L`,*#C*`"-XD`0C>(#(-'G`R#`YP$P@^((`%/C -M^O__&@`PH.-0(I_E!5""X"@0C>(#(-'G`R#%YP$P@^((`%/C^O__&AP``.H! -M8(;BH!"-XD(`C>@'`*#A$!"=Y0P@G>4),*#A"/S_ZPL`H.$'$*#A"""@X1K[ -M_^L(`*#A!!"@X04@H.$O_/_K`#"@XP,@U><#(,3G`3"#XA``4^/Z__\:$$"$ -MX@H`5N'F__\:%""=Y0HB@N`4((WE"@``Z@``6N,(```*L$&?Y10PG>4#0(3@ -M`&"@XV!PC>*+7___J&,"=Y0``7.,P```*H#"-X@`PC>4! -MH(KB!*"-Y6``C>(0$)WE#""=Y60QG^7<^__K`#"@XS`0C>(#(*#A`R#!YP$P -M@^(0`%/C^___&@`PH.,\(9_E%!"=Y0$@@N`P`(WB&,"=Y0)0H.$#$-+G`Q#` -MYP$P@^(,`%/A^?__&D!`C>(+`*#A8!"-X@0@H.':^O_K!`"@X3`0C>)0((WB -M[_O_ZP`PH.-0$(WB&`"=Y0,@T><#(,7G`3"#X@``4^'Z__\:%""=Y1@PG>4# -M((+@%""-Y:`PC>(`,(WE`$"@XP1`C>5@`(WB$!"=Y0P@G>6@,)_EJ_O_ZS`@ -MC>($,*#A!##"YP%`A.(0`%3C^___&@`PH.,P`(WB',"=Y200G>4!((S@;!"? -MY0(0@>`#(-'G`R#`YP$P@^((`%/C^O__&D!`C>(+`*#A8!"-X@0@H.&J^O_K -M!`"@X3`0C>)0((WBO_O_ZP`PH.,H`)_E%""=Y0(`@.!0$(WB`R#1YP,@P.@$!```<$`MZ0!0H.$!0*#A?&"1Y2\P -MT>4$`%/C`0"@$W"`O1A;#87B.`"`XD`0@>+^___K``!0XP``H`-P@+T(1C#4 -MY0$`$^-5`-05``*%$!D,@!(L`(`2$0Z``B$0U.5TP)3E#,!AX#`PU.4&(*#A -M##!CX"3^_^L!`*#C<("]Z/!%+>E'WTWB`%"@X0%`H.%\8)'E+S#1Y04`4^,! -M`%,3)0``&E6`T>49/8CB!#"#X@,Q@.`$H)/E#7"@X2$0T>4-`*#A`1"&X`,@ -MH./^___K8X^(X@&`B.((4H7@`P"-X@00A>(*(*#A_O__ZR$PU.4P(-3E=%"4 -MY0508^`%4&+@`S""X`-@AN`00(WB!`"@X0T0H.$#((KB^_;_ZP0`H.$&$*#A -M!B"@X04PH.$7]__K!@"@X0001>)*]__K1]^-XO"%O>CP3RWI3=]-X@!@H.$! -M0*#A;""1Y0``4N-I```*=1#1Y1TPU.4%`%/C`0!3$V0``!IQH*_F!*"*XHJA -MH.%ZH._F"J""X-`X`>,#,)#G&3V#X@0P@^(#,8#@!#"3Y00PC>4`@*#C%#"- -MX@,P@^((,(WE-+4!XR20C>($,)WE`S"#X@PPC>4$4*#A2@``ZK(1U>$4`(WB -M`1"*X`,@H./^___KT#@!XP,0EN=C'X'B`1"!X@$2AN`(`)WE!!"!X@0@G>7^ -M___K'C#5Y;(AU>$#<(+@!W"*X`&`B.(<$-7E`0!8X1<``!H80)7E!$!BX`1` -M8^`?$-7E!$!AX`<`H.$$$*#A!_?_ZRP!C>4)`*#A%!"-X@P@G>6K]O_K"0"@ -MX0<0H.$'(*#A!#"@X($,*#CPO;_ZQP``.H+0);G -M!$!BX`1`8^`?$-7E!$!AX`<`H.$$$*#A[_;_ZRP!C>4)`*#A%!"-X@P@G>63 -M]O_K"0"@X0<0H.$'(*#A!#"@X:_V_^L)`*#A!!"'X$LOC>($,*#CJO;_ZPLP -MEN<#H(K@`S`:X@$PH!,JH8/@"J&@X1PPU>4#`%CAL?__NDW?C>+PC[WH$$`M -MZ0`PH.%2#8#B!`"`XHPD`>,/X*#A`O"3YQ"`O>@00"WI`#"@X5(-@.($`(#B -MD"0!XP_@H.$"\)/G$("]Z!!`+>D`,*#A4@V`X@0`@.*4)`'C#^"@X0+PD^<0 -M@+WH$$`MZ0#`H.',"P/C``"D`P*#A4@V`X@0`@.*X1`'C#^"@ -MX03PG.<0@+WH$$`MZ0#`H.',"P/C``"G4-`'C`S"0YP``4^,0 -M@+T(4@V`X@0`@.(S_R_A$("]Z!!`+>D`P*#A4@V`X@0`@.+(1`'C#^"@X03P -MG.<0@+WH$$`MZ,,P)#G``!G8-`'C`S"0YP``4^,0@+T(4@V`X@0`@.(S_R_A$("]Z!!`+>E2/:#C -M`P"`YX0T`>,#`(#G'""`XH@T`>,#((#G4@V`X@P`@.+^___K`0"@XQ"`O>@0 -M0"WI`#"@X5(-@.($`(#BL,0!XP_@H.$,\)/G_O__ZQ"`O>@00"WI`#"@X5(- -M@.($`(#BK,0!XP_@H.$,\)/G_O__ZQ"`O>@00"WI`#"@X5(-@.($`(#BJ,0! -MXP_@H.$,\)/G_O__ZQ"`O>@00"WI`,"@X5(-@.($`(#BI$0!XP_@H.$$\)SG -M_O__ZQ"`O>@00"WI`#"@X5(-@.($`(#BH,0!XP_@H.$,\)/G_O__ZQ"`O>@0 -M0"WI`#"@X5(-@.($`(#BG,0!XP_@H.$,\)/G_O__ZQ"`O>@00"WI`#"@X5(- -M@.($`(#BF,0!XP_@H.$,\)/G_O__ZQ"`O>@`$)#E(`!1XQ0``(H``%'C%``` -M"@0PT.4@,$/B -M_R_A`0!1XP``H(-8%8"5`0"@DQ[_+^$00"WI`2"@X_[__^L0@+WH<$`MZ0!0 -MH.$!0*#A`0"@X0`0`.,`$$#C_O__ZP``4.,-```*!`"@X0`0`.,`$$#C_O__ -MZP``4.,"$*`#!P``"@0`H.$`$`#C`!!`X_[__^L``%#C!1"@`P````H`$*#C -M!0"@X?[__^MP@+WH\$`MZ0S03>(`4*#A`4"@X0`PH.,$,(WELC#-X0$PS>5L -M,)#E`0`3XP(``!I``!/C``"@`U````IT,-3E=2#4Y0(T@^%V(-3E`CB#X7<@ -MU.4"/(/AA`"$XBT0H.,$((WB##!#XO[__^L`$%#B$```"@0PG>4``%/C#0`` -M"@%@H.$"`(WB!1"!X@(@H./^___K`C#VY0$@UN4"-(/ATW#@YV``$^,`8*`# -M`6"@$P$0H.,"``#J`&"@XP9PH.$&$*#A8##4Y0$@0^)R(._F_0!2XP``H(,) -M``"*``"@XW\P`^(``%/A`P"@(6$PU.4!0(3B`2!#XG(@[^;]`%+C]O__F@$` -M4>.@`*`1&P``&@4`H.$4$*#C`2"-XF@[`^,/X*#A`_"5YP$PW>4#`%/C"0`` -M&@``5^,#```*``!6XY8`H!.'`*`##```Z@``5N-(`*`300"@`P@``.H``%?C -M`P``"@X!`.,``%;C2P^@$P(``.H``%;CD`"@$X(`H`,,T(WB\("]Z!!`+>D` -M,*#A!""1Y0T1TN,3```:`0,2XP<``!H9/(#B+#"#X@,@`N("`H/@`!"@XQ`@ -MH./^___K"0``ZEL-@.(X`(#BX!"#XO[__^L``%#C`P``"A$.@.(`$*#C$""@ -MX_[__^L!`*#C$("]Z/!!+>D!0*#A`6"@X0!0H.$!`'#B``"@,Z$/D.$5```: -M`P!1XQ,``(IC?87B%`"'X@$"@.``$*#C$""@X_[__^L%`*#A"!"'X@0@H.$` -M,*#C_O__ZQE-A.($0(3B!$&%X`1`A.(`,*#C`#"$Y0,`4.`!`*`3\(&]Z``` -MH./P@;WH<$`MZ0!`H.$!4*#A!&"1Y0-AQN,$`%;C``"@PW"`O<@(,)'E!0!3 -MXP$@H`/,.`$#`R"$!P8```H-`%/C`""@$\PX`1,#((07!2"@`\PX`0,#((0' -M8P^&X@$`@.(``H3@!`"`X@P0A>((()7E_O__ZQD]AN($,(/B`S&$X`@@E>4$ -M((/ET#@!XP-@A.<$`*#A8QV$X@@0@>(&(*#A`3"@X_[__^L``%#B`0"@$W"` -MO>CP1RWI"-!-X@!`H.$!4*#A!#"1Y0``4^,"``"Z`0$3XRX```H\`0#J`0$3 -MXRL```I;#8#B.`"`XN`0A.+^___K``!0XP0```K(.`'C`S"4YP(`4^/L8)`% -M`0``"LPX`>,#8)3G!##5Y0``4^,J`0`:##"5Y0$`<^,J`0`:L"'5X?\_#^,# -M`%+A)@$`&B(!`.H(,)7E(`!3XQ\!`!I,``#J!`!6XPD``!H(,)7E$`!3XP8` -M``H@`%/C%P$`&A`PH.,(,(7E`'"@XP<@H.%$``#J!0!6XP$`5A,/`0`*/``` -MZC`\`>,#,)3G`P!3XQ,``(HD.0'C`S"4YP``4^,/```:"#"5Y04`4^,!(*`# -MS#@!`P,@A`<&```*#0!3XP`@H!/,.`$3`R"$%P4@H`/,.`$#`R"$!\PX`>,# -M8)3G`0``ZB0Y`>,#8)3G;#"4Y2``$^,&```*##"5Y0$`<^/N```:L"'5X?\_ -M#^,#`%+AZ@``&@(`5N,#```:"#"5Y2``4^/E```:"```Z@0`5N,&```:"#"5 -MY1``4^,@`%,3W@``&B``4^,0,*`#"#"%!01PE>77?>#G;#"4Y2``$^,'```* -M`0`3XP%PH!,'(*`1`P``"@,``.H`<*#C!R"@X0```.H!(*#CR#@!XP,PE.<" -M`%/C)@``"@4`5N,!`%83(P``&@@@E>4@((+BL#\!XP,@A.<$8)7E`F'&X[0_ -M`>,#8(3G"""5Y;@_`>,#((3G('"%XGZ-A.(\`(CB!Q"@X0@@E>7^___K8S^& -MX@$P@^(#,H3@!`"#X@<0H.$(()7E_O__ZQD]AN($,(/B`S&$X`@@E>4$((/E -MT#@!XP-@A.<$`*#A,!"(XO[__^L!`*#CHP``Z@0PE>4"`A/C&P``"@$`4N,, -M```:V('%X0``X./_'P_C`"`(X`$P">`($(WB^"!AX6<-A.(X`(#B#1"@X0@@ -MH./^___K#@``ZMB!Q>$``.#C_Q\/XP`@".`!,`G@"!"-XO@@8>%G#83B,`"` -MX@T0H.$((*#C_O__ZU```.H!`%+C3@``&@$`5^,$(-4%*#D!`P,@A`<$,)7E -M`P`3XWH```H9;(3B+&"&X@,P`^(#`H;@`!"@XQ`@H./^___K97V$XBQPA^($ -M`-7E`P``X@`"A^``$*#C$""@X_[__^MFC83B+("(X@0`U>4#``#B``*(X``0 -MH.,0(*#C_O__ZP0PE>4!`A/C"P``"@,P`^(#`H?@,!"%X@@@H./^___K!`#5 -MY0,``.(``HC@.!"%X@@@H./^___K"@``Z@,P`^(#`H?@.!"%X@@@H./^___K -M!`#5Y0,``.(``HC@,!"%X@@@H./^___K!`#5Y0,``.(``H;@(!"%X@@@E>7^ -M___K!#"5Y0,P`^($,(7E`3"@XR`L`>,",,3G`!"@XR(L`>,"$,3G!`"@X6,= -MA.(($('B!""5Y?[__^L``%#B`0"@$S,``.I;#83B.`"`XN`0A.+^___K`(!0 -MX@$`H`,L```*$:Z(X@H`H.$`$*#C$""@X_[__^L@D(7B"@"@X0D0H.$0(*#C -M_O__ZP(`5N,6```:`""@XR$\`>,#(,3G!#"5Y0$"$^,(```*\`"(XA`0B>(( -M(*#C_O__ZP$,B.(8$(GB"""@X_[__^L'``#J\`"(XA@0B>(((*#C_O__ZP$, -MB.(0$(GB"""@X_[__^L``%?C!`"@X0@0H.$`(*`3`2"@`_[__^L``%#B`0"@ -M$P```.H``*#C"-"-XO"'O>@"`%;CV_[_&M;^_^H00"WI8SV`X@@P@^(P+`'C -M`A"`YP,`4>,"$*"#R"@!@P(0@(<#$*#A_O__ZP$`4.,``*`3`0"@`Q"`O>AP -M0"WI`$!0XAH```KA.P/C`S#4YP``4^,6```*;#"4Y2(-$^,5```:JY0$` -M4^,2```*_O__ZPTPH.%_74!,(/B!#"%Y00`H.$`$*#C`2"@ -MX?[__^L`0*#A!#"5Y0$P0^($,(7E_O__ZP(``.H`0*#C````Z@%`H.,$`*#A -M<("]Z!!`+>D`0*#A_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B!""#Y6PPE.4! -M`!/C!@``"@0`H.'^___K!`"@X?[__^L$`*#A`1"@X_[__^L-(*#A?SW"XS\P -MP^,$()/E`2!"X@0@@^7^___K`0"@XQ"`O>AP0"WI`$"@X0%0H.$X,9#E`0!3 -MX3\```K^___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/E;#"4Y0$`$^,"```: -M."&4Y0``4N,$```:!`"@X?[__^ML,)3E`0`3XP$``!I``!/C!0``"@0`H.$! -M$*#C_O__ZVPPE.4!`!/C!```&C@QE.4!`%/C`0``"@``4^,!```:!`"@X?[_ -M_^LX,93E!`!3XP,``!H`,.#CV#"$Y00`H.'^___K.%&$Y6PPE.5X,,/C;#"$ -MY0$`5>,(,(,#;#"$!0@```H@,(,S;#"$-04``#H$`%7C`P``&A`P@^-L,(3E -M!`"@X?[__^L-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K`0"@XW"`O>AP -M0"WI`$"@X?[__^L-(*#A?SW"XS\PP^,$()/E`2""X@0@@^6$,)3E`2#@X]@@ -MA.5L()3E@"""XVP@A.5X,(3E`3"@XW$PQ.6$`(3B_O__ZP$`4.,4```:#2"@ -MX7\]PN,_,,/C!""3Y0$@0N($((/E_O__ZVPPE.6`,,/C;#"$Y1@UU.4``%/C -M`@``"G(PU.4``%/C0P``"@0`H.&4$(3B`2"@X_[__^MP@+WH#2"@X7\]PN,_ -M,,/C!""3Y0$@0N($((/E_O__ZVP`A.+^___K`0!0XPL``!H`,*#C<3#$Y0`P -M`.,`,$#C`!"3Y44.A.((`(#BHA^!X@(0@>+^___K`0"@XW"`O>AL,)3E(``3 -MXQ<```I`,*#C;#"$Y:YMA.(.4(;B!0"@X0`0H.,D(*#C_O__ZP4`H.&4$(3B -M)""@X_[__^L$`*#A_O__ZP8`AN+^___K!`"@X?[__^L!`%#C``"@$P`PH`-Q -M,,0%`0"@`W"`O>B`,,/C;#"$Y1@UU.4``%/C`@``"G(PU.4``%/C!```"@0` -MH.&4$(3B`2"@X_[__^MP@+WH`0"@XW"`O>AP0"WI`$"@X0%0H.'A.P/C`S#0 -MYP``4^,`0*`#<```"O[__^L-(*#A?SW"XS\PP^,$()/E`2""X@0@@^5L,)3E -M`@L3XS@``!J``!/C6@``&D$`$^,T```*E""4Y0`PE>4#`%+A(0``&I@`A.($ -M$(7B_O__ZP$`4.,<```:;#"4Y0@`$^,4```:!`"@X<`0A.+^___K``!0XT<` -M`!H$`*#A_O__ZVPPE.4!`!/C`0``"@0`H.'^___K!`"@X0$0H./^___K;#"4 -MY4``$^-`,,,3(#"#$VPPA!43``#J!`"@X0$0H.,!(*#A_O__ZPX``.H$`*#A -M_O__ZVPPE.4!`!/C`0``"@0`H.'^___K!`"@X0$0H./^___K;#"4Y4``$^-` -M,,,3(#"#$VPPA!4H-P+C`S#4YP$`4^,+```:_O__ZRPW`N,#,)3G`#!CX'`G -M`>,"`%/A&@``F@`PH.,H)P+C`C#$YRPG`N,",(3G!0"@X?[__^L``%#C$0`` -M"I0`A.(%$*#A)""@X_[__^L`,*#CC#2$Y6PPE.4""Q/C`3"@$W$PQ!4#0*`1 -M!@``&@0`H.'^___K`$"@X0(``.H!0*#C````Z@!`H.,-(*#A?SW"XS\PP^,$ -M()/E`2!"X@0@@^7^___K!`"@X7"`O>AP0"WI`$"@X0%0H.$`,-'E``!3XP\` -M`!H!(-'E``!2XPP``!H",-'E``!3XQH``!H#,-'E``!3XQ<``!H$,-'E``!3 -MXQ0``!H%,-'E``!3XQ$``!IA``#J_P!3XPX``!H!,-7E_P!3XPL``!H",-7E -M_P!3XP@``!H#,-7E_P!3XP4``!H$,-7E_P!3XP(``!H%,-7E_P!3XU````K^ -M___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/E;#"4Y0(+$^,<```:@``3XSL` -M`!I!`!/C&```"N``A.(%$*#A!B"@X_[__^L!`%#C`P``&FPPE.4(`!/C,``` -M"@X``.H$`*#A_O__ZVPPE.4!`!/C`0``"@0`H.'^___K!`"@X0$0H./^___K -M;#"4Y4``$^-`,,,3(#"#$VPPA!4H-P+C`S#4YP$`4^,,```:_O__ZRPW`N,# -M,)3G`#!CX'`G`>,"`%/A`$"@DQ4``)H`,*#C*"<"XP(PQ.@$0"WE%-!-X@#`H.$`,`#C`#!`XPU`H.$/ -M`)/H!P"DZ``PQ.4`,-WE``!3XPX```H,`%/A`#"@`P4``!H!``#J#`!2X00` -M`!H!`*#C$`.@X08``.H`,*#C#1"@X0$P@^(#(-'G``!2X_3__QH``*#C%-"- -MXA``O>@>_R_A`##0Y0``4^,8```*?S`#X@0`4^,"`%,3$@``"@L`4^,0```* -M%@!3XP`@H!,(```:#```ZG\P`^($`%/C`@!3$P@```H+`%/C!@``"A8`4^,$ -M```*`2""X@(PT.<``%/C\___&@$``.H!`*#C'O\OX0``H.,>_R_A`##0Y0`` -M4^,.```*`""@XW\P`^("`%/C!`!3$P4```H+`%/C`P``"A8`4^,!```*``"@ -MXQ[_+^$!((+B`C#0YP``4^/Q__\:`0"@XQ[_+^$00"WI`$"@X0X`4N,$``#: -M_O__ZP$`4.,$`*`3``"@`Q"`O>C^___K`0!0XQ"`O0@$`*#A_O__ZP$`4.,# -M`*`#`@"@$Q"`O>@P`"WI``!3XPP``-H`P*#C`,""Y0!`T.4!`%3A`3#0!0`P -M@@4&```*`4#0Y0)0A.(%P(S@#`!3X04`@,#T___*``"@XS``O>@>_R_A`##0 -MY0``4^,`,*`3`@``&@4``.H-`%/C`P``"@$P@^(#(-#G``!2X_G__QH#`*#A -M'O\OX1!`+>D!P*#A`C"@X3`0H.,,(*#A_O__ZQ"`O>@`,*#A,`!`XG``[^8) -M`%#C'O\OD6$@0^)R(._F!0!2XU<`0Y)P`.^6'O\OD4$@0^)R(._F!0!2X_\` -MH(,W`$.2<`#OEA[_+^%P0"WI`5"@X>K__^L`0*#A!0"@X>?__^L$083@A`"` -MX'``[^9P@+WH<$`MZ0%0H.'@___K`$"@X04`H.'=___K!`*`X7``[^9P@+WH -M`0!1XPH``!H`,-#E(`!3XPD``!H-``#J`1!!X@$PT.<``%/C"P``&@``4>/Y -M__\:!@``Z@``4>,$```*`1!!X@$PT.<``%/C]O__"@$``.H!`*#C'O\OX0`` -MH.,>_R_A##``X@0`4^,)```*"`!3XQ@PH!,.```:@``0XQ@PH`,:,*`3`PP` -MX@,,4.,&,(,"!P``ZO`@`.+`,$+B$`!3XQ`PH(,`,`"3`#!`DP(A@Y#P,A*5 -M`P"@X1[_+^$00"WI`D"@X0`0P.4B)*#A`B#`Y0%`P.4`$%/B`@``"@,`@.($ -M(*#A_O__ZP,`A.(0@+WH\$`MZ0S03>(`<%#B20``"@`P`.,`,$#C`$"3Y0`` -M5.,.```*`&"@XPU0H.$``-3E`1#4Y?[__^L&`,7G`6"&X@-`A.(&`%;C]___ -M&@<`H.$-$*#A!B"@X_[__^L#``#J#0"@X0<0H.$&(*#C_O__ZP`PW>7_`%/C -M#P``&@$@W>7_`%+C#```&@(PW>7_`%/C*```&@,PW>7_`%/C)0``&@0PW>7_ -M`%/C(@``&@4PW>7_`%/C'P``&A```.H``%/C'```&@$PW>4``%/C&0``&@(P -MW>4``%/C%@``&@,PW>4``%/C$P``&@0PW>4``%/C$```&@4PW>4``%/C#0`` -M&@`PH.,`,,WE'R#@XP$@S>5,(*#C`B#-Y7@@X.,#(,WE!##-Y04PS>4'`*#A -M#1"@X08@H./^___K#-"-XO"`O>AP0"WI`$"@X0)0H.$08)WE`!#`Y0$@Q.4` -M`%+C`@``"@(`@.(#$*#A_O__ZP(`A>(`,);E`#"#X``PAN4``(3@<("]Z'!` -M+>D`8*#A`4"@X0-0H.$"$*#A!""@X?[__^L`,)7E!#"#X``PA>4$`(;@<("] -MZ/!!+>D`8*#A`5"@X0)`H.$"`*#A`!"@X[@@H./^___K`0!5XP``H).5``": -M`##6Y0$0]N4"4$7B`2"@X04`4>&4``"*`6"&X@``H./R<`7C3,`)XP<``.H" -M8(;@`##6Y0$0]N4"4$7B`2"@X0$`5>&(```Z`6"&XB0`4^.`8(0%A!#$!7L` -M``H@``"*!`!3XR!@A`4D$,0%=@``"@T``(H!`%/C"&"$!0P0Q`5Q```*`&"$ -M-000Q#5N```Z`@!3XQ!@A`44$,0%:@``"@,`4^-G```:+P``Z@8`4^,P8(0% -M-!#$!6,```HH8(0U+!#$-6```#H0`%/C.&"$!3P0Q`5<```*(0!3XUD``!I5 -M``#J-@!3XXA@A`6,$,0%50``"@X``(HM`%/CH&"$!:00Q`50```*`@``BBH` -M4^-,```:%P``ZC``4^-88(0%7!#$!4@```HR`%/C10``&A,``.HX`%/CF&"$ -M!9P0Q`5!```*D&"$-900Q#4^```Z/0!3XZA@A`6L$,0%.@``"MT`4^,W```: -M"```ZAA@A.4<$,3E-```ZD!@A.5$$,3E,0``ZDA@A.5,$,3E+@``Z@,`4N,F -M``":`C#6Y0"`UN4(.(/A`8#6Y0@T@^$'`%/A`@``"@P`4^$=```:%P``Z@,P -MUN4"`%/C"```"@0`4^-P8(0%=!#$!1L```H!`%/C4&"$!500Q`41```:%@`` -MZ@0`4N,.``":!##6Y0$`4^-@8(259!#$E0\``)H"`%/C!P``&FA@A.5L$,3E -M"@``Z@,PUN4S`%/CL&"$!;00Q`4%```*`0"`X@,``.IX8(3E?!#$Y0```.H! -M`(#B!5!BX`$`5>-T__^*``!5XP(``!H``%#B`0"@$_"!O>@``.#C\(&]Z'!` -M+>D`4*#A`4"@X0`0H.,0(*#C_O__ZQ0`5.-P@+V(`3"@XQ-$H.$4,`#C$3!` -MXP,P!.```%/C#```&@@]`.,`,$#C`S`$X```4^,,```:`@`4XW"`O0@%`*#A -M`!``XP`00.,$(*#C_O__ZW"`O>@%`*#A-!"?Y0@@H./^___K<("]Z`!``.,` -M0$#C!0"@X000H.$$(*#C_O__ZP0`A>($$(3B"""@X_[__^MP@+WH]`,``/!! -M+>D0T$WB`$"@X;HHT.&Z+,#A"C"@XPPPC>7,`(#B`B"@X[`@P.$M(-3E`P!2 -MXR(@H`.P(,`!NB?4X;P7U.$!&)+AL"#0$1`@@A.P(,`1##"=Y0(P@^(08(WB -M!#`FY;8UU.&X)=3A`&"-Y0(`@.(`$*#C`BB#X5HPA.+^___K`("@X2H0U.4? -M`%'C!0``&K(YU.&T&=3A`1B#X0X`4>,4$*"#"Q"@DZIPA.('`*#A_O__ZP<` -MH.'^___K`""@X0!0H.$(`%#C%0``V@!@C>4(`*#A`1"@XP@@H.,',*#A_O__ -MZP!@C>4#$*#C`2"@XY(PA.+^___K`&"-Y080H.,"(*#CCC"$XO[__^L`8(WE -M,A"@XP@@1>*R,(3B_O__ZPX``.H`8(WE"`"@X0$0H.,',*#A_O__ZP!@C>4# -M$*#C`2"@XY(PA.+^___K`&"-Y080H.,"(*#CCC"$XO[__^L,`)WE$-"-XO"! -MO>CP1RWI"-!-X@!0H.$!<*#A`H"@X0.@H.$H8)WE`#``XP`P0.-4,)/E!#"- -MY0``5N,`,*`3`#"&%0`PT.7=`%/C)P``&@(`@.($$(WB!""@X_[__^L!`%#C -M(0``&@9`A>($,&7@`P!7X1T``)H"D-3E`3#4Y0F4@^$#D(GB>9#_Y@`PU.4( -M`%/A$0``&@<``.H"D-3E`3#4Y0F4@^$#D(GB>9#_Y@`PU.4(`%/A"```&@`` -M6N,#```*"@"@X000H.$)(*#A_O__ZP``5N,`D(85!```Z@E`A.`$,&7@!P!3 -MX>K__SH`0*#C!`"@X0C0C>+PA[WH<$`MZ1#03>(#4*#A($"=Y0``5.,`,*`3 -M`#"$%0PPC>(`,(WE`#"@X_[__^L`8%#B#@``"@P@G>4``%+C"P``"@``5>,# -M```*!0"@X0,0AN(#($+B_O__ZP``5.,,,)T5`S!#$@`PA!4#`(;B````Z@`` -MH.,0T(WB<("]Z/!/+>D4T$WB`%"@X0%PH.$$((WE`"``XP`@0.-8()+E#""- -MY0"P4^(`,*`3`#"+%0``4>,B```*`$"@XPR@C>($D*#C`8"@XP1@A>``,-;E -MW0!3XQ0``!H"`(3B``"%X`H0H.$)(*#A_O__ZP$`4.,-```:!A"@X00PG>4` -M`%/C`P``"@$@UN4$`)WE`B""XO[__^L``%OC!$"%$`$PU!4",(,2`#"+%08` -M`.H$,(7@"##3YP(P@^(#0(3@!`!7X>#__XH`8*#C!@"@X130C>+PC[WH\$\M -MZ1S03>(`L*#A#!"-Y70PT.5U$-#E`12#X78PT.4#&('A=S#0Y0,<@>&$`(#B -M#!!!X@`@H.,4,(WB_O__ZP"04.)+```*%&"=Y0!PH.,!@(GB$#"-X@`PC>4) -M`*#A!A"@X0P@G>4',*#A_O__ZP!`4.(7```*$""=Y0``4N,4```*`J"$X`E0 -M:N`&4(7@!`"@X0<0H.'^___K!`"@X0H0H.$%(*#A_O__ZP4`A.`'$*#A$""= -MY?[__^L`(-CE$##=Y0(P8^``,,CE$#"=Y09@8^#>___J%!"=Y08`4>$D```* -M`1")X`:0B>!X0(OB!$!AX'0PV^5U(-OE`C2#X78@V^4".(/A=R#;Y0(\@^$# -M0(3@"0"@X00@H.'^___K!`")X``0H.,4()WE`B!FX/[__^MT,-OE=2#;Y0(T -M@^%V(-OE`CB#X7<@V^4"+(/A%#"=Y0(P8^`&8(/@=&#+Y28TH.%U,,OE)CB@ -MX78PR^4F;*#A=V#+Y1S0C>+PC[WH,$`MZ0S03>(`4*#A`4"@X0`@H.,$,(WB -M_O__ZP``5>$.```:!#"=Y0``4^,+```*!C"%X@,@9>`"`%3A!P``F@(0T^4! -M(-/E`22"X0,@@N(",(/@`R!EX`(`5.'W__^*#-"-XC"`O>CP1RWI"-!-X@!0 -MH.$!<*#A`H"@X0.@H.$H8)WE`#``XP`P0.-<,)/E!#"-Y0``5N,`,*`3`#"& -M%0`PT.7=`%/C*P``&@(`@.($$(WB!""@X_[__^L!`%#C)0``&@9`A>($,&7@ -M`P!7X2$``)H"D-3E`S#4Y0F4@^$$D(GB>9#_Y@`@U.4!,-3E`C2#X0@`4^$3 -M```:"0``Z@*0U.4#,-3E"92#X020B>)YD/_F`"#4Y0$PU.4"-(/A"`!3X0@` -M`!H``%KC`P``"@H`H.$$$*#A"2"@X?[__^L``%;C`)"&%00``.H)0(3@!#!E -MX`<`4^'H__\Z`$"@XP0`H.$(T(WB\(>]Z'!`+>D0T$WB`U"@X2!`G>4``%3C -M`#"@$P`PA!4,,(WB`#"-Y0`PH./^___K`&!0X@X```H,()WE``!2XPL```H` -M`%7C`P``"@4`H.$$$(;B!"!"XO[__^L``%3C##"=%00P0Q(`,(05!`"&X@`` -M`.H``*#C$-"-XG"`O>CP3RWI%-!-X@!0H.$!<*#A!""-Y0`@`.,`($#C8""2 -MY0P@C>4`L%/B`#"@$P`PBQ4``%'C``!0$R0```H``%'C(@``"@!`H.,,H(WB -M!)"@XP&`H.,$8(7@`##6Y=T`4^,4```:`@"$X@``A>`*$*#A"2"@X?[__^L! -M`%#C#0``&@80H.$$,)WE``!3XP,```H!(-;E!`"=Y0(@@N+^___K``!;XP1` -MA1`!,-05`C"#$@`PBQ4&``#J!#"%X`@PT^<",(/B`T"$X`0`5^'@__^*`&"@ -MXP8`H.$4T(WB\(^]Z#!`+>D,T$WB`%"@X0%`H.$`(*#C!#"-XO[__^L``%7A -M#@``&@0PG>4``%/C"P``"@8PA>(#(&7@`@!4X0<``)H"$-/E`R#3Y0$D@N$$ -M((+B`C"#X`,@9>`"`%3A]___B@S0C>(P@+WH\$$MZ0%PH.$`8*#A`$"@X0%0 -MU.4$`*#A!1"@X?[__^L$`*#A!1"@X?[__^L"4(7B!4"$X`0P9N`'`%/A\___ -MFO"!O>@P0"WI#-!-X@%0H.$`,`#C`#!`XV0PD^4$,(WE`$!0X@L```H`,-3E -MW0!3XP@``!H"`(3B!!"-X@0@H./^___K`0!0XP$PU`4",(,"`#"%!0````H` -M`*#C#-"-XC"`O>CP3RWI%-!-X@!@H.$!@*#A!""-Y0.0H.$`,`#C`#!`XV@P -MD^4,,(WE#`!1XSP``)H,0*#C`:"@XP1PAN``4-?EW0!5XQH``!H"L(3B"P"& -MX`P0C>($(*#C_O__ZP$`4.,3```:`4"$X@1`AN``(-3E.`"=Y0<0H.$"((+B -M_O__ZP`0U.4"(('B`#"@XP@P@^)S,._F`@!3X?O__[H"$('B/#"=Y;`0P^$` -M0-3E!$"+X!D``.HP`%7C$P``&@%0A.(%4(;@`"#5Y00`G>4'$*#A`B""XO[_ -M_^L`$-7E`B"!X@`PH.,(,(/B$"0(3B`##5 -MY0-`A.`#``#J!#"&X`HPT^<"0(3B`T"$X`0`6.'$__^*/#"=Y;``T^&P,-GA -M`P"`X!30C>+PC[WH$$`MZ0!`H.&`$)_E!""@X_[__^L!`%#C$("]"`0`H.%L -M$)_E!""@X_[__^L!`%#C`@"@`Q"`O0@$`*#A5!"?Y00@H./^___K`0!0XP@` -MH`,0@+T(!`"@X3P0G^4$(*#C_O__ZP$`4.,0`*`#$("]"`0`H.$D$)_E!""@ -MX_[__^L!`%#C!`"@`P``H!,0@+WH_`,````$```$!```"`0```P$``#P02WI -M`E"@X0-`H.$``%'C+0``V@`PT.4P`%/C*@``&@(P0>(!(-#E(#`%;C!0``V@<`H.'^___K``"%Y01PA^($8$;B`0``Z@`` -M5N,9``#*`0!6XQ0``-H!@-?E`##7Y0B$D^$3```*`F!&X@@!5N$0``"Z``!8 -MXQ```-H"8(?B`'"@XP!0E.4&`*#A_O__ZP4`@.$``(3E!&"&X@%PA^('`%CA -M]O__R@0``.H!`%;B`0"@$_"!O>@``*#C\(&]Z`$`H./P@;WH$$`MZ0!`H.&` -M$)_E!""@X_[__^L!`%#C$("]"`0`H.%L$)_E!""@X_[__^L!`%#C`@"@`Q"` -MO0@$`*#A5!"?Y00@H./^___K`0!0XP@`H`,0@+T(!`"@X3P0G^4$(*#C_O__ -MZP$`4.,0`*`#$("]"`0`H.$D$)_E!""@X_[__^L!`%#C!`"@`P``H!,0@+WH -M$`0``!0$```8!```'`0``"`$``#P02WI`$"@X0)@H.$#<*#A`%!1XC,``-H` -M,-#EW0!3XS```!H",$7B`2#0Y7,P[^8#`%+A*P``&@(`@.*T$)_E!""@X_[_ -M_^L!`%#C)0``&@A`A.((4$7B`P!5XP4``-H$`*#A_O__ZP``AN4$0(3B!%!% -MX@$``.H``%7C&0``R@$`5>,4``#:`8#4Y0`PU.4(A)/A$P``"@)01>((`57A -M$```N@``6.,0``#:`E"$X@!@H.,`0)?E!0"@X?[__^L$`(#A``"'Y010A>(! -M8(;B!@!8X?;__\H$``#J`0!5X@$`H!/P@;WH``"@X_"!O>@!`*#C\(&]Z"0$ -M``#P3RWI'-!-X@!@H.$$$(WE`E"@X0`P`.,`,$#C;#"3Y0PPC>44<(WBW8"@ -MXPR@C>($D*#C`;#@XP@0H.$'(*#A!3"@X?[__^L`0%#B$```"@(`A.(*$*#A -M"2"@X?[__^L``%#C#@``"A(`C>(&$(3B`B"@X_[__^NR,=WA`0!3XP<``!H! -M,-3E!""=Y0`P@N4/``#J`#"@XP0@G>4`,(+E"P``ZA0PG>4+(&/@`B"&X`50 -M@N`%4&3@``!5XP(P@\(#`(3`V___R@!`H.,$,)WE`$"#Y00`H.$_R_A -M``"@XQ[_+^$*`(#B'O\OX1[_+^$(`(#B'O\OX,#,)#G``!3XP,```I, -M`)'E``!0X@$`H!,>_R_A3`"1Y0$`4.(!`*`3'O\OX1[_+^$>_R_A'O\OX6PP -MD.40`!/C!0``&H@S`>,#,)#G`0!3XQ\`H`,9```:'O\OX6,]H.,#,-#G``!3 -MXQ$```H&+(/B#2""X@(A@.`$()+E``!2XP3`H`,&```*"0``Z@8L@^(-((+B -M`B&`X`P0DN<``%'C`P``&@$P0^)S,._F``!3X_7__QH!,(/B@>_R_A\`4MZ1APG>4,`%/C``"@DS8``)H, -M`*#C`E"@XP-@H.,$@*#C`4"@XP#`T>?=`%SC)P``&@#`@>`%P-SG``!`#`-'G -M`P#,YP$P@^()`%/C^O__&@D`A^('((+@!S"@XP$PPN4&$(+B`#"@XP`PP>4( -M((+B`##"Y08``.H`P('@!,#_R_A!.`MY0S03>(`,*#A`""@X]0D@.70)(#EW"2`Y=@DD.4``%+C"@`` -M"@(O`N,"(-#G`0!2XP`@H!,'(,WE)!"@XP<@C>)DRP/C#^"@X0SPD^<&``#J -M"""-X@$0H.,!$&+E)!"@XV3+`^,/X*#A#/"3YPS0C>(`@+WH<$`MZ0!`H.&N -M78#B!@"%X@T;A.(1$('B!B"@X_[__^L.`(7B*QR$XCP0@>(D(*#C_O__ZP`P -MH..^*P+C(!"@X[(0A.&O+:#CLC"$X<(K`N-D$*#CLA"$X<0K`N.R,(3ASBL" -MX[(PA.'0*P+CLC"$X=(K`N.R,(3AU"L"X[(PA.'6*P+CLC"$X=@K`N.R,(3A -MVBL"X[(PA.'<*P+CLC"$X7"`O>@$X"WE#-!-XG@`@.+^___K`!"@X08`C>(" -M(*#C_O__Z[8`W>$,T(WB`("]Z'!`+>D`4*#A`4"@X48PT>4!`!/C<("]&`PU -MD.5C`%/C<("]F#!@T>5<`)'E``!0XP4``!I;#87B.`"`XD80@>+^___K``!0 -MXW"`O0B$-I#E`0!3XW"`O1B(-I#E`0!3XW"`O1B<-M#EFQ;0Y5,FH.%1)H+A -M`0`2XW"`O1@!(*#C$C:#X9PVP.4%`*#A!A"@X48@A.+^___K<("]Z'!`+>D( -MT$WB`$"@X=@TD.4``%/C5```"M([T.4``%/C40``"M$[T.4``%/C3@``"MPT -MD.4``%/C"@``&OP^`N,#,-#G`0!3XP8``!H"/P+C`S#0YP$`4^,`,*`#`3"@ -M$]PT@.4$``#J_#X"XP,PU.<"`%/C`3"@`]PTA`4(,(WB``"@XP0`(^4,4('B -M#&!"X@4`H.$M$*#C`R"@X08PH.'^___K``!0XPD```H$,)WE``!3XP8``-H$ -M,-#E`S`#X@,P@^(!(*#C$C.@X7,P[^;H-(3E"""-X@`PH.,$,"+E!0"@X3T0 -MH.,&,*#A_O__Z_L^`N,#,-3G``!3XQ,```KV.P#CLS"4X0(`$^,/```*%SS4 -MY00`$^,,```*`3"@X]\WQ.47/-3E`S`#X@$`4^,!,*`#X#?$!00```H#`%/C -M`#"@$^`WQ!4",*`#X#?$!?8[`..S,)3A4S'AY]8[Q.48/-3E`S`#XM,[Q.4( -MT(WB<("]Z/!/+>E$T$WB`$"@X0%@H.$"H*#A:)"=Y0`0`.,`$$#C%""-X@,` -MD>@$`(+DLA#"X"$8H.$`$,+E`""@X]@DA.4,8(;B/'"-X@R`0^(&`*#A+1"@ -MXP<@H.$(,*#A_O__ZP``4.-%```*/#"=Y0``4^-"```*S#24Y0``4^,(```: -M``"9Y0"0C>4``(K@W1"@XP<@H.,4,(WB_O__ZP$PH./,-(3E`+"9Y1P`C>(` -M$*#C&B"@X_[__^OB,`'CO#'-X6Q;`^,$`*#A!1"@XQ`@C>(/X*#A!?"4YP0` -MH.$$$*#C#""-X@_@H.$%\)3G!`"@X0L0H.,X((WB#^"@X07PE.7,*`'C`B"4YP0`4N,<,(,#'C#-!0"0C>4+`(K@+1"@XQH@H.,<,(WB -M_O__ZP$PH./8-(3E!@"@X3T0H.,'(*#A"#"@X?[__^L`,%#B"```"CP@G>46 -M`%+C!0``&@``F>4`D(WE``"*X#T0H.,",(/B_O__Z]@$E.5$T(WB\(^]Z!!` -M+>D`0*#A*PR`XC@`@.+,.`'C`Q"4YP`04>(!$*`3`#"@X[(K`N.R$(3AM"L" -MXP`0H..R$(3AMBL"X[(PA.&X*P+CLC"$X6([`N,#,-3G`3!#XAX`4^,#\9^7 -M/0``ZBA^``!$?@``1'X``&!^``"D?@``I'X``*1^``!$?@``I'X``$1^``!$ -M?@``I'X``*1^``"D?@``I'X``*1^``"D?@``I'X``*1^``!@?@``I'X``*1^ -M``"D?@``I'X``*1^``"D?@``I'X``*1^``"D?@``I'X``'Q^``"Z.P+C`2"@ -MX[,@A.&\.P+C`!"@X[,0A.$7``#JNCL"XP,@H..S((3AO#L"XP`0H..S$(3A -M$```ZKH[`N,"(*#CLR"$X;P[`N,`$*#CLQ"$X0D``.IA.P+C`S#4YPX`4^.Z -M.P+C`B"@@P,@H).S((3AO#L"XP`0H..S$(3A83L"XP,@U.?*.P+CLR"$X`"`XH([`N.S`(3A(`B@X80[`N.S`(3A$("]Z/A/+>D`8*#A`I"@X3`\`>,# -MH)#G`@"@X0P@H./^___K!J!*X@$`6N/=H*"#,*"@DQ@Z`>,#,-;G`0!3XPL` -M`!H<3`'C#`")XAH($$*#A -M`B""XO[__^L%L-;G#K"+X@8`H.$*$*#A!""@X?[__^NX<(;B)UR&XC!0A>(` -M0*#C!H"@XP`PU>4``%/C!P``"@0#AN`G#(#B,0"`X@<0H.$((*#A_O__ZP$` -M4.,$```*`4"$XD!0A>(0`%3C\/__&@,``.H0`%3C`0``"@``5.,!``"J"P"@ -MX?B/O>@P`%KC$P``&@E0H.$-,/7E%`!3XP\``(H!,*#C"S#)YP.PB^``,*#C -M"S#)YP$`B^($$X;@``")X"<<@>(W$('B$""@X_[__^L1L(OB`##5Y1(P@^(` -M,,7E"P"@X?B/O>@P0"WI#-!-X@!`H.$!4*#A>`"`XO[__^L`$*#A!@"-X@(@ -MH./^___K>`"%XO[__^L`$*#A!`"-X@(@H./^___K###4Y0T@U.4")(/A#C#4 -MY0,H@N$/,-3E`RR"X0PPU>4-$-7E`32#X0X0U>4!.(/A#Q#5Y0$\@^$#`%+A -M&```&@0`A.($$(7B!B"@X_[__^L!`%#C$@``&@PPU.4-(-3E`C2#X0X@U.4" -M.(/A#R#4Y1``A.(0$(7B`BR#X?[__^L!`%#C!@``&K0@W>&V,-WA`S`BX`,` -M$^,``*`3`0"@`P```.H``*#C#-"-XC"`O>CP1RWI`%"@X0%`H.$"8*#A<(#1 -MY7&@T>4T,-'E-7#1Y0=T@^$V,-'E`WB'X34#?(?A`@"@X040H.$$(*#A -MC#L#XP_@H.$#\);G;#"6Y0$`$^,W```*W`"&X@00H.&J___K``!0XS(```J< -M-@'C`S#6YW`PQ.6=-@'C`S#6YW$PQ.5E`%/C&P``"C0PU>4U(-7E`B2#X38P -MU>4#*(+A-S#5Y0,L@N$T,-3E-1#4Y0$T@^$V$-3E`3B#X3<0U.4!/(/A`B&# -MX&4"/(/A-##$Y2,DH.$U -M(,3E(RB@X38@Q.4C/*#A-S#$Y3X``.IQ,-3E90!3XRD```IP(-7E<##4Y0(A -M@^#-/`SCS#Q,XY,2@N`B(:#A<"#$Y7$0U>5Q(-3E`2&"X),"@^`C,:#A<3#$ -MY30PU>4U$-7E`12#X38PU>4#&('A-S#5Y0,<@>$T,-3E-2#4Y0(T@^$V(-3E -M`CB#X3<@U.4"/(/A`1&#X&5Q,,3E-##5Y34@ -MU>4"-(/A-B#5Y0(X@^$W(-7E`CR#X30PQ.4C)*#A-2#$Y2,HH.$V(,3E(SR@ -MX3@0 -M0"WI###0Y0T@T.4")(/A#C#0Y0,H@N$/,-#E`RR"X0PPT>4-P-'E##2#X0[` -MT>4,.(/A#\#1Y0P\@^$#`%+A``"@$Q"`O1@0`(#B$!"!XO[__^L!`%#C``"@ -M$P$`H`,0@+WH\$$MZ0C03>(`4*#A`7"@X0`PH.,`,,WE`3#-Y0(PS>4#,,WE -M!##-Y04PS>4-`*#A!B"@X_[__^L``%#C$```&@!`E>4$`%7A#0``"@:`H.,$ -M8*#A!P"@X2`0A.(((*#A_O__ZP$`4.,#```*`$"4Y00`5>'U__\:`0``Z@4` -M5.$````:`&"@XP8`H.$(T(WB\(&]Z!!`+>G^___K$("]Z'!`+>D`0*#A`5"@ -MX0``D.4``%#C<("]"``0D>7^___K`#"@XP`PA>4`,(3E<("]Z'!`+>D`0*#A -M<6Z`XG)>@.($`(;B!!"%XNS__^L(`(;B"!"%XNG__^L,`(;B#!"%XN;__^MS -M;H3B!0"@X080H.'B___K'5V$X@0`AN(($(7BWO__ZP@`AN(,$(7BV___ZW5. -MA.(,`(;B!!"@X=?__^L%`*#A!!"$XM3__^L$`(7B"!"$XM'__^MP@+WH^$\M -MZ0!PH.$!8*#A`I"@X0.PH.$<`*#C_O__ZP"`H.$`4*#A``!0XTP```H4`*#C -M_O__ZP"@H.$`0*#A``!0XP0``!H(`*#A'!"@X_[__^L``*#C^(^]Z``0H.,4 -M(*#C_O__ZP`PEN4"`%/C7#"6!00PEA4`,,KE>3#OY@$PRN4#L,KE5"77Y0$0 -MH.,1,X+A5#7'Y0`PVN4!,$/B!`!3XP/QGY`0(*#C_O__ZP$PH.,",,KE!@``ZF00AN($ -M`(KB"1*!X!`@H./^___K`3"@XP(PRN44,*#CL##%X02@A>4(,(7E`#"@XPPP -MA>40,(7E%`"%XO[__^L%"X?B*`"`X@40H.'^___K^(^]Z```H./XC[WH\$]"`0`H./^___K -M`&"@X0!PH.$``%#C!```&@4`H.$<$*#C_O__ZP``H./PA[WH`!"@XP0@H./^ -M___K`#"8Y0`PQN43,*#CL##%X01@A>4$,*#C"#"%Y0`PH.,,,(7E$#"%Y10` -MA>+^___K!0N*XB@`@.(%$*#A_O__Z_"'O>AP0"WI`&"@X0!`D.4`4*#C!@"@ -MX000H.'^___K`0!0XPT```H$(*#A##"4Y0$`4^,'```*``!5XP0```H0$)3E -M$#"5Y0$P8^```%/C````J@)0H.$`0)3E[/__Z@4`H.%P@+WH$$`MZ0!`4.(0 -M@+T(X3L#XP,PU.<``%/C$("]",P[`^,#,)3G`0!3XQ"`O0C0.P/C`S"4YP$` -M4^,0@+T(K#P#XP,PE.D`0*#A``!1XA"`O0@,,)#E`0!3XQ"`O0@,`)#H -M!#""Y0`@@^4``(#E!`"`Y1`0A.+^___K)#"4Y0$P0^(D,(3E$("]Z!!`+>G^ -M___K$("]Z'!`+>D`8*#A`%!1X@T```K^___K#3"@X7]-P^,_0,3C!#"4Y0$P -M@^($,(3E!0"@X080H.'^___K!#"4Y0$P0^($,(3E_O__ZP$`H.-P@+WH$$`M -MZ?[__^L0@+WH$$`MZ0!`H.$8$)'E_O__ZP0`H.'^___K$("]Z!!`+>G^___K -M$("]Z!!`+>D`0*#A_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B!""#Y6P@E.4" -M*\+C;""$Y0`@H.-P(,3E!""3Y0$@0N($((/E_O__ZP0`H.$!$*#C_O__ZQ"` -MO>@00"WI`$"@X6PPD.6!,,/C;#"`Y>0V`^,#,)#G``!3XP$```H#$*#C,_\O -MX7(PU.4``%/C`0``&@0`H.'^___K!`"@X0,0H.,!(*#C_O__ZP0`H.$`$*#C -M`2"@X_[__^L0@+WH$$`MZ0!`H.$``%'CP!"``G(PT.4``%/C$("]")0`@.(H -M$('B)""@X_[__^L`,*#CC#2$Y00`H.'^___K`0!0XQ"`O0AR,-3E`3!#XG,P -M[^9R,,3E``!3X_7__QH$`*#A_O__ZQ"`O>AP0"WI`%"@X0%@H.'^___K#3"@ -MX7]-P^,_0,3C!#"4Y0$P@^($,(3E!0"@X080H.'^___K!#"4Y0$P0^($,(3E -M_O__ZW"`O>CP02WI`$"@X6Q0@.+,.P/C`S"0YP``4^/P@;T8T#L#XP,PD.<` -M`%/C\(&]&/[__^L-(*#A?SW"XS\PP^,$()/E`2""X@0@@^5R,-3E``!3XPT` -M``IR,-3E`3!#XG,P[^9R,,3E``!3XP0```H$`*#A_O__ZP$`4./U__\:+0`` -MZ@0`H.'^___K*@``Z@0`H.'^___K_O__ZPTPH.%_;D`0*#A -M`""@XW$@P.4S$*#C9#L#XP_@H.$#\)#G;#"4Y0$P@^-L,(3EY#8#XP,PE.<` -M`%/C`@``"@0`H.$"$*#C,_\OX00`H.'^___K`#"@XW(PQ.40@+WH\$$MZ0!` -MH.$!8*#A`7"@X2\,@.(,`(#B_O__ZP``4./P@;T(;#"4Y1``$^,Z```*6PV$ -MXC@`@.(&$*#A_O__ZP!04.+P@;T(_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B -M!""#Y0@XE>4``%/C$0``"@P(E>4``%#C#@``"O[__^L`8%#B#```"@R(E>4& -M`*#A"!B5Y0@@H.'^___K"`B5Y0P8E>7^___K`#"@XP@XA>4,.(7E````Z@!@ -MH.,-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K``!6XP``6!,&```*!`"@ -MX080H.$((*#A_O__ZP8`H.$($*#A_O__ZP0`H.$%$*#A_O__ZP0`H.$%$*#A -M_O__Z_"!O>A;783B.%"%X@4`H.$&$*#A_O__ZP``4./P@;T8!0"@X080H.'^ -M___K`%!0XO"!O0@`,*#CW#"%Y0@PEN78,(7E>#L#XP/`E.<``%SC!```"@0` -MH.$`$*#C!2"@X0$PH.,\_R_A!`"@X040H.'^___KR#@!XP,PE.<"`%/CS#@! -M`P,PE`?L,(4%`#"@X^@PA>7^___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/E -M;#"4Y4``$^,!```:(``3XQD```H(.`'C`S"4YP(`4^,5```:_O__ZPT@H.%_ -M/<+C/S##XP0@D^4!((+B!""#Y80`A.+@$(3B_O__ZP``4.,!,*`3##"`%0T@ -MH.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^L$`*#A_O__ZPT@H.%_/<+C/S## -MXP0@D^4!($+B!""#Y?[__^L$`*#A!1"@X?[__^OP@;WH^$\MZ0!`H.$!4*#A -M(`"!XN`0A.(&(*#C_O__ZP!@H.&0,)7E>#"#XAPPA>7>#U/C,P$`BO[__^L- -M$*#A?SW!XS\PP^,$()/E`2""X@0@@^48,)7E``!3XQ$!`-K^___K#2"@X7\] -MPN,_,,/C!""3Y0$@@N($((/E`#``XP`P0.,`(*#C`"##Y6PPE.6``!/C^P`` -M"EN]A.(XL(OB`0`3XRT```H!`%;C!```&H0`A.+@$(3B_O__ZP!@H.$R``#J -MA'"$XN!@A.('`*#A!A"@X?[__^L``%#C`#"@$PPP@!4+`*#A!A"@X?[__^L` -M@%#B#0``"O[__^L-,*#A?VW#XS]@QN,$,);E`3"#X@0PAN4$`*#A"!"@X?[_ -M_^L$,);E`3!#X@0PAN7^___K!P"@X2`0A>+^___K`&"@X6PPE.4(`!/C$``` -M"@``4.,!,*`3##"`%0X``!I+``#JA`"$XB`0A>+^___K`&"@X6PPE.4(`!/C -M!```"@``4.,!,*`3##"`%0(``!H_``#J``!6XST```K<`(3B'!"%XAP@E>7^ -M___K&#"5Y=0PA.5:K83B**"*X@!P`.,`<$#C`#"7Y=R6`>,)$)3G9""@XY(! -M`>#3C03C8H!!XY@A@>`*`*#A(1.#X/[__^N,(-;EG#8!XP,@Q.>-(-;EG38! -MXP,@Q.>,(-;E`2""XJ(@H.%?($+BFC8!XP,@Q.<`,)?E"2"4YV00H..1`@+@ -MF!*(X`H`H.$H$X/@_O__ZW@PE>4``%/C(#"@`VPPA`4#```*`0!3XP@PH`,` -M,*`3;#"$Y00`H.$6'H3B4"&4Y?[__^L$`*#A51^$XE`AE.7^___K;#"4Y0@` -M$^-S```*!P``Z@T@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^N5``#J('"% -MX@L`H.$'$*#A_O__ZP!@4.($```:"P"@X0<0H.'^___K`&!0XE4```H8,)7E -MU#"&Y0`PH./8,(;E>#L#XP/`E.<``%SC!```"@0`H.$`$*#C!B"@X0$PH.,\ -M_R_AR#@!XP,PE.<"`%/C'P``&@!0H.,@/`'C`U#$YR$\`>,#4,3G(SP!XP-0 -MQ.,#,)3G[#"&Y1$.AN(%$*#A$""@X_[__^L!#(;B!1"@ -MX1`@H./^___K\`"&X@40H.$0(*#C_O__ZQ(.AN(%$*#A"""@X_[__^M*#X;B -M!1"@X0@@H./^___K>C^&X@`@H.,"P*#A`!#@XT``H.,`P,/ELA##X;00P^$& -M`,/E`2""XD@P@^(0`%+C]___&@0`H.'^___K``!0XPP```IZ/X#B`""@XP+` -MH.$`$.#C0`"@XP#`P^6R$,/AM!##X08`P^4!((+B2#"#XA``4N/W__\:!`"@ -MX080H.'^___K;#"4Y0@`$^,(```:"0``Z@T0H.%_/<'C/S##XP0@D^4!($+B -M!""#Y?[__^LL``#J!`"@X?[__^M%#H3B"`"`XO[__^L-(*#A?SW"XS\PP^,$ -M()/E`2!"X@0@@^7^___K'P``Z@T0H.%_/<'C/S##XP0@D^4!($+B!""#Y?[_ -M_^L7``#J!`!SXPP``!H$`*#A_O__ZP`P`.,`,$#C`!"3Y44.A.((`(#B_O__ -MZVPPE.6``!/C@###$VPPA!4(``#J`#``XP`P0.,`$)/E10Z$X@@`@.+^___K -M;#"4Y8`PP^-L,(3E#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__Z_B/O>CP -M02WI`$"@X0%0H.%L,)#E&``3XQ(```I;#8#B.`"`XN`0A.+^___K`'"@X?[_ -M_^L-(*#A?VW"XS]@QN,$,);E`3"#X@0PAN4$`*#A!Q"@X?[__^L$,);E`3!# -MX@0PAN7^___K;#"4Y7``$^,4```*!`"@X?[__^L$`*#A_O__ZP!PH.'^___K -M#3"@X7]MP^,_8,;C!#"6Y0$P@^($,(;E!`"@X0<0H.'^___K!#"6Y0$P0^($ -M,(;E_O__ZP0`H.'^___K``!5XP8```K^___K#2"@X7\]PN,_,,/C!""3Y0$@ -M@N($((/EA`"$XN`0A.+^___K`!!0X@`PH!,,,($5;#"4Y4``$^,%```*"#@! -MXP,PE.(`,*#A-"P!XP+`D.=, -M()'E&`H!XP``T^6@`('B#!!#X@`@H.,$,(WB_O__ZP`` -M4.(!`*`3%P``Z@(/`N,``-/G`0!0XP$`H!,%```:`0!""1Y3@QD^4#`%+A``"@$PC0C>(0@+WH\$\MZ1303>(`0*#A`'"@XP]PS>7^ -M___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/E&&"$X@@PE.4`,(WE&#"4Y0PP -MA.5,D(3B++"$XH`@A.($((WE;(!$X@:@H.,V``#J##"4Y0-0H.$``%/C6``` -M"@`PD^4,,(3E(#24Y0$`4^,%```:(`"%X@D0H.$*(*#A_O__ZP``4.,G```* -M*""4Y0``4N,'```**#"5Y0,`4N$A```:+`"%X@L0H.'^___K``!0XQP```H( -M`*#A!1"@X?[__^L``%#C%P``"@8PU.4``%/C#0``"A``E>7^___KSS<`XP,` -M4.$/``#**""5Y7PPE.4#`%+A"P``&BP`A>($$)WE_O__ZP$`4.,&```:``!7 -MXP,```I0()?E4#"5Y0,`4N$```"J!7"@X08`H.$,$)3E_O__ZP``4./#__\* -M``!7XQX```H`4)WE`#"4Y0$`$^,&```*!0"@X?[__^L%`*#A_O__ZP4`H.$` -M$*#C_O__ZP4`H.$!$*#C#R"-XFP[`^,/X*#A`_"5YP\PW>4!`%/C!0``&@4` -MH.$"$*#C#B"-XFP[`^,/X*#A`_"5YP4`H.$'$*#A_O__ZP!`H.$```#J`$"@ -MXPT@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^L$`*#A%-"-XO"/O>@00"WI -M`$"@X?[__^L-(*#A?SW"XS\PP^,$()/E`2""X@0@@^4$`*#A_O__ZP$`4.,` -M0*`#`$"4%00PE!4`()05!#""%0`@@Q4`0(05!$"$%0T@H.%_/<+C/S##XP0@ -MD^4!($+B!""#Y?[__^L$`*#A$("]Z!!`+>D`0*#A_O__ZP(PH.,`,,3E$3"@ -MXP$PQ.5X,.#C`C#$Y0,`Q.4@-*#A!##$Y2`(H.$%`,3E$("]Z/!`+>D,T$WB -M`$"@X0%0H.$!<*#A6PV`XC@`@.+^___K`&!0X@@```JX/=;A`S2@X0@@C>*R -M,&+A!`"@X4$0H.-D.P/C#^"@X0/PE.=L,)3E$``3XP0```H$`*#A!Q"@X;8@ -MU>'^___KA0``ZFQPA.($`*#A_O__Z_[__^L-(*#A?SW"XS\PP^,$()/E`2"" -MX@0@@^5L,)3E"``3XRD```IR,-3E``!3XP$P0Q(*/P(#`S#4!W(PQ.6V(-7A -M_S\/XP,`4N$`,*`34'`*#A_O__ZPT@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^L$`*#AP!"$ -MXO[__^ML,)3E0``3XP$``!H@`!/C0@``"O[__^L-,*#A?UW#XS]0Q>,$,)7E -M`3"#X@0PA>4$`*#A!A"@X?[__^L$,)7E`3!#X@0PA>7^___K"#@!XP,PE.CP02WI`$"@X?[__^L-`*#A?SW`XS\PP^,$()/E`2"" -MX@0@@^4`,*#C7#>$Y6PPE.4""Q/C!P``"DD.A.($`(#B_O__ZVPPE.4".\/C -M;#"$Y0`PH.-P,,3E`#``XP`P0.,`,)/EW"8!XP(@E.=D$*#CD0(!X-,M!.-B -M($'CD@&!X%H-A.(H`(#B(1.#X/[__^MQ,-3E`0!3XUX``!IL`(3B;#"4Y2`` -M$^,H```*`0`3XU@``!J`,(/C;#"$Y?[__^L!`%#C"```&@`P`.,`,$#C`!"3 -MY44.A.((`(#BHA^!X@(0@>+^___K2@``ZFPPE.4".\/C;#"$Y0!@H.-P8,3E -MKGV$X@Y0A^(%`*#A!A"@X20@H./^___K!0"@X900A.(D(*#C_O__ZP0`H.'^ -M___K!@"'XO[__^M`,*#C;#"$Y00`H.'^___K<6#$Y3$``.J`,(/C;#"$Y0`P -MH.-Q,,3E_O__ZP$`4.,(```:`#``XP`P0.,`$)/E10Z$X@@`@.*B'X'B`A"! -MXO[__^LA``#J`@!0XP4``!IL,)3E@###XVPPA.4$`*#A_O__ZQD``.IR,-3E -M``!3XQ,```H!,$/BD`4*#A -M`F"@X0!`4>)P@+T(##"4Y0$`4^-P@+T(_O__ZP`@E>5``!+C`@``&B``$N,4 -M(*`#````"@$@H.,``%;C!@``&A`PE.4``&/@'S4(X^LQ1>.3$(/@HP)2X7"` -MO8C^___K#3"@X7]MP^,_8,;C!#"6Y0$P@^($,(;E#`"4Z`0P@N4`((/E`$"$ -MY01`A.4$`*#A$!"%XO[__^LD,)7E`3!#XB0PA>4$,);E`3!#X@0PAN7^___K -M<("]Z!!`+>G^___K$("]Z/!!+>D`0*#A`6"@X6QP@.+^___K#2"@X7\]PN,_ -M,,/C!""3Y0$@@N($((/EA%"$XH1`E.4$``#J!!"@X0!`E.4'`*#A!B"@X?[_ -M_^L%`*#A!!"@X?[__^L``%#C]?__"@T@H.%_/<+C/S##XP0@D^4!($+B!""# -MY?[__^OP@;WH$$`MZ?[__^L0@+WH<$`MZ0!0H.'^___K#2"@X7\]PN,_,,/C -M!""3Y0$@@N($((/E$`"%XO[__^L!`%#C`$"@`P\```H00)7E#`"4Z`0P@N4` -M((/E`$"$Y01`A.4`8*#C"&"$Y0Q@A.7^___K$`"$Y11@A.488(3E)#"5Y0$P -M@^(D,(7E#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__ZP0`H.%P@+WH$$`M -MZ?[__^L0@+WH\$GW_^L``%#C"0``&@``5N,$```*$""4Y1`PEN4",&/@``!3XP`` -M`*H%8*#A`$"4Y>K__^H(`*#A!!"@X?[__^L!`%#C/P``&GP`BN+^___K`0!0 -MXQ@``!H*`*#A`A"@XW(@A^)L.P/C#^"@X0/PFN=T,-?E=2#7Y0(T@^%V(-?E -M`CB#X7<@U^4"+(/A'`"&X@<0H.%X((+B_O__ZP!`H.,,0(;E_O__ZQ``AN4( -M0(;E%$"&Y1A`AN4U``#J;`"*XO[__^L`4%#B,0``"G0PU^5U(-?E`C2#X78@ -MU^4".(/A=T#7Y01,@^%X0(3B`$#'Y20TH.$!,,?E)#B@X0(PQ^4D/*#A`S#' -MY0H`H.$"$*#C('$*#A!""@X?[__^O^___K -M$`"%Y04`H.$($*#A_O__ZQ(``.K^___K$`"%Y70PU^5U(-?E`C2#X78@U^4" -M.(/A=R#7Y0(\@^&0()7E`P!2X0(``)H*,-?E`0!3XP,```H<`(7B!Q"@X0H@ -MH.'!]__K#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__Z_"'O>AP0"WI`$"@ -MX0%@H.$!`*#A#A"@X_[__^ML,)3E`0`3XPT```K<4(3B!0"@X080H.%P]__K -M``!0XP<```H%`*#A!A"@X00@H.&F]__K!`"@X18>A.)0(93E_O__ZP0`H.$& -M$*#A_O__ZW"`O>AP0"WI`%"@X0%`H.%T,-'E=2#1Y0(T@^%V(-'E`CB#X7<@ -MT>4"/(/A>#"#XMX/4^-P@+V(_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B!""# -MY6PPE>5``!/C*0``"N``A>($$(3B!B"@X_[__^L``%#C(P``"GA@A.)5#X7B -M!A"@X0@@H./^___K_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B!""#Y80`A>($ -M$(3B_O__ZP``4.,+```*E`"`X@80H.$((*#C_O__ZPT@H.%_/<+C/S##XP0@ -MD^4!($+B!""#Y?[__^L2``#J#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__ -MZVPPE>6``!/C"```&A`PU.4``%/C###$!0TPQ`4.,,0%#S#$!04`H.$$$*#A -M_O__ZPT@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^MP@+WH$$`MZ0!`H.'^ -M___K&`"$XO[__^L@`(3B_O__ZQ"`O>@00"WI`$"@X?[__^L``%3C$("]"`0` -MH.'^___K(`"4Y0``4.,0@+T(`!H,XP$00./^___K$("]Z!!`+>G^___K$("] -MZ/!!+>D`<*#A=`"'Y0!`H.-X0(#E;$"`Y0(PH.,X,8#E`3"@XU@U@.5L`(#B -M_O__ZWP`A^+^___KA`"'XO[__^O^___K#2"@X7\]PN,_,,/C!""3Y0$@@N($ -M((/ED$"'Y00@D^4!($+B!""#Y?[__^N4`(?B!!"@X20@H./^___K``H,XP$` -M0./^___K`$!0XO"!O0B,0(?E?&"'XG);A.("7(7B!`"@X?[__^L$`*#A!A"@ -MX?[__^OE3X3B!0!4X??__QH'`*#A_O__ZP$`H./P@;WH$$`MZ?[__^L0@+WH -M`##0Y0``4^,(```*`0!3X0,``!H(``#J#`"`X@$`4^$%```*###0Y0``4^/Y -M__\:``!3X@$`H!,>_R_A`0"@XQ[_+^$`,*#C?\#@XP,`T>=_(`#B`B!"XBX` -M4N,"\9^7,```ZMRF``#DI@``W*8``.2F``#DI@``Y*8``.2F``#DI@``Y*8` -M`-RF``#_R_A`0"@ -MXQ[_+^$!`*#C'O\OX0$`H.,>_R_A`0"@XQ[_+^$!`*#C'O\OX?!!+>D`@*#A -M`7"@X7PPD>484-/E`#"@XP-`H.$`8`#C`&!`XX,P@^`#,8;@`""3Y0(`5>$# -M```:"`"@X0<0H.$/X*#A"/"3Y0%`A.($,*#A"P!4X_+__QH!`*#C\(&]Z`$` -MH.,>_R_A$$`MZ0`PH.'0*P/C`B"0YP$`4N,0@+T(S"L#XP(@D.@P`"WI,-!-X@%`H.$`4`#C`%!`XPW`H.$/`+7H -M#P"LZ`\`M>@/`*SH#P"5Z`<`K.@`,,SE`##=Y00`4^$)```*`3"@XPT0H.$# -M(-'G!`!2X00```H!,(/B+0!3X_G__QH``*#C````Z@$`H.,PT(WB,`"]Z![_ -M+^$$X"WE#-!-X@`PH.$<*Y#E`R`"X@(`4N,$```:#!"@XP0@C>)LRP/C#^"@ -MX0SPD^<,T(WB`("]Z```4.,>_R\!A#:0Y0$`4^,>_R\1B#:0Y0$`4^,>_R\1 -MG#;0Y0``4^,`,*`3G#;`%1[_+^$``*#C'O\OX03@+>4,T$WB`#"@X0`@T>4$ -M`%+C`R"@`QPK@`4'(,T%#```"@$`4N,&```:'"N0Y0,@PN,"((+C'"N`Y0(@ -MH.,'(,WE`P``Z@``4N,!(*`#`""@$P<@S>4#`*#A`A"@XP<@C>)DRP/C#^"@ -MX0SPD^<``*#C#-"-X@"`O>@`,-'E`P!3XS`[@)4``*#C'O\OX0``4>,$`*`# -M``"@$Q[_+^$P`"WI`#"@X0``H.,&+:#C6A^@XP)`D^@>_R_A`#"@ -MX=@DD.4!`%+C``"@`Q[_+P%\)P#CLB"3X00`$N,'```:3Y0``4>,,```* -M!"""XWP7`..Q((/A`0"@XP@``.IP%Y/E``!1XP0``!H$(,+C?!<`X[$@@^$! -M`*#C````Z@``H.-\)P#CLB"3X1``$N,*```:T!23Y0``4>,"```:>!>3Y0`` -M4>,1```*$"""XWP7`..Q((/A`0"`X@D``.K0%)/E``!1XQ@``!IX%Y/E``!1 -MXP8``!H0(,+C?!<`X[$@@^$!`(#BT"23Y0``4N,.```:?"<`X[(@D^$$`!+C -M"@``&O`DD^4"#!+C`P``"G0GD^4``%+C`B"@$P0``!IX)Y/E`"!2X@$@H!,` -M``#J`R"@XWP7`..Q$)/A`\`!X@(`7.$>_R\!`Q#!XP$@@N%\QP#CO""#X0$` -M@.(>_R_A`#"@X\@WP.4@)`'C`C#`YV`W@.5D-X#E:#>`Y7`W@.70-(#E=#>` -MY6PW@.5X-X#E?"<`X[(P@.$#$*#A`R"`X`8K@N(\((+B`!""Y00P@^*``%/C -M^/__&@`PH..`-X#EB#>`Y8PW@.6@-X#EJ#>`Y1[_+^$``%'C!`"@`P``H!,> -M_R_A!0"@XQ[_+^$%`*#C'O\OX?A/+>D`8*#A`4"@X0)0H.$"`*#A`!"@XW(O -MH./^___K?P!4XT``5!,``*"#^(^]B&([`N,#,-;G`@`3XP!@H`,&(*`!!@`` -M"G\`5.,"8*`#`"``$P`@0!.$(((0,%0$@H.,$`!/C`+"@`PN0H`$&```* -M?P!4XP6PH`,`,``3`#!`$X0P@Q`QL-,5`9"@XP``4N,``*`#+0``"@`P`.,` -M,$#C!B)FX`(P@^#"`-/E``!0XR8```H`,*#C`R"@X0;"9N`4$9_E#,"!X`.@ -MH.$!<*#C`A#<)`%3C"P``&@&`0>)X@._F"@!8XP,0A9`$<(&5$``` -MF@P00>)Q$._F`@!1XP,0A9`$H(&5"@``ZA,`5.,*`%03`P``"@``5N,#$(40 -M!'"!%0,``!H+`%'C`Q"%X`1P@94$H(&%`2""X@PP@^)R$._F`0!0X=___XH` -M`%GC^(^]"``P`.,`,$#C"R&+X`(A@N`",(/@&,'3Y0``7./XC[T(`#"@XP*P -MH.%88)_E`F"&X`&`H.,#<*#A`R#6YS$00N)Q$._F8P!1XP@``)J`$(#@`1&% -MX``@P>43`%3C"""@$0<@H`$$(('E`0"`XG``[^8!,(/B___Z^('Q.4``*#C$("]Z'!`+>D`4*#A`4"@X0$`H.$`$*#C6""@X_[_ -M_^L8,*#CNC#$X0$PH.,4,,3E!S"@XR@PQ.4`,*#C*C#$Y1(@H.-/(,3E##"$ -MY>$WU>4!`!/C!C"@$P4PH`-',,3E`#"@XQ4PQ.4",,3E13#$Y48PQ.5(,,3E -M23#$Y4HPQ.7<-P#CLS"5X;8PQ.$!,*#C4S#$Y7"`O>CP12WI#-!-X@"`H.$! -M8*#AT#"1Y0$`$^-=```*``!1XUL```H!4*#A`'"@XP=`H.$P`=7E``!0XP(` -M``I_``#B_O__ZP!PA^$!0(3B`5"%XA``5./U__\:A#:6Y0``4^,`4*`#'P`` -M"@@`H.$4$*#C!R"-XF@[`^,/X*#A`_"8YP?@W>4"`%[C$."@`PC@H!,`,*#C -MF,8`XP%`H.,'((/B``!3XP,@H*'"(8;@#"""X`@0TN7#+Z#AHBZ@X0(`@^`' -M``#B`"!BX%$BH.$!`!+C#""#$A1RAQ$!,(/B#@!3X>W__[J:5M;E)#&8Y0X` -M4^,$``":_S['X_\BT^,4`*`3!`"@`P8``.K_/L?C_R+3XPL`H!,"```:_PX7 -MXP,`H!,!`*`#_O__ZP!`H.$/`L?C_O__Z]0PEN4?`%/C%```BC^@`.+8(-;E -M'R`"XH`@@N,!`%7C!P``&@@`H.$$'H?A("""XX0[`^,/X*#A`_"8YT"@BN,$ -M``#J"`"@X00>A^&$.P/C#^"@X0/PF.=.0<;E3Z'&Y0S0C>+PA;WH\$(!0*#A>("!XG0PT>5U$-'E`32#X780U.4!.(/A=Q#4Y0$\@^&$`(3B`A"@ -MX00@C>(,,$/B_O__ZP!P4.(R```*!)"=Y0``6>,O```*`I")X@20C>5T,-3E -M=6#4Y09D@^%V,-3E`VB&X7+PA[WH -M`&"@X_+__^KP3RWI#-!-X@%0H.$"0*#A`Z"@X3!@W>5X@('B=##1Y77@T>4. -MY(/A=C#1Y0/HCN%W<-'E!^R.X0P`7N,7``":"'"@X0$@H.&$,/+E`P!4X1(` -M`#H$`%/A##"@$PD``!H$``#J`R"'X``0TN4$`%'A"@``B@,``!H"`*#A`<#2 -MY0$PH.,&``#J`@"@X0'`TN4"((SB`C"#X`,`7N'P__^*`#"@XP``4.,``%P3 -M`'"@`S,```H"P(SB#""`X``@C>4`<&C@#N!GX`*PH.$``%/C`+"@$0QP7N`I -M```*!P"@X?[__^L`D*#A`#!0X@$PH!,$,(WE`""=Y0``4N,``%`3`@``"@(0 -MH.$'(*#A_O__ZP%`R^0+0*#A`6#$Y`0`H.$*$*#A!B"@X?[__^L&0(3@!#"= -MY0``4^,&```*!`"@X0D0H.$'(*#A_O__ZPD`H.$'$*#A_O__ZP1`:.`'<(3@ -M='#%Y24G?*#A=W#%Y0S0C>+PC[WH`4#+Y`M`H.$! -M8,3D!`"@X0H0H.$&(*#A_O__ZP9`A.#K___J\$$MZ0!0H.$!8*#A`$"@XP9P -MH..&@0#C!!"&X`4`H.$A$('B!R"@X?[__^L``%#C`0``"@$`H./P@;WH)T"$ -MX@@`5.'S__\:``"@X_"!O>CP0"WI#-!-X@!PH.$!0*#A`F"@X0TPH.%H()_E -M`P"2Z`0`@^2P$,/A?%"6Y0@PE.4``%/C$0``"@10A>(%`*#A#1N'XA$0@>(& -M(*#C_O__ZP``4.,%```:!0"@X0T0H.$&(*#C_O__ZP``4.,#```*!P"@X080 -MH.$/X*#A"/"4Y0S0C>+P@+WH;!$``/!'+>D(T$WB`'"@X0%0H.$"0*#A?&"1 -MY70PD>48,$/B!#"-Y0,,4^,A`0"*`@"@X0`0H./>+Z#C_O__Z[`PUN'\,`/B -M@`!3XP$PH`,`,*`3"C#$Y0B`C>($(#CE>#""X@`PQ.4C%*#A`1#$Y2,8H.$" -M$,3E(SR@X0,PQ.5T(,3E(C2@X74PQ.4B.*#A=C#$Y2(\H.%W,,3E>`"$XA@0 -MAN+^___KVS;5X30PQ.4C+*#A-2#$Y38@Q.4W(,3E93#5Y7$PQ.5M,-7E<##$ -MY0<`H.$"$*#C4(`%+CMP``B@H`H.$" -M$('B_O__ZP20G>5T,-3E=2#4Y0(T@^%V(-3E`CB#X7<@U.4"/(/A!0"@X3(0 -MH.,((*#A##!#XO[__^L`$%#B!@``"@0@G>40,&GB`@!3X:$``#H)`(K@`A"! -MXO[__^L`H*#C`Q"@XS@0Q.4YH,3E.J#$Y3N@Q.5T,-3E=2#4Y0(T@^%V(-3E -M`CB#X7<@U.4"/(/A!0"@X0@@H.$,,$/B_O__ZTB@Q.5)H,3E2J#$Y4N@Q.4\ -MH,3E/:#$Y3Z@Q.4_H,3E``!0XP4```H",-#E2##$Y4F@Q.5*H,3E2Z#$Y2`` -M`.IT,-3E=2#4Y0(T@^%V(-3E`CB#X7<@U.4"/(/A!0"@X3T0H.,((*#A##!# -MXO[__^L``%#C!@``"@(PT.5(,,3E`#"@XTDPQ.5*,,3E2S#$Y0L``.K(.9?E -M`P!3X]`YEP4,(*`#DG,C`.0WTP7>-]<52##$Y0`PH.-),,3E2C#$Y4LPQ.5X -M`(3B_O__ZP`0H.%``(3B`B"@X_[__^L$`*#A_O__ZP"@H.$!`!#C"@``"@`P -MH.,!(*#C7"#$Y5TPQ.5>,,3E7S#$Y00`A.(*$(;B!B"@X_[__^L(``#J`#"@ -MXUPPQ.5=,,3E7C#$Y5\PQ.4$`(3B$!"&X@8@H./^___K$``:XP`PH.,!(*`3 -M,"#$%3`PQ`4Q,,3E,C#$Y3,PQ.4`,*#C1##$Y44PQ.5&,,3E1S#$Y0(_`N,# -M,-?G`0!3XQP``!K<.]?E``!3XQD``!IT,-3E=2#4Y0(T@^%V(-3E`CB#X7<@ -MU.4"/(/A!0"@X2T0H.,((*#A##!#XO[__^L``%#C"```"@0PG>4``%/C!0`` -M"@,PT.5``!/CU#27%0$P@Q+4-(<5`@``ZM`TE^4!,(/BT#2'Y4@PU.5)(-3E -M`C2#X4H@U.4".(/A2R#4Y0(L@^'0.9?E@S"#X`-QA^#D-]?E`P!2X64PH!-Q -M,,05`0"@XP```.H``*#C"-"-XO"'O>@00"WIWA?0Y>`GT.7?-]#E_O__ZP$` -MH.,0@+WH$$`MZ0!`H.$?#8#B"`"`XO[__^L$`*#A_O__ZQ"`O>AP0"WI`%"@ -MX0%`H.$`()'E4FCGYQ@`5N,7``"*`#``XP`P0..&,8/@Y#*3Y0``4^,"```* -MCREN5\-`'C`R"5YP$@@N(#((7G``"@XW"`O>CP02WI`'"@X1P` -MH./^___K`%"@X0!`H.$``%#C``"@`_"!O0C>#Z#C_O__ZP!@H.$``%;C!``` -M&@4`H.$<$*#C_O__ZP``H./P@;WHPAZ'X@P0@>+>+Z#C_O__ZQ0`A>+^___K -M-S"@X[`PQ>$$8(7EWC^@XP@PA>4`,*#C##"%Y1`PA>4%"X?B*`"`X@40H.'^ -M___K<`#OYO"!O>CP1RWI$-!-X@%0H.$"<*#A`V"@X0!`4.+;```*(#0!XP,P -MU.<``%/CUP``"O[__^L-(*#A?SW"XS\PP^,$()/E`2""X@0@@^4%`%7C`@`` -M"MT`5>._```:;@``ZLJ.A.($D(CBOC@!X[,PE.&^,,WA$("(XJ`\E.4(`*#A -M!1"@XP0@C>(,,$/B_O__ZP!04.(*```*!'"=Y0``5^,'```*`G"'X@1PC>4' -MH(7@!3!IX*`LE.4",&/@`W!GX!8``.H`,*#C!#"-Y3A(%H(3@RJZ* -MX@2@BN*@?)3E!U!EX`0PG>4%<&/@"E"@X0``5^,`@*`#"```"@<`H.'^___K -M`("@X0``4.,``%H3`@``"@H0H.$'(*#A_O__ZP4PH.,!,,7DOC@!X[,PE.'_ -M#!/C`P``"OP`$^,%,*`3!#"-%0$``!H$,*#C!#"-Y00PG>4!,,7D`#"@XP$P -MQ>0!,*#C`3#%Y+XX`>.S,)3A`0`3XP$PH!,`,*`#`3#%Y`0PG>4$`%/C#C#= -M!0$PQ00&```*!0!3XP0``!H%`*#A#A"-X@(@H./^___K`E"%X@``6.,&```* -M!0"@X0@0H.$'(*#A_O__ZP@`H.$'$*#A_O__ZP50:>`'<(7@H'R$Y00`H.'^ -M___K3P``ZG0!G^4'$*#A!""@X_[__^L``%#C20``&F`!G^4'$*#A!""@X_[_ -M_^L``%#C0P``&DP!G^4'$*#A!""@X_[__^L``%#C.0``"@`@H.,0,(WB#"`C -MY`'4%7@`*"@`P<```H%`*#A_O__ZP"@4.(#```*"@"@X0<0B.`% -M(*#A_O__ZX`7E.4``%'C'P``"@$@T>4$((WE`B""X@DP@N`%,(/@`PQ3XPX` -M`(H(`*#A_O__ZP0`G>4``%KC!```"@(`@.(``(C@"A"@X04@H.'^___K!#"= -MY0(P@^(),(/@!3"#X*`\A.4``%KC!P``"@H`H.$%$*#A_O__ZP,``.I0`)_E -M!Q"@X00@H./^___K`3"@X\@WQ.4-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^ -M___K``!6XP$```H$`*#A_O__ZQ#0C>+PA[WHT`0``-0$``#8!```W`0``'!` -M+>D`4*#A`4"@X5@WD>4``%/C#0``JI4WT>4``%/C&```&@$PH..5-\'E8#>0 -MY0$P@^)@-X#E`0!3XQ$``!HJ$*#C`""@X_[__^L-``#JE3?1Y0``4^,*```* -M`#"@XY4WP>5@-Y#E`3!#XF`W@.4``%/C`P``&BH0H.,`(*#C`3"@X_[__^M4 -M-P#CLS"4X0$+$^,1```:EC?4Y0``4^,@```:`3"@XY8WQ.5D-Y7E`3"#XF0W -MA>7A)]7E`0!2XQ@``)H!`%/C%@``&@4`H.'_$*#C`""@X_[__^L1``#JEC?4 -MY0``4^,.```*`#"@XY8WQ.5D-Y7E`3!#XF0WA>7A)]7E`0!2XP8``)H``%/C -M!```&@4`H.'_$*#C`""@XP$PH./^___K6#>4Y8``$^,1```:ES?4Y0``4^,@ -M```:`3"@XY7A)]7E`0!2XQ@``)H!`%/C%@``&@4` -MH.'_$*#C`""@X_[__^L1``#JES?4Y0``4^,.```*`#"@XY7A)]7E`0!2XP8``)H``%/C!```&@4`H.'_$*#C`""@XP$PH./^___K -M6#>4Y0(+$^,<```*G#:4Y5,T[^>9)]3E``!2XP`@H!.9)\05T"25%0$@0A+0 -M)(45$``3XP8``!J8)]3E``!2XP$@H`.8)\0%<">5!0$@@@)P)X4%`@`3XP\` -M`!J:-]3E``!3XPP``!H!,*#CFC?$Y70WE>4!,(/B=#>%Y08``.J9-]3E``!3 -MXP$PH`.9-\0%T#25!0$P@P+0-(4%!0"@X83Z_^L``%#C<("]V`4`H.$M$*#C -M`""@XP(PH.'^___K!0"@X3T0H.,`(*#C`3"@X_[__^MP@+WH\$$MZ0!`H.'( -M.9#E`0!3X_"!O=@#`%/CT#F0!0$P@P+0.8`%#C0!XP,PT.(`4*#A`4"@X1P[D.4#,`/B`P!3XQP` -M`!H&,-'E``!3XP,``!H'$-'E_O__ZP$`H.,H``#J`6"@X5L-@.(X`(#B_O__ -MZP``4.,A```*!B#4Y=@PD.4!$$/B&P!1XQP``(H#,(/B`B&@X0A`A.(`0(WE -M!0"@X7,0[^8"*8+C!C"@X?[__^L!`*#C$@``Z@8@T>4``%+C`P``&@<0T>7^ -M___K``"@XPL``.H"(:#A"#"!X@`PC>4$$*#C`BF"XP0PH.'^___K!C#4Y3@[ -MA>4``*#C````Z@4`H.,(T(WB<("]Z`3@+>44T$WB`#"@XP@PS>4),,WE"C#- -MY0LPS>4,,,WE#3#-Y0,PT>4``%/C`3#1%3P[@!4!,-'E@RC@X03`T>2B*.#A -M#"&"X0`0C>4#$*#A+^___K``"@XQ30C>(`@+WH$$`MZ0!`H.$` -M,)#E``!3XQ"`O0C,*P/C`C"3YP$`4^,0@+T8O0Z`X@0`@.+^___K`PN$X@@` -M@.+^___K$("]Z'!`+>D`0*#A_O__ZP``4.,#```:!`"@X?[__^L``%#C<("] -M"&1;`^,$`*#A"Q"@XP`@H.,/X*#A!?"4YP0`H.$$$*#C`"``XP`@0.,/X*#A -M!?"4YP!0H./?5\3EX%?$Y00`H.'>%]3E!2"@X04PH.'^___K!`"@X?[__^L< -M6X3E!`"@X0(0H./^___K3PV$XA@`@.+^___K<("]Z#!`+>D,T$WB`$"@X0`` -M4>,-``"J"""-X@$PH.,!,&+E9%L#XPT0H.,/X*#A!?"4YP0`H.$$$*#C`"`` -MXP`@0.,/X*#A!?"4YV4``.H<.Y#E`S`#X@$`4^,+```:_O__ZP!04.((```* -MV#"5Y8,RA."D7X/E!`"@X=@0E>7^___K!`"@X=@0E>7^___K!`"@X0\2X.,! -M(*#C_O__ZP0`H.'^___K9%L#XP0`H.$&$*#C,BV$X@P@@N(/X*#A!?"4YP0` -MH.$.$*#C+RV$X@8@@N(/X*#A!?"4YP0`H.'(.P#CLQ"4X?[__^L$`*#A_O__ -MZP0`H.'^___K!`"@X=X7U.7@)]3EWS?4Y?[__^M;#83B.`"`XL,>A.+^___K -M`%!0XAP```K8,)7E@S*$X*1?@^4$`*#A!1"@X?[__^MD.P/C`S"4YP``4^,( -M```*F`"?Y9@0G^7^___K!`"@X4`0H./8((7B9#L#XP_@H.$#\)3GN#W5X0,T -MH.$!,(/C"""-XK0P8N$$`*#A01"@XV0[`^,/X*#A`_"4YP@@C>(",*#C`3!B -MY00`H.$-$*#C9#L#XP_@H.$#\)3G'#N4Y0,P`^("`%/C`@``&@0`H.%]'H3B -M_O__ZP0`H.$"$*#C`""@X_[__^L,T(WB,("]Z!P````T$@``<$`MZ0!0H.$! -M0*#A_O__Z]@TE>4``%/C#0``"@$PH..$-H3EW#25Y8@VA.4%`*#AOQZ%X@80 -M@>+^___K``!0XP$PH!.:-L05`3"@X]PPA.4$``#J`#"@XX0VA.6(-H3EFC;$ -MY=PPA.7?-]7EF#;$Y>`WU>69-L3E`#"@XYLVQ.6<-L3ES#25Y0``4^,!,*`3 -MW#"$%0$PH./0,(3E<("]Z/!'+>D`<*#A`8"@X0*@H.$<`*#C_O__ZP!@H.$` -M0*#A``!0X_"'O0@4`*#C_O__ZP!04.(#```:!@"@X1P0H./^___K\(>]Z!0` -MAN+^___K.#"@X[`PQN$4,*#C"#"&Y010AN4`,*#C##"&Y1`PAN4,,*#CL##% -MX0LPH.,",,7E?0Z'X@@`@.+^___K`P#%Y0A0A>(%`*#A"!"@X08@H./^___K -M"*"%Y04+A^(H`(#B!A"@X?[__^OPA[WH\$$MZ0C03>(`<*#A`8"@X;8@S>$< -M`*#C_O__ZP!@H.$`0*#A``!0XR4```H0`*#C_O__ZP!04.(#```:!@"@X1P0 -MH./^___K'0``ZA0`AN+^___K.#"@X[`PQN$0,*#C"#"&Y010AN4`,*#C##"& -MY1`PAN4(,*#CL##%X0PPH.,",,7E?0Z'X@@`@.+^___K`P#%Y0@`A>(($*#A -M!B"@X_[__^L.`(7B!A"-X@(@H./^___K!0N'XB@`@.(&$*#A_O__ZPC0C>+P -M@;WH\$$MZ0!@H.$<`*#C_O__ZP!PH.$`0*#A``!0X_"!O0@,`*#C_O__ZP!0 -M4.(#```:!P"@X1P0H./^___K\(&]Z!0`A^+^___K.#"@X[`PQ^$,,*#C"#"' -MY010A^4`,*#C##"'Y1`PA^4$,*#CL##%X0DPH.,",,7E?0Z&X@@`@.+^___K -M`P#%YCP02WI`8"@X0!@4.+P -M@;T('`"@X_[__^L`<*#A`$"@X0``4./P@;T(#@V@X_[__^L`4%#B`P``&@<` -MH.$<$*#C_O__Z_"!O>@4`(?B_O__ZS@PH..P,,?A#CV@XP@PA^4$4(?E`#"@ -MXPPPA^40,(?EWC^@X[`PQ>$(,*#C`C#%Y7T.AN(#`(#@_O__ZP,`Q>4&`*#A -M"!"@X0@@A>+^___K``!0XP8``!H'`*#A'!"@X_[__^L%`*#A#AV@X_[__^OP -M@;WH!0N&XB@`@.('$*#A_O__Z\PYEN4!,(/BS#F&Y?"!O>CP02WI`'"@X0&` -MH.$<`*#C_O__ZP!0H.$`0*#A``!0X_"!O0CG#Z#C_O__ZP!@4.(#```:!0"@ -MX1P0H./^___K\(&]Z!0`A>+^___K.#"@X[`PQ>'G/Z#C"#"%Y01@A>4`,*#C -M##"%Y1`PA>7E/Z#CL##&X0HPH.,",,;E?0Z'X@@`@.+^___K`P#&Y0A0AN(D -M`(;BPAZ'X@P0@>+>+Z#C_O__ZQ2`A>48@(7E!P"@X040H.'^___K!0N'XB@` -M@.($$*#A_O__Z_"!O>AP0"WI`$"@X0%0H.$"8*#AP@Z`X@P`@.+^___K`!"@ -MX04`H.$&(*#C_O__ZP``4.,3```*'#N4Y0,@`^("`%+C#P``&@$)$^,&```* -M`#"@XQP[A.4$`*#A!1"@X08@H.'^___K!@``ZB<,$^,$```*`#"@XQP[A.4$ -M`*#A`1#@X_[__^L!`*#C<("]Z#!`+>D,T$WB`$"@X<)>@.(,4(7B=#R0Y=XW -MP.4%`*#A_O__Z\8[`..S`(3A!`"@X?[__^L%`*#A_O__ZP!0H.$$`*#A!1"@ -MX?[__^L!`!7C)```"@0`H.$"$*#C_O__ZS`[E.4"`%/CS#"@`\\PH!,(((WB -M`3!BY00`H.$2$*#C9#L#XP_@H.$#\)3G!`"@X=X7U.7@)]3EWS?4Y?[__^O& -M.P#CLP"4X?[__^L`,`#C`#!`XP`PD^5D$*#CD0`!X-,M!.-B($'CD@&!X$\- -MA.(8`(#B(1.#X/[__^L",0#C'#N$Y1<``.H"`!7C%0``"@0`H.$!$*#C_O__ -MZP@@C>(P,.#C`3!BY00`H.$2$*#C9#L#XP_@H.$#\)3G!`"@X=X7U.7@)]3E -MWS?4Y?[__^L$`*#A_O__ZP$0H.,<&X3E!`"@X?[__^L,T(WB,("]Z'!`+>D` -M4*#A_O__ZP!`4.(.```*!0"@X?[__^L``%#C!```&@4`H.$$$*#A_O__ZP!` -MH.,%``#J`S"@XV0PA.5P`(3E$#"0Y6PPA.440(#E!`"@X7"`O>CP3RWII-!- -MX@!`H.&,,(WB`""@XP0@@^0$((/D!""#Y``@@^74-)#E`@!3X:\```K0-)#E -M`@!3X:P```K<.]#E`0!3XZD```H$,*#CGS#-Y9X@S>53#8#B(`"`XO[__^L` -M<%#BH0``"@0`H.$($(?B_O__ZVP`E^4`$*#C:""@X_[__^ML8)?E!E"@X0`P -MH.,H,.7E`3#%Y<*.A.(,@(CB"`"@X?[__^L`$*#A+`"&X@8@H./^___K,@"& -MX@T;A.(1$('B!B"@X_[__^L(`*#A_O__ZP`0H.$X`(;B!B"@X_[__^L&(*#A -MOA/RX=PW`..S`)3A#Q`!X@`2@>&P$,+ALR"4X0$@@N*S((3AL##5X?PPP^/0 -M,(/CL##%X0>PH.$8,*#C%#"KY4``AN(!$*#CGR"-X@LPH.'^___K`1"@XYX@ -MC>(+,*#A_O__ZPP`C>74-)3E``!3XP<``-J@,(WB!""@XY`@8^4`L(WE2!"@ -MXP$@H./^___K#`"-Y10`C>(`$*#C>""@X_[__^O0-)3E``!3XU```-K^___K -M#2"@X7\]PN,_,,/C!""3Y0$@@N($((/EA("$XH1@E.40H(WB+9"@XP10H.$( -M`*#A!A"@X?[__^L!`%#C&```"@9`H.$`8);ED#"4Y:``A.()$*#A"B"@X0PP -M0^+^___K``!0XP(```H0,)WE``!3X^W__QID,)3E`2!#X@T`4N/I__^*H,"- -MX@,PC.`!(*#CC"!#Y10PW>4``%/C%"#-!>'__^H%0*#A#<"@X7\]S.,_,,/C -M!""3Y0$@0N($((/E_O__ZQ10C>(`8*#C`:"@XPJ0H.$3@.#C#`"=Y0`PU>4! -M`%/C$0``&HQ@S>4*(*#A"3"@X0,0U>+PC[WH\$$MZ1C03>(`0*#A -M`8"@X0<@S>6T,,WA`S"@XQ53#8#B(`"`XO[__^L`4%#BRP``"@0`H.$( -M$(7B_O__ZVP`E>4`$*#C:""@X_[__^ML<)7E!V"@X0`PH.,H,.;E`3#&Y2P` -MA^(($*#A!B"@X_[__^LR`(?B#1N$XA$0@>(&(*#C_O__Z\(.A.(,`(#B_O__ -MZP`0H.$X`(?B!B"@X_[__^L'(*#AOA/RX=PW`..S`)3A#Q`!X@`2@>&P$,+A -MLR"4X0$@@N*S((3AL##6X?PPP^/0,(/CL##&X05@H.$8,*#C%#"FY4``A^(! -M$*#C%R"-X@8PH.'^___K`1"@XP<@C>(&,*#A_O__Z[0@W>$7,-WE`P!3XXP` -M`!H',-WE`0!3XS<```K:.]0U`@``.@(`4^.%```:=P``Z@$P@^)S,._F``!3 -MX_O__PK:.\3E`1"@X[TNA.(*((+B!C"@X?[__^NT,-WA#S`#X@,QH.$!.H/C -M`C"#XQ@@C>*T,&+A`A"@XP8PH.'^___K&""-XH@S`>.X,&+A`A"@XP8PH.'^ -M___K`'"@X5L-A.(X`(#B"!"@X?[__^L``%#C"P``"K0@W>$'(`+B@C"`X+@W -MT^$/.L/C`3"#XG,P_^8S+H+B@@"`X+0PP.$#,J#AOC#-X0<`H.$"$*#C#B"- -MX@8PH.'^___K40``Z@$0H..]+H3B#2""X@8PH.'^___K`A"@XP0@C>(&,*#A -M_O__ZP!PH.$$`*#A"Q"@XP@@C>)L.P/C#^"@X0/PE.<(,)WE`P!3XP4``!K> -M.P#CLS"4X3\P`^(!.H/CM#'-X18``.H"`%/C!0``&MX[`..S,)3A/S`#X@([ -M@^.T,$&``#J``!3 -MX]X[`..S,)3A/S`#X@(\@P,!.H,3M#'-X?X^`N,#,-3G``!3X[0QW0$!,,,# -MM#'-`0,```H!`%/CM#'=`0$P@P.T,+P@;WH\$$MZ0!`H.$!8*#A!'"!XEL-@.(X`(#B!Q"@X?[__^L`4%#B -M&0``"AP[E.4!"1/C`@``"M`KU.4``%+C`@``&@,P`^(#`%/C"P``&@0`H.$' -M$*#A`""@X[`PUN'^___K`#``XP`P0.,`$)/E&PZ%XL@0@>+^___K!```Z@`P -MEN6<)M7E`1"@XQ$SPN&<-L7E``"@X_"!O>CP1RWI`&"@X0%`H.$"@*#A'#N0 -MY0,@`^(#`%+C`0``"@$)$^,V```*6PV&XC@`@.(($*#A_O__ZP!04.(P```* -M``!4XQ,``!IZ7X7B`G"@XP2@H.$`D.#C`"#5Y0$`4N,'```:A#"@X08`H.$( -M$*#A!R"@X1XP`^+^___K`*#%Y;*0Q>$!0(3B2%"%XA``5./P__\:&@``Z@$` -M5.,8```:`$"@XP*@H.,!D*#C!'"@X9LVU>53-*#A`0`3XPT```J$,*#A`3"# -MXP8`H.$($*#A"B"@X1\P`^+^___K&73@X9LVU>4#,`?@FS;%Y9PVU>4#<`?@ -MG';%Y0%`A.(0`%3CZ?__&@$`H./PA[WH<$`MZ0!@H.$!0*#AU#"1Y0$P@^+8 -M,('E>#L#XP/`D.<``%SC`P``"@`0H.,$(*#A`3"@XSS_+^'(.`'C`S"6YP(` -M4^,!,*`#`#"@$^@PA.4&`*#A!!"@X?[__^N$-I3E``!3XQ0```K<-);EB#:$ -MY?`DEN6<-I3E4S3OYR(T`^!@`!/C`3"@$YHVQ!7P));EG#:4Y5,T[^!0A.(&`*#A`!"@XP4@H.'^___K!@"@X0$0H.,%(*#A_O__ZP`0 -MH..;%L3EG!;$Y58/A.)8(*#C_O__Z_[__^L-(*#A?SW"XS\PP^,$()/E`2"" -MX@0@@^70()3E`2""X]`@A.4$()/E`2!"X@0@@^7^___K<("]Z!!`+>E8-Y'E -M`@P3XP$@H!,`(*`#W""!Y(`0*#A`:"@X;8@ -MS>%3#8#B(`"`XO[__^L`4%#B-@``"@0`H.$($(7B_O__ZP"`H.-;@,7E;`"5 -MY0@0H.%H(*#C_O__ZVQPE>4'8*#A*(#FY0&`QN4L`(?B"A"@X08@H./^___K -M,@"'X@T;A.(1$('B!B"@X_[__^O"#H3B#`"`XO[__^L`$*#A.`"'X@8@H./^ -M___K!R"@X;X3\N'<-P#CLP"4X0\0`>(`$H'AL!#"X;,@E.$!((+BLR"$X;`P -MUN'\,,/CP#"#X[`PQN$%,*#A&""@XQ0@H^5``(?B`A"@XP8@C>+^___K%#"5 -MY1@PA>4$`*#A!1"@X?[__^L,T(WB\(6]Z'!`+>D`0*#A`%!1XG"`O0B5-]7E -M``!3XPH```H`,*#CE3?%Y6`WD.4!,$/B8#>`Y0``4^,#```:*A"@XP`@H.,! -M,*#C_O__ZY8WU>4``%/C#@``"@`PH..6-\7E9#>4Y0$P0^)D-X3EX2?4Y0$` -M4N,&``":``!3XP0``!H$`*#A_Q"@XP`@H.,!,*#C_O__ZY4``%/C#@`` -M"@`PH..7-\7E:#>4Y0$P0^)H-X3EX2?4Y0$`4N,&``":``!3XP0``!H$`*#A -M_Q"@XP`@H.,!,*#C_O__ZY@WU>4``%/C`#"@$Y@WQ15P-Y05`3!#$G`WA!69 -M-]7E``!3XP`PH!.9-\45T#24%0$P0Q+0-(05FC?5Y0``4^,`,*`3FC?%%70W -ME!4!,$,2=#>$%00`H.&8]/_K``!0XPD``-H$`*#A+1"@XP`@H.,",*#A_O__ -MZP0`H.$]$*#C`""@XP$PH./^___KX&"%X@0`H.$`$*#C!B"@X?[__^L$`*#A -M`1"@XP8@H.'^___K`#"@XYLVQ>6<-L7E!`"@X080H.$#(*#C_O__Z]@@U>4# -M((+B!`"@X040H.%R(._F`3"@X_[__^NH/`/C`S"4YP0PD^4#`%/C!```&@0` -MH.$&$*#A`R"@X_[__^L"``#J!`"@X040H.'^___K_O__ZPTPH.%_;4``%/C'0``"@$P -M0^+(-H7E``!3XQD``!H;/87BQ":5Y<`6E>4$(('E`!""Y<`VA>7$-H7E!#"8 -MY0$P0^($,(CE_O__Z_[__^L$,)KE`3"#X@0PBN4&`*#A!1"@X?[__^L$,)GE -M`3!#X@0PB>7^___K_O__ZP0PF^4!,(/B!#"+Y0<`H.$$$*#A_O__ZP``4./7 -M__\*#3"@X7]-P^,_0,3C!#"4Y0$P0^($,(3E_O__Z_[__^L$,)3E`3"#X@0P -MA.4&>X;B('"'XB`X`>,#4);G.(@!XP"@H.,!D*#C/@``ZFM.1>((0$3B`%"5 -MY00`H.'^___K``!0XP@PEA?(-H05!*C$%<@VE.4``%/C,@``"@$P0^+(-H3E -M6">4Y0(+$N,8```*FR;4Y0``4N,"```:!"C4Y0``4N,2```*"""6YS(00N(! -M`%/A!*C$EAP0"WI"-!-X@!0H.$-,*#AR""?Y0,` -MDN@$`(/DL!##X1P[E>4#,`/B`P!3XR@``!K^___K#2"@X7\]PN,_,,/C!""3 -MY0$@@N($((/E!FN%XB!@AN(@.`'C`T"5YPP``.IK'D3B"!!!X@!`E.5K/H'B -M"#"#XKPFD>6X!I'E!""`Y0``@N6X-H'EO#:!Y04`H.'^___K!@"@X000H.'^ -M___K``!0X^W__PH-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K!0"@X0T0 -MH.$#(*#C_O__ZP``H.,(T(WB<("]Z%02``!P0"WI`$"@X0`PH./(-\#E("0! -MXP(PP.?^___K!`"@X?[__^L$`*#A_O__ZP!@H.'^___K#3"@X7]=P^,_4,7C -M!#"5Y0$P@^($,(7E!`"@X080H.'^___K!#"5Y0$P0^($,(7E_O__ZP0`H.'^ -M___K;`"$XO[__^MP@+WH<$`MZ0!`H.$`4*#CR%?`Y2`T`>,#4,#G_O__ZQQ; -MA.4$`*#A_O__ZP0`H.'^___K`&"@X?[__^L-,*#A?UW#XS]0Q>,$,)7E`3"# -MX@0PA>4$`*#A!A"@X?[__^L$,)7E`3!#X@0PA>7^___K'PV$X@@`@.+^___K -M<("]Z#!`+>D,T$WB`$"@X?[__^L``%#C`P``"@0`H.'#'H3B`R"@X_[__^L` -M(*#C'"N$Y61;`^,$`*#A"Q"@XP_@H.$%\)3G!`"@X000H.,`(`#C`"!`XP_@ -MH.$%\)3G'#N4Y0,P`^(#`%/C`0!3$P8``!H(((WB`#"@XP$P8N4$`*#A"!"@ -MXP_@H.$%\)3G!`"@X0(0H./^___K`%"@XQQ;A.7?5\3EX%?$Y00`H.'>%]3E -M!2"@X04PH.'^___K!`"@X?[__^M/#83B&`"`XO[__^L%`*#A#-"-XC"`O>CP -M3RWI#-!-X@!`H.$!8*#APEZ`X@Q0A>(!<*#A'#N0Y0$)$^,4```*`@`3XP(` -M``K#'H3B`R"@X_[__^L`@*#C'(N$Y00`H.'^___K3PV$XA@`@.+^___K!`"@ -MX0(0H./^___K!`"@X0L0H.,((*#A9#L#XP_@H.$#\)3G!`"@X7(0U^4`(*#C -M_O__ZP0`H.'^___K`#"@X]\WQ.7@-\3ESCO$Y$!((+BLR"%X;`P -MUN'\,,/CR#"#X[`PQN$:,*#C%#"$Y1@PA.4%`*#A!!"@X?[__^OPA[WH\$]"%,-A.(@`(#B_O__ZP!04.+PA[T(!`"@X0@0A>+^___K -M`("@XUN`Q>5L`)7E"!"@X6@@H./^___K;'"5Y2APA^('8*#A`(#'Y0&`Q^4< -M.Y3E`S`#X@,`4^,`@,8%`C"@`P$PQP4$```*`@!3XP`PH`,`,,<%`3"@`P$P -MQP4``%KC!P``"@`PUN4!(-;E`C2#X0$Z@^-S,/_F`##&Y2,TH.$!,,;EPHZ$ -MX@R`B.((`*#A_O__ZP`0H.$$`(;B!B"@X_[__^L*`(;B#1N$XA$0@>(&(*#C -M_O__ZP@`H.'^___K`!"@X1``AN(&(*#C_O__Z[8A]N'<-P#CLQ"4X0\@`N(! -M(H+AL"#&X;,@E.$!((+BLR"$X;`PU^'\,,/C2#"#X[`PQ^$8,*#C%#"%Y1@P -MA>4$`*#A!1"@X?[__^OPA[WH\$\MZ57?3>(`0*#A4QV`XB`0@>(,$(WE`!"@ -MXR01C>4D`(WB_R"@X_[__^L,`)WE_O__ZP"`4.+@`0`*!`"@X0@0B.+^___K -M;`"8Y0`0H.-H(*#C_O__ZVQ0F.4%8*#A`*"@XRB@YN4!H,;EPGZ$X@QPA^(' -M`*#A_O__ZP`0H.$L`(7B!B"@X_[__^L-*X3B$2""XA@@C>4R`(7B`A"@X08@ -MH./^___K!P"@X?[__^L`$*#A.`"%X@8@H./^___K!2"@X;X3\N'<-P#CLP"4 -MX0\0`>(`$H'AL!#"X;,@E.$!((+BLR"$X;`PUN'\,,/CL##&X4!@A>(8,*#C -M%#"(Y%"`(7B`B"@X_[__^L4,)CE`C"#X@@0H.$4,*'E$!"-Y3@L -ME.4`$(WE1`"%X@H0H.'#/H3B##"#XO[__^L4`(WE!`"@X4H?C>))+XWB_O__ -MZ]XWU.4.`%/C!#"@`R0QC06,?-3E``!7XS(```H!,*#C`R"$X(PLTN4``%+C -M"P``&B3!G>45[HWB**!^Y8JLX.&JK.#A>J#OY@`@H.,"8*#A?U#@XQ>PX.," -MD*#A!P``Z@$P@^(0`%/C[/__&N___^H&,(3@C'S3Y0``5^,6```*``!$#```*`3"# -MX@P`4^'W__\:`P``ZA4>C>(",('@"W##YP$@@N(!8(;B$`!6X^3__QH"8*#A -M``!2XP8``!H,`)WE44`)WE`1"@XP@@H.,%,*#A_O__ZQ`PG>4`,(WE,A"@XP@@ -M1N((,(7B_O__ZP"PH.$&``#J$!"=Y0`0C>44`)WE`1"@XTX_C>+^___K`+"@ -MXA.)2;XWBH#R4Y04`H.$P$*#C!B"@X0PP0^+^___K`#!0X@<```H0()WE -M`""-Y0L`H.$P$*#C2"&=Y0(P@^+^___K`+"@X=@TE.4!`%/C4@``&J`\E.4% -M`*#A+1"@XP8@H.$,,$/B_O__ZP!04.)*```*!`"@X?[__^L``%#C1@``&K\. -MA.(&`(#B`A"%XB`@H./^___K^SX"XP,PU.<``%/C]CL`X[,@E.%"(,(#`B"" -M$[,@A.'V.P#CLR"4X0P@@N.S((3A!`"@X100H.-1+XWB`R""XF@[`^,/X*#A -M`_"4YT4#`%/C#```&OT^`N,#,-3G``!3X_8[`!.S()01`2R"$[,@A!&_ -M#H3B"0"`XL`3G^40(*#C_O__ZQ4``.K]/@+C`S#4YP,`4^,(```*X2?4Y0@` -M$N,!```*`0!3XP,```H0`!+C!0``"@(`4^,#```:]CL`X[,@E.$"+(+CLR"$ -MX;\.A.()`(#B:!.?Y1`@H./^___KOSZ$XA`0G>4`$(WE"P"@X2T0H.-((9WE -M!C"#XO[__^L`L*#AH#R4Y0P`4^,Y``":RJZ$X@2@BN(,8*#C`#``XP`P0..$ -M((/B%""-Y020H..,$(/B#!"-Y8@P@^(<,(WE!'"@X090BN``,-7EW0!3XR$` -M`!H"0(7B!`"@X100G>4)(*#A_O__ZP``4.,+```:!`"@X1P0G>4)(*#A_O__ -MZP``4.,%```:!`"@X0P0G>4)(*#A_O__ZP``4.,.```*!`"@X0P0G>4)(*#A -M_O__ZP``4.,.(*`3`2#%%0$@U>40,)WE`#"-Y0L`H.'=$*#C`C"%XO[__^L` -ML*#A`3#5Y0(P@^(#8(;@H#R7Y08`4^'3__^*!T"@X4`$(WE"P"@X=T0H.,&(*#C*#*?Y?[__^L`L*#AJ#P#XP,PE.<``%/C`@`` -M&A`"G^7W%P#C_O__ZP`PD^4``%/C`@``&O@!G^4Y%P#C_O__ZR$RT^4``%/C -M#```"K`7E.4``%'C;```"L0GE.4``%+C:0``"@L`H.'^___K%""8Y<0WE.4# -M,(+@%#"(Y6(``.HL.@/C`S"4YP``4^->```*`0!3XUP```I0,*#C)##-Y1\P -M@^(E,,WE93#@XR8PS>5O,(/B)S#-Y0(PH.,H,,WE)%"-XK4PQ>$>,(/B*S#- -MY0`PH.,L,,WE"#"#XBTPS>4$(*#CNB#%X0`PX..\,,7AOC#%X0XP@^(T,,WE -M>CH#XP,PU.<5,(/BL3'%X1,`A>(8$)WE!B"@X_[__^O$.@/C`S"4YP$P0^(! -M`%/C`CN@DP(YH(.Y,<7A'AR@X[L1Q>$D8(WB`#`%X_(T0.,=,(;E`2R@X[$B -MQ>$`,*#C1S#-Y1`Q`>.T,L7A>GH#XP<@U.>R/[_FMC+%X>D=A.),`(WB&A"! -MXO[__^L',-3G*#"#XA4>C>(#(('@$!"@XRP10N4!,(/B#2"@X[,@A>$"4(/B -M.GR$XC!PA^(%`(;@!Q"@X08@H./^___K!E"%XA4>C>(%,('@`2"@XRPA0^4" -M4(7@!0"&X`<0H.$%((+B_O__ZQ`@G>4`((WE"P"@X=T0H.,&((7B!C"@X?[_ -M_^L4,)CE&#"(Y00`H.$($*#A_O__ZU7?C>+PC[WHX`0``/`$````````)``` -M`'!`+>D`4*#A3TV`XAA`A.($`*#A_O__ZQP[E>4#/,/C"3N#XQP[A>4%`*#A -M_O__ZP`P`.,`,$#C`!"3Y00`H.$>$('B_O__ZW"`O>CP3RWI)-!-X@!`H.$" -M8*#A`Z"@X;X0S>%3#8#B(`"`XO[__^L`4%#B_0``"@0`H.$($(7B_O__ZVP` -ME>4`$*#C:""@X_[__^ML<)7E*("'X@B0H.$`,*#C`##(Y0$PR.4L`(?BX!"& -MX@8@H./^___K,@"'X@T;A.(1$('B!B"@X_[__^O"#H3B#`"`XO[__^L`$*#A -M.`"'X@8@H./^___KOB/WX=PW`..S$)3A#R`"X@$B@N&P(,?ALR"4X0$@@N*S -M((3A,`!:XQ``6A/4```:RKZ$X@2PB^*P,-CA_###XP.@BN&PH,CA&!"@X[(1 -MQ>$4,)7E&#"#X@6@H.$4,*KE&("(X@L`H.'^___K('"-XK``T.&R`&?A"`"@ -MX0(0H.,'(*#A"C"@X?[__^L"$*#C#B"-X@HPH.'^___KM#W6X0,YX.$C.>#A -MOC'-X0(0H.,'(*#A"C"@X?[__^M`(9;E"`!2XP4``(H`H(WE`1"@XQ,^AN+^ -M___K"`"-Y0L``.H`H(WE`1"@XP@@H.,3/H;B_O__ZT`AEN4`H(WE,A"@XP@@ -M0N)./X;B_O__ZP@`C>58-Y;E`@L3XS0```K8-)3E``!3XS$```H@<(WB`#"@ -MXP@P)^4,@(OBH#R4Y0@`H.$M$*#C!R"@X0PP0^+^___K`!!0X@X```H8()WE -M``!2XPL```H(`)WE`B""XO[__^L8,)WE`B"#X@@0G>4"$('@"!"-Y10@E>4" -M,(/@`C"#XA0PA>6@/)3E"`"@X3T0H.,'(*#A##!#XO[__^L`$%#B#@``"A@@ -MG>4``%+C"P``"@@`G>4"((+B_O__ZQ@PG>4"((/B"!"=Y0(0@>`($(WE%""5 -MY0(P@^`",(/B%#"%Y5@WEN4"#!/C+@``"LPTE.4``%/C*P``"@`PH.,8,(WE -M$#"-XG`AG^4#`)+H!`"#Y+`0P^$,`(OB&("-XMV0H.,0L(WBH,R4Y0[`3.() -M$*#A"""@X1@PG>4,,&/@_O__ZP!P4.(7```*`@"'X@L0H.$&(*#C_O__ZP`` -M4.-````*"`"=Y0<0H.$8()WE`B""XO[__^L8,)WE`B"#X@@0G>4"$('@"!"- -MY10@E>4",(/@`C"#XA0PA>4"``#J`C"#X@,`A^#>___JRCO4Y0$`4^,'```: -M`*"-Y0@`G>7=$*#C!B"@XP`P`.,`,$#C_O__ZP@`C>6,%Y3E``!1XPL```J< -M)Y3E``!2XP@```H(`)WE_O__ZYPWE.4(()WE`R""X`@@C>44()7E`S""X!0P -MA>4D.@/C`S"4YP,`4^,*```:K#?6Y0$`4^,'```:W0V$XB``@.(($)WEK2?6 -MY?[__^L4,)7E`#"#X!0PA>44,)7E&#"%Y00`H.$%$*#A_O__ZP,``.H8,)WE -M``!3X\K__QK,___J)-"-XO"/O>A<$@``\$\MZ1303>(`0*#A`8"@X0*@H.%3 -M#8#B(`"`XO[__^L`8%#BN0``"@0`H.$($(;B_O__ZVP`EN4`$*#C:""@X_[_ -M_^MLD);E"7"@X0`PH.,H,.?E`3#'Y0D@H.&^$_+AW#<`X[,`E.$/$`'B`!*! -MX;`0PN&S()3A`2""XK,@A.&P,-?A_###X[`P@^.P,,?A0)")XA@PH.,4,(;E -M``!8XS<```H$`(?BX!"(X@8@H./^___K#5N$XA%0A>(*`(?B!1"@X08@H./^ -M___K$`"'X@40H.$&(*#C_O__Z]"VF.5[L/_F"S"@X;JPS>$``%KC`+"@$PLP -MH!&Z,,T1`0``&@"P6^(!L*`3"G"-XA10AN()`*#A`A"@XP<@H.$%,*#A_O__ -MZ\PVF.6Z,,WA`A"@XP<@H.$%,*#A_O__Z[J@S>$"$*#C!R"@X04PH.'^___K -MS#:8Y0(`4^-D```:T#"8Y:,T&^!A```*`%"-Y1`0H..`(*#C;3Z(X@0P@^+^ -M___K6@``ZL)>A.(,4(7B!0"@X?[__^L`$*#A!`"'X@8@H./^___K"@"'X@T; -MA.(1$('B!B"@X_[__^L%`*#A_O__ZP`0H.$0`(?B!B"@X_[__^LPNY3E`0!; -MXP"PH!,!L*`#NK#-X2P[E.4#`%/C$```&AP[E.6C-!O@#0``"D`[E.4\&Y3E -M`1^#X1`@C>($$"+E`3"#XD`[A.4)`*#A!!"@XQ0PAN+^___K`)"@X00PH.,> -M,,;E"H"-XA10AN()`*#A`A"@XP@@H.$%,*#A_O__ZRP[E.6Z,,WA`A"@XP@@ -MH.$%,*#A_O__Z[J@S>$"$*#C"""@X04PH.'^___K+#N4Y0,`4^,9```:'#N4 -MY:,T&^`6```*`%"-Y1`0H..`(*#C+3V$X@0P@^+^___K`##7Y0$@U^4"-(/A -M`3F#XW,P_^8`,,?E(S2@X0$PQ^48,*#CLC'&X0$PH.,=,,;E!#"@XQ\PQN44 -M,);E!#"#XA0PAN44,);E&#"&Y00`H.$&$*#A_O__ZP0`H.$&$*#A_O__ZQ30 -MC>+PC[WH$$`MZ0!`H.$<.Y#E`0P3XP0```H`,*#C'#N`Y0(0X./^___K$("] -MZ`(,$^,6```*(#N0Y0$P@^(@.X#E`@!3XP0``)H`,*#C'#N`Y0`0X./^___K -M$("]Z`$PH.,L.X#E`!"@XP$@H.'^___K`#``XP`P0.,`$)/E3PV$XA@`@.(> -M$('B_O__ZQ"`O>@""A/C$("]""0[D.4!,(/B)#N`Y0(`4^,$``":`#"@XQP[ -M@.4!$.#C_O__ZQ"`O>C^___K`#``XP`P0.,`$)/E3PV$XA@`@.(>$('B_O__ -MZQ"`O>AP0"WI`$"@X4]M@.(88(;B!@"@X?[__^L<.Y3E`3S#XP(\@^,<.X3E -M`3"@XRP[A.4`4*#C(%N$Y21;A.4H6X3E!`"@X<,>A.(#(*#C_O__ZP0`H.$% -M$*#A!2"@X?[__^L`,`#C`#!`XP`0D^4&`*#A'A"!XO[__^MP@+WH\$`MZ0S0 -M3>(`4*#A?$"1Y71PD>4-"X#B$0"`X@1@H.&P,-3A`0P3XP(@H!,`(*`#TS3@ -MYP,P@N$!`%/C!!"$`@$```H0$(0B!!"$,@8@H./^___K``!0XT,```H<.Y7E -M`@P3XT````JP,-;A`0D3XP0PH!,`,*`#`S"$X+HAT^&\,=/A``!3XPX```H- -M`%/C!```&C`[E>4!`%/C`#"@`P$PH!,P.X7E`#``XP`P0.,`$)/E3PV%XA@` -M@.+^___K``"@XRL``.H"`%+C'0``&C`[E>4!`%/C'P``&AX`A.(0$*#C!""- -MXAXP1^+^___K`!!0XAX```HM#87B!`"`X@(0@>($()WE_O__ZP,PH.,L.X7E -M!0"@X0`0H.,!(*#A_O__ZP`P`.,`,$#C`!"3Y4\-A>(8`(#B'A"!XO[__^L! -M`*#C"P``Z@0`4N,(```:,#N5Y0$`4^,%```:!0"@X?[__^L!`*#C`@``Z@$` -MH.,```#J``"@XPS0C>+P@+WH\$(`8*#A`9"@X0)0H.$`,*#C%#"- -MY0PPC>(`(I_E`P"2Z`0`@^2P$,/A4PV&XB``@.+^___K`$!0XG8```H&`*#A -M"!"$XO[__^ML`)3E`!"@XV@@H./^___K;'"4Y2APA^('@*#A#:N&XA&@BN(` -M,*#C`##'Y0$PQ^4#`%7A#@``&L)>AN(,4(7B!0"@X?[__^L`$*#A!`"'X@8@ -MH./^___K!0"@X?[__^L`$*#A$`"'X@8@H./^___K"```Z@Q0C>($`(?B!1"@ -MX08@H./^___K$`"'X@40H.$&(*#C_O__ZPH`B.(*$*#A!B"@X_[__^NV(?CA -MW#<`X[,0EN$/(`+B`2*"X;`@R.&S();A`2""XK,@AN&P,-?A_###XT`P@^,' -M`*#AN#'`X!@PH.,4,(3E``!9XPDPH!$$(),4%!"$$@`0C14`$*`3%#"$`@`P -MC04`$*`#`2"@`0$PH`'^___K`%"@X08`H.$8$(WB%""-XO[__^L4()WE"`!2 -MXPX``-H4<(3B&("-X@!PC>4%`*#A`1"@XP@@H.,(,*#A_O__ZP!PC>4R$*#C -M%""=Y0@@0N((,(CB_O__ZP4``.H4,(3B`#"-Y04`H.$!$*#C&#"-XO[__^M< -M)Y;E`1!"XOXQ`.,#`%'A!@``BE4>AN(,$('B_O__ZQ0@E.5<-Y;E`S""X!0P -MA.44,)3E&#"$Y08`H.$$$*#A_O__ZRC0C>+PA[WH9!(``/!/+>D(`(*#C%#"-XO[__^N( -M-Y3E`)"@X0``4^,``%`3+P``"A1@G>4``%;C+```"LH>A.($$('B`(!AX*"\ -ME.4+L&C@"[!FX`<`H.$((*#A_O__ZPAPA^`4,)7E"#"#X!0PA>6(-Y3E`2#3 -MY10@C>4"((+B"#""X`,,4^,)``"*!P"@X8@7E.7^___K%#"=Y0(@@^("<(?@ -M%""5Y0(P@^`",(/B%#"%Y10PG>4",(/B"("#X`N`B.`##%CC9```B@<`H.$& -M$(G@"R"@X?[__^L+<(?@%#"5Y0NP@^`4L(7E6P``Z@<`H.'*'H3B!!"!XJ`L -ME.7^___KH#R4Y0-PA^`4()7E`S""X!0PA>50``#J"("'XB`PH.,4,(7ERFZ$ -MX@1@AN(&`*#A_O__ZP`0H.$(`*#A`B"@X_[__^L*@(?B%#"5Y0(P@^(4,(7E -M!@"@X?[__^L`$*#A"`"@X0(@H./^___K%#"5Y0(P@^(%8*#A%#"FY3@LE.4` -M8(WE#`"'X@`0H./#/H3B##"#XO[__^L`D*#A,GV$X@QPA^('`*#A_O__ZP"` -MH.$`8(WE"0"@X0$0H.,(`%CC"""@,0@@H",',*#A_O__ZP!@C>4#$*#C`2"@ -MX\<^A.($,(/B_O__ZP!PH.$<.Y3E`S`#X@$`4^,-```:`""@XQ,@S>48,(WB -M#"`CY0!@C>4&$*#C`B"@X_[__^L`8(WE*A"@XP$@H.,3,(WB_O__ZP!PH.$( -M`%CC!P``F@!@C>4'`*#A,A"@XP@@2.+)/H3B!#"#XO[__^L`<*#A)#H#XP,P -ME.<#`%/C(@``&@``6N,@```*J#P#XP,PE.<``%/C`@``&H@`G^7W%P#C_O__ -MZP`PD^4``%/C`@``&G``G^4Y%P#C_O__ZR$RT^4``%/C"```"L!GE.6L%Y3E -M``!1XP``5A,(```*!P"@X08@H.'^___K!```ZMT-A.(@`(#B!Q"@X?[__^L` -M8*#A%#"5Y09@@^`48(7E%#"5Y1@PA>4$`*#A!1"@X?[__^L4'8*#A`#"@XR@PYN4! -M,,;E+`"'XA`0C>(&(*#C_O__ZS(`A^(-&X3B$1"!X@8@H./^___KP@Z$X@P` -M@.+^___K`!"@X3@`A^(&(*#C_O__ZP4``%SC`@``&L0#G^4Y%P#C_O__Z\H>A.($$('B`&!AX`.0@.`"H&;@"J!C -MX"$"W.4``%#C)@``"H`WE.4``%/C&P``"I`WE.4``%/C&```"@<`H.$&(*#A -M_O__ZP9PA^`4,)7E!F"#X!1@A>4'`*#A@!>4Y9`GE.7^___KD#>4Y0-@A^`4 -M()7E`S""X!0PA>4&`*#A"1"@X0H@H.'^___K"G"&X!0PE>4*H(/@%*"%Y40` -M`.H'`*#A_O__ZZ`\E.4#<(?@%""5Y0,P@N`4,(7E/```Z@<`H.$#((;@_O__ -MZPPPG>4#,(;@`X"'X!0@E>4#,(+@%#"%Y1`T!>.P,,CA`CN@X[(PR.$>+*#C -MM"#(X0`P!>/R-$#C!C"(Y0$\H..Z,,CA$#$!X[PPR.%ZN@/C"S#4Y[,_O^:^ -M,,CA$`"(XND=A.(:$('B"R#4Y_[__^L+,-3G$#"#X@9@A^`,(-WE`B!"X@(@ -M@^`!(,;E`X"(X!0@E>4#,(+@%#"%Y0@`H.$)$*#A"B"@X?[__^L*<(C@%#"5 -MY0J@@^`4H(7E"0``Z@<`H.'*'H3B!!"!XJ`LE.7^___KH#R4Y0-PA^`4()7E -M`S""X!0PA>4D.@/C`S"4YP,`4^-J```:J#P#XP,PE.<``%/C`@``&N0!G^7W -M%P#C_O__ZP`PD^4``%/C`@``&LP!G^4Y%P#C_O__ZR$RT^4``%/C"```"K1G -ME.6@%Y3E``!1XP``5A,(```*!P"@X08@H.'^___K!```ZMT-A.(@`(#B!Q"@ -MX?[__^L`8*#A%#"5Y09@@^`48(7E2```Z@B`A^(@,*#C%#"%Y4",(/B%#"%Y08`H.'^ -M___K`!"@X0@`H.$"(*#C_O__ZQ0PE>4",(/B!6"@X10PIN4X+)3E`&"-Y0P` -MA^(`$*#CPSZ$X@PP@^+^___K`*"@X3)]A.(,<(?B!P"@X?[__^L`@*#A`&"- -MY0H`H.$!$*#C"`!8XP@@H#$((*`C!S"@X?[__^L`8(WE`Q"@XP$@H./'/H3B -M!#"#XO[__^L`(*#C#"#-Y1@PC>(0("/E`&"-Y080H.,"(*#C_O__ZP!@C>4J -M$*#C`2"@XPPPC>+^___K"`!8XP4``)H`8(WE,A"@XP@@2.+)/H3B!#"#XO[_ -M_^L`,*#CR#?$Y0T@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^L4,)7E(""# -MX@(,4N,#``"*&#"%Y00`H.$%$*#A_O__ZQS0C>+PC[WH;!(``"0```#P02WI -M"-!-X@!`H.$`4*#C"&"-X@%09N5H>P/C$X"@XP0`H.'^___K_O__ZP0`H.$( -M$*#A!B"@X0_@H.$'\)3G!S#=Y0``4^,"```:`5"%XF0`5>/Q__\:9`!5X@$` -MH!,(T(WB\(&]Z/!/+>E$T$WB`$"@X0%0H.$`,*#C/#"-Y0`0`.,`$$#CY#.1 -MY2`PC>48,(WB^A^!X@,`D>@$`(/DL!##X6PPE.40`!/CF0(`"@,,4N.7`@#* -M56^$XE`AA.4&`*#A`!"@XP,LH./^___K!@"@X040H.%0(93E_O__ZS@QE.4$ -M`%/CB@(`&@!0H.,0483EX`"$X@T;A.(1$('B!B"@X_[__^L&`*#A_O__ZP$@ -MT.4`,-#E`C2#X1PQA.4!@-;E5#'4Y0B$@^$,D(;B/&"-XE`QE.4)`*#A!1"@ -MX08@H.$,,$/B_O__ZP!04.(,```*/#"=Y0``4^,)```*Z`"$X@`0H.,D(*#C -M_O__Z^P`A.("$(7B/""=Y?[__^L\,)WEZ#"$Y0`PH.,8,83E4#&4Y0D`H.$# -M$*#C!B"@X0PP0^+^___K``!0XP,```H\,)WE``!3XP)PT!4````:`'"@XR1Q -MA.4D`(WB`!"@XQ`@H./^___K4#&4Y0D`H.$!$*#C!B"@X0PP0^+^___K`!!0 -MX@!0H`,$```*)`"-X@(0@>(\()WE_O__ZSQ0G>50,93E"0"@X3(0H.,&(*#A -M##!#XO[__^L`$%#B!@``"B0`C>(%`(#@`A"!XCP@G>7^___K/#"=Y0-0A>`D -M`(WB!1"@X0<@H.'^___K<+#OYD\OA.($((WE`@"@X0L0H.'^___K4#&4Y0D` -MH.$J$*#C!B"@X0PP0^+^___K`!!0X@0```H\,)WE``!3XP$```H$`*#A_O__ -MZQ``&.,!,*`3`#"@`PPQA.4`,*#C!"H!XP(PA.,",(3G -M%"H!XP(PA.=0,93E"0"@X3`0H.,&(*#A##!#XO[__^L``%#C&```"CP0G>4` -M`%'C%0``"@(0@>(X((WB-#"-XO[__^L!`%#C#P``&@(@H./(.`'C`R"$YP$@ -MH.,:/*#C`R"$YP0Z`>,#()3G`B""XP,@A.4T,(WE""H!XP(PA.<0*@'C`C"$YPD`H.'=<*#C -M(("-X@2@H.-0P93E#L!,X@<0H.$&(*#A/#"=Y0PP8^#^___K`%!0XB$```H" -M`(7B"!"@X0H@H.'^___K``!0X]4!``H%`*#A/!"=Y0(0@>(X((WB-#"-XO[_ -M_^L!`%#C$P``&@(@H./(.`'C`R"$YP$@H.,:/*#C`R"$YP0Z`>,#()3G`2"" -MXP,@A.#4___J -M`#"@XSPPC>7,-(3E>SL"XP,PU.<``%/C'```"@D`H.'=<*#C&("-X@:@H.-0 -MP93E#L!,X@<0H.$&(*#A/#"=Y0PP8^#^___K`%!0X@\```H"`(7B"!"@X0H@ -MH.'^___K``!0XZ,!``H!,*#CS#2$Y0@P]>6#/.#AHSS@X0`PQ>4"``#J`C"# -MX@,`A>#F___J4#&4Y0D`H.$M$*#C!B"@X0PP0^+^___K`%!0XB,```H\,)WE -M``!3XR````H"<(7B"+"+XP0`H.$4$*#C%R"-XF@[`^,/X*#A`_"4YQ`Z`>,# -M,)3G$``3XP,``!H4.@'C`S"4YQ``$^,"```*`C#7Y1PP@^,",,?E%S#=Y0,` -M4^,`,.`#`S#'!0`PH`,$,,<%3PZ$X@$`@.("$(7B/""=Y?[__^L%<*#A`5"@ -MXP$``.H`4*#C!7"@X5`QE.4)`*#A/1"@XP8@H.$,,$/B_O__ZP!@4.("```* -M/#"=Y0``4^,````:`&"@XPL`6^,1``"*>S"OY@$@H.,2(Z#A##P`XP`P0.,# -M,`+@``!3XP,PH!,4,805"0``&A``$N,",*`3%#&$%04``!H"`!+C`3"@$Q0Q -MA!4!```:`S"@XQ0QA.7(L(3E`#"@X]@TA.7Z/@+C`S#4YP``4^,`4*`#`5`% -M$@``5>,,```*`3"@X]@TA.7,-(3E_#X"XP,PU.53,>+G0""-XBLP8N5D6P/C -M!`"@X2(0H.,/X*#A!?"4YP0`H.$C$*#C%B"-X@_@H.$%\)3G]CL`X[,PE.%3 -M,>'GUCO$Y=@PE.4!`%/C`0``"@0`H.'^___K!`"@X0,0H./^___KX+"$XF1K -M`^,$`*#A!!"@XPL@H.$/X*#A!O"4YT!0C>(7,@/C+S!`XS0P)>4$`*#A'1"@ -MXP4@H.$/X*#A!O"4YQ,$#C##"-Y00`H.$>$*#C!2"@X0_@H.$&\)3G -M*S0*XUXP0.,,,(WE!`"@X1\0H.,%(*#A#^"@X0;PE.=$-`KC##"-Y00`H.$@ -M$*#C!2"@X0_@H.$&\)3GR#@!XP,PE.<"`%/CS#"@`\\PH!-`((WB*3!BY090 -MH.$$`*#A$A"@XP_@H.$&\)3G!`"@X0X0H.,2((WB#^"@X0;PE.<$`*#A!!"= -MY5'G_^L$`*#A!A"@XP0@G>4/X*#A!O"4Y]@PE.4!`%/C`P``"@0`H.$/$N#C -M`2"@X_[__^M0,93E"@"@X3T0H.,(((WB##!#XO[__^L``%#C%0``"@@PG>4` -M`%/C$@``"OL^`N,#,-3G``!3XPX```H#,-#E!``3XPL```H#,`/B`2!#X@(` -M4N,`4*"#`6"@@P$P0Y(`(`"3`"!`DP,@@I#P8]*5]%/2E0$``.H`4*#C!6"@ -MX00`H.$)$*#A!2"@X08PH.'^___KWI?$Y=]GQ.7@5\3ER#"4Y>$WQ.4$`*#A -M_O__ZP@`H.$'$*#AW""4Y?[__^OJ#83B(@"`XNP0A.+H()3E_O__Z^@@E.7" -M.@/C`R#$YR`T`>,#,-3G`0!3XP8``!H$`*#A!1"@XP`@H.,",*#A_O__ZP0` -MH.'^___K!`"@X?[__^L`@%#B3@``"@`0H./4$(CE`5"@X]A0B.7<$(CEA!:( -MY>@0B.56#XCB6""@X_[__^L$`)WE_O__ZP!PH.$$`)WE!Q"@X04@H.'^___K -M$PZ(XD\?A.('(*#A_O__ZT!QB.4``%?C"@``V@A0H.$`8*#C,`'5Y0``4.,! -M```*?P``XO[__^L!8(;B`5"%X@8`5^'V__\:)`&4Y0X`4.,57J"##U"@DPX` -M4.,$`*"#`0"@D_[__^L`8*#A!0"@X?[__^L_<`#B>#L#XP/`E.<``%SC!``` -M"@0`H.$`$*#C"""@X0$PH.,\_R_AV"#8Y1\@`N($`*#A!AZ%X8`@@N.$.P/C -M#^"@X0/PE.=.84``%/C/_[_&D'^_^H\,)WE``!3XU_^_QIA_O_J -M^$\MZ0!0H.'^___K``!0XP0`H`/XC[T(!0"@X?[__^L`<%#B/```"KXX`>.S -M,)7A`0`3XS@```K,,)?E``!3XS4```H*`*#C_O__Z_[__^L-(*#A?SW"XS\P -MP^,$()/E`2""X@0@@^7$H(?BQ&"7Y0&`H.,1D*#CE+L#XQ@``.H&0*#A`&"6 -MY00PE.4$,(;E`&"#Y0!`A.4$0(3ES#"7Y0$P0^+,,(?E``!3XU2`Q!4`,*`# -M5##$!5:`Q.57D,3E!0"@X000H.$/X*#A"_"5YP$`4.,"```:!0"@X000H.'^ -M___K"@"@X080H.'^___K``!0X^'__PH-(*#A?SW"XS\PP^,$()/E`2!"X@0@ -M@^7^___K``"@X_B/O>@``*#C^(^]Z#!`+>D,T$WB`$"@X0%0H.$<.Y#E`R`# -MX@$`4N,<```:`0D3XQ(``!I]'H3B_O__ZP0`H.'^___K``!0XPD``!K8,)7E -M?3"#XH,RA.`(,(/B`""@XP`@@^4<.Y3E`3`CXAP[A.43``#J'#N4Y0$Y@^,< -M.X3E"""-X@(PH.,!,&+E!`"@X0T0H.-D.P/C#^"@X0/PE.?8,)7E@S*$X*1? -M@^4$`*#AV!"5Y?[__^L$`*#A!1"@X?[__^L,T(WB,("]Z#!`+>D,T$WB`$"@ -MX<)>@.(,4(7B=#R0Y=XWP.4%`*#A_O__Z\8[`..S`(3A!`"@X?[__^L%`*#A -M_O__ZP!0H.$$`*#A!1"@X?[__^L"`!7C,```"@@@C>(P,.#C`3!BY00`H.$2 -M$*#C9#L#XP_@H.$#\)3G!`"@X=X7U.4`(*#C`C"@X?[__^L$`*#A_O__ZP$0 -MH.,<&X3E!`"@X?[__^L$`*#A_O__ZP``4.,%```:!`"@X0`0X./^___K`#"@ -MXQP[A.43``#J9%L#XP0`H.$$$*#CKBV$X@8@@N(/X*#A!?"4YP@@C>(`,*#C -M`C!BY00`H.$-$*#C#^"@X07PE.<$`*#A`1"@X_[__^L<.Y3E`3F#XQP[A.4, -MT(WB,("]Z'!`+>D`0*#A`5"@X5PPT>5=(-'E`C2#X5X@T>4".(/A7R#1Y0(\ -M@^$$`%/C+P``"@``4^,M```:_O__ZP!@H./?9\3EX&?$Y4" -M)(/A=C#5Y0,H@N%W,-7E`RR"X:`LA.4##%+C!`"@@W"`O8C*#H3B!`"`XG@0 -MA>+^___K!`"@X?[__^L``*#C<("]Z```H.-P@+WH\$\MZ87?3>(`0*#A@C^- -MXJ@CG^4#`)+H!`"#Y+`0P^'_4*#C0@^-X@`0H.,%(*#A_O__ZP@`C>(`$*#C -M!2"@X?[__^M3#83B(`"`XO[__^L`8%#BUP``"@0`H.$($(;B_O__ZVP`EN4` -M$*#C:""@X_[__^ML@);E"'"@X0`PH.,H,.?E`3#'Y8)?C>(L`(CB!1"@X08@ -MH./^___K.`"(X@40H.$&(*#C_O__ZS(`B.(-&X3B$1"!X@8@H./^___K"""@ -MX;X3\N'<-P#CLP"4X0\0`>(`$H'AL!#"X;,@E.$!((+BLR"$X;`PU^'\,,/C -M0#"#X[`PQ^%``(CB&#"@XQ0PAN4L.@/C`S"4YP8`4^,(```:"#@#XP,@E.<4 -M,(;B`#"-Y0`0H.,..X3B##"#XO[__^L&``#J%#"&X@`PC>4`$*#C!R"@X^D] -MA.(+,(/B_O__ZQ1PAN(`<(WE`1"@XP@@H./I/83B`S"#XO[__^L`H*#AJ#P# -MXP,PE.<``%/C`@``&C@"G^7W%P#C_O__ZP`PD^4``%/C`@``&B`"G^4Y%P#C -M_O__ZR$RT^4``%/C%0``"H07E.4``%'C>```"J0WE.4``%/C=0``"I0GE.7^ -M___K%""6Y90WE.4#,(+@%#"&Y90'E.4``(K@I!>4Y;@GE.7^___K%""6Y;@W -ME.4#,(+@%#"&Y64``.HA7HWB`(`%X_*$0.,(@27E$#H$X[0PQ>$!O*#CMK#% -MX1`PH.,0,%ZF@/C"2#4Y[(_O^:[,,7A#0"%XND=A.(:$('B -M_O__ZPD@U.<-((+B$#0%X[(PA>$"((+B`CN@X[(PA>$"((+B'CR@X[(PA>$" -M((+B`H"%YP0@@N*RL(7A`'"-Y0H`H.'=$*#C`B""X@4PH.'^___K4#"@XP@P -MS>5O,*#C"3#-Y64PX.,*,,WE"3"@XPLPS>4"(*#C#"#-Y0@PC>*U(,/A(""@ -MXP\@S>4`(*#C$"#-Y08@H.,1(,WE!2"@X[H@P^%5(*#C%"#-Y5,@H.,5(,WE -M!""@XQ8@S>51$*#C%Q#-Y>D=H.,!$-3G&!#-Y0@0H.,9$,WELB'#X0`@X..T -M(4%(*#CN2'#X54P -MH.,C,,WE4S"@XR0PS>4$,*#C)3#-Y5$PH.,F,,WE03H#XP,PU.7=$*#C"#"-XO[__^L4,);E&#"&Y00`H.$&$*#A_O__ZX7?C>+PC[WH -MB!(``"0```#P3RWI'-!-X@!@H.&S/`/C`S#0YP``4^,````*_O__ZP8`H.'^ -M___K``!0XW8```K#3H;B6PV&XC@`@.($$*#A_O__ZP``4..D```*7C^@X].` -M@.$7/J#CT""#X0*@F.`#L*G@!CV@X]`@@^$"@)K@`Y"KX!8^H./3H(#A5C^@ -MX]`@@^$"H)K@`["KX/"AS>%:/Z#CTZ"`X=`AS>$*()+@"S"CX`(`6.$J```: -M`P!9X2@``!H0-`'C`S"6YP<`4^,;``"*``!3XQ0``!HL.@/C`S"6YP``4^," -M```*!@"@X?[__^L-``#JPTZ&X@A`A.(&`*#A!!"@X0`@H./^___K!@"@X000 -MH.$`(*#C_O__ZP8`H.$$$*#A`""@X_[__^L0-`'C`R"6YP$@@N(#((;G%P`` -MZ@!0H.,0-`'C`U"&YP8`H.$$$*#A_R\/X_[__^LH6X;E80``Z@`@H.,0-`'C -M`R"&YU8_H./30(#A%SZ@X_-`@.$6/J#CTT"`X5X_H./S0(#A6C^@X]-`@.$& -M/:#C\T"`X08PH.%()0'C`B"SYP0`D^5@-0'C`Q"6YP(`4>$.```:`S"&X`0P -MD^4``%/A"@``&B@[EN4!((/B*"N&Y0\`4^-!```:!@"@X0`0H./^___K`#"@ -MXR@[AN4[``#J!C"@X6`5`>,!(*/G!`"#Y0`PH.,H.X;E-```Z@8`H.'^___K -M``!0XS````K^3H;B"$"$XDY=AN(H4(7B`)"@XQ9^H.-6CZ#C`#"4Y0$`4^,C -M```:!!`4Y0``4>,@```*!`"4Y=B@@>'7(('A"B"2X`LPH^#P(`0@>+_+P_C_O__ZP8``.H(D(3E!R"1YP@PD><#,(+@ -M:"&1Y0(P@^`$,(3E($"$X@4`5.'5__\:'-"-XO"/O>CP02WI"-!-X@!`H.$` -M,*#C`#"-Y2PZ`^,#,)#G!0!3XPX``!I]*@/C`B#0YP``4N/0*9#E`B"`$#HL -M@A(X(((2!!#2%0%0H!."(((``B&``'XN@@($$-(%"%"2!0D``.H``%/C`0`` -M"@$`4^-2```:T"F4Y8(@@N`"(83@?BZ"X@00TN4(4)+E``!1XTH```K0.93E -M``!3XP0``!H$`*#A`""@XP(PH.'^___K`0``Z@0`H.'^___K`0!5XR\``!HL -M.@/C`S"4YP,`4^,!```*!0!3XP8``!H$`*#A_O__ZP0`H.'^___K!`"@X?[_ -M_^LB``#JG6Z$X@A@AN(`<*#C`8"@XP`PEN4``%/C#```"H=1A^`%4:#AG5Z% -MX@A0A>(%4(3@!`"@X040H.$((*#A_O__ZP0`H.$%$*#A"""@X?[__^L!<(?B -M)&"&X@D`5^/K__\:U#F4Y0$`4^,'```:!`"@X0`0H.,!(*#C_O__ZP0`H.$` -M$*#C`2"@X_[__^L`,`#C`#!`XP`PD^4,)`'CLB"4X600H..1`@'@TRT$XV(@ -M0>.2`8'@3@V$XB0`@.(A$X/@_O__ZXL``.H#`%/C`0``"@4`4^,K```:?3H# -MXP,PU.<"`%/C)P``B@0`H.'I/:#C`Q#4YP`@H.,",*#A_O__ZRPZ`^,#,)3G -M!`!3XP0@H!,L.@,3`R"$%P`PH./(.83E"""-XO\PH.,(,"+E!`"@X2X0H.,- -M(*#A9#L#XP_@H.$#\)3G!`"@X?[__^L`,`#C`#!`XP`PD^5"*@/C`B#4YQ`7 -M`N.1`@'@TRT$XV(@0>.2`8'@W0V$XB0`@.(A$X/@_O__ZUL``.H$`*#AB#L# -MXP_@H.$#\)3G``!0XPX```H`,*#CS#F$Y0`PX./0.83E##0!XS(@H..S((3A -M`#``XP`P0.,`$)/E3@V$XB0`@.(%$('B_O__ZT8``.HL.@/C`S"4YP,`4^,! -M```*!0!3XP(``!H"(*#C+#H#XP,@A.<$,*#CR#F$Y2PZ`^,#,)3G"@!3XP@` -M`!I\.@/C`Q#4YP``4>,$```*!`"@X>`GU.7?-]3E_O__ZP0``.H$`*#AWA?4 -MY>`GU.7?-]3E_O__ZP@@C>(`,*#C`3!BY61;`^,$`*#A#!"@XP_@H.$%\)3G -M'!O4Y00`H.$#$`'B_O__ZP@@C>+_,*#C"#`BY00`H.$N$*#C#2"@X0_@H.$% -M\)3G!`"@X?[__^L$`*#A_O__ZP$`4.,"```:!`"@X0`0H./^___K!`"@X?[_ -M_^L,-`'C9`"@X[,`A.$`,*#CR#F$Y00`H.%1[/_K!`"@X4_L_^L$`*#A3>S_ -MZPC0C>+P@;WH\$(`0*#A`8"@X<@YD.4``%/C.```&CL0H.,`(*#C -M9#L#XP_@H.$#\)3G`3"@X\@YA.4`8*#CS&F$Y01PH.'0::?E"%"@X0APA^(& -MH*#A()"@XP@PE>4``%/C`*"'!0H```J&$8;@`1&@X0$`A.`!$(C@G0Z`X@P` -M@.(,$('B"2"@X?[__^L(,)7E`#"'Y0%@AN(D4(7B)'"'X@D`5N/K__\:`#"8 -MY=0YA.4$`*#A_O__ZP$`4.,/```:`C"@X\@YA.4$`*#A`1"@X_[__^L$`*#A -M`1"@X_[__^L`,`#C`#!`XP`0D^5.#83B)`"`X@40@>+^___K+P``ZL@YE.4! -M,$/B`0!3XRD``(H$`*#A_O__ZP0`H.$`$*#C`2"@X?[__^NH/`/C`S"4YP`` -M4^,"```:C`"?Y?<7`./^___K`#"3Y0``4^,"```:=`"?Y3D7`./^___K(3+3 -MY0$`4^,P,*`#'C"@$P`PC>5D6P/C!`"@X2X0H.,-(*#A#^"@X07PE.<$`*#A -M`!"@X_[__^L(((WB`3"@XP$P8N4$`*#A#!"@XP_@H.$%\)3G`S"@X\@YA.4$ -M`*#A_O__ZP``H.,(T(WB\(>]Z"0```#P1RWI1M]-X@!`H.$!H*#A`Y"@X0\@ -MS>4$,*#C%S'-Y0D@H.,6((`$*#C_R"@ -MX_[__^M3#83B(`"`XO[__^L`4%#BBP``"@0`H.$($(7B_O__ZVP`E>4`$*#C -M:""@X_[__^ML<)7E!V"@X0"`H.,H@.;E`8#&Y2P`A^(*$*#A!B"@X_[__^LR -M`(?B#1N$XA$0@>(&(*#C_O__ZS@`A^(*$*#A!B"@X_[__^L'(*#AOA/RX=PW -M`..S`)3A#Q`!X@`2@>&P$,+ALR"4X0$@@N*S((3AL##6X?PPP^/0,(/CL##& -MX05@H.$8,*#C%#"FY4``A^(!$*#C12^-X@,@@N(&,*#A_O__ZP$0H.-%+XWB -M`B""X@8PH.'^___K!!"@XQ$NC>(&,*#A_O__ZP$0H.-#+XWB`R""X@8PH.'^ -M___K$'"-X@$0H.,!($?B!C"@X?[__^M0,*#C$##-Y6\PH.,1,,WE93#@XQ(P -MS>4),*#C$S#-Y12`S>4!$*#CM1#'X0@`6>$H```*%X#-Y04@H.,8(,WE`L"@ -MX[G`Q^$W,.#C&S#-Y1PPS>4+,*#C'3#-Y1`0H..^$,?A51"@XR`0S>53$*#C -M(1#-Y000H.,B$,WE4>"@XR/@S>4D,,WE`>"@XR7@S>4FP,WE`\"@XR?`S>4H -M$,WE*2#-Y08@H.,J(,WE!R"@XRL@S>4((*#C+"#-Y0D@H.,M(,WE"B"@XRX@ -MS>4O,,WE(""@XPD``.H!,*#C%S#-Y04PH.,8,,WE`C"@X[DPQ^$W,.#C&S#- -MY1PPS>4-(*#C`&"-Y=T0H.,0,(WB_O__ZQ0PE>48,(7E!`"@X040H.'^___K -M1M^-XO"'O>CP3RWI2=]-X@!@H.$!H*#A!#"@XQ\QS>4),*#C'C'-Y5`_!N.: -M.4#C&#&-Y0-`H.,7053#8;B(`"`XO[_ -M_^L`@%#BS0``"@8`H.$($(CB_O__ZVP`F.4`$*#C:""@X_[__^ML4)CE!4"@ -MX0`@H.,H(.3E`2#$Y2P`A>(*$*#A!B"@X_[__^L-FX;B$9")XC(`A>()$*#A -M!B"@X_[__^LX`(7B"A"@X08@H./^___K!2"@X;X3\N'<-P#CLP"6X0\0`>(` -M$H'AL!#"X;,@EN$!((+BLR"&X;`PU.'\,,/CT#"#X[`PQ.$(<*#A&#"@XQ0P -MI^5``(7B`1"@XT(#((+B!S"@X?[__^L!$*#C1R^-X@(@@N(',*#A_O__ -MZP00H.-&+XWB!S"@X?[__^L!$*#C12^-X@,@@N(',*#A_O__ZQA`C>(!$*#C -M`2!$X@5E,.#C&C#-Y0D0H.,; -M$,WE!0"@XQP`S>4"X*#CM>#$X340P*#COL#$X57`H.,HP,WE4\"@XRG`S>4$P*#C*L#- -MY5%0H.,K4,WE+##-Y2T@S>4NX,WE`R"@XR\@S>4PP,WE,0#-Y08@H.,R(,WE -M!R"@XS,@S>4((*#C-"#-Y340S>4*(*#C-B#-Y34/,*#C.##-Y6=8`^,% -M,-;G!C"#XK$RQ.$C`(3B"A"@X08@H./^___K*0"$XN$=AN('$('B!2#6Y_[_ -M_^L%4-;G*5"%XG50[^;XK@_C_Z]/XQ+.C>(%,(S@#2"@XPH@P^/*#CM3"$X0)0A>)U4._F`#`%X_(T0.,% -M,(3G!%"%XG50[^8!S*#CM<"$X0)0A>)U4._F$BZ-X@4P@N`*H(/@`#"@XP`P -MRN4!4(7B=5#OYA`Q`>.U,(3A`E"%XG50[^8+(-;GLC^_YK4PA.$"4(7B=5#O -MY@4`A.#I'8;B&A"!XO[__^L+,-;G`U"%X`!PC>4,`)WEW1"@XW4@[^8$,*#A -M_O__ZQ0PF.48,(CE!@"@X0@0H.'^___K2=^-XO"/O>CP3RWI1=]-X@!`H.$! -M4*#A`K"@X00PH.,/,50/P;CFCE`XP@QC>4",*#C!S'-Y0@` -MC>(`$*#C_R"@X_[__^M3#83B(`"`XO[__^L`8%#BJ0``"@0`H.$($(;B_O__ -MZVP`EN4`$*#C:""@X_[__^ML@);E"'"@X0"@H.,HH.?E`:#'Y2P`B.(%$*#A -M!B"@X_[__^L-6X3B$5"%XC(`B.(%$*#A!B"@X_[__^LX`(CB!1"@X08@H./^ -M___K"""@X;X3\N'<-P#CLP"4X0\0`>(`$H'AL!#"X;,@E.$!((+BLR"$X;`P -MU^'\,,/CT#"#X[`PQ^$&4*#A&#"@XQ0PI>5``(CB`1"@XT,OC>(#((+B!3"@ -MX?[__^L!$*#C0R^-X@(@@N(%,*#A_O__ZP00H.-"+XWB!3"@X?[__^L!$*#C -M02^-X@,@@N(%,*#A_O__ZP$0H./J+83B!3"@X?[__^L`D*#A4#"@XP@PS>5O -M,*#C"3#-Y64PX.,*,,WE"3"@XPLPS>4,H,WE"'"-X@$0H..U$,?A#[#-Y0(P -MH.,0,,WEN3#'X2`PH.,3,,WE%*#-Y1$PH.,5,,WE!3"@X[XPQ^%5,*#C&##- -MY5,PH.,9,,WE!#"@XQHPS>51,*#C&S#-Y20Z`^,#,)3G`@!3XWPZ`P-!.@,3 -M`S#4YQPPS>4+,*#C'3#-Y51,*#C(S#-Y20@S>4E`(WBZQV$X@L0@>+^___K""#4YQT@ -M@N)R(._F)#H#XP,PE.<#`%/C&P``&A$>C>(",('@#Q"@XP@10^4!((+B('`(K@.AR$XC`0@>(&(*#C -M_O__ZP9PA^)W<._F!P"*X.H=A.(!$('B""#4Y_[__^L((-3G`G"'X'<@[^8` -M4(WE"0"@X=T0H.,(,(WB_O__ZQ0PEN48,(;E!`"@X080H.'^___K1=^-XO"/ -MO>CP3RWIA]]-X@!`H.$!<*#A!#"@XQ4),*#C%C+-Y5`_!N.:.4#C$#*- -MY0!0H.,/4LWE_V"@XQ$.C>(%$*#A!B"@X?[__^L0`(WB!1"@X08@H.'^___K -M4PV$XB``@.+^___K`(!0XBL!``H$`*#A"!"(XO[__^ML`)CE!1"@X6@@H./^ -M___K;&"8Y090H.$`,*#C*##EY0$PQ>4L`(;B!Q"@X08@H./^___K#:N$XA&@ -MBN(R`(;B"A"@X08@H./^___K.`"&X@H0H.$&(*#C_O__ZP8@H.&^$_+AW#<` -MX[,`E.$/$`'B`!*!X;`0PN&S()3A`2""XK,@A.&P,-7A_###X]`P@^.P,,7A -M"'"@X1@PH.,4,*?E0`"&X@$0H..%+XWB`R""X@(" -M((+B!S"@X?[__^L$$*#C(2Z-X@(#((+B!S"@X?[_ -M_^L!$*#CZCV@XP,0Q.<#((3@!S"@X?[__^N&/XWB`"`%X_(D0.,((2/E$"H$ -MX[0@P^$!'*#CMA##X1`@H.,8(7= -M$*#C#R"@XQ$^C>+^___K#`"-Y5`PH.,0,,WE;S"@XQ$PS>5E,.#C$C#-Y0D0 -MH.,3$,WE`C"@XQ0PS>404(WBM3#%X2`@H.,7(,WE`""@XQ@@S>4$8*#C&6#- -MY0$@H..Z(,7A4BH#XP(@U.>"(*#A`2""XQP@S>4%`*#C'0#-Y;XPQ>$W,.#C -M(##-Y2$PS>4&(*#C(B#-Y;,!Q>%5D*#C)9#-Y5.PH.,FL,WE)V#-Y5'@H.,H -MX,WEZ3V@XP,PU.6[8<7A`##@X[TQQ>&_,<7A,1#-Y;(B -MQ>$D`(7B"A"@X?[__^L+,*#C.C#-Y>(WU.4%((/BNR+%X3V0S>4^L,WE/V#- -MY5$0H.-`$,WE03#-Y0``4^,R(*`#$@``"@`PH.,R(*#C^`T/X_\/3^-^SJ#C -MAN^-X@(0CN"#X(/@#N&$X`S@CN`$X-[E`.#!YP$@@N)R(._F`3"#XG,P[^;B -M%]3E`P!1X?'__XKX;0_C_V]/XX8?C>(",('@#1"@XP80P^$"((+B40D(WB`@")X`H0H.$&(*#C_O__ -MZP@@G>4&H(+B>J#OYL@Z`^.S,)3ALS^_YKHPA>$"H(KB>J#OYAX\H..Z,(7A -M`J"*XGJ@[^8`,`7C\C1`XPHPB><$H(KB>J#OY@'LH..ZX(7A`J"*XGJ@[^:& -M'XWB"C"!X`8P@^``(*#C`"##Y0&@BN)ZH._F$#$!X[HPA>$"H(KB>J#OY@L@ -MU.>R/[_FNC"%X0*@BN)ZH._F"@")X.D=A.(:$('B_O__ZPL@U.<"((K@(",([@$1"@XP80P^7=$*#CD`4*#A?$"1Y71@D>4-"X#B$0"`X@00A.(&(*#C -M_O__ZP``4.,F```*!#"@X1@@\^5_`%+C(@``&@$0D^4Q'[_F"2H)XV\@1>," -M`%'A'```&J@L`^,"()7G``!2XP(``!ID`)_E]Q<`X_[__^L`()+E``!2XP(` -M`!I,`)_E.1<`X_[__^LA(M+E``!2XP0```H%`*#A!!"@X08@H.'^___K!P`` -MZ@4PT^4!`%/C!```&MT-A>(@`(#B!!"@X08@H.'^___K`0"@XW"`O>@D```` -M\$\MZ47?3>(`0*#A`8"@X600H.,!+(WBOA#"X0`0H..\$,+A#`"-XO\@H./^ -M___K+#<#X[,`E.'^___K"P#-Y5,-A.(@`(#B_O__ZP!@4.(#`0`*!`"@X0@0 -MAN+^___K;`"6Y0`0H.-H(*#C_O__ZVQPEN4'4*#A#:N$XA&@BN(`D*#C*)#E -MY0&0Q>4L`(?B"!"@X08@H./^___K,@"'X@H0H.$&(*#C_O__ZS@`A^(*$*#A -M!B"@X_[__^L'(*#AOA/RX=PW`..S`)3A#Q`!X@`2@>&P$,+ALR"4X0$@@N*S -M((3A`##5Y0$@U>4"-(/A_###XP,XH.$C.*#A4#"#XP`PQ>4C-*#A`3#%Y1@P -MH..R,<;A(#"@XQ0PAN5(`(?B0Q^-X@(0@>("(*#C_O__ZQ0PEN4",(/B%#"& -MY0$*\,-'A0CZ#XQ$>C>*T,&'A2@"'X@(@H./^___K%#"6Y0(P@^(&@*#A -M%#"HY>E=A.(`@(WE3`"'X@D0H.$'(*#C"S"%XO[__^L`@(WE`1"@XP@@H.,# -M,(7B_O__ZZ@\`^,#,)3G"0!3X0(``!JX`I_E]Q<`X_[__^L`,)/E``!3XP(` -M`!J@`I_E.1<`X_[__^LA,M/E``!3XPH```H+,-WE``!3XP<```H`@(WE`Q"@ -MXP$@H.,,,(WB`3!#XO[__^L`<*#A!0``Z@"`C>4#$*#C`2"@X^D]A.+^___K -M`'"@X:@\`^,#,)3G``!3XP(``!HT`I_E]Q<`X_[__^L`,)/E``!3XP(``!H< -M`I_E.1<`X_[__^LA,M/E``!3XQ8```J(%Y3E``!1XW@```JH-Y3E``!3XW4` -M``H'`*#AF">4Y?[__^L4();EF#>4Y0,P@N`4,(;EF`>4Y0``A^"H%Y3EO">4 -MY?[__^L4();EO#>4Y0,P@N`4,(;E9```ZA%>C>(`L`7C\K1`XP2Q)>40.@3C -MM##%X0&40-`3CN3#%X;N0Q>$!,*#C&3#-Y1`K`^.^ -M(,7AL)'%X1XPS>40-P3CLS'%X0$JH..U(<7A%P"%X@H0H.$&(*#C_O__ZQ`Q -M`N.W,L7A!SR@X[DRQ>$K`(7B`!``XP`00.,'(*#C_O__ZQ`S`N.R,\7A!JR@ -MX[2CQ>$V`(7B`!``XP`00.,&(*#C_O__ZQ`T`N.\,\7AOI/%X3$PH.-,,,WE -M$#($X[$TQ>&SI,7A10"%X@`0`.,`$$#C!B"@X_[__^L0-`7CNS3%X0(;H..] -M%,7A'BR@X[\DQ>%1L(7EM97%X1`Q`>.W-<7A>JH#XPH@U.>R/[_FN37%X5L` -MA>+I'83B&A"!XO[__^L*(-3G6S""XH$>H..S$(7A73""X@($`@(WE!P"@X=T0H.-A((+B!3"@X?[__^L`$*#A -MW0V$XB``@.+^___K%#"6Y0`P@^`4,(;E%#"6Y1@PAN4$`*#A!A"@X?[__^M% -MWXWB\(^]Z"0````00"WI_O__ZP$`H.,0@+WH\$(`0*#A`8"@X0*@ -MH.$#D*#A!#"@XW4),*#C=C#-Y0$PH.-U,,WE4#\&XYHY0.-P,(WE!S"@ -MXV\PS>4(`(WB`!"@XV0@H./^___K4PV$XB``@.+^___K`%!0XF8```H$`*#A -M"!"%XO[__^ML`)7E`!"@XV@@H./^___K;'"5Y0=@H.$`,*#C*##FY0$PQN4L -M`(?B"!"@X08@H./^___K,@"'X@T;A.(1$('B!B"@X_[__^LX`(?B"!"@X08@ -MH./^___K!R"@X;X3\N'<-P#CLP"4X0\0`>(`$H'AL!#"X;,@E.$!((+BLR"$ -MX;`PUN'\,,/CT#"#X[`PQN$%8*#A&#"@XQ0PIN5``(?B`1"@XW<@C>(&,*#A -M_O__ZP$0H.-V((WB!C"@X?[__^L$$*#C<""-X@8PH.'^___K`1"@XV\@C>(& -M,*#A_O__ZP$0H.-U((WB!C"@X?[__^L`<*#AF#"=Y0`PC>7=#83B(`"`X@<0 -MH.$*(*#A"3"@X?[__^L4,)7E`#"#X!0PA>5X,(WB`"`%X_(D0.-P("/E$"H$ -MX[0@P^$!+*#CMB##X1`@H.,0(,WE@2Z@X[D@P^$"+*#CNR##X0XKH..R()3A -MLB^_YKT@P^$`8(WE``"'X-T0H.,/(*#C_O__ZQ0PE>48,(7E!`"@X040H.'^ -M___K>-"-XO"'O>@P0"WI#-!-X@!`H.$!4*#A?!"1Y2PZ`^,#,)#G!@!3XRH` -M`!HX.`/C`S#0YP$`4^-````:#@N`XC(`@.(*$('B!B"@X_[__^L``%#C.0`` -M"B0Z`^,#,)3G`@!3XPP``!H`(*#C.#@#XP,@Q.<.*X3B"#@#XP,PU.CP3RWIC=]-X@!`H.$!8*#A`K"@X0PPC>58 -M$MWE%!"-Y00PH.,O,LWE"3"@XRXRS>50/P;CFCE`XR@RC>4!,*#C)S+-Y?]0 -MH.-*#XWB`!"@XP4@H.'^___K*`"-X@`0H.,%(*#A_O__ZP`PH.,D,(WE\BT/ -MX_\O3^,C[HWBLC".X1PPC>53#83B(`"`XO[__^L`<%#B>@$`"@0`H.$($(?B -M_O__ZVP`E^4`$*#C:""@X_[__^ML@)?E"%"@X0"0H.,HD.7E`9#%Y2P`B.(& -M$*#A!B"@X_[__^L-JX3B$:"*XC(`B.(*$*#A!B"@X_[__^LX`(CB"A"@X08@ -MH./^___K"""@X;X3\N'<-P#CLP"4X0\0`>(`$H'AL!#"X;,@E.$!((+BLR"$ -MX;`PU>'\,,/CT#"#X[`PQ>$'8*#A&#"@XQ0PIN5``(CB`1"@XXLOC>(#((+B -M!C"@X?[__^L!$*#CBR^-X@(@@N(&,*#A_O__ZP00H..*+XWB!C"@X?[__^L! -M$*#CB2^-X@,@@N(&,*#A_O__ZP<@V^7J/:#C`R#$YP$0H.,#((3@!C"@X?[_ -M_^L0`(WE2H^-XB10C>((`(OB#""=Y0@00N(((*#A!3"@X?[__^L<,(WB`#"- -MY0@`H.$D$)WE$B`!XP(P1>+^___K\ET/X_]?3^,C[HWBM3">X;,_O^:U,([A -M"`"@X0D0H.'_(*#C_O__ZP`P!>/R-$#C`#"(Y00PH.,0*@3CLR"(X0(P@^(D -M,(WE`1R@X[,0B.$D,)WE(^Z-X@,@CN`0$*#C!A%"Y0,P@^(D,(WE$"(!X[,@ -MB.$D,)WE`C"#XB0PC>4"'*#CLQ"(X20PG>4",(/B)#"-Y;4@GN$!`%+C!2R@ -M`[,@B`$$```*!0!2XP'LH`.SX(@!`1N@$[,0B!$D,)WE`C"#XB0PC>7A783B -M`E"%X@4`H.$`$`#C`!!`XP,@H./^___K``!0XQ,```KR/0_C_S]/XR,NC>*S -M,)+A`0!3XP4``!H%`*#A`!``XP`00.,#(*#C_O__ZP<``.H%`%/C!0"@X0`0 -M``,`$$`#`!``$P`00!,#(*#C_O__ZP!@C>40`)WEW1"@XR0@G>5*/XWB_O__ -MZQ``C>50,*#C*##-Y6\PH.,I,,WE93#@XRHPS>4),*#C*S#-Y0`PH.,L,,WE -M*%"-X@$PH..U,,7A%."=Y2_@S>4",*#C,##-Y;DPQ>$D.@/C`S"4YP(`4^,` -M,*`#(#"@$S,PS>4`,*#C-##-Y00PH.,U,,WE`1"@X[X0Q>%9.@/C`S#4YP$` -M$^-2.@/C`S#4YX,PH.$!,(,#.##-Y04PH.,Y,,WE`B"@X[(AQ>$W(.#C/"#- -MY3T@S>41(*#C/B#-Y;%5@*#C08#-Y5.0H.-"D,WE!+"@XT.PS>51X*#C -M1.#-Y4$Z`^,#,-3G13#-Y0DPH.-&,,WE!B"@X[\AQ>$H`(WB(0"`X@H0H.'^ -M___K"S"@XT\PS>7B-]3E!2"#XK@BQ>%2@,WE4Y#-Y52PS>51$*#C51#-Y58P -MS>4``%/C+R"@`Q(```H`,*#C+R"@X_@-#^/_#T_C?LZ@XR/NC>("$([@@^"# -MX`[AA.`,X([@!.#>Y0#@P>'Q__^* -M^(T/X_^/3^,C'HWB`C"!X`T0H.,($,/G`2""XG(@[^9ZN@/C"S#4YQ4P@^*R -M,(7A`B""XG(@[^8,((WE*)"-X@(`B>`*$*#A!B"@X_[__^L,,)WE!B"#XG(@ -M[^;(.@/CLS"4X;,_O^:R,(7A`B""XG(@[^8>[*#CLN"%X0(@@N)R(._F`#`% -MX_(T0.,",(GG!#""XG,P[^8!'*#CLQ"%X0(P@^)S,._F(^Z-X@,@CN`(@(+@ -M`""@XP`@R.4!@(/B>(#OYA`Q`>.X,(7A`H"(XGB`[^8+(-3GLC^_YK@PA>$" -M@(CB>(#OY@@`B>#I'83B&A"!XO[__^L+(-3G`H"(X'@@[^8D.@/C`S"4YP,` -M4^,;```:(QZ-X@(P@>`/$*#C"!)#Y0$P@N)S,._FH8H#XP@@U.<&((+BLR"% -MX0(P@^)S4._F**"-X@4`BN`Z'(3B,!"!X@8@H./^___K!E"%XG50[^8%`(K@ -MZAV$X@$0@>(((-3G_O__ZP@@U.<"((7@40`)WEW1"@XR@PC>+^ -M___K%#"7Y1@PA^4$`*#A!Q"@X?[__^N-WXWB\(^]Z/!'+>E(T$WB`%"@X7Q` -MD>5TH)'E`#"@XSPPS>4],,WE/C#-Y3\PS>5`,,WE03#-Y;ART>$J8-'E!("@ -MX0T+@.(1`(#B!!"$X@8@H./^___K``!0XT,!``H/8`;B!W*&X7=P_^:P,-3A -M`@L3XP0```HB-`'CLS"5X0<`4^$``*`#.0$`"B(T`>.S<(7A!&"@X1@P]N4$ -M`%/C,@$`&@$PUN4)`%/C+P$`&@(@EN4R+[_F"3H)XV\P1>,#`%+A*0$`&J@\ -M`^,#,)7G``!3XP(``!J#87B&`"`XO[__^LH.@/C`S"5YRPJ`^,"()7G`@!3X2PJ`Q,",(47+#H# -MXP,PE><)`%/C!```"B@J`^,"()7G`@!3X2@J`Q,",(47#IN%XCR0B>()`*#A -M/!"-X@8@H./^___K"D"(X@D`H.$$$*#A!B"@X_[__^L'`*#A!A"@X0H@H.'^ -M___K``"-Y04`H.$$$*#A!B"@X0HPH.'^___K`#``XP`P0.,`$)/EW@V%XA@` -M@.)]'X'B_O__ZP$`H./+``#J+#H#XP,PE><)`%/CQ@``&MY-A>(80(3B!`"@ -MX?[__^L'`*#A!A"@X0H@H.'^___K`""@X6`W`^,#`)7G"A"(XO[__^L!(*#C -MZCV@XP,@Q>=4,$/B`S"5YPL`4^.R```:U#*?Y0`0D^4$`*#A?1^!XO[__^L! -M`*#CK```Z@<`H.$&$*#A"B"@X?[__^L!`*#CI@``Z@@`AN(($$KB`""@XT0P -MC>+^___K``!0XYX```H,,(WB`""@XP0@@^0$((/D!""#Y`0@@^0$((/D!""# -MY`0@@^0$((/D!""#Y+`@P^$X((WE#$"-XC@PC>(`,(WE1!"=Y0\@H.,$,*#A -M_O__Z^D-A>(3`(#B!!"@X08@H./^___K+#H#XP,PE><,`%/C#""@$RPZ`Q,# -M((47Z4V%XA-`A.($`*#AX1V%XBD0@>+^___K!R#6Y>\Y`^,#(,7G`#!0X@$P -MH!,%`*#A!!"@X?[__^L!`*#C<```Z@`@H.,X(,WE-""-Y0@`AN(($$KB1#"- -MXO[__^L``%#C9@``"C0PC>(`,(WE1!"=Y0`@H.,X,(WB_O__ZS0PG>4!`%/C -M$P``&C@PW>4``%/C"```&B0Z`^,#,)7G`@!3XU8```H"(*#C)#H#XP,@A>=*``#J)#H#XP,P -ME><" -M`%/A*"H#$P(PA1#87B&`"`XGT?@>+^___K`0"@XQ4``.K>;87B&&"&X@8`H.'^___K+#H# -MXP,PE><'`%/C!R"@$RPZ`Q,#((47!P"@X000H.'^___K`#``XP`P0.,`$)/E -M!@"@X7T?@>+^___K`0"@XP```.H!`*#C2-"-XO"'O>@D`````````/!!+>D` -M4*#A?$"1Y01@H.$-"X#B$0"`X@00A.(&(*#C_O__ZP``4.-7```*'#N5Y0,@ -M`^(#`%+C`0``"@$)$^-1```*"G"&XEL-A>(X`(#B!Q"@X?[__^L``%#C2@`` -M"A@P].4#`%/C1P``&M`[U>4``%/C1```"@$PU.4!`%/C%@``"@(``#H"`%/C -M/@``&B<``.J];H7B#6"&X@8`H.$"$(3B!R"@X_[__^L%`*#A!A"@X0<@H.'^ -M___KVSO5Y0$`4^,%`*#A!Q"@X0$@H.,`,*`#)3"@$_[__^LJ``#J!3#4Y5,1 -MXN<$(-3E`S#4Y0(TD^$)```:`3"@XQ,QH.%S,._FFR;0Y0(@@^&;)L#EG";0 -MY0,PPN&<-L#E&@``ZILVT.4!(*#C$A'#X9L6P.45``#J`S#TY0@`$^,*```: -M(S*@X0$@H..;%M#E$C/!X9LVP.4`$-3E(1*@X9PVT.42(/H/B`""@XP@@P^4`(.#CNB##X0$`H./P@;WH\$$MZ0!` -MH.%\4)'E!7"@X1!@A>+"#H#B#`"`XO[__^L`$*#A!@"@X08@H./^___K``!0 -MXRP```JX(=7A;#"4Y1``$^,C```*6PV$XC@`@.(*$(7B_O__ZP!@4.(B```* -M_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B!""#Y6M>AN((4(7B!0"@X?[__^L` -M`%#C"```&KPVEN6X)I;E!#""Y0`@@^6X5H;EO%:&Y00`H.$&$*#A_O__ZPT@ -MH.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^L$``#J!`"@X080H.'^___K`#"@ -MXQ@UQ.4!`*#C\(&]Z/!!+>D`0*#A?%"1Y05PH.$08(7BP@Z`X@P`@.+^___K -M`!"@X08`H.$&(*#C_O__ZP``4.,L```*N"'5X6PPE.40`!/C(P``"EL-A.(X -M`(#B"A"%XO[__^L`8%#B(@``"O[__^L-(*#A?SW"XS\PP^,$()/E`2""X@0@ -M@^5K7H;B"%"%X@4`H.'^___K``!0XP@``!J\-I;EN":6Y00P@N4`((/EN%:& -MY;Q6AN4$`*#A!A"@X?[__^L-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K -M!```Z@0`H.$&$*#A_O__ZP`PH.,8-<3E`0"@X_"!O>CX3RWI`%"@X7Q`D>5T -M@)'E#0N`XA$`@.($8*#AL##4X0$,$^,"(*`3`""@`],TX.<#,(+A`0!3XP00 -MA`(!```*$!"$(@00A#(&(*#C_O__ZP``4.-/```*'#N5Y0D+$^-,```*`0D3 -MXTH``!I/#87B&`"`XO[__^NZ,=;A``!3XP`PH!,<.X45`Z#@$SX``!JX,=;A -MR"L`X[(PA>$!"Q/C"3"@$Q0PH`/+.\7EO*'6X0JIH.$JJ:#AQ#L`X[.@A>$> -M`%CC*```FAY@H./,D)_E!K"@XP9PA.``,-?E+0!3XQ$```H"``"**@!3XQD` -M`!H5``#J/0!3XP\```K=`%/C%```&@(`A^()$*#A"R"@X?[__^L``%#C#@`` -M"@4`H.$'$*#A_O__ZPH``.H%`*#A!Q"@X?[__^L&``#J!0"@X0<0H.'^___K -M`@``Z@4`H.$'$*#A_O__ZP$PU^4",(/B`V"&X`8`6.'9__^*'#N5Y0(ZP^,! -M.8/C'#N%Y04`H.$R'87B#!"!XG+8_^L%`*#A"A"@X?[__^L!`*#C^(^]Z``% -M``#P3RWI'-!-X@!`H.%\8)'E=)"1Y1P[D.4#,`/B`P!3XP``H!/$```:!B"@ -MX<@X`>,#@)3GNC'6X00PC>6XH=;A`@!8XP8``!K,.`'C`S"4YP$`4^.]```* -M!0!3X[L```H`@*#C`;!XX@"PH#,``%KC`#"@`P$P"Q(``%/CL```&@$P>N(` -M,*`S##"-Y0$`6.,``%H#J@``"EM=A.(X4(7B"B""X@@@C>4%`*#A`A"@X?[_ -M_^L`<%#B"@``&@4`H.$($)WE_O__ZP!P4.(18*`#E```"@$\H./0,(?E`#"@ -MX\PVA^49``#J_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B!""#Y6M>A^((4(7B -M!0"@X?[__^L``%#C!0``&KPVE^6X)I?E!#""Y0`@@^6X5H?EO%:'Y0T@H.%_ -M/<+C/S##XP0@D^4!($+B!""#Y?[__^O^___K#2"@X7\]PN,_,,/C!""3Y0$@ -M@N($((/E&UV'X@4`H.'^___K``!0XP,```H%`*#A!AN$XB@0@>+^___K#2"@ -MX7\]PN,_,,/C!""3Y0$@0N($((/E_O__Z\PVE^4``%/C,#@!`P,PE`?(-H<% -M!%"=Y,#,)3GR#:'Y="F -MA^4C``#J`0!5XP<``!K0,)?E`3S#XP(\@^/0,(?ET*:'Y0(PH./,-H?E&0`` -MZ@,`5>,C```:(@"&XA`0H.,4((WB(C!)XO[__^L``%#C'@``"A0PG>4``%/C -M&P``"FT>A^("`(#B!!"!XH`@H./^___K``!0XQ0```K0,)?E`CS#XP$[@^/0 -M,(?E-#@!XP,PE.?(-H?E`5"%XLQ6A^4$`*#A!Q"@X0`@H./^___KT#"7Y0$+ -M$^,`,*`3S#:'%0$`H.,6``#J#F"@XP```.H/8*#C``!7XPP```H`4`#C`%!` -MXPAPA>('`*#A`!"@XR$MH./^___K`C"@X]0VA>7H`(7B"!"=Y08@H./^___K -M!`"@X0<0H.$&(*#A_O__ZP``H.,N(` -M,*`S##"-Y0"PH.-,___J\$\MZ4'?3>(`0*#A`2"@X4`PC>+0&9_E`P"1Z`0` -M@^2P$,/A?%"2Y71@DN4`,*#C*#"-Y1P[E.4#,`/B`P!3XUH"`!JPH-7A_*`: -MX@2`H`,*@*`3&#"(X@,`5N%3`@`Z"I"%XEL-A.(X`(#B"1"@X?[__^L`<%#B -M.@(`"AD0U>48(-7ET#"7Y0$+$^,!.\,3`CJ#$]`PAQ4$```:`0D3XP$YPQ," -M.H,3T#"'%2T"``H8D$;B"9!HX!B`B.((@(7@`22"X50W`..S((?A"`"@X0D0 -MH.%(((WB`3"@X_[__^L!`'#C)0(`"D@PG>4``%/C(@(`"@R0C>4(`*#A`!"@ -MXSP@C>(),*#A_O__ZP"PH.$\,)WE``!3XQ@"``H"`(#BPQZ$X@P0@>(X+)3E -M_O__ZP``4.,!L*`#`0``"@&P>^(`L*`S.#R4Y3P@G>4#`%+A"@(`&@``6^,) -M`@`:"`"@X0$0H.,\((WB##"=Y?[__^L`$%#B`0(`"BP`C>("$('B/""=Y?[_ -M_^L!+(WBQ#`RY1`PC>4(`*#A,A"@XPPPG>7^___K`!!0X@L```H0,)WE$`!3 -MXP@``(HL`(WB`P"`X`(0@>(\()WE_O__ZSPPG>40()WE`R""X!`@C>40,)WE -M0#&'Y1,.A^(L$(WB$""=Y?[__^L`$*#C7!>'Y6`7A^5D%X?E:!>'Y6P7A^4' -M,*#ACY04P@^(0,(WE`P"@X2`@H./^___K!#H!XP,PE.<"`!/C(P``"J`@ -MG>4``%+C(```"@`PH.,@,(WE)#"-Y10@C>6D,-WE&#"-Y0(`0N("$(/B(""- -MXB0PC>+^___K`0!0X](!`!H!,*#C7#>'Y6`WE^4",(/C8#>'Y0PZ`>,#,)3G -M(""=Y0,P`N!H-X?E%"H!XP(0E.4@,(WEF""=Y10@ -MC>6<,-WE&#"-Y0(`0N("$(/B)""-XB`PC>+^___K`0!0XZL!`!H!,*#C7#>' -MY6`WE^4!,(/C8#>'Y0@Z`>,#,)3G)""=Y0,P`N!D-X?E$"H!XP(0E.<@()WE -M`2`"X&PGA^4``%/C*;"@`P``4N.6`0`*``!;XX8!`!I8-Y?E`SK#XU@WA^44 -M()WE``!2XQL``!JX()WE``!2XP$Z@Q,".H,#6#>'Y00Z`>,#,)3G``!3XR8` -M``I8-Y?E`PH3XR,```J`-Y3E``!3XR````H`(*#C`3R-XN`@8^4`((WE@`>4 -MY9`7E.5!(`'C_O__ZR`PW>4``%/C$;"@`V4!``H3``#J!"H!XP(@E.<``%+C -M*+"@`U\!``JX()WE``!2XP$Z@Q-8-X<5"0``&A@PG>4"((/B(`!2XR`@H",` -M`%+C`P``VA``G>44,)WE`A!#XO[__^M8-Y?E`CS#XU@WA^4`,*#CW#"'Y:`W -MQ^4!(*#CIB?'Y:4WQ^6D-\?EHS?'Y:(WQ^7,-)3E``!3XT\```H!+(WB`#"@ -MX\0P(N40((WE"`"@X11@C>484(WE'*"-Y0Q@G>4(H*#A!X"@X01PH.$"4*#A -MW1"@XP4@H.$&,*#A_O__ZP!`4.(V```*`@"$XD`0C>(&(*#C_O__ZP``4.,L -M```*#$"-Y11@G>484)WE!T"@X0APH.$*@*#A'*"=Y5@WE^4"/(/C6#>'Y0$P -MH./<,(?E#""=Y0@PTN6@-\?ETR+AYZ$GQ^4/,`/B#P!3XP$PH!,`,*`#IC?' -MY:`WU^4/`!/C'0``"@$`$^,#,*`3`#"@`Z4WQ^6@-]?E`@`3XP,PH!,`,*`# -MI#?'Y:`WU^4$`!/C`S"@$P`PH`.B-\?EH#?7Y0@`$^,#,*`3`#"@`Z,WQ^4) -M``#J/`"=Y0(`@.(``(3@PO__ZA1@G>484)WE!T"@X0APH.$*@*#A'*"=Y6D^ -MA^(-,(/B##"-Y0,`H.$`$*#C&B"@X_[__^OH,)WE``!3XPH```KL,-WE&0!3 -MXP<``)I8-Y?E"CR#XU@WA^4,`)WEZ!"=Y1H@H./^___K`@``ZE@WE^4".\/C -M6#>'Y=@TE.4``%/C`@``&E@WE^4""Q/CT@``&EC'E^4"P8SC6,>'Y4`!E^4` -M`%#C$0``"C`QU^5_,`/B%@!3XP<@H-$`,*#3"```V@0``.HQ$=+E?Q`!X@$@ -M@N(6`%'C`@``V@+!S.-8QX?E`@``Z@$P@^(``%/A]/__&E0W`..S,)?A(``3 -MXU@WE^6`,(,3@###`U@WA^4`,*#CK#?'Y20Z`^,#,)3G`P!3XQ0``!H(`*#A -M"1"@X0`@H.,H,(WB_O__ZP``4.,-```*`3"@XZPWQ^7=#83B(`"`X@40H.$& -M(*#A!S"@X?[__^MP`._F``!0XZT'QQ4*L*`3F@``&@```.H``*#CK0?'Y=0P -ME^4``%/C&0``&@$P@^+4,(?E/#@!XP,PE.<``%/C`3"#`I\``!H'``#J`!"2 -MY0``4>,$```*`3"#XM0PA^4$((+B(0!3X_?__QIC+:#CLB"4X0,`4N$`,*`S -MU#"'-1&PH#-]```Z!CR#X@,QA.`X<(/ET#"7Y0(ZP^,!.8/CT#"'Y?[__^L- -M(*#A?SW"XS\PP^,$()/E`2""X@0@@^4;C8?B"`"@X?[__^L``%#C!0``&L0V -ME^7`)I?E!#""Y0`@@^7`AH?EQ(:'Y0TPH.%_C@JL*#C[___ZBBPH./M -M___J`C"@X]0PA^5A+83B7/__ZE@WE^4#.L/C6#>'Y63^_^J0$@``^$\MZ0!` -MH.%\8)'E='"1Y<@YD.4#`%/C`0``&O[__^MU``#J!E"@X<(.@.(,`(#B_O__ -MZP`0H.$0`(;B!B"@X_[__^L``%#C:P``"GV.A.(<*Y3E`0P2XPH```H8`(;B -M&!!'XO[__^O*"\3E"`"@X080H.$'(*#A_O__ZP0`H.'^___K7```ZEL-A.(X -M`(#B'!N4Y0,P!.,`,$#C`S`!X`(0!.,!`%/A'```&@H0AN+^___K`#!0XD\` -M``H6+J#CTJ"#X58OH./2`(/A`(":X`&0J^!:+Z#CT@"#X0"@F.`!L*G@#X"@ -MXP"0H.,(``K@"1`+X`$@D.$#```:!`"@X080H.$'(*#A_O__ZP0`H.$8$(;B -M&"!'XO[__^LV``#J`R`"X@$`4N,S```:"J"&X@H0H.'^___K`#!0XA0```H6 -M+J#CTJ"#X58OH./2`(/A`(":X`&0J^!:+Z#CT@"#X0"@F.`!L*G@#X"@XP"0 -MH.,(``K@"1`+X`$@D.$>```:!`"@X080H.$'(*#A_O__ZQD``.H$`*#A_O__ -MZP!0H.$@`%#C%```"@0`H.$D$(;B)"!'X@4PH.'^___K``!0XP4``!I],(7B -M@S*$X`@P@^(`(*#C`""#Y0<``.H(`*#A!A"@X0<@H.'^___K!`"@X0H0H.$% -M(*#A_O__ZP$`H./XC[WH\$`MZ0S03>(`0*#A?%"1Y71PD>4L.@/C`S"0YP`` -M4^,I```*`0!3XR<```HD*@/C`B"0YP(`4N,C```*!0!3XR$```H#`%/C'P`` -M"E8PT>4#`%/C'```FMT-@.(@`(#B!1"@X0<@H.'^___K<&#OY@$`5N,5```: -M)#H#XP,PE.$!#!+C`C"@$P`PH`/2).#G`C"#X0$`4^,0 -M$(4"!```"@H0A3("```Z`@!3XQ@0A1(*$(4"!`"@X?[__^LQ``#J`&"@XVPP -ME.4(`!/C+0``&@$`$^,!```:4``3XRD```H8`(7B`!"@XP0@C>(8,$?B_O__ -MZP``4.,B```*`0!6XPD```H$,)WE``!3XP8```H"`(#BPQZ$X@P0@>(X+)3E -M_O__ZP``4.,6```*;#"4Y0$`$^,3```*V#"4Y0$`4^,0```:L"#5X0$,$N," -M,*`3`#"@`](DX.<",(/A`0!3XQ`0A0($```*"A"%,@(``#H"`%/C&!"%$@H0 -MA0($`*#A!B"@X?[__^L!`*#C#-"-XO"`O>CP0"WI#-!-X@!@H.$!0*#A#3"@ -MX3@AG^4#`)+H!`"#Y+`0P^%\4)3E!7"@X;`PU>$,`!/C1```&@10A>(%`*#A -M#1N&XA$0@>(&(*#C_O__ZP``4.,%```:!0"@X0T0H.$&(*#C_O__ZP``4.,V -M```*L##7X?PP`^)#$J#A#0!1XS$``,J!$('@R""?Y0$1@N!``%/C%P``"@0` -M`,H``%/C$```"B``4^,>```:#0``ZK``4^,$```*T`!3XQ4```J``%/C%P`` -M&@X``.IL,);E$``3XP`P`!,`,$`3`#```P`P0`,(,('E!@"@X00@H.$PU__K -M%```Z@8`H.$$(*#A+-?_ZQ```.H&`*#A!""@X2C7_^L,``#J!@"@X00@H.$D -MU__K"```Z@8`H.$$(*#A(-?_ZVPPEN40`!/C`@``"@8`H.$$$*#A_O__ZPS0 -MC>+P@+WHF!(```@%``#P0"WI)-!-X@!`H.'0!X3E$,"-XE@QG^4/`)/H!P"L -MZ``PS.4-,*#A`%"@XP10@^0$4(/D!%"#Y`!0P^4!8*#C`6#-Y0)PH.,"<,WE -M`S"@XP,PS>4`,.#C!##-Y7T.A.((`(#B!1"@X?[__^O<-P#CLU"$X6$[`N,# -M,-3GWC?$Y=]7Q.7@5\3E$#0!XP-0A.=B.P+C`S#4Y^$WQ.6;#H3B"0"`XA`0 -MC>(-(*#C_O__ZYH.A.(,`(#B#1"@X0T@H./^___KR%F$Y=!9A.7,683E#C0! -MXP-0Q.<<6X3E(%N$Y21;A.4H6X3E+%N$Y3!;A.4\6X3E0%N$Y3A;A.4T6X3E -M+0V$X@0`@.(%$*#A@""@X_[__^L),*#CRSO$Y-D(*#CLR"$X=1GQ.4&`*#A)-"-XO"`O>B@$@````!1XQD``-H`,-#E?S`# -MX@0`4^,"`%,3$@``"@L`4^,0```*%@!3XP`@H!,)```:#```Z@(PT.=_,`/B -M!`!3XP(`4Q,'```*"P!3XP4```H6`%/C`P``"@$@@N(!`%+A\___&@$``.H! -M`*#C'O\OX0``H.,>_R_A``!1XPX``-H`,*#C`R#0YW\@`N("`%+C!`!2$P4` -M``H+`%+C`P``"A8`4N,!```*``"@XQ[_+^$!,(/B`0!3X?'__QH!`*#C'O\O -MX0$`0.)P`._F$P!0XP0`H(,`,`"3`#!`DP``TY<>_R_A<$`MZ0%`H.$"8*#A -MWC?0Y0X`4^,$``":T`O0Y0``4.,4`*`3!`"@`W"`O>C06]#E``!5XPA0H!,` -M4*`#`0"@X0(0H.'^___K`0!0XP$`A0-P@+T(!`"@X080H.'^___K`0!0XP,` -MA0,"`(43<("]Z'\``.(+`%#C``"@@P`P`),`,$"3``"#D!0`T)4>_R_A<$`M -MZ0!0H.$!8*#A`$"@XP0PA>"L"=/E`C"`XG,P[^8!`%/C!```FO[__^L&`%#A -M`0``&@$`H.-P@+WH`4"$X@T`5./Q__\:``"@XW"`O>CP1RWI`("@X0&@H.&; -M3H#B"4"$XB=M@.(&8(;B`'"@XW^0X.,``-3E_@!0XPL```K_`%#C#```"O[_ -M_^L`4*#A"`"@X040H.'^___K`0!0XPE0A0%U4.\&!U#*YP%PA^(!0(3B!@!4 -MX>W__QH'`*#A\(>]Z`3@+>4,T$WB"""-X@$PH.,!,&+E%A"@XV0[`^,/X*#A -M`_"0YPS0C>(`@+WH!.`MY0S03>((((WB`#"@XP$P8N46$*#C9#L#XP_@H.$# -M\)#G#-"-X@"`O>@$X"WE#-!-X@`PH.$$$(WE`0!2XQ<0H`,8$*`3!""-XF3+ -M`^,/X*#A#/"3YPS0C>(`@+WH!.`MY0S03>((((WB`1!BY0`0H.-D.P/C#^"@ -MX0/PD.<,T(WB`("]Z!!`+>E<.P/C`S"0YP``4^,0@+T(,_\OX1"`O>@00"WI -M6#L#XP,PD.<``%/C$("]"#/_+^$0@+WH<$`MZ0!`H.$#8*#A`E"@X0``4N,` -M`%,3`0``&O[__^L$``#J`0!2XP(0@0("$$$2<1#OYO[__^L$`*#A!A"@X04@ -MH.'^___K<("]Z`$`$.,#`*`3T`#@!Q[_+^$$`(#B'O\OX0``4.,``*`#'O\O -M`1PKD.4#,`3C`#!`XP,P`N`"``3C``!3X0``H!,!`*`#'O\OX1PKD.4#,`3C -M`#!`XP,P`N`!``3C``!3X0``H!,!`*`#'O\OX>@_D.4!`%/C"P``"@`@H.," -M,(#@`3J#X@@P@^(`,)/E`0!3XP0```H@((+B.@Y2X_;__QH!`*#C'O\OX0`` -MH.,>_R_A``&@X6\W`>,#`%#A<`_R_A!.`M -MY0S03>((((WB`1!BY1D0H.-D.P/C#^"@X0/PD.<,T(WB`("]Z!!`+>D:$*#C -M`""@XV0[`^,/X*#A`_"0YQ"`O>CP3RWI%-!-X@!PH.$$((WE`V"@X8&QH.$% -M4(OB!$"@XV2+`^,(H(WB&Y"@XP$``.H!0$3B`5!%X@$PE.("```*`0!3XQ\` -M`!H.``#J`"#6Y000G>4"*('A`1#6Y0$L@N$(((WE"["#X`RPC>4'`*#A&Q"@ -MXP@@C>)D.P/C#^"@X0/PE^4,4(WE!P"@X0D0H.$*(*#A#^"@X0CPE^<``%3CQ/__JA30C>+PC[WH!.`M -MY2303>(`(*#C&"#-Y1D@S>4:(,WE&R#-Y1P@S>4=(,WE"#"-X@0@@^0$((/D -M!""#Y``@@^4(,(WB`#"-Y1@PC>+^___K)-"-X@"`O>CH/Y#E``!3XP(@H`,% -M```*`3J`X@@P@^(#(*#C`!"3Y0``4>,'```:@C*`X`$0H..H'X/E^@Z#X@@` -M@.(`,*#C"#"`Y0,``.H!((+B(#"#XB``4N/P__\:`@"@X1[_+^'P3RWI#-!- -MX@!0H.'-.]#E``!3XU4UP`54```*`#"@XP7AA]#E`0!8XPJ`H`,0@*`3 -MODZ`X@9`A.*_;H#B!F"&XF2K`^,-D*#A';"@XP9PH.$`,-3E4V+@YP$@U.4/ -M$`+B(B*@X0(FH.$!)(+ALA#4X0$H@N$/$`/BRPO5Y9"!(>!Q$._F`2""X0`@ -MC>73,N'G`P!3XP/QGY$*#C#2"@X0_@H.$*\)7G!S#=Y09A@^$'8,WE!P``Z@4`H.$+ -M$*#A#2"@X0_@H.$*\)7G!S#=Y89A@^$'8,WE!$"$X@<`5.'%__\:>CL"XP,P -MU>+PC[WH\$`MZ0S03>(`0*#A``!1XST```K8-)#E``!3XSH```H!,*#C -MT3O`Y0$PT>4``%/C'```"K\N@.(&((+B`#"@XP(`4^,%```*`P"!X`+`T.4` -M`-+E```,X```PN4,``#J^,O4Y00`T>4#<`SB`V``X@8`5^$#8`S2'%`,XAS@ -M`.(.`%7A'``,PAP``-(&`(#A^`O$Y0$P@^(!((+B`0#1Y0,`4.'E__^*!`"@ -MX100H.,'((WB:#L#XP_@H.$#\)3GOTZ$X@E`A.(`,*#C`,``XP#`0.,```#C -M``!`XP<@W>4``%+C`P!2$P`0TP<,$-,7`"#4Y0(@`>``(,3E`3"#X@%`A.(0 -M`%/C\___&@S0C>+P@+WH,$`MZ0S03>(`0*#ATCO0Y0``4^,4```*T3O0Y0`` -M4^,1```*`3"@X]`[P.7X.]#E`R`#X@<@S>53,>+G"""-X@(P8N5D6P/C(A"@ -MXP_@H.$%\)3G!`"@X2,0H.,'((WB#^"@X07PE.4>_R_A`#"@XTTQP>5,,<'E'O\OX7\``.($`$#B:`!0XP#QGY=J``#J -M*&0!`-AC`0#88P$`V&,!`-AC`0#88P$`V&,!`"!D`0`09`$`V&,!`-AC`0#8 -M8P$`V&,!`-AC`0`(9`$`V&,!`-AC`0#88P$`&&0!`-AC`0``9`$`V&,!`-AC -M`0#88P$`V&,!`-AC`0#88P$`V&,!`-AC`0#88P$`V&,!`-AC`0#X8P$`V&,! -M`-AC`0#88P$`V&,!`-AC`0#88P$`V&,!`-AC`0#88P$`V&,!`-AC`0#P8P$` -MV&,!`-AC`0#88P$`V&,!`-AC`0#88P$`V&,!`-AC`0#88P$`V&,!`-AC`0#8 -M8P$`V&,!`-AC`0#88P$`V&,!`-AC`0#88P$`V&,!`-AC`0#88P$`V&,!`-AC -M`0#H8P$`V&,!`-AC`0#88P$`V&,!`-AC`0#88P$`V&,!`-AC`0#88P$`V&,! -M`-AC`0#88P$`V&,!`-AC`0#88P$`V&,!`-AC`0#88P$`V&,!`-AC`0#88P$` -MV&,!`-AC`0#@8P$`V&,!`-AC`0#88P$`V&,!`-AC`0#88P$`V&,!`-AC`0#8 -M8P$`V&,!`-AC`0#08P$`"P"@XQ[_+^$``*#C'O\OX0H`H.,>_R_A"0"@XQ[_ -M+^$(`*#C'O\OX0<`H.,>_R_A!@"@XQ[_+^$%`*#C'O\OX00`H.,>_R_A`P"@ -MXQ[_+^$"`*#C'O\OX0$`H.,>_R_A\$$MZ0!@H.$-`%'C`5"@,0U0H",``%7C -M`'"@`PH```H`<*#C!T"@X0&`H.,$`-;G@``0XP$```K^___K&'"'X0%`A.(% -M`%3A]___&@<`H.'P@;WH\$$MZ0!PH.$-`%'C`6"@,0U@H",``%;C`%"@`P@` -M``H`4*#C!4"@X0&`H.,$`-?G_O__ZQA0A>$!0(3B!@!4X?G__QH%`*#A\(&] -MZ`0@T.4#,-#E`S:@X0(*@^$>_R_AT#O0Y0``4^,,```*RCO0Y00`4^,)```* -MWS?0Y0$`$^,&,*`3!3"@`P`@T>4!`-'E``2"X5`#H.$!``#B'O\OX0``H.,> -M_R_A`@,0XQLPH!,#```:&C"@XP$@H.,2$Q#@`0``"G,`[^8>_R_A`3!#X@$` -M<^/X__\:``"@XQ[_+^$$(-#E`S#0Y0(D@^$""1+C#P"@$P8``!H.`*#C4C"@ -MX0$`$^,"```:`0!`X@$`<./Y__\:<`#OYA[_+^$00"WI?#L#XP_@H.$#\)#G -M$("]Z!!`+>G^___K$("]Z!!`+>G8$)'E_O__ZQ"`O>@00"WIRCO0Y00`4^,) -M```*"`!3XP(```H!`%/C$```&@L``.H!,*#CU#O`Y0`PH./5.\#E$("]Z``@ -MH./4*\#E`3"@X]4[P.4$$.#C_O__ZQ"`O>@$$.#C`""@X_[__^L0@+WH`#"@ -MX]0[P.4!,*#CU3O`Y1"`O>@P0"WI#-!-X@!`H.$!4*#A(``1XPP```K,.]#E -M`P!3XQ4```H(((WB`3"@XP$P8N4#,*#CS#O`Y1$0H.-D.P/C#^"@X0/PE.<+ -M``#JS#O0Y0$`4^,(```*"""-X@`PH.,!,&+E`3"@X\P[P.41$*#C9#L#XP_@ -MH.$#\)3G`@`5XQ0PH!/+.\05$@``&N$WU.4*`!/C"P``"@$+%>,$```*RSO4 -MY0D`4^,),*`3RSO$%0@``.K+.]3E%`!3XQ0PH!/+.\05`P``ZA0`$^,),*`3 -M%#"@`\L[Q.4$`*#A#Q"@XR\MA.(+((+B9#L#XP_@H.$#\)3G#-"-XC"`O>@> -M_R_A,``MZ1@0@>($,)'E`""@XTC,`./\((#A`!"1Y0%`@N$#4*#A_$"`X3`` -MO>@>_R_A$$`MZ0D0H.,`(*#C9#L#XP_@H.$#\)#G$("]Z!!`+>GN/:#C#^"@ -MX0/PD.<0@+WH<$`MZ0!`H.$!4*#A6PV`XC@`@.("$*#A_O__ZP``4.-P@+T( -M`2#5Y5(AX^>"(8+@@C&`X!X^@^(`(.#CNB##X=LKU.4!`%+C`""@$P$@H`,( -M(,/E<("]Z/!!+>D(T$WB`("@X0%0H.$#0*#A!&"-X@)PH.$!`*#A`1"@XP8@ -MH.$',*#A_O__ZP`04.(4```*A$*(X/M.A.($0(3B!`"@X0(0@>($()WE_O__ -MZP2`G>4%`*#A,A"@XP8@H.$',*#A_O__ZP`04.(!`*`#!```"@@`A.`"$('B -M!""=Y?[__^L!`*#C"-"-XO"!O>@00"WIX3?0Y0$`$^.!`H#@^PZ`X@0`@.(` -M$``3`!!`$P@0GP4$(*#C_O__ZQ"`O>C(!0``$$`MZ0$PH.$!(-'E`0!2XQ"` -MO8@!(*#CSBO`Y2\-@.(/`(#B`A"!X@$@T^7^___K$("]Z/!/+>D4T$WB`&"@ -MX0%PH.$`,(WE)(!2XD4```I;K8#B.*"*XL,>@.($$(WE`$"@XP&PH.,$D*#A -M`#``XP`P0.,,,(WE"$"-Y210A.(%4(?@`##5Y2H`4^,J```*/0!3XRX``!H` -M`%7C+```"@,PU>4$`!/C"2"@`0@PG04)```*`S`#X@$@0^("`%+C"2"@@0LP -MH($!,$.2#!"=E0,@@9`@,-*5)"#2E=\7UN4#`%'A`P``&N`7UN4"`%'AW)O& -M!18```K`GQN4*`*#A!!"=Y?[__^L``%#C#@``"H0VD.4``%/C -MWS?6%9@VP!7@-]85F3;`%9B6P`69EL`%!0``Z@8`H.$%$*#A_O__ZP8`H.$` -M$)WE_O__ZP$PU>4",(/B`T"$X`0`6.'$__^*%-"-XO"/O>@00"WI`#!1XA"` -MO0C8))#E``!2XQ"`O0@!(-/E%@!2XQ"`O8@!(*#CTBO`Y<$.@.(&`(#B`A"# -MX@$@T^7^___K$("]Z!!`+>G,-)#E``!3XP!`H`/-2\`%!`"@`1"`O0@!0*#C -MS4O`Y;X.@.($`(#B"!"!XA(@H./^___K!`"@X1"`O>CP0"WI#-!-X@!`H.$R -M78#B#%"%X@4`H.'^___KTCO4Y0``4^,#```*T3O4Y0``4^,!,*`3T#O$%=XW -MU.4.`%/C!```FM![U.4``%?C%'"@$P1PH`,0``#JT'O4Y0``5^,(<*`3`'"@ -M`P!@H.$%`*#A!A"@X?[__^L!`%#C`7"'`P4```H%`*#A!A"@X?[__^L!`%#C -M`W"'`P)PAQ-B.P+C`S#4YP-P!^#A=\3E`G!'XG=P[^8!`%?C"CH`DPX^`(.V -M,,WA!`"@X1`0H.,&((WB9#L#XP_@H.$#\)3G#-"-XO"`O>CP3RWI'-!-X@"@ -MH.$!@*#A#`!1XUX``)H,4*#C`'``XP!P0.,(L(?B!3"'X`0PC>40,(?B"#"- -MY120A^(8,(?B##"-Y1PPA^(0,(WE(#"'XA0PC>4%8(K@`##6Y=T`4^-!```: -M`D"&X@0`H.$+$*#A`R"@X_[__^L``%#C0```&@0`H.$$$)WE`R"@X_[__^L` -M`%#C.@``&@0`H.$($)WE`R"@X_[__^L``%#C-@``&@0`H.$)$*#A`R"@X_[_ -M_^L``%#C,```&@0`H.$)$*#A`R"@X_[__^L``%#C*@``&@0`H.$,$)WE`R"@ -MX_[__^L``%#C"`"@$R8``!H$`*#A$!"=Y0,@H./^___K``!0XP0`H!,?```: -M!`"@X100G>4#(*#C_O__ZP``4.,&`*`3&```&@0`H.$D$(?B`R"@X_[__^L` -M`%#C`0"@$Q$``!H$`*#A*!"'X@,@H./^___K``!0XPL`H!,*```:`3#6Y0(P -M@^(#4(7@!0!8X;3__XH#``#J!0"@XP(``.H#`*#C````Z@``H.,D,T$WB`'"@X<(.@.(,`(#B_O__ZQ``$.,P```*H#R7Y0P`4^,M``": -MRHZ'X@2`B.(,0*#C`)``XP"00.,$H*#C`+``XP"P0.,`,`#C`#!`XP0PC>4$ -M8(C@`##6Y3``4^,/```*W0!3XQ,``!H"4(;B!0"@X0L0H.$*(*#A_O__ZP`` -M4.,,```*#`"%X@00G>4*(*#A_O__ZP``4.,&```*#```Z@H`AN()$*#A"B"@ -MX?[__^L``%#C!@``&@$PUN4",(/B`T"$X*`\E^4$`%/AW___B@$``.H!`*#C -M````Z@``H.,,T(WB\(^]Z!!`+>D`0*#A&A"@XP`@H.-D.P/C#^"@X0/PD.?Z -M#H3B!`"`X@`0H.,!*Z#C_O__ZQ"`O>CP0"WI%-!-X@!0H.$!<*#A`F"@X0U` -MH.$-`*#A`!"@XPT@H./^___K!0"@X0T0H.'^___K`""@X0``AN4'`*#A#1"@ -MX?[__^L4T(WB\("]Z`3@+>4,T$WB>`"`XO[__^L`$*#A!@"-X@(@H./^___K -MM@#=X0S0C>(`@+WH<$`MZ0C03>(`0*#A#U`!XA@S`^,#,-#G!0!3X2(```K0 -M.P/C`S"0YP$`4^,#```*X3L#XP,PT.<``%/C`P``&@P@H.,9,P/C`R#$YQ8` -M`.K,.P/C`S"0YP$`4^,!```:`0!5XQ```)H:8P/C!C#4YP,PA>$(((WB`3!B -MY1@S`^,#4,3G!`"@X240H.-D.P/C#^"@X0/PE.<&,-3G@#`CX@8PQ.<9,P/C -M`U#$YPC0C>)P@+WH`#"@XQ0PP.4>_R_A$$`MZ9`[`^,#,)#G``!3XP$`H`,0 -M@+T(,_\OX1"`O>@00"WI`$"@X0`PH.,`,<#E^#"0Y0``4^,!```*[`"`XO[_ -M_^L`,*#C^#"$Y?PPA.40@+WH$$`MZ1XPH./T,(#E`#``XP`P0./X,(#E`#`` -MXP`P0./\,(#E[`"`XO[__^L0@+WH$$`MZ>Q`0.(`,=3E``!3XQ"`O0@S#$3B -M#`!`XO[__^L`,*#C`#'$Y1"`O>@00"WI,TR`X@Q`A.($`*#A_O__ZP0`H.'^ -M___K$("]Z'!`+>D`0*#A,VR`X@Q@AN(&`*#A`1"@X_[__^L`4*#CV#,#XP-0 -MA.=$,P/C`U"$YT@S`^,#4(3G;SL"XP,PU.?.+:#C`C#$YX$C`^,",,3G?2Z@ -MX\@S`^,#((3GS#,#XP-0Q.>1,P/C`U#$YY(S`^,#4,3GXS,#XP-0Q.>#,P/C -M`U#$YVX[`N,#,-3GA",#XP(PQ.<%,%/@`3"@$X(C`^,",,3GA3,#XP-0Q.<8 -M,P/C`U#$YPP@H.,9,P/C`R#$YQPS`^,#4,3G<#L"XP,@U.<=,P/C`R#$YW\@ -MX.,:,P/C`R#$YP`@`..D,P/C`"!`XP,@A.>H,P/C`T"$Y\X-A.(4`(#B!1"@ -MX04@H.'^___K!#0#XP-0A.<&`*#A_O__ZW"`O>@00"WI`$"@X6PPD.4!`!/C -M$("]"``0H.,!(*#A_O__ZP0`H.$%$*#C`""@X_[__^L0@+WH$$`MZ0!`H.'^ -M___KB#,#XP,PE.<`,&/@8P!3XQ@``)IL,)3E`0`3XQ4```H""Q/C$P``&A`` -M$^,1```:0``3XP\``!H@`!/C#0``&I(S`^,#,-3G`0!3XPD```K(.`'C`S"4 -MYP(`4^,!`*`3$("]&"`\`>,#`-3G``!0X@$`H!,0@+WH``"@XQ"`O>@P0"WI -M#-!-X@!`H.$"4*#A!Q#-Y0H`4>,Y``"*'#,#XP,PT.)D.P/C#^"@X0/PE.>%,P/C`U#$ -MYQP``.H$`*#A_O__ZP``4.,8```*`2"@XX4S`^,#(,3G"""-X@$0(P@+WH$$`MZ0!` -MH.'^___K``!0XQ"`O0B",P/C`S#4YP``4^,0@+T(@S,#XP,PU.(`0*#A`#"@XP6" -M,P/C`S#0YP``4^,?```*'#,#XP,PT.<``%/C&P``"@`0H.,!(*#A_O__Z_[_ -M_^L`H*#A:&L#XP=PC>(H@*#CT%L#XV20H.,$`*#A"!"@X0<@H.$/X*#A!O"4 -MYP4``%/C"0``&@4PE.<``%/C!@``&@H`H.'^___K9`!0XP(``,H)`*#A -M_O__Z^W__^H`(*#C-#,#XP,@Q.<(T(WB\(>]Z!!`+>D`0*#AXC,#XP,PT.<` -M`%/C#P``"O[__^L`,`#C`#!`XP`PD^7((P/C`B"4YV00H..1`@'@TRT$XV(@ -M0>.2`8'@S@V$XA0`@.(A$X/@_O__ZQ"`O>AL,)#E$``3XQ```!I``!/C#@`` -M&B``$^,,```:@2@`XP`@0.,"(`/@``!2XP<``!HD/`/C`S"0YP``4^,#```* -M+#H#XP,PD.<``%/C#@``"@`P`.,`,$#C`#"3Y<@C`^,"()3G9!"@XY$"`>#3 -M+03C8B!!XY(!@>#.#83B%`"`XB$3@^#^___K$("]Z-@S`^,#,)#G``!3XQ"` -MO1C0,P/C`S"0YP``4^,0@+T8`B"@X]PS`^,#((#G`""@X\PS`^,#(,#G_O__ -MZQ"`O>CX3RWI`$"@X6-M@.((8(;B,UR`X@Q0A>(%`*#A_O__Z]@S`^,#,)3G -M`@!3XS<``!K0,P/C`S"4YP``4^,S```:`("@X]PS`^,#@(3G2#,#XP,@E.,(D*#A`;"@ -MXU0UU.53.*#A`0`3XP@```H*,)3G"`!3X00`H.$&$*#A"""@X0LPH`$),*`1 -M_O__ZP!PH.$!@(CB!`!8X^___QH`,*#CT",#XP(PA.?C(P/C`C#$YS0C`^," -M,,3G````Z@%PH.,%`*#A_O__ZP<`H.'XC[WH$$`MZ0!`H.&0,P/C`S"0Y_\T -MP^/_,,/C`0A3XS,```J1,P/C`S#0YP$`4^,#```:K#P#XP,PD.AP0"WI`$"@X3-<@.(,4(7B!0"@X?[__^L!(*#CT#,#XP,@A.>!,P/C -M`R#4Y\X]H.,#(,3G1#,#XP,0E.,S`P,#(,0'!`"@X?[__^L"(*#CV#,#XP,@ -MA.<`(*#CT#,#XP,@A.<%`*#A_O__ZW"`O>@00"WI`$"@X=`S`^,#,)#G`0!3 -MXQ"`O0CB,P/C`S#0YP``4^,:```*_O__Z]@S`^,#,)3G`P!0X1$```H"`%#C -M"@``&@(@H./<,P/C`R"$YP$PH./D(P/C`C#$Y]0K`^,",(3G!`"@X?[__^L$ -M``#J`""@X]PS`^,#((3G!`"@X?[__^O,,P/C`R#4YP$@@N(#(,3GA#,#XP,P -MU.<``%/C$("]"-@S`^,#,)3G``!3XQ"`O1C,,P/C`S#4YP,`$^,0@+T8;""4 -MY8$X`.,`,$#C`S`"X```4^,0@+T8$``2XQ"`O1A``!+C$("]&"``$N,0@+T8 -M)#P#XP,PE.<``%/C$("]""PZ`^,#,)3G``!3XQ"`O1@"(*#CW#,#XP,@A.<$ -M`*#A_O__ZQ"`O>@P`"WI`#``XP`P0.,`P)/E``!$(```:`#`` -MXP`P0..",8/@"`"3Y0D``.H`,*#C`%``XP!00.,$0*#C`3"#XG,P[^8#(*#A -M#`!3X>W__[H``*#C;#D`XP(`7.$#`*`!,`"]Z![_+^$P`"WI`#``XP`P0.,` -MP)/E``!$(```:`#``XP`P0..",8/@!`"3Y0D``.H`,*#C`%`` -MXP!00.,(0*#C`3"#XG,P[^8#(*#A#`!3X>W__[H``*#C`@!%Q$/_F@P""X+``T.$! -M`%#A@S""$+`0PQ$!`*`3'O\O$0``H.,>_R_A\`,MZ71`D>7$7Z#A%CR@X].` -M@.$(8)3@"7"EX/-@@.$0-9#E`3"#XA`U@.4T,)'E`0!SXP,``!JXP]'A_S\/ -MXP,`7.$$```*-##1Y0$`$^,4-9`%`3"#`A0U@`4``%+C`@``&HP@D>4``%+C -M"P``"EH_H./3@(+A`6"@XP!PH.,&`)C@!Q"IX/,`@N%B/Z#CTV""X08`E.`' -M$*7@\P""X?`#O>@>_R_A,``MZ0K`T.6V(-#A_S\/XP,`4N&V$,`!`5"@X;8P -MT.$!0&/@`@L4XP``H!,6```:`P!1X04``!H!$('B`1J@X2$:H.&V$,#A`0"@ -MXPX``.H,,*#A`2!"X@(@C.`"(&'@`@L2XP$`H`,'```*`$!,&.B -M`3ICL@$P@[(#$('@MA#`X0$`H.,P`+WH'O\OX1!`+>F8-@'C`S#0YP``4^,) -M```*F38!XP,PT.><)@'C`C#`YP$P@^*C,*#A7S!#XIHF`>,",,#G.0``ZNPV -M`>,#,-#G``!3XP#`H!,,(*`1[38!`P,@T`?A-@$#`\#0!P$PH./L%@'C`3#` -MY^`6`>,!,,#G;#"0Y0(+$^,H```:G#8!XP,PT.>#((+@JQH*XZH:2N.1,H'@ -MH1"@X8$0@>`!`%+AJQH*XZH:2N.1,H'@H1"@X0$0@1)D`%'C9!"@(YTV`>,# -M,-#G@S",X*LJ"N.J*DKCDL."X*(@H.&"((+@`@!3X:LJ"N.J*DKCDL.#X*,P -MH.$!,(,2G"8!XP(0P.*:)@'C`A#`YV0`4^-D,*`CG28! -MXP(PP.<`,`#C`#!`XP`PD^7<)@'C`B"0YV00H..1`@'@TRT$XV(@0>.2P8'@ -M6@V`XB@`@.(A$X/@_O__ZQ"`O>AP0"WI`5"@X0Q@@.(,0)#E"0``ZK@BU.&X -M,M7A`A!CX`(+$>,`0)05`P``&@,`4N$``*`#!0``&G"`O>@&`*#A!!"@X?[_ -M_^L``%#C\/__"@P`E>@$,(+E`""#Y0!0A>4$4(7E!0"@X000H.'^___K`0"@ -MXW"`O>AP0"WI`$"@X0%@H.$04)#E_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B -M!""#Y0P`E.@$,(+E`""#Y0!`A.4$0(3E!`"@X080H.'^___K``!5XP8```I7 -M/87B&#"#X@,`5N'P-0$#`R"5!P$@@@(#((4'#2"@X7\]PN,_,,/C!""3Y0$@ -M0N($((/E_O__ZP$`H.-P@+WH\$$MZ0C03>(`0*#A$("0Y0``4.,`<*`#?'"0 -M%2\PT.4``%/C#```"C$@T.4``%#C"0``"H`PD.4#,&+@@#"`Y7P0D.4!`%/A -M`C"#,(`P@#5T,)`E`R!B('0@@"4P4-3E(3#4Y0-0A>`%8(?@!@"@X0`0`.,` -M$$#C!B"@X_[__^L``%#C#0``"@90A>(%4(?@!0"@X801G^4"(*#C_O__ZP`` -M4.,%```:!0"@X7`1G^4"(*#C_O__ZP``4.,%```*!@"@X5P1G^4&(*#C_O__ -MZP``4.-+```*,"#4Y2$PU.4#,(+@`6"@XP8@H.,",(/@M"?4X0(@8^"V(,WA -M;""8Y0$($N,:```*`W"'X'@@X.,`(,?E$B"@XP$@Q^4``%3C`%"@`P40H`$, -M```*)#!#XGQ0E.4#4(7@?%"$Y8`@E.4"`%7A!5!C@'Q0A(4`4*"#=""4E0(P -M8Y!T,(25>!"4Y04`H.$8(*#C_O__ZQA0A>(0``#JAB"@X0``5.,`4*`##``` -M"@XP0^(",(/@?%"4Y0-0A>!\4(3E@""4Y0(`5>$%,&.`?#"$A0!0H(-T()25 -M`C!CD'0PA)4%`*#A-!"$X@8@H./^___K!@"%XCH0A.(&(*#C_O__ZP``5N,& -M```:MC#=X;,_O^8($(WBLC!AX0P`A>("(*#C_O__ZP$`H.,(T(WB\(&]Z"$@ -MU.4P,-3E`S""X`!@H.,&(*#ALO__ZK`'``"T!P``N`<``/A/+>D`0*#A`5"@ -MX0*0H.%\<)'E6VV`XCA@AN+@H(#B-(#1Y6PPD.4(`!/C0```"@$`$^,!```: -M@``3XSP```JP,-?A_"`#XD@`4N->```*B"`#XH@`4N,!```:<``3XUD``!H- -M>X3B$7"'X@<`H.$Z$(7B!B"@X_[__^L``%#C40``&@&`".('`*#A-!"%X@8@ -MH./^___K``!0XP$``!H``%CC2```"DQPA>('`*#A`!``XP`00.,&(*#C_O__ -MZP``4.-````:"@"@X0`0`.,`$$#C!B"@X_[__^L``%#C.0``&@<`H.$*$*#A -M!B"@X_[__^L``%#C,P``"@``6.,#```*!`"@X?[__^L``(GE`P``Z@8`H.%, -M$(7B_O__ZP``B>4``)GE``!0X@$`H!/XC[WH`0@3XR,```H!`!/C(0``"C2` -MA>((`*#A!!"'X@8@H./^___K.K"%X@L`H.$*$(?B!B"@X_[__^M,0(7B!`"@ -MX1`0A^(&(*#C_O__ZT8`A>(($*#A!B"@X_[__^M``(7B"Q"@X08@H./^___K -M!`"@X0H0H.$&(*#C_O__ZP8`H.$$$*#A_O__ZP``B>4``%#B`0"@$_B/O>@` -M`*#C^(^]Z/A/+>D`8*#A`4"@X0)PH.%\H)'EX)"`XC2`T>4!@`CB;#"0Y2`` -M$^,!```:0``3XR<```H-6X;B$5"%X@4`H.$Z$(3B!B"@X_[__^L``%#C90`` -M&@4`H.$T$(3B!B"@X_[__^L``%#C`0``&@``6.-=```*3%"$X@4`H.$`$`#C -M`!!`XP8@H./^___K``!0XU4``!H)`*#A`!``XP`00.,&(*#C_O__ZP``4.-. -M```:!0"@X0D0H.$&(*#C_O__ZP``4.,Z$(02`5"@$SD``!I%``#J"``3XP@` -M``I,`('B.A"!X@8@H./^___K``!0XTP0A!(!4*`3+@``&CH``.H0`!/C#P`` -M"@``6.,$```*3##1Y0$`$^,!4*`3)P``&C$``.I,`('B-!"!X@8@H./^___K -M``!0XSH0A!(!4*`3(@``&B@``.H!"!/C`!"@`P%0H`$7```*-+"$X@L`H.$$ -M$(KB!B"@X_[__^LZ4(3B!0"@X0H0BN(&(*#C_O__ZTP`A.(0$(KB!B"@X_[_ -M_^M&`(3B"Q"@X08@H./^___K0`"$X@40H.$&(*#C_O__ZPD0H.$!4*#C``!8 -MXP,```H&`*#A_O__ZP``A^4#``#J6PV&XC@`@.+^___K``"'Y0`PE^4``%/C -M````&@!0H.,%`*#A^(^]Z'!`+>D`4*#A_O__ZPT@H.%_/<+C/S##XP0@D^4! -M((+B!""#Y04`H.'^___K`0!0XP!`H`,/```*`$"5Y0P`E.@$,(+E`""#Y0!` -MA.4$0(3E$""4Y0``4N,&```*5SV"XA@P@^(#`%7A\#4!`P,0D@G^___K -M$("]Z/A/+>D`4*#A`4"@X7QPD>4'8*#AL##7X0PP`^($`%/CCP``&@0`A^(- -M&X7B$1"!X@8@H./^___K``!0XX@```JP,-?A_#`#XJ0`4^.$```:LH#7X5L- -MA>(X`(#B"A"'XO[__^L`8%#B?0``"@B)H.$HB:#AU#"6Y0@`4^%X```:%CZ@ -MX].@AN$!@*#C`)"@XP@`FN`)$*O@\P"&X24PU.4'`%/C$0``BM4RU.$!(*#C -M$C.@X<``$^,)```:,``3XP0``!H&`!/C"```"J(WUN4",`/@!P``ZJ0WUN4! -M,`/B!```ZJ4WUN4!,`/B`0``ZJ,WUN4!,`/B``!3XU@``!K0,);E!``3XU4` -M``J\.`'CLR"5X=0PEN52,Z#A`0`3XT\```K^___K#2"@X7\]PN,_,,/C!""3 -MY0$@@N($((/E!@"@X<1`L.4$$*#A_O__ZP``4.,F```:#`"4Z`0P@N4`((/E -M`$"$Y01`A.7,,);E`3!#XLPPAN4``%/C`3"@$P`PH`-4,,3E`3"@XU8PQ.4% -M`*#A!!"@X90[`^,/X*#A`_"5YP$`4.,"```:!0"@X000H.'^___KS#"6Y0`` -M4^,@```:OC@!X]0@EN6S$)7A`0"@XQ`BP>&S((7A!0"@X040H.,`(*#C`C"@ -MX?[__^L4``#JOC@!X[,@E>'4,);E4C.@X0$`$^,.```*S#"6Y0``4^,`,*`3 -MS#"&%;XX`>/4();ELQ"5X0$`H.,0(L'ALR"%X04`H.$%$*#C`""@XP(PH.'^ -M___K#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__ZP``H./XC[WH<$`MZ0!0 -MH.$!0*#A6PV`XC@`@.(Z$('B_O__ZP`04.)P@+T(W#"1Y0``4^-P@+T(H#?1 -MY0\`$^-P@+T(T#"1Y00`$^-P@+T()2#4Y0<`4N,1``"*4``%/C`@``"@4` -MH.'^___K<("]Z`4`H.'@$('B_O__ZW"`O>AP0"WI`$"@X7Q0D>5;#8#B.`"` -MXCH0@>+^___KL##5X0`04.)P@+T(`0H3XP4```K0,)'E!``3XW"`O1@$`*#A -M_O__ZW"`O>C0,)'E!``3XW"`O0@$`*#A_O__ZW"`O>CP02WI`%"@X0%`H.$" -M8*#A?'"1Y6PPD.40`!/C*0``"DP`@>+@$(7B!B"@X_[__^L``%#C)0``"EL- -MA>(X`(#B.A"$XO[__^L``(;E``!0XQX```H%`*#A!!"@X?[__^NP,-?A_"`# -MXD@`4N,%```:!0"@X000H.$`();E_O__ZP``H./P@;WHB#`#XH@`4^,,```: -MR`!2XP4``!H%`*#A!!"@X0`@EN7^___K``"@X_"!O>@%`*#A!!"@X?[__^L! -M`*#C\(&]Z`$`H./P@;WH``"@X_"!O>CP3RWI#-!-X@"0H.$!0*#A`#"@XP0P -MC>5\4)'E!;"@X;!@U>$!'!;B`B"@$P,@H`'6-.#G`R""X0$`4N,$H(4"`0`` -M"A"@A2($H(4R``!1XP(@H!,`(*`#`R""X0$`4N,0@(4"!```"@J`A3("```Z -M`@!2XQB`A1(*@(4"``!1XP(0H!,`$*`#`S"!X0,`4^,#\9^7`P``ZH"*`0"( -MB@$`D(H!`)B*`0``<*#C!@``ZA!PA>($``#J"G"%X@(``.H$<(7B````Z@1P -MA>(``%?CM0``"C0`A.(*$*#A!B"@X_[__^LZ`(3B"!"@X08@H./^___K3`"$ -MX@<0H.$&(*#C_O__ZR(PU.4#`%/C`_&?ES0``.KTB@$`*(L!`%R+`0"0BP$` -M1@"$X@H0H.$&(*#C_O__ZT``A.(($*#A!B"@X_[__^L)`*#A!!"@X00@C>+^ -M___K)```ZD8`A.(*$*#A!B"@X_[__^M``(3B!Q"@X08@H./^___K"0"@X000 -MH.$$((WB_O__ZQ<``.I&`(3B!Q"@X08@H./^___K0`"$X@@0H.$&(*#C_O__ -MZPD`H.$$$*#A!""-XO[__^L*``#J1@"$X@00A>(&(*#C_O__ZT``A.(*$(7B -M!B"@X_[__^L``*#C<0``Z@``H.,``%#C;@``"@0PG>4``%/C:@``"HPPA.4` -M,*#C(S#$Y20PU.4!`%/C$```&A@P^^4/,`/B)3#$Y;`@V^'2(^#G(R#$Y2(@ -MU.4#`%+C(""@`QH@H!,A(,3E``!3XP,`4Q,!(*`3^#4!$P,@B1<&``#J`#"@ -MXR4PQ.4B,-3E`P!3XQXPH`,8,*`3(3#$Y2PPU.4``%/C(3#4%00P@Q(A,,05 -M)3#4Y8,Q@^`$()WE@S&"X'D_@^*0,(3E!`"@X=85X.>D((+B_O__ZP``4.,[ -M```*+3#4Y0``4^,R```*R#@!XP,PF><#`%/C`_&?EPX``.J\C`$`O(P!`,R, -M`0"\C`$`S#@!XP,PF>+PC[WH$$`MZ0%`H.$O,-'E``!3 -MXR0```HA,-'E?""1Y0,P@N`#,-/E(S.@X54PP>4O,-'E'```"BX@T>4``%+C -M`P``"B@L`>,"()#G`0!2XQ4``!H`(*#C+#P!XP,@@.D4T$WB -M`%"@X0%`H.%;#8#B.`"`XD`0@>+^___K+S#4Y0(`4^,!`*`37P``&@``4.-1 -M```*1C#4Y0$`$^,!#(`""```"E4@U.4@/`'C`S#5YP``4^,``*`#`@*%$&8- -M@!(L`(`24```"B$PU.4P8-3E='"4Y0=P8^`Q(-3E!W!BX`AP1^('<&;@?!"4 -MY0-@AN`&8('@"#"-X@`PC>4E,-3E!#"-Y08@H.$',*#A_O__ZP=@AN``(*#C -M`C"@X0C`C>(#`-SG`Q#6YP$`4.$!(*`3`3"#X@@`4^/X__\:`0!2XQL``!IT -M()3E``!2XP,```H`,*#C"#"#X@(`4^'\__\Z1A#4Y0$0`>(!`%'C`2"@$P0` -M`!I5(-3E/#N5Y0,`4N$`(*`3`2"@`RXPU.4!`%/C`#"@$P$P`@(``%/C``"@ -M`PX```H%`*#A_O__ZP``H.,*``#J(CP!XP,PU><``%/C!0``&D8PU.4!`!/C -M`0"@$R(\`1,#`,47````&@$`H.,``%3C"```"H`@E.4(,$+B@#"$Y7P0E.4! -M`%/A@""$-70PE"4(,$,B=#"$)130C>+P@+WH<$`MZ0!`H.$`4`_A@``,\0T@ -MH.%_/<+C/S##XP0@D^4!((+B!""#Y?[__^L!`%#C`$"@`P!`E!4$,)05`""4 -M%00P@A4`((,5`$"$%01`A!4%\"'A#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E -M`#"3Y0(`$^,````*_O__ZP0`H.%P@+WH$$`MZ0`PH.$`0`_A@``,\0W`H.%_ -M+,&```*5SV%XA@P@^(#`%;A\#4!`P,@E0E+WTWB`&"@X1`0 -MC>57#8#B&`"`XAP`C>4A(-'E``!1XPL```I\,)'E`C"#X'PP@>40`)WE@!"0 -MY0$`4^$#,&*`?#"`A1`0G95T,)&5`R!BD'0@@940()WE,##2Y0``4^,-```* -M``!2XPL```I\()+E`R""X!``G>5\((#E@!"0Y0$`4N$",&.`?#"`A1`0G95T -M()&5`C!CD'0P@940()WE=("2Y7R@DN4.`%CCP```V@Q0VN4-,-KE!52#X060 -MH.$.L(7B"P!8X;D``+H`<*#C!C"@X0I@H.$#H*#A"0``Z@5@AN`+8(;@#%#6 -MY0TPUN4%5(/A!9"@X0ZPA>(!<(?B"`!;X:H``,H.8(;B#`")XO[__^L`0%#B -M#```"J@PE.4,,(/BJ#"$Y9PPE.4,,(/BG#"$Y00`H.$%$*#A_O__ZP80H.$% -M(*#A_O__ZPL``.H0,)WE"`"3Y2`0H./^___K`$!0X@I@H`%W<.\&'```"JA@ -MA.504(3E!3"&X)PPA.4H`(WB!T&`YS\`5^,*8*`!`7"'`G=P[P81```*#H!( -MX@F`6.`*8*`!`7"'`G=P[P8+```*`[`+X@2P:^($`%OC`+"@`P@`6^%Y``#* -M"(!KX`X`6./!___*"F"@X0%PA^)W<._F``!7XW$```H0$)WE.K"!XC0@@>($ -M((WE`7!'XG>0[^8!D(GB"9&@X0!PH.,HH(WB_CX/X_\_3^,(,(WE`@!*X@P` -MC>4`,`#C`#!`XQ0PC>40$(/B&!"-Y0=0FN>H`)7E!D#0Y0>`T.50,)7E!P!3 -MXR```)H4$)WE!B"@X_[__^L``%#C!0``"@1$B.'S(`CC-S$(XP(`5.$#`%01 -M!0``&J@`E>48$)WE!B"@X_[__^L``%#C#P``"@4`H.$&$*#C_O__ZP4`H.$& -M$*#C_O__ZPL0H.$&(*#C_O__ZP4`H.$&$*#C_O__ZP00G>4&(*#C_O__ZQ8` -M`.I0,)7ELS^_YDH?C>((`)WEL#"!X04`H.$"$*#C_O__ZPP0G>4"(*#C_O__ -MZP4`H.$&$*#C_O__ZPL0H.$&(*#C_O__ZP4`H.$&$*#C_O__ZP00G>4&(*#C -M_O__ZP``5>,9```*_O__ZP@\`^,#,);G:C^#X@!`D^7^___K``!4XP4```IL -M,);E*``3XP(```H&`*#A!1"@X?[__^L(3`/C!0"@X000EN?^___KM@;%X00P -MEN<4,(7E9##5Y1\QP^=D,,7E!0"@X?[__^L$<(?B"0!7X:'__QH`,*#C$""= -MY70P@N40`)WE'!"=Y?[__^L!`*#C2]^-XO"/O>CX3RWI`'"@X0%@H.$,@('B -M#%"1Y0$`4N,%```:"`"@X?[__^L``%#C-@``&K@RU>&V,,;A5[V'XABPB^+, -MJP/CT)L#XRD``.H%0*#AMB#6X;@RU>$",&/@`@L3XRD``!H`4)7E!#"4Y00P -MA>4`4(/E`$"$Y01`A.6V,-;AN"+4X0,`4N$!,(,"`SJ@`2,ZH`&V,,8!(S#4 -MY0``4^,)```:"C"7YP``4^,0```:"3"7YP``4^,-```:!P"@X000H.'^___K -M"0``Z@$`4^,'```:!P"@X000H.'^___K`0!0XP(```H$`*#A"Q"@X?[__^L( -M`*#A_O__ZP``4./1__\*``"@X_B/O>@!`*#C^(^]Z'!`+>D`4*#A`$"0Y(#$('B_O__ZPT@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^MP -M@+WH<$`MZ0!@H.$!0*#AD%"1Y2,PT>4``%/C(```&@$`H.'^___K)##4Y0$` -M4^,,```*S#L#XP,PEN<``%/C7P``&M`[`^,#,);G``!3XUL``!H&`*#A!!"@ -MX?[__^L!`*#C<("]Z`0PU>4``%/C&0``&K@BU.&V(,7A!@"@X000H.'^___K -MMC#5X0$P@^(#.J#A(SJ@X;8PQ>$!`*#C<("]Z`$`4^,+```:!##5Y0``4^,( -M```:N#+1X;8PQ>'^___KMC#5X0$P@^(#.J#A(SJ@X;8PQ>%P@+WH_O__ZPT@ -MH.%_/<+C/S##XP0@D^4!((+B!""#Y04`H.&X$M3A_O__ZP``4.,D```*!0"@ -MX000H.'^___K``!0XQ\```H&`*#A!1"@X0`@H./^___K`0!0XPX``!H`,`#C -M`#!`XP`0D^44`(7B`Q"!XO[__^L-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^ -M___K`0"@XW"`O>@-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K%`"%XO[_ -M_^L!`*#C<("]Z`T@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^L``*#C<("] -MZ```H.-P@+WH<$`MZ0!`H.$!8*#AV#20Y0$`4^,+```:_O__ZP$`4.,;```* -MS#L#XP,PE.<``%/C%P``&M`[`^,#4)3G`%!5X@%0H!,3``#J`0"@X?[__^L` -M4*#A`0!0XPX``!K,.P/C`S"4YP``4^,'```:T#L#XP,PE.<``%/C`P``&@0` -MH.$&$*#A_O__ZP(``.H`4*#C````Z@%0H.,%`*#A<("]Z'!`+>D(T$WB`%"@ -MX0`PH..V,,WA6PV`XC@`@.(`0%'B`&"@`WQ@E!5`$(3B_O__Z\@X`>,#,)7G -M`@!3XQD``!H``%#C%P``"N@PD.4``%/C%```"B$0U.4P,-3E`Q"!X`80@>(& -M`(WB`1"&X`(@H./^___KMC#=X;,_O^9S,/_FCB@(XP(`4^$&```*MC#-X00` -MH.%7'87B&!"!XO[__^L``*#C````Z@0`H.$(T(WB<("]Z/!!+>D`4*#A`6"@ -MX0AP@.('`*#A_O__ZP!`E>4#``#J!`"@X0!`E.4&$*#A_O__ZP4`H.$$$*#A -M_O__ZP``4./V__\*!P"@X?[__^OP@;WH\$4!<*#C0P``Z@90H.$J,-;E!P!3 -MX0<```H$`*#A"1"@X?[__^L*`*#A"1"@X?[__^L`0*#C/P``Z@%P@^)W<._F -M(3#6Y3`@UN4``%;C"P``"@,@@N!R(._F?#"6Y0(P@^!\,(;E@!"6Y0$`4^$# -M,&*`?#"&A70PEI4#(&*0=""&E3$@U.4``%3C%P``"H`PE.4#,&+@@#"$Y7P0 -ME.4!`%/A`C"#,(`PA#5T,)0E`R!B('0@A"6``)3E?!"5Y70@E>7^___K=""5 -MY8`PE.4",(/@@#"$Y800E.4!`%/A`S!B@(`PA(4(``"*!```ZH``E.5\$)7E -M=""5Y?[__^L"``#J=#"4Y0(@@^!T((3E,3#5Y3$PQ.4`8);E"`"@X080H.'^ -M___K``!0X[;__PH*`*#A"1"@X?[__^L$`*#A\(>]Z/!'+>D`8*#A`4"@X5>- -M@.(8@(CB*W#1Y2J@T>5;#8#B.`"`XD`0@>+^___K``!0XYR0@!((```:?#"4 -MY0`PT^4,,`/B"`!3XP"0H`,"```*!@"@X?[__^N,'```*!`"@X0D0H.'^___K!@"@ -MX0D0H.'^___K`%"@X00``.H$`*#A"!"@X?[__^L`4*#C#0``Z@``5>,+```* -M+3#5Y0``4^,(```*!@"@X040H.'^___K``!0XP,``!H%`*#A"!"@X?[__^L` -M4*#C!0"@X?"'O>CX3RWI`$"@X0%0H.%\$)'E6PV`XC@`@.(*$('B_O__ZP`` -M4.,&```*5C^@X].@@.$!@*#C`)"@XPA@FN`)<*O@\V"`X00`H.$%$*#A_O__ -MZP`04.(!```*!`"@X?[__^L!`*#C^(^]Z/!/+>D,T$WB`%"@X0%`H.%\,)'E -M`"#3Y0,@`N+(&9#E`P!1XP<``!K0&9#E@1"!X`$1@.!^'H'B"!"!X@0`D>4! -M`(#B!`"!Y0``4N-6```:`R"@X;`0T^%Q<._F#&`'X@$,$>/1%.#G`@"@$P`` -MH`,`$('A(A#$Y180\^4/$`'B*A#$Y;`PT^$C,J#AN#+$X;`PTN%3-N#G)C#$ -MY;`PTN%3->#G*S#$Y;`PTN'3-N#G)S#$Y;`PTN%3-^#G+3#$Y;`PTN&C-Z#A -M+##$Y04`H.$&$*#C!R"-XFP[`^,/X*#A`_"5YP4!`%/C"```"@(`4^," -M```:``!6XPH```H#``#J`P!3XP$``!H(`%;C#P``"@0`5N,(```*"`!6XPL` -M``H``%;C'P``&@4`H.$$$*#A_O__ZP``H.,;``#J!0"@X000H.'^___K``"@ -MXQ8``.KD-@/C`S"5YP``4^,"```*!0"@X040H.,S_R_AIW.@X21PQ.4%`*#A -M!!"@X?[__^L``%#C"```&A`V`>/3H(7A`8"@XP"0H.,(8)K@"7"KX/-@A>$` -M``#J``"@XPS0C>+PC[WH\$/3H(3A`8"@XP"0H.,(8)K@"7"KX/-@A.'0C[WH$$`MZ0!`H.'^___K -M`#"@XW0PA.40@+WH$$`MZ0!`H.'^___K"`"$XO[__^L0`(3B_O__Z[P`A.+^ -M___K$("]Z'!`+>D`0*#A'%"0Y?[__^L$`*#A_O__ZQ``E.4``%#C`0``"I4< -MH./^___K!0"@X2@[`^,/X*#A`_"5YW"`O>CP02WI`("@X0%@H.'^___K"`"@ -MX?[__^L(`(CB_O__ZQQ@B.4!/*#C&#"(Y0@`H.$&$*#A_O__ZY4,H./^___K -M$`"(Y0``4.,`4*`#*P``"O\`@.+_0,#C%$"(Y0APH.$E6X3B!`"@X?[__^L$ -M`*#A!Q"@X?[__^L&`*#A!!"@X?[__^L08(3EE$"$X@4`5.'S__\:`3"@XV@P -MR.58`(CB`!"@X_[__^L&`*#A)#L#XP_@H.$#\);G`%"@X=!`B.(`,`#C`#!` -MX^`PB.7D8(CE!`"@X0`0H.,!(*#A_O__Z_H_H.,$,8CE`#``XP`P0.,`$)/E -M!`"@X600@>+^___K!0"@X?"!O>@00"WI`$"@X0`0H.,L(*#C_O__ZP0`H.'^ -M___K!`"$XO[__^L0@+WH`0"@XQ[_+^'P02WI"-!-X@!`H.$!4*#A`"``XP`@ -M0.,-,*#A`P"2Z`0`@^2P$,/A``!5XP!@H`,P```*`##5Y0$`$^,-4*`1` -MY0$PU>4&82/@`C#5Y09A(^`#,-7E!F$CX`0PU>4&82/@!3#5Y09A(^`F9";@ -M'V`&XO[__^L-(*#A?SW"XS\PP^,$()/E`2""X@0@@^4"8(;BAG&$X(9!E.<& -M@*#C!P``Z@A@1.+8`(3B!1"@X0@@H.'^___K`0!0XP8```H`0)3E!P"@X000 -MH.'^___K``!0X_+__PH`8*#C#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__ -MZP8`H.$(T(WB\(&]Z`3@+>4,T$WB`""@X0TPH.$@$)_E`P"1Z`0`@^2P$,/A -M6PV"XC@`@.(-$*#A_O__ZPS0C>(`@+WHZ!(``/!/+>D,T$WB!`"-Y0!P4>+$ -M```*4TV`XB!`A.+^___K#0"@X7^MP.,_H,KC!#":Y0$P@^($,(KE!`"@X<00 -MA^+^___K`("@X\R`A^4$`*#A7!"'XO[__^M4,(?B6""7Y500E^4$(('E`!"" -MY50PA^58,(?E!`"@X4@0A^+^___K0#"'XD0@E^5`$)?E!""!Y0`0@N5`,(?E -M1#"'Y00`H.$T$(?B_O__ZRPPA^(P()?E+!"7Y00@@>4`$(+E+#"'Y3`PA^4$ -M`*#A(!"'XO[__^L8,(?B'""7Y1@0E^4$(('E`!""Y1@PA^4<,(?E!#":Y0$P -M0^($,(KE_O__ZP@PA^(,()?E"!"7Y00@@>4`$(+E"#"'Y0PPA^4(.`'C!!"= -MY0,@D>57;8+B -M&&"&X@J0H.$'L*#AB%&(X(51H.$%`(?@?@^`XO[__^O^___K!#":Y0$P@^($ -M,(KE!5"'X!]>A>+P09OE"```Z@0`H.$`0)3E!#"0Y00PA.4`0(/E``"`Y00` -M@.4&$*#A_O__ZP4`H.'^___K``!0X_+__PH$,)GE`3!#X@0PB>7^___K`8"( -MXDBPB^(0`%CCW?__&G@[`^,$`)WE`\"0YP``7.,#```*`!"@XP<@H.$!,*#A -M//\OX?[__^L-$*#A?SW!XS\PP^,$()/E`2""X@0@@^4;+8?BQ!:7Y<`&E^4$ -M$(#E``"!Y<`FA^7$)H?E!""3Y0$@0N($((/E_O__ZP`PH./(-H?EJ#>'Y:`W -MQ^6A-\?EHC?'Y:,WQ^6D-\?EI3?'Y:8WQ^6\.`'C`2"@X]0`E^4$P)WELQ"< -MX1(0P>&S$(SAOC@!X]0`E^6S$)SA$B#!X;,@C.'4,)?E``!3XPP```H!,$/B -M!BR#X@X@@N("(8S@!""2Y0<`4N$%```:!CR#X@,1C.`\$('B`#"@XP`P@>74 -M,(+E`#"@XP0XQ^7^___K#0"@X7]-P.,_0,3C!#"4Y0$P@^($,(3E!P"@X00@ -MG>47'(+B_O__ZP0PE.4!,$/B!#"$Y?[__^L!`*#C#-"-XO"/O>CP1RWI`'"@ -MX?[__^L`8*#A"#@!XP,PE^]"/[__^L-(*#A?SW"XS\PP^,$()/E -M`2""X@0@@^47K(?B"*"*X@"`H.,N7HCB`5"%XH51A^``0)KE!0``Z@@01.(` -M0)3E`0!6X0$```H'`*#A_O__ZP4`H.$$$*#A_O__ZP``4./T__\*`8"(X@B@ -MBN(@`%CCZ___&@T@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^OPA[WH$$`M -MZ0!`H.'^___K&`"$XO[__^LL`(3B_O__ZT``A.+^___K5`"$XO[__^L0@+WH -M$$`MZ0!`H.$``%3C````"O[__^L0`(3B_O__ZY@`A.+^___KI`"$XO[__^L0 -M@+WH<$`MZ0!`H.'^___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/E"%"$X@A` -ME.4"``#J!`"@X0!`E.7^___K!0"@X000H.'^___K``!0X_?__PH-(*#A?SW" -MXS\PP^,$()/E`2!"X@0@@^7^___K<("]Z'!`+>D`0*#A_O__ZQ!0A.(%`*#A -M_O__ZP4`H.'^___K20^$XO[__^M'#X3B_O__ZTY/A.($`*#A_O__ZP0`H.'^ -M___K<("]Z!!`+>D`0%#B!P``"@0`H.'^___K``"4Y0``4.,"```*!!@`XP$0 -M0./^___K`0"@XQ"`O>AP0"WI`$"@X0`0H.,A+:#C_O__ZP0`H.'^___K!`"@ -MX?[__^L(`(3B_O__Z\0`A.+^___K`%"@X\Q0A.40`(3B_O__ZY@`A.+^___K -M:PZ$X@@`@.+^___K&PV$XO[__^O(5H3E6%>$Y50G`..R4(3A=%?$Y957Q.66 -M5\3EEU?$Y9A7Q.695\3EFE?$Y018Q.5P@+WH\$\MZ0S03>(`<*#A`4"@X0`@ -MX..V(,WA_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B!""#Y0@`A^+^___K`0!0 -MXP@``!H-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K`&"@XUD``.H(8)?E -M#`"6Z`0P@N4`((/E`&"&Y01@AN4-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^ -M___K!@"@X?[__^O@`(;B!!"@X08@H./^___K`%#4Y0$PU.4%42/@`C#4Y051 -M(^`#,-3E!5$CX`0PU.4%42/@!3#4Y051(^`E5"7@'U`%XO[__^L-,*#A?TW# -MXS]`Q.,$,)3E`3"#X@0PA.4"$(7B"`"&XH$1A^#^___K$#&7Y0$P@^(0,8?E -M!#"4Y0$P0^($,(3E_O__ZZ10AN(`0*#C!H"-X@*@H.,$`(7@"!"@X0H@H.'^ -M___K`D"$XB``5./X__\:)`&7Y080H.'^___K>T^&X@!0H.,%D*#A`*#@XT"P -MH.,D,9?E"#`$Y0201.6RH$3AL*#$X0*PQ.6%@87@B(&@X0@`AN`?#H#B_O__ -MZP@`AN!Y#X#B_O__ZP%0A>)(0(3B$`!5X^W__QH`,.#C$#B&Y10XAN4&`*#A -M#-"-XO"/O>@$X"WE#-!-X@`@H.$-,*#A,!"?Y0,`D>@$`(/DL!##X5L-@N(X -M`(#B#1"@X?[__^L``%#C`3"@$]@P@!4!`*#C#-"-X@"`O>CP$@``\$$MZ0!@ -MH.$$"`#C`0!`X_[__^L``(;E``!0X_"!O0@#`,#C!`"`X@0`AN4(<(;B!P"@ -MX?[__^L0`(;B_O__ZP!`H.,008;E10^&XO[__^M'#X;B_O__ZP10EN4%`*#A -M_O__ZP(`A.*``8;@_O__ZP4`H.$'$*#A_O__ZR%=A>(!0(3B(`!4X_/__QH` -M,*#C<2^@X[(PAN'&(0#CLC"&X4H/AN+^___K$PZ&XO[__^M.3X;B!`"@X?[_ -M_^L$`*#A_O__ZP,PH.,X,8;E/#&&Y3PPH.-`,8;EA4,)'E*"#1Y0<`4N,+``"*V"+1X0$0H.,1(J#AP``2XU0P@Q(&```: -M,``2XT`P@Q(#```:!@`2XRPP@Q(````:&#"#XA``D^4>_R_A%B#0Y;HPT.$# -M((+@##"0Y0@P@^(",(/@%2#0Y0(`4N,(,(,"%P#0Y0``@^`>_R_A\`,MZ60P -MD>4/,`/B`0!3XQD``!H"0*#AQ%^@X54]H./3@(#A"&"4X`EPI>#S8(#A=##1 -MY0PED.4#,(+@##6`Y5PPD>4``%/C"P``"F8OH.-T@-'E`)"@X])@@^$&`)C@ -M!Q"IX/(`@^$:+J#CTF"#X08`E.`'$*7@\@"#X?`#O>@>_R_A!P!2XQ```(H! -M`*#C$"*@X<``$N-4`($2`""@$P`@PQ4>_R\1,``2XT``@1(!(*`3`"##%1[_ -M+Q$&`!+C+`"!$@,@H!,`(,,5'O\O$1@`@>("(*#C`"##Y1[_+^$``%'C'O\O -MT0`PH.,#P*#A@R&`X`3`@N4!,(/B`0!3X?K__QH>_R_A^$\MZ0"`H.$!4*#A -M_O__ZPT0H.%_/<'C/S##XP0@D^4!((+B!""#Y<2@A>+$8)7E`7"@XY2[`^,` -MD*#C0P``Z@9`H.$`8);E,##4Y0<`4^,0``"*T#/4X16H-Y7E`3!#XJ@WA>4``%/C5'#$%5B0Q!54D,0%6'#$!59PQ.4( -M`*#A!!"@X0_@H.$+\)CG`0!0XP(``!H(`*#A!!"@X?[__^NH-Y7E``!3XPP` -M`!JF-]7E``!3XPD``!K4()7EOA@!X[$PF.$7,L/AL3"(X0@`H.$%$*#C"2"@ -MX0DPH.'^___K"@"@X080H.'^___K``!0X[;__PH-(*#A?SW"XS\PP^,$()/E -M`2!"X@0@@^7^___K^(^]Z/!/+>D4T$WB`&"@X0%0H.'^___K#1"@X7^MP>,_ -MH,KC!#":Y0$P@^($,(KEQ""%X@0@C>7$<)7E"I"@X0`PH.,(,(WE`8"@X[ZX -M`>,,@(WE5```Z@=`H.$`<)?E!#"4Y00PA^4`<(/E`$"$Y01`A.4P,-3E!P!3 -MXQ```(K0,]3A&#.@X<``$^,)```:,``3XP0``!H&`!/C"```"J(GU>4"(`+B -M!P``ZJ0GU>4"(`+B!```ZJ4GU>4"(`+B`0``ZJ,GU>4"(`+BS#"5Y0$P0^+, -M,(7E``!3XU2`Q!4`$*`#5!#$!0``4N,)```*J#>5Y0$P0^*H-X7E``!3XU2` -MQ!4`(*`36"#$%0`PH`-4,,0%6(#$!5:`Q.4$,)KE`3!#X@0PBN7^___K!@"@ -MX000H.&4*P/C#^"@X0+PEN7,,)7E``!3XPX``!K4()7ENS"6X1@RP^&[,(;AT#"5Y00`$^,$ -M,",2T#"%%=0@E>6\&`'CL3"6X1@RP^&Q,(;A#""=Y0@@C>4$`)WE!Q"@X?[_ -M_^L``%#CI?__"@T0H.%_/<'C/S##XP0@D^4!($+B!""#Y?[__^L&`*#A_O__ -MZP!04.)6```*O#@!X[,@EN'^/P_C`#!`XP,P`N```%/C1P``&O[__^L-(*#A -M?XW"XS^`R.,$,)CE`3"#X@0PB.7$,(7B!#"-Y<1PE>4(H*#A`9"@X[ZX`>,M -M``#J!T"@X0!PE^4$,)3E!#"'Y0!P@^4`0(3E!$"$Y4!,$/BS#"%Y0`` -M4^-4D,05`!"@`U00Q`56D,3E!#"8Y0$P0^($,(CE_O__ZP8`H.$$$*#AE"L# -MXP_@H.$"\);G`0!0XP(``!H&`*#A!!"@X?[__^O^___K!#":Y0$P@^($,(KE -MS#"5Y0``4^,)```:NS"6X0$PP^.[,(;AO!@!X[$PEN$!,,/CL3"&X0@@G>4" -M((+C"""-Y00`G>4'$*#A_O__ZP``4./,__\*#1"@X7\]P>,_,,/C!""3Y0$@ -M0N($((/E_O__ZP@@G>4``%+C!```"@8`H.$%$*#C`""@XP(PH.'^___K%-"- -MXO"/O>CP02WI`%"@X0%`H.%&<-'E;#"0Y1``$^.=```*7&"1Y0``5N,%```: -M6PV`XC@`@.)&$('B_O__ZP!@4.*4```*`7`'XE8PU.4!`%/C!0``&@``5^,1 -M,*`35S#$%0!`H!.,```:B@``Z@``5^,L```*_O__ZPT@H.%_/<+C/S##XP0@ -MD^4!((+B!""#Y;PX`>.S,)7A``!3XP!`H`,8```*#`"4Z`0P@N4`((/E`$"$ -MY01`A.4$`*#AQ!"&XO[__^O,,);E`3"#XLPPAN6^.`'CLR"5X0$@@N.S((7A -MO#@!X[,@E>$!((+CLR"%X04`H.$%$*#C`""@XP(PH.'^___K`4"@XPT@H.%_ -M/<+C/S##XP0@D^4!($+B!""#Y?[__^M<``#J_O__ZPT@H.%_/<+C/S##XP0@ -MD^4!((+B!""#Y=`PEN4$`!/C1@``"KPX`>.S()7AU#"6Y5(SH.$!`!/C0``` -M"@P`E.@$,(+E`""#Y0!`A.4$0(3E!`"@X<00AN+^___KS#"6Y0$P@^+,,(;E -M,##4Y0<`4^,1``"*T#/4X0$@H.,2,Z#AP``3XPD``!HP`!/C!```&@8`$^,( -M```*HC?6Y0(P`^`'``#JI#?6Y0$P`^($``#JI3?6Y0$P`^(!``#JHS?6Y0$P -M`^(``%/C"0``"J@GEN4!((+BJ">&Y:8GUN4``%+C`#"@$P$P`P(``%/C`P`` -M&A0``.JF-];E``!3XQ$```J^.`'CU""6Y;,0E>$!`*#C$"*!X;,@A>',,);E -M``!3X0@``!H%`*#A!1"@XP`@H.,",*#A_O__ZP%`H.,"``#J`$"@XP```.H! -M0*#C#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__ZP```.H`0*#C!`"@X?"! -MO>CP1RWI"-!-X@!@H.$!@*#A:#4!XP.@D.<"<*#A`$"2Y0>0C>(1``#J!%"@ -MX0!`E.4&`*#A!1"@X?[__^L&`*#A"!"@X3`@U>4),*#A_O__ZQ`PD.4!,$/B -M$#"`Y06#,8K@!""3Y0$@0N($((/E!P"@X000H.'^___K``!0X^C__PH( -MT(WB\(>]Z/!!+>D`4*#A`4"@X?[__^L`8*#A_O__ZPTPH.%_?/4()3ELQ"5X0$`H.,0(H'ALR"% -MX04`H.$$$*#A7""$XL/__^M4,(3B6""4Y500E.4$(('E`!""Y50PA.58,(3E -M!0"@X000H.%(((3BN/__ZT`PA.)$()3E0!"4Y00@@>4`$(+E0#"$Y40PA.4% -M`*#A!!"@X2`@A.*M___K&#"$XAP@E.48$)3E!""!Y0`0@N48,(3E'#"$Y04` -MH.$$$*#A-""$XJ+__^LL,(3B,""4Y2P0E.4$(('E`!""Y2PPA.4P,(3E!0"@ -MX080H.$@((;BE___ZQ@PAN(<();E&!"6Y00@@>4`$(+E&#"&Y1PPAN4$,)?E -M`3!#X@0PA^7^___K\(&]Z#!`+>DLT$WB`%"@X0%`H.$``)#E!1"@X?[__^L% -M`*#A&!"-X@X@H./^___KM##4X0(+4^,&```:!0"@X000C>(4(*#C_O__ZP4P -MW>6C,J#A`P``ZHXH".,"`%/A!S"@`P`PH!,H,,3E&C"@X[HPQ.%W,.#C`3#$ -MY2S0C>(P@+WH53#@XP`PP.4!,,#E`S"@XP(PP.7S,`CC-\$(XP,`4>$,`%$1 -M`#``$P`P0!,`,``#`#!``P#`T^4#P,#E`<#3Y03`P.4",-/E!3#`Y;$?O^:V -M$,#A"`"@XQ[_+^'P3RWI%-!-X@!@H.$!H*#A`$"1Y?[__^L(/`/C`S"6YVH_ -M@^(`<)/E_O__Z_[__^L-(*#A?SW"XS\PP^,$()/E`2""X@0@@^6H4)3E`##5 -MY0$P(^(``%?C`'"@`P%P`Q(``%?C*@``"@9PA>('`*#A/1R&X@P0@>(&(*#C -M_O__ZP``4.,B```*O##5X8$`4^,D```*"`!3XT$``!KS#8;B/@"`X@<0H.$& -M(*#C_O__ZP``4.,Z```:"#T#XP,PEN<``%/C-@``"@<`H.$-&X;B$1"!X@8@ -MH./^___K`#``XP`P0.,`()/E"#T#XP,PEN<4((/E#2"@X7\]PN,_,,/C!""3 -MY0$@0N($((/E_O__Z]8``.J\,-7A@0!3XP"`H!,(<*`1#0``&KZ`U>$.,*#C -M`P#@XZ@@E.4#$(+@L!"1X;,0@N$",$/B`@!3X_C__QH$`*#A!!"@X_[__^L! -M<*#CJ%"4Y08`A>(]'(;B#!"!X@8@H./^___K``!0XPH``!J\,-7A"`!3XT(` -M`!H]#(;B$@"`XAH0A>($(*#C_O__ZP$``.H`@*#C"'"@X:B0E.6\,-GA"`!3 -MXS8``!KSO8;B/K"+X@90B>(+`*#A!1"@X08@H./^___K``!0XQH```H&`*#A -M!1"@X1H@B>+^___K"#T#XP,`AN<``%#C)0``"J@0E.4+`*#A!A"!X@8@H./^ -M___KJ!"4Y3T,AN($`(#B&A"!X@0@H./^___K`#``XP`P0.,`()/E"#T#XP,P -MEN<4((/E`%"@XQ,``.H(/0/C`R"6YP``4N,%```*`#``XP`P0.,`,)/E%#"" -MY0!0H.,)``#J"P"@X080H./^___K/0R&X@0`@.($$*#C_O__ZP%0H.,```#J -M`5"@XPT@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^L``%7C3P``"@8`H.$$ -M$*#A`2"@X_[__^L``%#C,```&@``5^,0```*!`"@X000H./^___K`#"@XP0` -MH..H()3E`Q""X+`0D>&S$(+A`C"#X@P`4^/X__\:J#"4Y8$@H..\(,/AJ#"4 -MY;Z`P^$$`*#A(!"@X_[__^L`4%#B`P``&J@!G^7^___K``#@XV```.H$`*#A -M_O__ZP!0BN4``%?C!4"@`0X```JH,)7EOH#3X0XPH.,#`.#CJ""5Y0,0@N"P -M$)'ALQ""X0(P0^("`%/C^/__&@4`H.$$$*#C_O__ZP5`H.%4,)3E``!3XPD` -M``H\`9_E/!&?Y?[__^M4$)3E``!1XP,```H$`*#A_O__ZP``4.-````*!@"@ -MX000H.$"(*#C_O__ZP``4.,%``"J`@!PXS4``!K\`)_E_O__ZP``X.,R``#J -MJ`"4Y08`@.(-&X;B$1"!X@8@H./^___K!@"@X000H.'^___K``!7XQ````H$ -M`*#A!!"@X_[__^L`,*#C!`"@XZ@@E.4#$(+@L!"1X;,0@N$",(/B#`!3X_C_ -M_QJH,)3E@2"@X[P@P^&H,)3EOH##X:A0E.4&0(7B!`"@X0T;AN(1$('B!B"@ -MX_[__^L``%#C#```"@`0U.4'(-7E"##5Y0D`U>4``(WE"@#5Y00`C>4+`-7E -M"`"-Y3@`G^7^___K``#@XP```.H``*#C%-"-XO"/O>@```#C``!`X_[__^L` -M`.#C^/__ZJ@!``#$`0``^!(``.`!`````@``$$`MZ6@U`>,#,)#G``!3XQ"` -MO0AL)0'C`A#0YP,`H.&!$:#A_O__ZQ"`O>AP0"WI`$"@X6Q5`>,$,*#C!3#` -MYR``H./^___K:#4!XP,`A.<%,-3G!0!3XPL``!H5/(3B&""#X@`@@.40((/B -M"""`Y0@@@^(0((#E&#"`Y5--A.(X0(3B($"`Y7"`O>@$`%/C<("]&!4\A.(0 -M((/B`""`Y0@@@^((((#E4TV$XCA`A.(00(#E&#"`Y7"`O>CP0"WI#-!-X@!` -MH.$!4*#A:#4!XP-@D.=<$)'E``!1XPD``!I;#8#B.`"`XD80A>+^___K`!!0 -MX@,``!IT`)_E_O__ZP``H.,8``#J!`"@X3`@U>4',(WB_O__ZP!`H.$`<*#A -M_O__ZP``4.,#```*!S#=Y00`H.&#$9;G_O__ZP4`H.$($(3B_O__ZQ`PE.4! -M,(/B$#"$Y06#88;@!#"6Y0$P@^($,(;E`0"@XPS0C>+P@+WH7`(``!!` -M+>G^___K``!0X@$`H!,0@+WH\$\MZ2S03>(`$(WE`D"@X5@@D.4`,*#C&#"- -MY0$PH.,<,(WE`C"@XR`PC>4#,*#C)#"-Y0(_`N,#,-+G`0!3XRD``!K`,)#E -M"#"-Y;PPD.4,,(WEM#"0Y1`PC>6X,)#E%#"-Y0#@H.,!P*#C##"@X1\@X.,/ -M4.#C````Z@'`H.$H`(WB`Q&`X`(`D>4!,(/B`P!3 -MXPP0H-'H___:`1",X@,`4>,,X*#1`3"@T>/__]K^___K#0"@X7\]P.,_,,/C -M!""3Y0$@@N($((/E``!4XS(``-H$0:#A!$"-Y0"@H.,8L(WB"I";YP`@G>6) -MD8+@`("9Y0!`F.4?``#J!&"@X0APA.((4)3E!P"@X040H.'^___K``!0XQ8` -M`!H,`)7H!#""Y0`@@^4`4(7E!%"%Y1`PE.4!,$/B$#"$Y0``5>,,```*!#"9 -MY0$P0^($,(GE!P"@X?[__^L``%#C$```"@P`E.@$,(+E`""#Y0!`AN4$0(;E -M"@``Z@!`E.4(`*#A!!"@X?[__^L``%#CVO__"@2@BN($,)WE`P!:X=#__QH` -M4*#C#6"@X7\]QN,_,,/C!""3Y0$@0N($((/E_O__ZP4`H.$LT(WB\(^]Z!!` -M+>D`0*#A4PV`XC@`@.+^___K``!0XPX```H5#(3B_O__ZP``4.,*```*%0R$ -MX@@`@.+^___K``!0XP4```H5#(3B$`"`XO[__^L!`'#B``"@,Q"`O>@!`*#C -M$("]Z/!!+>D`4*#A6'"0Y0!`4>(A```*_O__ZPT@H.%_/<+C/S##XP0@D^4! -M((+B!""#Y00`H.$,`)3H!#""Y0`@@^4`0(3E!$"$Y6!@E.4``%;C`#"@$V`P -MA!5,$(7B_O__ZT@PE>4!,(/B2#"%Y0T@H.%_/<+C/S##XP0@D^4!($+B!""# -MY?[__^L``%;C`@``"@<`H.$&$*#A_O__ZP$`H./P@;WH<$`MZ0!@H.$!4*#A -M_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B!""#Y0!`E>4#``#J!!"@X0!`E.4& -M`*#A_O__ZP4`H.$$$*#A_O__ZP``4./V__\*#2"@X7\]PN,_,,/C!""3Y0$@ -M0N($((/E_O__ZW"`O>@00"WI``!1XP````K^___K`0"@XQ"`O>CP02WI`("@ -MX0%PH.$"4*#A`4"@X3XPTN548)+E``!6XPD``!H!`!/C`@``"O[__^L`8*#A -M!```ZEL-@.(X`(#B/A""XO[__^L`8*#A!P"@X0`0H.-`(*#C_O__ZP`PU.4! -M(-3E`B2#X0,_#^,`,$#C`S`"X`,@`N(`(,3E(R2@X0$@Q.4!(-7E`C"#X0`P -MQ.4C)*#A`2#$Y0$@U>4(`!+CK```"FP@F.4(`!+C$P``"@$\@^,`,,3E(S2@ -MX0$PQ.4$`(3BX!"(X@8@H./^___K"@"$XC(0A>(&(*#C_O__ZQ``A.(L$(7B -M!B"@X_[__^O,-)CE``!3XRH``!HK``#J$``2XQ,```H"/(/C`##$Y2,TH.$! -M,,3E!`"$XBP0A>(&(*#C_O__ZPH`A.+@$(CB!B"@X_[__^L0`(3B,A"%X@8@ -MH./^___KW#"6Y0``4^,4```:%0``ZB``$N,"```:0``2XP``H`/P@;T(!`"$ -MXBP0A>(&(*#C_O__ZPH`A.(R$(7B!B"@X_[__^L0`(3BX!"(X@8@H./^___K -MW#"6Y0``4^,!```*`3"@XP```.H`,*#C3"#5Y0``4N,'```*`"#4Y0$0U.4! -M)(+A`BJ"XW(@_^8`(,3E(B2@X0$@Q.45(-7E``!2XP<```H`(-3E`1#4Y0$D -M@N$!*8+C*!(H+AL"##X0``5N,[```**##5Y3PP@^*#,(;@L"#3X0$@@N*P -M(,/A*"#5Y3P@@N*"((;@L##2X0,ZH.$C.J#AL##"X2@PU>6#,(;@N#?3X;8P -MQ>&V(??A#R`"X@,R@N&P,,?A1C#5Y0``4^,)```*B#:6Y0``4^,&```*FR;6 -MY2@PU>52,Z#A`0`3XP$PH!-+,,45`@``&DLPU>4!`%/C%@``&B@0U>4/$`'B -M,SZ!XH,PAN"T(-/AMC#5X0,`8N`""Q#C`#"@$TLPQ14!`*`3\(&]&`,`4N$S -M'H'B@6"&X`$P@@(!,(,2`SJ@X2,ZH.&T,,;A`0"@XTL`Q>7P@;WH`0"@X_"! -MO>CP02WI`%"@X5APD.7^___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/E3`"% -MXO[__^L!`%#C`$"@`RX```I,0)7E#`"4Z`0P@N4`((/E`$"$Y01`A.4``%3C -M)@``"D@PE>4!,$/B2#"%Y0!@H.-L8(3E<&"$Y0@`A.(&$*#A6""@X_[__^L! -M,*#C9#"$Y6!@A.5U,,3E=##$Y4@PE>4!`%/C%```&@@\`^,#,)?GL"&3Y0(P -MH.$($+/E`0`1XPT``!H&`%+A!0``&DP`G^5*%P#C_O__ZT0`G^7^___K!0`` -MZ@`@#^&```SQ`!"3Y0$0@>,`$(/E`O`AX0T@H.%_/<+C/S##XP0@D^4!($+B -M!""#Y?[__^L$`*#A\(&]Z(`"``"<`@``\$\MZ4303>(`8*#A`8"@X5-]@.(@ -M<(?B!P"@X?[__^L`0%#B``#@`W0!``K^___K"#P#XP,PEN=J/X/B`%"3Y?[_ -M_^L``%7C#```"FPPEN4H`!/C"0``"@8`H.$($*#A_O__ZP$`<.,$```:!P"@ -MX000H.'^___K``#@XU\!`.H`L)CE&%"-X@L`H.$%$*#A_O__ZS"0C>(%`*#A -M"1"@X0X@H./^___KO#/=X;,_O^:\,,3A-%"$X@4`H.$)$*#A!B"@X_[__^LZ -MH(3B"@"@X080B>(&(*#C_O__ZP`PH.-5,,3E;#"6Y2``$^,!```:0``3XP@` -M``I&`(3B!1"@X08@H./^___K0`"$X@H0H.$&(*#C_O__ZQ0``.H(`!/C"``` -M"D8`A.+@$(;B!B"@X_[__^M``(3B"A"@X08@H./^___K"0``ZA``$^,'```* -M1@"$X@40H.$&(*#C_O__ZT``A.+@$(;B!B"@X_[__^L<,)WE%#"$Y;PPU.$" -M"U/C&@``&A@`C>(-$*#A&""@X_[__^L`,*#C"S#$Y1HQ`.,<()WE`P!2X1`` -M`)J\,-3A`@M3XPT``!H5,-WE1`!3XP,``!H7,-WE0P!3XPT``!H$``#J0P!3 -MXP0``!H7,-WE1`!3XP$``!H!,*#C"S#$Y;PPU.&.*`CC!A@`XP(`4^$!`%,1 -M`@``"@LPU.4!`%/C`P``&@8`H.$$$*#C`2"@X_[__^M&D-3E`9`9X@0```H& -M`*#A_O__ZP!04.(,```:P0``ZEL-AN(X`(#B1A"$XO[__^L`4%#BNP``"FPP -MEN40`!/C`@``"M`PE>4!`!/CM0``"@B@A.+8,)7E,C#$Y5Q0A.4`,*#C,3#$ -MY0X@H..P(<3A&""@X[(AQ.$((*#C"2#$Y3`PQ.5L,);E<``3XP8```K<,)7E -M``!3XR0```H8`(WB"A"@X6S[_^L@``#JS#26Y0``4^,=```*&`"-X@H0H.%E -M^__K5376Y0``4^,7```*,"#4Y0<`4N,4``"*T"/4X0$0H.,1(J#A"0`2XP0` -M`!K``!+C"@``&C``$N,$```:"@``Z@(`$^,",*`3,##$%08``.H$`!/C`S"@ -M$S`PQ!4"``#J"``3XP4PH!,P,,05Z#"5Y0$`4^,)```:`#"@XQTPQ.6\(-3A -MCC@(XP,`4N%%```*;#"6Y0$($^-"```:<```ZL@X`>,#,);G`P!3XP/QGY<, -M``#J,,L!`##+`0!`RP$`,,L!`,PX`>,#,);G'3#$Y00``.H``%GC)#D!$P,P -MEA?L,)4%'3#$Y<@X`>,#,);G`P!3XP/QGY<-``#J>,L!`'C+`0"(RP$`>,L! -M`-`X`>,#,);G3##$Y0<``.H``%GC*#D!$P,PEA<`,*`#3##$Y0$``.H`,*#C -M3##$Y1TPU.4!,$/B!`!3XP/QGY<5``#JT,L!`.#+`0`4S`$`!,P!`-#+`0`$ -M,*#C'C#$Y1\PQ.4/``#J"#"@XQXPQ.4$,*#C'S#$Y2$\`>,#,-;G``!3XP<` -M`!HR``#J"#"@XQXPQ.4?,,3E`@``Z@`PH.,>,,3E'S#$Y1TPU.4``%/C"@`` -M"B0\`>,#,);G`0!3XP,```HL/`'C`S"6YP``4^,"```:`3"@XPHPQ.4!``#J -M`#"@XPHPQ.4+`*#A"A"@X?[__^L`,*#C5##$Y5@PQ.56,,3EW""5Y4T@Q.6$ -M)I7E3B#$Y4XAU>5/(,3EF";5Y5`@Q.69)M7E42#$Y9HFU>52(,3E4S#$Y5LP -MQ.4`,)CE8#"$Y>0V`^,#,);G``!3XP4``!H'``#J!P"@X000H.'^___K``#@ -MXR<``.H&`*#A!!"@XS/_+^$P,-3E5S#$Y?[__^L-(*#A?SW"XS\PP^,$()/E -M`2""X@0@@^4&`*#A!!"@X?[__^L!`%#C"```&@T@H.%_/<+C/S##XP0@D^4! -M($+B!""#Y?[__^L!`*#C#0``Z@T@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[_ -M_^L&`*#A!!"@X90[`^,/X*#A`_"6YP$`<.(``*`S1-"-XO"/O>AP0"WI`%"@ -MX0!@#^&```SQ#2"@X7\]PN,_,,/C!""3Y0$@@N($((/EQ`"`XO[__^L!`%#C -M`$"@`PL```K$0)7E#`"4Z`0P@N4`((/E`$"$Y01`A.4``%3CW#"5%0$P0Q+< -M,(45`#"@$Q0PA!4&\"'A#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E`#"3Y0(` -M$^,````*_O__ZP0`H.%P@+WH<$`MZ0!`H.$``%'B``"@`W"`O0@`4`_A@``, -M\0T@H.%_/<+C/S##XP0@D^4!((+B!""#Y0P`D.@$,(+E`""#Y0``@.4$`(#E -MX!"$XO[__^OP,)3E`3"#XO`PA.4%\"'A#2"@X7\]PN,_,,/C!""3Y0$@0N($ -M((/E`#"3Y0(`$^,!`*`#<("]"/[__^L!`*#C<("]Z'!`+>D`0*#A``!1XP`` -MH`-P@+T(N#'1X0``4^,#```*!`"@X?[__^L!`*#C<("]Z`!0#^&```SQ#2"@ -MX7\]PN,_,,/C!""3Y0$@@N($((/E#`"1Z`0P@N4`((/E`!"!Y000@>4!`*#A -MQ!"$XO[__^O<,)3E`3"#XMPPA.4%\"'A#2"@X7\]PN,_,,/C!""3Y0$@0N($ -M((/E`#"3Y0(`$^,!`*`#<("]"/[__^L!`*#C<("]Z'!`+>D`4*#A`&`/X8`` -M#/$-(*#A?SW"XS\PP^,$()/E`2""X@0@@^7@`(#B_O__ZP$`4.,`0*`#"P`` -M"N!`E>4,`)3H!#""Y0`@@^4`0(3E!$"$Y0``5./P,)45`3!#$O`PA14`,*`3 -M%#"$%0;P(>$-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^4`,)/E`@`3XP````K^ -M___K!`"@X7"`O>@00"WI"-!-X@!`H.$",*#A/"4!XP(@T.<``%+C`""@`STU -M`0,#(,`'%P``"@$`4N,5```*`0"@X2H0H.,$((WB_O__ZP``4.,`(*`#/34! -M`P,@Q`<,```*`C#0Y0(`$^,`(*`#/34!`P,@Q`<&```*9SL"XP,PU.(0@+WH\$\MZ7S03>(4`(WE`6"@X0)`H.$@ -M((WE`@"@X4:0\.4@`(WE`9`)XA00G>5;'8'B.!"!XAP0C>4!`*#A(!"=Y?[_ -M_^L`H%#B50(`"FPPE.4``%/C!```&F`)G^5@&9_E_O__ZP``H.--`@#JU2?4 -MX00@@N*"(:#A4",(/@"#"-Y10`G>4#$*#A"""$XO[__^L``%#C -M`P``&B`)G^7^___K``"@XSP"`.I@4(WB!@"@X040H.'^___K!0"@X0`0H..P -M(=3A_O__ZS0U`>,4()WE`S"2YP0P0^(,,(WE*#"$XB0PC>4@`(3B&`"-Y0A@ -MG>4`@*#C8+"-X@90H.&P,-;A`3N#X[`PQN&R<=3A!V"&X`P0G>4!<&?@'C#4 -MY0``4^.T```*'3#4Y0$P0^($`%/C`_&?EZ@``.K\T0$`8-(!`(S4`0"`TP$` -M_-$!`"`QVN4@,,3E(3':Y2$PQ.4B,=KE(C#$Y4PPU.4#,Z#A(S#$Y1(.H./0 -M((KA_Q3@XP$`4N$#```:``!3XP``H`,`$*`#`P``"@$`H.,`$*#C`@"0X`,0 -MH>`2+J#C\@"*X8H``.H``%GC(P``"B$QVN4@,,3E(3':Y5\P`^(@,(/C(3#$ -MY2`QVN4B,,3E3##4Y0,SH.$@,(/C(S#$Y2(QVN4D,,3E(S':Y24PQ.4D,=KE -M)C#$Y24QVN4G,,3E$@Z@X]`@BN$!`'+C!```&O\?#^,!`%/A``"@`P`0H`,# -M```*`0"@XP`0H.,"`)#@`Q"AX!(NH./R`(KA9```ZB$QVN4@,,3E(3':Y5\P -M`^(@,(/C(3#$Y2`QVN4B,,3E(#"@XR,PQ.4B,=KE)##$Y2,QVN4E,,3E)#': -MY28PQ.4E,=KE)S#$Y1(.H./0((KA`0!RXP0``!K_'P_C`0!3X0``H`,`$*`# -M`P``"@$`H.,`$*#C`@"0X`,0H>`2+J#C\@"*X4(``.H``%GC(0``"B`QVN4@ -M,,3E(3':Y2$PQ.4`,*#C(C#$Y4PPU.4#,Z#A(#"#XR,PQ.4B,=KE)##$Y2,Q -MVN4E,,3E)#':Y28PQ.4E,=KE)S#$Y1(.H./0((KA`0!RXP0``!K_'P_C`0!3 -MX0``H`,`$*`#`P``"@$`H.,`$*#C`@"0X`,0H>`2+J#C\@"*X1X``.H@,=KE -M(##$Y2$QVN4A,,3E`#"@XR(PQ.4@`*#C(P#$Y2(QVN4D,,3E(S':Y24PQ.4D -M,=KE)C#$Y24QVN4G,,3E$AZ@X]$@BN$!`'+C!```&O\/#^,``%/A``"@`P`0 -MH`,#```*`0"@XP`0H.,"`)#@`Q"AX!(NH./R`(KA!@"@X1@0G>4>(-3E_O__ -MZQXPU.4#8(;@!W!CX```6.,`,*`3!#"-%04``!H&`*#AO!#4X?[__^L$`(WE -M`&"&X`=P8.`?,-3E``!3XP(```H*(-3E``!2XP=P8Q```%GC"P"@X080H.$4 -M()05!R"@`?[__^L`<*#A`&"&X!\@U.4``%+C!P``"@HPU.4``%/C!```"@8` -MH.$D$)WE_O__ZQ\PU.4#8(;@`8"(X@``6>,#```:"P"@X?[__^L!`%#CNP`` -M&GB`[^8<@,3ELB'4X1X0U.4$`)WE`0!8XP``H!,$`(WE"C#4Y0``4^,?,-05 -M`B"!X`=P@N`$$)WE`7"'X`-PA^`8<(3EL##5X0$[P^.P,,7A`#"@XUPPS>5= -M,,WE7C#-Y5\PS>5&8-3E7%"4Y0,`5>$#```:'`"=Y2`0G>7^___K`%"@X75P -MU.4=,-3E`@!3XY(``!H``%7CD```"D0PC>(`(*#C!""#Y`0@@^0$((/D`""# -MY6R`E.4!`!;C$P``"B@Y`>,4()WE`P"2YP`"@N!E#8#B+`"`XD00C>(0(*#C -M_O__ZP$`4.,%`0`**#D!XQ0`G>4#$)#G`1*`X"P`C>)E'8'B+!"!XO[__^L( -M``#J\`"%XD00C>(0(*#C_O__ZP$`4./V```*+`"-XO`0A>+^___K=W"OY@1P -MA^*'<:#A=W#OY@=PB.`'4*#A`3#UY0$`$^,+```*+`"-XA`0A^(&(*#C_O__ -MZP`PU>4"`!/C+`"-XA@0AQ(*$(<"!B"@X_[__^L*``#J+`"-X@00A^(&(*#C -M_O__ZP`PU>4"`!/C+`"-XA`0AQ(*$(<"!B"@X_[__^M-,-3E``!3XS`PU!5< -M,,T5+`"-XEP0C>($(*#C_O__ZP!@H.,TA0'C+*"-X@:PH.$$4*#A)P``Z@-` -M%^(!0*`3)W&$X+(1U>$>(-7E`0""X`=Q@.`!8(;B`P!6X0T``!H8,)7E`Q!A -MX`$@8N`*,-7E``!3XPLPH`$?,-45`D!CX`H`H.$'$*#A!""@X?[__^L$<(?@ -M#P``ZA0PG>4(0)/G!!!AX`$@8N`*,-7E``!3XPM`H`$?0-45`D!DX`H`H.$' -M$*#A!""@X?[__^L?,-7E`T"$X`1PA^`<,-7E`P!6X=3__[H%0*#A5%"-XBP` -MC>(%$*#A_O__ZP<`H.$%$*#A"""@X_[__^L8()3E""""XA@@A.4``%+C`P`` -M"@`PH.,(,(/B`@!3X?S__SH*,-3E``!3XPH``!H>``#J`S`6X@$PH!,F88/@ -M$`"=Y09A@.`&`*#A"!"=Y;(AU.'^___K3_[_ZATPU.4!,$/B!`!3XP/QGY4$$*#A_O__ZP``6>,`,*`3,S#$%0$`H!->```:7#"4 -MY1P@U.4!`%+C-"4!$Q0`G14"$)`7&!"4!10`G>7A)]#E!P!2XP,``)H"+P+C -M`B#0YP``4N,2```*:"L"XQ0`G>6R()#A`0!2X0$`H#,S`,0U2```.DTAT^4` -M`%+C`0"@$S,`Q!5#```:3#'3Y0``4^,",*`3`#"@`S,PQ.4!`*#C/```ZA0` -MG>7**]#E!0!2XPD``!I3(-3E`0!2XP8``!K,*`'C`B"0YP0`4N,",*`#,S#$ -M!0$`H`,N```*4R^@X[(@D^$``%+C"@``"DTAT^4``%+C`0"@$S,`Q!4E```: -M3#'3Y0``4^,",*`3,S#$%0$`H.,?``#J3C#4Y0``4^,.```*%""=Y=,[TN7? -M)]+E``!2XP0```H",$/B6S,)#A`P!1X0$`H(,S`,2%!@``BE,PU.4!`%/C`0"@ -M`S,`Q`4`,*`3,S#$%0$`H!-\T(WB\(^]Z````.,``$#C_O__ZP``H./X___J -MX`(```P3``#X`@``$$`MZ0!`H.'^___K!`"@X?[__^L,`(3B_O__ZR``A.+^ -M___K*`"$XO[__^LP`(3B_O__ZS@`A.+^___K0`"$XO[__^M4`(3B_O__Z\P` -MA.+^___KU`"$XO[__^L0@+WH\$$MZ0"`H.%88)#E1$"0Y=APD.4&`*#A(#L# -MXP_@H.$#\);G"`"@X?[__^M$,)CE``!3X_"!O0@>6X3B!@"@X000H.'^___K -M>$"$X@4`5.'Y__\:!U"@X0I-A^)2?*#C!@"@X040H.$'(*#A_O__ZZ!0A>($ -M`%7A^/__&D``F.4``%#C`0``"@08!^/^___KU`"8Y0``4.,!```*H1^@X_[_ -M_^OH`(CB_O__Z^Q`F.4%6X3B`GN@XP8`H.$$$*#A!R"@X?[__^N@0(3B!0!4 -MX?C__QKH`)CE``!0XP$```H$%`'C_O__ZP8`H.'^___K\(&]Z!!`+>D`0*#A -M_O__ZP@`A.+^___K`#"@XQ`PA.40@+WH$$`MZ0!`H.$`$*#CB""@X_[__^L$ -M`*#A_O__ZP@`A.+N___K'`"$XNS__^LP`(3BZO__ZT0`A.+H___K6`"$XO[_ -M_^M@`(3B_O__ZQ"`O>CP3RWI#-!-X@"@H.$!<*#A_O__ZPH`H.$`$*#C_O__ -MZPP`BN(`$*#C_O__ZUAPBN48`(KB_O__ZR``BN+^___K*`"*XO[__^LP`(KB -M_O__ZS@`BN+^___K3`"*XO[__^L$"`?C_O__ZT``BN4``%#C`&"@`T1@B@5X -M```*`P"`X@-`P.-$0(KE3("*XAY;A.(`8*#C!`"@X?[__^MH<(3E9&"$Y6!@ -MA.5L8(3E<&"$Y00`H.$($*#A_O__ZWA`A.(%`%3A\O__&@$\H.-(,(KE*CD` -MXU0PBN7$`(KB_O__Z\P`BN+^___KH0^@X_[__^O4`(KE``!0XU<```H#`(#B -M`T#`X]A`BN7$L(KB'CZ$X@0PC>4`4*#C4IR@XP2`H.$$`*#A_O__ZQ10A.4( -M<(3EN%'$X0<`H.$$$*#A"2"@X?[__^L`8%#B1```"KI1Q.$$`*#A"Q"@X?[_ -M_^L$,)WE`P!4X:!`A!+K__\:!#"@X]PPBN7@`(KB_O__ZP0$`>/^___KZ`"* -MY0``4.,R```*`P"`X@-`P./L0(KEX#"*X@0PC>5-C83B(("(X@"0H.,!L*#C -M!%"@X00`H.'^___K%)"$Y0APA.6XL<3A!P"@X000H.$"*Z#C_O__ZP!@4.(> -M```*!`"@X000G>7^___K"`!4X:!`A!+M__\:(#"@X_`PBN4'`*#A_O__ZX@` -MFN6,$-KE_O__ZP$PH..<,,KED`"*X@`0H./^___K`#"@X[0PBN6X,(KEO#"* -MY<`PBN4<.P/C`S"7YP``4^,#```*!P"@X3/_+^$```#J`&"@XP8`H.$,T(WB -M\(^]Z```4N,-``#:`##1Y0``4^$`,*`3`P``&@8``.H#P-'G``!_R_A`0"@XQ[_ -M+^$!`*#C'O\OX1!`+>D(T$WB`$"@X0<0S>4!`%'C$```&N$Z`^,#,-#G``!3 -MXPP```H=,P/C`S#0YP``4^,(```*`""@XQTS`^,#(,#G)A"@XS,LA.(<((+B -M9#L#XP_@H.$#\)3G!`"@X2D0H.,'((WB9#L#XP_@H.$#\)3G!S#=Y0``4^,; -M```:X"H#XP(PQ.?A*@/C`C#$Y^(J`^,",,3GXRH#XP(PQ.?8*@/C`C#$YX4S -M`^,#,-3G`0!3XPT``!H=,P/C`S#4YP``4^,)```:`B"@XQTS`^,#(,3G!`"@ -MX280H.,S+(3B'"""XF0[`^,/X*#A`_"4YPC0C>(0@+WH<$`MZ1#03>*HS`/C -M#,"0YP``7.,"```:^`"?Y?<7`./^___K`%","```:X`"?Y3D7`./^ -M___K`<"@X1A`_.4$`%3C*P``&@9@W.4!0-SE"0!4XRH``!H"7(7B!D"@X0$` -M5N,*```*`@``.@<`5N,D```:"0``Z@``4^,A```*(C#5Y0``4^,>```:_O__ -MZQP``.H``%/C(C#%!1D``.H`,*#C##"-Y0@PC>4B,,7E"`",XB`00N(#(*#A -M##"-XO[__^L``%#C#@``"@@PC>(`,(WE#!"=Y0\@H.,`,*#C_O__ZP``4.,` -M,*`3`3"@`R(PQ>4#``#J?P!4XP5`W`4````*`$#@XP0`H.$0T(WB<("]Z&0# -M``#P3RWI=-!-X@!0H.$`P*#C<#"-X@3`(^4($('B&!"-Y0@@0N(4((WE`0"@ -MX0(0H.$,(*#A_O__ZP!`4.(`(*`#'""-!9````HX,(7B+#"-Y:?/A>(HP(WE -M*BZ%X@(@@N(D((WE`#"@XQPPC>4T8(WB!'"&X@2`A^($H(CB!)"*X@2PB>($ -MP(OB#,"-Y00@C.(0((WE!#""XB`PC>4`(*#C:R#-Y5P@C>5@(,WE`""&Y0`@ -MA^4`((CE`""*Y0`@B>4`((OE#,"=Y0`@C.40,)WE`""#Y2`PG>4$((/DL"## -MX60@C>4!,*#C(#/%Y60PC>(`,(WE!`"@X6P0G>5K,(WB_O__ZV0PG>4!`%/C -M+P``&FO`W>44*`%/C"C"@$\PRA17R -M(M7E^1+5Y:$PH.$#`%+A!```FL0RE>4#`%/C`S"@$\0RA14;``#J`P!2X00` -M`"K$,I7E`@!3XP(PH!/$,H45%```Z@$`$>,$```*Q#*5Y0(`4^,",*`3Q#*% -M%0T``.K$,I7E`P!3XP,PH!/$,H45"```ZL0RE>4!`%/C`3"@$\0RA17,,I7E -M"P!3XPLPH!/,,H45+@``Z@`0H.-D$(WE!@"@X28@H./^___K9#"-X@`PC>4$ -M`*#A;!"=Y0\@H.,&,*#A_O__ZP``4.,(```**`"=Y080H.$&(*#C_O__ZR0` -MG>4&$(;B9""=Y08@0N+^___K`#"@XV0PC>5D,(WB`#"-Y00`H.%L$)WE$2"@ -MXUPPC>+^___K``!0XV`PW14<,\45<#"-X@0`,^44()WE`A!@X!C`G>4$(&S@ -M``"$X`$08N``(*#C_O__ZP!`4.*#__\:'`"=Y730C>+PC[WH\$#<#XP-`A.?=#83B)`"`X@40H.$%(*#A_O__ZP`@`..H-P/C -M`"!`XP,@A.>L-P/C`T"$Y]X-A.(8`(#B!1"@X04@H.'^___K`"``X]PW`^,` -M($#C`R"$Y^`W`^,#0(3GWPV$X@P`@.(%$*#A!2"@X?[__^M].@/C`U#$Y_[_ -M_^NK.@KCJCI*XY,@@^"C,*#A@S"#X```8^`!`(#B0BH#XP(`Q.<."X3B!1"@ -MX3P@H./^___K#CN@X[-0A.$)`(?@!1"@X0P@H./^___K!("@XWXZ`^.S@(3A -M`2"@X^H]H.,#(,3G`P"$X`(`@.`%$*#A(""@X_[__^NA.@/C`U#$Y\0Z`^,# -M4(3GR#H#XV(OH..S((3ARCH#XP-0Q.?K#83B"P"`X@40H.$-(*#C_O__ZP)@ -MAN(&`*#A!1"@X0@@H.'^___K!@"@X0D0H.$*(*#A_O__ZSP`A^(%$*#A)B"@ -MX_[__^OPA[WH<$`MZ0!`H.$!4*#A`3!!X@(`4^,2``"*`!``XP`00./^___K -M``!0XW"`O0@$`*#A!1"@X?[__^MX.P/C`\"4YP``7.-#```*!`"@X0$0H.,` -M(*#C`3"@X3S_+^$!`*#C<("]Z```4>,Z```:+#H#XP,PD.<``%/C&0``"MT- -M@.(D`(#B_O__Z]X-A.(8`(#B_O__Z]\-A.(,`(#B_O__ZRPZ`^,#,)3G``!3 -MXP`@H!,L.@,3`R"$%R0Z`^,#,)3G``!3XP`@H!,D.@,3`R"$%PX+A.(\`(#B -M`!"@XPH@H./^___K>#L#XP/`E.<``%SC!```"@0`H.$!$*#C`""@XP(PH.$\ -M_R_AT#,#XP,PE.<``%/C#P``&@`P`.,`,$#C`#"3Y<@C`^,"()3G9!"@XY$" -M`>#3+03C8B!!XY(!@>#.#83B%`"`XB$3@^#^___K`0"@XW"`O>@!`*#C<("] -MZ'!`+>D`4*#AVTV`XC!`A.($`*#A`!"@XW`@H./^___K`"``XS<\H.,`($#C -M`R"%YP0W`^,#4(7G!`"@X0`0H.,!(*#A_O__ZW"`O>@00"WI+#H#XP,PD.<` -M`%/C$("]"`$0H./^___K$("]Z!!`+>DL.@/C`S"0YP``4^,0@+T(?3H#XP,@ -MT.D%$*#C_O__ZQ"`O>@00"WI`$"@ -MX2PZ`^,#,)#G``!3XQ"`O0C^___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/E -M+#H#XP,PE.<&`%/C!P``&C@X`^,#,-3G`0!3XPP``!H$`*#A`A"@X_[__^L( -M``#J"0!3XP8``!KZ.0/C`S#4YP$`4^,"```:!`"@X0,0H./^___K#2"@X7\] -MPN,_,,/C!""3Y0$@0N($((/E_O__ZQ"`O>CP02WI`$"@X0%0H.$L.@/C`S"0 -MYP``4^,S```*W#H#XP,PD.<%`%/A+P``"M@Z`^,#,-#G``!3XRL```K<.@/C -M`Q"`YP``4N,C```*'`"@X_[__^L`<*#A`&"@X0``4.,``*`#\(&]"`P`H./^ -M___K`("@X0``4.,$```:!P"@X1P0H./^___K``"@X_"!O>@'(*#C)`"`Z`!0 -MH.,(4(#E%`"'XO[__^LY,*#CL##'X02`A^4,,*#C"#"'Y0Q0A^404(?E!0N$ -MXB@`@.('$*#A_O__ZW``[^;P@;WH!1"@X?[__^L!`*#C\(&]Z`$`H./P@;WH -M\$\MZ4??3>((`(WE`5"@X0)@H.$`0*#C%$&-Y10`C>($$*#A`2R@X_[__^L0 -M0(WE+#H#XP@`G>4#,)#G!`!3X9,```H,`%;CD0``F@Q0A>(,8$;B!0"@X080 -MH.$$(*#A13^-XO[__^L`0%#BB```"A1PC>(0@(WB#*"@XT6?C>(`L*#C`("- -MY00`H.$4$9WE"B"@X04"(-'G -M``!2XP,```K@*@/C`B#1YP,`4N%Q```*X"H#XP@`G>4",,#G%3#=Y:,3H.'B -M*@/C`A#`YW\P`^+A*@/C`C#`YQ`PG>4"`%/C`%"@DRL``)H($)WEZSV!XBB0 -M@^(PL(/B.#"#X@PPC>4`4*#C`D"@X_RN#^/_KT_C%'"-X@2`H.,(()WE!3"" -MX.L]@^(@,(/B1@^-X@0@@.`*(-+G!"##Y05AH.$!$(3B!@")X'$0Y^8((*#A -M_O__ZP40A.(&`(O@<1#GY@@@H.'^___K"1"$X@P@G>4&`(+@<1#GY@@@H.'^ -M___K#4"$XG1`[^8!4(7B=5#OYA`PG>4#`%3AW___.N,Z`^,(`)WE`U#`Y^(Z -M`^,#,-#G`0!3XPH``!H!(*#CV#H#XP,@P.>%,P/C`S#0YP(`4^$I```:"`"= -MY0(0H.'^___K)0``Z@``5>,'```*`2"@X]@Z`^,($)WE`R#!YP@`G>4"$*#A -M_O__ZQL``.K8.@/C"""=Y0,PTN@00"WI`#"@ -MX2PJ`^,"()#G"0!2XP$```H+`%+C!0``&B0J`^,"()/G`0!2XP$0H!,D*@,3 -M`A"#%R@J`^,"()/G+!H#XP$0D^DMH.,"$-/G`""@XP(PH.'^___K$("]Z!!`+>D0T$WB`$"@X20W -M`^,#$-#GWC?0Y0$`4^$#```*WA?`Y0`@H.,",*#A_O__ZR@Z`^,#,)3G+"H# -MXP(@E.<"`%/A+"H#$P(PA!=8-P/C`P"4YU`W`^/4((/A-QR$XB@0@>(`$(WE -M3!<#XP$0E.<$$(WET!"@XP@0C>7^___K$-"-XA"`O>@P0"WI#-!-X@!`H.$( -M4(WB`3"@XP$P9>7P.0/C`Q#0YP`@H.,",*#A_O__ZP0`H.$,$*#C!2"@X60[ -M`^,/X*#A`_"4YP0`H.'^___K`#``XP`P0.,`$)/EWPV$X@P`@.(*$('B_O__ -MZPS0C>(P@+WH,$`MZ0S03>(`0*#A"%"-X@$PH.,!,&7E`C@#XP,0T.<`(*#C -M`C"@X?[__^L$`*#A#!"@XP4@H.%D.P/C#^"@X0/PE.<$`*#A_O__ZP`P`.,` -M,$#C`!"3Y=\-A.(,`(#B"A"!XO[__^L,T(WB,("]Z#!`+>DLT$WB`%"@X01` -MC>($`*#A`!"@XR0@H./^___K!`"$XND=A>(+$('B!R"@X_[__^L',*#C!#"- -MY2PZ`^,#,)7G!0!3XP4@H!,L.@,3`R"%%_[__^L-,*#A?TW#XS]`Q.,$,)3E -M`3"#X@0PA.4%`*#A!!"-X@$@H./^___K!#"4Y0$P0^($,(3E_O__ZRS0C>(P -M@+WH$$`MZ04`4>,!\9^7#@``ZHSP`0"4\`$`G/`!`*3P`0"P\`$`K/`!`/[_ -M_^L0@+WH_O__ZQ"`O>C^___K$("]Z/[__^L0@+WH_O__ZQ"`O>@P0"WI1]]- -MX@%0H.$/(,WE&$"-X@0`H.$`$*#C`2R@X_[__^L`$*#C%!"-Y5`PH.,8,,WE -M;S"@XQDPS>5E,.#C&C#-Y0DPH.,;,,WE!`"$X@$@H.,0,(WB`3!#XO[__^L$ -M((#B%#"-X@`PC>4%`*#AW1"@XP0PH.'^___K%`"=Y4??C>(P@+WH\$$MZ1'> -M3>(`0*#A`6"@X0*`H.$#<*#A$%"-X@4`H.$`$*#C`2R@X_[__^L`,*#C##"- -MY5`@H.,0(,WE;R"@XQ$@S>5E(.#C$B#-Y0D@H.,3(,WE`B"@XQ0@S>46,,WE -M%2#-Y2`@H.,7(,WE&##-Y0TPH.,9,,WE&C/4Y14@@^(B)*#A&R#-Y14P@^(: -M,,WE#`"%XBT>A.(&(*#C_O__ZV0SE.4#`%/C`#"@XR(PS>5_,.`#"#"@$R,P -MS>4`,*#C)##-Y1X@H.,E(,WE)C#-Y5`@H.,G(,WE#2#@XR@@S>4$(*#C*2#- -MY2HPS>4!(*#C*R#-Y2PPS>40,*#C+3#-Y1$PH.,N,,WE&B/4Y4(TH.$O,,WE -M,"#-Y3$`C>*^'X3B`A"!XO[__^L:4]3E(5"%XL0RE.4"`%/C%0``&A$NC>(% -M,(+@#R"@XP`A0^4!,(7B$$"-X@00@^`&((?B(@2@X0$`P>4#(,3G`P"%X@`` -MA.`H$9WE!B"@X_[__^L)4(7B!0"$X`@0H.$'(*#A_O__ZP50A^`,,(WB`#"- -MY08`H.'=$*#C!2"@X1`PC>+^___K#`"=Y1'>C>+P@;WH\$`MZ47?3>(`8*#A -M`7"@X1``C>(`$*#C`2R@X_[__^L`,*#C"#"-Y5`PH.,0,,WE;S"@XQ$PS>5E -M,.#C$C#-Y0DPH.,3,,WE_CX/X_\_3^,B*0#C$1Z-XK,@@>',,I;E#0!3X_X^ -M#P/_/T\#(BD$`[,@@0$00(WB!`"$X@(0H.,!(*#A`C!$XO[__^L$4(#B!0"$ -MX`,0H.,&(*#C+3Z&XO[__^L`((7@"#"-X@`PC>4'`*#AW1"@XP0PH.'^___K -M"`"=Y47?C>+P@+WH\$(`4*#A`9"@X0\@S>4.,,WE`&"0Y7\PH.,_ -M,4T`(WB`!"@XP$LH./^___K%#"-X@`@ -MH.,$((/D!""#Y`0@@^0$((/D!""#Y`0@@^0$((/D`""#Y5,-AN(@`(#B_O__ -MZP!`4.)A```*!@"@X0@0A.+^___K;`"4Y0`0H.-H(*#C_O__ZVR`E.4(<*#A -M`*"@XRB@Y^4!H,?E+`"(X@D0H.$&(*#C_O__Z[5?A>("4(7B,@"(X@40H.$& -M(*#C_O__ZS@`B.(%$*#A!B"@X_[__^L((*#AOA/RX=PW`..S`);A#Q`!X@`2 -M@>&P$,+ALR"6X0$@@N*S((;AL##7X?PPP^/0,(/CL##'X010H.$8,*#C%#"E -MY4``B.(!$*#C3R^-X@,@@N(%,*#A_O__ZP00H.-.+XWB!3"@X?[__^L!$*#C -M32^-X@,@@N(%,*#A_O__ZQ"`C>(!$*#C`B!(X@4PH.'^___K`)"@X5`PH.,T -M,,WE;S"@XS4PS>5E,.#C-C#-Y0DPH.,W,,WE-'"-X@0`A^(*$*#A`2"@XP$P -M2.+^___K!("`X@$PH.,4,,WE%:#-Y0@`A^`,$*#C`B"@XQ0PC>+^___K`""( -MX`!0C>4)`*#AW1"@XP]Z!!`+>D!,*#A"A"!X@`@H.,>,-/E=/__ZP$`H.,0@+WH\$(! -M0*#A`Y"@X0!0D.4$,*#C=S#-Y0DPH.-V,,WE!S#2Y74PS>50/P;CFCE`XW`P -MC>4(,*#C;S#-Y0,`C>``$*#C9""@X_[__^M3#87B(`"`XO[__^L`8%#B6@`` -M"@4`H.$($(;B_O__ZVP`EN4`$*#C:""@X_[__^ML@);E"'"@X0"@H.,HH.?E -M`:#'Y2P`B.($$*#A!B"@X_[__^L-2X7B$4"$XC(`B.($$*#A!B"@X_[__^LX -M`(CB!!"@X08@H./^___K"""@X;X3\N'<-P#CLP"5X0\0`>(`$H'AL!#"X;,@ -ME>$!((+BLR"%X;`PU^'\,,/CT#"#X[`PQ^$&0*#A&#"@XQ0PI.5``(CB`1"@ -MXW<@C>($,*#A_O__ZP$0H.-V((WB!#"@X?[__^L$$*#C<""-X@0PH.'^___K -M`1"@XV\@C>($,*#A_O__ZP$0H.-U((WB!#"@X?[__^L(H,WE4#"@XPDPS>4- -M,.#C"C#-Y00PH.,+,,WE$#"@XPPPS>4(,*#C#3#-Y0Z@S>4",*#C#S#-Y2DT -MH.$0,,WE$9#-Y0!`C>7=$*#C"B"@XP@PC>+^___K%#"6Y1@PAN4%`*#A!A"@ -MX?[__^MXT(WB\(>]Z/!/+>FLT$WB`%"@X0B@@>((D$+B"@"@X0D0H.$`(*#C -MH#"-XO[__^L``%#C`#"@$R@PC14%```:S#*5Y0L`4^,+,*`3S#*%%0(PH.,H -M,(WE"@"@X0D0H.$`(*#CI#"-XO[__^L`0%#B"@``&L0RE>4!`%/C`3"@$\0R -MA17,,I7E"P!3XPLPH!/,,H45`C"@XR@PC>7<``#J`""@XY\@S>68((WEC""- -MY9`@S>64((WE,#"-X@0@@^0$((/D!""#Y`0@@^0$((/D!""#Y`0@@^0$((/D -M!""#Y`0@@^0$((/D!""#Y+`@P^$OOH7B`["+XB"PC>6G/X7B%#"-Y2T^A>(L -M,(WE*CZ%X@(P@^(,,(WE,CZ%X@$P@^(D,(WEVC^%X@,P@^(0,(WEGX"-XIA@ -MC>(P,(WB!3"#XA@PC>5D<(WB!C"'XAPPC>4`8(WE!`"@X:00G>4`(*#C"#"@ -MX?[__^N8,)WE`0!3XPT``!J?,-WE``!3XPH```K$,I7E`0!3XP$PH!/$,H45 -MS#*5Y0L`4^,+,*`3S#*%%9\PW>4H,(WEF0``Z@`PH..8,(WE`&"-Y00`H.&D -M$)WE"2"@XPLPH.'^___K``!0XP8```J8,)WE!@!3XP,```H@`)WE`!"@XP8@ -MH./^___K`#"@XY\PS>68,(WE`&"-Y00`H.&D$)WE!""@XP@PH.'^___K``!0 -MXT0```J?(-WE^2+%Y?(RU>6B(*#A`@!3X2```!H/`%/C#0``&L0RE>4!`%/C -M`3"@$\0RA17,,I7E"P!3XPLPH!/,,H45Q#*5Y0,`4^,),*`3*#"-%2\``!HD -M``#JS#*5Y0H`4^,*,*`3S#*%%9\PW>4!`!/C!```"L0RE>4"`%/C`C"@$\0R -MA14B``#JQ#*5Y0,`4^,#,*`3Q#*%%14``.H"`%/A"```FLPRE>4*`%/C"C"@ -M$\PRA17$,I7E`P!3XP,PH!/$,H45"@``ZLPRE>4*`%/C"C"@$\PRA17$,I7E -M`@!3XP(PH!/$,H45"0``Z@DPH.,H,(WE%`"=Y2P0G>4&(*#C_O__ZPP`G>4D -M$)WE02/5Y?[__^L`,*#CF#"-Y0!@C>4$`*#AI!"=Y1$@H..,,(WB_O__ZP`` -M4..0,-T5'#/%%90PC>(`,(WE!`"@X:00G>4+(*#C,#"-XO[__^L``%#C!``` -M"C0@W>5J(\7E$`"=Y1@0G>7^___K`!"@XY@0C>4'`*#A)B"@X_[__^L`8(WE -M!`"@X:00G>4/(*#C!S"@X?[__^L``%#C"```"A0`G>4'$*#A!B"@X_[__^L, -M`)WE'!"=Y9@@G>4&($+B_O__ZZ0`G>4)$&#@!#!JX```A.`!$&/@`""@XZ0P -MC>+^___K`$!0XD[__QHH`)WEK-"-XO"/O>CP3RWIE-!-X@!`H.$`,*#CC#"- -MY8@PC>6V.,WA@#"-Y60SD.4``%/C!0``&LPRD.4+`%/C"S"@$\PR@!4!D*#C -MXP``Z@AP@>((@$+B!P"@X0@0H.$`(*#CB#"-XO[__^L`8%#B(P``"N)0A.(% -M`*#A`!``XP`00.,#(*#C_O__ZP``4.,B```*@#"-X@`PC>4&`*#AB!"=Y1(@ -M`>.&,(WB_O__Z[8XW>&S/[_F$!`%/C!0``&@4`H.$`$`#C`!!` -MXP,@H./^___K#P``Z@4`4^,%`*#A`!```P`00`,`$``3`!!`$P,@H./^___K -M!@``ZLPRE.4+`%/C"S"@$\PRA!4"D*`3L```&JX``.H'`*#A"!"@X0`@H.., -M,(WB_O__ZP!04.(&```:S#*4Y0L`4^,+,*`3S#*$%0*0H!.B```:H```ZJ4J+H3B`B""XB@@C>4R/H3B`3"#XB0PC>4OKH3B`Z"* -MXBR@C>4`D*#C0&"-X@2PAN($((OB#""-Y00P@N(0,(WE!""#XA0@C>4$,(+B -M&#"-Y00@@^(<((WE!#""XB`PC>4$((/B/""-Y3B0C>4"D*#A`#"@XW\PS>5X -M,(WE`#"&Y0`PB^4,()WE`#""Y1`@G>4`,(+E%""=Y0`P@N48()WE`#""Y1P@ -MG>4`,(+E(""=Y0`P@N4)(*#A!#""Y`0P@N0$,(+D!#""Y+`PPN%T,(WES#*4 -MY0D`4^,),*`3S#*$%7@PC>(`,(WE!0"@X8P0G>4$(*#C?S"-XO[__^L``%#C -M*```"G\@W>7Y(L3E\C+4Y:(@H.$"`%/A%P``&@\`4^,(```:Q#*4Y0$`4^,) -M,*`#.#"-!0$PH!/$,H05"2"@$S@@C147``#J?S#=Y0$`$^,$```*Q#*4Y0(` -M4^,",*`3Q#*$%0\``.K$,I3E`P!3XP,PH!/$,H0500``Z@(`4^$$``":Q#*4 -MY0,`4^,#,*`3Q#*$%3H``.K$,I3E`@!3XP(PH!/$,H05`#"@XW@PC>5X,(WB -M`#"-Y04`H.&,$)WE"2"@XPHPH.'^___K``!0XP8```IX,)WE!@!3XP,```HL -M`)WE`!"@XP8@H./^___K=#"-X@`PC>4%`*#AC!"=Y0L@H.,&,*#A_O__ZP`` -M4.,+```*X0+4Y040AN)T(-WE_O__ZP``4.,%```:S#*4Y0L`4^,+,*`3S#*$ -M%0>0H.,,``#JD#"-X@0`,^4($&#@!2!GX```A>`!$&+@`""@X_[__^L`4%#B -M@/__&CB0G>4```#J`I"@XPD`H.&4T(WB\(^]Z#0`G>4P$)WE!B"@X_[__^LH -M`)WE)!"=Y4$CU.7^___KO___ZG!`+>D8T$WB`%"@X0%`H.$`,*#C%#"-Y1`P -MC>6^,,WA&&"!XB``@>(($$+B`R"@X10PC>+^___K``!0XS(```H0,(WB`#"- -MY100G>4((`'C#C"-XO[__^L``%#C*@``"KXPW>&S/[_F$(`%/C -M"```"@(``(H$`%/C'```&@H``.J``%/C#@``"@$,4^,7```:$0``ZN(`A>(` -M$`#C`!!`XP,@H./^___K$```ZN(`A>(`$`#C`!!`XP,@H./^___K"@``ZN(` -MA>(`$`#C`!!`XP,@H./^___K!```ZN(`A>(`$`#C`!!`XP,@H./^___K!0"@ -MX0H0A.(&(*#AOC#=X3_]_^L!`*#C&-"-XG"`O>CP3RWI/-!-X@-@H.$`,*#C -M-#"-Y;(SS>$L,(WEQ#*0Y0,`4^,%`*`3?@``&K`PT>'\,`/B``!3XP0PH`,* -M,*`3&`"#X@``@>`0`(WE&"!"X@(@8^`,((WE`A"@X0`@H.,L,(WB_O__ZP!` -M4.($`*`#;```"GH>AN(.$('B%!"-Y7L^AN(&((/B'""-Y0@P@^(8,(WE'SV& -MX@$P@^(D,(WE?AZ&X@00@>(@$(WE-*"-X@*PH.,`@*#C!%"@X0"@C>4%`*#A -M+!"=Y0L@H.$R,(WB_O__ZP``4..R,]T1M#?&%0"@C>4%`*#A+!"=Y0T@H.,( -M,*#A_O__ZP``4.,]```*-`"=Y?[__^L`<%#B.0``"@"@C>4%`*#A+!"=Y0T@ -MH.,',*#A_O__ZQ0`G>4'$*#A!B"@X_[__^L<`)WE!A"'X@L@H.'^___KMB<` -MX[(PEN&S/[_FLC"&X0B0A^(8`)WE"1"@X0@@H./^___K"$#9Y0F0B>(``%3C -MP(?&!0@```K`1\;EA$&@X20`G>4)$*#A(`!4XP0@H#$@(*`C_O__ZP20B>#B -M-P#CLX"&X;`PV>&S/[_F,!`%/A"0``&K(@V>&R+[_F`!$&/@"""@X2PPC>+^___K`%!0XJ3__QH\T(WB -M\(^]Z/!/+>E($P"/E'V#1Y2``@>(( -M$$+B#""@X?[__^L`0%#BL@``"A0PC>(`(*#C!""#Y`0@@^0$((/D!""#Y`0@ -M@^0$((/D!""#Y`0@@^0$((/DL"##X3P@C>6P),WA3""-Y4PPC>(`,(WE!`"@ -MX500G>4/(*#C%#"-XO[__^L``%#CF@``"BT.BN(4$(WB!B"@X_[__^L``%#C -ME@``"@T-BN("`(#B&A"-XF(CVN7^___K``!0XX\```H`,*#C3#"-Y4PPC>(` -M,(WE!`"@X500G>4#(*#C/#"-XO[__^L``%#CA```"O[__^L-(*#A?SW"XS\P -MP^,$()/E`2""X@0@@^4&>X7B('"'XB`X`>,#0)7G")"@XP&`H.-G``#J:UY$ -MX@A01>(`0)3EK#?5Y0``4^-@```*M#?5Y0(`$^-=```*>@Z%X@X`@.(\$(WB -M!B"@X_[__^L``%#C5@``"@"`FN5_,*#C43#-Y5`_!N.:.4#C2#"-Y0,PH.-2 -M,,WE`#"@XU,PS>53#8CB(`"`XO[__^L`<%#B`)"@`TP```H(`*#A"!"'XO[_ -M_^ML`)?E`!"@XV@@H./^___K;#"7Y0PPC>4#D*#A`""@XR@@Z>4!(,GE+`"# -MXN`0A>(&(*#C_O__Z[5/BN("0(3B##"=Y3(`@^($$*#A!B"@X_[__^L,()WE -M.`""X@00H.$&(*#C_O__ZPP@G>6^$_+AW#<`X[,`F.$/$`'B`!*!X;`0PN&S -M()CA`2""XK,@B.&P,-GA_###X]`P@^.P,,GA!T"@X1@PH.,4,*3E##"=Y4`` -M@^(!$*#C42"-X@0PH.'^___K!!"@XT@@C>($,*#A_O__ZP$0H.-2((WB!#"@ -MX?[__^L!$*#C4R"-X@0PH.'^___K%#"7Y1@PA^4(`*#A!Q"@X?[__^L`D*#C -M!0``Z@B0H.$'`*#A!!"@X?[__^L``%#CDO__"@T@H.%_/<+C/S##XP0@D^4! -M($+B!""#Y?[__^L"``#J")"@XP```.H$D*#C4Y#-Y5)@S>4`8)KE!#"@XU$P -MS>4),*#C2##-Y5`_!N.:.4#C1#"-Y08PH.-,,,WE`#"@XSPPC>5`,(WE4PV& -MXB``@.+^___K`%!0XE@```H&`*#A"!"%XO[__^ML`)7E`!"@XV@@H./^___K -M;("5Y0APH.$`,*#C*##GY0$PQ^4L`(CB"A"+X@8@H./^___K+4Z*XC(`B.($ -M$*#A!B"@X_[__^LX`(CB!!"@X08@H./^___K"""@X;X3\N'<-P#CLP"6X0\0 -M`>(`$H'AL!#"X;,@EN$!((+BLR"&X;`PU^'\,,/CT#"#X[`PQ^$%0*#A&#"@ -MXQ0PI.5``(CB`1"@XU$@C>($,*#A_O__ZP$0H.-(((WB!#"@X?[__^L$$*#C -M1""-X@0PH.'^___K`1"@XTP@C>($,*#A_O__ZP$0H.-2((WB!#"@X?[__^L` -M@*#A4#"@XSPPS>5O,*#C/3#-Y64PX.,^,,WE"3"@XS\PS>4\<(WB!`"'X@`0 -MH.,!(*#C4S"-XO[__^L$((#B`$"-Y0@`H.'=$*#C!S"@X?[__^L4,)7E&#"% -MY08`H.$%$*#A_O__ZP$`>>(``*`S7-"-XO"/O>CP3RWI1]]-X@!PH.$($(WE -M&`"-X@`0H.,!+*#C_O__ZP`@H.,4((WE4#"@XQ@PS>5O,*#C&3#-Y64PX.,: -M,,WE"3"@XQLPS>4",*#C'##-Y1X@S>4=,,WE(C"@XQ\PS>7$,I?E`P!3XP<` -M`!H),*#C(##-Y($,(+@"""@XPH@P^<#((3B!1""X``PX.,&,,'G`C#%YP4@A.(% -M$(+@!C#!YP(PQ><',(3B1B^-X@,P@N`-(*#C"B##YP@PA.(%$(/@&B/7Y14` -M@N(@!*#A!@#!YQ4@@N(#(,7G"@"$X@``A>`M'H?B!B"@X_[__^O:/Z#CLR"7 -MX2(4H.$0,(3B!1#CYP8@P^<2,(3B!8#CYQX@H.,&(,/G%#"$X@6`X^=0(*#C -M!B##YPT@X.,"(,/E`Y##Y1@PA.(%@./G!F##YQHPA.)&+XWB`S""X`J@@^`` -M@,KE&S"$XA`@H.,%(./G$2"@XP8@P^<:(]?E0A2@X1TPA.(%$./G!B##YQ]` -MA.($`(7@OA^'X@(0@>+^___K&H/7Y0B`A.#$,I?E`P!3XW(``!H`0)?E`0R@ -MX_[__^L,`(WE_O__ZPT@H.%_/<+C/S##XP0@D^4&((+@!""#Y09[A.(@<(?B -M(#@!XP-0E.<,8)WE!J"@X0"PH..VEP#C1```ZFM.1>((0$3B`%"5Y:PWU.4` -M`%/C/@``"@$`AN)Z'H3B#A"!X@8@H./^___K!P"&XN`0A.(&(*#C_O__Z[0W -MU.4-,,;E!C"@X;D@E.$B)*#A#B#CY;D@E.$!(,/E$`"&XGL>A.(($('B"""@ -MX_[__^L$$*#AP#?QY1@PQN498(;BP"?4Y08`H.$!$('B@B&@X?[__^O`-]3E -M@V&&X.(G`..R,)3A``!3XQ(```H0,*#C`##&Y1$@H.,!(,;EXB<`X[(PE.$C -M-*#A`C#FY;(PE.$!,,;E`F"&X@8`H.%^'H3B!!"!XK(@E.'^___KXB<`X[(P -ME.$#8(;@!C!JX',P[^8!($/B`"#*Y0NP@^![L/_F!J"@X0<`H.$%$*#A_O__ -MZP``4..U__\*#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__ZP``6^,`0*`# -M!@``"A@`C>((`(#@#A"@XPL@H.$,,)WE_O__ZP!`H.$,`)WE`1R@X_[__^L$ -M@(C@%#"-X@`PC>4(`)WEW1"@XP@@H.$8,(WB_O__ZQ0`G>5'WXWB\(^]Z/!` -M+>D4T$WB`&"@X0``H.,,`(WE"`"-Y1`PC>(,`"/E&%"!XAA`0N($<*#A!0"@ -MX0$0H.,#(*#A!#"@X?[__^L$$)WE!`!1XQ$``,H``%'C*P``V@#`H.,,(*#A -M`C#0Y0(`4^,$`%,3`P``"@L`4^,!```*%@!3XP'`H!,!((+B`0"`X@$`4N'S -M__\:``!(',*#A_O__ZP!PH.'$,I;E`0!3XP$` -M``H#`%/C$```&@4`H.$$$*#A`""@XPPPC>+^___K``!0XPD```H``%?C!P`` -M"@(`A^*Z'X;B`Q"!X@<@H./^___K``!0X@$`H!,```#J``"@XQ30C>+P@+WH -M!$`MY0``4>,.``#:@T&@X0#`T.4"`%SA!0``&@'`T.4#`%SA`@``&@$`5.$" -M`(#2!0``V@'`T.6,$4'@``!1XXP!@,#Q___*``"@XQ``O>@>_R_A``!1XQ[_ -M+P$@/0/C`S"0YP``4^,>_R\1J#"1Y;P@T^$(`%+C'O\O$0XP@^()(-/E$0!2 -MXQ[_+Q$`(-/E#R`"X@(Q@^`#$*#AL"#3X1$+4N,>_R\1LB#3X4,,4N,>_R\1 -M"#"#XF,B".-3(T;C[`"3Y0(`4.$>_R\1NB#3X8``$N,>_R\1@"""X[H@P^&V -M,-'A`S#@X7,P\N9#*+#A`@``"G,P\N9#*+#A_/__&@,PX.&V,,'A'O\OX7!` -M+>D8T$WB`&"@X0)0H.$$0(WB!`"@X1$0H./^___K`3"@XP0PS>4'`(3B!1"@ -MX00@H./^___K!##=Y0$`4^,(```:"S#=Y0P@W>4#("+@#3#=Y0,@(N`.,-WE -M`R`BX`\@`N)?``#J`P!3XQ0``!H%,-WE!B#=Y0,@(N`',-WE`R`BX`@PW>4# -M("+@"3#=Y0,@(N`*,-WE`R`BX`LPW>4#("+@###=Y0,@(N`-,-WE`R`BX`XP -MW>4#("+@#R`"XD@``.H$`%/C!@``&@4PW>4&(-WE`R`BX`4#("+@#R`" -MXC\``.H%`%/C$0``&@8PW>4%(-WE`R`BX`4@(N(',-WE`R`BX`@PW>4#("+@ -M"3#=Y0,@(N`*,-WE`R`BX`LPW>4#("+@###=Y0,@(N`/(`+B*P``Z@(`4^,@ -M```:!3#=Y08@W>4#("+@!S#=Y0,@(N`(,-WE`R`BX`DPW>4#("+@"C#=Y0,@ -M(N`+,-WE`R`BX`PPW>4#("+@#3#=Y0,@(N`.,-WE`R`BX`\PW>4#("+@$##= -MY0,@(N`1,-WE`R`BX!(PW>4#("+@$S#=Y0,@(N`4,-WE`R`BX`\@`N((``#J -M`""@XP(PH.$$`(WB`Q#0YP$@(N`!,(/B$0!3X_K__QH/(`+B\BZ"X@P@@N(" -M(8;@!$"2Y0``5.,+```*!%"-XA%@H.,8`(3B!1"@X08@H.'^___K``!0XP0` -MH`$#```*`$"4Y0``5./U__\:``"@XQC0C>)P@+WH<$`MZ0!0H.$!0*#A$1"@ -MX_[__^L%`*#A`C"@XP$PP.0$$*#A$""@X_[__^MP@+WH$$`MZ?[__^L-(*#A -M?SW"XS\PP^,$()/E`2""X@0@@^4$()/E`2!"X@0@@^7^___K$("]Z/!!+>D` -M0*#A`7"@X0)0H.'^___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/E`##5Y0$` -M4^,(```:""#5Y04#("+@"3#5Y0,@(N`*,-7E`R`BX`\@`N)>``#J`P!3 -MXQ0``!H"(-7E`3#5Y0,@(N`#,-7E`R`BX`0PU>4#("+@!3#5Y0,@(N`&,-7E -M`R`BX`4#("+@"##5Y0,@(N`),-7E`R`BX`HPU>4#("+@#R`"XD<``.H$ -M`%/C!@``&@(@U>4!,-7E`R`BX`,PU>4#("+@#R`"XCX``.H%`%/C$0``&@$@ -MU>4",-7E`R`BX`4@(N(#,-7E`R`BX`0PU>4#("+@!3#5Y0,@(N`&,-7E`R`B -MX`4#("+@"##5Y0,@(N`/(`+B*@``Z@(`4^,`(*`3`C"@$2```!H"(-7E -M`3#5Y0,@(N`#,-7E`R`BX`0PU>4#("+@!3#5Y0,@(N`&,-7E`R`BX`4# -M("+@"##5Y0,@(N`),-7E`R`BX`HPU>4#("+@"S#5Y0,@(N`,,-7E`R`BX`TP -MU>4#("+@#C#5Y0,@(N`/,-7E`R`BX!`PU>4#("+@#R`"X@4``.H#$-7G`2`B -MX`$P@^(1`%/C^O__&@\@`N+R+H+B#"""X@(AA.`$0)+E``!4XR0```H18*#C -M&`"$X@40H.$&(*#A_O__ZP``4.,:```:`#``XP`P0.,`()/E=2Q"XA0PE.4" -M,&/@,`!3XPD``%JH`)?E#!"$X@8@H./^___K"$"$XI\_E.$!,(/BDR^$X0`` -M,N/Z__\:#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__ZP$`H./P@;WH`$"4 -MY0``5./;__\:#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__ZP``H./P@;WH -M<$`MZ0!0H.$"0*#A`C"!X)P@D.4"`%/A$```BE``D.4``%3A#0``B@,`4N$+ -M```Z`B!CX```4N,"``#:`0"@X0,0H.'^___K4!"5Y04`H.$!$&3@_O__ZP`` -MH.-P@+WH``#@XW"`O>CP1RWI`'"@X0&@H.$"4*#A_O__ZPT@H.%_/<+C/S## -MXP0@D^4!((+B!""#Y0`PU>4!`%/C"```&@B`U>4',-7E`X`HX`DPU>4#@"C@ -M"C#5Y0.`*.`/@`CB7@``Z@,`4^,4```:`H#5Y0$PU>4#@"C@`S#5Y0.`*.`$ -M,-7E`X`HX`4PU>4#@"C@!C#5Y0.`*.`',-7E`X`HX`@PU>4#@"C@"3#5Y0.` -M*.`*,-7E`X`HX`^`".)'``#J!`!3XP8``!H"@-7E`3#5Y0.`*.`#,-7E`X`H -MX`^`".(^``#J!0!3XQ$``!H!@-7E`C#5Y0.`*.`%@"CB`S#5Y0.`*.`$,-7E -M`X`HX`4PU>4#@"C@!C#5Y0.`*.`',-7E`X`HX`@PU>4#@"C@#X`(XBH``.H" -M`%/C`("@$P@PH!$@```:`H#5Y0$PU>4#@"C@`S#5Y0.`*.`$,-7E`X`HX`4P -MU>4#@"C@!C#5Y0.`*.`',-7E`X`HX`@PU>4#@"C@"3#5Y0.`*.`*,-7E`X`H -MX`LPU>4#@"C@###5Y0.`*.`-,-7E`X`HX`XPU>4#@"C@#S#5Y0.`*.`0,-7E -M`X`HX`^`".(%``#J`R#5YP*`*.`!,(/B$0!3X_K__QH/@`CB\CZ(X@PP@^(# -M,8?@!$"3Y0``5.,9```*$6"@XQ@`A.(%$*#A!B"@X?[__^L``%#C#P``&@P` -MA.(*$*#A!B"@X_[__^L`,`#C`#!`XP`PD^44,(3E#2"@X7\]PN,_,,/C!""3 -MY0$@0N($((/E_O__Z_"'O>@`0)3E``!4X^;__QHL`*#C_O__ZP!`4.('```: -M#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__Z_"'O>@8`(3B!1"@X1$@H./^ -M___K#`"$X@H0H.$&(*#C_O__ZP$PH.,(,(3E`#``XP`P0.,`,)/E%#"$Y?(^ -MB.(,,(/B`S&'X`0PD^4`,(3E``!3XP1`@Q7RCHCB#("(X@B!A^`$0(CE!("( -MX@2`A.4-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K\(>]Z/!%+>E4'`(3B#!"(X@0@H./^___KJ!"7Y08`H.$&$('B -M!""@X0G__^L&`*#A-O[_ZP``H./%`P#J$("(XD1`C>($`*#A$1"@X_[__^L! -M,*#C1##-Y0<`A.(($*#A!""@X_[__^L&`*#A!Q"@X00@H.$R_O_K``!0X[,# -M`!H#,-CE_P!3XP4``!JH`)?E_Q"@XP8@H./^___K``"@XZL#`.JH`)?E/1R& -MX@P0@>(&(*#C_O__ZP``H..D`P#J"!8`XP$`4^%&```:#E"%XK(PU>$(`%/C -M!0``"K,_O^:$#I_E("`%3C!```"@,`5.,< -M```*`0!4XXT#`!J.`P#J"`"@X0T;AN(1$('B!B"@X_[__^L$,-7E`X"(X$1` -MC>($`*#A$1"@X_[__^L!,*#C1##-Y0<`A.(($*#A!""@X_[__^NH$)?E!@"@ -MX080@>($(*#AN?[_ZP8`H.'F_?_K``"@XW4#`.H$H-7E!3#5Y8J@B.`#H(K@ -M1$"-X@0`H.$1$*#C_O__ZP$PH.-$,,WE!P"$X@H0H.$$(*#C_O__ZP8`H.$' -M$*#A!""@X=_]_^L%`-7E!##5Y0,`@.```(C@J!"7Y08@H./^___K``"@XUH# -M`.H%&@[C`0!3X30!`(H`(`#C`"!`X[`@TN&P),WAJ%"7Y0Y0A>*!)P/C`@!3 -MX40```I``(WB!1"@X0(@H./^___K``!0XSX```H`,-7EJ@!3XS(``!HL+9_E -M.#"-X@00@N(#`)'H!`"#Y``0P^4P,(WB#!""X@,`D>@$`(/D`!##Y0@PC>(4 -M((+B`P"2Z`0`@^0`$,/E`U"%XC@`C>(%$*#A!2"@X_[__^L``%#C!5"%`B,` -M``HP`(WB!1"@X04@H./^___K``!0XP50A0(`@*`#)P,`"@@`C>(%$*#A!2"@ -MX_[__^L``%#C!8"%`@!0H`,?`P`*`!#5Y0$@U>4",-7E`P#5Y0``C>4$`-7E -M!`"-Y70,G^7^___K``#@XQ(#`.K@`%/C#0,`&@-0A>)``(WB!1"@X0(@H./^ -M___K``!0XP8#`!H``%7C`("@`[4```H"`%3C"P``"@,`5.,\```*`0!4X_T" -M`!JH`)?E!@"`XA80A>(&(*#C_O__ZP``4./X`@`*]0(`ZA:`A>*H`)?E!@"` -MX@@0H.$&(*#C_O__ZP``4.,3```:1$"-X@0`H.$1$*#C_O__ZP,PH.-$,,WE -M`0"$XA(0A>($(*#C_O__ZP4`A.(<$(7B`B"@X_[__^L-&X;B"`"@X1$0@>(& -M(*#C_O__ZPT``.I$0(WB!`"@X1$0H./^___K`S"@XT0PS>4!`(3B$A"%X@0@ -MH./^___K!0"$XA80A>(&(*#C_O__ZZ@0E^4&`*#A!A"!XD0@C>()_O_K!@"@ -MX3;]_^L``*#CQ0(`Z@J`A>(-"X;B$0"`X@@0H.$&(*#C_O__ZP``4.,7```: -M1$"-X@0`H.$1$*#C_O__ZP,PH.-$,,WE`0"$X@80A>($(*#C_O__ZP4`A.(0 -M$(7B`B"@X_[__^L&`*#A!Q"@X00@H.$G_?_K"`"@X:@0E^4&(*#C_O__ZP`` -MH..E`@#J1$"-X@0`H.$1$*#C_O__ZP,PH.-$,,WE`0"$X@80A>($(*#C_O__ -MZP4`A.(*$(7B!B"@X_[__^L&`*#A!Q"@X00@H.$/_?_K``"@XY$"`.H$,-7E -M!@!3XP(``!H%,-7E!`!3XP,```I,"I_E_O__ZP``X..'`@#J`@!4XP0```H# -M`%3C'```"@$`5.-^`@`:?P(`Z@@`A>(-&X;B$1"!X@8@H./^___K1$"-X@0` -MH.$1$*#C_O__ZP0PH.-$,,WE`0"$X@\0A>("(*#C_O__ZQ$PU>5',,WEJ!"7 -MY08`H.$&$('B!""@X:K]_^L&`*#AU_S_ZP``H.-F`@#J1$"-X@0`H.$1$*#C -M_O__ZP0PH.-$,,WE`0"$XAD0A>("(*#C_O__ZQLPU>5',,WE!@"@X0<0H.$$ -M(*#ATOS_ZQ(`A>*H$)?E!B"@X_[__^L``*#C4`(`Z@``6.-+`@`*`@!4XP(` -M``H#`%3C1P(`&A0``.I$0(WB!`"@X1$0H./^___K!#"@XT0PS>4!`(3B!A"( -MX@(@H./^___K"3#8Y46H$)?E!@"@X080@>($(*#A>/W_ZP8`H.&E_/_K -M``"@XS0"`.I$0(WB!`"@X1$0H./^___K!#"@XT0PS>4!`(3B`Q"(X`(@H./^ -M___K"##8Y44&`*#A!Q"@X00@H.&@_/_K``"@XR("`.J(%`;CB`,&XP$` -M4^$``%,1?`$`&@Z`A>("`%3C"0``"@,`5./6```*`0!4XQ,"`!H",-CE`R#8 -MY0(DD^$``*`#`0"@$Q`"`.H",-CE`R#8Y0(DD^&B```:`3#8Y1D`4^,)`%,3 -M!0(`&B0]`^,#,);G``!3XX$```H(4(WB!C"(X@0@V.4%$-CE`22"X0-`H.&R -M+[_F!Q$/_F!!"!X@%`A.`$$&/@`@!1X?#__[HH``#J``!4XR8```H",-3E`V#4 -MY09D@^&V;[_F=F#_Y@PPAN(H`%/C`P``FJ@'G^7^___K``#@X]T!`.H,`(7B -M!!"$X@8@H.'^___K!P"@X000H.$$((;B^_S_ZP``4.,#``"J=`>?Y?[__^L` -M`.#CSP$`Z@0PV.4%(-CE`C2#X;,_O^9S,/_F!#!#X@,P9N"S/[_F4/,(/B`3#%Y0@PAN*S/[_F4C-*#A`S#%Y8$V"./_/T_CM##%X:@0E^4&`(7B!A"!X@8@H./^___K -MJ("7Y0(PU>4#8-7E!F2#X01@AN)4,)?E``!3XP`PH!.@()<%G#"7!0(P8P`# -M`%;A`P``VK0&G^7^___K``#@XYX!`.H.0(CB!P"@X080H.'^___K%'"(X@0P -MU.4%(-3E`B2#X;(OO^8&`(?@!Q"@X7(@_^;^___K!##4Y04@U.4"-(/ALS^_ -MYG,P]N:S/[_F($`*#A$1"@X_[__^L%,*#C1##-Y0$`A.("$(CB`B"@ -MX_[__^L#`(3B!1"@X08@H./^___KJ!"7Y08`H.$&$('B!""@X9;\_^L&`*#A -MP_O_ZR0]`^,#,);G``!3XT\!`!KT/`/C`S"6YP``4^-+`0`*J`"7Y?,=AN(& -M`(#B.!"!X@8@H./^___K``!0X_0\`P,#`(8'0@$`"D`!`.H!,-CE!P!3XP`@ -MH!,!(*`#!P!3XV4`4Q-_```:)#T#XP,PEN<``%/C:0``"@8PB.($$-CE!0#8 -MY0`4@>$#0*#AL1^_YG$0_^8+``#J`L#4Y0,`U.4!X-3E`Y0;DCN!^X/_F -M$0Y>XP<```H,!(#@<`#_Y@0`@.(`0(3@!`!CX`$`4.'P__^Z`0``Z@``5.,# -M```:I`2?Y?[__^L``.#C&`$`Z@)@U.4#,-3E!F2#X'9@_^8!,-3E`!#4Y0$4 -M@^!Q$/_F!P!6XP`PH(,!,*"3$0Y1XP$P@Q,``%/C!```"EP$G^4&$*#A_O__ -MZP``X.,$`0#J!*"@X000H.&T`/'AL`^_YG``_^:&,0CC`P!0X0D```H``%+C -M`!``XP`00.,`,`#C`#!`XP,0H`$4!)_E_O__ZP``X./R``#J!0"@X0(0@>(& -M(*#C_O__ZP@`5N,$4*"#`%"@DP<`H.$%$(3@#"!EX@W\_^L``%#C`P``JM0# -MG^7^___K``#@X^$``.H$,-CE!2#8Y0(D@^&R+[_F##!%XG(P\^:S/[_F/3``#:"#!&XK,_O^9S,/_F`C#$Y2,TH.$#,,3E -M``"@X\P``.KT/`/C`S"6YP``4^,#```:9`.?Y?[__^L``.#CQ```ZO,=AN(% -M`*#A.!"!X@8@H./^___K!2"@X_0\`^,#((;G``"@X[H``.H",-CE`R#8Y0(D -MD^&S```*1$"-X@0`H.$1$*#C_O__ZP4PH.-$,,WE`0"$X@(0B.("(*#C_O__ -MZP,`A.(&$(7B!B"@X_[__^L&`*#A!Q"@X00@H.$@^__K!@"@X1'[_^L``*#C -MH```ZH@>".,!`%/A!@``&@(`4N.8``"*`#``XP`P0.,$,8/@&`"3Y98``.KB -M'PKCX@X*XP$`4^$``%,1!@``&@(`4N.,``"*`#``XP`P0.,$,8/@)`"3Y8H` -M`.J&+0WC`@!3X80``!I0,)?E#C!#XB@`4^,#``"*5`*?Y?[__^L``.#C?P`` -MZ@Z`A>("`%3C!P``"@,`5.-M```*`0!4XW4``!H`,-7E`0`3XW0``!IQ``#J -M"*"(X@H`H.$4$I_E$""@X_[__^L``%#C;```"D1`C>($`*#A"A"@X($(*#AI/O_ZP8`H.'1^O_K!C#8Y3H`4^->```:4!"7Y3H` -M4>-;``":J`"7Y3800>(-2X;B$4"$XC8P\.6%`%/C#```&@<`4>-2``#:"`"` -MX@@00>(!(*#C`C"@X=_Y_^L``%#C2P``"@00H.$&(*#C_O__ZUT``.J&`%/C -M#```&@\`4>-#``#:$`"`XA`00>(!(*#C`C"@X=#Y_^L``%#C/```"@00H.$& -M(*#C_O__ZTX``.J'`%/C#```&A<`4>,T``#:&`"`XA@00>(!(*#C`C"@X<'Y -M_^L``%#C+0``"@00H.$&(*#C_O__ZS\``.J(`%/C#```&A<`4>,E``#:&`"` -MXA@00>("(*#C`3"@X[+Y_^L``%#C'@``"@00H.$&(*#C_O__ZS```.J)`%/C -M&```&B<`4>,6``#:*`"`XB@00>("(*#C`3"@XZ/Y_^L``%#C#P``"@00H.$& -M(*#C_O__ZR$``.I$0(WB!`"@X1@0B.)K^O_K!@"@X0<0H.$$(*#A@/K_ZP`` -MH.,"``#J``#@XP```.H``*#C7-"-XO"%O>@``%7C:?W_&JG]_^JL`P``S`,` -M`#03``#P`P``)`0``%`$``!L!```H`0``,@$```0!0``.`4``'`%``"8!0`` -MS`4```@&``!H$P``J%"7Y390A>(`8*#CLF#%X;1`V.$%`*#A!!"@X08@H.'^ -M___K-"^_Y@``C>4*`*#A&!"(XCHTH./^___K8#B`X`,PX.$C.*#ALC#%X08` -MH.'5___J\$$MZ0!0H.$!0*#AJ#"1Y0`@T^4!`!+C>@``&KP@T^&!`%+C`'"@ -M$P=@H!$-```:OG#3X0XPH.,#`.#CJ""4Y0,0@N"P$)'ALQ""X0(P0^("`%/C -M^/__&@0`H.$$$*#C_O__ZP%@H.,8/0/C`S"5YP``4^,P```:_O__ZPT@H.%_ -M/<+C/S##XP0@D^4!((+B!""#Y3`]`^,#,)7G``!3XQ@``!JH@)3EO##8X0@` -M4^,4```:/0R%X@0`@.(>$(CB!""@X_[__^L``%#C#0``&O,=A>((`*#A/A"! -MX@8@H./^___K#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__ZP!0H.,I``#J -M#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__ZP4`H.$$$*#A`R"@X_[__^L` -M4*#A'```ZJ@0E.6\,-'A"`!3XP<``!H]#(7B$@"`XAX0@>($(*#C_O__ZP`` -M4.,*```*#P``Z@@F`.,"`%/A#```&CT,A>(2`(#B)A"!X@0@H./^___K``!0 -MXP4``!H%`*#A!!"@X0,@H./^___K`%"@X0```.H`4*#C``!6XQ````H$`*#A -M!!"@X_[__^L`,*#C!`"@XZ@@E.4#$(+@L!"1X;,0@N$",(/B#`!3X_C__QJH -M,)3E@2"@X[P@P^&H,)3EOG##X0$`=>,``.`#\(&]"```H./P@;WH\$\MZ130 -M3>(`<*#A_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B!""#Y?,]A^(^((/B#""- -MY3TLA^($((+B"""-Y?*=A^(TD(GB-#"#X@0PC>4(C0/C`*"@XRRPH./88)_E -M`$"9Y0``5.,F```*`%"4Y0`PEN5U/$/B%""4Y0,P8N`P`%/C'```2@@PA.*? -M+Y/A`2!"XI(?@^$``#'C^O__&@``4N,4```:"#"7YP0`4^$&```:#`"=Y080 -MH./^___K"`"=Y000H./^___K"*"'YPP`E.@`((/E`#"4Y0``4^,$()05!""# -M%0"@A.4$H(3E!`"@X0L0H.'^___K``!5XP5`H!'8__\:!)")X@0PG>4#`%GA -MT?__&@T@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^L4T(WB\(^]Z`````#P -M3RWI#-!-X@!@H.'^___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/E\[V&XCXP -MB^($,(WE/2R&X@0@@N(`((WE\IV&XC20B>(TL(OB"'T#XP"`H.,LH*#C`$"9 -MY0``5.,8```*`%"4Y04&$*#C_O__ZP``G>4$$*#C -M_O__ZP>`AN<,`)3H`""#Y0`PE.4``%/C!""4%00@@Q4`@(3E!("$Y00`H.$* -M$*#A_O__ZP``5>,%0*`1YO__&@20B>(+`%GAX/__&@T@H.%_/<+C/S##XP0@ -MD^4!($+B!""#Y?[__^L,T(WB\(^]Z`(,4>,``*`C'O\O(0`P`.,`,$#C`##3 -MY0``4^,&```:`#``XP`P0.,!$(/@!##1Y0`PPN4!`*#C'O\OX0```.,``$#C -M`3!#XH,$@.`!$(#@!#+1Y0`PPN4!`*#C'O\OX0(,4>,``*`C'O\O(0`P`.,` -M,$#C`##3Y0``4^,%```:`#``XP`P0.,!$(/@!"#!Y0$`H.,>_R_A````XP`` -M0.,!,$/B@P2`X`$0@.`$(L'E`0"@XQ[_+^$00"WIK#L#XP_@H.$#\)#G$("] -MZ!!`+>FX.P/C#^"@X0/PD.<0@+WH`#"@X0$`(.(!``#B`@`3XP$`@`)P`.\& -M!``3XP$`@`)P`.\&"``3XP$`@`)P`.\&'O\OX03@+>4,T$WB%,#=Y1#@G>4` -MX(WE!,"-Y;#+`^,/X*#A#/"0YPS0C>(`@+WH!.`MY0S03>(0P-WE`,"-Y;3+ -M`^,/X*#A#/"0YPS0C>(`@+WH$$`MZ;S+`^,/X*#A#/"0YQ"`O>@$X"WE#-!- -MXA#`W>4`P(WE[\V@XP_@H.$,\)#G#-"-X@"`O>@$X"WE#-!-XA#`W>4`P(WE -MR,L#XP_@H.$,\)#G#-"-X@"`O>@!`!#C`##1!0`PP@4!,-$%`3#"!0(`$.," -M,-$%`C#"!0,PT04#,,(%!``0XP0PT04$,,(%!3#1!04PP@4(`!#C!C#1!08P -MP@4',-$%!S#"!1[_+^$$X"WE#-!-XA#`W>4`P(WEQ,L#XP_@H.$,\)#G#-"- -MX@"`O>CP3RWI%-!-X@!@H.$!L*#A`D"@X0.@H.$XD)WE`%"@X[Y0S>&\4,WA -M`%"-Y040H.$!(*#C#C"-XO[__^L`4(WE!@"@X040H.$#(*#C##"-XO[__^N^ -M,-WA!`!3X2D``#H!`%OC`(``$P"`0!,%```:!""*X+PPW>$#`%+A(0``R@"` -M`.,`@$#C!@"@X0L0H.$!(*#C_O__ZP``6N,3``#:OC#=X00`4^$`4*"#!0`` -MB@X``.H!0(3B=$#_YKXPW>$$`%/A"0``F@8`H.$$$*#A!2")X#C_+^$`<%#B -M!```"@%0A>(*`%7A\?__N@```.H`<*#C!@"@X0L0H.$`(*#C_O__ZP```.H` -M<*#C!P"@X130C>+PC[WH!.`MY1303>(`$*#C`!"-Y0,@H.,.,(WB_O__Z[X` -MW>$4T(WB`("]Z'!`+>D`0*#A`5"@X0`0H.,!(*#C_O__ZP0`H.$`$*#C`2"@ -MX?[__^NP`,7A!`"@X0`0H.,!(*#A_O__ZP$`H.-P@+WH\$`MZ1303>(`8*#A -M`5"@X0)`H.$#<*#A`!"@XQ`PC>*R$&/A`!"-Y00@H./^___K!2"$X+XPW>$# -M`%+A``"@PQ```,H&`*#A`!"@XP$@H./^___K`'"-Y0!PH.,$<(WE!@"@X0<0 -MH.$%(*#A!#"@X?[__^L&`*#A!Q"@X0<@H.'^___K`0"@XQ30C>+P@+WH\$`M -MZ1303>(`8*#A`5"@X0)`H.$#<*#A`""@XQ`PC>*R(&/A`""-Y0$0H.,$(*#C -M_O__ZP4@A."^,-WA`P!2X0``H,,0``#*!@"@X0`0H.,!(*#C_O__ZP!PC>4` -M<*#C!'"-Y08`H.$!$*#C!2"@X00PH.'^___K!@"@X0<0H.$'(*#A_O__ZP$` -MH.,4T(WB\("]Z/!%+>D4T$WB`&"@X0&`H.$"H*#A`W"@X0!`H.,04(WBLD!E -MX000H.$!(*#C_O__ZP!PC>4&`*#A"!"@X00@H.,%,*#A_O__Z[XPW>$`H(WE -M!'"-Y08`H.$($*#A!""@X?[__^L&`*#A!!"@X00@H.'^___K%-"-XO"%O>@! -M`%'C!0``&@(@@.`-*X+B&"""X@,@TN4`(,/E'O\OX0(`4>,*```:`B"`X`T; -M@N(8$('B`Q#1Y;`0P^$-*X+B&2""X@,@TN4"%('AL!##X1[_+^$$`%'C'O\O -M$0(`@.`-*X#B&"""X@,0TN4`$(/E#2N`XAD@@N(#(-+E`A2!X0`0@^4-*X#B -M&B""X@,@TN4"*('A`""#Y0T+@.(;`(#B`Q#0Y0$L@N$`((/E'O\OX1[_+^'P -M02WI`$``XP!`0.,$`(3B_Q"@XP(LH./^___K`@N$X@0`@.+_$*#C`2R@X_[_ -M_^L)#(3B!`"`XO\0H.,!+*#C_O__ZPI,A.($0(3B!ER$X@)LH./_<*#C!`"@ -MX080H.$'(*#A_O__ZP),A.(%`%3A^/__&@!``.,`0$#C_PY$X@0`0.+_$*#C -M`2N@X_[__^N_#D3B!`!`XO\0H.,!*Z#C_O__ZU1`G^4&7(3B_V"@XP)\H.,$ -M`*#A!A"@X0<@H.'^___K`DR$X@4`5.'X__\:`$``XP!`0.-_#D3B!`!`XO\0 -MH.,!*Z#C_O__Z_T/1.+_$*#C`2N@X_[__^OP@;WH6!8``'!`+>D0T$WB`$"@ -MX0%@H.$"4*#A$#"-X@`@H..R(&/A`%"-Y00@H./^___K$#0#XP,PU.'^___K!0``Z@0`H.$&$*#A#2N$XAL@@N(% -M,*#A_O__ZQ#0C>)P@+WH\$\MZ3303>(`L*#A`6"@X0)0H.$#D*#A`""@XS`P -MC>*Z(&/A`""-Y0$0H.,$(*#C_O__ZQQ@C>6V`MWA!C"%X```4^&-``#*_O__ -MZP``4.,8`(WEB0``"@L`H.$`$*#CMB+=X1@PG>7^___K`'!0XGX```H+`*#A -M`1"@XP$@H.'^___KUF'GYR@`C>+_$*#C"""@X_[__^L<`)WE!S``X@$`$.,` -M0*`##R"@`U(```H<`)WE`!#9Y1C`G>4`(-SG`@!1X0\@H`,+```*PR"@X0$0 -MH.,1(N#A#R`"XC#@C>(#$([@&,"=Y0``C.`!`%#E"0!!Y0``V>4(`$'E`3"# -MX@%`H.,\``#J!0!4X3X```H%$&3@`0!1XQ(``!H$`-GG'."=Y0X0A.`8X)WE -M`<#>YP``7.$)```*P\"@X0'@H.,>+,+A,,"-X@,PC.`(`$/E&."=Y0$0CN`! -M$-'E!Q!#Y0%`A.(H``#J!,"@X000V><<`)WE``"$X!0`C>48X)WE`.#>YP$` -M7N$-```:!`")X`P`C>48X)WE%`"=Y0#@CN`4X(WE#."=Y0'@WN4,X(WE%."= -MY0$`WN4,X)WE``!>X0@```K#`*#A`>"@XQX@PN$PX(WB`P".X`@00.4,P(G@ -M`1#(`H*#C!P!3X[[__]H/ -M`%+C!P``"@"@C>4+`*#A!A"@X0@PH.'^___K<'#OY@``5^,*```*!0!4X0@` -M``H!8(;B=F#OY@@`H.'_$*#C"""@X_[__^L*,*#A#R"@X^C__^H+`*#A`1"@ -MXP`@H./^___K&`"=Y;82W>'^___K````Z@!PH.,'`*#A--"-XO"/O>CP3RWI -M--!-X@"PH.$!8*#A`E"@X0.0H.$`$*#C,#"-XKH08^$`$(WE!""@X_[__^L< -M8(WEM@+=X08PA>```%/AC0``RO[__^L``%#C&`"-Y8D```H+`*#A`!"@X[8B -MW>$8,)WE_O__ZP!P4.)^```*"P"@X0$0H.,!(*#A_O__Z]9AY^48P)WE -M`"#$/(*`#"P``"L,@H.$!$*#C$2+@X0\@`N(PX(WB`Q".X!C`G>4` -M`(S@`0!0Y0D`0>4``-GE"`!!Y0$P@^(!0*#C/```Z@4`5.$^```*!1!DX`$` -M4>,2```:!`#9YQS@G>4.$(3@&."=Y0'`WN<``%SA"0``"L/`H.$!X*#C'BS" -MX3#`C>(#,(S@"`!#Y1C@G>4!$([@`1#1Y0<00^4!0(3B*```Z@3`H.$$$-GG -M'`"=Y0``A.`4`(WE&."=Y0#@WN`,`(WE&."=Y10`G>4` -MX([@%."-Y0S@G>4!X-[E#."-Y13@G>4!`-[E#."=Y0``7N$(```*PP"@X0'@ -MH.,>(,+A,."-X@,`CN`($$#E#,")X`$0W.4'$$#E`D"$X@0`5>$",(,2`@`` -M&@,``.HH@(WB`*"@XP<`4^.^___:#P!2XP<```H`H(WE"P"@X080H.$(,*#A -M_O__ZW!P[^8``%?C"@``"@4`5.$(```*`6"&XG9@[^8(`*#A_Q"@XP@@H./^ -M___K"C"@X0\@H./H___J"P"@X0$0H.,`(*#C_O__ZQ@`G>6V$MWA_O__ZP`` -M`.H`<*#C!P"@X330C>+PC[WH<$`MZ0!0H.$!0*#A`F"@X0``4^,!```*_O__ -MZW"`O>@Q$*#C="#OYO[__^L%`*#A,A"@X_[__^M41.'G_"``X@4`H.$R$*#C -M!"""X?[__^L%`*#A,!"@XP8@H.'^___K!0"@X3,0H./R(*#C_O__ZP!`H.,S -M8*#C`0``Z@%`A.)T0._F!0"@X080H.'^___K@``0XP$```ID`%3C]O__&F,` -M5.,``*"#`0"@DW"`O>@00"WI`"#2Y0`PH./^___K$("]Z/!!+>D`4*#A`4"@ -MX0)PH.$``%/C`0``"O[__^OP@;WH,1"@XW0@[^;^___K!0"@X3(0H./^___K -M5$3AY_P@`.(%`*#A,A"@XP0@@N'^___K!0"@X3,0H.-R(*#C_O__ZP!`H.,S -M8*#C`0``Z@%`A.)T0._F!0"@X080H.'^___K@``0XP(``!ID`%3C]O__&@<` -M`.IC`%3C!0``B@4`H.$P$*#C_O__ZP``Q^4!`*#C\(&]Z``PX.,`,,?E``"@ -MX_"!O>@00"WI`#"@X_[__^L0@+WH<$`MZ1#03>(`4*#A`4"@X0)@H.$`$*#C -M$#"-XK(08^$`$(WE`2"@X_[__^N^,-WA!`!3X2<``)H%`*#A,!"@XP8@H.'^ -M___K!0"@X3$0H.-T(._F_O__ZP4`H.$R$*#C_O__ZU1$X>?\(`#B!0"@X3(0 -MH.,$((+A_O__ZP4`H.$S$*#C_O__ZX`LX.&B+.#A!0"@X3,0H.-R(._F_O__ -MZP4`H.$S$*#C_O__ZP!`H.,S8*#C!0``Z@4`H.$&$*#A_O__ZP%`A.)D`%3C -M`0``"H``$./W__\:$-"-XG"`O>AP0"WI$-!-X@!0H.$!0*#A`!"@XQ`PC>*R -M$&/A`!"-Y0$@H./^___KOC#=X00`4^'_`*"3)```F@4`H.$Q$*#C="#OYO[_ -M_^L%`*#A,A"@X_[__^M41.'G_"``X@4`H.$R$*#C!"""X?[__^L%`*#A,Q"@ -MX_[__^M_(`#B!0"@X3,0H./^___K!0"@X3,0H./^___K`$"@XS-@H.,%``#J -M!0"@X080H.'^___K`4"$XOH/5.,!```*@``0X_?__PH%`*#A,!"@X_[__^L0 -MT(WB<("]Z/!!+>D`4*#A`4"@X0*`H.$``%/C`0``"O[__^OP@;WH,1"@XW0@ -M[^;^___K!0"@X3(0H./^___K5$3AY_P@`.(%`*#A,A"@XP0@@N'^___K!0"@ -MX3,0H./^___K?R``X@4`H.$S$*#C_O__ZP4`H.$P$*#C_O__ZP``4.,.``"Z -M`$"@XS!@H.,/=P+C!0"@X080H.'^___K`4"$XG1`_^8'`%3A`#"@@P$PH),` -M`%#C`#"@LP``4^/S__\:,@"@X_[__^L%`*#A,!"@X_[__^L``,CE\(&]Z!!` -M+>E$.P/C`S"0YP``4^,0@+T(,_\OX1"`O>@00"WI2#L#XP,PD.<``%/C$("] -M"#/_+^$0@+WH$$`MZ3P[`^,#,)#G``!3XQ"`O0@S_R_A$("]Z!!`+>DT.P/C -M`S"0YP``4^,0@+T(,_\OX1"`O>@00"WI.#L#XP,PD.<``%/C$("]"#/_+^$0 -M@+WH$$`MZ2P[`^,#,)#G``!3XQ"`O0@S_R_A$("]Z!!`+>DP.P/C`S"0YP`` -M4^,0@+T(,_\OX1"`O>@00"WI`$"@X0`@H./A.P/C`R#`YP@[`^,/X*#A`_"0 -MYP$`4.,!(*`#X3L#`P,@Q`<`(*`3X3L#$P,@Q!<0@+WH$$`MZ0!`H.$,.P/C -M#^"@X0/PD.ED.P/C`S"0YP``4^,0 -M@+T(,_\OX1"`O>@00"WI:#L#XP,PD.<``%/C$("]"#/_+^$0@+WH$-!-X@W` -MH.$/`(SH$-"-XA[_+^$``-WE``!0XP(`H!$&```:@``1XP,``!I_`%+C0`!2 -M$P(`H)$>_R^1?P`!XG\`4.-``%`3`P"@@1[_+^$[/*#C`Q"0YP`PH..%(P/C -M`C#`YQDJ`N,",,'G'O\OX0`PH.,#`-'G@``0XYX```I_``#B`@!`XFH`4.,` -M\9^7F0``ZB!``@#<0`(`,$`"`-Q``@#<0`(`W$`"`-Q``@#<0`(`W$`"`$!` -M`@!@0`(`W$`"`-Q``@#<0`(`W$`"`-Q``@!P0`(`W$`"`-Q``@#<0`(`4$`" -M`-Q``@"`0`(`W$`"`-Q``@#<0`(`W$`"`-Q``@#<0`(`W$`"`-Q``@#<0`(` -MW$`"`-Q``@"00`(`W$`"`-Q``@#<0`(`W$`"`-Q``@#<0`(`W$`"`-Q``@#< -M0`(`W$`"`-Q``@"@0`(`W$`"`-Q``@#<0`(`W$`"`-Q``@#<0`(`W$`"`-Q` -M`@#<0`(`W$`"`-Q``@#<0`(`W$`"`-Q``@#<0`(`W$`"`-Q``@#<0`(`W$`" -M`-Q``@#<0`(`W$`"`-Q``@"P0`(`W$`"`-Q``@#<0`(`W$`"`-Q``@#<0`(` -MW$`"`-Q``@#<0`(`W$`"`-Q``@#<0`(`W$`"`-Q``@#<0`(`W$`"`-Q``@#< -M0`(`W$`"`-Q``@#<0`(`W$`"`-Q``@#`0`(`W$`"`-Q``@#<0`(`W$`"`-Q` -M`@#<0`(`W$`"`-Q``@#<0`(`W$`"`-Q``@#00`(`L`#2X0$`@..P`,+A*@`` -MZK``TN$"`(#CL`#"X28``.JP`-+A!`"`X[``PN$B``#JL`#2X0@`@..P`,+A -M'@``ZK``TN$0`(#CL`#"X1H``.JP`-+A(`"`X[``PN$6``#JL`#2X4``@..P -M`,+A$@``ZK``TN&``(#CL`#"X0X``.JP`-+A`0R`X[``PN$*``#JL`#2X0(, -M@..P`,+A!@``ZK``TN$!"X#CL`#"X0(``.JP`-+A`@N`X[``PN$!,(/B$`!3 -MXUK__QH>_R_A!@!2XP+QGY<;``#J%$$"`"!!`@`X00(`1$$"`%!!`@!<00(` -M+$$"`$`@H.,`(,/E'O\OX0$LH..P(,/A'O\OX0$LH..P(,/A'O\OX>X@H..P -M(,/A'O\OX>X@H..P(,/A'O\OX0(LH..P(,/A'O\OX1(@H.,`(,/E'O\OX0`@ -MH.,`(,/E'O\OX08`4N,"\9^7&P``ZIQ!`@"H00(`P$$"`,Q!`@#800(`Y$$" -M`+1!`@!`(*#C`"##Y1[_+^$!+*#CL"##X1[_+^$!+*#CL"##X1[_+^'N(*#C -ML"##X1[_+^'N(*#CL"##X1[_+^$"+*#CL"##X1[_+^$2(*#C`"##Y1[_+^$` -M(*#C`"##Y1[_+^$00"WI",#=Y0``7.,!```*_O__ZQ"`O>C^___K$("]Z![_ -M+^$`,`#C`#!`XP@P@.4`,`#C`#!`XRPP@.4`,`#C`#!`XS`P@.4`,`#C`#!` -MXS0P@.4`,`#C`#!`XU`P@.4`,`#C`#!`XU0P@.4`,`#C`#!`XU@P@.4`,`#C -M`#!`XWPP@.4`,`#C`#!`XX`P@.4`,`#C`#!`XX0P@.4`,`#C`#!`XY0P@.4` -M,`#C`#!`XY@P@.4`,`#C`#!`XYPP@.4`,`#C`#!`XZ`P@.4`,`#C`#!`XZ0P -M@.4`,`#C`#!`XZ@P@.4`,`#C`#!`XZPP@.4`,`#C`#!`X[`P@.4`,`#C`#!` -MX[0P@.4`,`#C`#!`X[@P@.4`,`#C`#!`X[PP@.4`,`#C`#!`XVPP@.4`,`#C -M`#!`XW`P@.4>_R_AL"#1X2DQ".,#`%+A`2"@$P`@H`,0-`/C`R#`YQ[_+^$` -M`%+C!0``"@`PH./A(P/C`C#`YY,C`^,",,#G'O\OX0<_`N,#,-#G`@!3X\(@ -MT040(`("X3,#`P,@P`?A(P,3`C#`%\(@T>52(^#GDS,#XP,@P.<>_R_A.SR@ -MXP,PD.<``%+C(!"@$]PH`A,"$,,7'O\O$;D@T>7<&`+C`2##Y_\`4N,@$*`# -MW"@"`P(0PP<>_R_A.SR@XP,PD.<``%+CP2#1!:(BH`$`(*`30R##Y1[_+^$[ -M/*#C`S"0YP``4N,!(*`33B##%1[_+Q'$(-'E3B##Y?\`4N,`(*`#3B##!1[_ -M+^$[/*#C`S"0YP``4N/%(-$%3"##!0`@H!-,(,,532##%1[_+^$[/*#C`S"0 -MYP``4N,`$*`3V2@#$P(0PQ<>_R\1!2\"XP(@T.<"`%+CV0@#$P`@PQ<)```: -M`2"@X<'`\N7

    'GV0@#XP#`P^<`(-+E_P!2XP``H`/9*`,#`@##!\D@T>7: -M&`/C`2##Y_\`4N,!$*`#VB@#`P(0PP<>_R_A.SR@XP,PD.<``%+C&""@$U$@ -MPQ4#```:NB#1Y5$@P^7_`%+C'O\O$0$@H.-2(,/E&""@XU$@P^4>_R_A'O\O -MX1!`+>D[/*#C`\"0YQPZ`N,#X)SG#D"!X0)`Q.$#0(SG51Z@XW0@[^;^___K -M$("]Z#!`+>D,T$WB`%"@X0@PC>(`(*#C`2!CY3LLH.,"0)#G`1"@X\(@H./^ -M___K!S#=Y1``$^,&```*-S,#XP,PU><``%/C`2"@$]XX`Q,#(,07`@``&@`@ -MH./>.`/C`R#$Y]XX`^,#`-3G#-"-XC"`O>@00"WI"-!-X@!`H.$``%'C_Q"@ -M`[@0T14#/P+C`S#0YP`@C>4#(*#A"C"@X_[__^M6!<3E"-"-XA"`O>CP3RWI -M3-!-X@@0C>4$((WE.SR@XP.PD.<0`(WB`!"@XS8@H./^___K!`"=Y0``4.,+ -M```:$,"-X@R`H.$,4*#A`#"@XQ`0H.,#8*#A#Y#@XP!`C>4,L(WE`["@X0A` -MG>63``#J$!"-X@%0H.$!`*#A`&"@XRT@H.,!D*#A`<#@XP)PH.,$H*#C!("@ -MX1L``.H#(,'G`T"`X`P@Q.4!,(/B!@!3X_G__QH&,8G@)C"#X@%`H.,!``#J -M`4"$X@$P@^(!`%3C)G#%!1Z@Q07Y__\*`,##Y0C`P^40P$/E",!#Y0,`5./S -M__^:`6"&X@80@>(%`(#B!%"%X@(`5N-U```*`#"@X^'__^H`<*#A`R#0YP,@ -MS.?_`%+C+2"@`P,@R@`,(,#E_P!2 -MXRT@H`,,(,`%`3"#X@%PA^(%`%/C]?__&@L0@>(0`(WB"S&`X"XP@^(&(*#A -M!*"@XP5PH.$``%+C%P``&BY@R.4!`(3@`%#0Y?\`5>,"4*`#)E#(!00```HE -M4J#A"%!#Y0@`%>,)4(41"%!#%0``T.7_`%#C$*!#!00```H/``#B$`!#Y0@` -M$.,)`(`1$`!#%1A@0^4!$('B*P``Z@$`A.``4-#E_P!5XP%0X`,`4,,%!``` -M"B52H.$`4,/E"``5XPE0A1$`4,,5``#0Y?\`4.,!`.`#"`!#!00```H/``#B -M"`!#Y0@`$.,)`(`1"`!#%0$0@>(!`(3@`%#0Y?\`5>,!4.`#$%!#!00```HE -M4J#A$%!#Y0@`%>,)4(41$%!#%0``T.7_`%#C`0#@`Q@`0P4$```*#P``XA@` -M0^4(`!#C"0"`$1@`0Q4!$('B`2""X@$P@^($`%+CM?__&@&PB^(%4(?B!L", -MX@2`B.("`%OC`P``"@8PH.$!`(3@#*"@X9#__^H`0)WE#+"=Y0$PH.-0,,OE -M````Z@A`H.%",-OE``!3XX(```H`P*#C#'"@X040H.,`$(WE$""-XAH@@N(, -M((WE<@``ZG(P[^8.`%/C$```B@(`4^,S``":!0!3XP%`H),Q``":"`!3XP)` -MH),N``":"P!3XP-`H),K``":#0!3XP1`H),H``":#@!3XW<``!I_``#J*`!3 -MXP=`H)$_``":,`!3XP%`H),\``":.`!3XP)`H),Y``":0`!3XP-`H),V``": -M:`!3XP1`H),S``":<`!3XV,``)IX`%/C80``FH``4^,&0*"3+```FH@`4^,' -M0*"3*0``FI``4^,(0*"3)@``FID`4^,)0*"3(P``FJ$`4^,*0*"3(```FK$` -M4^,+0*"3'0``Z@=`H.$,$*#A!&"@X0(`BN"178#B*%"%X@2`B>`X@%CE`(#% -MY0X`4^,*```:`3*@X8$P0^`#,(O@`B"#X)(M@N(!$8'@2#"-X@$0@^`H,%'E -M!##"Y0H``.J2#8#B!`"`X@$1@>!(4(WB`1"%X`80@>`L,%'E`##`Y0$@@N(/ -M`%+CI?__&A``C>(,,8#@%C"#XI(NC.((((+B`B&+X`P0G>4,`8'@`!#3Y0`0 -MPN4($-/E"!#"Y1`0T^40$,+E&!#3Y1@0PN4!,(/B`2""X@``4^'S__\:`<", -MXGS`[^9",-OE#`!3X0<``)H'(*#AC)"@X0RB:>`*H(O@#)")X$@PC>*)D(/@ -MA/__Z@1`G>4``%3C`#"@$T\PRQ4A```:"#"=Y<$@\^4'(`+B3R#+Y0`PT^7_ -M`%/C`#"@`T\PRP48``#J`$"=Y`X4%7E`%##Y;K__^H,$*#AC`"@X0PR8.`#,(O@`C"#X)$]@^(H,(/B#`"` -MX$A0C>*``(7@,P!0Y0``P^4%0*#CH?__ZDS0C>+PC[WH<$`MZ0!`H.$!4*#A -M$#0#XP,PT.<``%/C#```&AHT`^,#,-#G`0!3XW"`O0@`$*#C`2"@X?[__^L% -M`*#A#1N$XAL0@>("+*#C_O__ZW"`O>@:-`/C`S#0YP``4^,"```:`!"@XP$@ -MH.'^___K!0"@X0T;A.(;$('B`BR@X_[__^MP@+WH$$`MZ0!`H.$!+*#A(BB@ -MX1X>H.,"(8+C_O__ZP0`H.$>'J#C_O__ZR`_L.'_`*`3<`#O!A"`O>@00"WI -M`$"@X0$H.,!(8+C_O__ZP0`H.$>'J#C_O__ZP$`H.,0 -M@+WH\$$MZ0!@H.$!<*#A`!"@XP%01^(&``#J`4"!X@8`H.$$(*#A_O__ZP$` -M4./P@;T8!!"@X04`4>'V__\Z!@"@X040H.'_(*#C_O__ZP$`4./P@;T8!P`` -MZ@00H.$!0('B!@"@X00@H.'^___K`0!0XP0```KP@;WHKP!7XP<0H)'U__^: -M`0``ZK``5./Q__\:!@"@X;`0H.,'(*#A_O__Z_"!O>@00"WI"A"@X_[__^L0 -M``#B``!0XP8`H!,$`*`#$("]Z/!/+>D40`(WB_Q"@XP@@H./^___K`0`7XPJPH!$/H*`3)@``&@&0BN)YD/_F!`"@ -MX0H0H.$`(-CE!C"@X?[__^L!L(GB>[#_Y@2`C>4$`*#A"1"@X0@PH.$!(//E -M!#"-Y08PH.'^___K$%"-X@0`H.$*$*#A!2"@X08PH.'^___K!`"@X0D0H.$! -M((7B!C"@X?[__^L`(-CE$##=Y0,`4N$%```:!#"=Y0`@T^41,-WE`P!2X0^@ -MH`,````*#J"@XP(`%^,+D*`1*@``&@$PB^)S,/_F"`&-Z00`H.$+$*#A"#"@ -MX0(@\^4(,(WE!C"@X?[__^L$,)WE`9"#XGF0_^8,@(WE!`"@X0,0H.$(,*#A -M`R#SY0PPC>4&,*#A_O__ZQ!0C>($`*#A"Q"@X0(@A>(&,*#A_O__ZP0`H.$$ -M$)WE`R"%X@8PH.'^___K"#"=Y0`@T^42,-WE`P!2X00``!H,,)WE`"#3Y1,P -MW>4#`%+A````"OV@"N($`!?C";"@$2H``!H!,(GBD$`*#A"1"@ -MX0@PH.$$(//E"#"-Y08PH.'^___K!#"=Y0&P@^)[L/_F#("-Y00`H.$#$*#A -M"#"@X04@\^4,,(WE!C"@X?[__^L04(WB!`"@X0D0H.$$((7B!C"@X?[__^L$ -M`*#A!!"=Y04@A>(&,*#A_O__ZP@PG>4`(-/E%##=Y0,`4N$$```:##"=Y0`@ -MT^45,-WE`P!2X0````K[H`KB"``7XR```!H!D(OB>9#_Y@APH.$$`*#A"Q"@ -MX08@]^4&,*#A_O__ZP0`H.$)$*#A!R#XY08PH.'^___K$%"-X@0`H.$+$*#A -M!B"%X@8PH.'^___K!`"@X0D0H.$'((7B!C"@X?[__^L`(-?E%C#=Y0,`4N$# -M```:`"#8Y14#`%+A````"O>@"N(*`*#A'-"-XO"/O>@$X"WE#-!-XA#` -MW>4``%SC`,"@`P#`C>5`___K#-"-X@"`O>CP3RWI1-!-X@"@H.$($(WE`G"@ -MX0-@H.$`(*#C0#"-X@T@8^4`8(WE`A"@X?[__^L``%?CF@``"C,PW>4(()WE -M`@!3X98``#H'`*#A_Q"@XP@@H./^___K-`"-XO\0H.,((*#C_O__ZP"0H.,) -M4*#A#)"-Y0%`H.,_L(WB&)"-Y?^!`.,0D(WE`0`4XUT```H*`*#A!1"@X0L@ -MH.$&,*#A_O__ZP``4.-D```*/Y#=Y?\`6>-A```*'S`)X@\`4^,I0J`1#Y`) -M$A"0C140```:`5"%XG50_^8*`*#A!1"@X0L@H.$&,*#A_O__ZS\PW>4/(`/B -M#P!2XP%0A0)U4/\&3```"O`0`^*A0*#AJ4*$X1`@C>40`)WE_O__ZPP`C>4( -M,)WE`P!4X2\``!J`(*#A'""-Y0``4N,D``#:`)"@XQA`G>4!,*#C%#"-Y0,@ -MA>"P(LWA*%"-Y2QPC>4<<)WE()D(+@##!)Y10@G>7_`%/C`""@$Q0@C>4!0(3B -M=$#OY@20H.$'`%3AZO__NBA0G>4L<)WE%#"=Y0``4^,@0*`#&0``"@%0A>(, -M()WE@C"@X750\^9U4/_F`4"@XQ(``.H!4(7B#""=Y8(PH.%U4//F=5#_Y@%` -MH.,+``#J(``4XPD```H0`)WE-!"-X@<@H.'^___K`5"%X@P@G>6",*#A=5#S -MYG50_^8!0*#C"`!5X9'__YH`,-?E_P!3XQ<``!H!,-?E_P!3XQ0``!H",-?E -M_P!3XQ$``!H#,-?E_P!3XPX``!H$,-?E_P!3XPL``!H%,-?E_P!3XP@``!H& -M,-?E_P!3XP4``!H'`-?E_P!0X@$`H!,"``#J``"@XP```.H!`*#C1-"-XO"/ -MO>@00"WI``!3XP$```I-___K$("]Z``PH.-*___K$("]Z/!`+>D,T$WB`$"@ -MX0`PH..V,,WA`%!1X@0```H`,`#C`#!`X[`PT^&V,,WA(0``ZC<0H.,&((WB -M:#L#XP_@H.$#\)3G&P``Z@4`W>7_`%#C)```"A\@`.(/`%+C#P``$@X``!H! -M,(/B$$`*#A!B"@X04PH.'^___K!0#=Y0\P`.(/`%/C#P``$K8P -MW0$!,(,"MC#-`0<```K^___KMC#=X0$P@^*`,(/@MC#-X0$``.H%8(WB_W$` -MXP0`H.&V$-WA!B"@X04PH.'^___K``!0XP(```JV,-WA!P!3X=?__YH``%7C -M!```"@`P`.,`,$#CMB#=X0`@@^4%``#J!`"@X3<0H.,&((WB9#L#XP_@H.$# -M\)3GM@#=X0S0C>+P@+WH$$`MZ0`04N(!```*L?__ZQ"`O>@`$*#CKO__ZQ"` -MO>CP1RWI$-!-X@!PH.$!D*#A`D"@X0-@H.$P@-WEL*#3X0A0C>(%`*#A_Q"@ -MXP@@H./^___K!P"@X0`0U.4%(*#A"#"@X?[__^L``%#C&@``"@$0BN(!(-3E -M`("-Y0<`H.%Q$/_F"#"-XO[__^L`(*#A#P!0XPL```H`$-3E`("-Y0<`H.$( -M,(WB_O__ZP``4.,/```*!P"@X0D0H.$((*#A_O__ZP@``.H*`-3E@`"*X`$` -M@.)P`/_F`P``Z@H`U.6``(K@`0"`XG``_^:P`,;A`0"@XQ#0C>+PA[WH\$\M -MZ3S03>(`8*#A`8"@X0)PH.$#H*#A8%#=Y0!`H.,X,(WBL$%CX0!0C>4$$*#A -M`R"@X_[__^L&`*#A!!"@X04@H.'^___KN#+=X0``4^&9`0":+D"-X@0`H.'_ -M$*#C"""@X_[__^LL@,WE+7#-Y0<`H.$*$*#A!""@X?[__^LM`-WE_O__ZS8` -MS>4`0*#C*T#-Y;9"S>&R0LWAM$+-X0!0C>4&`*#A!!"@X0(@H.,B,(WB_O__ -MZP!0C>4&`*#A!!"@X0$@H.,D,(WB_O__ZP0`5>$,```*`#``XP`P0..P,-/A -M@SN@X:,[H.&V,LWAMA+=X;(RW>$!`%/A`""@@PP@C84+``"*:P$`Z@8`H.$W -M$*#C)B"-XF@[`^,/X*#A`_"6Y[8RW>&#.Z#AHSN@X;8RS>'M___J!@"@X2L@ -MC>(%,*#A_O__ZP``4.-U```**T#=Y?\`5.-R```*'S`$X@\`4^,DHJ`1#X`$ -M$A```!JV$MWA`1"!XG$0_^:V$LWA!@"@X2L@C>(%,*#A_O__ZRN`W>4(H*#A -M#S`(X@\`4^-%`0`*\*`(XJJ@H.&DHHKA`X"@X0@`H.'^___K`'"@X2PPW>4* -M`%/A3```&K:RW>$!L(OB>[#_YH"@H.$``%KC$@``V@"0H.,,0)WE"Q"$X`8` -MH.%Q$/_F*""-X@4PH.'^___K``!0XP(```HH,-WE_P!3XP&0H!,!0(3B=$#O -MY@H`5.'P__^Z``!9XS,``!HM,-WE`0`3XP(``!H!`!CC#D"@`P````H/0*#C -M`@`3XP$``!H"`!CC_4`$`@0`$^,!```:!``8X_M`!`((`!/C`0``&@@`&./W -M0`0"#P!4XQX```JV$MWA`1"!X@!0C>4&`*#A<1#_Y@0@H.$N,(WB_O__ZP`@ -MH.$/`%#C!@``"BP0W>4`4(WE!@"@X2XPC>+^___K``!0X_L```HM`-WE`#"@ -MXU0CH.$!`!+C`2"@`Q(#@`%P`.\&`3"#X@0`4^/W__\:+0#-Y?[__^LV`,WE -MMA+=X0$0@>*'<*#A<1#WYG$0_^:V$LWALC+=X0$`4^&$__^*Y```ZK:2W>$L -M,-WE#P!3XXP``)JTDLWA`$"@X[)"S>$H0,WE`%"-Y08`H.$$$*#A`B"@XR(P -MC>+^___K**"-XA2PC>)V``#J+(#=Y8B"H.$/@(CC>(#OY@8`H.$((*#A!3"@ -MX?[__^L&`*#AM!+=X0H@H.$%,*#A_O__ZRAPW>7_`%?C%0``&@,`5.-K``"* -M`4"$XG1`[^8#``#J!`!4XV8```H!0(3B=$#OY@8`H.&T$MWA"""@X04PH.'^ -M___K!@"@X;02W>$*(*#A!3"@X?[__^LH<-WE_P!7X^[__PH(`%?A20``&K02 -MW>$!$('B<1#_YK02S>$L@-WE>(`(XBTPW>6(@(/A!@"@X0@@H.$%,*#A_O__ -MZP8`H.&T$MWA"B"@X04PH.'^___K*##=Y?\`4^,5```:`P!4XS\``(H!0(3B -M=$#OY@,``.H$`%3C.@``"@%`A.)T0._F!@"@X;02W>$((*#A!3"@X?[__^L& -M`*#AM!+=X0H@H.$%,*#A_O__ZR@PW>7_`%/C[O__"@\0`^(/`%'C!P``&@,` -M5.,F``"*`4"$XG1`[^:T,MWA`3"#XK0RS>$9``#J`P!8X0$PH`,;```*\#`# -MXJ=RH.&C,(?A%##-Y2@`W>4/``#B%0#-Y?[__^L>`,WE`%"-Y08`H.$`$*#C -M"R"@X20PC>)^_O_K``!0XP4``!H+``#J'W`'X@\`5^.T,MT!`C"#`K0RS0&T -M$MWALC+=X0$`4^&$__^*`#"@X[22W>$_``#J`#"@XST``.H`,*#C*##-Y;*2 -MS>$L<-WE+3#=Y0=R@^%W<._F!@"@X0D0H.$'(*#A!3"@X?[__^L&`*#ALA+= -MX2@@C>(%,*#A_O__ZR@PW>7_`%/C`4"@`RB`C0($```*$```Z@0`5.,C```* -M`4"$XG1`[^8&`*#ALA+=X0<@H.$%,*#A_O__ZP8`H.&R$MWA"""@X04PH.'^ -M___K*##=Y?\`4^/N__\*!P!3X0$PH`,/```*(S*@X10PS>4H`-WE#P``XA4` -MS>7^___K'@#-Y0!0C>4&`*#A`!"@XQ0@C>(B,(WB-?[_ZP``4.,"```*`#"@ -MX[*2W>$```#J`#"@XP``4^,3```*`1")XBT@W>4`4(WE!@"@X7$0_^8N,(WB -M_O__ZP`@H.$/`%#C`0"@`PD```HX,(WB#!!SY0!0C>4&`*#A`C"#XO[__^L` -M`%#B`0"@$P```.H``*#C/-"-XO"/O>@$X"WE#-!-XA#`W>4``%SC`,"@`P#` -MC>5&_O_K#-"-X@"`O>@00"WI`$"@X3L\H.,#`)#G``!0XQ"`O0CE':#C_O__ -MZP`@H.,[/*#C`R"$YQ"`O>CP3RWI)-!-X@"@H.$,$(WE"""-Y10PC>5(D-WE -M``"@X[H!S>$!,(+@`@Q3XP(``-I,`Y_E_O__Z\\``.H"#*#C_O__ZP``4.,0 -M`(WER@``"D``H.,$$*#C`B"@X_[__^L`0*#A!`"-Y0``4..\```*`#"@XP`@ -MX.,#$)3GL"#!X0,0E.>R(,'A`Q"4Y[0@P>$#$)3GMB#!X00P@^(!#%/C]/__ -M&@H`H.$`$*#C'""-X@DPH.'^___K''#=Y?\`5^.G```*NC'=X0$P@^*Z,($@*#A'S`'X@\`4^,G,J`1#V`'$A\``!H*`*#A!1"@X0L@H.$) -M,*#A_O__ZQQ@W>4/,`;B#P!3XQ```!H!0(7B=$#_Y@H`H.$$$*#A"R"@X0DP -MH.'^___K'"#=Y?\P4N(!,*`3_P!4XP`PH(,``%/C3```"@%`A.)T4/_F0@`` -MZO`P!N*G)U4/_FNC'=X0$P@^*Z -M,6T((/A_P!5XV```(H*`*#A!1"@X0L@H.$),*#A_O__ZP%0 -MA>)U4/_FNC'=X0$P@^*Z,4`$*#C`>"@X0X` -M`.H!`)3GLP"0X0``PN4!`)3GLP"0X2`$H.$!`,+E`C"#X@(@@N((`%/C]/__ -M&@C`C.($$('B`0Q1XP(```H,(*#A#C"@X>W__^H(,)WE``!3XPL```H`,*#C -M$,"=Y0P`G>4`$(S@"`"=Y13`G>4#(-'G`R#,YP$P@^)S(/_F`@!0X?G__XH* -M`*#A-Q"@XQH@C>)D.P/C#^"@X0/PFN<+``#J!`"=Y4`0H.,$(*#C`C"@X_[_ -M_^L+``#J"@"@X040H.$+(*#A"3"@X?[__^N____J$`"=Y0(@H!@``!.`MY0S03>("$*#A`R"@X1`PG>44P-WE -M``!(`@+WH<$`MZ0!`H.$!4*#A`0!2XRT``!K/ -M$*#C:2"@X_[__^L$`*#A`!"@X_[__^L""1#C!0``&H`HX.&B*.#A!`"@X0`0 -MH.-R(/_F_O__ZP0`H.$"$*#C_O__ZP$*$.,$```:`2J`XP0`H.$"$*#C-P@+T8!`"@X3<0H./^___K#R``X@0`H.$W$*#CL"""X_[__^MP -M@+WHSQ"@XP`@H./^___K`0!5XW"`O1@$`*#A-Q"@X_[__^M_(`#B!`"@X3<0 -MH./^___K<("]Z!!`+>D`0*#A``!1XPX```J`$*#C_O__ZP$@@.,$`*#A@!"@ -MXW(@[^;^___K!`"@X8(0H./^___K]R``X@0`H.&"$*#C_O__ZQ"`O>B`$*#C -M_O__Z_X@`.($`*#A@!"@X_[__^L$`*#A@1"@XP`@H./^___K$("]Z'!`+>D` -M0*#A`Q"@X_[__^L`4*#A!`"@X0,0H./[(`7B_O__ZP0@A>,$`*#A`Q"@XW(@ -M[^;^___K<("]Z/!'+>D@T$WB`%"@X3L\H.,#0)#G\!"@X_[__^L"E2#BV9O@ -MY]"IX.=0AN/G4`S@YR``A.4%`*#A]!"@X_[__^L`<*#C&'"$Y04`H.%H$*#C -M_O__ZU`AX.<8,)3E`S""X0$G`.('`%+A`B"@$P<@H`$",(/A`24`X@<`4N$$ -M(*`3!R"@`0(P@^$8,(3ET`#@YQP`A.4<<,WE$("-Y12@C>4'4*#A&'"-Y0R0 -MC>4%8*#C"&"-Y1@PC>(#`)/H#3"@X0,`@^@(,(WB#P"3Z/[__^L4<,3E"("$ -MY0R@A.40<(3E0`*$Z`,PH.-!,,3E`3"@XT(PQ.4@T(WB\(>]Z'!`+>D[S*#C -M#$"0YZE-A.(00(3B`0!1XQ4```H"```Z`@!1XW"`O1@7``#J`E"@X0``4^,( -M```*!`"@X3`0H..X+=+A!3"@X?[__^L$`*#AV!#5Y?[__^MP@+WH!`"@X3`0 -MH..X+=+A`#"@X_[__^MP@+WH!`"@X2<0H./_(`/B`#"@X_[__^MP@+WH!`"@ -MX2@0H./_(`/B`#"@X_[__^MP@+WH\$\MZ0S03>(`<*#A`!"-Y0*0H.$$$(WE -MG:((XY>C1>.:,HK@*J.PX0$`H`,/```*`%"=Y0%*H.,`8*#CQ("@XP<`H.$$ -M$*#A"""@X04PH.'^___K``!0XS$```H!8(;BQ$"$XL10A>(*`%;A\___&IVR -M"..7LT7CFSF+X"NSH.'$,*#CDYMKX```6^,D```*DPH)X*N!L.$0```*`4J) -MX@0PG>4)4(/@`&"@XPB@H.,'`*#A!!"@X0H@H.$%,*#A_O__ZP``4.,5```* -M`6"&X@A`A.((4(7B"`!6X?/__QH'8!OB#@``"HB!B>`!6HCB`$"@XP`PG>4( -M@(/@!P"@X040H.$$(-CG_O__ZP``4.,#```*`4"$X@%0A>(&`%3A]?__&@S0 -MC>+PC[WH\$$MZ0!`H.$!4*#A`F"@X0-PH.&"$*#C_O__ZP<@P.,'4`7B!2"" -MX00`H.&"$*#CDDT$WB -M`&"@X3L\H.,#4)#G#`"@X_[__^L8`(WE``!0XP!PH`.M```*`2"@XP`@@.4` -M0`#C`$!`XP1`@.64*0/C"""`Y;0@U.&V(L7A!C#4Y;HRQ>&P,-3AO#+%X;`@ -MU.'P/P_C`#!`XP,P`N#`*`CCP!()XP(`4^$!`%,1!@``"B,,4^,$```*X"@( -MXP(`4^&4*0,3#""-%0(``!H@0(3B=#D#XPPPC>4&`*#A@!"@X_[__^N``!#C -M!0``"@8`H.&`$*#C`""@X_[__^L&`*#A_O__ZP8`H.$!$*#CT_[_Z_[__^L( -M`(WE#""=Y2*&H.$(-H3@'#"-Y0`@H.,4((WE@)"@XSN\H./T.0#C`#!`XPP@ -MG>4#,`+@$#"-Y01`C>4!JJ#C!@"@X0D0H.'^___K!""`XP8`H.$)$*#A((`%3A]/__&@!PH.$0 -M,)WE``!3XPH```H&`*#A"!"@X1P@G>5^___K`'"@X00``.H&`*#A!!"=Y0P@ -MG>4M___K`'"@X0$`5^,!```:"P``Z@!PH.$(`)WE_O__ZWT/4./,___:%""= -MY0,`4N,[```*`3""XG,P[^84,(WEQ?__Z@8`H.$`$*#CA?[_ZP!`H..`4*#C -MZ8,`XP8`H.$%$*#A_O__ZP0`$.,#```:`4"$X@@`5.'W__\:(P``ZOH/5.,A -M```J!@"@X8`0H./^___K`B"`XP8`H.&`$*#C0"#"X_[__^L&`*#A`Q"@X_[_ -M_^L`0*#A!@"@X0,0H./[(`3B_O__ZP0@A.,&`*#A`Q"@XW(@[^;^___K`$"@ -MXX!0H.,%@*#C!@"@X040H.'^___K0``0XPP``!H(`*#A_O__Z_H/5.,!0(02 -M]?__&@!PH.,%``#J!P"@X230C>+PC[WH!@"@X0`0H.--_O_K&`"=Y0P0H./^ -M___K]?__Z@$`$.,`,*`3!@``&@$PH.,P(Z#A`0`2XP(``!H!,(/B(`!3X_G_ -M_QH#`*#A'O\OX1[_+^$$0"WE.\R@XPP`D.<.#%'C!@``&I7%`N,,P-#G#,.` -MX);-C.(8P(SB`#",Y1@``.H$S@#C#`!1X0H``!J5Q0+C#,#0YPS#@."6S8SB -M',",X@`PC.5LR`#C#`!1X0#`H!,!P*`#%P``Z@C.`.,,`%'A!P``&I7%`N,, -MP-#G#,.`X);-C.(PP(SB`#",Y0#`H.,5``#J;$@`XP0`4>$`P*`3`<"@`P$, -M$.4>,&```:E44" -MXP1`T.<$0X#@EDV$XB!`A.(`,(3E$P``ZA1.`.,$`%'A!@``&I5%`N,$0-#G -M!$.`X)9-A.(D0(3B`#"$Y1,``.H83@#C!`!1X08``!J510+C!$#0YP1#@."6 -M383B*$"$X@`PA.42``#J'$X`XP0`4>$&```:E44"XP1`T.<$0X#@EDV$XBQ` -MA.(`,(3E$@``ZH,.4>,&```:E44"XP1`T.<$0X#@EDV$XCA`A.(`,(3E$@`` -MZC1(`.,$`%'A!@``&I5%`N,$0-#G!$.`X)9-A.(\0(3B`#"$Y0@``.HX2`#C -M!`!1X04``!J510+C!$#0YP1#@."7383B$$"$X@`PA.7_`%+C`""@$P$@#`(` -M`%+C!0``"I4E`N,"(-#G`B.`X)$&```:E24"XP(@T.<"`X#@EPV` -MX@0`@.(`,(#E%0``ZDPH`.,"`%'A!@``&I4E`N,"(-#G`@.`X)<-@.((`(#B -M`#"`Y0L``.IH*`#C`@!1X0@``!J5)0+C`A#0YP$3@."7'8'B#!"!X@`P@>4" -M,-#G`3"#X@(PP.<0`+WH'O\OX0$`H.,>_R_A`0"@XQ[_+^$!$$'B!P!1XP

    ('`%'C!P#@@P`P`),`,$"3`1&#D"``D96B`(#@'O\OX?!!+>D`0*#A -M`8"@X3L\H.,#4)#G`1"@XX4U`N,#(-7G_O__ZP!PH.&&-0+C`V#5YX0U`N,# -M(-7G`B"&X`0`H.$"$*#CDPT$WB.\R@XPP`D.(24(7BL&0"XP:@@>"2C8'B -M-("(XI)-@>($4(WE``!4`D,+EJ)0"XPF0T.<$ -M4-3E#Y`)X@F0A>``D,/E!I#0YP10U.4/D`GB"9"%X%!0G>4`D,7E!)#4Y52P -MG>4`D,OEA@``Z@$`7.,;```:D9V!XC:0B>(`D-GE`9#"Y0"PVN4/L`OB&+#- -MY0"PV.4/D`OB&+#=Y0E0B^`$D-3E"9"%X`&0P^6T5`+C!9#0YP!0V.4$L-3E -M*9*+X"62B>!04)WE`9#%Y9*=@>(.D(GB!)#9Y52PG>4!D,OE:```Z@(`7.,K -M```:DIV!X@20B>(`D-GE`I#"Y0"PVN4/L`OB&+#-Y0"PV.4/D`OB&%#=Y0F0 -MA>"2O8'B.+"+X@10U.4%D(G@&)#-Y0"0V^4/D`GB()#-Y1A0W>4)4(7@+%"- -MY0)0P^4`D-KE&)"-Y0"0V.4IDJ#A&%"=Y252B>`84,WE`+#;Y2RPC>4$L-3E -M"Y"%X"Q0G>4EDHG@4+"=Y0*0R^62G8'B')")X@20V>544)WE`I#%Y3H``.H# -M`%SC.```&@2PG>4`D-OE`Y#"Y0"PVN4/L`OB&+#-Y0"PV.4/D`OB&%#=Y0F0 -MA>"2O8'B.+"+X@10U.4%D(G@+)#-Y0"0V^4/D`GB()#-Y9)=@>(\4(7B&%"- -MY0"0U>40D,WE+)#=Y2!0W>4%4(G@(%#-Y1!0W>4/4`7B()#=Y060B>`LD(WE -M`Y##Y0!0VN4`D-CE*9*@X262B>`@D,WE`+#;Y2RPC>4$L-3E"[")X""PS>48 -M4)WE`%#5Y0Q0C>4L4)WE)9*+X`RPG>4KDHG@4%"=Y0.0Q>62G8'B*I")X@20 -MV>54L)WE`Y#+Y0'`C.)\P._F#`!7X5[__XHPT(WB\`^]Z![_+^$['*#C`1"0 -MYP``TN6%)0+C`@#!YP`@T^6&-0+C`R#!YP`PG>4`(-/EAS4"XP,@P><$,)WE -M`"#3Y8@U`N,#(,'G'O\OX?!!+>D`4*#A`6"@X3L\H.,#<)#G`1"@XP8@H.'Y -M_O_K`$"@X04`H.$($*#C!B"@X?3^_^N$-0+C`S#7YP`@8^```%+C`#"@TP`P -M8\!S,._&DWV'X@`@H.,`0,?E.##'Y1PPQ^4.0,?E1C#'Y2HPQ^4!((+B,!$*`#/!##Y1[_+^$>_R_A`0"@XQ[_+^'P12WI'-!-X@!@H.$! -MH*#A%%"-XA!PC>(,@(WB`("-Y0A`C>($0(WE!2"@X04&`*#A"A"@X04@H.$',*#A_O__ZP8`H.$%$*#A_O__ZP"@C>4&`*#A!Q"@ -MX0@@H.$$,*#A_O__ZQS0C>+PA;WH\$$MZ0!PH.$!@*#A`D"@X0-@H.$!`'+C -M!0``"O[__^L`4*#A!`"@X>O]_^L$0,7A%F"$X0<`H.$($*#A!B"@X?[__^OP -M@;WH$$`MZ0!`H.$(&0#C_R\/XP`PH./^___K!`"@X0@9`./_+P_C`S@`X_[_ -M_^L$`*#A"!D`X_\O#^,&.@#C_O__ZP0`H.$(&0#C_R\/XP$[`^,#,-#G``!3XPP``!I.$*#C_O__ZX`LX.&B+.#A!`"@X4X0 -MH.-R(._F_O__ZP0`H.%X&`#C`BJ@XP$PH./^___K``!5XP<```H``%;C!`"@ -MX608`.-@(*#C`3"@$P(PH`/^___K<("]Z```5N,$`*#AAAZ@XP,LH.,",*`3 -M`3"@`_[__^MP@+WH$$`MZ3L\H.,#,)#G`""3Y0$@0N(!`%+C!0``BA`PD^4" -M`%/C`@``&@$@H./,___K$("]Z``@H./)___K$("]Z/!!+>D`4*#A.SR@XP-` -MD.H./_(*#C_O__ZY$U`N,#`,3G!0"@X5@< -M`./_(*#C_O__ZY(U`N,#`,3G!0"@X<8>H./_(*#C_O__ZY,U`N,#`,3G!0"@ -MX6@<`./_(*#C_O__ZY0U`N,#`,3G!0"@X3@<`./_(*#C_O__ZXDU`N,#`,3G -M!0"@X30<`.,`(.#C_O__ZXPU`N,#`(3G<("]Z!!`+>G^___K$("]Z/!!+>D` -M0*#A.UR@XP4PD.>'+J#C\!@"XP$@@^H./X*`+C`A"#YV0H`..ES:#C#""#Y_S(`N,,$(/G1!D"XP$@@^8&0+C`2"#Y^`9 -M`N,!((/G@AZ@XPPI`N,"$(/G*!@`XU0I`N,"$(/G)!@`XQ`I`N,"$(/G+!@` -MXU@I`N,"$(/G6"@`XQ09`N,!((/G7!D"XP$@@^=<*`#CI!D"XP$@@^?L&0+C -M`2"#Y\4>H.,8*0+C`A"#YU@<`.-@*0+C`A"#Y\8>H..H*0+C`A"#YV@<`./P -M*0+C`A"#YU0<`.,<*0+C`A"#YUP<`.-D*0+C`A"#YV0<`..L*0+C`A"#YVP< -M`./T*0+C`A"#YQ0<`.,@*0+C`A"#YQP<`.-H*0+C`A"#YR0<`..P*0+C`A"# -MYRP<`./X*0+C`A"#Y\$>H.,D*0+C`A"#YQ@<`.-L*0+C`A"#Y\(>H..T*0+C -M`A"#YR@<`./\*0+C`A"#YS(=H.,H*0+C`A"#YX@<`.-P*0+C`A"#Y\D>H..X -M*0+C`A"#YY@<`.,J+*#C`A"#YX0<`.,L*0+C`A"#YXP<`.-T*0+C`A"#YY0< -M`..\*0+C`A"#YYP<`.,$*@+C`A"#YXH>H.,P*0+C`A"#YZ08`.-X*0+C`A"# -MYZ@8`..G+:#C`A"#YZP8`.,(*@+C`A"#Y[@8`.,T*0+C`A"#Y[P8`.-\*0+C -M`A"#YP(0H./^___K`BJ`XP,@@N,$`*#A`A"@XW(@_^;^___K!`"@X1\0H.,' -M(*#C_O__ZP0`H.$"$*#C%R"@X_[__^L$`*#A%1"@X^D@H./^___K!7"4YZE= -MA^(04(7B!0"@X0`0H./^___K`6!0X@%@H!,!`%;C"@``&A`T`^,#,-3G``!3 -MXP`@H`.5-0(#`R#'!P4`H.$!$*#C_O__ZP$`4.,`8*`#!@"@X?"!O>AP0"WI -M`$"@X3L\H.,#`)#GJ0V`XA``@.+^___K`%"@X00`H.'*%`#C"R"@X_[__^L! -M`%7B`0"@$W"`O>CP1RWI`$"@X0%@H.$[/*#C`W"0YW*@[^8D&`#C`"#@X_[_ -M_^L`@*#A``!6XQT```J&D8;@B9&'X"F(0D(GB!`"@X0`0F>4`(.#C_O__ -MZW\$P.,"5<#C!`"@X208`.,`(.#C`C'(X_[__^L*`*#C_O__ZXI;A>$$`*#A -M`!"9Y0`@X.,",87C_O__ZV0`H./^___K"@"@X_[__^L!`%;C+```&AH``.H$ -M`*#A)!@`XP`@X.,",]Z(9AAN"& -M<8?@*7R'XC!PA^($`*#A`!"7Y?\O#^,/($#C_O__Z_"'O>CP1RWI`&"@X0%` -MH.$"@*#A`W"@X2"@G>7_/P_C#S!`XP,`5^$%```*E/__ZP!0H.$'`*#AA?O_ -MZP=0Q>$:H(7A.SR@XP,PEN>$083@A$&#X"E,A.+_I,KC#Z;*X_\P".(&`*#A -M`!"4Y0`@X.,#.HKA_O__Z_"'O>CP12WI#-!-X@!0H.$!0*#A.SR@XP,PD.<\ -M$-/E0"#3Y04`4N,J```*``!4XP%`H`,\0,/ES"L#XP(@D.<``%+C(@``&M`K -M`^,"()#G``!2XQX``!H[/*#C`V"0YP00H.'^___K!("@X4(PUN4``%/C%P`` -M"@!`H./_?P_C#W!`XQB@H.,J/83B!#"#X@,AEN?_+\+C`R#"XP@@@N$#(8;G -M`""-Y04`H.$$$*#A"B"@X0W__XH` -M``#J/!##Y0S0C>+PA;WH<$`MZ0-`H.%'___K`%"@X00`H.$X^__K!$`%X#0` -MH.%P@+WH\$\MZ3303>(`@*#A`7"@X0*PH.$0P(WB'#&?Y0\`D^@/`(SH`3R@ -MXR`PC>4)/*#C)#"-Y0([H.,H,(WE`S"@XRPPC>4`0*#C`9"@XP10H.$,8*#A -M_Z\/XP^@0.,P((WB!S&"X!`P0^(,,(WE`P!7XP?QGY<#``#J)'P"`*A[`@"H -M>P(`U'L"``"0H.,>``#J##"=Y0!0D^4(`*#A!1"@X00@EN?^___K"`"@X040 -MH.'^___K`%"@X1,``.H$,);G`SJ@X2,ZH.$$,(;G`#"-Y0@`H.$+$*#A`R"@ -MXPHPH.'^___K"@"@X_[__^L(`*#A"Q"@X0,@H.,`,.#C_O__ZP!0H.$*`*#C -M_O__ZP0PEN<%`%/A!```&@1`A.(0`%3C`@``"@-0H.'/___J`)"@XPD`H.$T -MT(WB\(^]Z+P3```>_R_A<``MZ0S03>(<0)WE(,"=Y3M,5```*`!"@XP-`X.,X`)7E``!0XPA@C>(!`(;@`6#2!P%@TQ<$8,#G -M"&"-X@$`AN`$`-#G`&B@X0!LAN$`8(;A``2&X0$!C.4! -M`%#AZ___B@S0C>)P`+WH'O\OX?`/+>DHT$WB#!"-Y1PPC>4[/*#C`\"0YT^P -MW.6578'B*%"%X@50C.``,*#C`Q"@X0-PH.$#D*#A`Z"@X22`C>+Z"0_C^0E/ -MXQ0`C>449`'C%&1!XQA@C>4#`%OC"_&?EWX``.J(?0(`P'T"`'!^`@"(?@(` -M``!1XP@`H!,``*`#`@"`X)8.@.(&`(#B``&4%`%3C`9"@DPX``)H,8)WE"`!6XP*0H),*``":#`"= -MY0L`4.,#D*"3!@``F@Q`G>4-`%3C!)"@DP(``)H,8)WE#@!6XP60H`,``%'C -M"$"@$P!`H`,)`H+@!`"`X)8.@.(&`(#B``&"63H3B!D"$X@1!G.=_,*#C$T4$X#1%H.%T0._F`$#(YQ`PG>4# -M`%3A`'#(QP$`@.($`%#C[/__&@90H.$$,)WE)P#=Y29`W>4$2*#A`$R$X20` -MW>4`0(3A)0#=Y0!$A.$!`%+C'&"=E4A@G84#`);G!$"`X`J0H.$,``#J``!1 -MXP@`H!,``*`#``""X)8.@.(&`(#B``&("`%'C7O__&BC0C>+P#[WH'O\OX0`P -M`.,`,$#C`1-AX`(@@>""`9/G'O\OX0```.,``$#C`1-AX`(0@>#_-,/C#S;# -MXX$Q@.>!$8#@`3"@XP4>_R_A````XP``0.,!$V'@`A"!X($!@.`$,,#E -M'O\OX0```.,``$#C`1-AX`(0@>"!`8#@!C#`Y1[_+^'P02WI`&"@X0!0H.,% -M<*#A`8"@XPT``.HF,$3B`0!3XP8`H.$%$*#A!""@X0("`%7C\(&]"`=`H.'O___J\$$MZ0!@H.$`4*#C!7"@ -MX0&`H.,-``#J)C!$X@$`4^,&`*#A!1"@X00@H.$',*"!"#"@D?[__^L!0(3B -M0`!4X_3__QH!4(7B`@!5X_"!O0@'0*#A[___Z@``H.,`P`#C`,!`XP`@H.$+ -M``#J`""#Y00@P^4&(,/E!2##Y0<@P^4!$('B"#"#XD``4>/V__\:`0"`X@(` -M4.,>_R\!@#2@X8`Q0^`#,(S@`A"@X>[__^H$X"WE#-!-X@`P`.,`,$#C`<-A -MX`+`C.",,8/@!3#3Y0$`4^,0```:`#``XP`P0.,!PV'@`L",X(PQ@^`&,-/E -M`0!3XP@``!H`,`#C`#!`XP'#8>`"P(S@C#&3YP`PC>7_/P_C#S!`X_[__^L, -MT(WB`("]Z/!!+>D`8*#A`%"@XP5PH.$)``#J!@"@X040H.$$(*#A_O__ZP%` -MA.)``%3C^/__&@%0A>("`%7C\(&]"`=`H.'S___J!.`MY0S03>([/*#C`S"0 -MYP``4>,"```*`0!1XQ8``!H*``#J$!H"XP$@D^<#*X+C`2"#YP`@C>4`$*#C -M&""@X_\_#^,/,$#C_O__ZPH``.H0&@+C`2"3YP,KPN,!*X+C`2"#YP`@C>4` -M$*#C&""@X_\_#^,/,$#C_O__ZPS0C>(`@+WH<$`MZ0%`H.$"4*#A`#``XP`P -M0.,!(V'@!2""X((Q@^`$,-/E`0!3XP``H!-P@+T8!2"@X?\_#^,/,$#C_O__ -MZP`P`.,`,$#C!"-DX`4@@N"",9/G`P!0X08```H`,`#C`#!`XP0C9.`%((+@ -M@C&#X`$@H.,%(,/E`#``XP`P0.,$0V3@!5"$X(4Q@^`%`-/E<("]Z/!!+>D` -M8*#A`%"@XP5PH.$)``#J!@"@X040H.$$(*#A_O__ZP%`A.)``%3C^/__&@%0 -MA>("`%7C\(&]"`=`H.'S___J\$\MZ0S03>(`@*#A.SR@XP,PD.=!(-/E`P!2 -MXP$@H`,"(*`30B##Y3L\H.,#H)#G0C#:Y0``4^,!4*`#?0``"JDMBN(0((+B -M!""-Y0`PH.,`,(WE`W"@X0%@H.,#L*#A!U"@X0,`5^,'\9^7%```ZA2$`@`X -MA`(`%(0"`#B$`@"',8?@@S&*X`@`H.'P*`+C`A"3YQ`@H./^___K``"-Y0<` -M`.J',8?@@S&*X`@`H.'P*`+C`A"3YP$FH./^___K``"-Y861A>")D8K@HTV) -MXCA`A.((`*#A!!"4Y0$FH.,&,*#A_O__ZP8`H.'^___K"`"@X0`0E.40(*#C -M!C"@X?[__^L&`*#A_O__ZRE,B>(00(3B"`"@X0`0E.4!*Z#C"S"@X?[__^L& -M`*#A_O__ZP@`H.$`$)3E`BN@XPLPH.'^___K!@"@X?[__^L``%?C`@``"@$` -M5^,0```:!P``Z@0`G>4%$*#A!2"@X?[__^L!`%#C"T"@`1$``!H1``#J!`"= -MY040H.$%(*#A_O__ZP$`4.,+0*`!$P``&A,``.H#`%?C!_&?EP,``.I8A0(` -M@(4"`%B%`@"`A0(`!D"@X1(``.H&0*#AA5&%X(51BN`(`*#A\#@"XP,0E><0 -M(*#C`#"=Y?[__^L(``#J!D"@X851A>"%48K@"`"@X?`H`N,"$)7G`2:@XP`P -MG>7^___K`0!4XP8``!H!<(?B=W#OYD(PVN4'`%/AC/__B@10H.$```#J!%"@ -MX04`H.$,T(WB\(^]Z'!`+>D0T$WB`$"@X3L\H.,#`)#G`#"@XP@PC>4,,(WE -MR#F4Y0,`4^,=```:/S\#XS\_0^,,,(WE`##1Y0,HH.$#)(+A`R""X0,\@N$( -M,(WE(`!3XP0``)KI.`+C`S#0YP``4^,@,*`3"#"-%0$PT>4#**#A`R2"X0,@ -M@N$#/(+A##"-Y2``4^,O``":Z3@"XP,PT.<``%/C(#"@$PPPC14I``#J1CH" -MXP,PT.,0,$'C"#"-Y0PPC>4@``#J`@!3XQX```H`,-'E -M`RR@X0,D@N$#((+A`SB"X0@PC>4!,-'E`RB@X0,D@N$#((+A`SR"X0PPC>5/ -M,-#E``!3XP\``!JP-0+C`S"0YP@@G>4#,(+@M"4"XP(@D.<"-(/@"#"-Y=`U -M`N,#,)#G#""=Y0,P@N#4)0+C`B"0YP(\@^`,,(WE","-XA!@C>(`4*#C/^"@ -MXPP0H.$%,*#A`R#1YS\`4N,#X,&'`3"#X@0`4^/Y__\:!,",X@8`7.'T__\: -MJ0V`XA``@.(!$*#C`R"-X@0PC>+^___K`S#=Y0$`4^,'```:!#"=Y0@@G>4# -M((+@"""-Y0P@G>4#,(+@##"-Y0@``.H"`%/C!@``&@0PG>4(()WE`B!CX`@@ -MC>4,()WE`C!CX`PPC>4$`*#A"!X`X_\LH.,(,-WE_O__ZP0`H.%L&`#C_R#@ -MXP@PG>4C-*#A_O__ZP0`H.%L&`#C_R"@XP\PW>7^___K!`"@X3@8`./_(.#C -M##"=Y?\TP^/^___K$-"-XG"`O>CP3RWI;-!-X@"0H.&0P-WE),"-Y3O,H.,, -M0)#G),"=Y0#`C>58P(WB!,"-Y5#`C>((P(WE_O__ZZD-A.(0`(#B`!"@XTL@ -MC>),,(WB_O__ZP`0H.,4$(WE&!"-Y7^@H.-$8(WB4#"-X@`PC>5@,(WB!#"- -MY0D`H.$D$)WE&""=Y5@PC>+^___K2S#=Y0$`4^,'```:3#"=Y6`@G>4#((+@ -M8""-Y60@G>4#,(+@9#"-Y0@``.H"`%/C!@``&DPPG>5@()WE`B!CX&`@C>5D -M()WE`C!CX&0PC>4[/*#C`S"9YQPPC>4X,(WB`,``XP#`0.,'`)SH!P"#Z"PP -MC>*@P9_E!P"5@((WB!Q&2YPLPH.&#(:#A&@(! -MX#`BH.%R(._F`R#&YS\`4N,_P*"#`\#&AP$P@^($`%/C]/__&D>`W>5&,-WE -M`SB@X0@\@^%$(-WE`C"#X44@W>4"-(/A=R#OY@``4N,X((T"%!"=!;%`D@$L -M((T2%,"=%;Q`DA$)`*#A!!"@X0`@X./^___K'!"=Y4$PT>4"`%/C!0``&F@X -M`.,<+@#C`P!4X0(`5!$%```**```ZD@X`.,4+@#C`P!4X0(`5!$C```:%#X` -MXQPN`.,#`%3A`@!4$4)`*#A!!"%X'@@[^;^___K`5"%X@,` -M5>/H__\:`7"'X@(`5^.G__\:&""=Y0$P@N)S,._F&#"-Y10PG>4",(/B%#"- -MY1C`G>4&`%SC+PC[WHV!,``#L\H.,#`)#GV3@#XP,PT.<``%/C -M'O\O`30PT>4U`-'E`#2#X38`T>4`.(/A-P#1Y0`\@^$T`-+E-<#2Y0P$@.$V -MP-+E#`B`X3?`TN4,#(#A``!3X1[_+[$T,,+E(P2@X34`PN4C"*#A-@#"Y2,\ -MH.$W,,+E_R_A$$`MZ3L\H.,#,)#GV2@#XP(@T^<``%+C%@`` -M"FP@D.4!`!+C$P``&KP+P+C`A#3YP(`4>,!$*`#`A"@$P(0P^<`(*#C_O__ZP$`H.,0 -M@+WH``"@XQ"`O>@00"WI.SR@XP,`D.>I#8#B$`"`XO[__^L0@+WH\$$MZ0!@ -MH.$[3*#C!`"0YZE]@.(0<(?B*@R`XB0`@.(`$*#C+""@X_[__^L$4);GJ4V% -MXA!`A.($`*#A`!"@XP0@H./^___K4#H"XP-@A><$`*#A`!"@XP0@H./^___K -M!`"@X0(0H..X(=;A_O__ZP0`H.$$$*#C$""@X_[__^L$`*#A!A"@XP`@H./^ -M___K!`"@X040H.,!(*#C_O__ZP0@E>4$`*#A`Q"@XP$`4N,`(*`3`2"@`_[_ -M_^L$`*#A#!"@X[0BU>'^___K!`"@X0X0H.,"/P+C`R#6Y_[__^M!,-7E`P!3 -MXP4``!H$`*#A!Q"@XP`@H.,`,*#C_O__ZPX``.H"`%/C!0``&@0`H.$'$*#C -M`B"@XP`PH./^___K!@``Z@``4^,$```:!`"@X0<0H.,!(*#C`#"@X_[__^L% -M)*#C*#H"XP,@A><$`*#A`1"@XP4DH.,`,*#C_O__ZP<`H.'^___K!P"@X?[_ -M_^OP@;WH<$`MZ0C03>(`0*#A"""-X@$PH.,!,&+E.SR@XP-@D.>%,P/C`U#0 -MYR@0H.-H.P/C#^"@X0/PD.?8.@/C`S#4YP``4^,`,*`3!S#-%>$[`^,#,-3G -M`0!3XS8``!H``%7C-```&@4``%/C,0``"FP@E.40`!+C`@``&F``$N,! -M(`("!```"@@X`>,#()3G`@!2XP`@H-,!(*##J5V&XA!0A>(%`*#A*1"@X_\@ -M`N(`,*#C_O__ZSL\H.,#,)3G;""4Y0$`$N,)```:-"H"XP(@D^<``%+C"@`` -M&@`0H.,\*@+C`A"#YVP@E.4!`!+C!```"C0J`N,"$)/G/"H"XP(0@^<#``#J -M-"H"XP(0D^<\*@+C`A"#YSPZ`N,#();G!0"@X2H0H./"/Z#A_O__ZP4`H.'^ -M___K"-"-XG"`O>CP1RWI`("@X3M*_(`#C*#H"XP$E0.,#((3G!0"@X;\@`.,!)4#C`#"@X_[__^L%`*#A -M$1"@XU4MB.+^___K!0"@X1(0H.,6+(CB_O__ZP4`H.$3$*#C?BZ(X@$@@N+^ -M___K!0"@X140H.,]((3B_O__ZP4`H.$6$*#C8RV(X@P@@N+^___K!0"@X1<0 -MH.,X((3B_O__ZP4`H.$8$*#C/""$XO[__^L%`*#A)A"@X_(MB.(L((+B_O__ -MZP4`H.$?$*#C<""(XO[__^L%`*#A(!"@XS,LB.(T((+B_O__ZP4`H.$O$*#C -M_R"@X_[__^L&0*#A,&"@XP1PH.$%`*#A!A"@X70@_^8',*#A_O__ZP%`A.(@ -M`%3C]___&@H`H.'^___K`"#@XS0]`^,#(,CG\(>]Z'!`+>D`0*#A`5"@X>PV -M`>,#,-#G``!3XP8```H`,*#C\"8!XP(P@.?T)@'C`C"`Y^PF`>,",,#G\#8! -MXP,0E.7T-@'C`R"4YP(`@.`#`(3G_O__Z^TV`>,#`,3G -M``!4XP``51-P@+T(X#8!XP,PU.<``%/C!@``"@`PH./D)@'C`C"$Y^@F`>," -M,(3GX"8!XP(PQ.?D-@'C`Q"4YP$0@>(#$(3G90#5Y>@V`>,#()3G`@"`X`,` -MA.?^___KX38!XP,`Q.=P@+WH\$\MZ0S03>(`0*#A`8"@X1!0D.4[/*#C`Z"5 -MYV20@.(`,*#C`C#-Y0,PS>4$,,WE`P!0X0-@H`%\8)`5!G"@X;`PUN$,(`/B -M!`!2XW<```JR(]#A``!2XW0``!H!#!/C`B"@$P`@H`/3-.#G`S""X0,`4^,# -M\9^7`P``ZH21`@",D0(`E)$"`)R1`@```*#C!@``ZA``AN($``#J"@"&X@(` -M`.H$`(;B````Z@0`AN+@$(7B!B"@X_[__^L``%#C6@``"@$PH.,",,WEL"#7 -MX0$,$N,",*`3`#"@`](DX.<",(/A`0!3XP0`A@(!```*$`"&(@0`AC(-&X7B -M$1"!X@8@H./^___K``!0X@$`H!,#`,WE`C#=Y0``4^-&```*L##7X?PP`^*` -M`%/C0@``&@$PH.,$,,WE;#"5Y0@`$^/@L(42"0``Z@$`4^,*L(8R!@``.@(` -M4^,8L(82`P``&@$``.H0L(;B````Z@JPAN(`,.#C`3#-Y5L-A>(X`(#B"Q"@ -MX?[__^L`8%#BV#"6%0$PS156(-3E"#"-X@@@8^6I#8KB$`"`X@D0H.$((*#A -M#3"@X?[__^L`,*#CC#"$Y0(PW>4``%/C"0``"FPPE>40`!/C!@``"@``5N,A -M```*C&"$Y04`H.$$$*#A_O__ZQP``.H#,-WE``!3XP(``!H$,-WE``!3XQ8` -M``IL,)7E8``3XP$```H``%;CC&"$%04`H.$$$*#A_O__ZPT``.H``*#C`@#- -MY;3__^H`,*#C!##-Y;`PU^$!#!/C`""@`P(@H!/3-.#G`S""X0$`4^.X__\: -MOO__Z@S0C>+PC[WH,$`MZ1S03>(`0*#A`#"1Y0`PC>4$,)'E!#"-Y0@PD>4( -M,(WE##"1Y0PPC>40,)'E$#"-Y10PD>44,(WE#5"@X1P`@.(`$*#C6""@X_[_ -M_^L!,-WE4S/@YS(PQ.4-,-WE4S/AYUDPQ.4``%/C*@``&K`PW>%3,.WGO#'$ -MX0(PW>53(./G@B&@X1\@Q.4#(-WE4A'@YQX0Q.4(("+BTB'@YRX@Q.53(N+G -M+R#$Y=,SX.X -M,L3A"3#=Y5,RX^73,^#G,S#$Y1<``.H!`%/C!```&@@PH..\,<3A`#"@ -MXQ\PQ.40``#J`@!3XPH``!JP,-WA`SN@X2,[H.&\,<3A`#"@XQ\PQ.40,)WE -M7#"$Y10PG>5@,(3E`P``Z@,`4^.P,-T!4S#M![PQQ`$_R_A'O\OX1[_+^%P0"WI`%"@X0%` -MH.$"8*#A`""@XP`@P>4!(,'E!`"!X@,0H.$&(*#C_O__ZPH`A.(-&X7B$1"! -MX@8@H./^___K$`"$XL,>A>(&(*#C_O__ZP0PH.&V(?/A#R`"XK`@P^$`,-3E -M`2#4Y0(T@^'\,,/C`SB@X2,XH.%0,(/C`##$Y2,TH.$!,,3EH"R5Y0,,4N-P -M@+V(&`"$XLH>A>($$('B_O__ZZ`\E>48,(/B`#"&Y7"`O>CP3RWI+-!-X@!` -MH.$!L*#A`I"@X10PC>4[/*#C`S"0YQ`PC>4$@)/E`0!8XP"`H!,!@*`#`#"@ -MXR0PC>4@,(WEL#P#XP,PT.<``%/C>```"A00G>4``%'C=0``"@<`4N-S``"* -MT#L#XP,PD.49&@+C`1#2YP00C>5D0*#C4%`*#A!A"@X?[__^L'``#@<`#OY@``6.,"```*``!0XU8```H&``#J``!0 -MXP0``!H%`*#A"!"=Y?[__^L``%#C3@``"@``5.-)```*`4!$XNK__^H<`)WE -M%!"=Y0D@H.'^___K&0``ZAP`G>44$)WE`R"@X_[__^L@`(WB%""=Y0,0@N(8 -M()WE_O__ZP0PG>5\8(/B!F&@X1@0G>4``%'C"@``"@!`H.,!<*#A!0"@X000 -MAN`@,(WB!"#3Y_[__^L!0(3B=##OY@,`5^'V__^*!!"=Y71`@>($0:#A`&"@ -MXP4`H.$$$(;@!B#:Y_[__^L!8(;B!`!6X_C__QH``%CC"P``&@4`H.%S'Z#C -M_O__ZP0@G>50`J#A`0`0XPP```H%0*#A!0"@X0<=@N+_(*#C_O__ZP0PG>4! -M((/B`R`"XADZ`N,0$)WE`R#!YP$`H.,(``#J#""=Y0``4N,!`*`#!```"@PP -MG>4!,$/B##"-Y9C__^H``*#C+-"-XO"/O>@`L,KE`P!9X['__YJU___J!.`M -MY0S03>((,(WB!!!CY200H.,!(*#C9/__ZPS0C>(`@+WH!.`MY0S03>((,(WB -MLA!CX0$0H.,"(*#C6___ZPS0C>(`@+WH!.`MY0S03>(%`%'C`?&?ER```.J$ -MF`(`M)@"`,28`@#0F`(`\)@"`."8`@``,*#C`##-Y1TS`^,#,-#G`S*@X0$P -MS>4!,*#C`C#-Y7P[`N,#,-#G`S#-Y1X``.H!,*#C`##-Y0`PH.,B``#J`3"@ -MXP`PS>4?``#J`3"@XP`PS>4",*#C&P``Z@(PH.,`,,WE`#"@XQ<``.H`,*#C -M`##-Y1TS`^,#,-#G`S*@X0$PS>4!,*#C`C#-Y7P[`N,#,-#G`S#-Y0``4>," -M```*`#"@XP0PS>4!``#J##"@XP0PS>4@$*#C!2"@XPTPH.$=___K#-"-X@"` -MO>@=(P/C`B#0YP(R@^$!,,WE`3"@XP(PS>5\.P+C`S#0YP,PS>7J___J$$`M -MZ0`P4>($`*`#$("]"``0T^4!(-/E`C"#X@G__^L``*#C$("]Z/A/+>D`8*#A -M`5"@X0*@H.$#<*#A*(#=Y2RPW>4PD-WE-"#=Y0%`H.$`,*#C`##!Y0$PP>4# -M`%+A`##!%1`PH!,!,,$5.#&0Y0$`4^,"```*!`!3XS(``!H8``#J`##1Y0$@ -MT>4"-(/A`3R#XW,P_^8`,,'E(S2@X0$PP>7"#H#B#`"`XO[__^L`$*#A!`"% -MX@8@H./^___K"@"%X@T;AN(1$('B!B"@X_[__^L0`(7B!Q"@X08@H./^___K -M*```Z@`PT>4!(-'E`C2#X0(\@^-S,/_F`##!Y2,TH.$!,,'E!`"!X@<0H.$& -M(*#C_O__Z\(.AN(,`(#B_O__ZP`0H.$*`(7B!B"@X_[__^L0`(7B#1N&XA$0 -M@>(&(*#C_O__ZP\``.H$`('B!Q"@X08@H./^___K"@"%X@T;AN(1$('B!B"@ -MX_[__^O"#H;B#`"`XO[__^L`$*#A$`"%X@8@H./^___KMC'TX0\P`^*P,,3A -M`0!8XQ```!JP,-7A_###X\@P@^.P,,7A`9`)XA@PU>49(-7E#Q`+X@(T@^$# -M,('A"9*#X7F0_^88D,7E*92@X1F0Q>4:,*#C!```ZK`PU>'\,,/C2#"#X[`P -MQ>$8,*#C`#"*Y?B/O>CP02WI`%"@X0%`H.$"<*#A`#"@XP`PP>408*#C`6#! -MY;`PT>'\,,/CI#"#X[`PP>'$.P#CLS"0X0,YX.$C.>#ALC#!X<(.@.(,`(#B -M_O__ZP`0H.$$`(3B!B"@X_[__^L*`(3B#1N%XA$0@>(&(*#C_O__ZP!@A^7P -M@;WH\$4MZ1S03>(`4*#A`4"@X0*@H.$`(`#C`"!`XPPPC>(#`)+H!`"#Y+`0 -MP^$`,*#C`##$Y0$PQ.4$`(3B#!"-X@8@H./^___K"@"$X@T;A>(1$('B!B"@ -MX_[__^O"#H7B#`"`XO[__^L`$*#A$`"$X@8@H./^___K!#"@X;8A\^$/(`+B -ML"##X;`PU.'\,,/C@#"#XP1PH.&P,L?@(#"@XQ0PC>7*;H7B!&"&X@8`H.'^ -M___K`!"@X0<`H.$"(*#C_O__ZR)PA.(4,)WE`C"#XA0PC>4&`*#A_O__ZP`0 -MH.$'`*#A`B"@X_[__^LD`(3B%#"=Y0(P@^(4,(WE'"N5Y0,@`N(#`%+C!@`` -M&J`LM>4,($+B`R""X!0@C>40$(7B_O__ZR\``.HX+)7E%&"-X@!@C>4`$*#C -MPSZ%X@PP@^+^___K`("@X3)-A>(,0(3B!`"@X?[__^L`<*#A`&"-Y0@`H.$! -M$*#C"`!7XP<@H#$((*`C!#"@X?[__^L`8(WE`Q"@XP$@H./'/H7B!#"#XO[_ -M_^L<.Y7E`S`#X@$`4^,'```:&#"-X@`@H.,0("/E%""-X@`@C>4&$*#C`B"@ -MX_[__^L(`%?C!@``FA0PC>(`,(WE,A"@XP@@1^+)/H7B!#"#XO[__^L4,)WE -M(""#X@(,4N,`,(J5'-"-XO"%O>CP3RWI1-!-X@!@H.$[/*#C`S"0YP$`4>,1 -M`0`:&#"-Y<0[`..S()#A`BG@X2(IX.&H%@#C<&`*#A`1$`X_[__^L&`*#A`!"@XP@@H./^___K!@"@ -MX1`0H.,`(*#C_O__ZR!*`N,8,)WE!"#3YT`0`N(<$(WE!@"@X2(4`.._(`+B -M_O__ZQ@@G>4$,-+G0###XP0PPN=3/8;B(#"#XA0PC>7"'H;B#!"!XA`0C>4` -ML*#C"W"@X08`H.$*$@#C_O__ZP$@@.,&`*#A"A(`XW(@[^;^___K^@^@X_[_ -M_^L`0%#BD0``"CLLH.,"@);G!@"@X2@0A.(\((WB_O__ZSQ0G>4@4(7B?S`5 -MX@$PH!.E4X/@_U`%X@$`5>,"4*`#W3@#XP-0R.>%HZ#A**"*XB50S>4&`*#A -M"A"$X#0@C>+^___K(!!*X@!PC>4&`*#A`1"$X#0@G>4!,*#C_O__ZS0@G>4@ -M((+B?S`2X@$PH!.B,X/@!U4._F@X.*X'B`_^8F4,WE$`"=Y?[_ -M_^L`,*#A`'"-Y01PC>4(<(WE#'"-Y08`H.$($(3@,""-XO[__^L@$$CB`'"- -MY08`H.$!$(3@,""=Y0(#_YB10S>40`)WE_O__ZP`PH.$`<(WE!@"@X0@0A.`X -M((WB_O__ZR`02.(`<(WE!@"@X0$0A.`X()WE!S"@X?[__^LX()WE("""XG\P -M$N(!,*`3HC.#X',P[^:#@XC@`U"%X"=0S>7X7P_C`%!`XP50".`0`)WE_O__ -MZP`PH.$!(*#CA`"-Z`APC>4,<(WE!@"@X040A.`L((WB_O__ZR`01>(`<(WE -M!@"@X0$0A.`L()WE!S"@X?[__^LLH)WE%`"=Y?[__^L`@%#B%@``"@I0A>`& -M`*#A"!"(XO[__^L0,*#C5S#(Y2@P1>(8,(CE%#"(Y6P`F.4$$*#A!2"@X?[_ -M_^L&`*#A"!"@X9@[`^,/X*#A`_"6YP8`H.$'$*#A!2"@XR0PC>(B_?_K!`"@ -MX?H?H./^___K_O__ZP8`H.$*$@#C_O__ZP&`$.(8```:!U"@X0J@H.,*D@#C -M`5"%XG50[^8*`*#A_O__ZP8`H.$)$*#A_O__ZP&`$.(`,*`3`3"@`Q,`5>,` -M(*"#`2`#D@``4N/P__\:`;"+XGNP[^8$`%OC`#"@@P$P`Y(``%/C0O__&@!` -MH.$&`*#A"!"@XP`@H./^___K!@"@X0`0H.,0(*#C_O__ZQP0G>4``%'C"P`` -M"B!:`N,8,)WE!2#3YT`@@N,&`*#A(A0`XW(@[^;^___K&!"=Y04PT>=`,(/C -M!3#!YP``6.,$```*`2"$XP8`H.$*$@#C?^ -M(`+B`R#!YP8`H.$!$0#C_O__ZT30C>+PC[WH\$`MZ0S03>(!0*#A`E"@X3L\ -MH.,#<)#G#V+!XP8`H.'^___KU3+@YP`PC>6I#8?B$`"`XA\0!>(D+J#A!C"@ -MX?[__^L,T(WB\("]Z#!`+>D4T$WB`$"@X000C>4[/*#C`R"0YQHZ`N,#,-+G -M`0!3XP``H!,.```:#%"-X@4`H.$`$*#C`R"@X_[__^L%`*#A!!"-X@,@H./^ -M___K!`"@X4`0H.,#(*#C!3"@X:O\_^L!`*#C%-"-XC"`O>@$0"WE.SR@XP,P -MD.@``&CL\H.,#,)#G`A\"XP$0T.<`$%'B`1"@$P(`4N,$```*`P!2XRX` -M``H!`%+C;@``&EL``.H``%'C%```"CDLH.,"$)/GYB@#XP(0P^?\*`/C`B"3 -MY^<(`^,`(,/GZ`@#XP`0P^?I&`/C`2##Y^H8`^,!(,/GZQ@#XP$@P^?L&`/C -M`2##Y^T8`^,!(,/G5@``ZOPH`^,"()/GYA@#XP$@P^?G&`/C`2##YSD,6```*_"@#XP(@D^?F&`/C`2##YSD@>_R_A'O\OX1[_+^$>_R_A'O\OX?A/+>D`0*#A4GV`X@1PA^+$ -M-`'C`X"0YX`@H.,\-@'C`R"`YX@V`>,#4)#GV+"%XCRF`>,`D*#CE&8!XP<` -MH.$*$)3G"2"@X04PH.$X_R_A``!0XP@```H&,)3G`3!#X@8PA.<+`%7A`0`` -M&@$`H./XC[WH2%"%XN___^H``*#C^(^]Z![_+^$[/*#C`Q"0YP`@H.,:.@+C -M`R#!Y^,S`^,#,-#G`@!3X1DZ`@,#(,$'`#"@XWPG`^,",,'GL"`#XP(PP>>5 -M)0+C`C#!YPT@H.,N(,'EW2`#XP(PP><#`*#A`R"!X,,M@N(5((+B``#"Y0$P -M@^((`%/C^/__&A[_+^$!`*#C'O\OX1!`+>D`0*#AY0V@X_[__^L[/*#C`P"$ -MY^4MH.,$.P/C`R"$YP`@`.,(.P/C`"!`XP,@A.<`(`#C##L#XP`@0.,#((3G -M`"``XQ0[`^,`($#C`R"$YP`@`.,8.P/C`"!`XP,@A.<`(`#C'#L#XP`@0.,# -M((3G`"``XR`[`^,`($#C`R"$YP`@`.,D.P/C`"!`XP,@A.<`(`#C*#L#XP`@ -M0.,#((3G`"``XRP[`^,`($#C`R"$YP`@`.,P.P/C`"!`XP,@A.<`(`#C[3V@ -MXP`@0.,#((3G`"``XT0[`^,`($#C`R"$YP`@`.-(.P/C`"!`XP,@A.<`(`#C -M9#L#XP`@0.,#((3G`"``XV@[`^,`($#C`R"$YP`@`.-L.P/C`"!`XP,@A.<` -M(`#C<#L#XP`@0.,#((3G`"``XWP[`^,`($#C`R"$YP`@`./N/:#C`"!`XP,@ -MA.<`(`#CE#L#XP`@0.,#((3G`"``XY@[`^,`($#C`R"$YP`@`..0.P/C`"!` -MXP,@A.<[#(3B"`"`XO[__^L0@+WH$$`MZ3L\H.,#0)#G!P!1XP4```H-`%'C -M0```"@8`4>,``*`3$("]&#<``.H`,-+E``!3XP0``!H`(*#C<#H"XP,@A.@#`%/C!0``&G`Z`N,#()3G`2/" -MXP,@A.H./^___K8#X"XP,`Q.AP0"WI@M]-X@!`H.$(4(WB!1"@X?[__^L$`*#A!1"@ -MX?[__^L[/*#C`S"4YQ`D`^,"(-3G``!2XPD``!H(((WBL!W2X;04P^&R+=+A -MMB3#X5,(,/E,B#@XTT@P^4'``#J>"8%X[0DP^$T(@'CMB3#X50@X.-, -M(,/E,B#@XTT@P^40-`/C`R#4YP`0`.,`$$#C#3"@X0,`D>@$`(/DL!##X0`` -M4N,2```*`"#=Y1$T`^,#(,3G`2#=Y1(T`^,#(,3G`B#=Y1,T`^,#(,3G`R#= -MY10T`^,#(,3G!"#=Y14T`^,#(,3G!2#=Y18T`^,#(,3G!0``Z@T+A.(1`(#B -MX!"-X@$00>(&(*#C_O__ZPA@C>(05`/C!`"@X080H.$%(-3G_O__ZP0`H.$& -M$*#A!2#4Y_[__^L$`*#A!A"@X04@U.?^___K!`"@X080H.$%(-3G_O__ZP0` -MH.$&$*#A!2#4Y_[__^L$`*#A!A"@X04@U.?^___K!`"@X080H.$%(-3G_O__ -MZP0`H.$&$*#A!2#4Y_[__^L$`*#A_O__ZX+?C>)P@+WH$$`MZ0!`H.'^___K -MX#L#XP,`Q.?^___K.SR@XP,PE.<$(*#C0"##Y00`H.$*$*#C_O__ZU`BX.<: -M-`/C`R#$YR``(.+0`N#G$#0#XP,`Q.<$`*#A?___ZQ"`O>AP0"WI`$"@X3L\ -MH.,#4)#G51Z@XQ`@`>/^___K!`"@X14=H.,$)`;C_O__ZP0`H.%8%0#C!2"@ -MX_[__^L$`*#A614`XP(@H./^___K!`"@X5$>H.,/)@;C_O__ZP0`H.%5'J#C -M_O__ZQPZ`N,#`(7G!`"@X2(5`./^___K&SH"XP,`Q><$`*#A(A0`X_[__^L@ -M.@+C`P#%YP0`H.%"%0#C_O__ZR$Z`N,#`,7G!`"@X0$1`./^___K(CH"XP,` -MQ>=P@+WH<$`MZ0!`H.$[/*#C`U"0YP0PE>4!`%/C%0``&B!J`N,&(-7G0""" -MXR(4`.-R(._F_O__ZP8PU>=`,(/C!C#%YP0`H.%!%0#C_R"@X_[__^LA.@+C -M`R#5YP$@@N-R(._F`R#%YP0`H.%"%0#C_O__ZW"`O>@B%0#C_O__ZP`@H.$; -M.@+C`P#%YP0`H.$B%0#COR`"XO[__^MP@+WH<$`MZ0!0H.$!0*#A$1V@XW0@ -M[^;^___K!0"@X4$4`.-4).?G_O__ZP$`5.,`(*"3!0``F@`@H..D0*#A`2"" -MXG(@[^8!`%3C^O__B@4`H.$2':#C_O__ZW"`O>AP0"WI`$"@X3L\H.,#4)#G -M!#"5Y0$`4^,3```:(&H"XP8@U><$ -M`*#A014`XV0@H./^___K(3H"XP,@U>?^(`+B`R#%YP0`H.%"%0#C_O__ZW"` -MO>@B%0#C_O__ZP`@H.$;.@+C`P#%YP0`H.$B%0#C0"""X_[__^MP@+WH$$`M -MZ0!`H.$<$*#C`""@X_[__^L$`*#A!!"@XQ(H"./^___K$("]Z!!`+>D`0*#A -MX3,#XP,PT.<``%/C!```"EP0H./^___K@``0XPL```H,``#J0Q"@X_[__^OW -M(`#B!`"@X4,0H./^___K!`"@X4(0H./^___K"``0XP$```H``*#C$("]Z`(` -MH.,0@+WH<$`MZ0!`H.%4%0#CQCL`X[,@D.'^___K!`"@X5H5`.,"(*#C_O__ -MZP0`H.$[___K!`"@X1L5`.,)(*#C_O__ZP0`H.$$%@#C_O__ZP%0P.,$`*#A -M!!8`XP4@H.'^___K!`"@X006`.,!((7C_O__ZP0`H.%>%0#C4""@X_[__^L$ -M`*#A7Q4`XU`@H./^___K!`"@X54>H.,:(*#C_O__ZP0`H.$E%0#C;R"@X_[_ -M_^L$`*#A2O__ZP0`H.%5'J#C_O__ZP(@@.,$`*#A51Z@XW(@[^;^___K<("] -MZ'!`+>D`0*#A`E"@X3L\H.,#,)#G!A!!XC$`4>,!\9^77P``ZNBP`@#PL`(` -MH+$"`*"Q`@"@L0(`H+$"`*"Q`@"@L0(`H+$"`*"Q`@"@L0(`H+$"`*"Q`@`$ -ML0(`1+$"`#2Q`@"@L0(`H+$"`*"Q`@"@L0(`H+$"`*"Q`@"@L0(`H+$"`*"Q -M`@"@L0(`H+$"`*"Q`@"@L0(`H+$"`*"Q`@"@L0(`H+$"`*"Q`@!0L0(`H+$" -M`*"Q`@"@L0(`H+$"`*"Q`@"@L0(`H+$"`*"Q`@"@L0(`A+$"`*"Q`@"@L0(` -MH+$"`*"Q`@"4L0(`OC/3X;`PPN$$`*#A(A4`X_[__^L``,7E<("]Z((?H./^ -M___K`""@X0$($.-P@+T(!`"@X8(?H.,!*(+C_O__ZP$PH.,`,,7E<("]Z'`J -M`N,",)/G`##%Y7"`O>A!,-/E`##"Y7"`O>C8,P/C`S"0YP(`4^,!,*`#`##" -M!7"`O0@!'*#C_O__Z\``$.,!,*`3`#"@`P`PQ>5P@+WHV"@#XP(PT^<`,,7E -M<("]Z/(H`^.R()/AL"#%X7"`O>CP3RWI#-!-X@!`H.$!4*#A.SR@XP.`D.,P```:'@``ZC)] -M@.(,<(?B!P"@X?[__^L`D*#A!`"@X0<0H.$)(*#A_O__ZP\``.+^___K`*"@ -MX0<`H.$)$*#A_O__ZP!PH.'0.]3E``!3XP``H`,"```*OPZ$X@8`@.+^___K -M!W"`X00`H.&_'H3B!A"!XO[__^L`L%#B`;"@$R,``.K]#H#B!`"`XO[__^L` -M<*#AX3?4Y0$`$^,!`*`3`@"@`_[__^L`H*#A,@V$X@P`@.('$*#A_O__ZP!P -MH.$`L*#C$@``ZH%R@.#[?H?B!'"'X@<`H.'^___K`)"@X00`H.$'$*#A"2"@ -MX?[__^L/``#B_O__ZP"@H.$R#83B#`"`X@D0H.'^___K`'"@X0"PH.,'`*#A -M_O__ZS^0`.(:.@+C`S#8YP$`4^,$```:4'&&Y00`H.$'$*#A_O__ZP8``.H` -ML(WEJ0V(XA``@.)U$._F"B"@X0D(T$WB`#"@X0)`H.$[+*#C`B"0YPT`4>,!\9^7#0``ZK2S`@#&T@MWAN*+=X4,?H./^___K`U`%X@-`!.($1*#A!F.@X055A.'`8`;B`W`' -MX@90A>$#@`CB!W*%X0B&A^$*IXCA!P``X@"@BN$)`*#A0Q^@X_(`0*#A`F"@X3L\H.,#4)#GJ0V%XA``@.)! -M`%'C`?&?EUD#`.H(MP(`,+<"`%RW`@"TN`(`V+@"`&C#`@``N0(`G+D"`+"Y -M`@#PN0(`T+H"`!R[`@!@NP(`G+P"`&"]`@!TO0(`\+T"`%2^`@!TO@(`:,," -M`&C#`@"(O@(`F+X"`,"^`@`$OP(`'+\"`,R_`@#@OP(`:,,"``S``@`@P`(` -M-,`"`%3``@!HP`(`O,`"`!3!`@"PP0(`:,,"`-#!`@`0P@(`:,,"`&C#`@!H -MPP(`:,,"`&C#`@!HPP(`(,("`&C#`@!HPP(`:,,"`&C#`@!8P@(`8,("`&C# -M`@!HPP(`B,("`&C#`@!HPP(`F,("`&C#`@!HPP(`:,,"`&C#`@!,P@(`0,," -M`%S#`@`$`*#A`A$`X_[__^L,(`#B`##6Y00`H.$"$0#C`R""X?[__^L-`P#J -M!`"@X0(1`./^___K`##6Y0,@`.(#(8+A!`"@X0(1`.-R(._F_O__ZP(#`.H` -M4-+E``!5XP(`51,&```:!`"@X:']_^L$`*#A51Z@XQD@H./^___K00``Z@$` -M5>,&```:!`"@X5K]_^L$`*#A51Z@XQH@H./^___K.```Z@,`5>,V```:!`"@ -MX5']_^L$`*#A$A"@X^T@H./^___K!`"@X0@6`...(@+C`"!'X_[__^L$`*#A -MI!8`X_\O#^/^___K!`"@X:(6`.,!*Z#C_O__ZP0`H.%9%0#C`B"@X_[__^L$ -M`*#A6!4`XP4@H./^___K!`"@X5H5`.,*(*#C_O__ZP0`H.%1'J#C`""@X_[_ -M_^L$`*#A%1V@XP0D!N/^___K!`"@X5,5`.,!(*#C_O__ZP0`H.$8$*#C`""@ -MX_[__^L$`*#A4A4`X_[__^L(((#C!`"@X5(5`.-R(._F_O__ZP0`H.$"$0#C -M_O__ZPP@`.($`*#A`A$`XP4@@N'^___KK`(`Z@!0H.,$`*#A81Z%X@4@UN?^ -M___K`5"%X@8`5>/X__\:HP(`Z@!0H.,$`*#A81Z%X@@0@>(%(-;G_O__ZP%0 -MA>(&`%7C]___&ID"`.H0((WB`#"@X[(P8N$$`*#A!A"@X?[__^N^,-WA%3X# -MX@TP@^.^,,WAOC/%X;X@W>$!((+C$$`*#A$1V@XW(@[^;^___K -MOB#=X00`H.%!%`#C(B2@X?[__^N^,-WA`0!3XP`@H),&``":`""@XZ,PH.$! -M((+BH./^___K\R``X@0`H.%5'J#C_O__ZUT"`.H8-`'CTV"$X<8[`..S()3A -M`B6@X08`H.$'$*#APC^@X?[__^L`C`_C_X]/XP"0X.,(();@"3"GX`)@H.$# -M<*#A`&!6X`%PQ^`<.Y3E`S`#X@,`4^,!`%,3`0``&@0`H.'I_/_K!`"@X54> -MH./^___K]R``X@0`H.%5'J#C_O__ZP0`H.%6'J#C!B"@X?[__^L$`*#A9!4` -MXP<@H.'^___K!`"@X54>H./^___K"""`XP0`H.%5'J#CH./^___K$""`XP0`H.%5'J#CH./^___K[R``X@0`H.%5'J#C_O__ZP\``.H#`%/C&0``&@0`H.$(%@#C -M_O__ZP(K@.,$`*#A"!8`X_[__^L$`*#A51Z@X_[__^OO(`#B!`"@X54>H./^ -M___K'#N4Y0,P`^(#`%/C!P``&@0`H.$(%@#C_O__ZX`@@.,$`*#A"!8`X_[_ -M_^NZ`0#J!`"@X0@6`./^___KP""`XP0`H.$(%@#C_O__Z[(!`.H`,-+E``!3 -MXQ$``!H$`*#AI!8`X_\O#^/^___K!`"@X0@6`./^___KP""`XP0`H.$(%@#C -M_O__ZVPPE.4(`!/C%P``"K0RU>$2`%/C%@``&A,``.H!`%/C!0``&@0`H.&D -M%@#C`""@X_[__^LP(*#C#@``Z@(`4^,+```:!`"@X54>H./^___K[R``X@0` -MH.%5'J#C_O__ZVPPE.5@`!/C`0``"@<@H.,```#J,""@XP0`H.$J%`#C`B2" -MX?[__^N!`0#J!`"@X505`..P(-+A_O__ZWP!`.H$`*#A&Q4`XP`@TN7^___K -MS3O4Y0``4^-U`0`:X3?4Y0$`4^,*,*`#$#"@$\M;U.6%4(/@=5#OY@0`H.$% -M'*#C!2"@X?[__^L$`*#A!!4`XP4@H.'^___K!`"@X0@5`.,%(*#A_O__ZP0` -MH.$,%0#C!2"@X?[__^M=`0#J!`"@X145`.,`(-+E_O__ZP0`H.$7%0#C`2#6 -MY?[__^L$`*#A*10`XP`@UN7^___K!`"@X3L6`.,`(-;E_O__ZP0`H.$]%@#C -M`"#6Y?[__^L$`*#A/Q8`XP`@UN7^___K1`$`Z@`@TN4$`*#A0A0`XP``4N.` -M(*`3`""@`_[__^L\`0#J!`"@X1H=H.,`(-+E_O__ZS<8`0#J<#H"XP`0DN4#()7G`B`!X`,@A><2 -M`0#J`##2Y8.AH.$!<*#C`&"@XP:`H.%TE@#C9[Z@XP,P`^(0,(/C!#"-Y00` -M`.H`@*#C`6"&XG9@[^8!<(?B=W#OY@``5N,,```:!#"=Y0.`B.$*4(;@!`"@ -MX0D0H.$((*#A_O__ZP(AA>,$`*#A"Q"@X0$H@N/^___K[/__Z@I0AN`$`*#A -M"1"@X0`@H./^___K`B&%XP0`H.$+$*#A`2B"X_[__^L'`%?CW___FN8``.H$ -M`*#A9QZ@XP,AH./^___KX0``Z@0`H.%T%@#C`""2Y?[__^L$();E`B&"XP0` -MH.%G'J#C`2B"X_[__^O6``#J!`"@X04,$(((3^R`"`@(`%>,"(((3_2`"`@0` -MH.$7':#C_O__ZZH``.H`4-+E!P!5XZ<``(K,.`'C`S"4YP4`4^,'8*"#`"`` -MDP`@0),#,(*0"E00`H.%<%`#C_O__Z_@@`.($`*#A7!0`XP4`5N$&(((A -M!2"",?[__^N4``#J`#``XP`P0.,0,)/E"#"-Y0`PTN4#`%/CC0``B@(P@^(! -MD*#C&9.@X7F0[^8/`%GC#Y"@(PF`H.$)('H*#A!3#6Y_`@ -M`^('`%+A#S`#P@,PBL$%,,;'!3#6YP\@`^("`%CA\#`#L@,PB;$%,,:W!`"@ -MX44>A>(($('B!2#6Y_[__^L!4(7B!`!5X^O__QIM``#J`"#2Y0``4N,^.0,# -M`R#5!P0`H.$*':#C_O__ZV4``.H`8-+E``!6XP@```H`,)7E`3!#X@$`4^," -M``"*$#"5Y0(`4^,!```*`1"@X_[__^L$`*#A!A"@X?[__^M5``#J!`"@X0`0 -MTN7^___K40``Z@`0DN7_`%'C83X"`P,0U0=@/@(3`R#5%V$^`A,#(,47<1#O -M%O[__^M&``#JL!#2X?[__^M#``#J_O__ZT$``.H`0-+EV#@#XP,PU><$`%/A -M/```"@00H.'^___KV#@#XP-`Q>,S`^,#,-3G`0!3XR8` -M``H$`*#AAQ(`X_[__^L!)X#C!`"@X8<2`./^___K9%"@XX=B`.,$`*#A!A"@ -MX?[__^L""!#C`P``"@``5>,!4$42=5#O%O;__QH$`*#AA1^@XP`@H./^___K -M!`"@X0(T4`.-R -M(._F_O__ZP(``.H$`*#AL!#2X?[__^L4T(WB\(^]Z!!`+>G^___K`0"@XQ"` -MO>@00"WI"-!-X@!`H.'L%`#C_O__Z_T@`.($`*#A[!0`X_[__^L$`*#A`1R@ -MXP`@H./^___K`#``XP`P0.,`,(WE!`"@X?\0H.,/(*#C`C"@X_[__^L$`*#A -M@!"@X_[__^N``!#C"@``"K`\`^,#,-3G``!3XP8```H$`*#A`Q"@X_[__^O[ -M(`#B!`"@X0,0H./^___K!`"@X8`0H.,`(*#C_O__ZP0`H.%E'Z#C_O__Z_X@ -M`.($`*#A91^@X_[__^L`,`#C`#!`XP`PC>4$`*#A_Q"@XP\@H.,",*#C_O__ -MZP0`H.$=$*#C_O__Z_<@`.($`*#A'1"@X_[__^L$`*#A'1"@X_[__^L(((#C -M!`"@X1T0H.-R(._F_O__ZP0`H.%$$*#C_O__ZP`@H.$$`*#A11"@X_[__^L$ -M`*#A1A"@X_\@H./^___K!`"@X4(0H./^___K`"*`X00`H.%"$*#C(0@+WH$$`M -MZ0!`H.'C,P/C`S#0YP``4^,)```*XC,#XP,PT.<``%/C%```"N$S`^,#,-#G -M``!3XQ````I0^O_K#@``ZN$[`^,#,-#G`0!3XPH``!K^___KXC,#XP,PU.<` -M`%/C!0``"N$S`^,#,-3G``!3XP$```H$`*#A0/K_ZP$`H.,0@+WH\$`MZ0S0 -M3>(`0*#A`F"@X3L\H.,#4)#G``!1XP(```H"`%'CA`$`BJ```.H!`%+C00`` -M&A$0H./^___K"2"`XP0`H.$1$*#C<>H.,`(.#CH#4"X]LS -M1N/^___K!P``Z@,`4^,%```:!`"@X><>H.,`(.#CH#4"XQLS1N/^___KE3T" -MXP,P0.,`,(WE!`"@X0`0H.,!(*#A_S\/XP\P0./^___K03#5Y0(`4^-)`0`: -ME3T"XP,P0.,`,(WE!`"@X0$0H.,`(*#C_S\/XP\P0./^___K/P$`ZB@0H..! -M(*#C_O__ZP0`H.$D$*#C#R`(X_[__^L!`*#C_O__ZP0`H.$1$*#C_O__ZPD@ -M@.,$`*#A$1"@XW(@[^;^___K03#5Y0(`4^,$`*#A>!@`XS@@``,X($`#.""@ -M$P$PH./^___K!`"@X00<`./P(*#C`3"@X_[__^L$`*#A`AN@XP(@H.,`,*#C -M_O__ZT$PU>4"`%/C!@``&@0`H.'G'J#C`"#@XZ`U`N/;,T;C_O__ZP<``.H# -M`%/C!0``&@0`H.'G'J#C`"#@XZ`U`N,;,T;C_O__ZY4]`N,#,$#C`#"-Y00` -MH.$`$*#C`2"@X?\_#^,/,$#C_O__ZT$PU>4"`%/C"```&I4]`N,#,$#C`#"- -MY00`H.$!$*#C`""@X_\_#^,/,$#C_O__ZP0`H.$&'*#C_O__Z[\@`.($`*#A -M!AR@X_[__^L*`*#C_O__ZP0`H.$"$*#C%R"@X_[__^L$`*#A(A4`XP`@H./^ -M___KX@``ZA$0H./^___K`#"5Y0$P0^(!`%/C!@``B@PPE>4!`%/C`P``&@@P -ME>4!`%/C_G```@````KV<`#B`0!6XUH``!H$`*#A>!@`XP`@X./^___KZ#,# -MXP,`A.<$`*#A!!P`XP`@X./^___K[#,#XP,`A.<$`*#A`AN@XP`@X./^___K -M\#,#XP,`A.=!,-7E`@!3XP8``!H$`*#A>!@`XS@@`.,X($#C`#"@X_[__^L& -M``#J`P!3XP0``!H$`*#A>!@`XS@@H.,`,*#C_O__ZP0`H.$$'`#C\""@XP`P -MH./^___K!`"@X0(;H.,"(*#C`3"@X_[__^L$`*#AYQZ@XP`@X./^___K]#,# -MXP,`A.=!,-7E`@!3XP8``!H$`*#AYQZ@XP`@X..@-0+CVS!`X_[__^L'``#J -M`P!3XP4``!H$`*#AYQZ@XP`@X..@-0+C&S!`X_[__^L`(*#C`""-Y00`H.$" -M$*#A_S\/XP\P0./^___K03#5Y0(`4^,&```:`""@XP`@C>4$`*#A`1"@X_\_ -M#^,/,$#C_O__ZP0`H.$1$*#C!R"@X?[__^MW``#J!`"@X2(5`./_(*#C_O__ -MZP`@H.,`((WE!`"@X0(0H.'_,*#C_O__ZP0`H.$&'*#C0""@X_[__^L*`*#C -M_O__ZP0`H.$"$*#C%B"@X_[__^L$`*#A>!@`XP`@X./^___KZ#,#XP,`A.<$ -M`*#A!!P`XP`@X./^___K[#,#XP,`A.<$`*#A`AN@XP`@X./^___K\#,#XP,` -MA.=!,-7E`@!3XP8``!H$`*#A>!@`XS@@`.,X($#C`#"@X_[__^L&``#J`P!3 -MXP0``!H$`*#A>!@`XS@@H.,`,*#C_O__ZP0`H.$$'`#C\""@XP`PH./^___K -M!`"@X0(;H.,"(*#C`3"@X_[__^L$`*#AYQZ@XP`@X./^___K]#,#XP,`A.=! -M,-7E`@!3XP8``!H$`*#AYQZ@XP`@X..@-0+CVS!`X_[__^L'``#J`P!3XP4` -M`!H$`*#AYQZ@XP`@X..@-0+C&S!`X_[__^L`(*#C`""-Y00`H.$"$*#A_S\/ -MXP\P0./^___K03#5Y0(`4^,&```:`""@XP`@C>4$`*#A`1"@X_\_#^,/,$#C -M_O__ZP0`H.$1$*#C!R"@X?[__^L$`*#A*!"@XX`@H./^___K`0"@X_[__^L$ -M`*#A)!"@XP\H"N/^___K#-"-XO"`O>CP12WI%-!-X@!`H.$[/*#C`V"0Y_[_ -M_^OC,P/C`S#4YP``4^,4```*?#<#XP,PUN<``%/C`P``"@0`H.$!$*#C_O__ -MZP4``.H$`*#A`!"@X_[__^L!(*#C?#<#XP,@QN>I#8;B$`"`XO[__^L$`*#A -M_O__ZP%0H.-8`@#J`#``XP`P0.,`,(WE!`"@X?\0H.,/(*#C`C"@X_[__^L` -M`%#C`%"@`TT"``H$`*#A`1R@XP`@H./^___K!`"@X0$P4`./^___K`R"`XP0`H.'L%`#CH./P+0SC_O__ZP0`H.%-'J#C`""@X_[_ -M_^L$`*#A_O__ZP!0H.$!`%#C!0``"@`PH..P+`/C`C#$YQHJ`N,",,;G#`(` -MZ@$@H..P/`/C`R#$YP`@H.,:.@+C`R#&YP0`H.'^___K-C,#XP,PU.?E8,P@I"T,=.1`#"-Y00PC>4(,(WE!`"@X0,0H.$#(*#AFOG_ -MZR,``.KD.`/C`S#2YP,P0^)S,._F`P!3XP`0H(,!,*"!Q":?E8,@@I"\,=*1 -MM!+2D0(O`N,"(-3G``!2XP$`H!$#(*`1`P"@`0$@H`$)`(WH"#"-Y00`H.&# -M^?_K#```Z@(_`N,#(-3G`S"@XP`PC>4$,(WE"#"-Y00`H.$!$*#C``!2XP$@ -MH`$"(*`3`C"@XW7Y_^L$`*#A%A$`X_\C`N/^___K!`"@X4$?H.,1(*#C_O__ -MZP0`H.$/%@#C!""@X_[__^L$`*#A21^@XP`@X./^___K!`"@X1(>H.,`(.#C -M_O__ZV%>H.,6=@#C!3"$X"X\@^(!,(/B!`"@X040H.$`(-/E_O__ZP%0A>(' -M`%7A]?__&@0`H.$!'*#C_O__ZP,HP.,$`*#A`1R@XP(H@N/^___K.UR@XP4P -ME.?/(`;C`"!'XS`@@^4$`*#A"!8`X_[__^L$`*#A8AZ@XP`@X./^___K!`"@ -MX206`.,`(.#C_O__ZP0`H.$1':#C_O__ZR`JH.'Q/P_C#S!`XP0`H.$1':#C -M`BJ#X?[__^L$`*#A*!0`XQ`@`>/^___K!`"@X2H4`.,P(`/C_O__ZP0`H.$H -M%`#C"B`!X_[__^L$`*#A.A8`XPH@`>/^___K!`"@X105`.,*(`'C_O__ZP0` -MH.$6%0#C"B`!X_[__^L$`*#A"!4`XRLD"N->($#C_O__ZP0`H.$,%0#C3R0* -MX_[__^L$`*#A!!4`XR0C"N->($#C_O__ZP0`H.$%'*#C)B(*XR\@0./^___K -M!`"@X4(>H./^___K@"S@X:(LX.$$`*#A0AZ@XW(@[^;^___K!`"@X1D=H.-` -M(*#C_O__ZP6`E.<"/P+C`S#4YP``4^,`(*`3,#D#$P,@R!#^,] -M.0/C`R#7Y_[__^L4``#J!`"@X0H=H.,^.0/C`R#7Y_[__^L_.0/C`R#7YP0` -MH.&!$@#C'R`"XO[__^L$`*#A71X/XSPY`^,#(-?G_O__ZP0`H.%<'@_C/3D# -MXP,@U^?^___K,CD#XX`@H..S((?A`""@X^\X`^,#(,CG!`"@X3SV_^L$`*#A -M`1R@X_[__^L`+>#A(BW@X00`H.$!'*#C!@`XP(JH.,!,*#C_O__ZP0`H.&&'J#C`RR@X_[__^L"`%#C`B"@ -M`P$@H!/8.`/C`R#'YP0`H.',%`#C_R\/XP$B0./^___K!`"@X2,4`./_(*#C -M_O__ZP(_`N,#,-3G``!3XP,```H$`*#A1AZ@XP`@H./^___K!`"@X5(6`.,` -M(*#C_O__ZP0`H.'^___KV',#XP`PH.,',(3G!`"@X2$4`.,/(*#C_O__ZP0` -MH.'3%`#C`2"@X_[__^L$`*#A3QZ@X_`M`^/^___K!S"4YP``4^,2```:?#<# -MXP,PUN<``%/C`P``"@0`H.$!$*#C_O__ZP4``.H$`*#A`!"@X_[__^L!(*#C -M?#<#XP,@QN>I#8;B$`"`XO[__^L$`*#A_O__ZP0`H.%8'@_C`""@X_[__^MA -M;J#C%G8`XP0`H.$&$*#A_O__ZP%@AN('`%;A^?__&@4`H.$4T(WB\(6]Z`0@ -MH.-`(,/E`R"@XT$@P^4#_O_J[!,```(PH.,(,(#E`#"@XPPPP.4.,,#E#S#` -MY1`PP.41,,#E$C#`Y1,PP.44,(#E&#"`Y1[_+^$00"WI`$"@X1P`@.+^___K -M!`"@X>S__^L0@+WH$$`MZ0!`H.$V#(#B'`"`XO/__^O9#83B/`"`XO#__^L0 -M@+WH$$`MZ0%`H.$%`('H`0"@X=W__^L`,`#C`#!`XRPPA.4P0(3E'`"$X@`0 -MH.,!(*#A_O__ZP(\H.-0,(3E5#"$XE0PA.58,(3E`#``XP`P0.-<,(3E$("] -MZ!!`+>D`0*#A`"``X^0V`^,`($#C`R"`YS8<@.(<$('B`2"@X]___^L$`*#A -MV1V$XCP0@>("(*#CVO__ZQ"`O>@00"WI`#"0Y=`K`^,"()/G`0!2XQ"`O0C, -M*P/C`C"3YP$`4^,0@+T(4`"`XO[__^L0@+WH<$`MZ0!`H.$!4*#A.SR@XP,@ -MD.?0.P/C`S"0YP$`4^,C```*S#L#XP,PD.4!`%/C`@`` -M"@(`4^,:```:$@``ZMDX`^,#,-+G``!3XP8```I.$*#C_O__ZP0`H.%.$*#C -MZ""@X_[__^L.``#J3!"@X_[__^MP(`#B!`"@X4P0H.,(((+C_O__ZP8``.I- -M$*#C_O__ZW`@`.($`*#A31"@XP@@@N/^___K`#"@XPPPQ>5P@+WH<$`MZ0!0 -MH.$[/*#C`S"0YTPPT^4&`%/C-DR`$AQ`A!+938`"/$"$`@$00>(&`%'C`?&? -MEU8``.HPV`(`,-@"`##8`@#+^___K<("]Z`XPU.4``%/C<("]&`@PE.4&`%/C -M<("]"`$PH.,.,,3E"C"@XP@PA.4",*#C%#"$Y0PPU.4``%/C`C"@$P$PH`,8 -M,(3E`#``XP`P0.,`$)/E'`"$X@40@>+^___K<("]Z`(PH.,(,(3E&#"$Y0XP -MU.4``%/C`P``"AP`A.+^___K`#"@XPXPQ.4%`*#A!!"@X6K__^MP@+WH<$`M -MZ0!`H.'0.P/C`S"0YP$`4^-P@+T(S#L#XP,PD.4!`%/C`P`` -M&AP`A>+^___K`#"@XPXPQ>4!,*#C#S#%Y0,P@^((,(7E###5Y0``4^,",*`3 -M`3"@`Q@PA>5H/9_E`!"3Y1P`A>)D$('B_O__ZW"`O>@0,-7E``!3XW"`O1@( -M,)7E!@!3XW"`O0@+`%/C"0!3$W"`O0@3,-7E``!3XW"`O1@/,-7E`0!3XP,` -M`!H<`(7B_O__ZP`PH.,/,,7E#C#5Y0$`4^,#```:'`"%XO[__^L`,*#C#C#% -MY0$PH.,0,,7E`C"#X@@PA>4,,-7E``!3XP(PH!,!,*`#&#"%Y<0\G^4`$)/E -M'`"%XC(0@>+^___K<("]Z!@UU.4``%/C`@``"FPPE.4!`!/C<("]&!(PU>4` -M`%/C<("]&`@PE>4+`%/C"0!3$W"`O0@3,-7E``!3XW"`O1@/,-7E`0!3XP,` -M`!H<`(7B_O__ZP`PH.,/,,7E$##5Y0$`4^,#```:'`"%XO[__^L`,*#C$##% -MY0XPU>4!`%/C`P``&AP`A>+^___K`#"@XPXPQ>4!,*#C$C#%Y04P@^((,(7E -M$C"#XA0PA>4,,-7E``!3XP(PH!,!,*`#&#"%Y>P[G^4`$)/E'`"%XA(0@>+^ -M___K<("]Z`XPU>4``%/C<("]&`@PE>4&`%/C<("]"`L`4^,)`%,3<("]"!,P -MU>4``%/C<("]&`\PU>4!`%/C`P``&AP`A>+^___K`#"@XP\PQ>40,-7E`0!3 -MXP,``!H<`(7B_O__ZP`PH.,0,,7E`3"@XPXPQ>4),(/B"#"%Y0(PH.,4,(7E -M###5Y0``4^,",*`3`3"@`Q@PA>5`.Y_E`!"3Y1P`A>(%$('B_O__ZW"`O>@3 -M,-7E``!3XW"`O1@/,-7E`0!3XP,``!H<`(7B_O__ZP`PH.,/,,7E$##5Y0$` -M4^,#```:'`"%XO[__^L`,*#C$##%Y0XPU>4!`%/C`P``&AP`A>+^___K`#"@ -MXPXPQ>42,-7E`0!3XP,``!H<`(7B_O__ZP`PH.,2,,7E`3"@XQ,PQ>4),*#C -M"#"%Y0PPU>4``%/C`C"@$P$PH`,8,(7E`#``XP`P0.,`$)/E'`"%XA(0@>+^ -M___K<("]Z`\PU>4!`%/C`P``&AP`A>+^___K`#"@XP\PQ>40,-7E`0!3XP,` -M`!H<`(7B_O__ZP`PH.,0,,7E#C#5Y0$`4^,#```:'`"%XO[__^L`,*#C#C#% -MY1(PU>4!`%/C`P``&AP`A>+^___K`#"@XQ(PQ>43,-7E``!3XP$PH`,3,,4% -M`0``"AP`A>+^___K"S"@XP@PA>4,,-7E``!3XP@```H",*#C&#"%Y0`P`.,` -M,$#C`!"3Y1P`A>)]'X'B_O__ZW"`O>@!,*#C&#"%Y0`P`.,`,$#C`!"3Y1P` -MA>+^___K<("]Z!,PU>4``%/C`P``"AP`A>+^___K`#"@XQ,PQ>4!,*#C#S#% -MY00PH.,(,(7E###5Y0``4^,",*`3`3"@`Q@PA>4`,`#C`#!`XP`0D^4<`(7B -M9!"!XO[__^MP@+WH`C"@XP@PA>48,(7E#S#5Y0``4^,#```*'`"%XO[__^L` -M,*#C#S#%Y1`PU>4``%/C`P``"AP`A>+^___K`#"@XQ`PQ>4.,-7E``!3XP,` -M``H<`(7B_O__ZP`PH.,.,,7E$S#5Y0``4^,#```*'`"%XO[__^L`,*#C$S#% -MY1(PU>4``%/C`P``"AP`A>+^___K`#"@XQ(PQ>4$`*#A!1"@X8-Y_E`!"3Y38,A.(X`(#B$A"!XO[__^MP@+WH*C8#XP,P -MU.<``%/C<("]&&PPE.4!`!/C<("]""0V`^,#,)3G!@!3XW"`O0@+`%/C"0!3 -M$W"`O0@O-@/C`S#4YP``4^-P@+T8`2"@XRHV`^,#(,3G"2""X@8P0^(#((3G -M`B"@XPPP@^(#((3G"#!#X@,PU.<``%/C`2"@`S0V`^,#((3G^#:?Y0`0D^4V -M#(3B.`"`X@40@>+^___K<("]Z`$PH.,D)@/C`C"$YS0F`^,",(3G*C8#XP,P -MU.<``%/C!0``"C8,A.(X`(#B_O__ZP`@H.,J-@/C`R#$YRXV`^,#,-3G``!3 -MXP4```HV#(3B.`"`XO[__^L`(*#C+C8#XP,@Q.<`,`#C`#!`XP`0D^4V#(3B -M.`"`XO[__^MP@+WH+S8#XP,PU.<``%/C<("]&"HV`^,#,-3G`0!3XP4``!HV -M#(3B.`"`XO[__^L`(*#C*C8#XP,@Q.@`$*#C+R8#XP(0Q.?8(P/C -M`B"4YP$`4N$#```*!`"@X0,0H.$._?_K<("]Z`$PH.,D)@/C`C"$YS0F`^," -M,(3G`#``XP`P0.,`$)/E-@R$XC@`@.+^___K<("]Z``0H.,O)@/C`A#$Y]@C -M`^,"()3G`0!2X0,```H$`*#A`Q"@X??\_^MP@+WH`C"@XR0F`^,",(3G-"8# -MXP(PA.<`,`#C`#!`XP`0D^4V#(3B.`"`XO[__^MP@+WH+C8#X[,PE.$``%/C -M<("]&`(P@^(D)@/C`C"$YQ`@@N(",(3GZ#2?Y0`0D^4V#(3B.`"`XO[__^MP -M@+WH`C"@XR0F`^,",(3G-"8#XP(PA.,! -M\9^7L0,`ZO3E`@!(Z`(`5.4"`%3E`@"0Y`(`B.@"`$CH`@"8Y@(`3.<"`)CF -M`@#PYP(`JY0``4^-P@+T8+C8#XP,PU.<``%/C<("]&"0V`^,#,)3G"P!3 -MXPD`4Q-P@+T(+S8#XP,PU.<``%/C<("]&"HV`^,#,-3G`0!3XP4``!HV#(3B -M.`"`XO[__^L`(*#C*C8#XP,@Q.+^___K<("]Z"HV`^,#,-3G``!3XW"`O1AL,)3E`0`3 -MXW"`O0@D-@/C`S"4YP8`4^-P@+T("P!3XPD`4Q-P@+T(+S8#XP,PU.<``%/C -M<("]&`$@H.,J-@/C`R#$YPD@@N(&,$/B`R"$YP(@H.,,,(/B`R"$YP@P0^(# -M,-3G``!3XP$@H`,T-@/C`R"$YZ0RG^4`$)/E-@R$XC@`@.(%$('B_O__ZW"` -MO>@D-@/C`S"4YPL`4^,)`%,3<("]""\V`^,#,-3G``!3XW"`O1@!,*#C)"8# -MXP(PA.+^___K<("]Z"\V`^,#,-3G``!3XP$@ -MH`,O-@,#`R#$!P4```HV#(3B.`"`XO[__^L`(*#C+S8#XP,@Q.<+(*#C)#8# -MXP,@A.@!(*#C-#8#XP,@A.<`,`#C`#!`XP`0D^4V -M#(3B.`"`XO[__^MP@+WH+S8#XP,PU.<``%/C!0``"C8,A.(X`(#B_O__ZP`@ -MH.,O-@/C`R#$YP(PH.,D)@/C`C"$YS0F`^,",(3G`#``XP`P0.,`$)/E-@R$ -MXC@`@.+^___K<("]Z"XV`^.S,)3A``!3XW"`O1@",(/B)"8#XP(PA.<0((+B -M`C"$YQ`PG^4`$)/E-@R$XC@`@.+^___K<("]Z``````",*#C)"8#XP(PA.@",$'B"P!3XP/QGY=Z`@#JU.H"`-3J`@#H -M[`(`Z.P"`/#K`@!<\0(`<.D"`*3M`@`$[P(`I.T"`(#O`@!H\`(`CS8#XP,P -MU.<``%/C$P``"@`@H../-@/C`R#$Y]H-A.(8`(#B_O__ZP(PH..4)@/C`C"$ -MYQ`@0N(",(3GB#8#XP,PU.<``%/C!```"D`Q'^4`$)/E-@R$XC@`@.+^___K -M+38#XP,PU.<``%/C<("]&"0V`^,#,)3G!@!3XW"`O0@+`%/C"0!3$W"`O0@O -M-@/C`S#4YP``4^-P@+T8*C8#XP,PU.+^___K<("]Z`$@H.,T -M-@/C`R"$YSPR'^4`$)/E-@R$XC@`@.(*$('B_O__ZW"`O>@"`%'C%P``&H\V -M`^,#,-3G``!3XQ,```H`(*#CCS8#XP,@Q.?:#83B&`"`XO[__^L",*#CE"8# -MXP(PA.<0($+B`C"$YX@V`^,#,-3G``!3XP0```JL,A_E`!"3Y38,A.(X`(#B -M_O__ZRLV`^,#,-3G``!3XW"`O1@D-@/C`S"4YP8`4^-P@+T("P!3XPD`4Q-P -M@+T(+S8#XP,PU.<``%/C<("]&"HV`^,#,-3G`0!3XP4``!HV#(3B.`"`XO[_ -M_^L`(*#C*C8#XP,@Q.+^___K -M<("]Z!@UU.4``%/C`@``"FPPE.4!`!/C<("]&"XV`^,#,-3G``!3XW"`O1@D -M-@/C`S"4YPL`4^,)`%,3<("]""\V`^,#,-3G``!3XW"`O1@K-@/C`S#4YP$` -M4^,%```:-@R$XC@`@.+^___K`""@XRLV`^,#(,3G*C8#XP,PU.B/-@/C`S#4YP`` -M4^,3```*`""@XX\V`^,#(,3GV@V$XA@`@.+^___K`C"@XY0F`^,",(3G$"!" -MX@(PA.>(-@/C`S#4YP``4^,$```*=#4?Y0`0D^4V#(3B.`"`XO[__^LO-@/C -M`S#4YP``4^-P@+T8*S8#XP,PU.@!(*#C-#8#XP,@A.=L -M-A_E`!"3Y38,A.(X`(#B"A"!XO[__^MP@+WH+S8#XP,PU.<``%/C!0``"C8, -MA.(X`(#B_O__ZP`@H.,O-@/C`R#$YP$@H.,K-@/C`R#$YP0@H.,D-@/C`R"$ -MYR@V`^,#,-3G``!3XP(@H!,!(*`#-#8#XP,@A.<`,`#C`#!`XP`0D^4V#(3B -M.`"`XF00@>+^___K<("]Z"\V`^,#,-3G``!3XP4```HV#(3B.`"`XO[__^L` -M(*#C+S8#XP,@Q.(`,`#C`#!`XP`0D^4%`*#A9!"! -MXO[__^N/-@/C`S#4YP``4^,!(*`#CS8#`P,@Q`<"```*V@V$XA@`@.+^___K -M"R"@XX0V`^,#((3GB#8#XP,PU.<``%/C`B"@$P$@H`.4-@/C`R"$YP`P`.,` -M,$#C`!"3Y04`H.$*$('B_O__ZW"`O>@O-@/C`S#4YP``4^,%```*-@R$XC@` -M@.+^___K`""@XR\V`^,#(,3G`2"@XRLV`^,#(,3G!""@XR0V`^,#((3G*#8# -MXP,PU.<``%/C`B"@$P$@H`,T-@/C`R"$YS9+^___KCS8#XP,PU.<``%/C`2"@`X\V`P,#(,0'`@``"MH-A.(8 -M`(#B_O__ZPP@H..$-@/C`R"$YPH@H..0-@/C`R"$YX@V`^,#,-3G``!3XP(@ -MH!,!(*`#E#8#XP,@A.<`,`#C`#!`XP`0D^4%`*#A"A"!XO[__^MP@+WH`C"@ -MXR0F`^,",(3G-"8#XP(PA./-@/C`S#4YP``4^,% -M```*V@V$XA@`@.+^___K`""@XX\V`^,#(,3G`""@XY0V`^,#((3G!`"@X38< -MA.(<$('B'?G_ZP0`H.'9'83B/!"!XAGY_^MP@+WH!`"@X4;Y_^MP@+WH`0!1 -MXW"`O3@#`%'C`@``F@<`4>-P@+T8#@``ZC94!`%/C`@``"@(`4^,8```:$0`` -MZMDX`^,#,-+G``!3XP8```I.$*#C_O__ZP0`H.%.$*#CX""@X_[__^L,``#J -M3!"@X_[__^MP(`#B!`"@X4P0H./^___K!0``ZDT0H./^___K<"``X@0`H.%- -M$*#C_O__ZP$PH.,,,,7E<("]Z/!!+>D`0*#A`%"0Y=`[`^,#,)7G`0!3X_"! -MO0C,.P/C`S"5YP$`4^/P@;T(W#8#XP,PE><&`%/C`_&?ER,$`.I$]`(`W/4" -M`/CY`@#H^P(`S/X"`"@"`P!8!`,`&#"0Y0$`4^,#```:!0"@X000H.&T___K -M`@``Z@4`H.$$$*#AJ_C_ZQ0@E.4!($+B%""$Y0@PE.4(`%/C!P``"@D`4^,1 -M```*`P!3XP$PH!,0```:`3!RX@`PH#,-``#J;#"5Y0$`$^,`,*`#!```"B`` -M$^,,```:0``3XPH``!K3,>#G``!2XP0```H!``#J`3!RX@`PH#,``%/C$``` -M"FPPE>4!`!/C"0``"@PPU.4``%/CX0,`&@4`H.$$$*#AB?__ZP(``.H%`*#A -M!!"@X8#X_^L`,*#C%#"$Y0XPQ.7P@;WH&#"4Y0$`4^,",*`#`3"@$Q@PA.4( -M,)3E`S!#X@8`4^,#\9^7&P``ZFSU`@"(]0(`P/4"`,#U`@#`]0(`B/4"`*3U -M`@``,`#C`#!`XP`0D^4<`(3B"A"!XO[__^OP@;WH`#``XP`P0.,`$)/E'`"$ -MXA00@>+^___K\(&]Z``P`.,`,$#C`!"3Y1P`A.(H$('B_O__Z_"!O>@`,`#C -M`#!`XP`0D^4<`(3B%!"!XO[__^OP@;WH.SR@XP-PE>?9;87B/&"&XDPPU^4& -M`%/C!D"@`1@PE.4!`%/C`P``&@4`H.$$$*#A1___ZP(``.H%`*#A!!"@X3[X -M_^M,,-?E``!3XR<``!IL,)7E`0`3XQ(```J)-@/C`S#5YP``4^,&```:!0"@ -MX080H.$V___K`2"@XXDV`^,#(,7G&0``ZH@V`^,#,-7G``!3XQ4``!H%`*#A -M!A"@X2O__^L1``#JB38#XP,PU><``%/C!@``&@4`H.$&$*#A'OC_ZP$@H..) -M-@/C`R#%YP8``.J(-@/C`S#5YP``4^,"```*!0"@X080H.$3^/_KV#,#XP,P -ME><``%/C!0``"@4`H.$$$*#A#/C_ZP0`H.&Z]__K\(&]Z`@PE.4#,$/B"`!3 -MXP/QGY=K`P#J7/<"`"SW`@"X!`,`C/<"`+@$`P"X!`,`4/D"`&SX`@"`^0(` -M###4Y0``4^,",*`3`3"@`Q@PA.4`,`#C`#!`XP`0D^4<`(3B9!"!XO[__^OP -M@;WH###4Y0``4^,",*`3`3"@`Q@PA.4`,`#C`#!`XP`0D^4<`(3B,A"!XO[_ -M_^OP@;WH%#"4Y0$P0^(4,(3E``!3XR8``!IL,)7E`3`#X@$`4^,.```:$##$ -MY0,PH.,(,(3E###4Y0``4^,",*`3`3"@`Q@PA.4`,`#C`#!`XP`0D^4<`(3B -M,A"!XO[__^L0``#J``!3XPX``!H!,*#C#S#$Y00PH.,(,(3E###4Y0``4^," -M,*`3`3"@`Q@PA.4`,`#C`#!`XP`0D^4<`(3B9!"!XO[__^L`,*#C$C#$Y?"! -MO>@,,-3E``!3XP(PH!,!,*`#&#"$Y0`P`.,`,$#C`!"3Y1P`A.(2$('B_O__ -MZ_"!O>@4,)3E`3!#XA0PA.4``%/C)P``&FPPE>4!,`/B`0!3XPX``!H0,,3E -M`S"@XP@PA.4,,-3E``!3XP(PH!,!,*`#&#"$Y0`P`.,`,$#C`!"3Y1P`A.(R -M$('B_O__ZQ```.H``%/C#@``&@$PH.,/,,3E!#"@XP@PA.4,,-3E``!3XP(P -MH!,!,*`#&#"$Y0`P`.,`,$#C`!"3Y1P`A.)D$('B_O__ZP`PH.,4,(3E#C#$ -MY?"!O>@,,-3E``!3XP(PH!,!,*`#&#"$Y0`P`.,`,$#C`!"3Y1P`A.(%$('B -M_O__Z_"!O>@,,-3E``!3XP(PH!,!,*`#&#"$Y0`P`.,`,$#C`!"3Y1P`A.(2 -M$('B_O__Z_"!O>@8,)3E`0!3XQ$```H!,*#C$##$Y0,PH.,(,(3E###4Y0`` -M4^,",*`3`3"@`Q@PA.4`,`#C`#!`XP`0D^4<`(3B,A"!XO[__^L`,*#C$S#$ -MY?"!O>@",*#C&#"$Y0`P`.,`,$#C`!"3Y1P`A.)]'X'B_O__Z_"!O>@8,)#E -M`0!3XP,``!H%`*#A!!"@X4?^_^L"``#J!0"@X000H.$^]__K"#"4Y08`4^," -M```*"@!3X_"!O1@U``#J%#"4Y0$P0^(4,(3E``!3XQP``!K8,P/C`S"5YP`` -M4^,#```*!0"@X000H.$L]__K$0``ZFPPE>4!,`/B`0!3XP4``!H(,(3E&#"$ -MY04`H.$$$*#A)_[_ZP<``.H``%/C!0``&@(PH.,(,(3E&#"$Y04`H.$$$*#A -M&??_ZP`PH.,2,,3E\(&]Z-@S`^,#,)7G``!3XP,```H%`*#A!!"@X0_W_^OP -M@;WH###4Y0``4^,",*`3`3"@`Q@PA.4`,`#C`#!`XP`0D^4<`(3B$A"!XO[_ -M_^OP@;WH%#"4Y0$P0^(4,(3E``!3XQP``!K8,P/C`S"5YP``4^,#```*!0"@ -MX000H.'V]O_K$0``ZFPPE>4!,`/B`0!3XP4``!H(,(3E&#"$Y04`H.$$$*#A -M\?W_ZP<``.H``%/C!0``&@(PH.,(,(3E&#"$Y04`H.$$$*#AX_;_ZP`PH.,. -M,,3E\(&]Z-@S`^,#,)7G``!3XP,```H%`*#A!!"@X=GV_^OP@;WH###4Y0`` -M4^,",*`3`3"@`Q@PA.4`,`#C`#!`XP`0D^4<`(3B!1"!XO[__^OP@;WH&#"0 -MY0$`4^,#```:!0"@X000H.'+_?_K!0``Z@@PD.4+`%/CG0``"@4`H.$$$*#A -MO_;_ZP@PE.4&,$/B!0!3XP/QGY4!,`/B`0!3XP@``!H(,(3E&#"$Y0PPU.4``%/C#@`` -M&@4`H.$$$*#AH/W_ZPH``.H``%/C"```&@(PH.,(,(3E&#"$Y0PPU.4``%/C -M`@``"@4`H.$$$*#AC_;_ZP`PH.,2,,3E\(&]Z-@S`^,#,)7G``!3XP,```H% -M`*#A!!"@X87V_^OP@;WH###4Y0``4^,",*`3`3"@`Q@PA.4`,`#C`#!`XP`0 -MD^4<`(3B$A"!XO[__^OP@;WH%#"4Y0$P0^(4,(3E``!3XR(``!K8,P/C`S"5 -MYP``4^,#```*!0"@X000H.%L]O_K%P``ZFPPE>4!,`/B`0!3XP@``!H(,(3E -M&#"$Y0PPU.4``%/C#@``&@4`H.$$$*#A9/W_ZPH``.H``%/C"```&@(PH.,( -M,(3E&#"$Y0PPU.4``%/C`@``"@4`H.$$$*#A4_;_ZP`PH.,.,,3E\(&]Z-@S -M`^,#,)7G``!3XP,```H%`*#A!!"@X4GV_^OP@;WH###4Y0``4^,",*`3`3"@ -M`Q@PA.4`,`#C`#!`XP`0D^4<`(3B!1"!XO[__^OP@;WH###4Y0``4^,",*`3 -M`3"@`Q@PA.4`,`#C`#!`XP`0D^4<`(3B$A"!XO[__^OP@;WH&#"4Y0$`4^,( -M```:`C"@XQ@PA.4`,`#C`#!`XP`0D^4<`(3B?1^!XO[__^OP@;WHV#,#XP,P -ME><``%/C`P``"@4`H.$$$*#A'?;_ZP4``.H!,*#C"#"$Y1@PA.4%`*#A!!"@ -MX1O]_^L`,*#C$S#$Y?"!O>@8,)#E`0!3XP,``!H%`*#A!!"@X1+]_^L"``#J -M!0"@X000H.$)]O_KCS8#XP,PU><``%/C#```&I0V`^,#,)7G``!3XP@``!H" -M,*#CE"8#XP(PA>>$)@/C`C"%YP4`H.'9'87B/!"!XOCU_^L(,)3E!#!#X@@` -M4^,#\9^76@$`ZG#_`@"X!`,`]/\"`+@$`P"@_P(`3`$#`&```P"@`0,`T`$# -M``PPU.4``%/C`C"@$P$PH`,8,(3E`#``XP`P0.,`$)/E'`"$XF00@>+^___K -M\(&]Z`PPU.4``%/C"```"@(PH.,8,(3E`#``XP`P0.,`$)/E'`"$XA00@>+^ -M___K\(&]Z`$PH.,8,(3E`#``XP`P0.,`$)/E'`"$X@H0@>+^___K\(&]Z!0P -ME.4!,$/B%#"$Y=@S`^,#,)7G``!3XP<```HX,P/C`S"5YP("4^,#``":!0"@ -MX000H.&[]?_K\(&]Z`PPU.4``%/C`C"@$P$PH`,8,(3E`#``XP`P0.,`$)/E -M'`"$XA(0@>+^___K\(&]Z!0PE.4!,$/B%#"$Y0``4^,=```:V#,#XP,PE><` -M`%/C!P``"C@S`^,#,)7G`@)3XP,``)H%`*#A!!"@X9[U_^L.``#J`3"@XP\P -MQ.4$,*#C"#"$Y0PPU.4``%/C`C"@$P$PH`,8,(3E`#``XP`P0.,`$)/E'`"$ -MXF00@>+^___K`#"@XPXPQ.7P@;WHV#,#XP,PE><``%/C!P``"C@S`^,#,)7G -M`@)3XP,``)H%`*#A!!"@X8#U_^OP@;WH###4Y0``4^,",*`3`3"@`Q@PA.4` -M,`#C`#!`XP`0D^4<`(3B!1"!XO[__^OP@;WH###4Y0``4^,(```*`C"@XQ@P -MA.4`,`#C`#!`XP`0D^4<`(3B%!"!XO[__^OP@;WH`3"@XQ@PA.4`,`#C`#!` -MXP`0D^4<`(3B"A"!XO[__^OP@;WH###4Y0``4^,",*`3`3"@`Q@PA.4`,`#C -M`#!`XP`0D^4<`(3B"A"!XO[__^OP@;WH%#"4Y0$P0^(4,(3E``!3XP0``!H, -M,-3E``!3XZ<```H!,*#C%#"$Y0PPU.4``%/C`C"@$P$PH`,8,(3E`#``XP`P -M0.,`$)/E'`"$X@H0@>+^___K\(&]Z!@PD.4!`%/C`P``&@4`H.$$$*#A._S_ -MZP(``.H%`*#A!!"@X3+U_^L(,)3E!@!3XP(```H*`%/C\(&]&#T``.H4,)3E -M`3!#XA0PA.4``%/C(```&M@S`^,#,)7G``!3XPT```HX,P/C`S"5YP("4^,) -M``":`C"@XP@PA.48,(3E###4Y0``4^,/```*!0"@X000H.$6]?_K"P``Z@$P -MH.,(,(3E&#"$Y0PPU.4``%/C!0``&@`P`.,`,$#C`!"3Y1P`A.(%$('B_O__ -MZP`PH.,2,,3E\(&]Z-@S`^,#,)7G``!3XP<```HX,P/C`S"5YP("4^,#``": -M!0"@X000H.'[]/_K\(&]Z`PPU.4``%/C`C"@$P$PH`,8,(3E`#``XP`P0.,` -M$)/E'`"$XA(0@>+^___K\(&]Z!0PE.4!,$/B%#"$Y0``4^,@```:V#,#XP,P -ME><``%/C#0``"C@S`^,#,)7G`@)3XPD``)H",*#C"#"$Y1@PA.4,,-3E``!3 -MXP\```H%`*#A!!"@X=CT_^L+``#J`3"@XP@PA.48,(3E###4Y0``4^,%```: -M`#``XP`P0.,`$)/E'`"$X@40@>+^___K`#"@XPXPQ.7P@;WHV#,#XP,PE><` -M`%/C!P``"C@S`^,#,)7G`@)3XP,``)H%`*#A!!"@X;WT_^OP@;WH###4Y0`` -M4^,",*`3`3"@`Q@PA.4`,`#C`#!`XP`0D^4<`(3B!1"!XO[__^OP@;WH&#"0 -MY0$`4^,#```:!0"@X000H.&O^__K\(&]Z`4`H.$$$*#AIO3_Z_"!O>@!`%/C -M(OS_&A[\_^H*,*#C%#"$Y0$PH.,8,(3E`#``XP`P0.,`$)/E'`"$XC(0@>+^ -M___K\(&]Z!!`+>E0`$#B_O__ZQ"`O>@>_R_A5S#0Y1(`4^,"`*"#`"``DP`@ -M0),#`9*7'O\OX1!`+>D[/*#C`S"0YR``@>+X*`/C`A"3Y_[__^L!`''B``"@ -M,Q"`O>B^P=#A#,B@X1S`@.4`,*#C`R"@X;,0D.$!("+@`C"#XB``4^/Z__\: -M#"""X1P@@.4>_R_A%3#0Y0``4^,>_R\!`B#0Y0``4N,>_R\1`3!#X@0`4^,# -M\9^7&```ZH0%`P"@!0,`H`4#`+P%`P"$!0,`!#"1Y0$U@^,$,('E"#"1Y04!-8/C!#"!Y0@PD>4'-H/C"#"!Y1[_+^$$,)'E`S6# -MXP0P@>4(,)'E!S:#XP@P@>4>_R_A*S#0Y0$`4^,"```*`@!3XP<``!H#``#J -M`#"1Y0$Z@^,`,('E`@``Z@`PD>4".X/C`#"!Y2LPT.4``%/C`#"1%0(Z@Q,` -M,($5'O\OX48PT.4``%/C'O\O`0`PD>5((-#E`0`2XP(DH!,`(*`#`R""X0`@ -M@>5),-#E`0!3XP$F@@,`(($%'O\O`0(`4^,")H(#`""!!1[_+P$``%/C`R:" -M$P`@@14>_R_A`#"@X1X0T.6R(=#A`A"!X!0`D.4*(-/E``!2XQ\@TQ4(`(#B -M`0"`X`(`@.`=,-/E`@!3XP@`@`(>_R_A\$$MZ0)0H.$#8*#A&'#=Y0%`H.$! -M`*#A`!"@XR`@H./^___K`#"4Y2,S@^,"-H/C=5#_Y@50@^$`4(3E!#"4Y1(\ -M@^,$,(3E``!6XP$V@Q,$,(05$#"4!8`P@P,0,(0%##"4!0(Q@P,,,(0%`0!7 -MXP@PE`4"-8,#"#"$!1`PE.4!/(/C$#"$Y00`H.'^___K\(&]Z/A/+>D`8*#A -M`E"@X6APD.4[+*#C`K"7YP%`H.%&H-#E`:`*X@"04^(&```:!P"@X040H.'^ -M___K``!0XPA`A`(!@*`#````"@"`H.,$`*#A`!"@XR`@H./^___K`#"4Y2,S -M@^,"-H/C=5#_Y@50@^$`4(3E``!:XP%4A1,`4(05``!9XP<``!H``%CC!0`` -M"G4PUN5S(*_F``!2XPD``-H!,$/B=3#&Y74PUN5S(*_F``!2XP,]H,$?,P/" -M!""4Q0,P@L$$,(3%$#"4Y0$\@^,0,(3E9#"6Y0\P`^(!`%/C:0``&@B@AN(R -M(-;E/R`"X@0PE.4#((+A!""$Y5#`P,V@Q,4 -M,(3E+#H#XP,PE^<``%/C%#"4%00P@Q,4,(05#```Z@@`4^,*```*!#"4Y08X -M@^,$,(/C!#"$Y;X@UN$`,`#C_S]`XP(X`^`,()3E`S""X0PPA.5-,-;E``!3 -MXP4``!H,,)3E`C&#XPPPA.40,)3E@#"#XQ`PA.4$`*#A_O__ZP<`H.%D$);E -M!""@X?[__^L(`*#A^(^]Z/!/+>DLT$WB!`"-Y1`0C>4[/*#C`S"0YR0PC>7X -M.`/C)!"=Y0,PD><,,(WE``!2XQ@@C>4%```:$`"=Y?[__^L``%#C&`"-Y0`` -MH`/I```*$`"=Y0`0H./^___K$`"=Y8@0D.6,(-#E_O__ZP!04.($```:$`"= -MY1@0G>7^___K``"@X]L``.H8()WE<""%Y1`PDN5L,(7E%%""Y0$PH.-T,,7E -M=3#%Y00`G>5@$)7E!2"@X?[__^L$`)WE!1"@X?[__^L%`*#AL?[_Z]5'U>&$ -M08#@($"$X@>0%.(!D*`3I)&)X(F1H.$,,)WE"0!3X10PC84!$*"#"!"-A0<` -M`(H)`*#A#!"=Y?[__^L,()WED"(@X!0`C>4`,*#C"#"-Y5R@E>4P,-7E!P!3 -MXPL``(K0,]7A`2"@XQ(SH.'``!/C5*"*$@8``!HP`!/C0*"*$@,``!H&`!/C -M+*"*$@```!H8H(KB_O__ZPT0H.%_/<'C/S##XP0@D^4!((+B!""#Y0@@BN(< -M((WE"(":Y2!`C>4`L*#C!6"@X4P``.H(0*#A`("8Y72PQ.5UL,3E!`"@X7?^ -M_^L@<(GB`'"'X`=0%^(!4*`3IU&%X(51H.$%"E7C!0``F@90H.$!,*#C=##$ -MY74PQ.4@<)WE00``Z@P`E.@$,(+E`""#Y0!`A.4$0(3E$#":Y0$P0^(0,(KE -M&!"=Y1`PD>4)D(/@;)"$Y00`G>5@$)3E!""@X?[__^L$`)WE!!"@X?[__^L$ -M`*#A;!"4Y1@@E.4!,*#CA?[_ZQ``G>4$$*#A_O__ZW0PUN4!,(/B4%`%+A"P``F@@0G>4!,('B4D$)WE,2D# -MXP(PT><(()WE`@!3X0@``!H&4*#A$0``Z@4`H.$,$)WE_O__ZPPPG>60,R#@ -M%`"-Y0BPC>4@<(WE!9"@X1P`G>4($*#A_O__ZP``4..M__\*!E"@X2!PG>4` -M``#J!E"@X0@`BN+^___K`0!0XP0``!H,`)KH!#""Y0`@@^4`H(KE!*"*Y0T0 -MH.%_/<'C/S##XP0@D^4!($+B!""#Y?[__^N\,-7ACB@(XP88`.,!`%/A`@!3 -M$04```H+,-7E`0!3XP(```H$`)WE!1"@X?[__^L'`*#A#!"=Y?[__^L``%'C -M!@``&@AP1^)L,)7E"#"#XFPPA>5U,-7E`3!#XG4PQ>4%`*#A;!"5Y1@@E>4! -M,*#C+O[_ZP4`H.'^___K`!"@X00`G>4'(*#A&#"=Y?[__^O5-]7A="#5Y8(B -MH.$`(&+B@R%"X`0`G>4%$*#A!R""X/[__^L0`)WE!1"@X?[__^L!`*#C+-"- -MXO"/O>CP3RWI%-!-X@!0H.$!0*#A!""-Y7`PD>4(,(WE4SV`XB`P@^(,,(WE -M9#"1Y0$`4^,*```:O##1X08H`.,"`%/A!@``"HXH".,"`%/A`P``"@LPT>4! -M`%/C````"O[__^ML8)3E'"#4Y0``4N,T``#:`'"@XS25`>,DO`'C`2!"X@<` -M4N$8@)0%!@``"@F`E><$@$CB"S"5YP``4^,`,*`3'S#4!0B`8^`$`*#A!A"@ -MX0@@H.$`,*#CZ?W_ZP``4.,(8(82;&"$%2"@B!(HH(@"!`"@X?[__^L`$*#A -M!#"=Y0$`4^,$```:!0"@X0H@H.$(,)WE_O__ZP,``.H%`*#A"B"@X0@PG>7^ -M___K!0"@X000H.$((*#A_O__ZP%PA^(<(-3E!P!2X04``-H*8(;@`S`6X@$P -MH!,F88/@!F&@XD!(*#CIO__ -MZQ"`O>@00"WI`""@XZ+__^L0@+WH\$+^___K``!0XR@``,IL -M,)3E(@T3XR4``!H&`*#A_O__ZP!P4.(A```*#2"@X7\]PN,_,,/C!""3Y0$@ -M0N($((/E_O__ZW!PA>40,)?E;#"%Y110A^4$`*#A8!"5Y04@H.'^___K`0!0 -MXP4``!H$`*#A!1"@X0`@H.-T___K`0"@X_"'O>BH`)_EJ!"?Y?[__^L&`*#A -M!Q"@X?[__^L&`*#A!1"@X?[__^L!`*#C\(>]Z`0`H.$%$*#A_O__ZP!PH.$- -M(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K`0!7XP``H`/PA[T(!@"@X040 -MH.'^___K2#4!X].`A.$`8.#C`'#@XP8`F.`'$*G@\P"$X5`U`>/3@(3A`6"@ -MXP!PH.,&`)C@!Q"IX/,`A.$!`*#C\(>]Z,0&``!D%```$$`MZ0`@H.-!___K -M$("]Z!!`+>D`(*#A5@V`X@`0`.,`$$#C_O__ZP$`H.,0@+WH`#"@XSPP@>48 -M,('E"#"!Y1`PD>4``%/C)#"!%1PP@14@,($5#SN#$B@P@14>_R_A<$`MZ0!@ -MH.&(-@'C`T"0YQ)>A.(&`*#A!!"@X?[__^M(0(3B!0!4X?G__QJ$-@'C`P"6 -MYP``4.,!```*21^@X_[__^M9;8;B.`"&XO[__^LL`(;B_O__ZW"`O>CP1RWI -M`$"@X5D-@.(8`(#B`!``XP`00.,$(*#A_O__ZUH-A.(,`(#B_O__ZTD/H./^ -M___KA#8!XP,`A.<``%#C`*"@`T0```H`$*#C22^@X_[__^N$-@'C`U"4YP-0 -MA>(#4,7CB#8!XP-0A.?8<(7B#VN@XP"`H.,%`*#A_O__ZP@`A>+^___K-&"% -MY00`H.$%$*#A_O__ZP"@4.($```*"("%Y0Q`A>4'`%7A2%"%$O#__QH$(*#C -ME#8!XP,@A.=9C83B.#"(XG@F`>,",(3G?"8!XP(PA.<`8*#C6CV@XP-@A.,#8(3G"%P#XR!PH.,%`)3G!1"@X0<@ -MH.'^___K`!!0X@L```H%,)3G%#"!Y:@@D>4',`+B"#!CX@,@@N"H(('EG""1 -MY0,P@N"<,('E"`"@X?[__^L!8(;B"`!6X^K__QH*`*#A\(>]Z$C`D.4`()#E -M.SR@XP,PDN>``%'C!```&@``G.6`,`CC`#!,XP`$@^$>_R_A@0!1XP0``!H` -M`)SE@#``XP(P3.,`!(/A'O\OX0<`4>,``*"#'O\O@0`@G.4")*#A`R&"XW$0 -MX^;C'8'B(!"!X@8`T>4/``#B@`>"X1[_+^$>_R_A'O\OX04PH..T,<#A$3"@ -MX[8QP.$>_R_A$$`MZ0!`H.$`$*#C4""@X_[__^L`,`#C`#!`XP`PA.4`,`#C -M`#!`XP0PA.4`,`#C`#!`XP@PA.4`,`#C`#!`XR@PA.4`,`#C`#!`XS@PA.4` -M,`#C`#!`XPPPA.4`,`#C`#!`XQ`PA.4`,`#C`#!`XQ0PA.4`,`#C`#!`XQ@P -MA.4`,`#C`#!`XRPPA.4`,`#C`#!`XSPPA.4`,`#C`#!`XT`PA.4`,`#C`#!` -MXT@PA.4`,`#C`#!`XTPPA.40@+WH\$4``%#C````"O[__^L!0(3B!%"%X@@`5./W -M__\:!P!6X0,```J@8(;B!E"@X0A`H.'Q___JS#4!XP-@FN=-?8;B('"'X@"` -MH.,*``#J0`"5Y0``4.,````*_O__ZP%`A.($4(7B"`!4X_?__QH'`%;A\(>] -M"*!@AN(&4*#A"$"@X?'__^IP0"WI`#"0Y8@F`>,"0)/G`1"@X[$L`^,"$,/G -MV%"$X@%@H.%$8,3E+`"4Y0``4.,````*_O__ZP4`5.%P@+T(2$"$XO;__^KX -M3RWI`7"@X0*0H.$HL)WE`$"0Y0-0H.$4@)/E9*"4Y,_,,/C!!"3Y0$0@>($$(/E -M!@!7XP?QGY,# -M$)3G`1"!X@,0A.<`,*#CNC'%X1D``.J<-0'C`Q"4YP$0@>(#$(3G`1"@X[H1 -MQ>$2``#JE#4!XP,0E.,#$)3G`1"! -MX@,0A.<#$*#CNA'%X00``.H&,*#CNC'%X0$``.H`$*#CNA'%X0+P(>$-(*#A -M?SW"XS\PP^,$()/E`2!"X@0@@^4`,)/E`@`3XP````K^___K0&"5Y1P`A.(' -M$*#A#___ZVPPF.4HH(;E,`"&Y4`PAN50D(;E`#``XP`P0.-T,(;E<%"&Y08` -MH.$@$*#C_O__ZP``6^,"``"J`0!PX@``H#/XC[WH``!;XP)QX`,"```*"P"@ -MX?[__^L`<*#A`$"@XVQ`A>5P`(7B`!``XP`00./^___K`3"@XV0PQ>5H0(7E -M;`"%X@<0H.'^___K!`!0X6@`E14$```:!@"@X?[__^MH`)7E`@!PXVT`X`,! -M`'#B``"@,_B/O>@$X"WE#-!-XHC#`>,`P(WE(`@+WH!.`MY0S0 -M3>(`P.#C`,"-Y6G__^L,T(WB`("]Z/!!+>D`<*#A<%"0Y0A`E>53;83B(&"& -MXKHQU>$&`%/C`_&?EQP``.KL&`,``!D#`!09`P`H&0,`1!D#`$09`P`\&0,` -MH#4!XP,@E.,# -M()3G`2!"X@,@A.<&``#JF#4!XP,@E.+^___K!@"@X040H.'^ -M___K5CV$X@`0#^&```SQ!""SY0$`@N,``(/E`?`AX0$`$N/P@;T85@V$XO[_ -M_^OP@;WH\$\MZ3303>(`0*#A`8"@X0)@H.$#<*#AO+7=X6"0W>4`4)#E2*"0 -MY=`[`^,#,)7G``!3XVD``!J0,P/C`S#5YP``4^-E```:_@!;XQ5`X(-C``"* -M,""$XB@@C>4"`*#A_O__ZT!`E.480(WE``!4XPM`X`-6```*:#"%XB0PC>4! -M(*#C(""-Y1RPC>4!.D;B48`)WE`!"@XQP@G>7^___K`0!9XP4` -M`!H`0)KE!$2@X0)!A..`0(3CP#"@XP<``.H`0)KE!$2@X0)!A.,8`)WE6!"= -MY1P@G>7^___K0#"@X\``C>@8()WE"""-Y1P@G>4,((WE?2^@XQ`@C>4*`*#A -M!!"@X0@@H.'^___K`$"@X0L`4.$)```:)`"=Y0`0H./^___K`0!9XQL``!I8 -M`)WE&!"=Y1P@G>7^___K%@``Z@``4.,%``"J;`!PXQ,`48$)WE'""=Y?[__^LD`)WE_O__ -MZP0`4.,!(*##T#L#PP,@A<<+``#*+#"=Y?\O`.,"`%/A!P``FAPPG>4#`%3A -M!```"B`@G>4!((+B(""-Y0L`4N.P__\:*`"=Y?[__^L```#J`$#@XP0`H.$T -MT(WB\(^]Z/!!+>D1WDWB`%"@X0&`H.$"8*#A`W"@X1!`C>($`*#A`!"@X_X@ -MH./^___K!%"5Y79@_^8$`*#A!Q"@X08@H.'^___K4`"-Z``PH.,(,(WE!0"@ -MX040H.-X(/_F:___ZQ'>C>+P@;WH!.`MY1S03>($`)#E&#"-X@0@(^5Q(/_F -M`#"-Y00PH.,$,(WE`#"@XP@PC>4%$*#C7/__ZQS0C>(`@+WH!.`MY1S03>($ -M`)#E&#"-XK(@8^%Q(/_F`#"-Y0(PH.,$,(WE`#"@XP@PC>4%$*#C3?__ZQS0 -MC>(`@+WH!.`MY1S03>($`)#E&#"-X@$@8^5Q(/_F`#"-Y0$PH.,$,(WE`#"@ -MXP@PC>4%$*#C/O__ZQS0C>(`@+WH!.`MY1S03>(`,*#C&,"-X@0P+.4$`)#E -M<2#_Y@#`C>4$$*#C!!"-Y0$0H.,($(WE!1"@XR[__^L4`)WE'-"-X@"`O>@$ -MX"WE'-!-X@`PH.,8P(WBLC!LX00`D.5Q(/_F`,"-Y0(0H.,$$(WE`1"@XP@0 -MC>4%$*#C'?__Z[8!W>$4(!,&SE!`"0 -MY7$@_^8`P(WE`1"@XP00C>4($(WE!1"@XPW__^L7`-WE'-"-X@"`O>CP02WI -M`7"@X01@D.4`0);E2("6Y -M```:D",#XP(@U.<``%+C6@``&@-0H.%$,-/E``!3XP(```I`,)7E``!3XP8` -M`!I9#83B+`"`XO[__^M``(7E``!0XP$PH!-$,,45``!5XTH```H$`*#A!1"@ -MX?[__^M$,-7E``!3XP(```I`,)7E``!3XQH``!H('`/C`0"4YR`@H./^___K -M0`"%Y0``4.,Z```*J""0Y06H()/E(""%Y9P@D^4D((7EH""3Y2@@A>6H,)/E$#"%Y0P` -M`.JD,)/E'#"%Y4`PE>6H()/E(""%Y9P@D^4D((7EH""3Y2@@A>6H,)/E$#"% -MY0`PH.-$,,7E63V@XP,@U.4&`*#A!Q"@X2[]_^L0,)7E -M*("$Y3``A.5`,(3E#SN@XU`PA.4`,`#C`#!`XW0PA.5P4(3E!`"@X2`0H./^ -M___K`0"`X@$`4.,``*"#`0"@D_"!O>@``*#C\(&]Z'!`+>D`8*#A<%"0Y0Q` -ME>59/:#C`R#4YP$@0N(#(,3GT#L#XP,PE.<``%/C!P``&LP[`^,#,)3G``!3 -MXP,``!JQ/`/C`S#4YP``4^,"```*`3"@XT0PQ>5P@+WH.#"0Y0``4^,R```: -M5""0Y1@@0N+H.P/C`P!2X0@``)H!,*#C1##%Y00`H.$\-@'C`Q"4YP`@H.,% -M,*#A_O__ZW"`O>AH`(3B`!"@X_[__^M4,);E/#"%Y4``E>54$);E_O__ZUD- -MA.(X`(#B0!"5Y?[__^M:/:#C`S"4YP$`4^,+``"*63V$X@`0#^&```SQ'""S -MY0$`@N,``(/E`?`AX0$`$N,"```:60V$XA@`@.+^___K`""@XT`@A>5$(,7E -M!`"@X3PV`>,#$)3G!3"@X?[__^MP@+WH:`"$XO[__^L$`%#C`2"@P]`[`\,# -M((3'.#"6Y2``<^,+```*!```RFP`<^,(```*1P!SXW"`O1@)``#J$P!SXP,` -M``H"`'/C`0``"A8`<^-P@+T8`2"@X\P[`^,#((3G<("]Z`$PH.-$,,7E!`"@ -MX3PV`>,#$)3G`""@XP4PH.'^___K<("]Z/!'+>D`0*#A4WV`XB!PA^)L,)#E -M`@L3X_"'O1C,6P/CT&L#X[*,`^,`H*#C!3"4YP$`4^/PA[T(!C"4YP$`4^/P -MA[T("##4YP$`4^/PA[T(!`"@X0<0H.$*(*#A_O__ZP``4./P__\:\(>]Z/!/ -M+>D\T$WB`)"@X5D]@.(X$(/B+!"-Y5<@,(WE&#"=Y5!0D^6H<)/E"H#7Y2`0G>6I -M'8'B$!"!XB00C>4`(*#C*""-Y10`G>7^___K`$!0XK,```H<<(WE!`"@X?[_ -M_^L`,*#CB#"$Y70PA.4$`*#A!Q"@X?[__^LR,-3E``!3XP,```H$`*#A%!"= -MY?[__^NC``#J'C#4Y0``4^,%```*63#4Y0``4^,@,-0%&#"#`@,PAP`H,(T% -MO*'4X1]@U.4&8(K@&&"&X@6PH.$%`%;A`#"@DP$PH(,``%KC`3"#`P``4^,# -M```*!`"@X100G>7^___KB@``ZB0PU.4``%/C!C"@$P`PH`,0,(WENC+4X0$, -M4^,.$(H2#!"-%04``!IR%@#C`0!:X1HMH),,((V5#C"*@@PPC84(+`/C`@"9 -MYPP0G>4@(*#C_O__ZP!04.(B```*"!P#XP$PF><4,(7E"%"$Y:@`E>4',`#B -M"#!CX@,`@."<()7E`S""X!`@G>4"`(#@J`"%Y0(P@^"<,(7E'Q#4Y1@0@>(! -M$(?@"B"@X?[__^NH,)7E@#"$Y7PPA.5X,(3EJ""5Y0P0G>4!((+@A""$Y0HP -M@^"`,(3E`@!3X0.@:H"`H(2%"P``B@<``.H8`)WE(!"@X_[__^L(`(3E!`"@ -MX100G>7^___K2```ZG0PE.4*H(/@=*"$Y1XPU.4``%/C!0``"EDPU.4``%/C -M`@``&@0`H.$H$)WE_O__ZR`0G>4X*0/C`C"1YP(`4^,)```*`P!3XP$```H! -M`%/C"@``&G\P%N(!,*`3IF.#X(9CH.%V8/_F!```Z@,P%N(!,*`3)F&#X`9A -MH.%V8/_F63#4Y0``4^,"```:!`"@X?[__^L0``#J`0!3XP(``!HT`)WE_O__ -MZP@``.H"`%/C!@``&GP0E.6\(=3A7#"4Y6``E.4``(WE)`"=Y?[__^L$`*#A -M%!"=Y?[__^L!@$CB>(#_Y@M09N```%7C`#"@TP$PH,,``%CC`""@$P$@`P(` -M`%+C'""=%0J`TA4``%CC`#"@`P$P`Q(``%/C!G"'$$?__QH8$)WEJ#"1Y9PP -M@>4`(*#C4""!Y3``G>48$)WE_O__ZRP`G>7^___K``!0XQ@`C>4B__\:/-"- -MXO"/O>A7,-#E$@!3XQ$``(K7-=#A`2"@XQ(CH.'`,`#C!S!`XP,P`N```%/C -M!`"@$Q[_+Q$P`!+C"```&@8`$N,$```*:""0Y0(_`N,#,-+G``!3XP$``!H& -M`*#C'O\OX04`H.,>_R_A,$`MZ0S03>(!0*#A`E"@X0T0H.,'((WB;#L#XP_@ -MH.$#\)#G!S#=Y0$`4^,$```:#T`$X@$`5.,`0*`3`4"@`P4``.H"`%/C(@`` -M&@]`!.(#`%3C`$"@$P%`H`,``%3C'```"G1`G^4$`*#A_O__ZVP`G^4`$)7E -M_O__ZV0`G^4$$)7E_O__ZUP`G^4($)7E_O__ZU0`G^4,$)7E_O__ZTP`G^40 -M$)7E_O__ZT0`G^44$)7E_O__ZSP`G^48$)7E_O__ZS0`G^4<$)7E_O__ZP0` -MH.'^___K#-"-XC"`O>CT!@``'`<``"P'```\!P``3`<``%P'``!L!P``?`<` -M`(P'```%,*#C&#"`Y0`@H.,`,*#C\"'`X1[_+^$>_R_A'O\OX1[_+^$>_R_A -M'O\OX1[_+^$>_R_A'O\OX1[_+^$!`*#C'O\OX1!`+>D!`*#A_O__ZQ"`O>@0 -M0"WI$""!Y10`@>4!`*#A`!"@XP$@H.'^___K$("]Z!!`+>D`,`#C`#!`XP`P -MD^5D`*#CD`("X-/-!.-BP$'CG`*"X`$`H.$B$X/@_O__ZQ"`O>@00"WI_O__ -MZQ"`O>@00"WI_O__ZQ"`O>@00"WI_O__ZQ"`O>@00"WI_O__ZQ"`O>@00"WI -M_O__ZQ"`O>@00"WI`0"@X0(0H.$#(*#A_O__ZQ"`O>@00"WI`0"@X0(0H.'^ -M___K$("]Z!!`+>D!0*#A`@"@X?[__^L``(3E$("]Z!!`+>D``)#E_O__ZQ"` -MO>@$X"WE#-!-X@``D.40P)WE`,"-Y?[__^L,T(WB`("]Z!!`+>D``)#E_O__ -MZQ"`O>@00"WI``"0Y?[__^L0@+WH$$`MZ0``D.7^___K$("]Z!!`+>D``)#E -M_O__ZQ"`O>@00"WI``"0Y?[__^L0@+WH$$`MZ0``D.7^___K$("]Z!!`+>D` -M`)#E_O__ZQ"`O>@00"WI``"0Y?[__^L0@+WH$$`MZ0``D.7^___K$("]Z!!` -M+>D``)#E_O__ZQ"`O>AP,._F8R"#XG(@[^9V`%+C``"@@Q[_+X$``%#C9`"@ -MHV0P@[)S`.^V'O\OX0``H.,>_R_A``"@XQ[_+^$D(-#E`2!"XG(@[^8!`%+C -M+```B@$PH.$S($'B,0!2XV0PH),G``":*2!#X@D`4N.!,*"1(P``FA\@0^() -M`%+C)#"!DA\``)H5($/B"0!2XR(P@9(;``":"B!#X@H`4N,'``"*"A!!XH$0 -MH.%6)07C525%XY(!P^#!/T/@*C"#XA```.H%($/B!`!2XP4``(J!$('@#S!! -MXJ,_@^##,*#A%C"#X@<``.H!,$/B`P!3XP$PH($!$$&2@1"!D*$?@9#!,*"1 -M!C"#D@,`H.$>_R_A$$`MZ1\PT.4(`%/C#```&B0PT.4``%/C!```"C,PT.4* -M`%/C!@``&O[__^L0@+WH,S#0Y1,`4^,!```:_O__ZQ"`O>C^___K$("]Z``` -MH.,>_R_A\$\MZ1303>(`0*#A`6"@X0.`H.$"4*#A`##3Y0,`4^,`,*"#`3"@ -MDPPPC>4`,.#C`C#!Y0,PP>4,`)WE``!0XQ4!``JV/Z#CTP"$X0&@H.,`L*#C -M"@"0X`L0H>#S`(3A'+#4Y060TN4H,)3E,``3XVT```H?,`GBJ9*@X0<`6>,) -M\9^73P``ZN0K`P#0*P,`@"L#`&`K`P!`*P,`("L#```K`P#4*@,`&P!3XYP` -MH(,(`(V%_S1CDO\X@Y+_/(.2Z3"#DH,PH)%S,.^6"#"-E3P``.K_-&/B_SB# -MXO\\@^+J,(/B@S"@X7,P[^8(,(WE-```ZO\T8^+_.(/B_SR#XO(P@^*#,*#A -M4L``#J_S1CXO\X@^+_/(/B]3"#XH,PH.%S,._F"#"-Y20``.K_ -M-&/B_SB#XO\\@^+[,(/B@S"@X7,P[^8(,(WE'```Z@``6^,(```*`S#@X8.@ -MH.$&H(KB>J#OY@B@C>5Z`*_F_O__ZP!PH.&7``#J`C!CXH.@H.$&H(KB>J#O -MY@B@C>5Z`*_F_O__ZP!PH.$1``#J!*!CXHJ@H.%ZH._F"*"-Y0,``.H'H&/B -MBJ"@X7J@[^8(H(WE"!"=Y0:@@>)ZH._F"*"-Y7H`K^;^___K`'"@X0``6^-\ -M```:3P!7XP4``)I0<$?BAS"@X5`P@^*G<(/@_W`'X@0``.H4,$?B2=W#OEF0`5^-L``"*;```Z@``6^,D```:*3.@X0,`4^,#\9^7/P`` -MZN`L`P#`+`,`H"P#`(`L`P`^H`GB_Z1JXO^HBN+_K(KBTJ"*XGJ@[^8(H(WE -M,P``ZCZ@">+_I&KB_ZB*XO^LBN+FH(KB>J#OY@B@C>4K``#J/J`)XO^D:N+_ -MJ(KB_ZR*XO2@BN)ZH._F"*"-Y2,``.H^H`GB$*!JXGJ@[^8(H(WE'@``ZMDR -MX><#`%/C`_&?EQH``.I<+0,`1"T#`"PM`P`4+0,`'S`)XBV@X..#H$K@>J#O -MY@B@C>40``#J'S`)XAF@X..#H$K@>J#OY@B@C>4*``#J'S`)X@N@X..#H$K@ -M>J#OY@B@C>4$``#J'Z`)XHJ@H.$0H&KB>J#OY@B@C>4(()WE<@"OYO[__^L` -M<*#A+S#4Y0$`4^,4```:@``9XP0``!I>`%#C!G"`DG=P[Y8(``":%P``ZB8` -M4.,0<$""=W#OA@,``(H0`%?C5W'GEPQP1X)W<.^&&C!'XG,P[^8B`%/C!G"' -MDG=P[Y8*``#J8P!0XPAP0()W<.^&!@``BC,P1^)S,._F$0!3XP1PAY)W<.^6 -M````ZF1PH.,`<,;E"'#&Y0@PG>4',,;E`C#8Y0``4^.S```*'S#4Y0@`4^,) -M```:,S#4Y1,`4^,&```:`#"@XP`PC>4$`*#A#!"=Y0<@H.'R_O_K%0``ZB@` -M5^,"``":-##4Y0``4^,/```*!##5Y4``4^,``*"##```BA,`4^,)``":0#!C -MXF0@H..2`P/@Z2(*XXLN0N.2H\#@PS^@X<`!8^!P`._F````ZF0`H.,!`,;E -M`@#&Y0`PX.,#,,;EBP``ZBX^H.,!H*#C`+"@X],`A.$*`)#@"Q"AX/,`A.$! -ML*#C`*"@XPB@C>4*D*#A!G"@X0)@H.$#``#J`:"*XGJ@[^8!L(OB>[#OY@I0 -MH.$=,-3E4SJ@X0$`$^,(`)T5`3"`$G,P[Q8(,(T5"@#6YS\``.(W`$#B@`"@ -MX7``[^8*,(?@"@##Y7``K^;^___K"9"`X'F0[^8O,-3E`0!3XQ```!H*,-;G -M@``3XP4```I>`%#C9`"@@P8`@))P`.^6!```F@<``.H0`%#CT`'GEQ``0()P -M`.^&!#!`XG,P[^8>`%/C`P"@D04PA^`$`,/E!2"&X`\@TN6B(*#A!5"$X,@B -MQ>4,(,/E`C#8Y0``4^,/```*'S#4Y0@`4^,,```:,S#4Y1,`4^,)```:``!: -MXP<``!H``(WE!`"@X0P0G>4`(*#C`C"@X83^_^L!`,?EN?__Z@$`6^.W__^: -M!E"@X0=@H.$$<-7EIW"@X6YP1^)W<._F=P"OYO[__^L``,;E"`#&Y09PQN4' -M<,;E'S#4Y0@`4^,"```:,S#4Y1,`4^,Z```*``#8Y10`0.)P`._F!P!0XP(` -MH),!`*"#!2"@X0`PH.-DP*#CW1#2X<$?`>!Q<._F(`!QXP4``+H`$&?B@1"! -MX'$0[^9Q<*_F8P!7XP```!H,$*#A`G#8Y0``5^,%```*<1#OYG-P[^8``%?C -M`1#&!0-PAN`"$,?E`3"#X@$@@N)S$._F`0!0X>7__XH6``#J!`"@X0<0H.'^ -M___K"0#&Y08``.H)`*#A"!"=Y?[__^MP$._F!`"@X?[__^L)`,;E&S#5Y=,S -MX.?Z,L3E&S#5Y5,SX.?[,L3E&S#5Y5,PX.?\,L3E%-"-XO"/O>@($)WE``!1 -MX_'__PKI___J'O\OX?A/+>D!,-+E_P!3X_B/O0@#P8#@G$"4`8)/E!5"&X`!0@^4! -M,-+E[#"#XI,,(^`,,(/@``"3Y0$`@.(``(/E#@``ZN0P@^($P*#CDPPCX`PP -M@^``4-'E`&"3Y050AN``4(/E`3#2Y?0P@^*3#"/@##"#X```D^4!`(#B``"# -MY0``TN446)3E&&B4Y0,PTN4``%/C`@``&@0PTN4``%/C^(^]"`,`4.,M``": -M!3#1Y0``4^,$,-$%#@``"@0@T>4"`%/A`@"@(0,@H"$#`*`Q`C"@X0(@8.`" -M`%+C!0``V@4`4N,!,$/2`@``V@D`4N,",$/2`S!#P@``5N,`8-'5#0``V@`@ -MT>4&`%+AAB&&X()@AN`&,(/@9R8&XV8F1N.2$\:`PS^@@<9A8X`!8(:"DA/" -MD,,_H)'"86.0@CZ@X],`A.$`H)#@`;"AX`&`H.,`D*#C"`"*X0D0B^'S`(3A -M%0``Z@``5>,`4-'5#0``V@`PT>4%`%/AA2&%X()0A>`#,(7@9R8&XV8F1N.2 -M$\6`PS^@@<518X`!4(6"DA/"D,,_H)'"46.0@CZ@X],`A.$`@)#@`9"AX/.` -MA.$H&-3E/P!1XP<``)I`$*#C*!C$Y00PH.$@B+/E!`"3Y0`PH.,#P*#A!0`` -MZ@$0@>)Q$._F*!C$Y0``4>/T__\:&P``ZB!P8^(X(Z#A$">"X2!P4^(P)Z!1 -M`2`"X@+`C.`!,(/B,$```*`0!LX)8,#."5P"#@_O__ZP`` -M`.H``*#C%%B$Y1AHA.40"(3E^(^]Z```TN446)3E&&B4Y8#__^H>_R_A'O\O -MX1!`+>DH,)#E$`!3XP```!K^___K``"@XQ"`O>@00"WI`$"@X2@PD.40`%/C -M5```&@``4>,!```:_O__ZP(``.H!`%'C````&O[__^L0,)3E``!3XTH``*H8 -M,)3E`P!3XT<``)HH,)3E`@!3XP(``!H4`9_E_O__ZQ<``.H$`%/C`@``&@0! -MG^7^___K$@``Z@@`4^,"```:]`"?Y?[__^L-``#J$`!3XP(``!KD`)_E_O__ -MZP@``.H@`%/C`@``&M0`G^7^___K`P``ZD``4^,!```:Q`"?Y?[__^O``)_E -MP!"?Y?[__^L0,)3E``!3XR,``*H8,)3E`P!3XR```)HH,)3E`@!3XP(``!IX -M`)_E_O__ZQ<``.H$`%/C`@``&F@`G^7^___K$@``Z@@`4^,"```:6`"?Y?[_ -M_^L-``#J$`!3XP(``!I(`)_E_O__ZP@``.H@`%/C`@``&C@`G^7^___K`P`` -MZD``4^,!```:*`"?Y?[__^LL`)_E)!"?Y?[__^L``*#C$("]Z)P'``"H!P`` -MM`<``,0'``#4!P``X`<``.P'``!X%```-`@``'!`+>D`0*#A`E"@X1`PD.4` -M`%/C(P``JA@PD.4#`%/C(```FB@PD.4"`%/C`@``&FP"G^7^___K%P``Z@0` -M4^,"```:7`*?Y?[__^L2``#J"`!3XP(``!I,`I_E_O__ZPT``.H0`%/C`@`` -M&CP"G^7^___K"```ZB``4^,"```:+`*?Y?[__^L#``#J0`!3XP$``!H<`I_E -M_O__ZQ@"G^48$I_E_O__ZR@PE.40`%/C40``&@``5>,!```:!`"@X?[__^L0 -M,)3E``!3XW(``*H8,)3E`P!3XTH``)HH,)3E`@!3XP(``!JT`9_E_O__ZQ<` -M`.H$`%/C`@``&J0!G^7^___K$@``Z@@`4^,"```:E`&?Y?[__^L-``#J$`!3 -MXP(``!J$`9_E_O__ZP@``.H@`%/C`@``&G0!G^7^___K`P``ZD``4^,!```: -M9`&?Y?[__^MH`9_E8!&?Y?[__^L0,)3E``!3XTL``*H8,)3E`P!3XR,``)HH -M,)3E`@!3XP(``!H8`9_E_O__ZQ<``.H$`%/C`@``&@@!G^7^___K$@``Z@@` -M4^,"```:^`"?Y?[__^L-``#J$`!3XP(``!KH`)_E_O__ZP@``.H@`%/C`@`` -M&M@`G^7^___K`P``ZD``4^,!```:R`"?Y?[__^O0`)_EQ!"?Y?[__^L0,)3E -M``!3XR0``*H8,)3E!`!3XR$``)HH,)3E`@!3XP(``!I\`)_E_O__ZQ<``.H$ -M`%/C`@``&FP`G^7^___K$@``Z@@`4^,"```:7`"?Y?[__^L-``#J$`!3XP(` -M`!I,`)_E_O__ZP@``.H@`%/C`@``&CP`G^7^___K`P``ZD``4^,!```:+`"? -MY?[__^LX`)_E*!"?Y04@H.'^___K``"@XW"`O>BD`0*#A`6"@X0-0H.'^ -M___KZ#74Y0$`4^,*```:`S#5Y0``4^,"```:!##5Y0``4^-P@+T(!`"@X0$0 -MU>4&(*#A_O__ZW"`O>@$`*#A!A"@X04@H.'^___K<("]Z!!`+>G^___K$("] -MZ"\`4>,!\9^74```ZJ`Z`P"8.@,`J#H#`+`Z`P"X.@,`P#H#`,@Z`P#0.@,` -MX#H#`.@Z`P#P.@,`^#H#```[`P`(.P,`$#L#`!@[`P`<.P,`'#L#`!P[`P`< -M.P,`'#L#`!P[`P`<.P,`'#L#`!P[`P`<.P,`'#L#`!P[`P`<.P,`'#L#`!P[ -M`P`<.P,`'#L#`!P[`P`<.P,`'#L#`!P[`P`<.P,`'#L#`!P[`P`<.P,`'#L# -M`!P[`P`<.P,`'#L#`!P[`P`<.P,`V#H#`"`@@.4>``#J'R#`Y1P``.HD(,#E -M&@``ZID@P.48``#J*""`Y18``.HL(,#E%```ZBT@P.42``#J+B#`Y1```.H\ -M(,#E#@``ZB\@P.4,``#J,"#`Y0H``.HQ(,#E"```ZC(@P.4&``#J,R#`Y00` -M`.HT(,#E`@``ZC4@P.4```#J-B#`Y0PPH./@/<#EX3W`Y0`PH./C/<#E'O\O -MX1`00>(6`%'C`?&?ET,``.J@.P,`J#L#`+`[`P"X.P,`P#L#`,@[`P#0.P,` -MV#L#`.`[`P#H.P,`\#L#`/@[`P``/`,`"#P#`!`\`P`8/`,`(#P#`"@\`P`P -M/`,`.#P#`$`\`P!(/`,`4#P#`$0@@.4>_R_A2""`Y1[_+^%,((#E'O\OX5`@ -M@.4>_R_A5""`Y1[_+^%8((#E'O\OX5P@@.4>_R_A8""`Y1[_+^%D((#E'O\O -MX6@@@.4>_R_A;""`Y1[_+^%P((#E'O\OX70@@.4>_R_A?""`Y1[_+^%X((#E -M'O\OX8`@@.4>_R_AA""`Y1[_+^&(((#E'O\OX?@E@.4>_R_A_"6`Y1[_+^$` -M)H#E'O\OX8P@@.4>_R_AD""`Y1[_+^$P`%'C`@&``)PP@`4>_R_A`1!!XBT` -M4>,!\9^700``ZC`]`P"`/0,`@#T#`(`]`P"`/0,`@#T#`#@]`P"`/0,`@#T# -M`(`]`P"`/0,`@#T#`(`]`P"`/0,`@#T#`(`]`P"`/0,`@#T#`(`]`P"`/0,` -M@#T#`(`]`P"`/0,`@#T#`(`]`P"`/0,`@#T#`(`]`P"`/0,`@#T#`(`]`P"` -M/0,`@#T#`(`]`P"`/0,`@#T#`(`]`P"`/0,`0#T#`$@]`P!0/0,`6#T#`&`] -M`P!L/0,`=#T#`'P]`P`@((#E'O\OX2X@P.4>_R_AE"#`Y1[_+^&5(,#E'O\O -MX98@P.4>_R_AER#`Y1[_+^$0((#E%#"`Y1[_+^$8((#E'O\OX4$FP.4>_R_A -M0B;`Y1[_+^%@,)#E`##3Y0$`4^,1```:6#"0Y0`PT^4!`%/C!P``&F0PD.4` -M,-/E`C!#XAXPP.4`(*#A`#"@XP/`H.$)``#J`@!3XV0PD`4`,-,%`C"#`AXP -MP`7U___J9#"0Y0`PT^4>,,#E\?__ZIP0DN4``%'C`<",$GS`[Q8!,(/B_R_A``!1XP`D@`4>_R\! -M`0!1X_PC@`4>_R\!!0!1XP$PH`/X,\`%'O\O`08`4>,`,*`#^#/`!1[_+P$" -M`%'C`P``&AX`4N,>(*`C$B3`Y1[_+^$#`%'C`P``&@``4N,!(*`#%B3`Y1[_ -M+^$$`%'C'O\O$5``4N-0(*`C%23`Y1[_+^$O`%#C'O\OP3`P8.('`%/C,`"@ -MTP@`@,(>_R_A`C"@XS`TP.4Q-,#E,C3`Y3,TP.4`,*#C-#2`Y3@TP.4>_R_A -M`#"@XV_R_A`#"@XW@U@.5\-8#EZ#7`Y0`@X.-8)<#E8C7`Y54PX.-E -M-<#E'O\OX2`PD.5``!/C'O\O`68UT.4!`%/A'O\O$6`UT.4"`%/C!P``&@`P -MTN5P)9#E`S""X'`U@.5X-9#E`3"#XG@U@.4>_R_A`##2Y70ED.4#,(+@=#6` -MY7PUD.4!,(/B?#6`Y1[_+^$>_R_A'O\OX4`VT.4!`%/C`#"@$S\VP.4`,*#C -M0S;`Y3(PH.-!-L#E%#"@XT(VP.4>_R_A'O\OX1[_+^$>_R_A'O\OX0`@D.4[ -M/*#C`S"2YP`@H.-$&@+C`2##YT4:`N,!(,/G1AH"XP$@P^<>_R_A'O\OX1[_ -M+^$>_R_A'O\OX1[_+^$>_R_A'O\OX1[_+^$>_R_A``"@XQ[_+^$>_R_A`3"@ -MXUXVP.4`(*#C7";`Y5TFP.5?-L#E'O\OX1!`+>G^___K$("]Z![_+^$>_R_A -M<`#_Y@`P`.,`,$#CMC'3X0,`4.$,``":`#``XP`P0.,!(*#COA+3X0$`4.$' -M``":`2""XG(@[^88,(/B"`!2X_?__QI@`*#C'O\OX0`@H.,`,`#C`#!`XX(0 -M@N"!,8/@L##3X0,`4.$`,*"3#```F@`P`.,`,$#C@A""X($1@^`!,*#CLL#1 -MX0P`4.$$``":`3"#XG,P[^8"$('B#`!3X_?__QJ"((+@`C&#X`$`@^(>_R_A -M'O\OX0$PH.-L-<#E;37`Y1[_+^'P1RWI`*"@X0&`H.$"<*#A`&!3XO"'O0@` -M0*#C!%"@X0"0X.,*`*#A!!"8YPD@H.$$,)?G_O__ZP%0A>($0(3B!@!5X?;_ -M_QKPA[WH$$`MZ0$PH.&&'J#C`RR@X_[__^L0@+WH$$`MZ0!`H.&7,-#E_P!3 -MXP(PH`,Q-,`%"P``"C`DT.4!`%+C!```&B(`4^,`,*"#`3"@DS$TP.4#``#J -M'@!3XP$PH),`,*"#,33`Y3$TU.4P)-3E`P!2X1"`O0@``%/C"```&BXPU.4" -M`%/C!`"@X00<`./_(*#C$S"@`R,PH!/^___K!```Z@0`H.$$'`#C_R"@XS,P -MH./^___K,334Y3`TQ.40@+WH\$'V__\: -M\(>]Z'!`+>D`0*#A`3"@X0)0H.$(&`#C_R,`X_[__^L$`*#A"!@`XP$EH.,! -M,*#C_O__ZQX`H./^___K!`"@X0@8`.,!):#C`#"@X_[__^L$`*#AM!@`XP`@ -MX./^___K<`#_YO[__^L<4$7B``"%X'"`O>CP02WI`$"@X0%0H.$S<-#E*`!7 -MXQE@H!,M8*`#*`!7XQYPH!,R<*`#.#30Y0``4^,9```:=!@`XP`@X./^___K -MH.,`(.#C_O__Z]`!X.=`!(3E!`"@X5P8`.,` -M(.#C_O__ZR`,H.%$!(3E!`"@X70:`.,`(.#C_O__ZU`&X^=(!(3E`3"@XS@T -MQ.4``%7C`3"@$S,TQ!40```:ES#4Y?\`4^,",*`#,S3$!0L```HR)-3E`0!2 -MXP0``!H#`%?A`#"@DP$PH(,S-,3E`P``Z@,`5N$!,*`C`#"@,S,TQ.4S--3E -M,B34Y0,`4N'P@;T(``!3XRL``!HH,)3E"`!3XP0``!H$`*#A=!@`XR`@H.,! -M,*#C_O__ZP0`H.%T&`#C!R>@XP(PH./^___K!`"@X<<>H.,((*#C`#"@X_[_ -M_^L$`*#A7!@`X_\DH.-C,*#C_O__ZP0`H.%T&`#C`RF@XP(PH./^___K!`"@ -MX70:`.,/*J#C`S"@X_[__^L$`*#A&!@`XP$BH.,`,*#C_O__ZP0`H.$8&`#C -M`2*@XP$PH./^___K(```Z@0`H.%T&`#CH.,( -M(*#C0#24Y?[__^L$`*#A7!@`X_\DH.-$-)3E_O__ZP0`H.%T&@#C#RJ@XT@T -ME.7^___K!`"@X1@8`.,!(J#C`#"@X_[__^LH,)3E"`!3XP0``!H$`*#A=!@` -MXR`@H.,`,*#C_O__ZS,TU.4R-,3E\(&]Z!!`+>DH,)#E%``3XQ"`O1@@()#E -M@``2XQ"`O0@?(-#E#``2XQ"`O0@"`%/C!```&BXPT.4"`%/C`0``&O[__^L0 -M@+WH`!"@X_[__^L0@+WH$$`MZ0!`H.'%'J#C?R"@X_[__^L0!,3E(S"@X_PS -MA.4H,*#C`#2$Y1D^H.,$-(3E^C^@XP@TA.4^,*#C%33$Y1XPH.,6-,3E"C"@ -MXQ(TQ.4,,*#C$S3$Y0,PX.,4-,3E`##@XQ@TQ.5\,.#C&33$Y1XPH.,=-,3E -M`#"@XQPTQ.4@-(3E)2"@XR0DQ.4E),3E)C3$Y2CP -M3RWII-!-X@!`H.$!@*#A(,"-XC!?G^4/`+7H#P"LZ`\`M>@/`*SH#P"UZ`\` -MK.@/`)7H#P",Z"@PE.4*`!/CO@,`"B`@E.5``!+CNP,`"@(`4^,.```:!`"@ -MX0@8`.,#*Z#C`S"@X_[__^L$`*#A"!@`XP,JH.,!,*#C_O__ZP0`H.$(&`#C -M`RF@XP`PH./^___K_V\/XP]@0.,$`*#A`!"@XQ@@H.,&,*#A_O__ZQ@`C>4$ -M`*#A`!"@XP$@H.$&,*#A_O__ZQ0`C>4$`*#AAAZ@XP,LH.,",*#C_O__ZPH` -MH./^___K!`"@X8P8`.,`(.#C_O__ZP"PH.$$`*#A"!P`XP`@X./^___K$`"- -MY00`H.%T&`#C`"#@X_[__^L,`(WE!`"@X<4>H.,`(.#C_O__ZP@`C>4@H(WB -M8)"-X@0`H.$*$*#A"2"@X1`PH./^___K!`"@X0@8`.,#*:#C`#"@X_[__^L! -M<*#C`'"-Y00`H.$`$*#C&""@XP8PH.'^___KI%4"X]M?1N,$`*#AYQZ@XP`@ -MX.,%,*#A_O__ZP0`H.%T'@#C`"#@XP4PH.'^___K!`"@X7@>`.,`(.#C!3"@ -MX?[__^L$`*#A?!X`XP`@X.,%,*#A_O__ZP0`H.$Z':#C`"#@XP4PH.'^___K -M!`"@X80>`.,`(.#C!3"@X?[__^L$`*#AB!X`XP`@X.,%,*#A_O__ZP0`H.&, -M'@#C`"#@XP4PH.'^___K!`"@X>T>H.,`(.#C!3"@X?[__^L$`*#AU!X`XP`@ -MX.,%,*#A_O__ZP0`H.'8'@#C`"#@XP4PH.'^___K!`"@X=P>`.,`(.#C!3"@ -MX?[__^L$`*#A[AZ@XP`@X.,%,*#A_O__ZP0`H.'L'@#C`"#@XP4PH.'^___K -M!`"@X5P8`.,`(.#C!3"@X?[__^L$`*#A;!X`XP`@X.,%,*#A_O__ZP0`H.&, -M&`#C`"#@X\`P`./P/$SC_O__ZP0`H.$('`#C`"#@X^0P`.,(,$#C_O__ZP0` -MH.%T&`#C`"#@XP`P".,@,D+C_O__ZP0`H.'C'J#C`"#@XQP\".,`,$'C_O__ -MZP0`H.$Y':#C`"#@XP`\!^,`,4#C_O__ZP0`H.%H&P#C`"#@XP(WH./^___K -M!`"@X6@;`.,`(.#C]C:@X_[__^L$`*#A1!X`XP`@X.,`.`3C`#%`X_[__^L$ -M`*#A-!X`XP`@X.,?/`CC`#!!X_[__^L$`*#A.!X`XP`@X.,(,`#C%3)(X_[_ -M_^L$`*#A/!X`XP`@X.,(,`#C%3A"X_[__^L$`*#A3!X`XP`@X./0.`+C$#!` -MX_[__^L(,`#C!3!`XP`PC>4$`*#A`!"@XP$@H.$&,*#A_O__ZP0`H.$H'@#C -M`"#@XP`P`..`,$CC_O__ZP0`H.%('@#C`"#@XSXSH./^___K^@^@X_[__^L$ -M`*#A#A"@XUH@H./^___K``!0XP!0H"$`4*`S!`"@X0X0H.-:(*#C_O__ZP4` -M4.$%`*`Q'`"-Y00`H.&&'J#C`RR@XP -M`.,`(.#C`#"@X_[__^L$`*#AAAZ@XP,LH.,",*#C_O__ZP0`H.&,&`#C`"#@ -MXPLPH.'^___K!`"@X0@<`.,`(.#C$#"=Y?[__^L$`*#A=!@`XP`@X.,,,)WE -M_O__ZP0`H.'%'J#C?R"@XT`PH./^___K!`"@X<4>H.,`(.#C"#"=Y?[__^L8 -M$)WE`!"-Y00`H.$`$*#C&""@XP8PH.'^___K%""=Y0`@C>4$`*#A`!"@XP$@ -MH.$&,*#A_O__ZP0`H.$*$*#A"2"@X1`PH./^___KT*'$X4``H.,`$*#C`"`* -MX`$P"^`#$)+A?P``"A@PE.4#`%/C?```FB@PE.4"`%/C`@``&B@)G^7^___K -M%P``Z@0`4^,"```:&`F?Y?[__^L2``#J"`!3XP(``!H("9_E_O__ZPT``.H0 -M`%/C`@``&O@(G^7^___K"```ZB``4^,"```:Z`B?Y?[__^L#``#J0`!3XP$` -M`!K8")_E_O__Z]0(G^74&)_EERZ@XQPPG>7^___KT*'$X4``H.,`$*#C`"`* -MX`$P"^`#$)+A4@``"A@PE.4#`%/C3P``FB@PE.4"`%/C`@``&G0(G^7^___K -M%P``Z@0`4^,"```:9`B?Y?[__^L2``#J"`!3XP(``!I4")_E_O__ZPT``.H0 -M`%/C`@``&D0(G^7^___K"```ZB``4^,"```:-`B?Y?[__^L#``#J0`!3XP$` -M`!HD")_E_O__ZR@(G^4@&)_EERZ@XP?Y?[__^L2``#J"`!3XP(``!J@!Y_E_O__ZPT``.H0 -M`%/C`@``&I`'G^7^___K"```ZB``4^,"```:@`>?Y?[__^L#``#J0`!3XP$` -M`!IP!Y_E_O__ZW@'G^5L%Y_EERZ@XP4PH.'^___K*#"4Y0@`4^,\`0`:`@!8 -MXW4``!H<()WE8P!2XV```)H!,(+B!P!3X2X``"H`,*#C;37$Y=!AQ.%``*#C -M`!"@XP`@!N`!,`?@`Q"2X;D!``H8,)3E`P!3X[8!`)HH,)3E`@!3XP(``!K8 -M!I_E_O__ZQ<``.H$`%/C`@``&L@&G^7^___K$@``Z@@`4^,"```:N`:?Y?[_ -M_^L-``#J$`!3XP(``!JH!I_E_O__ZP@``.H@`%/C`@``&I@&G^7^___K`P`` -MZD``4^,!```:B`:?Y?[__^N4!I_EA!:?Y?[__^L!`*#CE`$`Z@$PH.-M-<3E -MT&'$X4``H.,`$*#C`"`&X`$P!^`#$)+AB@$`"A@PE.4#`%/CAP$`FB@PE.4" -M`%/C`@``&AP&G^7^___K%P``Z@0`4^,"```:#`:?Y?[__^L2``#J"`!3XP(` -M`!K\!9_E_O__ZPT``.H0`%/C`@``&NP%G^7^___K"```ZB``4^,"```:W`6? -MY?[__^L#``#J0`!3XP$``!K,!9_E_O__Z]P%G^7(%9_E_O__ZP$`H.-E`0#J -MT&'$X4``H.,`$*#C`"`&X`$P!^`#$)+A!P``"A@PE.4#`%/C!```FGP%G^7^ -M___KG`6?Y805G^7^___K``"@XVT%Q.53`0#J``!8XU`!`!ID,$7B$0!3XTT! -M`(H!,(7B'""=Y0(`4^$M```J`#"@XVPUQ.70@<3A0`"@XP`0H.,`(`C@`3`) -MX`,0DN%1```*&#"4Y0,`4^-.``":*#"4Y0(`4^,"```:]`2?Y?[__^L7``#J -M!`!3XP(``!KD!)_E_O__ZQ(``.H(`%/C`@``&M0$G^7^___K#0``ZA``4^," -M```:Q`2?Y?[__^L(``#J(`!3XP(``!JT!)_E_O__ZP,``.I``%/C`0``&J0$ -MG^7^___KO`2?Y:`4G^7^___K+```Z@$PH.-L-<3ET('$X4``H.,`$*#C`"`( -MX`$P">`#$)+A(P``"A@PE.4#`%/C(```FB@PE.4"`%/C`@``&CP$G^7^___K -M%P``Z@0`4^,"```:+`2?Y?[__^L2``#J"`!3XP(``!H('`%7A+@``*@`PH.-M-<3ET&'$ -MX4``H.,`$*#C`"`&X`$P!^`#$)+AX@``"A@PE.4#`%/CWP``FB@PE.4"`%/C -M`@``&GP#G^7^___K%P``Z@0`4^,"```:;`.?Y?[__^L2``#J"`!3XP(``!I< -M`Y_E_O__ZPT``.H0`%/C`@``&DP#G^7^___K"```ZB``4^,"```:/`.?Y?[_ -M_^L#``#J0`!3XP$``!HL`Y_E_O__ZTP#G^4H$Y_E_O__ZP$`H..]``#J`3"@ -MXVTUQ.708<3A0`"@XP`0H.,`(`;@`3`'X`,0DN&S```*&#"4Y0,`4^.P``": -M*#"4Y0(`4^,"```:P`*?Y?[__^L7``#J!`!3XP(``!JP`I_E_O__ZQ(``.H( -M`%/C`@``&J`"G^7^___K#0``ZA``4^,"```:D`*?Y?[__^L(``#J(`!3XP(` -M`!J``I_E_O__ZP,``.I``%/C`0``&G`"G^7^___KE`*?Y6P2G^7^___K`0"@ -MXXX``.H"`%/CBP``&AP@G>5C`%+C=```F@(P@N('`%/A-```*@`PH.-L-<3E -M`3"@XVTUQ.4$`*#AAAZ@XP,LH./^___KT&'$X4``H.,`$*#C`"`&X`$P!^`# -M$)+A=@``"A@PE.4#`%/C4"`%?A`0"@(VP%Q"5M -M!<0E2@``*@$PH.-L-<3E`#"@XVTUQ.4$`*#AAAZ@XP,LH.,",*#C_O__Z]!A -MQ.%``*#C`!"@XP`@!N`!,`?@`Q"2X3D```H8,)3E`P!3XS8``)HH,)3E`@!3 -MXP(``!K8`)_E_O__ZQ<``.H$`%/C`@``&L@`G^7^___K$@``Z@@`4^,"```: -MN`"?Y?[__^L-``#J$`!3XP(``!JH`)_E_O__ZP@``.H@`%/C`@``&I@`G^7^ -M___K`P``ZD``4^,!```:B`"?Y?[__^N4`)_EA!"?Y?[__^L!`*#C%```ZM!A -MQ.%``*#C`!"@XP`@!N`!,`?@`Q"2X0<```H8,)3E`P!3XP0``)HP`)_E_O__ -MZU@`G^5`$)_E_O__ZP$PH.-L-<3E``"@XVT%Q.4```#J`0"@XZ30C>+PC[WH -MD`0*#A`7"@X0*@ -MH.$#4*#A06;0Y4*&T.4`,-/E`P!3XP/QGY<+``#J5%8#`%16`P#L50,`^%4# -M``5@AN)V8._F%@``Z@5@AN)V8._F!8"(XGB`[^81``#J````XP``0.,`$`#C -M`!!`X_[__^L8D9_E````XP``0.,`$`#C`!!`XPD@H.%M/0#C_O__ZP```.,` -M`$#C"1"@X0`@U>7^___K!P!6X0%@H+,"``"Z"`!7X0)@H,,#8*#3`##5Y0`` -M6N,&`%,!``"@`_"'O0C0@<3A`@"@XP`0H.,`(`C@`3`)X`,0DN$E```*&#"4 -MY0,`4^,B``":*#"4Y0(`4^,"```:B`"?Y?[__^L7``#J!`!3XP(``!IX`)_E -M_O__ZQ(``.H(`%/C`@``&F@`G^7^___K#0``ZA``4^,"```:6`"?Y?[__^L( -M``#J(`!3XP(``!I(`)_E_O__ZP,``.I``%/C`0``&C@`G^7^___K-`"?Y100 -MG^4`(-7E!C"@X?[__^L`8,7E`0"@X_"'O>C0%0``;`D``'@)``"$"0``E`D` -M`*0)``"P"0``!`P``-!`+>D`0*#A(#"0Y0@`$^/0@+T(*#"0Y2``4^.L`0`* -M`QN@XP(AH.,!,*#C_O__ZP0`H.$-'*#C`B&@XP$PH./^___K!`"@X<\>H.,` -M(.#C_O__ZW`P_^8`-83E(`B@X00%A.4$`*#AVAZ@XP`@X./^___K<##_Y@@U -MA.4@"*#AY`2$Y00`H.&D'0#C`"#@X_[__^MP,/_FZ#2$Y2`(H.'L!(3E!`"@ -MX:@=`.,`(.#C_O__ZW``_^;P!(3EZ"24Y>0TE.4#,(+@["24Y0(P@^``)93E -M`C"#X`0EE.4",(/@``"#X/0$A.4H,)3E$`!3XP<``!H$`*#AQ!@`XP`@X./^ -M___K<##_YA@UA.4@"*#A%`6$Y00`H.$L&@#C`2J@XP$PH./^___K!`"@X2P: -M`.,!*:#C`3"@X_[__^L$`*#A7!H`X_\@H./^___K^`2$Y00`H.%8&@#C_R2@ -MX_[__^L`#*#A^#24Y2`(@^#X!(3E!`"@X:8>H.,`(.#C_O__ZU`TY^<`#*#A -M(`B#X0P%A.4$)93E`#64Y0,P@N#D))3E`C"#X.@DE.4",(/@["24Y0(P@^#P -M))3E`C"#X/@DE.4",(/@_#2$Y0@UE.4#`(#@$`6$Y2@PE.4'`%/C,0``F@0` -MH.$,'`#C`B&@XP$PH./^___K!`"@X0P<`.,"(:#C`#"@X_[__^L$`*#A#1R@ -MXP(CH.,!,*#C_O__ZP0`H.$-'*#C`B.@XP`PH./^___K!`"@X0,;H.,"(:#C -M`#"@X_[__^L$`*#A#1R@XP(AH.,`,*#C_O__ZP0`H.$L&@#C`RJ@XP`PH./^ -M___K!`"@X2P:`.,#*J#C`C"@X_[__^L$`*#A+!H`XP,IH.,`,*#C_O__ZP0` -MH.$L&@#C`RF@XP(PH./^___KT&'$X0@`H.,`$*#C`"`&X`$P!^`#$)+AT("] -M"!@PE.4#`%/CT("]F"@PE.4"`%/C`@``&DP$G^7^___K%P``Z@0`4^,"```: -M/`2?Y?[__^L2``#J"`!3XP(``!HL!)_E_O__ZPT``.H0`%/C`@``&AP$G^7^ -M___K"```ZB``4^,"```:#`2?Y?[__^L#``#J0`!3XP$``!K\`Y_E_O__Z_@# -MG^7X$Y_E_O__Z]!AQ.$(`*#C`!"@XP`@!N`!,`?@`Q"2X="`O0@8,)3E`P!3 -MX]"`O9@H,)3E`@!3XP(``!J@`Y_E_O__ZQ<``.H$`%/C`@``&I`#G^7^___K -M$@``Z@@`4^,"```:@`.?Y?[__^L-``#J$`!3XP(``!IP`Y_E_O__ZP@``.H@ -M`%/C`@``&F`#G^7^___K`P``ZD``4^,!```:4`.?Y?[__^M4`Y_E3!.?Y0`E -ME.4$-93E_O__Z]!AQ.$(`*#C`!"@XP`@!N`!,`?@`Q"2X="`O0@8,)3E`P!3 -MX]"`O9@H,)3E`@!3XP(``!KL`I_E_O__ZQ<``.H$`%/C`@``&MP"G^7^___K -M$@``Z@@`4^,"```:S`*?Y?[__^L-``#J$`!3XP(``!J\`I_E_O__ZP@``.H@ -M`%/C`@``&JP"G^7^___K`P``ZD``4^,!```:G`*?Y?[__^ND`I_EF!*?Y>0D -ME.7H-)3E_O__Z]!AQ.$(`*#C`!"@XP`@!N`!,`?@`Q"2X="`O0@8,)3E`P!3 -MX]"`O9@H,)3E`@!3XP(``!HX`I_E_O__ZQ<``.H$`%/C`@``&B@"G^7^___K -M$@``Z@@`4^,"```:&`*?Y?[__^L-``#J$`!3XP(``!H(`I_E_O__ZP@``.H@ -M`%/C`@``&O@!G^7^___K`P``ZD``4^,!```:Z`&?Y?[__^OT`9_EY!&?Y>PD -ME.7P-)3E_O__Z]!AQ.$(`*#C`!"@XP`@!N`!,`?@`Q"2X="`O0@8,)3E`P!3 -MX]"`O9@H,)3E`@!3XP(``!J$`9_E_O__ZQ<``.H$`%/C`@``&G0!G^7^___K -M$@``Z@@`4^,"```:9`&?Y?[__^L-``#J$`!3XP(``!I4`9_E_O__ZP@``.H@ -M`%/C`@``&D0!G^7^___K`P``ZD``4^,!```:-`&?Y?[__^M$`9_E,!&?Y?@D -ME.7^___KT&'$X0@`H.,`$*#C`"`&X`$P!^`#$)+AT("]"!@PE.4#`%/CT("] -MF"@PE.4"`%/C`@``&M0`G^7^___K%P``Z@0`4^,"```:Q`"?Y?[__^L2``#J -M"`!3XP(``!JT`)_E_O__ZPT``.H0`%/C`@``&J0`G^7^___K"```ZB``4^," -M```:E`"?Y?[__^L#``#J0`!3XP$``!J$`)_E_O__ZY@`G^6`$)_E_"24Y?[_ -M_^O0@+WH2!\`X_\O#^/^___K]`2$Y00`H.%<&@#C_R\/X_[__^OX!(3E]#24 -MY0,`@.#\!(3E!`"@X5@;`.,!(*#C`C"@X?[__^L$`*#A6!L`XP$@H.,`,*#C -M_O__Z]"`O>AL"0``>`D``(0)``"4"0``I`D``+`)```@#```Y!4``%`,``"` -M#```L`P``-P,``#T#```<$`MZ0!`H.$!4*#A$#30Y0$`4^&H```*'S#0Y0P` -M$^,:```**#"0Y2``4^,-```*`6"@X<4>H.-_(*#C!3"@X?[__^LH,)3E$`!3 -MXW$```H$`*#A6!P`XW\@H.,%,*#A_O__ZVL``.K%'J#C`"#@XP4PH.'^___K -M!`"@X>4>H.,`(.#C!3"@X?[__^MA``#J`P`3XU\```J(,)#E`##3Y0$`4^,> -M```*`@``.@(`4^-8```:.```ZB@PD.4@`%/C#0``"@%@H.'%'J#C?R"@XP4P -MH.'^___K*#"4Y1``4^-,```*!`"@X5@<`.-_(*#C!3"@X?[__^M&``#JQ1Z@ -MXP`@X.,%,*#A_O__ZP0`H.'E'J#C`"#@XP4PH.'^___K/```ZB@PD.4@`%/C -M#@``"L4>H.-_(*#C!3"@X?[__^LH,)3E$`!3XS(```H%`*#A_O__ZP`PH.$$ -M`*#A6!P`XW\@H./^___K*@``ZL4>H.,`(.#C!3"@X?[__^L%`*#A_O__ZP`P -MH.$$`*#AY1Z@XP`@X./^___K'@``ZB@PD.4@`%/C#P``"@$`H.'^___K`#"@ -MX00`H.'%'J#C?R"@X_[__^LH,)3E$`!3XQ$```H$`*#A6!P`XW\@H.,%,*#A -M_O__ZPL``.H!`*#A_O__ZP`PH.$$`*#AQ1Z@XP`@X./^___K!`"@X>4>H.,` -M(.#C!3"@X?[__^L0,)3E`0`3XR0```H8,)3E`P!3XR$``)HH,)3E`@!3XP(` -M`!H<`9_E_O__ZQ<``.H$`%/C`@``&@P!G^7^___K$@``Z@@`4^,"```:_`"? -MY?[__^L-``#J$`!3XP(``!KL`)_E_O__ZP@``.H@`%/C`@``&MP`G^7^___K -M`P``ZD``4^,!```:S`"?Y?[__^O(`)_ER!"?Y04@H.'^___K$%3$Y1`PE.4! -M`!/C<("]"!@PE.4#`%/C<("]F"@PE.4"`%/C`@``&G@`G^7^___K%P``Z@0` -M4^,"```::`"?Y?[__^L2``#J"`!3XP(``!I8`)_E_O__ZPT``.H0`%/C`@`` -M&D@`G^7^___K"```ZB``4^,"```:.`"?Y?[__^L#``#J0`!3XP$``!HH`)_E -M_O__ZRP`G^4D$)_E!2"@X?[__^MP@+WH;`D``'@)``"$"0``E`D``*0)``"P -M"0``$`T```06```L#0``\$TMZ0!`H.$05-#E$#"0Y0$`$^,C```*&#"0Y0,` -M4^,@``":*#"0Y0(`4^,"```:G`V?Y?[__^L7``#J!`!3XP(``!J,#9_E_O__ -MZQ(``.H(`%/C`@``&GP-G^7^___K#0``ZA``4^,"```:;`V?Y?[__^L(``#J -M(`!3XP(``!I<#9_E_O__ZP,``.I``%/C`0``&DP-G^7^___K2`V?Y4@=G^7^ -M___K(#"4Y0DP`^()`%/C)P``"A`PE.4!`!/C\(V]"!@PE.4#`%/C\(V]F"@P -ME.4"`%/C`@``&O`,G^7^___K%P``Z@0`4^,"```:X`R?Y?[__^L2``#J"`!3 -MXP(``!K0#)_E_O__ZPT``.H0`%/C`@``&L`,G^7^___K"```ZB``4^,"```: -ML`R?Y?[__^L#``#J0`!3XP$``!J@#)_E_O__ZZ0,G^6<')_E_O__Z_"-O>B` -M,)3E`##3Y0``4^,G```*$#"4Y0$`$^/PC;T(&#"4Y0,`4^/PC;V8*#"4Y0(` -M4^,"```:0`R?Y?[__^L7``#J!`!3XP(``!HP#)_E_O__ZQ(``.H(`%/C`@`` -M&B`,G^7^___K#0``ZA``4^,"```:$`R?Y?[__^L(``#J(`!3XP(``!H`#)_E -M_O__ZP,``.I``%/C`0``&O`+G^7^___K^`N?Y>P;G^7^___K\(V]Z#XVU.4` -M`%/C)P``&A`PE.4!`!/C\(V]"!@PE.4#`%/C\(V]F"@PE.4"`%/C`@``&I0+ -MG^7^___K%P``Z@0`4^,"```:A`N?Y?[__^L2``#J"`!3XP(``!IT"Y_E_O__ -MZPT``.H0`%/C`@``&F0+G^7^___K"```ZB``4^,"```:5`N?Y?[__^L#``#J -M0`!3XP$``!I$"Y_E_O__ZU`+G^5`&Y_E_O__Z_"-O>@H,)3E!`!3XS,``!I$ -M()3E`"#2Y0$`4N,7```:<""4Y0`@TN4``%+C"0``"B1DU.66(-3E``!2XP"` -MH`,"```*)H34Y0&`>.(`@*`S>(#OYCL``.HE9-3EEB#4Y0``4N,`@*`#`@`` -M"B>$U.4!@'CB`("@,WB`[^8Q``#J5""4Y0`@TN4"`%+C"0``&B1DU.66(-3E -M``!2XP"`H`,"```*)H34Y0&`>.(`@*`S>(#OYA(``.HE9-3EEB#4Y0``4N,` -M@*`#`@``"B>$U.4!@'CB`("@,WB`[^8(``#J)&34Y98@U.4``%+C`("@`P(` -M``HFA-3E`8!XX@"`H#-X@._F"@`3XPX```HO(-3E`0!2XP(```HP(-3E``!2 -MXP@```H?(-3E`P`2XRYPH`-"`*`#1B"@`S!PH!-"`*`3`""@$0<``.H?(-3E -M`P`2XQYPH`,R`*`#/B"@`R!PH!,R`*`3`""@$980U.4``%'CBP``"@@`4^,+ -M```:ER#4Y0HP@N(^`%/C/C"@PQ4TQ,6N``#*'0!3XQXPH-,5-,35"B""PA4D -MQ,6H``#JEQ#4Y10P@>("`%/A%23$Q0,``,H'`%/A%73$M100@:(5%,2EFC#4 -MY0``4^-6```*EV#4Y08`5^$'8*"!`0``B@8`4.$`8*`Q$#"4Y0$`$^.3```* -M&#"4Y0,`4^.0``":*#"4Y0(`4^,"```:!`F?Y?[__^L7``#J!`!3XP(``!KT -M")_E_O__ZQ(``.H(`%/C`@``&N0(G^7^___K#0``ZA``4^,"```:U`B?Y?[_ -M_^L(``#J(`!3XP(``!K$")_E_O__ZP,``.I``%/C`0``&K0(G^7^___KQ`B? -MY;`8G^4&(*#A_O__ZQ`PE.4!`!/C:P``"A@PE.4#`%/C:```FB@PE.4"`%/C -M`@``&F0(G^7^___K%P``Z@0`4^,"```:5`B?Y?[__^L2``#J"`!3XP(``!I$ -M")_E_O__ZPT``.H0`%/C`@``&C0(G^7^___K"```ZB``4^,"```:)`B?Y?[_ -M_^L#``#J0`!3XP$``!H4")_E_O__ZR@(G^40&)_EER#4Y?[__^M%``#J*#"4 -MY1``4^-"```:(#"4Y4``$^,_```*/##4Y0$`4^,\```:*&34Y="AQ.%``*#C -M`!"@XP`@"N`!,`O@`Q"2X30```H8,)3E`P!3XS$``)J@!Y_E_O__Z\`'G^6D -M%Y_E*"24Y?[__^LJ``#J%23$Y1`PE.4!`!/C)0``"A@PE.4#`%/C(@``FB@P -ME.4"`%/C`@``&E`'G^7^___K%P``Z@0`4^,"```:0`>?Y?[__^L2``#J"`!3 -MXP(``!HP!Y_E_O__ZPT``.H0`%/C`@``&B`'G^7^___K"```ZB``4^,"```: -M$`>?Y?[__^L#``#J0`!3XP$``!H`!Y_E_O__ZQP'G^7\%I_E_O__ZP=@H.$` -M``#J!V"@X?PDE.40-P+C`P!2X3L``)H0,)3E`0`3XR,```H8,)3E`P!3XR`` -M`)HH,)3E`@!3XP(``!J8!I_E_O__ZQ<``.H$`%/C`@``&H@&G^7^___K$@`` -MZ@@`4^,"```:>`:?Y?[__^L-``#J$`!3XP(``!IH!I_E_O__ZP@``.H@`%/C -M`@``&E@&G^7^___K`P``ZD``4^,!```:2`:?Y?[__^MH!I_E1!:?Y?[__^L< -M)-3E`2""XG(@[^8<),3E'334Y0,`5>$=5,2%`3"@@QPTQ(4>``"*`@!2XQP` -M`)H5)-3E`1"#X@(`4>$6),3%`3"#TA8TQ-7A/J#C(#2$Y1,``.H@-)3E``!3 -MXP$P0Q(@-(05#@``&APTU.4``%/C"```&ATTU.4!($/B!@!2X1UDQ+469,2U -M`2!#HATDQ*46-,2E`@``Z@,`4^,`,*`#'#3$!98PU.4``%/C;@``"A`PE.4! -M`!/C(P``"A@PE.4#`%/C(```FB@PE.4"`%/C`@``&DP%G^7^___K%P``Z@0` -M4^,"```:/`6?Y?[__^L2``#J"`!3XP(``!HL!9_E_O__ZPT``.H0`%/C`@`` -M&AP%G^7^___K"```ZB``4^,"```:#`6?Y?[__^L#``#J0`!3XP$``!K\!)_E -M_O__ZR`%G^7X%)_E_O__ZP``6.,H```*EU#4Y1`PE.4!`!/C(@$`"A@PE.4# -M`%/C)@$`FB@PE.4"`%/C`@``&J0$G^7^___K%P``Z@0`4^,"```:E`2?Y?[_ -M_^L2``#J"`!3XP(``!J$!)_E_O__ZPT``.H0`%/C`@``&G0$G^7^___K"``` -MZB``4^,"```:9`2?Y?[__^L#``#J0`!3XP$``!I4!)_E_O__ZWP$G^50%)_E -M_O__ZU```.HH,)3E!`!3XPP``!K\-)3E!@Q3XP)0A8)U4.^&2```B@$+4^,! -M4(6"=5#OAD0``(K_`%/C`5!%DG50[Y9```#J_#24Y0$+4^,"4(6"=5#OACL` -M`(H##%/C`5"%@G50[X8W``"*`@Q3XP%013)U4.\V,P``ZA`PE.4!`!/C(P`` -M"A@PE.4#`%/C(```FB@PE.4"`%/C`@``&I`#G^7^___K%P``Z@0`4^,"```: -M@`.?Y?[__^L2``#J"`!3XP(``!IP`Y_E_O__ZPT``.H0`%/C`@``&F`#G^7^ -M___K"```ZB``4^,"```:4`.?Y?[__^L#``#J0`!3XP$``!I``Y_E_O__ZVP# -MG^4\$Y_E_O__Z_PTE.40)P+C`@!3X0)0A8)U4.^&!@``BGT-4^,!4(6"=5#O -MA@(``(I]#U/C`5!%,G50[S80,)3E`0`3XZD```H8,)3E`P!3XZT``)HH,)3E -M`@!3XP(``!K``I_E_O__ZQ<``.H$`%/C`@``&K`"G^7^___K$@``Z@@`4^," -M```:H`*?Y?[__^L-``#J$`!3XP(``!J0`I_E_O__ZP@``.H@`%/C`@``&H`" -MG^7^___K`P``ZD``4^,!```:<`*?Y?[__^N@`I_E;!*?Y?[__^L5)-3E%C34 -MY0(`5>$"4*`A`P!5X0-0H#$0,)3E`0`3XW4```H8,)3E`P!3XW(``)HH,)3E -M`@!3XP(``!H,`I_E_O__ZQ<``.H$`%/C`@``&OP!G^7^___K$@``Z@@`4^," -M```:[`&?Y?[__^L-``#J$`!3XP(``!K<`9_E_O__ZP@``.H@`%/C`@``&LP! -MG^7^___K`P``ZD``4^,!```:O`&?Y?[__^OP`9_EN!&?Y14DU.46--3E_O__ -MZQ`PE.4!`!/C3```"A@PE.4#`%/C20``FB@PE.4"`%/C`@``&F@!G^7^___K -M%P``Z@0`4^,"```:6`&?Y?[__^L2``#J"`!3XP(``!I(`9_E_O__ZPT``.H0 -M`%/C`@``&C@!G^7^___K"```ZB``4^,"```:*`&?Y?[__^L#``#J0`!3XP$` -M`!H8`9_E_O__ZU`!G^44$9_E_"24Y?[__^L0,)3E`0`3XR0```H8,)3E`P!3 -MXR$``)HH,)3E`@!3XP(``!K(`)_E_O__ZQ<``.H$`%/C`@``&K@`G^7^___K -M$@``Z@@`4^,"```:J`"?Y?[__^L-``#J$`!3XP(``!J8`)_E_O__ZP@``.H@ -M`%/C`@``&H@`G^7^___K`P``ZD``4^,!```:>`"?Y?[__^NT`)_E=!"?Y04@ -MH.'^___K!`"@X040H.'^___KEC#4Y28TQ.4D9,3E\(V]Z!4DU.46--3E`@!5 -MX0)0H"$#`%7A`U"@,?'__^H5)-3E%C34Y0(`5>$"4*`A`P!5X0-0H#'J___J -M;`D``'@)``"$"0``E`D``*0)``"P"0``5`T``!06``!H#0``N`T``.0-```0 -M#@``4`X``'@.``"L#@``R`X``/@.```8#P``-`\``%@/``"`#P``Q`\``.0/ -M``#00"WI`$"@X=!AP.$!`:#C`!"@XP`@!N`!,`?@`Q"2X="`O0@8,)3E`P!3 -MX]"`O9@H,)3E`@!3XP(``!HT`Y_E_O__ZQ<``.H$`%/C`@``&B0#G^7^___K -M$@``Z@@`4^,"```:%`.?Y?[__^L-``#J$`!3XP(``!H$`Y_E_O__ZP@``.H@ -M`%/C`@``&O0"G^7^___K`P``ZD``4^,!```:Y`*?Y?[__^O@`I_EX!*?Y?[_ -M_^O08<3A`0&@XP`0H.,`(`;@`3`'X`,0DN'0@+T(&#"4Y0,`4^/0@+V8*#"4 -MY0(`4^,"```:B`*?Y?[__^L7``#J!`!3XP(``!IX`I_E_O__ZQ(``.H(`%/C -M`@``&F@"G^7^___K#0``ZA``4^,"```:6`*?Y?[__^L(``#J(`!3XP(``!I( -M`I_E_O__ZP,``.I``%/C`0``&C@"G^7^___K/`*?Y302G^64(-3E_O__Z]!A -MQ.$!`:#C`!"@XP`@!N`!,`?@`Q"2X="`O0@8,)3E`P!3X]"`O9@H,)3E`@!3 -MXP(``!K8`9_E_O__ZQ<``.H$`%/C`@``&L@!G^7^___K$@``Z@@`4^,"```: -MN`&?Y?[__^L-``#J$`!3XP(``!JH`9_E_O__ZP@``.H@`%/C`@``&I@!G^7^ -M___K`P``ZD``4^,!```:B`&?Y?[__^N0`9_EA!&?Y94@U.7^___KT&'$X0$! -MH.,`$*#C`"`&X`$P!^`#$)+AT("]"!@PE.4#`%/CT("]F"@PE.4"`%/C`@`` -M&B@!G^7^___K%P``Z@0`4^,"```:&`&?Y?[__^L2``#J"`!3XP(``!H(`9_E -M_O__ZPT``.H0`%/C`@``&O@`G^7^___K"```ZB``4^,"```:Z`"?Y?[__^L# -M``#J0`!3XP$``!K8`)_E_O__Z^0`G^74$)_EEB#4Y?[__^O08<3A`0&@XP`0 -MH.,`(`;@`3`'X`,0DN'0@+T(&#"4Y0,`4^/0@+V8*#"4Y0(`4^,"```:>`"? -MY?[__^L7``#J!`!3XP(``!IH`)_E_O__ZQ(``.H(`%/C`@``&E@`G^7^___K -M#0``ZA``4^,"```:2`"?Y?[__^L(``#J(`!3XP(``!HX`)_E_O__ZP,``.I` -M`%/C`0``&B@`G^7^___K.`"?Y200G^67(-3E_O__Z]"`O>AL"0``>`D``(0) -M``"4"0``I`D``+`)```($```'!8``"P0``!$$```7!```'`0``#00"WI`$"@ -MX=!AP.$!`:#C`!"@XP`@!N`!,`?@`Q"2X;@!``H8,)3E`P!3X[4!`)HH,)3E -M`@!3XP(``!J(!Y_E_O__ZQ<``.H$`%/C`@``&G@'G^7^___K$@``Z@@`4^," -M```::`>?Y?[__^L-``#J$`!3XP(``!I8!Y_E_O__ZP@``.H@`%/C`@``&D@' -MG^7^___K`P``ZD``4^,!```:.`>?Y?[__^LT!Y_E-!>?Y?[__^O08<3A`0&@ -MXP`0H.,`(`;@`3`'X`,0DN&-`0`*&#"4Y0,`4^.*`0":*#"4Y0(`4^,"```: -MW`:?Y?[__^L7``#J!`!3XP(``!K,!I_E_O__ZQ(``.H(`%/C`@``&KP&G^7^ -M___K#0``ZA``4^,"```:K`:?Y?[__^L(``#J(`!3XP(``!J?Y?[__^L2``#J"`!3XP(``!KH!Y_E_O__ZPT``.H0`%/C`@`` -M&M@'G^7^___K"```ZB``4^,"```:R`>?Y?[__^L#``#J0`!3XP$``!JX!Y_E -M_O__Z\@'G^6T%Y_E*""4Y?[__^O08<3A`0&@XP`0H.,`(`;@`3`'X`,0DN'0 -M@+T(&#"4Y0,`4^/0@+V8*#"4Y0(`4^,"```:6`>?Y?[__^L7``#J!`!3XP(` -M`!I(!Y_E_O__ZQ(``.H(`%/C`@``&C@'G^7^___K#0``ZA``4^,"```:*`>? -MY?[__^L(``#J(`!3XP(``!H8!Y_E_O__ZP,``.I``%/C`0``&@@'G^7^___K -M'`>?Y007G^4L(-3E_O__Z]!AQ.$!`:#C`!"@XP`@!N`!,`?@`Q"2X="`O0@8 -M,)3E`P!3X]"`O9@H,)3E`@!3XP(``!JH!I_E_O__ZQ<``.H$`%/C`@``&I@& -MG^7^___K$@``Z@@`4^,"```:B`:?Y?[__^L-``#J$`!3XP(``!IX!I_E_O__ -MZP@``.H@`%/C`@``&F@&G^7^___K`P``ZD``4^,!```:6`:?Y?[__^MP!I_E -M5!:?Y2T@U.7^___KT&'$X0$!H.,`$*#C`"`&X`$P!^`#$)+AT("]"!@PE.4# -M`%/CT("]F"@PE.4"`%/C`@``&O@%G^7^___K%P``Z@0`4^,"```:Z`6?Y?[_ -M_^L2``#J"`!3XP(``!K8!9_E_O__ZPT``.H0`%/C`@``&L@%G^7^___K"``` -MZB``4^,"```:N`6?Y?[__^L#``#J0`!3XP$``!JH!9_E_O__Z\0%G^6D%9_E -M+B#4Y?[__^O08<3A`0&@XP`0H.,`(`;@`3`'X`,0DN'0@+T(&#"4Y0,`4^/0 -M@+V8*#"4Y0(`4^,"```:2`6?Y?[__^L7``#J!`!3XP(``!HX!9_E_O__ZQ(` -M`.H(`%/C`@``&B@%G^7^___K#0``ZA``4^,"```:&`6?Y?[__^L(``#J(`!3 -MXP(``!H(!9_E_O__ZP,``.I``%/C`0``&O@$G^7^___K&`6?Y?04G^4O(-3E -M_O__Z]!AQ.$!`:#C`!"@XP`@!N`!,`?@`Q"2X="`O0@8,)3E`P!3X]"`O9@H -M,)3E`@!3XP(``!J8!)_E_O__ZQ<``.H$`%/C`@``&H@$G^7^___K$@``Z@@` -M4^,"```:>`2?Y?[__^L-``#J$`!3XP(``!IH!)_E_O__ZP@``.H@`%/C`@`` -M&E@$G^7^___K`P``ZD``4^,!```:2`2?Y?[__^ML!)_E1!2?Y3`@U.7^___K -MT&'$X0$!H.,`$*#C`"`&X`$P!^`#$)+AT("]"!@PE.4#`%/CT("]F"@PE.4" -M`%/C`@``&N@#G^7^___K%P``Z@0`4^,"```:V`.?Y?[__^L2``#J"`!3XP(` -M`!K(`Y_E_O__ZPT``.H0`%/C`@``&K@#G^7^___K"```ZB``4^,"```:J`.? -MY?[__^L#``#J0`!3XP$``!J8`Y_E_O__Z\`#G^64$Y_E,2#4Y?[__^O08<3A -M`0&@XP`0H.,`(`;@`3`'X`,0DN'0@+T(&#"4Y0,`4^/0@+V8*#"4Y0(`4^," -M```:.`.?Y?[__^L7``#J!`!3XP(``!HH`Y_E_O__ZQ(``.H(`%/C`@``&A@# -MG^7^___K#0``ZA``4^,"```:"`.?Y?[__^L(``#J(`!3XP(``!KX`I_E_O__ -MZP,``.I``%/C`0``&N@"G^7^___K%`.?Y>02G^4R(-3E_O__Z]!AQ.$!`:#C -M`!"@XP`@!N`!,`?@`Q"2X="`O0@8,)3E`P!3X]"`O9@H,)3E`@!3XP(``!J( -M`I_E_O__ZQ<``.H$`%/C`@``&G@"G^7^___K$@``Z@@`4^,"```::`*?Y?[_ -M_^L-``#J$`!3XP(``!I8`I_E_O__ZP@``.H@`%/C`@``&D@"G^7^___K`P`` -MZD``4^,!```:.`*?Y?[__^MH`I_E-!*?Y3,@U.7^___KT&'$X0$!H.,`$*#C -M`"`&X`$P!^`#$)+AT("]"!@PE.4#`%/CT("]F"@PE.4"`%/C`@``&M@!G^7^ -M___K%P``Z@0`4^,"```:R`&?Y?[__^L2``#J"`!3XP(``!JX`9_E_O__ZPT` -M`.H0`%/C`@``&J@!G^7^___K"```ZB``4^,"```:F`&?Y?[__^L#``#J0`!3 -MXP$``!J(`9_E_O__Z[P!G^6$$9_E-"#4Y?[__^O08<3A`0&@XP`0H.,`(`;@ -M`3`'X`,0DN'0@+T(&#"4Y0,`4^/0@+V8*#"4Y0(`4^,"```:*`&?Y?[__^L7 -M``#J!`!3XP(``!H8`9_E_O__ZQ(``.H(`%/C`@``&@@!G^7^___K#0``ZA`` -M4^,"```:^`"?Y?[__^L(``#J(`!3XP(``!KH`)_E_O__ZP,``.I``%/C`0`` -M&M@`G^7^___K$`&?Y=00G^4U(-3E_O__Z]!AQ.$!`:#C`!"@XP`@!N`!,`?@ -M`Q"2X="`O0@8,)3E`P!3X]"`O9@H,)3E`@!3XP(``!IX`)_E_O__ZQ<``.H$ -M`%/C`@``&F@`G^7^___K$@``Z@@`4^,"```:6`"?Y?[__^L-``#J$`!3XP(` -M`!I(`)_E_O__ZP@``.H@`%/C`@``&C@`G^7^___K`P``ZD``4^,!```:*`"? -MY?[__^MD`)_E)!"?Y38@U.7^___KT("]Z&P)``!X"0``A`D``)0)``"D"0`` -ML`D``*01``!,%@``Q!$``.`1``#\$0``&!(``#02``!,$@``9!(``'@2``", -M$@``H!(``+`2``#$$@``V!(``/`2```$$P``^$\MZ0!0H.$`0)#E.SR@XP,P -ME.<"+P+C`B#4YP$`4N-3```*RBO4Y0\`4N-0``"*^!4!XP$0E.<``%'C0@`` -M&E4]H./3@(3A6#4!X]-@A.$(`*#A"1"@X08`4.`'$,'@%CR@X].@A.$8-@'C -MTV"$X0J`H.$+D*#A!H!8X`>0R>`$,$+B$.``"*`0``&@@`4.$+``"*`6"@XPD``.H`8*#C`3&@X2`_ -M@^$``:#A`P!9X0(``(H"```:``!8X0```)H!8*#C\#65Y08`4^$"```:[#75 -MY0``4^,0```:!@!2XP<``!KA-]3E"``3XP0```H`,`#C`#!`XQ(@AN("(9/G -M`@``Z@`P`.,`,$#C!B&3YP0`H.$(%0#C_O__Z_!EA>4!,*#C[#7%Y0D``.KL -M)=#E``!2XP8```H$`*#A"!4`X^PH`N,"()/G_O__ZP`PH./L-<7E`""@X_@U -M`>,#((3G53V@X],`A.%8-0'C\P"$X18\H./3`(3A!X_,`A.'XC[WHT$`M -MZ0!`H.'08<#A`0B@XP`0H.,`(`;@`3`'X`,0DN$C```*&#"4Y0,`4^,@``": -M*#"4Y0(`4^,"```:0`&?Y?[__^L7``#J!`!3XP(``!HP`9_E_O__ZQ(``.H( -M`%/C`@``&B`!G^7^___K#0``ZA``4^,"```:$`&?Y?[__^L(``#J(`!3XP(` -M`!H``9_E_O__ZP,``.I``%/C`0``&O``G^7^___K[`"?Y>P0G^7^___K(#"4 -MY0$($^/0@+T('S#4Y00`4^,!```:!`"@X?[__^O08<3A`0B@XP`0H.,`(`;@ -M`3`'X`,0DN'0@+T(&#"4Y0,`4^/0@+V8*#"4Y0(`4^,"```:=`"?Y?[__^L7 -M``#J!`!3XP(``!ID`)_E_O__ZQ(``.H(`%/C`@``&E0`G^7^___K#0``ZA`` -M4^,"```:1`"?Y?[__^L(``#J(`!3XP(``!HT`)_E_O__ZP,``.I``%/C`0`` -M&B0`G^7^___K*`"?Y2`0G^7^___KT("]Z&P)``!X"0``A`D``)0)``"D"0`` -ML`D``"@3``!D%@``7!,``-!`+>D`0*#A`!"0Y0`PH./L-<#E[37`Y?@E`>," -M,('GT&'`X0$(H.,`$*#C`"`&X`$P!^`#$)+AT("]"!@PE.4#`%/CT("]F"@P -ME.4"`%/C`@``&K@"G^7^___K%P``Z@0`4^,"```:J`*?Y?[__^L2``#J"`!3 -MXP(``!J8`I_E_O__ZPT``.H0`%/C`@``&H@"G^7^___K"```ZB``4^,"```: -M>`*?Y?[__^L#``#J0`!3XP$``!IH`I_E_O__ZP0`H.$%'*#C_O__ZP`@H.%4 -M`I_E5!*?Y?[__^O08<3A`0B@XP`0H.,`(`;@`3`'X`,0DN'0@+T(&#"4Y0,` -M4^/0@+V8*#"4Y0(`4^,"```:_`&?Y?[__^L7``#J!`!3XP(``!KL`9_E_O__ -MZQ(``.H(`%/C`@``&MP!G^7^___K#0``ZA``4^,"```:S`&?Y?[__^L(``#J -M(`!3XP(``!J\`9_E_O__ZP,``.I``%/C`0``&JP!G^7^___K!`"@X005`./^ -M___K`""@X:`!G^68$9_E_O__Z]!AQ.$!"*#C`!"@XP`@!N`!,`?@`Q"2X="` -MO0@8,)3E`P!3X]"`O9@H,)3E`@!3XP(``!I``9_E_O__ZQ<``.H$`%/C`@`` -M&C`!G^7^___K$@``Z@@`4^,"```:(`&?Y?[__^L-``#J$`!3XP(``!H0`9_E -M_O__ZP@``.H@`%/C`@``&@`!G^7^___K`P``ZD``4^,!```:\`"?Y?[__^L$ -M`*#A"!4`X_[__^L`(*#AZ`"?Y=P0G^7^___KT&'$X0$(H.,`$*#C`"`&X`$P -M!^`#$)+AT("]"!@PE.4#`%/CT("]F"@PE.4"`%/C`@``&H0`G^7^___K%P`` -MZ@0`4^,"```:=`"?Y?[__^L2``#J"`!3XP(``!ID`)_E_O__ZPT``.H0`%/C -M`@``&E0`G^7^___K"```ZB``4^,"```:1`"?Y?[__^L#``#J0`!3XP$``!HT -M`)_E_O__ZP0`H.$,%0#C_O__ZP`@H.$P`)_E(!"?Y?[__^O0@+WH;`D``'@) -M``"$"0``E`D``*0)``"P"0``D!,``'@6``"P$P``T!,``/`3``#00"WI`$"@ -MX=!AP.%``*#C`!"@XP`@!N`!,`?@`Q"2X2,```H8,)3E`P!3XR```)HH,)3E -M`@!3XP(``!K\`)_E_O__ZQ<``.H$`%/C`@``&NP`G^7^___K$@``Z@@`4^," -M```:W`"?Y?[__^L-``#J$`!3XP(``!K,`)_E_O__ZP@``.H@`%/C`@``&KP` -MG^7^___K`P``ZD``4^,!```:K`"?Y?[__^NH`)_EJ!"?Y?[__^L`,*#C<#6$ -MY7@UA.5T-83E?#6$Y0(@H.-@)<3E827$Y0`@X.-8)<3E7#6$Y6(`0*#A``"0 -MY2`PE.4!!!/C$```"F`VU.4``%/C"@``&F`PH.,`,(WE!`"@X0`0H.,D(*#C -M_S\/XP\P0./^___K`3"@XV`VQ.4"``#J_O__ZP`PH.-@-L3E"-"-XA"`O>@0 -M0"WI'S#0Y00`4^,0@+T8_O__ZQ"`O>@00"WI`$"@X5L>@.($$('B_O__ZP0` -MH.'E'H3B_O__ZQ"`O>@00"WI6QZ`X@00@>+^___K$("]Z`3@+>4,T$WB`#`` -MXP`P0.,`,(WE6QZ`X@00@>(`(`#C`"!`XP`PH./^___K#-"-X@"`O>CP3RWI -MI-!-X@``D.40`(WE.SR@XP,PD.<4,(WE(`"-X@`0H..`(*#C_O__ZQ``G>5L -M,)#E`0`3XWL```H8,(WB["&?Y0,`DN@$`(/DL!##X?[__^L-$*#A?SW!XS\P -MP^,$()/E`2""X@0@@^40()WE#2N"XA$@@N(`((WE$#"=Y1>\@^((L(OB``"@ -MXP0`C>7_$*#C"!"-Y0P`C>4`D*#A!G"@XQB@C>(NCHGB`8"(XA`@G>6(@8+@ -M`%";Y28``.H(8$7B`%"5Y>!`AN($`*#A"A"@X0<@H.'^___K``!0XQT``!H$ -M`*#A`!"=Y0<@H.'^___K``!0XQ<``!K0,);E`0`3XQ0```H0.);E"`"=Y0,` -M4.$#`*"A"`"-Y0P0G>4#`%'A`Q"@L0P0C>4!`'/C"0``"J``C>($$)WE`2&` -MX-@0EN4#.('A@#`"Y00@G>4!,(+B4(`*#A!1"@X?[__^L``%#C -MT___"@&0B>((L(OB(`!9X\G__QH4<)WE#0"@X7\]P.,_,,/C!""3Y0$@0N($ -M((/E_O__ZP00G>4``%'C$@``VJFMA^(0H(KB`5&@X0!`H.,@8(WB&HH"XP0@ -MEN<``%+C!@``"@@PU^7_`%/C-#H"$P@`G14#`(<7 -M`""@`S0Z`@,#((<'I-"-XO"/O>B@%@``$$`MZ2`PD.40`!/C$("]"!\PT.4$ -M`%/C$("]&/[__^L0@+WH\$`MZ1S03>(`8*#A`7"@X0W`H.$XX)_E#P"^Z`\` -MK.@#`)[H`P",Z`!`H.,-4*#A!@"@X000E><'(*#A_O__ZP1`A.(8`%3C^/__ -M&AS0C>+P@+WHJ!8``'!`+>D`0*#A`5"@X1DTT.4!`%/A`@``"@H:`.,%(*#A -M_O__ZQDTU.48-,3E&53$Y7"`O>@00"WI(#"0Y2@`$^,0@+T(,##0Y0``4^,0 -M@+T8EC#0Y0``4^,+```*ES#0Y1D`4^/-$*"##0``B@LP0^)S,._F#@!3XP8` -M`)KX-)#E^@]3XP,``(H$``#J^#20Y?H/4^,!``":@Q"@XP```.I`$*#C_O__ -MZQ"`O>CP0"WI'-!-X@!0D.4[/*#C`V"5YPW`H.%$X)_E#P"^Z`\`K.@#`)[H -M`P",Z`!`H.,-<*#A!#"&X*D]@^(',(/B!0"@X001E^<`(-/E_O__ZP%`A.(& -M`%3C]?__&AS0C>+P@+WHP!8``/!`+>D+P@+WHV!8``!!`+>D`0*#A -M)!@`XP(LH./^___K'`#$Y00`H.$$'`#C#R"@X_[__^L=`,3E!`"@X?[__^L0 -M@+WH$$`MZ0!`H.'^___K!`"@X?[__^L$`*#A_O__ZP0`H.'^___K!`"@X?[_ -M_^L$`*#A_O__ZP0`H.'^___K!`"@X?[__^L$`*#A_O__ZP0`H.'^___K!`"@ -MX?[__^L$`*#A_O__ZQ"`O>@00"WI`$"@X?[__^L$`*#A_O__ZP0`H.'^___K -M!`"@X?[__^L$`*#A_O__ZP0`H.'^___K!`"@X?[__^L$`*#A_O__ZP0`H.'^ -M___K!`"@X?[__^L$`*#A_O__ZP0`H.'^___K!`"@X?[__^L0@+WH,``MZ4#0 -M3>(`4*#A`$``XP!`0.,$P(WB#P"TZ`\`K.@/`+3H#P"LZ`\`M.@/`*SH!P"4 -MZ`,`K.BR(,S@(BB@X0`@S.4.`%7C$```FA(PW>4%`%/A#C"@`P0```H$((WB -M#S"@XP\0TN4%`%'A`@``&@TP0^)S`._F!0``Z@$P@^)S,._F`2""XCL`4^/T -M__\:``"@XT#0C>(P`+WH'O\OX=!`+>D`0*#A`#"0Y;8QT^$+,$/B#>/O?0SCL(&?Y021 -MH.$)$)CG`3"$X@,AF.?,/0SCS3U,XP,`4>$#``"*"@"@X7(@[^;^___K6P`` -MZ@`@G>4"`%'A*@``"O\P`>($()WE`P`2X0`@H!,!(*`#'P!3XP`PH`,!,`(2 -M``!3XP4``!I1-.?G!P!3XP(``!I1&.?G#P!1XQH```H"((3B`T"$X@0QF.<% -M`%/A!P!3$1(```K-'0SC`0!3X0\```JO`%+C#0``B@`0H.,)D(C@S0T,XP(@ -M@N(!,(G@%#"3Y04`4^$'`%,1!```"@``4^$"```*"!"!XJ\`4N/T__^:`D!" -MXBT``.H"0(3B!!&8YP$PA.(#(9CG!0!2X0<`4A$6```*S3T,XP,`4N$5```* -MKP!4XQ$``(H`8*#C"9"(X`.PH.$*`*#AB8"P``S3T,X\T]3.,#`%#A -M`0"@`Q[_+P'_,`#B`P`1X0`@H!,!(*`#'P!3XP`PH`,!,`(2``!3XP<``!I0 -M-.?G!P!3XP0``!I0".?G#P!0XP``H!,!`*`#'O\OX0``H.,>_R_A\$\MZ0S0 -M3>(`D*#A+S#0Y?\T@^(D(-#E`C2#X!\@T.4"*(/@!""-Y0!`H..M7@WC[WT, -MXX2AG^7-C0SC!"&@X0`@C>4"$)KG`3"$X@,QFN?,+0SCS2U,XP(`4>$#``"* -M"0"@X0`@X./^___K3@``Z@$`H.$$$)WER/__ZP``4.,9```:`B"$X@-`A.($ -M,9KG!0!3X0<`4Q$1```*"`!3X0\```H!`%+C#0``B@`0H.,`,)WE`P"*X`(@ -M@N(!,(#@%#"3Y04`4^$'`%,1!```"@@`4^$"```*"!"!X@$`4N/T__^:`D!" -MXB\``.H"0(3B!!&:YP$PA.(#,9KG!0!3X0<`4Q$8```*"`!3X1@```H!`%3C -M%```B@!@H.,`L.#C`""=Y0(@BN``((WE"0"@X0L@H.'^___K`D"$X@`@G>4& -M,(+@$!"3Y10PD^4%`%/A!P!3$00```H(`%/A!```"@A@AN(!`%3C[___F@4` -M4^$-```*`0!4XPL``(H$,*#A`""@XP1!BN`",(/B`A"$X`P0D>4%`%'A`@`` -M"@@@@N(!`%/C]___F@-`H.$"0(3B`P!4XZ#__YH,T(WB\(^]Z&`.``#P3RWI -M#-!-X@"0H.$O,-#E_S2#XB0@T.4"-(/@'R#0Y0(H@^`$((WE`$"@XYRAG^6M -M7@WC[XT,XWEA`.,$(:#A`""-Y0(0FN57___K``!0XQL``!H"((3B`T"$ -MX@0QFN<%`%/A"`!3$1,```K-'0SC`0!3X1````H&`%+A#@``B@`0H.,`,)WE -M`P"*X,W-#.,"((+B`3"`X!0PD^4%`%/A"`!3$00```H,`%/A`@``"@@0@>(& -M`%+A]/__F@)`0N(Q``#J`D"$X@01FN4)`*#A"R"@ -MX?[__^L"0(3B`""=Y04%`%'A`@``"@@@@N(&`%/A]___F@-`H.$"0(3B7P]4XYS_ -M_SH,T(WB\(^]Z'`.``#P3RWI#-!-X@"0H.$O,-#E_S2#XB0@T.4"-(/@'R#0 -MY0(H@^`$((WE`$"@XXRAG^6M7@WC[WT,X\V-#.,$(:#A`""-Y0(0FN7B -M_O_K``!0XQD``!H"((3B`T"$X@0QFN<%`%/A!P!3$1$```H(`%/A#P``"OT` -M4N,-``"*`!"@XP`PG>4#`(K@`B""X@$P@.`4,)/E!0!3X0<`4Q$$```*"`!3 -MX0(```H($('B_0!2X_3__YH"0$+B+P``Z@)`A.($$9KG`3"$X@,QFN<%`%/A -M!P!3$1@```H(`%/A&```"OT`5.,4``"*`&"@XP"PX.,`()WE`B"*X``@C>4) -M`*#A"R"@X?[__^L"0(3B`""=Y08P@N`0$)/E%#"3Y04`4^$'`%,1!```"@@` -M4^$$```*"&"&XOT`5./O__^:!0!3X0T```K]`%3C"P``B@0PH.$`(*#C!$&* -MX`(P@^("$(3@#!"1Y04`4>$"```*""""XOT`4^/W__^:`T"@X0)`A.+_`%3C -MH/__F@S0C>+PC[WH8!0``/!/+>D,T$WB`*"@X2\PT.7_-(/B)"#0Y0(T@^`? -M(-#E`BB#X`0@C>4`0*#CS2T,X\TM3.,`((WEK5X-X^]]#..H@9_E!)&@X0D0 -MF.,:```*`B"$X@-`A.($,9CG!0!3X0<`4Q$2 -M```*S1T,XP$`4^$/```*PP!2XPT``(H`$*#C"9"(X,T-#.,"((+B`3")X!0P -MD^4%`%/A!P!3$00```H``%/A`@``"@@0@>+#`%+C]/__F@)`0N(L``#J`D"$ -MX@01F.A@&````0"@XQ[_+^$>_R_A<$,MZ0%0H.$"8*#A -M.SR@XP-`D.=@.@+CTX"$X0$#H.,`$*#C`"`(X`$P">`#$)+A<(.]"&@Z`N,# -M,)3G`P!3XW"#O9AX.@+C`S"4YP(`4^,"```:2`&?Y?[__^L7``#J!`!3XP(` -M`!HX`9_E_O__ZQ(``.H(`%/C`@``&B@!G^7^___K#0``ZA``4^,"```:&`&? -MY?[__^L(``#J(`!3XP(``!H(`9_E_O__ZP,``.I``%/C`0``&O@`G^7^___K -M]`"?Y?00G^4%(*#A_O__ZV`Z`N/3@(3A`0.@XP`0H.,`(`C@`3`)X`,0DN%P -M@[T(:#H"XP,PE.<#`%/C<(.]F'@Z`N,#,)3G`@!3XP(``!J,`)_E_O__ZQ<` -M`.H$`%/C`@``&GP`G^7^___K$@``Z@@`4^,"```:;`"?Y?[__^L-``#J$`!3 -MXP(``!I<`)_E_O__ZP@``.H@`%/C`@``&DP`G^7^___K`P``ZD``4^,!```: -M/`"?Y?[__^L``%;C`"``XP`@0.,`,`#C`#!`XP,@H`$H`)_E(!"?Y?[__^MP -M@[WHW!0``.@4``#T%```!!4``!05```@%0``+!4``-10``!H%0``\$\MZ3S0 -M3>(4$(WE&""-Y1PPC>4[/*#C`X"0YP`P`.,`,$#CN#'3X;0SS>$`,)CE`3!# -MX@$`4^,%``"*$#"8Y0(`4^,!`*`#(`"-!0B0H`,"```*`!"@XR`0C>4$D*#C -M8#H"X]-`B.$!`Z#C`!"@XP`@!.`!,`7@`P"2X2<```IH.@+C`S"8YP,`4^,C -M``":>#H"XP,PF.<"`%/C`@``&@@$G^7^___K%P``Z@0`4^,"```:^`.?Y?[_ -M_^L2``#J"`!3XP(``!KH`Y_E_O__ZPT``.H0`%/C`@``&M@#G^7^___K"``` -MZB``4^,"```:R`.?Y?[__^L#``#J0`!3XP$``!JX`Y_E_O__Z[0#G^6T$Y_E -M&""=Y1PPG>7^___K``!9XP"@H`-N```*%!"=Y1@@G>6"`` -M4*#C`6"@XP6@H.$%0*#A`#``XP`P0.,D,(WE`#``XP`P0.,H,(WE`#``XP`P -M0.,L,(WE!3"7YP4@F^<"`%/A`S!BP`(P8]`%`%/C4```FF`Z`N/3`(CA`""@ -MX0$PH.$!`Z#C`!"@XP`@`N`!,`/@`Q"2X2D```IH.@+C`S"8YP,`4^,E``": -M>#H"XP,PF.<"`%/C`@``&M`"G^7^___K%P``Z@0`4^,"```:P`*?Y?[__^L2 -M``#J"`!3XP(``!JP`I_E_O__ZPT``.H0`%/C`@``&J`"G^7^___K"```ZB`` -M4^,"```:+`"=Y?[__^L#``#J0`!3XP$``!HH`)WE_O__ZP4PF^<`,(WE)`"= -MY702G^4$(*#A!3"7Y_[__^L&`%3C`@!4$Q<``!H``%KC%0``&@8QH.$#$)?G -M!2"7YP(@@>```%+C!```&C@@C>(D,8+@'`"=Y00`0^4,``#J`R";YP4PF^<# -M,(+@``!3XS@0C0(D,8$`&""=!00@0P4!,*`3$Z2*$0$``.H!,*#C$Z2*X0%` -MA.(!8(;B!%"%X@D`5.&B__\:8#H"X]-`B.$!`Z#C`!"@XP`@!.`!,`7@`P"2 -MX28```IH.@+C`S"8YP,`4^,B``":>#H"XP,PF.<"`%/C`@``&H`!G^7^___K -M%P``Z@0`4^,"```:<`&?Y?[__^L2``#J"`!3XP(``!I@`9_E_O__ZPT``.H0 -M`%/C`@``&E`!G^7^___K"```ZB``4^,"```:0`&?Y?[__^L#``#J0`!3XP$` -M`!HP`9_E_O__ZS0!G^4L$9_E"B"@X?[__^L``%KC'@``&BF1L.$!`*`#.P`` -M"@+`H.,!`*#C`$"@XS10C>($8*#A%'"=Y000U>?_`%'C#0``"@0QH.$,`%/A -M"0``*H$2A^`#(:#A`A"!X`(@A^`$`)'D8`""Y0$P@^($((+B`P!48()WE@@*!X`$@ -MH.$`,*#C`Q"0YV`0@N4$,(/B!"""XA``4^/Y__\:$```ZO``&N,@`)WE`#"@ -M$P$P``(``%/C"@``"A00G>48,)WE@R*!X`$PH.$0`('B$!"2Y7`0@^4$((+B -M!#"#X@``4^'Y__\:``"@XSS0C>+PC[WHW!0``.@4``#T%```!!4``!05```@ -M%0``B!4``/!0```H%@``\$-G```:T('`X0$$ -MH.,`$*#C`"`(X`$P">`#$)+A)0``"A@PE>4#`%/C(@``FB@PE>4"`%/C`@`` -M&H0"G^7^___K%P``Z@0`4^,"```:=`*?Y?[__^L2``#J"`!3XP(``!ID`I_E -M_O__ZPT``.H0`%/C`@``&E0"G^7^___K"```ZB``4^,"```:1`*?Y?[__^L# -M``#J0`!3XP$``!HT`I_E_O__ZS`"G^4P$I_EX"W5Y>,]U>7^___KX"W5Y>(] -MU>4#`%+A`3"@DP`PQI7B3=65X#W5E0(PH(,`,,:%X$W5A>(]U84$0&/@=$#O -MYM"!Q>$!!*#C`!"@XP`@".`!,`G@`Q"2X6,```H8,)7E`P!3XV```)HH,)7E -M`@!3XP(``!J<`9_E_O__ZQ<``.H$`%/C`@``&HP!G^7^___K$@``Z@@`4^," -M```:?`&?Y?[__^L-``#J$`!3XP(``!IL`9_E_O__ZP@``.H@`%/C`@``&EP! -MG^7^___K`P``ZD``4^,!```:3`&?Y?[__^M(`9_E2!&?Y>`MU>7C/=7E_O__ -MZSP``.H!`%'C`$"@$SX``!K0@<#A`02@XP`0H.,`(`C@`3`)X`,0DN$E```* -M&#"5Y0,`4^,B``":*#"5Y0(`4^,"```:V`"?Y?[__^L7``#J!`!3XP(``!K( -M`)_E_O__ZQ(``.H(`%/C`@``&K@`G^7^___K#0``ZA``4^,"```:J`"?Y?[_ -M_^L(``#J(`!3XP(``!J8`)_E_O__ZP,``.I``%/C`0``&H@`G^7^___KC`"? -MY800G^7D+=7EYCW5Y?[__^OD+=7EYCW5Y0,`4N$!,*"3`##&E>9-U97D/=65 -M`C"@@P`PQH7D3=6%YCW5A01`8^!T0._F!0!4XP(``)H`,-;E`0!3XP9`H`,$ -M.*#A!#2#X00P@^$$3(/A`$"'Y?"'O>C<%```Z!0``/04```$%0``%!4``"`5 -M``!L%@``#%$``)P6``!P3RWI`6"@X0)0H.$[/*#C`S"0YZE-@^(00(3B8"H" -MX]*@@^$!@Z#C`)"@XP@`"N`)$`O@`2"0X24```IH*@+C`B"3YP,`4N,A``": -M>"H"XP(PD^<"`%/C`@``&L``G^7^___K%P``Z@0`4^,"```:L`"?Y?[__^L2 -M``#J"`!3XP(``!J@`)_E_O__ZPT``.H0`%/C`@``&I``G^7^___K"```ZB`` -M4^,"```:@`"?Y?[__^L#``#J0`!3XP$``!IP`)_E_O__ZVP`G^5L$)_E_O__ -MZP0`H.$`$);E/R"@X_[__^L$(-7E!`"@X000EN7W(`+B_O__ZP@@U>4$`*#A -M"!"6Y?<@`N+^___K#"#5Y00`H.$,$);EWR`"XO[__^MPC[WHW!0``.@4``#T -M%```!!4``!05```@%0``X!8``"11``#P02WI"-!-X@!0H.$!<*#A.SR@XP-` -MD.>I383B$$"$X@0`H.$#'0#C_O__ZP!@H.%P`!#C#```"@0`H.$#'0#CCR`& -MXO[__^L%`*#A`!"@XP$@H.'_/P#C_O__ZP"`H.$``%?C3@``"A8``.H$`*#A -M(A4`X_\@H./^___K!0"@X0`0H.,8(*#C_S\`X_[__^L""8#C``"-Y00`H.$` -M$*#C&""@X_\_`./^___K9`"@X_[__^L$`*#A(A4`XP`@H./^___K5P``Z@4` -MH.$!$*#C`""@X_\_`./^___K`'"@X?\TR./W.,/C`3B#XP`PC>4$`*#A`!"@ -MXP$@H.'_/P#C_O__Z_\TQ^/W.,/C`3B#XP`PC>4$`*#A`1"@XP`@H./_/P#C -M_O__ZP4`H.$`$*#C&""@X_\_`./^___K`@F`XP``C>4$`*#A`!"@XQ@@H./_ -M/P#C_O__ZV0`H./^___K!`"@X0,=`.,&(*#A_O__ZP"`C>4$`*#A`!"@XP$@ -MH.'_/P#C_O__ZP!PC>4$`*#A`1"@XP`@H./_/P#C_O__ZR```.K_-,#C]SC# -MXP$X@^,`,(WE!`"@X0`0H.,!(*#A_S\`X_[__^L%`*#A`!"@XQ@@H./_/P#C -M_O__ZP()@.,``(WE!`"@X0`0H.,8(*#C_S\`X_[__^MD`*#C_O__ZP0`H.$# -M'0#C!B"@X?[__^L`@(WE!`"@X0`0H.,!(*#A_S\`X_[__^L(T(WB\(&]Z/!' -M+>D`H*#A.SR@XP-0D.=P.@+C`S"5YP$#$^/PA[T(T#H"XP,PE><`,-/E``!3 -MXPX```H`0*#C,G"@X]!J`N//AP#C!P"@X?[__^LR0(3B!C"5YP`@T^4`,%+B -M`3"@$P@`5.$`,*"#``!3X_3__QH!(*#C?3<#XP,@Q><0,)7E`@!3XPH`H.$" -M$*`!`!"@$_[__^L`(*#C?3<#XP,@Q>=@.@+CTV"%X0$#H.,`$*#C`"`&X`$P -M!^`#$)+A\(>]"&@Z`N,#,)7G`P!3X_"'O9AX.@+C`S"5YP(`4^,"```:?`"? -MY?[__^L7``#J!`!3XP(``!IL`)_E_O__ZQ(``.H(`%/C`@``&EP`G^7^___K -M#0``ZA``4^,"```:3`"?Y?[__^L(``#J(`!3XP(``!H\`)_E_O__ZP,``.I` -M`%/C`0``&BP`G^7^___K*`"?Y2@0G^7H.@+C`R#5Y_[__^OPA[WHW!0``.@4 -M``#T%```!!4``!05```@%0``"!<``$!1``#P1RWI"-!-X@&@H.$"@*#A`W"@ -MX3L\H.,#0)#GJ6V$XA!@AN+^___K``!0XST```I@.@+CTP"$X?``S>$!`Z#C -M`!"@X]`@S>$`(`+@`3`#X`,0DN$E```*:#H"XP,PE.<#`%/C(0``FG@Z`N,# -M,)3G`@!3XP(``!JP`)_E_O__ZQ<``.H$`%/C`@``&J``G^7^___K$@``Z@@` -M4^,"```:D`"?Y?[__^L-``#J$`!3XP(``!J``)_E_O__ZP@``.H@`%/C`@`` -M&G``G^7^___K`P``ZD``4^,!```:8`"?Y?[__^M<`)_E7!"?Y?[__^L``%?C -M"P``"@!`H.,$4*#A`)#@XP8`H.$$$)KG"2"@X?[__^L$`(CG`5"%X@1`A.(' -M`%7A]O__&@C0C>+PA[WHW!0``.@4``#T%```!!4``!05```@%0``+!<``%A1 -M``#P1RWI`5"@X3L\H.,#,)#GJ4V#XA!`A.)@*@+CTH"#X0%CH.,`<*#C!@`( -MX`<0">`!()#A*P``"F@J`N,"()/G`P!2XR<``)IX*@+C`C"3YP(`4^,"```: -MR`"?Y?[__^L7``#J!`!3XP(``!JX`)_E_O__ZQ(``.H(`%/C`@``&J@`G^7^ -M___K#0``ZA``4^,"```:F`"?Y?[__^L(``#J(`!3XP(``!J(`)_E_O__ZP,` -M`.I``%/C`0``&G@`G^7^___K``!5XP`@`.,`($#C`#``XP`P0.,#(*`!7`"? -MY5P0G^7^___K``!5XP`Q`.,`,4#C`U"@$0%4H`,$`*#A@AZ@XP`@X.,%,*#A -M_O__ZP0`H.$H&`#C`"#@XP4PH.'^___K\(>]Z-P4``#H%```]!0```05```4 -M%0``(!4``%07``!P40``T$,MZ3L\H.,#,)#GJ4V#XA!`A.)@*@+CTH"#X0%C -MH.,`<*#C!@`(X`<0">`!()#A)0``"F@J`N,"()/G`P!2XR$``)IX*@+C`C"3 -MYP(`4^,"```:M`"?Y?[__^L7``#J!`!3XP(``!JD`)_E_O__ZQ(``.H(`%/C -M`@``&I0`G^7^___K#0``ZA``4^,"```:A`"?Y?[__^L(``#J(`!3XP(``!IT -M`)_E_O__ZP,``.I``%/C`0``&F0`G^7^___K8`"?Y6`0G^7^___K!`"@X2@> -M`.,`(.#C`#"@X_[__^L$`*#A(1V@XP`@X.,!.*#C_O__ZP0`H.$H'@#C`"#@ -MXP`P`..`,$CC_O__Z]"#O>C<%```Z!0``/04```$%0``%!4``"`5``!T%P`` -MA%$``/!-+>D(T$WB`7"@X0)`H.$#@*#A.SR@XP,PD.>I;8/B$&"&XF`J`N/2 -M`(/A\`#-X0&CH.,`L*#C"@``X`L0`>`!()#A)0``"F@J`N,"()/G`P!2XR$` -M`)IX*@+C`C"3YP(`4^,"```:]`"?Y?[__^L7``#J!`!3XP(``!KD`)_E_O__ -MZQ(``.H(`%/C`@``&M0`G^7^___K#0``ZA``4^,"```:Q`"?Y?[__^L(``#J -M(`!3XP(``!JT`)_E_O__ZP,``.I``%/C`0``&J0`G^7^___KH`"?Y:`0G^7^ -M___K``!4XZ15`@,;6T`#I%4"$]M40!,``%CC"```&@8`H.$`$)?E`"#@XZ`U -M`N,;.T#C_O__ZZ!5`N/;6T#C!```Z@8`H.$`$)?E`"#@XP4PH.'^___K`4"@ -MXP"`X.,&`*#A!!&7YP@@H.$%,*#A_O__ZP%`A.(0`%3C]___&@C0C>+PC;WH -MW!0``.@4``#T%```!!4``!05```@%0``D!<``)A1``#P1RWI"-!-X@&@H.$" -M@*#A`W"@X3L\H.,#,)#GJ6V#XA!@AN)@*@+CT@"#X?``S>$!0Z#C`%"@XP0` -M`.`%$`'@`2"0X24```IH*@+C`B"3YP,`4N,A``":>"H"XP(PD^<"`%/C`@`` -M&K``G^7^___K%P``Z@0`4^,"```:H`"?Y?[__^L2``#J"`!3XP(``!J0`)_E -M_O__ZPT``.H0`%/C`@``&H``G^7^___K"```ZB``4^,"```:<`"?Y?[__^L# -M``#J0`!3XP$``!I@`)_E_O__ZUP`G^5<$)_E_O__ZP``5^,+```*`$"@XP10 -MH.$`D.#C!@"@X000FN<)(*#A!#"8Y_[__^L!4(7B!$"$X@<`5>'V__\:"-"- -MXO"'O>C<%```Z!0``/04```$%0``%!4``"`5``"@%P``J%$``/!/+>D,T$WB -M`5"@X0)PH.$#8*#A,*#=Y3L\H.,#0)#G8#H"X].`A.$!`Z#C`!"@XP`@".`! -M,`G@`P"2X2L```IH.@+C`S"4YP,`4^,G``":>#H"XP,PE.<"`%/C`@``&C0# -MG^7^___K%P``Z@0`4^,"```:)`.?Y?[__^L2``#J"`!3XP(``!H4`Y_E_O__ -MZPT``.H0`%/C`@``&@0#G^7^___K"```ZB``4^,"```:]`*?Y?[__^L#``#J -M0`!3XP$``!KD`I_E_O__ZP``5>,`(`#C`"!`XP`P`.,`,$#C`R"@`<@"G^7( -M$I_E_O__Z_\`5N.F```*``!5XZ0```JI783B$%"%X@4`H.&('`#C`"#@X_[_ -M_^L@FZ#AAF*'X!!PEN4"#!?C!WO@$2=[X!&9!PC@*+2@X6`Z`N/3`(3A\`#- -MX0$#H.,`$*#CT"#-X0`@`N`!,`/@`Q"2X2<```IH.@+C`S"4YP,`4^,C``": -M>#H"XP,PE.<"`%/C`@``&A0"G^7^___K%P``Z@0`4^,"```:!`*?Y?[__^L2 -M``#J"`!3XP(``!KT`9_E_O__ZPT``.H0`%/C`@``&N0!G^7^___K"```ZB`` -M4^,"```:U`&?Y?[__^L#``#J0`!3XP$``!K$`9_E_O__Z\@!G^7`$9_E!R"@ -MX0LPH.'^___K!0"@X8@<`./_(P#C"S"@X?[__^L%`*#A3!P`XP(CH./8,^#G -M_O__ZQ1PEN4"#!?C!WO@$2=[X!&9!PG@*82@X0BPH.%@.@+CTP"$X?``S>$! -M`Z#C`!"@X]`@S>$`(`+@`3`#X`,0DN$G```*:#H"XP,PE.<#`%/C(P``FG@Z -M`N,#,)3G`@!3XP(``!H(`9_E_O__ZQ<``.H$`%/C`@``&O@`G^7^___K$@`` -MZ@@`4^,"```:Z`"?Y?[__^L-``#J$`!3XP(``!K8`)_E_O__ZP@``.H@`%/C -M`@``&L@`G^7^___K`P``ZD``4^,!```:N`"?Y?[__^O``)_EM!"?Y0<@H.$+ -M,*#A_O__ZP4`H.&<'`#C#R*@XULSX^?^___K!0"@X8@<`.,_**#C/S`(XO[_ -M_^L%`*#A3!P`XP(DH./9,^#G_O__ZP``6N,0```:!0"@X1P<`./_(P#C&#"6 -MY?[__^L<,);E!0"@X1P<`.,_*Z#C/S`#XO[__^L<,);E!0"@X7@<`.,/*J#C -M4S/CY_[__^L,T(WB\(^]Z-P4``#H%```]!0```05```4%0``(!4``.`7``#$ -M40``!!@``"08``#P3RWI%-!-X@%0H.$"<*#A`V"@X3B@W>4[/*#C`T"0YV`Z -M`N/3@(3A`0.@XP`0H.,`(`C@`3`)X`,`DN$K```*:#H"XP,PE.<#`%/C)P`` -MFG@Z`N,#,)3G`@!3XP(``!KT`Y_E_O__ZQ<``.H$`%/C`@``&N0#G^7^___K -M$@``Z@@`4^,"```:U`.?Y?[__^L-``#J$`!3XP(``!K$`Y_E_O__ZP@``.H@ -M`%/C`@``&K0#G^7^___K`P``ZD``4^,!```:I`.?Y?[__^L``%7C`"``XP`@ -M0.,`,`#C`#!`XP,@H`&(`Y_EB!.?Y?[__^O_`%;CU@``"@``5>/4```*J5V$ -MXA!0A>(%`*#A,AV@XP`@X./^___K()N@X89RA^``8)?E`@P6XP9KX!$F:^`1 -MF08(X"BTH.%@.@+CTP"$X?@`S>$!`Z#C`!"@X]@@S>$`(`+@`3`#X`,0DN$H -M```*:#H"XP,PE.<#`%/C)```FG@Z`N,#,)3G`@!3XP(``!K4`I_E_O__ZQ<` -M`.H$`%/C`@``&L0"G^7^___K$@``Z@@`4^,"```:M`*?Y?[__^L-``#J$`!3 -MXP(``!JD`I_E_O__ZP@``.H@`%/C`@``&I0"G^7^___K`P``ZD``4^,!```: -MA`*?Y?[__^L`D(WEA`*?Y7P2G^4&(*#A"S"@X?[__^L%`*#A,AV@X_\C`.,+ -M,*#A_O__ZP4`H.%,'`#C`B&@X]@SX.?^___K!&"7Y0(,%N,&:^`1)FO@$9D& -M">`IA*#A"+"@X6`Z`N/3`(3A^`#-X0$#H.,`$*#CV"#-X0`@`N`!,`/@`Q"2 -MX2<```IH.@+C`S"4YP,`4^,C``":>#H"XP,PE.<"`%/C`@``&L0!G^7^___K -M%P``Z@0`4^,"```:M`&?Y?[__^L2``#J"`!3XP(``!JD`9_E_O__ZPT``.H0 -M`%/C`@``&I0!G^7^___K"```ZB``4^,"```:A`&?Y?[__^L#``#J0`!3XP$` -M`!IT`9_E_O__ZWP!G^5P$9_E!B"@X0LPH.'^___K!0"@X90<`.,/(J#C6S/C -MY_[__^L%`*#A,AV@XS\HH.,_,`CB_O__ZP4`H.%,'`#C`B*@X]DSX.?^___K -M``!:XRX```I@.@+CTV"$X0$#H.,`$*#C`"`&X`$P!^`#`)+A-P``"F@Z`N,# -M,)3G`P!3XS,``)IX.@+C`S"4YP(`4^,"```:P`"?Y?[__^L7``#J!`!3XP(` -M`!JP`)_E_O__ZQ(``.H(`%/C`@``&J``G^7^___K#0``ZA``4^,"```:D`"? -MY?[__^L(``#J(`!3XP(``!J``)_E_O__ZP,``.I``%/C`0``&G``G^7^___K -M?`"?Y6P0G^7^___K$```Z@4`H.$4'`#C_R,`XP@PE^7^___K##"7Y04`H.$4 -M'`#C/RN@XS\P`^+^___K##"7Y04`H.'*'J#C#R*@XU,SX^?^___K%-"-XO"/ -MO>C<%```Z!0``/04```$%0``%!4``"`5``!$&```W%$``&@8``"8&```M!@` -M`/!/+>D,T$WB.SR@XP-`D.>I783B$%"%XF`Z`N/38(3A`0.@XP`0H.,`(`;@ -M`3`'X`,`DN%3```*:#H"XP,PE.<#`%/C3P``FG@Z`N,#,)3G`@!3XP(``!I4 -M!Y_E_O__ZQ<``.H$`%/C`@``&D0'G^7^___K$@``Z@@`4^,"```:-`>?Y?[_ -M_^L-``#J$`!3XP(``!HD!Y_E_O__ZP@``.H@`%/C`@``&A0'G^7^___K`P`` -MZD``4^,!```:!`>?Y?[__^L`!Y_E`!>?Y?[__^M@.@+CTV"$X0$#H.,`$*#C -M`"`&X`$P!^`#$)+A)0``"F@Z`N,#,)3G`P!3XR$``)IX.@+C`S"4YP(`4^," -M```:G`:?Y?[__^L7``#J!`!3XP(``!J,!I_E_O__ZQ(``.H(`%/C`@``&GP& -MG^7^___K#0``ZA``4^,"```:;`:?Y?[__^L(``#J(`!3XP(``!I8>H.,`(.#C -M`C"@X_[__^L%`*#AYAZ@XP`@X.,`,*#C_O__ZV`Z`N/38(3A`0.@XP`0H.,` -M(`;@`3`'X`,`DN$F```*:#H"XP,PE.<#`%/C(@``FG@Z`N,#,)3G`@!3XP(` -M`!J\!9_E_O__ZQ<``.H$`%/C`@``&JP%G^7^___K$@``Z@@`4^,"```:G`6? -MY?[__^L-``#J$`!3XP(``!J,!9_E_O__ZP@``.H@`%/C`@``&GP%G^7^___K -M`P``ZD``4^,!```:;`6?Y?[__^MT!9_E:!6?Y0H@H./^___K"@"@X_[__^L% -M`*#AK!X`XP`@X./^___K`&"@X6`Z`N/3@(3A`0.@XP`0H.,`(`C@`3`)X`,0 -MDN$F```*:#H"XP,PE.<#`%/C(@``FG@Z`N,#,)3G`@!3XP(``!KD!)_E_O__ -MZQ<``.H$`%/C`@``&M0$G^7^___K$@``Z@@`4^,"```:Q`2?Y?[__^L-``#J -M$`!3XP(``!JT!)_E_O__ZP@``.H@`%/C`@``&J0$G^7^___K`P``ZD``4^,! -M```:E`2?Y?[__^N@!)_ED!2?Y08@H.'^___K!0"@X;0>`.,`(.#C_O__ZP!P -MH.%@.@+CTX"$X0$#H.,`$*#C`"`(X`$P">`#`)+A)@``"F@Z`N,#,)3G`P!3 -MXR(``)IX.@+C`S"4YP(`4^,"```:%`2?Y?[__^L7``#J!`!3XP(``!H$!)_E -M_O__ZQ(``.H(`%/C`@``&O0#G^7^___K#0``ZA``4^,"```:Y`.?Y?[__^L( -M``#J(`!3XP(``!K4`Y_E_O__ZP,``.I``%/C`0``&L0#G^7^___KU`.?Y<`3 -MG^4'(*#A_O__ZP4`H.&\'@#C`"#@X_[__^L`@*#A8#H"X].@A.$!`Z#C`!"@ -MXP`@"N`!,`O@`Q"2X28```IH.@+C`S"4YP,`4^,B``":>#H"XP,PE.<"`%/C -M`@``&D0#G^7^___K%P``Z@0`4^,"```:-`.?Y?[__^L2``#J"`!3XP(``!HD -M`Y_E_O__ZPT``.H0`%/C`@``&A0#G^7^___K"```ZB``4^,"```:!`.?Y?[_ -M_^L#``#J0`!3XP$``!KT`I_E_O__ZP@#G^7P$I_E"""@X?[__^L%`*#AQ!X` -MXP`@X./^___K`*"@X6`Z`N/3`(3A\`#-X0$#H.,`$*#CT"#-X0`@`N`!,`/@ -M`Q"2X28```IH.@+C`S"4YP,`4^,B``":>#H"XP,PE.<"`%/C`@``&FP"G^7^ -M___K%P``Z@0`4^,"```:7`*?Y?[__^L2``#J"`!3XP(``!I,`I_E_O__ZPT` -M`.H0`%/C`@``&CP"G^7^___K"```ZB``4^,"```:+`*?Y?[__^L#``#J0`!3 -MXP$``!H<`I_E_O__ZS0"G^48$I_E"B"@X?[__^L%`*#AS!X`XP`@X./^___K -M`%"@X6`Z`N/3`(3A\`#-X0$#H.,`$*#CT"#-X0`@`N`!,`/@`Q"2X28```IH -M.@+C`S"4YP,`4^,B``":>#H"XP,PE.<"`%/C`@``&I0!G^7^___K%P``Z@0` -M4^,"```:A`&?Y?[__^L2``#J"`!3XP(``!IT`9_E_O__ZPT``.H0`%/C`@`` -M&F0!G^7^___K"```ZB``4^,"```:5`&?Y?[__^L#``#J0`!3XP$``!I$`9_E -M_O__ZV`!G^5`$9_E!2"@X?[__^L``%;C0```NE=XZ>=",0#C`P!7X3P```I8 -MB.GG0@!8XSD```H!`1;C!P``&EJHZ>#H"XP,PE.<"`%/C`@``&HP`G^7^___K%P``Z@0`4^,"```: -M?`"?Y?[__^L2``#J"`!3XP(``!IL`)_E_O__ZPT``.H0`%/C`@``&EP`G^7^ -M___K"```ZB``4^,"```:3`"?Y?[__^L#``#J0`!3XP$``!H\`)_E_O__ZUP` -MG^4X$)_E_O__ZP$`H.,"``#J``"@XP```.H!`*#C#-"-XO"/O>C<%```Z!0` -M`/04```$%0``%!4``"`5``#@&```]%$``/08```8&0``3!D``&`9``!T&0`` -MB!D``)P9``"P&0``\$\MZ0S03>([/*#C`U"0YZE-A>(00(3B8#H"X]-@A>$! -M`Z#C`!"@XP`@!N`!,`?@`Q"2X5,```IH.@+C`S"5YP,`4^-/``":>#H"XP,P -ME><"`%/C`@``&JP/G^7^___K%P``Z@0`4^,"```:G`^?Y?[__^L2``#J"`!3 -MXP(``!J,#Y_E_O__ZPT``.H0`%/C`@``&J0/G^7^___K"```ZB``4^,"```: -MJ`^?Y?[__^L#``#J0`!3XP$``!J8#Y_E_O__ZTP/G^64'Y_E_O__ZV`Z`N/3 -M8(7A`0.@XP`0H.,`(`;@`3`'X`,0DN$E```*:#H"XP,PE><#`%/C(0``FG@Z -M`N,#,)7G`@!3XP(``!KT#I_E_O__ZQ<``.H$`%/C`@``&N0.G^7^___K$@`` -MZ@@`4^,"```:U`Z?Y?[__^L-``#J$`!3XP(``!KL#I_E_O__ZP@``.H@`%/C -M`@``&O`.G^7^___K`P``ZD``4^,!```:X`Z?Y?[__^N8#I_EW!Z?Y?[__^L$ -M`*#A*!X`XP`@X.,`,*#C_O__Z_]O#^,/8$#CH#``XP@P0.,`,(WE!`"@X0`0 -MH./O(*#C!C"@X?[__^L#.*#C`#"-Y00`H.$`$*#C,""@XP8PH.'^___K#S"@ -MXP`PC>4$`*#A`!"@XS$@H.,&,*#A_O__ZWLQ`>,/,$#C`#"-Y00`H.$`$*#C -M,B"@XP8PH.'^___K!`"@X2@>`.,`(.#C`#``XX`P2./^___K!`"@X3D=H.,` -M(.#C`#P'XP`Q0./^___K!`"@X40>`.,`(.#C`#@$XP`Q2./^___K!`"@X>,> -MH.,`(.#C'#P(XP`P0>/^___K!`"@X30>`.,`(.#C'#P(XP`P0^/^___K!`"@ -MX3@>`.,`(.#C!#@`XQ8R2./^___K!`"@X3P>`.,`(.#C`#``XQ8X0N/^___K -M8#H"X]-@A>$!`Z#C`!"@XP`@!N`!,`?@`Q"2X24```IH.@+C`S"5YP,`4^,A -M``":>#H"XP,PE><"`%/C`@``&@`-G^7^___K%P``Z@0`4^,"```:\`R?Y?[_ -M_^L2``#J"`!3XP(``!K@#)_E_O__ZPT``.H0`%/C`@``&O@,G^7^___K"``` -MZB``4^,"```:_`R?Y?[__^L#``#J0`!3XP$``!KL#)_E_O__ZZ@,G^7H')_E -M_O__ZP0`H.%,'@#C`"#@XQ$Y"N-&,$#C_O__ZV`Z`N/38(7A`0.@XP`0H.,` -M(`;@`3`'X`,0DN$E```*:#H"XP,PE><#`%/C(0``FG@Z`N,#,)7G`@!3XP(` -M`!HP#)_E_O__ZQ<``.H$`%/C`@``&B`,G^7^___K$@``Z@@`4^,"```:$`R? -MY?[__^L-``#J$`!3XP(``!HH#)_E_O__ZP@``.H@`%/C`@``&BP,G^7^___K -M`P``ZD``4^,!```:'`R?Y?[__^O<"Y_E&!R?Y?[__^L$`*#A2!X`XP`@X./Y -M-*#C_O__ZP0`H.%('@#C`"#@XSXSH./^___K8#H"X]-@A>$!`Z#C`!"@XP`@ -M!N`!,`?@`Q"2X28```IH.@+C`S"5YP,`4^,B``":>#H"XP,PE><"`%/C`@`` -M&E`+G^7^___K%P``Z@0`4^,"```:0`N?Y?[__^L2``#J"`!3XP(``!HP"Y_E -M_O__ZPT``.H0`%/C`@``&D@+G^7^___K"```ZB``4^,"```:3`N?Y?[__^L# -M``#J0`!3XP$``!H\"Y_E_O__ZP`+G^4X&Y_E"B"@X_[__^L*`*#C_O__ZP0` -MH.&L'@#C`"#@X_[__^L`8*#A8#H"X].`A>$!`Z#C`!"@XP`@".`!,`G@`Q"2 -MX28```IH.@+C`S"5YP,`4^,B``":>#H"XP,PE><"`%/C`@``&G@*G^7^___K -M%P``Z@0`4^,"```::`J?Y?[__^L2``#J"`!3XP(``!I8"I_E_O__ZPT``.H0 -M`%/C`@``&G`*G^7^___K"```ZB``4^,"```:=`J?Y?[__^L#``#J0`!3XP$` -M`!ID"I_E_O__ZRP*G^5@&I_E!B"@X?[__^L$`*#AE!X`XP`@X./^___K`("@ -MX6`Z`N/3H(7A`0.@XP`0H.,`(`K@`3`+X`,0DN$F```*:#H"XP,PE><#`%/C -M(@``FG@Z`N,#,)7G`@!3XP(``!JH"9_E_O__ZQ<``.H$`%/C`@``&I@)G^7^ -M___K$@``Z@@`4^,"```:B`F?Y?[__^L-``#J$`!3XP(``!J@"9_E_O__ZP@` -M`.H@`%/C`@``&J0)G^7^___K`P``ZD``4^,!```:E`F?Y?[__^M@"9_ED!F? -MY0@@H.'^___K!`"@X9P>`.,`(.#C_O__ZP!PH.%@.@+CTZ"%X0$#H.,`$*#C -M`"`*X`$P"^`#$)+A)@``"F@Z`N,#,)7G`P!3XR(``)IX.@+C`S"5YP(`4^," -M```:V`B?Y?[__^L7``#J!`!3XP(``!K(")_E_O__ZQ(``.H(`%/C`@``&K@( -MG^7^___K#0``ZA``4^,"```:T`B?Y?[__^L(``#J(`!3XP(``!K4")_E_O__ -MZP,``.I``%/C`0``&L0(G^7^___KE`B?Y<`8G^4'(*#A_O__ZP$"%N-Y`@`: -M`#``X_\S0.,#,`C@0B$`XR,(4N%S`@`*5WCIYT(`5^-P`@`*`C&#XQ\[@^,' -M<(/A!`"@X3D=H.,`(.#C!S"@X?[__^M@.@+CTX"%X0$#H.,`$*#C`"`(X`$P -M">`#$)+A60``"F@Z`N,#,)7G`P!3XU4``)IX.@+C`S"5YP(`4^,"```:T`>? -MY?[__^L7``#J!`!3XP(``!K`!Y_E_O__ZQ(``.H(`%/C`@``&K`'G^7^___K -M#0``ZA``4^,"```:R`>?Y?[__^L(``#J(`!3XP(``!K,!Y_E_O__ZP,``.I` -M`%/C`0``&KP'G^7^___K!`"@X3D=H.,`(.#C_O__ZP`@H.%\!Y_EI!>?Y0

    $!`Z#C`!"@XP`@!N`!,`?@`Q"2X24```IH.@+C`S"5 -MYP,`4^,A``":>#H"XP,PE><"`%/C`@``&@`'G^7^___K%P``Z@0`4^,"```: -M\`:?Y?[__^L2``#J"`!3XP(``!K@!I_E_O__ZPT``.H0`%/C`@``&O@&G^7^ -M___K"```ZB``4^,"```:_`:?Y?[__^L#``#J0`!3XP$``!KL!I_E_O__Z\0& -MG^7H%I_E_O__ZP0`H.$H'@#C`"#@XP`PH./^___K_V\/XP]@0..@,`#C"#!` -MXP`PC>4$`*#A`!"@X^\@H.,&,*#A_O__ZP,XH.,`,(WE!`"@X0`0H.,P(*#C -M!C"@X?[__^L/,*#C`#"-Y00`H.$`$*#C,2"@XP8PH.'^___K^C\'XP\P0.,` -M,(WE!`"@X0`0H.,R(*#C!C"@X?[__^L$`*#A*!X`XP`@X.,`,`#C@#!(X_[_ -M_^L$`*#A1!X`XP`@X.,`.`3C`#%`X_[__^L$`*#AXQZ@XP`@X.,`.,` -M(.#C$3D*XT8P0./^___K8#H"X]-@A>$!`Z#C`!"@XP`@!N`!,`?@`Q"2X24` -M``IH.@+C`S"5YP,`4^,A``":>#H"XP,PE><"`%/C`@``&E0$G^7^___K%P`` -MZ@0`4^,"```:1`2?Y?[__^L2``#J"`!3XP(``!HT!)_E_O__ZPT``.H0`%/C -M`@``&DP$G^7^___K"```ZB``4^,"```:4`2?Y?[__^L#``#J0`!3XP$``!I` -M!)_E_O__ZP`$G^4\%)_E_O__ZP0`H.%('@#C`"#@X_DTH./^___K!`"@X4@> -M`.,`(.#C/C.@X_[__^M@.@+CTV"%X0$#H.,`$*#C`"`&X`$P!^`#$)+A)@`` -M"F@Z`N,#,)7G`P!3XR(``)IX.@+C`S"5YP(`4^,"```:=`.?Y?[__^L7``#J -M!`!3XP(``!ID`Y_E_O__ZQ(``.H(`%/C`@``&E0#G^7^___K#0``ZA``4^," -M```:;`.?Y?[__^L(``#J(`!3XP(``!IP`Y_E_O__ZP,``.I``%/C`0``&F`# -MG^7^___K)`.?Y5P3G^4*(*#C_O__ZPH`H./^___K!`"@X:P>`.,`(.#C_O__ -MZP!@H.%@.@+CTX"%X0$#H.,`$*#C`"`(X`$P">`#$)+A)@``"F@Z`N,#,)7G -M`P!3XR(``)IX.@+C`S"5YP(`4^,"```:G`*?Y?[__^L7``#J!`!3XP(``!J, -M`I_E_O__ZQ(``.H(`%/C`@``&GP"G^7^___K#0``ZA``4^,"```:E`*?Y?[_ -M_^L(``#J(`!3XP(``!J8`I_E_O__ZP,``.I``%/C`0``&H@"G^7^___K4`*? -MY802G^4&(*#A_O__ZP0`H.&4'@#C`"#@X_[__^L`<*#A8#H"X].`A>$!`Z#C -M`!"@XP`@".`!,`G@`Q"2X28```IH.@+C`S"5YP,`4^,B``":>#H"XP,PE><" -M`%/C`@``&LP!G^7^___K%P``Z@0`4^,"```:O`&?Y?[__^L2``#J"`!3XP(` -M`!JL`9_E_O__ZPT``.H0`%/C`@``&L0!G^7^___K"```ZB``4^,"```:R`&? -MY?[__^L#``#J0`!3XP$``!JX`9_E_O__ZX0!G^6T$9_E!R"@X?[__^L$`*#A -MG!X`XP`@X./^___K`'"@X6`Z`N/3@(7A`0.@XP`0H.,`(`C@`3`)X`,0DN$F -M```*:#H"XP,PE><#`%/C(@``FG@Z`N,#,)7G`@!3XP(``!K\`)_E_O__ZQ<` -M`.H$`%/C`@``&NP`G^7^___K$@``Z@@`4^,"```:W`"?Y?[__^L-``#J$`!3 -MXP(``!KT`)_E_O__ZP@``.H@`%/C`@``&O@`G^7^___K`P``ZD``4^,!```: -MZ`"?Y?[__^NX`)_EY!"?Y0<@H.'^___K!`"@X:0>`.,`(.#C_O__ZP!`H.%@ -M.@+CTX"%X0$#H.,`$*#C`"`(X`$P">`#$)+A/0``"F@Z`N,#,)7G`P!3XSD` -M`)IX.@+C`S"5YP(`4^,"```:+`"?Y?[__^LN``#J!`!3XP(``!H<`)_E_O__ -MZRD``.H(`%/C&0``&@P`G^7^___K)```ZMP4``#H%```]!0``,P9``#D&0`` -M%!H``/08```T&@``3!D``&@:``!\&@``D!H``+0:```$%0``Y!H``-P4``#H -M%```]!0```05```4%0``(!4``/@:```(4@``$`!3XP(``!HX`!_E_O__ZP@` -M`.H@`%/C`@``&C0`'^7^___K`P``ZD``4^,!```:1``?Y?[__^MD`!_E2!`? -MY00@H.'^___K`@,6XP<``!I42.GG,C$`XP,`5.$#```*5FCIYS8`5N,#`*`3 -M,@``&F`Z`N/38(7A`0.@XP`0H.,`(`;@`3`'X`,0DN$I```*:#H"XP,PE><# -M`%/C)0``FG@Z`N,#,)7G`@!3XP(``!K8`!_E_O__ZQ<``.H$`%/C`@``&N@` -M'^7^___K$@``Z@@`4^,"```:^``?Y?[__^L-``#J$`!3XP(``!H(`1_E_O__ -MZP@``.H@`%/C`@``&A@!'^7^___K`P``ZD``4^,!```:*`$?Y?[__^LL`1_E -M+!$?Y?[__^L!`*#C`@``Z@``H.,```#J`0"@XPS0C>+PC[WH^$\MZ3L\H.,# -M0)#GJ5V$XA!0A>)@.@+CTV"$X0$#H.,`$*#C`"`&X`$P!^`#$)+A4P``"F@Z -M`N,#,)3G`P!3XT\``)IX.@+C`S"4YP(`4^,"```:;`>?Y?[__^L7``#J!`!3 -MXP(``!I?Y?[__^L(``#J(`!3XP(``!HL!Y_E_O__ZP,``.I``%/C`0``&AP'G^7^ -M___K&`>?Y1@7G^7^___K8#H"X]-@A.$!`Z#C`!"@XP`@!N`!,`?@`Q"2X24` -M``IH.@+C`S"4YP,`4^,A``":>#H"XP,PE.<"`%/C`@``&K0&G^7^___K%P`` -MZ@0`4^,"```:I`:?Y?[__^L2``#J"`!3XP(``!J4!I_E_O__ZPT``.H0`%/C -M`@``&H0&G^7^___K"```ZB``4^,"```:=`:?Y?[__^L#``#J0`!3XP$``!ID -M!I_E_O__ZV@&G^5@%I_E_O__ZP4`H.'C'J#C`"#@XQP\".,`,$'C_O__ZP4` -MH.$T'@#C`"#@XQP\".,`,$/C_O__ZP4`H.$X'@#C`"#@XRHS`.,4,DCC_O__ -MZP4`H.$\'@#C`"#@XP`P`.,6.$+C_O__ZV`Z`N/38(3A`0.@XP`0H.,`(`;@ -M`3`'X`,0DN$E```*:#H"XP,PE.<#`%/C(0``FG@Z`N,#,)3G`@!3XP(``!J< -M!9_E_O__ZQ<``.H$`%/C`@``&HP%G^7^___K$@``Z@@`4^,"```:?`6?Y?[_ -M_^L-``#J$`!3XP(``!IL!9_E_O__ZP@``.H@`%/C`@``&EP%G^7^___K`P`` -MZD``4^,!```:3`6?Y?[__^M4!9_E2!6?Y?[__^L%`*#A3!X`XP`@X.,1.0+C -M1C!`X_[__^M@.@+CTV"$X0$#H.,`$*#C`"`&X`$P!^`#$)+A)0``"F@Z`N,# -M,)3G`P!3XR$``)IX.@+C`S"4YP(`4^,"```:S`2?Y?[__^L7``#J!`!3XP(` -M`!J\!)_E_O__ZQ(``.H(`%/C`@``&JP$G^7^___K#0``ZA``4^,"```:G`2? -MY?[__^L(``#J(`!3XP(``!J,!)_E_O__ZP,``.I``%/C`0``&GP$G^7^___K -MB`2?Y7@4G^7^___K!0"@X4@>`.,`(.#C^32@X_[__^L%`*#A2!X`XP`@X.,^ -M,Z#C_O__ZV`Z`N/38(3A`0.@XP`0H.,`(`;@`3`'X`,0DN$F```*:#H"XP,P -ME.<#`%/C(@``FG@Z`N,#,)3G`@!3XP(``!KL`Y_E_O__ZQ<``.H$`%/C`@`` -M&MP#G^7^___K$@``Z@@`4^,"```:S`.?Y?[__^L-``#J$`!3XP(``!J\`Y_E -M_O__ZP@``.H@`%/C`@``&JP#G^7^___K`P``ZD``4^,!```:G`.?Y?[__^NL -M`Y_EF!.?Y0H@H./^___K"@"@X_[__^L%`*#AK!X`XP`@X./^___K`&"@X6`Z -M`N/3@(3A`0.@XP`0H.,`(`C@`3`)X`,0DN$F```*:#H"XP,PE.<#`%/C(@`` -MFG@Z`N,#,)3G`@!3XP(``!H4`Y_E_O__ZQ<``.H$`%/C`@``&@0#G^7^___K -M$@``Z@@`4^,"```:]`*?Y?[__^L-``#J$`!3XP(``!KD`I_E_O__ZP@``.H@ -M`%/C`@``&M0"G^7^___K`P``ZD``4^,!```:Q`*?Y?[__^O8`I_EP!*?Y08@ -MH.'^___K!0"@X90>`.,`(.#C_O__ZP!PH.%@.@+CTX"$X0$#H.,`$*#C`"`( -MX`$P">`#$)+A)@``"F@Z`N,#,)3G`P!3XR(``)IX.@+C`S"4YP(`4^,"```: -M1`*?Y?[__^L7``#J!`!3XP(``!HT`I_E_O__ZQ(``.H(`%/C`@``&B0"G^7^ -M___K#0``ZA``4^,"```:%`*?Y?[__^L(``#J(`!3XP(``!H$`I_E_O__ZP,` -M`.I``%/C`0``&O0!G^7^___K#`*?Y?`1G^4'(*#A_O__ZP4`H.&<'@#C`"#@ -MX_[__^L`@*#A8#H"X].@A.$!`Z#C`!"@XP`@"N`!,`O@`Q"2X28```IH.@+C -M`S"4YP,`4^,B``":>#H"XP,PE.<"`%/C`@``&G0!G^7^___K%P``Z@0`4^," -M```:9`&?Y?[__^L2``#J"`!3XP(``!I4`9_E_O__ZPT``.H0`%/C`@``&D0! -MG^7^___K"```ZB``4^,"```:-`&?Y?[__^L#``#J0`!3XP$``!HD`9_E_O__ -MZT`!G^4@$9_E"""@X?[__^L%`*#AI!X`XP`@X./^___K`%"@X6`Z`N/3H(3A -M`0.@XP`0H.,`(`K@`3`+X`,0DN$F```*:#H"XP,PE.<#`%/C(@``FG@Z`N,# -M,)3G`@!3XP(``!JD`)_E_O__ZQ<``.H$`%/C`@``&I0`G^7^___K$@``Z@@` -M4^,"```:A`"?Y?[__^L-``#J$`!3XP(``!IT`)_E_O__ZP@``.H@`%/C`@`` -M&F0`G^7^___K`P``ZD``4^,!```:5`"?Y?[__^MT`)_E4!"?Y04@H.'^___K -M`0(6XP<``!I7>.GG0C$`XP,`5^$#```*6(CIYT(`6.(!`*`3^(^]Z```H./X -MC[WHW!0``.@4``#T%```!!4``!05```@%0``%!L``!A2```H&P``%!H``/08 -M```T&@``3!D``&@:``!\&@``Y!H``/A/+>D!8*#A`G"@X3L\H.,#,)#GJ5V# -MXA!0A>)@*@+CTJ"#X0&#H.,`D*#C"``*X`D0"^`!()#A)0``"F@J`N,"()/G -M`P!2XR$``)IX*@+C`C"3YP(`4^,"```:I`"?Y?[__^L7``#J!`!3XP(``!J4 -M`)_E_O__ZQ(``.H(`%/C`@``&H0`G^7^___K#0``ZA``4^,"```:=`"?Y?[_ -M_^L(``#J(`!3XP(``!ID`)_E_O__ZP,``.I``%/C`0``&E0`G^7^___K4`"? -MY5`0G^7^___K`$"@XP4`H.$$$);G!"#7Y_[__^L$0(3B#`!4X_C__QH%`*#A -M#!"6Y0P@E^7^___K^(^]Z-P4``#H%```]!0```05```4%0``(!4``$0;```L -M4@``^$\MZ0%@H.$"<*#A.SR@XP,PD.>I78/B$%"%XF`J`N/2H(/A`8.@XP"0 -MH.,(``K@"1`+X`$@D.$E```*:"H"XP(@D^<#`%+C(0``FG@J`N,",)/G`@!3 -MXP(``!JD`)_E_O__ZQ<``.H$`%/C`@``&I0`G^7^___K$@``Z@@`4^,"```: -MA`"?Y?[__^L-``#J$`!3XP(``!IT`)_E_O__ZP@``.H@`%/C`@``&F0`G^7^ -M___K`P``ZD``4^,!```:5`"?Y?[__^M0`)_E4!"?Y?[__^L`0*#C!0"@X000 -MEN?^___K!`"'YP1`A.(,`%3C^/__&@4`H.$,$);E_O__ZPP`A^7XC[WHW!0` -M`.@4``#T%```!!4``!05```@%0``9!L``$12``#P3RWIG-!-X@!PH.$($(WE -M`I"@X0.@H.$[/*#C`U"0YZF-A>(0@(CB`$``XP!`0.-8P(WB8N^$X@\`ON@/ -M`*SH#P"^Z`\`K.@/`+[H#P"LZ`\`GN@/`(SH2,"-XG(_A.(/`)/H#P",Z"3` -MC>)V3X3B#P"TZ`\`K.@/`+3H#P"LZ``PE.4`,(SE``!9XT4``!I@.@+CTP"% -MX?``S>$!`Z#C`!"@X]`@S>$`(`+@`3`#X`,0DN$L```*:#H"XP,PE><#`%/C -M*```FG@Z`N,#,)7G`@!3XP(``!H$#I_E_O__ZQ<``.H$`%/C`@``&O0-G^7^ -M___K$@``Z@@`4^,"```:Y`V?Y?[__^L-``#J$`!3XP(``!K4#9_E_O__ZP@` -M`.H@`%/C`@``&L0-G^7^___K`P``ZD``4^,!```:M`V?Y?[__^L``%KC`"`` -MXP`@0.,`,`#C`#!`XP,@H`&8#9_EF!V?Y0DPH.'^___K!P"@X5@0C>+>+87B -M$#"@X_[__^O?387B!P"@X4@0C>($(*#A_O__ZP<`H.$D$(WB-""$X@DPH./^ -M___K8#H"X],`A>'P`,WA`0.@XP`0H./0(,WA`"`"X`$P`^`#$)+A+```"F@Z -M`N,#,)7G`P!3XR@``)IX.@+C`S"5YP(`4^,"```:[`R?Y?[__^L7``#J!`!3 -MXP(``!K<#)_E_O__ZQ(``.H(`%/C`@``&LP,G^7^___K#0``ZA``4^,"```: -MO`R?Y?[__^L(``#J(`!3XP(``!JL#)_E_O__ZP,``.I``%/C`0``&IP,G^7^ -M___K``!:XP`@`.,`($#C`#``XP`P0.,#(*`!@`R?Y8`?),`/C`S#5YP``4^,"```:!P"@X0$0H./^___K"`"@X0(;H.,!)*#C -M`#"@X_[__^L(`*#A!!P`XP`@X.,`-@7CH#-`X_[__^L(`*#A"!P`XP`@X./D -M,`#C"#!`X_[__^L(`*#A=!@`XP`@X.,`,`3C(#)"X_[__^L(`*#AAQZ@XP$K -MH.,!,*#C_O__ZP@`H.&''J#C`2.@XP$PH./^___K"`"@X88>H.,!*Z#C`#"@ -MX_[__^L(`*#A9!@`XP$KH.,`,*#C_O__ZP``6N,9```*"`"@X2$=H.,`(.#C -M`3B@X_[__^L(`*#A1!@`XP`@X.,!.*#C_O__Z]^]A>('`*#A2!"-X@L@H.'^ -M___K"`"@X6@;`.,`(.#C]C:@X_[__^L(`*#A;!L`XP`@X./V-J#C_O__ZPD` -M`.K?O87B!P"@X4@0C>(+(*#A_O__ZP@`H.%H&P#C`"#@X_8VH./^___K8#H" -MX],`A>'P`,WA`0.@XP`0H./0(,WA`"`"X`$P`^`#$)+A)0``"F@Z`N,#,)7G -M`P!3XR$``)IX.@+C`S"5YP(`4^,"```:?`J?Y?[__^L7``#J!`!3XP(``!IL -M"I_E_O__ZQ(``.H(`%/C`@``&EP*G^7^___K#0``ZA``4^,"```:3`J?Y?[_ -M_^L(``#J(`!3XP(``!H\"I_E_O__ZP,``.I``%/C`0``&BP*G^7^___K,`J? -MY2@:G^7^___K"`"@X2@>`.,`(.#C`#``XX`P2./^___K"`"@X3D=H.,`(.#C -M`#P'XP`Q0./^___K"`"@X40>`.,`(.#C`#@$XP`Q2./^___K!P"@X0H0H.'^ -M___K`0!0XP0```H'`*#A"A"@X?[__^L!`%#C/0``&F`Z`N/3`(7A\`#-X0$# -MH.,`$*#CT"#-X0`@`N`!,`/@`Q"2X24```IH.@+C`S"5YP,`4^,A``":>#H" -MXP,PE><"`%/C`@``&DP)G^7^___K%P``Z@0`4^,"```:/`F?Y?[__^L2``#J -M"`!3XP(``!HL"9_E_O__ZPT``.H0`%/C`@``&AP)G^7^___K"```ZB``4^," -M```:#`F?Y?[__^L#``#J0`!3XP$``!K\")_E_O__ZP0)G^7X&)_E_O__ZP@P -MG>6)0H/@"`"@X90>`.,`(.#C_O__ZU`(Z><``(3E"`"@X9P>`.,`(.#C_O__ -MZU`(Z><$`(3E`$"@XP`P`.,`,$#C%#"-Y0`P`.,`,$#C&#"-Y0`P`.,`,$#C -M'#"-Y0<`H.$*$*#A_O__ZP!@H.$#`%#C/@``&F`Z`N/3`(7A\`#-X0$#H.,` -M$*#CT"#-X0`@`N`!,`/@`Q"2X24```IH.@+C`S"5YP,`4^,A``":>#H"XP,P -ME><"`%/C`@``&A0(G^7^___K%P``Z@0`4^,"```:!`B?Y?[__^L2``#J"`!3 -MXP(``!KT!Y_E_O__ZPT``.H0`%/C`@``&N0'G^7^___K"```ZB``4^,"```: -MU`>?Y?[__^L#``#J0`!3XP$``!K$!Y_E_O__Z]`'G^7`%Y_E_O__ZP@PG>6) -M0H/@"`"@X:0>`.,`(.#C_O__ZU`(Z><(`(3E"`"@X:P>`.,`(.#C_O__ZU`( -MZ><,`(3E9```ZF`Z`N/3`(7A\`#-X0$#H.,`$*#CT"#-X0`@`N`!,`/@`Q"2 -MX24```IH.@+C`S"5YP,`4^,A``":>#H"XP,PE><"`%/C`@``&A@'G^7^___K -M%P``Z@0`4^,"```:"`>?Y?[__^L2``#J"`!3XP(``!KX!I_E_O__ZPT``.H0 -M`%/C`@``&N@&G^7^___K"```ZB``4^,"```:'`"=Y?[__^L#``#J0`!3XP$` -M`!H8`)WE_O__ZQ0`G>7$%I_E_O__ZP%`A.("`%3CA___&@``5N,O```:8#H" -MX],`A>'P`,WA`0.@XP`0H./0(,WA`"`"X`$P`^`#$)+A)0``"F@Z`N,#,)7G -M`P!3XR$``)IX.@+C`S"5YP(`4^,"```:1`:?Y?[__^L7``#J!`!3XP(``!HT -M!I_E_O__ZQ(``.H(`%/C`@``&B0&G^7^___K#0``ZA``4^,"```:%`:?Y?[_ -M_^L(``#J(`!3XP(``!H$!I_E_O__ZP,``.I``%/C`0``&O0%G^7^___K!`:? -MY?`5G^7^___K``!:X]L```H'`*#A_O__ZP<`H.%8$(WB`""@XPHPH.'^___K -M"#"=Y8DR@^``,(WE`$"@XP`P`.,`,$#C%#"-Y0`P`.,`,$#C&#"-Y0`P`.,` -M,$#C'#"-Y0<`H.'^___K`&"@X0,`4.-,```:8#H"X],`A>'X`,WA`0.@XP`0 -MH./8(,WA`"`"X`$P`^`#$)+A)0``"F@Z`N,#,)7G`P!3XR$``)IX.@+C`S"5 -MYP(`4^,"```:&`6?Y?[__^L7``#J!`!3XP(``!H(!9_E_O__ZQ(``.H(`%/C -M`@``&O@$G^7^___K#0``ZA``4^,"```:Z`2?Y?[__^L(``#J(`!3XP(``!K8 -M!)_E_O__ZP,``.I``%/C`0``&L@$G^7^___KW`2?Y<04G^7^___K"`"@X;0> -M`.,`(.#C_O__ZU`(Z><`,)WE$`"#Y0@`H.&\'@#C`"#@X_[__^M0".GG`!"= -MY10`@>4(`*#AQ!X`XP`@X./^___K4`CIYP`PG>48`(/E"`"@X

    `.,`(.#C -M_O__ZU`(Z><`$)WE'`"!Y74``.H!`%3C`0!0`ST``!I@.@+CTP"%X?@`S>$! -M`Z#C`!"@X]@@S>$`(`+@`3`#X`,0DN$E```*:#H"XP,PE><#`%/C(0``FG@Z -M`N,#,)7G`@!3XP(``!K8`Y_E_O__ZQ<``.H$`%/C`@``&L@#G^7^___K$@`` -MZ@@`4^,"```:N`.?Y?[__^L-``#J$`!3XP(``!JH`Y_E_O__ZP@``.H@`%/C -M`@``&AP`G>7^___K`P``ZD``4^,!```:&`"=Y?[__^L4`)WEA!.?Y?[__^L( -M`*#AM!X`XP`@X./^___K4`CIYP`PG>40`(/E"`"@X;P>`.,`(.#C_O__ZU`( -MZ><`$)WE%`"!Y0%`A.("`%3C:?__&@``5N,O```:8#H"X],`A>'P`,WA`0.@ -MXP`0H./0(,WA`"`"X`$P`^`#$)+A50``"F@Z`N,#,)7G`P!3XRL``)IX.@+C -M`S"5YP(`4^,"```:S`*?Y?[__^L7``#J!`!3XP(``!J\`I_E_O__ZQ(``.H( -M`%/C`@``&JP"G^7^___K#0``ZA``4^,"```:G`*?Y?[__^L(``#J(`!3XP(` -M`!J,`I_E_O__ZP,``.I``%/C`0``&GP"G^7^___KE`*?Y7@2G^7^___K8#H" -MX],`A>'P`,WA`0.@XP`0H./0(,WA`"`"X`$P`^`#$)+A)0``"F@Z`N,#,)7G -M`P!3XR$``)IX.@+C`S"5YP(`4^,"```:#`*?Y?[__^L7``#J!`!3XP(``!K\ -M`9_E_O__ZQ(``.H(`%/C`@``&NP!G^7^___K#0``ZA``4^,"```:W`&?Y?[_ -M_^L(``#J(`!3XP(``!K,`9_E_O__ZP,``.I``%/C`0``&KP!G^7^___KV`&? -MY;@1G^7^___K"`"@X2@>`.,`(.#C`#"@X_[__^L``%GC+P``"LDP`^,#,-7G -M``!3XP(``!H'`*#A`!"@X_[__^L'`*#A6!"-XMXMA>(0,*#C_O__ZP<`H.%( -M$(WB"R"@X?[__^L'`*#A)!"-XM\MA>(T((+B"3"@X_[__^L(`*#A(1V@XP`@ -MX./3/@+C`S!`X_[__^L``%KC!0``"@@`H.%$&`#C`"#@X],^`N,#,$#C_O__ -MZP!,".,`04#C"`"@X>,>H.,`(.#C!#"@X?[__^L(`*#A-!X`XP`@X.,$,*#A -M_O__ZV`Z`N/38(7A`0.@XP`0H.,`(`;@`3`'X`,`DN$E```*:#H"XP,PE><# -M`%/C(0``FG@Z`N,#,)7G`@!3XP(``!IX`)_E_O__ZQ<``.H$`%/C`@``&F@` -MG^7^___K$@``Z@@`4^,"```:6`"?Y?[__^L-``#J$`!3XP(``!I(`)_E_O__ -MZP@``.H@`%/C`@``&C@`G^7^___K`P``ZD``4^,!```:*`"?Y?[__^M(`)_E -M)!"?Y?[__^N<#`%/C(0``FG@Z`N,#,)7G`@!3XP(``!JL -M"Y_E_O__ZQ<``.H$`%/C`@``&IP+G^7^___K$@``Z@@`4^,"```:C`N?Y?[_ -M_^L-``#J$`!3XP(``!I\"Y_E_O__ZP@``.H@`%/C`@``&FP+G^7^___K`P`` -MZD``4^,!```:7`N?Y?[__^M8"Y_E6!N?Y?[__^L&`*#A3!"-XM\MA>(0((+B -M"3"@X_[__^O$`@#J8#H"X].`A>$!`Z#C`!"@XP`@".`!,`G@`P"2X24```IH -M.@+C`S"5YP,`4^,A``":>#H"XP,PE><"`%/C`@``&M@*G^7^___K%P``Z@0` -M4^,"```:R`J?Y?[__^L2``#J"`!3XP(``!JX"I_E_O__ZPT``.H0`%/C`@`` -M&J@*G^7^___K"```ZB``4^,"```:F`J?Y?[__^L#``#J0`!3XP$``!J("I_E -M_O__ZXP*G^6$&I_E_O__ZW!PC>(@D(?B!S"@X0`@H.,`((/E(""#Y4`@@^5@ -M((/E!#"#X@D`4^'X__\:`$"@XW"`C>(!L*#C!*"@X0`PE>4!,$/B`0!3XP@` -M`(H0,)7E`@!3XP4``!H&`*#A"!"@X00@H.$+,*#A_O__ZP0``.H&`*#A"!"@ -MX00@H.$*,*#A_O__ZP$`5.,X```:!@"@X0@0H.$*(*#A"S"@X?[__^L``%#C -M`D"@`^/__PI@.@+CTX"%X0$#H.,`$*#C`"`(X`$P">`#$)+AJ@``"F@Z`N,# -M,)7G`P!3XZ8``)IX.@+C`S"5YP(`4^,"```:=`F?Y?[__^L7``#J!`!3XP(` -M`!ID"9_E_O__ZQ(``.H(`%/C`@``&E0)G^7^___K#0``ZA``4^,"```:1`F? -MY?[__^L(``#J(`!3XP(``!HT"9_E_O__ZP,``.I``%/C`0``&B0)G^7^___K -M+`F?Y2`9G^4`(*#C_O__ZP!`H.."``#J`@!4XWD``!H&`*#A$!`Z#C`!"@XP`@".`!,`G@`P"2X7`` -M``IH.@+C`S"5YP,`4^-L``":>#H"XP,PE><"`%/C`@``&HP(G^7^___K%P`` -MZ@0`4^,"```:?`B?Y?[__^L2``#J"`!3XP(``!IL")_E_O__ZPT``.H0`%/C -M`@``&EP(G^7^___K"```ZB``4^,"```:3`B?Y?[__^L#``#J0`!3XP$``!H\ -M")_E_O__ZT@(G^4X&)_E`""@X_[__^L`0*#C2```Z@8`H.%P$(WB`2"@XP(P -MH./^___K``!0XW`PC0(`0*`#+P``"F`Z`N/3@(7A`0.@XP`0H.,`(`C@`3`) -MX`,0DN'M`0`*:#H"XP,PE><#`%/CZ0$`FG@Z`N,#,)7G`@!3XP(``!JD!Y_E -M_O__ZQ<``.H$`%/C`@``&I0'G^7^___K$@``Z@@`4^,"```:A`>?Y?[__^L- -M``#J$`!3XP(``!IT!Y_E_O__ZP@``.H@`%/C`@``&F0'G^7^___K`P``ZD`` -M4^,!```:5`>?Y?[__^MD!Y_E4!>?Y0$@H./^___KQ0$`ZF`@D^4"0(3@!#"# -MX@,`6>'Z__\:``!4X_]`H`,#0*`3!@``Z@%`A.)T0._F`@!4XS+__YK_0*#C -M````Z@!`H.-P((WB@+""X@`P`.,`,$#C/#"-Y0`P`.,`,$#C0#"-Y0`P`.,` -M,$#C1#"-Y31`C>4X8(WE`("7Y00PE^4P,(WE")"7Y0Q`E^40H)?E%&"7Y1@` -ME^4H`(WE'!"7Y2P0C>5@.@+CTP"%X?`"S>$!`Z#C`!"@X]`BS>$`(`+@`3`# -MX`,0DN$N```*:#H"XP,PE><#`%/C*@``FG@Z`N,#,)7G`@!3XP(``!H\!I_E -M_O__ZQ<``.H$`%/C`@``&BP&G^7^___K$@``Z@@`4^,"```:'`:?Y?[__^L- -M``#J$`!3XP(``!H,!I_E_O__ZP@``.H@`%/C`@``&D0`G>7^___K`P``ZD`` -M4^,!```:0`"=Y?[__^L`D(WE$`2-Z0Q@C>4H()WE$""-Y2PPG>44,(WE/`"= -MY<$`/C`8"%YP00@^("L)'GH!`#XP&PA><( -M$(/B`I"1YW00$^4L$(WE$!"#X@*@D>>D(`/C`J"%YVQP$^6H(`/C`G"%YV@@ -M$^4H((WE9#`3Y2`PC>5@.@+CTP"%X0`@H.$!,*#A`0.@XP`0H.,`(`+@`3`# -MX`,0DN&?```*:#H"XP,PE><#`%/CFP``FG@Z`N,#,)7G`@!3XP(``!K4!)_E -M_O__ZQ<``.H$`%/C`@``&L0$G^7^___K$@``Z@@`4^,"```:M`2?Y?[__^L- -M``#J$`!3XP(``!JD!)_E_O__ZP@``.H@`%/C`@``&I0$G^7^___K`P``ZD`` -M4^,!```:A`2?Y?[__^N8!)_E@!2?Y3`@G>7^___K8#H"X],`A>$`(*#A`3"@ -MX0$#H.,`$*#C`"`"X`$P`^`#$)+A;@``"F@Z`N,#,)7G`P!3XVH``)IX.@+C -M`S"5YP(`4^,"```:$`2?Y?[__^L7``#J!`!3XP(``!H`!)_E_O__ZQ(``.H( -M`%/C`@``&O`#G^7^___K#0``ZA``4^,"```:X`.?Y?[__^L(``#J(`!3XP(` -M`!K0`Y_E_O__ZP,``.I``%/C`0``&L`#G^7^___K`)"-Y2P@G>4$!(WI#'"- -MY2@PG>40,(WE(`"=Y10`C>6X`Y_EG!.?Y0@@H.$+,*#A_O__ZP%PH.,'$*#A -M/0``ZF`Z`N/3`(7A\`+-X0$#H.,`$*#CT"+-X0`@`N`!,`/@`Q"2X24```IH -M.@+C`S"5YP,`4^,A``":>#H"XP,PE><"`%/C`@``&AP#G^7^___K%P``Z@0` -M4^,"```:#`.?Y?[__^L2``#J"`!3XP(``!K\`I_E_O__ZPT``.H0`%/C`@`` -M&NP"G^7^___K"```ZB``4^,"```:W`*?Y?[__^L#``#J0`!3XP$``!K,`I_E -M_O__Z^@"G^7($I_E_O__ZP$\H..D(`/C`C"%YYP@`^,",(7G`'"@XZ@P`^,# -M<(7GH#`#XP-PA><'$*#A`0``Z@%PH.,'$*#A``!8XP8```H!D'GB`)"@,P"0 -MC>4&`*#A<""-X@0PH.'^___K`#"5Y0$P0^(!`%/C#0``BA`PE>4"`%/C"@`` -M&@``6N,(```**""=Y0$P<#`%/C(@``FG@Z`N,#,)7G`@!3XP(``!I<`9_E_O__ZQ<``.H$`%/C -M`@``&DP!G^7^___K$@``Z@@`4^,"```:/`&?Y?[__^L-``#J$`!3XP(``!HL -M`9_E_O__ZP@``.H@`%/C`@``&AP!G^7^___K`P``ZD``4^,!```:#`&?Y?[_ -M_^LL`9_E"!&?Y0<@H.'^___K!@"@X4P0C>+?+87B$"""X@DPH./^___K8#H" -MX]-@A>$!`Z#C`!"@XP`@!N`!,`?@`Q"2X2@```IH.@+C`S"5YP,`4^,D``": -M>#H"XP,PE><"`%/C`@``&H@`G^7^___K%P``Z@0`4^,"```:>`"?Y?[__^L2 -M``#J"`!3XP(``!IH`)_E_O__ZPT``.H0`%/C`@``&E@`G^7^___K"```ZB`` -M4^,"```:2`"?Y?[__^L#``#J0`!3XP$``!HX`)_E_O__ZUP`G^4T$)_E_O__ -MZP$``.H!0*#C1_[_ZO30C>+PC[WHZ%(``-P4``#H%```]!0```05```4%0`` -M(!4``.P<```,4P``)!T``#@=``!H'0``F!T``"@>``#('0``3!X``'`>``"4 -M'@``T$`MZ0!`H.'C/=#E`0!3XP(```KG/=#E`0!3X]"`O1C08<3A`02@XP`0 -MH.,`(`;@`3`'X`,0DN$E```*&#"4Y0,`4^,B``":*#"4Y0(`4^,"```:F`"? -MY?[__^L7``#J!`!3XP(``!J(`)_E_O__ZQ(``.H(`%/C`@``&G@`G^7^___K -M#0``ZA``4^,"```::`"?Y?[__^L(``#J(`!3XP(``!I8`)_E_O__ZP,``.I` -M`%/C`0``&D@`G^7^___K9#"4Y4``G^5`$)_E`"#3Y?[__^MD,)3E``"4Y0`0 -MT^7^___K`#"@X^,]Q.7G/<3ET("]Z-P4``#H%```]!0```05```4%0``(!4` -M`*@>```D4P``\$\MZ8303>(`D*#A.SR@XP-`D.<`X`#C`.!`XU3`C>*:7X[B -M#P"UZ`\`K.@/`)7H!P"LZ+`PS.$TP(WBHN^.X@\`ON@/`*SH#P">Z`<`K.BP -M,,SAJ8V$XA"`B.((`*#A_O__Z\PP`^,#()3G`2""X@,@A.$!`Z#C`!"@X]`BS>$`(`+@`3`#X`,0DN$M```*:#H"XP,PE.<#`%/C*0`` -MFG@Z`N,#,)3G`@!3XP(``!ID#9_E_O__ZQ<``.H$`%/C`@``&E0-G^7^___K -M$@``Z@@`4^,"```:1`V?Y?[__^L-``#J$`!3XP(``!HT#9_E_O__ZP@``.H@ -M`%/C`@``&EP-G^7^___K`P``ZD``4^,!```:9`V?Y?[__^MV8*_F`&"-Y0@- -MG^58'9_E,BV@XP4PH.'^___K`@``Z@$P@^(K`%/CO___&I@P`^,#,)3G?#"- -MY=Q\G^7<;)_E`%"@XP"P`.,`L$#C`#``XP`P0.,H,(WE`#``XP`P0.,L,(WE -MT#`#XP,PU.<``%/C00``"@@`H.%\$(WB!R"@X00PH./^___K``!0X[```!IU -M8._F-C@#XP-0Q.=@.@+CTP"$X?`"S>$!`Z#C`!"@X]`BS>$`(`+@`3`#X`,0 -MDN&I```*:#H"XP,PE.<#`%/CI0``FG@Z`N,#,)3G`@!3XP(``!H4#)_E_O__ -MZQ<``.H$`%/C`@``&@0,G^7^___K$@``Z@@`4^,"```:]`N?Y?[__^L-``#J -M$`!3XP(``!KD"Y_E_O__ZP@``.H@`%/C`@``&@P,G^7^___K`P``ZD``4^,! -M```:%`R?Y?[__^MV,*_F`#"-Y=`P`^,#,-3G!#"-Y;@+G^7\&Y_E)"H`XWPP -MG>7^___K>P``ZF`Z`N/3`(3A\`+-X0$#H.,`$*#CT"+-X0`@`N`!,`/@`Q"2 -MX2D```IH.@+C`S"4YP,`4^,E``":>#H"XP,PE.<"`%/C`@``&C0+G^7^___K -M%P``Z@0`4^,"```:)`N?Y?[__^L2``#J"`!3XP(``!H4"Y_E_O__ZPT``.H0 -M`%/C`@``&@0+G^7^___K"```ZB``4^,"```:+`"=Y?[__^L#``#J0`!3XP$` -M`!HH`)WE_O__ZP`PUN4`,(WE"P"@X2@;G^5\()WE!3"@X?[__^L(`*#A?!"- -MX@8@H.$$,*#C_O__ZP``4.,Z```:=6#OYC8X`^,#4,3G8#H"X],`A.'P`LWA -M`0.@XP`0H./0(LWA`"`"X`$P`^`#$)+A,P``"F@Z`N,#,)3G`P!3XR\``)IX -M.@+C`S"4YP(`4^,"```:/`J?Y?[__^L7``#J!`!3XP(``!HL"I_E_O__ZQ(` -M`.H(`%/C`@``&AP*G^7^___K#0``ZA``4^,"```:#`J?Y?[__^L(``#J(`!3 -MXP(``!HT"I_E_O__ZP,``.I``%/C`0``&CP*G^7^___K=C"OY@`PC>70,`/C -M`S#4YP0PC>7D"9_E)!J?Y20J`.-\,)WE_O__ZP4``.H!4(7B"'"'X@A@AN(A -M`%7C/O__&@!@H..U,`/C`S#4YP``4^,+```:42#4Y;4P`^,#(,3GMC`#XP.@ -MQ.>W,`/C`Z#$YW0@W>72,`/C`R#$Y]$P`^,#8,3GR#`#XP,PU.<``%/C+0`` -M"F`Z`N/38(3A`0.@XP`0H.,`(`;@`3`'X`,`DN$E```*:#H"XP,PE.<#`%/C -M(0``FG@Z`N,#,)3G`@!3XP(``!K\")_E_O__ZQ<``.H$`%/C`@``&NP(G^7^ -M___K$@``Z@@`4^,"```:W`B?Y?[__^L-``#J$`!3XP(``!K,")_E_O__ZP@` -M`.H@`%/C`@``&O0(G^7^___K`P``ZD``4^,!```:_`B?Y?[__^N\")_E^!B? -MY?[__^O!,`/C`R#4YP(@A.#"+8+B."""X@&@PN4#(-3G`2""XG(@[^8#(,3G -M!`!2XP`@H`,#(,0'`#"@XP,`H.$#$*#A`R"$X,(M@N(Y((+B`"#2Y0``4N," -M`(`0`1"!$G$0[Q8!,(/B!`!3X_3__QH``%'C,```"O[__^MPH._F8#H"X]-@ -MA.$!`Z#C`!"@XP`@!N`!,`?@`Q"2X28```IH.@+C`S"4YP,`4^,B``":>#H" -MXP,PE.<"`%/C`@``&L@'G^7^___K%P``Z@0`4^,"```:N`>?Y?[__^L2``#J -M"`!3XP(``!JH!Y_E_O__ZPT``.H0`%/C`@``&I@'G^7^___K"```ZB``4^," -M```:P`>?Y?[__^L#``#J0`!3XP$``!K(!Y_E_O__ZXP'G^7$%Y_E"B"@X?[_ -M_^O(,`/C`S#4YP``4^,*```*43#4Y0,`6N$*,&.``S!JD'-P[^8`,*#CR"`# -MXP(PQ.?4(`/C`C#$YPD``.K4,`/C`S#4YP``4^.U,`,3`S#4%U$PU`4#`%KA -M"C!C@`,P:I!S<._FMC`#XP-0U.<%`%KA"E!E@`50:I!U4._FMS`#XP-@U.<& -M`%KA"F!F@`9@:I!V8._F8#H"X],`A.$`(*#A`3"@X0$#H.,`$*#C`"`"X`$P -M`^`#$)+A9@``"F@Z`N,#,)3G`P!3XV(``)IX.@+C`S"4YP(`4^,"```:<`:? -MY?[__^L7``#J!`!3XP(``!I@!I_E_O__ZQ(``.H(`%/C`@``&E`&G^7^___K -M#0``ZA``4^,"```:0`:?Y?[__^L(``#J(`!3XP(``!IH!I_E_O__ZP,``.I` -M`%/C`0``&G`&G^7^___KM3`#XP,PU.=1(-3EA`"-Z`A0C>4,8(WE(`:?Y506 -MG^4*(*#A_O__ZV`Z`N/3`(3A`""@X0$PH.$!`Z#C`!"@XP`@`N`!,`/@`Q"2 -MX2\```IH.@+C`S"4YP,`4^,K``":>#H"XP,PE.<"`%/C`@``&I0%G^7^___K -M%P``Z@0`4^,"```:A`6?Y?[__^L2``#J"`!3XP(``!IT!9_E_O__ZPT``.H0 -M`%/C`@``&F0%G^7^___K"```ZB``4^,"```:C`6?Y?[__^L#``#J0`!3XP$` -M`!J4!9_E_O__Z[8P`^,#(-3G`3"#X@,PU.=9%P/C`1#4YP`0C>58%P/C`1#4 -MYP00C>4X!9_E:!6?Y?[__^L'`%7C`P``FK8P`^,#H,3G"0"@X?[__^L``%?C -M=@$`"J\P`^,#,-3G``!3XW(!``I1,-3E`P!:X0H`8X`#`&J0<`#OY@,`6N$` -MP*"3`<"@@P,`6N$/,*"#`#"@DX`@C>(#,(+@3#!3Y0``4^$`,*"##P``BC0@ -MC>(,(H+@`B!LX`$PH.,!$-+E``!1X0,``)H``%/C`3!#$G,P[Q8$``#J`3"# -MXG,P[^8!((+B#P!3X_/__QJ``(WB#"*`X`+`;.`.`%/C`S",D`XPC((L,%/E -MTB`#XP)0U.<%4(/@=5#OYGA0S>71(`/C`B#4YP(P@^!S<._F8#H"X],`A.$` -M(*#A`3"@X0$#H.,`$*#C`"`"X`$P`^`#$)+A*0``"F@Z`N,#,)3G`P!3XR4` -M`)IX.@+C`S"4YP(`4^,"```:N`.?Y?[__^L7``#J!`!3XP(``!JH`Y_E_O__ -MZQ(``.H(`%/C`@``&I@#G^7^___K#0``ZA``4^,"```:B`.?Y?[__^L(``#J -M(`!3XP(``!JP`Y_E_O__ZP,``.I``%/C`0``&K@#G^7^___KB`.?Y;03G^72 -M,`/C`R#4YP$P0^(#,-3G_O__ZW4PK^8J`%/C*C"@PW@PS<4#``#*=5"OY@4` -M5>,&,*#3>##-U7=0K^;%7\7A(`!5XR!0H*-U4._F8#H"X],`A.'P`LWA`0.@ -MXP`0H./0(LWA`"`"X`$P`^`#$)+A)P``"F@Z`N,#,)3G`P!3XR,``)IX.@+C -M`S"4YP(`4^,"```:L`*?Y?[__^L7``#J!`!3XP(``!J@`I_E_O__ZQ(``.H( -M`%/C`@``&I`"G^7^___K#0``ZA``4^,"```:@`*?Y?[__^L(``#J(`!3XP(` -M`!JH`I_E_O__ZP,``.I``%/C`0``&K`"G^7^___KA`*?Y:P2G^78)]WA=3"O -MYO[__^NO,`/C`S#4YP``4^/)```*`2"@X]0P`^,#(,3G>##=Y0`@`.,`($#C -M`R&2YR(KH.$@((WEY"`#XP)PE.?H(`/C`K"4YS`H`^,",,3G-"@#XP)0Q.^`1(%"=Y94'`^!3-.GG*#"-Y0(,&^,+N^`1*[O@$94+!>!55.GG -M8#H"X],`A.$`(*#A`3"@X0$#H.,`$*#C`"`"X`$P`^`#$)+AC```"F@Z`N,# -M,)3G`P!3XX@``)IX.@+C`S"4YP(`4^,"```:#`&?Y?[__^L7``#J!`!3XP(` -M`!K\`)_E_O__ZQ(``.H(`%/C`@``&NP`G^7^___K#0``ZA``4^,"```:W`"? -MY?[__^L(``#J(`!3XP(``!H$`9_E_O__ZP,``.I``%/C`0``&@P!G^7^___K -M*""=Y20`C>@@,)WE"#"-Y0QPC>40L(WES`"?Y?`0G^4'(*#A"S"@X?[__^M@ -M.@+CTP"$X?`"S>$!`Z#C`!"@X]`BS>$`(`+@`3`#X`,0DN%4```*:#H"XP,P -ME.<#`%/C4```FG@Z`N,#,)3G`@!3XP(``!HL`)_E_O__ZS,``.H$`%/C`@`` -M&AP`G^7^___K+@``Z@@`4^,>```:#`"?Y?[__^LI``#JW!0``.@4``#T%``` -M!!4``-`>```<'P``6H -M`!_EC!`?Y04@H.$',*#A_O__ZP<`5N,&``":"`"@X?[__^NW,`/C`Z#$YPD` -MH.$`$*#C_O__ZZ\P`^,#,-3G``!3X[4P`Q,#H,078#H"X]-@A.$!`Z#C`!"@ -MXP`@!N`!,`?@`P"2X24```IH.@+C`S"4YP,`4^,A``":>#H"XP,PE.<"`%/C -M`@``&C`!'^7^___K%P``Z@0`4^,"```:0`$?Y?[__^L2``#J"`!3XP(``!I0 -M`1_E_O__ZPT``.H0`%/C`@``&F`!'^7^___K"```ZB``4^,"```:<`$?Y?[_ -M_^L#``#J0`!3XP$``!J``1_E_O__ZX0!'^6$$1_E_O__ZP`@H..L,`/C`R#$ -MYX30C>+PC[WH\$$MZ0!0H.$!0*#A`G"@X0-@H.'^`%'C`@``&C(`H./^___K -M&P``ZOT`4>,"```:!0"@X_[__^L6``#J_`!1XP(``!H!`*#C_O__ZQ$``.K[ -M`%'C`@``&C(`H./^___K#```ZOH`4>,"```:!0"@X_[__^L'``#J^0!1XP(` -M`!H!`*#C_O__ZP(``.HD.@#C`P!1X4AF@`4%`*#A!!"@X0<@H.$&,*#A_O__ -MZP$`H./^___K$#"5Y0``4^/P@;VH&#"5Y00`4^/P@;V8*#"5Y0(`4^,"```: -M?`"?Y?[__^L7``#J!`!3XP(``!IL`)_E_O__ZQ(``.H(`%/C`@``&EP`G^7^ -M___K#0``ZA``4^,"```:3`"?Y?[__^L(``#J(`!3XP(``!H\`)_E_O__ZP,` -M`.I``%/C`0``&BP`G^7^___K*`"?Y2@0G^4$(*#A!C"@X?[__^OP@;WH`",` -M``PC```8(P``*",``#@C``!$(P``4",``*Q3``#P0"WI#-!-X@!0H.$!0*#A -M`G"@X0-@H.'^`%'C`@``&C(`H./^___K%P``ZOT`4>,"```:!0"@X_[__^L2 -M``#J_`!1XP(``!H!`*#C_O__ZPT``.K[`%'C`@``&C(`H./^___K"```ZOH` -M4>,"```:!0"@X_[__^L#``#J^0!1XP$``!H!`*#C_O__ZQ`PE>4``%/C)@`` -MJA@PE>4$`%/C(P``FB@PE>4"`%/C`@``&H0`G^7^___K%P``Z@0`4^,"```: -M=`"?Y?[__^L2``#J"`!3XP(``!ID`)_E_O__ZPT``.H0`%/C`@``&E0`G^7^ -M___K"```ZB``4^,"```:1`"?Y?[__^L#``#J0`!3XP$``!HT`)_E_O__ZP!@ -MC>4L`)_E+!"?Y00@H.$',*#A_O__ZPS0C>+P@+WH`",```PC```8(P``*",` -M`#@C``!$(P``C",``,13``!P0"WI`$"@X0%0H.$#8*#A_O__ZP$`H./^___K -M$#"4Y0``4^-P@+VH&#"4Y00`4^-P@+V8*#"4Y0(`4^,"```:?`"?Y?[__^L7 -M``#J!`!3XP(``!IL`)_E_O__ZQ(``.H(`%/C`@``&EP`G^7^___K#0``ZA`` -M4^,"```:3`"?Y?[__^L(``#J(`!3XP(``!H\`)_E_O__ZP,``.I``%/C`0`` -M&BP`G^7^___K*`"?Y2@0G^4%(*#A!C"@X?[__^MP@+WH`",```PC```8(P`` -M*",``#@C``!$(P``T",``.13``!P0"WI`$"@X0%0H.$"8*#A_O__ZQ`PE.4` -M`%/C<("]J!@PE.4$`%/C<("]F"@PE.4"`%/C`@``&GP`G^7^___K%P``Z@0` -M4^,"```:;`"?Y?[__^L2``#J"`!3XP(``!I<`)_E_O__ZPT``.H0`%/C`@`` -M&DP`G^7^___K"```ZB``4^,"```:/`"?Y?[__^L#``#J0`!3XP$``!HL`)_E -M_O__ZR@`G^4H$)_E!2"@X08PH.'^___K<("]Z``C```,(P``&",``"@C```X -M(P``1",```PD``#\4P``!.`MY0S03>+^SP#C#`!1X0(``!HR`*#C_O__ZR`` -M`.K]`%'C`@``&@4`H./^___K&P``ZOP`4>,"```:`0"@X_[__^L6``#J^P!1 -MXP(``!HR`*#C_O__ZQ$``.KZ`%'C`@``&@4`H./^___K#```ZOD`4>,"```: -M`0"@X_[__^L'``#J`""-Y0,0H.$0()WE_S\/XP\P0./^___K`0"@X_[__^L, -MT(WB`("]Z'!`+>D(T$WB`$"@X0%0H.$"8*#A`!"-Y0$PH./^___K$#"4Y0`` -M4^,E``"J&#"4Y00`4^,B``":*#"4Y0(`4^,"```:@`"?Y?[__^L7``#J!`!3 -MXP(``!IP`)_E_O__ZQ(``.H(`%/C`@``&F``G^7^___K#0``ZA``4^,"```: -M4`"?Y?[__^L(``#J(`!3XP(``!I``)_E_O__ZP,``.I``%/C`0``&C``G^7^ -M___K+`"?Y2P0G^4%(*#A!C"@X?[__^L(T(WB<("]Z``C```,(P``&",``"@C -M```X(P``1",``$PD```05```<$`MZ0C03>(`0*#A`5"@X0)@H.$`$(WE`#"@ -MX_[__^L0,)3E``!3XR4``*H8,)3E!`!3XR(``)HH,)3E`@!3XP(``!J``)_E -M_O__ZQ<``.H$`%/C`@``&G``G^7^___K$@``Z@@`4^,"```:8`"?Y?[__^L- -M``#J$`!3XP(``!I0`)_E_O__ZP@``.H@`%/C`@``&D``G^7^___K`P``ZD`` -M4^,!```:,`"?Y?[__^LL`)_E+!"?Y04@H.$&,*#A_O__ZPC0C>)P@+WH`",` -M``PC```8(P``*",``#@C``!$(P``B"0``"Q4```P`"WI`#"@X0$C@.#0P(+B -M$P"@XP``S.4!`,SE`@#,Y0``H.,#`,SE`Q"!X@$#P^'J#C`!"%Y000C.4$`,/EZ,""X@%` -MH.,&0,SE\!""XGPR">/_/T_CL##!X;0`S.&T`,7AO@W"X;`.PN&R#L+AM`[" -MX0``C.4"`,'E`P#!Y01`P>4%`,'E!<"@XP;`P>7X((+B/\#@XP3`PN4'`,'E -M``#"Y0$`PN4"`,+E`P#"Y3``O>@>_R_A\$$` -M,*`#"@``"@`0`.,`$$#C`3"@X[+`T>$%`%SA!```"@$P@^)S,._F`A"!X@4` -M4^/W__\:``!2XP`PH`,+```*`0!2XP0``!H!,(/B`"?Y?[__^L7``#J!`!3XP(``!IH`)_E_O__ZQ(``.H(`%/C`@``&E@` -MG^7^___K#0``ZA``4^,"```:2`"?Y?[__^L(``#J(`!3XP(``!HX`)_E_O__ -MZP,``.I``%/C`0``&B@`G^7^___K)`"?Y200G^6P(]3A_O__Z_"'O>C$)``` -MT"0``-PD``#L)```_"0```@E```4)0``5%0``/!/+>D`^?Y?[__^L(``#J(`!3XP(``!IH#Y_E -M_O__ZP,``.I``%/C`0``&E@/G^7^___K5`^?Y50?G^7^___K+C#4Y0``4^/4 -M!``**#"4Y0``4^/1!``*#3#4Y0X@U.4#$$+B`0!3X0(``+H#((+B`@!3X0(` -M`-H`,*#C,C#$Y3,PQ.428-3E$3#4Y0,`5N$#8*`A`#``XP`P0.,&((/@#;#4 -MY4`@TN4"`%OA`+"@@P&PH).+(J#A"R%"X`(P@^`&,(/@7'#3Y="!Q>$"#*#C -M`!"@XP`@".`!,`G@`Q"2X20```H8,)7E!`!3XR$``)HH,)7E`@!3XP(``!IT -M#I_E_O__ZQ<``.H$`%/C`@``&F0.G^7^___K$@``Z@@`4^,"```:5`Z?Y?[_ -M_^L-``#J$`!3XP(``!I$#I_E_O__ZP@``.H@`%/C`@``&C0.G^7^___K`P`` -MZD``4^,!```:)`Z?Y?[__^LH#I_E(!Z?Y1@@E.7^___K`"``XP`@0..4$*#C -MAP"'X(`P@N`!P-/GO('4X1B@E.68K"C@E<#3Y;ZAU.&:C"S@`0"`XH`@@N`! -M(-+GL!+4X9'"(>"7(-/EL@+4X9`2(N"8,-/EM!+4X9$C(^`8,(3ET('%X0(, -MH.,`$*#C`"`(X`$P">`#$)+A*@``"A@PE>4$`%/C)P``FB@PE>4"`%/C`@`` -M&F0-G^7^___K%P``Z@0`4^,"```:5`V?Y?[__^L2``#J"`!3XP(``!I$#9_E -M_O__ZPT``.H0`%/C`@``&C0-G^7^___K"```ZB``4^,"```:)`V?Y?[__^L# -M``#J0`!3XP$``!H4#9_E_O__ZQP=G^4&,*#CDQ(8()3EG`,#X/[__^L8()3E`#``XP`P0..'$(?@@3"#X)DPT^4H$)3ED0,# -MX`,`4N$",&.``#"@DQ@PA.4`,`#C`#!`XP8P@^`@@=/E`@R@XP`0H./0(<7A -M`"`"X`$P`^`#$)+A)```"A@PE>4$`%/C(0``FB@PE>4"`%/C`@``&EP,G^7^ -M___K%P``Z@0`4^,"```:3`R?Y?[__^L2``#J"`!3XP(``!H\#)_E_O__ZPT` -M`.H0`%/C`@``&BP,G^7^___K"```ZB``4^,"```:'`R?Y?[__^L#``#J0`!3 -MXP$``!H,#)_E_O__ZQP,G^4(')_E%""4Y?[__^L`(`#C`"!`XY00H..(`(C@ -M@#""X`'`T^>\D=3A%*"4Y9FL+."5H-/EOI'4X9G**>`!`(#B@"""X`$@TN>P -MHM3AFI(JX)<@T^6RPM3AG*(LX)@PT^6T(M3ADL,CX!0PA.4"#*#C`!"@X]`A -MQ>$`(`+@`3`#X`,0DN$J```*&#"5Y00`4^,G``":*#"5Y0(`4^,"```:3`N? -MY?[__^L7``#J!`!3XP(``!H\"Y_E_O__ZQ(``.H(`%/C`@``&BP+G^7^___K -M#0``ZA``4^,"```:'`N?Y?[__^L(``#J(`!3XP(``!H,"Y_E_O__ZP,``.I` -M`%/C`0``&OP*G^7^___K!!N?Y08PH..3&"/@F3#3Y2C`E.7\"I_E*!"!XA0@ -ME.6<`P/@_O__ZQ0@E.4`,`#C`#!`XX@0B."!,(/@F3#3Y2@0E.61`P/@`P!2 -MX0(P8X``,*"3%#"$Y1`@E>4`,@#C`#!(XP,P`N```%/C+0``"A@PE>4#`%/C -M*@``FB@PE>4"`%/C`@``&E@*G^7^___K%P``Z@0`4^,"```:2`J?Y?[__^L2 -M``#J"`!3XP(``!HX"I_E_O__ZPT``.H0`%/C`@``&B@*G^7^___K"```ZB`` -M4^,"```:&`J?Y?[__^L#``#J0`!3XP$``!H("I_E_O__ZPT@U.6``8WH"&"- -MY1@PE.4,,(WE%#"4Y1`PC>4,,-3E%#"-Y?P)G^7@&9_E"S"@X?[__^L`,`#C -M`#!`XX8P@^!//X/BL##3X1@@E.4#`%+A!@``.@`P`.,`,$#C!C"#X+PBU.%T -M,=/E`P!2X7$!`)K08<7A`@R@XP`0H.,`(`;@`3`'X`,0DN$C```*&#"5Y00` -M4^,@``":*#"5Y0(`4^,"```:2`F?Y?[__^L7``#J!`!3XP(``!HX"9_E_O__ -MZQ(``.H(`%/C`@``&B@)G^7^___K#0``ZA``4^,"```:&`F?Y?[__^L(``#J -M(`!3XP(``!H("9_E_O__ZP,``.I``%/C`0``&O@(G^7^___K%`F?Y109G^7^ -M___K``!4XRL``!K08<7A`@R@XP`0H.,`(`;@`3`'X`,0DN'D`@`*&#"5Y0,` -M4^/A`@":*#"5Y0(`4^,"```:E`B?Y?[__^L7``#J!`!3XP(``!J$")_E_O__ -MZQ(``.H(`%/C`@``&G0(G^7^___K#0``ZA``4^,"```:9`B?Y?[__^L(``#J -M(`!3XP(``!I4")_E_O__ZP,``.I``%/C`0``&D0(G^7^___K:`B?Y6`8G^7^ -M___KOP(`ZA%PU.43@-3E$F#4Y="AQ>$"#*#C`!"@XP`@"N`!,`O@`Q"2X2@` -M``H8,)7E!`!3XR4``)HH,)7E`@!3XP(``!K8!Y_E_O__ZQ<``.H$`%/C`@`` -M&L@'G^7^___K$@``Z@@`4^,"```:N`>?Y?[__^L-``#J$`!3XP(``!JH!Y_E -M_O__ZP@``.H@`%/C`@``&I@'G^7^___K`P``ZD``4^,!```:B`>?Y?[__^L` -M8(WE###4Y00PC>6D!Y_EF!>?Y0<@H.$(,*#A_O__ZP8`5^$;``"*###4Y0`` -M4^,`,*`3###$%0=@H!$5```:"`!7X0A@H)$2``":``!7XP\```H!8$?B=F#O -MY@8`6.$+```J"#"4Y0$@H.,2)A/@`2"@`P(```H&``#J$A83X`0``!H!8$;B -M=F#OY@8`6.'Y__\Z!V"@X3(PU.4!`%/C!0``&@(PH.,R,,3E,S#4Y0$P@^(S -M,,3E!```Z@``4^,`,*`3,C#$%3,PQ!4#```:,S#4Y0,`4^,$,*"#,S#$A1!@ -MQ.4%`*#A!!"@X0(@H.-'_?_KT('%X0(,H.,`$*#C`"`(X`$P">`#$)+A4`(` -M"A@PE>4#`%/C)P``FB@PE>4"`%/C`@``&D0&G^7^___K%P``Z@0`4^,"```: -M-`:?Y?[__^L2``#J"`!3XP(``!HD!I_E_O__ZPT``.H0`%/C`@``&A0&G^7^ -M___K"```ZB``4^,"```:!`:?Y?[__^L#``#J0`!3XP$``!KT!9_E_O__ZR`& -MG^40%I_E_O__Z]"!Q>$"#*#C`!"@XP`@".`!,`G@`Q"2X24"``H8,)7E!`!3 -MXRD``)HH,)7E`@!3XP(``!J8!9_E_O__ZQ<``.H$`%/C`@``&H@%G^7^___K -M$@``Z@@`4^,"```:>`6?Y?[__^L-``#J$`!3XP(``!IH!9_E_O__ZP@``.H@ -M`%/C`@``&E@%G^7^___K`P``ZD``4^,!```:2`6?Y?[__^N4!9_E9!6?Y3(@ -MU.4S,-3E_O__Z]"!Q>$"#*#C`!"@XP`@".`!,`G@`Q"2X?@!``H8,)7E`P!3 -MXRD``)HH,)7E`@!3XP(``!KD!)_E_O__ZQ<``.H$`%/C`@``&M0$G^7^___K -M$@``Z@@`4^,"```:Q`2?Y?[__^L-``#J$`!3XP(``!JT!)_E_O__ZP@``.H@ -M`%/C`@``&J0$G^7^___K`P``ZD``4^,!```:E`2?Y?[__^O$!)_EL!2?Y08@ -MH.$,,-3E_O__Z]!AQ>$"#*#C`!"@XP`@!N`!,`?@`Q"2X4$`%/C(@``FB@PE>4"`%/C -M`@``&O0!G^7^___K%P``Z@0`4^,"```:Y`&?Y?[__^L2``#J"`!3XP(``!K4 -M`9_E_O__ZPT``.H0`%/C`@``&L0!G^7^___K"```ZB``4^,"```:M`&?Y?[_ -M_^L#``#J0`!3XP$``!JD`9_E_O__Z^0!G^7T$9_E"""@X04# -M`%/C(```FB@PE>4"`%/C`@``&@0!G^7^___K%P``Z@0`4^,"```:]`"?Y?[_ -M_^L2``#J"`!3XP(``!KD`)_E_O__ZPT``.H0`%/C`@``&M0`G^7^___K"``` -MZB``4^,"```:Q`"?Y?[__^L#``#J0`!3XP$``!JT`)_E_O__Z_@`G^4$$9_E -M_O__ZP<`6.$0```J`6"(XG9@[^8&`%?A1```.@@PE.4!(*#C$B83X`$@H`," -M```*/P``ZA(6$^`]```:`6"&XG9@[^8&`%?A^?__*C<``.H'`%CA!V"@$34` -M`!H/,-3E``!3XP<```H,(-3E`0!2XP$PH!,,,,05"&"@$2P``!H!`%/C*0`` -M"@`PH.,,,,3E"&"@X28``.K$)```T"0``-PD``#L)```_"0```@E```T)0`` -M<%0``%PE``!(5```>"4``*@E``#$)0``["4``%0F``#850``>"8``*@F``#D -M)@``/"<``&@G``",)P``L"<``-PG````*```,"@```PG``!,*```)%8``'`H -M``#$)```T"0``-PD``#L)```_"0```@E``"L*```<%0```A@H.$R(-3E`#`` -MXP`P0.,S$-3E`3"#X/`QT^4$,(/B`P!2X0`PH`,R,,0%`2""$C(@Q!408,3E -MT('%X0(,H.,`$*#C`"`(X`$P">`#$)+A?```"A@PE>4#`%/C*```FB@PE>4" -M`%/C`@``&I0`'^7^___K%P``Z@0`4^,"```:I``?Y?[__^L2``#J"`!3XP(` -M`!JT`!_E_O__ZPT``.H0`%/C`@``&L0`'^7^___K"```ZB``4^,"```:U``? -MY?[__^L#``#J0`!3XP$``!KD`!_E_O__ZQ0!'^4,$1_E!B"@X?[__^O08<7A -M`@R@XP`0H.,`(`;@`3`'X`,0DN%0```*&#"5Y00`4^--``":*#"5Y0(`4^," -M```:1`$?Y?[__^L7``#J!`!3XP(``!I4`1_E_O__ZQ(``.H(`%/C`@``&F0! -M'^7^___K#0``ZA``4^,"```:=`$?Y?[__^L(``#J(`!3XP(``!J$`1_E_O__ -MZP,``.I``%/C`0``&I0!'^7^___KP`$?Y;P1'^4R(-3E,S#4Y?[__^O08<7A -M`@R@XP`0H.,`(`;@`3`'X`,0DN$C```*&#"5Y00`4^,@``":*#"5Y0(`4^," -M```:^`$?Y?[__^L7``#J!`!3XP(``!H(`A_E_O__ZQ(``.H(`%/C`@``&A@" -M'^7^___K#0``ZA``4^,"```:*`(?Y?[__^L(``#J(`!3XP(``!HX`A_E_O__ -MZP,``.I``%/C`0``&D@"'^7^___K<`(?Y7`2'^7^___K$"#4Y1$PU.4#`%+A -M"```&@`P`.,`,$#C`"#3Y0$@@N)R(._F`"##Y0,`4N,%``"*-P``Z@`P`.,` -M,$#C`""@XP`@P^4R``#J!0"@X000H.$!(*#CV?K_Z]!AQ>$"#*#C`!"@XP`@ -M!N`!,`?@`Q"2X2,```H8,)7E`P!3XR```)HH,)7E`@!3XP(``!K\`A_E_O__ -MZQ<``.H$`%/C`@``&@P#'^7^___K$@``Z@@`4^,"```:'`,?Y?[__^L-``#J -M$`!3XP(``!HL`Q_E_O__ZP@``.H@`%/C`@``&CP#'^7^___K`P``ZD``4^,! -M```:3`,?Y?[__^ML`Q_E4!,?Y?[__^L`,`#C`#!`XP`@H.,`(,/E$"#4Y1$@ -MQ.4`,`#C`#!`XX(P@^!/+X/BL"#2X6D_@^*P,-/A`S""X,,PH.$4,(3E&#"$ -MY=!AQ>$"#*#C`!"@XP`@!N`!,`?@`Q"2X2,```H8,)7E!`!3XR```)HH,)7E -M`@!3XP(``!KL`Q_E_O__ZQ<``.H$`%/C`@``&OP#'^7^___K$@``Z@@`4^," -M```:#`0?Y?[__^L-``#J$`!3XP(``!HD`0*#A`5"@X0)@H.'0@<#A`@R@XP`0H.,`(`C@`3`)X`,0DN$E```* -M&#"4Y00`4^,B``":*#"4Y0(`4^,"```:G`"?Y?[__^L7``#J!`!3XP(``!J, -M`)_E_O__ZQ(``.H(`%/C`@``&GP`G^7^___K#0``ZA``4^,"```:;`"?Y?[_ -M_^L(``#J(`!3XP(``!I<`)_E_O__ZP,``.I``%/C`0``&DP`G^7^___K2`"? -MY4@0G^4%(*#A!C"@X?[__^L'`%7C`#"@DP$PH(,``%3C`3"#`P``4^,%0X0` -MS6#$!7"#O>C$)```T"0``-PD``#L)```_"0```@E``#4*```0%8``/!'+>D` -M,*#A!P!1XP`@H),!(*"#``!0XP$@@@,``%+C`$"@$R\``!H!4*#A`2.`X/9` -MTN70@<#A`FR@XP!PH.,&``C@!Q`)X`$@D.$E```*&""3Y00`4N,B``":*#"3 -MY0(`4^,"```:@`"?Y?[__^L7``#J!`!3XP(``!IP`)_E_O__ZQ(``.H(`%/C -M`@``&F``G^7^___K#0``ZA``4^,"```:4`"?Y?[__^L(``#J(`!3XP(``!I` -M`)_E_O__ZP,``.I``%/C`0``&C``G^7^___K+`"?Y2P0G^4%(*#A!#"@X?[_ -M_^L$`*#A\(>]Z,0D``#0)```W"0``.PD``#\)```""4``/`H``!85@``\$$"#*#C`!"@XP`@!N`!,`?@`Q"2X28```H8,)7E!`!3XR,``)HH,)7E`@!3 -MXP(``!J(`)_E_O__ZQ<``.H$`%/C`@``&G@`G^7^___K$@``Z@@`4^,"```: -M:`"?Y?[__^L-``#J$`!3XP(``!I8`)_E_O__ZP@``.H@`%/C`@``&D@`G^7^ -M___K`P``ZD``4^,!```:.`"?Y?[__^L$,X7@,`"?Y3`0G^4$(*#AS##3Y?[_ -M_^L$0X7@S`#4Y?"!O>C$)```T"0``-PD``#L)```_"0```@E```T*0``E%8` -M`/!!+>D`4*#AT&'`X0(,H.,`$*#C`"`&X`$P!^`#$)+A(P``"A@PE>4#`%/C -M(```FB@PE>4"`%/C`@``&IP`G^7^___K%P``Z@0`4^,"```:C`"?Y?[__^L2 -M``#J"`!3XP(``!I\`)_E_O__ZPT``.H0`%/C`@``&FP`G^7^___K"```ZB`` -M4^,"```:7`"?Y?[__^L#``#J0`!3XP$``!I,`)_E_O__ZT@`G^5($)_E_O__ -MZP!`H..\2\7A!0"@X000H.'^___K`4"$XG1`[^8(`%3C^/__&@``H./P@;WH -MQ"0``-`D``#<)```["0``/PD```()0``3"D``*Q6``#00"WI`$"@X=!AP.$" -M#*#C`!"@XP`@!N`!,`?@`Q"2X2,```H8,)3E`P!3XR```)HH,)3E`@!3XP(` -M`!J$`)_E_O__ZQ<``.H$`%/C`@``&G0`G^7^___K$@``Z@@`4^,"```:9`"? -MY?[__^L-``#J$`!3XP(``!I4`)_E_O__ZP@``.H@`%/C`@``&D0`G^7^___K -M`P``ZD``4^,!```:-`"?Y?[__^LP`)_E,!"?Y?[__^LH,)3E$`!3XP$PH`/` -M,L0%T("]Z,0D``#0)```W"0``.PD``#\)```""4``%PI``#`5@``\$\MZ3S0 -M3>(`4*#A`6"@X0*PH.$@,(WET('`X0(,H.,`$*#C`"`(X`$P">`#$)+A)@`` -M"A@PE>4#`%/C(P``FB@PE>4"`%/C`@``&C0)G^7^___K%P``Z@0`4^,"```: -M)`F?Y?[__^L2``#J"`!3XP(``!H4"9_E_O__ZPT``.H0`%/C`@``&@0)G^7^ -M___K"```ZB``4^,"```:]`B?Y?[__^L#``#J0`!3XP$``!KD")_E_O__ZP"P -MC>7<")_EW!B?Y2`@G>5@,)WE_O__ZZNQH.%\@@GC`$"@XP`P`.,`,$#C-#"- -MY0`P`.,`,$#C)#"-Y:,O@^(H((WE`#``XP`P0.,L,(WE`#``XP`P0.,P,(WE -M!P!4XP1PH(%9`0"*'P!4XR`P1((!(*"#8!"=A1(S`8`!,*"3(""=E1,T`I`$ -M<*#A``!3XTX!``H$,X7@V*"#XK`0UN&T$,KAVI"#X@(@UN6T(,GAW,"#X@,@ -MUN6T(,SAW@"#X@0@UN6T(,#AX!"#X@4@UN6T(,'A!B#6Y>@P@^*T(,/AM)#9 -MX;2@VN$*D(G@M*#"TH-#A"I")X+2@T>$*D(G@`I")X`"0@^4``%GC -M`P$`"@(,H.,`$*#CT"'%X0`@`N`!,`/@`Q"2X3<```H8,)7E`P!3XS0``)HH -M,)7E`@!3XP(``!J`!Y_E_O__ZQ<``.H$`%/C`@``&G`'G^7^___K$@``Z@@` -M4^,"```:8`>?Y?[__^L-``#J$`!3XP(``!I0!Y_E_O__ZP@``.H@`%/C`@`` -M&C``G>7^___K`P``ZD``4^,!```:+`"=Y?[__^L'(X7@Z#""XKP=TN$`$(WE -MOAW2X000C>6P'M+A"!"-Y;(>TN$,$(WEM"[2X1`@C>6T(-/A%""-Y2`@G>48 -M((WE8!"=Y1P0C>7L!I_E*!"=Y00@H.$`,)/E_O__ZP,0A^(!$X7@!S.%X/0P -MT^4``%/CNP``"@#[,-/E!`!3XP(``(H%`*#AA?C_ZZD``.H%`%/C:``` -M&@#P((/B`!"@XP40PN7Z,-/E`P!3XP/QGY<>``#JC#D$`'`Y!`!4.00` -M.#D$``#0,-/E&`!3XP#0,-/E`@!3XP#-(-/E+P!2X_`P@Y(`(*"3!B## -ME38``)H',X7@]3#3Y0$`4^,L```:!S.%X/#Y,-/E -M!1""X@$`4^$'``#*!2!"X@(`4^$$``"Z!S.%X-`@T^7X,-/E`P!2X1(```H' -M,X7@]C#3Y0``4^,',X4``2"@`_8@PP4$```*`0!3XP`#(*`#!2"@$_8@ -MP^4',X7@S2#3Y?D@P^7P,(/B`""@XP<@P^4.``#J!S.%X/@@@^(`$*#C`Q#" -MY?`P@^('(-/E`2""X@<@P^4%``#J!R.%X/`0@N(`,*#C!C#!Y?@@@N(#,,+E -M!S.%X-`@T^7X(,/E/@``Z@#HD)/EB9*@X;P]T^$B(*#CDP(#X`,`6>$` -M(*`S$0``.B0@G>6J#X+B`2"@XPB@H.$!P-#EOH'1X9@\(^`#`%GA!P``.@$@ -M@N)R(._F`A"!X@$`@.(%`%+C]/__&@J`H.$```#J"H"@X:(@H.$',X7@]A#3 -MY0$0@>*A$*#A`0!2X0`0H",!$&(P<1#O-@#X,(/B!"#3Y2(!H.&B((#@ -M`B""X@$B@N!R(._F!"##Y<``4N,$``":!S.%X#\@X./\(,/E!C"@XP(``.JB -M,J#A!C`3X@$```H!,$/B"\+M+A`P!2XP`PH(,'(X7@]C#"Y0#[,-/E!0!3XP4#`%/C -M(```FB@PE>4"`%/C`@``&G`#G^7^___K%P``Z@0`4^,"```:8`.?Y?[__^L2 -M``#J"`!3XP(``!I0`Y_E_O__ZPT``.H0`%/C`@``&D`#G^7^___K"```ZB`` -M4^,"```:,`"=Y?[__^L#``#J0`!3XP$``!HL`)WE_O__ZS0`G>4H$)WE_O__ -MZP=SA>"P/]?A`P!8X0.`H"$!0(3B=$#OY@0`6^$(8(:"F?[_BM!AQ>$"#*#C -M`!"@XP`@!N`!,`?@`Q"2X2,```H8,)7E!`!3XR```)HH,)7E`@!3XP(``!J@ -M`I_E_O__ZQ<``.H$`%/C`@``&I`"G^7^___K$@``Z@@`4^,"```:@`*?Y?[_ -M_^L-``#J$`!3XP(``!IP`I_E_O__ZP@``.H@`%/C`@``&F`"G^7^___K`P`` -MZD``4^,!```:4`*?Y?[__^M8`I_E6!*?Y?[__^N\.]7A"`!3X3````K08<7A -M`@R@XP`0H.,`(`;@`3`'X`,0DN$E```*&#"5Y0,`4^,B``":*#"5Y0(`4^," -M```:Z`&?Y?[__^L7``#J!`!3XP(``!K8`9_E_O__ZQ(``.H(`%/C`@``&L@! -MG^7^___K#0``ZA``4^,"```:N`&?Y?[__^L(``#J(`!3XP(``!JH`9_E_O__ -MZP,``.I``%/C`0``&I@!G^7^___KJ`&?Y:`1G^6\*]7A"#"@X?[__^L``)7E -M"!"@X?[__^N\B\7AT&'%X0(,H.,`$*#C`"`&X`$P!^`#$)+A3@``"A@PE>4$ -M`%/C)P``FB@PE>4"`%/C`@``&B0!G^7^___K%P``Z@0`4^,"```:%`&?Y?[_ -M_^L2``#J"`!3XP(``!H$`9_E_O__ZPT``.H0`%/C`@``&O0`G^7^___K"``` -MZB``4^,"```:Y`"?Y?[__^L#``#J0`!3XP$``!K4`)_E_O__Z^@`G^7<$)_E -M_O__Z]!AQ>$"#*#C`!"@XP`@!N`!,`?@`Q"2X2,```H8,)7E`P!3XR```)HH -M,)7E`@!3XP(``!IX`)_E_O__ZQ<``.H$`%/C`@``&F@`G^7^___K$@``Z@@` -M4^,"```:6`"?Y?[__^L-``#J$`!3XP(``!I(`)_E_O__ZP@``.H@`%/C`@`` -M&C@`G^7^___K`P``ZD``4^,!```:*`"?Y?[__^M``)_E)!"?Y?[__^L\T(WB -M\(^]Z,0D``#0)```W"0``.PD``#\)```""4``(`I``#45@``T"D``#@J``#X -M5@``8"H``)0J``"\*@``$$`MZ0$@H.%/'J#C_O__ZQ"`O>CP32WI"-!-X@!` -MH.$!4*#A`F"@X0-PH.$H@-WET*'`X0(,H.,`$*#C`"`*X`$P"^`#`)+A)@`` -M"A@PE.4#`%/C(P``FB@PE.4"`%/C`@``&L0$G^7^___K%P``Z@0`4^,"```: -MM`2?Y?[__^L2``#J"`!3XP(``!JD!)_E_O__ZPT``.H0`%/C`@``&I0$G^7^ -M___K"```ZB``4^,"```:A`2?Y?[__^L#``#J0`!3XP$``!IT!)_E_O__ZX`! -MC>AL!)_E;!2?Y04@H.$&,*#A_O__ZP<`5>,`,*"3`3"@@P``5.,!,(,#``!3 -MXP@!`!H#,(7B`V/$YP,CA.`$<(+E!2.$X,^`PN4#,]3G#P!3XP/QGY=<``#J -M,$$$`$Q!!`!H000`A$$$`*!!!`"\000`T$$$`&1"!`!D0@0`9$($`&1"!`!D -M0@0`Y$$$``1"!``D0@0`1$($``4CA.#$$)+E%3`/XX\_0.,#,`'@R#""Y4@` -M`.H%(X3@Q!"2Y1`P#^.//T#C`S`!X,@P@N5!``#J!2.$X,00DN4%,`_CCS]` -MXP,P`>#(,(+E.@``Z@4CA.#$$)+E`#`/XX\_0.,#,`'@R#""Y3,``.H%(X3@ -MQ!"2Y?4_`.,`,$#C`S`!X,@P@N4L``#J!3.$X,0@D^7_+@+BR""#Y2<``.H% -M,X3@Q""3Y0T@`N+(((/E(@``Z@0`H.%$%`#C_O__ZP4SA.#$()/E`B``X,@@ -M@^4:``#J!`"@X4@4`./^___K!3.$X,0@D^4"(`#@R""#Y1(``.H$`*#A3!0` -MX_[__^L%,X3@Q""3Y0(@`.#(((/E"@``Z@0`H.%%'J#C_O__ZP4SA.#$()/E -M`B``X,@@@^4"``#J!3.$X,0@D^7(((/E!3.$X,@@D^4``%+C#@``"@$"$N,< -M,*`3!```&ALPH.,!$*#C$0,2X`,```IS,._F!2.$X-(PPN4'``#J`3!#X@$` -M<^/V__\:!P``Z@4SA.#0,(/B`""@XP(@P^4%,X3@R#"3Y0``4^,0```*!3.$ -MX,@@D^4!`!+C`#"@$P0``!H!,*#C`Q"@X1$#$N`#```*4X`)_E,!"?Y00PD^7^___K"-"-XO"-O>C$)```T"0` -M`-PD``#L)```_"0```@E``#H*@``$%<``"`K```L5P``3"L``![_+^$`,*#C -M3S3`Y4TTP.5.-,#E4#3`Y4PTP.4>_R_A3P30Y1[_+^$>_R_AT$`MZ0!`H.$\ -M,-#E`0!3X]"`O1@H-)#E%C3`Y=!AP.%``*#C`!"@XP`@!N`!,`?@`Q"2X="` -MO0@8,)3E`P!3X]"`O9@H,)3E`@!3XP(``!IX`)_E_O__ZQ<``.H$`%/C`@`` -M&F@`G^7^___K$@``Z@@`4^,"```:6`"?Y?[__^L-``#J$`!3XP(``!I(`)_E -M_O__ZP@``.H@`%/C`@``&C@`G^7^___K`P``ZD``4^,!```:*`"?Y?[__^LD -M`)_E)!"?Y2@DE.7^___KT("]Z*0K``"P*P``O"L``,PK``#<*P``Z"L``/0K -M``!$5P``\$\MZ2303>(`4*#AQ1Z@XX`@H.,!,*#C_O__ZP5`H.$%@*#A`!"@ -MXQ`0C>4($(WE`;"@X?\@H.,,((WE`9"@X0`P`.,`,$#C%#"-Y0`P`.,`,$#C -M&#"-Y0`P`.,`,$#C'#"-Y9PPE.4``%/C>P$`"K03E.4``%'C`'"@`P(```IT -M`Y3E_O__ZP!PH.'4$Y3E``!1XP!@H`,"```*E`.4Y?[__^L`8*#A!@!7X0"@ -MH(,!H*"30`"@XP`0H./0(<7A`"`"X`$P`^`#$)+AA```"A@PE>4#`%/C@0`` -MFB@PE>4"`%/C`@``&L`&G^7^___K%P``Z@0`4^,"```:L`:?Y?[__^L2``#J -M"`!3XP(``!J@!I_E_O__ZPT``.H0`%/C`@``&I`&G^7^___K"```ZB``4^," -M```:@`:?Y?[__^L#``#J0`!3XP$``!IP!I_E_O__Z[0SE.4`,(WE9`:?Y606 -MG^4)(*#A=#.4Y?[__^M``*#C`!"@X]`AQ>$`(`+@`3`#X`,0DN%5```*&#"5 -MY0,`4^-2``":*#"5Y0(`4^,"```:!`:?Y?[__^L7``#J!`!3XP(``!KT!9_E -M_O__ZQ(``.H(`%/C`@``&N0%G^7^___K#0``ZA``4^,"```:U`6?Y?[__^L( -M``#J(`!3XP(``!K$!9_E_O__ZP,``.I``%/C`0``&K0%G^7^___KU#.4Y0`P -MC>6P!9_EJ!6?Y0D@H.&4,Y3E_O__ZT``H.,`$*#CT"'%X0`@`N`!,`/@`Q"2 -MX28```H8,)7E`P!3XR,``)HH,)7E`@!3XP(``!I(!9_E_O__ZQ<``.H$`%/C -M`@``&C@%G^7^___K$@``Z@@`4^,"```:*`6?Y?[__^L-``#J$`!3XP(``!H8 -M!9_E_O__ZP@``.H@`%/C`@``&@@%G^7^___K`P``ZD``4^,!```:^`2?Y?[_ -M_^L`8(WE_`2?Y?`4G^4)(*#A!S"@X?[__^L'`%;A!C"@(04``%/C -M``!7`P9PH`$"```*`0!3XP``5@,'8*`!!P!6X0=@H"$,,)WE`P!6X1"@C34, -M8(TU!0"@X608`.,X(*#C"C"@X?[__^L%`*#A9!@`XP%``*#C`!"@ -MXP`@!N`!,`?@`Q"2X:@```H8,)7E`P!3XZ4``)HH,)7E`@!3XP(``!K4`Y_E -M_O__ZQ<``.H$`%/C`@``&L0#G^7^___K$@``Z@@`4^,"```:M`.?Y?[__^L- -M``#J$`!3XP(``!JD`Y_E_O__ZP@``.H@`%/C`@``&I0#G^7^___K`P``ZD`` -M4^,!```:A`.?Y?[__^L4`)WE@!.?Y0H@H.'^___KT&'%X4``H.,`$*#C`"`& -MX`$P!^`#$)+A?```"A@PE>4#`%/C>0``FB@PE>4"`%/C`@``&B0#G^7^___K -M%P``Z@0`4^,"```:%`.?Y?[__^L2``#J"`!3XP(``!H$`Y_E_O__ZPT``.H0 -M`%/C`@``&O0"G^7^___K"```ZB``4^,"```:Y`*?Y?[__^L#``#J0`!3XP$` -M`!K4`I_E_O__ZQ@`G>70$I_E7"/8Y?[__^O08<7A0`"@XP`0H.,`(`;@`3`' -MX`,0DN%0```*&#"5Y0,`4^--``":*#"5Y0(`4^,"```:=`*?Y?[__^L7``#J -M!`!3XP(``!ID`I_E_O__ZQ(``.H(`%/C`@``&E0"G^7^___K#0``ZA``4^," -M```:1`*?Y?[__^L(``#J(`!3XP(``!HT`I_E_O__ZP,``.I``%/C`0``&B0" -MG^7^___K'`"=Y2`2G^5D(]CE_O__Z]!AQ>%``*#C`!"@XP`@!N`!,`?@`Q"2 -MX20```H8,)7E`P!3XR$``)HH,)7E`@!3XP(``!K$`9_E_O__ZQ<``.H$`%/C -M`@``&K0!G^7^___K$@``Z@@`4^,"```:I`&?Y?[__^L-``#J$`!3XP(``!J4 -M`9_E_O__ZP@``.H@`%/C`@``&H0!G^7^___K`P``ZD``4^,!```:=`&?Y?[_ -M_^N``9_E4#`%+A"0``&@4`H.%D&`#C.""@X_[__^L%`*#A -M9!@`XP708<7A0`"@XP`0H.,`(`;@`3`'X`,0 -MDN$D```*&#"5Y0,`4^,A``":*#"5Y0(`4^,"```:B`"?Y?[__^L7``#J!`!3 -MXP(``!IX`)_E_O__ZQ(``.H(`%/C`@``&F@`G^7^___K#0``ZA``4^,"```: -M6`"?Y?[__^L(``#J(`!3XP(``!I(`)_E_O__ZP,``.I``%/C`0``&C@`G^7^ -M___K2`"?Y300G^40()WE_O__ZRBTA>4(()WE+"2%Y230C>+PC[WHI"L``+`K -M``"\*P``S"L``-PK``#H*P``."P``%Q7``!D+```D"P``/PL```0+0``\$$M -MZ2@0D.40`%'C`@``&B`PD.5``!/C*@``&M!AP.%`0*#C`%"@XP0@!N`%,`?@ -M`\"2X?"!O0@8,)#E`P!3X_"!O9@"`%'C`@``&M0`G^7^___K%P``Z@0`4>," -M```:Q`"?Y?[__^L2``#J"`!1XP(``!JT`)_E_O__ZPT``.H0`%'C`@``&J0` -MG^7^___K"```ZB``4>,"```:E`"?Y?[__^L#``#J0`!1XP$``!J$`)_E_O__ -MZX``G^6`$)_E_O__Z_"!O>B6,-#E``!3XP\``!K08<#A0$"@XP!0H.,$(`;@ -M!3`'X`,0DN'P@;T(&#"0Y0,`4^/P@;V8,`"?Y?[__^L\`)_E-!"?Y?[__^OP -M@;WH/##0Y0$`4^/P@;T8_O__Z_"!O>BD*P``L"L``+PK``#,*P``W"L``.@K -M```D+0``<%<``%PM``#P02WI`$"@X=!AP.%``*#C`!"@XP`@!N`!,`?@`Q"2 -MX2,```H8,)3E`P!3XR```)HH,)3E`@!3XP(``!I,`I_E_O__ZQ<``.H$`%/C -M`@``&CP"G^7^___K$@``Z@@`4^,"```:+`*?Y?[__^L-``#J$`!3XP(``!H< -M`I_E_O__ZP@``.H@`%/C`@``&@P"G^7^___K`P``ZD``4^,!```:_`&?Y?[_ -M_^OX`9_E^!&?Y?[__^L$`*#A!#"@X0`0H.,!(*#A]"+`Y0`C@^4<(X/E.".# -MY0$0@>(!`(#B!#"#X@8`4>/V__\:`%"@XUA3A.544\3E!`"@X4P0H.,`(.#C -M_O__ZPHU@.,$`*#A3!"@XP`@X./^___K!`"@X;07`.,`(.#C_O__ZP,X@.,$ -M`*#AM!<`XP`@X./^___K!`"@X;07`./_+P_C!3"@X?[__^L$`*#A>QZ@XP`@ -MX.,%,*#A_O__ZP0`H.&''J#C`RR@XP4PH.'^___K!`"@X608`.,!*Z#C!3"@ -MX?[__^L$`*#A+!L`XP$EH.,%,*#A_O__ZP0`H.$L&P#C`B&@XP$PH./^___K -M!`"@X:0<`.,`(.#CH#"@X_[__^N9,-3E!0!3X0H``!H$`*#A6!@`XPBD*P`` -ML"L``+PK``#,*P``W"L``.@K``"L+0``I%<``-!`+>D`0*#AT&'`X4``H.,` -M$*#C`"`&X`$P!^`#$)+A(P``"A@PE.4#`%/C(```FB@PE.4"`%/C`@``&A`! -MG^7^___K%P``Z@0`4^,"```:``&?Y?[__^L2``#J"`!3XP(``!KP`)_E_O__ -MZPT``.H0`%/C`@``&N``G^7^___K"```ZB``4^,"```:T`"?Y?[__^L#``#J -M0`!3XP$``!K``)_E_O__Z[P`G^6\$)_E_O__ZP0`H.%,$*#C`"#@X_[__^L* -M-8#C!`"@X4P0H.,`(.#C_O__ZP0`H.&''J#C`RR@XP`PH./^___K!`"@X608 -M`.,!*Z#C`#"@X_[__^L$`*#A+!L`XP$EH.,!,*#C_O__ZP0`H.$L&P#C`B&@ -MXP$PH./^___K!`"@X:0<`.,`(.#CH#"@X_[__^L$`*#AQ1Z@XX`@H.,!,*#C -M_O__Z]"`O>BD*P``L"L``+PK``#,*P``W"L``.@K``#,+0``O%<``-!`+>D` -M0*#A*#"0Y1``4^/0@+T8T&'`X4``H.,`$*#C`"`&X`$P!^`#$)+A.@``"A@P -ME.4#`%/C-P``FA@!G^7^___K%`&?Y101G^4\(-3E_O__Z]!AQ.%``*#C`!"@ -MXP`@!N`!,`?@`Q"2X2H```H8,)3E`P!3XR<``)HH,)3E`@!3XP(``!K8`)_E -M_O__ZQ<``.H$`%/C`@``&L@`G^7^___K$@``Z@@`4^,"```:N`"?Y?[__^L- -M``#J$`!3XP(``!J0`)_E_O__ZP@``.H@`%/C`@``&I0`G^7^___K`P``ZD`` -M4^,!```:A`"?Y?[__^N9$-3E``!1XP`@`.,`($#C`#``XP`P0.,#(*`!9`"? -MY4@0G^7^___K/##4Y0(`4^,"```:!`"@X?[__^O0@+WH`0!3XP(``!H$`*#A -M_O__Z]"`O>@$`%/CT("]&`0`H.'^___KT("]Z,PK``#L+0``T%<``*0K``"P -M*P``O"L``-PK``#H*P``'"X``/!/+>D,T$WB!`"-Y0&@H.$"@*#A`["@X3!` -MG>4`D*#C!G#4Y050U.6P8-3A!`#4Y5`"X^<#,-3E4Q+CYP(@U.4/,`/B`P`8 -MX2\```H"`!KA+0``"@$`&^$K```*`0!`X@,`4.,`\9^7)P``ZH!7!`"L5P0` -M]%<$`'A7!``!`*#C)```Z@0`G>4&$*#A_O__ZP4@P.$'4`7@!2""X00`G>4& -M$*#A4&$*#A_O__ZP4``.```%?A`3"@`P(` -M``H*`*#C_O__ZP`PH..((P'C`@!9X0H``(H!D(GB``!3X^___PH$``#J``!7 -MXP8`H`'Z/Z`3DP8`$/[__^L(0(3BPO__Z@``H.,,T(WB\(^]Z```X.&@#Z#A -M'O\OX0``@.4$`(#E'O\OX0`PD.4``%/A``"@$P$`H`,>_R_A`#"1Y00`@^4` -M,(#E!!"`Y0``@>4>_R_A!#"1Y00`@>4*`(#H``"#Y1[_+^$$,(#B"@"`Z`@P -M@.4>_R_A'O\OX1[_+^$>_R_A'O\OX0T@H.%_/<+C/S##XP0@D^4!((+B!""# -MY1[_+^$-(*#A?SW"XS\PP^,$()/E`2""X@0@@^4>_R_A$$`MZ?[__^L0@+WH -M$$`MZ?[__^L0@+WH``!1X0``H!,!`*`#'O\OX0`P`.,`,$#C``"3Y1[_+^'Z -M/Z#CDP`#X!\E"./K(47CDA."X*("H.$>_R_A`#``XP`P0.,`,)/E`S!@X/HO -MH..2`P/@'R4(X^LA1>.2$X+@H@*@X1[_+^$!$&#@^C^@XY,!`>`?-0CCZS%% -MXY,A@^"C`J#A'O\OX0`0@.4>_R_A``"0Y1[_+^&?/Y#A`3"#X),O@.$``#+C -M^O__&A[_+^&?/Y#A`3!#X),O@.$``#+C^O__&A[_+^&?/Y#A`3"#XI,O@.$` -M`#+C^O__&A[_+^&?/Y#A`3!#XI,O@.$``#+C^O__&A[_+^$`,*#AGP^3X0$` -M@."0+X/A```RX_K__QH>_R_A`#"@X9\/D^$!`$#@D"^#X0``,N/Z__\:'O\O -MX0`PH.&?#Y/A`0"`XI`O@^$``#+C^O__&A[_+^$`,*#AGP^3X0$`0.*0+X/A -M```RX_K__QH>_R_A\$$MZ0!0H.$!<*#A`F"@X1`PD.4``%/C&```"@@PD^4` -M`%/C%0``"@``4N,`0*#3$```VB"`@.(`0*#C$,"5Y04`H.$$$(?@!B!DX`@P -MH.$/X*#A"/"@``.#C\(&]Z!!`+>D"0*#A_O__ZP(`H.$#$*#A$("]Z!!`+>D"0*#A -M_O__ZP$`H.$`$*#C$("]Z'!`+>D`0*#A`5"@X0@`H.,!$*#C`2"@X?[__^L` -M`%#C`#"@$0!4HQ4$0(,5<("]Z!!`+>D`0*#A`0"@X0(0H.$#(*#A_O__ZP$* -M<.,`,*"#`#"$A0``A)4``*"3$("]Z!!`+>D`$*#C_O__ZP``H.,0@+WH\$("<*#A`#"@X0%0H.$``%#C``!1$Q5`X`,O```*!`"-X@,0H.%!(*#C -MMC$`X^#__^L`0%#B*```&@T@H.%_/<+C/S##XPB0D^4`(*#C"""#Y01@G>40 -M,);E`@!3X1<```H,,)/E`@!3X10```H`@%?B$P``VB"@AN($<*#A$,"6Y08` -MH.$'$(7@""!GX`HPH.$/X*#A#/"7!___K -MQ`_$X0C0C>+PA[WH\$$MZ0C03>("8*#A`#"@X0%0H.$``%#C``!1$Q5`X`,4 -M```*!`"-X@,0H.$`(*#C`C"@X:3__^L`0%#B#0``&@TPH.%_?4%$*#A!B"@X5[__^L`0*#A"("'Y00`G>6@___KQ`_$ -MX0C0C>+P@;WH<$`MZ0C03>(`$*#C`2"@X?[__^L`0*#A`0IPXP!0H($2``"* -M#2"@X7\]PN,_,,/C"&"3Y0`@H.,(((/E!Q"-X@$@H.-%___K`0!0XP10H!$` -M4*`##2"@X7\]PN,_,,/C"&"#Y00`H.$`$*#C_O__ZP$`=>(``*`S"-"-XG"` -MO>@00"WI`"``XP`@0.,`,0#C$#!`XP`@DN4#`%+A$("]"``@`.,`($#C`#(` -MXR`P0.,$()+E`P!2X1"`O0@```#C``!`X_[__^L0@+WH$$`MZ0`@`.,`($#C -M`#$`XQ`P0.,`()+E`P!2X1"`O0@`(`#C`"!`XP`R`.,@,$#C!""2Y0,`4N$0 -M@+T(````XP``0./^___K$("]Z!!`+>D`(`#C`"!`XP`Q`.,0,$#C`""2Y0,` -M4N$0@+T(`"``XP`@0.,`,@#C(#!`XP0@DN4#`%+A$("]"````.,``$#C_O__ -MZQ"`O>@00"WI````XP``0.,`$*#C`"``XP`@0./^___K$("]Z!!`+>G^___K -M$("]Z!!`+>G^___K$("]Z'!`+>D`0%#B<("]"+!5!N-F5D#C!0"@X?[__^L! -M0%3B^___&G"`O>@00"WI?0Y0XP$`H*/3/02S8C!!LY,@P[#`#Z"Q0P-@L`$` -M@++^___K$("]Z!!`+>G^___K$("]Z!!`+>ED,*#CDP``X-,M!.-B($'CDC#" -MX,`/H.%"`V#@``!0XP$`H`,-(*#A?SW"XS\PP^,,,)/E`2"@XP`@@^7^___K -M$("]Z!!`+>D-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^4`,)/E`@`3XQ"`O0C^ -M___K$("]Z!!`+>D-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^4`,)/E`@`3XQ"` -MO0C^___K$("]Z!!`+>D`$`#C`!!`XP0@G^7^___K$("]Z*`X```00"WI_O__ -MZP$`<.(``*`S$("]Z!!`+>G^___K$("]Z!!`+>D``%+C$("]"/[__^L0@+WH -M$$`MZ?[__^L!`'#B``"@,Q"`O>@00"WI_O__ZQ"`O>AP0"WI`$"@X0%@H.$( -M/`/C`U"0YP``4.,O```*##P#XP,`D.<``%#C`P``"O[__^L`(*#C##P#XP,@ -MA.?^___K``!0XP(``!H%`*#A_O__ZP(``.H%`*#A`!"@X_[__^L,/`/C`U"$ -MYP0`H.'^___K`%!0XA@```I@,)3E(#"#XC`RA>5@`)3E(`"`X@40H.'^___K -M!0"@X080H.'^___K=`&5Y0T;A.(1$('B!B"@X_[__^O^___K``!0XP(``!H% -M`*#A_O__ZP$``.H%`*#A_O__ZP``4.-P@+T(``#@XW"`O>@00"WI_O__ZQ"` -MO>@00"WID0("X`$1H.&3$B'@_O__ZQ"`O>@00"WI(!"@X_[__^L0@+WH<$`M -MZ0!0H.'^___K`$!0X@0```H``%7C`@``"@0`H.$%$*#A_O__ZP0`H.%P@+WH -M\$$MZ0!`H.$!4*#A`F"@X0!QH.&0`0#@DG`@X/[__^L`(*#A``!0X_"!O0@` -M`%3C!P``VI4&!>`'<(#@`#"@XP-Q@.@00"WI_O__ZQ"`O>@00"WI`$!0XA"`O0@`!)3E``!0XQ"`O0C^___K!`"@ -MX?[__^L0@+WH$$`MZ?[__^L0@+WH<$`MZ0!0H.'^___K`$!0X@0```H``%7C -M`@``"@0`H.$%$*#A_O__ZP0`H.%P@+WH\$$MZ0!`H.$(`*#C`1"@XP$@H.'^ -M___K`&!0XA$```H!>X;B!`"@X?[__^L`4*#A`("@X0``4.,#```*``!4XP$` -M``H$$*#A_O__ZP"`A^4``%7C!$"'%0(``!H&`*#A_O__ZP!@H.,&`*#A\(&] -MZ``$D.5(-0'C`R"0YRP\`^,#((#G"#8!XP,@D.,#()#G -M1#P#XP,@@.<0-@'C`R"0Y_$]H.,#((#G53V@XP,@D.D`0*#A_O__ZP$PH./4*P/C`C"$YZPL`^,",(3G -MY#8#XP,PE.<``%/C`@``"@0`H.$'$*#C,_\OX00`H.'^___K`""@X]0[`^,# -M((3G$("]Z'!`+>D`0*#A`#"@XZPL`^,",(#GS"L#XP(P@.?0*P/C`C"`Y]0K -M`^,",(#G`2"@XR0\`^,#((#G_O__ZP``4.,9```*#SN@XP,PE.<``%/C`0`` -M"@0`H.$S_R_A`%``XP!00.,`,)7ER",#XP(@E.=D$*#CD0(!X-,M!.-B($'C -MD@&!X,X-A.(4`(#B(1.#X/[__^L`$)7E4@Z$XGT?@>+^___K`0"@XW"`O>@` -M`*#C)#P#XP,`A.=P@+WH$$`MZ0!`H.'M/:#C#^"@X0/PD.<`,*#CL2P#XP(P -MQ.>R+`/C`C#$Y[,L`^,",,3G'B"@XU0DA.70(P/C`C"$Y]@C`^,",(3GDB,# -MXP(PQ.<``*#C`!"@XT@E`>/R`(3A""8!X_(`A.$8-<3E;""4Y2(MPN-L((3E -MS",#XP(PQ.?(.83E`#``XP`P0.,`,)/EW"8!XP(@E.=D$*#CD0(!X-,M!.-B -M($'CD@&!X%H-A.(H`(#B(1.#X/[__^L!`*#C$("]Z'!`+>D`0*#A_O__ZP0` -MH.'^___K!`"@X?[__^L`4*#AY#8#XP,PE.<``%/C`@``"@0`H.$#$*#C,_\O -MX04`H.%P@+WH<$`MZ0!`H.$(/`/C`U"0YRPZ`^,#,)#G``!3XPX```K=#8#B -M)`"`XO[__^O>#83B&`"`XO[__^O?#83B#`"`XO[__^LL.@/C`S"4YP``4^,` -M(*`3+#H#$P,@A!?R#83B-`"`XO[__^M]#H3B_O__ZP4+A.(H`(#B_O__ZU$- -MA.(P`(#B_O__ZVP`A.+^___K4PV$XB``@.+^___K6PV$XC@`@.+^___K5PV$ -MXA@`@.+^___K!`"@X?[__^L$`*#A$#L#XP_@H.$#\)3G##P#XP,`E.<``%#C -M`P``"O[__^L`(*#C##P#XP,@A.<``%7C`0``"@4`H.'^___K`0"@XW"`O>@0 -M0"WI`$"@X44.@.((`(#B_O__ZTD.A.($`(#B_O__ZU(.A.+^___K!`"@X?[_ -M_^O.#83B%`"`XO[__^O;#83B,`"`XO[__^M:#83B*`"`XO[__^L$`*#A_O__ -MZQ"`O>AP0"WI`$"@X68[`N,#(-#G/#4!XP,@P.=G.P+C`S#0YSTE`>,",,#G -M/B4!XP(PP.=J.P+CLR"0X30U`>,#((#G'C"@XU0T@.4!8*#C6&6`Y0!0H./< -M5(#E(#P!XP-0P.=X.P+C`R#0YR0\`>,#((#G>3L"XP,@T.,#4(#GS#@!XP-0@.?0.`'C`U"`YR0Y`>,#4(#G*#D!XP-@@.

    ,#8(#G_O__ZP0`H.'^___K!`"@X>T]H.,/X*#A`_"4Y[$\`^,#4,3G -MLCP#XP-0Q.>S/`/C`U#$YP8`H.%P@+WH<$`MZ0!`H.$%"X#B*`"`XO[__^L` -M`%#C,@``"FPT`>,#0(3G40V$XC``@.+^___K``!0XRL```H$`*#A_O__ZP`` -M4.,G```*!`"@X?[__^L$`*#A_O__ZP``4.,A```*4PV$XB``@.($$*#A_O__ -MZP``4.,;```*5PV$XA@`@.($$*#A_O__ZP``4.,5```*6PV$XC@`@.+^___K -M``!0XQ````H<.`'C`T"$YP0`H.'^___K!`"@X?[__^L$`*#A_O__ZP!0H.$$ -M`*#A_O__ZP0`H.'^___K\@V$XC0`@.+^___K````Z@!0H.,%`*#A<("]Z!!` -M+>D`0*#A!0N`XB@`@.+^___KZ#L#XP,PE.<``%/C$("]"`4+A.(T`(#B_O__ -MZQ"`O>@00"WI`$"@X0```.,``$#C!!"@X08LH./^___KZ#L#XP,`A.<``%#C -M``"@LQ"`O;@%"X3B-`"`XO[__^L!`*#C$("]Z'!`+>D`4*#A`$20Y0`P`.,` -M,$#C`#"3Y0$`4^,(```:`#``XP`P0.,`,)/E`0!3XP,```J0`I_E_O__ZP`` -MH.-P@+WH`#``XP`P0.,`(*#C`""#Y=0S`^,#,)3G`0!3XP(`H`&L/`,#`P"$ -M!W"`O0@D/`/C`S"4YP``4^,C```:S"L#XP(PA.?0*P/C`C"$Y]0K`^,",(3G -M!`"@X?[__^L``%#C<0``"@0`H.'^___K``!0XVT```H$`*#A_O__ZP``4.-I -M```*#SN@XP,PE.<``%/C`0``"@0`H.$S_R_A!`"@X?[__^OD-@/C`S"4YP`` -M4^,"```*!`"@X0,0H.,S_R_A`2"@XR0\`^,#((3G`""@XZP\`^,#((3G`#`` -MXP`P0.,`$)/E4@Z$XL@0@>+^___KA#,#XP,PU.<``%/C`P``&N(S`^,#,-3G -M``!3XQ````H`(*#CT#,#XP,@A.<`,`#C`#!`XP`PD^7((P/C`B"4YV00H..1 -M`@'@TRT$XV(@0>.2`8'@S@V$XA0`@.(A$X/@_O__Z[`AE>4",*#A"!"SY0$` -M$>,&```:`"`/X8``#/$`$)/E`1#!XP`0@^4"\"'A"0``Z@``#^&```SQ`!"3 -MY0'`P>,`P(/E`/`AX0$`$>,!```*!`"2Y?[__^O^___K"#P#XP,PE.=J/X/B -M`#"3Y0``4^,2```*````XP``0.,`$`#C`!!`X_[__^L`4%#B"P``"CT,A.(, -M`(#B=!&5Y08@H./^___K`"`/X8``#/$`,I7E`!"3Y0$00>(`$(/E`O`AX0$@ -MH.,D/0/C`R"$Y_[__^L``*#C<("]Z``@H.,D/`/C`R"$YP4`H.'^___KL#&5 -MY0``4^,&```:.`"?Y4H7`./^___K,`"?Y?[__^L``.#C<("]Z``@#^&```SQ -M"!"SY0$0@>,`$(/E`O`AX0``X.-P@+WH4"X``)`N``"L+@``$$`MZ0`P`.,` -M,$#C`2"@XP`@@^4``%'C`0``"O[__^L$``#J``20Y?[__^L!`%#C``"@`P`` -MX!,`,`#C`#!`XP`@H.,`((/E$("]Z!!`+>D`!)#E)#P#XP,PD.<``%/C!``` -M&@T+@.(1`(#B`A"!X@8@H./^___K``"@XQ"`O>CP02WI`!!0X@,```HX#0/C -M_O__ZP!PH.$"``#J.`T#X_[__^L`<*#A``!7XZD```H`1)?E"#P#XP-PA.<` -M,`#C`#!`X^`PA^5+/Z#CR#&'Y0`P`.,`,$#CV#"'Y0!@`.,`8$#C!""6Y3@[ -M`N,#(,3G`%``XP!00.,`()7E.3L"XP,@Q.<(();E.CL"XP,@Q.<,();E8#L" -MXP,@Q.>M#83B`!``XP`00.,#(*#C_O__ZP,@H.,\.P+C`R"$YP0@E>5A.P+C -M`R#$YP@@E>5B.P+C`R#$YPP@E>5F.P+C`R#$YQ`@E>5G.P+C`R#$YV@[`N.T -M(=7ALR"$X6H[`N.X(=7ALR"$X1P@E>5E.P+C`R#$YR`@E>5C.P+C`R#$YR0@ -ME>5L.P+C`R#$YQ`@EN5M.P+C`R#$YR@@E>5P.P+C`R#$YRP@E>5N.P+C`R#$ -MYS`@E>5O.P+C`R#$YS0@E>5D.P+C`R#$YS@@E>5Q.P+C`R#$YSP@E>5R.P+C -M`R#$YW0[`N.P)-7ALR"$X10@EN5V.P+C`R#$YQ@@EN5W.P+C`R#$YQP@EN5X -M.P+C`R#$YR`@EN5Y.P+C`R#$YR0@EN5Z.P+C`R#$YT0@E>5[.P+C`R#$YR@@ -MEN5\.P+C`R#$YRP@EN5].P+C`R#$YS`@EN5^.P+C`R#$YS0@EN5_.P+C`R#$ -MYS@@EN6N/:#C`R#$YSP@EN6!.P+C`R#$YT@@E>7Z/@+C`R#$YTP@E>7[/@+C -M`R#$YU`@E>7\/@+C`R#$YU0@E>7]/@+C`R#$YT`@EN7^/@+C`R#$YU@@E>7_ -M/@+C`R#$YUP@E>4O/*#C`R#$YT0@EN4!/P+C`R#$YT@@EN4"/P+C`R#$YV`@ -ME>4#/P+C`R#$YV0@E>4$/P+C`R#$YV@@E>4%/P+C`R#$YVP@E>4'/P+C`R#$ -MYTP@EN4(/P+C`R#$YW`@E>4)/P+C`R#$YW0@E>4*/P+C`R#$YP<`H.'P@;WH -M$$`MZ0!$D.61,P/C`S#4YP$`4^,%```:V#,#XP,PE.<"`%/C`2"@`]0S`P,# -M((0'`2"@XZP\`^,#((3GV#,#XP,PE.<``%/C&P``&@``4.,2```*L"&0Y0(P -MH.$($+/E`0`1XPT``!H``%+C!0``&BP!G^5*%P#C_O__ZR0!G^7^___K!0`` -MZ@`@#^&```SQ`!"3Y0$0@>,`$(/E`O`AX>0V`^,#,)3G``!3XP(```H$`*#A -M!Q"@XS/_+^$$`*#A_O__ZZ@\`^,#,)3G``!3XP(``!K0`)_E]Q<`X_[__^L` -M,)/E``!3XP(``!JX`)_E.1<`X_[__^LA(M/E`0!2XP`@H`,A(L,%!`"@X0`0 -MH./^___KJ#P#XP,PE.<``%/C`@``&H``G^7W%P#C_O__ZP``D^4``%#C`@`` -M&F@`G^4Y%P#C_O__ZP(,@.(!$*#C_O__ZZ@\`^,#,)3G``!3XP(``!I``)_E -M]Q<`X_[__^L`,)/E``!3XP(``!HH`)_E.1<`X_[__^L``*#C(P+#Y:@\`^,# -M,)3G!B"@XP0@@^40@+WHD"X``*PN``#T+@``$$`MZ0!`H.'^___K!`"@X?[_ -M_^L``*#C$("]Z!!`+>D4.P/C`S"0YP``4^,0@+T(,_\OX1"`O>@00"WI```` -MXP``0.,`$`#C`!!`X_[__^O^___K````XP``0.,`,*#C<#"`Y?[__^O^___K -M$("]Z!!`+>G^___K$("]Z!!`+>D`0*#A)#P#XP,PD.D@`(#B_O__ZP!0H.$`1)#E)#P#XP,PE.<``%/C -M2@``"LP[`^,#,)3G``!3XT8``!K0.P/C`S"4YP``4^-"```:``!4XP``X`-P -M@+T(`2"@XY(S`^,#(,3G!`"@X?[__^L$`*#A_O__ZS-LA.(,8(;B!@"@X?[_ -M_^L``%7C$```"@4`H.'^___KL#&5Y0``4^,%```:N`"?Y4H7`./^___KL`"? -MY?[__^L%``#J`"`/X8``#/$($+/E`1"!XP`0@^4"\"'A!`"@X0`0H./^___K -M;#"4Y0@`$^,"```*`0`3XP$PH!-R,,05!`"@X?[__^L$`*#A`1"@X_[__^L$ -M`*#A`1"@X_[__^L$`*#AF?__ZP8`H.'^___K;#"4Y0(+$^,"```*!`"@X0$0 -MH./^___K;#"4Y8``$^,#```*!`"@X?[__^L``*#C<("]Z```H.-P@+WHC"\` -M`*@O``#P02WI`%"@X2!@@.(&`*#A_O__ZP!PH.$`1)#E!@"@X0`0H./^___K -M``!4XSX```JH/`/C`X"4YS,,A.(,`(#B_O__ZP0`H.'^___K;#"4Y0$`$^," -M```*!`"@X0`0H./^___K`#``XP`P0.-P,)/E`0!3XP$@H`/0.P,#`R"$!P0` -MH.'^___K`#"4Y0$`4^,#```*``!7XP$```H'`*#A_O__ZP0`H.'^___K!`"@ -MX5G__^LA,-3E`@!3XP%@H!,#```:(Y0$`5N,`8*`3`6"@`_P[`^,#,)3G -M``!3XP$```H$`*#A,_\OX00`H.'^___K"`"@X?[__^L@`)7E:`!`XO[__^L! -M`%;C\(&]&"``E>5H`$#B&#"0Y0``4^/P@;T(_O__Z_"!O>@@`)7E:`!`XO[_ -M_^OP@;WH$$`MZ0!`H.$8.P/C`S"0YP``4^,````*,_\OX00`H.'^___K$("] -MZ!!`+>D```#C``!`XP`0`.,`$$#C_O__ZP`P`.,`,$#C`$"@XP!`@^7^___K -M_O__Z_[__^L```#C``!`XP$PH.-P,(#E!!"@X0`@`.,`($#C_O__ZQ"`O>@0 -M0"WI_O__ZQ"`O>AP0"WI`$!0XB0```H(/`/C`V"4YS-@0 -M0"WI(`"`XO[__^L`!)#E`#``XP`P0.,!(*#C`""#Y9$S`^,#,-#G``!3XP$` -M``K^___K$("]Z`0T`^,#,)#G``!3XP0```H!(*#C##0#XP,@P.<``*#C$("] -MZ/[__^L0@+WH<$`MZ0!`H.%@`)#E(`"`XO[__^L``%3C``#@`W"`O0@`4*#A -M,VR$X@Q@AN(&`*#A_O__ZP$@H./0,P/C`R"$YP0`H.'^___K!0"@X0`0H./^ -M___K``!0XP,```H&`*#A_O__ZP``X.-P@+WH!0"@X?[__^L%`*#A_O__Z[`A -ME>4",*#A"!"SY0$`$>,&```:`"`/X8``#/$`$)/E`1#!XP`0@^4"\"'A"0`` -MZ@``#^&```SQ`!"3Y0'`P>,`P(/E`/`AX0$`$>,!```*!`"2Y?[__^L`4*#C -MXS,#XP-0Q.?D,P/C`U#$Y]@S`^,#4(3GT#,#XP-0A.<&`*#A_O__ZP4`H.%P -M@+WH<$`MZ0!`H.%@`)#E(`"`XO[__^LD/`/C`S"4YP``4^--```*S#L#XP,P -ME.<``%/C20``&M`[`^,#,)3G``!3XT4``!H``%3C0P``"@!0H.$$`*#A_O__ -MZS-LA.(,8(;B!@"@X?[__^L!(*#CT#,#XP,@A.<``%7C$```"@4`H.'^___K -ML#&5Y0``4^,%```:S`"?Y4H7`./^___KQ`"?Y?[__^L%``#J`"`/X8``#/$( -M$+/E`1"!XP`0@^4"\"'A!`"@X0`0H./^___K;#"4Y0$`$^,.```*`3##XVPP -MA.7D-@/C`S"4YP``4^,"```*!`"@X0,0H.,S_R_A!`"@X?[__^L$`*#A`Q"@ -MXP`@H./^___K!`"@X0$0H./^___K!`"@X0$0H./^___K!`"@X?[__^L"(*#C -MV#,#XP,@A.<`4*#C"#!#X@-0A.<&`*#A_O__ZP4`H.%P@+WH``#@XW"`O>B, -M+P``J"\``!!`+>D`0*#A7#"0Y0``4^,"```*6`"0Y0X1`./^___K3`"$XO[_ -M_^L!`*#C$("]Z!!`+>G^___K$("]Z/!'+>D`8*#A`4"@X2``D.5H`$#B_O__ -MZP`PH.,`$`#C`!!`XP`@`.,"<*#A`'!`XP-0H.$`(`#C`H"@X0"`0.,`(`#C -M`J"@X0"@0.,#(('@ML#2X0/@D>>T`-+ALB#4X0(`4.$&```:M"#4X0P`4N$# -M```:`@`>XP!0AQ4`4(@5`%"*%0@P@^(P`%/C[O__&@``H./^___K`'!0XE@` -M``H@@(;B,(*'Y0!$E^4!4*#CS#L#XP-0A.<<0(3E8&"$Y2`PEN5H,$/B9#"$ -MY00`H.$($*#A_O__ZP@`H.$'$*#A_O__Z[A1Q.$`,*#CM#'$X00`H.'^___K -M!`"@X?[__^L`(`#C^#L#XP`@0.,#((3G`"``X_P[`^,`($#C`R"$YP`@`.,/ -M.Z#C`"!`XP,@A.<`(`#C!#P#XP`@0.,#((3G!`"@X50``.L%`%#A-@``&@0` -MH.'^___K!`"@X?[__^L``%#C,```"I,S`^,#,-3G``!3XPD```ID,)3E_"+3 -MY04@@N'\(L/E&##6Y0@P@^,8,,;E"`"@X040H.'^___K!P"@X;`PG^4`$)/E -M_O__ZPU;A.(14(7B!0"@X?[__^MT`9?E!1"@X08@H./^___KB#"?Y0@`D^4` -M`%#C`P``"O[__^L,$*#C`2"@X_[__^L'`*#A_O__ZP``4./PA[T("0``ZB`` -MMN5H`$#B_O__ZP8`H.$`$*#C_O__ZP``H.-S___K$@#@X_"'O>@@`);E:`!` -MXO[__^L(`*#A`!"@X_[__^L$`*#A:?__ZP<`H.'^___K$@#@X_"'O>@````` -M_#@``!!`+>D`0*#A3`"`XO[__^L.`0#C_O__ZU@`A.4``%#C6`"$!0\`@!(/ -M`,`37`"$%0$`H!,0@+WH\$$MZ0!`H.%D8)#E8""0Y1P`A.4`,*#C)##`Y24P -MP.4`X)+EP#&6Y00PT^4A,,#E`C#>Y2`PP.4$4-[E(E#`Y0``5>,B``#:`#"@ -MXP,@H.$,$)[E`Q"1X!@```H#P-'E`\`,X@(`7.,T```:TG#1X0``5^,S``"J -M),#4Y0'`C.(DP,3E"@``ZM+`T>$``%SC),#4M0'`C+(DP,2U!```ZM+`T>$` -M`%SC)<#4I0'`C*(EP,2E`A#1Y0\0`>(H$(#E`2""XBPP@^($`(#B!0!2X=[_ -M_[H<,);E`P!3XP$PH`,`,*`3(S#$Y00`H.'^___K`%"@X00`H.'^___K``!0 -MXP!0H`,!```*`%!5X@%0H!-``(3B`!"@X_[__^L$`*#A_O__ZP0`H.'^___K -M:`"$X@`0H./^___K!0"@X?"!O>@#`%SCS___"@(`7./8__\:TO__ZC`P0.)S -M,._F"0!3XS``0)(>_R^183!`XG,P[^8%`%/C5P!`DA[_+Y%!,$#B,"`(/G`A"@ -MXS`L`>,"$(/G`Q"@X\@H`>,"$(/G'O\OX0(`$>,(```*``"@XS0L`>,"`(/G -M`2"@XS`<`>,!((/GR!@!XP$@@^<>_R_A`0`1XPD```HP+`'C`B"3YP,`4N,( -M``"*``"@XS`L`>,"`(/GR"@!XP(`@^<>_R_A!``1XQ4`X`,>_R\!``"@XQ[_ -M+^$``*#C'O\OX0`TD.5L,)/E"``3XP(PH!,`,((5"@``&D``$^,!```:(``3 -MXP(```H!,*#C`#""Y0,``.H0`!/C`S"@$P`PH`,`,(+E``"@XQ[_+^$``*#C -M``""Y00`PN4!,*#C!3#"Y1[_+^$`%)#E:#L"X[,PD>$`,(+E``"@XP0`PN4> -M_R_A`!20Y04PTN4``%/C!```"BHI`.,T-0'C`R"!YP``H.,>_R_A`#"2Y0$, -M0^(J*`#C`@!0X14`X(,!,,.3-"4!DP(P@9<``*"3'O\OX0`4D.4T-0'C`S"1 -MYP`P@N4``*#C!`#"Y1[_+^$',*#C`#""Y0``H.,$`,+E`3"@XP4PPN4>_R_A -M``"@XP``@N4$`,+E`3"@XP4PPN4>_R_A$$`MZ0C03>(`Q)#E#@"3Z``PC>4, -M`*#A_S\/XP\P0..H2P/C#^"@X03PG.<``*#C"-"-XA"`O>@``.#C'O\OX0`` -MX.,>_R_A``"@XQ[_+^$``*#C'O\OX0``H.,>_R_A``"@XQ[_+^$`-)#ES!L# -MXP$0D^<"`*#A`2!RX@`@H#,``%'C`A"@`0$0@A,``%'C%0#@$Q[_+Q$`()#E -M`@!2XP``H(,",8.0!!"PE000@Y4`,`"3`#!`DP`0D)4"$8.7``"@DQ[_+^$> -M_R_A'O\OX?!'+>D(T$WB`%"@X100H.,'((WB:#L#XP_@H.$#\)#G!S#=Y0,` -M4^,``%,3`:"@`P*@H!,`8*#C!I"@X:1[`^,`@.#C"P``Z@4`H.$&$*#A!""@ -MX0@PH.$/X*#A!_"5YP%`A.(!#%3C]O__&@%@AN(*`%;A`0``J@E`H.'Q___J -M"-"-XO"'O>@``*#C'O\OX0`$D.5L,)#E`0`3XP<``!H`,*#CABP#XP(PP.>' -M+`/C`C#`YX@L`^,",,#G#@``ZITV`>,#$-#GGC8!XP,@T.><-@'C`\#0YP'` -MC.*LP*#A7\!,XH<\`^,#P,#GACP#XP,0P.>(/`/C`R#`YP\@H..)/`/C`R#` -MY_(-@.($`(#B'O\OX7!`+>D(T$WB`F"@X;1`TN$$`*#A_O__ZP!04.(+`.`# -M+```"@`0EN4-(*#A?SW"XS\PP^,(,)/E!""1X`,@TC``,*`S``!3XP4``!H% -M`*#A!""@X?[__^L``%#C"@``"@0``.H``%3C!P``"@4`H.$$$*#A_O__ZP4` -MH.$$$*#A_O__ZPT`X.,2``#J"`"-X@10(.4`$`#C`!!`X_[__^L``%#C`@`` -M"@`PT.4``%/C!```&@4`H.$$$*#A_O__ZPT`X.,#``#J!0"@X000H.'^___K -M``"@XPC0C>)P@+WH<$`MZ0C03>(#8*#A`%20Y0)`H.$`,*#C!#"-Y0`0DN4- -M(*#A?SW"XS\PP^,(,)/E!""1X@,@TC``,*`S``!3XP,``!H$`(WB!""@X_[_ -M_^L"``#J!`"-X@00H./^___KS#L#XP,PE>4!`%/C"```&N0V`^,#,)7G -M``!3XQH```H%`*#A"1"@XS/_+^$``*#C%@``Z@(`4^,(```:Y#8#XP,PE><` -M`%/C#P``"@4`H.$*$*#C,_\OX0``H.,+``#J`P!3XP@``!KD-@/C`S"5YP`` -M4^,$```*!0"@X0P0H.,S_R_A``"@XP```.H``*#C"-"-XG"`O>AP0"WI`T"@ -MX0#$D.4,`*#A!@"3Z/\_#^,/,$#CI%L#XP_@H.$%\)SG`""@X00`H.$`$`#C -M`!!`X_[__^L``*#C<("]Z/!/+>DTT$WB`T"@X0`PH..Z,4D8(WE,*"-X@1`*N4$``#J#`!6XP<```H< -M((WB!@""YP1@AN(*`*#A)!N?Y?[__^L``%#C]?__&@B`C>4<8)WE!@"@X0`0 -M`.,`$$#C_O__ZP``4.,_```:!0"@X0`0H.,!+*#C"("=Y68^B.+^___K``!0 -MXZ\"``H$`*#AU!J?Y0(@H./^___K`#"@XPPPC>4`H`#C`*!`XPS`G>40P(WE -M!`"@X;`:G^4$(*#A##"@X?[__^L`4*#C#`"=Y0!@B.`%,(;@!`"@X0H0H.$$ -M(*#A8#;3Y?[__^L!4(7B"`!5X_;__QH$`*#A -M@N((,)WE!5"#X`A@H.,$`*#A"A"@X00@H.$(,-7E_O__ZP%@AN)V8/_F`5"% -MXA``5N/U__\:!`"@X2@:G^4$(*#A_O__ZPS`G>40P(SB#,"-Y0$,7./0__\: -M=0(`Z@8`H.$`$`#C`!!`X_[__^L``%#C,0``&B``G>4``%#C:@(`"B1@G>4` -M`%;C9P(`"BB`C>(($*#A$""@X_[__^L`H*#A!@"@X0@0H.$*(*#C_O__ZW!@ -M_^8``%;C6P(`"GJ`_^8`$*#C`!"-Y04`H.$#(*#C&C"-XO[__^L(((;@NC'= -MX0,`4N%0`@#*!0"@X0@0H.$&(*#A"3"@X?[__^L``%#C30(`"@!0H.,`4,3E -M6(F?Y04``.H$`*#A"!"@X00@H.$%,-GG_O__ZP%0A>)U,/_F`P!6X?;__XH] -M`@#J!@"@X0`0`.,`$$#C_O__ZP``4.,G```:`+"-Y04`H.$`$*#C`2"@X0(\ -MH./^___K``!0XS$"``H$`*#AW!B?Y0(@H./^___K`%"@X^!HG^7@B)_ES*B? -MY00`H.$&$*#A!""@X04PV^?^___K#R`%X@\`4N,$```:!`"@X:@8G^4$(*#A -M_O__ZP8``.H',`7B!P!3XP0`H.$*$*`!"!"@$00@H.'^___K`5"%X@(,5>/H -M__\:#P(`Z@8`H.$`$`#C`!!`X_[__^L``%#C(P``&@`0H.,`$(WE!0"@X0,@ -MH.,:,(WB_O__Z[HQW>$%`%/C`@(`V@4`H.$`$*#C!B"@XPDPH.'^___K``!0 -MX_L!``H`4*#C`%#$Y11HG^48B)_E!`"@X080H.$$(*#A!3#9Y_[__^MU,/_F -M!0!3XP,```H$`*#A"!"@X00@H.'^___K`5"%X@8`5>/P__\:Y0$`Z@8`H.$` -M$`#C`!!`X_[__^L``%#C(P``&@`0H.,`$(WE!0"@X0,@H.,:,(WB_O__Z[HQ -MW>$#`%/CV`$`V@4`H.$`$*#C!""@XPDPH.'^___K``!0X]$!``H`4*#C`%#$ -MY7AGG^5XAY_E!`"@X080H.$$(*#A!3#9Y_[__^MU,/_F`P!3XP,```H$`*#A -M"!"@X00@H.'^___K`5"%X@0`5>/P__\:NP$`Z@8`H.$`$`#C`!!`X_[__^L` -M`%#C#```&@4`H.$8$(WB_O__ZP4`H.'^___KN"'=X0`@8N`$`*#A`!``XP`0 -M0./^___K`%"@XZL!`.H&`*#A`!``XP`00./^___K``!0XT```!H(`)WEYCZ` -MX@4`H.$`$*#C`2N@XP,P@^+^___K``!0XYL!``H$`*#AA!:?Y0(@H./^___K -M`""@XPP@C>4`H`#C`*!`XPPPG>40,(WE!`"@X806G^4$(*#A_O__ZP!0H.,, -MP)WE#&"(X`4PAN`$`*#A"A"@X00@H.%C/M/E_O__ZP%0A>((`%7C]O__&@0` -MH.$D%I_E!""@X?[__^L0`)WEYEZ`X@@@G>4%4(+@`U"%X@A@H.,$`*#A"A"@ -MX00@H.$(,-7E_O__ZP%@AN)V8/_F`5"%XA``5N/U__\:!`"@X=@5G^4$(*#A -M_O__ZPPPG>40,(/B##"-Y0(,4^/0__\:80$`Z@8`H.$`$`#C`!!`X_[__^L` -M`%#C0```&@C`G>7F/HSB!0"@X0`0H.,!*Z#C`S"#XO[__^L``%#C5`$`"@0` -MH.%H%9_E`B"@X_[__^L(`)WE`JR`X@(LH.,,((WE`(``XP"`0.,,8)WE!`"@ -MX605G^4$(*#A!C"@X?[__^L`4*#C!3"*X`0`H.$($*#A!""@X6,^T^7^___K -M`5"%X@@`5>/V__\:!`"@X0@5G^4$(*#A_O__Z^9>AN((,)WE!5"#X`-0A>(( -M8*#C!`"@X0@0H.$$(*#A"##5Y?[__^L!8(;B=F#_Y@%0A>(0`%;C]?__&@0` -MH.'`%)_E!""@X?[__^L,P)WE$,",X@S`C>40H(KB`0MH#_Y@`PH.,`,(WE!0"@X0$0H.,#(*#C&C"-XO[__^L(((;@NC'=X0,` -M4N'X``#*!0"@X0@0H.$&(*#A"3"@X?[__^L``%#C\0``"@!0H.,`4,3E!(2? -MY04``.H$`*#A"!"@X00@H.$%,-GG_O__ZP%0A>)U,/_F!@!3X?;__SKA``#J -M!@"@X0`0`.,`$$#C_O__ZP``4.,]```:!`"@X0`0`.,`$$#C`B"@X_[__^L` -M4*#C`*``XP"@0.,,L(WE$)"-Y0BPG>4(<(WE!7"@X0B0H.$'@*#A!`"@X7@3 -MG^4$(*#A!S"@X?[__^L`4*#C!V")X`4PAN"!/8/B)C"#X@0`H.$*$*#A!""@ -MX0`PT^7^___K`5"%X@@`5>/T__\:!`"@X1`3G^4$(*#A_O__ZPA0B^"!787B -M)E"%X@A@H.,$`*#A"A"@X00@H.$(,-7E_O__ZP%@AN)V8/_F`5"%XA``5N/U -M__\:!`"@X40D)WE"'"=Y9T` -M`.H&`*#A`!``XP`00./^___K``!0XSX``!H$`*#A`!``XP`00.,"(*#C_O__ -MZP@`G>4"K(#B`ER@XP"``.,`@$#C#+"-Y1"0C>4`D*#A!["@X05PH.$'8*#A -M!`"@X602G^4$(*#A!S"@X?[__^L`4*#C!3"*X($]@^(F,(/B!`"@X0@0H.$$ -M(*#A`##3Y?[__^L!4(7B"`!5X_3__QH$`*#A`!*?Y00@H.'^___K!E")X(%= -MA>(F4(7B"&"@XP0`H.$($*#A!""@X0@PU>7^___K`6"&XG9@_^8!4(7B$`!6 -MX_7__QH$`*#AO!&?Y00@H.'^___K$'"'XA"@BN(!"U?CT___&A"0G>4+<*#A -M#+"=Y5@``.H&`*#A`!``XP`00./^___K``!0XSX``!H$`*#A`!``XP`00.," -M(*#C_O__ZP!@H.,`,`#C`U"@X0!00.,`H`#C`*!`XPRPC>40D(WE%'"-Y0BP -MH.$&@*#A!7"@X0B0H.$$`*#A)!&?Y00@H.$(,*#A_O__ZP!0H.,(8(O@!3"& -MX`0`H.$'$*#A!""@X6`WT^7^___K`5"%X@@`5>/V__\:!`"@X>@0G^4$(*#A -M_O__ZW9>B>((()WE!5""X`A@H.,$`*#A"A"@X00@H.$(,-7E_O__ZP%@AN)V -M8/_F`5"%XA``5N/U__\:!`"@X:00G^4$(*#A_O__ZQ"`B.(!#%CCU?__&@RP -MG>40D)WE%'"=Y1,``.H$`*#A`!``XP`00.,3(*#C_O__ZP!0H.,/``#J"P"@ -MX0$;H./^___K``!5XP(``!H$`*#A_O__Z[0`Q^$%`*#A--"-XO"/O>@54.#C -M`@``Z@!0H.,```#J#5#@XPD`H.$!&Z#C_O__ZP``6^/J__\:[/__Z@`P```4 -M,```&#```"PP```P,```/#```%`P``!8,```8#```&PP``!X,```K#```,@P -M``#P3RWI+-!-X@.`H.$`,*#CLC'-X0!DD.4[/*#C`Z"6YP$+H./^___K`'!0 -MX@!`H`,+8.`#!%"@`:X!``H!"Z#C_O__ZP"04.(+8.`#`%"@`P5`H`&Y`0`* -M`0R@X_[__^L`0%#B"V#@`P!0H`.S`0`*`@R@X_[__^L`4%#B"V#@`ZX!``H` -M,*#C%#"-Y1@PC>4<,(WE*+"-X@2`*^4#@*#A!```Z@P`6.,'```*%#"-X@@` -M@^<$@(CB"P"@X906G^7^___K``!0X_7__QH4@)WE"`"@X8`6G^7^___K``!0 -MXRX``!H8`)WE``!0XXX!``H<@)WE``!8XXL!``H@$(WB$""@X_[__^L,`(WE -M"`"@X?[__^MP`/_F`0`0XX(!`!J@L+#A`*"@$W\!``H$``#J`@!8Y0$06.7^ -M___K"@#'YP&@BN("@(CB"P!:X??__SH,,)WE4``%CC+P$`"@@`H.'^___K -M<`#_Y@$`$.,J`0`:H+"PX2@!``H&`%OC`*"@DRD!`(H$``#J`@!8Y0$06.7^ -M___K"@#'YP&@BN("@(CB"P!:X??__SH`$*#C`!"-Y08`H.$#(*#C$C"-XO[_ -M_^NR,=WA`P!;X1T` -M`,H&`*#A`!"@XPL@H.$',*#A_O__ZP``4./D```:Y0``Z@@`H.&\$Y_E_O__ -MZP``4.,P```:&`"=Y0``4./9```*'("=Y0``6./6```*(!"-XA`@H./^___K -M#`"-Y0@`H.'^___K<`#_Y@$`$./-```:H+"PX0"@H!/*```*!```Z@(`6.4! -M$%CE_O__ZPH`Q^4&`*#A`1"@XP,@H.,2,(WB_O__ZP@@B^"R,=WA`P!2X;<``,H&`*#A"!"@ -MX0L@H.$',*#A_O__ZP``4..N```:KP``Z@@`H.'H$I_E_O__ZP``4.,A```: -M&`"=Y0``4..C```*'&"=Y0``5N.@```*(!"-XA`@H./^___K``J@X2`*H.$, -M`(WE!@"@X?[__^MP`/_F`0`0XY4``!J@L+#A`("@$PPPG14#H(H0!P``&H\` -M`.H"`%;E`1!6Y?[__^L(,(K@@3V#XB8`P^4!@(CB`F"&X@L`6.'U__\ZA@`` -MZ@@`H.%0$I_E_O__ZP``4.,(```:@3V*X@8`H.$`$*#C`2N@XR8P@^+^___K -M`0!0XWD```IZ``#J"`"@X1P2G^7^___K``!0XP<``!H&`*#A`!"@XP$KH.-V -M/HKB_O__ZP$`4.-L```*;0``Z@@`H.'L$9_E_O__ZP``4.,8```:20V*XH$= -MBN(C`(#B)A"!X@$KH./^___K`#"@XP`PC>4&`*#A`1"@XP,@H.,2,(WB_O__ -MZ[(QW>$``%/C6```"H$]BN(&`*#A`!"@XP$KH.,F,(/B_O__ZP``4.-.```: -M3P``Z@@`H.%X$9_E_O__ZP``4.,0```:`!"@XP`0C>4&`*#A`R"@XQ(PC>+^ -M___KLC'=X0``4^-!```*!@"@X0`0H.,!+*#C=CZ*XO[__^L``%#C.```&CD` -M`.H(`*#A)!&?Y?[__^L``%#C,@``&A@`G>4``%#C+0``"AQ@G>4``%;C*@`` -M"B`0C>(0(*#C_O__ZP`*H.$@"J#A#`"-Y08`H.'^___K<`#_Y@$`$.,?```: -MH+"PX0"`H!,,,)T5`Z"*$`8``!H9``#J`@!6Y0$05N7^___K"#"*X&`'P^4! -M@(CB`F"&X@L`6.'V__\Z$0``Z@D`H.$!&Z#C_O__ZP``5.,"```*!`"@X0$< -MH./^___K``!5XP(```H%`*#A`AR@X_[__^L&`*#A+-"-XO"/O>@58.#C`@`` -MZ@!@H.,```#J#6#@XP<`H.$!&Z#C_O__ZP``6>/E__\:Y___Z@`P```,,0`` -M%#$``%PP``!D,```'#$``"0Q```L,0``.#$``$0Q``!0,0``7#$``'!`+>D" -M0*#A`%20Y6P@E>4!`!+C"```&D``$N,&```:``"@X[0`Q.&V,-3A@SC@X:,X -MX.&V,,3A<("]Z`8@U.4``%+C!```"@0`4N,5`."#`2!"D@(``)IP@+WHT"@! -MXP(@E>,!\9^7-P``ZIB7!`"`EP0` -M1)@$`("7!``LF`0`1)@$`"R8!````*#CM`#$X8S(X.&LR.#AML#$X7"`O>@9 -M'8+B!!"!X@$1A>"T$-'AM!#$X0``4>,7```*8Q^"X@$0@>(!$H7@&2V"X@0@ -M@N("(87@`P"@X000@>($()+E_O__Z[8@U.&V(,3A,#P!XP,PE><``%/C`BJ" -M`[8@Q`$``*`#<("]"`$`4^,!*8(#MB#$`0``H.-P@+WH``"@X[0`Q.&,R.#A -MK,C@X;;`Q.%P@+WH$#"@X[0PQ.$*RXSCML#$X0``H.-P@+WH``"@X[0`Q.&, -MR.#AK,C@X;;`Q.%P@+WH$$`MZ0``4^('```*#L"@X[3`PN$!,*#CMC#"X0`0 -M`.,`$$#C#""@X?[__^L``*#C$("]Z!!`+>D"0*#A`!20Y6P@D>4!`!+C`@`` -M&D``$N,``.`#$("]".@@D>6T(,3A`P"@X>P0@>+^___K`3"@X[8PQ.$``*#C -M$("]Z/!`+>D4T$WB`E"@X0!$D.40/`/C`S#4YP``4^,)```:`#``XP`P0.,/ -M"X3B$`"`X@`0D^40(*#C_O__ZP`@H.,?/`/C`R#$Y[0PU>$0`%/C6P``B@`0 -ME>4-(*#A?SW"XS\PP^,(,)/E$""1X@,@TC``,*`S``!3XP4``!H-`*#A$""@ -MX_[__^L``%#C!0``"DL``.H-`*#A$!"@X_[__^L-4.#C1P``Z@]KA.(08(;B -M!@"@X0T0H.'^___K``!0XP!0H`,_```*!`"@X0T0H.'^___K`%!0XCH``!H/ -M"X3B$`"`X@`0`.,`$$#C"2"@X_[__^L!`%#C"@``&B$\`^,#(-3G%3U#X@$P -M0^(#(,3G!`"@X?[__^L@/`/C`R#4YX$S`^,#(,3G#7"@X08`H.$-$*#A$""@ -MX_[__^L`(*#C'SP#XP,@Q.<-`*#A`!``XP`00.,)(*#C_O__ZP$`4.,8```: -M!`"@X0$0H./^___KY#8#XP,PE.<``%/C`@``"@0`H.$'$*#C,_\OX>`V`^,# -M$-3G(2P#XP(0Q.<`8*#C`V#$YP0`H.'^___K@3,#XP,0U.<@+`/C`A#$YP-@ -MQ.<```#J#5#@XP4`H.$4T(WB\("]Z/!'+>E0T$WB`%"@X0*@H.$#0*#A`P"@ -MX0`0`.,`$$#C!B"@X_[__^L``%#C<```"K0PVN$&,$/BM##*X0:0A.(`=)7E -M`&"@XSQ@C>6P9,WA*#"-X@1@@^0$8(/D!&"#Y`1@@^0`8,/E*$"-X@0`H.$) -M$*#A$2"@X_[__^L\4(WB``#4Y0$0U.7^___K!@#%YP%@AN(#0(3B!@!6X_?_ -M_QK^___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/EA%"'XH1`E^4\8(WB!G"@ -MXP4`H.$$$*#A_O__ZP$`4.,M```*!("@X2``A.(&$*#A!R"@X?[__^L``%#C -M)```"@`@H.-$((WEOB3-X4@@C>60$)3EH`"$X@P00>)$,(WB_O__ZP``4.,; -M```*2#"-X@`PC>5$$)WE""`!XTXPC>+^___K2#"=Y0``4^,2```*OB3=X;(O -MO^9R(/_FOB3-X0D`H.$`$`#C`!!`X_[__^L``)KE"1"@X0@@H./^___K`#": -MY0`@H.,((,/E`4"@XP(``.H`0)3ES/__Z@!`H.,-(*#A?SW"XS\PP^,$()/E -M`2!"X@0@@^7^___K``!4XXP``!H)`*#A`!``XP`00.,)(*#C_O__ZP``FN4) -M$*#A"""@X_[__^L`,)KE`""@XP@@P^5_``#J!`"@X0`0`.,`$$#C!2"@X_[_ -M_^L``%#C>```"K0PVN$%,$/BM##*X060A.(`=)7E`&"@XSQ@C>6P9,WA*#"- -MX@1@@^0$8(/D!&"#Y`1@@^0`8,/E*$"-X@0`H.$)$*#A$2"@X_[__^L\4(WB -M``#4Y0$0U.7^___K!@#%YP%@AN(#0(3B!@!6X_?__QK^___K#2"@X7\]PN,_ -M,,/C!""3Y0$@@N($((/EA%"'XH1`E^4\8(WB!G"@XP4`H.$$$*#A_O__ZP$` -M4.,V```*!("@X2``A.(&$*#A!R"@X?[__^L``%#C+0``"@`@H.-(((WE"#"- -MX@0@@^0$((/D!""#Y`0@@^0$((/D!""#Y`0@@^0`((/E1""-Y9`0E.6@`(3B -M#!!!XD@PC>+^___K``!0XQP```I$,(WB`#"-Y4@0G>41(`'C"#"-XO[__^M$ -M,)WE``!3XQ,```H)`*#A`!``XP`00.,(((WB_O__ZP``FN4)$*#A1""=Y00@ -M@N+^___K`"":Y40PG>4#,(+@!#"#X@`@H.,`(,/E`4"@XP(``.H`0)3EP___ -MZ@!`H.,-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K``!4XPL``!H)`*#A -M`!``XP`00.,)(*#C_O__ZP``FN4)$*#A"""@X_[__^L`,)KE`""@XP@@P^4` -M`*#C4-"-XO"'O>CP0"WI%-!-X@!@H.$"0*#A`U"@X0``DN4`$`#C`!!`XP8@ -MH./^___K``!0XQ,```H`9);E+'H#XP4`H.$`$`#C`!!`XP<@EN?^___K!0"@ -MX?[__^NT`,3A!S"6YP(`4^-I```:!@"@X>D]H.,#$-;G`""@XP(PH.'^___K -M8@``Z@``E.4`$`#C`!!`XP0@H./^___K``!0XPH```H`));E!0"@X0`0`.,` -M$$#C)#H#XP,@DN?^___K!0"@X?[__^NT`,3A4```Z@``E.4`$`#C`!!`XP@@ -MH./^___K``!0XQ@```H`%);E4SH#XP,@T>=4.@/C`S#1YU4*`^,``-'G``"- -MY58*`^,``-'G!`"-Y5<*`^,``-'G"`"-Y5@*`^,`$-'G#!"-Y04`H.$`$`#C -M`!!`X_[__^L%`*#A_O__Z[0`Q.$P``#J``"4Y0`0`.,`$$#C!B"@X_[__^L` -M`%#C"@``"@`DEN4%`*#A`!``XP`00./A+8+B`B""XO[__^L%`*#A_O__Z[0` -MQ.$>``#J``"4Y0`0`.,`$$#C"2"@X_[__^L``%#C%P``"@`4EN4\.`/C`R#1 -MYSTX`^,#,-'G/@@#XP``T><``(WE/P@#XP``T><$`(WEX0V@XP``T><(`(WE -M00@#XP`0T><,$(WE!0"@X0`0`.,`$$#C_O__ZP4`H.'^___KM`#$X0``H.,4 -MT(WB\("]Z/!%+>D4T$WB`$20Y0-@H.$`,*#C"#"-Y;PPS>$`,(WEM##-X0T` -MH.$&$(;B!B"@X_[__^L`,);E`0!3XRH``!H-`*#A"!"-X@8@H./^___K`0!0 -MXU````H`4*#C#7"@X0:`H.,%H*#A!0.$X"<,@.(Q`(#B#1"@X0@@H.'^___K -M`0!0XP\``!H%HZ#A"@"$X"<,@.(W`(#B%!"&XA`@H./^___K"J"$X">LBN(P -MH(KB`0"@XP``RN4`4(7@,#L"XP-0Q./C__\:-0``Z@`@ -MH.,P.P+C`R#$YP$`H.,N``#J`@!3XQT``!H`4*#C#6"@X09PH.,%@*#A!0.$ -MX"<,@.(Q`(#B#1"@X0<@H.'^___K`0!0XPT``!H%@Z#A"`"$X"<,@.(Q`(#B -M`!"@XP8@H./^___K"$"$X"=,A.(P0(3B`#"@XP`PQ.4!`*#C$@``Z@%0A>(0 -M`%7CY?__&@T``.H#`%/C"0``&B<,A.(P`(#B`!"@XP$KH./^___K`""@XS`[ -M`N,#(,3G`0"@XP(``.H``*#C````Z@$`H.,4T(WB\(6]Z#!;`N,%`-3G``.$ -MX"<,@.(Q`(#B#1"@X08@H./^___K!0#4YP`#A.`G#(#B-P"`XA00AN(0(*#C -M_O__ZP4PU.<#,X3@)SR#XC`P@^(!(*#C`"##Y04PU.<",(/@`0A>(&(*#C_O__ -MZP,``.H$`*#A`!"@XP8@H./^___K``"@XW"`O>CP3RWI9-!-X@!@H.$"4*#A -M`T"@X0,`H.$`$`#C`!!`XP<@H./^___K``!0XR,```H`5);E!S#4Y3``4^,( -M```*,0!3XP%`H`,&```*,@!3XP)`H`,#```*,P!3XP-`H`,````*`$"@XP4` -MH.$$$*#A_O__ZP``4..3`@`*``!4XY$"``HL.@/C`S"5YP(`4^/I/:`#`Q#5 -M!P`PH`,#(*`!WA?5%4$Z`Q,#$,47X"?5%=\WU14%`*#A_O__ZX("`.H$`*#A -M`!``XP`00.,&(*#C_O__ZP``4.,2```*M##5X08P0^)S,/_FM##%X0!DEN5Z -M>@/C`3!#X@$`5);E+#H#XP,PE><``%/C60(`"@1@H.$-,/;E,`!3XP@``!KA#87B -M*0"`X@`0H..&(0#C_O__ZP`@H.-[.@/C`R#%YTP"`.I[.@/C`S#5YPD`4^-( -M`@"*!'"@X0"`H.-[J@/CB)@#XR>PH.,*0-7G#@#7Y0\0U^7^___KFU0DX`A` -MA.`)0(3@`@#$Y0&`B.(#<(?B!@!8X_/__QI[2@/C!`#5YV@X`^,G(*#CDE`@ -MX`,`@.`3P-;E$A#6Y0$1@>`0P$SB@1",X`$0P.4$$-7GD@$"X`(`A>`#,(#@ -MX0V`XBH`@.(4$(;B`2#3Y?[__^L$,-7G`3"#X@0PQ><>`@#J!`"@X0`0`.,` -M$$#C"B"@X_[__^L``%#C!0$`"K0PU>$*,$/BM##%X0IPA.(`9);E"&"-Y0`@ -MH.-0((WEM"7-X1PPC>($((/D!""#Y`0@@^0$((/D!""#Y`0@@^0$((/D!""# -MY`0@@^0$((/D!""#Y`0@@^2P(,/A7""-Y5@@C>4L.@/C`S"6YP(`4^'Z`0`* -M`0!3X_@!``H.6X;B+""%X@P@C>4"`*#A`!"@XP8@H./^___K,C"%XA`PC>4# -M`*#A`!"@XP8@H./^___K"%"%XA10C>4%`*#A`!"@XR0@H./^___K`&"@XP(X -M`^,($)WELV"!X00X`^.S8('A.#@#XP-@P>=04(WB"@#4Y0L0U.7^___K!@#% -MYP%@AN(#0(3B!@!6X_?__QH2<(?B!P"@X0`0`.,`$$#C!R"@X_[__^L``%#C -M!```"@X[H.,((*#C"!"=Y;,@@>$A``#J!P"@X0`0`.,`$$#C!R"@X_[__^L` -M`%#C!```"@X[H.,!+*#C"!"=Y;,@@>$5``#J!P"@X0`0`.,`$$#C`R"@X_[_ -M_^L``%#C!```"@X[H..`(*#C"!"=Y;,@@>$)``#J!P"@X<`6G^4%(*#C_O__ -MZP``4..I`0`*#CN@XP0@H.,($)WELR"!X?[__^L-(*#A?SW"XS\PP^,$()/E -M`2""X@0@@^4(,)WEA("#XH1`D^4`<*#C7*"-X@>0H.$<8(WB6+"-X@10H.$( -M`*#A!1"@X?[__^L!`%#C*0``"@5PH.&0$)7EH`"%X@P00>()(*#A"C"@X?[_ -M_^L`0%#B'@``"@"PC>4$`*#A7!"=Y0,@H.,&,*#A_O__ZP``4.,'```*!@"@ -MX5`0C>(&(*#C_O__ZP``4.,0```*9$"5Y1$``.H`L(WE!`"@X5P0G>4-(*#C -M!C"@X?[__^L``%#C!@``"@8`H.%0$(WB!B"@X_[__^L``%#C9$"5%0(``!H` -M4)7ET/__Z@!`H.,-$*#A?SW!XS\PP^,$()/E`2!"X@0@@^7^___K``!4XUP! -M``H0`)WE(!"'X@8@H./^___K#`"=Y5`0C>(&(*#C_O__ZP(X`^,(()WELT"" -MX0$@H.,X.`/C"!"=Y0,@P>4#,)+G!@!3XP8@H!,L.@,3"!"=%0,@@14H$(?B)""@X_[__^L.``#J`0!3XP$```H#`%/C"@``&@@P -MG>4."X/B#`"`XND=@^(+$('B!R"@X_[__^L'(*#C"#@#XP@0G>4#(('G"`"= -MY700[^8`(*#C`C"@X?[__^L`0`#C`$!`XP`0E.4(()WEWPV"X@P`@.(*$('B -M_O__ZP`0E.4(,)WEW@V#XA@`@.)]'X'B_O__ZQ$!`.H$`*#A`!``XP`00.,% -M(*#C_O__ZP``4.-K```*M##5X04P0^*T,,7A`%26Y0`PH.-0,(WEM#7-X2PZ -M`^,#,)7G``!3X_\```H!`%/C_0``"L0Z`^,#,)7G``!3X_D```H$8*#A`'"@ -MXU!`C>(%`-;E!A#6Y?[__^L'`,3G`7"'X@-@AN(&`%?C]___&O[__^L-$*#A -M?SW!XS\PP^,$()/E`2""X@0@@^6$<(7BA$"5Y0!@H.-0@(WB!J"@XP<`H.$$ -M$*#A_O__ZP$`4.,)```*!&"@X2``A.(($*#A"B"@X?[__^L``%#C9$"4%0(` -M`!H`0)3E\/__Z@!`H.,-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K``!4 -MX\D```KG?87B,`"'X@`0H.,,(*#C_O__ZSP`A^(`$*#C)B"@X_[__^OP.0/C -MLT"%X30`A^(@$(;B!B"@X_[__^L!(*#C^CD#XP,@Q><)`%/C"2"@$RPZ`Q,#((47M$*?Y0`0 -ME.7?#87B#`"`X@H0@>+^___K`!"4Y=X-A>(8`(#B?1^!XO[__^N>``#J!`"@ -MX0`0`.,`$$#C!R"@X_[__^L``%#C%P``"K0PU>$(,$/B$'0(3B -M`%26Y5(J`^,"`-7G`0!3XP(```H"`%/C!P``&@,``.H``-3E,`!`XG``[^8" -M``#J``#4Y0$0U.7^___K#P!0XU(Z`Y,#`,67?P``Z@0`H.$`$`#C`!!`XP4@ -MH./^___K``!0XQ````JT,-7A!3!#XK0PQ>$%0(3B`%26Y00`H.'^___K`""@ -MX>H-A>(!`(#B!!"@X?[__^L$`*#A_O__ZZ$Z`^,#`,7G9P``Z@0`H.$`$`#C -M`!!`XPP@H./^___K``!0XQD```JT,-7A##!#XK0PQ>$`));E###4Y3``4^,` -M$*`#Q#H#`P,0@@=6```*,0!3XP$0H`/$.@,#`Q""!U$```HR`%/C`A"@`\0Z -M`P,#$(('3```"C,`4^,#$*`#`!"@$\0Z`^,#$(+G1@``Z@0`H.$`$`#C`!!` -MXPH@H./^___K``!0XQ\```JT,-7A"S!#XG,P_^:T,,7A"D"$X@!4EN7I+:#C -M`A#5YP$`4^,"```*`@!3XP@``!H#``#J`!#4Y3`00>)Q$._F`P``Z@``U.4! -M$-3E_O__ZP`0H.$!,$'B<%`*#A`""@XP(P -MH.'^___K'P``Z@0`H.$`$`#C`!!`XP8@H./^___K``!0XQ@```JT,-7A!S!# -MXG,P_^:T,,7A!D"$X@!4EN5!*@/C`@#5YP$`4^,"```*`@!3XP<``!H#``#J -M``#4Y3``0.)P`._F`@``Z@``U.4!$-3E_O__ZP$P0.)S,._F#`!3XT$Z`Y,# -M`,67``"@XV30C>+PC[WHF#(````````00"WI&-!-X@!$D.4`(*#C#""-Y10@ -MC>40((WE$""-X@`@C>4#`*#A`!``XP`00.,,((WB%#"-XO[__^L,,)WE`@!3 -MXPH```H$`%/C#@``"@$`4^,5`.`3$```&@0`H.$4$)WE$"#=Y?[__^L``*#C -M"@``Z@0`H.$4$)WEL"'=X?[__^L``*#C!```Z@0`H.$4$)WE$""=Y?[__^L` -M`*#C&-"-XA"`O>CP02WI$-!-X@!DD.4``)+E<$#_YE`8Y^<$,)+E##"-Y2`, -MH.%Q`$#B#@!0XP#QGY?:``#J2*\$`'BR!`"+($`+BO!`#8KP0`>+($ -M`'BR!`!XL@0`>+($`'BR!`!XL@0`>+($`'BR!``8L`0``@!1XP@```H$`%'C -M"P``"@$`4>/%```:!@"@X000H.%S(._F_O__Z\```.H&`*#A!!"@X7,@_^;^ -M___KNP``Z@8`H.$$$*#A`R"@X?[__^NV``#J!@"@X000H.$`(.#CH,L#XP_@ -MH.$,\);GKP``Z@`PC>4&`*#A!""@X0`PX..HRP/C#^"@X0SPEN>G``#J``!1 -MXP`@H`.8-@$#`R#&!Z(```H!`%'CH```&@$@H..8-@'C`R#&YPP@G>5D`%+C -M9""@(YDV`>,#(,;GEP``ZA$`4>.S+`,#`C#&!Y,```H*``"*!@!1XQ@```H" -M``"*!0!1XXT``!H/``#J"0!1XR(```H,`%'CB```&D```.K=`%'C5P``"@(` -M`(JJ`%'C@@``&DP``.KN`%'C8```"OT`4>-]```:4T/0/C`R#&YRT``.H``%/C`@``&@8` -MH.'^___K*```Z@$`4^,"```:!@"@X?[__^LC``#J`@!3XR$``!H&`*#A_O__ -MZQX``.H/`%/C!@``&@8`H.$'$*#C"""-XFP[`^,/X*#A`_"6YQ4``.H&`*#A -M!Q"@XPP@C>)P.P/C#^"@X0/PEN<&`*#A!Q"@XP@@C>)L.P/C#^"@X0/PEN<( -M``#J=$#OY@8`H.'%'J#C!""@X?[__^L&`*#A6!P`XP0@H.'^___K``"@XQ#0 -MC>+P@;WH$$`MZ0`$D.4`$-+E`2"@X_[__^L!`%#C``#@$P``H`,0@+WH\$\M -MZ3S03>(`5)#ES#L#XP,PE><"H*#A`2!RX@`@H#,``%/C`C"@`0$P@A,``%/C -M`$"@`QY@H`,%```*C```Z@8`H.'^___K`4"$XF4`5.,"```*;#"5Y2(-$^/W -M__\:`""@X[8@RN&T,-KA'P!3XW\``)H`$)KE#2"@X7\]PN,_,,/C"#"3Y2`@ -MD>(#(-(P`#"@,P``4^,%```:#`"-XB`@H./^___K``!0XP4```IO``#J#`"- -MXB`0H./^___K%0#@XVT``.K^___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/E -MA$"%XH2`E>4`D*#C#+"-XBQPC>*`!(WH!*"@X0H`H.$($*#A_O__ZP$`4.,\ -M```*"4"@X0M0H.$``-7E0_+_ZP!@4.(0``"Z`0#UY3_R_^L``%#C#```N@%0 -MA>(&8H#A!&#'YP0`5.,#``#*`##5Y3H`4^,$```:`5"%X@%`A.(&`%3CZ___ -M&D4``.H-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K%0#@XSH``.J@4(3B -MD""4Y04`H.$T$(WB#"!"XO[__^L``%#C!0``"C0PG>4``%/C!*"=%0$PH!.V -M,,H1#P``&I`@E.4%`*#A-!"-X@P@0N+^___K``!0XP4```HT,)WE``!3XP2@ -MG14"(*`3MB#*$0(``!H`@)CEO?__Z@2@G>4-(*#A?SW"XS\PP^,$()/E`2!" -MX@0@@^7^___KM##:X2$`4^,1``":``":Y2``@.(-(*#A?SW"XS\PP^,(,)/E -M`2"0X@,@TC``,*`S``!3XP0``!H&$(KB`2"@X_[__^L``%#C`0``"A4`X.,` -M``#J``"@XSS0C>+PC[WH"$"@X0``G>4@$(CB!B"@X_[__^L!`%#CUO__&KK_ -M_^KP12WI#-!-X@)`H.$`5)#EMX0``5N.+```*`#"2Y0``4^.(```*MJ#2 -MX08`H.'^___K`(!0X@M`X`.#```*`!"4Y0T@H.%_/<+C/S##XP@PD^4&()'@ -M`R#2,``PH#,``%/C!0``&@@`H.$&(*#A_O__ZP``4.-W```:!@``Z@``5N,$ -M```*"`"@X080H.'^___K#4#@XW(``.H(<*#A`#"8Y2(`4^,50."#;0``B@AP -MB.(&`%/C-@``"@0``(H"`%/C!P``"@,`4^-*```:&@``Z@<`4^,W```*'P!3 -MXT4``!H^``#J!#"7Y0(`4^,(```*!`!3XPL```H!`%/C/0``&@4`H.$`$)?E -M_O__ZP@`A^4X``#J!0"@X0`0E^7^___K"`"'Y3,``.H%`*#A`!"7Y?[__^L( -M`(?E+@``Z@0PE^4"`%/C"```"@0`4^,+```*`0!3XR<``!H%`*#A`!"7Y0@@ -MU^7^___K(@``Z@4`H.$`$)?EN"#7X?[__^L=``#J!0"@X0`0E^4(()?E_O__ -MZQ@``.H%`*#A`!#7Y00@U^4`,.#CI,L#XP_@H.$,\)7G"`"'Y0\``.H`$-?E -M!"#7Y0@PE^4`,(WE!0"@X0`PX..HRP/C#^"@X0SPE><%``#J!0"@X2\0H.,` -M(*#C9#L#XP_@H.$#\)7G>J#OY@``6N,6```:``"4Y0T@H.%_/<+C/S##XP@P -MD^4&()#@`R#2,``PH#,``%/C!@"@$0(``!H($*#A!B"@X?[__^L``%#C!@`` -M"@,``.H50.#C!`"@X0S0C>+PA;WH#4#@XP```.H`0*#C"`"@X080H.'^___K -M]?__ZO!!+>D(T$WB`E"@X0.`H.$`=)#EM$#2X00`H.'^___K`&!0X@L`X`-( -M```*`!"5Y0T@H.%_/<+C/S##XP@PD^4$()'@`R#2,``PH#,``%/C!0``&@8` -MH.$$(*#A_O__ZP``4.,%```:"0``Z@``5.,'```*!@"@X000H.'^___K!@"@ -MX000H.'^___K#0#@XRX``.H`,*#C`#"-Y00PC>4&`*#A`!``XP`00.,-(*#A -M!#"-XO[__^L`,)WE`@!3XPT```H$`%/C%```"@$`4^,5`.`3'0``&@<`H.$$ -M$)WE_O__ZP`@H.$(`*#A`!``XP`00./^___K$```Z@<`H.$$$)WE_O__ZP`@ -MH.$(`*#A`!``XP`00./^___K!P``Z@<`H.$$$)WE_O__ZP`@H.$(`*#A`!`` -MXP`00./^___K!@"@X000H.'^___K``"@XPC0C>+P@;WH<$`MZ2#03>("4*#A -M`V"@X0!$D.4$`(WB`!"@XQP@H./^___KMC#5X0()$^,,```*`2"@XS0\`>,# -M((3G``"@X\PX`>,#`(3G)#D!XP,`A.?(.`'C`P"$YS`\`>,#`(3G8@``ZO\@ -M$^(%```*!`!2XQ4`X(,!($*2`1"@DP,``)I:``#JT"@!XP(@E.<`$*#C`@H3 -MXPL```H`,*#C-`P!XP`PA.?("`'C`#"$Y\P(`>,`,(3G)`D!XP`PA.,` -M,(3GS`@!XP`PA.,`,(3G"""-Y;0PU>$``%/C!@``"@4` -M4^,%,*"3#3"@@PPPC>4,,(/B!#"-Y1L``.H`,*#C##"-Y0$`4>,7```:T#@! -MXP,@A.<9+8+B!"""X@(AA.`$,)+E!0!3XP4```H-`%/C``"@$\PX`1,#`(07 -M'0``&@0``.H!(*#CS#@!XP,@A.<``*#C%P``Z@4@H./,.`'C`R"$YP``H.,2 -M``#J"#"=Y0(Q@^,(,(WE!%"-X@P`A>(&$*#A#""=Y?[__^L$`*#A!1"@X?[_ -M_^L``%#C!```&M@S`^,#,)3G``!3XUX`X`,````*``"@XR#0C>)P@+WH\$4;,,'EOC+1X3`P@^("`%/ATP``B@0PD>4!`'/C -MT```&K@@T>'_/P_C`P!2X(' -M`*#A`!``XP`00./^___K``!0XT4``!H`(*#C-#P!XP,@A>=8((+B`C"%YR2`U.6^,M3A!`!8XQ5`X(.V``"*``!3X[$```H%`%/C!9"@ -MDPV0H(,,H(GB"@"@X?[__^L`<%#BJP``"@<`H.$`$*#C"B"@X?[__^L(D(?E -M`*"'Y0T`6>,%,*`#S"@!`P(PA0=8((("`C"%!P(QB.,$,(?E#)"'X@D`H.$P -M$(3B"""7Y?[__^L<,-3E``!3XP4```H%`*#A!Q"@X?[__^L``%#CE0``"I(` -M`.H#`%CCD@``BF,/B.(``H7@%`"`X@D0H.$(()?E_O__ZQD]B.(#,87@"""7 -MY10@@^4%`*#A!A"@X0@@H.$`,*#C_O__ZP!`H.."``#JR#@!XP,PE><"`%/C -M>```&FP@E>4(,`#C`3!`XP,P`N```%/C<@``"EL-A>(X`(#BX!"%XO[__^L` -M@%#B5@``"@<`H.'0$9_E_O__ZP``4.,`,*`3Z#"(%30\`>,#,)7G!@!3XP0` -M4Q/,.`$#`S"5!^PPB`4<,-3E`0!3XQL``!HP8(3BOB+4X1$.B.(&$*#A$`!2 -MXQ`@H"/^___K!P"@X7@1G^7^___K``!0XPH``!KP`(CB$!"&X@@@H./^___K -M`0R(XA@0AN(((*#C_O__ZP`@H.,A/`'C`R#%YP4`H.$($*#A`2"@X_[__^LJ -M``#J)`#4Y08`@.(``H7@8PV`XC"`A.*^(M3A#`"`X@@0H.$0`%+C$""@(_[_ -M_^LD`-3E"@"`X@`"A>!C#8#B#`"`XA`0B.(((*#C_O__ZR0`U.4.`(#B``*% -MX&,-@.(,`(#B&!"(X@@@H./^___K`3"@XR`L`>,",,7G)!#4Y;XO0N("$(7G -M!0"@X080H.$D(-3E_O__ZRPZ`^,#,)7G#0!3XPX@H`,L.@,#`R"%!P4`H.'^ -M___K`$!0XA$```H'`*#A9!"?Y?[__^L``%#C`#"@$^@PA!4T/`'C`S"5YP8` -M4^,$`%,3!@``&LPX`>,#,)7G[#"$Y0!`H.,"``#J%4#@XP```.H`0*#C!`"@ -MX?"'O>@`0*#C````ZEY`X.,'`*#A"A"@X?[__^OV___J##,``!0S``#P1RWI -M`*"@X0*`H.$#4*#AMF+3X4!@AN(&`*#A_O__ZP!`H.$`<*#A``!0XT$```H` -M$*#C!B"@X?[__^L$`*#A`S"@XP0P@.3_$*#C!B"@X_[__^NT,M7A`P!3XP/Q -MGY4(`!/C`3"@$QPPQQ4&,-CE`3!#XB0PQ^4`,)7E`@`3XP,```HE -M`(?B#!"%X@@@H./^___KMC+5X0``4^,$```*OC+'X3``A^(H$(7BMB+5X?[_ -M_^L*`*#A!Q"@X08@H.'*_O_K`%"@X00`H.$&$*#A_O__ZP```.H`4.#C!0"@ -MX?"'O>AP0"WI`%"@X0)`H.$`9)#EMC#2X0,ZH.$C.J#A"@!3XP/QGY<*``#J -M&,$$`!C!!``8P00`&,$$`&C`!`"0P`0`X,`$`!C!!``8P00`8,`$`!C!!`!> -M`.#C<("]Z``PDN4``%/C`2"@$R@W`A,#(,87``"@$P``H`,H-P(#`P#&!W"` -MO>@T/`'C`S"6YP``4^,=```*`#"2Y0``4^,:```*`2"@XS0\`>,#((;G``"@ -MX\PX`>,#`(;G)#D!XP,`AN?(.`'C`P"&YS`\`>,#`(;G<("]Z&PPEN4!`!/C -M!@``"@8`H.'^___K!@"@X?[__^L&`*#A`1"@X_[__^L%`*#A`!"4Y0'O_^MP -M@+WH``"@XW"`O>CP3RWI%-!-X@!@H.$"0*#A`#"@XPPPC>4(,(WE`5"@X0,` -M4>$`$*`3`1"@`X``4N,!,*"1`3"!@P``4^,&```*`""@XQ@Z`>,#(,#G`@!1 -MX0)`H!$50.`#W```Z@``4N,`0*`#V0``"@2PH.$$`*#A_O__ZP!P4.(+0.`# -MTP``"@<`H.$%$*#A"R"@X?[__^L$4*#A``!4XP,``-H`,*#C"#"#X@,`5>'\ -M___*`P!4XP!`X)/3``":!P"@X040H.$,((WB"#"-XO[__^L!`%#C"@``&@(@ -MH./(.`'C`R"&YP0@H.,P/`'C`R"&YR8,AN(D`(#B!Q"@X0L@H.'^___K!P"@ -MX040H.$,((WB"#"-XO[__^L!`%#C"@``&@(@H./(.`'C`R"&YP<@H.,P/`'C -M`R"&YR8,AN(D`(#B!Q"@X0L@H.'^___K##"=Y0$P0^(/`%/C`_&?ES$``.J\ -MP@0`V,($`$3#!``LPP0`1,,$`$3#!`!$PP0`],($`$3#!`!$PP0`1,,$`$3# -M!`!$PP0`1,,$`$3#!``0PP0``""@XR0Y`>,#((;G`2"@XS0\`>,#((;G&@`` -MZ@$@H.,D.0'C`R"&YP`@H.,T/`'C`R"&YQ,``.H"(*#C)#D!XP,@AN<$(*#C -M-#P!XP,@AN<,``#J!""@XR0Y`>,#((;G!B"@XS0\`>,#((;G!0``Z@4@H.,D -M.0'C`R"&YP`@H.,T/`'C`R"&YP@PG>4!,$/B#P!3XP/QGY,#((;G!""@XS0\`>,# -M((;G0P``Z@0@H./,.`'C`R"&YP8@H.,T/`'C`R"&YSP``.H%(*#CS#@!XP,@ -MAN<`(*#C-#P!XP,@AN,#(,;G`#``XP`P0.,`,)/E!#"- -MY30``.H%@*#A!:"'X``PVN7=`%/C'0``&@(`A>(``(?@!!"-X@0@H./^___K -M`0!0XQ8``!H!0*#C"H"@X00@VN<"((+B`@Q2XP(LH*,!U4/_F!0!4X=7__XH,``#J!`"@ -MX130C>+PC[WH`""@XQ@Z`>,#(,;G`#``XP`P0.,`,)/E!#"-Y0!0H.,!D*#C -MQ___Z@!`H.,'`*#A"Q"@X?[__^OM___J$$`MZ0`$D.4#$*#AM"#2X?3^_^L0 -M@+WH\$$MZ0C03>("0*#A`#"@XP0PC>4`5)#ELC#-X0$PS>5L,)7E`0`3XP(` -M`!I``!/C``#@`UD```I0,97E%@Z%XBT0H.,$((WB##!#XO[__^L`$%#B$``` -M"@0PG>4``%/C#0``"@%@H.$"`(WB!1"!X@(@H./^___K`C#VY0$@UN4"-(/A -MTW#@YV``$^,`8*`#`6"@$P&`H.,"``#J`&"@XP9PH.$&@*#A/#'5Y0$@0^)R -M(._F_0!2XP`0H(,,``"*!2"@X0`0H.,!P*#A?S`#X@$`4^$#$*`A!,#$Y3TQ -MTN4!((+B`0!#XG``[^;]`%#C]?__F@$`6.,C```:!0"@X100H.,!((WB:#L# -MXP_@H.$#\)7G`3#=Y0,`4^,)```:``!7XP,```H``%;CEF"@$X=@H`,-``#J -M``!6XTA@H!-!8*`#"0``Z@``5^,$```*#C$`XP``5N,#8*`!2V^@$P(``.H` -M`%;CD&"@$X)@H`.&(*#A(#$*XPD@T$WB`%20Y0!`DN4$X-+E#<"@ -MX3`QG^4/`)/H!P"LZ``PS.4!`'3C,```"J1"H.'%.@7C?#I`XY,D@^"C,Z#A -M;@!3XP5`H`,I```*#P``BC<`4^,"0*`#)0``"@4``(H*`%/C`$"@`R$```H4 -M`%/C'@``&A4``.H\`%/C`T"@`QL```I:`%/C&```&A$``.KP`%/C"$"@`Q4` -M``H%``"*>`!3XP9`H`,1```*M`!3XPX``!H)``#J6@]3XPE`H`,+```*'@Y3 -MXP@``!H%``#J`4"@XP8``.H$0*#C!```Z@=`H.,"``#J"D"@XP```.H+0*#C -M`#"@XPW`H.$0`(WB`&#@XP,@W.<$`%+A`V#`%P(``!H#(,#G``!>XP(```H! -M,(/B#0!3X_7__QH%`*#A$!"-XO[__^L!`%#C``"@`P``X!,@T(WB<("]Z)!; -M``#P0"WI#-!-X@)@H.$`1)#E`#"@XP0PC>5L,)3E00`3XSL```I0,93E%@Z$ -MXBT0H.,$((WB##!#XO[__^L``%#C`'"@`P(```H$<)WE`'!7X@%PH!-/7X3B -M!0"@X?[__^L!`%#C"```&@$`5^,&`*#A$!"@XP`@``,`($`#`"``$P`@0!/^ -M___K)@``Z@4`H.'^___K`0!0XP@``!H!`%?C!@"@X1`0H.,`(``#`"!``P`@ -M`!,`($`3_O__ZQD``.HD,93E#@!3XP@``)H!`%?C!@"@X1`0H.,`(``#`"!` -M`P`@`!,`($`3_O__ZPT``.H!`%?C!@"@X1`0H.,`(``#`"!``P`@`!,`($`3 -M_O__ZP0``.H"`*#A$!"@XP`@`.,`($#C_O__ZP``H.,,T(WB\("]Z/A/+>D# -M<*#A`$20Y8X_H..T,,+A!P"@X0`0H.,#(*#A_O__ZT`[!.-,,$#C`#"'Y60P -MH.,L,,?E+3#'Y2XPQ^4',*#C+S#'Y5P@H.,P(,?E32#@XS$@Q^4`4*#C,E#' -MY3,PQ^4$,*#C-##'Y0`P`.,`,$#C`""3Y3@@A^4$()/E/""'Y0@@D^5`((?E -M##"3Y40PA^4!/*#CP#"'Y2HY`./$,(?EO%W'X18PH.,8,/K__\:$SZ@X[-@A^$R8$D,93E!C#%Y0D``.K>!]3E_O__ZZ`V".,!,$#CDP`#X``P -MA>4!,*#CM##%X=XWU.4&,,7E``"@XW"`O>CP3RWIQ=]-X@`0H.$"L*#A`T"@ -MX0`PH./T,HWE`BR-XK([PN$L.@/C`S"0YP``4^,1```*`0!3XP\```HL`(OB -MZ1V!X@L0@>('(*#C_O__ZP``4./*`@`*`""@XS$^C>)D("/ED!";Y:``B^(, -M$$'B_O__ZP``4./!`@`*%3L(X_\_3^,"+(WBOC_"X0$PH.,#+(WBL##"X0,, -MC>("`(#B(!"+X@8@H./^___K%&"$XC@SG>4&`%/A"P``FC%>C>(4(*#CM"%E -MX00`H.$%$*#A!""@X_[__^L$`(3B!!"%XA`@H./^___K!D"@X1L["./_/T_C -M`BR-XKX_PN$!,*#C`RR-XK8PPN&X,MOA(`!3XR`PH".T,,+A+*"+X@@P@^(# -M<(3@.".=Y0<`4N$0``":,5Z-XK0Q9>$$8*#C!`"@X040H.$&(*#A_O__ZP8` -MA.`($(7B!B"@X?[__^L(`(3B"A"@X0,\C>*T(-/A_O__ZP=`H.&@((OB&""- -MY9`PF^4"`*#A+1"@X[TOC>(,,$/B_O__ZP`04.(4```*]#*=Y0``4^,1```* -M`5"@X2L.C>("`(#B!1"!X@(@H./^___K`C#UY0$@U>4"-(/ATR#@YR0@C>5@ -M`!/C`#"@`P$PH!,4,(WE`2"@XQ`@C>4#``#J`#"@XQ0PC>4D,(WE$#"-Y0$[ -M"./_/T_C`BR-XKX_PN%\4(OB!0"@X?[__^L!`%#C"0``&A`PG>4!`%/C`PR- -MXA`0H.,`(``#`"!``P`@`!,`($`3_O__ZR,``.H%`*#A_O__ZP$`4.,)```: -M$""=Y0$`4N,##(WB$!"@XP`@``,`($`#`"``$P`@0!/^___K%0``ZF0PF^4. -M`%/C"0``FA`PG>4!`%/C`PR-XA`0H.,`(``#`"!``P`@`!,`($`3_O__ZP@` -M`.H0()WE`0!2XP,,C>(0$*#C`"```P`@0`,`(``3`"!`$_[__^L48(3B.#.= -MY08`4^$+``":,5Z-XA0@H..T(67A!`"@X040H.$$(*#C_O__ZP0`A.($$(7B -M$""@X_[__^L&0*#A!SL(X_\_3^,"+(WBOC_"X90PB^(,,(WE`P"@X?[__^L` -M$*#AO@^-X@(`@.("(*#C_O__ZP(LC>*Z/]+A`P`3XQ0```H!`!/C`S"@$P$P -MH`,`,XWE"("$XC@SG>4(`%/A#```FC%>C>(((*#CM"%EX01@H.,$`*#A!1"@ -MX08@H.'^___K!@"$X`80A>`&(*#A_O__ZP```.H$@*#A9#";Y0``4^,!,*`# -M9#"+!04["./_/T_C`BR-XKX_PN%D`)OE_O__ZZ`V".,!,$#CDP`#X``SC>4! -M,*#C`RR-XK0PPN%D,)OE!C/-Y0Q0B.(X,YWE!0!3X0L``)HQ3HWB#""@X[0A -M9.$(`*#A!!"@X00@H./^___K!`"(X@00A.(((*#C_O__ZP6`H.$K.PCC_S]/ -MXP(LC>*^/\+ANC_2X1``$^,".Z`3`CF@`P,LC>*V,,+A`#"@XP,LC>*T,,+A -M"%"(XC@SG>4%`%/A$0``FC%.C>(((*#CM"%DX01@H.,(`*#A!!"@X08@H.'^ -M___K!@"(X`@0A.(&(*#A_O__ZP4`H.$*$*#A`SR-XK0@T^'^___K!8"@X:U_ -MC>('`*#A0!"@XP`@`.,`($#C_O__ZWP@V^4``%+C`&"@`Q\```JM3XWB`$"$ -MX`M0H.$`8*#C0'"'X@"0`.,`D$#C`#``XP`P0.,<,(WE`*``XP"@0.,@@(WE -M`X"@X7\P`N(&`%/A`V"@(0<09."C,*#A`0`2XP@@H`$)(*`1`""-Y00`H.$* -M(*#A_O__ZWT@U>4!4(7B``!2XP!`A!#N__\:(("=Y1`@G>4!`%+C+P``&@(L -MC>*R.]+A`@D3XPP```HD,)WE``!3XP0```H.80#C%""=Y0``4N-+;Z`3(@`` -MZA0PG>4``%/CD&"@$X)@H`,=``#J@``3XPH```HD()WE``!2XP,```H4,)WE -M``!3XQ0``!H/``#J%""=Y0``4N,.```:"0``ZB0PG>4``%/C`P``"A0@G>4` -M`%+C"0``&@0``.H4,)WE``!3XP,``!I!8*#C!```ZH=@H.,"``#J2&"@XP`` -M`.J68*#CAF"@X2$["./_/T_C`BR-XKX_PN$`,*#C!3/-Y00SS>4@,0KC!S!` -MXY,&`^``,XWE#%"(XC@SG>4%`%/A"P``FC%.C>(,(*#CM"%DX0@`H.$$$*#A -M!""@X_[__^L$`(CB!!"$X@@@H./^___K!8"@X0`PH.,"+(WBL#O"X;PZPN&0 -M$)OE2S^-X@`PC>4K/HWB!#"-Y0P`G>4L((WBJS^-XO[__^L"+(WBL#O2X0`` -M4^-@```*BT^-X@0`H.$`$*#C@""@X_[__^L`,`#C`#!`XP,`D^@#`(3H`BR- -MXK`[TN$``%/C#P``"B->C>(#4(7B`$"@XP!@`.,`8$#C2W^-X@4`H.$&$*#A -M!"#7Y_[__^L`4(7@`4"$X@(LC>*P.]+A!`!3X?7__XJ_#XWB`!"@XQ0@H./^ -M___K`CP(X_\_3^,"+(WBOC_"X8L/C>+^___K<##_Y@,LC>*T,,+A"#"#X@-@ -MB.`X(YWE!@!2X1```)HQ3HWBM#%DX010H.,(`*#A!!"@X04@H.'^___K!0"( -MX`@0A.(%(*#A_O__ZP@`B.*+'XWB`SR-XK0@T^'^___K!H"@X;\/C>(`$*#C -M%""@X_[__^L%/`CC_S]/XP(LC>*^/\+AL#O2X0,LC>*T,,+A"#"#X@-@B.`X -M(YWE!@!2X1```)HQ3HWBM#%DX010H.,(`*#A!!"@X04@H.'^___K!0"(X`@0 -MA.(%(*#A_O__ZP@`B.)+'XWB`SR-XK0@T^'^___K!H"@X0(LC>*\.M+A``!3 -MXV````J+3XWB!`"@X0`0H..`(*#C_O__ZP`P`.,`,$#C`P"3Z`,`A.@"+(WB -MO#K2X0``4^,/```*(UZ-X@-0A>(`0*#C`&``XP!@0.,L<(WB!0"@X080H.$$ -M(-?G_O__ZP!0A>`!0(3B`BR-XKPZTN$$`%/A]?__BK\/C>(`$*#C%""@X_[_ -M_^L"/`CC_S]/XP(LC>*^/\+ABP^-XO[__^MP,/_F`RR-XK0PPN$(,(/B`V"( -MX#@CG>4&`%+A$```FC%.C>*T,63A!%"@XP@`H.$$$*#A!2"@X?[__^L%`(C@ -M"!"$X@4@H.'^___K"`"(XHL?C>(#/(WBM"#3X?[__^L&@*#AOP^-X@`0H.,4 -M(*#C_O__ZP4\"./_/T_C`BR-XKX_PN&\.M+A`RR-XK0PPN$(,(/B`V"(X#@C -MG>4&`%+A$```FC%.C>*T,63A!%"@XP@`H.$$$*#A!2"@X?[__^L%`(C@"!"$ -MX@4@H.'^___K"`"(XBP0C>(#/(WBM"#3X?[__^L&@*#A`#"@XZPRC>60<)OE -M#'!7XC<```H#0*#AJZ^-X@4L"./_+T_C#""-Y;\_C>((,(/B$#"-Y0&0H.,$ -M4*#A%+"-Y0>PH.$8<)WE!6"'X`8`H.$*$*#A_O__ZP``4.,=```*K#*=Y0(` -M4^,:``":#""=Y0(\C>*^+\/AO#K3X0,LC>*T,,+A"#"#X@-`B.`X(YWE!`!2 -MX0\``)H"+(WBO#_"X0@`H.&_'XWB!""@X_[__^L$`(CB$!"=Y00@H./^___K -M"`"(X@80H.$#/(WBM"#3X?[__^L$@*#A!3"'X`DPT^<",(/B`U"%X`4`6^'5 -M__^*%+"=Y0$\"./_/T_C`BR-XKX_PN%+,*#C`S/-Y8PPV^4!,(/BHS"@X5\P -M0^(!,\WEC3#;Y0`SS>4`,*#C`C/-Y0A@B.(X,YWE!@!3X0X``)HQ3HWB"""@ -MX[0A9.$$4*#C"`"@X000H.$%(*#A_O__ZP4`B.`%$(3@!2"@X?[__^L&@*#A -M````Z@2`H.$(`*#AQ=^-XO"/O>CP3RWI'-!-XA00C>4,((WE$#"-Y0!DD.6T -ML-+A"["#X.0S`^,#,-;G``!3XP0```K,.P/C`S"6YP``4^,50.`31@``&BPZ -M`^,#4);G``!5X\A0H!-D4*`#`$"@XQYPH.,$``#J!P"@X?[__^L!0(3B!`!5 -MX0(``#IL,);E`@L3X_?__QK^___K#2"@X7\]PN,_,,/C!""3Y0$@@N($((/E -MA*"&XH1`EN5^?H;B!'"'XA"`G>7_D@#C"@"@X000H.'^___K`0!0XQ8```H+ -M,&C@"0!3X09`X-,3``#:!%"@X0<`H.%D$)3E_O__ZP$`4.,*```:*`"$XO[_ -M_^L!`%#C!@``&@"PC>4&`*#A%!"=Y00@H.$(,*#AT_S_ZP"`H.$`0)3EX___ -MZ@!`H.,-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K$#"=Y0B`8^`,()WE -MM(#"X0`PH..V,,+A!`"@X1S0C>+PC[WH$$`MZ0`$D.4``%/C#0``"K`PT^$` -M`%/C`P``"@$`4^->`.`3$("]&`,``.K^___K``!0XP,```H$``#J_O__ZP`` -M4.,!```:``#@XQ"`O>@``*#C$("]Z/!`+>D4T$WB`%"@X0%`H.$!`*#A_O__ -MZP$,4.,:``"*`0$`X_[__^L`8%#B%@``"@0`H.'^___K`""@X08`H.$$$*#A -M_O__ZPUPH.$-`*#A`!"@XQ`@H./^___K!`"@X?[__^NT`,WA"#P#XP,`E><" -M'`CC#2"@X08PH.'^___K!@"@X0$1`./^___K%-"-XO"`O>@P0"WI%-!-X@!0 -MH.$-0*#A#0"@X0`0H.,0(*#C_O__ZP$PH..P,,WA`@"-X@`0H.,&(*#C_O__ -MZP@\`^,#`)7G%1L(XPT@H.$`,*#C_O__ZQ30C>(P@+WH,$`MZ1303>(`4*#A -M#4"@X0T`H.$`$*#C$""@X_[__^L!,*#CL##-X0(`C>+@$(7B!B"@X_[__^L( -M/`/C`P"5YQ4;".,-(*#A`#"@X_[__^L4T(WB,("]Z#!`+>D4T$WB`%"@X0U` -MH.$-`*#A`!"@XQ`@H./^___K"#P#XP,`E><9&PCC#2"@X0`PH./^___K%-"- -MXC"`O>CX3RWI`+"@X0&0H.$"@*#A`Z"@X1P`H./^___K`&"@X0!`H.$``%#C -M``"@`_B/O0@4`*#C_O__ZP!PH.$`4*#A``!0XP0``!H&`*#A'!"@X_[__^L` -M`*#C^(^]Z``0H.,4(*#C_O__ZP&@Q^4`@,?E`3"@XP,PQ^4!@$CB>(#OY@0` -M6.,0(*"#`#``DP`P0),(@(.0%"#8E00`A^()$*#A_O__ZQ0PH..P,,;A!'"& -MY0@PAN4`,*#C##"&Y1`PAN44`(;B_O__ZP4+B^(H`(#B!A"@X?[__^OXC[WH -M$$`MZ04@0N)R(._F"`!2XP`@H(,`P`"3`,!`DP(@C)`<(-*5OO__ZQ"`O>CP -M3RWI%-!-X@!0H.$!0*#A_#L(XP,`4N&<```*_CL(XP,`4N$$```*\3D(XP,` -M4N%>4.`3S`,`&L<#`.JT`='A/P!0XX\``)H0,)'E``!3XXP```K^___K`'"@ -MX0!@H.$``%#C"U#@`[\#``H0$)3EM"'4X0T`H.%_/<#C/S##XP@PD^4"`)'@ -M`P#0,``PH#,``%/C!```&@<`H.'^___K``!0XPH```H$``#J``!2XP<```H' -M`*#A`A"@X?[__^L'`*#AM!'4X?[__^L-4.#CI0,`Z@`PEN4!,$/B`P!3XP/Q -MGY<#``#J&-P$`-#4,,-;E!P!3 -MXP@``(K<,-;A`0"@XQ`SH.'<`!/C(0``&B``$^,;```:`@`3XP$``!I>4.#C -M.P``Z@(`H./(.`'C`P""Y_\0`>(!`%'C`@``"@``4>$3```:!@``Z@0PH.,P -M'`'C`3""YS0<`>,!,(+G`%"@XRL``.H'$*#C,#P!XP,0@N<&$*#C-#P!XP,0 -M@N<`4*#C(P``Z@4`H.$6Z/_K`%"@X1\``.H`4*#C'0``Z@`$E>4P$(;BO"#6 -MX0_Y_^L`4*#A%P``Z@4`H.$&$*#AM"'4X8?W_^L`4*#A$0``Z@`$E>4,,);E -M`0!3XP,```H"`%/C7E#@$PH``!H#``#J_O__ZP``4.,#```:!```ZO[__^L` -M`%#C`0``"@!0H.,```#J`%#@XP``5>,/```:$`"4Y;0AU.$-$*#A?SW!XS\P -MP^,(,)/E`A"0X`,0T3``,*`S``!3XP(``!H&$*#A_O__ZP`@H.$``%+C#5#@ -M$P<`H.&T$=3A_O__ZS@#`.H54.#C-@,`Z@`DM>7A.P/C`S#2YP``4^,`4.`# -M,`,`"A`PD>4``%/C%5#@`RP#``JT`='A_O__ZP0`C>4`8*#A``!0XPM0X`,E -M`P`*$!"4Y;0AU.$-`*#A?SW`XS\PP^,(,)/E`@"1X`,`T#``,*`S``!3XP0` -M`!H&`*#A_O__ZP``4.,*```*!```Z@``4N,'```*!@"@X0(0H.'^___K!`"= -MY;01U.'^___K#5#@XPL#`.H`,);E`3!#XA(`4^,#\9^7$@``ZKS>!`#8W@0` -ML-\$`+3>!``(Z`0`Y.`$`+3>!`"TW@0`M-X$`+3>!`"TW@0`M-X$`+3>!`"T -MW@0`M-X$`'S@!`"8Z`0`..D$`*SI!`!>4.#CUP(`Z@!0E>4%`*#A_O__ZP4` -MH.'^___K`%"@X=`"`.H`<)7E;#"7Y1$`$^,O```*!#"6Y0$`<^,#```:N"#6 -MX0$X@^(#`%+A*```"EL-A^(X`(#B!!"&XO[__^L`4%#B"U#@`[X"``H0@);E -MO##6X=0PA>43#H7B%!"&XA`@H./^___K`@P8XP$PH!,`,*`#W#"%Y5I#H7B#0"`XB00 -MAN(:(*#C_O__Z]@TE^4``%/CA#:%!0<`H.$%$*#A_O__ZP!0H..<`@#J%5#@ -MXYH"`.H`<)7E;#"7Y1$`$^,L```*!#"6Y0$`<^,#```:N"#6X0$X@^(#`%+A -M)0``"EL-A^(X`(#B!!"&XO[__^L`4%#B`%"@`X@"``K^___K#1"@X7\]P>,_ -M,,/C!""3Y0$@@N($((/E:XZ%X@B`B.((`*#A_O__ZP``4.,(```:O#:5Y;@F -ME>4$,(+E`""#Y;B&A>6\AH7E!P"@X040H.'^___K#2"@X7\]PN,_,,/C!""3 -MY0$@0N($((/E_O__ZP!0H.-I`@#J%5#@XV<"`.JT<=3A`%"5Y6PPE>40`!/C -M$@``"F,-A>(,$(;B`B"@X_[__^MC/:#CLS"5X0$P0^)S,/_F'P!3XV,]H(,@ -M`*"#LP"%@04`H.$.$(;B#B!'XO[__^L!`%#C`%"@`T\"``H54.#C30(`ZK0A -MU.$`<)7E`#"@XR`PAN4;,,;EOC+6X4`P@^(#`%+A:P(`&@0PEN4!`'/C!P`` -M&K@@UN$!.(/B`P!2X0,``!HD,-;E`P!3XV$"`(H&``#J6PV'XC@`@.($$(;B -M_O__ZP"`4.)0`@`:5P(`Z@Q0AN(%`*#A8!F?Y?[__^L``%#C40(`"@4`H.%0 -M&9_E_O__ZP$`<.(``*`S``!0XP$PH`,`@*`#4P``"B2`UN6^DM;A`3!YX@`P -MH#,#`%CC`3"#@P``4^-"`@`:``!9XP!0H`,%H*`!#0``"@4`6>,%D*"3#9"@ -M@PR@B>(*`*#A_O__ZP!04.(T`@`*!0"@X0`0H.,*(*#A_O__ZPB0A>4`H(7E -M!("%Y0R0A>()`*#A,!"&X@@@E>7^___K'##6Y0``4^,@```*`""@XS0\`>,# -M((?G`3"@X\PH`>,",(?G6"""X@(PA^<(,)7E#0!3XP4PH`-8($("`C"'!U@@ -M@@(",(<'T#@!XP.`A^=C#XCB``*'X!0`@.()$*#A"""5Y?[__^L9/8CB`S&' -MX`@@E>44((/E!P"@X0P0A>(((-7E"#"@X13^_^M3`0#J8P^(X@`"A^`4`(#B -M"1"@X0@@E>7^___K&3V(X@,QA^`(()7E%""#Y0<`H.$,$(7B""#5Y0@PH.$$ -M_O_K0P$`Z@``4^-P```*;#"7Y1``$^-M```*'##6Y0$`4^/L`0`:``!0XQ(` -M``HD`-;E!@"`X@`"A^!C#8#BOB+6X0P`@.(P$(;B$`!2XQ`@H"/^___K`2"@ -MXR0Y`>,#((?GOC+6X0T`4^,$(((")#D!`P,@AP<\``#J!0"@X6P7G^7^___K -M``!0XR$``!H"(*#C)#D!XP,@A^,#,)?G[#"`Y5P!`.K(.`'C`R"7YP(`4N,`,*`3`3"@`P``6.,`,*`# -M``!3XW@!``IL,)?E$``3XW4!``H<,-;E`0!3XU8``!HPH(;BOB+6X1$.B.(* -M$*#A$`!2XQ`@H"/^___K!0"@X;@5G^7^___K``!0XP8``!H!,*#C[#"(Y;XR -MUN$-`%/C!3"@`^PPB`49``#J!0"@X8P5G^7^___K``!0XPT``!H",*#C[#"( -MY?``B.(0$(KB"""@X_[__^L!#(CB&!"*X@@@H./^___K`2"@XR$\`>,#(,?G -M!@``Z@4`H.%$%9_E_O__ZP``4.,$,*`#`#"@$^PPB.4<`*#C_O__ZP"@H.$` -M`%#C(0``"A@`H./^___K`)"@X0"PH.$``%#C`P``&@H`H.$<$*#C_O__ZQ<` -M`.H4`(KB_O__ZQ40H..P$,KA!)"*Y1@PH.,(,(KE`#"@XPPPBN40,(KE[#"8 -MY08PR>4)`*#AX!"(X@8@H./^___K"`")XA$>B.(0(*#C_O__ZP4+A^(H`(#B -M"A"@X?[__^L`4*#CZ%"(Y?8``.H``%#C$@``"B0`UN4&`(#B``*'X&,-@.*^ -M(M;A#`"`XC`0AN(0`%+C$""@(_[__^L!(*#C)#D!XP,@A^>^,M;A#0!3XP0@ -M@@(D.0$#`R"'!SP``.H%`*#A*!2?Y?[__^L``%#C(0``&@(@H.,D.0'C`R"' -MYR0`UN4&`(#B``*'X&,-@.(P4(;BOB+6X0P`@.(%$*#A$`!2XQ`@H"/^___K -M)`#6Y0H`@.(``H?@8PV`X@P`@.(0$(7B"""@X_[__^LD`-;E#@"`X@`"A^!C -M#8#B#`"`XA@0A>(((*#C_O__ZP$@H.,A/`'C`R#'YQ4``.H%`*#AD!.?Y?[_ -M_^L``%#C#0``&@0@H.,D.0'C`R"'YR0`UN4&`(#B``*'X&,-@.*^(M;A#`"` -MXC`0AN(0`%+C$""@(_[__^L"``#J`""@XR0Y`>,#((?G)"#6Y2@Y`>,#((?G -M`2"@X[X_@^(#(,?GOS]#X@,@E^=8,$/B`R"'YP<`H.$P$(;B.)```*!0"@X0H0H.'^___K`%"@XX0``.H`,)7E;""3Y1$`$N,=```*!""6 -MY0$`4"((+B(`!2XR`@H",, -M((;E=QZ!XA``AN(%$('B_O__ZP!0H.-B``#J%5#@XV```.JT<=3A+#*?Y2@P -MD^4,,(WE`%"5Y6PPE>40`!/C'0``"@YP1^*`!Y7E``!0XP,```J0%Y7E_O__ -MZP`PH..`-X7E``!7XP!0H---``#:!P"@X?[__^N`!X7ED'>%Y0``4.,,```* -M#A"&X@<@H.'^___K!0"@X=T0H.,,((WB`3"@X_[__^L!(*#C(#0!XP,@Q><` -M4*#C.@``ZA50X.,X``#JM''4X0!0E>5L,)7E$``3XQ4```H.<$?BB`>5Y0`` -M4.,#```*F!>5Y?[__^L`,*#CB#>%Y0``5^,`4*#3*```V@<`H.'^___KB`>% -MY9AWA>4``%#C!```"@X0AN('(*#A_O__ZP!0H.,=``#J%5#@XQL``.JT<=3A -M`%"5Y6PPE>40`!/C%0``"@YP1^*,!Y7E``!0XP,```J<%Y7E_O__ZP`PH.., -M-X7E``!7XP!0H-,+``#:!P"@X?[__^N,!X7EG'>%Y0``4.,$```*#A"&X@<@ -MH.'^___K`%"@XP```.H54.#C``!5XP\``!H0`)3EM"'4X0T0H.%_/<'C/S## -MXP@PD^4"$)#@`Q#1,``PH#,``%/C`@``&@80H.'^___K`""@X0``4N,-4.`3 -M!`"=Y;01U.'^___K`P``Z@4`H.'Q*0CC_O__ZP!0H.$%`*#A%-"-XO"/O>@, -M4(;B!0"@X200G^7^___K`0!PX@``H#,`,*#C"O[_Z@!0H./8___J%5#@X];_ -M_^H,,P``"#,``!0S```<,P``C%L``!!`+>F0,P/C`S"0Y_\TP^/_,,/C`0A3 -MXRH```J$,P/C`S#0YP``4^,H```*D3,#XP,PT..2P8'@S@V`XA0`@.(A$X/@_O__ZP$`H.,0@+WH``"@ -MXQ"`O>@!`*#C$("]Z/!!+>D(T$WB`&"@X0)0H.$#0*#A`P"@X0`0`.,`$$#C -M!""@X_[__^L``%#C)P``"K0@U>$$($+B$$,(3B`(26Y0$@0N(! -M`%+C`P``"@(`4N,`<*`3"```&@,``.H`<-/E,'!'XG=P[^8#``#J``#3Y0$0 -MT^7^___K`'"@X0H`5^,0``"*A#,#XP,PV.<'`%/A#```"@``5^,"(*`3@S,# -M$P,@R!(` -M,*#C!#`BY00`A.(`$`#C`!!`X_[__^L$,)WE`0!3XQ,``(J!(P/C`C#%YP$@ -MH..$,P/C`R#%YP`P`.,`,$#C`#"3Y<@C`^,"()7G9!"@XY$"`>#3+03C8B!! -MXY(!@>#.#87B%`"`XB$3@^#^___K!P``Z@(`4^,%```:!0"@X?[__^L``%#C -M`""@$X0S`Q,#(,47``"@XPC0C>+P@;WH\$4MZ2S03>("4*#A`V"@X0!$D.4$ -M`*#A_O__ZP``4.-?```*)#P#XP,PE.<``%/C6P``"K2`U>$@`%CC!@#@@UH` -M`(IL,)3E$``3XU0``!HP/`'C`Z"4Y[8PU>$``%/C40``"@``6.-/```*(`!8 -MXR"`H",$4(WB!0"@X0`0H.,D(*#C_O__ZRAPC>(D@"?E!`"%X@80H.$((*#A -M_O__Z_[__^L-(*#A?SW"XS\PP^,$()/E`2""X@0@@^6$8(3BA#"4Y7@PA.4$ -M<(?B!@"@X7@0E.7^___K`0!0XR$```IX4)3E!0"@X2PPD.1X,(3E!Q"@X00@ -MG>7^___K`0!0X_'__QHH()7E!#"=Y0,`4N'M__\:;#"4Y2``$^,#```*>""5 -MY3@QE.4#`%+AYO__&@0`H.%X$)7E_O__ZP``4.,(```:#2"@X7\]PN,_,,/C -M!""3Y0$@0N($((/E_O__ZP``X.,1``#J#2"@X7\]PN,_,,/C!""3Y0$@0N($ -M((/E_O__ZP0`H.$*$*#A_O__ZP0`H.$$$(WB_O__ZP``4.,!```:``#@XP`` -M`.H``*#C+-"-XO"%O>CP3RWI4]]-X@)0H.$#8*#A`$20Y00`H.'^___K``!0 -MXZ@```K,.P/C`S"4YP``4^.D```:)#P#XP,PE.<``%/CH```"N$[`^,#,-3G -M``!3XYP```H8-=3E`0!3XP,``!H$`*#A_O__ZP``H..6``#J;#"4Y2(-$^,# -M```*!`"@X?[__^L``*#CCP``ZBPZ`^,#,)3G``!3XPL```H!`%/C"0``"@4` -M4^,%(*`3+#H#$P,@A!<`(*#C?3H#XP,@Q.<$`*#A`1"@X_[__^L$`(WB`!"@ -MXU$OH./^___KM##5X4\/4^,;```:MC#5X0(`$^-T```*`5#6Y2``5>,@4*"C -M"`"-XA00AN(%(*#A_O__ZP10C>7^___K#1"@X7]=P>,_4,7C!#"5Y0$P@^($ -M,(7E!`"@X000C>(!(*#C_O__ZP!`H.$$,)7E`3!#X@0PA>7^___K6```Z@L` -M4^-3``":!@"@X6@1G^4,(*#C_O__ZP$`4.--```:M(#5X0R`2.(,8(;B`'"@ -MXP>@H.$DD*#C!+"-XC(``.H!,-;D`8!(XD@`4^,"8(8"`H!(`BP```H&``"* -M00!3XP)@A@("@$@")P``"D,`4^,D```:'0``ZE,`4^,&```*5`!3XP%@A@(! -M@$@"'@``"E``4^,;```:%P``Z@``6.,8``#:`5#6Y`&`2.(``%7C"P``"@4` -M6.$)``"ZF0<#X%(?C>(#(('@1%$"Y0,PB^`$`(/B!A"@X04@H.'^___K`7"' -MX@5@AN`(@&7@!@``Z@%@AN(!@$CB`P``Z@)@AN("@$CB````Z@J`H.$``%CC -MRO__RO[__^L-,*#A?UW#XS]0Q>,$,)7E`3"#X@0PA>4$`*#A!!"-X@D@H./^ -M___K`$"@X00PE>4!,$/B!#"%Y?[__^L"``#J!`"@X?[__^L`0*#A``!4XP`` -MH!,````:``#@XU/?C>+PC[WHN%L``/!/+>E,T$WB`*"@X0&PH.$"@*#A%#"- -MY0"4D.4"8*#AM%#2X05PH.$%`*#A_O__ZP!`4.(+4.`#"@$`"@`0F.4-(*#A -M?SW"XS\PP^,(,)/E!R"1X`,@TC``,*`S``!3XP4``!H$`*#A!R"@X?[__^L` -M`%#C"@``"@0``.H``%?C!P``"@0`H.$'$*#A_O__ZP0`H.$'$*#A_O__ZPU0 -MX./P``#JMA#6X68G".,"`%'A`#"@$P$PH`,(`%7C`#"@TP``4^,6```*`#`` -MXP`P0.,\,)/E.#"-Y0`PU.7=`%/CW```&@(`A.(X$(WB!""@X_[__^L!`%#C -MU@``&@(,5>,"7*"C50Z)X@P`@.($$*#A!2"@X?[__^M<5XGE`%"@X\T``.H+ -M`%7C#```V@0`H.$\$Y_E#""@X_[__^L!`%#C!@``&@H`H.$+$*#A"""@X00P -MH.'S_O_K`%"@X;X``.H$`*#A_O__ZQ<`4.,`\9^7FP``ZK#S!`#$\P0`I/0$ -M`,3T!`#8\P0`'/0$`,#U!`#`]00`P/4$`,#U!`#`]00`P/4$`,#U!`#`]00` -MP/4$`,#U!`#`]00`P/4$`.3T!`#`]00`P/4$`,#U!`#`]00`9/0$``D`H.$` -M$`#C`!!`XS+Y_^N#``#J"0"@X0`0`.,`$$#C+?G_ZWX``.IL,)GE`0`3XP<` -M``H$`*#A`!``XP`00./L((GBFC8!X],PF>'^___K5']/_K``!0XP`@H!,H$)T% -M@SX-`QLS1`.3(<,`P1^@`4,I80`$`*#A`!``XP`00./^___K6P``ZG01FN4` -M(-'E`3#1Y0(`T>4``(WE`P#1Y00`C>4$`-'E"`"-Y040T>4,$(WE!`"@X0`0 -M`.,`$$#C_O__ZTL``.H!,*#C6#6)Y00`H.$`$`#C`!!`XP,@H./^___K0P`` -MZ@`PH.-8-8GE!`"@X0`0`.,`$$#C`R"@X_[__^L[``#J`#"@XT0PC>4X4(WB -M!`"@X0`0`.,`$$#C!2"@X?[__^L%`*#A`!``XP`00./^___K``!0XP`PH`-$ -M,(T%%@``"C@`C>(`$`#C`!!`X_[__^L``%#C`C"@`T0PC04.```*.`"-X@`0 -M`.,`$$#C_O__ZP``4.,%,*`#1#"-!08```HX`(WB`!``XP`00./^___K``!0 -MXPPPH`-$,(T%&%"-X@4`H.%$$(WB!""@X_[__^L*`*#A"Q"@X04@H.$4,)WE -M-N__ZP0`H.$`$`#C`!!`XP,@H./^___K!```Z@0`H.$`$`#C`!!`XP,@H./^ -M___K`%"6Y;1@UN$$`*#A_O__ZP$@@.)R(/_F`@!6X08@H#$-$*#A?SW!XS\P -MP^,(,)/E`A"5X`,0T3``,*`S``!3XP,``!H%`*#A!!"@X?[__^L`(*#A``!2 -MXPU0X!,````:`%"@XP0`H.$'$*#A_O__ZP4`H.%,T(WB\(^]Z+A;``#P1RWI -M`F"@X0!$D.4$`*#A_O__ZP``4.-!```*)#P#XP,PE.<``%/C/0``"K`PUN$! -M`%/C%0#@$_"'O1@P/`'C`Z"4Y_[__^L-(*#A?SW"XS\PP^,$()/E`2""X@0@ -M@^6$@(3BA#"4Y7@PA.4"8(;B!G"@XP@`H.%X$)3E_O__ZP$`4.,6```*>%"4 -MY04`H.$@,)#D>#"$Y080H.$'(*#A_O__ZP$`4./Q__\:!`"@X7@0E>7^___K -M``!0XP@``!H-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K``#@X_"'O>@- -M(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K!`"@X0H0H.'^___K!`"@X080 -MH.'^___K``!0XP``H!/PA[T8``#@X_"'O>AP0"WI`E"@X0!$D.4$`*#A_O__ -MZP``4.,>```*X3L#XP,PU.<``%/C&@``"@`PE>4#`%/C`_&?EP,``.K<]P0` -MU/<$`.SW!`#D]P0`%0#@XW"`O>@`4*#C!```Z@)0H.,"``#J!%"@XP```.H! -M4*#C!`"@X040H.'^___K``!0XP0```H$`*#A!1"@X?[__^L``*#C<("]Z``` -MX.-P@+WH#""0Y10PD.4#((+@$#"0Y0(`8^`>_R_A``"!Y:@PD.4,,('E$#"! -MY5`@D.44(('E#`"!Z1[_+^$$`)#E`0!PX@``H#,>_R_A'O\OX?!/+>D,T$WB -M`("@X0%0H.'^___K#1"@X7\]P>,_,,/C!""3Y0$@@N($((/E!JN(XB"@BN(@ -M.`'C`T"8YP9PH.,@L*#C2)4!XSH``.IK;D3B`$"4Y=A@AN*H$)7E!@"@X080 -M@>('(*#A_O__ZP``4.,P```*!0"@X0L0H.'^___K!`"-Y0``4.,:```*J`"0 -MY080H.$'(*#A_O__ZP@`H.$$$(WB_O__ZP``4.,*``"J4"4!X](`B.$!(*#C -M`#"@XP`@DN`!,*/@4!4!X_$@B.$$`)WE_O__ZQ8``.K9`(CA`2"@XP`PH.,` -M()+@`3"CX/D@B.$/``#J4#4!X]-@B.$!0*#C`%"@XP0`EN`%$*?@\P"(X0T@ -MH.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^L``*#C#@``Z@H`H.$$$*#A_O__ -MZP``4..___\*#1"@X7\]P>,_,,/C!""3Y0$@0N($((/E_O__ZP4`H.'^___K -M`0"@XPS0C>+PC[WHT$,MZ0C03>($`(WE`$21Y00`H.'^___K``!0XS````H` -M,`#C`#!`XP`PD^4``%/C'@``&FPPE.40`!/C&P``"@00G>6H,)'E`"#3Y0$` -M4N,&```:`2#3Y0``4N,3```:`C#3Y5X`4^,0```:!P``ZC,`4N,-```:`2#3 -MY3,`4N,*```:`C#3Y?\`4^,'```**#4!XP,PE.=``%/C`P``F@0`H.'^___K -M`0!0XQ4```H$`*#A!!"-XO[__^L``%#C!P``ND@U`>/3@(3A`6"@XP!PH.,& -M`)C@!Q"IX/,`A.$(``#J4#4!X].`A.$!8*#C`'"@XP8`F.`'$*G@\P"$X00` -MG>7^___K``"@XPC0C>+0@[WH$$`MZ0!`4.(0@+T(_O__ZPT@H.%_/<+C/S## -MXP0@D^4!((+B!""#Y00`H.'^___K``!0XPH```I6/83B`!`/X8``#/$$(+/E -M`0""XP``@^4!\"'A`0`2XP$``!I6#83B_O__ZPT@H.%_/<+C/S##XP0@D^4! -M($+B!""#Y?[__^L0@+WH$$`MZ0%`H.$(/`/C`S"0Y[`AD^4",*#A"!"SY0$` -M$>,)```*```/X8``#/$`$)/E`<#!XP#`@^4`\"'A`0`1XP$```H$`)+E_O__ -MZP0`H.'^___K$("]Z!!`+>D!0*#A8!"1Y0``4>,````*_O__ZP`PH.-@,(3E -M$("]Z/!!+>D!8*#A`G"@X0%0H.$`0*#C0`"5Y0``4.,````*_O__ZP%`A.($ -M4(7B"`!4X_?__QH,`);E``!0X_"!O0@'$*#A_O__Z_"!O>CP02WI`4"@X0(` -MH.'^___K#`"$Y0``4.,4```*?P^`X@,`@.*@!*#A@`2@X1``A.4`4*#C8%"$ -MY05@H.'0<*#C!@"@X0<0H.'^___K0`"$Y0``4.,%```*`5"%X@1`A.((`%7C -M]?__&@$`H./P@;WH``"@X_"!O>AP0"WI`$"@X0%@H.$"4*#A_O__ZP4`4.$` -M4*`Q``!6XP4```H4$)3E"0"4Z`$08^`&(*#A!3"@X?[__^L0,)3E!3"#X!`P -MA.4$,)3E`S!EX`0PA.4%`*#A<("]Z#!`+>D4T$WB`$"@X0``4>,5```*U#"1 -MY2``4^,2``"*!CR#X@TP@^(#,8#@!#"3Y0$`4^$,```:$%"-X@$@H..P(67A -M`@"%XN`0@^(&(*#C_O__ZP@\`^,#`)3G!!P(XPT@H.$`,*#C_O__ZQ30C>(P -M@+WH,$`MZ1303>(`0*#A``!1XQ4```K4,)'E(`!3XQ(``(H&/(/B#3"#X@,Q -M@.`$,)/E`0!3X0P``!H04(WB`2"@X[`A9>$"`(7BX!"#X@8@H./^___K"#P# -MXP,`E.<#'`CC#2"@X0`PH./^___K%-"-XC"`O>@00"WI`$"@X0`@`..T,P'C -M`"!`XP,@@.>X,P'C`P"$YTX-@.(D`(#B`!"@XP$@H.'^___K`"``X^@S`>,` -M($#C`R"$Y^PS`>,#0(3G3PV$XA@`@.(`$*#C`2"@X?[__^L0@+WH$$`MZ0`P -M`.,`,$#CP#&!Y<01@>4;#H'B`!"@XP$@H.'^___K$("]Z!!`+>D`0*#A`#`` -MXP`P0.-H-(#E;`2$Y44.@.((`(#B`!"@XP$@H.'^___K`#``XP`P0..D-(3E -MJ$2$Y4D.A.($`(#B`!"@XP$@H.'^___K`#``XP`P0.,P-83E-$6$Y5(.A.(` -M$*#C`2"@X?[__^L0@+WH$$`MZ?[__^L0@+WH$$`MZ?[__^L0@+WH$$`MZ?[_ -M_^L0@+WH\$\MZ0S03>(`0*#AR#@!XP,PD.<"`%/C)@``&@!0`.,`4$#C!0"@ -MX0`0H.,!*Z#C_O__ZR=LA.(P8(;B!0"@X080H.$!*Z#C_O__ZS![`N,'D-3G -M*(<"XPBPU.5C#83B"`"`X@`0H.-P(@'C_O__ZP8`H.$% -M$*#A`2N@X_[__^L'D,3G"+#$YP0PG>4*,(3G`""@XS`\`>,#((3G`2"@XS0\ -M`>,#((3G$0``Z@`PH./(*`'C`C"`Y\PH`>,",(#GT"@!XP(P@.,!,(#G-!P!XP$@@.<8*@'C`C#`YPS0C>+PC[WH -M\$(`D*#A`F"@X=T`4>,Z```:`0R@X_[__^L`H*#A`!"@XP$LH./^ -M___K"@"@X0`0`.,`$$#C$B"@X_[__^L14(KB`7#6Y0)PA^(!#%?C`7R@(P`` -M5^,-```*`#"@XP-`H.$`@`#C`(!`XP4`H.$($*#A`R#6Y_[__^L`4(7@`4"$ -MXG1`[^8$,*#A!`!7X?7__XH%`*#A`!``XP`00.,"(*#C_O__ZPU`H.$-`*#A -M`!"@XQ`@H./^___K`3"%X@,P:N!S,/_F`0Q3XP$\H".T,,WA"#P#XP,`F><" -M'`CC#2"@X0HPH.'^___K``!:XP(```H*`*#A`1R@X_[__^L0T(WB\(>]Z!!` -M+>D`0*#A"#P#XP,`D.?^___K!`"@X?[__^L$`*#A_O__ZP0`H.'^___K$("] -MZ!!`+>D`0*#AJ#P#XP,PD.<``%/C`@``&C``G^7W%P#C_O__ZP``D^4``%#C -M`@``&A@`G^4Y%P#C_O__ZP(,@.+^___K!`"@X?[__^L0@+WHD#0``!!`+>D` -M0*#A_O__ZP0`H.'^___K"#P#XP,`E.?^___K#`"4Y0``4.,0@+T(_O__ZPX0 -MH.,!(*#C_O__ZQ"`O>@00"WI`$"@X?[__^L`,`#C`#!`XP`0D^52#H3BR!"! -MXO[__^L0@+WH$$`MZ?[__^L0@+WH$$`MZ?[__^L0@+WH`0"@XQ[_+^$`,*#C -M"#"!Y0PP@>4!`*#C'O\OX1[_+^$>_R_A$$`MZ0`P`.,`,$#C)#"`Y2@`@.44 -M`(#B`!"@XP$@H.'^___K$("]Z!!`+>G^___K$("]Z'!`+>D`4*#A`4"@X0@P -MD>4!,$/B"#"!Y4``D>7^___K`#"@XT`PA.5$,,3E.##4Y0``4^-P@+T8!0"@ -MX3PV`>,#$)7G`""@XP0PH.'^___K<("]Z/!'+>D`8*#A`7"@X5>-@.(8@(CB -M"$"1Y0``5.-,```*?#"1Y:@PA.6`,)'EG#"$Y70PD>50,(3E;#"0Y1``$^,B -M```*`0"@X310\.4-&X;B$1"!X@8@H./^___K``!0XQH``!H!H!7B!P``"@8` -MH.'^___K`%"@X00`H.$@$*#C_O__ZP"0H.$%``#J6PV&XC@`@.(T$(?B_O__ -MZP!0H.$`D*#C``!5XP@```H(/`/C`R"6YQ0@A.4$`*#A`Q"6Y_[__^L``%KC -M&@``"@E`H.'^___K"#P#XP,PEN=J/X/B`%"3Y?[__^L``%7C!0``"FPPEN4H -M`!/C`@``"@8`H.$$$*#A_O__ZV0PU.4?,@``%'C`@``"@$`H.$($*#A_O__ZQ`V`>/3@(;A`4"@XP!0H.,$`)C@ -M!1"IX/,`AN$``*#C\(>]Z'!`+>DXT$WB`$"@X0%0H.$D-P+C`S"0YP``4^,# -M```:_O__ZR0W`N,#`(3G$@``ZO[__^LD-P+C`R"4YP`@8N!O-P'C`P!2X0@` -M`(H!(*#C*#<"XP,@Q.<`(*#C)#<"XP,@A.(%$*#A'""@X_[__^L,,)WE"#"#XPPPC>40``#J"#P#XP,`E.<` -M4*#C`%"-Y2`PH.,$,(WEN!"$X@4@H.$`,.#C_O__ZPP`C>(%$*#A'""@X_[_ -M_^L,,)WE!#"#XPPPC>4!,*#CL#'-X0Q@C>(&`(;BN!"$X@8@H./^___K*%"- -MX@4`H.$`$*#C$""@X_[__^L<,*#CO#+-X0@\`^,#`)3G!AP(XP4@H.$&,*#A -M_O__ZSC0C>)P@+WH$$`MZ0%`H.$L`)'E``!0XP````K^___K0`"4Y0``4.,` -M```*_O__ZP$`H.,0@+WH<$`MZ0%`H.$`4*#C.%#!Y04`H.'0$*#C_O__ZRP` -MA.5`4(3E1%#$Y1!0A.444(3E*%"$Y210A.4<4(3E(%"$Y3Q0A.484(3E!0!0 -MX`$`H!-P@+WH`0!1XP8``!JV,$#B#@!3XP`!@.#Z#H"23@V`@@@`@((>_R_A -M#@!0X[0)``,>_R\!#0!0XP``H,,``8#0E@Z`T@<`@-(>_R_A'O\OX1!`+>D` -M``#C``!`XP`0`.,`$$#C_O__ZP``H.,0@+WH$$`MZ0%`H.$```#C``!`XQ`0 -MG^7^___K##"@XP`PA.4``*#C$("]Z/A=```00"WI````XP``0.,($)_E_O__ -MZP``H.,0@+WH%%X``!!`+>D```#C``!`XP@0G^7^___K``"@XQ"`O>@P7@`` -M$$`MZ0```.,``$#C"!"?Y?[__^L``*#C$("]Z%!>```00"WI````XP``0.,( -M$)_E_O__ZP``H.,0@+WH:%X``/!!+>D`4*#A`4"@X0!@4N($<(`27'"``@`` -M`.,``$#C^!"?Y08@H.$$,*#A_O__ZP``5.,$```:``"@XP``A^4!,*#C;#.% -MY?"!O>@"/`KC#S!`XP,`5.$<```*!@``B@$`5.,-```*`3P*XP\P0.,#`%3A -M'0``&@P``.H$/`KC#S!`XP,`5.$4```*!3P*XP\P0.,#`%3A%```&@<``.H` -M,*#C`#"'Y0$PH.,6``#J`3"@XP`PA^4`,*#C$@``Z@4PH.,`,(?E`#"@XPX` -M`.H",*#C`#"'Y00PH.,*``#J!#"@XP`PA^4&,*#C!@``Z@```.,``$#C!!"@ -MX?[__^OT#0_C_P]/X_"!O>@``%;C``"@`VPSA14``*`3\(&]Z(!>```00"WI -M````XP``0.,($)_E_O__ZP``H.,0@+WHF%X``!!`+>D```#C``!`XP@0G^7^ -M___K``"@XQ"`O>BT7@``$$`MZ0```.,``$#C"!"?Y?[__^L``*#C$("]Z,Q> -M```00"WI````XP``0.,($)_E_O__ZP``H.,0@+WHZ%X``!!`+>D```#C``!` -MXP@0G^7^___K``"@XQ"`O>@$7P``$$`MZ0```.,``$#C"!"?Y?[__^L``*#C -M$("]Z"!?```00"WI````XP``0.,($)_E_O__ZP``H.,0@+WH.%\``!!`+>D` -M``#C``!`XP@0G^7^___K``"@XQ"`O>A87P``$$`MZ0```.,``$#C"!"?Y?[_ -M_^L``*#C$("]Z'!?```00"WI````XP``0.,($)_E_O__ZP``H.,0@+WHB%\` -M`!!`+>D```#C``!`XP00G^7^___K$("]Z+!?```00"WI````XP``0.,($)_E -M_O__ZP``H.,0@+WHW%\``!!`+>D```#C``!`XP@0G^7^___K``"@XQ"`O>C\ -M7P``$$`MZ0$PH.,",,#E8A@!X[`0P.$#$*#C`Q#`Y0<0H.,$$,#E$3#`Y0,` -M4N,)```:`##@XP4PP.4`,*#C!C#`Y0$@H.,)(,#E:2#@XP\@P.40,,#E$("] -MZ`(`4N,``%(3"```&@`PX.,%,,#E!C#`Y0$PH.,),,#E+""@XP\@P.40,,#E -M$("]Z`@`G^4($)_E_O__ZQ"`O>CD-```'&```!!`+>D(T$WBJ"P#XP(@D.<` -M0)+E%!"@XP<@C>)HRP/C#^"@X0SPD.<```#C``!`XS00G^4'(-WE_O__ZY`` -ME.44`(#B`!"@XP<@W>7#___KE`"4Y10`@.(!$*#C!R#=Y;[__^L(T(WB$("] -MZ#A@```00"WI``!0XP(``!H<`)_E.1<`X_[__^L```#C``!`XPP0G^7^___K -M``"@XQ"`O>@,-0``4&```!!`+>D``%#C`@``&AP`G^4Y%P#C_O__ZP```.,` -M`$#C#!"?Y?[__^L``*#C$("]Z`PU``!H8```<$`MZ0%`H.$`4%#B`@``&EP` -MG^4Y%P#C_O__ZP```.,``$#C3!"?Y00@H.'^___K``!4XPP```H"7(7B!`"@ -MX?[__^L$`*#A_O__ZPPPE>4$`%/A!```&AP`G^7^___K`#"@XPPPA>40,,7E -M``"@XW"`O>@,-0``@&```#0U``#P1RWI`'"@X0%0H.$(/`/C`X"0YP```.,` -M`$#C;!&?Y0<@H.'^___K%@Z@X_[__^L`H*#A`$"@X0``4.,#```:3`&?Y?[_ -M_^L+4.#C30``Z@```.,``$#C*!"@X_[__^L``(KE``!0XP,``!HD`9_E_O__ -MZPM0X.,_``#JH%"`Y:@\`^,#H(?G:*&(Y0``FN4``%#C`@``&OP`G^4Y%P#C -M_O__ZP)<@.(`8*#C#&"%Y1!@Q>4`H(7E!'"%Y0A@A>6##X#B_O__ZR%@Q>4B -M8,7E(V#%Y1"`BN4&,*#C!#"*Y0`PFN4!(*#C*""#Y0D@H.,P(,/E"2R@X[(C -MP^$$$*#C@A##Y0`@X..P*,/A3B,`X[`BP^$`(`#C`"!`X[4/@N(0`(/EOR^" -MXC@@@^4T$(/E`"``XP`@0./X$(+BD!"#Y4DO@N*4((/E``":Y?[__^L`4%#B -M!```JD``G^7^___K``":Y?[__^L#``#J`#":Y:`PD^4P,HCE`@``Z@H`H.$6 -M'J#C_O__ZP4`H.'PA[WHH&```&0U``"(-0``##4``*@U```00"WI`2"@X0`` -M4.,"```:2`"?Y3D7`./^___K!$*0Y0```.,``$#C-!"?Y?[__^O;#83B,`"` -MXO[__^LH.@/C`S"4YRPJ`^,"()3G`@!3X2PJ`Q,",(07``"@XQ"`O>@,-0`` -MZ&````3@+>4,T$WB``!0XP(``!HL`)_E.1<`X_[__^L```#C``!`XQP0G^7^ -M___K#0"@X0@0H./^___K``"@XPS0C>(`@+WH##4``!!A```00"WI`2"@X0`` -M4.,"```:2`"?Y3D7`./^___K!$*0Y0```.,``$#C-!"?Y?[__^ML,)3E`0`3 -MXP8```H$`*#A_O__ZP0`H.'^___K!`"@X0$0H./^___K``"@XQ"`O>@,-0`` -M+&$``/!/+>E<``%/C`@``&E`*G^7W%P#C_O__ZP`PD^4``%/C`@`` -M&C@*G^4Y%P#C_O__ZR0RT^4``%/C#V#@$WP"`!H%`*#A'!J?Y?[__^L``%#C -M=`(`"FPPE>40`!/C<0(`&@@PE.4``%/C<`(`"@PPE.4``%/C;0(`"B``4^,& -M8."#:P(`BC1@C>(&`*#A`!"@XR0@H./^___K#""4Y30@C>4$`(;B"!"4Y?[_ -M_^L$`)3E``!0XPH```H`$-#E`2#0Y0(PT.4#P-#E`,"-Y03`T.4$P(WE!0#0 -MY0@`C>6("9_E_O__ZVP@E>4B#1+C!```"G@)G^5L&9_E_O__ZP]@X.-+`@#J -M_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B!""#Y81PA>*$,)7E>#"%Y0!@H.,X -MH(WB!H"@XP<`H.%X$)7E_O__ZP$`4.,`<*`#/0``"GA@E>4`,);E>#"%Y000 -ME.4``%'C!```"B``AN(((*#A_O__ZP``4./N__\*"!"4Y0``4>,)```*#""4 -MY0``4N,&```**#"6Y0,`4N'E__\:+`"&XO[__^L``%#CX?__"@00E.4``%'C -M#P``"B``AN(((*#A_O__ZP$`4./9__\:G`B?Y?[__^LH,);E6`"-XB0P(.4$ -M`(#B+!"&XB@@EN7^___K`7"@XQ(``.H(,)3E``!3X\O__PH,,)3E``!3X\C_ -M_PHL`(;B"A"@X30@G>7^___K`0!0X\+__QHH();E-#"=Y0,`4N&^__\:-`B? -MY?[__^L!<*#C#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__ZP$P)^(``%;C -M`3"#`P$`$^,#```*_`>?Y?[__^L/8.#CZ@$`Z@4`H.%X$);E_O__ZP``4./B -M`0`*`2"@XS0\`>,#((7G`#"@X\PH`>,",(7G)"D!XP(PA>?(*`'C`C"%YS`L -M`>,",(7G(&"4Y0```.,``$#CH!>?Y08@H.'^___K``!6XP`@H`,P/`$#`R"% -M!P,```H#`!;C!""@$S`\`1,#((47$&"4Y0```.,``$#C:!>?Y08@H.'^___K -M`0!6XQ````H%```Z!`!6XQ0``!H#(*#CR#@!XP,@A><3``#J`""@X\@X`>,# -M((7GVC^#X@,PE><#`%/C`B""@L@X`8,#((6'"0``Z@$@H./(.`'C`R"%YP`@ -MH./;/X/B`R"%YP(``.H`(*#CR#@!XP,@A>=CK87B"*"*XB@PE.4``%/C`&"@ -M`P4```H*`*#A+!"4Y0$@H.,8_?_K`&!0XIL!`+K(.`'C`S"5YP,`4^,!`%,3 -M+@``&EDPU.44,(WE6##4Y10@G>4$`%+CCP$`B@``4^.-`0`*!0!3XP6PH),- -ML*"##("+X@@`H.'^___K`)"@X0!PH.$``%#C"V#@`X,!``H`$*#C"""@X?[_ -M_^L(L(GE`(")Y0T`6^,%,*`#S"@!`P(PA0=8((("`C"%!Q0@G>4",8+C!#") -MY0P`B>)4$)3E"""9Y?[__^L%`*#A"1"@X?[__^L``%#C4D,(WE -M`P!6X0`PH!,!,*`##@U4XP,@H)$!((.#``!2XP8```H`$*#C&"H!XP(0Q>(L,(WB_O__ZP$`4.,- -M```:`B"@X\@X`>,#((7G`B""XMH_@^(#((7G)@R%XB0`@.()$*#A*""=Y0(@ -M@N+^___K0`2?Y?[__^L``%OC%P``"B00G>4``%'C%```V@L`H.$"$('B,""- -MXBPPC>+^___K`0!0XPT``!H"(*#CR#@!XP,@A><%((+BVC^#X@,@A>4!,$/B#P!3XP/QGY<`(*#C,3Z#X@,@A><3``#J`B"@XR0Y`>,#((7G -M`B""XC$^@^(#((7G#```Z@0@H.,D.0'C`R"%YP(@@N(Q/H/B`R"%YP4``.H% -M(*#C)#D!XP,@A><`(*#C,3Z#X@,@A><:``#J -M`2"@X\PX`>,#((7G`""@X]H_@^(#((7G$P``Z@(@H./,.`'C`R"%YP(@@N+: -M/X/B`R"%YPP``.H$(*#CS#@!XP,@A><"((+BVC^#X@,@A><%``#J!2"@X\PX -M`>,#((7G`""@X]H_@^(#((7G`&"@XQ@Z`>,#8,7G%#*?Y=@SD^4@,(WE6#"- -MXCQ@(^4'`*#A!!"@X08@H.'^___K`*"@X2$``.H(,(K@%#"-Y0`PT^7=`%/C -M%P``&@(`B.(``(K@(!"-X@0@H./^___K`0!0XQ```!H(@(K@`2#8Y0(@@N(" -M#%+C`BR@HQP\`>,#((7G&@R%XAD`@.(4$)WE_O__ZP``6>,``%L#`2"@`Q@Z -M`0,#(,4'"```Z@B`BN`!,-CE`C"#X@-@AN!V8/_F!H"@X1PPG>4#`%;AV?__ -M.@`@H.-8,(WB/"`CY0<`H.$$$*#A_O__ZP"`4.(`8*`#-```"K`WE>4``%/C -M!0``"L07E>4`8*#CQ&>%Y0,`H.'^___KL&>%Y1P`G>7^___KL`>%Y0``4.,% -M```:^`"?Y?@0G^4'*0#C_O__ZP!@H.,@``#J"!"@X1P@G>7^___K'#"=Y<0W -MA>4`8*#C&0``Z@``5N,4``"Z!0"@X3`\`>,#$)7G_O__ZP4`H.$T$(WB_O__ -MZP``4.,(```*H`"?Y<@X`>,#$)7G!#"#X@,@E>=8,(/B`S"5Y_[__^L"``#J -M`&#@XP```.H58.#C!@"@X5S0C>+PC[WH!P"@X000H.'^___KX?__Z@D`H.$( -M$*#A_O__ZUY@X./S___J##4``$1A```8-@``0#8``&`V``!T-@``B#8``%QA -M``!\80``X#8``)AA``#T-@``##<``!PW```H-P``W%T``#@W``"X80``6#<` -M`'!`+>D"4*#A`V"@X0``4.,"```:X`"?Y3D7`./^___K!$*0Y0``4N,O```* -M;#"4Y0@`$^,8```*`0`3XQ8```H"`*#AX!"$X@8@H./^___K``!0XR0```H` -M,);E0""#XP`@AN6<)@'C`B#4YP$@@N*B(*#A7R!"XAD@QN7`,(/C`#"&Y00` -MH.'<$(3B_O__ZP`Q@."#,*#AOC'&X6PPE.4@`!/C`P``&D``$^,!```:$``3 -MXPX```H!`!/C#```"EL-A.(X`(#B!1"@X?[__^L``%#C!@``&B``G^4@$)_E -M_O__ZP$`X.-P@+WH`0#@XW"`O>@``*#C<("]Z`PU``"H-P``T&$``/!'+>D0 -MT$WB`D"@X0"4D>4```#C``!`X\01G^7^___K;#"9Y1$`$^,$```:M`&?Y:P1 -MG^7^___K%0#@XV8``.H``%3C!P``&@```.,``$#C_O__ZPD`H.'^___K"0"@ -MX?[__^M<``#J!%"@X01@H.$$<*#A!("@X02@H.$`$-3E`2#UY0(P]N4#`/?E -M``"-Y00`^.4$`(WE!0#ZY0@`C>4```#C``!`X_[__^L`,-3E_P!3XP\``!H` -M,-7E_P!3XPP``!H`,-;E_P!3XPD``!H`,-?E_P!3XP8``!H`,-CE_P!3XP,` -M`!H`,-KE_P!3XQ4`X`,X```*_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B!""# -MY09[B>(@<(?B(#@!XP-0F><&@*#C&@``ZFL>1>((8$'B`%"5Y00`H.'8$('B -M"""@X?[__^L``%#C$0``"EPWEN4!`%/C`@``&G0WUN4``%/C"P``"FL^AN(( -M,(/BO":6Y;@6EN4$(('E`!""Y;@VAN6\-H;E"0"@X080H.'^___K!```Z@<` -MH.$%$*#A_O__ZP``4./?__\*#2"@X7\]PN,_,,/C!""3Y0$@0N($((/E_O__ -MZP```.,``$#C#!"?Y?[__^L``*#C$-"-XO"'O>CL80``R#<``/!%+>D4T$WB -M`<"@X0)`H.$`,*#C##"-Y0@PC>4``%#C`@``&C0"G^4Y%P#C_O__ZP12D.40 -M,)+E%""2Y0`@C>4```#C``!`XQ02G^4,(*#A_O__ZVPPE>40`!/C>P``"A`P -ME.47`%/C>```VA0`E.4``(/@_O__ZP!@4.(+4.`#(8($+B_O__ZQ``E.48`$#B``"&X`00E.44()3E_O__ZQ"`E.44,)3E -M`X"(X!B@2.(,<(;B)(!(X@<`H.$($*#A`""@XPPPC>+^___K``!0XP(```IX -M`9_E#!"=Y?[__^L'`*#A"!"@X0`@H.,(,(WB_O__ZP``4.,"```*5`&?Y0@0 -MG>7^___K!0"@X080H.$(()WE"B!BX/[__^L!`%#C%5#@$SX``!H'`*#A"!"@ -MX0`@H.,(,(WB_O__ZP``4.,`4*`#-@``"BPZ`^,#,)7G``!3XQ,``!K\`)_E -M_O__ZP4`H.$#$*#C_O__ZZ@\`^,#,)7G``!3XP(``!K(`)_E]Q<`X_[__^L` -M,)/E``!3XP$@H!,A(L,5'0``&J@`G^4Y%P#C_O__Z]T-A>(D`(#B_O__Z]X- -MA>(8`(#B_O__Z]\-A>(,`(#B_O__ZXP`G^4($)WE_O__ZR0Z`^,#,)7G`P!3 -MXP,@H!,D.@,3`R"%%RPZ`^,#,)7G"@!3XPH@H!,L.@,3`R"%%P\@H.-2.@/C -M`R#%Y]XGU>5!.@/C`R#%YP!0H.,4$)3E$#"4Y08`H.$#$('@_O__ZP```.H5 -M4.#C!0"@X130C>+PA;WH##4```AB``"(.```H#@``+0X``#<.```\$$MZ0%0 -MH.$"8*#A`$!0X@(``!H\`)_E.1<`X_[__^L$@`$*#C%""@X_[__^L!H,?E`(#'Y0$PH.,#,,?E`8!(XGB`[^8$`%CC$""@ -M@P`P`),`,$"3"("#D%PDV)4$`(?B"1"@X?[__^L4,*#CL##&X01PAN4(,(;E -M`#"@XPPPAN40,(;E%`"&XO[__^L%"XOB*`"`X@80H.'^___K^(^]Z!!`+>D% -M($+B(!@*#A`G"@X0-0H.$XD)WE/$"=Y0``4.,"```:H`V?Y3D7`./^___K`"*P -MY00@C>4$L)#E````XP``0..$'9_E"""@X0DPH.'^___K````XP``0.,0$)3E -M_O__ZP```.,``$#C"!"4Y?[__^L```#C``!`XPP0E.7^___K````XP``0.,' -M$*#A_O__ZP```.,``$#C!1"@X?[__^L(8)3E0&"&X@8`H.'^___K`%"@X0"@ -MH.$``%#C`$#@`R8#``H`$*#C!B"@X?[__^L#,*#C!2"@X00P@N0(((WE`@"@ -MX?\0H.,&(*#C_O__ZQ`@E.4"/`KC#S!`XP,`4N$8```*!@``B@$`4N,2```* -M`3P*XP\P0.,#`%+A"```&@H``.H$/`KC#S!`XP,`4N$/```*!3P*XP\P0.,# -M`%+A`@``"O1-#^/_3T_C`P,`Z@`0`.,`$$#C!P``Z@`0`.,`$$#C!```Z@`0 -M`.,`$$#C`0``Z@`0`.,`$$#C##"*X@PPC>4#`*#A$""@X_[__^L``%GC#@`` -M"@$@V>4",-GE`R`"X``PV>4#(`+@`S#9Y0,@`N`$,-GE`R`"X`4PV>4#,`+@ -M_P!3XP$PH!,<,,H5`0``&@`PH.,<,,KE)'#*Y0P@E.4``%+C!```"@00E.4` -M`%'C`0``"B4`BN+^___K"#"4Y0``4^,'```*`""4Y0``4N,$```*OC+*X3`` -MBN(`$)3E"""4Y?[__^ML$)OE"``1X_````H`1)CE````XP``0..$&Y_E_O__ -MZP`PH.,@,(KE&S#*Y;XRVN$P,(/B`P!6X=P``#H$,)KE`0!SX]D``!JX(-KA -M_S\/XP,`4N'5```:)##:Y0,`4^/2``"*8WV$X@APA^(,`)WE`!``XP`00./^ -M___K``!0XT@``!H`(*#C-#P!XP,@A.4`L(GE -M#0!2XP4PH`/,*`$#`C"$!U@@@@(",(0'`C&(XP0PB>4,,(GB!#"-Y0,`H.$P -M$(KB"""9Y?[__^L<,-KE``!3XP4```H$`*#A"1"@X?[__^L``%#C>P(`"G@" -M`.H#`%CC>`(`BF,/B.(``H3@%`"`X@00G>4(()GE_O__ZQD]B.(#,83@"""9 -MY10@@^4$`*#A!Q"@X0@@H.$`,*#C_O__ZP!`H.-H`@#JR#@!XP,PE.<"`%/C -M?P``&FP@E.4(,`#C`3!`XP,P`N```%/C>0``"EL-A.(X`(#BX!"$XO[__^L` -M@%#B`P``&K@)G^6P&9_E_O__ZUD``.H,`)WEJ!F?Y?[__^L``%#C`#"@$^@P -MB!4T/`'C`S"4YP8`4^,$`%,3S#@!`P,PE`?L,(@%'##:Y0$`4^,>```:<`F? -MY6`9G^7^___K,'"*XKXBVN$1#HCB!Q"@X1``4N,0(*`C_O__ZPP`G>5(&9_E -M_O__ZP``4.,*```:\`"(XA`0A^(((*#C_O__ZP$,B.(8$(?B"""@X_[__^L` -M(*#C(3P!XP,@Q.<$`*#A"!"@X0$@H./^___K*@``ZB0`VN4&`(#B``*$X&,- -M@.(P@(KBOB+:X0P`@.(($*#A$`!2XQ`@H"/^___K)`#:Y0H`@.(``H3@8PV` -MX@P`@.(0$(CB"""@X_[__^LD`-KE#@"`X@`"A.!C#8#B#`"`XA@0B.(((*#C -M_O__ZP$PH.,@+`'C`C#$YR00VN6^+T+B`A"$YP0`H.$'$*#A)"#:Y?[__^LL -M.@/C`S"4YPT`4^,.(*`#+#H#`P,@A`<$`*#A_O__ZP!P4.(1```*#`"=Y3`8 -MG^7^___K``!0XP`PH!/H,(<5-#P!XP,PE.<&`%/C!`!3$P8``!K,.`'C`S"4 -MY^PPA^4`0*#C`@``ZA5`X.,```#J`$"@X_0'G^7<%Y_E!""@X?[__^O5`0#J -M$``1X\X!``H``%GC`P``"@@`G>4)$*#A!B"@X_[__^L`=)CE`#"@XR`PBN4; -M,,KEOC+:X4`P@^(#`%;AX`$`&@0PFN4!`'/C!P``&K@@VN'_/P_C`P!2X0,` -M`!HD,-KE`P!3X]8!`(H&``#J6PV'XC@`@.($$(KB_O__ZP"`4.+%`0`:S`$` -MZ@P`G>5(%Y_E_O__ZP``4./'`0`*#`"=Y407G^7^___K`0!PX@``H#,``%#C -M4P``"B20VN6^LMKA`3![X@`PH#,#`%GC`3"#@P``4^.Z`0`:``!;XP!`H`,$ -M@*`!#0``"@4`6^,%L*"3#;"@@PR`B^((`*#A_O__ZP!`4.*L`0`*!`"@X0`0 -MH.,((*#A_O__ZPBPA.4`@(3E!)"$Y0RPA.(+`*#A,!"*X@@@E.7^___K'##: -MY0``4^,@```*`""@XS0\`>,#((?G`3"@X\PH`>,",(?G6"""X@(PA^<(,)3E -M#0!3XP4PH`-8($("`C"'!U@@@@(",(<'T#@!XP.0A^=C#XGB``*'X!0`@.(+ -M$*#A"""4Y?[__^L9/8GB`S&'X`@@E.44((/E!P"@X0P0A.(((-3E"3"@X0/^ -M_^M7`0#J8P^)X@`"A^`4`(#B"Q"@X0@@E.7^___K&3V)X@,QA^`(()3E%""# -MY0<`H.$,$(3B""#4Y0DPH.'S_?_K1P$`Z@"`H.,!,*#C``!3XW````IL,)?E -M$``3XVT```H<,-KE``!3XV(!`!H``%#C$@``"B0`VN4&`(#B``*'X&,-@.*^ -M(MKA#`"`XC`0BN(0`%+C$""@(_[__^L!(*#C)#D!XP,@A^>^,MKA#0!3XP0@ -M@@(D.0$#`R"'!SP``.H,`)WE5!6?Y?[__^L``%#C(0``&@(@H.,D.0'C`R"' -MYR0`VN4&`(#B``*'X&,-@.(P0(KBOB+:X0P`@.($$*#A$`!2XQ`@H"/^___K -M)`#:Y0H`@.(``H?@8PV`X@P`@.(0$(3B"""@X_[__^LD`-KE#@"`X@`"A^!C -M#8#B#`"`XA@0A.(((*#C_O__ZP$@H.,A/`'C`R#'YQ4``.H,`)WEQ!2?Y?[_ -M_^L``%#C#0``&@0@H.,D.0'C`R"'YR0`VN4&`(#B``*'X&,-@.*^(MKA#`"` -MXC`0BN(0`%+C$""@(_[__^L"``#J`""@XR0Y`>,#((?G)"#:Y2@Y`>,#((?G -M`2"@X[X_@^(#(,?GOS]#X@,@E^=8,$/B`R"'YP<`H.$P$(KB,#()?G`@!2XP`PH!,!,*`#``!8XP`PH`,``%/C[@``"FPPE^40`!/CZP`` -M"APPVN4!`%/C6```&C!`BN*^(MKA$0Z(X@00H.$0`%+C$""@(_[__^L,`)WE -MK!.?Y?[__^L``%#C!@``&@$PH./L,(CEOC+:X0T`4^,%,*`#[#"(!1D``.H, -M`)WE=!.?Y?[__^L``%#C#0``&@(PH./L,(CE\`"(XA`0A.(((*#C_O__ZP$, -MB.(8$(3B"""@X_[__^L!(*#C(3P!XP,@Q^<&``#J#`"=Y303G^7^___K``!0 -MXP0PH`,`,*`3[#"(Y1P`H./^___K`*"@X0``4.,A```*&`"@X_[__^L`D*#A -M`+"@X0``4.,#```:"@"@X1P0H./^___K%P``ZA0`BN+^___K%2"@X[`@RN$$ -MD(KE&#"@XP@PBN4`,*#C##"*Y1`PBN7L,)CE!C#)Y0D`H.'@$(CB!B"@X_[_ -M_^L(`(GB$1Z(XA`@H./^___K!0N'XB@`@.(*$*#A_O__ZP!`H./H0(CE`3"@ -MXW0WR.5V``#J``!0XQ(```HD`-KE!@"`X@`"A^!C#8#BOB+:X0P`@.(P$(KB -M$`!2XQ`@H"/^___K`2"@XR0Y`>,#((?GOC+:X0T`4^,$(((")#D!`P,@AP<\ -M``#J#`"=Y0@2G^7^___K``!0XR$``!H"(*#C)#D!XP,@A^,#()?GS#@!XP,@A^<'`*#A,!"*XG(@[^8D,-KE??S_ZP<`H.'^___K -M``!0XRH```H`0*#CZ$"`Y20Y`>,#,)?G[#"`Y0L``.H``%3C"0``"@0`H.$( -M$*#A_O__ZP!`H.,$``#JJ`"?Y00PG>4$()/E_O__ZP!`H.,%`*#A!A"@X?[_ -M_^L$`*#A%-"-XO"/O>@`0*#C````ZEY`X.-D`)_E3!"?Y00@H.'^___K"0"@ -MX0L0H.'^___K[O__Z@P`G>4`$`#C`!!`X_[__^L!`'#B``"@,P`PH..4_O_J -M`$"@X^3__^H50.#CXO__Z@PU``!,8@``9&(``(PY``!T.0``K#D``'PY``#0 -M.0``<#D``(0Y``#<.0``\$$MZ0C03>("4*#A``!0XP(``!J@`9_E.1<`X_[_ -M_^L"#(#B!$"0Y0!@D.4!`*#A_O__ZP``4.-<```:!`"@X7@1G^7^___K``!0 -MXU<```H$@);E:`&?Y6`1G^4((*#A!3"@X?[__^L%,%C@`3"@$P(`5>,&```* -M`P!5XRP```H!`%7C7@#@$P!PH`-(```:.0``Z@``4^,T```*)#H#XP,PE.<# -M`%/C,```&MT-A.(D`(#B_O__Z]X-A.(8`(#B_O__Z]\-A.(,`(#B_O__ZR0Z -M`^,#,)3G`0!3XP$@H!,D.@,3`R"$%R@Z`^,#,)3G+"H#XP(@E.<"`%/A+"H# -M$P(PA!6P`)_EI!"?Y20Z`^,#()3G"#"#X@,PE.?^___K -M`7"@XQ$``.H``%/C#@``"BPZ`^,#,)3G``!3XPH```HD.@/C`S"4YP,`4^,& -M```*`R"@XR0Z`^,#((3G!'"@XP(``.H!<*#C````Z@1PH.,$4(;E!`"@X0<0 -MH.'^___K``!0XP2`A@4``.`#!0``"@0`H.$'$*#A_O__ZP``H.,```#J``#@ -MXPC0C>+P@;WH##4``(!B````.@``)#H``/!`+>D,T$WB`5"@X0)`H.$``%#C -M`@``&L@!G^4Y%P#C_O__ZP1BD.4`((WE````XP``0..P$9_E!B"@X04PH.'^ -M___K"0!4XU<``(H!,*#C$T2@X;XS`.,`,$#C`S`$X```4^,`0*`34P``&D`` -M%.--```*J#P#XP,PEN<``%/C`@``&EP!G^7W%P#C_O__ZP!PD^4``%?C`@`` -M&D0!G^4Y%P#C_O__ZP)\A^(```#C``!`XS01G^7^___K``!5XP!`H`,58.`# -M+P``"@4`H.'^___K`""@X04`H.$0$(?B_O__ZP``4.,(```:#$"7Y0``5.,% -M```*]`"?Y>P0G^4%(*#A_O__ZP!@H.,>``#J"`"@XP$0H.,!(*#A_O__ZP!` -M4.(+8.`#%P``"B,C`.,!/*#CLR"$X00`H.$%$*#A$""@X_[__^L`,*#C#S#$ -MY:`PG^7@,(3E!#"@X0!DH^4X+0/C!""#Y00`H.'^___K`&!0XA<``!H,0(?E -M$`"'X@40H.$1(*#C_O__ZPPPE^4`8(WE````XP``0.-,$)_E!""@X?[__^L# -M``#J````XP``0./^___K`$"@XP```.,``$#C!!"@X?[__^L$`*#A#-"-XO"` -MO>@$`*#A_O__ZP!`H./H___J##4``)QB``"\8@``?#H``-AB``#P3RWI%-!- -MX@!`H.$!(*#A`(21Y0```.,``$#CW!&?Y?[__^M0()3E!P!2XVX``)JH$)3E -M`##1Y0``4^-J```:`A"!X@$`T>4`,-'E`#2#X0,0H.$#`%+A8P``.@X`4^," -M```*F`&?Y?[__^M>``#J!`"@X?[__^NH8)3E!E"@X0`PUN4!$-;E`12#X0PP -M`>((`%/C)0``&H``$>,`L*`#`K"@$P,<`>(##%'C&)"@$QZ0H`,-<*#A!F"@ -MXPT`H.$$$(7B!B"@X?[__^L(H(WB"@"@X0H0A>(&(*#A_O__ZPL0B>`$`*#A -M!A!!XO[__^NH4)3E!0"@X0T0H.$&(*#A_O__ZP8`A>`*$*#A!B"@X?[__^OL -M`)_E_O__ZP0`H.$(/`/C`Q"8Y_[__^LQ``#J_!`!XM``4>,I```:4*"4Y0@` -MH.$&$*#A"B"@X0$PH./^___K``!0XR,``+I3#8CB(`"`XO[__^L`<%#B'@`` -M"@@`H.$($(?B_O__ZP`0H.-;$,?E;`"7Y6@@H./^___K;%"7Y2A0A>(%`*#A -M!A"@X0H@H.'^___K%*"'Y;8AU>$B(J#AW#<`X[,@B.&^(,?ALR"8X0$@@N*S -M((CA%#"7Y1@PA^4(`*#A!Q"@X?[__^L!``#J(`"?Y?[__^L$`*#A_O__ZP`` -MH.,4T(WB\(^]Z%AC``#P.@``%#L``"P[``#P02WI*-!-X@!PH.$!4*#A`D"@ -MX0-@H.$`(*#C)""-Y2`@C>4$@*#A`0"@X000H.$D,(WB_O__ZP``4.,"```* -M)#"=Y0``4^,)```:!0"@X0@0H.$`(*#C(#"-XO[__^L``%#C&`$`"B`PG>4` -M`%/C%0$`"@``5^,3`0`*`@!6XV0```H$`%;CZP``"@$`5N,-`0`:`#"@XQ0P -MC>4<,(WE"#"-Y0PPC>50,*#C"3#-Y0TPX.,*,,WE!#"@XPLPS>4`9)?E```` -MXP``0.,$%)_E!R"@X00PH.'^___K``!4XP``H-/Y``#:!D"@X04`H.$($*#A -M`""@XQ0PC>+^___K`'!0XAT```J`-Y;E``!3XP4```J0%Y;E`&"@XY!GA.4# -M`*#A_O__ZX!GA.44`)WE_O__ZX`'A.4``%#C!0``&I0#G^6,$Y_EZR\`X_[_ -M_^L5`.#CW0``Z@<0H.$4()WE_O__ZQ0PG>60-X3E!`"@X=T0H.,(((WB`3"@ -MX_[__^L4$)WE`0"%X`@08>``(*#C'#"-XO[__^L`4%#B&```"J`WE.4``%/C -M!0``"K07E.4`8*#CM&>$Y0,`H.'^___KH&>$Y1P`G>7^___KH`>$Y0``4.,% -M```:_`*?Y?02G^4+(`'C_O__ZQ4`X..W``#J!1"@X1P@G>7^___K'#"=Y;0W -MA.4!(*#C(#0!XP,@Q.<``*#CK0``Z@`PH.,<,(WE&#"-Y0`TE^4``%3C@``` -MV@-`H.$%`*#A"!"@X0`@H.,<,(WB_O__ZP!@4.(G```*`#"@XQ0PC>6(-Y3E -M``!3XP4```J8%Y3E`'"@XYAWA.4#`*#A_O__ZXAWA.4<`)WE_O__ZX@'A.4` -M`%#C!0``&D0"G^5$$I_E02`!X_[__^L5`.#CB0``ZA0PC>(`,(WE!@"@X1P0 -MG>4((`'C`#"@X_[__^L``%#CL##0$8,XX!&C..`1L##`$8@'E.4&$*#A'""= -MY?[__^L<,)WEF#>$Y1P0G>4!`(7@"!!AX``@H.,8,(WB_O__ZP!04.)(```* -M`#"@XQ`PC>6T,4%`*#A&!"=Y0(@H.,4,(WB_O__ZP``4.,) -M```*M!'=X2$4H.$!`!'C!0``"HP!G^7^___KK#>4Y0``4^,;```:(```ZJ@W -ME.4``%/C!0``"KP7E.4`8*#CO&>$Y0,`H.'^___KJ&>$Y1@`G>7^___KJ`>$ -MY0``4.,%```:-`&?Y301G^6!(`'C_O__ZQ4`X.-%``#J!1"@X1@@G>7^___K -M&#"=Y;PWA.4``*#C/@``ZL`7E.4`8*#CP&>$Y:P'E.7^___KK&>$Y1@`G>7^ -M___KK`>$Y0``4.,%```:U`"?Y=00G^64(`'C_O__ZQ4`X.,M``#J!1"@X1@@ -MG>7^___K&#"=Y<`WA.4``*#C)@``Z@``H.,D``#J`&27Y0```.,``$#CF!"? -MY00@H.'^___K``!4XP``H-,;``#:!D"@X8PWEN4``%/C!0``"IP7EN4`8*#C -MG&>$Y0,`H.'^___KC&>$Y0@`H.'^___KC`>$Y0``4.,%```:.`"?Y4`0G^6Y -M(`'C_O__ZQ4`X.,&``#J!1"@X0@@H.'^___KG(>$Y0``H.,```#J``"@XRC0 -MC>+P@;WH?&,``#@W``"@8P``6#L``,AC``#P3RWIG=]-X@!`H.$!H*#A`I"@ -MX0!0H.,"'(WBOE;!X6A2C>5:CXWB_V"@XP@`H.$%$*#A!B"@X?[__^MH`(WB -M!1"@X08@H.'^___K9%"-Y6!0C>5<4(WE'`"-X@40H.%`(*#C_O__ZZH]#^/_ -M/T_C)RZ-XK-0@N$44(WE!#"@XQ,PS>4),*#C$C#-Y0$PH.,1,,WE4#\&XYHY -M0.,,,(WE!S"@XPLPS>53;83B(&"&X@Y[A.(RL(?B!%"*X@L`H.$%$*#A!B"@ -MX_[__^LL`(?B!1"@X08@H./^___K#CN@XX#`H..SP(3A(%"*XB!P2>(%`*#A -M!Q"@X0@@H.%@,(WB_O__ZYH_C>(`,(WE"`"@X6`0G>42(`'CFS^-X@(P@^+^ -M___K`AR-XKXVT>&S/[_F$%`%/C`_&?EQ0``.KT.@4`!#L%`#`[ -M!0`P.P4`%#L%`"0[!0`..Z#C!""@X[,@A.$*``#J#CN@XPC`H..SP(3A!@`` -MZ@X[H..`$*#CLQ"$X0(``.H..Z#C`2R@X[,@A.$%`*#A!Q"@X6@@C>)D,(WB -M_O__ZP``4.,/```*:%"-XAQPC>)<,(WB`#"-Y04`H.%D$)WE#2"@XP4%`*#A9!"=Y0(@H.,",$?B_O__ZUH/C>(`$*#C_R"@X_[_ -M_^MH`(WB`!"@X_\@H./^___K`#"@XV0PC>4&`*#A_O__ZP!@4.*2```*!`"@ -MX0@0AN+^___K;`"6Y0`0H.-H(*#C_O__ZVR`EN4(4*#A`)"@XRB0Y>4!D,7E -M+`"(X@L0H.$&(*#C_O__ZS(`B.(-&X3B$1"!X@8@H./^___K.`"(X@L0H.$& -M(*#C_O__ZP@@H.&^$_+AW#<`X[,`E.$/$`'B`!*!X;`0PN&S()3A`2""XK,@ -MA.&P,-7A_###X]`P@^.P,,7A!G"@X1@PH.,4,*?E%*"-XD``B.(!$*#C`2!* -MX@($$*#C!2"@X0(',*#A_O__ZP$0H.,#($KB!S"@X?[__^L`H*#A4#"@XV@PS>5O -M,*#C:3#-Y64PX.-J,,WE"3"@XVLPS>4"(*#C;"#-Y6Z0S>5M(,WE:%"-XAR` -MC>('`(7B`A!(XO[__^L-,*#C<3#-Y5P@G>52-.?G4,`(7B"!"@ -MX?[__^MD,(WB`#"-Y0H`H.'=$*#C7""=Y0P@@N(%,*#A_O__ZQ0@EN5D,)WE -M`S""X!0PAN4G/HWB`"`%X_(D0.,((2/E!""@XQ`:!..R$(/A`B""XF`@C>4! -MS*#CLL"#X6`@G>4GSHWB`A",X!#`H.,&P4'E`R""XF`@C>6!'J#CLA"#X6`@ -MG>4"((+B8""-Y0+,H..RP(/A8""=Y0(@@N)@((WE#AN@X[$0E.&Q'[_FLA"# -MX6`@G>4"((+B8""-Y0!PC>7=$*#C_O__ZQ0PEN48,(;E!`"@X080H.'^___K -MG=^-XO"/O>AP0"WI"-!-X@!`H.$!4*#A`F"@X0`PH./^___KW@?4Y0X`4.,` -M$*#3`1"@PP7R_^L`$*#A"#P#XP,`E.<@,*#C`#"-Y04@H.$&,*#A_O__ZPC0 -MC>)P@+WH<$`MZ0C03>(`0*#A`5"@X0)@H.$`,*#C_O__Z]X'U.4.`%#C`!"@ -MTP$0H,/O\?_K`!"@X0@\`^,#`)3G(#"@XP`PC>4%(*#A!C"@X?[__^L(T(WB -M<("]Z'!`+>F0T$WB`%"@X0%@H.&V(,WA#$"-X@0`H.$`$*#C@""@X_[__^L` -M``#C``!`X[P0G^4%(*#A_O__ZP`PH.,`,,3E`3#$Y00`A.(-&X7B$1"!X@8@ -MH./^___K"@"$X@80H.$&(*#C_O__Z\(.A>(,`(#B_O__ZP`0H.$0`(3B!B"@ -MX_[__^L$,*#AM@'SX=PG`..R$)7A#P``X@$"@.&P`,/A`1"!XK(0A>&P,-3A -M_###X\`P@^,$`*#AN#'`X!@PH..,,(WE`A"@XP8@C>*,,(WB_O__ZP@\`^,# -M`)7G!!"@X8P@G>7^___KD-"-XG"`O>CP8P``\$$MZ0!0H.$!8*#A`G"@X:@\ -M`^,#0)#G````XP``0.-($)_E!2"@X?[__^L"$*#C!!"$Y0```.,``$#C_O__ -MZP@\`^,#`)7G!A"@X0<@H.'^___K````XP``0.,$$)3E_O__ZP,PH.,$,(3E -M\(&]Z!1D``#P1RWI,=Y-X@"`H.$!0*#A"#"-XI0AG^4#`)+H!`"#Y+`0P^&H -M/`/C`S"8YP!PD^6T!M3A#@!0XP`0H),!$*"#>?'_ZP`0H.$'`*#A_O__ZP"0 -MH.$`,`#C`#!`XP``D^7^___KE%"$X@4`H.'^___K!0"@X?[__^N,H-3E`:"* -MXJJ@H.%?H$KB9#"@XY,*"N`Q;HWB`#"@XP`S9N4!,,;E!C"@X;8A\^$/(`+B -ML"##X28PU.4!`%/C"0``&@0`AN(($(WB!B"@X_[__^L0,(WBL"#3X?P@PN.` -M((+CL"##X0D``.H$`(;B#1N(XA$0@>(&(*#C_O__ZQ`PC>*P(-/A_"#"XU`@ -M@N.P(,/A(%"$X@H`AN(%$*#A!B"@X_[__^L0`(;B!1"@X08@H./^___K*`"- -MXI00A.*0()3E_O__ZY`0E.484('BH`"$X@P00>(`(*#C`C"@X?[__^L``%#C -M`@``"D@`G^5($)_E_O__ZP"@C>4@,*#C!#"-Y0<`H.$)$*#A$""-X@4PH.'^ -M___K``!0XP``H!,"```:&`"?Y?[__^L5`.#C,=Z-XO"'O>@T9```^#L``#QD -M```(/```\$$MZ0"`H.&H/`/C`S"0YP``4^,"```:Q`"?Y?<7`./^___K`#"3 -MY0``4^,"```:K`"?Y3D7`./^___K_O__ZPT@H.%_/<+C/S##XP0@D^4!((+B -M!""#Y81PB.*$0)CE?FZ(X@1@AN('`*#A!!"@X?[__^L!`%#C#@``"@10H.$& -M`*#A9!"4Y?[__^L!`%#C!@``&B@`A.+^___K`0!0XP(``!H(`*#A!!"@X6/_ -M_^L`0)3EZ___Z@T@H.%_/<+C/S##XP0@D^4!($+B!""#Y?[__^L(`*#A`!"@ -MX_[__^OP@;WH##4``/!/+>E7WTWB`8"@X0)@H.$``%#C`@``&A@$G^4Y%P#C -M_O__ZP2BD.6H/`/C`S":YP``4^,"```:^`.?Y?<7`./^___K`$"3Y0``5.," -M```:X`.?Y3D7`./^___K`%"2Y2!PDN7^___K#2"@X7\]PN,_,,/C!""3Y0$@ -M@N($((/E"&*$Y00@D^4!($+B!""#Y?[__^L*`*#AG!.?Y?[__^L``%#CW@`` -M"@4`H.$``%7C/0``"@`0`.,`$$#C!R"@X_[__^L``%#C-P``"@P`EN40$);E -M`""@XP(PH.'^___K``!0XS````HL.@/C`S":YP``4^,1```:"@"@X0$0H./^ -M___KJ#P#XP,PFN<``%/C`@``&AP#G^7W%P#C_O__ZP`PD^4``%/C`2"@$R$B -MPQ4'```:_`*?Y3D7`./^___K*"H#XP(@FN<"`%/A*"H#$P(PBA7^___K$#"=Y90WB.40`)WE!W!@X```A.`' -M$*#A`""@XPPPC>+^___K`$!0XA<```JD-YCE``!3XP4```JX%YCE`+"@X[BW -MB.4#`*#A_O__ZZ2WB.4'`*#A_O__ZZ0'B.4``%#C!```&H`!G^6`$9_EF28` -MX_[__^L$``#J!!"@X0P@G>7^___K##"=Y;@WB.48-=KE`0!3XP,``!I4`9_E -M1!&?Y?[__^M)``#J;"":Y2(-$N,#```*/`&?Y2@1G^7^___K0@``ZBPZ`^,# -M,)KG``!3XPT```H!`%/C"P``"@4`4^,%(*`3+#H#$P,@BA<*`*#A`1"@X_[_ -M_^L``%GC`""@`P(@H!-].@/C`R#*YQ0`C>(`$*#C42^@X_[__^L$,);E``!3 -MXQ4``-H`<*#C!T"@X12`C>*$`83@``&(X`0`@.(%$*#A("#5Y?[__^L@,-7E -M!S"(YP%`A.(A4(7B)'"'X@0@EN4$`%+A`#"@TP$PH,,(`%3C`#"@PP``4^/L -M__\:_O__ZPTPH.%_3,``*`3``#@`P(``.H*`*#A_O__ -MZP``H.-7WXWB\(^]Z`PU``!49```.#<``&AD```P/```3#P``'!`+>D`0*#A -M`5"@X?[__^L-(*#A?SW"XS\PP^,$()/E`2""X@0@@^4(`)3E``!0XPL```H` -M,)3E%""0Y0`PD^4#`%+A`@``"C0`G^7^___K`0``Z@40H.'^___K`#"@XP@P -MA.4-(*#A?SW"XS\PP^,$()/E`2!"X@0@@^7^___K<("]Z&`\``!P0"WI`$"@ -MX0```.,``$#CC!"?Y00@H.'^___K``!4XW"`O0@`4)3E``!5XP(``!IP`)_E -M.1<`X_[__^L"7(7B````XP``0.-4$)_E_O__ZP4`H.$!$*#C_O__ZPPPE>4` -M`%/C!@``"CP`G^4P$)_E_O__ZPP`E>7^___K#`"5Y?[__^L``)3E_O__ZP`` -ME.7^___K!`"@X18>H./^___K<("]Z(QD```,-0``K#P``/!!+>D`0*#A`2"@ -MXPXT`>,#(,#G`%"@XP!@`.,`8$#C@'"?Y12`H.,*``#J!@"@X0<0H.'^___K -M"`"@X?[__^L!4(7B"P!5XP(``!I8`)_E_O__ZP(``.IL,)3E`@L3X_'__QJH -M/`/C`S"4YP``4^,"```:-`"?Y?<7`./^___K``"3Y0``4.,"```:'`"?Y3D7 -M`./^___K`@R`X@$0H./^___K\(&]Z)QD``#T/```##4``/!/+>D4T$WB`9"@ -MX0)0H.%$<(WB@`F7Z#Q@W>4``%#C`@``&NP!G^4Y%P#C_O__ZP1"D.4`<(OE -M`#"@XP0PB^6T`-+A_O__ZP``C>4X,)WE!#"-Y0```.,``$#CN!&?Y0D@H.$( -M,*#A_O__ZP```.,``$#C!A"@X?[__^L`,-?E`2#7Y0(D@^'0`%+C#0``"E`` -M4N,%```:@`&?Y7@1G^7^___K`4"@XP"@H.-*``#J;`&?Y6`1G^7^___K`4"@ -MXP"@H.-$``#J!`"@X9[__^NT`-7A_O__Z]XWU.4#`%#A!P``"K0`U>'^___K -M70$*#C#!"-Y0D`H.'^___K!`"@X080H.'^ -M___K#0``Z@!`H.,$H*#A````XP``0.,P$)_E!""@X?[__^O0(,OA@`&-Z`A` -MC>70$*#C#!"-Y0D`H.'^___K"@"@X130C>+PC[WH##4``+1D``!D4T$WB`7"@X0)@H.$#H*#A.)"=Y3RPG>4``%#C`@``&L`!G^4Y%P#C -M_O__ZP1"D.6T`-+A_O__ZW"`[^:H49_E`)"-Y0```.,``$#C!1"@X0<@H.$( -M,*#A_O__ZP0`H.$%$*#A_O__ZP``4.,-`.`#6@``"E@W`^,#<(3G-PR$XB@` -M@.(&$*#A)""@X_[__^M,-P/C`Z"$Y]``R^%0-P/C\P"$X=`@R^%`!(WH")"- -MY=`0H.,,$(WE!P"@X?[__^O>)]3E)#<#XP,@Q.=L,)3E`@L3XP$```H$`*#A -M#___Z]XWU.4(`%/A"P``"GX.A.($`(#B"!"@X?[__^L``%#C!0``"MZ'Q.4$ -M`*#A"!"@X0`@H.,",*#A_O__ZRPZ`^,#,)3G``!3XQ$``!H$`*#A`1"@X_[_ -M_^NH/`/C`S"4YP``4^,"```:F`"?Y?<7`./^___K`#"3Y0``4^,!(*`3(2+# -M%0<``!IX`)_E.1<`X_[__^LH*@/C`B"4YP(`4^$H*@,3`C"$%RPZ`^,#,)3G -M`@!3XP(@H!,L.@,3`R"$%]XGU.7I/:#C`R#$YP`P`.,`,$#C`#"3Y600H..1 -M"0G@TRT$XV(@0>.2"8'@VPV$XC``@.(A$X/@_O__ZP``H.,4T(WB\(^]Z`PU -M``#,9```,$`MZ1303>(`0*#AJ#P#XP-0D.<```#C``!`XS@1G^4$(*#A_O__ -MZP0PE>4"`%/C"`!3$T8``!IL,)3E$``3XT,``!HL.@/C`S"4YP``4^,?```* -MW0V$XB0`@.+^___KW@V$XA@`@.+^___KWPV$X@P`@.+^___K*#H#XP,PE.4!(*#C"""-Y1\@@N(,((WE -M""P#XP(`E.<#$*#A`R"@X?[__^L)``#J`@!3XP<``!H>,(/B`#"-Y0@\`^,# -M`)3G`!"@XP$@H.$!,*#A_O__ZQ@`G^5<$)7E_O__ZQ30C>(P@+WH[&0``"0Z -M``#D4T$WB`$"@X:@\`^,#4)#G````XP``0.,L$9_E!""@ -MX?[__^L$,)7E`@!3XP@`4Q-#```:;#"4Y1``$^-````:+#H#XP,PE.<``%/C -M&@``"B@J`^,"()3G`@!3X2@J`Q,",(07)#H#XP,PE.<"`%/C`B"@$R0Z`Q,# -M((07+#H#XP,PE.<*`%/C"B"@$RPZ`Q,#((07*#H#XP,PE.<`,(WEJ`"?Y:`0 -MG^4D.@/C`R"4YP@P@^(#,)3G_O__ZW(PU.4``%/C#0``"@@\`^,#`)3G4#&4 -MY0PP0^(`,(WE`!"@XP00C>4($(WE(#"@XPPPC>7@((3B%CZ$XO[__^L0``#J -M3`"?Y5P0E>7^___K`#"@XP`PC>4$,(WE"#"-Y2`@H.,,((WE""P#XP(`E.?@ -M$(3B`R"@X?[__^L8`)_E7!"5Y?[__^L4T(WB,("]Z!!E```D.@``W#T``/0] -M```$X"WE'-!-XG0!D.4`,-#E`<#0Y0#`C>4"P-#E!,"-Y0/`T.4(P(WE!,#0 -MY0S`C>4%`-#E$`"-Y0$`H.$"$*#A`"``XP`@0./^___K'-"-X@"`O>@$X"WE -M#-!-X@`TD.5L`)/E`0`0XP``H`,(```*F@8!X]``D^$``(WE`0"@X0(0H.$` -M(`#C`"!`X^PP@^+^___K#-"-X@"`O>AP0"WI`$"@X0%0H.$`,`#C`#!`XV`` -MD^7^___K`"24Y:@\`^,#,)+G``!3XP(``!HX`)_E]Q<`X_[__^L`,)/E``!3 -MXP(``!H@`)_E.1<`X_[__^L`4(7@`2#5Y3`@4N(!(*`3)"+#Y0``H.-P@+WH -M0#X``!!`+>ET,9#E`0"@X0,0H.$&(*#C_O__ZP8`H.,0@+WH<$`MZ0!0H.$! -M0*#A`#``XP`P0.-(`)/E_O__ZP$0@.(`!)7E`1"$X/[__^L!`%#C``"@`P`` -MX!-P@+WH<$`MZ0%0H.$"0*#A`!20Y0$`H.'<$('B_O__ZP`PH.$%`*#A!!"@ -MX0`@`.,`($#C_O__ZW"`O>CP02WI`'"@X0!`H.,`4`#C`%!`XP1AE><&`*#A -M_O__ZP`@H.$'`*#A!A"@X?[__^L``%#C`@``"@%`A.(9`%3C\___&@0`H.'P -M@;WH,$`MZ1303>(`0*#A`5"@X?[__^L0$)7E``!1XQ5`X`.U```*#0"@X7\] -MP.,_,,/C"#"3Y0P@D>(#(-(P`#"@,P``4^,&```:!`"-X@P@H./^___K``!0 -MXPU`X!,%```*I0``Z@0`C>(,$*#C_O__ZPU`X..@``#J#`"=Y=`0H./^___K -M`%!0X@M`X`.:```*!!"=Y0P@G>4-`*#A?SW`XS\PP^,(,)/E`@"1X`,`T#`` -M,*`S``!3XY,``!H-`*#A?SW`XS\PP^,(,)/E`@"1X`,`T#``,*`S``!3XP0` -M`!H%`*#A_O__ZP``4..&```:!@``Z@``4N,$```*!0"@X0(0H.'^___K#4#@ -MXW\``.H%`*#A_O__ZP`P4.)7```*#P!3XU4```H!,$/B%P!3XP/QGY=+``#J -M<%0%`(A3!0"<4P4`L%,%`,13!0!P5`4`<%0%`'!4!0!P5`4`<%0%`'!4!0!P -M5`4`<%0%`!14!0!85`4`<%0%`'!4!0``5`4`<%0%`'!4!0!P5`4`*%0%`-A3 -M!0#L4P4```24Y0$0H./^___K``"@XS@``.H`!)3E`!"@X_[__^L``*#C,P`` -MZ@0`H.$%$*#A#""=Y?[__^LK``#J!`"@X040H.$,()WE_O__ZR8``.H$`*#A -M!1"@X0P@G>7^___K(0``Z@0`H.$%$*#A#""=Y?[__^L<``#J!`"@X040H.$, -M()WE_O__ZQ<``.H$`*#A!1"@X0P@G>7^___K$@``ZN`PG^58`)/E_O__ZP,@ -M@.("$(7@`C!1Y00`H.$,P)WE#"!BX#`P0^+^___K!@``Z@4`H.$#$*#CK""? -MY?[__^L"`*#C`P``Z@``H.,``%#C`$"@L1\``+H``%#C`P``&@PPG>4``%/C -M`#"@PP`PQ<4,()WE``!2X0$@@,((((WE!`"=Y0T0H.%_/<'C/S##XP@PD^4" -M$)#@`Q#1,``PH#,``%/C`@``&@40H.'^___K`""@X0``4N,`0*`#!0``"@,` -M`.K^___K!`"@X130C>(P@+WH#4#@X_[__^L%`*#A_O__Z_?__^I8+```:#X` -M`*7&A/B9[HWV#?^]UK'>5)%08`,"J'718 -M+C0M-K+<[K3[6_:D379AM\Y]>U(^W7%>EQ/UIFBY```LP6!`'^/(>>VVOM1& -MC=EG2W+>E-28Z+!*A6N[*L7E3Q;MQ8;7FE5FE!'/BA#I!@2!_O"@1'BZ)>-+ -M\Z+^7<"`B@6M/[PA2'`$\=]CP7=UKV-","`:Y0[];;],@108-28OP^&^HC7, -MB#DN5Y/R58+\1WJLR.>Z*S*5YJ#`F!G1GG^C9D1^5*L[@PO*C"G'TVL\*'FG -MXKP=%G:M.]M69$YT'A3;D@H,;$CDN%V?;KWO0Z;$J#FD,3?3B_(RU4.+66ZW -MVHP!9+'2G.!)M-CZK`?S)<^ORH[TZ4<8$-5OB/!O2G)<)#CQ5\=S49%!ZI8\#^%F`"1<:VF4QU\:$ -MN-##@K`I=UH1'LM[_*C6;3HLQJ7XA.Z9]HW_#=:]WK&15&!0`@/.J59]YQFU -M8DWF[)J/11^=B4#ZA^\5LNN.R?L+0>RS9U_]1>HCOU/WY):;6W7"X1P]KDQJ -M;%I^0?4"@T]H7%'TT33Y".*3JW-B4RH_"`R54D9EG5XP*#>A"@\OM0X))#8; -MF]\]S29.:7_-ZI\2&QV>6'0T+C8MW+*T[EO[I/9V3;=A?]T^7G$3EZ;U -MN6@``,$L0&#C'WG(MNW4OHU&9]ER2Y3>F-2PZ(5*NVO%*D_E[1:&Q9K79E41 -ME(K/Z1`$!OZ!H/!X1"6Z2^.B\UW^@,`%BC^M(;QP2/$$8]]WP:]U0F,@,.4: -M_0Z_;8%,&!0F-<,OON$UHHC,+CF35U7R_()Z1\BLNN#8M*SZ\P?/)74),Z*5Z`X]9^`F`&A=EVM\NH_&W6+#IC?'=[\FMOQ3`! -M9RO^UZMVRH+)??I91_"MU**OG*1RP+?]DR8V/_?,-*7E\7'8,14$QR/#&)8% -MF@<2@.+K)[)U"8,L&AMN6J!2.]:S*>,OA%/1`.T@_+%;:LN^.4I,6,_0[ZK[ -M0TTSA47Y`G]0/)^H4:-`CY*=./6\MMHA$/_STLT,$^Q?ET07Q*=^/61=&7-@ -M@4_<(BJ0B$;NN!3>7@O;X#(Z"DD&)%S"TZQBD97D>>?(-VV-U4ZI;%;TZF5Z -MK@BZ>"4N'*:TQNC==!]+O8N*<#ZU9D@#]@YA-5>YAL$=GN'XF!%IV8Z4FQZ' -MZ@X,=="PL6"X:&C0M&QLVLFYNW.Y: -M6K3[H*!;]E)2I$T[.W9AUM:WSK.S?7LI*5(^X^/=<2\O7I>$A!/U4U.F:-'1 -MN0`````L[>W!8"`@0!_\_./(L;%Y[5M;MKYJ:M1&R\N-V;Z^9TLY.7+>2DJ4 -MU$Q,F.A86+!*S\^%:]#0NRKO[\7EJJI/%OO[[<5#0X;734V:53,S9I2%A1'/ -M146*$/GYZ08"`@2!?W_^\%!0H$0\/'BZGY\EXZBH2_-14:+^HZ-=P$!`@(J/ -MCP6MDI(_O)V=(4@X.'`$]?7QW[R\8\&VMG=UVMJO8R$A0C`0$"`:___E#O/S -M_6W2TK],S?]S[NQ].XN&L\%!0H>=[>I^)>7KP="PL6=MO;K3O@ -MX-M6,C)D3CHZ=!X*"A3;24F2"@8&#&PD)$CD7%RX7<+"GV[3T[WOK*Q#IF)B -MQ*B1D3FDE94Q-^3DTXMY>?(RY^?50\C(BUDW-VZW;6W:C(V-`635U;'23DZ< -MX*FI2;1L;-CZ5E:L!_3T\R7JZL^O967*CGIZ].FNKD<8"`@0U;JZ;XAX>/!O -M)25*NT+FY:9&&AA=8P<&9)QT=.KF>GB'9$_CXZ[.8F"LS$1$B -MNVEITG#9V:F)CHX'IY24,[:;FRTB'AX\DH>'%2#IZR["P>_Q45*C6N[MM.A86+%"G]%%394%^PZ07&I9>)SK+:ZL[\46= -M'ZM8^JR3`^-+5?HP(/9M=JV1=LR()4P"]?S7Y4_7RRK%@$0U)H^C8K5)6K'> -M9QNZ)9@.ZD7AP/Y=`G4OPQ+P3(&CET:-QOG3:^=?CP.5G)(5ZWIMO]I94I4M -M@[[4TR%T6"EIX$E$R,F.:HG"=7AYCO1K/EB9W7&Y)[9/X;X7K8CP9JP@R;0Z -MSGT82M]C@C$:Y6`S49=%?U-BX'=DL82N:[L -ME+?X>U(CTW.KX@)+/'^,JJU5F!RCKL@/"M2^:>\6&I0@WT_*'*#"RI;\C -MNFH#`ER"%NTK',^*DK1YI_#R!_.AXFE.S?3:9=6^!08?8C31BOZFQ)U3+C2@ -M5?.B,N&*!77K]J0Y[(,+JN]@0`:?<5Y1$&Z]^8HA/CT&W9:N!3[=1KWF3;6- -M5)$%7<1Q;]0&!/\54&`D^Y@9E^F]ULQ#0(EWGMEGO4+HL(B+B04<*?*'I#T)\R1Z$^`````"#AH`)2.TK,JQP$1Y.U:X] -M)SDM-F39#PHAIEQHT51;FSHN-B2Q9PH,#^=7D]*6[K2>D9L;3\7`@*(@W&%I -M2W=:%AH2'`JZD^+E*J#`0^`B/!T7&Q(+#0D.K<>+\KFHMBW(J1X4A1GQ5TP' -M=:^[W9GN_6!_HY\F`?>\]7)2XRMPQ -MUQ"%8T)`(I<3(!'&A'TD2H7X/;O2$3+YKFVA*<=++YX=\S"RW.Q2A@W0X\%W -M;!:S*YFY<*GZ2)01(F3I1\2,_*@:/_"@V"Q]5N^0,R+'3DF'P=$XV?ZBRHPV -M"]28SX'UIBC>>J4FCK?:I+^M/^2=.BP-DGA0F\Q?:F)&?E3"$XWVZ+C8D%[W -M.2[UK\."OH!=GWR3T&FI+=5OLQ(ESSN9K,BG?1@0;F.";-]!A9 -M;@&WFNRHFD^#96Z5YG[F_ZH(S[PAYN@5[]F;Y[K.-F]*U`F?ZM9\L"FOLJ0Q -M,2,_*C"4I<;`9J(U-[Q.=*;*@ORPT)#@%=BG,TJ8!/'WVNQ!#E#-?R_VD1>- -MUDUV3;#O0U1-JLS?!);DX[71GAN(:DRX'RS!?U%E1@3J7IU=-8P!S4M+;DC-6$.D31]9MC&'7FGH,H3>.%/A9B3P3Z^XGJ4< -MX3RQ1WI9W]*('SK\H^Q&BY -M+#0D.%]`H\)RPQT6#"7BO(M)/"A!E0W_<0&H.=ZS#`B-G820V*L`C+S3"O?D6`6XLT4&T"P>C\H_#P+!K[T# -M`1.*:SJ1$4%/9]SJE_+/SO"TYG.6K'0BYZTUA>+Y-^@<==]N1_$:<1TIQ8EO -MMV(.JAB^&_Q6/DO&TGD@FMO`_GC-6O0?W:@SB`?',;$2$%DG@.Q?8%%_J1FU -M2@TMY7J?D\F<[Z#@.TVN*O6PR.N[/(-3F6$7*P1^NG?6)N%I%&-5(0Q]`0($ -M"!`@0(`;-@```@0+%@P2&"0P2&!L``````H````0````$````!`````0```` -M$````!`````0````$````!`````0````$````!`````0````$````!`````* -M````4&^:"5!OF@D`4/($`%#R!`!0\@0`4/(!`%#R`0!0\@(``0``)"8H*BPN -M,#(T-C@Z/#Y`9&9H:FQN<')T=GAZ?'Z`@H2&B(J,E9>9FYV?H:.E`````A$" -M"@$!`0`!``$``0`!"0,)`P````(/`0@"!@(+`@D!`0(%`1(`!`(0```````` -M`````````````````````````0`"``,`!``"!``!`PP`"P`%```````````` -M``````8`!P`(``D""@`"``,##0,.`@\````````````````"$````0(#!`4& -M!P@)"@L,#0`-`0(#!`4&!P@)"@L-#0`-`0(#!`4&!P@)"@L````+`0(#!`4& -M!P@)"@L,#0X."@L,#0`````````````$```````````````````````````` -M```````D*"PP-#@\0&1H;'!T>'R`A(B,```````3)"@L,#0X/$!D:&QP='A\ -M@(2(C)69G:&E&"0H+#`T.#Q`9&AL<'1X?("$E9F=H:4``!8D*"PP-#@\0&1H -M;'!T>'R`A(B,E9F=H:48)"@L,)69G:&E````````````````````"20H+#`T -M.#Q`E9F=H:4```````````````TD*"PP-#@\0)69G:$````````````````, -ME9F=H:4`````````````````````````!20H+#`T.#Q````````````````` -M``````@D*"PP-#@\0&1H;'!TB(R5F9VAI0`````4)"@L,#0X/$!D:&QP='A\ -ME9F=H:4`````%"0H+#`T.#Q`9&AL<'1X?("$B(P``````!,D*"PP-#@\0``` -M```````````````````(9&AL<'1X?("$B(P`````````````````"S@\0&1H -M;'!TB(R5F9VAI0````````````\X/$"5F9VAI0`````````````````````( -M)"@L,#0X/$!D:&QP=(2(C)69G:&E````%20H+#`````````````````````` -M``````0`________```````````````````````````````````````````` -M```````````````````````````````````````````````````````$```` -M````````````````#``````````(```````````````````````````````` -M```````````````````````````````````````````````````````````` -M``````````````````````````````````!M;&UE97AT7VIO:6YB`````!R='=?>&UI=&9R86UE7V-O86QE`FP```/____\` -M`````````/____\`````````````````````````````````````^?____C_ -M___X____^/____C____X____^/____C____Y____^/____C____X____^/__ -M__C____X____^/___R?P__\OH%6J)P```"]0JE4`#@0.$`X4#A@.'`XP"#0( -M/`A("$P(:`C_______\```#@3(&(`@````8&!@`&``!!J'*Y`P`!`````@`# -M`````P`"``$````"``$``@````,````#`````@````$````!```````````` -M```"`````@````(````"`````@````(````"`````@````0````&````!0`` -M`'AM:71F_"-`)`@M:#-P-C0]S$903 -M]Q6F&*<;!Q_1(A`GU"LM,2TWZ3UW1?%-YX`-B8**@^23H_8(W_GL^JGP[?LB -MB8**@^SZX*/(Q8+(S,6#S/"CR,6"R,S%@\S?ZM[H@-N)@HJ#Y).C\@C?^8#, -MB/#O8`$.3F##B/#M)`*T!`!0N?6"ZR0"M`0`4*\C(T6"(Y!"4'.[`0F)@HJ# -M^.`H\")0`R?W(KO^!?CC*/,BBH.)@OCDDR@BNP$/^.6"*?6"Y8,Z]8/@*/`B -M4`G%@BGXY8(F]B*[_@G%@BGXXB6"\B+XZB6#]8/IDR@BQ?#XH^`H\,7P^.6" -M%8)P`A6#X#CP(N]+_^Y*_NU)_>Q(_"+@_*/@_:/@_J/@_R*D)8+U@N7P-8/U -M@R+@^Z/@^J/@^2+K\*/J\*/I\"+0@]""^.23"CM?`VW_:`,HB"C(.'\`GDDZ.U -M\"7?]8`AB(*,@^/U\`G@H[7P%-_U@!"(@HR#X_7P">23H[7P`M_T`D4:@(>` -MZ8"0@-2`/H`5@&Z`?H"=@+>`C8"C@%&`=(`\`D4FB8**@^SZY)/U\*/(Q8+( -MS,6#S.23H\C%@LC,Q8/,M?!VW^/>X8!PB8**@^23]?"CX@BU\&+?](!>B8** -M@^#U\*/F"+7P4=_U@$V)@HJ#X/7PH^((M?!`W_6`/(F"BH/DD_7PH^8(M?`N -MW_2`*H`"@%>)@HJ#[/KDD_7PH\C%@LC,Q8/,X*/(Q8+(S,6#S+7P!M_DWN*` -M`'__M?`"#R)``G\!(HF"BH/L^N#U\*/(Q8+(S,6#S."CR,6"R,S%@\RU\-7? -MY=[C@,^)@HJ#[/K@]?"CR,6"R,S%@\SDDZ/(Q8+(S,6#S+7PK]_DWN*`J8CP -M[V`!#DY@J^TD`K0$`%"8]8+K)`*T!`!0CB,C18(CD$1B<\*O@/XR$D69A=`+ -M==`(JN#"C.6*)&?UBN6,-'GUC-*,["2+^.:\!`)T_\.5@;1``$#.>05X@!;F -M"'`+PJ_F,.$#1!CVTJ\(V>WJB]`BY0S_(R2!^`\("+\%!'\`>('F,.3R`.4, -MPY]0(`4,=(HE#/CF_::!".:N#+X$`G3_S?CH;6#@".;`X(#VY0S3GT`GY0PD -MB_CFK@R^!`)T__T8YLWXY8%M8`;0X/88@/7E#"2*R/85#(#3Y0PC)('X?P3" -MK^8PX`,0X@Q_`##A!S#C!'\(5/14?,;2KU2`0@(JF@70$8`;_"';_W_M_ -M!>1X@/8(]@C?^GB!=C"023%T`9/`X.23P.!#B0%UBF!UC'G2C-*O(@3OTY0$ -M0`-__R)T@2\O^.8@Y?3"K^9$,/;2KZX,[L.?4"$.=(HN^.;Y".88O@0"=/_] -M[6E@"0GG&1GW"0F`\Q86@-KNTY]`!`6!!8'NTY]`(G2*+O@(YOGNM0P"J8$8 -M!@;F_>UI8`D9&><)"?<9@/,>@-GO)(KXY@3X[R\$D$DQD_8([R^3]G\`(N_3 -ME`1``W__(N\C)('XYC#E],*OYE2,]M*OY0RU!PITBB_XYO6!`D7B4"YTBR_X -MYK\$`G3__1CF^72*+_C[YOSI;&`(J`7G]AT9@/2H`Z8%'^4,M0?C?P`B=(LO -M^.;]&(8!#W2*+_BF`0B&!.4,M0<"K('M;&`(#0FH!>;W@/3E#+4'WHF!?P`B -M[].4!$`#?_\B[R,D@?C"K^8PY04PX`+2Y-+BQM*O?P`PX@$/`D7AC_#D__[E -M#",D@/C"J3#W#7\(YF`++?9@,%`N@`23H_A4!R0,R,,SQ%0/1"#(@T`$]%:``4;V -MW^2`"P$"!`@0($"`D$DDY'X!DV"\H_]4/S#E"50?_N23HV`!#L]4P"7@8*A` -MN.23H_KDDZ/XY).CR,6"R,K%@\KPH\C%@LC*Q8/*W^G>YX"^BTV*3HE/JU"J -M4:E2$A^D_JM-JDZI3Q(?I/]N<"OO8`WE5!54<`(54Q1%4W`#?P`B=`$E3_5/ -MY#5.]4YT`252]5+D-5'U48"^JTVJ3JE/$A^D_]/N9(#X[V2`F$`#?P$B?_\B -M`$P!!@TP`08-<`%CL8)9B!&-79)S`X,#PP(/`@L#0==``P`#``<`"P`/` -M!,`%P`;`!Y`!Q'0[\'1)H_!3D>\29QWE.C#F`C&3_43Q]>'\"43Q]`G\#43R0!@K@1`?PD($QH^"0!5CPD("CX+0!%)"! -M)>!4^_"0@2G@(.(-?0%_!(`,D($EX$0$\")]`7\$TQ"O`9"#5.!D#&`"8?V1`N]D`6`" -M8?V1NV']D(-4X+0.!Y$"OP$"D7F0@U3@M`8"D5.0@U3@M`P'D0*_`0*1NY"# -M5.!D!'!=$FLB[V0!<%6Q4X!1D(-4X+0.!Y$"OP$"D7F0@U3@M`8"D5.0@U3@ -MM`P'D0*_`0*1NY"#5.!P!'\!D:&0@U3@M`0;$FO1@!:0@U3@M`P/D($EX/\3 -M$U0_,.`#$E]ET-"2KR(24BGO9`%@")`!N'0!\(`XD($DX/\3$Q-4'S#@")`! -MN'0"\(`C[\14#S#@")`!N'0$\(`4D($HX-.4!$`(D`&X=`CP@`-_`2*0`;ET -M`O!_`"*0@27@D`8$(.`,X$1`\)"!*70$\(`*X%1_\)"!*70,\)`%(N3P(I"! -M)>##$R#@")"!*70,\(`1D`8$X$1`\.!$@/"0@2ET!/"0!2+D\"*0@UOO\!)H -MIY"#6^!@!9`%(N3PD($I=`3P(I"`H^!D`7`MD($EX%3]\)`%(G1O\'\!\8V_ -M`0Z0@23@1(#PD($I=`[P(I`!N70!\)`!N`3P(N]P.WT!_[$[?7A_`K$[?0)_ -M`[$[?_O9T,"_U@N0T`?6#[O`BD`4B=/_P$FA? -MD`$W=`+P_7\#43P26LSDD($I\"+#$U0!_Y""?N_P?X!^"!(M7)"!/Q(@SI"" -M?N"0@3=@!>!$`?`BX%3^\"*0@GL20X\2'Z0PX&>Q<)``1N!4\_U_1A(R'I`` -M1^!$#/U_1Q(R'I"">Q)#AA(?I!,35#^0`$@PX!+@1`S]?T@2,AZ0@3?@1`+P -M@!#@1`3]?T@2,AZ0@3?@5/WPD`!1X$0,_7]1$C(>?09_`=%`?0=_`8`SY/^Q -M=9``1^!4\_U_1Q(R'I``2.!4\_U_2!(R'I"!-^!4_?!]!G\!T5%]!W\!T5'D -M_R&KK@=T-2[XYDWV_>XD4/\",AZN!W0U+OCF_^WT7_;][B10_P(R'I"!*>!D -M!F`D$FF6D($EX!,3$U0?,.`5D($LX/^CX&]P"Q)I&PD($IX,.4!%`"4:8BD($G -MX&!%D($EX/\3$Q-4'S#@$I`!.^`PY`NQ,9"!+.`4D`5S\)"#3>1U\`$20TO# -MD(-.X)2`D(--X&2`E(!`"Y`!F.!4_O#@1`'P\<.0@EO@,.`MD("CX+0!)I"# -M7.`$\."T"@N0@EW@!/#DD(-<\)""7>#_D()2C\/&+(O%6D($LX!20 -M!7/P?0)_`E$\@+B0@2?@8"Z0@*/@9`%P)I"!+?`$8!^0@2K@1!#PY/4=D($N -M$E))D`%7=`7PD($IX"#B`E&F(N3_CPT2:#&_`1B0@`026SBM!ZP&KPT2:^60 -M!!]T(/!_`2)_`"*0!@3@5'_PD`4BY/"0@2ET#/`BD()>X##@+)""8>`$\.#_ -MD()?X+4''9`&DN!4''`*\8N0@F+@!/"`!I`&DG0<\.20@F'P(L#@P/#`@\"" -MP-!UT`#``,`!P`+``\`$P`7`!L`'D`'$=/?P=$^C\!)G4^5!,.`",=/E03#C -M`Q)GK>5!,.0%?P(21[SE0S#@`A&KY4,PX0,23L'E0S#B`Q).9>5#,.,",7KE -M0S#D`C&;Y4,PY0(Q1^5#,.8",2SE1##A`Q)GNN5$,.(#$F@7Y40PXP,2:"1T -M]P20`<3P=$^C\-`'T`;0!=`$T`/0`M`!T`#0T-""T(/0\-#@,N3_D($GX&!X -MD("CX&0!<'"0@2;@Q%0/8"0D_F`#!'`?D($MX!3PX/Y@!I"!+^!@#^YP!I"! -M+."C\'\!@`)_`>]@/I"!*N!$$/"0@2_@8`.T`0GD]1V0@2_@@`WD]1V0@2_@ -M=?`#I"3^_Y"!+N`O44J0`5=T!?"0@2G@(.(#$DJF(I"`H^"T`1.0@2?@8`V0 -M@2K@5/[P5`=P`C')(I"`H^"T`120@2?@8`Z0@2;@5`]D`F`"@`-Q&"(2:#&_ -M`1"0@`/@_^3]$EL\D`0?="#P(I"`H^!D`7`8D($GX&`2D`%7Y/"0`3QT`E%" -MD`%7=`7P(I"`H^!D`7`ED($GX&`?D`%7Y/"0`3QT`O"0@23@5/OPD($JX%3] -M\%0'<`(QR2*0@2C@_WT!`DJJD($FX/_$5`\D_5`"@$?O5`]@.Y`!6^3PD`$\ -M=`3P42GO9`%P,/4=D($UX,,35'_U'N3[_7]8?@%14Y`!6W0%\)`&DG0!\)"! -M).!$"/`B42F_`0(QR2*0!!K@]&`#?P`BD`0;X%0'9`=_`6`"?P`B\.3U'9"! -M-.#U'N3[_7]4?@&.&8\:Y1Y4!\0S5."%&8.%&H+PY1U4!\0S5.#_Y1X3$Q-4 -M'T^C\.M4!\0S5.#_Y1T3$Q-4'T^%&H*%&8.CH_"]`0R%&H*.@Z.CHW0#\"*% -M&H*%&8.CHZ-T`?`BD`:IX)""8_#@5,!P#)"!*N!4_O!4_?`AR9""8^`PYB&0 -M@2?@9`%P()"!*N!$`?"0@2;@5`]D`F`$,6.`"W$8@`>0@2K@5/[PD()CX)"! -M*C#G$^!$`E%"D`%7=`7PD($DX$0$\"+@5/WP(I`!7^3PD`$\=`CPY/4=D($U -MX,,35'_U'N3[_7]0!I#@1`'P(M,0KP'#P-"0@I9T"/#DH_"C\)`! -M'^#^D`$>X'P`)`#_[#Z0@HSPH^_PD`*"X)""E?"0@4/@(.`"H`D&"__(I"!)^!@,Y`&DN`PX"/D]1V0@37@PQ-4?_4>Y/O]?UA^`5%3 -MD`%;=`7PD`:2=`'P(I"!).!4]_`QR2*0@2?@8#.0!I+@,.$CY/4=D($UX,,3 -M5'_U'N3[_7]0`<1T=_!T5J/P4Y'?$F>`Y4DPX0+Q1.5) -M,.("T0/E23#C`M$]Y4HPX`,29\3E3##A!7\#$D>\Y4PPY`,23T/E3##E`G%B -MY4PPY@+Q!W1W!)`!Q/!T5J/PT`?0!M`%T`30`]`"T`'0`-#0T(+0@]#PT.`R -MD($DX/_$$Q,35`$PX"OO5'_PD`3@X)"!)3#A!N!$`O"`#^!4_?"0`;ET`?"0 -M`;@$\)"!)^!@`C')?P%AEY"!)^!@`O&6(GT!$EL\D(-7L="0@U>CX"\D-OGD -M-/QU$P'U%(D5=18$>P%Z@7E5$BOMY/]T&"_U@N0T!O6#X/YT22_U@N0T@?6# -M[O`/[[0&XR*0@23@_Q,35#\PX!'O5/OPD($JX%3]\%0'<$&`/9"!+^`$\)"! -M*N!4[_"0@2_@_[0!`H`$[[0"!I`%6.`$\)"!,^#_D($OX-.?0`^0@*/@M`$* -MD($EX%3[\"(QR2*0`/?@(.<)X'\!(.8,?P(BD`#WX##F`G\#(A)7\Y"``>_P -M$2"0`61T`?`"+:<1BQ&[$4T1;.3U-?4V]3?U.*TU?U`2,AZM-G]1$C(>K3=_ -M4A(R'JTX?U,",AYU/1#D]3YU/P=U0`*0`3#E/?"CY3[PH^4_\*/E0/`B=44. -M=48!=4<#=4ABD`$XY47PH^5&\*/E1_"CY4CP(I`!,.3PH_"C\*/PD`$X\*/P -MH_"C\/U_4!(R'N3]?U$2,A[D_7]2$C(>Y/U_4P(R'I`!-'3_\*/PH_"C\)`! -M//"C\*/PH_#]?U02,AY]_W]5$C(>??]_5A(R'GW_?U<",AZ0`(#@1(#]?X`2 -M,AZ0_0#@5+_P,;X2,G<29I=_`1)&JI""6G0"\/\21JJ0@EK@!/!_`Q)&JI"" -M6N`$\'\$$D:JD():X`3P$0TQ3Y``@.!$0/U_@!(R'G4@_S&O$F;'Y/\"1S,Q -MJ3&V$FI$,6TQQI""7N!4_O"C=`/PH_#DH_"C\"*0@4/@5/[PD(%(X%3^\)`& -MD.!$(/"0@43@5/[P5/WP5/OP5/?P5._P5-_P5+_P5'_PY*/PH_"CX%3^\"+D -MD("C\")UZ`-UJ(0BY)"`G?"C\"*0`93@1`'P(I""6^!4_O!4?_"C=`KPY*/P -M(C&"D`$_=`3PD(`!X+0!!Y#]`.!4[_`B[Y`$[&!.X%3=\)""4.#_46V0`1?@ -M_I`!%N!\`"0`_^P^D("?\*/O\)`&">!4_O"0!2)T__!1S)`"AN!$!/!17!)H -MIY`%(N3PD`$T=`CP_>3_`DH\X$0B\'T(Y/\233N0!I#D\)`"AN!4^_`AV!)L -MAY`"A^!P]Y`&D.!$`O`B?0%Q/'0`+_GD-/QU$P'U%(D5=18(>P%Z@7E:$BOM -MD(%:X)"!8O"0@5O@D(%C\)"!7."0@63PD(%=X)"!9?"0@5[@D(%F\)"!7^"0 -M@6?PD(%@X)"!:/"0@6'@D(%I\"(2:%^0A;L2(-K,\`#`?XQ^"!(NHI"%NQ(@ -MV@```!1_<'X.$BZBD(66$B#:`````.3]_Q(Q37]\?@@2+5SL1(#\D(-'$B#. -MD(-'$D-ND(6[$B#.?WQ^"!(NHI`!`'0_\*/@5/WPD`53X$0@\"+@_WT!TQ"O -M`0@T_@D`0E\)"#4.!@#G0/+_6"Y#3\ -M]8/@1(#PKP5T""_U@N0T_/6#Y/!T"2_U@N0T_/6#X%3P\'0A+?6"Y#3\]8/@ -M5/?PK@2O!=#0DJ\BD(*O$D./$F@Q[V0!8`*!0T_/I[`9""M>#]D720@K:CX"0P^>0T_/I[`<`#P`+``9""LA)# -MAHL3BA2)%746!M`!T`+0`Q(K[9""MJ/@_Z/@+R0Z^>0T_/I[`<`#P`+``9"" -MLA)#AHL3BA2)%746!M`!T`+0`Q(K[9""MJ/@_Z/@+R1`^>0T_/I[`<`#P`+` -M`9""KQ)#AHL3BA2)%746!-`!T`+0`Q(K[9`&,.!$$/"0!!]T(/`BD(*\[?"0 -M@KD20X_DD(*]\*/P$E7>D(*][_"0@KD20X82;JN0@K[O\)"!6>`D_&`:%&`' -M%&`$)`5P67L!>H%Y6I""O.#]$GCW@!M[`7J!>6*0@L(20X^0@KS@D(+%\'J! -M>5H2=WN0@K[@_Y""N1)#AI""O>!\`"GY[#KZP^F?^>J4`/IU$P%U%(%U%5JC -MX/46$BOM(M,0KP'#P-`2'Z3_5`'^D(%#X%3^3O[P[U0"_^Y4_4__\!(?I/Y4 -M!/WO5/M-_Y"!0_#N5`C^[U3W3O_P$A^D_E00_>]4[TW_D(%#\.Y4(/[O5-]. -M\)`!%^#^D`$6X'P`)`#_[#Z0@)_PH^_PD`'"=`'PD(%#X,,35`'_\6Z0@4/@ -M$Q-4`?_Q19`!PG0"\)"!0^`3$Q-4`?_Q2Y"!0^#$5`'_\5&0`<)T`_"0@4/@ -MQ!-4`?_Q5Y`!PG0$\)"!0^!4`?\Q[Y`!PG0%\-#0DJ\BD()X$D./[Q)#F%X4 -M`%X=`5XF`EXO`UXW!%Y`(%Y((5Y1(UY98%YB85YK8EY\@%YT@5Z$@EZ,@UZ5 -MA```7IZ0@G@20X8"99J0@G@20X8"9/20@G@20X8"9>*0@G@20X;ANY"">!)# -MA@)QAI"">!)#AH!>D()X$D.&`F8:D()X$D.&X5V0@G@20X8"2?>0@G@20X8" -M39J0@G@20X8"9F"0@G@20X:A")"">!)#AN';D()X$D.&X:&0@G@20X8"Q)#C_%Z -MD($GX/\23/&0@2?@8!F0@GL20X:0``$2'[U4#_^0``(2'[W]$FKQ(I"">^_P -M(I"">^_P(I"">^_P(I"">^_P(A(?I)"!,/`B4_`2'Z20@D[PD``!$A^]D()/\"(2'Z3_5`'^D();X%3^3O#OPQ,PX`J0 -M``$2'[V0@ESP(M,0KP'#P-`2'Z3\(.`%,=@"8)$2'Z3_5`'^D(%$X%3^3O[P -M[U0"_^Y4_4__\!(?I/Y4!/WO5/M-_Y"!1/#N5`C^[U3W3O_P$A^D_E00_>]4 -M[TW_D(%$\.Y4(/[O5-].__`2'Z3^5$#][U2_3?^0@43P[E2`_N]4?T[P[!,3 -M5#\PX`>0!I#@1`3P$A^D$Q,35!\PX`>0!I#@1`CPD(`!X+0"%)```1(?O9"! -M1?"0``(2'[V0@4;PT-"2KR+DD()J\)"":N!D`?`DEI`!Q/!T8*/PD($IX/^0 -M@2C@;V`#$E')D($DX##@!S&GOP$"$>"0@2G@D`&\\)"`H^"0`;WP,9X21>*` -MN],0KP'#P-"0@2G@<`!_`##G`G\![V4.8#[#D()LX)2( -MD()KX)030`B0`<#@1!#P(I"":^1U\`$20TM_%'X`$C*JTY"";."4,I"":^"4 -M`$"YD`'&X##@LB*0@3#@_7^3$C(>D``(X$00_7\($C(>?P$Q&9``D.!$`?U_ -MD!(R'G\4?@`",JHBD`"0X"#@^2)_`I""6N#^[\.>4!#O)>`D@?CF,.0#?P`B -M#X#F?P$BD`*'X&`(D`&X=`'P@">0@4/@,.`.D`*"X&`(D`&X=`+P@!*0`H;@ -M(.$(D`&X=`3P@`-_`2*0`;ET"/!_`"+D^_K]?P$21^.0@FWO\&#P41B`[-,0 -MKP'#P-"0`H)Y7$27=:0@TO@!/#@5`/P02F0`<#@1`+PD`%-X&2`\)"#2^"0`(GPT-"2 -MKR+D^_K]?P$21^.0@H#O\&#P<6N`[-,0KP'#P-"0@)[@_Y"`G>#^M0<$?P&` -M`G\`[V0!8$60`:_@<#_N=?`/I/^N\"0'^72`/OI[`<`"P`%T"2_Y=(`^^I"" -MA!)#C]`!T`)QU)"`G>`$\.!_`+0*`G\![V`%Y)"`G?#0T)*O(M,0KP'#P-"0 -M@H$20X^0@TS@_P3PD``![Q(?_'^O?@&11N]@29""@1)#AHL3BA2)%746`GL! -M>@%YH!(K[9""A!)#AHL3BA2)%9""@1)#AA(?I/_$5`_U%GL!>@%YHA(K[9`! -MKW3_\)`!R^!D@/#0T)*O(M,0KP'#P-"0@H?N\*/O\.2C\*/PD(*'X/ZCX/6" -MCH/@8"W#D(**X)3HD(*)X)0#0`N0`<#@1(#P?P"`%9""B>1U\`$20TM_"GX` -M$C*J@,5_`=#0DJ\BY/OZ_7\!$D?CD(*+[_!@\)&VOP'K$E/V@.;DD(-5\*/P -MD`*&X"#A+,.0@U;@E-"0@U7@E`=`"I`!P>!$!/!_`"*0@U7D=?`!$D-+?PI^ -M`!(RJH#-?P$B(I"">Q)#CY```1(?O?_^$A^D_<,3,.`2D()[$D.&D``"$A^] -MD()_\(`%D()_[_"0@G[N\)""?^#^D()^X/_3GE`XD()[$D.&$A^D5`'^=*,O -M]8+D-(#U@^[P=*,O]8+D-(#U@^!P!+&9@`>0@G[@_Y'SD()^X`3P@+J0@*/@ -M<"60@2G@<`3_$DRAD($IX&0,8`,23["0@23@5/?P5._P5+_P5'_P(B*0`@G@ -M_1(?I/ZO!>TND(`"\)```1(?O?_M+Y"``_"0``(2'[W_[2^0@`3PD``#$A^] -M_^TOD(`%\)``!!(?O?^N!>TOD(`&\"+3$*\!P\#0$A^D_Y"!(_"_`1*0``$2 -M'[UD`6`7D`4B=&_P@`^0``$2'[UD`6`%D`4BY/#0T)*O(I```A(?O?\PX"82 -M'Z20@3/PD``!$A^]D($T\.]4_O^CX%0!3_"0``,2'[V0@3;P(I"!,W0!\*-T -M`_"CX%0!1"CPHW0%\"(2'Z1^`'@8PS/.,\[8^?_[J@;J,Y7@^?B0@3\20V[L -M5`/\$D-AD($[`B#.D(-9[_`BD(-:[_`BD`$!X$0$\)`!G'1^\*-TDO"C=*#P -MHW0D\)`!FW1)\)`!FG3@\)`!F>3PD`&8!/`BY)"":/"C\)`!F.!_`##D`G\! -M[V0!8#[#D()IX)2(D()HX)030`B0`<'@1!#P(I"":.1U\`$20TM_%'X`$C*J -MTY"":>"4,I"":."4`$"YD`'&X##CLB*0`%3@537U.:/@53;U.J/@53?U.Z/@ -M53CU/*TY?U02,AZM.G]5$C(>K3M_5A(R'JT\?U<",AZ0`33@53WU0:/@53[U -M0J/@53_U0Z/@54#U1)`!-.5!\*/E0O"CY4/PH^5$\"*0`3S@547U2:/@54;U -M2J/@54?U2Z/@54CU3)`!/.5)\*/E2O"CY4OPH^5,\"*0@4/@,.`%?P021[PB -MD($GX&`#$DZ2(A)I*Y""9._PX/Q4`?Z0@23@5/Y.\.PPYA&0`2_@,.<$Y/"` -M!I`!+W2`\)"!).`PX!J0@3'D\*-T!_"0@3&CX)`%6/"0!.S@5-WP(I`$[.!$ -M(O`BD($WX##@!>3_$DFK(I"!-^`PX`5_`1))JR+3$*\!P\#0D`0=X&`:D`4B -MX%208`>0`<#@1`CPD`'&X##AY'\`@`)_`=#0DJ\BY)"#4?"C\)`%^.!P#Z/@ -M<`NCX'`'H^!P`W\!(M.0@U+@E.B0@U'@E`-`"I`!P.!$(/!_`")_,GX`$C*J -MD(-1Y'7P`1)#2X"_TQ"O`!$`O"0`0!T__"0!K=T"?"0!K1TAO!_ -M?'X($BU<[%1__)"#0Q(@SI"#0Q)#;I"%NQ(@SG]\?@@2+J*0A;L2(-K,P`#` -M?XQ^"!(NHI"%NQ(@V@#``!1_<'X.$BZBD(66$B#:``,^8.3]_Q(Q3=#0DJ\B -M$:>0@2ET#/`BY)""9?"C\*/PD`"#X)""9?"0`(/@_I""9>#_M08!(L.0@F?@ -ME&20@F;@E`!`#9`!P.!$0/"0@F7@_R*0@F;D=?`!$D-+@,+O%)`%<_"0`3]T -M$/#]?P-T12_XYDW^]G0X+_6"Y#0!]8/N\"*0@*/@9`%@`D$KD($GX'`"02N0 -M@2;@Q%0/9`%P(I`&J^"0@2WPD`:JX)"!+/"CX/]P")"!+.#^_X``D($M[_"0 -M@27@1`3PY)"!+_"0@3&CX)`%6/"0`5?D\)`!/'0"\)"!*N!4_?!4[_"0@2;@ -M_\14#R3]4`*``Q)2KI"!)>`3$Q-4'S#@#Y"!+.#_H^"U!P4Q3PHW0"\.20 -M@2KPD($DX%3^\)"!*'0,\)"!).!4W_"0@2ET#/"0@23@5+_P5'_PH^!4_O!4 -M_?!4]_"0@`'@_[0!")"!,'21\(`/[Y"!,+0#!720\(`#=$#PD($S=`'PHW0# -M\*/@5`%$*/"C=`7P(N\D_F`,!'`HD($L=`'PH_`B[7`*D($VX)"!+/"`!9"! -M+.WPD($LX*/PD($EX$0(\"(24BGO9`%@")`!N'0!\(!4D($JX/]4`V`(D`&X -M=`+P@$.0@2C@_N3#GE`(D`&X=`3P@#'O,.((D`&X=`CP@"60@2K@,.0(D`&X -M=!#P@!:0@27@$Q-4/R#@")`!N'0@\(`#?P$BD`&Y=`3P?P`B[V`^D("CX&0! -M<#:0@27@5/[PD`4B=`_PD`8$X%2_\.3_$D^-OP$.D($DX$1`\)"!*70&\"*0 -M`;ET`?"0`;AT"/`BD`4B=&_PD`4GX%2_\)"!*70&\")T'RWU@N0T_/6#X%0_ -M\.]@'70A+?6"Y#3\]8/@1!#P=!\M]8+D-/SU@^!$@/`B="$M]8+D-/SU@^!4 -M[_!T'RWU@N0T_/6#X$1`\"*K!ZH&[2O[Y#KZPY"`H.";D("?X)I0$Z/@)`'_ -MD("?X#0`_L/KG_OJGOKJD/T1\*\#=``O]8+D-/OU@^#_(N#^H^#_D`*$[_#N -MH_"CX$0!\)`!O.`$\"*0`1_@_I`!'N!\`"0`_^P^D()[\*/O\)`"A^#YD(%# -MX"#@`J%9Y/OKPYE``J%9D()[X/RCX/WLD/T1\'0"+?6"Y#3[]8/@5`\S,S-4 -M^/IT`2WU@N0T^_6#X/YT`"WU@N0T^_6#X'P`)`#_[#Y4/ZT'_.HD&/_D,_[O -M+?WN//R0@*'@_J/@_[%:K0>0@GONC_`20TN0@)_@_J/@_Y"">^#\H^#3G^R> -M0"*0@GO@_J/@_Y"`G^#\H^`D`?WD//S#[YW_[IR0@GOPH^_PD()[D6X+@:XB -M[X[P$D.^;7@`0&V@`(!MRP$`;=\"`&WW!````&X4[50_<`3^_X`$?@!_0.\M -M_^X\_N]X!L[#$\X3V/EX!L,SSC/.V/F`)NU4?W`$_O^`!'X`?X#O+?_N//[O -M>`?.PQ/.$]CY>`?#,\XSSMCY_:P&@$GM<`3^_X`$?@%_`.\M[CQ]`/R`->Q4 -M`4UP!/[_@`1^`G\`[RWN/,,3?0"`&NQ4`TUP!/[_@`1^!'\`[RWN/!,35#]] -M`"7@)>#\K@2O!2*0@4C@_R#@!Y`!/^`PXA3O1`&0@4CPD(%$X,14#R#@`W\` -M(G\!(N^0`<>TH`;@1`3P@`3@1`CPD(%(X$0!\"+D_G00+O6"Y#0&]8/@_72? -M+O6"Y#2"]8/M\.\N)`3U@N0T^_6#X/UTF2[U@N0T@O6#[?`.[K0&RGB??()] -M`7L!>H)YF7X`?P8217'O?P!P`G\!(M,0KP'#P-"0@SD20X_DD(,\\)"#.1)# -MANDD$/GD.HL3]12)%746!GL!>H-Y/1(K[750`751@7523W53`'54!GL!>H-Y -M/1)(P>]P!9""3H`#D()/X)"!6?"0@5G@%&`1%&`6)/Y@$A1@!Q1@!"0&@!"0 -M@SQT!/"`#9"#/'0(\(`%Y)"#//"0@SS@_]#0DJ\BD(*9[_"C[?!XH7R"?0%[ -M_WI`>*=\@GT!>_]Z0'G&?@!_!!)"T'BK?()]`7O_>D!YRGX` -M?P020M"0@IK@_Y""F>`O_R0&]8+D-/OU@^!D"&`#`G"!=``D"OGD-/MU$P'U%(D5=18&>P%Z@GF;$BOMD(*: -MX/^0@IG@+R00^>0T^W43`?44B15U%@9[`7J">:$2*^V0@IK@_Y""F>`O)!;Y -MY#3[=1,!]12)%746!'L!>H)YIQ(K[7B;?()]`7L!>H%Y27X`?P8217'O<%B0 -M@IK@_Y""F>`O)"#YY#3[=1,!]12)%746!'L!>H)YJQ(K[7BK?()]`7L!>H%Y -M57X`?P0217'O:&0@K(20X_DD(*U\'J">:<"6Z60!C#@1"#P(G0` -M+_6"Y#3[]8/@5`QD"'!B[RW^)`;U@N0T^_6#X&2(<%%T!R[U@N0T^_6#X&2. -M<$+O+2O^)`'U@N0T^_6#X&0#<#!T!B[U@N0T^_6#X##C&Y"!1.#$$Q-4`S#@ -M%I`!Q^!$`?"0@4C@1`'P(I`!Q^!$`O`BD`()X/T2'Z3^KP7M+I""4/"0``$2 -M'[W_[2^0@E'PD``"$A^]_^TOD()2\)```Q(?O?_M+Y""4_"0``02'[W_[2^0 -M@E3PD``%$A^]_^TOD()5\)``!A(?O?^N!>TOD()6\"*0`@G@_1(?I/ZO!>TN -MD()7\)```1(?O?_M+Y""6/"0``(2'[W_K@7M+Y""6?`B$A^D_U0!_I""7N!4 -M_D[P[\,3,.`4D``!$A^]D()?\)```A(?O9""8/`BD(+'$D./D(+*[?#DD(,6 -M\)"#%N#_PY1`4!1TTR_U@N0T@O6#Y/"0@Q;@!/"`XI""QQ)#AHL3BA2)%9"" -MRN#U%GL!>H)YTQ(K[>20@M+PD(+2X/_#E$!0%G33+_6"Y#2"]8/@9#;PD(+2 -MX`3P@."0@LL20X:0@L[@__6"=8,`=(`2'_SO=?`(I"0`_^7P-`+\D`!^$A_\ -M[Y``?Q(?_.20@Q/PH_"0@Q/@_J/@_\.4P.Z4`$`"@0/#[Y1`[I0`4%*C=$#P -M=-,O^>0T@OI[`71`1(C]$B@(D(,3H^`DU_GD-(+Z>P&CX$2)_1(H")"#$Z/@ -M)-OYY#2"^GL!H^!$BOT2*`B0@Q.CX"3?^>0T@OI[`6%$Y)"#%?"0@LL20X:0 -M@Q/@_J/@*?GJ/OKI),#YZC3_^G2(_1(H")""RQ)#AI"#$^#^H^`I^>H^^NDD -MQ/GJ-/_ZH^!$B?T2*`B0@LL20X:0@Q/@_J/@*?GJ/OKI),CYZC3_^J/@1(K] -M$B@(D(++$D.&D(,3X/ZCX"GYZC[ZZ23,^>HT__JCX$2+_1(H")"#%>!$D)`! -MC/#DD(,7\*/PD`&,X"#D#\.0@QC@E!"0@Q?@E"=0$W\!?@`2,JJ0@Q?D=?`! -M$D-+@->0@Q?@_J/@_\.4$.Z4)T`,D`8QX$0!\.Z0!C;PD(,4X%0_9#!P2Y"# -M%_"C\)`!C.`PY0_#D(,8X)00D(,7X)0G4!-_`7X`$C*JD(,7Y'7P`1)#2X#7 -MD(,7X/ZCX/_#E!#NE"=`#)`&,>!$`O#ND`8V\)"#$^1U\!`20TM!5)""SQ)# -MANDD$/GD.OI]@!(JCY""SQ)#ANDD#/GD.OI]@1(JCY""SQ)#ANDD"/GD.OI] -M@A(JCY""SQ)#ANDD!/GD.OI]@Q(JCY""SQ)#AGV$$BJ/Y)"#%O"0@Q;@_\.4 -M0%`4=-,O]8+D-(+U@^3PD(,6X`3P@.*0@L<20X:+$XH4B160@LK@]19[`7J" -M>=,2*^WDD(+2\)""TN#_PY1`4!9TTR_U@N0T@O6#X&1<\)""TN`$\(#@Y)"" -MTO"0@L\20X:0@M+@__6"=8,`$A^]_I""RQ)#AH^"=8,`[A(?_)""TN`$\."T -M%-.0@LL20X:0`!1T@!(?_)""TG05\)""TN#_PY0^4!>0@LL20X:/@G6#`.02 -M'_R0@M+@!/"`WY""RQ)#AI``/G0"$A_\D``_=*`2'_SDD(,3\*/PD(,3X/ZC -MX/_#E(#NE`!``L'LP^^40.Z4`%!2HW1`\'33+_GD-(+Z>P%T0$2(_1(H")"# -M$Z/@)-?YY#2"^GL!H^!$B?T2*`B0@Q.CX"3;^>0T@OI[`:/@1(K]$B@(D(,3 -MH^`DW_GD-(+Z>P'!+>20@Q7PD(++$D.&D(,3X/ZCX"GYZC[ZZ23`^>HT__IT -MB/T2*`B0@LL20X:0@Q/@_J/@*?GJ/OKI),3YZC3_^J/@1(G]$B@(D(++$D.& -MD(,3X/ZCX"GYZC[ZZ23(^>HT__JCX$2*_1(H")""RQ)#AI"#$^#^H^`I^>H^ -M^NDDS/GJ-/_ZH^!$B_T2*`B0@Q7@1)"0`8SPY)"#%_"C\)`!C.`@Y`_#D(,8 -MX)00D(,7X)0G4!-_`7X`$C*JD(,7Y'7P`1)#2X#7D(,7X/ZCX/_#E!#NE"=` -M#)`&,>!$`?#ND`8V\)"#%.!4/V0P<$N0@Q?PH_"0`8S@,.4/PY"#&."4$)"# -M%^"4)U`3?P%^`!(RJI"#%^1U\`$20TN`UY"#%^#^H^#_PY00[I0G0`R0!C'@ -M1`+P[I`&-O"0@Q/D=?`0$D-+H3V0@L\20X;I)!#YY#KZ?8`2*H^0@L\20X;I -M)`SYY#KZ?8$2*H^0@L\20X;I)`CYY#KZ?8(2*H^0@L\20X;I)`3YY#KZ?8,2 -M*H^0@L\20X9]A`(JC\/NE`%`"@WM$Y#]$/#D+_\BP^Z4`4`DD/T1X&UP&I`! -M%^"U!0V0`>1T=_"0_1'D\(`&[020_1'PY"__(I""OQ)#CY""Q>!@`P)X4I"" -MPA)#AA(?I/1@`P)X1Q(?ZI""PA)#AI```1(?O?1@`P)X-Y```1(?_)```A(? -MO?1P;Y""PA)#AI```N02'_R0``,2'[WT<$Z0@L(20X:0``/D$A_\D``$$A^] -M]'`MD(+"$D.&D``$Y!(?_)``!1(?O9""PK3_#!)#AI``!>02'_R`1!)#AI`` -M!8`JD(+"$D.&D``$@!^0@L(20X:0``.`%)""PA)#AI```H`)D(+"$D.&D``! -M=`$20QB`"Y""PA)#AG0!$D+VD(+"$D.&$A^D_Y""OQ)#AN\2'^J0@L(20X:0 -M``$2'[W_D(*_$D.&D``![Q(?_)```N02'_R0``-T(!(?_)""PA)#AI```A(? -MO?^0@K\20X:0``3O$A_\D(+"$D.&D``#$A^]_Y""OQ)#AI``!>\2'_R0@L(2 -M0X:0``02'[W_D(*_$D.&D``&[Q(?_)""PA)#AI``!1(?O?^0@K\20X:0``?O -M`A_\D(+"[?"0@K\20X^0``,2'[V0@L;PD(*_$D.&BQ.*%(D5=18#>P%Z@GG# -M$BOMD(+"X'!&_W3#+_6"Y#2"]8/@M/\.=,,O]8+D-(+U@^3P@`]TPR_U@N0T -M@O6#X`3P@`4/[[0#T'43`744@G45PW46`Y""OQ)#AA(K[2(`8'!P:'E?05!# -M86QI8G)A=&5?.#$X.$4```#__P``<&AY7U-I;75L87)I='E#;VUP87)E7S@Q -M.#A%`$]$35]4>%!W`!?4$A97U!A=&A!1FEL -M;$E12TUA=')I>`!P:'E?4&%T:$)?25%+7S@Q.#A%`'!H>5]0871H05]2>$E1 -M2P!P:'E?4&%T:$%?25%+7S@Q.#A%`%]02%E?4F5L;V%D34%#4F5G:7-T97)S -M`%]02%E?4V%V94U!0U)E9VES=&5R`P` -M`(`,``"(#```E`P``)P,``"@#```4$A97TE10V%L:6)R871E7S@Q.#A%```` -M;V1M7U1X4'=R5')A8VM39710=W(X.$4````"`P0$!08'!P@)"@H+``#__OW\ -M_/S\^_GX]_?V`````@0&"`H,#A`2%!88&AL``@0&"`H,#A`2%!89&1D``&]D -M;5]46%!O=V5R5')A8VMI;F=#86QL8F%C:U]4:&5R;6%L365T97)?.#$X.$4` -M`&]D;5]#;VYF:6="0E]02%E?.#$X.$4``&]D;5]#;VYF:6="0E]02%E?4D5' -M7U!'7S@Q.#A%````;V1M7T-O;F9I9T)"7T%'0U\X,3@X10``;V1M7T-O;F9I -M9TU!0U\X,3@X10!O9&U?0V]N9FEG4D9?4F%D:6]"7S@Q.#A%````;V1M7T-O -M;F9I9U)&7U)A9&EO05\X,3@X10```&H8U#`^2:AA$GI\DF]D;5]39714>%)0 -M5%1I;6EN9U\X,3@X10````!O9&U?4F%T941E8VES:6]N7S@Q.#A%```````` -M```````D)BH8&AT?(2`"@`,@!0`'@`R``8`4`!E@"@`/``:`'T`5@"(`/H`P$!`0$!`@,$!08' -M"`$"`P0%!@<(!08'"`D*"PQO9&U?4F%T941O=VY?.#$X.$4```0`!``(`!`` -M&``D`#``2`!@`)``P`#8`#P`4`!D`*``\`"0`3`"@`(L`4`!X`'0`N@#L`1` -M!M`';V1M7U)A=&55<%\X,3@X10`````""A@H/````$]$35]205]397124U-) -M7S@Q.#A%`````$]$35]205]'971(=U!W&``@``!O9&U?4D%4>%)0 -M5%1I;65R4V5T=&EN9P!/1$U?4D%?57!D871E4F%T94EN9F]?.#$X.$4`;V1M -M7T%21D)2969R97-H7S@Q.#A%````3T1-7T1)1U],;W=E5\X.$4` -M````;V1M7T9A4EN:71?.#A%```````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M````````.#$X.&5U+G)T=U]M8S)U7V1I&UI=``X,3@X974N'0```````#CBP`````` -M`&UP7VEO8W1L``````````#DBP```4@``&%P:6YF;P````````````#EBP`` -M`D@``'-E='!I9`````````````#FBP```4@``'=P0#HBP```4@``'=P"4P,G@E,#)X -M)3`R>"4P,G@*`$Y!5#(U.B!!<'!L971A;&L@04%24"!386YI='D@8VAE8VL@ -M9F%I;"$*````4TE$('1A9R!L96YG=&@@=&]O(&QO;F71E -M"Q2 -M871E4T=)(#T@)60L($1E8VES:6]N4F%T92`](#!X)3`R>"`L4%13=&%G92`] -M("5D"@```#T]/B`E&1W,"@P>"4P.'@I"@``='AD=S$H,'@E,#AX*0H``'1X9'"D*``!T>&1W,R@P>"4P.'@I"@``='AD=S0H,'@E,#AX*0H``'1X9'"D*``!T>&1W-B@P>"4P.'@I"@``='AD=S0H`````)7,H*3H@(#T]/3X@<&AY7T-O;F9I9T)"5VET:$AE -M861E0H`````)7,H*3H@4$A97T-O;F9I9U)&5VET:$AE861E"DN(`H`)7,H*3H@3T1-7U=R:71E7T1) -M1R@I.D-U"`*`"5S*"DZ(&]D;5]$243TE9`H`)7,H*3H@8DQI;FME -M9#TE9`H````E71E`H````E"5X"@```"5S*"DZ($-U=%9E7!E/25D"@`E'1,3D$])60*`````"5S*"DZ($5X=%!!/25D"@`E -M'144E-7/25D"@```"5S*"DZ(%!A=&-H240])60*````)7,H*3H@ -M8DEN2&-T5&5S=#TE9`H`````)7,H*3H@8E=)1DE497-T/25D"@`E"5X"@``)7,H*3H@3W)G:6YI86P@ -M5DD@4$%204TZ(#!X)7@*```E`H``"5S*"DZ($]R9VEN:6%L($)+(%!!4D%-.B`P>"5X"@``)7,H*3H@4U=! -M4SI);FET(%-7($%N=&5N;F$@4W=I=&-H"@``4W=!;G1E;FYA4W=I=&-H5&EM -M97(`````6T]$32TY,D-=(```6T]$32TY,D1=(```6T]$32TX-S(S05T@```` -M`%M/1$TM.#$X.$5=(`````!;3T1-+3@X,3)=(`!;3T1-+3@X,C%=(``E5]3:6UU;&%R:71Y0V]M<&%R95\X -M,3@X12!C,2`E9"!C,B`E9"$A(0H``"5S*"DZ($E12SIP:'E?4VEM=6QA4-O;7!A"`E9"!C -M;VUP87)E,2`P>"5X(&-O;7!A"5X+"!46#%?02`](#!X)7@*```` -M)7,H*3H@62`](#!X)7@L(%18,5]#(#T@,'@E>`H````E"P@5%@P7T$@ -M/2`P>"5X+"!/;&1V86Q?,"`P>"5X"@`````E"P@5%@@ -M/2`P>"5X"@``)7,H*3H@7U!(65]0871H049I;&Q)44M-871R:7@@;VYL>2!4 -M>"!/2PH````E&5A8R`](#!X)7@* -M`"5S*"DZ(#!X96(T(#T@,'@E>`H`)7,H*3H@,'AE8F,@/2`P>"5X"@`E&5C-"`](#!X)7@*`"5S*"DZ(#!X96-C(#T@,'@E>`H`)7,H*3H@4&%T -M:"!"(%)X($E12R!F86EL(2$*`"5S*"DZ(%!A=&@@02!2>"!)44LA"@```"5S -M*"DZ(%!A=&@M02!2>"!)44L@;6]D:69Y(%)825%+(&UO9&4@=&%B;&4A"@`` -M`"5S*"DZ($Q/(&-A;&EB`H`)7,H*3H@,'AE.6,@/2`P>"5X"@`E&4T -M,"`](#!X)7@@=31T;7`@/2`P>"5X(`H````E2!26$E12R!M;V1E('1A8FQE(#(A"@`E&5A-"`](#!X -M)7@*`"5S*"DZ(%!A=&@@02!2>"!)44L@9F%I;"$A"@`E"!)44L@1F%I;"$A"@`E2$*```E"!296=%030])7@@ -M4F5G14%#/25X(%)E9T5"-#TE>"!296=%0D,])7@@4F5G14,T/25X(%)E9T5# -M0STE>`H@`````"5S*"DZ($E12SH@9FEN86Q?8V%N9&ED871E(&ES("5X"@`` -M`"5S*"DZ($E12SH@1D%)3"!U"!P"5X($5% -M4%)/371H97)M86QM971E"5X"@`E"5X+"!/1D1-7VEN9&5X/3!X)7@*```E"5X+"!#0TM?:6YD97@],'@E>"P@8V@@,30@ -M)60*`"5S*"DZ(%)E9T$R-#H@,'@E6"P@0T-+4W=I;F=486)L95]#:#%?0V@Q -M,ULE9%U;,ETZ($-#2U-W:6YG5&%B;&5?0V@Q7T-H,3-;:5U;,ETZ(#!X)5@* -M```E"5X+"!#0TM?:6YD97@],'@E -M>"P@8V@Q-"`E9`H``"5S*"DZ(')E;&]A9"!O9F1M(&EN9&5X(&9O"5X(`H` -M````)7,H*3H@4F5A9&)A8VL@5&AE"!%15!23TUT:&5R;6%L;65T97(@,'@E>"!D96QT -M82`P>"5X(&1E;'1A7TQ#2R`P>"5X(&1E;'1A7TE12R`P>"5X(`H````E"!P"!D96QT85],0TM?8F]U;F0@,'@E>"!D96QT85])44M?8F]U -M;F0@,'@E>`H``"5S*"DZ('1E;7`@3T9$35]!7VEN9&5X/3!X)7@L($-#2U]I -M;F1E>#TP>"5X"@```"5S*"DZ(&YE=R!/1D1-7T%?:6YD97@],'@E>"P@0T-+ -M7VEN9&5X/3!X)7@*`````"5S*"DZ(%1X4'=R5')A8VMI;F<@9F]R('!A=&@@ -M03H@6"`](#!X)7@L(%D@/2`P>"5X(&5L95]!(#T@,'@E>"!E;&5?0R`](#!X -M)7@@96QE7T0@/2`P>"5X(#!X93DT(#T@,'@E>"`P>&4Y8R`](#!X)7@*```` -M`"5S*"DZ(%1X4'=R5')A8VMI;F<@,'AC.#`@/2`P>"5X+"`P>&,Y-"`](#!X -M)7@@4D8@,'@R-"`](#!X)7@*```E"5X"@`````E"!2871E240] -M)60@3G-C1&]W;CTE9"!.'1E;F0@4E!4(%1I;6EN9PH` -M```E`H`````)7,H*3H@($UA8TE$/25D($1E8VES:6]N4F%T93TP>"5X -M"@``)7,H*3H@36%C240])60@4T=)/25D"@``)7,H*3H@/3T]/3T^"@```"5S -M*"DZ(#T]/3T]/D]$35]205-U<'!O%)05#)(86YD;&5?.#$X.$4H*3H@=F%L:60P/25D('9A;&ED -M,3TE9"!"=69F97),96YG=&@])60*````)7,H*3H@;6%C:60])60@5&]T86P] -M)60@4C`])60@4C$])60@4C(])60@4C,])60@4C0])60@1#`])60@=F%L:60P -M/25X('9A;&ED,3TE>`H`````)7,H*3H@(%1/5$%,/3`A(2$A"@`E"4P-'@@;6EN4G!T5&EM93TP>"4P-'@*`````"5S*"DZ -M("`\/3T]/3UO9&U?4D%4>%)05%1I;65R4V5T=&EN9R@I"@`E"5X(%)A=&5-87-K/3!X)7@@4T=)16YA8FQE/25D"@`` -M)7,H*3H@3T1-7T%21D)2969R97-H7S@Q.#A%*"DZ(%!436]D95-3/25D"@`E -M"!(:6=H97-T4F%T93TE9`H`6T]$ -M32TY,D-=(```6T]$32TY,D1=(```6T]$32TX-S(S05T@`````%M/1$TM.#$X -M.$5=(`````!;3T1-+3@X,3)=(`!;3T1-+3@X,C%=(``E`````` -M"4P,G@)````)7,E,#)8(``E"4P,E@@````"4P,E@`````)7,L`&%B;&5R87<`6V%V86EL86)L92!R87<@ -M"4P,E@@``!B=&9F86ME`&)T8F9A:V4`=VQR9FMM87`` -M````)7,@)3`R6`!#;VUM86YD(&YO="!F;W5N9"$``'=M87``````=W)A=P`` -M``!B='=M87```&)T=V9A:V4`8G1D=6UP9F%K90``=VQD=6UP9F%K90``8G1F -M:S)M87``````=VQF:S)M87``````=VQW9F%K90`\5TE&24!214%,5$5+/@`` -M9&ES86)L925D````=W!S0TT]```*"DT])2XT9``````*"DT],#`P,`````!D -M979./0````H*3CTE7!A9```<&)C`&QA8F5L````;F5G;ST```!I;G1E;G0] -M`'-S:60]````9V]T7W=P"4P,E@``#!X)3`T6```,'@E,#A8``!7 -M15``;F]N90````!42TE0`````$-#35``````245%12`X,#(N,3%B;@```$E% -M144@.#`R+C$Q8@````!)145%(#@P,BXQ,6)G;@``245%12`X,#(N,3%B9P`` -M`$E%144@.#`R+C$Q86X```!)145%(#@P,BXQ,6$`````245%12`X,#(N,3%G -M;@```$E%144@.#`R+C$Q9P````!U;F%S#HE,#)X.B4P,G@Z)3`R>``E*G,@)7,``%53``!%50``2E```$-.``!! -M4U-/0TE.1D\H4F5Q245S/0```"4P,G@`````*0```&EN8VQU9&4O;F5T+V-F -M9S@P,C$Q+F@``"5S"@`E"5X"@``56YS -M=7!P;W)T960@8VEP:&5R.B`P>"5X"@```"5S+"!E7!E/25D -M"@```"5S.G)F7W1Y<&4])60*``!I;F-L=61E+VYE="]C9F3TE<"P@:V5Y7VQE -M;CTE9"P@:V5Y7VED>#TE9`H`8G-S:60])3`R>#HE,#)X.B4P,G@Z)3`R>#HE -M,#)X.B4P,G@*`````"5S+"!F=U]S=&%T93TP>"5X+"!G;W1O(&5X:70*```` -M;6%T8VAE9"!B>2!B"5X"@```$EN=F%L:60@:V5Y(&UG=#H@,'@E>`H``"5S+"!I95]L -M96X])60*``!G;W0@=W!A7VEE"@!G;W0@=W!A,E]I90H`````)7,H*2TE9#H@ -M3TE9`H``"5S+"!S=&%?:6YF;R!I#HE,#)X.B4P,G@Z)3`R>#HE,#)X"@`````M)7,*```` -M`"5S*&YE=&1E=CTE<"DL(&)E86-O;E]H96%D7VQE;CTE9"P@8F5A8V]N7W1A -M:6Q?;&5N/25D"@``861D(&)C;BP@=W!S7VEE;&5N/25D"@``9V]T('`R<%]I -M92P@;&5N/25D"@!%;F%B;&4@4#)0(&9U;F-T:6]N(&9O`H````` -M:V5Y7VQE;CTP>"5X"@```'-E<5]L96X],'@E>`H```!K97E?:6YD97@])60* -M````<&%I7!T+G-E=%]T>"`]/3$@"@```"5S+"!R970])60*`&5R"5X+"!I9G1Y<&4])60*`````"5S+"!O;&1?:69T>7!E/25D -M+"!N97=?:69T>7!E/25D"@```"5S+"!R;VQE/25D+"!P,G!?7!E/25D"@`````E&ES=&5D"@``)7,L(&YD978])7`L('!M;VY?;F1E=CTE<"P@"5X"@`E"P@:7-?1T\*````)7,L(&EE;&5N/25D"@```&EF='EP93TE9"!B969O -M7!E7W9A;&ED/25D"@``)7,L(&9C(#T]($E% -M144X,#(Q,5]35%E015]04D]"15]215-0"@```"5S+"!F#HE -M,#)X.B4P,G@Z)3`R>#HE,#)X.B4P,G@`)7,@&ET7VUO9'5L90!M=C@X=S@V.#9?:69?``"P -ML*Z`W!X``+"PKH!\'P``L+"N@!P@``"PL*Z`O"```+"PKH!H(0``KPBQ@!PC -M``"PL*R`L",``+"PJ(``)```L+"H@`PD``"PL*B`+"0``+"PJ(`X)```L+"H -M@,@D``"PL*B`U"0``+!?@(!8)0``L+"G@-PE``"PL+"`,"8``+"O!(!$)P`` -ML+"P@&PG``"PL+"`C"<``+"PL("L)P``L+"J@-PG``"PL+"`6"@``+"PK(", -M*```L+"J@!PI``"PJPB``"H``+"G`8`L+```L*<#@/@N``"PL*"`)"\``+"P -MH(!0+P``L+"P@&0O``"PJ@.`)#```+"PJH!0,```L+"P@-0P``"PJPB`,#(` -M`+"O$H"$,P``L+"C@#`T``"PL+"`Q#0``+"PHX#8-0``L+"B@)0V``"PL*"` -MP#8``+"PL(#0-@```````%`X``"O/PZ`>#H``+"O*H"P/P``L+"N@-1```"P -MKRJ`S$<``+"PJH!(2```#`````Q)``"O/PR`V$H``+"PJ(#X2@``L+"H@!A+ -M``"PL*B`.$L``+"PJ(!X2P``L+"H@)A+``"PL*B`V$L``+"PJ(#\2P``L+"H -M@!Q,``"PL*B`1$P``+"PJ(!H3```L+"H@)Q,``"PL*B`P$P``+"PJ(#D3``` -ML+"H@`A-``"PL*B`+$T``+"PJ(!030``L+"H@'1-``"PL*B`F$T``+"PL(`( -M3@``L+"P@!Q.``"PL*B`+$X``+"PJH"83@``L*L"@!Q0``"PL*B`B%```+"P -MK(`(40``L+"J@+A1``"PK@&`[%8``+"PJ(`H5P``L+"J@+17``"PL*B`)%@` -M`+"PJH!$60``L+"J@/1:``"PL*J`X%P``+"PJH#,7@``L*`$@$A?``"PL+"` -MP%\``+"PL(`08```L+"H@%A@``"PL*&`I&```+"PL(#88```L+"H@/1@``"P -ML+"`/&$``+"PJH!D80``L+"J@(AA``"PL+"`Z&$``+"PL(!$8@``L+"H@'AB -M``"PJP*`N&,``+"PJH#\8P``L+"J@"QD``"PL*R`S&8``+"PJH"`9P``L*P# -M@.QH``"PK@&`X&D``+"J`X!<:@``L*\$@#!K``"PKP:`L&P``+"I`H`8;0`` -ML*X!@!QN``"PJ@.`F&X``+"O!(!X;P``L*D"@.!O``"PL*R`)'```+"I`H"$ -M<```L*\$@,!Q``"PL*B`9'(``+"PK(!````L+"P@&AX````A`*`X'@``+"PJH"$>0```(0"@+!Y``"P -ML*J`3'H``+"J`8#`>P``L*\0@$Q]``"PL*B`+'\``*\(L8"P@```L*D"@*"! -M``"PL*Z`*(0``+"PJ(",A```L*P!@""%``"PL*B`+(4``+"PJH!(L``+"PJH#`BP``L+"L@!B-``"PL*B`=(T``+"P -MK(#DCP``KPBQ@`B5``"PL*R`7)8``+"H`8`0EP``L*\$@!"9``"PL*B`A)D` -M`+"PJ(#`F0``L*L"@$R<``"PL*R`K)X``+"PJH!LGP``L+"H@'B?``"PL*R` -M^)\``+"PJ(`$H```L+"J@*"@``"PL*B`K*```+"PKH"XH@``L+"J@"2C``"P -ML*J`>*0``+"PJ("8I```L+"H@-"D``"PL*B`W*0``+"PK("PI0``L+"H@+RE -M``"PL+"``*8``+"PL(#TI@``L+"P@/RF``"PL+"`!*<``+"PL(`,IP``L+"P -M@!2G``"PL+"`'*<``+"PK(!\IP``L+"P@(2G``"PL*B`O*<``+"A"X`TJ``` -M`(0"@&RH``"PL+"`H*@``+"PL("HJ````(0"@"2I``"PL+"`.*D``+"PL(!( -MJ0``L+"A@,2I``"PL+"`"*L``+"PL(!\JP``L+"P@(RK``"PL+"`E*L``+"P -ML(".H``+"PJH#$Z@``L*\(@/3N``"PKP2`#/(` -M`+"PJ(#L\@``L+"J@&CS``"PJP*`Z/0``+"N"8`4]P``L*\&@"S[``"PKP:` -M;``!`+"L`8#4``$`L*\0@+`+`0"O"+&`U`P!`+"I`H"4#0$`L*D"@+0.`0"P -ML*J`K`\!`*\$LH!T$P$`L*\&@%P6`0"PK`&`4!H!`+"N`8`@'`$`KC\%@+0> -M`0"O/PB`4"(!`*\_!(!<)0$`KP:R@(`J`0"PL*J`5"L!`*\_!(#$+P$`L+"H -M@-0O`0"PKAV`X#$!`+"I`H`D,P$`KPRR@+`Y`0"PKA&`+#\!`+"PK(#`0`$` -ML+"L@+1!`0"PL*R`J$(!`*\(L8!,1`$`L*\&@+!'`0"O/P"`H%$!`*\(L8"D -M4P$`L*L"@$15`0"PJP*`H%8!`+"K"(`86`$`L+"P@)!8`0"PL+"`W%@!`+"P -ML(#\6`$`L+"J@&Q9`0"PL+"`C%D!`+"PJH#<60$`L+"N@%!:`0``A`*`?%H! -M``"$`H"H6@$``(0"@-Q:`0``A`*`!%L!`+"PJ(`@6P$`L+"H@#Q;`0"PL*J` -MB%L!`+"PL("86P$`L+"P@*!;`0"PL+"`T%L!`+"PL(#T6P$`L+"P@#A<`0"P -ML+"`7%P!``"$`H"$7`$`L+"H@*!<`0"PKP2`Q%T!``"$"(`47@$`L+"P@'1> -M`0"PKP*`[%\!`+"K`H``80$`L*D"@'QA`0"PL+"`&&(!`+"PL(`P9`$`L+"L -M@(1D`0"PL*R`T&0!`+"PL(#D9`$`L+"P@"QE`0"PL+"`9&4!`+"PL("@90$` -ML+"H@+1E`0"PL*B`P&4!`+"PJ(#090$`L+"H@$AF`0"PJ0*`1&`$`L+"H -M@)AY`0"PL*&`-'H!`+"PH8#,>@$`L+"P@!![`0"PL*6`N'L!`+"PH8!,?`$` -ML+"H@*Q]`0"PL*J`)'X!`+"PJH"X?@$`L*P!@.2``0"O"+&`N((!`*\(L8"P -MA`$`L+"J@$R%`0"PL*B`6(4!`*\(L8#$AP$`L+"J@)B(`0"PL*J`^(@!`+"P -MK(#0B0$`L*\"@(B-`0"PL*B`<(X!`+"K!(`HD`$`L+"J@*R0`0"PL*B`))$! -M`+"PJ("`0"O -M"+&`D)X!`+"O`H!(H`$`L+"N@"RA`0"P_82`:*$!`+"PJ("`H0$`L+"H@*BA -M`0"PL*J`Z*$!`+"PK(#PH@$`L+"H@!BC`0"PL+"`(*,!`+"L`8`DI`$``(0" -M@&"D`0"PKP*`E*@'3:`0"PL*B`U-H!`+"PK(#(VP$`L+"H -M@.C;`0"PL*B`.-P!`+"O`H"DW@$`L+"P@.S>`0"PL+"`]-X!`+"PL(#\W@$` -ML+"P@`3?`0"PJ`&`_-\!`+"J`X`8X0$`L*\<@+#C`0"PL*Z`H.@(`7X0"@/1Z`@"P -ML*J`&'L"`+"O#(!8?`(`L+"P@%Q\`@"PH@*`%'T"`+"G"8#\?P(`L+"P@!2` -M`@"PL+"`0(`"`+"PL(!<@`(`L+"P@'B``@"PL*R`T(`"`+"PK(`H@0(`L+"P -M@("!`@``A`*`]($"`+"PK(`X@@(``(0"@+R"`@"PL*J`4(,"`+"PK("4@P(` -ML*\"@-B%`@"PJ@.`*(@"`+"O&H#0B@(`L+"P@%"+`@"PL*B`T(L"`+"PJ(#L -MBP(`L+"L@&"-`@"PJ@&`H(X"`+"PKH`)D"`+"PJ("@F0(`KPBQ@'B;`@"PL*R` -M])L"`%^$!H#TG0(`L*\0@&"B`@"PJP*`K*("`+"I!(`$$#`+"PJ(`@0@,`L+"N@&Q"`P"PL*J`W$(#`+"PK(`D10,`L+"H@'1%`P"P -ML*B`&$8#`+"O*("P50,`L+"N@&!7`P"P#82`Q%X#`+"PJH!(8@,`L-^$@'AP -M`P"P#82`('0#`+`-A(`T?`,`L`V$@)B'`P"O"+&`/(D#`+`-A(#DB@,`L`V$ -M@"2.`P"P#82`A(\#`+"H`8#LCP,`L+"H@`20`P"PL*B`*)`#`+"PJ(`\D`,` -M`(0"@'"0`P"PKRB`J)(#`+"PJ(#,D@,`L*L&@"23`P"PL*J`6),#`+"PJ(#0 -MDP,`L*L&@#B4`P"PJP:`I)0#`+"PJ(#$@!"C`P"PKPZ` -MY*<#`+"PKH#@J@,`L/>$@"2L`P"PK`&`5*X#`+"PKH#8KP,`L*X!@"BQ`P"P -ML*Z`<+(#`+`]A("@LP,`WX0!@"2U`P"PK@&`9+8#`+"O`H`HN@,`L*\$@+"^ -M`P"PKP*`I,8#`+"O`H!0V`,`KPBQ@%C@`P"O"+&`@.$#`*\(L8"HX@,`L*\F -M@,SQ`P"PKSR`5/X#`+`-A(!H_P,`L*\@@+`1!`"PL*R`+!,$`+"K`H"(%`0` -ML+"J@&P5!`"PL*J`2!8$``"$`H#T%@0`L*H!@.`7!`"PJ@&`S!@$`+"PH8"H -M&00`L+"N@!0;!`"PKP:`Y"\$`+`WA(#L,`0`L+"N@/PQ!`"PL*Z`##,$`+"P -MK(`<-`0`L+"L@!PU!`"P#82`!#8$`+"O#H#$/P0`L+"H@-@_!`#?A`&`($4$ -M`+"PL(`D100`L+"P@$!%!`"PL+"`2$4$`+"PL(!,100`L`V$@#Q&!`"PKPB` -M'$X$`+"PK(!H3P0`L+"L@!A2!`"PL*R`"%0$`+`-A(!\500`L`V$@/Q6!`"P -MKP*`'%@$`+"PL(`H6`0`L+"P@#18!`"PL+"`2%@$`+"PL(!@6`0`L+"P@'18 -M!`"PL+"`A%@$`+"PL("(6`0`L+"P@(Q8!`"PL+"`D%@$`+"PL("46`0`L+"P -M@+!8!`"PL+"`S%@$`+"PJ(#86`0`L+"H@.18!`"PL+"`]%@$`+"PL(`$600` -ML+"P@"!9!`"PL+"`3%D$`+"PL(!L600`L+"P@'19!`"PL+"`?%D$`+"PL("4 -M600`L+"P@*Q9!`"PL+"`Q%D$`+"PL(#<600`L+"P@/A9!`"PL+"`%%H$`+"P -ML(`P6@0`L+"P@$Q:!`"PL*R`U%H$`+"PJ(#L6@0`L+"H@`1;!`"PL*J`-%L$ -M`+"PJ(!D6P0`L+"H@'A;!`"PK@&`:%P$`+"L`8#L7`0`L*H!@&Q=!`"PL*B` -MN%T$`+"PJ(`$7@0`L+"H@%!>!`"PL*B`<%X$`+"PJ(!\7@0`L+"H@(A>!`"P -ML*J`L%X$`+"PJ(#<7@0`L+"H@.A>!`"PL*B`,%\$`+"PJ(!@7P0`L+"H@)!? -M!`"PL*B`K%\$`+"PJ(#`7P0`L+"H@,Q?!`"PL*B`X%\$`+"PJ(#T7P0`L+"H -M@`!@!`"PL*J`Y&`$`+"PJ(#P8`0`L+"H@`AA!`"PL*B`&&$$`+"PJH!(800` -ML+"L@*1A!`"PL*B`L&$$`+"PJ(#8800`L+"H@.1A!`"PL*J`%&($`+"PK("$ -M8@0`L+"P@/1B!`"PL*B`1&,$`+"PJ("88P0`L+"J@%1D!`"PL*B`&&4$`+"P -MJH!<900`L+"J@&!F!`"PL*B`P&8$`+"PJH"T9P0`L+"J@*AH!`"PL*B`W&@$ -M`+"PJ(`@:00`L+"J@/AK!`"PL*B`1&P$`+"PJ(!X;`0`L+"L@%AO!`"PL*B` -M"'$$`+"PJ(`D<00`L+"H@$!Q!`"PL*B`>'$$`+"PJ("$<00`L+"H@`AR!`"P -ML*J`:',$`+"PK("D=`0`L+"H@,QT!`"PL*B`)'4$`+"PJ(`P=00`L+"J@-AU -M!`"PL*B`/'8$`+"PJH!$=P0`L+"J@+!X!`"PL*B`X'@$`+"PJ(#L>`0`L+"N -M@%![!`"PL*B`B'L$`+"PK(#`&+L$`+"PKH#(O@0`L+"N@`S`!`"PL*J`(,$$`+"O!(`XQ00` -ML+"H@%#%!`"PK`&`^,8$`+"J!X!,R`0`L*L"@(#)!`"O"+&`P,H$`+"PJH`T -MRP0`KT2R@,C6!`"PKP:`--@$`+"PJ(",V`0`L*L$@"#9!`"PJ02`>-D$`+"I -M!(#0V00`L*D$@!#:!`"O"+&`[-H$`+"PJ(`8VP0`L*\$@-3J!`"PL*B`K.L$ -M`+"L`8!,[00`7X0*@`3O!`"O/Q*`W/$$`+"O$H!4]@0`L+"N@(#W!`"PL*J` -M(/@$`+"PL(`X^`0`L+"P@%CX!`"PL+"`:/@$`+"PL(!L^`0`L*\"@.CY!``] -MA`&`_/H$`+"PJ("`^P0`L+"H@-C[!`"PL*B`_/L$`+"PK(!(_`0`L+"L@,#\ -M!`"PL*J`'/T$`+"I!("0_00`L*D$@`3^!`"PL*B`:/X$`+"PJ("0_@0`L+"H -M@`3_!`"PL*B`$/\$`+"PJ(`<_P0`L+"H@"C_!`"PKP*`,``%`+"N`X`\`04` -ML+"H@&P!!0"PL*B`P`$%`+"PJ(```@4`L+"H@"@"!0"PL*B`-`(%`+"PJ(!` -M`@4`L+"P@$@"!0"PL+"`7`(%`+"PL(!@`@4`L+"P@&0"!0"PL*B`C`(%`+"P -MJ("8`@4`L+"J@.P"!0"PL*Z`>`0%`+"J#8#````.`5``!\````]!4``(`````(%@``A````!P6``"(```` -M,!8``(P```!$%@``(@```#(4```F````1A0``"H```!:%```+@```&X4``"X -M````.!,``+P```!,$P``P````&`3``#$````=!,``-````"P$P``U````,03 -M``#8````V!,``*JJ`P``````@3<``(#S``"JJ@,``/@`````^``3````I)X" -M`!,```!T7@(`$P```*0.`@`3````T,X!`!,```!`GP$`$P```'!.`0`3```` -MH`8!`!,```!PQ@``$P```*""```3````<$(``!,```!``@``*Z1>`"ND7@`K -MI%X`3Z0``$^D7@`<0UX`*Z1>`"ND7@`KI%X`*Z->`"ND7@`B0UX`(J1>`$^D -M``!/I```(J->`#"F``!/I```(D->`")#7@`B0UX`3Z1>`$^D```KI%X`*Z1> -M`"ND7@`KI%X`*Z1>`#"F```<0UX````````````````````````````````` -M```````````````````````````````````````````````````````````` -M````_@&`?^(!@'C'`````!P4````````( -M!0``*P````D%``"D````"@4``%X````+!0````````P%``!/````#04``*0` -M```.!0````````\%````````$@4``!P````4!0``"@```!8%```*````)04` -M`$\```!0!0``$````%$%```0````604```(```!=!0``_P````4&```P```` -M"`8```X````)!@``*@```"`&``#_````(08``/\````B!@``_P```",&``#_ -M````)`8``/\````E!@``_P```"8&``#_````)P8``/\```!2!@``(````#P& -M```*````/08```X````^!@``"@```#\&```.````0`8``$````!N!@``!0`` -M```'```A`````0<``$,````"!P``90````,'``"'````"`<``"$````)!P`` -M0P````H'``!E````"P<``(<````P#```2JSI:3P,```8EY<*``@`````!(`$ -M"````P````@(````_```#`@```H````0"```,1,`$!0(```0/0P"&`@``(4# -M(`(<"````````"`(`````0`!)`@```0".0`H"````````"P(````````,`@` -M```````T"````````#@(````````/`@```````!`"``````!`$0(```````` -M2`@```````!,"````````%`(````````5`@```````!8"```J1&:5EP(```4 -M```!8`@``!`!]F9D"```008?!F@(````````;`@````G)R=P"```8`<`!W0( -M````0``E>`@```@(``!\"````````(`(```<#`"PA`@```$```"("``````` -M`(P(``#``,#,D`@````(``"4"```_O___Y@(```0(#!`G`@``%!@<```"0`` -M``````0)```C````"`D````````,"0``$1$2@1`)```"````%`D````!```` -M"@``R$?0``0*```,`/^`"`H```"#@XP,"@``#Q)_+A`*``!XNP"5%`H``"C0 -M%!$8"@``%Q&(`!P*````#Q2)(`H`````&QHD"@``%Q,."2@*```$`@``+`H` -M````TP!P"@```+\?$'0*```'````>`H````)``!\"@``!@9;(H`*``"Q=8`A -M+`L``````(``#```0!T'2`0,```15J`#"`P``.0````,#```;&QL;!`,```` -M`(`(%`P````!`$`8#`````"`"!P,`````0!`(`P````````D#````````"@, -M````````+`P````````P#```1ZSI:30,``"O4I9&.`P``)19>4D\#```')>7 -M"D`,```_0'P?1`P``+<``0!(#```!P$"[$P,``!_`W\`4`P``"`T56E4#``` -ME`"\0U@,``!I,0$`7`P``)($)0!@#````````&0,``"+A!)Q:`P``/\+P$=L -M#```-@```'`,```-`'\L=`P``-L0!@)X#```'P```'P,```2%KD`@`P````! -M`$"$#`````#V((@,`````0!`C`P`````(""0#```(14)`)0,````````F`P` -M`"`8$@"<#```?W\``*`,````````I`P``*```P"H#````````*P,```````` -ML`P```````"T#````````+@,````````O`P``````"C`#````````,0,```` -M````R`P```````#,#````````-`,````````U`P```````#8#```)R2R9-P, -M```R:78`X`P``"(B(@#D#````````.@,```"0V0W[`P```S4ER\`#0``0`<` -M``0-```!!`(`"`T``'^0```,#0```0(!(!`-```S,V.@%`T``$.\,S,8#0`` -M;UN/>BP-``!UF9?,,`T````````T#0```(!@@#@-````````/`T``%-S$@!` -M#0```````$0-````````2`T```````!,#0```````%`-```*%#=D5`T````` -M``!8#0``@@(``%P-``!D(`,P8`T``&C>4T9D#0``/(I1!&@-```!(0``;`T` -M`!8<("IP#0``+C82&'0-```@(BPR>`T``"0\#@``#@``+2TM+00.```M+2TM -M"`X``"TGD`,0#@``+2TM+10.```M+2TM&`X``"TM+2T<#@``+2TM+2@.```` -M````,`X``!_<`!`T#@``'XP`$#@.```"`10"/`X``,($%FA`#@```'P``40. -M````2``!2`X``````/M,#@``T2@``%`.```?W``05`X``!^,`!!8#@```@$4 -M`EP.```%#18H8`X```@```!H#@``I"4;`&P.```4`,``<`X``!0`P`!T#@`` -M%````7@.```4```!?`X``!0```&`#@``%````80.```4`,``B`X``!0```&, -M#@``%`#``-`.```4`,``U`X``!0`P`#8#@``%`#``-P.```4````X`X``!0` -M``#L#@``%`#``4P/``````````\````#``!X#````0``^W@,```!``'[>`P` -M``$``OMX#````0`#^W@,```!``3[>`P```$`!?MX#````0`&^G@,```!``?Y -M>`P```$`"/AX#````0`)]W@,```!``KV>`P```$`"_5X#````0`,]'@,```! -M``WS>`P```$`#O)X#````0`/\7@,```!`!#P>`P```$`$>]X#````0`2[G@, -M```!`!/M>`P```$`%.QX#````0`5ZW@,```!`!;J>`P```$`%^EX#````0`8 -MZ'@,```!`!GG>`P```$`&N9X#````0`;Y7@,```!`!SD>`P```$`'>-X#``` -M`0`>XG@,```!`!_A>`P```$`((IX#````0`AB7@,```!`"*(>`P```$`(X=X -M#````0`DAG@,```!`"6%>`P```$`)H1X#````0`G@W@,```!`"B">`P```$` -M*6MX#````0`J:G@,```!`"MI>`P```$`+&AX#````0`M9W@,```!`"YF>`P` -M``$`+V5X#````0`P9'@,```!`#%C>`P```$`,F)X#````0`S87@,```!`#1& -M>`P```$`-45X#````0`V1'@,```!`#=#>`P```$`.$)X#````0`Y07@,```! -M`#I`>`P```$`.T!X#````0`\0'@,```!`#U`>`P```$`/D!X#````0`_0'@, -M```!`$#[>`P```$`0?MX#````0!"^W@,```!`$/[>`P```$`1/MX#````0!% -M^W@,```!`$;[>`P```$`1_MX#````0!(^W@,```!`$GZ>`P```$`2OEX#``` -M`0!+^'@,```!`$SW>`P```$`3?9X#````0!.]7@,```!`$_T>`P```$`4/-X -M#````0!1\G@,```!`%+Q>`P```$`4_!X#````0!4[W@,```!`%7N>`P```$` -M5NUX#````0!7['@,```!`%CK>`P```$`6>IX#````0!:Z7@,```!`%OH>`P` -M``$`7.=X#````0!=YG@,```!`%[E>`P```$`7^1X#````0!@XW@,```!`&'B -M>`P```$`8L-X#````0!CPG@,```!`&3!>`P```$`98MX#````0!FBG@,```! -M`&>)>`P```$`:(AX#````0!IAW@,```!`&J&>`P```$`:X5X#````0!LA'@, -M```!`&UG>`P```$`;F9X#````0!O97@,```!`'!D>`P```$`<6-X#````0!R -M8G@,```!`'-A>`P```$`=&!X#````0!U1G@,```!`'9%>`P```$`=T1X#``` -M`0!X0W@,```!`'E">`P```$`>D%X#````0![0'@,```!`'Q`>`P```$`?4!X -M#````0!^0'@,```!`']``````````P`(`````$`(`!@````'!```&0```!(` -M```>````"0`(`!\```"`"```+P```&"@`0`_`````````$(```#`8```5P`` -M````#0!8````@.$+`&<```!2%0``@P````````"P````_/@/`+$`````1`4` -ML@```!G,#`"T`````S`$`+8````^E00`MP```!C'`0"X````_V```+D````! -M``@`N@``````!`"[``````0``+\```````P`P@`````D``##````"0```,0` -M``"1#`0`Q0```)F9"0#&````HP```,<````@B`@`R`````9L!P#)```````` -M`,H```````@`WP```(`!``#O````H`$``%$```!]L@8`'P0/_\VK``!2```` -MW>0'`,W-S````````````!X``````````````````````````0```/05?``````` -M`````!X``````````````````````````0````@6@````````````!X````` -M`````````````````````0```!P6A````````````!X````````````````` -M`````````0```#`6B````````````!X``````````````````````````0`` -M`$06C````````````!X``````````````````````````0```'$6E0`````` -M`````!X``````````````````````````0```(46F0```````````!X````` -M`````````````````````0```)D6G0```````````!X````````````````` -M`````````0```*T6H0```````````!X``````````````````````````0`` -M`,$6I0```````````!X``````````````````````````0```"`7N``````` -M`````!X``````````````````````````0```#07O````````````!X````` -M`````````````````````0```$@7P````````````!X````````````````` -M`````````0```%P7Q````````````!X``````````````````````````0`` -M`'`7R````````````!X``````````````````````````0```(07S``````` -M`````!X``````````````````````````0```)@7T````````````!X````` -M`````````````````````0```*P7U````````````!X````````````````` -M`````````0```,`7V````````````!X`````````````````````````;#X` -M`'0^``!\/@``B#X``)@^``"@/@``K#X``+P^``#,/@``W#X``.P^````/P`` -M$#\``!P_```L/P``/#\``$@_``!0/P``6#\``&`_``!L/P``>#\``(0_``"8 -M/P``H#\`````````1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N -M,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H -M1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N -M,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H -M1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N -M,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H -M1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N -M,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H -M1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N -M,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H -M1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N -M,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H -M1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N -M,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H -M1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N -M,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H -M1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N -M,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H -M1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N -M,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H -M1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N -M,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H -M1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N,P``1T-#.B`H1TY5*2`T+C0N -M,P``1T-#.B`H1TY5*2`T+C0N,P!!*@```&%E86)I``$@````!36UT86(`+G-T&ET7VUO9'5L90`N'1A8@`N&ED>``N0P` -MB`(``!RL#@",`@``'/\+`,@"```<*0L`W`(``!RW#`#L`@``'+`,`/@"```< -MI`L```,``!S_"P`H`P``'$\*`$P#```0P`*`4``"NM#0`L!0``+*T-`#P%```<>0P`1`4``!QG -M"P!0!0``'"H.`(0%```"`0``B`4```(!``",!0```@$``)`%```"`0``E`4` -M``(!``"8!0```@$``*0%```<30T`K`4``!Q-#0#L!0``'$T-``P&```<7PP` -M'`8``!Q-#0`D!@``'$T-`#@&```<+`L`[`8``!PY"@#X!@``'$T-``0'```< -M30T`A`<```(!``"(!P```@$``(P'```"`0``D`<```(!``"4!P```@$``)@' -M```"`0``G`<```(!``"@!P```@$``*0'```"`0``J`<```(!``"L!P```@$` -M`+`'```"`0``P`<``!SI"@#4!P``'`0,`.0'```#`!X"P``'*`-`(0+```<9PL`D`L``!P3#@"<"P``'.\.`-@+ -M```PT`^`P``!PJ#0`0#0`` -M'&4,`"P-```<90P`1`T``!P^"@!H#0``''L-`)0-```<*@T`K`T``!QE#`#( -M#0``'&4,`.`-````X``!QE -M#`"0#@``'#X*`+`.```<>PT`W`X``!PJ#0`T#P``'&4,`%`/```<90P`:`\` -M`!P^"@"(#P``''L-`+0/```<*@T`R`\``!QA#0#H#P``'&4,``00```<90P` -M'!```!P^"@`\$```''L-`&`0```<*@T`A!```!QE#`"@$```'&4,`+@0```< -M/@H`V!```!Q[#0`$$0``'"H-`!`1```PT`.!(``!PJ#0!D$@``'&4,`(02```<90P`F!(``!P^"@"H$@`` -M''L-`-@2```<*@T`[!(``!S_"@``$P``'#X*`"@3```<90P`1!,``!QE#`!< -M$P``'#X*`(`3```<>PT`K!,``!PJ#0#,$P``'&4,`.@3```<90P``!0``!P^ -M"@`8%```'(`*`"`4```<>PT`4!0``!PJ#0!L%```'&4,`(@4```<90P`I!0` -M`!P^"@"T%```'&4,`,@4```PT` -MX!D``!PJ#0`<&@``'&4,`&@:```PT`"!P``!PJ#0`L'```'&4,`#P<```<>PT`9!P``!PJ#0"4'```'&4, -M`*0<```<>PT`!!T``!PJ#0`D'0``'&4,`$`=```<90P`7!T``!P^"@!L'0`` -M''L-`)P=```<*@T`O!T``!QE#`#8'0``'&4,`/0=``````<90P`=!X``!QE#`"0'@``'#X*`*`>```<>PT`T!X``!PJ -M#0#P'@``'&4,``P?```<90P`*!\``!P^"@`X'P``''L-`'`?```<*@T`D!\` -M`!QE#`"L'P``'&4,`,@?```PT`H"```!R`"@"P(```'"H-`,P@```< -M90P`Z"```!QE#``$(0``'#X*`!0A```<>PT`3"$``!R`"@!<(0``'"H-`(`A -M```<10L`D"$``!S,#`"8(0``'&4,`+`A```<90P`S"$``!P^"@#@(0``'(0. -M`.@A```<>PT`)"(``!RI"@!<(@``'(`*`*0B```<*@T`M"(``!Q?#`"\(@`` -M*ZT-`,`B```LK0T`U"(``!QY#``L(P``'&4,`$@C```<90P`8",``!P^"@!T -M(P``''L-`*0C```<*@T`P",``!Q_"@#((P``'&4-`-`C```<90T`Y",``!P^ -M"@#X(P``'#X*``0D```"@``!P-"@"<*```'`T*`*@H```<#0H`M"@``!P-"@#`*```'`T*`,PH -M```<#0H`Z"@``!P-"@!4*0``'%L.`'@I```<3@H`E"D``!Q."@"H*0``'$X* -M`,0I```<3@H`V"D``!Q."@#H*0``'$X*`/0I```<2`P`6"H``"MT``!<*@`` -M+'0``&PL```K=```<"P``"QT``!0+P``*W0``%0O```L=```(#````("```$ -M-P``'"D+`)0X```<*0L`I#H``!RI"@"T.@``'*D*`,0Z```$X``!R;#0"03@``'/L)`/Q.```%4``!R`"@"050``'(`*`*A5```<@`H`P%4``!R`"@#X50``'"<-`!16```< -M*0L`-%8``!RI"@!(5@``'(`*`'A6```<@`H`B%8``!R`"@"<5@``'(`*`*Q6 -M```<@`H`Q%8``!Q4#``45P``'-T+`%Q7```<_PL`A%<``!R_"@"85P``'(P+ -M`+Q7```<_PL`Z%<``!PS"@#P5P``')P+`/Q7``````<@`H`D%X``!PU#0"X7@`` -M'(P+`-A>```KT```W%X``"S0```@8```'"H,`#1@```<1PH`1&```!PJ#`#L -M8```''X-`"QB```KT```,&(``"S0``!L8@``'(`*`(AB```K:@X`C&(``"QJ -M#@"L8@``'+8.`-!B```<@`H`Y&(``!R`"@"L8P``'(`*`.!C```<@`H`%&0` -M`!R`"@!(9```'*D*`.!F```0``'(`*`)!Y```<_`P` -MH'D``!R`"@#P>0``'"D+`$1Z```<#PH`['H``!Q^#0`X>P``''X-`-A[```K -M&P$`W'L``"P;`0`0P`3)(``!RY"P!< -MD@``'#X+`(B2````P` -MF)0``"NM#0"0P`Q)0``"NM#0#(E```+*T-`-B4```< -M>0P``)4``!R,"P`LE0``'"D+`#25```<_PL`6)4``!P\"@!HE0``'(P+`'R5 -M```<"@L`A)4``!SK#0",E0``'/\+`+"5```)D``!R,"P",F0``'%\,`-R9```<*0L`))H` -M`!SB#``TF@``'/0,`#B:```<_PL`E)H``!RR#`"0P`8)T``!RI"@!P -MG0``'(`*`'B=```<*0T`@)T``!PE#`"0G0``'!@*`*R=```<"PH`N)T``"NM -M#0"\G0``+*T-`-2=```<>0P`])T``!RP#``HG@``'+\*`$R>`````````<)0L` -MS)X``!Q?#``0GP``'/\+`$B?```#0!,H@``'%\,`+"B````H`&+<``!R`"@!`MP``'(`*`,"W```PT`J,```!PJ#0#@ -MP```'%(*`/C````<*0L`.,$``!R"#0!4P0``'%(*`'C!```<@@T`\,$``!R" -M#0`LP@``'*P.`#C"```PT`N,8``!SK"0#,Q@``'(`*`-S&```<@`H`[,8``!PJ -M#0`$QP``'&4,`!S'```<90P`,,<``!P^"@`\QP``''L-`'C'```-<``!SZ"@",UP``'/H*`*#7 -M```<'0P`L-<``!P=#`#,UP``'/H-`.C7```<.`H`#-@``!P<#@`"@!8VP``'+X+`'S;``````<@`H`U-X``!P""P", -MWP``'*P.`)3?```<(@P`I-\```(-``#`WP``'%<*`-3?```<2@T`".```!RI -M"@#,X```'(`*`.#@```<@`H`[.```!P0"@#\X```'(`*`$CA```<-@P`:.$` -M`!Q7"@!\X0``'$H-`)3A```0P``/,``!RL#@`X -M\P``'/H-`$CS```<*0H`3/,``"NM#0!0\P``+*T-`&#S```<>0P`N/,``!P" -M"P`0]```*ZT-`!3T```LK0T`)/0``!QY#`!4]```''X-`'#T```<@`H`B/0` -M`!PI"@",]```*ZT-`)#T```LK0T`I/0``!QY#`#(]```'#4*`"#U```<5PH` -M-/4``!Q*#0!$]0``'*D*`'SU```<$`H`C/4``!R`"@"4]0``'!`*`*3U```< -M@`H`O/4``!R`"@#,]0``'(`*`-SU```<@`H`3/8``!RT"@!@]@``'`T.`(SV -M````$!`!Q]#0"T`0$`''X-`-@!`0`0P`#!D!`"NM#0`0&0$`+*T-`"09`0`<>0P` -MA!D!`!SF#`"<&0$`'.8,`,P9`0`<+PT`]!D!`!SE#`#\&0$`'"\+`!`:`0`< -MN@X`&!H!`!S(#`#8&@$`'(`*``0;`0`<+PL`(!L!`!RZ#@`L&P$`'+H.`#`; -M`0`KK0T`-!L!`"RM#0!(&P$`''D,`&0;`0`<.`X`=!L!`!Q^"@"0&P$`''0+ -M`*@;`0`<=`L`X!L!`!PO#0`,'`$`'`4+`!P<`0`"`P``9!P!`!Q"#0!P'`$` -M'%<*`(0<`0`<2@T`E!P!`!RI"@"X'`$`'(`*`,P<`0`<@`H`W!P!`!R`"@`X -M'0$`'$@-`$P=`0`<2`T`7!T!`!Q(#0!P'0$`'$@-`(0=`0`<2`T`E!X!`!RT -M"@"H'@$`'#8,`/0>`0`<0@T`!!\!`!Q7"@`8'P$`'$H-`"@?`0`#`!`!R`"@",,`$`'(`*`)PP`0`<@`H`]#`!`!Q(#0`$,0$`'$@-`!0Q`0`< -M2`T`)#$!`!Q(#0`T,0$`'$@-`%@Q`0`0P`=#P!`!S& -M#`"0/`$`'+\+`.@\`0`<<0T`_#P!`!R`"@`L/0$`'$P-`$P]`0`<)0H`<#T! -M`!R_"P"0/0$`''$-`!P^`0`<`0P`-#X!`!Q`#0!,/@$`'(T+`&`^`0`<@`H` -MH#X!`"NM#0"D/@$`+*T-`+@^`0`<>0P`T#X!`!RL#@#T/@$`'`H*`/@^`0`K -MK0T`_#X!`"RM#0`,/P$`''D,`"0_`0`"`P``*#\!``*M#0!,/P$`'`(+`(`_ -M`0`<*0L`U#\!`!R`"@#D/P$`'$P+``1``0`&,!``(!``!\8P$``@$``(!C`0`"`0``A&,!``(!``"(8P$``@$` -M`(QC`0`"`0``D&,!``(!``"48P$``@$``)AC`0`"`0``G&,!``(!``"@8P$` -M`@$``*1C`0`"`0``J&,!``(!``"L8P$``@$``+!C`0`"`0``M&,!``(!``"X -M8P$``@$``+QC`0`"`0``P&,!``(!``#$8P$``@$``,AC`0`"`0``S&,!``(! -M``!H9`$`'%@-`+1D`0`<6`T`N&4!`!R,#0#(90$`'%,-`!QF`0`0P`Y'`$`''T,`&1X`0`<$PX` -ME'@!`!P,#@#4>`$`'(H+`.QX`0`<\0X`D'D!`!RC"P"<>0$`*V,"`*!Y`0`L -M8P(`N'D!`"MC`@"\>0$`+&,"`.1Y`0`K8P(`Z'D!`"QC`@#\>0$`*V,"``!Z -M`0`L8P(`.'H!`"MC`@`\>@$`+&,"`%1Z`0`K8P(`6'H!`"QC`@"`>@$`*V," -M`(1Z`0`L8P(`F'H!`"MC`@"<>@$`+&,"`'!]`0`KK0T`='T!`"RM#0"D?0$` -M''D,`/!]`0`#0`T?@$`'/\+`&Q^`0`($!`!P""P"4@0$`*W$"`)B!`0`L<0(` -MH($!`!P""P"P@0$`*W$"`+2!`0`L<0(`O($!`!P""P#4@0$`'`(+`.R!`0`< -MZPT``((!`!PI"P`X@@$`'(`*`$R"`0`<@`H`8((!`!R`"@!P@@$`'(`*`("" -M`0`<@`H`D((!`!R`"@"<@@$`'"D+``"#`0`<`@L`&(,!`!P""P`T@P$`*W$" -M`#B#`0`L<0(`0(,!`!P""P!0@P$`*W$"`%2#`0`L<0(`7(,!`!P""P!T@P$` -M'`(+`*"#`0`<`@L`Z(,!`!P""P`@A`$`'(`*`#2$`0`<@`H`1(0!`!R`"@!4 -MA`$`'(`*`&2$`0`<@`H`?(0!`!SK#0"0A`$`'"D+`+B$`0`<_PL`V(0!`!R! -M#`!`A0$`'(P+`%"%`0`<9@L`C(4!`!P""P"XA0$`'"D+`'R&`0`<_PL`I(8! -M`!R^"P`,AP$`'#D-`$2'`0`<^@H`G()0!`"QN`@"LE`$`'`(+`-R4`0`<`@L`\)0!`!Q9#`#\ -ME`$`')8,``B5`0`<@`H`%)4!`!R6#``@E0$`'(`*`$25`0`0P`Q)0P`,)D!`!R,"P!4F0$` -M'(P+`%R9`0``0`<`PH`1)X!`!PI"P!TG@$`'!L*`(2> -M`0`<]`D`Q)\!`!RT"P#8GP$`'-$.`!"@`0`"P#$H@$`'.X-`-"B`0`KK0T` -MU*(!`"RM#0#DH@$`''D,``"C`0`PT`P*D!`!Q[#0#(J0$`'!D,`-BI`0`PT`1*H!`!S_"P!DJ@$`'($,`(BJ`0`*L!`!R` -M"@"0JP$`',<+`-"K`0`<&0P`W*L!`!Q'#0`TK`$`'+<,`%"L`0`"`@``9*P! -M`!Q#"P"(K`$`'!D,`)"L`0`PT``*T!`!Q[#0`,K0$`'#T*`!2M`0`< -M/0H`T*X!`!S_"P#0KP$`'#D-`!"P`0`<^@H`'+`!`!R^"P!`L`$`'(P+`%BP -M`0`<_PL`;+$!`!R,"P"4L0$`'#D-`)BQ`0`<_PL`^+$!`!R^"P`#0"0 -MM`$`'/H*`+"T`0`#0`@OP$`')X-`%"_ -M`0`"`P``6+\!`!QR#@!4P`$`'/\+`+3``0`PT`V-L!`!P9#`#XVP$`'*D*``#<`0`PT`>-T!`!S*"@"0W0$`')X-`+#=`0`<&0P`N-T!`!Q#"P#TW0$`''L-`!#> -M`0`#0!`W@$`'+P+`$S>`0`<[0X`8-X!`!Q_"P`.!`"`!SR"@"$$`(` -M'/\+`*P0`@``@`< -M\@H`0!\"`!P`#0!8'P(`'/(*`'@?`@`<``T``"`"`!SR"@`\(`(`'``-`%0@ -M`@`<.PH`>"`"`!QC"@"P(`(`'/(*`-@@`@`<\PP`Z"`"`!P`#0`$(0(`'/(* -M`"@A`@`<5`T`0"$"`!SR"@!0(0(`'/(*`*0A`@`<\PP`5"("`!P`#0"D(@(` -M'``-`-0B`@`K/@,`V"("`"P^`P#<(@(`*S\#`.`B`@`L/P,`["("`!P`#0`$ -M(P(`'/(*`#`C`@`<``T`I","`!P`#0#`(P(`'/(*`/0C`@`<5`T`#"0"`!SR -M"@`<)`(`'/(*`%0D`@`K/0,`6"0"`"P]`P"$)`(`*ST#`(@D`@`L/0,`N"0" -M`!P`#0``)0(`'/,,`)@E`@`<\@H`U"4"`!SR"@`0)@(`'/(*`$PF`@`<\@H` -MB"8"`!SR"@#8)@(``@,``-PF`@`"`P``X"8"``("``#D)@(``@,``.@F`@`" -M`P``["8"``(#``#P)@(``@,``/0F`@`"`P``^"8"``(#``#\)@(``@,````G -M`@`"`P``!"<"``(#```()P(``@,```PG`@`"`P``$"<"``(#```4)P(``@(` -M`#@G`@`<80H`4"<"`!P)"P#,)P(`'%D,`.0G`@`<_PL`,"@"`!SS#`!,*`(` -M'/(*`&@H`@``P!P+@(`+%X#`(`N`@`<@@X`["X"`!R"#@`<+P(`'!D. -M`$`O`@`<@@X`4"\"`!S?"P!D+P(`'((.`)PO`@`<&0X`P"\"`!R"#@#@+P(` -M'"T+`/`O`@`<@@X`,#`"`!P9#@!4,`(`'((.`'0P`@`<+0L`A#`"`!R"#@#` -M,`(`'((.`-@P`@`<&0X`]#`"`!PM"P`$,0(`'((.`,@Q`@`K4`,`S#$"`"Q0 -M`P#<,0(`'*D*`/`Q`@`#D"`!R"#`"8.0(`',\-`,`Y`@`#X"``(!``!\/@(``@$``(`^`@`"`0``A#X"``(!``"( -M/@(``@$``(P^`@`"`0``D#X"``(!``"4/@(``@$``)@^`@`"`0``G#X"``(! -M``"@/@(``@$``*0^`@`"`0``J#X"``(!``"L/@(``@$``+`^`@`"`0``M#X" -M``(!``"X/@(``@$``+P^`@`"`0``P#X"``(!``#$/@(``@$``,@^`@`"`0`` -MS#X"``(!``#0/@(``@$``-0^`@`"`0``V#X"``(!``#%4"`!P9#@"(50(` -M'-\+`*A5`@``@`@H`B&`"`!S5#`"4 -M8`(`''H*`+1@`@`0H`G&L" -M`!QY"@#(;P(`'+$+`.1O`@`<&@T`\&\"`!SP#@`(<`(`'(4.`#!P`@`'$"`!P@"P"8<0(`'"`+`#QR`@``(`'`(*`&QX`@`<`@H`B'@"`!P@"P"0>`(`'/$-`*AX`@`< -M(`L`L'@"`!SQ#0"X>`(`'/$-`-AX`@`<(`L`X'@"`!SQ#0`(>0(`'"`+`!!Y -M`@`<\0T`&'D"`!SQ#0`H>0(`'`(*`$!Y`@`<`@H`<'D"`!P""@"8>0(`'`(* -M`!!Z`@`<(`L`>'H"`!SO"@#,>@(`'!@,`)![`@`"`0``E'L"``(!``"8>P(` -M`@$``)Q[`@`"`0``O'L"`!P*#@#(>P(`'-(+`/A[`@`<&`P``'P"`!Q5"@`4 -M?`(`'&(*`"!\`@`<50H`5'P"``("``!X?0(``@$``'Q]`@`"`0``@'T"``(! -M``"$?0(``@$``/Q_`@`K_P,``(`"`"S_`P`4@`(`*_\#`!B``@`L_P,`0(`" -M`"O_`P!$@`(`+/\#`%R``@`K_P,`8(`"`"S_`P"L@`(`'.H+``2!`@`<``L` -M+($"`"O_`P`P@0(`+/\#`(B!`@`K_P,`C($"`"S_`P"H@0(`*_\#`*R!`@`L -M_P,`R($"`"O_`P#,@0(`+/\#`.B!`@`<&`P`%(("`!PP"@"`@@(`'!@,`+"" -M`@`<&`P`R(("`"O_`P#,@@(`+/\#`/B"`@`<8@H`_(("`"O_`P``@P(`+/\# -M`!B#`@`K_P,`'(,"`"S_`P`T@P(`*_\#`#B#`@`L_P,`<(,"`!S<"P`$A`(` -M`@$```B$`@`"`0``#(0"``(!```0A`(``@$``"R$`@`<`@H`4(0"`!P""@!X -MA`(`'"`+`("$`@`<\0T`E(0"`!P@"P"(4"`!P@"P"@A0(`'"`+`'2'`@`<``H` -MV(<"`!P@"P#PAP(`'"`+``2(`@`<(`L`'(@"`!P@"P!`@`<#PT`<)X"`!P/#0"4 -MG@(`'((,`-">`@`*@"`"O8#0"`J`(`+-@-`(BH`@`K=0L`D*@"`"QU"P"8J`(`*]D.`*"H`@`L -MV0X`J*@"`"L"#@"PJ`(`+`(.`+BH`@`K'`T`P*@"`"P<#0#(J`(`*U8,`-"H -M`@`L5@P`V*@"`"M+#0#@J`(`+$L-`.BH`@`K100`\*@"`"Q%!```J0(`'!T. -M`/2I`@`"@`@L@(`'%H,`$"R`@`<2@L` -M5+("`!Q9"P!LL@(`'*P*`(2R`@`"P"XL@(`'*P*`,RR`@`< -M6@H`U+("`!S>"@#HL@(`'%H,`/BR`@`+,"``(!``!\LP(``@$``("S`@`"`0``A+,"``(!``"(LP(``@$` -M`(RS`@`"`0``D+,"``(!``"4LP(``@$``)BS`@`"`0``G+,"``(!``"@LP(` -M`@$``*2S`@`"`0``J+,"``(!``#`LP(`'"D+`'RT`@`<3`H`F+0"`!Q/"P"T -MM`(`'/X.`!2U`@`<``T`5+4"``(#``!\M0(`''H*`,RU`@`+8"``(!``!\M@(``@$``("V`@`"`0``A+8"``(!``"(M@(` -M`@$``(RV`@`"`0``D+8"``(!``"4M@(``@$``)BV`@`"`0``G+8"``(!``"@ -MM@(``@$``*2V`@`"`0``J+8"``(!``"LM@(``@$``+"V`@`"`0``M+8"``(! -M``"XM@(``@$``+RV`@`"`0``P+8"``(!``#$M@(``@$``,BV`@`"`0``S+8" -M``(!``#0M@(``@$``-2V`@`"`0``V+8"``(!``#,("`!S^"P"DP@(`'((,`+#"`@`<>@H`U,("`!S2 -M"P#DP@(`'`H.`/C"`@`P0`:-8"`"Q[!`"`U@(`'.X-`)C6 -M`@`K?`0`G-8"`"Q\!`"PU@(`*WX$`+C6`@`L?@0`%-<"`!PH#@!\UP(`',\- -M`(S7`@`<@@P`F-<"`!S/#0"LUP(`'((,`+C7`@`0P`(-D"`"NM#0`DV0(`+*T-`#39`@`<>0P`6-D" -M`!RL#@`0V@(``@$``!3:`@`"`0``&-H"``(!```-H"``(!``!\V@(``@$``(#: -M`@`"`0``A-H"``(!``#(V@(`'*P.`.3:`@``@`<>0P`(-X"`!RL -M#@`\W@(`'*P.`%C>`@``@`KK0T`O-X" -M`"RM#0#,W@(`''D,`-S>`@`KK0T`X-X"`"RM#0#LW@(`''D,``3?`@`0P`;-\"`!RL#@"(WP(`'*P.`*3?`@`< -MK`X`P-\"`!RL#@#0P`F.$"`!QY#`#,X0(` -M'*P.`/3A`@`0P`2.("`!RL#@!P -MX@(`'*P.`)SB`@`KK0T`H.("`"RM#0"PX@(`''D,`/CB`@`KK0T`_.("`"RM -M#0`,XP(`''D,`%3C`@`KK0T`6.,"`"RM#0!HXP(`''D,`*3C`@`<>0P`V.," -M`!RL#@``Y`(`'*P.`"CD`@`0P` -M9.0"``(!``!HY`(``@$``&SD`@`"`0``<.0"``(!``!TY`(``@$``'CD`@`" -M`0``?.0"``(!``"`Y`(``@$``(3D`@`"`0``B.0"``(!``",Y`(``@$``.CD -M`@`0P`<.<"`!RL#@"HYP(`*ZT-`*SG`@`LK0T`P.<"`!QY#`#4 -MYP(`*ZT-`-CG`@`LK0T`Z.<"`!QY#``(Z`(`'*P.`"SH`@`KK0T`,.@"`"RM -M#0!`Z`(`''D,`'SH`@`<>0P`A.@"``*M#0"TZ`(`'*P.`-SH`@`0P`).H"`!RL#@!,Z@(`'*P.`*3J`@`<>0P`S.H"`!QY#```ZP(`'*P. -M`#CK`@`<>0P`D.L"`!RL#@#HZP(`''D,`%3L`@`0P`+.X"`!RL#@!4 -M[@(`'*P.`'SN`@`0P`F.\"`!RL#@#D[P(`*ZT-`.CO`@`LK0T`^.\" -M`!QY#``@\`(`'*P.`$SP`@`KK0T`4/`"`"RM#0!@\`(`''D,`(#P`@`0P`"/$"`!RL#@!`\0(`*ZT-`$3Q`@`L -MK0T`5/$"`!QY#`"(\0(`'*P.`+#Q`@`0P`D/,"`!S/#0"@\P(`'((,`*SS`@``@#`!PA"@`8"0,`'&H,`"0)`P`< -M+@P`7`D#`!Q/"P"`"0,`'$P*`)P)`P`<_@X`T`H#`!P?#0#@"@,`',\+`"@+ -M`P`PP`5!(#`!RG#@!X$@,`'#X*`(02 -M`P`<40T`C!(#`!Q1#0"D$@,`*VT.`*@2`P`L;0X`L!(#`!Q[#`"\$@,`'!D, -M`,02`P`<90P`Y!(#`!RI"@`0$P,`''L-`!@3`P`"@!@'@,`')$.`(@>`P` -M"P"<)`,`'!8*`+`D`P`<``T`V"0#`!PX#0#D)`,`'`,*`$PE`P`<``P`5"4# -M`!R>"@`\)@,`'``-`$@F`P`<``T`5"8#`!P`#0!@)@,`'``-`&PF`P`<``T` -M>"8#`!P`#0"$)@,`'``-`)`F`P`<``T`G"8#`!P`#0"D)@,`'``-`+`F`P`" -M`P``M"8#``(#``"X)@,``@,``+PF`P`"`P``P"8#``(#``#$)@,``@,``,@F -M`P`"`P``S"8#``(#``#0)@,``@,``"`G`P`$0#`!P\"P",1`,`'#P+ -M`*1$`P`#`!X -M2@,`'-X,`)A*`P`#0"P2@,`'-X,`,Q*`P`#``\2P,`'#P+`%!+`P`%4#``(#``!\50,``@,``(!5`P`"`P``A%4#``("``"(50,``@,``(Q5`P`" -M`P``D%4#``(#``"450,``@,``)A5`P`"`P``G%4#``(#``"@50,``@,``*15 -M`P`"`P``J%4#``(#``"L50,``@,``-Q5`P`"`0``X%4#``(!``#D50,``@$` -M`.A5`P`"`0``#%8#`"MS!0`05@,`+',%`!16`P`K=`4`&%8#`"QT!0`<5@,` -M'``-`"16`P`K=04`*%8#`"QU!0`L5@,`*W8%`#!6`P`L=@4`/%8#`!P`#0!` -M5@,`*W<%`$16`P`L=P4`4%8#`!P`#0"X5@,`'``-`,Q6`P`<``T`X%8#`!P` -M#0#T5@,`'``-``A7`P`<``T`'%<#`!P`#0`P5P,`'``-`$!7`P`"`@``1%<# -M``(#``!(5P,``@,``$Q7`P`"`P``4%<#``(#``!45P,``@,``%A7`P`"`P`` -M7%<#``(#``",5P,`'#P+`*!7`P`%D#`!P\"P",60,`'#P+ -M`*!9`P``P`<``T`'%X#`!P`#0`L7@,`'``-`#Q>`P`<*`H`4%X#`!PH"@!T7@,` -M'#P+`(A>`P``P`"`P``G%X#``(#``"@ -M7@,``@,``*1>`P`"`P``J%X#``(#``"L7@,``@(``+!>`P`"`P``M%X#``(# -M``"X7@,``@,``+Q>`P`"`P``P%X#``(#```$7P,`'#P+`"1?`P`&$#`!P`#0"H80,`'``-`+QA`P`<``T`T&$#`!P`#0#D80,` -M'``-`/AA`P`<``T`#&(#`!P`#0`<8@,`'``-`"1B`P`"`P``*&(#``(#```L -M8@,``@,``#!B`P`"`P``-&(#``(#```X8@,``@,``#QB`P`"`P``0&(#``(" -M``!$8@,``@,``'QB`P`<``T`D&(#`!P`#0"D8@,`'``-`+AB`P`<``T`S&(# -M`!P`#0#@8@,`'``-`.QB`P`<``T`*&,#`!P`#0`\8P,`'``-`%!C`P`<``T` -M9&,#`!P`#0!X8P,`'``-`(QC`P`<``T`F&,#`!P`#0#88P,`'``-`.QC`P`< -M``T``&0#`!P`#0`49`,`'``-`"AD`P`<``T`/&0#`!P`#0!(9`,`'``-`(1D -M`P`<``T`F&0#`!P`#0"L9`,`'``-`,!D`P`<``T`U&0#`!P`#0#H9`,`'``- -M`/1D`P`<``T`%&<#`!P`#0`H9P,`'``-`#QG`P`<``T`4&<#`!P`#0!D9P,` -M'``-`'AG`P`<``T`B&<#`!P`#0"T9P,`'``-`,AG`P`<``T`W&<#`!P`#0#P -M9P,`'``-``1H`P`<``T`&&@#`!P`#0`H:`,`'``-`(1H`P`<``T`E&@#`!P` -M#0#(:`,`'``-`-QH`P`<``T`\&@#`!P`#0`$:0,`'``-`!AI`P`<``T`+&D# -M`!P`#0`X:0,`'``-`(!I`P`<``T`E&D#`!P`#0"H:0,`'``-`+QI`P`<``T` -MT&D#`!P`#0#D:0,`'``-`/!I`P`<``T`S&H#`!P`#0#@:@,`'``-`/1J`P`< -M``T`"&L#`!P`#0`<:P,`'``-`#!K`P`<``T`/&L#`!P`#0!T:P,`'``-`(AK -M`P`<``T`G&L#`!P`#0"P:P,`'``-`,1K`P`<``T`V&L#`!P`#0#D:P,`'``- -M`(AL`P`<``T`G&P#`!P`#0"P;`,`'``-`,1L`P`<``T`V&P#`!P`#0#L;`,` -M'``-`/AL`P`<``T`6&T#`!P`#0!L;0,`'``-`(!M`P`<``T`E&T#`!P`#0"H -M;0,`'``-`+QM`P`<``T`R&T#`!P`#0`,;@,`'``-`"!N`P`<``T`-&X#`!P` -M#0!(;@,`'``-`%QN`P`<``T`<&X#`!P`#0"$;@,`'``-`+!N`P`<``T`Q&X# -M`!P`#0#8;@,`'``-`.QN`P`<``T``&\#`!P`#0`4;P,`'``-`"1O`P`<``T` -M4&\#`!P`#0!D;P,`'``-`'AO`P`<``T`C&\#`!P`#0"@;P,`'``-`+1O`P`< -M``T`Q&\#`!P`#0#0;P,`'*4.`!QP`P`"`P``('`#``(#```D<`,``@,``"AP -M`P`"`P``+'`#``(#```P<`,``@,``#1P`P`"`P``.'`#``("```\<`,``@,` -M`$!P`P`"`P``1'`#``(#``!(<`,``@,``$QP`P`"`P``4'`#``(#``!4<`,` -M`@,``%AP`P`"`P``7'`#``(#``!@<`,``@,``&1P`P`"`P``:'`#``(#``!L -M<`,``@,``'!P`P`"`P``='`#``(#``"X<`,`'``-`,QP`P`<``T`X'`#`!P` -M#0#T<`,`'``-``AQ`P`<``T`''$#`!P`#0`H<0,`'``-`&1Q`P`<``T`>'$# -M`!P`#0",<0,`'``-`*!Q`P`<``T`M'$#`!P`#0#(<0,`'``-`-AQ`P`<``T` -M%'(#`!P`#0`H<@,`'``-`#QR`P`<``T`4'(#`!P`#0!D<@,`'``-`'AR`P`< -M``T`B'(#`!P`#0#$<@,`'``-`-AR`P`<``T`['(#`!P`#0```,`'``-`!AX`P`<``T`+'@#`!P`#0!` -M>`,`'``-`%1X`P`<``T`D'@#`!P`#0"D>`,`'``-`+AX`P`<``T`S'@#`!P` -M#0#@>`,`'``-`/1X`P`<``T`"'D#`!P`#0!$>0,`'``-`%AY`P`<``T`;'D# -M`!P`#0"`>0,`'``-`)1Y`P`<``T`J'D#`!P`#0"\>0,`'``-`/AY`P`<``T` -M#'H#`!P`#0`@>@,`'``-`#1Z`P`<``T`2'H#`!P`#0!<>@,`'``-`'!Z`P`< -M``T`K'H#`!P`#0#`>@,`'``-`-1Z`P`<``T`Z'H#`!P`#0#\>@,`'``-`!![ -M`P`<``T`)'L#`!P`#0!L>P,`'``-`(![`P`<``T`E'L#`!P`#0"H>P,`'``- -M`+Q[`P`<``T`T'L#`!P`#0#D>P,`'``-`.Q[`P`"`P``\'L#``(#``#T>P,` -M`@,``/A[`P`"`P``_'L#``(#````?`,``@,```1\`P`"`P``"'P#``("```, -M?`,``@,``!!\`P`"`P``%'P#``(#```8?`,``@,``!Q\`P`"`P``('P#``(# -M```D?`,``@,``"A\`P`"`P``+'P#``(#```P?`,``@,``'1\`P`<``T`B'P# -M`!P`#0"(<#``(#``!\AP,``@,``("'`P`"`P``A(<#``(# -M``"(AP,``@,``(R'`P`"`P``D(<#``(#``"4AP,``@,``*B(`P`KA@4`K(@# -M`"R&!0"\B`,`*X8%`,"(`P`LA@4`T(@#`!P*#@``B0,`'`H.`'R)`P`<``T` -MD(D#`!P`#0"DB0,`'``-`+B)`P`<``T`S(D#`!P`#0#@B0,`'``-`.R)`P`< -M``T`#(H#`!PU"P!(B@,`'``-`%R*`P`<``T`<(H#`!P`#0"$B@,`'``-`)B* -M`P`<``T`K(H#`!P`#0"XB@,`'``-`,"*`P`"`P``Q(H#``(#``#(B@,``@,` -M`,R*`P`"`P``T(H#``(#``#4B@,``@,``-B*`P`"`P``W(H#``("``#@B@,` -M`@,``#R+`P`<``T`4(L#`!P`#0!DBP,`'``-`'B+`P`<``T`C(L#`!P`#0"@ -MBP,`'``-`*R+`P`@L`R),#`!P,"P`)0#`!S/#0"@E`,``@(``+24`P`<*`H`R)0#`!PH"@#4E`,` -M'%8.`.24`P` -M"@`XH0,``@T``*"A`P`<``T`M*$#`!P`#0#(H0,`'``-`-RA`P`<``T`\*$# -M`!P`#0`$H@,`'``-`!2B`P`<``T`7*(#`!P`#0!PH@,`'``-`(2B`P`<``T` -MF*(#`!P`#0"LH@,`'``-`,"B`P`<``T`R*(#`"O3!0#,H@,`+-,%`-"B`P`K -MU`4`U*(#`"S4!0#DH@,`'``-`.RB`P`"`P``\*(#``(#``#TH@,``@,``/BB -M`P`"`P``_*(#``(#````HP,``@,```2C`P`"`P``"*,#``("```,HP,``@,` -M`"RC`P`KUP4`,*,#`"S7!0"THP,`'``-`,BC`P`<``T`W*,#`!P`#0#PHP,` -M'``-``2D`P`<``T`&*0#`!P`#0`LI`,`'``-`&"D`P`KV`4`9*0#`"S8!0!L -MI`,`*]D%`'"D`P`LV04`>*0#`"O:!0!\I`,`+-H%`.RD`P`<``T``*4#`!P` -M#0`4I0,`'``-`"BE`P`<``T`/*4#`!P`#0!0I0,`'``-`&RE`P`<``T`/*8# -M`!P`#0!0I@,`'``-`&2F`P`<``T`>*8#`!P`#0",I@,`'``-`*"F`P`<``T` -ML*8#`!P`#0#`IP,``@,``,2G`P`"`P``R*<#``(#``#,IP,``@,``-"G`P`" -M`P``U*<#``(#``#8IP,``@,``-RG`P`"`@``X*<#``(#```TJ`,`'``-`$BH -M`P`<``T`7*@#`!P`#0!PJ`,`'``-`(2H`P`<``T`F*@#`!P`#0"LJ`,`'``- -M`!RI`P`<``T`,*D#`!P`#0!$J0,`'``-`%BI`P`<``T`;*D#`!P`#0"`J0,` -M'``-`)2I`P`<``T`X*D#`!P`#0#TJ0,`'``-``BJ`P`<``T`'*H#`!P`#0`P -MJ@,`'``-`$2J`P`<``T`6*H#`!P`#0"\J@,``@,``,"J`P`"`P``Q*H#``(# -M``#(J@,``@,``,RJ`P`"`P``T*H#``(#``#4J@,``@,``-BJ`P`"`@``W*H# -M``(#``!`JP,`'``-`%2K`P`<``T`:*L#`!P`#0!\JP,`'``-`)"K`P`<``T` -MI*L#`!P`#0"PJP,`'``-`,"K`P`<>@L`U*L#`!QZ"P#HJP,`''H+`/RK`P`< -M>@L`!*P#``(#```(K`,``@,```RL`P`"`P``$*P#``(#```4K`,``@,``!BL -M`P`"`P``'*P#``(#```@K`,``@(``$RL`P`<\`P`:*P#`!QZ"P!\K`,`'&(* -M`)RL`P`<>@L`L*P#`!QB"@#,K`,`'$0,`-2L`P`<_`D`Y*P#`!QZ"P#\K`,` -M'&(*`"2M`P`<1`P`2*T#`!Q$#`!@L`2*X#`!Q$#`"+X#`!P\"P"$O@,``@,``(B^`P`" -M`P``C+X#``(#``"0O@,``@,``)2^`P`"`P``F+X#``(#``",T#`!P` -M#0"(S0,`'"@*`-3-`P`<``T`Z,T#`!P`#0#\S0,`'``-`!#.`P`<``T`),X# -M`!P`#0`XS@,`'``-`$C.`P`<``T`E,X#`!P\"P#-H# -M`!P`#0",V@,`'``-`*#:`P`<``T`M-H#`!P`#0#(V@,`'``-`-S:`P`<``T` -MZ-H#`!P`#0``VP,`'#P+`$C;`P`<``T`7-L#`!P`#0!PVP,`'``-`(3;`P`< -M``T`F-L#`!P`#0"LVP,`'``-`+C;`P`<``T`S-L#`!P\"P#@VP,`'#P+`"C< -M`P`<``T`/-P#`!P`#0!0W`,`'``-`&3<`P`<``T`>-P#`!P`#0",W`,`'``- -M`)S<`P`<``T`I-P#`!S\"0"TW`,`'"@*``#=`P`<``T`%-T#`!P`#0`HW0,` -M'``-`#S=`P`<``T`4-T#`!P`#0!DW0,`'``-`'3=`P`<``T`A-T#`!PH"@#0 -MW0,`'``-`.3=`P`<``T`^-T#`!P`#0`,W@,`'``-`"#>`P`<``T`--X#`!P` -M#0!$W@,`'``-`%3>`P`<*`H`H-X#`!P`#0"TW@,`'``-`,C>`P`<``T`W-X# -M`!P`#0#PW@,`'``-``3?`P`<``T`%-\#`!P`#0`DWP,`'"@*`'#?`P`<``T` -MA-\#`!P`#0"8WP,`'``-`*S?`P`<``T`P-\#`!P`#0#4WP,`'``-`.3?`P`< -M``T`&.`#``(#```@L`6.$#`!Q&#`!@X0,``@,``&3A`P`"`P``:.$#``(# -M``!LX0,``@,``'#A`P`"`P``=.$#``(#``!XX0,``@,``'SA`P`"`@``X.$# -M`!P`#0#TX0,`'``-``CB`P`<``T`'.(#`!P`#0`PX@,`'``-`$3B`P`<``T` -M4.(#`!P`#0!@X@,`'/`,`'SB`P``H$`!P`#0"L"@0`'``-`,0*!``@L`J!4$`!P`#0"\%00`'``-`-`5!``<``T`Y!4$ -M`!P`#0#X%00`'``-``P6!``<``T`(!8$`!P`#0`H%@0``@,``"P6!``"`P`` -M,!8$``(#```T%@0``@,``#@6!``"`P``/!8$``(#``!`%@0``@,``$06!``" -M`@``8!8$`!S9#`!T%@0`'/P)`(@6!``<_`D`G!8$`!Q-#@"P%@0`'$T.`,06 -M!``<30X`X!8$`!Q$#`#H%@0`'$T.`!`7!``<8@X`/!<$`!P`#0!0%P0`'``- -M`&07!``<``T`>!<$`!P`#0",%P0`'``-`*`7!``<``T`M!<$`!P`#0#`%P0` -M`@,``,07!``"`P``R!<$``(#``#,%P0``@,``-`7!``"`P``U!<$``(#``#8 -M%P0``@,``-P7!``"`@``_!<$`!QB#@`H&`0`'``-`#P8!``<``T`4!@$`!P` -M#0!D&`0`'``-`'@8!``<``T`C!@$`!P`#0"@&`0`'``-`*P8!``"`P``L!@$ -M``(#``"T&`0``@,``+@8!``"`P``O!@$``(#``#`&`0``@,``,08!``"`P`` -MR!@$``("``#$&00`*T(&`,@9!``L0@8`+!H$`"M"!@`P&@0`+$(&`'@:!``< -M``T`C!H$`!P`#0"@&@0`'``-`+0:!``<``T`R!H$`!P`#0#<&@0`'``-`.P: -M!``<``T`]!H$``(#``#X&@0``@,``/P:!``"`P```!L$``(#```$&P0``@,` -M``@;!``"`P``#!L$``(#```0&P0``@(``%P;!``<``T`!``<``T` -M-!X$`"M"!@`X'@0`+$(&`&`>!``K0@8`9!X$`"Q"!@"H'@0`'``-`+P>!``< -M``T`T!X$`!P`#0#D'@0`'``-`/@>!``<``T`#!\$`!P`#0`<'P0`'``-`"`? -M!``K0@8`)!\$`"Q"!@"X'P0`'``-`,P?!``<``T`X!\$`!P`#0#T'P0`'``- -M``@@!``<``T`'"`$`!P`#0!$(`0`'``-`$P@!``K0@8`4"`$`"Q"!@"L(`0` -M'``-`,`@!``<``T`U"`$`!P`#0#H(`0`'``-`/P@!``<``T`$"$$`!P`#0!$ -M(00`'``-`$@A!``K0@8`3"$$`"Q"!@!H(00`*T(&`&PA!``L0@8`O"$$`!P` -M#0#0(00`'``-`.0A!``<``T`^"$$`!P`#0`,(@0`'``-`"`B!``<``T`+"($ -M`!P`#0!P(@0`'``-`(0B!``<``T`F"($`!P`#0"L(@0`'``-`,`B!``<``T` -MU"($`!P`#0#@(@0`'``-`"PC!``<``T`0",$`!P`#0!4(P0`'``-`&@C!``< -M``T`?",$`!P`#0"0(P0`'``-`+`C!``<``T`P"0$`!P`#0#4)`0`'``-`.@D -M!``<``T`_"0$`!P`#0`0)00`'``-`"0E!``<``T`,"4$`!P`#0!L)00`'``- -M`(`E!``<``T`E"4$`!P`#0"H)00`'``-`+PE!``<``T`T"4$`!P`#0#D)00` -M'``-`"`F!``<``T`-"8$`!P`#0!()@0`'``-`%PF!``<``T`<"8$`!P`#0"$ -M)@0`'``-`)@F!``<``T`U"8$`!P`#0#H)@0`'``-`/PF!``<``T`$"<$`!P` -M#0`D)P0`'``-`#@G!``<``T`1"<$`!P`#0!,)P0`*T(&`%`G!``L0@8`I"<$ -M`!P`#0"X)P0`'``-`,PG!``<``T`X"<$`!P`#0#T)P0`'``-``@H!``<``T` -M%"@$`!P`#0!8*`0`'``-`&PH!``<``T`@"@$`!P`#0"4*`0`'``-`*@H!``< -M``T`O"@$`!P`#0#(*`0`'``-`!`I!``<``T`)"D$`!P`#0`X*00`'``-`$PI -M!``<``T`8"D$`!P`#0!T*00`'``-`(@I!``<``T``"H$`!P`#0`4*@0`'``- -M`"@J!``<``T`/"H$`!P`#0!0*@0`'``-`&0J!``<``T`<"H$`!P`#0`(*P0` -M`@,```PK!``"`P``$"L$``(#```4*P0``@,``!@K!``"`P``'"L$``(#```@ -M*P0``@,``"0K!``"`@``*"L$``(#```L*P0``@(``#`K!``"`P``-"L$``(# -M```X*P0``@,``#PK!``"`P``0"L$``(#``!$*P0``@(``$@K!``"`P``3"L$ -M``(#``!0*P0``@,``%0K!``"`P``6"L$``(#``!<*P0``@,``&`K!``"`P`` -M9"L$``(#``!H*P0``@,``&PK!``"`P``<"L$``(#``!T*P0``@,``'@K!``" -M`@``?"L$``(#``"`*P0``@,``(0K!``"`P``B"L$``(#``",*P0``@,``)`K -M!``"`P``E"L$``(#``"8*P0``@,``)PK!``"`@``J"L$`"M"!@"L*P0`+$(& -M`!`L!``<``T`)"P$`!P`#0`X+`0`'``-`$PL!``<``T`8"P$`!P`#0!T+`0` -M'``-`(0L!``<``T`P"P$`!P`#0#4+`0`'``-`.@L!``<``T`_"P$`!P`#0`0 -M+00`'``-`"0M!``<``T`."T$`!P`#0!T+00`'``-`(@M!``<``T`G"T$`!P` -M#0"P+00`'``-`,0M!``<``T`V"T$`!P`#0#D+00`'``-`/@M!``K2`8`_"T$ -M`"Q(!@`<+@0`*T@&`"`N!``L2`8`>"X$`!P`#0",+@0`'``-`*`N!``<``T` -MM"X$`!P`#0#(+@0`'``-`-PN!``<``T`Z"X$`!P`#0#L+@0`*T@&`/`N!``L -M2`8`!"\$`"M"!@`(+P0`+$(&`&@O!``<``T`?"\$`!P`#0"0+P0`'``-`*0O -M!``<``T`N"\$`!P`#0#,+P0`'``-`-@O!``<``T`+#`$`!P`#0!`,`0`'``- -M`%0P!``<``T`:#`$`!P`#0!\,`0`'``-`)`P!``<``T`I#`$`!P`#0#,,`0` -M`@,``-`P!``"`P``U#`$``(#``#8,`0``@,``-PP!``"`P``X#`$``(#``#D -M,`0``@,``.@P!``"`@``6#$$`!P`#0!L,00`'``-`(`Q!``<``T`E#$$`!P` -M#0"H,00`'``-`+PQ!``<``T`T#$$`!P`#0#<,00``@,``.`Q!``"`P``Y#$$ -M``(#``#H,00``@,``.PQ!``"`P``\#$$``(#``#T,00``@,``/@Q!``"`@`` -M:#($`!P`#0!\,@0`'``-`)`R!``<``T`I#($`!P`#0"X,@0`'``-`,PR!``< -M``T`X#($`!P`#0#L,@0``@,``/`R!``"`P``]#($``(#``#X,@0``@,``/PR -M!``"`P```#,$``(#```$,P0``@,```@S!``"`@``<#,$`!P`#0"$,P0`'``- -M`)@S!``<``T`K#,$`!P`#0#`,P0`'``-`-0S!``<``T`[#,$`!P`#0#\,P0` -M`@,````T!``"`P``!#0$``(#```(-`0``@,```PT!``"`P``$#0$``(#```4 -M-`0``@,``!@T!``"`@``7#0$`!P`#0!P-`0`'``-`(0T!``<``T`F#0$`!P` -M#0"L-`0`'``-`,`T!``<``T`S#0$`!P`#0#@-`0`'&`.`/PT!``"`P```#4$ -M``(#```$-00``@,```@U!``"`P``##4$``(#```0-00``@,``!0U!``"`P`` -M$``("``!<-00`'``-`'`U!``<``T`A#4$`!P`#0"8-00`'``-`*PU!``< -M``T`P#4$`!P`#0#,-00`'``-`.0U!``"`P``Z#4$``(#``#L-00``@,``/`U -M!``"`P``]#4$``(#``#X-00``@,``/PU!``"`P```#8$``("``!4-@0`'``- -M`&@V!``<``T`?#8$`!P`#0"0-@0`'``-`*0V!``<``T`N#8$`!P`#0#0-@0` -M'``-`.`V!``K5@8`Y#8$`"Q6!@#L-@0`*T(&`/`V!``L0@8``#<$`"M7!@`$ -M-P0`+%<&``PW!``K6`8`$#<$`"Q8!@`(.`0`'``-`!PX!``<``T`,#@$`!P` -M#0!$.`0`'``-`%@X!``<``T`;#@$`!P`#0#(.`0`'``-`"@Y!``"`0``+#D$ -M``(!```P.00``@$``#0Y!``"`0``&#P$`!P`#0`L/`0`'``-`$`\!``<``T` -M5#P$`!P`#0!H/`0`'``-`'P\!``<``T`B#P$`!P`#0#H/`0`'``-`/P\!``< -M``T`$#T$`!P`#0`D/00`'``-`#@]!``<``T`3#T$`!P`#0!8/00`'``-`*`] -M!``<``T`M#T$`!P`#0#(/00`'``-`-P]!``<``T`\#T$`!P`#0`$/@0`'``- -M`!@^!``<``T`)#X$`!PW"P!D/@0`'``-`'@^!``<``T`C#X$`!P`#0"@/@0` -M'``-`+0^!``<``T`R#X$`!P`#0#4/@0`'``-`!`_!``<``T`)#\$`!P`#0`X -M/P0`'``-`$P_!``<``T`8#\$`!P`#0!T/P0`'``-`(`_!``<``T`C#\$``(# -M``"0/P0``@,``)0_!``"`P``F#\$``(#``"$H$`!P`#0"(2@0`'``-`,1*!``<``T`V$H$`!P`#0#L2@0` -M'``-``!+!``<``T`%$L$`!P`#0`H2P0`'``-`#A+!``<``T`=$L$`!P`#0"( -M2P0`'``-`)Q+!``<``T`L$L$`!P`#0#$2P0`'``-`-A+!``<``T`Z$L$`!P` -M#0`D3`0`'``-`#A,!``<``T`3$P$`!P`#0!@3`0`'``-`'1,!``<``T`B$P$ -M`!P`#0"83`0`'``-`-Q,!``%4$``(" -M``"\500`'``-`,Q5!``<``T`"%8$`!P`#0`<5@0`'``-`#!6!``<``T`1%8$ -M`!P`#0!85@0`'``-`&Q6!``<``T`>%8$`"N1!@!\5@0`+)$&`(!6!``KD@8` -MA%8$`"R2!@"45@0`'``-`*A6!``PT`W%@$`!S?"@#T6`0`*ZT-`/A8!``LK0T`(%D$`"NM#0`D -M600`+*T-`-Q:!``<*PP`]%H$`!PK#``<6P0`'.X)`$A;!``<\0D`;%L$`!P% -M#@#\7`0`'/$)`%A=!``!``K -MS`8`#%X$`"S,!@`D7@0`*\P&`"A>!``LS`8`0%X$`"O,!@!$7@0`+,P&`$A> -M!``!``KT`8`9%X$`"S0!@!H7@0`'/`* -M`'1>!``!``<]`X`X%X$`!ST#@`H7P0` -M'*(+`%A?!``<7`P`B%\$`!Q<#`"47P0`*]H&`)A?!``LV@8`H%\$`!P##0"H -M7P0``@X``+!?!``<&PX`Q%\$`!S1"@#87P0`'$(-`.1?!``<\PP`^%\$`!SR -M"@`L8`0`',T,`#Q@!``<40H`3&`$`!R2"@!<8`0`'#D+`&Q@!``0P`V&0$`"NM#0#<9`0`+*T-``QE!``<>0P`(&4$`!Q?#``H -M900`'!<,`#!E!``',$`!PC"@",`0`'(D+`%1X -M!``<10L`8'@$`!RR#`!L>`0`'(0.`'1X!```0``@,` -M`*QX!``"`P``S'@$`!P^"@#4>`0`'$T+`.1X!``<@PT``'D$`!S4"P`(>00` -M*W,'``QY!``L00`+-H+`"!Y!``KEPT`*'D$`"R7#0`L -M>00`*Y@+`#1Y!``LF`L`@'D$`!S!#@#`>00`'.L,`,QY!``00`'`X*`.QY!``K=`<`]'D$`"QT!P#\>00`*V\'``1Z!``L;P<`#'H$ -M`"M4!P`4>@0`+%0'`!QZ!``K8@<`)'H$`"QB!P!`>@0`'.P*`$AZ!``<`0T` -MB'H$`!Q8#`"8>@0`'+T,`*AZ!``@0`'&P.`-AZ!``< -M;0P`X'H$`!RX#`#X>@0`'*<+``1[!``P0`')P.`#Q[ -M!``P0``@X``%Q[!``(T$`!S$#0"@C00`*\T' -M`*2-!``LS0<`J(T$`!R;#0"XC00`*\L'`+R-!``LRP<`Q(T$`!SR"@#,C00` -M*\`'`-2-!``LP`<`V(T$`"O.!P#)($`!RI#@"@ -MD@0`'+8.`,R2!``<&0X`[)($`!PK#@`$DP0`')L-`#"3!``<+PX`/),$`!RI -M#@!DDP0`'+8.`*"3!``<&0X`Q),$`!P8#@#!``LY@<`")X$`!S$#0`!``!``<\@H`D)X$`!R`"@#$G@0`*^H'`,B>!``L -MZ@<`T)X$`!P""P#HG@0`*^L'`.R>!``LZP<`])X$`!S$#0#\G@0`'*D.`"2? -M!``0P`V*D$`"L!"`#0P`F*L$`!QY#`"DJP0`*P((`*BK!``L`@@`L*L$`!P""P`( -MK`0`'&0+`""L!``K`P@`)*P$`"P#"``LK`0`'`(+`%"L!``@H`A+8$`!S2"P"XM@0`'((,`,RV -M!``@H`V+@$`"L9"`#< -MN`0`+!D(`."X!``,,$``(!``!\PP0``@$``(##!``"`0``A,,$ -M``(!``"(PP0``@$``(S#!``"`0``D,,$``(!``"4PP0``@$``##$!``K,@@` -M-,0$`"PR"`!HQ`0`'`(+`*#$!``<@`H`",4$`"LR"``,Q00`+#((`##%!``< -M/@H`G,4$`!Q^#0#$Q00`'(`*`##(!```L`@,L$`!P""P"DRP0`'+\+`-S+!``<@`H` -M",P$`!SR"@`8S`0`'/(*`'S,!``<\@H`C,P$`!SR"@"@S`0`'/(*`,3,!``< -M?@T`\,P$`!R`"@!,S00`'$<*`&C-!``K/`@`;,T$`"P\"`!PS00`*ST(`'3- -M!``L/0@`>,T$`!QS"@"$S00`'"H,`*#-!``K/@@`I,T$`"P^"`"HS00`*S\( -M`*S-!``L/P@`L,T$`!QS"@#4S00`*T`(`-C-!``L0`@`W,T$`"M!"`#@S00` -M+$$(`.3-!``<`L`8,\$`!SR"@!PSP0`'/(*`-C/!``<\@H`Z,\$ -M`!SR"@#\SP0`'/(*`!#0!``K3`@`%-`$`"Q,"``8T`0`'',*`$#0!``K30@` -M1-`$`"Q-"`!(T`0`*TX(`$S0!``L3@@`5-`$`"M/"`!8T`0`+$\(`)#0!``< -M!``< -M/@H`:-X$``(!``!LW@0``@$``'#>!``"`0``=-X$``(!``!XW@0``@$``'S> -M!``"`0``@-X$``(!``"$W@0``@$``(C>!``"`0``C-X$``(!``"0W@0``@$` -M`)3>!``"`0``F-X$``(!``"!``"`0``I-X$``(!``"HW@0` -M`@$``*S>!``"`0``L-X$``(!``#$W@0`'+0-`,S>!``<4`L`$-\$`!PI"P`X -MWP0`'(`*`(3?!``<@`H`G-\$`!QN"P#HWP0`'"D+`/C?!``<_PL`(.`$`!S? -M"@!,X`0`'!X*`&C@!```@`%/0$`!SR"@!4]`0`*WD(`%CT!``L>0@`7/0$`!S$#0"4]`0`*WH(`)CT -M!``L>@@`G/0$`!S$#0"P]`0`*W@(`+3T!``L>`@`O/0$`!SR"@#0]`0`*W@( -M`-3T!``L>`@`W/0$`!SR"@#T]`0`*WL(`/CT!``L>P@``/4$`!S^#``(]00` -M*WP(``SU!``L?`@`$/4$`!R;#0`H]00`*WT(`"SU!``L?0@`,/4$`!R;#0!( -M]00`*WX(`$SU!``L?@@`4/4$`!R;#0!H]00`*W\(`&SU!``L?P@``@`L/4$`"QX"`"X]00`'/(*`,3U!``K>`@`R/4$ -M`"QX"`#0]00`'/(*`.#U!``#@`, -M^@0`+)X.`(SZ!``<>@T`H/H$`!PV#@#L^@0`'#X,``C[!``<_PL`*/L$`!SM -M"0!<^P0`'$X.`'C[!``0P`+`(%`!QQ"P`X`@4`'*,-`&@"!0`K70P`;`(%`"Q=#`"$`@4` -M'.X-`)`"!0`0T`-`0%`!P#"@!0!`4`'`,*`)@$!0`<7PP`J`0% -M`!Q?#`#H!`4`'%\,`!P%!0`!D%`!P` -M#0"@&04`'#X*`+`9!0`!0`< -M``T`*!X%`!R8#0!('@4`'+\+`&P>!0`<``T`>!X%`!R""P"4'@4`''0+`+0> -M!0`<=`L`P!X%`!RL#@#,'@4`'*P.`-@>!0`"@%`!R`"@"X*`4`'(`*`#@I!0`<@`H`:"D%`!R;#0"H*04` -M'(`*`,@I!0`<@`H`Z"D%`!R`"@`$*@4`')L-`$`J!0`<@`H`E"H%`!SK#0`, -M*P4`'(`*`!@K!0`$8%`!R`"@"P -M1@4`'/\+`-A&!0`$<% -M`!P`#0"$1P4`'$D*`*A'!0`@D` -MS$<%`!P`#0#L1P4`''0+`/1'!0`K>PD`^$<%`"Q["0``2`4`'``-``Q(!0`< -M,PL`)$@%`!P`#0`L2`4`')(*`#1(!0`$X%`!Q."P"$3@4`'``-`)!.!0`"`@``E$X% -M``(#``"83@4``@,``)Q.!0`"`P``M$X%`"L8"0"X3@4`+!@)`,1.!0`<``T` -M7$\%`!P`#0"<3P4`'-8+`*Q/!0`<``T`V$\%`!R1#`#D3P4`'``-`/!/!0`" -M`@``]$\%``(#``#X3P4``@,``/Q/!0`"`P``0%`%`"O:"0!$4`4`+-H)`$A0 -M!0`<"0"L4`4`+-X) -M`+10!0`"0"T404`+-X)`,!1!0``@` -M`"H!``"`"```*@$``(@(```J`0``D`@``"H!``"8"```*@$``*`(```J`0`` -MJ`@``"H!``"P"```*@$``+@(```J`0``P`@``"H!``#("```*@$``-`(```J -M`0``V`@``"H!``#@"```*@$``.@(```J`0``\`@``"H!``#X"```*@$````) -M```J`0``"`D``"H!```0"0``*@$``!@)```J`0``(`D``"H!```H"0``*@$` -M`#`)```J`0``.`D``"H!``!`"0``*@$``$@)```J`0``4`D``"H!``!8"0`` -M*@$``&`)```J`0``:`D``"H!``!P"0``*@$``'@)```J`0``@`D``"H!``"( -M"0``*@$``)`)```J`0``F`D``"H!``"@"0``*@$``*@)```J`0``L`D``"H! -M``"X"0``*@$``,`)```J`0``R`D``"H!``#0"0``*@$``-@)```J`0``X`D` -M`"H!``#H"0``*@$``/`)```J`0``^`D``"H!````"@``*@$```@*```J`0`` -M$`H``"H!```8"@``*@$``"`*```J`0``*`H``"H!```P"@``*@$``#@*```J -M`0``0`H``"H!``!("@``*@$``%`*```J`0``6`H``"H!``!@"@``*@$``&@* -M```J`0``<`H``"H!``!X"@``*@$``(`*```J`0``B`H``"H!``"0"@``*@$` -M`)@*```J`0``H`H``"H!``"H"@``*@$``+`*```J`0``N`H``"H!``#`"@`` -M*@$``,@*```J`0``T`H``"H!``#0"@```(0*`-@*```J`0``X`H``"H!``#H -M"@``*@$``/`*```J`0``^`H``"H!````"P``*@$```@+```J`0``$`L``"H! -M```8"P``*@$``"`+```J`0``*`L``"H!```P"P``*@$``#@+```J`0``0`L` -M`"H!``!("P``*@$``%`+```J`0``6`L``"H!``!@"P``*@$``&@+```J`0`` -M<`L``"H!``!X"P``*@$``(`+```J`0``B`L``"H!``"0"P``*@$``)@+```J -M`0``H`L``"H!``"H"P``*@$``+`+```J`0``N`L``"H!``#`"P``*@$``,@+ -M```J`0``T`L``"H!``#8"P``*@$``.`+```J`0``Z`L``"H!``#P"P``*@$` -M`/@+```J`0````P``"H!```(#```*@$``!`,```J`0``&`P``"H!```@#``` -M*@$``"@,```J`0``,`P``"H!```X#```*@$``$`,```J`0``2`P``"H!``!0 -M#```*@$``%@,```J`0``8`P``"H!``!H#```*@$``'`,```J`0``>`P``"H! -M``"`#```*@$``(@,```J`0``D`P``"H!``"8#```*@$``*`,```J`0``H`P` -M``"$"@"H#```*@$``+`,```J`0``N`P``"H!``#`#```*@$``,@,```J`0`` -MT`P``"H!``#8#```*@$``.`,```J`0``Z`P``"H!``#P#```*@$``/@,```J -M`0````T``"H!```(#0``*@$``!`-```J`0``&`T``"H!```@#0``*@$``"@- -M```J`0``,`T``"H!```P#0```(0*`#@-```J`0``0`T``"H!``!`#0```(0* -M`$@-```J`0``4`T``"H!``!8#0``*@$``&`-```J`0``:`T``"H!``!P#0`` -M*@$``'@-```J`0``@`T``"H!``"(#0``*@$``)`-```J`0``F`T``"H!``"@ -M#0``*@$``*@-```J`0``L`T``"H!``"X#0``*@$``,`-```J`0``R`T``"H! -M``#0#0``*@$``-@-```J`0``X`T``"H!``#H#0``*@$``/`-```J`0``^`T` -M`"H!````#@``*@$```@.```J`0``$`X``"H!```8#@``*@$``"`.```J`0`` -M*`X``"H!```P#@``*@$``#@.```J`0``0`X``"H!``!(#@``*@$``%`.```J -M`0``6`X``"H!``!@#@``*@$``&@.```J`0``<`X``"H!``!X#@``*@$``(`. -M```J`0``@`X```"$"@"(#@``*@$``)`.```J`0``F`X``"H!``"@#@``*@$` -M`*@.```J`0``L`X``"H!``"X#@``*@$``,`.```J`0``R`X``"H!``#0#@`` -M*@$``-@.```J`0``X`X``"H!``#H#@``*@$``/`.```J`0``\`X```"$"@#X -M#@``*@$````/```J`0``"`\``"H!```0#P``*@$``!@/```J`0``(`\``"H! -M```H#P``*@$``#`/```J`0``.`\``"H!``!`#P``*@$``$@/```J`0``4`\` -M`"H!``!8#P``*@$``&`/```J`0``:`\``"H!``!P#P``*@$``'@/```J`0`` -M@`\``"H!``"(#P``*@$``)`/```J`0``F`\``"H!``"@#P``*@$``*@/```J -M`0``L`\``"H!``"X#P``*@$``,`/```J`0``R`\``"H!``#0#P``*@$``-@/ -M```J`0``X`\``"H!``#H#P``*@$``/`/```J`0``^`\``"H!````$```*@$` -M``@0```J`0``$!```"H!```0$````(0*`!@0```J`0``(!```"H!```H$``` -M*@$``#`0```J`0``.!```"H!``!`$```*@$``$@0```J`0``4!```"H!``!8 -M$```*@$``&`0```J`0``:!```"H!``!P$```*@$``'@0```J`0``@!```"H! -M``"($```*@$``)`0```J`0``F!```"H!``"@$```*@$``*@0```J`0``L!`` -M`"H!``"X$```*@$``,`0```J`0``R!```"H!``#0$```*@$``-@0```J`0`` -MX!```"H!``#H$```*@$``/`0```J`0``^!```"H!````$0``*@$```@1```J -M`0``$!$``"H!```8$0``*@$``"`1```J`0``*!$``"H!```H$0```(0*`#`1 -M```J`0``.!$``"H!``!`$0``*@$``$@1```J`0``4!$``"H!``!8$0``*@$` -M`&`1```J`0``:!$``"H!``!P$0``*@$``'@1```J`0``@!$``"H!``"($0`` -M*@$``(@1````A`H`D!$``"H!``"8$0``*@$``*`1```J`0``J!$``"H!``"P -M$0``*@$``+@1```J`0``P!$``"H!``#($0``*@$``-`1```J`0``V!$``"H! -M``#@$0``*@$``.@1```J`0``\!$``"H!``#X$0``*@$````2```J`0``"!(` -M`"H!```0$@``*@$``!@2```J`0``(!(``"H!```H$@``*@$``#`2```J`0`` -M.!(``"H!``!`$@``*@$``$@2```J`0``4!(``"H!``!8$@``*@$``&`2```J -M`0``:!(``"H!``!P$@``*@$``'@2```J`0``@!(``"H!``"`$@```(0*`(@2 -M```J`0``D!(``"H!``"8$@``*@$``*`2```J`0``J!(``"H!``"P$@``*@$` -M`+@2```J`0``P!(``"H!``#($@``*@$``-`2```J`0``V!(``"H!``#8$@`` -M`(0*`.`2```J`0``Z!(``"H!``#H$@```(0*`/`2```J`0``^!(``"H!```` -M$P``*@$```@3```J`0``$!,``"H!```8$P``*@$``"`3```J`0``*!,``"H! -M```P$P``*@$``#@3```J`0``0!,``"H!``!($P``*@$``%`3```J`0``6!,` -M`"H!``!@$P``*@$``&@3```J`0``!8``"H!``"`%@``*@$``(@6 -M```J`0``D!8``"H!``"8%@``*@$``*`6```J`0``H!8```"$"@"H%@``*@$` -M`+`6```J`0``N!8``"H!``#`%@``*@$``,@6```J`0``T!8``"H!``#8%@`` -M*@$``.`6```J`0``Z!8``"H!``#P%@``*@$``/@6```J`0```!<``"H!```( -M%P``*@$``!`7```J`0``&!<``"H!```@%P``*@$``"@7```J`0``,!<``"H! -M```X%P``*@$``$`7```J`0``2!<``"H!``!0%P``*@$``%@7```J`0``8!<` -M`"H!``!H%P``*@$``'`7```J`0``>!<``"H!``"`%P``*@$``(@7```J`0`` -MD!<``"H!``"0%P```(0*`)@7```J`0``H!<``"H!``"H%P``*@$``+`7```J -M`0``N!<``"H!``#`%P``*@$``,@7```J`0``T!<``"H!``#8%P``*@$``.`7 -M```J`0``Z!<``"H!``#P%P``*@$``/`7````A`H`^!<``"H!````&```*@$` -M``@8```J`0``$!@``"H!```8&```*@$``"`8```J`0``*!@``"H!```P&``` -M*@$``#@8```J`0``0!@``"H!``!(&```*@$``%`8```J`0``6!@``"H!``!@ -M&```*@$``&@8```J`0`````J`0``$!X``"H!```8'@``*@$``"`>```J`0`` -M*!X``"H!```H'@```(0*`#`>```J`0``.!X``"H!``!`'@``*@$``$@>```J -M`0``4!X``"H!``!8'@``*@$``&`>```J`0``8!X```"$"@!H'@``*@$``'`> -M```J`0``>!X``"H!``"`'@``*@$``(@>```J`0``D!X``"H!``"8'@``*@$` -M`*`>```J`0``J!X``"H!``"P'@``*@$``+@>```J`0``P!X``"H!``#`'@`` -M`(0*`,@>```J`0``T!X``"H!``#8'@``*@$``.`>```J`0``Z!X``"H!``#P -M'@``*@$``/@>```J`0```!\``"H!```('P``*@$``!`?```J`0``&!\``"H! -M```8'P```(0*`"`?```J`0``(!\```"$"@`H'P``*@$``#`?```J`0``.!\` -M`"H!``!`'P``*@$``$@?```J`0``4!\``"H!``!8'P``*@$``&`?```J`0`` -M:!\``"H!``!P'P``*@$``'@?```J`0``@!\``"H!``"('P``*@$``)`?```J -M`0``F!\``"H!``"@'P``*@$``*@?```J`0``L!\``"H!``"X'P``*@$``,`? -M```J`0``R!\``"H!``#0'P``*@$``-@?```J`0``X!\``"H!``#H'P``*@$` -M`/`?```J`0``^!\``"H!````(```*@$```@@```J`0``$"```"H!```8(``` -M*@$``"`@```J`0``*"```"H!```P(```*@$``#@@```J`0``0"```"H!``!( -M(```*@$``%`@```J`0``6"```"H!``!@(```*@$``&@@```J`0``<"```"H! -M``!X(```*@$``(`@```J`0``B"```"H!``"0(```*@$``)@@```J`0``H"`` -M`"H!``"H(```*@$``+`@```J`0``N"```"H!``#`(```*@$``,@@```J`0`` -MT"```"H!``#8(```*@$``.`@```J`0``Z"```"H!``#P(```*@$``/@@```J -M`0```"$``"H!```((0``*@$``!`A```J`0``&"$``"H!```@(0``*@$``"@A -M```J`0``,"$``"H!```X(0``*@$``#@A````A`H`0"$``"H!``!((0``*@$` -M`%`A```J`0``6"$``"H!``!@(0``*@$``&@A```J`0``<"$``"H!``!X(0`` -M*@$``(`A```J`0``B"$``"H!``"0(0``*@$``)@A```J`0``H"$``"H!``"H -M(0``*@$``+`A```J`0``N"$``"H!``#`(0``*@$``,@A```J`0``R"$```"$ -M"@#0(0``*@$``-@A```J`0``X"$``"H!``#H(0``*@$``/`A```J`0``^"$` -M`"H!````(@``*@$```@B```J`0``$"(``"H!```8(@``*@$``"`B```J`0`` -M*"(``"H!```P(@``*@$``#@B```J`0``0"(``"H!``!((@``*@$``%`B```J -M`0``6"(``"H!``!8(@```(0*`&`B```J`0``:"(``"H!``!P(@``*@$``'@B -M```J`0``@"(``"H!``"((@``*@$``)`B```J`0``F"(``"H!``"@(@``*@$` -M`*@B```J`0``L"(``"H!``"X(@``*@$``,`B```J`0``R"(``"H!``#0(@`` -M*@$``-@B```J`0``X"(``"H!``#H(@``*@$``/`B```J`0``^"(``"H!```` -M(P``*@$```@C```J`0``$",``"H!```8(P``*@$``"`C```J`0``*",``"H! -M```P(P``*@$``#@C```J`0``0",``"H!``!((P``*@$``%`C```J`0``6",` -M`"H!``!@(P``*@$``&@C```J`0``<",``"H!``!X(P``*@$``(`C```J`0`` -MB",``"H!``"0(P``*@$``)@C```J`0``H",``"H!``"H(P``*@$``+`C```J -M`0``N",``"H!``#`(P``*@$``,@C```J`0``T",``"H!``#8(P``*@$``.`C -M```J`0``Z",``"H!``#P(P``*@$``/@C```J`0```"0``"H!```()```*@$` -M`!`D```J`0``&"0``"H!```@)```*@$``"@D```J`0``,"0``"H!```X)``` -M*@$``$`D```J`0``2"0``"H!``!0)```*@$``%@D```J`0``8"0``"H!``!H -M)```*@$``'`D```J`0``>"0``"H!``"`)```*@$``(@D```J`0``D"0``"H! -M``"0)````(0*`)@D```J`0``H"0``"H!``"H)```*@$``+`D```J`0``N"0` -M`"H!``#`)```*@$``,@D```J`0``T"0``"H!``#8)```*@$``.`D```J`0`` -MZ"0``"H!``#P)```*@$``/`D````A`H`^"0``"H!````)0``*@$```@E```J -M`0``$"4``"H!```8)0``*@$``"`E```J`0``*"4``"H!```P)0``*@$``#@E -M```J`0``0"4``"H!``!()0``*@$``%`E```J`0``6"4``"H!``!@)0``*@$` -M`&@E```J`0``<"4``"H!``!P)0```(0*`'@E```J`0``@"4``"H!``"()0`` -M*@$``)`E```J`0``F"4``"H!``"@)0``*@$``*@E```J`0``L"4``"H!``"X -M)0``*@$``,`E```J`0``R"4``"H!``#()0```(0*`-`E```J`0``V"4``"H! -M``#@)0``*@$``.@E```J`0``\"4``"H!``#X)0``*@$````F```J`0``""8` -M`"H!```0)@``*@$``!@F```J`0``("8``"H!```H)@``*@$``#`F```J`0`` -M."8``"H!``!`)@``*@$``$@F```J`0``4"8``"H!``!8)@``*@$``&`F```J -M`0``:"8``"H!``!P)@``*@$``'@F```J`0``@"8``"H!``"()@``*@$``)`F -M```J`0``F"8``"H!``"@)@``*@$``*@F```J`0``L"8``"H!``"X)@``*@$` -M`,`F```J`0``R"8``"H!``#0)@``*@$``-@F```J`0``X"8``"H!``#H)@`` -M*@$``/`F```J`0``^"8``"H!````)P``*@$```@G```J`0``$"<``"H!```8 -M)P``*@$``"`G```J`0``*"<``"H!```P)P``*@$``#@G```J`0``0"<``"H! -M``!()P``*@$``%`G```J`0``6"<``"H!``!@)P``*@$``&@G```J`0``<"<` -M`"H!``!X)P``*@$``(`G```J`0``B"<``"H!``"0)P``*@$``)@G```J`0`` -MF"<```"$"@"@)P``*@$``*@G```J`0``L"<``"H!``"X)P``*@$``,`G```J -M`0``R"<``"H!``#0)P``*@$```0````"&`L`#`````(8"P`4`````A@+`!P` -M```"&`L`)`````(8"P`L`````A@+`'0````"W`P`?`````*(#@"$`````A\. -M`(P````"6@L`E`````+J"@"<`````I(+`*0````"!P\`K`````+Z"0!L`0`` -M`OD-`+P!```"4PL`Q`$```*;#@#,`0```N\)`-0!```"HPX`W`$```+_"@#D -M`0```G,,`.P!```"^PL`]`$```++#``,`@```BX*`!P"```"+@H`;`(```)S -M"P!T`@```FX.`'P"```"H@H`C`(```+*"P"D`@```FD-`*P"```"RPH`4`0` -M``(#``!4!````@H,`%P$```"`P``8`0```)>#@!H!````@,``&P$```"DPX` -M=`0```(#``!X!````GP*`(`$```"`P``A`0```+V"P",!````@,``)`$```" -M"@P`F`0```(#``""(` -M``(U"`!\(@```J('`(`B```"E`<`A"(```*6!P"((@```I@'`(PB```"H@<` -MD"(```*B!P"4(@```J('`)@B```"F@<`G"(```(;"`"@(@```M0'`*0B```" -MH@<`J"(```*"0`0)``` -M`H<)`!0D```"&PD`&"0```*!"0`@)````L@(`"@D```"Q@@`1"0```(-``!( -M)````@T``'`D```"#0``="0```(-``!8+````@,``%PL```"`P``8"P```(# -M``!D+````@,``&@L```"`P``;"P```(#``!P+````@,``'0L```"`P``>"P` -M``(#``!\+````@,``(`L```"`P``A"P```(#``"(+````@,``(PL```"`P`` -MD"P```(#``"4+````@,``)@L```"`P``G"P```(#``"@+````@,``*0L```" -M`P``J"P```(#``"L+````@,``+`L```"`P``M"P```(#``"X+````@,````` -M```````````````````````````````````#``$``````````````````P`# -M``````````````````,`!0`````````````````#``8````````````````` -M`P`(``````````````````,`"@`````````````````#``P````````````` -M`````P`.``````````````````,`#P`````````````````#`!$````````` -M`````````P`3``````````````````,`%``````````````````#`!8````` -M`````````````P`8``````````````````,`&0`````````````````#`!H` -M`````````````````P`;``$```````````````0`\?\+```````````````` -M``$`"P````0````````````!``L````(`````````````0`+````A``````` -M``````$`"P```)0````````````!``L```"<`````````````0`+````Q``` -M``````````$`"P```.P````````````!``L````,`0```````````0`+```` -M+`$```````````$`"P```'P!```````````!``L```",`0```````````0`+ -M````*`(```````````$`"P```$P"```````````!``L````P!``````````` -M`0`+````C`0```````````$`"P```/`$```````````!``L```!,!0`````` -M`````0`+````6`4```````````$`#@```(0%```````````!``L```"&\```````````$`"P`` -M`.!O```````````!``L````D<````````````0`+````A'````````````$` -M"P```,!Q```````````!``X```!0<@```````````0`+````9'(````````` -M``$`"P```$!S```````````!``X```#0`X```0````!``,`5@(``'P.```$`````0`#`&("``"`#@``!`````$` -M`P!N`@``A`X```0````!``,`>@(``/`#```$`````0`6``X```#P`P`````` -M````%@"(`@``]`,```@````!`!8`EP(`````````````!`#Q_PL```#`=0`` -M`````````0`+````]'4```````````$`"P```/QU```````````!``L````` -M=@```````````0`+````"'8```````````$`"P```#AV```````````!``L` -M```\=@```````````0`+````0'8```````````$`"P```$1V```````````! -M``L```#\=@```````````0`+````:'<```````````$`"P```&QW```````` -M```!``L```!D>````````````0`+````:'@```````````$`"P```.!X```` -M```````!``L```"$>0```````````0`+````L'D```````````$`"P```$QZ -M```````````!``L```#`>P```````````0`;````B`X```````````,`"P`` -M`$Q]```````````!``X```"L?0```````````0`+````*'X```````````$` -M"P```"Q_```````````!`*("``"P@```\`````(``0`+````L(`````````` -M``$`L@(``*"!``"(`@```@`!``L```"@@0```````````0`+````*(0````` -M``````$`"P```(R$```````````!``L````@A0```````````0#!`@``+(4` -M`#`````"``$`"P```"R%```````````!``L```!(L```````````$`"P```,"+```````````!``L` -M```8C0```````````0`+````=(T```````````$`"P```.2/```````````! -M`)X````$#```````````&``+````")4```````````$`"P```%R6```````` -M```!``L````0EP```````````0`+````$)D```````````$`"P```(29```` -M```````!``L```#`F0```````````0`+````3)P```````````$`"P```*R> -M```````````!``L```!LGP```````````0`+````>)\```````````$`"P`` -M`/B?```````````!``L````$H````````````0`+````H*````````````$` -M"P```*R@```````````!``L```"XH@```````````0`+````)*,````````` -M``$`"P```'BD```````````!``L```"8I````````````0`+````T*0````` -M``````$`"P```-RD```````````!``L```"PI0```````````0#7`@``B`X` -M``<````!``,`#@```(@.```````````#`.,"```$#````0````$`&`#O`@`` -M```````````$`/'_"P```+RE```````````!`/X"````I@``]`````(``0`+ -M`````*8```````````$`#@```""F```````````!``L```#,X```````````$`"P```.31```` -M```````!``L```!\T@```````````0`+````B-,```````````$`"P```-#4 -M```````````!``L````@U0```````````0`+````+-8```````````$`"P`` -M`%S8```````````!``L```"\V@```````````0`.````G-L```````````$` -M"P```*#;```````````!``L`````0`````````! -M``L```!T7@$``````````0`.````%%\!``````````$`"P```"1?`0`````` -M```!``L```#L7P$``````````0`+`````&$!``````````$`"P```'QA`0`` -M```````!``L````88@$``````````0`.````+&(!``````````$`"P```-!C -M`0`````````!``L````P9`$``````````0`+````A&0!``````````$`"P`` -M`-!D`0`````````!``L```#D9`$``````````0`+````+&4!``````````$` -M"P```&1E`0`````````!``L```"@90$``````````0`+````M&4!```````` -M``$`"P```,!E`0`````````!``L```#090$``````````0`+````2&8!```` -M``````$`"P```$1G`0`````````!``L```!(9P$``````````0`+````>&@$``````````0`.```` -M_`4``````````!8`"`4`````````````!`#Q_PL```#,>@$``````````0`+ -M````$'L!``````````$`"P```+A[`0`````````!``L```!,?`$````````` -M`0`+````K'T!``````````$`"P```"1^`0`````````!``L```"X?@$````` -M`````0`;````J`<``````````!8`#@```-B``0`````````!``L```#D@`$` -M`````````0">````V!(```````````,`"P```+B"`0`````````!``L```"P -MA`$``````````0`+````3(4!``````````$`"P```%B%`0`````````!``L` -M``#$AP$``````````0`+````F(@!``````````$`"P```/B(`0`````````! -M``L```#0B0$``````````0`.````:(H!``````````$`"P```'B*`0`````` -M```!``X```#DB@$``````````0`+````](H!``````````$`#@```*R,`0`` -M```````!``L```"\C`$``````````0`.````_(P!``````````$`"P```!"- -M`0`````````!``L```"(C0$``````````0`.````^(T!``````````$`"P`` -M``R.`0`````````!``L```!PC@$``````````0`+````*)`!``````````$` -M"P```*R0`0`````````!``L````DD0$``````````0`+````G)$!```````` -M``$`"P```$B2`0`````````!``L````DE@$``````````0`+````-)`0`````````!``L```"0G@$``````````0`+ -M````2*`!``````````$`"P```"RA`0`````````!``L```!HH0$````````` -M`0`+````@*$!``````````$`"P```*BA`0`````````!``L```#HH0$````` -M`````0`+````\*(!``````````$`$P4``*@'```&`````0`6``X```"H!P`` -M````````%@`F!0``L`<```(````!`!8`.`4``+0'```"`````0`6`%4%``"X -M!P``!@````$`%@!N!0`````````````$`/'_"P```!BC`0`````````!``L` -M```@HP$``````````0`;````X!(```````````,`"P```"2D`0`````````! -M``X```!`0`````````!``L```#T -MW@$``````````0`+````_-X!``````````$`"P````3?`0`````````!``L` -M``#\WP$``````````0`.````%.$!``````````$`"P```!CA`0`````````! -M``L```"PXP$``````````0`6````?`,```````````4`[0$``(0#```````` -M```%`"P&``!LZ0$`,`````(``0!%!@``3.D!`"`````"``$`908``*SI`0"H -M`````@`!``L```"@YP$``````````0`;````)!,```````````,`"P````#I -M`0`````````!`'\&``"!P``"#D"`!0````"``$`"P````0O`@`` -M```````!``L````L+P(``````````0`+````<"\"``````````$`"P`````P -M`@`````````!``L```"4,`(``````````0`+````$#$"``````````$`"P`` -M`,`Q`@`````````!``L```#$,0(``````````0">````3#0``````````!@` -M#@```,0R`@`````````!``L```#(,@(``````````0`+````/#,"```````` -M``$`"P```,PU`@`````````!``L```!8.`(``````````0`+````"#D"```` -M``````$`"P```!PY`@`````````!``L```#@.0(``````````0`+````\#D" -M``````````$`"P```-`Z`@`````````!``L```"D.P(``````````0`.```` -M5!0``````````!@`ZP<`````````````!`#Q_PL```!\/`(``````````0`+ -M````F#P"``````````$`"P```+0\`@`````````!``L```#0/`(````````` -M`0`+````[#P"``````````$`"P````@]`@`````````!``L````D/0(````` -M`````0`+````0#T"``````````$`"P```(`]`@`````````!``L```"H/0(` -M`````````0`+````Q#T"``````````$`]@<`````````````!`#Q_PL```#@ -M/0(``````````0`+````]#T"``````````$```@`````````````!`#Q_PL` -M```P/@(``````````0`+````4#X"``````````$`#@```'0^`@`````````! -M``L````@0`(``````````0`+````[$`"``````````$`#@```/A``@`````` -M```!``L````400(``````````0`+````=$$"``````````$`#@```(!!`@`` -M```````!``L```"<00(``````````0`4"```_$$"`"`````"``$`"P```/Q! -M`@`````````!``L````<0@(``````````0`+````($("``````````$`-@@` -M`#!<`@`P`````@`!`$T(``#,80(`_`````(``0!H"```&&`"```!```"``$` -M@@@``.A?`@`P`````@`!`)4(``!(5`(`(`````(``0"R"````%,"`"`````" -M``$`S@@```Q<`@`D`````@`!`.L(```D4`(`)`````(``0`+````.$,"```` -M``````$`"P```%A#`@`````````!``L```"P0P(``````````0`+````[$," -M``````````$`"P````Q$`@`````````!``L````\1`(``````````0`+```` -M8$0"``````````$`"P```-Q$`@`````````!``L````810(``````````0`+ -M````'$4"``````````$`"P```$Q%`@`````````!``L```"\10(````````` -M`0`+````^$4"``````````$`"P```)!+`@`````````!``L````43`(````` -M`````0`+````3$P"``````````$`"P```(!,`@`````````!``L````D30(` -M`````````0`."0``1$T"`.`"```"``$`"P```$1-`@`````````!``L````D -M4`(``````````0`K"0``2%`"`+@"```"``$`"P```$A0`@`````````!``L` -M````4P(``````````0!'"0``(%,"`"@!```"``$`"P```"!3`@`````````! -M``L```!(5`(``````````0!E"0``:%0"`-P````"``$`"P```&A4`@`````` -M```!`'\)``!$50(`R`8```(``0`+````1%4"``````````$`"P````Q<`@`` -M```````!``L````P7`(``````````0"<"0``8%P"`(@#```"``$`"P```&!< -M`@`````````!``X```#D7P(``````````0`+````Z%\"``````````$`"P`` -M`!A@`@`````````!`+()```880(`>`````(``0`+````&&$"``````````$` -M"P```)!A`@`````````!``L```#,80(``````````0`+````R&("```````` -M``$`Q`D``&QC`@`L`0```@`!``L```!L8P(``````````0#0"0``F&0"`$P` -M```"``$`"P```)AD`@`````````!``L```#D9`(``````````0#;"0`````` -M```````$`/'_[0D``/!G`@`P`````@`!``L```#P9P(``````````0`+```` -M(&@"``````````$`"P```"1H`@`````````!``L```#,:@(``````````0`+ -M````U&H"``````````$``PH``-QJ`@`X`````@`!``L```#<:@(````````` -M`0`;````?!,```````````,`"P```!1K`@`````````!``L````X:P(````` -M`````0`+````L&L"``````````$`"P```)!N`@`````````!``L```#4;@(` -M`````````0`+````8&\"``````````$`"P```&1O`@`````````!``L```!H -M;P(``````````0`+````C&\"``````````$`"P```)!O`@`````````!``L` -M``"8;P(``````````0`+````%'`"``````````$`"P```%QP`@`````````! -M`!4*```$<0(`G`````(``0`+````!'$"``````````$`"P```*!Q`@`````` -M```!``L```#@<0(``````````0`+````O',"``````````$`"P```.!S`@`` -M```````!``L```"`=`(``````````0`+````C'0"``````````$`"P```.1W -M`@`````````!`"H*```@>`(`@`$```(``0`+````('@"``````````$`"P`` -M`*!Y`@`````````!``L````8>@(``````````0`+````]'H"``````````$` -M"P```!A[`@`````````!``X```"0>P(``````````0`+````H'L"```````` -M``$`#@```%1\`@`````````!`#L*``!\$P``(`````$``P`.````?!,````` -M``````,`1@H``)P3```@`````0`#`%$*``"\$P``$`````$``P`.````Q`<` -M`````````!8`70H`````````````!`#Q_PL```!8?`(``````````0`+```` -M7'P"``````````$`"P```!1]`@`````````!``X```!X?0(``````````0`+ -M````B'T"``````````$`"P```/Q_`@`````````!`!L```!D-``````````` -M&``+````%(`"``````````$`"P```$"``@`````````!``L```!<@`(````` -M`````0`+````>(`"``````````$`"P```-"``@`````````!``L````H@0(` -M`````````0`+````@($"``````````$`"P```/2!`@`````````!``L````X -M@@(``````````0`+````O(("``````````$`"P```%"#`@`````````!``L` -M``"4@P(``````````0`.````!(0"``````````$`"P```!2$`@`````````! -M``X```!`A0(``````````0`+````4(4"``````````$`"P```-B%`@`````` -M```!``L````HB`(``````````0">````S!,```````````,`#@```,R*`@`` -M```````!`&\*``#,$P``#`````$``P`.````S!,```````````,`>PH``-@3 -M```,`````0`#`(<*``!D-```\`,```$`&`"1"@`````````````$`/'_"P`` -M`-"*`@`````````!``L```!0BP(``````````0`+````T(L"``````````$` -M"P```.R+`@`````````!``L```!@C0(``````````0`+````H(X"```````` -M``$`GPH`````````````!`#Q_PL````)L"``````````$`"P```/2;`@`````````!`!L```#D -M$P```````````P`+````])T"``````````$`"P```&"B`@`````````!``L` -M``"LH@(``````````0#/"@``Y!,```8````!``,`#@```.03```````````# -M`-L*``````````````0`\?\+````'*,"``````````$`"P```%RF`@`````` -M```!``L```!@I@(``````````0`+````9*8"``````````$`"P```&BF`@`` -M```````!``L```!LI@(``````````0`+````\*8"``````````$`Z0H``/2F -M`@!X`````@`!``L```#TI@(``````````0`&"P``;*<"``@````"``$`"P`` -M`&RG`@`````````!``L```!TIP(``````````0`8"P``Y*L"`%P````"``$` -M"P````BI`@`````````!`"X+```\J@(`J`$```(``0`+````/*H"```````` -M``$`&P```.P3```````````#``L```#DJP(``````````0!%"P``0*P"`,0` -M```"``$`"P```$"L`@`````````!`%L+```$K0(`G`````(``0`+````!*T" -M``````````$`"P```*"M`@`````````!`&H+``#\K0(`E`````(``0`+```` -M_*T"``````````$`=PL``)"N`@`H`````@`!``L```"0K@(``````````0`+ -M````N*X"``````````$`"P```""O`@`````````!``L```#\KP(````````` -M`0`.````(+`"``````````$`"P```.BP`@`````````!``L```"DL0(````` -M`````0`+````4+,"``````````$`#@```'2S`@`````````!``L```"LLP(` -M`````````0`.````5+4"``````````$`CPL``%BU`@!\`````@`!``L```!8 -MM0(``````````0`+````U+4"``````````$`#@````"V`@`````````!``L` -M```(MP(``````````0`+````<,,"``````````$`"P```(##`@`````````! -M``L````0Q0(``````````0`+````E,4"``````````$`"P```-C+`@`````` -M```!``X```#8U0(``````````0"J"P``[!,```8````!``,`#@```.P3```` -M```````#`+8+``#T$P``!@````$``P#!"P``_!,```0````!``,`S0L````4 -M```(`````0`#`-@+```(%```"`````$``P#C"P``$!0```@````!``,`[@L` -M````````````!`#Q__X+``#!0#``0````"``$`"P```'@4`P`` -M```````!``L```!\%`,``````````0`+````D!0#``````````$`+0T``)0= -M`P!``````@`!`#<-``!0'0,`1`````(``0!"#0``#!T#`$0````"``$`30T` -M`-0=`P"X`0```@`!`%L-``#0'`,`/`````(``0!F#0``E!P#`#P````"``$` -M<@T``%@<`P`\`````@`!`'X-``#P&P,`:`````(``0")#0``C!@#`!P````" -M``$`G@T``'`8`P`<`````@`!`+(-````%@,`2`````(``0#'#0``4!4#`+`` -M```"``$`"P```%`5`P`````````!``L`````%@,``````````0#=#0``2!8# -M`"@"```"``$`"P```$@6`P`````````!``X```#<%@,``````````0`+```` -M^!8#``````````$`[`T``*@8`P!8`0```@`!`!L```!4.```````````&``+ -M````$$#``````````$`"P```"!"`P`````````!``L```!L0@,````` -M`````0`+````W$(#``````````$`"P```"1%`P`````````!``L```!T10,` -M`````````0`+````&$8#``````````$`#@```&15`P`````````!``L```"P -M50,``````````0`.````W%4#``````````$`"P```.Q5`P`````````!`-$. -M``!H"P``````````!0#7#@``B`L```````````4`W0X``)`+```````````% -M`.,.``"L"P``````````!0#I#@``X`L```````````4`#@```$!7`P`````` -M```!``L```!@5P,``````````0`.````D%X#``````````$`"P```,1>`P`` -M```````!``X````D8@,``````````0`+````2&(#``````````$`#@```!QP -M`P`````````!``L```!X<`,``````````0`.````\',#``````````$`"P`` -M`"!T`P`````````!``X```#L>P,``````````0`+````-'P#``````````$` -M#@```#R'`P`````````!``L```"8AP,``````````0">````'`@````````` -M`!8`"P```#R)`P`````````!``X```#`B@,``````````0`+````Y(H#```` -M``````$`#@```/B-`P`````````!``L````DC@,``````````0`.````9(\# -M``````````$`"P```(2/`P`````````!``L```#LCP,``````````0`+```` -M!)`#``````````$`"P```"B0`P`````````!``L````\D`,``````````0#O -M#@``-!0```````````4`"P```'"0`P`````````!``X```"DD@,````````` -M`0`+````J)(#``````````$`"P```,R2`P`````````!``X````@DP,````` -M`````0`+````)),#``````````$`"P```%B3`P`````````!``L```#0DP,` -M`````````0`.````-)0#``````````$`"P```#B4`P`````````!``X```"@ -ME`,``````````0`+````I)0#``````````$`"P```-R4`P`````````!``L` -M``!$E0,``````````0`.````L!0```````````,`]0X``'`5``!``````0`# -M``$/``"P%0``'P````$``P`0#P``T!4``!$````!``,`'P\``.05```@```` -M`0`#`"X/```$%@``#@````$``P`]#P``%!8```@````!``,`3`\``!P6```8 -M`````0`#`%L/```T%@``%@````$``P!J#P``3!8``!8````!``,`>0\``&06 -M```3`````0`#`(@/``!X%@``$@````$``P"7#P``C!8``!$````!``,`I@\` -M`*`6```&`````0`#`+(/``"H%@``&`````$``P"^#P``P!8``!@````!``,` -MR@\``-@6```8`````0`#``X````<"```````````%@#6#P`````````````$ -M`/'_"P```+25`P`````````!`!L```#P%@```````````P`+````5)8#```` -M``````$`#@```'"7`P`````````!`.$/``#P%@``.P````$``P`.````\!8` -M``````````,`[0\``"P7```3`````0`#`/P/``````````````0`\?\+```` -MD)<#``````````$`#@```(B9`P`````````!``X```"8"P``````````%@`0 -M$``````````````$`/'_(Q```(R9`P!@`````@`!``L```",F0,````````` -M`0`+````[)D#``````````$`#@```*R;`P`````````!``L```"PFP,````` -M`````0`.````@)T#``````````$`"P```(2=`P`````````!``X```!$GP,` -M`````````0`.````8`X``````````!8`,A``````````````!`#Q_PL```!( -MGP,``````````0`.````.*$#``````````$`#@```&`8```````````6`$40 -M``````````````0`\?\.````0!<```````````,`6!``````````````!`#Q -M_PL````\H0,``````````0`+````1*$#``````````$`"P```$BA`P`````` -M```!`(<#``!@%0``````````!0""`P``6!4```````````4`#@```.RB`P`` -M```````!``L````0HP,``````````0`;````U%````````````,`<`<``,05 -M```````````%`'@#```@%0``````````!0!S`P``%!4```````````4`#@`` -M`,"G`P`````````!``L```#DIP,``````````0`.````O*H#``````````$` -M"P```."J`P`````````!``X````$K`,``````````0`+````)*P#```````` -M``$`"P```%2N`P`````````!``X```"XKP,``````````0`+````V*\#```` -M``````$`#@````BQ`P`````````!``L````HL0,``````````0#=#@``4!<` -M``````````4`UPX``$P7```````````%``X```!0L@,``````````0`+```` -M<+(#``````````$`#@```("S`P`````````!``L```"@LP,``````````0`. -M````!+4#``````````$`"P```"2U`P`````````!``X```!$M@,````````` -M`0`+````9+8#``````````$`:1```-@7```````````%`&\0``#0%P`````` -M````!0`.`````+H#``````````$`"P```"BZ`P`````````!``X```"$O@,` -M`````````0`+````L+X#``````````$`#@```&3&`P`````````!``L```"D -MQ@,``````````0`.````L-8#``````````$`"P````S7`P`````````!``L` -M``!0V`,``````````0`.````&.`#``````````$`"P```%C@`P`````````! -M``X```!@X0,``````````0`+````@.$#``````````$`#@```(CB`P`````` -M```!``L```"HX@,``````````0!U$````!P```````````4`>Q```%0<```` -M```````%``X```",\0,``````````0`+````S/$#``````````$`@1```,@= -M```````````%``X````,_@,``````````0`+````5/X#``````````$`#@`` -M`$C_`P`````````!``L```!H_P,``````````0"'$```Y!\```````````4` -M#@```*P/!``````````!``L````<$`0``````````0"-$```U%```!8````! -M``,`G!```.Q0```"`````0`#``X```#L4````````````P"H$```\%```!P` -M```!``,`MQ````Q1```8`````0`#`,80```D40``&P````$``P#5$```0%$` -M`!8````!``,`Y!```%A1```7`````0`#`/,0``!P40``$@````$``P`"$0`` -MA%$``!(````!``,`$1$``)A1```0`````0`#`"`1``"H40``&0````$``P`O -M$0``Q%$``!@````!``,`/A$``-Q1```8`````0`#`$T1``#T40``%`````$` -M`P!<$0``"%(``!`````!``,`:Q$``!A2```4`````0`#`'H1```L4@``&``` -M``$``P")$0``1%(``!8````!``,`F!$``%Q2``!``````0`#`*01``"<4@`` -M$`````$``P"P$0``K%(``"0````!``,`O!$``-!2```6`````0`#`,L1``#H -M4@``)`````$``P#7$0``#%,``!8````!``,`YA$``"13```8`````0`#`/41 -M```\4P``'@````$``P`!$@``7%,``!X````!``,`#1(``'Q3```O`````0`# -M`!P2``````````````0`\?\+````L!$$``````````$`#@````P3!``````` -M```!``L````L$P0``````````0`.````:!0$``````````$`"P```(@4!``` -M```````!``X```!,%00``````````0`+````;!4$``````````$`#@```"@6 -M!``````````!``L```!(%@0``````````0`+````]!8$``````````$`#@`` -M`,`7!``````````!``L```#@%P0``````````0`.````K!@$``````````$` -M,1(``*Q3```7`````0`#`$`2``#$4P``'@````$``P!/$@``Y%,``!<````! -M``,`7A(``/Q3```4`````0`#`&T2```05```&@````$``P!\$@``+%0``!H` -M```!``,`BQ(`````````````!`#Q_PL```#,&`0``````````0"B$@``J!D$ -M`&P!```"``$`"P```*@9!``````````!`!L```!(5````````````P`.```` -M]!H$``````````$`NQ(``!0;!`#0%````@`!``L````4&P0``````````0`. -M````""L$``````````$`"P```*`K!``````````!`)X```!4.``````````` -M&``+````Y"\$``````````$`#@```,PP!``````````!``L```#L,`0````` -M`````0`.````W#$$``````````$`"P```/PQ!``````````!``X```#L,@0` -M`````````0`+````##,$``````````$`#@```/PS!``````````!``L````< -M-`0``````````0`.````_#0$``````````$`"P```!PU!``````````!``X` -M``#D-00``````````0`+````!#8$``````````$`TA(``"0J```````````% -M`'@#```()0``````````!0!S`P``_"0```````````4`#@```"@Y!``````` -M```!``L````X.00``````````0`.````C#\$``````````$`"P```,0_!``` -M```````!``L```#8/P0``````````0`.````\$`$``````````$`"P```#!! -M!``````````!``X```#T1`0``````````0#8$@``2%0```P````!``,`#@`` -M`$A4```````````#`.L2``!45```&0````$``P#Z$@``<%0``!<````!``,` -M"1,``(A4```<`````0`#`!@3``"D5```.`````$``P`J$P``W%0``(H````! -M``,`.!,``&A5```<`````0`#`$T3``"$50``.`````$``P!=$P``O%4``!P` -M```!``,`;Q,``-A5```3`````0`#`'X3``#L50``.`````$``P"/$P``)%8` -M`!$````!``,`GA,``#A6```%`````0`#`+,3``!`5@``%0````$``P#"$P`` -M6%8``!P````!``,`T1,``'16```=`````0`#`.`3``"45@``&`````$``P#O -M$P``K%8``!0````!``,`_A,``,!6```3`````0`#``T4``#45@``&@````$` -M`P`<%```\%8```8````!``,`)Q0``/A6```8`````0`#`#84```05P``'``` -M``$``P!%%```+%<``!8````!``,`#@```%0X```````````8`%04``!4.``` -M`0````$`&`!T%``````````````$`/'_"P```"!%!``````````!``L````D -M100``````````0`+````0$4$``````````$`"P```$A%!``````````!``L` -M``!,100``````````0`.````'$8$``````````$`"P```#Q&!``````````! -M`-@%``#`+```````````!0!P!P``U"P```````````4`@Q0``.@L```````` -M```%``X```#L300``````````0`+````'$X$``````````$`#@```$1/!``` -M```````!``L```!H3P0``````````0`.````^%$$``````````$`"P```!A2 -M!``````````!``X```#H4P0``````````0`+````"%0$``````````$`#@`` -M`%Q5!``````````!``L```!\500``````````0")%```%"X```````````4` -MZ0X```PN```````````%``X```#85@0``````````0"/%```1%<``!<````! -M``,`GA0``%Q7```1`````0`#`*T4``!P5P``&0````$``P#F$0``C%<``!@` -M```!``,`O!0``*17```5`````0`#`,L4``"\5P``%`````$``P#:%```T%<` -M`!T````!``,`Z10`````````````!`#Q_PL```#\5@0``````````0`.```` -M:%<$``````````$`"P```'A7!``````````!`/@4``````````````0`\?\. -M````>!L``````````!8`"14`````````````!`#Q_PL````<6`0````````` -M`0`+````*%@$``````````$`"P```#18!``````````!``L```!(6`0````` -M`````0`+````8%@$``````````$`"P```'18!``````````!``L```"$6`0` -M`````````0`+````B%@$``````````$`"P```(Q8!``````````!``L```"0 -M6`0``````````0`+````E%@$``````````$`"P```+!8!``````````!``L` -M``#,6`0``````````0`+````V%@$``````````$`"P```.18!``````````! -M``L```#T6`0``````````0`+````!%D$``````````$`"P```"!9!``````` -M```!``L```!,600``````````0`+````;%D$``````````$`"P```'19!``` -M```````!``L```!\600``````````0`+````E%D$``````````$`"P```*Q9 -M!``````````!``L```#$600``````````0`+````W%D$``````````$`"P`` -M`/A9!``````````!``L````46@0``````````0`+````,%H$``````````$` -M&14``$Q:!`"(`````@`!``L```!,6@0``````````0`+````U%H$```````` -M``$`"P```.Q:!``````````!``L````$6P0``````````0`B%0``-%L$`#`` -M```"``$`"P```#1;!``````````!`"L5``!D6P0`%`````(``0`+````9%L$ -M``````````$`"P```'A;!``````````!``L```!H7`0``````````0`+```` -M[%P$``````````$`"P```&Q=!``````````!`!L```!8.```````````&``+ -M````N%T$``````````$`"P````1>!``````````!``L```!07@0````````` -M`0`1````/"X```````````4`"P```'!>!``````````!``L```!\7@0````` -M`````0`+````B%X$``````````$`"P```+!>!``````````!``L```#<7@0` -M`````````0`+````Z%X$``````````$`"P```#!?!``````````!``L```!@ -M7P0``````````0`+````D%\$``````````$`%@```$@N```````````%``X` -M``"H7P0``````````0`+````K%\$``````````$`"P```,!?!``````````! -M``L```#,7P0``````````0`+````X%\$``````````$`"P```/1?!``````` -M```!``L`````8`0``````````0`+````Y&`$``````````$`"P```/!@!``` -M```````!``L````(800``````````0`+````&&$$``````````$`"P```$AA -M!``````````!``L```"D800``````````0`+````L&$$``````````$`"P`` -M`-AA!``````````!``L```#D800``````````0`+````%&($``````````$` -M#@```%@X```````````8`#45``!8.```2`````$`&`!&%0``H#@````````! -M`!@`4A4`````````````!`#Q_UT5``"$8@0`<`````(``0`+````A&($```` -M``````$`"P```/1B!``````````!``L```!$8P0``````````0`+````F&,$ -M``````````$`"P```%1D!``````````!``L````8900``````````0`+```` -M7&4$``````````$`"P```&!F!``````````!``L```#`9@0``````````0`+ -M````M&<$``````````$`"P```*AH!``````````!``L```#<:`0````````` -M`0`+````(&D$``````````$`&P```*`X```````````8`!8```",+@`````` -M````!0`.````[&L$``````````$`"P```/AK!``````````!`&\5``!$;`0` -M-`````(``0`+````1&P$``````````$`"P```'AL!``````````!`)X```#P -M5P```````````P!&`P``<"```````````!8`A<```Q:```5`````0`#`)07```D6@``%P````$``P"P%P``/%H` -M`!0````!``,`R1<``%!:```>`````0`#`.P7``!P6@``%@````$``P`'&``` -MB%H``!,````!``,`'Q@``)Q:```3`````0`#`#<8``"P6@``&`````$``P!4 -M&```R%H``!,````!``,`;!@``-Q:```3`````0`#`(08``#P6@``&`````$` -M`P"A&```"%L``!@````!``,`OA@``"!;```3`````0`#`-88```T6P``#@`` -M``$``P#I&```1%L``!0````!``,``AD````````$`````0`&``X````````` -M````````!@`0&0``["```"0````!`!8`#@```'`@```````````6`!\9```` -M````$`````$`"``.``````````````````@`.!D``!`````0`````0`(`%89 -M```@````$`````$`"`!M&0``,````!`````!``@`AQD``$`````0`````0`( -M`)X9``!0````$`````$`"`"R&0``8````!`````!``@`R1D``'`````0```` -M`0`(`-\9``"`````$`````$`"`#U&0``D````!`````!``@`"AH``*`````0 -M`````0`(`"$:``"P````$`````$`"``W&@``P````!`````!``@`5!H``-`` -M```0`````0`(`&P:``#@````$`````$`"`"`&@``\````!`````!``@`F1H` -M```!```0`````0`(`+(:```0`0``$`````$`"`#(&@``(`$``!`````!``@` -MX!H``#`!```0`````0`(`/4:``!``0``$`````$`"``4&P``4`$``!`````! -M``@`*QL``&`!```0`````0`(`#\;``!P`0``$`````$`"`!3&P``@`$``!`` -M```!``@`;!L``)`!```0`````0`(`(`;``"@`0``$`````$`"`"4&P``L`$` -M`!`````!``@`K1L``,`!```0`````0`(`,8;``#0`0``$`````$`"`#:&P`` -MX`$``!`````!``@`Z1L``/`!```0`````0`(`/X;``````````````0`\?\) -M'```)'$$`!P````"``$`"P```"1Q!``````````!``L```!`<00````````` -M`0`1````/"\```````````4`%@```(0O```````````%`!L````0(0`````` -M````%@`+````>'$$``````````$`&!P``(1Q!`"$`````@`!``L```"$<00` -M`````````0`G'```"'($`&`!```"``$`"P````AR!``````````!``X```!@ -M`0``````````0!;'```X'@$``P````"``$`"P`` -M`.!X!``````````!`&P<``#L>`0`9`(```(``0`+````['@$``````````$` -M1@,``%A;```````````#`'D<``"(>P0`5`$```(``0`.````2'L$```````` -M``$`"P```%![!``````````!``L```"(>P0``````````0"('```6%L``#`` -M```!``,`#@```%A;```````````#`)\<````````"`````$`"@`.```````` -M``````````H`QQP``#0````>`````0`.`.\<````````"`````$`#``.```` -M``````````````P`$QT````````:`````0`.`#<=```:````&@````$`#@!; -M'0``4@```!X````!``X`@QT``!`A``!T`````0`6``X````0(0`````````` -M%@"+'0``A"$``"@````!`!8`FAT````````(`````0`/``X````````````` -M````#P#"'0````````@````!`!$`#@`````````````````1`.8=```````` -M``````0`\?_T'0``W'P$`$`````"``$`"P```-Q\!``````````!`/X=```< -M?00`J`````(``0`+````''T$``````````$`$!X``,1]!``(`````@`!``L` -M``#$?00``````````0`@'@``S'T$`$P````"``$`"P```,Q]!``````````! -M`#`>```8?@0`&`````(``0`+````&'X$``````````$`0!X``#!^!``<```` -M`@`!``L````P?@0``````````0!/'@``3'X$`$P````"``$`"P```$Q^!``` -M```````!`%\>``"8?@0`'`````(``0`+````F'X$``````````$`;QX``+1^ -M!``<`````@`!``L```"T?@0``````````0"`'@``T'X$`!@````"``$`"P`` -M`-!^!``````````!`)$>``#H?@0`.`````(``0`+````Z'X$``````````$` -MH1X``"!_!``(`````@`!``L````@?P0``````````0"R'@``*'\$``@````" -M``$`"P```"A_!``````````!`+@>```P?P0`"`````(``0`+````,'\$```` -M``````$`U!X``#A_!``(`````@`!``L````X?P0``````````0#K'@``0'\$ -M``@````"``$`"P```$!_!``````````!``$?``!(?P0`"`````(``0`+```` -M2'\$``````````$`$!\``%!_!`!@`````@`!``L```!0?P0``````````0`+ -M````L'\$``````````$`"P```+1_!``````````!``L```"X?P0````````` -M`0`<'P``0(`$``@````"``$`"P```$"`!``````````!`"4?``!(@`0`A``` -M``(``0`+````2(`$``````````$`/!\``,R`!`#@`````@`!``L```#,@`0` -M`````````0`1`````#````````````4`11\``*R!!``H`0```@`!``L```"L -M@00``````````0!3'P``U(($`$0````"``$`"P```-2"!``````````!`!8` -M```$,```````````!0!B'P``&(,$`$`,```"``$`"P```!B#!``````````! -M`.T!```,,```````````!0!X`P``)#````````````4`AP,``#0P```````` -M```%`-@%``!(,```````````!0!S'P``7#````````````4`>1\``&0P```` -M```````%`-<.``!\,```````````!0#=#@``A#````````````4`XPX``*0P -M```````````%`(D4``"X,```````````!0!_'P``P#````````````4`:1`` -M`-0P```````````%`&X#```4,```````````!0"%'P``W#````````````4` -MBQ\``.0P```````````%`)$?``#P,```````````!0"7'P``^#`````````` -M``4`#@```"2/!``````````!`)T?``!8CP0`B`<```(``0`+````6(\$```` -M``````$`#@```+"6!``````````!`*X?``#@E@0`?`$```(``0`+````X)8$ -M``````````$`#@```&27!``````````!``L```"`EP0``````````0"]'P`` -M7)@$`#0````"``$`"P```%R8!``````````!`,T?``!D,0``````````!0#3 -M'P``D)@$`$@````"``$`"P```)"8!``````````!`.0?``#8F`0`U`$```(` -M`0`+````V)@$``````````$`]A\``'0Q```````````%`/P?``"LF@0```0` -M``(``0`+````K)H$``````````$`"2```(`Q```````````%``\@``"(,0`` -M````````!0`5(```E#$```````````4`&R```*`Q```````````%`"$@``"H -M,0``````````!0`G(```L#$```````````4`+2```*R>!``8`@```@`!``L` -M``"LG@0``````````0`Y(```O#$```````````4`/R```,0Q```````````% -M`$4@``#4,0``````````!0!+(```W#$```````````4`42```.PQ```````` -M```%`%<@``#X,0``````````!0!=(```'#(```````````4`8R```"0R```` -M```````%`&D@```P,@``````````!0!O(```/#(```````````4`=2```,2@ -M!``@`@```@`!``L```#$H`0``````````0"&(```Y*($`&P````"``$`"P`` -M`.2B!``````````!`)4@``!0HP0`X`H```(``0`+````4*,$``````````$` -MH2```%@R```````````%`*<@``!@,@``````````!0"M(```:#(````````` -M``4`=1```'@R```````````%`+,@``"$,@``````````!0"Y(```C#(````` -M``````4`>Q```)0R```````````%`+\@``"@,@``````````!0#%(```J#(` -M``````````4`RR```+`R```````````%`-$@``"X,@``````````!0#7(``` -MR#(```````````4`W2```-0R```````````%``X````HK@0``````````0#C -M(```,*X$`*@````"``$`"P```#"N!``````````!`/(@``#<,@`````````` -M!0#X(```V*X$`*P#```"``$`"P```-BN!``````````!``X````,KP0````` -M`````0`+````2*\$``````````$`!2$``(2R!``D`````@`!``L```"$L@0` -M`````````0`=(0``J+($`*@"```"``$`"P```*BR!``````````!`"TA``!0 -MM00`>`(```(``0`+````4+4$``````````$`/B$``,BW!`!8`0```@`!``L` -M``#(MP0``````````0"!$```Z#(```````````4`3"$``/`R```````````% -M`%(A``#X,@``````````!0!8(0```#,```````````4`7B$``""Y!`#X`0`` -M`@`!``L````@N00``````````0!M(0``&+L$`+`#```"``$`"P```!B[!``` -M```````!`(`A```(,P``````````!0`.````P+X$``````````$`AB$``,B^ -M!`!$`0```@`!``L```#(O@0``````````0`.````++\$``````````$`"P`` -M`#R_!``````````!`)DA```,,P``````````!0"?(0``%#,```````````4` -MI2$``!PS```````````%`*LA```,P`0`%`$```(``0`+````#,`$```````` -M``$`#@```#3`!``````````!``L```!@P`0``````````0"[(0``(,$$`!@$ -M```"``$`"P```"#!!``````````!``X```!\P@0``````````0`+````O,($ -M``````````$`#@```%C#!``````````!``L```"8PP0``````````0`;```` -MC%L```````````,`RB$``#C%!``8`````@`!``L````XQ00``````````0#< -M(0``4,4$`*@!```"``$`"P```%#%!``````````!`.PA``#XQ@0`5`$```(` -M`0`+````^,8$``````````$`#@```$C(!``````````!`/PA``!,R`0`-`$` -M``(``0`+````3,@$``````````$`#"(``"0S```````````%`!(B```T,P`` -M````````!0"'$```1#,```````````4`&"(``%0S```````````%`!XB``!D -M,P``````````!0`D(@``=#,```````````4`[PX``(0S```````````%`"HB -M``"4,P``````````!0`P(@``I#,```````````4`-B(``(#)!`!``0```@`! -M``L```"`R00``````````0">````K"$``````````!8`1R(``,#*!`!T```` -M`@`!``L```#`R@0``````````0!7(@``-,L$`)0+```"``$`"P```#3+!``` -M```````!`&8B``"T,P``````````!0!L(@``R#,```````````4`!``````````!``L```"TW@0````````` -M`0`.````P.H$``````````$`"P```-3J!``````````!`.,B``"LZP0`H`$` -M``(``0`+````K.L$``````````$`[B(``.PS```````````%`/0B``#T,P`` -M````````!0#Z(@``_#,```````````4``",``$SM!`"X`0```@`!``L```!, -M[00``````````0`1(P``!.\$`-@"```"``$`"P````3O!``````````!``X` -M``#8\00``````````0`A(P``W/$$`'@$```"``$`"P```-SQ!``````````! -M``X```!0\P0``````````0`+````L/,$``````````$`,2,````T```````` -M```%`#@C```(-```````````!0`_(P``$#0```````````4`1B,``!PT```` -M```````%`$TC```@-```````````!0!4(P``,#0```````````4`6R,``%@T -M```````````%`&(C``!@-```````````!0!I(P``9#0```````````4`<",` -M`&@T```````````%`'`````$` -M%@`5)``````````````$`/'_"P```"#X!``````````!``L````X^`0````` -M`````0`+````6/@$``````````$`"P```&CX!``````````!``L```!L^`0` -M`````````0`+````Z/D$``````````$`"P```/SZ!``````````!``L```"` -M^P0``````````0`+````V/L$``````````$`"P```/S[!``````````!``L` -M``!(_`0``````````0`+````P/P$``````````$`(B0`````````````!`#Q -M_PL````<_00``````````0`+````D/T$``````````$`"P````3^!``````` -M```!``L```!H_@0``````````0`+````D/X$``````````$`"P````3_!``` -M```````!``L````0_P0``````````0`+````'/\$``````````$`"P```"C_ -M!``````````!`!L````0.0``````````&``+````,``%``````````$`$0`` -M`'`T```````````%`!8```"$-```````````!0#M`0``C#0```````````4` -M"P```#P!!0`````````!``L```!L`04``````````0`.````O`$%```````` -M``$`"P```,`!!0`````````!``L``````@4``````````0`+````*`(%```` -M``````$`"P```#0"!0`````````!``X````0.0``````````&``O)```$#D` -M```$```!`!@`/R0`````````````!`#Q_PL```!``@4``````````0`+```` -M2`(%``````````$`"P```%P"!0`````````!``L```!@`@4``````````0`+ -M````9`(%``````````$`"P```(P"!0`````````!``L```"8`@4````````` -M`0`+````[`(%``````````$`"P```'@$!0`````````!``L```#)@``G`D%`"`````"``$`"P```)P)!0`````````! -M``X```"X"04``````````0`S)@``O`D%`"`````"``$`"P```+P)!0`````` -M```!``X```#8"04``````````0!;)@``W`D%`!P````"``$`"P```-P)!0`` -M```````!``X```#T"04``````````0"&)@``^`D%`"`````"``$`"P```/@) -M!0`````````!``X````4"@4``````````0"D)@``&`H%`"`````"``$`"P`` -M`!@*!0`````````!``X````T"@4``````````0#!)@``.`H%`*`````"``$` -M"P```#@*!0`````````!``X```#0"@4``````````0`+````V`H%```````` -M``$`````3",``````````!8`#@```,@-!0`````````!`"@G``#<#04`:``` -M``(``0`+````W`T%``````````$`#@```#P.!0`````````!`$XG``!$#@4` -M3`````(``0`+````1`X%``````````$`#@```(@.!0`````````!`&(@``H#T```````````4`#@```#!+!0`` -M```````!`.```>`````0`#`$(I``!07@``&`````$``P!1*0``:%X``!<` -M```!``,`8"D``(!>```8`````0`#`&\I``"87@``&0````$``P!^*0``M%X` -M`!@````!``,`C2D``,Q>```:`````0`#`)PI``#H7@``'`````$``P"K*0`` -M!%\``!D````!``,`NBD``"!?```8`````0`#`,DI```X7P``'0````$``P#8 -M*0``6%\``!4````!``,`YRD``'!?```5`````0`#`/8I``"(7P``*`````$` -M`P`%*@``L%\``"L````!``,`%"H``-Q?```>`````0`#`",J``#\7P``'0`` -M``$``P`R*@``'&```!L````!``,`02H``#A@```8`````0`#`%`J``!08``` -M%P````$``P!?*@``:&```!<````!``,`;BH``(!@```>`````0`#`'TJ``"@ -M8```#P````$``P",*@``L&```"@````!``,`#@```+1@```````````#`*TJ -M``#88```$`````$``P"_*@``Z&```"8````!``,`SBH``!!A```9`````0`# -M`-TJ```L80``&`````$``P#L*@``1&$``!4````!``,`^RH``%QA```=```` -M`0`#``HK``!\80``&P````$``P`9*P``F&$``!D````!``,`*"L``+1A```$ -M`````0`#`#0K``"X80``&`````$``P!#*P``T&$``!D````!``,`4BL``.QA -M```9`````0`#`&$K```(8@``&`````$``P!P*P``(&(``!@````!``,`?RL` -M`#AB```%`````0`#`(HK``!`8@``"0````$``P"5*P``3&(``!4````!``,` -MI"L``&1B```<`````0`#`+,K``"`8@``&@````$``P#"*P``G&(``!X````! -M``,`T2L``+QB```<`````0`#`.`K``#88@``@`````$``P#\*P``6&,``",` -M```!``,`"RP``'QC```A`````0`#`!HL``"@8P``)0````$``P`I+```R&,` -M`"4````!``,`."P``/!C```C`````0`#`$`0`(```` -M$@`!`*TO```0EP````(``!(``0#4+P`````````````0````W2\``-PG``!\ -M````$@`!`/(O``!TIP(`E`$``!(``0`(,```N!,``*0````2``$`&3```)A; -M`0`(````$@`!`"8P```LU@(`)````!(``0`],```;``!`&@````2``$`23`` -M`-0O`0`,`@``$@`!`&4P``!XV00`6````!(``0"!,```:*8"``0````2``$` -MCC```"RA`0`\````$@`!`)TP``#T;P$`,````!(``0"X,```!``H````$@`!`%8U```D30(`(``` -M`!(``0!I-0``*,L``%@````2``$`?#4```@```!\````$@`!`(LU``!,A0$` -M#````!(``0"A-0``_%@!`'`````2``$`M#4``#B4`P!L````$@`!`-4U``"D -MW@$`2````!(``0#P-0`````````````0````_#4``.`7!`#L````$@`!`!8V -M``!8^`0`$````!(``0`G-@``0'$$`#@````2``$`138`````````````$``` -M`%(V``#T>@(`)````!(``0!J-@`````````````0```````I````!(``0`Y-P``:+\!``@"```2``$`3#<` -M`.`T`P`<````$@`!`&@W``#<600`'````!(``0!Z-P``J#T"`!P````2``$` -MBS<``'".`0"X`0``$@`!`)PW```8HP$`"````!(``0"L-P``?(D``$@````2 -M``$`Q3<`````````````$````,XW``#,!`,`!````!(``0#G-P``_/L$`$P` -M```2``$``3@`````````````$`````HX```X:P(`>````!(``0`C.```A'D` -M`"P````2``$`-C@``!1K`@`D````$@`!`$@X``#X2@``(````!(``0!4.``` -M5!0```$````1`!@`8C@``"P_`0"4`0``$@`!`'`X``!<900`!`$``!(``0"` -M.```J%H!`#0````2``$`CS@``)!8!``$````$@`!`*(X``#T7P0`#````!(` -M`0"N.```'/\$``P````2``$`P#@``&P!!0!4````$@`!`-HX``"((```!``` -M`!$`%@#J.``````````````0`````3D``+!>!``L````$@`!``\Y``!XGP`` -M@````!(``0`G.0``7"4!`"0%```2``$`/#D``.SR``!\````$@`!`$PY```4 -M00,`3````!(``0!G.0``7`T"`+@````2``$`=SD```!``P`$````$@`!`(LY -M```0Q0(`A````!(``0"@.0``W)0#`&@````2``$`KSD``-`\`@`<````$@`! -M`+LY``!8*`````0``!$`&`#..0``P'4``#0````2``$`V#D``!1B!`!P```` -M$@`!`.LY`````````````!````#].0``M)4#`*`````2``$`&3H``#A<`0`D -M````$@`!`#@Z`````````````!````!;.@``N'L!`)0````2``$`;CH``,"9 -M``",`@``$@`!`(@Z``#0!0```P```!$`%@"6.@``2+@``!P````2``$`ISH` -M``@]`@`<````$@`!`+!L``%@````1`!8`ZCP``)BD```X````$@`!`/X\ -M```HL0,`2`$``!(``0`0/0`````````````0````)#T``,P@```$````$0`6 -M`#(]``"@K0(`7````!(``0!(/0``A%P!`!P````2``$`6ST``#@.``"P```` -M$@`!`&\]``!H(0``M`$``!(``0""/0``8%<#`&0'```2``$`HCT``/PT`P"4 -M`0``$@`!`+T]``"P%```P````!$``P#-/0``+$X``&P````2``$`W3T``/A% -M`@"8!0``$@`!`/0]``!()P,`-````!(``0`!/@``J-\``*@!```2``$`%#X` -M`$A%!``$````$@`!`"H^``#0I```#````!(``0`]/@``B%L```0````1``,` -M3#X``$C\!`!X````$@`!`&<^``",`0``G````!(``0"'/@``E)D!`*`````2 -M``$`H3X``,@5``"@````$@`!`+(^``"LJ`$`<````!(``0#(/@``[(\#`!@` -M```2``$`X3X``.Q``@"(````$@`!```_`````````````!`````#/P``\`0` -M`!`````1`!8`#S\``%2N`P"$`0``$@`!`"4_``#`0`$`]````!(``0`P/P`` -MV"D#`$P````2``$`1S\``/PX```$````$0`8`%8_``#,:@(`"````!(``0!X -M/P``/*$#``@````2``$`C3\``/@!``#X`0``$0`6`)X_````00,`!````!(` -M`0"U/P``>(`"`%@````2``$`TS\``+P&`P"4````$@`!`.T_``",K0$`,``` -M`!(``0`50```W%@!`"`````2``$`*4```#18!``4````$@`!`#M````'$$``P````2``$` -M`D(``!`G`P`(````$@`!`!%"```8900`1````!(``0`@0@``0!<``)0Y```1 -M``,`,T(``*2Y``"D`P``$@`!`$%"``"P;```:````!(``0!-0@`````````` -M```0````4T(``/!1!0`H`P``$@`!`&A"``!H3P0`L`(``!(``0"`0@``A*T` -M`#0````2``$`CT(``%R``@`<````$@`!`*M"``!T+0(`5````!(``0#$0@`` -MX%\$`!0````2``$`T$(``.BO```<`0``$@`!`.)"```81@,`F`\``!(``0`! -M0P``7!8!`/0#```2``$`#4,``"!T`P`4"```$@`!`"-#``#L/P,`!````!(` -M`0`X0P``)#T"`!P````2``$`2D,`````````````$````%Q#``"4IP$`N``` -M`!(``0!Q0P``>`0%`&0!```2``$`B4,``"23`P`T````$@`!`*%#```DD0$` -M>````!(``0"]0P``$`0```0````1`!8`TT,``#`^`@`@````$@`!`/-#``#< -MI```U````!(``0`'1```Q%D$`!@````2``$`$D0``.BA`0`(`0``$@`!`"9$ -M``#4;@(`C````!(``0!`1```M%<``'`````2``$`7$0``.@1`P`@````$@`! -M`'5$``"080(`/````!(``0"#1```S#D#`&@!```2``$`DT0``*"H```(```` -M$@`!`)Q$``!4K`$`[````!(``0"O1```X&\``$0````2``$`N$0``-`<``"H -M````$0`6`-)$```L^P``0`4``!(``0#?1```3)P``&`"```2``$`_40``"PD -M```,````$@`!``]%```<_00`=````!(``0`O10``%'`"`$@````2``$`144` -M`*!1`0`$`@``$@`!`$Y%``#L&0``+`(``!(``0!>10``<)`#`#@"```2``$` -M=44``+RG``!X````$@`!`(9%``#T004`Z````!(``0"M10``!"\"`"@````2 -M``$`OD4``(0@```$````$0`6`,U%```0HP,`U`0``!(``0#I10``(*,!``0! -M```2``$`^44``(!T`@`,````$@`!``M&``"4LP$`H`(``!(``0`N1@``=!,! -M`.@"```2``$`0$8``,@L`@`L````$@`!`%!&``#4#`$`P````!(``0!O1@`` -MH%L!`#`````2``$`BD8``.1,```D````$@`!`)Q&``!(2```Q````!(``0"L -M1@``>&\``&@````2``$`N$8``"Q'!0"(````$@`!`-A&``"X)P,`&````!(` -M`0#J1@``F(<#`*0!```2``$`_T8``,![``",`0``$@`!`!5'``#8#P``E``` -M`!(``0`K1P``Z)H!`%`````2``$`1$<`````````````$````%]'``#4Z@0` -MV````!(``0!P1P``E"````0````1`!8`@4<``$PH`P`0````$@`!`(Y'``"0 -M6`$`3````!(``0"D1P``3'H``'0!```2``$`MD<``&!F!`!@````$@`!`,M' -M``"L.```!````!$`&`#<1P``!%L$`#`````2``$`_4<```25`@`$````$@`! -M`!1(``#D800`,````!(``0`B2```9+@``"`````2``$`-$@``&P0``"P```` -M$@`!`$A(``!\600`&````!(``0!32```'*,"`$`#```2``$`<4@``*`@```$ -M````$0`6`'Y(```4+`(`6````!(``0"<2```T&0!`!0````2``$`K$@``.@X -M```$````$0`8`+I(``"H9P$`6````!(``0#,2```B%@$``0````2``$`W$@` -M````````````$````/)(```,,P0`$`$``!(``0`*20``O-H``.0````2``$` -M&$D``%B8`@`@`0``$@`!`#-)``!D;P(`!````!(``0!020``L`L!`"0!```2 -M``$`7DD``#`$```$````$0`6`'Y)````````!````!(``0"120``2+`!`$P# -M```2``$`I$D``*@=``"<````$@`!`+5)``!@7P0`,````!(``0#%20``Y&0! -M`$@````2``$`UDD``*BH``!\````$@`!`.1)``#4!```!````!$`%@#L20`` -M<'`!`"0!```2``$``DH``-3:`0#T````$@`!`!9*```P9`$`5````!(``0`H -M2@```"D#``@````2``$`8TH``+!'`0#P"0``$@`!`&Y*``#\`P``!````!$` -M%@"$2@``+`0```0````1`!8`FTH``-`$```$````$0`6`*=*```\80``*``` -M`!(``0"U2@``R"T"`"0````2``$`STH``+"$`0"<````$@`!`.-*```L`0`` -M4````!(``0#T2@``./@$`"`````2``$`!DL``)P````H````$@`!`!]+```` -M:`$`E````!(``0`W2P``!%L!`!P````2``$`14L``%!P`0`@````$@`!`%M+ -M``#\/P,`!````!(``0!N2P``B-,``$@!```2``$`A4L``/QU```$````$@`! -M`*!+``#\?P(`&````!(``0"Q2P``5(H``%@````2``$`RDL``$1G`0`$```` -M$@`!`-U+```P!```7````!(``0#V2P`````````````0````_$L``%"S`@`( -M`@``$@`!`!%,``"830``<````!(``0`C3```?%4$`(`!```2``$`0$P``)AY -M`0"<````$@`!`$Q,``!07@0`(````!(``0!B3```C"@#`!`````2``$`<4P` -M`/A9!``<````$@`!`(-,``!<*`,`$````!(``0"13``````````````0```` -MH$P``!P1``"4````$@`!`+!,``!T6`0`$````!(``0"_3```R&@!`#0````2 -M``$`SDP``+QJ`0#D````$@`!`.-,``"@YP$`8`$``!(``0#R3```E,4"`$0& -M```2``$`!DT``$Q``P"T````$@`!`!--``"8;@``X````!(``0`B30``]&($ -M`%`````2``$`-4T``,@@```$````$0`6`$I-```D,P$`C`8``!(``0!@30`` -M/`$%`#`````2``$`>TT``$1W!`!L`0``$@`!`(I-``!8)`````0``!$`&`"9 -M30`````````````0````J4T``.S_`0`8`0``$@`!`,)-``",60$`4````!(` -M`0#/30``[(L"`'0!```2``$`Y4T```20`P`D````$@`!`/I-``!TC0``<`(` -M`!(``0`53@``)*D``!0````2``$`(4X``'P_`P`$````$@`!`#U.```````` -M`````!````!73@``"&$$`!`````2``$`8TX``/`%```#````$0`6`'%.``#@ -M!`!(````$@`!`-U/``",;P(`!````!(``0#U3P``]%H``.P!```2``$` -M"5```(#[!`!8````$@`!`!U0`````````````!`````N4```V&```!P````2 -M``$`/E```*0^`P`<````$@`!`$Q0`````````````!````!=4```Q(D```P` -M```2``$`=5```+!K`@#@`@``$@`!`(A0``!XS@``;`,``!(``0"84```C(0` -M`)0````2``$`JE```"B>`0!H````$@`!`,-0``"<*`,`$````!(``0#14``` -M[`0#`"@````2``$`Y5```*"9`@#8`0``$@`!`/]0``!U(``.0O!``(`0`` -M$@`!`)!2```TF`(`)````!(``0"O4@``L!$$`'P!```2``$`QE(``-`E`P`$ -M`0``$@`!`-A2``",S0$`H````!(``0#J4@``,%$%`#P````2``$``E,``!A+ -M```@````$@`!``Y3``"DQ@,`K!$``!(``0`>4P`````````````0````*E,` -M````````````$````#13`````````````!````!$4P``+"H#`#@'```2``$` -M95,``(!,`@"D````$@`!`')3``#8(```!````!$`%@"!4P``N"````0````1 -M`!8`CU,``/06!`#L````$@`!`*E3``"\@@(`E````!(``0"]4P``4(<``*0` -M```2``$`RE,``$Q\`0!@`0``$@`!`.13``"`+`(`%````!(``0#Y4P``W$(# -M`$@"```2``$`!U0``+@_`P`$````$@`!`"E4``!X<`,`J`,``!(``0!!5``` -M+'\``(0!```2``$`550``+!A!``H````$@`!`&54```P6@0`'````!(``0!W -M5```@#\#``0````2``$`D%0``,@R`@!T````$@`!`*94``"\(```K````!(` -M`0"Z5```M"L"`&`````2``$`V50``$"``@`<````$@`!`/14``"("0``"`$` -M`!$`%@`+50``6#@"`+`````2``$`'E4``.C[`0`$!```$@`!`#]5``"LH``` -M#`(``!(``0!:50`````````````0````:54``*A"`0"D`0``$@`!`'15``#D -M)P,`&````!(``0"'50``[%H$`!@````2``$`E54``*!6`0!X`0``$@`!`*A5 -M``"P50,`L`$``!(``0"Y50``6$,"`%@````2``$`U%4``+`Y`0!\!0``$@`! -M`.15``#,=`0`6````!(``0`"5@``Y(\``"0%```2``$`'E8````````````` -M$````#)6``"\10(`/````!(``0!.5@``C*L```@````2``$`6E8``(A0``"` -M````$@`!`'16```P``4`#`$``!(``0"&5@``8$$#`!@````2``$`E58````` -M````````$````*96`````````````!````"U5@``-`,"`-@$```2``$`S58` -M`(2=`P#$`0``$@`!`/!6``"4600`&````!(``0#[5@``3`4```P````2``$` -M#U<``-S"``#T`0``$@`!`"Y7``#0)P,`%````!(``0`]5P``P#\%`'0````2 -M``$`75<```1>!`!,````$@`!`'57``!(H`$`Y````!(``0!_5P``?*<```@` -M```2``$`BE<``(0````0````$@`!`)I7``!(GP,`]`$``!(``0"\5P``;*@` -M`#0````2``$`S%<``&CX!``$````$@`!`.97``"DE`,`.````!(``0#]5P`` -MY`4```,````1`!8`!U@``.C"`0`8````$@`!`!U8``#@/0(`%````!(``0`L -M6```^"@#``@````2``$`9E@``)`4`P#`````$@`!`'U8``"X?@$`+`(``!(` -M`0"/6```&$`#``0````2``$`L%@``%1D!`#$````$@`!`,%8``"@>0(`>``` -M`!(``0#76```S%@$``P````2``$`YU@``&P5!`#<````$@`!`/M8``!LGP`` -M#````!(``0`,60``3$0!`&0#```2``$`$UD``'S2```,`0``$@`!`!Y9```` -M`````````!`````L60``X#$!`$0!```2``$`-UD``+`1``"4````$@`!`$E9 -M``!@%`````0``!$`%@!@60``V,D``%`!```2``$`<%D``$AF`0#\````$@`! -M`']9``"@;P$`(````!(``0"560``A)D``#P````2``$`KED``%`X```H`@`` -M$@`!`+]9``"(LP``P`0``!(``0#060``1$`#``0````2``$`ZUD``#R)`P"H -M`0``$@`!`/Y9``!(7P``>````!(``0`76@`````````````0````(EH``$Q, -M`@`T````$@`!`"Q:``!X9P$`'````!(``0`X6@``)`8#`%P````2``$`2%H` -M`/PF`P`$````$@`!`%E:``"T?P0`!````!(``0!E6@``A(\#`&@````2``$` -M@%H``/S?`0`<`0``$@`!`)5:`````````````!````"B6@``Y'<"`#P````2 -M``$`M5H``%@L````!```$0`8`,A:``"$IP``.````!(``0#76@``\*(!`"@` -M```2``$`[UH``*"S`P"$`0``$@`!`/]:```$#0``G````!(``0`46P``S)70``Y)0"`"`````2``$`-%T``&00`P!T -M`0``$@`!`$==```0F0``=````!(``0!<70`````````````0````;UT````` -M````````$````'A=``"$9`$`3````!(``0".70``!`0```0````1`!8`I%T` -M````````````$````+5=``",`@4`#````!(``0#:70``M`4```8````1`!8` -MYUT``/18!``0````$@`!`/Q=``"8`@4`5````!(``0`-7@``'$P``"@````2 -M``$`(EX``!0$```$````$0`6`#E>```8+0(`%````!(``0!,7@``6"P``&0` -M```1`!8`85X``!AA!``P````$@`!`&Y>``#\!0``!````!$`%@!^7@``K%D$ -M`!@````2``$`B5X``#C<`0!L`@``$@`!`)U>```D/@,`@````!(``0"]7@`` -MV`4#`$P````2``$`S5X``&PG`@`0`@``$@`!`.!>```(N0``G````!(``0#R -M7@`````````````0````^UX``#Q$`@`D````$@`!`!=?`````````````!`` -M```I7P``P&\!`#0````2``$`1E\``&`"!0`$````$@`!`%I?``!P7@0`#``` -M`!(``0!G7P``?*L``!`````2``$`=5\``+A_!`"(````$@`!`(%?``!0@P(` -M1````!(``0"87P``<+(#`#`!```2``$`JE\``&PE`P!D````$@`!`+Q?```H -M_P0`"`$``!(``0#37P`````````````0````W5\```#"``!`````$@`!`/!? -M`````````````!````#]7P``)'X!`)0````2``$`$V```$1C!`!4````$@`! -M`"1@```\=@``!````!(``0`]8```M!X!`)P#```2``$`6F````0G`P`$```` -M$@`!`&]@``#86`0`#````!(``0"`8```=$T``"0````2``$`C&```-QH!`!$ -M````$@`!`*)@`````````````!````"_8```.)L!`)P!```2``$`T&```*AH -M!``T````$@`!`.5@```4#@(`/`(``!(``0#T8```((4```P````2``$`!6$` -M`-"``@!8````$@`!`"1A``"LG@``P````!(``0`V80``'*<``&`````2``$` -M/V$``,`!!0!`````$@`!`%=A``!0BP(`@````!(``0!O80``P+8!`$0!```2 -M``$`?6$```3_!``,````$@`!`(YA```0404`(````!(``0"K80`````````` -M```0````PV$``%![!``X````$@`!`-9A``"D.P(`V````!(``0#D80`````` -M```````0````[V$``$`]`@!`````$@`!`/QA`````````````!`````%8@`` -M//$!`+P!```2``$`)&(`````````````$````#=B``!,J`$`,````!(``0!4 -M8@``G$P``"0````2``$`9V(``'`O`@"0````$@`!`'IB``"P6`0`'````!(` -M`0"+8@``2&(#`#`.```2``$`DV(``!2``@`L````$@`!`*5B``"0EP,`_`$` -M`!(``0#%8@`````````````0````U6(``'@=``"H````$0`6`.MB``!(ZP$` -MG`(``!(``0#]8@``@&<``&P!```2``$`#6,``'A+```@````$@`!`!HM``"L -M(0``,````!$`%@`<8P``[&@``/0````2``$`+6,``-`@```$````$0`6`#YC -M``#0B0$`N`,``!(``0!78P``+&0``*`"```2``$`FD``!`Q`@"P````$@`!`(MI``#T=0`` -M"````!(``0"F:0``^#\#``0````2``$`O&D`````````````$````,-I```` -M"0``B````!(``0#4:0`````````````0````VVD``+1G!`#T````$@`!`.MI -M``"<4`4`=````!(``0`!:@`````````````0````#FH``&"-`@!``0``$@`! -M`"5J``"4,`(`?````!(``0`V:@``:%P$`(0````2``$`3&H``*11!0!,```` -M$@`!`&9J```D100`'````!(``0!Z:@`````````````0````B6H``)BI`0"4 -M````$@`!`)MJ``"0(```!````!$`%@"I:@`````````````0````NFH``"!% -M!``$````$@`!`,]J```,.0``!````!$`&`#=:@``'$4"`#`````2``$`ZVH` -M`!@^!0!8````$@`!``UK``"L*`,`$````!(``0`;:P``!-\!`/@````2``$` -M*6L``&2F`@`$````$@`!`#5K```8>@(`W````!(``0!%:P``&$4"``0````2 -M``$`66L``$B]``"<`@``$@`!`&AK``#`0`(````$@`!``=O``"@<0(`0````!(``0`D;P`````````````0 -M````*V\``'PI`@!``0``$@`!`#MO``!X00,`J````!(``0!&;P``S&8``+0` -M```2``$`76\``)A.``"$`0``$@`!`'9O``!D`@4`*````!(``0"*;P``_&,` -M`#`````2``$`FV\``%@<`````0``$0`8`*QO``"XK0``E````!(``0#$;P`` -MV!$#`!`````2``$`V&\``*RR``!0````$@`!`/)O``#8`0` -M,````!(``0`A=```9'@```0````2``$`2W0``%C@`P`H`0``$@`!`&-T``!H -M;P(`)````!(``0!V=```N#@```0````1`!@`@G0```19!``<````$@`!`)1T -M````8`0`Y````!(``0"F=```"'8``#`````2``$`MW0``!R0`@#4````$@`! -M`-%T``"@90$`%````!(``0#A=```E`````@````2``$`[G0``.`@```$```` -M$0`6`/UT`````````````!`````5=0``]`4```8````1`!8`)'4``"B$``!D -M````$@`!`#!U```L%0``G````!(``0!!=0``?&$!`)P````2``$`3'4``#AV -M```$````$@`!`&AU``#0B@(`@````!(``0!]=0``K%\$`!0````2``$`C'4` -M`+P@```$````$0`6`)UU``#4``$`W`H``!(``0"S=0``O*4``$0````2``$` -MUW4``"@"!0`,````$@`!`/%U`````````````!````#X=0`````````````0 -M`````78``.AA``!<````$@`!`!9V``!@6`0`%````!(``0`K=@``W%X$``P` -M```2``$`.78``(@)```0````$@`!`$EV``!T(```!````!$`%@!5=@``U#@` -M``0````1`!@`9W8``,"+``!8`0``$@`!`(%V``!\)P,`#````!(``0".=@`` -MH`T``)@````2``$`F78``!PT!````0``$@`!`*UV``"$<```/`$``!(``0"\ -M=@``@,,"`)`!```2``$`T78``,0]`@`<````$@`!`.)V``"X700`3````!(` -M`0#S=@``!`````0````2``$`!7<``,0'``!8````$0`6`"5W```````````` -M`!`````M=P``S'H!`$0````2``$`.G<``$P$``"$````$0`6`$=W```8)P,` -M$````!(``0!7=P``K#0%`.P$```2``$`=G<``&!$`@!\````$@`!`))W``#@ -M<0(`W`$``!(``0"E=P``,&X!`#0````2``$`N7<``#A``P`,````$@`!`-%W -M``"0"@``"`$``!$`%@#D=P``Z-L!`%`````2``$`_'<``#27`0"8````$@`! -M`"!X``#P/P,`!````!(``0`W>```\&`$`!@````2``$`0W@``.PM`@`8`0`` -M$@`!`%1X``!D\`$`4````!(``0!H>```5/X#`!0!```2``$`@'@``#PH`P`0 -M````$@`!`(YX``!``@4`"````!(``0"H>```T#@```0````1`!@`NG@``$RN -M``"<`0``$@`!`--X``"\/P,`!````!(``0#O>```O#@```0````1`!@`!'D` -M````````````$`````QY```X:@$`1````!(``0`<>0``)%@``"`!```2``$` -M/WD``%@4`````@``$0`8`%!Y`````````````!````!<>0``*"<#`"`````2 -M``$`<'D``*#B``#8!P``$@`!`']Y``!H#```G````!(``0".>0``[%8``#P` -M```2``$`L7D``"#X!``8````$@`!`,-Y```(5`0`=`$``!(``0#7>0``V$H` -M`"`````2``$`XGD````G`P`$````$@`!`/-Y```$0`,`!````!(``0`*>@`` -MF`L``,@"```1`!8`'GH``/SZ!`"$````$@`!`#-Z``"07P0`'````!(``0!# -M>@``V#\$`$@%```2``$`7WH``(`@```$````$0`6`&QZ``#P'P``@````!$` -M%@"$>@``_*\"`*@!```2``$`DWH``)@@```$````$0`6`*!Z``#`3```)``` -M`!(``0"S>@``<,4``+P````2``$`R'H``)@)```(`@``$@`!`-=Z``#`90$` -M$````!(``0#D>@``H"<#``P````2``$`]WH``-1J`@`(````$@`!``Y[``!$ -M=@``N````!(``0`@>P``)'```&`````2``$`+GL`````````````$````#1[ -M```<3@0`3`$``!(``0!->P`````````````0````9'L``)#^!`!T````$@`! -M`'A[``#0-@``@`$``!(``0")>P``H&L!`*`!```2``$`F'L``&Q1!0`X```` -M$@`!`+-[```P`````````````0````TGL``"2D`0`\ -M````$@`!`.=[`````````````!````#T>P``G,<``.0````2``$`"'P````` -M````````$````!=\``!T7@$`>`$``!(``0`E?```8#D#`&`````2``$`0GP` -M`'Q>!``,````$@`!`%!\``#L)@,`!````!(``0!D?```]#T"`#P````2``$` -M?7P```P$```$````$0`6`)5\`````````````!````"D?```Q#\$`!0````2 -M``$`NGP``%@6````!@``$0`8`,U\``#$Z@``,`0``!(``0#;?```Y-$``)@` -M```2``$`YGP``"#5```,`0``$@`!`/-\``#,*`,`+````!(``0`,?0``?!0# -M`!0````2``$`(GT`````````````$````"M]``"P!0``!````!$`%@`S?0`` -MV`0```0````1`!8`.WT``%Q<`0`H````$@`!`$M]``#@!```$````!$`%@!7 -M?0``I+$"`*P!```2``$`;WT``/0_`P`$````$@`!`(9]``"\*@(`^````!(` -M`0"7?0`````````````0````HGT`````````````$````+-]``!8-```!``` -M`!$`&`#&?0``2)(!`-P#```2``$`U'T``/AK!`!,````$@`!`.-]```L30`` -M)````!(``0#P?0`````````````0````^GT``+BN`@!H````$@`!``A^``!D -M;@$`4````!(``0`5?@``&'L"`$`!```2``$`*'X``.@.``#P````$@`!`#]^ -M``!TV@$`8````!(``0!8?@``5%`%`$@````2``$`;7X`````````````$``` -M`'I^``#`7P0`#````!(``0"'?@``'#D"`,0````2``$`F7X```A-```D```` -M$@`!`*5^`````````````!````"W?@``7'`"`*@````2``$`RGX``#PS`@"0 -M`@``$@`!`.%^``#T+`(`)````!(``0#Z?@``>)D"`"@````2``$`#W\````` -M````````$````")_```LQ@``S````!(``0`W?P``($("`!@!```2``$`3'\` -M`"`>``"H````$0`6`&%_``"T#@$`^````!(``0!O?P``Q*X!`(0!```2``$` -MC'\``&2I`0`T````$@`!`)]_``#\)P,`$````!(``0"L?P``Y+\``,P````2 -M``$`O7\``'3"`0!T````$@`!`-9_``#TFP(```(``!(``0#F?P``W`@``*P` -M```1`!8`]7\``$A8!``8````$@`!``J``````````````!`````8@```_%8$ -M`"`!```2``$`+(```&QX`0`L`0``$@`!`#V```#,-0(`C`(``!(``0!1@``` -MH#@```0````1`!@`8(``````````````$````&F``````````````!````!Z -M@``````````````0````B8````R5`@"T````$@`!`)N``````````````!`` -M``"K@``````````````0````M8```-0%```#````$0`6`,.```!P(```!``` -M`!$`%@#/@```W"$``!@````1`!8`X(```(3'`0`(!@``$@`!`.F```#8!0`` -M`P```!$`%@#W@```4%H!`"P````2``$`"8$``$BI``!\````$@`!`!J!``!8 -M'@````8``!$`&``I@0``Q`4```0````1`!8`/H$``&C_`P!($@``$@`!`&V! -M``"4@P(`1`(``!(``0"$@0``Y"````0````1`!8`FH$`````````````$``` -M`*N!``#H]```+`(``!(``0"Z@0``L#\``"0!```2``$`RH$``.R9`P#$`0`` -M$@`!`.V!``#T@0(`1````!(``0`%@@``.$,"`"`````2``$`'8(``"!H`@`$ -M````$@`!`#2"``!(`@4`%````!(``0!/@@``?&H!`$`````2``$`88(```## -M`0!@`P``$@`!`'*"``#`.```!````!$`&`"'@@``!`$"`#`"```2``$`H((` -M`$@$```$````$0`6`+:"`````````````!````#*@@``E"<#``P````2``$` -MUX(`````````````$````.V"``#8%@(`E!```!(``0#]@@``I&$$``P````2 -M``$`"8,``.!N`0"T````$@`!`!:#``#L7`0`@````!(``0`K@P```#D```P` -M```1`!@`,H,``!`=``"8````$@`!`$.#```,"`(`[`,``!(``0!;@P``U"8# -M`!@````2``$`<(,``.CS`@#4$```$@`!`'V#``#,.```!````!$`&`".@P`` -M"`0```0````1`!8`I(,``&#&`0`D`0``$@`!`+B#``"L)P``,````!(``0#) -M@P``W$0"`#P````2``$`XH,``(A;`0`0````$@`!`.Z#``#\I@``"````!(` -M`0#[@P``[%\!`!0!```2``$`"X0``,P8!`#<````$@`!`!N$```````````` -M`!`````UA```2!8$`*P````2``$`2X0``"26`0`0`0``$@`!`&:$````Z0$` -M3````!(``0"(A```$/\$``P````2``$`F(0``"2U`P!``0``$@`!`+&$``"L -MH@(`<````!(``0#'A```P#\#`"P````2``$`WH0``-"+`@`<````$@`!`/:$ -M``#X.```!````!$`&``"A0``)(X#`&`!```2``$`$X4`````````````$``` -M`!V%``"T(0,`N`,``!(``0`TA0``C`0``&0````2``$`3H4``"PM`@`D```` -M$@`!`&*%``"HH0$`0````!(``0!VA0``_&@!`#P!```2``$`B84``)B^`0"\ -M````$@`!`)V%``#`,0(`!````!(``0"OA0``8*("`$P````2``$`Q84``-#! -M`0"D````$@`!`-B%``"8.04`@`0``!(``0`!A@``^"8#``0````2``$`$X8` -M`(P@```$````$0`6`""&```HD`$`A````!(``0`TA@``*+H#`(@$```2``$` -M3(8``'@@```$````$0`6`%Z&```DK`,`,`(``!(``0!TA@``(%L!`!P````2 -M``$`?H8``,`%```$````$0`6`(Z&``#$+P$`$````!(``0"GA@``Y.T!`(`` -M```2``$`P88``%PT```$````$0`8`-*&``!L+`(`%````!(``0#DA@``$&`` -M`$@````2``$`^X8``/B?```,````$@`!`!*'```HB`(`J`(``!(``0`TAP`` -M;%D!`"`````2``$`2H<``%`^`@"<`@``$@`!`&*'``"8W```W````!(``0!Q -MAP``D)X!`+@!```2``$`A8<``$"N`0!<````$@`!`)F'``#0&P``6````!$` -M%@"QAP``&!P``%@````2``$`QH<````D```,````$@`!`-B'```````````` -M`!````#WAP``*($"`%@````2``$`"X@``&@Q`P!P`P``$@`!`"&(```($@,` -M,````!(``0`XB```?*@!`#`````2``$`2H@```2G```(````$@`!`%>(``!$ -M$`,`$````!(``0!LB```^(@!`-@````2``$`?H@``/@+`@`0`0``$@`!`)>( -M```,20``S`$``!(``0"GB```(-D$`%@````2``$`QH@``!P@``"@````$@`! -M`-N(``#82P``)````!(``0#QB```A+@``(0````2``$`_H@````````````` -M$`````Z)`````````````!`````@B0``]#@```0````1`!@`,8D``!AM```$ -M`0``$@`!`$*)``#@N`$`_`0``!(``0!3B0``E'$!`#0````2``$`:8D``%26 -M`P`\`0``$@`!`'R)```XJ0``$````!(``0"(B0``X*H#`$0!```2``$`HXD` -M`,1>`P"$`P``$@`!`+&)``!0``G````!(` -M`0`&BP```%`%`%0````2``$`'HL``%#A``!0`0``$@`!`"V+``#``"H````$0`6`$"-```D:`(`J`(``!(``0!``!\````$@`!`)>-```(J0(`-`$``!(``0"LC0``V#0#``0` -M```2``$`S(T```P&!0!4````$@`!`.J-```4IP``"````!(``0#WC0``.((" -M`(0````2``$`%XX``'AB``!``0``$@`!`">.``#46@0`&````!(``0`VC@`` -M#$`#``0````2``$`5HX``%`B`0`,`P``$@`!`&N.`````````````!````!\ -MC@``G"````0````1`!8`BXX``-P$```$````$0`6`)..``!/```X -M!```!````!$`%@!=CP`````````````0````;X\``-B%`@!0`@``$@`!`)"/ -M```\=@0`"`$``!(``0">CP``"*L``'0````2``$`K(\``+1U`0`D`0``$@`! -M`+:/`````````````!````"]CP``:*$!`!@````2``$`T(\``#2H```X```` -M$@`!`/./```84@0`\`$``!(``0`(D```(`0```0````1`!8`()````Q$`@`P -M````$@`!`#N0``#$AP$`U````!(``0!.D```*!P``*@````1`!8`:9```#0[ -M`P`D`0``$@`!`'F0`````````````!````"#D```[#`$`!`!```2``$`GY`` -M`)B(`0!@````$@`!`+.0```T`@4`#````!(``0#,D```L#@```0````1`!@` -MV)```&RF`@"$````$@`!`.V0```LB@``'````!(``0`(D0``2&2``!XBP``2````!(` -M`0`SD@``7(4``(P````2``$`3I(``!C;!`"\#P``$@`!`%B2```````````` -M`!````!KD@`````````````0````?9(``(@4!`#D````$@`!``!R='=?8VUD -M+F,`)&$`)&0`+DQ#,``N3$,Q`"Y,04Y#2$]2,`!R='=?7!T`&-R8S,R7W)E=F5R'1?:V5Y`&)Y=&5?#$`%]T86)L90!#+C8P-BXT,S`V.0!B8W)C,S)I;FET:6%L:7IE9`!C -M2YC`')T=U]I;V-T;%]S970N8P`N3$,R`')T=U]I -M965E.#`R,3$N8P!K97E?8VAA2XT,C@W-`!R='=?;6QM95]E>'0N8P!5<&1A=&5" -M5]S=7-P96YD`')T=U]L -M871E7W)EF5?.#$X.&4`:&%L7T5F=7-E1FEX2&5A9&5R4')O8V5S6-F9RYC`'!H>5]#86QC=6QA=&5":713:&EF=`!P:'E?1&)M5&]4 -M>%!W`!?4$A97U-E=%)&4&%T:%-W:71C:`!P:'E?4D9397)I86Q296%D -M`$-35U1#2"XV,#4`0U-75$-(+C8P.`!#+C4X."XT-#0P-@!R=&PX,3@X95]R -M9C8P-3(N8P!#+C4X-"XT-#0R-@!#+C4X-2XT-#0R-P!21E]3:&%D;W<`&1E$)E86-O -M;@!R=&PX,3DR8W5?:'=?<&]W97)?9&]W;@!?26YI=$YO0!#+C8Q,"XT-#DW.0!#4U=40T@N-C4T`$,N-C(U+C0U-#8Y`$-3 -M5U1#2"XV-#<`0U-75$-(+C8U,`!#4U=40T@N-C4Q`')T;#@Q.#AE=5]L960N -M8P!297-E=$QE9%-T871U6YC`'5S8E]W%)05%1I;6EN9U\X,3@X10!O9&U?4F%T941E8VES:6]N7S@Q.#A%`"Y,0S,V -M`$1Y;F%M:6-4>%)05%1I;6EN9P!?7V9U;F-?7RXT-#`Y,P!?7V9U;F-?7RXT -M-#4V.0!24U-)7U1(4D532$],1`!2151265]014Y!3%197TE$6`!2151265]0 -M14Y!3%19`%)%5%)97U!%3D%,5%E?55!?2418`$Y?5$A215-(3TQ$7TQ/5P!$ -M4D]024Y'7TY%0T534T%260!?7V9U;F-?7RXT-#$T-`!.7U1(4D532$],1%]( -M24=(`%]?9G5N8U]?+C0T,S0Y`%!E;F1I;F=&;W)2871E57!&86EL`%]?9G5N -M8U]?+C0U-#`W`%]?9G5N8U]?+C0U,S(R`%]?9G5N8U]?+C0U,C@S`%]?9G5N -M8U]?+C0U,C0S`%]?9G5N8U]?+C0U,C`Y`%]?9G5N8U]?+C0U,38Q`%]?9G5N -M8U]?+C0U-#8P`%!47U!%3D%,5%D`7U]F=6YC7U\N-#4P.#0`7U]F=6YC7U\N -M-#4S-C0`7U]F=6YC7U\N-#0X.34`1'EN86UI8U1X4E!45&EM:6YG0V]U;G1E -M2XT -M,C(T,`!O%]R;V%M:6YG7W1I;65S`%]? -M<&%R86U?6UT86)?;78X.'6UT86)?"YC`&AE>#)N=6U?:0!W<&%?%]G971?%]G971?0!R='=?=WA?0!R='=?=WA?%]R96%D7W)F`')T=U]M<%]E9G5S95]G970`+DQ#,3,`+DQ#,34` -M+DQ#,C,`+DQ#,C8`+DQ#,C<`+DQ#,C@`+DQ#,CD`%]S971?875T:`!R='=?%]G971?;F%M90`N3$,X,``N3$,X,0`N3$,X,P`N3$,X -M-``N3$,X-0`N3$,X-P`N3$,X.`!R='=?=WA?9V5T7W)A;F=E`')T=U]W>%]G -M971?9G)E<0!T5]P87)A;7,`8V9G.#`R,3%?`!C9F'1R85]C;61?:&1L`$]$35]3=T%N=$1I=D-H:U!E5]M6YA;6EC5'A0;W=E&1E5]I;F-L=61E9`!(86Q?26YI=%!'1&%T83@X10!C -M9F6YA;6EC -M4')I;6%R>4-#05]$=7!25%,`&UI=&9R -M86UE`')T=U]C;61?9FEL=&5R`')T=U]D97%U975E7W)E8W9F%!O=V5R4V%V95!O=V5R26YD -M97@`&UI=%]R97-O=7)C95]F%!O=V5R3&5V -M96PX,3@X10!R='=?9V5T7V-A<&%B:6QI='D`<&AY7U1X4'=R261X5&]$8FT` -M7W)T=U]R96%D,38`9F%K945F=7-E0F%N:P!/;D%C=&EO;E]B86-K`')T=U]F -M5]T:6UE5]S=7-P96YD`')T=U]C -M%!O=V5R5W)I -M=&5686Q">5)E9W5L871O`!R=&PX,3@X -M15]P;W=E5]C;60`;V1M7T9A;'-E06QA -M5]A='1R:6)U90!N971W;W)K='EP95]T;U]R86ED`')T=U]I7!T;W(`7W)T=U]R;V%M:6YG`&]D;5]);FET7U)3 -M4TE&;W)$30!O9&U?0V]M;6]N26YF;U-E;&95<&1A=&4`7!E.#A%`%]R='=?96YQ=65U -M95]N971W;W)K`&1Y;F%M:6-?8VAK7W=K7VAD;`!S:71E`!02%E? -M4V5T5'A0;W=E6YA;6EC7V-H:U]W:U]C;60`;V1M7T-M -M;DEN9F]);FET7T1E8G5G`')T=U]A;&QO8U]N971W;W)K`')O8VMC:&EP7W=I -M9FE?97AI=%]M;V1U;&4`3T1-7T9I;&Q(,D-#;60`6YA;6EC -M5'A0;W=E61O;F5?979E;G1? -M8V%L;&)A8VL`969U4-O;7!A'1? -M0!O9&U?161C851U%]P=W(`3T1-7U-E=$)"4F5G`&-C:W)A -M=&5S;VYL>5]I;F-L=61E9`!R='=?=7!D871E7VAT7V-A<`!R='=?8V%N8V5L -M7V%L;%]T:6UE<@!R='=?;F5T=V]R:U]M;V1E`')T=U]A;&QO8U]E=&AE&UI=%]P71E`$%43TU)0U]354)?4D54 -M55).`$]$35]3971-04-296<`971H7W1Y<&5?=')A;G,`5]35]O;E]C:&%N;F5L`%]R='=?;6%L;&]C`$)23T%$0T]-7T]5 -M23,`F5R;U]P86-K971?8VAK -M`$-O;G-T5]T:6UE<@!I&UI=&)U9@!R='=?86YD0!?F4`3T1-7U)&7U-A=FEN9P!O9&U?4F5F -M0!R='=?;6]D=6QA'1? -M<')I=@!/1$U?4D%3=&%T94-H96-K`$AA;%]296%D4&]W97)3879I;F=-;V1E -M.#A%`$]N06-T:6]N7W!U8FQI8P!M=C@X=S@V.#9?:69?'1?:F]I;F)S0!R='=?8V9G.#`R,3%?:6YD:6-A=&5?&UI=&9R86UE -M7V5X`&1U;7!?8VAI<%]I;F9O`&]D;5]3:6=N86Q38V%L94UA<'!I;F=?.3)# -M4V5R:65S7W!A=&-H7U)47T-)1%\X,3EX7TQE;F]V;P!R=&PX,3@X975?&1E0!49#``5U!!7T-)4$A%4E]354E415]42TE0`')T;#@Q.#AE -M7W-E=%]P,G!?8W1W7W!E%]B96%C;VY?8VUD`&MI -M;&Q?<&ED`$AA;%]%9G5S95!A0!G971?='AF:69O7VAW861D<@!R='=?5]E -M=F5N=%]C86QL8F%C:P!I0!R='=?9FEN9%]N971W;W)K`%!(65]21E-H861O -M=U)E8V]R=F5R1FQA9U-E=$%L;`!?&UI=%]P -M6YC`')T=U]E9G5S95]M87!?71E`')T=U]I;F1I8V%T95]C;VYN96-T`%)%04Q414M?3U5)`')T -M=U]F0!R='=?:6YI=%]N971D979?;F%M -M90!?7W1A%!A=&@`3T1-7U-W06YT1&EV4F5S971"969O6YA;6EC5'A0;W=E`!/;D%C=&EO;E]P,G``7W)T=U]W'1?%]I;FET`')T;#@Q.#AE7TAA;$1M5V%T8VA$;V<`169U4-#05]);FET`'5S8E]D97)E9VES=&5R`%]R='=? -M:6YI=%]S=&%I;F9O`')T=U]S8V%N7VUO9&4`:FEF9FEE4%N=$1I=@!R='=?5]0;W=E&9R86UE'!I5]0871H05])44M?.#$X.$4`5]S=7-P96YD`&5N86)L95]R871E7V%D87!T:79E`%]?;65M>F5R;P!R='=? -M9'5M<%]X9G)A;64`5]E7!T7V1E8W)Y<'1? -M9G)O;5]R96=I7!R:78`7U!(65]296QO861-04-296=I3@Q.3)#`')T=U]M<%]M;V1E`')T=U]S>7-T:6UE7W1O7VUS -M`')T=U]C:&%N9V5?:69N86UE`')T=U]I3@X -M10!02%E?4V5T0E=-;V1E.#$X.$4`9FQU0!O9&U? -M5%A0;W=E%!O=V5R7SDR0P!R='=?;69R964R9`!R -M='=?969U%]I;FET`$]$35]205]5<&1A=&52871E26YF;U\X,3@X10!R -M='=?=F-S7W1Y<&4`%]M86-?:60`5\X.$4`8V9G.#`R,3%?%]A5-T871U%!W7!E`'-T&UI=`!"4D]!1$-/35]/54DR`%-A=F5?1$U?1G5N8U]&;&%G`&-H:U]S -M=&%?:7-?86QI=F4`0E1%9G5S94-O;G1E;G0`8FUC7W-U<'!O5]#;VYF:6="0D5X=&5R;F%L4$$`7!E`$]N06-T:6]N7W%O5],0T-A;&EB7!T`')T=U]I;F1I8V%T95]W>%]D:7-A0!R='=? -M;6,R=5]D:7-A8FQE`')T=U]G971?=W!S7V%T='(``!,96%V94%L;%!O=V5R4V%V94UO9&4`3T1-7U)EF57;W)K271E;0!S=')L96X`5]F$%G9W(X,3@X155S8@!W:7!H>5]F5]2861I;T%?,51?.#$X.$4`07)R87E?4$A97U)%1U]-4%\X -M,3@X10!?5]L;70`0V]N5]E -M=F5N=%]C86QL8F%C:P!/1$U?1$U);FET`&ES -#include -#include -#include - -#include "wifi_power.h" - -/* - * rtw_channel_plan : The initialization parameter of wifi channel, - * Allow number is "0" "2" and "5". - * 0 => 11 ( channel 1 ~ 11 is SCAN_ACTIVE ) - * 2 => 13 ( channel 1 ~ 13 is SCAN_ACTIVE ) - * 5 => 14 ( channel 1 ~ 14 is SCAN_ACTIVE ) - * default number is "2". - */ -char init_channel_plan = 2; - -#if (WIFI_GPIO_POWER_CONTROL == 1) - -/* - * GPIO to control LDO/DCDC. - * - * 鐢ㄤ簬鎺у埗WIFI鐨勭數婧愶紝閫氬父鏄3.3V鍜1.8V锛屽彲鑳1.2V涔熷湪鍏朵腑銆 - * - * 濡傛灉鏄墿灞旾O锛岃鍙傝冧笅闈㈢殑渚嬪瓙: - * POWER_USE_EXT_GPIO, 0, 0, 0, PCA9554_Pin1, GPIO_HIGH - */ -struct wifi_power power_gpio = -{ - //POWER_NOT_USE_GPIO, 0, 0, 0, 0, 0 - - // RBOX - //POWER_USE_GPIO, POWER_GPIO_IOMUX, - //GPIO5D6_SDMMC1PWREN_NAME, GPIO5H_GPIO5D6, RK29_PIN5_PD6, GPIO_HIGH - -#define GPIO_WIFI_POWER RK29_PIN6_PC0 - - // YIFANG M803 - //POWER_USE_GPIO, 0, - //0, 0, GPIO_WIFI_POWER, GPIO_HIGH - - //SDK - POWER_NOT_USE_GPIO, 0, 0, 0, 0, 0 -}; - -/* - * GPIO to control WIFI PowerDOWN/RESET. - * - * 鎺у埗WIFI鐨凱owerDown鑴氥傛湁浜涙ā缁凱owerDown鑴氭槸鍜孯eset鑴氱煭鎺ュ湪涓璧枫 - */ -struct wifi_power power_save_gpio = -{ - POWER_NOT_USE_GPIO, 0, 0, 0, 0, 0 -}; - -/* - * GPIO to reset WIFI. Keep this as NULL normally. - * - * 鎺у埗WIFI鐨凴eset鑴氾紝閫氬父WiFi妯$粍娌℃湁鐢ㄥ埌杩欎釜寮曡剼銆 - */ -struct wifi_power power_reset_gpio = -{ - POWER_NOT_USE_GPIO, 0, 0, 0, 0, 0 -}; - -/* - * 鍦╓IFI琚笂鐢靛墠锛屼細璋冪敤杩欎釜鍑芥暟銆 - */ -void wifi_turn_on_callback(void) -{ -} - -/* - * 鍦╓IFI琚笅鐢靛悗锛屼細璋冪敤杩欎釜鍑芥暟銆 - */ -void wifi_turn_off_callback(void) -{ -} - -/* - * If external GPIO chip such as PCA9554 is being used, please - * implement the following 2 function. - * - * id: is GPIO identifier, such as GPIOPortF_Pin0, or external - * name defined in struct wifi_power. - * sens: the value should be set to GPIO, usually is GPIO_HIGH or GPIO_LOW. - * - * 濡傛灉鏈夌敤鎵╁睍GPIO鏉ユ帶鍒禬IFI锛岃瀹炵幇涓嬮潰鐨勫嚱鏁: - * 鍑芥暟鐨勫姛鑳芥槸锛氭帶鍒舵寚瀹氱殑IO鍙d锛屼娇鍏剁姸鎬佸垏鎹负瑕佹眰鐨剆ens鐘舵併 - * id : 鏄疘O鐨勬爣璇嗗彿锛屼互鏁存暟鐨勫舰寮忔爣璇嗐 - * sens: 鏄姹傜殑IO鐘舵侊紝涓洪珮鎴栦綆銆 - */ -void wifi_extgpio_operation(u8 id, u8 sens) -{ - //pca955x_gpio_direction_output(id, sens); -} - -/* - * 鍦ㄧ郴缁熶腑濡傛灉瑕佽皟鐢╓IFI鐨処O鎺у埗锛屽皢WIFI涓嬬數锛屽彲浠ヨ皟鐢ㄥ涓嬫帴鍙o細 - * void rockchip_wifi_shutdown(void); - * 浣嗘敞鎰忛渶瑕佸湪瀹廤IFI_GPIO_POWER_CONTROL鐨勬帶鍒朵笅銆 - */ - -#endif /* WIFI_GPIO_POWER_CONTROL */ - diff --git a/drivers/net/wireless/rtl8188eu/wifi_power.h b/drivers/net/wireless/rtl8188eu/wifi_power.h deleted file mode 100644 index ea21f11060ae..000000000000 --- a/drivers/net/wireless/rtl8188eu/wifi_power.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * wifi_power.h - * - * WIFI power control. - * - * Yongle Lai - */ - -#ifndef WIFI_POWER_H -#define WIFI_POWER_H - -#include - -#define DONT_SWITCH_USB 0 /* Don't switch USB automaticately. */ -#define WIFI_USE_OTG 1 /* WiFi will be connected to USB OTG. */ -#define WIFI_USE_HOST11 2 /* WiFi will be connected to USB HOST 1.1. */ - -#define WIFI_USE_IFACE WIFI_USE_HOST11 /* Select USB Controler */ -#define WIFI_GPIO_POWER_CONTROL 1 /* Enable GPIO Control Power */ - -#if (WIFI_GPIO_POWER_CONTROL == 1) - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25) -#include -#include -#else -//#include -#include -#endif - -#define WIFI_CHIP_MV8686 0 -#define WIFI_CHIP_AR6002 1 -#define WIFI_CHIP_BCM4319 2 -#define WIFI_CHIP_NRX700 3 -#define WIFI_CHIP_RT3070 4 -#define WIFI_CHIP_RTL8192C 5 - -#define POWER_NOT_USE_GPIO 0 -#define POWER_USE_GPIO 1 -#define POWER_USE_EXT_GPIO 2 /* External GPIO chip is used, such as PCA9554. */ - -#define POWER_GPIO_NOT_IOMUX 0 -#define POWER_GPIO_IOMUX 1 - -#define GPIO_SWITCH_OFF 0 -#define GPIO_SWITCH_ON 1 - -struct wifi_power -{ - u16 use_gpio; /* If uses GPIO to control wifi power supply. 0 - no, 1 - yes. */ - u16 gpio_iomux; /* If the GPIO is iomux. 0 - no, 1 - yes. */ - char *iomux_name; /* IOMUX name */ - u16 iomux_value; /* IOMUX value - which function is choosen. */ - u16 gpio_id; /* GPIO number */ - u16 sensi_level; /* GPIO sensitive level. */ -}; - -int wifi_turn_on_card(int module); -int wifi_turn_off_card(void); -int wifi_reset_card(void); -void wifi_extgpio_operation(u8 id, u8 sens); - -void rockchip_wifi_shutdown(void); - -#endif /* WIFI_GPIO_POWER_CONTROL */ - -#define WIFI_NETWORK_BUSY 0 -#define WIFI_NETWORK_IDLE 1 - -int wifi_power_save_init(void); -int wifi_power_save_exit(void); -int wifi_power_save_stop(void); -int wifi_power_save_state(void); -void wifi_power_save_suspend(void); -void wifi_power_save_resume(void); -int wifi_power_save_register_callback(int (*callback)(int status)); - -void wifi_turn_on_callback(void); -void wifi_turn_off_callback(void); - -/* usb wifi */ -int wifi_activate_usb(void); -int wifi_deactivate_usb(void); -void wifi_usb_init(void); - -#endif /* WIFI_POWER_H */ - diff --git a/drivers/net/wireless/rtl8188eu/wifi_power_ops.c b/drivers/net/wireless/rtl8188eu/wifi_power_ops.c deleted file mode 100644 index 4096bdac15fd..000000000000 --- a/drivers/net/wireless/rtl8188eu/wifi_power_ops.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * wifi_power.c - * - * Yongle Lai @ Rockchip Fuzhou @ 20100303. - * - * Power control for WIFI module. - * - * There are Power supply and Power Up/Down controls for WIFI typically. - */ -#include -#include -#include -#include - -#include "wifi_power.h" - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25) -#include -#include -#else -#include -#include -#endif - - -#if (WIFI_GPIO_POWER_CONTROL == 1) - -extern struct wifi_power power_gpio; -extern struct wifi_power power_save_gpio; -extern struct wifi_power power_reset_gpio; - -#define OS_IOMUX(name, value) rk29_mux_api_set((name), (value)); - -int wifi_gpio_operate(struct wifi_power *gpio, int flag) -{ - int sensitive; - - if (gpio->use_gpio == POWER_NOT_USE_GPIO) - return 0; - - if (gpio->gpio_iomux == POWER_GPIO_IOMUX) - { - OS_IOMUX(gpio->iomux_name, gpio->iomux_value); - } - - if (flag == GPIO_SWITCH_ON) - sensitive = gpio->sensi_level; - else - sensitive = 1 - gpio->sensi_level; - - if (gpio->use_gpio == POWER_USE_EXT_GPIO) - { - wifi_extgpio_operation(gpio->gpio_id, sensitive); - } - else - { - int ret; - - ret = gpio_request(gpio->gpio_id, NULL); - if (ret != 0) - printk("Request GPIO for WIFI POWER error!\n"); - - gpio_direction_output(gpio->gpio_id, sensitive); - gpio_set_value(gpio->gpio_id, sensitive); - - gpio_free(gpio->gpio_id); - } - - return 0; -} - -/* - * WiFi power up sequence - */ -int wifi_turn_on_rtl8192c_card(void) -{ - wifi_gpio_operate(&power_gpio, GPIO_SWITCH_ON); - if (power_gpio.use_gpio != POWER_NOT_USE_GPIO) - msleep(1000); - - return 0; -} - -int wifi_turn_on_card(int module) -{ - wifi_turn_on_callback(); - - wifi_turn_on_rtl8192c_card(); - - return 0; -} - -int wifi_turn_off_card(void) -{ - wifi_gpio_operate(&power_gpio, GPIO_SWITCH_OFF); - msleep(5); - - wifi_turn_off_callback(); - - return 0; -} - -void rockchip_wifi_shutdown(void) -{ - printk("rockchip_wifi_shutdown....\n"); - - wifi_turn_off_card(); -} -EXPORT_SYMBOL(rockchip_wifi_shutdown); - -#endif /* WIFI_GPIO_POWER_CONTROL */ - diff --git a/drivers/net/wireless/rtl8188eu/wifi_power_usb.c b/drivers/net/wireless/rtl8188eu/wifi_power_usb.c deleted file mode 100644 index c979cc34958c..000000000000 --- a/drivers/net/wireless/rtl8188eu/wifi_power_usb.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * wifi_power.c - * - * Power control for WIFI module. - * - * There are Power supply and Power Up/Down controls for WIFI typically. - */ -#include -#include -#include -#include - -#include "wifi_power.h" - -#if (WIFI_GPIO_POWER_CONTROL == 1) - -int wifi_change_usb_mode = 0; -int usb_wifi_status = 0; - -void wifi_usb_init(void) -{ - wifi_change_usb_mode = 0; - usb_wifi_status = 0; -} - -#if (WIFI_USE_IFACE == WIFI_USE_OTG) - -#define USB_NORMAL 0 -#define USB_FORCE_HOST 1 -#define USB_FORCE_DEVICE 2 - -extern int usb_force_usb_for_wifi(int mode); - -/* - * Change USB mode to HOST. - */ -int wifi_activate_usb(void) -{ - wifi_turn_on_card(WIFI_CHIP_RTL8192C); - - wifi_change_usb_mode = usb_force_usb_for_wifi(USB_FORCE_HOST); - msleep(1000); - - usb_wifi_status = 1; - - return 0; -} - -/* - * Change USB mode to be original. - */ -int wifi_deactivate_usb(void) -{ - if (wifi_change_usb_mode == 1) - { - usb_force_usb_for_wifi(USB_FORCE_DEVICE); - msleep(1000); - usb_force_usb_for_wifi(USB_NORMAL); - msleep(1000); - } - wifi_turn_off_card(); - - usb_wifi_status = 0; - - return 0; -} - -#elif (WIFI_USE_IFACE == WIFI_USE_HOST11) - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25) -extern int usb_switch_usb_host11_for_wifi(int enabled); -#endif - -int wifi_deactivate_usb(void) -{ -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25) - usb_switch_usb_host11_for_wifi(0); - msleep(1000); -#endif - - wifi_turn_off_card(); - msleep(100); - - return 0; -} - -int wifi_activate_usb(void) -{ - wifi_turn_on_card(WIFI_CHIP_RTL8192C); - msleep(100); - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25) - usb_switch_usb_host11_for_wifi(1); - msleep(1000); -#endif - - return 0; -} - -#else - -int wifi_deactivate_usb(void) -{ - wifi_turn_off_card(); - msleep(1000); - return 0; -} - -int wifi_activate_usb(void) -{ - wifi_turn_on_card(WIFI_CHIP_RTL8192C); - msleep(1000); - return 0; -} -#endif - -#endif /* WIFI_GPIO_POWER_CONTROL */ - diff --git a/drivers/net/wireless/rtl8188eu/wifi_version.h b/drivers/net/wireless/rtl8188eu/wifi_version.h deleted file mode 100755 index 154a0140063e..000000000000 --- a/drivers/net/wireless/rtl8188eu/wifi_version.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Yongle Lai @ Rockchip - */ -#ifndef _WIFI_VERSION_H_ -#define _WIFI_VERSION_H_ - -/* - * Broadcom BCM4319 driver version. - */ -#define RTL8192_DRV_VERSION "1.01" - -#endif /* WIFI_VERSION_H */ - diff --git a/drivers/net/wireless/wifi_sys/rkwifi_sys_iface.c b/drivers/net/wireless/wifi_sys/rkwifi_sys_iface.c index 593d078d4550..8963eae6c6ec 100644 --- a/drivers/net/wireless/wifi_sys/rkwifi_sys_iface.c +++ b/drivers/net/wireless/wifi_sys/rkwifi_sys_iface.c @@ -19,13 +19,8 @@ static ssize_t wifi_chip_read(struct class *cls, char *_buf) #endif #ifdef CONFIG_RTL8192CU - count = sprintf(_buf, "%s", "RTL8188CU"); - printk("Current WiFi chip is RTL8188CU.\n"); -#endif - -#ifdef CONFIG_RTL8188EU - count = sprintf(_buf, "%s", "RTL8188EU"); - printk("Current WiFi chip is RTL8188EU.\n"); + count = sprintf(_buf, "%s", "RTL8188"); + printk("Current WiFi chip is RTL8188.\n"); #endif #ifdef CONFIG_BCM4330 From ebe214e01018d858493abaaa637aa7d1f345b69d Mon Sep 17 00:00:00 2001 From: kfx Date: Sun, 19 Aug 2012 15:18:44 +0800 Subject: [PATCH 229/261] rk2928: a720 init --- arch/arm/configs/rk2928_a720_defconfig | 381 +++++++++++ arch/arm/mach-rk2928/Kconfig | 2 + arch/arm/mach-rk2928/Makefile | 1 + arch/arm/mach-rk2928/board-rk2928-a720-key.c | 39 ++ .../mach-rk2928/board-rk2928-a720-tps65910.c | 628 ++++++++++++++++++ arch/arm/mach-rk2928/board-rk2928-a720.c | 499 ++++++++++++++ arch/arm/mach-rk2928/clock_data.c | 2 +- drivers/input/keyboard/rk29_keys.c | 2 +- drivers/video/display/screen/Kconfig | 3 + drivers/video/display/screen/Makefile | 1 + .../video/display/screen/lcd_rk2928_a720.c | 80 +++ drivers/video/rockchip/chips/rk2928_lcdc.c | 25 + 12 files changed, 1661 insertions(+), 2 deletions(-) create mode 100644 arch/arm/configs/rk2928_a720_defconfig create mode 100755 arch/arm/mach-rk2928/board-rk2928-a720-key.c create mode 100755 arch/arm/mach-rk2928/board-rk2928-a720-tps65910.c create mode 100755 arch/arm/mach-rk2928/board-rk2928-a720.c create mode 100644 drivers/video/display/screen/lcd_rk2928_a720.c diff --git a/arch/arm/configs/rk2928_a720_defconfig b/arch/arm/configs/rk2928_a720_defconfig new file mode 100644 index 000000000000..9f3b4f64fcc1 --- /dev/null +++ b/arch/arm/configs/rk2928_a720_defconfig @@ -0,0 +1,381 @@ +CONFIG_EXPERIMENTAL=y +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_KERNEL_LZO=y +CONFIG_LOG_BUF_SHIFT=19 +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_CGROUP_SCHED=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_PANIC_TIMEOUT=1 +# CONFIG_SYSCTL_SYSCALL is not set +# CONFIG_ELF_CORE is not set +CONFIG_ASHMEM=y +# CONFIG_AIO is not set +CONFIG_EMBEDDED=y +# CONFIG_SLUB_DEBUG is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_ARCH_RK2928=y +CONFIG_RK_DEBUG_UART=0 +CONFIG_MACH_RK2928_A720=y +CONFIG_FIQ_DEBUGGER=y +CONFIG_FIQ_DEBUGGER_NO_SLEEP=y +CONFIG_FIQ_DEBUGGER_CONSOLE=y +CONFIG_FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +CONFIG_HIGHMEM=y +CONFIG_COMPACTION=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=32768 +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="console=ttyFIQ0 androidboot.console=ttyFIQ0 init=/init" +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_WAKELOCK=y +CONFIG_PM_RUNTIME=y +CONFIG_SUSPEND_TIME=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_INET_ESP=y +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_TUNNEL=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SIP=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_REJECT_SKERR=y +CONFIG_IP_NF_TARGET_LOG=y +CONFIG_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_TARGET_LOG=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_TARGET_REJECT_SKERR=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE=y +# CONFIG_BRIDGE_IGMP_SNOOPING is not set +CONFIG_PHONET=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_BT=y +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_HIDP=y +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIBCM4325=y +CONFIG_BT_AUTOSLEEP=y +CONFIG_CFG80211=y +CONFIG_MAC80211=y +CONFIG_RFKILL=y +CONFIG_RFKILL_RK=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_FIRMWARE_IN_KERNEL is not set +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_NAND_IDS=y +CONFIG_MTD_RKNAND=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_MISC_DEVICES=y +CONFIG_UID_STAT=y +CONFIG_APANIC=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_NETDEVICES=y +CONFIG_PHYLIB=y +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +CONFIG_WLAN_80211=y +CONFIG_USB_USBNET=y +CONFIG_PPP=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_MPPE=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_KEYRESET=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_KEYCHORD=y +CONFIG_INPUT_UINPUT=y +CONFIG_SENSOR_DEVICE=y +# CONFIG_SERIO is not set +# CONFIG_CONSOLE_TRANSLATIONS is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_HW_RANDOM is not set +CONFIG_I2C=y +# CONFIG_I2C_COMPAT is not set +CONFIG_I2C0_CONTROLLER_RK30=y +CONFIG_I2C1_CONTROLLER_RK30=y +CONFIG_I2C2_CONTROLLER_RK30=y +CONFIG_I2C3_CONTROLLER_RK30=y +CONFIG_ADC_RK30=y +CONFIG_EXPANDED_GPIO_NUM=0 +CONFIG_EXPANDED_GPIO_IRQ_NUM=0 +CONFIG_SPI_FPGA_GPIO_NUM=0 +CONFIG_SPI_FPGA_GPIO_IRQ_NUM=0 +CONFIG_POWER_SUPPLY=y +CONFIG_TEST_POWER=y +# CONFIG_HWMON is not set +CONFIG_MFD_TPS65910=y +CONFIG_MFD_TPS65090=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_TPS65910=y +CONFIG_RK30_PWM_REGULATOR=y +CONFIG_ION=y +CONFIG_ION_ROCKCHIP=y +CONFIG_FB=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set +CONFIG_DISPLAY_SUPPORT=y +CONFIG_LCD_RK2928_A720=y +CONFIG_FB_ROCKCHIP=y +CONFIG_LCDC_RK2928=y +CONFIG_RGA_RK30=y +CONFIG_RK_LVDS=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +# CONFIG_LOGO_LINUX_BMP is not set +CONFIG_SOUND=y +CONFIG_SND=y +# CONFIG_SND_SUPPORT_OLD_API is not set +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_ARM is not set +CONFIG_SND_SOC=y +CONFIG_SND_RK29_SOC=y +CONFIG_SND_I2S_DMA_EVENT_STATIC=y +CONFIG_SND_RK_SOC_RK2928=y +CONFIG_SND_RK29_CODEC_SOC_SLAVE=y +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WALTOP=y +CONFIG_HID_GYRATION=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LCPOWER=y +CONFIG_HID_LOGITECH=y +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_LOGIWII_FF=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +CONFIG_HID_QUANTA=y +CONFIG_HID_ROCCAT_ARVO=y +CONFIG_HID_ROCCAT_KONE=y +CONFIG_HID_ROCCAT_KONEPLUS=y +CONFIG_HID_ROCCAT_KOVAPLUS=y +CONFIG_HID_ROCCAT_PYRA=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +CONFIG_GREENASIA_FF=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_THRUSTMASTER=y +CONFIG_THRUSTMASTER_FF=y +CONFIG_HID_WACOM=y +CONFIG_HID_ZEROPLUS=y +CONFIG_ZEROPLUS_FF=y +CONFIG_HID_ZYDACRON=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_OTG_BLACKLIST_HUB=y +CONFIG_USB_STORAGE=y +CONFIG_USB_SERIAL=y +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_OPTION=y +CONFIG_USB_GADGET=y +CONFIG_USB20_HOST=y +CONFIG_USB20_OTG=y +CONFIG_MMC=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_EMBEDDED_SDIO=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_SDMMC_RK29=y +# CONFIG_SDMMC0_RK29 is not set +# CONFIG_SDMMC1_RK29 is not set +CONFIG_SWITCH=y +CONFIG_SWITCH_GPIO=y +CONFIG_RTC_CLASS=y +CONFIG_TPS65910_RTC=y +CONFIG_STAGING=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOGGER=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +# CONFIG_CMMB is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_FS_XATTR is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_XATTR is not set +# CONFIG_DNOTIFY is not set +CONFIG_FUSE_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +# CONFIG_MISC_FILESYSTEMS is not set +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_EFI_PARTITION=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DETECT_HUNG_TASK=y +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_FTRACE is not set +CONFIG_CRYPTO_TWOFISH=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/arm/mach-rk2928/Kconfig b/arch/arm/mach-rk2928/Kconfig index 9427d232d354..5e8d1cf53bfc 100644 --- a/arch/arm/mach-rk2928/Kconfig +++ b/arch/arm/mach-rk2928/Kconfig @@ -10,6 +10,8 @@ config MACH_RK2928_FPGA config MACH_RK2928_SDK bool "RK2928 SDK board" +config MACH_RK2928_A720 + bool "RK2928 A720 board" endchoice endif diff --git a/arch/arm/mach-rk2928/Makefile b/arch/arm/mach-rk2928/Makefile index 6acd3f120855..e68d38bce304 100644 --- a/arch/arm/mach-rk2928/Makefile +++ b/arch/arm/mach-rk2928/Makefile @@ -13,3 +13,4 @@ CFLAGS_pm.o += -Os -mthumb obj-$(CONFIG_MACH_RK2928_FPGA) += board-rk2928-fpga.o obj-$(CONFIG_MACH_RK2928_SDK) += board-rk2928-sdk.o +obj-$(CONFIG_MACH_RK2928_A720) += board-rk2928-a720.o diff --git a/arch/arm/mach-rk2928/board-rk2928-a720-key.c b/arch/arm/mach-rk2928/board-rk2928-a720-key.c new file mode 100755 index 000000000000..73248246e9a3 --- /dev/null +++ b/arch/arm/mach-rk2928/board-rk2928-a720-key.c @@ -0,0 +1,39 @@ +#include +#include + +#define EV_ENCALL KEY_F4 +#define EV_MENU KEY_F1 + +#define PRESS_LEV_LOW 1 +#define PRESS_LEV_HIGH 0 + +static struct rk29_keys_button key_button[] = { + { + .desc = "play", + .code = KEY_POWER, + .gpio = RK2928_PIN1_PA4, + .active_low = PRESS_LEV_LOW, + //.code_long_press = EV_ENCALL, + .wakeup = 1, + }, + { + .desc = "vol+", + .code = KEY_VOLUMEUP, + .gpio = INVALID_GPIO, + .adc_value = 1, + .active_low = PRESS_LEV_LOW, + }, + { + .desc = "vol-", + .code = KEY_VOLUMEDOWN, + .gpio = INVALID_GPIO, + .adc_value = 512, + .active_low = PRESS_LEV_LOW, + }, +}; +struct rk29_keys_platform_data rk29_keys_pdata = { + .buttons = key_button, + .nbuttons = ARRAY_SIZE(key_button), + .chn = 1, //chn: 0-7, if do not use ADC,set 'chn' -1 +}; + diff --git a/arch/arm/mach-rk2928/board-rk2928-a720-tps65910.c b/arch/arm/mach-rk2928/board-rk2928-a720-tps65910.c new file mode 100755 index 000000000000..a34547d78a9f --- /dev/null +++ b/arch/arm/mach-rk2928/board-rk2928-a720-tps65910.c @@ -0,0 +1,628 @@ +#include +#include +#include +#include +#include + +#include +#include + +#define grf_readl(offset) readl_relaxed(RK30_GRF_BASE + offset) +#define grf_writel(v, offset) do { writel_relaxed(v, RK30_GRF_BASE + offset); dsb(); } while (0) + +#define CRU_CLKGATE5_CON_ADDR 0x00e4 +#define GRF_GPIO6L_DIR_ADDR 0x0030 +#define GRF_GPIO6L_DO_ADDR 0x0068 +#define GRF_GPIO6L_EN_ADDR 0x00a0 +#define GPIO6_PB3_DIR_OUT 0x08000800 +#define GPIO6_PB3_DO_LOW 0x08000000 +#define GPIO6_PB3_DO_HIGH 0x08000800 +#define GPIO6_PB3_EN_MASK 0x08000800 +#define GPIO6_PB3_UNEN_MASK 0x08000000 +#define GPIO6_PB1_DIR_OUT 0x02000200 +#define GPIO6_PB1_DO_LOW 0x02000000 +#define GPIO6_PB1_DO_HIGH 0x02000200 +#define GPIO6_PB1_EN_MASK 0x02000200 +#define GPIO6_PB1_UNEN_MASK 0x02000000 + +#ifdef CONFIG_MFD_TPS65910 +#define PMU_POWER_SLEEP RK2928_PIN3_PD2 +extern int platform_device_register(struct platform_device *pdev); + +int tps65910_pre_init(struct tps65910 *tps65910){ + + int val = 0; + int i = 0; + int err = -1; + + printk("%s,line=%d\n", __func__,__LINE__); + gpio_request(PMU_POWER_SLEEP, "NULL"); + gpio_direction_output(PMU_POWER_SLEEP, GPIO_LOW); + + val = tps65910_reg_read(tps65910, TPS65910_DEVCTRL2); + if (val<0) { + printk(KERN_ERR "Unable to read TPS65910_DEVCTRL2 reg\n"); + return val; + } + /* Set sleep state active high and allow device turn-off after PWRON long press */ + val |= (DEVCTRL2_SLEEPSIG_POL_MASK | DEVCTRL2_PWON_LP_OFF_MASK); + + err = tps65910_reg_write(tps65910, TPS65910_DEVCTRL2, val); + if (err) { + printk(KERN_ERR "Unable to write TPS65910_DEVCTRL2 reg\n"); + return err; + } + #if 1 + /* set PSKIP=0 */ + val = tps65910_reg_read(tps65910, TPS65910_DCDCCTRL); + if (val<0) { + printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n"); + return val; + } + + val &= ~DEVCTRL_DEV_OFF_MASK; + val &= ~DEVCTRL_DEV_SLP_MASK; + err = tps65910_reg_write(tps65910, TPS65910_DCDCCTRL, val); + if (err) { + printk(KERN_ERR "Unable to write TPS65910_DCDCCTRL reg\n"); + return err; + } + #endif + /* Set the maxinum load current */ + /* VDD1 */ + val = tps65910_reg_read(tps65910, TPS65910_VDD1); + if (val<0) { + printk(KERN_ERR "Unable to read TPS65910_VDD1 reg\n"); + return val; + } + + val |= (1<<5); //when 1: 1.5 A + val |= (0x07<<2); //TSTEP[2:0] = 111 : 2.5 mV/|ìs(sampling 3 Mhz/5) + err = tps65910_reg_write(tps65910, TPS65910_VDD1, val); + if (err) { + printk(KERN_ERR "Unable to write TPS65910_VDD1 reg\n"); + return err; + } + + /* VDD2 */ + val = tps65910_reg_read(tps65910, TPS65910_VDD2); + if (val<0) { + printk(KERN_ERR "Unable to read TPS65910_VDD2 reg\n"); + return val; + } + + val |= (1<<5); //when 1: 1.5 A + err = tps65910_reg_write(tps65910, TPS65910_VDD2, val); + if (err) { + printk(KERN_ERR "Unable to write TPS65910_VDD2 reg\n"); + return err; + } + + /* VIO */ + val = tps65910_reg_read(tps65910, TPS65910_VIO); + if (val<0) { + printk(KERN_ERR "Unable to read TPS65910_VIO reg\n"); + return -EIO; + } + + val |= (1<<6); //when 01: 1.0 A + err = tps65910_reg_write(tps65910, TPS65910_VIO, val); + if (err) { + printk(KERN_ERR "Unable to write TPS65910_VIO reg\n"); + return err; + } + #if 1 + /* Mask ALL interrupts */ + err = tps65910_reg_write(tps65910,TPS65910_INT_MSK, 0xFF); + if (err) { + printk(KERN_ERR "Unable to write TPS65910_INT_MSK reg\n"); + return err; + } + + err = tps65910_reg_write(tps65910, TPS65910_INT_MSK2, 0x03); + if (err) { + printk(KERN_ERR "Unable to write TPS65910_INT_MSK2 reg\n"); + return err; + } + + /* Set RTC Power, disable Smart Reflex in DEVCTRL_REG */ + #if 1 + val = 0; + val |= (DEVCTRL_SR_CTL_I2C_SEL_MASK); + err = tps65910_reg_write(tps65910, TPS65910_DEVCTRL, val); + if (err) { + printk(KERN_ERR "Unable to write TPS65910_DEVCTRL reg\n"); + return err; + } + printk(KERN_INFO "TPS65910 Set default voltage.\n"); + #endif + #if 0 + //read sleep control register for debug + for(i=0; i<6; i++) + { + err = tps65910_reg_read(tps65910, &val, TPS65910_DEVCTRL+i); + if (err) { + printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n"); + return -EIO; + } + else + printk("%s.......is 0x%04x\n",__FUNCTION__,val); + } + #endif + + #if 1 + //sleep control register + /*set func when in sleep mode */ + val = tps65910_reg_read(tps65910, TPS65910_DEVCTRL); + if (val<0) { + printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n"); + return val; + } + + val |= (1 << 1); + err = tps65910_reg_write(tps65910, TPS65910_DEVCTRL, val); + if (err) { + printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \ + \n", TPS65910_VDIG1); + return err; + } + + /* open ldo when in sleep mode */ + val = tps65910_reg_read(tps65910, TPS65910_SLEEP_KEEP_LDO_ON); + if (val<0) { + printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n"); + return val; + } + + val &= 0; + err = tps65910_reg_write(tps65910, TPS65910_SLEEP_KEEP_LDO_ON, val); + if (err) { + printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \ + \n", TPS65910_VDIG1); + return err; + } + + /*set dc mode when in sleep mode */ + val = tps65910_reg_read(tps65910, TPS65910_SLEEP_KEEP_RES_ON); + if (val<0) { + printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n"); + return val; + } + + val |= 0xff; + err = tps65910_reg_write(tps65910, TPS65910_SLEEP_KEEP_RES_ON, val); + if (err) { + printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \ + \n", TPS65910_VDIG1); + return err; + } + + /*close ldo when in sleep mode */ + val = tps65910_reg_read(tps65910, TPS65910_SLEEP_SET_LDO_OFF); + if (val<0) { + printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n"); + return val; + } + + val |= 0x9B; + err = tps65910_reg_write(tps65910, TPS65910_SLEEP_SET_LDO_OFF, val); + if (err) { + printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \ + \n", TPS65910_VDIG1); + return err; + } + + #endif + #if 0 + //read sleep control register for debug + for(i=0; i<6; i++) + { + err = tps65910_reg_read(tps65910, &val, TPS65910_DEVCTRL+i); + if (err) { + printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n"); + return -EIO; + } + else + printk("%s.......is 0x%4x\n",__FUNCTION__,val); + } + #endif + #endif + + printk("%s,line=%d\n", __func__,__LINE__); + return 0; + +} +int tps65910_post_init(struct tps65910 *tps65910) +{ + struct regulator *dcdc; + struct regulator *ldo; + printk("%s,line=%d\n", __func__,__LINE__); + + #ifdef CONFIG_RK30_PWM_REGULATOR + platform_device_register(&pwm_regulator_device[0]); + #endif + + dcdc = regulator_get(NULL, "vio"); //vcc_io + regulator_set_voltage(dcdc, 3300000, 3300000); + regulator_enable(dcdc); + printk("%s set vio vcc_io=%dmV end\n", __func__, regulator_get_voltage(dcdc)); + regulator_put(dcdc); + udelay(100); + /* + ldo = regulator_get(NULL, "vpll"); // vcc25 + regulator_set_voltage(ldo, 2500000, 2500000); + regulator_enable(ldo); + printk("%s set vpll vcc25=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + */ + ldo = regulator_get(NULL, "vdig2"); // vdd12 + regulator_set_voltage(ldo, 1200000, 1200000); + regulator_enable(ldo); + printk("%s set vdig2 vdd12=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "vaux33"); //vcc_tp + regulator_set_voltage(ldo, 3300000, 3300000); + regulator_enable(ldo); + printk("%s set vaux33 vcc_tp=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + dcdc = regulator_get(NULL, "vdd_cpu"); //vdd_cpu + regulator_set_voltage(dcdc, 1200000, 1200000); + regulator_enable(dcdc); + printk("%s set vdd1 vdd_cpu=%dmV end\n", __func__, regulator_get_voltage(dcdc)); + regulator_put(dcdc); + udelay(100); + + dcdc = regulator_get(NULL, "vdd2"); //vcc_ddr + regulator_set_voltage(dcdc, 1200000, 1200000); // 1.5*4/5 = 1.2 and Vout=1.5v + regulator_enable(dcdc); + printk("%s set vdd2 vcc_ddr=%dmV end\n", __func__, regulator_get_voltage(dcdc)); + regulator_put(dcdc); + udelay(100); + + ldo = regulator_get(NULL, "vdig1"); //vcc18_cif + regulator_set_voltage(ldo, 1500000, 1500000); + regulator_enable(ldo); + printk("%s set vdig1 vcc18_cif=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + dcdc = regulator_get(NULL, "vaux1"); //vcc28_cif + regulator_set_voltage(dcdc,2800000,2800000); + regulator_enable(dcdc); + printk("%s set vaux1 vcc28_cif=%dmV end\n", __func__, regulator_get_voltage(dcdc)); + regulator_put(dcdc); + udelay(100); + + ldo = regulator_get(NULL, "vaux2"); //vcca33 + regulator_set_voltage(ldo, 3300000, 3300000); + regulator_enable(ldo); + printk("%s set vaux2 vcca33=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + /* + ldo = regulator_get(NULL, "vdac"); // vccio_wl + regulator_set_voltage(ldo,1800000,1800000); + regulator_enable(ldo); + printk("%s set vdac vccio_wl=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + */ + ldo = regulator_get(NULL, "vmmc"); //vccio_wl + regulator_set_voltage(ldo,3300000,3300000); + regulator_enable(ldo); + printk("%s set vmmc vccio_wl=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + printk("%s,line=%d END\n", __func__,__LINE__); + + return 0; +} + +static struct regulator_consumer_supply tps65910_smps1_supply[] = { + { + .supply = "vdd1", + }, + { + .supply = "vdd_cpu", + }, +}; +static struct regulator_consumer_supply tps65910_smps2_supply[] = { + { + .supply = "vdd2", + }, + +}; +static struct regulator_consumer_supply tps65910_smps3_supply[] = { + { + .supply = "vdd3", + }, +}; +static struct regulator_consumer_supply tps65910_smps4_supply[] = { + { + .supply = "vio", + }, +}; +static struct regulator_consumer_supply tps65910_ldo1_supply[] = { + { + .supply = "vdig1", + }, +}; +static struct regulator_consumer_supply tps65910_ldo2_supply[] = { + { + .supply = "vdig2", + }, +}; + +static struct regulator_consumer_supply tps65910_ldo3_supply[] = { + { + .supply = "vaux1", + }, +}; +static struct regulator_consumer_supply tps65910_ldo4_supply[] = { + { + .supply = "vaux2", + }, +}; +static struct regulator_consumer_supply tps65910_ldo5_supply[] = { + { + .supply = "vaux33", + }, +}; +static struct regulator_consumer_supply tps65910_ldo6_supply[] = { + { + .supply = "vmmc", + }, +}; +static struct regulator_consumer_supply tps65910_ldo7_supply[] = { + { + .supply = "vdac", + }, +}; + +static struct regulator_consumer_supply tps65910_ldo8_supply[] = { + { + .supply = "vpll", + }, +}; + +static struct regulator_init_data tps65910_smps1 = { + .constraints = { + .name = "VDD1", + .min_uV = 600000, + .max_uV = 1500000, + .apply_uV = 1, + .always_on = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + + }, + .num_consumer_supplies = ARRAY_SIZE(tps65910_smps1_supply), + .consumer_supplies = tps65910_smps1_supply, +}; + +/* */ +static struct regulator_init_data tps65910_smps2 = { + .constraints = { + .name = "VDD2", + .min_uV = 600000, + .max_uV = 1500000, + .apply_uV = 1, + .always_on = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + + }, + .num_consumer_supplies = ARRAY_SIZE(tps65910_smps2_supply), + .consumer_supplies = tps65910_smps2_supply, +}; + +/* */ +static struct regulator_init_data tps65910_smps3 = { + .constraints = { + .name = "VDD3", + .min_uV = 1000000, + .max_uV = 1400000, + .apply_uV = 1, + .always_on = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + + }, + .num_consumer_supplies = ARRAY_SIZE(tps65910_smps3_supply), + .consumer_supplies = tps65910_smps3_supply, +}; + +static struct regulator_init_data tps65910_smps4 = { + .constraints = { + .name = "VIO", + .min_uV = 1800000, + .max_uV = 3300000, + .apply_uV = 1, + .always_on = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + + }, + .num_consumer_supplies = ARRAY_SIZE(tps65910_smps4_supply), + .consumer_supplies = tps65910_smps4_supply, +}; +static struct regulator_init_data tps65910_ldo1 = { + .constraints = { + .name = "VDIG1", + .min_uV = 1200000, + .max_uV = 2700000, + .apply_uV = 1, + + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + + }, + .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo1_supply), + .consumer_supplies = tps65910_ldo1_supply, +}; + +/* */ +static struct regulator_init_data tps65910_ldo2 = { + .constraints = { + .name = "VDIG2", + .min_uV = 1000000, + .max_uV = 1800000, + .apply_uV = 1, + + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + + }, + .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo2_supply), + .consumer_supplies = tps65910_ldo2_supply, +}; + +/* */ +static struct regulator_init_data tps65910_ldo3 = { + .constraints = { + .name = "VAUX1", + .min_uV = 1800000, + .max_uV = 3300000, + .apply_uV = 1, + + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + + }, + .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo3_supply), + .consumer_supplies = tps65910_ldo3_supply, +}; + +/* */ +static struct regulator_init_data tps65910_ldo4 = { + .constraints = { + .name = "VAUX2", + .min_uV = 1800000, + .max_uV = 3300000, + .apply_uV = 1, + + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + + }, + .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo4_supply), + .consumer_supplies = tps65910_ldo4_supply, +}; + +/* */ +static struct regulator_init_data tps65910_ldo5 = { + .constraints = { + .name = "VAUX33", + .min_uV = 1800000, + .max_uV = 3300000, + .apply_uV = 1, + + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + + }, + .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo5_supply), + .consumer_supplies = tps65910_ldo5_supply, +}; + +/* */ +static struct regulator_init_data tps65910_ldo6 = { + .constraints = { + .name = "VMMC", + .min_uV = 1800000, + .max_uV = 3300000, + .apply_uV = 1, + + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + + }, + .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo6_supply), + .consumer_supplies = tps65910_ldo6_supply, +}; + +/* */ +static struct regulator_init_data tps65910_ldo7 = { + .constraints = { + .name = "VDAC", + .min_uV = 1800000, + .max_uV = 2850000, + .apply_uV = 1, + + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + + }, + .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo7_supply), + .consumer_supplies = tps65910_ldo7_supply, +}; + +/* */ +static struct regulator_init_data tps65910_ldo8 = { + .constraints = { + .name = "VPLL", + .min_uV = 1000000, + .max_uV = 2500000, + .apply_uV = 1, + .always_on = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + + }, + .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo8_supply), + .consumer_supplies = tps65910_ldo8_supply, +}; +/* +void __sramfunc board_pmu_tps65910_suspend(void) +{ + grf_writel(GPIO6_PB1_DIR_OUT, GRF_GPIO6L_DIR_ADDR); + grf_writel(GPIO6_PB1_DO_HIGH, GRF_GPIO6L_DO_ADDR); //set gpio6_b1 output low + grf_writel(GPIO6_PB1_EN_MASK, GRF_GPIO6L_EN_ADDR); +} +void __sramfunc board_pmu_tps65910_resume(void) +{ + grf_writel(GPIO6_PB1_DIR_OUT, GRF_GPIO6L_DIR_ADDR); + grf_writel(GPIO6_PB1_DO_LOW, GRF_GPIO6L_DO_ADDR); //set gpio6_b1 output low + grf_writel(GPIO6_PB1_EN_MASK, GRF_GPIO6L_EN_ADDR); + #ifdef CONFIG_CLK_SWITCH_TO_32K //switch clk to 24M + sram_32k_udelay(10000); + #else + sram_udelay(2000); + #endif +} +*/ +static struct tps65910_board tps65910_data = { + .irq = (unsigned)TPS65910_HOST_IRQ, + .irq_base = NR_GIC_IRQS + NR_GPIO_IRQS, + .gpio_base = TPS65910_GPIO_EXPANDER_BASE, + + .pre_init = tps65910_pre_init, + .post_init = tps65910_post_init, + + //TPS65910_NUM_REGS = 13 + // Regulators + .tps65910_pmic_init_data[TPS65910_REG_VRTC] = NULL, + .tps65910_pmic_init_data[TPS65910_REG_VIO] = &tps65910_smps4, + .tps65910_pmic_init_data[TPS65910_REG_VDD1] = &tps65910_smps1, + .tps65910_pmic_init_data[TPS65910_REG_VDD2] = &tps65910_smps2, + .tps65910_pmic_init_data[TPS65910_REG_VDD3] = &tps65910_smps3, + .tps65910_pmic_init_data[TPS65910_REG_VDIG1] = &tps65910_ldo1, + .tps65910_pmic_init_data[TPS65910_REG_VDIG2] = &tps65910_ldo2, + .tps65910_pmic_init_data[TPS65910_REG_VPLL] = &tps65910_ldo8, + .tps65910_pmic_init_data[TPS65910_REG_VDAC] = &tps65910_ldo7, + .tps65910_pmic_init_data[TPS65910_REG_VAUX1] = &tps65910_ldo3, + .tps65910_pmic_init_data[TPS65910_REG_VAUX2] = &tps65910_ldo4, + .tps65910_pmic_init_data[TPS65910_REG_VAUX33] = &tps65910_ldo5, + .tps65910_pmic_init_data[TPS65910_REG_VMMC] = &tps65910_ldo6, + + +}; + +#endif + diff --git a/arch/arm/mach-rk2928/board-rk2928-a720.c b/arch/arm/mach-rk2928/board-rk2928-a720.c new file mode 100755 index 000000000000..d5da5352fb97 --- /dev/null +++ b/arch/arm/mach-rk2928/board-rk2928-a720.c @@ -0,0 +1,499 @@ +/* arch/arm/mach-rk2928/board-rk2928-fpga.c + * + * Copyright (C) 2012 ROCKCHIP, Inc. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_HDMI_RK30) + #include "../../../drivers/video/rockchip/hdmi/rk_hdmi.h" +#endif + +#if defined(CONFIG_SPIM_RK29) +#include "../../../drivers/spi/rk29_spim.h" +#endif + +#include "board-rk2928-a720-key.c" + +#ifdef CONFIG_THREE_FB_BUFFER +#define RK30_FB0_MEM_SIZE 12*SZ_1M +#else +#define RK30_FB0_MEM_SIZE 8*SZ_1M +#endif + +static struct spi_board_info board_spi_devices[] = { +}; + +/*********************************************************** +* rk30 backlight +************************************************************/ +#ifdef CONFIG_BACKLIGHT_RK29_BL +#define PWM_ID 0 +#define PWM_MUX_NAME GPIO0D2_PWM_0_NAME +#define PWM_MUX_MODE GPIO0D_PWM_0 +#define PWM_MUX_MODE_GPIO GPIO0D_GPIO0D2 +#define PWM_GPIO RK2928_PIN0_PD2 +#define PWM_EFFECT_VALUE 1 + +#define LCD_DISP_ON_PIN + +#ifdef LCD_DISP_ON_PIN + +#define BL_EN_PIN RK2928_PIN1_PB0 +#define BL_EN_VALUE GPIO_HIGH +#endif +static int rk29_backlight_io_init(void) +{ + int ret = 0; + rk30_mux_api_set(PWM_MUX_NAME, PWM_MUX_MODE); +#ifdef LCD_DISP_ON_PIN + // rk30_mux_api_set(BL_EN_MUX_NAME, BL_EN_MUX_MODE); + + ret = gpio_request(BL_EN_PIN, NULL); + if (ret != 0) { + gpio_free(BL_EN_PIN); + } + + gpio_direction_output(BL_EN_PIN, 0); + gpio_set_value(BL_EN_PIN, BL_EN_VALUE); +#endif + return ret; +} + +static int rk29_backlight_io_deinit(void) +{ + int ret = 0; +#ifdef LCD_DISP_ON_PIN + gpio_free(BL_EN_PIN); +#endif + rk30_mux_api_set(PWM_MUX_NAME, PWM_MUX_MODE_GPIO); + return ret; +} + +static int rk29_backlight_pwm_suspend(void) +{ + int ret = 0; + rk30_mux_api_set(PWM_MUX_NAME, PWM_MUX_MODE_GPIO); + if (gpio_request(PWM_GPIO, NULL)) { + printk("func %s, line %d: request gpio fail\n", __FUNCTION__, __LINE__); + return -1; + } + gpio_direction_output(PWM_GPIO, GPIO_LOW); +#ifdef LCD_DISP_ON_PIN + gpio_direction_output(BL_EN_PIN, 0); + gpio_set_value(BL_EN_PIN, !BL_EN_VALUE); +#endif + + return ret; +} + +static int rk29_backlight_pwm_resume(void) +{ + gpio_free(PWM_GPIO); + rk30_mux_api_set(PWM_MUX_NAME, PWM_MUX_MODE); +#ifdef LCD_DISP_ON_PIN + msleep(30); + gpio_direction_output(BL_EN_PIN, 1); + gpio_set_value(BL_EN_PIN, BL_EN_VALUE); +#endif + return 0; +} + +static struct rk29_bl_info rk29_bl_info = { + .pwm_id = PWM_ID, + .bl_ref = PWM_EFFECT_VALUE, + .io_init = rk29_backlight_io_init, + .io_deinit = rk29_backlight_io_deinit, + .pwm_suspend = rk29_backlight_pwm_suspend, + .pwm_resume = rk29_backlight_pwm_resume, +}; + +static struct platform_device rk29_device_backlight = { + .name = "rk29_backlight", + .id = -1, + .dev = { + .platform_data = &rk29_bl_info, + } +}; + +#endif + +#ifdef CONFIG_FB_ROCKCHIP + +#define LCD_MUX_NAME GPIO0C2_UART0_RTSN_NAME +#define LCD_GPIO_MODE GPIO0C_GPIO0C2 + +#define LCD_EN RK2928_PIN0_PC2 +#define LCD_EN_VALUE GPIO_LOW + +static int rk_fb_io_init(struct rk29_fb_setting_info *fb_setting) +{ + int ret = 0; + + rk30_mux_api_set(LCD_MUX_NAME, LCD_GPIO_MODE); + + ret = gpio_request(LCD_EN, NULL); + if (ret != 0) + { + gpio_free(LCD_EN); + printk(KERN_ERR "request lcd en pin fail!\n"); + return -1; + } + else + { + gpio_direction_output(LCD_EN, LCD_EN_VALUE); //disable + } + return 0; +} +static int rk_fb_io_disable(void) +{ + gpio_set_value(LCD_EN, !LCD_EN_VALUE); + return 0; +} +static int rk_fb_io_enable(void) +{ + gpio_set_value(LCD_EN, LCD_EN_VALUE); + return 0; +} + +#if defined(CONFIG_LCDC_RK2928) +struct rk29fb_info lcdc_screen_info = { + .prop = PRMRY, //primary display device + .io_init = rk_fb_io_init, + .io_disable = rk_fb_io_disable, + .io_enable = rk_fb_io_enable, + .set_screen_info = set_lcd_info, +}; +#endif + +static struct resource resource_fb[] = { + [0] = { + .name = "fb0 buf", + .start = 0, + .end = 0,//RK30_FB0_MEM_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "ipp buf", //for rotate + .start = 0, + .end = 0,//RK30_FB0_MEM_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [2] = { + .name = "fb2 buf", + .start = 0, + .end = 0,//RK30_FB0_MEM_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device device_fb = { + .name = "rk-fb", + .id = -1, + .num_resources = ARRAY_SIZE(resource_fb), + .resource = resource_fb, +}; +#endif + +#ifdef CONFIG_ION +#define ION_RESERVE_SIZE (80 * SZ_1M) +static struct ion_platform_data rk30_ion_pdata = { + .nr = 1, + .heaps = { + { + .type = ION_HEAP_TYPE_CARVEOUT, + .id = ION_NOR_HEAP_ID, + .name = "norheap", + .size = ION_RESERVE_SIZE, + } + }, +}; + +static struct platform_device device_ion = { + .name = "ion-rockchip", + .id = 0, + .dev = { + .platform_data = &rk30_ion_pdata, + }, +}; +#endif + +#if CONFIG_RK30_PWM_REGULATOR +const static int pwm_voltage_map[] = { + 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 1400000 +}; + +static struct regulator_consumer_supply pwm_dcdc1_consumers[] = { + { + .supply = "vdd_core", + } +}; + +struct regulator_init_data pwm_regulator_init_dcdc[1] = +{ + { + .constraints = { + .name = "PWM_DCDC1", + .min_uV = 600000, + .max_uV = 1800000, //0.6-1.8V + .apply_uV = true, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(pwm_dcdc1_consumers), + .consumer_supplies = pwm_dcdc1_consumers, + }, +}; + +static struct pwm_platform_data pwm_regulator_info[1] = { + { + .pwm_id = 2, + .pwm_gpio = RK2928_PIN0_PD4, + .pwm_iomux_name = GPIO0D4_PWM_2_NAME, + .pwm_iomux_pwm = GPIO0D_PWM_2, + .pwm_iomux_gpio = GPIO0D_GPIO0D4, + .pwm_voltage = 1200000, + .suspend_voltage = 1050000, + .min_uV = 1000000, + .max_uV = 1400000, + .coefficient = 455, //45.5% + .pwm_voltage_map = pwm_voltage_map, + .init_data = &pwm_regulator_init_dcdc[0], + }, +}; + +struct platform_device pwm_regulator_device[1] = { + { + .name = "pwm-voltage-regulator", + .id = 0, + .dev = { + .platform_data = &pwm_regulator_info[0], + } + }, +}; +#endif + + +static struct platform_device *devices[] __initdata = { +#ifdef CONFIG_BACKLIGHT_RK29_BL + &rk29_device_backlight, +#endif +#ifdef CONFIG_FB_ROCKCHIP + &device_fb, +#endif +#ifdef CONFIG_ION + &device_ion, +#endif +}; +//i2c +#ifdef CONFIG_I2C0_RK30 +#ifdef CONFIG_MFD_TPS65910 +#define TPS65910_HOST_IRQ RK2928_PIN1_PB2 +#include "board-rk2928-a720-tps65910.c" +#endif +static struct i2c_board_info __initdata i2c0_info[] = { +#if defined (CONFIG_MFD_TPS65910) + { + .type = "tps65910", + .addr = TPS65910_I2C_ID0, + .flags = 0, + .irq = TPS65910_HOST_IRQ, + .platform_data = &tps65910_data, + }, +#endif +}; +#endif +#ifdef CONFIG_I2C1_RK30 +static struct i2c_board_info __initdata i2c1_info[] = { +}; +#endif +#ifdef CONFIG_I2C2_RK30 +static struct i2c_board_info __initdata i2c2_info[] = { +}; +#endif +#ifdef CONFIG_I2C3_RK30 +static struct i2c_board_info __initdata i2c3_info[] = { +}; +#endif +#ifdef CONFIG_I2C_GPIO_RK30 +#define I2C_SDA_PIN INVALID_GPIO //set sda_pin here +#define I2C_SCL_PIN INVALID_GPIO //set scl_pin here +static int rk30_i2c_io_init(void) +{ + //set iomux (gpio) here + + return 0; +} +struct i2c_gpio_platform_data default_i2c_gpio_data = { + .sda_pin = I2C_SDA_PIN, + .scl_pin = I2C_SCL_PIN, + .udelay = 5, // clk = 500/udelay = 100Khz + .timeout = 100,//msecs_to_jiffies(100), + .bus_num = 5, + .io_init = rk30_i2c_io_init, +}; +static struct i2c_board_info __initdata i2c_gpio_info[] = { +}; +#endif +static void __init rk30_i2c_register_board_info(void) +{ +#ifdef CONFIG_I2C0_RK30 + i2c_register_board_info(0, i2c0_info, ARRAY_SIZE(i2c0_info)); +#endif +#ifdef CONFIG_I2C1_RK30 + i2c_register_board_info(1, i2c1_info, ARRAY_SIZE(i2c1_info)); +#endif +#ifdef CONFIG_I2C2_RK30 + i2c_register_board_info(2, i2c2_info, ARRAY_SIZE(i2c2_info)); +#endif +#ifdef CONFIG_I2C3_RK30 + i2c_register_board_info(3, i2c3_info, ARRAY_SIZE(i2c3_info)); +#endif +#ifdef CONFIG_I2C_GPIO_RK30 + i2c_register_board_info(4, i2c_gpio_info, ARRAY_SIZE(i2c_gpio_info)); +#endif +} +//end of i2c + +#define POWER_ON_PIN RK2928_PIN1_PA4 //power_hold +static void rk2928_pm_power_off(void) +{ + printk(KERN_ERR "rk2928_pm_power_off start...\n"); + + #if defined(CONFIG_MFD_TPS65910) + tps65910_device_shutdown();//tps65910 shutdown + #endif + gpio_direction_output(POWER_ON_PIN, GPIO_LOW); + +}; + +static void __init rk2928_board_init(void) +{ + gpio_request(POWER_ON_PIN, "poweronpin"); + gpio_direction_output(POWER_ON_PIN, GPIO_HIGH); + gpio_free(POWER_ON_PIN); + + pm_power_off = rk2928_pm_power_off; + + rk30_i2c_register_board_info(); + spi_register_board_info(board_spi_devices, ARRAY_SIZE(board_spi_devices)); + platform_add_devices(devices, ARRAY_SIZE(devices)); + +} + +static void __init rk2928_reserve(void) +{ +#ifdef CONFIG_ION + rk30_ion_pdata.heaps[0].base = board_mem_reserve_add("ion", ION_RESERVE_SIZE); +#endif +#ifdef CONFIG_FB_ROCKCHIP + resource_fb[0].start = board_mem_reserve_add("fb0", RK30_FB0_MEM_SIZE); + resource_fb[0].end = resource_fb[0].start + RK30_FB0_MEM_SIZE - 1; +#endif +#ifdef CONFIG_VIDEO_RK29 + rk30_camera_request_reserve_mem(); +#endif + board_mem_reserved(); +} +/** + * dvfs_cpu_logic_table: table for arm and logic dvfs + * @frequency : arm frequency + * @cpu_volt : arm voltage depend on frequency + * @logic_volt : logic voltage arm requests depend on frequency + * comments : min arm/logic voltage + */ +static struct dvfs_arm_table dvfs_cpu_logic_table[] = { + {.frequency = 216 * 1000, .cpu_volt = 1200 * 1000, .logic_volt = 1200 * 1000},//0.975V/1.000V + {.frequency = 312 * 1000, .cpu_volt = 1200 * 1000, .logic_volt = 1200 * 1000},//0.975V/1.000V + {.frequency = 408 * 1000, .cpu_volt = 1200 * 1000, .logic_volt = 1200 * 1000},//1.000V/1.025V + {.frequency = 504 * 1000, .cpu_volt = 1200 * 1000, .logic_volt = 1200 * 1000},//1.000V/1.025V + {.frequency = 600 * 1000, .cpu_volt = 1200 * 1000, .logic_volt = 1200 * 1000},//1.025V/1.050V + //{.frequency = 696 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.000V/1.025V + //{.frequency = 816 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V + //{.frequency = 912 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V +#if 0 + {.frequency = 1008 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V + {.frequency = 1104 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V + {.frequency = 1200 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V + {.frequency = 1104 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V + {.frequency = 1248 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V +#endif + //{.frequency = 1000 * 1000, .cpu_volt = 1225 * 1000, .logic_volt = 1200 * 1000},//1.150V/1.100V + {.frequency = CPUFREQ_TABLE_END}, +}; + +static struct cpufreq_frequency_table dvfs_gpu_table[] = { + {.frequency = 266 * 1000, .index = 1050 * 1000}, + {.frequency = 400 * 1000, .index = 1275 * 1000}, + {.frequency = CPUFREQ_TABLE_END}, +}; + +static struct cpufreq_frequency_table dvfs_ddr_table[] = { + {.frequency = 300 * 1000, .index = 1050 * 1000}, + {.frequency = 400 * 1000, .index = 1125 * 1000}, + {.frequency = CPUFREQ_TABLE_END}, +}; + +#define DVFS_CPU_TABLE_SIZE (ARRAY_SIZE(dvfs_cpu_logic_table)) +static struct cpufreq_frequency_table cpu_dvfs_table[DVFS_CPU_TABLE_SIZE]; +static struct cpufreq_frequency_table dep_cpu2core_table[DVFS_CPU_TABLE_SIZE]; + +void __init board_clock_init(void) +{ + rk2928_clock_data_init(periph_pll_default, codec_pll_default, RK30_CLOCKS_DEFAULT_FLAGS); + dvfs_set_arm_logic_volt(dvfs_cpu_logic_table, cpu_dvfs_table, dep_cpu2core_table); + dvfs_set_freq_volt_table(clk_get(NULL, "gpu"), dvfs_gpu_table); + //dvfs_set_freq_volt_table(clk_get(NULL, "ddr"), dvfs_ddr_table); + printk("%s end\n", __func__); +} + + +MACHINE_START(RK2928, "RK2928board") + .boot_params = PLAT_PHYS_OFFSET + 0x800, + .fixup = rk2928_fixup, + .reserve = &rk2928_reserve, + .map_io = rk2928_map_io, + .init_irq = rk2928_init_irq, + .timer = &rk2928_timer, + .init_machine = rk2928_board_init, +MACHINE_END diff --git a/arch/arm/mach-rk2928/clock_data.c b/arch/arm/mach-rk2928/clock_data.c index 50eb07b4e6f4..a1c3440bdbd4 100644 --- a/arch/arm/mach-rk2928/clock_data.c +++ b/arch/arm/mach-rk2928/clock_data.c @@ -2449,7 +2449,7 @@ static void __init rk2928_clock_common_init(unsigned long gpll_rate,unsigned lon { CLKDATA_DBG("ENTER %s\n", __func__); - clk_set_rate_nolock(&clk_core_pre, 816 * MHZ);//816 + clk_set_rate_nolock(&clk_core_pre, 600 * MHZ);//816? //general clk_set_rate_nolock(&general_pll_clk, gpll_rate); //code pll diff --git a/drivers/input/keyboard/rk29_keys.c b/drivers/input/keyboard/rk29_keys.c index 79e1b678ecd5..1fc354b1d2f7 100755 --- a/drivers/input/keyboard/rk29_keys.c +++ b/drivers/input/keyboard/rk29_keys.c @@ -29,7 +29,7 @@ #define EMPTY_ADVALUE 950 #define DRIFT_ADVALUE 70 -#define INVALID_ADVALUE 10 +#define INVALID_ADVALUE -1 #define EV_MENU KEY_F1 diff --git a/drivers/video/display/screen/Kconfig b/drivers/video/display/screen/Kconfig index 0b62f51a534b..7f075480c6d7 100644 --- a/drivers/video/display/screen/Kconfig +++ b/drivers/video/display/screen/Kconfig @@ -92,6 +92,9 @@ config LCD_HV070WSA100 bool "HV070WSA-100 1024X600" config LCD_COMMON bool "LCD COMMON" +config LCD_RK2928_A720 + bool "RK2928 A720 panel 800x480" + endchoice diff --git a/drivers/video/display/screen/Makefile b/drivers/video/display/screen/Makefile index 08f3f71b6d8b..d9f0b5c890ba 100644 --- a/drivers/video/display/screen/Makefile +++ b/drivers/video/display/screen/Makefile @@ -42,3 +42,4 @@ obj-$(CONFIG_LCD_HJ050NA_06A) += lcd_hj050na_06a.o obj-$(CONFIG_LCD_HSD100PXN_FOR_TDW851) += lcd_hsd100pxn_for_tdw851.o obj-$(CONFIG_LCD_HV070WSA100) += lcd_hv070wsa.o obj-$(CONFIG_LCD_COMMON) += lcd_common.o +obj-$(CONFIG_LCD_RK2928_A720) += lcd_rk2928_a720.o diff --git a/drivers/video/display/screen/lcd_rk2928_a720.c b/drivers/video/display/screen/lcd_rk2928_a720.c new file mode 100644 index 000000000000..c7e7290c61d4 --- /dev/null +++ b/drivers/video/display/screen/lcd_rk2928_a720.c @@ -0,0 +1,80 @@ +/* This Lcd Driver is HSD070IDW1 write by cst 2009.10.27 */ +#include +#include +#include "../../rk29_fb.h" +#include +#include +#include +#include "screen.h" + + +/* Base */ +#define OUT_TYPE SCREEN_RGB +#define OUT_FACE OUT_P666 +#define OUT_CLK 30000000 +#define LCDC_ACLK 150000000 //29 lcdc axi DMA 频率 + +/* Timing */ +#define H_PW 48 //10 +#define H_BP 40 //100 +#define H_VD 800 //1024 +#define H_FP 40 //210 + +#define V_PW 3 //10 +#define V_BP 29 //10 +#define V_VD 480 //768 +#define V_FP 13 //18 + +/* Other */ +#define DCLK_POL 0 +#define SWAP_RB 0 + +#define LCD_WIDTH 154 //need modify +#define LCD_HEIGHT 85 + +static struct rk29lcd_info *gLcd_info = NULL; + +void set_lcd_info(struct rk29fb_screen *screen, struct rk29lcd_info *lcd_info ) +{ + /* screen type & face */ + screen->type = OUT_TYPE; + screen->face = OUT_FACE; + + /* Screen size */ + screen->x_res = H_VD; + screen->y_res = V_VD; + + screen->width = LCD_WIDTH; + screen->height = LCD_HEIGHT; + + /* Timing */ + screen->lcdc_aclk = LCDC_ACLK; + screen->pixclock = OUT_CLK; + screen->left_margin = H_BP; + screen->right_margin = H_FP; + screen->hsync_len = H_PW; + screen->upper_margin = V_BP; + screen->lower_margin = V_FP; + screen->vsync_len = V_PW; + + /* Pin polarity */ + screen->pin_hsync = 0; + screen->pin_vsync = 0; + screen->pin_den = 0; + screen->pin_dclk = DCLK_POL; + + /* Swap rule */ + screen->swap_rb = SWAP_RB; + screen->swap_rg = 0; + screen->swap_gb = 0; + screen->swap_delta = 0; + screen->swap_dumy = 0; + + /* Operation function*/ + /*screen->init = init;*/ + screen->init = NULL; + screen->standby = NULL; + if(lcd_info) + gLcd_info = lcd_info; +} + diff --git a/drivers/video/rockchip/chips/rk2928_lcdc.c b/drivers/video/rockchip/chips/rk2928_lcdc.c index df7b28ee423d..e7dfdd262f6d 100755 --- a/drivers/video/rockchip/chips/rk2928_lcdc.c +++ b/drivers/video/rockchip/chips/rk2928_lcdc.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "rk2928_lcdc.h" #include "../lvds/rk_lvds.h" @@ -71,6 +72,30 @@ static int init_rk2928_lcdc(struct rk_lcdc_device_driver *dev_drv) #ifdef CONFIG_RK_LVDS rk_lvds_register(lcdc_dev->screen); #endif + if(lcdc_dev->screen->type == SCREEN_RGB) //iomux for RGB screen + { + + rk30_mux_api_set(GPIO2B0_LCDC0_DCLK_LCDC1_DCLK_NAME, GPIO2B_LCDC0_DCLK); + rk30_mux_api_set(GPIO2B1_LCDC0_HSYNC_LCDC1_HSYNC_NAME, GPIO2B_LCDC0_HSYNC); + rk30_mux_api_set(GPIO2B2_LCDC0_VSYNC_LCDC1_VSYNC_NAME, GPIO2B_LCDC0_VSYNC); + rk30_mux_api_set(GPIO2B3_LCDC0_DEN_LCDC1_DEN_NAME, GPIO2B_LCDC0_DEN); + rk30_mux_api_set(GPIO2B4_LCDC0_D10_LCDC1_D10_NAME, GPIO2B_LCDC0_D10); + rk30_mux_api_set(GPIO2B5_LCDC0_D11_LCDC1_D11_NAME, GPIO2B_LCDC0_D11); + rk30_mux_api_set(GPIO2B6_LCDC0_D12_LCDC1_D12_NAME, GPIO2B_LCDC0_D12); + rk30_mux_api_set(GPIO2B7_LCDC0_D13_LCDC1_D13_NAME, GPIO2B_LCDC0_D13); + rk30_mux_api_set(GPIO2C0_LCDC0_D14_LCDC1_D14_NAME, GPIO2C_LCDC0_D14); + rk30_mux_api_set(GPIO2C1_LCDC0_D15_LCDC1_D15_NAME, GPIO2C_LCDC0_D15); + rk30_mux_api_set(GPIO2C2_LCDC0_D16_LCDC1_D16_NAME, GPIO2C_LCDC0_D16); + rk30_mux_api_set(GPIO2C3_LCDC0_D17_LCDC1_D17_NAME, GPIO2C_LCDC0_D17); + //rk30_mux_api_set(GPIO2C4_LCDC0_D18_LCDC1_D18_I2C2_SDA_NAME, GPIO2C_LCDC1_D18); + //rk30_mux_api_set(GPIO2C5_LCDC0_D19_LCDC1_D19_I2C2_SCL_NAME, GPIO2C_LCDC1_D19); + //rk30_mux_api_set(GPIO2C6_LCDC0_D20_LCDC1_D20_UART2_SIN_NAME, GPIO2C_LCDC1_D20); + //rk30_mux_api_set(GPIO2C7_LCDC0_D21_LCDC1_D21_UART2_SOUT_NAME, GPIO2C_LCDC1_D21); + //rk30_mux_api_set(GPIO2D0_LCDC0_D22_LCDC1_D22_NAME, GPIO2D_LCDC1_D22); + //rk30_mux_api_set(GPIO2D1_LCDC0_D23_LCDC1_D23_NAME, GPIO2D_LCDC1_D23); + printk("RGB screen connect to rk2928\n"); + + } clk_enable(lcdc_dev->pd); clk_enable(lcdc_dev->hclk); //enable aclk and hclk for register config From dbe3cb9f74d2e47b0e716f3acd8052418a033c9b Mon Sep 17 00:00:00 2001 From: chenxing Date: Sun, 19 Aug 2012 15:57:41 +0800 Subject: [PATCH 230/261] rk2928:a720: fix vdd_log dvfs error --- arch/arm/mach-rk2928/dvfs.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-rk2928/dvfs.c b/arch/arm/mach-rk2928/dvfs.c index 5e1111939953..ff74f32a2fa4 100644 --- a/arch/arm/mach-rk2928/dvfs.c +++ b/arch/arm/mach-rk2928/dvfs.c @@ -1167,8 +1167,9 @@ int dvfs_target_core(struct clk *clk, unsigned long rate_hz) if (volt_dep_new < 0) goto fail_roll_back; - ret = dvfs_scale_volt_bystep(dvfs_clk->vd, dvfs_clk_cpu->vd, volt_new, volt_dep_new, - LOGIC_HIGHER_ARM, ARM_HIGHER_LOGIC); + ret = dvfs_scale_volt_direct(dvfs_clk->vd, volt_new); + //ret = dvfs_scale_volt_bystep(dvfs_clk->vd, dvfs_clk_cpu->vd, volt_new, volt_dep_new, + // LOGIC_HIGHER_ARM, ARM_HIGHER_LOGIC); if (ret < 0) goto fail_roll_back; } @@ -1197,8 +1198,9 @@ int dvfs_target_core(struct clk *clk, unsigned long rate_hz) if (volt_dep_new < 0) goto out; - ret = dvfs_scale_volt_bystep(dvfs_clk->vd, dvfs_clk_cpu->vd, volt_new, volt_dep_new, - LOGIC_HIGHER_ARM, ARM_HIGHER_LOGIC); + ret = dvfs_scale_volt_direct(dvfs_clk->vd, volt_new); + //ret = dvfs_scale_volt_bystep(dvfs_clk->vd, dvfs_clk_cpu->vd, volt_new, volt_dep_new, + // LOGIC_HIGHER_ARM, ARM_HIGHER_LOGIC); if (ret < 0) goto out; } From afafab12077b4bb93439607e4ef2efbd95f006cd Mon Sep 17 00:00:00 2001 From: lw Date: Sun, 19 Aug 2012 18:17:03 +0800 Subject: [PATCH 231/261] sensor:add gsensor mma7660 support --- drivers/input/sensors/accel/Kconfig | 6 + drivers/input/sensors/accel/Makefile | 3 +- drivers/input/sensors/accel/mma7660.c | 280 ++++++++++++++++++++++++++ drivers/input/sensors/sensor-dev.c | 1 + 4 files changed, 289 insertions(+), 1 deletion(-) create mode 100755 drivers/input/sensors/accel/mma7660.c mode change 100644 => 100755 drivers/input/sensors/sensor-dev.c diff --git a/drivers/input/sensors/accel/Kconfig b/drivers/input/sensors/accel/Kconfig index 701e6ec008e1..1ded64e9a524 100755 --- a/drivers/input/sensors/accel/Kconfig +++ b/drivers/input/sensors/accel/Kconfig @@ -27,6 +27,12 @@ config GS_LIS3DH To have support for your specific gsesnor you will have to select the proper drivers which depend on this option. +config GS_MMA7660 + bool "gsensor mma7660" + help + To have support for your specific gsesnor you will have to + select the proper drivers which depend on this option. + config GS_BMA023 bool "gsensor bma023" help diff --git a/drivers/input/sensors/accel/Makefile b/drivers/input/sensors/accel/Makefile index e8af86346516..1f9ac9adcf80 100755 --- a/drivers/input/sensors/accel/Makefile +++ b/drivers/input/sensors/accel/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_GS_KXTIK) += kxtik.o obj-$(CONFIG_GS_MMA8452) += mma8452.o -obj-$(CONFIG_GS_LIS3DH) += lis3dh.o \ No newline at end of file +obj-$(CONFIG_GS_LIS3DH) += lis3dh.o +obj-$(CONFIG_GS_MMA7660) += mma7660.o \ No newline at end of file diff --git a/drivers/input/sensors/accel/mma7660.c b/drivers/input/sensors/accel/mma7660.c new file mode 100755 index 000000000000..cc72897b7d9a --- /dev/null +++ b/drivers/input/sensors/accel/mma7660.c @@ -0,0 +1,280 @@ +/* drivers/input/sensors/access/mma7660.c + * + * Copyright (C) 2012-2015 ROCKCHIP. + * Author: luowei + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include + +#if 0 +#define SENSOR_DEBUG_TYPE SENSOR_TYPE_ACCEL +#define DBG(x...) if(sensor->pdata->type == SENSOR_DEBUG_TYPE) printk(x) +#else +#define DBG(x...) +#endif + +#define MMA7660_ENABLE 1 + +#define MMA7660_REG_X_OUT 0x0 +#define MMA7660_REG_Y_OUT 0x1 +#define MMA7660_REG_Z_OUT 0x2 +#define MMA7660_REG_TILT 0x3 +#define MMA7660_REG_SRST 0x4 +#define MMA7660_REG_SPCNT 0x5 +#define MMA7660_REG_INTSU 0x6 +#define MMA7660_REG_MODE 0x7 +#define MMA7660_REG_SR 0x8 +#define MMA7660_REG_PDET 0x9 +#define MMA7660_REG_PD 0xa + + +#define MMA7660_RANGE 2000000 + +/* LIS3DH */ +#define MMA7660_PRECISION 6 +#define MMA7660_BOUNDARY (0x1 << (MMA7660_PRECISION - 1)) +#define MMA7660_GRAVITY_STEP (MMA7660_RANGE / MMA7660_BOUNDARY) + + + +/****************operate according to sensor chip:start************/ + +static int sensor_active(struct i2c_client *client, int enable, int rate) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + int status = 0; + + sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg); + + //register setting according to chip datasheet + if(enable) + { + status = MMA7660_ENABLE; //mma7660 + sensor->ops->ctrl_data |= status; + } + else + { + status = ~MMA7660_ENABLE; //mma7660 + sensor->ops->ctrl_data &= status; + } + + DBG("%s:reg=0x%x,reg_ctrl=0x%x,enable=%d\n",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable); + result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); + if(result) + printk("%s:fail to active sensor\n",__func__); + + return result; + +} + +static int sensor_init(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + + result = sensor->ops->active(client,0,0); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + sensor->status_cur = SENSOR_OFF; + + printk("%s:MMA7660_REG_TILT=0x%x\n",__func__,sensor_read_reg(client, MMA7660_REG_TILT)); + + if(sensor->pdata->irq_enable) //open interrupt + { + result = sensor_write_reg(client, MMA7660_REG_INTSU, 1<<4);//enable int,GINT=1 + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + } + + sensor->ops->ctrl_data = 1<<6; //Interrupt output INT is push-pull + result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + return result; +} + + +static int sensor_convert_data(struct i2c_client *client, char high_byte, char low_byte) +{ + s64 result; + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + //int precision = sensor->ops->precision; + + result = (int)low_byte; + if (result < MMA7660_BOUNDARY) + result = result* MMA7660_GRAVITY_STEP; + else + result = ~( ((~result & (0x7fff>>(16-MMA7660_PRECISION)) ) + 1) + * MMA7660_GRAVITY_STEP) + 1; + + return (int)result; +} + +static int gsensor_report_value(struct i2c_client *client, struct sensor_axis *axis) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + + /* Report acceleration sensor information */ + input_report_abs(sensor->input_dev, ABS_X, axis->x); + input_report_abs(sensor->input_dev, ABS_Y, axis->y); + input_report_abs(sensor->input_dev, ABS_Z, axis->z); + input_sync(sensor->input_dev); + DBG("Gsensor x==%d y==%d z==%d\n",axis->x,axis->y,axis->z); + + return 0; +} + +#define GSENSOR_MIN 10 +static int sensor_report_value(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + struct sensor_platform_data *pdata = sensor->pdata; + int ret = 0; + int x,y,z; + struct sensor_axis axis; + char buffer[3] = {0}; + char value = 0; + + if(sensor->ops->read_len < 3) //sensor->ops->read_len = 3 + { + printk("%s:lenth is error,len=%d\n",__func__,sensor->ops->read_len); + return -1; + } + + memset(buffer, 0, 3); + + /* Data bytes from hardware xL, xH, yL, yH, zL, zH */ + do { + *buffer = sensor->ops->read_reg; + ret = sensor_rx_data(client, buffer, sensor->ops->read_len); + if (ret < 0) + return ret; + } while (0); + + + //this gsensor need 6 bytes buffer + x = sensor_convert_data(sensor->client, 0, buffer[0]); //buffer[1]:high bit + y = sensor_convert_data(sensor->client, 0, buffer[1]); + z = sensor_convert_data(sensor->client, 0, buffer[2]); + + axis.x = (pdata->orientation[0])*x + (pdata->orientation[1])*y + (pdata->orientation[2])*z; + axis.y = (pdata->orientation[3])*x + (pdata->orientation[4])*y + (pdata->orientation[5])*z; + axis.z = (pdata->orientation[6])*x + (pdata->orientation[7])*y + (pdata->orientation[8])*z; + + DBG( "%s: axis = %d %d %d \n", __func__, axis.x, axis.y, axis.z); + + //Report event only while value is changed to save some power + if((abs(sensor->axis.x - axis.x) > GSENSOR_MIN) || (abs(sensor->axis.y - axis.y) > GSENSOR_MIN) || (abs(sensor->axis.z - axis.z) > GSENSOR_MIN)) + { + gsensor_report_value(client, &axis); + + /* 互斥地缓存数据. */ + mutex_lock(&(sensor->data_mutex) ); + sensor->axis = axis; + mutex_unlock(&(sensor->data_mutex) ); + } + + if((sensor->pdata->irq_enable)&& (sensor->ops->int_status_reg >= 0)) //read sensor intterupt status register + { + + value = sensor_read_reg(client, sensor->ops->int_status_reg); + DBG("%s:sensor int status :0x%x\n",__func__,value); + } + + return ret; +} + + +struct sensor_operate gsensor_mma7660_ops = { + .name = "mma7660", + .type = SENSOR_TYPE_ACCEL, //sensor type and it should be correct + .id_i2c = ACCEL_ID_MMA7660, //i2c id number + .read_reg = MMA7660_REG_X_OUT, //read data + .read_len = 3, //data length + .id_reg = SENSOR_UNKNOW_DATA, //read device id from this register + .id_data = SENSOR_UNKNOW_DATA, //device id + .precision = MMA7660_PRECISION, //12 bit + .ctrl_reg = MMA7660_REG_MODE, //enable or disable + .int_status_reg = SENSOR_UNKNOW_DATA, //intterupt status register + .range = {-MMA7660_RANGE,MMA7660_RANGE}, //range + .trig = IRQF_TRIGGER_LOW|IRQF_ONESHOT, + .active = sensor_active, + .init = sensor_init, + .report = sensor_report_value, +}; + +/****************operate according to sensor chip:end************/ + +//function name should not be changed +static struct sensor_operate *gsensor_get_ops(void) +{ + return &gsensor_mma7660_ops; +} + + +static int __init gsensor_mma7660_init(void) +{ + struct sensor_operate *ops = gsensor_get_ops(); + int result = 0; + int type = ops->type; + result = sensor_register_slave(type, NULL, NULL, gsensor_get_ops); + printk("%s\n",__func__); + return result; +} + +static void __exit gsensor_mma7660_exit(void) +{ + struct sensor_operate *ops = gsensor_get_ops(); + int type = ops->type; + sensor_unregister_slave(type, NULL, NULL, gsensor_get_ops); +} + + +module_init(gsensor_mma7660_init); +module_exit(gsensor_mma7660_exit); + + + diff --git a/drivers/input/sensors/sensor-dev.c b/drivers/input/sensors/sensor-dev.c old mode 100644 new mode 100755 index 6008deb94f34..8d10cedc8739 --- a/drivers/input/sensors/sensor-dev.c +++ b/drivers/input/sensors/sensor-dev.c @@ -1281,6 +1281,7 @@ static const struct i2c_device_id sensor_id[] = { {"gs_mma8452", ACCEL_ID_MMA845X}, {"gs_kxtik", ACCEL_ID_KXTIK}, {"gs_lis3dh", ACCEL_ID_LIS3DH}, + {"gs_mma7660", ACCEL_ID_MMA7660}, /*compass*/ {"compass", COMPASS_ID_ALL}, {"ak8975", COMPASS_ID_AK8975}, From f81e3371f3ed83b9d3e16e1d90120b0aae36fc7b Mon Sep 17 00:00:00 2001 From: lw Date: Sun, 19 Aug 2012 18:27:06 +0800 Subject: [PATCH 232/261] rk2928 a720:add mma7660 support --- arch/arm/mach-rk2928/board-rk2928-a720.c | 31 ++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/arch/arm/mach-rk2928/board-rk2928-a720.c b/arch/arm/mach-rk2928/board-rk2928-a720.c index d5da5352fb97..b27c36438f95 100755 --- a/arch/arm/mach-rk2928/board-rk2928-a720.c +++ b/arch/arm/mach-rk2928/board-rk2928-a720.c @@ -259,6 +259,27 @@ static struct platform_device device_ion = { }; #endif +/*MMA7660 gsensor*/ +#if defined (CONFIG_GS_MMA7660) +#define MMA7660_INT_PIN RK2928_PIN1_PB1 + +static int mma7660_init_platform_hw(void) +{ + rk30_mux_api_set(GPIO4C0_SMCDATA0_TRACEDATA0_NAME, GPIO4C_GPIO4C0); + + return 0; +} + +static struct sensor_platform_data mma7660_info = { + .type = SENSOR_TYPE_ACCEL, + .irq_enable = 1, + .poll_delay_ms = 30, + .init_platform_hw = mma7660_init_platform_hw, + .orientation = {-1, 0, 0, 0, 0, 1, 0, -1, 0}, +}; +#endif + + #if CONFIG_RK30_PWM_REGULATOR const static int pwm_voltage_map[] = { 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 1400000 @@ -345,6 +366,16 @@ static struct i2c_board_info __initdata i2c0_info[] = { #endif #ifdef CONFIG_I2C1_RK30 static struct i2c_board_info __initdata i2c1_info[] = { +#if defined (CONFIG_GS_MMA7660) + { + .type = "gs_mma7660", + .addr = 0x4c, + .flags = 0, + .irq = MMA7660_INT_PIN, + .platform_data = &mma7660_info, + }, +#endif + }; #endif #ifdef CONFIG_I2C2_RK30 From 07a6776286234cbff27f7efce3272da2ece4fdbb Mon Sep 17 00:00:00 2001 From: kfx Date: Sun, 19 Aug 2012 19:11:31 +0800 Subject: [PATCH 233/261] rk2928: a720: cpufreq(1G) && pmic sleep io && backlight && gsensor --- arch/arm/configs/rk2928_a720_defconfig | 10 ++++++++++ arch/arm/mach-rk2928/board-rk2928-a720-tps65910.c | 2 +- arch/arm/mach-rk2928/board-rk2928-a720.c | 10 +++++----- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/arch/arm/configs/rk2928_a720_defconfig b/arch/arm/configs/rk2928_a720_defconfig index 9f3b4f64fcc1..bb5d2ec4d623 100644 --- a/arch/arm/configs/rk2928_a720_defconfig +++ b/arch/arm/configs/rk2928_a720_defconfig @@ -22,6 +22,7 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_ARCH_RK2928=y +CONFIG_RK_CLOCK_PROC=y CONFIG_RK_DEBUG_UART=0 CONFIG_MACH_RK2928_A720=y CONFIG_FIQ_DEBUGGER=y @@ -39,6 +40,13 @@ CONFIG_DEFAULT_MMAP_MIN_ADDR=32768 CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 CONFIG_CMDLINE="console=ttyFIQ0 androidboot.console=ttyFIQ0 init=/init" +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y CONFIG_CPU_IDLE=y CONFIG_VFP=y CONFIG_NEON=y @@ -216,7 +224,9 @@ CONFIG_INPUT_TOUCHSCREEN=y CONFIG_INPUT_MISC=y CONFIG_INPUT_KEYCHORD=y CONFIG_INPUT_UINPUT=y +CONFIG_GS_MMA7660=y CONFIG_SENSOR_DEVICE=y +CONFIG_GSENSOR_DEVICE=y # CONFIG_SERIO is not set # CONFIG_CONSOLE_TRANSLATIONS is not set # CONFIG_LEGACY_PTYS is not set diff --git a/arch/arm/mach-rk2928/board-rk2928-a720-tps65910.c b/arch/arm/mach-rk2928/board-rk2928-a720-tps65910.c index a34547d78a9f..7f6eec382855 100755 --- a/arch/arm/mach-rk2928/board-rk2928-a720-tps65910.c +++ b/arch/arm/mach-rk2928/board-rk2928-a720-tps65910.c @@ -26,7 +26,7 @@ #define GPIO6_PB1_UNEN_MASK 0x02000000 #ifdef CONFIG_MFD_TPS65910 -#define PMU_POWER_SLEEP RK2928_PIN3_PD2 +#define PMU_POWER_SLEEP RK2928_PIN1_PA1 extern int platform_device_register(struct platform_device *pdev); int tps65910_pre_init(struct tps65910 *tps65910){ diff --git a/arch/arm/mach-rk2928/board-rk2928-a720.c b/arch/arm/mach-rk2928/board-rk2928-a720.c index b27c36438f95..5808b81359cb 100755 --- a/arch/arm/mach-rk2928/board-rk2928-a720.c +++ b/arch/arm/mach-rk2928/board-rk2928-a720.c @@ -74,7 +74,7 @@ static struct spi_board_info board_spi_devices[] = { #define PWM_MUX_MODE GPIO0D_PWM_0 #define PWM_MUX_MODE_GPIO GPIO0D_GPIO0D2 #define PWM_GPIO RK2928_PIN0_PD2 -#define PWM_EFFECT_VALUE 1 +#define PWM_EFFECT_VALUE 0 #define LCD_DISP_ON_PIN @@ -479,11 +479,11 @@ static struct dvfs_arm_table dvfs_cpu_logic_table[] = { {.frequency = 408 * 1000, .cpu_volt = 1200 * 1000, .logic_volt = 1200 * 1000},//1.000V/1.025V {.frequency = 504 * 1000, .cpu_volt = 1200 * 1000, .logic_volt = 1200 * 1000},//1.000V/1.025V {.frequency = 600 * 1000, .cpu_volt = 1200 * 1000, .logic_volt = 1200 * 1000},//1.025V/1.050V - //{.frequency = 696 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.000V/1.025V - //{.frequency = 816 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V - //{.frequency = 912 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V -#if 0 + {.frequency = 696 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.000V/1.025V + {.frequency = 816 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V + {.frequency = 912 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V {.frequency = 1008 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V +#if 0 {.frequency = 1104 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V {.frequency = 1200 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V {.frequency = 1104 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V From 1d47ad320f5a6b84f6d69c24e82135fbc86df35f Mon Sep 17 00:00:00 2001 From: "lw@rock-chips.com" Date: Sun, 19 Aug 2012 19:39:42 +0800 Subject: [PATCH 234/261] sensor:add setting gsensor orientation online support --- arch/arm/plat-rk/include/plat/board.h | 1 + drivers/input/sensors/sensor-dev.c | 78 +++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/arch/arm/plat-rk/include/plat/board.h b/arch/arm/plat-rk/include/plat/board.h index 36013e75c6b2..9b3576be7d5d 100755 --- a/arch/arm/plat-rk/include/plat/board.h +++ b/arch/arm/plat-rk/include/plat/board.h @@ -127,6 +127,7 @@ struct sensor_platform_data { int x_min; //filter int y_min; int z_min; + int factory; unsigned char address; signed char orientation[9]; short m_layout[4][3][3]; diff --git a/drivers/input/sensors/sensor-dev.c b/drivers/input/sensors/sensor-dev.c index 8d10cedc8739..81d5f559ca05 100755 --- a/drivers/input/sensors/sensor-dev.c +++ b/drivers/input/sensors/sensor-dev.c @@ -45,6 +45,8 @@ struct sensor_private_data *g_sensor[SENSOR_NUM_TYPES]; static struct sensor_operate *sensor_ops[SENSOR_NUM_ID]; +static struct class *g_sensor_class[SENSOR_NUM_TYPES]; + static int sensor_get_id(struct i2c_client *client, int *value) { @@ -482,6 +484,72 @@ static long gsensor_dev_ioctl(struct file *file, return result; } +static ssize_t gsensor_set_orientation_online(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int i=0; + char orientation[20]; + + struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_ACCEL]; + struct sensor_platform_data *pdata = sensor->pdata; + + + char *p = strstr(buf,"gsensor_class"); + int start = strcspn(p,"{"); + int end = strcspn(p,"}"); + + strncpy(orientation,p+start,end-start+1); + char *tmp = orientation; + + + while(strncmp(tmp,"}",1)!=0) + { + if((strncmp(tmp,",",1)==0)||(strncmp(tmp,"{",1)==0)) + { + + tmp++; + continue; + } + else if(strncmp(tmp,"-",1)==0) + { + pdata->orientation[i++]=-1; + DBG("i=%d,data=%d\n",i,pdata->orientation[i]); + tmp++; + } + else + { + pdata->orientation[i++]=tmp[0]-48; + DBG("----i=%d,data=%d\n",i,pdata->orientation[i]); + } + tmp++; + + + } + + for(i=0;i<9;i++) + DBG("i=%d gsensor_info=%d\n",i,pdata->orientation[i]); + return 0; + +} + +static CLASS_ATTR(orientation, 0660, NULL,gsensor_set_orientation_online); + +static int gsensor_class_init(void) +{ + int ret ; + struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_ACCEL]; + g_sensor_class[SENSOR_TYPE_ACCEL] = class_create(THIS_MODULE, "gsensor_class"); + ret = class_create_file(g_sensor_class[SENSOR_TYPE_ACCEL], &class_attr_orientation); + if (ret) + { + printk("%s:Fail to creat class\n",__func__); + return ret; + } + printk("%s:%s\n",__func__,sensor->i2c_id->name); + return 0; +} + + static int compass_dev_open(struct inode *inode, struct file *file) { @@ -1222,6 +1290,16 @@ int sensor_probe(struct i2c_client *client, const struct i2c_device_id *devid) g_sensor[type] = sensor; + if((type == SENSOR_TYPE_ACCEL) && (sensor->pdata->factory)) //only support setting gsensor orientation online now + { + result = gsensor_class_init(); + if (result) { + dev_err(&client->dev, + "fail to register misc device %s\n", sensor->i2c_id->name); + goto out_misc_device_register_device_failed; + } + } + #ifdef CONFIG_HAS_EARLYSUSPEND if((sensor->ops->suspend) && (sensor->ops->resume)) { From 486c7667947a9c1d2a807572847b20a46fe9bd02 Mon Sep 17 00:00:00 2001 From: lw Date: Sun, 19 Aug 2012 19:48:54 +0800 Subject: [PATCH 235/261] sensor:mask some debug information --- drivers/input/sensors/accel/kxtik.c | 2 +- drivers/input/sensors/accel/lis3dh.c | 2 +- drivers/input/sensors/accel/mma7660.c | 2 +- drivers/input/sensors/accel/mma8452.c | 2 +- drivers/input/sensors/compass/ak8975.c | 2 +- drivers/input/sensors/gyro/l3g4200d.c | 2 +- drivers/input/sensors/lsensor/cm3217.c | 0 drivers/input/sensors/lsensor/ls_al3006.c | 2 +- drivers/input/sensors/lsensor/ls_stk3171.c | 2 +- drivers/input/sensors/psensor/ps_al3006.c | 2 +- drivers/input/sensors/psensor/ps_stk3171.c | 2 +- 11 files changed, 10 insertions(+), 10 deletions(-) mode change 100644 => 100755 drivers/input/sensors/lsensor/cm3217.c mode change 100644 => 100755 drivers/input/sensors/lsensor/ls_al3006.c mode change 100644 => 100755 drivers/input/sensors/lsensor/ls_stk3171.c diff --git a/drivers/input/sensors/accel/kxtik.c b/drivers/input/sensors/accel/kxtik.c index ac0eca4b950d..e4f2f2b5877a 100755 --- a/drivers/input/sensors/accel/kxtik.c +++ b/drivers/input/sensors/accel/kxtik.c @@ -247,7 +247,7 @@ static int __init gsensor_kxtik_init(void) int result = 0; int type = ops->type; result = sensor_register_slave(type, NULL, NULL, gsensor_get_ops); - printk("%s\n",__func__); + DBG("%s\n",__func__); return result; } diff --git a/drivers/input/sensors/accel/lis3dh.c b/drivers/input/sensors/accel/lis3dh.c index 1ca48a8cece9..aae6e6e2c198 100755 --- a/drivers/input/sensors/accel/lis3dh.c +++ b/drivers/input/sensors/accel/lis3dh.c @@ -325,7 +325,7 @@ static int __init gsensor_lis3dh_init(void) int result = 0; int type = ops->type; result = sensor_register_slave(type, NULL, NULL, gsensor_get_ops); - printk("%s\n",__func__); + DBG("%s\n",__func__); return result; } diff --git a/drivers/input/sensors/accel/mma7660.c b/drivers/input/sensors/accel/mma7660.c index cc72897b7d9a..6f789a464c84 100755 --- a/drivers/input/sensors/accel/mma7660.c +++ b/drivers/input/sensors/accel/mma7660.c @@ -261,7 +261,7 @@ static int __init gsensor_mma7660_init(void) int result = 0; int type = ops->type; result = sensor_register_slave(type, NULL, NULL, gsensor_get_ops); - printk("%s\n",__func__); + DBG("%s\n",__func__); return result; } diff --git a/drivers/input/sensors/accel/mma8452.c b/drivers/input/sensors/accel/mma8452.c index 0264e5f009d2..e25e0022690e 100755 --- a/drivers/input/sensors/accel/mma8452.c +++ b/drivers/input/sensors/accel/mma8452.c @@ -288,7 +288,7 @@ static int __init gsensor_mma8452_init(void) int result = 0; int type = ops->type; result = sensor_register_slave(type, NULL, NULL, gsensor_get_ops); - printk("%s\n",__func__); + DBG("%s\n",__func__); return result; } diff --git a/drivers/input/sensors/compass/ak8975.c b/drivers/input/sensors/compass/ak8975.c index 3319618705ae..3d2448f5893f 100755 --- a/drivers/input/sensors/compass/ak8975.c +++ b/drivers/input/sensors/compass/ak8975.c @@ -741,7 +741,7 @@ static int __init compass_akm8975_init(void) atomic_set(&open_flag, 0); init_waitqueue_head(&open_wq); - printk("%s\n",__func__); + DBG("%s\n",__func__); error: return result; } diff --git a/drivers/input/sensors/gyro/l3g4200d.c b/drivers/input/sensors/gyro/l3g4200d.c index 03a0d264fe14..6d08849fa17d 100755 --- a/drivers/input/sensors/gyro/l3g4200d.c +++ b/drivers/input/sensors/gyro/l3g4200d.c @@ -246,7 +246,7 @@ static int __init gyro_l3g4200d_init(void) int result = 0; int type = ops->type; result = sensor_register_slave(type, NULL, NULL, gyro_get_ops); - printk("%s\n",__func__); + DBG("%s\n",__func__); return result; } diff --git a/drivers/input/sensors/lsensor/cm3217.c b/drivers/input/sensors/lsensor/cm3217.c old mode 100644 new mode 100755 diff --git a/drivers/input/sensors/lsensor/ls_al3006.c b/drivers/input/sensors/lsensor/ls_al3006.c old mode 100644 new mode 100755 index 416df23002b4..fb9b4940381a --- a/drivers/input/sensors/lsensor/ls_al3006.c +++ b/drivers/input/sensors/lsensor/ls_al3006.c @@ -285,7 +285,7 @@ static int __init light_al3006_init(void) int result = 0; int type = ops->type; result = sensor_register_slave(type, NULL, NULL, light_get_ops); - printk("%s\n",__func__); + DBG("%s\n",__func__); return result; } diff --git a/drivers/input/sensors/lsensor/ls_stk3171.c b/drivers/input/sensors/lsensor/ls_stk3171.c old mode 100644 new mode 100755 index 7913b6fa0244..4bac702323d2 --- a/drivers/input/sensors/lsensor/ls_stk3171.c +++ b/drivers/input/sensors/lsensor/ls_stk3171.c @@ -304,7 +304,7 @@ static int __init light_stk3171_init(void) int result = 0; int type = ops->type; result = sensor_register_slave(type, NULL, NULL, light_get_ops); - printk("%s\n",__func__); + DBG("%s\n",__func__); return result; } diff --git a/drivers/input/sensors/psensor/ps_al3006.c b/drivers/input/sensors/psensor/ps_al3006.c index 83be85d6572c..631a3998c1b1 100755 --- a/drivers/input/sensors/psensor/ps_al3006.c +++ b/drivers/input/sensors/psensor/ps_al3006.c @@ -246,7 +246,7 @@ static int __init proximity_al3006_init(void) int result = 0; int type = ops->type; result = sensor_register_slave(type, NULL, NULL, proximity_get_ops); - printk("%s\n",__func__); + DBG("%s\n",__func__); return result; } diff --git a/drivers/input/sensors/psensor/ps_stk3171.c b/drivers/input/sensors/psensor/ps_stk3171.c index 431b8f7a90fa..5b4c8e3880bd 100755 --- a/drivers/input/sensors/psensor/ps_stk3171.c +++ b/drivers/input/sensors/psensor/ps_stk3171.c @@ -252,7 +252,7 @@ static int __init proximity_stk3171_init(void) int result = 0; int type = ops->type; result = sensor_register_slave(type, NULL, NULL, proximity_get_ops); - printk("%s\n",__func__); + DBG("%s\n",__func__); return result; } From 28e07bcda61c19f385e6de550a54c80f7f732bba Mon Sep 17 00:00:00 2001 From: Zheng Yang Date: Mon, 20 Aug 2012 09:18:06 +0800 Subject: [PATCH 236/261] rk30 hdmi: Modify Kconfig to support hdcp. --- .../video/rockchip/hdmi/chips/rk30/Kconfig | 1 + drivers/video/rockchip/hdmi/hdcp/Kconfig | 14 - drivers/video/rockchip/hdmi/hdcp/Makefile | 8 - drivers/video/rockchip/hdmi/hdcp/rk30_hdcp.c | 570 ------------------ .../video/rockchip/hdmi/hdcp/rk30_hdmi_hdcp.c | 157 ----- .../video/rockchip/hdmi/hdcp/rk30_hdmi_hdcp.h | 99 --- 6 files changed, 1 insertion(+), 848 deletions(-) delete mode 100755 drivers/video/rockchip/hdmi/hdcp/Kconfig delete mode 100755 drivers/video/rockchip/hdmi/hdcp/Makefile delete mode 100755 drivers/video/rockchip/hdmi/hdcp/rk30_hdcp.c delete mode 100755 drivers/video/rockchip/hdmi/hdcp/rk30_hdmi_hdcp.c delete mode 100755 drivers/video/rockchip/hdmi/hdcp/rk30_hdmi_hdcp.h diff --git a/drivers/video/rockchip/hdmi/chips/rk30/Kconfig b/drivers/video/rockchip/hdmi/chips/rk30/Kconfig index c33318d43622..31deae4f6526 100755 --- a/drivers/video/rockchip/hdmi/chips/rk30/Kconfig +++ b/drivers/video/rockchip/hdmi/chips/rk30/Kconfig @@ -13,3 +13,4 @@ config HDMI_RK30_DEBUG help Enableds verbose debugging the the HDMI drivers +source "drivers/video/rockchip/hdmi/chips/rk30/hdcp/Kconfig" \ No newline at end of file diff --git a/drivers/video/rockchip/hdmi/hdcp/Kconfig b/drivers/video/rockchip/hdmi/hdcp/Kconfig deleted file mode 100755 index 1bb3c3a24f56..000000000000 --- a/drivers/video/rockchip/hdmi/hdcp/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -config HDCP_RK30 - bool "RK30 HDCP support" - depends on LCDC_RK30 && HDMI_RK30 - default n - help - HDCP Interface. This adds the High Definition Content Protection Interface. - See http://www.digital-cp.com/ for HDCP specification. - -config HDCP_RK30_DEBUG - bool "RK30 HDCP Debugging" - depends on HDCP_RK30 - default n - help - Enableds verbose debugging the the HDCP drivers diff --git a/drivers/video/rockchip/hdmi/hdcp/Makefile b/drivers/video/rockchip/hdmi/hdcp/Makefile deleted file mode 100755 index 108b67ca134e..000000000000 --- a/drivers/video/rockchip/hdmi/hdcp/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Makefile for HDCP linux kernel module. -# - -ccflags-$(CONFIG_HDCP_RK30_DEBUG) = -DDEBUG -DHDCP_DEBUG - -obj-$(CONFIG_HDCP_RK30) += hdcp.o -hdcp-y := rk30_hdcp.o rk30_hdmi_hdcp.o diff --git a/drivers/video/rockchip/hdmi/hdcp/rk30_hdcp.c b/drivers/video/rockchip/hdmi/hdcp/rk30_hdcp.c deleted file mode 100755 index 68d0ac841a67..000000000000 --- a/drivers/video/rockchip/hdmi/hdcp/rk30_hdcp.c +++ /dev/null @@ -1,570 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include "../rk30_hdmi.h" -#include "../rk30_hdmi_hw.h" -#include "rk30_hdmi_hdcp.h" - -struct hdcp *hdcp = NULL; - -static void hdcp_work_queue(struct work_struct *work); - -/*----------------------------------------------------------------------------- - * Function: hdcp_submit_work - *----------------------------------------------------------------------------- - */ -static struct delayed_work *hdcp_submit_work(int event, int delay) -{ - struct hdcp_delayed_work *work; - - DBG("%s event %04x delay %d", __FUNCTION__, event, delay); - - work = kmalloc(sizeof(struct hdcp_delayed_work), GFP_ATOMIC); - - if (work) { - INIT_DELAYED_WORK(&work->work, hdcp_work_queue); - work->event = event; - queue_delayed_work(hdcp->workqueue, - &work->work, - msecs_to_jiffies(delay)); - } else { - printk(KERN_WARNING "HDCP: Cannot allocate memory to " - "create work\n"); - return 0; - } - - return &work->work; -} - -/*----------------------------------------------------------------------------- - * Function: hdcp_cancel_work - *----------------------------------------------------------------------------- - */ -static void hdcp_cancel_work(struct delayed_work **work) -{ - int ret = 0; - - if (*work) { - ret = cancel_delayed_work(*work); - if (ret != 1) { - ret = cancel_work_sync(&((*work)->work)); - printk(KERN_INFO "Canceling work failed - " - "cancel_work_sync done %d\n", ret); - } - kfree(*work); - *work = 0; - } -} - -/*----------------------------------------------------------------------------- - * Function: hdcp_wq_authentication_failure - *----------------------------------------------------------------------------- - */ -static void hdcp_wq_authentication_failure(void) -{ - if (hdcp->hdmi_state == HDMI_STOPPED) { - return; - } - - rk30_hdcp_disable(); - rk30_hdmi_control_output(false); - - hdcp_cancel_work(&hdcp->pending_wq_event); - - if (hdcp->retry_cnt && (hdcp->hdmi_state != HDMI_STOPPED)) { - if (hdcp->retry_cnt < HDCP_INFINITE_REAUTH) { - hdcp->retry_cnt--; - printk(KERN_INFO "HDCP: authentication failed - " - "retrying, attempts=%d\n", - hdcp->retry_cnt); - } else - printk(KERN_INFO "HDCP: authentication failed - " - "retrying\n"); - - hdcp->hdcp_state = HDCP_AUTHENTICATION_START; - - hdcp->pending_wq_event = hdcp_submit_work(HDCP_AUTH_REATT_EVENT, - HDCP_REAUTH_DELAY); - } else { - printk(KERN_INFO "HDCP: authentication failed - " - "HDCP disabled\n"); - hdcp->hdcp_state = HDCP_ENABLE_PENDING; - } - -} - -/*----------------------------------------------------------------------------- - * Function: hdcp_wq_start_authentication - *----------------------------------------------------------------------------- - */ -static void hdcp_wq_start_authentication(void) -{ - int status = HDCP_OK; - - hdcp->hdcp_state = HDCP_AUTHENTICATION_START; - - DBG("HDCP: authentication start"); - - status = rk30_hdcp_start_authentication(); - - if (status != HDCP_OK) { - DBG("HDCP: authentication failed"); - hdcp_wq_authentication_failure(); - } else { - hdcp->hdcp_state = HDCP_WAIT_KSV_LIST; - } -} - -/*----------------------------------------------------------------------------- - * Function: hdcp_wq_check_bksv - *----------------------------------------------------------------------------- - */ -static void hdcp_wq_check_bksv(void) -{ - int status = HDCP_OK; - - DBG("Check BKSV start"); - - status = rk30_hdcp_check_bksv(); - - if (status != HDCP_OK) { - printk(KERN_INFO "HDCP: Check BKSV failed"); - hdcp->retry_cnt = 0; - hdcp_wq_authentication_failure(); - } - else { - DBG("HDCP: Check BKSV successful"); - - hdcp->hdcp_state = HDCP_LINK_INTEGRITY_CHECK; - - /* Restore retry counter */ - if(hdcp->retry_times == 0) - hdcp->retry_cnt = HDCP_INFINITE_REAUTH; - else - hdcp->retry_cnt = hdcp->retry_times; - } -} - -/*----------------------------------------------------------------------------- - * Function: hdcp_wq_authentication_sucess - *----------------------------------------------------------------------------- - */ -static void hdcp_wq_authentication_sucess(void) -{ - printk(KERN_INFO "HDCP: authentication pass"); - rk30_hdmi_control_output(true); -} - -/*----------------------------------------------------------------------------- - * Function: hdcp_wq_disable - *----------------------------------------------------------------------------- - */ -static void hdcp_wq_disable(int event) -{ - printk(KERN_INFO "HDCP: disabled"); - - hdcp_cancel_work(&hdcp->pending_wq_event); - rk30_hdcp_disable(); - if(event == HDCP_DISABLE_CTL) { - hdcp->hdcp_state = HDCP_DISABLED; - if(hdcp->hdmi_state == HDMI_STARTED) - rk30_hdmi_control_output(true); - } - else if(event == HDCP_STOP_FRAME_EVENT) - hdcp->hdcp_state = HDCP_ENABLE_PENDING; -} - -/*----------------------------------------------------------------------------- - * Function: hdcp_work_queue - *----------------------------------------------------------------------------- - */ -static void hdcp_work_queue(struct work_struct *work) -{ - struct hdcp_delayed_work *hdcp_w = - container_of(work, struct hdcp_delayed_work, work.work); - int event = hdcp_w->event; - - mutex_lock(&hdcp->lock); - - DBG("hdcp_work_queue() - START - %u hdmi=%d hdcp=%d evt= %x %d", - jiffies_to_msecs(jiffies), - hdcp->hdmi_state, - hdcp->hdcp_state, - (event & 0xFF00) >> 8, - event & 0xFF); - - if(event == HDCP_STOP_FRAME_EVENT) { - hdcp->hdmi_state = HDMI_STOPPED; - } - - if (event == HDCP_DISABLE_CTL || event == HDCP_STOP_FRAME_EVENT) { - hdcp_wq_disable(event); - } - - if (event & HDCP_WORKQUEUE_SRC) - hdcp->pending_wq_event = 0; - - /* First handle HDMI state */ - if (event == HDCP_START_FRAME_EVENT) { - hdcp->pending_start = 0; - hdcp->hdmi_state = HDMI_STARTED; - } - - /**********************/ - /* HDCP state machine */ - /**********************/ - switch (hdcp->hdcp_state) { - case HDCP_DISABLED: - /* HDCP enable control or re-authentication event */ - if (event == HDCP_ENABLE_CTL) { - if(hdcp->retry_times == 0) - hdcp->retry_cnt = HDCP_INFINITE_REAUTH; - else - hdcp->retry_cnt = hdcp->retry_times; - if (hdcp->hdmi_state == HDMI_STARTED) - hdcp_wq_start_authentication(); - else - hdcp->hdcp_state = HDCP_ENABLE_PENDING; - } - break; - - case HDCP_ENABLE_PENDING: - /* HDMI start frame event */ - if (event == HDCP_START_FRAME_EVENT) - hdcp_wq_start_authentication(); - - break; - - case HDCP_AUTHENTICATION_START: - /* Re-authentication */ - if (event == HDCP_AUTH_REATT_EVENT) - hdcp_wq_start_authentication(); - - break; - - case HDCP_WAIT_KSV_LIST: - /* KSV failure */ - if (event == HDCP_FAIL_EVENT) { - printk(KERN_INFO "HDCP: KSV switch failure\n"); - - hdcp_wq_authentication_failure(); - } - /* KSV list ready event */ - else if (event == HDCP_KSV_LIST_RDY_EVENT) - hdcp_wq_check_bksv(); - break; - - case HDCP_LINK_INTEGRITY_CHECK: - /* Ri failure */ - if (event == HDCP_FAIL_EVENT) { - printk(KERN_INFO "HDCP: Ri check failure\n"); - hdcp_wq_authentication_failure(); - } - else if(event == HDCP_AUTH_PASS_EVENT) - hdcp_wq_authentication_sucess(); - break; - - default: - printk(KERN_WARNING "HDCP: error - unknow HDCP state\n"); - break; - } - - kfree(hdcp_w); - if(event == HDCP_STOP_FRAME_EVENT) - complete(&hdcp->complete); - - mutex_unlock(&hdcp->lock); -} - -/*----------------------------------------------------------------------------- - * Function: hdcp_start_frame_cb - *----------------------------------------------------------------------------- - */ -static void hdcp_start_frame_cb(void) -{ - DBG("hdcp_start_frame_cb()"); - - /* Cancel any pending work */ - if (hdcp->pending_start) - hdcp_cancel_work(&hdcp->pending_start); - if (hdcp->pending_wq_event) - hdcp_cancel_work(&hdcp->pending_wq_event); - - hdcp->pending_start = hdcp_submit_work(HDCP_START_FRAME_EVENT, - HDCP_ENABLE_DELAY); -} - -/*----------------------------------------------------------------------------- - * Function: hdcp_irq_cb - *----------------------------------------------------------------------------- - */ -static void hdcp_irq_cb(int interrupt) -{ - int value; - DBG("%s 0x%x", __FUNCTION__, interrupt); - if(interrupt & m_INT_HDCP_ERR) - { - value = HDMIRdReg(HDCP_ERROR); - HDMIWrReg(HDCP_ERROR, value); - printk(KERN_INFO "HDCP: Error 0x%02x\n", value); - - if( (hdcp->hdcp_state != HDCP_DISABLED) && - (hdcp->hdcp_state != HDCP_ENABLE_PENDING) ) - { - hdcp_submit_work(HDCP_FAIL_EVENT, 0); - } - } - else if(interrupt & (m_INT_BKSV_RPRDY | m_INT_BKSV_RCRDY)) - hdcp_submit_work(HDCP_KSV_LIST_RDY_EVENT, 0); - else if(interrupt & m_INT_AUTH_DONE) - hdcp_submit_work(HDCP_AUTH_PASS_EVENT, 0); -} - -/*----------------------------------------------------------------------------- - * Function: hdcp_power_on_cb - *----------------------------------------------------------------------------- - */ -static int hdcp_power_on_cb(void) -{ - DBG("%s", __FUNCTION__); - return rk30_hdcp_load_key2mem(hdcp->keys); -} - -/*----------------------------------------------------------------------------- - * Function: hdcp_power_off_cb - *----------------------------------------------------------------------------- - */ -static void hdcp_power_off_cb(void) -{ - DBG("%s", __FUNCTION__); - if(!hdcp->enable) - return; - - hdcp_cancel_work(&hdcp->pending_start); - hdcp_cancel_work(&hdcp->pending_wq_event); - init_completion(&hdcp->complete); - /* Post event to workqueue */ - if (hdcp_submit_work(HDCP_STOP_FRAME_EVENT, 0)) - wait_for_completion_interruptible_timeout(&hdcp->complete, - msecs_to_jiffies(2000)); -} - -// Load HDCP key to external HDCP memory -static void hdcp_load_keys_cb(const struct firmware *fw, void *context) -{ - if (!fw) { - pr_err("HDCP: failed to load keys\n"); - return; - } - - if(fw->size < HDCP_KEY_SIZE) { - pr_err("HDCP: firmware wrong size %d\n", fw->size); - return; - } - - hdcp->keys = kmalloc(HDCP_KEY_SIZE, GFP_KERNEL); - if(hdcp->keys == NULL) { - pr_err("HDCP: can't allocated space for keys\n"); - return; - } - - memcpy(hdcp->keys, fw->data, HDCP_KEY_SIZE); - - rk30_hdcp_load_key2mem(hdcp->keys); - printk(KERN_INFO "HDCP: loaded hdcp key success\n"); - - if(fw->size > HDCP_KEY_SIZE) { - DBG("%s invalid key size %d", __FUNCTION__, fw->size - HDCP_KEY_SIZE); - if((fw->size - HDCP_KEY_SIZE) % 5) { - pr_err("HDCP: failed to load invalid keys\n"); - return; - } - hdcp->invalidkeys = kmalloc(fw->size - HDCP_KEY_SIZE, GFP_KERNEL); - if(hdcp->invalidkeys == NULL) { - pr_err("HDCP: can't allocated space for invalid keys\n"); - return; - } - memcpy(hdcp->invalidkeys, fw->data + HDCP_KEY_SIZE, fw->size - HDCP_KEY_SIZE); - hdcp->invalidkey = (fw->size - HDCP_KEY_SIZE)/5; - printk(KERN_INFO "HDCP: loaded hdcp invalid key success\n"); - } -} - -static ssize_t hdcp_enable_read(struct device *device, - struct device_attribute *attr, char *buf) -{ - int enable = 0; - - if(hdcp) - enable = hdcp->enable; - - return snprintf(buf, PAGE_SIZE, "%d\n", enable); -} - -static ssize_t hdcp_enable_write(struct device *device, - struct device_attribute *attr, const char *buf, size_t count) -{ - int enable; - - if(hdcp == NULL) - return -EINVAL; - - sscanf(buf, "%d", &enable); - if(hdcp->enable != enable) - { - /* Post event to workqueue */ - if(enable) { - if (hdcp_submit_work(HDCP_ENABLE_CTL, 0) == 0) - return -EFAULT; - } - else { - hdcp_cancel_work(&hdcp->pending_start); - hdcp_cancel_work(&hdcp->pending_wq_event); - - /* Post event to workqueue */ - if (hdcp_submit_work(HDCP_DISABLE_CTL, 0) == 0) - return -EFAULT; - } - hdcp->enable = enable; - } - return count; -} - -static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR, hdcp_enable_read, hdcp_enable_write); - -static ssize_t hdcp_trytimes_read(struct device *device, - struct device_attribute *attr, char *buf) -{ - int trytimes = 0; - - if(hdcp) - trytimes = hdcp->retry_times; - - return snprintf(buf, PAGE_SIZE, "%d\n", trytimes); -} - -static ssize_t hdcp_trytimes_wrtie(struct device *device, - struct device_attribute *attr, const char *buf, size_t count) -{ - int trytimes; - - if(hdcp == NULL) - return -EINVAL; - - sscanf(buf, "%d", &trytimes); - if(hdcp->retry_times != trytimes) - hdcp->retry_times = trytimes; - - return count; -} - - -static DEVICE_ATTR(trytimes, S_IRUGO|S_IWUSR, hdcp_trytimes_read, hdcp_trytimes_wrtie); - - -static struct miscdevice mdev; - -static int __init rk30_hdcp_init(void) -{ - int ret; - - DBG("[%s] %u", __FUNCTION__, jiffies_to_msecs(jiffies)); - - hdcp = kmalloc(sizeof(struct hdcp), GFP_KERNEL); - if(!hdcp) - { - printk(KERN_ERR ">>HDCP: kmalloc fail!"); - ret = -ENOMEM; - goto error0; - } - memset(hdcp, 0, sizeof(struct hdcp)); - mutex_init(&hdcp->lock); - - mdev.minor = MISC_DYNAMIC_MINOR; - mdev.name = "hdcp"; - mdev.mode = 0666; - if (misc_register(&mdev)) { - printk(KERN_ERR "HDCP: Could not add character driver\n"); - ret = HDMI_ERROR_FALSE; - goto error1; - } - ret = device_create_file(mdev.this_device, &dev_attr_enable); - if(ret) - { - printk(KERN_ERR "HDCP: Could not add sys file enable\n"); - ret = -EINVAL; - goto error2; - } - - ret = device_create_file(mdev.this_device, &dev_attr_trytimes); - if(ret) - { - printk(KERN_ERR "HDCP: Could not add sys file trytimes\n"); - ret = -EINVAL; - goto error3; - } - - hdcp->workqueue = create_singlethread_workqueue("hdcp"); - if (hdcp->workqueue == NULL) { - printk(KERN_ERR "HDCP,: create workqueue failed.\n"); - goto error4; - } - - - ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG, - "hdcp.keys", mdev.this_device, GFP_KERNEL, - hdcp, hdcp_load_keys_cb); - if (ret < 0) { - printk(KERN_ERR "HDCP: request_firmware_nowait failed: %d\n", ret); - goto error5; - } - - rk30_hdmi_register_hdcp_callbacks( hdcp_start_frame_cb, - hdcp_irq_cb, - hdcp_power_on_cb, - hdcp_power_off_cb); - - DBG("%s success %u", __FUNCTION__, jiffies_to_msecs(jiffies)); - return 0; - -error5: - destroy_workqueue(hdcp->workqueue); -error4: - device_remove_file(mdev.this_device, &dev_attr_trytimes); -error3: - device_remove_file(mdev.this_device, &dev_attr_enable); -error2: - misc_deregister(&mdev); -error1: - if(hdcp->keys) - kfree(hdcp->keys); - if(hdcp->invalidkeys) - kfree(hdcp->invalidkeys); - kfree(hdcp); -error0: - return ret; -} - -static void __exit rk30_hdcp_exit(void) -{ - if(hdcp) { - mutex_lock(&hdcp->lock); - rk30_hdmi_register_hdcp_callbacks(0, 0, 0, 0); - device_remove_file(mdev.this_device, &dev_attr_enable); - misc_deregister(&mdev); - destroy_workqueue(hdcp->workqueue); - if(hdcp->keys) - kfree(hdcp->keys); - if(hdcp->invalidkeys) - kfree(hdcp->invalidkeys); - mutex_unlock(&hdcp->lock); - kfree(hdcp); - } -} - -module_init(rk30_hdcp_init); -module_exit(rk30_hdcp_exit); \ No newline at end of file diff --git a/drivers/video/rockchip/hdmi/hdcp/rk30_hdmi_hdcp.c b/drivers/video/rockchip/hdmi/hdcp/rk30_hdmi_hdcp.c deleted file mode 100755 index 1184989a57b2..000000000000 --- a/drivers/video/rockchip/hdmi/hdcp/rk30_hdmi_hdcp.c +++ /dev/null @@ -1,157 +0,0 @@ -#include -#include -#include -#include "../rk30_hdmi.h" -#include "../rk30_hdmi_hw.h" -#include "rk30_hdmi_hdcp.h" - -static void rk30_hdcp_write_mem(int addr_8, char value) -{ - int temp; - int addr_32 = addr_8 - addr_8%4; - int shift = (addr_8%4) * 8; - - temp = HDMIRdReg(addr_32); - temp &= ~(0xff << shift); - temp |= value << shift; -// printk("temp is %08x\n", temp); - HDMIWrReg(addr_32, temp); -} - -int rk30_hdcp_load_key2mem(struct hdcp_keys *key) -{ - int i; - - if(key == NULL) return HDMI_ERROR_FALSE; - - HDMIWrReg(0x800, HDMI_INTERANL_CLK_DIV); - - for(i = 0; i < 7; i++) - rk30_hdcp_write_mem(HDCP_RAM_KEY_KSV1 + i, key->KSV[i]); - for(i = 0; i < 7; i++) - rk30_hdcp_write_mem(HDCP_RAM_KEY_KSV2 + i, key->KSV[i]); - for(i = 0; i < HDCP_PRIVATE_KEY_SIZE; i++) - rk30_hdcp_write_mem(HDCP_RAM_KEY_PRIVATE + i, key->DeviceKey[i]); - for(i = 0; i < HDCP_KEY_SHA_SIZE; i++) - rk30_hdcp_write_mem(HDCP_RAM_KEY_PRIVATE + HDCP_PRIVATE_KEY_SIZE + i, key->sha1[i]); - - HDMIWrReg(0x800, HDMI_INTERANL_CLK_DIV | 0x20); - return HDCP_OK; -} - -void rk30_hdcp_disable(void) -{ - int temp; - // Diable HDCP Interrupt - HDMIWrReg(INTR_MASK2, 0x00); - // Stop and Reset HDCP - HDMIMskReg(temp, HDCP_CTRL, m_HDCP_FRAMED_ENCRYPED | m_HDCP_AUTH_STOP | m_HDCP_RESET, - v_HDCP_FRAMED_ENCRYPED(0) | v_HDCP_AUTH_STOP(1) | v_HDCP_RESET(1) ); -} - -static int rk30_hdcp_load_key(void) -{ - int value, temp = 0; - - if(hdcp->keys == NULL) { - pr_err("[%s] HDCP key not loaded.\n", __FUNCTION__); - return HDCP_KEY_ERR; - } - - value = HDMIRdReg(HDCP_KEY_MEM_CTRL); - //Check HDCP key loaded from external HDCP memory - while((value & (m_KSV_VALID | m_KEY_VALID | m_KEY_READY)) != (m_KSV_VALID | m_KEY_VALID | m_KEY_READY)) { - if(temp > 10) { - pr_err("[%s] loaded hdcp key is incorrectable %02x\n", __FUNCTION__, value & 0xFF); - return HDCP_KEY_ERR; - } - //Load HDCP Key from external HDCP memory - HDMIWrReg(HDCP_KEY_ACCESS_CTRL2, m_LOAD_HDCP_KEY); - msleep(1); - value = HDMIRdReg(HDCP_KEY_MEM_CTRL); - temp++; - } - - return HDCP_OK; -} - - -int rk30_hdcp_start_authentication(void) -{ - int rc, temp; - - rc = rk30_hdcp_load_key(); - if(rc != HDCP_OK) - return rc; - - // Set 100ms & 5 sec timer - switch(hdmi->vic) - { - case HDMI_720x576p_50Hz_4_3: - case HDMI_720x576p_50Hz_16_9: - case HDMI_1280x720p_50Hz: - case HDMI_1920x1080i_50Hz: - case HDMI_720x576i_50Hz_4_3: - case HDMI_720x576i_50Hz_16_9: - case HDMI_1920x1080p_50Hz: - HDMIWrReg(HDCP_TIMER_100MS, 5); - HDMIWrReg(HDCP_TIMER_5S, 250); - break; - - default: - HDMIWrReg(HDCP_TIMER_100MS, 0x26); - HDMIWrReg(HDCP_TIMER_5S, 0x2c); - break; - } - // Config DDC Clock - temp = (hdmi->tmdsclk/HDCP_DDC_CLK)/4; - HDMIWrReg(DDC_BUS_FREQ_L, temp & 0xFF); - HDMIWrReg(DDC_BUS_FREQ_H, (temp >> 8) & 0xFF); - // Enable HDCP Interrupt - HDMIWrReg(INTR_MASK2, m_INT_HDCP_ERR | m_INT_BKSV_RPRDY | m_INT_BKSV_RCRDY | m_INT_AUTH_DONE | m_INT_AUTH_READY); - // Start HDCP - HDMIMskReg(temp, HDCP_CTRL, m_HDCP_AUTH_START | m_HDCP_FRAMED_ENCRYPED, v_HDCP_AUTH_START(1) | v_HDCP_FRAMED_ENCRYPED(0)); - - return HDCP_OK; -} - -int rk30_hdcp_check_bksv(void) -{ - int i, temp; - char bksv[5]; - char *invalidkey; - - temp = HDMIRdReg(HDCP_BCAPS); - DBG("Receiver capacity is 0x%02x", temp); - -#ifdef DEBUG - if(temp & m_HDMI_RECEIVED) - DBG("Receiver support HDMI"); - if(temp & m_REPEATER) - DBG("Receiver is a repeater"); - if(temp & m_DDC_FAST) - DBG("Receiver support 400K DDC"); - if(temp & m_1_1_FEATURE) - DBG("Receiver support 1.1 features, such as advanced cipher, EESS."); - if(temp & m_FAST_REAUTHENTICATION) - DBG("Receiver support fast reauthentication."); -#endif - - for(i = 0; i < 5; i++) { - bksv[i] = HDMIRdReg(HDCP_KSV_BYTE0 + (4 - i)*4) & 0xFF; - } - - DBG("bksv is 0x%02x%02x%02x%02x%02x", bksv[0], bksv[1], bksv[2], bksv[3], bksv[4]); - - for(i = 0; i < hdcp->invalidkey; i++) - { - invalidkey = hdcp->invalidkeys + i *5; - if(memcmp(bksv, invalidkey, 5) == 0) { - printk(KERN_ERR "HDCP: BKSV was revocated!!!\n"); - HDMIMskReg(temp, HDCP_CTRL, m_HDCP_BKSV_FAILED | m_HDCP_FRAMED_ENCRYPED, v_HDCP_BKSV_FAILED(1) | v_HDCP_FRAMED_ENCRYPED(0)); - return HDCP_KSV_ERR; - } - } - HDMIMskReg(temp, HDCP_CTRL, m_HDCP_BKSV_PASS | m_HDCP_FRAMED_ENCRYPED, v_HDCP_BKSV_PASS(1) | v_HDCP_FRAMED_ENCRYPED(1)); - return HDCP_OK; -} diff --git a/drivers/video/rockchip/hdmi/hdcp/rk30_hdmi_hdcp.h b/drivers/video/rockchip/hdmi/hdcp/rk30_hdmi_hdcp.h deleted file mode 100755 index 0224d88ab134..000000000000 --- a/drivers/video/rockchip/hdmi/hdcp/rk30_hdmi_hdcp.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef __RK30_HDMI_HDCP_H__ -#define __RK30_HDMI_HDCP_H__ - -/***************************/ -/* Definitions */ -/***************************/ - -/* Status / error codes */ -#define HDCP_OK 0 -#define HDCP_KEY_ERR 1 -#define HDCP_KSV_ERR 2 - -/* Delays */ -#define HDCP_ENABLE_DELAY 300 -#define HDCP_REAUTH_DELAY 100 - -/* Event source */ -#define HDCP_SRC_SHIFT 8 -#define HDCP_IOCTL_SRC (0x1 << HDCP_SRC_SHIFT) -#define HDCP_HDMI_SRC (0x2 << HDCP_SRC_SHIFT) -#define HDCP_IRQ_SRC (0x4 << HDCP_SRC_SHIFT) -#define HDCP_WORKQUEUE_SRC (0x8 << HDCP_SRC_SHIFT) - -/* Event */ -#define HDCP_ENABLE_CTL (HDCP_IOCTL_SRC | 0) -#define HDCP_DISABLE_CTL (HDCP_IOCTL_SRC | 1) -#define HDCP_START_FRAME_EVENT (HDCP_HDMI_SRC | 2) -#define HDCP_STOP_FRAME_EVENT (HDCP_HDMI_SRC | 3) -#define HDCP_KSV_LIST_RDY_EVENT (HDCP_IRQ_SRC | 4) -#define HDCP_FAIL_EVENT (HDCP_IRQ_SRC | 5) -#define HDCP_AUTH_PASS_EVENT (HDCP_IRQ_SRC | 6) -#define HDCP_AUTH_REATT_EVENT (HDCP_WORKQUEUE_SRC | 7) - -/* Key size */ -#define HDCP_KEY_SIZE 308 - -/* Authentication retry times */ -#define HDCP_INFINITE_REAUTH 0x100 - -enum hdcp_states { - HDCP_DISABLED, - HDCP_ENABLE_PENDING, - HDCP_AUTHENTICATION_START, - HDCP_WAIT_KSV_LIST, - HDCP_LINK_INTEGRITY_CHECK, -}; - -enum hdmi_states { - HDMI_STOPPED, - HDMI_STARTED -}; - -#define HDCP_PRIVATE_KEY_SIZE 280 -#define HDCP_KEY_SHA_SIZE 20 -#define HDCP_DDC_CLK 100000 - -struct hdcp_keys{ - u8 KSV[8]; - u8 DeviceKey[HDCP_PRIVATE_KEY_SIZE]; - u8 sha1[HDCP_KEY_SHA_SIZE]; -}; - -struct hdcp_delayed_work { - struct delayed_work work; - int event; -}; - -struct hdcp { - int enable; - int retry_times; - struct hdcp_keys *keys; - int invalidkey; - char *invalidkeys; - struct mutex lock; - struct completion complete; - struct workqueue_struct *workqueue; - - enum hdmi_states hdmi_state; - enum hdcp_states hdcp_state; - - struct delayed_work *pending_start; - struct delayed_work *pending_wq_event; - int retry_cnt; -}; - -extern struct hdcp *hdcp; - -#ifdef HDCP_DEBUG -#define DBG(format, ...) \ - printk(KERN_INFO "HDCP: " format "\n", ## __VA_ARGS__) -#else -#define DBG(format, ...) -#endif - -extern void rk30_hdcp_disable(void); -extern int rk30_hdcp_start_authentication(void); -extern int rk30_hdcp_check_bksv(void); -extern int rk30_hdcp_load_key2mem(struct hdcp_keys *key); -#endif /* __RK30_HDMI_HDCP_H__ */ \ No newline at end of file From ecf80461d23d8fe9910379b334c6657a9257ff8e Mon Sep 17 00:00:00 2001 From: yzq Date: Mon, 20 Aug 2012 10:29:14 +0800 Subject: [PATCH 237/261] rk2928 hdmi: remove unnecessary files and update low power mode --- .../hdmi/chips/rk2928/rk2928_hdmi_hw.c | 12 +- .../hdmi/chips/rk2928/rk2928_hdmi_hw.hbak | 497 ------------------ drivers/video/rockchip/hdmi/rk_hdmi_core.c | 254 --------- 3 files changed, 6 insertions(+), 757 deletions(-) delete mode 100755 drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.hbak delete mode 100755 drivers/video/rockchip/hdmi/rk_hdmi_core.c diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.c b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.c index fb1c0686cbef..b5dd18054bff 100755 --- a/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.c +++ b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.c @@ -55,12 +55,12 @@ static void rk2928_hdmi_set_pwr_mode(int mode) case LOWER_PWR: rk2928_hdmi_av_mute(0); rk2928_hdmi_sys_power_down(); - HDMIWrReg(0xe0, 0x0a); - HDMIWrReg(0xe1, 0x03); - HDMIWrReg(0xe2, 0x99); - HDMIWrReg(0xe3, 0x0f); - HDMIWrReg(0xe4, 0x00); - HDMIWrReg(0xec, 0x02); + HDMIWrReg(0xe0, 0x3a); + HDMIWrReg(0xe1, 0x00); + HDMIWrReg(0xe2, 0x00); + HDMIWrReg(0xe3, 0x00); + HDMIWrReg(0xe4, 0x03); + HDMIWrReg(0xec, 0x03); break; default: hdmi_dbg(hdmi->dev,"unkown rk2928 hdmi pwr mode %d\n",mode); diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.hbak b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.hbak deleted file mode 100755 index fe06fe040278..000000000000 --- a/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.hbak +++ /dev/null @@ -1,497 +0,0 @@ -#ifndef __RK2928_HDMI_HW_H__ -#define __RK2928_HDMI_HW_H__ - - -//0x00 -#define INT_POL 1 -#define SYS_PWR_ON 0 -#define SYS_PWR_OFF 1 -#define PHY_CLK 0 -#define SYS_CLK 1 - -#define MCLK_FS 0x01 //256fs -//0x01 -// INPUT_VIDEO_FORMAT -#define RGB_YUV444 0x00 -#define DDR_RGB444_YUV444 0x05 -#define DDR_YUV422 0x06 - -//0x02 -//video output format -#define RGB444 0x00 -#define YUV444 0x01 -#define YUV422 0x02 - -//DATA WIDTH -#define DATA_12BIT 0X00 -#define DATA_10BIT 0X01 -#define DATA_8BIT 0X03 - -//0X04 -//1:after 0:not After 1st sof for external DE sample -#define DE_AFTER_SOF 0 -#define DE_NOAFTER_SOF 1 - -#define CSC_ENABLE 0 -#define CSC_DISABLE 1 - -//0X05 -#define CLEAR_AVMUTE(x) (x)<<7 -#define SET_AVMUTE(x) (x)<<6 -#define AUDIO_MUTE(x) (x)<<1 -#define VIDEO_BLACK(x) (x)<<0 //1:black 0:normal - -//0x08 -#define VSYNC_POL(x) (x)<<3 //0:Negative 1:Positive -#define HSYNC_POL(x) (x)<<2 //0:Negative 1:Positive -#define INTER_PROGRESSIVE(x) (x)<<1 //0: progressive 1:interlace -#define VIDEO_SET_ENABLE(x) (x)<<0 //0:disable 1: enable - -/* 0xe1 */ -//Main-driver strength :0000~1111: the strength from low to high -#define M_DRIVER_STR(x) (((x)&0xf)<<4) -//Pre-driver strength :00~11: the strength from low to high -#define P_DRIVER_STR(x) (((x)&3)<<2) -//TX driver enable 1: enable 0: disable -#define TX_DRIVER_EN(x) (((x)&1)<<1) -/* 0xe2 */ -//Pre-emphasis strength 00~11: the strength from 0 to high -#define P_EMPHASIS_STR(x) (((x)&3)<<4) -//Power down TMDS driver 1: power down. 0: not -#define PWR_DOWN_TMDS(x) (((x)&1)<<0) -/* 0xe3 */ -//PLL out enable. Just for test. need set to 1鈥檅0 -#define PLL_OUT_EN(x) (((x)&1)<<7) -/* 0xe4 */ -// Band-Gap power down 11: power down 00: not -#define BAND_PWR(x) (((x)&3)<<0) -/* 0xe5 */ -//PLL disable 1: disable 0: enable -#define PLL_PWR(x) (((x)&1)<<4) -// PLL reset 1: reset 0: not -#define PLL_RST(x) (((x)&1)<<3) -//PHY TMDS channels reset 1: reset 0: not -#define TMDS_RST(x) (((x)&1)<<2) -/* 0xe7 */ -// PLL LDO power down 1: power down 0: not -#define PLL_LDO_PWR(x) (((x)&1)<<2) - -enum PWR_MODE{ - NORMAL, - LOWER_PWR, -}; - -#if 0 -/* HDMI_SYS_CONTROL */ -#define SYS_CTRL 0x0 - -enum { - PWR_SAVE_MODE_A = 1, - PWR_SAVE_MODE_B = 2, - PWR_SAVE_MODE_D = 4, - PWR_SAVE_MODE_E = 8 -}; -#define m_PWR_SAVE_MODE 0xF0 -#define v_PWR_SAVE_MODE(n) (n << 4) -#define PLL_B_RESET (1 << 3) - -#define N_32K 0x1000 -#define N_441K 0x1880 -#define N_882K 0x3100 -#define N_1764K 0x6200 -#define N_48K 0x1800 -#define N_96K 0x3000 -#define N_192K 0x6000 - -#define LR_SWAP_N3 0x04 -#define N_2 0x08 -#define N_1 0x0c - -#define AUDIO_CTRL1 0x28 -#define AUDIO_CTRL2 0x2c -#define I2S_AUDIO_CTRL 0x30 -enum { - I2S_MODE_STANDARD = 0, - I2S_MODE_RIGHT_JUSTIFIED, - I2S_MODE_LEFT_JUSTIFIED -}; -#define v_I2S_MODE(n) n -enum { - I2S_CHANNEL_1_2 = 1, - I2S_CHANNEL_3_4 = 3, - I2S_CHANNEL_5_6 = 7, - I2S_CHANNEL_7_8 = 0xf -}; -#define v_I2S_CHANNEL(n) ( (n) << 2 ) - -#define I2S_INPUT_SWAP 0x40 - -#define SRC_NUM_AUDIO_LEN 0x50 - -/* HDMI_AV_CTRL1*/ -#define AV_CTRL1 0x54 -enum { - AUDIO_32K = 0x3, - AUDIO_441K = 0x0, - AUDIO_48K = 0x2, - AUDIO_882K = 0x8, - AUDIO_96K = 0xa, - AUDIO_1764K = 0xc, - AUDIO_192K = 0xe, -}; -#define m_AUDIO_SAMPLE_RATE 0xF0 -#define v_AUDIO_SAMPLE_RATE(n) (n << 4) -#define m_INPUT_VIDEO_MODE (7 << 1) -#define v_INPUT_VIDEO_MODE(n) (n << 1) -enum { - INTERNAL_DE = 0, - EXTERNAL_DE -}; -#define m_DE_SIGNAL_SELECT (1 << 0) - -/* HDMI_AV_CTRL2 */ -#define AV_CTRL2 0xec -#define m_CSC_ENABLE (1 << 0) -#define v_CSC_ENABLE(n) (n) - -/* HDMI_VIDEO_CTRL1 */ -#define VIDEO_CTRL1 0x58 - -#define m_VIDEO_OUTPUT_MODE (0x3 << 6) -#define v_VIDEO_OUTPUT_MODE(n) (n << 6) -enum { - VIDEO_INPUT_DEPTH_12BIT = 0, - VIDEO_INPUT_DEPTH_10BIT = 0x1, - VIDEO_INPUT_DEPTH_8BIT = 0x3 -}; -#define m_VIDEO_INPUT_DEPTH (3 << 4) -#define v_VIDEO_INPUT_DEPTH(n) (n << 4) -enum { - VIDEO_EMBEDDED_SYNC_LOCATION_0 = 0, - VIDEO_EMBEDDED_SYNC_LOCATION_1, - VIDEO_EMBEDDED_SYNC_LOCATION_2 -}; -#define m_VIDEO_EMBEDDED_SYNC_LOCATION (3 << 2) -#define VIDEO_EMBEDDED_SYNC_LOCATION(n) (n << 2) -#define m_VIDEO_INPUT_COLOR_MODE (1 << 0) - -/* DEEP_COLOR_MODE */ -#define DEEP_COLOR_MODE 0x5c -enum{ - TMDS_CLOCK_MODE_8BIT = 0, - TMDS_CLOKK_MODE_10BIT, - TMDS_CLOKK_MODE_12BIT -}; -#define TMDS_CLOCK_MODE_MASK 0x3 << 6 -#define TMDS_CLOCK_MODE(n) (n) << 6 - -/* VIDEO_CTRL2 */ -#define VIDEO_SETTING2 0x114 -#define m_UNMUTE (1 << 7) -#define m_MUTE (1 << 6) -#define m_AUDIO_RESET (1 << 2) -#define m_NOT_SEND_AUDIO (1 << 1) -#define m_NOT_SEND_VIDEO (1 << 0) -#define AV_UNMUTE (1 << 7) // Unmute video and audio, send normal video and audio data -#define AV_MUTE (1 << 6) // Mute video and audio, send black video data and silent audio data -#define AUDIO_CAPTURE_RESET (1 << 2) // Reset audio process logic, only available in pwr_e mode. -#define NOT_SEND_AUDIO (1 << 1) // Send silent audio data -#define NOT_SEND_VIDEO (1 << 0) // Send black video data - -/* Color Space Convertion Parameter*/ -#define CSC_PARA_C0_H 0x60 -#define CSC_PARA_C0_L 0x64 -#define CSC_PARA_C1_H 0x68 -#define CSC_PARA_C1_L 0x6c -#define CSC_PARA_C2_H 0x70 -#define CSC_PARA_C2_L 0x74 -#define CSC_PARA_C3_H 0x78 -#define CSC_PARA_C3_L 0x7c -#define CSC_PARA_C4_H 0x80 -#define CSC_PARA_C4_L 0x84 -#define CSC_PARA_C5_H 0x88 -#define CSC_PARA_C5_L 0x8c -#define CSC_PARA_C6_H 0x90 -#define CSC_PARA_C6_L 0x94 -#define CSC_PARA_C7_H 0x98 -#define CSC_PARA_C7_L 0x9c -#define CSC_PARA_C8_H 0xa0 -#define CSC_PARA_C8_L 0xa4 -#define CSC_PARA_C9_H 0xa8 -#define CSC_PARA_C9_L 0xac -#define CSC_PARA_C10_H 0xac -#define CSC_PARA_C10_L 0xb4 -#define CSC_PARA_C11_H 0xb8 -#define CSC_PARA_C11_L 0xbc - -#define CSC_CONFIG1 0x34c -#define m_CSC_MODE (1 << 7) -#define m_CSC_COEF_MODE (0xF << 3) //Only used in auto csc mode -#define m_CSC_STATUS (1 << 2) -#define m_CSC_VID_SELECT (1 << 1) -#define m_CSC_BRSWAP_DIABLE (1) - -enum { - CSC_MODE_MANUAL = 0, - CSC_MODE_AUTO -}; -#define v_CSC_MODE(n) (n << 7) -enum { - COE_SDTV_LIMITED_RANGE = 0x08, - COE_SDTV_FULL_RANGE = 0x04, - COE_HDTV_60Hz = 0x2, - COE_HDTV_50Hz = 0x1 -}; -#define v_CSC_COE_MODE(n) (n << 3) -enum { - CSC_INPUT_VID_5_19 = 0, - CSC_INPUT_VID_28_29 -}; -#define v_CSC_VID_SELECT(n) (n << 1) -#define v_CSC_BRSWAP_DIABLE(n) (n) -#endif -/* CONTROL_PACKET_BUF_INDEX */ -#define CONTROL_PACKET_BUF_INDEX 0x17c -enum { - INFOFRAME_AVI = 0x06, - INFOFRAME_AAI = 0x08 -}; -#define CONTROL_PACKET_HB0 0x180 -#define CONTROL_PACKET_HB1 0x184 -#define CONTROL_PACKET_HB2 0x188 -#define CONTROL_PACKET_PB_ADDR 0x18c -#define SIZE_AVI_INFOFRAME 0x11 // 17 bytes -#define SIZE_AUDIO_INFOFRAME 0x0F // 15 bytes -enum { - AVI_COLOR_MODE_RGB = 0, - AVI_COLOR_MODE_YCBCR422, - AVI_COLOR_MODE_YCBCR444 -}; -enum { - AVI_COLORIMETRY_NO_DATA = 0, - AVI_COLORIMETRY_SMPTE_170M, - AVI_COLORIMETRY_ITU709, - AVI_COLORIMETRY_EXTENDED -}; -enum { - AVI_CODED_FRAME_ASPECT_NO_DATA, - AVI_CODED_FRAME_ASPECT_4_3, - AVI_CODED_FRAME_ASPECT_16_9 -}; -enum { - ACTIVE_ASPECT_RATE_SAME_AS_CODED_FRAME = 0x08, - ACTIVE_ASPECT_RATE_4_3, - ACTIVE_ASPECT_RATE_16_9, - ACTIVE_ASPECT_RATE_14_9 -}; -#if 0 -/* External Video Parameter Setting*/ -#define EXT_VIDEO_PARA 0xC0 -#define m_VSYNC_OFFSET (0xF << 4) -#define m_VSYNC_POLARITY (1 << 3) -#define m_HSYNC_POLARITY (1 << 2) -#define m_INTERLACE (1 << 1) -#define m_EXT_VIDEO_ENABLE (1 << 0) - -#define v_VSYNC_OFFSET(n) (n << 4) -#define v_VSYNC_POLARITY(n) (n << 3) -#define v_HSYNC_POLARITY(n) (n << 2) -#define v_INTERLACE(n) (n << 1) -#define v_EXT_VIDEO_ENABLE(n) (n << 0) - -#define EXT_VIDEO_PARA_HTOTAL_L 0xC4 -#define EXT_VIDEO_PARA_HTOTAL_H 0xC8 -#define EXT_VIDEO_PARA_HBLANK_L 0xCC -#define EXT_VIDEO_PARA_HBLANK_H 0xD0 -#define EXT_VIDEO_PARA_HDELAY_L 0xD4 -#define EXT_VIDEO_PARA_HDELAY_H 0xD8 -#define EXT_VIDEO_PARA_HSYNCWIDTH_L 0xDC -#define EXT_VIDEO_PARA_HSYNCWIDTH_H 0xE0 - -#define EXT_VIDEO_PARA_VTOTAL_L 0xE4 -#define EXT_VIDEO_PARA_VTOTAL_H 0xE8 -#define EXT_VIDEO_PARA_VBLANK_L 0xF4 -#define EXT_VIDEO_PARA_VDELAY 0xF8 -#define EXT_VIDEO_PARA_VSYNCWIDTH 0xFC - -#define PHY_PLL_SPEED 0x158 - #define v_TEST_EN(n) (n << 6) - #define v_PLLA_BYPASS(n) (n << 4) - #define v_PLLB_SPEED(n) (n << 2) - #define v_PLLA_SPEED(n) (n) - enum { - PLL_SPEED_LOWEST = 0, - PLL_SPEED_MIDLOW, - PLL_SPEED_MIDHIGH, - PLL_SPEED_HIGHEST - }; - -#define PHY_PLL_17 0x15c // PLL A & B config bit 17 - #define v_PLLA_BIT17(n) (n << 2) - #define v_PLLB_BIT17(n) (n << 1) - -#define PHY_BGR 0x160 - #define v_BGR_DISCONNECT(n) (n << 7) - #define v_BGR_V_OFFSET(n) (n << 4) - #define v_BGR_I_OFFSET(n) (n) - -#define PHY_PLLA_1 0x164 -#define PHY_PLLA_2 0x168 -#define PHY_PLLB_1 0x16c -#define PHY_PLLB_2 0x170 - -#define PHY_DRIVER_PREEMPHASIS 0x174 - #define v_TMDS_SWING(n) (n << 4) - #define v_PRE_EMPHASIS(n) (n) - -#define PHY_PLL_16_AML 0x178 // PLL A & B config bit 16 and AML control - #define v_PLLA_BIT16(n) (n << 5) - #define v_PLLB_BIT16(n) (n << 4) - #define v_AML(n) (n) -#endif -/* Interrupt Setting */ -#define INTR_MASK1 0xc0 -#define INTR_STATUS1 0xc1 - #define m_INT_HOTPLUG (1 << 7) - #define m_INT_VSYNC (1 << 5) - #define m_INT_EDID_READY (1 << 2) - -#define INTR_MASK2 0xc2 -#define INTR_STATUS2 0xc3 - #define m_INT_HDCP_ERR (1 << 7) // HDCP error detected - #define m_INT_BKSV_RPRDY (1 << 6) // BKSV list ready from repeater - #define m_INT_AUTH_DONE (1 << 4) // HDCP authentication done - -#if 0 -#define DDC_READ_FIFO_ADDR 0x200 -#define DDC_BUS_FREQ_L 0x204 -#define DDC_BUS_FREQ_H 0x208 -#define DDC_BUS_CTRL 0x2dc -#define DDC_I2C_LEN 0x278 -#define DDC_I2C_OFFSET 0x280 -#define DDC_I2C_CTRL 0x284 -#define DDC_I2C_READ_BUF0 0x288 -#define DDC_I2C_READ_BUF1 0x28c -#define DDC_I2C_READ_BUF2 0x290 -#define DDC_I2C_READ_BUF3 0x294 -#define DDC_I2C_WRITE_BUF0 0x298 -#define DDC_I2C_WRITE_BUF1 0x29c -#define DDC_I2C_WRITE_BUF2 0x2a0 -#define DDC_I2C_WRITE_BUF3 0x2a4 -#define DDC_I2C_WRITE_BUF4 0x2ac -#define DDC_I2C_WRITE_BUF5 0x2b0 -#define DDC_I2C_WRITE_BUF6 0x2b4 - -#endif -#define EDID_SEGMENT_POINTER 0x4d -#define EDID_WORD_ADDR 0x4e -#define EDID_FIFO_ADDR 0x4f - -#define PIN_STATUS 0xc8 -#define m_HOTPLUG_STATUS (1 << 7) -#define m_DDCSDA_STATUS (1 << 5) -#define m_DDCSCL_STATUS (1 << 4) -#if 0 -/* HDCP_CTRL */ -#define HDCP_CTRL 0x2bc - enum { - OUTPUT_DVI = 0, - OUTPUT_HDMI - }; - #define m_HDCP_AUTH_START (1 << 7) // start hdcp - #define m_HDCP_BKSV_PASS (1 << 6) // bksv valid - #define m_HDCP_BKSV_FAILED (1 << 5) // bksv invalid - #define m_HDCP_FRAMED_ENCRYPED (1 << 4) - #define m_HDCP_AUTH_STOP (1 << 3) // stop hdcp - #define m_HDCP_ADV_CIPHER (1 << 2) // advanced cipher mode - #define m_HDMI_DVI (1 << 1) - #define m_HDCP_RESET (1 << 0) // reset hdcp - #define v_HDCP_AUTH_START(n) (n << 7) - #define v_HDCP_BKSV_PASS(n) (n << 6) - #define v_HDCP_BKSV_FAILED(n) (n << 5) - #define v_HDCP_FRAMED_ENCRYPED(n) (n << 4) - #define v_HDCP_AUTH_STOP(n) (n << 3) - #define v_HDCP_ADV_CIPHER(n) (n << 2) - #define v_HDMI_DVI(n) (n << 1) - #define v_HDCP_RESET(n) (n << 0) -#define HDCP_CTRL2 0x340 - -/* HDCP Key Memory Access Control */ -#define HDCP_KEY_ACCESS_CTRL1 0x338 -#define HDCP_KEY_ACCESS_CTRL2 0x33c - #define m_LOAD_FACSIMILE_HDCP_KEY (1 << 1) - #define m_LOAD_HDCP_KEY (1 << 0) -/* HDCP Key Memory Control */ -#define HDCP_KEY_MEM_CTRL 0x348 - #define m_USE_KEY1 (1 << 6) - #define m_USE_KEY2 (1 << 5) - #define m_LOAD_AKSV (1 << 4) - #define m_KSV_SELECTED (1 << 3) - #define m_KSV_VALID (1 << 2) - #define m_KEY_VALID (1 << 1) - #define m_KEY_READY (1 << 0) - #define v_USE_KEY1(n) (n << 6) - #define v_USE_KEY2(n) (n << 5) - #define v_LOAD_AKSV(n) (n << 4) - -/* HDCP B device capacity */ -#define HDCP_BCAPS 0x2f8 - #define m_HDMI_RECEIVED (1 << 7) //If HDCP receiver support HDMI, this bit must be 1. - #define m_REPEATER (1 << 6) - #define m_KSV_FIFO_READY (1 << 5) - #define m_DDC_FAST (1 << 4) - #define m_1_1_FEATURE (1 << 1) - #define m_FAST_REAUTHENTICATION (1 << 0) //For HDMI, this function is supported whether this bit is enabled or not. - -/* HDCP KSV Value */ -#define HDCP_KSV_BYTE0 0x2fc -#define HDCP_KSV_BYTE1 0x300 -#define HDCP_KSV_BYTE2 0x304 -#define HDCP_KSV_BYTE3 0x308 -#define HDCP_KSV_BYTE4 0x30c - -/* HDCP error status */ -#define HDCP_ERROR 0x320 - -/* HDCP 100 ms timer */ -#define HDCP_TIMER_100MS 0x324 -/* HDCP 5s timer */ -#define HDCP_TIMER_5S 0x328 - -/* HDCP Key ram address */ -#define HDCP_RAM_KEY_KSV1 0x400 -#define HDCP_RAM_KEY_KSV2 0x407 -#define HDCP_RAM_KEY_PRIVATE 0x40e -#define HDCP_KEY_LENGTH 0x13C - - -#define HDCP_ENABLE_HW_AUTH // Enable hardware authentication mode -#define HDMI_INTERANL_CLK_DIV 0x19 - -#define HDMIRdReg(addr) __raw_readl(hdmi->regbase + addr) -#define HDMIWrReg(addr, val) __raw_writel((val), hdmi->regbase + addr); -#define HDMIMskReg(temp, addr, msk, val) \ - temp = __raw_readl(hdmi->regbase + addr) & (0xFF - (msk)) ; \ - __raw_writel(temp | ( (val) & (msk) ), hdmi->regbase + addr); - - - -/* Color Space Convertion Mode */ -enum { - CSC_RGB_0_255_TO_ITU601_16_235 = 0, //RGB 0-255 input to YCbCr 16-235 output according BT601 - CSC_RGB_0_255_TO_ITU709_16_235, //RGB 0-255 input to YCbCr 16-235 output accroding BT709 - CSC_ITU601_16_235_TO_RGB_16_235, //YCbCr 16-235 input to RGB 16-235 output according BT601 - CSC_ITU709_16_235_TO_RGB_16_235, //YCbCr 16-235 input to RGB 16-235 output according BT709 - CSC_ITU601_16_235_TO_RGB_0_255, //YCbCr 16-235 input to RGB 0-255 output according BT601 - CSC_ITU709_16_235_TO_RGB_0_255 //YCbCr 16-235 input to RGB 0-255 output according BT709 -}; -#endif -extern int rk2928_hdmi_initial(void); -extern int rk2928_hdmi_detect_hotplug(void); -extern int rk2928_hdmi_read_edid(int block, unsigned char *buff); -extern int rk2928_hdmi_removed(void); -extern int rk2928_hdmi_config_video(struct hdmi_video_para *vpara); -extern int rk2928_hdmi_config_audio(struct hdmi_audio *audio); -extern void rk2928_hdmi_control_output(int enable); - -#endif diff --git a/drivers/video/rockchip/hdmi/rk_hdmi_core.c b/drivers/video/rockchip/hdmi/rk_hdmi_core.c deleted file mode 100755 index 1b17185b6da9..000000000000 --- a/drivers/video/rockchip/hdmi/rk_hdmi_core.c +++ /dev/null @@ -1,254 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - - -struct class *hdmi_class; -struct hdmi_id_ref_info { - struct hdmi *hdmi; - int id; - int ref; -}ref_info[HDMI_MAX_ID]; -#ifdef CONFIG_SYSFS - -extern int hdmi_create_attrs(struct hdmi *hdmi); -extern void hdmi_remove_attrs(struct hdmi *hdmi); - -#else - -static inline int hdmi_create_attrs(struct hdmi *hdmi) -{ return 0; } -static inline void hdmi_remove_attrs(struct hdmi *hdmi) {} - -#endif /* CONFIG_SYSFS */ -static void __hdmi_changed(struct hdmi *hdmi) -{ - int precent; - - mutex_lock(&hdmi->lock); - precent = hdmi->ops->hdmi_precent(hdmi); - if(precent && (hdmi->mode == DISP_ON_LCD) && hdmi->display_on){ - if(hdmi->ops->insert(hdmi) == 0){ - hdmi->mode = hdmi->display_on; - kobject_uevent(&hdmi->dev->kobj, KOBJ_CHANGE); - } - else - hdmi_dbg(hdmi->dev, "insert error\n"); - hdmi_set_backlight(hdmi->display_on==DISP_ON_HDMI?HDMI_DISABLE: HDMI_ENABLE); - - } - else if(precent &&(hdmi->mode != hdmi->display_on)&& hdmi->display_on){ - hdmi->mode = hdmi->display_on; - hdmi_set_backlight(hdmi->display_on==DISP_ON_HDMI?HDMI_DISABLE: HDMI_ENABLE); - } - else if((!precent || !hdmi->display_on) && hdmi->mode != DISP_ON_LCD){ - if(hdmi->ops->remove(hdmi) == 0){ - hdmi->mode = DISP_ON_LCD; - hdmi_set_backlight(HDMI_ENABLE); - kobject_uevent(&hdmi->dev->kobj, KOBJ_CHANGE); - } - else - hdmi_dbg(hdmi->dev, "remove error\n"); - } - mutex_unlock(&hdmi->lock); - return; -} - -void hdmi_changed(struct hdmi *hdmi, int msec) -{ - schedule_delayed_work(&hdmi->work, msecs_to_jiffies(msec)); - return; -} -void hdmi_suspend(struct hdmi *hdmi) -{ - del_timer(&hdmi->timer); - flush_delayed_work(&hdmi->work); - if(hdmi->mode != DISP_ON_LCD){ - hdmi->ops->remove(hdmi); - hdmi->mode = DISP_ON_LCD; - } - return; -} -void hdmi_resume(struct hdmi *hdmi) -{ - mod_timer(&hdmi->timer, jiffies + msecs_to_jiffies(10)); - return; -} - -static void hdmi_changed_work(struct work_struct *work) -{ - struct hdmi *hdmi = container_of(work, struct hdmi, - work.work); - - __hdmi_changed(hdmi); - return; -} - -void *hdmi_priv(struct hdmi *hdmi) -{ - return (void *)hdmi->priv; -} -static void hdmi_detect_timer(unsigned long data) -{ - struct hdmi *hdmi = (struct hdmi*)data; - - int precent = hdmi->ops->hdmi_precent(hdmi); - - if((precent && hdmi->mode == DISP_ON_LCD) || - (!precent && hdmi->mode != DISP_ON_LCD)) - hdmi_changed(hdmi, 100); - mod_timer(&hdmi->timer, jiffies + msecs_to_jiffies(200)); -} -struct hdmi *hdmi_register(int extra, struct device *parent) -{ - int rc = 0, i; - char name[8]; - struct hdmi *hdmi = kzalloc(sizeof(struct hdmi)+ extra, GFP_KERNEL); - - if(!hdmi) - return NULL; - for(i = 0; i < HDMI_MAX_ID; i++) - { - if(ref_info[i].ref == 0) - { - ref_info[i].ref = 1; - hdmi->id = i; - break; - } - } - if(i == HDMI_MAX_ID) - { - kfree(hdmi); - return NULL; - } - sprintf(name, "hdmi-%d", hdmi->id); - - hdmi->dev = device_create(hdmi_class, parent, 0, - "%s", name); - if (IS_ERR(hdmi->dev)) { - rc = PTR_ERR(hdmi->dev); - goto dev_create_failed; - } - - dev_set_drvdata(hdmi->dev, hdmi); - ref_info[i].hdmi = hdmi; - - INIT_DELAYED_WORK(&hdmi->work, hdmi_changed_work); - - rc = hdmi_create_attrs(hdmi); - if (rc) - goto create_attrs_failed; - - goto success; - -create_attrs_failed: - device_unregister(hdmi->dev); -dev_create_failed: - hdmi_remove_attrs(hdmi); - kfree(hdmi); - return NULL; -success: - mutex_init(&hdmi->lock); - setup_timer(&hdmi->timer, hdmi_detect_timer,(unsigned long)hdmi); - mod_timer(&hdmi->timer, jiffies + msecs_to_jiffies(200)); - return hdmi; -} -void hdmi_unregister(struct hdmi *hdmi) -{ - int id; - - if(!hdmi) - return; - id = hdmi->id; - del_timer(&hdmi->timer); - flush_scheduled_work(); - hdmi_remove_attrs(hdmi); - device_unregister(hdmi->dev); - - kfree(hdmi); - hdmi = NULL; - ref_info[id].ref = 0; - ref_info[id].hdmi = NULL; -} -struct hdmi *get_hdmi_struct(int nr) -{ - if(ref_info[nr].ref == 0) - return NULL; - else - return ref_info[nr].hdmi; -} -int hdmi_is_insert(void) -{ - struct hdmi *hdmi = get_hdmi_struct(0); - - if(hdmi && hdmi->ops && hdmi->ops->hdmi_precent) - return hdmi->ops->hdmi_precent(hdmi); - else - return 0; -} -int hdmi_get_scale(void) -{ - struct hdmi* hdmi = get_hdmi_struct(0); - if(!hdmi) - return 100; - else if(hdmi->mode != DISP_ON_LCD) - return hdmi->scale; - else - return 100; -} - -int hdmi_set_scale(int event, char *data, int len) -{ - int result; - struct hdmi* hdmi = get_hdmi_struct(0); - - if(!hdmi) - return -1; - if(len != 4) - return -1; - if(fb_get_video_mode() || hdmi->mode == DISP_ON_LCD) - return -1; - - result = data[0] | data[1]<<1 | data[2]<<2; - if(event != MOUSE_NONE && (result & event) != event) - return -1; - - hdmi->scale += data[3]; - - hdmi->scale = (hdmi->scale>100)?100:hdmi->scale; - hdmi->scale = (hdmi->scalescale; - return 0; -} - -static int __init hdmi_class_init(void) -{ - int i; - - hdmi_class = class_create(THIS_MODULE, "hdmi"); - - if (IS_ERR(hdmi_class)) - return PTR_ERR(hdmi_class); - for(i = 0; i < HDMI_MAX_ID; i++) { - ref_info[i].id = i; - ref_info[i].ref = 0; - ref_info[i].hdmi = NULL; - } - return 0; -} - -static void __exit hdmi_class_exit(void) -{ - class_destroy(hdmi_class); -} -EXPORT_SYMBOL(hdmi_changed); -EXPORT_SYMBOL(hdmi_register); -EXPORT_SYMBOL(hdmi_unregister); -EXPORT_SYMBOL(get_hdmi_struct); - -subsys_initcall(hdmi_class_init); -module_exit(hdmi_class_exit); - From b7e358d29eedc2a1ac247aa3a7c5f76ce386a150 Mon Sep 17 00:00:00 2001 From: ywj Date: Mon, 20 Aug 2012 11:29:51 +0800 Subject: [PATCH 238/261] amend DEVICE_ATTR 0660 of rk29_keys and rk29_backlight factorytool --- drivers/input/keyboard/rk29_keys.c | 4 ++-- drivers/video/backlight/rk29_backlight.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/input/keyboard/rk29_keys.c b/drivers/input/keyboard/rk29_keys.c index 1fc354b1d2f7..bc67d41c4964 100755 --- a/drivers/input/keyboard/rk29_keys.c +++ b/drivers/input/keyboard/rk29_keys.c @@ -114,12 +114,12 @@ static ssize_t rk29key_set(struct device *dev, } for(i=0;i<7;i++) - printk("desc=%s, code=%d\n",pdata->buttons[i].desc,pdata->buttons[i].code); + key_dbg("desc=%s, code=%d\n",pdata->buttons[i].desc,pdata->buttons[i].code); return 0; } -static DEVICE_ATTR(rk29key,0777, NULL, rk29key_set); +static DEVICE_ATTR(rk29key,0660, NULL, rk29key_set); void rk29_send_power_key(int state) { diff --git a/drivers/video/backlight/rk29_backlight.c b/drivers/video/backlight/rk29_backlight.c index 6ea850f95725..9aa6cd5c2b27 100755 --- a/drivers/video/backlight/rk29_backlight.c +++ b/drivers/video/backlight/rk29_backlight.c @@ -88,7 +88,7 @@ static ssize_t backlight_read(struct device *dev, printk("rk29_bl_info->min_brightness=%d\n",rk29_bl_info->min_brightness); } -static DEVICE_ATTR(rk29backlight, 0777, backlight_read, backlight_write); +static DEVICE_ATTR(rk29backlight, 0660, backlight_read, backlight_write); static int rk29_bl_update_status(struct backlight_device *bl) { From 6c1f41812947580cb8bf13b52d0d01ed45526308 Mon Sep 17 00:00:00 2001 From: ywj Date: Mon, 20 Aug 2012 11:40:56 +0800 Subject: [PATCH 239/261] remove bmp_logo option and del rk29_backlight.c printklog --- arch/arm/configs/rk3066_sdk_defconfig | 4 ++-- drivers/video/backlight/rk29_backlight.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/configs/rk3066_sdk_defconfig b/arch/arm/configs/rk3066_sdk_defconfig index 0d91d95faf38..2964f7e38e97 100755 --- a/arch/arm/configs/rk3066_sdk_defconfig +++ b/arch/arm/configs/rk3066_sdk_defconfig @@ -22,9 +22,8 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_ARCH_RK30=y -CONFIG_WIFI_CONTROL_FUNC=y -CONFIG_MACH_RK3066_SDK=y CONFIG_CLK_SWITCH_TO_32K=y +CONFIG_MACH_RK3066_SDK=y # CONFIG_SWP_EMULATE is not set CONFIG_FIQ_DEBUGGER=y CONFIG_FIQ_DEBUGGER_NO_SLEEP=y @@ -289,6 +288,7 @@ CONFIG_RGA_RK30=y CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set +# CONFIG_LOGO_LINUX_BMP is not set CONFIG_SOUND=y CONFIG_SND=y # CONFIG_SND_SUPPORT_OLD_API is not set diff --git a/drivers/video/backlight/rk29_backlight.c b/drivers/video/backlight/rk29_backlight.c index 9aa6cd5c2b27..1d151b35229b 100755 --- a/drivers/video/backlight/rk29_backlight.c +++ b/drivers/video/backlight/rk29_backlight.c @@ -86,7 +86,7 @@ static ssize_t backlight_read(struct device *dev, { struct rk29_bl_info *rk29_bl_info = bl_get_data(rk29_bl); - printk("rk29_bl_info->min_brightness=%d\n",rk29_bl_info->min_brightness); + DBG("rk29_bl_info->min_brightness=%d\n",rk29_bl_info->min_brightness); } static DEVICE_ATTR(rk29backlight, 0660, backlight_read, backlight_write); From d0273dd2e778b3d61c0f37f735474e1dfcca195c Mon Sep 17 00:00:00 2001 From: kfx Date: Mon, 20 Aug 2012 13:16:32 +0800 Subject: [PATCH 240/261] rk2928: a720: touchscren && camera && sdmmc && usb wifi support --- arch/arm/configs/rk2928_a720_defconfig | 9 +- .../mach-rk2928/board-rk2928-a720-camera.c | 448 ++++++ arch/arm/mach-rk2928/board-rk2928-a720.c | 118 +- arch/arm/mach-rk2928/include/mach/board.h | 10 + drivers/input/touchscreen/Kconfig | 7 +- drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/sitronix_ts_a720.c | 1233 +++++++++++++++++ drivers/input/touchscreen/sitronix_ts_a720.h | 175 +++ 8 files changed, 1993 insertions(+), 8 deletions(-) create mode 100644 arch/arm/mach-rk2928/board-rk2928-a720-camera.c create mode 100755 drivers/input/touchscreen/sitronix_ts_a720.c create mode 100755 drivers/input/touchscreen/sitronix_ts_a720.h diff --git a/arch/arm/configs/rk2928_a720_defconfig b/arch/arm/configs/rk2928_a720_defconfig index bb5d2ec4d623..e4af82c036e9 100644 --- a/arch/arm/configs/rk2928_a720_defconfig +++ b/arch/arm/configs/rk2928_a720_defconfig @@ -202,6 +202,7 @@ CONFIG_PHYLIB=y # CONFIG_NETDEV_1000 is not set # CONFIG_NETDEV_10000 is not set CONFIG_WLAN_80211=y +CONFIG_RTL8188EU=y CONFIG_USB_USBNET=y CONFIG_PPP=y CONFIG_PPP_MULTILINK=y @@ -221,6 +222,7 @@ CONFIG_INPUT_KEYRESET=y CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TABLET=y CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_SITRONIX_A720=y CONFIG_INPUT_MISC=y CONFIG_INPUT_KEYCHORD=y CONFIG_INPUT_UINPUT=y @@ -250,6 +252,12 @@ CONFIG_MFD_TPS65090=y CONFIG_REGULATOR=y CONFIG_REGULATOR_TPS65910=y CONFIG_RK30_PWM_REGULATOR=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_VIDEO_DEV=y +CONFIG_SOC_CAMERA=y +CONFIG_SOC_CAMERA_OV2659=y +CONFIG_VIDEO_RK29=y +CONFIG_VIDEO_RK29_CAMMEM_ION=y CONFIG_ION=y CONFIG_ION_ROCKCHIP=y CONFIG_FB=y @@ -350,7 +358,6 @@ CONFIG_MMC_UNSAFE_RESUME=y CONFIG_MMC_EMBEDDED_SDIO=y CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_SDMMC_RK29=y -# CONFIG_SDMMC0_RK29 is not set # CONFIG_SDMMC1_RK29 is not set CONFIG_SWITCH=y CONFIG_SWITCH_GPIO=y diff --git a/arch/arm/mach-rk2928/board-rk2928-a720-camera.c b/arch/arm/mach-rk2928/board-rk2928-a720-camera.c new file mode 100644 index 000000000000..b92e6b28428e --- /dev/null +++ b/arch/arm/mach-rk2928/board-rk2928-a720-camera.c @@ -0,0 +1,448 @@ +#ifdef CONFIG_VIDEO_RK29 +/*---------------- Camera Sensor Macro Define Begin ------------------------*/ +/*---------------- Camera Sensor Configuration Macro Begin ------------------------*/ +#define CONFIG_SENSOR_0 RK29_CAM_SENSOR_OV5642 /* back camera sensor */ +#define CONFIG_SENSOR_IIC_ADDR_0 0 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_0 0 +#define CONFIG_SENSOR_CIF_INDEX_0 0 +#define CONFIG_SENSOR_ORIENTATION_0 90 +#define CONFIG_SENSOR_POWER_PIN_0 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_0 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_0 INVALID_GPIO//RK2928_PIN3_PB3 +#define CONFIG_SENSOR_FALSH_PIN_0 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_0 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_0 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_0 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_0 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_0 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_0 30000 + +#define CONFIG_SENSOR_01 RK29_CAM_SENSOR_OV5642 /* back camera sensor 1 */ +#define CONFIG_SENSOR_IIC_ADDR_01 0x00 +#define CONFIG_SENSOR_CIF_INDEX_01 0 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_01 4 +#define CONFIG_SENSOR_ORIENTATION_01 90 +#define CONFIG_SENSOR_POWER_PIN_01 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_01 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_01 INVALID_GPIO//RK2928_PIN3_PB3 +#define CONFIG_SENSOR_FALSH_PIN_01 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_01 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_01 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_01 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_01 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_01 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_01 30000 + +#define CONFIG_SENSOR_02 RK29_CAM_SENSOR_OV5640 /* back camera sensor 2 */ +#define CONFIG_SENSOR_IIC_ADDR_02 0x00 +#define CONFIG_SENSOR_CIF_INDEX_02 0 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_02 4 +#define CONFIG_SENSOR_ORIENTATION_02 90 +#define CONFIG_SENSOR_POWER_PIN_02 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_02 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_02 INVALID_GPIO//RK2928_PIN3_PB3 +#define CONFIG_SENSOR_FALSH_PIN_02 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_02 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_02 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_02 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_02 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_02 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_02 30000 + +#define CONFIG_SENSOR_1 RK29_CAM_SENSOR_OV2659 /* front camera sensor 0 */ +#define CONFIG_SENSOR_IIC_ADDR_1 0x60 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_1 1 +#define CONFIG_SENSOR_CIF_INDEX_1 0 +#define CONFIG_SENSOR_ORIENTATION_1 270 +#define CONFIG_SENSOR_POWER_PIN_1 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_1 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_1 RK2928_PIN3_PB3 +#define CONFIG_SENSOR_FALSH_PIN_1 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_1 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_1 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_1 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_1 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_1 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_1 30000 + +#define CONFIG_SENSOR_11 RK29_CAM_SENSOR_OV2659 /* front camera sensor 1 */ +#define CONFIG_SENSOR_IIC_ADDR_11 0x00 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_11 3 +#define CONFIG_SENSOR_CIF_INDEX_11 0 +#define CONFIG_SENSOR_ORIENTATION_11 270 +#define CONFIG_SENSOR_POWER_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_FALSH_PIN_11 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_11 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_11 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_11 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_11 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_11 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_11 30000 + +#define CONFIG_SENSOR_12 RK29_CAM_SENSOR_OV2659//RK29_CAM_SENSOR_OV2655 /* front camera sensor 2 */ +#define CONFIG_SENSOR_IIC_ADDR_12 0x00 +#define CONFIG_SENSOR_IIC_ADAPTER_ID_12 3 +#define CONFIG_SENSOR_CIF_INDEX_12 0 +#define CONFIG_SENSOR_ORIENTATION_12 270 +#define CONFIG_SENSOR_POWER_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_RESET_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_POWERDN_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_FALSH_PIN_12 INVALID_GPIO +#define CONFIG_SENSOR_POWERACTIVE_LEVEL_12 RK29_CAM_POWERACTIVE_L +#define CONFIG_SENSOR_RESETACTIVE_LEVEL_12 RK29_CAM_RESETACTIVE_L +#define CONFIG_SENSOR_POWERDNACTIVE_LEVEL_12 RK29_CAM_POWERDNACTIVE_H +#define CONFIG_SENSOR_FLASHACTIVE_LEVEL_12 RK29_CAM_FLASHACTIVE_L + +#define CONFIG_SENSOR_QCIF_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_240X160_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_QVGA_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_CIF_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_VGA_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_480P_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_SVGA_FPS_FIXED_12 15000 +#define CONFIG_SENSOR_720P_FPS_FIXED_12 30000 + + +#endif //#ifdef CONFIG_VIDEO_RK29 +/*---------------- Camera Sensor Configuration Macro End------------------------*/ +#include "../../../drivers/media/video/rk2928_camera.c" +/*---------------- Camera Sensor Macro Define End ---------*/ + +#define PMEM_CAM_SIZE PMEM_CAM_NECESSARY +/***************************************************************************************** + * camera devices + * author: ddl@rock-chips.com + *****************************************************************************************/ +#ifdef CONFIG_VIDEO_RK29 +#define CONFIG_SENSOR_POWER_IOCTL_USR 0 //define this refer to your board layout +#define CONFIG_SENSOR_RESET_IOCTL_USR 0 +#define CONFIG_SENSOR_POWERDOWN_IOCTL_USR 0 +#define CONFIG_SENSOR_FLASH_IOCTL_USR 0 + +static void rk_cif_power(int on) +{ + struct regulator *ldo_18,*ldo_28; + ldo_28 = regulator_get(NULL, "ldo7"); // vcc28_cif + ldo_18 = regulator_get(NULL, "ldo1"); // vcc18_cif + if (ldo_28 == NULL || IS_ERR(ldo_28) || ldo_18 == NULL || IS_ERR(ldo_18)){ + printk("get cif ldo failed!\n"); + return; + } + if(on == 0){ + regulator_disable(ldo_28); + regulator_put(ldo_28); + regulator_disable(ldo_18); + regulator_put(ldo_18); + mdelay(500); + } + else{ + regulator_set_voltage(ldo_28, 2800000, 2800000); + regulator_enable(ldo_28); + // printk("%s set ldo7 vcc28_cif=%dmV end\n", __func__, regulator_get_voltage(ldo_28)); + regulator_put(ldo_28); + + regulator_set_voltage(ldo_18, 1800000, 1800000); + // regulator_set_suspend_voltage(ldo, 1800000); + regulator_enable(ldo_18); + // printk("%s set ldo1 vcc18_cif=%dmV end\n", __func__, regulator_get_voltage(ldo_18)); + regulator_put(ldo_18); + } +} + +#if CONFIG_SENSOR_POWER_IOCTL_USR +static int sensor_power_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + //#error "CONFIG_SENSOR_POWER_IOCTL_USR is 1, sensor_power_usr_cb function must be writed!!"; + rk_cif_power(on); +} +#endif + +#if CONFIG_SENSOR_RESET_IOCTL_USR +static int sensor_reset_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + #error "CONFIG_SENSOR_RESET_IOCTL_USR is 1, sensor_reset_usr_cb function must be writed!!"; +} +#endif + +#if CONFIG_SENSOR_POWERDOWN_IOCTL_USR +static int sensor_powerdown_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + #error "CONFIG_SENSOR_POWERDOWN_IOCTL_USR is 1, sensor_powerdown_usr_cb function must be writed!!"; +} +#endif + +#if CONFIG_SENSOR_FLASH_IOCTL_USR +static int sensor_flash_usr_cb (struct rk29camera_gpio_res *res,int on) +{ + #error "CONFIG_SENSOR_FLASH_IOCTL_USR is 1, sensor_flash_usr_cb function must be writed!!"; +} +#endif + +static struct rk29camera_platform_ioctl_cb sensor_ioctl_cb = { + #if CONFIG_SENSOR_POWER_IOCTL_USR + .sensor_power_cb = sensor_power_usr_cb, + #else + .sensor_power_cb = NULL, + #endif + + #if CONFIG_SENSOR_RESET_IOCTL_USR + .sensor_reset_cb = sensor_reset_usr_cb, + #else + .sensor_reset_cb = NULL, + #endif + + #if CONFIG_SENSOR_POWERDOWN_IOCTL_USR + .sensor_powerdown_cb = sensor_powerdown_usr_cb, + #else + .sensor_powerdown_cb = NULL, + #endif + + #if CONFIG_SENSOR_FLASH_IOCTL_USR + .sensor_flash_cb = sensor_flash_usr_cb, + #else + .sensor_flash_cb = NULL, + #endif +}; + +#if CONFIG_SENSOR_IIC_ADDR_0 +static struct reginfo_t rk_init_data_sensor_reg_0[] = +{ + {0x0000, 0x00,0,0} + }; +static struct reginfo_t rk_init_data_sensor_winseqreg_0[] ={ + {0x0000, 0x00,0,0} + }; +#endif + +#if CONFIG_SENSOR_IIC_ADDR_1 +static struct reginfo_t rk_init_data_sensor_reg_1[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_1[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_01 +static struct reginfo_t rk_init_data_sensor_reg_01[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_01[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_02 +static struct reginfo_t rk_init_data_sensor_reg_02[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_02[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_11 +static struct reginfo_t rk_init_data_sensor_reg_11[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_11[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +#if CONFIG_SENSOR_IIC_ADDR_12 +static struct reginfo_t rk_init_data_sensor_reg_12[] = +{ + {0x0000, 0x00,0,0} +}; +static struct reginfo_t rk_init_data_sensor_winseqreg_12[] = +{ + {0x0000, 0x00,0,0} +}; +#endif +static rk_sensor_user_init_data_s rk_init_data_sensor[RK_CAM_NUM] = +{ + #if CONFIG_SENSOR_IIC_ADDR_0 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_0, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_0, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_0) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_0) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_1 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_1, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_1, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_1) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_1) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_01 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_01, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_01, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_01) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_01) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_02 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_02, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_02, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_02) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_02) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_11 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_11, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_11, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_11) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_11) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + #if CONFIG_SENSOR_IIC_ADDR_12 + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = rk_init_data_sensor_reg_12, + .rk_sensor_init_winseq = rk_init_data_sensor_winseqreg_12, + .rk_sensor_winseq_size = sizeof(rk_init_data_sensor_winseqreg_12) / sizeof(struct reginfo_t), + .rk_sensor_init_data_size = sizeof(rk_init_data_sensor_reg_12) / sizeof(struct reginfo_t), + }, + #else + { + .rk_sensor_init_width = INVALID_VALUE, + .rk_sensor_init_height = INVALID_VALUE, + .rk_sensor_init_bus_param = INVALID_VALUE, + .rk_sensor_init_pixelcode = INVALID_VALUE, + .rk_sensor_init_data = NULL, + .rk_sensor_init_winseq = NULL, + .rk_sensor_winseq_size = 0, + .rk_sensor_init_data_size = 0, + }, + #endif + + }; +#include "../../../drivers/media/video/rk2928_camera.c" + +#endif /* CONFIG_VIDEO_RK29 */ diff --git a/arch/arm/mach-rk2928/board-rk2928-a720.c b/arch/arm/mach-rk2928/board-rk2928-a720.c index 5808b81359cb..0bc1895fc61b 100755 --- a/arch/arm/mach-rk2928/board-rk2928-a720.c +++ b/arch/arm/mach-rk2928/board-rk2928-a720.c @@ -54,6 +54,7 @@ #include "../../../drivers/spi/rk29_spim.h" #endif +#include "board-rk2928-a720-camera.c" #include "board-rk2928-a720-key.c" #ifdef CONFIG_THREE_FB_BUFFER @@ -259,13 +260,51 @@ static struct platform_device device_ion = { }; #endif + +#if defined(CONFIG_TOUCHSCREEN_SITRONIX_A720) + +#define TOUCH_RESET_PIN RK2928_PIN1_PA3 +#define TOUCH_INT_PIN RK2928_PIN1_PB3 +int ft5306_init_platform_hw(void) +{ + + //printk("ft5306_init_platform_hw\n"); + if(gpio_request(TOUCH_RESET_PIN,NULL) != 0){ + gpio_free(TOUCH_RESET_PIN); + printk("ft5306_init_platform_hw gpio_request error\n"); + return -EIO; + } + + if(gpio_request(TOUCH_INT_PIN,NULL) != 0){ + gpio_free(TOUCH_INT_PIN); + printk("ift5306_init_platform_hw gpio_request error\n"); + return -EIO; + } + gpio_direction_output(TOUCH_RESET_PIN, GPIO_HIGH); + mdelay(10); + gpio_set_value(TOUCH_RESET_PIN,GPIO_LOW); + mdelay(10); + gpio_set_value(TOUCH_RESET_PIN,GPIO_HIGH); + msleep(300); + return 0; + +} + +struct ft5x0x_platform_data sitronix_info = { + .model = 5007, + .init_platform_hw= ft5306_init_platform_hw, +}; + +#endif + + /*MMA7660 gsensor*/ #if defined (CONFIG_GS_MMA7660) #define MMA7660_INT_PIN RK2928_PIN1_PB1 static int mma7660_init_platform_hw(void) { - rk30_mux_api_set(GPIO4C0_SMCDATA0_TRACEDATA0_NAME, GPIO4C_GPIO4C0); + rk30_mux_api_set(GPIO1B1_SPI_TXD_UART1_SOUT_NAME, GPIO1B_GPIO1B1); return 0; } @@ -333,7 +372,69 @@ struct platform_device pwm_regulator_device[1] = { }, }; #endif +/************************************************************************************************** + * SDMMC devices, include the module of SD,MMC,and sdio.noted by xbw at 2012-03-05 +**************************************************************************************************/ +#ifdef CONFIG_SDMMC_RK29 +#include "board-rk2928-sdk-sdmmc.c" +#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) +#define SDMMC0_WRITE_PROTECT_PIN RK2928_PIN1_PA7 //According to your own project to set the value of write-protect-pin. +#endif + +#if defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT) +#define SDMMC1_WRITE_PROTECT_PIN RK2928_PIN0_PD5 //According to your own project to set the value of write-protect-pin. +#endif + +#define RK29SDK_WIFI_SDIO_CARD_DETECT_N RK2928_PIN0_PB2 + +#endif //endif ---#ifdef CONFIG_SDMMC_RK29 + +#ifdef CONFIG_SDMMC0_RK29 +static int rk29_sdmmc0_cfg_gpio(void) +{ + rk29_sdmmc_set_iomux(0, 0xFFFF); + + rk30_mux_api_set(GPIO1C1_MMC0_DETN_NAME, GPIO1C_MMC0_DETN); + +#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) + gpio_request(SDMMC0_WRITE_PROTECT_PIN, "sdmmc-wp"); + gpio_direction_input(SDMMC0_WRITE_PROTECT_PIN); +#endif + + return 0; +} + +#define CONFIG_SDMMC0_USE_DMA +struct rk29_sdmmc_platform_data default_sdmmc0_data = { + .host_ocr_avail = + (MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 | MMC_VDD_28_29 | + MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | + MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36), + .host_caps = + (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), + .io_init = rk29_sdmmc0_cfg_gpio, + +#if !defined(CONFIG_SDMMC_RK29_OLD) + .set_iomux = rk29_sdmmc_set_iomux, +#endif + + .dma_name = "sd_mmc", +#ifdef CONFIG_SDMMC0_USE_DMA + .use_dma = 1, +#else + .use_dma = 0, +#endif + .detect_irq = RK2928_PIN1_PC1, // INVALID_GPIO + .enable_sd_wakeup = 0, + +#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) + .write_prt = SDMMC0_WRITE_PROTECT_PIN, +#else + .write_prt = INVALID_GPIO, +#endif +}; +#endif // CONFIG_SDMMC0_RK29 static struct platform_device *devices[] __initdata = { #ifdef CONFIG_BACKLIGHT_RK29_BL @@ -380,6 +481,15 @@ static struct i2c_board_info __initdata i2c1_info[] = { #endif #ifdef CONFIG_I2C2_RK30 static struct i2c_board_info __initdata i2c2_info[] = { +#if defined (CONFIG_TOUCHSCREEN_SITRONIX_A720) +{ + .type ="sitronix", + .addr = 0x38, + .flags = 0, + .irq = TOUCH_INT_PIN, + .platform_data = &sitronix_info, +}, +#endif }; #endif #ifdef CONFIG_I2C3_RK30 @@ -426,7 +536,7 @@ static void __init rk30_i2c_register_board_info(void) } //end of i2c -#define POWER_ON_PIN RK2928_PIN1_PA4 //power_hold +#define POWER_ON_PIN RK2928_PIN1_PA2 //power_hold static void rk2928_pm_power_off(void) { printk(KERN_ERR "rk2928_pm_power_off start...\n"); @@ -481,8 +591,8 @@ static struct dvfs_arm_table dvfs_cpu_logic_table[] = { {.frequency = 600 * 1000, .cpu_volt = 1200 * 1000, .logic_volt = 1200 * 1000},//1.025V/1.050V {.frequency = 696 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.000V/1.025V {.frequency = 816 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V - {.frequency = 912 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V - {.frequency = 1008 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V + //{.frequency = 912 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V + //{.frequency = 1008 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V #if 0 {.frequency = 1104 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V {.frequency = 1200 * 1000, .cpu_volt = 1400 * 1000, .logic_volt = 1200 * 1000},//1.100V/1.050V diff --git a/arch/arm/mach-rk2928/include/mach/board.h b/arch/arm/mach-rk2928/include/mach/board.h index 9292adca4591..f6d6e99b2bdd 100644 --- a/arch/arm/mach-rk2928/include/mach/board.h +++ b/arch/arm/mach-rk2928/include/mach/board.h @@ -57,6 +57,16 @@ struct eeti_egalax_platform_data{ }; #endif +#if defined (CONFIG_TOUCHSCREEN_SITRONIX_A720) +struct ft5x0x_platform_data{ + u16 model; + int (*get_pendown_state)(void); + int (*init_platform_hw)(void); + int (*ft5x0x_platform_sleep)(void); + int (*ft5x0x_platform_wakeup)(void); + void (*exit_platform_hw)(void); +}; +#endif enum _periph_pll { periph_pll_1485mhz = 148500000, periph_pll_297mhz = 297000000, diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 6e95e5098039..50d915718bcc 100755 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -969,9 +969,6 @@ config LAIBAO_TS config TOUCHSCREEN_GT801_IIC tristate "GT801_IIC based touchscreens" depends on I2C2_RK29 -config TOUCHSCREEN_GT82X_IIC - tristate "GT82x_IIC based touchscreens" - depends on I2C2_RK30 config TOUCHSCREEN_GT818_IIC tristate "GT818_IIC based touchscreens" @@ -1002,6 +999,10 @@ config TOUCHSCREEN_FT5306 tristate "FT5306 based touchscreens: FT5306 Interface" depends on I2C2_RK29 || I2C2_RK30 +config TOUCHSCREEN_SITRONIX_A720 + tristate "SITRONIX based touchscreens: SITRONIX Interface for a720" + depends on I2C2_RK29 || I2C2_RK30 + config TOUCHSCREEN_FT5306_WPX2 tristate "FT5306 based touchscreens: FT5306 Interface,only used for umeox wpx2 board" depends on I2C2_RK29 || I2C2_RK30 diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index d64b4a9063f5..7b28f1998469 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_D70_L3188A) += goodix_touch.o obj-$(CONFIG_TOUCHSCREEN_GT8XX) += rk29_i2c_goodix.o obj-$(CONFIG_TOUCHSCREEN_FT5406) += ft5406_ts.o obj-$(CONFIG_TOUCHSCREEN_FT5306) += ft5306_ts.o +obj-$(CONFIG_TOUCHSCREEN_SITRONIX_A720) += sitronix_ts_a720.o obj-$(CONFIG_TOUCHSCREEN_FT5306_WPX2) += ft5306_ts_wpx2.o obj-$(CONFIG_TOUCHSCREEN_GT819) += gt819.o obj-$(CONFIG_TOUCHSCREEN_NAS) += nas_ts.o diff --git a/drivers/input/touchscreen/sitronix_ts_a720.c b/drivers/input/touchscreen/sitronix_ts_a720.c new file mode 100755 index 000000000000..7e8922dec869 --- /dev/null +++ b/drivers/input/touchscreen/sitronix_ts_a720.c @@ -0,0 +1,1233 @@ +/* + * drivers/input/touchscreen/sitronix_i2c_touch.c + * + * Touchscreen driver for Sitronix (I2C bus) + * + * Copyright (C) 2011 Sitronix Technology Co., Ltd. + * Rudy Huang + */ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif // CONFIG_HAS_EARLYSUSPEND +#include "sitronix_ts_a720.h" +#ifdef SITRONIX_FW_UPGRADE_FEATURE +#include +#include +#endif // SITRONIX_FW_UPGRADE_FEATURE +#include +#include +#include +#include // to be compatible with linux kernel 3.2.15 +#include +#include +#include + +#ifdef SITRONIX_MONITOR_THREAD +#include +//#include +#endif // SITRONIX_MONITOR_THREAD + +#define DRIVER_AUTHOR "Sitronix, Inc." +#define DRIVER_NAME "sitronix" +#define DRIVER_DESC "Sitronix I2C touch" +#define DRIVER_DATE "20120507" +#define DRIVER_MAJOR 2 +#define DRIVER_MINOR 9 +#define DRIVER_PATCHLEVEL 1 + +MODULE_AUTHOR("Rudy Huang "); +MODULE_DESCRIPTION("Sitronix I2C multitouch panels"); +MODULE_LICENSE("GPL"); + +#ifdef SITRONIX_SENSOR_KEY +#define SITRONIX_NUMBER_SENSOR_KEY 3 +int sitronix_sensor_key[SITRONIX_NUMBER_SENSOR_KEY] = { + KEY_BACK, // bit 0 + KEY_HOMEPAGE,//KEY_HOME, // bit 1 + KEY_MENU, // bit 2 +}; +#endif // SITRONIX_SENSOR_KEY + +#ifdef SITRONIX_TOUCH_KEY +#define SITRONIX_NUMBER_TOUCH_KEY 4 + +#ifdef SITRONIX_KEY_BOUNDARY_MANUAL_SPECIFY +#define SITRONIX_TOUCH_RESOLUTION_X 480 /* max of X value in display area */ +#define SITRONIX_TOUCH_RESOLUTION_Y 854 /* max of Y value in display area */ +#define SITRONIX_TOUCH_GAP_Y 10 /* Gap between bottom of display and top of touch key */ +#define SITRONIX_TOUCH_MAX_Y 915 /* resolution of y axis of touch ic */ +struct sitronix_AA_key sitronix_key_array[SITRONIX_NUMBER_TOUCH_KEY] = { + {15, 105, SITRONIX_TOUCH_RESOLUTION_Y + SITRONIX_TOUCH_GAP_Y, SITRONIX_TOUCH_MAX_Y, KEY_MENU}, /* MENU */ + {135, 225, SITRONIX_TOUCH_RESOLUTION_Y + SITRONIX_TOUCH_GAP_Y, SITRONIX_TOUCH_MAX_Y, KEY_HOME}, + {255, 345, SITRONIX_TOUCH_RESOLUTION_Y + SITRONIX_TOUCH_GAP_Y, SITRONIX_TOUCH_MAX_Y, KEY_BACK}, /* KEY_EXIT */ + {375, 465, SITRONIX_TOUCH_RESOLUTION_Y + SITRONIX_TOUCH_GAP_Y, SITRONIX_TOUCH_MAX_Y, KEY_SEARCH}, +}; +#else +#define SCALE_KEY_HIGH_Y 15 +struct sitronix_AA_key sitronix_key_array[SITRONIX_NUMBER_TOUCH_KEY] = { + {0, 0, 0, 0, KEY_MENU}, /* MENU */ + {0, 0, 0, 0, KEY_HOME}, + {0, 0, 0, 0, KEY_BACK}, /* KEY_EXIT */ + {0, 0, 0, 0, KEY_SEARCH}, +}; + +#endif // SITRONIX_KEY_BOUNDARY_MANUAL_SPECIFY +#endif // SITRONIX_TOUCH_KEY +struct sitronix_ts_data { + uint16_t addr; + struct i2c_client *client; + struct input_dev *input_dev; +#if defined(SITRONIX_SENSOR_KEY) || defined (SITRONIX_TOUCH_KEY) + struct input_dev *keyevent_input; +#endif // defined(SITRONIX_SENSOR_KEY) || defined (SITRONIX_TOUCH_KEY) + int use_irq; + struct hrtimer timer; +#ifndef SITRONIX_INT_POLLING_MODE + struct work_struct work; +#else + struct delayed_work work; +#endif // SITRONIX_INT_POLLING_MODE + void (*reset_ic)(void); +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif // CONFIG_HAS_EARLYSUSPEND + uint8_t fw_revision[4]; + int resolution_x; + int resolution_y; + uint8_t max_touches; + uint8_t touch_protocol_type; + uint8_t pixel_length; + int suspend_state; +}; + +static unsigned char initkey_code[] = +{ + KEY_BACK, KEY_HOMEPAGE, KEY_MENU +}; + +static int i2cErrorCount = 0; + +#ifdef SITRONIX_MONITOR_THREAD +static struct task_struct * SitronixMonitorThread = NULL; +static int gMonitorThreadSleepInterval = 300; // 0.3 sec +static atomic_t iMonitorThreadPostpone = ATOMIC_INIT(0); + +static uint8_t PreCheckData[4] ; +static int StatusCheckCount = 0; +static int sitronix_ts_monitor_thread(void *data); +static int sitronix_ts_delay_monitor_thread_start = DELAY_MONITOR_THREAD_START_PROBE; +#endif // SITRONIX_MONITOR_THREAD + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void sitronix_ts_early_suspend(struct early_suspend *h); +static void sitronix_ts_late_resume(struct early_suspend *h); +#endif // CONFIG_HAS_EARLYSUSPEND + +static MTD_STRUCTURE sitronix_ts_gMTDPreStructure[SITRONIX_MAX_SUPPORTED_POINT]={{0}}; + +static struct sitronix_ts_data *sitronix_ts_gpts = NULL; +static int sitronix_ts_irq_on = 0; + +#ifdef SITRONIX_FW_UPGRADE_FEATURE +int sitronix_release(struct inode *, struct file *); +int sitronix_open(struct inode *, struct file *); +ssize_t sitronix_write(struct file *file, const char *buf, size_t count, loff_t *ppos); +ssize_t sitronix_read(struct file *file, char *buf, size_t count, loff_t *ppos); +long sitronix_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +static struct cdev sitronix_cdev; +static struct class *sitronix_class; +static int sitronix_major = 0; + +int sitronix_open(struct inode *inode, struct file *filp) +{ + return 0; +} +EXPORT_SYMBOL(sitronix_open); + +int sitronix_release(struct inode *inode, struct file *filp) +{ + return 0; +} +EXPORT_SYMBOL(sitronix_release); + +ssize_t sitronix_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + int ret; + char *tmp; + + if (count > 8192) + count = 8192; + + tmp = (char *)kmalloc(count,GFP_KERNEL); + if (tmp==NULL) + return -ENOMEM; + if (copy_from_user(tmp,buf,count)) { + kfree(tmp); + return -EFAULT; + } + UpgradeMsg("writing %zu bytes.\n", count); + + ret = i2c_master_send(sitronix_ts_gpts->client, tmp, count); + kfree(tmp); + return ret; +} +EXPORT_SYMBOL(sitronix_write); + +ssize_t sitronix_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + char *tmp; + int ret; + + if (count > 8192) + count = 8192; + + tmp = (char *)kmalloc(count,GFP_KERNEL); + if (tmp==NULL) + return -ENOMEM; + + UpgradeMsg("reading %zu bytes.\n", count); + + ret = i2c_master_recv(sitronix_ts_gpts->client, tmp, count); + if (ret >= 0) + ret = copy_to_user(buf,tmp,count)?-EFAULT:ret; + kfree(tmp); + return ret; +} +EXPORT_SYMBOL(sitronix_read); + +static int sitronix_ts_resume(struct i2c_client *client); +static int sitronix_ts_suspend(struct i2c_client *client, pm_message_t mesg); +long sitronix_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int err = 0; + int retval = 0; + uint8_t temp[4]; + + if (_IOC_TYPE(cmd) != SMT_IOC_MAGIC) return -ENOTTY; + if (_IOC_NR(cmd) > SMT_IOC_MAXNR) return -ENOTTY; + if (_IOC_DIR(cmd) & _IOC_READ) + err = !access_ok(VERIFY_WRITE,(void __user *)arg,\ + _IOC_SIZE(cmd)); + else if (_IOC_DIR(cmd) & _IOC_WRITE) + err = !access_ok(VERIFY_READ,(void __user *)arg,\ + _IOC_SIZE(cmd)); + if (err) return -EFAULT; + + switch(cmd) { + case IOCTL_SMT_GET_DRIVER_REVISION: + UpgradeMsg("IOCTL_SMT_GET_DRIVER_REVISION\n"); + temp[0] = SITRONIX_TOUCH_DRIVER_VERSION; + if(copy_to_user((uint8_t __user *)arg, &temp[0], 1)){ + UpgradeMsg("fail to get driver version\n"); + retval = -EFAULT; + } + break; + case IOCTL_SMT_GET_FW_REVISION: + UpgradeMsg("IOCTL_SMT_GET_FW_REVISION\n"); + if(copy_to_user((uint8_t __user *)arg, &sitronix_ts_gpts->fw_revision[0], 4)) + retval = -EFAULT; + break; + case IOCTL_SMT_ENABLE_IRQ: + UpgradeMsg("IOCTL_SMT_ENABLE_IRQ\n"); + if(!sitronix_ts_irq_on){ + sitronix_ts_irq_on = 1; + enable_irq(sitronix_ts_gpts->client->irq); +#ifdef SITRONIX_MONITOR_THREAD + atomic_set(&iMonitorThreadPostpone,1); + SitronixMonitorThread = kthread_run(sitronix_ts_monitor_thread,"Sitronix","Monitorthread"); + if(IS_ERR(SitronixMonitorThread)) + SitronixMonitorThread = NULL; +#endif // SITRONIX_MONITOR_THREAD + } + break; + case IOCTL_SMT_DISABLE_IRQ: + UpgradeMsg("IOCTL_SMT_DISABLE_IRQ\n"); + if(sitronix_ts_irq_on){ + sitronix_ts_irq_on = 0; + disable_irq_nosync(sitronix_ts_gpts->client->irq); +#ifdef SITRONIX_MONITOR_THREAD + if(SitronixMonitorThread){ + kthread_stop(SitronixMonitorThread); + SitronixMonitorThread = NULL; + } +#endif // SITRONIX_MONITOR_THREAD + } + break; + case IOCTL_SMT_RESUME: + UpgradeMsg("IOCTL_SMT_RESUME\n"); + sitronix_ts_resume(sitronix_ts_gpts->client); + break; + case IOCTL_SMT_SUSPEND: + UpgradeMsg("IOCTL_SMT_SUSPEND\n"); + sitronix_ts_suspend(sitronix_ts_gpts->client, PMSG_SUSPEND); + break; + case IOCTL_SMT_HW_RESET: + UpgradeMsg("IOCTL_SMT_HW_RESET\n"); + if(sitronix_ts_gpts->reset_ic) + sitronix_ts_gpts->reset_ic(); + break; + default: + retval = -ENOTTY; + } + + return retval; +} +EXPORT_SYMBOL(sitronix_ioctl); +#endif // SITRONIX_FW_UPGRADE_FEATURE + +static int sitronix_get_fw_revision(struct sitronix_ts_data *ts) +{ + int ret = 0; + uint8_t buffer[4]; + + buffer[0] = FIRMWARE_REVISION_3; + ret = i2c_master_send(ts->client, buffer, 1); + if (ret < 0){ + printk("send fw revision command error (%d)\n", ret); + return ret; + } + ret = i2c_master_recv(ts->client, buffer, 4); + if (ret < 0){ + printk("read fw revision error (%d)\n", ret); + return ret; + }else{ + memcpy(ts->fw_revision, buffer, 4); + printk("fw revision (hex) = %x %x %x %x\n", buffer[0], buffer[1], buffer[2], buffer[3]); + } + return 0; +} + +static int sitronix_get_max_touches(struct sitronix_ts_data *ts) +{ + int ret = 0; + uint8_t buffer[1]; + + buffer[0] = MAX_NUM_TOUCHES; + ret = i2c_master_send(ts->client, buffer, 1); + if (ret < 0){ + printk("send max touches command error (%d)\n", ret); + return ret; + } + ret = i2c_master_recv(ts->client, buffer, 1); + if (ret < 0){ + printk("read max touches error (%d)\n", ret); + return ret; + }else{ + ts->max_touches = buffer[0]; + printk("max touches = %d \n",ts->max_touches); + } + return 0; +} + +static int sitronix_get_protocol_type(struct sitronix_ts_data *ts) +{ + int ret = 0; + uint8_t buffer[1]; + + buffer[0] = I2C_PROTOCOL; + ret = i2c_master_send(ts->client, buffer, 1); + if (ret < 0){ + printk("send i2c protocol command error (%d)\n", ret); + return ret; + } + ret = i2c_master_recv(ts->client, buffer, 1); + if (ret < 0){ + printk("read i2c protocol error (%d)\n", ret); + return ret; + }else{ + ts->touch_protocol_type = buffer[0] & I2C_PROTOCOL_BMSK; + if(ts->touch_protocol_type == SITRONIX_A_TYPE) + ts->pixel_length = PIXEL_DATA_LENGTH_A; + else if(ts->touch_protocol_type == SITRONIX_B_TYPE) + ts->pixel_length = PIXEL_DATA_LENGTH_B; + else + ts->pixel_length = PIXEL_DATA_LENGTH_A; + printk("i2c protocol = %d \n", ts->touch_protocol_type); + } + return 0; +} + +static int sitronix_get_resolution(struct sitronix_ts_data *ts) +{ + int ret = 0; + uint8_t buffer[3]; + + buffer[0] = XY_RESOLUTION_HIGH; + ret = i2c_master_send(ts->client, buffer, 1); + if (ret < 0){ + printk("send resolution command error (%d)\n", ret); + return ret; + } + ret = i2c_master_recv(ts->client, buffer, 3); + if (ret < 0){ + printk("read resolution error (%d)\n", ret); + return ret; + }else{ + ts->resolution_x = ((buffer[0] & (X_RES_H_BMSK << X_RES_H_SHFT)) << 4) | buffer[1]; + ts->resolution_y = ((buffer[0] & Y_RES_H_BMSK) << 8) | buffer[2]; + printk("resolution = %d x %d\n", ts->resolution_x, ts->resolution_y); + } + return 0; +} + +static int sitronix_ts_set_powerdown_bit(struct sitronix_ts_data *ts, int value) +{ + int ret = 0; + uint8_t buffer[2]; + + DbgMsg("%s, value = %d\n", __FUNCTION__, value); + buffer[0] = DEVICE_CONTROL_REG; + ret = i2c_master_send(ts->client, buffer, 1); + if (ret < 0){ + printk("send device control command error (%d)\n", ret); + return ret; + } + + ret = i2c_master_recv(ts->client, buffer, 1); + if (ret < 0){ + printk("read device control status error (%d)\n", ret); + return ret; + }else{ + DbgMsg("dev status = %d \n", buffer[0]); + } + + if(value == 0) + buffer[1] = buffer[0] & 0xfd; + else + buffer[1] = buffer[0] | 0x2; + + buffer[0] = DEVICE_CONTROL_REG; + ret = i2c_master_send(ts->client, buffer, 2); + if (ret < 0){ + printk("write power down error (%d)\n", ret); + return ret; + } + + return 0; +} + +static int sitronix_ts_get_touch_info(struct sitronix_ts_data *ts) +{ + int ret = 0; + ret = sitronix_get_resolution(ts); + if(ret < 0) + return ret; + ret = sitronix_get_fw_revision(ts); + if(ret < 0) + return ret; + if((ts->fw_revision[0] == 0) && (ts->fw_revision[1] == 0)){ + ts->touch_protocol_type = SITRONIX_B_TYPE; + ts->pixel_length = PIXEL_DATA_LENGTH_B; + ts->max_touches = 2; + printk("i2c protocol = %d \n", ts->touch_protocol_type); + printk("max touches = %d \n",ts->max_touches); + }else{ + ret = sitronix_get_protocol_type(ts); + if(ret < 0) + return ret; + if(ts->touch_protocol_type == SITRONIX_B_TYPE){ + ts->max_touches = 2; + printk("max touches = %d \n",ts->max_touches); + }else{ + ret = sitronix_get_max_touches(ts); + if(ret < 0) + return ret; + } + } + return 0; +} + +static int sitronix_ts_get_device_status(struct sitronix_ts_data *ts, uint8_t *dev_status) +{ + int ret = 0; + uint8_t buffer[8]; + + DbgMsg("%s\n", __FUNCTION__); + buffer[0] = STATUS_REG; + ret = i2c_master_send(ts->client, buffer, 1); + if (ret < 0){ + printk("send status reg command error (%d)\n", ret); + return ret; + } + + ret = i2c_master_recv(ts->client, buffer, 8); + if (ret < 0){ + printk("read status reg error (%d)\n", ret); + return ret; + }else{ + DbgMsg("status reg = %d \n", buffer[0]); + } + + *dev_status = buffer[0] & 0xf; + + return 0; +} + +static int sitronix_ts_Enhance_Function_control(struct sitronix_ts_data *ts, uint8_t *value) +{ + int ret = 0; + uint8_t buffer[4]; + + DbgMsg("%s\n", __FUNCTION__); + buffer[0] = 0xF0; + ret = i2c_master_send(ts->client, buffer, 1); + if (ret < 0){ + printk("send Enhance Function command error (%d)\n", ret); + return ret; + } + + ret = i2c_master_recv(ts->client, buffer, 1); + if (ret < 0){ + printk("read Enhance Functions status error (%d)\n", ret); + return ret; + }else{ + DbgMsg("Enhance Functions status = %d \n", buffer[0]); + } + + *value = buffer[0] & 0x4; + + return 0; +} + +static int sitronix_ts_FW_Bank_Select(struct sitronix_ts_data *ts, uint8_t value) +{ + int ret = 0; + uint8_t buffer[1]; + + DbgMsg("%s\n", __FUNCTION__); + buffer[0] = 0xF1; + ret = i2c_master_send(ts->client, buffer, 1); + if (ret < 0){ + printk("send FW Bank Select command error (%d)\n", ret); + return ret; + } + + ret = i2c_master_recv(ts->client, buffer, 1); + if (ret < 0){ + printk("read FW Bank Select status error (%d)\n", ret); + return ret; + }else{ + DbgMsg("FW Bank Select status = %d \n", buffer[0]); + } + + buffer[1] = ((buffer[0] & 0xfc) | value); + buffer[0] = 0xF1; + ret = i2c_master_send(ts->client, buffer, 2); + if (ret < 0){ + printk("send FW Bank Select command error (%d)\n", ret); + return ret; + } + + return 0; +} + +static int sitronix_get_id_info(struct sitronix_ts_data *ts, uint8_t *id_info) +{ + int ret = 0; + uint8_t buffer[4]; + + buffer[0] = 0x0C; + ret = i2c_master_send(ts->client, buffer, 1); + if (ret < 0){ + printk("send id info command error (%d)\n", ret); + return ret; + } + ret = i2c_master_recv(ts->client, buffer, 4); + if (ret < 0){ + printk("read id info error (%d)\n", ret); + return ret; + }else{ + memcpy(id_info, buffer, 4); + } + return 0; +} + +static int sitronix_ts_identify(struct sitronix_ts_data *ts) +{ + int ret = 0; + uint8_t id[4]; + uint8_t Enhance_Function = 0; + + ret = sitronix_ts_FW_Bank_Select(ts, 1); + if(ret < 0) + return ret; + ret = sitronix_ts_Enhance_Function_control(ts, &Enhance_Function); + if(ret < 0) + return ret; + if(Enhance_Function == 0x4){ + ret = sitronix_get_id_info(ts, &id[0]); + if(ret < 0) + return ret; + printk("id (hex) = %x %x %x %x\n", id[0], id[1], id[2], id[3]); + if((id[0] == 1)&&(id[1] == 2)&&(id[2] == 0xb)&&(id[3] == 1)){ + return 0; + }else{ + printk("Error: It is not Sitronix IC\n"); + return -1; + } + }else{ + printk("Error: Can not get ID of Sitronix IC\n"); + return -1; + } +} + +#ifdef SITRONIX_MONITOR_THREAD +static int sitronix_ts_monitor_thread(void *data) +{ + int ret = 0; + uint8_t buffer[4]; + int result = 0; + int once = 1; + DbgMsg("%s:\n", __FUNCTION__); + + printk("delay %d ms\n", sitronix_ts_delay_monitor_thread_start); + msleep(sitronix_ts_delay_monitor_thread_start); + while(!kthread_should_stop()){ + DbgMsg("%s:\n", "Sitronix_ts_monitoring"); + if(atomic_read(&iMonitorThreadPostpone)){ + atomic_set(&iMonitorThreadPostpone,0); + }else{ + if(once == 1){ + buffer[0] = DEVICE_CONTROL_REG; + ret = i2c_master_send(sitronix_ts_gpts->client, buffer, 1); + if (ret < 0){ + DbgMsg("send device control command error (%d)\n", ret); + goto exit_i2c_invalid; + } + ret = i2c_master_recv(sitronix_ts_gpts->client, buffer, 1); + if (ret < 0){ + DbgMsg("read device control status error (%d)\n", ret); + goto exit_i2c_invalid; + }else{ + DbgMsg("read DEVICE_CONTROL_REG status = %d \n", buffer[0]); + } + buffer[0] &= 0xf3; + ret = i2c_master_send(sitronix_ts_gpts->client, buffer, 1); + if (ret < 0){ + DbgMsg("write power down error (%d)\n", ret); + goto exit_i2c_invalid; + } + once = 0; + } + buffer[0] = 0x40; + ret = i2c_master_send(sitronix_ts_gpts->client, buffer, 1); + if (ret < 0){ + DbgMsg("send device control command error (%d)\n", ret); + goto exit_i2c_invalid; + } + ret = i2c_master_recv(sitronix_ts_gpts->client, buffer, 4); + if (ret < 0){ + DbgMsg("read device 1D data error (%d)\n", ret); + goto exit_i2c_invalid; + }else{ + DbgMsg("1D data h40-43 = %d, %d, %d, %d \n", buffer[0], buffer[1], buffer[2], buffer[3]); + result = 1; + if ((PreCheckData[0] == buffer[0]) && (PreCheckData[1] == buffer[1]) && + (PreCheckData[2] == buffer[2]) && (PreCheckData[3] == buffer[3])) + StatusCheckCount ++; + else + StatusCheckCount =0; + PreCheckData[0] = buffer[0]; + PreCheckData[1] = buffer[1]; + PreCheckData[2] = buffer[2]; + PreCheckData[3] = buffer[3]; + if (3 <= StatusCheckCount){ + DbgMsg("IC Status doesn't update! \n"); + result = -1; + StatusCheckCount = 0; + } + } + if (-1 == result){ + printk("Chip abnormal, reset it!\n"); + if(sitronix_ts_gpts->reset_ic) + sitronix_ts_gpts->reset_ic(); + i2cErrorCount = 0; + StatusCheckCount = 0; + } +exit_i2c_invalid: + if(0 == result){ + i2cErrorCount ++; + if ((2 <= i2cErrorCount)){ + printk("I2C abnormal, reset it!\n"); + if(sitronix_ts_gpts->reset_ic) + sitronix_ts_gpts->reset_ic(); + i2cErrorCount = 0; + StatusCheckCount = 0; + } + }else + i2cErrorCount = 0; + } + msleep(gMonitorThreadSleepInterval); + } + DbgMsg("%s exit\n", __FUNCTION__); + return 0; +} +#endif // SITRONIX_MONITOR_THREAD + +static void sitronix_ts_work_func(struct work_struct *work) +{ + int tmp = 0, i = 0; +#ifdef SITRONIX_TOUCH_KEY + int j; +#endif // SITRONIX_TOUCH_KEY + int ret; +#ifndef SITRONIX_INT_POLLING_MODE + struct sitronix_ts_data *ts = container_of(work, struct sitronix_ts_data, work); +#else + struct sitronix_ts_data *ts = container_of(to_delayed_work(work), struct sitronix_ts_data, work); +#endif // SITRONIX_INT_POLLING_MODE + uint8_t buffer[2+ SITRONIX_MAX_SUPPORTED_POINT * PIXEL_DATA_LENGTH_A]; + static MTD_STRUCTURE MTDStructure[SITRONIX_MAX_SUPPORTED_POINT]={{0}}; + uint8_t PixelCount = 0; + static uint8_t all_clear = 1; + + DbgMsg("%s\n", __FUNCTION__); + if(ts->suspend_state){ + goto exit_invalid_data; + } + + // get finger count + buffer[0] = FINGERS; + ret = i2c_master_send(ts->client, buffer, 1); + if (ret < 0) + printk("send finger command error (%d)\n", ret); + ret = i2c_master_recv(ts->client, buffer, 2 + ts->max_touches * ts->pixel_length); + if (ret < 0) { + printk("read finger error (%d)\n", ret); + i2cErrorCount ++; + goto exit_invalid_data; + }else{ + i2cErrorCount = 0; +#ifdef SITRONIX_FINGER_COUNT_REG_ENABLE + PixelCount = buffer[0] & FINGERS_BMSK ; +#else + for(i = 0; i < ts->max_touches; i++){ + if(buffer[2 + i * ts->pixel_length] >= 0x80) + PixelCount++; + } +#endif // SITRONIX_FINGER_COUNT_REG_ENABLE + DbgMsg("fingers = %d\n", PixelCount); + } + DbgMsg("key buffer[1] = %d\n", buffer[1]); +#ifdef SITRONIX_SENSOR_KEY + if (PixelCount == 0) + { + for(i = 0; i < SITRONIX_NUMBER_SENSOR_KEY; i++){ + if(buffer[1] & (1 << i)){ + DbgMsg("key[%d] down\n", i); + input_event(ts->input_dev, EV_KEY, sitronix_sensor_key[i], 1); + }else{ + DbgMsg("key[%d] up\n", i); + input_event(ts->input_dev, EV_KEY, sitronix_sensor_key[i], 0); + } + } + } +#endif // SITRONIX_SENSOR_KEY + + for(i = 0; i < ts->max_touches; i++){ +#ifndef SITRONIX_TOUCH_KEY + if((buffer[2 + ts->pixel_length * i] >> X_COORD_VALID_SHFT) == 1){ + MTDStructure[i].Pixel_X = ((buffer[2 + ts->pixel_length * i] & (X_COORD_H_BMSK << X_COORD_H_SHFT)) << 4) | (buffer[2 + ts->pixel_length * i + X_COORD_L]); + MTDStructure[i].Pixel_Y = ((buffer[2 + ts->pixel_length * i] & Y_COORD_H_BMSK) << 8) | (buffer[2 + ts->pixel_length * i + Y_COORD_L]); + MTDStructure[i].Current_Pressed_area = AREA_DISPLAY; + }else + MTDStructure[i].Current_Pressed_area = AREA_NONE; +#endif // SITRONIX_TOUCH_KEY + } + + if(PixelCount != 0) + { + for(i = 0; i < ts->max_touches; i++) + { +#ifndef SITRONIX_TOUCH_KEY + if(MTDStructure[i].Current_Pressed_area == AREA_DISPLAY) + { + tmp = MTDStructure[i].Pixel_X; + MTDStructure[i].Pixel_X = MTDStructure[i].Pixel_Y; + MTDStructure[i].Pixel_Y = tmp; + + MTDStructure[i].Pixel_X = MTDStructure[i].Pixel_X < 50 ? 3 + MTDStructure[i].Pixel_X : MTDStructure[i].Pixel_X*97/100; + MTDStructure[i].Pixel_Y = MTDStructure[i].Pixel_Y < 50 ? 3 + MTDStructure[i].Pixel_Y : MTDStructure[i].Pixel_Y*98/100; + input_mt_slot(ts->input_dev, i); + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, i); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 200); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, MTDStructure[i].Pixel_X); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, 480 - MTDStructure[i].Pixel_Y); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 100); + DbgMsg("lr[%d](%d, %d)+\n", i, MTDStructure[i].Pixel_X, MTDStructure[i].Pixel_Y); + }else if(MTDStructure[i].Current_Pressed_area == AREA_NONE){ + DbgMsg("lr[%d](%d, %d)-\n", i, MTDStructure[i].Pixel_X, MTDStructure[i].Pixel_Y); + input_mt_slot(ts->input_dev, i); + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1); + } + memcpy(&sitronix_ts_gMTDPreStructure[i], &MTDStructure[i], sizeof(MTD_STRUCTURE)); +#endif // SITRONIX_TOUCH_KEY + } + all_clear = 0; +#ifdef SITRONIX_INT_POLLING_MODE +#ifdef SITRONIX_MONITOR_THREAD + atomic_set(&iMonitorThreadPostpone,1); +#endif // SITRONIX_MONITOR_THREAD + schedule_delayed_work(&ts->work, msecs_to_jiffies(INT_POLLING_MODE_INTERVAL)); +#endif // SITRONIX_INT_POLLING_MODE + } + else + { + if(all_clear == 0) + { + DbgMsg("lr: all_clear\n"); + for(i = 0; i < ts->max_touches; i++) + { + input_mt_slot(ts->input_dev, i); + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1); + } + all_clear = 1; + } + else + { + DbgMsg("ignore dummy finger leave\n"); + } +#ifdef SITRONIX_INT_POLLING_MODE + if (ts->use_irq){ + sitronix_ts_irq_on = 1; + enable_irq(ts->client->irq); + } +#endif // SITRONIX_INT_POLLING_MODE + } + input_sync(ts->input_dev); + +exit_invalid_data: +#if defined(SITRONIX_LEVEL_TRIGGERED) + if (ts->use_irq){ + sitronix_ts_irq_on = 1; + enable_irq(ts->client->irq); + } +#endif // defined(SITRONIX_LEVEL_TRIGGERED) + if ((2 <= i2cErrorCount)){ + printk("I2C abnormal in work_func(), reset it!\n"); + if(sitronix_ts_gpts->reset_ic) + sitronix_ts_gpts->reset_ic(); + i2cErrorCount = 0; +#ifdef SITRONIX_MONITOR_THREAD + StatusCheckCount = 0; +#endif // SITRONIX_MONITOR_THREAD + } +} + + +static irqreturn_t sitronix_ts_irq_handler(int irq, void *dev_id) +{ + struct sitronix_ts_data *ts = dev_id; + +// DbgMsg("%s\n", __FUNCTION__); +// printk("lr:%s\n", __FUNCTION__); +#if defined(SITRONIX_LEVEL_TRIGGERED) || defined(SITRONIX_INT_POLLING_MODE) + sitronix_ts_irq_on = 0; + disable_irq_nosync(ts->client->irq); +#endif // defined(SITRONIX_LEVEL_TRIGGERED) || defined(SITRONIX_INT_POLLING_MODE) +#ifdef SITRONIX_MONITOR_THREAD + atomic_set(&iMonitorThreadPostpone,1); +#endif // SITRONIX_MONITOR_THREAD +#ifndef SITRONIX_INT_POLLING_MODE + schedule_work(&ts->work); +#else + schedule_delayed_work(&ts->work, msecs_to_jiffies(0)); +#endif // SITRONIX_INT_POLLING_MODE + return IRQ_HANDLED; +} + +static int sitronix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ +#if defined(SITRONIX_SENSOR_KEY) || defined (SITRONIX_TOUCH_KEY) + int i; +#endif // defined(SITRONIX_SENSOR_KEY) || defined (SITRONIX_TOUCH_KEY) + struct sitronix_ts_data *ts; + int ret = 0; + uint16_t max_x = 0, max_y = 0; + struct ft5x0x_platform_data *pdata; + uint8_t dev_status = 0; + + printk("lr------> %s start ------\n", __FUNCTION__); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + ret = -ENODEV; + goto err_check_functionality_failed; + } + + ts = kzalloc(sizeof(*ts), GFP_KERNEL); + if (ts == NULL) { + ret = -ENOMEM; + goto err_alloc_data_failed; + } +#ifndef SITRONIX_INT_POLLING_MODE + INIT_WORK(&ts->work, sitronix_ts_work_func); +#else + INIT_DELAYED_WORK(&ts->work, sitronix_ts_work_func); +#endif // SITRONIX_INT_POLLING_MODE + ts->client = client; + i2c_set_clientdata(client, ts); + pdata = client->dev.platform_data; +#if 0 + if(pdata->reset_ic){ + ts->reset_ic = pdata->reset_ic; + pdata->reset_ic(); + mdelay(SITRONIX_TS_CHANGE_MODE_DELAY); + } +#endif + if(pdata->init_platform_hw) + pdata->init_platform_hw(); + + sitronix_ts_gpts = ts; + + ret = sitronix_ts_get_device_status(ts, &dev_status); + if((ret < 0) || (dev_status == 0x6)) + goto err_device_info_error; + + ret = sitronix_ts_get_touch_info(ts); + if(ret < 0) + goto err_device_info_error; + + //ret = sitronix_ts_identify(ts); + //if(ret < 0) + // goto err_device_info_error; + +#ifdef SITRONIX_MONITOR_THREAD + //== Add thread to monitor chip + atomic_set(&iMonitorThreadPostpone,1); + SitronixMonitorThread = kthread_run(sitronix_ts_monitor_thread,"Sitronix","Monitorthread"); + if(IS_ERR(SitronixMonitorThread)) + SitronixMonitorThread = NULL; +#endif // SITRONIX_MONITOR_THREAD + + ts->input_dev = input_allocate_device(); + if (ts->input_dev == NULL){ + printk("Can not allocate memory for input device."); + ret = -ENOMEM; + goto err_input_dev_alloc_failed; + } + + ts->input_dev->name = "sitronix-i2c-touch-mt"; + //set_bit(EV_KEY, ts->input_dev->evbit); + //set_bit(BTN_TOUCH, ts->input_dev->keybit); + //set_bit(EV_ABS, ts->input_dev->evbit); + +#if defined(SITRONIX_SENSOR_KEY) || defined (SITRONIX_TOUCH_KEY) + ts->keyevent_input = input_allocate_device(); + if (ts->keyevent_input == NULL){ + printk("Can not allocate memory for key input device."); + ret = -ENOMEM; + goto err_input_dev_alloc_failed; + } + ts->keyevent_input->name = "sitronix-i2c-touch-key"; + //set_bit(EV_KEY, ts->keyevent_input->evbit); +#endif // defined(SITRONIX_SENSOR_KEY) || defined (SITRONIX_TOUCH_KEY) +#if defined(SITRONIX_SENSOR_KEY) + for(i = 0; i < SITRONIX_NUMBER_SENSOR_KEY; i++){ + //set_bit(sitronix_sensor_key[i], ts->keyevent_input->keybit); + } +#endif // defined(SITRONIX_SENSOR_KEY) + +#ifndef SITRONIX_TOUCH_KEY + max_x = ts->resolution_x; + max_y = ts->resolution_y; +#else +#ifdef SITRONIX_KEY_BOUNDARY_MANUAL_SPECIFY + for(i = 0; i < SITRONIX_NUMBER_TOUCH_KEY; i++){ + //set_bit(sitronix_key_array[i].code, ts->keyevent_input->keybit); + } + max_x = SITRONIX_TOUCH_RESOLUTION_X; + max_y = SITRONIX_TOUCH_RESOLUTION_Y; +#else + for(i = 0; i < SITRONIX_NUMBER_TOUCH_KEY; i++){ + sitronix_key_array[i].x_low = ((ts->resolution_x / SITRONIX_NUMBER_TOUCH_KEY ) * i ) + 15; + sitronix_key_array[i].x_high = ((ts->resolution_x / SITRONIX_NUMBER_TOUCH_KEY ) * (i + 1)) - 15; + sitronix_key_array[i].y_low = ts->resolution_y - ts->resolution_y / SCALE_KEY_HIGH_Y; + sitronix_key_array[i].y_high = ts->resolution_y; + DbgMsg("key[%d] %d, %d, %d, %d\n", i, sitronix_key_array[i].x_low, sitronix_key_array[i].x_high, sitronix_key_array[i].y_low, sitronix_key_array[i].y_high); + //set_bit(sitronix_key_array[i].code, ts->keyevent_input->keybit); + + } + max_x = ts->resolution_x; + max_y = ts->resolution_y - ts->resolution_y / SCALE_KEY_HIGH_Y; +#endif // SITRONIX_KEY_BOUNDARY_MANUAL_SPECIFY +#endif // SITRONIX_TOUCH_KEY +#if defined(SITRONIX_SENSOR_KEY) || defined (SITRONIX_TOUCH_KEY) + ret = input_register_device(ts->keyevent_input); + if(ret < 0){ + printk("Can not register key input device."); + goto err_input_register_device_failed; + } +#endif // defined(SITRONIX_SENSOR_KEY) || defined (SITRONIX_TOUCH_KEY) + + __set_bit(EV_ABS, ts->input_dev->evbit); + __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); + set_bit(ABS_MT_POSITION_X, ts->input_dev->absbit); + set_bit(ABS_MT_POSITION_Y, ts->input_dev->absbit); + set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit); + set_bit(ABS_MT_WIDTH_MAJOR, ts->input_dev->absbit); + ts->max_touches = 5; + + input_mt_init_slots(ts->input_dev, ts->max_touches); + + input_set_abs_params(ts->input_dev,ABS_MT_POSITION_X, 0, 800, 0, 0); + input_set_abs_params(ts->input_dev,ABS_MT_POSITION_Y, 0, 480, 0, 0); + input_set_abs_params(ts->input_dev,ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + + for (i = 0; i < ARRAY_SIZE(initkey_code); i++) { + input_set_capability(ts->input_dev, EV_KEY, initkey_code[i]); + } + + ret = input_register_device(ts->input_dev); + if(ret < 0){ + printk("Can not register input device."); + goto err_input_register_device_failed; + } + + ts->suspend_state = 0; + if (client->irq){ +#ifdef SITRONIX_LEVEL_TRIGGERED + ret = request_irq(client->irq, sitronix_ts_irq_handler, IRQF_TRIGGER_LOW | IRQF_DISABLED, client->name, ts); +#else + ret = request_irq(client->irq, sitronix_ts_irq_handler, IRQF_TRIGGER_FALLING | IRQF_DISABLED, client->name, ts); +#endif // SITRONIX_LEVEL_TRIGGERED + if (ret == 0){ + sitronix_ts_irq_on = 1; + ts->use_irq = 1; + }else + dev_err(&client->dev, "request_irq failed\n"); + } +#ifdef CONFIG_HAS_EARLYSUSPEND + ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + ts->early_suspend.suspend = sitronix_ts_early_suspend; + ts->early_suspend.resume = sitronix_ts_late_resume; + register_early_suspend(&ts->early_suspend); +#endif // CONFIG_HAS_EARLYSUSPEND + + printk("lr------> %s end ------\n", __FUNCTION__); + + return 0; + +err_input_register_device_failed: + input_free_device(ts->input_dev); +#if defined(SITRONIX_SENSOR_KEY) || defined (SITRONIX_TOUCH_KEY) + input_free_device(ts->keyevent_input); +#endif // defined(SITRONIX_SENSOR_KEY) || defined (SITRONIX_TOUCH_KEY) +err_input_dev_alloc_failed: + kfree(ts); +err_alloc_data_failed: +err_check_functionality_failed: +#ifdef SITRONIX_MONITOR_THREAD + if(SitronixMonitorThread){ + kthread_stop(SitronixMonitorThread); + SitronixMonitorThread = NULL; + } +#endif // SITRONIX_MONITOR_THREAD +err_device_info_error: + gpio_free(RK2928_PIN1_PA3); + gpio_free(RK2928_PIN1_PB3); + + return ret; +} + +static int sitronix_ts_remove(struct i2c_client *client) +{ + struct sitronix_ts_data *ts = i2c_get_clientdata(client); +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&ts->early_suspend); +#endif // CONFIG_HAS_EARLYSUSPEND +#ifdef SITRONIX_MONITOR_THREAD + if(SitronixMonitorThread){ + kthread_stop(SitronixMonitorThread); + SitronixMonitorThread = NULL; + } +#endif // SITRONIX_MONITOR_THREAD + if (ts->use_irq) + free_irq(client->irq, ts); + else + hrtimer_cancel(&ts->timer); + input_unregister_device(ts->input_dev); +#if defined(SITRONIX_SENSOR_KEY) || defined (SITRONIX_TOUCH_KEY) + input_unregister_device(ts->keyevent_input); +#endif // defined(SITRONIX_SENSOR_KEY) || defined (SITRONIX_TOUCH_KEY) + kfree(ts); + return 0; +} + +static int sitronix_ts_suspend(struct i2c_client *client, pm_message_t mesg) +{ + int ret = 0, i = 0; + struct sitronix_ts_data *ts = i2c_get_clientdata(client); + + DbgMsg("%s\n", __FUNCTION__); +#ifdef SITRONIX_MONITOR_THREAD + if(SitronixMonitorThread){ + kthread_stop(SitronixMonitorThread); + SitronixMonitorThread = NULL; + } + sitronix_ts_delay_monitor_thread_start = DELAY_MONITOR_THREAD_START_RESUME; +#endif // SITRONIX_MONITOR_THREAD + if(ts->use_irq){ + sitronix_ts_irq_on = 0; + disable_irq_nosync(ts->client->irq); + } + ts->suspend_state = 1; + + ret = sitronix_ts_set_powerdown_bit(ts, 1); +#ifdef SITRONIX_WAKE_UP_TOUCH_BY_INT + gpio_direction_output(irq_to_gpio(client->irq), 1); +#endif // SITRONIX_WAKE_UP_TOUCH_BY_INT + DbgMsg("%s return\n", __FUNCTION__); + + for(i = 0; i < ts->max_touches; i++) + { + input_mt_slot(ts->input_dev, i); + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1); + } + input_sync(ts->input_dev); + + return 0; +} + +static int sitronix_ts_resume(struct i2c_client *client) +{ +#ifdef SITRONIX_WAKE_UP_TOUCH_BY_INT + unsigned int gpio; +#else + int ret; +#endif // SITRONIX_WAKE_UP_TOUCH_BY_INT + struct sitronix_ts_data *ts = i2c_get_clientdata(client); + + DbgMsg("%s\n", __FUNCTION__); + +#ifdef SITRONIX_WAKE_UP_TOUCH_BY_INT + gpio = irq_to_gpio(client->irq); + gpio_set_value(gpio, 0); + gpio_direction_input(gpio); +#else + ret = sitronix_ts_set_powerdown_bit(ts, 0); +#endif // SITRONIX_WAKE_UP_TOUCH_BY_INT + + ts->suspend_state = 0; + if(ts->use_irq){ + sitronix_ts_irq_on = 1; + enable_irq(ts->client->irq); + } +#ifdef SITRONIX_MONITOR_THREAD + atomic_set(&iMonitorThreadPostpone,1); + SitronixMonitorThread = kthread_run(sitronix_ts_monitor_thread,"Sitronix","Monitorthread"); + if(IS_ERR(SitronixMonitorThread)) + SitronixMonitorThread = NULL; +#endif // SITRONIX_MONITOR_THREAD + DbgMsg("%s return\n", __FUNCTION__); + + return 0; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void sitronix_ts_early_suspend(struct early_suspend *h) +{ + struct sitronix_ts_data *ts; + DbgMsg("%s\n", __FUNCTION__); + ts = container_of(h, struct sitronix_ts_data, early_suspend); + sitronix_ts_suspend(ts->client, PMSG_SUSPEND); +} + +static void sitronix_ts_late_resume(struct early_suspend *h) +{ + struct sitronix_ts_data *ts; + DbgMsg("%s\n", __FUNCTION__); + ts = container_of(h, struct sitronix_ts_data, early_suspend); + sitronix_ts_resume(ts->client); +} +#endif // CONFIG_HAS_EARLYSUSPEND + +static const struct i2c_device_id sitronix_ts_id[] = { + { SITRONIX_I2C_TOUCH_DRV_NAME, 0 }, + { } +}; + +static struct i2c_driver sitronix_ts_driver = { + .probe = sitronix_ts_probe, + .remove = sitronix_ts_remove, + .id_table = sitronix_ts_id, + .driver = { + .name = SITRONIX_I2C_TOUCH_DRV_NAME, + }, +}; + +#ifdef SITRONIX_FW_UPGRADE_FEATURE +static struct file_operations nc_fops = { + .owner = THIS_MODULE, + .write = sitronix_write, + .read = sitronix_read, + .open = sitronix_open, + .unlocked_ioctl = sitronix_ioctl, + .release = sitronix_release, +}; +#endif // SITRONIX_FW_UPGRADE_FEATURE + +static int __devinit sitronix_ts_init(void) +{ +#ifdef SITRONIX_FW_UPGRADE_FEATURE + int result; + int err = 0; +#endif // SITRONIX_FW_UPGRADE_FEATURE + printk("Sitronix touch driver %d.%d.%d\n", DRIVER_MAJOR, DRIVER_MINOR, DRIVER_PATCHLEVEL); + printk("Release date: %s\n", DRIVER_DATE); +#ifdef SITRONIX_FW_UPGRADE_FEATURE + dev_t devno = MKDEV(sitronix_major, 0); + result = alloc_chrdev_region(&devno, 0, 1, SITRONIX_I2C_TOUCH_DEV_NAME); + if(result < 0){ + printk("fail to allocate chrdev (%d) \n", result); + return 0; + } + sitronix_major = MAJOR(devno); + cdev_init(&sitronix_cdev, &nc_fops); + sitronix_cdev.owner = THIS_MODULE; + sitronix_cdev.ops = &nc_fops; + err = cdev_add(&sitronix_cdev, devno, 1); + if(err){ + printk("fail to add cdev (%d) \n", err); + return 0; + } + + sitronix_class = class_create(THIS_MODULE, SITRONIX_I2C_TOUCH_DEV_NAME); + if (IS_ERR(sitronix_class)) { + result = PTR_ERR(sitronix_class); + unregister_chrdev(sitronix_major, SITRONIX_I2C_TOUCH_DEV_NAME); + printk("fail to create class (%d) \n", result); + return result; + } + device_create(sitronix_class, NULL, MKDEV(sitronix_major, 0), NULL, SITRONIX_I2C_TOUCH_DEV_NAME); +#endif // SITRONIX_FW_UPGRADE_FEATURE + return i2c_add_driver(&sitronix_ts_driver); +} + +static void __exit sitronix_ts_exit(void) +{ +#ifdef SITRONIX_FW_UPGRADE_FEATURE + dev_t dev_id = MKDEV(sitronix_major, 0); +#endif // SITRONIX_FW_UPGRADE_FEATURE + i2c_del_driver(&sitronix_ts_driver); +#ifdef SITRONIX_FW_UPGRADE_FEATURE + cdev_del(&sitronix_cdev); + + device_destroy(sitronix_class, dev_id); //delete device node under /dev + class_destroy(sitronix_class); //delete class created by us + unregister_chrdev_region(dev_id, 1); +#endif // SITRONIX_FW_UPGRADE_FEATURE +} + +module_init(sitronix_ts_init); +module_exit(sitronix_ts_exit); + +MODULE_DESCRIPTION("Sitronix Multi-Touch Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/sitronix_ts_a720.h b/drivers/input/touchscreen/sitronix_ts_a720.h new file mode 100755 index 000000000000..cb651c1027d1 --- /dev/null +++ b/drivers/input/touchscreen/sitronix_ts_a720.h @@ -0,0 +1,175 @@ +/* + * drivers/input/touchscreen/sitronix_i2c_touch.h + * + * Touchscreen driver for Sitronix + * + * Copyright (C) 2011 Sitronix Technology Co., Ltd. + * Rudy Huang + */ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#ifndef __SITRONIX_I2C_TOUCH_h +#define __SITRONIX_I2C_TOUCH_h + +#include /* needed for the _IOW etc stuff used later */ + +#define SITRONIX_TOUCH_DRIVER_VERSION 0x03 +#define SITRONIX_MAX_SUPPORTED_POINT 5 +#define SITRONIX_I2C_TOUCH_DRV_NAME "sitronix" +#define SITRONIX_I2C_TOUCH_DEV_NAME "sitronixDev" + +//#define SITRONIX_WAKE_UP_TOUCH_BY_INT + +//#define SITRONIX_MONITOR_THREAD +#define DELAY_MONITOR_THREAD_START_PROBE 10000 +#define DELAY_MONITOR_THREAD_START_RESUME 3000 +#define SITRONIX_FW_UPGRADE_FEATURE +#define SITRONIX_LEVEL_TRIGGERED +// When enable_irq() is invoked, irq will be sent once while INT is not triggered if CONFIG_HARDIRQS_SW_RESEND is set. +// This behavior is implemented by linux kernel, it is used to prevent irq from losting when irq is edge-triggered mode. +#ifndef SITRONIX_LEVEL_TRIGGERED +#define SITRONIX_INT_POLLING_MODE +#define INT_POLLING_MODE_INTERVAL 14 +#endif // SITRONIX_LEVEL_TRIGGERED +#define SITRONIX_FINGER_COUNT_REG_ENABLE + +//#define EnableDbgMsg 0 +//#define EnableUpgradeMsg 1 + +#ifdef EnableDbgMsg +#define DbgMsg(arg...) printk(arg) +#else +#define DbgMsg(arg...) +#endif + +#ifdef EnableUpgradeMsg +#define UpgradeMsg(arg...) printk(arg) +#else +#define UpgradeMsg(arg...) +#endif + +typedef enum{ + FIRMWARE_VERSION, + STATUS_REG, + DEVICE_CONTROL_REG, + TIMEOUT_TO_IDLE_REG, + XY_RESOLUTION_HIGH, + X_RESOLUTION_LOW, + Y_RESOLUTION_LOW, + FIRMWARE_REVISION_3 = 0x0C, + FIRMWARE_REVISION_2, + FIRMWARE_REVISION_1, + FIRMWARE_REVISION_0, + FINGERS, + KEYS_REG, + XY0_COORD_H, + X0_COORD_L, + Y0_COORD_L, + I2C_PROTOCOL = 0x3E, + MAX_NUM_TOUCHES, + DATA_0_HIGH, + DATA_0_LOW, + + PAGE_REG = 0xff, +}RegisterOffset; + +#define SITRONIX_TS_CHANGE_MODE_DELAY 150 + +typedef enum{ + XY_COORD_H, + X_COORD_L, + Y_COORD_L, + PIXEL_DATA_LENGTH_B, + PIXEL_DATA_LENGTH_A, +}PIXEL_DATA_FORMAT; + +#define X_RES_H_SHFT 4 +#define X_RES_H_BMSK 0xf +#define Y_RES_H_SHFT 0 +#define Y_RES_H_BMSK 0xf +#define FINGERS_SHFT 0 +#define FINGERS_BMSK 0xf +#define X_COORD_VALID_SHFT 7 +#define X_COORD_VALID_BMSK 0x1 +#define X_COORD_H_SHFT 4 +#define X_COORD_H_BMSK 0x7 +#define Y_COORD_H_SHFT 0 +#define Y_COORD_H_BMSK 0x7 + +typedef enum{ + SITRONIX_A_TYPE = 1, + SITRONIX_B_TYPE, +}I2C_PROTOCOL_TYPE; + +#define I2C_PROTOCOL_SHFT 0x0 +#define I2C_PROTOCOL_BMSK 0x3 + +#define SMT_IOC_MAGIC 0xf1 + +enum{ + SMT_GET_DRIVER_REVISION = 1, + SMT_GET_FW_REVISION, + SMT_ENABLE_IRQ, + SMT_DISABLE_IRQ, + SMT_RESUME, + SMT_SUSPEND, + SMT_HW_RESET, + SMT_IOC_MAXNR, +}; + +#define IOCTL_SMT_GET_DRIVER_REVISION _IOC(_IOC_READ, SMT_IOC_MAGIC, SMT_GET_DRIVER_REVISION, 1) +#define IOCTL_SMT_GET_FW_REVISION _IOC(_IOC_READ, SMT_IOC_MAGIC, SMT_GET_FW_REVISION, 4) +#define IOCTL_SMT_ENABLE_IRQ _IOC(_IOC_NONE, SMT_IOC_MAGIC, SMT_ENABLE_IRQ, 0) +#define IOCTL_SMT_DISABLE_IRQ _IOC(_IOC_NONE, SMT_IOC_MAGIC, SMT_DISABLE_IRQ, 0) +#define IOCTL_SMT_RESUME _IOC(_IOC_NONE, SMT_IOC_MAGIC, SMT_RESUME, 0) +#define IOCTL_SMT_SUSPEND _IOC(_IOC_NONE, SMT_IOC_MAGIC, SMT_SUSPEND, 0) +#define IOCTL_SMT_HW_RESET _IOC(_IOC_NONE, SMT_IOC_MAGIC, SMT_HW_RESET, 0) + +#define SITRONIX_SENSOR_KEY +//#define SITRONIX_TOUCH_KEY +//#define SITRONIX_KEY_BOUNDARY_MANUAL_SPECIFY + +typedef struct _tag_MTD_STRUCTURE{ + u16 Pixel_X; + u16 Pixel_Y; + u8 First_Pressed_area; /* 0: no press; 1: display; 2: touch key */ + u8 Current_Pressed_area; /* 0: no press; 1: display; 2: touch key */ + unsigned int First_key_index; + unsigned int Current_key_index; +}MTD_STRUCTURE, *PMTD_STRUCTURE; + +#ifndef SITRONIX_TOUCH_KEY +enum{ + AREA_NONE, + AREA_DISPLAY, +}; +#else +enum{ + AREA_NONE, + AREA_DISPLAY, + AREA_KEY, + AREA_INVALID, +}; + +struct sitronix_AA_key{ + int x_low; + int x_high; + int y_low; + int y_high; + unsigned int code; +}; +#endif // SITRONIX_TOUCH_KEY + +struct sitronix_i2c_touch_platform_data { + uint32_t version; /* Use this entry for panels with */ + /* (major << 8 | minor) version or above. */ + /* If non-zero another array entry follows */ + void (*reset_ic)(void); +}; + +#endif // __SITRONIX_I2C_TOUCH_h From ebb93cff36c953ba0eebe4b9c6a8d71e54b2be4d Mon Sep 17 00:00:00 2001 From: chenxing Date: Mon, 20 Aug 2012 14:22:55 +0800 Subject: [PATCH 241/261] rk2928:sdk: codec pll for sclk_lcdc only, aclk_vio_pre need yxj fixed, move other clks to general pll --- arch/arm/mach-rk2928/clock_data.c | 192 ++++++++++++++++++------------ 1 file changed, 118 insertions(+), 74 deletions(-) diff --git a/arch/arm/mach-rk2928/clock_data.c b/arch/arm/mach-rk2928/clock_data.c index a1c3440bdbd4..1a734cdb94a4 100644 --- a/arch/arm/mach-rk2928/clock_data.c +++ b/arch/arm/mach-rk2928/clock_data.c @@ -291,17 +291,18 @@ static unsigned long pll_clk_recalc(u8 pll_id, unsigned long parent_rate) if (PLLS_IN_NORM(pll_id)) { u32 pll_con0 = cru_readl(PLL_CONS(pll_id, 0)); u32 pll_con1 = cru_readl(PLL_CONS(pll_id, 1)); + u32 pll_con2 = cru_readl(PLL_CONS(pll_id, 2)); //integer mode rate64 = (u64)parent_rate * PLL_GET_FBDIV(pll_con0); do_div(rate64, PLL_GET_REFDIV(pll_con1)); if (FRAC_MODE == dsmp) { //fractional mode - frac_rate64 = (u64)parent_rate * PLL_GET_FRAC(pll_con1); + frac_rate64 = (u64)parent_rate * PLL_GET_FRAC(pll_con2); do_div(frac_rate64, PLL_GET_REFDIV(pll_con1)); rate64 += frac_rate64 >> 24; - CLKDATA_DBG("%s id=%d frac_rate=%llu(0x%08x/2^24) by pass mode\n", - __func__, pll_id, frac_rate64, PLL_GET_FRAC(pll_con1)); + CLKDATA_DBG("%s id=%d frac_rate=%llu(%08x/2^24) by pass mode\n", + __func__, pll_id, frac_rate64 >> 24, PLL_GET_FRAC(pll_con2)); } do_div(rate64, PLL_GET_POSTDIV1(pll_con0)); do_div(rate64, PLL_GET_POSTDIV2(pll_con1)); @@ -322,7 +323,8 @@ static unsigned long plls_clk_recalc(struct clk *clk) /************************clk set rate*********************************/ static int clksel_set_rate_freediv(struct clk *clk, unsigned long rate) { - u32 div; + u32 div = 0; + for (div = 0; div < clk->div_max; div++) { u32 new_rate = clk->parent->rate / (div + 1); if (new_rate <= rate) { @@ -700,30 +702,55 @@ static int pll_clk_get_set(unsigned long fin_hz,unsigned long fout_hz, { // FIXME set postdiv1/2 always 1 u32 gcd; - + u64 fin_64, frac_64; + u32 f_frac; if(!fin_hz || !fout_hz || fout_hz == fin_hz) return -1; - fin_hz /= MHZ; - fout_hz /= MHZ; - gcd = clk_gcd(fin_hz, fout_hz); - *refdiv = fin_hz / gcd; - *fbdiv = fout_hz / gcd; - *postdiv1 = 1; - *postdiv2 = 1; + if (fin_hz / MHZ * MHZ == fin_hz && fout_hz /MHZ * MHZ == fout_hz) { + fin_hz /= MHZ; + fout_hz /= MHZ; + gcd = clk_gcd(fin_hz, fout_hz); + *refdiv = fin_hz / gcd; + *fbdiv = fout_hz / gcd; + *postdiv1 = 1; + *postdiv2 = 1; - *frac = 0; + *frac = 0; - CLKDATA_DBG("fin=%lu,fout=%lu,gcd=%u,refdiv=%u,fbdiv=%u,postdiv1=%u,postdiv2=%u,frac=%u\n", - fin_hz, fout_hz, gcd, *refdiv, *fbdiv, *postdiv1, *postdiv2, *frac); + CLKDATA_DBG("fin=%lu,fout=%lu,gcd=%u,refdiv=%u,fbdiv=%u,postdiv1=%u,postdiv2=%u,frac=%u\n", + fin_hz, fout_hz, gcd, *refdiv, *fbdiv, *postdiv1, *postdiv2, *frac); + } else { + CLKDATA_DBG("******frac div running, fin_hz=%lu, fout_hz=%lu, fin_mhz=%lu, fout_mhz=%lu\n", + fin_hz, fout_hz, fin_hz / MHZ * MHZ, fout_hz / MHZ * MHZ); + gcd = clk_gcd(fin_hz / MHZ, fout_hz / MHZ); + *refdiv = fin_hz / MHZ / gcd; + *fbdiv = fout_hz / MHZ / gcd; + *postdiv1 = 1; + *postdiv2 = 1; + *frac = 0; + + f_frac = (fout_hz % MHZ); + fin_64 = fin_hz; + do_div(fin_64, (u64)*refdiv); + frac_64 = (u64)f_frac << 24; + do_div(frac_64, fin_64); + *frac = (u32) frac_64; + CLKDATA_DBG("frac_64=%llx, frac=%u\n", frac_64, *frac); + } return 0; } static int pll_set_con(u8 id, u32 refdiv, u32 fbdiv, u32 postdiv1, u32 postdiv2, u32 frac) { struct pll_clk_set temp_clk_set; - temp_clk_set.pllcon0 = PLL_SET_FBDIV(fbdiv) | PLL_SET_POSTDIV1(postdiv1) ; + temp_clk_set.pllcon0 = PLL_SET_FBDIV(fbdiv) | PLL_SET_POSTDIV1(postdiv1); temp_clk_set.pllcon1 = PLL_SET_REFDIV(refdiv) | PLL_SET_POSTDIV2(postdiv2); + if (frac != 0) { + temp_clk_set.pllcon1 |= PLL_SET_DSMPD(0); + } else { + temp_clk_set.pllcon1 |= PLL_SET_DSMPD(1); + } temp_clk_set.pllcon2 = PLL_SET_FRAC(frac); temp_clk_set.rst_dly = 1500; CLKDATA_DBG("setting....\n"); @@ -836,6 +863,7 @@ static int cpll_clk_set_rate(struct clk *clk, unsigned long rate) CLKDATA_DBG("%s get fin=%lu, fout=%lu, rate=%lu, refdiv=%u, fbdiv=%u, postdiv1=%u, postdiv2=%u", __func__, fin_hz, fout_hz, rate, refdiv, fbdiv, postdiv1, postdiv2); pll_set_con(pll_data->id, refdiv, fbdiv, postdiv1, postdiv2, frac); + } CLKDATA_DBG("setting OK\n"); @@ -1132,7 +1160,8 @@ static struct clk aclk_vepu = { .gate_idx = CLK_GATE_ACLK_VEPU_SRC, .recalc = clksel_recalc_div, .clksel_con = CRU_CLKSELS_CON(32), - .set_rate = clkset_rate_freediv_autosel_parents, + //.set_rate = clkset_rate_freediv_autosel_parents, + .set_rate = clksel_set_rate_freediv, CRU_DIV_SET(0x1f, 0, 32), CRU_SRC_SET(0x1, 7), CRU_PARENTS_SET(clk_aclk_vepu_parents), @@ -1143,7 +1172,8 @@ static struct clk aclk_vdpu = { .mode = gate_mode, .gate_idx = CLK_GATE_ACLK_VDPU_SRC, .recalc = clksel_recalc_div, - .set_rate = clkset_rate_freediv_autosel_parents, + //.set_rate = clkset_rate_freediv_autosel_parents, + .set_rate = clksel_set_rate_freediv, .clksel_con = CRU_CLKSELS_CON(32), CRU_DIV_SET(0x1f, 8, 32), CRU_SRC_SET(0x1, 15), @@ -1169,7 +1199,7 @@ static struct clk hclk_vdpu = { static struct clk *clk_aclk_vio_pre_parents[] = SELECT_FROM_2PLLS_CG; static struct clk aclk_vio_pre = { .name = "aclk_vio_pre", - .parent = &clk_cpu_div, + .parent = &general_pll_clk, .mode = gate_mode, .gate_idx = CLK_GATE_ACLK_VIO_SRC, .recalc = clksel_recalc_div, @@ -1374,6 +1404,17 @@ static struct clk clk_emmc_drv = { #endif /****************lcdc*******************/ // DO NOT USE ARM_PLL +static int sclk_lcdc_set_rate(struct clk *clk, unsigned long rate) +{ + int ret = 0; + struct clk *parent; + + CLKDATA_DBG("enter %s clk=%s, rate=%lu\n", __func__, clk->name, rate); + parent = clk->parent; + ret = clk_set_rate_nolock(parent, rate); + set_cru_bits_w_msk(0, clk->div_mask, clk->div_shift, clk->clksel_con); + return ret; +} static struct clk *dclk_lcdc_parents[] = {&codec_pll_clk, &general_pll_clk}; static struct clk dclk_lcdc = { .name = "dclk_lcdc", @@ -1381,7 +1422,8 @@ static struct clk dclk_lcdc = { .mode = gate_mode, .gate_idx = CLK_GATE_DCLK_LCDC0_SRC, .recalc = clksel_recalc_div, - .set_rate = clkset_rate_freediv_autosel_parents, + //.set_rate = clkset_rate_freediv_autosel_parents, + .set_rate = clksel_set_rate_freediv, .clksel_con = CRU_CLKSELS_CON(27), CRU_DIV_SET(0xff, 8, 256), CRU_SRC_SET(0x3, 0), @@ -1394,7 +1436,8 @@ static struct clk sclk_lcdc = { .mode = gate_mode, .gate_idx = CLK_GATE_SCLK_LCDC_SRC, .recalc = clksel_recalc_div, - .set_rate = clkset_rate_freediv_autosel_parents, + //.set_rate = clkset_rate_freediv_autosel_parents, + .set_rate = sclk_lcdc_set_rate, .clksel_con = CRU_CLKSELS_CON(28), CRU_DIV_SET(0xff, 8, 256), CRU_SRC_SET(0x1, 0), @@ -1438,7 +1481,8 @@ static struct clk clk_cif_out_div = { .mode = gate_mode, .gate_idx = CLK_GATE_CIF_OUT_SRC, .recalc = clksel_recalc_div, - .set_rate = clkset_rate_freediv_autosel_parents, + //.set_rate = clkset_rate_freediv_autosel_parents, + .set_rate = clksel_set_rate_freediv, .clksel_con = CRU_CLKSELS_CON(29), CRU_SRC_SET(0x1, 0), CRU_DIV_SET(0x1f, 1, 32), @@ -1625,7 +1669,8 @@ static struct clk clk_gpu_pre = { .mode = gate_mode, .gate_idx = CLK_GATE_GPU_PRE, .recalc = clksel_recalc_div, - .set_rate = clkset_rate_freediv_autosel_parents, + //.set_rate = clkset_rate_freediv_autosel_parents, + .set_rate = clksel_set_rate_freediv, .round_rate = clk_freediv_round_autosel_parents_rate, .clksel_con = CRU_CLKSELS_CON(34), CRU_SRC_SET(0x1, 8), @@ -1824,8 +1869,7 @@ GATE_CLK(aclk_dma2, aclk_periph_pre, ACLK_DMAC2); GATE_CLK(aclk_peri_niu, aclk_periph_pre, ACLK_PERI_NIU); GATE_CLK(aclk_cpu_peri, aclk_periph_pre, ACLK_CPU_PERI); GATE_CLK(aclk_peri_axi_matrix, aclk_periph_pre, ACLK_PERI_AXI_MATRIX); -//FIXME -//GATE_CLK(aclk_gps, aclk_periph_pre, ACLK_GPS); +GATE_CLK(aclk_gps, aclk_periph_pre, ACLK_GPS); /*************************hclk_periph***********************/ GATE_CLK(hclk_peri_axi_matrix, hclk_periph_pre, HCLK_PERI_AXI_MATRIX); @@ -2094,8 +2138,7 @@ static struct clk_lookup clks[] = { CLK_GATE_NODEV(aclk_peri_niu), CLK_GATE_NODEV(aclk_cpu_peri), CLK_GATE_NODEV(aclk_peri_axi_matrix), - //FIXME - //CLK_GATE_NODEV(aclk_gps), + CLK_GATE_NODEV(aclk_gps), CLK_GATE_NODEV(hclk_peri_axi_matrix), CLK_GATE_NODEV(hclk_peri_ahb_arbi), @@ -2359,11 +2402,11 @@ struct clk_dump_ops dump_ops={ static void periph_clk_set_init(void) { unsigned long aclk_p, hclk_p, pclk_p; - unsigned long ppll_rate=general_pll_clk.rate; + unsigned long gpll_rate=general_pll_clk.rate; //aclk 148.5 /* general pll */ - switch (ppll_rate) { + switch (gpll_rate) { case 148500* KHZ: aclk_p = 148500*KHZ; hclk_p = aclk_p>>1; @@ -2375,13 +2418,13 @@ static void periph_clk_set_init(void) pclk_p = aclk_p>>2; case 297 * MHZ: - aclk_p = ppll_rate>>1; - hclk_p = aclk_p>>0; + aclk_p = gpll_rate>>0; + hclk_p = aclk_p>>1; pclk_p = aclk_p>>1; break; case 300 * MHZ: - aclk_p = ppll_rate>>1; + aclk_p = gpll_rate>>1; hclk_p = aclk_p>>0; pclk_p = aclk_p>>1; break; @@ -2391,10 +2434,10 @@ static void periph_clk_set_init(void) pclk_p = 75 * MHZ; break; } - clk_set_parent_nolock(&aclk_periph_pre, &general_pll_clk); - clk_set_rate_nolock(&aclk_periph_pre, aclk_p); - clk_set_rate_nolock(&hclk_periph_pre, hclk_p); - clk_set_rate_nolock(&pclk_periph_pre, pclk_p); + clk_set_parent_nolock(&peri_aclk, &general_pll_clk); + clk_set_rate_nolock(&peri_aclk, aclk_p); + clk_set_rate_nolock(&peri_hclk, hclk_p); + clk_set_rate_nolock(&peri_pclk, pclk_p); } @@ -2408,37 +2451,32 @@ void rk2928_clock_common_i2s_init(void) unsigned long i2s_rate; //struct clk *max_clk,*min_clk; //20 times - if(rk2928_clock_flags&CLK_FLG_MAX_I2S_49152KHZ) - { - i2s_rate=49152000; - }else if(rk2928_clock_flags&CLK_FLG_MAX_I2S_24576KHZ) - { - i2s_rate=24576000; - } - else if(rk2928_clock_flags&CLK_FLG_MAX_I2S_22579_2KHZ) - { - i2s_rate=22579000; - } - else if(rk2928_clock_flags&CLK_FLG_MAX_I2S_12288KHZ) - { - i2s_rate=12288000; - } - else - { - i2s_rate=49152000; + if(rk2928_clock_flags & CLK_FLG_MAX_I2S_49152KHZ) { + i2s_rate = 49152000; + + } else if(rk2928_clock_flags & CLK_FLG_MAX_I2S_24576KHZ) { + i2s_rate = 24576000; + + } else if(rk2928_clock_flags & CLK_FLG_MAX_I2S_22579_2KHZ) { + i2s_rate = 22579000; + + } else if(rk2928_clock_flags & CLK_FLG_MAX_I2S_12288KHZ) { + i2s_rate = 12288000; + + } else { + i2s_rate = 49152000; } - if(((i2s_rate*20)<=general_pll_clk.rate)||!(general_pll_clk.rate%i2s_rate)) - { + if(((i2s_rate * 20) <= general_pll_clk.rate) + || !(general_pll_clk.rate % i2s_rate)) { clk_set_parent_nolock(&clk_i2s_pll, &general_pll_clk); - } - else if(((i2s_rate*20)<=codec_pll_clk.rate)||!(codec_pll_clk.rate%i2s_rate)) - { + + } else if(((i2s_rate * 20) <= codec_pll_clk.rate) + || !(codec_pll_clk.rate % i2s_rate)) { clk_set_parent_nolock(&clk_i2s_pll, &codec_pll_clk); - } - else - { - if(general_pll_clk.rate>codec_pll_clk.rate) + + } else { + if(general_pll_clk.rate > codec_pll_clk.rate) clk_set_parent_nolock(&clk_i2s_pll, &general_pll_clk); else clk_set_parent_nolock(&clk_i2s_pll, &codec_pll_clk); @@ -2447,9 +2485,8 @@ void rk2928_clock_common_i2s_init(void) } static void __init rk2928_clock_common_init(unsigned long gpll_rate,unsigned long cpll_rate) { - CLKDATA_DBG("ENTER %s\n", __func__); - clk_set_rate_nolock(&clk_core_pre, 600 * MHZ);//816? + clk_set_rate_nolock(&clk_core_pre, 816 * MHZ);//816 //general clk_set_rate_nolock(&general_pll_clk, gpll_rate); //code pll @@ -2478,7 +2515,6 @@ static void __init rk2928_clock_common_init(unsigned long gpll_rate,unsigned lon clk_set_parent_nolock(&clk_mac_pll_div, &ddr_pll_clk); else CRU_PRINTK_ERR("mac can't get 50mhz\n"); -#endif //hsadc //auto pll sel //clk_set_parent_nolock(&clk_hsadc_pll_div, &general_pll_clk); @@ -2488,27 +2524,35 @@ static void __init rk2928_clock_common_init(unsigned long gpll_rate,unsigned lon //lcdc0 lcd auto sel pll //clk_set_parent_nolock(&dclk_lcdc0_div, &general_pll_clk); +#endif //cif clk_set_parent_nolock(&clk_cif_out_div, &general_pll_clk); + // FIXME yxj this plase cause display unusual + //clk_set_parent_nolock(&aclk_vio_pre, &general_pll_clk); + //axi lcdc auto sel //clk_set_parent_nolock(&aclk_lcdc0, &general_pll_clk); //clk_set_parent_nolock(&aclk_lcdc1, &general_pll_clk); // FIXME -#if 0 - clk_set_rate_nolock(&aclk_lcdc0_ipp_parent, 300*MHZ); - clk_set_rate_nolock(&aclk_lcdc1_rga_parent, 300*MHZ); -#endif + + clk_set_rate_nolock(&aclk_vio_pre, 300*MHZ); //axi vepu auto sel - //clk_set_parent_nolock(&aclk_vepu, &general_pll_clk); - //clk_set_parent_nolock(&aclk_vdpu, &general_pll_clk); + clk_set_parent_nolock(&aclk_vepu, &general_pll_clk); + clk_set_parent_nolock(&aclk_vdpu, &general_pll_clk); clk_set_rate_nolock(&aclk_vepu, 300*MHZ); clk_set_rate_nolock(&aclk_vdpu, 300*MHZ); //gpu auto sel - //clk_set_parent_nolock(&clk_gpu, &general_pll_clk); - // + clk_set_parent_nolock(&clk_gpu_pre, &general_pll_clk); + + clk_set_parent_nolock(&clk_cpu_div, &general_pll_clk); + + clk_set_parent_nolock(&clk_sdmmc0, &general_pll_clk); + clk_set_parent_nolock(&clk_sdio, &general_pll_clk); + clk_set_parent_nolock(&clk_emmc, &general_pll_clk); + clk_set_parent_nolock(&dclk_lcdc, &general_pll_clk); } void __init _rk2928_clock_data_init(unsigned long gpll,unsigned long cpll,int flags) { From e85be8c2be54e911099abe07d6374d6642ce8836 Mon Sep 17 00:00:00 2001 From: gwl Date: Mon, 20 Aug 2012 14:50:02 +0800 Subject: [PATCH 242/261] add rtl8188eu to rkwifi_sys_iface.c --- drivers/net/wireless/wifi_sys/rkwifi_sys_iface.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/wifi_sys/rkwifi_sys_iface.c b/drivers/net/wireless/wifi_sys/rkwifi_sys_iface.c index 8963eae6c6ec..593d078d4550 100644 --- a/drivers/net/wireless/wifi_sys/rkwifi_sys_iface.c +++ b/drivers/net/wireless/wifi_sys/rkwifi_sys_iface.c @@ -19,8 +19,13 @@ static ssize_t wifi_chip_read(struct class *cls, char *_buf) #endif #ifdef CONFIG_RTL8192CU - count = sprintf(_buf, "%s", "RTL8188"); - printk("Current WiFi chip is RTL8188.\n"); + count = sprintf(_buf, "%s", "RTL8188CU"); + printk("Current WiFi chip is RTL8188CU.\n"); +#endif + +#ifdef CONFIG_RTL8188EU + count = sprintf(_buf, "%s", "RTL8188EU"); + printk("Current WiFi chip is RTL8188EU.\n"); #endif #ifdef CONFIG_BCM4330 From 82a500834e1ed52904732f2c5dbb28b415e15e56 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 20 Aug 2012 16:18:30 +0800 Subject: [PATCH 243/261] camera rk30: add scale by arm,rga and pp. --- arch/arm/mach-rk30/include/mach/rk30_camera.h | 18 + drivers/media/video/rk30_camera_oneframe.c | 667 ++++++++++++++++-- 2 files changed, 615 insertions(+), 70 deletions(-) diff --git a/arch/arm/mach-rk30/include/mach/rk30_camera.h b/arch/arm/mach-rk30/include/mach/rk30_camera.h index 85391efff2e3..b8539fe86357 100755 --- a/arch/arm/mach-rk30/include/mach/rk30_camera.h +++ b/arch/arm/mach-rk30/include/mach/rk30_camera.h @@ -35,5 +35,23 @@ #include +#define CONFIG_CAMERA_SCALE_CROP_MACHINE RK_CAM_SCALE_CROP_IPP + +#if (CONFIG_CAMERA_SCALE_CROP_MACHINE==RK_CAM_SCALE_CROP_ARM) + #define CAMERA_SCALE_CROP_MACHINE "arm" +#elif (CONFIG_CAMERA_SCALE_CROP_MACHINE==RK_CAM_SCALE_CROP_IPP) + #define CAMERA_SCALE_CROP_MACHINE "ipp" +#elif (CONFIG_CAMERA_SCALE_CROP_MACHINE==RK_CAM_SCALE_CROP_RGA) + #define CAMERA_SCALE_CROP_MACHINE "rga" +#elif (CONFIG_CAMERA_SCALE_CROP_MACHINE==RK_CAM_SCALE_CROP_PP) + #define CAMERA_SCALE_CROP_MACHINE "pp" +#endif + +#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_ARM) + #define CAMERA_VIDEOBUF_ARM_ACCESS 1 +#else + #define CAMERA_VIDEOBUF_ARM_ACCESS 0 +#endif + #endif diff --git a/drivers/media/video/rk30_camera_oneframe.c b/drivers/media/video/rk30_camera_oneframe.c index b77d345e94ce..768760ed7b7c 100755 --- a/drivers/media/video/rk30_camera_oneframe.c +++ b/drivers/media/video/rk30_camera_oneframe.c @@ -38,7 +38,8 @@ #include #include #include - +#include +#include "../../video/rockchip/rga/rga.h" #if defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK31) #include #include @@ -47,8 +48,9 @@ #if defined(CONFIG_ARCH_RK2928) #include +#include "../../video/rockchip/rga/rga.h" #endif - +#include static int debug ; module_param(debug, int, S_IRUGO|S_IWUSR); @@ -230,6 +232,7 @@ module_param(debug, int, S_IRUGO|S_IWUSR); *v0.x.e: fix bugs of early suspend when display_pd is closed. *v0.x.f: fix calculate ipp memory size is enough or not in try_fmt function; *v0.x.11: fix struct rk_camera_work may be reentrant +*v0.x.13: add scale by arm,rga and pp. */ #define RK_CAM_VERSION_CODE KERNEL_VERSION(0, 2, 0x11) @@ -305,8 +308,17 @@ struct rk_camera_zoominfo struct semaphore sem; struct v4l2_crop a; int vir_width; + int vir_height; int zoom_rate; }; +#if CAMERA_VIDEOBUF_ARM_ACCESS +struct rk29_camera_vbinfo +{ + unsigned int phy_addr; + void __iomem *vir_addr; + unsigned int size; +}; +#endif struct rk_camera_timer{ struct rk_camera_dev *pcdev; struct hrtimer timer; @@ -337,10 +349,14 @@ struct rk_camera_dev unsigned int pixfmt; //for ipp unsigned int vipmem_phybase; + void __iomem *vipmem_virbase; unsigned int vipmem_size; unsigned int vipmem_bsize; - - int host_width; //croped size +#if CAMERA_VIDEOBUF_ARM_ACCESS + struct rk29_camera_vbinfo *vbinfo; + unsigned int vbinfo_count; +#endif + int host_width; int host_height; int host_left; //sensor output size ? int host_top; @@ -406,13 +422,25 @@ static int rk_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, struct soc_camera_device *icd = vq->priv_data; struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct rk_camera_dev *pcdev = ici->priv; - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - int bytes_per_line_host = soc_mbus_bytes_per_line(pcdev->host_width, - icd->current_fmt->host_fmt); - unsigned int i; + unsigned int i; struct rk_camera_work *wk; + struct soc_mbus_pixelfmt fmt; + int bytes_per_line; + int bytes_per_line_host; + fmt.packing = SOC_MBUS_PACKING_1_5X8; + + bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + if(icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_RGB565) + bytes_per_line_host = soc_mbus_bytes_per_line(pcdev->host_width, + &fmt); + else if(icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_RGB24) + bytes_per_line_host = pcdev->host_width*3; + else + bytes_per_line_host = soc_mbus_bytes_per_line(pcdev->host_width, + icd->current_fmt->host_fmt); + printk("user code = %d,packing = %d",icd->current_fmt->code,fmt.packing); dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size); if (bytes_per_line_host < 0) @@ -453,7 +481,22 @@ static int rk_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, } pcdev->camera_work_count = (*count); } - +#if CAMERA_VIDEOBUF_ARM_ACCESS + if (pcdev->vbinfo && (pcdev->vbinfo_count != *count)) { + kfree(pcdev->vbinfo); + pcdev->vbinfo = NULL; + pcdev->vbinfo_count = 0x00; + } + + if (pcdev->vbinfo == NULL) { + pcdev->vbinfo = kzalloc(sizeof(struct rk29_camera_vbinfo)*(*count), GFP_KERNEL); + if (pcdev->vbinfo == NULL) { + RKCAMERA_TR("\n %s vbinfo kmalloc fail\n", __FUNCTION__); + BUG(); + } + pcdev->vbinfo_count = *count; + } +#endif } pcdev->video_vq = vq; RKCAMERA_DG("%s..%d.. videobuf size:%d, vipmem_buf size:%d, count:%d \n",__FUNCTION__,__LINE__, *size,pcdev->vipmem_size, *count); @@ -567,6 +610,7 @@ static void rk_videobuf_queue(struct videobuf_queue *vq, struct soc_camera_device *icd = vq->priv_data; struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct rk_camera_dev *pcdev = ici->priv; + struct rk29_camera_vbinfo *vb_info; dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, vb, vb->baddr, vb->bsize); @@ -580,6 +624,31 @@ static void rk_videobuf_queue(struct videobuf_queue *vq, else BUG(); /* ddl@rock-chips.com : The same videobuffer queue again */ } +#if CAMERA_VIDEOBUF_ARM_ACCESS + if (pcdev->vbinfo) { + vb_info = pcdev->vbinfo+vb->i; + if ((vb_info->phy_addr != vb->boff) || (vb_info->size != vb->bsize)) { + if (vb_info->vir_addr) { + iounmap(vb_info->vir_addr); + release_mem_region(vb_info->phy_addr, vb_info->size); + vb_info->vir_addr = NULL; + vb_info->phy_addr = 0x00; + vb_info->size = 0x00; + } + + if (request_mem_region(vb->boff,vb->bsize,"rk_camera_vb")) { + vb_info->vir_addr = ioremap_cached(vb->boff,vb->bsize); + } + + if (vb_info->vir_addr) { + vb_info->size = vb->bsize; + vb_info->phy_addr = vb->boff; + } else { + RKCAMERA_TR("%s..%d:ioremap videobuf %d failed\n",__FUNCTION__,__LINE__, vb->i); + } + } + } +#endif if (!pcdev->active) { pcdev->active = vb; rk_videobuf_capture(vb,pcdev); @@ -609,16 +678,219 @@ static int rk_pixfmt2ippfmt(unsigned int pixfmt, int *ippfmt) rk_pixfmt2ippfmt_err: return -1; } -static void rk_camera_capture_process(struct work_struct *work) + +static int rk_pixfmt2rgafmt(unsigned int pixfmt, int *ippfmt) +{ + switch (pixfmt) + { + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_UYVY: // yuv 422, but sensor has defined this format(in fact ,should be defined yuv 420), treat this as yuv 420. + case V4L2_PIX_FMT_YUYV: + { + *ippfmt = RK_FORMAT_YCbCr_420_SP; + break; + } + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_YVYU: + { + *ippfmt = RK_FORMAT_YCrCb_420_SP; + break; + } + case V4L2_PIX_FMT_RGB565: + { + *ippfmt = RK_FORMAT_RGB_565; + break; + } + case V4L2_PIX_FMT_RGB24: + { + *ippfmt = RK_FORMAT_RGB_888; + break; + } + default: + goto rk_pixfmt2rgafmt_err; + } + + return 0; +rk_pixfmt2rgafmt_err: + return -1; +} +#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_PP) +static int rk_camera_scale_crop_pp(struct work_struct *work){ + struct rk_camera_work *camera_work = container_of(work, struct rk_camera_work, work); + struct videobuf_buffer *vb = camera_work->vb; + struct rk_camera_dev *pcdev = camera_work->pcdev; + int vipdata_base; + unsigned long int flags; + int scale_times,w,h; + int src_y_offset; + PP_OP_HANDLE hnd; + PP_OPERATION init; + int ret = 0; + vipdata_base = pcdev->vipmem_phybase + vb->i*pcdev->vipmem_bsize; + + memset(&init, 0, sizeof(init)); + init.srcAddr = vipdata_base; + init.srcFormat = PP_IN_FORMAT_YUV420SEMI; + init.srcWidth = init.srcHStride = pcdev->zoominfo.vir_width; + init.srcHeight = init.srcVStride = pcdev->zoominfo.vir_height; + + init.dstAddr = vb->boff; + init.dstFormat = PP_OUT_FORMAT_YUV420INTERLAVE; + init.dstWidth = init.dstHStride = pcdev->icd->user_width; + init.dstHeight = init.dstVStride = pcdev->icd->user_height; + + printk("srcWidth = %d,srcHeight = %d,dstWidth = %d,dstHeight = %d\n",init.srcWidth,init.srcHeight,init.dstWidth,init.dstHeight); + #if 0 + ret = ppOpInit(&hnd, &init); + if (!ret) { + ppOpPerform(hnd); + ppOpSync(hnd); + ppOpRelease(hnd); + } else { + printk("can not create ppOp handle\n"); + } + #endif + return ret; +} +#endif +#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_RGA) +extern rga_service_info rga_service; +extern int rga_blit_sync(rga_session *session, struct rga_req *req); +extern void rga_service_session_clear(rga_session *session); +static int rk_camera_scale_crop_rga(struct work_struct *work){ + struct rk_camera_work *camera_work = container_of(work, struct rk_camera_work, work); + struct videobuf_buffer *vb = camera_work->vb; + struct rk_camera_dev *pcdev = camera_work->pcdev; + int vipdata_base; + unsigned long int flags; + int scale_times,w,h; + int src_y_offset; + struct rga_req req; + rga_session session; + int rga_times = 3; + const struct soc_mbus_pixelfmt *fmt; + int ret = 0; + fmt = soc_mbus_get_fmtdesc(pcdev->icd->current_fmt->code); + vipdata_base = pcdev->vipmem_phybase + vb->i*pcdev->vipmem_bsize; + if((pcdev->icd->current_fmt->host_fmt->fourcc != V4L2_PIX_FMT_RGB565) + && (pcdev->icd->current_fmt->host_fmt->fourcc != V4L2_PIX_FMT_RGB24)){ + RKCAMERA_TR("RGA not support this format !\n"); + goto do_ipp_err; + } + if ((pcdev->icd->user_width > 0x800) || (pcdev->icd->user_height > 0x800)) { + scale_times = MAX((pcdev->icd->user_width/0x800),(pcdev->icd->user_height/0x800)); + scale_times++; + } else { + scale_times = 1; + } + session.pid = current->pid; + INIT_LIST_HEAD(&session.waiting); + INIT_LIST_HEAD(&session.running); + INIT_LIST_HEAD(&session.list_session); + init_waitqueue_head(&session.wait); + /* no need to protect */ + list_add_tail(&session.list_session, &rga_service.session); + atomic_set(&session.task_running, 0); + atomic_set(&session.num_done, 0); + + memset(&req,0,sizeof(struct rga_req)); + req.src.act_w = pcdev->zoominfo.a.c.width/scale_times; + req.src.act_h = pcdev->zoominfo.a.c.height/scale_times; + + req.src.vir_w = pcdev->zoominfo.vir_width; + req.src.vir_h =pcdev->zoominfo.vir_height; + req.src.yrgb_addr = vipdata_base; + req.src.uv_addr =vipdata_base + req.src.vir_w*req.src.vir_h; + req.src.v_addr = req.src.uv_addr ; + req.src.format =fmt->fourcc; + rk_pixfmt2rgafmt(fmt->fourcc,&req.src.format); + req.src.x_offset = pcdev->zoominfo.a.c.left; + req.src.y_offset = pcdev->zoominfo.a.c.top; + + req.dst.act_w = pcdev->icd->user_width/scale_times; + req.dst.act_h = pcdev->icd->user_height/scale_times; + + req.dst.vir_w = pcdev->icd->user_width; + req.dst.vir_h = pcdev->icd->user_height; + req.dst.x_offset = 0; + req.dst.y_offset = 0; + req.dst.yrgb_addr = vb->boff; + rk_pixfmt2rgafmt(pcdev->icd->current_fmt->host_fmt->fourcc,&req.dst.format); + req.clip.xmin = 0; + req.clip.xmax = req.dst.vir_w-1; + req.clip.ymin = 0; + req.clip.ymax = req.dst.vir_h -1; + + req.rotate_mode = 1; + req.scale_mode = 2; + + req.sina = 0; + req.cosa = 65536; + req.mmu_info.mmu_en = 0; + + for (h=0; hzoominfo.a.c.left+w*pcdev->zoominfo.a.c.width/scale_times; + req.src.y_offset = pcdev->zoominfo.a.c.top+h*pcdev->zoominfo.a.c.height/scale_times; + req.dst.x_offset = pcdev->icd->user_width*w/scale_times; + req.dst.y_offset = pcdev->icd->user_height*h/scale_times; + req.dst.yrgb_addr = vb->boff ; + // RKCAMERA_TR("src.act_w = %d , src.act_h = %d! vir_w = %d , vir_h = %d,off_x = %d,off_y = %d\n",req.src.act_w,req.src.act_h ,req.src.vir_w,req.src.vir_h,req.src.x_offset,req.src.y_offset); + // RKCAMERA_TR("dst.act_w = %d , dst.act_h = %d! vir_w = %d , vir_h = %d,off_x = %d,off_y = %d\n",req.dst.act_w,req.dst.act_h ,req.dst.vir_w,req.dst.vir_h,req.dst.x_offset,req.dst.y_offset); + // RKCAMERA_TR("req.src.yrgb_addr = 0x%x,req.dst.yrgb_addr = 0x%x\n",req.src.yrgb_addr,req.dst.yrgb_addr); + + while(rga_times-- > 0) { + if (rga_blit_sync(&session, &req)){ + RKCAMERA_TR("rga do erro,do again,rga_times = %d!\n",rga_times); + } else { + break; + } + } + + if (rga_times <= 0) { + spin_lock_irqsave(&pcdev->lock, flags); + vb->state = VIDEOBUF_NEEDS_INIT; + spin_unlock_irqrestore(&pcdev->lock, flags); + mutex_lock(&rga_service.lock); + list_del(&session.list_session); + rga_service_session_clear(&session); + mutex_unlock(&rga_service.lock); + goto session_done; + } + } + } + session_done: + mutex_lock(&rga_service.lock); + list_del(&session.list_session); + rga_service_session_clear(&session); + mutex_unlock(&rga_service.lock); + + do_ipp_err: + + return ret; + +} + +#endif +#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_IPP) + +static int rk_camera_scale_crop_ipp(struct work_struct *work) { struct rk_camera_work *camera_work = container_of(work, struct rk_camera_work, work); struct videobuf_buffer *vb = camera_work->vb; struct rk_camera_dev *pcdev = camera_work->pcdev; - struct rk29_ipp_req ipp_req; + int vipdata_base; unsigned long int flags; - int src_y_offset,src_uv_offset,dst_y_offset,dst_uv_offset,src_y_size,dst_y_size; - int scale_times,w,h,vipdata_base; - + + struct rk29_ipp_req ipp_req; + int src_y_offset,src_uv_offset,dst_y_offset,dst_uv_offset,src_y_size,dst_y_size; + int scale_times,w,h; + int ret = 0; /* *ddl@rock-chips.com: * IPP Dest image resolution is 2047x1088, so scale operation break up some times @@ -632,7 +904,6 @@ static void rk_camera_capture_process(struct work_struct *work) memset(&ipp_req, 0, sizeof(struct rk29_ipp_req)); - down(&pcdev->zoominfo.sem); ipp_req.timeout = 3000; ipp_req.flag = IPP_ROT_0; ipp_req.store_clip_mode =1; @@ -691,15 +962,166 @@ static void rk_camera_capture_process(struct work_struct *work) } } - if (pcdev->icd_cb.sensor_cb) - (pcdev->icd_cb.sensor_cb)(vb); do_ipp_err: - up(&pcdev->zoominfo.sem); - wake_up(&(camera_work->vb->done)); - spin_lock_irqsave(&pcdev->camera_work_lock, flags); - list_add_tail(&camera_work->queue, &pcdev->camera_work_queue); - spin_unlock_irqrestore(&pcdev->camera_work_lock, flags); - return; + return ret; +} +#endif +#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_ARM) +static int rk_camera_scale_crop_arm(struct work_struct *work) +{ + struct rk_camera_work *camera_work = container_of(work, struct rk_camera_work, work); + struct videobuf_buffer *vb = camera_work->vb; + struct rk_camera_dev *pcdev = camera_work->pcdev; + struct rk29_camera_vbinfo *vb_info; + unsigned char *psY,*pdY,*psUV,*pdUV; + unsigned char *src,*dst; + unsigned long src_phy,dst_phy; + int srcW,srcH,cropW,cropH,dstW,dstH; + long zoomindstxIntInv,zoomindstyIntInv; + long x,y; + long yCoeff00,yCoeff01,xCoeff00,xCoeff01; + long sX,sY; + long r0,r1,a,b,c,d; + int ret = 0; + + src_phy = pcdev->vipmem_phybase + vb->i*pcdev->vipmem_bsize; + src = psY = (unsigned char*)(pcdev->vipmem_virbase + vb->i*pcdev->vipmem_bsize); + psUV = psY + pcdev->host_width*pcdev->host_height; + + srcW = pcdev->zoominfo.vir_width; + srcH = pcdev->zoominfo.vir_height; + cropW = pcdev->zoominfo.a.c.width; + cropH = pcdev->zoominfo.a.c.height; + + psY = psY + (srcW-cropW); + psUV = psUV + (srcW-cropW); + + vb_info = pcdev->vbinfo+vb->i; + dst_phy = vb_info->phy_addr; + dst = pdY = (unsigned char*)vb_info->vir_addr; + pdUV = pdY + pcdev->icd->user_width*pcdev->icd->user_height; + dstW = pcdev->icd->user_width; + dstH = pcdev->icd->user_height; + + zoomindstxIntInv = ((unsigned long)cropW<<16)/dstW + 1; + zoomindstyIntInv = ((unsigned long)cropH<<16)/dstH + 1; + + //y + //for(y = 0; y> 16); + + for(x = 0; x> 16); + + a = psY[sY*srcW + sX]; + b = psY[sY*srcW + sX + 1]; + c = psY[(sY+1)*srcW + sX]; + d = psY[(sY+1)*srcW + sX + 1]; + + r0 = (a * xCoeff01 + b * xCoeff00)>>16 ; + r1 = (c * xCoeff01 + d * xCoeff00)>>16 ; + r0 = (r0 * yCoeff01 + r1 * yCoeff00)>>16; + + pdY[x] = r0; + } + pdY += dstW; + } + + dstW /= 2; + dstH /= 2; + srcW /= 2; + srcH /= 2; + + //UV + //for(y = 0; y> 16); + + for(x = 0; x> 16); + + //U + a = psUV[(sY*srcW + sX)*2]; + b = psUV[(sY*srcW + sX + 1)*2]; + c = psUV[((sY+1)*srcW + sX)*2]; + d = psUV[((sY+1)*srcW + sX + 1)*2]; + + r0 = (a * xCoeff01 + b * xCoeff00)>>16 ; + r1 = (c * xCoeff01 + d * xCoeff00)>>16 ; + r0 = (r0 * yCoeff01 + r1 * yCoeff00)>>16; + + pdUV[x*2] = r0; + + //V + a = psUV[(sY*srcW + sX)*2 + 1]; + b = psUV[(sY*srcW + sX + 1)*2 + 1]; + c = psUV[((sY+1)*srcW + sX)*2 + 1]; + d = psUV[((sY+1)*srcW + sX + 1)*2 + 1]; + + r0 = (a * xCoeff01 + b * xCoeff00)>>16 ; + r1 = (c * xCoeff01 + d * xCoeff00)>>16 ; + r0 = (r0 * yCoeff01 + r1 * yCoeff00)>>16; + + pdUV[x*2 + 1] = r0; + } + pdUV += dstW*2; + } + +rk_camera_scale_crop_arm_end: + + dmac_flush_range((void*)src,(void*)(src+pcdev->vipmem_bsize)); + outer_flush_range((phys_addr_t)src_phy,(phys_addr_t)(src_phy+pcdev->vipmem_bsize)); + + dmac_flush_range((void*)dst,(void*)(dst+vb_info->size)); + outer_flush_range((phys_addr_t)dst_phy,(phys_addr_t)(dst_phy+vb_info->size)); + + return ret; +} +#endif +static void rk_camera_capture_process(struct work_struct *work) +{ + struct rk_camera_work *camera_work = container_of(work, struct rk_camera_work, work); + struct videobuf_buffer *vb = camera_work->vb; + struct rk_camera_dev *pcdev = camera_work->pcdev; + //enum v4l2_mbus_pixelcode icd_code = pcdev->icd->current_fmt->code; + unsigned long flags = 0; + int err = 0; + + if (!CAM_WORKQUEUE_IS_EN()) + goto rk_camera_capture_process_end; + + down(&pcdev->zoominfo.sem); + if (pcdev->icd_cb.scale_crop_cb){ + err = (pcdev->icd_cb.scale_crop_cb)(work); + } + up(&pcdev->zoominfo.sem); + + if (pcdev->icd_cb.sensor_cb) + (pcdev->icd_cb.sensor_cb)(vb); + +rk_camera_capture_process_end: + if (err) { + vb->state = VIDEOBUF_ERROR; + } else { + if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) { + vb->state = VIDEOBUF_DONE; + vb->field_count++; + } + } + wake_up(&(camera_work->vb->done)); + spin_lock_irqsave(&pcdev->camera_work_lock, flags); + list_add_tail(&camera_work->queue, &pcdev->camera_work_queue); + spin_unlock_irqrestore(&pcdev->camera_work_lock, flags); + return; } static irqreturn_t rk_camera_irq(int irq, void *data) { @@ -768,11 +1190,7 @@ static irqreturn_t rk_camera_irq(int irq, void *data) RKCAMERA_DG("%s video_buf queue is empty!\n",__FUNCTION__); } - if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) { - vb->state = VIDEOBUF_DONE; - do_gettimeofday(&vb->ts); - vb->field_count++; - } + do_gettimeofday(&vb->ts); if (CAM_WORKQUEUE_IS_EN()) { if (!list_empty(&pcdev->camera_work_queue)) { wk = list_entry(pcdev->camera_work_queue.next, struct rk_camera_work, queue); @@ -783,6 +1201,10 @@ static irqreturn_t rk_camera_irq(int irq, void *data) queue_work(pcdev->camera_wq, &(wk->work)); } } else { + if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) { + vb->state = VIDEOBUF_DONE; + vb->field_count++; + } wake_up(&vb->done); } @@ -802,6 +1224,7 @@ static void rk_videobuf_release(struct videobuf_queue *vq, struct soc_camera_device *icd = vq->priv_data; struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct rk_camera_dev *pcdev = ici->priv; + struct rk29_camera_vbinfo *vb_info =NULL; #ifdef DEBUG dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, vb->baddr, vb->bsize); @@ -822,16 +1245,25 @@ static void rk_videobuf_release(struct videobuf_queue *vq, break; } #endif - if (vb->i == 0) { - flush_workqueue(pcdev->camera_wq); - } - if (vb == pcdev->active) { RKCAMERA_DG("%s Wait for this video buf(0x%x) write finished!\n ",__FUNCTION__,(unsigned int)vb); interruptible_sleep_on_timeout(&vb->done, msecs_to_jiffies(500)); - flush_workqueue(pcdev->camera_wq); RKCAMERA_DG("%s This video buf(0x%x) write finished, release now!!\n",__FUNCTION__,(unsigned int)vb); } + + flush_workqueue(pcdev->camera_wq); +#if CAMERA_VIDEOBUF_ARM_ACCESS + if (pcdev->vbinfo) { + vb_info = pcdev->vbinfo + vb->i; + + if (vb_info->vir_addr) { + iounmap(vb_info->vir_addr); + release_mem_region(vb_info->phy_addr, vb_info->size); + memset(vb_info, 0x00, sizeof(struct rk29_camera_vbinfo)); + } + + } +#endif rk_videobuf_free(vq, buf); } @@ -1020,6 +1452,8 @@ static void rk_camera_remove_device(struct soc_camera_device *icd) struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct rk_camera_dev *pcdev = ici->priv; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + struct rk29_camera_vbinfo *vb_info; + unsigned int i; mutex_lock(&camera_lock); BUG_ON(icd != pcdev->icd); @@ -1059,6 +1493,22 @@ static void rk_camera_remove_device(struct soc_camera_device *icd) INIT_LIST_HEAD(&pcdev->camera_work_queue); } rk_camera_deactivate(pcdev); +#if CAMERA_VIDEOBUF_ARM_ACCESS + if (pcdev->vbinfo) { + vb_info = pcdev->vbinfo; + for (i=0; ivbinfo_count; i++) { + if (vb_info->vir_addr) { + iounmap(vb_info->vir_addr); + release_mem_region(vb_info->phy_addr, vb_info->size); + memset(vb_info, 0x00, sizeof(struct rk29_camera_vbinfo)); + } + vb_info++; + } + kfree(pcdev->vbinfo); + pcdev->vbinfo = NULL; + pcdev->vbinfo_count = 0; + } +#endif pcdev->active = NULL; pcdev->icd = NULL; pcdev->icd_cb.sensor_cb = NULL; @@ -1207,6 +1657,18 @@ static const struct soc_mbus_pixelfmt rk_camera_formats[] = { .bits_per_sample = 8, .packing = SOC_MBUS_PACKING_2X8_PADHI, .order = SOC_MBUS_ORDER_LE, + },{ + .fourcc = V4L2_PIX_FMT_RGB565, + .name = "RGB565", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_2X8_PADHI, + .order = SOC_MBUS_ORDER_LE, + },{ + .fourcc = V4L2_PIX_FMT_RGB24, + .name = "RGB888", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_2X8_PADHI, + .order = SOC_MBUS_ORDER_LE, } }; @@ -1216,6 +1678,16 @@ static void rk_camera_setup_format(struct soc_camera_device *icd, __u32 host_pix struct rk_camera_dev *pcdev = ici->priv; unsigned int cif_fs = 0,cif_crop = 0; unsigned int cif_fmt_val = read_cif_reg(pcdev->base,CIF_CIF_FOR) | INPUT_MODE_YUV|YUV_INPUT_422|INPUT_420_ORDER_EVEN|OUTPUT_420_ORDER_EVEN; + + const struct soc_mbus_pixelfmt *fmt; + fmt = soc_mbus_get_fmtdesc(icd_code); + + if((host_pixfmt == V4L2_PIX_FMT_RGB565) || (host_pixfmt == V4L2_PIX_FMT_RGB24)){ + if(fmt->fourcc == V4L2_PIX_FMT_NV12) + host_pixfmt = V4L2_PIX_FMT_NV12; + else if(fmt->fourcc == V4L2_PIX_FMT_NV21) + host_pixfmt = V4L2_PIX_FMT_NV21; + } switch (host_pixfmt) { case V4L2_PIX_FMT_NV16: @@ -1342,42 +1814,62 @@ static int rk_camera_get_formats(struct soc_camera_device *icd, unsigned int idx case V4L2_MBUS_FMT_YUYV8_2X8: case V4L2_MBUS_FMT_YVYU8_2X8: case V4L2_MBUS_FMT_VYUY8_2X8: - formats++; - if (xlate) { - xlate->host_fmt = &rk_camera_formats[0]; - xlate->code = code; - xlate++; - dev_dbg(dev, "Providing format %s using code %d\n", - rk_camera_formats[0].name,code); - } - - formats++; - if (xlate) { - xlate->host_fmt = &rk_camera_formats[1]; - xlate->code = code; - xlate++; - dev_dbg(dev, "Providing format %s using code %d\n", - rk_camera_formats[1].name,code); - } - - formats++; - if (xlate) { - xlate->host_fmt = &rk_camera_formats[2]; - xlate->code = code; - xlate++; - dev_dbg(dev, "Providing format %s using code %d\n", - rk_camera_formats[2].name,code); - } - - formats++; - if (xlate) { - xlate->host_fmt = &rk_camera_formats[3]; - xlate->code = code; - xlate++; - dev_dbg(dev, "Providing format %s using code %d\n", - rk_camera_formats[3].name,code); - } +#if (CONFIG_CAMERA_SCALE_CROP_MACHINE != RK_CAM_SCALE_CROP_RGA) + formats++; + if (xlate) { + xlate->host_fmt = &rk_camera_formats[0]; + xlate->code = code; + xlate++; + dev_dbg(dev, "Providing format %s using code %d\n", + rk_camera_formats[0].name,code); + } + + formats++; + if (xlate) { + xlate->host_fmt = &rk_camera_formats[1]; + xlate->code = code; + xlate++; + dev_dbg(dev, "Providing format %s using code %d\n", + rk_camera_formats[1].name,code); + } + + formats++; + if (xlate) { + xlate->host_fmt = &rk_camera_formats[2]; + xlate->code = code; + xlate++; + dev_dbg(dev, "Providing format %s using code %d\n", + rk_camera_formats[2].name,code); + } + + formats++; + if (xlate) { + xlate->host_fmt = &rk_camera_formats[3]; + xlate->code = code; + xlate++; + dev_dbg(dev, "Providing format %s using code %d\n", + rk_camera_formats[3].name,code); + } + break; +#else + formats++; + if (xlate) { + xlate->host_fmt = &rk_camera_formats[4]; + xlate->code = code; + xlate++; + dev_dbg(dev, "Providing format %s using code %d\n", + rk_camera_formats[4].name,code); + } + formats++; + if (xlate) { + xlate->host_fmt = &rk_camera_formats[5]; + xlate->code = code; + xlate++; + dev_dbg(dev, "Providing format %s using code %d\n", + rk_camera_formats[5].name,code); + } break; +#endif default: break; } @@ -2361,15 +2853,38 @@ static int rk_camera_probe(struct platform_device *pdev) if (pcdev->pdata && IS_CIF0()) { pcdev->vipmem_phybase = pcdev->pdata->meminfo.start; pcdev->vipmem_size = pcdev->pdata->meminfo.size; + + if (!request_mem_region(pcdev->vipmem_phybase,pcdev->vipmem_size,"rk29_vipmem")) { + err = -EBUSY; + goto exit_ioremap_vipmem; + } + pcdev->vipmem_virbase = ioremap_cached(pcdev->vipmem_phybase,pcdev->vipmem_size); + if (pcdev->vipmem_virbase == NULL) { + dev_err(pcdev->dev, "ioremap() of vip internal memory(Ex:IPP process/raw process) failed\n"); + err = -ENXIO; + goto exit_ioremap_vipmem; + } RKCAMERA_TR("%s(%d): Memory(start:0x%x size:0x%x) for IPP obtain \n",__FUNCTION__,__LINE__, pcdev->pdata->meminfo.start,pcdev->pdata->meminfo.size); } else if (pcdev->pdata) { pcdev->vipmem_phybase = pcdev->pdata->meminfo_cif1.start; pcdev->vipmem_size = pcdev->pdata->meminfo_cif1.size; + + if (!request_mem_region(pcdev->vipmem_phybase,pcdev->vipmem_size,"rk29_vipmem")) { + err = -EBUSY; + goto exit_ioremap_vipmem; + } + pcdev->vipmem_virbase = ioremap_cached(pcdev->vipmem_phybase,pcdev->vipmem_size); + if (pcdev->vipmem_virbase == NULL) { + dev_err(pcdev->dev, "ioremap() of vip internal memory(Ex:IPP process/raw process) failed\n"); + err = -ENXIO; + goto exit_ioremap_vipmem; + } RKCAMERA_TR("%s(%d): Memory(start:0x%x size:0x%x) for IPP obtain \n",__FUNCTION__,__LINE__, pcdev->pdata->meminfo.start,pcdev->pdata->meminfo.size); } else { RKCAMERA_TR("\n%s Memory for IPP have not obtain! IPP Function is fail\n",__FUNCTION__); pcdev->vipmem_phybase = 0; pcdev->vipmem_size = 0; + pcdev->vipmem_virbase = 0; } #endif INIT_LIST_HEAD(&pcdev->capture); @@ -2441,6 +2956,15 @@ static int rk_camera_probe(struct platform_device *pdev) pcdev->fps_timer.timer.function = rk_camera_fps_func; pcdev->icd_cb.sensor_cb = NULL; +#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_IPP) + pcdev->icd_cb.scale_crop_cb = rk_camera_scale_crop_ipp; +#elif (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_ARM) + pcdev->icd_cb.scale_crop_cb = rk_camera_scale_crop_arm; +#elif (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_RGA) + pcdev->icd_cb.scale_crop_cb = rk_camera_scale_crop_rga; +#elif(CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_PP) + pcdev->icd_cb.scale_crop_cb = rk_camera_scale_crop_pp; +#endif RKCAMERA_DG("%s(%d) Exit \n",__FUNCTION__,__LINE__); return 0; @@ -2465,7 +2989,10 @@ static int rk_camera_probe(struct platform_device *pdev) iounmap(pcdev->base); exit_ioremap_vip: release_mem_region(res->start, res->end - res->start + 1); - +exit_ioremap_vipmem: + if (pcdev->vipmem_virbase) + iounmap(pcdev->vipmem_virbase); + release_mem_region(pcdev->vipmem_phybase,pcdev->vipmem_size); exit_reqmem_vip: if(pcdev->aclk_cif) pcdev->aclk_cif = NULL; From 7c315761365a9fe821312b8f5e7715a4854506d2 Mon Sep 17 00:00:00 2001 From: xbw Date: Mon, 20 Aug 2012 17:16:05 +0800 Subject: [PATCH 244/261] sdmmc: some card, SDHC 32G Class10, maybe miss the nobusy_INT. so close the nobusy_INT function --- drivers/mmc/host/rk29_sdmmc.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/host/rk29_sdmmc.c b/drivers/mmc/host/rk29_sdmmc.c index 825672ca26c7..82751006aba5 100755 --- a/drivers/mmc/host/rk29_sdmmc.c +++ b/drivers/mmc/host/rk29_sdmmc.c @@ -66,7 +66,7 @@ int debug_level = 5; #if defined(CONFIG_ARCH_RK29) #define SDMMC_USE_INT_UNBUSY 0 #else -#define SDMMC_USE_INT_UNBUSY 1 +#define SDMMC_USE_INT_UNBUSY 0///1 #endif #if defined(CONFIG_ARCH_RK29) @@ -1950,7 +1950,7 @@ static void rk29_sdmmc_INT_CMD_DONE_timeout(unsigned long host_data) if(STATE_SENDING_CMD == host->state) { - if((0==host->cmd->retries)&&(12 != host->cmd->opcode)/*&&(55 != host->cmd->opcode)*/) + if((0==host->cmd->retries)&&(12 != host->cmd->opcode)) { printk(KERN_WARNING "%d... cmd=%d, INT_CMD_DONE timeout, errorStep=0x%x, host->state=%x [%s]\n",\ __LINE__,host->cmd->opcode, host->errorstep,host->state,host->dma_name); @@ -3465,11 +3465,7 @@ static int rk29_sdmmc_probe(struct platform_device *pdev) #else if(RK29_CTRL_SDMMC_ID== host->pdev->id) { -#ifdef CONFIG_ARCH_RK2928 - mmc->f_max = SD_FPP_FREQ; -#else mmc->f_max = SDHC_FPP_FREQ; -#endif } else { From 0d54b690bb77e314de2bf5aa65532a7cdd87f6fe Mon Sep 17 00:00:00 2001 From: hcy Date: Mon, 20 Aug 2012 17:58:39 +0800 Subject: [PATCH 245/261] fix DLL off bug, fix ZQCR[1] bug, add to support change BL, add dsb() --- arch/arm/mach-rk30/ddr.c | 117 ++++++++++++++++++++++++++++----------- 1 file changed, 86 insertions(+), 31 deletions(-) mode change 100644 => 100755 arch/arm/mach-rk30/ddr.c diff --git a/arch/arm/mach-rk30/ddr.c b/arch/arm/mach-rk30/ddr.c old mode 100644 new mode 100755 index ad62e0dcc981..a50e3e8b836e --- a/arch/arm/mach-rk30/ddr.c +++ b/arch/arm/mach-rk30/ddr.c @@ -124,7 +124,7 @@ typedef uint32_t uint32; //mr1 for ddr3 #define DDR3_DLL_ENABLE (0) #define DDR3_DLL_DISABLE (1) -#define DDR3_MR1_AL(n) (((n)&0x7)<<3) +#define DDR3_MR1_AL(n) (((n)&0x3)<<3) #define DDR3_DS_40 (0) #define DDR3_DS_34 (1<<1) @@ -914,11 +914,11 @@ DDR_CONFIG_2_RBC_T ddr_cfg_2_rbc[16] = {15,3,10} // bank ahead }; -uint32_t ddr_data_training_buf[32]; +__attribute__((aligned(4096))) uint32_t ddr_data_training_buf[32]; uint32_t __sramdata ddr3_cl_cwl[22][4]={ /* 0~330 330~400 400~533 speed -* tCK >3 2.5~3 1.875~2.5 1.875~1.5 +* tCK >3 2.5~3 1.875~2.5 1.5~1.875 * cl<<16, cwl cl<<16, cwl cl<<16, cwl */ {((5<<16)|5), ((5<<16)|5), 0 , 0}, //DDR3_800D {((5<<16)|5), ((6<<16)|5), 0 , 0}, //DDR3_800E @@ -929,7 +929,7 @@ uint32_t __sramdata ddr3_cl_cwl[22][4]={ {((5<<16)|5), ((5<<16)|5), ((6<<16)|6), ((7<<16)|7)}, //DDR3_1333F {((5<<16)|5), ((5<<16)|5), ((7<<16)|6), ((8<<16)|7)}, //DDR3_1333G - {((5<<16)|5), ((6<<16)|5), ((7<<16)|6), ((9<<16)|7)}, //DDR3_1333H + {((5<<16)|5), ((6<<16)|5), ((8<<16)|6), ((9<<16)|7)}, //DDR3_1333H {((5<<16)|5), ((6<<16)|5), ((8<<16)|6), ((10<<16)|7)}, //DDR3_1333J {((5<<16)|5), ((5<<16)|5), ((6<<16)|6), ((7<<16)|7)}, //DDR3_1600G @@ -993,13 +993,13 @@ Cpu highest frequency is 1.6 GHz 1 cycle = 1/1.6 ns 1 us = 1000 ns = 1000 * 1.6 cycles = 1600 cycles *****************************************************************************/ -static __sramdata uint32_t loops_per_us; +static __sramdata volatile uint32_t loops_per_us; #define LPJ_100MHZ 999456UL /*static*/ void __sramlocalfunc ddr_delayus(uint32_t us) { - uint32_t count; + volatile uint32_t count; count = loops_per_us*us; while(count--) // 3 cycles @@ -1115,12 +1115,15 @@ __sramfunc void ddr_move_to_Lowpower_state(void) { case Init_mem: pDDR_Reg->SCTL = CFG_STATE; + dsb(); while((pDDR_Reg->STAT.b.ctl_stat) != Config); case Config: pDDR_Reg->SCTL = GO_STATE; + dsb(); while((pDDR_Reg->STAT.b.ctl_stat) != Access); case Access: pDDR_Reg->SCTL = SLEEP_STATE; + dsb(); while((pDDR_Reg->STAT.b.ctl_stat) != Low_power); break; default: //Transitional state @@ -1135,6 +1138,7 @@ __sramfunc void ddr_move_to_Access_state(void) //set auto self-refresh idle pDDR_Reg->MCFG1=(pDDR_Reg->MCFG1&0xffffff00)|ddr_sr_idle; + dsb(); while(1) { @@ -1148,14 +1152,17 @@ __sramfunc void ddr_move_to_Access_state(void) { case Low_power: pDDR_Reg->SCTL = WAKEUP_STATE; + dsb(); while((pDDR_Reg->STAT.b.ctl_stat) != Access); while((pPHY_Reg->PGSR & DLDONE) != DLDONE); //wait DLL lock break; case Init_mem: pDDR_Reg->SCTL = CFG_STATE; + dsb(); while((pDDR_Reg->STAT.b.ctl_stat) != Config); case Config: pDDR_Reg->SCTL = GO_STATE; + dsb(); while(!(((pDDR_Reg->STAT.b.ctl_stat) == Access) || ((pDDR_Reg->STAT.b.lp_trig == 1) && ((pDDR_Reg->STAT.b.ctl_stat) == Low_power)))); break; @@ -1187,11 +1194,13 @@ __sramfunc void ddr_move_to_Config_state(void) { case Low_power: pDDR_Reg->SCTL = WAKEUP_STATE; + dsb(); while((pDDR_Reg->STAT.b.ctl_stat) != Access); while((pPHY_Reg->PGSR & DLDONE) != DLDONE); //wait DLL lock case Access: case Init_mem: pDDR_Reg->SCTL = CFG_STATE; + dsb(); while((pDDR_Reg->STAT.b.ctl_stat) != Config); break; default: //Transitional state @@ -1203,9 +1212,8 @@ __sramfunc void ddr_move_to_Config_state(void) //arg包括bank_addr和cmd_addr void __sramlocalfunc ddr_send_command(uint32 rank, uint32 cmd, uint32 arg) { - uint32 i; pDDR_Reg->MCMD = (start_cmd | (rank<<20) | arg | cmd); - for (i = 0; i < 10; i ++) {;} + dsb(); while(pDDR_Reg->MCMD & start_cmd); } @@ -1214,17 +1222,18 @@ void __sramlocalfunc ddr_send_command(uint32 rank, uint32 cmd, uint32 arg) //!0 DTT失败 uint32_t __sramlocalfunc ddr_data_training(void) { - uint32 i,value,cs; + uint32 value,cs; // disable auto refresh value = pDDR_Reg->TREFI; pDDR_Reg->TREFI = 0; + dsb(); // clear DTDONE status pPHY_Reg->PIR |= CLRSR; cs = ((pPHY_Reg->PGCR>>18) & 0xF); // trigger DTT pPHY_Reg->PIR |= INIT | QSTRN | LOCKBYP | ZCALBYP | CLRSR | ICPC; - for (i = 0; i < 10; i ++) {;} + dsb(); // wait echo byte DTDONE while((pPHY_Reg->DATX8[0].DXGSR[0] & cs) != cs); while((pPHY_Reg->DATX8[1].DXGSR[0] & cs) != cs); @@ -1343,14 +1352,14 @@ uint32_t __sramlocalfunc ddr_set_pll(uint32_t nMHz, uint32_t set) else { pCRU_Reg->CRU_MODE_CON = (0x3<<((pll_id*4) + 16)) | (0x0<<(pll_id*4)); //PLL slow-mode - + dsb(); pCRU_Reg->CRU_PLL_CON[pll_id][3] = PLL_RESET; pCRU_Reg->CRU_PLL_CON[pll_id][0] = NR(clkr) | NO(clkod); pCRU_Reg->CRU_PLL_CON[pll_id][1] = NF(clkf); pCRU_Reg->CRU_PLL_CON[pll_id][2] = NB(clkf>>1); ddr_delayus(1); pCRU_Reg->CRU_PLL_CON[pll_id][3] = PLL_DE_RESET; - + dsb(); while (delay > 0) { ddr_delayus(1); @@ -1364,6 +1373,7 @@ uint32_t __sramlocalfunc ddr_set_pll(uint32_t nMHz, uint32_t set) | 0; //clk_ddr_src:clk_ddrphy = 1:1 pCRU_Reg->CRU_MODE_CON = (0x3<<((pll_id*4) + 16)) | (0x1<<(pll_id*4)); //PLL normal + dsb(); } out: return ret; @@ -1374,7 +1384,7 @@ uint32_t ddr_get_parameter(uint32_t nMHz) uint32_t tmp; uint32_t ret = 0; uint32_t al; - uint32_t bl; + uint32_t bl,bl_tmp; uint32_t cl; uint32_t cwl; PCTL_TIMING_T *p_pctl_timing=&(ddr_reg.pctl.pctl_timing); @@ -1561,7 +1571,8 @@ uint32_t ddr_get_parameter(uint32_t nMHz) tmp = tmp - 4; else tmp = tmp>>1; - p_publ_timing->mr[0] = DDR3_BL8 | DDR3_CL(cl) | DDR3_WR(tmp); + bl_tmp = (bl == 8) ? DDR3_BL8 : DDR3_BC4; + p_publ_timing->mr[0] = bl_tmp | DDR3_CL(cl) | DDR3_WR(tmp); /* * tWTR, max(4 tCK,7.5ns) @@ -1901,7 +1912,8 @@ uint32_t ddr_get_parameter(uint32_t nMHz) * tWR, 15ns */ p_pctl_timing->twr = ((LPDDR2_tWR*nMHz+999)/1000)&0x1F; - p_publ_timing->mr[1] = LPDDR2_BL8 | LPDDR2_nWR(((LPDDR2_tWR*nMHz+999)/1000)); + bl_tmp = (bl == 16) ? LPDDR2_BL16 : ((bl == 8) ? LPDDR2_BL8 : LPDDR2_BL4); + p_publ_timing->mr[1] = bl_tmp | LPDDR2_nWR(((LPDDR2_tWR*nMHz+999)/1000)); /* * tWTR, 7.5ns(533-266MHz) 10ns(200-166MHz) */ @@ -2194,7 +2206,8 @@ uint32_t ddr_get_parameter(uint32_t nMHz) */ tmp = ((DDR2_tWR*nMHz+999)/1000); p_pctl_timing->twr = tmp&0x1F; - p_publ_timing->mr[0] = DDR2_BL4 | DDR2_CL(cl) | DDR2_WR(tmp); + bl_tmp = (bl == 8) ? DDR2_BL8 : DDR2_BL4; + p_publ_timing->mr[0] = bl_tmp | DDR2_CL(cl) | DDR2_WR(tmp); /* * tWTR, 10ns(200MHz) 7.5ns(>200MHz) */ @@ -2360,7 +2373,8 @@ uint32_t ddr_get_parameter(uint32_t nMHz) */ cl = 3; cwl = 1; - p_publ_timing->mr[0] = mDDR_BL4 | mDDR_CL(cl); + bl_tmp = (bl == 8) ? mDDR_BL8 : ((bl == 4) ? mDDR_BL4 : mDDR_BL2); + p_publ_timing->mr[0] = bl_tmp | mDDR_CL(cl); p_publ_timing->mr[2] = mDDR_DS_3_4; //mr[2] is mDDR MR1 p_publ_timing->mr[1] = 0; p_publ_timing->mr[3] = 0; @@ -2596,7 +2610,7 @@ uint32_t ddr_get_parameter(uint32_t nMHz) uint32_t __sramlocalfunc ddr_update_timing(void) { - uint32_t i; + uint32_t i,bl_tmp; PCTL_TIMING_T *p_pctl_timing=&(ddr_reg.pctl.pctl_timing); PHY_TIMING_T *p_publ_timing=&(ddr_reg.publ.phy_timing); NOC_TIMING_T *p_noc_timing=&(ddr_reg.noc_timing); @@ -2607,15 +2621,28 @@ uint32_t __sramlocalfunc ddr_update_timing(void) // Update PCTL BL if(mem_type == DDR3) { - pDDR_Reg->MCFG = (pDDR_Reg->MCFG & (~(0x1|(0x3<<18)|(0x1<<17)|(0x1<<16)))) | ddr2_ddr3_bl_8 | tfaw_cfg(5)|pd_exit_slow|pd_type(1); + bl_tmp = ((p_publ_timing->mr[0] & 0x3) == DDR3_BL8) ? ddr2_ddr3_bl_8 : ddr2_ddr3_bl_4; + pDDR_Reg->MCFG = (pDDR_Reg->MCFG & (~(0x1|(0x3<<18)|(0x1<<17)|(0x1<<16)))) | bl_tmp | tfaw_cfg(5)|pd_exit_slow|pd_type(1); pDDR_Reg->DFITRDDATAEN = pDDR_Reg->TCL-2; pDDR_Reg->DFITPHYWRLAT = pDDR_Reg->TCWL-1; } else if(mem_type == LPDDR2) { + switch(p_publ_timing->mr[1] & 0x7) + { + case LPDDR2_BL4: + bl_tmp = mddr_lpddr2_bl_4; + break; + case LPDDR2_BL8: + bl_tmp = mddr_lpddr2_bl_8; + break; + case LPDDR2_BL16: + bl_tmp = mddr_lpddr2_bl_16; + break; + } if(ddr_freq>=200) { - pDDR_Reg->MCFG = (pDDR_Reg->MCFG & (~((0x3<<20)|(0x3<<18)|(0x1<<17)|(0x1<<16)))) | mddr_lpddr2_bl_8 | tfaw_cfg(5)|pd_exit_fast|pd_type(1); + pDDR_Reg->MCFG = (pDDR_Reg->MCFG & (~((0x3<<20)|(0x3<<18)|(0x1<<17)|(0x1<<16)))) | bl_tmp | tfaw_cfg(5)|pd_exit_fast|pd_type(1); } else { @@ -2628,11 +2655,24 @@ uint32_t __sramlocalfunc ddr_update_timing(void) } else if(mem_type == DDR2) { - pDDR_Reg->MCFG = (pDDR_Reg->MCFG & (~(0x1|(0x3<<18)|(0x1<<17)|(0x1<<16)))) | ddr2_ddr3_bl_8 | tfaw_cfg(5)|pd_exit_fast|pd_type(1); + bl_tmp = ((p_publ_timing->mr[0] & 0x3) == DDR2_BL8) ? ddr2_ddr3_bl_8 : ddr2_ddr3_bl_4; + pDDR_Reg->MCFG = (pDDR_Reg->MCFG & (~(0x1|(0x3<<18)|(0x1<<17)|(0x1<<16)))) | bl_tmp | tfaw_cfg(5)|pd_exit_fast|pd_type(1); } else// if(mem_type == LPDDR) { - pDDR_Reg->MCFG = (pDDR_Reg->MCFG & (~((0x3<<20)|(0x3<<18)|(0x1<<17)|(0x1<<16)))) | mddr_lpddr2_bl_4 | tfaw_cfg(5)|pd_exit_fast|pd_type(1); + switch(p_publ_timing->mr[0] & 0x7) + { + case mDDR_BL2: + bl_tmp = mddr_lpddr2_bl_2; + break; + case mDDR_BL4: + bl_tmp = mddr_lpddr2_bl_4; + break; + case mDDR_BL8: + bl_tmp = mddr_lpddr2_bl_8; + break; + } + pDDR_Reg->MCFG = (pDDR_Reg->MCFG & (~((0x3<<20)|(0x3<<18)|(0x1<<17)|(0x1<<16)))) | bl_tmp | tfaw_cfg(5)|pd_exit_fast|pd_type(1); } return 0; } @@ -2640,15 +2680,16 @@ uint32_t __sramlocalfunc ddr_update_timing(void) uint32_t __sramlocalfunc ddr_update_mr(void) { PHY_TIMING_T *p_publ_timing=&(ddr_reg.publ.phy_timing); - uint32_t cs; + uint32_t cs,dll_off; cs = ((pPHY_Reg->PGCR>>18) & 0xF); + dll_off = (pPHY_Reg->MR[1] & DDR3_DLL_DISABLE) ? 1:0; ddr_copy((uint32_t *)&(pPHY_Reg->MR[0]), (uint32_t*)&(p_publ_timing->mr[0]), 4); if((mem_type == DDR3) || (mem_type == DDR2)) { if(ddr_freq>DDR3_DDR2_DLL_DISABLE_FREQ) { - if(pPHY_Reg->MR[1] & DDR3_DLL_DISABLE) // off -> on + if(dll_off) // off -> on { ddr_send_command(cs, MRS_cmd, bank_addr(0x1) | cmd_addr((uint8_t)(p_publ_timing->mr[1]))); //DLL enable ddr_send_command(cs, MRS_cmd, bank_addr(0x0) | cmd_addr(((uint8_t)(p_publ_timing->mr[0]))| DDR3_DLL_RESET)); //DLL reset @@ -2716,9 +2757,11 @@ void __sramlocalfunc ddr_update_odt(void) cs = ((pPHY_Reg->PGCR>>18) & 0xF); if(cs > 1) { - pPHY_Reg->ZQ1CR[0] = tmp; + pPHY_Reg->ZQ1CR[1] = tmp; + dsb(); } pPHY_Reg->ZQ0CR[0] = tmp; + dsb(); } __sramfunc void ddr_adjust_config(uint32_t dram_type) @@ -2736,6 +2779,7 @@ __sramfunc void ddr_adjust_config(uint32_t dram_type) flush_cache_all(); outer_flush_all(); flush_tlb_all(); + isb(); DDR_SAVE_SP(save_sp); for(i=0;i<16;i++) @@ -2796,30 +2840,35 @@ void __sramlocalfunc idle_port(void) if ( (pPMU_Reg->PMU_PWRDN_ST & pd_a9_0_pwr_st) == 0 ) { pPMU_Reg->PMU_MISC_CON1 |= idle_req_cpu_cfg; + dsb(); while( (pPMU_Reg->PMU_PWRDN_ST & idle_cpu) == 0 ); } if ( (pPMU_Reg->PMU_PWRDN_ST & pd_peri_pwr_st) == 0 ) { pPMU_Reg->PMU_MISC_CON1 |= idle_req_peri_cfg; + dsb(); while( (pPMU_Reg->PMU_PWRDN_ST & idle_peri) == 0 ); } if ( (pPMU_Reg->PMU_PWRDN_ST & pd_vio_pwr_st) == 0 ) { pPMU_Reg->PMU_MISC_CON1 |= idle_req_vio_cfg; + dsb(); while( (pPMU_Reg->PMU_PWRDN_ST & idle_vio) == 0 ); } if ( (pPMU_Reg->PMU_PWRDN_ST & pd_video_pwr_st) == 0 ) { pPMU_Reg->PMU_MISC_CON1 |= idle_req_video_cfg; + dsb(); while( (pPMU_Reg->PMU_PWRDN_ST & idle_video) == 0 ); } if ( (pPMU_Reg->PMU_PWRDN_ST & pd_gpu_pwr_st) == 0 ) { pPMU_Reg->PMU_MISC_CON1 |= idle_req_gpu_cfg; + dsb(); while( (pPMU_Reg->PMU_PWRDN_ST & idle_gpu) == 0 ); } @@ -2844,29 +2893,34 @@ void __sramlocalfunc deidle_port(void) if ( (pPMU_Reg->PMU_PWRDN_ST & pd_a9_0_pwr_st) == 0 ) { pPMU_Reg->PMU_MISC_CON1 &= ~idle_req_cpu_cfg; + dsb(); while( (pPMU_Reg->PMU_PWRDN_ST & idle_cpu) != 0 ); } if ( (pPMU_Reg->PMU_PWRDN_ST & pd_peri_pwr_st) == 0 ) { pPMU_Reg->PMU_MISC_CON1 &= ~idle_req_peri_cfg; + dsb(); while( (pPMU_Reg->PMU_PWRDN_ST & idle_peri) != 0 ); } if ( (pPMU_Reg->PMU_PWRDN_ST & pd_vio_pwr_st) == 0 ) { pPMU_Reg->PMU_MISC_CON1 &= ~idle_req_vio_cfg; + dsb(); while( (pPMU_Reg->PMU_PWRDN_ST & idle_vio) != 0 ); } if ( (pPMU_Reg->PMU_PWRDN_ST & pd_video_pwr_st) == 0 ) { pPMU_Reg->PMU_MISC_CON1 &= ~idle_req_video_cfg; + dsb(); while( (pPMU_Reg->PMU_PWRDN_ST & idle_video) != 0 ); } if ( (pPMU_Reg->PMU_PWRDN_ST & pd_gpu_pwr_st) == 0 ) { pPMU_Reg->PMU_MISC_CON1 &= ~idle_req_gpu_cfg; + dsb(); while( (pPMU_Reg->PMU_PWRDN_ST & idle_gpu) != 0 ); } @@ -2948,6 +3002,7 @@ uint32_t __sramfunc ddr_change_freq(uint32_t nMHz) flush_cache_all(); outer_flush_all(); flush_tlb_all(); + isb(); DDR_SAVE_SP(save_sp); for(i=0;i<16;i++) { @@ -2997,10 +3052,10 @@ void __sramfunc ddr_suspend(void) volatile unsigned int * temp=(volatile unsigned int *)SRAM_CODE_OFFSET; /** 1. Make sure there is no host access */ - flush_cache_all(); - outer_flush_all(); - flush_tlb_all(); - + //flush_cache_all(); + //outer_flush_all(); + //flush_tlb_all(); + for(i=0;i<16;i++) { n=temp[1024*i]; @@ -3170,7 +3225,7 @@ int ddr_init(uint32_t dram_speed_bin, uint32_t freq) uint32_t cs,die=1; uint32_t gsr,dqstr; - ddr_print("version 1.00 20120608 \n"); + ddr_print("version 1.00 20120820 \n"); mem_type = pPHY_Reg->DCR.b.DDRMD; ddr_speed_bin = dram_speed_bin; @@ -3228,7 +3283,7 @@ int ddr_init(uint32_t dram_speed_bin, uint32_t freq) gsr = pPHY_Reg->DATX8[value].DXGSR[0]; dqstr = pPHY_Reg->DATX8[value].DXDQSTR; ddr_print("DTONE=0x%x, DTERR=0x%x, DTIERR=0x%x, DTPASS=0x%x, DGSL=%d extra clock, DGPS=%d\n", \ - (gsr&0xF), ((gsr>>4)&0xF), ((gsr>>8)&0xF), ((gsr>>13)&0xFFF), (dqstr&0x7), (((dqstr>>12)&0x3)*90)); + (gsr&0xF), ((gsr>>4)&0xF), ((gsr>>8)&0xF), ((gsr>>13)&0xFFF), (dqstr&0x7), ((((dqstr>>12)&0x3)+1)*90)); } ddr_print("ZERR=%x, ZDONE=%x, ZPD=0x%x, ZPU=0x%x, OPD=0x%x, OPU=0x%x\n", \ (pPHY_Reg->ZQ0SR[0]>>30)&0x1, \ From c9a94ee42d1894f0be0947e36d5d3a8c48d5c698 Mon Sep 17 00:00:00 2001 From: Zheng Yang Date: Mon, 20 Aug 2012 18:40:47 +0800 Subject: [PATCH 246/261] rk2928 codec: add speaker control. --- sound/soc/codecs/rk2928_codec.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/soc/codecs/rk2928_codec.c b/sound/soc/codecs/rk2928_codec.c index 5a2fe5dc4d33..54a75a2ec61c 100755 --- a/sound/soc/codecs/rk2928_codec.c +++ b/sound/soc/codecs/rk2928_codec.c @@ -41,6 +41,8 @@ #include "rk2928_codec.h" +#define SPK_CTL RK2928_PIN1_PA0 + static struct rk2928_codec_data { struct device *dev; int regbase; @@ -147,6 +149,9 @@ static int rk2928_audio_trigger(struct snd_pcm_substream *substream, int cmd, if(!rk2928_data.hdmi_enable) rk2928_write(codec, CODEC_REG_DAC_MUTE, v_MUTE_DAC(0)); rk2928_data.mute = 0; + if(SPK_CTL != INVALID_GPIO) { + gpio_direction_output(SPK_CTL, GPIO_HIGH); + } } else { rk2928_write(codec, CODEC_REG_ADC_PGA_GAIN, 0xFF); @@ -158,6 +163,9 @@ static int rk2928_audio_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if(SPK_CTL != INVALID_GPIO) { + gpio_direction_output(SPK_CTL, GPIO_LOW); + } rk2928_write(codec, CODEC_REG_DAC_MUTE, v_MUTE_DAC(1)); rk2928_data.mute = 1; } @@ -241,6 +249,14 @@ static int rk2928_probe(struct snd_soc_codec *codec) // Select SDI input from internal audio codec writel(0x04000400, RK2928_GRF_BASE + GRF_SOC_CON0); + if(SPK_CTL != INVALID_GPIO) { + ret = gpio_request(SPK_CTL, NULL); + if (ret != 0) { + gpio_free(SPK_CTL); + } + else + gpio_direction_output(SPK_CTL, GPIO_LOW); + } // Mute and Power off codec rk2928_write(codec, CODEC_REG_DAC_MUTE, v_MUTE_DAC(1)); rk2928_set_bias_level(codec, SND_SOC_BIAS_OFF); From 6fef705fc0b66d90a8e594a37e577b7b701445d2 Mon Sep 17 00:00:00 2001 From: chenxing Date: Mon, 20 Aug 2012 20:14:33 +0800 Subject: [PATCH 247/261] rk2928:a720: setup frequency 600M for a720 --- arch/arm/mach-rk2928/clock_data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-rk2928/clock_data.c b/arch/arm/mach-rk2928/clock_data.c index 1a734cdb94a4..5b1c0f14c724 100644 --- a/arch/arm/mach-rk2928/clock_data.c +++ b/arch/arm/mach-rk2928/clock_data.c @@ -2486,7 +2486,7 @@ void rk2928_clock_common_i2s_init(void) static void __init rk2928_clock_common_init(unsigned long gpll_rate,unsigned long cpll_rate) { - clk_set_rate_nolock(&clk_core_pre, 816 * MHZ);//816 + clk_set_rate_nolock(&clk_core_pre, 600 * MHZ);//816? //general clk_set_rate_nolock(&general_pll_clk, gpll_rate); //code pll From 0f3b17d283a4ede5d54fd7b5082c7b4b7331744c Mon Sep 17 00:00:00 2001 From: chenxing Date: Mon, 20 Aug 2012 20:19:06 +0800 Subject: [PATCH 248/261] rk2928:sdk: disable unused clocks --- arch/arm/mach-rk2928/clock_data.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-rk2928/clock_data.c b/arch/arm/mach-rk2928/clock_data.c index 5b1c0f14c724..a908f71ae142 100644 --- a/arch/arm/mach-rk2928/clock_data.c +++ b/arch/arm/mach-rk2928/clock_data.c @@ -2200,16 +2200,37 @@ static struct clk_lookup clks[] = { static void __init rk30_init_enable_clocks(void) { CLKDATA_DBG("ENTER %s\n", __func__); - clk_enable_nolock(&clk_core_pre); //cpu + // core + clk_enable_nolock(&clk_core_pre); clk_enable_nolock(&clk_core_periph); + clk_enable_nolock(&clken_core_periph); + clk_enable_nolock(&clk_l2c); + clk_enable_nolock(&aclk_core_pre); + + // logic clk_enable_nolock(&aclk_cpu_pre); clk_enable_nolock(&hclk_cpu_pre); clk_enable_nolock(&pclk_cpu_pre); + // ddr + clk_enable_nolock(&clk_ddrc); + clk_enable_nolock(&clk_ddrphy); + clk_enable_nolock(&clk_ddrphy2x); + clk_enable_nolock(&aclk_periph_pre); clk_enable_nolock(&pclk_periph_pre); clk_enable_nolock(&hclk_periph_pre); + // others + clk_enable_nolock(&clk_aclk_vio0); + clk_enable_nolock(&clk_pclk_pwm01); + clk_enable_nolock(&clk_hclk_otg0); + clk_enable_nolock(&clk_hclk_otg1); + clk_enable_nolock(&clk_pclk_gpio0); + clk_enable_nolock(&clk_pclk_gpio1); + clk_enable_nolock(&clk_pclk_gpio2); + clk_enable_nolock(&clk_pclk_gpio3); + #if CONFIG_RK_DEBUG_UART == 0 clk_enable_nolock(&clk_uart0); clk_enable_nolock(&clk_pclk_uart0); @@ -2580,11 +2601,11 @@ void __init _rk2928_clock_data_init(unsigned long gpll,unsigned long cpll,int fl * enable other clocks as necessary */ rk30_init_enable_clocks(); - /* * Disable any unused clocks left on by the bootloader */ - //clk_disable_unused(); + clk_disable_unused(); + CLKDATA_DBG("rk2928_clock_common_init, gpll=%lu, cpll=%lu\n", gpll, cpll); rk2928_clock_common_init(gpll, cpll); preset_lpj = loops_per_jiffy; From 97044776120135351222b1c3eb9af6816ab93488 Mon Sep 17 00:00:00 2001 From: chenxing Date: Mon, 20 Aug 2012 20:27:32 +0800 Subject: [PATCH 249/261] rk2928:sdk: rename gpio(i) --- arch/arm/mach-rk2928/clock_data.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-rk2928/clock_data.c b/arch/arm/mach-rk2928/clock_data.c index a908f71ae142..a052019f5040 100644 --- a/arch/arm/mach-rk2928/clock_data.c +++ b/arch/arm/mach-rk2928/clock_data.c @@ -1897,10 +1897,10 @@ GATE_CLK(pclk_i2c2, pclk_periph_pre, PCLK_I2C2); GATE_CLK(pclk_i2c3, pclk_periph_pre, PCLK_I2C3); GATE_CLK(pclk_timer0, pclk_periph_pre, PCLK_TIMER0); GATE_CLK(pclk_timer1, pclk_periph_pre, PCLK_TIMER1); -GATE_CLK(pclk_gpio0, pclk_periph_pre, PCLK_GPIO0); -GATE_CLK(pclk_gpio1, pclk_periph_pre, PCLK_GPIO1); -GATE_CLK(pclk_gpio2, pclk_periph_pre, PCLK_GPIO2); -GATE_CLK(pclk_gpio3, pclk_periph_pre, PCLK_GPIO3); +GATE_CLK(gpio0, pclk_periph_pre, PCLK_GPIO0); +GATE_CLK(gpio1, pclk_periph_pre, PCLK_GPIO1); +GATE_CLK(gpio2, pclk_periph_pre, PCLK_GPIO2); +GATE_CLK(gpio3, pclk_periph_pre, PCLK_GPIO3); GATE_CLK(pclk_saradc, pclk_periph_pre, PCLK_SARADC); GATE_CLK(pclk_efuse, pclk_periph_pre, PCLK_EFUSE); @@ -2164,10 +2164,10 @@ static struct clk_lookup clks[] = { CLK("rk30_i2c.3", "i2c", &clk_pclk_i2c3), CLK_GATE_NODEV(pclk_timer0), CLK_GATE_NODEV(pclk_timer1), - CLK_GATE_NODEV(pclk_gpio0), - CLK_GATE_NODEV(pclk_gpio1), - CLK_GATE_NODEV(pclk_gpio2), - CLK_GATE_NODEV(pclk_gpio3), + CLK_GATE_NODEV(gpio0), + CLK_GATE_NODEV(gpio1), + CLK_GATE_NODEV(gpio2), + CLK_GATE_NODEV(gpio3), CLK_GATE_NODEV(pclk_saradc), CLK_GATE_NODEV(pclk_efuse), @@ -2226,10 +2226,10 @@ static void __init rk30_init_enable_clocks(void) clk_enable_nolock(&clk_pclk_pwm01); clk_enable_nolock(&clk_hclk_otg0); clk_enable_nolock(&clk_hclk_otg1); - clk_enable_nolock(&clk_pclk_gpio0); - clk_enable_nolock(&clk_pclk_gpio1); - clk_enable_nolock(&clk_pclk_gpio2); - clk_enable_nolock(&clk_pclk_gpio3); + clk_enable_nolock(&clk_gpio0); + clk_enable_nolock(&clk_gpio1); + clk_enable_nolock(&clk_gpio2); + clk_enable_nolock(&clk_gpio3); #if CONFIG_RK_DEBUG_UART == 0 clk_enable_nolock(&clk_uart0); From e2c1923a259c351c9764b9bbeb6053b74d03d1f2 Mon Sep 17 00:00:00 2001 From: chenxing Date: Mon, 20 Aug 2012 20:31:16 +0800 Subject: [PATCH 250/261] rk2928:sdk: default disable gpio clk --- arch/arm/mach-rk2928/clock_data.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm/mach-rk2928/clock_data.c b/arch/arm/mach-rk2928/clock_data.c index a052019f5040..ab9105c758c7 100644 --- a/arch/arm/mach-rk2928/clock_data.c +++ b/arch/arm/mach-rk2928/clock_data.c @@ -2226,10 +2226,6 @@ static void __init rk30_init_enable_clocks(void) clk_enable_nolock(&clk_pclk_pwm01); clk_enable_nolock(&clk_hclk_otg0); clk_enable_nolock(&clk_hclk_otg1); - clk_enable_nolock(&clk_gpio0); - clk_enable_nolock(&clk_gpio1); - clk_enable_nolock(&clk_gpio2); - clk_enable_nolock(&clk_gpio3); #if CONFIG_RK_DEBUG_UART == 0 clk_enable_nolock(&clk_uart0); From d663394000152d4cd86ee8568762a46ecdc65189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Mon, 20 Aug 2012 20:52:44 +0800 Subject: [PATCH 251/261] rk2928: usb_detect: support bvalid irq wake up system --- arch/arm/plat-rk/usb_detect.c | 53 ++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/arch/arm/plat-rk/usb_detect.c b/arch/arm/plat-rk/usb_detect.c index a71a60c8a823..411b0dd5aa6d 100644 --- a/arch/arm/plat-rk/usb_detect.c +++ b/arch/arm/plat-rk/usb_detect.c @@ -4,6 +4,8 @@ #include #include +#define WAKE_LOCK_TIMEOUT (10 * HZ) + static irqreturn_t usb_detect_irq_handler(int irq, void *dev_id); static int detect_gpio = INVALID_GPIO; @@ -28,7 +30,7 @@ static struct wake_lock usb_wakelock; static irqreturn_t usb_detect_irq_handler(int irq, void *dev_id) { - wake_lock_timeout(&usb_wakelock, 10 * HZ); + wake_lock_timeout(&usb_wakelock, WAKE_LOCK_TIMEOUT); schedule_delayed_work(&wakeup_work, HZ / 10); return IRQ_HANDLED; } @@ -72,3 +74,52 @@ int board_usb_detect_init(unsigned gpio) return 0; } +#if defined(CONFIG_ARCH_RK2928) +#include +#include + +static irqreturn_t bvalid_irq_handler(int irq, void *dev_id) +{ + /* clear irq */ +#ifdef CONFIG_ARCH_RK2928 + writel_relaxed((1 << 31) | (1 << 15), RK2928_GRF_BASE + GRF_UOC0_CON5); +#endif + + wake_lock_timeout(&usb_wakelock, WAKE_LOCK_TIMEOUT); + rk28_send_wakeup_key(); + + return IRQ_HANDLED; +} + +static int bvalid_init(void) +{ + int ret; + int irq = IRQ_OTG_BVALID; + + if (detect_gpio != INVALID_GPIO) { + printk("usb detect inited by board_usb_detect_init, disable detect by bvalid irq\n"); + return 0; + } + + if (!wakelock_inited) { + wake_lock_init(&usb_wakelock, WAKE_LOCK_SUSPEND, "usb_detect"); + wakelock_inited = true; + } + + ret = request_irq(irq, bvalid_irq_handler, 0, "bvalid", NULL); + if (ret < 0) { + pr_err("%s: request_irq(%d) failed\n", __func__, irq); + return ret; + } + + /* enable bvalid irq */ +#ifdef CONFIG_ARCH_RK2928 + writel_relaxed((1 << 30) | (1 << 14), RK2928_GRF_BASE + GRF_UOC0_CON5); +#endif + + enable_irq_wake(irq); + + return 0; +} +late_initcall(bvalid_init); +#endif From ac2bc560e8ee759fa7904d9e4d8c345818ff2c56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Mon, 20 Aug 2012 20:53:41 +0800 Subject: [PATCH 252/261] rk2928: pm: fix unable to suspend bug --- arch/arm/mach-rk2928/pm.c | 42 ++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/arch/arm/mach-rk2928/pm.c b/arch/arm/mach-rk2928/pm.c index 0591da0f482f..56dbb22cb9b0 100755 --- a/arch/arm/mach-rk2928/pm.c +++ b/arch/arm/mach-rk2928/pm.c @@ -276,7 +276,7 @@ static void __sramfunc rk2928_sram_suspend(void) | (1 << CLK_GATE_PCLK_CPU) | (1 << CLK_GATE_ACLK_CORE) , clkgt_regs[0], CRU_CLKGATES_CON(0), 0xffff); - if (!(clkgt_regs[8] & (0xf << (CLK_GATE_PCLK_GPIO0 % 16)))) { + if (((clkgt_regs[8] >> (CLK_GATE_PCLK_GPIO0 % 16)) & 0xf) != 0xf) { gate_save_soc_clk(0 | (1 << CLK_GATE_PERIPH_SRC % 16) | (1 << CLK_GATE_PCLK_PERIPH % 16) @@ -295,7 +295,7 @@ static void __sramfunc rk2928_sram_suspend(void) gate_save_soc_clk(0, clkgt_regs[7], CRU_CLKGATES_CON(7), 0xffff); gate_save_soc_clk(0 | (1 << CLK_GATE_CLK_L2C % 16) - , clkgt_regs[9], CRU_CLKGATES_CON(9), 0x07ff); + , clkgt_regs[9], CRU_CLKGATES_CON(9), 0xffff); board_pmu_suspend(); cru_clksel0_con = cru_readl(CRU_CLKSELS_CON(0)); @@ -354,6 +354,7 @@ static int rk2928_pm_enter(suspend_state_t state) gate_save_soc_clk(0 | (1 << CLK_GATE_CORE_PERIPH) + | (1 << CLK_GATE_CPU_GPLL) | (1 << CLK_GATE_DDRPHY_SRC) | (1 << CLK_GATE_ACLK_CPU) | (1 << CLK_GATE_HCLK_CPU) @@ -366,7 +367,7 @@ static int rk2928_pm_enter(suspend_state_t state) | (1 << CLK_GATE_PCLK_PERIPH % 16) | (1 << CLK_GATE_ACLK_PERIPH % 16) , clkgt_regs[2], CRU_CLKGATES_CON(2), 0xffff); - gate_save_soc_clk(0, clkgt_regs[3], CRU_CLKGATES_CON(3), 0xff9f); + gate_save_soc_clk(0, clkgt_regs[3], CRU_CLKGATES_CON(3), 0xffff); gate_save_soc_clk(0 | (1 << CLK_GATE_HCLK_PERI_AXI_MATRIX % 16) | (1 << CLK_GATE_PCLK_PERI_AXI_MATRIX % 16) @@ -381,19 +382,31 @@ static int rk2928_pm_enter(suspend_state_t state) , clkgt_regs[5], CRU_CLKGATES_CON(5), 0xffff); gate_save_soc_clk(0, clkgt_regs[6], CRU_CLKGATES_CON(6), 0xffff); gate_save_soc_clk(0 - |(1 << CLK_GATE_PCLK_PWM01%16) + | (1 << CLK_GATE_PCLK_PWM01 % 16) , clkgt_regs[7], CRU_CLKGATES_CON(7), 0xffff); - gate_save_soc_clk(0, clkgt_regs[8], CRU_CLKGATES_CON(8), 0x01ff); + gate_save_soc_clk(0 + | (1 << CLK_GATE_PCLK_GPIO0 % 16) + | (1 << CLK_GATE_PCLK_GPIO1 % 16) + | (1 << CLK_GATE_PCLK_GPIO2 % 16) + | (1 << CLK_GATE_PCLK_GPIO3 % 16) + , clkgt_regs[8], CRU_CLKGATES_CON(8), 0xffff); gate_save_soc_clk(0 | (1 << CLK_GATE_CLK_L2C % 16) | (1 << CLK_GATE_HCLK_PERI_ARBI % 16) | (1 << CLK_GATE_ACLK_PERI_NIU % 16) - , clkgt_regs[9], CRU_CLKGATES_CON(9), 0x07ff); + , clkgt_regs[9], CRU_CLKGATES_CON(9), 0xffff); sram_printch('2'); cru_mode_con = cru_readl(CRU_MODE_CON); + //apll + clk_sel0 = cru_readl(CRU_CLKSELS_CON(0)); + clk_sel1 = cru_readl(CRU_CLKSELS_CON(1)); + cru_writel(PLL_MODE_SLOW(APLL_ID), CRU_MODE_CON); + cru_writel(CLK_CORE_DIV(1) | ACLK_CPU_DIV(1) | CPU_SEL_PLL(SEL_APLL), CRU_CLKSELS_CON(0)); + cru_writel(CLK_CORE_PERI_DIV(1) | ACLK_CORE_DIV(1) | HCLK_CPU_DIV(1) | PCLK_CPU_DIV(1), CRU_CLKSELS_CON(1)); + //cpll cru_writel(PLL_MODE_SLOW(CPLL_ID), CRU_MODE_CON); @@ -405,13 +418,6 @@ static int rk2928_pm_enter(suspend_state_t state) | PERI_SET_A2P_RATIO(RATIO_11) , CRU_CLKSELS_CON(10)); - //apll - clk_sel0 = cru_readl(CRU_CLKSELS_CON(0)); - clk_sel1 = cru_readl(CRU_CLKSELS_CON(1)); - cru_writel(PLL_MODE_SLOW(APLL_ID), CRU_MODE_CON); - cru_writel(CLK_CORE_DIV(1) | ACLK_CPU_DIV(1), CRU_CLKSELS_CON(0)); - cru_writel(CLK_CORE_PERI_DIV(1) | ACLK_CORE_DIV(1) | HCLK_CPU_DIV(1) | PCLK_CPU_DIV(1), CRU_CLKSELS_CON(1)); - sram_printch('3'); rk30_pwm_suspend_voltage_set(); @@ -427,11 +433,6 @@ static int rk2928_pm_enter(suspend_state_t state) rk30_pwm_resume_voltage_set(); sram_printch('3'); - //apll - cru_writel(0xffff0000 | clk_sel1, CRU_CLKSELS_CON(1)); - cru_writel(0xffff0000 | clk_sel0, CRU_CLKSELS_CON(0)); - cru_writel((PLL_MODE_MSK(APLL_ID) << 16) | (PLL_MODE_MSK(APLL_ID) & cru_mode_con), CRU_MODE_CON); - //gpll cru_writel(0xffff0000 | clk_sel10, CRU_CLKSELS_CON(10)); cru_writel(clk_sel10, CRU_CLKSELS_CON(10)); @@ -440,6 +441,11 @@ static int rk2928_pm_enter(suspend_state_t state) //cpll cru_writel((PLL_MODE_MSK(CPLL_ID) << 16) | (PLL_MODE_MSK(CPLL_ID) & cru_mode_con), CRU_MODE_CON); + //apll + cru_writel(0xffff0000 | clk_sel1, CRU_CLKSELS_CON(1)); + cru_writel(0xffff0000 | clk_sel0, CRU_CLKSELS_CON(0)); + cru_writel((PLL_MODE_MSK(APLL_ID) << 16) | (PLL_MODE_MSK(APLL_ID) & cru_mode_con), CRU_MODE_CON); + sram_printch('2'); for (i = 0; i < CRU_CLKGATES_CON_CNT; i++) { From 9edeaf1839534f9ceeaca8b78470a491c8019939 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=8B=E7=A7=80=E6=9D=B0?= Date: Mon, 20 Aug 2012 22:35:49 +0800 Subject: [PATCH 253/261] phonepad: make rt3261 incall volume control work. --- sound/soc/codecs/rt3261.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt3261.c b/sound/soc/codecs/rt3261.c index f7e18dd050a7..863991ccd304 100644 --- a/sound/soc/codecs/rt3261.c +++ b/sound/soc/codecs/rt3261.c @@ -821,10 +821,13 @@ static const struct snd_kcontrol_new rt3261_snd_controls[] = { SOC_DOUBLE_EXT_TLV("Speaker Playback Volume", RT3261_SPK_VOL, RT3261_L_VOL_SFT, RT3261_R_VOL_SFT, RT3261_VOL_RSCL_RANGE, 0, rt3261_vol_rescale_get, rt3261_vol_rescale_put, out_vol_tlv), + SOC_DOUBLE_EXT_TLV("Earpiece Playback Volume", RT3261_SPK_VOL, + RT3261_L_VOL_SFT, RT3261_R_VOL_SFT, RT3261_VOL_RSCL_RANGE, 0, + rt3261_vol_rescale_get, rt3261_vol_rescale_put, out_vol_tlv), /* Headphone Output Volume */ SOC_DOUBLE("HP Playback Switch", RT3261_HP_VOL, RT3261_L_MUTE_SFT, RT3261_R_MUTE_SFT, 1, 1), - SOC_DOUBLE_EXT_TLV("HP Playback Volume", RT3261_HP_VOL, + SOC_DOUBLE_EXT_TLV("Headphone Playback Volume", RT3261_HP_VOL, RT3261_L_VOL_SFT, RT3261_R_VOL_SFT, RT3261_VOL_RSCL_RANGE, 0, rt3261_vol_rescale_get, rt3261_vol_rescale_put, out_vol_tlv), /* OUTPUT Control */ From 62669068b886d34771cd13a19f4517ab2ab8d4a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Tue, 21 Aug 2012 09:08:32 +0800 Subject: [PATCH 254/261] rk2928: usb_detect: mark bvalid_init as __init, clear bvalid irq when init --- arch/arm/plat-rk/usb_detect.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/plat-rk/usb_detect.c b/arch/arm/plat-rk/usb_detect.c index 411b0dd5aa6d..40a46884d036 100644 --- a/arch/arm/plat-rk/usb_detect.c +++ b/arch/arm/plat-rk/usb_detect.c @@ -91,7 +91,7 @@ static irqreturn_t bvalid_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -static int bvalid_init(void) +static int __init bvalid_init(void) { int ret; int irq = IRQ_OTG_BVALID; @@ -112,9 +112,9 @@ static int bvalid_init(void) return ret; } - /* enable bvalid irq */ + /* clear & enable bvalid irq */ #ifdef CONFIG_ARCH_RK2928 - writel_relaxed((1 << 30) | (1 << 14), RK2928_GRF_BASE + GRF_UOC0_CON5); + writel_relaxed((3 << 30) | (3 << 14), RK2928_GRF_BASE + GRF_UOC0_CON5); #endif enable_irq_wake(irq); From ebfe38927fc4e87d927cbfc15df2085834ca441a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Tue, 21 Aug 2012 09:36:17 +0800 Subject: [PATCH 255/261] rk: usb_detect: mark board_usb_detect_init as __init, use irq_set_irq_type support both edge trigger --- arch/arm/plat-rk/include/plat/board.h | 2 +- arch/arm/plat-rk/usb_detect.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm/plat-rk/include/plat/board.h b/arch/arm/plat-rk/include/plat/board.h index 9b3576be7d5d..4a97fe415e9a 100755 --- a/arch/arm/plat-rk/include/plat/board.h +++ b/arch/arm/plat-rk/include/plat/board.h @@ -190,7 +190,7 @@ int board_boot_mode(void); /* for USB detection */ #ifdef CONFIG_USB_GADGET -int board_usb_detect_init(unsigned gpio); +int __init board_usb_detect_init(unsigned gpio); #else static int inline board_usb_detect_init(unsigned gpio) { return 0; } #endif diff --git a/arch/arm/plat-rk/usb_detect.c b/arch/arm/plat-rk/usb_detect.c index 40a46884d036..267ce2546168 100644 --- a/arch/arm/plat-rk/usb_detect.c +++ b/arch/arm/plat-rk/usb_detect.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -13,14 +14,13 @@ static void usb_detect_do_wakeup(struct work_struct *work) { int ret; int irq = gpio_to_irq(detect_gpio); - unsigned long flags; + unsigned int type; rk28_send_wakeup_key(); - free_irq(irq, NULL); - flags = gpio_get_value(detect_gpio) ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING; - ret = request_irq(irq, usb_detect_irq_handler, flags, "usb_detect", NULL); + type = gpio_get_value(detect_gpio) ? IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING; + ret = irq_set_irq_type(irq, type); if (ret < 0) { - pr_err("%s: request_irq(%d) failed\n", __func__, irq); + pr_err("%s: irq_set_irq_type(%d, %d) failed\n", __func__, irq, type); } } @@ -35,7 +35,7 @@ static irqreturn_t usb_detect_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -int board_usb_detect_init(unsigned gpio) +int __init board_usb_detect_init(unsigned gpio) { int ret; int irq = gpio_to_irq(gpio); From f2428c1dff932a5f15edc2335908113dd9b60599 Mon Sep 17 00:00:00 2001 From: Zheng Yang Date: Tue, 21 Aug 2012 09:50:46 +0800 Subject: [PATCH 256/261] rk2928: acodec: move audio codec platform device registration to board file to configure speaker control pin. --- arch/arm/mach-rk2928/board-rk2928-a720.c | 25 ++++++++++++++++ arch/arm/mach-rk2928/board-rk2928-sdk.c | 25 ++++++++++++++++ arch/arm/mach-rk2928/devices.c | 20 ------------- sound/soc/codecs/rk2928_codec.c | 37 +++++++++++++++--------- 4 files changed, 73 insertions(+), 34 deletions(-) diff --git a/arch/arm/mach-rk2928/board-rk2928-a720.c b/arch/arm/mach-rk2928/board-rk2928-a720.c index 0bc1895fc61b..9ee25c281577 100755 --- a/arch/arm/mach-rk2928/board-rk2928-a720.c +++ b/arch/arm/mach-rk2928/board-rk2928-a720.c @@ -436,6 +436,28 @@ struct rk29_sdmmc_platform_data default_sdmmc0_data = { }; #endif // CONFIG_SDMMC0_RK29 +#ifdef CONFIG_SND_SOC_RK2928 +static struct resource resources_acodec[] = { + { + .start = RK2928_ACODEC_PHYS, + .end = RK2928_ACODEC_PHYS + RK2928_ACODEC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = RK2928_PIN1_PA0, + .end = RK2928_PIN1_PA0, + .flags = IORESOURCE_IO, + }, +}; + +static struct platform_device device_acodec = { + .name = "rk2928-codec", + .id = -1, + .num_resources = ARRAY_SIZE(resources_acodec), + .resource = resources_acodec, +}; +#endif + static struct platform_device *devices[] __initdata = { #ifdef CONFIG_BACKLIGHT_RK29_BL &rk29_device_backlight, @@ -446,6 +468,9 @@ static struct platform_device *devices[] __initdata = { #ifdef CONFIG_ION &device_ion, #endif +#ifdef CONFIG_SND_SOC_RK2928 + &device_acodec, +#endif }; //i2c #ifdef CONFIG_I2C0_RK30 diff --git a/arch/arm/mach-rk2928/board-rk2928-sdk.c b/arch/arm/mach-rk2928/board-rk2928-sdk.c index 0eb825055991..0e743011f20f 100755 --- a/arch/arm/mach-rk2928/board-rk2928-sdk.c +++ b/arch/arm/mach-rk2928/board-rk2928-sdk.c @@ -636,6 +636,28 @@ static struct platform_device device_rfkill_rk = { }; #endif +#ifdef CONFIG_SND_SOC_RK2928 +static struct resource resources_acodec[] = { + { + .start = RK2928_ACODEC_PHYS, + .end = RK2928_ACODEC_PHYS + RK2928_ACODEC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = RK2928_PIN3_PD4, + .end = RK2928_PIN3_PD4, + .flags = IORESOURCE_IO, + }, +}; + +static struct platform_device device_acodec = { + .name = "rk2928-codec", + .id = -1, + .num_resources = ARRAY_SIZE(resources_acodec), + .resource = resources_acodec, +}; +#endif + static struct platform_device *devices[] __initdata = { #ifdef CONFIG_BACKLIGHT_RK29_BL &rk29_device_backlight, @@ -652,6 +674,9 @@ static struct platform_device *devices[] __initdata = { #ifdef CONFIG_RFKILL_RK &device_rfkill_rk, #endif +#ifdef CONFIG_SND_SOC_RK2928 + &device_acodec, +#endif }; //i2c #ifdef CONFIG_I2C0_RK30 diff --git a/arch/arm/mach-rk2928/devices.c b/arch/arm/mach-rk2928/devices.c index 9be98c671c93..c5eab43b1f3f 100755 --- a/arch/arm/mach-rk2928/devices.c +++ b/arch/arm/mach-rk2928/devices.c @@ -786,23 +786,6 @@ static void __init rk2928_init_sdmmc(void) #endif } -#ifdef CONFIG_SND_SOC_RK2928 -static struct resource resources_acodec[] = { - { - .start = RK2928_ACODEC_PHYS, - .end = RK2928_ACODEC_PHYS + RK2928_ACODEC_SIZE - 1, - .flags = IORESOURCE_MEM, - }, -}; - -static struct platform_device device_acodec = { - .name = "rk2928-codec", - .id = -1, - .num_resources = ARRAY_SIZE(resources_acodec), - .resource = resources_acodec, -}; -#endif - static struct resource resource_arm_pmu = { .start = IRQ_ARM_PMU, .end = IRQ_ARM_PMU, @@ -848,9 +831,6 @@ static int __init rk2928_init_devices(void) rk_serial_debug_init(DEBUG_UART_BASE, IRQ_DEBUG_UART, IRQ_UART_SIGNAL, -1); #endif rk2928_init_i2s(); -#ifdef CONFIG_SND_SOC_RK2928 - platform_device_register(&device_acodec); -#endif #ifdef CONFIG_HDMI_RK2928 platform_device_register(&device_hdmi); #endif diff --git a/sound/soc/codecs/rk2928_codec.c b/sound/soc/codecs/rk2928_codec.c index 54a75a2ec61c..a31276077b7d 100755 --- a/sound/soc/codecs/rk2928_codec.c +++ b/sound/soc/codecs/rk2928_codec.c @@ -41,8 +41,6 @@ #include "rk2928_codec.h" -#define SPK_CTL RK2928_PIN1_PA0 - static struct rk2928_codec_data { struct device *dev; int regbase; @@ -50,6 +48,7 @@ static struct rk2928_codec_data { int regsize_phy; int mute; int hdmi_enable; + int spkctl; } rk2928_data; static const struct snd_soc_dapm_widget rk2928_dapm_widgets[] = { @@ -149,8 +148,8 @@ static int rk2928_audio_trigger(struct snd_pcm_substream *substream, int cmd, if(!rk2928_data.hdmi_enable) rk2928_write(codec, CODEC_REG_DAC_MUTE, v_MUTE_DAC(0)); rk2928_data.mute = 0; - if(SPK_CTL != INVALID_GPIO) { - gpio_direction_output(SPK_CTL, GPIO_HIGH); + if(rk2928_data.spkctl != INVALID_GPIO) { + gpio_direction_output(rk2928_data.spkctl, GPIO_HIGH); } } else { @@ -163,8 +162,8 @@ static int rk2928_audio_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - if(SPK_CTL != INVALID_GPIO) { - gpio_direction_output(SPK_CTL, GPIO_LOW); + if(rk2928_data.spkctl != INVALID_GPIO) { + gpio_direction_output(rk2928_data.spkctl, GPIO_LOW); } rk2928_write(codec, CODEC_REG_DAC_MUTE, v_MUTE_DAC(1)); rk2928_data.mute = 1; @@ -246,17 +245,27 @@ static int rk2928_probe(struct snd_soc_codec *codec) ret = -ENXIO; goto err1; } + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if(!res) { + rk2928_data.spkctl = INVALID_GPIO; + } + else { + rk2928_data.spkctl = res->start; + } + + if(rk2928_data.spkctl != INVALID_GPIO) { + ret = gpio_request(rk2928_data.spkctl, NULL); + if (ret != 0) { + gpio_free(rk2928_data.spkctl); + } + else + gpio_direction_output(rk2928_data.spkctl, GPIO_LOW); + } + // Select SDI input from internal audio codec writel(0x04000400, RK2928_GRF_BASE + GRF_SOC_CON0); - if(SPK_CTL != INVALID_GPIO) { - ret = gpio_request(SPK_CTL, NULL); - if (ret != 0) { - gpio_free(SPK_CTL); - } - else - gpio_direction_output(SPK_CTL, GPIO_LOW); - } // Mute and Power off codec rk2928_write(codec, CODEC_REG_DAC_MUTE, v_MUTE_DAC(1)); rk2928_set_bias_level(codec, SND_SOC_BIAS_OFF); From 42205e957934325440d191a695a7f28a4fd39fa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E7=9B=9B=E9=A3=9E?= Date: Tue, 21 Aug 2012 11:13:44 +0800 Subject: [PATCH 257/261] slove the bug -- support gpio3 and gpio4 interrupt wake up sysytem --- arch/arm/mach-rk30/pm.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-rk30/pm.c b/arch/arm/mach-rk30/pm.c index 055999f64d5e..03b08f8c6383 100644 --- a/arch/arm/mach-rk30/pm.c +++ b/arch/arm/mach-rk30/pm.c @@ -377,14 +377,18 @@ static void __sramfunc rk30_sram_suspend(void) | (1 << CLK_GATE_PCLK_CPU) , clkgt_regs[0], CRU_CLKGATES_CON(0), 0xffff); gate_save_soc_clk(0, clkgt_regs[1], CRU_CLKGATES_CON(1), 0xffff); - if(clkgt_regs[8]&((1<<12)|(1<13))){ + //if(clkgt_regs[8]&((1<> CLK_GATE_PCLK_GPIO3% 16) & 0x03) == 0x03){ + gate_save_soc_clk(0 + , clkgt_regs[2], CRU_CLKGATES_CON(2), 0xffff); + + }else{ gate_save_soc_clk(0 | (1 << CLK_GATE_PERIPH_SRC % 16) | (1 << CLK_GATE_PCLK_PERIPH % 16) , clkgt_regs[2], CRU_CLKGATES_CON(2), 0xffff); - }else{ - gate_save_soc_clk(0 - , clkgt_regs[2], CRU_CLKGATES_CON(2), 0xffff); + sram_printch('8'); + } gate_save_soc_clk(0 From 55a4cbf7c8084bcbd6f2e5eed7d0715c1843fe8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E7=9B=9B=E9=A3=9E?= Date: Tue, 21 Aug 2012 11:23:00 +0800 Subject: [PATCH 258/261] rk30: rm the sram_printch(8) --- arch/arm/mach-rk30/pm.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm/mach-rk30/pm.c b/arch/arm/mach-rk30/pm.c index 03b08f8c6383..99fb2ca7a280 100644 --- a/arch/arm/mach-rk30/pm.c +++ b/arch/arm/mach-rk30/pm.c @@ -387,9 +387,6 @@ static void __sramfunc rk30_sram_suspend(void) | (1 << CLK_GATE_PERIPH_SRC % 16) | (1 << CLK_GATE_PCLK_PERIPH % 16) , clkgt_regs[2], CRU_CLKGATES_CON(2), 0xffff); - sram_printch('8'); - - } gate_save_soc_clk(0 | (1 << CLK_GATE_ACLK_STRC_SYS % 16) From ca6be0fe2207cb125db911d9823ee75897a81a86 Mon Sep 17 00:00:00 2001 From: lw Date: Tue, 21 Aug 2012 11:51:35 +0800 Subject: [PATCH 259/261] phonepad:add touch screen Kconfig again --- drivers/input/touchscreen/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 50d915718bcc..c4b92a3d671d 100755 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -969,6 +969,10 @@ config LAIBAO_TS config TOUCHSCREEN_GT801_IIC tristate "GT801_IIC based touchscreens" depends on I2C2_RK29 + +config TOUCHSCREEN_GT82X_IIC + tristate "GT82x_IIC based touchscreens" + depends on I2C2_RK30 config TOUCHSCREEN_GT818_IIC tristate "GT818_IIC based touchscreens" From 64fdea83d9575773f8015c5f8b708d30c04057da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Tue, 21 Aug 2012 11:57:29 +0800 Subject: [PATCH 260/261] logo: bmp: default n --- drivers/video/logo/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig index a783e87086c2..b53c9627852e 100755 --- a/drivers/video/logo/Kconfig +++ b/drivers/video/logo/Kconfig @@ -29,7 +29,6 @@ config LOGO_LINUX_CLUT224 config LOGO_LINUX_BMP bool "bmp logo" - default y config LOGO_BLACKFIN_VGA16 bool "16-colour Blackfin Processor Linux logo" From beb9e50ebc85126c78554632f50ec6bcfa0da55e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=99=B4?= Date: Tue, 21 Aug 2012 12:04:40 +0800 Subject: [PATCH 261/261] rk2928:sdk and a720:support pmu sleep --- .../mach-rk2928/board-rk2928-a720-tps65910.c | 50 ++++++------- .../mach-rk2928/board-rk2928-sdk-tps65910.c | 72 +++++++++---------- 2 files changed, 52 insertions(+), 70 deletions(-) diff --git a/arch/arm/mach-rk2928/board-rk2928-a720-tps65910.c b/arch/arm/mach-rk2928/board-rk2928-a720-tps65910.c index 7f6eec382855..3193edb5e40e 100755 --- a/arch/arm/mach-rk2928/board-rk2928-a720-tps65910.c +++ b/arch/arm/mach-rk2928/board-rk2928-a720-tps65910.c @@ -7,23 +7,15 @@ #include #include -#define grf_readl(offset) readl_relaxed(RK30_GRF_BASE + offset) -#define grf_writel(v, offset) do { writel_relaxed(v, RK30_GRF_BASE + offset); dsb(); } while (0) +#define gpio_readl(offset) readl_relaxed(RK2928_GPIO1_BASE + offset) +#define gpio_writel(v, offset) do { writel_relaxed(v, RK2928_GPIO1_BASE + offset); dsb(); } while (0) -#define CRU_CLKGATE5_CON_ADDR 0x00e4 -#define GRF_GPIO6L_DIR_ADDR 0x0030 -#define GRF_GPIO6L_DO_ADDR 0x0068 -#define GRF_GPIO6L_EN_ADDR 0x00a0 -#define GPIO6_PB3_DIR_OUT 0x08000800 -#define GPIO6_PB3_DO_LOW 0x08000000 -#define GPIO6_PB3_DO_HIGH 0x08000800 -#define GPIO6_PB3_EN_MASK 0x08000800 -#define GPIO6_PB3_UNEN_MASK 0x08000000 -#define GPIO6_PB1_DIR_OUT 0x02000200 -#define GPIO6_PB1_DO_LOW 0x02000000 -#define GPIO6_PB1_DO_HIGH 0x02000200 -#define GPIO6_PB1_EN_MASK 0x02000200 -#define GPIO6_PB1_UNEN_MASK 0x02000000 +#define GPIO_SWPORTA_DR 0x0000 +#define GPIO_SWPORTA_DDR 0x0004 + +#define GPIO1_A1_OUTPUT (1<<1) +#define GPIO1_A1_OUTPUT_HIGH (1<<1) +#define GPIO1_A1_OUTPUT_LOW (~(1<<1)) #ifdef CONFIG_MFD_TPS65910 #define PMU_POWER_SLEEP RK2928_PIN1_PA1 @@ -578,25 +570,23 @@ static struct regulator_init_data tps65910_ldo8 = { .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo8_supply), .consumer_supplies = tps65910_ldo8_supply, }; -/* -void __sramfunc board_pmu_tps65910_suspend(void) +void __sramfunc board_pmu_suspend(void) { - grf_writel(GPIO6_PB1_DIR_OUT, GRF_GPIO6L_DIR_ADDR); - grf_writel(GPIO6_PB1_DO_HIGH, GRF_GPIO6L_DO_ADDR); //set gpio6_b1 output low - grf_writel(GPIO6_PB1_EN_MASK, GRF_GPIO6L_EN_ADDR); + int ret; + ret = gpio_readl(GPIO_SWPORTA_DDR); + gpio_writel(ret | GPIO1_A1_OUTPUT, GPIO_SWPORTA_DDR); + ret = gpio_readl(GPIO_SWPORTA_DR); + gpio_writel(ret | GPIO1_A1_OUTPUT_HIGH, GPIO_SWPORTA_DR); //set pmu_sleep output high } -void __sramfunc board_pmu_tps65910_resume(void) +void __sramfunc board_pmu_resume(void) { - grf_writel(GPIO6_PB1_DIR_OUT, GRF_GPIO6L_DIR_ADDR); - grf_writel(GPIO6_PB1_DO_LOW, GRF_GPIO6L_DO_ADDR); //set gpio6_b1 output low - grf_writel(GPIO6_PB1_EN_MASK, GRF_GPIO6L_EN_ADDR); - #ifdef CONFIG_CLK_SWITCH_TO_32K //switch clk to 24M - sram_32k_udelay(10000); - #else + int ret; + ret = gpio_readl(GPIO_SWPORTA_DDR); + gpio_writel(ret | GPIO1_A1_OUTPUT, GPIO_SWPORTA_DDR); + ret = gpio_readl(GPIO_SWPORTA_DR); + gpio_writel(ret & GPIO1_A1_OUTPUT_LOW, GPIO_SWPORTA_DR); //set pmu_sleep output low sram_udelay(2000); - #endif } -*/ static struct tps65910_board tps65910_data = { .irq = (unsigned)TPS65910_HOST_IRQ, .irq_base = NR_GIC_IRQS + NR_GPIO_IRQS, diff --git a/arch/arm/mach-rk2928/board-rk2928-sdk-tps65910.c b/arch/arm/mach-rk2928/board-rk2928-sdk-tps65910.c index 4b8d6058d3ee..1a8773b6d1bb 100755 --- a/arch/arm/mach-rk2928/board-rk2928-sdk-tps65910.c +++ b/arch/arm/mach-rk2928/board-rk2928-sdk-tps65910.c @@ -7,23 +7,15 @@ #include #include -#define grf_readl(offset) readl_relaxed(RK30_GRF_BASE + offset) -#define grf_writel(v, offset) do { writel_relaxed(v, RK30_GRF_BASE + offset); dsb(); } while (0) +#define gpio_readl(offset) readl_relaxed(RK2928_GPIO3_BASE + offset) +#define gpio_writel(v, offset) do { writel_relaxed(v, RK2928_GPIO3_BASE + offset); dsb(); } while (0) -#define CRU_CLKGATE5_CON_ADDR 0x00e4 -#define GRF_GPIO6L_DIR_ADDR 0x0030 -#define GRF_GPIO6L_DO_ADDR 0x0068 -#define GRF_GPIO6L_EN_ADDR 0x00a0 -#define GPIO6_PB3_DIR_OUT 0x08000800 -#define GPIO6_PB3_DO_LOW 0x08000000 -#define GPIO6_PB3_DO_HIGH 0x08000800 -#define GPIO6_PB3_EN_MASK 0x08000800 -#define GPIO6_PB3_UNEN_MASK 0x08000000 -#define GPIO6_PB1_DIR_OUT 0x02000200 -#define GPIO6_PB1_DO_LOW 0x02000000 -#define GPIO6_PB1_DO_HIGH 0x02000200 -#define GPIO6_PB1_EN_MASK 0x02000200 -#define GPIO6_PB1_UNEN_MASK 0x02000000 +#define GPIO_SWPORTA_DR 0x0000 +#define GPIO_SWPORTA_DDR 0x0004 + +#define GPIO3_D2_OUTPUT (1<<26) +#define GPIO3_D2_OUTPUT_HIGH (1<<26) +#define GPIO3_D2_OUTPUT_LOW (~(1<<26)) #ifdef CONFIG_MFD_TPS65910 #define PMU_POWER_SLEEP RK2928_PIN3_PD2 @@ -256,10 +248,10 @@ int tps65910_post_init(struct tps65910 *tps65910) regulator_put(ldo); udelay(100); - ldo = regulator_get(NULL, "vdig2"); // vdd11 + ldo = regulator_get(NULL, "vdig2"); // vdd12 regulator_set_voltage(ldo, 1200000, 1200000); regulator_enable(ldo); - printk("%s set vdig2 vdd11=%dmV end\n", __func__, regulator_get_voltage(ldo)); + printk("%s set vdig2 vdd12=%dmV end\n", __func__, regulator_get_voltage(ldo)); regulator_put(ldo); udelay(100); @@ -291,10 +283,10 @@ int tps65910_post_init(struct tps65910 *tps65910) regulator_put(ldo); udelay(100); - dcdc = regulator_get(NULL, "vaux1"); //vcc25_hdmi - regulator_set_voltage(dcdc,2500000,2500000); + dcdc = regulator_get(NULL, "vaux1"); //vcc28_cif + regulator_set_voltage(dcdc,2800000,2800000); regulator_enable(dcdc); - printk("%s set vaux1 vcc25_hdmi=%dmV end\n", __func__, regulator_get_voltage(dcdc)); + printk("%s set vaux1 vcc28_cif=%dmV end\n", __func__, regulator_get_voltage(dcdc)); regulator_put(dcdc); udelay(100); @@ -305,17 +297,17 @@ int tps65910_post_init(struct tps65910 *tps65910) regulator_put(ldo); udelay(100); - ldo = regulator_get(NULL, "vdac"); // vccio_wl + ldo = regulator_get(NULL, "vdac"); // regulator_set_voltage(ldo,1800000,1800000); regulator_enable(ldo); - printk("%s set vdac vccio_wl=%dmV end\n", __func__, regulator_get_voltage(ldo)); + printk("%s set vdac =%dmV end\n", __func__, regulator_get_voltage(ldo)); regulator_put(ldo); udelay(100); - ldo = regulator_get(NULL, "vmmc"); //vcc28_cif - regulator_set_voltage(ldo,2800000,2800000); + ldo = regulator_get(NULL, "vmmc"); //vccio_wl + regulator_set_voltage(ldo,3300000,3300000); regulator_enable(ldo); - printk("%s set vmmc vcc28_cif=%dmV end\n", __func__, regulator_get_voltage(ldo)); + printk("%s set vmmc vccio_wl=%dmV end\n", __func__, regulator_get_voltage(ldo)); regulator_put(ldo); udelay(100); @@ -578,25 +570,25 @@ static struct regulator_init_data tps65910_ldo8 = { .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo8_supply), .consumer_supplies = tps65910_ldo8_supply, }; -/* -void __sramfunc board_pmu_tps65910_suspend(void) + +void __sramfunc board_pmu_suspend(void) { - grf_writel(GPIO6_PB1_DIR_OUT, GRF_GPIO6L_DIR_ADDR); - grf_writel(GPIO6_PB1_DO_HIGH, GRF_GPIO6L_DO_ADDR); //set gpio6_b1 output low - grf_writel(GPIO6_PB1_EN_MASK, GRF_GPIO6L_EN_ADDR); + int ret; + ret = gpio_readl(GPIO_SWPORTA_DDR); + gpio_writel(ret | GPIO3_D2_OUTPUT, GPIO_SWPORTA_DDR); + ret = gpio_readl(GPIO_SWPORTA_DR); + gpio_writel(ret | GPIO3_D2_OUTPUT_HIGH, GPIO_SWPORTA_DR); //set pmu_sleep output high } -void __sramfunc board_pmu_tps65910_resume(void) +void __sramfunc board_pmu_resume(void) { - grf_writel(GPIO6_PB1_DIR_OUT, GRF_GPIO6L_DIR_ADDR); - grf_writel(GPIO6_PB1_DO_LOW, GRF_GPIO6L_DO_ADDR); //set gpio6_b1 output low - grf_writel(GPIO6_PB1_EN_MASK, GRF_GPIO6L_EN_ADDR); - #ifdef CONFIG_CLK_SWITCH_TO_32K //switch clk to 24M - sram_32k_udelay(10000); - #else + int ret; + ret = gpio_readl(GPIO_SWPORTA_DDR); + gpio_writel(ret | GPIO3_D2_OUTPUT, GPIO_SWPORTA_DDR); + ret = gpio_readl(GPIO_SWPORTA_DR); + gpio_writel(ret & GPIO3_D2_OUTPUT_LOW, GPIO_SWPORTA_DR); //set pmu_sleep output low sram_udelay(2000); - #endif } -*/ + static struct tps65910_board tps65910_data = { .irq = (unsigned)TPS65910_HOST_IRQ, .irq_base = NR_GIC_IRQS + NR_GPIO_IRQS,

    k4yE;!>H`=aV(6}k;taw{Z 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%0ANY5o&F{X5KH-49?SG~h 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

  • UU~7gS6(=A{Kfx%mGZ)C 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